この問題への一般的なアプローチは、アプリにメモリを割り当てさせてから、それを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;