私は、最終的な使用のためにC++/CLIでラッパーを構築するために使用した(.libと.hppファイルで)作業しているネイティブのサードパーティのC++コードベースを持っていますC#で。C++コールバックからC#関数へのアクセス違反例外/クラッシュ
私は、デバッグモードからリリースモードに切り替えるときに特に問題に遭遇しました。コールバックのコードが返ってくると、アクセス違反例外が発生します。
コールバック関数形式のオリジナルHPPファイルからコード:コールバック関数形式のC++/CLIラッパーから
typedef int (*CallbackFunction) (void *inst, const void *data);
コード: (私はその瞬間に2を宣言した理由を私は説明します)
public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
--Quickly、私は2番目「UnManagedCallbackFunctionは」私はラッパーに「仲介」コールバックを作成しようとしましたので、チェーン>はネイティブC++のバージョンにネイティブC++> C#のから変更されたことであると宣言理由C++/CLI Wrapper> C#...フル・リリースure、問題はまだ生きている、それはちょうど同じ行(戻り値)に今すぐC + +/CLIのラッパーにプッシュされています。
そして最後に、C#のからクラッシュコード:
0x04d1004cで未処理の例外 に:
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; }
すべてが行われ、その後、我々はリターンに恐ろしいクラッシュを見ているコンソールへの書き込みhelloworld.exe:0xC0000005:アクセス 違反の読み取り場所0x04d1004c。
私はここからデバッガにステップ場合は、私が見るすべては、コールスタック上の最後のエントリがあるということである:ある80805964
:10進値に評価>「04d1004c()」あなたが示しコンソールを見ればのみ興味深い:
今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
を、私はデバッグの間とMicrosoftの世界ではかなり異なっているいくつかのことを解放することを知っています。私はもちろん、バイトパディングと変数の初期化について心配しています。もし私がここで提供していないものがあれば、私に知らせてください。私は(すでに長い)投稿に追加します。私はまた、マネージコードがすべての所有権を解放していない可能性があり、ネイティブC + +のもの(私はコードを持っていない)削除またはpDataオブジェクトを殺すため、アプリをクラッシュしようとしている可能性があります。
さらに詳細な情報があれば、デバッグモードではうまく動作します。
実際のヘッドスクラッチ問題は、どんな助けにも感謝します!
ほとんどの場合、サポートが必要でした。サードパーティのベンダーに連絡した後、私たちはcdecl specを使用してコンパイルし、Managed Code Complianceに必要なstdcallではないことを発見しました。http://msdn.microsoft.com/en-us/library/367eeye0%28VS.80%29.aspx 。 StackOverflowの質問を追加して、これがなぜ必要なのか尋ねます。うまくいけば、誰かが参照されているMSDNの記事よりも良い説明を与えるでしょう。 – TomO
プロジェクト設定では、__declspec()で指定されていない場合、使用される呼び出し規約(C/C++)の既定値があります。この呼び出し規約はコード内では見えませんでした。スタックのクリーンアップの責任が一致しない場合、スタックを破壊します(ダブルクリーンアップまたは少なすぎるためにコールの前の状態にリセットされません)。これは、スタックに渡される引数の量によって異なります。 http://en.wikipedia.org/wiki/Calling_convention – jdehaan