|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
dynupdt.c
Abstract:
Routines to handle dynamic update support during GUI setup phase
Author:
Ovidiu Temereanca (ovidiut) 15-Aug-2000
Revision History:
--*/
#include "setupp.h"
#include "hwdb.h"
#include "newdev.h"
#pragma hdrstop
#define STR_UPDATES_INF TEXT("updates.inf")
#define STR_DEFAULTINSTALL TEXT("DefaultInstall")
#define STR_DEFAULTINSTALLFINAL TEXT("DefaultInstallFinal")
#define STR_DRIVERCACHEINF TEXT("drvindex.inf")
#define STR_VERSION TEXT("Version")
#define STR_CABFILES TEXT("CabFiles")
#define STR_CABS TEXT("Cabs")
#define S_HWCOMP_DAT TEXT("hwcomp.dat")
static TCHAR g_DuShare[MAX_PATH];
BOOL BuildPath ( OUT PTSTR PathBuffer, IN DWORD PathBufferSize, IN PCTSTR Path1, IN PCTSTR Path2 )
/*++
Routine Description:
This function builds a path given the 2 components, assumed not to contain trailing or heading wacks
Arguments:
PathBuffer - Receives the full path
PathBuferSize - The size in chars of PathBuffer
Path1 - Specifies the head path
Path2 - Specifies the tail path
Return Value:
TRUE to indicate success; FALSE in case of failure; it means the supplied buffer was too small to fit the whole new path
--*/
{ if (!PathBuffer || !PathBufferSize || !Path1 || !Path2) { MYASSERT (FALSE); SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } if (_sntprintf (PathBuffer, PathBufferSize, TEXT("%s\\%s"), Path1, Path2) < 0) { PathBuffer[0] = 0; SetLastError (ERROR_INSUFFICIENT_BUFFER); return FALSE; } return TRUE; }
BOOL pDoesFileExist ( IN PCTSTR FilePath ) { WIN32_FIND_DATA fd;
return FileExists (FilePath, &fd) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); }
BOOL pDoesDirExist ( IN PCTSTR FilePath ) { WIN32_FIND_DATA fd;
return FileExists (FilePath, &fd) && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); }
DWORD CreateMultiLevelDirectory ( IN LPCTSTR Directory )
/*++
Routine Description:
This routine ensures that a multi-level path exists by creating individual levels one at a time. It can handle either paths of form x:... or \\?\Volume{...
Arguments:
Directory - supplies fully-qualified Win32 pathspec of directory to create
Return Value:
Win32 error code indicating outcome.
--*/
{ TCHAR Buffer[MAX_PATH]; PTSTR p,q; TCHAR c; BOOL Done; DWORD d = ERROR_SUCCESS;
if (FAILED (StringCchCopy (Buffer, ARRAYSIZE(Buffer), Directory))) { return ERROR_INSUFFICIENT_BUFFER; }
//
// If it already exists do nothing. (We do this before syntax checking
// to allow for remote paths that already exist. This is needed for
// remote boot machines.)
//
d = GetFileAttributes(Buffer); if(d != (DWORD)(-1)) { return((d & FILE_ATTRIBUTE_DIRECTORY) ? NO_ERROR : ERROR_DIRECTORY); }
//
// Check path format
//
c = (TCHAR)CharUpper((LPTSTR)Buffer[0]); if (c < TEXT('A') || c > TEXT('Z') || Buffer[1] != TEXT(':')) { return ERROR_INVALID_PARAMETER; }
if(Buffer[2] != TEXT('\\')) { return(Buffer[2] ? ERROR_INVALID_PARAMETER : ERROR_SUCCESS); } q = Buffer + 3; if(*q == 0) { return(ERROR_SUCCESS); }
Done = FALSE; do { //
// Locate the next path sep char. If there is none then
// this is the deepest level of the path.
//
if(p = _tcschr(q,TEXT('\\'))) { *p = 0; } else { Done = TRUE; }
//
// Create this portion of the path.
//
if(CreateDirectory(Buffer,NULL)) { d = ERROR_SUCCESS; } else { d = GetLastError(); if(d == ERROR_ALREADY_EXISTS) { d = ERROR_SUCCESS; } }
if(d == ERROR_SUCCESS) { //
// Put back the path sep and move to the next component.
//
if(!Done) { *p = TEXT('\\'); q = p+1; } } else { Done = TRUE; }
} while(!Done);
return(d); }
DWORD GetDriverCacheSourcePath ( OUT PTSTR Buffer, IN DWORD BufChars )
/*++
Routine Description:
This routine returns the source path to the local driver cache.
This value is retrieved from the following registry location:
\HKLM\Software\Microsoft\Windows\CurrentVersion\Setup
DriverCachePath : REG_EXPAND_SZ :
Arguments:
Buffer - Receives the path.
BufChars - Specifies the size of Buffer, in chars
Return Value:
If the function succeeds, the return value is TRUE
If the function fails, the return value is FALSE.
--*/
{ HKEY hKey; DWORD rc, DataType, DataSize; TCHAR Value[MAX_PATH];
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP TEXT("\\Setup"), 0, KEY_READ, &hKey ); if(rc == ERROR_SUCCESS) { //
// Attempt to read the "DriverCachePath" value.
//
DataSize = sizeof (Value); rc = RegQueryValueEx (hKey, REGSTR_VAL_DRIVERCACHEPATH, NULL, &DataType, (PBYTE)Value, &DataSize);
RegCloseKey(hKey);
if(rc == ERROR_SUCCESS) {
ExpandEnvironmentStrings (Value, Buffer, BufChars - 6);
if (Buffer[0]) { _tcscat ( Buffer, #if defined(_AMD64_)
TEXT("\\amd64") #elif defined(_X86_)
IsNEC_98 ? TEXT("\\nec98") : TEXT("\\i386") #elif defined(_IA64_)
TEXT("\\ia64") #else
#error "No Target Architecture"
#endif
); return ERROR_SUCCESS; } else { rc = ERROR_INVALID_DATA; } } }
return rc; }
PCTSTR FindSubString ( IN PCTSTR String, IN TCHAR Separator, IN PCTSTR SubStr, IN BOOL CaseSensitive )
/*++
Routine Description:
This function looks for a substring of a given string, only if found between the specified separator chars
Arguments:
String - Specifies the full string
Separator - Specifies the separator
SubStr - Specifies the sub string to look for
CaseSensitive - Specifies if the comparison should be case sensitive or not
Return Value:
NULL if the substring was not found; a pointer to the SubString inside String if it was found
--*/
{ SIZE_T len1, len2; PCTSTR end;
MYASSERT (Separator); MYASSERT (SubStr); MYASSERT (!_tcschr (SubStr, Separator));
len1 = lstrlen (SubStr); MYASSERT (SubStr[len1] == 0);
while (String) { end = _tcschr (String, Separator); if (end) { len2 = end - String; } else { len2 = lstrlen (String); } if ((len1 == len2) && (CaseSensitive ? !_tcsncmp (String, SubStr, len1) : !_tcsnicmp (String, SubStr, len1) )) { break; } if (end) { String = end + 1; } else { String = NULL; } }
return String; }
BOOL UpdateDrvIndex ( IN PCTSTR InfPath, IN PCTSTR CabFilename, IN PCTSTR SourceSifPath )
/*++
Routine Description:
This function fixes drvindex.inf such that SetupApi will pick up the file from the right cabinet
Arguments:
InfPath - Specifies the full path to drvindex.inf
CabFilename - Specifies the filename of the updates cabinet (basically it's "updates.cab")
SourceSifPath - Specifies the full path to the associated updates.sif containing the list of files in updates.cab
Return Value:
TRUE to indicate success; FALSE in case of failure; use GetLastError() to find the reason of failure
--*/
{ HANDLE sectFile = INVALID_HANDLE_VALUE; HANDLE concatFile = INVALID_HANDLE_VALUE; HANDLE hMap = NULL; PTSTR section = NULL; PBYTE base = NULL; TCHAR tempPath[MAX_PATH]; TCHAR tempFile[MAX_PATH]; TCHAR temp[MAX_PATH]; PTSTR p; DWORD sectSize; DWORD concatSize; DWORD rc; DWORD bytes; BOOL b = FALSE;
//
// create a temp file to put the new section in it
//
if (!GetTempPath (ARRAYSIZE(tempPath), tempPath) || !GetTempFileName (tempPath, TEXT("STP"), 0, tempFile) ) { return FALSE; }
__try {
if (!CopyFile (InfPath, tempFile, FALSE)) { __leave; } SetFileAttributes (tempFile, FILE_ATTRIBUTE_NORMAL);
section = pSetupDuplicateString (CabFilename); if (!section) { __leave; } p = _tcsrchr (section, TEXT('.')); if (p) { *p = 0; }
if (GetPrivateProfileString ( STR_CABS, section, TEXT(""), temp, ARRAYSIZE(temp), tempFile )) { if (lstrcmpi (temp, CabFilename) == 0) { if (GetPrivateProfileString ( STR_VERSION, STR_CABFILES, TEXT(""), tempPath, ARRAYSIZE(tempPath), tempFile )) { if (FindSubString (tempPath, TEXT(','), section, FALSE)) { //
// setup restarted, but drvindex.inf is already patched; nothing to do
//
b = TRUE; __leave; } } } }
if (!WritePrivateProfileString ( STR_CABS, section, CabFilename, tempFile )) { __leave; } if (!GetPrivateProfileString ( STR_VERSION, STR_CABFILES, TEXT(""), tempPath, ARRAYSIZE(tempPath), tempFile )) { __leave; } if (!FindSubString (tempPath, TEXT(','), section, FALSE)) { wsprintf (temp, TEXT("%s,%s"), section, tempPath); if (!WritePrivateProfileString ( STR_VERSION, STR_CABFILES, temp, tempFile )) { __leave; } }
sectFile = CreateFile ( SourceSifPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (sectFile == INVALID_HANDLE_VALUE) { __leave; }
sectSize = GetFileSize (sectFile, NULL); if (sectSize == INVALID_FILE_SIZE) { __leave; }
concatFile = CreateFile ( tempFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (concatFile == INVALID_HANDLE_VALUE) { __leave; } concatSize = GetFileSize (concatFile, NULL); if (concatSize == INVALID_FILE_SIZE) { __leave; }
hMap = CreateFileMapping (concatFile, NULL, PAGE_READWRITE, 0, concatSize + sectSize, NULL); if (!hMap) { __leave; }
base = MapViewOfFile ( hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); if (!base) { __leave; }
//
// make sure concatFile file didn't end in end-of-file
//
if (base[concatSize - 1] == 0x1A) { base[concatSize - 1] = ' '; } //
// now append the other file
//
if (!ReadFile (sectFile, (LPVOID)(base + concatSize), sectSize, &bytes, NULL) || bytes != sectSize) { __leave; } //
// now try to commit changes
//
if (!UnmapViewOfFile (base)) { __leave; } base = NULL; if (!CloseHandle (hMap)) { __leave; } hMap = NULL; //
// close the handle to the temporary file and overwrite the real one
//
if (!CloseHandle (concatFile)) { __leave; } concatFile = INVALID_HANDLE_VALUE; SetFileAttributes (InfPath, FILE_ATTRIBUTE_NORMAL); b = MoveFileEx (tempFile, InfPath, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); } __finally { rc = b ? ERROR_SUCCESS : GetLastError (); DeleteFile (tempFile); if (base) { UnmapViewOfFile (base); } if (hMap) { CloseHandle (hMap); } if (concatFile != INVALID_HANDLE_VALUE) { CloseHandle (concatFile); } if (sectFile != INVALID_HANDLE_VALUE) { CloseHandle (sectFile); } if (section) { MyFree (section); } SetLastError (rc); }
return b; }
UINT pExpandUpdatesCab ( IN PVOID Context, IN UINT Code, IN UINT_PTR Param1, IN UINT_PTR Param2 ) { switch (Code) { case SPFILENOTIFY_FILEINCABINET: { PFILE_IN_CABINET_INFO FileInCabInfo = (PFILE_IN_CABINET_INFO)Param1; //
// extract the file name
//
PCTSTR p = _tcsrchr (FileInCabInfo->NameInCabinet, TEXT('\\')); if (p) { p++; } else { p = FileInCabInfo->NameInCabinet; }
lstrcpy (FileInCabInfo->FullTargetName, (PCTSTR)Context); pSetupConcatenatePaths ( FileInCabInfo->FullTargetName, p, SIZECHARS (FileInCabInfo->FullTargetName), NULL ); return FILEOP_DOIT; }
case SPFILENOTIFY_NEEDNEWCABINET: { PCABINET_INFO CabInfo = (PCABINET_INFO)Param1; SetuplogError( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_SYSSETUP_CAB_MISSING, CabInfo->CabinetPath, CabInfo->CabinetFile, CabInfo->DiskName, CabInfo->SetId, CabInfo->CabinetNumber, NULL, NULL ); return ERROR_FILE_NOT_FOUND; } }
return NO_ERROR; }
VOID pInstallUpdatesInf ( IN PCTSTR SectionToInstall )
/*++
Routine Description:
This function installs the specified section of STR_UPDATES_INF if this file is found inside updates.cab
Arguments:
SectionToInstall - Specifies what section to install
Return Value:
none
--*/
{ TCHAR infPath[MAX_PATH]; TCHAR commandLine[MAX_PATH + 30]; /*
STARTUPINFO si; PROCESS_INFORMATION pi; */
MYASSERT (!MiniSetup && !OobeSetup);
MYASSERT (g_DuShare[0]);
if (BuildPath (infPath, ARRAYSIZE(infPath), g_DuShare, STR_UPDATES_INF) && pDoesFileExist (infPath)) { //
// install this INF as if the user chose "Install" on the right-click popup menu
//
if (SUCCEEDED (StringCchPrintf ( commandLine, ARRAYSIZE(commandLine), TEXT("RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection %s %u %s"), SectionToInstall, 128, // don't reboot
infPath ))) { InvokeExternalApplicationEx (NULL, commandLine, NULL, INFINITE, FALSE); } else { MYASSERT (FALSE); } /*
ZeroMemory (&si, sizeof (si)); si.cb = sizeof (si); if (CreateProcess ( NULL, commandLine, NULL, NULL, FALSE, CREATE_NO_WINDOW | ABOVE_NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi )) { CloseHandle (pi.hProcess); CloseHandle (pi.hThread); */ } else { SetuplogError ( LogSevInformation, TEXT("DUInfo: No %1 to install"), 0, STR_UPDATES_INF, NULL, NULL ); } }
BOOL DuInitialize ( VOID )
/*++
Routine Description:
This function initializes DU in GUI setup
Arguments:
none
Return Value:
TRUE to indicate success; FALSE in case of failure; use GetLastError() to find the reason of failure
--*/
{ PTSTR cabFilename; TCHAR sourceCabPath[MAX_PATH]; TCHAR workingDir[MAX_PATH]; DWORD rc;
MYASSERT (!MiniSetup && !OobeSetup);
MYASSERT (AnswerFile[0]);
if (!GetPrivateProfileString ( WINNT_SETUPPARAMS, WINNT_SP_UPDATEDSOURCES, TEXT(""), sourceCabPath, ARRAYSIZE(sourceCabPath), AnswerFile )) { return TRUE; }
if (!GetPrivateProfileString ( WINNT_SETUPPARAMS, WINNT_SP_DYNUPDTWORKINGDIR, TEXT(""), workingDir, ARRAYSIZE(workingDir), AnswerFile )) {
MYASSERT (FALSE);
if (!GetWindowsDirectory (workingDir, ARRAYSIZE(workingDir))) { return FALSE; } if (!pSetupConcatenatePaths (workingDir, TEXT("setupupd"), ARRAYSIZE(workingDir), NULL)) { return FALSE; }
WritePrivateProfileString ( WINNT_SETUPPARAMS, WINNT_SP_DYNUPDTWORKINGDIR, workingDir, AnswerFile ); }
MYASSERT (workingDir[0]); if (!pSetupConcatenatePaths (workingDir, TEXT("updates"), ARRAYSIZE(workingDir), NULL) || !pSetupConcatenatePaths ( workingDir, #if defined(_AMD64_)
TEXT("amd64"), #elif defined(_X86_)
TEXT("i386"), #elif defined(_IA64_)
TEXT("ia64"), #else
#error "No Target Architecture"
#endif
ARRAYSIZE(workingDir), NULL )) { return FALSE; }
if (CreateMultiLevelDirectory (workingDir) != ERROR_SUCCESS) { rc = GetLastError (); SetuplogError ( LogSevError, TEXT("DUError: DuInitialize: failed to create %1 (%2!u!)\r\n"), 0, workingDir, rc, NULL, NULL ); return FALSE; }
//
// expand updates.cab in this folder
//
if (!SetupIterateCabinet (sourceCabPath, 0, pExpandUpdatesCab, (PVOID)workingDir)) { rc = GetLastError (); SetuplogError ( LogSevError, TEXT("DUError: DuInitialize: failed to expand %1 to %2 (%3!u!)\r\n"), 0, sourceCabPath, workingDir, rc, NULL, NULL ); return FALSE; }
//
// OK, everything is set up; go ahead and set the global variable
//
MYASSERT (ARRAYSIZE(g_DuShare) >= ARRAYSIZE(workingDir)); lstrcpy (g_DuShare, workingDir);
return TRUE; }
DWORD DuInstallCatalogs ( OUT SetupapiVerifyProblem* Problem, OUT PTSTR ProblemFile, IN PCTSTR DescriptionForError OPTIONAL )
/*++
Routine Description:
This function installs any catalogs found inside updates.cab
Arguments:
same as InstallProductCatalogs
Return Value:
If successful, the return value is ERROR_SUCCESS, otherwise it is a Win32 error code indicating the cause of the failure.
--*/
{ TCHAR catPath[MAX_PATH]; WIN32_FIND_DATA fd; HANDLE h; UINT ErrorMessageId; DWORD rc = ERROR_SUCCESS;
MYASSERT (!MiniSetup && !OobeSetup);
if (!g_DuShare[0]) { return ERROR_SUCCESS; }
if (!BuildPath (catPath, ARRAYSIZE(catPath), g_DuShare, TEXT("*.cat"))) { return ERROR_INSUFFICIENT_BUFFER; } h = FindFirstFile (catPath, &fd); if (h != INVALID_HANDLE_VALUE) {
do { if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
if (!BuildPath (catPath, ARRAYSIZE(catPath), g_DuShare, fd.cFileName)) { SetuplogError ( LogSevWarning, TEXT("DUWarning: ignoring catalog [%1\\%2] - path too long\r\n"), 0, g_DuShare, fd.cFileName, NULL, NULL ); continue; }
rc = pSetupVerifyCatalogFile (catPath); if (rc == NO_ERROR) { rc = pSetupInstallCatalog(catPath, fd.cFileName, NULL); if(rc != NO_ERROR) { ErrorMessageId = MSG_LOG_SYSSETUP_CATINSTALL_FAILED; } } else { ErrorMessageId = MSG_LOG_SYSSETUP_VERIFY_FAILED; }
if(rc != NO_ERROR) {
SetuplogError ( LogSevError, SETUPLOG_USE_MESSAGEID, ErrorMessageId, catPath, rc, NULL, NULL ); //
// Also, add an entry about this failure to setupapi's PSS
// exception logfile.
//
pSetupHandleFailedVerification ( MainWindowHandle, SetupapiVerifyCatalogProblem, catPath, DescriptionForError, pSetupGetCurrentDriverSigningPolicy(FALSE), TRUE, // no UI!
rc, NULL, // log context
NULL, // optional flags
NULL ); break; } } } while (FindNextFile (h, &fd));
FindClose (h); } else { SetuplogError ( LogSevWarning, TEXT("DUWarning: no catalogs found in %1\r\n"), 0, g_DuShare, NULL, NULL ); }
return rc; }
DWORD DuInstallUpdates ( VOID )
/*++
Routine Description:
This routine updates drvindex.inf to point setupapi to the new binaries.
Arguments:
none
Return Value:
If successful, the return value is ERROR_SUCCESS, otherwise it is a Win32 error code indicating the cause of the failure.
--*/
{ PTSTR cabFilename; TCHAR sourceCabPath[MAX_PATH]; TCHAR sourceSifPath[MAX_PATH]; TCHAR cabPath[MAX_PATH]; TCHAR infPath[MAX_PATH]; TCHAR tmpPath[MAX_PATH]; DWORD rc;
MYASSERT (!MiniSetup && !OobeSetup);
if (!g_DuShare[0]) { return ERROR_SUCCESS; }
//
// make sure updates.sif is available
//
if (!GetPrivateProfileString ( WINNT_SETUPPARAMS, WINNT_SP_UPDATEDSOURCES, TEXT(""), sourceCabPath, ARRAYSIZE(sourceCabPath), AnswerFile )) { return GetLastError (); }
MYASSERT (ARRAYSIZE(sourceSifPath) >= ARRAYSIZE(sourceCabPath)); lstrcpy (sourceSifPath, sourceCabPath); cabFilename = _tcsrchr (sourceSifPath, TEXT('.')); if (!cabFilename || _tcschr (cabFilename, TEXT('\\'))) { SetuplogError ( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_INVALID_UPDATESCAB_NAME, sourceCabPath, NULL, NULL ); return ERROR_INVALID_DATA; } lstrcpyn (cabFilename + 1, TEXT("sif"), (INT)(sourceSifPath + ARRAYSIZE(sourceSifPath) - (cabFilename + 1))); if (!pDoesFileExist (sourceSifPath)) { rc = GetLastError (); SetuplogError ( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_UPDATESSIF_NOT_FOUND, sourceSifPath, sourceCabPath, rc, NULL, NULL ); return rc; } //
// copy this where source cabs reside
//
rc = GetDriverCacheSourcePath (cabPath, ARRAYSIZE(cabPath)); if (rc != ERROR_SUCCESS) { SetuplogError ( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_DRIVER_CACHE_NOT_FOUND, rc, NULL, NULL ); return rc; } cabFilename = _tcsrchr (sourceCabPath, TEXT('\\')); if (cabFilename) { cabFilename++; } else { cabFilename = cabPath; } if (!pSetupConcatenatePaths (cabPath, cabFilename, ARRAYSIZE(cabPath), NULL)) { return ERROR_INSUFFICIENT_BUFFER; } //
// GUI setup should be restartable; copy file, don't move it
//
SetFileAttributes (cabPath, FILE_ATTRIBUTE_NORMAL); if (!CopyFile (sourceCabPath, cabPath, FALSE)) { rc = GetLastError (); SetuplogError ( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_FAILED_TO_COPY_UPDATES, rc, NULL, NULL ); return rc; } //
// now make sure the file attributes are set to RHS to protect it
//
SetFileAttributes (cabPath, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
//
// temp folder for expanded files
//
if (!GetTempPath (ARRAYSIZE(tmpPath), tmpPath)) { rc = GetLastError (); return rc; } //
// full path to drvindex.inf, assuming the file is in %windir%\inf
//
if (!GetWindowsDirectory (infPath, ARRAYSIZE(infPath))) { rc = GetLastError (); return rc; } if (FAILED (StringCchCat (infPath, ARRAYSIZE(infPath), TEXT("\\inf\\"))) || FAILED (StringCchCat (infPath, ARRAYSIZE(infPath), STR_DRIVERCACHEINF)) || GetFileAttributes (infPath) == (DWORD)-1) {
rc = GetLastError (); SetuplogError ( LogSevError, TEXT("DUError: %1 not found (rc=%2!u!)\r\n"), 0, infPath, rc, NULL, NULL ); return rc; }
//
// now patch drvindex.inf
//
if (!UpdateDrvIndex (infPath, cabFilename, sourceSifPath)) { rc = GetLastError (); SetuplogError ( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_FAILED_TO_UPDATE_DRVINDEX, rc, NULL, NULL ); SetFileAttributes (cabPath, FILE_ATTRIBUTE_NORMAL); DeleteFile (cabPath); return rc; }
//
// finally run updates.inf (first part)
//
pInstallUpdatesInf (STR_DEFAULTINSTALL);
return rc; }
BOOL DuInstallEndGuiSetupDrivers ( VOID )
/*++
Routine Description:
This routine installs any WU drivers not approved for the beginning of GUI setup.
Arguments:
none
Return Value:
If successful, the return value is TRUE
--*/
{ DWORD chars; TCHAR datPath[MAX_PATH]; TCHAR infPath[MAX_PATH]; TCHAR buf[MAX_PATH * 16]; PTSTR source, p, next; BOOL bRebootRequired; HWDBINF_ENUM e; PCTSTR pnpId; HMODULE hNewDev; HINF hGuiDrvsInf; INFCONTEXT ic; UINT line; BOOL (WINAPI* pfnUpdateDriver) ( HWND hwndParent, LPCWSTR HardwareId, LPCWSTR FullInfPath, DWORD InstallFlags, PBOOL bRebootRequired OPTIONAL );
//
// try to append any additional POST GUI setup drivers
// in the DevicePath
//
if (!SpSetupLoadParameter ( WINNT_SP_DYNUPDTADDITIONALPOSTGUIDRIVERS, buf, ARRAYSIZE(buf) )) { return TRUE; }
chars = lstrlen (buf); if (!chars) { return TRUE; }
//
// load the support library newdev.dll
//
hNewDev = LoadLibrary (TEXT("newdev.dll")); if (!hNewDev) { return FALSE; } (FARPROC)pfnUpdateDriver = GetProcAddress (hNewDev, "UpdateDriverForPlugAndPlayDevicesW"); if (!pfnUpdateDriver) { FreeLibrary (hNewDev); return FALSE; }
if (!HwdbInitializeW (NULL)) { SetuplogError ( LogSevWarning, TEXT("DUWarning: HwdbInitialize failed (rc=%1!u!); no DU drivers will be installed\r\n"), 0, GetLastError (), NULL, NULL ); FreeLibrary (hNewDev); return FALSE; }
//
// look for driver-controlling inf
//
hGuiDrvsInf = INVALID_HANDLE_VALUE; if (SpSetupLoadParameter ( WINNT_SP_DYNUPDTDRIVERINFOFILE, infPath, ARRAYSIZE(infPath) )) { if (pDoesFileExist (infPath)) { hGuiDrvsInf = SetupOpenInfFile (infPath, NULL, INF_STYLE_WIN4, &line); if (hGuiDrvsInf == INVALID_HANDLE_VALUE) { SetuplogError ( LogSevWarning, TEXT("DUWarning: SetupOpenInfFile(%1) failed (rc=%2!u!); all DU drivers will be installed\r\n"), 0, infPath, GetLastError (), NULL, NULL ); } } else { SetuplogError ( LogSevWarning, TEXT("DUWarning: File %1 missing; all DU drivers will be installed\r\n"), 0, infPath, NULL, NULL ); } } else { SetuplogError ( LogSevInformation, TEXT("DUInfo: File %1 missing; all DU drivers will be installed\r\n"), 0, infPath, NULL, NULL ); } source = buf; while (source) { next = _tcschr (source, TEXT(',')); if (next) { *next = 0; } p = source; if (*p == TEXT('\"')) { p = ++source; } while (*p && *p != TEXT('\"')) { p++; } *p = 0; if (pDoesDirExist (source)) { if (BuildPath (datPath, ARRAYSIZE(datPath), source, S_HWCOMP_DAT) && pDoesFileExist (datPath)) {
//
// OK, we have the file with hardware info
//
if (HwdbEnumFirstInf (&e, datPath)) { do { if (!BuildPath (infPath, ARRAYSIZE(infPath), source, e.InfFile) || !pDoesFileExist (infPath)) { continue; } //
// iterate through all PNPIDs in this INF
//
for (pnpId = e.PnpIds; *pnpId; pnpId = _tcschr (pnpId, 0) + 1) { //
// excluded PNPID are NOT in hwcomp.dat
// guidrvs.inf was already processed during winnt32
//
if (!pfnUpdateDriver ( NULL, pnpId, infPath, 0, // BUGBUG - if we specify INSTALLFLAG_NONINTERACTIVE and there is a driver signing problem, the API will fail!
&bRebootRequired )) { if (GetLastError() != ERROR_SUCCESS) { //
// well, if the device we wanted to update the driver for
// doesn't actually exist on this machine, don't log anything
//
if (GetLastError() != ERROR_NO_SUCH_DEVINST) { SetuplogError ( LogSevWarning, TEXT("DUWarning: UpdateDriverForPlugAndPlayDevices failed (rc=%3!u!) for PNPID=%1 (INF=%2)\r\n"), 0, pnpId, infPath, GetLastError (), NULL, NULL ); } } else { SetuplogError ( LogSevInformation, TEXT("DUInfo: UpdateDriverForPlugAndPlayDevices did not update the driver for PNPID=%1\r\n"), 0, pnpId, NULL, NULL ); } continue; } //
// SUCCESS! - log this information
//
SetuplogError ( LogSevInformation, TEXT("DUInfo: UpdateDriverForPlugAndPlayDevices succeeded for PNPID=%1\r\n"), 0, pnpId, NULL, NULL ); //
// also update the PNF with the info that this is an INTERNET driver
//
if (!SetupCopyOEMInf ( infPath, NULL, SPOST_URL, SP_COPY_REPLACEONLY, NULL, 0, NULL, NULL )) { SetuplogError ( LogSevInformation, TEXT("DUInfo: SetupCopyOEMInf failed to update OEMSourceMediaType for INF=%1\r\n"), 0, infPath, NULL, NULL ); } } } while (HwdbEnumNextInf (&e)); } } } if (next) { source = next + 1; } else { source = NULL; } }
HwdbTerminate ();
FreeLibrary (hNewDev);
return TRUE; }
VOID DuCleanup ( VOID )
/*++
Routine Description:
This routine performs DU cleanup
Arguments:
none
Return Value:
none
--*/
{ TCHAR buf[MAX_PATH * 16]; DWORD chars; HKEY key; PTSTR devicePath; PTSTR p; DWORD rc; DWORD size; DWORD type;
//
// cleanup the file system
//
MYASSERT (AnswerFile[0]); if (GetPrivateProfileString ( WINNT_SETUPPARAMS, WINNT_SP_DYNUPDTWORKINGDIR, TEXT(""), buf, ARRAYSIZE(buf), AnswerFile )) { Delnode (buf); } //
// cleanup the registry
//
chars = GetPrivateProfileString ( WINNT_SETUPPARAMS, WINNT_SP_DYNUPDTADDITIONALGUIDRIVERS, TEXT(""), buf, ARRAYSIZE(buf), AnswerFile ); if (chars > 0) { //
// got it; now remove it from DevicePath
//
rc = RegOpenKey (HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, &key); if (rc == ERROR_SUCCESS) { rc = RegQueryValueEx (key, REGSTR_VAL_DEVICEPATH, NULL, NULL, NULL, &size); if (rc == ERROR_SUCCESS) { devicePath = (PTSTR) MyMalloc (size); if (devicePath) { rc = RegQueryValueEx (key, REGSTR_VAL_DEVICEPATH, NULL, &type, (LPBYTE)devicePath, &size); if (rc == ERROR_SUCCESS && size / sizeof (TCHAR) >= chars + 1) { p = _tcsstr (devicePath, buf); if (p && (p == devicePath || *(p - 1) == TEXT(';')) && (!p[chars] || p[chars] == TEXT(';')) ) { if (p == devicePath) { _tcscpy (p, p[chars] == TEXT(';') ? p + chars + 1 : p + chars); } else { _tcscpy (p - 1, p + chars); } size = (_tcslen (devicePath) + 1) * sizeof (TCHAR); rc = RegSetValueEx (key, REGSTR_VAL_DEVICEPATH, 0, type, (PBYTE)devicePath, size); } } MyFree (devicePath); } } RegCloseKey (key); } }
g_DuShare[0] = 0; }
BOOL DuInstallDuAsms ( VOID )
/*++
Routine Description:
This routine installs additional DU assemblies
Arguments:
none
Return Value:
TRUE if successful, FALSE otherwise
--*/
{ TCHAR duasmsRoot[MAX_PATH]; TCHAR duasmsSource[MAX_PATH]; DWORD chars; SIDE_BY_SIDE SideBySide = {0}; BOOL b1; BOOL b2; PTSTR p; PCTSTR source; BOOL fSuccess = TRUE;
//
// look for any assemblies root specified in the answer file
//
MYASSERT (AnswerFile[0]); if (GetPrivateProfileString ( WINNT_SETUPPARAMS, WINNT_SP_UPDATEDDUASMS, TEXT(""), duasmsRoot, ARRAYSIZE(duasmsRoot), AnswerFile )) {
//
// make sure this directory exists; remove any existing quotes first
//
p = duasmsRoot; if (*p == TEXT('\"')) { p++; } source = p; while (*p && *p != TEXT('\"')) { p++; } *p = 0; if (pDoesDirExist (source)) { //
// root directory found
// first copy them in a protected location, then install assemblies from there
//
DWORD rc;
rc = GetDriverCacheSourcePath (duasmsSource, ARRAYSIZE(duasmsSource)); if (rc != ERROR_SUCCESS) { SetuplogError ( LogSevError, SETUPLOG_USE_MESSAGEID, MSG_LOG_DRIVER_CACHE_NOT_FOUND, rc, NULL, NULL ); return FALSE; } if (!pSetupConcatenatePaths (duasmsSource, TEXT("duasms"), ARRAYSIZE(duasmsSource), NULL)) { return FALSE; }
//
// first remove any already existing duasms "backup source" previously downloaded
//
Delnode (duasmsSource); //
// now tree copy from the temp location to this "backup source"
//
rc = TreeCopy (source, duasmsSource); if (rc != ERROR_SUCCESS) { SetuplogError( LogSevError, TEXT("Setup failed to TreeCopy %2 to %3 (TreeCopy failed %1!u!)\r\n"), 0, rc, source, duasmsSource, NULL, NULL ); return FALSE; }
//
// install duasms from there
//
b1 = SideBySidePopulateCopyQueue (&SideBySide, NULL, duasmsSource); b2 = SideBySideFinish (&SideBySide, b1);
if (!b1 || !b2) { fSuccess = FALSE; SetuplogError ( LogSevError, TEXT("DUError: DuInstallDuAsms failed (rc=%1!u!)\r\n"), 0, GetLastError (), NULL, NULL ); } } else { fSuccess = FALSE; SetuplogError ( LogSevError, TEXT("DUError: Invalid directory %1; DuInstallDuAsms failed\r\n"), 0, source, NULL, NULL ); } }
return fSuccess; }
BOOL BuildPathToInstallationFileEx ( IN PCTSTR Filename, OUT PTSTR PathBuffer, IN DWORD PathBufferSize, IN BOOL UseDuShare )
/*++
Routine Description:
This routine returns the path to the updated DU file, if one exists and the caller wanted this. Otherwise it will simply return the path to the CD file.
Arguments:
Filename - Specifies the filename to look for
PathBuffer - Receives the full path to the file
PathBufferSize - Specifies the size in chars of the above buffer
UseDuShare - Specifies TRUE if the function should check the DU location first
Return Value:
TRUE if building the path was successful. This does not guarantee the file exist.
--*/
{ if (g_DuShare[0] && UseDuShare) { if (BuildPath (PathBuffer, PathBufferSize, g_DuShare, Filename) && pDoesFileExist (PathBuffer) ) { return TRUE; } } return BuildPath (PathBuffer, PathBufferSize, LegacySourcePath, Filename); }
PCTSTR DuGetUpdatesPath ( VOID ) { return g_DuShare[0] ? g_DuShare : NULL; }
BOOL DuDoesUpdatedFileExistEx ( IN PCTSTR Filename, OUT PTSTR PathBuffer, OPTIONAL IN DWORD PathBufferSize )
/*++
Routine Description:
This routine checks if there exists an updated file with the given name.
Arguments:
Filename - Specifies the filename to look for
PathBuffer - Receives the full path to the file; optional
PathBufferSize - Specifies the size in chars of the above buffer
Return Value:
TRUE if a DU file with this name exists, FALSE otherwise
--*/
{ TCHAR path[MAX_PATH];
if (g_DuShare[0] && BuildPath (path, ARRAYSIZE(path), g_DuShare, Filename) && pDoesFileExist (path) ) { if (PathBuffer) { return SUCCEEDED (StringCchCopy (PathBuffer, PathBufferSize, path)); } return TRUE; } return FALSE; }
UINT DuSetupPromptForDisk ( HWND hwndParent, // parent window of the dialog box
PCTSTR DialogTitle, // optional, title of the dialog box
PCTSTR DiskName, // optional, name of disk to insert
PCTSTR PathToSource, // optional, expected source path
PCTSTR FileSought, // name of file needed
PCTSTR TagFile, // optional, source media tag file
DWORD DiskPromptStyle, // specifies dialog box behavior
PTSTR PathBuffer, // receives the source location
DWORD PathBufferSize, // size of the supplied buffer
PDWORD PathRequiredSize // optional, buffer size needed
) { TCHAR buffer[MAX_PATH]; DWORD size;
if ((DiskPromptStyle & IDF_CHECKFIRST) && PathBuffer && PathBufferSize && FileSought && g_DuShare[0] ) {
if (BuildPath (buffer, ARRAYSIZE(buffer), g_DuShare, FileSought) && pDoesFileExist (buffer) ) {
size = lstrlen (buffer) + 1; if (size > PathBufferSize) { if (PathRequiredSize) { *PathRequiredSize = size; } return DPROMPT_BUFFERTOOSMALL; } CopyMemory (PathBuffer, buffer, size * sizeof (buffer[0])); return DPROMPT_SUCCESS; } }
return SetupPromptForDisk ( hwndParent, DialogTitle, DiskName, PathToSource, FileSought, TagFile, DiskPromptStyle, PathBuffer, PathBufferSize, PathRequiredSize ); }
VOID DuInstallUpdatesInfFinal ( VOID )
/*++
Routine Description:
This function installs the final installation section of STR_UPDATES_INF if this file is found inside updates.cab
Arguments:
none
Return Value:
none
--*/
{ if (!g_DuShare[0]) { SetuplogError ( LogSevInformation, TEXT("DUInfo: %1 is disabled"), 0, TEXT(__FUNCTION__), NULL, NULL ); return; } pInstallUpdatesInf (STR_DEFAULTINSTALLFINAL); }
|