Friday, January 20, 2017

Candy Kid WiX Installer

Candy Kid is a simple maze chase video game written in XNA using C#/.NET. All development was done on Windows therefore it made sense to build a PC version of the game to be published available for sale.

In order to build all binary files plus game content into a single deployable package, the Windows Installer XML [WiX] toolset was used. WiX is free software that builds Windows Installer packages from XML code.

Let's check it out!

Pre Requisites
First, obtain Candy Kid release build complete with game executable, managed assemblies and content:
 Folder  Content  All game content
 File  log4net.dll  log4net logging
 File  Ninject.dll  IoC Container
 File  WindowsGame.exe.config  Game configuration
 File  WindowsGame.exe  Game executable
Next, download WiX Installer here. Note: post is based heavily on the XNA Installer published by Cygon!

Implementation
Launch Visual Studio. File | New Project... | Windows Installer XML | Setup Project | CandyKidInstaller. Uncheck Create directory for solution. Delete Product.wxs and copy the following folders as per Cygon:
 Folder  Description
 Content  Candy Kid release build (as above)
 Documents  Includes license.rtf document only
 References  Includes the 2x Nuclex.Setup DLLs
 Resources  Includes all bmp, ico, and png files
 Source  Installer (wxs) + Include (wxi) files
Note: C:\Program Files (x86)\SharpDevelop\5.1\data\resources\InstallerBitmaps required in Resources.

Actions
Right click project name | Properties | Output name: RetroCandyKid. Next, action these following tasks: Note: anytime you need a GUID choose Tools menu | Create GUID | 2. DEFINE_GUID | New GUID | Copy
  • Add the Program Menu
  • Add Desktop Shortcut
  • Add the Program Files
  • Harvest content folder

Program Menu
Add this change to Files.wxs. This blob of XML is responsible to set Program Menu entry once installed. Important: make note of the Component Id as this will be used in Setup.wxs for Feature ComponentRef.
<Directory Id='ProgramMenuFolder' Name='Programs'>
<Directory Id='MyGameProgramMenuFolder' Name='Retro Candy Kid'>
        <Component Id="StartMenuEntriesComponent" Guid="{GUID}" DiskId="1">
                <RemoveFolder Id='MyGameProgramMenuFolder' On='uninstall' />
                <RegistryValue
                        Root='HKCU'
                        Key='SOFTWARE\SteveProStudios\RetroCandyKid'
                        Name="ProgramMenuFolder"
                        Type='string'
                        Value='Installed'
                        KeyPath='yes' />
        </Component>
</Directory>
</Directory>

Desktop Shortcut
Add this change to Files.wxs. This blob of XML is responsible to set the Desktop shortcut once installed. Important: make note of the Component Id as this will be used in Setup.wxs for Feature ComponentRef.
<Directory Id="DesktopFolder" Name="Desktop">
        <Component Id="ApplicationShortcutDesktop" Guid="{GUID}">
                <Shortcut
                        Id="ApplicationDesktopShortcut"
                        Name="Retro Candy Kid"
                        WorkingDirectory="INSTALLDIR"
                        Icon="ProductIcon.ico"
                        Target="[INSTALLDIR]WindowsGame.exe" />
                <RemoveFolder Id="DesktopFolder" On="uninstall" />
                <RegistryValue
                        Root="HKCU"
                        Key='SOFTWARE\SteveProStudios\RetroCandyKid'
                        Name="DesktopFolder"
                        Type="integer"
                        Value="1"
                        KeyPath="yes" />
        </Component>
</Directory>

Program Files
Add this change to Files.wxs. This blob of XML is responsible to install the executable and all assemblies. Important: make note of the Component Id as this will be used in Setup.wxs for Feature ComponentRef.
<Directory Id="ProgramFilesFolder" Name="PFiles">
<Directory Id="INSTALLDIR" Name="RetroCandyKid">
<Component Id="MyComponent" Guid="{GUID}" DiskId="1">

<File Id="WindowsGameExe" Name="WindowsGame.exe.config"
          Source="$(sys.SOURCEFILEDIR)/../Content/WindowsGame.exe.config" />
<File Id="log4netdll" Name="log4net.dll"
          Source="$(sys.SOURCEFILEDIR)/../Content/log4net.dll" />
<File Id="NinjectDll" Name="Ninject.dll"
          Source="$(sys.SOURCEFILEDIR)/../Content/Ninject.dll" />

<File Id="GameExecutable" Name="WindowsGame.exe" KeyPath="yes"
          Source="$(sys.SOURCEFILEDIR)/../Content/WindowsGame.exe">
         <Shortcut
                Id="MyGameShortcut"
                Name="Retro Candy Kid shortcut"
                Directory="MyGameProgramMenuFolder"
                Advertise="yes"
                WorkingDirectory="INSTALLDIR"
                Icon="ProductIcon.ico" />   
</File>
</Component>
</Directory>
</Directory>

Harvest Content
In order to copy the Content directory to the install folder, use the Wix "Heat" application to harvest the directory. The Wix Harvest Tool (Heat) generates the required fragment into its own Installer (wxs) file.

First, ensure that Wix Toolset is included in Environment PATH. Control Panel | Advanced system settings. Environment Variables | Path | Edit | Add install directory: C:\Program Files (x86)\WiX Toolset v3.10\bin

Next, launch Command Prompt and harvest content from Game executable level beneath Content folder: heat dir . -o MyHarvestedStuff.wxs -scom -frag -srd -sreg -gg -cg MyComponentGroupId -dr INSTALLDIR

Find and replace in wxs file Source="SourceDir\ to Source="$(sys.SOURCEFILEDIR)\..\Content\
Finally, remove all top entries with Directory="INSTALLDIR". Make note of the ComponentGroupRef Id.


Setup.wxs
Main entry point: update Product XML blob and complete the Feature list as per the components (above). Ensure you have ProductIcon value set as Icon for shortcut and Icon displayed in Add/Remove programs!
<Product Id="{GUID}"
         Name="Retro Candy Kid"
         Language="1033"
         Version="1.0.0"
         Manufacturer="StevePro Studios"
         UpgradeCode="{GUID}">

<Property Id="ALLUSERS" Value="1" />
<Property Id='ARPPRODUCTICON' Value='ProductIcon' />

<Feature Id="MyFeature" Title="Required Files" Level="1">
        <ComponentRef Id="StartMenuEntriesComponent" />
        <ComponentRef Id="ApplicationShortcutDesktop" />
        <ComponentRef Id="MyComponent" />
        <ComponentGroupRef Id="MyComponentGroupId" />
</Feature>

<!-- Includes the user interface definition defined in another file -->
<UIRef Id="UserInterface"/>
<Icon Id="ProductIcon" SourceFile="$(sys.SOURCEFILEDIR)/../Resources/Game.ico" />
<Icon Id="ProductIcon.ico" SourceFile="$(sys.SOURCEFILEDIR)/../Resources/Game.ico" />
</Product>

UserInterface.wxs
Update the relative location for "Default dialog resources for the setup" bitmap files e.g. banner and info:
 Binary  Source
 dialog.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/default-dialog.bmp
 banner.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/default-banner.bmp
 info.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/info.bmp
 up.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/up.bmp
 new.bmp  $(sys.SOURCEFILEDIR)/../Resources/InstallerBitmaps/new.bmp

Build
Finally, build WiX Installer from within Visual Studio to generate the MSI package RetroCandyKid.MSI.
Download source code here.

Summary
Double click to RetroCandyKid.MSI to install. Ensure there is a Program Menu entry + Desktop shortcut!
Retro Candy Kid is also in Programs and Features and could be uninstalled; not that you would want to J

No comments:

Post a Comment