.msi文件可以自行安装(大概通过"自定义操作")吗?

时间:2020-03-05 19:00:10  来源:igfitidea点击:

我要构造一个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作为文件包含在我的Media / CAB中(鸡肉和鸡蛋方案),因此我认为必须在安装过程之前通过自定义操作完成,将原始MSI即时添加到MSI DB的Media / CAB中,并在File表中添加相应的条目。可以做到吗?如果可以,怎么办?

考虑一个内容分发模型,其中内容文件只能与App一起分发。内容由最终用户在运行时通过App生成,并打包为可分发的EXE,其中既包含App又包含内容。

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

WIX不会与MyApp一起安装。

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

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

解决方案

回答

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

回答

让一个.MSI程序包从自身内部启动另一个.MSI程序包称为嵌套安装,这很不好(请参阅规则20)。 Windows Installer具有一些用于管理当前安装的全局数据,并且不能同时处理多个安装。出于同样的原因,如果先启动一个安装,然后在仍在进行第一次安装时尝试启动另一个安装,通常会弹出一个弹出窗口,提示"正在进行另一个安装,请等待完成"。

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

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

我们不需要自定义操作-实际上,由于引导程序本身并不是Windows Installer安装包,因此"自定义操作"对其没有任何意义。而且,如果我们对CA足够熟悉,可以了解托管/非托管/ DTF,那么我们将足够了解避免自定义操作的机会。 (笑)

回答

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

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

回答

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

然后在运行时,如果需要"编辑" MSI,请使用VBScript或者类似版本。

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

回答

像这样向wxs添加未压缩的介质:

<Media Id='2'/>

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

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

这将使安装程序在安装介质上与要安装的msi相同的文件夹中查找名为" myinstaller.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>

回答

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

它不能解决的问题是安装的GPO(全局策略对象)分发。 GPO需要一个dot-msi文件才能运行安装。

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

进一步走很容易。我将引导程序返回控件移到了顶级安装程序并继续。然后,我添加了一个WaitForSingleObject调用,以等待顶级安装完成,然后引导程序可以继续完成安装。

我的问题是GPO安装在引导时发生,并且顶层安装在子安装程序完成和GPO重新引导计算机之前完成。

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

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