.NET で C++ DLL (EMI プロトコルを実装し、ソース コードを利用できるサード パーティ ライブラリ) を使用しようとしています。マーシャリング、関数の呼び出し、すべてが正常に機能するようになりました。
この問題は、IntPtr から .NET Struct にマーシャリングを戻したいときに発生します。コードは次のとおりです (提案どおりに変更 - 「ref」を削除し、AllocHGlobal を変更して emiStruct のサイズを割り当てるようにしました)。
private EMI emiStruct;
private IntPtr emiIntPtr;
emiIntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(emiStruct));
Marshal.StructureToPtr(emiStruct, emiIntPtr, false);
EMIStruct.Error result = emi_init(emiIntPtr, hostname, portNumber, password, shortNumber, windowSize, throughput);
Marshal.PtrToStructure(emiIntPtr, emiStruct);
最後の行 (PtrToStructure) により、「保護されたメモリを読み書きしようとしました。これは多くの場合、他のメモリが破損していることを示しています」という例外が発生します。
また、デバッグ出力を確認できます。
A first chance exception of type 'System.AccessViolationException' occurred in mscorlib.dll
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0xc3fffff8.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x01fffff7.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x00001f1d.
問題は、ポインター emiIntPtr のメモリ割り当てのどこかにあると思います。ただし、コードを実行すると、サーバーへの接続に問題が発生します (サーバーが見つからないなど) が、続く構造体 emiStruct へのマーシャリングは正しく行われます (例外なし)。この問題は、接続が正常に確立され、サーバーが応答を送信した場合にのみ発生します。
また、.NET で使用しようとしているのと同じ DLL ライブラリを使用して C++ サンプル アプリを作成しました。このアプリケーションは (コンパイルすると) 正常に動作します。つまり、C++ DLL は問題なく、クラッシュを引き起こさないはずです。
さらに、プロジェクト コンパイラのいくつかのプロパティをチェック/チェック解除するためのいくつかのヒントを見つけました (JIT を使用する、x86 cpu 用にコンパイルするなど)。残念ながら、これは役に立ちませんでした。
問題がどこにあるのか、または .NET で IntPtr を正しく初期化して IntPtr と Struct をマッピングする方法について何か提案はありますか?
返信ありがとうございます:
ここでは、emi_init 関数の C++ ヘッダーを追加しています。
FUNC( init)( EMI* emi, /* out */
const char* hostname, /* in */
unsigned short port, /* in */
const char* password, /* in */
const char* origin_addr, /* in */
int window_sz, /* in */
int throughput); /* in */
C# の emi_init 宣言は次のとおりです (提案されたように、emiPtr の "ref" 属性を削除しました)。
[System.Runtime.InteropServices.DllImport("emi.dll", EntryPoint = "_emi_init")]
public static extern EMIStruct.Error emi_init(
System.IntPtr emiPtr,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string hostname,
ushort port,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string password,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string origin_addr,
int window_sz, int throughput);
ただし、それでも同じ例外が発生します。