我尝试使用 JNA 在 Java 程序中捕获 Windows 消息,以注入我自己的 WndProc 方法。由于我只对几种消息类型感兴趣,因此我必须将这些消息转发到之前的 WndProc。在我的测试中(Java 1.7.0_03,64 位,在 Windows 7 上),只要我将鼠标移到创建的窗口上,这个转发似乎就会失败,给我以下异常:
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。我在此处或 Internet 上的其他地方找到的许多代码示例似乎使用 JNA 3.2.x(拆分为 jna.jar 和 platform.jar 之前的任何版本),其中 User32 定义了一些非常适合此类工作的方法。在较新版本的 JNA/platform 中,缺少这些方法。这就是为什么我自己定义大部分类型,只使用 jna.jar,而不是 platform.jar。以下是我用来测试的代码,它会生成异常。知道出了什么问题以及为什么会发生异常吗?
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();
}
});
}
}
任何帮助表示赞赏,谢谢!