2012-05-01 48 views
8

Tôi tạo ra một c dự án DLL mới ++ trong VS2010 đó cho thấy nhiều chức năng 1chức năng Gọi từ một C++ DLL trong 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 ; 
} 

sau đó tôi đã tạo ra một ứng dụng C++ với VS2010 để kiểm tra DLL này. Việc xây dựng ứng dụng thử nghiệm trong VS2010 có thể gọi C++ DLL và nhận được kết quả mong đợi.

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

Tiếp theo tôi đã cố tạo một dự án mới trong Delphi 7 để gọi hàm DLL C++ này. Tôi đã sử dụng this tutorial để giúp tôi tạo dự án mới.

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. 

Kết quả từ dự án Delphi 7 là 6.155.731 Khi tôi mong đợi . Tôi đã kiểm tra nhị phân của kết quả nghĩ rằng nó có thể có một cái gì đó để làm với một kiểu dữ liệu nhưng nó trông ngẫu nhiên với tôi. Khi tôi biên dịch lại/chạy lại ứng dụng, nó nhận được kết quả tương tự mỗi lần.

Tôi không biết nhiều về Delphi đây là lần đầu tiên tôi đối phó với nó và tôi thấy nó khó hiểu.

Bất kỳ đề xuất nào về những gì cần kiểm tra tiếp theo?

Trả lời

16

Bạn cần phải xác định quy ước gọi, mà trong trường hợp này là cdecl:

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

Mã của bạn sử dụng các quy ước gọi mặc định Delphi là register và truyền thông số thông qua thanh ghi. Quy ước gọi số cdecl chuyển các tham số trên ngăn xếp và do đó kết hợp sai này giải thích tại sao thông tin liên lạc giữa hai mô-đun bị lỗi.


Một số chi tiết nhận xét:

Các chế độ thất bại cho LoadLibrary là để trở NULL, đó là 0. Kiểm tra thay vì giá trị trả về là >=32.

Đơn giản hơn khi sử dụng liên kết ngầm để nhập hàm này. Thay thế tất cả các mã LoadLibraryGetProcAddress với tuyên bố đơn giản này:

hệ thống
function DoMath(X, Y: Integer): Integer; cdecl; external 'exampleDLL.dll'; 

Bộ nạp sẽ giải quyết nhập khẩu này khi thực thi của bạn bắt đầu, do đó bạn không cần phải lo lắng về các chi tiết của liên kết.

+0

Đánh bại tôi sau 5 giây +1 –

+0

+1 Quy ước cuộc gọi luôn là điều cần quan tâm – Juliano

0

Trên RAD Studio Berlin, sử dụng trình biên dịch CLANG cho phần C++, một hàm cdecl bên ngoài "C" sẽ có tên được thêm vào với dấu gạch dưới, kiểu "C" kiểu truyền thống. Mã trên không hoạt động trong trường hợp này, nhưng sử dụng thuộc tính tên của khai báo bên ngoài để khắc phục sự cố:

chức năng DoMath (X, Y: Integer): Integer; cdecl; tên 'exampleDLL.dll' bên ngoài '_DoMath';

Không dùng thử với các trình biên dịch khác, vì vậy nó có thể là vấn đề chung với cdecl. Windows API không sử dụng cdecl, nhưng sử dụng cùng một quy ước gọi như Delphi, ví dụ, các khai báo của Winapi.Windows về các hàm DLL không có phần gạch dưới được thêm vào.

Tương tự nếu sử dụng GetProcAddress, lệnh gọi chính xác là GetProcAddress (hDLL, '_DoMath'); ngược lại nil được trả về.

Hy vọng điều này sẽ giúp bất kỳ ai gặp khó khăn để có được Delphi nói chuyện với C++.

+0

Tôi có Delphi RAD 10.2 và Sum (a + b + c) hoạt động tốt, với 'int __declspec (dllexport) __stdcall calcsum (int a, int b, int c) {return a + b + c; } 'trong DLL. Cuộc gọi dyn là: 'calcsum: = GetProcAddress (hmod, 'calcsum'); 'và cũng làm việc tốt. NHƯNG Tôi CÓ thực sự có vấn đề trong việc lấy một char * (hoặc chuỗi) của hàm trả về. Bạn có biết tại sao và bạn có thể cho tôi lời khuyên không? –

Các vấn đề liên quan