动态调用有源码的DLL中的导出类

前言

动态调用DLL的好处:
* 防止静态调用DLL不在报错
* 实现插件化编程

有源码的DLL可以添加接口
可以在DLL中加入建立类指针和释放类指针的接口, 不用自己去调用类构造和析构函数

对于虚函数的调用,可以通过类指针直接调用,因为可以在虚函数表中直接找到虚函数地址
对于非虚函数的调用,需要自己去拿成员函数地址,配合类指针进行强转, 进行调用.

DLL导出函数含义

>> ??0CTestOnDll@@QAE@ABV0@@Z == CTestOnDll::CTestOnDll
>> ??0CTestOnDll@@QAE@XZ == CTestOnDll::CTestOnDll
>> ??1CTestOnDll@@UAE@XZ == CTestOnDll::~CTestOnDll
>> ??4CTestOnDll@@QAEAAV0@ABV0@@Z == CTestOnDll::operator=
>> ??_7CTestOnDll@@6B@ == CTestOnDll::`vftable'
>> ?Add@CTestOnDll@@UAEHHH@Z == CTestOnDll::Add
>> ?CreateObject@@YAPAVCTestOnDll@@XZ == CreateObject
>> ?FreeObject@@YAXPAVCTestOnDll@@@Z == FreeObject
>> ?Sub@CTestOnDll@@QAEHHH@Z == CTestOnDll::Sub

调用代码

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

#include "stdafx.h"
#include <windows.h>
#include "MyDll.h"

union unionFunConvert {
    FARPROC pfnFarProc;
    int (CTestOnDll::*PFN_CTestOnDll_Sub)(int iLeft, int iRight);
};

void fnCallOurExportClass(); ///< 调用我们自己的导出类Dll的方法
int main(int argc, char* argv[])
{
    printf("dynamic call our export class on dll!\n");
    fnCallOurExportClass();
    
    /**
    dynamic call our export class on dll!
    CTestOnDll::CTestOnDll()
    pClass->Add(1, 2) = 3
    pClass->Sub(1, 2) = -1
    CTestOnDll::~CTestOnDll()
    */
    return 0;
}

void fnCallOurExportClass() {
    CTestOnDll* pClass = NULL;
    HINSTANCE hDll = NULL;
    unionFunConvert convert;

    // DYCALLCLASSONOURDLL CTestOnDll* __cdecl CreateObject();
    typedef CTestOnDll* (__cdecl*FUN_CreateObject)();
    FUN_CreateObject pFunCreateObject = NULL;

    // DYCALLCLASSONOURDLL void __cdecl FreeObject(CTestOnDll* pObj);
    typedef void (__cdecl* FUN_FreeObject)(CTestOnDll*);
    FUN_FreeObject pFunFreeObject = NULL;

    hDll = LoadLibrary(TEXT("DyCallClassOnOurDll.dll"));
    if (NULL != hDll) {
        // >> ?CreateObject@@YAPAVCTestOnDll@@XZ == CreateObject
        pFunCreateObject = (FUN_CreateObject)GetProcAddress(hDll, TEXT("?CreateObject@@YAPAVCTestOnDll@@XZ"));
        if (NULL != pFunCreateObject) {
            pClass = pFunCreateObject();
            if (NULL != pClass) {
                /// 只有虚函数才可以这么直接调用, 在虚函数表中找函数地址
                printf(TEXT("pClass->Add(1, 2) = %d\n"), pClass->Add(1, 2));

                // error LNK2001: unresolved external symbol "__declspec(dllimport) 
                // public: int __thiscall CTestOnDll::Sub(int,int)" (__imp_?Sub@CTestOnDll@@QAEHHH@Z)
                /// 非虚函数不能直接被调用, 因为非虚函数无法从一个类指针对应的虚表中得到函数地址
                // printf(TEXT("pClass->Sub(1, 2) = %d\n"), pClass->Sub(1, 2));

                // 直接去拿导出类非虚函数地址
                // >> ?Sub@CTestOnDll@@QAEHHH@Z == CTestOnDll::Sub
                convert.pfnFarProc = GetProcAddress(hDll, TEXT("?Sub@CTestOnDll@@QAEHHH@Z"));
                if (NULL != convert.pfnFarProc) {
                    printf(TEXT("pClass->Sub(1, 2) = %d\n"),
                    (pClass->*(convert.PFN_CTestOnDll_Sub))(1, 2));
                }

                // >> ?FreeObject@@YAXPAVCTestOnDll@@@Z == FreeObject
                pFunFreeObject = (FUN_FreeObject)GetProcAddress(hDll, TEXT("?FreeObject@@YAXPAVCTestOnDll@@@Z"));
                if (NULL != pFunFreeObject) {
                    pFunFreeObject(pClass);
                }
            }
        }
        FreeLibrary(hDll);
    }
}

dll代码

/// @file MyDll.h

#ifdef DYCALLCLASSONOURDLL_EXPORTS
#define DYCALLCLASSONOURDLL __declspec(dllexport)
#else
#define DYCALLCLASSONOURDLL __declspec(dllimport)
#endif // #ifndef DYCALLCLASSONOURDLL_EXPORTS

class DYCALLCLASSONOURDLL CTestOnDll {
public:
    CTestOnDll();
    virtual ~CTestOnDll();

    virtual int Add(int iLeft, int iRight);
    int Sub(int iLeft, int iRight);
};

DYCALLCLASSONOURDLL CTestOnDll* __cdecl CreateObject();
DYCALLCLASSONOURDLL void __cdecl FreeObject(CTestOnDll* pObj);

/// @file MyDll.cpp

#include "stdafx.h"
#include <stdio.h>
#include "MyDll.h"

CTestOnDll::CTestOnDll() {
    printf("CTestOnDll::CTestOnDll()\n");
}

CTestOnDll::~CTestOnDll() {
    printf("CTestOnDll::~CTestOnDll()\n");
}

int CTestOnDll::Add(int iLeft, int iRight) {
    return (iLeft + iRight);
}

int CTestOnDll::Sub(int iLeft, int iRight) {
    return (iLeft - iRight);
}

CTestOnDll* __cdecl CreateObject() {
    return new CTestOnDll();
}

void __cdecl FreeObject(CTestOnDll* pObj) {
    if (NULL != pObj) {
        delete pObj;
        pObj = NULL;
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值