【问题标题】:How do I export function from C++ DLL and use in delphi?如何从 C++ DLL 导出函数并在 delphi 中使用?
【发布时间】:2012-11-26 04:10:17
【问题描述】:

我正在尝试用 C++ 创建一个 DLL 并导出一个函数。

这是我的 C++ 代码:

#include <Windows.h>

void DLLMain(){

}

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

这是我的德尔福代码:

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 Loaded”的消息框就好了。但之后我得到“未加载功能”。我在这里做错了什么?

【问题讨论】:

    标签: c++ delphi dll


    【解决方案1】:

    您可以将其导出为 C 函数 (__cdecl),以便它在导出表上具有一个好听的名称。

    名称装饰约定: 下划线字符 (_) 是名称的前缀,但导出使用 C 链接的 __cdecl 函数时除外。

    所以基本上,您的函数在导出表中将具有名称 xMain

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

    而在 Delphi 部分,您只需指定 cdecl 并正常调用它:

    var
      xMainPrc: procedure; cdecl;
    

    例如:

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

    【讨论】:

    • 该函数已导出为__cdecl,因为这是 C/C++ 的默认调用约定。通过使用__cdecl,您强制导出的名称具有前导下划线,因此您必须使用该下划线导入函数。如果您不想要 unerscore,则必须使用 .def 文件将其删除,或者使用 _stdcall 而不是 __cdecl
    • 如果你使用__cdecl 没有.def 文件,那么你必须像这样使用GetProcAddress()@xMainPrc := GetProcAddress(handle, '_xMain');
    • 这就是为什么我没有在我的例子中使用__cdecl,因为他在Delphi中使用stdcall,我暗示他应该是cdecl(他没有写@ 987654337@ 用于 C++ 部分)。我写的括号 (__cdecl) 只是为了告诉他这是默认的调用约定。因此,或者,他可以使用stdcall,只要他写__stdcallextern "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.
    

    【讨论】:

    • 非常感谢这个珍贵的 sn-ps。
    猜你喜欢
    • 2012-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多