簡體   English   中英

從C ++調用Delphi DLL函數

[英]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&);

但是, 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; 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM