2013-07-11 31 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

優秀 - 它的工作原理。非常感謝你!! –