Search code examples
c#.netpinvokemouse-hook

PInvokeStackImbalance - invoking unmanaged code from HookCallback


my goal

i want to translate a left click to a right click

my approach

  • i register a low-level hook via SetWindowsHookEx (user32.dll)
  • filter left-mouse-clicks
  • check if i want to translate THAT specific click
  • in case that i really want to
    • do not pass on the message
    • create a new mouseclick via mouse_event (user32.dll too)

the problem

when i do the described stuff like that:

  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);
  }

the call to mouse_event fails with a PInvokeStackImbalance-Exception, which, i guess, i should care about.

DllImports

since normally a PInvokeStackImbalance comes due to incorrect import-signatures here are mine:

  [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);

emergence

my normal approach to isolate the problem fails in that case - since the mouse_event-call for itself works, and the trashing of left-clicks work too. i hate it when the structure is more than the sum of the parts...


Solution

  • The mouse_event signature should be like this

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