从C调用函数++在Delphi DLL(Calling functions from a c++ D

2019-06-24 02:49发布

我在VS2010暴露1个函数创建一个新的C ++ DLL项目

#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 ; 
}

然后我创建了一个C ++应用程序与VS2010中测试该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。 我用这个教程来帮助我建立新的项目。

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.

从德尔福7项目的结果是6155731当我预计5。 我检查结果认为它可能有一些做的一个数据类型的二进制文件,但它看起来随机给我。 当我重新编译/重新运行它得到了相同的结果每一次应用。

我不知道了很多关于德尔福,这是我第一次处理它,我发现它令人困惑。

什么任何建议旁边的检查?

Answer 1:

您需要指定调用约定,在这种情况下cdecl

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

您的代码使用默认的德尔福调用约定是register ,通过寄存器传递参数。 该cdecl调用约定堆栈传递参数,所以这种不匹配解释了为什么在两个模块之间的通信失败。


一些更多的评论:

失败模式LoadLibrary是返回NULL ,也就是0 。 检查,而不是返回值是>=32

这是简单的使用隐式链接导入该功能。 更换所有的LoadLibraryGetProcAddress代码如下声明:

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

当你的可执行文件开始,所以你不必担心链接的详细信息系统加载器将解决这个进口。



Answer 2:

在RAD Studio在柏林,使用CLANG编译的C ++部分,一个CDECL功能是为extern“C”,将其名字用下划线,传统的UNIX“C”风格的前缀。 上面的代码不会在这种情况下工作,但使用外部声明的name属性来解决这个问题:

功能DoMath(X,Y:整数):整数; CDECL; 外部 'exampleDLL.dll' 名 '_DoMath';

不与其他编译器试了一下,所以它可能是与CDECL一般的问题。 在Windows API不使用CDECL,但使用相同的调用约定德尔福这样,例如,DLL函数Winapi.Windows声明没有添加下划线。

同样如此,如果使用GetProcAddress的,正确的调用是GetProcAddress的(HDLL, '_DoMath'); 否则无返回。

希望这有助于任何人都努力让德尔福交谈C ++。



文章来源: Calling functions from a c++ DLL in Delphi