В Delphi в моей DLL мне нужно выделить возвращаемый pchar функции

у меня есть 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 ответов


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

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

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

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


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

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

Function GetNameStr : PChar;
Asm
  Call   @OverText
  DB     'Some text',0
@OverText:
  Pop    EAX
End;