作为对我最近一个问题(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 ++本机代码现在看起来像这样:
注意:因为在本练习中,我仅将回调部分(在原始c ++本地代码中)重构为JNA,所以这里不需要SetWindowSubclass()
#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应用程序。保存代码并运行应用程序后,出现以下问题:
我尝试了以下操作:
GetWindowLongPtr()
中的CallWindowProc()
替换“ baseWndProc” LONG_PTR。不幸的是没有用SetWindowLongPtr()
的问题与上次相同。但是如前所述,JNA似乎没有提供匹配的SetWindowSubclass()
方法,所以我没主意。Btw,上一次的本机代码解决方案仍然可以正常工作。但是出于可维护性的目的,使用Java实现所有功能将是理想的。
非常感谢有人花时间在我的问题上!
欢呼声
您应始终准备最少的样本,以重现问题并可以由潜在的帮助者来运行。对代码进行推理,这很难从上下文中剥离。