2013-07-11 33 views
3

在C#中调用void函数(在win32中)我在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)为目标,并使用该线程ID在win32的InstallHook函数中。 (这只是小数,而不是十六进制)

但我得到这个错误信息:

检测PInvokeStackImbalance消息:对PInvoke的功能 “!TheOperator TheOperator.Form1 :: InstallHook”呼叫具有不平衡栈。 这可能是因为托管PInvoke签名与非托管目标签名不匹配 。检查PInvoke签名的调用约定和 参数是否与目标非托管 签名匹配。

我试图改变调用约定在我的dll文件(配置属性 - > C/C++ - >所有选项 - >调用约定)从__cdel到__stdcall,但没有任何运气。 (同样的错误)

我在做什么错?

我已经将DWORD更改为UInt32,因为c#不支持DWORD等。但是,这是正确的方式吗?

任何提示?

+0

[MSDN](http://msdn.microsoft.com/zh-cn/library/windows/desktop/aa383751.aspx):“DWORD - 一个32位无符号整数。范围是0到4294967295十进制。 “所以匹配的C#类型确实是'UInt32'。 – dtb

回答

1

定义您的PInvoke是这样的:

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

原因是,当你调用这个特定的功能,主叫方需要清理堆栈。如果没有在你的PInvoke签名中明确地指定它,运行时将不会清除堆栈,因此会导致堆栈乱了,导致你看到的错误信息。

如果您没有明确指定CallingConvention,则运行时假定您尝试调用的函数是StdCall,其中被调用者清除堆栈。事实并非如此,堆栈将被全部搞砸和肮脏。

除此之外,您的签名看起来正确;一个DWORD确实是C#中的uintUInt32。如果那个人让你陷入困境,你可以尝试用MarshalAs属性装饰它,并让元帅将它作为非托管类型返回U8

+0

优秀 - 它的工作原理。非常感谢你!! –