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.
621 lines
21 KiB
621 lines
21 KiB
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Provider.cpp
|
|
//
|
|
// Module: WMI high performance provider
|
|
//
|
|
//
|
|
// History:
|
|
// a-dcrews 12-Jan-97 Created
|
|
//
|
|
//
|
|
// Copyright (c) 1997-2001 Microsoft Corporation
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "precomp.h"
|
|
#include <process.h>
|
|
#include <autoptr.h>
|
|
|
|
#include "Provider.h"
|
|
#include "CookerUtils.h"
|
|
|
|
#include <comdef.h>
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// Global, external and static variables
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
// The COM object counter (declared in server.cpp)
|
|
// ===============================================
|
|
|
|
extern long g_lObjects;
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
// CHiPerfProvider
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
CHiPerfProvider::CHiPerfProvider() : m_lRef(0)
|
|
|
|
{
|
|
// Increment the global COM object counter
|
|
InterlockedIncrement(&g_lObjects);
|
|
}
|
|
|
|
CHiPerfProvider::~CHiPerfProvider()
|
|
{
|
|
// Decrement the global COM object counter
|
|
InterlockedDecrement(&g_lObjects);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// COM methods
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CHiPerfProvider::QueryInterface(REFIID riid, void** ppv)
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// Standard QueryInterface
|
|
//
|
|
// Parameters:
|
|
// riid - the ID of the requested interface
|
|
// ppv - a pointer to the interface pointer
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
if (NULL == ppv) return E_POINTER;
|
|
|
|
if(riid == IID_IUnknown)
|
|
*ppv = (LPVOID)(IUnknown*)(IWbemProviderInit*)this;
|
|
else if(riid == IID_IWbemProviderInit)
|
|
*ppv = (LPVOID)(IWbemProviderInit*)this;
|
|
else if (riid == IID_IWbemHiPerfProvider)
|
|
*ppv = (LPVOID)(IWbemHiPerfProvider*)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
((IUnknown*)*ppv)->AddRef();
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CHiPerfProvider::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_lRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CHiPerfProvider::Release()
|
|
{
|
|
long lRef = InterlockedDecrement(&m_lRef);
|
|
if(lRef == 0) delete this;
|
|
return lRef;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::Initialize(
|
|
/* [unique][in] */ LPWSTR wszUser,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ LPWSTR wszNamespace,
|
|
/* [unique][in] */ LPWSTR wszLocale,
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ IWbemContext __RPC_FAR *pCtx,
|
|
/* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink)
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Called once during startup for any one-time initialization. The
|
|
// final call to Release() is for any cleanup.
|
|
//
|
|
// The parameters indicate to the provider which namespace it is being
|
|
// invoked for and which User. It also supplies a back pointer to
|
|
// WINMGMT so that class definitions can be retrieved.
|
|
//
|
|
// Initialize will create a single template object that can be used
|
|
// by the provider to spawn instances for QueryInstances. It will
|
|
// also initialize our mock data source and set the global ID access
|
|
// handle.
|
|
//
|
|
// Parameters:
|
|
// wszUser - The current user.
|
|
// lFlags - Reserved.
|
|
// wszNamespace - The namespace for which we are being activated.
|
|
// wszLocale - The locale under which we are to be running.
|
|
// pNamespace - An active pointer back into the current namespace
|
|
// from which we can retrieve schema objects.
|
|
// pCtx - The user's context object. We simply reuse this
|
|
// during any reentrant operations into WINMGMT.
|
|
// pInitSink - The sink to which we indicate our readiness.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
if (wszNamespace == 0 || pNamespace == 0 || pInitSink == 0)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
// We now have all the instances ready to go and the name handle
|
|
// stored. Tell WINMGMT that we're ready to start 'providing'
|
|
|
|
pInitSink->SetStatus(WBEM_S_INITIALIZED, 0);
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::CreateRefresher(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ long lFlags,
|
|
/* [out] */ IWbemRefresher __RPC_FAR *__RPC_FAR *ppRefresher )
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Called whenever a new refresher is needed by the client.
|
|
//
|
|
// Parameters:
|
|
// pNamespace - A pointer to the relevant namespace. Not used.
|
|
// lFlags - Reserved.
|
|
// ppRefresher - Receives the requested refresher.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
HRESULT hResult = WBEM_NO_ERROR;
|
|
|
|
if ( pNamespace == 0 || ppRefresher == 0 )
|
|
hResult = WBEM_E_INVALID_PARAMETER;
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
// Construct and initialize a new empty refresher
|
|
// ==============================================
|
|
|
|
CRefresher* pNewRefresher = new CRefresher;
|
|
|
|
if ( NULL == pNewRefresher )
|
|
{
|
|
hResult = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
else if ( !pNewRefresher->IsOK() )
|
|
{
|
|
hResult = WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
// Follow COM rules and AddRef() the thing before sending it back
|
|
// ==============================================================
|
|
|
|
pNewRefresher->AddRef();
|
|
*ppRefresher = pNewRefresher;
|
|
}
|
|
else
|
|
{
|
|
delete pNewRefresher;
|
|
}
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::CreateRefreshableObject(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [in] */ IWbemObjectAccess __RPC_FAR *pTemplate,
|
|
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext __RPC_FAR *pContext,
|
|
/* [out] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *ppRefreshable,
|
|
/* [out] */ long __RPC_FAR *plId )
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Called whenever a user wants to include an object in a refresher.
|
|
//
|
|
// Note that the object returned in ppRefreshable is a clone of the
|
|
// actual instance maintained by the provider. If refreshers shared
|
|
// a copy of the same instance, then a refresh call on one of the
|
|
// refreshers would impact the state of both refreshers. This would
|
|
// break the refresher rules. Instances in a refresher are only
|
|
// allowed to be updated when 'Refresh' is called.
|
|
//
|
|
// Parameters:
|
|
// pNamespace - A pointer to the relevant namespace in WINMGMT.
|
|
// pTemplate - A pointer to a copy of the object which is to be
|
|
// added. This object itself cannot be used, as
|
|
// it not owned locally.
|
|
// pRefresher - The refresher to which to add the object.
|
|
// lFlags - Not used.
|
|
// pContext - Not used here.
|
|
// ppRefreshable - A pointer to the internal object which was added
|
|
// to the refresher.
|
|
// plId - The Object Id (for identification during removal).
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
HRESULT hResult = WBEM_NO_ERROR;
|
|
|
|
if ( pNamespace == 0 || pTemplate == 0 || pRefresher == 0 )
|
|
hResult = WBEM_E_INVALID_PARAMETER;
|
|
|
|
// Verify hi-perf object
|
|
// =====================
|
|
|
|
if ( !IsHiPerfObj( pTemplate ) )
|
|
hResult = WBEM_E_INVALID_CLASS;
|
|
|
|
_variant_t VarClass;
|
|
hResult = pTemplate->Get(L"__CLASS",0,&VarClass,NULL,NULL);
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
if (VT_BSTR == V_VT(&VarClass))
|
|
{
|
|
if ( !IsHiPerf( pNamespace, V_BSTR(&VarClass) ) )
|
|
{
|
|
hResult = WBEM_E_INVALID_CLASS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hResult = WBEM_E_INVALID_CLASS;
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
// The refresher being supplied by the caller is actually
|
|
// one of our own refreshers, so a simple cast is convenient
|
|
// so that we can access private members.
|
|
// =========================================================
|
|
|
|
CRefresher *pOurRefresher = ( CRefresher * ) pRefresher;
|
|
|
|
// Add the object to the refresher. The ID is set by AddObject
|
|
// ===========================================================
|
|
|
|
// NB: We are passing a NULL in as the Raw object
|
|
|
|
hResult = pOurRefresher->AddInstance( pNamespace, pContext, pTemplate, NULL, ppRefreshable, plId );
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::CreateRefreshableEnum(
|
|
/* [in] */ IWbemServices* pNamespace,
|
|
/* [in, string] */ LPCWSTR wszClass,
|
|
/* [in] */ IWbemRefresher* pRefresher,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext* pContext,
|
|
/* [in] */ IWbemHiPerfEnum* pHiPerfEnum,
|
|
/* [out] */ long* plId )
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Called when an enumerator is being added to a refresher. The
|
|
// enumerator will obtain a fresh set of instances of the specified
|
|
// class every time that refresh is called.
|
|
//
|
|
// Parameters:
|
|
// pNamespace - A pointer to the relevant namespace.
|
|
// wszClass - The class name for the requested enumerator.
|
|
// pRefresher - The refresher object for which we will add
|
|
// the enumerator
|
|
// lFlags - Reserved.
|
|
// pContext - Not used here.
|
|
// pHiPerfEnum - The enumerator to add to the refresher.
|
|
// plId - A provider specified ID for the enumerator.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
HRESULT hResult = WBEM_NO_ERROR;
|
|
|
|
if ( pNamespace == 0 || pRefresher == 0 || pHiPerfEnum == 0 )
|
|
hResult = WBEM_E_INVALID_PARAMETER;
|
|
|
|
// Verify hi-perf class
|
|
// =====================
|
|
|
|
if ( !IsHiPerf( pNamespace, wszClass ) )
|
|
hResult = WBEM_E_INVALID_CLASS;
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
// The refresher being supplied by the caller is actually
|
|
// one of our own refreshers, so a simple cast is convenient
|
|
// so that we can access private members.
|
|
|
|
CRefresher *pOurRefresher = (CRefresher *) pRefresher;
|
|
|
|
// Add the enumerator to the refresher. The ID is generated by AddEnum
|
|
// ====================================================================
|
|
|
|
hResult = pOurRefresher->AddEnum( pNamespace, pContext, wszClass, pHiPerfEnum, plId );
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::StopRefreshing(
|
|
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
|
|
/* [in] */ long lId,
|
|
/* [in] */ long lFlags )
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Called whenever a user wants to remove an object from a refresher.
|
|
//
|
|
// Parameters:
|
|
// pRefresher - The refresher object from which we are to
|
|
// remove the perf object.
|
|
// lId - The ID of the object.
|
|
// lFlags - Not used.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
HRESULT hResult = WBEM_NO_ERROR;
|
|
|
|
if ( pRefresher == 0 )
|
|
hResult = WBEM_E_INVALID_PARAMETER;
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
// The refresher being supplied by the caller is actually
|
|
// one of our own refreshers, so a simple cast is convenient
|
|
// so that we can access private members.
|
|
// =========================================================
|
|
|
|
CRefresher *pOurRefresher = (CRefresher *) pRefresher;
|
|
|
|
hResult = pOurRefresher->Remove( lId );
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::QueryInstances(
|
|
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
|
|
/* [string][in] */ WCHAR __RPC_FAR *wszClass,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext __RPC_FAR *pCtx,
|
|
/* [in] */ IWbemObjectSink __RPC_FAR *pSink )
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Called whenever a complete, fresh list of instances for a given
|
|
// class is required. The objects are constructed and sent back to the
|
|
// caller through the sink. The sink can be used in-line as here, or
|
|
// the call can return and a separate thread could be used to deliver
|
|
// the instances to the sink.
|
|
//
|
|
// Parameters:
|
|
// pNamespace - A pointer to the relevant namespace. This
|
|
// should not be AddRef'ed.
|
|
// wszClass - The class name for which instances are required.
|
|
// lFlags - Reserved.
|
|
// pCtx - The user-supplied context (not used here).
|
|
// pSink - The sink to which to deliver the objects. The objects
|
|
// can be delivered synchronously through the duration
|
|
// of this call or asynchronously (assuming we
|
|
// had a separate thread). A IWbemObjectSink::SetStatus
|
|
// call is required at the end of the sequence.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
HRESULT hResult = WBEM_NO_ERROR;
|
|
|
|
if (pNamespace == 0 || wszClass == 0 || pSink == 0)
|
|
hResult = WBEM_E_INVALID_PARAMETER;
|
|
|
|
// Verify hi-perf object
|
|
// =====================
|
|
|
|
if ( !IsHiPerf( pNamespace, wszClass ) )
|
|
hResult = WBEM_E_INVALID_CLASS;
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
IWbemRefresher* pRefresher = NULL;
|
|
IWbemConfigureRefresher* pConfig = NULL;
|
|
IWbemHiPerfEnum* pHiPerfEnum = NULL;
|
|
IWbemObjectAccess** apAccess = NULL;
|
|
IWbemClassObject** apObject = NULL;
|
|
|
|
hResult = CoCreateInstance( CLSID_WbemRefresher,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWbemRefresher,
|
|
(void**) &pRefresher );
|
|
|
|
CReleaseMe rm1(pRefresher);
|
|
|
|
// Get the refresher configuration interface
|
|
// =========================================
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
hResult = pRefresher->QueryInterface( IID_IWbemConfigureRefresher, (void**)&pConfig );
|
|
}
|
|
CReleaseMe rm2(pConfig);
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
ULONG uArraySize = 0,
|
|
uObjRet = 0;
|
|
|
|
long lID = 0;
|
|
|
|
hResult = pConfig->AddEnum( pNamespace, wszClass, 0, pCtx, &pHiPerfEnum, &lID );
|
|
CReleaseMe arHiPerfEnum( pHiPerfEnum );
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
//
|
|
// we needs 2 samples for most of the calculations
|
|
//
|
|
hResult = pRefresher->Refresh( 0L );
|
|
hResult = pRefresher->Refresh( 0L );
|
|
}
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
hResult = pHiPerfEnum->GetObjects( 0L, 0, NULL, &uObjRet );
|
|
|
|
if ( WBEM_E_BUFFER_TOO_SMALL == hResult )
|
|
{
|
|
uArraySize = uObjRet;
|
|
|
|
wmilib::auto_buffer<IWbemObjectAccess*> apAccess( new IWbemObjectAccess*[ uObjRet ]);
|
|
|
|
if ( NULL != apAccess.get() )
|
|
{
|
|
hResult = pHiPerfEnum->GetObjects( 0L, uArraySize, apAccess.get(), &uObjRet );
|
|
|
|
}
|
|
else
|
|
{
|
|
hResult = WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
// since IWbemObjectAccess derives from IWbemClassObject cast is OK
|
|
hResult = pSink->Indicate( uArraySize, (IWbemClassObject **)apAccess.get() );
|
|
|
|
for ( ULONG uIndex = 0; uIndex < uArraySize; uIndex++ )
|
|
{
|
|
apAccess[ uIndex ]->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
pConfig->Remove( lID , 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
pSink->SetStatus(0, hResult, 0, 0);
|
|
|
|
return hResult;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::GetObjects(
|
|
/* [in] */ IWbemServices* pNamespace,
|
|
/* [in] */ long lNumObjects,
|
|
/* [in,size_is(lNumObjects)] */ IWbemObjectAccess** apObj,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext* pContext)
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Called when a request is made to provide all instances currently
|
|
// being managed by the provider in the specified namespace.
|
|
//
|
|
// Parameters:
|
|
// pNamespace - A pointer to the relevant namespace.
|
|
// lNumObjects - The number of instances being returned.
|
|
// apObj - The array of instances being returned.
|
|
// lFlags - Reserved.
|
|
// pContext - Not used here.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
// Update objects
|
|
// ==============
|
|
|
|
IWbemRefresher* pRefresher = NULL;
|
|
IWbemConfigureRefresher* pConfig = NULL;
|
|
wmilib::auto_buffer<IWbemClassObject*> apRefObj(new IWbemClassObject*[lNumObjects]);
|
|
|
|
if (0 == apRefObj.get())
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
// CoCreate the refresher interface
|
|
// ================================
|
|
|
|
HRESULT hResult = CoCreateInstance( CLSID_WbemRefresher,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IWbemRefresher,
|
|
(void**) &pRefresher );
|
|
|
|
CReleaseMe arRefresher( pRefresher );
|
|
|
|
// Get the refresher configuration interface
|
|
// =========================================
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
hResult = pRefresher->QueryInterface( IID_IWbemConfigureRefresher, (void**)&pConfig );
|
|
}
|
|
|
|
CReleaseMe arConfig( pConfig );
|
|
|
|
// Get the object data
|
|
// ===================
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
long lIndex = 0,
|
|
lID = 0;
|
|
|
|
// Add all of the requested objects to the refresher
|
|
// =================================================
|
|
|
|
for ( lIndex = 0; SUCCEEDED( hResult ) && lIndex < lNumObjects; lIndex++ )
|
|
{
|
|
// Verify hi-perf object
|
|
if ( !IsHiPerfObj( apObj[ lIndex ] ) )
|
|
hResult = WBEM_E_INVALID_CLASS;
|
|
|
|
#ifdef _VERBOSE
|
|
{
|
|
_variant_t VarPath;
|
|
apObj[lIndex]->Get(L"__RELPATH",0,&VarPath,NULL,NULL);
|
|
_variant_t VarName;
|
|
apObj[lIndex]->Get(L"Name",0,&VarName,NULL,NULL);
|
|
DbgPrintfA(0,"%S %S\n",V_BSTR(&VarPath),V_BSTR(&VarName));
|
|
}
|
|
#endif
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
hResult = pConfig->AddObjectByTemplate( pNamespace,
|
|
apObj[ lIndex ],
|
|
0,
|
|
NULL,
|
|
&(apRefObj[ lIndex ]),
|
|
&lID );
|
|
lID = 0;
|
|
}
|
|
}
|
|
|
|
if ( SUCCEEDED( hResult ) )
|
|
{
|
|
hResult = pRefresher->Refresh( 0L );
|
|
hResult = pRefresher->Refresh( 0L );
|
|
}
|
|
|
|
for ( lIndex = 0; SUCCEEDED( hResult ) && lIndex < lNumObjects; lIndex++ )
|
|
{
|
|
hResult = CopyBlob( apRefObj[lIndex], apObj[lIndex] );
|
|
apRefObj[lIndex]->Release();
|
|
}
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|