需要在C++中调用Delphi DLL的简单演示

发布于 2024-12-12 05:38:40 字数 403 浏览 0 评论 0原文

我不能很好地使用 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++ 创建简单的代码来调用 hello 函数并获取结果,感谢帮助。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烂柯人 2024-12-19 05:38:40

您正在尝试将 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));
...

同一种代码可以如果您需要在 Delphi 中使用相同的 DLL,可以很容易地转换为 Pascal:

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;

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;
黎夕旧梦 2024-12-19 05:38:40

更新 事实证明,Delphi 对 WideString 返回值使用了非标准调用约定。所以下面的代码将不起作用。基本概念是合理的,但您需要返回 BSTR 或使用 WideString 类型的 out 参数。更多详细信息请参见:为什么 WideString 不能用作互操作的函数返回值?


只要调用者知道要分配多大的缓冲区,Remy 的方法就很好。另一种方法是在 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 中的实际函数更复杂,那么这种方法的优势就更明显。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文