我尝试使用JNA在Java程序中捕获Windows消息来注入我自己的WndProc方法。 由于我只会对几种消息types感兴趣,所以我将不得不将消息转发给以前的WndProc。 在我的testing中(Java 1.7.0_03,64位,在Windows 7上),当我将鼠标移到创build的窗口上时,这个转发似乎失败了,给我以下exception:
com.sun.jna.LastErrorException: [2]The system cannot find the file specified. at com.sun.jna.Native.invokeLong(Native Method) at com.sun.jna.Function.invoke(Function.java:347) at com.sun.jna.Function.invoke(Function.java:276) at com.sun.jna.Library$Handler.invoke(Library.java:216) at $Proxy0.CallWindowProc(Unknown Source) at JnaWinEvents$1.callback(JnaWinEvents.java:102) at ...
我认为这很奇怪,因为我试图访问哪个文件? 我想有一些内存访问是完全错误的或如此… 🙁
我正在使用最新版本的JNA 3.4.0。 我在这里或在互联网上的其他地方find的许多代码示例似乎都使用JNA 3.2.x(分割成jna.jar和platform.jar之前的任何版本),其中User32定义了一些非常适合这种工作的方法。 在较新版本的JNA / platform中,缺less这些方法。 这就是为什么我自己定义了大部分types,只使用jna.jar,而不是platform.jar。 下面是我用来testing的代码,它生成了Exception。 任何想法出了什么问题,为什么发生exception?
import javax.swing.*; import com.sun.jna.*; import com.sun.jna.win32.*; public class JnaWinEvents extends JFrame { public LONG_PTR prevWndProc = null; // so it won't get GC'ed public User32.WNDPROC wndProcCallbackListener = null; // so it won't get GC'ed public JnaWinEvents() { this.add(new JLabel("Hello StackExchange!")); this.pack(); this.setVisible(true); setupEventsListener(); } public static class LONG_PTR extends IntegerType { public LONG_PTR() { this(0); } public LONG_PTR(long value) { super(Pointer.SIZE, value); } } static class HANDLE extends PointerType implements NativeMapped { } public static class HWND extends HANDLE { public HWND() { } } public static class UINT_PTR extends IntegerType { public UINT_PTR() { super(Pointer.SIZE); } public UINT_PTR(long value) { super(Pointer.SIZE, value); } public Pointer toPointer() { return Pointer.createConstant(longValue()); } } public static class WPARAM extends UINT_PTR { public WPARAM() { this(0); } public WPARAM(long value) { super(value); } } public static class LPARAM extends LONG_PTR { public LPARAM() { this(0); } public LPARAM(long value) { super(value); } } public static class LRESULT extends LONG_PTR { public LRESULT() { this(0); } public LRESULT(long value) { super(value); } } public interface User32 extends StdCallLibrary { static int GWL_WNDPROC = -4; User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS); interface WNDPROC extends StdCallCallback { LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam); } LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex) throws LastErrorException; LRESULT CallWindowProc(LONG_PTR proc, HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam) throws LastErrorException; LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, WNDPROC wndProc) throws LastErrorException; } private void setupEventsListener() { HWND hWnd = new HWND(); hWnd.setPointer(Native.getWindowPointer(this)); this.prevWndProc = User32.INSTANCE.GetWindowLongPtr(hWnd, User32.GWL_WNDPROC); this.wndProcCallbackListener = new User32.WNDPROC() { @Override public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) { System.out.println(hWnd + "\t" + uMsg + "\t" + wParam + "\t" + lParam); //Call the window's actual WndProc so the events get processed. return User32.INSTANCE.CallWindowProc(prevWndProc, hWnd, uMsg, wParam, lParam); } @Override protected void finalize() throws Throwable { System.out.println("FINALIZE!!!!"); super.finalize(); } }; //Set the WndProc function to use our callback listener instead of the window's one. LONG_PTR result = User32.INSTANCE.SetWindowLongPtr(hWnd, User32.GWL_WNDPROC, wndProcCallbackListener); System.out.println("setting my window proc, result = " + result); System.out.println("old pointer = " + this.prevWndProc); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new JnaWinEvents(); } }); } }
任何帮助表示赞赏,谢谢!
问题在于接口定义。 看这里
我最近与JNA有过索姆问题(因为我试图按照旧版本的教程)。 我只是设置了一个工作代码的框架,我不会在这里发表,因为它和你的很相似。 不同的是,我使用platform.jar。 你为什么不使用它?
编辑:对于延迟抱歉。 您需要以这种方式定义回调过程(为您提供StdCallBack)
public class WndProc implements StdCallCallback { public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) { } }
在某个地方宣布
private final WndProc procedure = new WndProc();
然后在适当的时候链接它。
user32.SetWindowLongPtr(window, com.sun.jna.platform.win32.WinUser.GWL_WNDPROC, procedure);
您可能需要在自定义的User32接口中声明SetWindowLongPtr,该接口扩展了所提供的接口。