Безопасно ли передавать константные строковые параметры Delphi через границы диспетчера памяти? - PullRequest
7 голосов
/ 05 июля 2010

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

procedure SomeExternalProc(s: string); external SOMEDLL_DLL;

, а затем реализую его в каком-то другом проекте с менеджером не разделяемой памяти:

library SeparateDll;
procedure SomeExternalProc(s: string);
begin
  //a bla bla bla
  //code here code here
end;

У меня (формально) нет никаких гарантий, Delphi не решает по какой-либо причине изменить строку, изменить ее счетчик ссылок, продублировать или уникально, или что-то еще.Например,

var InternalString: string;

procedure SomeExternalProc(s: string);
begin
  InternalString := s;
end;

Delphi увеличивает refcounter и копирует указатель, вот и все.Я бы хотел, чтобы Delphi скопировал данные.Делает ли объявление параметра «const» безопасным по этой причине?Если нет, есть ли способ сделать это?Объявление параметра как PChar не похоже на решение, потому что вам нужно приводить его каждый раз:

procedure SomeExternalProc(s: Pchar); forward;
procedure LocalProc;
var local_s: string;
begin
  SomeExternalProc(local_s); //<<--- incompatible types: 'string' and 'PAnsiChar'
end;

Ответы [ 4 ]

13 голосов
/ 05 июля 2010

Это, вероятно, сработает, если вы когда-либо используете свою DLL из кода, скомпилированного в той же версии Delphi. Известно, что внутренний формат string изменяется между выпусками, и у вас нет официальной гарантии, что он не изменится снова.

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

procedure SomeExternalProc(s: Pchar); external dllname;
procedure MyExternalProc(s: string); inline;
begin
  SomeExternalProc(PChar(local_s));
end;

Затем в своем коде вы звоните MyExternalProc вместо SomeExternalProc, и все счастливы.

6 голосов
/ 05 июля 2010

Если и приложение, и DLL написаны в одном выпуске Delphi, просто используйте диспетчер общей памяти (подробнее здесь ).

Если одна сторона написана на другом языкекроме как нет другого способа, кроме как использовать PChar или WideString (WideStrings управляются диспетчером памяти COM).

Или вы можете написать функцию-обертку:

procedure MyExternalProc(const s: string);
begin
  SomeExternalProc(PChar(s));
end;
0 голосов
/ 06 июля 2010

Просто чтобы добавить один факт:

Delphi позволяет вам просто назначить PChar для строки, так что на стороне DLL вам не понадобится Typecast:

function MyDllFunction(_s: PChar): integer;
var
  s: string;
begin
  s := _s; // implicit conversion to string

  // now work with s instead of the _s parameter
end;

Это также относится к передаче PChar в качестве параметра функции, которая ожидает (по значению) строку.

0 голосов
/ 05 июля 2010

Я рекомендую использовать альтернативный менеджер памяти, такой как RecyclerMM или FastMM.Они не требуют внешних общих dll MM и позволяют безопасно передавать строки в dll.В качестве бонуса вы можете получить хорошее улучшение производительности всего приложения.

FastMM используется в качестве менеджера памяти по умолчанию в Delphi 2006 и выше.Также это хороший инструмент для поиска утечек памяти.

...