Chuyu-Team / YY-Thunks

Fix DecodePointer, EncodePointer,RegDeleteKeyEx etc. APIs not found in Windows XP RTM.
MIT License
497 stars 102 forks source link

SDK5.* unresolved external symbol _SHSetFolderPathW@16 #53

Closed chirsz-ever closed 1 year ago

chirsz-ever commented 1 year ago

我在尝试用 VC6 链接 Rust 程序, 使用 Windows Server 2003 SP2 Platform SDK 加上 YY-Truncks v1.0.7-Beta4 编译, 出现如题报错,自行在代码中定义相应函数后不再报错。

根据 SHSetFolderPathW 的文档,它应该在 Windows Server 2003 Platform SDK 里,此处不知道为何报错找不到。

mingkuang-Chuyu commented 1 year ago

影响范围

sdk低于6.0,比如说vc6默认带的sdk5.0场景。

临时解决方案

编译器保持不变,但是将sdk升级到6.0或者更高版本比如说10.0。注意,升级sdk版本不影响编译的代码兼容老系统。

VC6的默认SDK版本受SDK注册表中的Current控制。可以手工更改它,也可以安装Win7 SDK,内部附带了一个SDK Configure工具,此工具最高可以调整到SDK 7.1。

修复计划

代码层面这个问题不打算修复。 我会更新readme最低要求为SDK6或者更高版本。

之前的回复

估计是VC6默认附带的sdk 5.0里shell32.lib没有这个函数。 如果你使用SDK 7.0或者10.0应该就没有问题了吧?

要不帮忙试试?

SDK升级到7.0或者更高,编译器保持6.0不变。

如果这样确定没问题的话,那我就把问题关了,毕竟sdk版本低我这边处理起来也不方便,另外升级SDK也很容易。

chirsz-ever commented 1 year ago

根据 wikipedia 的说法,VC6 附带的是 SDK 5.0,而最后支持 VC6 的 SDK 是 Microsoft Platform SDK February 2003 或 Windows Server 2003 R2 Platform SDK,二者版本号分别是 5.2.3790.0 和 5.2.3790.2075.51,差别应该不大。经测试无论是 VS6 附带的 shell32.lib 还是 Windows Server 2003 R2 Platform SDK 的 shell32.lib 都不带 SHSetFolderPathW 符号。

经过一番尝试,最后我发现它是一个未导出的符号

SHSetFolderPath is not exported by name from Shell32.dll. To use the function, you must call GetProcAddress with ordinal 231 for SHSetFolderPathA (for ANSI strings) or ordinal 232 for SHSetFolderPathW (for Unicode strings) to obtain a function pointer.

SHSetFolderPathW 需要 shell32.dll 版本 5.0,相当于 Windows 2000

YY-Thunks 使用了 SHSetFolderPathW,是因为更高版本的 Windows SDK 中的 shell32.lib 里有它的导出符号?

mingkuang-Chuyu commented 1 year ago

认真看英语,它是说它没有安名字导出,并没有说没有导出,不过从你的错误信息看,是真的没导出。

文档说XP支持。

首先VC6使用SDK 7应该是没问题的,改注册表就可以了,当然没测试过,VC6太古老了。因为微软也说vs2008不支持 SDK10.0,但是手工改注册表切过去并无问题。

当然是否支持这不重要,因为完全可以手工新的sdk里面的lib文件拿复制过去用。

chirsz-ever commented 1 year ago

经测试,使用 VS2008 附带的 SDK 6.0a 的 shell32.lib 能链接成功;

在我的 Windows 10 系统上 shell32.dll 里有 SHSetFolderPathW 的名字导出;

我觉得应该支持 VC6 + SDK 5.2,目前看来只需要加这个符号,而且不用重新实现,只要映射到 shell32.dll 的 ordinal 232 就行。

Windows Server 2000 的 shell32.dll 可能没有名字导出 SHSetFolderPathW 。等我或者谁测一下 Windows Server 2000 和 Windows XP 里面的 shell32.dll 有没有 SHSetFolderPathW 的导出名,我猜 2000 没有 XP 有。如果没有,在 YY-Thunks 里需要用 ordinal 加载它的地址;如果都有,那只需要像其它函数一样加载它就好,它总是会加载成功。

chirsz-ever commented 1 year ago

找到了 Windows Server 2000 和 Windows XP 安装盘,经过测试,他们的 shell32.dll 里没有 SHSetFolderPathW 的名字导出,但 ordinal 232 存在。

YY_Thunks 为了兼容 WinXP 和 Win2000 需要考虑这一点。

mingkuang-Chuyu commented 1 year ago

@chirsz-ever 嗯,这是一个好消息。Win2k存在这个API。 但是这有什么问题呢?我一直都没有明白。难道YY-Thunks就一定要支持古老的SDK?

我查看了 SDK 10.0.22000.0的shell32.lib,SHSetFolderPathW的导出为序数导出。

即使用户使用 SDK 10.0.22000.0,链接后在Win2K也正常啊,最多也就是那些VC6、VS2005的的用户使用时老SDK会受到影响而已,但是他们的SDK本身也就没有包含AcquireSRWLockExclusive之类的。

这些用户,最终任然需要新的SDK才能解决。

mingkuang-Chuyu commented 1 year ago

SDK 5这种从来就不是考虑范围,因为SDK 5.X本身也没有导出YY-Thunks需要Thunk的函数啊,在SDK5上用YY-Thunks到底有啥意义???我本身就是有很多问号脸。

最后升级SDK并不困难,改改WinSDK里面注册表就可以生效,跟你用什么版本编译器并不冲突。

你前几天放的vc6 搞rust,也不是缺了很多函数无法导入吗?你一开始就升级SDK,那这些问题就没有了,我不明白为什么你不升级SDK,却要求YY-Thunks兼容SDK 5.X甚至4.X,对你来说升级SDK的必然的。

当然我承认,SDK5.X下,编译兼容Win2K的程序时缺失受到的影响,但是这做法有违YY-Thunks的初衷,我的初衷是让VS2015-甚至VS2022可以也能正常编译出兼容Win2K的程序。

mingkuang-Chuyu commented 1 year ago

好了,升级SDK吧,这样有啥好纠结的呢,老的SDK也没有导出那些新的API啊。

chirsz-ever commented 1 year ago

当然我承认,SDK5.X下,编译兼容Win2K的程序时缺失受到的影响,但是这做法有违YY-Thunks的初衷,我的初衷是让VS2015-甚至VS2022可以也能正常编译出兼容Win2K的程序。

这一点上我之前理解有一些区别,我以为 YY-Thunks 是为了让使用了更新的 Win32 API 的项目能在旧版本编译器下编译。

这几天我经过学习了解到,微软对 XP 提供了很久的支持,v141_xp 工具集相当于给 SDK 7.1a 续命到了支持 VS2017,现在的 VS2022 也支持。YY-Thunks 的编译环境应该就是基于 v141_xp?

YY-Thunks 支持的目标平台包括 Win2K,而最后支持目标为 Windows 2000 的 SDK 是 Windows Server 2003 SP1 Platform SDK^1,缺少 SHSetFolderPathW 的符号,这样使用这个 SDK 加上 YY-Thunks 链接的时候就会报错。

关于 SDK,编译器,平台等话题,我并不是坚持老工具和老技术的人,而是希望在满足条件的情况下使用最新的工具和技术:

我觉得这一切工作的终极目的是让程序兼容老系统,编译器反倒是无关紧要的,但不知道 VS2022 的编译器能否支持 Windows Server 2003 R2 Platform SDK 或者 Windows Server 2003 R2 Platform SDK。

@mingkuang-Chuyu 您的意思似乎是只用看“事实标准”,出于简单考虑对 Windows 2000 目标平台也使用 SDK 7.1a + 设置 WINVER_WIN32_WINNT 宏来生成 YY_Thunks_for_Win2K.obj。

目前有三种解决方案:

  1. 严格支持 Windows 2000。在代码上目前看来只需要加上 SHSetFolderPathW 的符号就行,其余的 Windows 2000 支持但没有导出的符号不用管,因为用 SDK 5.2 的人根本无法直接使用相应函数;但 SHSetFolderPathW 是 YY-Thunks 用的,必须加上;同时 YY_Thunks_for_Win2K.obj 改为使用 Windows Server 2003 SP1 Platform SDK 编译;
  2. 宣布不再支持 Windows 2000,这是合理的,因为相比于巨量的还在用 Windows XP 的老机器,还在使用的 Widnows 2000 可以忽略不计;
  3. 维持现状,编出来的程序在 Windows 2000 上跑问题应该不大。

严格支持 Windows 2000 需要 YY-Thunks 本身也用 Windows Server 2003 SP1 Platform SDK 上编译,这确实需要耗费一些几乎无用的工作;但即使选择维持现状,也可以加上 SHSetFolderPathW 导出符号支持 SDK 5.2,这并没有什么坏处。

我没有要求您支持这个需求的意思,如果您觉得给 YY-Thunks 加上 SHSetFolderPathW 的导出符号可以接受,可以保留这个 issue 打开,我会进行相应开发。

目前在研究不用重新生成导入库就能按 ordinal 链接符号的办法。

MouriNaruto commented 1 year ago

@chirsz-ever

这一点上我之前理解有一些区别,我以为 YY-Thunks 是为了让使用了更新的 Win32 API 的项目能在旧版本编译器下编译。

该怎么说呢,VC-LTL 和 YY-Thunks 的设计目标之一是让开发者能使用最新的编译器优雅的编译兼容老系统的 C/C++ 项目(该怎么说呢,某种情况下我们可能恨透了一些目前还在继续使用 Visual C++ 6.0 和 Visual Studio 2008 工具链开发 C/C++ 应用且完全不考虑升级编译工具链的团队),遂应该是不会考虑很老的编译器和 Windows SDK 的

也就是我们希望越来越多的项目和团队用 Visual Studio 2022 和 Windows 11 SDK 这样的现代开发环境,为了让需要构建兼容 Windows XP 甚至 Windows 2000 的项目也能这么做,遂 VC-LTL 和 YY-Thunks 作为解决相关问题的方案出现了

毛利

MouriNaruto commented 1 year ago

@chirsz-ever

VC-LTL 和 YY-Thunks 的目的是: 哪怕限定条件是支持 Windows 2000 和 Windows XP,我们依然选择 Visual Studio 2022 v143 工具集 + Windows 11 SDK Build 22621 进行构建以使用现代 MSVC 工具链和现代 SDK 提供的特性(譬如对于我们来说写应用不使用现代 C++ 特性某种情况下可能是无法接受的)

我们宁愿在 MSBuild 编译配置塞一个 PE 文件头修改 Task 让 subsystem 设定可以下探到 NT 5.0 甚至 NT 4.0,也不希望用传统 MSVC 编译工具链和传统 SDK

遂你的理解某种意义上是大错特错

毛利

MouriNaruto commented 1 year ago

@chirsz-ever

顺便强调下,YY-Thunks 目前也是提供 Windows 2000 支持的,只不过是在用户使用现代 MSVC 工具链和现代 Windows SDK 的情况下

然后得纠正下你关于“我并不是坚持老工具和老技术的人,而是希望在满足条件的情况下使用最新的工具和技术”的理解:满足条件应该是指兼容老系统的需求,最新的工具和技术理应包含编译工具链和 SDK……遂你把支持 Windows XP 和能使用的编译系统限定为 v141_xp 工具集 + SDK 7.1a 这两件事情联系起来,我个人对此的理解基本等同于你大胆且自豪地承认了哪怕是拥有了使用新工具和新技术就能满足用途(你能通过 YY-Thunks 实现使用 Visual Studio 2022 C++ 工具链构建支持 Windows 2000 的应用程序)的方案的情况下你仍然坚持使用老工具和老技术(就是钟情于 VC6 和 Platform SDK)

毛利

chirsz-ever commented 1 year ago

@MouriNaruto

……哪怕是拥有了使用新工具和新技术就能满足用途……

这就是我说的“事实标准”的意思,而我更倾向于遵守文档。

当然,本项目的原本的意图也是极好的。

MouriNaruto commented 1 year ago

@chirsz-ever

而我更倾向于遵守文档

遵守文档的话,你完全不需要用 VC-LTL 和 YY-Thunks 了(Visual Studio 2008 和 Windows 7 WDK 就 OK 了),只不过在用新 API 的时候你需要自己从新 SDK 复制定义(毕竟新的 Windows SDK 巨硬也不提供旧 Visual Studio 工具链的支持)

就是因为文档的限定让人不爽,于是会有 VC-LTL 和 YY-Thunks 这样的项目出现

要是完全按照文档行事的话,基本上被巨硬牵着走(某些员工为了自己的 KPI 或者影响力搞了一堆新瓶装旧酒的行为)

毛利

mingkuang-Chuyu commented 1 year ago

@chirsz-ever 我再声明一下,兼容老版本系统跟SDK没有半毛钱关系。兼容老版本系统跟SDK没有半毛钱关系。兼容老版本系统跟SDK没有半毛钱关系。为啥你总是想方设法使用 Windows Server 2003 R2 Platform SDK 或者 Windows Server 2003 R2 Platform SDK

为啥你还在纠结这种问题?

既然你说满足条件下使用最新的技术,麻烦你先先把你的SDK升级到最新版,比如说SDK 11?为啥你总是缠上老版本SDK 5,我真的搞不懂。你就算使用VC6,跟你这个SDK版本也没有太大关系啊……

虽然微软的2022有v141_xp工具集,但是你这样做其实就是2017 编译器 + SDK 7.1,并没有升级到最新的编译器。

YY-Thunks目前是使用2022编译器 + SDK11编译的,也不会设置任何的_WIN32_WINNT。因为YY-Thunks需要为老系统提供最新的API,自然需要最新的SDK,这样它附带的头文件才能编译YY-Thunks。

另外使用YY-Thunks后理论上跟你使用什么编译器没有任何关系(也就是不论是使用v141 还是 v142 还是 v143,不论是时候使用XP兼容模式),只要使用YY-Thunks的XP模式后均能兼容XP。

我的结论依然跟之前一样,兼容Windows 2000,但是使用者需要SDK6或者更高版本。对编译器无要求,VC6~VC2022都可以。

mingkuang-Chuyu commented 1 year ago

@chirsz-ever 如果你更倾向于遵守文档,那么我遗憾,YY-Thunks不能给你提供任何帮助……

因为在你的标准中,YY-Thunks是没有机会发挥价值的。

YY-Thunks的受众是以下这些:

  1. 新的工具追求者,但是任然想要兼容老系统的程序。
    • 比如说使用VS2022编译兼容Windows 2000、Windows XP。
    • 比如说最新的rust编译出兼容XP的程序。
  2. 简化兼容支持,比如说某个第三方库使用了老系统不存在的API,使用YY-Thunks快速的兼容掉这些情况。
    • 比如Google Chrome v110已经删除Windows 7支持,使用YY-Thunks快速的重新兼容Windows 7,而不必修改Chrome的代码。
mingkuang-Chuyu commented 1 year ago

这一点上我之前理解有一些区别,我以为 YY-Thunks 是为了让使用了更新的 Win32 API 的项目能在旧版本编译器下编译。

对了,你上面说的问题只要升级SDK即可解决,跟YY-Thunks没有任何关系。

现在你使用VC6,但是并不要求兼容XP等老系统,不必使用YY-Thunks。总的来说你现在使用了不正确的方法。建议你直接升级SDK解决吧。

如果未来需要兼容XP或者Windows 7(未来rust可能移除win7兼容),我们可以再合作。

mingkuang-Chuyu commented 1 year ago

5.* SDK链接报错问题,未来明确指出YY-Thunks至少需要SDK6.0或者更高版本。

这个确实是问题,但是影响范围有限,也不符合YY-Thunks设计初衷。联系遇到这种可以考虑将SDK升级到新版本,比如10.0,这种可以顺利完成链接工作。

从VS2008的情况看,使用SDK10并没有什么问题。