2010-11-24 22 views
8

私はpcharを返す関数を持つDLLを持っています。私のDLLのDelphiでは、関数の戻りpcharを割り当てる必要があります

Result := pChar(SomeFuncThatReturnsString) 

その私はもともとPChar型として文字列をキャストして返していました何をやっていた(borlndmmを使用する必要がないように、など)しかし、私は時間の予想結果の90%を取得し、私は戻ってになるだろう、他の回ました何もない。

私はpcharにメモリを割り当てる必要があると思っていました。私のオリジナルのやり方では、関数が元々呼び出されたときにあったものではないメモリへのpcharポイントがありました。だから私は今、この

Result := StrAlloc(128); 
Strcopy(Result,PAnsiChar(Hash(Hash(Code,1,128),2,128))); 

を持っている。しかしこれには、$ 64個の質問がされ、私は

StrDispose(Pstr);  

を行うプログラムの最後に割り当てられたメモリをクリーンアップすることを私に残します:私が割り当てする必要がありますかDLL内の関数からPCharを返すときのメモリ、またはPCharにキャストできますか?

答えて

7

この問題の典型的なアプローチは、メモリにメモリを割り当て、それを埋め込むためにDLLに渡すようにすることです(DLLによって割り当てが必要なメモリをオーバー-割り当てるメモリ)する必要があります。これがあれば

var 
    S: String; 
begin 
    SetLength(S, 256); 
    SetLength(S, GetAString(PChar(S), 256)); 
    ... 
end; 

var 
    S: String; 
begin 
    SetLength(S, GetAString(nil, 0)); 
    if Length(S) > 0 then GetAString(PChar(S), Length(S)); 
    ... 
end; 

var 
    S: array[0..255] of Char; 
    Len: Integer; 
begin 
    Len := GetAString(S, 256); 
    ... 
end; 

:これは、いつ、どのようにメモリを割り当てるために決定することをアプリに許可します

function GetAString(Buffer: PChar; BufLen: Integer): Integer; stdcall; 
var 
    S: String; 
begin 
    S := SomeFuncThatReturnsString; 
    Result := Min(BufLen, Length(S)); 
    if (Buffer <> nil) and (Result > 0) then 
    Move(S[1], Buffer^, Result * SizeOf(Char)); 
end; 

(メモリ・ブロックなど)を再利用し、ヒープ対スタックあなたのためのオプションではない、その後、DLLをメモリを割り当てる必要が返す使用のためのアプリにそれ、その後、DLLは、解放のために戻ってDLLへのポインタを渡すために行われたときにアプリが呼び出すことができるという追加の関数をエクスポートしています

function GetAString: PChar; stdcall; 
var 
    S: String; 
begin 
    S := SomeFuncThatReturnsString; 
    if S <> '' then 
    begin 
    Result := StrAlloc(Length(S)+1); 
    StrPCopy(Result, S); 
    end else 
    Result := nil; 
end; 

procedure FreeAString(AStr: PChar); stdcall; 
begin 
    StrDispose(AStr); 
end; 

var 
    S: PChar; 
begin 
    S := GetAString; 
    if S <> nil then 
    try 
    ... 
    finally 
    FreeAString(S); 
    end; 
end; 
+0

シャットダウン機能を公開しているのは、Windows 3.1がfdwReason = DLL_PROCESS_DETACHのときにDllMainのクリーンアップだけです。 –

+0

それは私の答えと何が関係していますか?また、DllMain()では必ずしもクリーンアップが可能であるとは限りません。DllMain()の内部では安全に実行できない操作がいくつかあります。 –

+0

"WEP(Windows終了プロシージャ)コールバック関数は、ライブラリがアンロードされる前にダイナミックリンクライブラリ(DLL)のクリーンアップを実行します。それはあなたが提案したものではありませんか?再:安全でない操作 - 例を与えるケア? –

5

DLLとメインアプリケーションには2つの異なるメモリマネージャがあるため、DLLにメモリを割り当ててもメインアプリケーションでメモリを解放するのは間違いです。

dllから文字列を返すか、dllに渡すためにWideString型を使用できます。 - WideStringはシステムBSTR型のラッパーで、WideString変数のメモリはシステムメモリマネージャによって自動的に割り当てられます。

ShareMemの代わりにSimpleShareMem(Delphi 2007以前のみ)を使用することもできます。これはShareMemのように動作しますが、再配布するためにborlnmm.dllのようなライブラリは必要ありません。

+1

これを? http://edn.embarcadero.com/article/33416 –

+0

はい、 "ShareMemoryManager"セクション。そして、私の間違いは、2007年ではなく、デルファイ2006から新しいメモリマネージャーが利用可能です。 –

1

あなたはPChar型として文字列を返すときfunctionから文字列がスタックに保持されているため、時には破損していることがあります。私は、文字列を返すためのプロセスヒープメモリ、または文字のグローバルバッファ配列へのポインタを使用します。

また、あなたは、組み込みアセンブラで使用することができますし、これを実行します。右、

Function GetNameStr : PChar; 
Asm 
    Call @OverText 
    DB  'Some text',0 
@OverText: 
    Pop EAX 
End; 
関連する問題