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.
780 lines
23 KiB
780 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
factory.c
|
|
|
|
Abstract:
|
|
|
|
Factory Pre-install application. This application will be used to perform
|
|
pre-installation task in an OEM factory, or system builder (SB) setting.
|
|
|
|
The task performed will be:
|
|
Minimal boot (minimal device and services loaded)
|
|
WinBOM processing
|
|
Download updated device drivers from NET
|
|
Process OOBE info
|
|
Process User/Customer specific settings
|
|
Process OEM user specific customization
|
|
Process Application pre-installations
|
|
PnPDevice enumeration
|
|
Exit to Windows for Audit mode work.
|
|
|
|
Author:
|
|
|
|
Donald McNamara (donaldm) 2/8/2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// Include File(s):
|
|
//
|
|
|
|
#include "factoryp.h"
|
|
#include "shlobj.h"
|
|
#include "states.h" // should only ever be included by one c file.
|
|
|
|
|
|
//
|
|
// Defined Value(s):
|
|
//
|
|
|
|
#define FILE_WINBOM _T("winbom")
|
|
#define FILE_OOBE _T("oobe")
|
|
#define FILE_BAT _T(".bat")
|
|
#define FILE_CMD _T(".cmd")
|
|
|
|
#define REG_VAL_FIRSTPNP _T("PnPDetection")
|
|
#define PNP_INSTALL_TIMEOUT 600000 // 10 minutes
|
|
|
|
#define SZ_ENV_RESOURCE _T("ResourceDir")
|
|
#define SZ_ENV_RESOURCEL _T("ResourceDirL")
|
|
|
|
|
|
//
|
|
// Defined Macro(s):
|
|
//
|
|
|
|
#define CHECK_PARAM(lpCmdLine, lpOption) ( LSTRCMPI(lpCmdLine, lpOption) == 0 )
|
|
|
|
|
|
//
|
|
// Type Definition(s):
|
|
//
|
|
|
|
|
|
//
|
|
// External Global Variable(s):
|
|
//
|
|
|
|
// UI stuff...
|
|
//
|
|
HINSTANCE g_hInstance = NULL;
|
|
|
|
// Global factory flags.
|
|
DWORD g_dwFactoryFlags = 0;
|
|
|
|
|
|
// Debug Level - used for logging.
|
|
//
|
|
#ifdef DBG
|
|
DWORD g_dwDebugLevel = LOG_DEBUG;
|
|
#else
|
|
DWORD g_dwDebugLevel = 0;
|
|
#endif
|
|
|
|
|
|
// Path to the WinBOM file.
|
|
//
|
|
TCHAR g_szWinBOMPath[MAX_PATH] = NULLSTR;
|
|
|
|
// Path to the WinBOM log file.
|
|
//
|
|
TCHAR g_szLogFile[MAX_PATH] = NULLSTR;
|
|
|
|
// Path to FACTORY.EXE.
|
|
//
|
|
TCHAR g_szFactoryPath[MAX_PATH] = NULLSTR;
|
|
|
|
// Path to the sysprep directory (where factory.exe must be located).
|
|
//
|
|
TCHAR g_szSysprepDir[MAX_PATH] = NULLSTR;
|
|
|
|
|
|
//
|
|
// Internal Golbal Variable(s):
|
|
//
|
|
|
|
// This determines the mode that factory will run in and is set based on
|
|
// the command line parameters.
|
|
//
|
|
FACTMODE g_fm = modeUnknown;
|
|
|
|
|
|
//
|
|
// Internal Function Prototype(s):
|
|
//
|
|
|
|
static BOOL ParseCmdLine();
|
|
static BOOL IsUserAdmin();
|
|
static BOOL RunBatchFile(LPTSTR lpszSysprepFolder, LPTSTR lpszBaseFileName);
|
|
static BOOL CheckSetEnv(LPCTSTR lpName, LPCTSTR lpValue);
|
|
static void SetupFactoryEnvironment();
|
|
|
|
|
|
/*++
|
|
===============================================================================
|
|
Routine Description:
|
|
|
|
This routine is the main entry point for the program.
|
|
|
|
We do a bit of error checking, then, if all goes well, we update the
|
|
registry to enable execution of our second half.
|
|
|
|
===============================================================================
|
|
--*/
|
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
HANDLE hMutex;
|
|
|
|
LPTSTR lpFilePart = NULL,
|
|
lpMode = NULL,
|
|
lpBatchFile = NULL;
|
|
DWORD dwLocate,
|
|
cbStates = 0;
|
|
LPSTATES lpStates = NULL;
|
|
BOOL bBadCmdLine,
|
|
bOldVersion = FALSE;
|
|
|
|
|
|
// Save the instance handle globally.
|
|
//
|
|
g_hInstance = hInstance;
|
|
|
|
// This causes the system not to display the critical-error-handler
|
|
// message box. Instead, the system sends the error to the calling
|
|
// process.
|
|
//
|
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
// We need the path to factory.exe and where it is located.
|
|
//
|
|
if ( GetModuleFileName(NULL, g_szFactoryPath, AS ( g_szFactoryPath ) ) &&
|
|
GetFullPathName(g_szFactoryPath, AS(g_szSysprepDir), g_szSysprepDir, &lpFilePart) && g_szSysprepDir[0] && lpFilePart )
|
|
{
|
|
// Chop off the file name.
|
|
//
|
|
*lpFilePart = NULLCHR;
|
|
}
|
|
|
|
// If either of those file, we must quit (can't imagine that every happening).
|
|
//
|
|
// ISSUE-2002/02/25-acosma,robertko - why are we checking for g_szFactoryPath here when we already used it above?
|
|
//
|
|
if ( ( g_szFactoryPath[0] == NULLCHR ) || ( g_szSysprepDir[0] == NULLCHR ) )
|
|
{
|
|
// Can we log this failure?
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
// This will setup special factory environment variables.
|
|
//
|
|
SetupFactoryEnvironment();
|
|
|
|
//
|
|
// Check to see if we are allowed to run on this build of the OS.
|
|
//
|
|
if ( !OpklibCheckVersion( VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE ) )
|
|
{
|
|
bOldVersion = TRUE;
|
|
}
|
|
|
|
#ifdef DBG
|
|
// In debug builds, lets always try to log right away. In
|
|
// the retail case we want to wait until after we locate the
|
|
// winbom before we start our logging.
|
|
//
|
|
InitLogging(NULL);
|
|
FacLogFileStr(3, _T("DEBUG: Starting factory (%s)."), GetCommandLine());
|
|
#endif
|
|
|
|
// Check the command line for options (but don't error
|
|
// till we have the log file up).
|
|
//
|
|
bBadCmdLine = ( !ParseCmdLine() || ( g_fm == modeUnknown ) );
|
|
|
|
// Need to find the mode stuff: string, flags, and states.
|
|
//
|
|
dwLocate = LOCATE_NORMAL;
|
|
switch ( g_fm )
|
|
{
|
|
case modeLogon:
|
|
dwLocate = LOCATE_AGAIN;
|
|
SET_FLAG(g_dwFactoryFlags, FLAG_LOGGEDON);
|
|
lpStates = &g_FactoryStates[0];
|
|
cbStates = AS(g_FactoryStates);
|
|
lpMode = INI_VAL_WBOM_TYPE_FACTORY;
|
|
break;
|
|
|
|
case modeSetup:
|
|
lpStates = &g_FactoryStates[0];
|
|
cbStates = AS(g_FactoryStates);
|
|
lpMode = INI_VAL_WBOM_TYPE_FACTORY;
|
|
lpBatchFile = FILE_WINBOM;
|
|
break;
|
|
|
|
case modeWinPe:
|
|
lpStates = &g_MiniNtStates[0];
|
|
cbStates = AS(g_MiniNtStates);
|
|
// Fall through...
|
|
case modeMiniNt:
|
|
lpMode = INI_VAL_WBOM_TYPE_WINPE;
|
|
break;
|
|
|
|
case modeOobe:
|
|
dwLocate = LOCATE_NONET;
|
|
SET_FLAG(g_dwFactoryFlags, FLAG_NOUI);
|
|
SET_FLAG(g_dwFactoryFlags, FLAG_OOBE);
|
|
lpStates = &g_OobeStates[0];
|
|
cbStates = AS(g_OobeStates);
|
|
lpMode = INI_VAL_WBOM_TYPE_OOBE;
|
|
lpBatchFile = FILE_OOBE;
|
|
break;
|
|
|
|
default:
|
|
lpMode = NULL;
|
|
}
|
|
|
|
// If the mode isn't setup, then pnp is already started.
|
|
// Otherwise if this is the first run of factory, wait
|
|
// for pnp before all else.
|
|
//
|
|
if ( modeSetup != g_fm )
|
|
{
|
|
SET_FLAG(g_dwFactoryFlags, FLAG_PNP_STARTED);
|
|
}
|
|
else if ( !bBadCmdLine && !bOldVersion && !RegCheck(HKLM, REG_FACTORY_STATE, REG_VAL_FIRSTPNP) )
|
|
{
|
|
// Kick off pnp this first time so we can get the winbom
|
|
// off the floppy or cd-rom.
|
|
//
|
|
if ( StartPnP() )
|
|
{
|
|
WaitForPnp(PNP_INSTALL_TIMEOUT);
|
|
}
|
|
|
|
// Make sure we don't do this every boot.
|
|
//
|
|
// ISSUE-2002/02/25-acosma,robertko - We should only set this if PNP successfully started. Move into above block?
|
|
//
|
|
RegSetString(HKLM, REG_FACTORY_STATE, REG_VAL_FIRSTPNP, _T("1"));
|
|
}
|
|
|
|
// Run the batch file if we are running from the setup key.
|
|
//
|
|
if ( !bBadCmdLine && !bOldVersion && lpBatchFile )
|
|
{
|
|
RunBatchFile(g_szSysprepDir, lpBatchFile);
|
|
}
|
|
|
|
// Find the WinBOM (just use the one previously found if we
|
|
// are in the logon mode).
|
|
//
|
|
LocateWinBom(g_szWinBOMPath, AS(g_szWinBOMPath), g_szSysprepDir, lpMode, dwLocate);
|
|
|
|
// Find out if we're running on IA64.
|
|
//
|
|
if ( IsIA64() )
|
|
SET_FLAG(g_dwFactoryFlags, FLAG_IA64_MODE);
|
|
|
|
// Try to enable logging. This checks the WinBOM.
|
|
//
|
|
// ISSUE-2002/02/25-acosma,robertko - in debug mode we have already done this. We end up doing this twice. Make sure this is ok.
|
|
//
|
|
InitLogging(g_szWinBOMPath);
|
|
|
|
// Only let one of this guy run.
|
|
//
|
|
hMutex = CreateMutex(NULL,FALSE,TEXT("FactoryPre Is Running"));
|
|
if ( hMutex == NULL )
|
|
{
|
|
FacLogFile(0 | LOG_ERR, MSG_OUT_OF_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
// Make sure we are the only process with a handle to our named mutex.
|
|
//
|
|
if ( GetLastError() == ERROR_ALREADY_EXISTS )
|
|
{
|
|
FacLogFile(0 | LOG_ERR, MSG_ALREADY_RUNNING);
|
|
|
|
// Destroy the mutex and bail.
|
|
//
|
|
CloseHandle(hMutex);
|
|
return 0;
|
|
}
|
|
|
|
// Now we can log and return if there was a
|
|
// bad command line passed to factory.
|
|
//
|
|
if ( bBadCmdLine )
|
|
{
|
|
FacLogFile(0 | LOG_ERR, IDS_ERR_INVALIDCMDLINE);
|
|
|
|
// Destroy the mutex and bail.
|
|
//
|
|
CloseHandle(hMutex);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Now we can log and put up an error message if necessary in case the version of tool is too old.
|
|
//
|
|
if ( bOldVersion )
|
|
{
|
|
FacLogFile(0 | LOG_ERR, IDS_ERR_NOT_ALLOWED);
|
|
|
|
CloseHandle(hMutex);
|
|
return 0;
|
|
}
|
|
|
|
// Make sure we have a WinBOM file.
|
|
//
|
|
if ( g_szWinBOMPath[0] == NULLCHR )
|
|
FacLogFile(( g_fm == modeLogon ) ? (2 | LOG_ERR) : (0 | LOG_ERR), IDS_ERR_MISSINGWINBOM);
|
|
else
|
|
FacLogFile(( g_fm == modeLogon ) ? 2 : 0, IDS_LOG_WINBOMLOCATION, g_szWinBOMPath);
|
|
|
|
// Ensure that the user is in the admin group.
|
|
//
|
|
if ( ( g_fm != modeMiniNt ) && ( g_fm != modeWinPe ) && ( !IsUserAdmin() ) )
|
|
{
|
|
FacLogFile(0 | LOG_ERR, MSG_NOT_AN_ADMINISTRATOR);
|
|
|
|
// Destroy the mutex and bail.
|
|
//
|
|
CloseHandle(hMutex);
|
|
return 0;
|
|
}
|
|
|
|
// We don't do the state thing in MiniNT mode right now (but we could).
|
|
// The modeMiniNt mode is only temporary the real mode in modeWinPe.
|
|
//
|
|
if ( g_fm == modeMiniNt )
|
|
{
|
|
// ISSUE-2002/02/25-acosma,robertko - This function does not check if we are running on WinPE, so users can just run factory -mini on any
|
|
// machine.
|
|
//
|
|
if ( !SetupMiniNT() )
|
|
{
|
|
FacLogFileStr(0 | LOG_ERR | LOG_MSG_BOX, L"Failed to install network adapter -- check WINBOM");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Make sure factory will always run.
|
|
//
|
|
if ( modeWinPe == g_fm )
|
|
{
|
|
HKEY hKey;
|
|
|
|
// Make sure that if we are in "-winpe" mode we only run under WinPE
|
|
//
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\MiniNT"), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
else
|
|
{
|
|
FacLogFile(0 | LOG_ERR, IDS_ERR_NOT_WINPE);
|
|
|
|
// Destroy the mutex and bail.
|
|
CloseHandle(hMutex);
|
|
return 0;
|
|
}
|
|
}
|
|
else if ( modeOobe != g_fm )
|
|
{
|
|
HKEY hKey;
|
|
|
|
// Open the key, and set the proper SetupType value.
|
|
//
|
|
// Very important not to ever change this value in OOBE
|
|
// mode!
|
|
//
|
|
if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SYSTEM\\Setup"), 0, KEY_ALL_ACCESS, &hKey ) == ERROR_SUCCESS )
|
|
{
|
|
DWORD dwValue = SETUPTYPE_NOREBOOT;
|
|
RegSetValueEx(hKey, TEXT("SetupType"), 0, REG_DWORD, (CONST LPBYTE) &dwValue, sizeof(DWORD));
|
|
}
|
|
}
|
|
|
|
// Now process the winbom.ini file.
|
|
//
|
|
if ( lpStates && cbStates )
|
|
{
|
|
ProcessWinBOM(g_szWinBOMPath, lpStates, cbStates);
|
|
}
|
|
#ifdef DBG
|
|
else
|
|
{
|
|
FacLogFileStr(3, _T("DEBUG: ProcessWinBOM() error... lpStates or cbStates not set."));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Close the Mutex.
|
|
//
|
|
CloseHandle(hMutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Internal Function(s):
|
|
//
|
|
|
|
static BOOL ParseCmdLine()
|
|
{
|
|
DWORD dwArgs;
|
|
LPTSTR *lpArgs;
|
|
BOOL bError = FALSE;
|
|
|
|
|
|
// ISSUE-2002/02/25-acosma,robertko - this is really contorted, we seem to have our own implementation of CommandLineToArgvW inside this
|
|
// GetCommandLineArgs() function. Just use the Win32 function. Should be safer.
|
|
//
|
|
if ( (dwArgs = GetCommandLineArgs(&lpArgs) ) && lpArgs )
|
|
{
|
|
LPTSTR lpArg;
|
|
DWORD dwArg;
|
|
|
|
// We want to skip over the first argument (it is the path
|
|
// to the command being executed.
|
|
//
|
|
if ( dwArgs > 1 )
|
|
{
|
|
dwArg = 1;
|
|
lpArg = *(lpArgs + dwArg);
|
|
}
|
|
else
|
|
lpArg = NULL;
|
|
|
|
// Loop through all the arguments.
|
|
//
|
|
while ( lpArg && !bError )
|
|
{
|
|
// Now we check to see if the first char is a dash or not.
|
|
//
|
|
if ( *lpArg == _T('-') )
|
|
{
|
|
LPTSTR lpOption = CharNext(lpArg);
|
|
|
|
// This is where you add command line options that start with a dash (-).
|
|
//
|
|
// ISSUE-2002/02/25-acosma,robertko - We don't validate correct combinations of arguments. I can run
|
|
// "factory -setup -logon -winpe -oobe" and the last argument would be the one that is
|
|
// picked up. We should fix this and make it smarter.
|
|
//
|
|
if ( CHECK_PARAM(lpOption, _T("setup")) )
|
|
g_fm = modeSetup;
|
|
else if ( CHECK_PARAM(lpOption, _T("logon")) )
|
|
g_fm = modeLogon;
|
|
else if ( CHECK_PARAM(lpOption, _T("minint")) )
|
|
g_fm = modeMiniNt;
|
|
else if ( CHECK_PARAM(lpOption, _T("winpe")) )
|
|
g_fm = modeWinPe;
|
|
else if ( CHECK_PARAM(lpOption, _T("oobe")) )
|
|
g_fm = modeOobe;
|
|
else
|
|
bError = TRUE;
|
|
}
|
|
else if ( *lpArg )
|
|
{
|
|
bError = TRUE;
|
|
}
|
|
|
|
// Setup the pointer to the next argument in the command line.
|
|
//
|
|
if ( ++dwArg < dwArgs )
|
|
lpArg = *(lpArgs + dwArg);
|
|
else
|
|
lpArg = NULL;
|
|
}
|
|
|
|
// Make sure to free the two buffers allocated by the GetCommandLineArgs() function.
|
|
//
|
|
FREE(*lpArgs);
|
|
FREE(lpArgs);
|
|
}
|
|
|
|
return !bError;
|
|
}
|
|
|
|
/*++
|
|
|
|
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. --
|
|
*/
|
|
|
|
static BOOL IsUserAdmin(VOID)
|
|
{
|
|
BOOL b;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
PSID AdministratorsGroup;
|
|
|
|
b = AllocateAndInitializeSid(
|
|
&NtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&AdministratorsGroup);
|
|
|
|
if(b)
|
|
{
|
|
if (!CheckTokenMembership( NULL, AdministratorsGroup, &b))
|
|
{
|
|
b = FALSE;
|
|
}
|
|
FreeSid(AdministratorsGroup);
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine ckecks WinBOM setting for logging. Logging
|
|
is enabled by default if nothing is specified in the
|
|
WinBOM. Disables logging by setting g_szLogFile = NULL.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
VOID InitLogging(LPTSTR lpszWinBOMPath)
|
|
{
|
|
TCHAR szScratch[MAX_PATH] = NULLSTR;
|
|
LPTSTR lpszScratch;
|
|
BOOL bWinbom = ( lpszWinBOMPath && *lpszWinBOMPath );
|
|
|
|
// First check if logging is disabled in the WinBOM.
|
|
//
|
|
if ( ( bWinbom ) &&
|
|
( GetPrivateProfileString(WBOM_FACTORY_SECTION, WBOM_FACTORY_LOGGING, _T("YES"), szScratch, AS(szScratch), lpszWinBOMPath) ) &&
|
|
( LSTRCMPI(szScratch, _T("NO")) == 0 ) )
|
|
{
|
|
g_szLogFile[0] = NULLCHR;
|
|
}
|
|
else
|
|
{
|
|
// All these checks can only be done if we have a winbom.
|
|
//
|
|
if ( bWinbom )
|
|
{
|
|
// Check for quiet mode. If we are in quiet mode don't display any MessageBoxes.
|
|
// This only works for WinPE mode.
|
|
//
|
|
if ( (GetPrivateProfileString(WBOM_WINPE_SECTION, INI_KEY_WBOM_QUIET, NULLSTR, szScratch, AS(szScratch), lpszWinBOMPath) ) &&
|
|
(0 == LSTRCMPI(szScratch, WBOM_YES))
|
|
)
|
|
{
|
|
SET_FLAG(g_dwFactoryFlags, FLAG_QUIET_MODE);
|
|
}
|
|
|
|
// See if they want to turn on perf logging.
|
|
//
|
|
szScratch[0] = NULLCHR;
|
|
if ( ( GetPrivateProfileString(WBOM_FACTORY_SECTION, INI_KEY_WBOM_LOGPERF, NULLSTR, szScratch, AS(szScratch), lpszWinBOMPath) ) &&
|
|
( 0 == LSTRCMPI(szScratch, WBOM_YES) ) )
|
|
{
|
|
SET_FLAG(g_dwFactoryFlags, FLAG_LOG_PERF);
|
|
}
|
|
|
|
// Set the logging level.
|
|
//
|
|
g_dwDebugLevel = (DWORD) GetPrivateProfileInt(WBOM_FACTORY_SECTION, INI_KEY_WBOM_LOGLEVEL, (DWORD) g_dwDebugLevel, lpszWinBOMPath);
|
|
}
|
|
|
|
//
|
|
// In non-debug builds we do not want the log level to be set at LOG_DEBUG. Force it
|
|
// to drop down by one level if set at LOG_DEBUG or higher.
|
|
//
|
|
#ifndef DBG
|
|
if ( g_dwDebugLevel >= LOG_DEBUG )
|
|
g_dwDebugLevel = LOG_DEBUG - 1;
|
|
#endif
|
|
|
|
// Check to see if they have a custom log file they want to use.
|
|
//
|
|
if ( ( bWinbom ) &&
|
|
( lpszScratch = IniGetExpand(lpszWinBOMPath, INI_SEC_WBOM_FACTORY, INI_KEY_WBOM_FACTORY_LOGFILE, NULL) ) )
|
|
{
|
|
TCHAR szFullPath[MAX_PATH] = NULLSTR;
|
|
LPTSTR lpFind = NULL;
|
|
|
|
// Turn the ini key into a full path.
|
|
//
|
|
lstrcpyn( g_szLogFile, lpszScratch, AS( g_szLogFile ) );
|
|
if (GetFullPathName(g_szLogFile, AS(szFullPath), szFullPath, &lpFind) && szFullPath[0] && lpFind)
|
|
{
|
|
// Copy the full path into the global.
|
|
//
|
|
lstrcpyn(g_szLogFile, szFullPath, AS(g_szLogFile));
|
|
|
|
// Chop off the file part so we can create the
|
|
// path if it doesn't exist.
|
|
//
|
|
*lpFind = NULLCHR;
|
|
|
|
// If the directory cannot be created or doesn't exist turn off logging.
|
|
//
|
|
if (!CreatePath(szFullPath))
|
|
g_szLogFile[0] = NULLCHR;
|
|
}
|
|
|
|
// Free the original path buffer from the ini file.
|
|
//
|
|
FREE(lpszScratch);
|
|
}
|
|
else // default case
|
|
{
|
|
// Create it in the current directory (g_szSysprepDir)
|
|
//
|
|
lstrcpyn(g_szLogFile, g_szSysprepDir, AS ( g_szLogFile ) );
|
|
AddPathN(g_szLogFile, WINBOM_LOGFILE, AS ( g_szLogFile ));
|
|
}
|
|
|
|
// Check to see if we have write access to the logfile. If we don't, turn off logging.
|
|
// If we're running in WinPE we'll call this function again once the drive becomes
|
|
// writable.
|
|
//
|
|
// Write an FFFE header to the file to identify this as a Unicode text file.
|
|
//
|
|
if ( g_szLogFile[0] )
|
|
{
|
|
HANDLE hFile;
|
|
DWORD dwWritten = 0;
|
|
WCHAR cHeader = 0xFEFF;
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
if ( INVALID_HANDLE_VALUE != (hFile = CreateFile(g_szLogFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)))
|
|
{
|
|
// BUBBUG: This should check for an existing header in the file. There could be an empty
|
|
// file with no header.
|
|
//
|
|
if ( ERROR_ALREADY_EXISTS != GetLastError() )
|
|
WriteFile(hFile, &cHeader, sizeof(cHeader), &dwWritten, NULL);
|
|
CloseHandle(hFile);
|
|
}
|
|
else
|
|
{ // There was a problem opening the file. Most of the time this means that the media is not writable.
|
|
// Disable logging in that case.
|
|
//
|
|
g_szLogFile[0] = NULLCHR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static BOOL RunBatchFile(LPTSTR lpszSysprepFolder, LPTSTR lpszBaseFileName)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
TCHAR szCmdLine[] = NULLSTR,
|
|
szWinbomBat[MAX_PATH];
|
|
LPTSTR lpExtension;
|
|
DWORD dwExitCode;
|
|
|
|
// First make the fullpath to where the batch file should be.
|
|
//
|
|
lstrcpyn(szWinbomBat, lpszSysprepFolder, AS(szWinbomBat));
|
|
AddPathN(szWinbomBat, lpszBaseFileName, AS(szWinbomBat) );
|
|
lpExtension = szWinbomBat + lstrlen(szWinbomBat);
|
|
|
|
// Make sure there is still enough room for the extension.
|
|
//
|
|
if ( ((lpExtension + 4) - szWinbomBat ) >= AS(szWinbomBat) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// First try winbom.cmd.
|
|
//
|
|
lstrcpyn(lpExtension, FILE_CMD, AS ( szWinbomBat ) - lstrlen ( szWinbomBat ) );
|
|
if ( FileExists(szWinbomBat) )
|
|
{
|
|
bRet = InvokeExternalApplicationEx(szWinbomBat, szCmdLine, &dwExitCode, INFINITE, GET_FLAG(g_dwFactoryFlags, FLAG_NOUI));
|
|
}
|
|
else
|
|
{
|
|
// Also try winbom.bat if that one didn't exist.
|
|
//
|
|
lstrcpyn(lpExtension, FILE_BAT, AS ( szWinbomBat ) - lstrlen ( szWinbomBat ) );
|
|
if ( FileExists(szWinbomBat) )
|
|
{
|
|
bRet = InvokeExternalApplicationEx(szWinbomBat, szCmdLine, &dwExitCode, INFINITE, GET_FLAG(g_dwFactoryFlags, FLAG_NOUI));
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
static BOOL CheckSetEnv(LPCTSTR lpName, LPCTSTR lpValue)
|
|
{
|
|
if ( 0 == GetEnvironmentVariable(lpName, NULL, 0) )
|
|
{
|
|
SetEnvironmentVariable(lpName, lpValue);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void SetupFactoryEnvironment()
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
szPath[0] = NULLCHR;
|
|
if ( SHGetSpecialFolderPath(NULL, szPath, CSIDL_RESOURCES, 0) && szPath[0] )
|
|
{
|
|
CheckSetEnv(SZ_ENV_RESOURCE, szPath);
|
|
}
|
|
|
|
szPath[0] = NULLCHR;
|
|
if ( SHGetSpecialFolderPath(NULL, szPath, CSIDL_RESOURCES_LOCALIZED, 0) && szPath[0] )
|
|
{
|
|
CheckSetEnv(SZ_ENV_RESOURCEL, szPath);
|
|
}
|
|
}
|