windows-nt/Source/XPSP1/NT/base/ntsetup/msoobci/devinst.c
2020-09-26 16:20:57 +08:00

982 lines
30 KiB
C

/*++
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 _INST_POSTPROCESSING_INFO {
DWORD Flags;
} INST_POSTPROCESSING_INFO;
DWORD
CALLBACK
DriverInstallComponents (
IN DI_FUNCTION InstallFunction,
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN OUT PCOINSTALLER_CONTEXT_DATA Context
)
/*++
Routine Description:
co-installer callback
catch the moment of call to DIF_INSTALLDEVICE
Consider installing exception packs at this point
If we succeed, we may need to restart device install
Arguments:
InstallFunction - DIF_INSTALLDEVICE
DeviceInfoSet/DeviceInfoData - describes device
Return Value:
status, normally NO_ERROR
--*/
{
DWORD Status = NO_ERROR;
if((g_VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && (g_VerInfo.dwMajorVersion >= 5)) {
//
// we should only be executing co-installers on Win2k+
// but this is an added sanity check
//
switch (InstallFunction)
{
case DIF_INSTALLDEVICE:
VerbosePrint(TEXT("handling DIF_INSTALLDEVICE"));
if(Context->PostProcessing) {
Status = DoDriverInstallComponentsPostProcessing(DeviceInfoSet,DeviceInfoData,Context);
} else {
Status = DoDriverInstallComponents(DeviceInfoSet,DeviceInfoData,Context);
}
VerbosePrint(TEXT("finished DIF_INSTALLDEVICE with status=0x%08x"),Status);
break;
default:
break;
}
}
return Status;
}
DWORD
DoDriverInstallComponents (
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN OUT PCOINSTALLER_CONTEXT_DATA Context
)
/*++
Routine Description:
co-installer callback
enumerate all the components sections
Arguments:
DeviceInfoSet/DeviceInfoData - describes device
Context - callback context
Return Value:
status, normally NO_ERROR
--*/
{
SP_DRVINFO_DATA DriverInfoData;
SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
HINF InfFile = INVALID_HANDLE_VALUE;
DWORD AndFlags = (DWORD)(-1);
DWORD OrFlags = (DWORD)0;
INFCONTEXT CompLine;
TCHAR InstallSectionName[LINE_LEN];
TCHAR CompSectionName[LINE_LEN];
DWORD FieldIndex;
DWORD FieldCount;
DWORD Status;
DWORD FinalStatus = NO_ERROR;
INST_POSTPROCESSING_INFO PostProcess;
ZeroMemory(&PostProcess,sizeof(PostProcess));
//
// determine selected driver
// and INF
//
DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
if (!SetupDiGetSelectedDriver( DeviceInfoSet,
DeviceInfoData,
&DriverInfoData)) {
Status = GetLastError();
DebugPrint(TEXT("Fail: SetupDiGetSelectedDriver, Error: 0x%08x"),Status);
goto clean;
}
DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
DeviceInfoData,
&DriverInfoData,
&DriverInfoDetailData,
sizeof(SP_DRVINFO_DETAIL_DATA),
NULL)) {
Status = GetLastError();
if (Status == ERROR_INSUFFICIENT_BUFFER) {
//
// We don't need the extended information. Ignore.
//
} else {
DebugPrint(TEXT("Fail: SetupDiGetDriverInfoDetail, 0xError: %08x"),Status);
goto clean;
}
}
InfFile = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
NULL,
INF_STYLE_WIN4,
NULL);
if (InfFile == INVALID_HANDLE_VALUE) {
Status = GetLastError();
DebugPrint(TEXT("Fail: SetupOpenInfFile"));
goto clean;
}
if(!SetupDiGetActualSectionToInstall(InfFile,
DriverInfoDetailData.SectionName,
InstallSectionName,
LINE_LEN,
NULL,
NULL)) {
Status = GetLastError();
DebugPrint(TEXT("Fail: SetupDiGetActualSectionToInstall, Error: 0x%08x"),Status);
goto clean;
}
//
// look for one or more Components= entries in INF section
//
if (SetupFindFirstLine(InfFile,
InstallSectionName,
KEY_COMPONENTS,
&CompLine)) {
VerbosePrint(TEXT("Components keyword found in %s"),DriverInfoDetailData.InfFileName);
do {
//
// Components = section,section,...
// first section @ index 1.
//
FieldCount = SetupGetFieldCount(&CompLine);
for(FieldIndex = 1;FieldIndex<=FieldCount;FieldIndex++) {
if(SetupGetStringField(&CompLine,
FieldIndex,
CompSectionName,
LINE_LEN,
NULL)) {
//
// we have a listed section
//
Status = DoDriverComponentsSection(InfFile,
CompSectionName,
&AndFlags,
&OrFlags);
if(Status != NO_ERROR) {
FinalStatus = Status;
goto clean;
}
} else {
Status = GetLastError();
DebugPrint(TEXT("Fail: SetupGetStringField, Error: 0x%08x"),Status);
//
// non-fatal
//
}
}
} while (SetupFindNextMatchLine(&CompLine,
KEY_COMPONENTS,
&CompLine));
//
// handle AndFlags/OrFlags here
//
if(OrFlags & (FLAGS_REBOOT|FLAGS_REINSTALL)) {
//
// reboot is required
//
HMACHINE hMachine = NULL;
SP_DEVINFO_LIST_DETAIL_DATA DevInfoListDetail;
SP_DEVINSTALL_PARAMS DeviceInstallParams;
DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
if(SetupDiGetDeviceInstallParams(DeviceInfoSet,
DeviceInfoData,
&DeviceInstallParams)) {
//
// set reboot flags
//
DeviceInstallParams.Flags |= DI_NEEDRESTART|DI_NEEDREBOOT;
SetupDiSetDeviceInstallParams(DeviceInfoSet,
DeviceInfoData,
&DeviceInstallParams);
}
DevInfoListDetail.cbSize = sizeof(DevInfoListDetail);
if(GetDeviceInfoListDetail(DeviceInfoSet,&DevInfoListDetail)) {
hMachine = DevInfoListDetail.RemoteMachineHandle;
}
Set_DevNode_Problem_Ex(DeviceInfoData->DevInst,
CM_PROB_NEED_RESTART,
CM_SET_DEVINST_PROBLEM_OVERRIDE,
hMachine);
}
if(OrFlags & FLAGS_REINSTALL) {
//
// we'll need to mark the device as needing reinstall when we go through post-processing
//
FinalStatus = ERROR_DI_POSTPROCESSING_REQUIRED;
PostProcess.Flags |= POSTFLAGS_REINSTALL;
}
}
clean:
if (InfFile != INVALID_HANDLE_VALUE) {
SetupCloseInfFile(InfFile);
}
if(FinalStatus == ERROR_DI_POSTPROCESSING_REQUIRED) {
//
// data to use during post-processing
//
INST_POSTPROCESSING_INFO *pPostProcess = malloc(sizeof(INST_POSTPROCESSING_INFO));
if(!pPostProcess) {
return ERROR_OUTOFMEMORY;
}
*pPostProcess = PostProcess;
Context->PrivateData = pPostProcess;
}
return FinalStatus;
}
DWORD
DoDriverInstallComponentsPostProcessing (
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN OUT PCOINSTALLER_CONTEXT_DATA Context
)
/*++
Routine Description:
co-installer callback
enumerate all the components sections
Arguments:
DeviceInfoSet/DeviceInfoData - describes device
Context - callback context
Return Value:
status, normally NO_ERROR
--*/
{
INST_POSTPROCESSING_INFO PostProcess;
SP_DEVINFO_LIST_DETAIL_DATA DevInfoListDetail;
HMACHINE hMachine = NULL;
if(!Context->PrivateData) {
return Context->InstallResult;
}
PostProcess = *(INST_POSTPROCESSING_INFO*)(Context->PrivateData);
free(Context->PrivateData);
Context->PrivateData = NULL;
DevInfoListDetail.cbSize = sizeof(DevInfoListDetail);
if(GetDeviceInfoListDetail(DeviceInfoSet,&DevInfoListDetail)) {
hMachine = DevInfoListDetail.RemoteMachineHandle;
}
if(PostProcess.Flags & POSTFLAGS_REINSTALL) {
Set_DevNode_Problem_Ex(DeviceInfoData->DevInst,
CM_PROB_REINSTALL,
CM_SET_DEVINST_PROBLEM_OVERRIDE,
hMachine);
}
return Context->InstallResult;
}
DWORD
DoDriverComponentsSection(
IN HINF InfFile,
IN LPCTSTR CompSectionName,
IN OUT DWORD *AndFlags,
IN OUT DWORD *OrFlags
)
/*++
Routine Description:
enumerate all the component entries in component section
component entry consists of
filename,flags,identity,version
filename is absolute directory, eg, %1%\foo.inf
flags - bit 16 set indicating Exception Pack
bit 0 set indicating device install needs restarting
identity - component GUID
version - component version
Arguments:
InfFile - handle to INF file
CompSectionName - handle to components section
AndFlags/OrFlags - accumulated flags
Return Value:
status, normally NO_ERROR
--*/
{
INFCONTEXT EntryLine;
TCHAR Path[MAX_PATH];
DWORD Flags;
INT FieldVal;
DWORD SubFlags;
DWORD Status;
if (!SetupFindFirstLine(InfFile,
CompSectionName,
NULL,
&EntryLine)) {
//
// section was empty
//
VerbosePrint(TEXT("Section [%s] is empty"),CompSectionName);
return NO_ERROR;
}
VerbosePrint(TEXT("Processing components section [%s]"),CompSectionName);
do {
if(!SetupGetStringField(&EntryLine,COMPFIELD_NAME,Path,MAX_PATH,NULL)) {
Status = GetLastError();
DebugPrint(TEXT("- Fail: SetupGetStringField(1), Error: 0x%08x"),Status);
return NO_ERROR;
}
VerbosePrint(TEXT("Processing component %s"),Path);
if(SetupGetIntField(&EntryLine,COMPFIELD_FLAGS,&FieldVal)) {
Flags = (DWORD)FieldVal;
} else {
Status = GetLastError();
DebugPrint(TEXT("- Fail: SetupGetIntField(2), Error: 0x%08x"),Status);
return NO_ERROR;
}
SubFlags = Flags & ~ FLAGS_METHOD;
switch(Flags & FLAGS_METHOD) {
case FLAGS_EXPACK:
Status = DoDriverExPack(&EntryLine,Path,&SubFlags);
break;
case FLAGS_QFE:
Status = DoDriverQfe(&EntryLine,Path,&SubFlags);
break;
default:
DebugPrint(TEXT("- Fail: Invalid component type"));
Status = ERROR_INVALID_DATA;
break;
}
if(Status != NO_ERROR) {
return Status;
}
if(SubFlags & FLAGS_INSTALLED) {
*AndFlags &= SubFlags;
*OrFlags |= SubFlags;
}
} while (SetupFindNextLine(&EntryLine,&EntryLine));
return NO_ERROR;
}
DWORD
DoDriverExPack(
IN INFCONTEXT *EntryLine,
IN LPCTSTR PathName,
IN OUT DWORD *Flags
)
/*++
Routine Description:
queries and potentially installs exception-pack component
Arguments:
EntryLine - context for remaining information
PathName - name of exception pack INF (param 1)
SubFlags - flags passed in (param 2) sans type of install
component entry consists of
filename,flags,identity,version
filename is absolute directory, eg, %1%\foo.inf
identity - component GUID
version - component version
Return Value:
status, normally NO_ERROR
if return value >= 0x80000000 then it's a HRESULT error
--*/
{
TCHAR CompIdentity[64]; // expecting a GUID
TCHAR CompVersion[64]; // major.minor
TCHAR CompDesc[DESC_SIZE]; // description
GUID ComponentGuid;
INT VerMajor = -1;
INT VerMinor = -1;
INT VerBuild = -1;
INT VerQFE = -1;
DWORD Status;
DWORD dwLen;
HRESULT hrStatus;
SETUP_OS_COMPONENT_DATA OsComponentData;
SETUP_OS_EXCEPTION_DATA OsExceptionData;
UINT uiRes;
TCHAR SrcPath[MAX_PATH];
TCHAR NewSrcPath[MAX_PATH];
TCHAR CompOsVerRange[128];
LPTSTR ToVerPart;
LPTSTR SrcName;
BOOL PreInst = FALSE;
VerbosePrint(TEXT("- %s is an exception pack"),PathName);
//
// now read in identity and version
// we can then check to see if an apropriate version installed
//
if(!SetupGetStringField(EntryLine,COMPFIELD_COMP,CompIdentity,ARRAY_SIZE(CompIdentity),NULL)) {
Status = GetLastError();
DebugPrint(TEXT("- Fail: SetupGetStringField(3), Error: 0x%08x"),Status);
return Status;
}
if(!SetupGetStringField(EntryLine,COMPFIELD_VER,CompVersion,ARRAY_SIZE(CompVersion),NULL)) {
Status = GetLastError();
DebugPrint(TEXT("- Fail: SetupGetStringField(4), Error: 0x%08x"),Status);
return Status;
}
if(!SetupGetStringField(EntryLine,COMPFIELD_DESC,CompDesc,ARRAY_SIZE(CompDesc),NULL)) {
CompDesc[0] = TEXT('\0');
}
if(SetupGetStringField(EntryLine,COMPFIELD_OSVER,CompOsVerRange,ARRAY_SIZE(CompOsVerRange),NULL)) {
//
// need to verify OS version range, do that now
//
int maj_f,min_f,build_f,qfe_f;
int maj_t,min_t,build_t,qfe_t;
ToVerPart = _tcschr(CompOsVerRange,TEXT('-'));
if(ToVerPart) {
*ToVerPart = TEXT('\0');
ToVerPart++;
}
hrStatus = VersionFromString(CompOsVerRange,&maj_f,&min_f,&build_f,&qfe_f);
if(!SUCCEEDED(hrStatus)) {
return (DWORD)hrStatus;
}
if((hrStatus == S_FALSE) || (qfe_f != 0)) {
return ERROR_INVALID_PARAMETER;
}
if(ToVerPart) {
hrStatus = VersionFromString(ToVerPart,&maj_t,&min_t,&build_t,&qfe_t);
if(!SUCCEEDED(hrStatus)) {
return (DWORD)hrStatus;
}
if((hrStatus == S_FALSE) || (qfe_t != 0)) {
return ERROR_INVALID_PARAMETER;
}
if(CompareVersion(maj_f,
min_f,
build_f>0 ? build_f : -1,
0,
g_VerInfo.dwMajorVersion,
g_VerInfo.dwMinorVersion,
g_VerInfo.dwBuildNumber,
0) > 0) {
VerbosePrint(TEXT("- Skipped (OS < %u.%u.%u)"),
maj_f,min_f,build_f);
return NO_ERROR;
} else if(CompareVersion(maj_t,
min_t,
build_t>0 ? build_t : -1,
0,
g_VerInfo.dwMajorVersion,
g_VerInfo.dwMinorVersion,
g_VerInfo.dwBuildNumber,
0) < 0) {
VerbosePrint(TEXT("- Skipped (OS > %u.%u.%u)"),
maj_t,min_t,build_t);
return NO_ERROR;
}
} else {
if(CompareVersion(maj_f,
min_f,
build_f,
0,
g_VerInfo.dwMajorVersion,
g_VerInfo.dwMajorVersion,
g_VerInfo.dwMajorVersion,
0) != 0) {
VerbosePrint(TEXT("- Skipped (OS != %u.%u.%u)"),
maj_f,min_f,build_f);
return NO_ERROR;
}
}
}
//
// fold CompIdentity into a GUID
//
hrStatus = GuidFromString(CompIdentity,&ComponentGuid);
if(!SUCCEEDED(hrStatus)) {
return (DWORD)hrStatus;
}
//
// and version
//
hrStatus = VersionFromString(CompVersion,&VerMajor,&VerMinor,&VerBuild,&VerQFE);
if(hrStatus == S_FALSE) {
return ERROR_INVALID_PARAMETER;
}
if(!SUCCEEDED(hrStatus)) {
return (DWORD)hrStatus;
}
//
// now do a component check
//
ZeroMemory(&OsComponentData,sizeof(OsComponentData));
OsComponentData.SizeOfStruct = sizeof(OsComponentData);
ZeroMemory(&OsExceptionData,sizeof(OsExceptionData));
OsExceptionData.SizeOfStruct = sizeof(OsExceptionData);
if(QueryRegisteredOsComponent(&ComponentGuid,&OsComponentData,&OsExceptionData)) {
//
// maybe already registered?
//
if(CompareCompVersion(VerMajor,VerMinor,VerBuild,VerQFE,&OsComponentData)<=0) {
VerbosePrint(TEXT("- Skipped, %u.%u.%u.%u <= %u.%u.%u.%u"),
VerMajor,VerMinor,VerBuild,VerQFE,
OsComponentData.VersionMajor,
OsComponentData.VersionMinor,
OsComponentData.BuildNumber,
OsComponentData.QFENumber);
return NO_ERROR;
}
}
VerbosePrint(TEXT("- Install, %u.%u.%u.%u > %u.%u.%u.%u"),
VerMajor,VerMinor,VerBuild,VerQFE,
OsComponentData.VersionMajor,
OsComponentData.VersionMinor,
OsComponentData.BuildNumber,
OsComponentData.QFENumber);
//
// we need to make sure component INF media is in
// prompt for media if interactive and INF cannot be found
//
dwLen = GetFullPathName(PathName,MAX_PATH,SrcPath,&SrcName);
if(dwLen >= MAX_PATH) {
return ERROR_INSUFFICIENT_BUFFER;
}
if(SrcName == SrcPath) {
//
// shouldn't happen
//
return ERROR_INVALID_DATA;
}
*CharPrev(SrcPath,SrcName) = TEXT('\0');
uiRes = SetupPromptForDisk(
NULL, // parent
NULL, // title
CompDesc[0] ? CompDesc : NULL, // disk name
SrcPath, // path to source
SrcName, // name of file
NULL, // tag file
IDF_CHECKFIRST|IDF_NOCOMPRESSED|IDF_NOSKIP,
NewSrcPath,
ARRAY_SIZE(NewSrcPath),
NULL);
switch(uiRes) {
case DPROMPT_SUCCESS:
break;
case DPROMPT_CANCEL:
case DPROMPT_SKIPFILE:
return ERROR_FILE_NOT_FOUND;
case DPROMPT_BUFFERTOOSMALL:
return ERROR_INSUFFICIENT_BUFFER;
case DPROMPT_OUTOFMEMORY:
return ERROR_OUTOFMEMORY;
default:
//
// shouldn't happen
//
return ERROR_INVALID_DATA;
}
hrStatus = ConcatPath(NewSrcPath,MAX_PATH,SrcName);
if(!SUCCEEDED(hrStatus)) {
return (DWORD)hrStatus;
}
hrStatus = InstallComponent(NewSrcPath,
COMP_FLAGS_NOUI,
&ComponentGuid,
VerMajor,
VerMinor,
VerBuild,
VerQFE,
CompDesc[0] ? CompDesc : NULL);
if(!SUCCEEDED(hrStatus)) {
return (DWORD)hrStatus;
}
//
// if install was not skipped, we get S_OK, else S_FALSE
//
if(hrStatus == S_OK) {
*Flags |= FLAGS_INSTALLED;
} else if(hrStatus == INST_S_REBOOT) {
*Flags |= FLAGS_INSTALLED|FLAGS_REBOOT;
}
return NO_ERROR;
}
DWORD
CheckQfe(
IN INT SpNum,
IN LPCTSTR QfeNum
)
/*++
Routine Description:
This is pretty dirty, it knows where the QFE #'s will go
in registry for Win2k/WinXP so checks there
this saves us running the QFE unless we need to
(assumption is that target OS version already checked)
Arguments:
SpNum - service pack # that fix should be in
QfeNum - QfeNum of fix
Return Value:
ERROR_INVALID_PARAMETER if version not supported
NO_ERROR if QFE installed
other status if QFE might not be installed
--*/
{
HKEY hKey;
TCHAR KeyPath[MAX_PATH*2];
LONG res;
//
// what about the SP level?
//
if(g_VerInfo.wServicePackMajor >= SpNum) {
VerbosePrint(TEXT("- Skipped (SP >= %u)"),SpNum);
return NO_ERROR;
}
if((g_VerInfo.dwMajorVersion == 5) && (g_VerInfo.dwMinorVersion == 0)) {
//
// check for QFE presence on Windows 2000
//
_sntprintf(KeyPath,ARRAY_SIZE(KeyPath),
TEXT("Software\\Microsoft\\Updates\\Windows 2000\\SP%u\\%s"),
SpNum,
QfeNum);
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
KeyPath,
0,
KEY_READ,
&hKey);
if(res == NO_ERROR) {
RegCloseKey(hKey);
}
return (DWORD)res;
} else if((g_VerInfo.dwMajorVersion == 5) && (g_VerInfo.dwMinorVersion == 1)) {
//
// check for QFE presence on Windows XP
//
_sntprintf(KeyPath,ARRAY_SIZE(KeyPath),
TEXT("Software\\Microsoft\\Updates\\Windows XP\\SP%u\\%s"),
SpNum,
QfeNum);
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
KeyPath,
0,
KEY_READ,
&hKey);
if(res == NO_ERROR) {
RegCloseKey(hKey);
}
return (DWORD)res;
} else {
return ERROR_INVALID_PARAMETER;
}
}
DWORD
DoDriverQfe(
IN INFCONTEXT *EntryLine,
IN LPCTSTR PathName,
IN OUT DWORD *Flags
)
/*++
Routine Description:
queries and potentially installs QFE
Arguments:
EntryLine - context for remaining information
PathName - name of exception pack INF (param 1)
SubFlags - flags passed in (param 2) sans type of install
component entry consists of
<path\name>,<flags>,<osver>,<os-sp>,<qfenum>
filename is absolute directory, eg, %1%\foo.exe
<flags> indicates what to do if qfe installed
<osver> indicates os version QFE is for, eg, 5.0
<os-sp> indicates service pack QFE is in, eg, 1
<qfenum> indicates the qfe number as found in registry
Return Value:
status, normally NO_ERROR
if return value >= 0x80000000 then it's a HRESULT error
--*/
{
TCHAR QfeOs[64]; // expecting major.minor
TCHAR QfeNum[64]; // some descriptive name
INT QfeSp;
INT VerMaj,VerMin,VerBuild,VerQfe;
TCHAR Buffer[MAX_PATH];
TCHAR CmdLine[MAX_PATH*3];
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
DWORD ExitCode;
DWORD Status;
HRESULT hrStatus;
UINT uiRes;
DWORD dwLen;
TCHAR SrcPath[MAX_PATH];
TCHAR NewSrcPath[MAX_PATH];
LPTSTR SrcName;
VerbosePrint(TEXT("- %s is a QFE"),PathName);
if(!SetupGetStringField(EntryLine,COMPFIELD_QFEOS,QfeOs,ARRAY_SIZE(QfeOs),NULL)) {
Status = GetLastError();
DebugPrint(TEXT("- Fail: SetupGetStringField(3), Error: 0x%08x"),Status);
return Status;
}
if(!SetupGetIntField(EntryLine,COMPFIELD_QFESP,&QfeSp)) {
Status = GetLastError();
DebugPrint(TEXT("- Fail: SetupGetIntField(4), Error: 0x%08x"),Status);
return Status;
}
if(!SetupGetStringField(EntryLine,COMPFIELD_QFENUM,QfeNum,ARRAY_SIZE(QfeNum),NULL)) {
Status = GetLastError();
DebugPrint(TEXT("- Fail: SetupGetStringField(5), Error: 0x%08x"),Status);
return Status;
}
//
// see if QFE is targeted at this version?
//
hrStatus = VersionFromString(QfeOs,&VerMaj,&VerMin,&VerBuild,&VerQfe);
if(!SUCCEEDED(hrStatus)) {
return (DWORD)hrStatus;
}
if((hrStatus == S_FALSE) || (VerBuild != 0) || (VerQfe != 0)) {
return ERROR_INVALID_PARAMETER;
}
if(CompareVersion(VerMaj,
VerMin,
0,
0,
g_VerInfo.dwMajorVersion,
g_VerInfo.dwMinorVersion,
0,
0) != 0) {
VerbosePrint(TEXT("- Skipped (OS != %u.%u)"),VerMaj,VerMin);
return NO_ERROR;
}
//
// see if the Qfe needs to be installed on this OS
//
Status = CheckQfe(QfeSp,QfeNum);
if(Status == ERROR_INVALID_PARAMETER) {
//
// invalid parameter because in invalid version was
// specified
//
DebugPrint(TEXT("- Cannot install QFE's for %u.%u"),
g_VerInfo.dwMajorVersion,
g_VerInfo.dwMinorVersion);
return Status;
}
//
// ok, has the QFE already been installed?
//
if(Status == NO_ERROR) {
return NO_ERROR;
}
//
// we need to make sure component INF media is in
// prompt for media if interactive and INF cannot be found
//
dwLen = GetFullPathName(PathName,MAX_PATH,SrcPath,&SrcName);
if(dwLen >= MAX_PATH) {
return ERROR_INSUFFICIENT_BUFFER;
}
if(SrcName == SrcPath) {
//
// shouldn't happen
//
return ERROR_INVALID_DATA;
}
*CharPrev(SrcPath,SrcName) = TEXT('\0');
uiRes = SetupPromptForDisk(
NULL, // parent
NULL, // title
QfeNum, // disk name
SrcPath, // path to source
SrcName, // name of file
NULL, // tag file
IDF_CHECKFIRST|IDF_NOCOMPRESSED|IDF_NOSKIP,
NewSrcPath,
ARRAY_SIZE(NewSrcPath),
NULL);
switch(uiRes) {
case DPROMPT_SUCCESS:
break;
case DPROMPT_CANCEL:
case DPROMPT_SKIPFILE:
return ERROR_FILE_NOT_FOUND;
case DPROMPT_BUFFERTOOSMALL:
return ERROR_INSUFFICIENT_BUFFER;
case DPROMPT_OUTOFMEMORY:
return ERROR_OUTOFMEMORY;
default:
//
// shouldn't happen
//
return ERROR_INVALID_DATA;
}
hrStatus = ConcatPath(NewSrcPath,MAX_PATH,SrcName);
if(!SUCCEEDED(hrStatus)) {
return (DWORD)hrStatus;
}
// now build up command line
//
lstrcpy(CmdLine,NewSrcPath);
lstrcat(CmdLine,TEXT(" -n -o -z -q"));
ZeroMemory(&StartupInfo,sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
ZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
//
// kick off rundll32 process to install QFE
//
if(!CreateProcess(NewSrcPath,
CmdLine,
NULL,
NULL,
FALSE, // don't inherit handles
CREATE_NO_WINDOW, // creation flags
NULL, // environment
NULL, // directory
&StartupInfo,
&ProcessInfo
)) {
return GetLastError();
}
if(WaitForSingleObject(ProcessInfo.hProcess,INFINITE) == WAIT_OBJECT_0) {
//
// process terminated 'fine', retrieve status from shared data
//
if(GetExitCodeProcess(ProcessInfo.hProcess,&ExitCode)) {
Status = (DWORD)ExitCode;
} else {
Status = GetLastError();
}
} else {
//
// failure
//
Status = ERROR_INVALID_PARAMETER;
}
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
if(Status != NO_ERROR) {
return Status;
}
if(CheckQfe(QfeSp,QfeNum)!=NO_ERROR) {
//
// sanity check failed
//
return E_UNEXPECTED;
}
//
// if install was not skipped, we get S_OK, else S_FALSE
//
#if 0
if(hrStatus == S_OK) {
*Flags |= FLAGS_INSTALLED;
} else if(hrStatus == INST_S_REBOOT) {
}
#endif
*Flags |= FLAGS_INSTALLED|FLAGS_REBOOT;
return NO_ERROR;
}