Progress Bar - Move Bar |
This code demonstrates how you can move the progress bar during a lengthy custom action. While it demonstrates VBSCRIPT, the same details apply to all custom action types.
Some facts (if you want to end at 100%):
Windows Installer has made this way too hard with the need to first add and then consume a "fuzzy" tick. A CA simply indicating percentage completion would have done a much better, easier and accurate job.
EXAMPLE.MM |
The following demonstrates the basics of moving the progress bar.
<$VbsCa Binary="TestProgressBar.vbs"> ;--- Progress Bar Initialization ---------------------------------------- <$VbCaProgressTickFunctions> <$VbsCaEntry "DoDeferredInstallation"> ;--- Define (to this script) the maximum that ProgressTicksUse() can consume --- #define TICKS_DoDeferredInstallation 10000000 ProgressTicksAdd <$TICKS_DoDeferredInstallation> ;--- Now do some installation stuff --------------------------------- dim i for i = 1 to 10 ;--- Do something that takes some time... ----------------------- MsgBox "Doing installation stuff #" & i, vbInformation, "DEBUG" ;--- Indicate we have done something (in this case 10% of the work) --- ProgressTicksUse 1000000 next ;--- Use any left over ---------------------------------------------- ProgressTicksUse -1 <$/VbsCaEntry> <$VbsCaEntry "AddTicksToWindowsInstaller"> ;--- Need an IMMEDIATE CA to add to total tick count ---------------- ProgressTicksAdd <$TICKS_DoDeferredInstallation> <$/VbsCaEntry> <$/VbsCa> <$VbsCaSetup Binary="TestProgressBar.vbs" Entry="AddTicksToWindowsInstaller" Seq="CreateShortcuts-" Condition="<$CONDITION_INSTALL_ONLY>" TYPE="IMMEDIATE"> <$VbsCaSetup Binary="TestProgressBar.vbs" Entry="DoDeferredInstallation" Seq="CreateShortcuts-" Condition="<$CONDITION_INSTALL_ONLY>">
ProgressTicks Code |
The following shows the supporting code that needs to be included ASAP after the "VbsCa command.
#define VERSION_VbCaProgressTickFunctions 06.232 #define? PROGRESSTICKS_DEBUG_MAX_MSGBOX 0 ;;Set to max number of dialogs you want to see (or click on!) #define? PROGRESSTICKS_DEBUG_LOG Y ;;In Verbose and any "text" log #( '<?NewLine>' #define VbCaProgressTickFunctions ;--- Set up global variables reuired by Progress code -------------------- dim MaxMsgBoxes : MaxMsgBoxes = <$PROGRESSTICKS_DEBUG_MAX_MSGBOX> dim TotalProgressTicks : TotalProgressTicks = clng(0) <?NewLine><?NewLine> <?NewLine><?NewLine> ;===================================================================== function AddCommas(Numb) ;===================================================================== AddCommas = FormatNumber(Numb, 0, True, True) end function <?NewLine><?NewLine> ;===================================================================== sub TicksMsg(ByVal Msg) ;===================================================================== ;--- Output to verbose (and any "text") log ------------------------- err.clear() #if ['<$PROGRESSTICKS_DEBUG_LOG>' <> 'N'] CaDebug 0, "[\[]PROGRESS TICKS[\]]: " & Msg #endif ;--- Display message box -------------------------------------------- if MaxMsgBoxes <> 0 then MaxMsgBoxes = MaxMsgBoxes - 1 MsgBox Msg, vbInformation, "PROGRESS BAR TICKS DIAGNOSTIC" end if end sub <?NewLine><?NewLine> ;===================================================================== function MsgRc(ByVal MsRc) ;===================================================================== dim T : T = "" if err.number <> 0 then T = vbCRLF & "err.number = 0x" & hex(err.number) & " - " & err.description end if if MsRc <> 1 then T = vbCRLF & "Session.Message RC = " & MsRc & " (expected 1)" & T end if if T <> "" then T = vbCRLF & T end if MsgRc = T end function <?NewLine><?NewLine> ;===================================================================== sub ProgressTicksAdd(Ticks2Add) ;===================================================================== ;--- Immediate of deferred? ----------------------------------------- on error resume next dim Msg if session.mode(msiRunModeScheduled) then ;--- Deferred --------------------------------------------------- TotalProgressTicks = clng(TotalProgressTicks + Ticks2Add) #( TicksMsg "Setting tick limit only as this is a deferred Custom Action." & vbCRLF & vbCRLF & "Added " & AddCommas(Ticks2Add) & ", the new total is " & AddCommas(TotalProgressTicks) #) ;--- Don't want ActionData messages to change bar --------------- err.clear() set oRec = Installer.CreateRecord(3) oRec.IntegerData(1) = ActionInfo oRec.IntegerData(2) = 0 oRec.IntegerData(3) = 0 MsgRc = session.message(msiMessageTypeProgress, oRec) set oRec = Nothing Msg = MsgRc(MsgRc) TicksMsg "Preventing ActionInfo from moving bar." & Msg else ;--- Tell Windows Installer how many ticks the CA will use ------ err.clear() dim oRec : set oRec = Installer.CreateRecord(3) oRec.IntegerData(1) = ProgressAddition oRec.IntegerData(2) = Ticks2Add oRec.IntegerData(3) = 0 dim MsgRc : MsgRc = session.message(msiMessageTypeProgress, oRec) set oRec = Nothing Msg = MsgRc(MsgRc) TicksMsg "Added " & AddCommas(Ticks2Add) & " ticks to the Windows Installer progress bar as this is an immediate Custom Action." & Msg end if ;--- Make sure err.number is 0 -------------------------------------- err.clear() end sub <?NewLine><?NewLine> ;===================================================================== sub ProgressTicksUse(ByVal Ticks2Consume) ;===================================================================== ;--- We can't consume more ticks than we have added ----------------- on error resume next dim Msg dim UseTicks : UseTicks = Ticks2Consume if UseTicks = -1 then ;--- Asked to use the rest -------------------------------------- UseTicks = TotalProgressTicks elseif UseTicks > TotalProgressTicks then ;--- More than we have so just use what we have ----------------- UseTicks = TotalProgressTicks end if ;--- Remember what we have left ------------------------------------- dim T if UseTicks < 1 then ;--- No ticks left ---------------------------------------------- if Ticks2Consume = -1 then T = "all remaining" else T = AddCommas(Ticks2Consume) end if TicksMsg "Asked to use " & T & " ticks, but none left" exit sub end if TotalProgressTicks = clng(TotalProgressTicks - UseTicks) ;--- Output to progress bar ----------------------------------------- dim oRec : set oRec = Installer.CreateRecord(3) oRec.IntegerData(1) = ProgressReport oRec.IntegerData(2) = UseTicks oRec.IntegerData(3) = 0 dim MsgRc : MsgRc = session.message(msiMessageTypeProgress, oRec) set oRec = Nothing Msg = MsgRc(MsgRc) T = "Used " & AddCommas(UseTicks) & " ticks" if Ticks2Consume <> UseTicks then T = T & " (" & AddCommas(Ticks2Consume) & " requested)" end if T = T & ", total now " & AddCommas(TotalProgressTicks) TicksMsg T & Msg ;--- Make sure err.number is 0 -------------------------------------- err.clear() end sub #)