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.
 
 
 
 
 
 

410 lines
11 KiB

#include "inspch.h"
#include "insobj.h"
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
CInstaller::CInstaller(CInstallEngine *p) : CTimeTracker(60000)
{
_pInsEng = p;
_hkProg = NULL;
_hMutex = NULL;
_hStatus = NULL;
_cRef = 1;
DllAddRef();
}
CInstaller::~CInstaller()
{
DllRelease();
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP_(ULONG) CInstaller::AddRef()
{
return(++_cRef);
}
//=--------------------------------------------------------------------------=
// Function name here
//=--------------------------------------------------------------------------=
// Function description
//
// Parameters:
//
// Returns:
//
// Notes:
//
STDMETHODIMP_(ULONG) CInstaller::Release()
{
if(!--_cRef)
{
delete this;
return(0);
}
return( _cRef );
}
HRESULT CInstaller::Abort()
{
if(_hMutex)
{
WaitForMutex(_hMutex);
if(_hkProg)
{
DWORD dwCancel = 1;
RegSetValueEx(_hkProg, CANCEL_VALUENAME, 0, REG_DWORD, (BYTE *) &dwCancel, sizeof(dwCancel));
}
ReleaseMutex(_hMutex);
}
return NOERROR;
}
HRESULT CInstaller::Suspend()
{
// assume no install going on
HRESULT hr = S_OK;
// if we have a mutex grab it and check for safe
if(_hMutex)
{
// there is an install, assume it isn't safe to cancel it
hr = S_FALSE;
WaitForMutex(_hMutex);
if(_hkProg)
{
DWORD dwSafe = 0;
DWORD dwSize = sizeof(dwSafe);
if(RegQueryValueEx(_hkProg, SAFE_VALUENAME, NULL, NULL, (BYTE *) &dwSafe, &dwSize) == ERROR_SUCCESS)
{
if(dwSafe == 1)
hr = S_OK;
}
}
}
return hr;
}
HRESULT CInstaller::Resume()
{
// if we have a mutex release it
if(_hMutex)
ReleaseMutex(_hMutex);
return NOERROR;
}
HRESULT CInstaller::DoInstall(LPCSTR pszDir, LPSTR pszCmd, LPSTR pszArgs, LPCSTR pszProg, LPCSTR pszCancel,
UINT uType, LPDWORD pdwStatus, IMyDownloadCallback *pcb)
{
char szFileName[MAX_PATH + 128];
char szBuf[MAX_PATH];
HANDLE hProc = NULL;
HMODULE hAdvpack;
HRESULT hr = S_OK;
DWORD dwTemp;
INF_ARGUEMENTS InsArgs;
_uTotalProgress = 0;
// create progress key if we need to
if(pszProg && pszCancel)
{
lstrcpy(szBuf, REGSTR_PROGRESS_KEY);
lstrcat(szBuf, pszProg);
RegCreateKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, NULL,0, KEY_READ | KEY_WRITE,NULL, &_hkProg, &dwTemp);
lstrcpy(szBuf, pszCancel);
lstrcat(szBuf, "Mutex");
_hMutex = CreateMutex(NULL, FALSE, szBuf);
lstrcpy(szBuf, pszCancel);
lstrcat(szBuf, "Event");
_hStatus = CreateEvent(NULL, FALSE, FALSE, szBuf);
}
// copy the advpack we are using into the temp dir of what we want to launch
// this insures that we always get a "good" copy of advpack
hAdvpack = GetModuleHandle("advpack.dll");
if(hAdvpack)
{
if(GetModuleFileName(hAdvpack, szBuf, sizeof(szBuf)))
{
lstrcpy(szFileName, pszDir);
AddPath(szFileName, "advpack.dll");
CopyFile(szBuf, szFileName, TRUE);
szBuf[0] = 0;
szFileName[0] = 0;
}
}
switch(uType)
{
case InfCommand:
case InfExCommand:
GetStringField(pszCmd, 0, szBuf, sizeof(szBuf));
// ParseURLA below is to ensure we only run inf out of our temp dir
lstrcpy(szFileName, pszDir);
AddPath(szFileName, ParseURLA(szBuf));
GetStringField(pszCmd, 1, szBuf, sizeof(szBuf));
lstrcpy(InsArgs.szInfname, szFileName);
lstrcpy(InsArgs.szSection, szBuf);
lstrcpy(InsArgs.szDir, pszDir);
InsArgs.dwType = uType;
if(uType == InfCommand)
{
InsArgs.dwFlags = RSC_FLAG_INF | RSC_FLAG_NGCONV;
if(_pInsEng->GetCommandMode() == 0)
InsArgs.dwFlags |= RSC_FLAG_QUIET;
}
if(uType == InfExCommand)
{
// add cab name
lstrcpy(InsArgs.szCab, "");
InsArgs.dwFlags = AtoL(pszArgs);
}
if(_pInsEng->GetStatus() & STOPINSTALL_REBOOTNEEDED)
InsArgs.dwFlags |= RSC_FLAG_DELAYREGISTEROCX;
wsprintf(szLogBuf, "Launching Inf - inf: %s, section: %s\r\n", szFileName, lstrlen(szBuf) ? szBuf : "Default");
_pInsEng->WriteToLog(szLogBuf, TRUE);
hProc = CreateThread(NULL, 0, LaunchInfCommand, &InsArgs, 0, &dwTemp);
hr = E_FAIL;
if(hProc)
{
_WaitAndPumpProgress(hProc, pcb);
DWORD dwRet;
if(GetExitCodeThread(hProc, &dwRet))
{
hr = dwRet;
if(SUCCEEDED(hr))
{
if(hr == ERROR_SUCCESS_REBOOT_REQUIRED)
*pdwStatus |= STOPINSTALL_REBOOTNEEDED;
}
else
{
wsprintf(szLogBuf, "Inf failed - return code %x\r\n", dwRet);
_pInsEng->WriteToLog(szLogBuf, TRUE);
}
}
else
_pInsEng->WriteToLog("Failed to get exit code\r\n", TRUE);
}
else
_pInsEng->WriteToLog("Create thread failed\r\n", TRUE);
break;
case WExtractExe:
case Win32Exe:
case HRESULTWin32Exe:
// ParseURLA below is to ensure we only run exe out of our temp dir
wsprintf(szFileName, CMDLINE, pszDir, ParseURLA(pszCmd), pszArgs);
wsprintf(szLogBuf, "Launching exe: command: %s\r\n", szFileName);
_pInsEng->WriteToLog(szLogBuf, TRUE);
hr = LaunchProcess(szFileName, &hProc, pszDir, SW_SHOWNORMAL);
if(SUCCEEDED(hr))
_WaitAndPumpProgress(hProc, pcb);
if(SUCCEEDED(hr))
{
// BUGBUG: Trace this path with WEXTRACT > 1140
if ( (uType == WExtractExe) || (uType == HRESULTWin32Exe) )
{
DWORD dwRet;
hr = E_FAIL;
if(GetExitCodeProcess(hProc, &dwRet))
{
wsprintf(szLogBuf, "Exe return code: %x\r\n", dwRet);
_pInsEng->WriteToLog(szLogBuf, TRUE);
hr = (HRESULT) dwRet;
if (uType == WExtractExe)
{
if(SUCCEEDED(hr))
{
if(hr == ERROR_SUCCESS_REBOOT_REQUIRED)
*pdwStatus |= STOPINSTALL_REBOOTNEEDED;
}
}
}
else
_pInsEng->WriteToLog("Failed to get exit code\r\n", TRUE);
}
}
else
_pInsEng->WriteToLog("Create process failed\r\n", TRUE);
break;
default:
// whatever
hr = E_INVALIDARG;
}
if (_hkProg)
{
RegCloseKey(_hkProg);
_hkProg = NULL;
}
if (_hMutex)
{
CloseHandle(_hMutex);
_hMutex = NULL;
}
if (_hStatus)
{
CloseHandle(_hStatus);
_hStatus = NULL;
}
return hr;
}
#define PROGRESS_INTERVAL 1000
#define SEARCHFORCONFLICT_INTERVAL 3
void CInstaller::_WaitAndPumpProgress(HANDLE hProc, IMyDownloadCallback *pcb)
{
HANDLE pHandles[2] = {hProc, _hStatus};
DWORD dwStartTick = GetTickCount();
DWORD dwOldTick = dwStartTick;
DWORD dwTickChange = 0;
DWORD dwProgress;
DWORD dwCurrentTick;
BOOL fQuit = FALSE;
DWORD dwRet;
DWORD dwSearchCount = 0;
HWND hLastVersionConflict = NULL;
HWND hVersionConflict = NULL;
while(!fQuit)
{
dwRet = MsgWaitForMultipleObjects(_hStatus ? 2 : 1, pHandles, FALSE, 1000, QS_ALLINPUT);
dwCurrentTick = GetTickCount();
dwTickChange = dwCurrentTick - dwOldTick;
if(dwOldTick > dwCurrentTick)
dwTickChange = ~dwTickChange;
if(dwTickChange > PROGRESS_INTERVAL)
{
dwSearchCount++;
if(dwSearchCount > SEARCHFORCONFLICT_INTERVAL || hLastVersionConflict)
{
hVersionConflict = GetVersionConflictHWND();
if(hVersionConflict)
{
if(hVersionConflict != hLastVersionConflict)
{
if(GetForegroundWindow() == _pInsEng->GetHWND())
SetForegroundWindow(hVersionConflict);
BOOL foo = MessageBeep(MB_ICONASTERISK);
}
}
hLastVersionConflict = hVersionConflict;
dwSearchCount = 0;
}
// if there is a version conflict, we assume you made no progress during the last time period
if(!hLastVersionConflict)
{
dwProgress = (dwTickChange / 1000) * GetBytesPerSecond();
dwProgress >>= 10;
_uTotalProgress += dwProgress;
pcb->OnProgress(_uTotalProgress, NULL);
}
dwOldTick = dwCurrentTick;
}
// Handle Message or done
if(dwRet == WAIT_OBJECT_0)
{
fQuit = TRUE;
}
else if ( (dwRet == WAIT_OBJECT_0 + 1) && (_hStatus != 0)) // update jobexec's status msg
{
if (!(fQuit = WaitForMutex(_hMutex)))
{
if (_hkProg != NULL)
{
char szBuf[MAX_PATH];
DWORD dwSize = sizeof(szBuf);
if (RegQueryValueEx(_hkProg, PROGRESS_DISPLAY, NULL, NULL, (LPBYTE) szBuf, &dwSize) == ERROR_SUCCESS)
pcb->OnProgress(_uTotalProgress, szBuf);
}
ReleaseMutex(_hMutex);
}
}
else
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// if it's a quit message we're out of here
if (msg.message == WM_QUIT)
fQuit = TRUE;
else
{
// otherwise dispatch it
DispatchMessage(&msg);
} // end of PeekMessage while loop
}
}
}
}