|
|
/*****************************************************************************\
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; }
|