我想构建一个MSI,在其安装过程中,它将自己与其包含的文件/组件一起部署到TargetDir。
因此MyApp.msi在其文件表中包含MyApp.exe和MyAppBootstrapperEmpty.exe(没有资源)。
用户启动MyAppBootstrapperPackaged.exe(包含MyApp.msi作为资源,从某处获取,或通过电子邮件或其他方式获取)。 MyAppBootStrapperPackaged.exe将MyApp.msi提取到临时文件夹并通过msiexec.exe执行。
msiexec.exe进程完成后,我想要MyApp.msi,MyBootstrapperEmpty.exe(和%ProgramFiles%\ MyApp文件夹中的AND MyApp.exe,以便MyApp.exe在运行时可以放心访问MyApp.msi(用于创建)下面提到的包装内容。)
MyAppBootstrapper * .exe可以尝试将MyApp.msi复制到%ProgramFiles%\ MyApp文件夹,但需要提升才能执行此操作,并且不允许通过Windows Installer卸载过程(从“添加/删除程序”或其他方式删除) ),应该保留。
显然(我认为很明显 - 我错了吗?)我不能将MSI作为文件包含在我的Media / CAB(鸡蛋和鸡蛋场景)中,所以我相信它必须通过自定义动作来完成在安装过程之前,将原始MSI添加到MSI DB的Media / CAB以及动态文件表中的相应条目。可以这样做,如果是这样的话?
考虑一种内容分发模型,其中内容文件只能与App一起分发。内容由最终用户在运行时通过App生成,并打包成可分发的EXE,其中包括App和内容。
MyApp的安装程序必须保持MSI,但可以由Bootstrapper EXE执行。安装的MyApp.exe必须能够访问MyApp.msi和EXE将在运行时由应用程序从基础(空)MyAppBootstrapper.exe(也由MSI安装)和由内容创建的内容“组装”。最终用户。 EXE的资源MSI必须与用于安装运行时打包的App的资源相同。
WIX不与MyApp一起安装。
在运行/打包时不存在网络依赖性(即无法通过Web服务进行打包 - 必须在本地完成)。
我熟悉(并使用)自定义操作(托管和非托管,通过DTF等)。
答案 0 :(得分:9)
将未压缩的媒体添加到您的wx中,如下所示:
<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>
答案 1 :(得分:3)
让一个.MSI包从“内部”本身启动另一个.MSI包称为嵌套安装,它是bad juju(参见规则20)。 Windows Installer具有一些用于管理当前安装的全局数据,并且它无法同时处理多个安装。出于同样的原因,如果你开始一次安装,然后在第一次安装仍在进行时尝试启动另一次安装,你通常会看到弹出“另一个正在进行的安装,请等到它完成”的效果。
您可以拥有一个程序,通常称为引导程序(我认为这就是您所指的),它本身不是一个安装包,但包含一个安装包(例如。 MSI或.EXE)作为资源,可能是压缩的。引导程序的操作是将资源提取/扩展到文件,通常在%TEMP%
目录中,然后启动提取的.EXE或在提取的.MSI上运行MSIEXEC。如果您需要在主程序包之前安装先决条件,则引导程序可以包含多个资源并逐个提取和安装它们。或者您可以将多个包作为单独的文件发送,让引导程序一个接一个地直接从分发介质执行/安装它们,或者将它们复制到目标计算机并从那里运行一系列安装,或者......
WiX本身没有安装,没有。它是一个可以构建.MSI包的工具。 WiX项目在其愿望清单上有一个通用的bootstrapper程序,但尚未实现。还有其他可用的引导程序,例如this one
您不需要自定义操作 - 实际上,由于引导程序本身不是Windows Installer安装包,因此“自定义操作”对此没有任何意义。而且,如果您足够熟悉CA以了解托管/非托管/ DTF,那么您就足够了解,以便尽可能避免自定义操作。 (GRIN)
答案 2 :(得分:2)
我认为你的引导程序将MSI文件提取到某个预定义位置而不是临时文件夹要容易得多。例如,到C:\ Documents and Settings \ All Users \ Application Data \ My Company \ My Product Install Cache。安装完成后,bootstrapper会将MSI文件保留在那里。如果在某个阶段用户决定重新安装您的产品,Windows Installer将能够找到源MSI文件。
此外,将此文件的路径添加到RemoveFile table,以便在卸载时将其删除。您可以在WiX中使用RemoveFile element。
答案 3 :(得分:1)
所以,如果我理解,那么我想我会让应用创建一个包含内容文件的转换(MST)并将其应用到基础MSI。我仍然不相信我理解。 :)
答案 4 :(得分:0)
我将MSI缓存路径配置为已知位置。
然后在运行时如果你需要“编辑”MSI使用VBScript或类似的东西。
但是,我还是问为什么!?!
答案 5 :(得分:0)
我也在研究部署多个MSI文件的方法。我有一个bootstrapper.exe程序捆绑MSI文件并一次运行一个。在大多数情况下,这解决了我的问题。
它没有解决的情况是安装的GPO(全局策略对象)分发。 GPO需要dot-msi文件才能运行安装。
要做到这一点,我所做的几乎解决了问题(但并不完全)。我将dot-msi文件放在安装程序的文件表中,并将我的引导程序放在二进制表中,并在InstallExecuteSequence中的InstallFinalize之后插入的自定义操作中运行它。当然,引导程序将无法运行其他MSI,因为顶级MSI拥有_MSIExecute互斥锁。
很容易进一步。我使引导程序返回控制到顶级安装程序并继续。然后我添加了一个WaitForSingleObject调用来等待顶级安装完成,然后引导程序可以继续完成安装。
我的问题是GPO安装在启动时发生,顶级安装在子安装程序完成之前完成并且GPO重新启动计算机。
当以后安装可能实际失败时,toplevel install也会返回成功状态。
我仍然在寻找一种方法来阻止顶级安装完成,直到引导程序完成。