我目前正在使用SWT进行涉及Eclipse RCP的Java项目,并试图通过在保存时向Windows环境中的用户提供有意义的消息来处理正常关机。我应该使用 ShutdownBlockReasonCreate ShutdownBLockReasonDestroy API来实现此目的,但是经过一番研究后,我不得不在我刚接触的C++本机代码中实现它们。由于它们在JNA中不可用,因此Eclipse SWT不提供这种功能(不愿知道)

经过所有的努力,我能够整理一个有效的C++代码(如下所示)以控制SWT窗口(通过引用另一个实现https://github.com/seraphy/JavaGracefulShutdownForWin7)。但是,我偶然发现了与WindowProc回调有关的问题。来自Java的这些语法使我花了一些时间来理解。但是我有点理解它正在尝试做的事情。因为这是我们需要处理WM_QUERYENDSESSION和WM_ENDSESSION消息的地方。

但是在此之前,我想在这篇文章中讨论的问题与Windows API SetWindowLongPtr 特别相关,正如您在Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title)函数中看到的那样。如您所见,我将其注释掉了,仅仅是因为在ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON)之后调用此方法时,我的窗口的行为非常奇怪。例如,

  • 单击"file"选项时,不再显示菜单;
  • 调整窗口大小时,当您尝试调整窗口大小时,一半窗口变暗
    调整大小
  • 关闭窗口时,底层进程仍在运行

  • 是的,我需要使用此方法来激活用于接收os消息的窗口的控件,但是随后它开始与已经构建的Eclipse SWT窗口混淆。有谁知道我是否正确地完成了整个工作?还是我偏离了轨道? SetWindowLongPtr 到底做什么?我找不到任何好的引用资料,也无法从阅读Microsoft Doc中受益匪浅。

    提前致谢!
    #include <jni.h>
    
    #include <iostream>
    #include "com_app_project_winapi_WindowsAPI.h"
    #include <windows.h>
    
    using namespace std;
    
    namespace {
    
        LPCWSTR SHUTDOWN_REASON = L"Application is still saving ...";
    
        LRESULT CALLBACK AppWndProc(
            _In_ HWND hWnd,
            _In_ UINT message,
            _In_ WPARAM wParam,
            _In_ LPARAM lParam
        ) {
    
    
            switch (message) {
                // Not doing anything yet
            }
    
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    
    
    JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title) {
        cout << "shutdownblockreason create" << endl;
    
        const char *str = NULL;
    
        str = (env)->GetStringUTFChars(title, 0);
        HWND hWnd = FindWindow(NULL, str);
        (env)->ReleaseStringUTFChars(title, str);
        if (hWnd == NULL) {
            return;
        }
    
        ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON);
    
    
        //SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(AppWndProc));
    
        return;
    }
    
    JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonDestroy(JNIEnv *env, jclass cls, jstring title) {
        cout << "shutdownblockreason destroy" << endl;
    
        const char *str = NULL;
    
        str = (env)->GetStringUTFChars(title, 0);
        HWND hWnd = FindWindow(NULL, str);
        (env)->ReleaseStringUTFChars(title, str);
        if (hWnd == NULL) {
            return;
        }
    
        ShutdownBlockReasonDestroy(hWnd);
    
        return;
    }
    

    最佳答案

    首先,您要调用ANSI version of FindWindow() ,它不接受UTF-8字符串。请改用Unicode version,它接受UTF-16字符串。 Java字符串本机使用UTF-16作为其公共(public)接口(interface),因此您无需浪费时间将它们转换为UTF-8。

    其次,您的窗口在调用 SetWindowLongPtr() 之后无法正常运行,因为您的AppWndProc()需要使用 CallWindowProc() 而不是 DefWindowProc() 来调用您替换的上一个窗口过程。另外,使用AppWndProc()完成操作后,您将不会恢复以前的窗口过程。

    第三,您应该使用 SetWindowSubclass() 而不是SetWindowLongPtr()。参见Disadvantages of the Old Subclassing ApproachSafer subclassing

    话虽如此,请尝试以下类似的方法:

    #include <jni.h>
    #include <iostream>
    #include "com_app_project_winapi_WindowsAPI.h"
    #include <windows.h>
    #include <commctrl.h>
    
    namespace {
        LPCWSTR SHUTDOWN_REASON = L"Application is still saving ...";
    
        /*
        WNDPROC PrevWndProc = NULL;
        LRESULT CALLBACK AppWndProc(
            _In_ HWND hWnd,
            _In_ UINT message,
            _In_ WPARAM wParam,
            _In_ LPARAM lParam
        ) {
        */
        LRESULT CALLBACK AppWndProc(
            _In_ HWND hWnd,
            _In_ UINT message,
            _In_ WPARAM wParam,
            _In_ LPARAM lParam,
            _In_ UINT_PTR uIdSubclass,
            _In_ DWORD_PTR dwRefData
        ) {
            switch (message) {
                case WM_NCDESTROY:
                    RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
                    break;
    
                //...
            }
    
            //return CallWindowProc(PrevWndProc, hWnd, message, wParam, lParam);
            return DefSubclassProc(hWnd, message, wParam, lParam);
        }
    }
    
    JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title) {
        std::cout << "shutdownblockreason create" << std::endl;
    
        const jchar *str = env->GetStringChars(title, NULL);
        HWND hWnd = FindWindowW(NULL, (LPCWSTR) str);
        env->ReleaseStringChars(title, str);
        if (!hWnd) {
            return;
        }
    
        ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON);
    
        //PrevWndProc = (WNDPROC) SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(AppWndProc));
        SetWindowSubclass(hWnd, &AppWndProc, 1, 0);
    }
    
    JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonDestroy(JNIEnv *env, jclass cls, jstring title) {
        std::cout << "shutdownblockreason destroy" << std::endl;
    
        const jchar *str = env->GetStringChars(title, NULL);
        HWND hWnd = FindWindowW(NULL, (LPCWSTR) str);
        env->ReleaseStringChars(title, str);
        if (!hWnd) {
            return;
        }
    
        //SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(PrevWndProc));
        RemoveWindowSubclass(hWnd, &AppWndProc, 1);
    
        ShutdownBlockReasonDestroy(hWnd);
    }
    

    09-13 06:58