从DLL导出一个C ++类

我的大部分C / C ++开发都涉及单片模块文件,绝对没有任何类,因此通常当我需要使用可访问的函数构build一个DLL ,我只需使用标准的__declspec(dllexport)指令导出它们即可。 然后通过LoadLibrary()或者在编译时使用头文件和lib文件来dynamic访问它们。

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

是否有可能在运行时dynamic加载该类,如果是这样,如何?

你怎么用一个头文件和lib来编译链接?

那么迟绑定呢? 在加载LoadLibrary()和GetProcAddress()时? 我可以在运行时加载库,如果你可以在这里做,那将是非常好的。

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

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

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

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

如果要链接到在DLL中定义的类,并且希望在程序启动后的某个时候动态加载该DLL,则有两种选择:

  1. 使用一个特殊的工厂函数来创建类的对象,这个函数在内部将不得不使用(一点点)汇编器来将新创建的对象“钩住”到适当的偏移量。 这必须在DLL加载后的运行时完成,显然。 这个方法的一个很好的解释可以在这里找到。

  2. 使用延迟加载DLL 。

所有的事情考虑……可能更好的只是去隐式链接,在这种情况下,你一定要使用上面显示的预处理器技术。 事实上,如果您在Visual Studio中创建一个新的DLL,并选择“导出符号”选项,这些宏将为您创建。

祝你好运…

当您构建DLL和将使用该DLL的模块时,可以使用某种#define来区分一个和另一个,然后可以在您的类头文件中执行如下操作:

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

编辑:crashmstr击败我吧!

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

 #ifdef ISDLL
 #define DLL __declspec(dllexport)
 #万一

 #ifdef USEDLL
 #define DLL __declspec(dllimport)
 #万一

然后在头文件中声明这个类:

类DLL MyClassToExport {...}

然后在#define ISDLL中定义ISDLL,在将头文件包含到要使用类的位置之前,使用USEDLL

我不知道你是否需要为LoadLibrary做不同的工作

添加一个从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 ab; } 

B.加载并链接已创建的.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; } 

最近我问自己完全一样的问题,并在一篇博客中总结了我的发现。 你可能会觉得它很有用。

它涵盖了从DLL中导出C ++类,以及使用LoadLibrary动态加载它们,并讨论了其中的一些问题,如内存管理,名称修改和调用约定。

如果你愿意在导出的类中放入一个vtable,你可以导出一个返回接口并在.dll中实现这个类的函数,然后把它放在.def文件中。 你可能不得不做一些宣布的诡计,但不应该太难。

就像COM一样。 🙂