|
|
#include "precomp.h"
#pragma hdrstop
#include <io.h>
typedef struct _STANDALONE_COMP { struct _STANDALONE_COMP *Next; LPTSTR ComponentId; HINF Inf; OCMANAGER_ROUTINES HelperRoutines;
} STANDALONE_COMP, *PSTANDALONE_COMP;
PSTANDALONE_COMP StandaloneComponents = NULL;
DWORD InvokeStandAloneInstaller( IN LPCTSTR ComponentId, IN BOOL PreQueueCommit );
DWORD WaitOnApp( IN HANDLE Process, OUT PDWORD ExitCode );
void SetSuiteCurrentDir( IN PSTANDALONE_COMP Standalone ) { TCHAR NewPath[MAX_PATH]; LPTSTR p; PHELPER_CONTEXT pContext = (PHELPER_CONTEXT) Standalone->HelperRoutines.OcManagerContext; _tcscpy(NewPath,pContext->OcManager->MasterOcInfPath); p = _tcsrchr(NewPath,TEXT('\\')); if (p) { *p = 0; }
SetCurrentDirectory(NewPath);
}
BOOL CheckIfExistAndAskForMedia( IN PSTANDALONE_COMP Standalone, IN LPTSTR ExePath, IN LPCTSTR Description ) { // Check to see if the Exe even exits... if not ask the
PHELPER_CONTEXT pContext = (PHELPER_CONTEXT) Standalone->HelperRoutines.OcManagerContext; SOURCE_MEDIA Media; TCHAR NewPath[MAX_PATH*3]; LPTSTR p; BOOL b = FALSE; UINT i;
// Prepare Exe file name, Strip off arguments
// Can't have spaces in Exe name.
_tcscpy(NewPath,ExePath); p = _tcschr(NewPath,TEXT(' ')); if(!p) { p = _tcschr(NewPath,TEXT('\t')); } if(p) { *p = 0; }
// Check if we can find the file -
// Assumes that we have right CD or full path
i = GetFileAttributes(NewPath);
if ( i == -1 ) { // now backup to file part, strip off path leave file name.
p = _tcsrchr(NewPath,TEXT('\\')); if (!p) { p = NewPath; } Media.Reserved = NULL; // PCWSTR
Media.Description= Description; // PCWSTR
Media.SourcePath = NULL; // PCWSTR
Media.SourceFile = p; // PCWSTR
Media.Tagfile = p; // PCWSTR may be NULL
Media.Flags = 0; // DWORD subset of SP_COPY_xxx
for(b=FALSE,i=0; (i<pContext->OcManager->TopLevelOcCount) && !b; i++) {
b = OcInterfaceNeedMedia( pContext->OcManager, pContext->OcManager->TopLevelOcStringIds[i], &Media, (LPTSTR)NewPath ); if (b) { // Now we have a new Path to the file
// get the last segment of the path
p = _tcsrchr(ExePath,TEXT('\\')); if (p) { _tcscat(NewPath,p); } else { _tcscat(NewPath,TEXT("\\")); _tcscat(NewPath,ExePath); } // Rewrite path
_tcscpy(ExePath,NewPath); break; } } } return b; }
DWORD StandAloneSetupAppInterfaceRoutine( IN LPCVOID ComponentId, IN LPCVOID SubcomponentId, IN UINT Function, IN UINT_PTR Param1, IN OUT PVOID Param2 ) { DWORD d; PSTANDALONE_COMP Standalone,Prev;
switch(Function) {
case OC_PREINITIALIZE: //
// Run with native character width.
//
#ifdef UNICODE
d = OCFLAG_UNICODE; #else
d = OCFLAG_ANSI; #endif
break;
case OC_INIT_COMPONENT: //
// Inform OC Manager of the version we want.
//
((PSETUP_INIT_COMPONENT)Param2)->ComponentVersion = OCMANAGER_VERSION;
d = ERROR_NOT_ENOUGH_MEMORY; if(Standalone = pSetupMalloc(sizeof(STANDALONE_COMP))) { if(Standalone->ComponentId = pSetupMalloc((lstrlen(ComponentId)+1) * sizeof(TCHAR))) {
lstrcpy(Standalone->ComponentId,ComponentId);
Standalone->Inf = ((PSETUP_INIT_COMPONENT)Param2)->ComponentInfHandle; Standalone->HelperRoutines = ((PSETUP_INIT_COMPONENT)Param2)->HelperRoutines;
Standalone->Next = StandaloneComponents; StandaloneComponents = Standalone;
d = NO_ERROR; } else { pSetupFree(Standalone); } }
break;
case OC_SET_LANGUAGE: d = TRUE; break;
case OC_QUERY_IMAGE: d = 0; break;
case OC_REQUEST_PAGES: //
// This component has no pages.
//
d = 0; break;
case OC_QUERY_SKIP_PAGE:
d = FALSE; break;
case OC_QUERY_STATE: { DWORD dSetupMode; //
// Allow selection state transition.
//
for(Standalone=StandaloneComponents; Standalone; Standalone=Standalone->Next) { if(!lstrcmpi(ComponentId,Standalone->ComponentId)) { break; } }
dSetupMode = Standalone->HelperRoutines.GetSetupMode( Standalone->HelperRoutines.OcManagerContext); //
// Use default if we have no option...
//
d = SubcompUseOcManagerDefault;
if (Param1 == OCSELSTATETYPE_CURRENT) {
switch(dSetupMode & SETUPMODE_PRIVATE_MASK) { default: d = SubcompUseOcManagerDefault; break; case SETUPMODE_REMOVEALL: d = SubcompOff; break; case SETUPMODE_ADDEXTRACOMPS: case SETUPMODE_ADDREMOVE: case SETUPMODE_UPGRADEONLY: case SETUPMODE_REINSTALL: d = Standalone->HelperRoutines.QuerySelectionState( Standalone->HelperRoutines.OcManagerContext, SubcomponentId, OCSELSTATETYPE_ORIGINAL) ? SubcompOn : SubcompOff; break; } }
break; } case OC_QUERY_CHANGE_SEL_STATE: d = TRUE; break;
case OC_CALC_DISK_SPACE:
for(Standalone=StandaloneComponents; Standalone; Standalone=Standalone->Next) { if(!lstrcmpi(ComponentId,Standalone->ComponentId)) { break; } }
if(Standalone) {
INFCONTEXT Context;
if(SetupFindFirstLine(Standalone->Inf,ComponentId,TEXT("DiskSpaceEstimate"),&Context)) {
LONGLONG Space; int SpaceMB; BOOL b; TCHAR Path[MAX_PATH];
if(SetupGetIntField(&Context,1,&SpaceMB)) {
Space = (LONGLONG)SpaceMB * (1024*1024); if(!Param1) { Space = 0 - Space; }
GetWindowsDirectory(Path,MAX_PATH); Path[3] = 0;
b = SetupAdjustDiskSpaceList((HDSKSPC)Param2,Path,Space,0,0);
d = b ? NO_ERROR : GetLastError(); } else { d = ERROR_INVALID_DATA; } } } else { d = NO_ERROR; }
break;
case OC_QUEUE_FILE_OPS: //
// No files to queue.
//
d = NO_ERROR; break;
case OC_NOTIFICATION_FROM_QUEUE: d = 0; break;
case OC_QUERY_STEP_COUNT: //
// Just use 1 step.
//
d = 1; break;
case OC_ABOUT_TO_COMMIT_QUEUE: case OC_COMPLETE_INSTALLATION:
// Figure out whether state changed, and if so, invoke
// the install/uninstall cmd line. Just to be safe, we ignore
// any requests that are not for the component as a whole,
// since these were not supposed to have been specified in the first place.
//
d = SubcomponentId ? NO_ERROR : InvokeStandAloneInstaller(ComponentId,Function == OC_ABOUT_TO_COMMIT_QUEUE);
break;
case OC_CLEANUP: //
// Return value is ignored.
//
Prev = NULL; for(Standalone=StandaloneComponents; Standalone; Standalone=Standalone->Next) {
if(!lstrcmpi(ComponentId,Standalone->ComponentId)) { if(Prev) { Prev->Next = Standalone->Next; } else { StandaloneComponents = Standalone->Next; }
pSetupFree(Standalone->ComponentId); pSetupFree(Standalone); break; }
Prev = Standalone; } break;
default: //
// Return something sane.
//
d = 0; break; }
return(d); }
DWORD RunStandaloneCmd( IN PSTANDALONE_COMP Standalone, IN LPCTSTR Description, IN LPCTSTR cmd ) { STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInfo; TCHAR ExePath[3*MAX_PATH]; DWORD ExitCode; BOOL b;
ZeroMemory(&StartupInfo,sizeof(STARTUPINFO)); ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION));
StartupInfo.cb = sizeof(STARTUPINFO);
lstrcpyn(ExePath,cmd,3*MAX_PATH);
pOcExternalProgressIndicator(Standalone->HelperRoutines.OcManagerContext,TRUE);
// We will try two times to invoke the external setup. For both attempt the Current
// Directory is set the same directory of where the suite.inf file is located.
// In the first attempt we invoke the command line as we find it from the Standalone
// inf file. An for almost all cases this will work. If we fail in that invokcation we
// ask the suite dll for a "Needs Media" can allow them to tell us where the Standalone exe is.
// This accounts the two following form of commands
// InstalledCmd = "wpie15-x86.exe /Q:A /R:NG"
// UninstallCmd = "RunDll32 ADVPACK.DLL,LaunchINFSection %17%\enuwpie.inf,WebPostUninstall,5"
// Where Wpie15-x86.exe will be found in the Current Directory, and if it's not we will ask the
// suite to provide it. (Web Download) or in the second case where a system dll must be executed
// to uninstall the product. What's not covered here is if we fail to do a createProcess on the
// second form of command.
b = FALSE; while( ! b) { b = CreateProcess( NULL, ExePath, NULL, NULL, FALSE, 0, NULL, NULL, // Sysocmgr set CD to sourcedir
&StartupInfo, &ProcessInfo );
// If we failed to start the external setup, try asking the suite where
// to find this
if ( ! b) { if ( ! CheckIfExistAndAskForMedia(Standalone, ExePath, Description)) { // if the Suite could not locate the exe thengive up
break; } } }
if (!b) { pOcExternalProgressIndicator(Standalone->HelperRoutines.OcManagerContext,FALSE); return GetLastError(); }
CloseHandle(ProcessInfo.hThread); WaitOnApp(ProcessInfo.hProcess,&ExitCode); CloseHandle(ProcessInfo.hProcess); pOcExternalProgressIndicator(Standalone->HelperRoutines.OcManagerContext,FALSE);
return NO_ERROR; }
DWORD InvokeStandAloneInstaller( IN LPCTSTR ComponentId, IN BOOL PreQueueCommit ) { PSTANDALONE_COMP Standalone; BOOL OldState,NewState; LPCTSTR Key; INFCONTEXT Context; LPCTSTR CmdLine; TCHAR CurDir[MAX_PATH]; BOOL b; LPCTSTR Description; TCHAR Text[150]; TCHAR Text2[350]; TCHAR *p; DWORD ExitCode; DWORD d; DWORD dSetupMode;
//
// Find the component.
//
for(Standalone=StandaloneComponents; Standalone; Standalone=Standalone->Next) { if(!lstrcmpi(ComponentId,Standalone->ComponentId)) { break; } }
if(!Standalone) { d = NO_ERROR; goto c0; }
//
// Determine whether this component wants to be invoked pre or post-queue.
// If this doesn't match the notification we're processing then bail.
//
b = FALSE; if(SetupFindFirstLine(Standalone->Inf,ComponentId,TEXT("InvokeBeforeQueueCommit"),&Context) && SetupGetIntField(&Context,1,&d)) { b = (d != 0); } if((b == FALSE) != (PreQueueCommit == FALSE)) { d = NO_ERROR; goto c0; }
OldState = Standalone->HelperRoutines.QuerySelectionState( Standalone->HelperRoutines.OcManagerContext, ComponentId, OCSELSTATETYPE_ORIGINAL );
NewState = Standalone->HelperRoutines.QuerySelectionState( Standalone->HelperRoutines.OcManagerContext, ComponentId, OCSELSTATETYPE_CURRENT );
dSetupMode = Standalone->HelperRoutines.GetSetupMode( Standalone->HelperRoutines.OcManagerContext);
// Qualify this setup mode and see if we do anything
// if no change in state
// SETUPMODE_UPGRADE
// SETUPMODE_UPGRADEONLY
// SETUPMODE_ADDEXTRACOMPS
//
// SETUPMODE_MAINTANENCE
// SETUPMODE_ADDREMOVE
// SETUPMODE_REINSTALL
// SETUPMODE_REMOVEALL
// SETUPMODE_FRESH
d = NO_ERROR;
if ( NewState == OldState ) {
// no change in slected state What we do depends on the secondary setup modes
// if Setupmode is AddRemove or Removeall then Skip this
if ( NewState == 0) { goto c0; // do nothing
}
// Mask off Public mode bits
//
dSetupMode &= SETUPMODE_PRIVATE_MASK; if ( dSetupMode == SETUPMODE_ADDREMOVE || dSetupMode == SETUPMODE_REMOVEALL ) { goto c0; // do nothing
} // What remains here is NewState=1
// and Reinstall and Upgrade
}
Description = NULL; if(SetupFindFirstLine(Standalone->Inf,ComponentId,TEXT("OptionDesc"),&Context)) { Description = pSetupGetField(&Context,1); } if(Description) {
LoadString( MyModuleHandle, OldState ? (NewState ? IDS_EXTERNAL_UPGRADE : IDS_EXTERNAL_UNINST) : (NewState ? IDS_EXTERNAL_INST : IDS_EXTERNAL_EXAMINE), Text, sizeof(Text)/sizeof(TCHAR) );
wsprintf(Text2,Text,Description);
Standalone->HelperRoutines.SetProgressText( Standalone->HelperRoutines.OcManagerContext, Text2 ); } else { Standalone->HelperRoutines.SetProgressText( Standalone->HelperRoutines.OcManagerContext, TEXT("") ); }
if(OldState == NewState) { Key = OldState ? TEXT("InstalledCmd") : TEXT("UninstalledCmd"); } else { Key = OldState ? TEXT("UninstallCmd") : TEXT("InstallCmd"); }
d = NO_ERROR;
if(!SetupFindFirstLine(Standalone->Inf,ComponentId,Key,&Context)) goto c0;
// The current Directory to the Suite's Inf Path, with Initial installs "-N" option
// this may on the CD, with Mainatiance mode it will be the %systemroot%\system32\setup
SetSuiteCurrentDir(Standalone);
do { if (!(CmdLine = pSetupGetField(&Context,1))) break; d = RunStandaloneCmd(Standalone, Description, CmdLine); if (d != NO_ERROR) break; } while (SetupFindNextMatchLine(&Context,Key,&Context));
c0: Standalone->HelperRoutines.TickGauge( Standalone->HelperRoutines.OcManagerContext );
return d; }
DWORD WaitOnApp( IN HANDLE Process, OUT PDWORD ExitCode ) { DWORD dw; BOOL Done; MSG msg;
//
// Process any messages that may already be in the queue.
//
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { DispatchMessage(&msg); }
//
// Wait for process to terminate or more messages in the queue.
//
Done = FALSE; do { switch(MsgWaitForMultipleObjects(1,&Process,FALSE,INFINITE,QS_ALLINPUT)) {
case WAIT_OBJECT_0: //
// Process has terminated.
//
dw = GetExitCodeProcess(Process,ExitCode) ? NO_ERROR : GetLastError(); Done = TRUE; break;
case WAIT_OBJECT_0+1: //
// Messages in the queue.
//
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { DispatchMessage(&msg); } break;
default: //
// Error.
//
dw = GetLastError(); Done = TRUE; break; } } while(!Done);
return(dw); }
|