2012-05-01 41 views
8

ho creato un nuovo progetto C++ DLL in VS2010 che espone 1 funzioneChiamata di funzioni da un C++ DLL in Delphi

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

Poi ho creato un'applicazione C++ con VS2010 per testare questa DLL. La build dell'applicazione di test in VS2010 può chiamare la DLL C++ e ottenere il risultato previsto.

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

Successivamente ho tentato di creare un nuovo progetto in Delphi 7 per chiamare questa DLL C++. Ho usato this tutorial per aiutarmi a costruire il nuovo progetto.

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. 

Il risultato del progetto Delphi 7 è 6.155.731 Quando mi aspettavo . Ho controllato il file binario del risultato pensando che potrebbe avere qualcosa a che fare con un tipo di dati, ma mi sembra casuale. Quando ricompilare/rieseguire l'applicazione ottiene sempre lo stesso risultato.

Non so molto su Delphi questa è la prima volta che ho a che fare con esso e trovo confuso.

Qualche suggerimento su cosa controllare in seguito?

risposta

16

è necessario specificare la convenzione di chiamata, che in questo caso è cdecl:

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

Il codice utilizza la convenzione di chiamata predefinita di Delphi, che è register e passa i parametri attraverso i registri. La convenzione di chiamata cdecl passa i parametri nello stack e quindi questa corrispondenza errata spiega perché le comunicazioni tra i due moduli non vanno a buon fine.


Alcuni ulteriori commenti:

La modalità di guasto per LoadLibrary è quello di restituire NULL, cioè 0. Verificare che anziché il valore restituito sia >=32.

È più semplice utilizzare il collegamento implicito per importare questa funzione. Sostituire tutto il codice LoadLibrary e GetProcAddress con questa semplice dichiarazione:

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

Il sistema loader risolvere questo importazione quando il vostro eseguibile inizia in modo da non dovete preoccuparvi dei dettagli di collegamento.

+0

mi ha battuto per 5 secondi +1 +1 –

+0

convenzione di chiamata è sempre qualcosa di prendersi cura di – Juliano

0

Su RAD Studio Berlin, utilizzando il compilatore CLANG per la parte C++, una funzione cdecl che è extern "C" avrà il suo nome preceduto da un carattere di sottolineatura, tradizionale "C" unix. Il codice sopra riportato non funziona in questo caso, ma usa l'attributo name della dichiarazione esterna per risolvere il problema:

function DoMath (X, Y: Integer): Integer; cdecl; nome 'exampleDLL.dll' esterno '_DoMath';

Non provato con altri compilatori, quindi potrebbe essere un problema generale con cdecl. L'API di Windows non usa cdecl, ma usa la stessa convenzione di chiamata di Delphi così, per esempio, le dichiarazioni Winapi.Windows delle funzioni DLL non hanno aggiunto il carattere di sottolineatura.

Stesso vero se si utilizza GetProcAddress, la chiamata corretta è GetProcAddress (hDLL, '_DoMath'); altrimenti viene restituito nullo.

Spero che questo aiuti chiunque a lottare per far parlare Delphi con C++.

+0

ho Delphi RAD 10.2 e la somma (a + b + c) funziona bene, con 'int __declspec (dllexport) __stdcall calcsum (int a, int b, int c) {return a + b + c; } 'nella DLL. La chiamata din è: 'calcsum: = GetProcAddress (hmod, 'calcsum'); 'e funziona anche bene. Ma ho davvero problemi nell'ottenere un char * (o stringa) della funzione return. Sai perché e potresti darmi un consiglio, per favore? –

Problemi correlati