1. 程式人生 > >託管除錯助手 "PInvokeStackImbalance":的呼叫導致堆疊不對稱。原因可能是託管的 PInvoke 簽名與非託管的目標籤名不匹配。請檢查 PInvoke 簽名的呼叫約定和引數與非託管

託管除錯助手 "PInvokeStackImbalance":的呼叫導致堆疊不對稱。原因可能是託管的 PInvoke 簽名與非託管的目標籤名不匹配。請檢查 PInvoke 簽名的呼叫約定和引數與非託管

 

在C#中一定要檢查引用時的資料型別 WinAPI 的資料型別 預設是32位的,但是引用時外部的是 Long型別預設是64位的。所以引用時需要將 long 改為 int 型。

參照 http://blog.sina.com.cn/s/blog_8248282d0101hcbd.html

情況一:

對 PInvoke 函式“TestDLL!TestDLL.Form1::mySum”的呼叫導致堆疊不對稱。原因可能是託管的 PInvoke 簽名與非託管的目標籤名不匹配。請檢查 PInvoke 簽名的呼叫約定和引數與非託管的目標籤名是否匹配。

解決方法:


已經可以了。加C++ 加入_stdcall 把,“允許不安全程式碼”,“啟用非託管程式碼除錯“去掉這樣才行。
謝謝,HolyPlace,founderfang。
使用者名稱:zp20040101  得分:0  時間:2010-09-29 06:59:30
情況二:

對 PInvoke 函式“HTLib::Usb_DelHtFile”的呼叫導致堆疊不對稱。原因可能是託管的 PInvoke 簽名與非託管的目標籤名不匹配。請檢查 PInvoke 簽名的呼叫約定和引數與非託管的目標籤名是否匹配。

把:

[DllImport("ht32dll.dll")]

public static extern long Usb_DelHtFile(string filename,long mIndex);

改成:

[DllImport("ht32dll.dll")]

public static extern int Usb_DelHtFile(string filename, int mIndex);

後來查閱網文(網址:http://hi.baidu.com/wzlv/blog/item/cfd09e189ebf320134fa41eb.html),把這個問題說的比較清楚,引述如下,備忘:


從.NET1.1升級到.NET2.0時出現的PInvokeStackImbalance錯誤
微軟官方的解釋(http://msdn2.microsoft.com/zh-cn/library/0htdy0k3.aspx)
如果 CLR 檢測到平臺呼叫之後的堆疊深度與 DllImportAttribute 屬性指定的呼叫約定中以及託管簽名的引數宣告中提供的預期堆疊深度不匹配,則將啟用 PInvokeStackImbalance 託管除錯助手 (MDA)。
下面將舉一個具體的例子
PCCamera類(UserLib.Device.PCCamera攝像頭類)在從.NET1.1升級到.NET2.0時出現的PInvokeStackImbalance錯誤:
檢測到 PInvokeStackImbalance
Message: 對 PInvoke 函式“WindowsApplication1!UserLib.Device.PCCamera::SendMessage”的呼叫導致堆疊不對稱。原 因可能是託管的 PInvoke 簽名與非託管的目標籤名不匹配。請檢查 PInvoke 簽名的呼叫約定和引數與非託管的目標籤名是否匹配。
錯誤首次發生在這一行程式碼: SendMessage(hWndC, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0);
經過分析發現所有呼叫SendMessage函式的地方都會出現以上錯誤
於是檢視DLLImport:
[DllImport("User32.dll")]
private static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, long lParam);
原來是因為WinAPI的long型別是32位的,而C#的long是64位的,這就導致堆疊不對稱,引發錯誤.
原因:(http://discuss.develop.com/archives/wa.exe?A2=ind0512c&L=dotnet-winforms&D=0&T=0&P=8094)
在.NET2.0 中加入了MDA(managed debugging assistant), 在平臺呼叫時後會檢查棧的指標, 如果發現不平衡, 就會丟擲PInvokeStackImbalance異常; 而在.NET1.1中不會檢查, 所以不會捕獲到異常, 但在執行時會導致不穩定.
解決方法:
將最後一個”long lParam” 改為 “int wParam”, 因為C#中int是32位的. 並且將之後有涉及到SendMessage函式的引數適當地轉成int型就可以了.


但是, 之後查閱了資料http://www.pinvoke.net/default.aspx/user32/SendMessage.html
發 現先前的解決方案還有不合適的地方, 應該將其中的 ”wParm” 和 ”lParm” 引數的型別都轉成IntPtr型別,並且將後面涉及到的引數的 ”0” 改為 “IntPtr.Zero”. 因為如果使用int型別,那麼這段程式碼在64位的Windows上面將會無法正常執行.
總結:
我 們在呼叫WinAPI時要特別小心, 因為WinAPI和C#的資料型別不是完全一樣, 就好像在WinAPI中的long型別在C#中就是int型別, 如果沒有處理好型別問題, 就很可能會導致堆疊的不平衡,引發PInvokeStackImbalance錯誤, 但是這類錯誤在.NET1.1下不會被暴露出來, 所以在從.NET1.1升級到.NET2.0時要特別注意此類問題.