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

600 lines
19 KiB
C++

/*++
Copyright (C) 1997-2001 Microsoft Corporation
Module Name:
Abstract:
History:
--*/
//***************************************************************************
//
// PERFHELP.CPP
//
// Registry-based performance counter reading helper
//
//***************************************************************************
#include "precomp.h"
#include <stdio.h>
#include <wbemidl.h>
#include <wbemint.h>
#include "flexarry.h"
#include "ntperf.h"
#include "perfhelp.h"
#include "refreshr.h"
//***************************************************************************
//
// PerfHelper::GetInstances
//
// This is called to retrieve all instances of a given class.
//
// Parameters:
// <pBuf> The perf blob retrieved from HKEY_PERFORMANCE_DATA.
// <pClassMap> A map object of the class required.
// <pSink> The sink to which to deliver the objects.
//
//***************************************************************************
void PerfHelper::GetInstances(
LPBYTE pBuf,
CClassMapInfo *pClassMap,
IWbemObjectSink *pSink
)
{
PPERF_OBJECT_TYPE PerfObj = 0;
PPERF_INSTANCE_DEFINITION PerfInst = 0;
PPERF_COUNTER_DEFINITION PerfCntr = 0, CurCntr = 0;
PPERF_COUNTER_BLOCK PtrToCntr = 0;
PPERF_DATA_BLOCK PerfData = (PPERF_DATA_BLOCK) pBuf;
DWORD i, j, k;
// Get the first object type.
// ==========================
PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfData +
PerfData->HeaderLength);
// Process all objects.
// ====================
for (i = 0; i < PerfData->NumObjectTypes; i++ )
{
// Within each PERF_OBJECT_TYPE is a series of
// PERF_COUNTER_DEFINITION blocks.
// ==========================================
PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj +
PerfObj->HeaderLength);
// If the current object isn't of the class we requested,
// simply skip over it. I am not sure if this can really
// happen or not in practice.
// ======================================================
if (PerfObj->ObjectNameTitleIndex != pClassMap->m_dwObjectId)
{
PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +
PerfObj->TotalByteLength);
continue;
}
if (PerfObj->NumInstances > 0)
{
// Get the first instance.
// =======================
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj +
PerfObj->DefinitionLength);
// Retrieve all instances.
// =======================
for (k = 0; k < DWORD(PerfObj->NumInstances); k++ )
{
CurCntr = PerfCntr;
// Get the first counter.
// ======================
PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst +
PerfInst->ByteLength);
// Quickly clone a new instance to send back to the user.
// Since SpawnInstance() returns an IWbemClassObject and
// we really need an IWbemObjectAccess,we have to QI
// after the spawn. We need to fix this, as this number
// of calls is too time consuming.
// ======================================================
IWbemObjectAccess *pNewInst = 0;
IWbemClassObject *pClsObj = 0;
pClassMap->m_pClassDef->SpawnInstance(0, &pClsObj);
pClsObj->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewInst);
pClsObj->Release(); // We only need the IWbemObjectAccess pointer
// Locate the instance name.
// ==========================
LPWSTR pName = (LPWSTR) ((PBYTE)PerfInst + PerfInst->NameOffset);
// Retrieve all counters.
// ======================
for(j = 0; j < PerfObj->NumCounters; j++ )
{
// Find the WBEM property handle based on the counter title index.
// This function does a quick binary search of the class map object
// to find the handle that goes with this counter.
// ================================================================
LONG hPropHandle = pClassMap->GetPropHandle(CurCntr->CounterNameTitleIndex);
if (hPropHandle == 0)
continue;
// Data is (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);
// Only supporting simple DWORD types for now. BobW knows more about
// all this stuff and can extend it properly.
// ==================================================================
if ((CurCntr->CounterType & 0x700) == 0)
{
LPDWORD pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset));
HRESULT hRes = pNewInst->WriteDWORD(hPropHandle, *pdwVal);
}
// Get next counter.
// =================
CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr +
CurCntr->ByteLength);
}
// Write the instance 'name'
// =========================
if (pName && pClassMap->m_dwNameHandle)
{
pNewInst->WritePropertyValue(
pClassMap->m_dwNameHandle,
(wcslen(pName) + 1) * 2,
LPBYTE(pName)
);
}
// Deliver the instance to the user.
// =================================
pSink->Indicate(1, (IWbemClassObject **) &pNewInst);
pNewInst->Release();
// Move to the next perf instance.
// ================================
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PtrToCntr +
PtrToCntr->ByteLength);
}
}
// Cases where the counters have no instances.
// ===========================================
else
{
// Get the first counter.
// ======================
PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj +
PerfObj->DefinitionLength );
// Quickly clone a new instance to send back to the user.
// Since SpawnInstance() returns an IWbemClassObject and
// we really need an IWbemObjectAccess,we have to QI
// after the spawn. We need to fix this, as this number
// of calls is too time consuming.
// ======================================================
IWbemObjectAccess *pNewInst = 0;
IWbemClassObject *pClsObj = 0;
pClassMap->m_pClassDef->SpawnInstance(0, &pClsObj);
pClsObj->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewInst);
pClsObj->Release();
// Retrieve all counters.
// ======================
for( j=0; j < PerfObj->NumCounters; j++ )
{
// Find the WBEM property handle based on the counter title index.
// This function does a quick binary search of the class map object
// to find the handle that goes with this counter.
// ================================================================
LONG hPropHandle = pClassMap->GetPropHandle(PerfCntr->CounterNameTitleIndex);
if (hPropHandle == 0)
continue;
// Data is (LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
// We will ignore non-DWORD types for now.
// =======================================
if ((PerfCntr->CounterType & 0x700) == 0)
{
LPDWORD pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset));
HRESULT hRes = pNewInst->WriteDWORD(hPropHandle, *pdwVal);
}
PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr +
PerfCntr->ByteLength);
}
// Since IWbemObjectAccess derives from IWbemClassObject, the following
// cast is legal. Note that indicate wants IWbemClassObject objects.
// ====================================================================
pSink->Indicate(1, (IWbemClassObject **) &pNewInst);
pNewInst->Release();
}
// Get the next object type.
// =========================
PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +
PerfObj->TotalByteLength);
}
}
//***************************************************************************
//
// PerfHelper::RefreshInstances
//
//***************************************************************************
void PerfHelper::RefreshInstances(
LPBYTE pBuf,
CNt5Refresher *pRef
)
{
PPERF_OBJECT_TYPE PerfObj = 0;
PPERF_INSTANCE_DEFINITION PerfInst = 0;
PPERF_COUNTER_DEFINITION PerfCntr = 0, CurCntr = 0;
PPERF_COUNTER_BLOCK PtrToCntr = 0;
PPERF_DATA_BLOCK PerfData = (PPERF_DATA_BLOCK) pBuf;
DWORD i, j, k;
// Get the first object type.
// ==========================
PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfData +
PerfData->HeaderLength);
// Process all objects.
// ====================
for (i = 0; i < PerfData->NumObjectTypes; i++ )
{
// Within each PERF_OBJECT_TYPE is a series of
// PERF_COUNTER_DEFINITION blocks.
// ==========================================
PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj +
PerfObj->HeaderLength);
if (PerfObj->NumInstances > 0)
{
// Get the first instance.
// =======================
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj +
PerfObj->DefinitionLength);
// Retrieve all instances.
// =======================
for (k = 0; k < DWORD(PerfObj->NumInstances); k++ )
{
CurCntr = PerfCntr;
// Get the first counter.
// ======================
PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst +
PerfInst->ByteLength);
// Locate the instance name.
// ==========================
LPWSTR pName = (LPWSTR) ((PBYTE)PerfInst + PerfInst->NameOffset);
// Find the instance in the refresher, if there is one, which
// corresponds to the instance we are looking at.
// ==========================================================
CClassMapInfo *pClassMap = 0;
IWbemObjectAccess *pInst = 0;
BOOL bRes = pRef->FindInst(
PerfObj->ObjectNameTitleIndex, // Object type (WBEM Class)
pName, // Instance name
&pInst,
&pClassMap
);
// Retrieve all counters for the instance if it was one of the instances
// we are supposed to be refreshing.
// =====================================================================
if (bRes)
{
for (j = 0; j < PerfObj->NumCounters; j++ )
{
LONG hPropHandle = pClassMap->GetPropHandle(CurCntr->CounterNameTitleIndex);
if (hPropHandle == 0)
continue;
// Data is (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);
if ((CurCntr->CounterType & 0x700) == 0)
{
LPDWORD pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset));
HRESULT hRes = pInst->WriteDWORD(hPropHandle, *pdwVal);
}
// Get next counter.
// =================
CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr +
CurCntr->ByteLength);
}
}
// Get the next instance.
// ======================
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PtrToCntr +
PtrToCntr->ByteLength);
}
}
// Cases where the counters have no instances.
// ===========================================
else
{
// Get the first counter.
// ======================
PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj +
PerfObj->DefinitionLength );
// Find the singleton WBEM instance which correponds to the singleton perf instance
// along with its class def so that we have the property handles.
//
// Note that since the perf object index translates to a WBEM class and there
// can only be one instance, all that is required to find the instance in the
// refresher is the perf object title index.
// =================================================================================
CClassMapInfo *pClassMap = 0;
IWbemObjectAccess *pInst = 0;
BOOL bRes = pRef->FindSingletonInst(
PerfObj->ObjectNameTitleIndex,
&pInst,
&pClassMap
);
// Retrieve all counters if the instance is one we are supposed to be refreshing.
// ==============================================================================
if (bRes)
{
for( j=0; j < PerfObj->NumCounters; j++ )
{
// Get the property handle for the counter.
// ========================================
LONG hPropHandle = pClassMap->GetPropHandle(PerfCntr->CounterNameTitleIndex);
if (hPropHandle == 0)
continue;
// Data is (LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
// We will ignore non-DWORD types for now.
// =======================================
if ((PerfCntr->CounterType & 0x700) == 0)
{
LPDWORD pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset));
HRESULT hRes = pInst->WriteDWORD(hPropHandle, *pdwVal);
}
PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr +
PerfCntr->ByteLength);
}
}
}
// Get the next object type.
// =========================
PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +
PerfObj->TotalByteLength);
}
}
//***************************************************************************
//
// QueryInstances
//
// Used to send back all instances of a perf counter. The counter
// is specified by the <pClassMap> object, which is tightly bound to
// a particular counter.
//
//***************************************************************************
BOOL PerfHelper::QueryInstances(
CClassMapInfo *pClassMap,
IWbemObjectSink *pSink
)
{
DWORD dwBufSize = 0;
DWORD dwType = 0;
LPBYTE pBuf = 0;
for (;;)
{
dwBufSize += 0x20000; // 128K
pBuf = new BYTE[dwBufSize];
wchar_t ID[32];
LONG lStatus;
swprintf(ID, L"%d", pClassMap->m_dwObjectId);
lStatus = RegQueryValueExW(
HKEY_PERFORMANCE_DATA,
ID,
0,
&dwType,
pBuf,
&dwBufSize
);
if (lStatus == ERROR_MORE_DATA)
{
continue;
}
if (lStatus)
return FALSE;
break;
}
// Decode the instances and send them back.
// ========================================
GetInstances(pBuf, pClassMap, pSink);
// Cleanup.
// ========
delete [] pBuf;
return TRUE;
}
//***************************************************************************
//
// RefreshInstances
//
// Used to refresh a set of instances.
//
//***************************************************************************
BOOL PerfHelper::RefreshInstances(
CNt5Refresher *pRef
)
{
DWORD dwBufSize = 0;
DWORD dwType = 0;
LPBYTE pBuf = 0;
// Build up the Perf Object ID list.
// =================================
DWORD dwNumIds;
DWORD *pdwIdList;
pRef->GetObjectIds(&dwNumIds, &pdwIdList);
wchar_t *IDList = new wchar_t[dwNumIds * 8]; // Allow 8 wide chars per id
IDList[0] = 0;
for (DWORD n = 0; n < dwNumIds; n++)
{
wchar_t Tmp[32];
swprintf(Tmp, L"%d", pdwIdList[n]);
if (n > 0)
wcscat(IDList, L" ");
wcscat(IDList, Tmp);
}
delete [] pdwIdList;
for (;;)
{
dwBufSize += 0x20000; // 128K
pBuf = new BYTE[dwBufSize];
LONG lStatus;
lStatus = RegQueryValueExW(
HKEY_PERFORMANCE_DATA,
IDList,
0,
&dwType,
pBuf,
&dwBufSize
);
if (lStatus == ERROR_MORE_DATA)
{
continue;
}
if (lStatus)
{
delete [] pBuf;
delete [] IDList;
return FALSE;
}
break;
}
// Decode the instances and send them back.
// ========================================
RefreshInstances(pBuf, pRef);
// Cleanup.
// ========
delete [] pBuf;
delete [] IDList;
return TRUE;
}