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

1370 lines
30 KiB
C++

//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: expression.CPP
//
// Author: Charles Ma
// 2000.10.27
//
// Description:
//
// Implement function related to detection expressions
//
//=======================================================================
#include "iuengine.h"
#include "SchemaMisc.h"
#include "expression.h"
#include <RegUtil.h>
#include <FileUtil.h>
#include <StringUtil.h>
#include <shlwapi.h>
#include "SchemaKeys.h"
#include "iucommon.h"
//
// include IDetection interface
//
#ifdef _MIDL_USE_GUIDDEF_
#ifndef INITGUID
#define INITGUID
#include <guiddef.h>
#undef INITGUID
#else
#include <guiddef.h>
#endif
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
#else // !_MIDL_USE_GUIDDEF_
#ifndef __IID_DEFINED__
#define __IID_DEFINED__
typedef struct _IID
{
unsigned long x;
unsigned short s1;
unsigned short s2;
unsigned char c[8];
} IID;
#endif // __IID_DEFINED__
#ifndef CLSID_DEFINED
#define CLSID_DEFINED
typedef IID CLSID;
#endif // CLSID_DEFINED
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
#endif !_MIDL_USE_GUIDDEF_
MIDL_DEFINE_GUID(IID, IID_IDetection,0x8E2EF6DC,0x0AB8,0x4FE0,0x90,0x49,0x3B,0xEA,0x45,0x06,0xBF,0x8D);
#ifndef __IDetection_FWD_DEFINED__
#define __IDetection_FWD_DEFINED__
typedef interface IDetection IDetection;
#endif /* __IDetection_FWD_DEFINED__ */
#ifndef __IDetection_INTERFACE_DEFINED__
#define __IDetection_INTERFACE_DEFINED__
/* interface IDetection */
/* [unique][helpstring][dual][uuid][object] */
EXTERN_C const IID IID_IDetection;
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("8E2EF6DC-0AB8-4FE0-9049-3BEA4506BF8D")
IDetection : public IDispatch
{
public:
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Detect(
/* [in] */ BSTR bstrXML,
/* [out] */ DWORD *pdwDetectionResult) = 0;
};
#else /* C style interface */
typedef struct IDetectionVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IDetection * This,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IDetection * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IDetection * This);
HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )(
IDetection * This,
/* [out] */ UINT *pctinfo);
HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )(
IDetection * This,
/* [in] */ UINT iTInfo,
/* [in] */ LCID lcid,
/* [out] */ ITypeInfo **ppTInfo);
HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )(
IDetection * This,
/* [in] */ REFIID riid,
/* [size_is][in] */ LPOLESTR *rgszNames,
/* [in] */ UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ DISPID *rgDispId);
/* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )(
IDetection * This,
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS *pDispParams,
/* [out] */ VARIANT *pVarResult,
/* [out] */ EXCEPINFO *pExcepInfo,
/* [out] */ UINT *puArgErr);
/* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Detect )(
IDetection * This,
/* [in] */ BSTR bstrXML,
/* [out] */ DWORD *pdwDetectionResult);
END_INTERFACE
} IDetectionVtbl;
interface IDetection
{
CONST_VTBL struct IDetectionVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define IDetection_QueryInterface(This,riid,ppvObject) \
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
#define IDetection_AddRef(This) \
(This)->lpVtbl -> AddRef(This)
#define IDetection_Release(This) \
(This)->lpVtbl -> Release(This)
#define IDetection_GetTypeInfoCount(This,pctinfo) \
(This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
#define IDetection_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \
(This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
#define IDetection_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
(This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
#define IDetection_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \
(This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
#define IDetection_Detect(This,bstrXML,pdwDetectionResult) \
(This)->lpVtbl -> Detect(This,bstrXML,pdwDetectionResult)
#endif /* COBJMACROS */
#endif /* C style interface */
/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IDetection_Detect_Proxy(
IDetection * This,
/* [in] */ BSTR bstrXML,
/* [out] */ DWORD *pdwDetectionResult);
void __RPC_STUB IDetection_Detect_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
#endif /* __IDetection_INTERFACE_DEFINED__ */
//
// deckare the constants used to manipulate the result of Detect() method
//
//
// First group, used in <expression> tag, to tell the detection result. This result
// should combined with other expression(s) at the same level
//
const DWORD IUDET_BOOL = 0x00000001; // mask
const DWORD IUDET_FALSE = 0x00000000; // expression detect FALSE
const DWORD IUDET_TRUE = 0x00000001; // expression detect TRUE
const DWORD IUDET_NULL = 0x00000002; // expression detect data missing
//
// Second group, used in <detection> tag, to tell the detection result. This result
// should overwrite the rest of <expression>, if any
//
extern const LONG IUDET_INSTALLED = 0x00000010; /* mask for <installed> result */
extern const LONG IUDET_INSTALLED_NULL = 0x00000020; /* <installed> missing */
extern const LONG IUDET_UPTODATE = 0x00000040; /* mask for <upToDate> result */
extern const LONG IUDET_UPTODATE_NULL = 0x00000080; /* <upToDate> missing */
extern const LONG IUDET_NEWERVERSION = 0x00000100; /* mask for <newerVersion> result */
extern const LONG IUDET_NEWERVERSION_NULL = 0x00000200; /* <newerVersion> missing */
extern const LONG IUDET_EXCLUDED = 0x00000400; /* mask for <excluded> result */
extern const LONG IUDET_EXCLUDED_NULL = 0x00000800; /* <excluded> missing */
extern const LONG IUDET_FORCE = 0x00001000; /* mask for <force> result */
extern const LONG IUDET_FORCE_NULL = 0x00002000; /* <force> missing */
extern const LONG IUDET_COMPUTER = 0x00004000; // mask for <computerSystem> result
extern const LONG IUDET_COMPUTER_NULL = 0x00008000; // <computerSystem> missing
#define GotoCleanupIfNull(p) if (NULL==p) goto CleanUp
#define GotoCleanupHR(hrCode) hr = hrCode; LOG_ErrorMsg(hr); goto CleanUp
// ----------------------------------------------------------------------
//
// public helper function to convert a bstr value to
// version status enum value, if possible
//
// ----------------------------------------------------------------------
BOOL ConvertBstrVersionToEnum(BSTR bstrVerVerb, _VER_STATUS *pEnumVerVerb)
{
//
// convert the versionStatus in bstr into enum
//
if (CompareBSTRsEqual(bstrVerVerb, KEY_VERSTATUS_HI))
{
*pEnumVerVerb = DETX_HIGHER;
}
else if (CompareBSTRsEqual(bstrVerVerb,KEY_VERSTATUS_HE))
{
*pEnumVerVerb = DETX_HIGHER_OR_EQUAL;
}
else if (CompareBSTRsEqual(bstrVerVerb, KEY_VERSTATUS_EQ))
{
*pEnumVerVerb = DETX_SAME;
}
else if (CompareBSTRsEqual(bstrVerVerb, KEY_VERSTATUS_LE))
{
*pEnumVerVerb = DETX_LOWER_OR_EQUAL;
}
else if (CompareBSTRsEqual(bstrVerVerb, KEY_VERSTATUS_LO))
{
*pEnumVerVerb = DETX_LOWER;
}
else
{
return FALSE;
}
return TRUE;
}
//----------------------------------------------------------------------
//
// public function DetectExpression()
// retrieve the data from the express node,
// and do actual detection work
//
// Input:
// expression node
// LPCTSTR lpcsDllPath, // path that this provider saved the cust detection Dll
//
// Return:
// TRUE/FALSE, detection result
//
//----------------------------------------------------------------------
HRESULT DetectExpression(IXMLDOMNode* pExpression, BOOL *pfResult)
{
HRESULT hr = E_INVALIDARG;
int iRet = -1;
BOOL fRet = TRUE;
IXMLDOMNodeList* pChildList = NULL;
IXMLDOMNode* pCandidate = NULL;
BSTR bstrName = NULL;
BSTR bstrKey = NULL,
bstrEntry = NULL,
bstrValue = NULL;
LPCTSTR lpszKeyComputer = NULL;
LOG_Block("DetectExpression()");
USES_IU_CONVERSION;
if (NULL == pExpression || NULL == pfResult)
{
LOG_ErrorMsg(hr);
return hr;
}
*pfResult = TRUE;
//
// retrieve all child nodes
//
(void)pExpression->get_childNodes(&pChildList);
if (NULL == pChildList)
{
LOG_XML(_T("Empty expression found!"));
GotoCleanupHR(E_INVALIDARG);
}
//
// get the first child
//
(void)pChildList->nextNode(&pCandidate);
if (NULL == pCandidate)
{
LOG_XML(_T("empty child list for passed in expresson node!"));
GotoCleanupHR(E_INVALIDARG);
}
//
// loop through each child node, find out the type
// of node, call actual detection func accordingly
//
lpszKeyComputer = OLE2T(KEY_COMPUTERSYSTEM);
CleanUpFailedAllocSetHrMsg(lpszKeyComputer);
while (NULL != pCandidate)
{
CleanUpIfFailedAndSetHrMsg(pCandidate->get_nodeName(&bstrName));
LPTSTR lpszName = OLE2T(bstrName);
CleanUpFailedAllocSetHrMsg(lpszName);
if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_REGKEYEXISTS,
-1))
{
//
// call detection function
//
hr = DetectRegKeyExists(pCandidate, pfResult);
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_REGKEYVALUE,
-1))
{
//
// process RegKeyValue expression
//
hr = DetectRegKeyValue(pCandidate, pfResult);
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_REGKEYSUBSTR,
-1))
{
//
// process RegKeySubstring expression
//
hr = DetectRegKeySubstring(pCandidate, pfResult);
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_REGKEYVERSION,
-1))
{
//
// process RegVersion expression
//
hr = DetectRegVersion(pCandidate, pfResult);
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_FILEVERSION,
-1))
{
//
// process FileVersion expression
//
hr = DetectFileVersion(pCandidate, pfResult);
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_FILEEXISTS,
-1))
{
//
// process FileExists expression
//
hr = DetectFileExists(pCandidate, pfResult);
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
lpszKeyComputer,
-1))
{
//
// process computerSystem check
//
hr = DetectComputerSystem(pCandidate, pfResult);
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_AND,
-1))
{
//
// process AND expression
//
IXMLDOMNodeList* pSubExpList = NULL;
IXMLDOMNode* pSubExp = NULL;
long lLen = 0;
//
// get child list
//
pCandidate->get_childNodes(&pSubExpList);
if (NULL == pSubExpList)
{
LOG_XML(_T("Found no children of AND expression"));
GotoCleanupHR(E_INVALIDARG);
}
pSubExpList->get_length(&lLen);
fRet = TRUE;
for (long i = 0; i < lLen && fRet; i++)
{
//
// each child should be an expression
// process it. if false, then short-cut.
//
pSubExpList->get_item(i, &pSubExp);
if (NULL == pSubExp)
{
pSubExpList->Release();
pSubExpList = NULL;
LOG_XML(_T("Failed to get the #%d sub-expression in this AND expression"), i);
GotoCleanupHR(E_INVALIDARG);
}
hr = DetectExpression(pSubExp, &fRet);
SafeReleaseNULL(pSubExp);
if (FAILED(hr))
{
//
// if found something wrong in recursion, don't continue
//
break;
}
}
SafeReleaseNULL(pSubExpList);
*pfResult = fRet;
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_OR,
-1))
{
//
// process OR expression
//
IXMLDOMNodeList* pSubExpList = NULL;
IXMLDOMNode* pSubExp = NULL;
long lLen = 0;
//
// get child list
//
pCandidate->get_childNodes(&pSubExpList);
if (NULL == pSubExpList)
{
LOG_XML(_T("Found no children of OR expression"));
GotoCleanupHR(E_INVALIDARG);
}
pSubExpList->get_length(&lLen);
fRet = FALSE;
for (long i = 0; i < lLen && !fRet; i++)
{
//
// each child is one expression
// do it one by one
//
pSubExpList->get_item(i, &pSubExp);
if (NULL == pSubExp)
{
pSubExpList->Release();
pSubExpList = NULL;
LOG_XML(_T("Failed to get the #%d sub-expression in this OR expression"), i);
GotoCleanupHR(E_INVALIDARG);
}
hr = DetectExpression(pSubExp, &fRet);
SafeReleaseNULL(pSubExp);
if (FAILED(hr))
{
//
// if found something wrong in recursion, don't continue
//
break;
}
}
SafeReleaseNULL(pSubExpList);
*pfResult = fRet;
}
else if (CSTR_EQUAL == CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
lpszName,
-1,
KEY_NOT,
-1))
{
//
// process NOT expression
//
IXMLDOMNode* pSubExp = NULL;
//
// get the only child
//
pCandidate->get_firstChild(&pSubExp);
if (NULL == pSubExp)
{
LOG_XML(_T("Failed to get first child in NOT expression"));
GotoCleanupHR(E_INVALIDARG);
}
//
// the child must be an expression, process it
//
hr = DetectExpression(pSubExp, &fRet);
if (SUCCEEDED(hr))
{
fRet = !fRet; // flip the result for NOT expression
*pfResult = fRet;
}
else
{
LOG_ErrorMsg(hr);
}
SafeReleaseNULL(pSubExp);
}
if (FAILED(hr))
{
goto CleanUp;
}
if (!*pfResult)
{
//
// if found one expression FALSE, the whole thing false, so
// no need to continue
//
break;
}
SafeReleaseNULL(pCandidate);
pChildList->nextNode(&pCandidate);
SafeSysFreeString(bstrName);
}
CleanUp:
SafeReleaseNULL(pCandidate);
SafeReleaseNULL(pChildList);
SysFreeString(bstrName);
SysFreeString(bstrKey);
SysFreeString(bstrEntry);
SysFreeString(bstrValue);
return hr;
}
//----------------------------------------------------------------------
//
// Helper function DetectRegKeyExists()
// retrieve the data from the node,
// and do actual detection work
//
// Input:
// RegKeyExists node
//
// Return:
// int - detection result: -1=none, 0=FALSE, 1=TRUE
//
// Assumption:
// input parameter not NULL
//
//----------------------------------------------------------------------
HRESULT
DetectRegKeyExists(
IXMLDOMNode* pRegKeyExistsNode,
BOOL *pfResult
)
{
LOG_Block("DetectRegKeyExists");
HRESULT hr = E_INVALIDARG;
BOOL fRet = FALSE;
LPTSTR lpszKey = NULL, lpszEntry = NULL;
BSTR bstrKey = NULL, bstrEntry = NULL;
USES_IU_CONVERSION;
//
// find the key value
//
if (FindNodeValue(pRegKeyExistsNode, KEY_KEY, &bstrKey))
{
lpszKey = OLE2T(bstrKey);
CleanUpFailedAllocSetHrMsg(lpszKey);
//
// find the optional entry value
//
if (FindNodeValue(pRegKeyExistsNode, KEY_ENTRY, &bstrEntry))
{
lpszEntry = OLE2T(bstrEntry);
CleanUpFailedAllocSetHrMsg(lpszEntry);
}
*pfResult = RegKeyExists(lpszKey, lpszEntry);
hr = S_OK;
}
CleanUp:
SysFreeString(bstrKey);
SysFreeString(bstrEntry);
return hr;
}
//----------------------------------------------------------------------
//
// Helper function DetectRegKeyExists()
// retrieve the data from the node,
// and do actual detection work
//
// Input:
// RegKeyValue node
//
// Return:
// int - detection result: -1=none, 0=FALSE, 1=TRUE
//
// Assumption:
// input parameter not NULL
//
//----------------------------------------------------------------------
HRESULT
DetectRegKeyValue(
IXMLDOMNode* pRegKeyValueNode,
BOOL *pfResult
)
{
LOG_Block("DetectRegKeyValue");
HRESULT hr = E_INVALIDARG;
BOOL fRet = FALSE;
LPTSTR lpszKey = NULL,
lpszEntry = NULL,
lpszValue = NULL;
BSTR bstrKey = NULL,
bstrEntry = NULL,
bstrValue = NULL;
USES_IU_CONVERSION;
//
// find the key value
//
if (!FindNodeValue(pRegKeyValueNode, KEY_KEY, &bstrKey))
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
lpszKey = OLE2T(bstrKey);
CleanUpFailedAllocSetHrMsg(lpszKey);
//
// find the optional entry value
//
if (FindNodeValue(pRegKeyValueNode, KEY_ENTRY, &bstrEntry))
{
lpszEntry = OLE2T(bstrEntry);
CleanUpFailedAllocSetHrMsg(lpszEntry);
}
//
// find the value to compare
//
if (!FindNodeValue(pRegKeyValueNode, KEY_VALUE, &bstrValue))
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
lpszValue = OLE2T(bstrValue);
CleanUpFailedAllocSetHrMsg(lpszValue);
*pfResult = RegKeyValueMatch((LPCTSTR)lpszKey, (LPCTSTR)lpszEntry, (LPCTSTR)lpszValue);
hr = S_OK;
CleanUp:
SysFreeString(bstrKey);
SysFreeString(bstrEntry);
SysFreeString(bstrValue);
return hr;
}
//----------------------------------------------------------------------
//
// Helper function DetectRegKeySubstring()
// retrieve the data from the node,
// and do actual detection work
//
// Input:
// RegKeyValue node
//
// Return:
// int - detection result: -1=none, 0=FALSE, 1=TRUE
//
// Assumption:
// input parameter not NULL
//
//----------------------------------------------------------------------
HRESULT
DetectRegKeySubstring(
IXMLDOMNode* pRegKeySubstringNode,
BOOL *pfResult
)
{
LOG_Block("DetectRegKeySubstring");
HRESULT hr = E_INVALIDARG;
BOOL fRet = FALSE;
LPTSTR lpszKey = NULL,
lpszEntry = NULL,
lpszValue = NULL;
BSTR bstrKey = NULL,
bstrEntry = NULL,
bstrValue = NULL;
USES_IU_CONVERSION;
//
// find the key value
//
if (!FindNodeValue(pRegKeySubstringNode, KEY_KEY, &bstrKey))
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
lpszKey = OLE2T(bstrKey);
CleanUpFailedAllocSetHrMsg(lpszKey);
//
// find the optional entry value
//
if (FindNodeValue(pRegKeySubstringNode, KEY_ENTRY, &bstrEntry))
{
lpszEntry = OLE2T(bstrEntry);
CleanUpFailedAllocSetHrMsg(lpszEntry);
}
//
// find the value to compare
//
if (!FindNodeValue(pRegKeySubstringNode, KEY_VALUE, &bstrValue))
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
lpszValue = OLE2T(bstrValue);
CleanUpFailedAllocSetHrMsg(lpszValue);
*pfResult = RegKeySubstring((LPCTSTR)lpszKey, (LPCTSTR)lpszEntry, (LPCTSTR)lpszValue);
hr = S_OK;
CleanUp:
SysFreeString(bstrKey);
SysFreeString(bstrEntry);
SysFreeString(bstrValue);
return hr;
}
//----------------------------------------------------------------------
//
// Helper function DetectFileVersion()
// retrieve the data from the node,
// and do actual detection work
//
// Input:
// RegKeyValue node
//
// Return:
// int - detection result: -1=none, 0=FALSE, 1=TRUE
//
// Assumption:
// input parameter not NULL
//
//----------------------------------------------------------------------
HRESULT
DetectRegVersion(
IXMLDOMNode* pRegKeyVersionNode,
BOOL *pfResult
)
{
HRESULT hr = E_INVALIDARG;
BOOL fRet = FALSE;
LPTSTR lpszKey = NULL,
lpszEntry = NULL,
lpszVersion = NULL;
BSTR bstrVerVerb = NULL,
bstrKey = NULL,
bstrEntry = NULL,
bstrVersion = NULL;
_VER_STATUS verStatus;
LOG_Block("DetectRegVersion()");
USES_IU_CONVERSION;
//
// find the key value
//
if (!FindNodeValue(pRegKeyVersionNode, KEY_KEY, &bstrKey))
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
lpszKey = OLE2T(bstrKey);
CleanUpFailedAllocSetHrMsg(lpszKey);
LOG_XML(_T("Found Key=%s"), lpszKey);
//
// find the optional entry value
//
if (FindNodeValue(pRegKeyVersionNode, KEY_ENTRY, &bstrEntry))
{
lpszEntry = OLE2T(bstrEntry);
CleanUpFailedAllocSetHrMsg(lpszEntry);
LOG_XML(_T("Found optional entry=%s"), lpszEntry);
}
//
// find the value to compare
//
if (!FindNodeValue(pRegKeyVersionNode, KEY_VERSION, &bstrVersion))
{
goto CleanUp;
}
lpszVersion = OLE2T(bstrVersion);
CleanUpFailedAllocSetHrMsg(lpszVersion);
LOG_XML(_T("Version found from node: %s"), lpszVersion);
//
// get the attribute versionStatus, a version compare verb
//
if (S_OK != (hr = GetAttribute(pRegKeyVersionNode, KEY_VERSIONSTATUS, &bstrVerVerb)))
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
LOG_XML(_T("Version verb found from node: %s"), OLE2T(bstrVerVerb));
//
// convert the versionStatus in bstr into enum
//
if (!ConvertBstrVersionToEnum(bstrVerVerb, &verStatus))
{
SafeSysFreeString(bstrVerVerb);
goto CleanUp;
}
*pfResult = RegKeyVersion((LPCTSTR)lpszKey, (LPCTSTR)lpszEntry, (LPCTSTR)lpszVersion, verStatus);
hr = S_OK;
CleanUp:
SysFreeString(bstrKey);
SysFreeString(bstrEntry);
SysFreeString(bstrVersion);
SysFreeString(bstrVerVerb);
return hr;
}
//----------------------------------------------------------------------
//
// Helper function DetectFileVersion()
// retrieve the data from the node,
// and do actual detection work
//
// Input:
// RegKeyValue node
//
// Return:
// int - detection result: -1=none, 0=FALSE, 1=TRUE
//
// Assumption:
// input parameter not NULL
//
//----------------------------------------------------------------------
HRESULT
DetectFileVersion(
IXMLDOMNode* pFileVersionNode,
BOOL *pfResult
)
{
BOOL fRet = FALSE;
BOOL fFileExists = FALSE;
HRESULT hr = E_INVALIDARG;
IXMLDOMNode* pFilePathNode = NULL;
TCHAR szFilePath[MAX_PATH];
int iFileVerComp;
LPTSTR lpszTimeStamp = NULL,
lpszVersion = NULL;
BSTR bstrTime = NULL,
bstrVersion = NULL,
bstrVerState= NULL;
FILE_VERSION fileVer;
_VER_STATUS verStatus;
LOG_Block("DetectFileVersion()");
USES_IU_CONVERSION;
if (NULL == pfResult || NULL == pFileVersionNode)
{
LOG_ErrorMsg(hr);
return hr;
}
*pfResult = FALSE;
//
// find the version value
//
if (!FindNodeValue(pFileVersionNode, KEY_VERSION, &bstrVersion))
{
LOG_ErrorMsg(hr);
return hr;
}
if (NULL == (lpszVersion = OLE2T(bstrVersion)))
{
LOG_ErrorMsg(E_OUTOFMEMORY);
goto CleanUp;
}
LOG_XML(_T("Version=%s"), lpszVersion);
if (!ConvertStringVerToFileVer(T2A(lpszVersion), &fileVer))
{
LOG_ErrorMsg(hr);
goto CleanUp; // bad version string
}
//
// find the file path value
//
//if (!FindNodeValue(pFileVersionNode, KEY_FILEPATH, &bstrFile))
if (!FindNode(pFileVersionNode, KEY_FILEPATH, &pFilePathNode) ||
NULL == pFilePathNode ||
FAILED(hr = GetFullFilePathFromFilePathNode(pFilePathNode, szFilePath)))
{
LOG_ErrorMsg(hr);
goto CleanUp; // no file path found!
}
LOG_XML(_T("File=%s"), szFilePath);
//
// check if file exist
//
fFileExists = FileExists(szFilePath);
//
// get the attribute versionStatus, a version compare verb
//
if (S_OK != GetAttribute(pFileVersionNode, KEY_VERSIONSTATUS, &bstrVerState))
{
goto CleanUp; // no version status found
}
LOG_XML(_T("VersionStatus=%s"), OLE2T(bstrVerState));
if (!ConvertBstrVersionToEnum(bstrVerState, &verStatus))
{
//
// bad version enum, shouldn't happen since the manifest has
// been loaded into XMLDOM
//
LOG_ErrorMsg(hr);
goto CleanUp;
}
//
// get optional timestamp
//
if (S_OK == GetAttribute(pFileVersionNode, KEY_TIMESTAMP, &bstrTime))
{
TCHAR szFileTimeStamp[20];
LPTSTR lpXmlTimeStamp = OLE2T(bstrTime);
CleanUpFailedAllocSetHrMsg(lpXmlTimeStamp);
//
// find out the file creation time stamp
//
int iCompare;
if (!fFileExists || !GetFileTimeStamp(szFilePath, szFileTimeStamp, 20))
{
//szFileTimeStamp[0] = '\0'; // we don't have a timestamp to compare
//
// for timestamp compare, it's date/time ISO format compare, i.e.,
// in alphabetical order, so empty timestamp always smaller.
//
iCompare = -1;
}
else
{
//
// compare file timestamp, if szFileTimeStamp < lpXmlTimeStamp, -1
//
int iCompVal = CompareString(
MAKELCID(0x0409, SORT_DEFAULT),
NORM_IGNORECASE,
szFileTimeStamp,
-1,
lpXmlTimeStamp,
-1);
iCompare = (CSTR_EQUAL == iCompVal) ? 0 : ((CSTR_LESS_THAN == iCompVal) ? -1 : +1);
}
switch (verStatus)
{
case DETX_LOWER:
fRet = (iCompare < 0);
break;
case DETX_LOWER_OR_EQUAL:
fRet = (iCompare <= 0);
break;
case DETX_SAME:
fRet = (iCompare == 0);
break;
case DETX_HIGHER_OR_EQUAL:
fRet = (iCompare >= 0);
break;
case DETX_HIGHER:
fRet = (iCompare > 0);
break;
}
*pfResult = fRet;
if (!fRet)
{
//
// false, not need to continue
//
hr = S_OK;
goto CleanUp;
}
}
//
// compare file version: if a < b, -1; a > b, +1
//
if (!fFileExists || (FAILED(CompareFileVersion((LPCTSTR)szFilePath, fileVer, &iFileVerComp))))
{
//
// failed to compare version - file may doesn't have a version data.
// in this case, we assume the file need to compare have version 0,0,0,0, and force
// the comparision oontinue.
//
FILE_VERSION verNoneExists = {0,0,0,0};
iFileVerComp = CompareFileVersion(verNoneExists, fileVer);
}
switch (verStatus)
{
case DETX_LOWER:
fRet = (iFileVerComp < 0);
break;
case DETX_LOWER_OR_EQUAL:
fRet = (iFileVerComp <= 0);
break;
case DETX_SAME:
fRet = (iFileVerComp == 0);
break;
case DETX_HIGHER_OR_EQUAL:
fRet = (iFileVerComp >= 0);
break;
case DETX_HIGHER:
fRet = (iFileVerComp > 0);
break;
}
*pfResult = fRet;
hr = S_OK;
CleanUp:
SysFreeString(bstrTime);
SysFreeString(bstrVersion);
SysFreeString(bstrVerState);
SafeReleaseNULL(pFilePathNode);
return hr;
}
//----------------------------------------------------------------------
//
// Helper function DetectFileExists()
// retrieve the data from the node,
// and do actual detection work
//
// Input:
// RegKeyValue node
//
// Return:
// int - detection result: -1=none, 0=FALSE, 1=TRUE
//
// Assumption:
// input parameter not NULL
//
//----------------------------------------------------------------------
HRESULT
DetectFileExists(
IXMLDOMNode* pFileExistsNode,
BOOL *pfResult
)
{
BOOL fRet = FALSE;
HRESULT hr = E_INVALIDARG;
TCHAR szFilePath[MAX_PATH];
IXMLDOMNode* pFilePathNode = NULL;
_VER_STATUS verStatus;
USES_IU_CONVERSION;
LOG_Block("DetectFileExists()");
if (NULL == pFileExistsNode || NULL == pfResult)
{
return E_INVALIDARG;
}
//
// find the version value
//
if (!FindNode(pFileExistsNode, KEY_FILEPATH, &pFilePathNode) ||
NULL == pFilePathNode ||
FAILED(hr = GetFullFilePathFromFilePathNode(pFilePathNode, szFilePath)))
{
LOG_ErrorMsg(hr);
}
else
{
*pfResult = FileExists((LPCTSTR)szFilePath);
hr = S_OK;
}
SafeReleaseNULL(pFilePathNode);
return hr;
}
//----------------------------------------------------------------------
//
// Helper function DetectComputerSystem()
// retrieve the data from the node,
// and do actual detection work
//
// Input:
// computerSystem node
//
// Return:
// detection result TRUE/FALSE
//
// Assumption:
// input parameter not NULL
//
//----------------------------------------------------------------------
HRESULT
DetectComputerSystem(
IXMLDOMNode* pComputerSystemNode,
BOOL *pfResult
)
{
HRESULT hr = E_INVALIDARG;
LOG_Block("DetectComputerSystem()");
BSTR bstrManufacturer = NULL;
BSTR bstrModel = NULL;
BSTR bstrSupportURL = NULL;
BSTR bstrXmlManufacturer = NULL;
BSTR bstrXmlModel = NULL;
if (NULL == pComputerSystemNode || NULL == pfResult)
{
LOG_ErrorMsg(hr);
return hr;
}
*pfResult = FALSE; // anything wrong, result should be FALSE and return error
//
// get manufecturer and model from XML node
//
hr = GetAttribute(pComputerSystemNode, KEY_MANUFACTURER, &bstrXmlManufacturer);
CleanUpIfFailedAndMsg(hr);
//
// optional model
//
GetAttribute(pComputerSystemNode, KEY_MODEL, &bstrXmlModel);
//
// find out real manufectuer and model of this machine
//
hr = GetOemBstrs(bstrManufacturer, bstrModel, bstrSupportURL);
CleanUpIfFailedAndMsg(hr);
//
// compare to see if manufacturer and model match.
// mafufacturer match required. If no model provided in xml
// then no check on model performed.
//
// definition of match: both empty or bstr compare equal
// definition of empty: bstr NULL or string length zero
//
*pfResult = (
(((NULL == bstrXmlManufacturer || SysStringLen(bstrXmlManufacturer) == 0) && // xml data empty and
(NULL == bstrManufacturer || SysStringLen(bstrManufacturer) == 0)) || // machine manufecturer empty, or
CompareBSTRsEqual(bstrManufacturer, bstrXmlManufacturer)) && // manufacturer same as xml data, also,
((NULL == bstrXmlModel) || // xml data empty or
CompareBSTRsEqual(bstrModel, bstrXmlModel))); // model matches xml data
LOG_Out(_T("XML: %ls (%ls), Machine: %ls (%ls), Return: %hs"),
(LPCWSTR)bstrManufacturer,
(LPCWSTR)bstrModel,
(LPCWSTR)bstrXmlManufacturer,
(LPCWSTR)bstrXmlModel,
((*pfResult) ? "True" : "False"));
CleanUp:
SysFreeString(bstrManufacturer);
SysFreeString(bstrModel);
SysFreeString(bstrSupportURL);
SysFreeString(bstrXmlManufacturer);
SysFreeString(bstrXmlModel);
return hr;
}