そのため、C# で最終的に使用するために C++/CLI でラッパーを構築するために使用したネイティブ サード パーティの C++ コード ベース (.lib および .hpp ファイル) を使用しています。
デバッグ モードからリリース モードに切り替えるときに、コールバックのコードが返されたときにアクセス違反例外が発生するという特定の問題に遭遇しました。
コールバック関数形式の元の hpp ファイルのコード:
typedef int (*CallbackFunction) (void *inst, const void *data);
コールバック関数形式の C++/CLI ラッパーからのコード: (すぐに 2 つ宣言した理由を説明します)
public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
-- 簡単に言うと、2 つ目の「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;
}
コンソールへのすべての書き込みが完了すると、戻ってきたときに恐ろしいクラッシュが発生します。
helloworld.exe の 0x04d1004c で未処理の例外: 0xC0000005: アクセス違反の読み取り場所 0x04d1004c.
ここからデバッガーにステップインすると、コール スタックの最後のエントリが次のようになるだけです: > "04d1004c()" これは 10 進数値として評価されます:
これは、次のようなコンソールを見る場合にのみ興味深いものです。
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 オブジェクトを削除または強制終了しようとして、アプリがクラッシュする可能性があると思います。
より完全な開示、それはすべてデバッグモードで(一見)正常に動作します!
どんな助けにも感謝する本当のヘッドスクラッチの問題!