作为我最近的问题的扩展(Winapi - SetWindowLongPtr in ShutdownBlockReasonCreate / Destroy implementation of JNI native code)我想知道是否有机会使用 JNA 实现相同的功能(最新版本 5.5.0 - https://github. com/java-native-access/jna)。
SetWindowSubclass()
由于我在文档(http://java-native-access.github.io/jna/5.5.0/javadoc/ )中找不到任何相关的内容,我不得不使用SetWindowLongPtr()
.
在网上做了一些研究之后,这里有一些我负责预期功能的代码片段:
private static LONG_PTR baseWndProc;
private static HWND hWnd;
public static void initiateWindowsShutdownHook() {
Display.getDefault().syncExec(()->{
hWnd = new WinDef.HWND(Pointer.createConstant(Display.getDefault().getActiveShell().handle));
});
baseWndProc = IWindowsAPIUtil.WSBINSTANCE.SetWindowLongPtr(
hWnd, IWindowsAPIUtil.GWL_WNDPROC, new IWindowsAPIUtil.WNDPROC() {
@Override
public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
case IWindowsAPIUtil.WM_QUERYENDSESSION:
Logger.logWarning("Shutdown initiated");
IWindowsAPIUtil.WSBINSTANCE.PostMessage(hWnd, User32.WM_CLOSE, wParam, lParam);
return new LRESULT(0);
}
return IWindowsAPIUtil.WSBINSTANCE.CallWindowProc(baseWndProc, hWnd, uMsg, wParam, lParam);
}
});
}
public interface IWindowsAPIUtil extends User32 {
public static final IWindowsAPIUtil WSBINSTANCE =
(IWindowsAPIUtil) Native.loadLibrary("user32", IWindowsAPIUtil.class, W32APIOptions.UNICODE_OPTIONS);
interface WNDPROC extends StdCallCallback{
LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam);
}
public static final int GWL_WNDPROC = -4;
public static final int WM_QUERYENDSESSION = 17;
LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, WNDPROC wndProc);
LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex);
LRESULT CallWindowProc(LONG_PTR proc, HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam);
void PostMessage(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam);
}
我的新 c++ 本机代码现在看起来像这样:
注意:SetWindowSubclass()
由于在本练习中我只将回调部分(在原始 c++ 本机代码中)重构为 JNA,因此此处不需要
#include <windows.h>
#include <jni.h>
#include <iostream>
#include "com_app_project_winapi_WindowsAPI.h"
#include <commctrl.h>
using namespace std;
namespace {
// Default reason text. The actual reason text should be defined by application logic not the native code
LPCWSTR SHUTDOWN_REASON = L"Application is still saving ...";
}
JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title, jstring reasonText) {
cout << "In shutdownBlockReasonCreate method" << endl;
const jchar *str = env->GetStringChars(title, NULL);
HWND hWnd = FindWindowW(NULL, (LPCWSTR)str);
env->ReleaseStringChars(title, str);
if (hWnd == NULL) {
return;
}
ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON);
return;
}
JNIEXPORT void JNICALL Java_com_app_project_winapi_WindowsAPI_shutdownBlockReasonDestroy(JNIEnv *env, jclass cls, jstring title) {
cout << "In shutdownBlockReasonDestroy method" << endl;
const jchar *str = env->GetStringChars(title, NULL);
HWND hWnd = FindWindowW(NULL, (LPCWSTR)str);
env->ReleaseStringChars(title, str);
if (hWnd == NULL) {
return;
}
ShutdownBlockReasonDestroy(hWnd);
return;
}
从我的代码中,您可能会看到我将 Eclipse SWT 用于我的 GUI 应用程序。保存我的代码并运行应用程序后,我遇到以下问题:
- 虽然在第一次应用程序保存期间激活了 blockReasonCreate(此功能的目的是在保存时阻止关闭),但它在后续保存中不再激活。原因文本显示“此应用程序正在阻止关闭”,而不是传入的原因文本。
- 作为上面的扩展行为,我的 GUI 应用程序冻结并且窗口无法关闭,直到我从任务管理器强制关闭它
我尝试了以下方法:
- 将“baseWndProc”LONG_PTR 替换为
GetWindowLongPtr()
inCallWindowProc()
。不幸的是没有工作 - 我怀疑我和
SetWindowLongPtr()
上次有同样的问题。但如前所述,JNA 似乎没有SetWindowSubclass()
提供匹配方法,所以我没有想法。
顺便说一句,上次的本机代码解决方案仍然可以完美运行。但是出于可维护性的目的,将所有功能都用 Java 实现是理想的。
真的很感谢任何人花时间在我的问题上!
干杯