https://reactos.org/blogs/gui-setup-part1-setupapi
作者: hbelusca
2023年12月4日
向所有ReactOS关注者问好! 你们中的许多人现在肯定都知道,我已被ReactOS Deutschland eV正式雇用来开发第一阶段ReactOS安装程序的图形版本(“第一阶段 GUI 设置”)。 在第一个月(2023 年 9 月),我的目标是将 setupapi.dll 模块的代码与 Wine 的部分同步。 事实上,这个模块早在 2005 年就被分叉了,后来对其某些功能的代码进行了部分同步。 对于那些不知道 setupapi 是什么的人来说,它是一个模块: - 公开用于读取和处理 INF 文件的通用安装函数,将文件从安装源介质移动/复制到目标,还支持从压缩的 .CAB 中提取内阁文件; - 并公开设备安装功能。 由于其本质,它是“由于架构差异,我们不完全共享的 Wine 组件之一”(CORE-7662[https://jira.reactos.org/browse/CORE-7662])(主要是由于设备安装功能),因此,随着时间的推移,Wine与操作系统和体系结构特定方面无关的代码改进可能会被忽视,并且我们的共享代码会无缘无故地慢慢分开。 作为第一阶段 GUI 设置的一部分,我需要使用文件队列和文件柜功能。 这些是最近从 Wine 获得的改进/错误修复,并且可以在没有太多麻烦的情况下进行同步。 (注意:应该注意的是,我们当前的文本模式第一阶段安装程序 USETUP 重新实现了这些功能的一个非常小的子集,用于从 Reactos.cab 源文件中提取文件并将它们复制到 ReactOS 安装目录. 在 GUI 设置中,我的目标是直接使用 setupapi.dll 公开的那些。) 我需要解决的不同子任务列在这份 JIRA 报告CORE-19209(https://jira.reactos.org/browse/CORE-19209)中。
这项工作首先尝试使用我们内部的 winesync.py python 脚本来帮助同步 Wine 代码。 它需要编写一个配置文件(例如 setupapi.cfg),列出可以为给定模块同步的文件/目录,并从 Wine 存储库中的名称映射这些文件/目录,例如:dlls/setupapi(或一个或多个其文件),到 ReactOS 存储库中相应的路径名。 对于任何 ReactOS 开发任务,总是会遇到问题或错误:我尝试使用 winesync.py 脚本也不例外。 该脚本假设人们始终将代码与Wine和Wine-staging存储库同步; 该脚本不支持仅与Wine存储库进行同步。 这个问题必须得到解决。 接下来,我在运行Windows 7的旧笔记本电脑上使用Git-for-Windows和python开发ReactOS。 winesync.py脚本期望其用户在类Unix环境下运行它,并且在许多地方假设路径操作操作始终在这种上下文中完成。 当在Windows上的Python下运行时,这些操作生成Windows格式的路径,但并不总是能够理解(主要是 pygit 模块)。 (请注意,由于我的设置,我无法按照某些人的建议在那里使用 WSL!) 其他类似的问题也需要解决,我就不一一列举了。 您可以在以下 PR #5898 (https://github.com/reactos/reactos/pull/5898)中查阅所需修复和改进的列表(注意:在撰写本文时它尚未合并到 master分支中)。
在 winesync 脚本中进行这些修复后,我开始了 setupapi 模块的部分同步。 正如简介中提到的,它的代码很早就从相当旧的(2005)版本的 Wine 代码中分叉出来,并添加了特定于 ReactOS 的更改。 这在当时是合理的,因为 ReactOS 项目必须实现设备/驱动程序安装管理,而 Wine 当时并不真正关心这一点。 因此,代码很快就出现了分歧。 我需要保持最新的功能存在于多个文件中,为了仔细(重新)同步代码,我发现逐个文件执行同步很有用,而不是全部同步一次用于所有感兴趣的文件,正如通常所做的那样。 这使我能够分析 Wine 方面添加了哪些更改、是否存在特定于 ReactOS 的更改,并注意潜在引入的错误。 我们的 setupapi 版本还有 2 或 3 个文件,这些文件对于我的 GUI 设置正常工作来说并不是必需的,我还没有同步这些文件,其中包含与 Wine 完全不同的(特定于 ReactOS 的)API 实现。 此同步可以在 setupapi_partial_winesync (https://github.com/reactos/reactos/commits/hbelusca/setupapi_partial_winesync)分支中找到。 此外,setupapi 的相应测试套件已在 setupapi_winetest_winesync 分支中单独同步。 一旦所有内容都经过彻底测试和验证,两个分支将合并到主 ReactOS 主分支中。
我的第一次同步测试没有按预期进行: 在第二阶段 ReactOS 安装步骤中,为检测到的设备安装 PnP 驱动程序时,它最终陷入挂起状态。 必要的驱动程序的安装确实是由 setupapi 完成的,它解释了它们相应的 .inf 文件。 调试这个问题,发现这是由于Wine新实现的 “源媒体路径解析” 功能造成的。 该代码基本上无限“循环”,未能成功地尝试找到我们在安装阶段“安装”的驱动程序的安装介质。 原则上,应该出现一个对话框,提示用户在哪里可以找到安装源(就像在 Windows 上一样),只是 Wine 尚未为此目的实现任何功能。 结果,代码只是无限循环。 通过交换 ReactOS 的快速测试 setupapi.dll使用 Windows 2003 的情况,显示这基本上就是正在发生的情况,并显示提示对话框(“无限循环”将由按“确定”、失败、再次按“确定”等引起)

针对此问题的临时修复 已添加(https://github.com/reactos/reactos/commit/7ceac0dda8da4b60847bb1183ab4f852e84a4864) setupapi 同步中 。 它导致 find-installation-media 循环仅运行一次,而不是无限多次。 这给出的结果行为与同步之前代码中存在的行为相同。 之所以在 ReactOS 中发生这种情况,是因为我们使用 .inf指定安装驱动程序的目标目录的文件, 但此类驱动程序的安装源是在 layout.inf文件......我们不支持(我们的是空的)! 更复杂的是,Wine 的 setupapi 不支持 layout.inf也支持。
setupapi 部分同步理论上已经完成,但它还没有变成 PR,因为我想在之前进一步测试它:更新的 winetest,以及第一阶段 GUI 设置的文件复制安装步骤(这是一个工作正在进行中)。 这是为了看看当我不得不在那里调整一些额外的 ROS 特定代码时,是否有由 Wine 或我自己引入的细微错误。 此外,还有一些事情需要进一步解决。 多年来,Wine 改变了他们在全局范围内使用的内存分配函数 setupapi.dll,这出现在同步中间。 因此,我还需要调整那些未同步的文件,使它们与此更改兼容。 否则,就会存在堆损坏等风险。 例如,一个文件中的函数使用 CRT malloc() 分配某个缓冲区,然后将该缓冲区传递给这些非同步文件之一中的某个其他函数,该函数将使用 Win32 HeapFree() 释放该缓冲区。 在 Wine 暂存补丁文件中已经遇到过这样的错误,并且已在本地(https://github.com/reactos/reactos/commit/82ee64728360e9cc91025f78b1483d485b349972)修复(与另一个不相关的错误一起)。
在下一篇 博文(https://reactos.org/blogs/gui-setup-part2-partitioning)中,我将讨论使分区 UI 代码在第一阶段 GUI 设置中工作的工作,以及之前进行的分区的必要准备工作。 敬请关注!