从DLL导出C ++类

时间:2008-08-26 13:18:30

标签: c++ windows dll

我的大多数C / C ++开发涉及单片模块文件,绝对没有任何类,所以通常当我需要使用可访问函数创建 DLL 时,我只需使用标准{{1}导出它们指令。然后通过__declspec(dllexport)动态访问它们,或者在编译时使用头文件和lib文件访问它们。

如果要导出整个类(及其所有公共方法和属性),如何执行此操作?

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

如何使用头和lib进行编译时链接?

6 个答案:

答案 0 :(得分:17)

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

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

编辑:crashmstr击败了我!

答案 1 :(得分:17)

  

后期绑定怎么样?如在装载   它与LoadLibrary()和   GetProcAddress()?我习惯了   在运行时加载库和它   如果你能做到这一点会很棒   这里。

因此有两种方法可以加载DLL。第一个是引用DLL中的一个或多个符号(例如,您的类名),提供适当的导入.LIB并让链接器解决所有问题。

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

这两种方法都适用于C级函数导出。您可以让链接器处理它,也可以按照您的说明调用GetProcAddress。

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

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

  1. 使用特殊的工厂函数创建类的对象,该函数在内部将必须使用(一小部分)汇编程序将新创建的对象“挂钩”到其适当的偏移量。这显然必须在DLL加载后的运行时完成。可以找到对此方法的一个很好的解释here

  2. 使用delay-load DLL

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

    祝你好运......

答案 2 :(得分:12)

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

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

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

然后在头文件中声明该类:

class DLL MyClassToExport { ... }

然后在库中#define ISDLLUSEDLL,然后将头文件包含在您要使用该类的位置。

我不知道您是否可能需要采取不同的方式来处理LoadLibrary

答案 3 :(得分:12)

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

以下给出的示例仅为您提供了dll和exe如何相互交互的简短概述(自解释),但需要添加更多内容才能更改为生产代码。

完整示例示例分为两部分

甲。创建.dll库(MyDLL.dll)

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

:一种。 .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中。加载并链接已创建的.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;
}

答案 4 :(得分:7)

最近我问自己完全相同的问题,并总结了我的发现in a blog post。您可能会发现它很有用。

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

答案 5 :(得分:0)

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

就像COM一样。 :)