我已经用Delphi编写了一个DLL,现在我需要从C ++代码测试该DLL的功能。
我以前从未使用过C ++。我安装了Code :: Blocks并尝试使用C ++进行编码。
返回整数或布尔值的函数没有问题,但是返回BSTR
类型的函数有问题:
error: cannot convert 'GetLastErrText_funtype {aka wchar_t* (__attribute__((__stdcall__)) *)()}' to 'BSTR {aka wchar_t*}' in initialization
Delphi函数标头:
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;
}
如何解决此代码?
更新(阅读雷米·勒博的评论后):
在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;
}
答案 0 :(得分:1)
您试图先调用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&);
但是,WideString
是BSTR
的包装器,它本身并不是 actual 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;