3

我在 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 等。但这是正确的方法吗?

有什么提示吗?

4

1 回答 1

1

像这样定义您的 PInvoke:

    [DllImport("TheHookDll.dll", CallingConvention = CallingConvention.Cdecl)]
    public extern static void InstallHook(UInt32 ThreadId);

原因是当你调用这个特定的函数时,调用者需要清理堆栈。如果没有在您的 PInvoke 签名中明确指定这一点,运行时将不会清理堆栈,因此它会将堆栈弄乱,从而导致您看到的错误消息。

如果您没有明确指定 a CallingConvention,则运行时假定您尝试调用的函数是 an StdCall,被调用者在其中清理堆栈。事实并非如此,堆栈将被弄得一团糟。

除此之外,您的签名看起来正确;a在 C#DWORD中确实是 auint或。UInt32如果那个给你带来麻烦,你可以尝试用MarshalAs属性装饰它,并让 Marshal 将它作为非托管类型返回U8

于 2013-07-11T21:39:26.163 回答