//======================================================================= // // Copyright (c) 1999 Microsoft Corporation. All Rights Reserved. // // File: install.cpp // // Purpose: Install/uninstall components // //======================================================================= #include "stdafx.h" #include "install.h" #include 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; } }