【问题标题】:Calling functions from a c++ DLL in Delphi在 Delphi 中从 c++ DLL 调用函数
【发布时间】:2012-05-01 23:58:54
【问题描述】:

我在 VS2010 中创建了一个新的 c++ DLL 项目,它公开了 1 个函数

#include "stdafx.h"    
#define DllImport   extern "C" __declspec( dllimport )
#define DllExport   extern "C" __declspec( dllexport )    
DllExport int DoMath( int a, int b) {
    return a + b ; 
}

然后我用 VS2010 创建了一个 C++ 应用程序来测试这个 DLL。在VS2010中构建的测试应用程序可以调用c++ DLL并获得预期的结果。

#include "stdafx.h"
#include <windows.h>

typedef int (*DoMath)(int, int) ; 
int _tmain(int argc, _TCHAR* argv[])
{
    HMODULE hMod = LoadLibrary ("exampleDLL.dll");
    if (NULL != hMod) {
        DoMath mf1 = (DoMath) GetProcAddress(hMod,"DoMath");
        if( mf1 != NULL ) {
            printf ("DoMath(8,7)==%d \n", mf1(8,7) );   
        } else {
            printf ("GetProcAddress Failed \n");
        }
        FreeLibrary(hMod);
    } else { 
        printf ("LoadLibrary failed\n");
        return 1;
    }
    return 0;
}

接下来我尝试在 Delphi 7 中构建一个新项目来调用这个 C++ DLL。我使用this tutorial 来帮助我构建新项目。

unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TmyFunction = function(X,Y: Integer):Integer;

  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    hDll: THandle;
  end;

var
  Form1: TForm1;
  fDoMath : TmyFunction;

implementation
{$R *.dfm}

procedure TForm1.FormShow(Sender: TObject);
begin
  hDll := LoadLibrary('exampleDLL.dll');
   if HDll >= 32 then { success }
   begin
     fDoMath := GetProcAddress(hDll, 'DoMath');
   end
   else
     MessageDlg('Error: could not find exampleDLL.DLL', mtError, [mbOk], 0)
end;

procedure TForm1.Button1Click(Sender: TObject);
 var i: Integer;
begin
 i := fDoMath(2,3);
 edit1.Text := IntToStr(i);
end;
end.

Delphi 7 项目的结果是 6155731,而我期望 5。我检查了结果的二进制文件,认为它可能与数据类型有关,但在我看来它是随机的。当我重新编译/重新运行应用程序时,每次都会得到相同的结果。

我对 Delphi 了解不多,这是我第一次处理它,我觉得它很混乱。

关于下一步检查什么有什么建议吗?

【问题讨论】:

    标签: c++ delphi dll delphi-7


    【解决方案1】:

    您需要指定调用约定,在本例中为cdecl

    TMyFunction = function(X, Y: Integer): Integer; cdecl;
    

    您的代码使用默认的 Delphi 调用约定 register 并通过寄存器传递参数。 cdecl 调用约定在堆栈上传递参数,因此这种不匹配解释了为什么两个模块之间的通信失败。


    更多的cmets:

    LoadLibrary 的失败模式是返回NULL,即0。检查返回值而不是 &gt;=32

    使用隐式链接来导入这个函数更简单。用这个简单的声明替换所有 LoadLibraryGetProcAddress 代码:

    function DoMath(X, Y: Integer): Integer; cdecl; external 'exampleDLL.dll';
    

    系统加载器将在您的可执行文件启动时解析此导入,因此您不必担心链接的细节。

    【讨论】:

    • 大卫赫弗南你是明星☼
    【解决方案2】:

    在 RAD Studio Berlin 中,对于 C++ 部分使用 CLANG 编译器,作为 extern "C" 的 cdecl 函数将在其名称前加上下划线、传统的 unix "C" 样式。上面的代码在这种情况下不起作用,但是使用外部声明的name属性来解决问题:

    function DoMath(X, Y: Integer): Integer; cdecl;外部“exampleDLL.dll”名称“_DoMath”;

    没有用其他编译器尝试过,所以它可能是 cdecl 的一般问题。 Windows API 不使用 cdecl,但使用与 Delphi 相同的调用约定,例如,DLL 函数的 Winapi.Windows 声明没有添加下划线。

    如果使用 GetProcAddress 也是如此,正确的调用是 GetProcAddress(hDLL, '_DoMath');否则返回 nil。

    希望这可以帮助任何努力让 Delphi 与 C++ 对话的人。

    【讨论】:

    • 我有 Delphi RAD 10.2 并且 Sum(a+b+c) 工作正常,在 DLL 中有 int __declspec(dllexport) __stdcall calcsum(int a, int b, int c){ return a +b +c; }。 dyn 调用是:` calcsum := GetProcAddress(hmod, 'calcsum'); ` 并且工作正常。但是我在获取函数返回的 char* (或字符串)方面确实存在问题。你知道为什么吗,能给我一个建议吗?
    猜你喜欢
    • 1970-01-01
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 2015-07-28
    • 1970-01-01
    相关资源
    最近更新 更多