windows-nt/Source/XPSP1/NT/shell/ext/cdfview/xmlutil.cpp
2020-09-26 16:20:57 +08:00

2775 lines
71 KiB
C++

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// xmlutil.cpp
//
// XML item helper functions.
//
// History:
//
// 4/1/97 edwardp Created.
//
////////////////////////////////////////////////////////////////////////////////
//
// Includes
//
#include "stdinc.h"
#include "cdfidl.h"
#include "xmlutil.h"
#include "winineti.h"
#include <ocidl.h> // IPersistStreamInit.
//
// Function prototypes.
//
//
// XML helper functions.
//
////////////////////////////////////////////////////////////////////////////////
//
// *** XML_MarkCacheEntrySticky ***
//
// Description:
// Marks the cache entry for the given URL as sticky by setting its
// expiration delta to be very high
//
// Parameters:
// [In] lpszUrl - url for cache entry to make sticky
//
// Return:
// S_OK if the url entry was successfully marked sticky
// E_FAIL otherwise.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT XML_MarkCacheEntrySticky(LPTSTR lpszURL)
{
char chBuf[MAX_CACHE_ENTRY_INFO_SIZE];
LPINTERNET_CACHE_ENTRY_INFO lpInfo = (LPINTERNET_CACHE_ENTRY_INFO) chBuf;
DWORD dwSize = sizeof(chBuf);
lpInfo->dwStructSize = dwSize;
if (GetUrlCacheEntryInfo(lpszURL, lpInfo, &dwSize))
{
lpInfo->dwExemptDelta = 0xFFFFFFFF; // make VERY sticky
if (SetUrlCacheEntryInfo(lpszURL, lpInfo, CACHE_ENTRY_EXEMPT_DELTA_FC))
{
return S_OK;
}
}
return E_FAIL;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_SynchronousParse ***
//
//
// Description:
// Synchronously parses the given URL.
//
// Parameters:
// [In] pIXMLDocument - An interface pointer to an XML document object.
// [In] pidl - The pidl of the cdf file (contains the full path).
//
// Return:
// S_OK if the object was parsed successfully.
// E_FAIL otherwise.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_SynchronousParse(
IXMLDocument* pIXMLDocument,
LPTSTR szPath
)
{
ASSERT(pIXMLDocument);
ASSERT(szPath);
HRESULT hr;
IPersistStreamInit* pIPersistStreamInit;
hr = pIXMLDocument->QueryInterface(IID_IPersistStreamInit,
(void**)&pIPersistStreamInit);
if (SUCCEEDED(hr))
{
ASSERT(pIPersistStreamInit);
IStream* pIStream;
//
// URLOpenBlockingStream pumps window messages! Don't use it!
//
//hr = URLOpenBlockingStream(NULL, szPath, &pIStream, 0, NULL);
hr = SHCreateStreamOnFile(szPath, STGM_READ, &pIStream);
TraceMsg(TF_CDFPARSE, "[%s SHCreateStreamOnFileW %s %s %s]",
PathIsURL(szPath) ? TEXT("*** ") : TEXT(""), szPath,
SUCCEEDED(hr) ? TEXT("SUCCEEDED") : TEXT("FAILED"),
PathIsURL(szPath) ? TEXT("***") : TEXT(""));
if (SUCCEEDED(hr))
{
ASSERT(pIStream);
//
// Load loads and parses the file. If this call succeeds the cdf
// will be displayed. If it fails none of the cdf is displayed.
//
hr = pIPersistStreamInit->Load(pIStream);
TraceMsg(TF_CDFPARSE, "[XML Parser %s]",
SUCCEEDED(hr) ? TEXT("SUCCEEDED") : TEXT("FAILED"));
pIStream->Release();
//
// If CDFVIEW is downloading a CDF from the net mark it as sticky
// in the cache
//
if (PathIsURL(szPath))
{
XML_MarkCacheEntrySticky(szPath);
}
}
pIPersistStreamInit->Release();
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_DownloadImages ***
//
//
// Description:
//
//
// Parameters:
//
//
// Return:
//
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_DownloadLogo(
IXMLDocument *pIXMLDocument
)
{
ASSERT(pIXMLDocument);
HRESULT hr;
IXMLElement* pIXMLElement;
LONG nIndex;
hr = XML_GetFirstChannelElement(pIXMLDocument, &pIXMLElement, &nIndex);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
BSTR bstrURL = XML_GetAttribute(pIXMLElement, XML_LOGO);
if (bstrURL)
{
hr = XML_DownloadImage(bstrURL);
SysFreeString(bstrURL);
}
//
// Download the wide logo also.
//
bstrURL = XML_GetAttribute(pIXMLElement, XML_LOGO_WIDE);
if (bstrURL)
{
hr = XML_DownloadImage(bstrURL);
SysFreeString(bstrURL);
}
pIXMLElement->Release();
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_DownloadImages ***
//
//
// Description:
//
//
// Parameters:
//
//
// Return:
//
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_DownloadImages(
IXMLDocument *pIXMLDocument
)
{
ASSERT(pIXMLDocument);
HRESULT hr;
IXMLElement* pIXMLElement;
LONG nIndex;
hr = XML_GetFirstChannelElement(pIXMLDocument, &pIXMLElement, &nIndex);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
hr = XML_RecursiveImageDownload(pIXMLElement);
pIXMLElement->Release();
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_RecuriveImageDownload ***
//
//
// Description:
//
//
// Parameters:
//
//
// Return:
//
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_RecursiveImageDownload(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
HRESULT hr = S_OK;
BSTR bstrTagName;
HRESULT hr2 = pIXMLElement->get_tagName(&bstrTagName);
if (SUCCEEDED(hr2) && bstrTagName)
{
if (StrEqlW(bstrTagName, WSTR_LOGO))
{
BSTR bstrURL = XML_GetAttribute(pIXMLElement, XML_HREF);
if (bstrURL && *bstrURL != 0)
{
hr = XML_DownloadImage(bstrURL);
SysFreeString(bstrURL);
}
}
else if (XML_IsCdfDisplayable(pIXMLElement))
{
IXMLElementCollection* pIXMLElementCollection;
hr2 = pIXMLElement->get_children(&pIXMLElementCollection);
if (SUCCEEDED(hr2) && pIXMLElementCollection)
{
ASSERT(pIXMLElementCollection);
LONG nCount;
hr2 = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr2) || (FAILED(hr2) && 0 == nCount));
for (int i = 0; i < nCount; i++)
{
IXMLElement* pIXMLElementChild;
hr2 = XML_GetElementByIndex(pIXMLElementCollection, i,
&pIXMLElementChild);
if (SUCCEEDED(hr2))
{
ASSERT (pIXMLElementChild);
XML_RecursiveImageDownload(pIXMLElementChild);
pIXMLElementChild->Release();
}
}
pIXMLElementCollection->Release();
}
}
SysFreeString(bstrTagName);
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_DownloadImage ***
//
//
// Description:
//
//
// Parameters:
//
//
// Return:
//
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_DownloadImage(
LPCWSTR pwszURL
)
{
ASSERT (pwszURL);
HRESULT hr;
WCHAR szFileW[MAX_PATH];
hr = URLDownloadToCacheFileW(NULL, pwszURL, szFileW,
ARRAYSIZE(szFileW), 0, NULL);
//
// Mark the logo in the cache as sticky
//
if (SUCCEEDED(hr))
{
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
SHUnicodeToTChar(pwszURL, szURL, ARRAYSIZE(szURL));
XML_MarkCacheEntrySticky(szURL);
}
#ifdef DEBUG
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
SHUnicodeToTChar(pwszURL, szURL, ARRAYSIZE(szURL));
TraceMsg(TF_CDFPARSE,
"[*** Image URLDownloadToCacheFileW %s %s ***]",
szURL, SUCCEEDED(hr) ? TEXT("SUCCEEDED") :
TEXT("FAILED"));
#endif // DEBUG
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetDocType ***
//
//
// Description:
// Returns the type of the given xml document.
//
// Parameters:
// [In] pIXMLDocument - A pointer to the xml document.
//
// Return:
// DOC_CHANNEL, DOC_DESKTOPCOMPONENT, DOC_SOFTWAREUPDATE, or DOC_UNKNOWN.
//
// Comments:
// If at the root level of a channel an ITEM contains a USAGE type of
// DesktopComponent then the document is a Desktop Component otherwise
// it is a channel.
//
////////////////////////////////////////////////////////////////////////////////
XMLDOCTYPE
XML_GetDocType(IXMLDocument* pIXMLDocument)
{
ASSERT(pIXMLDocument);
XMLDOCTYPE xdtRet;
IXMLElement* pIXMLElement;
LONG nIndex;
HRESULT hr = XML_GetFirstDesktopComponentElement(pIXMLDocument,
&pIXMLElement,
&nIndex);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
xdtRet = DOC_DESKTOPCOMPONENT;
pIXMLElement->Release();
}
else
{
hr = XML_GetFirstChannelElement(pIXMLDocument, &pIXMLElement,
&nIndex);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
BSTR bstr = XML_GetAttribute( pIXMLElement, XML_USAGE_SOFTWAREUPDATE );
if (bstr)
{
SysFreeString(bstr);
xdtRet = DOC_SOFTWAREUPDATE;
}
else
{
xdtRet = DOC_CHANNEL;
}
pIXMLElement->Release();
}
else
{
xdtRet = DOC_UNKNOWN;
}
}
return xdtRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetChildElementCollection ***
//
//
// Description:
// Returns an element collection given the parent collection and an index.
//
// Parameters:
// [In] pParentIXMLElementCollection - The parent collection.
// [In] nIndex - Index to the requested collection.
// [Out] ppIXMLElementCollection - A pointer that receives the
// requested collection.
//
// Return:
// S_OK if the collection is returned.
// E_FAIL otherwise.
//
// Comments:
// The caller is responsible for calling Release() on the returned interface
// pointer.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetChildElementCollection(
IXMLElementCollection *pParentIXMLElementCollection,
LONG nIndex,
IXMLElementCollection** ppIXMLElementCollection
)
{
ASSERT(pParentIXMLElementCollection);
ASSERT(ppIXMLElementCollection);
HRESULT hr;
IXMLElement* pIXMLElement;
hr = XML_GetElementByIndex(pParentIXMLElementCollection, nIndex,
&pIXMLElement);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
hr = pIXMLElement->get_children(ppIXMLElementCollection);
if(SUCCEEDED(hr) && !(*ppIXMLElementCollection))
hr = E_FAIL;
pIXMLElement->Release();
}
ASSERT((SUCCEEDED(hr) && (*ppIXMLElementCollection)) || FAILED(hr));
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetElementByIndex ***
//
//
// Description:
// Returns the nIndex'th element of the given collection.
//
// Parameters:
// [In] pIXMLElementCollection - A pointer to the collection.
// [In] nIndex - The index of the item to retrieve.
// [Out] ppIXMLElement - A pointer that receives the item.
//
// Return:
// S_OK if the item was retrieved.
// E_FAIL otherwise.
//
// Comments:
// The caller is responsible for calling Release() on the returned interface
// pointer.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetElementByIndex(
IXMLElementCollection* pIXMLElementCollection,
LONG nIndex,
IXMLElement** ppIXMLElement
)
{
ASSERT(pIXMLElementCollection);
ASSERT(ppIXMLElement);
HRESULT hr;
VARIANT var1, var2;
VariantInit(&var1);
VariantInit(&var2);
var1.vt = VT_I4;
var1.lVal = nIndex;
IDispatch* pIDispatch;
hr = pIXMLElementCollection->item(var1, var2, &pIDispatch);
if (SUCCEEDED(hr))
{
ASSERT(pIDispatch);
hr = pIDispatch->QueryInterface(IID_IXMLElement, (void**)ppIXMLElement);
pIDispatch->Release();
}
else
{
*ppIXMLElement = NULL;
}
ASSERT((SUCCEEDED(hr) && *ppIXMLElement) ||
(FAILED(hr) && NULL == *ppIXMLElement));
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetElementByName ***
//
//
// Description:
// Returns the first element with the given tag name.
//
// Parameters:
// [In] pIXMLElementCollection - A pointer to the collection.
// [In] nszNameW - The tag name of the item to retrieve.
// [Out] ppIXMLElement - A pointer that receives the item.
//
// Return:
// S_OK if the item was retrieved.
// E_OUTOFMEMORY if a sys string could not be allocated.
// E_FAIL otherwise.
//
// Comments:
// The caller is responsible for calling Release() on the returned interface
// pointer.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetElementByName(
IXMLElementCollection* pIXMLElementCollection,
LPWSTR szNameW,
IXMLElement** ppIXMLElement
)
{
ASSERT(pIXMLElementCollection);
ASSERT(ppIXMLElement);
HRESULT hr = E_FAIL;
LONG nCount;
HRESULT hr2 = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr2) || (FAILED(hr2) && 0 == nCount));
for (int i = 0, bElement = FALSE; (i < nCount) && !bElement; i++)
{
IXMLElement* pIXMLElement;
hr2 = XML_GetElementByIndex(pIXMLElementCollection, i, &pIXMLElement);
if (SUCCEEDED(hr2))
{
ASSERT(pIXMLElement);
BSTR pStr;
hr2 = pIXMLElement->get_tagName(&pStr);
if (SUCCEEDED(hr2) && pStr)
{
ASSERT(pStr);
if (bElement = StrEqlW(pStr, szNameW))
{
pIXMLElement->AddRef();
*ppIXMLElement = pIXMLElement;
hr = S_OK;
}
SysFreeString(pStr);
}
pIXMLElement->Release();
}
}
hr = FAILED(hr2) ? hr2 : hr;
/* Enable this when pIXMLElementCollection->item works with VT_BSTR
VARIANT var1, var2;
VariantInit(&var1);
VariantInit(&var2);
var1.vt = VT_BSTR;
var1.bstrVal = SysAllocString(szNameW);
var2.vt = VT_I4
var2.lVal = 1;
if (var1.bstrVal)
{
IDispatch* pIDispatch;
hr = pIXMLElementCollection->item(var1, var2, &pIDispatch);
if (SUCCEEDED(hr))
{
ASSERT(pIDispatch);
hr = pIDispatch->QueryInterface(IID_IXMLElement,
(void**)ppIXMLElement);
pIDispatch->Release();
}
SysFreeString(var1.bstrVal);
}
else
{
hr = E_OUTOFMEMORY;
}
*/
ASSERT((SUCCEEDED(hr) && ppIXMLElement) || FAILED(hr));
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetFirstChannelElement ***
//
//
// Description:
// Returns the IXMLElement of the first channel in the XML document.
//
// Parameters:
// [In] pIXMLDocument - A pointer to the XML document object.
// [Out] ppIXMLElement - The pointer that receives the element.
// [Out] pnIndex - The index of the element.
//
// Return:
// S_OK if the first channel element was returned.
// E_FAIL if the element couldn't be returned.
//
// Comments:
// This function can't call XML_GetElementByName to find the first channel.
// XML channels can have a tag name of "Channel" or "CHAN".
// XML_GetElementByName wouldn't be able to determine which of the items
// came first if both where present in the XML doc.
//
// The caller is responsible for calling Release() on the returned interface
// pointer. The return pointer is not NULL'ed out on error.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetFirstChannelElement(
IXMLDocument* pIXMLDocument,
IXMLElement** ppIXMLElement,
PLONG pnIndex)
{
ASSERT(pIXMLDocument);
ASSERT(ppIXMLElement);
ASSERT(pnIndex);
IXMLElement *pRootElem = NULL;
HRESULT hr = E_FAIL;
*pnIndex = 0;
hr = pIXMLDocument->get_root(&pRootElem);
if (SUCCEEDED(hr) && pRootElem)
{
ASSERT(pRootElem);
if (XML_IsChannel(pRootElem))
{
*ppIXMLElement = pRootElem;
hr = S_OK;
}
else
{
pRootElem->Release();
hr = E_FAIL;
}
}
else
{
hr = E_FAIL;
}
ASSERT((SUCCEEDED(hr) && (*ppIXMLElement)) || FAILED(hr));
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetDesktopElementFromChannelElement ***
//
//
// Description:
// Returns the IXMLElement of the first dekstop component in the channel.
//
// Parameters:
// [In] pChannelIXMLElement - A pointer to the XML channel element.
// [Out] ppIXMLElement - The pointer that receives the element.
// [Out] pnIndex - The index of the element.
//
// Return:
// S_OK if the first desktop element was returned.
// E_FAIL if the element couldn't be returned.
//
// Comments:
// This looks for the first ITEM with a usage of DesktopComponent.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetDesktopElementFromChannelElement(
IXMLElement* pChannelIXMLElement,
IXMLElement** ppIXMLElement,
PLONG pnIndex)
{
ASSERT(pChannelIXMLElement);
ASSERT(ppIXMLElement);
ASSERT(pnIndex);
HRESULT hr;
IXMLElementCollection* pIXMLElementCollection;
hr = pChannelIXMLElement->get_children(&pIXMLElementCollection);
if (SUCCEEDED(hr) && pIXMLElementCollection)
{
ASSERT(pIXMLElementCollection);
LONG nCount;
hr = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr) || (FAILED(hr) && 0 == nCount));
hr = E_FAIL;
for (int i = 0, bComponent = FALSE; (i < nCount) && !bComponent;
i++)
{
IXMLElement* pIXMLElement;
HRESULT hr2 = XML_GetElementByIndex(pIXMLElementCollection, i,
&pIXMLElement);
if (SUCCEEDED(hr2))
{
ASSERT(pIXMLElement);
if (bComponent = XML_IsDesktopComponent(pIXMLElement))
{
pIXMLElement->AddRef();
*ppIXMLElement = pIXMLElement;
*pnIndex = i;
hr = S_OK;
}
pIXMLElement->Release();
}
hr = FAILED(hr2) ? hr2 : hr;
}
pIXMLElementCollection->Release();
}
else
{
hr = E_FAIL;
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetFirstDesktopComponentElement ***
//
//
// Description:
// Returns the IXMLElement of the first dekstop component in the channel.
//
// Parameters:
// [In] pIXMLDocument - A pointer to the XML document object.
// [Out] ppIXMLElement - The pointer that receives the element.
// [Out] pnIndex - The index of the element.
//
// Return:
// S_OK if the first channel element was returned.
// E_FAIL if the element couldn't be returned.
//
// Comments:
// This function gets the first channel and then looks for the first
// top-level ITEM with a usage of DesktopComponent.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetFirstDesktopComponentElement(
IXMLDocument* pIXMLDocument,
IXMLElement** ppIXMLElement,
PLONG pnIndex)
{
ASSERT(pIXMLDocument);
ASSERT(ppIXMLElement);
ASSERT(pnIndex);
HRESULT hr;
IXMLElement* pChannelIXMLElement;
LONG nIndex;
hr = XML_GetFirstChannelElement(pIXMLDocument, &pChannelIXMLElement,
&nIndex);
if (SUCCEEDED(hr))
{
ASSERT(pChannelIXMLElement);
hr = XML_GetDesktopElementFromChannelElement(pChannelIXMLElement,
ppIXMLElement,
pnIndex);
pChannelIXMLElement->Release();
}
ASSERT((SUCCEEDED(hr) && *ppIXMLElement) || FAILED(hr));
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetFirstDesktopComponentUsageElement ***
//
//
// Description:
// Returns the first USAGE VALUE="DesktopComponent" element of the first
// desktop component.
//
// Parameters:
// [In] pIXMLDocument - A pointer to the the document.
// [Out] pIXMLElement - A pointer the receives the element.
//
// Return:
// S_OK if the element was found.
// E_FAIL if the element wasn't found.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetFirstDesktopComponentUsageElement(
IXMLDocument* pIXMLDocument,
IXMLElement** ppIXMLElement
)
{
ASSERT(pIXMLDocument);
ASSERT(ppIXMLElement);
HRESULT hr;
IXMLElement* pParentIXMLElement;
LONG nIndex;
hr = XML_GetFirstDesktopComponentElement(pIXMLDocument, &pParentIXMLElement,
&nIndex);
if (SUCCEEDED(hr))
{
IXMLElementCollection* pIXMLElementCollection;
hr = pParentIXMLElement->get_children(&pIXMLElementCollection);
if (SUCCEEDED(hr) && pIXMLElementCollection)
{
ASSERT(pIXMLElementCollection);
LONG nCount;
hr = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr) || (FAILED(hr) && 0 == nCount));
hr = E_FAIL;
for (int i = 0, bUsage = FALSE; (i < nCount) && !bUsage; i++)
{
IXMLElement* pIXMLElement;
HRESULT hr2 = XML_GetElementByIndex(pIXMLElementCollection, i,
&pIXMLElement);
if (SUCCEEDED(hr2))
{
ASSERT(pIXMLElement);
if (bUsage = XML_IsDesktopComponentUsage(pIXMLElement))
{
pIXMLElement->AddRef();
*ppIXMLElement = pIXMLElement;
//*pnIndex = i;
hr = S_OK;
}
pIXMLElement->Release();
}
hr = FAILED(hr2) ? hr2 : hr;
}
pIXMLElementCollection->Release();
}
else
{
hr = E_FAIL;
}
pParentIXMLElement->Release();
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetDesktopComponentInfo ***
//
//
// Description:
// Fills in the desktop component information structure.
//
// Parameters:
// [In] pIXMLDocument - A ponter to the document.
// [Out] pInfo - A desktop component information structure.
//
// Return:
// S_OK if the given document is desktop component document.
// E_FAIL otherwise.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetDesktopComponentInfo(
IXMLDocument* pIXMLDocument,
COMPONENT* pInfo
)
{
ASSERT(pIXMLDocument);
ASSERT(pInfo);
HRESULT hr;
IXMLElement* pIXMLElement;
hr = XML_GetFirstDesktopComponentUsageElement(pIXMLDocument, &pIXMLElement);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
memset(pInfo, 0, sizeof(COMPONENT));
pInfo->dwSize = sizeof(COMPONENT);
pInfo->fChecked = TRUE;
pInfo->fDirty = TRUE;
pInfo->fNoScroll = FALSE;
pInfo->cpPos.dwSize = sizeof(COMPPOS);
pInfo->cpPos.izIndex = COMPONENT_TOP;
pInfo->dwCurItemState = IS_NORMAL;
BSTR bstrValue;
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_OPENAS))
{
if (!(0 == StrCmpIW(bstrValue, WSTR_IMAGE)))
{
pInfo->iComponentType = COMP_TYPE_WEBSITE;
}
else
{
pInfo->iComponentType = COMP_TYPE_PICTURE;
}
SysFreeString(bstrValue);
}
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_WIDTH))
{
pInfo->cpPos.dwWidth = StrToIntW(bstrValue);
SysFreeString(bstrValue);
}
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_HEIGHT))
{
pInfo->cpPos.dwHeight = StrToIntW(bstrValue);
SysFreeString(bstrValue);
}
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_ITEMSTATE))
{
if(!StrCmpIW(bstrValue, WSTR_NORMAL))
pInfo->dwCurItemState = IS_NORMAL;
else
{
if(!StrCmpIW(bstrValue, WSTR_FULLSCREEN))
pInfo->dwCurItemState = IS_FULLSCREEN;
else
pInfo->dwCurItemState = IS_SPLIT;
}
SysFreeString(bstrValue);
}
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_CANRESIZE))
{
pInfo->cpPos.fCanResize = StrEqlW(bstrValue, WSTR_YES);
SysFreeString(bstrValue);
}
else
{
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_CANRESIZEX))
{
pInfo->cpPos.fCanResizeX = StrEqlW(bstrValue, WSTR_YES);
SysFreeString(bstrValue);
}
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_CANRESIZEY))
{
pInfo->cpPos.fCanResizeY = StrEqlW(bstrValue, WSTR_YES);
SysFreeString(bstrValue);
}
}
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_PREFERREDLEFT))
{
if (StrChrW(bstrValue, L'%'))
{
pInfo->cpPos.iPreferredLeftPercent = StrToIntW(bstrValue);
}
else
{
pInfo->cpPos.iLeft = StrToIntW(bstrValue);
}
SysFreeString(bstrValue);
}
if (bstrValue = XML_GetAttribute(pIXMLElement, XML_PREFERREDTOP))
{
if (StrChrW(bstrValue, L'%'))
{
pInfo->cpPos.iPreferredTopPercent = StrToIntW(bstrValue);
}
else
{
pInfo->cpPos.iTop = StrToIntW(bstrValue);
}
SysFreeString(bstrValue);
}
IXMLElement *pIXMLElementParent;
hr = pIXMLElement->get_parent(&pIXMLElementParent);
if(!pIXMLElementParent)
hr = E_FAIL;
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElementParent);
if (bstrValue = XML_GetAttribute(pIXMLElementParent, XML_TITLE))
{
StrCpyNW(pInfo->wszFriendlyName, bstrValue,
ARRAYSIZE(pInfo->wszFriendlyName));
SysFreeString(bstrValue);
}
if (bstrValue = XML_GetAttribute(pIXMLElementParent, XML_HREF))
{
if (*bstrValue)
{
StrCpyNW(pInfo->wszSource, bstrValue,
ARRAYSIZE(pInfo->wszSource));
SysFreeString(bstrValue);
}
else
{
hr = E_FAIL;
}
}
if (SUCCEEDED(hr))
{
IXMLElement *pIXMLChannel;
LONG nIndex;
hr = XML_GetFirstChannelElement(pIXMLDocument, &pIXMLChannel,
&nIndex);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLChannel);
if (bstrValue = XML_GetAttribute(pIXMLChannel, XML_SELF))
{
StrCpyNW(pInfo->wszSubscribedURL, bstrValue,
ARRAYSIZE(pInfo->wszSubscribedURL));
SysFreeString(bstrValue);
}
pIXMLChannel->Release();
}
}
pIXMLElementParent->Release();
}
pIXMLElement->Release();
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetAttribute ***
//
//
// Description:
// Returns a bstr representing the requested attribute of the given element.
//
// Parameters:
// [In] pIXMLElement - A pointer to the XML element.
// [In] attribute - The requested attribute.
//
// Return:
// A bstr with the attribute value.
// NULL if there wasn't enough memory to allocated the bstr.
//
// Comments:
// This function keeps a table of attributes and their properties. It bases
// attribute look up on this table.
//
////////////////////////////////////////////////////////////////////////////////
BSTR
XML_GetAttribute(
IXMLElement* pIXMLElement,
XML_ATTRIBUTE attrIndex
)
{
//
// A table is used to read values associated with a given xml element. The
// xml element can have attributes (values inside the elements tag) or child
// elements (elements between tags).
//
// Rules:
// 1) If child is NULL. Read the Attribute from the current item.
// 2) If child is not NULL, read the Attribute from the child
// item.
// 3) If AttributeType is NULL, use the Attribute value to read the
// attribute.
// 4) If AttributeType is not NULL, verify that the item contains
// the AttributeType attribute before using Attribute to read
// the value.
// 5) If the value is not found use Default as the return value.
//
static const struct _tagXML_ATTRIBUTE_ARRAY
{
LPWSTR szChildW;
LPWSTR szAttributeW;
LPWSTR szQualifierW;
LPWSTR szQualifierValueW;
XML_ATTRIBUTE attrSecondary;
LPWSTR szDefaultW;
BOOL fUseBaseURL;
XML_ATTRIBUTE attribute; // Only used in ASSERT.
}
aAttribTable[] =
{
/*
Child Attribute Qualifier Qual. Value Secondary Lookup Default Base URL Enum Check
-------------- -------------- ----------- ------------ ----------------- ---------- -------- -----------------*/
{WSTR_TITLE, NULL, NULL, NULL, XML_TITLE_ATTR, WSTR_EMPTY, FALSE, XML_TITLE },
{NULL, WSTR_TITLE, NULL, NULL, XML_HREF, WSTR_EMPTY, FALSE, XML_TITLE_ATTR },
{NULL, WSTR_HREF, NULL, NULL, XML_A_HREF, WSTR_EMPTY, TRUE, XML_HREF },
{WSTR_ABSTRACT, NULL, NULL, NULL, XML_ABSTRACT_ATTR, WSTR_EMPTY, FALSE, XML_ABSTRACT },
{NULL, WSTR_ABSTRACT, NULL, NULL, XML_HREF, WSTR_EMPTY, FALSE, XML_ABSTRACT_ATTR},
{WSTR_LOGO, WSTR_HREF, WSTR_STYLE, WSTR_ICON, XML_NULL, NULL, TRUE, XML_ICON },
{WSTR_LOGO, WSTR_HREF, WSTR_STYLE, WSTR_IMAGE, XML_LOGO_DEFAULT, NULL, TRUE, XML_LOGO },
{WSTR_LOGO, WSTR_HREF, NULL, NULL, XML_NULL, NULL, TRUE, XML_LOGO_DEFAULT },
{NULL, WSTR_SELF, NULL, NULL, XML_SELF_OLD, NULL, TRUE, XML_SELF },
{WSTR_SELF, WSTR_HREF, NULL, NULL, XML_NULL, NULL, TRUE, XML_SELF_OLD },
{NULL, WSTR_BASE, NULL, NULL, XML_NULL, NULL, FALSE, XML_BASE },
{WSTR_USAGE, WSTR_VALUE, NULL, NULL, XML_SHOW, NULL, FALSE, XML_USAGE },
{WSTR_USAGE, WSTR_VALUE, WSTR_VALUE, WSTR_CHANNEL, XML_SHOW_CHANNEL, NULL, FALSE, XML_USAGE_CHANNEL},
{WSTR_USAGE, WSTR_VALUE, WSTR_VALUE, WSTR_DSKCMP, XML_SHOW_DSKCMP, NULL, FALSE, XML_USAGE_DSKCMP },
{WSTR_WIDTH, WSTR_VALUE, NULL, NULL, XML_NULL, WSTR_ZERO, FALSE, XML_WIDTH },
{WSTR_HEIGHT, WSTR_VALUE, NULL, NULL, XML_NULL, WSTR_ZERO, FALSE, XML_HEIGHT },
{WSTR_RESIZE, WSTR_VALUE, NULL, NULL, XML_NULL, NULL, FALSE, XML_CANRESIZE },
{WSTR_RESIZEX, WSTR_VALUE, NULL, NULL, XML_NULL, WSTR_YES, FALSE, XML_CANRESIZEX },
{WSTR_RESIZEY, WSTR_VALUE, NULL, NULL, XML_NULL, WSTR_YES, FALSE, XML_CANRESIZEY },
{WSTR_PREFLEFT, WSTR_VALUE, NULL, NULL, XML_NULL, NULL, FALSE, XML_PREFERREDLEFT},
{WSTR_PREFTOP, WSTR_VALUE, NULL, NULL, XML_NULL, NULL, FALSE, XML_PREFERREDTOP },
{WSTR_OPENAS, WSTR_VALUE, NULL, NULL, XML_NULL, WSTR_HTML, FALSE, XML_OPENAS },
{NULL, WSTR_SHOW, NULL, NULL, XML_NULL, NULL, FALSE, XML_SHOW },
{NULL, WSTR_SHOW, WSTR_SHOW, WSTR_CHANNEL, XML_NULL, NULL, FALSE, XML_SHOW_CHANNEL },
{NULL, WSTR_SHOW, WSTR_SHOW, WSTR_DSKCMP, XML_NULL, NULL, FALSE, XML_SHOW_DSKCMP },
{WSTR_A, WSTR_HREF, NULL, NULL, XML_INFOURI, WSTR_EMPTY, TRUE, XML_A_HREF },
{NULL, WSTR_INFOURI, NULL, NULL, XML_NULL, WSTR_EMPTY, TRUE, XML_INFOURI },
{WSTR_LOGO, WSTR_HREF, WSTR_STYLE, WSTR_IMAGEW, XML_NULL, NULL, TRUE, XML_LOGO_WIDE },
{WSTR_LOGIN, NULL, NULL, NULL, XML_NULL, NULL, FALSE, XML_LOGIN },
{WSTR_USAGE, WSTR_VALUE, WSTR_VALUE, WSTR_SOFTWAREUPDATE, XML_SHOW_SOFTWAREUPDATE, NULL, FALSE, XML_USAGE_SOFTWAREUPDATE},
{NULL, WSTR_SHOW, WSTR_SHOW, WSTR_SOFTWAREUPDATE, XML_NULL, NULL, FALSE, XML_SHOW_SOFTWAREUPDATE },
{WSTR_ITEMSTATE,WSTR_VALUE, NULL, NULL, XML_NULL, WSTR_NORMAL,FALSE, XML_ITEMSTATE },
};
ASSERT(pIXMLElement);
//
// REVIEW: aAttribTable attribute field only used in debug builds.
//
ASSERT(attrIndex == aAttribTable[attrIndex].attribute);
BSTR bstrRet = NULL;
if (NULL == aAttribTable[attrIndex].szAttributeW)
{
bstrRet = XML_GetGrandChildContent(pIXMLElement,
aAttribTable[attrIndex].szChildW);
}
else if (NULL != aAttribTable[attrIndex].szChildW)
{
bstrRet = XML_GetChildAttribute(pIXMLElement,
aAttribTable[attrIndex].szChildW,
aAttribTable[attrIndex].szAttributeW,
aAttribTable[attrIndex].szQualifierW,
aAttribTable[attrIndex].szQualifierValueW);
}
else
{
bstrRet = XML_GetElementAttribute(pIXMLElement,
aAttribTable[attrIndex].szAttributeW,
aAttribTable[attrIndex].szQualifierW,
aAttribTable[attrIndex].szQualifierValueW);
}
//
// If the title or tooltip aren't displayable on the local system use the
// URL in their place.
//
if (bstrRet && (XML_TITLE == attrIndex || XML_TITLE_ATTR == attrIndex ||
XML_ABSTRACT == attrIndex))
{
if (!StrLocallyDisplayable(bstrRet))
{
SysFreeString(bstrRet);
bstrRet = NULL;
}
}
//
// Special cases:
// TITLE can also be an attribute.
// ABSTRACT can also be an attribute.
// LOGO elements don't have to have the TYPE="IMAGE"
// SELF is now an attribute SELF_OLD can be removed in the future.
// USAGE can also be specified via the SHOW attribute.
// USAGE_CHANNEL should also check for SHOW="Channel".
// USAGE_DSKCMP should also check for SHOW="DesktopComponent"
//
if (NULL == bstrRet && XML_NULL != aAttribTable[attrIndex].attrSecondary)
{
bstrRet = XML_GetAttribute(pIXMLElement,
aAttribTable[attrIndex].attrSecondary);
}
//
// Combine URL if required.
//
if (bstrRet && aAttribTable[attrIndex].fUseBaseURL)
{
BSTR bstrBaseURL = XML_GetBaseURL(pIXMLElement);
if (bstrBaseURL)
{
BSTR bstrCombinedURL = XML_CombineURL(bstrBaseURL, bstrRet);
if (bstrCombinedURL)
{
SysFreeString(bstrRet);
bstrRet = bstrCombinedURL;
}
SysFreeString(bstrBaseURL);
}
}
/* The following prevent long urls from over-running the pidl buffer */
if (bstrRet &&
(attrIndex == XML_HREF) &&
(SysStringLen(bstrRet) > INTERNET_MAX_URL_LENGTH))
{
SysReAllocStringLen(&bstrRet, bstrRet, INTERNET_MAX_URL_LENGTH-1);
}
//
// Set default return value.
//
if (NULL == bstrRet && aAttribTable[attrIndex].szDefaultW)
bstrRet = SysAllocString(aAttribTable[attrIndex].szDefaultW);
return bstrRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetFirstChildContent ***
//
// Description:
// Returns a bstr value from first child of the given element.
//
// Parameters:
// [In] pIXMLElement - A pointer to the element.
// The caller is responsible for freeing the returned bstr.
//
// Comments:
// If pIElement represents
//
// <Title>Harvey is a Cool Cat<B>this will be ignored</B></Title>
//
// Then this function will return
//
// "Harvey is a Cool Cat"
//
// REVIEW THIS IS A TEMPORARY ROUTINE UNTIL THE XML PARSER SUPPORTS THIS DIRECTLY
//
////////////////////////////////////////////////////////////////////////////////
BSTR
XML_GetFirstChildContent(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
BSTR bstrRet = NULL;
IXMLElementCollection* pIXMLElementCollection;
if ((SUCCEEDED(pIXMLElement->get_children(&pIXMLElementCollection)))
&& pIXMLElementCollection)
{
ASSERT(pIXMLElementCollection);
LONG nCount;
HRESULT hr = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr) || (FAILED(hr) && 0 == nCount));
if (nCount >= 1)
{
IXMLElement* pChildIXMLElement;
if (SUCCEEDED(XML_GetElementByIndex(pIXMLElementCollection, 0,
&pChildIXMLElement)))
{
ASSERT(pChildIXMLElement);
if (FAILED(pChildIXMLElement->get_text(&bstrRet)))
{
bstrRet = NULL;
}
pChildIXMLElement->Release();
}
}
pIXMLElementCollection->Release();
}
return bstrRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetGrandChildContent ***
//
// Description:
// Returns a bstr value from the requested child of the given element.
//
// Parameters:
// [In] pIXMLElement - A pointer to the element.
// [In] szChildW - The name of the child element.
// The caller is responsible for freeing the returned bstr.
//
// Comments:
// If pIElement represents
//
// <Channel>
// <Title>Harvey is a Cool Cat</Title>
// </Channel>
//
// Then this function will return
//
// "Harvey is a Cool Cat" for "TITLE",
//
////////////////////////////////////////////////////////////////////////////////
BSTR
XML_GetGrandChildContent(
IXMLElement* pIXMLElement,
LPWSTR szChildW
)
{
ASSERT(pIXMLElement);
ASSERT(szChildW);
BSTR bstrRet = NULL;
IXMLElementCollection* pIXMLElementCollection;
if ((SUCCEEDED(pIXMLElement->get_children(&pIXMLElementCollection)))
&& pIXMLElementCollection)
{
ASSERT(pIXMLElementCollection);
LONG nCount;
HRESULT hr = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr) || (FAILED(hr) && 0 == nCount));
for (int i = 0; (i < nCount) && !bstrRet; i++)
{
IXMLElement* pChildIXMLElement;
if (SUCCEEDED(XML_GetElementByIndex(pIXMLElementCollection, i,
&pChildIXMLElement)))
{
ASSERT(pChildIXMLElement);
BSTR bstrTagName;
if (SUCCEEDED(pChildIXMLElement->get_tagName(&bstrTagName)) && bstrTagName)
{
ASSERT(bstrTagName);
if (StrEqlW(bstrTagName, szChildW))
{
bstrRet = XML_GetFirstChildContent(pChildIXMLElement);
//
// If the tag exists, but it is empty, return the empty
// string.
//
if (NULL == bstrRet)
bstrRet = SysAllocString(L"");
}
SysFreeString(bstrTagName);
}
pChildIXMLElement->Release();
}
}
pIXMLElementCollection->Release();
}
return bstrRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetChildAttribute ***
//
//
// Description:
// Returns a bstr value from the requested child of the given element.
//
// Parameters:
// [In] pIXMLElement - A pointer to the element.
// [In] szChildW - The name of the child element.
// [In] szAttributeW - The name of the attribute.
// [In] szQualifierW - The name of the attribute qualifier.
// [In] szQualifierValueW - The required value of the qaulifier.
//
// Return:
// A bstr of the value contained in the child element if it is found.
// NULL if the child element or its value isn't found.
//
// Comments:
// This function will return atributes found in the child elements of the
// given element. For example:
//
// If pIElement represents
//
// <Channel>
// <Title VALUE="foo">
// <Author VALUE="bar">
// <Logo HRREF="url" TYPE="ICON">
// </Channel>
//
// Then this function will return
//
// "foo" for "TITLE", "VALUE", "", ""
// "bar" for "AUTHOR", "VALUE", "", ""
// "url" for "LOGO", "HREF", "TYPE", "ICON"
//
// NULL when the names have any other values.
//
// The caller is responsible for freeing the returned bstr.
//
////////////////////////////////////////////////////////////////////////////////
BSTR
XML_GetChildAttribute(
IXMLElement* pIXMLElement,
LPWSTR szChildW,
LPWSTR szAttributeW,
LPWSTR szQualifierW,
LPWSTR szQualifierValueW
)
{
ASSERT(pIXMLElement);
ASSERT(szChildW);
ASSERT(szAttributeW);
BSTR bstrRet = NULL;
IXMLElementCollection* pIXMLElementCollection;
if ((SUCCEEDED(pIXMLElement->get_children(&pIXMLElementCollection)))
&& pIXMLElementCollection)
{
ASSERT(pIXMLElementCollection);
LONG nCount;
//
// REVIEW: hr only used in debug builds.
//
HRESULT hr = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr) || (FAILED(hr) && 0 == nCount));
for (int i = 0; (i < nCount) && !bstrRet; i++)
{
IXMLElement* pChildIXMLElement;
if (SUCCEEDED(XML_GetElementByIndex(pIXMLElementCollection, i,
&pChildIXMLElement)))
{
ASSERT(pChildIXMLElement);
BSTR bstrTagName;
if (SUCCEEDED(pChildIXMLElement->get_tagName(&bstrTagName)) && bstrTagName)
{
ASSERT(bstrTagName);
if (StrEqlW(bstrTagName, szChildW))
{
bstrRet = XML_GetElementAttribute(pChildIXMLElement,
szAttributeW,
szQualifierW,
szQualifierValueW);
}
SysFreeString(bstrTagName);
}
pChildIXMLElement->Release();
}
}
pIXMLElementCollection->Release();
}
return bstrRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetElementAttribute ***
//
//
// Description:
// Returns the bstr value of of the requested attribute if it is found.
//
// Parameters:
// [In] pIXMLElement - The element that contains the attribute.
// [In] szAttributeW - The name of the attribute.
// [In] szQualifierW - The type qualifier for the atribute.
// [In] szQualifierValueW - The required value of the qaulifier.
//
// Return:
// A bstr containig the attributes value if it was found.
// NULL if the attribute wasn't found.
//
// Comments:
// The function will return attributes found inside of tags. For
// example:
//
// If pIXMLElement represents
//
// <Channel HREF="foo" Cloneable="NO">
// <USAGE VALUE="Channel">
// <USAGE VALUE="Screen Saver">
//
// Then this function will return
//
// "foo" for "HREF", "", ""
// "NO" for "Cloneable", "", ""
// "CHANNEL" for "VALUE", "VALUE", "CHANNEL"
// NULL for "VALUE", "VALUE", "NONE"
// "foo" for "HREF", "CLONEABLE", "NO"
//
// The caller is responsible for freeing the returned bstr.
//
////////////////////////////////////////////////////////////////////////////////
BSTR
XML_GetElementAttribute(
IXMLElement* pIXMLElement,
LPWSTR szAttributeW,
LPWSTR szQualifierW,
LPWSTR szQualifierValueW
)
{
ASSERT(pIXMLElement);
ASSERT(szAttributeW);
ASSERT((NULL == szQualifierW && NULL == szQualifierValueW) ||
(szQualifierW && szQualifierValueW));
BSTR bstrRet = NULL;
VARIANT var;
VariantInit(&var);
if (NULL == szQualifierW)
{
if (SUCCEEDED(pIXMLElement->getAttribute(szAttributeW, &var)))
{
ASSERT(var.vt == VT_BSTR || NULL == var.bstrVal);
bstrRet = var.bstrVal;
}
}
else
{
if (SUCCEEDED(pIXMLElement->getAttribute(szQualifierW, &var)))
{
ASSERT(var.vt == VT_BSTR || NULL == var.bstrVal);
if(var.bstrVal)
{
if (0 == StrCmpIW(var.bstrVal, szQualifierValueW))
{
bstrRet = XML_GetElementAttribute(pIXMLElement, szAttributeW,
NULL, NULL);
}
}
VariantClear(&var);
}
}
return bstrRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetScreenSaverURL ***
//
//
// Description:
// Returns the screen saver URL of the first screen saver component in the channel.
//
// Parameters:
// [In] pXMLDocument - An XML document
// [Out] pbstrSSURL - The pointer that receives the screen saver URL.
//
// Return:
// S_OK if the screen saver URL was returned.
// E_FAIL if the screen saver URL couldn't be returned.
//
// Comments:
// This function gets the first screen saver element and then looks
// for the first top-level ITEM with a usage of ScreenSaver.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetScreenSaverURL(
IXMLDocument * pXMLDocument,
BSTR * pbstrSSURL)
{
HRESULT hr;
ASSERT(pXMLDocument);
ASSERT(pbstrSSURL);
IXMLElement* pIXMLElement;
LONG lDontCare;
hr = XML_GetFirstChannelElement(pXMLDocument, &pIXMLElement, &lDontCare);
if (SUCCEEDED(hr))
{
IXMLElement* pSSElement;
ASSERT(pIXMLElement);
hr = XML_GetScreenSaverElement(pIXMLElement, &pSSElement);
if (SUCCEEDED(hr))
{
ASSERT(pSSElement);
*pbstrSSURL = XML_GetAttribute(pSSElement, XML_HREF);
hr = *pbstrSSURL ? S_OK : E_FAIL;
pSSElement->Release();
}
pIXMLElement->Release();
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetScreenSaverElement ***
//
//
// Description:
// Returns the IXMLElement of the first screen saver component in the channel.
//
// Parameters:
// [In] pXMLElemet - An XML element
// [Out] ppIXMLElement - The pointer that receives the screen saver element.
//
// Return:
// S_OK if the first screen saver element was returned.
// E_FAIL if the element couldn't be returned.
//
// Comments:
// This function gets the first screen saver element and then looks
// for the first top-level ITEM with a usage of ScreenSaver.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetScreenSaverElement(
IXMLElement * pXMLElement,
IXMLElement ** ppScreenSaverElement)
{
ASSERT(pXMLElement);
ASSERT(ppScreenSaverElement);
IXMLElementCollection * pIXMLElementCollection;
HRESULT hr;
hr = pXMLElement->get_children(&pIXMLElementCollection);
if (SUCCEEDED(hr) && pIXMLElementCollection)
{
LONG nCount;
hr = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr) || (FAILED(hr) && 0 == nCount));
hr = E_FAIL;
BOOL bScreenSaver = FALSE;
for (int i = 0; (i < nCount) && !bScreenSaver; i++)
{
IXMLElement * pIXMLElement;
HRESULT hr2 = XML_GetElementByIndex(pIXMLElementCollection,
i,
&pIXMLElement);
if (SUCCEEDED(hr2))
{
ASSERT(pIXMLElement != NULL);
if (bScreenSaver = XML_IsScreenSaver(pIXMLElement))
{
pIXMLElement->AddRef();
*ppScreenSaverElement = pIXMLElement;
hr = S_OK;
}
pIXMLElement->Release();
}
hr = FAILED(hr2) ? hr2 : hr;
}
pIXMLElementCollection->Release();
}
else
hr = E_FAIL;
ASSERT((SUCCEEDED(hr) && *ppScreenSaverElement) || FAILED(hr));
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetSubscriptionInfo ***
//
//
// Description:
// Fills a structure with the subscription info for the given element.
//
// Parameters:
// [In] pIXMLElement - An xml element. The element doesn't have to be a
// subscription element.
// [Out] psi - The subscription info structure used by the
// subscription manager.
//
// Return:
// S_OK if any information was obtained.
//
// Comments:
// This function uses a webcheck API that fills a task trigger with
// subscription information.
//
// This function assumes that the psi->pTrigger points to a TASK_TRIGGER.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
XML_GetSubscriptionInfo(
IXMLElement* pIXMLElement,
SUBSCRIPTIONINFO* psi
)
{
ASSERT(pIXMLElement);
ASSERT(psi);
ASSERT(psi->pTrigger);
HRESULT hr = E_FAIL;
#ifndef UNIX
HINSTANCE hinst = LoadLibrary(TEXT("webcheck.dll"));
if (hinst)
{
typedef (*PFTRIGGERFUNCTION)(IXMLElement* pIXMLElement,
TASK_TRIGGER* ptt);
PFTRIGGERFUNCTION XMLSheduleElementToTaskTrigger;
XMLSheduleElementToTaskTrigger = (PFTRIGGERFUNCTION)
GetProcAddress(hinst,
"XMLScheduleElementToTaskTrigger");
if (XMLSheduleElementToTaskTrigger)
{
((TASK_TRIGGER*)(psi->pTrigger))->cbTriggerSize =
sizeof(TASK_TRIGGER);
hr = XMLSheduleElementToTaskTrigger(pIXMLElement,
(TASK_TRIGGER*)psi->pTrigger);
if (FAILED(hr))
psi->pTrigger = NULL;
}
FreeLibrary(hinst);
}
// See if there is a screen saver available.
IXMLElement * pScreenSaverElement;
if (SUCCEEDED(XML_GetScreenSaverElement( pIXMLElement,
&pScreenSaverElement)))
{
psi->fUpdateFlags |= SUBSINFO_CHANNELFLAGS;
psi->fChannelFlags |= CHANNEL_AGENT_PRECACHE_SCRNSAVER;
pScreenSaverElement->Release();
}
BSTR bstrLogin = XML_GetAttribute(pIXMLElement, XML_LOGIN);
if (bstrLogin)
{
psi->bNeedPassword = TRUE;
psi->fUpdateFlags |= SUBSINFO_NEEDPASSWORD; //this member is now valid
SysFreeString(bstrLogin);
}
#endif /* !UNIX */
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_GetBaseURL ***
//
//
// Description:
// Returns the base url for the given collection.
//
// Parameters:
// [In] pIXMLElement - A pointer to an XML element.
//
// Return:
// A bstr containing the base URL if there is one.
// NULL if ther isn't a base URL.
//
// Comments:
// If the current element has a BASE attribute return this attributes value.
// Else return the BASE attribute of its parent.
//
////////////////////////////////////////////////////////////////////////////////
BSTR
XML_GetBaseURL(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
BSTR bstrRet = XML_GetAttribute(pIXMLElement, XML_BASE);
if (NULL == bstrRet)
{
IXMLElement* pParentIXMLElement;
if (SUCCEEDED(pIXMLElement->get_parent(&pParentIXMLElement)) && pParentIXMLElement)
{
ASSERT(pParentIXMLElement);
bstrRet = XML_GetBaseURL(pParentIXMLElement);
pParentIXMLElement->Release();
}
}
return bstrRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_CombineURL ***
//
//
// Description:
// Combine the given URL with the base URL.
//
// Parameters:
// [In] bstrBaseURL - The base URL.
// [In] bstrRelURL - The relative URL.
//
// Return:
// A combination of the base and relative URL.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
BSTR
XML_CombineURL(
BSTR bstrBaseURL,
BSTR bstrRelURL
)
{
ASSERT(bstrBaseURL);
ASSERT(bstrRelURL);
BSTR bstrRet = NULL;
WCHAR wszCombinedURL[INTERNET_MAX_URL_LENGTH];
DWORD cch = ARRAYSIZE(wszCombinedURL);
if (InternetCombineUrlW(bstrBaseURL, bstrRelURL, wszCombinedURL, &cch, 0))
bstrRet = SysAllocString(wszCombinedURL);
return bstrRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsCdfDisplayable ***
//
//
// Description:
// Determines if the given item should be displayed in the cdf view.
//
// Parameters:
// [In] pIXMLElement - A pointer to the IXMLElement interface of an object.
//
// Return:
// TRUE if the object should be displayed.
// FALSE otherwise.
//
// Comments:
// aCDFTypes contains the tag names of XML items that the cdf shell
// shell extension displays.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsCdfDisplayable(
IXMLElement* pIXMLElement
)
{
#define KEYWORDS (sizeof(aCDFTypes) / sizeof(aCDFTypes[0]))
static const LPWSTR aCDFTypes[] = {
WSTR_ITEM,
WSTR_CHANNEL,
WSTR_SOFTDIST
};
ASSERT(pIXMLElement);
BOOL bRet = FALSE;
BSTR pStr;
HRESULT hr = pIXMLElement->get_tagName(&pStr);
if (SUCCEEDED(hr) && pStr)
{
ASSERT(pStr);
for(int i = 0; (i < KEYWORDS) && !bRet; i++)
bRet = StrEqlW(pStr, aCDFTypes[i]);
if (bRet)
bRet = XML_IsUsageChannel(pIXMLElement);
//
// Special processing.
//
if (bRet && StrEqlW(pStr, WSTR_SOFTDIST))
bRet = XML_IsSoftDistDisplayable(pIXMLElement);
SysFreeString(pStr);
}
return bRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsSoftDistDisplayable ***
//
//
// Description:
// Determins if the given software distribution element should be displayed.
//
// Parameters:
// [In] pIXMLElement - Pointer to the software distribution xml element.
//
// Return:
// TRUE if the element should be displayed.
// FALSE if the element shouldn't be displayed.
//
// Comments:
// This function asks the software disribution COM object if this software
// distribution tag should be displayed on this users machine.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsSoftDistDisplayable(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
ISoftDistExt* pISoftDistExt;
HRESULT hr = CoCreateInstance(CLSID_SoftDistExt, NULL, CLSCTX_INPROC_SERVER,
IID_ISoftDistExt, (void**)&pISoftDistExt);
if (SUCCEEDED(hr))
{
ASSERT(pISoftDistExt);
hr = pISoftDistExt->ProcessSoftDist(NULL, pIXMLElement, 0);
pISoftDistExt->Release();
}
return SUCCEEDED(hr) ? TRUE : FALSE;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsUsageChannel ***
//
//
// Description:
// Determines if this item should be displayed in channel view based on its
// usage tag.
//
// Parameters:
// [In] pIXMLelement - A pointer to the element.
//
// Return:
// TRUE if the item should be displayed in the channel view.
// FALSE otherwise.
//
// Comments:
// If an element doesn't have a USAGE tag then it gets displayed. If an
// element has any numberf of usage tags one of them must have a value of
// CHANNEL or will not get displayed.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsUsageChannel(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
BOOL bRet;
//
// First check if there are any USAGE elements.
//
BSTR bstrUsage = XML_GetAttribute(pIXMLElement, XML_USAGE);
if (bstrUsage)
{
//
// See if USAGE is CHANNEL.
//
if (StrEqlW(bstrUsage, WSTR_CHANNEL))
{
bRet = TRUE;
}
else
{
//
// Check if there are any other USAGE tags with value CHANNEL.
//
BSTR bstrChannel = XML_GetAttribute(pIXMLElement,
XML_USAGE_CHANNEL);
if (bstrChannel)
{
SysFreeString(bstrChannel);
bRet = TRUE;
}
else
{
bRet = FALSE;
}
}
SysFreeString(bstrUsage);
}
else
{
bRet = TRUE; // No USAGE tag defaults channel usage.
}
return bRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsChannel ***
//
//
// Description:
// Determines if the given XML item is a channel.
//
// Parameters:
// [In] pIXMLElement - A pointer to the IXMLElement interface of an object.
//
// Return:
// TRUE if the object is a channel.
// FALSE otherwise.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsChannel(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
BOOL bRet = FALSE;
BSTR pStr;
HRESULT hr = pIXMLElement->get_tagName(&pStr);
if (SUCCEEDED(hr) && pStr)
{
ASSERT(pStr);
bRet = StrEqlW(pStr, WSTR_CHANNEL);
SysFreeString(pStr);
}
return bRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsDesktopComponent ***
//
//
// Description:
// Determines if the given XML item is a desktop component.
//
// Parameters:
// [In] pIXMLElement - A pointer to the IXMLElement interface of an object.
//
// Return:
// TRUE if the object is a desktop component.
// FALSE otherwise.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsDesktopComponent(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
BOOL bRet;
BSTR bstr = XML_GetAttribute(pIXMLElement, XML_USAGE_DSKCMP);
if (bstr)
{
SysFreeString(bstr);
bRet = TRUE;
}
else
{
bRet = FALSE;
}
return bRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsScreenSaver ***
//
//
// Description:
// Determines if the given XML item is a screen saver.
//
// Parameters:
// [In] pIXMLElement - A pointer to the IXMLElement interface of an object.
//
// Return:
// TRUE if the object is a screen saver
// FALSE otherwise.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsScreenSaver(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
BOOL bRet;
BSTR bstrUsage = XML_GetAttribute(pIXMLElement, XML_USAGE);
if (bstrUsage)
{
bRet = (
(StrCmpIW(bstrUsage, WSTR_SCRNSAVE) == 0)
||
(StrCmpIW(bstrUsage, WSTR_SMARTSCRN) == 0)
);
SysFreeString(bstrUsage);
}
else
{
bRet = FALSE;
}
return bRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsDesktopComponentUsage ***
//
//
// Description:
// Determines if the given XML item is a desktop component usage element.
//
// Parameters:
// [In] pIXMLElement - A pointer to the IXMLElement interface of an object.
//
// Return:
// TRUE if the object is a desktop component usage element.
// FALSE otherwise.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsDesktopComponentUsage(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
BOOL bRet = FALSE;
BSTR bstrName;
if (SUCCEEDED(pIXMLElement->get_tagName(&bstrName)) && bstrName)
{
ASSERT(bstrName);
if (StrEqlW(bstrName, WSTR_USAGE))
{
BSTR bstrValue = XML_GetElementAttribute(pIXMLElement, WSTR_VALUE, NULL,
NULL);
if (bstrValue)
{
bRet = (0 == StrCmpIW(bstrValue, WSTR_DSKCMP));
SysFreeString(bstrValue);
}
}
SysFreeString(bstrName);
}
return bRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsFolder ***
//
//
// Description:
// Determines if the given item is a folder.
//
// Parameters:
// [In] pIXMLElement - A pointer to the IXMLElement interface of an object.
//
// Return:
// TRUE if the object contains other cdf displayable objects.
// FALSE otherwise.
//
// Comments:
// An item is a folder if at least one of its children is displayable as a
// cdf item.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsFolder(
IXMLElement* pIXMLElement
)
{
ASSERT(pIXMLElement);
BOOL bRet = FALSE;
IXMLElementCollection* pIXMLElementCollection;
HRESULT hr = pIXMLElement->get_children(&pIXMLElementCollection);
if (SUCCEEDED(hr) && pIXMLElementCollection)
{
ASSERT(pIXMLElementCollection);
LONG nCount;
hr = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr) || (FAILED(hr) && 0 == nCount));
for (int i = 0; (i < nCount) && !bRet; i++)
{
IXMLElement* pIXMLElementTemp;
hr = XML_GetElementByIndex(pIXMLElementCollection, i, &pIXMLElementTemp);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElementTemp);
if (XML_IsCdfDisplayable(pIXMLElementTemp))
bRet = TRUE;
pIXMLElementTemp->Release();
}
}
pIXMLElementCollection->Release();
}
return bRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_ContainsFolder ***
//
//
// Description:
// Determines if there are any cdf folders in the given collection.
//
// Parameters:
// [In] pIXMLElementCollection - A pointer to the collection.
//
// Return:
// TRUE if the collection contains a cf folder.
// FALSE otherwise.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_ContainsFolder(
IXMLElementCollection* pIXMLElementCollection
)
{
ASSERT(pIXMLElementCollection);
BOOL bContainsFolder = FALSE;
LONG nCount;
HRESULT hr = pIXMLElementCollection->get_length(&nCount);
ASSERT(SUCCEEDED(hr) || (FAILED(hr) && 0 == nCount));
for (int i = 0; (i < nCount) && !bContainsFolder; i++)
{
IXMLElement* pIXMLElement;
hr = XML_GetElementByIndex(pIXMLElementCollection, i, &pIXMLElement);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
bContainsFolder = XML_IsFolder(pIXMLElement);
pIXMLElement->Release();
}
}
return bContainsFolder;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_ChildContainsFolder ***
//
//
// Description:
//
//
// Parameters:
//
//
// Return:
//
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_ChildContainsFolder(
IXMLElementCollection *pIXMLElementCollectionParent,
ULONG nIndexChild
)
{
BOOL bRet = FALSE;
IXMLElement* pIXMLElement;
HRESULT hr = XML_GetElementByIndex(pIXMLElementCollectionParent,
nIndexChild, &pIXMLElement);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
IXMLElementCollection* pIXMLElementCollection;
hr = pIXMLElement->get_children(&pIXMLElementCollection);
if (SUCCEEDED(hr) && pIXMLElementCollection)
{
ASSERT(pIXMLElementCollection);
bRet = XML_ContainsFolder(pIXMLElementCollection);
pIXMLElementCollection->Release();
}
pIXMLElement->Release();
}
return bRet;
}
#ifdef DEBUG
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsCdfidlMemberOf ***
//
//
// Description:
// Checks if the cdf item id list is associated with a member of the given
// element collection.
//
// Parameters:
// [In] pIXMLElementCollection - The element collection to check.
// [In] pcdfidl - A pointer to cdf item id list
//
// Return:
// TRUE if the given id list can be associated with an elemnt of the given
// collection.
// FALSE otherwise.
//
// Comments:
// This function checks if the last id in the list could have been
// generated from its corresponding element in the element collection.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
XML_IsCdfidlMemberOf(
IXMLElementCollection* pIXMLElementCollection,
PCDFITEMIDLIST pcdfidl
)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
BOOL bRet = FALSE;
//
// pIXMLElementCollection is NULL when a Folder hasn't been initialized.
// It isn't always neccessary to parse the cdf to get pidl info from
// the pidl. pIXMLElement collection will be NULL in low memory situations
// also. Don't return FALSE for these cases. Also check for special
// pidls that aren't in element collections.
//
if (pIXMLElementCollection &&
CDFIDL_GetIndexId(&pcdfidl->mkid) != INDEX_CHANNEL_LINK)
{
IXMLElement* pIXMLElement;
HRESULT hr = XML_GetElementByIndex(pIXMLElementCollection,
CDFIDL_GetIndexId(&pcdfidl->mkid),
&pIXMLElement);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
PCDFITEMIDLIST pcdfidlElement;
pcdfidlElement = CDFIDL_CreateFromXMLElement(pIXMLElement,
CDFIDL_GetIndexId(&pcdfidl->mkid));
if (pcdfidlElement)
{
ASSERT(CDFIDL_IsValid(pcdfidlElement));
bRet = (0 == CDFIDL_CompareId(&pcdfidl->mkid,
&pcdfidlElement->mkid));
CDFIDL_Free(pcdfidlElement);
}
pIXMLElement->Release();
}
}
else
{
bRet = TRUE;
}
return bRet;
}
#endif //DEBUG
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** XML_IsStrEqualW ***
//
//
// Description:
// Determines if two WCHAR strings are equal.
//
// Parameters:
// [In] p1 - The first string to compare.
// [In] p2 - The second string to compare.
//
// Return:
// TRUE if the strings are equal.
// FALSE otherwise.
//
// Comments:
// lstrcmpW doesn't work on W95 so this function has its own strcmp logic.
//
////////////////////////////////////////////////////////////////////////////////
#if 0
inline
BOOL
XML_IsStrEqualW(
LPWSTR p1,
LPWSTR p2
)
{
ASSERT(p1);
ASSERT(p2);
while ((*p1 == *p2) && *p1 && *p2)
{
p1++; p2++;
}
return (*p1 == *p2);
}
#endif