MAKEMSI quickly and reliably creates MSI files in a non-programmatic way
Have your say! Join the MAKEMSI discussion list or view archive! Suggest improvements. No question too simple or too complex.
[Bottom][Contents][Prev]: FIREWALL.MMH - Adding and Removing Windows Firewall Exceptions[Next]: Visual Studio Integration
Have your say! Join the MAKEMSI discussion list or view archive! Suggest improvements. No question too simple or too complex.
\->User Contributions->Patch Creation - Julian Onions

Patch Creation - Julian Onions

This information and/or code in this section was provided by Julian Onions (thank you).

Please see the Patches section for general patch information. I also recommend that you also see the "Patch Creation" tip for some details of how I used the information shown below.

Julian has supplied me with two files "PatchDoc.TXT" to document the process and "Patch.mmh" which contains the supporting code. You should have a look at the documentation for the "COMPANY_AUTO_UNINSTALL_VIA_UPGRADE_TABLE" macro.

MAKEMSI installs the header file, to include it:

#include "UserExtns\JulianOnions\patch.mmh"

patch.txt

This file was dated Wed Sep 21 2005 at 7:23:16pm, its contents follows:

;----------------------------------------------------------------------------
;    MODULE NAME:   PATCH.TXT
;
;         Author:   Julian Onions
;      $Revision:   1.1  $
;          $Date:   21 Sep 2005 19:23:16  $
;       $Logfile:   C:/DBAREIS/Projects.PVCS/Win32/MakeMsi/patch[JulianOnions].mmh.txt.pvcs  $
;
; DESCRIPTION
; ~~~~~~~~~~~
; Maintained by Julian Onions.
;----------------------------------------------------------------------------


Various macros and general instructions specified here.

-----------------------------------------------------------------------------------------
Patch

This command is used to create or open an MSI PCP file for patch production.

This command takes several parameters:

- The MSI Patch file name
The first positional parameter is the name of the patch being created. This is used
as the name of the file and to fill in some of the fields.

- Template (optional)
This is a patch template to use to build the patch PCP file. If not supplied it defaults to
"template.PCP" which can be copied from the MSI SDK.


- Version (optional)
This sets the minimum installer version the patch will require. If not set, this will be
set to 200 stating the windows installer version 2 is the target. This allows a lot more
flexibilty in some of the tables.

Examples

Start creation of a patch

; include the relevant support file
#include "patch.mmh"

; Open a patch to create MyPatch
<$Patch "MyPatch">


-----------------------------------------------------------------------------------------

/Patch

This command is used to close a patch database previously opened with the Patch command.

-----------------------------------------------------------------------------------------

PatchFamily

This command is used to define a table entry in the patch database for a family.
It is primarily used to link together other tables. It populates the ImageFamilies
table.

This command takes a number of parameters:

- Family (OPTIONAL)
This is the name of the family. Note that with the standard PCP file this field
is constrained to 8 characters. It seems to be used mainly as a linking table however,
so the value is not critical. If not supplied the Patch name supplied in the Patch
command will be used.


- MediaSrc (OPTIONAL)
This fills out the MediaSrcPropName and defaults to empty.
This is not used particularly with version 2 of MSI. More care needs to be taken
if MSI v1 is the target.

- MediaDisk (OPTIONAL)
This parameter sets the MediaDiskId entry in the ImageFamilies record. See the MSI documentation
for various restrictions on its use. It defaults to empty.

- Seq (OPTIONAL)
The parameter sets the FileSequenceStart entry. Again there are various restrictions on
this field if the target is MSI V1. It defaults to 1000.

- DiskPrompt (OPTIONAL)
The parameter sets the DiskPrompt entry in the table. It defaults to empty if not specified.

- VolumeLabel (OPTIONAL)
The parameter sets the VolumeLabel of this table. It defaults to empty.

Example

; include the relevant support file
#include "patch.mmh"
<$Patch "MyPatch" >
    #define Family MyFamily
    <$PatchFamily Family="<$Family>">
    <$PatchImage Key="MyOrig" SrcMsi="srcmsi\MyMSI.msi" Upgraded="MyPatch">
    <$PatchUpgrade Key="MyPatch" NewMsi="patchmsi\MyMSI.msi" Family="<$Family>">
    <$PatchSequence Family="<$Family>" Version="1.0.1">
<$/Patch>


-----------------------------------------------------------------------------------------

PatchUpgrade


This command adds an upgrade record to the patch database. Its is possible to have several
of these records, although a basic patch will have only one. It populates the UpgradedImages
records.


It has several parameters:

- NewMsi (REQUIRED)
This is a path name to an MSI file that is the target for the patch. So the after file
in a before and after msi build.

- Family (OPTIONAL)
This the patch family name. It will default to the name of the patch
specified in the Patch command if not supplied. It should match the
name you used in PatchFamily if you specified one.

- Key (OPTIONAL)
This is the key for this table, and defaults to the name of the
patch with "_fixed" appended if not supplied. It should match the Upgraded entry
given in the PatchImage line.

- PatchMsi (OPTIONAL)
An optional pathname to an MSI for additional properties. See the MSI documentation
for more details. It defaults to empty.

- SymbolPaths (OPTIONAL)
This is a semi-colon separated list of folders that will be searched for .PDB fies
relating to any .EXE files that are to be patched. This can result in smaller patch images.
It defaults to empty.

Example
; include the relevant support file
#include "patch.mmh"
<$Patch "MyPatch" >
    #define Family MyFamily
    <$PatchFamily Family="<$Family>">
    <$PatchImage Key="MyOrig" SrcMsi="srcmsi\MyMSI.msi" Upgraded="MyPatch">
    <$PatchUpgrade Key="MyPatch" NewMsi="patchmsi\MyMSI.msi" Family="<$Family>">
    <$PatchSequence Family="<$Family>" Version="1.0.1">
<$/Patch>

-----------------------------------------------------------------------------------------

PatchImage

This command adds an entry to the patch database relating to the original MSI build.
The before, in a before and after build. There may be more than one PatchImage lines for
a complex patch.

- SrcMsi (REQUIRED)
This is the path to the original MSI file. The base version that the patch will be generated
against.

- Upgraded (REQUIRED)
This is a link to a PatchUpgrade entry. It specifies the key used in that record.

- Key (OPTIONAL)
This is the key for this record. It defaults to the patch name as specified in the Patch command
with the string "Error" appended.

- SymbolPaths (OPTIONAL)
This is a semi-colon separated list of folders that will be searched for .PDB fies
relating to any .EXE files that are to be patched. This can result in smaller patch images.
It defaults to empty.

- Order (OPTIONAL)
This specifies where this record exists in a list of patch targets within this database.
It defaults to 1 which is suitable if only one patch is being built.

- ValidateFlags (OPTIONAL)
This allows various flags to be set to control the patch generation. It defaults to 0x00000922
which is the value recommended in the MSI documentation.

- IgnoreMissing (OPTIONAL)
This allows the patch process to ignore missing files from the MSI images if set to 1.
In this case these files are obviously skipped rather than being examined for changes.
This can speed up the patch generation, but is also subject to error. It defaults to 0.


Example
; include the relevant support file
#include "patch.mmh"
<$Patch "MyPatch" >
    #define Family MyFamily
    <$PatchFamily Family="<$Family>">
    <$PatchImage Key="MyOrig" SrcMsi="srcmsi\MyMSI.msi" Upgraded="MyPatch">
    <$PatchUpgrade Key="MyPatch" NewMsi="patchmsi\MyMSI.msi" Family="<$Family>">
    <$PatchSequence Family="<$Family>" Version="1.0.1">
<$/Patch>


-----------------------------------------------------------------------------------------

PatchSequence

This command allows patch sequencing to be controlled - which is a windows installer version 3
feature.

It has the following parameters:

- Version (REQUIRED)
This specifies the patch order using a version number sequence. Higher version numbers
being applied after earlier versions.


- Family (OPTIONAL)
The family name of the patch. This defaults to the name of the patch sepcified in the
Patch command if not provided.

- ProductCode (OPTIONAL)
This is a GUID that allows the patch to be targeted at a specific product code.
It defaults to empty, which allows the patch sequence to be applied to any applicable
product.

- Attributes (OPTIONAL)
This defaults to 0, which indicates this is a sequential patch. If set to one then
it implies this superceeds a previous patch.

Example
; include the relevant support file
#include "patch.mmh"
<$Patch "MyPatch" >
    #define Family MyFamily
    <$PatchFamily Family="<$Family>">
    <$PatchImage Key="MyOrig" SrcMsi="srcmsi\MyMSI.msi" Upgraded="MyPatch">
    <$PatchUpgrade Key="MyPatch" NewMsi="patchmsi\MyMSI.msi" Family="<$Family>">
    <$PatchSequence Family="<$Family>" Version="1.0.1">
<$/Patch>


-----------------------------------------------------------------------------------------

PatchProperty

This command allows various patch properties to be set. For a complete list
see the MSI documentation. Note that this is not the same as the Property table
that is found in normal MSI files. The table is actually called "Properties" as
opposed to "Property"

It has two parameters
- First parameter positional (REQUIRED)
This is the name of the property that is being set.

- Value (REQUIRED)
This is the value of the property.

Example
    <$PatchProperty "OptimizePatchSizeForLargeFiles" Value=1>


-----------------------------------------------------------------------------------------

PatchMetaData

This is additional information that can be suppleid and used with version 3 of the
windows installer. There are a number of properties that can be set that influence
how the patch is built. They allow the possibility of specifing the patch is removable
as well as giving it a useful name.

It has a number of parameters:


- First parameter positional (REQUIRED)
The name of the patch meta data property. See the MSI documentation for some standard
ones.

- Value (REQUIRED)
The value of the patch meta data.

- Company (OPTIONAL)
This defaults to empty, which specifies the property is a standard one, rather than
a company specific one.

My default, the Patch command fills in a number of these for you, which can be
overridden by #define-ing them. These are shown in the example. See the MSI documentation
for their specific meaning. The CreationTimeUTC meta-data is set to the current time of patch build.



Example:

#define? PATCH_ALLOW_REMOVAL 1
#define? PATCH_MANUFACTURER  MakeMsi
#define? PATCH_URL <$COMPANY_ARP_URL_APPLICATION_UPDATE_INFORMATION>
#define? PATCH_PRODUCTNAME Patch
#define? PATCH_DISPLAYNAME Patch
#define? PATCH_DESCRIPTION Patch
#define? PATCH_CLASSIFICATION Normal Patch Upgrade

...

    <$PatchMetaData "AllowRemoval" Value="<$PATCH_ALLOW_REMOVAL>">
    <$PatchMetaData "ManufacturerName" Value="<$PATCH_MANUFACTURER>">
    <$PatchMetaData "MoreInfoURL" Value="<$PATCH_URL>">
    <$PatchMetaData "DisplayName" Value="<$PATCH_DISPLAYNAME>">
    <$PatchMetaData "Description" Value="<$PATCH_DESCRIPTION>">
    <$PatchMetaData "Classification" Value="<$PATCH_CLASSIFICATION>">
    <$PatchMetaData "CreationTimeUTC" Value="<$PatchBuildTime>">
    <$PatchMetaData "TargetProductName" Value="<$PATCH_PRODUCTNAME>">



-----------------------------------------------------------------------------------------

SimplePatch

This command wraps up the whole patching sequence in one command, for the cases where
the patch being made is a simple one between two MSI files. It uses generated defaults
for most of the fields.

It has the following parameters:
- Name (REQUIRED)
What the patch is to be called. It is used as the parameter internally to the Patch Command.

- BaseMsi (REQUIRED)
The path name of the base MSI build that you want to generate the patch with respect to.

- FinalMsi (REQUIRED)
The path name of the new MSI build that has the new data in it.


Example:
<$SimplePatch Name="<$PatchName>" BaseMsi="basemsi\MYMSI.msi" FinalMsi="updated\MYMSI.msi">

-----------------------------------------------------------------------------------------

Patch Production

There are a confusing number of patch types that are around, and that can be generated.
These include

small updates - this is equivalent to a hot fix, or quick fix. It does not change
the product code, or the version number. There are a number of restrictions on what
can be included in this. No new features and only certain additions can be made.

minor update - this is a small change to the product, equivalent to a service pack or
small upgrade. The product code does not change, but the version number does.

major update - this is almost a full blown reinstall, and the advice is not to bother with
these, but use a full reinstall instead.

To make both the first two types, it is important that things stay the same as much
as possible. This means fixing the productcode GUID, and the component GUIDs.

The productcode can be fixed, using the same mechanism in the TryMeWithFixedIds example.

The componentIds can be fixed using the ComponentId="?" in each component.

Another thing to watch out for is custom actions, in some cases you may need to
skip CA's when installing a patch, which you can control with the condtion
"not PATCH"

You will also require the following from the SDK.
Template.PCP, PatchWiz.dll, mspatchc.dll and MsiMSP.exe


With that preparation, this is one way to go about making a patch.

1. Build your installer as normal with makemsi, and save the results somewhere.

2. Make the changes required to the source material.

3. Build the new installer - updating the version number as required.
At this point it is worth running the MsiDiff command to compare the images and
see what has changed. You need to look at the output carefully to be sure no
componentIds have been changed unexpectedly.

4. Extract both contents to two separate directories using an Admin install. Patching
will only work on uncompressed images. You can do this with the command
msiexec /a "MyInst.msi" TARGETDIR="c:/build/msi1" /q

5. Run the patch .MM file to produce the patch.

This should result in a MSP file which can be applied with the command
   msiexec /p File.MSP REINSTALLMODE=omus REINSTALL=ALL
you may wish to include the paremeters /l*v applypatch.log
to get a verbose trace of the attempt to apply the patch.

patch.mmh

This file was dated Wed Sep 21 2005 at 7:23:16pm, its contents follows:

;----------------------------------------------------------------------------
;    MODULE NAME:   PATCH.MMH
;
;         Author:   Julian Onions
;      $Revision:   1.1  $
;          $Date:   21 Sep 2005 19:23:16  $
;       $Logfile:   C:/DBAREIS/Projects.PVCS/Win32/MakeMsi/patch[JulianOnions].mmh.pvcs  $
;
; DESCRIPTION
; ~~~~~~~~~~~
; Maintained by Julian Onions.
;----------------------------------------------------------------------------

;;; How to make a patch with this module.
;;; You will need msimsp.exe in your PATH and PatchWiz.dll too. Also for simple patches the template.pcp file.
;;;
;;; 1. Build your regular MSI file as normal. Then save it and any associated CAB files etc somewhere safe
;;;    This is your base distribution
;;; 2. Sometime later, you need to create a new MSI file with the updated contents. There are a few
;;;    restrictions on what can go in a patch, basically stuff like new features are suspect. New files are ok
;;;    as are changed files
;;; 3. Make sure you increment at least one of the version number components in the .VER file
;;; 4. Build the new MSI file as normal.
;;; 5. Patches only work between two uncompressed MSI packages. So you need to uncompress them.
;;;    The easiest way to do this is to perform an admin install.
;;;    msiexec /a origpackage.msi   - put in directory .\origmsi
;;;    msiexec /a newpackage.msi    - put in directory .\newmsi
;;; 6. Now you can build a patch. If you are not doing anything clever, just include the patch.mmh file
;;;    and use the SimplePatch Macro.
;;;    <$SimplePatch Name="MyPatch" BaseMsi="origmsi\package.msi" FinalMsi="newmsi\package.msi">
;;; 7. This will generate you a MyPatch.msp which you can now Apply to an installation with just the original
;;;    package installed (origpackage.msi) to bring it up to the same level as newpackage.msi.
;;;    The bonus is that the MyPatch.msp should be considerably smaller than the full installation,
;;;    as only the new and changed files are included, and for changed files just the bytes that have changed.


;;; Stuff that could be overridden

#define? PATCH_ALLOW_REMOVAL 1
#define? PATCH_MANUFACTURER  MakeMsi
#define? PATCH_URL <$COMPANY_ARP_URL_APPLICATION_UPDATE_INFORMATION>
#define? PATCH_PRODUCTNAME Patch
#define? PATCH_DISPLAYNAME Patch
#define? PATCH_DESCRIPTION Patch
#define? PATCH_CLASSIFICATION Normal Patch Upgrade


#define? MAKEMSI_PATCHCTLFILE_SUFFIX PCP
#define? MSI_SUMMARY_MSI_NAME_TITLE <$MAKEMSI_PATCHCTLFILE_SUFFIX> Name
#define? MAKEMSI_PATCHFILE_SUFFIX MSP
#define?  MAKEMSI_UPDATING_WHAT_TEXT    patch file
#define?  MAKEMSI_UPDATING_WHAT_EXTN    <$MAKEMSI_PATCHFILE_SUFFIX>
;; Some of the table sizes
#define? MAXFAMILYNAMESIZE 8
#define? MAXUPGRADESIZE 13
#define? MAXTARGETSIZE 13
;;; Do not attempt to validate this! Its not an MSI file.
#define? VALID_ValidateTheGeneratedMsi  ""

#include "openmsi.mmh"

#DefineRexx ''
   call Info "Make directory <$MAKEMSI_OUT_LOG_DIR>";
   call MakeDirectoryTree "<$MAKEMSI_OUT_LOG_DIR>";
#DefineRexx

;; define the tables we will be manipulating
<$TableDefinition "Properties">
    <$Column "Name" TYPE="s72"   KEY="Y">
    <$Column "Value" Type="l255">
<$/TableDefinition>
<$TableDefinition "ImageFamilies">
    <$Column "Family" TYPE="s<$MAXFAMILYNAMESIZE>"   KEY="Y">
    <$Column "MediaSrcPropName" Type="s72">
    <$Column "MediaDiskId" Type="i2">
    <$Column "FileSequenceStart" Type="i2">
    <$Column "DiskPrompt" Type="S128">
    <$Column "VolumeLabel" Type="S32">
<$/TableDefinition>
<$TableDefinition "UpgradedImages">
    <$Column "Upgraded" TYPE="s<$MAXUPGRADESIZE>"   KEY="Y">
    <$Column "MsiPath" Type="s255">
    <$Column "PatchMsiPath" Type="S255">
    <$Column "SymbolPaths" Type="S255">
    <$Column "Family" Type="s<$MAXFAMILYNAMESIZE>">
<$/TableDefinition>
<$TableDefinition "UpgradedFilesToIgnore">
    <$Column "Upgraded" TYPE="s<$MAXUPGRADESIZE>"   KEY="Y">
    <$Column "FTK" Type="s255" KEY="Y">
<$/TableDefinition>
<$TableDefinition "TargetImages">
    <$Column "Target" TYPE="s<$MAXTARGETSIZE>"   KEY="Y">
    <$Column "MsiPath" Type="s255">
    <$Column "SymbolPaths" Type="S255">
    <$Column "Upgraded" Type="s<$MAXUPGRADESIZE>">
    <$Column "Order" Type="i2">
    <$Column "ProductValidateFlags" Type="s16">
    <$Column "IgnoreMissingSrcFiles" Type="i2">
<$/TableDefinition>
<$TableDefinition "PatchMetadata">
    <$Column "Company" Type="S72" Key="Y">
    <$Column "Property" Type="s72" Key="Y">
    <$Column "Value" Type="l0">
<$/TableDefinition>
<$TableDefinition "MsiPatchSequence">
    <$Column "PatchFamily" Type="s<$MAXFAMILYNAMESIZE>" Key="Y">
    <$Column "ProductCode" Type="S72" Key="Y">
    <$Column "Version" Type="s40">
    <$Column "Attributes" Type="I2">
<$/TableDefinition>

 #evaluate  "PatchBuildTime"  ^FormatTime("%m-%d-%y %H:%M", TimeStamp())^
;; Start a patch - open the MSI and update the properties.
;; uses the SDK sample template to work from by default.
;; Parameters
;;  - first one is the name of the Patch we want to produce, without any suffix
;;  - optional TEMPLATE="template.pcp" to specify a different template
#(
 #define Patch
 {$!KEYWORDS}  ;;Don't Expect any keywords!
 ;;;; Save the patch name that we are building
 #RexxVar @@PatchName = '{$#1}'
 <$Msi "<$MAKEMSI_OUT_MSI_DIR><??@@PatchName>.<$MAKEMSI_PATCHCTLFILE_SUFFIX>" Template=^{$TEMPLATE="template.pcp"}^>

  <$PatchProperty "PatchOutputPath" Value="<$MAKEMSI_OUT_MSI_DIR><??@@PatchName>.<$MAKEMSI_PATCHFILE_SUFFIX>">
  <$PatchProperty "MinimumRequiredMsiVersion" Value="{$Version=200}">
  <$Table "Properties">
  dim PatchGUID : <$Guid 'PatchGUID' VB="PatchGUID">
  <$Row Name="PatchGUID" *Value="PatchGUID">
  <$/Table>

    <$PatchMetaData "AllowRemoval" Value="<$PATCH_ALLOW_REMOVAL>">
    <$PatchMetaData "ManufacturerName" Value="<$PATCH_MANUFACTURER>">
    <$PatchMetaData "MoreInfoURL" Value="<$PATCH_URL>">
    <$PatchMetaData "DisplayName" Value="<$PATCH_DISPLAYNAME>">
    <$PatchMetaData "Description" Value="<$PATCH_DESCRIPTION>">
    <$PatchMetaData "Classification" Value="<$PATCH_CLASSIFICATION>">
    <$PatchMetaData "CreationTimeUTC" Value="<$PatchBuildTime>">
    <$PatchMetaData "TargetProductName" Value="<$PATCH_PRODUCTNAME>">
#)

;; finish up a patch
;; No parameters
#(
 #define /Patch
 {$!KEYWORDS}  ;;Don't Expect any keywords!
 <$/Msi>
#)

;; when all said and done, run this
#(
   #define+ ONEXIT_AFTER_MSI_BUILT_AND_VALIDATED

  #DefineRexx ''
   ;--- Make the full patch file ------------
   call Info "Building the patch file from <$MAKEMSI_OUT_MSI_DIR><??@@PatchName>.<$MAKEMSI_PATCHCTLFILE_SUFFIX>...";
   call Say  "";
   @@Rc = AddressCmd('Msimsp.exe -s <$MAKEMSI_OUT_MSI_DIR><??@@PatchName>.<$MAKEMSI_PATCHCTLFILE_SUFFIX> -p <$MAKEMSI_OUT_MSI_DIR>\<??@@PatchName>.<$MAKEMSI_PATCHFILE_SUFFIX> -l <$MAKEMSI_OUT_LOG_DIR>patch.log');
   if  @@Rc <> 0 then
     error("Failed to build the patch - see <$MAKEMSI_OUT_LOG_DIR>patch.log");
   call Info "Patch file built in <$MAKEMSI_OUT_MSI_DIR><??@@PatchName>.<$MAKEMSI_PATCHFILE_SUFFIX>";
   call Summary "Patch File", FileNameRelative('<$MAKEMSI_OUT_MSI_DIR><??@@PatchName>.<$MAKEMSI_PATCHFILE_SUFFIX>');

  #DefineRexx
#)

;; add an upgrade line
;; Parameters
;;  - Key OPTIONAL, the Upgraded key into the table, defaults to <Patchname>_fixed
;;  - NewMsi the MSI file we will be comparing to - this is the later one
;;  - PatchMsi OPTIONAL allows you to populate this table entry
;;  - SymbolPaths OPTIONAL populate field
;;  - Family OPTIONAL, reference to the Family. Defaults to the current Patch Name
#(
  #define PatchUpgrade
  {$!KEYWORDS}  ;;Don't Expect any keywords!
  <$Table "UpgradedImages">
   #(
       <$Row
               Upgraded=^{$Key="<??@@PatchName>_fixed"}^
                MsiPath="{$NewMsi}"
           PatchMsiPath=^{$PatchMsi=""}^
            SymbolPaths=^{$SymbolPaths=""}^
                 Family=^{$Family="<??@@PatchName>"}^
       >
   #)
   <$/Table>
#)

;; add an image line
;; Parameters
;;  - Key OPTIONAL, the key name for the target, defaults to <PatchName>Error
;;  - SrcMsi, the base MSI file to diff against
;;  - SymbolPaths OPTIONAL populate field
;;  - Order OPTIONAL defaults to 1
;;  - ValidateFlags OPTIONAL defaults to 0x00000922
;;  - IgnoreMissing OPTIONAL defaults to 0
#(
  #define PatchImage
  {$!KEYWORDS}  ;;Don't Expect any keywords!
  <$Table "TargetImages">
   #(
       <$Row
                          Target=^{$Key="<??@@PatchName>Error"}^
                         MsiPath="{$SrcMsi}"
                     SymbolPaths=^{$SymbolPaths=""}^
                        Upgraded="{$Upgraded}"
                           Order="{$Order=1}"
            ProductValidateFlags=^{$ValidateFlags="0x00000922"}^
           IgnoreMissingSrcFiles="{$IgnoreMissing=0}"
       >
   #)
  <$/Table>
#)

;; add a family line - whatever that is
;; Parameters
;;  - Family OPTIONAL - the name of the Family, defaults to PatchName
;;  - MediaSrc OPTIONAL - Defaults to <PatchName>SrcPropName
;;  - MediaDisk OPTIONAL, Defaults to 2
;;  - Seq OPTIONAL, Defaults to 1000
;;  - DiskPrompt OPTIONAL, Defaults to empty
;;  - VolumeLabel OPTIONAL, Defaults to empty

#(
  #define PatchFamily
  {$!KEYWORDS}  ;;Don't Expect any keywords!
  <$Table "ImageFamilies" Create=Y">
   #(
       <$Row
                      Family=^{$Family="<??@@PatchName>"}^
            MediaSrcPropName=^{$MediaSrc=""}^
                 MediaDiskId="{$MediaDisk=''}"
           FileSequenceStart="{$Seq=1000}"
                  DiskPrompt=^{$DiskPrompt=""}^
                 VolumeLabel=^{$VolumeLabel=""}^
       >
   #)
  <$/Table>
#)

;; Add an entry to the patch sequence table
;; Parameters
;;  - Family OPTIONAL - the name of the Family, defaults to the PatchName
;;  - ProductCode OPTIONAL - defaults to blank
;;  - Version REQUIRED - the version number of the patch sequence
;;  - Attributes OPTIONAL - defaults to 0, could be one see MSI documentation

#(
  #define PatchSequence
  {$!KEYWORDS} ;; No keywords
  <$Table "MsiPatchSequence" Create="Y">
   #(
       <$Row
                 PatchFamily=^{$Family="<??@@PatchName>"}^
                 ProductCode=^{$ProductCode=""}^
                     Version="{$Version}"
                  Attributes=^{$Attributes="0"}^
       >
   #)
  <$/Table>
#)

;; Add to the Patch Properties table
;; Parameters
;;  - First Parameter REQUIRED - property name
;;  - Value REQUIRED - property value
#(
  #define PatchProperty
   <$Table "Properties">
   <$Row Name="{$#1}" Value="{$Value}">
   <$/Table>
#)

;; Files to ignore
;; Parameters
;;   - First Parameter REQUIRED - Upgraded images or *
;;   - Value REQUIRED - the File KEY
#(
  #define PatchIgnoreFile
    <$Table "UpgradedFilesToIgnore">
      <$Row Upgraded="{$#1}" FTK="{$Value}">
    <$/Table>
#)

;; Add to the Patch Meta data table
;; Parameters
;;  - First Parameter REQUIRED - property name
;;  - Value REQUIRED - property value
;;  - Company OPTIONAL - company specific value, defaults to empty
#(
  #define PatchMetaData
 <$Table "PatchMetadata" Create="Y">
   <$Row Company=^{$Company=""}^ Property="{$#1}" Value="{$Value}">
 <$/Table>
 #)

;; SimplePatch - how to create a quick and simple patch
;; Parameters
;; - Name - what to call the patch name
;; - BaseMsi - starting Msi
;; - FinalMsi - finishing MSI file
#(
  #define SimplePatch
  {$!KEYWORDS}  ;;Don't Expect any keywords!
    ; work out some names, being careful on the limited size.
    #DefineRexx ''
       @@PatchFamilyName = "FAM" || '{$Name}';
       if length(@@PatchFamilyName) > <$MAXFAMILYNAMESIZE> then
           @@PatchFamilyName = left(@@PatchFamilyName, <$MAXFAMILYNAMESIZE>);
       @@PatchUpgrade = "PCH" || '{$Name}';
       if length(@@PatchUpgrade) > <$MAXUPGRADESIZE> then
           @@PatchUpgrade = left(@@PatchUpgrade, <$MAXUPGRADESIZE>);
       @@PatchOrig = "ORG" || '{$Name}';
       if length(@@PatchOrig) > <$MAXTARGETSIZE> then
           @@PatchOrig = left(@@PatchOrig, <$MAXTARGETSIZE>);
    #DefineRexx
   <$Patch "{$Name}" >
    <$PatchFamily Family="<??@@PatchFamilyName>">
    <$PatchImage Key="<??@@PatchOrig>" SrcMsi="{$BaseMsi}" Upgraded="<??@@PatchUpgrade>">
    <$PatchUpgrade Key="<??@@PatchUpgrade>" NewMsi="{$FinalMsi}" Family="<??@@PatchFamilyName>">
   <$/Patch>
#)


Microsoft awarded me an MVP (Most Valuable Professional award) in 2004, 2005, 2006, 2007, 2008 & 2009 for the Windows SDK (Windows Installer) area.Please email me any feedback, additional information or corrections.
See this page online (look for updates)

[Top][Contents][Prev]: FIREWALL.MMH - Adding and Removing Windows Firewall Exceptions[Next]: Visual Studio Integration


MAKEMSI© is (C)opyright Dennis Bareis 2003-2008 (All rights reserved).
Saturday May 28 2022 at 3:11pm
Visit MAKEMSI's Home Page
Microsoft awarded me an MVP (Most Valuable Professional award) in 2004, 2005, 2006, 2007, 2008 & 2009 for the Windows SDK (Windows Installer) area.