В 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;