在C#中一定要檢查引用時的數據類型 WinAPI 的數據類型 默認是32位的,但是引用時外部的是 Long類型默認是64位的。所以引用時需要將 long 改為 int 型。
參照 http://blog.sina.com.cn/s/blog_8248282d0101hcbd.html
https://blog.csdn.net/jinhuicao/article/details/83584973
情況一:
對 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時要特別注意此類問題.