2012-05-01 17 views
8

yo creamos un nuevo proyecto DLL de C++ en VS2010 que expone la función 1las funciones de llamada desde un archivo DLL en C++ 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 ; 
} 

Entonces creó una aplicación C++ con VS2010 para poner a prueba esta DLL. La construcción de la aplicación de prueba en VS2010 podría llamar a la DLL de C++ y obtener el resultado esperado.

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

Después intenté construir un nuevo proyecto en Delphi 7 para llamar a este C++ DLL. Usé this tutorial para ayudarme a construir el nuevo proyecto.

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. 

El resultado del proyecto de Delphi 7 es Cuando yo esperaba . Comprobé el binario del resultado pensando que podría tener algo que ver con un tipo de datos, pero parece aleatorio para mí. Cuando recompilo/vuelvo a ejecutar la aplicación, obtiene el mismo resultado cada vez.

No sé mucho sobre Delphi esta es la primera vez que lo trato y me resulta confuso.

¿Alguna sugerencia sobre qué revisar a continuación?

Respuesta

16

Es necesario especificar la convención de llamada, que en este caso es cdecl:

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

Su código se utiliza la convención de llamada por defecto de Delphi que es register y pasa los parámetros a través de registros. La convención de llamadas cdecl pasa parámetros en la pila y, por lo tanto, esta falta de coincidencia explica por qué fallan las comunicaciones entre los dos módulos.


Algunos más comentarios:

El modo de fallo para LoadLibrary es volver NULL, es decir 0. Verifique que el valor de retorno no sea >=32.

Es más fácil utilizar enlaces implícitos para importar esta función. Reemplace todo el código LoadLibrary y GetProcAddress con esta simple declaración:

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

El sistema resolverá esta importación cuando el ejecutable se inicia por lo que no tiene que preocuparse de los detalles de la vinculación.

+0

me ganó por 5 segundos 1 –

+0

convención 1 llamado es siempre algo para cuidar de – Juliano

0

En RAD Studio Berlin, usando el compilador CLANG para la parte C++, una función cdecl que es externa "C" tendrá su nombre antepuesto con un guión bajo, estilo tradicional "C" de unix. El código anterior no funciona en este caso, pero use el atributo de nombre de la declaración externa para solucionar el problema:

función DoMath (X, Y: Entero): Entero; cdecl; external 'exampleDLL.dll' name '_DoMath';

No lo intenté con otros compiladores, por lo que podría ser un problema general con cdecl. La API de Windows no usa cdecl, pero usa la misma convención de llamadas como Delphi, por lo que, por ejemplo, las declaraciones Winapi.Windows de las funciones DLL no tienen el subrayado agregado.

Lo mismo ocurre si se usa GetProcAddress, la llamada correcta es GetProcAddress (hDLL, '_DoMath'); de lo contrario, se devuelve nil.

Espero que esto ayude a cualquiera que esté luchando para conseguir que Delphi hable con C++.

+0

tengo Delphi RAD 10.2 y la suma (a + b + c) funciona bien, con 'int __declspec (dllexport) __stdcall calcsum (int a, int b, int c) {return a + b + c; } 'en la DLL. La llamada dyn es: 'calcsum: = GetProcAddress (hmod, 'calcsum'); 'y funciona bien también. PERO TENGO realmente problemas para recuperar un char * (o cadena) de la función. ¿Sabes por qué y podrías darme un consejo, por favor? –

Cuestiones relacionadas