桌面文件扩展 Windows PE

Wes Miller

甚至在五年前我们还没有发布 Windows PE 的时候,就已经有心急的客户在要求更多的功能了。遗憾的是,Windows PE 不像 Windows XP Embedded 那样能够通过在操作系统的附加层中添加更多的功能轻松地进行扩展。当然,Windows PE 必须具有基本的

Win32® 支持(从而可以运行大多数 Windows® 应用程序)以及网络连接和大容量存储支持(以通过网络进行通信并能够安装 Windows)。但是甚至从一开始我们就想要限制使用外壳;由于使用了 cmd.exe 而不是传统的 Windows Explorer 外壳,我们限制了 Windows PE 环境的功能范围,但更重要的是,我们可以在默认环境下针对所有自动化任务轻松地进行脚本化。

您仍然可以扩展 Windows PE — 只是您必须记住的是它受到了限制。您可以预计如果您的应用程序需要图 1 中列出的任何技术(此列表并不全面),它就可能无法运行或可能出现错误的行为。

Figure 1 缺少的 Windows API

.NET Framework(任何版本)
Active Directory® Services Interfaces (ADSI)
DirectX®
Microsoft 数据访问组件 (MDAC)
Jet (Access)
Visual Basic®(包括 .NET 之前的版本)
需要不使用 Windows 进行本机安装的框架的任何可执行文件类型。
Windows 资源管理器或 Internet Explorer
Windows Media® Player
SAPI、MAPI、TAPI(分别为 Windows Speech、Mail、Telephony 的 API)

如果您不知道您的应用程序依赖什么,就需要查明。不过,该如何查明呢?当我们尝试在发布 Windows PE 之前获取在 Windows PE 下运行的 ADO、HTML Applications (HTA) 和 Windows Script Host (WSH) 组件时,我们面临着相同的问题。不过,应当注意,虽然本文将介绍追踪这些依赖项的方法,但是最终用户许可协议 (EULA) 并不涵盖将 MKIMG 命令所包含的 Windows 二进制文件之外的任何二进制文件添加到 Windows PE 映像。为了在您的环境中进行实质性的更改,您将需要从 Microsoft 获得许可附录。

了解依赖项

如果您在记事本中打开应用程序的 .inf 文件并对其进行仔细检查,就会了解到大量的信息。实际上,通常这是搞清楚某应用程序并查看其所具有的依赖项的最容易的方法。要了解 Windows PE,重要的在于了解通常它的简化程度极高,因此您必须调试多个级别的依赖项 — 应用程序自身的直接依赖项和那些直接依赖项中的每个依赖项可能引入的依赖项 — 以便使应用程序能够可靠地运行。其实,如果您不小心,就可能会发生相当大的依赖项层叠。通过一些意外(或有意)的组件添加,您的映像会在大小和复杂性方面显著增长。

如果您有用于介绍该应用程序的 .inf 文件,就可以通过查找 .inf 添加到系统的注册表项和文件来获得有关依赖项的线索。查找 CopyFiles 部分和 AddReg 部分。这些条目将指向应用程序、DLL 和应用程序所依赖的其他文件。在 Windows PE 的三个加载项(ADO、HTA 和 WSH)中,创建方法最简单的是 WSH。因为 WSH 的可再发行版本仍可用于 Windows 的早期版本,并且因为在现在的 Windows 中内置了一个执行针对 WSH 的文件关联的 .inf 文件(位于 %windir%\inf\wsh.inf),所以将其安装到 Windows PE 中就相对容易。

Orca 和快照

如果所讨论的应用程序作为 Microsoft® 安装程序 (MSI) 文件分发,您可以做两件事来查找依赖项。如果您是一位 MSI 权威,您就可以使用 Orca(一种用于编辑 Windows 安装程序文件的工具,该工具作为 Windows Server® 2003 R2 Platform SDK 的一部分分发:go.microsoft.com/fwlink/?LinkId=77941)进行查看。您还可以为您想要的组件安装 MSI,从而对已发生变化的文件和注册表项执行前后对比分析。您可以转储注册表,安装应用程序,再次导出注册表,然后针对注册表运行 WinDiff [请参阅“Using WinDiff”(使用 WinDiff)边栏]。接着可以将运行结果用作更改的模板(需要对注册表进行这些更改)。问题在于可以虚构更改的数量。不过,如果您手边没有 .inf(或应用程序的作者),那么它可能是最佳选项。

您可能很熟悉应用程序快照的过程。其实,它就是为了运行应用程序而执行的同一前后对比分析。Microsoft 以前分发过(随 Windows 2000)执行此操作的工具,但该工具不能与任何更新版本的 Windows 协同工作。许多商业应用程序(安装重新打包程序)可以执行此操作,但一些免费的实用工具也可以执行此操作。针对一个解决方案,安装 Platform SDK(请参阅前一段中的链接),其中包括 WinDiff。请注意,要执行 WinDiff 比较,理想情况下,您要在 Windows Server 2003、Service Pack 1 (SP1) 上安装该应用程序,因为该版本正是您应该使用的 Windows PE 版本 — Windows PE 1.6 作为 Standard Edition 或 Enterprise Edition (with SP1) 的内部版本。在 Windows Server 2003 上执行此任务,您将使此环境与在 Windows PE 上运行时的环境最为接近(很明显,您无法在 Windows PE 上执行 MSI)。遵循“Using WinDiff”(使用 WinDiff)边栏中的步骤。

此边栏将向您显示大量已更改的信息。遗憾的是,并没有一种简单的方法来从注册表或文件捕获中导出已更改的信息,从而创建某些类型的指令清单以安装应用程序。您需要手动合并这些更改。这正是我们使用第一版 Windows PE 时遇到某些最困难的问题的地方。使 HTA 组件处理所有问题很复杂,因为在 Microsoft 内部并没有对这些组件进行定义(在 Internet Explorer® 之外)。通过使用差分化,我们能够手动接合足够的 HTA 支持,以便其能够起作用。虽然可以将这些注册表项手动添加到 Windows PE 注册表,但您可能想要在 Windows PE 启动后再添加这些注册表项。您可以通过 Windows PE 构建工具中包括的 buildoptionalcomponents.vbs 脚本来查看用于将 HTA、WSH 和/或 ADO 支持安装到 Windows PE 的 OC.bat 文件和 OC2.bat 文件。

有用的工具

甚至在隔离了直接依赖项后,您通常也无法找到应用程序所依赖的每个二进制文件。例如,您不会知道是否需要另一个 DLL 或 OCX 才能执行某些任务。那么,如何进行分辨?Sysinternals fame 的 Mark Russinovich(现在是 Microsoft 的一位技术人员)编写的一个称为 listdlls 的小巧实用工具所做的正是这件事情。可从 microsoft.com/technet/sysinternals/utilities/ListDlls.mspx 下载 Listdlls。要使用此实用工具,请运行命令 listdlls.exe > dlls.txt,然后检查输出。图 2 显示了 listdlls 在其自身上运行的输出信息。可以将此列表同 Windows PE 中包含的 DLL 文件和 OCX 文件进行比较,以确定应用程序的所有依赖项是否具备(就 listdlls 而言,所有依赖项都已显示)。对于 Windows PE 中的 HTA 支持,listdlls 对于识别某些依赖项很关键(否则无法识别)。

图 2 Lisdlls 在其自身上运行的输出

图 2** Lisdlls 在其自身上运行的输出 **(单击该图像获得较大视图)

但是仅因为列出了 DLL,并不一定意味着应用程序需要该 DLL 才会起作用。例如,如果您加载了记事本,您就将看到它加载 uxtheme.dll。在 Windows PE 下,此 DLL 不可用,并且实际上,由于没有使用 Windows 主题,也就将永远不会加载 uxtheme.dll。确实必须了解 listdlls 向您显示 DLL 中哪些是您实际需要的以及哪些是 Windows 按需加载的,遗憾的是,这是一种不公开的技术,您将需要大量的试验和错误或者您变得非常熟悉 Windows 的低层方面(为此,我建议阅读 Mark Russinovich 和 David Solomon 合著的书《Microsoft Windows Internals, Fourth Editio》[Microsoft Windows 内核(第四版)] (Microsoft Press®, 2004)。

实际上,Mark 还在取代 Windows 任务管理器免费的 Process Explorer 中包含了相同的功能。区别在于,listdlls 创建的输出(在我看来)更易于编写脚本和用于查找和收集缺少的依赖项。

请注意,甚至在您将一个 DLL 添加到映像中之后,您可能仍然要做一些工作。就是说,有两种类型的 DLL:需要注册的 DLL 和不需要注册的 DLL。遗憾的是,除了试图注册每一个 DLL 以外,并没有能够轻松的将它们区别开来的方法。为了注册 DLL(或 OCX),请运行 regsvr32 dllname.dll。如果它能正确运行,您将收到一个对话框,告诉您注册了该 DLL。如果它不能正确运行,您可能收不到消息或更有可能的是,您将看到一个对话框,通知您该 DLL 注册失败或无法注册。在开发用于 Windows PE 的 HTA 和 ADO 可选组件时,我们发现 DLL 在执行其注册时需要可写存储器,以临时写入用于安装的 .inf 文件或记录某些其他的依赖项(比如,他们所必需的特定目录)。在 Windows PE 中,这在以前就意味着失败。谢天谢地,使用 Windows PE 2.0,由于默认情况下可以使用暂存空间,与这些相类似的任务将恰好起作用。

Mark 创建并于最近发布的第三个工具称为 Process Monitor。可以将 Process Monitor 看作 Regmon 和 Filemon 的一个超集,它提供的细节仍明显多于 Regmon 和 Filemon 提供的细节,同时添加了一个全新的进程间通信层。这个功能非常强大的工具会帮助您排除 Windows 中应用程序的故障,并帮助您回答有关 DLL 相互依赖关系到底发生了什么的问题。可以下载 Process Monitor。

删除 Windows PE 文件

除了能够向 Windows PE 添加内容,另一个常见的请求是就如何使 Windows PE 变小进行指导。您可以采取几个步骤将 Windows PE 的大小减小一点。已获得许可的 Windows PE 应该包括构建工具的集合和一些文档。其中的一个文档是名为 winpe.chm 的一个帮助文件。如果您打开此文件并浏览“Windows Preinstallation Environment User’s Guide”(Windows 预安装环境用户指南)部分,就会看到一个标题为“Reducing the Size of Windows PE”(减小 Windows PE 的大小)的主题。此部分列出可以安全删除的文件的集合(假定您不需要这些文件)。您将发现与可删除文件相关的三个部分:

  • 始终可以安全删除字体文件。
  • 虽然可以删除与网络连接相关的 .inf 文件和实用工具,但仅限在您根本不打算在网络上使用内部版本时方可如此。
  • 不应该删除命令行实用工具。建议不要删除这些命令行实用工具中的任何一个,除非您明确了解该实用工具的用处以及如果将其删除可能会发生什么。

决定了可以安全地排除哪些文件后,您就可以直接编写批处理文件或其他脚本,并在 mkimg.cmd 完成内部版本后将它们从 Windows PE 内部版本中删除。

修改 Windows PE 注册表

您可以设法使我们在构建时有意不安装那些可选组件。尽管这意味着运行时间会稍长,但也意味着我们不必设计一个全新的方法来将这些组件接合回 Windows PE — 我们没有时间这样做,并且这也很可能意味着将完全忽略这些组件。但是,如果您想要更改注册表(如为应用程序添加注册表更改的变化量)或只是想要编辑某个可能会保持应用程序运行的注册表项,该怎么办?使用图 3 中显示的 regedit 就可以很容易地完成此任务。请遵循以下的步骤:

  1. 运行 regedit 并选择 HKEY_LOCAL_MACHINE 配置单元。
  2. 选择“File”(文件)|“Load Hive”(加载配置单元),然后浏览到 Windows PE 内部版本的位置。在 I386\System32\(或者如果这是放置在硬盘驱动器上的映像,则在 MiniNT\System32 下选择 setupreg.hiv。
  3. 输入配置单元的临时名称(如 WinPE),然后在 HKLM 下浏览到该节点。
  4. 相应地修改此注册表项。有趣的是,请注意,此节点在效用上与将在正常 Windows 安装中出现的节点 HKLM\System 相同。
  5. 做出修改后,请在 HKLM 下选择您在步骤 3 中创建的注册表项(正确地执行这一操作很重要,否则将损害您的系统)。
  6. 选择“File”(文件)|“Unload Hive...”(卸载配置单元...),并确认“Yes”(是)|“No”(否)对话框,并且由于锁定此注册表将阻止 Windows PE 的成功构建,因此要确保每次都卸除该注册表。

图 3 打开 Windows PE 注册表

图 3** 打开 Windows PE 注册表 **(单击该图像获得较大视图)

遵循以下的步骤就可以修改 HKLM\System。在 I386\System32 下还有另两个可用来修改注册表其他区域的注册表项:DEFAULT 和 SOFTWARE,前者是用户的默认配置单元(甚至在您使用 Windows PE 时会以 SYSTEM 身份运行),而后者与 HKLM\Software 相同。通常在修改注册表时要多加小心并仅在需要时进行修改。

现在可以利用一些方法帮助您开始将喜爱的故障排除或恢复工具迁移到 Windows PE 上。下个月,我将讨论 PSTools 套件 — 这还是由 Mark Russinovich 编写的非常有用的系统管理工具的集合。

使用 WinDiff

WinDiff 可以帮助您查找应用程序的依赖项。只需遵循以下步骤就可以成功地进行安装和执行:

  1. 使系统做好安装准备 — 您要将安装时间降至最低并最小化初始快照和最终快照之间的任何文件或注册表更改。
  2. 打开命令提示符并运行 reg export HKLM C:\HKLM1.reg 以完全导出 HKEY_Local_Machine 注册表配置单元。
  3. 运行 dir C:\*.* /S > C:\C1.txt 以完全转储 C: 驱动器(假定 C: 为您的系统驱动器)上的所有文件。
  4. 安装应用程序并配置任何安装后设置。
  5. 运行 reg export HKLM C:\HKLM2.reg。
  6. 运行 dir C:\*.* /S > C:\C2.txt。
  7. 打开 WinDiff,选择“File”(文件)|“Compare Files...”(比较文件...),然后在第一个“File Open”(文件打开)对话框中选择 HKLM1.reg,并在第二个“File Open”(文件打开)对话框中选择 HKLM2.reg。
  8. 您会看到显示为红色的消息,这表明该消息是更新的消息。别急;由于 HKLM 导出文件可能会很大,这可能会花上一点时间。
  9. 双击红色的文本以扩展这些差异。
  10. 您可能想要通过选中“Options”(选项)|“Show Right-Only Lines”(仅显示右边文件中的行)来配置在比较中显示的内容。此操作将只显示在第二个比较文件中新添加的行(因此将仅显示新文件和新注册表项)。

请注意,您可能需要使用 Find 函数来找到与应用程序相关的注册表项。在图 A 和图 B 中,您可以看到我所创建的虚构应用程序的文件和注册表更改。令人高兴的是,在 WinDiff 中可以使用复制和粘贴操作。要使用这些功能,只需单击 !> 行并选择所需的行即可。

图 A WinDiff 条目

图 A** WinDiff 条目 **(单击该图像获得较大视图)

图 B WinDiff 中的特定注册表项

图 B** WinDiff 中的特定注册表项 **(单击该图像获得较大视图)

Wes Miller 是德克萨斯州奥斯汀市 Pluck 公司 (www.pluck.com) 的一位开发经理。在这之前,Wes 在位于奥斯汀市的 Winternals Software 公司任职,并曾在微软担任 Windows 程序经理和产品经理。Wes 的联系方式如下:technet@getwired.com

© 2008 Microsoft Corporation 与 CMP Media, LLC.保留所有权利;不得对全文或部分内容进行复制.