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]: ME.MMH[Next]: Environment Variables (MAKEMSI Configuration)
Have your say! Join the MAKEMSI discussion list or view archive! Suggest improvements. No question too simple or too complex.
\->Source Code->Configuration / Options->Configuration Header Files->DENNIS.MMH

DENNIS.MMH

This is my "personal configuration file" which is doubling as an example of how you can and should configure the "Preferred MSI Interface for Building a Complete MSI".

Please see "ME.MMH" for a simpler example.

It is supplied as an example but please don't use it's contents as is (and rename it to "JohnSmith.mmh" or something more appropriate).

;----------------------------------------------------------------------------
;
;    MODULE NAME:   DENNIS.MMH
;
;        $Author:   USER "Dennis"  $
;      $Revision:   1.53  $
;          $Date:   27 Apr 2022 15:57:34  $
;       $Logfile:   D:/DBAREIS/Projects.PVCS/Win32/MakeMsi/DENNIS.mmh.pvcs  $
;
; Used by Dennis Bareis (me) to customise "DEPT.MMH" and "COMPANY.MMH" as well
; as to define common macros that I'll want to use in many packages.
;
; SEE "ME.MMH" for a much simpler and easier to understand example.
;
; #################################################################
; #### DO NOT USE FOR YOUR OWN MSIs (contains my branding etc) ####
; #################################################################
;
; This file serves two distinct purposes, it is used by me to build my MSIs
; as mentioned above but its secondary purpose is an an example file for
; MAKEMSI customisation.
; You should create a file similar to this one, in general I don't recommend
; using any of my MAKEMSI header files directly.
;
; There are hundreds of configurable options available this file only contains
; a fraction, the reason for this is probably obvious, I made te defaults
; how I thought they should be! If you need to change a MAKEMSI supplied file
; because you can't configure something let me know and I will try to solve the
; issue.
;
; Note that where I use a "#define?" I am specifically allowing and expecting
; that at times individual scripts may override this value.
; If a value shouldn't be overriden then the "#define" command should be
; used instead.
;
; Note that in this header I define platforms based on operating systems, in
; a company where the MSI is intended for internal deployment the platforms
; may be more like "BRANCH_SERVER" and "BRANCH_WORKSTATION".
;----------------------------------------------------------------------------


;----------------------------------------------------------------------------
;--- This header is not only for me but a SAMPLE distributed with MAKEMSI ---
;----------------------------------------------------------------------------
#if left(GetEnv('COMPUTERNAME'), 10) = 'CN-DENNIS-'
    ;--- Running at home on my personal computer ----------------------------
    #define THIS_COMPUTER_IS_MINE   Y
#elseif
    ;--- Not my computer (so not me!) ---------------------------------------
    #define THIS_COMPUTER_IS_MINE   N
#endif


;----------------------------------------------------------------------------
;--- Set up some branding options -------------------------------------------
;----------------------------------------------------------------------------
#define? DEPT_NAME                       Dennis Bareis              ;;My name
#define? DEPT_ADDRESS                    Australia                  ;;Full address (45 Xyz Drive<$CRLF>SomePlace, 1234<$CRLF>Australia etc)
#define? COMPANY_CONTACT_NAME            <$DEPT_NAME>               ;;My name
#define? COMPANY_CONTACT_NAME_PHONE                                 ;;My phone contact (don't even think about it :-)
#define? DEPT_ARP_URL_PUBLISHER          <?PpwizardAuthorHomePage>  ;;My main web page
#define? DEPT_ARP_URL_TECHNICAL_SUPPORT  <?PpwizardAuthorHomePage>  ;;Default to my web site (root)


;----------------------------------------------------------------------------
;--- Set up sundry MAKEMSI options ------------------------------------------
;----------------------------------------------------------------------------
#define? DBG_ALL                             Y                          ;;Add MAKEMSI debugging to "console file"
#define? DEFAULT_FILE_WANT_FILEHASH          Y                          ;;My box can generate MD5 hashes!
#define? COMPANY_PREPROCESS_LICENCE_FILE     Y                          ;;Default is to preprocess licence files
#define? MERGEMOD_DLL_ACCEPTABLE_VERSIONS    "2.1"                      ;;Only want to accept "Msm.Merge2.1"


;----------------------------------------------------------------------------
;--- I want to "mark" my development MSIs -----------------------------------
;----------------------------------------------------------------------------
#define? COMPANY_MSINAME_SUFFIX.D        (test)
#define? COMPANY_MSINAME_SUFFIX.P
#define? COMPANY_MSINAME_SUFFIX          <$COMPANY_MSINAME_SUFFIX.[MMMODE]>  ;;Adds "(test)" in development mode
#define? COMPANY_PRODUCT_NAME_PREFIX.D   !!!                                 ;;Developer friendy - sorts up front in ARP (in development mode)


;----------------------------------------------------------------------------
;--- Some options more as examples than anything else (sets to defaults anyway) ---
;----------------------------------------------------------------------------
#define? MAKEMSI_HTML_EXTENSION                      hta        ;;Default extension (HTML Application - gets around WINXP SP2 issue)

;--- IE Automation works well on my machine (well my retry code gets well used...) ---
#define? MSI_HTML2TEXT_FUNCTION_USES_IE_AUTOMATION   Y


;----------------------------------------------------------------------------
;--- The Graphics I want to use (at least by default) -----------------------
;----------------------------------------------------------------------------
#if ['<$THIS_COMPUTER_IS_MINE>' = 'Y']
    ;--- I don't want others to use my branding! ----------------------------
    #define? UISAMPLE_DIALOG_FILE_dlgbmp     LeftSide-Dennis.bmp   ;;My replacement graphic for the left hand side (vertical) bitmap
    #define? UISAMPLE_LEFTSIDE_TEXT                                ;;Disable "left side text"
    #define? UISAMPLE_BITMAP_WHITE_BANNER    PrettyBanner.bmp     ;;Use "white.bmp" if you just want it plain
    #define? UISAMPLE_BITMAP_BANNER_GRAPHIC  Aust_DB.bmp          ;;The graphic on the right of the "UISAMPLE_BITMAP_WHITE_BANNER"
    #define? COMPANY_PRODUCT_ICON            Aust_DB.ico          ;;Add-Remove (control panel) icon
#endif


;----------------------------------------------------------------------------
;--- Define the types of boxes that I support -------------------------------
;----------------------------------------------------------------------------
#(
    ;--- The VER file will refer to one or more of these platforms or groups ---
    #define COMPANY_DEFINE_DEPARTMENTS_PLATFORMS

   ;--- WINXP ---------------------------------------------------------------
   #define  PD_WINXP  Windows\XP
   <$Platform "WINDOWS_XP_SERVER" DESC=^Windows XP Server^ PLATDIR="<$PD_WINXP>\Servers">
   <$Platform "WINDOWS_XP_PRO"    DESC=^Windows XP PRO^    PLATDIR="<$PD_WINXP>\PRO">
   #(
       <$Platform "WINDOWS_XP"    DESC=^Windows XP (Server/PRO)^
                   Contains="WINDOWS_XP_SERVER WINDOWS_XP_PRO"
       >
   #)

   ;--- WIN2000 -------------------------------------------------------------
   #define  PD_WIN2000  Windows\2000
   <$Platform "WINDOWS_2000_SERVER" DESC=^Windows 2000 Server^ PLATDIR="<$PD_WIN2000>\Servers">
   <$Platform "WINDOWS_2000_PRO"    DESC=^Windows 2000 PRO^    PLATDIR="<$PD_WIN2000>\PRO">
   #(
       <$Platform "WINDOWS_2000"    DESC=^Windows 2000 (Server/PRO)^
                   Contains="WINDOWS_2000_SERVER WINDOWS_2000_PRO"
       >
   #)

   ;--- Others --------------------------------------------------------------
   <$Platform "WINDOWS_NT4" DESC=^Windows NT 4^ PLATDIR="Windows\NT4">
   <$Platform "WINDOWS_ME"  DESC=^Windows ME^   PLATDIR="Windows\ME">
   <$Platform "WINDOWS_98"  DESC=^Windows 98^   PLATDIR="Windows\98">
   <$Platform "WINDOWS_95"  DESC=^Windows 95^   PLATDIR="Windows\95">

   ;--- A generic one for testing (Maybe it will never be supported) --------
   <$Platform "TEST"       DESC=^Testing (NOT SUPPORTED)^ PLATDIR="Testing-Unsupported">

   ;--- Now create a group for all WINDOWS (groups can contain groups) ------
   #(
       <$Platform "WINDOWS_ALL" DESC=^Any Windows workstations or servers^
                   Contains="WINDOWS_95 WINDOWS_98 WINDOWS_ME WINDOWS_NT4 WINDOWS_2000 WINDOWS_XP"
       >
   #)
#)


;----------------------------------------------------------------------------
;--- I want local build logs & platform logs updated only for production ----
;----------------------------------------------------------------------------
#define? DENNIS_LOCAL_LOG_ROOT <??*APPDATA>\MAKEMSI.LOGS
#(  ';'
    ;--- Local files for Development Mode Build -----------------------------
    #define? DENNIS_MAKEMSI_LOCAL_LOGS_FOR_DEVELOPER_MODE

    <$DENNIS_LOCAL_LOG_ROOT>\ALL.LOG                              ;;Dev+Prod
    <$DENNIS_LOCAL_LOG_ROOT>\DEVELOPER.LOG                        ;;Dev Only
    <$DENNIS_LOCAL_LOG_ROOT>\Product\{ProductName}.LOG            ;;Dev+Prod
    <$DENNIS_LOCAL_LOG_ROOT>\Product\Developer\{ProductName}.LOG  ;;Dev Only
#)
#(  ';'
    ;--- Local files for Production Mode Build ------------------------------
    #define? DENNIS_MAKEMSI_LOCAL_LOGS_FOR_PRODUCTION_MODE

    <$DENNIS_LOCAL_LOG_ROOT>\ALL.LOG                              ;;Dev+Prod
    <$DENNIS_LOCAL_LOG_ROOT>\PRODUCTION.LOG                       ;;Prod Only
    <$DENNIS_LOCAL_LOG_ROOT>\Product\{ProductName}.LOG            ;;Dev+Prod
    <$DENNIS_LOCAL_LOG_ROOT>\Product\Production\{ProductName}.LOG ;;Prod Only
#)
#(  ';'
    ;--- Development Build --------------------------------------------------
    #define? PLATFORM_LOG_FILES.D

    ;--- Only local files (don't touch platform logs) -----------------------
    <$DENNIS_MAKEMSI_LOCAL_LOGS_FOR_DEVELOPER_MODE>
#)
#(  ';'
    ;--- Production build ---------------------------------------------------
    #define? PLATFORM_LOG_FILES.P

    ;--- Logs in other directories ------------------------------------------
    <$DENNIS_MAKEMSI_LOCAL_LOGS_FOR_PRODUCTION_MODE>

    ;--- The normal log files in platform directories (prod only) -----------
    <$PLATFORM_DEFAULT_LOG_FILES>
#)
#define? PLATFORM_LOG_FILES <$PLATFORM_LOG_FILES.[MmMode]>


;---[ReadMeMacros4MakemsiDoco]----
;----------------------------------------------------------------------------
;--- ReadMe Macros (creates and adds readme.txt to current component) -------
;----------------------------------------------------------------------------
#(
    ;--- Define README start macro ------------------------------------------
    #define ReadMe

    ;--- Open the output file (following lines placed in the file) ----------
    #define+ @@ReadmeName  <$MAKEMSI_OUT_LOG_DIR_RELATIVE>\ReadmeFiles\Readme-<$Component?>.TXT  ;;Only once per-component!
    #define+ @@IsKeyFile   {$KeyFile=^N^}
    <$FileMake "<$@@ReadmeName>">

    ;--- Want to keep blank lines! ------------------------------------------
    #option  PUSH LeaveBlankLines=ON

    ;--- You add readme text lines between the "<$readme>" and  "<$/readme>" tags ---
#)
#(
    ;--- Define README end macro --------------------------------------------
    #define /ReadMe

    ;--- Restore options to original state ----------------------------------
    #option  POP

    ;--- Close the file -----------------------------------------------------
    <$/FileMake>

    ;--- Add the file to the current component ------------------------------
    <$File Source="<$@@ReadmeName>" Destination="{$Destination=^ReadMe.TXT^}" KEYPATH=^<$@@IsKeyFile>^>
#)
;---[ReadMeMacros4MakemsiDoco]----


#if ['<$THIS_COMPUTER_IS_MINE>' = 'Y']
;---[4Doco-SuspendCpuIntensiveTasks]----
;----------------------------------------------------------------------------
;--- Define list of resource intensive background applications --------------
;----------------------------------------------------------------------------
#( ';'
    #define @@SuspendProcessList
    seti@home.exe                      ;;Little Green Men...
    *_windows_intelx86*                ;;BOINC - All BOINC processes have this naming convention? (not all have ".exe" extension!)
    WCGrid_Rosetta.exe                 ;;Cancer Research etc
    GIANTAntiSpywareMain.exe           ;;Microsoft AniSpyware
    CopernicDesktopSearch.exe          ;;Can interfere with builds
    ud_ligfit_Release.exe              ;;United Devices

    ;--- Not suspending (as this stops explorer etc working while building msi) ---
    ;YahooDesktopSearch.exe             ;;Can interfere with builds (suspending can stop Explorer etc opening)
                                        ;;Commented out if it still hangs until the piece of cr.p
#)


;----------------------------------------------------------------------------
;--- Stop CPU intensive processes as soon as possible -----------------------
;----------------------------------------------------------------------------
;---[4Doco-HookIntoExample]---
#(
    ;--- Code we wish to execute early in build (but after logging locations known) ---
    #define SuspendCpuIntensiveTasks

    ;--- Need to perform latter when the logging directory is known! --------
    #evaluate ^^ ^<$Rexx4SuspendCpuIntensiveTasks>^
#)
#include "HookInto.MMH"             ;;We haven't already included the MAKEMSI headers...
<$HookInto "MAKEMSI_HOOK_ASAP_AFTER_LOG_DIRECTORIES_DEFINED" Before="SuspendCpuIntensiveTasks">
;---[4Doco-HookIntoExample]---
#DefineRexx 'Rexx4SuspendCpuIntensiveTasks'
    ;--- Create logging directory -------------------------------------------
    @@MainDir = '<$MAKEMSI_OTHER_DIR>\SuspendResume'
    @@LogDir = @@MainDir || '\Logs'
    call AddressCmd 'rd "' || @@LogDir  || '" /q /s >nul <$Stderr2Out>'
    call AddressCmd 'rd "' || @@MainDir || '" /q /s >nul <$Stderr2Out>'
    call MakeDirectoryTree @@LogDir;

    ;--- Set up files -------------------------------------------------------
    @@ProcessFile = @@MainDir || '\MatchingProcesses.txt';
    @@SuspendCmd  = @@MainDir || '\Suspend.CMD';     ;;Only for user invokation (if user aborted - may need to be manually executed)
    @@ResumeCmd   = @@MainDir || '\Resume.CMD';      ;;Only for user invokation (if user aborted - may need to be manually executed)
    call FileDelete @@ProcessFile;
    call FileDelete @@SuspendCmd;
    call FileDelete @@ResumeCmd;

    ;--- Initialize "emergency" Batch file (user invoked if required) -------
    @@Batch = "@echo off" || '0A0A'x;
    @@Batch = @@Batch || '@REM ***' || '0A'x;
    @@Batch = @@Batch || '@REM *** Provided for your use (not actually used by MAKEMSI due to AntiSpyware programs)' || '0A'x;
    @@Batch = @@Batch || '@REM ***' || '0A0A'x;
    @@Batch = @@Batch || '@REM *** List of MASKS ***' || '0A'x;

    ;--- Produce a file containing the matching tasks (those running any matching the mask) ---
    call ArraySplit '@@ProcessMasks', '<$@@SuspendProcessList>', ';'
    @@PvExe = "PV.EXE --quiet"
    do  @@i = 1 to @@ProcessMasks.0
        ;--- Add this wilcard process mask to the list ----------------------
        @@PvExe = @@PvExe || ' "' || @@ProcessMasks.@@i || '"';
        @@Batch = @@Batch || "@REM MASK #" || @@i || ': ' || @@ProcessMasks.@@i || '0A'x;
    end
    @@Batch = @@Batch || '0A0A'x;

    ;--- Process matching (running) processes -------------------------------
    address system @@PvExe || ' > "' || @@ProcessFile || '" 2>&1'
    @@ProcessCnt = 0;
    do  while lines(@@ProcessFile) <> 0
        ;--- All lines should have a tab (process name ends with tab) -------
        @@Line   = linein(@@ProcessFile);
        @@TabPos = pos('09'x, @@Line);

        ;--- Now Extract the Name of the process ----------------------------
        if  @@TabPos <> 0 then
        do
            ;--- Looks OK ---------------------------------------------------
            @@ProcessCnt  = @@ProcessCnt + 1;
            @@ProcessName = left(@@Line, @@TabPos-1);

            ;--- Create Batch file resume command ----------------------------
            @@Batch = @@Batch || 'PsSuspend.exe {Action} "' || @@ProcessName || '"' || '0A'x;

            ;--- Add to the Process list ------------------------------------
            @@Process.@@ProcessCnt = @@ProcessName;
        end;
    end;
    call FileClose @@ProcessFile;
    @@Process.0 = @@ProcessCnt;

    ;--- Actually create the batch files ------------------------------------
    @@Batch = ReplaceString(@@Batch, '0A'x, '0D0A'x);
    call FileLineOut @@SuspendCmd, ReplaceString(@@Batch, "{Action} ", "");
    call FileLineOut @@ResumeCmd,  ReplaceString(@@Batch, "{Action}",  "-r");
    call FileClose @@SuspendCmd;
    call FileClose @@ResumeCmd;     ;;We won't actually run the batch files automatically due to SpyWare programs etc...

    ;--- Schedule RESUME at end of PPWIZARD's processing --------------------
    call ScheduleCleanupCode 'ResumeCpuIntensiveTasks';

    ;--- SUSPEND ignoring return codes/failure (but log for debug) ----------
    do  @@i = 1 to @@Process.0
        @@LogFile = @@LogDir || '\Suspending-' || @@Process.@@i || '.log'
        address system 'PsSuspend.EXE "' || @@Process.@@i || '" > "' || @@LogFile || '" 2>&1'
    end
#DefineRexx


;----------------------------------------------------------------------------
;--- This RESUME code was scheduled in the SUSPEND step above ---------------
;----------------------------------------------------------------------------
#DefineRexx 'ResumeCpuIntensiveTasks'       ;;Define "resume" code (not yet executed)
    ;--- RESUME ignoring return codes/failure (but log for debug) -----------
    do  @@i = 1 to @@Process.0
        @@LogFile = @@LogDir || '\Resuming-' || @@Process.@@i || '.log'
        address system 'PsSuspend.EXE -r "' || @@Process.@@i || '" > "' || @@LogFile || '" 2>&1'
    end
#DefineRexx
;---[4Doco-SuspendCpuIntensiveTasks]----
#endif


;---[4Doco-FindWscript.exe]----
;##################################################################################
;### Note that I have now created a "FileFindInListedDirs" command
;### which simplifies this and makes it more generic:
;###       <$FileFindInListedDirs File="wscript.exe" DIRS="System64Folder;SystemFolder;WindowsFolder">
;##################################################################################

;----------------------------------------------------------------------------
;--- Macro to find "WSCRIPT.EXE"
;--- MS stupidly places this file in logically different locations
;--- ("C:\windows" in WIN98). Also just to make it more difficult it is not
;--- possible to search by attribute, or search path and thus not possible
;--- to avoid possible incorrect matches in fixpack backup directories.
;--- All in all nearly a handful of reasons to swear at MS in one go....
;----------------------------------------------------------------------------
#(
    #define WSCRIPT.EXE

    ;--- Can't do this! Can find files in "$NtServicePackUninstall" type directories ---
    ;<$FileFind File="WSCRIPT.EXE" Property="WSCRIPT.EXE" PATH="[WindowsFolder]" Depth="1">   ;;Danger, Danger...

    ;--- Thanks MS... -------------------------------------------------------
    <$FileFind File="WSCRIPT.EXE" Property="WSCRIPT.EXE.WF" PATH="[WindowsFolder]" Depth="0" Default="">
    <$FileFind File="WSCRIPT.EXE" Property="WSCRIPT.EXE.SF" PATH="[SystemFolder]"  Depth="0" Default="">
    <$PropertyCa "WSCRIPT.EXE" Value="[WSCRIPT.EXE.WF]" Seq="AppSearch-" Condition="WSCRIPT.EXE.WF and (<$CONDITION_EXCEPT_UNINSTALL>)" SeqTable="InstallUISequence InstallExecuteSequence">
    <$PropertyCa "WSCRIPT.EXE" Value="[WSCRIPT.EXE.SF]" Seq="AppSearch-" Condition="WSCRIPT.EXE.SF and (<$CONDITION_EXCEPT_UNINSTALL>)" SeqTable="InstallUISequence InstallExecuteSequence">
    <$AbortIf
        Condition="not WSCRIPT.EXE and (<$CONDITION_EXCEPT_UNINSTALL>)"
          Message=^The file "WSCRIPT.EXE" was not found in the "[WindowsFolder]" or "[SystemFolder]" directories!^
         SeqTable="InstallUISequence InstallExecuteSequence"
              Seq="AppSearch-"
    >
    <$PropertyList "SecureCustomProperties" Value="WSCRIPT.EXE">
#)
;---[4Doco-FindWscript.exe]----

#(

    #define CSCRIPT.EXE

    ;--- Can't do this! Can find files in "$NtServicePackUninstall" type directories ---
    ;<$FileFind File="WSCRIPT.EXE" Property="WSCRIPT.EXE" PATH="[WindowsFolder]" Depth="1">   ;;Danger, Danger...

    ;--- Thanks MS... -------------------------------------------------------
    <$FileFind File="CSCRIPT.EXE" Property="CSCRIPT.EXE.WF" PATH="[WindowsFolder]" Depth="0" Default="">
    <$FileFind File="CSCRIPT.EXE" Property="CSCRIPT.EXE.SF" PATH="[SystemFolder]"  Depth="0" Default="">
    <$PropertyCa "CSCRIPT.EXE" Value="[CSCRIPT.EXE.WF]" Seq="AppSearch-" Condition="CSCRIPT.EXE.WF and (<$CONDITION_EXCEPT_UNINSTALL>)" SeqTable="InstallUISequence InstallExecuteSequence">
    <$PropertyCa "CSCRIPT.EXE" Value="[CSCRIPT.EXE.SF]" Seq="AppSearch-" Condition="CSCRIPT.EXE.SF and (<$CONDITION_EXCEPT_UNINSTALL>)" SeqTable="InstallUISequence InstallExecuteSequence">
    <$AbortIf
        Condition="not CSCRIPT.EXE and (<$CONDITION_EXCEPT_UNINSTALL>)"
          Message=^The file "CSCRIPT.EXE" was not found in the "[WindowsFolder]" or "[SystemFolder]" directories!^
         SeqTable="InstallUISequence InstallExecuteSequence"
              Seq="AppSearch-"
    >
    <$PropertyList "SecureCustomProperties" Value="CSCRIPT.EXE">
#)


;---[4Doco-DebugWaitMacro]----
;----------------------------------------------------------------------------
;--- Macro for inserting Debug Pauses (ver 06.113) --------------------------
;----------------------------------------------------------------------------
#( '<?NewLine>'
    #define DebugWait

    ;--- Validate parameters and keep count ---------------------------------
    {$!:TEXT,SEQ,SEQTABLE,TYPE,CONDITION}
    #RexxVar RxDebugWaitCnt + 1     ;;Inc Count (need diff binaries as text may/will differ)

    ;--- Don't do anything in production mode! ------------------------------
    #if ['<$MmMode>' = '<$MMMODE_PRODUCTION>']
        ;--- In production mode warn first time -----------------------------
        #if [RxDebugWaitCnt = 1]
            #info ^DebugWait not inserted in production mode!^
        #endif
    #elseif
        ;--- Not Production mode --------------------------------------------
        <$VbsCa Binary="DebugWait_<??RxDebugWaitCnt>.vbs">
           <$VbsCaEntry "MessageBox">
               ;--- Will display whether or not in "silent" mode --------------------
               MsgBox "{$Text=^Waiting...^}" & vbCRLF & vbCRLF & "Defined at <??RxMmLocation>", vbInformation, "DebugWait: <$ProdInfo.ProductName> v<$ProductVersion>"
           <$/VbsCaEntry>
        <$/VbsCa>
        <$VbsCaSetup Binary="DebugWait_<??RxDebugWaitCnt>.vbs" Entry="MessageBox" Seq="{$Seq}" CONDITION=^{$Condition=~<$CONDITION_INSTALL_ONLY>~}^ Type="{$Type=^Deferred^}" SeqTable="{$SeqTable=^InstallExecuteSequence^}">
    #endif
#)
#RexxVar RxDebugWaitCnt = 0         ;;Init count
;---[4Doco-DebugWaitMacro]----


;---[4Doco-DebugCauseFailureMacro]----
;-----------------------------------------------------------------------------
;--- DEBUG MACRO: RollBack (use to abort install/repair/uninstall activity ---
;-----------------------------------------------------------------------------
#( '<?NewLine>'
    #define DebugRollback                   ;;Version 08.241

    ;--- Validate parameters and keep count ---------------------------------
    {$!:SEQ,SEQTABLE,TYPE,CONDITION}
    #RexxVar RxDebugRollBackCnt + 1     ;;Inc Count (need diff binaries as conditions, scheduling may/will differ)

    ;--- Don't do anything in production mode! ------------------------------
    #if ['<$MmMode>' = '<$MMMODE_PRODUCTION>']
        ;--- In production mode warn first time -----------------------------
        #if [RxDebugRollBackCnt = 1]
            #info ^DebugRollback not inserted in production mode!^
        #endif
    #elseif
        ;--- Not Production mode --------------------------------------------
        <$VbsCa Binary="DebugRollback_<??RxDebugRollBackCnt>.vbs">
           <$VbsCaEntry "FailedOnPurpose">
               #(
                    VbsCaRaiseError "FailedOnPurpose()",
                                    "<$DebugCauseFailureMsg>" & vbCRLF &
                                    vbCRLF &
                                    "MSI       : <$ProdInfo.ProductName> v<$ProductVersion> (build <?CompileTime>)"  & vbCRLF &
                                    "Sequenced : {$Seq=^<-InstallFinalize^}  (in {$SeqTable=^InstallExecuteSequence^})"  & vbCRLF &
                                    "Condition : {$Condition=~<$CONDITION_INSTALL_ONLY>~}"  & vbCRLF &
                                    "CA Type   : {$Type=^Deferred^}"  & vbCRLF &
                                    "Defined   : <??RxMmLocation>"
               #)
           <$/VbsCaEntry>
        <$/VbsCa>
        <$VbsCaSetup Binary="DebugRollback_<??RxDebugRollBackCnt>.vbs" Entry="FailedOnPurpose" Seq="{$Seq}" CONDITION=^{$Condition}^ Type="{$Type}" SeqTable="{$SeqTable}">
    #endif
#)
#RexxVar RxDebugRollBackCnt = 0         ;;Init count
#(
    #define? DebugCauseFailureMsg
    We are causing a failure on purpose,
    perhaps to test rollback or because we want to test an install
    over and over again without needing to uninstall all the time!
#)
#define DebugCauseFailure <$DebugRollback {$?}>             ;;Create an alias for the macro.
;---[4Doco-DebugCauseFailureMacro]----




#ifndef FeatureIs                               ;;Defined elsewhere?
    ;--- Define Feature and Component state queries -------------------------
    #define FeatureIs       (!{$#1} <$INSTALLCOMPARE_{$IS=^EQUAL^}> <$INSTALLSTATE_{$STATE=^LOCAL^}>)  ;;Feature   is already installed
    #define FeatureWillBe   (&{$#1} <$INSTALLCOMPARE_{$IS=^EQUAL^}> <$INSTALLSTATE_{$STATE=^LOCAL^}>)  ;;Feature   is being installed
    #define ComponentIs     (?{$#1} <$INSTALLCOMPARE_{$IS=^EQUAL^}> <$INSTALLSTATE_{$STATE=^LOCAL^}>)  ;;Component is already installed
    #define ComponentWillBe (${$#1} <$INSTALLCOMPARE_{$IS=^EQUAL^}> <$INSTALLSTATE_{$STATE=^LOCAL^}>)  ;;Component is being installed

    ;--- Define valid "IS" parameter comparison types -----------------------
    #define INSTALLCOMPARE_EQUAL      =
    #define INSTALLCOMPARE_NOT_EQUAL  <>

    ;--- Define valid "STATE" parameter values ------------------------------
    #define INSTALLSTATE_UNKNOWN     -1     ;;No action to be taken on the feature or component.
    #define INSTALLSTATE_ADVERTISED   1     ;;Advertised feature. This state is not available for components.
    #define INSTALLSTATE_ABSENT       2     ;;Feature or component is not present.
    #define INSTALLSTATE_LOCAL        3     ;;Feature or component on the local computer.
    #define INSTALLSTATE_SOURCE       4     ;;Feature or component run from the source.
#endif




;----------------------------------------------------------------------------
;--- Include MAKEMSI support ------------------------------------------------
;----------------------------------------------------------------------------
#include "DEPT.MMH"


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]: ME.MMH[Next]: Environment Variables (MAKEMSI Configuration)


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.