Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1740 lines
42 KiB

//=--------------------------------------------------------------------------=
// inseng.cpp
//=--------------------------------------------------------------------------=
// Copyright 1995-1996 Microsoft Corporation. All Rights Reserved.
//
//
#include "inspch.h"
#include "regstr.h"
#include "globals.h"
#include "insobj.h"
#include "resource.h"
#include "diskspac.h"
#define GRPCONV "grpconv -o"
#define BUFFERSIZE 4096
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
CInstallEngine::CInstallEngine(IUnknown **punk)
{
DWORD dwThreadID;
HANDLE hThread;
HKEY hKey = NULL;
char szBuf[16];
DWORD dwType;
GetWindowsDirectory(g_szWindowsDir, sizeof(g_szWindowsDir));
if(g_szWindowsDir[0] >= 'a' && g_szWindowsDir[0] <= 'z')
g_szWindowsDir[0] -= 32;
hThread = CreateThread(NULL, 0, CleanUpAllDirs, NULL, 0, &dwThreadID);
CloseHandle(hThread);
_chInsDrive = g_szWindowsDir[0];
// Decide whether we are in stepping mode or not
_uCommandMode = 0;
_fSteppingMode = FALSE;
_fResetTrust = TRUE;
_fIgnoreTrust = FALSE;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, ACTIVESETUP_KEY,0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
// Get Steeping mode value. OK if not present
DWORD dwSize = sizeof(szBuf);
if(RegQueryValueEx(hKey, STEPPING_VALUE, NULL, &dwType, (LPBYTE) szBuf, &dwSize) == ERROR_SUCCESS)
{
if(szBuf[0] == 'y' || szBuf[0] == 'Y')
_fSteppingMode = TRUE;
}
// Get CommandMode value. OK if not present
dwSize = sizeof(szBuf);
if(RegQueryValueEx(hKey, COMMAND_VALUE, NULL, &dwType, (LPBYTE) szBuf, &dwSize) == ERROR_SUCCESS)
{
_uCommandMode = AtoL(szBuf);
// Once we read it, set it to zero
// BUGBUG: beware of hardcoded "0" and 2 below (2 includes null terminator)
RegSetValueEx(hKey, COMMAND_VALUE, 0, REG_SZ, (BYTE *) "0", 2 );
}
if(RegQueryValueEx(hKey, CHECKTRUST_VALUE, NULL, &dwType, (LPBYTE) szBuf, &dwSize) == ERROR_SUCCESS)
{
if(szBuf[0] == 'Y' || szBuf[0] == 'y')
{
_fIgnoreTrust = TRUE;
_fResetTrust = FALSE;
}
// Once we read it, set it to zero
// BUGBUG: beware of hardcoded "0" and 2 below (2 includes null terminator)
RegDeleteValue(hKey, CHECKTRUST_VALUE);
}
RegCloseKey(hKey);
}
_hwndForUI = NULL;
_pStmLog = NULL;
_fIgnoreDownloadError = FALSE;
_enginestatus = ENGINESTATUS_NOTREADY;
_dwStatus = 0;
_pcb = NULL;
_cRef = 0;
_dwDLRemaining = 0;
_dwInstallRemaining = 0;
_dwInstallOld = 0;
_dwDLOld = 0;
_fUseCache = FALSE;
_dwInstallOptions = INSTALLOPTIONS_DOWNLOAD | INSTALLOPTIONS_INSTALL;
_hContinue = NULL;
_hAbort = NULL;
_fCleanUpDir = FALSE;
//init CCifFile
_pCif = new CCifFile();
_pCif->AddRef();
_pCif->SetInstallEngine(this);
// init downloader
_pDL = new CDownloader();
_pIns = new CInstaller(this);
_szBaseUrl[0] = 0;
_fSRLiteAvailable = IsPatchableIEVersion() && IsCorrectAdvpExt() && InitSRLiteLibs();
if (!_fSRLiteAvailable)
WriteToLog("Install engine failed to initialize the advpack extension DLL\r\n", FALSE);
_pPDL = new CPatchDownloader(_fSRLiteAvailable);
AddRef();
*punk = (IInstallEngine *) this;
}
//=--------------------------------------------------------------------------=
// CInstallEngine::~CInstallEngine
//=--------------------------------------------------------------------------=
// Destructor for InstallEngine class
//
// Parameters:
//
// Returns:
//
// Notes:
//
CInstallEngine::~CInstallEngine()
{
char szBuf[MAX_PATH];
WriteToLog("Install Engine - object destroyed\r\n", TRUE);
if(_fCleanUpDir)
{
lstrcpy(szBuf, _pCif->GetDownloadDir());
}
if(_hAbort)
CloseHandle(_hAbort);
if(_hContinue)
CloseHandle(_hContinue);
if(_pStmLog)
_pStmLog->Release();
_pcb = NULL;
_pCif->Release();
_pDL->Release();
delete _pPDL;
_pIns->Release();
if(_fCleanUpDir)
{
CleanUpTempDir(szBuf);
}
FreeSRLiteLibs();
DllRelease();
}
//************ IUnknown implementation ***************
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP_(ULONG) CInstallEngine::AddRef()
{
return(_cRef++);
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP_(ULONG) CInstallEngine::Release()
{
ULONG temp = --_cRef;
if(temp == 0)
delete this;
return temp;
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::QueryInterface(REFIID riid, void **ppv)
{
*ppv = NULL;
if((riid == IID_IUnknown) || (riid == IID_IInstallEngine))
*ppv = (IInstallEngine *)this;
else if(riid == IID_IInstallEngineTiming)
*ppv = (IInstallEngineTiming *)this;
else if(riid == IID_IInstallEngine2)
*ppv = (IInstallEngine2 *)this;
if(*ppv == NULL)
return E_NOINTERFACE;
AddRef();
return NOERROR;
}
//************* IInstallEngine interface ************
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::SetLocalCif(LPCSTR pszCifPath)
{
HCURSOR hNew = NULL;
HCURSOR hOld = NULL;
OnEngineStatusChange(ENGINESTATUS_LOADING, 0);
hNew = LoadCursor(NULL, IDC_WAIT);
hOld = SetCursor(hNew);
HRESULT hr = _pCif->SetCifFile(pszCifPath, FALSE);
if(SUCCEEDED(hr))
OnEngineStatusChange(ENGINESTATUS_READY, 0);
else
OnEngineStatusChange(ENGINESTATUS_NOTREADY, hr);
SetCursor(hOld);
return hr;
}
STDMETHODIMP CInstallEngine::GetICifFile(ICifFile **pic)
{
*pic = (ICifFile *) _pCif;
(*pic)->AddRef();
return NOERROR;
}
STDMETHODIMP CInstallEngine::GetEngineStatus(DWORD * theenginestatus)
{
*theenginestatus = _enginestatus;
return(NOERROR);
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::Abort(DWORD lFlag)
{
// If we are NOT downLOADING or INSTALLING, an abort command makes no sense.
if( !(_enginestatus == ENGINESTATUS_INSTALLING || _enginestatus == ENGINESTATUS_LOADING) )
return E_UNEXPECTED;
// if we are downloading, this will cause the abort to filter thru
_pDL->Abort();
// this will abort an install if possible
_pIns->Abort();
// any other time, we will pick this up just as soon as we can
SetEvent(_hAbort);
WriteToLog("Install Engine - Abort called\r\n", FALSE);
return(NOERROR);
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::Suspend()
{
HRESULT hr;
if(_enginestatus != ENGINESTATUS_INSTALLING)
return E_UNEXPECTED;
WriteToLog("Install Engine - Suspend called\r\n", FALSE);
_pDL->Suspend();
// we only catch suspend return, because it tells us "zsafe to cancel or not"
hr = _pIns->Suspend();
ResetEvent(_hContinue);
// If we cant create the resume event, we will fail this call and not pause
return hr;
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::Resume()
{
if(_enginestatus != ENGINESTATUS_INSTALLING)
return E_UNEXPECTED;
WriteToLog("Install Engine - Resume called\r\n", FALSE);
_pDL->Resume();
_pIns->Resume();
SetEvent(_hContinue);
return NOERROR;
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::SetCifFile(LPCSTR pszCabName, LPCSTR pszCifName)
{
HRESULT hr = NOERROR;
HANDLE hThread;
DWORD dwThreadID;
if(_enginestatus == ENGINESTATUS_LOADING || _enginestatus == ENGINESTATUS_INSTALLING)
return E_UNEXPECTED;
SETCIFARGS *p = new SETCIFARGS;
if (p == NULL)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
if(_szBaseUrl[0] != 0)
{
if (lstrlen(_szBaseUrl) + lstrlen(pszCabName) + 2 > INTERNET_MAX_URL_LENGTH)
{
hr = E_INVALIDARG;
goto Cleanup;
}
p->szUrl[0] = '\0';
lstrcpy(p->szUrl, _szBaseUrl);
lstrcat(p->szUrl, "/");
lstrcat(p->szUrl, pszCabName);
}
else
{
lstrcpy(p->szUrl, "file://");
lstrcat(p->szUrl, _pCif->GetDownloadDir());
SafeAddPath(p->szUrl, pszCabName, sizeof(p->szUrl));
}
lstrcpyn(p->szCif, pszCifName, MAX_PATH);
p->pCif = _pCif;
// do the actual downloading of the CIF file in a separate thread
if ((hThread = CreateThread(NULL, 0, DownloadCifFile, (LPVOID) p, 0, &dwThreadID)) != NULL)
CloseHandle(hThread);
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
Cleanup:
if (FAILED(hr) && p != NULL)
delete p;
return hr;
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::SetBaseUrl(LPCSTR pszBaseName)
{
DWORD dwLen;
if(_enginestatus == ENGINESTATUS_INSTALLING)
if(!_IsValidBaseUrl(pszBaseName))
return E_UNEXPECTED;
lstrcpyn(_szBaseUrl, pszBaseName, INTERNET_MAX_URL_LENGTH);
wsprintf(szLogBuf,"Install Engine - base url set to %s\r\n", pszBaseName);
WriteToLog(szLogBuf, FALSE);
return NOERROR;
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::SetDownloadDir(LPCSTR pszDLDir)
{
char szBuf[MAX_PATH];
DWORD dwLen;
DWORD dwVer;
if(_enginestatus == ENGINESTATUS_INSTALLING)
return E_UNEXPECTED;
if(pszDLDir != NULL && lstrlen(pszDLDir) > (MAX_PATH - 20))
return E_FAIL;
// clean up what we have
if(_fCleanUpDir)
{
DelNode(_pCif->GetDownloadDir(), 0);
_fCleanUpDir = FALSE;
}
if(pszDLDir == NULL)
{
_fCleanUpDir = TRUE;
if(FAILED(CreateTempDirOnMaxDrive(szBuf, sizeof(szBuf))))
return E_FAIL;
}
else
{
_fCleanUpDir = FALSE;
// Make sure the directory exists
if(GetFileAttributes(pszDLDir) == 0xffffffff)
CreateDirectory(pszDLDir, NULL);
}
_pCif->SetDownloadDir(pszDLDir ? pszDLDir : szBuf);
wsprintf(szLogBuf,"Install Engine - download directory set to %s\r\n", _pCif->GetDownloadDir());
WriteToLog(szLogBuf, FALSE);
return NOERROR;
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::IsComponentInstalled(LPCSTR pszComponentID, DWORD *lResult)
{
DWORD dwResult = ICI_NOTINSTALLED;
ICifComponent *pComp = NULL;
if(SUCCEEDED(_pCif->FindComponent(pszComponentID, &pComp)))
{
dwResult = pComp->IsComponentInstalled();
}
*lResult = dwResult;
return(pComp ? NOERROR : E_INVALIDARG);
}
STDMETHODIMP CInstallEngine::SetInstallDrive(CHAR chDrive)
{
HRESULT hr = E_INVALIDARG;
if(chDrive >= 'a' && chDrive <= 'z')
chDrive -= 32;
if(chDrive >= 'A' && chDrive <= 'Z')
{
hr = NOERROR;
_chInsDrive = chDrive;
}
return hr;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::SetInstallOptions(DWORD dwOptions)
{
_fUseCache = !(dwOptions & INSTALLOPTIONS_NOCACHE);
_dwInstallOptions = dwOptions;
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::GetInstallOptions(DWORD *pdwOptions)
{
if (!pdwOptions)
return E_POINTER;
else
{
*pdwOptions = _dwInstallOptions;
return NOERROR;
}
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::GetSizes(LPCSTR pszID, COMPONENT_SIZES *p)
{
if(!p)
return E_POINTER;
// work around bug in old versions of jobexec where it didn't init
// this field properly
if(p->cbSize > sizeof(COMPONENT_SIZES))
p->cbSize = COMPONENTSIZES_SIZE_V1;
DWORD dwSize = p->cbSize;
ZeroMemory(p, p->cbSize);
p->cbSize = dwSize;
if(_enginestatus != ENGINESTATUS_READY)
return E_UNEXPECTED;
if(pszID != NULL)
{
ICifComponent *pComp = NULL;
if(SUCCEEDED(_pCif->FindComponent(pszID, &pComp)))
{
DWORD dwWin, dwApp;
p->dwDownloadSize = pComp->GetDownloadSize();
pComp->GetInstalledSize(&dwWin, &dwApp);
p->dwInstallSize = dwApp;
p->dwWinDriveSize = dwWin;
}
else
return E_INVALIDARG;
}
else
_GetTotalSizes(p);
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
void CInstallEngine::_GetTotalSizes(COMPONENT_SIZES *pSizes)
{
ICifComponent *pComp;
DriveInfo drvinfo[3];
LPSTR pszDep = NULL;
UINT uTempDrive;
UINT uWinDrive = 0;
UINT uInstallDrive = 1;
UINT uDownloadDrive = 2;
LPCSTR pszDownloadDir = _pCif->GetDownloadDir();
COMPONENT_SIZES Sizes;
ZeroMemory(&Sizes, sizeof(COMPONENT_SIZES));
// Fill in all arrays to start
drvinfo[uWinDrive].InitDrive(g_szWindowsDir[0]);
if(_dwInstallOptions & INSTALLOPTIONS_INSTALL)
{
// We know we can do a compare because these are always uppcase
if(_chInsDrive != drvinfo[uWinDrive].Drive())
{
drvinfo[uInstallDrive].InitDrive(_chInsDrive);
}
else
uInstallDrive = uWinDrive;
}
if(_dwInstallOptions & INSTALLOPTIONS_DOWNLOAD)
{
if(pszDownloadDir[0] == drvinfo[uWinDrive].Drive())
uDownloadDrive = uWinDrive;
else if(pszDownloadDir[0] == drvinfo[uInstallDrive].Drive())
uDownloadDrive = uInstallDrive;
else
drvinfo[uDownloadDrive].InitDrive(pszDownloadDir[0]);
}
// do space for download phase (easy part)
if(_dwInstallOptions & INSTALLOPTIONS_DOWNLOAD)
{
Sizes.dwDownloadSize = _GetActualDownloadSize(FALSE);
Sizes.dwTotalDownloadSize = _GetTotalDownloadSize();
Sizes.dwDependancySize = 0;
// add download to download drive
drvinfo[uDownloadDrive].UseSpace(Sizes.dwDownloadSize + Sizes.dwDependancySize, TRUE);
// if going to cache
// BUGBUG: we still assume cache is on windows drive
if(_fUseCache)
{
drvinfo[uWinDrive].UseSpace(Sizes.dwDownloadSize + Sizes.dwDependancySize, TRUE);
}
}
// do space for install (hard part)
if(_dwInstallOptions & INSTALLOPTIONS_INSTALL)
{
// walk the install list in order (very important)
// do any dependancy, then original
IEnumCifComponents *penum;
ICifComponent *pComp = NULL;
_pCif->EnumComponents(&penum, 0, NULL);
for(penum->Next(&pComp); pComp; penum->Next(&pComp))
{
if(pComp->GetInstallQueueState() == SETACTION_INSTALL)
{
DWORD dwWin, dwApp;
pComp->GetInstalledSize(&dwWin, &dwApp);
// add install
// add the install size
Sizes.dwInstallSize += dwApp;
// size that goes to windows dir
Sizes.dwWinDriveSize += dwWin;
drvinfo[uInstallDrive].UseSpace(dwApp, FALSE);
drvinfo[uWinDrive].UseSpace(dwWin, FALSE);
// Add (and then remove) temp space
AddTempSpace(pComp->GetDownloadSize(), pComp->GetExtractSize(), drvinfo);
}
}
penum->Release();
}
// fill in the required amounts
Sizes.dwWinDriveReq = drvinfo[uWinDrive].MaxUsed();
Sizes.chWinDrive = drvinfo[uWinDrive].Drive();
if(uWinDrive != uInstallDrive)
{
Sizes.dwInstallDriveReq = drvinfo[uInstallDrive].MaxUsed();
Sizes.chInstallDrive = drvinfo[uInstallDrive].Drive();
}
if((uDownloadDrive != uWinDrive) && (uDownloadDrive != uInstallDrive))
{
Sizes.dwDownloadDriveReq = drvinfo[uDownloadDrive].MaxUsed();
Sizes.chDownloadDrive = drvinfo[uDownloadDrive].Drive();
}
CopyMemory((LPVOID)(&(pSizes->dwInstallSize)), (LPVOID)(&(Sizes.dwInstallSize)),
pSizes->cbSize - sizeof(DWORD));
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::SetAction(LPCSTR pszComponentID, DWORD action, DWORD dwPriority)
{
HRESULT hr = NOERROR;
if(_enginestatus != ENGINESTATUS_READY)
return E_UNEXPECTED;
ICifComponent *pComp = NULL;
if(pszComponentID == NULL || lstrlen(pszComponentID) == 0)
{
_pCif->ClearQueueState();
}
else
{
if(SUCCEEDED(_pCif->FindComponent(pszComponentID, &pComp)))
{
if(dwPriority != 0xffffffff)
pComp->SetCurrentPriority(dwPriority);
hr = pComp->SetInstallQueueState(action);
}
else
hr = E_INVALIDARG;
}
return hr;
}
// the following two are now ridiculously inefficient. New clients should use the enumerators
STDMETHODIMP CInstallEngine::EnumInstallIDs(UINT uIndex, LPSTR *ppszID)
{
HRESULT hr;
UINT i = 0;
*ppszID = NULL;
IEnumCifComponents *penum;
ICifComponent *pComp;
_pCif->EnumComponents(&penum, 0, NULL);
for(penum->Next(&pComp); pComp; penum->Next(&pComp))
{
if(pComp->GetInstallQueueState())
{
if(uIndex == i)
break;
i++;
}
}
penum->Release();
if(pComp)
{
char szID[MAX_ID_LENGTH];
pComp->GetID(szID, sizeof(szID));
*ppszID = COPYANSISTR(szID);
hr = NOERROR;
}
else
hr = E_FAIL;
return hr;
}
STDMETHODIMP CInstallEngine::EnumDownloadIDs(UINT uIndex, LPSTR *ppszID)
{
HRESULT hr;
UINT i = 0;
*ppszID = NULL;
IEnumCifComponents *penum;
ICifComponent *pComp;
_pCif->EnumComponents(&penum, 0, NULL);
for(penum->Next(&pComp); pComp; penum->Next(&pComp))
{
if(pComp->GetInstallQueueState() && (pComp->IsComponentDownloaded() == S_FALSE))
{
if(uIndex == i)
break;
i++;
}
}
penum->Release();
if(pComp)
{
char szID[MAX_ID_LENGTH];
pComp->GetID(szID, sizeof(szID));
*ppszID = COPYANSISTR(szID);
hr = NOERROR;
}
else
hr = E_FAIL;
return hr;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::DownloadComponents(DWORD lFlags)
{
DWORD dwThreadID;
HRESULT hr = NOERROR;
WriteToLog("Install Engine - Starting download phase\r\n", TRUE);
if(_enginestatus == ENGINESTATUS_NOTREADY || _enginestatus == ENGINESTATUS_LOADING)
hr = E_UNEXPECTED;
// BUGBUG - add a downloading status? it really just a "busy" indication
if(_enginestatus == ENGINESTATUS_INSTALLING)
hr = E_PENDING;
if(SUCCEEDED(hr))
{
OnEngineStatusChange(ENGINESTATUS_INSTALLING, 0);
// since trust may be set globally, only turn it on, not off
if(EXECUTEJOB_IGNORETRUST & lFlags)
_fIgnoreTrust = TRUE;
if(EXECUTEJOB_IGNOREDOWNLOADERROR & lFlags)
_fIgnoreDownloadError = TRUE;
else
_fIgnoreDownloadError = FALSE;
HANDLE h = CreateThread(NULL, 0, InitDownloader, this, 0, &dwThreadID);
if(h == NULL)
{
// Won't be doing any downloading today.....
hr = E_FAIL;
}
else
CloseHandle(h);
}
return hr;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::InstallComponents(DWORD lFlags)
{
DWORD dwThreadID;
HRESULT hr = NOERROR;
WriteToLog("Install Engine - Starting install phase\r\n", TRUE);
EnterCriticalSection(&g_cs);
if(_enginestatus == ENGINESTATUS_NOTREADY || _enginestatus == ENGINESTATUS_LOADING)
hr = E_UNEXPECTED;
if(_enginestatus == ENGINESTATUS_INSTALLING)
hr = E_PENDING;
LeaveCriticalSection(&g_cs);
if(SUCCEEDED(hr))
{
// We first check to see if all files are present
// by seeing if we would download anything!!!
//
if(EXECUTEJOB_VERIFYFILES & lFlags)
{
WriteToLog("Checking for missing files\r\n", FALSE);
if(_GetActualDownloadSize(TRUE) != 0)
return E_FILESMISSING;
}
OnEngineStatusChange(ENGINESTATUS_INSTALLING, 0);
// since trust may be set globally, only turn it on, not off
if(EXECUTEJOB_IGNORETRUST & lFlags)
_fIgnoreTrust = TRUE;
HANDLE h = CreateThread(NULL, 0, InitInstaller, this, 0, &dwThreadID);
if(h == NULL)
{
// Won't be doing any installing today.....
hr = E_FAIL;
}
else
CloseHandle(h);
}
return hr;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
DWORD WINAPI InitInstaller(LPVOID pv)
{
CInstallEngine *pInsEng = (CInstallEngine *) pv;
HRESULT hr = S_OK;
BOOL fOneInstalled = FALSE;
ICifComponent *pComp;
EnableSage(FALSE);
EnableScreenSaver(FALSE);
EnableDiskCleaner(FALSE);
pInsEng->_dwStatus = 0;
pInsEng->_hAbort = CreateEvent(NULL, FALSE, FALSE, NULL);
pInsEng->_hContinue = CreateEvent(NULL, TRUE, TRUE, NULL);
//BUGBUG check for failure
pInsEng->AddRef();
pInsEng->OnStartInstall(0, pInsEng->_GetTotalInstallSize());
// check trust the Cif cab if it has not been done so
hr = pInsEng->CheckForContinue();
// this is the install pass
if(SUCCEEDED(hr))
hr = pInsEng->_pCif->Install(&fOneInstalled);
if(fOneInstalled && FNeedGrpConv())
{
if(!(pInsEng->GetStatus() & STOPINSTALL_REBOOTNEEDED))
{
// if we dont need a reboot launch grpconv immeadiatly
HANDLE h = NULL;
pInsEng->WriteToLog("Install Engine - No reboot required\r\n", FALSE);
LaunchAndWait(GRPCONV, NULL, &h, NULL, SW_SHOWMINIMIZED);
if(h)
CloseHandle(h);
}
else
{
HKEY hKey;
DWORD dumb;
// otherwise put grpconv into runonce
if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE,
0,0,0, KEY_SET_VALUE, NULL, &hKey, &dumb) == ERROR_SUCCESS)
{
RegSetValueEx(hKey, "GrpConv", 0, REG_SZ,
(BYTE *) GRPCONV, sizeof(GRPCONV));
RegCloseKey(hKey);
}
}
}
// reset to checking trust
if(pInsEng->_fResetTrust)
pInsEng->_fIgnoreTrust = FALSE;
// Send a install all done message
if(!(pInsEng->GetStatus() & STOPINSTALL_REBOOTNEEDED))
{
// If we don't need a reboot, enable the screen saver and sage.
EnableScreenSaver(TRUE);
EnableSage(TRUE);
}
EnableDiskCleaner(TRUE);
CloseHandle(pInsEng->_hAbort);
pInsEng->_hAbort = NULL;
CloseHandle(pInsEng->_hContinue);
pInsEng->_hContinue = NULL;
pInsEng->OnStopInstall(hr, NULL, pInsEng->GetStatus());
pInsEng->OnEngineStatusChange(ENGINESTATUS_READY, 0);
pInsEng->Release();
return 0;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
DWORD WINAPI InitDownloader(LPVOID pv)
{
CInstallEngine *pInsEng = (CInstallEngine *) pv;
HRESULT hr = S_OK;
EnableSage(FALSE);
EnableScreenSaver(FALSE);
EnableDiskCleaner(FALSE);
pInsEng->_hAbort = CreateEvent(NULL, FALSE, FALSE, NULL);
pInsEng->_hContinue = CreateEvent(NULL, TRUE, TRUE, NULL);
//BUGBUG check for failure
pInsEng->AddRef();
pInsEng->OnStartInstall(pInsEng->_GetActualDownloadSize(FALSE), 0);
// check trust the Cif cab if it has not been done so
hr = pInsEng->CheckForContinue();
// this is the download pass
if(SUCCEEDED(hr))
{
hr = pInsEng->_pCif->Download();
}
if(SUCCEEDED(hr))
{
pInsEng->WriteToLog("Install Engine - Download complete\r\n", FALSE);
}
// reset to checking trust
if(pInsEng->_fResetTrust)
pInsEng->_fIgnoreTrust = FALSE;
CloseHandle(pInsEng->_hAbort);
pInsEng->_hAbort = NULL;
CloseHandle(pInsEng->_hContinue);
pInsEng->_hContinue = NULL;
EnableScreenSaver(TRUE);
EnableSage(TRUE);
EnableDiskCleaner(TRUE);
// Send a install all done message
EnterCriticalSection(&g_cs);
pInsEng->OnStopInstall(hr, NULL, 0);
pInsEng->OnEngineStatusChange(ENGINESTATUS_READY, 0);
LeaveCriticalSection(&g_cs);
pInsEng->Release();
return 0;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
DWORD CInstallEngine::_GetTotalDownloadSize()
{
DWORD dwTotalSize = 0;
IEnumCifComponents *penum;
ICifComponent *pComp = NULL;
_pCif->EnumComponents(&penum, 0, NULL);
for(penum->Next(&pComp); pComp; penum->Next(&pComp))
{
if(pComp->GetInstallQueueState() == SETACTION_INSTALL)
dwTotalSize += pComp->GetDownloadSize();
}
penum->Release();
return dwTotalSize;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
DWORD CInstallEngine::_GetActualDownloadSize(BOOL bLogMissing)
{
DWORD dwTotalSize = 0;
IEnumCifComponents *penum;
ICifComponent *pComp = NULL;
_pCif->EnumComponents(&penum, 0, NULL);
for( penum->Next(&pComp); pComp; penum->Next(&pComp))
{
if(pComp->GetInstallQueueState() == SETACTION_INSTALL)
dwTotalSize += pComp->GetActualDownloadSize();
}
penum->Release();
return dwTotalSize;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
DWORD CInstallEngine::_GetTotalInstallSize()
{
DWORD dwTotalSize = 0;
DWORD dwWin, dwApp;
IEnumCifComponents *penum;
ICifComponent *pComp = NULL;
_pCif->EnumComponents(&penum, 0, NULL);
for(penum->Next(&pComp); pComp; penum->Next(&pComp))
{
if(pComp->GetInstallQueueState() == SETACTION_INSTALL)
{
pComp->GetInstalledSize(&dwWin, &dwApp);
dwTotalSize += (dwWin + dwApp);
}
}
penum->Release();
return dwTotalSize;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::LaunchExtraCommand(LPCSTR pszInfName, LPCSTR pszSection)
{
return E_NOTIMPL;
}
//=---------------------------------------------------------------------------=
// RegisterInstallEngineCallback
//=---------------------------------------------------------------------------=
// Register the callback interface
//
// Parameters:
// IInstallEngineCallback * - the callback interface
// HWND - For ui
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::RegisterInstallEngineCallback(IInstallEngineCallback *pcb)
{
_pcb = pcb;
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::UnregisterInstallEngineCallback()
{
_pcb = NULL;
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::SetHWND(HWND h)
{
_hwndForUI = h;
return NOERROR;
}
//*********** IInstallEngineCallback implementation ************
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::OnEngineStatusChange(DWORD status,DWORD substatus)
{
_enginestatus = status;
if(_pcb)
_pcb->OnEngineStatusChange(_enginestatus, substatus);
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::OnStartInstall(DWORD dwDLSize, DWORD dwInstallSize)
{
_dwDLRemaining = dwDLSize;
_dwInstallRemaining = dwInstallSize;
wsprintf(szLogBuf, "\r\nOnStartInstall:\r\n Download: %d KB\r\n Install %d KB\r\n", dwDLSize, dwInstallSize);
WriteToLog(szLogBuf, TRUE);
if(_pcb)
_pcb->OnStartInstall(dwDLSize, dwInstallSize);
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::OnStartComponent(LPCSTR pszID, DWORD dwDLSize,
DWORD dwInstallSize, LPCSTR pszString)
{
wsprintf(szLogBuf, "OnStartComponent:\r\n ID: %s\r\n Download: %d KB\r\n Install %d KB\r\n",
pszID, dwDLSize, dwInstallSize);
WriteToLog(szLogBuf, TRUE);
_dwDLOld = 0;
_dwInstallOld = 0;
if(_pcb)
_pcb->OnStartComponent(pszID, dwDLSize, dwInstallSize, pszString);
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::OnEngineProblem(DWORD dwProblem, LPDWORD pdwAction)
{
HRESULT hr = S_FALSE;
if(_pcb)
hr = _pcb->OnEngineProblem(dwProblem, pdwAction);
return hr;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::OnComponentProgress(LPCSTR pszID, DWORD dwPhase,
LPCSTR pszString, LPCSTR pszMsgString, ULONG prog, ULONG max)
{
DWORD dwNew;
if(dwPhase == INSTALLSTATUS_DOWNLOADING)
{
_dwDLOld = prog;
}
else if(dwPhase == INSTALLSTATUS_RUNNING)
{
_dwInstallOld = prog;
}
if(_pcb)
_pcb->OnComponentProgress(pszID, dwPhase, pszString, pszMsgString, prog, max);
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::OnStopComponent(LPCSTR pszID, HRESULT hError,
DWORD dwPhase, LPCSTR pszString, DWORD dwStatus)
{
// adjust remaining
if(_dwDLRemaining > _dwDLOld)
_dwDLRemaining -= _dwDLOld;
else
_dwDLRemaining = 0;
// adjust remaining
if(_dwInstallRemaining > _dwInstallOld)
_dwInstallRemaining -= _dwInstallOld;
else
_dwInstallRemaining = 0;
wsprintf(szLogBuf, "Timing rates: Download: %d, Install %d\r\n",
_pDL->GetBytesPerSecond(), _pIns->GetBytesPerSecond());
WriteToLog(szLogBuf, TRUE);
wsprintf(szLogBuf, "OnStopComponent:\r\n ID: %s\r\n HRESULT: %x (%s)\r\n Phase: %d\r\n Status: %d\r\n",
pszID, hError, SUCCEEDED(hError) ? STR_OK : STR_FAILED, dwPhase, dwStatus);
WriteToLog(szLogBuf, TRUE);
if(_pcb)
_pcb->OnStopComponent(pszID, hError, dwPhase, pszString, dwStatus);
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::OnStopInstall(HRESULT hrError, LPCSTR szError,
DWORD dwStatus)
{
_dwDLRemaining = 0;
_dwInstallRemaining = 0;
wsprintf(szLogBuf, "\r\nOnStopInstall:\r\n HRESULT: %x (%s)\r\n Status: %d\r\n",
hrError, SUCCEEDED(hrError) ? STR_OK : STR_FAILED, dwStatus);
WriteToLog(szLogBuf, TRUE);
if(_pcb)
_pcb->OnStopInstall(hrError, szError, dwStatus);
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::SetIStream(IStream *pstm)
{
if(_pStmLog)
_pStmLog->Release();
_pStmLog = pstm;
if(_pStmLog)
_pStmLog->AddRef();
return NOERROR;
}
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::GetDisplayName(LPCSTR pszComponentID, LPSTR *ppszName)
{
HRESULT hr = E_INVALIDARG;
char szTitle[MAX_DISPLAYNAME_LENGTH];
if(!ppszName)
return E_POINTER;
*ppszName = 0;
ICifComponent *pComp = NULL;
if(pszComponentID)
{
if(SUCCEEDED(_pCif->FindComponent(pszComponentID, &pComp)))
{
pComp->GetDescription(szTitle, sizeof(szTitle));
*ppszName = COPYANSISTR(szTitle);
if(!(*ppszName))
hr = E_OUTOFMEMORY;
else
hr = NOERROR;
}
}
else
{
_pCif->GetDescription(szTitle, sizeof(szTitle));
*ppszName = COPYANSISTR(szTitle);
if(!(*ppszName))
hr = E_OUTOFMEMORY;
else
hr = NOERROR;
}
return hr;
}
//************** IInstallEngineTiming **********************
//=---------------------------------------------------------------------------=
// Function name here
//=---------------------------------------------------------------------------=
// Function description
//
// Parameters
//
// Returns:
//
// Notes:
//
STDMETHODIMP CInstallEngine::GetRates(DWORD *pdwDownload, DWORD *pdwInstall)
{
*pdwDownload = _pDL->GetBytesPerSecond();
*pdwInstall = _pIns->GetBytesPerSecond();
return NOERROR;
}
STDMETHODIMP CInstallEngine::GetInstallProgress(INSTALLPROGRESS *pinsprog)
{
if(!pinsprog)
return E_POINTER;
DWORD dwTemp;
pinsprog->dwDownloadKBRemaining = _dwDLRemaining - _dwDLOld;
pinsprog->dwInstallKBRemaining = _dwInstallRemaining - _dwInstallOld;
dwTemp = _pDL->GetBytesPerSecond();
if(dwTemp == 0)
pinsprog->dwDownloadSecsRemaining = 0xffffffff;
else
pinsprog->dwDownloadSecsRemaining = (pinsprog->dwDownloadKBRemaining << 10)/dwTemp;
dwTemp = _pIns->GetBytesPerSecond();
if(dwTemp == 0)
pinsprog->dwInstallSecsRemaining = 0xffffffff;
else
pinsprog->dwInstallSecsRemaining = (pinsprog->dwInstallKBRemaining << 10)/dwTemp;
return NOERROR;
}
HRESULT CInstallEngine::CheckForContinue()
{
HRESULT hr = S_OK;
// Need to check Abort before AND after check for pause...
if(_pCif->CanCancel() && (WaitForSingleObject(_hAbort, 0) == WAIT_OBJECT_0))
{
hr = E_ABORT;
}
if(SUCCEEDED(hr))
{
WaitForEvent(_hContinue, NULL);
}
if(_pCif->CanCancel() && (WaitForSingleObject(_hAbort, 0) == WAIT_OBJECT_0))
{
hr = E_ABORT;
}
return hr;
}
#define STEPPINGMODE_NO "n"
void CInstallEngine::WriteToLog(char *sz, BOOL pause)
{
ULONG foo;
UINT ret;
HKEY hKey;
if(_fSteppingMode && pause)
{
ret = MessageBox(_hwndForUI, sz, "Stepping Mode Message", MB_OKCANCEL | MB_ICONINFORMATION);
if(ret == IDCANCEL)
{
// turn off stepping mode
_fSteppingMode = FALSE;
// Whack the key
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, ACTIVESETUP_KEY,0,
KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
// I don't check for failure of delete - what would I do anyways?
RegSetValueEx(hKey, STEPPING_VALUE, 0, REG_SZ,
(BYTE *) STEPPINGMODE_NO, lstrlen(STEPPINGMODE_NO) + 1);
RegCloseKey(hKey);
}
}
}
if(_pStmLog)
_pStmLog->Write(sz, lstrlen(sz), &foo);
}
BOOL CInstallEngine::_IsValidBaseUrl(LPCSTR pszUrl)
{
BOOL bValid = TRUE;
if(!pszUrl)
bValid = FALSE;
return bValid;
}