使用GetProcAddress获取C++重载函数
2015-09-20 20:02
267 查看
GetProcAddress函数是用来在动态加载完动态链接库后,从链接库中获取函数地址的。它的用法如下:
hModule参数就是LoadLibrary函数返回的动态链接库的句柄,lpProcName指向要获取的函数名称,函数名称以0结尾,对于函数名称是数值编号的lpProcName可以指定为编号数值。函数执行成功则返回要获取的函数的入口地址,失败则返回NULL。
C++是支持函数重载的,也就是说允许多个不同的函数可以有同样的函数名。那么能不能通过函数名来获取C++的重载函数呢?从理论上来分析,由于GetProcAddress函数是通过函数名来唯一确定被调用函数的地址的,所以重载函数的地址是不可能用GetProcAddress通过函数名来获取的。
MSDN对GetProcAddress函数进行解释时,说
The spelling and case of the function name pointed to by lpProcName must be identical to that in the EXPORTS statement of the source DLL’s module-definition (.DEF) file. The exported names of Win32 API functions may differ from the names you use when calling these functions in your code.
翻译过来就是,lpProcName指向的函数名,它的拼写和大小写必须和DLL源代码中的模块定义源文件(.DEF)里的EXPORTS声明中指定的相同。Win32 API函数的导出名可能不同于你在代码中调用的这些函数名。
那么如何处理函数的导出名与调用名不同呢?这个不同被宏隐含在相关的SDK头文件中。从MSDN对GetProcAddress函数解释可以看出,GetProcAddress函数实际是通过函数的导出名来在DLL中搜索需要的函数的。这样其实也解释了为何不能通过函数名来获取C++的重载函数了。C++的编译器为了保证导出函数名的唯一性,就无法将重载函数指定成相同的名称,于是就对函数名进行了处理,这样导出的函数名与源文件中定义的函数名不一样了,也就无法用源文件中的函数名来获取函数地址。这不仅仅是对于重载的C++函数,对于没有重载的C++函数也是一样的。
通过上面的解释我们既知道GetProcAddress无法通过源文件中的函数名来获取C++的函数的原因,同时也为我们提供了通过GetProcAddress函数获取我们需要的C++函数的方法。我们通常的做法就是对要导出的C++函数加上extern “C”关键字,让该函数用标准C语言的方式来编译和导出的,但这样就无法定义重载函数,因为C语言不支持函数重载。
不使用extern “C”关键字来声明C++函数的话,虽然能支持函数重载,但我们就只能使用函数的导出名来获取函数地址。我们有两种方式来获取函数的导出名,一种是按照C++编译器的函数名修饰规则来推导导出的函数名,具体的规则参见函数调用约定与名字修饰约定,不过如果函数导出名被重新定义为了其他名字,这个方式就不适用了。第二种方法是用工具来查看DLL中的导出表,像VS2013里就可以在使用命令行的命令dumpbin来察看导出表,具体使用方法如下:
通过这个命令可以得到DLL中的函数的导出名和序数值,这样既可以使用序数值,也可以使用函数的导出名来获取函数地址了。
FARPROC GetProcAddress(HMODULE hModule,LPCSTR lpProcName);
hModule参数就是LoadLibrary函数返回的动态链接库的句柄,lpProcName指向要获取的函数名称,函数名称以0结尾,对于函数名称是数值编号的lpProcName可以指定为编号数值。函数执行成功则返回要获取的函数的入口地址,失败则返回NULL。
C++是支持函数重载的,也就是说允许多个不同的函数可以有同样的函数名。那么能不能通过函数名来获取C++的重载函数呢?从理论上来分析,由于GetProcAddress函数是通过函数名来唯一确定被调用函数的地址的,所以重载函数的地址是不可能用GetProcAddress通过函数名来获取的。
MSDN对GetProcAddress函数进行解释时,说
The spelling and case of the function name pointed to by lpProcName must be identical to that in the EXPORTS statement of the source DLL’s module-definition (.DEF) file. The exported names of Win32 API functions may differ from the names you use when calling these functions in your code.
翻译过来就是,lpProcName指向的函数名,它的拼写和大小写必须和DLL源代码中的模块定义源文件(.DEF)里的EXPORTS声明中指定的相同。Win32 API函数的导出名可能不同于你在代码中调用的这些函数名。
那么如何处理函数的导出名与调用名不同呢?这个不同被宏隐含在相关的SDK头文件中。从MSDN对GetProcAddress函数解释可以看出,GetProcAddress函数实际是通过函数的导出名来在DLL中搜索需要的函数的。这样其实也解释了为何不能通过函数名来获取C++的重载函数了。C++的编译器为了保证导出函数名的唯一性,就无法将重载函数指定成相同的名称,于是就对函数名进行了处理,这样导出的函数名与源文件中定义的函数名不一样了,也就无法用源文件中的函数名来获取函数地址。这不仅仅是对于重载的C++函数,对于没有重载的C++函数也是一样的。
通过上面的解释我们既知道GetProcAddress无法通过源文件中的函数名来获取C++的函数的原因,同时也为我们提供了通过GetProcAddress函数获取我们需要的C++函数的方法。我们通常的做法就是对要导出的C++函数加上extern “C”关键字,让该函数用标准C语言的方式来编译和导出的,但这样就无法定义重载函数,因为C语言不支持函数重载。
不使用extern “C”关键字来声明C++函数的话,虽然能支持函数重载,但我们就只能使用函数的导出名来获取函数地址。我们有两种方式来获取函数的导出名,一种是按照C++编译器的函数名修饰规则来推导导出的函数名,具体的规则参见函数调用约定与名字修饰约定,不过如果函数导出名被重新定义为了其他名字,这个方式就不适用了。第二种方法是用工具来查看DLL中的导出表,像VS2013里就可以在使用命令行的命令dumpbin来察看导出表,具体使用方法如下:
dumpbin /exports dllname.dll
通过这个命令可以得到DLL中的函数的导出名和序数值,这样既可以使用序数值,也可以使用函数的导出名来获取函数地址了。
相关文章推荐
- C++中虚析构函数
- C++那些细节--inline关键字
- 实现一个数组中奇数和偶数分开,奇数在前部分,偶数在后部分 时间复杂度为O(n),空间复杂度为O(1)
- OC学习将C语言字符串转换为OC字符串
- C++ 数组
- c语言学习笔记(1)基本数据类型及auto,register,static分析
- C语言 --- 函数指针(初级)
- C语言实现单链表-04版
- C++中CString,int,string,char*之间的转换
- Eclipse环境下通过C语言连接MySQL数据库方法
- c++实现两个元素进栈和出栈的顺序
- C++拷贝构造函数详解
- c++地址问题
- C++虚继承的概念
- C/C++堆和栈的区别
- 项目19.2 能够对齐的数据
- 黑马程序员--C语言学习笔记之运算符
- C文件API函数
- C++中接口与抽象类
- 3Sum, 3Sum Closest, 4 Sum