684 lines
16 KiB
C++
684 lines
16 KiB
C++
/*++
|
|
|
|
Copyright (C) 1996-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Abstract:
|
|
|
|
History:
|
|
|
|
--*/
|
|
|
|
|
|
// WMIObjCooker.cpp
|
|
|
|
#include "precomp.h"
|
|
#include "WMIObjCooker.h"
|
|
#include "RawCooker.h"
|
|
#include <comdef.h>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Helper Functions
|
|
// ================
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
WMISTATUS GetPropValue( CProperty* pProp, IWbemObjectAccess* pInstance, __int64* pnResult )
|
|
{
|
|
WMISTATUS dwStatus = WBEM_NO_ERROR;
|
|
|
|
unsigned __int64 nResult = 0;
|
|
DWORD dwRes = 0;
|
|
|
|
switch( pProp->GetType() )
|
|
{
|
|
case CIM_UINT32:
|
|
{
|
|
dwStatus = pInstance->ReadDWORD( pProp->GetHandle(), &dwRes );
|
|
if (pnResult) {
|
|
*pnResult = dwRes;
|
|
}
|
|
}break;
|
|
case CIM_UINT64:
|
|
{
|
|
dwStatus = pInstance->ReadQWORD( pProp->GetHandle(), &nResult );
|
|
if (pnResult) {
|
|
*pnResult = nResult;
|
|
}
|
|
}break;
|
|
default:
|
|
dwStatus = WBEM_E_TYPE_MISMATCH;
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// CWMISimpleObjectCooker
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
CWMISimpleObjectCooker::CWMISimpleObjectCooker( WCHAR* wszCookingClassName,
|
|
IWbemObjectAccess* pCookingClass,
|
|
IWbemObjectAccess* pRawClass,
|
|
IWbemServices * pNamespace ) :
|
|
m_lRef( 1 ),
|
|
m_pCookingClass( NULL ),
|
|
m_wszClassName(NULL),
|
|
m_pNamespace(NULL),
|
|
m_dwPropertyCacheSize( 16 ),
|
|
m_dwNumProperties( 0 ),
|
|
m_NumInst(0),
|
|
m_InitHR(WBEM_E_INITIALIZATION_FAILURE)
|
|
{
|
|
#ifdef _VERBOSE
|
|
{
|
|
char pBuff[128];
|
|
wsprintfA(pBuff,"Cooker %p\n",this);
|
|
OutputDebugStringA(pBuff);
|
|
}
|
|
#endif
|
|
|
|
if (pNamespace){
|
|
m_pNamespace = pNamespace;
|
|
m_pNamespace->AddRef();
|
|
}
|
|
|
|
m_InitHR = SetClass( wszCookingClassName, pCookingClass, pRawClass );
|
|
|
|
if (m_pNamespace){
|
|
m_pNamespace->Release();
|
|
m_pNamespace = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
CWMISimpleObjectCooker::~CWMISimpleObjectCooker()
|
|
{
|
|
|
|
Reset();
|
|
|
|
// Release the cooking class
|
|
// =========================
|
|
|
|
if ( m_pCookingClass ){
|
|
m_pCookingClass->Release();
|
|
}
|
|
|
|
if (m_pNamespace){
|
|
m_pNamespace->Release();
|
|
}
|
|
|
|
// Delete the property cache
|
|
// =========================
|
|
|
|
for (DWORD i=0;i<m_apPropertyCache.size();i++){
|
|
CCookingProperty* pCookProp = m_apPropertyCache[i];
|
|
if (pCookProp)
|
|
delete pCookProp;
|
|
}
|
|
|
|
if (m_wszClassName)
|
|
delete [] m_wszClassName;
|
|
|
|
#ifdef _VERBOSE
|
|
{
|
|
char pBuff[128];
|
|
wsprintfA(pBuff,"~Cooker %p istances left %d\n",this,m_NumInst);
|
|
OutputDebugStringA(pBuff);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// COM methods
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CWMISimpleObjectCooker::QueryInterface(REFIID riid, void** ppv)
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// Standard QueryInterface
|
|
//
|
|
// Parameters:
|
|
// riid - the ID of the requested interface
|
|
// ppv - a pointer to the interface pointer
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
if(riid == IID_IUnknown)
|
|
*ppv = (LPVOID)(IUnknown*)(IWMISimpleCooker*)this;
|
|
else if(riid == IID_IWMISimpleCooker)
|
|
*ppv = (LPVOID)(IWMISimpleCooker*)this;
|
|
else return E_NOINTERFACE;
|
|
|
|
((IUnknown*)*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CWMISimpleObjectCooker::AddRef()
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// Standard COM AddRef
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
return InterlockedIncrement(&m_lRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CWMISimpleObjectCooker::Release()
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// Standard COM Release
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
long lRef = InterlockedDecrement(&m_lRef);
|
|
if(lRef == 0)
|
|
delete this;
|
|
|
|
return lRef;
|
|
}
|
|
|
|
STDMETHODIMP CWMISimpleObjectCooker::SetClass(
|
|
/*[in] */ WCHAR* wszCookingClassName,
|
|
/*[in] */ IWbemObjectAccess *pCookingClassAccess,
|
|
/*[in] */ IWbemObjectAccess *pRawClass )
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
IWbemClassObject * pClass = NULL;
|
|
|
|
// Cannot override the original cooking class for now
|
|
// ==================================================
|
|
|
|
if ( ( NULL != m_pCookingClass ) || ( NULL == pCookingClassAccess ) )
|
|
hResult = E_FAIL;
|
|
|
|
// what we put here MUST be a class, Singletons are OK
|
|
|
|
if (m_pNamespace)
|
|
{
|
|
_variant_t VarGenus;
|
|
hResult = pCookingClassAccess->Get(L"__GENUS",0,&VarGenus,NULL,NULL);
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
if ((CIM_SINT32 == V_VT(&VarGenus)) &&
|
|
WBEM_GENUS_CLASS == V_I4(&VarGenus))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
BSTR BstrName = SysAllocString(wszCookingClassName);
|
|
if (BstrName)
|
|
{
|
|
CAutoFree sfm(BstrName);
|
|
m_pNamespace->GetObject(BstrName,0,NULL,&pClass,NULL);
|
|
}
|
|
else
|
|
{
|
|
hResult = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IWbemClassObject * pCookingClassAccess2;
|
|
pCookingClassAccess2 = (pClass)?pClass:pCookingClassAccess;
|
|
|
|
// Verify and process the cooking class
|
|
// ====================================
|
|
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
BOOL bRet;
|
|
bRet = IsCookingClass( pCookingClassAccess );
|
|
|
|
if ( bRet ){
|
|
// Save the class
|
|
// ==============
|
|
|
|
m_pCookingClass = pCookingClassAccess;
|
|
m_pCookingClass->AddRef();
|
|
} else {
|
|
hResult = WBEM_E_INVALID_CLASS;
|
|
}
|
|
|
|
// Set the class name
|
|
// ==================
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
m_wszClassName = new WCHAR[ wcslen( wszCookingClassName ) + 1 ];
|
|
wcscpy( m_wszClassName, wszCookingClassName );
|
|
}
|
|
|
|
// Initialize the cooking properties
|
|
// =================================
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
hResult = SetProperties( pCookingClassAccess2, pRawClass );
|
|
}
|
|
}
|
|
|
|
if (pClass){
|
|
pClass->Release();
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
WMISTATUS CWMISimpleObjectCooker::SetProperties( IWbemClassObject* pCookingClassObject, IWbemObjectAccess *pRawClass )
|
|
{
|
|
WMISTATUS dwStatus = WBEM_NO_ERROR;
|
|
|
|
BSTR strPropName = NULL;
|
|
long lHandle = 0;
|
|
CIMTYPE ct;
|
|
|
|
BOOL bAtLeastOne = FALSE;
|
|
|
|
IWbemObjectAccess * pCookingClassAccess = NULL;
|
|
dwStatus = pCookingClassObject->QueryInterface(IID_IWbemObjectAccess ,(void **)&pCookingClassAccess);
|
|
if (FAILED(dwStatus))
|
|
{
|
|
return dwStatus;
|
|
}
|
|
CAutoRelease rm(pCookingClassAccess );
|
|
|
|
// get only once the qualifier set
|
|
IWbemQualifierSet* pCookingClassQSet = NULL;
|
|
dwStatus = pCookingClassObject->GetQualifierSet(&pCookingClassQSet);
|
|
if (FAILED(dwStatus))
|
|
{
|
|
return dwStatus;
|
|
}
|
|
CAutoRelease rm1(pCookingClassQSet);
|
|
|
|
//
|
|
// should we be using [TimeStamp|Frequency]_[Time|Sys100ns|Object] ?
|
|
//
|
|
BOOL bUseWellKnownIfNeeded = FALSE;
|
|
dwStatus = pCookingClassQSet->Get(WMI_COOKER_AUTOCOOK_RAWDEFAULT,0,NULL,NULL);
|
|
// we have already verified version and property, just test if it's there
|
|
if ( SUCCEEDED(dwStatus) )
|
|
{
|
|
bUseWellKnownIfNeeded = TRUE;
|
|
}
|
|
else // do not propagate this error
|
|
{
|
|
dwStatus = WBEM_NO_ERROR;
|
|
}
|
|
|
|
// Enumerate and save the autocook properties
|
|
// ==========================================
|
|
|
|
pCookingClassObject->BeginEnumeration( WBEM_FLAG_NONSYSTEM_ONLY );
|
|
|
|
while ( WBEM_S_NO_ERROR == pCookingClassObject->Next(0,&strPropName,NULL,&ct,NULL) &&
|
|
SUCCEEDED(dwStatus))
|
|
{
|
|
CAutoFree afPropName( strPropName );
|
|
|
|
DWORD dwCounterType = 0;
|
|
DWORD dwReqProp = 0;
|
|
|
|
// Determine if it is an autocook property
|
|
// =======================================
|
|
|
|
if ( IsCookingProperty( strPropName, pCookingClassObject, &dwCounterType, &dwReqProp ) )
|
|
{
|
|
m_dwNumProperties++;
|
|
|
|
// The property is an autocook; save the Name, ObjectAccess handle, type and cooking object
|
|
// ========================================================================================
|
|
|
|
dwStatus = pCookingClassAccess->GetPropertyHandle( strPropName, &ct, &lHandle );
|
|
|
|
if ( SUCCEEDED( dwStatus ) )
|
|
{
|
|
#ifdef _VERBOSE
|
|
{
|
|
char pBuff[128];
|
|
wsprintfA(pBuff,"%S %08x %08x\n",strPropName,dwCounterType,dwReqProp);
|
|
OutputDebugStringA(pBuff);
|
|
}
|
|
#endif
|
|
CCookingProperty* pProperty = new CCookingProperty( strPropName,
|
|
dwCounterType,
|
|
lHandle,
|
|
ct,
|
|
dwReqProp,
|
|
bUseWellKnownIfNeeded);
|
|
|
|
// Initialize the property object
|
|
// ==============================
|
|
|
|
IWbemQualifierSet* pCookingPropQualifierSet = NULL;
|
|
|
|
dwStatus = pCookingClassObject->GetPropertyQualifierSet( strPropName, &pCookingPropQualifierSet );
|
|
CAutoRelease arQualifierSet( pCookingPropQualifierSet );
|
|
|
|
if ( SUCCEEDED( dwStatus ) )
|
|
{
|
|
dwStatus = pProperty->Initialize( pCookingPropQualifierSet, pRawClass, pCookingClassQSet );
|
|
}
|
|
|
|
// If everything worked out then add the property to the cache
|
|
// ===========================================================
|
|
|
|
if ( SUCCEEDED( dwStatus ) )
|
|
{
|
|
bAtLeastOne = TRUE;
|
|
try
|
|
{
|
|
m_apPropertyCache.push_back(pProperty);
|
|
}
|
|
catch (...)
|
|
{
|
|
dwStatus = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete pProperty;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pCookingClassObject->EndEnumeration();
|
|
|
|
if (!bAtLeastOne && (SUCCEEDED(dwStatus))){
|
|
dwStatus = WBEM_E_INVALID_CLASS;
|
|
}
|
|
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
STDMETHODIMP CWMISimpleObjectCooker::SetCookedInstance(
|
|
/*[in] */ IWbemObjectAccess *pCookedInstance,
|
|
/*[out] */ long *plID)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
|
|
CCookingInstance* pInstance = new CCookingInstance( pCookedInstance, m_apPropertyCache.size() );
|
|
|
|
if (!pInstance || !pInstance->IsValid())
|
|
{
|
|
delete pInstance;
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
for ( DWORD dwProp = 0; dwProp < m_apPropertyCache.size() && SUCCEEDED(hResult); dwProp++ )
|
|
{
|
|
CCookingProperty* pProp = m_apPropertyCache[dwProp];
|
|
|
|
hResult = pInstance->InitProperty( dwProp, pProp->NumberOfActiveSamples(), pProp->MinSamplesRequired() );
|
|
}
|
|
|
|
if (FAILED(hResult))
|
|
{
|
|
delete pInstance;
|
|
return hResult;
|
|
}
|
|
|
|
// Add new cooked instance
|
|
// =======================
|
|
|
|
hResult = m_InstanceCache.Add( (DWORD *)plID, pInstance );
|
|
|
|
m_NumInst++;
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CWMISimpleObjectCooker::BeginCooking(
|
|
/*[in] */ long lId,
|
|
/*[in] */ IWbemObjectAccess *pSampleInstance,
|
|
/*[in] */ DWORD dwRefreshStamp)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
|
|
CCookingInstance* pCookedInstance = NULL;
|
|
|
|
// Add an initial sample to the cache
|
|
// ==================================
|
|
|
|
hResult = m_InstanceCache.GetData( lId, &pCookedInstance );
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
if ( NULL != pCookedInstance )
|
|
{
|
|
hResult = pCookedInstance->SetRawSourceInstance( pSampleInstance );
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
hResult = UpdateSamples( pCookedInstance, dwRefreshStamp );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hResult = E_FAIL;
|
|
}
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CWMISimpleObjectCooker::StopCooking(
|
|
/*[in] */ long lId)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
|
|
CCookingInstance* pInstance = NULL;
|
|
|
|
// ????
|
|
hResult = m_InstanceCache.GetData( lId, &pInstance );
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CWMISimpleObjectCooker::Recalc(DWORD dwRefreshStamp)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
|
|
CCookingInstance* pInstance = NULL;
|
|
|
|
// Cook all of the instances which have a cached sample
|
|
// ====================================================
|
|
|
|
m_InstanceCache.BeginEnum();
|
|
DWORD i=0;
|
|
|
|
while ( S_OK == m_InstanceCache.Next( &pInstance ) )
|
|
{
|
|
// since we are inside a CritSec
|
|
// we need to ensire that we call
|
|
// EndEnum, that will release the Lock on the CritSec
|
|
try {
|
|
if ( pInstance )
|
|
{
|
|
hResult = CookInstance( pInstance, dwRefreshStamp );
|
|
#ifdef _VERBOSE
|
|
{
|
|
char pBuff[128];
|
|
wsprintfA(pBuff,"%S %p %d\n",pInstance->GetKey(),pInstance,i++);
|
|
OutputDebugStringA(pBuff);
|
|
}
|
|
#endif
|
|
}
|
|
} catch(...){
|
|
#ifdef _VERBOSE
|
|
OutputDebugStringA("exception\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
m_InstanceCache.EndEnum();
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CWMISimpleObjectCooker::Remove(
|
|
/*[in] */ long lId)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
|
|
// Remove the specified instance from the cache
|
|
// ============================================
|
|
|
|
CCookingInstance * pInst = NULL;
|
|
hResult = m_InstanceCache.Remove( lId, &pInst );
|
|
if (pInst){
|
|
delete pInst;
|
|
m_NumInst--;
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CWMISimpleObjectCooker::Reset()
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
|
|
// Remove all of the instances from the cache
|
|
// ==========================================
|
|
CCookingInstance * pInstance = NULL;
|
|
m_InstanceCache.BeginEnum();
|
|
|
|
while ( S_OK == m_InstanceCache.Next( &pInstance ) )
|
|
{
|
|
if (pInstance){
|
|
delete pInstance;
|
|
m_NumInst--;
|
|
pInstance = NULL;
|
|
}
|
|
}
|
|
|
|
m_InstanceCache.EndEnum();
|
|
|
|
hResult = m_InstanceCache.RemoveAll();
|
|
|
|
return hResult;
|
|
}
|
|
|
|
WMISTATUS CWMISimpleObjectCooker::CookInstance( CCookingInstance* pInstance,
|
|
DWORD dwRefreshStamp)
|
|
{
|
|
WMISTATUS dwStatus = S_OK;
|
|
|
|
if ( SUCCEEDED( dwStatus ) )
|
|
{
|
|
dwStatus = UpdateSamples( pInstance, dwRefreshStamp );
|
|
|
|
// Loop through the cooking properties
|
|
// ===================================
|
|
|
|
for ( DWORD dwProp = 0; dwProp < m_apPropertyCache.size(); dwProp++ )
|
|
{
|
|
// Update the cooking instance property
|
|
// ====================================
|
|
pInstance->CookProperty( dwProp, m_apPropertyCache[dwProp] );
|
|
}
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|
|
|
|
WMISTATUS CWMISimpleObjectCooker::UpdateSamples( CCookingInstance* pCookedInstance, DWORD dwRefreshStamp )
|
|
{
|
|
WMISTATUS dwStatus = WBEM_NO_ERROR;
|
|
|
|
IWbemObjectAccess* pRawInstance = NULL;
|
|
|
|
if ( NULL == pCookedInstance )
|
|
{
|
|
dwStatus = WBEM_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( SUCCEEDED( dwStatus ) )
|
|
{
|
|
dwStatus = pCookedInstance->GetRawSourceInstance( &pRawInstance );
|
|
CAutoRelease arRawInstance( pRawInstance );
|
|
|
|
if ( NULL == pRawInstance )
|
|
{
|
|
dwStatus = WBEM_E_FAILED;
|
|
}
|
|
|
|
#ifdef _VERBOSE
|
|
{
|
|
WCHAR pBuff[256];
|
|
_variant_t Var;
|
|
HRESULT hr = pRawInstance->Get(L"__RELPATH",0,&Var,NULL,NULL);
|
|
wsprintfW(pBuff,L"%p hr %08x __RELPATH %s Key %s\n",pRawInstance,hr,V_BSTR(&Var),pCookedInstance->GetKey());
|
|
OutputDebugStringW(pBuff);
|
|
}
|
|
#endif
|
|
|
|
for ( DWORD dwProp = 0; ( SUCCEEDED( dwStatus ) ) && dwProp < m_apPropertyCache.size(); dwProp++ )
|
|
{
|
|
CCookingProperty* pProp = m_apPropertyCache[dwProp];
|
|
|
|
CProperty* pRawProp = pProp->GetRawCounterProperty();
|
|
CProperty* pBaseProp = pProp->GetBaseProperty();
|
|
CProperty* pTimeProp = pProp->GetTimeProperty();
|
|
|
|
__int64 nRawCounter = 0;
|
|
__int64 nRawBase = 0;
|
|
__int64 nTimeStamp = 0;
|
|
|
|
dwStatus = GetPropValue( pRawProp, pRawInstance, &nRawCounter );
|
|
|
|
if ( pBaseProp )
|
|
{
|
|
GetPropValue( pBaseProp, pRawInstance, &nRawBase );
|
|
}
|
|
else if (pProp->IsReq(REQ_BASE))
|
|
{
|
|
nRawBase = 1;
|
|
}
|
|
|
|
if ( pTimeProp )
|
|
{
|
|
GetPropValue( pTimeProp, pRawInstance, &nTimeStamp );
|
|
}
|
|
else if (pProp->IsReq(REQ_TIME))
|
|
{
|
|
LARGE_INTEGER li;
|
|
QueryPerformanceCounter(&li);
|
|
nTimeStamp = li.QuadPart;
|
|
}
|
|
|
|
dwStatus = pCookedInstance->AddSample( dwRefreshStamp, dwProp, nRawCounter, nRawBase, nTimeStamp );
|
|
|
|
#ifdef _VERBOSE
|
|
{
|
|
char pBuff[128];
|
|
wsprintfA(pBuff,"Prop %d status %08x\n"
|
|
" counter %I64u base %I64u time %I64u\n",
|
|
dwProp, dwStatus, nRawCounter, nRawBase, nTimeStamp);
|
|
OutputDebugStringA(pBuff);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
return dwStatus;
|
|
}
|