繁体   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