Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

313 lines
9.6 KiB

// compkey.h: interface for the CCompoundKey class
// Copyright (c)1997-2001 Microsoft Corporation
//
//////////////////////////////////////////////////////////////////////
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
/*
Class description
Naming:
CCompoundKey stands for a key that is compounded by many properties.
Base class:
None. This is not a class that implements a WMI class.
It is not derived from CGenericClass.
Purpose of class:
(1) Comparing two instances of the same WMI class is not an easy job because
most of time we need to look up an instance based on its key. Ideally, if
WMI provides some canonical name, it will be very easy. The closest thing
WMI gives us regarding the identify of instance is the instance path.
But WMI gives inconsistent paths for the same instance. At least, we've
found that if a boolean property is part of the key, then sometimes WMI
gives its path containing a string portion like "BoolPropName=1" and other
times (for the same instance) it gives "BoolPropName=TRUE". For this reason,
we are forced to create a robust identify lookup mechanism.
(2) This class serves two purposes:
(a) the key for our map of instance lookup. Potentially, we may have tens of
thousands of instances (like random ports). We need an efficient way to
find an instance.
(b) provide access (GetPropertyValue) for key properties of an instance.
(3) This is part of the effort to implement another open extension model (embedding)
Design:
(1) We only store the key property's values (m_pValues). In other words, we rely
on user to know the order properties are put into the class. The reasons for
this design are:
(a) Efficiency.
(b) Don't want to store the property names because one class only needs one
copy of the property names.
(c) For each embedded class, we already have to find out all its key property names.
Use:
(1) Create an instance. Our constructor strictly requires the count for key properties
at construction time. This is because you have to know each class (and their key
property names, even the names particular order) at this point.
(2) Call AddKeyPropertyValue to add a property value. Please note: for efficiency reasons,
the variant pointer passed into the call is owned by this class (so that no copy needs
to be made).
(3) most likely, you will add this newly created instance to a map.
*/
class CCompoundKey
{
public:
CCompoundKey(DWORD dwSize);
~CCompoundKey();
HRESULT AddKeyPropertyValue (DWORD dwIndex, VARIANT** ppVar);
bool operator < (const CCompoundKey& right)const;
HRESULT GetPropertyValue (DWORD dwIndex, VARIANT* pVar)const;
protected:
int CompareVariant (VARIANT* pVar1, VARIANT* pVar2)const;
VARIANT** m_pValues;
DWORD m_dwSize;
};
//=========================================================================
/*
Class description
Naming:
CompKeyLessThan.
Base class:
None.
Purpose of class:
(1) This is the functor for our map that uses CCompoundKey as key.
Design:
(1) Just one operator ()
Use:
(1) Give it to the map's comparison parameter.
*/
struct CompKeyLessThan
{
bool operator()( const CCompoundKey* pX, const CCompoundKey* pY ) const;
};
//=========================================================================
//
// declarations for the ease of use for maps using CCompoundKey
//
typedef std::map<CCompoundKey*, DWORD, CompKeyLessThan > MapExtClassCookie;
typedef MapExtClassCookie::iterator ExtClassCookieIterator;
//=========================================================================
//
// forward declaration for the use in CExtClassInstCookieList
//
class CSceStore;
//=========================================================================
/*
Class description
Naming:
CExtClassInstCookieList.
Base class:
None.
Purpose of class:
(1) To support multiple instance persistence, we need a mechanism to tell
instances apart in the persistence store. Due to the limitations of INF
format file API, this is not an easy job. All instances of a particular
class must be written into one section of the INF file. We have absolutely
no control as what order the key=value pair will be written. To make things
worse, the key in the key=value pair is not allowed to repeat. In other
words, if we don't know anything, we can only persist one single instance.
To solve this problem, we invent the notation of cookies for instances.
For each class (and thus a section bearing the class's name), we have
cookie arrays in the following form (the numbers are cookies):
A1 = 12 : 2 : 3 : 6 :
A2 = 1 : 5 : 8 : 10 : 24 : 112233 : 7 :
For a particular instance, it is associated with a cookie. In order for us
to persist or read an instance's properties, we must obtain the cookie, say, 5.
Then all key properties of this instance is saved in the value of
K5 = value
and all non-key properties are all saved in
5PropertyName = value
Design:
(1) Instancce lookup (given a compound key CCompoundKey to find its cookie) must
efficient. So, a map is used (m_mapCookies).
(2) We want to control the order an instance is used. Map doesn't work well in this
case. So, we create a vector (m_vecCookies) to link cookies back to its compound key.
This way when the access starts, we can traverse the vector using index.
(3) We don't want to blindly continue to look for cookie arrays (A1, A2, etc.) when we
need to create the cookie list for a particular class. And we don't want to
write one cookie array to be so long that it is very hard to read. So, we adopt
a strategy that we increment the A_i count and continue try to read A_(i+1) only
if A_i exists. But then, if instances are deleted, we will need to have less cookie
arrays. To know how many cookie arrays were read out (and potentially remove the
unwanted ones when updating the store with the new cookie list), we have m_dwCookieArrayCount.
(4) New cookie are assign by increment the current maximum cookie m_dwMaxCookie. To avoid
DWORD overflow, we also have a function (GetNextFreeCookie) to look fora newer cookie
when the 0xFFFFFFFFF is already used.
(5) We also defined a cookie called INVALID_COOKIE = 0.
Use:
(1) Instantiate an instance of the class.
(2) Call Create function to populate its contents.
(3) Ready for your use.
*/
class CExtClassInstCookieList
{
public:
CExtClassInstCookieList();
~CExtClassInstCookieList();
HRESULT Create(
CSceStore* pSceStore,
LPCWSTR pszSectionName,
std::vector<BSTR>* pvecNames
);
HRESULT Save(
CSceStore* pSceStore,
LPCWSTR pszSectionName
);
DWORD GetCompKeyCookie(
LPCWSTR pszComKey,
ExtClassCookieIterator* pIt
);
HRESULT AddCompKey(
LPCWSTR pszCompKey,
DWORD dwDefCookie,
DWORD *pdwNewCookie
);
DWORD RemoveCompKey(
CSceStore* pSceStore,
LPCWSTR pszSectionName,
LPCWSTR pszCompKey
);
HRESULT Next(
BSTR* pbstrCompoundKey,
DWORD* pdwCookie,
DWORD* pdwResumeHandle
);
//
// return the count of cookies
//
DWORD
GetCookieCount ()
{
return m_vecCookies.size();
}
private:
HRESULT DeleteKeyFromStore(
CSceStore* pSceStore,
LPCWSTR pszSectionName,
DWORD dwCookie
);
HRESULT GetNextFreeCookie(
DWORD* pdwCookie
);
HRESULT CreateCompoundKeyFromString(
LPCWSTR pszCompKeyStr,
CCompoundKey** ppCompKey
);
HRESULT CreateCompoundKeyString(
BSTR* pbstrCompKey,
const CCompoundKey* pKey
);
void Cleanup();
DWORD m_dwMaxCookie;
MapExtClassCookie m_mapCookies;
//
// memories (pKey) is not managed by this struct CookieKeyPair
// pKey is taken care of somewhere else (actually m_mapCookies does it)
//
struct CookieKeyPair
{
DWORD dwCookie;
CCompoundKey* pKey;
};
typedef std::vector<CookieKeyPair*> CookieKeyVector;
typedef CookieKeyVector::iterator CookieKeyIterator;
CookieKeyVector m_vecCookies;
std::vector<BSTR>* m_pVecNames;
DWORD m_dwCookieArrayCount;
};