|
|
#include "setupp.h"
#pragma hdrstop
//
// List of oem preinstall/unattend values we can fetch from profile files.
// Do NOT change the order of this without changing the order of the
// PreinstUnattendData array.
//
typedef enum { OemDatumBackgroundBitmap, OemDatumBannerText, OemDatumLogoBitmap, OemDatumMax } OemPreinstallDatum;
//
// Define structure that represents a single bit of data read
// from a profile file relating to preinstallation.
//
typedef struct _PREINSTALL_UNATTEND_DATUM { //
// Filename. If NULL, use the system answer file $winnt$.inf.
// Otherwise this is relative to the root of the source drive.
//
PCWSTR Filename;
//
// Section name.
//
PCWSTR Section;
//
// Key name.
//
PCWSTR Key;
//
// Default value. Can be NULL but that will be translated to
// "" when the profile API is called to retrieve the data.
//
PCWSTR Default;
//
// Where to put the actual value. The actual value may be
// a string, or NULL.
//
PWSTR *Value;
//
// Value for sanity checking.
//
OemPreinstallDatum WhichValue;
} PREINSTALL_UNATTEND_DATUM, *PPREINSTALL_UNATTEND_DATUM;
//
// Name of oem background bitmap file and logo bitmap file.
// Replacement banner text.
// Read from unattend.txt
//
PWSTR OemBackgroundBitmapFile; PWSTR OemLogoBitmapFile; PWSTR OemBannerText;
//
// If this is non-NULL, it is a replacement bitmap
// to use for the background.
//
HBITMAP OemBackgroundBitmap;
PREINSTALL_UNATTEND_DATUM PreinstUnattendData[OemDatumMax] = {
//
// Background bitmap
//
{ NULL, WINNT_OEM_ADS, WINNT_OEM_ADS_BACKGROUND, NULL, &OemBackgroundBitmapFile, OemDatumBackgroundBitmap },
//
// Banner text
//
{ NULL, WINNT_OEM_ADS, WINNT_OEM_ADS_BANNER, NULL, &OemBannerText, OemDatumBannerText },
//
// Logo bitmap
//
{ NULL, WINNT_OEM_ADS, WINNT_OEM_ADS_LOGO, NULL, &OemLogoBitmapFile, OemDatumLogoBitmap } };
//
// Path to the registry key that contains the list of preinstalled
// drivers (SCSI, keyboard and mouse)
//
PCWSTR szPreinstallKeyName = L"SYSTEM\\Setup\\Preinstall";
//
// Forward references
//
VOID ProcessOemBitmap( IN PWSTR FilenameAndResId, IN SetupBm WhichOne );
BOOL CleanupPreinstalledComponents( );
BOOL InitializePreinstall( VOID ) { WCHAR Buffer[2*MAX_PATH]; DWORD d; int i;
//
// Must be run after main initialization. We rely on stuff that is
// set up there.
//
MYASSERT(AnswerFile[0]);
//
// Special skip-eula value. Note that we want this value even if we're not
// doing a Preinstall.
//
GetPrivateProfileString( WINNT_UNATTENDED, L"OemSkipEula", pwNo, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), AnswerFile );
OemSkipEula = (lstrcmpi(Buffer,pwYes) == 0);
//
// For the mini-setup case, always be preinstall.
//
if( MiniSetup ) { Preinstall = TRUE; } else {
MYASSERT(SourcePath[0]);
//
// First, figure out whether this is an OEM preinstallation.
//
GetPrivateProfileString( WINNT_UNATTENDED, WINNT_OEMPREINSTALL, pwNo, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), AnswerFile );
Preinstall = (lstrcmpi(Buffer,pwYes) == 0);
//
// If not preinstallation, nothing more to do.
//
if(!Preinstall) { return(TRUE); } }
//
// OK, it's preinstsall. Fill in our data table.
//
for(i=0; i<OemDatumMax; i++) {
//
// Sanity check
//
MYASSERT(PreinstUnattendData[i].WhichValue == i);
//
// Retrieve data and duplicate. If the value comes back as ""
// assume it means there is no value in there.
//
GetPrivateProfileString( PreinstUnattendData[i].Section, PreinstUnattendData[i].Key, PreinstUnattendData[i].Default ? PreinstUnattendData[i].Default : NULL, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), PreinstUnattendData[i].Filename ? PreinstUnattendData[i].Filename : AnswerFile );
*PreinstUnattendData[i].Value = Buffer[0] ? pSetupDuplicateString(Buffer) : NULL; if(Buffer[0] && (*PreinstUnattendData[i].Value == NULL)) { //
// Out of memory.
//
pSetupOutOfMemory(MainWindowHandle); return(FALSE); } }
//
// Change the banner text, if the OEM supplied new text.
// Make sure our product name is in there.
//
if(OemBannerText) {
if(wcsstr(OemBannerText,L"Windows NT") || wcsstr(OemBannerText,L"BackOffice")) { //
// Substitute * with \n
//
for(i=0; OemBannerText[i]; i++) { if(OemBannerText[i] == L'*') { OemBannerText[i] = L'\n'; } } #if 0
//
// Disable the banner for now.
//
SendMessage(MainWindowHandle,WM_NEWBITMAP,SetupBmBanner,(LPARAM)OemBannerText); #endif
} else { MyFree(OemBannerText); OemBannerText = NULL; } }
//
// Load the OEM background bitmap, if any.
// Load the OEM logo bitmap, if any.
//
ProcessOemBitmap(OemBackgroundBitmapFile,SetupBmBackground); ProcessOemBitmap(OemLogoBitmapFile,SetupBmLogo);
//
// Repaint the main window. Specify that the background should be erased
// because the main window relies on this behavior.
//
InvalidateRect(MainWindowHandle,NULL,TRUE); UpdateWindow(MainWindowHandle);
CleanupPreinstalledComponents(); return(TRUE); }
VOID ProcessOemBitmap( IN PWSTR FilenameAndResId, IN SetupBm WhichOne )
/*++
Routine Description:
This routine processes a single oem bitmap specification.
The OEM bitmap may either be in a resource file or in a standalone bitmap file. Once the bitmap has been loaded the main window is told about it.
Arguments:
FileNameAndResId - specifies a profile string with either one or 2 fields. If the string contains a comma, it is assumed to be the name of a DLL followed by a resource ID. The dll is loaded from the $OEM$\OEMFILES directory and then we call LoadBitmap with the given resource id, which is a base-10 string of ascii digits. The string is split at the comma during this routine. If this parameter does not contain a comma then it is assumed to be the name of a .bmp in $OEM$\OEMFILES and we load it via LoadImage().
WhichOne - supplies a value indicating which bitmap this is.
Return Value:
None.
--*/
{ HINSTANCE ModuleHandle; PWCHAR p,q; HBITMAP Bitmap; WCHAR Buffer[MAX_PATH]; DWORD Result;
if(FilenameAndResId) {
Bitmap = NULL;
if( !MiniSetup ) { lstrcpy(Buffer,SourcePath); pSetupConcatenatePaths(Buffer,WINNT_OEM_DIR,MAX_PATH,NULL); } else { //
// If we're doing a mini-install, look for the bmp in
// the \sysprep directory on the drive where NT is
// installed, not $OEM$
//
Result = GetWindowsDirectory( Buffer, MAX_PATH ); if( Result == 0) { MYASSERT(FALSE); return; } Buffer[3] = 0; pSetupConcatenatePaths( Buffer, TEXT("sysprep"), MAX_PATH, NULL ); }
if(p = wcschr(FilenameAndResId,L',')) {
q = p; //
// Skip backwards over spaces and quotes. The text setup ini file writer
// will create a line like
//
// a = "b","c"
//
// whose RHS comes back as
//
// b","c
//
// since the profile APIs strip off the outermost quotes.
//
//
while((q > FilenameAndResId) && ((*(q-1) == L'\"') || iswspace(*(q-1)))) { q--; } *q = 0;
q = p+1; while(*q && ((*q == L'\"') || iswspace(*q))) { q++; }
pSetupConcatenatePaths(Buffer,FilenameAndResId,MAX_PATH,NULL);
if(ModuleHandle = LoadLibraryEx(Buffer,NULL,LOAD_LIBRARY_AS_DATAFILE)) {
Bitmap = LoadBitmap(ModuleHandle,MAKEINTRESOURCE(wcstoul(q,NULL,10))); FreeLibrary(ModuleHandle); } } else { pSetupConcatenatePaths(Buffer,FilenameAndResId,MAX_PATH,NULL);
Bitmap = (HBITMAP)LoadImage(NULL,Buffer,IMAGE_BITMAP,0,0,LR_LOADFROMFILE); }
if(Bitmap) { //
// Got a valid bitmap. Tell main window about it.
//
SendMessage(MainWindowHandle,WM_NEWBITMAP,WhichOne,(LPARAM)Bitmap); } } }
LONG ExaminePreinstalledComponent( IN HKEY hPreinstall, IN SC_HANDLE hSC, IN PCWSTR ServiceName )
/*++
Routine Description:
Query a preinstalled component, and disable it if necessary. If the component is an OEM component, and is running, then disable any associated service, if necessary.
Arguments:
hPreinstall - Handle to the key SYSTEM\Setup\Preinstall.
hSC - Handle to the Service Control Manager.
ServiceName - Name of the service to be examined.
Return Value:
Returns a Win32 error code indicating the outcome of the operation.
--*/
{ BOOL OemComponent; HKEY Key; LONG Error; DWORD cbData; WCHAR Data[ MAX_PATH + 1]; DWORD Type; SC_HANDLE hSCService; SERVICE_STATUS ServiceStatus;
//
// Open the key that contains the info about the preinstalled component.
//
Error = RegOpenKeyEx( hPreinstall, ServiceName, 0, KEY_READ, &Key );
if( Error != ERROR_SUCCESS ) { return( Error ); }
//
// Find out if the component is an OEM or RETAIL
//
cbData = sizeof(Data); Error = RegQueryValueEx( Key, L"OemComponent", 0, &Type, ( LPBYTE )Data, &cbData ); if( Error != ERROR_SUCCESS ) { RegCloseKey( Key ); return( Error ); }
OemComponent = (*((PULONG)Data) == 1);
if( OemComponent ) { //
// Get the name of the retail service to disable
//
cbData = sizeof(Data); Error = RegQueryValueEx( Key, L"RetailClassToDisable", 0, &Type, ( LPBYTE )Data, &cbData ); if( Error != ERROR_SUCCESS ) { *(( PWCHAR )Data) = '\0'; } } RegCloseKey( Key );
//
// Query the service
//
hSCService = OpenService( hSC, ServiceName, SERVICE_QUERY_STATUS );
if( hSCService == NULL ) { Error = GetLastError(); return( Error ); } if( !QueryServiceStatus( hSCService, &ServiceStatus ) ) { Error = GetLastError(); return( Error ); } CloseServiceHandle( hSCService ); if( ServiceStatus.dwCurrentState == SERVICE_STOPPED ) { //
// Due to the nature of the services that were pre-installed,
// we can assume that the service failed to initialize, and that
// it can be disabled.
//
MyChangeServiceStart( ServiceName, SERVICE_DISABLED ); } else { if( OemComponent && ( lstrlen( (PCWSTR)Data ) != 0 ) ) { MyChangeServiceStart( (PCWSTR)Data, SERVICE_DISABLED ); } }
return( ERROR_SUCCESS ); }
BOOL CleanupPreinstalledComponents( )
/*++
Routine Description:
Query the preinstalled components, and disable the ones that failed to start. This is done by enumerating the subkeys of SYSTEM\Setup\Preinstall. Each subkey represents a SCSI, Keyboard or Mouse installed. The video drivers are not listed here. The "Display" applet will determine and disable the video drivers that were preinstalled, but failed to start.
Arguments:
None.
Return Value:
Returns TRUE if the operation succeeded, or FALSE otherwise.
--*/
{ LONG Error; LONG SavedError; HKEY Key; HKEY SubKeyHandle; ULONG i; ULONG SubKeys; WCHAR SubKeyName[ MAX_PATH + 1 ]; ULONG NameSize; FILETIME LastWriteTime; SC_HANDLE hSC;
EnableEventlogPopup(); //
// Find out the number of subkeys of SYSTEM\Setup\Preinstall
//
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, szPreinstallKeyName, 0, KEY_READ, &Key );
if( Error != ERROR_SUCCESS ) { //
// If the key doesn't exist, then assume no driver to preinstall,
// and return TRUE.
//
return( Error == ERROR_FILE_NOT_FOUND ); }
Error = RegQueryInfoKey( Key, NULL, NULL, NULL, &SubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
if( Error != ERROR_SUCCESS ) { return( FALSE ); }
//
// If there are no subkeys, then assume no driver to preinstall
//
if( SubKeys == 0 ) { return( TRUE ); }
//
// Get a handle to the service control manager
//
hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if(hSC == NULL) { Error = GetLastError(); return( FALSE ); }
//
// Query each SCSI, keyboard and mouse driver that was preinstalled
// and disable it if necessary.
//
SavedError = ERROR_SUCCESS; for( i = 0; i < SubKeys; i++ ) { NameSize = sizeof( SubKeyName ) / sizeof( WCHAR ); Error = RegEnumKeyEx( Key, i, SubKeyName, &NameSize, NULL, NULL, NULL, &LastWriteTime ); if( Error != ERROR_SUCCESS ) { if( SavedError == ERROR_SUCCESS ) { SavedError = Error; } continue; }
Error = ExaminePreinstalledComponent( Key, hSC, SubKeyName ); if( Error != ERROR_SUCCESS ) { if( SavedError == ERROR_SUCCESS ) { SavedError = Error; } // continue;
} } RegCloseKey( Key ); //
// At this point we can remove the Setup\Preinstall key
//
// DeletePreinstallKey();
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, MAXIMUM_ALLOWED, &Key ); if( Error == ERROR_SUCCESS ) { pSetupRegistryDelnode( Key, L"Preinstall" ); RegCloseKey( Key ); } return( TRUE ); }
BOOL EnableEventlogPopup( VOID )
/*++
Routine Description:
Delete from the registry the value entry that disables the error popups displayed by the eventlog, if one or more pre-installed driver failed to load. This value entry is created in the registry during textmode setup.
Arguments:
None.
Return Value:
Returns TRUE if the operation succeeded, or FALSE otherwise.
--*/
{ HKEY hKey = 0; ULONG Error;
//
// Delete the 'NoPopupsOnBoot' value
//
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Windows", 0, KEY_SET_VALUE, &hKey );
if(Error == NO_ERROR) { Error = RegDeleteValue(hKey, L"NoPopupsOnBoot"); } if (hKey) { RegCloseKey(hKey); } return( Error == ERROR_SUCCESS ); }
BOOL ExecutePreinstallCommands( VOID )
/*++
Routine Description:
Executes all commands specified in the file $OEM$\OEMFILES\cmdlines.txt.
Arguments:
None.
Return Value:
Returns TRUE if the operation succeeded, or FALSE otherwise.
--*/
{ WCHAR OldCurrentDir[MAX_PATH]; WCHAR FileName[MAX_PATH]; HINF CmdlinesTxtInf; LONG LineCount,LineNo; INFCONTEXT InfContext; PCWSTR CommandLine; DWORD DontCare; BOOL AnyError; PCWSTR SectionName;
//
// Set current directory to $OEM$.
// Preserve current directory to minimize side-effects.
//
if(!GetCurrentDirectory(MAX_PATH,OldCurrentDir)) { OldCurrentDir[0] = 0; } lstrcpy(FileName,SourcePath); pSetupConcatenatePaths(FileName,WINNT_OEM_DIR,MAX_PATH,NULL); SetCurrentDirectory(FileName);
//
// Form name of cmdlines.txt and see if it exists.
//
pSetupConcatenatePaths(FileName,WINNT_OEM_CMDLINE_LIST,MAX_PATH,NULL); AnyError = FALSE; if(FileExists(FileName,NULL)) {
CmdlinesTxtInf = SetupOpenInfFile(FileName,NULL,INF_STYLE_OLDNT,NULL); if(CmdlinesTxtInf == INVALID_HANDLE_VALUE) { //
// The file exists but is invalid.
//
AnyError = TRUE; } else { //
// Get the number of lines in the section that contains the commands to
// be executed. The section may be empty or non-existant; this is not
// an error condition. In that case LineCount may be -1 or 0.
//
SectionName = L"Commands"; LineCount = SetupGetLineCount(CmdlinesTxtInf,SectionName);
for(LineNo=0; LineNo<LineCount; LineNo++) {
if(SetupGetLineByIndex(CmdlinesTxtInf,SectionName,(DWORD)LineNo,&InfContext) && (CommandLine = pSetupGetField(&InfContext,1))) { if(!InvokeExternalApplication(NULL,CommandLine,&DontCare)) { AnyError = TRUE; } } else { //
// Strange case, inf is messed up
//
AnyError = TRUE; } } } }
//
// Reset current directory and return.
//
if(OldCurrentDir[0]) { SetCurrentDirectory(OldCurrentDir); }
if(AnyError) { SetuplogError( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_OEMPRE_FAIL, NULL,NULL); }
return(!AnyError); }
|