Wednesday 3 October 2012

WiX Bootstrapper Application

EDIT: This code has been updated and is now available here http://wixextba.codeplex.com/.
I have been working with the new WiX bootstrapper applications and have created my own version based heavily on the standard BA.
This version has the following enhancements over the standard code:
  • Resized HyperlinkLicense and RtfLicense so they look the same as the default WiX UI – this is useful if you need to show an MSI internal UI.
  • Add welcome message to HyperlinkLicense install page.
  • Add support for Radio buttons on the option and install pages.
  • Add support for checkboxes on the install page (they are already supported on the options page).
  • Add support for second directory folder on the option page.
  • Add example HyperlinkTheme that supports a larger logo on the install page (see images below).
  • Add example textbox on the options page.
  • Added install version number to HyperlinkLicense install page.
  • Reformat the RtfLicense to have flat licence textbox.

Download

The source for this can be downloaded here. To use it add a reference to WixBalExtensionExt.dll (in the build folder) and add the following code to you bundle:
<BootstrapperApplicationRef Id="WixExtendedBootstrapperApplication.HyperlinkLicense" />
The code should build on any machine with Visual Studio 2010 and WiX 3.6 installed. The extended BA has been renamed to use Ext or Extended in place of Std or Standard but I have kept the filenames the same so it is easier to merge changes from the WiX standard BA.

Examples

See folder “Test” in the download for examples of using this BA.
image
image
image

Tuesday 1 May 2012

Burn UI Customisations

I have written a couple of WiX burn UI customisations and thought they were worth sharing. They are both based on the standard WiX burn templates and can be easily implemented as mentioned in my previous post http://neilsleightholm.blogspot.co.uk/2012/05/wix-burn-tipstricks.html.

HyperlinkLicense

I changed this to include the following features:
  1. Resized to match standard WiX UIs.
  2. Add welcome text
  3. Display version number.
image

The relevant bits of code to do this is shown below, all other code it the same as the standard UI:

<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
    <Window Width="500" Height="390" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>


    <Page Name="Install">
        <Text X="11" Y="80" Width="-11" Height="30" FontId="2">#(loc.InstallHeader)</Text>
        <Text X="11" Y="121" Width="-11" Height="-129" FontId="3">#(loc.InstallMessage)</Text>
        <Hypertext Name="EulaHyperlink" X="11" Y="-107" Width="-11" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallLicenseLinkText)</Hypertext>
        <Text X="11" Y="-73" Width="246" Height="17" FontId="3">#(loc.InstallVersion)</Text>
        <Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="246" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
        <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.InstallOptionsButton)</Button>
        <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
        <Button Name="WelcomeCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
    </Page>

This also requires the addition of a few items in the HyperlinkTheme.wxl file:

  <String Id="InstallHeader">Welcome</String>
  <String Id="InstallMessage">Setup will install [WixBundleName] on your computer. Click install to continue, options to set the install directory or Close to exit.</String>
  <String Id="InstallVersion">Version [WixBundleVersion]</String>

RtfLicense

I changed this to include the following features:
  1. Resized to match standard WiX UIs.
  2. Change odd looking 3D outline to a single line.
image

The relevant bits of code to do this is shown below, all other code it the same as the standard UI:

    <Page Name="Install">
        <Text X="11" Y="80" Width="-11" Height="-70" TabStop="no" FontId="2" HexStyle="0x800000" />
        <Richedit Name="EulaRichedit" X="12" Y="81" Width="-12" Height="-71" TabStop="yes" FontId="0" />
        <Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="246" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
        <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.InstallOptionsButton)</Button>
        <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
        <Button Name="WelcomeCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
    </Page>

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.

Wednesday 20 July 2011

VB6: Internal error during Pass2

Very occasionally something will change in one of my VB projects (yes I still use VB) and it will stop compiling and display an error similar to this:

Unexpected error occurred in code generator or linker. 
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

modCommon.OBJ : error : Internal error during Pass2

  ExceptionCode            = C0000005
  ExceptionFlags           = 00000000
  ExceptionAddress         = 10323E93
  NumberParameters         = 00000002
  ExceptionInformation[ 0] = 00000000
  ExceptionInformation[ 1] = 00842000

CONTEXT:
  Eax    = 00842000  Esp    = 0012EFAC
  Ebx    = 007D6008  Ebp    = 0012EFFC
  Ecx    = 00000001  Esi    = 0012EFC4
  Edx    = 00001000  Edi    = 007D6008
  Eip    = 10323E93  EFlags = 00010246
  SegCs  = 0000001B  SegDs  = 00000023
  SegSs  = 00000023  SegEs  = 00000023
  SegFs  = 0000003B  SegGs  = 00000000
  Dr0    = 0012EFAC  Dr3    = 007D6008
  Dr1    = 0012EFFC  Dr6    = 00000001
  Dr2    = 00000000  Dr7    = 00000000

I don’t know what causes this but I do know a simple fix, just re-order the file references. What I do is open the VBP file in a text editor and then sort the Class, Form, Module and UserControl values in to alphabetical order.

Sunday 3 October 2010

Silverlight 4 Tools Install Problem

I have been struggling to get the Silverlight 4 Tools for Visual Studio 2010 working on my laptop and I think I have found a solution.

The problem: you install the tools and the install (“Silverlight_tools.exe”) doesn’t report an errors. When you open a Silverlight 4 project Visual Studio tells you that you don’t have the tools installed.

Solution: uninstall “Microsoft Silverlight” i.e. the end user runtime and then re-install “Silverlight_tools.exe”. I would also suggest running Windows Update and letting it install the “Microsoft Silverlight” patch.

Additional information: Although “Silverlight_tools.exe” doesn’t report a problem buried in the logs it does says “silverlight_developer.exe” has failed. If you expand “Silverlight_tools.exe” (using WinZip or with the /createlayout option) and manually run “silverlight_developer.exe” it reports that a later version of Silverlight is installed. It seems that “silverlight_developer.exe” is installing “Microsoft Silverlight” but doesn’t support installing over the newer version.

Tuesday 28 September 2010

Building SilverLight 4 Applications without Visual Studio 2010

On my build machines I prefer not to install Visual Studio and just rely on the .Net framework which includes all the tools required to run a build. Unfortunately the SilverLight 4 tools have been released so that they will only install on a machine with Visual Studio 2010 installed. I hunted around for a solution to this but didn’t find anything, then I realised that the file Silverlight4_Tools.exe could be extracted and you can install just the SDK as follows:

  1. Download the SilverLight 4 tools (Silverlight4_Tools.exe).
  2. Extract the files silverlight_sdk.msi and silverlight_sdk.cab either by using WinZip or running Silverlight4_Tools.exe with the /createlayout command line.
  3. Run silverlight_sdk.msi on your build machine.

So far this is working for me but I may need to install some of the other tools at a later stage.

Tuesday 29 June 2010

WiX Reg File Heat Extension

WiX v2 had the tallow tool which was able to harvest a WiX fragment from a file exported from the registry (reg file). WiX v3’s replacement for this tool, Heat, lost this functionality. The code presented here adds this back as an extension to Heat. It also gives an example of how to write a custom heat extension.

You can download v0.90 of the extension from here and the source here. The extension has been built against the WiX v3.0 assemblies but works with Heat from both v3.0 and v3.5.

Using the extension

To create a basic fragment run:
        heat regfile filename.reg –ext Wix.RegFileHeatExtension.dll –out regfile.wxs

To create a more useful fragment run:
        heat regfile filename.reg –ext Wix.RegFileHeatExtension.dll –out regfile.wxs -gg -g1 -indent 2 -cg compGroup
This creates a fragment that can be referenced via the “compGroup” ComponentGroupRef/@Id element. It will also have automatically generated guids, for more information on the command line see the Heat documentation.

It should be noted that due to limitations in Windows Installer the following registry keys are not harvested by this extension:

  • REG_NONE(0), REG_LINK(6), REG_RESOURCE_LIST(8), REG_FULL_RESOURCE_DESCRIPTOR(9), REG_RESOURCE_REQUIREMENTS_LIST(a), REG_QWORD(b).
  • These will all start hex(n) in the reg file where “n” is the number/letter in brackets above.

I am hoping to get this functionality added to the WiX v3.5 core Heat command.

I hope you find this useful, if you find any problems with harvesting registry files please let me know.

Edit 04/08/10: Update to support WiX 3.0 properly.

Edit 16/12/10: This feature is now built in to WiX 3.5, see help file for details.

Wednesday 19 August 2009

Registration Free COM

From Windows XP SP2 Microsoft introduced a feature called RegFree COM, which allows you to call COM objects (yes some of us still use COM) without needing to register them first. The object in question must be in the same folder as the caller but this makes it much easier to install these objects and goes a little way to the xcopy distribution utopia. To use RegFree COM your caller and callee assemblies needs to have manifest files either externally or embedded - Manifest Files Reference. The assemblies can be written in any language that supports COM and you can call between languages, e.g. vb to vb, vb to .Net, .Net to vb.

The calling application needs a manifest file configured as follows, in this example the application is called MyApp.exe so the manifest is MyApp.exe.manifest:

<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="MyApp" version="0.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="ComAssembly.dll" version="1.2.3.4" />
</dependentAssembly>
</dependency>
</assembly>

The COM assembly needs a manifest file configured as follows, in this example the assembly is called ComAssembly.dll so the manifest is ComAssembly.dll.manifest:

<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="ComAssembly.dll" version="1.2.3.4" />
<file name="ComAssembly.dll">
<comClass clsid="{11111111-2222-3333-4444-555555555555}" threadingModel="Both" />
</file>
</assembly>

In MyApp.exe.manifest I have set the version to “0.0.0.0” this should really match the application version but “0.0.0.0” works. The dependentAssembly/assemblyIdentity  can be repeated for as many COM dependencies that you have.

The assemblyIdentity in the caller manifest must match exactly the one in the callee.

Getting this right can be quite difficult to debug, on XP the only clues to problems are written to the system eventlog with the source SideBySide. On Vista (and I assume Windows 7 and Windows Server 2008 although I haven’t tried it) you can use SxsTrace to help debug the problem. To start trace run “SxsTrace Trace -logfile:SxsTrace.etl” to convert the log file to something you can view run “SxsTrace Parse -logfile:SxsTrace.etl -outfile:SxsTrace.txt”.

The two manifest files presented here have been reduced to the minimum required to get the code to work, they are more settings that can be included see the Manifest Files Reference for more details.

See also:

Tuesday 6 January 2009

WiX Script for Major Upgrades

On the WiX mailing list recently there have been several requests for information about upgrades, this post presents a very basic script that has all the elements necessary to handle a major upgrade.

<?xml version="1.0" encoding="UTF-8"?>
<!--
Simple WiX template - This example installs a file in to a directory.
-->

<!-- This is application version number, update for each release -->
<?define Version = "1.0.0" ?>
<?define UpgradeCode = "2CFB7959-56C1-4968-94DB-A8FA212B0FA2" ?>

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="Simple WiX template $(var.Version)" Language="1033"
Version="$(var.Version)" Manufacturer="ACME Corporation"
UpgradeCode="$(var.UpgradeCode)">
<Package Description="Simple WiX template Installation" InstallerVersion="200" Compressed="yes" />

<Condition Message="A later version of [ProductName] is already installed.">NOT NEWERVERSIONDETECTED</Condition>

<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLDIR" />
</Directory>

<Feature Id="DefaultFeature" Level="1" ConfigurableDirectory="TARGETDIR">
<ComponentGroupRef Id="Test" />
</Feature>

<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Minimum="$(var.Version)" OnlyDetect="yes" Property="NEWERVERSIONDETECTED" />
<UpgradeVersion Minimum="0.0.0" Maximum="$(var.Version)"
IncludeMinimum="yes" IncludeMaximum="no"
Property="OLDERVERSIONBEINGUPGRADED" />
</Upgrade>

<Media Id="1" Cabinet="contents.cab" EmbedCab="yes" />

<UIRef Id="WixUI_ErrorProgressText" />

<InstallExecuteSequence>
<FindRelatedProducts Before="LaunchConditions" />
<RemoveExistingProducts After="InstallValidate" />
</InstallExecuteSequence>

<InstallUISequence>
<FindRelatedProducts Before="LaunchConditions" />
</InstallUISequence>
</Product>
</Wix>

For information on the FindRelatedProducts scheduling see here: LaunchConditions, FindRelatedProducts and Downgrades.

Useful links:
Patching and Upgrades
Paying for upgrades