Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1585 lines
46 KiB

/*++
Copyright (C) 2000-2001 Microsoft Corporation
Module Name:
Abstract:
History:
--*/
///////////////////////////////////////////////////////////////////////////////
//
// Cache.cpp
//
///////////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#include <winperf.h>
#include <comdef.h>
#include <algorithm>
#include <wbemint.h>
#include <sync.h> // for CInCritSec
#include <autoptr.h>
#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;i<m_apEnumerators.size();i++)
{
CEnumeratorManager* pEnumMgr = m_apEnumerators[i];
if (pEnumMgr) pEnumMgr->Release();
}
}
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;i<m_apEnumerators.size();i++)
{
if(m_apEnumerators[i] == NULL)
{
m_apEnumerators[i] = pEnumMgr;
if (pdwID)
{
*pdwID = i;
}
break;
}
}
// we need to expand the array
if (i == m_apEnumerators.size())
{
try
{
m_apEnumerators.push_back(pEnumMgr);
if (pdwID)
{
*pdwID = m_apEnumerators.size()-1;
}
}
catch (...)
{
pEnumMgr->Release();
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<CEnumeratorManager*> 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;i<m_apEnumerators.size();i++)
{
CEnumeratorManager* pEnumMgr = m_apEnumerators[i];
if (pEnumMgr)
{
pEnumMgr->AddRef();
ppEnumMang[j] = pEnumMgr;
j++;
}
}
}
for (i=0;i<j;i++)
{
dwStatus = ppEnumMang[i]->Refresh(dwRefreshId);
if (FAILED(dwStatus))
{
break;
}
}
for (i=0;i<j;i++)
{
ppEnumMang[i]->Release();
}
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<IWbemObjectAccess*, wbem_allocator<IWbemObjectAccess*> > & refArray,
std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > & 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<IWbemObjectAccess*> 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;i<dwNumRawObjects;i++)
{
HRESULT hr1;
_variant_t VarKey; // does not throw, just container
hr1 = apObjAccess[i]->Get(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<ULONG_PTR, wbem_allocator<ULONG_PTR> > & 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<ULONG_PTR, wbem_allocator<ULONG_PTR> > & Old = m_Delta[m_dwVector];
m_dwVector = (m_dwVector+1)%2;
m_Delta[m_dwVector].clear();
m_Delta[m_dwVector] = apObjKeyHash;
std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > & New = m_Delta[m_dwVector];
DWORD j,k;
for (j=0;j<New.size();j++)
{
BOOL bFound = FALSE;
for (k=0;k<Old.size();k++)
{
if (Old[k] == New[j])
{
Old[k] |= 1;
bFound = TRUE;
break;
}
}
if (!bFound)
{
New[j] |= 1; // ad the very NEW bit
}
}
return WBEM_S_NO_ERROR;
}
WMISTATUS CEnumeratorManager::Refresh( DWORD dwRefreshStamp )
{
WMISTATUS dwStatus = WBEM_NO_ERROR;
std::vector<IWbemObjectAccess*, wbem_allocator<IWbemObjectAccess*> > apObjAccess;
std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > apObjHashKeys;
dwStatus = GetRawEnumObjects( apObjAccess, apObjHashKeys );
// calculate the Delta of the caches
if (SUCCEEDED(dwStatus))
{
dwStatus = UpdateEnums(apObjHashKeys);
}
std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > & New = m_Delta[m_dwVector];
std::vector<ULONG_PTR, wbem_allocator<ULONG_PTR> > & 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; j<Old.size(); j++)
{
if (Old[j] & 1)
{
Old[j] &= (~1); // remove the ALREADY_THERE bit
}
else
{
EnumCookId thisEnumCookId;
thisEnumCookId = m_mapID[Old[j]];
m_mapID.erase(Old[j]);
RemoveCookingRecord(&thisEnumCookId);
}
}
m_pCooker->Recalc(dwRefreshStamp);
}
}
// in any case ....
for (DWORD i=0;i<apObjAccess.size();i++)
{
apObjAccess[i]->Release();
};
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;i<m_pKeyProps.size();i++)
{
// does not thorow, just a container
_variant_t VarVal;
CIMTYPE ct;
hr = pRawObject->Get(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;
}