没有合适的资源?快使用搜索试试~ 我知道了~
DLL中类的显式链接.pdf
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 22 浏览量
2021-09-13
19:58:08
上传
评论
收藏 1010KB PDF 举报
温馨提示
试读
23页
。。。
资源推荐
资源详情
资源评论
DLL 中类的显式链接
2008-03-14 00:33
DLL 的显式链接在某些时候比隐式链接具有更大的灵活性。比如,如果在
运行时发现 DLL 无法找到,程序可以显示一个错误信息并能继续运行。当你想为
你的程序提供插件服务时,显式链接也很有用处。
显式链接到全局 C/C++函数非常简单。假设你想调用 DLL 中的一个函数
ExportedFn,你可以像这样很简单地导出它:
extern "C" _declspec(dllexport)
void ExportedFn(int Param1, char* param2);
必须使用 extern "C"链接标记,否则 C++编译器会产生一个修饰过的函数名,这
样导出函数的名字将不再是 ExportedFn,而是一个形如"??ExportedFn@QAEX”
的名字。假设这个函数从 DLL1.dll 导出,那么客户端可以像这样调用这个函数:
HMODULE hMod = LoadLibrary("Dll1.dll");
typedef void (*PExportedFn)(int, char*);
PExportedFn pfnEF = (PExportedFn)GetProcAdress("ExportedFn");
pfnEF(1, "SomeString");
如果你想导出并显式链接一组 C++成员函数又该怎么办呢?这里有两个问题。第
一是 C++成员函数名是经过修饰的(即使指定 extern "C"标记也是这样);第二
是 C++不允许将指向成员函数的指针转换成其它类型。这两个问题限制了 C++类
的显式链接。下面介绍两种方法来解决这个问题:①用虚函数表的方法,这也是
COM 使用的方法;②用 GetProcAddress 直接调用。我将以下面这个类为例进行
讲解:
class A
{
private:
int m_nNum;
public:
A();
A(int n);
virtual ~A();
void SetNum(int n);
int GetNum();
};
一.用虚函数表进行显式链接
这个方法是 COM 的基础。当我们定义一组虚函数的时候,编译器会创建一个虚函
数表,将各虚函数的地址按声明的顺序放入其中。当一个类对象被创建时,它的
前四个字节是一个指针,指向这个虚函数表。如果我们将 A 的定义修改成这样:
class A
{
private:
int m_nNum;
public:
A();
A(int n);
virtual ~A();
virtual void SetNum(int n);
virtual int GetNum();
};
那么一个虚函数表将被编译器创建出来,其中包含三个函数的地址:析构函数,
SetNum 和 GetNum。现在类对象要在 dll 中创建。既然我们要显式链接,就需要
一些全局导出函数来调用 operator new 以创建对象。因为 A 有两种构造函数,
所以我们定义两个函数 CreateObjectofA()和 CreateObjectofA1(int)并将其导
出。客户可以这样来使用类对象:
typedef A* (*PFNCreateA1)();PFNCreateA1 pfnCreateA1 =
(PFNCreateA1)GetProcAddress(hMod, TEXT("CreateObjectofA1"));A* a =
(pfnCreateA1)();a->SetNum(1); _tprintf(TEXT("Value of m_nNum in a
is %d\n"),a->GetNum());delete a;要注意的是 CreateObjectofA 必须使用
operator new 来创建对象这样客户端才可以安全地调用 operator delete 来销
毁对象:
extern "C" __declspec(dllexport) A* CreateObjectofA1()
{
return new A();
}
这个方法的使用得用户可以很容易地为你的程序制作插件。它的缺点是创建对象
的内存必须在 dll 中分配。
二.直接使用 GetProcAddress 进行显式链接
这个方法的关键在于将 GetProcAddress 函数返回的 FARPROC 类型转化为 C++中
指向成员函数的指针。幸运的是,通过 C++的 unio 和模板机制,这个目标可以
很容易地实现。我们要做的只是定义如下的函数:
template<class Src , class Dest>
Dest force_cast(Src src){
union{
Dest d;
Src s;
} convertor;
convertor.s = Src;
return convertor.d;
}
上面的函数允许我们在任何类型间进行转换,比 reinterpret_cast 更加有效。
例如,我们定义一种指针类型:
typedef void (A::*PSetNum)(int);
我们可以将 FARPROC 类型的指针 fp 转化成 PSetNum:
PSetNum psn = force_cast<PSetNum>(fp);
找到了将 FARPROC 转化成成员函数指针的方法以后,我们要考虑如何将 C++成员
函数以更加友好的名字导出。这可以通过一个.def 文件来实现。
第一步是找到待导出函数经过修饰的函数名,这可以通过查看 map file 或者汇
编代码来实现。然后在.def 文件中指定导出函数的新的函数名:
EXPORTS
ConstructorOfA1 = ??0A@@QAE@XZ PRIVATE
ConstructorOfA2 = ??0A@@QAE@H@Z PRIVATE
SetNumOfA = ?SetNum@A@@UAEXH@Z PRIVATE
GetNumOfA = ?GetNum@A@@UAEHXZ PRIVATE
DestructorOfA = ??1A@@UAE@XZ PRIVATE
下面是调用这些成员函数的方法:
typedef void (A::*PfnConstructorOfA1)();
typedef void (A::*PfnConstructorOfA2)(int);
typedef void (A::*PfnDestructorOfA)();
typedef void (A::*PfnSetNumOfA)(int);
typedef int (A::*PfnGetNumOfA)();
A* a1 = (A*)_alloca(sizeof(A));
PfnConstructorOfA1 pfnConsA =
force_cast<PfnConstructorOfA1>(GetProcAddress(hMod,
TEXT("ConstructorOfA1")));
(a1->*pfnConsA)();
PfnSetNumOfA pfnSetNumA =
force_cast<PfnSetNumOfA>(GetProcAddress(hMod,
TEXT("SetNumOfA")));
剩余22页未读,继续阅读
资源评论
苦茶子12138
- 粉丝: 1w+
- 资源: 6万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功