532 lines
12 KiB
C
532 lines
12 KiB
C
/*++
|
|
|
|
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"
|
|
|
|
#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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|