How to handle WM_QUERYENDSESSION messages with JNA

随声附和 提交于 2019-12-22 10:23:20

问题


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 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();
    }
}

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)

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] The shutdown hook isn't executed when the application is launched using javaw.exe


回答1:


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.



来源:https://stackoverflow.com/questions/4901609/how-to-handle-wm-queryendsession-messages-with-jna

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!