Dmitry Streblechenko
Dmitry Streblechenko

Reputation: 66215

Wix installer does not overwrite previous version of an executable

I have a very simple installer - copy a single dll to a Program Files subfolder and register it with regsvr32.exe. Works great, but if an older version of the dll is installed, "Repair" does not overwrite the existing dll. The dll is signed and its version (build) number is always incremented (e.g. 2.0.0.123 - > 2.0.0.124).

Looking at the previous similar posts, I added RemoveExistingProducts and specified ProductId as "*". Uninstalling and then installing the newer version works fine, but I really need Repair to update the existing dll.

Is there anything else I need to do?

Thank you!

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">

  <!--
When creating a new install for the next version, these fields must be modified
-->
  <?define ProductVersion = "2.0.00" ?>

  <?define ProductId64 = "*" ?>
  <?define ProductId32 = "*" ?>

  <?define PackageId   = "45F34788-66AC-441C-B666-707FFA7F1EE9" ?>


  <!-- Product name as you want it to appear in Add/Remove Programs-->
  <?if $(var.Platform) = x64 ?>
  <?define ProductName = "XYZ (64 bit)" ?>
  <?define Win64 = "yes" ?>
  <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
  <?define ProductId = "$(var.ProductId64)" ?>
  <?define MainDllName = "XYZ64.dll" ?>
  <?define MainDllSource = "..\..\bin\Win64\Release\XYZ64.dll" ?>
  <?else ?>
  <?define ProductName = "XYZ (32 bit)" ?>
  <?define Win64 = "no" ?>
  <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
  <?define ProductId = "$(var.ProductId32)" ?>
  <?define MainDllName = "XYZ.dll" ?>
  <?define MainDllSource = "..\..\bin\Win32\Release\XYZ.dll" ?>
  <?endif ?>


  <?define UpgradeCode = "{C3763742-7C1C-4AB7-A404-F030B7550E97}" ?>


  <Product Id="$(var.ProductId)" Name="$(var.ProductName)" Language="1033" Version="$(var.ProductVersion)" Manufacturer="Advanced Messaging Systems LLC" UpgradeCode="$(var.UpgradeCode)">

    <Package Id="$(var.PackageId)" InstallerVersion="200" Compressed="yes" Description="XYZ Installer package"  InstallPrivileges="elevated"/>

    <!-- No restore point  -->
    <Property Id="MSIFASTINSTALL" Value="3" />

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

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="XYZ">

          <Component Id="XYZDll" Guid="E2CBEE41-6C0E-4A84-95C1-7282747B4A3D">
            <File Id='MainDll' Name="$(var.MainDllName)" DiskId='1' Source="$(var.MainDllSource)" SelfRegCost="0" />

            <!-- TODO: Insert files, registry keys, and other resources here. -->
          </Component>

        </Directory>
      </Directory>
    </Directory>

    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />

    <!-- Note: Custom actions to install/uninstall the dll using regsvr32.exe -->
    <CustomAction Id="RegisterDll"
                      Directory="INSTALLLOCATION"
                      ExeCommand='regsvr32.exe /s "[INSTALLLOCATION]$(var.MainDllName)"'

                      Return="check">
    </CustomAction>
    <CustomAction Id="UnregisterDll"
                  Directory="INSTALLLOCATION"
                  ExeCommand='regsvr32.exe /s /u "[INSTALLLOCATION]$(var.MainDllName)"'>
    </CustomAction>


    <Feature Id="ProductFeature" Title="XYZ" Level="1">
      <ComponentRef Id="XYZDll" />
      <!-- Note: The following ComponentGroupRef is required to pull in generated authoring from project references. -->
      <ComponentGroupRef Id="Product.Generated" />
    </Feature>

    <InstallUISequence>
      <Custom Action="WixCloseApplications" Before="AppSearch"/>
    </InstallUISequence>

    <InstallExecuteSequence>

      <!-- Uninstall previous version before installing this one. -->
      <RemoveExistingProducts Before="InstallInitialize"/>


      <SelfRegModules/>
    </InstallExecuteSequence>

    <Icon Id="XYZ.ico" SourceFile="..\Graphics\XYZ.ico"/>
    <Property Id="ARPPRODUCTICON" Value="XYZ.ico" />

    <!-- UI -->
    <UIRef Id="WixUI_InstallDir"/>
    <UIRef Id="WixUI_ErrorProgressText" />

    <WixVariable Id="WixUILicenseRtf" Value="..\EULA\license.rtf" />
    <WixVariable Id="WixUIBannerBmp"  Value="..\Graphics\banner.jpg" />
    <WixVariable Id="WixUIDialogBmp"  Value="..\Graphics\logo.jpg" />


    <!-- End UI -->
  </Product>
</Wix>

UPDATE. The following worked for me after modifying the upgrade entries:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">

  <!--
When creating a new install for the next version, these fields must be modified
-->
  <?define ProductVersion = "2.0.4" ?>

  <?define ProductId64 = "*" ?>
  <?define ProductId32 = "*" ?>

  <?define PackageId   = "*" ?>


  <!-- Product name as you want it to appear in Add/Remove Programs-->
  <?if $(var.Platform) = x64 ?>
  <?define ProductName = "XYZ (64 bit)" ?>
  <?define Win64 = "yes" ?>
  <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
  <?define ProductId = "$(var.ProductId64)" ?>
  <?define MainDllName = "XYZ64.dll" ?>
  <?define MainDllSource = "..\..\bin\Win64\Release\XYZ64.dll" ?>
  <?else ?>
  <?define ProductName = "XYZ (32 bit)" ?>
  <?define Win64 = "no" ?>
  <?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
  <?define ProductId = "$(var.ProductId32)" ?>
  <?define MainDllName = "XYZ.dll" ?>
  <?define MainDllSource = "..\..\bin\Win32\Release\XYZ.dll" ?>
  <?endif ?>


  <?define UpgradeCode = "{C3763742-7C1C-4AB7-A404-F030B7550E97}" ?>


  <Product
    Id="$(var.ProductId)"
    Name="$(var.ProductName)"
    Language="1033"
    Version="$(var.ProductVersion)"
    Manufacturer="Advanced Messaging Systems LLC"
    UpgradeCode="$(var.UpgradeCode)"
    >

    <Package Id="$(var.PackageId)"
             InstallerVersion="200"
             Compressed="yes"
             Description="XYZ Installer package"
             InstallPrivileges="elevated"
     />

    <!-- No restore point  -->
    <Property Id="MSIFASTINSTALL" Value="3" />


    <Upgrade Id="$(var.UpgradeCode)">
      <UpgradeVersion Minimum="1.0.0"
                      IncludeMinimum="yes"
                      OnlyDetect="no"
                      Maximum="$(var.ProductVersion)"
                      IncludeMaximum="no"
                      Property="PREVIOUSFOUND" />
    </Upgrade>


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

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="$(var.PlatformProgramFilesFolder)">
        <Directory Id="INSTALLLOCATION" Name="XYZ">

          <Component Id="XYZDll" Guid="E2CBEE41-6C0E-4A84-95C1-7282747B4A3D">
            <File Id='MainDll' Name="$(var.MainDllName)" DiskId='1' Source="$(var.MainDllSource)" SelfRegCost="0" />

            <!-- TODO: Insert files, registry keys, and other resources here. -->
          </Component>

        </Directory>
      </Directory>
    </Directory>

    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />

    <!-- Note: Custom actions to install/uninstall the dll using regsvr32.exe -->
    <CustomAction Id="RegisterDll"
                      Directory="INSTALLLOCATION"
                      ExeCommand='regsvr32.exe /s "[INSTALLLOCATION]$(var.MainDllName)"'

                      Return="check">
    </CustomAction>
    <CustomAction Id="UnregisterDll"
                  Directory="INSTALLLOCATION"
                  ExeCommand='regsvr32.exe /s /u "[INSTALLLOCATION]$(var.MainDllName)"'>
    </CustomAction>


    <Feature Id="ProductFeature" Title="XYZ" Level="1">
      <ComponentRef Id="XYZDll" />
      <!-- Note: The following ComponentGroupRef is required to pull in generated authoring from project references. -->
      <ComponentGroupRef Id="Product.Generated" />
    </Feature>

    <InstallUISequence>
      <Custom Action="WixCloseApplications" Before="AppSearch"/>
    </InstallUISequence>

    <InstallExecuteSequence>

     <RemoveExistingProducts After="InstallInitialize"/>

      <SelfRegModules/>

    </InstallExecuteSequence>

    <Icon Id="XYZ.ico" SourceFile="..\Graphics\XYZ.ico"/>
    <Property Id="ARPPRODUCTICON" Value="XYZ.ico" />

    <!-- UI -->
    <UIRef Id="WixUI_InstallDir"/>
    <UIRef Id="WixUI_ErrorProgressText" />

    <WixVariable Id="WixUILicenseRtf" Value="..\EULA\license.rtf" />
    <WixVariable Id="WixUIBannerBmp"  Value="..\Graphics\banner.jpg" />
    <WixVariable Id="WixUIDialogBmp"  Value="..\Graphics\logo.jpg" />


    <!-- End UI -->
  </Product>
</Wix>

Upvotes: 11

Views: 6927

Answers (3)

Stein &#197;smul
Stein &#197;smul

Reputation: 42126

I am surprised that this line actually is allowed by the Wix compiler and linker:

 <?define PackageId   = "45F34788-66AC-441C-B666-707FFA7F1EE9" ?>

If this actually works and goes through, which I haven't tested, it means your package has a hard coded package id. I thought Wix featured protection against this problem? Perhaps it does? We should check with the Wix community if it ever makes any sense to allow hard coded package guid. I suppose it could be necessary for debugging and testing purposes - but there should at least be a compiler warning.

The idea of a package GUID is that it should be unique for each compiled MSI file. It is simply there to uniquely identify a file. Two different MSI files with the same package guid will be treated by Windows Installer as the same file by definition. All kinds of x-files problems result. Accordingly a package GUID should always be auto-generated since it is simply supposed to be unique. Please try to resolve this problem first to check if this solves your overall problem. Set it equal to *.

My advice is to auto-generate package id and product id but to set a hard coded upgrade code. An upgrade code identifies a "family of products" and is useful for identifying any instance of your product regardless of language and version. It might be useful to use a separate upgrade code for your 64 vs 32 bit setups since both versions can be installed at the same time on some systems.

You might also want to eliminate the use of regsvr32.exe for self-registration and extract COM data from your dll for proper MSI support: MSI register dll - Self-Registration considered harmful. And perhaps also check this: Register ActiveX exe server using WiX (check out RegSpy2 if Heat doesn't work).

Also note that you can leave out a lot of source attributes from your Wix xml file and rely on Wix defaults instead of hard coding values.

Some further details on GUIDs and file replacement:

Upvotes: 6

PhilDW
PhilDW

Reputation: 20780

If you want a major uprade, start with the WiX MajorUpgrade element. The general rules for an upgrade are:

  1. Different ProductCode and PackageCode from older product.
  2. Increment ProductVersion somewhere in the first three fields.
  3. Same UpgradeCode as older product.
  4. Do something (like Wix MajorUprade or Upgrade elements) to ensure that you have an upgrade in place.
  5. A per user install will not upgrade a per system install, or vice versa.

In your original case, failure to follow rules 1 and 2 meant that Windows thought the same product was already installed and went into Repair mode. That should have been your first warning because a major upgrade looks like a fresh install, not a repair. If you have two entries in Programs&Features it means that one or more of those 4 requirements has not been met. If you get "Another version of this product is already installed" it means you didn't follow rule 1, and variations in behavior are about ProductCode and PackageCode values compared with the installed product.

Upvotes: 10

Stein &#197;smul
Stein &#197;smul

Reputation: 42126

Short answer (the other one became too messy): try removing this line and let the package ID be auto generated by setting it to "*":

 <?define PackageId   = "45F34788-66AC-441C-B666-707FFA7F1EE9" ?>

Note that you must stop using all previous MSI builds after uninstalling them all. This is due to the faulty hard coded package guid which can cause unpredictable and unforeseen problems.

Upvotes: 3

Related Questions