[英]Call a Delphi DLL function from C++
我已經用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;
}
您試圖先調用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 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 ++代碼失敗的原因。 請參見為什么不能將WideString用作互操作的函數返回值? 。 C ++端的正確函數簽名必須看起來像這樣:
typedef void (__stdcall* GetLastErrText_funtype)(WideString&);
但是, WideString
是BSTR
的包裝 ,它本身並不是實際的 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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.