2012-04-22 77 views
2

我嘗試在使用JNA注入我自己的WndProc方法的Java程序中捕獲Windows消息。由於我只會對幾種消息類型感興趣,因此我必須將消息轉發給以前的WndProc。在我的測試(Java 1.7.0_03,64位,在Windows 7)該轉發似乎將我的鼠標所創建的窗口儘快失敗,讓我有以下異常:用JNA替換WndProc失敗,出現異常

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。我在這裏或在互聯網上的其他地方發現了很多代碼示例似乎使用JNA 3.2.x(分割成jna.jar和platform.jar之前的任何版本),其中User32定義了一些非常適合這類工作的方法。在較新版本的JNA/platform中,缺少這些方法。爲什麼我自己定義了大部分類型,只能使用jna.jar,而不能使用platform.jar 以下是我用來測試的代碼,它產生了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(); 
     } 
    }); 
} 
} 

任何幫助表示讚賞,謝謝!

+0

消息文本可能不相關,因爲LastErrorException由於顯式測試了最後一次函數調用的返回碼而引發。更好地檢查** 2 **在特定函數調用的上下文中的含義。 – 2012-04-22 11:05:36

回答

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,該接口擴展了提供的接口。

+0

你使用哪個版本的JNA?在我使用的3.4.0中,我需要實現的WNDPROC沒有定義,並且CallWindowProc在jna.jar和platform.jar中也缺少。你有一個工作的例子,取代wndproc *和*調用原始方法嗎?如果是,請發佈您的代碼,即使它非常相似。我主要的問題是調用原始的wndproc在任何情況下都不起作用。 – cello 2012-05-03 12:28:53

相關問題