10

pcharを返す関数を含むDLLがあります。(borlndmmを使用する必要がないように)私が最初に行っていたのは、文字列をpcharとしてキャストし、それを返すことでした。

Result := pChar(SomeFuncThatReturnsString)

しかし、90%の確率で期待どおりの結果が得られ、それ以外の場合は何も返されませんでした。

次に、pcharにメモリを割り当てる必要があること、そしてそれを元の方法で行うことは、関数が最初に呼び出されたときに常に存在するわけではないメモリをpcharポイントにすることであると考えるようになりました。だから私は今これを持っています

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

しかし、これは私が行うプログラムの終わりに割り当てられたメモリをクリーンアップする必要があります

StrDispose(Pstr);    

したがって、64ドルの質問は次のとおりです。DLL内の関数からPCharを返すときにメモリを割り当てる必要がありますか、それともPCharにキャストするだけですか。

4

3 に答える 3

10

この問題への一般的なアプローチは、アプリにメモリを割り当てさせてから、それをDLLに渡して入力することです(DLLがアプリに割り当てる必要のあるメモリの量を照会できるようにして、過剰に割り当てる必要がない場合はさらに良いでしょう。メモリの割り当て):

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;

これにより、アプリはメモリをいつどのように割り当てるか(スタックとヒープ、メモリブロックの再利用など)を決定できます。

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;

これがオプションでない場合は、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;
于 2010-11-24T19:51:14.167 に答える
5

DLLとメインアプリには2つの異なるメモリマネージャーがあるため、DLLにメモリを割り当てるのは正しくありませんが、メインアプリでメモリを解放します。その逆も同様です。

WideStringタイプを使用して、dllから文字列を返すかdllに渡すことができます— WideStringはシステムBSTRタイプのラッパーであり、WideString変数のメモリはシステムメモリマネージャによって自動的に割り当てられます。

もう1つの解決策は、ShareMemの代わりにSimpleShareMemを使用することです(Delphi 2007以前のみ)。ShareMemと同様に機能しますが、再配布するためにborlnmm.dllのようなライブラリは必要ありません。

于 2010-11-24T17:40:01.023 に答える
1

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

また、組み込みアセンブラを使用してこれを行うこともできます。

Function GetNameStr : PChar;
Asm
  Call   @OverText
  DB     'Some text',0
@OverText:
  Pop    EAX
End;
于 2010-11-26T05:29:22.377 に答える