前言
动态调用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;
}
}