|
|
/*++
Copyright (c) Microsoft Corporation. All Rights Reserved.
Module Name:
msoobci.c
Abstract:
Exception Pack installer helper DLL Can be used as a co-installer, or called via setup app, or RunDll32 stub
This DLL is for internal distribution of exception packs to update OS components.
Author:
Jamie Hunter (jamiehun) 2001-11-27
Revision History:
Jamie Hunter (jamiehun) 2001-11-27
Initial Version
--*/ #include "msoobcip.h"
typedef struct _CALLBACKDATA { PVOID pDefContext; // context for default queue callback
LPCTSTR Media; // where old root was
LPCTSTR Store; // where new root is
BOOL PreCopy; // if using PreCopy section
} CALLBACKDATA;
HRESULT HandleReboot( IN DWORD Flags ) /*++
Routine Description:
Prompt for and execute reboot
Arguments:
Flags - how reboot should be handled
Return Value:
INST_S_REBOOT INST_S_REBOOTING
--*/
{ if(Flags & COMP_FLAGS_NOPROMPTREBOOT) { //
// TODO
// if set, reboot unconditionally
//
HANDLE Token; BOOL b; TOKEN_PRIVILEGES NewPrivileges; LUID Luid;
//
// we need to "turn on" reboot privilege
// if any of this fails, try reboot anyway
//
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) { goto try_reboot; }
if(!LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&Luid)) { CloseHandle(Token); goto try_reboot; }
NewPrivileges.PrivilegeCount = 1; NewPrivileges.Privileges[0].Luid = Luid; NewPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges( Token, FALSE, &NewPrivileges, 0, NULL, NULL );
CloseHandle(Token);
try_reboot:
//
// attempt reboot - inform system that this is planned hardware install
//
if(ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_FLAG_PLANNED |SHTDN_REASON_MAJOR_SOFTWARE |SHTDN_REASON_MINOR_INSTALLATION)) { return INST_S_REBOOTING; }
} else if(Flags & COMP_FLAGS_PROMPTREBOOT) { //
// TODO
// if set, prompt for reboot
//
if(IsInteractiveWindowStation()) { if(SetupPromptReboot(NULL,NULL,FALSE) & SPFILEQ_REBOOT_IN_PROGRESS) { return INST_S_REBOOTING; } } } return INST_S_REBOOT; }
HRESULT WINAPI InstallInfSectionW( IN LPCTSTR InfPath, IN LPCWSTR SectionName, OPTIONAL IN DWORD Flags ) /*++
Routine Description:
Does an install along lines of InstallHinfSection
Arguments:
InfPath - full path to INF file SectionName - name of section including any decoration
Return Value:
status as hresult
--*/ { TCHAR SectionNameBuffer[LINE_LEN]; TCHAR ServiceSection[LINE_LEN+32]; HINF hInf = INVALID_HANDLE_VALUE; HSPFILEQ hFileQueue = INVALID_HANDLE_VALUE; PVOID QueueContext = NULL; DWORD Status = NO_ERROR; BOOL reboot = FALSE; BOOL needUninstallInf = FALSE; INT res; INFCONTEXT InfLine; DWORD InstFlags;
//
// Some decisions are version based
//
//
// Load the inf file
//
hInf = SetupOpenInfFile(InfPath, NULL, INF_STYLE_WIN4, NULL); if(hInf == INVALID_HANDLE_VALUE) { Status = GetLastError(); goto final; }
if(!SectionName) { //
// determine section name
//
if(!SetupDiGetActualSectionToInstall(hInf, KEY_DEFAULTINSTALL, SectionNameBuffer, ARRAY_SIZE(SectionNameBuffer), NULL, NULL)) { Status = GetLastError(); goto final; } SectionName = SectionNameBuffer; }
//
// Check to see if the install section has a "Reboot" line.
// or otherwise reboot forced
//
if((Flags & COMP_FLAGS_NEEDSREBOOT) || (SetupFindFirstLine(hInf, SectionName, KEY_REBOOT, &InfLine))) { reboot = TRUE; }
//
// See if UI allowed
//
if(((Flags & COMP_FLAGS_NOUI)==0) && !IsInteractiveWindowStation()) { Flags |= COMP_FLAGS_NOUI; }
//
// Load any layout file
//
SetupOpenAppendInfFile(NULL, hInf, NULL);
//
// Create a setup file queue and initialize the default queue callback.
//
hFileQueue = SetupOpenFileQueue(); if(hFileQueue == INVALID_HANDLE_VALUE) { Status = GetLastError(); goto final; } QueueContext = SetupInitDefaultQueueCallbackEx( NULL, ((Flags & COMP_FLAGS_NOUI) ? INVALID_HANDLE_VALUE : NULL), 0, 0, 0 );
if(!QueueContext) { Status = GetLastError(); goto final; }
if(!SetupInstallFilesFromInfSection(hInf, NULL, hFileQueue, SectionName, NULL, 0 // SP_COPY_xxxx
)) { Status = GetLastError(); goto final; } //
// Commit file queue.
//
if(!SetupCommitFileQueue(NULL, hFileQueue, SetupDefaultQueueCallback, QueueContext)) { Status = GetLastError(); goto final; }
//
// Note, if the INF contains a (non-NULL) ClassGUID, then it will have
// been installed into %windir%\Inf during the above queue committal.
// We make no effort to subsequently uninstall it (and its associated
// PNF and CAT) if something fails below.
//
needUninstallInf = TRUE;
InstFlags = SPINST_ALL; if(g_VerInfo.dwMajorVersion < 5) { InstFlags = 0x1f; }
if(!SetupInstallFromInfSection(NULL, hInf, SectionName, InstFlags &~ SPINST_FILES, NULL, // HKEY_xxxx
NULL, // no copying...
0, NULL, NULL, NULL, NULL )) { Status = GetLastError(); goto final; } lstrcpyn(ServiceSection,SectionName,LINE_LEN); lstrcat(ServiceSection,KEY_DOTSERVICES); //
// If services section exists, install it
//
if(SetupFindFirstLine(hInf, ServiceSection, NULL, &InfLine)) { if(!SetupInstallServicesFromInfSection(hInf,ServiceSection,0)) { Status = GetLastError(); goto final; } if(GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) { reboot = TRUE; } } res = SetupPromptReboot(hFileQueue, NULL, TRUE); if((res!=-1) && (res & SPFILEQ_REBOOT_RECOMMENDED)) { reboot = TRUE; }
final:
if(QueueContext) { SetupTermDefaultQueueCallback(QueueContext); } if(hFileQueue != INVALID_HANDLE_VALUE) { SetupCloseFileQueue(hFileQueue); } if(hInf != INVALID_HANDLE_VALUE) { SetupCloseInfFile(hInf); } if(Status == NO_ERROR) { //
// are we meant to prompt for reboot?
//
if(reboot) { return HandleReboot(Flags); } else { return S_OK; } } if(needUninstallInf) { //
// call SetupUninstallOEMInf ?
//
} return HRESULT_FROM_SETUPAPI(Status); }
HRESULT WINAPI InstallInfSectionA( IN LPCSTR InfPath, IN LPCSTR SectionName, OPTIONAL IN DWORD Flags ) { TCHAR OutPath[MAX_PATH]; TCHAR OutSection[LINE_LEN]; // as per friendly name
INT sz; if(InfPath) { sz = MultiByteToWideChar(CP_ACP,0,InfPath,-1,OutPath,ARRAY_SIZE(OutPath)); if(!sz) { return E_INVALIDARG; } } if(SectionName) { sz = MultiByteToWideChar(CP_ACP,0,SectionName,-1,OutSection,ARRAY_SIZE(OutSection)); if(!sz) { return E_INVALIDARG; } } return InstallInfSection(InfPath ? OutPath : NULL, SectionName ? OutSection : NULL, Flags); }
HRESULT AttemptStoreCopy( IN CALLBACKDATA *pCallbackData, IN LPCTSTR Root, OPTIONAL IN LPCTSTR Source, IN LPCTSTR Target OPTIONAL ) /*++
Routine Description:
Copy from source to target, redirected to the expack store
Arguments:
pCallbackData - as passed to PreCopyQueueCallback Root - root to source directory Source - source, relative to Root Target - target name
Return Value:
status as hresult
--*/ { TCHAR FullSource[MAX_PATH]; TCHAR FullTarget[MAX_PATH]; LPTSTR SubDir; LPTSTR BaseName; LPTSTR DestName; LPCTSTR p; DWORD dwStatus; HRESULT hrStatus;
if(Root) { lstrcpyn(FullSource,Root,MAX_PATH); hrStatus = ConcatPath(FullSource,MAX_PATH,Source); if(!SUCCEEDED(hrStatus)) { return hrStatus; } } else { lstrcpyn(FullSource,Source,MAX_PATH); } //
// we want to determine the source sub-directory
//
SubDir = FullSource; p = pCallbackData->Media; while(*p && (*p == *SubDir)) { p = CharNext(p); SubDir = CharNext(SubDir); } if(*p || ((*SubDir != TEXT('\\')) && (*SubDir != TEXT('/')))) { //
// not a sub-directory of media
//
DebugPrint(TEXT("Not copying \"%s\" (not subdirectory of \"%s\")"),FullSource,pCallbackData->Media); return E_FAIL; } lstrcpyn(FullTarget,pCallbackData->Store,MAX_PATH); hrStatus = ConcatPath(FullTarget,MAX_PATH,SubDir); if(!SUCCEEDED(hrStatus)) { return hrStatus; } if(Target) { //
// change final name of this
//
BaseName = GetBaseName(Target); DestName = GetBaseName(FullTarget); if(((DestName-FullTarget)+lstrlen(BaseName))>=MAX_PATH) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } lstrcpy(DestName,BaseName); } if(GetFileAttributes(FullTarget)!=INVALID_FILE_ATTRIBUTES) { //
// allow file to be replaced
//
SetFileAttributes(FullTarget,FILE_ATTRIBUTE_NORMAL); } MakeSureParentPathExists(FullTarget); if(CopyFile(FullSource,FullTarget,FALSE)) { return S_OK; } dwStatus = GetLastError(); return HRESULT_FROM_WIN32(dwStatus); }
UINT CALLBACK PreCopyQueueCallback( IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2 ) /*++
Routine Description:
Intent is to copy files from existing media to final media Copy all files
Arguments:
FileName - name of file to scan
Return Value:
status as hresult
--*/ { CALLBACKDATA * pCallbackData = (CALLBACKDATA *)Context;
switch(Notification) { case SPFILENOTIFY_NEEDMEDIA: { UINT res; SOURCE_MEDIA *pMedia = (SOURCE_MEDIA *)Param1; SOURCE_MEDIA MediaCopy = *pMedia; LPCTSTR Path = NULL; //
// get the media in place - let default callback do this
// however we can't deal with media location being changed
// so don't allow it
//
MediaCopy.Flags |= SP_COPY_NOSKIP|SP_COPY_NOBROWSE; res= SetupDefaultQueueCallback(pCallbackData->pDefContext, Notification, (UINT_PTR)&MediaCopy, Param2); if(res==FILEOP_DOIT) { //
// typical case
// SourcePath unchanged
//
Path = pMedia->SourcePath; } else if(res == FILEOP_NEWPATH) { //
// alternative case
// we said above we don't want this
//
SetLastError(ERROR_CANCELLED); return FILEOP_ABORT; } else if(res == FILEOP_SKIP) { //
// skip
// we said above we don't want this
//
SetLastError(ERROR_CANCELLED); return FILEOP_ABORT; } else { //
// existing failure case
//
return res; } //
// if the tag exists at source media, copy it
// if the sourcefile exists at source media, copy it now
// (it might reference a cab file)
//
AttemptStoreCopy(pCallbackData,Path,pMedia->Tagfile,NULL); AttemptStoreCopy(pCallbackData,Path,pMedia->SourceFile,NULL); } return FILEOP_DOIT;
case SPFILENOTIFY_STARTCOPY: { UINT res; FILEPATHS *pPaths = (FILEPATHS*)Param1; if(pCallbackData->PreCopy) { //
// we want the target name (PRECOPY case)
//
AttemptStoreCopy(pCallbackData,NULL,pPaths->Source,pPaths->Target); } else { //
// we want the source name
//
AttemptStoreCopy(pCallbackData,NULL,pPaths->Source,NULL); } } return FILEOP_SKIP;
case SPFILENOTIFY_STARTDELETE: return FILEOP_SKIP;
case SPFILENOTIFY_STARTRENAME: return FILEOP_SKIP;
default: return SetupDefaultQueueCallback(pCallbackData->pDefContext, Notification, Param1, Param2); } }
HRESULT InstallExceptionPackFromInf( IN LPCTSTR InfPath, IN LPCTSTR Media, IN LPCTSTR Store, IN DWORD Flags ) /*++
Routine Description:
Assume INF installed into INF directory all decisions made media/store known
Arguments:
InfPath - name of Inf in Media location Media - InfPath less InfName Store - expack store Flags - various flags
Return Value:
status as hresult
--*/ { TCHAR SectionName[LINE_LEN]; TCHAR PrecopySectionName[LINE_LEN]; HINF hInf; HSPFILEQ hFileQueue = INVALID_HANDLE_VALUE; PVOID QueueContext = NULL; CALLBACKDATA CallbackData; DWORD Status;
//
// exception packs must be moved to a component-specific store
// run through a file-install to see what files we have to copy
// and use that list to determine source media
//
hInf = SetupOpenInfFile(InfPath, NULL, INF_STYLE_WIN4, NULL); if(hInf == INVALID_HANDLE_VALUE) { Status = GetLastError(); goto final; } if(!SetupDiGetActualSectionToInstall(hInf, KEY_DEFAULTINSTALL, SectionName, ARRAY_SIZE(SectionName), NULL, NULL)) { Status = GetLastError(); goto final; } SetupOpenAppendInfFile(NULL,hInf,NULL); hFileQueue = SetupOpenFileQueue(); if(hFileQueue == INVALID_HANDLE_VALUE) { Status = GetLastError(); goto final; }
if((lstrlen(SectionName)+10)>LINE_LEN) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } lstrcpy(PrecopySectionName,SectionName); lstrcat(PrecopySectionName,KEY_DOTPRECOPY);
QueueContext = SetupInitDefaultQueueCallbackEx( NULL, ((Flags & COMP_FLAGS_NOUI) ? INVALID_HANDLE_VALUE : NULL), 0, 0, 0 );
if(!QueueContext) { Status = GetLastError(); goto final; } ZeroMemory(&CallbackData,sizeof(CallbackData)); CallbackData.pDefContext = QueueContext; CallbackData.Store = Store; CallbackData.Media = Media;
if(SetupGetLineCount(hInf,PrecopySectionName)>0) { //
// do the pre-copy install via this section instead
//
CallbackData.PreCopy = TRUE; if(!SetupInstallFilesFromInfSection(hInf, NULL, hFileQueue, PrecopySectionName, NULL, 0 // SP_COPY_xxxx
)) { Status = GetLastError(); goto final; } } else { CallbackData.PreCopy = FALSE; if(!SetupInstallFilesFromInfSection(hInf, NULL, hFileQueue, SectionName, NULL, 0 // SP_COPY_xxxx
)) { Status = GetLastError(); goto final; } }
//
// Commit file queue, this will get the files to the store
//
if(!SetupCommitFileQueue(NULL, hFileQueue, PreCopyQueueCallback, &CallbackData)) { Status = GetLastError(); goto final; } if(hFileQueue != INVALID_HANDLE_VALUE) { SetupCloseFileQueue(hFileQueue); hFileQueue = INVALID_HANDLE_VALUE; } if(hInf != INVALID_HANDLE_VALUE) { SetupCloseInfFile(hInf); hInf = INVALID_HANDLE_VALUE; } //
// now install files from here to final destination
// this should be relatively quick so don't bother with UI
//
if(!(Flags & COMP_FLAGS_NOINSTALL)) { return InstallInfSection(InfPath, SectionName, COMP_FLAGS_NOUI); } return S_OK;
//
// TODO - move files to component directory
//
final: if(QueueContext) { SetupTermDefaultQueueCallback(QueueContext); } if(hFileQueue != INVALID_HANDLE_VALUE) { SetupCloseFileQueue(hFileQueue); } if(hInf != INVALID_HANDLE_VALUE) { SetupCloseInfFile(hInf); } return HRESULT_FROM_SETUPAPI(Status); }
DWORD DownlevelQueryInfOriginalFileInformation( IN HINF hInf, PSP_INF_INFORMATION InfInformation, PSP_ORIGINAL_FILE_INFO OriginalFileInfo ) /*++
Routine Description:
Emulates SetupQueryInfOriginalFileInformation we need to look in hINF to determine catalog name only partial implementation enough to support x86 (will degrade on other architectures)
Arguments:
hInf - handle to open INF file InfInformation - information obtained about original INF pInfOriginalFileInformation - fill with inf/catalog names
Return Value:
status as DWORD (not HRESULT)
--*/ { //
// in downlevel case, filename is name of file we opened
// catalog is referenced in the INF
//
// get basename of the INF
// (actually returns full name, but we'll deal with it right)
//
INFCONTEXT InfLine; SYSTEM_INFO SysInfo; TCHAR KeyName[LINE_LEN];
if(!SetupQueryInfFileInformation(InfInformation, 0, OriginalFileInfo->OriginalInfName, ARRAY_SIZE(OriginalFileInfo->OriginalInfName), NULL)) { return GetLastError(); } //
// now determine name of catalog
//
GetSystemInfo(&SysInfo); if(SysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { //
// look for .NTx86
// only makes sence for x86
// which is the only architecture we'll migrate Win9x/NT4 to Win2k+
//
lstrcpy(KeyName,INFSTR_KEY_CATALOGFILE); lstrcat(KeyName,TEXT(".NTx86")); if(SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,KeyName,&InfLine)) { if(SetupGetStringField(&InfLine, 1, OriginalFileInfo->OriginalCatalogName, ARRAY_SIZE(OriginalFileInfo->OriginalCatalogName), NULL)) { return NO_ERROR; } } } //
// look for .NT (even on 9x, as the exception pack will be re-parsed
// on NT)
//
lstrcpy(KeyName,INFSTR_KEY_CATALOGFILE); lstrcat(KeyName,TEXT(".NT")); if(SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,KeyName,&InfLine)) { if(SetupGetStringField(&InfLine, 1, OriginalFileInfo->OriginalCatalogName, ARRAY_SIZE(OriginalFileInfo->OriginalCatalogName), NULL)) { return NO_ERROR; } } //
// finally look for undecorated
//
if(SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,INFSTR_KEY_CATALOGFILE,&InfLine)) { if(SetupGetStringField(&InfLine, 1, OriginalFileInfo->OriginalCatalogName, ARRAY_SIZE(OriginalFileInfo->OriginalCatalogName), NULL)) { return NO_ERROR; } } //
// no catalog
//
OriginalFileInfo->OriginalCatalogName[0] = TEXT('\0'); return NO_ERROR; }
HRESULT GetInfOriginalFileInformation( IN HINF hInf, OUT PSP_ORIGINAL_FILE_INFO pInfOriginalFileInformation ) /*++
Routine Description:
Given a handle to an INF, determine names of inf and catalog files
Arguments:
hInf - handle to open INF file pInfOriginalFileInformation - inf/catalog names
Return Value:
status as hresult
--*/ { PSP_INF_INFORMATION pInfInformation = NULL; DWORD InfInformationSize; DWORD Status;
InfInformationSize = 8192; pInfInformation = (PSP_INF_INFORMATION)malloc(InfInformationSize); if (pInfInformation == NULL) { return E_OUTOFMEMORY; } if(!SetupGetInfInformation(hInf,INFINFO_INF_SPEC_IS_HINF,pInfInformation,InfInformationSize,&InfInformationSize)) { PVOID TempBuf; Status = GetLastError(); if(Status != ERROR_INSUFFICIENT_BUFFER) { free(pInfInformation); return HRESULT_FROM_SETUPAPI(Status); } TempBuf = realloc(pInfInformation,InfInformationSize); if(!TempBuf) { free(pInfInformation); return E_OUTOFMEMORY; } } if(!SetupGetInfInformation(hInf,INFINFO_INF_SPEC_IS_HINF,pInfInformation,InfInformationSize,&InfInformationSize)) { Status = GetLastError(); free(pInfInformation); return HRESULT_FROM_SETUPAPI(Status); } pInfOriginalFileInformation->cbSize = sizeof(SP_ORIGINAL_FILE_INFO); if((g_VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && (g_VerInfo.dwMajorVersion >= 5)) { //
// Win2k+ - have SetupAPI tell us the information (we're querying oem*.inf)
//
if (!QueryInfOriginalFileInformation(pInfInformation,0,NULL,pInfOriginalFileInformation)) { Status = GetLastError(); free(pInfInformation); return HRESULT_FROM_SETUPAPI(Status); } } else { //
// <Win2k - querying source INF, get information from there
//
Status = DownlevelQueryInfOriginalFileInformation(hInf,pInfInformation,pInfOriginalFileInformation); if(Status != NO_ERROR) { free(pInfInformation); return HRESULT_FROM_SETUPAPI(Status); } } free(pInfInformation); return S_OK; }
HRESULT DeleteDirectoryRecursive( IN LPCTSTR Path ) /*++
Routine Description:
delete specified directory recursively
Arguments:
Path - path of the directory to delete
Return Value:
as HRESULT S_FALSE if directory doesn't exist S_OK if directory deleted other error if, eg, files in use
--*/ { TCHAR Wildcard[MAX_PATH]; TCHAR Target[MAX_PATH]; HRESULT hrStatus; DWORD Status; HRESULT hrFirstError = S_FALSE; HANDLE hFind; WIN32_FIND_DATA FindData;
//
// enumerate the directory
//
lstrcpyn(Wildcard,Path,MAX_PATH); hrStatus = ConcatPath(Wildcard,MAX_PATH,TEXT("\\*.*")); if(!SUCCEEDED(hrStatus)) { return hrStatus; } hFind = FindFirstFile(Wildcard,&FindData); if(hFind != INVALID_HANDLE_VALUE) { hrFirstError = S_OK; do { if(lstrcmp(FindData.cFileName,TEXT(".")) == 0) { continue; } if(lstrcmp(FindData.cFileName,TEXT("..")) == 0) { continue; } lstrcpyn(Target,Path,MAX_PATH); hrStatus = ConcatPath(Target,MAX_PATH,FindData.cFileName); if(SUCCEEDED(hrStatus)) { if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { hrStatus = DeleteDirectoryRecursive(Target); if(SUCCEEDED(hrFirstError) && !SUCCEEDED(hrStatus)) { hrFirstError = hrStatus; } } else { SetFileAttributes(Target,FILE_ATTRIBUTE_NORMAL); if(!DeleteFile(Target)) { Status = GetLastError(); if(SUCCEEDED(hrFirstError)) { hrFirstError = HRESULT_FROM_WIN32(Status); } } } } else if(SUCCEEDED(hrFirstError)) { hrFirstError = hrStatus; } } while (FindNextFile(hFind,&FindData)); FindClose(hFind); } //
// now delete this directory
//
SetFileAttributes(Path,FILE_ATTRIBUTE_NORMAL); if(RemoveDirectory(Path) || !SUCCEEDED(hrFirstError)) { return hrFirstError; } Status = GetLastError(); if((Status == ERROR_PATH_NOT_FOUND) || (Status == ERROR_FILE_NOT_FOUND)) { return hrFirstError; } return HRESULT_FROM_WIN32(Status); }
HRESULT RevertStore( IN LPCTSTR BackupDir, IN LPCTSTR TargetDir ) /*++
Routine Description:
moves contents from backup back to original location overwriting files/directories if needed
Arguments:
BackupDir - directory restoring from TargetDir - directory restoring to
Return Value:
as HRESULT S_OK if backup created other error if, eg, files in use
--*/ { TCHAR Wildcard[MAX_PATH]; TCHAR Source[MAX_PATH]; TCHAR Target[MAX_PATH]; HRESULT hrStatus; HRESULT hrFirstError = S_FALSE; DWORD Status; DWORD dwRes; HANDLE hFind; WIN32_FIND_DATA FindData;
lstrcpyn(Wildcard,BackupDir,MAX_PATH); hrStatus = ConcatPath(Wildcard,MAX_PATH,TEXT("\\*.*")); if(!SUCCEEDED(hrStatus)) { return hrStatus; } hFind = FindFirstFile(Wildcard,&FindData); if(hFind != INVALID_HANDLE_VALUE) { hrFirstError = S_OK; do { if(lstrcmp(FindData.cFileName,TEXT(".")) == 0) { continue; } if(lstrcmp(FindData.cFileName,TEXT("..")) == 0) { continue; } lstrcpyn(Source,BackupDir,MAX_PATH); hrStatus = ConcatPath(Source,MAX_PATH,FindData.cFileName); if(!SUCCEEDED(hrStatus)) { if(SUCCEEDED(hrFirstError)) { hrFirstError = hrStatus; } continue; } lstrcpyn(Target,TargetDir,MAX_PATH); hrStatus = ConcatPath(Target,MAX_PATH,FindData.cFileName); if(!SUCCEEDED(hrStatus)) { if(SUCCEEDED(hrFirstError)) { hrFirstError = hrStatus; } continue; } //
// does target exist?
//
dwRes = GetFileAttributes(Target); if(dwRes != INVALID_FILE_ATTRIBUTES) { if(dwRes & FILE_ATTRIBUTE_DIRECTORY) { //
// revert store recursively
//
hrStatus = RevertStore(Source,Target); if(!SUCCEEDED(hrStatus)) { if(SUCCEEDED(hrFirstError)) { hrFirstError = hrStatus; } continue; } } else { SetFileAttributes(Target,FILE_ATTRIBUTE_NORMAL); if(!DeleteFile(Target)) { Status = GetLastError(); } } } if(!MoveFile(Source,Target)) { Status = GetLastError(); hrStatus = HRESULT_FROM_WIN32(Status); if(SUCCEEDED(hrFirstError)) { hrFirstError = hrStatus; } } } while (FindNextFile(hFind,&FindData)); FindClose(hFind); } //
// now attempt to remove the backup directory
//
if(RemoveDirectory(BackupDir) || !SUCCEEDED(hrFirstError)) { return hrFirstError; } Status = GetLastError(); if((Status == ERROR_PATH_NOT_FOUND) || (Status == ERROR_FILE_NOT_FOUND)) { return hrFirstError; } return HRESULT_FROM_WIN32(Status); }
HRESULT BackupStore( IN LPCTSTR Path, OUT LPTSTR BackupDir, OUT DWORD BackupDirLen ) /*++
Routine Description:
moves contents to new backup, ideally to \\$BACKUP$ returns name of backup
Arguments:
Path - path of the store BackupDir - filled with directory containing backup BackupDirLen - containing length of BackupDir
Return Value:
as HRESULT S_OK if backup created other error if, eg, files in use
--*/ { TCHAR Wildcard[MAX_PATH]; TCHAR Source[MAX_PATH]; TCHAR Target[MAX_PATH]; HRESULT hrStatus; DWORD Status; HANDLE hFind; WIN32_FIND_DATA FindData; int i; int len;
lstrcpyn(BackupDir,Path,BackupDirLen); hrStatus = ConcatPath(BackupDir,BackupDirLen,TEXT("\\$BACKUP$")); if(!SUCCEEDED(hrStatus)) { //
// obviously path is too big, no point ignoring
// as we'd fail elsewhere
//
return hrStatus; } len = lstrlen(BackupDir); if((BackupDirLen-len)<5) { return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); }
//
// first, if there's a backup, try and delete it
//
hrStatus = DeleteDirectoryRecursive(BackupDir); if(SUCCEEDED(hrStatus)) { hrStatus = MakeSurePathExists(BackupDir); } if((hrStatus == HRESULT_FROM_WIN32(ERROR_WRITE_PROTECT)) || (hrStatus == HRESULT_FROM_WIN32(ERROR_INVALID_ACCESS))) { //
// no point even trying again
//
return hrStatus; } for(i = 0;!SUCCEEDED(hrStatus) && i<1000;i++) { _sntprintf(BackupDir+len,5,TEXT(".%03u"),i); hrStatus = DeleteDirectoryRecursive(BackupDir); if(SUCCEEDED(hrStatus)) { hrStatus = MakeSurePathExists(BackupDir); } } if(!SUCCEEDED(hrStatus)) { return hrStatus; } //
// now we have a backup directory, move all the files there
//
lstrcpyn(Wildcard,Path,MAX_PATH); hrStatus = ConcatPath(Wildcard,MAX_PATH,TEXT("\\*.*")); if(!SUCCEEDED(hrStatus)) { return hrStatus; } hrStatus = S_FALSE; hFind = FindFirstFile(Wildcard,&FindData); if(hFind != INVALID_HANDLE_VALUE) { do { if(lstrcmp(FindData.cFileName,TEXT(".")) == 0) { continue; } if(lstrcmp(FindData.cFileName,TEXT("..")) == 0) { continue; } if(_tcsnicmp(FindData.cFileName,TEXT("$BACKUP$"),8) == 0) { //
// a/the backup directory
//
continue; } lstrcpyn(Source,Path,MAX_PATH); hrStatus = ConcatPath(Source,MAX_PATH,FindData.cFileName); if(!SUCCEEDED(hrStatus)) { break; } lstrcpyn(Target,BackupDir,MAX_PATH); hrStatus = ConcatPath(Target,MAX_PATH,FindData.cFileName); if(!SUCCEEDED(hrStatus)) { break; } if(!MoveFile(Source,Target)) { Status = GetLastError(); hrStatus = HRESULT_FROM_WIN32(Status); } if(!SUCCEEDED(hrStatus)) { break; } hrStatus = S_OK; } while (FindNextFile(hFind,&FindData)); FindClose(hFind); } if(!SUCCEEDED(hrStatus)) { RevertStore(BackupDir,Path); } return hrStatus; }
HRESULT WINAPI InstallComponentW( IN LPCTSTR InfPath, IN DWORD Flags, IN const GUID * CompGuid, OPTIONAL IN INT VerMajor, OPTIONAL IN INT VerMinor, OPTIONAL IN INT VerBuild, OPTIONAL IN INT VerQFE, OPTIONAL IN LPCTSTR Name OPTIONAL ) /*++
Routine Description:
exported for call by setup routine install a component with a given version assumed show progress while pulling files from original location
Arguments:
InfPath - path to INF file Flags - flags COMP_FLAGS_NOINSTALL - place in store, don't install COMP_FLAGS_NOUI - don't show any UI COMP_FLAGS_NOPROMPTREBOOT - reboot if needed (no prompt) COMP_FLAGS_PROMPTREBOOT - prompt for reboot if needed COMP_FLAGS_NEEDSREBOOT - assume reboot needed
CompGuid - if NULL, use GUID specified in INF (ComponentId) else verify against GUID specified in INF VerMajor/VerMinor/VerBuild/VerQFE - if -1, use version specified in INF (ComponentVersion) else use this version and verify against version if specified in INF Name - if NULL, use name specified in INF (ComponentName) else use this component name.
Return Value:
status as hresult
--*/ { HINF hInf = INVALID_HANDLE_VALUE; INFCONTEXT InfLine; TCHAR Buffer[MAX_PATH*3]; TCHAR FriendlyName[DESC_SIZE]; TCHAR NewStore[MAX_PATH]; TCHAR OldStore[MAX_PATH]; TCHAR MediaRoot[MAX_PATH]; TCHAR GuidString[64]; LPTSTR BaseName; LPTSTR SubDir; DWORD Status = NO_ERROR; // set Status or hrStatus
DWORD DwRes; UINT UiRes; HRESULT hrStatus = S_OK; GUID InfGuid; INT InfVerMajor,InfVerMinor,InfVerBuild,InfVerQFE; BOOL PrevReg = FALSE; BOOL NeedProxy = FALSE; BOOL CanRevert = FALSE; BOOL BackedUp = FALSE; SETUP_OS_COMPONENT_DATA OsComponentData; SETUP_OS_EXCEPTION_DATA OsExceptionData; SETUP_OS_COMPONENT_DATA NewOsComponentData; SETUP_OS_EXCEPTION_DATA NewOsExceptionData; SP_ORIGINAL_FILE_INFO InfOriginalFileInformation;
//
// validate args
//
if((InfPath == NULL) || (VerMajor<-1) || (VerMajor>65535) || (VerMinor<-1) || (VerMinor>65535) || (VerBuild<-1) || (VerBuild>65535) || (VerQFE<-1) || (VerQFE>65535) || (lstrlen(InfPath)>=MAX_PATH) || (Name && (lstrlen(Name)>=ARRAY_SIZE(FriendlyName)))) { return E_INVALIDARG; } //
// open the INF, we're going to do some information finding
//
hInf = SetupOpenInfFile(InfPath,NULL,INF_STYLE_WIN4,NULL); if(hInf == INVALID_HANDLE_VALUE) { Status = GetLastError(); goto final; } //
// get various information about this exception pack
// We want to know about the exception pack
// check classguid is correct
// get componentid
// get version if exists, and validate against any passed in
// get description if exists (overwritten by that passed in)
//
//
// CLASSGUID={F5776D81-AE53-4935-8E84-B0B283D8BCEF}
//
if(!SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,INFSTR_KEY_CLASSGUID,&InfLine)) { Status = GetLastError(); goto final; } if(!SetupGetStringField(&InfLine,1,Buffer,MAX_PATH,NULL)) { Status = GetLastError(); goto final; } if(_tcsicmp(Buffer,TEXT("{F5776D81-AE53-4935-8E84-B0B283D8BCEF}"))!=0) { hrStatus = SPAPI_E_CLASS_MISMATCH; goto final; } //
// determine what component the INF says
// ComponentId must exist for exception packs
//
if(!SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,KEY_COMPONENTID,&InfLine)) { Status = GetLastError(); goto final; } if(!SetupGetStringField(&InfLine,1,Buffer,MAX_PATH,NULL)) { Status = GetLastError(); goto final; } hrStatus = GuidFromString(Buffer,&InfGuid); if(SUCCEEDED(hrStatus)) { hrStatus = S_OK; } else { goto final; } if(CompGuid && !IsEqualGUID(CompGuid,&InfGuid)) { //
// mismatched
//
hrStatus = E_INVALIDARG; goto final; } //
// determine version - optional, just for msoobci
// but if not specified in INF in DriverVer = <date>,<version>
// must be passed in
//
if(SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,INFSTR_DRIVERVERSION_SECTION,&InfLine)) { if(!SetupGetStringField(&InfLine,2,Buffer,MAX_PATH,NULL)) { Status = GetLastError(); goto final; } hrStatus = VersionFromString(Buffer,&InfVerMajor,&InfVerMinor,&InfVerBuild,&InfVerQFE); if(hrStatus == S_FALSE) { hrStatus = E_INVALIDARG; goto final; } if(SUCCEEDED(hrStatus)) { hrStatus = S_OK; } else { goto final; } if(VerMajor>=0) { if(VerMajor != InfVerMajor) { hrStatus = E_INVALIDARG; goto final; } if(VerMinor>=0) { if(VerMinor != InfVerMinor) { hrStatus = E_INVALIDARG; goto final; } if(VerBuild>=0) { if(VerBuild != InfVerBuild) { hrStatus = E_INVALIDARG; goto final; } if(VerQFE>=0) { if(VerQFE != InfVerQFE) { hrStatus = E_INVALIDARG; goto final; } } } else if(VerQFE != -1) { //
// VerQFE must be -1
//
hrStatus = E_INVALIDARG; goto final; } } else if((VerBuild != -1) || (VerQFE != -1)) { //
// VerBuild & VerQFE must be -1
//
hrStatus = E_INVALIDARG; goto final; } } else if((VerMinor != -1) || (VerBuild != -1) || (VerQFE != -1)) { //
// VerMinor, VerBuild & VerQFE must be -1
//
hrStatus = E_INVALIDARG; goto final; } } else { //
// must be specified
//
if((VerMajor<0) || (VerMinor<0) || (VerBuild<0) || (VerQFE<0)) { hrStatus = E_INVALIDARG; goto final; } InfVerMajor = VerMajor; InfVerMinor = VerMinor; InfVerBuild = VerBuild; InfVerQFE = VerQFE; } //
// determine friendly name
// use Class= entry in INF (must always be specified)
// if Name not defined, use class name instead
//
if(!SetupFindFirstLine(hInf,INFSTR_SECT_VERSION,INFSTR_KEY_CLASS,&InfLine)) { Status = GetLastError(); goto final; } if(!Name) { if(!SetupGetStringField(&InfLine,1,FriendlyName,ARRAY_SIZE(FriendlyName),NULL)) { Status = GetLastError(); goto final; } Name = FriendlyName; }
//
// we might not need to update this package after all
//
ZeroMemory(&OsComponentData,sizeof(OsComponentData)); OsComponentData.SizeOfStruct = sizeof(OsComponentData); ZeroMemory(&OsExceptionData,sizeof(OsExceptionData)); OsExceptionData.SizeOfStruct = sizeof(OsExceptionData); if(QueryRegisteredOsComponent(&InfGuid,&OsComponentData,&OsExceptionData)) { //
// already registered? see if we supercede
//
if(((Flags & COMP_FLAGS_FORCE)==0) && (CompareCompVersion(InfVerMajor,InfVerMinor,InfVerBuild,InfVerQFE,&OsComponentData)<=0)) { VerbosePrint(TEXT("Not installing %s, %u.%u.%u.%u <= %u.%u.%u.%u"), InfPath, InfVerMajor,InfVerMinor,InfVerBuild,InfVerQFE, OsComponentData.VersionMajor, OsComponentData.VersionMinor, OsComponentData.BuildNumber, OsComponentData.QFENumber); hrStatus = S_FALSE; goto final; } PrevReg = TRUE; }
//
// determine MediaRoot and INF basename
//
DwRes= GetFullPathName(InfPath,MAX_PATH,MediaRoot,&BaseName); if(DwRes == 0) { Status = GetLastError(); goto final; } else if(DwRes >= MAX_PATH) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } if((BaseName == NULL) || (BaseName == InfPath) || !BaseName[0]) { hrStatus = E_INVALIDARG; goto final; } if(BaseName[-1] != TEXT('\\')) { hrStatus = E_INVALIDARG; goto final; } //
// split off MediaRoot and BaseName
//
BaseName[-1] = TEXT('\0'); //
// get Windows directory
//
UiRes = GetRealWindowsDirectory(Buffer,MAX_PATH); if(UiRes == 0) { Status = GetLastError(); goto final; } else if(UiRes >= MAX_PATH) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } if(!SUCCEEDED(ConcatPath(Buffer,MAX_PATH,TEXT("\\")))) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } SubDir = Buffer+lstrlen(Buffer); //
// c:\windows\ // ^-buffer ^-subdir
// we'll do a number of operations using the subdir part of this buffer
//
// if PrevReg is TRUE, we most likely have access to previous package
// so that we can install prev package to revert back to it
// we expect this package to be in the windows directory as per spec
// if it's not, then the old package might not still be around
//
if(PrevReg && _tcsncmp(OsExceptionData.ExceptionInfName,Buffer,SubDir-Buffer)==0) { //
// it's a sub-directory of %windir%
// now check for presence of INF and CAT files
//
DwRes = GetFileAttributes(OsExceptionData.ExceptionInfName); if(DwRes != INVALID_FILE_ATTRIBUTES) { DwRes = GetFileAttributes(OsExceptionData.CatalogFileName); if(DwRes != INVALID_FILE_ATTRIBUTES) { //
// both present, looks good
//
CanRevert = TRUE; } } }
//
// determine final path/name of INF and catalog
// We must place it directly in %windir%\<comp>
// (WFP relies on this!!!!)
// we'll backup what's there so that we can restore it later if needed
//
hrStatus = StringFromGuid(&InfGuid,GuidString,ARRAY_SIZE(GuidString)); if(!SUCCEEDED(hrStatus)) { goto final; } hrStatus = S_OK; _sntprintf(SubDir,MAX_PATH,TEXT("%s\\%s"), TEXT("RegisteredPackages"), GuidString ); if((lstrlen(Buffer)+16)>MAX_PATH) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } lstrcpy(NewStore,Buffer);
if(CanRevert) { hrStatus = BackupStore(NewStore,OldStore,ARRAY_SIZE(OldStore)); if(!SUCCEEDED(hrStatus)) { //
// if we failed backup, that means there's something bad
// such as files in the store in use
// probability is that we'll fail later
// so fail gracefully now instead of badly later
//
goto final; } hrStatus = S_OK; }
//
// see if %windir%\INF\<BaseName> is there?
//
lstrcpy(SubDir,TEXT("INF\\")); if(!SUCCEEDED(ConcatPath(Buffer,MAX_PATH,BaseName))) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } DwRes = GetFileAttributes(Buffer); if(DwRes != INVALID_FILE_ATTRIBUTES) { //
// replacing an existing INF
// to work around a cache bug, we'll kick the actuall install
// off in another process
//
NeedProxy = TRUE; }
hrStatus = MakeSurePathExists(NewStore); if(!SUCCEEDED(hrStatus)) { goto final; }
//
// install INF into %windir%\INF directory noting location the files
// should be
//
if((g_VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && (g_VerInfo.dwMajorVersion >= 5)) { //
// only do this on Win2k+
// this will have SetupAPI tell us the original name and the catalog
// name
//
if(CopyOEMInf(InfPath,NewStore,SPOST_PATH,0,NULL,0,NULL,NULL)) { //
// Switch to the INF that's in %windir%\INF directory
//
SetupCloseInfFile(hInf); hInf = SetupOpenInfFile(Buffer,NULL,INF_STYLE_WIN4,NULL); if(hInf == INVALID_HANDLE_VALUE) { Status = GetLastError(); goto final; } } else { Status = GetLastError(); goto final; } } //
// now find out what the catalog name would be
//
hrStatus = GetInfOriginalFileInformation(hInf,&InfOriginalFileInformation); if(!SUCCEEDED(hrStatus)) { goto final; } if((InfOriginalFileInformation.OriginalInfName[0]==TEXT('\0')) ||(InfOriginalFileInformation.OriginalCatalogName[0]==TEXT('\0'))) { //
// shouldn't happen
//
hrStatus = E_FAIL; goto final; }
ZeroMemory(&NewOsExceptionData,sizeof(NewOsExceptionData)); NewOsExceptionData.SizeOfStruct = sizeof(NewOsExceptionData); //
// INF name
//
BaseName = GetBaseName(InfOriginalFileInformation.OriginalInfName); lstrcpyn(NewOsExceptionData.ExceptionInfName,NewStore,ARRAY_SIZE(NewOsExceptionData.ExceptionInfName)); if(!SUCCEEDED(ConcatPath(NewOsExceptionData.ExceptionInfName,ARRAY_SIZE(NewOsExceptionData.ExceptionInfName),BaseName))) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } lstrcpy(Buffer,MediaRoot); if(!SUCCEEDED(ConcatPath(Buffer,MAX_PATH,BaseName))) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } if(!CopyFile(Buffer,NewOsExceptionData.ExceptionInfName,FALSE)) { Status = GetLastError(); goto final; } //
// CAT name
//
BaseName = GetBaseName(InfOriginalFileInformation.OriginalCatalogName); lstrcpyn(NewOsExceptionData.CatalogFileName,NewStore,ARRAY_SIZE(NewOsExceptionData.CatalogFileName)); if(!SUCCEEDED(ConcatPath(NewOsExceptionData.CatalogFileName,ARRAY_SIZE(NewOsExceptionData.CatalogFileName),BaseName))) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } lstrcpy(Buffer,MediaRoot); if(!SUCCEEDED(ConcatPath(Buffer,MAX_PATH,BaseName))) { Status = ERROR_INSUFFICIENT_BUFFER; goto final; } if(!CopyFile(Buffer,NewOsExceptionData.CatalogFileName,FALSE)) { Status = GetLastError(); goto final; }
//
// WFP may query exception pack as a source to restore files that are replaced
// change registration so if WFP does get in loop, it goes to the right place
//
if(PrevReg) { UnRegisterOsComponent(&InfGuid); } ZeroMemory(&NewOsComponentData,sizeof(NewOsComponentData)); NewOsComponentData.SizeOfStruct = sizeof(NewOsComponentData); NewOsComponentData.ComponentGuid = InfGuid; lstrcpyn(NewOsComponentData.FriendlyName,Name,ARRAY_SIZE(NewOsComponentData.FriendlyName)); NewOsComponentData.VersionMajor = (WORD)InfVerMajor; NewOsComponentData.VersionMinor = (WORD)InfVerMinor; NewOsComponentData.BuildNumber = (WORD)InfVerBuild; NewOsComponentData.QFENumber = (WORD)InfVerQFE; if(!RegisterOsComponent(&NewOsComponentData,&NewOsExceptionData)) { Status = GetLastError(); goto final; } if(((Flags & COMP_FLAGS_NOUI)==0) && !IsInteractiveWindowStation()) { Flags |= COMP_FLAGS_NOUI; }
if(NeedProxy) { //
// A bug in Win2k/XP means that we have problems if replacing an existing
// exception-pack component
//
hrStatus = ProxyInstallExceptionPackFromInf(InfPath,MediaRoot,NewStore,Flags); } else { hrStatus = InstallExceptionPackFromInf(InfPath,MediaRoot,NewStore,Flags); } if(!SUCCEEDED(hrStatus)) { //
// not sure best thing to do here, but
// the component that we had above is definately invalid
//
UnRegisterOsComponent(&InfGuid); if(PrevReg) { RegisterOsComponent(&OsComponentData,&OsExceptionData); } if(BackedUp) { //
// we got part through and failed. Re-install the old component
// to revert whatever we did
//
RevertStore(OldStore,NewStore); BackedUp = FALSE; InstallInfSection(OsExceptionData.ExceptionInfName,NULL,COMP_FLAGS_NOUI); } goto final; } else { //
// don't need backup any more
//
if(BackedUp) { DeleteDirectoryRecursive(OldStore); BackedUp = FALSE; } } //
// succeeded
//
Status = NO_ERROR; if(hrStatus == INST_S_REBOOT) { hrStatus = HandleReboot(Flags); } else { hrStatus = S_OK; }
final: if(hInf != INVALID_HANDLE_VALUE) { SetupCloseInfFile(hInf); } if((hrStatus == S_OK) && Status != NO_ERROR) { hrStatus = HRESULT_FROM_SETUPAPI(Status); } if(BackedUp) { //
// we need to revert the backup
//
RevertStore(OldStore,NewStore); } return hrStatus; }
HRESULT WINAPI InstallComponentA( IN LPCSTR InfPath, IN DWORD Flags, IN const GUID * CompGuid, OPTIONAL IN INT VerMajor, OPTIONAL IN INT VerMinor, OPTIONAL IN INT VerBuild, OPTIONAL IN INT VerQFE, OPTIONAL IN LPCSTR Name OPTIONAL ) { TCHAR OutPath[MAX_PATH]; TCHAR OutDesc[DESC_SIZE]; // as per friendly name
INT sz; if(InfPath) { sz = MultiByteToWideChar(CP_ACP,0,InfPath,-1,OutPath,ARRAY_SIZE(OutPath)); if(!sz) { return E_INVALIDARG; } } if(Name) { sz = MultiByteToWideChar(CP_ACP,0,Name,-1,OutDesc,ARRAY_SIZE(OutDesc)); if(!sz) { return E_INVALIDARG; } } return InstallComponent(InfPath ? OutPath : NULL, Flags, CompGuid, VerMajor, VerMinor, VerBuild, VerQFE, Name ? OutDesc : NULL); }
VOID WINAPI DoInstallW( IN HWND Window, IN HINSTANCE ModuleHandle, IN PCTSTR CommandLine, IN INT ShowCommand ) /*++
Routine Description:
exported for call by rundll32
Arguments:
Window - parent window (not used) ModuleHandle - not used CommandLine - see below ShowCommand - not used
CommandLine - "InfPath;Flags;GUID;High.Low.Build.QFE;Name" (; - CMD_SEP)
Return Value:
none
--*/ { TCHAR InfPath[MAX_PATH]; TCHAR Desc[DESC_SIZE]; TCHAR Hold[64]; INT VerMajor = -1; INT VerMinor = -1; INT VerBuild = -1; INT VerQFE = -1; GUID Guid; DWORD Flags = 0; LPGUID pGuid = NULL; LPTSTR pDesc = NULL; LPCTSTR pCmd = CommandLine; LPCTSTR pEnd; HRESULT hResult = S_OK;
//
// break CommandLine up into relevent parts
// First InfPath
//
pEnd = _tcschr(pCmd,CMD_SEP); if(!pEnd) { pEnd = pCmd+lstrlen(pCmd); } if((pEnd == pCmd) || ((pEnd-pCmd)>=MAX_PATH)) { hResult = E_INVALIDARG; goto final; } CopyMemory(InfPath,pCmd,(pEnd-pCmd)*sizeof(TCHAR)); InfPath[pEnd-pCmd] = TEXT('\0'); if(*pEnd == CMD_SEP) { pCmd = pEnd+1; if((*pCmd == CMD_SEP) || (*pCmd == TEXT('\0'))) { //
// skip
//
pEnd = pCmd; } else { //
// Flags
//
Flags = (DWORD)_tcstoul(pCmd,&(LPTSTR)pEnd,0); if((*pEnd != CMD_SEP) && (*pEnd != TEXT('\0'))) { hResult = E_INVALIDARG; goto final; } } } if(*pEnd == CMD_SEP) { pCmd = pEnd+1; if((*pCmd == CMD_SEP) || (*pCmd == TEXT('\0'))) { //
// skip
//
pEnd = pCmd; } else { //
// Guid
//
pEnd = _tcschr(pCmd,CMD_SEP); if(!pEnd) { pEnd = pCmd+lstrlen(pCmd); } if((pEnd-pCmd)>=ARRAY_SIZE(Hold)) { hResult = E_INVALIDARG; goto final; } CopyMemory(Hold,pCmd,(pEnd-pCmd)*sizeof(TCHAR)); Hold[pEnd-pCmd] = TEXT('\0'); hResult = GuidFromString(Hold,&Guid); if(!SUCCEEDED(hResult)) { goto final; } pGuid = &Guid; } } if(*pEnd == CMD_SEP) { pCmd = pEnd+1; if((*pCmd == CMD_SEP) || (*pCmd == TEXT('\0'))) { //
// skip
//
pEnd = pCmd; } else { //
// Version
//
pEnd = _tcschr(pCmd,CMD_SEP); if(!pEnd) { pEnd = pCmd+lstrlen(pCmd); } if((pEnd-pCmd)>=ARRAY_SIZE(Hold)) { hResult = E_INVALIDARG; goto final; } CopyMemory(Hold,pCmd,(pEnd-pCmd)*sizeof(TCHAR)); Hold[pEnd-pCmd] = TEXT('\0'); hResult = VersionFromString(Hold,&VerMajor,&VerMinor,&VerBuild,&VerQFE); if(!SUCCEEDED(hResult)) { goto final; } if(hResult == S_FALSE) { VerMajor = VerMinor = VerBuild = VerQFE = -1; } } } if(*pEnd == CMD_SEP) { pCmd = pEnd+1; pEnd = pCmd+lstrlen(pCmd); if(pEnd != pCmd) { if((pEnd-pCmd) >= ARRAY_SIZE(Desc)) { hResult = E_INVALIDARG; goto final; } CopyMemory(Desc,pCmd,(pEnd-pCmd)*sizeof(TCHAR)); Desc[pEnd-pCmd] = TEXT('\0'); pDesc = Desc; } } hResult = InstallComponent(InfPath,Flags,pGuid,VerMajor,VerMinor,VerBuild,VerQFE,pDesc);
final: if(SUCCEEDED(hResult)) { //
// deal with specific success scenarios
//
} else { //
// an error occurred
//
DebugPrint(TEXT("DoInstall failed with error: 0x%08x"),hResult); } }
VOID WINAPI DoInstallA( IN HWND Window, IN HINSTANCE ModuleHandle, IN PCSTR CommandLine, IN INT ShowCommand ) { TCHAR OutLine[MAX_PATH*2]; INT sz; sz = MultiByteToWideChar(CP_ACP,0,CommandLine,-1,OutLine,ARRAY_SIZE(OutLine)); if(!sz) { DebugPrint(TEXT("DoInstallA was passed too big a command line")); return; } DoInstall(Window,ModuleHandle,OutLine,ShowCommand); }
|