名称修饰(decoration)的好处和坏处
dllexport属性告诉链接器:请将指定的函数标记为导出并为它生成一个导出项。这个导出项是经过修饰的,对于导出多个重载的函数来说,导出修饰后的名称是十分必要的。但是,这也意味着:你传入到GetProcAddress函数中的函数字符串也需要是修饰版本的。
从我们之前的几篇关于调用约定的文章中,我们知道,函数导出名称的修饰语法在各种硬件平台上是各不相同的,同时,随着调用约定的不同,导出的名称也会不同。举个例子,如果你从PowerPC平台上的一个DLL中导出一个函数,则你需要使用GetProcAddress(hinst,“..SomeFunction”)来获取这个这个函数指针。如果是平台上使用extern“C”__stdcall调用约定,则需要使用GetProcAddress(hinst,“_SomeFunction
8”)。如果使用的是__fastcall调用约定,则需要使用GetProcAddress(hinst,“SomeFunction8”)。另外,C++里的名称修饰和编译器厂商相关。如果是MicrosoftC++编译器,则对于一个C++导出函数,需要使用GetProcAddress(hinst,“?SomeFunction
YGXHHZ”),但是如果是BorlandC++编译器,则需要另外的函数字符串来表示。所以,如果你开发了一个函数,你希望你的函数在各种不同的硬件平台,或者不同的语言,或者不同的C++编译器上都可以供客户调用,那么你必须导出它的未修饰版本。
当生成一个DLL时,编译器会同时生成一个对应的LIB文件,这个LIB文件会将修饰后的名称翻译成未经修饰的版本。所以,举个例子,如果客户代码需要获取函数_GetTickCount
0,则这个LIB文件会将它翻译为kernel32!GetTickCount。课后练习题
既然dllexport属性将导出函数绑定到某个特殊的硬件平台,编译器或者语言(通过将函数导出为修饰版本),那为什么MSVCRT.DLL会使用这个属性呢?
最后
RaymondChen的《TheOldNewThing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。本文来自:《Whycan’tIGetProcAddressafunctionIdllexport’ed?》