windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/wmicooker/wmiobjcooker.cpp
2020-09-26 16:20:57 +08:00

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;
}