显式加载DLL并使用 DLL 中的类(原创)
首先需要强调,当使用某个类时一般目的有二:实例化成对象或者继承它产生新类。
对于前者,我们可以构造一个抽象类(java里的接口)来连接调用方和DLL。
抽象类:
// Interface.h
公共文件/
#pragma
once
class
Interface
{
public
:
virtual void ShowMsg() = 0; //
将调用方需要调用的成员函数声明成纯虚函数.
virtual ~Interface(){};//
抽象类的虚析构函数
};
// Interface.cpp
被调用方文件
//
注意下面的代码并不是实现 Interface 类,而是因为联系紧密才写在这。
#include
"stdafx.h"
#include
"Test.h"
#include
"Interface.h"
//
通过导出函数形式向调用方提供指向派生类对象的基类指针
extern
"C" __declspec(dllexport) Interface* Export(void)
{
return (Interface*)new Test();
}
|
将真正要调用的类声明成抽象类 Interface 的派生类:
// Test.h
被调用方文件//
//
类的声明
#pragma
once
#include
"Interface.h"
class
Test:public Interface
{
public
:
Test()
virtual ~Test();
virtual void ShowMsg(void);
private
:
CString s;
};
// Test.cpp
被调用方文件
//
类的实现
#include
"stdafx.h"
#include
"Test.h"
Test::Test()
{
s = "hello form dll";
}
Test::~Test()
{
AfxMessageBox(_T("destructor"));
}
void
Test::ShowMsg()
{
AfxMessageBox(s);
}
|
在调用方调用DLL时动态加载:
//
调用方文件 /
#include
"stdafx.h"
#include
"Interface.h" //
包含抽象类从而使用接口
//
在调用处添加如下代码
HINSTANCE hDll;
hDll = LoadLibrary(_T("module1.dll"));//
加载DLL库文件,DLL名称和路径用自己的
if(hDll == NULL)
{
TRACE("/n/nload dll fail/n/n");
return;
}
typedef Interface*(*pExport)(void); //
定义指向导出函数的指针类型
pExport Get;
Get = (pExport)GetProcAddress(hDll,"Export");//
将指针指向函数首地址
if(Get == NULL)
{
TRACE("/n/nload address fail/n/n");
return;
}
Interface *t = Get();//
调用导出函数获得抽象类指针
t->ShowMsg();//
通过该指针调用类成员函数
delete t; //
释放DLL中生成的对象
FreeLibrary(hDll); //
释放库句柄
|
写到这第一个目的达到了。其实将需要调用的类的指针直接导出更简单,但是使用抽象类接口
却更加优雅,思路也比较清晰(在这方面java比较舒服)。
至于继承DLL中的类,最好的方法是使用扩展DLL。其实我们应该尽量避免继承DLL中的类。
动态链接库顾名思义是可以随时更新动态链接到程序的模块库,目的是方便程序的模块化和动
态更新。而继承的本意是为了实现多态,多态的基础就是所有同一基类的派生类可以通过相同
基类指针来访问,基类是所有派生类的抽象,是基石,是很少甚至不可改变的。因此把基类放在
动态链接库,然后从外面去继承他是不明智也是很奇怪的。
个人理解有限,高手不要见笑。