【引用】Wix使用说明

 Wix:全称Windows Installer XML,属于微软的一个开源项目,目标是使用XML语言灵活的定制具有各种功能的安装包,需要微软的Windows Installer服务支持。

   Wix生成的产品为msi文件,这种可执行文件与exe文件最大的不同为,它更底层,安装文件的同时可以对系统或者其他软件进行设置。
LanguageCodepage的设

Language指所在地区使用的语言,为数字编号。
Codepage
指所在地区的代码页,用来进行区域区分。
下来列举几个常见的区域代号:
语言                              语言国家     Language      Codepage
English                            en-us             1033               1252
Simplified Chinese            zh-cn              2052               936
Traditional Chinese           zh-tw              1028                950

GUID的生成

VS2005中,通过工具”——“创建GUID”生成。
GUID
也可以自行定义,但是前提是要保证唯一。

安装文件描述XML自动生成

当安装文件特别多的时候,我们就需要用专用的工具进行文件描述XML的自动生成了,采用的是Wix自带的heat工具,位于安装目录的bin下。
    Heat
的使用方法为:
    heat.exe [-?] harvestType <harvester arguments> -out sourceFile.wxs
   
详细见Wix说明文档。
   
例子:
    heat.exe  dir ABC -gg -ke -sfrag -template:fragment -dr INSTALLLOCATION -cg BasicComponentGroup -srd -out  ABC.wxs
   
作用为:将目录ABC(相对目录)下的所有文件(包括空目录)作为一个ComponentGroup添加到ABC.wxs文件中,其中根目录为INSTALLLOCATION,段标签为fragment
运行这行命令会自动生成一个wxs文件,里面包含ABC目录下所有文件的描述。

Feature的选择安装

Wix安装包中所有的组件都是以Feature的方式安装到系统中的,Level是安装级别,是最重要的属性之一,不可缺少。
    Level
的值为整型,最小为0,最大1000。为0的时候此Feature不安装。 一般来说Level与选择安装关联,与之相对应的一个属性为INSTALLLEVEL,默认为1.小于1Feature将不会被安装。Level值为3FeatureTypical类型,Level值大于3Complete类型。Level也可以在安装时动态修改,使用<Condition>条件判断。例如:
<Feature Id=”DesktopFt” Title=”Desktop” Level=”1″>
        <Condition Level=”0″><![CDATA[HASDESKTOP <> “1”]]></Condition>
        <ComponentRef Id=”DesktopShortcutComponent”/>
  </Feature>
   
如果HASDESKTOP属性值不为1,那么此FeatureLevel将为0,不会被安装。使用此种方式选择安装需注意HASDESKTOP属性的初始化位置,一定要保证在Feature初始化前进行。否则设置无效。
   
也可以采用另一种方法选择性安装:
    HASDESKTOP
属性修改的地方添加<Publish>
      <Publish Event=”AddLocal” Value=”ALL”>1</Publish>
      <Publish Event=”Remove” Value=”DesktopFt”><![CDATA[HASDESKTOP <> “1”]]></Publish>
   
这样效果一样,但是不需要HASDESKTOP的值的初始化在Feature之前。
   
详细参考 http://www.joyofsetup.com/2007/05/30/feature-conditions-and-ui/

Property的使用

Wix中使用自定义变量的方法为声明Property(属性)。
Property
分为两种:全局的和局部的。全局属性必须全部大写,否则视为局部属性。
例如:
<Property Id=”HASDESKTOP” Value=”1″/>
如果改为小写,那么其他文件(也许是fragment)的代码调用属性无效。
搜索、判断得到的属性一律为全局属性,大写。例如:
<Property Id=”VC71PATH”>
      <RegistrySearch Id=”VC71″ Type=”raw” Root=”HKLM” Key=”SOFTWAREMicrosoftVisualStudio7.1″ Name=”InstallDir”/>
</Property>
上述例子为在注册表中查找VC71InstallDir的值,如存在将值付给VC71PATH,不存在则VC71PATH为空。

安装包的中文化

Wix默认的语言为en-us,中文化需要另外添加zh-cnzh-tw的描述文件。
拥有了中文拓展的文件以后,在代码中使用loc调用属性即可,使用方式与en-us无异。
当然也可以自定义一些中文化的标签,格式为:
<WixLocalization Culture=”zh-cn” xmlns=”http://schemas.microsoft.com/wix/2006/localization”>
<String Id=”LicenseThirdPartText” Overridable=”yes”>
请仔细阅读以下声明</String>
</WixLocalization>
调用方式为:text =”!(loc.LicenseThirdPartText)”

中文语言包下载地址为:http://download.csdn.net/salever

内置CustomAction的使用

1. Quiet Execution Custom Action 安静模式下执行操作。允许用户在后台执行一些命令,但是不出现执行窗口。
   
1,安静模式下执行CMD操作 
<Property Id=”QtExecCmdLine” Value=”command line to run”/>
<CustomAction Id=”QtExecExample” BinaryKey=”WixCA” DllEntry=”CAQuietExec” Execute=”immediate” Return=”check”/>
<InstallExecuteSequence>   
   <Custom Action=”QtExecExample” After=”TheActionYouWantItAfter”/>
</InstallExecuteSequence>
采用安静模式执行CMD操作,但是不出现CMD命令窗口。注意Value中的命令以及应用程序必须加引号,即使没有空格也要加上。

2,安静模式下执行其他应用程序操作
<CustomAction
Id=”QtExecDeferredExampleWithProperty_Cmd” Property=”QtExecDeferredExampleWithProperty”
              Value=””[#MyExecutable.exe]”” Execute=”immediate”/>
<CustomAction Id=”QtExecDeferredExampleWithProperty” BinaryKey=”WixCA” DllEntry=”CAQuietExec”
              Execute=”deferred” Return=”check” Impersonate=”no”/>

<InstallExecuteSequence>
    <Custom Action=”QtExecDeferredExampleWithProperty_Cmd” After=”CostFinalize”/>
    <Custom Action=”QtExecDeferredExampleWithProperty” After=”TheActionYouWantItAfter”/>
</InstallExecuteSequence>

2.ShellExecute CustomAction 执行打开文档或URL等操作。典型应用为安装完成后打开帮助文件或则运行安装程序。
例:
<Property Id=”WixShellExecTarget” Value=”myapplication.exe” />
    <CustomAction Id=”LaunchApplication”
        BinaryKey=”WixCA”
        DllEntry=”WixShellExec”
        Impersonate=”yes” />
    </Product>

安装卸载时进行日志记录

Wix制作的Installer的调试很麻烦,没有直接的Bug工具,可以通过记录安装日志的方式进行间接调试。命令为
msiexec /i package.msi /l log.txt

详细参考:
msiexec /Option <Required Parameter> [Optional Parameter]
安装选项
        </package | /i> <Product.msi>
               
安装或配置产品
        /a <Product.msi>
               
管理安装在网络上安装产品
        /j<u|m> <Product.msi> [/t <Transform List>] [/g <Language ID>]
               
播发产品 – m 播发到所有用户,u 播发到当前用户
        </uninstall | /x> <Product.msi | ProductCode>
               
卸载产品
显示选项
        /quiet
               
安静模式,无用户交互
        /passive
               
无从参与模式只显示进程栏
        /q[n|b|r|f]
               
设置用户界面级别
                n –
无用户界面
                b –
基本界面
                r –
精简界面
                f –
完整界面(默认值)
        /help
               
帮助信息

重新启动选项
        /norestart
               
安装完成后不重新启动
        /promptrestart
               
提示用户重新启动(如果必要)
        /forcerestart
               
安装后总是重新启动计算机

日志选项
        /l[i|w|e|a|r|u|c|m|o|p|v|x|+|!|*] <LogFile>
                i –
状态消息
                w –
非致命警告
                e –
全部错误消息
                a –
操作的启动
                r –
操作特定记录
                u –
用户请求
                c –
初始界面参数
                m –
内存不足或致命退出信息
                o –
磁盘空间不足消息
                p –
终端属性
                v –
详细输出
                x –
额外调试信息
                + –
扩展到现有日志文件
                ! –
每一行刷新到日志
                * –
记录所有信息,除了 v x 选项
        /log <LogFile>
               
/l* <LogFile> 相同
更新选项
        /update <Update1.msp>[;Update2.msp]
               
应用更新
        /uninstall <PatchCodeGuid>[;Update2.msp] /package <Product.msi | ProductCode>
               
删除产品的更新
修复选项
        /f[p|e|c|m|s|o|d|a|u|v] <Product.msi | ProductCode>
               
修复产品
                p –
仅当文件丢失时
                o –
如果文件丢失或安装了更旧的版本(默认值)
                e –
如果文件丢失或安装了相同或更旧的版本

                d –
如果文件丢失或安装了不同版本
                c –
如果文件丢失或较验和与计算的值不匹配
                a –
强制重新安装所有文件
                u –
所有必要的用户特定注册表项(默认值)
                m –
所有必要的计算机特定注册表项(默认值
)
                s –
所有现有的快键方式(默认值
)
                v –
从源运行并缓存本地数据包

设置公共属性
        [PROPERTY=PropertyValue]

安装默认位置的修改

安装包一般默认安装在系统盘的Program Files文件夹下,此文件在Wix中为ProgramFilesFolder,使用形式为:
<Directory Id=”ProgramFilesFolder”></Directory >
   
还有很多内置的文件夹描述属性,比如桌面——DesktopFolder、开始菜单的程序——ProgramMenuFolder,这些都可以直接用。
   
有时候安装程序限定要装在某个盘的根目录中,这时候可以用WindowsVolume来代替系统盘,但是使用方法上有一定的区别:
    <SetDirectory Id=”WINDOWSVOLUME” Value=”[WindowsVolume]”/>
    <Directory Id=”WINDOWSVOLUME”></Directory>
   
不加上SetDirectory会报错,最好加上。

    要想使用自己定义的安装目录,则要对Wix自带的属性WIXUI_INSTALLDIR进行包装。
    <Property Id=”WIXUI_INSTALLDIR” Value=”INSTALLLOCATION” />

自定义CustomAction()

CustomActionWix中扮演着很重要的角色,这里讲讲它的其中一个用途——根据条件设置属性的值。
例子:
<Property Id=”IDEVC71″ Value=”not detected”/>
<Property Id=”VC71PATH”>
      <RegistrySearch Id=”VC71″ Type=”raw” Root=”HKLM” Key=”SOFTWAREMicrosoftVisualStudio7.1″ Name=”InstallDir”/>
</Property>
<CustomAction Id=”MyAction.SetVC71Property” Return=”check” Property=”IDEVC71″ Value=”detected”>VC71PATH</CustomAction>

用途:一旦在注册表中找到相关的值,那么属性IDEVC71的值将被设为detected,否则为not detected

如何在安装时设置注册表和环境变量

设置注册表:
<RegistryValue Root=”HKCU” Key=”SoftwareDeveloper” Name=”installed” Type=”integer” Value=”1″ KeyPath=”yes”/>
   
设置环境变量:(这里将环境变量的设置作为一个Component
<Component Id=”ProductEnvironment” Guid=”” KeyPath=”yes”>
     <Environment Id=’UpdatePath’ Name=’PATH’ Action=’set’ System=’yes’ Part=’first’ Value='[INSTALLLOCATION]bin’/>
      <Environment Id=’SetTclLibraryPath’ Name=’TCL_LIBRARY’ Action=’set’ System=’yes’ Part=’all’ Value='[INSTALLLOCATION]msyslib’/>
</Component>
   
前者是添加到系统变量PATH中,后者是新建系统环境变量TCL_LIBRARY

自定义CustomAction()

调用本机应用程序:
<Property Id=”NOTEPAD”>Notepad.exe</Property>
<CustomAction Id=”LaunchReadme” Property=”NOTEPAD” ExeCommand=”[INSTALLLOCATION]README.txt” Return=”asyncNoWait”/>
   
用途:调用Notepad程序(记事本)打开安装目录下的README.txt文件。

INI文件的操作

Wix提供对标准INI文件的操作,包括新建、编辑等。
例子:
<IniFile Id=”WriteIntoFile” Action=”addLine” Key=”InstallDir” Name=”Foobar.ini” Sections=”Paths” Value=”[INSTALLDIR]”/>
用途:在文件Foobar.ini文件中Paths段下添加一行“InstallDir = 安装目录
Action
中的操作包括添加、删除、新建等。在实际编写代码时会有自动提示。

Heat的特殊用法

Heat工具用于harvest文件或者文件夹,是比较基础的Wix工具,这里讲讲它的一个特殊用法:配合candle使用var传递参数。
   
例如:
      heat.exe dir  VC80 -gg -nologo -ke -sfrag -template:fragment  -dr INSTALLLOCATION -cg VC80ComponentGroup -var var.VC80Dir -out buildVC80.wxs
   
用途:将文件夹VC80下的所有文件和文件夹打包进VC80ComponentGroup里,源文件根目录SourceDir用($var.VC80Dir )代替。
   
编译的时候使用candle -dVC80Dir=”VC80″即可,这样就可以同时对不同文件夹下的文件进行一次性处理。-d参数可以有多个,也可以在light的时候调用,尝试成功。

Wix自动化Build流程

heat

candle

light
目前可以考虑使用基本的BAT批处理命令进行自动化的Build过程,以后可以考虑引入Build系统。

  关于FilesInUse的使用

Wix中自带了FilesInUseMsiRMFilesInUse2个错误处理的对话框
一般不需要开发人员去处理,只需要在Install UI Sequence前引用这两个对话框即可
<DialogRef Id = “FilesInUse”>
这样卸载或者其他操作时,当前安装的文件正在被使用时会出现提示框,要求用户选择操作

安装时用户权限的判断

使用MSI程序进行安装时,一般要进行用户权限的判断,可以使用内置的属性Privileged进行判断,也可以通过设置Package的相关属性进行判断。

Privileged属性

      <Condition Message=”!(loc.InstallWarning)”>Privileged</Condition>
      
当用户不具备管理员权限时,安装停止并给出提示消息。

使用Package属性设置,一般来说有2中安装方式,面向用户和面向机器。
面向用户指的是所有用户下均进行安装,而不需要操作权限,即所有的用户均可安装、卸载。而面向机器指的是要求一定的管理员权限来安装或卸载程序。
    Wix
中的代码为:
<Package InstallerVersion=”200″ Compressed=”yes”  InstallScope=”perMachine”/>
    InstallScope
perMachine时面向机器,为perUser时为面向用户。

patch更新方式实现

对于少量文件的更新,Wix提供了patch的方式进行更新,不需要对所有的安装源文件进行覆盖,仅仅选择更新后的文件进行安装。
   
具体流程为:

准备2分安装源文件,一份为原始的,一份为更新后的文件

分别对2分安装源文件进行build操作,得到不同的msi安装文件

使用torch.exe pyro.exe 工具对2msi文件进行分析,得到两者之间的不同,整理出patch安装文件
  
实例:
Product.wxs

<?xml version=”1.0″ encoding=”UTF-8″?>
<Wix xmlns=”
http://schemas.microsoft.com/wix/2006/wi“>
    <Product Id=”48C49ACE-90CF-4161-9C6E-9162115A54DD”
        Name=”WiX Patch Example Product”
        Language=”1033″
        Version=”1.0.0″
        Manufacturer=”Dynamo Corporation”
        UpgradeCode=”48C49ACE-90CF-4161-9C6E-9162115A54DD”>
        <Package Description=”Installs a file that will be patched.”
            Comments=”This Product does not install any executables”
            InstallerVersion=”200″
            Compressed=”yes” />

        <Media Id=”1″ Cabinet=”product.cab” EmbedCab=”yes” />
        <FeatureRef Id=”SampleProductFeature”/>
    </Product>

    <Fragment>
        <Feature Id=”SampleProductFeature” Title=”Sample Product Feature” Level=”1″>
            <ComponentRef Id=”SampleComponent” />
        </Feature>
    </Fragment>

    <Fragment>
        <DirectoryRef Id=”SampleProductFolder”>
            <Component Id=”SampleComponent” Guid=”{C28843DA-EF08-41CC-BA75-D2B99D8A1983}” DiskId=”1″>
                <File Id=”SampleFile” Name=”Sample.txt” Source=”.$(var.Version)Sample.txt” />
            </Component>
        </DirectoryRef>
    </Fragment>

    <Fragment>
        <Directory Id=”TARGETDIR” Name=”SourceDir”>
            <Directory Id=”ProgramFilesFolder” Name=”PFiles”>
                <Directory Id=”SampleProductFolder” Name=”Patch Sample Directory”>
                </Directory>
            </Directory>
        </Directory>
    </Fragment>
</Wix>

Patch.wxs
<?xml version=”1.0″ encoding=”UTF-8″?>
<Wix xmlns=”
http://schemas.microsoft.com/wix/2006/wi“>
    <Patch
        AllowRemoval=”yes”
        Manufacturer=”Dynamo Corp”
        MoreInfoURL=”
http://www.dynamocorp.com/
        DisplayName=”Sample Patch”
        Description=”Small Update Patch”
        Classification=”Update”
        >

        <Media Id=”5000″ Cabinet=”RTM.cab”>
            <PatchBaseline Id=”RTM”/>
        </Media>

        <PatchFamilyRef Id=”SamplePatchFamily”/>
    </Patch>

    <Fragment>   
        <PatchFamily Id=’SamplePatchFamily’ Version=’1.0.0.0′ Supersede=’yes’>
            <ComponentRef Id=”SampleComponent”/>
        </PatchFamily>
    </Fragment>
</Wix>

cmd命令依次为:
candle.exe -dVersion=1.0 product.wxs
light.exe product.wixobj -out 1.0product.msi
candle.exe -dVersion=1.1 product.wxs
light.exe product.wixobj -out 1.1product.msi
torch.exe -p -xi 1.0product.wixpdb 1.1product.wixpdb -out patchdiff.wixmst
candle.exe patch.wxs
light.exe patch.wixobj -out patchpatch.wixmsp
pyro.exe patchpatch.wixmsp -out patchpatch.msp -t RTM patchdiff.wixmst
最后得到的msp文件即为patch更新文件。

安装程序版本控制问题

在安装程序更新时,假如productid没有改变,则表明该安装程序不允许多个版本共存。
一般msi程序更新时,都需要用到UpGradeCode,这个属性是安装程序更新唯一标示。

序列号验证机制的加入

    <Control Id=”CDKeyNumber” Type=”Edit” X=”55″ Y=”80″ Width=”200″ Height=”15″ Property=”CDKEY”/>

        <Control Id=”CDKeyErrorInfo” Type=”Text” X=”55″ Y=”100″  Width=”200″ Height=”15″ Hidden=”yes” Text=”!(loc.CDKeyError)”>

          <Condition Action=”show”><![CDATA[CDKEY <> “123” AND CDKEYCHECK = “yes”]]></Condition>

        </Control>     

自定义一个安装对话框,然后使用typetextcontrol控件,采用一个公用属性 CDKEY 获得用户输入的CDKey,然后定义一个CustomAction,对CDKey进行判断即可。此处将CDKey限定为123

    更多用户信息要求的对话框:

<Fragment>

  <UI>

    <Dialog Id=”UserRegistrationDlg” Width=”370″ Height=”270″ Title=”[ProductName] [Setup]” NoMinimize=”yes”>

      <Control Id=”NameLabel” Type=”Text” X=”45″ Y=”73″ Width=”100″ Height=”15″ TabSkip=”no” Text=”&UserName:” />”

        <Control Id=”NameEdit” Type=”Edit” X=”45″ Y=”85″ Width=”220″ Height=”18″ Property=”USERNAME” Text=”{80}” />

        <Control Id=”OrganizationLabel” Type=”Text” X=”45″ Y=”110″ Width=”100″ Height=”15″ TabSkip=”no” Text=”&Organization:” />”

          <Control Id=”OrganizationEdit” Type=”Edit” X=”45″ Y=”122″ Width=”220″ Height=”18″ Property=”COMPANYNAME” Text=”{80}” />

          <Control Id=”CDKeyLabel” Type=”Text” X=”45″ Y=”147″ Width=”50″ Height=”10″ TabSkip=”no”>

            <Text>CD &Key:</Text>

                  </Control>

          <Control Id=”CDKeyEdit” Type=”MaskedEdit” X=”45″ Y=”159″ Width=”250″ Height=”16″ Property=”PIDKEY” Text=”[PIDTemplate]” />

          <Control Id=”Back” Type=”PushButton” X=”180″ Y=”243″ Width=”56″ Height=”17″ Text=”&Back”>

            <Publish Event=”NewDialog” Value=”[WixUI_UserRegistrationDlgBack]”>1</Publish>

          </Control>

          <Control Id=”Next” Type=”PushButton” X=”236″ Y=”243″ Width=”56″ Height=”17″ Default=”yes”  Text=”&Next”>

            <Publish Event=”ValidateProductID” Value=”0″>1</Publish>

            <Publish Event=”SpawnWaitDialog” Value=”WaitForCostingDlg”>CostingComplete = 1</Publish>

            <Publish Event=”NewDialog” Value=”[WixUI_UserRegistrationDlgNext]”>ProductID</Publish>

          </Control>

          <Control Id=”Cancel” Type=”PushButton” X=”304″ Y=”243″ Width=”56″ Height=”17″ Cancel=”yes”  Text=”Cancel”>

            <Publish Event=”SpawnDialog” Value=”CancelDlg”>1</Publish>

          </Control>

          <Control Id=”BannerBitmap” Type=”Bitmap” X=”0″ Y=”0″ Width=”370″ Height=”44″ TabSkip=”no”  Text=”WixUI_Bmp_Banner” />

          <Control Id=”Description” Type=”Text” X=”25″ Y=”23″ Width=”280″ Height=”15″ Transparent=”yes” NoPrefix=”yes”>

            <Text>Please enter your customer information</Text>

          </Control>

          <Control Id=”BottomLine” Type=”Line” X=”0″ Y=”234″ Width=”370″ Height=”0″ />

          <Control Id=”Title” Type=”Text” X=”15″ Y=”6″ Width=”200″ Height=”15″ Transparent=”yes” NoPrefix=”yes”>

            <Text>{WixUI_Font_Title}Customer Information</Text>

          </Control>

          <Control Id=”BannerLine” Type=”Line” X=”0″ Y=”44″ Width=”370″ Height=”0″ />

        </Dialog>

  </UI>

</Fragment>

    (选自WIx tutorial

如何给本机所有用户安装桌面快捷方式和开始菜单项

<Package InstallerVersion=”200″ Compressed=”yes”  InstallScope=”perMachine”/>

InstallScope 设置为 perMachine 即可。