gpt4 book ai didi

c++ - 从 C++ 调用 Delphi DLL 函数

转载 作者:行者123 更新时间:2023-11-28 04:14:33 24 4
gpt4 key购买 nike

我已经用 Delphi 编写了一个 DLL,现在我需要从 C++ 代码测试这个 DLL 的一个功能。

我以前从未使用过 C++。我安装了 Code::Blocks 并尝试用 C++ 编写代码。

返回整数或 bool 值的函数没有问题,但返回 BSTR 类型的函数有问题:

error: cannot convert 'GetLastErrText_funtype {aka wchar_t* (__attribute__((__stdcall__)) *)()}' to 'BSTR {aka wchar_t*}' in initialization

Delphi function header:

function GetLastErrText: BSTR; stdcall;

C++代码:

#include <iostream>
#include <cstdlib>
#include <windows.h>

using namespace std;

int main()
{
HINSTANCE dll_module = LoadLibrary("test.dll");

if(dll_module == NULL) { return -1; }

FARPROC GetLastErrText = GetProcAddress(dll_module, "GetLastErrText");
typedef BSTR (__stdcall* GetLastErrText_funtype)();

std::cout << "\nGetLastErrText = " << (void*)GetLastErrText;

if (GetLastErrText != 0) {
BSTR bstr = (GetLastErrText_funtype) GetLastErrText(); // <<<< ERROR
std::cout << "\nstr = " << bstr;
}

FreeLibrary(dll_module);

std::cout << "\n";

return 0;
}

如何修复此代码?


更新(阅读 Remy Lebeau 的评论后):

Delphi 中非常简化的代码

library test_ws;

uses
System.SysUtils,
Vcl.Dialogs;

function GetLastErrText: WideString; stdcall;
begin
try
Result := 'This is the result of GetLastErrText';
except
on E:Exception do
ShowMessage('Delphi exception::GetLastErrText : ' + E.Message); // when call from C++ code : Out of memory
end;
end;

exports
GetLastErrText;

begin
end.

根据 C++ 中的代码:

#include <iostream>
#include <windows.h>

using namespace std;

int main()
{
HMODULE lib = LoadLibrary("test_ws.dll");

typedef BSTR (__stdcall *Func)();
Func GetLastErrText = (Func) GetProcAddress(lib, "GetLastErrText");

BSTR bstr = GetLastErrText(); // <<<--- Out of memory
std::wcout << bstr;
SysFreeString(bstr);

return 0;
}

最佳答案

您尝试先调用 DLL 函数,然后将其返回值类型转换为函数指针。您不能将函数指针分配给 BSTR 指针,这是编译器所提示的。

您需要先对函数指针进行类型转换,然后才能正确调用该函数。您正在尝试在函数调用时执行此操作,但要正确执行此操作,您需要改为这样做:

BSTR bstr = ((GetLastErrText_funtype)GetLastErrText)(); // <-- note the extra parenthesis around the cast!

否则,最好在第一次获取函数指针时强制转换它,然后在需要时可以像普通函数一样调用它:

typedef BSTR (__stdcall* GetLastErrText_funtype)();
GetLastErrText_funtype GetLastErrText = (GetLastErrText_funtype) GetProcAddress(dll_module, "GetLastErrText");
...
BSTR bstr = GetLastErrText();

不要忘记在使用完 BSTR 后释放它(前提是 DLL 使用 SysAllocString...() 函数之一正确分配它):

BSTR bstr = GetLastErrText();
std::cout << "\nstr = "; // <-- std::cout does not support wchar_t data!
std::wcout << bstr; // <-- use std::wcout instead...
SysFreeString(bstr); // <-- free it!

更新:您的 DLL 的 Delphi 代码实际上并未返回原始 BSTR 指针,就像您的 C++ 代码所期望的那样。它实际上返回一个 WideString,它是 Delphi 中的一个托管类型,并且总是通过一个隐藏的输出参数从函数返回,您的 C++ 代码没有填充该参数。这就是您的 C++ 代码失败的原因。参见 Why can a WideString not be used as a function return value for interop? . C++ 端的正确函数签名必须看起来更像这样:

typedef void (__stdcall* GetLastErrText_funtype)(WideString&);

但是,WideStringBSTR包装器,它本身并不是实际 BSTR。您不能在 Delphi 和 C++Builder 编译器之外按原样使用 WideString

您需要重写 DLL 函数,使其更兼容非 C++Builder 编译器。例如:

function GetLastErrText: PWideChar; stdcall;
var
RealResult: WideString absolute Result;
begin
try
Initialize(RealResult);
RealResult := 'This is the result of GetLastErrText';
except
on E: Exception do
ShowMessage('Delphi exception::GetLastErrText : ' + E.Message);
end;
end;

或者:

function GetLastErrText: PWideChar; stdcall;
begin
try
Result := nil;
WideString(Result) := 'This is the result of GetLastErrText';
except
on E: Exception do
ShowMessage('Delphi exception::GetLastErrText : ' + E.Message);
end;
end;

关于c++ - 从 C++ 调用 Delphi DLL 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56955088/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com