500 lines
14 KiB
C++
500 lines
14 KiB
C++
/*++
|
|
|
|
Copyright (C) 1998-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Abstract:
|
|
|
|
History:
|
|
|
|
--*/
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HiPerfProv.cpp
|
|
//
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
|
|
#include <wbemidl.h>
|
|
#include <wbemint.h>
|
|
|
|
#include "common.h"
|
|
#include "HiPerProv.h"
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// CHiPerfProvider
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
CHiPerfProvider::CHiPerfProvider(CLifeControl *pControl) :
|
|
CUnk(pControl), m_XProviderInit(this), m_XHiPerfProvider(this), m_XRefresher(this)
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::CHiPerfProvider");
|
|
|
|
// Initialize internal instance cache to empty
|
|
for (int i = 0; i < NUM_SAMPLE_INSTANCES; i++)
|
|
m_aInstances[i] = 0;
|
|
|
|
// Initialize property value handles to zero
|
|
m_hName = 0;
|
|
}
|
|
|
|
CHiPerfProvider::~CHiPerfProvider()
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::~CHiPerfProvider");
|
|
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
void* CHiPerfProvider::GetInterface(REFIID riid)
|
|
//ok
|
|
{
|
|
if(riid == IID_IWbemProviderInit)
|
|
return &m_XProviderInit;
|
|
if (riid == IID_IWbemHiPerfProvider)
|
|
return &m_XHiPerfProvider;
|
|
if (riid == IID_IUnknown)
|
|
return &m_XHiPerfProvider;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// COM implementations
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CHiPerfProvider::SetHandles(IWbemClassObject* pSampleClass)
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::SetHandles");
|
|
|
|
// Get the property handles for the well-known properties in
|
|
// this counter type. These property handles are available
|
|
// to all nested classes of HiPerfProvider
|
|
IWbemObjectAccess *pAccess;
|
|
LONG hName = 0;
|
|
HRESULT hRes = 0;
|
|
BSTR PropName = 0;
|
|
|
|
hRes = pSampleClass->QueryInterface(IID_IWbemObjectAccess, (LPVOID *)&pAccess);
|
|
if (FAILED(hRes))
|
|
{
|
|
LOGERROR("Could not retrieve the IWbemObjectAccess object");
|
|
return hRes;
|
|
}
|
|
|
|
// Name handle
|
|
PropName = SysAllocString(L"Name");
|
|
hRes = pAccess->GetPropertyHandle(PropName, 0, &hName);
|
|
if (FAILED(hRes))
|
|
{
|
|
LOGERROR("Could not get access handle for Name property");
|
|
pAccess->Release();
|
|
return hRes;
|
|
}
|
|
m_hName = hName;
|
|
SysFreeString(PropName);
|
|
|
|
pAccess->Release();
|
|
return WBEM_NO_ERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CHiPerfProvider::XProviderInit::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)
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::XProviderInit::Initialize");
|
|
|
|
IWbemClassObject *pSampleClass = 0;
|
|
IWbemObjectAccess *pAccess = 0;
|
|
|
|
// Get a copy of our sample class def so that we can create & maintain
|
|
// instances of it.
|
|
BSTR bstrObject = SysAllocString(SAMPLE_CLASS);
|
|
|
|
HRESULT hRes = pNamespace->GetObject(bstrObject, 0, pCtx, &pSampleClass, 0);
|
|
|
|
SysFreeString(bstrObject);
|
|
|
|
if (FAILED(hRes))
|
|
{
|
|
LOGERROR("Could not create a sample object");
|
|
return hRes;
|
|
}
|
|
|
|
hRes = m_pObject->SetHandles(pSampleClass);
|
|
if (FAILED(hRes))
|
|
{
|
|
pSampleClass->Release();
|
|
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;
|
|
|
|
hRes = pSampleClass->SpawnInstance(0, &pInst);
|
|
if (FAILED(hRes))
|
|
{
|
|
LOGERROR("Could not spawn an instance of the sample class");
|
|
pSampleClass->Release();
|
|
return hRes;
|
|
}
|
|
|
|
// Get the IWbemObjectAccess interface and cache it
|
|
pInst->QueryInterface(IID_IWbemObjectAccess, (LPVOID *)&pAccess);
|
|
pInst->Release();
|
|
|
|
// Set the instance's name.
|
|
WCHAR wcsName[128];
|
|
swprintf(wcsName, L"Inst_%d", i);
|
|
hRes = pAccess->WritePropertyValue(m_pObject->m_hName, (wcslen(wcsName)+1)*sizeof(wchar_t), (BYTE*)wcsName);
|
|
if (FAILED(hRes))
|
|
{
|
|
LOGERROR("Failed to set name of sample class");
|
|
pSampleClass->Release();
|
|
pAccess->Release();
|
|
return hRes;
|
|
}
|
|
|
|
// Add to the instance array
|
|
m_pObject->m_aInstances[i] = pAccess;
|
|
}
|
|
|
|
// 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(WBEM_S_INITIALIZED, 0);
|
|
|
|
pSampleClass->Release();
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::XHiPerfProvider::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 )
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::XHiPerfProvider::QueryInstances");
|
|
|
|
HRESULT hRes;
|
|
|
|
if (pNamespace == 0 || wszClass == 0 || pSink == 0)
|
|
return WBEM_E_INVALID_PARAMETER;
|
|
|
|
for (int i = 0; i < NUM_SAMPLE_INSTANCES; i++)
|
|
{
|
|
IWbemObjectAccess *pAccess = m_pObject->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;
|
|
hRes = pAccess->QueryInterface(IID_IWbemClassObject, (LPVOID *) &pOtherFormat);
|
|
if (FAILED(hRes))
|
|
{
|
|
LOGERROR("Could not obtain the IWbemClassObject interface");
|
|
return hRes;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::XHiPerfProvider::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> Not used.
|
|
// <ppRefresher> Receives the requested refresher.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
LOG("CContinousProvider::XContinousProvider::CreateRefresher");
|
|
|
|
*ppRefresher = NULL;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::XHiPerfProvider::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.
|
|
//
|
|
// 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
|
|
{
|
|
LOG("CHiPerfProvider::XHiPerfProvider::CreateRefreshableObject");
|
|
|
|
// Find out which object is being requested for addition.
|
|
wchar_t wcsBuf[128];
|
|
*wcsBuf = 0;
|
|
LONG lNameLength = 0;
|
|
pTemplate->ReadPropertyValue(m_pObject->m_hName, (wcslen(wcsBuf)+1)*sizeof(wchar_t), &lNameLength, LPBYTE(wcsBuf));
|
|
|
|
// Scan out the index from the instance name. We only do this
|
|
// because the instance name is a string.
|
|
DWORD dwIndex = 0;
|
|
swscanf(wcsBuf, L"Inst_%u", &dwIndex);
|
|
|
|
// Now we know which object is desired.
|
|
IWbemObjectAccess *pOurCopy = m_pObject->m_aInstances[dwIndex];
|
|
|
|
pOurCopy->ReadPropertyValue(m_pObject->m_hName, 128, &lNameLength, LPBYTE(wcsBuf));
|
|
|
|
char szbuf[256];
|
|
wcstombs(szbuf, wcsBuf, 127);
|
|
LOG(szbuf);
|
|
|
|
// 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.
|
|
XRefresher *pOurRefresher;
|
|
|
|
if (pRefresher)
|
|
{
|
|
LOG ("NON-NULL refresher");
|
|
pOurRefresher = (XRefresher *) pRefresher;
|
|
}
|
|
else
|
|
{
|
|
LOG ("NULL refresher");
|
|
pOurRefresher = &m_pObject->m_XRefresher;
|
|
}
|
|
|
|
if(pOurRefresher)
|
|
pOurRefresher->AddObject(pOurCopy, plId);
|
|
|
|
// Return a copy of the internal object.
|
|
pOurCopy->AddRef();
|
|
*ppRefreshable = pOurCopy;
|
|
*plId = LONG(dwIndex);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::XHiPerfProvider::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
|
|
{
|
|
LOG("CHiPerfProvider::XHiPerfProvider::StopRefreshing");
|
|
|
|
// 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.
|
|
XRefresher *pOurRefresher;
|
|
|
|
if (pRefresher)
|
|
{
|
|
LOG ("NON-NULL refresher");
|
|
pOurRefresher = (XRefresher *) pRefresher;
|
|
}
|
|
else
|
|
{
|
|
LOG ("NULL refresher");
|
|
pOurRefresher = &m_pObject->m_XRefresher;
|
|
}
|
|
|
|
pOurRefresher->RemoveObject(lId);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::XHiPerfProvider::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
|
|
LOG("CHiPerfProvider::XHiPerfProvider::CreateRefreshableEnum");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CHiPerfProvider::XHiPerfProvider::GetObjects(
|
|
/* [in] */ IWbemServices* pNamespace,
|
|
/* [in] */ long lNumObjects,
|
|
/* [in,size_is(lNumObjects)] */ IWbemObjectAccess** apObj,
|
|
/* [in] */ long lFlags,
|
|
/* [in] */ IWbemContext* pContext)
|
|
{
|
|
// Just a placeholder for now
|
|
LOG("CHiPerfProvider::XHiPerfProvider::GetObjects");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
CHiPerfProvider::XRefresher::XRefresher(CHiPerfProvider *pObject) :
|
|
CImpl<IWbemRefresher, CHiPerfProvider>(pObject)
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::XRefresher::XRefresher");
|
|
// Initialize the instance cache to be empty
|
|
for (int i = 0; i < NUM_SAMPLE_INSTANCES; i++)
|
|
m_aRefInstances[i] = 0;
|
|
}
|
|
|
|
CHiPerfProvider::XRefresher::~XRefresher()
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::XRefresher::~XRefresher");
|
|
// Release the cached IWbemObjectAccess instances.
|
|
for (DWORD i = 0; i < NUM_SAMPLE_INSTANCES; i++)
|
|
{
|
|
if (m_aRefInstances[i])
|
|
m_aRefInstances[i]->Release();
|
|
}
|
|
}
|
|
|
|
BOOL CHiPerfProvider::XRefresher::AddObject(IWbemObjectAccess *pObj, LONG *plId)
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Adds an object to the refresher. This is a private mechanism
|
|
// used by CHiPerfProvider and not part of the COM interface.
|
|
//
|
|
// The ID we return for future identification is simply
|
|
// the array index.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::XRefresher::AddObject");
|
|
|
|
for (DWORD i = 0; i < NUM_SAMPLE_INSTANCES; i++)
|
|
{
|
|
if (m_aRefInstances[i] == 0)
|
|
{
|
|
pObj->AddRef();
|
|
m_aRefInstances[i] = pObj;
|
|
|
|
// The ID we return for future identification is simply
|
|
// the array index.
|
|
*plId = i;
|
|
LOG("Added Object");
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
LOGERROR("Failed to Add Object");
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CHiPerfProvider::XRefresher::RemoveObject(LONG lId)
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Removes an object from the refresher. This is a private mechanism
|
|
// used by CHiPerfProvider 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.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::XRefresher::RemoveObject");
|
|
|
|
if (m_aRefInstances[lId] == 0)
|
|
return FALSE;
|
|
|
|
m_aRefInstances[lId]->Release();
|
|
m_aRefInstances[lId] = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT CHiPerfProvider::XRefresher::Refresh(/* [in] */ long lFlags)
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Executed to refresh a set of instances bound to the particular
|
|
// refresher.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
//ok
|
|
{
|
|
LOG("CHiPerfProvider::XRefresher::Refresh");
|
|
return NO_ERROR;
|
|
}
|