题
我的大部分 C/C++ 开发都涉及整体模块文件,并且绝对没有任何类,所以通常当我需要制作一个 DLL 具有可访问的功能,我只需使用标准导出它们 __declspec(dllexport)
指示。然后通过动态访问它们 LoadLibrary()
或者在编译时使用头文件和 lib 文件。
当您想要导出整个类(及其所有公共方法和属性)时,如何执行此操作?
是否可以在运行时动态加载该类,如果可以,如何加载?
您将如何使用标头和库来进行编译时链接?
解决方案
后期绑定怎么样?就像用LoadLibrary()和getProcAddress()加载它一样?我用来在运行时加载库,如果您可以在这里做到这一点,那就太好了。
所以加载DLL有两种方法。第一种方法是引用 DLL 中的一个或多个符号(例如,您的类名),提供适当的导入 .LIB 并让链接器计算出所有内容。
第二种是通过LoadLibrary显式加载DLL。
这两种方法对于 C 级函数导出都适用。您可以让链接器处理它,也可以按照您的说明调用 GetProcAddress。
但说到出口 类, ,通常只使用第一种方法,即隐式链接到 DLL。在这种情况下,DLL 在应用程序启动时加载,如果找不到 DLL,应用程序将无法加载。
如果您想要链接到 DLL 中定义的类,并且希望在程序启动后的某个时间动态加载该 DLL,您有两种选择:
使用特殊的工厂函数创建该类的对象,该函数在内部必须使用(一点点)汇编器将新创建的对象“连接”到其适当的偏移量。显然,这必须在加载 DLL 之后在运行时完成。可以找到这种方法的很好的解释 这里.
用一个 延迟加载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) #endif #ifdef USEDLL #define DLL __declspec(dllimport) #endif
然后在头文件中声明该类:
class DLL MyClassToExport { ... }
然后 #define ISDLL
在图书馆,以及 USEDLL
在将头文件包含在要使用该类的位置之前。
我不知道您是否需要做任何不同的事情来与 LoadLibrary
添加一个从 DLL 导出 C++ 类的简单工作示例:
下面给出的示例仅向您简要概述了 dll 和 exe 如何相互交互(不言自明),但它需要添加更多内容才能更改为生产代码。
完整的示例分为两部分
A。创建 .dll 库 (MyDLL.dll)
B.创建使用 .dll 库的应用程序(应用程序)。
A。.dll项目文件(MyDLL.dll):
1.dll头文件
#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.加载并链接已创建的 .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一样。:)