我在win32中有以下代码,它在目标应用程序中设置了一个钩子。
void InstallHook(DWORD ThreadId)
{
g_hHook = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, g_hInstDll, ThreadId);
}
我希望从C#(。net)调用此函数。
到目前为止,我有这个:
[DllImport("TheHookDll.dll")]
public extern static void InstallHook(UInt32 ThreadId);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
我称之为:
IntPtr hWnd = FindWindow(null, "MyTargetAppWindowTitle");
UInt32 threadID = GetWindowThreadProcessId(hWnd, IntPtr.Zero);
InstallHook(threadID);
这为我提供了目标的句柄(hWnd),以及win32中InstallHook函数中使用的threadID。 (它只是小数而不是十六进制)
但我收到此错误消息:
检测到PInvokeStackImbalance消息:调用PInvoke函数 'TheOperator!TheOperator.Form1 :: InstallHook'使堆栈失衡。 这可能是因为托管的PInvoke签名不匹配 非托管目标签名。检查调用约定和 PInvoke签名的参数与目标非托管匹配 签名。
我试图将我的dll文件中的调用约定(配置属性 - > C / C ++ - >所有选项 - >调用约定)从__cdel更改为__stdcall,但没有任何运气。 (同样的错误)
我做错了什么?
我已将DWORD更改为UInt32,因为c#不支持DWORD等。但这是正确的方法吗?
任何提示?
答案 0 :(得分:1)
像这样定义你的PInvoke:
[DllImport("TheHookDll.dll", CallingConvention = CallingConvention.Cdecl)]
public extern static void InstallHook(UInt32 ThreadId);
原因是当您调用此特定函数时,调用者需要清理堆栈。如果没有在PInvoke签名中明确指定它,运行时将不会清理堆栈,因此它会使堆栈混乱,从而导致您看到的错误消息。
如果未明确指定CallingConvention
,则运行时假定您尝试调用的函数为StdCall
,其中被调用者清理堆栈。情况并非如此,堆栈将全部搞砸并且很脏。
除此之外,您的签名看起来是正确的; DWORD
确实是C#中的uint
或UInt32
。如果那个让您遇到麻烦,可以尝试使用MarshalAs
属性进行装饰,并让Marshal将其作为非托管类型U8
返回。