C# PinVokeStackResponsibility-从HookCallback调用非托管代码 我的目标
我想将左键单击转换为右键单击 我的方法C# PinVokeStackResponsibility-从HookCallback调用非托管代码 我的目标,c#,.net,pinvoke,mouse-hook,C#,.net,Pinvoke,Mouse Hook,我想将左键单击转换为右键单击 我的方法 我通过SetWindowsHookEx(user32.dll)注册一个低级钩子 过滤鼠标左键单击 检查我是否要翻译特定的点击 如果我真的想 不要传递信息 通过鼠标事件(user32.dll)创建新的鼠标单击 问题 当我这样做时: private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if(nCode >= 0 &&
- 我通过SetWindowsHookEx(user32.dll)注册一个低级钩子
- 过滤鼠标左键单击
- 检查我是否要翻译特定的点击
- 如果我真的想
- 不要传递信息
- 通过鼠标事件(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_事件失败,出现一个PinVokeStack异常,我想我应该关心这个异常
DllImports
由于通常情况下,PinvokesTack不平衡是由不正确的导入签名引起的,因此我的签名如下:
[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);
出现
在这种情况下,我通常隔离问题的方法失败了——因为鼠标事件调用本身可以工作,而左键点击也可以工作。我讨厌当结构超过部分的总和时…鼠标事件签名应该是这样的
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, IntPtr dwExtraInfo);
鼠标事件签名应该是这样的
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, IntPtr dwExtraInfo);
鼠标事件定义为:
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表示uintpttr。因此,正确地说,应该是:
[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注意到并非所有内容都已从堆栈中删除。它会为您执行此操作(但您传递了错误的数据,因此该函数可能执行了与您所希望的不同的操作)并向您发出警告。鼠标事件定义为:
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表示uintpttr。因此,正确地说,应该是:
[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注意到并非所有内容都已从堆栈中删除。它会为您执行此操作(但您传递了错误的数据,因此该函数可能执行了与您所希望的不同的操作)并警告您。Internet上有许多错误的p/invoke声明。他们通常从VB6开始生活。在该语言中,整数是16位,长是32位。返回到在16位操作系统上运行的VB1。它们在VB.NET或C#中无法正常工作
堆栈不平衡MDA是专门为捕捉这种错误声明而设计的,但它是一个选项(调试+异常)。如果只有一个参数或传递了大量零,则实际调用往往会起作用。不幸的是,调用后代码保持正常运行的几率也不坏。当方法返回时,堆栈指针值会自动更正。不过,你可能会遇到一些非常棘手的问题。互联网上有很多糟糕的p/invoke声明。他们通常从VB6开始生活。在该语言中,整数是16位,长是32位。返回到在16位操作系统上运行的VB1。它们在VB.NET或C#中无法正常工作
堆栈不平衡MDA是专门为捕捉这种错误声明而设计的,但它是一个选项(调试+异常)。如果只有一个参数或传递了大量零,则实际调用往往会起作用。不幸的是,调用后代码保持正常运行的几率也不坏。当方法返回时,堆栈指针值会自动更正。不过,你可能会遇到一些非常棘手的问题。该死的,我真傻——我甚至说通常签名是错误的。。。但现在我想知道-我从另一个项目(生产代码)复制了sig,它正在那里工作。。。发生了什么?P/Invoke在某种程度上可以原谅不正确的签名,尽管在您的情况下,不正确的数据可能会传递给函数。为了警告您签名不正确,PinVokeStacks调试助手在激活时会触发。该死的,我很愚蠢-我甚至说通常签名是错误的。。。但现在我想知道-我从另一个项目(生产代码)复制了sig,它正在那里工作。。。发生了什么?P/Invoke在某种程度上可以原谅不正确的签名,尽管在您的情况下,不正确的数据可能会传递给函数。为警告您的签名不正确,PinVokeStack托管调试助手将在其处于活动状态时触发。我知道CLR数据类型定义,但我只是傻到期望我们的productioncode是正确的:)我知道CLR数据类型定义,我只是傻到期望我们的productioncode是正确的:)