3
我想用JNA捕獲Java中的WM_QUERYENDSESSION消息,以便我可以執行關閉方法,因爲Runtime#addShutdownHook(Thread)在Windows [1]上不起作用。我知道這可以做,因爲我已經看到它使用JNIWrapper實現,但我想有一個基於JNA的解決方案。如何使用JNA處理WM_QUERYENDSESSION消息
JNIWrapper解決方案
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();
}
}
我試圖創建自己的USER32類與WindowProc中的回調,並接受它作爲參數調用SetWindowLong方法,但我得到以下異常:
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類:
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);
};
和試圖把類一切融合在一起:
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] The shutdown hook isn't executed when the application is launched using javaw.exe