1

.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);

ただし、それでも同じ例外が発生します。

4

2 に答える 2

1

使い方がMarshal.PtrToStructure間違っています。

2 番目の引数には、タイプ iow が必要ですtypeof(EMI)

戻り値には、結果の構造体が含まれます。

したがって、解決策は次のようになります。

var s = (EMI) Marshal.PtrToStructure(emiIntPtr, typeof(EMI));
于 2011-08-23T10:34:20.457 に答える
0

私の推測では、C# で最初のパラメーターを間違って宣言したと思われます。C++ の EMI** に相当する ref IntPtr として宣言しました。しかし、残念ながらあなたが含めなかった C++ 宣言は、EMI* を読み取るに違いありません。したがって、単に参照を削除すると、すべてがうまくいくはずです。

私は、emi_init が EMI パラメータから読み取らないことを期待しています。つまり、セマンティクスがありません。この場合、emi_init を呼び出す前に StructureToPtr を呼び出す必要はありません。

于 2011-08-23T11:39:15.627 に答える