You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1391 lines
40 KiB
1391 lines
40 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
loadstate.c
|
|
|
|
Abstract:
|
|
|
|
<abstract>
|
|
|
|
Author:
|
|
|
|
<full name> (<alias>) <date>
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include "ism.h"
|
|
#include "modules.h"
|
|
#include "trans.h"
|
|
#include <tlhelp32.h>
|
|
#include <shlobjp.h>
|
|
#ifdef DEBUG
|
|
#include <shellapi.h>
|
|
#endif
|
|
|
|
#include "logmsg.h"
|
|
#include "common.h"
|
|
|
|
#define DBG_LOADSTATE "LoadState"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define LOG_VERBOSE_BIT 0x01
|
|
#define LOG_UNUSED_BIT 0x02 // for v1 compatibility, do not use
|
|
#define LOG_STATUS_BIT 0x04
|
|
#define LOG_DEBUGGER_BIT 0x08
|
|
#define LOG_UPDATE_BIT 0x10
|
|
|
|
#define LOADSTATE_LOAD 0x00000001
|
|
#define LOADSTATE_EXECUTE 0x00000002
|
|
#define LOADSTATE_COMPLETED 0x00000003
|
|
|
|
#define RETURN_SUCCESS 0
|
|
#define RETURN_FATAL_ERROR 1
|
|
#define RETURN_ERROR 2
|
|
#define RETURN_IGNORED_ERROR 3
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
typedef struct
|
|
{
|
|
UINT cbSize;
|
|
SHELLSTATE ss;
|
|
} REGSHELLSTATE, *PREGSHELLSTATE;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
PTSTR g_Explorer = NULL;
|
|
BOOL g_ContinueOnError = FALSE;
|
|
DWORD g_ReturnCode = ERROR_SUCCESS;
|
|
TCHAR g_JournalPath[MAX_PATH_PLUS_NUL];
|
|
BOOL g_Break;
|
|
|
|
#ifdef PRERELEASE
|
|
HANDLE g_CallbackEvent;
|
|
#endif
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
#define REQUIRED_INFS \
|
|
DEFMAC(OSFILES, TEXT("USMTDef.inf")) \
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
MESSAGECALLBACK pSaveMsgCallback;
|
|
|
|
PTSTR
|
|
pGetShellFolderPath (
|
|
IN INT Folder
|
|
);
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
//
|
|
// This is the structure used for handling required infs
|
|
//
|
|
typedef struct {
|
|
PCTSTR InfId;
|
|
PCTSTR InfName;
|
|
} REQUIREDINF_STRUCT, *PREQUIREDINF_STRUCT;
|
|
|
|
//
|
|
// Declare a global array of required infs
|
|
//
|
|
#define DEFMAC(infid,infname) {TEXT(#infid),infname},
|
|
static REQUIREDINF_STRUCT g_RequiredInfs[] = {
|
|
REQUIRED_INFS
|
|
{NULL, NULL}
|
|
};
|
|
#undef DEFMAC
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
VOID
|
|
pCleanUpApp (
|
|
VOID
|
|
)
|
|
{
|
|
IsmTerminate();
|
|
|
|
if (g_JournalPath[0]) {
|
|
DeleteFile (g_JournalPath);
|
|
g_JournalPath[0] = 0;
|
|
}
|
|
|
|
#ifdef PRERELEASE
|
|
CloseHandle (g_CallbackEvent);
|
|
#endif
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
CtrlCRoutine (
|
|
IN DWORD ControlSignal
|
|
)
|
|
{
|
|
PrintMsgOnConsole (MSG_EXITING);
|
|
|
|
LOG ((LOG_WARNING, (PCSTR) MSG_TOOL_STOPPED));
|
|
|
|
g_Break = TRUE;
|
|
|
|
IsmSetCancel();
|
|
while (IsmCurrentlyExecuting()) {
|
|
Sleep (1000);
|
|
}
|
|
|
|
pCleanUpApp();
|
|
|
|
printf ("\n");
|
|
exit (1);
|
|
}
|
|
|
|
|
|
VOID
|
|
pHelpAndExit (
|
|
VOID
|
|
)
|
|
{
|
|
PrintMsgOnConsole (MSG_HELP);
|
|
|
|
#ifdef PRERELEASE
|
|
printf ("\nAdditional PRERELEASE options:\n\n"
|
|
"/tf Uses full transport instead of v1 transport\n"
|
|
"/tc Enable compression\n"
|
|
"/ta Enable automatic capability (for homenet transport)\n"
|
|
"/ti:<tag> Specify an identity tag for the homenet transprot\n"
|
|
" Default is user name\n"
|
|
"/t:<name> Specifies transport to use\n"
|
|
"/r Start in recovery mode\n"
|
|
);
|
|
#endif
|
|
|
|
UtTerminate ();
|
|
exit (1);
|
|
}
|
|
|
|
VOID
|
|
pSwitchToClassicDesktop (
|
|
IN PCTSTR Args
|
|
)
|
|
{
|
|
HKEY key = NULL;
|
|
TCHAR data[] = TEXT("0");
|
|
|
|
//
|
|
// The only thing that we need to do is to turn off:
|
|
// HKCU\Software\Microsoft\Windows\CurrentVersion\ThemeManager [ThemeActive]
|
|
//
|
|
key = OpenRegKeyStr (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager"));
|
|
|
|
if (key) {
|
|
|
|
RegSetValueEx (
|
|
key,
|
|
TEXT("ThemeActive"),
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)data,
|
|
sizeof (data)
|
|
);
|
|
|
|
CloseRegKey (key);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
pSwitchToClassicTaskBar (
|
|
IN PCTSTR Args
|
|
)
|
|
{
|
|
HKEY key = NULL;
|
|
DWORD dataType;
|
|
DWORD dataSize = 0;
|
|
PBYTE data = NULL;
|
|
PREGSHELLSTATE shellState = NULL;
|
|
LONG result;
|
|
|
|
//
|
|
// The only thing that we need to do is to turn off the fStartPanelOn field in:
|
|
// HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer [ShellState]
|
|
//
|
|
key = OpenRegKeyStr (TEXT("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"));
|
|
|
|
if (key) {
|
|
|
|
result = RegQueryValueEx (
|
|
key,
|
|
TEXT ("ShellState"),
|
|
NULL,
|
|
&dataType,
|
|
NULL,
|
|
&dataSize
|
|
);
|
|
|
|
if ((result == ERROR_SUCCESS) || (result == ERROR_MORE_DATA)) {
|
|
data = MemAllocUninit (dataSize);
|
|
if (data) {
|
|
result = RegQueryValueEx (
|
|
key,
|
|
TEXT ("ShellState"),
|
|
NULL,
|
|
&dataType,
|
|
data,
|
|
&dataSize
|
|
);
|
|
if ((result == ERROR_SUCCESS) &&
|
|
(dataType == REG_BINARY) &&
|
|
(dataSize == sizeof (REGSHELLSTATE))
|
|
) {
|
|
if (dataType == REG_BINARY) {
|
|
shellState = (PREGSHELLSTATE) data;
|
|
shellState->ss.fStartPanelOn = FALSE;
|
|
RegSetValueEx (
|
|
key,
|
|
TEXT("ShellState"),
|
|
0,
|
|
REG_BINARY,
|
|
(PBYTE)data,
|
|
dataSize
|
|
);
|
|
}
|
|
}
|
|
FreeAlloc (data);
|
|
}
|
|
}
|
|
|
|
CloseRegKey (key);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
pRegisterFonts (
|
|
IN PCTSTR Args
|
|
)
|
|
{
|
|
WIN32_FIND_DATA findData;
|
|
HANDLE findHandle = INVALID_HANDLE_VALUE;
|
|
PTSTR fontDir = NULL;
|
|
TCHAR fontPattern [MAX_PATH];
|
|
//
|
|
// Let's (re)register all the fonts (in case the user migrated some new ones).
|
|
//
|
|
fontDir = pGetShellFolderPath (CSIDL_FONTS);
|
|
if (fontDir) {
|
|
StringCopyTcharCount (fontPattern, fontDir, ARRAYSIZE (fontPattern) - 4);
|
|
StringCat (fontPattern, TEXT("\\*.*"));
|
|
findHandle = FindFirstFile (fontPattern, &findData);
|
|
if (findHandle != INVALID_HANDLE_VALUE) {
|
|
do {
|
|
AddFontResource (findData.cFileName);
|
|
} while (FindNextFile (findHandle, &findData));
|
|
FindClose (findHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
pLoadstateExecute (
|
|
IN PCTSTR ExecuteArgs
|
|
)
|
|
{
|
|
PCTSTR funcName = NULL;
|
|
PCTSTR funcArgs = NULL;
|
|
|
|
funcName = ExecuteArgs;
|
|
if (!funcName || !(*funcName)) {
|
|
return FALSE;
|
|
}
|
|
funcArgs = _tcschr (funcName, 0);
|
|
if (funcArgs) {
|
|
funcArgs ++;
|
|
if (!(*funcArgs)) {
|
|
funcArgs = NULL;
|
|
}
|
|
}
|
|
// BUGBUG - temporary, make a macro expansion list out of it
|
|
if (StringIMatch (funcName, TEXT("SwitchToClassicDesktop"))) {
|
|
pSwitchToClassicDesktop (funcArgs);
|
|
}
|
|
if (StringIMatch (funcName, TEXT("SwitchToClassicTaskBar"))) {
|
|
pSwitchToClassicTaskBar (funcArgs);
|
|
}
|
|
if (StringIMatch (funcName, TEXT("RegisterFonts"))) {
|
|
pRegisterFonts (funcArgs);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
ULONG_PTR
|
|
pSaveMsgCallback (
|
|
UINT Message,
|
|
ULONG_PTR Arg
|
|
)
|
|
{
|
|
#ifdef PRERELEASE
|
|
PRMEDIA_EXTRADATA extraData;
|
|
#endif
|
|
|
|
switch (Message) {
|
|
|
|
#ifdef PRERELEASE
|
|
case TRANSPORTMESSAGE_READY_TO_CONNECT:
|
|
{
|
|
TCHAR msg[512];
|
|
|
|
wsprintf (msg, TEXT("Do you want to connect to %s?"), (PCTSTR) Arg);
|
|
if (MessageBox (NULL, msg, TEXT("Question For You"), MB_YESNO|MB_SYSTEMMODAL) == IDYES) {
|
|
SetEvent (g_CallbackEvent);
|
|
return APPRESPONSE_SUCCESS;
|
|
}
|
|
|
|
return APPRESPONSE_FAIL;
|
|
}
|
|
|
|
case TRANSPORTMESSAGE_RMEDIA_LOAD:
|
|
extraData = (PRMEDIA_EXTRADATA) Arg;
|
|
if (!extraData) {
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("Please insert the next media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
}
|
|
if (extraData->MediaNumber == 1) {
|
|
switch (extraData->LastError) {
|
|
case RMEDIA_ERR_NOERROR:
|
|
return TRUE;
|
|
case RMEDIA_ERR_WRONGMEDIA:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("You have inserted the wrong media.\n\nPlease insert the first media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
case RMEDIA_ERR_DISKFULL:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("The media you inserted does not have enough free space.\n\nPlease insert the first media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
case RMEDIA_ERR_WRITEPROTECT:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("The media you inserted is write protected.\n\nPlease insert the first media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
case RMEDIA_ERR_NOTREADY:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("The drive is not ready for use. Please check the drive and make sure that a disk is inserted and that the drive door is closed."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
case RMEDIA_ERR_CRITICAL:
|
|
return FALSE;
|
|
default:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("Your media is toast.\n\nPlease insert the first media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
}
|
|
} else {
|
|
switch (extraData->LastError) {
|
|
case RMEDIA_ERR_NOERROR:
|
|
return TRUE;
|
|
case RMEDIA_ERR_WRONGMEDIA:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("You have inserted the wrong media.\n\nPlease insert the next media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
case RMEDIA_ERR_DISKFULL:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("The media you inserted does not have enough free space.\n\nPlease insert the next media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
case RMEDIA_ERR_WRITEPROTECT:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("The media you inserted is write protected.\n\nPlease insert the next media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
case RMEDIA_ERR_NOTREADY:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("The drive is not ready for use. Please check the drive and make sure that a disk is inserted and that the drive door is closed."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
case RMEDIA_ERR_CRITICAL:
|
|
return FALSE;
|
|
default:
|
|
return (MessageBox (
|
|
NULL,
|
|
TEXT("Your media is toast.\n\nPlease insert the next media in your drive."),
|
|
TEXT("LoadState"),
|
|
MB_OKCANCEL
|
|
) == IDOK);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
case ISMMESSAGE_EXECUTE_REFRESH:
|
|
pLoadstateExecute ((PCTSTR) Arg);
|
|
return APPRESPONSE_SUCCESS;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
pIsUserAdmin (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns TRUE if the caller's process is a member of the
|
|
Administrators local group.
|
|
|
|
Caller is NOT expected to be impersonating anyone and IS expected to be
|
|
able to open their own process and process token.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Caller has Administrators local group.
|
|
|
|
FALSE - Caller does not have Administrators local group.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE token;
|
|
DWORD bytesRequired;
|
|
PTOKEN_GROUPS groups;
|
|
BOOL b;
|
|
DWORD i;
|
|
SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
|
|
PSID administratorsGroup;
|
|
|
|
if (ISWIN9X()) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Open the process token.
|
|
//
|
|
if (!OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
|
return FALSE;
|
|
}
|
|
|
|
b = FALSE;
|
|
groups = NULL;
|
|
|
|
//
|
|
// Get group information.
|
|
//
|
|
if (!GetTokenInformation (token, TokenGroups, NULL, 0, &bytesRequired) &&
|
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER
|
|
) {
|
|
|
|
groups = (PTOKEN_GROUPS) MemAllocUninit (bytesRequired);
|
|
b = GetTokenInformation (token, TokenGroups, groups, bytesRequired, &bytesRequired);
|
|
}
|
|
|
|
if (b) {
|
|
|
|
b = AllocateAndInitializeSid (
|
|
&ntAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&administratorsGroup
|
|
);
|
|
|
|
if (b) {
|
|
|
|
//
|
|
// See if the user has the administrator group.
|
|
//
|
|
b = FALSE;
|
|
for (i = 0 ; i < groups->GroupCount ; i++) {
|
|
if (EqualSid (groups->Groups[i].Sid, administratorsGroup)) {
|
|
b = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreeSid (administratorsGroup);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up and return.
|
|
//
|
|
|
|
if (groups) {
|
|
FreeAlloc (groups);
|
|
}
|
|
|
|
CloseHandle (token);
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
pMyLogCallback (
|
|
IN PLOGARG LogArg
|
|
)
|
|
{
|
|
if (LogArg->Debug) {
|
|
DEBUGDIRECT (LogArg->Type, LogArg->FormattedMessage);
|
|
} else {
|
|
if (StringIMatchA (LogArg->Type, LOG_ERROR)) {
|
|
if (g_ReturnCode == RETURN_SUCCESS) {
|
|
g_ReturnCode = g_ContinueOnError?RETURN_IGNORED_ERROR:RETURN_ERROR;
|
|
}
|
|
if (g_ReturnCode == RETURN_IGNORED_ERROR) {
|
|
g_ReturnCode = g_ContinueOnError?RETURN_IGNORED_ERROR:RETURN_ERROR;
|
|
}
|
|
} else if (StringIMatchA (LogArg->Type, LOG_MODULE_ERROR) ||
|
|
StringIMatchA (LogArg->Type, LOG_FATAL_ERROR)) {
|
|
g_ReturnCode = RETURN_FATAL_ERROR;
|
|
}
|
|
LOGDIRECT (LogArg->Type, LogArg->FormattedMessage);
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
VOID
|
|
pStopAndDisplayInfs (
|
|
IN PGROWBUFFER InputInfs,
|
|
IN BOOL Begin
|
|
)
|
|
{
|
|
MULTISZ_ENUM infEnum;
|
|
|
|
if (MessageBox (
|
|
NULL,
|
|
TEXT("LoadState stopped. Do you want to display all loaded INFs?"),
|
|
Begin?TEXT("LoadState-Begin"):TEXT("LoadState-End"),
|
|
MB_YESNO
|
|
) == IDYES) {
|
|
//
|
|
// now let's open append all INF files and pass the HINF to
|
|
// everybody.
|
|
//
|
|
if (EnumFirstMultiSz (&infEnum, (PCTSTR)InputInfs->Buf)) {
|
|
do {
|
|
ShellExecute (NULL, TEXT("open"), infEnum.CurrentString, NULL, NULL, SW_SHOWNORMAL);
|
|
} while (EnumNextMultiSz (&infEnum));
|
|
}
|
|
MessageBox (NULL, TEXT("Press OK to continue..."), TEXT("LoadState-Begin"), MB_OK);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
pOpenOrAppendInfFile (
|
|
IN HINF *InfHandle,
|
|
IN PCTSTR Filename
|
|
)
|
|
{
|
|
BOOL result = TRUE;
|
|
|
|
if (*InfHandle == INVALID_HANDLE_VALUE) {
|
|
*InfHandle = SetupOpenInfFile (Filename, NULL, INF_STYLE_WIN4 | INF_STYLE_OLDNT, NULL);
|
|
if (*InfHandle == INVALID_HANDLE_VALUE) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_OPEN_FILE, Filename));
|
|
result = FALSE;
|
|
}
|
|
} else {
|
|
if (!SetupOpenAppendInfFile (Filename, *InfHandle, NULL)) {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_CANT_OPEN_FILE, Filename));
|
|
result = FALSE;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PTSTR
|
|
pGetShellFolderPath (
|
|
IN INT Folder
|
|
)
|
|
{
|
|
PTSTR result = NULL;
|
|
HRESULT hResult;
|
|
BOOL b;
|
|
LPITEMIDLIST localpidl = NULL;
|
|
IMalloc *mallocFn;
|
|
|
|
hResult = SHGetMalloc (&mallocFn);
|
|
if (hResult != S_OK) {
|
|
return NULL;
|
|
}
|
|
|
|
hResult = SHGetSpecialFolderLocation (NULL, Folder, &localpidl);
|
|
|
|
if (hResult == S_OK) {
|
|
|
|
result = (PTSTR) LocalAlloc (LPTR, MAX_PATH);
|
|
if (result) {
|
|
b = SHGetPathFromIDList (localpidl, result);
|
|
|
|
if (b) {
|
|
return result;
|
|
}
|
|
|
|
LocalFree (result);
|
|
}
|
|
}
|
|
|
|
if (localpidl) {
|
|
mallocFn->lpVtbl->Free (mallocFn, localpidl);
|
|
localpidl = NULL;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
VOID
|
|
__cdecl
|
|
_tmain (
|
|
IN INT Argc,
|
|
IN PCTSTR Argv[]
|
|
)
|
|
{
|
|
TCHAR appPath[MAX_PATH_PLUS_NUL];
|
|
PCTSTR delayedCmd = NULL;
|
|
TCHAR ismPath[MAX_PATH_PLUS_NUL];
|
|
TCHAR infPath[MAX_PATH_PLUS_NUL];
|
|
PTSTR iconLibRoot = NULL;
|
|
TCHAR iconLibSrc[MAX_PATH] = TEXT("");
|
|
TCHAR iconLibDest[MAX_PATH] = TEXT("");
|
|
BOOL iconLibFound = FALSE;
|
|
PCTSTR commandLine = NULL;
|
|
DWORD err;
|
|
PTSTR p;
|
|
MIG_TRANSPORTID transportId;
|
|
MIG_TRANSPORTSTORAGEID transportStorageId;
|
|
MULTISZ_ENUM infEnum;
|
|
HINF infHandle = INVALID_HANDLE_VALUE;
|
|
ENVENTRY_STRUCT infHandleStruct;
|
|
MIG_OBJECTSTRINGHANDLE objectPattern;
|
|
MIG_OBJECT_ENUM objectEnum;
|
|
MULTISZ_ENUM e;
|
|
DWORD appStatus;
|
|
BOOL loadResult;
|
|
BOOL storagePathIsValid = FALSE;
|
|
BOOL terminateIsm = FALSE;
|
|
BOOL logEnabled = FALSE;
|
|
PCTSTR msg;
|
|
#ifdef UNICODE
|
|
PCSTR ansimsg;
|
|
#endif
|
|
PCTSTR argArray[1];
|
|
BOOL fail;
|
|
TOOLARGS args;
|
|
|
|
#ifdef PRERELEASE
|
|
g_CallbackEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
#endif
|
|
|
|
SET_RESETLOG();
|
|
UtInitialize (NULL);
|
|
|
|
SuppressAllLogPopups (TRUE);
|
|
|
|
// this part is for matching thread's locale to the console code page
|
|
CallSetThreadUILanguage ();
|
|
|
|
PrintMsgOnConsole (MSG_RUNNING);
|
|
|
|
// initialize app journal path
|
|
g_JournalPath [0] = 0;
|
|
if (GetWindowsDirectory (g_JournalPath, ARRAYSIZE (g_JournalPath))) {
|
|
StringCopy (AppendWack (g_JournalPath), TEXT("LOADSTATE.JRN"));
|
|
}
|
|
|
|
GetModuleFileName (NULL, appPath, ARRAYSIZE(appPath));
|
|
delayedCmd = JoinText (appPath, TEXT(" /d"));
|
|
p = _tcsrchr (appPath, TEXT('\\'));
|
|
if (p) {
|
|
*p = 0;
|
|
}
|
|
|
|
iconLibSrc [0] = 0;
|
|
GetSystemDirectory (iconLibSrc, ARRAYSIZE(iconLibSrc));
|
|
StringCopy (AppendWack (iconLibSrc), TEXT("usmt\\iconlib.dll"));
|
|
|
|
//
|
|
// Parse the command line
|
|
//
|
|
|
|
fail = TRUE;
|
|
|
|
switch (ParseToolCmdLine (FALSE, &args, Argc, Argv)) {
|
|
|
|
case PARSE_SUCCESS:
|
|
fail = FALSE;
|
|
break;
|
|
|
|
case PARSE_MULTI_LOG:
|
|
PrintMsgOnConsole (MSG_MULTI_LOG);
|
|
g_ReturnCode = RETURN_FATAL_ERROR;
|
|
goto END;
|
|
|
|
case PARSE_BAD_LOG:
|
|
argArray[0] = args.LogFile;
|
|
msg = ParseMessageID (MSG_CANT_OPEN_LOG, argArray);
|
|
if (msg) {
|
|
#ifdef UNICODE
|
|
ansimsg = ConvertWtoA (msg);
|
|
printf ("%s", ansimsg);
|
|
FreeConvertedStr (ansimsg);
|
|
#else
|
|
printf ("%s", msg);
|
|
#endif
|
|
FreeStringResource (msg);
|
|
}
|
|
|
|
g_ReturnCode = RETURN_FATAL_ERROR;
|
|
goto END;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (fail) {
|
|
pHelpAndExit();
|
|
}
|
|
|
|
g_ContinueOnError = args.ContinueOnError;
|
|
|
|
if (args.HackHiveOn) {
|
|
// This is the second copy of loadstate.exe that's running.
|
|
// We are going to wait for the first copy to finish and then
|
|
// we are going to attempt to unload the user's hive.
|
|
DWORD processId = 0;
|
|
HANDLE processHandle = NULL;
|
|
DWORD waitResult = 0;
|
|
|
|
_stscanf (args.HackProcessId, TEXT("%lx"), &(processId));
|
|
|
|
processHandle = OpenProcess (SYNCHRONIZE, TRUE, processId);
|
|
|
|
if (processHandle) {
|
|
|
|
waitResult = WaitForSingleObject (processHandle, INFINITE);
|
|
// we don't really care about the result. We are going to
|
|
// attempt to unload the hive anyway
|
|
}
|
|
|
|
// now let's try to unload the hive
|
|
g_ReturnCode = RegUnLoadKey (HKEY_USERS, args.HackMappedHive);
|
|
|
|
if (g_ReturnCode == ERROR_SUCCESS) {
|
|
PrintMsgOnConsole (MSG_SUCCESS);
|
|
} else {
|
|
PrintMsgOnConsole (MSG_FAILED_NO_LOG);
|
|
}
|
|
|
|
UtTerminate ();
|
|
|
|
while (g_Break) {
|
|
// infinite loop, because we'll get terminated in the ctrl+c handler
|
|
Sleep (50);
|
|
}
|
|
|
|
exit (g_ReturnCode);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
if (DoesFileExist (TEXT("C:\\LOADSTATE.BEGIN"))) {
|
|
pStopAndDisplayInfs (&args.InputInf, TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
LogReInit (NULL, NULL, args.LogFile ? args.LogFile : TEXT("loadstate.log"), NULL);
|
|
logEnabled = TRUE;
|
|
|
|
// Let's log the command line that was used
|
|
commandLine = GetCommandLine ();
|
|
if (commandLine) {
|
|
LOG ((LOG_INFORMATION, (PCSTR)MSG_COMMAND_LINE_USED, commandLine));
|
|
}
|
|
|
|
//
|
|
// Check requirements
|
|
//
|
|
|
|
if (args.BadInfs.End || args.MultiInfs.End) {
|
|
SetLastError (ERROR_BAD_COMMAND);
|
|
|
|
if (EnumFirstMultiSz (&e, (PCTSTR) args.BadInfs.Buf)) {
|
|
do {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_INF_FILE_NOT_FOUND, e.CurrentString));
|
|
} while (EnumNextMultiSz (&e));
|
|
}
|
|
|
|
if (EnumFirstMultiSz (&e, (PCTSTR) args.MultiInfs.Buf)) {
|
|
do {
|
|
LOG ((LOG_ERROR, (PCSTR) MSG_INF_SPECIFIED_MORE_THAN_ONE, e.CurrentString));
|
|
} while (EnumNextMultiSz (&e));
|
|
}
|
|
|
|
g_ReturnCode = RETURN_ERROR;
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_CMD_LINE_ERROR));
|
|
goto END;
|
|
}
|
|
|
|
if (!GetFilePath (TEXT("migism.inf"), ismPath, ARRAYSIZE(ismPath))) {
|
|
g_ReturnCode = RETURN_ERROR;
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_ISM_INF_MISSING));
|
|
goto END;
|
|
}
|
|
|
|
if (ISWIN9X()) {
|
|
g_ReturnCode = RETURN_ERROR;
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_NT_REQUIRED));
|
|
goto END;
|
|
}
|
|
|
|
#ifndef UNICODE
|
|
// ANSI version of loadstate.exe is not tested, let's not allow it to run
|
|
g_ReturnCode = RETURN_ERROR;
|
|
SetLastError (ERROR_APP_WRONG_OS);
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_UNICODE_REQUIRED));
|
|
goto END;
|
|
#endif
|
|
|
|
if (!pIsUserAdmin() && !args.DelayedOpsOn) {
|
|
g_ReturnCode = RETURN_ERROR;
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_ADMIN_REQUIRED));
|
|
goto END;
|
|
}
|
|
|
|
//
|
|
// Initialize ISM
|
|
//
|
|
|
|
if (!IsmInitialize (ismPath, pSaveMsgCallback, pMyLogCallback)) {
|
|
g_ReturnCode = RETURN_ERROR;
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_CANT_START_ISM));
|
|
goto END;
|
|
}
|
|
|
|
terminateIsm = TRUE;
|
|
SetLogVerbosity (args.VerboseLevel);
|
|
|
|
SetConsoleCtrlHandler (CtrlCRoutine, TRUE);
|
|
|
|
// upload environment variables
|
|
UploadEnvVars (PLATFORM_DESTINATION);
|
|
|
|
// we will try to copy iconlib.dll from our directory into "Common AppData" directory
|
|
// If we don't succeed, we will not set the S_ENV_ICONLIB env variable
|
|
|
|
iconLibFound = FALSE;
|
|
|
|
iconLibRoot = pGetShellFolderPath (CSIDL_COMMON_APPDATA);
|
|
if (iconLibRoot) {
|
|
__try {
|
|
StringCopy (iconLibDest, iconLibRoot);
|
|
StringCopy (AppendWack (iconLibDest), TEXT("Microsoft"));
|
|
if (!CreateDirectory (iconLibDest, NULL)) {
|
|
err = GetLastError ();
|
|
if (err != ERROR_ALREADY_EXISTS) {
|
|
__leave;
|
|
}
|
|
}
|
|
StringCopy (AppendWack (iconLibDest), TEXT("USMT"));
|
|
if (!CreateDirectory (iconLibDest, NULL)) {
|
|
err = GetLastError ();
|
|
if (err != ERROR_ALREADY_EXISTS) {
|
|
__leave;
|
|
}
|
|
}
|
|
StringCopy (AppendWack (iconLibDest), TEXT("iconlib.dll"));
|
|
if (!CopyFile (iconLibSrc, iconLibDest, TRUE)) {
|
|
err = GetLastError ();
|
|
if (err != ERROR_FILE_EXISTS) {
|
|
__leave;
|
|
}
|
|
}
|
|
iconLibFound = TRUE;
|
|
}
|
|
__finally {
|
|
LocalFree (iconLibRoot);
|
|
iconLibRoot = NULL;
|
|
}
|
|
}
|
|
|
|
// Set the icon lib data
|
|
if (iconLibFound) {
|
|
IsmSetEnvironmentString (PLATFORM_DESTINATION, NULL, S_ENV_ICONLIB, iconLibDest);
|
|
}
|
|
|
|
infHandle = InitRequiredInfs (appPath, (PCSTR) MSG_CANT_OPEN_REQUIRED_FILE);
|
|
|
|
if (infHandle != INVALID_HANDLE_VALUE) {
|
|
infHandleStruct.Type = ENVENTRY_BINARY;
|
|
infHandleStruct.EnvBinaryData = (PVOID)(&infHandle);
|
|
infHandleStruct.EnvBinaryDataSize = sizeof (HINF);
|
|
IsmSetEnvironmentValue (PLATFORM_DESTINATION, NULL, S_GLOBAL_INF_HANDLE, &infHandleStruct);
|
|
}
|
|
|
|
if (args.UserOn) {
|
|
IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_HKCU_V1);
|
|
IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_HKCU_ON);
|
|
}
|
|
|
|
if (args.FilesOn) {
|
|
IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_ALL_FILES);
|
|
}
|
|
|
|
IsmSetPlatform (PLATFORM_DESTINATION);
|
|
|
|
if (!args.CurrentUser) {
|
|
IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_REQUIRE_DOMAIN_USER);
|
|
IsmSetEnvironmentFlag (PLATFORM_DESTINATION, NULL, S_ENV_CREATE_USER);
|
|
}
|
|
|
|
//
|
|
// Start ETM modules
|
|
//
|
|
|
|
if (!IsmStartEtmModules ()) {
|
|
if (!IsmCheckCancel()) {
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_CANT_START_ETMS));
|
|
}
|
|
goto END;
|
|
}
|
|
|
|
if (args.DelayedOpsOn) {
|
|
|
|
appStatus = ReadAppStatus (g_JournalPath);
|
|
|
|
if ((appStatus != LOADSTATE_COMPLETED) &&
|
|
(appStatus != LOADSTATE_EXECUTE) &&
|
|
(appStatus != 0)
|
|
) {
|
|
|
|
// unknown state, just cleanup the delayed ops journal
|
|
IsmExecute (EXECUTETYPE_DELAYEDOPERATIONSCLEANUP);
|
|
|
|
} else {
|
|
|
|
IsmSetRollbackJournalType (FALSE);
|
|
if (appStatus == LOADSTATE_EXECUTE) {
|
|
IsmRollback ();
|
|
}
|
|
// write the app status
|
|
WriteAppStatus (g_JournalPath, LOADSTATE_EXECUTE);
|
|
IsmExecute (EXECUTETYPE_DELAYEDOPERATIONS);
|
|
// write the app status
|
|
WriteAppStatus (g_JournalPath, LOADSTATE_COMPLETED);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Initialize transport
|
|
//
|
|
|
|
if (!IsmStartTransport ()) {
|
|
if (!IsmCheckCancel()) {
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_CANT_START_TRANS));
|
|
}
|
|
goto END;
|
|
}
|
|
|
|
transportStorageId = IsmRegisterTransport (args.TransportName);
|
|
|
|
if (args.FullTransport) {
|
|
transportId = IsmSelectTransport (transportStorageId, TRANSPORTTYPE_FULL, args.Capabilities);
|
|
} else {
|
|
transportId = IsmSelectTransport (transportStorageId, TRANSPORTTYPE_LIGHT, args.Capabilities);
|
|
}
|
|
|
|
if (!transportId) {
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_TRANSPORT_UNAVAILABLE));
|
|
goto END;
|
|
}
|
|
|
|
#ifdef PRERELEASE
|
|
|
|
IsmSetEnvironmentString (PLATFORM_DESTINATION, NULL, TRANSPORT_ENVVAR_HOMENET_TAG, args.Tag);
|
|
|
|
#endif
|
|
|
|
if (!IsmSetTransportStorage (
|
|
PLATFORM_DESTINATION,
|
|
transportId,
|
|
transportStorageId,
|
|
args.Capabilities,
|
|
args.StoragePath,
|
|
&storagePathIsValid,
|
|
NULL
|
|
) ||
|
|
storagePathIsValid == FALSE) {
|
|
if (!IsmCheckCancel()) {
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_TRANSPORT_STORAGE_INVALID, args.StoragePath));
|
|
}
|
|
goto END;
|
|
}
|
|
|
|
#ifdef PRERELEASE
|
|
if (args.Capabilities & CAPABILITY_AUTOMATED) {
|
|
WaitForSingleObject (g_CallbackEvent, INFINITE);
|
|
}
|
|
#endif
|
|
|
|
appStatus = ReadAppStatus (g_JournalPath);
|
|
|
|
if (appStatus != LOADSTATE_COMPLETED) {
|
|
|
|
// if we need to, call IsmRollback
|
|
if (appStatus == LOADSTATE_EXECUTE) {
|
|
|
|
IsmRollback ();
|
|
|
|
appStatus = LOADSTATE_LOAD;
|
|
}
|
|
|
|
#ifdef PRERELEASE
|
|
if (!args.Recovery) {
|
|
#endif
|
|
// write the app status
|
|
WriteAppStatus (g_JournalPath, LOADSTATE_LOAD);
|
|
|
|
//
|
|
// Recover the state
|
|
//
|
|
|
|
if (appStatus == LOADSTATE_LOAD) {
|
|
loadResult = IsmResumeLoad ();
|
|
if (!loadResult) {
|
|
loadResult = IsmLoad ();
|
|
}
|
|
} else {
|
|
loadResult = IsmLoad ();
|
|
}
|
|
|
|
if (loadResult) {
|
|
|
|
// before we go further, let's see if we wanted to change the user name and/or domain
|
|
if (args.NewDomainName) {
|
|
IsmSetEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT("ALTUSERDOMAIN"), args.NewDomainName);
|
|
}
|
|
if (args.NewUserName) {
|
|
IsmSetEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, TEXT("ALTUSERNAME"), args.NewUserName);
|
|
}
|
|
|
|
// Load INFs that were specified in scanstate
|
|
|
|
if (!args.NoScanStateInfs) {
|
|
objectPattern = IsmCreateSimpleObjectPattern (TEXT("External"), FALSE, S_INF_OBJECT_NAME TEXT("*"), TRUE);
|
|
|
|
if (IsmEnumFirstSourceObject(&objectEnum, MIG_DATA_TYPE, objectPattern)) {
|
|
do {
|
|
if (IsmGetControlFile (objectEnum.ObjectTypeId, objectEnum.ObjectName, infPath)) {
|
|
IsmAppendEnvironmentMultiSz (
|
|
PLATFORM_DESTINATION,
|
|
NULL,
|
|
S_INF_FILE_MULTISZ,
|
|
infPath
|
|
);
|
|
pOpenOrAppendInfFile (&infHandle, infPath);
|
|
}
|
|
} while (IsmEnumNextObject (&objectEnum));
|
|
}
|
|
IsmDestroyObjectHandle (objectPattern);
|
|
}
|
|
|
|
if (args.InputInf.Buf) {
|
|
//
|
|
// now let's open append all INF files and pass the HINF to
|
|
// everybody.
|
|
//
|
|
if (EnumFirstMultiSz (&infEnum, (PCTSTR)args.InputInf.Buf)) {
|
|
do {
|
|
IsmAppendEnvironmentMultiSz (
|
|
PLATFORM_DESTINATION,
|
|
NULL,
|
|
S_INF_FILE_MULTISZ,
|
|
infEnum.CurrentString
|
|
);
|
|
pOpenOrAppendInfFile (&infHandle, infEnum.CurrentString);
|
|
} while (EnumNextMultiSz (&infEnum));
|
|
}
|
|
}
|
|
|
|
if (!args.FullTransport) {
|
|
|
|
//
|
|
// Execute the preparsing to populate components
|
|
//
|
|
|
|
if (IsmExecute (EXECUTETYPE_EXECUTESOURCE_PARSING)) {
|
|
|
|
IsmSelectMasterGroup (MASTERGROUP_ALL, TRUE);
|
|
|
|
if (!args.SystemOn) {
|
|
IsmSelectMasterGroup (MASTERGROUP_SYSTEM, FALSE);
|
|
IsmSelectMasterGroup (MASTERGROUP_USER, FALSE);
|
|
IsmSelectMasterGroup (MASTERGROUP_APP, FALSE);
|
|
}
|
|
|
|
SelectComponentsViaInf (infHandle);
|
|
|
|
//
|
|
// Execute data gather
|
|
//
|
|
|
|
if (!IsmExecute (EXECUTETYPE_EXECUTESOURCE)) {
|
|
if (!IsmCheckCancel()) {
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_CANT_EXECUTE_SOURCE));
|
|
}
|
|
}
|
|
|
|
} else {
|
|
if (!IsmCheckCancel()) {
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_CANT_EXECUTE_SOURCE));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Apply saved state
|
|
//
|
|
|
|
// write the app status
|
|
WriteAppStatus (g_JournalPath, LOADSTATE_EXECUTE);
|
|
|
|
IsmSetDelayedOperationsCommand (delayedCmd);
|
|
|
|
if (!IsmExecute (EXECUTETYPE_EXECUTEDESTINATION)) {
|
|
if (!IsmCheckCancel()) {
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_CANT_EXECUTE_DEST));
|
|
}
|
|
}
|
|
|
|
} else {
|
|
LOG ((LOG_FATAL_ERROR, (PCSTR) MSG_CANT_FIND_SAVED_STATE));
|
|
}
|
|
|
|
#ifdef PRERELEASE
|
|
}
|
|
#endif
|
|
// write the app status
|
|
WriteAppStatus (g_JournalPath, LOADSTATE_COMPLETED);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We're done!
|
|
//
|
|
|
|
SetupCloseInfFile (infHandle);
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
if (DoesFileExist (TEXT("C:\\LOADSTATE.END"))) {
|
|
pStopAndDisplayInfs (&args.InputInf, FALSE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
END:
|
|
|
|
// If we were successfull, it is time to check for registry leaks
|
|
// We call OE DLL entries and sometimes they leak registry keys.
|
|
// When we create a new profile this is particularly bad because
|
|
// we cannot unload the hive.
|
|
if (!g_Break) {
|
|
if (g_ReturnCode == RETURN_SUCCESS) {
|
|
DWORD sizeNeeded;
|
|
HKEY tempKey = NULL;
|
|
PTSTR mappedKeyStr = NULL;
|
|
DWORD processId = 0;
|
|
TCHAR tempStr1 [sizeof (DWORD) * 2 + sizeof(TEXT(" /hp: 0x")) + 1];
|
|
PCTSTR tempStr2 = NULL;
|
|
PTSTR tempStr3 = NULL;
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
// Let's get the location of the mapped hive
|
|
if (IsmGetEnvironmentString (
|
|
PLATFORM_DESTINATION,
|
|
NULL,
|
|
S_VER_HIVEMAPPEDLOCATION,
|
|
NULL,
|
|
0,
|
|
&sizeNeeded
|
|
)) {
|
|
|
|
mappedKeyStr = AllocPathString (sizeNeeded);
|
|
if (mappedKeyStr) {
|
|
|
|
if (IsmGetEnvironmentString (
|
|
PLATFORM_DESTINATION,
|
|
NULL,
|
|
S_VER_HIVEMAPPEDLOCATION,
|
|
mappedKeyStr,
|
|
sizeNeeded,
|
|
NULL
|
|
)) {
|
|
tempKey = OpenRegKey (HKEY_USERS, mappedKeyStr);
|
|
if (tempKey) {
|
|
// Yep, we had a leak and the hive was not unloaded
|
|
LOG ((LOG_INFORMATION, (PCSTR)MSG_UNLOAD_HIVE_HACK));
|
|
|
|
// What we are going to do is we are going to launch
|
|
// ourself passing the mappedKeyStr and our process ID
|
|
processId = GetCurrentProcessId ();
|
|
if (processId) {
|
|
wsprintf (tempStr1, TEXT(" /hp:0x%08X "), processId);
|
|
tempStr2 = JoinText (TEXT("/hm:"), mappedKeyStr);
|
|
if (tempStr2) {
|
|
|
|
tempStr3 = JoinText (tempStr1, tempStr2);
|
|
if (tempStr3) {
|
|
|
|
if (GetModuleFileName (NULL, appPath, ARRAYSIZE(appPath))) {
|
|
ZeroMemory (&si, sizeof (si));
|
|
if (CreateProcess (
|
|
appPath,
|
|
tempStr3,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NEW_CONSOLE,
|
|
NULL,
|
|
NULL,
|
|
&si,
|
|
&pi
|
|
)) {
|
|
CloseHandle (pi.hThread);
|
|
CloseHandle (pi.hProcess);
|
|
}
|
|
}
|
|
FreeText (tempStr3);
|
|
}
|
|
FreeText (tempStr2);
|
|
}
|
|
}
|
|
|
|
CloseRegKey (tempKey);
|
|
}
|
|
}
|
|
FreePathString (mappedKeyStr);
|
|
mappedKeyStr = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (terminateIsm) {
|
|
if (!g_Break) {
|
|
pCleanUpApp();
|
|
}
|
|
}
|
|
|
|
if (delayedCmd) {
|
|
FreeText (delayedCmd);
|
|
delayedCmd = NULL;
|
|
}
|
|
GbFree (&args.InputInf);
|
|
GbFree (&args.BadInfs);
|
|
GbFree (&args.MultiInfs);
|
|
|
|
if (!g_Break) {
|
|
if (g_ReturnCode == RETURN_SUCCESS) {
|
|
PrintMsgOnConsole (MSG_SUCCESS);
|
|
} else if (g_ReturnCode == RETURN_IGNORED_ERROR) {
|
|
if (logEnabled) {
|
|
PrintMsgOnConsole (MSG_IGNORE_FAILED_WITH_LOG);
|
|
} else {
|
|
PrintMsgOnConsole (MSG_IGNORE_FAILED_NO_LOG);
|
|
}
|
|
g_ReturnCode = RETURN_SUCCESS;
|
|
} else {
|
|
if (logEnabled) {
|
|
PrintMsgOnConsole (MSG_FAILED_WITH_LOG);
|
|
} else {
|
|
PrintMsgOnConsole (MSG_FAILED_NO_LOG);
|
|
}
|
|
}
|
|
}
|
|
|
|
UtTerminate ();
|
|
|
|
while (g_Break) {
|
|
// infinite loop, because we'll get terminated in the ctrl+c handler
|
|
Sleep (50);
|
|
}
|
|
|
|
exit (g_ReturnCode);
|
|
}
|