1

ネイティブ(Delphi 7)関数は次のとおりです。

function Foo(const PAnsiChar input) : PAnsiChar; stdcall; export;
var
  s : string;
begin
    s := SomeInternalMethod(input);
    Result := PAnsiChar(s);
end;

これを C# から呼び出す必要がありますが、コンパイル時に dll の名前がわからないため、LoadLibrary を使用して取得する必要があります。

これまでのところ、私の C# コードは次のようになります。

[DllImport("kernel32.dll")]
public extern static IntPtr LoadLibrary(String lpFileName);

[DllImport("kernel32.dll")]
public extern static IntPtr GetProcAddress(IntPtr handle, string funcName);

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate string FooFunction(string input);

...

IntPtr dllHandle = LoadLibrary(dllName);
IntPtr fooProcAddr = GetProcAddress(dllHandle, "Foo");

FooFunction foo = (FooFunction)Marshal.GetDelegateForFunctionPointer(
    fooProcAddr, typeof(FooFuncion)
);

string output = foo(myInputString);

これで実際に動作します。少なくとも、Delphi コードは文字列を正しく受け取り、C# コードは出力文字列を受け取ります。

ただし、C# コードから呼び出されたときに Delphi コードをデバッグするときに、奇妙な点に気付きました。

そして、私はメモリをリークしているのではないかと心配しています - 誰かがそれらの PChars をクリーンアップしていますか?

これをどのように行うべきかについて、フィードバックやアドバイスをくれる人はいますか?

4

2 に答える 2

3

あなたができる唯一の合理的なことは、この関数を破棄して書き直すことです。これが機能する方法はありません。sFoo()関数のローカル文字列変数であるため、文字列が占有するメモリは、終了時に解放されますFoo()。返されるポインターは無効なメモリ位置を指していますが、これには偶然にも文字列データが含まれています。メモリへのポインタが解放されたときにメモリをクリアするメモリマネージャを使用すると、データが含まれなくなります。メモリが再利用されると、何か他のものが含まれます。そのメモリのチャンクを含むブロックが解放されると、AV が発生します。

DLL から文字シーケンス データを返す方法については、StackOverflow でさらに質問があります。Windows API がビジネスを行う方法と互換性のある文字列型である COM 文字列を使用するか、事前に割り当てられたバッファーを関数に渡してデータを入力します。後者の場合、すべての同様の API 関数と同様に、関数を使用する同じ方法を使用できます。

于 2009-11-10T05:14:41.613 に答える
2

メモリリークの検出には、Delphi用のオープンソースのFastMM4メモリマネージャを使用できます。

「FastMMは、Embarcadero Delphi Win32アプリケーション用の超高速の代替メモリマネージャであり、マルチスレッドアプリケーションで適切に拡張でき、メモリの断片化が発生しにくく、外部の.DLLファイルを使用せずに共有メモリをサポートします。」

速度、リークチェック、dll間のメモリ共有に最適です。

また、FastMM4の構成に役立つFastMM4オプションインターフェイスも非常に便利です。

于 2009-11-10T12:43:26.797 に答える