2011-02-04 87 views
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

回答

1

確保你在你的環境中JNA的jar文件。 jna.jar和platform.jar都必須存在,否則引用將失敗。另一件事是,如果您打算加載它們,則通過JNA使用的dll文件必須位於您的環境中(例如user32.dll)。