windows-nt/Source/XPSP1/NT/enduser/windows.com/wuau/wuauclt/installcallback.cpp
2020-09-26 16:20:57 +08:00

454 lines
12 KiB
C++

//=======================================================================
//
// 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;
}