Leaked source code of windows server 2003
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.
 
 
 
 
 
 

924 lines
31 KiB

/*****************************************************************************\
MAIN.CPP
Microsoft Confidential
Copyright (c) Microsoft Corporation 1998
All rights reserved
Contains...
1/99 - JCOHEN
Created main program file.
\*****************************************************************************/
#include "precomp.h"
#include "msobmain.h"
#include "setupkey.h"
#include "resource.h"
#define ICWDESKTOPCHANGED L"DesktopChanged"
#define MAX_MESSAGE_LEN 256
#define ICWSETTINGSPATH L"Software\\Microsoft\\Internet Connection Wizard"
#define ICW_REGKEYCOMPLETED L"Completed"
#define REGSTR_PATH_SETUPKEY REGSTR_PATH_SETUP REGSTR_KEY_SETUP
#define REGSTR_PATH_SYSTEMSETUPKEY L"System\\Setup"
#define REGSTR_VALUE_CMDLINE L"CmdLine"
#define REGSTR_VALUE_SETUPTYPE L"SetupType"
#define REGSTR_VALUE_MINISETUPINPROGRESS L"MiniSetupInProgress"
#define REGSTR_PATH_IEONDESKTOP REGSTR_PATH_IEXPLORER L"\\AdvancedOptions\\BROWSE\\IEONDESKTOP"
static const WCHAR g_szRegPathWelcomeICW[] = L"Welcome\\ICW";
static const WCHAR g_szAllUsers[] = L"All Users";
static const WCHAR g_szConnectApp[] = L"ICWCONN1.EXE";
static const WCHAR g_szConnectLink[] = L"Connect to the Internet";
static const WCHAR g_szOEApp[] = L"MSINM.EXE";
static const WCHAR g_szOELink[] = L"Outlook Express";
static const WCHAR g_szRegPathICWSettings[] = L"Software\\Microsoft\\Internet Connection Wizard";
static const WCHAR g_szRegValICWCompleted[] = L"Completed";
WCHAR g_szShellNext [MAX_PATH+1] = L"\0nogood";
WCHAR g_szShellNextParams [MAX_PATH+1] = L"\0nogood";
HINSTANCE g_hInstance = NULL;
/*******************************************************************
NAME: RegisterComObjects
SYNOPSIS: App entry point
********************************************************************/
BOOL SelfRegisterComObject(LPWSTR szDll, BOOL fRegister)
{
HINSTANCE hModule = LoadLibrary(szDll);
BOOL bRet = FALSE;
if (hModule)
{
HRESULT (STDAPICALLTYPE *pfn)(void);
if (fRegister)
(FARPROC&)pfn = GetProcAddress(hModule, REG_SERVER);
else
(FARPROC&)pfn = GetProcAddress(hModule, UNREG_SERVER);
if (pfn && SUCCEEDED((*pfn)()))
bRet = TRUE;
FreeLibrary(hModule);
}
return bRet;
}
// This undoes what DoDesktopChanges did
void UndoDesktopChanges()
{
WCHAR szConnectTotheInternetTitle[MAX_PATH];
HKEY hkey;
// Verify that we really changed the desktop
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
ICWSETTINGSPATH,
0,
KEY_ALL_ACCESS,
&hkey))
{
DWORD dwDesktopChanged = 0;
DWORD dwTmp = sizeof(DWORD);
DWORD dwType = 0;
if (ERROR_SUCCESS == RegQueryValueEx(hkey,
ICWDESKTOPCHANGED,
NULL,
&dwType,
(LPBYTE)&dwDesktopChanged,
&dwTmp))
{
}
RegCloseKey(hkey);
// Bail if the desktop was not changed by us
if(!dwDesktopChanged)
{
return;
}
}
// Always nuke the Connect to the internet icon
HINSTANCE hInst = LoadLibrary(OOBE_MAIN_DLL);
if (!LoadString(hInst,
IDS_CONNECT_DESKTOP_TITLE,
szConnectTotheInternetTitle,
MAX_CHARS_IN_BUFFER(szConnectTotheInternetTitle)))
{
lstrcpy(szConnectTotheInternetTitle, g_szConnectLink);
}
RemoveDesktopShortCut(szConnectTotheInternetTitle);
}
void StartIE
(
LPWSTR lpszURL
)
{
WCHAR szIEPath[MAX_PATH];
HKEY hkey;
// first get the app path
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
REGSTR_PATH_APPPATHS,
0,
KEY_READ,
&hkey) == ERROR_SUCCESS)
{
DWORD dwTmp = sizeof(szIEPath);
if(RegQueryValue(hkey, L"iexplore.exe", szIEPath, (PLONG)&dwTmp) != ERROR_SUCCESS)
{
ShellExecute(NULL, L"open",szIEPath,lpszURL,NULL,SW_NORMAL);
}
else
{
ShellExecute(NULL, L"open",L"iexplore.exe",lpszURL,NULL,SW_NORMAL);
}
RegCloseKey(hkey);
}
else
{
ShellExecute(NULL, L"open",L"iexplore.exe",lpszURL,NULL,SW_NORMAL);
}
}
void HandleShellNext()
{
DWORD dwVal = 0;
DWORD dwSize = sizeof(dwVal);
HKEY hKey = NULL;
if(RegOpenKeyEx(HKEY_CURRENT_USER,
ICWSETTINGSPATH,
0,
KEY_ALL_ACCESS,
&hKey) == ERROR_SUCCESS)
{
RegQueryValueEx(hKey,
ICW_REGKEYCOMPLETED,
0,
NULL,
(LPBYTE)&dwVal,
&dwSize);
RegCloseKey(hKey);
}
if (dwVal)
{
TRACE3(L"Starting IE because HKCU\\%s\\%s = %d", ICWSETTINGSPATH, ICW_REGKEYCOMPLETED, dwVal);
UndoDesktopChanges();
if (PathIsURL(g_szShellNext))
{
TRACE1(L"Navigating to %s", g_szShellNext);
StartIE(g_szShellNext);
}
else if(g_szShellNext[0] != L'\0')
{
// Let the shell deal with it
TRACE1(L"ShellExecuting %s", g_szShellNext);
ShellExecute(NULL, L"open",g_szShellNext,g_szShellNextParams,NULL,SW_NORMAL);
}
}
}
//+----------------------------------------------------------------------------
//
// Function: GetShellNextFromReg
//
// Synopsis: Reads the ShellNext key from the registry, and then parses it
// into a command and parameter. This key is set by
// SetShellNext in inetcfg.dll in conjunction with
// CheckConnectionWizard.
//
// Arguments: none
//
// Returns: none
//
// History: jmazner 7/9/97 Olympus #9170
//
//-----------------------------------------------------------------------------
BOOL GetShellNextFromReg
(
LPWSTR lpszCommand,
LPWSTR lpszParams
)
{
BOOL fRet = TRUE;
WCHAR szShellNextCmd [MAX_PATH] = L"\0";
DWORD dwShellNextSize = sizeof(szShellNextCmd);
LPWSTR lpszTemp = NULL;
HKEY hkey = NULL;
if( !lpszCommand || !lpszParams )
{
return FALSE;
}
if ((RegOpenKey(HKEY_CURRENT_USER, ICWSETTINGSPATH, &hkey)) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hkey,
L"ShellNext",
NULL,
NULL,
(BYTE *)szShellNextCmd,
(DWORD *)&dwShellNextSize) != ERROR_SUCCESS)
{
fRet = FALSE;
goto GetShellNextFromRegExit;
}
}
else
{
fRet = FALSE;
goto GetShellNextFromRegExit;
}
//
// This call will parse the first token into lpszCommand, and set szShellNextCmd
// to point to the remaining tokens (these will be the parameters). Need to use
// the pszTemp var because GetCmdLineToken changes the pointer's value, and we
// need to preserve lpszShellNextCmd's value so that we can GlobalFree it later.
//
lpszTemp = szShellNextCmd;
GetCmdLineToken( &lpszTemp, lpszCommand );
lstrcpy( lpszParams, lpszTemp );
//
// it's possible that the shellNext command was wrapped in quotes for
// parsing purposes. But since ShellExec doesn't understand quotes,
// we now need to remove them.
//
if( L'"' == lpszCommand[0] )
{
//
// get rid of the first quote
// note that we're shifting the entire string beyond the first quote
// plus the terminating NULL down by one byte.
//
memmove( lpszCommand, &(lpszCommand[1]), BYTES_REQUIRED_BY_SZ(lpszCommand) );
//
// now get rid of the last quote
//
lpszCommand[lstrlen(lpszCommand) - 1] = L'\0';
}
GetShellNextFromRegExit:
if (hkey)
RegCloseKey(hkey);
return fRet;
}
//+----------------------------------------------------------------------------
//
// Function: RemoveShellNextFromReg
//
// Synopsis: deletes the ShellNext reg key if present. This key is set by
// SetShellNext in inetcfg.dll in conjunction with
// CheckConnectionWizard.
//
// Arguments: none
//
// Returns: none
//
// History: jmazner 7/9/97 Olympus #9170
//
//-----------------------------------------------------------------------------
void RemoveShellNextFromReg( void )
{
HKEY hkey;
if ((RegOpenKey(HKEY_CURRENT_USER, ICWSETTINGSPATH, &hkey)) == ERROR_SUCCESS)
{
RegDeleteValue(hkey, L"ShellNext");
RegCloseKey(hkey);
}
}
//GetShellNext
//
// 5/21/97 jmazner Olympus #4157
// usage: /shellnext c:\path\executeable [parameters]
// the token following nextapp will be shellExec'd at the
// end of the "current" path. It can be anything that the shell
// knows how to handle -- an .exe, a URL, etc.. If executable
// name contains white space (eg: c:\program files\foo.exe), it
// should be wrapped in double quotes, "c:\program files\foo.exe"
// This will cause us to treat it as a single token.
//
// all consecutive subsequent tokens will
// be passed to ShellExec as the parameters until a token is
// encountered of the form /<non-slash character>. That is to say,
// the character combination // will be treated as an escape character
//
// this is easiest to explain by way of examples.
//
// examples of usage:
//
// icwconn1.exe /shellnext "C:\prog files\wordpad.exe" file.txt
// icwconn1.exe /prod IE /shellnext msimn.exe /promo MCI
// icwconn1.exe /shellnext msimn.exe //START_MAIL /promo MCI
//
// the executeable string and parameter string are limited to
// a length of MAX_PATH
//
BOOL GetShellNextToken(LPWSTR szCmdLine, LPWSTR szOut)
{
if (lstrcmpi(szOut, CMD_SHELLNEXT)==0)
{
// next token is expected to be white space
GetCmdLineToken(&szCmdLine, szOut);
if (szOut[0])
{
ZeroMemory(g_szShellNext, sizeof(g_szShellNext));
ZeroMemory(g_szShellNextParams, sizeof(g_szShellNextParams));
// Read white space
GetCmdLineToken(&szCmdLine, szOut);
//this should be the thing to ShellExec
if(*szCmdLine != L'/')
{
// watch closely, this gets a bit tricky
//
// if this command begins with a double quote, assume it ends
// in a matching quote. We do _not_ want to store the
// quotes, however, since ShellExec doesn't parse them out.
if( L'"' != szOut[0] )
{
// no need to worry about any of this quote business
lstrcpy( g_szShellNext, szOut );
}
else
{
lstrcpy( g_szShellNext, &szOut[1] );
g_szShellNext[lstrlen(g_szShellNext) - 1] = L'\0';
}
TRACE1(L"g_szShellNext = %s", g_szShellNext);
// now read in everything up to the next command line switch
// and consider it to be the parameter. Treat the sequence
// "//" as an escape sequence, and allow it through.
// Example:
// the token /whatever is considered to be a switch to
// icwconn1, and thus will break us out of the whle loop.
//
// the token //something is should be interpreted as a
// command line /something to the the ShellNext app, and
// should not break us out of the while loop.
GetCmdLineToken(&szCmdLine, szOut);
while( szOut[0] )
{
if( L'/' == szOut[0] )
{
if( L'/' != szOut[1] )
{
// it's not an escape sequence, so we're done
break;
}
else
{
// it is an escape sequence, so store it in
// the parameter list, but remove the first /
lstrcat( g_szShellNextParams, &szOut[1] );
}
}
else
{
lstrcat( g_szShellNextParams, szOut );
}
GetCmdLineToken(&szCmdLine, szOut);
}
TRACE1(L"g_szShellNextParams = %s", g_szShellNextParams);
return TRUE;
}
}
}
return FALSE;
}
void ParseCommandLine(LPTSTR lpszCmdParam, APMD *pApmd, DWORD *pProp, int *pRmdIndx)
{
if(lpszCmdParam && pApmd && pProp && pRmdIndx)
{
WCHAR szOut[MAX_PATH];
GetCmdLineToken(&lpszCmdParam, szOut);
while (szOut[0])
{
if (0 == lstrcmpi(szOut, CMD_FULLSCREENMODE))
{ // For now, full screen => OEM OOBE mode
*pProp |= (PROP_FULLSCREEN | PROP_OOBE_OEM);
*pApmd = APMD_OOBE;
}
else if (0 == lstrcmpi(szOut, CMD_RETAIL))
{ // retail => full screen => OOBE mode
*pProp |= PROP_FULLSCREEN;
*pProp &= ~PROP_OOBE_OEM;
*pApmd = APMD_OOBE;
}
else if (0 == lstrcmpi(szOut, CMD_PRECONFIG))
{
*pApmd = APMD_MSN;
}
else if (0 == lstrcmpi(szOut, CMD_OFFLINE))
{
*pApmd = APMD_MSN;
}
else if (0 == lstrcmpi(szOut, CMD_SETPWD))
{
*pProp |= PROP_SETCONNECTIOD;
}
else if (0 == lstrcmpi(szOut, CMD_OOBE))
{
*pApmd = APMD_OOBE;
}
else if (0 == lstrcmpi(szOut, CMD_REG))
{
*pApmd = APMD_REG;
}
else if (0 == lstrcmpi(szOut, CMD_ISP))
{
*pApmd = APMD_ISP;
}
else if (0 == lstrcmpi(szOut, CMD_ACTIVATE))
{
*pApmd = APMD_ACT;
}
else if (0 == lstrcmpi(szOut, CMD_1))
{
*pRmdIndx = 1;
}
else if (0 == lstrcmpi(szOut, CMD_2))
{
*pRmdIndx = 2;
}
else if (0 == lstrcmpi(szOut, CMD_3))
{
*pRmdIndx = 3;
}
else if (0 == lstrcmpi(szOut, CMD_MSNMODE))
{
*pApmd = APMD_MSN;
*pProp |= PROP_CALLFROM_MSN;
}
else if (0 == lstrcmpi(szOut, CMD_ICWMODE))
{
*pApmd = APMD_MSN;
}
else if (GetShellNextToken(lpszCmdParam, szOut))
{
//*pApmd = APMD_DEFAULT;
}
else if (0 == lstrcmpi(szOut, CMD_2NDINSTANCE))
{
*pProp |= PROP_2NDINSTANCE;
}
GetCmdLineToken(&lpszCmdParam, szOut);
}
}
}
void AutoActivation()
{
// See if we are in an unattend case
WCHAR File [MAX_PATH*2] = L"\0";
DWORD dwExit;
BOOL AutoActivate = FALSE;
TRACE( L"Starting AutoActivation");
if (GetCanonicalizedPath(File, INI_SETTINGS_FILENAME))
{
TRACE1( L"GetCanonicalizedPath: %s",File);
if (GetPrivateProfileInt(OPTIONS_SECTION,
L"IntroOnly",
0,
File) > 0)
{
TRACE( L"Found intro Only");
AutoActivate = TRUE;
}
}
if (AutoActivate)
{
// Since we did intro only call autoactivation. it checks
// if it should run.
ExpandEnvironmentStrings(
TEXT("%SystemRoot%\\System32\\oobe\\oobebaln.exe /S"),
File,
sizeof(File)/sizeof(WCHAR));
TRACE1( L"Launching:%s", File);
// Launch and wait.
// I tried without wait and the activation did not succeed.
InvokeExternalApplicationEx(NULL, File, &dwExit, INFINITE, TRUE);
}
TRACE( L"AutoActivation done");
}
VOID
RunFactory(
)
{
TCHAR szFileName[MAX_PATH + 32] = TEXT("");
DWORD dwExit;
if ( ( ExpandEnvironmentStrings(
TEXT("%SystemDrive%\\sysprep\\factory.exe"),
szFileName,
sizeof(szFileName) / sizeof(TCHAR)) == 0 ) ||
( szFileName[0] == TEXT('\0') ) ||
( GetFileAttributes(szFileName) == 0xFFFFFFFF ) )
{
// If this fails, there is nothing we can really do.
//
TRACE( L"Factory.exe not found");
} else {
InvokeExternalApplicationEx(
szFileName,
L"-oobe",
&dwExit,
INFINITE,
TRUE
);
}
}
void RemoveIntroOnly()
{
WCHAR File [MAX_PATH*2] = L"\0";
if (GetCanonicalizedPath(File, INI_SETTINGS_FILENAME))
{
WritePrivateProfileString(OPTIONS_SECTION,
L"IntroOnly",
L"0",
File);
}
}
INT WINAPI LaunchMSOOBE(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpszCmdParam, INT nCmdShow)
{
HANDLE Mutex;
BOOL bRegisteredDlls = FALSE;
BOOL bUseOleUninitialize = FALSE;
int iReturn=1;
APMD Apmd = APMD_DEFAULT;
DWORD Prop = 0;
int RmdIndx = 0;
//
// We can't use TRACE() until this is called, so don't put anything before it.
//
SetupOobeInitDebugLog();
TRACE1( L"OOBE run with the following parameters: %s", lpszCmdParam );
OOBE_SHUTDOWN_ACTION osa = SHUTDOWN_NOACTION;
g_hInstance = hInstance;
// Parse the command line early. The out params are passed to CObMain to
// set the private members.
ParseCommandLine(lpszCmdParam, &Apmd, &Prop, &RmdIndx);
// If we are not the 2nd instance
if (!(Prop & PROP_2NDINSTANCE))
{
CheckDigitalID();
if (Apmd == APMD_OOBE) {
CSetupKey setupkey;
MYASSERT(setupkey.IsValid());
if ( Prop & PROP_OOBE_OEM ) {
// Remove IntroOnly, just in case it is still set from the original install.
RemoveIntroOnly();
// reset the SetupType so that OOBe can be restarted (OEM case)
if (ERROR_SUCCESS != setupkey.set_SetupType(SETUPTYPE_NOREBOOT)) {
return FALSE;
}
} else {
//
// In the retail OOBE case, clean up the registry early, in case we
// fail to run to completion for some reason. We need to make sure
// we get rid of the OobeInProgress key.
//
CleanupForLogon(setupkey);
}
}
// If we are the first instance, do the checking and register the DLLs
// If we are the 2nd instance this is not needed.
//Exit if MSN app window is aready running and push that window to front
HWND hWnd = FindWindow(OOBE_MAIN_CLASSNAME, NULL);
if(hWnd != NULL)
{
SetForegroundWindow(hWnd);
if (IsIconic(hWnd))
SendMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, NULL);
TRACE(L"OOBE is already running in this session.");
return 0;
}
// It's possible that OOBE is running in another session. If so, we need
// to bail out.
Mutex = CreateMutex( NULL, TRUE, TEXT("Global\\OOBE is running") );
if ( !Mutex || GetLastError() == ERROR_ALREADY_EXISTS ) {
WCHAR szTitle [MAX_PATH] = L"\0";
WCHAR szMsg [MAX_PATH] = L"\0";
HINSTANCE hInst = GetModuleHandle(OOBE_MAIN_DLL);
TRACE(L"OOBE is already running in another session.");
if(hInst) {
LoadString(hInst, IDS_APPNAME, szTitle, MAX_CHARS_IN_BUFFER(szTitle));
LoadString(hInst, IDS_ALREADY_RUNNING, szMsg, MAX_CHARS_IN_BUFFER(szMsg));
MessageBox( NULL, szMsg, szTitle, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL );
}
if ( Mutex ) {
CloseHandle( Mutex );
}
return 0;
}
if(!SelfRegisterComObject(OOBE_WEB_DLL, TRUE)) {
TRACE(L"SelfRegisterComObject() failed.");
return 1;
}
if(!SelfRegisterComObject(OOBE_SHELL_DLL, TRUE)) {
TRACE(L"SelfRegisterComObject() failed.");
return 1;
}
if(!SelfRegisterComObject(OOBE_COMM_DLL, TRUE)) {
TRACE(L"SelfRegisterComObject() failed.");
return 1;
}
bRegisteredDlls = TRUE;
}
//If CoInit fails something is seriously messed up, run away
if (!(Prop & PROP_FULLSCREEN))
{
bUseOleUninitialize = TRUE;
// Need to use OleInitialize to get Clipboard support or Ctrl+C (Copy) does not work
// in the edit controls on the OOBE pages.
if(FAILED(OleInitialize(NULL))) {
TRACE(L"OleInitialize() failed.");
return 1;
}
}
else
{
// Don't have the support in fullscreen OOBE.
if(FAILED(CoInitialize(NULL))) {
TRACE(L"CoInitialize() failed.");
return 1;
}
}
{
// DO NOT REMOVE THIS SCOPE BLOCK. It controls the scope of ObMain.
// ObMain must be initialized after CoInitialize is called and
// destroyed prior to calling CoUninitialize.
//
CObMain ObMain(Apmd, Prop, RmdIndx);
// If we are the 1st instance or
// if we are the second instance and we are in OOBE mode and in fullscreen mode
if (!ObMain.Is2ndInstance() ||
(ObMain.Is2ndInstance() && ObMain.FHasProperty(PROP_OOBE_OEM)))
{
// If not in safe mode proceed.
//
if (!InSafeMode() || InDsRestoreMode() )
{
BOOL fOemOobeMode = ObMain.InOobeMode() && ObMain.FHasProperty(PROP_OOBE_OEM);
// Start the fullscreen background
//
if (!ObMain.Is2ndInstance() && ObMain.FFullScreen())
{
ObMain.CreateBackground();
}
// Run factory.exe if we're in OEM mode.
//
if (fOemOobeMode && !ObMain.Is2ndInstance()) {
RunFactory();
}
// CObMain::Init contains critical initialization. DO NOT call any other
// CObMain methods prior to it.
//
if (ObMain.Init())
{
if (Prop & PROP_SETCONNECTIOD)
{
ObMain.SetConnectoidInfo();
}
else if ((osa = ObMain.DisplayReboot()) != SHUTDOWN_NOACTION)
{
// Either we ran minisetup or we're done.
//
if (osa == SHUTDOWN_REBOOT)
{
ObMain.PowerDown(TRUE);
}
}
else
{
if (!ObMain.Is2ndInstance())
{
// If we are the 1st instance, call syssetup
// and start the magnifier if needed.
// The 2nd instance does not need this.
SetupOobeInitPreServices( fOemOobeMode );
if (ObMain.FFullScreen())
{
WCHAR WinntPath[MAX_PATH];
WCHAR Answer[MAX_PATH];
// Check if we should run Magnifier
if(GetCanonicalizedPath(WinntPath, WINNT_INF_FILENAME))
{
if(GetPrivateProfileString( L"Accessibility",
L"AccMagnifier",
L"",
Answer,
sizeof(Answer)/sizeof(WCHAR),
WinntPath
))
{
if ( lstrcmpi( Answer, L"1") == 0)
{
InvokeExternalApplication(L"magnify.exe", L"", NULL);
}
}
}
}
}
else
{
//
// The first instance did the minisetup stuff, so
// we don't need to do it again.
//
SetupOobeInitPreServices(FALSE);
}
if(0 != ObMain.InitApplicationWindow())
{
// BUGBUG: Is the following true for NT?
// If we finish OOBE, we return 0 to let the machine boot,
// otherwise we return 1 and the machine shutsdown because
// the user canceled or there was a fatal error.
//
iReturn = ObMain.RunOOBE() ? 0 : 1;
}
if (!ObMain.InAuditMode())
{
// We need to remove this entry now, so ICWMAN (INETWIZ) does not
// pick it up later
RemoveShellNextFromReg();
HandleShellNext();
if (!ObMain.Is2ndInstance() && ObMain.FFullScreen())
{
// Only the 1st instance can do this.
// it called SetupOobeInitPreServices
CSetupKey setupkey;
OOBE_SHUTDOWN_ACTION action;
// We want to clear the restart stuff before
// calling SetupOobeCleanup. SetupOobeCleanup
// enables System Restore, which creates a restore
// point immediately and the restore point would
// cause Winlogon to start OOBE.
ObMain.RemoveRestartStuff(setupkey);
// SHUTDOWN_POWERDOWN happens only if bad pid
// is entered or eula is declined. We don't want to call
// SetupOobeCleanup and enable system restore
// at this point. This has to be called after
// RemoveRestartStuff.
if ((setupkey.get_ShutdownAction(&action) != ERROR_SUCCESS) ||
(action != SHUTDOWN_POWERDOWN))
{
if (fOemOobeMode)
{
ObMain.CreateBackground();
SetupOobeCleanup( fOemOobeMode );
ObMain.StopBackgroundWindow();
}
else
{
SetupOobeCleanup( fOemOobeMode );
}
}
}
}
}
}
if (!ObMain.InAuditMode() && ObMain.FFullScreen())
{
// OOBE is done, let see if we should launch AutoActivation?
AutoActivation();
}
ObMain.Cleanup();
} else if (ObMain.InMode(APMD_ACT)) {
WCHAR szTitle [MAX_PATH] = L"\0";
WCHAR szMsg [MAX_PATH] = L"\0";
HINSTANCE hInst = GetModuleHandle(OOBE_MAIN_DLL);
TRACE(L"Desktop activation cannot be run in safe mode.");
if(hInst) {
LoadString(hInst, IDS_APPNAME, szTitle, MAX_CHARS_IN_BUFFER(szTitle));
LoadString(hInst, IDS_SAFEMODE, szMsg, MAX_CHARS_IN_BUFFER(szMsg));
MessageBox( NULL, szMsg, szTitle, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL );
}
} else {
// we are in safemode and not running Activation.
// At least start the services.
SignalComputerNameChangeComplete();
}
}
// DO NOT REMOVE THIS SCOPE BLOCK. It controls the scope of ObMain.
// ObMain must be initialized after CoInitialize is called and
// destroyed prior to calling CoUninitialize.
//
}
if (bUseOleUninitialize)
{
OleUninitialize();
}
else
{
CoUninitialize();
}
if (bRegisteredDlls)
{
SelfRegisterComObject(OOBE_WEB_DLL, FALSE);
SelfRegisterComObject(OOBE_SHELL_DLL, FALSE);
SelfRegisterComObject(OOBE_COMM_DLL, FALSE);
CloseHandle( Mutex );
}
TRACE( L"OOBE has finished." );
return iReturn;
}