/*++ Copyright (C) 2000-2001 Microsoft Corporation Module Name: Abstract: History: --*/ /////////////////////////////////////////////////////////////////////////////// // // Cache.cpp // /////////////////////////////////////////////////////////////////////////////// #include "precomp.h" #include #include #include #include #include // for CInCritSec #include #include "Cache.h" #include "WMIObjCooker.h" #include "CookerUtils.h" /////////////////////////////////////////////////////////////////////////////// // // CProperty // ========= // // The base property - used for raw properties and the base // class for the CookedProperty. // /////////////////////////////////////////////////////////////////////////////// CProperty::CProperty(LPWSTR wszName, long lHandle, CIMTYPE ct ) : #ifdef _VERBOSE m_wszName( NULL ), #endif m_lPropHandle( lHandle ), m_ct( ct ) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { #ifdef _VERBOSE size_t length = wcslen( wszName ) + 1; m_wszName = new WCHAR[ length ]; if (m_wszName) StringCchCopyW( m_wszName, length , wszName); #endif } CProperty::~CProperty() { #ifdef _VERBOSE delete [] m_wszName; #endif } #ifdef _VERBOSE LPWSTR CProperty::GetName() { return m_wszName?m_wszName:L""; } #endif CIMTYPE CProperty::GetType() { return m_ct; } long CProperty::GetHandle() { return m_lPropHandle; } /////////////////////////////////////////////////////////////////////////////// // // CCookingProperty // ================ // // The cooked property - used to model the data required to // cook a property of a cooked class // /////////////////////////////////////////////////////////////////////////////// CCookingProperty::CCookingProperty( LPWSTR wszName, DWORD dwCounterType, long lPropHandle, CIMTYPE ct, DWORD dwReqProp, BOOL bUseWellKnownIfNeeded) : CProperty( wszName, lPropHandle, ct ), m_dwCounterType( dwCounterType ), m_dwReqProp(dwReqProp), m_nTimeFreq( 0 ), m_lScale(0), // 10^0 = 1 m_pRawCounterProp( NULL ), m_pTimeProp( NULL ), m_pFrequencyProp( NULL ), m_pBaseProp( NULL ), m_nSampleWindow( 0 ), m_nTimeWindow( 0 ), m_bUseWellKnownIfNeeded(bUseWellKnownIfNeeded) /////////////////////////////////////////////////////////////////////////////// // // Constructor // // Parameters: // wszName - The property name // dwCounterType - The property's counter type // lPropHandle - The cooking property's WMI Access handle // ct - The CIM type of the property // /////////////////////////////////////////////////////////////////////////////// {} CCookingProperty::~CCookingProperty() { delete m_pRawCounterProp; delete m_pTimeProp; delete m_pFrequencyProp; delete m_pBaseProp; } // // // // Parameters: // pCookingClassAccess - The class definition for the cooking class // // Description: // For each property of the class to be cooked // we need to find the property of the Raw class needed in the formula // The 'Counter' qualifier is always needed, // but thereafter we might need the timestap, the base, the frequency, ecc, ecc // SOme of these are in the PropertyQualifierSet, but other can be defaulted in the // ClassQualifierSet // /////////////////////////////////////////////////////////////////////////////// WMISTATUS CCookingProperty::Initialize( IWbemQualifierSet* pCookingPropQualifierSet, IWbemObjectAccess* pRawAccess, IWbemQualifierSet* pCookingClassQSet) { WMISTATUS dwStatus = WBEM_NO_ERROR; _variant_t vVal; // Initialize the raw counter property ("Counter") // =============================================== dwStatus = pCookingPropQualifierSet->Get( WMI_COOKER_RAW_COUNTER, 0, &vVal, NULL ); if ( SUCCEEDED( dwStatus ) && ( vVal.vt != VT_BSTR ) ) { dwStatus = E_FAIL; } if ( SUCCEEDED( dwStatus ) ) { // Get the raw data properties // =========================== CIMTYPE ct; long lHandle = 0; WCHAR* wszRawCounterName = vVal.bstrVal; // Get the raw counter property // ============================ dwStatus = pRawAccess->GetPropertyHandle( wszRawCounterName, &ct, &lHandle ); if ( SUCCEEDED( dwStatus ) ) { m_pRawCounterProp = new CProperty( wszRawCounterName, lHandle, ct ); if ( NULL == m_pRawCounterProp ) { dwStatus = WBEM_E_OUT_OF_MEMORY; } } // Get the raw base property // ========================= if ( SUCCEEDED( dwStatus ) ) { _variant_t vProp; dwStatus = pCookingPropQualifierSet->Get( WMI_COOKER_RAW_BASE, 0, &vProp, NULL ); if ( SUCCEEDED( dwStatus ) ) { if ( vProp.vt == VT_BSTR ) { dwStatus = pRawAccess->GetPropertyHandle( vProp.bstrVal, &ct, &lHandle ); if ( SUCCEEDED( dwStatus ) ) { m_pBaseProp = new CProperty( vProp.bstrVal, lHandle, ct ); if ( NULL == m_pBaseProp ) { dwStatus = WBEM_E_OUT_OF_MEMORY; } } } else { dwStatus = WBEM_E_TYPE_MISMATCH; } } else { // the property qualifier set failed, try the class one _variant_t varProp; // does not throw, simple container dwStatus = pCookingClassQSet->Get( WMI_COOKER_RAW_BASE, 0, &varProp, NULL ); if ( SUCCEEDED( dwStatus ) ) { if ( varProp.vt == VT_BSTR ) { dwStatus = pRawAccess->GetPropertyHandle( varProp.bstrVal, &ct, &lHandle ); if ( SUCCEEDED( dwStatus ) ) { m_pBaseProp = new CProperty( varProp.bstrVal, lHandle, ct ); if ( NULL == m_pBaseProp ) { dwStatus = WBEM_E_OUT_OF_MEMORY; } } } else { dwStatus = WBEM_E_TYPE_MISMATCH; } } else { dwStatus = WBEM_NO_ERROR; } } // // no error so far, the BASE qulifier is REQUIRED, but none is found // if ( SUCCEEDED( dwStatus ) && IsReq(REQ_BASE) && (NULL == m_pBaseProp)) { dwStatus = WBEM_E_INVALID_CLASS; } } // Get the raw timestamp property record // ===================================== if ( SUCCEEDED( dwStatus ) ) { _variant_t vProp2; dwStatus = pCookingPropQualifierSet->Get( WMI_COOKER_RAW_TIME, 0, &vProp2, NULL ); if ( SUCCEEDED( dwStatus ) ) { if ( vProp2.vt == VT_BSTR ) { dwStatus = pRawAccess->GetPropertyHandle( vProp2.bstrVal, &ct, &lHandle ); if ( SUCCEEDED( dwStatus ) ) { m_pTimeProp = new CProperty( vProp2.bstrVal, lHandle, ct ); if ( NULL == m_pTimeProp ) { dwStatus = WBEM_E_OUT_OF_MEMORY; } } } else { dwStatus = WBEM_E_TYPE_MISMATCH; } } else { // the property qualifier set failed, try the class one //PERF_TIMER_TICK //PERF_TIMER_100NS //PERF_OBJECT_TIMER _variant_t varProp; // does not throw, simple container if (m_dwCounterType & PERF_OBJECT_TIMER) { dwStatus = pCookingClassQSet->Get( WMI_COOKER_RAW_TIME_OBJ, 0, &varProp, NULL ); if (FAILED(dwStatus) && m_bUseWellKnownIfNeeded) { dwStatus = WBEM_NO_ERROR; varProp = WMI_COOKER_REQ_TIMESTAMP_PERFTIME; } } else if (m_dwCounterType & PERF_TIMER_100NS) { dwStatus = pCookingClassQSet->Get( WMI_COOKER_RAW_TIME_100NS, 0, &varProp, NULL ); if (FAILED(dwStatus) && m_bUseWellKnownIfNeeded) { dwStatus = WBEM_NO_ERROR; varProp = WMI_COOKER_REQ_TIMESTAMP_SYS100NS; } } else { dwStatus = pCookingClassQSet->Get( WMI_COOKER_RAW_TIME_SYS, 0, &varProp, NULL ); if (FAILED(dwStatus) && m_bUseWellKnownIfNeeded) { dwStatus = WBEM_NO_ERROR; varProp = WMI_COOKER_REQ_TIMESTAMP_OBJECT; } } if ( SUCCEEDED( dwStatus ) ) { if ( varProp.vt == VT_BSTR ) { dwStatus = pRawAccess->GetPropertyHandle( varProp.bstrVal, &ct, &lHandle ); if ( SUCCEEDED( dwStatus ) ) { m_pTimeProp = new CProperty( varProp.bstrVal, lHandle, ct ); if ( NULL == m_pTimeProp ) { dwStatus = WBEM_E_OUT_OF_MEMORY; } } } else { dwStatus = WBEM_E_TYPE_MISMATCH; } } else { dwStatus = WBEM_NO_ERROR; } } // get in cascade the frequency property if (SUCCEEDED(dwStatus)) { _variant_t VarFreqName; // simple container, does not throw dwStatus = pCookingPropQualifierSet->Get( WMI_COOKER_RAW_FREQUENCY, 0, &VarFreqName, NULL ); if (SUCCEEDED(dwStatus)) { if (VarFreqName.vt == VT_BSTR) { dwStatus = pRawAccess->GetPropertyHandle( VarFreqName.bstrVal, &ct, &lHandle ); if (SUCCEEDED(dwStatus)) { m_pFrequencyProp = new CProperty( VarFreqName.bstrVal, lHandle, ct ); if ( NULL == m_pFrequencyProp ) { dwStatus = WBEM_E_OUT_OF_MEMORY; } } } else { dwStatus = WBEM_E_TYPE_MISMATCH; } } else { if (m_dwCounterType & PERF_OBJECT_TIMER) { dwStatus = pCookingClassQSet->Get( WMI_COOKER_RAW_FREQ_OBJ, 0, &VarFreqName, NULL ); if (FAILED(dwStatus) && m_bUseWellKnownIfNeeded) { dwStatus = WBEM_NO_ERROR; VarFreqName = WMI_COOKER_REQ_FREQUENCY_PERFTIME; } } else if (m_dwCounterType & PERF_TIMER_100NS) { dwStatus = pCookingClassQSet->Get( WMI_COOKER_RAW_FREQ_100NS, 0, &VarFreqName, NULL ); if (FAILED(dwStatus) && m_bUseWellKnownIfNeeded) { dwStatus = WBEM_NO_ERROR; VarFreqName = WMI_COOKER_REQ_FREQUENCY_SYS100NS; } } else { dwStatus = pCookingClassQSet->Get( WMI_COOKER_RAW_FREQ_SYS, 0, &VarFreqName, NULL ); if (FAILED(dwStatus) && m_bUseWellKnownIfNeeded) { dwStatus = WBEM_NO_ERROR; VarFreqName = WMI_COOKER_REQ_FREQUENCY_OBJECT; } } if (SUCCEEDED(dwStatus)) { if (VarFreqName.vt == VT_BSTR) { dwStatus = pRawAccess->GetPropertyHandle( VarFreqName.bstrVal, &ct, &lHandle ); if (SUCCEEDED(dwStatus)) { m_pFrequencyProp = new CProperty( VarFreqName.bstrVal, lHandle, ct ); if ( NULL == m_pFrequencyProp ) { dwStatus = WBEM_E_OUT_OF_MEMORY; } } } else { dwStatus = WBEM_E_TYPE_MISMATCH; } } else { dwStatus = WBEM_S_NO_ERROR; } } } } // // Get the Scale factor from ONLY the property Qualifier // if ( SUCCEEDED( dwStatus ) ) { _variant_t VarScale; // does not throw, simple container dwStatus = pCookingPropQualifierSet->Get( WMI_COOKER_SCALE_FACT, 0, &VarScale, NULL ); if ( SUCCEEDED( dwStatus ) && (V_VT(&VarScale) == VT_I4)) { m_lScale = VarScale.intVal; } else { dwStatus = WBEM_S_NO_ERROR; } } // Get the Sample and Time windows value // ===================================== if ( SUCCEEDED( dwStatus ) ) { DWORD dwSampleStatus = WBEM_NO_ERROR, dwTimeStatus = WBEM_NO_ERROR; _variant_t vSampleProp; // does not throw, simple container _variant_t vTimeProp; // does not throw, simple container dwSampleStatus = pCookingPropQualifierSet->Get( WMI_COOKER_SAMPLE_WINDOW, 0, &vSampleProp, NULL ); dwTimeStatus = pCookingPropQualifierSet->Get( WMI_COOKER_TIME_WINDOW, 0, &vTimeProp, NULL ); if ( SUCCEEDED( dwSampleStatus ) && SUCCEEDED( dwTimeStatus ) ) { dwStatus = WBEM_E_INVALID_PROPERTY; } else if ( SUCCEEDED( dwSampleStatus ) ) { if ( vSampleProp.vt != VT_I4 ) { dwStatus = E_FAIL; } else { m_nSampleWindow = vSampleProp.intVal; } } else if ( SUCCEEDED( dwTimeStatus ) ) { if ( vTimeProp.vt != VT_I4 ) dwStatus = E_FAIL; else m_nTimeWindow = vTimeProp.intVal; } else { m_nSampleWindow = WMI_DEFAULT_SAMPLE_WINDOW; } } } return dwStatus; } // // Description: the RawCooker could easily be a Singleton shared among // all the cooking properties, since it does not mantain state on behaf of the // Cooking property // /////////////////////////////////////////////////////////////////// WMISTATUS CCookingProperty::Cook( DWORD dwNumSamples, __int64* aRawCounter, __int64* aBaseCounter, __int64* aTimeStamp, __int64* pnResult ) { WMISTATUS dwStatus = WBEM_NO_ERROR; dwStatus = m_Cooker.CookRawValues( m_dwCounterType, dwNumSamples, aTimeStamp, aRawCounter, aBaseCounter, m_nTimeFreq, m_lScale, pnResult ); return dwStatus; } CProperty* CCookingProperty::GetRawCounterProperty() { return m_pRawCounterProp; } CProperty* CCookingProperty::GetBaseProperty() { return m_pBaseProp; } CProperty* CCookingProperty::GetTimeProperty() { return m_pTimeProp; } HRESULT CCookingProperty::SetFrequency(IWbemObjectAccess * pObjAcc) { if (m_nTimeFreq == 0) { // get the Frequency from the Raw Object if (m_pFrequencyProp) { __int64 lTmp; HRESULT hRes = GetPropValue(m_pFrequencyProp,pObjAcc,lTmp); if (SUCCEEDED(hRes)) m_nTimeFreq = lTmp; return hRes; } else if (!(m_dwReqProp & REQ_FREQ)) { return WBEM_NO_ERROR; } else { LARGE_INTEGER li; if (QueryPerformanceFrequency(&li)) { m_nTimeFreq = li.QuadPart; return WBEM_NO_ERROR; } else { return WBEM_E_INVALID_PARAMETER; } } } else { return WBEM_NO_ERROR; } } unsigned __int64 CCookingProperty::GetFrequency(void) { return m_nTimeFreq; } /////////////////////////////////////////////////////////////////////////////// // // CPropertySampleCache // ==================== // // This class caches the sample data for a single property for a single // instance // /////////////////////////////////////////////////////////////////////////////// CPropertySampleCache::CPropertySampleCache(): m_aRawCounterVals(NULL), m_aBaseCounterVals(NULL), m_aTimeStampVals(NULL), m_dwRefreshID(0) { } CPropertySampleCache::~CPropertySampleCache() { delete [] m_aRawCounterVals; delete [] m_aBaseCounterVals; delete [] m_aTimeStampVals; } WMISTATUS CPropertySampleCache::SetSampleInfo( DWORD dwNumActiveSamples, DWORD dwMinReqSamples ) { WMISTATUS dwStatus = WBEM_NO_ERROR; m_dwNumSamples = 0; m_dwTotSamples = dwNumActiveSamples; m_aRawCounterVals = new __int64[dwNumActiveSamples]; if (!m_aRawCounterVals) return WBEM_E_OUT_OF_MEMORY; memset( m_aRawCounterVals, 0, sizeof(__int64) * dwNumActiveSamples ); m_aBaseCounterVals = new __int64[dwNumActiveSamples]; if (!m_aBaseCounterVals) return WBEM_E_OUT_OF_MEMORY; memset( m_aBaseCounterVals, 0, sizeof(__int64) * dwNumActiveSamples ); m_aTimeStampVals = new __int64[dwNumActiveSamples]; if (!m_aTimeStampVals) return WBEM_E_OUT_OF_MEMORY; memset( m_aBaseCounterVals, 0, sizeof(__int64) * dwNumActiveSamples ); return dwStatus; } WMISTATUS CPropertySampleCache::SetSampleData( DWORD dwRefreshID, __int64 nRawCounter, __int64 nRawBase, __int64 nTimeStamp ) { WMISTATUS dwStatus = WBEM_NO_ERROR; if (dwRefreshID <= m_dwRefreshID) { return dwStatus; } else { m_dwRefreshID = dwRefreshID; } if ( m_dwNumSamples < m_dwTotSamples ) { m_dwNumSamples++; } if ( m_dwTotSamples >= 2 ) { for (LONG i = (LONG)(m_dwTotSamples-2); i>=0; i--) { m_aRawCounterVals[i+1] = m_aRawCounterVals[i]; m_aBaseCounterVals[i+1] = m_aBaseCounterVals[i]; m_aTimeStampVals[i+1] = m_aTimeStampVals[i]; } } m_aRawCounterVals[0] = nRawCounter; m_aBaseCounterVals[0] = nRawBase; m_aTimeStampVals[0] = nTimeStamp; return dwStatus; } WMISTATUS CPropertySampleCache::GetData( DWORD* pdwNumSamples, __int64** paRawCounter, __int64** paBaseCounter, __int64** paTimeStamp ) { WMISTATUS dwStatus = WBEM_NO_ERROR; *pdwNumSamples = m_dwNumSamples; *paRawCounter = m_aRawCounterVals; *paBaseCounter = m_aBaseCounterVals; *paTimeStamp = m_aTimeStampVals; return dwStatus; } /////////////////////////////////////////////////////////////////////////////// // // 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. // /////////////////////////////////////////////////////////////////////////////// CCookingInstance::CCookingInstance( IWbemObjectAccess *pCookingInstance, DWORD dwNumProps ) : m_wszKey( NULL ), m_aPropertySamples( NULL ), m_pCookingInstance( pCookingInstance ), m_pRawInstance( NULL ), m_dwNumProps( dwNumProps ) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { if ( m_pCookingInstance ) { m_pCookingInstance->AddRef(); m_wszKey = ::GetKey( m_pCookingInstance ); } if (dwNumProps) { // allocation checked in IsValid m_aPropertySamples = new CPropertySampleCache[dwNumProps]; }; } CCookingInstance::~CCookingInstance() { delete [] m_wszKey; if ( NULL != m_pCookingInstance ) { m_pCookingInstance->Release(); } delete [] m_aPropertySamples; if ( NULL != m_pRawInstance ) { m_pRawInstance->Release(); } } WMISTATUS CCookingInstance::InitProperty( DWORD dwProp, DWORD dwNumActiveSamples, DWORD dwMinReqSamples ) { return m_aPropertySamples[dwProp].SetSampleInfo( dwNumActiveSamples, dwMinReqSamples ); } WMISTATUS CCookingInstance::SetRawSourceInstance( IWbemObjectAccess* pRawSampleSource ) { WMISTATUS dwStatus = WBEM_NO_ERROR; if ( NULL != m_pRawInstance ) { m_pRawInstance->Release(); } m_pRawInstance = pRawSampleSource; if ( NULL != m_pRawInstance ) { m_pRawInstance->AddRef(); } return dwStatus; } WMISTATUS CCookingInstance::GetRawSourceInstance( IWbemObjectAccess** ppRawSampleSource ) { WMISTATUS dwStatus = WBEM_NO_ERROR; *ppRawSampleSource = m_pRawInstance; if ( NULL != m_pRawInstance ) { m_pRawInstance->AddRef(); } return dwStatus; } IWbemObjectAccess* CCookingInstance::GetInstance() { if ( NULL != m_pCookingInstance ) m_pCookingInstance->AddRef(); return m_pCookingInstance; } WMISTATUS CCookingInstance::AddSample( DWORD dwRefreshStamp, DWORD dwProp, __int64 nRawCounter, __int64 nRawBase, __int64 nTimeStamp ) { return m_aPropertySamples[dwProp].SetSampleData( dwRefreshStamp, nRawCounter, nRawBase, nTimeStamp ); } WMISTATUS CCookingInstance::Refresh( IWbemObjectAccess* pRawData, IWbemObjectAccess** ppCookedData ) { WMISTATUS dwStatus = WBEM_NO_ERROR; return dwStatus; } WMISTATUS CCookingInstance::UpdateSamples() { WMISTATUS dwStatus = WBEM_NO_ERROR; return dwStatus; } WMISTATUS CCookingInstance::CookProperty( DWORD dwProp, CCookingProperty* pProperty ) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { WMISTATUS dwStatus = WBEM_NO_ERROR; DWORD dwNumSamples = 0; __int64* aRawCounter; __int64* aBaseCounter; __int64* aTimeStamp; __int64 nResult = 0; long lHandle = pProperty->GetHandle(); dwStatus = m_aPropertySamples[dwProp].GetData( &dwNumSamples, &aRawCounter, &aBaseCounter, &aTimeStamp ); if ( SUCCEEDED( dwStatus ) ) { #ifdef _VERBOSE { unsigned __int64 Freq = pProperty->GetFrequency(); DbgPrintfA(0,"PropName %S sample %d\n" "Raw %I64d %I64d\n" "Base %I64d %I64d\n" "Time %I64d %I64d\n" "Freq %I64d\n", pProperty->GetName(),dwNumSamples, aRawCounter[0],aRawCounter[1], aBaseCounter[0],aBaseCounter[1], aTimeStamp[0],aTimeStamp[1], Freq); } #endif if (SUCCEEDED(dwStatus = pProperty->SetFrequency(m_pRawInstance))){ dwStatus = pProperty->Cook( dwNumSamples, aRawCounter, aBaseCounter, aTimeStamp, &nResult ); } #ifdef _VERBOSE DbgPrintfA(0,"Result %I64d dwStatus %08x\n",nResult,dwStatus); #endif }; if ( SUCCEEDED( dwStatus ) ) { switch ( pProperty->GetType() ) { case CIM_UINT32: dwStatus = m_pCookingInstance->WriteDWORD( lHandle, (DWORD) nResult ); break; case CIM_UINT64: dwStatus = m_pCookingInstance->WriteQWORD( lHandle, nResult ); break; default: dwStatus = WBEM_E_TYPE_MISMATCH; } }; return dwStatus; } ///////////////////////////////////////////////////////////////////////// // // // CEnumeratorCache // // ///////////////////////////////////////////////////////////////////////// CEnumeratorCache::CEnumeratorCache() : m_dwEnum( 0 ) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { } CEnumeratorCache::~CEnumeratorCache() { CInCritSec ics(&m_cs); for (DWORD i=0;iRelease(); } } WMISTATUS CEnumeratorCache::AddEnum( LPCWSTR wszCookingClass, IWbemClassObject* pCookedClass, IWbemClassObject* pRawClass, IWbemHiPerfEnum* pCookedEnum, IWbemHiPerfEnum* pRawEnum, long lIDRaw, DWORD* pdwID ) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { WMISTATUS dwStatus = WBEM_NO_ERROR; CEnumeratorManager* pEnumMgr = new CEnumeratorManager( wszCookingClass, pCookedClass, pRawClass, pCookedEnum, pRawEnum, lIDRaw ); if (NULL == pEnumMgr) return WBEM_E_OUT_OF_MEMORY; CInCritSec ics(&m_cs); if (SUCCEEDED(pEnumMgr->GetInithResult())) { DWORD i; for (i=0;iRelease(); dwStatus = WBEM_E_OUT_OF_MEMORY; } } } else { dwStatus = pEnumMgr->GetInithResult(); } return dwStatus; } WMISTATUS CEnumeratorCache::RemoveEnum( DWORD dwID , long * pRawId ) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { WMISTATUS dwStatus = WBEM_NO_ERROR; CInCritSec ics(&m_cs); if ( dwID < m_apEnumerators.size() ) { CEnumeratorManager* pEnumMgr = m_apEnumerators[dwID]; m_apEnumerators[dwID] = NULL; if (pRawId) *pRawId = pEnumMgr->GetRawId(); pEnumMgr->Release(); } else { dwStatus = E_FAIL; } return dwStatus; } WMISTATUS CEnumeratorCache::Refresh(DWORD dwRefreshId) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { WMISTATUS dwStatus = WBEM_NO_ERROR; CEnumeratorManager** ppEnumMang = new CEnumeratorManager*[m_apEnumerators.size()]; wmilib::auto_buffer rm_(ppEnumMang); if (!ppEnumMang) return WBEM_E_OUT_OF_MEMORY; memset(ppEnumMang,0,sizeof(CEnumeratorManager*)*m_apEnumerators.size()); DWORD j=0; DWORD i=0; { CInCritSec ics(&m_cs); for (i=0;iAddRef(); ppEnumMang[j] = pEnumMgr; j++; } } } for (i=0;iRefresh(dwRefreshId); if (FAILED(dwStatus)) { break; } } for (i=0;iRelease(); } return dwStatus; } ///////////////////////////////////////////////////////////////////////// // // // CEnumeratorManager // // ///////////////////////////////////////////////////////////////////////// CEnumeratorManager::CEnumeratorManager( LPCWSTR wszCookingClass, IWbemClassObject* pCookedClass, IWbemClassObject* pRawClass, IWbemHiPerfEnum* pCookedEnum, IWbemHiPerfEnum* pRawEnum, long lRawID ) : m_pCookedClass( pCookedClass ), m_pRawEnum(pRawEnum), m_pCookedEnum( pCookedEnum ), m_pCooker(NULL), m_lRawID(lRawID), m_dwSignature('mMnE'), m_cRef(1), //-------------- initial refcount m_dwVector(0), m_wszCookingClassName(NULL) { size_t length = wcslen( wszCookingClass ) + 1; m_wszCookingClassName = new WCHAR[ length]; if ( NULL != m_wszCookingClassName ) StringCchCopyW( m_wszCookingClassName, length, wszCookingClass ); _DBG_ASSERT(m_pCookedClass); m_pCookedClass->AddRef(); if ( NULL != m_pRawEnum ) m_pRawEnum->AddRef(); if ( NULL != m_pCookedEnum ) m_pCookedEnum->AddRef(); _DBG_ASSERT(pRawClass); m_IsSingleton = IsSingleton(pRawClass); m_InithRes = Initialize( pRawClass ); } CEnumeratorManager::~CEnumeratorManager() { m_dwSignature = 'gmne'; delete m_wszCookingClassName; // one reference is held by the CWMISimpleObjectCooker if (m_pCookedClass ) m_pCookedClass->Release(); if (m_pRawEnum) m_pRawEnum->Release(); if (m_pCookedEnum) m_pCookedEnum->Release(); delete m_pCooker; #ifdef _VERBOSE DbgPrintfA(0,"~CEnumeratorManager %08x\n",this); #endif } LONG CEnumeratorManager::AddRef() { return InterlockedIncrement(&m_cRef); } LONG CEnumeratorManager::Release() { LONG lRet = InterlockedDecrement(&m_cRef); if (lRet == 0) delete this; return lRet; } // // called from the constructor // WMISTATUS CEnumeratorManager::Initialize( IWbemClassObject* pRawClass ) { WMISTATUS dwStatus; HRESULT hr1,hr2; IWbemObjectAccess* pCookedAccess = NULL; IWbemObjectAccess* pRawAccess = NULL; hr1 = m_pCookedClass->QueryInterface( IID_IWbemObjectAccess, (void**)&pCookedAccess ); CReleaseMe arCookedAccess( pCookedAccess ); hr2 = pRawClass->QueryInterface( IID_IWbemObjectAccess, (void**)&pRawAccess ); CReleaseMe arRawAccess( pRawAccess ); if (SUCCEEDED(hr1) && SUCCEEDED(hr2)) { m_pCooker = new CWMISimpleObjectCooker( m_wszCookingClassName, pCookedAccess, // acquired by CWMISimpleObjectCooker pRawAccess ); } if (m_pCooker == NULL) { dwStatus = WBEM_E_OUT_OF_MEMORY; } else { dwStatus = m_pCooker->GetLastHR(); } return dwStatus; } // // returns an hash-ed value of the __RELPATH in a ULONG_PTR with the lower bit stripped // the lower bit is used to flag the entry when updating the enumerators // ///////////////////////////////////////////////////////////////////////////// ULONG_PTR hash_string (WCHAR * pKey) { ULONG_PTR acc = 0; ULONG_PTR i = 0; WCHAR *this_char = pKey; while (*this_char != NULL) { acc ^= *(this_char++) << i; i = (i + 1) % sizeof (void *); } return (acc<<1); // so we can save the LOWEST bit } // // this function simply fills out an array of pointers to IWbemObejctAccess // obtaining them from the RAW-Enumerator // it also builds an array with hashes of the __RELPATHs of the instances // /////////////////////////////////////////////////////////////// WMISTATUS CEnumeratorManager::GetRawEnumObjects(std::vector > & refArray, std::vector > & refObjHashKeys) { WMISTATUS dwStatus = WBEM_NO_ERROR; DWORD dwRet = 0, dwNumRawObjects = 0; IWbemObjectAccess** apObjAccess = NULL; dwStatus = m_pRawEnum->GetObjects( 0L, 0, apObjAccess, &dwRet); if ( WBEM_E_BUFFER_TOO_SMALL == dwStatus ) { // Set the buffer size // =================== dwNumRawObjects = dwRet; wmilib::auto_buffer apObjAccess( new IWbemObjectAccess*[dwNumRawObjects]); if ( NULL != apObjAccess.get() ) { memset( apObjAccess.get(), 0, dwNumRawObjects * sizeof(IWbemObjectAccess*)); dwStatus = m_pRawEnum->GetObjects( 0L, dwNumRawObjects, (IWbemObjectAccess **)apObjAccess.get(), &dwRet ); } else { dwStatus = WBEM_E_OUT_OF_MEMORY; } if ( SUCCEEDED( dwStatus ) ) { try { refArray.reserve(dwNumRawObjects); refObjHashKeys.reserve(dwNumRawObjects); } catch (...) { dwStatus = WBEM_E_OUT_OF_MEMORY; dwNumRawObjects = 0; } for (DWORD i=0;iGet(L"__RELPATH",0,&VarKey,NULL,NULL); if (SUCCEEDED(hr1)) { DWORD Hash = hash_string(VarKey.bstrVal); refObjHashKeys.push_back(Hash); refArray.push_back(apObjAccess[i]); } else { // if we cannot give out the ownership of a pointer, release apObjAccess[i]->Release(); } } } } return dwStatus; } // // the problem that UpdateEnums and Refresh are trying to solve is the following: // The Cooked enumerator needs 2 Raw values for calculating 1 value. // the 2 values comes from two distinc enumeration // the 2 distinct enumeration can give a different resultset // OLD: A B C D E // NEW: B C E F G // we are adding to the "cooking cache" only the new objects, // and we are removing the old ones // ////////////////////////////////////////////////////////////////////// WMISTATUS CEnumeratorManager::UpdateEnums( /*out*/ std::vector > & apObjKeyHash) { // cyclic logic: // we have a 'circular array' of std::vector // and the m_dwVector is the index // circular increment of the index will decide // who is the New and who is the Old std::vector > & Old = m_Delta[m_dwVector]; m_dwVector = (m_dwVector+1)%2; m_Delta[m_dwVector].clear(); m_Delta[m_dwVector] = apObjKeyHash; std::vector > & New = m_Delta[m_dwVector]; DWORD j,k; for (j=0;j > apObjAccess; std::vector > apObjHashKeys; dwStatus = GetRawEnumObjects( apObjAccess, apObjHashKeys ); // calculate the Delta of the caches if (SUCCEEDED(dwStatus)) { dwStatus = UpdateEnums(apObjHashKeys); } std::vector > & New = m_Delta[m_dwVector]; std::vector > & Old = m_Delta[(m_dwVector-1)%2]; { CInCritSec ics(&m_cs); // Merge into the cache if ( SUCCEEDED(dwStatus) ) { // // Elements in the New array with the bit set are really new // DWORD j; for (j=0; j< New.size(); j++) { if (New[j] & 1) // test the very new BIT { EnumCookId thisEnumCookId; dwStatus = InsertCookingRecord( apObjAccess[j], &thisEnumCookId, dwRefreshStamp ); if (SUCCEEDED(dwStatus)) { try { m_mapID[New[j]] = thisEnumCookId; } catch (...) { break; } } else { break; } //remove the bit New[j] &= (~1); } } for (j=0; jRecalc(dwRefreshStamp); } } // in any case .... for (DWORD i=0;iRelease(); }; return dwStatus; } WMISTATUS CEnumeratorManager::InsertCookingRecord( IWbemObjectAccess* pRawObject, EnumCookId * pEnumCookId, DWORD dwRefreshStamp) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { WMISTATUS dwStatus = WBEM_NO_ERROR; if (!pRawObject || !pEnumCookId) { return WBEM_E_INVALID_PARAMETER; } IWbemObjectAccess* pCookedObject = NULL; long lID = 0; dwStatus = CreateCookingObject( pRawObject, &pCookedObject ); CReleaseMe rm1(pCookedObject); if ( SUCCEEDED( dwStatus ) ) { dwStatus = m_pCooker->SetCookedInstance( pCookedObject, &lID ); if ( SUCCEEDED( dwStatus ) ) { dwStatus = m_pCooker->BeginCooking( lID, pRawObject,dwRefreshStamp); } } if ( SUCCEEDED( dwStatus ) ) { DWORD dwTarget; long EnumId = lID; dwStatus = m_pCookedEnum->AddObjects( 0L, 1, &EnumId, &pCookedObject ); if (SUCCEEDED(dwStatus)) { pEnumCookId->CookId = lID; pEnumCookId->EnumId = EnumId; m_dwUsage++; } else { pEnumCookId->CookId = 0; pEnumCookId->EnumId = 0; } } return dwStatus; } WMISTATUS CEnumeratorManager::CreateCookingObject( IWbemObjectAccess* pRawObject, IWbemObjectAccess** ppCookedObject ) /////////////////////////////////////////////////////////////////////////////// // // Create a new instance of the cooked object and set the key(s) based on the // raw object's key(s) value. // // Parameters: // // pRawObject - The new object's corresponding raw object // ppCookedObject - The new cooked object // /////////////////////////////////////////////////////////////////////////////// { HRESULT hr = WBEM_E_FAILED; IWbemClassObject * pCookedInst = NULL; hr = m_pCookedClass->SpawnInstance(0,&pCookedInst); CReleaseMe rm1(pCookedInst); if (SUCCEEDED(hr) && !m_IsSingleton) { // get the 'list' of all the key property // if you haven't got it in the past if (m_pKeyProps.size() == 0) { hr = pRawObject->BeginEnumeration(WBEM_FLAG_KEYS_ONLY); if (SUCCEEDED(hr)) { BSTR bstrName; while(WBEM_S_NO_ERROR == pRawObject->Next(0,&bstrName,NULL,NULL,NULL)) { try { m_pKeyProps.push_back(bstrName); } catch (...) { hr = WBEM_E_OUT_OF_MEMORY; }; SysFreeString(bstrName); }; pRawObject->EndEnumeration(); } } // copy all the key properties from the Raw to the cooked instance if (m_pKeyProps.size() > 0 && SUCCEEDED(hr)) { for(int i=0;iGet(m_pKeyProps[i],0,&VarVal,&ct,NULL); if (SUCCEEDED(hr)) { hr = pCookedInst->Put(m_pKeyProps[i],0,&VarVal,0); if (FAILED(hr)) { break; } } else { break; } VarVal.Clear(); } } else { hr = WBEM_E_INVALID_CLASS; } }; if (SUCCEEDED(hr)){ hr = pCookedInst->QueryInterface( IID_IWbemObjectAccess, (void**)ppCookedObject ); } return hr; } WMISTATUS CEnumeratorManager::RemoveCookingRecord( EnumCookId * pEnumCookID ) /////////////////////////////////////////////////////////////////////////////// // // // // Parameters: // // /////////////////////////////////////////////////////////////////////////////// { if (!pEnumCookID) { return WBEM_E_INVALID_PARAMETER; } WMISTATUS dwStatus = WBEM_NO_ERROR; dwStatus = m_pCookedEnum->RemoveObjects( 0L, 1, &pEnumCookID->EnumId ); m_pCooker->StopCooking(pEnumCookID->CookId); m_pCooker->Remove(pEnumCookID->CookId); --m_dwUsage; return dwStatus; }