Windows2003-3790/sdktools/pdh/wbemperf/ntperf.cpp

1076 lines
35 KiB
C++
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
ntperf.cpp
Abstract:
Mapped NT5 Perf counter provider
History:
raymcc 02-Dec-97 Created.
raymcc 20-Feb-98 Updated to use new initializer.
bobw 8-Jun-98 tuned up
--*/
#include "wpheader.h"
#include <stdio.h>
#include "oahelp.inl"
//***************************************************************************
//
// CNt5PerfProvider constructor
//
//***************************************************************************
// ok
CNt5PerfProvider::CNt5PerfProvider(enumCLSID OriginClsid)
{
m_lRef = 0;
m_OriginClsid = OriginClsid;
m_hClassMapMutex = CreateMutex(NULL, FALSE, NULL);
}
//***************************************************************************
//
// CNt5PerfProvider destructor
//
//***************************************************************************
// ok
CNt5PerfProvider::~CNt5PerfProvider()
{
int i;
CClassMapInfo *pClassElem;
assert (m_lRef == 0);
for (i = 0; i < m_aCache.Size(); i++) {
pClassElem = (CClassMapInfo *) m_aCache[i];
m_PerfObject.RemoveClass (pClassElem->m_pClassDef);
delete pClassElem;
}
m_aCache.Empty(); // reset the buffer pointers
if (m_hClassMapMutex != 0)
CloseHandle(m_hClassMapMutex);
// RegCloseKey(HKEY_PERFORMANCE_DATA); // causes more problems than it solves
}
//***************************************************************************
//
// CNt5PerfProvider::AddRef
//
// Standard COM AddRef().
//
//***************************************************************************
// ok
ULONG CNt5PerfProvider::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
//***************************************************************************
//
// CNt5PerfProvider::Release
//
// Standard COM Release().
//
//***************************************************************************
// ok
ULONG CNt5PerfProvider::Release()
{
long lRef = InterlockedDecrement(&m_lRef);
if(lRef == 0) {
delete this;
}
return lRef;
}
//***************************************************************************
//
// CNt5PerfProvider::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)
{
HRESULT hReturn;
if (riid == IID_IUnknown || riid == IID_IWbemHiPerfProvider) {
*ppv = (IWbemHiPerfProvider*) this;
AddRef();
hReturn = S_OK;
} else if (riid == IID_IWbemProviderInit) {
*ppv = (IWbemProviderInit *) this;
AddRef();
hReturn = S_OK;
} else {
*ppv = NULL;
hReturn = E_NOINTERFACE;
}
return hReturn;
}
//***************************************************************************
//
// CNt5PerfProvider::Initialize
//
// Called once during startup. Indicates to the provider which
// namespace it is being invoked for and which User. It also supplies
// a back pointer to CIMOM 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 CIMOM.
// <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
)
{
UNREFERENCED_PARAMETER(wszUser);
UNREFERENCED_PARAMETER(lFlags);
UNREFERENCED_PARAMETER(wszNamespace);
UNREFERENCED_PARAMETER(wszLocale);
UNREFERENCED_PARAMETER(pNamespace);
UNREFERENCED_PARAMETER(pCtx);
pInitSink->SetStatus(0, WBEM_S_INITIALIZED);
return NO_ERROR;
}
//***************************************************************************
//
// CNt5PerfProvider::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 or retained past the
// execution of this method.
// <wszClass> The class name for which instances are required.
// <lFlags> Reserved.
// <pCtx> The user-supplied context (used during callbacks
// into CIMOM).
// <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
)
{
HRESULT hReturn;
BOOL bRes ;
CClassMapInfo *pClsMap = NULL;
UNREFERENCED_PARAMETER(lFlags);
hReturn = CoImpersonateClient(); // make sure we're legit.
BOOL fRevert = SUCCEEDED( hReturn );
// The following error appears to occur when we are in-proc and there is no
// proxy/stub, so we are effectively impersonating already
if ( RPC_E_CALL_COMPLETE == hReturn ) {
hReturn = S_OK;
}
if (S_OK == hReturn) {
hReturn = CheckImpersonationLevel();
}
// Check Registry security here.
if ((hReturn != S_OK) || (!HasPermission())) {
// if Impersonation level is incorrect or
// the caller doesn't have permission to read
// from the registry, then they cannot continue
hReturn = WBEM_E_ACCESS_DENIED;
}
if (hReturn == S_OK) {
if (pNamespace == 0 || wszClass == 0 || pSink == 0) {
hReturn = WBEM_E_INVALID_PARAMETER;
} else {
// Ensure the class is in our cache and mapped.
// ============================================
bRes = MapClass(pNamespace, wszClass, pCtx);
if (bRes == FALSE) {
// Class is not one of ours.
hReturn = WBEM_E_INVALID_CLASS;
} else {
pClsMap = FindClassMap(wszClass);
if (pClsMap == NULL) {
hReturn = WBEM_E_INVALID_CLASS;
}
}
if (hReturn == NO_ERROR) {
// Refresh the instances.
// ======================
PerfHelper::QueryInstances(&m_PerfObject, pClsMap, pSink);
// Tell CIMOM we are finished.
// ===========================
pSink->SetStatus(0, WBEM_NO_ERROR, 0, 0);
hReturn = NO_ERROR;
}
}
} else {
// return error
}
// Revert if we successfuly impersonated the user
if ( fRevert )
{
CoRevertToSelf();
}
return hReturn;
}
//***************************************************************************
//
// CNt5PerfProvider::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
)
{
HRESULT hReturn;
CNt5Refresher *pNewRefresher;
UNREFERENCED_PARAMETER(lFlags);
hReturn = CoImpersonateClient(); // make sure we're legit.
BOOL fRevert = SUCCEEDED( hReturn );
// The following error appears to occur when we are in-proc and there is no
// proxy/stub, so we are effectively impersonating already
if ( RPC_E_CALL_COMPLETE == hReturn ) {
hReturn = S_OK;
}
if (S_OK == hReturn) {
hReturn = CheckImpersonationLevel();
}
// Check Registry security here.
if ((hReturn != S_OK) || (!HasPermission())) {
// if Impersonation level is incorrect or
// the caller doesn't have permission to read
// from the registry, then they cannot continue
hReturn = WBEM_E_ACCESS_DENIED;
}
if (hReturn == S_OK) {
if (pNamespace == 0 || ppRefresher == 0) {
hReturn = WBEM_E_INVALID_PARAMETER;
} else {
// Construct a new empty refresher.
// ================================
pNewRefresher = new CNt5Refresher (this);
if (pNewRefresher != NULL) {
// Follow COM rules and AddRef() the thing before sending it back.
// ===============================================================
pNewRefresher->AddRef();
*ppRefresher = pNewRefresher;
hReturn = NO_ERROR;
} else {
hReturn = WBEM_E_OUT_OF_MEMORY;
}
}
}
// Revert if we successfuly impersonated the user
if ( fRevert )
{
CoRevertToSelf();
}
return hReturn;
}
//***************************************************************************
//
// CNt5PerfProvider::CreateRefresherObject
//
// Called whenever a user wants to include an object in a refresher.
//
// Parameters:
// <pNamespace> A pointer to the relevant namespace in CIMOM.
// <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::CreateRefresherObject(
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
/* [in] */ IWbemObjectAccess __RPC_FAR *pTemplate,
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
/* [in] */ long lFlags,
/* [in] */ IWbemContext __RPC_FAR *pContext,
/* [string][in] */ LPCWSTR wszClass,
/* [in] */ IWbemHiPerfEnum __RPC_FAR *pHiPerfEnum,
/* [out] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *ppRefreshable,
/* [out] */ long __RPC_FAR *plId
)
{
IWbemClassObject *pOriginal = 0;
IWbemClassObject *pNewCopy = 0;
IWbemObjectAccess *pNewAccess = 0;
CNt5Refresher *pRef = 0;
CClassMapInfo *pClsMap;
VARIANT v;
BOOL bRes;
HRESULT hReturn = NO_ERROR;
CBSTR cbClassName(cszClassName);
UNREFERENCED_PARAMETER(lFlags);
if( NULL == (BSTR)cbClassName ){
return WBEM_E_OUT_OF_MEMORY;
}
if (ppRefreshable != NULL) {
// Initialize the argument
*ppRefreshable = 0;
}
// init the variant
VariantInit(&v);
if (pTemplate != NULL) {
// Make a copy of the template object.
// ===================================
hReturn = pTemplate->QueryInterface(IID_IWbemClassObject, (LPVOID *) &pOriginal);
if (hReturn == NO_ERROR) {
hReturn = pOriginal->Clone(&pNewCopy);
// Get the class name of the object.
// =================================
if (hReturn == NO_ERROR) {
hReturn = pOriginal->Get( cbClassName, 0, &v, 0, 0);
if ((hReturn == NO_ERROR) && (v.vt != VT_BSTR)) {
hReturn = WBEM_E_INVALID_CLASS;
}
}
// We are now done with the original object
// ========================================
pOriginal->Release();
}
if (hReturn == NO_ERROR) {
// We now get the IWbemObjectAccess form of the cloned object
// and release the unused interface.
// ==========================================================
hReturn = pNewCopy->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewAccess);
}
if( NULL != pNewCopy ){
pNewCopy->Release();
}
} else {
// copy the class name passed in
v.vt = VT_BSTR;
v.bstrVal = SysAllocString(wszClass);
}
if (hReturn == NO_ERROR) {
// cast refresher pointer to our refresher object
pRef = (CNt5Refresher *) pRefresher;
// Map the class info for this instance.
// =====================================
bRes = MapClass(pNamespace, V_BSTR(&v), pContext);
if (bRes == FALSE) {
// Class is not one of ours.
if (pNewAccess != NULL) pNewAccess->Release();
hReturn = WBEM_E_INVALID_CLASS;
} else {
pClsMap = FindClassMap(V_BSTR(&v));
if (pClsMap == 0) {
if (pNewAccess != NULL) pNewAccess->Release();
hReturn = WBEM_E_INVALID_CLASS;
} else {
// Add the object to the refresher.
if (pHiPerfEnum != NULL) {
// then this is an Enum object so add it
bRes = pRef->AddEnum (
pHiPerfEnum,
pClsMap,
plId);
if (bRes) {
// Return new ID to caller
// ==========================
hReturn = NO_ERROR;
} else {
// unable to add enumerator
pNewAccess->Release();
hReturn = GetLastError();
}
} else {
// This method will AddRef() the object before returning.
// ======================================================
bRes = pRef->AddObject(
&pNewAccess,
pClsMap,
plId);
if (bRes) {
// Return object to the user.
// ==========================
*ppRefreshable = pNewAccess;
hReturn = NO_ERROR;
} else {
// unable to add object
pNewAccess->Release();
hReturn = GetLastError();
}
}
}
}
}
VariantClear(&v);
return hReturn;
}
//***************************************************************************
//
// CNt5PerfProvider::CreateRefreshableObject
//
// Called whenever a user wants to include an object in a refresher.
//
// Parameters:
// <pNamespace> A pointer to the relevant namespace in CIMOM.
// <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
)
{
HRESULT hReturn = NO_ERROR;
hReturn = CoImpersonateClient(); // make sure we're legit.
BOOL fRevert = SUCCEEDED( hReturn );
// The following error appears to occur when we are in-proc and there is no
// proxy/stub, so we are effectively impersonating already
if ( RPC_E_CALL_COMPLETE == hReturn ) {
hReturn = S_OK;
}
if (S_OK == hReturn) {
hReturn = CheckImpersonationLevel();
}
// Check Registry security here.
if ((hReturn != S_OK) || (!HasPermission())) {
// if Impersonation level is incorrect or
// the caller doesn't have permission to read
// from the registry, then they cannot continue
hReturn = WBEM_E_ACCESS_DENIED;
}
if (hReturn == S_OK) {
hReturn = CreateRefresherObject(
pNamespace,
pTemplate,
pRefresher,
lFlags,
pContext,
NULL,
NULL,
ppRefreshable,
plId);
}
// Revert if we successfuly impersonated the user
if ( fRevert )
{
CoRevertToSelf();
}
return hReturn;
}
//***************************************************************************
//
// CNt5PerfProvider::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
)
{
CNt5Refresher *pRef;
BOOL bRes ;
HRESULT hReturn;
UNREFERENCED_PARAMETER(lFlags);
hReturn = CoImpersonateClient(); // make sure we're legit.
BOOL fRevert = SUCCEEDED( hReturn );
// The following error appears to occur when we are in-proc and there is no
// proxy/stub, so we are effectively impersonating already
if ( RPC_E_CALL_COMPLETE == hReturn ) {
hReturn = S_OK;
}
if (S_OK == hReturn) {
hReturn = CheckImpersonationLevel();
}
// Check Registry security here.
if ((hReturn != S_OK) || (!HasPermission())) {
// if Impersonation level is incorrect or
// the caller doesn't have permission to read
// from the registry, then they cannot continue
hReturn = WBEM_E_ACCESS_DENIED;
}
if (hReturn == S_OK) {
pRef = (CNt5Refresher *) pRefresher;
bRes = pRef->RemoveObject(lId);
if (bRes == FALSE) {
hReturn = WBEM_E_FAILED;
} else {
hReturn = WBEM_NO_ERROR;
}
}
// Revert if we successfuly impersonated the user
if ( fRevert )
{
CoRevertToSelf();
}
return hReturn;
}
HRESULT CNt5PerfProvider::CreateRefreshableEnum(
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
/* [string][in] */ LPCWSTR wszClass,
/* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
/* [in] */ long lFlags,
/* [in] */ IWbemContext __RPC_FAR *pContext,
/* [in] */ IWbemHiPerfEnum __RPC_FAR *pHiPerfEnum,
/* [out] */ long __RPC_FAR *plId)
{
HRESULT hReturn;
hReturn = CoImpersonateClient(); // make sure we're legit.
BOOL fRevert = SUCCEEDED( hReturn );
// The following error appears to occur when we are in-proc and there is no
// proxy/stub, so we are effectively impersonating already
if ( RPC_E_CALL_COMPLETE == hReturn ) {
hReturn = S_OK;
}
if (S_OK == hReturn) {
hReturn = CheckImpersonationLevel();
}
// Check Registry security here.
if ((hReturn != S_OK) || (!HasPermission())) {
// if Impersonation level is incorrect or
// the caller doesn't have permission to read
// from the registry, then they cannot continue
hReturn = WBEM_E_ACCESS_DENIED;
}
if (hReturn == S_OK) {
hReturn = CreateRefresherObject(
pNamespace,
NULL,
pRefresher,
lFlags,
pContext,
wszClass,
pHiPerfEnum,
NULL,
plId);
}
// Revert if we successfuly impersonated the user
if ( fRevert )
{
CoRevertToSelf();
}
return hReturn;
}
HRESULT CNt5PerfProvider::GetObjects(
/* [in] */ IWbemServices __RPC_FAR *pNamespace,
/* [in] */ long lNumObjects,
/* [size_is][in] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *apObj,
/* [in] */ long lFlags,
/* [in] */ IWbemContext __RPC_FAR *pContext)
{
DBG_UNREFERENCED_PARAMETER(pNamespace);
DBG_UNREFERENCED_PARAMETER(lNumObjects);
DBG_UNREFERENCED_PARAMETER(apObj);
DBG_UNREFERENCED_PARAMETER(lFlags);
DBG_UNREFERENCED_PARAMETER(pContext);
return WBEM_E_METHOD_NOT_IMPLEMENTED;
}
//***************************************************************************
//
// CNt5PerfProvider::MapClass
//
// Adds the class map to an internal cache.
//
// <pClsMap> The pointer to the map info to add. This pointer
// is acquired by this function and should not be
// deleted by the caller.
//
//***************************************************************************
// ok
BOOL CNt5PerfProvider::AddClassMap(
IN CClassMapInfo *pClsMap
)
{
DWORD dwResult = ERROR_SUCCESS;
int i;
CClassMapInfo *pTracer;
int nNumElements;
BOOL bInCache = FALSE;
if (m_hClassMapMutex != 0) {
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hClassMapMutex, cdwClassMapTimeout)) {
nNumElements = m_aCache.Size();
// Because of a problem in which perflibs seem to ignore supported methods of updating
// the perflib names database (lodctr/unlodctr), do a quick initial traversal to ensure
// that we don't have any duplicate object indices, since this can cause real problems
// during adding and refreshing, since incorrect indexes can be returned.
for (i = 0; i < nNumElements; i++) {
pTracer = (CClassMapInfo *) m_aCache[i];
// We've got a problem -- we cannot add this class
if (pClsMap->m_dwObjectId == pTracer->m_dwObjectId )
{
if (m_PerfObject.CheckClassExist(pTracer->m_pszClassName, pTracer->m_pClassDef)) {
ReleaseMutex(m_hClassMapMutex);
return FALSE;
}
else {
m_PerfObject.RemoveClass(pTracer->m_pClassDef);
m_aCache.RemoveAt(i);
delete pTracer;
nNumElements = m_aCache.Size();
break;
}
}
}
for (i = 0; i < nNumElements; i++) {
pTracer = (CClassMapInfo *) m_aCache[i];
if (_wcsicmp(pClsMap->m_pszClassName, pTracer->m_pszClassName) < 0) {
if( CFlexArray::no_error == m_aCache.InsertAt(i, pClsMap) ){
bInCache = TRUE;
}
break;
}
}
if (i == nNumElements) {
// If here, add it to the end.
// ===========================
if( CFlexArray::no_error == m_aCache.Add(pClsMap) ){
bInCache = TRUE;
}
}
// make sure the library is in the list
if( bInCache ){
dwResult = m_PerfObject.AddClass (pClsMap->m_pClassDef, TRUE);
if( ERROR_SUCCESS != dwResult ){
m_aCache.Remove( pClsMap );
}
}else{
dwResult = ERROR_INVALID_BLOCK;
}
ReleaseMutex(m_hClassMapMutex);
} else {
dwResult = ERROR_LOCK_FAILED;
}
}
return (dwResult == ERROR_SUCCESS);
}
//***************************************************************************
//
// CNt5PerfProvider::FindClassMap
//
//***************************************************************************
// ok
CClassMapInfo *CNt5PerfProvider::FindClassMap(
LPWSTR pszClassName
)
{
int l = 0;
int u;
int m;
CClassMapInfo *pClsMap;
CClassMapInfo *pClsMapReturn = NULL;
// Binary search the cache.
// ========================
if( NULL == pszClassName ){
return NULL;
}
if (m_hClassMapMutex != 0) {
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hClassMapMutex, cdwClassMapTimeout)) {
u = m_aCache.Size() - 1;
__try{
while (l <= u) {
m = (l + u) / 2;
pClsMap = (CClassMapInfo *) m_aCache[m];
if (pClsMap != NULL) {
if (_wcsicmp(pszClassName, pClsMap->m_pszClassName) < 0) {
u = m - 1;
} else if (_wcsicmp(pszClassName, pClsMap->m_pszClassName) > 0) {
l = m + 1;
} else { // Hit!
pClsMapReturn = pClsMap;
break;
}
} else {
break;
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
pClsMapReturn = NULL;
}
ReleaseMutex(m_hClassMapMutex);
}
}
return pClsMapReturn;
}
//***************************************************************************
//
// CNt5PerfProvider::MapClass
//
// Retrieves the requested class and places it in the cache.
//
// Parameters:
// pNs The namespace which contains the class definition.
// wsClass The class name.
// pCtx The inbound context object. Only used for reentrant
// calls.
//
//***************************************************************************
// ok
BOOL CNt5PerfProvider::MapClass(
IN IWbemServices *pNs,
IN WCHAR *wszClass,
IN IWbemContext *pCtx
)
{
HRESULT hRes = 0;
BOOL bReturn = FALSE;
IWbemClassObject *pClsDef = 0;
IWbemQualifierSet *pQSet = 0;
VARIANT v;
CClassMapInfo *pMapInfo = 0;
CBSTR cbClass(wszClass);
CBSTR cbProvider(cszProvider);
if( NULL == (BSTR)cbClass ||
NULL == (BSTR)cbProvider ){
return FALSE;
}
if (m_hClassMapMutex != 0) {
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hClassMapMutex, cdwClassMapTimeout)) {
// See if the class is already in the cache.
// =========================================
if (FindClassMap(wszClass) != 0) {
// already loaded so quit now
bReturn = TRUE;
} else {
// Get the class definition from CIMOM.
// ====================================
hRes = pNs->GetObject( cbClass, 0, pCtx, &pClsDef, 0);
if (hRes == NO_ERROR) {
// Verify the class is one of ours by checking
// the "provider" qualifier to ensure it matches
// the name that we we have for this component.
// =============================================
hRes = pClsDef->GetQualifierSet(&pQSet);
if (hRes == NO_ERROR) {
VariantInit(&v);
hRes = pQSet->Get( cbProvider, 0, &v, 0);
pQSet->Release();
if ((hRes == NO_ERROR) && (v.vt == VT_BSTR)) {
if (_wcsicmp(V_BSTR(&v), cszProviderName) == 0) {
// Get the property handles and mappings to the perf counter ids
// by calling the Map() method of CClassMapInfo.
// ==============================================================
pMapInfo = new CClassMapInfo;
if (pMapInfo != NULL) {
if (pMapInfo->Map(pClsDef)) {
// Add it to the cache.
// ====================
bReturn = AddClassMap(pMapInfo);
if( !bReturn ){
delete pMapInfo;
}
} else {
// unable to add this to the cache
delete pMapInfo;
pMapInfo = NULL;
}
} else {
// inable to create new class
bReturn = FALSE;
}
}
} else {
SetLastError ((DWORD)WBEM_E_INVALID_PROVIDER_REGISTRATION);
}
VariantClear(&v);
}
}
if( pMapInfo == NULL && pClsDef != NULL ){
pClsDef->Release();
}
}
ReleaseMutex(m_hClassMapMutex);
}
}
return bReturn;
}
//***************************************************************************
//
// CNt5PerfProvider::HasPermission
//
// tests to see if the caller has permission to access the functions
//
// Parameters:
// void N/A
//
//***************************************************************************
// ok
BOOL CNt5PerfProvider::HasPermission (void)
{
DWORD dwStatus;
HKEY hKeyTest;
BOOL bReturn;
dwStatus = RegOpenKeyExW (
HKEY_LOCAL_MACHINE,
(LPCWSTR)L"Software\\Microsoft\\Windows NT\\CurrentVersion\\WbemPerf",
0, KEY_READ, &hKeyTest);
if ((dwStatus == ERROR_SUCCESS) || (dwStatus == ERROR_FILE_NOT_FOUND)) {
bReturn = TRUE;
if (dwStatus == ERROR_SUCCESS) RegCloseKey (hKeyTest);
} else {
bReturn = FALSE;
}
return bReturn;
}
//***************************************************************************
//
// CNt5PerfProvider::CheckImpersonationLevel
//
// tests caller's security impersonation level for correct access
//
// Only call here if CoImpersonate worked.
//
// Parameters:
// void N/A
//
//***************************************************************************
// ok
HRESULT CNt5PerfProvider::CheckImpersonationLevel (void)
{
HRESULT hr = WBEM_E_ACCESS_DENIED;
BOOL bReturn;
// Now, let's check the impersonation level. First, get the thread token
HANDLE hThreadTok;
DWORD dwImp, dwBytesReturned;
bReturn = OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY,
TRUE,
&hThreadTok);
if (!bReturn) {
// If the CoImpersonate works, but the OpenThreadToken fails, we are running under the
// process token (either local system, or if we are running with /exe, the rights of
// the logged in user). In either case, impersonation rights don't apply. We have the
// full rights of that user.
hr = WBEM_S_NO_ERROR;
} else {
// We really do have a thread token, so let's retrieve its level
bReturn = GetTokenInformation(
hThreadTok,
TokenImpersonationLevel,
&dwImp,
sizeof(DWORD),
&dwBytesReturned);
if (bReturn) {
// Is the impersonation level Impersonate?
if ((dwImp == SecurityImpersonation) || (dwImp == SecurityDelegation)) {
hr = WBEM_S_NO_ERROR;
} else {
hr = WBEM_E_ACCESS_DENIED;
}
} else {
hr = WBEM_E_FAILED;
}
// Done with this handle
CloseHandle(hThreadTok);
}
return hr;
}