【发布时间】:2020-01-09 07:19:50
【问题描述】:
我目前正在处理一个涉及使用 SWT 的 Eclipse RCP 的 Java 项目,并试图通过在保存时向 Windows 环境中的用户提供有意义的消息来处理正常关闭。我应该使用 ShutdownBlockReasonCreate 和 ShutdownBLockReasonDestroy API 来实现这一点,但经过一些研究后,我不得不在我非常陌生的 C++ 本机代码中实现它们。因为它们在 JNA 中不可用,并且 Eclipse SWT 不提供这种现成的功能(很想知道)
经过所有努力后,我能够将一个有效的 C++ 代码(如下)组合在一起来控制 SWT 窗口(通过引用另一个实现 https://github.com/seraphy/JavaGracefulShutdownForWin7)。但是我偶然发现了一个与 WindowProc CALLBACK 相关的问题。来自 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) 之后调用此方法时,我的窗口往往表现得非常奇怪。例如,
- 单击“文件”选项时,不再显示菜单;
- 调整窗口大小时,当您尝试调整窗口大小时,一半窗口会变暗 调整大小
- 关闭窗口时,底层进程仍在运行
是的,我需要使用此方法来激活窗口的控制以接收操作系统消息,但随后它开始与已经构建的 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;
}
【问题讨论】:
-
您的问题可能源于在您的
AppWndProc中直接调用DefWindowProc。 M/S documentation 声明:“应用程序必须通过调用 CallWindowProc 将任何未被新窗口过程处理的消息传递给前一个窗口过程。这允许应用程序创建一个窗口过程链。” -
不要使用
SetWindowLongPtr子类化窗口,使用SetWindowSubclass。 -
感谢@AdrianMole 和@Jonathan Potter 的及时回复。到目前为止,我发现了一个帖子stackoverflow.com/questions/31648180/…,它也建议使用类似于乔纳森推荐的
SetWindowSubclass。当我刚刚尝试时,似乎工作得更好。我会多玩一点。谢谢大家!
标签: c++ winapi java-native-interface save shutdown