我目前正在使用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)
之后调用此方法时,我的窗口的行为非常奇怪。例如,
调整大小
是的,我需要使用此方法来激活用于接收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 Approach和Safer 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);
}