[英]PInvokeStackImbalance - invoking unmanaged code from HookCallback
我想将鼠标左键转换为鼠标右键
当我做这样的描述的东西:
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,我想我应该在意。
因为通常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.