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

2076 lines
43 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// compkey.cpp: implementation of the CCompoundKey class
// Copyright (c)1997-2001 Microsoft Corporation
//
//////////////////////////////////////////////////////////////////////
// original author: shawnwu
// creation date: 4/18/2001
#include "precomp.h"
#include "compkey.h"
#include "persistmgr.h"
/*
Routine Description:
Name:
CompKeyLessThan::operator()
Functionality:
override () operator
Virtual:
No.
Arguments:
pX - left.
pY - right.
Return Value:
read code. It's easier that way.
Notes:
We are not really doing much other than call CCompoundKey's operator <.
*/
bool CompKeyLessThan::operator() (
IN const CCompoundKey* pX,
IN const CCompoundKey* pY
) const
{
if (pX == NULL && pY != NULL)
return true;
else if (pX != NULL && pY == NULL)
return false;
else
return *pX < *pY;
}
/*
Routine Description:
Name:
CCompoundKey::CCompoundKey
Functionality:
constructor.
Virtual:
No.
Arguments:
dwSize - This will be size of the compound key's capacity to hold values.
you can't change it.
Return Value:
none
Notes:
If dwSize == 0, it's considered a null key. Null keys are useful for identifying
static method calls, and singletons (because they don't have keys)
*/
CCompoundKey::CCompoundKey (
IN DWORD dwSize
)
:
m_dwSize(dwSize),
m_pValues(NULL)
{
if (m_dwSize > 0)
{
m_pValues = new VARIANT*[m_dwSize];
if (m_pValues == NULL)
{
m_dwSize = 0;
}
else
{
//
// make sure that we initialize those VARIANT* to NULL
// because we are going to own them and delete them!
//
::memset(m_pValues, 0, m_dwSize * sizeof(VARIANT*));
}
}
}
/*
Routine Description:
Name:
CCompoundKey::~CCompoundKey
Functionality:
destructor.
Virtual:
No.
Arguments:
none
Return Value:
none
Notes:
Just need to know how to delete a VARIANT*
*/
CCompoundKey::~CCompoundKey()
{
for (DWORD i = 0; i < m_dwSize; i++)
{
if (m_pValues[i])
{
::VariantClear(m_pValues[i]);
delete m_pValues[i];
}
}
delete [] m_pValues;
}
/*
Routine Description:
Name:
CCompoundKey::AddKeyPropertyValue
Functionality:
Add a key property value to this compound key.
Virtual:
No.
Arguments:
none
Return Value:
WBEM_NO_ERROR if succeeded.
WBEM_E_INVALID_PARAMETER if ppVar == NULL;
WBEM_E_VALUE_OUT_OF_RANGE is the given index is not in range.
Notes:
CCompoundKey doesn't keep track of property names. Instead, it simply records
its values. The order this function is called determines what value belongs to
what property. Caller must keep track of that order. Different compound keys
become comparable only if they have the same order.
Also, the in coming parameter *ppVar is owned by the this object after this call
*/
HRESULT
CCompoundKey::AddKeyPropertyValue (
IN DWORD dwIndex,
IN OUT VARIANT ** ppVar
)
{
if (ppVar == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
else if (dwIndex >= m_dwSize)
{
return WBEM_E_VALUE_OUT_OF_RANGE;
}
//
// if there is already a value, then we need to delete the old one
//
if (m_pValues[dwIndex])
{
::VariantClear(m_pValues[dwIndex]);
delete m_pValues[dwIndex];
}
//
// attach to the new one
//
m_pValues[dwIndex] = *ppVar;
//
// hey, we own it now
//
*ppVar = NULL;
return WBEM_NO_ERROR;
}
/*
Routine Description:
Name:
CCompoundKey::GetPropertyValue
Functionality:
Retrieve a key property value by key property index (caller must know that).
Virtual:
No.
Arguments:
none
Return Value:
Read code.
Notes:
See AddKeyPropertyValue's notes
*/
HRESULT
CCompoundKey::GetPropertyValue (
IN DWORD dwIndex,
OUT VARIANT * pVar
)const
{
if (pVar == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
else if (dwIndex >= m_dwSize)
{
return WBEM_E_VALUE_OUT_OF_RANGE;
}
//
// make sure that our out-bound parameter is in a empty state
//
::VariantInit(pVar);
if (m_pValues[dwIndex])
{
return ::VariantCopy(pVar, m_pValues[dwIndex]);
}
else
{
return WBEM_E_NOT_AVAILABLE;
}
}
/*
Routine Description:
Name:
CCompoundKey::operator <
Functionality:
Compare this object with the in-bound parameter and see which compound key
key is greater. Ultimately, the relation is determined by the variant values
of each corresponding key property.
Virtual:
No.
Arguments:
none
Return Value:
Read code.
Notes:
(1) See AddKeyPropertyValue's notes.
(2) See CompareVariant's notes
*/
bool
CCompoundKey::operator < (
IN const CCompoundKey& right
)const
{
//
// defensive against potential erroneous comparison.
// This shouldn't happen in our correct use. But sometimes we write
// less-than-correct code.
//
if (m_dwSize != right.m_dwSize)
{
return (m_dwSize < right.m_dwSize);
}
int iComp = 0;
//
// The first less than or greater than result wins
//
for (int i = 0; i < m_dwSize; i++)
{
//
// if both variants are valid
//
if (m_pValues[i] != NULL && right.m_pValues[i] != NULL)
{
//
// CompareVariant returns the exact same int value
// as string comparison results
//
iComp = CompareVariant(m_pValues[i], right.m_pValues[i]);
if (iComp > 0)
{
return false;
}
else if (iComp < 0)
{
return true;
}
//
// else is equal! need to continue comparing the rest of the values
//
}
else if (m_pValues[i] == NULL)
{
return true;
}
else
{
//
// right.m_pValues[i] == NULL
//
return false;
}
}
//
// if reach here, this must be an equal case
//
return false;
}
/*
Routine Description:
Name:
CCompoundKey::CompareVariant
Functionality:
Compare two variants
Virtual:
No.
Arguments:
pVar1 - must not be NULL
pVar2 - must not be NULL
Return Value:
less than 0 if pVar1 < pVar2
Greater than 0 if pVar1 < pVar2
0 if they are considered equal
Notes:
(1) for efficiency reasons, we don't check the parameters.
(2) The reason we are doing this is due the fact that WMI will give us inconsistent
path when boolean are used. Sometimes it gives boolVal=TRUE, sometimes it gives
boolVal=1. This creates problems for us.
(3) This function currently only works for our supported vt types.
(4) type mismatch will only be dealt with if one of them is boolean.
*/
int
CCompoundKey::CompareVariant (
IN VARIANT* pVar1,
IN VARIANT* pVar2
)const
{
//
// default to equal because that is the only consistent value
// in case of failure
//
int iResult = 0;
VARIANT varCoerced1;
::VariantInit(&varCoerced1);
VARIANT varCoerced2;
::VariantInit(&varCoerced2);
//
// if both are strings, then use case-insensitive comparison
//
if (pVar1->vt == pVar2->vt && pVar1->vt == VT_BSTR)
{
iResult = _wcsicmp(pVar1->bstrVal, pVar2->bstrVal);
}
//
// if one is boolean, then coerced both to boolean
//
else if (pVar1->vt == VT_BOOL || pVar2->vt == VT_BOOL)
{
//
// in case the coersion fails, we will call the failed one less then the succeeded one.
// Don't use the WBEM_NO_ERROR even though they are defined to be S_OK. WMI may change it
// later. So, use the MSDN documented hresult values
//
HRESULT hr1 = ::VariantChangeType(&varCoerced1, pVar1, VARIANT_LOCALBOOL, VT_BOOL);
HRESULT hr2 = ::VariantChangeType(&varCoerced2, pVar2, VARIANT_LOCALBOOL, VT_BOOL);
if (hr1 == S_OK && hr2 == S_OK)
{
if (varCoerced1.boolVal == varCoerced2.lVal)
{
//
// equal
//
iResult = 0;
}
else if (varCoerced1.boolVal == VARIANT_TRUE)
{
//
// greater
//
iResult = 1;
}
else
{
//
// less
//
iResult = -1;
}
}
else if (hr1 == S_OK)
{
//
// second coersion fails, we say the second is greater
//
iResult = 1;
}
else if (hr2 == S_OK)
{
//
// first coersion fails, we say the first is greater
//
iResult = -1;
}
else
{
//
// both fails. We are out of luck.
//
iResult = 0;
}
}
//
// everything else, coerced both to VI_I4
//
else
{
HRESULT hr1 = ::VariantChangeType(&varCoerced1, pVar1, VARIANT_LOCALBOOL, VT_I4);
HRESULT hr2 = ::VariantChangeType(&varCoerced2, pVar2, VARIANT_LOCALBOOL, VT_I4);
if (hr1 == S_OK && hr2 == S_OK)
{
iResult = varCoerced1.lVal - varCoerced2.lVal;
}
else if (hr1 == S_OK)
{
//
// second coersion fails, we say the second is greater
//
iResult = 1;
}
else if (hr2 == S_OK)
{
//
// first coersion fails, we say the first is greater
//
iResult = -1;
}
else
{
//
// both fails. We are out of luck.
//
iResult = 0;
}
}
::VariantClear(&varCoerced1);
::VariantClear(&varCoerced2);
return iResult;
}
//
// implementation of CExtClassInstCookieList
//
/*
Routine Description:
Name:
CExtClassInstCookieList::CExtClassInstCookie
Functionality:
constructor.
Virtual:
No.
Arguments:
none
Return Value:
none
Notes:
(1) INVALID_COOKIE is the invalid cookie value.
(2) No thread safety. Caller must be aware.
*/
CExtClassInstCookieList::CExtClassInstCookieList ()
:
m_dwMaxCookie(INVALID_COOKIE),
m_pVecNames(NULL),
m_dwCookieArrayCount(0)
{
}
/*
Routine Description:
Name:
CExtClassInstCookieList::~CExtClassInstCookieList
Functionality:
destructor.
Virtual:
No.
Arguments:
none
Return Value:
none
Notes:
(1) No thread safety. Caller must be aware.
*/
CExtClassInstCookieList::~CExtClassInstCookieList ()
{
Cleanup();
}
/*
Routine Description:
Name:
CExtClassInstCookieList::Create
Functionality:
Given a store and a section name (each class has a section corresponding to it, as
a matter of fact, the section name is, in current implementation, the class name),
this function populates its contents.
Virtual:
No.
Arguments:
pSceStore - pointer to the CSceStore object prepared to read
pszSectionName - section name where this cookie list is to be created.
pvecNames - the vector that holds the key property names in order. We rely
on this vector as our order guidence to push values into our own vector.
Remember? those two things must match in their order.
A NULL in-bounding value means it intends to create a NULL key cookie
Return Value:
Success: WBEM_NO_ERROR
Failure: Various HRESULT code. In particular, if the cookie array is incorrectly formated
( it must be a integer number delimited by : (including the trailing : at the end), then
we return WBEM_E_INVALID_SYNTAX.
Any failure indicates that the cookie list is not created.
Notes:
(1) No thread safety. Caller must be aware.
*/
HRESULT
CExtClassInstCookieList::Create (
IN CSceStore * pSceStore,
IN LPCWSTR pszSectionName,
IN std::vector<BSTR> * pvecNames
)
{
//
// we must have a valid store and a valid section name
//
if (pSceStore == NULL || pszSectionName == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
m_pVecNames = pvecNames;
//
// 1 is reserved for pszListPrefix
//
WCHAR szCookieList[MAX_INT_LENGTH + 1];
WCHAR szCompKey[MAX_INT_LENGTH + 1];
HRESULT hr = WBEM_NO_ERROR;
//
// Assume that we have no cookie array
//
m_dwCookieArrayCount = 0;
//
// cookie list is persisted in the following fashion: "A1=n:m:k:", "A2=n:m:k:", "A3=n:m:k:"
// where 'A' == pszListPrefix.
//
//
// enumerate all such possiblilities until we see a non-existent Ai (i is a integer).
//
DWORD dwCount = 1;
while (SUCCEEDED(hr))
{
//
// First, we need to create the cookie list name
//
wsprintf(szCookieList, L"%s%d", pszListPrefix, dwCount++);
DWORD dwRead = 0;
//
// pszBuffer will hold the contents read from the store.
// Need to free the memory allocated for pszBuffer
//
LPWSTR pszBuffer = NULL;
hr = pSceStore->GetPropertyFromStore(pszSectionName, szCookieList, &pszBuffer, &dwRead);
if (SUCCEEDED(hr) && pszBuffer)
{
//
// so far, we have this many cookie arrays
//
m_dwCookieArrayCount += 1;
LPCWSTR pszCur = pszBuffer;
DWORD dwCookie = 0;
//
// as long as it is a digit
//
while (iswdigit(*pszCur))
{
//
// conver the first portion as a number
//
dwCookie = _wtol(pszCur);
//
// First, prepare the composite key's name (K1, K2, depending on the dwCookie.)
//
wsprintf(szCompKey, L"%s%d", pszKeyPrefix, dwCookie);
//
// read the composite key of this cookie
// need to free the memory allocated for pszCompKeyBuffer
//
LPWSTR pszCompKeyBuffer = NULL;
DWORD dwCompKeyLen = 0;
hr = pSceStore->GetPropertyFromStore(pszSectionName, szCompKey, &pszCompKeyBuffer, &dwCompKeyLen);
if (SUCCEEDED(hr))
{
//
// AddCompKey can be called for two purposes (simply adding, or adding and requesting a new cookie)
// Here, we are just adding. But we need a place holder.
//
DWORD dwNewCookie = INVALID_COOKIE;
//
// we are truly adding the (compound key, cookie) pair
//
hr = AddCompKey(pszCompKeyBuffer, dwCookie, &dwNewCookie);
//
// increate the max used cookie member if appropriate
//
if (dwCookie > m_dwMaxCookie)
{
m_dwMaxCookie = dwCookie;
}
}
delete [] pszCompKeyBuffer;
//
//skip the current portion of the integer
//
while (iswdigit(*pszCur))
{
++pszCur;
}
if (*pszCur == wchCookieSep)
{
//
// skip the ':'
//
++pszCur;
}
else if (*pszCur == L'\0')
{
//
// see the end
//
break;
}
else
{
//
// see an invalid character
//
hr = WBEM_E_INVALID_SYNTAX;
break;
}
}
}
else if (hr == WBEM_E_NOT_FOUND)
{
// if Ai doesn't exist, we no longer look for A(i+1). For example, if A3 doesn't exist, then we
// no longer look for A4, A5, etc. So, if property manager fails to get Ai, we consider this as
// no more data.
delete [] pszBuffer;
pszBuffer = NULL;
hr = WBEM_NO_ERROR;
break;
}
delete [] pszBuffer;
}
//
// in case of failure, set proper default
//
if (FAILED(hr))
{
//
// maybe partial construction, so clean it up
//
Cleanup();
}
return hr;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::Save
Functionality:
save the cookie list into a store.
Virtual:
No.
Arguments:
pSceStore - pointer to the CSceStore object prepared for save
pszSectionName - section name where this cookie list is to be created.
Return Value:
Success: various potential success code. Use SUCCEEDED to test.
Failure: Various HRESULT code.
Any failure indicates that the cookie list is not saved properly.
Notes:
(1) No thread safety. Caller must be aware.
*/
HRESULT
CExtClassInstCookieList::Save (
IN CSceStore* pSceStore,
IN LPCWSTR pszSectionName
)
{
//
// pszBuffer will hold upto MAX_COOKIE_COUNT_PER_LINE count of cookie info = <cookie number> plus separater
//
LPWSTR pszBuffer = new WCHAR [(MAX_INT_LENGTH + 1) * MAX_COOKIE_COUNT_PER_LINE + 1];
if (pszBuffer == NULL)
{
return WBEM_E_OUT_OF_MEMORY;
}
//
// allocate a generous buffer to hold the key name and cookie array name
//
LPWSTR pszKey = new WCHAR[MAX_INT_LENGTH + wcslen(pszKeyPrefix) + wcslen(pszListPrefix) + 1];
if (pszKey == NULL)
{
delete [] pszBuffer;
return WBEM_E_OUT_OF_MEMORY;
}
DWORD dwCookieArrayCount = 1;
int iLenKey = wcslen(pszKeyPrefix);
int iLen = wcslen(pszListPrefix);
if (iLen < iLenKey)
{
iLen = iLenKey;
}
HRESULT hr = WBEM_NO_ERROR;
DWORD dwCookieCount = m_vecCookies.size();
//
// going through all cookies. Since we want to preserve the order
// this time, we need to use the m_vecCookies to enumerate.
//
DWORD dwIndex = 0;
while (dwIndex < dwCookieCount)
{
//
// this loop is to:
// (1) write the string version of each compound key
// (2) pack enough cookies into the cookie list (but won't write it)
//
LPWSTR pCur = pszBuffer;
for (int i = 0; (i < MAX_COOKIE_COUNT_PER_LINE) && (dwIndex < dwCookieCount); ++i, dwIndex++)
{
//
// packing the cookies into the cookie list. We need to advance our
// pCur to the next position (of pszBuffer) to write
//
wsprintf(pCur, L"%d%c", m_vecCookies[dwIndex]->dwCookie, wchCookieSep);
pCur += wcslen(pCur);
//
// now, write Knnn=<compound key>
//
wsprintf(pszKey, L"%s%d", pszKeyPrefix, m_vecCookies[dwIndex]->dwCookie);
CComBSTR bstrCompKey;
//
// create the string version of the composite key (the <compound key>)
//
hr = CreateCompoundKeyString(&bstrCompKey, m_vecCookies[dwIndex]->pKey);
if (SUCCEEDED(hr))
{
hr = pSceStore->SavePropertyToStore(pszSectionName, pszKey, (LPCWSTR)bstrCompKey);
}
if (FAILED(hr))
{
break;
}
}
//
// if everything is alright, now is time to write the cookie list prepared by
// the previous loop
//
if (SUCCEEDED(hr))
{
//
// prepare the cookie list name
//
wsprintf(pszKey, L"%s%d", pszListPrefix, dwCookieArrayCount);
hr = pSceStore->SavePropertyToStore(pszSectionName, pszKey, pszBuffer);
if (FAILED(hr))
{
break;
}
}
else
{
break;
}
++dwCookieArrayCount;
}
//
// if everything goes well (all cookie arrays have been saved), then, we need to remove
// any potential extra cookie arrays Axxx, where the count starts from dwCookieArrayCount to m_dwCookieArrayCount
//
if (SUCCEEDED(hr))
{
//
// we will delete all left over cookie arrays.
// In case of error during deleting, we will continue the deletion, but will report the error
//
while (dwCookieArrayCount <= m_dwCookieArrayCount)
{
//
// prepare the cookie list name
//
wsprintf(pszKey, L"%s%d", pszListPrefix, dwCookieArrayCount++);
HRESULT hrDelete = pSceStore->DeletePropertyFromStore(pszSectionName, pszKey);
//
// we won't stop the deletion in case of error.
// But we will report it.
//
if (FAILED(hrDelete))
{
hr = hrDelete;
}
}
}
delete [] pszBuffer;
delete [] pszKey;
return hr;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::DeleteKeyFromStore
Functionality:
Delete all key properties (Key=<Compound Key String>)
Virtual:
No.
Arguments:
pSceStore - pointer to the CSceStore object prepared for save
pszSectionName - section name where this cookie list is to be created.
dwCookie - the cookie to of the key to be deleted
Return Value:
Success: WBEM_NO_ERROR.
Failure: Various HRESULT code.
Any failure indicates that the cookie list is not delete properly.
Notes:
(1) No thread safety. Caller must be aware.
*/
HRESULT
CExtClassInstCookieList::DeleteKeyFromStore (
IN CSceStore* pSceStore,
IN LPCWSTR pszSectionName,
IN DWORD dwCookie
)
{
int iLen = wcslen(pszKeyPrefix);
//
// 1 for pszKeyPrefix
//
WCHAR szKey[MAX_INT_LENGTH + 1];
wsprintf(szKey, L"%s%d", pszKeyPrefix, dwCookie);
return pSceStore->DeletePropertyFromStore(pszSectionName, szKey);
}
/*
Routine Description:
Name:
CExtClassInstCookieList::GetCompKeyCookie
Functionality:
Given a string version of the compound key (what is really stored in our template),
find the cookie. If found, also give an interator of the map to that element.
Virtual:
No.
Arguments:
pszCompKey - string version of the compound key
pIt - The iterator to the map that points to the CCompoundKey
whose key properties match what is encoded in the pszCompKey
Return Value:
the cookie if found.
INVALID_COOKIE if not found.
Notes:
(1) No thread safety. Caller must be aware.
*/
DWORD
CExtClassInstCookieList::GetCompKeyCookie (
IN LPCWSTR pszCompKey,
OUT ExtClassCookieIterator * pIt
)
{
CCompoundKey* pKey = NULL;
//
// we need a CCompoundKey to lookup. Convert the string version
// to a CCompoundKey instance. Need to delete it.
//
HRESULT hr = CreateCompoundKeyFromString(pszCompKey, &pKey);
if (FAILED(hr))
{
*pIt = m_mapCookies.end();
return INVALID_COOKIE;
}
*pIt = m_mapCookies.find(pKey);
DWORD cookie = INVALID_COOKIE;
if (*pIt != m_mapCookies.end())
{
cookie = (*((ExtClassCookieIterator)(*pIt))).second;
}
delete pKey;
return cookie;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::AddCompKey
Functionality:
Add a string version of the compound key (what is really stored in our template) to
this object. Since our store really only give string version of the compound key,
this method is what is used during creation upon reading the compound key string.
Virtual:
No.
Arguments:
pszCompKey - string version of the compound key. pszCompKey == pszNullKey means
to add a static function call instance or a singleton
dwDefCookie - Default value for the cookie it is called to add.
If dwDefCookie == INVALID_COOKIE, we will create a new cookie while adding
*pdwNewCookie - pass back the new cookie for the just added compound key
Return Value:
Will return the cookie for the compound key
Notes:
(1) No thread safety. Caller must be aware.
(2) Calling this function multiple times for the same cookie is safe because we will
prevent it from being added more than once.
*/
HRESULT
CExtClassInstCookieList::AddCompKey (
IN LPCWSTR pszCompKey,
IN DWORD dwDefCookie,
OUT DWORD * pdwNewCookie
)
{
if (pdwNewCookie == NULL || pszCompKey == NULL || *pszCompKey == L'\0')
{
return WBEM_E_INVALID_PARAMETER;
}
HRESULT hr = WBEM_NO_ERROR;
CCompoundKey* pKey = NULL;
//
// We really need a CCompoundKey object
//
hr = CreateCompoundKeyFromString(pszCompKey, &pKey);
if (FAILED(hr))
{
*pdwNewCookie = INVALID_COOKIE;
return hr;
}
//
// make sure that we don't add duplicate keys
//
ExtClassCookieIterator it = m_mapCookies.find(pKey);
if (it != m_mapCookies.end())
{
//
// already there, just pass back the cookie
//
*pdwNewCookie = (*it).second;
}
else
{
//
// not present in our map yet
//
*pdwNewCookie = dwDefCookie;
if (dwDefCookie == INVALID_COOKIE)
{
if (m_dwMaxCookie + 1 == INVALID_COOKIE)
{
//
// If the next cookie is INVALID_COOKIE, we need to search
// for a free slot. This gets more expansive. But given that
// it needs to reach 0xFFFFFFFF to have this happen, ordinary
// situation won't get to this point.
//
hr = GetNextFreeCookie(pdwNewCookie);
}
else
{
*pdwNewCookie = ++m_dwMaxCookie;
}
}
//
// we need to maintain the other vector, which records the order at which
// cookies are added (so that it can be preserved and used as access order)
//
if (SUCCEEDED(hr))
{
//
// now, push the pair to the vector, it will take care of the memory
//
CookieKeyPair* pNewCookieKey = new CookieKeyPair;
if (pNewCookieKey == NULL)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
else
{
pNewCookieKey->dwCookie = *pdwNewCookie;
pNewCookieKey->pKey = pKey;
m_vecCookies.push_back(pNewCookieKey);
//
// the map takes the ownership of the memory of pKey
//
m_mapCookies.insert(MapExtClassCookie::value_type(pKey, *pdwNewCookie));
pKey = NULL;
}
}
}
//
// if we have added it to the map, pKey == NULL. So harmless
//
delete pKey;
return hr;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::RemoveCompKey
Functionality:
Will remove the compound key (given by the string) from the store. This is just a helper
not intended for outside use.
Virtual:
No.
Arguments:
pSceStore - the store
pszSectionName - section name
pszCompKey - the string version of the compound key to be removed from store
Return Value:
Will return the cookie for the compound key. INVALID_COOKIE indicate some failure to
remove the compound key from the store.
Notes:
(1) No thread safety. Caller must be aware.
*/
DWORD CExtClassInstCookieList::RemoveCompKey (
IN CSceStore * pSceStore,
IN LPCWSTR pszSectionName,
IN LPCWSTR pszCompKey
)
{
if (pszCompKey == NULL || *pszCompKey == L'\0')
{
return INVALID_COOKIE;
}
//
// We really need a CCompoundKey object
//
CCompoundKey* pKey = NULL;
HRESULT hr = CreateCompoundKeyFromString(pszCompKey, &pKey);
if (FAILED(hr))
{
return INVALID_COOKIE;
}
ExtClassCookieIterator it = m_mapCookies.find(pKey);
DWORD dwCookie = INVALID_COOKIE;
if (it != m_mapCookies.end())
{
dwCookie = (*it).second;
}
if (pSceStore && dwCookie != INVALID_COOKIE)
{
//
// found! So, we need to erase it from our map and our vector.
// make sure that we release the compound key managed by the element
// of the map and then erase it!
//
//
// if anything goes wrong with deleting from store, then we don't do it
//
if (SUCCEEDED(DeleteKeyFromStore(pSceStore, pszSectionName, dwCookie)))
{
delete (*it).first;
m_mapCookies.erase(it);
//
// remove it from the vector, too. This is expensive. Again, don't release
// the pointer of pKey inside the vector's struct element since it's taken care
// of by the map's release.
//
CookieKeyIterator itCookieKey = m_vecCookies.begin();
while (itCookieKey != m_vecCookies.end() && (*itCookieKey)->dwCookie != dwCookie)
{
++itCookieKey;
}
if (itCookieKey != m_vecCookies.end())
{
delete (*itCookieKey);
m_vecCookies.erase(itCookieKey);
}
}
}
return dwCookie;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::Next
Functionality:
Enumeration
Virtual:
No.
Arguments:
pbstrCompoundKey - the string version of the compound key the enumeration finds. May be NULL.
pdwCookie - the cookie where the enumeration find. May be NULL.
pdwResumeHandle - hint for next enumeration (0 when start enumeration)
Return Value:
Success: WBEM_E_NO_ERROR
Failure: WBEM_S_NO_MORE_DATA if the enueration has reached the end
WBEM_E_INVALID_PARAMETER if pdwResumeHandle == NULL
Other errors may also occur.
Notes:
(1) No thread safety. Caller must be aware.
(2) Pass in 0 to start the first enuemration step
(3) If caller is only interested in the cookie, then pass pbstrCompoundKey == NULL
(4) Similarly, if the caller is only interested in the string version of the compounp key,
then pass pdwCookie.
*/
HRESULT
CExtClassInstCookieList::Next (
OUT BSTR * pbstrCompoundKey,
OUT DWORD * pdwCookie,
IN OUT DWORD * pdwResumeHandle
)
{
if (pdwResumeHandle == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
HRESULT hr = WBEM_NO_ERROR;
//
// set some good default values
//
if (pbstrCompoundKey)
{
*pbstrCompoundKey = NULL;
}
if (pdwCookie)
{
*pdwCookie = INVALID_COOKIE;
}
if (*pdwResumeHandle >= m_vecCookies.size())
{
hr = WBEM_S_NO_MORE_DATA;
}
else
{
if (pbstrCompoundKey)
{
hr = CreateCompoundKeyString(pbstrCompoundKey, m_vecCookies[*pdwResumeHandle]->pKey);
}
if (pdwCookie)
{
*pdwCookie = m_vecCookies[*pdwResumeHandle]->dwCookie;
}
(*pdwResumeHandle)++;
}
return hr;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::GetNextFreeCookie
Functionality:
A private helper to deal with cookie value overflow problem. Will search for
a unused slot for the next cookie.
Virtual:
No.
Arguments:
pdwCookie - will pass back the next available cookie
Return Value:
Success: WBEM_E_NO_ERROR
Failure: WBEM_E_OUT_OF_MEMORY or WBEM_E_INVALID_PARAMETER
Notes:
(1) No thread safety. Caller must be aware.
(2) ***Warning*** Don't use it directly!
*/
HRESULT
CExtClassInstCookieList::GetNextFreeCookie (
OUT DWORD * pdwCookie
)
{
if (pdwCookie == NULL)
{
return WBEM_E_INVALID_PARAMETER;
}
ExtClassCookieIterator it = m_mapCookies.begin();
ExtClassCookieIterator itEnd = m_mapCookies.end();
int iCount = m_mapCookies.size();
//
// remember pigeon hole principle? iCount + 1 holes will definitely have one
// that is not occupied! So, we will find one in the first iCount + 1 indexes (1 -> iCount + 1)
//
//
// since we don't want 0, we will waste the first index
// for easy readability, I opt to wait this bit memory
//
BYTE *pdwUsedCookies = new BYTE[iCount + 2];
if (pdwUsedCookies == NULL)
{
return WBEM_E_OUT_OF_MEMORY;
}
//
// set all slots unused!
//
::memset(pdwUsedCookies, 0, iCount + 2);
while(it != itEnd)
{
if ((*it).second <= iCount + 1)
{
pdwUsedCookies[(*it).second] = 1;
}
it++;
}
//
// look for holes from 1 --> iCount + 1
//
for (int i = 1; i <= iCount + 1; ++i)
{
if (pdwUsedCookies[i] == 0)
break;
}
delete [] pdwUsedCookies;
*pdwCookie = i;
return WBEM_NO_ERROR;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::CreateCompoundKeyFromString
Functionality:
A private helper to deal with cookie value overflow problem. Will search for
a unused slot for the next cookie.
Virtual:
No.
Arguments:
pszCompKeyStr - string version of the compound key
ppCompKey - out-bound compound key if the string can be successfully interpreted as
compound key
Return Value:
Success: Any success code (use SUCCEEDED(hr) to test) indicates success.
Failure: any failure code indicates failure.
Notes:
(1) No thread safety. Caller must be aware.
(2) As normal, caller is responsible to release *ppCompKey.
*/
HRESULT
CExtClassInstCookieList::CreateCompoundKeyFromString (
IN LPCWSTR pszCompKeyStr,
OUT CCompoundKey ** ppCompKey
)
{
if (ppCompKey == NULL || pszCompKeyStr == NULL || *pszCompKeyStr == L'\0')
{
return WBEM_E_INVALID_PARAMETER;
}
*ppCompKey = NULL;
HRESULT hr = WBEM_NO_ERROR;
//
// deal with NULL_KEY
//
bool bIsNullKey = _wcsicmp(pszCompKeyStr, pszNullKey) == 0;
if (bIsNullKey)
{
//
// CCompoundKey(0) creates a null key
//
*ppCompKey = new CCompoundKey(0);
if (*ppCompKey == NULL)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
return hr;
}
if (m_pVecNames == NULL || m_pVecNames->size() == 0)
{
//
// in this case, you really have to pass in pszCompKeyStr as NULL_KEY.
//
return WBEM_E_INVALID_SYNTAX;
}
DWORD dwKeyPropCount = m_pVecNames->size();
*ppCompKey = new CCompoundKey(dwKeyPropCount);
if (*ppCompKey == NULL)
{
return WBEM_E_OUT_OF_MEMORY;
}
//
// ready to parse the string version of the compound key
//
//
// hold the key property name
//
LPWSTR pszName = NULL;
//
// hold the key property value
//
VARIANT* pVar = NULL;
//
// current parsing point
//
LPCWSTR pszCur = pszCompKeyStr;
//
// next token point
//
LPCWSTR pszNext;
pVar = new VARIANT;
if (pVar == NULL)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
else
{
hr = ::ParseCompoundKeyString(pszCur, &pszName, pVar, &pszNext);
while (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
{
//
// find the index to which the name occupies. Since the number of key properties
// are always relatively small, we opt not to use fancy algorithms for lookup
//
for (DWORD dwIndex = 0; dwIndex < dwKeyPropCount; dwIndex++)
{
if (_wcsicmp((*m_pVecNames)[dwIndex], pszName) == 0)
{
break;
}
}
//
// dwIndex >= dwKeyPropCount indicates that the name is not recognized!
//
//
// since we don't care about the names anymore, release it here
//
delete [] pszName;
pszName = NULL;
//
// a valid name, add it to the compound key, it takes the ownership of the variant memory
//
if (dwIndex < dwKeyPropCount)
{
//
// if successfully added, pVar will be set to NULL by the function
//
hr = (*ppCompKey)->AddKeyPropertyValue(dwIndex, &pVar);
}
else
{
//
// not recognized name, discard the variant, won't consider as an error
//
::VariantClear(pVar);
delete pVar;
pVar = NULL;
}
//
// start our next around
//
if (SUCCEEDED(hr))
{
pVar = new VARIANT;
if (pVar == NULL)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
if (SUCCEEDED(hr))
{
pszCur = pszNext;
hr = ::ParseCompoundKeyString(pszCur, &pszName, pVar, &pszNext);
}
}
//
// final cleanup, regarless of success
//
if (pVar)
{
::VariantClear(pVar);
delete pVar;
}
}
//
// if error occurs, clean up our partially created compound key
//
if (FAILED(hr) && *ppCompKey != NULL)
{
delete *ppCompKey;
*ppCompKey = NULL;
}
return hr;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::CreateCompoundKeyString
Functionality:
Given a compound key, the function creates a string version of the compound key
and pass it back to the caller.
Virtual:
No.
Arguments:
pszCompKeyStr - string version of the compound key
ppCompKey - out-bound compound key if the string can be successfully interpreted as
compound key
Return Value:
Success: Any success code (use SUCCEEDED(hr) to test) indicates success.
Failure: any failure code indicates failure.
Notes:
(1) No thread safety. Caller must be aware.
(2) As normal, caller is responsible to release *pbstrCompKey.
*/
HRESULT
CExtClassInstCookieList::CreateCompoundKeyString (
OUT BSTR* pbstrCompKey,
IN const CCompoundKey* pKey
)
{
HRESULT hr = WBEM_NO_ERROR;
if (pbstrCompKey == NULL)
{
hr = WBEM_E_INVALID_PARAMETER;
}
//
// if no names, or 0 names, or no compound key, then return Null_Key
//
else if (m_pVecNames == NULL || m_pVecNames->size() == 0 || pKey == NULL)
{
*pbstrCompKey = ::SysAllocString(pszNullKey);
if (*pbstrCompKey == NULL)
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
else
{
*pbstrCompKey = NULL;
DWORD dwCount = m_pVecNames->size();
//
// Somehow, CComBSTR's += operator doesn't work inside loops for several
// compilations!
//
CComBSTR *pbstrParts = new CComBSTR[dwCount];
if (pbstrParts == NULL)
{
return WBEM_E_OUT_OF_MEMORY;
}
DWORD dwTotalLen = 0;
//
// for each key property, we will format the (prop, value) pair
// into prop<vt:value> format. All each individual prop<vt:value>
// will be saved in our arrary for later assembling.
//
for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++)
{
//
// don't move these CComXXX out of the loop unless you know precisely
// what needs to be done for these ATL classes
//
CComVariant var;
hr = pKey->GetPropertyValue(dwIndex, &var);
if (FAILED(hr))
{
break;
}
CComBSTR bstrData;
//
// get the <vt:value> into bstrData
//
hr = ::FormatVariant(&var, &bstrData);
if (SUCCEEDED(hr))
{
//
// create the Name<vt:Value> formatted string
//
pbstrParts[dwIndex] = CComBSTR( (*m_pVecNames)[dwIndex] );
pbstrParts[dwIndex] += bstrData;
}
else
{
break;
}
dwTotalLen += wcslen(pbstrParts[dwIndex]);
}
//
// Do the final assembling - pack all the bstr's in pbstrParts into the
// out-bound parameter *pbstrCompKey
//
if (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
{
*pbstrCompKey = ::SysAllocStringLen(NULL, dwTotalLen + 1);
if (*pbstrCompKey != NULL)
{
//
// current copying point
//
LPWSTR pszCur = *pbstrCompKey;
DWORD dwLen;
for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
{
dwLen = wcslen(pbstrParts[dwIndex]);
::memcpy(pszCur, (const void*)(LPCWSTR)(pbstrParts[dwIndex]), dwLen * sizeof(WCHAR));
pszCur += dwLen;
}
//
// 0 terminate it
//
(*pbstrCompKey)[dwTotalLen] = L'\0';
}
else
{
hr = WBEM_E_OUT_OF_MEMORY;
}
}
delete [] pbstrParts;
}
return hr;
}
/*
Routine Description:
Name:
CExtClassInstCookieList::Cleanup
Functionality:
Cleanup.
Virtual:
No.
Arguments:
none
Return Value:
none
Notes:
Since we want to clean up after some partial construction.
*/
void
CExtClassInstCookieList::Cleanup ()
{
//
// all those heap CCompoundKey's are released here.
//
ExtClassCookieIterator it = m_mapCookies.begin();
ExtClassCookieIterator itEnd = m_mapCookies.end();
while(it != itEnd)
{
delete (*it).first;
it++;
}
m_mapCookies.clear();
//
// m_vecCookies's content (CookieKeyPair) has a compound key,
// but that memory is not managed by this vector, (released in the map cleanup above).
//
for (int i = 0; i < m_vecCookies.size(); i++)
{
delete m_vecCookies[i];
}
m_vecCookies.clear();
m_dwMaxCookie = 0;
m_dwCookieArrayCount = 0;
}