2010-08-10 37 views
0

我的目標調用非託管代碼

我想左擊轉換爲右鍵單擊PInvokeStackImbalance - 從HookCallback

我的做法

  • 我註冊通過調用SetWindowsHookEx低級別掛鉤(USER32 .dll)
  • 篩選鼠標左鍵單擊
  • 檢查我是否想翻譯該特定點擊
  • 的情況下,我真的想
    • 不傳遞消息
    • 創建通過mouse_event一個新的鼠標點擊(user32.dll中太)

問題

當我做這樣的描述:

private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { 
    if(nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam && doRight) { 
     doRight = false; 
     MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); 
     mouse_event(/*right down + right up*/8 | 16, hookStruct.pt.x, hookStruct.pt.y, 0, 0); 
     return new IntPtr(1); 
    } 
    return CallNextHookEx(_hookID, nCode, wParam, lParam); 
    } 

對mouse_event的調用失敗,出現PInvokeStackImpalance異常,我想我應該關心這個異常。

DllImports

因爲通常一個PInvokeStackImbalance談到由於不正確的進口簽名這裏是我的:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool UnhookWindowsHookEx(IntPtr hhk); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr GetModuleHandle(string lpModuleName); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] 
    public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo); 

出現

我找出問題的正常途徑在這種情況下,失敗 - 因爲本身的mouse_event-call會起作用,左鍵點擊的廢棄也起作用。我討厭的結構比部分的總和更多...

回答

1

的mouse_event簽名應該是這樣的

public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, IntPtr dwExtraInfo); 
+0

該死的我愚蠢 - 我甚至說,通常簽名是錯誤的...但現在我想知道 - 我複製了另一個項目(生產代碼)的信號,它在那裏工作...發生了什麼? – santa 2010-08-10 11:16:45

+1

P/Invoke在某種程度上可以原諒不正確的簽名,儘管在您的情況下不正確的數據可能會傳遞給函數。要警告您簽名不正確,PInvokeStackImbalance託管調試助手會在激活時觸發。 – 2010-08-10 11:23:56

2

mouse_event定義爲:

VOID WINAPI mouse_event(
    __in DWORD dwFlags, 
    __in DWORD dx, 
    __in DWORD dy, 
    __in DWORD dwData, 
    __in ULONG_PTR dwExtraInfo 
); 

WINAPI裝置STDCALL ,DWORD是uint,ULONG_PTR是UIntPtr。所以正確它應該是:

問題是,長在C#中定義爲64位,而(u)int是32位。 (U)IntPtr是32位或64位,取決於操作系統的位數。

編輯:換句話說,你傳遞的功能太多的數據。由於被調用者清除堆棧,PInvoke注意到並非所有東西都從堆棧中移除。它是爲你做的(但你已經傳遞了錯誤的數據,所以函數可能做了與你想要的不同的東西),並警告你。

+0

我知道CLR數據類型定義,我只是笨到足以期望我們的產品代碼是正確的:) – santa 2010-08-10 12:32:29

2

在互聯網上有一個很多壞的p/invoke聲明。他們通常在VB6中開始生活。在這種語言中,Integer是16位,Long是32位。回到在16位操作系統上運行的VB1。它們在VB.NET或C#中無法正常工作。

堆棧不平衡MDA專門設計用於捕獲此類錯誤聲明,但它是一個選項(Debug + Exceptions)。如果只有一個參數或傳遞很多零,實際的調用往往會起作用。在通話結束後代碼保持正常運行的可能性不幸的是也不壞。當方法返回時,堆棧指針值會自行糾正。儘管如此,你可能會遇到一些棘手的問題。

相關問題