因此,我有一個本機第三方C++代碼庫我正在使用(.lib和.hpp文件),我用它在C++/CLI中構建包裝以供最終使用在C#中。訪問衝突異常/從C++回調崩潰到C#函數
從調試模式切換到發佈模式時遇到特定問題,因爲回調代碼返回時出現訪問衝突異常。
從回調函數的格式原來的HPP文件的代碼:
typedef int (*CallbackFunction) (void *inst, const void *data);
從C++/CLI包裝代碼的回調函數格式: (我會解釋爲什麼我在某一時刻宣佈二)
public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
--Quickly,原因我聲明一個第二「UnManagedCallbackFunction」是我試圖創建在包裝的「中介」回調,所以鏈條從本機C++> C#改變爲版本本機C++>的C++/CLI包裝器> C#...完全公開這個問題仍然存在,它現在被推到了C++/CLI包裝器的同一行(返回)。
最後,從C#的崩潰代碼:
public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData)
{
Console.WriteLine("in hReceiveLogEvent...");
Console.WriteLine("pInstance: {0}", pInstance);
Console.WriteLine("pData: {0}", pData);
// provide object context for static member function
helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target;
if (hw == null || pData == null)
{
Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n");
return 0;
}
// typecast data to DataLogger object ptr
IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;
//Do Logging Stuff
Console.WriteLine("exiting hReceiveLogEvent...");
Console.WriteLine("pInstance: {0}", pInstance);
Console.WriteLine("pData: {0}", pData);
Console.WriteLine("Setting pData to zero...");
pData = IntPtr.Zero;
pInstance = IntPtr.Zero;
Console.WriteLine("pData: {0}", pData);
Console.WriteLine("pInstance: {0}", pInstance);
return 1;
}
所有寫入控制檯完成,然後我們看到了回報可怕的崩潰:在
未處理的異常在0x04d1004c helloworld.exe:0xC0000005:訪問 違規讀取地址0x04d1004c。
如果我踏入從這裏調試器,我看到的是,在調用堆棧中的最後一項是:>「04d1004c()」的計算結果爲十進制值:80805964
哪個只有當有趣,你看這表明控制檯:
entering registerDataLogger
pointer to callback handle: 790848
fp for callback: 2631370
pointer to inst: 790844
in hReceiveLogEvent...
pInstance: 790844
pData: 80805964
exiting hReceiveLogEvent...
pInstance: 790844
pData: 80805964
Setting pData to zero...
pData: 0
pInstance: 0
現在,我知道,調試之間並釋放出一些東西都在微軟的世界完全不同。當然,我擔心字節填充和變量的初始化,所以如果有些東西我不在這裏提供,只需告訴我,我將添加到(已經很長)的文章中。我也認爲託管代碼可能不會釋放所有權,然後本機C++的東西(我沒有代碼)可能試圖刪除或關閉pData對象,從而導致應用程序崩潰。
更全面的披露,這一切工作正常(看似)在調試模式!
一個真正的頭刮傷問題,將不勝感激任何幫助!
對於支持,這是最正確的。聯繫第三方供應商後,我們發現他們使用cdecl規範進行編譯,而不是託管代碼合規性所需的stdcall:http://msdn.microsoft.com/en-us/library/367eeye0%28VS.80%29.aspx 。我在StackOverflow上添加了一個問題,詢問爲什麼需要這樣做?希望有人會比引用的MSDN文章給出更好的解釋。 – TomO 2009-09-21 15:14:30
如果未使用__declspec()指定,則在項目設置中會使用調用約定(C/C++)的默認值。該調用約定在代碼中不可見。不匹配約定會發生什麼情況很明顯:如果堆棧清理的責任不匹配,則會壓碎堆棧(由於雙重清理或太少而未重置爲調用之前的狀態)。這取決於棧上傳遞的參數的數量。 http://en.wikipedia.org/wiki/Calling_convention – jdehaan 2009-09-21 16:20:22