如何使用VS2013将C++派生类封装成DLL并动态调用

前期知识


将派生类封装成DLL并动态调用

如果源程序中C++的基类和由该基类生成的多个派生类在同一头文件和cpp文件下,要想将派生类编译成DLL使用,需要分别将每个派生类单独编译成DLL,再建立一个测试工程动态调用生成的DLL。

1.dll动态库的动态调用接口函数说明

LoadLibrary

函数原型:HMODUBLE WINAPI LoadLibrary(LPCTSTR lpFileName);(其中HMODUBLE通常是被载入模块的线性地址类型;LPCTSTR =const tchar *。)
功能描述:表示要将库装载到内存,准备使用。如果要装载的库依赖于其它库,必须首先装载依赖库。如果LoadLibrary操作失败,返回NULL值;如果库已经被装载过,则LoadLibrary会返回同样的句柄。
参数中的lpFileName一般是库的全路径,这样LoadLibrary会直接装载该文件;如果只是指定了库名称,在LoadLibrary会在当前目录下查找。

GetProcAddress

函数原型:FARPROC WINAPI GetProcAddress (HMODUBLE hModule,LPCTSTR lpProcName);(其中FARPROC 通常代表函数指针)
功能描述:表示已获取指向应用程序要调用的每个导出函数的函数指针。由于应用程序是通过指针调用 DLL 的函数,编译器不生成外部引用,故无需与导入库链接。
参数中的hModule是由LoadLibrary加载库后返回的模块线性地址句柄;lpProcName是要调用的库函数名称。

FreeLibrary

函数原型: BOOL WINAPI FreeLibrary(HMODUBLE hModule)
功能描述:使用完 DLL 后调用 FreeLibrary卸载动态库。卸载成功返回true,否则返回false。

2. 将派生类封装成DLL并进行动态调用

建立一个普通测试项目

使用VS2013创建一个新项目,选择Win32——Win32控制台应用程序(此处需选择名称及位置,假设该处名称为dll_deal)
应用程序类型:控制台应用程序+附加选项:预编译头,完成以上步骤即可创建一个dll_deal项目。

修改项目的字符集属性

项目——dll_deal属性(最后一行就是)——配置属性——常规——字符集,设置为“未设置”。项目默认创建的字符集为“使用UNICODE字符集”。(如果字符集设置为UNICODE字符集的话,调试程序时无法自动实现 “char *”转换为“LPCWSTR”,需使用_T()或其它方法解决)

添加dll项目

文件——添加——新建项目——Win32——Win32控制台应用程序(此处填写名称dll1,位置默认)
应用程序类型:DLL+附加选项:空项目。
完成以上步骤即可在当前dll_deal项目中增加dll1项目。dll2项目也可参照dll1项目的添加即可。
在dll_deal、dll1和dll2项目中增加下面.h和.cpp源程序文件(其中dll_deal中的stdafx.h和stdafx.cpp为项目创建时默认生成,无需增加)。

说明
dll_deal.h/dll1.h/dll2.h中定义相同的含有纯虚函数virtual void display() const = 0的基类。
dll1.cpp中定义继承类test1,实现虚函数virtual void display() const的定义,并实现一个创建类函数和一个销毁类指针函数。
dll2.cpp中定义继承类test2,实现虚函数virtual void display() const的定义,并实现一个创建类函数和一个销毁类指针函数。
dll_deal.cpp中实现调用不同动态库的display()方法。

dll_deal.h

#ifndef DLL_DEAL_H
#define DLL_DEAL_H

#include <iostream>
using namespace std;

class test_base {
public:
    test_base(){}
    virtual ~test_base() {}
    void call_base()
    {
        cout << "call base" << endl;
    }
    virtual void display() const = 0;
};

// the types of the class factories
typedef test_base* create_t();
typedef void destroy_t(test_base*);

#endif

dll_deal.cpp

// dll_deal.cpp : Defines the entry point for the console application.

#include "stdafx.h"
#include <Windows.h>
#include <string>
#include "dll_deal.h"

int main()
{
    HINSTANCE hDll; //DLL句柄
    string dll_name;

    cout << "Please choose the dll_name(dll1.dll or dll2.dll):" << endl;
    cin >> dll_name;
    cout << endl;

    hDll = LoadLibrary(dll_name.c_str());//加载DLL,需要将DLL放到工程目录下.
    if (hDll != NULL)
    {
        cout << "LOAD DLL success!" << endl;
        // load the symbols
        create_t* create_test = (create_t*)GetProcAddress(hDll, "create");
        if (create_test == NULL)
        {
            cout << "Cannot load symbol create: " << endl;
            return 1;
        }
        destroy_t* destroy_test = (destroy_t*)GetProcAddress(hDll, "destroy");
        if (destroy_test == NULL)
        {
            cout << "Cannot load symbol destroy: " << endl;
            return 1;
        }

        // create an instance of the class
        test_base* c_test = create_test();

        // use the class
        c_test->display();

        // destroy the class
        destroy_test(c_test);

        // unload the? library
        FreeLibrary(hDll);
    }
    else
    {
        cout << "Load DLL Error or DLL not exist!" << endl;
    }
    return 0;
}

dll1.h

#ifndef DLL1_H
#define DLL1_H

#include <iostream>
using namespace std;

class test_base {

public:
    test_base(){}

    virtual ~test_base() {}

    void call_base() {
        cout << "call base" << endl;
    }

    virtual void display() const = 0;
};

// the types of the class factories
typedef test_base* create_t();
typedef void destroy_t(test_base*);

#endif

dll1.cpp

#include "dll1.h"

class test1 : public test_base {
public:
    virtual void display() const {
        cout << "Running in test1.so Now" << endl;
    }
};

// the class factories
extern "C" __declspec(dllexport)test_base* create() {
    return new test1;
}

extern "C" __declspec(dllexport)void destroy(test_base* p) {
    delete p;
}

dll2.h

#ifndef DLL2_H
#define DLL2_H

#include <iostream>
using namespace std;

class test_base {

public:
    test_base(){}

    virtual ~test_base() {}

    void call_base() {
        cout << "call base" << endl;
    }

    virtual void display() const = 0;
};

// the types of the class factories
typedef test_base* create_t();
typedef void destroy_t(test_base*);

#endif

dll2.cpp

#include "dll2.h"

class test2 : public test_base {
public:
    virtual void display() const {
        cout << "Running in test2.so Now" << endl;
    }
};

// the class factories
extern "C" __declspec(dllexport)test_base* create() {
    return new test2;
}

extern "C" __declspec(dllexport)void destroy(test_base* p) {
    delete p;
}

各源程序中代码填充完成之后,在dll1项目中完成dll1.dll的生成;在dll2项目中完成dll2.dll的生成;在dll_deal项目中进行Debug,结果如下:
DLL编译结果

输入dll1.dll或者dll2.dll后,结果如下:
DLL调用结果

3.补充

如果想在测试项目中调用各派生类专有的成员函数,要调用的函数需在基类头文件中声明为虚函数,并在其他派生类的cpp文件中定义一个空的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值