Получить массив строк из c ++ DLL в Delphi 7

0

Я создаю DLL в C++, он будет использоваться в проекте Delphi 7.

Этот вопрос связан с этим, когда я представляю две функции Validate и GetToken только, что теперь они будут выполнены в C++, а массив строк GetToken будет отправлен обратно в Delphi.

Проблемы в том, что я не знаю, как создать функцию в dll, которая вернет массив строки в C++, и я не знаю, как он будет храниться для дальнейшего использования в Delphi.

Объявление функции выглядит следующим образом:

function GetToken(Chain:string):Arrayofstring;

  • 1
    Как много вы знаете о взаимодействии? Вы знаете, как передавать целые числа и строки? Массивы - это еще один уровень сложности. Кто все распределяет? Звонящий или вызываемый? Как осуществляется управление памятью?
  • 0
    У меня есть метод Validate в dll (возвращает логическое значение) работает, также пытался с другими типами, такими как строки и целые числа в других примерах, и они тоже работают.
Показать ещё 2 комментария
Теги:
dll
arrays

1 ответ

2
Лучший ответ

Согласно вашему обзору кода, код Delphi ожидает, что функция будет иметь следующую подпись:

function GetToken(Chain: AnsiString): array of AnsiString;

Вы не можете записать такую функцию в C++. C++ не знает, что такое строки Delphi, и он не знает, что такое динамические массивы Delphi. Оба типа должны быть выделены из диспетчера памяти Delphi, к которым у вашей C++ DLL не будет доступа. Кроме того, C++ не знает, как использовать соглашение о register Delphi.

Интерфейс DLL был разработан плохо. DLL никогда не должны использовать типы, специфичные для языка, если только разработчик не намерен исключать все другие языки. (И в этом случае исключаются даже более поздние версии одного и того же языка, поскольку определение AnsiString изменено в Delphi 2009, чтобы включить больше метаданных, которые Delphi 7 не будет обрабатывать должным образом.) Самый безопасный вызов для выбора, как правило, является stdcall. Это то, что все в Windows API использует.

Лучший интерфейс будет использовать типы, общие для всех языков, и это будет диктовать использование управления памятью, доступное универсально. Существует несколько общих способов сделать это. Например:

  • Строки возвращаются как простые массивы символов с нуль-терминированием - PAnsiChar в Delphi; char* в C++. DLL выделяет буферы для строк, а также выделяет буфер для массива этих строк. Когда приложение хоста завершено с использованием массива и строк, оно вызывает другую функцию, экспортированную DLL, в которой DLL освобождает выделенную память. Это модель, используемая, например, FormatMessage; когда хост-программа завершена с строкой сообщения, она вызывает LocalFree.

    type
      PStringArray = ^TStringArray;
      TStringArray = array[0..Pred(MaxInt) div SizeOf(PAnsiChar)] of PAnsiChar;
    function GetToken(Char: PAnsiChar): PStringArray; stdcall;
    procedure FreeStringArray(StringArray: PStringArray); stdcall;
    
    char** __stdcall GetToken(char const* Chain);
    void __stdcall FreeStringArray(char** StringArray);
    
  • Используйте COM для возврата Safariray объектов BStr. Это похоже на предыдущую технику, но управление памятью определяется COM, а не вашей DLL, поэтому там меньше информации, которая должна быть определена любой из сторон интерфейса.

  • Передайте функцию обратного вызова в DLL, поэтому вместо того, чтобы возвращать массив строк, DLL просто вызывает функцию один раз для каждой идентифицируемой строки. Тогда вам не нужно определять, как выглядит какой-либо массив, а время жизни каждой строки может быть просто временем вызова обратного вызова - если хост-приложение хочет получить копию, оно может это сделать. Новая подпись функции будет выглядеть примерно так:

    type
      TTokenCallback = procedure(Token: PAnsiChar); stdcall;
    procedure GetToken(Chain: PAnsiChar; ProcessToken: TTokenCallback); stdcall;
    
    typedef void (__stdcall* TokenCallback)(char const* Token);
    void __stdcall GetToken(char const* Chain, TokenCallback ProcessToken);
    

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню