2008-08-26 67 views
23

我大部分的C/C++开发包括单片模块文件和任何绝对没有课,所以通常当我需要做一个DLL与使用的功能我只是用标准__declspec(dllexport)指令导出它们。然后通过LoadLibrary()或在编译时使用头文件和lib文件动态访问它们。从DLL导出C++类

当你想导出整个类(以及它的所有公共方法和属性)时,你如何做到这一点?

是否有可能在运行时动态加载该类,如果有,如何?

你会怎么做一个头和lib编译时链接?

+0

一个很好的答案写后:http://stackoverflow.com/a/22797419/1995714 – 2016-08-25 19:21:39

回答

15

那么迟绑定呢?如在加载 它与LoadLibrary()和 GetProcAddress()?我使用 可以在运行时加载库,如果您可以在此处执行 ,它会很棒。

所以有两种方法来加载DLL。首先是引用DLL中的一个或多个符号(例如,您的类名),提供相应的导入.LIB,并让链接器将所有内容全部排除。

第二个是通过LoadLibrary显式加载DLL。

这两种方法都适用于C级功能导出。你可以让链接器处理它,或者像你注意的那样调用GetProcAddress。

但是,当涉及到输出时,通常只使用第一种方法,即隐式链接到DLL。在这种情况下,DLL在应用程序启动时加载,如果找不到DLL,应用程序将无法加载。

如果你想链接到一个DLL中定义的类,并且希望该DLL动态加载,程序开始后的某个时候,你有两个选择:

  1. 使用创建的类的对象一个特殊的工厂功能,内部将不得不使用(一点点)汇编程序将新创建的对象“连接”到适当的偏移处。这必须在加载DLL后的运行时完成,显然。这种方法的一个很好的解释可以找到here

  2. 使用delay-load DLL

所有事情都考虑过......可能更好的方法是使用隐式链接,在这种情况下,您肯定希望使用上面显示的预处理器技术。事实上,如果您在Visual Studio中创建一个新DLL并选择“导出符号”选项,则会为您创建这些宏。

好运...

12

我使用了一些宏来标记导入或导出代码

 
#ifdef ISDLL 
#define DLL __declspec(dllexport) 
#endif 

#ifdef USEDLL 
#define DLL __declspec(dllimport) 
#endif 

然后声明类头文件:

 
class DLL MyClassToExport { ... } 

然后在libary #define ISDLL,并USEDLL包括前头文件在你想使用该类的地方。

我不知道,如果你可能需要用LoadLibrary

16

工作当你建立动态连接库,将使用DLL模块做不同的事情,有某种的#define,你可以用它来的一个与其他区分,那么你可以做这样的事情在你的类的头文件:

#if defined(BUILD_DLL) 
    #define IMPORT_EXPORT __declspec(dllexport) 
#else 
    #define IMPORT_EXPORT __declspec(dllimport) 
#endif 
class IMPORT_EXPORT MyClass { 
    ... 
}; 

编辑:crashmstr打我吧!

+0

如何处理错位类和构造函数(等)的名字,先生? – null 2013-03-20 08:06:27

+0

就是这样 - 你不需要处理损坏的名字。 `__declspec(dllimport)`告诉编译器/链接器你正在导入它,它做的是正确的。 – 2013-03-20 12:53:56

+0

这个或crashmstr的回答与原始问题没有任何关系。 null的问题还没有得到妥善解决。 – AudioGL 2014-02-22 06:42:12

0

如果你愿意把你导出类虚函数表,你可以导出返回的接口函数,实现.dll文件的类,然后把在.def文件中。你可能不得不做一些声明欺骗,但它不应该太难。

就像COM一样。 :)

7

最近我问自己完全一样的问题,并总结我的发现in a blog post。你可能会觉得它很有用。它涵盖了从DLL导出C++类,并且使用LoadLibrary动态加载它们,并讨论了其中的一些问题,如内存管理,名称修改和调用约定。

11

添加一个简单的工作示例从一个DLL导出一个C++类:

例如下面给出的只给你的DLL和EXE如何相互影响(言自明)一个简短的概述,但它需要更多的东西添加以更改为生产代码。

全部样品实例在分为两个部分

A.创建一个.dll库(MYDLL.DLL)

B.创建其使用的.dll库(应用程序)的应用程序。

A.的.dll项目文件(MYDLL.DLL):

1 dllHeader.h

#ifdef MYDLL_EXPORTS 
#define DLLCALL __declspec(dllexport) /* Should be enabled before compiling 
              .dll project for creating .dll*/ 
#else 
#define DLLCALL __declspec(dllimport) /* Should be enabled in Application side 
              for using already created .dll*/ 
#endif 

// Interface Class 
class ImyMath { 
public: 
    virtual ~ImyMath() {;} 
    virtual int Add(int a, int b) = 0; 
    virtual int Subtract(int a, int b) = 0; 
}; 

// Concrete Class 
class MyMath: public ImyMath { 
public: 
    MyMath() {} 
    int Add(int a, int b); 
    int Subtract(int a, int b); 
    int a,b; 
}; 

// Factory function that will return the new object instance. (Only function 
// should be declared with DLLCALL) 
extern "C" /*Important for avoiding Name decoration*/ 
{ 
    DLLCALL ImyMath* _cdecl CreateMathObject(); 
}; 

// Function Pointer Declaration of CreateMathObject() [Entry Point Function] 
typedef ImyMath* (*CREATE_MATH)(); 

2. dllSrc.cpp

#include "dllHeader.h" 

// Create Object 
DLLCALL ImyMath* _cdecl CreateMathObject() { 
    return new MyMath(); 
} 

int MyMath::Add(int a, int b) { 
    return a+b; 
} 

int MyMath::Subtract(int a, int b) { 
    return a-b; 
} 

B.应用程序Pr选择哪个负载并链接已经创建的。dll文件:

#include <iostream> 
#include <windows.h> 
#include "dllHeader.h" 

int main() 
{ 
    HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll" 

    if (hDLL == NULL) { 
     std::cout << "Failed to load library.\n"; 
    } 
    else { 
     CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject"); 
     ImyMath* pMath = pEntryFunction(); 
     if (pMath) { 
      std::cout << "10+10=" << pMath->Add(10, 10) << std::endl; 
      std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl; 
     } 
     FreeLibrary(hDLL); 
    } 
    std::cin.get(); 
    return 0; 
}