Steven smethurst Steven smethurst - 2 days ago 6
C++ Question

Calling functions from a c++ DLL in Delphi

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?

Answer

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.

Comments