В качестве дополнения к моему недавнему вопросу ( Winapi - SetWindowLongPtr в ShutdownBlockReasonCreate / Destroy реализация собственного кода JNI ) Я хотел бы знать, есть ли шанс реализовать такую же возможность с использованием JNA (последний выпуск 5.5 .0 - https://github.com/java-native-access/jna).
Поскольку я не смог найти ничего, что относится к SetWindowSubclass()
в do c (http://java-native-access.github.io/jna/5.5.0/javadoc/) I пришлось использовать 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 приложения. После сохранения кода и запуска приложения возникает следующая проблема:
- Хотя blockReasonCreate активируется во время первого сохранения приложения (целью этой функции является блокирование выключения при сохранении), оно больше не активируется в последующее сохранение. И текст причины говорит: «Это приложение предотвращает отключение», вместо текста причины, который был передан.
- В качестве расширенного поведения, приведенного выше, мое приложение GUI зависает, и окно не может быть закрыто, пока я принудительно закрыть его из диспетчера задач
Я попытался сделать следующее:
- Заменить "baseWndPro c" LONG_PTR на
GetWindowLongPtr()
в CallWindowProc()
. К сожалению, не сработало - У меня есть подозрение, что у меня та же проблема с
SetWindowLongPtr()
, что и в прошлый раз. Но, как описано ранее, JNA, по-видимому, не имеет соответствующего метода SetWindowSubclass()
, поэтому у меня нет идей.
Кстати, решение нативного кода последнего времени все еще работает отлично. Но в целях удобства обслуживания все функции, реализованные в Java, были бы идеальными.
Очень признателен всем, кто уделил время моей проблеме!
Приветствия