Действительно ли безопасно передать строковые параметрические усилители константы Delphi через границы диспетчера памяти?

Тема. Я хотел бы использовать строки вместо 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 скопировал данные. Объявление параметра как "константа" делают это безопасным по этой причине? В противном случае есть ли способ сделать это? При объявлении параметра, поскольку PChar, кажется, не решение, потому что необходимо бросить его каждый раз:

procedure SomeExternalProc(s: Pchar); forward;
procedure LocalProc;
var local_s: string;
begin
  SomeExternalProc(local_s); //<<--- incompatible types: 'string' and 'PAnsiChar'
end;
7
задан himself 5 July 2010 в 10:47
поделиться

4 ответа

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

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

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

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

13
ответ дан 6 December 2019 в 10:47
поделиться

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

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

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

procedure MyExternalProc(const s: string);
begin
  SomeExternalProc(PChar(s));
end;
6
ответ дан 6 December 2019 в 10:47
поделиться

Только добавлю один факт:

Delphi позволяет вам просто присвоить PChar строке, так что на стороне DLL вам не нужен никакой типокаст:

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
ответ дан 6 December 2019 в 10:47
поделиться

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

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

-1
ответ дан 6 December 2019 в 10:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: