В Delphi в моей DLL я должен выделить возврат pchar функции - PullRequest
8 голосов
/ 24 ноября 2010

У меня есть DLL, в которой у меня есть функция, которая возвращает pchar. (чтобы избежать необходимости использовать borlndmm) Первоначально я делал приведение строки как pchar и возвращал

Result := pChar(SomeFuncThatReturnsString)

Но в 90% случаев я получал ожидаемые результаты, а в остальное время ничего не получал.

Затем я подумал, что мне нужно выделить память для pchar, и что при моем первоначальном подходе у меня была точка pchar в памяти, которая не всегда была той, что была при первоначальном вызове функции. Так что теперь у меня есть это

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

Но это оставляет мне необходимость очищать выделенную память на конце программ, что я делаю с

StrDispose(Pstr);    

Итак, вопрос за 64 доллара: нужно ли выделять память при возврате PChar из функции внутри DLL или я могу просто привести ее к PChar?

Ответы [ 3 ]

7 голосов
/ 24 ноября 2010

Типичный подход к этой проблеме - приложение распределяет память, а затем передает ее в 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;
5 голосов
/ 24 ноября 2010

DLL и ваше основное приложение имеют два разных менеджера памяти, поэтому неправильно выделять память в DLL, но освобождать ее в основном приложении и наоборот.

Вы можете использовать тип WideString для возврата строки из dll или передачи ее в dll - WideString является оболочкой для системного типа BSTR, а память для переменных WideString автоматически распределяется администратором системной памяти.

Другим решением является использование SimpleShareMem вместо ShareMem (только Delphi 2007 и старше) - он работает как ShareMem, но не требует каких-либо библиотек, похожих на borlnmm.dll, для повторного распространения.

1 голос
/ 26 ноября 2010

Когда вы возвращаете строку как PChar из функции, строка хранится в стеке, поэтому иногда она искажается. Я использую память кучи процесса для возврата строк или указатель на глобальный буферный массив символов.

Также вы можете использовать встроенный ассемблер и сделать это:

Function GetNameStr : PChar;
Asm
  Call   @OverText
  DB     'Some text',0
@OverText:
  Pop    EAX
End;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...