且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

从Delphi中的c ++ DLL调用函数

更新时间:2023-02-07 17:51:41

指定调用约定,在这种情况下为 cdecl

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

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





更多评论:



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



使用隐式链接来导入此更简单功能。用简单的声明替换所有的 LoadLibrary GetProcAddress 代码:



函数DoMath(X,Y:Integer):整数; $ $ $ $ $ cdecl;外部exampleDLL.dll;

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


I created a new c++ DLL project in VS2010 that exposes 1 function

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

I then created a C++ application with VS2010 to test this DLL. The test application build in VS2010 could call the c++ DLL and get the expected result.

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

Next I attempted to build a new project in Delphi 7 to call this C++ DLL. I used this tutorial to help me build the new project.

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.

The result from the Delphi 7 project is 6155731 When I expected 5. I checked the binary of the result thinking it might have something to do with a data type but it looks random to me. When I recompile/rerun the application it gets the same result every time.

I do not know a lot about Delphi this is the first time I have deal with it and i find it confusing.

Any suggestion on what to check next?

You need to specify the calling convention, which in this case is cdecl:

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

Your code uses the default Delphi calling convention which is register and passes parameters through registers. The cdecl calling convention passes parameters on the stack and so this mis-match explains why communications between the two modules fail.


Some more comments:

The failure mode for LoadLibrary is to return NULL, that is 0. Check that rather than the return value being >=32.

It's simpler to use implicit linking to import this function. Replace all the LoadLibrary and GetProcAddress code with this simple declaration:

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

The system loader will resolve this import when your executable starts so you don't have to worry about the details of linking.