Wix:全称Windows Installer XML,属于微软的一个开源项目,目标是使用XML语言灵活的定制具有各种功能的安装包,需要微软的Windows Installer服务支持。
Wix生成的产品为msi文件,这种可执行文件与exe文件最大的不同为,它更底层,安装文件的同时可以对系统或者其他软件进行设置。
Language与Codepage的设
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.小于1的Feature将不会被安装。Level值为3的Feature为Typical类型,Level值大于3为Complete类型。Level也可以在安装时动态修改,使用<Condition>条件判断。例如:
<Feature Id=”DesktopFt” Title=”Desktop” Level=”1″>
<Condition Level=”0″><![CDATA[HASDESKTOP <> “1”]]></Condition>
<ComponentRef Id=”DesktopShortcutComponent”/>
</Feature>
如果HASDESKTOP属性值不为1,那么此Feature的Level将为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>
上述例子为在注册表中查找VC71的InstallDir的值,如存在将值付给VC71PATH,不存在则VC71PATH为空。
安装包的中文化
Wix默认的语言为en-us,中文化需要另外添加zh-cn或zh-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 Act
例1,安静模式下执行CMD操作
<Property Id=”QtExecCmdLine” Value=”command line to run”/>
<CustomAction Id=”QtExecExample” BinaryKey=”WixCA” DllEntry=”CAQuietExec” Execute=”immediate” Return=”check”/>
<InstallExecuteSequence>
<Custom Act
</InstallExecuteSequence>
例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 Act
<Custom Act
</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(一)
CustomAction在Wix中扮演着很重要的角色,这里讲讲它的其中一个用途——根据条件设置属性的值。
例子:
<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’ Act
<Environment Id=’SetTclLibraryPath’ Name=’TCL_LIBRARY’ Act
</Component>
自定义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” Act
Act
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中自带了FilesInUse和MsiRMFilesInUse2个错误处理的对话框
一般不需要开发人员去处理,只需要在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 工具对2份msi文件进行分析,得到两者之间的不同,整理出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更新文件。
安装程序版本控制问题
在安装程序更新时,假如product的id没有改变,则表明该安装程序不允许多个版本共存。
一般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 Act
</Control>
自定义一个安装对话框,然后使用type为text的control控件,采用一个公用属性 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 即可。