简体   繁体   English

从C ++调用Delphi DLL函数

[英]Call a Delphi DLL function from C++

I have written a DLL with Delphi and now I need to test a function of this DLL from C++ code. 我已经用Delphi编写了一个DLL,现在我需要从C ++代码测试该DLL的功能。

I've never used C++ before. 我以前从未使用过C ++。 I installed Code::Blocks and tried to code in C++. 我安装了Code :: Blocks并尝试使用C ++进行编码。

There are no problems with functions that return integers or booleans, but I have problems with functions that return BSTR type: 返回整数或布尔值的函数没有问题,但是返回BSTR类型的函数有问题:

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

Delphi function header: Delphi函数头:

function GetLastErrText: BSTR; stdcall;

C++ code: 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;
}

How do I fix this code? 如何修复此代码?


UPDATE (after reading comment of Remy Lebeau): 更新(阅读雷米·勒博的评论后):

Very simplified code in Delphi 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.

according code in C++: 根据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;
}

You are trying to call the DLL function first and then type-cast its return value to a function pointer. 您试图先调用DLL函数,然后将其返回值类型转换为函数指针。 You cannot assign a function pointer to a BSTR pointer, that is what the compiler is complaining about. 您不能将函数指针分配给BSTR指针,这正是编译器抱怨的。

You need to type-cast the function pointer before you can call the function properly. 您需要先强制转换函数指针,然后才能正确调用该函数。 You are trying to do that at the function call, but to do it properly you need to do that like this instead: 您正在尝试在函数调用中执行此操作,但是要正确执行此操作,您需要执行以下操作:

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

Otherwise, it would be better to cast the function pointer when you first obtain it, then you can call it like a normal function when needed: 否则,最好在首次获得函数指针时就对其进行转换,然后在需要时可以像普通函数一样调用它:

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

Don't forget to free the BSTR when you are done using it (provided the DLL is allocating it properly using one of the SysAllocString...() functions): 使用完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!

UPDATE : your DLL's Delphi code is not actually returning a raw BSTR pointer, like your C++ code is expecting. 更新 :您的DLL的Delphi代码实际上未返回原始的BSTR指针,就像您的C ++代码所期望的那样。 It is actually returning a WideString , which is a managed type in Delphi, and is always returned from a function via a hidden output parameter, which your C++ code is not populating. 实际上,它返回的是WideString ,这是Delphi中的托管类型,并且始终通过隐藏的输出参数从函数中返回,而您的C ++代码并未填充该参数。 That is why your C++ code fails. 这就是为什么您的C ++代码失败的原因。 See Why can a WideString not be used as a function return value for interop? 请参见为什么不能将WideString用作互操作的函数返回值? . The correct function signature on the C++ side would have to look more like this instead: C ++端的正确函数签名必须看起来像这样:

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

However, WideString is a wrapper for a BSTR , it is not itself an actual BSTR. 但是, WideStringBSTR包装 ,它本身并不是实际的 BSTR。 You cannot use WideString as-is outside of Delphi and C++Builder compilers. 您不能在Delphi和C ++ Builder编译器之外按原样使用WideString

You need to rewrite the DLL function to make it more compatible with non-C++Builder compilers. 您需要重写DLL函数,使其与非C ++ Builder编译器更加兼容。 For example: 例如:

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; 

Alternatively: 或者:

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