Version File Based Launch Conditions |
This shows how you can configure launch conditions so that you can list them by name in a version file (for example you could specify "SERVER IIS WIN2003" if you'd defined the appropriate information).
This is an example of how the keyword could look in the version file if the computer must not be a server and must have Windows 2000 or greater installed:
; ONLYON = WORKSTATION WIN2000+
The "TryMeAddVersionKeywordAndLaunchCondition.MM" sample is the full self contained sample which can be executed to see it in action. The folllowing sections show the relevant fragments of this file as well as some explanations.
All of this code would generally be in a single "configuration" file such as my "DENNIS.MMH" header file.
Configuration |
The code allows you to configure the conditions you'd like to be able to specify in the version file, for example you might wish to use "WINXP" if you want to ensure that the installer will only continue on WINXP based computers.
The following properties are associated with each "condition":
When processing the list of "OnlyOn" parameters the existance of the "Desc" property is used to determine whether the "condition" is valid or not.
The "OnlyOn" keyword can specify any number of parameters (test) however if more than one then all conditions must match.
Sample configuration follows:
;---------------------------------------------------------------------------- ;--- Macro to get box type from Windows Registry ---------------------------- ;---------------------------------------------------------------------------- #define? ComputerTypeProperty REGISTRY.PRODUCTTYPE #( #define? ComputerTypeGet ;;Useful macro (but also see the "MsiNTProductType" property) ;--- Only need to generate this code the first time! -------------------- #ifndef @@ComputerTypeGet.CodeGenerated ;--- Get the value form the Windows Registry ------------------------ <$RegistryRead Property="<$ComputerTypeProperty>" HKEY="LOCAL_MACHINE" KEY="SYSTEM\CurrentControlSet\Control\ProductOptions" NAME="ProductType" > ;--- Flag code generated -------------------------------------------- #define @@ComputerTypeGet.CodeGenerated #endif #) ;---------------------------------------------------------------------------- ;--- Define ONLYON=WORKSTATION ---------------------------------------------- ;---------------------------------------------------------------------------- #define ONLYON.WORKSTATION.Desc Windows Workstation #define ONLYON.WORKSTATION.Code <$ComputerTypeGet> #define ONLYON.WORKSTATION.Condition <$ComputerTypeProperty> ~= "WinNT" #define ONLYON.WORKSTATION.ErrInfo <$WindowsTypeErrInfo> #define? WindowsTypeErrInfo ComputerType="[<$ComputerTypeProperty>]" ;---------------------------------------------------------------------------- ;--- Define ONLYON=SERVER (of any type) ------------------------------------- ;---------------------------------------------------------------------------- #define ONLYON.SERVER.Desc Windows Server #define ONLYON.SERVER.Code <$ComputerTypeGet> #define ONLYON.SERVER.Condition "ServerNT, LanmanNT" ~>< <$ComputerTypeProperty> #define ONLYON.SERVER.ErrInfo <$WindowsTypeErrInfo> ;---------------------------------------------------------------------------- ;--- Define ONLYON=WIN2000+ ------------------------------------------------- ;---------------------------------------------------------------------------- #define ONLYON.WIN2000+.Desc Version WIN2000 or newer #define ONLYON.WIN2000+.Code #define ONLYON.WIN2000+.Condition VersionNT and (VersionNT >= 500) #( '{NL}' #define ONLYON.WIN2000+.ErrInfo VersionNT=[VersionNT] ;;Display version (blank if box on Win9x) Version9X=[Version9X] ;;Display version (blank if box on WinNT+) #)
Define "ONLYON" As a Valid Keyword |
This code needs to be placed before version file processing takes place:
;---------------------------------------------------------------------------- ;--- Add "OnlyOn" keyword to list of valid ".VER" file keywords ------------- ;---------------------------------------------------------------------------- #( "" #define COMPANY_PRODINFO_VALID_KEYWORD_LIST_EXTRA ,OnlyOn ;;New keyword starts with and keywords separated with "," #) #define? ProdInfo.Default.OnlyOn ;;Set the keywords default (make it optional) ;---------------------------------------------------------------------------- ;--- Add "OnlyOn" info to report's summary ---------------------------------- ;---------------------------------------------------------------------------- #( '' #define? HTMLSUMM_AFTER_BUILT_AT <TR> <TD align="center"<$HTMLSUMM_SUPPORTED_PLATFORMS_TT>> Supported<BR>Platforms </TD> <TD> <span<$HTMLSUMM_SUPPORTED_PLATFORMS_TT>> <$PLATFORM_MsiSupportedWhereHtml> </span> <$ONLYON_SUMMARY_TEXT> </TD> </TR> <$COMPANY_HTMLSUMM_AFTER_SUPPORTED_PLATFORMS> #)
Process the Configured "ONLYON" Keywords Value |
This code needs to be placed after version file processing has taken place:
;---------------------------------------------------------------------------- ;--- Support Developer box ignoring of any "OnlyOn" checking ---------------- ;---------------------------------------------------------------------------- #define? ONLYON_ALWAYS_OK_CONDITION.D %VCSID <> "" ;;If PVCS environment set then its a development box! #define? ONLYON_ALWAYS_OK_CONDITION.P #define? ONLYON_ALWAYS_OK_CONDITION <$ONLYON_ALWAYS_OK_CONDITION.[MMMODE]> ;;Blank or "0" (non-true) means don't ignore ;---------------------------------------------------------------------------- ;--- Process "OnlyOn" keywords value ---------------------------------------- ;---------------------------------------------------------------------------- #if ['<$ProdInfo.OnlyOn>' <> ''] ;--- YES, we don't run on just any type of box ----------------------- #DefineRexx '' ;--- Loop through all space separated "keywords" --------------------- @@Categories = '<$ProdInfo.OnlyOn>'; @@OnlyOnDesc = '' @@OnlyOnCode = d2c(10); @@OnlyOnCondition = '' @@OnlyOnErrInfo = '' @@UnknownCategories = '' call Info "Only Installs on: " || @@Categories; do while @@Categories <> '' ;--- Get next category -------------------------------------------- parse var @@Categories @@Category @@Categories; ;--- Is it valid (previously defined)? ---------------------------- @@MacBase = 'ONLYON.' || @@Category || '.' if Defined(@@MacBase || 'Desc') = 'N' then @@UnknownCategories = strip(@@UnknownCategories || ' ' || @@Category); else do ;--- Valid keyword, get details ----------------------------- @@Desc = ReplaceMacros(MacroGet(@@MacBase || 'Desc')); if Defined(@@MacBase || 'Condition') = 'N' then error('The "ONLYON" keyword "' || @@Category || '" is missing a condition definition!'); else @@Condition = ReplaceMacros(MacroGet(@@MacBase || 'Condition')); if Defined(@@MacBase || 'Code') = 'N' then @@Code = ''; else @@Code = ReplaceMacros(MacroGet(@@MacBase || 'Code')); if Defined(@@MacBase || 'ErrInfo') = 'N' then @@ErrInfo = ''; else @@ErrInfo = ReplaceMacros(MacroGet(@@MacBase || 'ErrInfo')); ;--- Combine info ------------------------------------------- if @@OnlyOnDesc <> '' then do ;--- Not the first item (seperator required) ------------ @@OnlyOnDesc = @@OnlyOnDesc || ' and ' @@OnlyOnCondition = @@OnlyOnCondition || ' and ' end; @@OnlyOnDesc = @@OnlyOnDesc || @@Desc; @@OnlyOnCondition = @@OnlyOnCondition || '(' || @@Condition || ')'; if @@Code <> '' then do if @@OnlyOnCode <> '' then @@OnlyOnCode = @@OnlyOnCode || ' ' @@OnlyOnCode = @@OnlyOnCode || @@Code; end; if @@ErrInfo <> '' then do if @@OnlyOnErrInfo <> '' then @@OnlyOnErrInfo = @@OnlyOnErrInfo || '{NL}' @@OnlyOnErrInfo = @@OnlyOnErrInfo || @@ErrInfo; end; end; end; if @@UnknownCategories <> '' then error('The "ONLYON" keyword specified these unknown categories:',, ' ' || @@UnknownCategories); ;--- Must restrict the message to 255 characters (MSI schema retriction) --- if length(@@OnlyOnErrInfo) > 255 then @@OnlyOnErrInfo = left(@@OnlyOnErrInfo, 252) || '...'; ;--- We may have a condition which indicates alls OK in any circumstance --- @@OkCondition = strip(ReplaceMacros(MacroGet('ONLYON_ALWAYS_OK_CONDITION'))); if @@OkCondition <> '' then do ;--- We do have such a condition (useful for testing etc) ------- @@OnlyOnCondition = '(' || @@OnlyOnCondition || ') or (' || @@OkCondition || ')' end; ;--- The condition can't be too long... ------------------------------ @@FullCondition = 'not (' || @@OnlyOnCondition || ')'; ;;True means OK (we need true to mean NOT OK) if length(@@FullCondition) > 255 then error('The ONLYON condition is ' || length(@@FullCondition) || ' bytes long (its limit is 255)!', 'The full condition is:',,@@FullCondition); ;--- Bit of a cludge ------------------------------------------------- @@OnlyOnErrInfo = ReplaceString(@@OnlyOnErrInfo, "{NL}", "<$CRLF>"); ;--- Want this info in the summary ------------------------------- @@H = '<p><b><i>' @@H = @@H || '<span title="This MSI has a launch condition (specified by the "OnlyOn" keyword).">' @@H = @@H || 'This product will only install on computers of type ' || @@OnlyOnDesc || '!' @@H = @@H || '</i></b>' if @@OkCondition <> '' then @@H = @@H || '<br><span style="font:xx-small">Note that for testing purposes this launch condition can be removed by ensuring the following condition evaluates to true: ' || @@OkCondition @@H = @@H || '</span>' call MacroSet "ONLYON_SUMMARY_TEXT", @@H #DefineRexx ;--- Generate any required code (to set up for "Condition") -------------- <??@@OnlyOnCode> ;--- Now perform the validation ------------------------------------------ #( <$AbortIf Condition=^<??@@FullCondition>^ Message=^We can't install <$ProdInfo.ProductName> as this computer is not <??@@OnlyOnDesc><$Crlf><$Crlf><$Crlf><??@@OnlyOnErrInfo>^ Seq="AppSearch-" SeqTable="InstallUISequence InstallExecuteSequence" Key="TestOnlyOnConditionDieOnFailure" > #) #endif #define? ONLYON_SUMMARY_TEXT ;;If not set above make empty