前一篇文章中是用隐式方法调用
DLL
的。下面介绍显式调用。
显式的调用就是指在应用程序中用
LoadLibrary
或
MFC
提供的
AfxLoadLibrary
显式的将自己所做的动态连接库调进来,动态连接库的文件名即是上面两个函数的参数,再用
GetProcAddress()
获取想要引入的函数。
在前面的基础上再建一个测试工程,代码如下:
#include
"stdafx.h"
#include
<iostream>
//#include "Try.h"
using
namespace
std;
typedef
int (*Fn_FunType)() ;
int
main()
{
HINSTANCE
hInstance = 0;
hInstance = LoadLibrary("Try.dll") ;
if (hInstance)
{
Fn_FunType
pFun = (Fn_FunType)::GetProcAddress(hInstance ,"fnTry") ;
if (pFun)
{
cout<<pFun()<<endl;
}
}
int
n = 10
;
n = *(int *)::GetProcAddress(hInstance ,"nTry") ;
cout<<n<<endl;
system("pause") ;
return 0 ;
}
上面的代码貌似没上面问题,但是实际上第一个
cout
永远也不会执行,第二个
cout
输出的是
10
。为什么会这样?
先来看看,上面的代码在
DLL
中是个什么模样,用
VS
自带的
dependency walker
可以查看
DLL
文件,该工具在
Microsoft Visual Studio 8/
common7/tools/bin
下。如下图所示:
原来,
"C"
或者
"C++"
函数在编译器内部(编译和链接)通过修饰名识别。修饰名是编译器在编译函数定义或者原型时生成的字符串。有些情况下使用函数的修饰名是必要的,如在模块定义文件里头指定输出
"C++"
重载函数、构造函数、析构函数,又如在汇编代码里调
用
"C""
或
"C++"
函数等。关于修饰名后面会讲到。
将上面的代码稍微作一下修改:
…
Fn_FunType
pFun = (Fn_FunType)::GetProcAddress(hInstance ," ?fnTry@@YAHXZ") ;
…
int
n = *(int *)::GetProcAddress(hInstance ,"?nTry@@3HA") ;
…
Ok,
现在可以正常输出了。
上面的方法可以导出全局函数和变量,但是却无法导出成员函数和成员变量。如下:
typedef
void (CTry::*Fn_FooType)() ;
int
main()
{
HINSTANCE
hInstance = 0;
hInstance = LoadLibrary("Try.dll") ;
CTry *pTry = (CTry *)_alloca(sizeof(CTry));
Fn_FooType pFun = (Fn_FooType)::GetProcAddress(hInstance, "?print@CTry@@QAEXXZ") ;
(pTry->*pFun)() ;
Return 0 ;
}
编译器会提示,
FARPROC
类型不能转换成
Fn_FooType
类型。因为
在
C++
中,成员函数的指针是个比较特殊的东西。对普通的函数指针来说,可以视为一个地址
,
在需要的时候可以任意转换并直接调用。但对成员函数来说,调用的时候也必须采用特殊的语法。
C++
专门为成员指针准备了三个运算符
: "::*"
用于指针的声明,而
"->*"
和
".*"
用来调用指针指向的函数。而且对成员函数指针不能进行类型转换。简单的说,每个成员函数指针都是一个独有的类型,无法转换到任何其它类型。
但是在
C++
中,总是有办法的。
使用
union
类型可以逃避
C++
的类型转换检测。为了通用,使用模板传入数据类型。
template
<classDest, classSrc>
Dest
force_cast(Srcsrc)
{
union
{
Dest
d;
Src
s;
} convertor;
convertor.s = src;
return
convertor.d;
}
上面的代码变为:
typedef
void (CTry::*Fn_FooType)() ;
int
main()
{
HINSTANCE
hInstance = 0;
hInstance = LoadLibrary("Try.dll") ;
if (hInstance)
{
CTry *pTry = (CTry *)_alloca(sizeof(CTry));
FARPROC
fp
= ::GetProcAddress(hInstance ,"?print@CTry@@QAEXXZ") ;
Fn_FooType
pFun = force_cast<Fn_FooType>(fp) ;
if (pFun)
{
(pTry->*pFun)() ;
}
}
return 0 ;
}
posted on 2009-03-06 00:54
隙中驹 阅读(339)
评论(1) 编辑 收藏 引用