簡體   English   中英

PInvokeStackImbalance-從HookCallback調用非托管代碼

[英]PInvokeStackImbalance - invoking unmanaged code from HookCallback

我的目標

我想將鼠標左鍵轉換為鼠標右鍵

我的方法

  • 我通過SetWindowsHookEx(user32.dll)注冊了一個低級鈎子
  • 過濾鼠標左鍵
  • 檢查我是否要翻譯那個特定的點擊
  • 萬一我真的很想
    • 不要傳遞消息
    • 通過mouse_event創建新的mouseclick(也是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的調用失敗,並出現PInvokeStackImbalance-Exception,我想我應該在意。

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本身起作用,並且對左鍵單擊的破壞也起作用。 當結構超過零件總和時,我討厭它...

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。 因此正確的應該是:

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

問題是long在C#中定義為64位,而(u)int是32位。 (U)IntPtr是32位還是64位,具體取決於操作系統的位數。

編輯:換句話說,您正在向該函數傳遞太多數據。 由於被調用方清理了堆棧,因此PInvoke注意到並不是從堆棧中刪除了所有內容。 它會為您執行此操作(但是您傳遞了錯誤的數據,因此該功能可能執行了與所需操作不同的操作)並發出警告。

互聯網上有很多錯誤的p / invoke聲明。 他們通常從VB6開始生活。 在該語言中,整數是16位,而Long是32位。 返回到在16位操作系統上運行的VB1。 它們在VB.NET或C#中無法正常工作。

堆棧不平衡MDA是專門為捕獲此類錯誤聲明而設計的,但它是一個選項(調試+異常)。 如果只有一個參數或傳遞大量零,則實際的調用通常會起作用。 不幸的是,調用后代碼保持正常運行的幾率也不錯。 方法返回時,堆棧指針值會自行更正。 但是,您會遇到一些非常棘手的問題。

mouse_event簽名應如下所示

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM