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

514 lines
12 KiB
C++

//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: detect.cpp
//
// Description:
//
// Implementation for the Detect() function
//
//=======================================================================
#include "iuengine.h"
#include "iuxml.h"
#include <logging.h>
#include <StringUtil.h>
#include <download.h>
#include "schemamisc.h"
#include "expression.h"
#include <iucommon.h>
//
// define constants used in this file
//
#define C_INDEX_STATUS_INSTALLED 0
#define C_INDEX_STATUS_UPTODATE 1
#define C_INDEX_STATUS_NEWVERSION 2
#define C_INDEX_STATUS_EXCLUDED 3
#define C_INDEX_STATUS_FORCE 4
#define C_INDEX_STATUS_COMPUTER 5 // <computerSystem>
#define C_INDEX_ARRAY_SIZE 6
//
// declare macros used in this cpp file
//
/**
* deckare the constants used to manipulate the result of Detect() method
*/
/**
* used in <detection> tag, to tell the detection result. This result
* should overwrite the rest of <expression>, if any
*/
extern const LONG IUDET_INSTALLED; /* mask for <installed> result */
extern const LONG IUDET_INSTALLED_NULL; /* mask for <installed> missing */
extern const LONG IUDET_UPTODATE; /* mask for <upToDate> result */
extern const LONG IUDET_UPTODATE_NULL; /* mask for <upToDate> missing */
extern const LONG IUDET_NEWERVERSION; /* mask for <newerVersion> result */
extern const LONG IUDET_NEWERVERSION_NULL; /* mask for <newerVersion> missing */
extern const LONG IUDET_EXCLUDED; /* mask for <excluded> result */
extern const LONG IUDET_EXCLUDED_NULL; /* mask for <excluded> missing */
extern const LONG IUDET_FORCE; /* mask for <force> result */
extern const LONG IUDET_FORCE_NULL; /* mask for <force> missing */
extern const LONG IUDET_COMPUTER; // mask for <computerSystem> result
extern const LONG IUDET_COMPUTER_NULL; // <computerSystem> missing
const DetResultMask[6][2] = {
{IUDET_INSTALLED, IUDET_INSTALLED_NULL},
{IUDET_UPTODATE, IUDET_UPTODATE_NULL},
{IUDET_NEWERVERSION, IUDET_NEWERVERSION_NULL},
{IUDET_EXCLUDED, IUDET_EXCLUDED_NULL},
{IUDET_FORCE, IUDET_FORCE_NULL},
{IUDET_COMPUTER, IUDET_COMPUTER_NULL}
};
//
// local macros
//
#define ReturnIfHrFail(hr) if (FAILED(hr)) {LOG_ErrorMsg(hr); return hr;}
#define GotoCleanupIfNull(p) if (p) goto CleanUp
#define SetDetResultFromDW(arr, index, dw, bit, bitNull) \
if (bitNull == (dw & bitNull)) \
arr[index] = -1; \
else \
arr[index] = (bit == (dw & bit)) ? 1 : 0;
/////////////////////////////////////////////////////////////////////////
//
// Private function DoDetection()
// do detection on one item
//
// Input:
// one item node
//
// Output:
// detect result: array of integer, each represents a result
// of one element. indexes are defined as C_INDEX_STATUS_XXX
// value: <0 expresison not present
// =0 evalues to FALSE
// >0 evalues to TRUE
//
//
// Return:
// S_OK if everything fine or error code
/////////////////////////////////////////////////////////////////////////
HRESULT
DoDetection(
IXMLDOMNode* pNode, // one item node
BOOL fIsItemNode, // need to go down 1 level to get detection node
int* pResultArray // array of result
)
{
LOG_Block("DoDetection");
int i;
BOOL fRet = FALSE;
BOOL fNeedReleaseNode = FALSE;
HRESULT hr = S_OK;
BSTR bstrNodeName = NULL;
BSTR bstrText = NULL;
IXMLDOMNode* pDetectionNode = NULL;
IXMLDOMNode* pDetectionChild = NULL;
IXMLDOMNode* pExpression = NULL;
USES_IU_CONVERSION;
if (fIsItemNode)
{
hr = pNode->selectSingleNode(KEY_DETECTION, &pDetectionNode);
if (S_FALSE == hr || NULL == pDetectionNode)
{
hr = E_INVALIDARG; // no detection node found!
LOG_ErrorMsg(hr);
return hr;
}
}
else
{
pDetectionNode = pNode;
}
if (NULL == pDetectionNode)
{
//
// no detection node. Legal schema though.
// nothing we can do, so bail out.
//
LOG_XML(_T("no detection node found for this item! Returns S_FALSE, so it won't be reported"));
return S_FALSE;
}
//
// initialize result array
//
for (i = 0; i < C_INDEX_ARRAY_SIZE; i++)
{
pResultArray[i] = -1;
}
//
// detection node may have a list of child nodes, each child node has
// a different name for different purpose of detection.
// each child node contains one and only one expression node
//
LOG_XML(_T("No costom detection DLL found. Detection children..."));
(void) pDetectionNode->get_firstChild(&pDetectionChild);
while (NULL != pDetectionChild)
{
//
// for each child, see if it is a known detection child
//
(void) pDetectionChild->get_nodeName(&bstrNodeName);
static const BSTR C_DETX_NAME[] = {
KEY_INSTALLED,
KEY_UPTODATE,
KEY_NEWERVERSION,
KEY_EXCLUDED,
KEY_FORCE,
KEY_COMPUTERSYSTEM
};
for (i = 0; i < ARRAYSIZE(C_DETX_NAME); i++)
{
if (CompareBSTRsEqual(bstrNodeName, C_DETX_NAME[i]))
{
//
// found this child node is a known detection node
//
if (C_INDEX_STATUS_COMPUTER == i)
{
//
// if this is the computerSystem detection,
// then we ignore all child nodes, just do a simple
// function call to find out if this machine matches
// the manufacturer and model
//
hr = DetectComputerSystem(pDetectionChild, &fRet);
}
else
//
// get the expression node from this child node
//
if (SUCCEEDED(hr = pDetectionChild->get_firstChild(&pExpression)))
{
if (NULL != pExpression)
{
hr = DetectExpression(pExpression, &fRet);
LOG_XML(_T("Detection result for tag %s = %d, returns 0x%08x"), OLE2T(bstrNodeName), fRet?1:0, hr);
}
else
{
//
// if there is no child, this is an empty detection type,
// then we will treat this as "ALWAYS TRUE", and reset hr so
// this "always true" result can be sent out
//
fRet = TRUE;
hr = S_OK;
}
SafeReleaseNULL(pExpression);
}
//
// store the detection result
//
pResultArray[i] = (fRet) ? 1 : 0;
break; // done with current node
}
}
SafeSysFreeString(bstrNodeName);
if (FAILED(hr))
{
//
// report error to log file
//
IXMLDOMNode* pIdentityNode = NULL, *pProviderNode = NULL;
BSTR bstrIdentStr = NULL;
char* pNodeType = (fIsItemNode) ? "Provider:" : "Item:";
//
// we need to find out the identity string of this node
//
if (fIsItemNode)
{
//
// this is an item node, containing identity node
//
(void)FindNode(pNode, KEY_IDENTITY, &pIdentityNode);
}
else
{
//
// this is the detection node of a provider
//
if (SUCCEEDED(pNode->get_parentNode(&pProviderNode)) && NULL != pProviderNode)
{
(void)FindNode(pProviderNode, KEY_IDENTITY, &pIdentityNode);
}
}
//
// if we have a valid identity node
//
if (NULL != pIdentityNode &&
SUCCEEDED(UtilGetUniqIdentityStr(pIdentityNode, &bstrIdentStr, 0x0)) &&
NULL != bstrIdentStr)
{
//
// output log about the error
//
#if defined(UNICODE) || defined(_UNICODE)
LogError(hr, "Found error during detection %hs %ls", pNodeType, bstrIdentStr);
#else
LogError(hr, "Found error during detection %s %s", pNodeType, OLE2T(bstrIdentStr));
#endif
SysFreeString(bstrIdentStr);
}
SafeReleaseNULL(pProviderNode);
SafeReleaseNULL(pIdentityNode);
//
// if any one detection returns fail, then this detection node is
// not valid - it means something wrong in the detection
// data. we will just ignore this detection, no output for it.
//
break;
}
//
// try next detection child
//
IXMLDOMNode* pNextNode = NULL;
pDetectionChild->get_nextSibling(&pNextNode);
SafeReleaseNULL(pDetectionChild);
pDetectionChild = pNextNode;
}
SafeReleaseNULL(pDetectionChild);
if (fIsItemNode)
{
SafeReleaseNULL(pDetectionNode);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// public function Detect()
//
// Do detection.
// Input:
// bstrXmlCatalog - the xml catalog portion containing items to be detected
// Output:
// pbstrXmlItems - the detected items in xml format
// e.g.
// <id guid="2560AD4D-3ED3-49C6-A937-4368C0B0E06D" installed="1" force="1"/>
/////////////////////////////////////////////////////////////////////////////
HRESULT WINAPI CEngUpdate::Detect(BSTR bstrXmlCatalog, DWORD dwFlags, BSTR *pbstrXmlItems)
{
HRESULT hr = S_OK;
IXMLDOMNodeList* pProviderList = NULL;
IXMLDOMNodeList* pProvChildList = NULL;
IXMLDOMNode* pCurProvider = NULL;
IXMLDOMNode* pCurNode = NULL;
CXmlCatalog xmlCatalog;
CXmlItems ItemList; // result item list
HANDLE_NODE hNode;
int DetStatus[C_INDEX_ARRAY_SIZE];
int i;
DWORD dwDownloadFlags = 0;
LOG_Block("Detect()");
//#if defined(_DEBUG) || defined(DEBUG)
USES_IU_CONVERSION;
//#endif
if (NULL == bstrXmlCatalog || NULL == pbstrXmlItems)
{
hr = E_INVALIDARG;
LOG_ErrorMsg(hr);
return hr;
}
LOG_XML(_T("Catalog=%s"), OLE2T(bstrXmlCatalog));
// Set Global Offline Flag - checked by XML Classes to disable Validation (schemas are on the net)
if (dwFlags & FLAG_OFFLINE_MODE)
{
m_fOfflineMode = TRUE;
}
else
{
m_fOfflineMode = FALSE;
}
//
// Convert bstrXmlCatalog to XMLDOM
//
hr = xmlCatalog.LoadXMLDocument(bstrXmlCatalog, m_fOfflineMode);
ReturnIfHrFail(hr);
LOG_XML(_T("Catalog has been loaded into XMLDOM"));
//
// get the list of providers from catalog
//
pProviderList = xmlCatalog.GetProviders();
if (NULL == pProviderList)
{
LOG_Error(_T("No provider found!"));
return E_INVALIDARG;
}
//
// get the first provider
//
(void) pProviderList->nextNode(&pCurProvider);
//
// for each provider, process their item list
//
while (NULL != pCurProvider)
{
//
// get the children list from this node
//
pCurProvider->get_childNodes(&pProvChildList);
if (NULL != pProvChildList)
{
long n;
//
// loop through the list to process each item of catalog
//
long iProvChildren = 0;
pProvChildList->get_length(&iProvChildren);
BOOL fProviderOkay = TRUE;
BSTR bstrHref = NULL;
//
// process each child of this provider to see
// if there is any detection node or any item node,
//
for (n = 0; n < iProvChildren && fProviderOkay; n++)
{
pProvChildList->get_item(n, &pCurNode);
BOOL fIsItemNode = DoesNodeHaveName(pCurNode, KEY_ITEM);
if (fIsItemNode ||
DoesNodeHaveName(pCurNode, KEY_DETECTION))
{
//
// initialize the status result array
//
for (i = 0; i < C_INDEX_ARRAY_SIZE; i++)
{
DetStatus[i] = -1; // init to not present
}
//
// detect each pression of this detection node of this item
// error reported inside this function
//
if (S_OK == DoDetection(pCurNode, fIsItemNode, DetStatus))
{
//
// add the item to the item list
//
if (SUCCEEDED(ItemList.AddItem(fIsItemNode ? pCurNode : pCurProvider, &hNode)) && HANDLE_NODE_INVALID != hNode)
{
//
// update the detection status result of this item
//
ItemList.AddDetectResult(
hNode,
DetStatus[C_INDEX_STATUS_INSTALLED],
DetStatus[C_INDEX_STATUS_UPTODATE],
DetStatus[C_INDEX_STATUS_NEWVERSION],
DetStatus[C_INDEX_STATUS_EXCLUDED],
DetStatus[C_INDEX_STATUS_FORCE],
DetStatus[C_INDEX_STATUS_COMPUTER]
);
ItemList.SafeCloseHandleNode(hNode);
}
}
}
SafeReleaseNULL(pCurNode);
} // end of this item
//SafeReleaseNULL(pCurNode); // in case it's not item node
} // end of non-empty node list of this provider
//
// finished processing the current provider
//
SafeReleaseNULL(pProvChildList);
SafeReleaseNULL(pCurProvider);
//
// try to get a hold of the next provider
//
(void) pProviderList->nextNode(&pCurProvider);
} // end of iterating provider list
//
// output the detection reuslt as an item list
//
ItemList.GetItemsBSTR(pbstrXmlItems);
LOG_XML(_T("Result=%s"), *pbstrXmlItems);
//
// done
//
SafeReleaseNULL(pProviderList);
return S_OK;
}