admin 发表于 2017-4-8 14:22:44

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

我们的目标
我们将在这里为我们的程序(称为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。
最简单的安装程序
这是一个非常基本的安装程序,无需用户界面。它在“程序文件”中创建一个名为“示例应用程序”的子文件夹,其中有一个可执行文件。
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='Sample App' Id='PRODUCT-GUID-HERE'
UpgradeCode='UPGRADE-GUID-HERE'
Language='1033' Version='YOUR-APP-VERSION-HERE' Manufacturer='YOU!'>

<Package Id='*' InstallerVersion='200' Compressed='yes' />
      
<Media Id='1' Cabinet='SampleApp.cab' EmbedCab='yes' />
      
<Directory Id='TARGETDIR' Name='SourceDir'>
   <Directory Id='ProgramFilesFolder'>
    <Directory Id='INSTALLDIR' Name='Sample App'>
   <Component Id='MainExecutable' Guid='COMPONENT-GUID-HERE'>
      <File Id='SampleAppEXE' Name='SampleApp.exe' Source='..\SampleApp\bin\Release\SampleApp.exe' Vital='yes' />
      <RemoveFolder Id="INSTALLDIR" On="uninstall" />
   </Component>
    </Directory>
   </Directory>
</Directory>
            
<Feature Id='Complete' Level="1">
   <ComponentRef Id='MainExecutable' />
</Feature>
   
</Product>
</Wix>
正如你所看到的,我们在这里定义了目录的层次结构,单个组件(我们的可执行文件)和一个功能。请注意,我们放置一个星号而不是包GUID。这可以让WiX在每次创建安装包时生成新的GUID。构建安装程序用有效号码替换GUID,并告诉WiX构建MSI:
> candle.exe SampleApp.wxs
> light.exe SampleApp.wixobj
使用它一段时间,检查是否将可执行文件安装到Program Files子目录中,如果您可以卸载该应用程序(如果它已被删除)。

程序菜单中的应用程序文件夹
好的,我们安装了我们的产品,但用户必须手动导航到其主目录才能启动它。我们真的应该在程序菜单中创建一个文件夹。这是我们如何做到这一点。
首先,我们必须在程序菜单中创建一个子文件夹。将以下目录结构添加为TARGETDIR目录标记的子代:
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgramMenuDir" Name="Sample App">
<Component Id='ProgramMenuDir' Guid='COMPONENT2-GUID-HERE'>
   <RegistryValue Root='HKCU' Key='SOFTWARE\you\Sample App'   
    Type='string' Value='Hello World' KeyPath='yes' />
   <RemoveFolder Id="ProgramMenuDir" On="uninstall" />
</Component>
</Directory>
</Directory>
这将创建一个我们想要的文件夹。我们有一个新的组件负责创建此目录。将其添加到我们的“完成”功能。我们还创建一个虚拟注册表项。这是必需的,因为没有它会抱怨ICE38错误。这是一个解决方法&#128578;
我们希望我们的快捷方式有一个图标。我们可以这样定义:
<Icon Id="SampleApp.ico" SourceFile="sample.ico" />
这可以放在Feature标签之前。
现在我们拥有在“ProgramMenuDir”文件夹中创建快捷方式所需的一切。要创建它,我们把它放在里面文件标签:

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

查看纯文本到剪贴板打印?
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<UIRef Id="WixUI_InstallDir" />
在创建安装程序时,我们必须使用包含我们的UI的扩展。使用以下命令:
> light.exe SampleApp.wixobj -ext WixUIExtension
那很简单,不是吗?现在我们可以自定义界面了一下。首先我们可以提供我们自己的许可证。它应该是RTF格式。我认为这个文件叫做OurLicense.rtf。你也可以改变图形(我真的不认为默认的红色皮肤看起来不错)。这样做创建两个位图。第一个是欢迎对话框。它的大小是493×312像素,调用文件dlgbmp.bmp。第二个图像是其余对话框中可见的顶部横幅。其大小为493×58像素。将其放在bannrbmp.bmp文件中。这两个位图都应该是RLE压缩的,这样会减少我们的msi文件输出文件大小。
现在,我们有必要的文件准备,我们可以自定义安装程序。这三条线照顾它:

查看纯文本到剪贴板打印?
<WixVariable Id="WixUIBannerBmp" Value="bannrbmp.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="dlgbmp.bmp" />
<WixVariable Id="WixUILicenseRtf" Value="OurLicense.rtf"
你可以把那些3行放在UIRef标签之后。瞧,我们定制我们的安装程序!

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

查看纯文本到剪贴板打印?
<Property Id="LAUNCHAPPONEXIT" Value="1" />
复选框旁边的文本具有固定的应用程序名称。在MyExitDialog.wxs中用''替换'Sample App 1.0'。WiX将自动添加应用程序名称。
第三个令人讨厌的事情是,每当安装程序完成时,ckeckbox都是可见的。如果您第二次运行安装程序并选择“删除”选项,那么您的应用程序将被删除,“启动...”复选框将不会被隐藏。所以让我们把它隐藏起来 再次打开MyExitDialog.wxs并添加隐藏复选框的条件:
<Control Id="LaunchCheckBox" Type="CheckBox"   
X="10" Y="243" Width="170" Height="17"   
Property="LAUNCHAPPONEXIT" CheckBoxValue="1"   
Text="Launch when setup exits.">
<Condition Action="hide">
   <!]>
</Condition>
</Control>
要确保删除应用程序后不会执行该操作,请编辑添加新的启动条件的SampleApp.wxs:
<Publish Dialog="MyExitDialog" Control="Finish" Order="1"   
Event="DoAction" Value="LaunchApplication">
LAUNCHAPPONEXIT AND NOT (WixUI_InstallMode = "Remove")
</Publish>
这是诀窍。要构建安装程序,请执行以下命令:
> candle.exe SampleApp.wxs MyExitDialog.wxs MyWixUI_InstallDir.wxs
> light SampleApp.wixobj MyExitDialog.wixobj MyWixUI_InstallDir.wixobj -out SampleApp.msi -ext WixUIExtension
次要安装程序改进
我们可以为我们的安装程序添加一些小功能:

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

查看纯文本到剪贴板打印?
<Property Id="ALLUSERS">1</Property>
先决条件
假设您的应用程序需要运行Microsoft .NET Framework 2.0。添加以下条件以检查是否已安装:
<Condition Message=
'This setup requires the .NET Framework 2.0 or higher.'>
<!]>
</Condition>
安装程序权限
如果您安装的软件需要管理权限,请添加以下条件:

查看纯文本到剪贴板打印?
<Condition Message=
'You need to be an administrator to install this product.'>
Privileged
</Condition>
产品版本
现在,产品版本在SampleApp.wxs文件中指定,并且必须在产品版本更改时手动更改。我使用一个Python脚本从编译的可执行文件读取版本并修改wxs文件。此外,如果产品版本从上次更改,则会生成新产品GUID。如果你想写这个脚本,这里有两个功能很有用:
import win32api
import msilib
import os.path

def get_version_number(file):
if os.path.exists(file):
info = win32api.GetFileVersionInfo(file, "\\")
ms = info['FileVersionMS']
ls = info['FileVersionLS']
return win32api.HIWORD(ms), win32api.LOWORD(ms),   
   win32api.HIWORD(ls), win32api.LOWORD(ls)

def generate_new _guid():
return msilib.gen_uuid()
我们的最终安装程序
以下是SampleApp.wxs文件的最终版本(请记住,此处还需要MyExitDialog.wxs和MyWixUI_InstallDir.wxs )。
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='Sample App' Id='PRODUCT-GUID-HERE'
UpgradeCode='UPGRADE-GUID-HERE'
Language='1033' Version='YOUR-APP-VERSION-HERE' Manufacturer='YOU!'>

<Package Id='*' InstallerVersion='200' Compressed='yes' />

<Condition Message=
"You need to be an administrator to install this product.">
   Privileged
</Condition>
<Condition Message=
'This setup requires the .NET Framework 2.0 or higher.'>
   <!]>
</Condition>

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

<Directory Id='TARGETDIR' Name='SourceDir'>
   <Directory Id='ProgramFilesFolder'>
    <Directory Id='INSTALLDIR' Name='Sample App'>
   <Component Id='MainExecutable' Guid='COMPONENT-GUID-HERE'>
      <File Id='SampleAppEXE' Name='SampleApp.exe'
       Source='..\SampleApp\bin\Release\SampleApp.exe' Vital='yes'>
       <Shortcut Id="startmenuSampleApp" Directory="ProgramMenuDir"
      Name="Sample App" WorkingDirectory='INSTALLDIR'
      Icon="SampleApp.ico" IconIndex="0" Advertise='yes' />
      </File>
      <RemoveFolder Id="INSTALLDIR" On="uninstall" />
   </Component>
    </Directory>
   </Directory>

   <Directory Id="ProgramMenuFolder">
    <Directory Id="ProgramMenuDir" Name="Sample App">
   <Component Id='ProgramMenuDir' Guid='COMPONENT2-GUID-HERE'>
      <RegistryValue Root='HKCU' Key='SOFTWARE\you\Sample App'
       Type='string' Value='Hello World' KeyPath='yes' />
      <RemoveFolder Id="ProgramMenuDir" On="uninstall" />
   </Component>
    </Directory>
   </Directory>
</Directory>

<Icon Id="SampleApp.ico" SourceFile="eye.ico"/>

<Feature Id='Complete' Level="1">
   <ComponentRef Id='MainExecutable' />
   <ComponentRef Id='ProgramMenuDir' />
</Feature>

<WixVariable Id="WixUIBannerBmp" Value="bannrbmp.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="dlgbmp.bmp" />
<WixVariable Id="WixUILicenseRtf" Value="OurLicense.rtf" />

<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
<UIRef Id="MyWixUI_InstallDir" />

<CustomAction Id="LaunchApplication"
   FileKey="SampleAppEXE" ExeCommand="" Execute="immediate"
   Impersonate="yes" Return="asyncNoWait" />
<UI>
   <Publish Dialog="MyExitDialog" Control="Finish"
    Order="1" Event="DoAction" Value="LaunchApplication">
    LAUNCHAPPONEXIT AND NOT (WixUI_InstallMode = "Remove")
   </Publish>
</UI>

<!-- This will ensure that the LaunchConditions
are executed only after searching -->
<InstallUISequence>
   <LaunchConditions After='AppSearch' />
</InstallUISequence>
<InstallExecuteSequence>
   <LaunchConditions After='AppSearch' />
</InstallExecuteSequence>

</Product>
</Wix>
页: [1]
查看完整版本: 如何使用WiX创建一个简单的MSI安装程序