windows-nt/Source/XPSP1/NT/ds/security/services/scerpc/escprov/sceparser.cpp

1583 lines
31 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// scecore.h: interface for the core services sceprov provides.
// Copyright (c)1997-2001 Microsoft Corporation
//
//////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include "sceprov.h"
#include "sceparser.h"
// IScePathParser
/*
Routine Description:
Name:
CScePathParser::CScePathParser
Functionality:
Constructor. Initialize pointer members.
Virtual:
No.
Arguments:
None.
Return Value:
None.
Notes:
If you add more members, please initialize them here.
*/
CScePathParser::CScePathParser ()
:
m_pszNamespace(NULL),
m_pszClassName(NULL)
{
}
/*
Routine Description:
Name:
CScePathParser::~CScePathParser
Functionality:
Destructor. Do clean up (free memory).
Virtual:
No.
Arguments:
None.
Return Value:
None.
Notes:
If you add more members, please consider do clean up in the Cleanup function.
*/
CScePathParser::~CScePathParser()
{
Cleanup();
}
/*
Routine Description:
Name:
CScePathParser::ParsePath
Functionality:
Parsing given path and store results in our members.
Virtual:
Yes.
Arguments:
pszObjectPath - the path to be parsed.
Return Value:
Success: S_OK
Failure: various error code. Any such error indicates the failure to parse the path.
(1) E_INVALIDARG
(2) E_OUTOFMEMORY
(3) E_UNEXPECTED for syntax error
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP
CScePathParser::ParsePath (
IN LPCWSTR pszObjectPath
)
{
if (pszObjectPath == NULL || *pszObjectPath == L'\0')
{
return E_INVALIDARG;
}
//
// just in case, this object has already parsed before. This allows repeated use of the same
// CScePathParser for parsing different paths.
//
Cleanup();
//
// Ask WMI for their path parser
//
CComPtr<IWbemPath> srpPathParser;
HRESULT hr = ::GetWbemPathParser(&srpPathParser);
if (FAILED(hr))
{
return hr;
}
//
// This is the parsing function.
//
hr = srpPathParser->SetText(WBEMPATH_CREATE_ACCEPT_ALL | WBEMPATH_TREAT_SINGLE_IDENT_AS_NS, pszObjectPath);
if (FAILED(hr))
{
return hr;
}
//
// Get the results...
//
ULONG uBufSize = 0;
DWORD dwCount = 0;
//
// get namespace count
//
hr = srpPathParser->GetNamespaceCount(&dwCount);
if (dwCount > 0)
{
//
// get the length needed for the namespace
//
hr = srpPathParser->GetNamespaceAt(0, &uBufSize, NULL);
if (FAILED(hr))
{
return hr;
}
//
// we will free this memory.
//
m_pszNamespace = new WCHAR[uBufSize];
if (m_pszNamespace == NULL)
{
return E_OUTOFMEMORY;
}
//
// will ignore the result
//
hr = srpPathParser->GetNamespaceAt(0, &uBufSize, m_pszNamespace);
}
//
// get the buffer size needed for the class name
//
uBufSize = 0;
hr = srpPathParser->GetClassName(&uBufSize, NULL);
if (SUCCEEDED(hr))
{
//
// we will free this memory.
//
m_pszClassName = new WCHAR[uBufSize];
if (m_pszClassName == NULL)
{
return E_OUTOFMEMORY;
}
//
// WMI path parser don't have a documented behavior as when the class name
// will be missing.
//
hr = srpPathParser->GetClassName(&uBufSize, m_pszClassName);
}
else
{
//
// this clearly don't have a class name, then the namespace should be the class name.
// for some reason, Query parser doesn't give us class name in case of singleton
// and the class name ends up in the namespace member. Obviously, in this case, there is no
// key properties.
//
//
// must have a namespace
//
if (m_pszNamespace)
{
//
// prepare to switch m_pszClassName to point to what the namesapce does.
//
delete [] m_pszClassName;
m_pszClassName = m_pszNamespace;
m_pszNamespace = NULL;
//
// we can return because there is no key property
//
return S_OK;
}
else
{
hr = E_UNEXPECTED;
}
}
if (FAILED(hr))
{
return hr;
}
//
// get key properties
//
CComPtr<IWbemPathKeyList> srpKeyList;
hr = srpPathParser->GetKeyList(&srpKeyList);
if (FAILED(hr))
{
return hr;
}
//
// now get the Key and value pairs
//
ULONG uKeyCount = 0;
hr = srpKeyList->GetCount(&uKeyCount);
if (FAILED(hr) || uKeyCount == 0)
{
return hr;
}
for (ULONG i = 0; i < uKeyCount; i++)
{
//
// this pKeyVal will cache the (name, value) pair
//
CPropValuePair* pKeyVal = NULL;
uBufSize = 0;
//
// now get the size of buffer needed
//
CComVariant var;
ULONG uCimType = CIM_EMPTY;
hr = srpKeyList->GetKey2(i,
0,
&uBufSize,
NULL,
&var,
&uCimType);
if (SUCCEEDED(hr))
{
//
// our vector will manage the memory used by pKeyVal
//
pKeyVal = new CPropValuePair;
if (pKeyVal == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
//
// need the name buffer
//
pKeyVal->pszKey = new WCHAR[uBufSize];
//
// variant member of pKeyVal needs to be initialized as well.
//
::VariantInit(&(pKeyVal->varVal));
//
// secondary allocation fails, need to free the first level pointer
//
if (pKeyVal->pszKey == NULL)
{
delete pKeyVal;
pKeyVal = NULL;
hr = E_OUTOFMEMORY;
break;
}
}
if (SUCCEEDED(hr))
{
hr = srpKeyList->GetKey2(i,
0,
&uBufSize,
pKeyVal->pszKey,
&(pKeyVal->varVal),
&uCimType);
}
if (SUCCEEDED(hr))
{
m_vecKeyValueList.push_back(pKeyVal);
}
else
{
//
// for any failure, we need to free the resource already partially allocated
// for the pKeyVal. This pKeyVal is pointing to our class, which knows how to free its members,
// this delete is enough.
//
delete pKeyVal;
break;
}
}
if (SUCCEEDED(hr))
{
hr = S_OK;
}
return hr;
}
/*
Routine Description:
Name:
CScePathParser::GetKeyPropertyCount
Functionality:
Get the key proeprty count contained in the path.
Virtual:
Yes.
Arguments:
pCount - receives the count.
Return Value:
Success: S_OK
Failure: E_INVALIDARG.
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP
CScePathParser::GetKeyPropertyCount (
OUT DWORD *pCount
)
{
if (pCount == NULL)
{
return E_INVALIDARG;
}
*pCount = m_vecKeyValueList.size();
return S_OK;
}
/*
Routine Description:
Name:
CScePathParser::GetNamespace
Functionality:
Get the namespace.
Virtual:
Yes.
Arguments:
pbstrNamespace - receives the namespace string.
Return Value:
Success: S_OK
Failure:
(1) E_INVALIDARG
(2) E_OUTOFMEMORY
(3) E_UNEXPECTED for syntax error
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP
CScePathParser::GetNamespace (
OUT BSTR *pbstrNamespace
)
{
if (pbstrNamespace == NULL)
{
return E_INVALIDARG;
}
if (m_pszNamespace)
{
*pbstrNamespace = ::SysAllocString(m_pszNamespace);
}
else
{
return E_UNEXPECTED;
}
return (*pbstrNamespace) ? S_OK : E_OUTOFMEMORY;
}
/*
Routine Description:
Name:
CScePathParser::GetClassName
Functionality:
Get the class name.
Virtual:
Yes.
Arguments:
pbstrClassName - receives the class name string.
Return Value:
Success: S_OK
Failure:
(1) E_INVALIDARG
(2) E_OUTOFMEMORY
(3) E_UNEXPECTED for syntax error
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP
CScePathParser::GetClassName (
OUT BSTR *pbstrClassName
)
{
if (pbstrClassName == NULL)
{
return E_INVALIDARG;
}
if (m_pszClassName)
{
*pbstrClassName = ::SysAllocString(m_pszClassName);
}
else
{
return E_UNEXPECTED;
}
return (*pbstrClassName) ? S_OK : E_OUTOFMEMORY;
}
/*
Routine Description:
Name:
CScePathParser::GetKeyPropertyValue
Functionality:
Get the named property's value
Virtual:
Yes.
Arguments:
pszKeyPropName - The key property's name whose value is to be retrieved.
pvarValue - receives the value.
Return Value:
Success: S_OK if the property value is properly retrieved.
WBEM_S_FALSE if the property value can't be found.
Failure:
(1) E_INVALIDARG
(2) E_OUTOFMEMORY
(5) Or errors from VariantCopy
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP
CScePathParser::GetKeyPropertyValue (
IN LPCWSTR pszKeyPropName,
OUT VARIANT *pvarValue
)
{
if (pszKeyPropName == NULL || *pszKeyPropName == L'\0' || pvarValue == NULL)
{
return E_INVALIDARG;
}
//
// set the variant to a valid empty initial state
//
::VariantInit(pvarValue);
//
// assume we can't find the property
//
HRESULT hr = WBEM_S_FALSE;
std::vector<CPropValuePair*>::iterator it;
//
// find the property (case-insensitive name comparison) and copy the value
//
for (it = m_vecKeyValueList.begin(); it != m_vecKeyValueList.end(); it++)
{
if (_wcsicmp((*it)->pszKey, pszKeyPropName) == 0)
{
hr = ::VariantCopy(pvarValue, &((*it)->varVal));
break;
}
}
return hr;
}
/*
Routine Description:
Name:
CScePathParser::GetKeyPropertyValueByIndex
Functionality:
Get the indexed property name and value.
Virtual:
Yes.
Arguments:
dwIndex - the (name, value) pair's index.
pbstrKeyPropName - receives key property's name.
pvarValue - receives the value. In caller not interested, this can be NULL.
Return Value:
Success: S_OK
Failure:
(1) E_INVALIDARG (illegal null or index out of range)
(2) E_OUTOFMEMORY
(3) E_UNEXPECTED for can't find the property
(4) Or errors from VariantCopy
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP CScePathParser::GetKeyPropertyValueByIndex (
IN DWORD dwIndex,
OUT BSTR* pbstrKeyPropName,
OUT VARIANT *pvarValue OPTIONAL
)
{
if (dwIndex >= m_vecKeyValueList.size() || pbstrKeyPropName == NULL)
{
return E_INVALIDARG;
}
//
// assume we can't find it
//
HRESULT hr = E_UNEXPECTED;
//
// initialize the out parameters
//
*pbstrKeyPropName = NULL;
if (pvarValue)
{
::VariantInit(pvarValue);
}
CPropValuePair *pKV = m_vecKeyValueList[dwIndex];
if (pKV)
{
*pbstrKeyPropName = ::SysAllocString(pKV->pszKey);
if (pbstrKeyPropName == NULL)
{
hr = E_OUTOFMEMORY;
}
if (SUCCEEDED(hr) && pvarValue)
{
hr = ::VariantCopy(pvarValue, &(pKV->varVal));
//
// don't want to return partial results
//
if (FAILED(hr))
{
::SysFreeString(*pbstrKeyPropName);
*pbstrKeyPropName = NULL;
}
}
}
return hr;
}
/*
Routine Description:
Name:
CScePathParser::Cleanup
Functionality:
Free memory resources.
Virtual:
No.
Arguments:
None.
Return Value:
None.
Notes:
Consider adding your clean up code here should you need to add members.
*/
void CScePathParser::Cleanup()
{
//
// empty the vector. Since the vector manages the (name, value) pair,
// its contents need to be deleted!
//
std::vector<CPropValuePair*>::iterator it;
for (it = m_vecKeyValueList.begin(); it != m_vecKeyValueList.end(); ++it)
{
delete *it;
}
m_vecKeyValueList.empty();
//
// This function may be called not just inside the destructor,
// so, properly reset the pointer values after free its memory.
//
delete [] m_pszNamespace;
m_pszNamespace = NULL;
delete [] m_pszClassName;
m_pszClassName = NULL;
}
//================================================================================================
// implementations for CSceQueryParser
//================================================================================================
/*
Routine Description:
Name:
CSceQueryParser::CSceQueryParser
Functionality:
Constructor. All members are classes. They initialize automatically.
Virtual:
No.
Arguments:
None.
Return Value:
None.
Notes:
If you add more members, please initialize them here.
*/
CSceQueryParser::CSceQueryParser()
{
}
/*
Routine Description:
Name:
CSceQueryParser::~CSceQueryParser
Functionality:
Destructor. do clean up.
Virtual:
No.
Arguments:
None.
Return Value:
None.
Notes:
If you add more members, please initialize them here.
*/
CSceQueryParser::~CSceQueryParser()
{
Cleanup();
}
/*
Routine Description:
Name:
CSceQueryParser::GetClassName
Functionality:
Get the class's name for the given index.
Virtual:
Yes.
Arguments:
iIndex - The index of the class. Currently, this is not used because WMI only
support unary query - query that spans over one class. What we won't
design our interface into that.
pbstrClassName - Receives the class name.
Return Value:
Success: S_OK
Failure:
(1) E_INVALIDARG (illegal null or index out of range)
(2) E_OUTOFMEMORY
(3) E_UNEXPECTED for can't find the property
(4) Or errors from VariantCopy
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP
CSceQueryParser::GetClassName (
IN int iIndex,
OUT BSTR * pbstrClassName
)
{
if (pbstrClassName == NULL || iIndex >= m_vecClassList.size())
{
return E_INVALIDARG;
}
if (m_vecClassList[iIndex])
{
*pbstrClassName = ::SysAllocString(m_vecClassList[iIndex]);
}
else
{
return E_UNEXPECTED;
}
return (*pbstrClassName) ? S_OK : E_OUTOFMEMORY;
}
/*
Routine Description:
Name:
CSceQueryParser::GetGetQueryingPropertyValue
Functionality:
Get querying property's value given the index.
Virtual:
Yes.
Arguments:
iIndex - Since the same querying property may have multiple values in the where clause
this is to get the iIndex-th value of the querying property. If you have a query
like this:
select * from Foo where FooVal = 1 AND BarVal = 5 OR FooVal = 2 AND BarVal = 6
you will end up only with FooVal's. The reason for this limitation is that WMI
doesn't have a full support on it (parser is maturing) and it's way too complicated
for our SCE parser. For users who needs that kind of support, please use WMI's query
parser directly.
pbstrQPValue - Receives the querying property's value in string format.
Return Value:
Success: S_OK
Failure:
(1) E_INVALIDARG (illegal null or index out of range)
(2) E_OUTOFMEMORY
(3) E_UNEXPECTED for can't find the property
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP
CSceQueryParser::GetQueryingPropertyValue (
IN int iIndex,
OUT BSTR * pbstrQPValue
)
{
if (pbstrQPValue == NULL || iIndex >= m_vecQueryingPropValueList.size())
{
return E_INVALIDARG;
}
if (m_vecQueryingPropValueList[iIndex])
{
*pbstrQPValue = ::SysAllocString(m_vecQueryingPropValueList[iIndex]);
}
else
{
return E_UNEXPECTED;
}
return (*pbstrQPValue) ? S_OK : E_OUTOFMEMORY;
}
/*
Routine Description:
Name:
CSceQueryParser::Cleanup
Functionality:
free the resources held by our members.
Virtual:
No.
Arguments:
None.
Return Value:
None.
Notes:
(1) Consider add clean up code here should you need to add more members.
*/
void CSceQueryParser::Cleanup()
{
//
// both vectors are storing heap strings, need to delete the contents!
//
std::vector<LPWSTR>::iterator it;
for (it = m_vecClassList.begin(); it != m_vecClassList.end(); it++)
{
delete [] (*it);
}
m_vecClassList.empty();
for (it = m_vecQueryingPropValueList.begin(); it != m_vecQueryingPropValueList.end(); it++)
{
delete [] (*it);
}
m_vecQueryingPropValueList.empty();
m_bstrQueryingPropName.Empty();
}
/*
Routine Description:
Name:
CSceQueryParser::ParseQuery
Functionality:
Given the property name we are looking for, this function will parsing the query.
Virtual:
Yes.
Arguments:
strQuery - The query to be parsed.
strQueryPropName - The querying property (the property we are looking for in the query).
Return Value:
Success: S_OK
Failure:
(1) E_INVALIDARG (illegal null or index out of range)
(2) E_OUTOFMEMORY
(3) E_UNEXPECTED for can't find the property
(4) Other errors from WMI query parser.
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP CSceQueryParser::ParseQuery (
IN LPCWSTR strQuery,
IN LPCWSTR strQueryPropName
)
{
if (strQuery == NULL || *strQuery == L'\0')
{
return E_INVALIDARG;
}
CComPtr<IWbemQuery> srpQuery;
//
// Get the WMI query object
//
HRESULT hr = ::GetWbemQuery(&srpQuery);
if (FAILED(hr))
{
return hr;
}
//
// Set up the query parser to use
//
ULONG uFeatures[] = {WMIQ_LF1_BASIC_SELECT, WMIQ_LF2_CLASS_NAME_IN_QUERY};
hr = srpQuery->SetLanguageFeatures(0, sizeof(uFeatures)/sizeof(*uFeatures), uFeatures);
if (FAILED(hr))
{
return hr;
}
//
// we are ready to parse, so, cleanup
//
Cleanup();
//
// parse the query
//
hr = srpQuery->Parse(L"WQL", strQuery, 0);
if (FAILED(hr))
{
return hr;
}
//
// Get the parsing results
//
//
// need to free memory. Don't do it ourselves. Ask query to free it!
//
SWbemRpnEncodedQuery *pRpn = 0;
hr = srpQuery->GetAnalysis(WMIQ_ANALYSIS_RPN_SEQUENCE, 0, (LPVOID *) &pRpn);
if (SUCCEEDED(hr))
{
//
// Need the class name from the results
//
hr = ExtractClassNames(pRpn);
//
// need the querying property values
//
if (SUCCEEDED(hr) && strQueryPropName && *strQueryPropName != L'\0')
{
m_bstrQueryingPropName = strQueryPropName;
hr = ExtractQueryingProperties(pRpn, strQueryPropName);
}
srpQuery->FreeMemory(pRpn);
}
return SUCCEEDED(hr) ? S_OK : hr;
}
/*
Routine Description:
Name:
CSceQueryParser::ExtractClassNames
Functionality:
Private helper to get the class name(s) from the query results.
Virtual:
No.
Arguments:
pRpn - The query result.
Return Value:
Success: S_OK
Failure:
(1) E_INVALIDARG (illegal null or index out of range)
(2) E_OUTOFMEMORY.
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
HRESULT CSceQueryParser::ExtractClassNames (
SWbemRpnEncodedQuery *pRpn
)
{
if (pRpn == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
int iLen = 0;
LPWSTR pszClassName = NULL;
//
// get the from clause, i.e., the class names
//
if (pRpn->m_uFromTargetType & WMIQ_RPN_FROM_UNARY)
{
//
// only one class
//
//
// copy the class name and push it to our list
//
iLen = wcslen(pRpn->m_ppszFromList[0]);
pszClassName = new WCHAR[iLen + 1];
if (pszClassName != NULL)
{
//
// won't overrun buffer, see size above
//
wcscpy(pszClassName, pRpn->m_ppszFromList[0]);
m_vecClassList.push_back(pszClassName);
}
else
{
hr = E_OUTOFMEMORY;
}
}
else if (pRpn->m_uFromTargetType & WMIQ_RPN_FROM_CLASS_LIST)
{
//
// multiple classes. Won't happen for the time being. But we want to be ready
// for WMI parser's enhancement.
//
for (ULONG uIndex = 0; uIndex < pRpn->m_uFromListSize; uIndex++)
{
iLen = wcslen(pRpn->m_ppszFromList[uIndex]);
pszClassName = new WCHAR[iLen + 1];
if (pszClassName != NULL)
{
//
// won't overrun buffer, see size above
//
wcscpy(pszClassName, pRpn->m_ppszFromList[uIndex]);
m_vecClassList.push_back(pszClassName);
}
else
{
hr = E_OUTOFMEMORY;
break;
}
}
}
return hr;
}
/*
Routine Description:
Name:
CSceQueryParser::ExtractQueryingProperties
Functionality:
Private helper to get the class name(s) from the query results.
Virtual:
No.
Arguments:
pRpn - The query result.
strQueryPropName - the querying property's name
Return Value:
Success: S_OK
Failure:
(1) E_INVALIDARG (illegal null or index out of range)
(2) E_OUTOFMEMORY.
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
(2) We only care about one querying property. Each subexpression will only have one querying property.
Plus, if the subexpressions are AND'ed together, we will skip the rest subexpressions until we
sees an OR again.
(3) We can't support NOT very well. For example, how can we answer:
select * from where NOT (SceStorePath = "c:\\test.inf")
Fundamentally, we can't do that because we don't know the score of files not equal "c:\\test.inf".
*/
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
HRESULT CSceQueryParser::ExtractQueryingProperties (
IN SWbemRpnEncodedQuery * pRpn,
IN LPCWSTR strQueryPropName
)
{
if (pRpn == NULL)
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
SWbemRpnQueryToken *pQueryToken = NULL;
//
// flags if we should ignore the next token
//
bool bSkip = false;
for (ULONG uIndex = 0; uIndex < pRpn->m_uWhereClauseSize; uIndex++)
{
pQueryToken = pRpn->m_ppRpnWhereClause[uIndex];
switch (pQueryToken->m_uTokenType)
{
case WMIQ_RPN_TOKEN_EXPRESSION:
//
// there is a subexpression, potentially a querying property here
//
if (!bSkip)
{
hr = GetQueryPropFromToken(pQueryToken, strQueryPropName);
}
//
// if hr == S_FALSE, then it means it doesn't find any Store path
// see it's use in case WMIQ_RPN_TOKEN_AND bellow
//
if (FAILED(hr))
{
return hr;
}
break;
case WMIQ_RPN_TOKEN_OR:
//
// we see an OR, next tokens should NOT been skipped
//
bSkip = false;
break;
case WMIQ_RPN_TOKEN_AND:
//
// see comments about S_FALSE in case WMIQ_RPN_TOKEN_EXPRESSION above
//
bSkip = (hr == S_FALSE) ? false : true;
//
// fall through
//
case WMIQ_RPN_TOKEN_NOT:
default:
//
// don't support parsing these tokens, so skip
//
bSkip = true;
break;
}
}
return S_OK;
}
/*
Routine Description:
Name:
CSceQueryParser::GetQueryPropFromToken
Functionality:
Private helper analyze the token and get the querying property's value if found.
Virtual:
No.
Arguments:
pRpnQueryToken - The token to analyze.
strQueryPropName - the querying property's name
Return Value:
Success: S_OK if a querying property's value is successfully retrieved.
S_FALSE if no querying property name if found in the token.
Failure:
(1) E_INVALIDARG (illegal null or index out of range)
(2) E_OUTOFMEMORY.
(3) Other errors only defined by WMI, such as WBEM_E_INVALID_SYNTAX, WBEM_E_NOT_SUPPORTED.
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
(2) We only care about one querying property. Each subexpression will only have one querying property.
Plus, if the subexpressions are AND'ed together, we will skip the rest subexpressions until we
sees an OR again.
(3) We can't support NOT very well. For example, how can we answer:
select * from where NOT (SceStorePath = "c:\\test.inf")
Fundamentally, we can't do that because we don't know the score of files not equal "c:\\test.inf".
*/
HRESULT
CSceQueryParser::GetQueryPropFromToken (
IN SWbemRpnQueryToken * pRpnQueryToken,
IN LPCWSTR strQueryPropName
)
{
HRESULT hr = S_OK;
//
// we only support <propertyName> = <value> and
// <value> should be string
//
if (pRpnQueryToken->m_uOperator != WMIQ_RPN_OP_EQ ||
pRpnQueryToken->m_uConstApparentType != VT_LPWSTR )
{
return WBEM_E_NOT_SUPPORTED;
}
//
// must have left identifier, we don't support it if it doesn't have one.
//
if (pRpnQueryToken->m_pLeftIdent == NULL)
{
hr = WBEM_E_NOT_SUPPORTED;
}
else
{
SWbemQueryQualifiedName *pLeft = pRpnQueryToken->m_pLeftIdent;
//
// no left, invalid
//
if (pLeft == NULL)
{
return WBEM_E_INVALID_SYNTAX;
}
if (pLeft->m_uNameListSize != 1)
{
return WBEM_E_NOT_SUPPORTED;
}
// if the right is StoreName, then this is what we need
if (_wcsicmp(strQueryPropName, pLeft->m_ppszNameList[0]) == 0)
{
int iLen = wcslen(pRpnQueryToken->m_Const.m_pszStrVal);
LPWSTR pName = new WCHAR[iLen + 1];
if (pName)
{
//
// won't overrun the buffer
//
wcscpy(pName, pRpnQueryToken->m_Const.m_pszStrVal);
m_vecQueryingPropValueList.push_back(pName);
}
else
{
return E_OUTOFMEMORY;
}
}
else
{
//
// no match for querying property name
//
hr = S_FALSE;
}
}
return hr;
}
/*
Routine Description:
Name:
CSceQueryParser::GetQueryPropFromToken
Functionality:
Get key proeprty value parsed from the query. Due to our query limitation, the property name
should really be the querying property name.
Virtual:
Yes.
Arguments:
pszKeyPropName - The key property name.
pvarValue - receives the value.
Return Value:
Success: S_OK if a key property's value is successfully retrieved.
WBEM_S_FALSE if the property can't be found.
Failure:
(1) E_INVALIDARG (illegal null or index out of range)
(2) E_OUTOFMEMORY.
(3) Other errors only defined by WMI, such as WBEM_E_INVALID_SYNTAX, WBEM_E_NOT_SUPPORTED.
Notes:
(1) Since this is regular COM server interface function, we use regular COM errors
instead of WMI errors. However, we can't guarantee what WMI returns.
*/
STDMETHODIMP
CSceQueryParser::GetKeyPropertyValue (
IN LPCWSTR pszKeyPropName,
OUT VARIANT * pvarValue
)
{
if (pvarValue == NULL)
{
return E_INVALIDARG;
}
//
// ready to say that we can't find it
//
HRESULT hr = WBEM_S_FALSE;
::VariantInit(pvarValue);
//
// If you are asking for the querying property's value, we certainly can give you one.
//
if ((LPCWSTR)m_bstrQueryingPropName != NULL && _wcsicmp(pszKeyPropName, m_bstrQueryingPropName) == 0)
{
CComBSTR bstrVal;
hr = GetQueryingPropertyValue(0, &bstrVal);
if (SUCCEEDED(hr))
{
//
// hand it over to the out parameter
//
pvarValue->vt = VT_BSTR;
pvarValue->bstrVal = bstrVal.Detach();
hr = S_OK;
}
}
return hr;
}