杉宫竹苑工作室

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3549|回复: 0

如何使用WiX创建一个简单的MSI安装程序

[复制链接]
发表于 2017-4-8 14:22:44 | 显示全部楼层 |阅读模式

正式会员享受无限制浏览网站功能和高速网盘下载,赶快加入本站吧!

您需要 登录 才可以下载或查看,没有账号?立即注册

x
我们的目标
我们将在这里为我们的程序(称为Sample App)创建一个简单的MSI安装程序。安装程序将:

允许用户选择安装目录
在开始 - >程序菜单中创建程序文件夹
显示许可协议对话框
有定制图形
为用户提供安装后启动应用程序的选项
为所有用户安装应用程序
有一件事要注意 - 有两个版本的WiX可用 - v2和v3。由于v3仍然处于测试阶段,所以我在开始使用v2。但是后来我尝试使用beta,它发生了更简单的使用,而且更强大,我还没有返回到v2。所以我建议使用WiX 3(如下面的例子所示)。

一点点理论
在互联网上有一些很好的WiX教程,这将给你更多的关于WiX和MSI的知识比这篇小文章。我建议阅读WiX教程一开始。在这里,我将向您展示如何使用WiX创建您的第一个MSI安装程序,而无需担心更高级的功能和背景细节。
首先一些基本概念:

我们的应用是一种产品。它被两个唯一的GUID识别。每次更改应用程序版本时,产品GUID都会更改。升级GUID必须保持不变,因为Windows Installer使用它来确定是否安装了其他版本
一个包装包含安装应用程序所需的一切; 每个包都有自己的GUID(每次构建MSI时都应该更改)
一个功能是应用程序的一个部分,用户可以决定是否安装(例如示例文件,皮肤,其他语言,文档); 在我们的示例中,我们不会给用户选择应该安装的内容,所以默认情况下只安装一个功能
一个部件是可安装的软件的小单元(一个文件,目录,快捷方式,注册表项); 每个特征由组件组成; 每个组件都有自己独特的GUID。
最简单的安装程序
这是一个非常基本的安装程序,无需用户界面。它在“程序文件”中创建一个名为“示例应用程序”的子文件夹,其中有一个可执行文件。
  1. <?xml version='1.0' encoding='windows-1252'?>  
  2. <Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>  
  3. <Product Name='Sample App' Id='PRODUCT-GUID-HERE'  
  4.   UpgradeCode='UPGRADE-GUID-HERE'  
  5.   Language='1033' Version='YOUR-APP-VERSION-HERE' Manufacturer='YOU!'>  
  6.   
  7.   <Package Id='*' InstallerVersion='200' Compressed='yes' />  
  8.         
  9.   <Media Id='1' Cabinet='SampleApp.cab' EmbedCab='yes' />  
  10.       
  11.   <Directory Id='TARGETDIR' Name='SourceDir'>  
  12.    <Directory Id='ProgramFilesFolder'>  
  13.     <Directory Id='INSTALLDIR' Name='Sample App'>  
  14.      <Component Id='MainExecutable' Guid='COMPONENT-GUID-HERE'>  
  15.       <File Id='SampleAppEXE' Name='SampleApp.exe' Source='..\SampleApp\bin\Release\SampleApp.exe' Vital='yes' />  
  16.       <RemoveFolder Id="INSTALLDIR" On="uninstall" />  
  17.      </Component>  
  18.     </Directory>  
  19.    </Directory>  
  20.   </Directory>  
  21.               
  22.   <Feature Id='Complete' Level="1">  
  23.    <ComponentRef Id='MainExecutable' />  
  24.   </Feature>  
  25.    
  26. </Product>  
  27. </Wix>  
复制代码

正如你所看到的,我们在这里定义了目录的层次结构,单个组件(我们的可执行文件)和一个功能。请注意,我们放置一个星号而不是包GUID。这可以让WiX在每次创建安装包时生成新的GUID。构建安装程序用有效号码替换GUID,并告诉WiX构建MSI:
  1. > candle.exe SampleApp.wxs
  2. > light.exe SampleApp.wixobj
复制代码

使用它一段时间,检查是否将可执行文件安装到Program Files子目录中,如果您可以卸载该应用程序(如果它已被删除)。

程序菜单中的应用程序文件夹
好的,我们安装了我们的产品,但用户必须手动导航到其主目录才能启动它。我们真的应该在程序菜单中创建一个文件夹。这是我们如何做到这一点。
首先,我们必须在程序菜单中创建一个子文件夹。将以下目录结构添加为TARGETDIR目录标记的子代:
  1. <Directory Id="ProgramMenuFolder">  
  2. <Directory Id="ProgramMenuDir" Name="Sample App">  
  3.   <Component Id='ProgramMenuDir' Guid='COMPONENT2-GUID-HERE'>  
  4.    <RegistryValue Root='HKCU' Key='SOFTWARE\you\Sample App'   
  5.     Type='string' Value='Hello World' KeyPath='yes' />  
  6.    <RemoveFolder Id="ProgramMenuDir" On="uninstall" />  
  7.   </Component>  
  8. </Directory>  
  9. </Directory>
复制代码

这将创建一个我们想要的文件夹。我们有一个新的组件负责创建此目录。将其添加到我们的“完成”功能。我们还创建一个虚拟注册表项。这是必需的,因为没有它会抱怨ICE38错误。这是一个解决方法&#128578;
我们希望我们的快捷方式有一个图标。我们可以这样定义:
  1. <Icon Id="SampleApp.ico" SourceFile="sample.ico" />  
复制代码

这可以放在Feature标签之前。
现在我们拥有在“ProgramMenuDir”文件夹中创建快捷方式所需的一切。要创建它,我们把它放在里面文件标签:

查看纯文本到剪贴板打印?
  1. <Shortcut Id="startmenuSampleApp" Directory="ProgramMenuDir"   
  2. Name="Sample App" WorkingDirectory='INSTALLDIR'   
  3. Icon="SampleApp.ico" IconIndex="0" Advertise='yes' />  
复制代码
   
添加和自定义UI
WiX提供了一些预定义的用户界面。我们将使用InstallDir,它显示许可协议,并允许用户指定安装目录。要添加此界面,请放置以下两行(例如,在功能关闭标记之后):

查看纯文本到剪贴板打印?
  1. <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />  
  2. <UIRef Id="WixUI_InstallDir" />  
复制代码

在创建安装程序时,我们必须使用包含我们的UI的扩展。使用以下命令:
  1. > light.exe SampleApp.wixobj -ext WixUIExtension
复制代码

那很简单,不是吗?现在我们可以自定义界面了一下。首先我们可以提供我们自己的许可证。它应该是RTF格式。我认为这个文件叫做OurLicense.rtf。你也可以改变图形(我真的不认为默认的红色皮肤看起来不错)。这样做创建两个位图。第一个是欢迎对话框。它的大小是493×312像素,调用文件dlgbmp.bmp。第二个图像是其余对话框中可见的顶部横幅。其大小为493×58像素。将其放在bannrbmp.bmp文件中。这两个位图都应该是RLE压缩的,这样会减少我们的msi文件输出文件大小。
现在,我们有必要的文件准备,我们可以自定义安装程序。这三条线照顾它:

查看纯文本到剪贴板打印?
  1. <WixVariable Id="WixUIBannerBmp" Value="bannrbmp.bmp" />  
  2. <WixVariable Id="WixUIDialogBmp" Value="dlgbmp.bmp" />  
  3. <WixVariable Id="WixUILicenseRtf" Value="OurLicense.rtf"
复制代码

你可以把那些3行放在UIRef标签之后。瞧,我们定制我们的安装程序!

设置结束时启动应用程序
假设我们要在最后一个安装程序对话框中添加一个复选框,例如“安装程序退出时启动示例应用程序”。这更复杂,我们必须复制默认退出对话框并对其进行修改。我发现一个非常有用的博客条目描述了这样做(“安装后有条件地启动应用程序”的第二种方法)。按照该文章中描述的步骤添加我们想要的复选框。这几乎完美无瑕。但是我建议改进一点。
首先,我们希望在默认情况下选中该复选框。要实现这一点,请将以下属性添加到我们的安装程序中:

查看纯文本到剪贴板打印?
  1. <Property Id="LAUNCHAPPONEXIT" Value="1" />  
复制代码

复选框旁边的文本具有固定的应用程序名称。在MyExitDialog.wxs中用'[ProductName]'替换'Sample App 1.0'。WiX将自动添加应用程序名称。
第三个令人讨厌的事情是,每当安装程序完成时,ckeckbox都是可见的。如果您第二次运行安装程序并选择“删除”选项,那么您的应用程序将被删除,“启动...”复选框将不会被隐藏。所以让我们把它隐藏起来 再次打开MyExitDialog.wxs并添加隐藏复选框的条件:
  1. <Control Id="LaunchCheckBox" Type="CheckBox"   
  2. X="10" Y="243" Width="170" Height="17"   
  3. Property="LAUNCHAPPONEXIT" CheckBoxValue="1"   
  4. Text="Launch [ProductName] when setup exits.">  
  5.   <Condition Action="hide">  
  6.    <![CDATA[WixUI_InstallMode = "Remove"]]>  
  7.   </Condition>  
  8. </Control>  
复制代码

要确保删除应用程序后不会执行该操作,请编辑添加新的启动条件的SampleApp.wxs:
  1. <Publish Dialog="MyExitDialog" Control="Finish" Order="1"   
  2. Event="DoAction" Value="LaunchApplication">  
  3. LAUNCHAPPONEXIT AND NOT (WixUI_InstallMode = "Remove")  
  4. </Publish>  
复制代码

这是诀窍。要构建安装程序,请执行以下命令:
  1. > candle.exe SampleApp.wxs MyExitDialog.wxs MyWixUI_InstallDir.wxs
  2. > light SampleApp.wixobj MyExitDialog.wixobj MyWixUI_InstallDir.wixobj -out SampleApp.msi -ext WixUIExtension
复制代码

次要安装程序改进
我们可以为我们的安装程序添加一些小功能:

为所有用户安装应用程序
如果你想为所有用户安装你的应用程序,不仅仅是当前的应用程序,这样做的诀窍在于:

查看纯文本到剪贴板打印?
  1. <Property Id="ALLUSERS">1</Property>  
复制代码

先决条件
假设您的应用程序需要运行Microsoft .NET Framework 2.0。添加以下条件以检查是否已安装:
  1. <Condition Message=  
  2. 'This setup requires the .NET Framework 2.0 or higher.'>  
  3. <![CDATA[MsiNetAssemblySupport >= "2.0.50727"]]>  
  4. </Condition>  
复制代码

安装程序权限
如果您安装的软件需要管理权限,请添加以下条件:

查看纯文本到剪贴板打印?
  1. <Condition Message=  
  2. 'You need to be an administrator to install this product.'>  
  3. Privileged  
  4. </Condition>  
复制代码

产品版本
现在,产品版本在SampleApp.wxs文件中指定,并且必须在产品版本更改时手动更改。我使用一个Python脚本从编译的可执行文件读取版本并修改wxs文件。此外,如果产品版本从上次更改,则会生成新产品GUID。如果你想写这个脚本,这里有两个功能很有用:
  1. import win32api  
  2. import msilib  
  3. import os.path  
  4.   
  5. def get_version_number(file):  
  6. if os.path.exists(file):  
  7.   info = win32api.GetFileVersionInfo(file, "\")  
  8.   ms = info['FileVersionMS']  
  9.   ls = info['FileVersionLS']  
  10.   return win32api.HIWORD(ms), win32api.LOWORD(ms),   
  11.    win32api.HIWORD(ls), win32api.LOWORD(ls)  
  12.   
  13. def generate_new _guid():  
  14. return msilib.gen_uuid()[1:-1]  
复制代码

我们的最终安装程序
以下是SampleApp.wxs文件的最终版本(请记住,此处还需要MyExitDialog.wxs和MyWixUI_InstallDir.wxs )。
  1. <?xml version='1.0' encoding='windows-1252'?>  
  2. <Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>  
  3. <Product Name='Sample App' Id='PRODUCT-GUID-HERE'  
  4.   UpgradeCode='UPGRADE-GUID-HERE'  
  5.   Language='1033' Version='YOUR-APP-VERSION-HERE' Manufacturer='YOU!'>  
  6.   
  7.   <Package Id='*' InstallerVersion='200' Compressed='yes' />  
  8.   
  9.   <Condition Message=  
  10. "You need to be an administrator to install this product.">  
  11.    Privileged  
  12.   </Condition>  
  13.   <Condition Message=  
  14. 'This setup requires the .NET Framework 2.0 or higher.'>  
  15.    <![CDATA[MsiNetAssemblySupport >= "2.0.50727"]]>  
  16.   </Condition>  
  17.   
  18.   <Media Id='1' Cabinet='SampleApp.cab' EmbedCab='yes' />  
  19.   
  20.   <Directory Id='TARGETDIR' Name='SourceDir'>  
  21.    <Directory Id='ProgramFilesFolder'>  
  22.     <Directory Id='INSTALLDIR' Name='Sample App'>  
  23.      <Component Id='MainExecutable' Guid='COMPONENT-GUID-HERE'>  
  24.       <File Id='SampleAppEXE' Name='SampleApp.exe'  
  25.        Source='..\SampleApp\bin\Release\SampleApp.exe' Vital='yes'>  
  26.        <Shortcut Id="startmenuSampleApp" Directory="ProgramMenuDir"  
  27.         Name="Sample App" WorkingDirectory='INSTALLDIR'  
  28.         Icon="SampleApp.ico" IconIndex="0" Advertise='yes' />  
  29.       </File>  
  30.       <RemoveFolder Id="INSTALLDIR" On="uninstall" />  
  31.      </Component>  
  32.     </Directory>  
  33.    </Directory>  
  34.   
  35.    <Directory Id="ProgramMenuFolder">  
  36.     <Directory Id="ProgramMenuDir" Name="Sample App">  
  37.      <Component Id='ProgramMenuDir' Guid='COMPONENT2-GUID-HERE'>  
  38.       <RegistryValue Root='HKCU' Key='SOFTWARE\you\Sample App'  
  39.        Type='string' Value='Hello World' KeyPath='yes' />  
  40.       <RemoveFolder Id="ProgramMenuDir" On="uninstall" />  
  41.      </Component>  
  42.     </Directory>  
  43.    </Directory>  
  44.   </Directory>  
  45.   
  46.   <Icon Id="SampleApp.ico" SourceFile="eye.ico"/>  
  47.   
  48.   <Feature Id='Complete' Level="1">  
  49.    <ComponentRef Id='MainExecutable' />  
  50.    <ComponentRef Id='ProgramMenuDir' />  
  51.   </Feature>  
  52.   
  53.   <WixVariable Id="WixUIBannerBmp" Value="bannrbmp.bmp" />  
  54.   <WixVariable Id="WixUIDialogBmp" Value="dlgbmp.bmp" />  
  55.   <WixVariable Id="WixUILicenseRtf" Value="OurLicense.rtf" />  
  56.   
  57.   <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />  
  58.   <UIRef Id="MyWixUI_InstallDir" />  
  59.   
  60.   <CustomAction Id="LaunchApplication"  
  61.    FileKey="SampleAppEXE" ExeCommand="" Execute="immediate"  
  62.    Impersonate="yes" Return="asyncNoWait" />  
  63.   <UI>  
  64.    <Publish Dialog="MyExitDialog" Control="Finish"  
  65.     Order="1" Event="DoAction" Value="LaunchApplication">  
  66.     LAUNCHAPPONEXIT AND NOT (WixUI_InstallMode = "Remove")  
  67.    </Publish>  
  68.   </UI>  
  69.   
  70.   <!-- This will ensure that the LaunchConditions  
  71.   are executed only after searching -->  
  72.   <InstallUISequence>  
  73.    <LaunchConditions After='AppSearch' />  
  74.   </InstallUISequence>  
  75.   <InstallExecuteSequence>  
  76.    <LaunchConditions After='AppSearch' />  
  77.   </InstallExecuteSequence>  
  78.   
  79. </Product>  
  80. </Wix>  
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|Archiver|SgzyStudio

GMT+8, 2024-3-28 18:51 , Processed in 0.447905 second(s), 22 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表