Нужна простая демонстрационная версия Delphi DLL в C ++ - PullRequest
2 голосов
/ 28 октября 2011

Я плохо работаю с C ++, но теперь мне нужно создать функцию, которая вызывает Delphi DLL и передает строку в DLL и возвращает новую строку.

вот мой код Delphi DLL:

library testdll;
uses
  System.Classes,Winapi.Windows,System.SysUtils;
{$R *.res}

function hello(name : PWideChar):PWideChar;
var
rs:PWideChar;
begin
  rs:=PWideChar('Hello '+rs);
  Result:=rs;
end;

exports
hello;
begin
end.

Любой может помочь мне создать простой код на C ++ для вызова и получения приветственной функции из формы результатов, спасибо за помощь.

Ответы [ 2 ]

5 голосов
/ 28 октября 2011

Вы пытаетесь объединить PWideChar со строковым литералом и вернуть его как другой PWideChar. Это не будет работать как есть. Вы не должны возвращать PWideChar в любом случае. Это приводит к кошмарам управления памятью. Лучшее решение - позволить вызывающей стороне передать буфер в DLL для заполнения, например:

library testdll;

uses
  System.Classes,
  Winapi.Windows,
  System.SysUtils;

{$R *.res}

function hello(name, buffer : PWideChar; buflen: Integer): Integer; stdcall;
var
  rs: UnicodeString;
begin
  rs := 'Hello '+UnicodeString(name);
  if buffer = nil then
  begin
    Result := Length(rs) + 1;
  end else
  begin
    Result := Min(buflen, Length(rs));
    Move(rs[1], buffer^, Result * SizeOf(WideChar));
  end;
end;

exports
  hello;

begin
end.

Тогда, учитывая это объявление C ++ ::

int __stdcall hello(wchar_t* name, wchar_t* buffer, int buflen);

Вы можете называть это разными способами, в зависимости от ваших потребностей:

wchar_t str[256];
int len = hello(L"joe", str, 255);
str[len] = 0;
...

int len = hello(L"joe", NULL, 0);
wchar_t *str = new wchar_t[len];
len = hello(L"joe", str, len);
str[len] = 0;
...
delete[] str;

int len = hello(L"joe", NULL, 0);
std::wstring str(len-1);
str.resize(hello(L"joe", &str[0], len));
...

int len = hello(L"joe", NULL, 0);
UnicodeString str;
str.SetLength(len-1);
str.SetLength(hello(L"joe", str.c_str(), len));
...

Код того же типа можно очень легко перевести на Pascal, если вам когда-либо понадобится использовать ту же DLL в Delphi:

function hello(name, buffer: PWideChar, buflen: Integer): Integer; stdcall; extern 'testdll.dll';


var
  str: array[0..255] of WideChar;
  len: Integer;
begin
  len := hello('joe', str, 255);
  str[len] := #0;
  ...
end;


var
  str; PWideChar
  len; Integer;
begin
  len := hello('joe', nil, 0);
  GetMem(str, len];
  len := hello('joe', str, len);
  str[len] := #0;
  ...
  FreeMem(str);
end;


var
  str; UnicodeString;
  len; Integer;
begin
  len := hello('joe', nil, 0);
  SetLength(str, len-1);
  SetLength(str, hello('joe', PWideChar(str), len));
  ...
end;
3 голосов
/ 28 октября 2011

Обновление Оказывается, что Delphi использует нестандартное соглашение о вызовах для WideString возвращаемых значений.Так что код ниже не будет работать.Основная концепция - это звук, но вам нужно вернуть BSTR или использовать параметр out типа WideString.Подробнее здесь: Почему WideString не может использоваться как возвращаемое функцией значение для взаимодействия?


Подход Реми хорош, пока вызывающая сторона знает, насколько большой буфер выделяется,Альтернативный подход заключается в выделении памяти в DLL и освобождении памяти вызывающей стороной.Это работает, только если обе стороны используют один и тот же распределитель.Примером общего распределителя является COM-распределитель, и COM BSTR, конечно, использует это.В Delphi BSTR отображается на WideString, что дает нам следующий подход:

Delphi

function concat(s1, s2: PWideChar): WideString; stdcall;
begin
  Result := s1 + s2;
end;

C ++

// DLL import
BSTR __stdcall concat(wchar_t *s1, wchar_t *s2);

BSTR bstr_res = concat(L"Wello, ", L"world!");
std::wstring res(bstr_res);
SysFreeString(bstr_res);

Очевидно, что в этом простом примере необходимый размер буфера для объединенной строки легко вычислить.Но если бы реальная функция в DLL была более сложной, то такой подход стал бы более очевидным.

...