// Microsoft Windows // // Copyright (C) Microsoft Corporation, 2000 // // File: aucatalog.cpp // // Purpose: AU catalog file using IU // // Creator: WeiW // // History: 08-15-01 first created // //-------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop const LPTSTR ITEM_FILE = _T("item.xml"); const LPTSTR DRIVERS_FILE = _T("drivers.xml"); const LPTSTR CATALOG_FILE = _T("catalog.xml"); const LPTSTR DETAILS_FILE = _T("details.xml"); //following files are write once and never be read. #ifdef DBG const LPTSTR DRIVER_SYSSPEC_FILE = _T("driversys.xml"); const LPTSTR NONDRIVER_SYSSPEC_FILE = _T("nondriversys.xml"); const LPTSTR PROVIDER_FILE = _T("provider.xml"); const LPTSTR PRODUCT_FILE = _T("product.xml"); const LPTSTR DETECT1_FILE = _T("detect1.xml"); const LPTSTR DETECT2_FILE = _T("detect2.xml"); const LPTSTR DETECT3_FILE = _T("detect3.xml"); const LPTSTR INSTALL_FILE = _T("install.xml"); #endif #ifdef DBG const TCHAR REG_AUCATLIFESPAN[] = _T("CatLifeSpan"); //REG_DWORD const TCHAR REG_AUCATOFFLINELIFESPAN[] = _T("CatOfflineLifeSpan"); //REG_DWORD #endif BSTR AUCatalog::AUPROVIDERQUERY; BSTR AUCatalog::AUPRODUCTQUERY; BSTR AUCatalog::AUITEMQUERY; BSTR AUCatalog::AUDETAILSQUERY; BSTR AUCatalog::AUDRIVERSQUERY; BSTR AUCatalog::PRODUCT_PRUNE_PATTERN; BSTR AUCatalog::DETAILS_PRUNE_PATTERN; BSTR AUCatalog::AUDRIVERSYSCLASS; BSTR AUCatalog::AUNONDRIVERSYSCLASS; BSTR AUCatalog::bstrParentItems; BSTR AUCatalog::bstrItemID; BSTR AUCatalog::bstrTagAUCATALOG; BSTR AUCatalog::bstrAttrVERSION; BSTR AUCatalog::bstrAttrDOWNLOADID; BSTR AUCatalog::bstrAttrITEMCOUNT; BSTR AUCatalog::bstrAttrUpdateDriver; BSTR AUCatalog::bstrAttrSTATUS; BSTR AUCatalog::bstrHiddenItems; BSTR AUCatalog::bstrTagITEM; BSTR AUCatalog::bstrAttrID; BSTR AUCatalog::bstrProviderNamePattern; BSTR AUCatalog::bstrItemIDPattern; BSTR AUCatalog::bstrTitlePattern; BSTR AUCatalog::bstrDescPattern; BSTR AUCatalog::bstrRTFUrlPattern; BSTR AUCatalog::bstrEulaUrlPattern; BSTR AUCatalog::bstrExclusiveItemPattern; BSTR AUCatalog::bstrItemIdsPattern; BSTR AUCatalog::bstrTemplate; BSTR AUCatalog::bstrResultTemplate; BSTR AUCatalog::bstrCatalog; inline BOOL FServiceShuttingDown() { return WaitForSingleObject(ghServiceFinished, 0) == WAIT_OBJECT_0; } #ifdef DBG inline BOOL fDBGUseLocalFile() { DWORD dwLevel; if (FAILED(GetRegDWordValue(TEXT("UseLocalFile"), &dwLevel)) || 1 != dwLevel) { return FALSE; } return TRUE; } #endif AUCatalog::~AUCatalog(void) { Clear(); SafeFreeBSTR(m_bstrClientInfo); SafeFreeBSTR(m_bstrDriverClientInfo); } //always called before any other method on AUCatalog is used. HRESULT AUCatalog::Init() { HRESULT hr = S_OK; m_fNeedToContinueJob = FALSE; m_bstrInstallation = NULL; m_fUpdateDriver = !gpState->fWin2K(); m_dwCatLifeSpan = CATALOG_LIFESPAN; m_dwOfflineCatLifeSpan = CATALOG_OFFLINE_LIFESPAN; ZeroMemory(&m_stExpireTime, sizeof(m_stExpireTime)) ; ZeroMemory(&m_stOfflineExpireTime, sizeof(m_stOfflineExpireTime)); m_bstrClientInfo = SysAllocString(AUCLIENTINFO); m_bstrDriverClientInfo = SysAllocString(AUDRIVERCLIENTINFO); if (NULL == m_bstrClientInfo || NULL == m_bstrDriverClientInfo) { DEBUGMSG("AUCatalog::Init() fail to alloc string for client info"); hr = E_FAIL; goto end; } #ifdef DBG if (FAILED(GetRegDWordValue(REG_AUCATLIFESPAN, &m_dwCatLifeSpan))) { m_dwCatLifeSpan = CATALOG_LIFESPAN; } if (FAILED(GetRegDWordValue(REG_AUCATOFFLINELIFESPAN, &m_dwOfflineCatLifeSpan))) { m_dwOfflineCatLifeSpan = CATALOG_OFFLINE_LIFESPAN; } #endif end: return hr; } ////////////////////////////////////////////////////////////////////// // clear out more dynamic internal data ///////////////////////////////////////////////////////////////////// void AUCatalog::Clear() { m_ItemList.Clear(); SafeFreeBSTRNULL(m_bstrInstallation); ZeroMemory(&m_stExpireTime, sizeof(m_stExpireTime)); ZeroMemory(&m_stOfflineExpireTime, sizeof(m_stOfflineExpireTime)); } HRESULT AUCatalog::GetSystemSpec(DETECTLEVEL enLevel, BSTR * pbstrSysSpec) { HRESULT hr = E_FAIL; if (FServiceShuttingDown()) { DEBUGMSG("Skip AUCatalog::GetSystemSpec() because service is shutting down"); hr = E_ABORT; goto done; } BSTR bstrSysClass = (DRIVERS_LEVEL == enLevel) ? AUDRIVERSYSCLASS : AUNONDRIVERSYSCLASS; hr = m_pfnGetSystemSpec(m_hIUEngineInst, bstrSysClass, 0, pbstrSysSpec); //online mode #ifdef DBG if (SUCCEEDED(hr)) { LOGXMLFILE((DRIVERS_LEVEL == enLevel) ? DRIVER_SYSSPEC_FILE : NONDRIVER_SYSSPEC_FILE, *pbstrSysSpec); } #endif done: return hr; } //////////////////////////////////////////////////////////////////////////////// // compose query based on a format and items picked out from detection result // HRESULT AUCatalog::GetQuery(IN DETECTLEVEL enLevel, IN BSTR bstrDetectResult, OUT BSTR *pbstrQuery) { BSTR bstrPrunePattern; BSTR bstrQuery = NULL; HRESULT hr = S_OK; IXMLDOMNodeList *pItems = NULL; IXMLDOMNode *pParentItems = NULL; IXMLDOMDocument *pQueryXML= NULL; IXMLDOMDocument *pResultXML= NULL; DEBUGMSG("GetQuery() starts"); AUASSERT(NULL != pbstrQuery); *pbstrQuery = NULL; switch (enLevel) { case PROVIDER_LEVEL: bstrQuery = AUPROVIDERQUERY; break; case DRIVERS_LEVEL: bstrQuery = AUDRIVERSQUERY; break; case PRODUCT_LEVEL: bstrQuery = AUPRODUCTQUERY; bstrPrunePattern = PRODUCT_PRUNE_PATTERN; break; case ITEM_LEVEL: bstrQuery = AUITEMQUERY; bstrPrunePattern = PRODUCT_PRUNE_PATTERN; //the same as product pruning logic break; case DETAILS_LEVEL: bstrQuery = AUDETAILSQUERY; bstrPrunePattern = DETAILS_PRUNE_PATTERN; break; default: AUASSERT(FALSE); //should never be here return E_INVALIDARG; } if (FAILED(hr = LoadXMLDoc(bstrQuery, &pQueryXML, TRUE))) { DEBUGMSG("GetQuery() fail to load query XML with error %#lx", hr); goto done; } if (enLevel != PROVIDER_LEVEL && DRIVERS_LEVEL != enLevel) { if (FAILED(hr = LoadXMLDoc(bstrDetectResult, &pResultXML, TRUE))) { DEBUGMSG("GetQuery() fail to load XML for detect result with error %#lx", hr); goto done; } if (FAILED(hr = pResultXML->selectNodes(bstrPrunePattern, &pItems))) { DEBUGMSG("GetQuery() fail to select node or nothing to select with error %#lx", hr); goto done; } long lLen = 0; if (FAILED(hr = pItems->get_length(&lLen))) { DEBUGMSG("GetQuery() fail to get item number with error %#lx", hr); goto done; } DEBUGMSG("GetQuery(): pruning result %d items", lLen); if (0 == lLen) { DEBUGMSG("No updates applicable"); hr = S_FALSE; goto done; } if (S_OK != (hr = pQueryXML->selectSingleNode(bstrParentItems, &pParentItems))) { DEBUGMSG("GetQuery() fail to select single node %#lx or nothing to select", hr); hr = E_FAIL; goto done; } for (int i = 0; i < lLen; i++) { IXMLDOMNode *pIdentity1 = NULL; IXMLDOMNode *pItemStatus; if (S_OK != (hr = pItems->get_item(i, &pItemStatus))) { hr = FAILED(hr) ? hr : E_FAIL; goto done; } hr = pItemStatus->selectSingleNode(bstrItemID, &pIdentity1); pItemStatus->Release(); if (FAILED(hr) || NULL == pIdentity1) { DEBUGMSG("GetQuery() fail to select itemID with error %#lx", hr); hr = FAILED(hr) ? hr : E_FAIL; goto done; } if (NULL == pIdentity1) { DEBUGMSG("GetQuery() fail to select itemID"); hr = E_FAIL; goto done; } { BSTR bstrItemId = NULL; IXMLDOMElement *pItem= NULL; IXMLDOMText *pItemIdText = NULL; if (S_OK != (hr = pIdentity1->get_text(&bstrItemId))) { DEBUGMSG("Fail to get text for item"); hr = FAILED(hr) ? hr : E_FAIL; } else if (FAILED(hr = pQueryXML->createTextNode(bstrItemId, &pItemIdText))) { DEBUGMSG("Fail to create text node"); } else if (FAILED (hr = pQueryXML->createElement(KEY_ITEM, &pItem))) { DEBUGMSG("GetQuery() fail to create element"); } else if (FAILED(hr = pItem->appendChild(pItemIdText, NULL))) { DEBUGMSG("Fail to append child"); } else if (FAILED(hr = pParentItems->appendChild(pItem, NULL))) { DEBUGMSG("Fail to append child with error %#lx", hr); } SafeRelease(pItem); SafeRelease(pItemIdText); SafeFreeBSTR(bstrItemId); pIdentity1->Release(); if (FAILED(hr)) { goto done; } } } } if (FAILED(hr = pQueryXML->get_xml(pbstrQuery))) { DEBUGMSG("Fail to get query xml with error %#lx", hr); goto done; } done: // DEBUGMSG("GetQuery(): Query string is %S", *pbstrQuery); SafeRelease(pItems); SafeRelease(pParentItems); SafeRelease(pQueryXML); SafeRelease(pResultXML); if (FAILED(hr)) { SafeFreeBSTRNULL(*pbstrQuery); } return hr; } HRESULT AUCatalog::DoDetection(IN DETECTLEVEL enLevel, IN BSTR bstrCatalog, OUT BSTR *pbstrResult, IN BOOL fOnline) { HRESULT hr = E_FAIL; #ifdef DBG DWORD dwStart = GetTickCount(); #endif AUASSERT(m_pfnDetect != NULL); AUASSERT(bstrCatalog != NULL); AUASSERT(m_hIUEngineInst != NULL); AUASSERT(NULL != pbstrResult); *pbstrResult = NULL; if (FServiceShuttingDown()) { DEBUGMSG("Skip AUCatalog::DoDetection() because service is shutting down"); hr = E_ABORT; goto done; } hr = m_pfnDetect(m_hIUEngineInst, bstrCatalog, fOnline ? 0 : FLAG_OFFLINE_MODE, pbstrResult); #ifdef DBG if (SUCCEEDED(hr)) { switch (enLevel) { case PROVIDER_LEVEL: LOGXMLFILE(DETECT1_FILE, *pbstrResult); break; case PRODUCT_LEVEL: LOGXMLFILE(DETECT2_FILE, *pbstrResult); break; case ITEM_LEVEL: LOGXMLFILE(DETECT3_FILE, *pbstrResult); break; default: AUASSERT(FALSE); hr = E_INVALIDARG; break; } } #endif done: #ifdef DBG DEBUGMSG("DoDetection() take %d msecs", GetTickCount() - dwStart); #endif if (FAILED(hr)) { SafeFreeBSTRNULL(*pbstrResult); } return hr; } LPCTSTR AUCatalog::GetLogFile(IN DETECTLEVEL enLevel) { switch (enLevel) { #ifdef DBG case PROVIDER_LEVEL: return PROVIDER_FILE; case PRODUCT_LEVEL: return PRODUCT_FILE; #endif case ITEM_LEVEL: return ITEM_FILE; case DETAILS_LEVEL: return DETAILS_FILE; case DRIVERS_LEVEL: return DRIVERS_FILE; default: return NULL; } } HRESULT AUCatalog::GetManifest(IN DETECTLEVEL enLevel, IN BSTR bstrDetectResult, OUT BSTR *pbstrManifest) { HRESULT hr = E_FAIL; BSTR bstrQuery = NULL; #ifdef DBG DWORD dwStart= GetTickCount(); #endif AUASSERT(NULL != m_pfnGetManifest); *pbstrManifest = NULL; if (FServiceShuttingDown()) { DEBUGMSG("Skip AUCatalog::GetManifest() because service is shutting down"); hr = E_ABORT; goto done; } if (S_OK != (hr = GetQuery(enLevel, bstrDetectResult, &bstrQuery))) { goto done; } BSTR bstrSysSpec = NULL; if (FAILED(hr = GetSystemSpec(enLevel, &bstrSysSpec))) { goto done; } DEBUGMSG("WUAUENG: Calling IU getmanifest()...."); hr = m_pfnGetManifest(m_hIUEngineInst, (DRIVERS_LEVEL == enLevel) ? m_bstrDriverClientInfo :m_bstrClientInfo, bstrSysSpec, bstrQuery, FLAG_USE_COMPRESSION, pbstrManifest); //compression on DEBUGMSG("WUAUENG: IU getmanifest() done"); SysFreeString(bstrSysSpec); if (FAILED(hr)) { goto done; } LPCTSTR ptszLogFile = GetLogFile(enLevel); if (NULL != ptszLogFile) { if (FAILED(hr = LOGXMLFILE(ptszLogFile, *pbstrManifest))) { goto done; } } done: SafeFreeBSTR(bstrQuery); #ifdef DBG DEBUGMSG("GetManifest() take %d msecs", GetTickCount() - dwStart); #endif if (FAILED(hr)) { SafeFreeBSTRNULL(*pbstrManifest); } return hr; } HRESULT AUCatalog::DownloadItems() { // USES_CONVERSION; HRESULT hr = S_OK; CItemDetails itemdetails; UINT uItemCount; DEBUGMSG("AUCatalog downloading items..."); PersistHiddenItems(m_ItemList, URLLOGACTIVITY_Download); if (m_fNeedToContinueJob) { m_fNeedToContinueJob = FALSE; if (SUCCEEDED(m_audownloader.ContinueLastDownloadJob())) { DEBUGMSG("found previous download job, reconnecting succeed"); goto end; } } #ifdef DBG else { DEBUGMSG("no previous download job found"); } #endif DWORD dwNumSelected = m_ItemList.GetNumSelected(); if (0 == dwNumSelected) { hr = S_FALSE; DEBUGMSG("Nothing to download, bail out"); goto end; } if (NULL == m_bstrInstallation) { DEBUGMSG("AUCatalog::DownloadItems() can't get installation xml"); hr = E_FAIL; goto end; } if (!itemdetails.Init(m_bstrInstallation)) { hr = E_FAIL; DEBUGMSG("fail to init itemdetails"); goto end; } for (UINT i = 0; i < m_ItemList.Count(); i++) { AUCatalogItem &item = m_ItemList[i]; if (item.fSelected() || m_ItemList.ItemIsRelevant(i)) { BSTR * pCRCCabNames, *pRealCabNames, *pCabChecksums; UINT uCabsNum; BSTR bstrItemId = item.bstrID(); BSTR bstrItemDownloadPath = itemdetails.GetItemDownloadPath(bstrItemId); if (NULL == bstrItemDownloadPath) { DEBUGMSG("fail to build item downloadPath"); hr = E_FAIL; goto end; } if (SUCCEEDED(hr = itemdetails.GetCabNames(bstrItemId, &pCRCCabNames, &pRealCabNames, &pCabChecksums, &uCabsNum))) { DEBUGMSG("Need to download following files for %S", bstrItemId); for (UINT j = 0; j < uCabsNum; j++) { TCHAR szFullFileName[MAX_PATH]; if (SUCCEEDED(hr) && SUCCEEDED(hr = StringCchCopyEx(szFullFileName, ARRAYSIZE(szFullFileName), W2T(bstrItemDownloadPath), NULL, NULL, MISTSAFE_STRING_FLAGS))) { if (SUCCEEDED(hr = PathCchAppend(szFullFileName, ARRAYSIZE(szFullFileName), W2T(pRealCabNames[j])))) { hr = m_audownloader.QueueDownloadFile(W2T(pCRCCabNames[j]), szFullFileName); } } DEBUGMSG(" from %S to %S", pCRCCabNames[j], szFullFileName); SafeFreeBSTR(pCRCCabNames[j]); SafeFreeBSTR(pRealCabNames[j]); SafeFreeBSTR(pCabChecksums[j]); } free(pCRCCabNames); free(pRealCabNames); free(pCabChecksums); } #ifdef DBG else { DEBUGMSG("fail to get cab names for %S", bstrItemId); } #endif SysFreeString(bstrItemDownloadPath); if (FAILED(hr)) { goto end; } } } if (SUCCEEDED(hr = m_audownloader.StartDownload())) { Serialize(); //serialize download id } end: itemdetails.Uninit(); if (FAILED(hr)) { m_audownloader.Reset(); } DEBUGMSG("AUCatalog downloading items done"); return hr; } char * AUCatalog::GetLevelStr(DETECTLEVEL enLevel) { switch (enLevel) { case PROVIDER_LEVEL: return "Provider"; case PRODUCT_LEVEL: return "Product"; case ITEM_LEVEL: return "Item"; case DETAILS_LEVEL: return "ItemDetails"; default: return NULL; } } BOOL AUCatalog::hasExpired(BOOL fOffline) { SYSTEMTIME stTmp ; SYSTEMTIME stExpire; ZeroMemory(&stTmp, sizeof(stTmp)); stExpire = fOffline ? m_stOfflineExpireTime : m_stExpireTime; GetSystemTime(&stTmp); #ifdef DBG TCHAR szExpireTime[80], szCurrentTime[80]; if (SUCCEEDED(SystemTime2String(stExpire, szExpireTime, ARRAYSIZE(szExpireTime))) && SUCCEEDED(SystemTime2String(stTmp, szCurrentTime, ARRAYSIZE(szCurrentTime)))) { DEBUGMSG("AUCatalog::hasExpired() expire time is %S current time is %S", szExpireTime, szCurrentTime); } #endif return TimeDiff(stExpire, stTmp) >= 0; } HRESULT AUCatalog::setExpireTime(BOOL fOffline) { SYSTEMTIME stCurrent; HRESULT hr = E_FAIL; GetSystemTime(&stCurrent); if (FAILED(hr = TimeAddSeconds(stCurrent, dwSecsToWait(m_dwOfflineCatLifeSpan), &m_stOfflineExpireTime))) { DEBUGMSG("Fail to calculate m_stOfflineExpireTime with error %#lx", hr); goto done; } if (!fOffline) { if (FAILED(hr = TimeAddSeconds(stCurrent, dwSecsToWait(m_dwCatLifeSpan), &m_stExpireTime))) { DEBUGMSG("Fail to calculate m_stExpireTime with error %#lx", hr); goto done; } } #ifdef DBG TCHAR szCurrentTime[80], szExpireTime[80]; if (SUCCEEDED(SystemTime2String(stCurrent, szCurrentTime, ARRAYSIZE(szCurrentTime))) && SUCCEEDED(SystemTime2String(m_stOfflineExpireTime, szExpireTime, ARRAYSIZE(szExpireTime)))) { DEBUGMSG("AUCatalog::setExpireTime with current time %S and expire time %S", szCurrentTime, szExpireTime); } #endif hr = S_OK; done: if (FAILED(hr)) { ZeroMemory(&m_stOfflineExpireTime, sizeof(m_stOfflineExpireTime)); ZeroMemory(&m_stExpireTime, sizeof(m_stOfflineExpireTime)); } return hr; } //when m_fUpdateDriver is FALSE, bstrDrivers are not looked at HRESULT AUCatalog::ValidateOffline(BSTR bstrItems, BSTR bstrDrivers) { HRESULT hr= E_FAIL; BSTR bstrResult = NULL; BSTR bstrQuery = NULL; IXMLDOMDocument *pQueryXml = NULL; IXMLDOMDocument *pDriversXml = NULL; // DEBUGMSG("ValidateOffline starts"); if (0 == m_ItemList.Count()) { hr = S_FALSE; goto done; //no need to validate } if (FAILED(hr = PrepareIU(FALSE))) { DEBUGMSG(" fail to prepare IU offline with error %#lx", hr); goto done; } if (FAILED(hr = DoDetection(ITEM_LEVEL, bstrItems, &bstrResult, FALSE))) { DEBUGMSG("Fail to detect items with error %#lx", hr); goto done; } if (S_OK != (hr = GetQuery(DETAILS_LEVEL, bstrResult, &bstrQuery))) { goto done; } // DEBUGMSG("Query Result is %S", bstrQuery); if (FAILED(hr = LoadXMLDoc(bstrQuery, &pQueryXml, TRUE)) || (m_fUpdateDriver && FAILED(hr = LoadXMLDoc(bstrDrivers, &pDriversXml, TRUE)))) //offline { DEBUGMSG("Fail to load xml with error %#lx", hr); goto done; } for (UINT u = 0; u < m_ItemList.Count(); u++) { IXMLDOMNode *pItemIdentityNode1 = NULL; IXMLDOMNode *pItemNode2 = NULL; CAU_BSTR aubsItemPattern; CAU_BSTR aubsDriverItemIdentityPattern; if (!aubsDriverItemIdentityPattern.append(L"/catalog/provider/item/identity[@itemID=\"") || !aubsDriverItemIdentityPattern.append(m_ItemList[u].bstrID()) || !aubsDriverItemIdentityPattern.append(L"\"]")) { DEBUGMSG("failed to create driver pattern string"); hr = E_OUTOFMEMORY; goto done; } if (!aubsItemPattern.append(L"/query/dObjQueryV1/parentItems/item[.=\"") || !aubsItemPattern.append(m_ItemList[u].bstrID()) || !aubsItemPattern.append(L"\"]")) { DEBUGMSG("OUT OF MEMORY and failed to create pattern string"); hr = E_OUTOFMEMORY; goto done; } if ((m_fUpdateDriver && HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == FindSingleDOMNode(pDriversXml, aubsDriverItemIdentityPattern, &pItemIdentityNode1) && HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == FindSingleDOMNode(pQueryXml, aubsItemPattern, &pItemNode2)) || (!m_fUpdateDriver && HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == FindSingleDOMNode(pQueryXml, aubsItemPattern, &pItemNode2))) { DEBUGMSG("item %S installed off band, remove it from AU's list", m_ItemList[u].bstrID()); m_ItemList.Remove(m_ItemList[u].bstrID()); } SafeRelease(pItemIdentityNode1); SafeRelease(pItemNode2); } done: FreeIU(); SafeFreeBSTR(bstrQuery); SafeFreeBSTR(bstrResult); SafeRelease(pQueryXml); SafeRelease(pDriversXml); // DEBUGMSG("ValidateOffline ends"); return hr; } /////////////////////////////////////////////////////////////////////////////////////// //update internal list to reflect latest applicable items // return S_FALSE if nothing is appliable anymore ////////////////////////////////////////////////////////////////////////////////////// HRESULT AUCatalog::ValidateItems(BOOL fOnline ) { HRESULT hr = S_OK; BSTR bstrNonDrivers = NULL, bstrDrivers = NULL; DEBUGMSG("AUCatalog validating items..."); if (fOnline && !hasExpired()) { DEBUGMSG("Catalog was valid and hasn't expired online. Do offline validation only"); fOnline = FALSE; } if (!fOnline && !hasExpired(TRUE)) { DEBUGMSG("Catalog was valid and hasn't expired offline. No validation needed"); goto done; } if (fOnline) { //do online detection DEBUGMSG("Doing online validating"); AUCatalogItemList olditemlist; if (FAILED(hr = olditemlist.Copy(m_ItemList))) { goto done; } if (S_OK != (hr = DetectItems(TRUE))) //update instead of building from scratch { //fail to detect or no items applicable goto done; } BOOL fItemPulled; do { fItemPulled = FALSE; UINT uOldListLen = olditemlist.Count(); for (UINT u=0; u < uOldListLen; u++) { if (m_ItemList.Contains(olditemlist[u].bstrID()) < 0) { DEBUGMSG("item %S is pulled from site", olditemlist[u].bstrID()); olditemlist.Remove(olditemlist[u].bstrID()); fItemPulled = TRUE; break; } } } while (fItemPulled); if (FAILED(hr = m_ItemList.Copy(olditemlist))) //update item list { goto done; } } if (NULL == (bstrNonDrivers =ReadXMLFromFile(ITEM_FILE)) || (m_fUpdateDriver && (NULL == (bstrDrivers = ReadXMLFromFile(DRIVERS_FILE))))) { DEBUGMSG("Fail to read item or drivers xml file "); hr = E_FAIL; goto done; } if (!fOnline) { //do offline validation for non drivers DEBUGMSG("Doing offline validating"); if (FAILED(hr = ValidateOffline(bstrNonDrivers, bstrDrivers))) { DEBUGMSG("Fail to validate offline with error %#lx", hr); goto done; } } if (m_ItemList.GetNumHidden() == m_ItemList.Count()) { DEBUGMSG("No applicable items left"); hr = S_FALSE; goto done; } if (FAILED(hr = BuildDependencyList(m_ItemList, bstrDrivers, bstrNonDrivers))) { DEBUGMSG("Fail to build dependency list with error %#lx", hr); goto done; } setExpireTime(fOnline); Serialize(); done: if (S_OK != hr) { Clear(); //need to redetect anyway DelCatFiles(); } SafeFreeBSTR(bstrNonDrivers); SafeFreeBSTR(bstrDrivers); DEBUGMSG("AUCatalog done validating items"); return hr; } HRESULT AUCatalog::getUpdatesList(VARIANT OUT *pvarList) { SAFEARRAYBOUND bound[1] = { m_ItemList.Count() * 7, 0}; SAFEARRAY * psa = SafeArrayCreate(VT_VARIANT, 1, bound); VARIANT * grVariant; BOOL fRet = FALSE; AUASSERT(NULL != pvarList); DEBUGMSG("AUCatalog::getUpdateList() starts"); VariantInit(pvarList); if ( 0 == m_ItemList.Count() ) { DEBUGMSG("AUCatalog::getUpdateList fails because getNumItems is 0"); goto done; } if (NULL == psa || S_OK != SafeArrayAccessData(psa, (void **)&grVariant)) goto done; BOOL fError = FALSE; for ( UINT n = 0; n < m_ItemList.Count(); n++ ) { grVariant[n*7+0].vt = VT_I4; grVariant[n*7+0].lVal = m_ItemList[n].dwStatus(); grVariant[n*7+1].vt = VT_BSTR; grVariant[n*7+1].bstrVal = SysAllocString(m_ItemList[n].bstrID()); grVariant[n*7+2].vt = VT_BSTR; grVariant[n*7+2].bstrVal = SysAllocString(m_ItemList[n].bstrProviderName()); grVariant[n*7+3].vt = VT_BSTR; grVariant[n*7+3].bstrVal = SysAllocString(m_ItemList[n].bstrTitle()); grVariant[n*7+4].vt = VT_BSTR; grVariant[n*7+4].bstrVal = SysAllocString(m_ItemList[n].bstrDescription()); grVariant[n*7+5].vt = VT_BSTR; grVariant[n*7+5].bstrVal = SysAllocString(m_ItemList[n].bstrRTFPath()); grVariant[n*7+6].vt = VT_BSTR; grVariant[n*7+6].bstrVal = SysAllocString(m_ItemList[n].bstrEULAPath()); if ((NULL != m_ItemList[n].bstrID() && NULL == grVariant[n*7+1].bstrVal) || (NULL != m_ItemList[n].bstrProviderName() && NULL == grVariant[n*7+2].bstrVal) || (NULL != m_ItemList[n].bstrTitle() && NULL == grVariant[n*7+3].bstrVal) || (NULL != m_ItemList[n].bstrDescription() && NULL == grVariant[n*7+4].bstrVal) || (NULL != m_ItemList[n].bstrRTFPath() && NULL == grVariant[n*7+5].bstrVal) || (NULL != m_ItemList[n].bstrEULAPath() && NULL == grVariant[n*7+6].bstrVal)) { DEBUGMSG("OUT OF MEMORY, Fail to allocate string"); fError = TRUE; break; } } if (FAILED(SafeArrayUnaccessData(psa))) { goto done; } if (!fError) { fRet = TRUE; pvarList->vt = VT_ARRAY | VT_VARIANT; pvarList->parray = psa; } done: DEBUGMSG("AUCatalog::getUpdateList() ends"); if (!fRet && NULL != psa) { SafeArrayDestroy(psa); } return (fRet ? S_OK : E_FAIL); } //if udpate, meaning get updated information about existing items. Used in online validation. Treat exclusive and non exclusive the same //if not update, meaning building a fresh new item list //return S_FALSE if nothing applicable HRESULT AUCatalog::DetectItems(BOOL fUpdate ) { HRESULT hr; BSTR bstrNonDriverInstall = NULL, bstrDriverInstall = NULL; AUCatalogItemList nonDriverList, driverList; BOOL fExclusiveItemFound = FALSE; BOOL fExclusiveDriverFound = FALSE; DEBUGMSG("CAUCatalog::DetectItems() starts"); //clean up memory and local disk Clear(); DelCatFiles(fUpdate); if (FAILED(hr = PrepareIU())) { DEBUGMSG("AUCatalog::DetectItems() fail to prepare IU %#lx", hr); goto done; } if (FAILED(hr = DetectNonDriverItems(&bstrNonDriverInstall, nonDriverList, &fExclusiveItemFound))) { if (E_ABORT != hr) { DEBUGMSG(" fail to detect non driver updates %#lx", hr); } goto done; } DEBUGMSG("Non driver items got"); if (m_fUpdateDriver) { if (FAILED(hr = DetectDriverItems(&bstrDriverInstall, driverList, &fExclusiveDriverFound))) { if (E_ABORT != hr) { DEBUGMSG("fail to detect driver updates %#lx", hr); DEBUGMSG("consider driver update not essential, continue even if it fails"); //consider driver update not essential, continue even if it fails m_fUpdateDriver = FALSE; //from now on in this cycle do not care about driver any more } else { goto done; //bail out if service shutdown } } DEBUGMSG("Driver items got"); } else { DEBUGMSG("Driver updates not supported"); } if (fExclusiveItemFound) { AUCatalogItemList dummydriverList; hr = MergeDetectionResult(NULL, dummydriverList, FALSE, bstrNonDriverInstall, nonDriverList, fExclusiveItemFound); DEBUGMSG("Exclusive item found"); } else if (fExclusiveDriverFound) { AUCatalogItemList dummynonDriverList; hr = MergeDetectionResult(bstrDriverInstall, driverList, fExclusiveDriverFound, NULL, dummynonDriverList, FALSE); DEBUGMSG("Exclusive driver found"); } else { hr = MergeDetectionResult(bstrDriverInstall, driverList, fExclusiveDriverFound, bstrNonDriverInstall, nonDriverList, fExclusiveItemFound); DEBUGMSG("Merge detection result for non driver and driver"); } if (FAILED(hr)) { DEBUGMSG("MergeDetectionResult fail with error %#lx", hr); goto done; } if (m_ItemList.Count() == m_ItemList.GetNumHidden()) { //nothing to show to the user hr = S_FALSE; goto done; } #ifdef DBG // m_ItemList.DbgDump(); #endif if (!fUpdate) { BSTR bstrNonDrivers; if (NULL == (bstrNonDrivers =ReadXMLFromFile(ITEM_FILE))) { DEBUGMSG("Fail to read item file "); goto done; } hr = BuildDependencyList(m_ItemList, bstrDriverInstall, bstrNonDrivers); SysFreeString(bstrNonDrivers); if (FAILED(hr)) { DEBUGMSG("fail to build dependency list with error %#lx", hr); goto done; } hr = DownloadRTFsnEULAs(GetSystemDefaultLangID()); DEBUGMSG("downloading RTF and EULAs %s", FAILED(hr)? "failed" : "succeeded"); setExpireTime(); Serialize(); } done: FreeIU(); SafeFreeBSTR(bstrNonDriverInstall); SafeFreeBSTR(bstrDriverInstall); if (FAILED(hr)) { Clear(); } DEBUGMSG("CAUCatalog::DetectItems() ends"); return hr; } HRESULT AUCatalog::MergeDetectionResult(BSTR bstrDriverInstall, AUCatalogItemList & driverlist, BOOL fExclusiveDriverFound, BSTR bstrNonDriverInstall, AUCatalogItemList & nondriverlist, BOOL fExclusiveItemFound) { HRESULT hr= S_OK; UINT uDriverNum = driverlist.Count(); UINT uNonDriverNum = nondriverlist.Count(); UINT nums[2] = {uDriverNum, uNonDriverNum}; AUCatalogItemList * pitemlists[2] = {&driverlist, &nondriverlist}; if (fExclusiveDriverFound || fExclusiveItemFound) { //no merge needed DEBUGMSG("Exclusive driver or non driver found, no need to merge"); AUCatalogItemList *pItemList = fExclusiveDriverFound ? &driverlist : & nondriverlist; BSTR bstrInstall = fExclusiveDriverFound? bstrDriverInstall : bstrNonDriverInstall; if (FAILED(hr = m_ItemList.Copy(*pItemList))) { goto done; } if (NULL == (m_bstrInstallation = SysAllocString(bstrInstall))) { hr = E_OUTOFMEMORY; DEBUGMSG("OUT of memory: fail to alloc string"); goto done; } } else { for (UINT j = 0; j < ARRAYSIZE(nums) ; j++) { for (UINT i = 0; i < nums[j]; i++) { AUCatalogItem * pItem = new AUCatalogItem((*pitemlists[j])[i]); if (NULL == pItem) { DEBUGMSG("Fail to create item"); hr = E_FAIL; goto done; } if (!pItem->fEqual((*pitemlists[j])[i])) { DEBUGMSG("Fail to create item"); hr = E_OUTOFMEMORY; delete pItem; goto done; } if (!m_ItemList.Add(pItem)) { hr = E_OUTOFMEMORY; delete pItem; goto done; } } } hr = MergeCatalogs(bstrDriverInstall, bstrNonDriverInstall, &m_bstrInstallation); } done: if (FAILED(hr)) { Clear(); } return hr; } // go through 1 cycle to detect driver items HRESULT AUCatalog::DetectDriverItems(OUT BSTR *pbstrInstall, OUT AUCatalogItemList &itemList, BOOL *pfFoundExclusiveItem) { HRESULT hr = S_OK; BSTR bstrManifest; if (NULL == pbstrInstall || NULL == pfFoundExclusiveItem) { return E_INVALIDARG; } DEBUGMSG("CAUCatalog detecting driver items..."); *pbstrInstall = NULL; *pfFoundExclusiveItem = FALSE; itemList.Clear(); #ifdef DBG if (fDBGUseLocalFile()) { DEBUGMSG("Use local file instead of going on line"); if (NULL == (bstrManifest = ReadXMLFromFile(DRIVERS_FILE))) { DEBUGMSG("fail to get drivers from file %s", DRIVERS_FILE); hr = E_FAIL; goto end; } } else #endif { if (FAILED(hr = GetManifest(DRIVERS_LEVEL, NULL, &bstrManifest))) { DEBUGMSG(" Fail to get drivers manifest %#lx", hr); goto end; } if (S_FALSE == hr) { //no updates applicable goto end; } } *pbstrInstall = bstrManifest; if (!fExtractItemInfo(*pbstrInstall, itemList, pfFoundExclusiveItem)) { DEBUGMSG("fail to extract information for driver items"); hr = E_FAIL; goto end; } #ifdef DBG // itemList.DbgDump(); #endif end: DEBUGMSG("CAUCatalog detecting driver items done"); if (FAILED(hr)) { SafeFreeBSTRNULL(*pbstrInstall); *pfFoundExclusiveItem = FALSE; itemList.Clear(); } return hr; } // go through 4 cycles to detect software items // get down manifest HRESULT AUCatalog::DetectNonDriverItems(OUT BSTR *pbstrInstall, OUT AUCatalogItemList &itemList, OUT BOOL *pfFoundExclusiveItem) { HRESULT hr = S_OK; BSTR bstrManifest = NULL; BSTR bstrResult=NULL; if (NULL == pbstrInstall || NULL == pfFoundExclusiveItem) { return E_INVALIDARG; } DEBUGMSG("CAUCatalog detecting non driver items..."); *pbstrInstall = NULL; *pfFoundExclusiveItem = FALSE; itemList.Clear(); #ifdef DBG if (fDBGUseLocalFile()) { DEBUGMSG("Use local file instead of going on line"); if (NULL == (bstrManifest = ReadXMLFromFile(DETAILS_FILE))) { hr = E_FAIL; DEBUGMSG("Fail to get item details from file %s", DETAILS_FILE); goto end; } } else #endif { for (int enLevel = MIN_LEVEL; enLevel <= MAX_LEVEL; enLevel++) { DEBUGMSG("#%d pass", enLevel+1); hr = GetManifest((DETECTLEVEL)enLevel, bstrResult, &bstrManifest); SafeFreeBSTR(bstrResult); if (FAILED(hr)) { DEBUGMSG(" Fail to get %s %#lx", GetLevelStr((DETECTLEVEL)enLevel), hr); goto end; } if (S_FALSE == hr) { goto end; } DEBUGMSG("%s got", GetLevelStr((DETECTLEVEL)enLevel)); if (DETAILS_LEVEL != enLevel) { DEBUGMSG("Doing detection........"); hr = DoDetection((DETECTLEVEL)enLevel, bstrManifest, &bstrResult); SafeFreeBSTR(bstrManifest); if (FAILED(hr)) { DEBUGMSG("Fail to do detection %#lx", hr); goto end; } } } } *pbstrInstall = bstrManifest; if (!fExtractItemInfo(bstrManifest, itemList, pfFoundExclusiveItem)) { DEBUGMSG("Fail to extract item information for non drivers"); hr = E_FAIL; goto end; } #ifdef DBG // itemList.DbgDump(); #endif end: DEBUGMSG("CAUCatalog detecting non driver items done"); if (FAILED(hr)) { SafeFreeBSTRNULL(*pbstrInstall); *pfFoundExclusiveItem = FALSE; itemList.Clear(); } if (gpState->fInCorpWU()) { if (SUCCEEDED(hr)) { gPingStatus.PingDetectionSuccess(TRUE, itemList.Count()); } else { gPingStatus.PingDetectionFailure(TRUE, hr); } } return hr; } ////////////////////////////////////////////////////////////////////////////////////////////// // delete all local cat log files we might use to do offline operation, including item.xml details.xml, // mergedcatalog.xml, drivers.xml and catalog.xml. If not fUpdate (i.e., will build everything from scratch), also clean up RTFs and Cabs ///////////////////////////////////////////////////////////////////////////////////////////// void AUCatalog::DelCatFiles(BOOL fUpdate) { TCHAR tszPath[MAX_PATH]; TCHAR tszFullFileName[MAX_PATH]; DEBUGMSG("DelCatFiles()"); #ifdef DBG if (fDBGUseLocalFile()) { DEBUGMSG("When use local file in debugging mode, do not delete local catalog files"); return; } else #endif { AUASSERT(_T('\0') != g_szWUDir[0]); if (FAILED(StringCchCopyEx(tszPath, ARRAYSIZE(tszPath) , g_szWUDir, NULL, NULL, MISTSAFE_STRING_FLAGS))) { return; } LPCTSTR FILES_TO_DELETE[] = {ITEM_FILE, DRIVERS_FILE, DETAILS_FILE, #ifdef DBG DETECT1_FILE, DETECT2_FILE, DETECT3_FILE, DRIVER_SYSSPEC_FILE, NONDRIVER_SYSSPEC_FILE, PROVIDER_FILE, PRODUCT_FILE, INSTALL_FILE, #endif CATALOG_FILE }; for (int i = 0; i< ARRAYSIZE(FILES_TO_DELETE); i++) { if (SUCCEEDED(StringCchCopyEx(tszFullFileName, ARRAYSIZE(tszFullFileName) , tszPath, NULL, NULL, MISTSAFE_STRING_FLAGS)) && SUCCEEDED(StringCchCatEx(tszFullFileName, ARRAYSIZE(tszFullFileName), FILES_TO_DELETE[i], NULL, NULL, MISTSAFE_STRING_FLAGS))) { AUDelFileOrDir(tszFullFileName); } } if (!fUpdate) { TCHAR tszDownloadTmpDir[MAX_PATH]; if (SUCCEEDED(GetDownloadPath(tszDownloadTmpDir, ARRAYSIZE(tszDownloadTmpDir)))) { DelDir(tszDownloadTmpDir); RemoveDirectory(tszDownloadTmpDir); } } } } //////////////////////////////////////////// // caller needs to free the returned BSTR //////////////////////////////////////////// BSTR GetCatalogFile(void) { TCHAR szFile[MAX_PATH]; AUASSERT(_T('\0') != g_szWUDir[0]); if (FAILED(StringCchCopyEx(szFile, ARRAYSIZE(szFile), g_szWUDir, NULL, NULL, MISTSAFE_STRING_FLAGS))|| FAILED(StringCchCatEx(szFile, ARRAYSIZE(szFile), CATALOG_FILE, NULL, NULL, MISTSAFE_STRING_FLAGS))) { return NULL; } return SysAllocString(T2W(szFile)); } //======================================================================= // // AUCatalog::Serialize // //======================================================================= HRESULT AUCatalog::Serialize(void) { HRESULT hr = S_OK; DEBUGMSG("WUAUENG: serializing"); BSTR bstrCatFile = NULL ; IXMLDOMDocument *pxmlCatalog = NULL; IXMLDOMElement *pelemAUCATALOG = NULL; AU_VARIANT varValueVERSION(CATALOG_XML_VERSION); AU_VARIANT varValueDOWNLOADID(m_audownloader.getID()); AU_VARIANT varValueITEMCOUNT(m_ItemList.Count()); AU_VARIANT varValueUpdateDriver(m_fUpdateDriver); if (NULL == (bstrCatFile = GetCatalogFile())) { DEBUGMSG("Fail to get catalog file with error %#lx", hr); goto done; } AUDelFileOrDir(W2T(bstrCatFile)); //delete old catalog file if ( FAILED(hr = CoCreateInstance(__uuidof(DOMDocument), NULL, CLSCTX_INPROC_SERVER, __uuidof(IXMLDOMDocument), (void**)&pxmlCatalog)) || FAILED(hr = pxmlCatalog->createElement(bstrTagAUCATALOG, &pelemAUCATALOG)) || FAILED(hr = pelemAUCATALOG->setAttribute(bstrAttrVERSION, varValueVERSION)) || FAILED(hr = pelemAUCATALOG->setAttribute(bstrAttrDOWNLOADID, varValueDOWNLOADID)) || FAILED(hr = pelemAUCATALOG->setAttribute(bstrAttrITEMCOUNT, varValueITEMCOUNT)) || FAILED(hr = pelemAUCATALOG->setAttribute(bstrAttrUpdateDriver, varValueUpdateDriver)) || FAILED(hr = pxmlCatalog->appendChild(pelemAUCATALOG, NULL)) ) { DEBUGMSG("Fail to create Catalog.xml"); goto done; } VARIANT varValueID; VARIANT varValueSTATUS; varValueID.vt = VT_BSTR; varValueSTATUS.vt = VT_I4; // write out item information for ( DWORD index = 0; index < m_ItemList.Count(); index++ ) { IXMLDOMElement *pelemITEM = NULL; varValueID.bstrVal = m_ItemList[index].bstrID(); varValueSTATUS.lVal = m_ItemList[index].dwStatus(); // DEBUGMSG("Status is %d for item %S", varValueSTATUS.lVal, m_ItemList[index].bstrID()); if ( FAILED(hr = pxmlCatalog->createElement(bstrTagITEM, &pelemITEM)) || FAILED(hr = pelemITEM->setAttribute(bstrAttrID, varValueID)) || FAILED(hr = pelemITEM->setAttribute(bstrAttrSTATUS, varValueSTATUS)) || FAILED(hr = pelemAUCATALOG->appendChild(pelemITEM, NULL)) ) { SafeRelease(pelemITEM); goto done; } SafeRelease(pelemITEM); } if ( FAILED(hr = SaveDocument(pxmlCatalog, bstrCatFile))) { DEBUGMSG("saving of %S failed, hr = %#lx", bstrCatFile, hr); if ( SUCCEEDED(hr) ) { hr = E_FAIL; } goto done; } done: if (FAILED(hr) && NULL != bstrCatFile) { AUDelFileOrDir(bstrCatFile); } SafeFreeBSTR(bstrCatFile); SafeRelease(pelemAUCATALOG); SafeRelease(pxmlCatalog); return hr; } //======================================================================= // // AUCatalog::Unserialize // //======================================================================= HRESULT AUCatalog::Unserialize() { // USES_CONVERSION; DEBUGMSG("WUAUENG: unserializing"); HRESULT hr = S_OK; IXMLDOMDocument *pxmlCatalog = NULL; IXMLDOMNodeList *pitemnodes = NULL; IXMLDOMNode *pcatalog = NULL; BSTR bstrCatFile = NULL; long lVersion; long lItemCount; BSTR bstrDownloadId = NULL; GUID downloadId; if (NULL == (bstrCatFile = GetCatalogFile())) { DEBUGMSG("Fail to get catalog file with error %#lx", hr); goto done; } if ( FAILED(hr = LoadDocument(bstrCatFile, &pxmlCatalog, TRUE))) { DEBUGMSG("Could not Load catalog file with error %#lx", hr); goto done; } //get catalog node (root) if (!FindNode(pxmlCatalog, bstrTagAUCATALOG, &pcatalog)) { hr = E_FAIL; DEBUGMSG("fail to find catalog node "); goto done; } // get version if ( FAILED(hr = GetAttribute(pcatalog, bstrAttrVERSION, &lVersion))) { DEBUGMSG("Fail to get version with error %#lx", hr); goto done; } DEBUGMSG("Catalog Version Number is %d", lVersion); if ( CATALOG_XML_VERSION != lVersion ) { DEBUGMSG("invalid XML version"); hr = E_FAIL; goto done; } // get DOWNLOADID if ( FAILED(hr = GetAttribute(pcatalog, bstrAttrDOWNLOADID, &bstrDownloadId)) || FAILED(hr = CLSIDFromString(bstrDownloadId, &downloadId))) { DEBUGMSG("failed to get download id with error %#lx", hr); goto done; } if (GUID_NULL != downloadId) { m_audownloader.setID(downloadId); m_fNeedToContinueJob = TRUE; } // get ITEMCOUNT if ( FAILED(hr = GetAttribute(pcatalog, bstrAttrITEMCOUNT, &lItemCount))) { DEBUGMSG("failed to get item count with error %#lx", hr); goto done; } if (m_fUpdateDriver) { if (FAILED(hr = GetAttribute(pcatalog, bstrAttrUpdateDriver, &m_fUpdateDriver))) { DEBUGMSG("failed to get fUpdateDriver with error %#lx", hr); goto done; } } DEBUGMSG("Catalog item count is %d", lItemCount); if (FAILED(hr = m_ItemList.Allocate(lItemCount))) { DEBUGMSG("Out of memory, fail to allocate item list"); goto done; } if ( NULL == (pitemnodes = FindDOMNodeList(pcatalog, bstrTagITEM))) { hr = E_FAIL; DEBUGMSG("Fail to find items in the catalog "); goto done; } // read in item list for ( DWORD index = 0; index < m_ItemList.Count(); index++ ) { IXMLDOMNode *pitemnode = NULL; if ( S_OK != (hr = pitemnodes->get_item(index, &pitemnode)) ) { DEBUGMSG("failed to get item node %d", index); hr = FAILED(hr) ? hr : E_FAIL; goto done; } // get ID if ( FAILED(hr = GetAttribute(pitemnode, bstrAttrID, &(m_ItemList[index].m_bstrID)))) { DEBUGMSG("Fail to find ID for item %d", index); SafeRelease(pitemnode); goto done; } // get STATUS if ( FAILED(hr = GetAttribute(pitemnode, bstrAttrSTATUS, (long*)(&(m_ItemList[index].m_dwStatus))))) { DEBUGMSG("Fail to find status for item %d with error %#lx", index, hr); SafeRelease(pitemnode); goto done; } // DEBUGMSG("item %S status is %d", m_ItemList[index].m_bstrID, m_ItemList[index].m_dwStatus); pitemnode->Release(); } //populate m_ItemList with other information than itemID and status hr = GetDetailedItemInfoFromDisk(m_ItemList, &m_bstrInstallation, m_fUpdateDriver); done: SafeFreeBSTR(bstrDownloadId); SafeFreeBSTR(bstrCatFile); SafeRelease(pcatalog); SafeRelease(pitemnodes); SafeRelease(pxmlCatalog); if (FAILED(hr)) { DelCatFiles(); Clear(); } DEBUGMSG("WUAUENG unserializing done with result %#lx", hr); return hr; } //only download RTFs for now HRESULT AUCatalog::DownloadRTFsnEULAs(LANGID langid) { BSTR bstrRTFUrl, bstrEULAUrl; TCHAR tszLocalRTFDir[MAX_PATH]; HRESULT hr; if (FAILED(hr = GetRTFDownloadPath(tszLocalRTFDir, ARRAYSIZE(tszLocalRTFDir), langid))) { DEBUGMSG("Fail to get RTF download path %#lx", hr); goto done; } DEBUGMSG("Got RTF path %S", tszLocalRTFDir); UINT uItemCount = m_ItemList.Count(); // DEBUGMSG("Downloading %d RTFs", uItemCount); for (UINT i = 0; i