Google Analytics

Tuesday, February 5, 2013

Beginning Wix 3.7 with VisualStudio 2012


Background

Our development team has been working on projects with basically a .Net flavored stack. We are creating WPF clients for services using WCF with SQL 2008 on the backend. Instead of Team Foundation Server there was an organizational decision to use the Atlassian suite of project management tools: Jira with Greenhopper, Bamboo, and Fisheye. Currently we are still using Subversion but there is some movement towards using Atlassian's Stash with Git.

We were primarily using Visual Studio Installer Setup Projects to create our installers. It was relatively simple when be started, but became more involved as we created custom actions and extended the installers. With Microsoft dropping support of the Setup projects (http://blogs.msdn.com/b/buckh/archive/2011/03/17/visual-studio-setup-projects-vdproj-will-not-ship-with-future-versions-of-vs.aspx) and a rather abrupt shift to using Visual Studio 2012 we needed to implement a Wix solution for our installers in rapid order.

The Wix tutorial (http://wix.tramontana.co.hu/tutorial) is fantastic and really quite thorough, but it only deals with building from an IDE like VisualStudio in general terms. So, I thought I'd compile what I did for walking through the tutorial using Wix 3.7 and Visual Studio 2012.

Getting Started

I'll assume you have Visual Studio 2012 and the Wix toolset (http://wixtoolset.org/ v3.7: http://wix.codeplex.com/releases/view/99514). Also you should review the tutorial. My walk-through is in no way meant to be as comprehensive as that tutorial, but rather to get one started using Wix with Visual Studio 2012. The tutorial also does a good job explaining 'candle' and 'light' and the other associated tools in the Wix toolkit. Finally, at least initially I will use the sample files from the tutorial: a simple executable, dll library, and user manual (http://wix.tramontana.co.hu/system/files/samples/SampleFirst.zip).
- The Software Package

I start by selecting File > New > Project in VS. If you have the Wix toolset installed you should see a Wix Setup Project template under Templates > Visual C# > Windows Installer XML.



I created my project with the name “WixTutorial”.
Wix has now created a Setup Project and an initial Product.wxs file.
The Product element has a wildcard “*” in the Id field. The wildcard will be turned into a random GUID at compile time. This isn’t necessarily a big deal since the recommended approach is to always to a major upgrade as opposed to minor upgrades or patches, but until I understand the upgrade process a bit better I’m replacing the wildcard with a generated GUID. By default the Id field in other elements that haveuse GUIDs as ID are defaulted to the wildcard. From what I’ve seen so far this is actually preferred even for components providing you are using the single file per component approach (http://stackoverflow.com/questions/1602831/wix-one-file-per-component-or-several-files-per-component/1604348#1604348).

While Wix adds the Language attribute to the Product (defaulted to ‘1033’ - English) it does not add the Codepage attribute, which is the character set used. I don’t know if this is simply defaulted to ‘1252’ now or is based on the Language attribute. As multi-language support is beyond the scope of this now, I’m just leaving it.

To the Package element I also add the Keywords, Description, Comments, and Manufacturer attributes as these are shown in the properties of the MSI package in Windows. The InstallerVersion is the minimum version of WindowsInstaller to be used. Wix has set this to 200 (WindowsInstaller v2.0) and I will leave this until it warrants some change. Compressed=”yes” indicates to use compressed (.cab) installer files. The InstallScope attribute is new since the tutorial. InstallScope=”perMachine” sets the installation scope for “All Users”. This can also be set to “perUser”. The “perMachine” installation will require elevated permissions to install the software.

The MajorUpgrade element tells MSI how to handle product upgrades. For now the default that Wix has in is sufficient.  I’ve added the EmbedCab=”yes” attribute to the empty MediaTemplate element that Wix created. This way my .cab files will be packaged in the .msi file. I’m not using the separate Media elements as the tutorial describes as I don’t plan to put the installer on separate media. The tutorial explains how to use this, however.

Finally Wix has added a feature element with a child ComponentGroupRef element. This differs from the tutorial, which has us create the entire directory hierarchy with the components within it. Instead Wix has created the directory structure and components within separate fragments. The tutorial explains this approach in Upgrades and Modularization > Fragments (http://wix.tramontana.co.hu/tutorial/upgrades-and-modularization/fragments), and I think it is a cleaner approach and easier to refactor common elements later. I changed the default Id and Title to fall in line with the tutorial. The Level is used to determine if the feature should be installed in a “Typical”, “Custom” or “Complete” installation. For our main feature it should be left at 1.

I also added a second ComponentGroupRef element that will refer to my shortcut files as those get installed to a different directory than our main install directory.

<Product Id="E240A99B-A6A2-41A6-A8F9-DF388EBAD98B" Name="Fubar 1.0" Language="1033"
    Version="1.0.0.0" Manufacturer="Dominion Voting Systems" UpgradeCode="585749c0-d21d-453f-bcbf-a565bbf0431d">
    <Package Keywords="Installer" Description="FUBAR Test Wix Installer"
        Comments="This is a test installer package." Manufacturer="Dominion Voting Systems" InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate EmbedCab="yes" />

    <Feature Id="Complete" Title="Fubar 1.0 Complete" Level="1">
        <ComponentGroupRef Id="ProductComponents" />
        <ComponentGroupRef Id="Shortcuts" />
    </Feature>
</Product>

The Files Inside

As described in the tutorial we lay out a hierarchical directory structure that Windows Installer will recreate upon installation. It then installs the components into the directories to which they are assigned. The top level directory has a predefined name “TARGETDIR”. The next level also uses a predefined name “ProgramFilesFolder” to indicate to MSI to install to the Windows Program Files directory. (A complete list of predefined names is here: http://kb.flexerasoftware.com/selfservice/viewContent.do?externalID=Q105880) . Finally we have an “INSTALLFOLDER” directory. This is not a predefined directory. INSTALLFOLDER is the ID that we will use to refer to the directory when assigning components. The Name attribute of the Directory is the name the directory will have in Windows.
We are also going to reference two more directories that use the Installer’s predefined names in order to place our shortcuts: the ProgramMenuFolder and the DesktopFolder, which reference the start menu Programs menu and the Desktop respectively. Within the ProgramMenuFolder we create our own directory for our application called “Fubar 1.0”.

<Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
        <Directory Id="ProgramFilesFolder">
            <Directory Id="INSTALLFOLDER" Name="WixTutorial" />
        </Directory>
        <Directory Id="ProgramMenuFolder" Name="Programs">
            <Directory Id="ProgramMenuDir" Name="Fubar 1.0" />
        </Directory>
        <Directory Id="DesktopFolder" Name="Desktop" />
    </Directory>
</Fragment>
The nesting indicates our hierarchy. This fragment tells the installer to create one directory named “WixTutorial” inside of our Program Files directory. This is usually C:\Program Files (x86). Note that Wix will not create directories with no components. However, the tutorial explains using the CreateFolder element in a component to create an empty directory (http://wix.tramontana.co.hu/tutorial/com-expression-syntax-miscellanea/creating-directories).

The second fragment that Wix provided describes our software components. The tutorial describes the component as the “atomic level” of thing to be installed. I think it’s probably more correct to think of it as the “molecular level” as a component can be composed of several VERY STRONGLY RELATED things, those things being files, registry keys, and shortcuts. However, as I mentioned before, it’s probably best to only have a single file in any given component. Only one file can be assigned the “KeyPath” attribute, the path that MSI will look at to determine if the entire component is installed. If the user accidentally deletes an installed file that is not the KeyPath file while leaving the component’s KeyPath file intact, that related file will not be restored by a “Repair” or even minor update.

The components are contained in a ComponentGroup element. This is a better way to put related files together without sticking them in the same component. Here we associated the ComponentGroup feature with the INSTALLFOLDER directory above meaning the components of the group will be installed to the “WixTutorial” directory. As directed, we’ll delete the comments that Wix put in and add our three file components to this group.

The first component is our main executable, FoobarAppl10.exe (I copied this along with the other components from the sample file download to my VS solution’s directory.) along with a Program Files shortcut and desktop shortcut. You’ll notice that I did not give the Component a GUID Id. As long as there is only a single file in the Component that GUID will be generated by the compiler. Each Component should have a unique string Id, however. I did not add a KeyPath=”yes” attribute to the file element either. The KeyPath will default to the single file within the component. Finally, I don’t have the  the DiskId attribute that the tutorial includes as that relates to the Media element that I chose to ignore for now.
For each File element there is a Name attribute. This is the name that the file will have when installed. The Source of the File, meaning the path to file to be packaged in the installer package, will default to this Name attribute. Since all three components are in the same directory as the Wix package I can just leave off the Source attribute.

The FoobarEXE file has two shortcuts as children. These shortcuts will be installed to the Program File directory and Desktop directory that we referenced when we set up the directory structure. Since they are children of the executable file, that file is automatically their target. The Icon attribute references the name of the Icon element to use as the shortcut. This name must have the same extension as the file that the shortcut points to. That Icon element (which I will add in a minute) can have the EXE as a source and the EXE can have multiple ICO files embedded within it. So you can add an IconIndex as the tutorial shows, but our executable has one generic icon and the index defaults to 0 (I believe). Finally Shortcuts can be advertised or normal Windows shortcuts. A normal windows shortcut just points to a file path and command and those can be changed by the user. An advertised shortcut is essentially more closely bound to the file. The link to it cannot be changed and if the shortcut cannot find the file it targets the installer will try and repair the installation and reinstall the targeted file.

We’ll add two more components the HelperLibrary and the instruction manual. The Manual also has a shortcut. This one has no icon so will just show up in our Program Files menu with a generic icon and the name “Fubar Instructions”.

I’ve added another ComponentGroup that we referenced above, the Shortcuts components. This component includes a RemoveFolder element and a RegistryValue element.  RemoveFolder is an element that you want to include if your application creates any directories that you want to clean up when a user uninstalls the application. Even though the installer is creating our ProgramMenuDir directory to hold our Program Files shortcuts, the compiler will fail unless we specifically tell it to clean up this directory on uninstall. My assumption is that because shortcuts are specific to the user profile that it needs to clean those up in a user-by-user basis. Thus we add a registry key for the current user that will be used as the keyPath to see if that program menu directory has been installed.

<Fragment>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
        <Component Id="MainExecutable">
            <File Id='FoobarEXE' Name='FoobarAppl10.exe'>
                <Shortcut Id='startmenuFoobar10' Directory='ProgramMenuDir' Name='FUBAR Tutorial 1.0' WorkingDirectory='INSTALLDIR' Icon='FoobarIcon.exe' Advertise='yes' />
                <Shortcut Id='desktopFoobar10' Directory='DesktopFolder' Name='FUBAR Tutorial 1.0' WorkingDirectory='INSTALLDIR' Icon='FoobarIcon.exe' Advertise='yes' />
            </File>
        </Component>
        <Component Id='HelperLibrary'>
            <File Id='HelperDLL' Name='Helper.dll' />
        </Component>
        <Component Id='Manual'>
            <File Id='Manual' Name='Manual.pdf'>
                <Shortcut Id='startmenuManual' Directory='ProgramMenuDir' Name='Fubar Instructions' Advertise='yes' />
            </File>
        </Component>
    </ComponentGroup>
    <ComponentGroup Id='Shortcuts' Directory='ProgramMenuDir'>
        <Component Id="ProgramMenuShortcut">
            <RemoveFolder Id='ProgramMenuDir' On='uninstall' />
            <RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]' Type='string' Value='' KeyPath='yes' />
        </Component>
    </ComponentGroup>
</Fragment>
The final fragment to our file defines our Icon source for the executable. While the Id must have the same extension as the file that the shortcuts target, it does not have to have the same name as the file itself.

<Fragment>
    <Icon Id="FoobarIcon.exe" SourceFile="FoobarAppl10.exe" />
</Fragment>

Putting It To Use

At this point you can right-click on the project in Solution Explorer and do Build. Wix will ‘candle’ (compile) and ‘light’ (link) the appropriate files. If you go to the Project Folder and then bin > Debug you should have a new msi file. If you install this you will see the Installer fire up, show some progress and voila! Your application is installed.

If you go to your Program Files (x86) folder you should see the WixTutorial directory (or whatever you named your INSTALLFOLDER) and under it should be the three component files. In your start menu > All Programs you should see the “Fubar 1.0” (or whatever you named ProgramMenuDir) and under that the two shortcuts for the executable and instructions. Finally on your desktop should be an Icon for the executable.

You can remove the application either through the Control Panel or by right-clicking on the .msi and clicking uninstall. Uninstalling should remove all the files, directories, and shortcuts.

To Be Continued

In near-future posts I plan on walking through the User Interface, Events and Actions (which includes Custom Actions), and the SQL  sections of the tutorial. I do want to learn more about Upgrades and Localization and will post about that when those things become pertinent to what we are doing. I also want to look at creating both Web and Windows services and probably user creation in conjunction with that.

10 comments:

Will Ellis said...

Nice little intro to using Wix. Thanks.
The only other thing that may have added some value was a quick mention of project references and variables:
http://wix.sourceforge.net/manual-wix3/votive_project_references.htm

Ben Rice said...

Good point. Thanks for adding that reference.

Anonymous said...

Thanks for this, this was a great "cliff notes" version.
One question.... your InstallScope is per machine. Shouldn't this mean your registryvalue root refer to HKLM?

Anonymous said...

Nice tutorial, thanks for sharing.

Anonymous said...

Please help me about how to check product version and .NET framework and please describle about user32.dll in check version. Thank you so much.

Best Regards,
Thuan
thuanpq78@yahoo.com

Unknown said...

Hi, nice description.Thanks for your help..

-Aparna
Theosoft

Kiquenet said...

Great mister.

It would be interesting to be continued in near-future posts walking through the User Interface, Events and Actions (Custom Actions).

Maybe soon near-future posts?

Ariel Illouz said...

Nice tutorial, Thanks. I've tried to create new installer and notice that Repair wont update my exe file. What i'm missing ? here is my wxs file https://drive.google.com/file/d/0B8nKPU4xJkD3UHNSQlhNUEZJUDQ/edit?usp=sharing

Anonymous said...

Very good getting started guide. Helped enormously

Anonymous said...

great guide - very well done - i will check out what else wix related you have

thank yu