\
MAKEMSI Installs...
Samples Installed by MAKEMSI
Samples - Build New MSI/MSM
TryMeUpdateRegistry00-99.MM
TryMeUpdateRegistry00-99.MM |
This is one of the MAKEMSI samples which build a new MSI/MSM.
This MSI makes use of these "TryMe.MM" files:
- TryMe.ver
- TryMe.rtf
In some ways this would have been easier and clearer using a DLL or
VBSCRIPT custom action, however this demonstrates a pure Windows Installer
solution (as a general rule don't use "external" custom actions where standard
Windows Installer behaviour will do):
;----------------------------------------------------------------------------
; MODULE NAME: TryMeUpdateRegistry00-99.MM
;
; $Author: USER "Dennis" $
; $Revision: 1.1 $
; $Date: 25 May 2007 18:01:30 $
; $Logfile: C:/DBAREIS/Projects.PVCS/Win32/MakeMsi/TryMeUpdateRegistry00-99.MM.pvcs $
;
; DESCRIPTION
; ~~~~~~~~~~~
; This example demonstrates a purely Windows Installer mechanism to do something
; that might otherwise require a DLL or VBSCRIPT based custom action.
;
; The requirement is that there is a key which is allowed to have up to 100
; string values whose names are "DATA00" to "DATA99", the install needs to
; find an "empty" (missing) location and place a value there.
;
; I chose to defined 100 components only one of which will ever install.
; The other major option was to define a single component and then use the
; registry value "DATA[USEXX]", however this would require the extra step of
; saving "USEXX" away so that it is available at "repair" time (or preventing
; repair of these values).
;
;
; The main logic is:
; * For ALL 100 values read the current registry value ("" for missing).
; The "AppSearch" action performs the search.
; * Find the lowest numbered location where there is no value.
; Put value in the "USEXX" property.
; * Install the component/registry with that number.
; * If no "gap" found (no component would install) then abort with message.
;
; I chose a single loop 00-99 rather than having multiple loops.
; I have also supplied self descriptive key names to components, registry
; and other resources to make it easier to examine and understand ("desk check")
; the generated code.
;----------------------------------------------------------------------------
;--- Include MAKEMSI support (with my customisations and MSI branding) ------
#define VER_FILENAME.VER TryMe.Ver ;;I only want one VER file for all samples! (this line not actually required in "tryme.mm")
#include "ME.MMH"
;--- Define default location where file should install and add files --------
<$DirectoryTree Key="INSTALLDIR" Dir="c:\program files\TryMe (makemsi sample)\<$MAKEMSI_MM_BASENAME>" CHANGE="\" PrimaryFolder="Y">
<$Files "<?InputFile>" DestDir="INSTALLDIR"> ;;Add this ".mm" script
;--- Define Registry where we wish to find a "gap" --------------------------
#define REG_HKEY_DATA HKLM
#define REG_KEY_DATA Software\SomePlace
#define REG_00_99_PREFIX DATA ;;SZ values in range DATA00 - DATA99
;--- Look for a registry "hole" ---------------------------------------------
#define COND_GAP_NOT_YET_FOUND USEXX = "" ;;A gap not yet found
#define COND_REGISTRY_MISSING VALUE4_DATA<$@@xx> = "" ;;The "RegRead" did not find the registry value (or its value is "", can't tell...)
#{ for @@i = 0 to 99 ;;For loop (0, 1, 2, ..., 99)
;--- Need number in form '00' - '99' ------------------------------------
#evaluate+ ^@@xx^ ^right('0<??@@i>', 2)^ ;;Gets last (rightmost) 2 bytes of "00" to "099"
;--- Read registry value (00-99) to property ("VALUE4_DATAxx") ----------
#(
<$RegistryRead
HKEY=^<$REG_HKEY_DATA>^
Key=^<$REG_KEY_DATA>^
Name=^<$REG_00_99_PREFIX><$@@xx>^
Property=^VALUE4_DATA<$@@xx>^
Default="" ;;Stop error message when value doen't exist
>
#)
;--- Set "USEXX" to first hole found (string "00" to "99") --------------
#(
<$PropertyCa "USEXX"
Value="<$@@xx>"
Condition=^<$COND_GAP_NOT_YET_FOUND> and <$COND_REGISTRY_MISSING>^
Seq="AppSearch-"
SeqTable="InstallUISequence InstallExecuteSequence"
Type="FirstSequence"
Key="SET_USEXX_TO_<$@@xx>"
>
#)
;--- Create component for each possble location so we don't need to save property ---
<$Component Condition=^USEXX = "<$@@xx>"^ "INSTALLS_IFF_GAP_AT_<$@@xx>" Create="Y" Directory_="<$AnyDir>"> ;;Only 1 component (or ZERO if aborting below) will match and therefore install.
#(
<$Registry
HKEY=^<$REG_HKEY_DATA>^
Key=^<$REG_KEY_DATA>^
Name=^<$REG_00_99_PREFIX><$@@xx>^
Value=^[INSTALLDIR]^ ;;The value we want to set "DATAXX" to
MsiFormatted="VALUE" ;;The above "Value" parameter contains MSI formatting
KeyPath="Y"
RowKey="INSTALLS_IFF_GAP_AT_<$@@xx>"
>
#)
<$/Component>
#}
;--- Abort if no hole found (DATA00 - DATA99 are ALL set) -------------------
#(
;--- Test for non-existance of property (INSTALL time only) --------------
<$AbortIf
Condition=^USEXX = ""^
Message=^All registry values at "<$REG_HKEY_DATA>\<$REG_KEY_DATA>\<$REG_00_99_PREFIX>00" to "<$REG_00_99_PREFIX>99" have already been alocated (no gap).^
SeqTable="InstallUISequence InstallExecuteSequence"
Seq="AppSearch-" ;;Sequence after all the "PropertyCa" commands above
Type="FirstSequence"
Key="AbortIfNoGapFound"
>
#)