问题描述
我想用JNA在Java中捕获WM_QUERYENDSESSION消息,这样我就可以执行一个shutdown方法,因为Runtime#addShutdownHook(Thread)在Windows [1]上不起作用。我知道这可以做到,因为我已经看到它用JNIWrapper实现但我希望有一个基于JNA的解决方案。
I want to catch WM_QUERYENDSESSION messages in Java with JNA so that I can execute a shutdown method because Runtime#addShutdownHook(Thread) doesn't work on Windows [1]. I know this can be done since I've seen it implemented with JNIWrapper but I would like to have a JNA-based solution.
JNIWrapper解决方案
JNIWrapper solution
import java.io.File;
import java.io.RandomAccessFile;
import javax.swing.JFrame;
import com.jniwrapper.win32.Msg;
import com.jniwrapper.win32.ui.WindowMessage;
import com.jniwrapper.win32.ui.WindowMessageListener;
import com.jniwrapper.win32.ui.WindowProc;
import com.jniwrapper.win32.ui.Wnd;
public class ShutdownJNIWrapper {
public static void main(String[] args) {
final JFrame frame = new JFrame("Shutdown Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Wnd frameHandle = new Wnd(frame);
WindowProc frameWindowProc = new WindowProc(frameHandle);
frameWindowProc.addMessageListener(new WindowMessageListener() {
public boolean canHandle(WindowMessage windowMessage, boolean beforeWindowProc) {
return windowMessage.getMsg() == Msg.WM_QUERYENDSESSION && beforeWindowProc;
}
public int handle(WindowMessage windowMessage) {
doSomething();
return 0;
}
private void doSomething() {
final File file = new File("shutdown-jniwrapper.txt");
try {
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.writeUTF("quit");
raf.close();
} catch (Exception e) {
}
}
});
frameWindowProc.substitute();
}
}
我尝试使用WindowProc创建自己的User32类回调和SetWindowLong方法接受它作为参数,但我得到以下异常:
I tried to create my own User32 class with a WindowProc callback and a SetWindowLong method that accepts it as a parameter but I get the following exception:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'SetWindowLong': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:179)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:344)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:324)
at com.sun.jna.Library$Handler.invoke(Library.java:203)
at $Proxy0.SetWindowLong(Unknown Source)
at ShutdownJNA.main(ShutdownJNA.java:34)
这是我的User32类:
Here's my User32 class:
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.win32.StdCallLibrary;
public interface MyUser32 extends StdCallLibrary {
public static final int WM_QUERYENDSESSION = 0x11;
public static int GWL_WNDPROC = -4;
interface WindowProc extends StdCallCallback {
LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam);
}
int SetWindowLong(HWND hWnd, int nIndex, int dwNewLong);
int SetWindowLong(HWND hWnd, int nIndex, WindowProc dwNewLong);
};
以及尝试将所有内容放在一起的类:
and the class that tries to put everything together:
import javax.swing.JFrame;
import javax.swing.JPanel;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
public class ShutdownJNA extends JPanel {
public static void main(String[] args) {
final JFrame frame = new JFrame("Shutdown Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
try {
HWND hwnd = new HWND();
hwnd.setPointer(Native.getComponentPointer(frame));
MyUser32.WindowProc proc = new MyUser32.WindowProc() {
public LRESULT callback(HWND wnd, int msg, WPARAM param, LPARAM param2) {
if (msg == MyUser32.WM_QUERYENDSESSION) {}
return new LRESULT(0);
}
};
MyUser32 user32 = (MyUser32)Native.loadLibrary("user32", MyUser32.class); //$NON-NLS-1$
user32.SetWindowLong(hwnd, MyUser32.GWL_WNDPROC, proc);
} catch (Exception e) {
e.printStackTrace();
}
}
}
[1]
推荐答案
确保您的环境中有JNA的jar文件。 jna.jar和platform.jar都必须在那里,否则引用将失败。另一方面,如果你打算加载它们,你通过JNA使用的dll文件必须在你的环境中(例如user32.dll)。
Make sure you have the jar files for JNA in your environment. Both jna.jar and platform.jar must be there, otherwise the reference will fail. The other thing is, the dll files you use thru JNA must be in your environment (such as user32.dll) if you plan to load them.
这篇关于如何使用JNA处理WM_QUERYENDSESSION消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!