//======================================================================= // // Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved. // // File: cv3.cpp // // Purpose: V3 control main code // //======================================================================= #include "stdafx.h" #include "WUV3IS.h" #include #include #include #include #define USEWUV3INCLUDES #include #undef USEWUV3INCLUDES #include #include #include #include #include "printers.h" #include "progress.h" #include "newtrust.h" #include "history.h" #include "CV3.h" #include "detect.h" #include "callback.h" #include "locstr.h" #include "safearr.h" #include "install.h" #include "log.h" #include "template.h" #include "filecrc.h" #include #include #include #include "..\..\inc\wuverp.h" const TCHAR REGPATH_EXPLORER[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"); const TCHAR REGKEY_WINUPD_DISABLED[] = _T("NoWindowsUpdate"); #define EXENAME_128BIT _T("128BIT.EXE") // // State management class. All retrieved catalogs are stored here. When the // control exits then this class cleans up the memory used by each catalog // stored with the state module. So the application must not delete any catalogs // that have been added to state storage. // CState g_v3state; TCHAR CCV3::s_szControlVer[20] = _T("\0"); void DownloadDLL(CDiamond *pDiamond, CWUDownload *pDownload, LPCTSTR pszDLLName, LPCTSTR pszPath); void DownloadFileVerInfo(CWUDownload* pDownload); PBYTE DownloadOemInfo(CWUDownload *pDownload, CDiamond *pDiamond);; void DownloadCabs(LPCTSTR szLocalDir, CWUDownload* pDownload, CDiamond* pDiamond, PBYTE pCabList, PBYTE pCRCList, IWUProgress* pProgress, BOOL bUnCab); void DownloadCif(LPCTSTR szLocalDir, CDiamond* pDiamond, PINSTALLINFOSTRUCT pInstallInfo); void Download128Bit(LPCTSTR pszLocalDir, PINVENTORY_ITEM pItem, IWUProgress* pProgress); void DetectPlatAndLang(); void DetectActiveSetupWU(CWUDownload* pDownload, CDiamond* pDiamond, CCatalog* pCatalog); void DownloadItem(LPCTSTR pszLocalDir, CWUDownload *pDownload, CDiamond *pDiamond, PINSTALLINFOSTRUCT pInstallInfo, IWUProgress* pProgress); void InstallItem(LPCTSTR pszLocalDir, PSELECTITEMINFO pStatusInfo, PINSTALLINFOSTRUCT pInstallInfo, IWUProgress* pProgress); DWORD WINAPI RebootThreadProc(LPVOID pv); void CheckDescDiagInfo(CCatalog* pCatalog); bool IsArabicOrHebrew() { WORD wCurPrimeLang = PRIMARYLANGID(LOWORD(g_v3state.GetBrowserLocale())); return LANG_HEBREW == wCurPrimeLang || LANG_ARABIC == wCurPrimeLang; } // // CDescriptionMerger class // // a local class used to merge description files // class CDescriptionMerger { public: CDescriptionMerger() : m_pMap(NULL), m_pDiamond(NULL) { } ~CDescriptionMerger() { if (m_pMap != NULL) delete m_pMap; if (m_pDiamond != NULL) delete m_pDiamond; } HRESULT CheckMerge(PINSTALLINFOSTRUCT pInstallInfo); private: CCRCMapFile* m_pMap; CDiamond* m_pDiamond; HRESULT ReadMapFile(CCatalog* pCatalog); }; // // CCV3 class // // this function is called when our ref count becomes zero void CCV3::FinalRelease() { LOG_block("CCV3::FinalRelease"); // // reset state // g_v3state.Reset(); // // make sure we undo registration of MS trust key if we registred it // CConnSpeed::WriteToRegistry(); } // this function is called after our object is created, this is the prefered // place to do initialization HRESULT CCV3::FinalConstruct() { LOG_block("CCV3::FinalConstruct"); wsprintf(CCV3::s_szControlVer, _T("5,04,%d,%d"), VER_PRODUCTBUILD,VER_PRODUCTBUILD_QFE); TCHAR szLogFN[MAX_PATH]; TCHAR szDate[50]; TCHAR szTime[50]; GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, szDate, sizeof(szDate)/sizeof(szDate[0])); GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER, NULL, NULL, szTime, sizeof(szTime)/sizeof(szTime[0])); LOG_out("Windows Update V3 Internet Site Control, Version %s",s_szControlVer); LOG_out("Session starting %s at %s", szDate, szTime); // // set up the application log // GetWindowsUpdateDirectory(szLogFN); lstrcat(szLogFN, HISTORY_FILENAME); g_v3state.AppLog().SetLogFile(szLogFN); CConnSpeed::ReadFromRegistry(); m_bValidInstance = FALSE; // // seed the random number generator // srand((int)GetTickCount()); return S_OK; } // The get catalog method retrieves a catalog array from the server. The get catalog method only // accesses the server if the catalog is not already resident on the clients computer system. // This allows the VB script page call this method to quickly obtain filtered catalog record information. STDMETHODIMP CCV3::GetCatalog( IN long puidCatalog, IN BSTR bstrServerUrl, IN long platformId, IN BSTR bstrBrowserLanguage, // BUGBUG - why is browser locale a string and not a long IN long lFilters, IN long lFlags, OUT RETVAL VARIANT *pCatalogArray ) { HRESULT hr; CCatalog* pCatalog; LOG_block("CCV3::GetCatalog"); try { pCatalog = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, lFilters, lFlags); //If we are retrieving the sub-catalog list then the return VB script array //needs to be different. if (pCatalog->GetCatalogPuid() == WU_CATALOG_LIST_PUID) { hr = MakeReturnCatalogListArray(pCatalog, lFilters, lFlags, pCatalogArray); if (FAILED(hr)) throw hr; } else { hr = MakeReturnCatalogArray(pCatalog, lFilters, lFlags, pCatalogArray); if (FAILED(hr)) throw hr; } } catch(HRESULT hr) { // create an empty array so that script doesn't throw a UBound error LPSAFEARRAY psa; SAFEARRAYBOUND rgsabound[2]; VariantInit(pCatalogArray); rgsabound[0].lLbound = 0; rgsabound[0].cElements = 0; rgsabound[1].lLbound = 0; rgsabound[1].cElements = 8; psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound); V_VT(pCatalogArray) = VT_ARRAY | VT_VARIANT; V_ARRAY(pCatalogArray) = psa; // we can't return a failure code, because that prevents script from // honoring the return value. return S_FALSE; } return S_OK; } STDMETHODIMP CCV3::GetCatalogHTML( IN long puidCatalog, IN BSTR bstrServerUrl, IN long platformId, IN BSTR bstrBrowserLanguage, IN long lFilters, IN long lFlags, OUT RETVAL VARIANT *pCatalogHTML ) { HRESULT hr; CCatalog* pCatalog; // we are currently not using the templates feature // the code for this templates are wrapped in HTML_TEMPLATE define #ifdef HTML_TEMPLATE TRACE("GetCatalogHTML: %d", puidCatalog); try { pCatalog = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, lFilters, lFlags); hr = MakeCatalogHTML(pCatalog, lFilters, pCatalogHTML); if (FAILED(hr)) throw hr; } catch(HRESULT hr) { return hr; } return S_OK; #endif return E_NOTIMPL; } /* * The process catalog function constructs or retireves the requested * V3 catalog. A pointer to the retrieved or constructed catalog is * returned to the caller if successfull or an HRESULT error code is * thrown if not. */ CCatalog *CCV3::ProcessCatalog( IN PUID puidCatalog, IN BSTR bstrServerUrl, IN long platformId, IN BSTR bstrBrowserLanguage, IN long lFilters, IN long lFlags ) { USES_CONVERSION; CCdm cdm; BOOL bCheckInNeeded; CDiamond dm; CBitmask bmAS; CBitmask bmCDM; CCatalog* pCatalog; TCHAR szIdentServer[MAX_PATH]; char szBuffer[1024]; PINVENTORY_ITEM pCatalogItem; int i; HRESULT hr; LOG_block("CCV3::ProcessCatalog"); LOG_out("puidCatalog = %d, bstrServerUrl = %s", puidCatalog, OLE2T(bstrServerUrl)); LOG_out("tick count is %d", GetTickCount()); // assume that the catalog is in state storage. bCheckInNeeded = FALSE; // // if catalog is not already in state storage go retrieve and prune it. // if ( !(pCatalog = g_v3state.Get(puidCatalog)) ) { if (NULL == bstrBrowserLanguage) // AutoUpdate { // We'll use this flag to determine whether to show UI when we call VerifyFile g_v3state.m_nClient = WUV3_CLIENT_AUTOUPDATE; LOG_out("Client Set to AutoUpdate"); LOG_out("Client is currently %s", (CWUDownload::s_fOffline) ? "Offline" : "Online"); } // // check if the ident server is trusted as well as read the valid server // list from ident.cab into memory // lstrcpy(szIdentServer, OLE2T(bstrServerUrl)); RemoveLastSlash(szIdentServer); g_v3state.CheckTrustedServer(szIdentServer, &dm); // // check the server the control was launch from. At this point the // ident cab is already loaded // this function will do the work only once and it will throw if // the server is not valid // CheckLaunchServer(); // // create a new catalog object // pCatalog = new CCatalog(g_v3state.GetContentServer(), puidCatalog); if (NULL == pCatalog) { LOG_out("ProcessCatalog: Creation of new Catalog failed. GetLastError() = %d", GetLastError()); throw HRESULT_FROM_WIN32(GetLastError()); } if (NULL != bstrBrowserLanguage) // AutoUpdate whould set it to NULL { pCatalog->SetBrowserLocale(OLE2T(bstrBrowserLanguage)); } // // Create a download object for the content // CWUDownload dl(pCatalog->GetCatalogServer(), 8192); // // read the catalog // pCatalog->Read(&dl, &dm); // // read the bitmask file // bmAS.Read(&dl, &dm, puidCatalog, BITMASK_ACTIVESETUP_TYPE, pCatalog->GetBitmaskName()); if (!g_v3state.m_pdwPlatformList) { TCHAR szOsdetServer[MAX_PATH]; lstrcpy(szOsdetServer, _T("OSDET.")); AppendExtForOS(szOsdetServer); DownloadFileVerInfo(&dl); DownloadDLL(&dm, &dl, szOsdetServer, NULL); DetectPlatAndLang(); LOG_out("Platform %d", g_v3state.m_pdwPlatformList[0]); LOG_out("Machine Language 0x%8.8x", GetMachineLangDW()); LOG_out("User UI Language 0x%8.8x", GetUserLangDW()); } if (NULL == bstrBrowserLanguage) // AutoUpdate { // For Windows XP, AU can't use the system language - we need to use the MUI user language //pCatalog->SetBrowserLocale(pCatalog->GetMachineLocaleSZ()); pCatalog->SetBrowserLocale(pCatalog->GetUserLocaleSZ()); } if (puidCatalog == WU_CATALOG_LIST_PUID) { // inventory.plt is platform 0 by convention pCatalog->SetPlatform(g_v3state.m_pdwPlatformList[0]); } else { // normal inventory item sub catalog. if (!platformId) { // if the caller did not pass in a platformId then we // need to detect the current platform and use that value // in the catalog. In this case we luck out since the first // platform id returned from osdet.dll is the client machines platform. pCatalog->SetPlatform(g_v3state.m_pdwPlatformList[0]); } else { pCatalog->SetPlatform(platformId); } } // inventory.plt catalog only does bitmask pruning if ( puidCatalog == WU_CATALOG_LIST_PUID ) { // if puidCatalog is 0 then we are retrieving the inventory.plt list of // catalogs. We need to handle this catalog differently. pCatalog->BitmaskPruning(&bmAS, g_v3state.m_pdwPlatformList, g_v3state.m_iTotalPlatforms); } else { // we are retrieving a normal inventory catalog. // since we need the OEM table to perform bitmask detection on an inventory catalog // we first check to see if the oem table has already been read. If it has not we // download. Note: We use full local caching on the OEM table. This is important for // maximum performance. if ( !g_v3state.m_pOemInfoTable ) //Pointer OEM info table that OEM detection needs. { byte_buffer bufOemInfo; if (! DownloadToBuffer( _T("oeminfo.bin"), &dl, &dm, bufOemInfo)) throw HRESULT_FROM_WIN32(GetLastError()); g_v3state.m_pOemInfoTable = bufOemInfo.detach(); } // perform active setup record bitmask pruning. pCatalog->BitmaskPruning(&bmAS, g_v3state.m_pOemInfoTable); // since windows 95 & NT4.0 do not support PnP drivers we cannot add any device driver records. // // NOTE: The catalog.Prune() method hides the device driver insertion record. So we do not need // to do anything if the OS does not allow device driver installations. if (DoesClientPlatformSupportDrivers()) { LOG_out("Support drivers on this platform"); // if there are device driver records to be added. if ( pCatalog->GetRecordIndex(WU_TYPE_CDM_RECORD_PLACE_HOLDER) != -1 ) { LOG_out("Have drivers on this platform"); // if there are no drivers for this platform // the bitmask will be missing and the Read() // method will throw. In this case, we do nothing. try { bmCDM.Read(&dl, &dm, puidCatalog, BITMASK_CDM_TYPE, NULL); cdm.CreateInventoryList(&bmCDM, &dl, &dm, puidCatalog, g_v3state.m_pOemInfoTable); pCatalog->AddCDMRecords(&cdm); } catch(HRESULT hr) { LOG_out("ProcessCatalog: bitmask.cdm or inventory.cdm missing."); } } else { LOG_out("Don't have drivers on this platform"); } } else { LOG_out("Don't support drivers on this platform"); } pCatalog->ProcessExclusions(&dl); // // do active setup detection // DetectActiveSetupWU(&dl, &dm, pCatalog); // perform catalog inventory link processing and use selected registry item hiding. pCatalog->Prune(); } if (puidCatalog == WU_CATALOG_LIST_PUID) { // description files for catalog list // // NOTE: With 3.1 we dropped the description fields for catalog list // we fill the structure with blank descriptions for (i = 0; i < pCatalog->GetHeader()->totalItems; i++) { if (NULL == (pCatalogItem = pCatalog->GetItem(i))) { continue; } if (pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED) { (void)pCatalog->BlankDescription(pCatalogItem); } } } else { // // read descriptions for the catalog items // 1. read gang description file // 2. (pass 1) read individual descriptions for items that did not get descriptions by // by using browser language // 3. (pass 2) read individual descriptions for itmes that still did not get descriptions // by using machine language // hr = pCatalog->ReadDescriptionGang(&dl, &dm); // check to see if we need to download any individual descriptions BOOL bNeedIndividual = FALSE; if (FAILED(hr)) { bNeedIndividual = TRUE; } else { for (i = 0; i < pCatalog->GetHeader()->totalItems; i++) { if (NULL == (pCatalogItem = pCatalog->GetItem(i))) { continue; } if ((pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED) && (pCatalogItem->pd == NULL)) { // need to download it bNeedIndividual = TRUE; break; } } // for } for (int iPass = 1; iPass <= 2; iPass++) { if (!bNeedIndividual) { break; } hr = S_OK; bNeedIndividual = FALSE; // // we need to download individual description files // TCHAR szMapFile[MAX_PATH]; TCHAR szMapFileLocal[MAX_PATH]; BYTE* pMapMem; DWORD dwMapLen; // build path for crc map file wsprintf(szMapFile, _T("%d_%s.des"), pCatalog->GetPlatform(), (iPass == 1) ? pCatalog->GetBrowserLocaleSZ() : pCatalog->GetMachineLocaleSZ()); //because the map file name isn't a CRC, we can't guarantee that it is the right one - always delete and re-download GetWindowsUpdateDirectory(szMapFileLocal); lstrcat(szMapFileLocal, szMapFile); if(!CWUDownload::s_fOffline) { DeleteFile(szMapFileLocal); } hr = DownloadFileToMem(&dl, szMapFile, &dm, &pMapMem, &dwMapLen); if (SUCCEEDED(hr)) { // create a crc map object with the memory image of the file CCRCMapFile DescMap(pMapMem, dwMapLen); CWUDownload dlRoot(g_v3state.GetRootServer(), 8192); for (i = 0; i < pCatalog->GetHeader()->totalItems; i++) { if (NULL == (pCatalogItem = pCatalog->GetItem(i))) { continue; } if ((pCatalogItem->ps->state != WU_ITEM_STATE_PRUNED) && (pCatalogItem->pd == NULL)) { DWORD dwDisp = 0; hr = pCatalog->ReadDescription(&dlRoot, &dm, pCatalogItem, &DescMap, &dwDisp); if (FAILED(hr)) { // description not found if (iPass == 1) { bNeedIndividual = TRUE; hr = S_OK; } else { switch(dwDisp) { case DISP_PUID_NOT_IN_MAP: wsprintfA(szBuffer, "Puid #%d not found in map file - removing from catalog", pCatalogItem->GetPuid()); LOG_out(szBuffer); pCatalogItem->ps->state = WU_ITEM_STATE_PRUNED; hr = S_OK; break; case DISP_DESC_NOT_FOUND: wsprintfA(szBuffer, "Missing description file for puid #%d - removing from catalog", pCatalogItem->GetPuid()); LOG_out(szBuffer); pCatalogItem->ps->state = WU_ITEM_STATE_PRUNED; hr = S_OK; break; } break; } } } } // for i V3_free(pMapMem); } else { if (iPass == 1) { bNeedIndividual = TRUE; hr = S_OK; } } } // for iPass if (FAILED(hr)) { throw hr; } #ifdef _WUV3TEST // validate descriptions CheckDescDiagInfo(pCatalog); #endif // _WUV3TEST } bCheckInNeeded = TRUE; LOG_out("catalog for %d NOT found in state cache, create it", puidCatalog);//added by wei } else //added by wei { LOG_out("catalog for %d found in state cache, return it", puidCatalog); } // in the case where the catalog is already in state storage we simply make // the catalog array and return. // NOTE: if this catalog came from state storage then there is no reason to check it in. if (bCheckInNeeded) { // finally check the pruned catalog into state storage. g_v3state.Add(puidCatalog, pCatalog); } // if we got here that also means that CheckLaunchServer has validated us // mark this instance as a valid one m_bValidInstance = TRUE; return pCatalog; } STDMETHODIMP CCV3::ChangeItemState( IN long puid, IN long lNewItemState ) { HRESULT hrRet = S_OK; try { hrRet = ProcessChangeItemState(puid, lNewItemState); } catch (HRESULT hr) { hrRet = hr; } return hrRet; } HRESULT CCV3::ProcessChangeItemState( IN long puid, IN long lNewItemState ) { HKEY hKey; BOOL bChanged; int i; int iTotalItems; Varray pItemList; if (!m_bValidInstance) { return E_ACCESSDENIED; } //if the requested state is SELECT by itself, we default to SELECT | INSTAL if (lNewItemState == ITEM_STATE_SELECT_ITEM) { lNewItemState = ITEM_STATE_SELECT_ITEM | ITEM_STATE_INSTALL_ITEM; } if (!(iTotalItems = g_v3state.GetItemList(puid, pItemList))) { TRACE("ChangeItemState called with invalid PUID %d", puid); return E_INVALIDARG; } bChanged = FALSE; for (i = 0; i < iTotalItems; i++) { // // show/hide // if (lNewItemState & ITEM_STATE_HIDE_ITEM) { if ( !pItemList[i]->ps->bHidden ) { pItemList[i]->ps->bHidden = TRUE; bChanged = TRUE; } } else if (lNewItemState & ITEM_STATE_SHOW_ITEM) { if ( pItemList[i]->ps->bHidden ) { pItemList[i]->ps->bHidden = FALSE; bChanged = TRUE; } } // // select // if (lNewItemState & ITEM_STATE_SELECT_ITEM) { // default is to select the item for install. if (lNewItemState & ITEM_STATE_INSTALL_ITEM) { if (!pItemList[i]->ps->bChecked ) { pItemList[i]->ps->bChecked = TRUE; bChanged = TRUE; g_v3state.m_selectedItems.Select(puid, TRUE); } } if ( lNewItemState & ITEM_STATE_REMOVE_ITEM ) { // remove only removes requested item. g_v3state.m_selectedItems.Select(puid, FALSE); bChanged = TRUE; } } // // unselect // if ( lNewItemState & ITEM_STATE_UNSELECT_ITEM ) { if ( pItemList[i]->ps->bChecked ) { if (pItemList[i]->ps->bChecked ) { pItemList[i]->ps->bChecked = FALSE; bChanged = TRUE; } // add item and all of its dependent items to selected items array. // remove item from selected items array. // // NOTE: This will only remove the item // if the select count is 0. g_v3state.m_selectedItems.Unselect(puid); } } // // personalize hide/unhide // if (lNewItemState & ITEM_STATE_PERSONALIZE_HIDE) { pItemList[i]->ps->bHidden = TRUE; pItemList[i]->ps->dwReason = WU_STATE_REASON_PERSONALIZE; bChanged = RegistryHidingUpdate(puid, TRUE); } if (lNewItemState & ITEM_STATE_PERSONALIZE_UNHIDE) { bChanged = RegistryHidingUpdate(puid, FALSE); if (bChanged) { pItemList[i]->ps->bHidden = FALSE; pItemList[i]->ps->dwReason = WU_STATE_REASON_NONE; } } } if (!bChanged) return E_INVALIDARG; return S_OK; } int __cdecl SortComparePriority(const void* p1, const void* p2) { DWORD d1 = ((DEPENDPUID*)p1)->dwPriority; DWORD d2 = ((DEPENDPUID*)p2)->dwPriority; // reverse order compare if (d1 > d2) return -1; else if (d1 < d2) return +1; else return 0; } // Now sort if by priority static Varray g_vPuidParent; static int g_cPuidParent; void ListDependenciesFirst(Varray& vInitList, int cInitList, Varray& vFinalList, int& cFinalList) { // sort initial list if (cInitList > 1) qsort((void *)(&vInitList[0]), cInitList, sizeof(DEPENDPUID), SortComparePriority); for (int iInitList = 0; iInitList < cInitList; iInitList++) { // check if we are in the parent array; for (int i = 0; i < g_cPuidParent; i++) { if (g_vPuidParent[i] == vInitList[iInitList].puid) break; } if (i != g_cPuidParent) continue; // didn't get to the very end // Get catalog CCatalog* pCatalog; PINVENTORY_ITEM pItem; if (!g_v3state.GetCatalogAndItem(vInitList[iInitList].puid, &pItem, &pCatalog)) { continue; } // Get dependancies Varray vTmpList; int cTmpList = 0; pCatalog->GetItemDirectDependencies(pItem, vTmpList, cTmpList); if (cTmpList) { // set vInitList[iList].pTopLevelItem, for them for(int j = 0; j < cTmpList; j ++) { if (NULL == vInitList[iInitList].pTopLevelItem) vTmpList[j].pTopLevelItem = pItem; else vTmpList[j].pTopLevelItem = vInitList[iInitList].pTopLevelItem; } // prepend them g_vPuidParent[g_cPuidParent ++] = vInitList[iInitList].puid; ListDependenciesFirst(vTmpList, cTmpList, vFinalList, cFinalList); g_cPuidParent --; } // Check if it's included by now for (i = 0; i < cFinalList; i++) { if (vFinalList[i].puid == vInitList[iInitList].puid) break; } if (i != cFinalList) continue; // didn't get to the very end // now add the item if it's not there vFinalList[cFinalList ++] = vInitList[iInitList]; } } void ProcessInstallList(Varray& vFinalList, int& cFinalList) { LOG_block("CCV3::ProcessInstallList"); PSELECTITEMINFO pSel = g_v3state.m_selectedItems.GetItems(); int cSel = g_v3state.m_selectedItems.GetTotal(); if (cSel == 0) return; // Build selection list Varray vSelectList; int cSelectList = 0; DEPENDPUID d = {0}; for (int iSel = 0; iSel < cSel; iSel++) { d.puid = pSel[iSel].puid; d.puidParent = 0; d.pTopLevelItem = NULL; // that is important CCatalog* pCatalog; PINVENTORY_ITEM pItem; if (!g_v3state.GetCatalogAndItem(d.puid, &pItem, &pCatalog)) { continue; } // look up priority and add the item to the array d.dwPriority = 0; PWU_VARIABLE_FIELD pvPri = pItem->pd->pv->Find(WU_DESC_INSTALL_PRIORITY); if (pvPri != NULL) d.dwPriority = *((DWORD*)(pvPri->pData)); vSelectList[cSelectList ++] = d; } // build final list g_cPuidParent = 0; ListDependenciesFirst(vSelectList, cSelectList, vFinalList, cFinalList); // // now, clear the select and reselect the items (including dependendcies) for installation in order // g_v3state.m_selectedItems.Clear(); for (int i = 0; i < cFinalList; i++) { LOG_out("Final List %d Pri=%d Parent=%d TopLevel=%s", vFinalList[i].puid, vFinalList[i].dwPriority, vFinalList[i].puidParent, (vFinalList[i].pTopLevelItem == NULL ? "NULL" : "Not NULL")); // select the item g_v3state.m_selectedItems.Select(vFinalList[i].puid, TRUE); } } STDMETHODIMP CCV3::InstallSelectedItems( IN BSTR bstrUnused, //Server Directory if blank then the server used with the catalog was retrieved is used. IN long lFlags, //Flags currently only WU_NOSPECIAL_FLAGS and WU_COPYONLY_NO_INSTALL supported. IN BSTR bstrNotUsed, OUT RETVAL VARIANT *pResultsArray ) { LOG_block("CCV3::InstallSelectedItems"); int iTotalItems = 0; TCHAR szTempDir[MAX_PATH]; TCHAR szLocalDir[MAX_PATH]; CDiamond dm; PSELECTITEMINFO pInfo = NULL; Varray InstallArr; int InstallCnt = 0; DWORD dwTotalBytes = 0; Varray vFinalList; int cFinalList = 0; int i; int t; if (!m_bValidInstance) { return E_ACCESSDENIED; } try { CWUProgress Progress(_Module.GetModuleInstance()); CServPauser ServPauser; CDescriptionMerger DescMerger; g_v3state.m_bRebootNeeded = FALSE; // // process depenendencies and priorities of the item // ProcessInstallList(vFinalList, cFinalList); iTotalItems = g_v3state.m_selectedItems.GetTotal(); pInfo = g_v3state.m_selectedItems.GetItems(); // pause task scheduler ServPauser.PauseTaskScheduler(); // // go thru all the selected items and build the InstallArr // for (i = 0, InstallCnt = 0; i < iTotalItems; i++) { if (pInfo[i].bInstall) { if (!g_v3state.GetCatalogAndItem(pInfo[i].puid, &InstallArr[InstallCnt].pItem, &InstallArr[InstallCnt].pCatalog)) { continue; } // // remove the "Checked" status from the item // InstallArr[InstallCnt].pItem->ps->bChecked = FALSE; dwTotalBytes += (InstallArr[InstallCnt].pItem->pd->size * 1024); // // create download objects. We use the GetCabPoolServer to get the server.for cabpool // we create objects for only one element and assign pdl of each install element to this object // // NOTE: We are ignoring the szServer passed in and we will eventually remove it from interface // if (InstallCnt == 0) { TRACE("InstallSelectedItems: creating download objects for %s and %s", g_v3state.GetCabPoolServer(), InstallArr[0].pCatalog->GetCatalogServer()); InstallArr[0].bServerNew = TRUE; InstallArr[0].pdl = new CWUDownload(g_v3state.GetCabPoolServer(), 8192); InstallArr[0].pdlRoot = new CWUDownload(g_v3state.GetRootServer(), 8192); } else { InstallArr[InstallCnt].pdl = InstallArr[0].pdl; InstallArr[InstallCnt].pdlRoot = InstallArr[0].pdlRoot; InstallArr[InstallCnt].bServerNew = FALSE; } InstallArr[InstallCnt].pInfo = &pInfo[i]; GetCurTime(&(InstallArr[InstallCnt].pInfo->stDateTime)); InstallArr[InstallCnt].pInfo->iStatus = ITEM_STATUS_FAILED; //init to failed InstallArr[InstallCnt].iSelIndex = i; InstallArr[InstallCnt].dwLocaleID = 0; // use systems InstallArr[InstallCnt].dwPlatform = 0; // use systems InstallArr[InstallCnt].bHistoryWritten = FALSE; InstallArr[InstallCnt].bDownloaded = FALSE; InstallArr[InstallCnt].pTopLevelItem = NULL; // // if the item is hidden, set the pTopLevelItem using the dependcies list // if (InstallArr[InstallCnt].pItem->ps->bHidden) { PUID puidDep = InstallArr[InstallCnt].pItem->GetPuid(); // //check puidDep, i.e. check if the function GetPuid() is returning valid info // if (puidDep > 0) { for (int iDep = 0; iDep < cFinalList; iDep++) { if (vFinalList[iDep].puid == puidDep) { InstallArr[InstallCnt].pTopLevelItem = vFinalList[iDep].pTopLevelItem; break; } } } } // // merge the descriptions if machine/browser languages are different so that // we have the correct installation information based on machine language // BLOCK { HRESULT hr = DescMerger.CheckMerge(&InstallArr[InstallCnt]); if (FAILED(hr)) { TRACE("Failed while mergeing description"); throw hr; } } InstallCnt++; } } // // get the directory where we will download CABs // GetWindowsUpdateDirectory(szTempDir); AddBackSlash(szTempDir); Progress.StartDisplay(); Progress.SetDownloadTotal(dwTotalBytes); Progress.SetInstallTotal(InstallCnt * 3); // // Create directory for and download each item // for (i = 0; i < InstallCnt; i++) { wsprintf(szLocalDir, _T("%sCabs\\%d"), szTempDir, InstallArr[i].pInfo->puid); V3_CreateDirectory(szLocalDir); InstallArr[i].bDownloaded = TRUE; //assume the download will be fine try { DownloadItem(szLocalDir, InstallArr[i].pdl, &dm, &InstallArr[i], &Progress); } catch (HRESULT hr) { InstallArr[i].pInfo->iStatus = ITEM_STATUS_FAILED; InstallArr[i].bDownloaded = FALSE; // // check to see if the Cancel button was pressed // if (WaitForSingleObject(Progress.GetCancelEvent(), 0) == WAIT_OBJECT_0) throw hr; } // even though the download for this item has succeeded, we reset the status to 'failed' // until we actually finish the installation InstallArr[i].pInfo->iStatus = ITEM_STATUS_FAILED; } Progress.SetDownload(); //100% // // Install each package and delete its directory // for (i = 0; i < InstallCnt; i++) { wsprintf(szLocalDir, _T("%sCabs\\%d"), szTempDir, InstallArr[i].pInfo->puid); Progress.SetInstallAdd(1); if (InstallArr[i].bDownloaded) { // if this is an exclusive component, hide the install progress. We assume // that, apart from dependencies, this will be the only component being installed // since it is by definition exclusive. In that case, this will be the last component // and install progress will be hidden so that the component's own setup UI is displayed if (InstallArr[i].pItem->pd->flags & DESCRIPTION_EXCLUSIVE) { Progress.SetStyle(CWUProgress::ProgStyle::OFF); } // install the item InstallItem(szLocalDir, InstallArr[i].pInfo, &InstallArr[i], &Progress); } Progress.SetInstallAdd(1); DeleteNode(szLocalDir); UpdateInstallHistory(InstallArr[i].pInfo, 1); InstallArr[i].bHistoryWritten = TRUE; if ((InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS) || (InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS_REBOOT_REQUIRED)) { //update item status to CURRENT InstallArr[i].pItem->ps->state = WU_ITEM_STATE_CURRENT; //indicate that a reboot is required if (InstallArr[i].pInfo->iStatus == ITEM_STATUS_SUCCESS_REBOOT_REQUIRED) g_v3state.m_bRebootNeeded = TRUE; } //remove the selected flag from the item InstallArr[i].pItem->ps->bChecked = FALSE; Progress.SetInstallAdd(1); } Progress.SetInstall(); //100% // create return array MakeInstallStatusArray(pInfo, iTotalItems, pResultsArray); // remove all items from selected items g_v3state.m_selectedItems.Clear(); // close server connections for (i = 0; i < iTotalItems; i++) { if (InstallArr[i].bServerNew) { delete InstallArr[i].pdl; delete InstallArr[i].pdlRoot; } } Progress.EndDisplay(); // delete any cached readthisfirst pages CleanupReadThis(); } catch (HRESULT hr) { if (pInfo != NULL) { // create return array MakeInstallStatusArray(pInfo, iTotalItems, pResultsArray); } else { return hr; } // // if there was an error, we don't want to reboot // g_v3state.m_bRebootNeeded = FALSE; // // remove all items from m_selected // g_v3state.m_selectedItems.Clear(); // close server connections for (i = 0; i < iTotalItems; i++) { if (InstallArr[i].bServerNew) { delete InstallArr[i].pdl; delete InstallArr[i].pdlRoot; } if (!InstallArr[i].bHistoryWritten) UpdateInstallHistory(InstallArr[i].pInfo, 1); } // delete any cached readthisfirst pages CleanupReadThis(); return S_FALSE; } return S_OK; } STDMETHODIMP CCV3::GetInstallMetrics( OUT RETVAL VARIANT *pMetricsArray ) { PSELECTITEMINFO pInfo; PINVENTORY_ITEM pItem; int iTotalSelectedItems; try { iTotalSelectedItems = g_v3state.m_selectedItems.GetTotal(); pInfo = g_v3state.m_selectedItems.GetItems(); MakeInstallMetricArray(pInfo, iTotalSelectedItems, pMetricsArray); } catch(HRESULT hr) { return hr; } return S_OK; } STDMETHODIMP CCV3::GetEula( OUT RETVAL VARIANT *pEulaArray ) { PSELECTITEMINFO pInfo; PINVENTORY_ITEM pItem; int i; int iTotalSelectedItems; if (!m_bValidInstance) { return E_ACCESSDENIED; } try { // // Walk though item array for each install item. Each item selected for installation // is store in a puid array that is part of the g_v3state class. This is a performance // enhancement. If we did not do this then we would need to walk through the entire // state structure for each catalog for every item and check it's installation state. // iTotalSelectedItems = g_v3state.m_selectedItems.GetTotal(); pInfo = g_v3state.m_selectedItems.GetItems(); MakeEulaArray(pInfo, iTotalSelectedItems, pEulaArray); } catch(HRESULT hr) { return hr; } return S_OK; } STDMETHODIMP CCV3::GetInstallHistory( OUT RETVAL VARIANT *pHistoryArray ) { int i; int iTotalItems; Varray History; if (!m_bValidInstance) { return E_ACCESSDENIED; } try { // // Walk though item array for each install item. Each item selected for installation // is store in a puid array that is part of the g_v3state class. This is a performance // enhancement. If we did not do this then we would need to walk through the entire // state structure for each catalog for every item and check it's installation state. // ReadHistory(History, iTotalItems); MakeInstallHistoryArray(History, iTotalItems, pHistoryArray); } catch(HRESULT hr) { return hr; } return S_OK; } STDMETHODIMP CCV3::GetDependencyList( IN long puid, OUT RETVAL VARIANT *pDependentItemsArray ) { return E_NOTIMPL; } STDMETHODIMP CCV3::GetCatalogItem( IN long puid, OUT RETVAL VARIANT *pCatalogItem ) { PINVENTORY_ITEM pItem; HRESULT hrRet = S_OK; if (!m_bValidInstance) { return E_ACCESSDENIED; } try { if (!g_v3state.GetCatalogAndItem(puid, &pItem, NULL)) hrRet = E_INVALIDARG; else hrRet = MakeReturnItemArray(pItem, pCatalogItem); } catch (HRESULT hr) { hrRet = hr; } return hrRet; } BOOL ConfirmUninstall(PINVENTORY_ITEM pItem) { USES_CONVERSION; PWU_VARIABLE_FIELD pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE); // // Prefix bug NTBUG9#114181 warning (25): bounds violation (overflow) using buffer 'szResStr' // TCHAR szResStr[512]; if (LoadString(_Module.GetModuleInstance(), IDS_UNINSTALLCHECK, szResStr, sizeof(szResStr)/sizeof(TCHAR)) == 0) { TRACE("Unable to get resource string for uninstall check"); return FALSE; } TCHAR szMsg[1024]; wsprintf(szMsg, szResStr, pvTitle ? W2T((LPWSTR)(pvTitle->pData)) : _T("")); DWORD dwMBFlags = MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_SETFOREGROUND; if (IsArabicOrHebrew()) dwMBFlags |= MB_RTLREADING | MB_RIGHT; if (MessageBox(GetActiveWindow(), szMsg, GetLocStr(IDS_APP_TITLE), dwMBFlags) != IDOK) { return FALSE; } return TRUE; } // confirms reboot, cleans up and reboot using a thread BOOL CleanupAndReboot() { TCHAR szBuf[512]; // NOTE: we assume that GetLocStr will not return strings that will overflow this buffer wsprintf(szBuf, _T("%s\n\n%s"), GetLocStr(IDS_REBOOT1), GetLocStr(IDS_REBOOT2)); // adadi Oct 6, 1999: arabic + hebrew hack // we need to add the RTL flag if we're running on loc, but not enabled BIDI systems // we don't want the dialog flipped with EN text on an enabled system DWORD dwMBFlags = MB_ICONQUESTION | MB_YESNO | MB_TASKMODAL | MB_SETFOREGROUND; if (IsArabicOrHebrew()) dwMBFlags |= MB_RTLREADING | MB_RIGHT; UINT id = MessageBox(GetActiveWindow(), szBuf, GetLocStr(IDS_APP_TITLE), dwMBFlags); if (id == IDNO) return FALSE; // cleanup g_v3state.Reset(); CConnSpeed::WriteToRegistry(); // create a thread to reboot DWORD dwThreadID; HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RebootThreadProc, NULL, 0, &dwThreadID); if (hThread != NULL) { // we close the handle because we don't need it. The thread will be destroyed after threadproc terminates CloseHandle(hThread); } return TRUE; } DWORD WINAPI RebootThreadProc(LPVOID pv) { // Wait for 1 second and reboot the system Sleep(1000); (void)V3_RebootSystem(); return 0; } STDMETHODIMP CCV3::RemoveSelectedItems() { USES_CONVERSION; PSELECTITEMINFO pInfo; PINVENTORY_ITEM pItem; PWU_VARIABLE_FIELD pvUninstall; if (!m_bValidInstance) { return E_ACCESSDENIED; } try { //we need the os type for any device driver installs. int iTotalItems = g_v3state.m_selectedItems.GetTotal(); HRESULT hr = NOERROR; g_v3state.m_bRebootNeeded = FALSE; pInfo = g_v3state.m_selectedItems.GetItems(); for (int i=0; irecordType == WU_TYPE_CDM_RECORD) { hr = UninstallDriverItem(pItem, &pInfo[i]); } else { pvUninstall = pItem->pd->pv->Find(WU_DESCRIPTION_UNINSTALL_KEY); if (pvUninstall != NULL) { // // its possible that uninstall will reboot. We have no way of knowing that // so we set the status initially to ITEM_STATUS_UNINSTALL_STARTED which // gets translated to "Started" entry in the log // pInfo[i].iStatus = ITEM_STATUS_UNINSTALL_STARTED; UpdateRemoveHistory(&pInfo[i], 1); hr = UninstallActiveSetupItem(A2T((LPSTR)pvUninstall->pData)); } else { hr = E_UNEXPECTED; } } if (SUCCEEDED(hr)) { pInfo[i].iStatus = ITEM_STATUS_SUCCESS; pInfo[i].hrError = NOERROR; pItem->ps->state = WU_ITEM_STATE_INSTALL; } else { pInfo[i].iStatus = ITEM_STATUS_INSTALLED_ERROR; pInfo[i].hrError = hr; //Fix #736: we leave the item state unchanged if the uninstall fails } pItem->ps->bChecked = FALSE; // // write history log for final status. We will write only the error case for active setup // items which have already written "Started". For drivers we do not write the "Started" // entry so we will write the history now for both success and failure // if (pItem->recordType == WU_TYPE_CDM_RECORD || pInfo[i].iStatus == ITEM_STATUS_INSTALLED_ERROR) { UpdateRemoveHistory(&pInfo[i], 1); } } } // // remove all items from m_selected // g_v3state.m_selectedItems.Clear(); // // reboot if an uninstall has indicated that we have to reboot // if (g_v3state.m_bRebootNeeded) { (void)CleanupAndReboot(); } g_v3state.m_bRebootNeeded = FALSE; } catch(HRESULT _hr) { g_v3state.m_bRebootNeeded = FALSE; return _hr; } return S_OK; } // // NOTE: This method is no longer supported. We simply return S_OK for compatibility. We will remove // this method // STDMETHODIMP CCV3::IsCatalogAvailable( IN long puidCatalog, //Name of catalog to be read from the server. IN BSTR bstrServerUrl //The http://servername/share location for the catalog to be retrieved. ) { HRESULT hr = S_OK; return hr; } STDMETHODIMP CCV3::FinalizeInstall(IN long lFlags) { if (!m_bValidInstance) { return E_ACCESSDENIED; } if (lFlags & FINALIZE_DOREBOOT) { if (g_v3state.m_bRebootNeeded) { (void)CleanupAndReboot(); } } g_v3state.m_bRebootNeeded = FALSE; return NOERROR; } STDMETHODIMP CCV3::SetStrings(IN VARIANT* vStringsArr, IN long lType) { if (!m_bValidInstance) { return E_ACCESSDENIED; } return SetStringsFromSafeArray(vStringsArr, lType); } STDMETHODIMP CCV3::FixCompatRollbackKey(VARIANT_BOOL *pbRegModified) { const TCHAR* pszIEVersionRegKey = _T("Software\\Microsoft\\Internet Explorer"); const TCHAR* pszIEUserAgentCompatKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\User Agent\\Post Platform"); const TCHAR* pszIEVersionRegValueName = _T("Version"); const TCHAR* pszIEUserAgentCompatValueName = _T("compat"); TCHAR szIEVersionValue[40]; DWORD dwDataType = 0; DWORD dwDataLength = sizeof(szIEVersionValue); HKEY IEVerKey = NULL; HKEY IEUserAgentKey = NULL; *pbRegModified = FALSE; if (!m_bValidInstance) { return E_ACCESSDENIED; } //check the version key first - we don't care what the UA string says unless we have rolled back to IE4 if(ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszIEVersionRegKey, 0, KEY_QUERY_VALUE, &IEVerKey)) { if(ERROR_SUCCESS == RegQueryValueEx(IEVerKey,pszIEVersionRegValueName,0,&dwDataType, (LPBYTE)szIEVersionValue,&dwDataLength)) { if (szIEVersionValue[0] == '4') //check whether the first character is "4" { if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,pszIEUserAgentCompatKey,0,KEY_SET_VALUE, &IEUserAgentKey)) { if(ERROR_SUCCESS == RegDeleteValue(IEUserAgentKey,pszIEUserAgentCompatValueName)) { *pbRegModified = TRUE; } RegCloseKey(IEUserAgentKey); } } else // otherwise, this is IE5 - we'll piggyback another reg change onto this function { UpdateToolsURL(); } } RegCloseKey(IEVerKey); } return S_OK; } void CCV3::UpdateToolsURL() { LOG_block("UpdateToolsURL"); const TCHAR DEFAULT_WU_URL[] = _T("http://windowsupdate.microsoft.com/"); const TCHAR WU_TOOLMENU_PARAM[] = _T("IE"); const TCHAR REGKEY_IE_URLS[] = _T("Software\\Microsoft\\Internet Explorer\\Help_Menu_Urls"); const TCHAR REGVALUENAME_WU_URL[] = _T("3"); const TCHAR REGKEY_WU_URL[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate"); const TCHAR REGVALUENAME_WU_Start_URL[] = _T("URL"); const TCHAR WU_STARTMENU_PARAM[] = _T("Start"); HKEY hkIEURLKey = 0; HKEY hkWUURLKey = 0; DWORD dwDisposition = REG_OPENED_EXISTING_KEY; TCHAR tszUpdateURL[INTERNET_MAX_URL_LENGTH] = _T("\0"); TCHAR tszStartMenuURL[INTERNET_MAX_URL_LENGTH] = _T("\0"); TCHAR tszNewStartMenuURL[INTERNET_MAX_URL_LENGTH] = _T("\0"); wsprintf( tszUpdateURL, _T("%s?%s"), DEFAULT_WU_URL, WU_TOOLMENU_PARAM ); if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_IE_URLS, 0, (LPTSTR)NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkIEURLKey, &dwDisposition ) ) { if( ERROR_SUCCESS == RegSetValueEx( hkIEURLKey, REGVALUENAME_WU_URL, 0, REG_SZ, (LPBYTE) tszUpdateURL, lstrlen(tszUpdateURL) * sizeof(TCHAR) ) ) { LOG_out("Updated Tools URL to %s", tszUpdateURL); } RegCloseKey( hkIEURLKey ); } //take the existing WU regkey and make sure it has "?Start" appended to it // this will misbehave in the following two cases: // 1) if the URL key exists but is invalid (such as spaces) - can only hapen if a user manually edits the key // 2) if the URL contains a fragment (# + parameter) // both of these will result in a start menu URL that is invalid. (the Start Menu link would be broken already if either of these cases existed) if (NO_ERROR == RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WU_URL, 0, (LPTSTR)NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE | KEY_READ, NULL, &hkWUURLKey, &dwDisposition )) { DWORD dwSize = sizeof(tszStartMenuURL); (void) RegQueryValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, 0, (LPBYTE)&tszStartMenuURL, &dwSize); if(0 != lstrcmp(tszStartMenuURL, _T(""))) // if the reg value isn't blank { LOG_out("Current Start Menu URL: %s", tszStartMenuURL); if( NULL == _tcsstr(tszStartMenuURL, _T("?"))) // if there isn't already a querystring on the URL, make the url currenturl?param { wsprintf(tszNewStartMenuURL, _T("%s?%s"), tszStartMenuURL, WU_STARTMENU_PARAM); RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR)); LOG_out("Updating Start Menu URL To %s", tszNewStartMenuURL); } else // if there's already a parameter { if(NULL != _tcsstr(tszStartMenuURL, WU_STARTMENU_PARAM))//if it already has "Start", bail { // do nothing } else//otherwise make the url currenturl?param&newparam { wsprintf(tszNewStartMenuURL, _T("%s&%s"), tszStartMenuURL, WU_STARTMENU_PARAM); RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR)); LOG_out("Updating Start Menu URL To %s", tszNewStartMenuURL); } } } else // if the reg value is blank, use the default WU URL + "?Start" { wsprintf(tszNewStartMenuURL, _T("%s?%s"), DEFAULT_WU_URL, WU_STARTMENU_PARAM); RegSetValueEx(hkWUURLKey, REGVALUENAME_WU_Start_URL, 0, REG_SZ, (LPBYTE)tszNewStartMenuURL, lstrlen(tszNewStartMenuURL) * sizeof(TCHAR)); LOG_out("Updated Start Menu URL to %s", tszNewStartMenuURL); } RegCloseKey(hkWUURLKey); } } // This function converts our internal V3 catalog structure into a safearray of variants // that the VBScript web page uses. The format of the safe array will be: // array(i,0) = NUMBER puid // array(i,1) = STRING TITLE // array(i,2) = STRING Description // array(i,3) = NUMBER Item Status // array(i,4) = NUMBER Download Size in Bytes // array(i,5) = NUMBER Download Time in seconds // array(i,6) = STRING Uninstall Key // array(i,7) = STRING Read This Url HRESULT CCV3::MakeReturnCatalogArray( CCatalog *pCatalog, //Pointer to catalog structure to be converted. long lFilters, //Filters to apply, see GetCatalog for the actual descriptions. long lFlags, //Flags that control the amount of information returned in each array record. VARIANT *pvaVariant //pointer to returned safearray. ) { USES_CONVERSION; PUID puid; PWSTR pTitle; PWSTR pDescription; PSTR pUninstall; PWSTR pReadThisUrl; HRESULT hr; LPVARIANT rgElems; LPSAFEARRAY psa; SAFEARRAYBOUND rgsabound[2]; PINVENTORY_ITEM pItem; PWU_VARIABLE_FIELD pv; PWU_VARIABLE_FIELD pvTitle; PWU_VARIABLE_FIELD pvDescription; PWU_VARIABLE_FIELD pvUninstall; PWU_VARIABLE_FIELD pvRTF; PWU_VARIABLE_FIELD pvAltName; int i; int t; int size; int downloadTime; TCHAR szRTF[MAX_PATH]; if ( !pvaVariant ) return E_INVALIDARG; VariantInit(pvaVariant); hr = NOERROR; rgsabound[0].lLbound = 0; rgsabound[0].cElements = 0; rgsabound[1].lLbound = 0; rgsabound[1].cElements = 8; // count number records to return for(i=0; iGetHeader()->totalItems; i++) { pItem = pCatalog->GetItem(i); if (NULL == pItem) { continue; } if ( !FilterCatalogItem(pItem, lFilters) ) continue; rgsabound[0].cElements++; } psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound); if (!psa) return E_OUTOFMEMORY; // plug references to the data into the SAFEARRAY if (FAILED(hr = SafeArrayAccessData(psa,(LPVOID*)&rgElems))) return hr; for(i = 0, t = 0; i < pCatalog->GetHeader()->totalItems; i++) { pItem = pCatalog->GetItem(i); if (NULL == pItem) { continue; } if (!FilterCatalogItem(pItem, lFilters)) { TRACE("Filtering (%d) skipped PUID %d while building SaveArray", lFilters, pItem->GetPuid()); continue; } if (!pItem->pd) { TRACE("PUID %d skipped while building SaveArray - no description", pItem->GetPuid()); continue; } size = pItem->pd->size; downloadTime = CalcDownloadTime(size, pItem->pd->downloadTime); pItem->GetFixedFieldInfo(WU_ITEM_PUID, (PVOID)&puid); if ( pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE) ) pTitle = (PWSTR)pvTitle->pData; else pTitle = _T(""); // SafeArray should return empty string, not NULL BSTR if (pvDescription = pItem->pd->pv->Find(WU_DESCRIPTION_DESCRIPTION)) pDescription = (PWSTR)pvDescription->pData; else pDescription = _T(""); // SafeArray should return empty string, not NULL BSTR // uninstall/altname field pUninstall = ""; // SafeArray should return empty string, not NULL BSTR if (pItem->recordType == WU_TYPE_CDM_RECORD) { //NOTE: we are simply returning a key that says script should put the uninstall button // currently we will always display this button but we will change this to only // display it when the driver can be uninstalled pUninstall = "DriverUninstall"; } else if (pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD) { if ((pvUninstall = pItem->pd->pv->Find(WU_DESCRIPTION_UNINSTALL_KEY))) { pUninstall = (char *)pvUninstall->pData; } } else { // for everything else, we pass the AltName field if provided if ((pvAltName = pItem->pd->pv->Find(WU_DESC_ALTNAME))) { pUninstall = (char *)pvAltName->pData; } } // read this first page if ((pvRTF = pItem->pd->pv->Find(WU_DESC_RTF_CRC_ARRAY))) { TCHAR szTemp[MAX_PATH]; GetWindowsUpdateDirectory(szTemp); wsprintf(szRTF, _T("file://%sRTF\\%d\\%d.htm"), szTemp, pItem->GetPuid(), pItem->GetPuid()); pReadThisUrl = szRTF; } else { pReadThisUrl = _T(""); // SafeArray should return empty string, not NULL BSTR } try { TRACE("PUID %d added to SaveArray with ReturnStatus %d", pItem->GetPuid(), GetItemReturnStatus(pItem)); /* // Noisy Debug Only TRACE("\t%S",pTitle); TRACE("\t%S", pDescription); TRACE("\t%d", GetItemReturnStatus(pItem)); TRACE("\t%d", size); TRACE("\t%d", downloadTime); TRACE("\t%s", pUninstall); TRACE("\t%s", pReadThisUrl); */ AddSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d%d%d%s%s", puid, pTitle, pDescription, GetItemReturnStatus(pItem), size, downloadTime, A2W(pUninstall), pReadThisUrl); t++; } catch(HRESULT hr) { TRACE("Exception thrown calling AddSafeArrayRecord"); for (; t; t--) DeleteSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d%d%d%s%s"); SafeArrayUnaccessData(psa); VariantInit(pvaVariant); throw hr; } } SafeArrayUnaccessData(psa); V_VT(pvaVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY(pvaVariant) = psa; return NOERROR; } // This function converts our internal V3 catalog structure for inventory.plt catalogs into a // safearray of variants that the VBScript web page uses. The format of the safe array will be: // array(i,0) = NUMBER puid // array(i,1) = STRING TITLE // array(i,2) = STRING Description // array(i,3) = NUMBER Item Status HRESULT CCV3::MakeReturnCatalogListArray( CCatalog *pCatalog, //Pointer to catalog structure to be converted. long lFilters, //Filters to apply, see GetCatalog for the actual descriptions. long lFlags, //Flags that control the amount of information returned in each array record. VARIANT *pvaVariant //pointer to returned safearray. ) { PUID puid; PWSTR pTitle; PWSTR pDescription; HRESULT hr; LPVARIANT rgElems; LPSAFEARRAY psa; SAFEARRAYBOUND rgsabound[2]; PINVENTORY_ITEM pItem; PWU_VARIABLE_FIELD pv; PWU_VARIABLE_FIELD pvTitle; PWU_VARIABLE_FIELD pvDescription; PWU_VARIABLE_FIELD pvUninstall; int i; int t; int size; int downloadTime; if ( !pvaVariant ) return E_INVALIDARG; VariantInit(pvaVariant); hr = NOERROR; rgsabound[0].lLbound = 0; rgsabound[0].cElements = 0; rgsabound[1].lLbound = 0; rgsabound[1].cElements = 4; // count number records to return for(i=0; iGetHeader()->totalItems; i++) { if (NULL == (pItem = pCatalog->GetItem(i))) { continue; } if ( !FilterCatalogItem(pItem, lFilters) ) continue; rgsabound[0].cElements++; } psa = SafeArrayCreate(VT_VARIANT, 2, rgsabound); if ( !psa ) return E_OUTOFMEMORY; // plug references to the data into the SAFEARRAY if (FAILED(hr = SafeArrayAccessData(psa,(LPVOID*)&rgElems))) return hr; for(i=0,t=0; iGetHeader()->totalItems; i++) { if (NULL == (pItem = pCatalog->GetItem(i))) { continue; } if ( !FilterCatalogItem(pItem, lFilters) ) continue; //array(i,0) = NUMBER puid //array(i,1) = STRING TITLE //array(i,2) = STRING Description //array(i,3) = NUMBER Item Status pItem->GetFixedFieldInfo(WU_ITEM_PUID, (PVOID)&puid); if ( pvTitle = pItem->pd->pv->Find(WU_DESCRIPTION_TITLE) ) pTitle = (PWSTR)pvTitle->pData; else pTitle = _T(""); // SafeArray should return empty string, not NULL BSTR if ( pvDescription = pItem->pd->pv->Find(WU_DESCRIPTION_DESCRIPTION) ) pDescription = (PWSTR)pvDescription->pData; else pDescription = _T(""); // SafeArray should return empty string, not NULL BSTR try { AddSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d", puid, pTitle, pDescription, GetItemReturnStatus(pItem)); t++; } catch(HRESULT hr) { for (; t; t--) DeleteSafeArrayRecord(rgElems, t, (int)rgsabound[0].cElements, "%d%s%s%d"); SafeArrayUnaccessData(psa); VariantInit(pvaVariant); throw hr; } } SafeArrayUnaccessData(psa); V_VT(pvaVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY(pvaVariant) = psa; return NOERROR; } void DetectActiveSetupWU( CWUDownload* pDownload, // CWUDLOAD download class to be used to download detection DLLs. CDiamond* pDiamond, // Diamond Expansion class. CCatalog* pCatalog // catalog that detection CIF is to be created from. ) { USES_CONVERSION; int cItemsDetected = 0; PWU_VARIABLE_FIELD pVar; DWORD dwDetectStatus; CComponentDetection CompDet; LOG_block("DetectActiveSetupWU"); //check input argument if valid if (NULL == pCatalog) { return ; } for (int i = 0; i < pCatalog->GetHeader()->totalItems; i++) { PINVENTORY_ITEM pItem = pCatalog->GetItem(i); //check if the function GetItem has returned valid value if (NULL == pItem) { continue; } if (pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD || (pItem->ps->state == WU_ITEM_STATE_PRUNED)) continue; if (!IsValidGuid(&pItem->pf->a.g)) continue; WCHAR wszGuid[64]; if (StringFromGUID2(pItem->pf->a.g, wszGuid, sizeof(wszGuid)/sizeof(wszGuid[0])) == 0) continue; PUID puid = pItem->GetPuid(); LOG_out("puid %d", puid); if (puid <= 0) { continue; } // // we have a valid component to detect // cItemsDetected++; // guid CompDet.SetValue(CComponentDetection::ccGUID, W2A(wszGuid)); // version char szVersion[64]; VersionToString(&pItem->pf->a.version, szVersion); CompDet.SetValue(CComponentDetection::ccVersion, szVersion); // // detection dll variable fields // char szDllName[128]; szDllName[0] = '\0'; if (pItem->pv->Find(WU_DETECT_DLL_REG_KEY_EXISTS)) { // WUDETECT.DLL,RegKeyExists special case CompDet.SetValue(CComponentDetection::ccDetectVersion, "wudetect.dll,RegKeyExists"); strcpy(szDllName, "wudetect.bin"); } if ((pVar = pItem->pv->Find(WU_DETECT_DLL_GENERIC))) { LPSTR ptr; // generic detection DLL including WUDETECT.DLL,RegKeyVersion case CompDet.SetValue(CComponentDetection::ccDetectVersion, (LPCSTR)pVar->pData); // parse out detection dll name from DetectVersion= value if ((ptr = (PSTR)_memccpy(szDllName, (char *)pVar->pData, '.', sizeof(szDllName)))) { *(ptr - 1) = 0; } strcat(szDllName, ".bin"); } // // download the dll. Download DLL takes care of caching // if (szDllName[0] != '\0') { TCHAR szPath[MAX_PATH]; // construct full path for the detection dll wsprintf(szPath, _T("Detect/%d/%s"), pCatalog->GetPlatform(), A2T(szDllName)); DownloadDLL(pDiamond, pDownload, A2T(szDllName), szPath); } // // other variable length fields // if ((pVar = pItem->pv->Find(WU_KEY_CUSTOMDETECT))) { // custom data CompDet.SetValue(CComponentDetection::ccCustomData, (LPCSTR)pVar->pData); } if ((pVar = pItem->pv->Find(WU_KEY_UNINSTALLKEY))) { // UninstallKey, remove quotes first char szKeyVal[MAX_PATH]; LPCSTR pszKeyDat = (LPCSTR)pVar->pData; if (pszKeyDat[0] == '"') { strcpy(szKeyVal, (pszKeyDat + 1)); int iKenLen = strlen(szKeyVal); if (iKenLen > 0) szKeyVal[iKenLen - 1] = '\0'; } else { strcpy(szKeyVal, pszKeyDat); } CompDet.SetValue(CComponentDetection::ccUninstallKey, szKeyVal); } // locale if (!(pVar = pItem->pv->Find(WU_DET_CIF_LOCALE))) { CompDet.SetValue(CComponentDetection::ccLocale, "*"); } else { CompDet.SetValue(CComponentDetection::ccLocale, (LPCSTR)pVar->pData); } /* DEBUG CODE ONLY LOG_out("[%d]", pItem->GetPuid()); char buf[512]; if (CompDet.GetValue(CComponentDetection::ccGUID, buf, sizeof(buf))) LOG_out("%s=%s", "GUID", buf); if (CompDet.GetValue(CComponentDetection::ccVersion, buf, sizeof(buf))) LOG_out("%s=%s", "Version", buf); if (CompDet.GetValue(CComponentDetection::ccUninstallKey , buf, sizeof(buf))) LOG_out("%s=%s", "UninstallKey", buf); if (CompDet.GetValue(CComponentDetection::ccDetectVersion, buf, sizeof(buf))) LOG_out("%s=%s", "DetectVersion", buf); if (CompDet.GetValue(CComponentDetection::ccRegKeyVersion , buf, sizeof(buf))) LOG_out("%s=%s", "RegKeyVersion", buf); if (CompDet.GetValue(CComponentDetection::ccLocale , buf, sizeof(buf))) LOG_out("%s=%s", "Locale", buf); if (CompDet.GetValue(CComponentDetection::ccQFEVersion , buf, sizeof(buf))) LOG_out("%s=%s", "QFEVersion", buf); if (CompDet.GetValue(CComponentDetection::ccCustomData , buf, sizeof(buf))) LOG_out("%s=%s", "CustomData", buf); */ // // now detect the item // dwDetectStatus = CompDet.Detect(); switch (dwDetectStatus) { case ICI_NOTINSTALLED: // 0 = item not installed(INSTALL) pItem->ps->state = WU_ITEM_STATE_INSTALL; LOG_out("puid %d not installed", pItem->GetPuid()); break; case ICI_INSTALLED: // 1 = this item is curretly installed pItem->ps->state = WU_ITEM_STATE_CURRENT; LOG_out("puid %d installed current version", pItem->GetPuid()); break; case ICI_NEWVERSIONAVAILABLE: // 2 Items is installed but newer available pItem->ps->state = WU_ITEM_STATE_UPDATE; { // we want to save currently installed version DWORD dwInstalledVer; DWORD dwInstalledBuild; CompDet.GetInstalledVersion(&dwInstalledVer, &dwInstalledBuild); pItem->ps->verInstalled.major = HIWORD(dwInstalledVer); pItem->ps->verInstalled.minor = LOWORD(dwInstalledVer); pItem->ps->verInstalled.build = HIWORD(dwInstalledBuild); pItem->ps->verInstalled.ext = LOWORD(dwInstalledBuild); LOG_out("puid %d installed version %d.%d.%d.%d and new version available ", pItem->GetPuid(), pItem->ps->verInstalled.major, pItem->ps->verInstalled.minor, pItem->ps->verInstalled.build, pItem->ps->verInstalled.ext); } break; case ICI_UNKNOWN: // 3 cannot be determined case ICI_OLDVERSIONAVAILABLE: // 4 Why would anyone want to install the older version? case ICI_NOTINITIALIZED: // 0xffffffff default: pItem->ps->bHidden = TRUE; pItem->ps->state = WU_ITEM_STATE_PRUNED; LOG_out("puid %d should be ignored and hidden", pItem->GetPuid()); break; } } // each item LOG_out("%d items were detected", cItemsDetected); } void DownloadItem( LPCTSTR pszLocalDir, //directory to download to. Must be created by caller CWUDownload* pDownload, //Pointer to internet download class CDiamond* pDiamond, //Pointer to compression class PINSTALLINFOSTRUCT pInstallInfo, //Pointer to installation information structure. IWUProgress* pProgress ) { USES_CONVERSION; BYTE itemFlags = 0; BOOL bCloseConnection = FALSE; DWORD platformId; HRESULT hrError; PWU_VARIABLE_FIELD pvCabs = NULL; PWU_VARIABLE_FIELD pvCRCs = NULL; PWU_VARIABLE_FIELD pvServer; PWU_VARIABLE_FIELD pvTmp; TCHAR szLocale[64]; BOOL b128Bit; //Check if the input argument is not NULL if ( (NULL == pInstallInfo) || (NULL == pInstallInfo->pItem) ) { return ; } //See if the package has a server override defined. if ((pvServer = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_SERVERROOT))) { pDownload = new CWUDownload((LPCTSTR)pvServer->pData); bCloseConnection = TRUE; } try { if (pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_TITLE)) { // if the item is hidden, look for the title in the TopLevel item if (pInstallInfo->pItem->ps->bHidden && (pInstallInfo->pTopLevelItem != NULL) && (pInstallInfo->pTopLevelItem->pd != NULL)) { PWU_VARIABLE_FIELD pvTopLvl = pInstallInfo->pTopLevelItem->pd->pv->Find(WU_DESCRIPTION_TITLE); if (pvTopLvl) { pvTmp = pvTopLvl; } } pProgress->SetStatusText(W2T((LPWSTR)(pvTmp->pData))); } // // Calculate CIF path // pInstallInfo->pItem->GetFixedFieldInfo(WU_ITEM_FLAGS, &itemFlags); // locale if (pInstallInfo->dwLocaleID == 0) { if (itemFlags & WU_BROWSER_LANGAUGE_FLAG) { lstrcpy(szLocale, pInstallInfo->pCatalog->GetBrowserLocaleSZ()); } else { wsprintf(szLocale, _T("0x%8.8x"), GetMachineLangDW()); } } else { wsprintf(szLocale, _T("0x%8.8x"), pInstallInfo->dwLocaleID); } // platform if (pInstallInfo->dwPlatform == 0) platformId = pInstallInfo->pCatalog->GetPlatform(); else platformId = pInstallInfo->dwPlatform; pInstallInfo->pInfo->iStatus = ITEM_STATUS_DOWNLOAD_COMPLETE; pInstallInfo->pInfo->hrError = NOERROR; // // download files // if (pInstallInfo->pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD || pInstallInfo->pItem->recordType == WU_TYPE_CDM_RECORD || pInstallInfo->pItem->recordType == WU_TYPE_RECORD_TYPE_PRINTER) { b128Bit = FALSE; if (pInstallInfo->pItem->recordType == WU_TYPE_ACTIVE_SETUP_RECORD) { //download CIF DownloadCif(pszLocalDir, pDiamond, pInstallInfo); // check for 128 bit if ((pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESC_128BIT_PRODID))) { b128Bit = TRUE; } } if (b128Bit) { // download 128 bit components Download128Bit(pszLocalDir, pInstallInfo->pItem, pProgress); } else { // download install CABs pvCabs = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_CABFILENAME); pvCRCs = pInstallInfo->pItem->pd->pv->Find(WU_DESC_CRC_ARRAY); if (NULL == pvCabs || NULL == pvCRCs) { // Active setup items can have no cabs if( pInstallInfo->pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD) throw HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } else { DownloadCabs(pszLocalDir, pDownload, pDiamond, (PBYTE)pvCabs->pData, (PBYTE)pvCRCs->pData, pProgress, pInstallInfo->pItem->recordType != WU_TYPE_ACTIVE_SETUP_RECORD); } } } else { throw E_UNEXPECTED; } } catch(HRESULT hr) { // // download failed // pInstallInfo->pInfo->hrError = hr; pInstallInfo->pInfo->iStatus = ITEM_STATUS_FAILED; if (bCloseConnection) { delete pDownload; } // // ping URL to report failure // if (pInstallInfo->pTopLevelItem == NULL) { // for top level components only URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pInstallInfo->pInfo, (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) ? URLPING_CANCELED : URLPING_FAILED); } throw hr; } if (bCloseConnection) { delete pDownload; } // // ping URL to report success // if (pInstallInfo->pTopLevelItem == NULL) { URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pInstallInfo->pInfo, URLPING_SUCCESS); } } // this function perform and installation of a catalog item. This function takes care // of ensuring that the correct installer is called based on the package type. void InstallItem( LPCTSTR pszLocalDir, //Local client machine root directory the temp storage PSELECTITEMINFO pStatusInfo, //Pointer to installation status array PINSTALLINFOSTRUCT pInstallInfo, //Pointer to installation information structure. IWUProgress* pProgress ) { HRESULT hrError; PWU_VARIABLE_FIELD pvTitle; PWU_VARIABLE_FIELD pvTmp; TCHAR szCIFFile[MAX_PATH]; BOOL bWindowsNT; //check the input arguments if (NULL == pszLocalDir || NULL == pStatusInfo || NULL == pInstallInfo) { return; } bWindowsNT = IsWindowsNT(); try { if (pvTitle = pInstallInfo->pItem->pd->pv->Find(WU_DESCRIPTION_TITLE)) { // if the item is hidden, look for the title in the TopLevel item if (pInstallInfo->pItem->ps->bHidden && (pInstallInfo->pTopLevelItem != NULL) && (pInstallInfo->pTopLevelItem->pd != NULL)) { PWU_VARIABLE_FIELD pvTopLvl = pInstallInfo->pTopLevelItem->pd->pv->Find(WU_DESCRIPTION_TITLE); if (pvTopLvl) { pvTitle = pvTopLvl; } } pProgress->SetStatusText(W2T((LPWSTR)(pvTitle->pData))); } GetCurTime(&(pStatusInfo->stDateTime)); pStatusInfo->iStatus = ITEM_STATUS_SUCCESS; pStatusInfo->hrError = NOERROR; TRACE("InstallItem, puid=%d, recordtype: %d", pInstallInfo->pItem->GetPuid(), (DWORD)pInstallInfo->pItem->recordType); switch (pInstallInfo->pItem->recordType) { case WU_TYPE_ACTIVE_SETUP_RECORD: BLOCK { TCHAR szCifBaseName[16]; wsprintf(szCifBaseName, _T("%d.cif"), pInstallInfo->pItem->GetPuid()); GetWindowsUpdateDirectory(szCIFFile); lstrcat(szCIFFile, szCifBaseName); } // // check to see if inseng is up to date (only done once) // CheckDllsToJit(pInstallInfo->pCatalog->GetCatalogServer()); // // install active setup item // if ((pvTmp = pInstallInfo->pItem->pd->pv->Find(WU_DESC_128BIT_PRODID))) { // 128 bit TCHAR szCmd[MAX_PATH]; long lRet; lstrcpy(szCmd, pszLocalDir); AddBackSlash(szCmd); lstrcat(szCmd, EXENAME_128BIT); lRet = LaunchProcess(szCmd, NULL, SW_NORMAL, TRUE); } else { InstallActiveSetupItem(pszLocalDir, szCIFFile, pStatusInfo, pProgress); } // delete CIF file DeleteFile(szCIFFile); break; case WU_TYPE_CDM_RECORD: InstallDriverItem(pszLocalDir, bWindowsNT, pvTitle ? W2T((LPWSTR)(pvTitle->pData)) : _T(""), pInstallInfo->pItem, pStatusInfo); break; case WU_TYPE_RECORD_TYPE_PRINTER: { PWU_VARIABLE_FIELD pvDriverName = pInstallInfo->pItem->pv->Find(WU_CDM_DRIVER_NAME); PWU_VARIABLE_FIELD pvArchitecture = pInstallInfo->pItem->pv->Find(WU_CDM_PRINTER_DRIVER_ARCH); if (NULL == pvDriverName) throw E_UNEXPECTED; // should never happen InstallPrinterItem((LPCTSTR)pvDriverName->pData, pszLocalDir, NULL == pvArchitecture ? NULL : (LPCTSTR)pvArchitecture->pData); } break; case WU_TYPE_CDM_RECORD_PLACE_HOLDER: case WU_TYPE_SECTION_RECORD: case WU_TYPE_SUBSECTION_RECORD: case WU_TYPE_SUBSUBSECTION_RECORD: default: throw E_UNEXPECTED; } if(ITEM_STATUS_FAILED == pStatusInfo->iStatus) { URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_FAILED); } else { URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_SUCCESS); } } catch(HRESULT hr) { pStatusInfo->hrError = hr; pStatusInfo->iStatus = ITEM_STATUS_FAILED; URLPingReport(pInstallInfo->pItem, pInstallInfo->pCatalog, pStatusInfo, URLPING_INSTALL_FAILED); } } // // Download128Bit // this shouldn't get called anymore since the US lifted export restrictions on 128 bit items: // we don't create items with the 128 bit flag anymore // void Download128Bit(LPCTSTR pszLocalDir, PINVENTORY_ITEM pItem, IWUProgress* pProgress) { USES_CONVERSION; static const TCHAR FAILUREURL[] = _T("about:blank"); static const TCHAR FORMDATA[] = _T("selProdID=%s&Next=Download+Now%%21&failureURL=%s"); CWUDownload* pDL = NULL; TCHAR szFormData[MAX_PATH]; TCHAR szLocalFile[MAX_PATH]; PWU_VARIABLE_FIELD pvTmp; DWORD dwErr = ERROR_SUCCESS; // get product id if (!(pvTmp = pItem->pd->pv->Find(WU_DESC_128BIT_PRODID))) throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // build form data wsprintf(szFormData, FORMDATA, A2T((LPSTR)pvTmp->pData), FAILUREURL); // get URL if (!(pvTmp = pItem->pd->pv->Find(WU_DESC_128BIT_URL))) throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // build local file name lstrcpy(szLocalFile, pszLocalDir); AddBackSlash(szLocalFile); lstrcat(szLocalFile, EXENAME_128BIT); // create download class pDL = new CWUDownload(A2T((LPSTR)pvTmp->pData), 8192); if (!pDL) { dwErr = GetLastError(); throw HRESULT_FROM_WIN32(dwErr); } if (!pDL->PostCopy(szFormData, szLocalFile, pProgress)) { dwErr = GetLastError(); } delete pDL; if (dwErr != ERROR_SUCCESS) throw HRESULT_FROM_WIN32(dwErr); } void DownloadCabs( LPCTSTR szLocalDir, //Local client machine directory to use for temp storage CWUDownload *pDownload, //Pointer to internet download class CDiamond *pDiamond, //Pointer to compression class PBYTE pCabList, //Multi SZ list of cabs to be downloaded. PBYTE pCRCList, //array to CRC hash structures IWUProgress* pProgress, BOOL bUnCab ) { TCHAR szLocalFile[MAX_PATH]; TCHAR szServerFile[MAX_PATH]; TCHAR szLocalCab[128]; TCHAR szServerCab[128]; int iCabNo = 0; V3_CreateDirectory(szLocalDir); for (;;) { if (FAILED(GetCRCNameFromList(iCabNo, pCabList, pCRCList, szServerCab, sizeof(szServerCab), szLocalCab))) break; // build full paths lstrcpy(szLocalFile, szLocalDir); AddBackSlash(szLocalFile); lstrcat(szLocalFile, szLocalCab); lstrcpy(szServerFile, _T("CabPool/")); lstrcat(szServerFile, szServerCab); TRACE("Downloading %s", szServerFile); if (!pDownload->Copy(szServerFile, szLocalFile, NULL, NULL, 0, pProgress)) { TRACE("Download of cab %s failed", szServerFile); throw HRESULT_FROM_WIN32(GetLastError()); } // // check signature of the download CAB file // Don't show an MS cert // use VerifyFile (see WU bug # 12251) // HRESULT hr = VerifyFile(szLocalFile, TRUE); TRACE("VerifyFile(%s) Result: %x (%s)", szLocalFile, hr, SUCCEEDED(hr) ? "SUCCESS" : "FAILURE"); if (FAILED(hr)) throw hr; if (bUnCab) { if (pDiamond->IsValidCAB(szLocalFile)) { TCHAR szUnCompFn[MAX_PATH]; lstrcpy(szUnCompFn, szLocalDir); AddBackSlash(szUnCompFn); lstrcat(szUnCompFn, _T("*")); pDiamond->Decompress(szLocalFile, szUnCompFn); // // delete the CAB file after uncompressing // DeleteFile(szLocalFile); } } iCabNo++; } } void DownloadCif( LPCTSTR szLocalDir, // Local client machine directory to use for temp storage CDiamond *pDiamond, // Pointer to compression class PINSTALLINFOSTRUCT pInstallInfo ) { V3_CreateDirectory(szLocalDir); PWU_VARIABLE_FIELD pvCif = pInstallInfo->pItem->pd->pv->Find(WU_DESC_CIF_CRC); if (!pvCif) { TRACE("CIF CRC field missing"); throw HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } TCHAR szCifBaseName[16]; wsprintf(szCifBaseName, _T("%d.cif"), pInstallInfo->pItem->GetPuid()); TCHAR szCifCRCName[64]; HRESULT hr = MakeCRCName(szCifBaseName, (WUCRC_HASH*)pvCif->pData, szCifCRCName, sizeof(szCifCRCName)); if (FAILED(hr)) throw hr; // create a temp file name for the .CIF file with .CI$ TCHAR szLocalFile[MAX_PATH]; TCHAR szServerFile[MAX_PATH]; lstrcpy(szLocalFile, szLocalDir); AddBackSlash(szLocalFile); lstrcat(szLocalFile, szCifBaseName); LPTSTR pszDot = _tcschr(szLocalFile, _T('.')); if (pszDot) *pszDot = _T('\0'); lstrcat(szLocalFile, _T(".CI$")); // server file name wsprintf(szServerFile, _T("CRCCif/%s"), szCifCRCName); if (!pInstallInfo->pdlRoot->Copy(szServerFile, szLocalFile, NULL, NULL, 0, NULL)) { TRACE("Download of CIF cab %s failed", szServerFile); throw HRESULT_FROM_WIN32(GetLastError()); } // copy or uncompress to a .CIF file name TCHAR szTemp[MAX_PATH]; GetWindowsUpdateDirectory(szTemp); lstrcat(szTemp, szCifBaseName); if (pDiamond->IsValidCAB(szLocalFile)) { pDiamond->Decompress(szLocalFile, szTemp); } else { CopyFile(szLocalFile, szTemp, FALSE); } // NOTE:we don't delete the .CI$ file because all the files in the directory get deleted later } // download and save the FileVer.ini file in the cache // // NOTE: For 3.1 filever.ini file contains image download information as well void DownloadFileVerInfo(CWUDownload* pDownload) { // if the file is missing, we don't have version information but we do not abort (void)pDownload->Copy(FILEVERINI_FN, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY, NULL); } void DownloadDLL(CDiamond *pDiamond, CWUDownload *pDownload, LPCTSTR pszDLLName, LPCTSTR pszPath) { // // check our state detection dlls array to see if we downloaded // this dll in this session already // // NOTE: We store the file name of the DLL as it is on the server OSDET.W98, wudetect.bin etc // TCHAR szDLLIn[MAX_PATH]; GetWindowsUpdateDirectory(szDLLIn); lstrcat(szDLLIn, pszDLLName); TCHAR szDLLOut[MAX_PATH]; lstrcpy(szDLLOut, szDLLIn); TCHAR* ptr = _tcschr(szDLLOut, _T('.')); if (ptr) *ptr = 0; lstrcat(szDLLOut, _T(".dll")); if (g_v3state.CacheDLLName(pszDLLName)) { //added by wei for test TRACE("%s found in state cache", pszDLLName); // doublecheck to make sure the DLL hasn't been deleted before we bail if (FileExists(szDLLOut)) { return; } } // // download the file // if (pszPath != NULL) { if (!pDownload->Copy(pszPath, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL)) throw HRESULT_FROM_WIN32(GetLastError()); } else { if (!pDownload->Copy(pszDLLName, NULL, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY, NULL)) throw HRESULT_FROM_WIN32(GetLastError()); } CConnSpeed::Learn(pDownload->GetCopySize(), pDownload->GetCopyTime()); // // check to see if we download the file or the cached copy was used. If cache was used // we just check to see if the DLL itself also exists, if yes then we return otherwise we // will copy the or decompress the compressed file into the DLL // if (pDownload->CacheUsed()) { if (FileExists(szDLLOut)) return; } if (pDiamond->IsValidCAB(szDLLIn)) pDiamond->Decompress(szDLLIn, szDLLOut); else CopyFile(szDLLIn, szDLLOut, FALSE); } void DetectPlatAndLang() { TCHAR szOSDETDLL[MAX_PATH]; GetWindowsUpdateDirectory(szOSDETDLL); lstrcat(szOSDETDLL, _T("osdet.dll")); // // do platform and langauge detection using Osdet // CallOsDet(szOSDETDLL, &g_v3state.m_pdwPlatformList, &g_v3state.m_iTotalPlatforms); //If we fail for any reason then use the default platform def_plat. if ( !g_v3state.m_pdwPlatformList ) { g_v3state.m_pdwPlatformList = (PULONG)&g_v3state.m_DefPlat; g_v3state.m_iTotalPlatforms = 1; } } // // IObjectSafety // STDMETHODIMP CCV3::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) { if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL) return E_POINTER; HRESULT hr = S_OK; if (riid == IID_IDispatch) { *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER; *pdwEnabledOptions = m_dwSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER; } else { *pdwSupportedOptions = 0; *pdwEnabledOptions = 0; hr = E_NOINTERFACE; } return hr; } STDMETHODIMP CCV3::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) { // If we're being asked to set our safe for scripting option then oblige if (riid == IID_IDispatch) { // Store our current safety level to return in GetInterfaceSafetyOptions m_dwSafety = dwEnabledOptions & dwOptionSetMask; return S_OK; } return E_NOINTERFACE; } // // IWUpdateCatalog interface // STDMETHODIMP CCV3::WUIsCatalogAvailable(long puidCatalog,BSTR bstrServerUrl) { return IsCatalogAvailable(puidCatalog, bstrServerUrl); } STDMETHODIMP CCV3::WUGetCatalog(long puidCatalog, BSTR bstrServerUrl, long platformId, BSTR bstrBrowserLanguage, CCatalog** ppCatalogArray) { // we don't want to check the launch server from this interface m_bLaunchServChecked = TRUE; *ppCatalogArray = ProcessCatalog(puidCatalog, bstrServerUrl, platformId, bstrBrowserLanguage, WU_ALL_ITEMS, WU_NO_PRUNING); return S_OK; } STDMETHODIMP CCV3::WUDownloadItems(CSelections* pSelections, BSTR bstrServer, BSTR bstrTempDir) { return E_NOTIMPL; } STDMETHODIMP CCV3::WUInstallItems(CSelections* pSelections, BSTR bstrServer, BSTR bstrTempDir) { return E_NOTIMPL; } STDMETHODIMP CCV3::WURemoveItems(CSelections* pSelections) { return E_NOTIMPL; } STDMETHODIMP CCV3::WUCopyInstallHistory(HISTORYARRAY** ppHistoryArray) { int iTotalItems; Varray History; PHISTORYARRAY pRetArray; //Walk though item array for each install item. Each item selected for installation //is store in a puid array that is part of the g_v3state class. This is a performance //enhancement. If we did not do this then we would need to walk through the entire //state structure for each catalog for every item and check it's installation state. ReadHistory(History, iTotalItems); //Since we must use the OLE allocator we now need to allocate the correct //type of return memory and copy the existing history structure to it. pRetArray = (PHISTORYARRAY)CoTaskMemAlloc(sizeof(HISTORYARRAY)+(iTotalItems * sizeof(HISTORYSTRUCT))); if (NULL == pRetArray) { return HRESULT_FROM_WIN32(GetLastError()); } pRetArray->iTotalItems = iTotalItems; memcpy((char *)pRetArray->HistoryItems, &History[0], (iTotalItems * sizeof(HISTORYSTRUCT))); *ppHistoryArray = pRetArray; return S_OK; } STDMETHODIMP CCV3::WUCopyDependencyList(long puidItem, long** ppDepPui) { return E_NOTIMPL; } STDMETHODIMP CCV3::WUProgressDlg(BOOL bOn) { return E_NOTIMPL; } STDMETHODIMP CCV3::IsWinUpdDisabled(VARIANT_BOOL * pfDisabled) { *pfDisabled = FALSE; if (!m_bValidInstance) { return E_ACCESSDENIED; } bool fDisabled = false; HKEY hKey; DWORD dwDisabled; DWORD dwSize = sizeof(dwDisabled); DWORD dwType; HKEY hkeyRoot = IsWindowsNT() ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; if ( RegOpenKeyEx( hkeyRoot, REGPATH_EXPLORER, NULL, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS ) { if ( RegQueryValueEx(hKey, REGKEY_WINUPD_DISABLED, NULL, &dwType, (LPBYTE)&dwDisabled, &dwSize) == ERROR_SUCCESS ) { if ( (dwType == REG_DWORD) && (dwDisabled != 0) ) { *pfDisabled = TRUE; } } RegCloseKey(hKey); } return S_OK; } STDMETHODIMP CCV3::IsReady(VARIANT_BOOL* pbYes) { *pbYes = TRUE; return S_OK; } STDMETHODIMP CCV3::GetContentURL(OUT RETVAL VARIANT* pURL) { USES_CONVERSION; VariantInit(pURL); V_VT(pURL) = VT_BSTR; pURL->bstrVal = SysAllocString(T2OLE((LPTSTR)g_v3state.GetContentServer())); return S_OK; } // downloads the readthis first page and images for the puid locally // script can then navigate to this page STDMETHODIMP CCV3::GetReadThisPage(IN long puid) { CCatalog* pCatalog; PINVENTORY_ITEM pItem; if (!m_bValidInstance) { // the control is not launched from a trusted location return E_ACCESSDENIED; } if (!g_v3state.GetCatalogAndItem(puid, &pItem, &pCatalog)) { return E_INVALIDARG; } return DownloadReadThis(pItem); } STDMETHODIMP CCV3::GetPrintAllPage(OUT RETVAL VARIANT* pURL) { USES_CONVERSION; const char READTHISLIST[] = "%READTHISLIST%"; // a semi-colon separated list of read this pages. For instance "readthis1.htm;readthis2.htm;readthis3.htm" const char READTHISPATH[] = "%READTHISPATH%"; // the URL to the read this pages. For instance "file://d:\windowsupdate\" TCHAR szSourceFile[MAX_PATH]; HRESULT hr; DWORD dwFileSize = 0; PBYTE pFileBuf = NULL; HANDLE hFile; DWORD dwBytes; LPTSTR pszReadThisList = NULL; if (!m_bValidInstance) { // the control is not launched from a trusted location return E_ACCESSDENIED; } // download the printall page GetWindowsUpdateDirectory(szSourceFile); lstrcat(szSourceFile, _T("RTF")); V3_CreateDirectory(szSourceFile); hr = DownloadCommonRTFFiles(TRUE, szSourceFile); if (FAILED(hr)) { return hr; } // build a list of readthis first page names for all selected items PSELECTITEMINFO pSel = g_v3state.m_selectedItems.GetItems(); int cSel = g_v3state.m_selectedItems.GetTotal(); if (cSel == 0) { // no items are selected return S_OK; } // allocate enough memory for names of format puid\puid.htm; pszReadThisList = (LPTSTR)malloc(cSel * 80); if(!pszReadThisList) { return E_OUTOFMEMORY; } pszReadThisList[0] = _T('\0'); for (int iSel = 0; iSel < cSel; iSel++) { CCatalog* pCatalog; PINVENTORY_ITEM pItem; if (g_v3state.GetCatalogAndItem(pSel[iSel].puid, &pItem, &pCatalog)) { if SUCCEEDED(DownloadReadThis(pItem)) { TCHAR szTemp[24]; wsprintf(szTemp, _T("%d\\%d.htm"), pItem->GetPuid(), pItem->GetPuid()); if (pszReadThisList[0] != _T('\0')) { lstrcat(pszReadThisList, _T(";")); } lstrcat(pszReadThisList, szTemp); } } } //for if (pszReadThisList[0] == _T('\0')) { // no items selected with readthisfirst pages free(pszReadThisList); return S_OK; } // read the file in memory with a null appended at the end hFile = CreateFile(szSourceFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { dwFileSize = GetFileSize(hFile, NULL); if (dwFileSize > 0) { pFileBuf = (PBYTE)malloc(dwFileSize + 1); if (pFileBuf != NULL) { if (!ReadFile(hFile, pFileBuf, dwFileSize, &dwBytes, NULL)) { free(pFileBuf); pFileBuf = NULL; dwFileSize = 0; } pFileBuf[dwFileSize] = 0; } } CloseHandle(hFile); } if (pFileBuf != NULL) { LPSTR pNewBuf; TCHAR szDest[MAX_PATH]; GetWindowsUpdateDirectory(szDest); lstrcat(szDest, _T("RTF\\")); // replace tokens if (ReplaceSingleToken(&pNewBuf, (LPSTR)pFileBuf, READTHISLIST, T2A(pszReadThisList))) { free(pFileBuf); pFileBuf = (PBYTE)pNewBuf; } if (ReplaceSingleToken(&pNewBuf, (LPSTR)pFileBuf, READTHISPATH, T2A(szDest))) { free(pFileBuf); pFileBuf = (PBYTE)pNewBuf; } // create the directory lstrcat(szDest, _T("0\\")); V3_CreateDirectory(szDest); // write out the file lstrcat(szDest, _T("printall.htm")); hFile = CreateFile(szDest, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL); if (hFile != INVALID_HANDLE_VALUE) { if (!WriteFile(hFile, pFileBuf, strlen((LPSTR)pFileBuf), &dwBytes, NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); } CloseHandle(hFile); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } free(pFileBuf); // return the path TCHAR szRTF[MAX_PATH]; VariantInit(pURL); wsprintf(szRTF, _T("file://%s"), szDest); V_VT(pURL) = VT_BSTR; pURL->bstrVal = SysAllocString(T2OLE(szRTF)); } else { hr = HRESULT_FROM_WIN32(GetLastError()); } return hr; } HRESULT DownloadReadThis(PINVENTORY_ITEM pItem) { LOG_block("DownloadReadThis"); BYTE mszFileNames[512]; TCHAR szBaseName[64]; TCHAR szLocalName[64]; TCHAR szServerName[64]; TCHAR szServerFile[MAX_PATH]; TCHAR szLocalFile[MAX_PATH]; TCHAR szLocalDir[MAX_PATH]; if (NULL == pItem->pd) { LOG_error("NULL == pItem->pd"); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } PWU_VARIABLE_FIELD pvRTFCRC = pItem->pd->pv->Find(WU_DESC_RTF_CRC_ARRAY); PWU_VARIABLE_FIELD pvRTFImages = pItem->pd->pv->Find(WU_DESC_RTF_IMAGES); if (pvRTFCRC == NULL) { LOG_error("pvRTFCRC == NULL"); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } // build a multisz string of file names int iLen = sprintf((char*)mszFileNames, "%d.htm", pItem->GetPuid()); mszFileNames[++iLen] = '\0'; if (pvRTFImages != NULL) { // we have images memcpy(mszFileNames + iLen, pvRTFImages->pData, pvRTFImages->len - 4); } // build local directory GetWindowsUpdateDirectory(szLocalDir); wsprintf(szBaseName, _T("RTF\\%d"), pItem->GetPuid()); lstrcat(szLocalDir, szBaseName); V3_CreateDirectory(szLocalDir); // download common images and other files (void)DownloadCommonRTFFiles(FALSE, NULL); // create a download object CWUDownload dlRoot(g_v3state.GetRootServer(), 8192); int iFileNo = 0; for (;;) { if (FAILED(GetCRCNameFromList(iFileNo, mszFileNames, pvRTFCRC->pData, szServerName, sizeof(szServerName), szLocalName))) { // end of the list break; } // build full paths lstrcpy(szLocalFile, szLocalDir); AddBackSlash(szLocalFile); lstrcat(szLocalFile, szLocalName); lstrcpy(szServerFile, _T("CRCRtf/")); lstrcat(szServerFile, szServerName); TRACE("Downloading RTF %s", szServerFile); if (!dlRoot.Copy(szServerFile, szLocalFile, NULL, NULL, 0, NULL)) { LOG_error("Download of RTF %s failed", szServerFile); return HRESULT_FROM_WIN32(GetLastError()); } iFileNo++; } // for return S_OK; } // deletes any cached readthisfirst pages bool CleanupReadThis() { LOG_block("CleanupReadThis"); // build local directory TCHAR szRtfPath[MAX_PATH]; GetWindowsUpdateDirectory(szRtfPath); PathAppend(szRtfPath, _T("RTF")); return_if_false(DeleteNode(szRtfPath)); return true; } // download common images for read-this-first pages and the printall page // // if bPrintAll=TRUE, only printall.htm page is downloaded, pszPrintAllFN returns locale filename // if bPrintAll=FALSE, mages are downloaded, pszPrintAllFN is not used and can be null // // NOTE: The function downloads images in WinUpdDir/RTF folder and expects it to exist HRESULT DownloadCommonRTFFiles(BOOL bPrintAll, LPTSTR pszPrintAllFN) { const TCHAR SECNAME[] = _T("RTF"); const TCHAR COUNT[] = _T("Count"); const TCHAR IMGENTRY[] = _T("Img%d"); const TCHAR PRINTALL[] = _T("PrintAll"); TCHAR szLocalDir[MAX_PATH]; TCHAR szIniFile[MAX_PATH]; int iCount; int iNo; CWUDownload* pDownload = NULL; TCHAR szBaseName[64]; TCHAR szServerFile[MAX_PATH]; TCHAR szLocalFile[MAX_PATH]; static BOOL bDoneImages = FALSE; static BOOL bDonePrintAll = FALSE; // build paths GetWindowsUpdateDirectory(szLocalDir); lstrcpy(szIniFile, szLocalDir); lstrcat(szLocalDir, _T("RTF\\")); lstrcat(szIniFile, FILEVERINI_FN); if (GetPrivateProfileString(SECNAME, PRINTALL, _T(""), szBaseName, sizeof(szBaseName) / sizeof(TCHAR), szIniFile) != 0) { lstrcpy(szLocalFile, szLocalDir); lstrcat(szLocalFile, szBaseName); } else { szLocalFile[0] = _T('\0'); } if (bPrintAll && pszPrintAllFN != NULL) { lstrcpy(pszPrintAllFN, szLocalFile); } // if we are asked to downloaded the printall page and we have not done it in this sesssion if (bPrintAll && !bDonePrintAll) { bDonePrintAll = TRUE; // // get the printall page // lstrcpy(szServerFile, g_v3state.GetSiteURL()); // find the last slash int l = lstrlen(szServerFile); while (l > 0 && szServerFile[l - 1] != _T('\\') && szServerFile[l - 1] != _T('/')) l--; if (l == 0) return E_FAIL; // put a null following the last slash szServerFile[l] = _T('\0'); // create the download object using the site URL without the file name try { pDownload = new CWUDownload(szServerFile, 8192); } catch(HRESULT hr) { return hr; } // download the file (void)pDownload->Copy(szBaseName, szLocalFile, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL); delete pDownload; } // if we are asked to download images and we have not yet done them in this session if (!bPrintAll && !bDoneImages) { bDoneImages = FALSE; // // download the images // iCount = (int)GetPrivateProfileInt(SECNAME, COUNT, 0, szIniFile); if (iCount == 0) { return S_OK; } for (iNo = 1; iNo <= iCount; iNo++) { TCHAR szKey[32]; wsprintf(szKey, IMGENTRY, iNo); if (GetPrivateProfileString(SECNAME, szKey, _T(""), szBaseName, sizeof(szBaseName) / sizeof(TCHAR), szIniFile) == 0) { // try next one continue; } if (pDownload == NULL) { // we don't have a download object, create one try { pDownload = new CWUDownload(g_v3state.GetContentServer(), 8192); } catch(HRESULT hr) { return hr; } } // build file names wsprintf(szServerFile, _T("images/%s"), szBaseName); lstrcpy(szLocalFile, szLocalDir); lstrcat(szLocalFile, szBaseName); // download the file (void)pDownload->Copy(szServerFile, szLocalFile, NULL, NULL, DOWNLOAD_NEWER | CACHE_FILE_LOCALLY | EXACT_FILENAME, NULL); } if (pDownload != NULL) { delete pDownload; } } return S_OK; } // this function validates the server the control was instantiated from void CCV3::CheckLaunchServer() { USES_CONVERSION; BOOL bValid; HRESULT hr; BSTR bstrURL; TCHAR szURL[MAX_PATH]; if (m_bLaunchServChecked) { // we only want to do this check once return; } m_bLaunchServChecked = TRUE; bValid = FALSE; // check to see we have a client site. This will be NULL if the contrainer has not // called our IObjectWithSimpleSite interface to set the site. if (m_spUnkSite != NULL) { // NOTE: We are using ATL smart pointers here which call release upon destruction // QI for IServiceProvider from IUnknown of client site CComQIPtr spServProv(m_spUnkSite); if (spServProv) { CComPtr spBrowser; // QueryService for the IWebBrowser2 hr = spServProv->QueryService(SID_SInternetExplorer, IID_IWebBrowser2, (LPVOID*)&spBrowser); if (SUCCEEDED(hr)) { // get the location URL of the page that instantiated us hr = spBrowser->get_LocationURL(&bstrURL); if (SUCCEEDED(hr) && bstrURL) { lstrcpy(szURL, OLE2T(bstrURL)); SysFreeString(bstrURL); // copy the entire site URL into the state structure g_v3state.SetSiteURL(szURL); // check to see if the host server matches // any of the site urls specified in ident.cab // this function will crack the site url and all // the site server urls to compare the hosts bValid = g_v3state.ValidateSiteURL(); } } // queryservice } // spServProv } // m_spUnkSite if (!bValid) { TRACE("CheckLauncServer: The control is launced from an untrusted server--aborting"); throw E_ACCESSDENIED; } } // // CDescriptionmMerger class // HRESULT CDescriptionMerger::CheckMerge(PINSTALLINFOSTRUCT pInstallInfo) { HRESULT hr = S_OK; if (!pInstallInfo->pCatalog->LocalesDifferent()) { // if the browser/machine locales are not different then we don't need to do anything return hr; } if (pInstallInfo->pItem->pd->pv->Find(WU_VARIABLE_MERGEINACTIVE) != NULL) { // there is a WU_VARIABLE_MERGEINACTIVE which means we have already merged return hr; } // // we need merge the descriptions // if (m_pMap == NULL || m_pDiamond == NULL) { // create CCRCMapFile and CDiamond objects for this and future use for this object // this method also sets m_pDiamond hr = ReadMapFile(pInstallInfo->pCatalog); } if (SUCCEEDED(hr)) { hr = pInstallInfo->pCatalog->MergeDescription(pInstallInfo->pdlRoot, m_pDiamond, pInstallInfo->pItem, m_pMap); } return hr; } HRESULT CDescriptionMerger::ReadMapFile(CCatalog* pCatalog) { HRESULT hr = S_OK; TCHAR szMapFile[MAX_PATH]; BYTE* pMapMem; DWORD dwMapLen; // create download object for content server and a diamond object CWUDownload dl(g_v3state.GetContentServer(), 8192); m_pDiamond = new CDiamond; // build path for crc map file for machine language wsprintf(szMapFile, _T("%d_%s.des"), pCatalog->GetPlatform(), pCatalog->GetMachineLocaleSZ()); hr = DownloadFileToMem(&dl, szMapFile, m_pDiamond, &pMapMem, &dwMapLen); if (SUCCEEDED(hr)) { // create a crc map object with the memory image of the file m_pMap = new CCRCMapFile(pMapMem, dwMapLen); } return hr; } #ifdef _WUV3TEST // validates the description using diagnosis variable length fields void CheckDescDiagInfo(CCatalog* pCatalog) { PINVENTORY_ITEM pItem; PWU_VARIABLE_FIELD pvDiag; DESCDIAGINFO* pDiagInfo; int cGood = 0; int cItems = 0; for (int i = 0; i < pCatalog->GetHeader()->totalItems; i++) { if (NULL == (pItem = pCatalog->GetItem(i))) { continue; } if ((pItem->ps->state != WU_ITEM_STATE_PRUNED)) { pvDiag = pItem->pd->pv->Find(WU_DESC_DIAGINFO); if (pvDiag != NULL) { pDiagInfo = (DESCDIAGINFO*)pvDiag->pData; if (pDiagInfo->puid != pItem->GetPuid() || pDiagInfo->dwPlat != pCatalog->GetPlatform() || pDiagInfo->dwLocale != pCatalog->GetBrowserLocaleDW()) { TRACE("CheckDescDiagInfo: puid=%d has invalid description", pItem->GetPuid()); } else { cGood++; } } else { TRACE("CheckDescDiagInfo: diagnosis information not found in descriptions"); break; } } cItems++; } TRACE("CheckDescDiagInfo: %d good found for %d items compared", cGood, cItems); } #endif