windows-nt/Source/XPSP1/NT/enduser/windows.com/wuv3/wuv3is/install.cpp
2020-09-26 16:20:57 +08:00

739 lines
17 KiB
C++

//=======================================================================
//
// Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
//
// File: install.cpp
//
// Purpose: Install/uninstall components
//
//=======================================================================
#include "stdafx.h"
#include "install.h"
#include <advpub.h>
extern CState g_v3state; //defined in CV3.CPP
// This function installs an active setup catalog item.
void InstallActiveSetupItem(LPCTSTR szLocalDir, LPCTSTR pszCifFile, PSELECTITEMINFO pStatusInfo, IWUProgress* pProgress)
{
USES_CONVERSION;
MSG msg;
HRESULT hr;
DWORD dwEngineStatus;
IInstallEngine2* pInsEng = NULL;
ICifFile* picif = NULL;
ICifComponent* pcomp = NULL;
IEnumCifComponents* penum = NULL;
CInstallEngineCallback* pCallback = NULL;
try
{
//
// Create active setup engine
//
hr = CoCreateInstance(CLSID_InstallEngine, NULL, CLSCTX_INPROC_SERVER, IID_IInstallEngine2,(void **)&pInsEng);
if (FAILED(hr))
throw hr;
// Tell active setup the direct and directory to use. This is the directory
// where we downloaded the files previously.
hr = pInsEng->SetDownloadDir(T2A(szLocalDir));
if (FAILED(hr))
throw hr;
hr = pInsEng->SetLocalCif(T2A(pszCifFile));
if (FAILED(hr))
throw hr;
//
// Create the callback object and register the install engines callback interface
//
pCallback = new CInstallEngineCallback;
if (!pCallback)
{
throw HRESULT_FROM_WIN32(GetLastError());
}
pCallback->SetProgressPtr(pProgress);
pInsEng->RegisterInstallEngineCallback((IInstallEngineCallback *)pCallback);
pCallback->SetEnginePtr(pInsEng);
//
// Get a pointer to the CIF interface we need in order to enum the
// CIF components and we need to do that on this single item CIF
// becuase we need to tell the install engine what action to perform.
//
hr = pInsEng->GetICifFile(&picif);
if (FAILED(hr))
throw hr;
hr = picif->EnumComponents(&penum, 0, NULL);
if (FAILED(hr))
throw hr;
hr = penum->Next(&pcomp);
if (FAILED(hr))
throw hr;
// Set action to install and then install the component.
pcomp->SetInstallQueueState(SETACTION_INSTALL);
hr = pInsEng->InstallComponents(EXECUTEJOB_IGNORETRUST | EXECUTEJOB_IGNOREDOWNLOADERROR);
if (FAILED(hr))
{
TRACE_HR(hr, "InstallActiveSetupItem: inseng.InstallComponents failed");
throw hr;
}
do
{
pInsEng->GetEngineStatus(&dwEngineStatus);
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
SleepEx(50, TRUE);
} while (dwEngineStatus != ENGINESTATUS_READY);
if (pcomp->IsComponentInstalled() != ICI_INSTALLED)
{
hr = pCallback->LastError();
//
// if we don't know the exact error from the callback, use E_FAIL
//
if (hr == NOERROR)
hr = E_FAIL;
TRACE_HR(hr, "InstallActiveSetupItem: inseng failed to install");
throw hr;
}
//
// get the return status
//
if (pCallback->GetStatus() & STOPINSTALL_REBOOTNEEDED)
pStatusInfo->iStatus = ITEM_STATUS_SUCCESS_REBOOT_REQUIRED;
else
pStatusInfo->iStatus = ITEM_STATUS_SUCCESS;
pStatusInfo->hrError = NOERROR;
//
// release interfaces
//
if (penum)
penum->Release();
if (picif)
picif->Release();
if (pInsEng)
pInsEng->Release();
if (pCallback)
delete pCallback;
}
catch(HRESULT hr)
{
pStatusInfo->iStatus = ITEM_STATUS_FAILED;
pStatusInfo->hrError = hr;
if (penum)
penum->Release();
if (picif)
picif->Release();
if (pInsEng)
pInsEng->Release();
if (pCallback)
delete pCallback;
throw hr;
}
}
//This function handles installation of a Device driver package.
void InstallDriverItem(
LPCTSTR szLocalDir, //Local directory where installation files are.
BOOL bWindowsNT, //TRUE if client machine is NT else FALSE.
LPCTSTR pszTitle, //Description of package, Device Manager displays this in its install dialog.
PINVENTORY_ITEM pItem, //Install Item Information
PSELECTITEMINFO pStatusInfo //Returned status information.
)
{
LOG_block("InstallDriverItem");
try
{
//Note: GetCatalog automatically prunes any drivers if the system is
//not either NT 5 or Windows 98 since we only support installation
//of drivers on these platforms.
//If we do not have a hardware id then we cannot install the device.
PWU_VARIABLE_FIELD pvTmp = pItem->pv->Find(WU_CDM_HARDWARE_ID);
if (!pvTmp)
{
pStatusInfo->iStatus = ITEM_STATUS_FAILED;
pStatusInfo->hrError = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
return;
}
BOOL reboot = FALSE;
CdmInstallDriver(bWindowsNT,
(WU_ITEM_STATE_CURRENT == pItem->ps->state) ? edsCurrent : edsNew,
(LPCTSTR)pvTmp->pData, szLocalDir, pszTitle, (PULONG)&reboot);
if (reboot)
pStatusInfo->iStatus = ITEM_STATUS_SUCCESS_REBOOT_REQUIRED;
else
pStatusInfo->iStatus = ITEM_STATUS_SUCCESS;
pStatusInfo->hrError = NOERROR;
}
catch(HRESULT hr)
{
pStatusInfo->iStatus = ITEM_STATUS_FAILED;
pStatusInfo->hrError = hr;
throw hr;
}
}
HRESULT UninstallDriverItem(PINVENTORY_ITEM pItem, PSELECTITEMINFO pStatusInfo)
{
PBYTE pTitle;
PWU_VARIABLE_FIELD pvTitle;
PWU_VARIABLE_FIELD pvTmp;
BOOL bWindowsNT;
TCHAR szLocalDir[MAX_PATH];
BOOL bReboot = FALSE;
bWindowsNT = IsWindowsNT();
if (!(pvTmp = pItem->pv->Find(WU_CDM_HARDWARE_ID)) )
{
pStatusInfo->iStatus = ITEM_STATUS_FAILED;
pStatusInfo->hrError = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
return E_UNEXPECTED;
}
if (pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE))
{
pTitle = (PBYTE)pvTitle->pData;
}
else
{
pTitle = (PBYTE)"";
}
pStatusInfo->iStatus = ITEM_STATUS_SUCCESS;
//we will call UpdateCDMDriver with our cache directory but this directory should not
//really be used by UpdateCDMDriver in case of an uninstall since the uninstall case
//reads the correct directory from the registry
GetWindowsUpdateDirectory(szLocalDir);
try
{
CdmInstallDriver(bWindowsNT, edsBackup, (LPCTSTR)pvTmp->pData, szLocalDir, (LPCTSTR)pTitle, (PULONG)&bReboot);
if (bReboot)
{
g_v3state.m_bRebootNeeded = TRUE;
}
}
catch(HRESULT hr)
{
pStatusInfo->iStatus = ITEM_STATUS_FAILED;
pStatusInfo->hrError = hr;
return hr;
}
return S_OK;
}
HRESULT GetUninstallCmdFromKey(LPCTSTR pszUninstallKey, LPTSTR pszCmdValue)
{
const TCHAR UNINSTALLKEY[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\");
const TCHAR UNINSTALLVALUE[] = _T("UninstallString");
const TCHAR QUIETUNINSTALLVALUE[] = _T("QuietUninstallString");
HKEY hRegKey = NULL;
DWORD dwRegType;
DWORD dwRegSize;
TCHAR szRegKey[256];
LONG lRet;
TCHAR szValue[256];
if (pszUninstallKey == NULL)
return E_FAIL;
if (pszUninstallKey[0] == _T('"'))
{
//strip quotes from the key
lstrcpy(szValue, (pszUninstallKey + 1));
int l = lstrlen(szValue);
if (l > 0)
szValue[l - 1] = _T('\0');
}
else
{
lstrcpy(szValue, pszUninstallKey);
}
lstrcpy(szRegKey, UNINSTALLKEY);
lstrcat(szRegKey, szValue);
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_READ, &hRegKey);
if (lRet != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(lRet);
//check the uninstall value
dwRegSize = sizeof(szValue);
lRet = RegQueryValueEx(hRegKey, UNINSTALLVALUE, NULL, &dwRegType, (LPBYTE)szValue, &dwRegSize);
if (lRet != ERROR_SUCCESS)
{
// try to find quiteuninstall value
dwRegSize = sizeof(szValue);
lRet = RegQueryValueEx(hRegKey, QUIETUNINSTALLVALUE, NULL, &dwRegType, (LPBYTE)szValue, &dwRegSize);
}
if (lRet != ERROR_SUCCESS)
{
HRESULT hr = HRESULT_FROM_WIN32(lRet);
RegCloseKey(hRegKey);
return hr;
}
RegCloseKey(hRegKey);
//
// copy the key to the output parameter
//
lstrcpy(pszCmdValue, szValue);
return S_OK;
}
//Given an uninstall key, looks up in the registry to find the uninsall command and launches it
//If quotes are found around the uninstall key, they are striped. This is done to make it
//compatible with the value specified in the AS CIF file. This function also understands the
//special INF syntax of the uninstall key.
HRESULT UninstallActiveSetupItem(LPCTSTR pszUninstallKey)
{
const TCHAR INFUNINSTALLCOMMAND[] = _T("RunDll32 advpack.dll,LaunchINFSection ");
const TCHAR INFDIRECTORY[] = _T("INF\\");
TCHAR szCmd[256] = {_T('\0')};
TCHAR szActualKey[128] = {_T('\0')};
LONG lRet;
LPCTSTR pszParse;
HRESULT hr = S_OK;
if (pszUninstallKey == NULL)
return E_FAIL;
if (lstristr(pszUninstallKey, _T(".inf")) != NULL)
{
//
// we have .INF syntax: frontpad,fpxpress.inf,uninstall, start parsing
//
pszParse = lstrcpystr(pszUninstallKey, _T(","), szActualKey); // get actual uninstall key
}
else
{
lstrcpy(szActualKey, pszUninstallKey);
pszParse = NULL;
}
//
// get the uninstall command from the registry
//
hr = GetUninstallCmdFromKey(szActualKey, szCmd);
if (SUCCEEDED(hr))
{
// we have the uninstall command, try to launch it
lRet = LaunchProcess(szCmd, NULL, SW_NORMAL, TRUE);
TRACE("Uninstall: %s, %d", szCmd, lRet);
if (lRet != 0)
{
hr = HRESULT_FROM_WIN32(lRet);
}
}
else
{
// we did not get the uninstall command from registry, launch INF
if (pszParse != NULL)
{
TCHAR szTemp[MAX_PATH];
hr = S_OK;
//get INF directory
if (! GetWindowsDirectory(szTemp, sizeof(szTemp) / sizeof(TCHAR)))
{
hr = HRESULT_FROM_WIN32(GetLastError());
TRACE("Uninstall: GetWindowsDirectory failed, hr=0x%x", hr);
return hr;
}
AddBackSlash(szTemp);
lstrcat(szTemp, INFDIRECTORY);
//start building the command
lstrcpy(szCmd, INFUNINSTALLCOMMAND);
lstrcat(szCmd, szTemp);
pszParse = lstrcpystr(pszParse, _T(","), szTemp); // get INF file name
lstrcat(szCmd, szTemp);
lstrcat(szCmd, _T(","));
pszParse = lstrcpystr(pszParse, _T(","), szTemp); // get INF section
lstrcat(szCmd, szTemp);
lRet = LaunchProcess(szCmd, NULL, SW_NORMAL, TRUE);
if (lRet != 0)
{
hr = HRESULT_FROM_WIN32(lRet);
}
TRACE("Uninstall: %s, %d", szCmd, lRet);
if (SUCCEEDED(hr))
{
//
// reboot handling after uninstall only if uninstall was successful
//
pszParse = lstrcpystr(pszParse, _T(","), szTemp); // get the reboot key
if (lstrcmpi(szTemp, _T("reboot")) == 0)
{
g_v3state.m_bRebootNeeded = TRUE;
}
}
}
else
{
hr = E_UNEXPECTED;
}
}
return hr;
}
void InstallPrinterItem(LPCTSTR pszDriverName, LPCTSTR pszInstallFolder, LPCTSTR pszArchitecture)
{
DWORD dw = InstallPrinterDriver(pszDriverName, pszInstallFolder, pszArchitecture);
HRESULT hr = HRESULT_FROM_WIN32(dw);
if (FAILED(hr))
throw hr;
}
HRESULT AdvPackRunSetupCommand(HWND hwnd, LPCSTR pszInfFile, LPCSTR pszSection, LPCSTR pszDir, DWORD dwFlags)
{
HRESULT hr = E_FAIL;
RUNSETUPCOMMAND pfRunSetupCommand;
HINSTANCE hAdvPack = LoadLibrary(_T("advpack.dll"));
if (hAdvPack != NULL)
{
pfRunSetupCommand = (RUNSETUPCOMMAND)GetProcAddress(hAdvPack, "RunSetupCommand");
if (pfRunSetupCommand)
{
dwFlags |= (RSC_FLAG_INF | RSC_FLAG_NGCONV | RSC_FLAG_QUIET);
hr = pfRunSetupCommand(hwnd, pszInfFile, pszSection, pszDir, NULL, NULL, dwFlags, NULL);
}
FreeLibrary(hAdvPack);
}
return hr;
}
// checks to see if inseng is up to date
void CheckLocalDll(LPCTSTR pszServer, LPCTSTR pszDllName, LPCTSTR pszServDllName, LPCTSTR pszDllVersion)
{
USES_CONVERSION;
const TCHAR TEMPINFFN[] = _T("temp.inf");
const TCHAR PERIOD[] = _T(".");
TCHAR szServDllName[32] = _T("\0");
TCHAR szValue[256] = _T("\0");
TCHAR szTempFN[MAX_PATH] = _T("\0");
TCHAR szDllFN[MAX_PATH] = _T("\0");
TCHAR szInfDir[MAX_PATH] = _T("\0");
TCHAR szDllName[MAX_PATH] = _T("\0");
TCHAR szDllVersion[64] = _T("\0");
TCHAR *pszToken = NULL;
DWORD dwIniMSVer = 0;
DWORD dwIniLSVer = 0;
DWORD dwFileMSVer = 0;
DWORD dwFileLSVer = 0;
LPTSTR p = NULL;
HRESULT hr = S_OK;
//check input arguments
if (NULL == pszDllName || NULL == pszServDllName || NULL == pszDllVersion)
{
return ;
}
if (!GetSystemDirectory(szDllFN, sizeof(szDllFN) / sizeof(TCHAR)))
{
return;
}
AddBackSlash(szDllFN);
lstrcat(szDllFN, pszDllName);
lstrcpy(szDllVersion, pszDllVersion);
lstrcpy(szServDllName, pszServDllName);
if (FileExists(szDllFN))
{
// convert file version
ConvertVersionStrToDwords(szDllVersion, &dwIniMSVer, &dwIniLSVer);
// get file version of the DLL
if (!GetFileVersionDwords(szDllFN, &dwFileMSVer, &dwFileLSVer))
{
TRACE("Could not check file version: %s", szDllFN);
return;
}
// compare the versions
if ((dwFileMSVer > dwIniMSVer) || ((dwFileMSVer == dwIniMSVer) && (dwFileLSVer >= dwIniLSVer)))
{
// install version is up to date
return;
}
}
//
// we need to download and install it!
//
BLOCK
{
CWUDownload dl(pszServer, 8192);
if (!dl.Copy(szServDllName, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY, NULL))
{
throw HRESULT_FROM_WIN32(GetLastError());
}
// filename with OS ext
GetWindowsUpdateDirectory(szTempFN);
lstrcat(szTempFN, szServDllName);
// filename with .dll
lstrcpy(szDllFN, szTempFN);
p = _tcschr(szDllFN, _T('.'));
if (p)
*p = _T('\0');
lstrcat(szDllFN, _T(".dll"));
CDiamond dm;
// decompress or copy to .dll name
if (dm.IsValidCAB(szTempFN))
{
hr = dm.Decompress(szTempFN, szDllFN);
if (FAILED(hr))
{
throw hr;
}
}
else
{
if (!CopyFile(szTempFN, szDllFN, FALSE))
{
return;
}
}
}
//
// write out an INF file
//
HANDLE hFile;
DWORD dwBytes;
char szInfText[1024];
sprintf (szInfText,
"[Version]\r\n\
Signature=\"$Chicago$\"\r\n\
AdvancedINF=2.5\r\n\
[DestinationDirs]\r\n\
WUSysDirCopy=11\r\n\
[InstallControl]\r\n\
CopyFiles=WUSysDirCopy\r\n\
RegisterOCXs=WURegisterOCXSection\r\n\
[WUSysDirCopy]\r\n\
%s,,,32\r\n\
[WURegisterOCXSection]\r\n\
%%11%%\\%s\r\n\
[SourceDisksNames]\r\n\
55=\"Disk\",,0\r\n\
[SourceDisksFiles]\r\n\
%s=55\r\n",
T2A(pszDllName), T2A(pszDllName), T2A(pszDllName));
GetWindowsUpdateDirectory(szTempFN);
lstrcat(szTempFN, TEMPINFFN);
hFile = CreateFile(szTempFN, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
WriteFile(hFile, (LPCVOID)szInfText, strlen(szInfText), &dwBytes, NULL);
CloseHandle(hFile);
}
//
// RunSetupCommand to install the .INF
//
GetWindowsUpdateDirectory(szInfDir);
hr = AdvPackRunSetupCommand(NULL, T2A(szTempFN), "InstallControl", T2A(szInfDir), 0);
if (FAILED(hr))
{
throw hr;
}
}
void CheckDllsToJit(LPCTSTR pszServer)
{
const TCHAR SEPS[] = _T("=");
TCHAR szValue[1024];
TCHAR szTempFN[MAX_PATH];
TCHAR szKey[256];
TCHAR szDllBaseName[64];
TCHAR szDllExt[32];
TCHAR szKeyLhs[64];
TCHAR szDllName[64];
TCHAR szDllTempName[64];
TCHAR szDllVersion[64];
TCHAR *pszValue;
long len;
if (g_v3state.m_bInsengChecked)
return;
g_v3state.m_bInsengChecked = TRUE;
GetWindowsUpdateDirectory(szTempFN);
lstrcat(szTempFN, FILEVERINI_FN);
if (0 == GetPrivateProfileSection(_T("version"), szValue, sizeof(szValue) / sizeof(TCHAR), szTempFN))
{
// version not available for this file
TRACE("Section: version is missing from FileVer.ini");
return;
}
pszValue = szValue;
while (0 != (len = lstrlen(pszValue)))
{
lstrcpyn(szKey, pszValue, len+1);
lstrcat(szKey, _T("\0"));
pszValue += len + 1;
_stscanf(szKey, _T("%[^=]=%s"), szKeyLhs, szDllVersion);
_stscanf(szKeyLhs, _T("%[^.].%s"), szDllBaseName, szDllExt);
wsprintf(szDllName, _T("%s.dll"), szDllBaseName);
wsprintf(szDllTempName, _T("%s."), szDllBaseName);
AppendExtForOS(szDllTempName);
if (0 == lstrcmpi(szDllTempName, szKeyLhs))
CheckLocalDll(pszServer, szDllName, szKeyLhs, szDllVersion);
}
}
// Pings a URL for tracking purposes
//
// NOTE: pszStatus must not contain spaces and cannot be null
void URLPingReport(PINVENTORY_ITEM pItem, CCatalog* pCatalog, PSELECTITEMINFO pSelectItem, LPCTSTR pszStatus)
{
LOG_block("URLPingReport");
//check for input arguments
if (NULL == pItem || NULL == pCatalog)
{
return;
}
// create a download object
try
{
CWUDownload dl(g_v3state.GetIdentServer(), 8192);
// build the URL with parameters
TCHAR szURL[INTERNET_MAX_PATH_LENGTH];
wsprintf(szURL, _T("wutrack.bin?VER=%s&PUID=%d&PLAT=%d&LOCALE=%s&STATUS=%s&ERR=0x%x&SESSID=%s"),
CCV3::s_szControlVer,
pItem->GetPuid(),
pCatalog->GetPlatform(),
pCatalog->GetMachineLocaleSZ(),
pszStatus,
pSelectItem->hrError,
CWUDownload::m_szWUSessionID);
LOG_out("Sending %s", szURL);
// ping the URL and receive the response in memory
PVOID pMemBuf;
ULONG ulMemSize;
if (dl.QCopy(szURL, &pMemBuf, &ulMemSize))
{
// we don't care about the response so we just free it
V3_free(pMemBuf);
}
}
catch(HRESULT hr)
{
return;
}
}