Winrt 环境自定义 API 与系统 API 冲突解决

来源:互联网 发布:网络奇兵1游侠 编辑:程序博客网 时间:2024/06/06 11:41

Winrt  环境中有许多  API  不能使用,为此需要通过一些手段模拟实现缺失的 API,使许多老代码能够继续工作。但是在 VS 编译环境中提供的链接库又包含这些 API 符号的定义,使得链接时链接到这些不能使用的 API 上,应用不能正常运行,也不能通过 Windows Store 验证。

比如:

void test(){    Sleep(0);}
在链接的时候,就会链接到 kernel32.lib 的 _Sleep@4 API

方案1—— C++ 语法

将模拟 API 定义为 C++ 语法,不加 extern "C" 修饰。
因为C++有函数重载机制,所以 API 定义成 C 语法的名称还是 C++ 语法的名称,都可以匹配,调用方不需要修改。在链接时寻找的是 C++ 语法的名称,不会与系统库的符号冲突。
这种方法只适用于老代码是 C++ 语言编写的,或者可以在 C++ 编译器上编译的情形。对于很多开源库,比如 ffmpeg,就无法通过该方案移植到 Winrt 平台。

方案2—— __cdecel调用方式

将模拟 API 定义为 __cdecl 调用方式,保持 C 语法格式。
Windows api 都是 __stdcall 调用方式,修改为 __cdecl ,不需要修改调用方的代码。在编译时,会引用 __cdecl 格式的名称,比如 _Sleep@4 在 __cdecl 方式下的名称为 _Sleep,这样也与系统库里面的 API 名称区分开来了。
这种方法在 ARM、X64 平台无效,因为这些平台不采用 __stdcall __cdecl 之类的调用方式,不管定义函数为 __stdcall 还是 __cdecl ,结果都是一样,解决不了符号冲突。

方案3—— 调整链接顺序

VC 链接器的工作原理是:
  1. 记录所有未定义符号(外部引用),集合 U
  2. 对所有链接库,依次处理,对每个库,搜寻 U 中的符号,比且有可能增加新的未定义符号到 U 集合
  3. 循环2直到 U 集合没有变化
VC IDE 环境中链接库的顺序一般为:
  1. 手动指定的库
  2. 工程依赖项目生成的库
  3. 默认引用的库
利用链接顺序解决符号冲突,需要仔细思考,并认真测试。只有在前两个方案不能解决问题的情况,才考虑使用该方案。另外也可以结合几种方案,综合考虑。
原创粉丝点击