9

我想构建一个 MSI,在其安装过程中,它将自身连同其包含的文件/组件一起部署到 TargetDir。

因此 MyApp.msi 在其文件表中包含 MyApp.exe 和 MyAppBootstrapperEmpty.exe(没有资源)。

用户启动 MyAppBootstrapperPackaged.exe(包含 MyApp.msi 作为资源,从某处的 Internet 或电子邮件或其他方式获得)。MyAppBootStrapperPackaged.exe 将 MyApp.msi 提取到一个临时文件夹并通过 msiexec.exe 执行它。

msiexec.exe 进程完成后,我想要 MyApp.msi、MyBootstrapperEmpty.exe(以及 %ProgramFiles%\MyApp 文件夹中的 MyApp.exe,以便 MyApp.exe 在运行时可以确保访问 MyApp.msi(用于创建以下 -提到的包装内容)。

MyAppBootstrapper*.exe 可以尝试将 MyApp.msi 复制到 %ProgramFiles%\MyApp 文件夹,但需要提升才能这样做,并且不允许通过 Windows Installer 卸载过程(从添加/删除程序或其他方式)将其删除,这应该保留。

显然(我认为这很明显 - 我错了吗?)我不能将 MSI 作为文件包含在我的媒体/CAB(鸡和蛋场景)中,所以我相信必须在安装之前通过自定义操作来完成过程中,将原始 MSI 添加到 MSI DB 的媒体/CAB 和文件表中的适当条目。这可以做到吗?如果可以,怎么做?

考虑一个内容分发模型,其中内容文件只能与应用程序一起分发。内容由最终用户在运行时通过应用程序生成,并打包成一个可分发的 EXE,其中包括应用程序和内容。

MyApp 的安装程序必须保持为 MSI,但可以由 Bootstrapper EXE 执行。安装的 MyApp.exe 必须同时访问 MyApp.msi 和 EXE 将由应用程序在运行时从基础(空)MyAppBootstrapper.exe(也由 MSI 安装)以及由应用程序创建的内容“组装”最终用户。EXE 的资源 MSI 必须与用于安装正在执行运行时打包的 App 的资源 MSI 相同。

WIX 不能与 MyApp 一起安装。

在运行/打包时不能有网络依赖(即不能通过 Web 服务进行打包 - 必须在本地完成)。

我熟悉(并使用)自定义操作(托管和非托管,通过 DTF 和其他方式)。

4

6 回答 6

9

像这样向你的 wxs 添加一个未压缩的媒体:

<Media Id='2'/>

然后创建一个带有 File 元素的组件,如下所示:

<File Source='/path/to/myinstaller.msi' Compressed='no' DiskId='2' />

这将使安装程序在安装介质上查找名为“myinstaller.msi”的文件,该文件与正在安装的 msi 位于同一文件夹中。上面的源路径应该指向一个虚拟文件,它只是为了安抚wix。

编辑:以下示例 test.wxs 演示了它的工作原理。它会生成一个 test.msi 文件,该文件会自行安装到 c:\program files\test。请注意,您需要将虚拟 test.msi 文件与 text.wxs 放在同一文件夹中以安抚wix。

<?xml version='1.0' encoding='utf-8'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
   <Product
         Name='ProductName'
         Id='*'
         Language='1033'
         Version='0.0.1'
         Manufacturer='ManufacturerName' >
      <Package
            Keywords='Installer'
            Description='Installer which installs itself'
            Manufacturer='ManufactererName'
            InstallerVersion='100'
            Languages='1033'
            Compressed='yes'
            SummaryCodepage='1252'/>

      <Media Id='1' Cabinet='test.cab' EmbedCab='yes'/> 
      <Media Id='2' /> 

      <Directory Id='TARGETDIR' Name="SourceDir">
         <Directory Id='ProgramFilesFolder'>
            <Directory Id='TestFolder' Name='Test' >
               <Component Id="InstallMyself">
                  <File Source="./test.msi" Compressed="no" DiskId="2" />
               </Component>
            </Directory>
         </Directory>
      </Directory>

      <Feature
            Id='Complete'
            Display='expand'
            Level='1'
            Title='Copy msi file to program files folder'
            Description='Test'>

         <ComponentRef Id="InstallMyself" />
      </Feature>

   </Product>
</Wix>
于 2009-02-18T00:52:54.280 回答
2

让一个 .MSI 包从“内部”启动另一个 .MSI 包称为嵌套安装,这很糟糕(参见规则 20)。Windows Installer 有一些用于管理当前安装的全局数据,它不能很好地同时处理多个安装。出于同样的原因,如果您开始一个安装,然后在第一个仍在进行中时尝试启动另一个,您通常会看到一个弹出窗口,显示“另一个正在进行中的安装,请等到它完成”。

您可以拥有一个程序,通常称为引导程序(我认为这就是您所指的),它本身不是安装包,但包含一个安装包(例如 .MSI 或 .EXE)作为资源,可能被压缩。引导程序的操作是将资源提取/扩展为文件,通常在%TEMP%目录中,然后启动提取的 .EXE 或在提取的 .MSI 上运行 MSIEXEC。如果您需要在主包之前安装先决条件,则引导程序可以包含多个资源并一一提取+安装它们。或者您可以将多个软件包作为单独的文件发送,并让引导程序直接从分发媒体中一个一个地执行/安装它们,或者将它们复制到目标机器并从那里运行一系列安装,或者......

WiX 本身没有安装,没有。它是一个可以用来构建 .MSI 包的工具。WiX 项目的愿望清单上有一个通用的引导程序,但尚未实施。还有其他可用的引导程序,例如这个

您不需要自定义操作——事实上,由于引导程序本身并不是 Windows Installer 安装包,因此“自定义操作”对它没有任何意义。而且,如果您对 CA 足够熟悉以了解托管/非托管/DTF,那么您就可以尽可能避免自定义操作。(咧嘴笑)

于 2008-09-18T04:42:54.443 回答
2

我认为您的引导程序将 MSI 文件提取到某个预定义位置而不是临时文件夹要容易得多。例如,到 C:\Documents and Settings\All Users\Application Data\My Company\My Product Install Cache。安装完成后,引导程序会留下 MSI 文件。如果在某个阶段用户决定重新安装您的产品,Windows Installer 将能够找到源 MSI 文件。

此外,将此文件的路径添加到RemoveFile 表中,以便在卸载时将其删除。您可以为此使用WiX 中的RemoveFile 元素

于 2008-09-19T23:01:07.607 回答
1

因此,如果我理解,那么我想我会让应用程序创建一个包含内容文件的转换 (MST) 并将其应用于基本 MSI。我仍然不相信我明白了。:)

于 2008-09-17T22:31:22.447 回答
0

我会将 MSI 缓存路径配置到已知位置。

然后在运行时,如果您需要“编辑”MSI 使用 VBScript 或类似的。

但是,我仍然问为什么!?!

于 2008-11-18T23:18:37.673 回答
0

我还在研究一种部署多个 MSI 文件的方法。我有一个 bootstrapper.exe 程序,它捆绑 MSI 文件并一次运行一个。这解决了我在大多数情况下的问题。

它没有解决的情况是安装的 GPO(全局策略对象)分发。GPO 需要一个 dot-msi 文件来运行安装。

要做到这一点,这就是我所做的,它几乎解决了这个问题(但不完全)。我将 dot-msi 文件放在安装程序的文件表中,并将我的引导程序放在二进制表中,并通过在 InstallExecuteSequence 中的 InstallFinalize 之后插入的自定义操作运行它。当然,引导程序将无法运行其他 MSI,因为顶级 MSI 拥有 _MSIExecute 互斥锁。

走得更远一点很容易。我将引导程序返回控制权交给顶级安装程序并继续。然后我添加了一个 WaitForSingleObject 调用来等待顶级安装完成,然后引导程序可以继续完成安装。

我的问题是 GPO 安装发生在启动时,顶层安装在子安装程序完成之前完成,GPO 重新启动机器。

当安装可能稍后实际失败时,顶层安装也会返回成功状态。

我仍在寻找一种方法来阻止顶级安装完成,直到引导程序完成。

于 2009-05-08T15:43:54.613 回答