2012-11-26 68 views
3

我想在C++中創建一個DLL並導出一個函數。如何從C++ DLL導出函數並在delphi中使用?

這是我的C++代碼:

#include <Windows.h> 

void DLLMain(){ 

} 

__declspec(dllexport) void xMain(){ 
MessageBox(NULL,L"Test",L"Test",NULL); 
} 

這是我的Delphi代碼:

program prjTestDllMain; 

Uses 
    Windows; 

Var 
    xMainPrc:procedure;stdcall; 
    handle : THandle; 
begin 
    handle := LoadLibrary('xdll.dll'); 
    if handle <> 0 then 
    begin 
     MessageBox(0,'DLL Loaded', 0, 0); 
     @xMainPrc := GetProcAddress(handle, 'xMain'); 
     if @xMainPrc <> nil then 
      MessageBox(0,'Function Loaded', 0, 0) 
     else 
      MessageBox(0,'Function Not Loaded', 0, 0); 
     MessageBox(0,'Process End', 0, 0); 
     FreeLibrary(handle); 
    end else 
     MessageBox(0,'DLL Not Loaded', 0, 0); 
end. 

我得到就好了 「加載的DLL」 一個消息。但之後我收到了「功能未加載」。我在這裏做錯了什麼?

回答

6

可以將它作爲C函數(__cdecl)導出,以便在導出表上有一個很好的名稱。

名稱裝修約定: 下劃線(_)的前綴名,出口__cdecl使用C鏈接功能時除外。

因此,基本上,您的函數將在導出表中具有名稱xMain

extern "C" __declspec(dllexport) void xMain() 

而在德爾福的部分,你只需指定cdecl,通常稱之爲:

var 
    xMainPrc: procedure; cdecl; 

例如:

if @xMainPrc <> nil then 
begin 
    MessageBox(0,'Function Loaded', 0, 0); 
    xMainPrc; 
end; 
+0

的功能是已經導出爲'__cdecl'因爲這是C/C++的默認調用約定。通過使用'__cdecl',您可以強制導出的名稱具有前導下劃線,因此您必須使用該下劃線導入該函數。如果您不想使用unerscore,則必須使用.def文件將其刪除,或者使用_stdcall而不是__cdecl。 –

+0

如果您不使用'__cdecl'。def文件,那麼你必須像這樣使用'GetProcAddress()':@xMainPrc:= GetProcAddress(handle,'_xMain');' –

+0

這就是爲什麼我沒有在我的例子中使用'__cdecl',因爲他使用Delphi中的'stdcall',我暗示他會'cdecl'(他沒有爲C++部分編寫'__stdcall')。我寫的括號('__cdecl')只是爲了告訴他它是默認的調用約定。因此,或者,他可以使用'stdcall',只要他寫'__stdcall'和'extern「C」'。這也是我引用MSDN的原因,所以他不使用'__cdecl'而沒有'extern「C」'。 –

2

出口使用__stcall調用約定(該功能特別是因爲您正試圖使用​​Delphi中的stdcall調用約定來導入它),並使用extern "C"刪除任何導出的名稱裝潢:

MyDll.h

#ifndef MyDLLH 
#define MyDLLH 

#ifdef __BUILDING_DLL 
#define MYDLLEXPORT __declspec(dllexport) 
#else 
#define MYDLLEXPORT __declspec(dllimport) 
#endif 

#ifdef __cplusplus 
extern "C" { 
#endif 

MYDLLEXPORT void __stdcall xMain(); 

#ifdef __cplusplus 
} 
#endif 

#endif 

MyDll.cpp

#define __BUILDING_DLL 
#include "MyDll.h" 

#include <Windows.h> 

void DLLMain() 
{ 
} 

void __stdcall xMain() 
{ 
    MessageBox(NULL, L"Test", L"Test", NULL); 
} 

prjTestDllMain.dpr

program prjTestDllMain; 

uses 
    Windows; 

var 
    xMainPrc: procedure; stdcall; 
    handle : THandle; 
begin 
    handle := LoadLibrary('xdll.dll'); 
    if handle <> 0 then 
    begin 
    MessageBox(0,'DLL Loaded', 0, 0); 
    @xMainPrc := GetProcAddress(handle, 'xMain'); 
    if @xMainPrc <> nil then 
    begin 
     MessageBox(0,'Function Loaded', 0, 0) 
     xMainPrc(); 
    end else 
     MessageBox(0,'Function Not Loaded', 0, 0); 
    MessageBox(0,'Process End', 0, 0); 
    FreeLibrary(handle); 
    end else 
    MessageBox(0,'DLL Not Loaded', 0, 0); 
end. 

或者:

prjTestDllMain.dpr

program prjTestDllMain; 

uses 
    Windows; 

procedure xMain; stdcall; extern 'MyDll.dll'; 

begin 
    MessageBox(0,'DLL Loaded', 0, 0); 
    xMain(); 
    MessageBox(0,'Process End', 0, 0); 
end. 
+0

非常感謝這寶貴的片段。 –