5

次の C 関数を想定します。

void do_something(const char* str)

後で参照できるように、文字列をどこかに保存します。

さらに、この関数を呼び出すために C# で次のシグネチャを使用しています。

[DllImport("NativeLib")]
static extern void do_something(string str);

さて、このメソッドに文字列を渡すときに何をする必要がありますか:

  • 文字列を固定する必要がありますか (でGCHandle.Alloc()) (またはマーシャラーがコピーを作成していますか)?
  • ピン留めする必要がある場合、「元の」文字列 (つまり、渡した文字列) を渡す必要がありますGCHandle.Alloc()か? または、戻り値を渡す必要がありGCHandle.AddrOfPinnedObject()ますか?
  • stringこの場合、 ( の) 正しいデータ型はありますdo_somethingか? または、IntPtr代わりに使用する必要がありますか?
4

2 に答える 2

7

相互運用境界を介してポインターを保存することは、本当に悪い考えです。代わりに、C コードを変更して文字列のコピーを作成するためにできる限りのことを行ってください。

賛成の回答で提案されているように文字列をピン留めしてもうまくいきません。pinvoke マーシャラーは文字列を char* に変換し、ネイティブ呼び出しを行った後にその変換された文字列を解放し、ポインターを無効にする必要があります。文字列を自分でマーシャリングする必要があります。引数を IntPtr として宣言し、Marshal.StringToHGlobalAnsi() を使用してポインター値を作成します。

または、Marshal.StringToCoTaskMemAnsi() を使用して、COM ヒープから割り当てます。これがあなたの本当の問題です。文字列を解放する素晴らしいシナリオはありません。C コードは、文字列がどのように割り当てられたかがわからないため、文字列を解放できません。あなたの C# コードは文字列を解放できません。これは、C コードがいつポインターを使用して終了したかがわからないためです。これが、文字列のコピーが非常に重要な理由です。この呼び出しを数回しか行わない場合は、メモリ リークに耐えることができます。

于 2012-06-11T12:31:36.047 に答える
0

アンマネージコードは文字列をコピーするのではなくポインタを格納するため、GCHandle.Alloc()を使用して文字列のコピーを手動で作成し、IntPtrとして渡すことをお勧めします。

その後、渡されたメモリブロックの存続期間を管理できるようになり、使い終わったときにのみ(GCHandleを介して)解放します。

于 2012-06-11T11:41:01.017 に答える