2

JNA を使用して Java プログラムで Windows メッセージをキャッチし、独自の WndProc メソッドを挿入しようとしています。いくつかのメッセージ タイプにのみ関心があるため、メッセージを前の WndProc に転送する必要があります。私のテスト (Windows 7 の Java 1.7.0_03、64 ビット) では、作成されたウィンドウにマウスを移動するとすぐにこの転送が失敗するようで、次の例外が発生します。

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 を使用しています。ここまたはインターネット上の他の場所で見つけた多くのコード例は、User32 がこの種の作業に適したいくつかのメソッドを定義した JNA 3.2.x (jna.jar と platform.jar に分割される前の任意のバージョン) を使用しているようです。JNA/プラットフォームの新しいバージョンでは、これらのメソッドが欠落しています。そのため、ほとんどの型を独自に定義し、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();
        }
    });
}
}

どんな助けでも大歓迎です、ありがとう!

4

2 に答える 2

1

問題はインターフェース定義にあります。ここを見て

于 2013-01-01T22:18:29.810 に答える
0

最近、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 を宣言する必要がある場合があります。

于 2012-05-03T09:25:14.577 に答える