Windows 11 的 System32 存放 64 位文件,而 SysWOW64 存放 32 位文件 显而易见,微软不会推出 32 位版 Windows 11,但操作系统仍得运行几十年来积累的 32 位应用,而且这类应用数量不少。微软的解决方案是设置两个系统文件夹:System32 存放原生 64 位文件,SysWOW64 存放 32 位副本;此外还有微软称为 WOW64 文件系统重定向器的机制,会在 32 位应用请求访问 System32 时,悄悄将其引导至 SysWOW64。
在我这台运行 Windows 11 26H2 的电脑上,两个文件夹里都有 kernel32.dll。毫不意外,这两个文件的大小不同,因为一个面向 64 位应用,另一个面向 32 位应用。
Windows 11 26H2 的 System32 和 SysWOW64 中都有 kernel32.dll,但 64 位和 32 位副本的大小不同。图片来源:Windows Latest试想一下,如果微软也能像苹果那样宣布停止支持 32 位软件,Windows 或许就不用背负这些历史包袱了!
在 16 位 Windows 时代,系统文件放在 C:\Windows\System 中。32 位 Windows 问世后,微软新增了 C:\Windows\System32 来存放 32 位文件,“32”便由此而来。
64 位 Windows 问世时,许多程序已经将 System32 路径写死,而不是通过 GetSystemDirectory 函数获取路径。微软资深员工雷蒙德·陈在他的 Windows Confidential 专栏中解释说,这些程序重新编译为 64 位版本后,仍会查找 System32,只不过现在它们需要的是 64 位文件。批处理文件也面临类似问题:如果该文件夹存放的是 32 位工具,那么运行 System32\reg.exe 的脚本就会修改注册表的 32 位副本。
因此,Windows 团队决定让 System32 存放与操作系统位数相匹配的文件。微软的文件系统重定向器文档写道:“在 64 位 Windows 上,%windir%\System32 目录专供 64 位应用使用。”微软制作 64 位版本时,大多数 DLL 也保留了原来的文件名。因此,遵循 MS-DOS 命名规则的 kernel32.dll,在两个文件夹中都叫 kernel32.dll,32 位副本则需要单独存放在另一个文件夹里。
陈写道:“32 只是名称的一部分,并没有实际含义。”他将其比作 KFC 和 HSBC 这类如今以首字母简称的品牌。他还补充说,理想情况下,这个文件夹应该叫作SysExec,因为里面存放的文件与正在运行的程序相匹配。
WOW64 是 Windows 32-bit on Windows 64-bit 的缩写(听起来确实有点好笑),是微软为 32 位应用提供的兼容层。因此,SysWOW64 中的“64”指的是操作系统,而文件夹里的文件则是 32 位的。讽刺的是,名称里带有“64”的系统文件夹,反而是 64 位应用不会使用的那个。
根据微软关于运行 32 位应用的指南,32 位进程无法加载 64 位 DLL 来执行,反之亦然。如果没有重定向,32 位程序从 System32 加载 kernel32.dll 时,就会拿到无法使用的文件。
在 x64 版 Windows 上,只要 32 位应用请求这些路径,WOW64 就会在后台替换路径。
32 位应用请求的路径64 位 Windows 将其指向的路径C:\Windows\System32C:\Windows\SysWOW64C:\Windows\lastgood\system32C:\Windows\lastgood\SysWOW64C:\Windows\regedit.exeC:\Windows\SysWOW64\regedit.exe
应用完全不会察觉到这一切。我从 C:\Windows\SysWOW64\cmd.exe 打开 32 位命令提示符,运行 echo %PROCESSOR_ARCHITECTURE% 得到的结果是 x86,而普通命令提示符显示的是 AMD64。随后,我在两个窗口中运行 dir C:\Windows\System32\kernel32.dll,发现同一个路径对应的文件大小竟然不同。
32 位命令提示符显示 x86;请求访问 System32 时,它看到的是 SysWOW64 中的 kernel32.dll。图片来源:Windows Latest
任务管理器显示哪个命令提示符以 32 位进程运行。图片来源:Windows Latest就连当时在微软 Visual Studio 团队工作的马特·皮特雷克也被这一机制弄糊涂了。他在 2006 年的一篇 MSDN Magazine 文章中写道,自己曾在 32 位命令提示符下分别列出两个文件夹中的 kernel32.dll,得到的结果却一模一样,让他困惑了好一阵子。
WOW64 还会通过注册表重定向器,为 32 位应用提供独立的注册表视图,路径位于 HKEY_LOCAL_MACHINE\Software\Wow6432Node;同时,它会将应用的 %ProgramFiles% 变量指向 Program Files (x86)。
在 Windows 11 上,32 位应用通过 WOW6432Node 使用独立的注册表视图。图片来源:Windows Latest有一点比较奇怪:如果打开重定向文件时弹出 UAC 提示,微软表示此时不会进行重定向,而是会启动 64 位版本。因此,开发者应该使用 SysWOW64 路径,或者以管理员身份运行 32 位应用。
Sysnative 是一个虚拟文件夹,所以你在 C:\Windows 中找不到它,而且 64 位应用也无法使用它。我在 64 位应用文件资源管理器的地址栏中输入 C:\Windows\Sysnative 时,Windows 找不到该路径;但在 32 位命令提示符中运行 dir C:\Windows\Sysnative\cmd.exe 却完全没问题。
Sysnative 仅供 32 位应用使用,因此 64 位文件资源管理器无法找到它。图片来源:Windows Latest开发者可以根据需要,使用 Wow64DisableWow64FsRedirection 函数关闭重定向,但这会影响该线程中的所有文件操作。微软文档警告称:“禁用文件系统重定向会导致 DLL 加载失败。”
有趣的是,TechNet 编辑为了控制篇幅,删掉了陈在专栏中对 Sysnative 的解释,于是他在 2010 年把内容发到了自己的博客上,并将其称为“针对局部问题的局部解决方案”。早在 2008 年,他就建议一位开发者别再和模拟器较劲,而是让 32 位安装程序启动 64 位安装程序。我也赞同,因为大多数麻烦都始于 32 位应用试图扮演 64 位应用。
微软列出了六个 32 位应用可以直接访问、不受重定向影响的 System32 子文件夹。
这个列表并非一直如此:在 Windows Vista、Windows XP、Windows Server 2003 和 Windows Server 2008 中,driverstore 曾经会被重定向。微软没有解释这些例外的原因,我猜这些文件夹存放的是共享数据,比如 drivers\etc 中的 hosts 文件;两类应用都需要访问同一份数据。
在搭载 Snapdragon X 等芯片的 Arm 电脑上,32 位 x86 应用同样会被引导至 SysWOW64,而 32 位 Arm 应用则会被重定向到第三个文件夹 SysArm32。根据微软对实现机制的说明,Arm64 上的 WOW64 会通过名为 xtajit.dll 的模拟器转换 x86 代码;而 x64 处理器可以原生运行 32 位代码,由 Wow64Cpu.dll 管理切换。
微软的 Arm 开发者文档现在指出,Arm 电脑不再支持 32 位 Arm 应用,sysarm32 文件夹中的系统二进制文件也会被移除。普通 x86 应用——无论是 32 位还是 64 位——仍能通过 Prism 模拟运行。Prism 去年新增了 AVX 和 AVX2 支持。
二十年前,微软本可以将 System32 改名,但那样会导致一大批应用出问题。于是,他们围绕这个旧名称构建了重定向器、别名和例外列表,就像为了兼容旧程序而保留 Windows 95 的堆管理器一样。不过,并不是所有东西都挺过了向 64 位的迁移,3D Pinball 就是一个例子。说实话,我很希望能有一个 SysExec 文件夹,但再令人困惑的名称,也好过让安装程序无法运行。你会给它改名吗?