Tuesday, 1 May 2012

WiX Burn – tips/tricks

This post outlines some of the things I have found out since working with the new Burn code, unless otherwise stated this refers to version 3.6.2830.0 or later. For my requirements I have only needed to create single file installation setups, so none of these examples will include download code. I keep the source to resources in a folder called “Resource” so in the examples below "Resource\" is a reference to this folder.

In many cases this information has been gleaned from the WiX Users mail list. If you spot any errors or can suggest improvements please let me know.

Basic Template

This is my outline framework that I have been using to create a burn project:
<?xml version="1.0" encoding="utf-8"?>

<?ifndef Version?>
<?define Version = "1.0.0.0" ?>
<?endif ?>

<Wix RequiredVersion="3.6.2830.0" xmlns="http://schemas.microsoft.com/wix/2006/wi
"
     xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
  <Bundle Name="My Application" Version="$(var.Version)" Manufacturer="ACME" UpgradeCode="PUT-GUID-HERE
"
    HelpUrl="http://www.nowhere.com
"
    Copyright="Copyright© 2012, ACME" IconSourceFile="Resource\Setup.ico
"
    SplashScreenSourceFile="Resource\SplashScreen.bmp
"
    AboutUrl="http://www.nowhere.com
"
    Condition="((VersionNT >= v5.1) AND (ServicePackLevel >= 3)) OR ((VersionNT >= v5.2) AND (ServicePackLevel >= 2)) OR (VersionNT >= v6.0)">

    <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense" />
    <WixVariable Id="WixStdbaLicenseUrl" Value="" />
    <WixVariable Id="WixStdbaLogo" Value="Resource\logoSmall.png" />
    <Variable Name="InstallFolder" Type="string" Value="[ProgramFilesFolder]ACME\My App" />

    <Chain>
      <PackageGroupRef Id="Netfx4Full" />

      <RollbackBoundary />
     
      <MsiPackage
        Id="Setup
"
        Compressed="yes
"
        SourceFile="$(var.Setup.TargetPath)
"
        Vital="yes">
        <MsiProperty Name="INSTALLLOCATION" Value="[InstallFolder]" />
      </MsiPackage>
    </Chain>
  </Bundle>
</Wix
>

Notes:

  • This template reference the .Net 4 framework, for this I just copied the WiX source but set ExePackage/@Compresses=”yes” to embed the framework in my installation.
  • The Bundle/@Condition sets the install to only run on Windows XP SP3, Windows 2003 SP2 or later.
  • The WixStdbaLicenseUrl is set to an empty string to hide the license URL hyperlink as it is not require for my installation.
  • By referencing my WiX MSI setup project in the burn project I can reference the MSI using the syntax SourceFile="$(var.Setup.TargetPath)" where Setup is the name of my project.
  • The preprocessor variable for the version allows me to set the version from my build environment.

No License UI

To create an installation without a license URL link use the following:
       <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense" /> 
    <WixVariable Id="WixStdbaLicenseUrl" Value="" />

Hyperlink to local License file

If you want to have a link to local license file as part of your installation save the license file as an html document and then reference it as follows:
    <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense">
      <Payload SourceFile="Resource\License.htm" />
    </BootstrapperApplicationRef>
    <WixVariable Id="WixStdbaLicenseUrl" Value="License.htm" />

This embeds the file license.htm file within the bundle and extracts it when the installation is run, if the user clicks the hyperlink then the file is loaded in the default browser.

RichText box license dialog

To create an installation with the license displayed in a richtext control use the following:
    <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense" />
    <WixVariable Id="WixStdbaLicenseRtf" Value="Resource\License.rtf" />

Custom UI

If you want to customise the standard UIs copy them from the WiX source and reference them like this:
    <WixVariable Id="WixStdbaThemeXml" Value="Resource\HyperlinkTheme.xml" />
    <WixVariable Id="WixStdbaThemeWxl" Value="Resource\HyperlinkTheme.wxl" />

.Net Framework 3.5 SP1 Install

To install the .Net Framework v3.5 SP1 I use this:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
  <Fragment>
    <util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\Net Framework Setup\NDP\v3.5" Value="Version" Variable="Netfx35Version" />

    <PackageGroup Id="Netfx35">
      <ExePackage Id="Netfx35
"
        Cache="no
"
        Compressed="yes
"
        PerMachine="yes
"
        Permanent="yes
"
        Vital="yes
"
        Name="Redist\dotnetfx35.exe
"
        SourceFile="..\Redist\dotnetfx35.exe
"
        InstallCommand="/q /norestart /lang:ENU
"
        RepairCommand="/q /norestart /lang:ENU
"
        UninstallCommand="/q /norestart /lang:ENU
"
        InstallCondition="NOT Netfx35Version OR (Netfx35Version &lt; v3.5.30729.1)" 
        DetectCondition="Netfx35Version AND (Netfx35Version &gt;= v3.5.30729.1)">
        <ExitCode Value ="3010" Behavior="forceReboot" />
      </ExePackage>
    </PackageGroup>
  </Fragment>
</Wix
>

Signing a package

This is the approach I use (http://wix.sourceforge.net/manual-wix3/insignia.htm):

  1. insignia -ib Setup.exe -o engine.exe
  2. signtool engine.exe (extra parameters excluded for simplicity)
  3. insignia -ab engine.exe Setup.exe -o Setup.exe
  4. signtool Setup.exe

You can also use modify the wixproj to override the SignBundleEngine and SignBundle targets (sample copied from this thread http://sourceforge.net/mailarchive/message.php?msg_id=29179087):

<Target Name="SignBundleEngine">
  <Exec Command="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\signtool.exe&quot; sign /f privatekey.pfx /p mypassword /t http://timestamp.comodoca.com/authenticode &quot;@(SignBundleEngine)&quot;" />
</Target>
<Target Name="SignBundle" >
  <Exec Command="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\signtool.exe&quot; sign /f privatekey.pfx /p mypassword /t http://timestamp.comodoca.com/authenticode &quot;@(SignBundle)&quot;" />
</Target>

I found this problematic because:

  1. My certificate is not in the certificate store so I have to use signtool (as above).
  2. Signtool is not in the path or referenced via an environment variable so you have to know the path to the location of the Platform SDK you have installed and hard code it.
  3. You signing password is hard coded in the wixproj file.

Edit 07/05/2012: ARPSYSTEMCOMPONENT not required as this supplied by burn.

71 comments:

  1. Can I put feature selection via checkboxes using the theme file approach ?

    ReplyDelete
  2. You can put checkboxes on the options dialog which may help if not you have to write a custom BA. I have a csutom BA that I will publish when I have time that allows radio buttons and checkboxes on the main page.

    ReplyDelete
  3. Yes, even I think that I need a functionality of custom BA which gets all the values from a WPF UI and then proceeds with the installation. It will be great if you can post some example related to this.

    I have followed wix-users list, but couldn't progress much.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. I assume this is with the WiX BA I posted. I have seen this problem and can't always reproduce it. I'll take another look and see if I can find out why it happens.

    ReplyDelete
  7. Andy, not sure I understand your second question. Is this related to my WiX BA post rather than this one? Have you tried the Codeplex version?

    ReplyDelete
  8. Apologies - I'd just realised I'd posted on the wrong page before you replied. It is relating to the Wix Extended BA - which I downloaded at lunch today from codeplex.
    Please feel fee to delete these posts and I can post them in the correct place if it helps (sorry... too much coffee I think...)

    ReplyDelete
  9. Hi Andy, thanks for the useful tips. In your article you are defining a install folder in the BA. MSI package also contains an installation folder. How can we synchronize the two, meaning that if we change the location in BA, MSI package install folder should also be updated?

    ReplyDelete
  10. The line:
    MsiProperty Name="INSTALLLOCATION" Value="[InstallFolder]
    passes the folder to the MSI as a property.

    ReplyDelete
  11. Hi, I don't understand! How do you set the version from your build environment? Can you please explain further? Thanks!

    ReplyDelete
  12. If depends how you are doing the build but using candle directly it would be with the option -DVersion=1.2.3.4

    ReplyDelete
  13. Is it possible for BURN to read the environment variables on the target machine and pass them as property to an underlying MSI?

    ReplyDelete
  14. I am not aware of a way of doing this but you can do it in the MSI using the [%ENV] method. May be you can do the same within burn.

    ReplyDelete
  15. Thanks for the reply. I think I found the answer, short answer is we cannot use Env variables directly in burn.

    Yes I know that we can read it in MSI, but I am dealing with vendor MSI for which I am creating a wrapper. I tried using [%env] but that doesnt work in burn. THey use something called WIX burn builtin variables. These are all environment variables, but they read all that from the code (burn.sln -> engine -> variable.cpp). I am looking at this code now to see if I can add some custom env variables.

    P.S: mean while we are using registry to set the values.

    ReplyDelete
  16. Neil,
    I am a beginner with Burn and Wix and I would like to make a bundle with no Burn UI (just use the msi UI). I have not found a way to do that. Any suggestions?
    Thanks, Dan

    ReplyDelete
  17. That isn't possible and I don't really see how it could work.

    ReplyDelete
  18. can you please explain why it wont work?

    ReplyDelete
  19. Burn is typically used to install pre-reqs (e.g. .NET framework) and then run your install. The Burn UI is used to let the user decide to install and also show progress, the MSI UI would be too late in that process.

    ReplyDelete
  20. You got confused between myself and Dan. I was talking about environment variables. Please use an @ tag going forward :)

    ReplyDelete
  21. @Anonymous - why what won't work? (Don't mind using @ tag but it helps if people aren't Anonymous!)

    ReplyDelete
  22. well it was all a confusion. Ignore my earlier question.

    Does the below paragraph makes sense? Is it the right path to go forward?

    Yes I know that we can read it in MSI, but I am dealing with vendor MSI for which I am creating a wrapper. I tried using [%env] but that doesnt work in burn. THey use something called WIX burn builtin variables. These are all environment variables, but they read all that from the code (burn.sln -> engine -> variable.cpp). I am looking at this code now to see if I can add some custom env variables.

    ReplyDelete
  23. That sounds perfectly reasonable, I would suggest it would be implemented using the [%ENV] format.

    As an alternative it might be simpler to read them from the registry using a RegistrySearch.

    User Variables: HKEY_CURRENT_USER\Environment

    System Variables:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

    ReplyDelete
  24. How does one display a ProgressText/ProgressBar that shows which Package in the Chain is currently being executed?

    ReplyDelete
  25. As far as I am aware that is part of the standard BA and is displayed but above the progress bar.

    ReplyDelete
  26. Neil, any idea how I can display localized license agreements using the local URL method?

    ReplyDelete
  27. I think you need something like this <Payload Compressed="yes" Name="1031\license.rtf" SourceFile="Resources\1033\license.rtf" /> in your BootstrapperApplicationRef where the number corresponds to the language id.

    ReplyDelete
  28. Hi Neil,

    I have done the UI customizations as suggested by you. But when I added a checkbox in the Install page, I am not able to get the value of the checked state to set the Install condition for my MSI package. Is this possible?You were mentioning something about the custom BA.Can you please provide some samples?Please help.

    Thanks in advance.

    ReplyDelete
  29. I don't think this is possible with the standard BA (yet). Take a look at the my extended BA http://wixextba.codeplex.com/ there are some examples the show how to use it.

    ReplyDelete
  30. Thanks a lot Neil. It worked. :)

    ReplyDelete
  31. Hi,

    Just one more doubt..is it possible to add an intermediate UI in between the Install and the Progress page?

    ReplyDelete
  32. Not currently, although it is a common request so I may get around to making it possible.

    ReplyDelete
  33. John M. Cooper9 April 2013 at 15:54

    For the Package Group for .NET 3.5 SP1, shouldn't the .exe and two .msu's for KB959209 also be installed?

    I'm working on adding that myself now . . .

    I'll let you know . . .

    ReplyDelete
  34. Possibly but it depends what you are targeting as I think they don't apply to Win7+.

    ReplyDelete
  35. John M. Cooper9 April 2013 at 18:16

    All server stuff for my particular product. x64 Windows Server 2008 R2.

    Going to have to figure out how to do Server 2012 soon as this product definitely will be expected to deploy to it.

    Nearly done with my first draft. Got do so testing.

    ReplyDelete
  36. According to http://support.microsoft.com/kb/959209 they don't apply to 2008 R2 (or I am missing your point).

    ReplyDelete
  37. I am looking to signed the bundle . but don't know where to put target tag . can you send me an example

    ReplyDelete
  38. I am afraid it is not something I have tried.

    ReplyDelete
  39. NetFx4Full isn't a valid PackageGroupRef in WinNetFxExtension librar, and shows up as an unresolved reference.

    ReplyDelete
  40. To use one of the standard ones it should be NetFx40Redist.

    ReplyDelete
  41. For what its worth, here is my 3.5 SP1 file:



















    If you've got a convenient place to upload to, I can manage that after hours. Behind lots of firewall right now. I haven't tested it as the 300 MB+ bloat was substantial.

    ReplyDelete
  42. Hell Neil,

    thanks for the info in this article

    I've created a managed bootstrapper using WPF, the bundle installs .net 4.0 as a pre requisite before installing my .msi package, the bootstrapper reboots the system after .net installation . The problem is when i run the bootstrapper in standard user mode after .net installation the bootstrapper reboots the system , but does not resume the installation in standard user mode, however it resume if i login as an admin user.

    is there any thing that i should do so that the bootstrapper resuemes after reboot even in standard user mode.

    thanks

    ReplyDelete
  43. Does your bootstrapper require elevated rights when you start it? If so you won't be able to run it on reboot. Other than that I would suggest posting a question to wix-users.

    ReplyDelete
  44. I had to add the following to my wixproj file to sign my bundle:

    <PropertyGroup>
    <SignOutput>true</SignOutput>
    </PropertyGroup>

    ReplyDelete
  45. That is ok but doesn't work for me as I don't want to install the certificate.

    ReplyDelete
  46. It is a command line application supplied with WiX.

    ReplyDelete
  47. Hi Neil, I dont want to hardcode my signing password into wixproject, is that possible? I'm planning to do this.. i'm leaving the password argument blank. When the build happens, will signtool raise one (or perhaps two) prompts for the password when it gets called, near the end of the process?




    "signtool location"

    timestamp URL>

    “certificate_path\cert.pfx"

    $(signtool) sign /f $(signkey) /t $(timeStampServer)



    true









    ReplyDelete
  48. Yes, see above "This is the approach I use".

    ReplyDelete
  49. If there is a later version of a bundled msi installed then the installation continues. How do you stop the bundle from installing if one of the msielements do not or should not install?

    ReplyDelete
  50. I am sorry I don't really understand the question.

    ReplyDelete
  51. ----------
    If there is a later version of a bundled msi installed then the installation continues. How do you stop the bundle from installing if one of the msielements do not or should not install?
    ----------

    if you have a bundle with 3 MsiPackage elements:

    <Chain>
    <MsiPackage SourceFile="Once v1.msi" DisplayName="Once" Visible="yes" Permanent="no" Vital="yes"/>
    <MsiPackage SourceFile="Doce v1.msi" DisplayName="Doce" Visible="yes" Permanent="no" Vital="yes"/>
    <MsiPackage SourceFile="Trece v1.msi" DisplayName="Trece" Visible="yes" Permanent="no" Vital="yes"/>
    </Chain>


    but "Doce v2.msi" has (for some reason) already been installed on the machine. When the Standard Bootstrapper runs with the above setup, then the other two packages are installed but "Doce v1" is skipped.
    How do I get the installation to fail with an error message "a later version of Doce has already been installed"? Or at least warn the user instead of just continuing and apparently succeeding

    ReplyDelete
  52. I afraid I don't know, if you could detect the version of the MSI may be via a registry read then you could add a condition. Try posting on wix-users some one else may have an idea.

    ReplyDelete
  53. How Install Accept Checkbox enable/disable the Install button in the Install page of WixBalExt?

    Beekeeper

    ReplyDelete
  54. How does it work in the Install page, the Accept Checkbox enable/disable the Install button in the Install page of WixBalExt?

    In the Install page, the option selection of checkbox1, I would also like to disable the browse button1 in the Option page, how to do that?

    Thanks!

    ReplyDelete
  55. Hi Neil - Thanks for your blog. It's been incredibly useful to me.

    I'm following your instructions to sign using insignia and it all looks fine, but some of our users are having problems typical of the BA not being signed properly (Failed to extract all files from container). So I went back to the installer and tried separating out the engine with insignia, expecting to find that the engine was still signed. It wasn't. Do you know if this is normal?

    ReplyDelete
  56. Yes when you extract again the signing it lost.

    ReplyDelete
  57. Thanks a lot Neil - that was just a red herring then. I'll post a question on the Wix mailing list.

    ReplyDelete
  58. Thank you so much. I was loosing my hair and sense of humour but you saved me. I would never have guessed the insignia magic if you had not written your blog. Thanks man you rock....

    ReplyDelete
  59. Hi Neil,
    How to create a wix bootstrapper application that runs self extracting exe as an exepackage

    ReplyDelete
  60. how to create a wix bootstrapper application that runs self extracting exe as an exepackage

    http://stackoverflow.com/questions/18993268/how-to-create-a-wix-bootstrapper-application-that-runs-self-extracting-exe-as-an

    ReplyDelete
  61. Not something I have ever tried but I would think it was the same as any other exe, that is use burn and the ExePackage element. The only requirement is that is has a silent/unattended command line option.

    ReplyDelete
  62. When I'm doing that it is expecting file to be there to include in the bootstrap.
    Getting the error.
    error LGHT0103: The system cannot find the file 'SourceDir\SETUP.EXE'.

    Actually the same file is in the package.

    ReplyDelete
  63. Burn will only execute files it installs otherwise this would be a massive security hole.

    (These comments are moderated so please can you only submit once.)

    ReplyDelete
  64. Hi Neil,

    Thanks for the information shared.
    I am new to Wix and Bootstrapper.
    I have to use my msi UI generated by Wix. And instead of msi I have to give exe. So I am using Bootstrapper to create exe and add some pre-installation condition checks.

    Is it possible to use msi UI and Bootstrapper to generate exe ?

    Thanks,
    Sreelakshmi

    ReplyDelete
  65. I think it is in theory but I have never done it - I would suggest asking the question on the wix-users mail list.

    ReplyDelete
  66. Thanks to Neil Sleightholm! I got an informative post here. How I use Wix-users mail list.

    ReplyDelete
  67. Hi Neil,

    Can I have hyperlink or hypertext in bundle theme file. If end user click on the link he should be navigated to install guide for help.

    Thanks,
    Sudhakar

    ReplyDelete
  68. Hi....,
    If there is any way to show prerequisites dialog in bootstrapper msi installer
    if using WIXSTDBA we link rftlicense and hyperlinklicense other then how customized the bootstrapper UI without using WPF.?
    Please help me for this Thanks in advanced.

    ReplyDelete