2

.NET 4.0 で実行されている Windows フォーム アプリケーションがあります。このアプリケーションは、以下で使用できる DLL をインポートします。

  • 32ビット
  • 64ビット

ここに私のコードスニペットがあります:

[DllImport("my64Bit.dll"), EntryPoint="GetLastErrorText"]
private static extern string GetLastErrorText();

// Do some stuff...

string message = GetLastErrorText();

この関数 (x64 用にコンパイル) を呼び出すと、アプリケーションがクラッシュします。Visual Studio 2012 でデバッグ メッセージすら表示されません。32 ビット DLL (x86 用にコンパイル) と同じコードは問題なく動作します。プロトタイプは次のとおりです。

LPCSTR APIENTRY GetLastErrorText()

残念ながら、DLL はサードパーティ製品であるため、これ以上の情報はありません。

4

2 に答える 2

5

関数のシグネチャは非常に面倒です。コードがクラッシュするかどうかは、実行しているオペレーティングシステムによって異なります。XPでは何も起こりません。Vista以降ではAccessViolation例外がスローされます。

問題は、文字列を返すC関数は通常、文字列を格納するバッファへのポインタを返すことによってそうする必要があるということです。そのバッファはヒープから割り当てる必要があり、呼び出し元は文字列を使用した後にそのバッファを解放する必要があります。pinvokeマーシャラーはそのコントラクトを実装し、System.Stringに変換した後、返された文字列ポインターでCoTaskMemFree()を呼び出します。

それは常にうまくいかず、C関数がCoTaskMemAlloc()を使用してバッファーを割り当てることはほとんどありません。XPヒープマネージャは非常に寛容であり、単に不正なポインタを無視します。それ以降のWindowsバージョンではなく、意図的に例外を生成します。「Vistasucks」ラベルの強力なイネーブラーですが、プログラマーがポインターのバグを修正するのにしばらく時間がかかりました。アンマネージデバッグを有効にしている場合は、ヒープマネージャーから、ポインターが無効であることを警告する診断が表示されます。非常に優れた機能ですが、マネージコードをデバッグする場合、アンマネージデバッグは常に無効になります。

戻り値をIntPtrとして宣言することにより、pinvokeマーシャラーが文字列を解放しようとするのを防ぐことができます。次に、Marshal.PtrToStringAnsi()またはその友人の1人を使用して文字列を自分でマーシャリングする必要があります。

あなたはまだ文字列バッファを解放しなければならないという問題を抱えています。これを確実に行う方法はありません。適切なデアロケーターを呼び出すことはできません。唯一の希望は、C関数が実際に文字列リテラルへのポインタを返すことです。文字列リテラルはデータセグメントに格納されているため、解放しないでください。これは、ローカリゼーションのような凝ったものを実装していなければ、エラー文字列を返す関数で機能する可能性があります。constchar*リターン型は有望です。

これをテストして、文字列バッファを解放しないことによるメモリリークがないことを確認する必要があります。簡単に実行できます。この関数をループで10億回呼び出します。IntPtr.Zeroを戻り値として取得せず、プログラムがメモリ不足の例外でフォールオーバーしない場合は、問題ありません。64ビットのピンボークの場合、テストプログラムのメモリ消費量を監視する必要があります。

于 2012-12-18T14:01:59.673 に答える
2

それを見つけた。ネイティブ関数は を返しますLPCSTR。つまり、C# 関数は文字列を返すことができません。代わりに、次のIntPtrように返す必要があります。

[DllImport("my64Bit.dll"), EntryPoint="GetLastErrorText"]
private static extern IntPtr GetLastErrorText();

// Do some stuff...

IntPtr ptr = GetLastErrorText();
string s = Marshal.PtrToStringAnsi(ptr);
于 2012-12-18T13:43:47.517 に答える