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
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
|
|
}
|
|
}
|
|
}
|
|
}
|