Windows Installer 4.5 Servicing Enhancements: Patch Uninstall Custom Actions

In this blog post, I will provide an overview on what you can do with the new patch uninstall custom actions and how they work. The hope is that by understanding how patch uninstall custom actions work you will be able to put this new custom action type to use easily.

Why Patch Uninstall Custom Actions?

If a patch carries a custom action or carries any updates to a custom action then, that updated custom action is not run when uninstalling the patch. Also, a custom action does not get the information associated with the patch that is being uninstalled. You can look at the attached PPT to get a high level overview of the problem and the way Windows Installer has addressed it in Windows Installer 4.5

How to use this new custom action type?

A custom action that wants to run during patch uninstall will mark itself with a new msidbCustomActionTypePatchUninstall attribute. This attribute can be specified in the ExtendedType column of the CustomAction table. This new column is of type DoubleInteger and can be added when releasing a patch. A custom action marked with this attribute will run only when a patch is being uninstalled.

a. This attribute can be part of the original MSI. But, this attribute should not be dropped or added by a patch to an existing custom action. Altering this attribute in a patch on an existing custom action will cause patch uninstall to fail.

b. A new custom action with this attribute can be added by a patch.

c. When running a patch uninstall custom action, Windows Installer will use the custom action provided in the patch being uninstalled.

d. Windows Installer will make the updates within the patch being uninstalled available to the patch uninstall custom action.

Walkthroughs

Walkthroughs in this section are aimed at understanding several key scenarios associated with this feature. Each walkthrough will discuss what occurs when certain events are triggered. They however, do not discuss the “how”. Walkthroughs try to provide a reason on why certain behavior is appropriate and why certain tradeoffs were made.

In Stream RTM Patch Uninstall Custom Action

  1. Install Product A:
    1. RTM version of the product A carries a patch uninstall custom action PatchUninstallCA1.
    2. This custom action is provided in a Binary Table in the form of RTMCA1.exe.
    3. Upon this install, the custom action is not run.
  2. Apply Patch Q1:
    1. Patch Q1 updates the custom action PatchUninstallCA1:

i. It has a patch sequence (as authored in the MsiPatchSequence table) number of 1.0.2.0.

ii. It replaces RTMCA1.exe in the binary table with Q1CA1.exe.

    1. Upon this patch application neither custom action is run.
  1. Apply Patch Q2:

    1. Patch Q2 updates the custom action PatchUninstallCA1:

i. It has a patch sequence number (as authored in the MsiPatchSequence table) of 1.0.1.0.

ii. It replaces RTMCA1.exe in the binary table with Q2CA1.exe.

    1. Upon this patch application neither custom action is run.
  1. Uninstall Patches Q1 and Q2:

    1. Patches Q1 and Q2 are uninstalled by setting MSIPATCHREMOVE=<Patch GUID of Q2><Patch GUID of Q1>
    2. When both the patches: Q1 and Q2 are uninstalled at the same time, custom action PatchUninstallCA1 ends up running Q1CA1.exe.

This walkthrough summarizes three behaviors:

  1. A custom action marked by the msidbCustomActionTypePatchUninstall attribute will be run only during a patch uninstall.
  2. When two patches that modify a custom action are uninstalled in a single transaction, the patch that has the highest patch sequence number wins. Note that the reason for respecting patch sequence numbers during patch uninstall is to have the ability to resolve ties in situations where a patch might become inapplicable implicitly.

While the above walkthrough takes an EXE custom action as an example, the behavior applies to even DLL and script custom actions.

On Disk Patch-Added Patch Uninstall Custom Action

  1. Install Product A:
    1. RTM version of the product does not have any custom actions. It installs file FTK.exe whose file table key is FTK. Version of FTK.exe is 1.0.
    2. The product is installed without running any custom actions.
    3. Sequence numbers of some important actions:

Action

Sequence Number

InstallFiles

900

PatchFiles

1050

  1. Apply Patch Q1:
    1. Patch Q1 adds a new patch uninstall custom action Q1CA and another new deferred patch uninstall custom action Q1CADeferred. When run, this custom action executes FTK.exe.
    2. Q1 carries FTK.exe 1.1.
    3. Action sequence numbers:

Action

Sequence Number

Q1CA

1000

Q1CADeferred

1005

    1. Upon patch install, FTK.exe will be updated to 1.1 and neither of the patch uninstall custom actions will be run.
  1. Apply Patch Q2:

    1. Patch Q2 adds another new patch uninstall custom action Q2CA. When run, this custom action executes FTK.exe.
    2. Q2 carries FTK.exe 1.2.

Action

Sequence Number

Q2CA

850

    1. Upon patch install, FTK.exe will be updated to 1.2 and Q2CA will not be run.
  1. Uninstall Patches Q1 and Q2:

    1. During patch uninstall the custom actions marked to run only during patch uninstall are run. The sequence in which they are run is:

i. Q2CA. This runs FTK.exe 1.2 because the files have not been updated by the patch uninstall operation yet.

ii. InstallFiles

iii. PatchFiles

iv. Q1CA. This also runs FTK.exe 1.2 because the files have not been updated by the patch uninstall operation yet.

v. Q1CADeferred. This will queue the custom action to run during script execution.

vi. During script execution, FTK.exe 1.0 will be run because the files have been updated by now.

This walkthrough summarizes the behavior that sequence numbers are important for patch uninstall custom actions that rely on non-“Binary Table” resources. Just like any standard custom action, based on when they are executed, they get different versions of the custom action.

Note that this behavior is applicable to DLL and script custom actions as well.

Patch Uninstall Custom Actions’ Ability to Access Install State

  1. Install Product A:
    1. RTM version of the product carries a patch uninstall custom action RTMCA. RTMCA is a patch uninstall DLL custom action.
    2. Upon install of this product RTMCA is not run.
    3. Action sequence numbers:

Action

Sequence Number

RTMCA

1000

  1. Apply Patch Q:
    1. Patch Q carries two patch uninstall custom action DeferredQCA and RollbackQCA.

i. DeferredQCA is a patch uninstall deferred DLL custom action and

ii. RollbackQCA is a patch uninstall rollback DLL custom action.

    1. Patch Q updates the RTM version of product A in the following way:

i. Adds a new component C. This results in the following changes:

· A new component added to the Component table.

· A new component-feature mapping in the FeatureComponents table.

· A new registry key associated with the component results in a new entry in the Registry table.

ii. Changes an existing file. This results in:

· A change in file version of an existing file in the File table.

    1. Action sequence numbers

Action

Sequence Number

DeferredQCA

1010

RollbackQCA

1011

    1. Upon patch install none of the patch uninstall custom actions is run.
  1. Uninstall Patch Q:

    1. Upon uninstall of patch Q, RTMCA will be run first amongst all patch uninstall custom actions. This custom action would like to know info that is being altered due to this patch uninstall. It therefore queries MsiTransformView<Patch GUID> table (for example, MsiTransformView{EA2EEDE8-94F8-4013-A370-36435C4B1259} ) to get that info. For this walkthrough, this table will have the following contents (Several entries not included for the sake of clarity):

Table

Column

Row

Data

Current

File

Version

BlueFile

1.2.0.0

1.0.0.0

Component

Condition

C_PS_QFE2

NULL

NULL

Component

Attributes

C_PS_QFE2

2

NULL

Component

ComponentId

C_PS_QFE2

{88838DDB-DA25-4C4A-B221-E2BAC0305975}

NULL

Component

Directory_

C_PS_QFE2

PATCHSEQFOLDER

NULL

Component

KeyPath

C_PS_QFE2

QFE2

NULL

Component

INSERT

C_PS_QFE2

NULL

NULL

FeatureComponents

INSERT

F_PS_StdColor,C_PS_QFE2

NULL

NULL

Registry

Name

QFE2

QFE2

NULL

Registry

Value

QFE2

QFE2-Simple1

NULL

Registry

Component_

QFE2

C_PS_QFE2

NULL

Registry

Key

QFE2

SOFTWARE\Microsoft\MsiTest\PatchSequencing

NULL

Registry

Root

QFE2

-1

NULL

Registry

INSERT

QFE2

NULL

NULL

RTMCA would query this table to identify the component that was originally added by this patch will be dropped due to this patch uninstall. Based on this information, it can make any decisions that it has to. It needs to be noted that any modifications made to this table will be ignored and not used by Windows Installer in any way. The purpose of this table is for a patch uninstall custom action to make its decisions off of the patch being uninstalled and the state of the machine.

    1. DeferredQCA will be run in script and therefore will not be able to access the MsiTransformView<Patch GUID> table.

Implicit Patch Uninstalls

  1. Install Product A:
    1. RTM version of the product does not have any custom actions.
  2. Apply Patch SP1:
    1. Patch SP1 adds a new binary patch uninstall custom action UninstallCA.
  3. Apply Patch Q1:
    1. Q1 targets SP1 and carries an update to UninstallCA.
  4. Apply Patch Q2:
    1. Q2 targets SP1 and carries an update to UninstallCA.
  5. Apply Patch Q3:
    1. Q3 targets SP1 and carries an update to UninstallCA.
  6. Notes:

The patch sequence numbers for the above three patches are:

Patch

Patch Family

Sequence Number

SP1

Fam1

1.1.0.0

SP1

Fam2

1.1.0.0

Q1

Fam1

1.1.1.0

Q2

Fam1

1.1.2.0

Q2

Fam2

1.1.1.0

  1. Uninstall SP1:
    1. MSIPATCHREMOVE property will be set to SP1 only. However, Q1, Q2 and Q3 will all be uninstalled because they transition from applicable to inapplicable. All patches that go out of view in this manner, get the opportunity to run their patch uninstall custom actions.
    2. However, since all of them update the same custom action, the question is whose custom action will be run. The answer is: the patch whose sequence number is the highest will be used. However, when there are two patches with different patch families then the choice will be non-deterministic.

[Author: Hemchander Sannidhanam]
This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm.

Patch Uninstall Custom Actions.ppt