使用LoadLibrary调用DLL中输出的class
著 Anup. V.
译 李成竹
原文地址:http://www.codeproject.com/dll/classesexportedusingLL.asp
引言
我见过相当多的用来说明在程序中如何使用从DLL中输出的class的代码,但这些方法都是通过隐式链接完成的。回忆一下DLL的概念,有两种方法可以使用DLL中输出的函数:一是在程序代码中简单地引用DLL中符号,这使得加载器在程序启动时隐式地加载(链接)所需的DLL,这就是众所周知的“隐式链接”。
第二种方法就是在程序运行过程中显式地加载所需的DLL(使用LoadLibrary())并且显式地链接到需要的输出符号。换句话说,如果程序要调用DLL中的一个函数,可以显式地加载一个DLL到她的进程地址空间,然后获得函数在DLL中的虚拟内存地址,并利用这个地址来调用函数。这种方法的优美之处就在于所有的工作都是在程序运行过程中完成的,并且程序可以从进程地址空间中卸载不再需要的DLL。这种方法就是“显式链接”。
背景
前面窝已经介绍了函数的调用方法,但是怎么使用输出类呢?对于隐式链接的DLL,调用类和调用函数没有什么区别;而在一般情况下,想要显示加载DLL并使用其中的类是不可能的。但是我写这篇文章并不是为了告诉你为什么这不可能,而是要告诉你如何来实现它。对了!就是使用LoadLibrary()。
在继续下文之前我想告诉你,以下的代码很粗糙,如果你准备将其用于你的项目中,请先征得你老板的同意。但是这些代码不仅用于让你加深理解,在实在没有办法的情况下也不失为一种极端的解决方法。
代码
在示例代码中,我创建了一个名为Calc.DLL计算器DLL,并在一个名为UserOfcalc的命令行程序中使用其提供的计算功能。
// Calc.DLL包含了一个名为CCalc的输出类
// 它包含3个方法,分别是 Add、Sub和GetLastFunc()
// CALC.H – CCalc类声明
#include <tchar.h>
#ifdef CALC_EXPORTS
#define CALC_API __declspec (dllexport)
#else
#define CALC_API __declspec (dllimport)
#endif
#define SOME_INSTN_BUF 260
class CALC_API CCalc
{
private:
TCHAR m_szLastUsedFunc[SOME_INSTN_BUF];
public:
CCalc ();
int Add (int i, int j);
int Sub (int i, int j);
TCHAR* GetLastUsedFunc ();
};
DLL的实现部分在文件Calc.cpp中:
#include "Calc.h"
#include <windows.h>
BOOL APIENTRY DllMain (HANDLE, DWORD, LPVOID)
{
return TRUE;
}
// 构造函数,初始化m_szLastFuncCalled数组
CCalc::CCalc ()
{
memset (m_szLastUsedFunc, 0, sizeof (m_szLastUsedFunc));
strcpy (m_szLastUsedFunc, "No function used yet");
}
int CCalc::Add (int i, int j)
{
strcpy (m_szLastUsedFunc, "Add used");
return (i + j);
}
int CCalc::Sub (int i, int j)
{
strcpy (m_szLastUsedFunc, "Sub used");
return (i - j);
}
现在,通过以下步骤可以显式地加载DLL并使用Calc类中提供的函数:
- 第一步是使用LoadLibrary将Calc.DLL加载到你的程序中。
HMODULE hMod = LoadLibrary ("Calc.dll");
if (NULL == hMod)
{
printf ("LoadLibrary failed/n");
return 1;
}
- 因为你有Calc.DLL的头文件,所以下一步就是分配一个与类大小匹配的内存块,然后调用构造函数代码。
CCalc *pCCalc = (CCalc *) malloc (sizeof (CCalc));
if (NULL == pCCalc)
{
printf ("memory allocation failed/n");