我们已经使用WiX有一段时间了,尽管人们对它的易用性有一些抱怨,但它运行得相当不错。我想要的是有用的建议:

设置WiX项目(布局、引用、文件模式) 将WiX集成到解决方案中,并构建/发布流程 为新的安装和升级配置安装程序 任何你想分享的好的WiX技巧


当前回答

奇妙的问题。我希望看到一些最佳实践的展示。

我有很多要分发的文件,所以我将项目设置为几个wxs源文件。

我有一个顶级源文件,我称之为产品。WXS,它主要包含用于安装的结构,但不包含实际的组件。这个文件有几个部分:

<Product ...>
  <Package ...>
    <Media>... 
   <Condition>s ...
   <Upgrade ..>
   <Directory> 
        ...
   </Directory>
   <Feature>
      <ComponentGroupRef ... > A bunch of these that
   </Feature>
   <UI ...>
   <Property...>
   <Custom Actions...>
   <Install Sequences....
  </Package>
</Product>

其余的.wix文件由包含在Product.wxs的Feature标签中引用的componentgroup的片段组成。我的项目包含我分发的文件的一个很好的逻辑分组

<Fragment>
   <ComponentGroup>
     <ComponentRef>
     ....
    </ComponentGroup>
    <DirectoryRef>
      <Component... for each file
      .... 
    </DirectoryRef>
</Fragment>

这并不完美,我的OO蜘蛛感觉有点刺痛,因为片段必须引用产品中的名称。wxs文件(例如DirectoryRef),但我发现维护一个大的源文件更容易。

我很想听到关于这一点的评论,或者如果有人有任何好的建议!

其他回答

包括COM对象:

Heat生成所有(如果不是全部)注册表项和它们所需的其他配置。喜乐!

包括托管COM对象(又名。net或c# COM对象)

在托管COM对象上使用heat将为您提供一个几乎完整的wix文档。

If you don't need the library available in the GAC (ie, globally available: MOST of the time you do not need this with your .NET assemblies anyway - you've probably done something wrong at this point if it's not intended to be a shared library) you will want to make sure to update the CodeBase registry key to be set to [#ComponentName]. If you ARE planning on installing it to the GAC (eg, you've made some new awesome common library that everyone will want to use) you must remove this entry, and add two new attributes to the File element: Assembly and KeyPath. Assembly should be set to ".net" and KeyPath should be set to "yes".

然而,某些环境(特别是带有托管内存的环境,如脚本语言)也需要访问Typelib。确保在你的打字单上运行热度并包括它。Heat将生成所有需要的注册表项。多酷啊!

Keep variables in a separate wxi include file. Enables re-use, variables are faster to find and (if needed) allows for easier manipulation by an external tool. Define Platform variables for x86 and x64 builds <!-- Product name as you want it to appear in Add/Remove Programs--> <?if $(var.Platform) = x64 ?> <?define ProductName = "Product Name (64 bit)" ?> <?define Win64 = "yes" ?> <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?> <?else ?> <?define ProductName = "Product Name" ?> <?define Win64 = "no" ?> <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?> <?endif ?> Store the installation location in the registry, enabling upgrades to find the correct location. For example, if a user sets custom install directory. <Property Id="INSTALLLOCATION"> <RegistrySearch Id="RegistrySearch" Type="raw" Root="HKLM" Win64="$(var.Win64)" Key="Software\Company\Product" Name="InstallLocation" /> </Property> Note: WiX guru Rob Mensching has posted an excellent blog entry which goes into more detail and fixes an edge case when properties are set from the command line. Examples using 1. 2. and 3. <?include $(sys.CURRENTDIR)\Config.wxi?> <Product ... > <Package InstallerVersion="200" InstallPrivileges="elevated" InstallScope="perMachine" Platform="$(var.Platform)" Compressed="yes" Description="$(var.ProductName)" /> and <Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="$(var.PlatformProgramFilesFolder)"> <Directory Id="INSTALLLOCATION" Name="$(var.InstallName)"> The simplest approach is always do major upgrades, since it allows both new installs and upgrades in the single MSI. UpgradeCode is fixed to a unique Guid and will never change, unless we don't want to upgrade existing product. Note: In WiX 3.5 there is a new MajorUpgrade element which makes life even easier! Creating an icon in Add/Remove Programs <Icon Id="Company.ico" SourceFile="..\Tools\Company\Images\Company.ico" /> <Property Id="ARPPRODUCTICON" Value="Company.ico" /> <Property Id="ARPHELPLINK" Value="http://www.example.com/" /> On release builds we version our installers, copying the msi file to a deployment directory. An example of this using a wixproj target called from AfterBuild target: <Target Name="CopyToDeploy" Condition="'$(Configuration)' == 'Release'"> <!-- Note we append AssemblyFileVersion, changing MSI file name only works with Major Upgrades --> <Copy SourceFiles="$(OutputPath)$(OutputName).msi" DestinationFiles="..\Deploy\Setup\$(OutputName) $(AssemblyFileVersion)_$(Platform).msi" /> </Target> Use heat to harvest files with wildcard (*) Guid. Useful if you want to reuse WXS files across multiple projects (see my answer on multiple versions of the same product). For example, this batch file automatically harvests RoboHelp output. @echo off robocopy ..\WebHelp "%TEMP%\WebHelpTemp\WebHelp" /E /NP /PURGE /XD .svn "%WIX%bin\heat" dir "%TEMP%\WebHelp" -nologo -sfrag -suid -ag -srd -dir WebHelp -out WebHelp.wxs -cg WebHelpComponent -dr INSTALLLOCATION -var var.WebDeploySourceDir There's a bit going on, robocopy is stripping out Subversion working copy metadata before harvesting; the -dr root directory reference is set to our installation location rather than default TARGETDIR; -var is used to create a variable to specify the source directory (web deployment output). Easy way to include the product version in the welcome dialog title by using Strings.wxl for localization. (Credit: saschabeaumont. Added as this great tip is hidden in a comment) <WixLocalization Culture="en-US" xmlns="http://schemas.microsoft.com/wix/2006/localization"> <String Id="WelcomeDlgTitle">{\WixUI_Font_Bigger}Welcome to the [ProductName] [ProductVersion] Setup Wizard</String> </WixLocalization> Save yourself some pain and follow Wim Coehen's advice of one component per file. This also allows you to leave out (or wild-card *) the component GUID. Rob Mensching has a neat way to quickly track down problems in MSI log files by searching for value 3. Note the comments regarding internationalization. When adding conditional features, it's more intuitive to set the default feature level to 0 (disabled) and then set the condition level to your desired value. If you set the default feature level >= 1, the condition level has to be 0 to disable it, meaning the condition logic has to be the opposite to what you'd expect, which can be confusing :) <Feature Id="NewInstallFeature" Level="0" Description="New installation feature" Absent="allow"> <Condition Level="1">NOT UPGRADEFOUND</Condition> </Feature> <Feature Id="UpgradeFeature" Level="0" Description="Upgrade feature" Absent="allow"> <Condition Level="1">UPGRADEFOUND</Condition> </Feature>

使用RobM特殊的“记住属性”模式

http://robmensching.com/blog/posts/2010/5/2/The-WiX-toolsets-Remember-Property-pattern

修复ProgressDlg,使其正确显示。

我将安装程序的字体大小从8增加到10,以使字体在高分辨率显示器上更人性化、更实用。我用这个XML魔法做到这一点:

<UI Id="MyCustomUI">
  <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="10" />
  <TextStyle Id="WixUI_Font_Big"    FaceName="Tahoma" Size="12" />
  <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="14" />
  <TextStyle Id="WixUI_Font_Title"  FaceName="Tahoma" Size="12" Bold="yes" />

  <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
</UI>

但这意味着ProgressDlg将无法正常显示。这是一个显示安装进度的程序,就在最后。ActionText被剪切,因此g和j等字母的下移不显示。在后处理Javascript中,通过调整Progressdialog中各种控件的大小和位置来解决这个问题。生成MSI后运行这个脚本:

var msiOpenDatabaseModeTransact = 1;
var filespec = WScript.Arguments(0);
var installer = new ActiveXObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

// The text on the exit dialog is too close to the title.  This 
// step moves the text down from Y=70 to Y=90, about one line. 
sql = "UPDATE `Control` SET `Control`.`Y` = '90' " +
    "WHERE `Control`.`Dialog_`='ExitDialog' AND `Control`.`Control`='Description'";
view = database.OpenView(sql);
view.Execute();
view.Close();

// The progressbar is too close to the status text on the Progress dialog. 
// This step moves the progressbar down from Y=115 to Y=118, about 1/3 line. 
sql = "UPDATE `Control` SET `Control`.`Y` = '118' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='ProgressBar'";
view = database.OpenView(sql);
view.Execute();
view.Close();

// The StatusLabel and ActionText controls are too short on the Progress dialog,
// which means the bottom of the text is cut off.  This step
// increases the height from 10 to 16.
sql = "UPDATE `Control` SET `Control`.`Height` = '16' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='StatusLabel'";
view = database.OpenView(sql);
view.Execute();
view.Close();
sql = "UPDATE `Control` SET `Control`.`Height` = '16' " +
    "WHERE `Control`.`Dialog_`='ProgressDlg' AND `Control`.`Control`='ActionText'";
view = database.OpenView(sql);
view.Execute();
view.Close();

database.Commit();

当安装不允许卸载或重新安装且不能回滚时,执行强制重新安装。 VBscript脚本,用于覆盖一个没有卸载的安装。

Dim objShell
set objShell = wscript.createObject("wscript.shell")

iReturn = objShell.Run("CMD /K MsiExec.exe /I ""C:\Users\TheUser\Documents\Visual Studio 2010\Projects\InstallationTarget\HelloInstaller\bin\Debug\HelloInstaller.msi"" REINSTALLMODE=vomus REINSTALL=ALL",,True)