从 DLL 导出 C++ 类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27998/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Exporting a C++ class from a DLL
提问by Adam Haile
Most of my C/C++ development involves monolithic module files and absolutely no classes whatsoever, so usually when I need to make a DLLwith accessible functions I just export them using the standard __declspec(dllexport)
directive. Then access them either dynamically via LoadLibrary()
or at compile time with a header and lib file.
我的大部分 C/C++ 开发都涉及单片模块文件,绝对没有任何类,所以通常当我需要使用可访问的函数制作DLL 时,我只是使用标准__declspec(dllexport)
指令导出它们。然后通过LoadLibrary()
头文件和 lib 文件通过或在编译时动态访问它们。
How do you do this when you want to export an entire class (and all it's public methods and properties)?
当您想导出整个类(及其所有公共方法和属性)时,您如何执行此操作?
Is it possible to dynamically load that class at runtime and if so, how?
是否可以在运行时动态加载该类,如果可以,如何加载?
How would you do it with a header and lib for compile time linking?
您将如何使用头文件和库进行编译时链接?
采纳答案by Graeme Perrow
What about late-binding? As in loading it with LoadLibrary() and GetProcAddress() ? I'm used being able to load the library at run time and it would be great if you could do that here.
后期绑定呢?就像用 LoadLibrary() 和 GetProcAddress() 加载它一样?我习惯于能够在运行时加载库,如果你能在这里做到这一点,那就太好了。
So there are two ways to load the DLL. The first is to reference one or more symbols from the DLL (your classname, for example), supply an appropriate import .LIB and let the linker figure everything out.
所以有两种方法可以加载DLL。第一种方法是从 DLL 中引用一个或多个符号(例如您的类名),提供适当的导入 .LIB 并让链接器解决所有问题。
The second is to explicitly load the DLL via LoadLibrary.
第二种是通过 LoadLibrary 显式加载 DLL。
Either approach works fine for C-level function exports. You can either let the linker handle it or call GetProcAddress as you noted.
这两种方法都适用于 C 级函数导出。您可以让链接器处理它,也可以按照您的说明调用 GetProcAddress。
But when it comes to exported classes, typically only the first approach is used, i.e., implicitly link to the DLL. In this case the DLL is loaded at application start time, and the application fails to load if the DLL can't be found.
但是当涉及到导出类时,通常只使用第一种方法,即隐式链接到 DLL。在这种情况下,DLL 在应用程序启动时加载,如果找不到 DLL,应用程序将无法加载。
If you want to link to a class defined in a DLL, and you want that DLL to be loaded dynamically, sometime after program initiation, you have two options:
如果要链接到 DLL 中定义的类,并且希望动态加载该 DLL,则在程序启动后的某个时间,您有两个选择:
Create objects of the class using a special factory function, which internally will have to use (a tiny bit of) assembler to "hook up" newly created objects to their appropriate offsets. This has to be done at run-time AFTER the DLL has been loaded, obviously. A good explanation of this approach can be found here.
Use a delay-load DLL.
使用特殊的工厂函数创建类的对象,该函数在内部必须使用(一点点)汇编程序将新创建的对象“连接”到它们适当的偏移量。显然,这必须在 DLL 加载后的运行时完成。可以在此处找到对这种方法的一个很好的解释。
使用延迟加载 DLL。
All things considered... probably better to just go with implicit linking, in which case you definitely want to use the preprocessor technique shown above. In fact, if you create a new DLL in Visual Studio and choose the "export symbols" option these macros will be created for you.
考虑到所有事情......可能最好使用隐式链接,在这种情况下,您肯定希望使用上面显示的预处理器技术。事实上,如果您在 Visual Studio 中创建一个新的 DLL 并选择“导出符号”选项,则会为您创建这些宏。
Good luck...
祝你好运...
回答by Graeme Perrow
When you build the DLL and the module that will use the DLL, have some kind of #define that you can use to distinguish between one and the other, then you can do something like this in your class header file:
当您构建 DLL 和将使用 DLL 的模块时,请使用某种 #define 来区分一个和另一个,然后您可以在类头文件中执行以下操作:
#if defined( BUILD_DLL )
#define IMPORT_EXPORT __declspec(dllexport)
#else
#define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
...
};
Edit: crashmstr beat me to it!
编辑: crashmstr 打败了我!
回答by crashmstr
I use some macros to mark the code for import or export
我使用一些宏来标记导入或导出的代码
#ifdef ISDLL #define DLL __declspec(dllexport) #endif #ifdef USEDLL #define DLL __declspec(dllimport) #endif
Then declare the class in a header file:
然后在头文件中声明类:
class DLL MyClassToExport { ... }
Then #define ISDLL
in the libary, and USEDLL
before including the header file in the place you want to use the class.
然后#define ISDLL
在库中,然后在USEDLL
要使用类的地方包含头文件之前。
I don't know if you might need to do anything differently for working with LoadLibrary
我不知道你是否可能需要做一些不同的事情来与 LoadLibrary
回答by SridharKritha
Adding a simple working example for exporting a C++ class from a DLL :
添加一个简单的工作示例,用于从 DLL 导出 C++ 类:
The given below example gives you only a short overview of how dll and exe can interact each other (self explanatory ) but it needs more things to add for changing into a production code.
下面给出的示例仅简要概述了 dll 和 exe 如何相互交互(不言自明),但需要添加更多内容以更改为生产代码。
Full sample example is divided in to two part
完整示例分为两部分
A. Creating a .dll library (MyDLL.dll)
A. 创建 .dll 库 (MyDLL.dll)
B. Creating an Application which uses .dll library (Application).
B. 创建一个使用 .dll 库的应用程序(应用程序)。
A. .dll project file (MyDLL.dll):
A. .dll 项目文件(MyDLL.dll):
1. dllHeader.h
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
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. Application Project which load and link the already created .dll file:
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;
}
回答by Eli Bendersky
Recently I asked myself exactly the same question, and summarized my findings in a blog post. You may find it useful.
最近我问了自己完全相同的问题,并在博客文章中总结了我的发现。你可能会发现它很有用。
It covers exporting C++ classes from a DLL, as well as loading them dynamically with LoadLibrary
, and discusses some of the issues around that, such as memory management, name mangling and calling conventions.
它涵盖了从 DLL 导出 C++ 类,以及使用 动态加载它们LoadLibrary
,并讨论了一些相关问题,例如内存管理、名称修改和调用约定。
回答by Mat Noguchi
If you're willing to put a vtable in the class you're exporting, you can export a function that returns an interface and implement the class in the .dll, then put that in the .def file. You might have to do some declaration trickery, but it shouldn't be too hard.
如果您愿意在要导出的类中放置一个 vtable,则可以导出一个返回接口的函数并在 .dll 中实现该类,然后将其放入 .def 文件中。您可能需要做一些声明技巧,但这应该不会太难。
Just like COM. :)
就像COM一样。:)