Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

796 lines
24 KiB

/*++
Copyright (C) 1997-2001 Microsoft Corporation
Module Name:
Abstract:
History:
--*/
//***************************************************************************
//
// NTPERF.CPP
//
// Sample NT5 Perf Counter Provider
//
// raymcc 02-Dec-97 Created
// raymcc 20-Feb-98 Updated to use new initializer
//
//***************************************************************************
#include "precomp.h"
#include <stdio.h>
#include <wbemidl.h>
#include <wbemint.h>
#include "ntperf.h"
//***************************************************************************
//
// CNt5Refresher constructor
//
//***************************************************************************
// ok
CNt5Refresher::CNt5Refresher()
{
m_lRef = 0; // COM Ref Count
// Set the instance cache to all zeros.
// As objects are added to the refresher
// we simply put them in unused slots in the array.
// ================================================
for (int i = 0; i < NUM_SAMPLE_INSTANCES; i++)
{
m_aInstances[i] = 0;
}
// Set the values of the property handles to zero.
// ===============================================
m_hName = 0;
m_hCounter1 = 0;
m_hCounter2 = 0;
m_hCounter3 = 0;
}
//***************************************************************************
//
// CNt5Refresher destructor
//
//***************************************************************************
// ok
CNt5Refresher::~CNt5Refresher()
{
// Release the cached IWbemObjectAccess instances.
// ===============================================
for (DWORD i = 0; i < NUM_SAMPLE_INSTANCES; i++)
{
if (m_aInstances[i])
m_aInstances[i]->Release();
}
}
//***************************************************************************
//
// CNt5Refresher::Refresh
//
// Executed to refresh a set of instances bound to the particular
// refresher.
//
//***************************************************************************
// ok
HRESULT CNt5Refresher::Refresh(/* [in] */ long lFlags)
{
// Zip through all the objects and increment the values.
// =====================================================
for (DWORD i = 0; i < NUM_SAMPLE_INSTANCES; i++)
{
// Get the object at this location.
// ================================
IWbemObjectAccess *pAccess = m_aInstances[i];
// If there is no object in this array slot (a NULL pointer)
// there is nothing to refresh.
// =========================================================
if (pAccess == 0)
continue;
// Increment all the counter values to simulate an update.
// The client already has a pointer to this object, so
// all we have to do is update the values.
// =======================================================
DWORD dwVal;
pAccess->ReadDWORD(m_hCounter1, &dwVal);
dwVal++;
pAccess->WriteDWORD(m_hCounter1, dwVal);
pAccess->ReadDWORD(m_hCounter3, &dwVal);
dwVal++;
pAccess->WriteDWORD(m_hCounter3, dwVal);
unsigned __int64 qwVal;
pAccess->ReadQWORD(m_hCounter2, &qwVal);
qwVal++;
pAccess->WriteQWORD(m_hCounter2, qwVal);
}
return NO_ERROR;
}
//***************************************************************************
//
// CNt5Refresher::TransferPropHandles
//
// This is a private mechanism used by CNt5PerfProvider.
// It is used to copy the property handles from the
// hi-perf provider object to the refresher. We need these handles to
// quickly access the properties in each instance. The same handles are
// used for all instances.
//
//***************************************************************************
// ok
void CNt5Refresher::TransferPropHandles(CNt5PerfProvider *pSrc)
{
m_hName = pSrc->m_hName;
m_hCounter1 = pSrc->m_hCounter1;
m_hCounter2 = pSrc->m_hCounter2;
m_hCounter3 = pSrc->m_hCounter3;
}
//***************************************************************************
//
// CNt5Refresher::AddRef
//
// Standard COM AddRef().
//
//***************************************************************************
// ok
ULONG CNt5Refresher::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
//***************************************************************************
//
// CNt5Refresher::Release
//
// Standard COM Release().
//
//***************************************************************************
// ok
ULONG CNt5Refresher::Release()
{
long lRef = InterlockedDecrement(&m_lRef);
if(lRef == 0)
delete this;
return lRef;
}
//***************************************************************************
//
// CNt5Refresher::QueryInterface
//
// Standard COM QueryInterface().
//
//***************************************************************************
// ok
HRESULT CNt5Refresher::QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown || riid == IID_IWbemRefresher)
{
*ppv = (IWbemRefresher *) this;
AddRef();
return S_OK;
}
else return E_NOINTERFACE;
}
//***************************************************************************
//
// CNt5Refresher::AddObject
//
// Adds an object to the refresher. This is a private mechanism
// used by CNt5PerfProvider and not part of the COM interface.
//
// The ID we return for future identification is simply
// the array index.
//
//***************************************************************************
// ok
BOOL CNt5Refresher::AddObject(
IWbemObjectAccess *pObj,
LONG *plId
)
{
for (DWORD i = 0; i < NUM_SAMPLE_INSTANCES; i++)
{
if (m_aInstances[i] == 0)
{
pObj->AddRef();
m_aInstances[i] = pObj;
// The ID we return for future identification is simply
// the array index.
// ====================================================
*plId = i;
return TRUE;
}
}
return FALSE;
}
//***************************************************************************
//
// CNt5Refresher::RemoveObject
//
// This is a private mechanism used by CNt5PerfProvider and not
// part of the COM interface.
//
// Removes an object from the refresher by ID. In our case, the ID
// is actually the array index we used internally, so it is simple
// to locate and remove the object.
//
//***************************************************************************
BOOL CNt5Refresher::RemoveObject(LONG lId)
{
if (m_aInstances[lId] == 0)
return FALSE;
m_aInstances[lId]->Release();
m_aInstances[lId] = 0;
return TRUE;
}
//***************************************************************************
//
// CNt5PerfProvider constructor
//
//***************************************************************************
// ok
CNt5PerfProvider::CNt5PerfProvider()
{
m_lRef = 0;
m_pSampleClass = 0;
// All the instances we work with are cached internally.
// =====================================================
for (int i = 0; i < NUM_SAMPLE_INSTANCES; i++)
m_aInstances[i] = 0;
// Property value handles.
// =======================
m_hName = 0; // "Name" property in the MOF
m_hCounter1 = 0; // "Counter1" in the MOF
m_hCounter2 = 0; // "Counter2" in the MOF
m_hCounter3 = 0; // "Counter3" in the MOF
}
//***************************************************************************
//
// CNt5PerfProvider destructor
//
//***************************************************************************
// ok
CNt5PerfProvider::~CNt5PerfProvider()
{
// Release all the objects which have been added to the array.
// ===========================================================
for (int i = 0; i < NUM_SAMPLE_INSTANCES; i++)
if (m_aInstances[i])
m_aInstances[i]->Release();
if (m_pSampleClass)
m_pSampleClass->Release();
}
//***************************************************************************
//
// CNt5Refresher::AddRef
//
// Standard COM AddRef().
//
//***************************************************************************
// ok
ULONG CNt5PerfProvider::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
//***************************************************************************
//
// CNt5Refresher::Release
//
// Standard COM Release().
//
//***************************************************************************
// ok
ULONG CNt5PerfProvider::Release()
{
long lRef = InterlockedDecrement(&m_lRef);
if(lRef == 0)
delete this;
return lRef;
}
//***************************************************************************
//
// CNt5Refresher::QueryInterface
//
// Standard COM QueryInterface(). We have to support two interfaces,
// the IWbemHiPerfProvider interface itself to provide the objects and
// the IWbemProviderInit interface to initialize the provider.
//
//***************************************************************************
// ok
HRESULT CNt5PerfProvider::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown || riid == IID_IWbemHiPerfProvider)
{
*ppv = (IWbemHiPerfProvider*) this;
AddRef();
return S_OK;
}
else if (riid == IID_IWbemProviderInit)
{
*ppv = (IWbemProviderInit *) this;
AddRef();
return S_OK;
}
else return E_NOINTERFACE;
}
//***************************************************************************
//
// CNt5Refresher::Initialize
//
// Called once during startup. Insdicates 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.
//
// We perform any one-time initialization in this routine. The
// final call to Release() is for any cleanup.
//
// <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
HRESULT CNt5PerfProvider::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
)
{
BSTR PropName = 0;
IWbemObjectAccess *pAccess = 0;
// Get a copy of our sample class def so that we can create & maintain
// instances of it.
// ===================================================================
HRESULT hRes = pNamespace->GetObject(BSTR(L"Win32_Nt5PerfTest"),
0, pCtx, &m_pSampleClass, 0
);
if (hRes)
return hRes;
// Precreate 10 instances, and set them up in an array which
// is a member of this C++ class.
//
// We only store the IWbemObjectAccess pointers, since
// we are updating 'well-known' properties and already
// know their names.
// ==========================================================
for (int i = 0; i < NUM_SAMPLE_INSTANCES; i++)
{
IWbemClassObject *pInst = 0;
m_pSampleClass->SpawnInstance(0, &pInst);
// Write out the instance name.
// ============================
wchar_t buf[128];
swprintf(buf, L"Inst_%d", i);
VARIANT vName;
VariantInit(&vName);
V_BSTR(&vName) = SysAllocString(buf);
V_VT(&vName) = VT_BSTR;
BSTR PropName = SysAllocString(L"Name");
pInst->Put(PropName, 0, &vName, 0);
SysFreeString(PropName);
VariantClear(&vName);
pInst->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pAccess);
m_aInstances[i] = pAccess;
pInst->Release();
}
// Get the property handles for the well-known properties in
// this counter type. We cache the property handles
// for each property so that we can transfer them to the
// refresher later on.
// =========================================================
m_pSampleClass->QueryInterface(IID_IWbemObjectAccess,
(LPVOID *) &pAccess);
PropName = SysAllocString(L"Name");
hRes = pAccess->GetPropertyHandle(PropName, 0, &m_hName);
SysFreeString(PropName);
PropName = SysAllocString(L"Counter1");
hRes = pAccess->GetPropertyHandle(PropName, 0, &m_hCounter1);
SysFreeString(PropName);
PropName = SysAllocString(L"Counter2");
hRes = pAccess->GetPropertyHandle(PropName, 0, &m_hCounter2);
SysFreeString(PropName);
PropName = SysAllocString(L"Counter3");
hRes = pAccess->GetPropertyHandle(PropName, 0, &m_hCounter3);
SysFreeString(PropName);
pAccess->Release();
// Now let's set all the instance to some default values.
// ======================================================
for (i = 0; i < NUM_SAMPLE_INSTANCES; i++)
{
IWbemObjectAccess *pAccess = m_aInstances[i];
hRes = pAccess->WriteDWORD(m_hCounter1, DWORD(i));
hRes = pAccess->WriteQWORD(m_hCounter2, (_int64) + 100 + i);
hRes = pAccess->WriteDWORD(m_hCounter3, DWORD(i + 1000));
}
// We now have all the instances ready to go and all the
// property handles cached. Tell WINMGMT that we're
// ready to start 'providing'.
// =====================================================
pInitSink->SetStatus(0, WBEM_S_INITIALIZED);
return NO_ERROR;
}
//***************************************************************************
//
// CNt5Refresher::QueryInstances
//
// 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 CNt5PerfProvider::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
)
{
if (pNamespace == 0 || wszClass == 0 || pSink == 0)
return WBEM_E_INVALID_PARAMETER;
// Quickly zip through the instances and update the values before
// returning them. This is just a dummy operation to make it
// look like the instances are continually changing like real
// perf counters.
// ==============================================================
for (int i = 0; i < NUM_SAMPLE_INSTANCES; i++)
{
IWbemObjectAccess *pAccess = m_aInstances[i];
// Every object can be access one of two ways. In this case
// we get the 'other' (primary) interface to this same object.
// ===========================================================
IWbemClassObject *pOtherFormat = 0;
pAccess->QueryInterface(IID_IWbemClassObject, (LPVOID *) &pOtherFormat);
// Send a copy back to the caller.
// ===============================
pSink->Indicate(1, &pOtherFormat);
pOtherFormat->Release(); // Don't need this any more
}
// Tell WINMGMT we are all finished supplying objects.
// =================================================
pSink->SetStatus(0, WBEM_NO_ERROR, 0, 0);
return NO_ERROR;
}
//***************************************************************************
//
// CNt5Refresher::CreateRefresher
//
// Called whenever a new refresher is needed by the client.
//
// Parameters:
// <pNamespace> A pointer to the relevant namespace. Not used.
// <lFlags> Not used.
// <ppRefresher> Receives the requested refresher.
//
//***************************************************************************
// ok
HRESULT CNt5PerfProvider::CreateRefresher(
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
/* [in] */ long lFlags,
/* [out] */ IWbemRefresher __RPC_FAR *__RPC_FAR *ppRefresher
)
{
if (pNamespace == 0 || ppRefresher == 0)
return WBEM_E_INVALID_PARAMETER;
// Construct a new empty refresher.
// ================================
CNt5Refresher *pNewRefresher = new CNt5Refresher();
// Move copies of the property handles to the refresher
// so that it can quickly update property values during
// a refresh operation.
// ====================================================
pNewRefresher->TransferPropHandles(this);
// Follow COM rules and AddRef() the thing before sending it back.
// ===============================================================
pNewRefresher->AddRef();
*ppRefresher = pNewRefresher;
return NO_ERROR;
}
//***************************************************************************
//
// CNt5Refresher::CreateRefreshableObject
//
// Called whenever a user wants to include an object in a refresher.
//
// 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 CNt5PerfProvider::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
)
{
// The object supplied by <pTemplate> must not be copied.
// Instead, we want to find out which object the caller is after
// and return a pointer to *our* own private instance which is
// already set up internally. This value will be sent back to the
// caller so that everyone is sharing the same exact instance
// in memory.
// ===============================================================
// Find out which object is being requested for addition.
// ======================================================
wchar_t buf[128];
*buf = 0;
LONG lNameLength = 0;
pTemplate->ReadPropertyValue(m_hName, 128, &lNameLength, LPBYTE(buf));
// Scan out the index from the instance name. We only do this
// because the instance name is a string.
// ===========================================================
DWORD dwIndex = 0;
swscanf(buf, L"Inst_%u", &dwIndex);
// Now we know which object is desired.
// ====================================
IWbemObjectAccess *pOurCopy = m_aInstances[dwIndex];
// 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.
// =========================================================
CNt5Refresher *pOurRefresher = (CNt5Refresher *) pRefresher;
pOurRefresher->AddObject(pOurCopy, plId);
// Return a copy of the internal object.
// =====================================
pOurCopy->AddRef();
*ppRefreshable = pOurCopy;
*plId = LONG(dwIndex);
return NO_ERROR;
}
//***************************************************************************
//
// CNt5Refresher::StopRefreshing
//
// 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 CNt5PerfProvider::StopRefreshing(
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
/* [in] */ long lId,
/* [in] */ long lFlags
)
{
// 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.
// =========================================================
CNt5Refresher *pOurRefresher = (CNt5Refresher *) pRefresher;
pOurRefresher->RemoveObject(lId);
return NO_ERROR;
}
//***************************************************************************
//
// CNt5Refresher::CreateRefreshableEnum
//
// Called whenever a user wants to create an enumeration in a refresher.
//
// Parameters:
// <pNamespace> The namespace this is for
// <wszClass> Name of the class we are enumerating
// <pRefresher> The refresher object from which we are to
// remove the perf object.
// <lFlags> Not used.
// <pContext> Wbem Context object
// <pHiPerfEnum> Enumerator object into which refresher should place
// its results
// <plId> The enum id (for identification during removal)
//
//***************************************************************************
// ok
HRESULT CNt5PerfProvider::CreateRefreshableEnum(
/* [in] */ IWbemServices* pNamespace,
/* [in, string] */ LPCWSTR wszClass,
/* [in] */ IWbemRefresher* pRefresher,
/* [in] */ long lFlags,
/* [in] */ IWbemContext* pContext,
/* [in] */ IWbemHiPerfEnum* pHiPerfEnum,
/* [out] */ long* plId )
{
// Just a placeholder for now
return E_NOTIMPL;
}
//***************************************************************************
//
// CNt5Refresher::CreateRefreshableEnum
//
// Called whenever a user wants to create an enumeration in a refresher.
//
// Parameters:
// <pNamespace> The namespace this is for
// <lNumObjects> Number of objects in the array
// <apObj> Objects to retrieve (keys are set)
// <lFlags> Not used.
// <pContext> Wbem Context object
// <pHiPerfEnum> Enumerator object into which refresher should place
// its results
// <plId> The enum id (for identification during removal)
//
//***************************************************************************
// ok
HRESULT CNt5PerfProvider::GetObjects(
/* [in] */ IWbemServices* pNamespace,
/* [in] */ long lNumObjects,
/* [in,size_is(lNumObjects)] */ IWbemObjectAccess** apObj,
/* [in] */ long lFlags,
/* [in] */ IWbemContext* pContext)
{
// Just a placeholder for now
return E_NOTIMPL;
}