2012-11-26 70 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

非常感谢这宝贵的片段。 –