|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
progress.c
Abstract:
This file implements routines that estimate the size of the progress bar.
Author:
Jim Schmidt (jimschm) 02-Jul-1998
Revision History:
jimschm 23-Sep-1998 MigrateShellFolders & split of usermig.c
--*/
/*++
Macro Expansion List Description:
The macro expansion lists FIRST_SYSTEM_ROUTINES, USER_ROUTINES and LAST_SYSTEM_ROUTINES list all the functions called to perform the migration of user and system settings. The functions are executed in the order they appear. Each function is responsible for estimating a tick count and ticking the progress bar.
Line Syntax:
SYSFUNCTION(Function, Flag) (for FIRST_SYSTEM_ROUTINES and LAST_SYSTEM_ROUTINES)
or
USERFUNCTION(Function, Flag) (for USER_ROUTINES)
Arguments:
Function - These functions must return DWORD and are called with a request as a parameter, request that can be either REQUEST_QUERYTICKS (the function should estimate the number of ticks it needs) or REQUEST_RUN (the function should do it's job). For user functions there are also three more parameters (UserName, UserAccount, and a handle to HKCU)
Flag - Specifies NOFAIL if the function terminates migration when it fails, or CANFAIL if migration can proceed even if the function fails
Variables Generated From List:
g_MigrationFnList
For accessing the arrays there are the following functions:
PrepareMigrationProgressBar PerformMigration
--*/
#include "pch.h"
#include "migmainp.h"
#define NOFAIL FALSE
#define CANFAIL TRUE
#define FIRST_SYSTEM_ROUTINES \
SYSFUNCTION(PrepareEnvironment, NOFAIL) \ SYSFUNCTION(ResolveDomains, NOFAIL) \ SYSFUNCTION(DeleteSysTapiSettings, NOFAIL) \ SYSFUNCTION(ProcessLocalMachine_First, CANFAIL) \ SYSFUNCTION(UninstallStartMenuCleanupPreparation, CANFAIL) \ SYSFUNCTION(RemoveBootIniCancelOption, CANFAIL) \ SYSFUNCTION(MigrateShellFolders, CANFAIL) \ SYSFUNCTION(MigrateGhostSystemFiles, CANFAIL) \
#define USER_ROUTINES \
USERFUNCTION(RunPerUserUninstallUserProfileCleanupPreparation, CANFAIL) \ USERFUNCTION(PrepareUserForMigration, NOFAIL) \ USERFUNCTION(DeleteUserTapiSettings, NOFAIL) \ USERFUNCTION(MigrateUserRegistry, CANFAIL) \ USERFUNCTION(MigrateLogonPromptSettings, CANFAIL) \ USERFUNCTION(MigrateUserSettings, CANFAIL) \ USERFUNCTION(RunPerUserExternalProcesses, CANFAIL) \ USERFUNCTION(SaveMigratedUserHive, CANFAIL) \
#define LAST_SYSTEM_ROUTINES \
SYSFUNCTION(DoCopyFile, CANFAIL) \ SYSFUNCTION(ProcessLocalMachine_Last, CANFAIL) \ SYSFUNCTION(ConvertHiveFiles, CANFAIL) \ SYSFUNCTION(MigrateBriefcases, CANFAIL) \ SYSFUNCTION(MigrateAtmFonts, CANFAIL) \ SYSFUNCTION(AddOptionsDiskCleaner, CANFAIL) \ SYSFUNCTION(DoFileEdit, CANFAIL) \ SYSFUNCTION(RunSystemExternalProcesses, CANFAIL) \ SYSFUNCTION(ProcessMigrationDLLs, CANFAIL) \ SYSFUNCTION(DisableFiles, CANFAIL) \ SYSFUNCTION(RunSystemUninstallUserProfileCleanupPreparation, CANFAIL) \ SYSFUNCTION(WriteBackupInfo, CANFAIL) \
//
// Declare tables of processing structures
//
// Create a combined list
#define MIGRATION_ROUTINES FIRST_SYSTEM_ROUTINES USER_ROUTINES LAST_SYSTEM_ROUTINES
// Processing functions types
typedef DWORD (MIGMAIN_SYS_PROTOTYPE) (DWORD Request); typedef MIGMAIN_SYS_PROTOTYPE * MIGMAIN_SYS_FN;
typedef DWORD (MIGMAIN_USER_PROTOTYPE) (DWORD Request, PMIGRATE_USER_ENUM EnumPtr); typedef MIGMAIN_USER_PROTOTYPE * MIGMAIN_USER_FN;
// Structure holding state for processing functions
typedef struct { // One of the two will be NULL, the other will be a valid fn ptr:
MIGMAIN_SYS_FN SysFnPtr; MIGMAIN_USER_FN UserFnPtr;
BOOL CanFail; UINT Ticks; PCTSTR FnName; GROWBUFFER SliceIdArray; } PROCESSING_ROUTINE, *PPROCESSING_ROUTINE;
#define PROCESSING_ROUTINE_TERMINATOR {NULL, NULL, FALSE, 0, NULL, GROWBUF_INIT}
// Declaration of prototypes
#define SYSFUNCTION(fn,flag) MIGMAIN_SYS_PROTOTYPE fn;
#define USERFUNCTION(fn,flag) MIGMAIN_USER_PROTOTYPE fn;
MIGRATION_ROUTINES
#undef SYSFUNCTION
#undef USERFUNCTION
// Declaration of table
#define SYSFUNCTION(fn,flag) {fn, NULL, flag, 0, L###fn, GROWBUF_INIT},
#define USERFUNCTION(fn,flag) {NULL, fn, flag, 0, L###fn, GROWBUF_INIT},
static PROCESSING_ROUTINE g_FirstSystemRoutines[] = { FIRST_SYSTEM_ROUTINES /* , */ PROCESSING_ROUTINE_TERMINATOR };
static PROCESSING_ROUTINE g_UserRoutines [] = { USER_ROUTINES /* , */ PROCESSING_ROUTINE_TERMINATOR };
static PROCESSING_ROUTINE g_LastSystemRoutines[] = { LAST_SYSTEM_ROUTINES /* , */ PROCESSING_ROUTINE_TERMINATOR };
#undef SYSFUNCTION
#undef USERFUNCTION
//
// Prototypes
//
BOOL pProcessTable ( IN DWORD Request, IN PPROCESSING_ROUTINE Table );
//
// Implementation
//
VOID pInitTable ( PPROCESSING_ROUTINE p ) { while (p->SysFnPtr || p->UserFnPtr) { p->SliceIdArray.GrowSize = sizeof (DWORD) * 8; p++; } }
VOID InitProcessingTable ( VOID ) { pInitTable (g_FirstSystemRoutines); pInitTable (g_UserRoutines); pInitTable (g_LastSystemRoutines); }
VOID pTerminateTable ( PPROCESSING_ROUTINE p ) { while (p->SysFnPtr || p->UserFnPtr) { FreeGrowBuffer (&p->SliceIdArray); p++; } }
VOID TerminateProcessingTable ( VOID ) { pTerminateTable (g_FirstSystemRoutines); pTerminateTable (g_UserRoutines); pTerminateTable (g_LastSystemRoutines); }
BOOL pCallAllRoutines ( BOOL Run ) { BOOL b; DWORD Request;
Request = Run ? REQUEST_RUN : REQUEST_QUERYTICKS;
b = pProcessTable (Request, g_FirstSystemRoutines);
if (b && Run) { b = pProcessTable (REQUEST_BEGINUSERPROCESSING, g_UserRoutines); }
if (b) { b = pProcessTable (Request, g_UserRoutines); }
if (b && Run) { b = pProcessTable (REQUEST_ENDUSERPROCESSING, g_UserRoutines); }
if (b) { b = pProcessTable (Request, g_LastSystemRoutines); }
return b; }
VOID PrepareMigrationProgressBar ( VOID ) { InitProcessingTable(); pCallAllRoutines (FALSE); }
BOOL CallAllMigrationFunctions ( VOID ) { return pCallAllRoutines (TRUE); }
BOOL pProcessWorker ( IN DWORD Request, IN PPROCESSING_ROUTINE fn, IN PMIGRATE_USER_ENUM EnumPtr OPTIONAL ) { DWORD rc; PDWORD SliceId; DWORD Size; BOOL Result = TRUE;
//
// If running the function, start the progress bar slice
//
if (Request == REQUEST_RUN) { if (fn->Ticks == 0) { return TRUE; }
Size = fn->SliceIdArray.End / sizeof (DWORD); if (fn->SliceIdArray.UserIndex >= Size) { DEBUGMSG ((DBG_WHOOPS, "pProcessWorker: QUERYTICKS vs. RUN mismatch")); return fn->CanFail; }
SliceId = (PDWORD) fn->SliceIdArray.Buf + fn->SliceIdArray.UserIndex; fn->SliceIdArray.UserIndex += 1;
BeginSliceProcessing (*SliceId);
DEBUGLOGTIME (("Starting function: %ls", fn->FnName)); }
//
// Now call the function
//
if (fn->SysFnPtr) {
//
// System processing
//
MYASSERT (!EnumPtr); rc = fn->SysFnPtr (Request);
if (Request != REQUEST_QUERYTICKS && rc != ERROR_SUCCESS) { DEBUGMSG ((DBG_ERROR, "%s failed with rc=%u", fn->FnName, rc)); Result = fn->CanFail; }
} else {
//
// User processing
//
MYASSERT (fn->UserFnPtr); rc = fn->UserFnPtr (Request, EnumPtr);
if (Request != REQUEST_QUERYTICKS && rc != ERROR_SUCCESS) { DEBUGMSG ((DBG_ERROR, "%s failed with rc=%u", fn->FnName, rc)); Result = fn->CanFail; }
}
//
// If running the function, end the progress bar slice
//
if (Request == REQUEST_RUN) { if (rc != ERROR_SUCCESS) { LOG ((LOG_ERROR, "Failure in %s, rc=%u", fn->FnName, rc)); }
EndSliceProcessing();
DEBUGLOGTIME (("Function complete: %ls", fn->FnName)); }
if (Request != REQUEST_QUERYTICKS) { SetLastError (rc); }
//
// If querying the ticks, register them and add slice ID to grow buffer
//
else { fn->Ticks += rc;
SliceId = (PDWORD) GrowBuffer (&fn->SliceIdArray, sizeof (DWORD)); *SliceId = RegisterProgressBarSlice (rc); }
return Result; }
BOOL pProcessTable ( IN DWORD Request, IN PPROCESSING_ROUTINE Table )
/*++
Routine Description:
pProcessTable calls all routines in the specified table to perform the specified request.
Arguments:
Request - Specifies REQUEST_QUERYTICKS when a tick estimate is needed, or REQUEST_RUN when the function needs to perform its processing. For User routines, there are the additional two requests REQUEST_BEGINUSERPROCESSING and REQUEST_ENDUSERPROCESSING Functions can use these requests to init/free needed resources for user processing.
Return Value:
none
--*/
{ MIGRATE_USER_ENUM e; PPROCESSING_ROUTINE OrgStart; DWORD Flags;
g_DomainUserName = NULL; g_Win9xUserName = NULL; g_FixedUserName = NULL;
MYASSERT (Table->SysFnPtr || Table->UserFnPtr);
while (Table->SysFnPtr || Table->UserFnPtr) {
if (Table->SysFnPtr || Request == REQUEST_BEGINUSERPROCESSING || Request == REQUEST_ENDUSERPROCESSING ) {
//
// Call system routine, or call per-user routine with begin or
// end request
//
__try { if (!pProcessWorker (Request, Table, NULL)) { return FALSE; } } __except (1) {
LOG ((LOG_WARNING, "Unhandled exception occurred during processing of function %s.", Table->FnName)); SafeModeExceptionOccured (); if (!Table->CanFail) { return FALSE; } }
//
// Loop inc
//
Table++;
} else {
//
// Enumerate each user, and run through all the per-user
// routines in the group.
//
OrgStart = Table;
if (Request == REQUEST_QUERYTICKS) { Flags = ENUM_NO_FLAGS; } else { Flags = ENUM_SET_WIN9X_HKR; }
if (EnumFirstUserToMigrate (&e, Flags)) {
do { if (!e.CreateOnly) {
for (Table = OrgStart ; Table->UserFnPtr ; Table++) {
__try { if (!pProcessWorker (Request, Table, &e)) { return FALSE; } } __except (1) { LOG ((LOG_WARNING, "Unhandled exception occurred during processing of function %s.", Table->FnName)); SafeModeExceptionOccured (); if (!Table->CanFail) { return FALSE; } } }
}
} while (EnumNextUserToMigrate (&e)); } ELSE_DEBUGMSG ((DBG_WARNING, "No active users to process!"));
//
// Loop inc
//
while (Table->UserFnPtr) { Table++; } }
TickProgressBar (); }
return TRUE; }
|