为什么GetProcAddress获取不到dllexport导出的函数?

为什么GetProcAddress获取不到dllexport导出的函数?

作者:BlogUpdater |  时间:2020-10-05 |  浏览:76 |  评论已关闭 条评论

名称修饰(decoration)的好处和坏处
dllexport属性告诉链接器:请将指定的函数标记为导出并为它生成一个导出项。
这个导出项是经过修饰的,对于导出多个重载的函数来说,导出修饰后的名称是十分必要的。但是,这也意味着:你传入到GetProcAddress函数中的函数字符串也需要是修饰版本的。

从我们之前的几篇关于调用约定的文章中,我们知道,函数导出名称的修饰语法在各种硬件平台上是各不相同的,同时,随着调用约定的不同,导出的名称也会不同。
举个例子,如果你从PowerPC平台上的一个DLL中导出一个函数,则你需要使用GetProcAddress(hinst, “..SomeFunction”)来获取这个这个函数指针。
如果是80386平台上使用extern “C” __stdcall调用约定,则需要使用GetProcAddress(hinst, “_SomeFunction@8”)。如果使用的是__fastcall调用约定,则需要使用GetProcAddress(hinst, “@SomeFunction@8”)。

另外,C++里的名称修饰和编译器厂商相关。如果是Microsoft C++编译器,则对于一个C++导出函数,需要使用GetProcAddress(hinst, “?SomeFunction@@YGXHH@Z”),但是如果是Borland C++编译器,则需要另外的函数字符串来表示。

所以,如果你开发了一个函数,你希望你的函数在各种不同的硬件平台,或者不同的语言,或者不同的C++编译器上都可以供客户调用,那么你必须导出它的未修饰版本。

当生成一个DLL时,编译器会同时生成一个对应的LIB文件,这个LIB文件会将修饰后的名称翻译成未经修饰的版本。所以,举个例子,如果客户代码需要获取函数_GetTickCount@0,则这个LIB文件会将它翻译为kernel32!GetTickCount。

课后练习题
既然dllexport属性将导出函数绑定到某个特殊的硬件平台,编译器或者语言(通过将函数导出为修饰版本),那为什么MSVCRT.DLL会使用这个属性呢?

最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《Why can’t I GetProcAddress a function I dllexport’ed?》

评论已关闭。