Detecting When a Reboot Is Necessary
SummaryThis article will explain how to detect if a reboot is necessary.
This article will explain how to detect if a reboot is necessary.
As an InstallShield developer, you will come across cases where it is necessary to install a portion of an application by using a third-party installation program. If you install the third-party program in silent mode and suppress any reboot prompts, it is possible to determine if that installation program needed to reboot the computer when it finished. In some cases, the third-party installation program might return a special value to indicate that a reboot is required, but more than likely, the third-party setup gives no indication about whether a reboot is necessary. It was for the latter situation that the function ISC_bRebootPending was developed, which examines the computer and returns TRUE if a reboot is necessary.
To understand ISC_bRebootPending, it is necessary to understand why reboots are needed in the first place. After all, good installation programs try to avoid reboots at all costs. Installation programs frequently need to update existing files on the computer to ensure that the applications they install are able to run. If any of those existing files happens to be open and, therefore, not writable, the installation program needs to queue the file for replacement immediately after the computer reboots, before the operating system or any other program can open the file again. Therefore, to determine if a reboot is required after another installation program runs, check the appropriate file-renaming queue.
Another indication of whether a reboot is required is the presence of a value in the RunOnce key in the Registry. Windows executes commands stored in the RunOnce key just after a user logs into the computer, and then Windows removes the commands from the RunOnce key. Installation programs like mdac_typ.exe and others often put commands into the RunOnce key to complete configuration of a computer after rebooting. Therefore, a complete determination of whether a reboot is required must look for values in the RunOnce key.
Returning to the issue of locked files, the queues of file replacement operations exist as lists of file rename operations, which the operating system loader performs just before Windows starts. Windows 95-style operating systems and Windows NT-style operating systems use different methods to store the names of files to rename at reboot. Windows 95 puts all of its rename operations into the file Wininit.ini. Windows NT puts the rename operations into a Registry value named "PendingFileRenameOperations". The rule is that if any file rename operations are listed in either Wininit.ini on Windows 95 or in PendingFileRenameOperations on Windows NT, a reboot is required to complete the installation or removal of some files.
ISC_bRebootPending relies on the rules above to make its assessment of the computer. ISC_bRebootPending first flushes the Registry to ensure that any subsequent reads of the Registry do not miss information that has not been written to disk, and then it determines the type of operating system: Windows 9x or Windows NT, which includes Windows 2000 and Windows XP. In the case of Windows 9x, ISC_bRebootPending looks for the file Wininit.ini and tries to read all of the values under the [rename] heading. For Windows NT, ISC_bRebootPending looks for the PendingFileRenameOperations value. In either case, if any data are found, a reboot is pending, and ISC_bRebootPending returns TRUE. If no rename operations are found, ISC_bRebootPending returns FALSE.
As a final check, ISC_bRebootPending examines the RunOnce key, and if it finds any values under that key, ISC_bRebootPending returns TRUE to indicate that a reboot is necessary.
Now that you know how ISC_bRebootPending works, you can use it to make your setup programs more robust. In addition to checking the value returned from ISC_bRebootPending after launching a third-party installation program, it's recommend to check its return value right at the beginning of a setup, to ensure that the system is in a stable state before attempting to make any changes. After all, to make sure that your setup program is successful, you should try to make sure that you are starting from a known state on the system.
Source code for the function ISC_bRebootPending
#define REG_SESSION_MANAGER "System\\CurrentControlSet\\Control\\Session Manager" #define REG_PENDINGFILERENAMEOPERATIONS "PendingFileRenameOperations" #define RUNONCE "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"prototype NUMBER advapi32.RegFlushKey(NUMBER); prototype BOOL ISC_bRebootPending(); /////////////////////////////////////////////////////////////////////////////// // ISC_bRebootPending - Returns TRUE if a reboot is needed. This function looks // for values in the PendingFileRenameOperations value in the // Registry on Windows NT/2000. If the operating system is // Windows 9x, this function looks for values in Wininit.ini. ///////////////////////////////////////////////////////////////////////////////function BOOL ISC_bRebootPending() NUMBER nvType, nvSize; STRING svValue; BOOL bRetVal; // Return value LONG lOS; LIST listRunOnceVals;begin bRetVal = FALSE; // Assume a reboot is not required RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); RegFlushKey(HKEY_LOCAL_MACHINE); GetSystemInfo (OS, lOS, svValue); if (lOS = IS_WINDOWS9X) then // In Windows 9x, file rename operations are stored in Wininit.ini // under the section name "rename". Get a list of rename values, // and if there are any, a reboot is pending. if (Is(FILE_EXISTS, WINDIR ^ "Wininit.ini") = TRUE) then if (GetProfString(WINDIR ^ "Wininit.ini", "rename", "", svValue) = 0) then if (StrLength(svValue) > 0) then bRetVal = TRUE; endif; endif; endif; else // In Windows 2000 and Windows NT, file rename operations are stored in // the PendingFileRenameOperations value. If there is any data in that // value, a reboot is pending. if (RegDBGetKeyValueEx(REG_SESSION_MANAGER, REG_PENDINGFILERENAMEOPERATIONS, nvType, svValue, nvSize) = 0) then if (nvSize > 0) then bRetVal = TRUE; endif; endif; endif; // Look for any values in the RunOnce key. If any values exist, a reboot // is pending. listRunOnceVals = ListCreate(STRINGLIST); RegDBQueryKey(RUNONCE, REGDB_NAMES, listRunOnceVals); if (ListCount(listRunOnceVals) > 0) then bRetVal = TRUE; endif; ListDestroy(listRunOnceVals); return bRetVal; end;
Sample code to call ISC_bRebootPending function
BOOL bReboot; begin // Check if reboot is necessary bReboot = ISC_bRebootPending(); if bReboot then // Reboot is necessary - set BATCH_INSTALL to TRUE. BATCH_INSTALL = TRUE; else // Reboot isn't necessary continue with setup. endif; end;