//======================================================================= // // Copyright (c) 2001 Microsoft Corporation. All Rights Reserved. // // File: AUCltCatalog.cpp // // Creator: PeterWi // // Purpose: Client AU Catalog Functions // //======================================================================= #include "pch.h" #include "iuprogress.h" #include "AUEventMsgs.h" //======================================================================= // // CInstallCallback::QueryInterface // //======================================================================= STDMETHODIMP CInstallCallback::QueryInterface(REFIID riid, void **ppvObject) { if ( (riid == __uuidof(IUnknown)) || (riid == IID_IProgressListener) ) { *ppvObject = this; AddRef(); } else { *ppvObject = NULL; return E_NOINTERFACE; } return S_OK; } //======================================================================= // // CInstallCallback::AddRef // //======================================================================= STDMETHODIMP_(ULONG) CInstallCallback::AddRef(void) { return InterlockedIncrement(&m_refs);; } //======================================================================= // // CInstallCallback::Release // //======================================================================= STDMETHODIMP_(ULONG) CInstallCallback::Release(void) { return InterlockedDecrement(&m_refs); } //======================================================================= // // CInstallCallback::OnItemStart // //======================================================================= STDMETHODIMP CInstallCallback::OnItemStart( IN BSTR /*bstrUuidOperation*/, IN BSTR bstrXmlItem, OUT LONG *plCommandRequest) { DEBUGMSG("InstallProgressListener::OnItemStart(%S)", bstrXmlItem); *plCommandRequest = 0; return S_OK; } //======================================================================= // // CInstallCallback::OnProgress // //======================================================================= STDMETHODIMP CInstallCallback::OnProgress( IN BSTR /*bstrUuidOperation*/, IN VARIANT_BOOL fItemCompleted, IN BSTR bstrProgress, OUT LONG *plCommandRequest) { DEBUGMSG("InstallProgressListener::OnProgress(%S), %s", bstrProgress, (VARIANT_TRUE == fItemCompleted) ? "completed" : "ongoing"); *plCommandRequest = 0; if ( fItemCompleted ) { SendMessage(ghCurrentDialog, AUMSG_INSTALL_PROGRESS, 0, 0); } return S_OK; } //======================================================================= // // CInstallCallback::OnOperationComplete // //======================================================================= HRESULT LogEventToServer( IUpdates *pUpdates, WORD wType, WORD wCategory, DWORD dwEventID, DWORD dwItemCount, BSTR *pbstrItems); STDMETHODIMP CInstallCallback::OnOperationComplete( /* [in] */ BSTR bstrUuidOperation, /* [in] */ BSTR bstrXmlItems) { DEBUGMSG("InstallProgressListener::OnOperationComplete() for %S", bstrUuidOperation); HRESULT hr; #ifdef DBG LOGXMLFILE(INSTALLRESULTS_FILE, bstrXmlItems); #endif // determine if reboot needed IXMLDOMDocument *pxmlInstallResult = NULL; IXMLDOMNodeList *pItemStatuses = NULL; BSTR *pbstrItemsSucceeded = NULL; BSTR *pbstrItemsFailed = NULL; BSTR *pbstrItemsNeedReboot = NULL; IXMLDOMNode *pItemStatus = NULL; IXMLDOMNode *pChild = NULL; BSTR bstrTitle = NULL; BSTR bstrStatus = NULL; DWORD dwNumOfItemsSucceeded = 0; DWORD dwNumOfItemsFailed = 0; DWORD dwNumOfItemsNeedReboot = 0; IUpdates *pUpdates = NULL; BOOL fCoInit = FALSE; BSTR bstrItemStatusXPath = SysAllocString(L"items/itemStatus"); BSTR bstrTitleXPath = SysAllocString(L"description/descriptionText/title"); BSTR bstrItemStatusNode = SysAllocString(L"installStatus"); BSTR bstrValueAttribute = SysAllocString(L"value"); BSTR bstrNeedsRebootAttribute = SysAllocString(L"needsReboot"); if (NULL == bstrItemStatusXPath || NULL == bstrTitleXPath || NULL == bstrItemStatusNode || NULL == bstrValueAttribute || NULL == bstrNeedsRebootAttribute) { hr = E_OUTOFMEMORY; goto CleanUp; } if (FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() CoInitialize failed (%#lx)", hr); goto CleanUp; } fCoInit = TRUE; if ( FAILED(hr = LoadXMLDoc(bstrXmlItems, &pxmlInstallResult)) ) { DEBUGMSG("InstallProgressListener::OnOperationComplete() call to LoadXMLDoc() failed (%#lx)", hr); pxmlInstallResult = NULL; goto CleanUp; } if (FAILED(hr = pxmlInstallResult->selectNodes(bstrItemStatusXPath, &pItemStatuses)) ) { DEBUGMSG("InstallProgressListener::OnOperationComplete() fail to select node"); pItemStatuses = NULL; goto CleanUp; } long lLen; if (FAILED(hr = pItemStatuses->get_length(&lLen))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() fail to get count of item statuses"); goto CleanUp; } if (0 >= lLen) { DEBUGMSG("InstallProgressListener::OnOperationComplete() no item statuses found"); hr = E_INVALIDARG; goto CleanUp; } if (NULL == (pbstrItemsSucceeded = (BSTR *) malloc(sizeof(BSTR) * lLen)) || NULL == (pbstrItemsFailed = (BSTR *) malloc(sizeof(BSTR) * lLen)) || NULL == (pbstrItemsNeedReboot = (BSTR *) malloc(sizeof(BSTR) * lLen))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() failed to alloc memory for BSTR *'s"); hr = E_OUTOFMEMORY; goto CleanUp; } for (long index = 0; index < lLen; index++) { if (S_OK != (hr = pItemStatuses->get_item(index, &pItemStatus))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() call to get_item() failed (%#lx)", hr); pItemStatus = NULL; if (S_FALSE == hr) { hr = E_FAIL; } goto CleanUp; } if (S_OK != (hr = pItemStatus->selectSingleNode(bstrTitleXPath, &pChild))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() call to selectSingleNode() failed (%#lx)", hr); pChild = NULL; if (S_FALSE == hr) { hr = E_INVALIDARG; } goto CleanUp; } if (S_OK != (hr = GetText(pChild, &bstrTitle))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() call to GetText() failed (%#lx)", hr); bstrTitle = NULL; if (S_FALSE == hr) { hr = E_INVALIDARG; } goto CleanUp; } pChild->Release(); pChild = NULL; if (S_OK != (hr = pItemStatus->selectSingleNode(bstrItemStatusNode, &pChild))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() call to selectSingleNode() failed (%#lx)", hr); pChild = NULL; if (S_FALSE == hr) { hr = E_INVALIDARG; } goto CleanUp; } if (S_OK != (hr = GetAttribute(pChild, bstrValueAttribute, &bstrStatus))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() call to GetAttribute(..., \"value\", ...) failed (%#lx)", hr); bstrStatus = NULL; if (S_FALSE == hr) { hr = E_INVALIDARG; } goto CleanUp; } if (CSTR_EQUAL == WUCompareStringI(bstrStatus, L"COMPLETE")) { BOOL fReboot; if (S_OK != (hr = GetAttribute(pChild, bstrNeedsRebootAttribute, &fReboot))) { DEBUGMSG("InstallProgressListener::OnOperationComplete() call to GetAttribute(..., \"needsReboot\", ...) failed (%#lx)", hr); if (S_FALSE == hr) { hr = E_INVALIDARG; } goto CleanUp; } if (fReboot) { pbstrItemsNeedReboot[dwNumOfItemsNeedReboot++] = bstrTitle; gpClientCatalog->m_fReboot = TRUE; } pbstrItemsSucceeded[dwNumOfItemsSucceeded++] = bstrTitle; // Now pbstrItemsSucceeded is responsible to free the BSTR. } else if (CSTR_EQUAL == WUCompareStringI(bstrStatus, L"FAILED")) { pbstrItemsFailed[dwNumOfItemsFailed++] = bstrTitle; // Now pbstrItemsFailed is responsible to free the BSTR. } SysFreeString(bstrStatus); bstrStatus = NULL; pChild->Release(); pChild = NULL; bstrTitle = NULL; } if (FAILED(hr = CoCreateInstance(__uuidof(Updates), NULL, CLSCTX_LOCAL_SERVER, IID_IUpdates, (LPVOID*)&pUpdates))) { DEBUGMSG("LogEventToServer failed to get Updates object (%#lx)", hr); goto CleanUp; } if (0 < dwNumOfItemsSucceeded) { DEBUGMSG("InstallProgressListener::OnOperationComplete() %lu items was successfully installed", dwNumOfItemsSucceeded); LogEventToServer( pUpdates, EVENTLOG_INFORMATION_TYPE, IDS_MSG_Installation, IDS_MSG_InstallationSuccessful, dwNumOfItemsSucceeded, pbstrItemsSucceeded); } if (0 < dwNumOfItemsFailed) { DEBUGMSG("InstallProgressListener::OnOperationComplete() %lu items failed to install", dwNumOfItemsFailed); LogEventToServer( pUpdates, EVENTLOG_ERROR_TYPE, IDS_MSG_Installation, IDS_MSG_InstallationFailure, dwNumOfItemsFailed, pbstrItemsFailed); } if (0 < dwNumOfItemsNeedReboot) { DEBUGMSG("InstallProgressListener::OnOperationComplete() %lu items was installed and require reboot", dwNumOfItemsNeedReboot); AUOPTION auopt; if (SUCCEEDED(hr = pUpdates->get_Option(&auopt)) && AUOPTION_SCHEDULED == auopt.dwOption) { LogEventToServer( pUpdates, EVENTLOG_INFORMATION_TYPE, IDS_MSG_Installation, IDS_MSG_RestartNeeded_Scheduled, dwNumOfItemsNeedReboot, pbstrItemsNeedReboot); } else { LogEventToServer( pUpdates, EVENTLOG_INFORMATION_TYPE, IDS_MSG_Installation, IDS_MSG_RestartNeeded_Unscheduled, dwNumOfItemsNeedReboot, pbstrItemsNeedReboot); } } CleanUp: SafeFreeBSTR(bstrItemStatusXPath); SafeFreeBSTR(bstrTitleXPath); SafeFreeBSTR(bstrItemStatusNode); SafeFreeBSTR(bstrValueAttribute); SafeFreeBSTR(bstrNeedsRebootAttribute); SafeRelease(pUpdates); SysFreeString(bstrStatus); SysFreeString(bstrTitle); SafeRelease(pChild); SafeRelease(pItemStatus); SafeFree(pbstrItemsNeedReboot); if (NULL != pbstrItemsFailed) { while(dwNumOfItemsFailed > 0) { SysFreeString(pbstrItemsFailed[--dwNumOfItemsFailed]); } free(pbstrItemsFailed); } if (NULL != pbstrItemsSucceeded) { while(dwNumOfItemsSucceeded > 0) { SysFreeString(pbstrItemsSucceeded[--dwNumOfItemsSucceeded]); } free(pbstrItemsSucceeded); } SafeRelease(pItemStatuses); SafeRelease(pxmlInstallResult); if (fCoInit) { CoUninitialize(); } DEBUGMSG("InstallProgressListener::OnOperationComplete() ends"); return hr; } HRESULT LogEventToServer( IUpdates *pUpdates, WORD wType, WORD wCategory, DWORD dwEventID, DWORD dwItemCount, BSTR *pbstrItems) { DEBUGMSG("LogEventToServer"); HRESULT hr; SAFEARRAY *psa; SAFEARRAYBOUND bound[1] = { dwItemCount, 0}; if (NULL == (psa = SafeArrayCreate(VT_BSTR, 1, bound))) { DEBUGMSG("LogEventToServer failed to create safearray"); hr = E_OUTOFMEMORY; goto CleanUp; } BSTR *pbstrElements; if (S_OK != (hr = SafeArrayAccessData(psa, (void **)&pbstrElements))) { DEBUGMSG("LogEventToServer failed to access savearray date (%#lx)", hr); goto CleanUp; } for ( DWORD i = 0; i < dwItemCount; i++ ) { if (NULL == (pbstrElements[i] = SysAllocString(pbstrItems[i]))) { DEBUGMSG("LogEventToServer failed to allocate BSTR memory"); hr = E_OUTOFMEMORY; break; } } if (S_OK != (hr = SafeArrayUnaccessData(psa))) { DEBUGMSG("LogEventToServer failed to unaccess safearray data (%#lx)", hr); } if (FAILED(hr)) { goto CleanUp; } VARIANT varItems; varItems.vt = VT_ARRAY | VT_BSTR; varItems.parray = psa; hr = pUpdates->LogEvent(wType, wCategory, dwEventID, varItems); if (FAILED(hr)) { DEBUGMSG("LogEventToServer failed to call pUpdates->LogEvent (%#lx)", hr); } CleanUp: if (NULL != psa) { (void) SafeArrayDestroy(psa); } return hr; }