mirror of https://github.com/tongzx/nt5src
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.
854 lines
19 KiB
854 lines
19 KiB
/*++
|
|
|
|
Copyright (C) 2000-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Cache.h
|
|
|
|
Abstract:
|
|
|
|
Contains all caching classes and objects.
|
|
|
|
History:
|
|
|
|
a-dcrews 01-Mar-00 Created
|
|
|
|
ivanbrug 23-Jun-2000 mostly rewritten
|
|
|
|
--*/
|
|
|
|
#ifndef _CACHE_H_
|
|
#define _CACHE_H_
|
|
|
|
#include <windows.h>
|
|
#include <wbemcli.h>
|
|
#include <wbemint.h>
|
|
#include <wstlallc.h>
|
|
|
|
#include "RawCooker.h"
|
|
#include "CookerUtils.h"
|
|
#include "DynArray.h"
|
|
|
|
#include <wstring.h>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <functional>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Macro Definitions
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define WMI_COOKER_CACHE_INCREMENT 8 // The cache size adjustment increment
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CProperty
|
|
// =========
|
|
//
|
|
// The base property - used for raw properties and the base
|
|
// class for the CookedProperty.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CProperty
|
|
{
|
|
protected:
|
|
LPWSTR m_wszName; // The property name
|
|
long m_lPropHandle; // The property handle
|
|
CIMTYPE m_ct;
|
|
|
|
public:
|
|
CProperty( LPWSTR wszName, long lHandle, CIMTYPE ct );
|
|
~CProperty();
|
|
|
|
LPWSTR GetName();
|
|
CIMTYPE GetType();
|
|
long GetHandle();
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCookingProperty
|
|
// ================
|
|
//
|
|
// The cooked property - used to model the data required to
|
|
// cook a property of a cooekd class
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CCookingProperty : public CProperty
|
|
{
|
|
DWORD m_dwCounterType; // Counter type
|
|
DWORD m_dwReqProp; // which property are needed to perform calculation
|
|
CRawCooker m_Cooker; // The cooker object
|
|
|
|
CProperty* m_pRawCounterProp; // The raw counter property
|
|
CProperty* m_pTimeProp; // The raw time property
|
|
CProperty* m_pFrequencyProp; // The raw frequency property
|
|
|
|
CProperty* m_pBaseProp; // The raw base property OPTIONAL for most counters
|
|
|
|
__int32 m_nSampleWindow; // The number of samples used for the computation
|
|
__int32 m_nTimeWindow; // The period used for the samples
|
|
|
|
unsigned __int64 m_nTimeFreq; // The timer frequency;
|
|
long m_lScale; // The Scale factor (10 ^ (m_lScale))
|
|
BOOL m_bUseWellKnownIfNeeded;
|
|
|
|
public:
|
|
CCookingProperty( LPWSTR wszName,
|
|
DWORD dwCounterType,
|
|
long lPropHandle,
|
|
CIMTYPE ct,
|
|
DWORD dwReqProp,
|
|
BOOL bUseWellKnownIfNeeded);
|
|
virtual ~CCookingProperty();
|
|
|
|
WMISTATUS Initialize( IWbemQualifierSet* pCookingPropQualifierSet,
|
|
IWbemObjectAccess* pRawAccess,
|
|
IWbemQualifierSet* pCookingClassQSet);
|
|
|
|
WMISTATUS Cook( DWORD dwNumSamples,
|
|
__int64* aRawCounter,
|
|
__int64* aBaseCounter,
|
|
__int64* aTimeStamp,
|
|
__int64* pnResult );
|
|
|
|
CProperty* GetRawCounterProperty();
|
|
CProperty* GetBaseProperty();
|
|
CProperty* GetTimeProperty();
|
|
|
|
HRESULT SetFrequency(IWbemObjectAccess * pObjAcc);
|
|
unsigned __int64 GetFrequency(void);
|
|
BOOL IsReq(DWORD ReqProp) { return (m_dwReqProp&ReqProp); };
|
|
|
|
DWORD NumberOfActiveSamples() { return m_nSampleWindow; };
|
|
DWORD MinSamplesRequired() { return m_nSampleWindow; };
|
|
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CPropertySampleCache
|
|
// ====================
|
|
//
|
|
// For every property in each instance, we must maintain a history of
|
|
// previous samples for the cooking. The type of cooking determines the
|
|
// number of required samples
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CPropertySampleCache
|
|
{
|
|
DWORD m_dwNumSamples; // The number of current samples
|
|
DWORD m_dwTotSamples; // The size of the sample array
|
|
DWORD m_dwRefreshID;
|
|
|
|
__int64* m_aRawCounterVals; // The array of raw counter values
|
|
__int64* m_aBaseCounterVals; // The array of base counter values
|
|
__int64* m_aTimeStampVals; // The array of timestamp values
|
|
|
|
public:
|
|
CPropertySampleCache();
|
|
~CPropertySampleCache();
|
|
|
|
WMISTATUS SetSampleInfo( DWORD dwNumActiveSamples, DWORD dwMinReqSamples );
|
|
WMISTATUS SetSampleData( DWORD dwRefreshID, __int64 nRawCounter, __int64 nRawBase, __int64 nTimeStamp );
|
|
WMISTATUS GetData( DWORD* pdwNumSamples, __int64** paRawCounter, __int64** paBaseCounter, __int64** paTimeStamp );
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCookingInstance
|
|
// ================
|
|
//
|
|
// The cooking instance - used to model an instance of a cooked object. Each
|
|
// property maintains a cache of values that will be used to compute the
|
|
// final cooked value.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CCookingInstance
|
|
{
|
|
LPWSTR m_wszKey; // The instance key
|
|
|
|
IWbemObjectAccess* m_pCookingInstance; // Cooking instance data
|
|
IWbemObjectAccess* m_pRawInstance; // Raw sample source
|
|
|
|
CPropertySampleCache* m_aPropertySamples; // The cache of property samples for this instance
|
|
DWORD m_dwNumProps;
|
|
|
|
public:
|
|
CCookingInstance( IWbemObjectAccess *pCookingInstance, DWORD dwNumProps );
|
|
virtual ~CCookingInstance();
|
|
|
|
WMISTATUS InitProperty( DWORD dwProp, DWORD dwNumActiveSamples, DWORD dwMinReqSamples );
|
|
|
|
WMISTATUS SetRawSourceInstance( IWbemObjectAccess* pRawSampleSource );
|
|
WMISTATUS GetRawSourceInstance( IWbemObjectAccess** ppRawSampleSource );
|
|
|
|
WMISTATUS AddSample( DWORD dwRefresherInc, DWORD dwProp, __int64 nRawCounter, __int64 nRawBase, __int64 nTimeStamp );
|
|
|
|
WMISTATUS GetCachedSamples( IWbemObjectAccess** ppOldSample, IWbemObjectAccess** ppNewSample );
|
|
IWbemObjectAccess* GetInstance();
|
|
|
|
WMISTATUS UpdateSamples();
|
|
WMISTATUS CookProperty( DWORD dwProp, CCookingProperty* pProperty );
|
|
|
|
LPWSTR GetKey() { return m_wszKey; }
|
|
WMISTATUS Refresh( IWbemObjectAccess* pRawData, IWbemObjectAccess** ppCookedData );
|
|
|
|
BOOL IsValid() {
|
|
return (m_dwNumProps && m_aPropertySamples);
|
|
};
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CRecord
|
|
// =======
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class T>
|
|
class CRecord
|
|
{
|
|
static long m_lRefIDGen; // The ID generator
|
|
long m_lID; // Instance ID
|
|
CRecord* m_pNext; // The next pointer in the list
|
|
|
|
public:
|
|
CRecord() : m_lID( m_lRefIDGen++ ), m_pNext( NULL ) {}
|
|
virtual ~CRecord() {}
|
|
|
|
void SetNext( CRecord* pRecord ) { m_pNext = pRecord; }
|
|
void SetID( long lID ) { m_lID = lID; }
|
|
|
|
CRecord* GetNext() { return m_pNext; }
|
|
long GetID() { return m_lID; }
|
|
|
|
virtual T* GetData() = 0;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CUnkRecord
|
|
// ==========
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class T>
|
|
class CUnkRecord : public CRecord<T>
|
|
{
|
|
T* m_pUnk;
|
|
|
|
public:
|
|
CUnkRecord( T* pUnk ) : m_pUnk( pUnk ) {}
|
|
~CUnkRecord(){ if ( NULL != m_pUnk ) m_pUnk->Release(); }
|
|
|
|
T* GetData(){ if ( NULL != m_pUnk ) m_pUnk->AddRef(); return m_pUnk; }
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CObjRecord
|
|
// ==========
|
|
//
|
|
// A hidden class used by the cache to manage elements
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class T>
|
|
class CObjRecord : public CRecord<T>
|
|
{
|
|
WCHAR* m_wszKey;
|
|
T* m_pObj;
|
|
|
|
public:
|
|
CObjRecord( T* pObj, WCHAR* wszKey ) : m_pObj( pObj ), m_wszKey( NULL )
|
|
{
|
|
if ( NULL != wszKey )
|
|
{
|
|
m_wszKey = new WCHAR[ wcslen( wszKey ) + 1 ];
|
|
wcscpy( m_wszKey, wszKey );
|
|
}
|
|
}
|
|
|
|
~CObjRecord()
|
|
{
|
|
if ( NULL != m_pObj ) delete m_pObj;
|
|
if ( NULL != m_wszKey ) delete m_wszKey;
|
|
}
|
|
|
|
T* GetData(){ return m_pObj; }
|
|
|
|
bool IsValueByKey( WCHAR* wszKey )
|
|
{
|
|
return ( 0 == _wcsicmp( m_wszKey, wszKey ) );
|
|
}
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCache
|
|
// ======
|
|
//
|
|
// BT - base type
|
|
// RT - record type
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class BT, class RT>
|
|
class CCache
|
|
{
|
|
RT* m_pHead; // Head of list
|
|
RT* m_pTail; // Tail of list
|
|
RT* m_pEnumNode; // Enumerator pointer
|
|
|
|
public:
|
|
|
|
CCache();
|
|
virtual ~CCache();
|
|
|
|
WMISTATUS Add( BT* pData, WCHAR* wszKey, long* plID );
|
|
WMISTATUS Remove( long lID );
|
|
WMISTATUS RemoveAll();
|
|
|
|
WMISTATUS GetData( long lID, BT** ppData );
|
|
|
|
WMISTATUS BeginEnum();
|
|
WMISTATUS Next( BT** ppData );
|
|
WMISTATUS EndEnum();
|
|
|
|
bool FindByKey( WCHAR* wszKey, BT* pData );
|
|
};
|
|
|
|
template<class T>
|
|
long CRecord<T>::m_lRefIDGen = 0;
|
|
|
|
template<class BT, class RT>
|
|
CCache<BT,RT>::CCache() : m_pHead( NULL ), m_pTail( NULL ), m_pEnumNode( NULL )
|
|
{
|
|
}
|
|
|
|
template<class BT, class RT>
|
|
CCache<BT,RT>::~CCache()
|
|
{
|
|
RT* pNode = m_pHead;
|
|
RT* pNext = NULL;
|
|
|
|
while ( NULL != pNode )
|
|
{
|
|
pNext = (RT*)pNode->GetNext();
|
|
delete pNode;
|
|
pNode = pNext;
|
|
}
|
|
};
|
|
|
|
template<class BT, class RT>
|
|
WMISTATUS CCache<BT,RT>::Add( BT *pData, WCHAR* wszKey, long* plID )
|
|
{
|
|
WMISTATUS dwStatus = S_OK;
|
|
|
|
if ( NULL == pData )
|
|
{
|
|
dwStatus = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( SUCCEEDED( dwStatus ) )
|
|
{
|
|
RT* pNewRecord = new RT( pData, wszKey );
|
|
|
|
if ( NULL != pNewRecord )
|
|
{
|
|
if ( NULL == m_pHead )
|
|
{
|
|
m_pHead = pNewRecord;
|
|
m_pTail = pNewRecord;
|
|
}
|
|
else
|
|
{
|
|
m_pTail->SetNext( pNewRecord );
|
|
m_pTail = pNewRecord;
|
|
}
|
|
|
|
*plID = pNewRecord->GetID();
|
|
}
|
|
else
|
|
{
|
|
dwStatus = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
return dwStatus;
|
|
};
|
|
|
|
template<class BT, class RT>
|
|
WMISTATUS CCache<BT,RT>::Remove( long lID )
|
|
{
|
|
WMISTATUS dwStatus = S_FALSE;
|
|
|
|
RT* pNode = m_pHead;
|
|
RT* pNext = (RT*)pNode->GetNext();
|
|
RT* pPrev = NULL;
|
|
|
|
while ( NULL != pNode )
|
|
{
|
|
if ( pNode->GetID() == lID )
|
|
{
|
|
if ( NULL == pNext )
|
|
m_pTail = pPrev;
|
|
|
|
if ( NULL == pPrev )
|
|
m_pHead = pNext;
|
|
else
|
|
pPrev->SetNext( pNext );
|
|
|
|
delete pNode;
|
|
|
|
dwStatus = S_OK;
|
|
}
|
|
|
|
pPrev = pNode;
|
|
pNode = pNext;
|
|
|
|
if ( NULL != pNode )
|
|
pNext = (RT*)pNode->GetNext();
|
|
}
|
|
|
|
return dwStatus;
|
|
};
|
|
|
|
template<class BT, class RT>
|
|
WMISTATUS CCache<BT,RT>::RemoveAll()
|
|
{
|
|
WMISTATUS dwStatus = S_FALSE;
|
|
|
|
RT* pNode = m_pHead;
|
|
RT* pNext = NULL;
|
|
|
|
while ( NULL != pNode )
|
|
{
|
|
pNext = (RT*)pNode->GetNext();
|
|
delete pNode;
|
|
pNode = pNext;
|
|
}
|
|
|
|
m_pHead = m_pTail = NULL;
|
|
|
|
return dwStatus;
|
|
};
|
|
|
|
template<class BT, class RT>
|
|
WMISTATUS CCache<BT,RT>::GetData( long lID, BT** ppData )
|
|
{
|
|
WMISTATUS dwStatus = S_FALSE;
|
|
|
|
RT* pNode = m_pHead;
|
|
|
|
while ( NULL != pNode )
|
|
{
|
|
if ( pNode->GetID() == lID )
|
|
{
|
|
*ppData = pNode->GetData();
|
|
dwStatus = S_OK;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pNode = (RT*)pNode->GetNext();
|
|
}
|
|
}
|
|
|
|
return dwStatus;
|
|
|
|
};
|
|
|
|
template<class BT, class RT>
|
|
WMISTATUS CCache<BT,RT>::BeginEnum()
|
|
{
|
|
WMISTATUS dwStatus = S_OK;
|
|
|
|
m_pEnumNode = m_pHead;
|
|
|
|
return dwStatus;
|
|
};
|
|
|
|
template<class BT, class RT>
|
|
WMISTATUS CCache<BT,RT>::Next( BT** ppData )
|
|
{
|
|
WMISTATUS dwStatus = WBEM_S_FALSE;
|
|
|
|
if ( NULL != m_pEnumNode )
|
|
{
|
|
*ppData = m_pEnumNode->GetData();
|
|
m_pEnumNode = (RT*)m_pEnumNode->GetNext();
|
|
dwStatus = S_OK;
|
|
}
|
|
|
|
return dwStatus;
|
|
};
|
|
|
|
template<class BT, class RT>
|
|
WMISTATUS CCache<BT,RT>::EndEnum()
|
|
{
|
|
WMISTATUS dwStatus = S_OK;
|
|
|
|
m_pEnumNode = NULL;
|
|
|
|
return dwStatus;
|
|
};
|
|
|
|
template<class BT, class RT>
|
|
bool CCache<BT,RT>::FindByKey( WCHAR* wszKey, BT* pData )
|
|
{
|
|
BT Data;
|
|
bool bRet = FALSE;
|
|
|
|
BeginEnum();
|
|
|
|
while( WBEM_S_FALSE != Next( &Data ) )
|
|
{
|
|
if ( pData->IsValueByKey( wszKey ) )
|
|
{
|
|
*pData = Data;
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
EndEnum();
|
|
|
|
return bRet;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// CInstanceCache
|
|
// ==============
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class CInstanceCache : public CCache<CCookingInstance,CObjRecord<CCookingInstance> >
|
|
{
|
|
public:
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// CEnumInstanceRecord
|
|
// ===================
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
class CInstanceRecord
|
|
{
|
|
long m_lID;
|
|
LPWSTR m_wszName;
|
|
|
|
public:
|
|
CInstanceRecord( LPWSTR wszName, long lID );
|
|
virtual ~CInstanceRecord();
|
|
|
|
long GetID(){ return m_lID; }
|
|
LPWSTR GetKey(){ return m_wszName; }
|
|
};
|
|
|
|
|
|
//
|
|
// used to add/remove an instance from the coooker
|
|
// and from the fastprox enumerator
|
|
//
|
|
|
|
typedef struct tagEnumCookId {
|
|
long CookId;
|
|
long EnumId;
|
|
} EnumCookId;
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// CEnumeratorManager
|
|
// ==================
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
class CWMISimpleObjectCooker;
|
|
|
|
class BstrAlloc : public wbem_allocator<WString>
|
|
{
|
|
};
|
|
|
|
class CEnumeratorManager
|
|
// Manages a single enumerator
|
|
{
|
|
DWORD m_dwSignature;
|
|
LONG m_cRef;
|
|
HRESULT m_InithRes;
|
|
CRITICAL_SECTION m_cs;
|
|
|
|
CWMISimpleObjectCooker* m_pCooker; // The class' cooker
|
|
long m_lRawID; // RawID
|
|
IWbemHiPerfEnum* m_pRawEnum; // The hiperf cooked enumerator
|
|
IWbemHiPerfEnum* m_pCookedEnum; // The hiperf cooked enumerator
|
|
|
|
IWbemClassObject* m_pCookedClass; // The class definition for the cooking class
|
|
|
|
std::vector<WString,BstrAlloc> m_pKeyProps;
|
|
WCHAR* m_wszCookingClassName;
|
|
BOOL m_IsSingleton;
|
|
|
|
// to keep track of the differences
|
|
// between the raw enum and our enum
|
|
DWORD m_dwUsage;
|
|
std::map< ULONG_PTR , EnumCookId , std::less<ULONG_PTR> ,wbem_allocator<EnumCookId> > m_mapID;
|
|
std::vector< ULONG_PTR , wbem_allocator<ULONG_PTR> > m_Delta[2];
|
|
DWORD m_dwVector;
|
|
|
|
// members
|
|
WMISTATUS Initialize( IWbemClassObject* pRawClass );
|
|
|
|
WMISTATUS CreateCookingObject( IWbemObjectAccess* pRawObject, IWbemObjectAccess** ppCookedObject );
|
|
|
|
WMISTATUS InsertCookingRecord( IWbemObjectAccess* pRawObject, EnumCookId * pStruct, DWORD dwRefreshStamp );
|
|
|
|
WMISTATUS RemoveCookingRecord( EnumCookId * pEnumCookId );
|
|
|
|
WMISTATUS GetRawEnumObjects( std::vector<IWbemObjectAccess*, wbem_allocator<IWbemObjectAccess*> > & refArray,
|
|
std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > & refObjHashKeys);
|
|
|
|
WMISTATUS SortRawArray(std::vector<IWbemObjectAccess*, wbem_allocator<IWbemObjectAccess*> > & refArray );
|
|
|
|
WMISTATUS UpdateEnums(std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > & apObjAccess);
|
|
|
|
public:
|
|
CEnumeratorManager( LPCWSTR wszCookingClass, IWbemClassObject* pCookedClass, IWbemClassObject* pRawClass, IWbemHiPerfEnum* pCookedEnum, IWbemHiPerfEnum* pRawEnum, long lRawID );
|
|
virtual ~CEnumeratorManager();
|
|
|
|
HRESULT GetInithResult(){ return m_InithRes; };
|
|
|
|
WMISTATUS Refresh( DWORD dwRefreshStamp );
|
|
long GetRawId(void){ return m_lRawID; };
|
|
LONG AddRef();
|
|
LONG Release();
|
|
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// CEnumeratorCache
|
|
// ================
|
|
//
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
class CEnumeratorCache
|
|
{
|
|
DWORD m_dwRefreshStamp; // The refresh counter
|
|
DWORD m_dwEnum; // The enumerator index
|
|
|
|
std::vector<CEnumeratorManager*, wbem_allocator<CEnumeratorManager*> > m_apEnumerators;
|
|
CRITICAL_SECTION m_cs;
|
|
|
|
WMISTATUS Initialize();
|
|
|
|
public:
|
|
CEnumeratorCache();
|
|
virtual ~CEnumeratorCache();
|
|
|
|
WMISTATUS AddEnum(
|
|
LPCWSTR wszCookingClass,
|
|
IWbemClassObject* pCookedClass,
|
|
IWbemClassObject* pRawClass,
|
|
IWbemHiPerfEnum* pCookedEnum,
|
|
IWbemHiPerfEnum* pRawEnum,
|
|
long lID,
|
|
DWORD* pdwID );
|
|
|
|
WMISTATUS RemoveEnum( DWORD dwID , long * pRawId);
|
|
|
|
WMISTATUS Refresh(DWORD dwRefreshStamp);
|
|
};
|
|
|
|
//
|
|
// Simple Cache based on the std::map
|
|
// It will use the ID semantics:
|
|
// Insertion will return an ID that need to be
|
|
// used for deletion
|
|
// ids are unique for the lifetime of the Cache object
|
|
//
|
|
|
|
template <class T>
|
|
class IdCache {
|
|
|
|
private:
|
|
|
|
std::map<DWORD, T> m_map;
|
|
DWORD m_NextId;
|
|
std::map<DWORD, T>::iterator m_it;
|
|
CRITICAL_SECTION m_cs;
|
|
|
|
public:
|
|
IdCache():m_NextId(0){
|
|
InitializeCriticalSection(&m_cs);
|
|
};
|
|
virtual ~IdCache(){
|
|
DeleteCriticalSection(&m_cs);
|
|
};
|
|
void Lock(){
|
|
EnterCriticalSection(&m_cs);
|
|
}
|
|
void Unlock(){
|
|
LeaveCriticalSection(&m_cs);
|
|
};
|
|
|
|
// traditional interfaces
|
|
HRESULT Add( DWORD * pId, T Elem);
|
|
HRESULT GetData(DWORD Id, T * pElem);
|
|
HRESULT Remove(DWORD Id, T * pRemovedElem);
|
|
|
|
// before calling this, delete the elements !!!!
|
|
HRESULT RemoveAll(void);
|
|
|
|
// Enumerator Style
|
|
HRESULT BeginEnum(void);
|
|
HRESULT Next(T * pElem);
|
|
HRESULT EndEnum(void);
|
|
};
|
|
|
|
|
|
template <class T>
|
|
HRESULT
|
|
IdCache<T>::Add( DWORD * pId, T Elem){
|
|
HRESULT hr;
|
|
Lock();
|
|
if (pId) {
|
|
|
|
std::map<DWORD, T>::iterator it = m_map.find(m_NextId);
|
|
|
|
if (it != m_map.end()) {
|
|
|
|
// should never happen
|
|
hr = E_FAIL;
|
|
|
|
} else {
|
|
|
|
m_map[m_NextId] = Elem;
|
|
*pId = m_NextId;
|
|
|
|
InterlockedIncrement((PLONG)&m_NextId);
|
|
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
} else {
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
Unlock();
|
|
return hr;
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT
|
|
IdCache<T>::GetData(DWORD Id, T * pElem){
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
Lock();
|
|
std::map<DWORD, T>::iterator it = m_map.find(Id);
|
|
|
|
if (it != m_map.end()){
|
|
|
|
*pElem = (*it).second;
|
|
|
|
} else {
|
|
hr = WBEM_E_NOT_FOUND;
|
|
}
|
|
Unlock();
|
|
return hr;
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT
|
|
IdCache<T>::Remove(DWORD Id, T * pRemovedElem){
|
|
|
|
HRESULT hr = WBEM_S_NO_ERROR;
|
|
Lock();
|
|
if (pRemovedElem) {
|
|
|
|
std::map<DWORD, T>::iterator it = m_map.find(Id);
|
|
|
|
if (it != m_map.end()) {
|
|
|
|
*pRemovedElem = (*it).second;
|
|
m_map.erase(it);
|
|
|
|
} else {
|
|
hr = WBEM_E_NOT_FOUND;
|
|
}
|
|
|
|
} else {
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
Unlock();
|
|
return hr;
|
|
|
|
}
|
|
|
|
//
|
|
// DEVDEV Empty the cache before removing from std::map
|
|
//
|
|
template <class T>
|
|
HRESULT
|
|
IdCache<T>::RemoveAll(void){
|
|
Lock();
|
|
m_map.erase(m_map.begin(),m_map.end());
|
|
Unlock();
|
|
return WBEM_S_NO_ERROR;
|
|
};
|
|
|
|
//
|
|
// DEVDEV Consider using Lock if no exception ....
|
|
//
|
|
template <class T>
|
|
HRESULT
|
|
IdCache<T>::BeginEnum(void){
|
|
Lock();
|
|
m_it = m_map.begin();
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT
|
|
IdCache<T>::Next(T * pElem){
|
|
HRESULT hr;
|
|
|
|
if (pElem){
|
|
if (m_it == m_map.end()){
|
|
hr = WBEM_S_NO_MORE_DATA;
|
|
} else {
|
|
* pElem = (*m_it).second;
|
|
++m_it;
|
|
hr = WBEM_S_NO_ERROR;
|
|
}
|
|
} else {
|
|
hr = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT
|
|
IdCache<T>::EndEnum(void){
|
|
Unlock();
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
#endif //_CACHE_H_
|