Need simple demo call Delphi DLL in C++

2019-01-27 02:49发布

i don't work well with C++ but now i need build a function that call Delphi DLL and pass a string to DLL and get return new string.

here is my Delphi DLL code:

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.

Anyone can help me create simple code in C++ to call and get result form hello function, thank for help.

标签: c++ delphi dll
2条回答
干净又极端
2楼-- · 2019-01-27 03:26

Update It turns out that Delphi uses a non-standard calling convention for WideString return values. So the code below won't work. The basic concept is sound but you need to return BSTR or use an out parameter of type WideString. More details here: Why can a WideString not be used as a function return value for interop?


Remy's approach is good so long as the caller knows how big a buffer to allocate. An alternative approach is to allocate memory in the DLL and have the caller free the memory. This only works if both parties use the same allocator. An example of a shared allocator is the COM allocator and COM BSTR of course uses this. In Delphi a BSTR maps to WideString which gives us the following approach.

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

Obviously in this simple example, the required buffer size for the concatenated string is simple to calculate. But if the actual function in the DLL was more complex then this approach would become more obviously advantageous.

查看更多
劳资没心,怎么记你
3楼-- · 2019-01-27 03:35

You are trying to concat a PWideChar to a String literal and return it as another PWideChar. That will not work as-is. You should not be returning a PWideChar anyway. That leads to memory management nightmares. A better design is to let the caller pass a buffer into the DLL to fill in instead, eg:

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.

Then, given this C++ declaration::

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

You can call it all kinds of different ways, depending on your needs:

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));
...

The same kind of code can be translated to Pascal very easily if you ever need to use the same DLL in 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;
查看更多
登录 后发表回答