windows-nt/Source/XPSP1/NT/base/ntsetup/syssetup/external.c

576 lines
15 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
external.c
Abstract:
Routines for handling external INFs
Author:
Andrew Ritz (andrewr) 20-Nov-1998
Revision History:
stole a bunch of code from optional.c for this
--*/
#include "setupp.h"
#pragma hdrstop
#include <windowsx.h>
#include <shlobj.h>
VOID
ReportError (
IN LogSeverity Severity,
IN PTSTR MessageString,
IN UINT MessageId,
...
)
/*++
Routine Description:
Records an error message in the setup action log if we're in Setup,
or puts the message in a dialog box if we're in the cpl.
Arguments:
Severity - the type of message being written
... - the message id and its arguments
Return Value:
nothing.
--*/
{
va_list arglist;
va_start (arglist, MessageId);
SetuplogErrorV(
Severity,
MessageString,
MessageId,
&arglist);
va_end (arglist);
}
VOID
DoRunonce (
)
/*++
Routine Description:
Invokes runonce.
Arguments:
none.
Return Value:
nothing.
--*/
{
#define RUNONCE_TIMEOUT 60*1000*30 //30 minutes
DWORD reRet = NO_ERROR;
if((reRet = pSetupInstallStopEx( FALSE, INSTALLSTOP_NO_UI, NULL)) == NO_ERROR) {
//
// We successfully setup the registry values - now do runonce
//
InvokeExternalApplicationEx(NULL, L"RUNONCE -r", &reRet, RUNONCE_TIMEOUT, FALSE);
} else {
//
// Log/report an error that registry mods failed for optional compononent.
//
ReportError(LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_REGISTRY_ERROR,
TEXT("HKEY_LOCAL_MACHINE\\") REGSTR_PATH_RUNONCE,
0,
SETUPLOG_USE_MESSAGEID,
reRet,
0,
0
);
}
#ifdef _WIN64
//
// on win64, invoke the 32 bit version of runonce as well
//
{
WCHAR Path[MAX_PATH+50];
ExpandEnvironmentStrings(
L"%systemroot%\\SysWOW64\\RUNONCE.EXE -r",
Path,
sizeof(Path)/sizeof(WCHAR));
InvokeExternalApplicationEx(NULL, Path , &reRet, RUNONCE_TIMEOUT, FALSE);
}
#endif
}
BOOL
DoInstallComponentInfs(
IN HWND hwndParent,
IN HWND hProgress, OPTIONAL
IN UINT ProgressMessage,
IN HINF InfHandle,
IN PCWSTR InfSection
)
{
HINF *hInfs = NULL;
PCWSTR *Sections = NULL, *InfNames = NULL;
PCWSTR Inf,Section;
PVOID p;
INFCONTEXT Context;
PVOID QContext = NULL;
HSPFILEQ FileQueue = INVALID_HANDLE_VALUE;
DWORD ScanQueueResult;
LONG NumInfs, InfCount, i;
DWORD LastErrorValue = ERROR_SUCCESS;
BOOL b = FALSE;
REGISTRATION_CONTEXT RegistrationContext;
RtlZeroMemory(&RegistrationContext,sizeof(RegistrationContext));
//
// initialize a file queue
//
FileQueue = SetupOpenFileQueue();
if (FileQueue == INVALID_HANDLE_VALUE) {
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_ALWAYS_ERROR, 0,
SETUPLOG_USE_MESSAGEID,
ERROR_NOT_ENOUGH_MEMORY, 0,0);
goto e0;
}
//
// Initialize the default queue callback.
//
QContext = InitSysSetupQueueCallbackEx(
hwndParent,
hProgress,
ProgressMessage,
0,NULL);
if (!QContext) {
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_ALWAYS_ERROR, 0,
SETUPLOG_USE_MESSAGEID,
ERROR_NOT_ENOUGH_MEMORY, 0,0);
goto e1;
}
//
// process 'mandatory' component infs.
//
NumInfs = SetupGetLineCount(InfHandle, InfSection);
if (NumInfs <= 0)
{
//
// nothing in section. return success for doing nothing
//
b = TRUE;
goto e2;
}
hInfs = MyMalloc( sizeof(HINF) * NumInfs );
Sections = MyMalloc( sizeof(PCWSTR) * NumInfs );
InfNames = MyMalloc( sizeof(PCWSTR) * NumInfs );
if (!hInfs) {
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_ALWAYS_ERROR, 0,
SETUPLOG_USE_MESSAGEID,
ERROR_NOT_ENOUGH_MEMORY, 0,0);
goto e2;
}
if (!Sections) {
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_ALWAYS_ERROR, 0,
SETUPLOG_USE_MESSAGEID,
ERROR_NOT_ENOUGH_MEMORY, 0,0);
goto e3;
}
if (!InfNames) {
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_ALWAYS_ERROR, 0,
SETUPLOG_USE_MESSAGEID,
ERROR_NOT_ENOUGH_MEMORY, 0,0);
goto e4;
}
RemainingTime = CalcTimeRemaining(Phase_InstallComponentInfs);
SetRemainingTime(RemainingTime);
BEGIN_SECTION(L"Installing component files");
InfCount = 0;
if(SetupFindFirstLine(InfHandle,InfSection,NULL,&Context)) {
do {
if((Inf = pSetupGetField(&Context,1)) && (Section = pSetupGetField(&Context,2))) {
MYASSERT(InfCount < NumInfs);
//
// save away the section name for later on
//
Sections[InfCount] = pSetupDuplicateString(Section);
if (!Sections[InfCount]) {
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_ALWAYS_ERROR, 0,
SETUPLOG_USE_MESSAGEID,
ERROR_NOT_ENOUGH_MEMORY, 0,0);
goto e6;
}
InfNames[InfCount] = pSetupDuplicateString(Inf);
if (!InfNames[InfCount]) {
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_ALWAYS_ERROR, 0,
SETUPLOG_USE_MESSAGEID,
ERROR_NOT_ENOUGH_MEMORY, 0,0);
goto e6;
}
BEGIN_SECTION((PWSTR)Section);
SetupDebugPrint2( TEXT("Installing Section [%s] from %s\n"), Section, Inf );
//
// queue files and save away the inf handle for later on
//
hInfs[InfCount] = SetupOpenInfFile(Inf,NULL,INF_STYLE_OLDNT|INF_STYLE_WIN4,NULL);
if(hInfs[InfCount] && (hInfs[InfCount] != INVALID_HANDLE_VALUE)) {
PCWSTR Signature;
INFCONTEXT Cntxt;
HINF layout = NULL;
if (SetupFindFirstLine( hInfs[InfCount], L"Version",L"Signature", &Cntxt)) {
Signature = pSetupGetField(&Cntxt,1);
MYASSERT(Signature);
if (_wcsicmp(Signature,L"$Windows NT$") == 0) {
SetupOpenAppendInfFile(NULL,hInfs[InfCount],NULL);
} else {
layout = InfCacheOpenLayoutInf(hInfs[InfCount]);
}
}
b = SetupInstallFilesFromInfSection(
hInfs[InfCount],
layout,
FileQueue,
Section,
NULL,
SP_COPY_NEWER
);
if (!b) {
//
// report error but continue with the rest of the infs
//
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_BAD_SECTION,
Section,
Inf,
NULL,
SETUPLOG_USE_MESSAGEID,
GetLastError(),
0,
0
);
SetupCloseInfFile(hInfs[InfCount]);
hInfs[InfCount] = INVALID_HANDLE_VALUE;
}
} else {
//
// failed to open inf file
//
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_CANT_OPEN_INF, Inf,
0,0);
END_SECTION((PWSTR)Section);
goto e5;
}
}
InfCount++;
END_SECTION((PWSTR)Section);
} while(SetupFindNextLine(&Context,&Context));
} else {
// We should have caught this case when we created the buffers!
MYASSERT(FALSE);
}
//
// queued all the files. check if we really have to install any files. if not, we can save
// the time required to commit the queue to disk
//
if(!SetupScanFileQueue(
FileQueue,
SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
hwndParent,
NULL,
NULL,
&ScanQueueResult)) {
//
// SetupScanFileQueue should really never
// fail when you don't ask it to call a
// callback routine, but if it does, just
// go ahead and commit the queue.
//
ScanQueueResult = 0;
}
if( ScanQueueResult != 1 ){
b = SetupCommitFileQueue(
hwndParent,
FileQueue,
SysSetupQueueCallback,
QContext
);
}
LastErrorValue = b ? NO_ERROR : GetLastError();
END_SECTION(L"Installing component files");
TermSysSetupQueueCallback(QContext);
QContext = NULL;
//
// Delete the file queue.
//
if(FileQueue != INVALID_HANDLE_VALUE) {
SetupCloseFileQueue(FileQueue);
FileQueue = INVALID_HANDLE_VALUE;
}
if (!b) {
//
// error commiting the queue. we can't continue at this point since the next operations
// might require the files that we (didn't) copy
//
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_INF_ALWAYS_ERROR, 0,
SETUPLOG_USE_MESSAGEID,
LastErrorValue, 0,0);
goto e6;
}
BEGIN_SECTION(L"Installing component reg settings");
for (i = 0; i< InfCount; i++) {
INFCONTEXT Cntxt;
TCHAR ScratchSectionName[100];
if (hInfs[i] != INVALID_HANDLE_VALUE) {
//
// if the section contains an Addservice or DelService directive,
// we must explicitly install it since SetupInstallFromInfSection
// does not process services. Note that we create the service
// BEFORE we do the other stuff in the section, in case that
// "other stuff" wants to use the service.
//
lstrcpy( ScratchSectionName, Sections[i]);
lstrcat( ScratchSectionName, TEXT(".Services"));
if (SetupFindFirstLine(
hInfs[i],
ScratchSectionName,
L"AddService",
&Cntxt) ||
SetupFindFirstLine(
hInfs[i],
Sections[i],
ScratchSectionName,
&Cntxt)) {
b = SetupInstallServicesFromInfSectionEx(
hInfs[i],
ScratchSectionName,
0,
NULL,
NULL,
NULL,
NULL);
if (!b) {
//
// log an error and continue
//
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_BAD_SECTION,
Sections[i],InfNames[i], 0,
SETUPLOG_USE_MESSAGEID,
GetLastError(), 0,0);
}
}
b = SetupInstallFromInfSection(
hwndParent,
hInfs[i],
Sections[i],
(SPINST_ALL & ~SPINST_FILES) | SPINST_REGISTERCALLBACKAWARE,
NULL,
NULL,
0,
RegistrationQueueCallback,
(PVOID)&RegistrationContext,
NULL,
NULL
);
if (!b) {
//
// log an error and continue
//
ReportError(
LogSevError,
SETUPLOG_USE_MESSAGEID,
MSG_LOG_BAD_SECTION,
Sections[i],InfNames[i], 0,
SETUPLOG_USE_MESSAGEID,
GetLastError(), 0,0);
}
}
}
END_SECTION(L"Installing component reg settings");
b = TRUE;
e6:
for (i = 0; i < InfCount; i++) {
MYASSERT(Sections != NULL);
MYASSERT(InfNames != NULL);
MYASSERT(hInfs != INVALID_HANDLE_VALUE);
if (Sections[i]) {
MyFree(Sections[i]);
}
if (InfNames[i]) {
MyFree(InfNames[i]);
}
if (hInfs[i] != INVALID_HANDLE_VALUE) {
SetupCloseInfFile(hInfs[i]);
}
}
e5:
if (InfNames) {
MyFree(InfNames);
}
e4:
if (Sections) {
MyFree(Sections);
}
e3:
if (hInfs) {
MyFree(hInfs);
}
e2:
if (QContext) {
TermSysSetupQueueCallback(QContext);
}
e1:
if (FileQueue != INVALID_HANDLE_VALUE) {
SetupCloseFileQueue(FileQueue);
}
e0:
return(b);
}
BOOL
SetupCreateOptionalComponentsPage(
IN LPFNADDPROPSHEETPAGE AddPageCallback,
IN LPARAM Context
)
{
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
return( FALSE );
}
BOOL
ProcessCompatibilityInfs(
IN HWND hwndParent,
IN HWND hProgress, OPTIONAL
IN UINT ProgressMessage
)
{
WCHAR UnattendFile[MAX_PATH];
PCWSTR SectionName = pwCompatibility;
HINF UnattendInf;
GetSystemDirectory(UnattendFile,MAX_PATH);
pSetupConcatenatePaths(UnattendFile,WINNT_GUI_FILE,MAX_PATH,NULL);
UnattendInf = SetupOpenInfFile(UnattendFile,NULL,INF_STYLE_OLDNT,NULL);
if(UnattendInf == INVALID_HANDLE_VALUE) {
return FALSE;
}
DoInstallComponentInfs(hwndParent,
hProgress,
ProgressMessage,
UnattendInf,
SectionName );
SetupCloseInfFile( UnattendInf );
return( TRUE );
}