【问题标题】:Replace WndProc with JNA fails with Exception用 JNA 替换 WndProc 失败并出现异常
【发布时间】:2012-04-22 10:54:31
【问题描述】:

我尝试在 Java 程序中捕获 Windows 消息,使用 JNA 注入我自己的 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();
        }
    });
}
}

感谢任何帮助,谢谢!

【问题讨论】:

  • 消息文本可能不相关,因为在对最后一个函数调用的返回码进行显式测试后抛出了 LastErrorException。更好地检查代码 2 在特定函数调用的上下文中的含义。

标签: java windows jna wndproc


【解决方案1】:

问题在于接口定义。看here

【讨论】:

    【解决方案2】:

    我最近在使用 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,该接口扩展了提供的接口。

    【讨论】:

    • 您使用哪个版本的 JNA?在我使用的 3.4.0 中,我需要实现的 WNDPROC 没有定义,并且在 jna.jar 和 platform.jar 中也缺少 CallWindowProc。您是否有替换 wndproc 调用原始方法的工作示例?如果是,请发布您的代码,即使它非常相似。我的主要问题是调用原始 wndproc 在所有情况下都不起作用...
    猜你喜欢
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 2021-03-04
    • 1970-01-01
    • 2015-02-20
    • 2018-07-28
    相关资源
    最近更新 更多