使用GetProcAddress获取C++重载函数

  GetProcAddress函数是用来在动态加载完动态链接库后,从链接库中获取函数地址的。它的用法如下:

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++)