mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2209 lines
53 KiB
2209 lines
53 KiB
//=======================================================================
|
|
//
|
|
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// File: SchemaMisc.CPP
|
|
//
|
|
// Author: Charles Ma
|
|
// 2000.10.27
|
|
//
|
|
// Description:
|
|
//
|
|
// Implement helper functions related to IU schemas
|
|
//
|
|
//=======================================================================
|
|
|
|
//#include "iuengine.h" // PCH - must include first
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <ole2.h>
|
|
//#include "iu.h"
|
|
#include <iucommon.h>
|
|
|
|
#include "schemamisc.h"
|
|
#include <MemUtil.h>
|
|
#include "regutil.h"
|
|
#include "fileutil.h"
|
|
#include "stringutil.h"
|
|
#include <shlwapi.h> // pathappend() api
|
|
#include "schemakeys.h"
|
|
#include <URLLogging.h>
|
|
#include <MISTSAFE.h>
|
|
|
|
#include<wusafefn.h>
|
|
|
|
//
|
|
// max length of platform when being converted into string
|
|
// this is an artificial number that we think enough to
|
|
// take any MS platform data.
|
|
//
|
|
const UINT MAX_PLATFORM_STR_LEN = 1024;
|
|
|
|
//
|
|
// private flags used by functions to retrieve string data
|
|
//
|
|
const DWORD SKIP_SUITES = 0x1;
|
|
const DWORD SKIP_SERVICEPACK_VER = 0x2;
|
|
|
|
const long MAX_VERSION = 256;
|
|
|
|
const TCHAR REGKEY_IUCTL[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\IUControl");
|
|
const TCHAR REGVAL_SCHEMAVALIDATION[] = _T("ValidateSchema");
|
|
|
|
//
|
|
// Global pointer gets initialized to NULL by runtime. Any module including schemamisc.h must
|
|
// allocate this object following its call to CoInitialize, and delete the object before
|
|
// calling CoUninitialize.
|
|
//
|
|
CSchemaKeys * g_pGlobalSchemaKeys /* = NULL */;
|
|
|
|
#define QuitIfNull(p) {if (NULL == p) {hr = E_INVALIDARG; return hr;}}
|
|
#define QuitIfFail(x) {hr = x; if (FAILED(hr)) goto CleanUp;}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FindSingleDOMNode()
|
|
//
|
|
// Retrieve the first xml node with the given tag name under the given parent node
|
|
// Return value:
|
|
// S_OK if *ppNode returns matching node value
|
|
// HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if node not found
|
|
// FAILED() otherwise
|
|
// Caller is responsible for releasing *ppNode.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT FindSingleDOMNode(IXMLDOMNode* pParentNode, BSTR bstrName, IXMLDOMNode** ppNode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
QuitIfNull(ppNode);
|
|
*ppNode = NULL;
|
|
QuitIfNull(pParentNode);
|
|
QuitIfNull(bstrName);
|
|
|
|
hr = pParentNode->selectSingleNode(bstrName, ppNode);
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
*ppNode = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FindSingleDOMNode()
|
|
//
|
|
// Retrieve the first xml node with the given tag name in the given xml doc
|
|
// Return value:
|
|
// S_OK if *ppNode returns matching node value
|
|
// HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if node not found
|
|
// FAILED() otherwise
|
|
// Caller is responsible for releasing *ppNode.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT FindSingleDOMNode(IXMLDOMDocument* pDoc, BSTR bstrName, IXMLDOMNode** ppNode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMNode *pParentNode = NULL;
|
|
|
|
QuitIfNull(ppNode);
|
|
*ppNode = NULL;
|
|
QuitIfNull(pDoc);
|
|
QuitIfNull(bstrName);
|
|
if (SUCCEEDED(hr = pDoc->QueryInterface(IID_IXMLDOMNode, (void**)&pParentNode)))
|
|
{
|
|
hr = FindSingleDOMNode(pParentNode, bstrName, ppNode);
|
|
SafeRelease(pParentNode);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FindDOMNodeList()
|
|
//
|
|
// Retrieve the xml nodelist with the given tag name under the given parent node
|
|
// Return value: NULL if failed or no match; matching node list otherwise.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
IXMLDOMNodeList* FindDOMNodeList(IXMLDOMNode* pParentNode, BSTR bstrName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMNodeList *pNodeList = NULL;
|
|
LONG lLength = 0;
|
|
|
|
if (NULL == pParentNode ||
|
|
NULL == bstrName ||
|
|
FAILED(pParentNode->selectNodes(bstrName, &pNodeList)) ||
|
|
NULL == pNodeList)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (SUCCEEDED(pNodeList->get_length(&lLength)) &&
|
|
lLength > 0)
|
|
{
|
|
return pNodeList;
|
|
}
|
|
|
|
SafeRelease(pNodeList);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FindDOMNodeList()
|
|
//
|
|
// Retrieve the xml nodelist with the given tag name in the given xml doc
|
|
// Return value: NULL if failed or no match; matching node list otherwise.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
IXMLDOMNodeList* FindDOMNodeList(IXMLDOMDocument* pDoc, BSTR bstrName)
|
|
{
|
|
IXMLDOMNode *pParentNode = NULL;
|
|
IXMLDOMNodeList *pNodeList = NULL;
|
|
|
|
if (NULL != pDoc &&
|
|
NULL != bstrName &&
|
|
SUCCEEDED(pDoc->QueryInterface(IID_IXMLDOMNode, (void**)&pParentNode)))
|
|
{
|
|
pNodeList = FindDOMNodeList(pParentNode, bstrName);
|
|
pParentNode->Release();
|
|
}
|
|
return pNodeList;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CreateDOMNode()
|
|
//
|
|
// Create an xml node of the given type
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
IXMLDOMNode* CreateDOMNode(IXMLDOMDocument* pDoc, SHORT nType, BSTR bstrName, BSTR bstrNamespaceURI /*= NULL*/)
|
|
{
|
|
if (NULL == pDoc ||
|
|
(NODE_TEXT != nType && NULL == bstrName))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
IXMLDOMNode *pNode = NULL;
|
|
VARIANT vType;
|
|
VariantInit(&vType);
|
|
|
|
vType.vt = VT_I2;
|
|
vType.iVal = nType;
|
|
|
|
if (S_OK != pDoc->createNode(vType, bstrName, bstrNamespaceURI, &pNode))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pNode;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetAttribute()
|
|
//
|
|
// Get attribute (integer) from the xml node
|
|
// If function fails, *piAttr preserves original value.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, INT* piAttr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(pNode);
|
|
QuitIfNull(bstrName);
|
|
QuitIfNull(piAttr);
|
|
|
|
VARIANT vAttr;
|
|
IXMLDOMElement *pElement = NULL;
|
|
IXMLDOMAttribute *pAttrNode = NULL;;
|
|
|
|
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
|
|
QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
|
|
if (NULL == pAttrNode) goto CleanUp;
|
|
|
|
QuitIfFail(pAttrNode->get_value(&vAttr));
|
|
if (VT_INT == vAttr.vt)
|
|
{
|
|
*piAttr = vAttr.intVal;
|
|
}
|
|
else if (VT_BSTR == vAttr.vt)
|
|
{
|
|
*piAttr = (INT)MyBSTR2L(vAttr.bstrVal);
|
|
}
|
|
else if (VT_I2 == vAttr.vt)
|
|
{
|
|
*piAttr = vAttr.iVal;
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
VariantClear(&vAttr);
|
|
|
|
CleanUp:
|
|
SafeRelease(pElement);
|
|
SafeRelease(pAttrNode);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetAttribute()
|
|
//
|
|
// Get attribute (long) from the xml node
|
|
// If function fails, *piAttr preservers original value.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, LONG* plAttr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(pNode);
|
|
QuitIfNull(bstrName);
|
|
QuitIfNull(plAttr);
|
|
|
|
VARIANT vAttr;
|
|
IXMLDOMElement *pElement = NULL;
|
|
IXMLDOMAttribute *pAttrNode = NULL;;
|
|
|
|
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
|
|
QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
|
|
if (NULL == pAttrNode) goto CleanUp;
|
|
|
|
QuitIfFail(pAttrNode->get_value(&vAttr));
|
|
if (VT_I4 == vAttr.vt)
|
|
{
|
|
*plAttr = vAttr.lVal;
|
|
}
|
|
else if (VT_BSTR == vAttr.vt)
|
|
{
|
|
*plAttr = MyBSTR2L(vAttr.bstrVal);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
VariantClear(&vAttr);
|
|
|
|
CleanUp:
|
|
SafeRelease(pElement);
|
|
SafeRelease(pAttrNode);
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetAttribute()
|
|
//
|
|
// Get attribute (BOOL) from the xml node
|
|
// If function fails, *piAttr preservers original value.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT GetAttributeBOOL(IXMLDOMNode* pNode, BSTR bstrName, BOOL * pfAttr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(pNode);
|
|
QuitIfNull(bstrName);
|
|
QuitIfNull(pfAttr);
|
|
|
|
VARIANT vAttr;
|
|
VARIANT vAttrBool;
|
|
IXMLDOMElement *pElement = NULL;
|
|
IXMLDOMAttribute *pAttrNode = NULL;;
|
|
|
|
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
|
|
QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
|
|
if (NULL == pAttrNode) goto CleanUp;
|
|
|
|
QuitIfFail(pAttrNode->get_value(&vAttr));
|
|
|
|
QuitIfFail(VariantChangeType(&vAttr, &vAttrBool, 0, VT_BOOL));
|
|
|
|
VariantClear(&vAttr);
|
|
|
|
*pfAttr = (VARIANT_TRUE == vAttrBool.boolVal) ? TRUE : FALSE;
|
|
|
|
CleanUp:
|
|
SafeRelease(pElement);
|
|
SafeRelease(pAttrNode);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetAttribute()
|
|
//
|
|
// Get attribute (BSTR) from the xml node
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, BSTR* pbstrAttr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(pbstrAttr);
|
|
*pbstrAttr = NULL;
|
|
QuitIfNull(pNode);
|
|
QuitIfNull(bstrName);
|
|
|
|
VARIANT vAttr;
|
|
IXMLDOMElement *pElement = NULL;
|
|
IXMLDOMAttribute *pAttrNode = NULL;;
|
|
|
|
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
|
|
QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
|
|
if (NULL == pAttrNode) goto CleanUp;
|
|
|
|
QuitIfFail(pAttrNode->get_value(&vAttr));
|
|
if (VT_BSTR == vAttr.vt)
|
|
{
|
|
*pbstrAttr = SysAllocString(vAttr.bstrVal);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
VariantClear(&vAttr);
|
|
|
|
CleanUp:
|
|
SafeRelease(pElement);
|
|
SafeRelease(pAttrNode);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetAttribute()
|
|
//
|
|
// Set attribute (integer) to the xml element
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, INT iAttr)
|
|
{
|
|
VARIANT vAttr;
|
|
VariantInit(&vAttr);
|
|
vAttr.vt = VT_INT;
|
|
vAttr.intVal = iAttr;
|
|
return SetAttribute(pNode, bstrName, vAttr);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetAttribute()
|
|
//
|
|
// Set attribute (BSTR) to the xml element
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, BSTR bstrAttr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(bstrAttr);
|
|
|
|
VARIANT vAttr;
|
|
VariantInit(&vAttr);
|
|
vAttr.vt = VT_BSTR;
|
|
vAttr.bstrVal = bstrAttr;
|
|
return SetAttribute(pNode, bstrName, vAttr);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetAttribute()
|
|
//
|
|
// Set attribute (VARIANT) to the xml element
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, VARIANT vAttr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(pNode);
|
|
QuitIfNull(bstrName);
|
|
|
|
IXMLDOMElement *pElement = NULL;
|
|
|
|
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
|
|
QuitIfFail(pElement->setAttribute(bstrName, vAttr));
|
|
|
|
CleanUp:
|
|
SafeRelease(pElement);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetText()
|
|
//
|
|
// Get text (BSTR) from the xml node
|
|
// Returns
|
|
// S_OK if *pbstrText returns text of 1st child of the given node
|
|
// S_FALSE if node has no child or 1st child has no text
|
|
// FAILED() otherwise
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT GetText(IXMLDOMNode* pNode, BSTR* pbstrText)
|
|
{
|
|
//USES_IU_CONVERSION;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
QuitIfNull(pbstrText);
|
|
*pbstrText = NULL;
|
|
QuitIfNull(pNode);
|
|
|
|
DOMNodeType nNodeType;
|
|
IXMLDOMNode* pNodeText = NULL;
|
|
|
|
QuitIfFail(pNode->get_firstChild(&pNodeText));
|
|
if (NULL == pNodeText) goto CleanUp;
|
|
|
|
QuitIfFail(pNodeText->get_nodeType(&nNodeType));
|
|
if (NODE_TEXT == nNodeType)
|
|
{
|
|
QuitIfFail(pNodeText->get_text(pbstrText));
|
|
}
|
|
else
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
CleanUp:
|
|
SafeRelease(pNodeText);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetValue()
|
|
//
|
|
// Set value (integer) for the xml node
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT SetValue(IXMLDOMNode* pNode, INT iValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(pNode);
|
|
|
|
VARIANT vValue;
|
|
VariantInit(&vValue);
|
|
vValue.vt = VT_INT;
|
|
vValue.intVal = iValue;
|
|
return (pNode->put_nodeValue(vValue));
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetValue()
|
|
//
|
|
// Set value (BSTR) for the xml node
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT SetValue(IXMLDOMNode* pNode, BSTR bstrValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(pNode);
|
|
|
|
VARIANT vValue;
|
|
VariantInit(&vValue);
|
|
vValue.vt = VT_BSTR;
|
|
vValue.bstrVal = bstrValue;
|
|
return (pNode->put_nodeValue(vValue));
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// InsertNode()
|
|
//
|
|
// Insert a child node to the parent node
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT InsertNode(IXMLDOMNode* pParentNode, IXMLDOMNode* pChildNode, IXMLDOMNode* pChildNodeRef /*= NULL*/)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
QuitIfNull(pParentNode);
|
|
QuitIfNull(pChildNode);
|
|
|
|
IXMLDOMNode *p = NULL;
|
|
if (NULL != pChildNodeRef) // insert before the ref child node
|
|
{
|
|
VARIANT vChildNodeRef;
|
|
VariantInit(&vChildNodeRef);
|
|
vChildNodeRef.vt = VT_UNKNOWN;
|
|
vChildNodeRef.punkVal = pChildNodeRef;
|
|
QuitIfFail(pParentNode->insertBefore(pChildNode, vChildNodeRef, &p));
|
|
}
|
|
else // append to the child list
|
|
{
|
|
VARIANT vEmpty;
|
|
VariantInit(&vEmpty);
|
|
vEmpty.vt = VT_EMPTY;
|
|
QuitIfFail(pParentNode->insertBefore(pChildNode, vEmpty, &p));
|
|
}
|
|
|
|
CleanUp:
|
|
SafeRelease(p);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CopyNode()
|
|
//
|
|
// Create an xml node as a copy of the given node;
|
|
// this is different from cloneNode() as it copies node across xml document
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CopyNode(IXMLDOMNode* pNodeSrc, IXMLDOMDocument* pDocDes, IXMLDOMNode** ppNodeDes)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrNodeName = NULL;
|
|
BSTR bstrText = NULL;
|
|
BSTR bstrAttrName = NULL;
|
|
IXMLDOMNode *pChild = NULL;
|
|
IXMLDOMNamedNodeMap *pAttrs = NULL;
|
|
|
|
LOG_Block("CopyNode()");
|
|
|
|
QuitIfNull(ppNodeDes);
|
|
*ppNodeDes = NULL;
|
|
QuitIfNull(pNodeSrc);
|
|
QuitIfNull(pDocDes);
|
|
|
|
DOMNodeType nNodeType;
|
|
CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_nodeType(&nNodeType));
|
|
|
|
switch (nNodeType)
|
|
{
|
|
case NODE_TEXT:
|
|
{
|
|
CleanUpFailedAllocSetHrMsg(*ppNodeDes = CreateDOMNode(pDocDes, NODE_TEXT, NULL));
|
|
CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_text(&bstrText));
|
|
CleanUpIfFailedAndSetHrMsg(SetValue(*ppNodeDes, bstrText));
|
|
break;
|
|
}
|
|
case NODE_ELEMENT:
|
|
{
|
|
CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_nodeName(&bstrNodeName));
|
|
CleanUpFailedAllocSetHrMsg(*ppNodeDes = CreateDOMNode(pDocDes, NODE_ELEMENT, bstrNodeName));
|
|
|
|
if (SUCCEEDED(pNodeSrc->get_attributes(&pAttrs)) && (NULL != pAttrs))
|
|
{
|
|
pAttrs->nextNode(&pChild);
|
|
while (pChild)
|
|
{
|
|
CleanUpIfFailedAndSetHrMsg(pChild->get_nodeName(&bstrAttrName));
|
|
|
|
VARIANT vAttrValue;
|
|
CleanUpIfFailedAndSetHrMsg(pChild->get_nodeValue(&vAttrValue));
|
|
hr = SetAttribute(*ppNodeDes, bstrAttrName, vAttrValue);
|
|
VariantClear(&vAttrValue);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
SafeSysFreeString(bstrAttrName);
|
|
SafeReleaseNULL(pChild);
|
|
pAttrs->nextNode(&pChild);
|
|
}
|
|
pAttrs->Release();
|
|
pAttrs = NULL;
|
|
}
|
|
|
|
pNodeSrc->get_firstChild(&pChild);
|
|
while (pChild)
|
|
{
|
|
IXMLDOMNode *pChildDes = NULL;
|
|
CleanUpIfFailedAndSetHrMsg(CopyNode(pChild, pDocDes, &pChildDes));
|
|
hr = InsertNode(*ppNodeDes, pChildDes);
|
|
SafeRelease(pChildDes);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
IXMLDOMNode *pNext = NULL;
|
|
CleanUpIfFailedAndMsg(pChild->get_nextSibling(&pNext));
|
|
pChild->Release();
|
|
pChild = pNext;
|
|
}
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
default:
|
|
//
|
|
// for now, do nothing for other node types
|
|
//
|
|
;
|
|
}
|
|
|
|
CleanUp:
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppNodeDes);
|
|
}
|
|
SysFreeString(bstrNodeName);
|
|
SysFreeString(bstrText);
|
|
SysFreeString(bstrAttrName);
|
|
SafeRelease(pChild);
|
|
SafeRelease(pAttrs);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// AreNodesEqual()
|
|
//
|
|
// Return TRUE if two nodes are identical, return FALSE if function failed or
|
|
// if they're different (including order of attributes).
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL AreNodesEqual(IXMLDOMNode* pNode1, IXMLDOMNode* pNode2)
|
|
{
|
|
if (pNode1 == pNode2)
|
|
{
|
|
return TRUE;
|
|
}
|
|
if ((NULL == pNode1) || (NULL == pNode2))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL fResult = FALSE;
|
|
BOOL fSkipAttribute = FALSE;
|
|
BOOL fSkipChildNode = FALSE;
|
|
LONG lenAttr1= -1 , lenAttr2= -1;
|
|
LONG lenNode1= -1 , lenNode2= -1;
|
|
DOMNodeType nNodeType1, nNodeType2;
|
|
BSTR bstrText1 = NULL, bstrText2 = NULL;
|
|
BSTR bstrNodeName1 = NULL, bstrNodeName2 = NULL;
|
|
BSTR bstrAttrName1 = NULL, bstrAttrName2 = NULL;
|
|
IXMLDOMNodeList *pChildNodes1 = NULL, *pChildNodes2 = NULL;
|
|
IXMLDOMNode *pChild1= NULL, *pNext1 = NULL;
|
|
IXMLDOMNode *pChild2= NULL, *pNext2 = NULL;
|
|
IXMLDOMNamedNodeMap *pAttrs1 = NULL, *pAttrs2 = NULL;
|
|
VARIANT vAttrValue1, vAttrValue2;
|
|
|
|
VariantInit(&vAttrValue1);
|
|
VariantInit(&vAttrValue2);
|
|
|
|
if (FAILED(pNode1->get_nodeType(&nNodeType1)) ||
|
|
FAILED(pNode2->get_nodeType(&nNodeType2)) ||
|
|
(nNodeType1 != nNodeType2))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
switch (nNodeType1)
|
|
{
|
|
case NODE_TEXT:
|
|
{
|
|
if (FAILED(pNode1->get_text(&bstrText1)) ||
|
|
FAILED(pNode2->get_text(&bstrText2)) ||
|
|
!CompareBSTRsEqual(bstrText1, bstrText2))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
break;
|
|
}
|
|
case NODE_ELEMENT:
|
|
{
|
|
if (FAILED(pNode1->get_nodeName(&bstrNodeName1)) ||
|
|
FAILED(pNode2->get_nodeName(&bstrNodeName2)) ||
|
|
!CompareBSTRsEqual(bstrNodeName1, bstrNodeName2))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// 1. compare number of attributes
|
|
//
|
|
if (FAILED(pNode1->get_attributes(&pAttrs1)) ||
|
|
FAILED(pNode2->get_attributes(&pAttrs2)))
|
|
{
|
|
// this shouldn't happen, but...
|
|
goto CleanUp;
|
|
}
|
|
if ((NULL != pAttrs1) && (NULL != pAttrs2))
|
|
{
|
|
if (FAILED(pAttrs1->get_length(&lenAttr1)) ||
|
|
FAILED(pAttrs2->get_length(&lenAttr2)) ||
|
|
(abs(lenAttr1-lenAttr2) > 1))
|
|
{
|
|
// known bug in MSXML3.dll: xmlns="" could be one of the attribute
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
else if (pAttrs1 == pAttrs2)
|
|
{
|
|
// pAttrs1 and pAttrs2 are both NULL,
|
|
// set flag to ingore comparison of each individual attribute,
|
|
// go ahead compare the number of child nodes
|
|
fSkipAttribute = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// one of pAttrs1 and pAttrs2 is NULL, the nodes are obviously different
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// 2. compare number of child nodes
|
|
//
|
|
if (FAILED(pNode1->get_childNodes(&pChildNodes1)) ||
|
|
FAILED(pNode2->get_childNodes(&pChildNodes2)))
|
|
{
|
|
// this shouldn't happen, but...
|
|
goto CleanUp;
|
|
}
|
|
if ((NULL != pChildNodes1) && (NULL != pChildNodes2))
|
|
{
|
|
if (FAILED(pChildNodes1->get_length(&lenNode1)) ||
|
|
FAILED(pChildNodes2->get_length(&lenNode2)) ||
|
|
(lenNode1 != lenNode2))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
else if (pChildNodes1 == pChildNodes2)
|
|
{
|
|
// pChildNodes1 and pChildNodes2 are both NULL,
|
|
// set flag to ingore comparison of each individual child node,
|
|
// go ahead compare each attribute in next step
|
|
fSkipChildNode = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// one of pChildNodes1 and pChildNodes2 is NULL, the nodes are obviously different
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// 3. compare each attribute
|
|
//
|
|
if (!fSkipAttribute)
|
|
{
|
|
pAttrs1->nextNode(&pChild1);
|
|
pAttrs2->nextNode(&pChild2);
|
|
while (pChild1 && pChild2)
|
|
{
|
|
if (NULL == bstrAttrName1)
|
|
{
|
|
if (FAILED(pChild1->get_nodeName(&bstrAttrName1)))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
if (NULL == bstrAttrName2)
|
|
{
|
|
if (FAILED(pChild2->get_nodeName(&bstrAttrName2)))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
if (!CompareBSTRsEqual(bstrAttrName1, bstrAttrName2))
|
|
{
|
|
if (CompareBSTRsEqual(bstrAttrName1, KEY_XML_NAMESPACE) && lenAttr1 == lenAttr2+1)
|
|
{
|
|
// ignore xmlns=""
|
|
SafeSysFreeString(bstrAttrName1);
|
|
pChild1->Release();
|
|
pAttrs1->nextNode(&pChild1);
|
|
continue;
|
|
}
|
|
else if (CompareBSTRsEqual(bstrAttrName2, KEY_XML_NAMESPACE) && lenAttr1 == lenAttr2-1)
|
|
{
|
|
// ignore xmlns=""
|
|
SafeSysFreeString(bstrAttrName2);
|
|
pChild2->Release();
|
|
pAttrs2->nextNode(&pChild2);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VariantInit(&vAttrValue1);
|
|
VariantInit(&vAttrValue2);
|
|
if (FAILED(pChild1->get_nodeValue(&vAttrValue1)) ||
|
|
FAILED(pChild2->get_nodeValue(&vAttrValue2)) ||
|
|
(vAttrValue1.vt != vAttrValue2.vt))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
switch (vAttrValue1.vt)
|
|
{
|
|
case VT_INT: // integer
|
|
{
|
|
if (vAttrValue1.intVal != vAttrValue2.intVal)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
break;
|
|
}
|
|
case VT_I2: // short
|
|
{
|
|
if (vAttrValue1.iVal != vAttrValue2.iVal)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
break;
|
|
}
|
|
case VT_I4: // long
|
|
{
|
|
if (vAttrValue1.lVal != vAttrValue2.lVal)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
break;
|
|
}
|
|
case VT_BOOL: // bool
|
|
{
|
|
if (vAttrValue1.boolVal != vAttrValue2.boolVal)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
break;
|
|
}
|
|
case VT_BSTR: // BSTR
|
|
{
|
|
if (!CompareBSTRsEqual(vAttrValue1.bstrVal, vAttrValue2.bstrVal))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
//
|
|
// for now, do nothing for other attribute types
|
|
//
|
|
;
|
|
}
|
|
SafeSysFreeString(bstrAttrName1);
|
|
SafeSysFreeString(bstrAttrName2);
|
|
VariantClear(&vAttrValue1);
|
|
VariantClear(&vAttrValue2);
|
|
pChild1->Release();
|
|
pChild2->Release();
|
|
pAttrs1->nextNode(&pChild1);
|
|
pAttrs2->nextNode(&pChild2);
|
|
}
|
|
}
|
|
|
|
if (pChild1 != pChild2)
|
|
{
|
|
if (NULL == pChild1)
|
|
{
|
|
// this is the case that we looped through all the attributes in the
|
|
// first node but we still found attribute left in the second node;
|
|
// if it's xmlns="", that's ok; otherwise these two nodes are different.
|
|
if (FAILED(pChild2->get_nodeName(&bstrAttrName2)) ||
|
|
(!CompareBSTRsEqual(bstrAttrName2, KEY_XML_NAMESPACE)))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(pChild1->get_nodeName(&bstrAttrName1)) ||
|
|
(!CompareBSTRsEqual(bstrAttrName1, KEY_XML_NAMESPACE)))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 4. compare each child node
|
|
//
|
|
if (!fSkipChildNode)
|
|
{
|
|
pNode1->get_firstChild(&pChild1);
|
|
pNode2->get_firstChild(&pChild2);
|
|
while (pChild1)
|
|
{
|
|
if (!pChild2)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
if (!AreNodesEqual(pChild1, pChild2))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
pChild1->get_nextSibling(&pNext1);
|
|
pChild2->get_nextSibling(&pNext2);
|
|
pChild1->Release();
|
|
pChild2->Release();
|
|
pChild1 = pNext1;
|
|
pChild2 = pNext2;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
//
|
|
// for now, do nothing for other node types
|
|
//
|
|
;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
|
|
CleanUp:
|
|
SafeSysFreeString(bstrText1);
|
|
SafeSysFreeString(bstrText2);
|
|
SafeSysFreeString(bstrNodeName1);
|
|
SafeSysFreeString(bstrNodeName2);
|
|
SafeSysFreeString(bstrAttrName1);
|
|
SafeSysFreeString(bstrAttrName2);
|
|
SafeRelease(pChildNodes1);
|
|
SafeRelease(pChildNodes2);
|
|
SafeRelease(pChild1);
|
|
SafeRelease(pChild2);
|
|
SafeRelease(pAttrs1);
|
|
SafeRelease(pAttrs2);
|
|
if (vAttrValue1.vt != VT_EMPTY)
|
|
VariantClear(&vAttrValue1);
|
|
if (vAttrValue2.vt != VT_EMPTY)
|
|
VariantClear(&vAttrValue2);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// LoadXMLDoc()
|
|
//
|
|
// Load an XML Document from string
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT LoadXMLDoc(BSTR bstrXml, IXMLDOMDocument** ppDoc, BOOL fOffline /*= TRUE*/)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
VARIANT_BOOL fSuccess = VARIANT_FALSE, fValidate = VARIANT_FALSE;
|
|
|
|
QuitIfNull(ppDoc);
|
|
*ppDoc = NULL;
|
|
QuitIfNull(bstrXml);
|
|
hr = CoCreateInstance(CLSID_DOMDocument,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IXMLDOMDocument,
|
|
(void **) ppDoc);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
fValidate = fOffline ? VARIANT_FALSE : VARIANT_TRUE;
|
|
|
|
//
|
|
// we don't do validation unless the reg key is set on to do so
|
|
//
|
|
if (fValidate)
|
|
{
|
|
HKEY hKey = NULL;
|
|
DWORD dwValue = 0x0;
|
|
DWORD dwSize = sizeof(dwValue);
|
|
DWORD dwType = REG_DWORD;
|
|
|
|
fValidate = VARIANT_FALSE;
|
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hKey))
|
|
{
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGVAL_SCHEMAVALIDATION, NULL, &dwType, (LPBYTE)&dwValue, &dwSize))
|
|
{
|
|
if (REG_DWORD == dwType && sizeof(dwValue) == dwSize && 1 == dwValue)
|
|
{
|
|
fValidate = VARIANT_TRUE;
|
|
}
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
//
|
|
// force validation on parse if not offline
|
|
//
|
|
hr = (*ppDoc)->put_validateOnParse(fValidate);
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppDoc);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// force resolving external definition if not offline
|
|
//
|
|
hr = (*ppDoc)->put_resolveExternals(fValidate);
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppDoc);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// do synchronized loading
|
|
//
|
|
hr = (*ppDoc)->put_async(VARIANT_FALSE);
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppDoc);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// load the XML Doc from input string
|
|
//
|
|
hr = (*ppDoc)->loadXML(bstrXml, &fSuccess);
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppDoc);
|
|
return hr;
|
|
}
|
|
//
|
|
// S_FALSE may be returned even if load fails, but
|
|
// fSuccess will return VARIANT_FALSE if there was
|
|
// an error so we call ValidateDoc to log the error
|
|
// and get the correct HRESULT.
|
|
//
|
|
if (S_FALSE == hr || VARIANT_FALSE == fSuccess)
|
|
{
|
|
hr = ValidateDoc(*ppDoc);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
SafeReleaseNULL(*ppDoc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// LoadDocument()
|
|
//
|
|
// Load an XML Document from the specified file
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT LoadDocument(BSTR bstrFilePath, IXMLDOMDocument** ppDoc, BOOL fOffline /*= TRUE*/)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
VARIANT_BOOL fSuccess = VARIANT_FALSE, fValidate = VARIANT_FALSE;;
|
|
VARIANT vFilePath;
|
|
|
|
QuitIfNull(ppDoc);
|
|
*ppDoc = NULL;
|
|
QuitIfNull(bstrFilePath);
|
|
hr = CoCreateInstance(CLSID_DOMDocument,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IXMLDOMDocument,
|
|
(void **) ppDoc);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// do synchronized loading
|
|
//
|
|
hr = (*ppDoc)->put_async(VARIANT_FALSE);
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppDoc);
|
|
return hr;
|
|
}
|
|
|
|
fValidate = fOffline ? VARIANT_FALSE : VARIANT_TRUE;
|
|
//
|
|
// force validation on parse if not offline
|
|
//
|
|
hr = (*ppDoc)->put_validateOnParse(fValidate);
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppDoc);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// force resolving external definition if not offline
|
|
//
|
|
hr = (*ppDoc)->put_resolveExternals(fValidate);
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppDoc);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// load the XML Doc from the given file path
|
|
//
|
|
VariantInit(&vFilePath);
|
|
vFilePath.vt = VT_BSTR;
|
|
vFilePath.bstrVal = bstrFilePath;
|
|
hr = (*ppDoc)->load(vFilePath, &fSuccess);
|
|
if (FAILED(hr))
|
|
{
|
|
SafeReleaseNULL(*ppDoc);
|
|
return hr;
|
|
}
|
|
//
|
|
// S_FALSE may be returned even if load fails, but
|
|
// fSuccess will return VARIANT_FALSE if there was
|
|
// an error so we call ValidateDoc to log the error
|
|
// and get the correct HRESULT.
|
|
//
|
|
if (VARIANT_FALSE == fSuccess)
|
|
{
|
|
hr = ValidateDoc(*ppDoc);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
SafeReleaseNULL(*ppDoc);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SaveDocument()
|
|
//
|
|
// Save an XML Document to the specified location
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT SaveDocument(IXMLDOMDocument* pDoc, BSTR bstrFilePath)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
QuitIfNull(pDoc);
|
|
QuitIfNull(bstrFilePath);
|
|
|
|
//
|
|
// save the XML Doc to the given location
|
|
//
|
|
VARIANT vFilePath;
|
|
VariantInit(&vFilePath);
|
|
vFilePath.vt = VT_BSTR;
|
|
vFilePath.bstrVal = bstrFilePath;
|
|
hr = pDoc->save(vFilePath);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ReportParseError()
|
|
//
|
|
// Report parsing error information
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT ReportParseError(IXMLDOMParseError *pXMLError)
|
|
{
|
|
USES_IU_CONVERSION;
|
|
|
|
HRESULT hr = S_OK;
|
|
LONG lLine, lLinePos, lErrCode;
|
|
BSTR bstrErrText = NULL, bstrReason = NULL;
|
|
|
|
QuitIfNull(pXMLError);
|
|
QuitIfFail(pXMLError->get_errorCode(&lErrCode));
|
|
hr = lErrCode;
|
|
QuitIfFail(pXMLError->get_line(&lLine));
|
|
QuitIfFail(pXMLError->get_linepos(&lLinePos));
|
|
QuitIfFail(pXMLError->get_srcText(&bstrErrText));
|
|
QuitIfFail(pXMLError->get_reason(&bstrReason));
|
|
|
|
if (lLine > 0)
|
|
{
|
|
LOG_Block("ReportParseError()");
|
|
LOG_Error(_T("XML line %ld, pos %ld error 0x%08x: %s)"),
|
|
lLine,
|
|
lLinePos,
|
|
lErrCode,
|
|
OLE2T(bstrReason));
|
|
LOG_Error(_T("XML starts: %s"), OLE2T(bstrErrText));
|
|
|
|
#if defined(_UNICODE) || defined(UNICODE)
|
|
LogError(lErrCode, "loadXML: line %ld, pos %ld, %S",
|
|
lLine,
|
|
lLinePos,
|
|
bstrReason);
|
|
LogMessage("%S", bstrErrText);
|
|
#else
|
|
LogError(lErrCode, "loadXML: line %ld, pos %ld, %s",
|
|
lLine,
|
|
lLinePos,
|
|
bstrReason);
|
|
LogMessage("%s", bstrErrText);
|
|
#endif
|
|
/*
|
|
//
|
|
// We want to ping this error even though we don't have the
|
|
// client information. This most likely indicates a server
|
|
// content error.
|
|
//
|
|
CUrlLog pingSvr;
|
|
|
|
#define MAX_XML_PING_MSG 512
|
|
|
|
TCHAR szMsg[MAX_XML_PING_MSG];
|
|
lstrcpyn(szMsg, OLE2T(bstrErrText), MAX_XML_PING_MSG);
|
|
|
|
pingSvr.Ping(
|
|
FALSE, // on-line (we don't know, so be safe)
|
|
URLLOGDESTINATION_DEFAULT, //fixcode: should depend of client and corp WU settings
|
|
NULL, // pt to cancel events
|
|
0, // number of events
|
|
URLLOGACTIVITY_Detection, // activity
|
|
URLLOGSTATUS_Failed, // status code
|
|
lErrCode, // error code
|
|
NULL, // itemID
|
|
NULL, // device data
|
|
szMsg // first MAX_XML_PING_MSG chars of XML for context
|
|
);
|
|
*/
|
|
}
|
|
|
|
CleanUp:
|
|
SysFreeString(bstrErrText);
|
|
SysFreeString(bstrReason);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ValidateDoc()
|
|
//
|
|
// Validate the xml doc against the schema
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT ValidateDoc(IXMLDOMDocument* pDoc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
QuitIfNull(pDoc);
|
|
|
|
LONG lErrCode = 0;
|
|
IXMLDOMParseError *pXMLError = NULL;
|
|
|
|
QuitIfFail(pDoc->get_parseError(&pXMLError));
|
|
QuitIfFail(pXMLError->get_errorCode(&lErrCode));
|
|
|
|
if (lErrCode != 0)
|
|
{
|
|
hr = ReportParseError(pXMLError);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// no error, so hr = S_FALSE. reset it --- charlma 1/17/01
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
|
|
CleanUp:
|
|
SafeRelease(pXMLError);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// Helper function FindNode()
|
|
// retrieve the named node
|
|
//
|
|
// Input:
|
|
// an IXMLDomNode and a bstr name
|
|
//
|
|
// Return:
|
|
// BOOL, tells succeed or not
|
|
//
|
|
// Assumption:
|
|
// input parameter not NULL
|
|
// in case of fail, variant not touched
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
BOOL
|
|
FindNode(
|
|
IXMLDOMNode* pCurrentNode,
|
|
BSTR bstrName,
|
|
IXMLDOMNode** ppFoundNode
|
|
)
|
|
{
|
|
BSTR bstrTag = NULL;
|
|
LONG lLength = 0L;
|
|
IXMLDOMNode* pChild = NULL;
|
|
IXMLDOMNode* pNextChild = NULL;
|
|
|
|
if (NULL == pCurrentNode ||
|
|
NULL == bstrName ||
|
|
NULL == ppFoundNode)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*ppFoundNode = NULL;
|
|
|
|
if (S_OK == pCurrentNode->selectSingleNode(bstrName, &pChild))
|
|
{
|
|
*ppFoundNode = pChild;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// Helper function FindNodeValue()
|
|
// retrieve the named data from child of the current node,
|
|
//
|
|
// Input:
|
|
// an IXMLDomNode
|
|
//
|
|
// Return:
|
|
// BOOL, tells succeed or not
|
|
//
|
|
// Assumption:
|
|
// input parameter not NULL
|
|
// in case of fail, variant not touched
|
|
//
|
|
//----------------------------------------------------------------------
|
|
BOOL
|
|
FindNodeValue(
|
|
IXMLDOMNode* pCurrentNode,
|
|
BSTR bstrName,
|
|
BSTR* pbstrValue)
|
|
{
|
|
IXMLDOMNode* pChild = NULL;
|
|
|
|
if (NULL == pbstrValue)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*pbstrValue = NULL;
|
|
|
|
if (FindNode(pCurrentNode, bstrName, &pChild))
|
|
{
|
|
pChild->get_text(pbstrValue);
|
|
SafeRelease(pChild);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// public function Get3IdentiStrFromIdentNode()
|
|
// retrieve the name, publisherName and GUID from an identity node
|
|
//
|
|
// Return:
|
|
// HREUSLT - error code
|
|
//
|
|
//----------------------------------------------------------------------
|
|
HRESULT Get3IdentiStrFromIdentNode(IXMLDOMNode* pIdentityNode, BSTR* pbstrName, BSTR* pbstrPublisherName, BSTR* pbstrGUID)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
BOOL fPublisherNameExist = FALSE, fGUIDExist = FALSE;
|
|
|
|
LOG_Block("Get3IdentiStrFromIdentNode()");
|
|
|
|
if (NULL == pIdentityNode || NULL == pbstrName || NULL == pbstrPublisherName || NULL == pbstrGUID)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pbstrName = NULL;
|
|
*pbstrPublisherName = NULL;
|
|
*pbstrGUID = NULL;
|
|
|
|
//
|
|
// get name attr
|
|
//
|
|
hr = GetAttribute(pIdentityNode, KEY_NAME, pbstrName);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
//
|
|
// try to get publisherName
|
|
//
|
|
fPublisherNameExist = FindNodeValue(pIdentityNode, KEY_PUBLISHERNAME, pbstrPublisherName);
|
|
|
|
fGUIDExist = FindNodeValue(pIdentityNode, KEY_GUID, pbstrGUID);
|
|
|
|
hr = (fPublisherNameExist || fGUIDExist) ? S_OK : E_FAIL;
|
|
|
|
CleanUp:
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
SysFreeString(*pbstrName);
|
|
SysFreeString(*pbstrPublisherName);
|
|
SysFreeString(*pbstrGUID);
|
|
*pbstrName = NULL;
|
|
*pbstrPublisherName = NULL;
|
|
*pbstrGUID = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// MakeUniqNameString()
|
|
//
|
|
// This is a utility function to construct the identity name string
|
|
// based on name|publiser|GUID and the rule to make this name string.
|
|
//
|
|
// This function defines the logic about what components can be used
|
|
// to define the uniqueness of an item based on the 3 parts of data from
|
|
// GetIdentity().
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT MakeUniqNameString(
|
|
BSTR bstrName,
|
|
BSTR bstrPublisher,
|
|
BSTR bstrGUID,
|
|
BSTR* pbstrUniqIdentifierString)
|
|
{
|
|
LPWSTR pszResult = NULL;
|
|
DWORD dwLen=0;
|
|
HRESULT hr=S_OK;
|
|
|
|
if (NULL == bstrName || SysStringLen(bstrName) == 0 || NULL == pbstrUniqIdentifierString)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pbstrUniqIdentifierString = NULL;
|
|
|
|
if (NULL != bstrPublisher && SysStringLen(bstrPublisher) > 0)
|
|
{
|
|
//
|
|
// if we have publisherName, we expect it is
|
|
// reverse DNS name (e.g., com.microsoft), and Name is
|
|
// the reverse DNS name (e.g., windowsupdate.autoupdate.client)
|
|
// inside that publisher. We combine them with a dot (.)
|
|
//
|
|
// Length of Publisher + Length of Name + 1 for the dot + 1 for null
|
|
dwLen=(SysStringLen(bstrPublisher) + SysStringLen(bstrName) + 2);
|
|
pszResult = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLen * sizeof(WCHAR));
|
|
|
|
if (NULL == pszResult)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// since we need to work on Win9x too, so we can not use Win32 API
|
|
// for UNICODE, and have to use shlwapi verison
|
|
//
|
|
|
|
hr=StringCchCopyExW(pszResult,dwLen,bstrPublisher,NULL,NULL,MISTSAFE_STRING_FLAGS);
|
|
if(FAILED(hr))
|
|
{
|
|
SafeHeapFree(pszResult);
|
|
return hr;
|
|
}
|
|
|
|
|
|
hr=StringCchCatExW(pszResult,dwLen,L".",NULL,NULL,MISTSAFE_STRING_FLAGS);
|
|
if(FAILED(hr))
|
|
{
|
|
SafeHeapFree(pszResult);
|
|
return hr;
|
|
}
|
|
|
|
|
|
hr=StringCchCatExW(pszResult,dwLen,bstrName,NULL,NULL,MISTSAFE_STRING_FLAGS);
|
|
if(FAILED(hr))
|
|
{
|
|
SafeHeapFree(pszResult);
|
|
return hr;
|
|
}
|
|
|
|
*pbstrUniqIdentifierString = SysAllocString(pszResult);
|
|
SafeHeapFree(pszResult);
|
|
if (NULL == *pbstrUniqIdentifierString)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (NULL == bstrGUID || SysStringLen(bstrGUID) == 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// if no suitable publisherName, then we use GUID
|
|
//
|
|
*pbstrUniqIdentifierString = SysAllocString(bstrGUID);
|
|
if (NULL == *pbstrUniqIdentifierString)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// public function UtilGetUniqIdentityStr()
|
|
// retrieve the unique string that make this <identity> node unique
|
|
//
|
|
// Return:
|
|
// HREUSLT - error code
|
|
//
|
|
//----------------------------------------------------------------------
|
|
HRESULT
|
|
UtilGetUniqIdentityStr(
|
|
IXMLDOMNode* pIdentityNode,
|
|
BSTR* pbstrUniqIdentifierString,
|
|
DWORD dwFlag)
|
|
{
|
|
DWORD dwLen=0;
|
|
LOG_Block("UtilGetUniqIdentityStr");
|
|
|
|
IXMLDOMNode *pNodeVersion = NULL;
|
|
IXMLDOMNode *pNodeIdentity = NULL;
|
|
BSTR bstrName = NULL,
|
|
bstrPublisher = NULL,
|
|
bstrGuid = NULL,
|
|
bstrResult = NULL;
|
|
|
|
USES_IU_CONVERSION;
|
|
|
|
if (NULL == pIdentityNode || NULL == pbstrUniqIdentifierString)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
//
|
|
// retrive string
|
|
//
|
|
HRESULT hr = Get3IdentiStrFromIdentNode(pIdentityNode, &bstrName, &bstrPublisher, &bstrGuid);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
//
|
|
// construct string to make it unique
|
|
//
|
|
hr = MakeUniqNameString(bstrName, bstrPublisher, bstrGuid, &bstrResult);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
//
|
|
// check if this identity has version node. not all have <identity> nodes have <version>
|
|
//
|
|
if (FindNode(pNodeIdentity, KEY_VERSION, &pNodeVersion) && NULL != pNodeVersion)
|
|
{
|
|
TCHAR szVersion[MAX_VERSION];
|
|
LPWSTR pszUniqueString = NULL;
|
|
|
|
hr = UtilGetVersionStr(pNodeVersion, szVersion, dwFlag);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
dwLen=(SysStringLen(bstrResult) + lstrlen(szVersion) + 2);
|
|
pszUniqueString = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLen* sizeof(WCHAR));
|
|
CleanUpFailedAllocSetHrMsg(pszUniqueString);
|
|
|
|
hr=StringCchCopyExW(pszUniqueString,dwLen,bstrResult,NULL,NULL,MISTSAFE_STRING_FLAGS);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
SafeHeapFree(pszUniqueString);
|
|
SetHrMsgAndGotoCleanUp(hr);
|
|
}
|
|
hr=StringCchCatExW(pszUniqueString,dwLen,L".",NULL,NULL,MISTSAFE_STRING_FLAGS);
|
|
if(FAILED(hr))
|
|
{
|
|
SafeHeapFree(pszUniqueString);
|
|
SetHrMsgAndGotoCleanUp(hr);
|
|
}
|
|
|
|
hr=StringCchCatExW(pszUniqueString,dwLen,T2W(szVersion),NULL,NULL,MISTSAFE_STRING_FLAGS);
|
|
if(FAILED(hr))
|
|
{
|
|
SafeHeapFree(pszUniqueString);
|
|
SetHrMsgAndGotoCleanUp(hr);
|
|
}
|
|
|
|
*pbstrUniqIdentifierString = SysAllocString(pszUniqueString);
|
|
SafeHeapFree(pszUniqueString);
|
|
}
|
|
else
|
|
{
|
|
*pbstrUniqIdentifierString = SysAllocString(bstrResult);
|
|
}
|
|
|
|
CleanUpFailedAllocSetHrMsg(*pbstrUniqIdentifierString);
|
|
|
|
hr = S_OK;
|
|
|
|
CleanUp:
|
|
|
|
SysFreeString(bstrName);
|
|
SysFreeString(bstrPublisher);
|
|
SysFreeString(bstrGuid);
|
|
SysFreeString(bstrResult);
|
|
|
|
SafeRelease(pNodeVersion);
|
|
SafeRelease(pNodeIdentity);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// public function UtilGetPlatformStr()
|
|
// retrieve the unique string that make this <platform> node unique
|
|
//
|
|
// Return:
|
|
// HREUSLT - error code
|
|
//
|
|
//----------------------------------------------------------------------
|
|
HRESULT
|
|
UtilGetPlatformStr(
|
|
IXMLDOMNode* pNodePlatform,
|
|
BSTR* pbstrPlatform,
|
|
DWORD dwFlag)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
IXMLDOMNode* pNodeVersion = NULL;
|
|
IXMLDOMNode* pNodeSuite = NULL;
|
|
IXMLDOMNodeList* pSuiteList = NULL;
|
|
IXMLDOMElement* pElement = NULL;
|
|
|
|
TCHAR szPlatformStr[MAX_PLATFORM_STR_LEN],
|
|
szVersion[256]; // should be enough for any version
|
|
|
|
const TCHAR PART_CONNECTOR[2] = _T("_");
|
|
const HRESULT RET_OVERFLOW = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
|
|
|
|
BSTR bstrName = NULL,
|
|
bstrProcessor = NULL,
|
|
bstrType = NULL,
|
|
bstrSuite = NULL;
|
|
|
|
long iCount = 0,
|
|
iLength = 0;
|
|
|
|
LOG_Block("UtilGetPlatformStr");
|
|
|
|
USES_IU_CONVERSION;
|
|
|
|
szPlatformStr[0] = _T('\0');
|
|
|
|
if (NULL == pNodePlatform || NULL == pbstrPlatform)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// get platform name
|
|
//
|
|
if (SUCCEEDED(GetAttribute(pNodePlatform, KEY_NAME, &bstrName)) &&
|
|
NULL != bstrName && SysStringLen(bstrName) > 0)
|
|
{
|
|
iLength = SysStringLen(bstrName);
|
|
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrName),NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
|
|
}
|
|
|
|
//
|
|
// if there is a valid processor architecture, like x86 or alpha, append it
|
|
//
|
|
if (FindNodeValue(pNodePlatform, KEY_PROCESSORARCHITECTURE, &bstrProcessor) &&
|
|
NULL != bstrProcessor && SysStringLen(bstrProcessor) > 0)
|
|
{
|
|
//
|
|
// processor architector should directly append to name, without
|
|
// the connect char "_"
|
|
iLength += SysStringLen(bstrProcessor) ;
|
|
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrProcessor),NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
}
|
|
|
|
//
|
|
// try to get version code
|
|
//
|
|
hr = (TRUE == FindNode(pNodePlatform, KEY_VERSION, &pNodeVersion)) ? S_OK : E_FAIL;
|
|
|
|
//
|
|
// if return code is not saying we don't have version node,
|
|
// then it must be an error
|
|
//
|
|
if (FAILED(hr) && HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr)
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// if we have a version node, try to find the version string
|
|
//
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = UtilGetVersionStr(pNodeVersion, szVersion, dwFlag);
|
|
SafeReleaseNULL(pNodeVersion);
|
|
//
|
|
// if we have a version node, it better be a good one
|
|
//
|
|
CleanUpIfFailedAndMsg(hr);
|
|
iLength += lstrlen(szVersion) + 1 ;
|
|
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),szVersion,NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
|
|
}
|
|
|
|
//
|
|
// try to get a list of suite nodes
|
|
//
|
|
if (0x0 == (dwFlag & SKIP_SUITES))
|
|
{
|
|
hr = pNodePlatform->QueryInterface(IID_IXMLDOMElement, (void**)&pElement);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
hr = pElement->getElementsByTagName(KEY_SUITE, &pSuiteList);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
//
|
|
// try to get the length of the list, i.e., how many suite node(s)
|
|
//
|
|
hr = pSuiteList->get_length(&iCount);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
|
|
//
|
|
// loop through each suite, if any
|
|
//
|
|
pSuiteList->reset();
|
|
for (int i = 0; i < iCount; i++)
|
|
{
|
|
hr = pSuiteList->get_item(i, &pNodeSuite);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
if (pNodeSuite)
|
|
{
|
|
hr = pNodeSuite->get_text(&bstrSuite);
|
|
CleanUpIfFailedAndMsg(hr);
|
|
iLength += SysStringLen(bstrSuite) + 1;
|
|
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
|
|
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrSuite),NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
|
|
pNodeSuite->Release();
|
|
pNodeSuite = NULL;
|
|
SafeSysFreeString(bstrSuite);
|
|
}
|
|
}
|
|
pSuiteList->Release();
|
|
pSuiteList = NULL;
|
|
}
|
|
|
|
//
|
|
// if we find a productType node, append its text data
|
|
//
|
|
if (FindNodeValue(pNodePlatform, KEY_PRODUCTTYPE, &bstrType) &&
|
|
NULL != bstrType && SysStringLen(bstrType) > 0)
|
|
{
|
|
iLength += SysStringLen(bstrType) + 1;
|
|
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrType),NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
}
|
|
|
|
*pbstrPlatform = SysAllocString(T2OLE(szPlatformStr));
|
|
|
|
LOG_XML(_T("Got platform string %s"), szPlatformStr);
|
|
|
|
hr = S_OK;
|
|
|
|
CleanUp:
|
|
|
|
SysFreeString(bstrName);
|
|
SysFreeString(bstrProcessor);
|
|
SysFreeString(bstrSuite);
|
|
SysFreeString(bstrType);
|
|
SafeRelease(pNodeVersion);
|
|
SafeRelease(pNodeSuite);
|
|
SafeRelease(pSuiteList);
|
|
SafeRelease(pElement);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// public function UtilGetVersionStr()
|
|
// retrieve the data from this <version> in string format
|
|
//
|
|
// Return:
|
|
// HREUSLT - error code
|
|
//
|
|
//----------------------------------------------------------------------
|
|
HRESULT
|
|
UtilGetVersionStr(
|
|
IXMLDOMNode* pVersionNode,
|
|
LPTSTR pszVersion,
|
|
DWORD dwFlag)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
LONG iMajor = -1,
|
|
iMinor = -1,
|
|
iBuild = -1,
|
|
iSvcPackMajor = -1,
|
|
iSvcPackMinor = -1;
|
|
|
|
LOG_Block("UtilGetVersionStr()");
|
|
|
|
BSTR bstrTimestamp = NULL;
|
|
BSTR bstrVersion = NULL;
|
|
TCHAR szNumber[16]; // enough to store a positive integer
|
|
|
|
BOOL fLastChunkExists = FALSE;
|
|
|
|
USES_IU_CONVERSION;
|
|
|
|
if (NULL == pVersionNode || NULL == pszVersion)
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
*pszVersion = _T('\0');
|
|
|
|
//
|
|
// a version node can contain either text version data (for binaries),
|
|
// or attribute version data (for OS). If both exist, we prefer text data
|
|
//
|
|
if (SUCCEEDED(pVersionNode->get_text(&bstrVersion)) && NULL != bstrVersion &&
|
|
SysStringLen(bstrVersion) > 0)
|
|
{
|
|
lstrcpyn(pszVersion, OLE2T(bstrVersion), MAX_VERSION);
|
|
}
|
|
else
|
|
{
|
|
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_MAJOR, &iMajor)) && iMajor > 0)
|
|
{
|
|
|
|
//It's an assumption that the pszVersion will be atleast MAX_VERSION characters wide
|
|
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(pszVersion,MAX_VERSION,NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%d"),iMajor));
|
|
|
|
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_MINOR, &iMinor)) && iMinor >= 0)
|
|
{
|
|
|
|
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T(".%d"),iMinor));
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
|
|
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_BUILD, &iBuild)) && iBuild >= 0)
|
|
{
|
|
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T(".%d"),iBuild));
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
}
|
|
}
|
|
fLastChunkExists = TRUE;
|
|
}
|
|
|
|
if (0x0 == (dwFlag & SKIP_SERVICEPACK_VER) &&
|
|
SUCCEEDED(GetAttribute(pVersionNode, KEY_SERVICEPACKMAJOR, &iSvcPackMajor)) &&
|
|
iSvcPackMajor > 0)
|
|
{
|
|
if (fLastChunkExists)
|
|
{
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(","),NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
}
|
|
|
|
|
|
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%d"),iSvcPackMajor));
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
|
|
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_SERVICEPACKMINOR, &iSvcPackMinor)) &&
|
|
iSvcPackMinor >= 0)
|
|
{
|
|
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS,_T(".%d"),iSvcPackMinor));
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
}
|
|
fLastChunkExists = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fLastChunkExists = FALSE;
|
|
}
|
|
|
|
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_TIMESTAMP, &bstrTimestamp)) &&
|
|
NULL != bstrTimestamp && SysStringLen(bstrTimestamp) > 0)
|
|
{
|
|
if (fLastChunkExists)
|
|
{
|
|
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(","),NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if we need to append timestamp, and we didn't get service pack
|
|
// data, we want to leave extra separator "," to tell the following
|
|
// part is timestamp and service pack data missing.
|
|
//
|
|
if (*pszVersion != _T('\0'))
|
|
{
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(",,"),NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
|
|
}
|
|
//
|
|
// if this is the first chunk we found, then no prefix needed
|
|
//
|
|
}
|
|
|
|
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,OLE2T(bstrTimestamp),NULL,NULL,MISTSAFE_STRING_FLAGS));
|
|
}
|
|
}
|
|
|
|
//
|
|
// if we got something, then this is a valid version node and
|
|
// we can pass back whatever we got. Otherwise we return E_INVALIDARG
|
|
//
|
|
if (*pszVersion != _T('\0'))
|
|
{
|
|
LOG_XML(_T("Got version str %s"), pszVersion);
|
|
hr = S_OK;
|
|
}
|
|
|
|
CleanUp:
|
|
SysFreeString(bstrTimestamp);
|
|
SysFreeString(bstrVersion);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
// function GetFullFilePathFromFilePathNode()
|
|
//
|
|
// retrieve the full qualified file path from a filePath node
|
|
//
|
|
// Input:
|
|
// a filePath XMLDom node
|
|
// a pointer to a buffer to receive path, assumes MAX_PATH long.
|
|
//
|
|
// Return:
|
|
// HRESULT
|
|
// Found path: S_OK
|
|
// Not found path: S_FALSE, lpszFilePath is empty
|
|
// otherwise, error code
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
HRESULT GetFullFilePathFromFilePathNode(
|
|
IXMLDOMNode* pFilePathNode,
|
|
LPTSTR lpszFilePath
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LOG_Block("GetFullFilePathFromFilePathNode");
|
|
|
|
USES_IU_CONVERSION;
|
|
|
|
IXMLDOMNode* pRegKeyNode = NULL;
|
|
|
|
TCHAR szPath[MAX_PATH] = {_T('\0')};
|
|
|
|
LPTSTR lpszFileName = NULL;
|
|
LPTSTR lpszKey = NULL;
|
|
LPTSTR lpszValue = NULL;
|
|
LPTSTR lpszPath = NULL;
|
|
|
|
BSTR bstrName = NULL;
|
|
BSTR bstrPath = NULL;
|
|
BSTR bstrKey = NULL;
|
|
BSTR bstrValue = NULL;
|
|
|
|
BOOL fPathExists = FALSE;
|
|
|
|
UINT nReqSize = 0;
|
|
|
|
|
|
if (NULL == pFilePathNode || NULL == lpszFilePath)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
LOG_ErrorMsg(hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// init path buffer
|
|
//
|
|
*lpszFilePath = _T('\0');
|
|
|
|
//
|
|
// try to get name data, note: S_FALSE won't do, it means everything is
|
|
// fine but this attribute does not exist.
|
|
//
|
|
if (S_OK == (hr = GetAttribute(pFilePathNode, KEY_NAME, &bstrName)))
|
|
{
|
|
//
|
|
// found name attribute
|
|
//
|
|
lpszFileName = OLE2T(bstrName);
|
|
LOG_XML(_T(" file name=%s"), lpszFileName);
|
|
fPathExists = TRUE;
|
|
}
|
|
|
|
|
|
if (FindNode(pFilePathNode, KEY_REGKEY, &pRegKeyNode) && NULL != pRegKeyNode)
|
|
{
|
|
//
|
|
// found a reg key node
|
|
//
|
|
if (!FindNodeValue(pRegKeyNode, KEY_KEY, &bstrKey))
|
|
{
|
|
//
|
|
// key node is required!
|
|
//
|
|
hr = E_INVALIDARG;
|
|
LOG_ErrorMsg(hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
lpszKey = OLE2T(bstrKey);
|
|
LOG_XML(_T("Found key=%s"), lpszKey);
|
|
|
|
//
|
|
// get optional value name
|
|
//
|
|
if (FindNodeValue(pRegKeyNode, KEY_ENTRY, &bstrValue))
|
|
{
|
|
lpszValue = OLE2T(bstrValue);
|
|
LOG_XML(_T("found entry=%s"), lpszValue);
|
|
}
|
|
else
|
|
{
|
|
LOG_XML(_T("found no value, use default"));
|
|
}
|
|
|
|
if (GetFilePathFromReg(lpszKey, lpszValue, NULL, NULL, szPath) && _T('\0') != *szPath)
|
|
{
|
|
//
|
|
// various reason can me this call fail, such as
|
|
// reg key wrong, no access to reg key, out of memory, etc
|
|
//
|
|
fPathExists = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (FindNodeValue(pFilePathNode, KEY_PATH, &bstrPath) && SysStringLen(bstrPath) > 0)
|
|
{
|
|
//
|
|
// found path element
|
|
//
|
|
lpszPath = OLE2T(bstrPath);
|
|
fPathExists = TRUE;
|
|
}
|
|
|
|
if (!fPathExists)
|
|
{
|
|
//
|
|
// nothing exist
|
|
//
|
|
lpszFilePath[0] = _T('\0');
|
|
LOG_XML(_T("empty node!"));
|
|
hr = S_FALSE;
|
|
goto CleanUp;
|
|
}
|
|
|
|
nReqSize = lstrlen(szPath) + SysStringLen(bstrPath) + SysStringLen(bstrName);
|
|
|
|
if (nReqSize >= MAX_PATH ||
|
|
NULL != lpszPath && FAILED(PathCchAppend(szPath,MAX_PATH,lpszPath)) || // append path to reg path
|
|
NULL != lpszFileName && FAILED(PathCchAppend(szPath,MAX_PATH,lpszFileName))) // append name
|
|
{
|
|
LOG_ErrorMsg(ERROR_BUFFER_OVERFLOW);
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (FAILED (hr = ExpandFilePath(szPath, lpszFilePath, MAX_PATH)))
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
goto CleanUp;
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
SysFreeString(bstrName);
|
|
SysFreeString(bstrPath);
|
|
SysFreeString(bstrKey);
|
|
SysFreeString(bstrValue);
|
|
SafeRelease(pRegKeyNode);
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT GetBstrFullFilePathFromFilePathNode(
|
|
IXMLDOMNode* pFilePathNode,
|
|
BSTR* pbstrFilePath
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
USES_IU_CONVERSION;
|
|
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
QuitIfNull(pbstrFilePath);
|
|
*pbstrFilePath = NULL;
|
|
if (SUCCEEDED(hr = GetFullFilePathFromFilePathNode(pFilePathNode, szPath)))
|
|
{
|
|
*pbstrFilePath = SysAllocString(T2OLE(szPath));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Helper function DoesNodeHaveName()
|
|
//
|
|
// find out the the current node has a matching name
|
|
//
|
|
// Input:
|
|
// a node
|
|
//
|
|
// Return:
|
|
// TRUE/FALSE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL DoesNodeHaveName(IXMLDOMNode* pNode, BSTR bstrTagName)
|
|
{
|
|
BSTR bstrName;
|
|
BOOL fRet = FALSE;
|
|
IXMLDOMElement* pElement = NULL;
|
|
|
|
if (NULL == pNode)
|
|
{
|
|
return fRet;
|
|
}
|
|
|
|
if (FAILED(pNode->QueryInterface(IID_IXMLDOMElement, (void**) &pElement)) || NULL == pElement)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (SUCCEEDED(pElement->get_nodeName(&bstrName)))
|
|
{
|
|
fRet = CompareBSTRsEqual(bstrName, bstrTagName);
|
|
}
|
|
|
|
SysFreeString(bstrName);
|
|
SafeReleaseNULL(pElement);
|
|
|
|
return fRet;
|
|
}
|