Sunday, August 19, 2012

Working WiX project sample with before uninstall and after install custom actions

This is a sample WiX configuration file for a setup project, that will install an application that knows how to handle the command line argument cleanUpUserData. After the install is done, will automatically start the application. Before uninstall will run the application with the argument that will clear the user data.

The referenced project have [assembly: AssemblyVersion("1.0.*")] (but is not a must). Take care of builds made in the same day (have the same version build number but different revision. Using this configuration file, the MSI product version will be taken from the installed exe assembly version. The configuration file will generate a MSI that will not upgrade, but will install side by side all the install files having identical major, minor and build numbers but with different revision numbers).

The setup project have references to:
   - above mentioned referenced project
   - WixNetFxExtension
   - WixUIExtension
   - WixUtilExtension

The wix file:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <?define Product_Name="MyProductName"?>
  <?define Product_Manufacturer="MyManufacturerName"?>
  <?define Product_Name_Short="MyProductName"?>
  <?define Product_Manufacturer_Short="MyManufacturerShortName"?>
  <?define MainExeID="MainExeID"?>
  <!--<?define Product_Version=!(bind.fileVersion.$(var.MainExeID))?>-->
  <?define Product_Version=!(bind.assemblyVersion.$(var.MainExeID))?>
  <?define SetupResourcesDir=$(var.SolutionDir)MySetupProjectName\Resources\?>

  <Product Id="*" Name="$(var.Product_Name)" Version="$(var.Product_Version)" Manufacturer="$(var.Product_Manufacturer)"
           Language="1033"
           UpgradeCode="02b3a042-923f-4db6-bc4b-5cb2717f4fb6">

    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
    
    <!--Check for .Net Framework 3.5 SP 1-->
    <PropertyRef Id='NETFRAMEWORK35'/>
    <PropertyRef Id='NETFRAMEWORK35_SP_LEVEL'/>
    <Condition Message="This application requires .NET Framework 3.5 SP1. Please install the .NET Framework then run this installer again.">
      <![CDATA[Installed OR (NETFRAMEWORK35_SP_LEVEL and NOT NETFRAMEWORK35_SP_LEVEL = "#0")]]>
    </Condition>

    <MajorUpgrade DowngradeErrorMessage="A newer version of $(var.Product_Name) is already installed." 
                  Schedule="afterInstallValidate"
                  />
    
    <MediaTemplate />

    <Feature Id="ProductFeature" Title="$(var.Product_Name) Setup" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
    </Feature>
   
    <!--Icon must be 16x16-->
    <Icon Id="AddRemoveProgramsIcon" SourceFile="$(var.SetupResourcesDir)network.ico"/>
    <Property Id="ARPPRODUCTICON" Value="AddRemoveProgramsIcon" />
    <Property Id="ARPHELPLINK" Value="http://www.alarma.ro" />

    <InstallExecuteSequence>
      <Custom Action="CleanUpUserData" After="InstallInitialize">Installed AND NOT UPGRADINGPRODUCTCODE AND NOT REINSTALL</Custom>
      <Custom Action="LaunchApplication" Before="InstallFinalize" >UPGRADINGPRODUCTCODE OR REINSTALL OR NOT Installed</Custom>
    </InstallExecuteSequence>

  </Product>

  <Fragment>
    <CustomAction Id="CleanUpUserData" FileKey="$(var.MainExeID)" ExeCommand="cleanUpUserData" Execute="immediate" Impersonate="yes" Return="ignore"/>
    <CustomAction Id="LaunchApplication" FileKey="$(var.MainExeID)" ExeCommand="mustBeSomethingOrTheUpdateWillFailWithError2753" Execute="commit" Impersonate="yes" Return="asyncNoWait"/>
  </Fragment>
  
  <!--Directory general structure-->
  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <!--Program Files-->
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLFOLDER" Name="$(var.Product_Name)" />
      </Directory>
      <!--Startup Programs Menu-->
      <Directory Id="ProgramMenuFolder" Name="Programs">
        <Directory Id="ProgramMenuDir" Name="$(var.Product_Manufacturer)">
          <Component Id="ProgramMenuDir" Guid="2986B6B8-783B-45A2-AB09-BDF61B8C49F7" >
            <Shortcut Id="UninstallProduct"
                      Name="Uninstall $(var.Product_Name)"
                      Target="[SystemFolder]msiexec.exe"
                      Arguments="/x [ProductCode]"
                      Description="Uninstalls $(var.Product_Name)" />
            <RemoveFolder Id='ProgramMenuDir' On='uninstall' />
            <RegistryValue Root='HKCU' Key='Software\$(var.Product_Manufacturer_Short)\$(var.Product_Name_Short)' Type='string' Value='' KeyPath='yes' />
          </Component>
        </Directory>
      </Directory>
      <!--Desktop-->
      <Directory Id="DesktopFolder" Name="Desktop" />
    </Directory>
  </Fragment>

  <!--Directory file structure-->
  <Fragment>
    <DirectoryRef Id="INSTALLFOLDER">
      <Component Id="MainExecutable" Guid="3BC285E4-E330-400D-9570-1D8BA01D8999">
        <File Id="$(var.MainExeID)" Name="$(var.Product_Name).exe" Source="$(var.MyReferencedProject.TargetPath)" DiskId="1" KeyPath="yes" Vital="yes" 
              Assembly=".net" AssemblyApplication="$(var.MainExeID)">
          <Shortcut Id="MainExeDesktop" Directory="DesktopFolder" Name="$(var.Product_Name)" WorkingDirectory="INSTALLFOLDER"
                    Icon="MainExeIcon.exe"
                    Description="Launches the $(var.Product_Name) application" Advertise="yes" >
            <Icon Id="MainExeIcon.exe" SourceFile="$(var.MyReferencedProject.TargetPath)"/>
          </Shortcut>
          <Shortcut Id="MainExeProgramMenu" Directory="ProgramMenuDir" Name="$(var.Product_Name)" WorkingDirectory="INSTALLFOLDER"
                    Icon="MainExeIcon.exe"
                    Description="Launches the $(var.Product_Name) application" Advertise="yes" />
          <Shortcut Id="CleanUpLocalFiles" Directory="ProgramMenuDir" Name="CleanUp the Local Files" Arguments="cleanUpUserData" WorkingDirectory="INSTALLFOLDER"
                    Icon="MainExeIcon.exe"
                    Description="Cleanup all the downloaded files of the $(var.Product_Name) for the current user" Advertise="yes"/>
        </File>
      </Component>
      <Component Id="MainExecutableConfig" Guid="27D20287-A34A-4735-A19B-37C464490351">
        <File Id="MainExeConfig" Name="$(var.Product_Name).exe.config" Source="$(var.MyReferencedProject.TargetPath).config" DiskId="1" KeyPath="yes" Vital="yes" />
      </Component>      
    </DirectoryRef>
  </Fragment>

  <!--Components groups-->
  <Fragment>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
      <ComponentRef Id="MainExecutable" />
      <ComponentRef Id="MainExecutableConfig" />
      <ComponentRef Id="ProgramMenuDir" />
    </ComponentGroup>
  </Fragment>
</Wix>

1 comment:

Calvin Morrison said...

Thank you for sharing! You know with any quesions about creating new software I used to use this software development company http://www.nixsolutions.com/services/custom-software-development/ Because as for me they are leaders in this sphere.