|
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
perfhelp.cpp
Abstract:
Registry-based performance counter reading helper
--*/
#include "wpheader.h"
#include <stdio.h>
BOOL PerfHelper::IsMatchingInstance ( PERF_INSTANCE_DEFINITION *pInstanceDef, DWORD dwCodePage, LPWSTR szInstanceNameToMatch, DWORD dwInstanceNameLength ) // compares pInstanceName to the name in the instance
{ DWORD dwThisInstanceNameLength; LPWSTR szThisInstanceName; size_t cchBufferSize = PDH_MAX_INSTANCE_NAME; WCHAR szBufferForANSINames[PDH_MAX_INSTANCE_NAME]; BOOL bReturn = FALSE;
if (dwInstanceNameLength == 0) { // get the length to compare
dwInstanceNameLength = lstrlenW (szInstanceNameToMatch); }
if (dwCodePage == 0) { // try to take a shortcut here if it's a unicode string
// compare to the length of the shortest string
// get the pointer to this string
szThisInstanceName = GetInstanceName(pInstanceDef);
// convert instance Name from bytes to chars
dwThisInstanceNameLength = pInstanceDef->NameLength / sizeof(WCHAR);
// see if this length includes the term. null. If so shorten it
if (szThisInstanceName[dwThisInstanceNameLength-1] == 0) { dwThisInstanceNameLength--; } } else { // go the long way and read/translate/convert the string
dwThisInstanceNameLength =GetInstanceNameStr (pInstanceDef, szBufferForANSINames, cchBufferSize, dwCodePage); if (dwThisInstanceNameLength > 0) { szThisInstanceName = &szBufferForANSINames[0]; } else { szThisInstanceName = (LPWSTR)cszSpace; } }
// if the lengths are not equal then the names can't be either
if (dwInstanceNameLength == dwThisInstanceNameLength) { if (lstrcmpiW(szInstanceNameToMatch, szThisInstanceName) == 0) { // this is a match
bReturn = TRUE; } else { // this is not a match
} } return bReturn; }
BOOL PerfHelper::ParseInstanceName ( IN LPCWSTR szInstanceString, IN LPWSTR szInstanceName, IN size_t cchInstanceName, IN LPWSTR szParentName, IN size_t cchParentName, IN LPDWORD lpIndex ) /*
parses the instance name formatted as follows
[parent/]instance[#index]
parent is optional and if present, is delimited by a forward slash index is optional and if present, is delimited by a colon
parent and instance may be any legal file name character except a delimeter character "/#\()" Index must be a string composed of decimal digit characters (0-9), less than 10 characters in length, and equate to a value between 0 and 2**32-1 (inclusive).
This function assumes that the instance name and parent name buffers are of sufficient size.
NOTE: szInstanceName and szInstanceString can be the same buffer
*/ { LPWSTR szSrcChar, szDestChar; BOOL bReturn = FALSE; WCHAR szIndexBuffer[WBEMPERF_STRING_SIZE]; // just to be safe
DWORD dwIndex = 0; size_t cchSize = 0; szDestChar = (LPWSTR)szInstanceName; szSrcChar = (LPWSTR)szInstanceString;
__try { do { *szDestChar++ = *szSrcChar++; cchSize++; } while ((*szSrcChar != 0) && (*szSrcChar != wcSlash) && (*szSrcChar != wcPoundSign) && cchSize < cchInstanceName ); // see if that was really the parent or not
if (*szSrcChar == wcSlash) { // terminate destination after test in case they are the same buffer
*szDestChar = 0; szSrcChar++; // and move source pointer past delimter
// it was the parent name so copy it to the parent
StringCchCopyW (szParentName, cchParentName, szInstanceName); // and copy the rest of the string after the "/" to the
// instance name field
cchSize = 0; szDestChar = szInstanceName; do { *szDestChar++ = *szSrcChar++; cchSize++; } while ((*szSrcChar != 0) && (*szSrcChar != wcPoundSign) && cchSize < cchInstanceName ); } else { // that was the only element so load an empty string for the parent
*szParentName = 0; } // *szSrcChar will either be pointing to the end of the input string
// in which case the "0" index is assumed or it will be pointing
// to the # delimiting the index argument in the string.
if (*szSrcChar == wcPoundSign) { *szDestChar = 0; // terminate the destination string
szSrcChar++; // move past delimter
szDestChar = &szIndexBuffer[0]; StringCchCopyW( szDestChar, WBEMPERF_STRING_SIZE, szSrcChar ); dwIndex = wcstoul (szIndexBuffer, NULL, 10); } else { *szDestChar = 0; // terminate the destination string
dwIndex = 0; } *lpIndex = dwIndex; bReturn = TRUE; } __except (EXCEPTION_EXECUTE_HANDLER) { // unable to move strings
bReturn = FALSE; } return bReturn; }
#pragma warning ( disable : 4127) // while (TRUE) error
PERF_OBJECT_TYPE * PerfHelper::GetObjectDefByTitleIndex( IN PERF_DATA_BLOCK *pDataBlock, IN DWORD ObjectTypeTitleIndex ) { DWORD NumTypeDef;
PERF_OBJECT_TYPE *pObjectDef = NULL; PERF_OBJECT_TYPE *pReturnObject = NULL; PERF_OBJECT_TYPE *pEndOfBuffer = NULL;
__try { pObjectDef = FirstObject(pDataBlock); pEndOfBuffer = (PPERF_OBJECT_TYPE) ((DWORD_PTR)pDataBlock + pDataBlock->TotalByteLength);
if (pObjectDef != NULL) { NumTypeDef = 0; while (1) { if ( pObjectDef->ObjectNameTitleIndex == ObjectTypeTitleIndex ) { pReturnObject = pObjectDef; break; } else { NumTypeDef++; if (NumTypeDef < pDataBlock->NumObjectTypes) { pObjectDef = NextObject(pObjectDef); //make sure next object is legit
if (pObjectDef >= pEndOfBuffer) { // looks like we ran off the end of the data buffer
assert (pObjectDef < pEndOfBuffer); break; } else { if (pObjectDef != NULL) { if (pObjectDef->TotalByteLength == 0) { // 0-length object buffer returned
assert (pObjectDef->TotalByteLength > 0); break; } } else { // and continue
assert (pObjectDef != NULL); break; } } } else { // no more data objects in this data block
break; } } } } // else no object found
} __except (EXCEPTION_EXECUTE_HANDLER) { pReturnObject = NULL; } return pReturnObject; } #pragma warning ( default : 4127) // while (TRUE) error
#pragma warning ( disable : 4127) // while (TRUE) error
PERF_OBJECT_TYPE * PerfHelper::GetObjectDefByName ( IN PERF_DATA_BLOCK *pDataBlock, IN DWORD dwLastNameIndex, IN LPCWSTR *NameArray, IN LPCWSTR szObjectName ) { DWORD NumTypeDef; PERF_OBJECT_TYPE *pReturnObject = NULL; PERF_OBJECT_TYPE *pObjectDef = NULL; PERF_OBJECT_TYPE *pEndOfBuffer = NULL;
__try {
pObjectDef = FirstObject(pDataBlock); pEndOfBuffer = (PPERF_OBJECT_TYPE) ((DWORD_PTR)pDataBlock + pDataBlock->TotalByteLength);
if (pObjectDef != NULL) {
NumTypeDef = 0; while (1) { if ( pObjectDef->ObjectNameTitleIndex < dwLastNameIndex ) { // look up name of object & compare
if (lstrcmpiW(NameArray[pObjectDef->ObjectNameTitleIndex], szObjectName) == 0) { pReturnObject = pObjectDef; break; } } NumTypeDef++; if (NumTypeDef < pDataBlock->NumObjectTypes) { pObjectDef = NextObject(pObjectDef); // get next
//make sure next object is legit
if (pObjectDef != NULL) { if (pObjectDef->TotalByteLength > 0) { if (pObjectDef >= pEndOfBuffer) { // looks like we ran off the end of the data buffer
assert (pObjectDef < pEndOfBuffer); break; } } else { // 0-length object buffer returned
assert (pObjectDef->TotalByteLength > 0); break; } } else { // null pointer
assert (pObjectDef != NULL); break; } } else { // end of data block
break; } } } // else no object found
} __except (EXCEPTION_EXECUTE_HANDLER) { pReturnObject = NULL; } return pReturnObject; } #pragma warning ( default : 4127) // while (TRUE) error
PERF_INSTANCE_DEFINITION * PerfHelper::GetInstance( IN PERF_OBJECT_TYPE *pObjectDef, IN LONG InstanceNumber ) {
PERF_INSTANCE_DEFINITION *pInstanceDef; PERF_INSTANCE_DEFINITION *pReturnDef = NULL; PERF_INSTANCE_DEFINITION *pEndOfBuffer = NULL; LONG NumInstance;
if (pObjectDef != NULL) { pInstanceDef = FirstInstance(pObjectDef); if (pInstanceDef != NULL) { pEndOfBuffer = (PERF_INSTANCE_DEFINITION *)EndOfObject(pObjectDef);
for ( NumInstance = 0; NumInstance < pObjectDef->NumInstances; NumInstance++ ) { if ( InstanceNumber == NumInstance ) { pReturnDef = pInstanceDef; } pInstanceDef = NextInstance(pInstanceDef); // go to next instance in object and check for buffer overrun
if (pInstanceDef >= pEndOfBuffer) { // something doesn't add up so bail out and return NULL
break; } } } }
return pReturnDef; }
PERF_INSTANCE_DEFINITION * PerfHelper::GetInstanceByUniqueId( IN PERF_OBJECT_TYPE *pObjectDef, IN LONG InstanceUniqueId ) { PERF_INSTANCE_DEFINITION *pInstanceDef; PERF_INSTANCE_DEFINITION *pReturnDef = NULL; PERF_INSTANCE_DEFINITION *pEndOfBuffer = NULL; LONG NumInstance;
if (pObjectDef != NULL) { pInstanceDef = FirstInstance(pObjectDef); if (pInstanceDef != NULL) { pEndOfBuffer = (PERF_INSTANCE_DEFINITION *)EndOfObject(pObjectDef);
for ( NumInstance = 0; NumInstance < pObjectDef->NumInstances; NumInstance++ ) { if ( InstanceUniqueId == pInstanceDef->UniqueID ) { pReturnDef = pInstanceDef; } pInstanceDef = NextInstance(pInstanceDef); // go to next instance in object and check for buffer overrun
if (pInstanceDef >= pEndOfBuffer) { // something doesn't add up so bail out and return NULL
break; } } } } return pReturnDef; }
DWORD PerfHelper::GetAnsiInstanceName (PPERF_INSTANCE_DEFINITION pInstance, LPWSTR lpszInstance, size_t cchBufferSize, DWORD dwCodePage) { LPSTR szSource; DWORD_PTR dwLength;
UNREFERENCED_PARAMETER(dwCodePage);
szSource = (LPSTR)GetInstanceName(pInstance);
// the locale should be set here
// pInstance->NameLength == the number of bytes (chars) in the string
dwLength = mbstowcs (lpszInstance, szSource, cchBufferSize ); if( dwLength < cchBufferSize ){ lpszInstance[dwLength] = 0; // null terminate string buffer
}
return (DWORD)dwLength; }
DWORD PerfHelper::GetUnicodeInstanceName (PPERF_INSTANCE_DEFINITION pInstance, LPWSTR lpszInstance, size_t cchBufferSize ) { LPWSTR wszSource; DWORD dwLength;
wszSource = GetInstanceName(pInstance) ;
// pInstance->NameLength == length of string in BYTES so adjust to
// number of wide characters here
dwLength = pInstance->NameLength / sizeof(WCHAR);
StringCchCopyW (lpszInstance, cchBufferSize, (LPWSTR)wszSource);
// add null termination if string length does not include the null
if ((dwLength > 0) && (lpszInstance[dwLength-1] != 0)) { // i.e. it's the last character of the string
lpszInstance[dwLength] = 0; // then add a terminating null char to the string
} else { // assume that the length value includes the terminating NULL
// so adjust value to indicate chars only
dwLength--; }
return (dwLength); // just incase there's null's in the string
}
DWORD PerfHelper::GetInstanceNameStr (PPERF_INSTANCE_DEFINITION pInstance, LPWSTR lpszInstance, size_t cchBufferSize, DWORD dwCodePage) { DWORD dwCharSize; DWORD dwLength = 0;
if (pInstance != NULL) { if (lpszInstance != NULL) { if (dwCodePage > 0) { dwCharSize = sizeof(CHAR); dwLength = GetAnsiInstanceName (pInstance, lpszInstance, cchBufferSize, dwCodePage); } else { // it's a UNICODE name
dwCharSize = sizeof(WCHAR); dwLength = GetUnicodeInstanceName (pInstance, lpszInstance, cchBufferSize); } // sanity check here...
// the returned string length (in characters) plus the terminating NULL
// should be the same as the specified length in bytes divided by the
// character size. If not then the codepage and instance data type
// don't line up so test that here
if ((dwLength + 1) != (pInstance->NameLength / dwCharSize)) { // something isn't quite right so try the "other" type of string type
if (dwCharSize == sizeof(CHAR)) { // then we tried to read it as an ASCII string and that didn't work
// so try it as a UNICODE (if that doesn't work give up and return
// it any way.
dwLength = GetUnicodeInstanceName (pInstance, lpszInstance, cchBufferSize ); } else if (dwCharSize == sizeof(WCHAR)) { // then we tried to read it as a UNICODE string and that didn't work
// so try it as an ASCII string (if that doesn't work give up and return
// it any way.
dwLength = GetAnsiInstanceName (pInstance, lpszInstance, cchBufferSize, dwCodePage); } } } // else return buffer is null
} else { // no instance def object is specified so return an empty string
*lpszInstance = 0; }
return dwLength; }
PERF_INSTANCE_DEFINITION * PerfHelper::GetInstanceByNameUsingParentTitleIndex( PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectDef, LPWSTR pInstanceName, LPWSTR pParentName, DWORD dwIndex ) { PERF_OBJECT_TYPE *pParentObj;
PERF_INSTANCE_DEFINITION *pParentInst; PERF_INSTANCE_DEFINITION *pInstanceDef; PERF_INSTANCE_DEFINITION *pReturnDef = NULL;
LONG NumInstance; DWORD dwLocalIndex; DWORD dwInstanceNameLength;
pInstanceDef = FirstInstance(pObjectDef); assert (pInstanceDef != NULL); dwLocalIndex = dwIndex;
dwInstanceNameLength = lstrlenW(pInstanceName);
for ( NumInstance = 0; NumInstance < pObjectDef->NumInstances; NumInstance++ ) {
if (IsMatchingInstance (pInstanceDef, pObjectDef->CodePage, pInstanceName, dwInstanceNameLength )) { // this is the correct instance, so see if we need to find a parent instance
if ( pParentName == NULL ) { // No parent, we're done if this is the right "copy"
if (dwLocalIndex == 0) { pReturnDef = pInstanceDef; break; } else { --dwLocalIndex; } } else { // Must match parent as well
pParentObj = GetObjectDefByTitleIndex( pDataBlock, pInstanceDef->ParentObjectTitleIndex);
if (!pParentObj) { // can't locate the parent, forget it
break; }
// Object type of parent found; now find parent
// instance
pParentInst = GetInstance(pParentObj, pInstanceDef->ParentObjectInstance);
if (!pParentInst) { // can't locate the parent instance, forget it
break ; }
if (IsMatchingInstance (pParentInst, pParentObj->CodePage, pParentName, 0)) { // Parent Instance Name matches that passed in
if (dwLocalIndex == 0) { pReturnDef = pInstanceDef; break; } else { --dwLocalIndex; } } } } // get the next one
pInstanceDef = NextInstance(pInstanceDef); } return pReturnDef; }
PERF_INSTANCE_DEFINITION * PerfHelper::GetInstanceByName( PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectDef, LPWSTR pInstanceName, LPWSTR pParentName, DWORD dwIndex ) { PERF_OBJECT_TYPE *pParentObj;
PERF_INSTANCE_DEFINITION *pParentInst; PERF_INSTANCE_DEFINITION *pInstanceDef; PERF_INSTANCE_DEFINITION *pReturnDef = NULL; PERF_INSTANCE_DEFINITION *pEndOfBuffer = NULL;
LONG NumInstance; DWORD dwLocalIndex; DWORD dwInstanceNameLength;
pInstanceDef = FirstInstance(pObjectDef); if (pInstanceDef != NULL) { dwLocalIndex = dwIndex; dwInstanceNameLength = lstrlenW(pInstanceName); pEndOfBuffer = (PERF_INSTANCE_DEFINITION *)EndOfObject(pObjectDef);
for ( NumInstance = 0; NumInstance < pObjectDef->NumInstances; NumInstance++ ) { if (IsMatchingInstance (pInstanceDef, pObjectDef->CodePage, pInstanceName, dwInstanceNameLength)) {
// Instance name matches
if ( !pInstanceDef->ParentObjectTitleIndex ) { // No parent, we're done
if (dwLocalIndex == 0) { pReturnDef = pInstanceDef; break; } else { --dwLocalIndex; } } else { // Must match parent as well
pParentObj = GetObjectDefByTitleIndex( pDataBlock, pInstanceDef->ParentObjectTitleIndex);
if (pParentObj != NULL) { // Object type of parent found; now find parent
// instance
pParentInst = GetInstance(pParentObj, pInstanceDef->ParentObjectInstance);
if (pParentInst != NULL) { if (IsMatchingInstance (pParentInst, pParentObj->CodePage, pParentName, 0)) { // Parent Instance Name matches that passed in
if (dwLocalIndex == 0) { pReturnDef = pInstanceDef; break; } else { --dwLocalIndex; } } } } else { // keep trying
} } } // go to next instance in object and check for buffer overrun
pInstanceDef = NextInstance(pInstanceDef); if (pInstanceDef >= pEndOfBuffer) { // something doesn't add up so bail out and return NULL
break; } } } return pReturnDef; } // GetInstanceByName
DWORD PerfHelper::GetFullInstanceNameStr ( PERF_DATA_BLOCK *pPerfData, PERF_OBJECT_TYPE *pObjectDef, PERF_INSTANCE_DEFINITION *pInstanceDef, LPWSTR szInstanceName, size_t cchBufferSize ) // compile instance name.
// the instance name can either be just
// the instance name itself or it can be
// the concatenation of the parent instance,
// a delimiting char (backslash) followed by
// the instance name
{
WCHAR szInstanceNameString[PDH_MAX_INSTANCE_NAME]; WCHAR szParentNameString[PDH_MAX_INSTANCE_NAME];
DWORD dwLength = 0; PERF_OBJECT_TYPE *pParentObjectDef; PERF_INSTANCE_DEFINITION *pParentInstanceDef;
szInstanceNameString[0] = UNICODE_NULL; szParentNameString[0] = UNICODE_NULL; if (pInstanceDef->UniqueID == PERF_NO_UNIQUE_ID) { dwLength = GetInstanceNameStr (pInstanceDef, szInstanceNameString, PDH_MAX_INSTANCE_NAME, pObjectDef->CodePage); } else { // make a string out of the unique ID
_ltow (pInstanceDef->UniqueID, szInstanceNameString, 10); dwLength = lstrlenW (szInstanceNameString); }
if (pInstanceDef->ParentObjectTitleIndex > 0) { // then add in parent instance name
pParentObjectDef = GetObjectDefByTitleIndex ( pPerfData, pInstanceDef->ParentObjectTitleIndex);
if (pParentObjectDef != NULL) { pParentInstanceDef = GetInstance ( pParentObjectDef, pInstanceDef->ParentObjectInstance); assert ((UINT_PTR)pParentObjectDef != (DWORD)0xFFFFFFFF); if (pParentInstanceDef != NULL) { if (pParentInstanceDef->UniqueID == PERF_NO_UNIQUE_ID) { dwLength += GetInstanceNameStr (pParentInstanceDef, szParentNameString, PDH_MAX_INSTANCE_NAME, pParentObjectDef->CodePage); } else { // make a string out of the unique ID
_ltow (pParentInstanceDef->UniqueID, szParentNameString, 10); dwLength += lstrlenW (szParentNameString); }
StringCchCatW( szParentNameString, PDH_MAX_INSTANCE_NAME, cszSlash ); dwLength += 1; StringCchCatW(szParentNameString, PDH_MAX_INSTANCE_NAME, szInstanceNameString); StringCchCopyW( szInstanceName, cchBufferSize, szParentNameString); } else { StringCchCopyW( szInstanceName, cchBufferSize, szInstanceNameString); } } else { StringCchCopyW( szInstanceName, cchBufferSize, szInstanceNameString); } } else { StringCchCopyW( szInstanceName, cchBufferSize, szInstanceNameString); }
return dwLength;
}
//***************************************************************************
//
// 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_OBJECT_TYPE pEndOfBuffer = 0; PPERF_INSTANCE_DEFINITION PerfInst = 0; PPERF_INSTANCE_DEFINITION pEndOfObject = 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;
IWbemObjectAccess *pNewInst = 0; IWbemClassObject *pClsObj = 0;
WCHAR pName[PDH_MAX_INSTANCE_NAME]; LONG lStatus = 0; LONG hPropHandle; LPDWORD pdwVal; ULONGLONG *pullVal; HRESULT hRes; LONG64 llVal;
// Get the first object type.
// ==========================
PerfObj = (PPERF_OBJECT_TYPE) ((PBYTE)PerfData + PerfData->HeaderLength);
if (PerfObj != NULL) { // get end of buffer
pEndOfBuffer = (PPERF_OBJECT_TYPE) ((DWORD_PTR)PerfData + PerfData->TotalByteLength);
// 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); if (PerfObj >= pEndOfBuffer) { // looks like we ran off the end of the data buffer
break; } else { continue; } }
if (PerfObj->NumInstances > 0) { // Get the first instance.
// =======================
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj + PerfObj->DefinitionLength); if (PerfInst < (PPERF_INSTANCE_DEFINITION)pEndOfBuffer) { // make sure we are still within the caller's buffer
// then find the end of this object
pEndOfObject = (PERF_INSTANCE_DEFINITION *)EndOfObject(PerfObj);
// Retrieve all instances.
// =======================
for (k = 0; k < DWORD(PerfObj->NumInstances); k++ ) { CurCntr = PerfCntr; pClsObj = NULL; pNewInst = NULL; HRESULT hr; // 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.
// ======================================================
hr = pClassMap->m_pClassDef->SpawnInstance(0, &pClsObj); if (SUCCEEDED(hr)) { hr = pClsObj->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewInst); pClsObj->Release(); // We only need the IWbemObjectAccess pointer
if( NULL == pNewInst ){ break; } } else { break; }
// Locate the instance name.
// ==========================
lStatus = GetFullInstanceNameStr ( PerfData, PerfObj, PerfInst, pName, PDH_MAX_INSTANCE_NAME );
// 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.
// ================================================================
hPropHandle = pClassMap->GetPropHandle( CM_MAKE_PerfObjectId(CurCntr->CounterNameTitleIndex, CurCntr->CounterType)); if (hPropHandle != 0) { // update value according to data type
if ((CurCntr->CounterType & 0x300) == 0) { pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset)); hRes = pNewInst->WriteDWORD(hPropHandle, *pdwVal); } else if ((CurCntr->CounterType & 0x300) == 0x100){ pullVal = (ULONGLONG *)((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset)); llVal = Assign64((PLARGE_INTEGER) pullVal); hRes = pNewInst->WriteQWORD(hPropHandle, llVal); } else { //this shouldn't happen
assert (FALSE); } }
// 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, (DWORD)(((DWORD)(wcslen(pName)) + 1) * 2), LPBYTE(pName) ); }
// update the timestamp
if (pClassMap->m_dwPerfTimeStampHandle) { UpdateTimers(pClassMap, pNewInst, PerfData, PerfObj); }
// 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); if (PerfInst >= pEndOfObject) { // something doesn't add up so bail out of this object
break; } } } } else if (PerfObj->NumInstances == PERF_NO_INSTANCES) { HRESULT hr; pClsObj = NULL; pNewInst = NULL; // Cases where the counters have one and only one instance.
// ========================================================
// 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.
// ======================================================
hr = pClassMap->m_pClassDef->SpawnInstance(0, &pClsObj); if (SUCCEEDED(hr)) { 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.
// ================================================================
hPropHandle = pClassMap->GetPropHandle( CM_MAKE_PerfObjectId(PerfCntr->CounterNameTitleIndex, PerfCntr->CounterType)); if (hPropHandle != 0) { if ((PerfCntr->CounterType & 0x300) == 0) { pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset)); hRes = pNewInst->WriteDWORD(hPropHandle, *pdwVal); } else if ((PerfCntr->CounterType & 0x300) == 0x100) { pullVal = (ULONGLONG *)((LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset)); llVal = Assign64((PLARGE_INTEGER) pullVal); hRes = pNewInst->WriteQWORD(hPropHandle, llVal); } else { // this shouldn't happen
assert (FALSE); } }
PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr + PerfCntr->ByteLength); }
// update the timestamp
if (pClassMap->m_dwPerfTimeStampHandle) { UpdateTimers(pClassMap, pNewInst, PerfData, PerfObj); }
pSink->Indicate(1, (IWbemClassObject **) &pNewInst); pNewInst->Release(); }
} else { // this object can have instances, but currently doesn't
// so there's nothing to report
} break; } } }
void PerfHelper::RefreshEnumeratorInstances ( IN RefresherCacheEl *pThisCacheEl, IN PPERF_DATA_BLOCK PerfData, IN PPERF_OBJECT_TYPE PerfObj ) { LONG lNumObjInstances; LONG lStatus; HRESULT hRes;
PPERF_INSTANCE_DEFINITION PerfInst = 0; PPERF_INSTANCE_DEFINITION pEndOfObject = 0; PPERF_COUNTER_DEFINITION PerfCntr = 0, CurCntr = 0; PPERF_COUNTER_BLOCK PtrToCntr = 0; WCHAR pName[PDH_MAX_INSTANCE_NAME];
LONG hPropHandle; LPDWORD pdwVal; ULONGLONG *pullVal; LONG64 llVal;
IWbemObjectAccess *pNewInst = 0;
assert (PerfObj != NULL); assert (pThisCacheEl != NULL);
if (pThisCacheEl == NULL) return;
// make sure we have enough pointers
// handle the singleton object case
if (PerfObj->NumInstances == PERF_NO_INSTANCES) { lNumObjInstances = 1; } else { lNumObjInstances = PerfObj->NumInstances; }
if (pThisCacheEl->m_aEnumInstances.Size() < lNumObjInstances) { LONG i; // alloc and init the ID array
if (pThisCacheEl->m_plIds != NULL) { delete (pThisCacheEl->m_plIds); } pThisCacheEl->m_lEnumArraySize = lNumObjInstances; pThisCacheEl->m_plIds = new LONG[lNumObjInstances]; if (pThisCacheEl->m_plIds == NULL) return;
for (i = 0; i < lNumObjInstances; i++) pThisCacheEl->m_plIds[i] = i; // add the new IWbemObjectAccess pointers
for (i = pThisCacheEl->m_aEnumInstances.Size(); i < PerfObj->NumInstances; i++) { IWbemClassObject * pClsObj = NULL; HRESULT hr; hr = pThisCacheEl->m_pClassMap->m_pClassDef->SpawnInstance(0, &pClsObj); if (SUCCEEDED(hr)) { pClsObj->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewInst); pClsObj->Release(); // We only need the IWbemObjectAccess pointer
pThisCacheEl->m_aEnumInstances.Add (pNewInst); } } } assert (pThisCacheEl->m_aEnumInstances.Size() >= lNumObjInstances);
// release enumerator items to prepare a new batch
hRes = pThisCacheEl->m_pHiPerfEnum->RemoveAll(0); assert (hRes == S_OK);
// update new instance list
if (PerfObj->NumInstances == PERF_NO_INSTANCES) { //handle the singleton case
} else if (PerfObj->NumInstances > 0) { // Get the first instance.
// =======================
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj + PerfObj->DefinitionLength);
// get pointer to the end of this object buffer
pEndOfObject = (PERF_INSTANCE_DEFINITION *)EndOfObject(PerfObj);
// point to the first counter definition in the object
PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj + PerfObj->HeaderLength);
// Retrieve all instances.
// =======================
for (LONG k = 0; k < PerfObj->NumInstances; k++ ) { CurCntr = PerfCntr; // Get the first counter.
// ======================
PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst + PerfInst->ByteLength);
// get the IWbemObjectAccess pointer from our
// cached array of pointers
pNewInst = (IWbemObjectAccess *)(pThisCacheEl->m_aEnumInstances.GetAt(k));
// Locate the instance name.
// ==========================
lStatus = GetFullInstanceNameStr ( PerfData, PerfObj, PerfInst, pName, PDH_MAX_INSTANCE_NAME );
// Retrieve all counters.
// ======================
if( NULL != pNewInst ){ for(DWORD 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.
// ================================================================
hPropHandle = pThisCacheEl->m_pClassMap->GetPropHandle( CM_MAKE_PerfObjectId(CurCntr->CounterNameTitleIndex, CurCntr->CounterType)); if (hPropHandle != 0) { // update value according to data type
if ((CurCntr->CounterType & 0x300) == 0) { pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset)); hRes = pNewInst->WriteDWORD(hPropHandle, *pdwVal); } else if ((CurCntr->CounterType & 0x300) == 0x100){ pullVal = (ULONGLONG *)((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset)); llVal = Assign64((PLARGE_INTEGER) pullVal); hRes = pNewInst->WriteQWORD(hPropHandle, llVal); } else { //this shouldn't happen
assert (FALSE); } }
// Get next counter.
// =================
CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr + CurCntr->ByteLength); }
// Write the instance 'name'
// =========================
if (pName && pThisCacheEl->m_pClassMap->m_dwNameHandle) { pNewInst->WritePropertyValue( pThisCacheEl->m_pClassMap->m_dwNameHandle, (DWORD)(((DWORD)(wcslen(pName)) + 1) * 2), LPBYTE(pName) ); }
// update the timestamp
if (pThisCacheEl->m_pClassMap->m_dwPerfTimeStampHandle) { UpdateTimers(pThisCacheEl->m_pClassMap, pNewInst, PerfData, PerfObj); }
// Move to the next perf instance.
// ================================
PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PtrToCntr + PtrToCntr->ByteLength);
if (PerfInst >= pEndOfObject) { // something doesn't add up so bail out of this object
break; } } } } else { // no instances so there's nothing to do
}
if (lNumObjInstances > 0) { // update the hiperf enumerator object
hRes = pThisCacheEl->m_pHiPerfEnum->AddObjects( 0, lNumObjInstances, pThisCacheEl->m_plIds, (IWbemObjectAccess __RPC_FAR *__RPC_FAR *)pThisCacheEl->m_aEnumInstances.GetArrayPtr()); } else { // nothing to do since we've already cleared the enumerator above
} }
//***************************************************************************
//
// PerfHelper::RefreshInstances
//
// searches the refresher's list first then
// looks up the corresponding items in the perf data structure
//
//***************************************************************************
//
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;
// for each refreshable object
PRefresherCacheEl pThisCacheEl; DWORD dwNumCacheEntries = pRef->m_aCache.Size(); DWORD dwThisCacheEntryIndex = 0; DWORD dwThisCounter; DWORD dwThisInstanceIndex = 0; DWORD dwNumInstancesInCache = 0; IWbemObjectAccess *pInst = 0; LONG hPropHandle; LPDWORD pdwVal; HRESULT hRes; ULONGLONG *pullVal; LONG64 llVal;
while (dwThisCacheEntryIndex < dwNumCacheEntries) { // get this entry from the cache
pThisCacheEl = (PRefresherCacheEl) pRef->m_aCache[dwThisCacheEntryIndex]; // get class map from this entry
CClassMapInfo *pClassMap = pThisCacheEl->m_pClassMap; // get perf object pointer from the perf data block
PerfObj = GetObjectDefByTitleIndex ( PerfData, pThisCacheEl->m_dwPerfObjIx); if (PerfObj != NULL) { // found the object so do each of the instances
// loaded in this refresher
PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj + PerfObj->HeaderLength);
// found so update the properties
if (PerfObj->NumInstances > 0) { // see if they have an enumerator interface and refresh it if they do
if (pThisCacheEl->m_pHiPerfEnum != NULL) { // refresh enum
RefreshEnumeratorInstances (pThisCacheEl, PerfData, PerfObj); } //do each instance in this class
dwThisInstanceIndex = 0; dwNumInstancesInCache = pThisCacheEl->m_aInstances.Size(); while (dwThisInstanceIndex < dwNumInstancesInCache ) { pInst = 0; // get the pointer to this instance in the refresher
CachedInst *pInstInfo = PCachedInst(pThisCacheEl->m_aInstances[dwThisInstanceIndex]); // get the pointer to the instance block in the current object
PerfInst = GetInstanceByName( PerfData, PerfObj, pInstInfo->m_szInstanceName, pInstInfo->m_szParentName, pInstInfo->m_dwIndex);
pInst = pInstInfo->m_pInst; // Get the first counter.
// ======================
CurCntr = PerfCntr;
if (PerfInst != NULL) { PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst + PerfInst->ByteLength);
// Retrieve all counters for the instance if it was one of the instances
// we are supposed to be refreshing.
// =====================================================================
for (dwThisCounter = 0; dwThisCounter < PerfObj->NumCounters; dwThisCounter++ ) { hPropHandle = pClassMap->GetPropHandle( CM_MAKE_PerfObjectId(CurCntr->CounterNameTitleIndex, CurCntr->CounterType)); if (hPropHandle != 0) { // Data is (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);
if ((CurCntr->CounterType & 0x300) == 0) { pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset)); hRes = pInst->WriteDWORD(hPropHandle, *pdwVal); } else if ((CurCntr->CounterType & 0x300) == 0x100) { pullVal = (ULONGLONG *)((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset)); llVal = Assign64((PLARGE_INTEGER) pullVal); hRes = pInst->WriteQWORD(hPropHandle, llVal); } else { // This shouldn't happen
assert (FALSE); } }
// Get next counter.
// =================
CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr + CurCntr->ByteLength); } // update the timestamp
if (pClassMap->m_dwPerfTimeStampHandle) { UpdateTimers(pClassMap, pInst, PerfData, PerfObj); } // else no timestamp handle present
} else { // then there's no data for this
// instance anymore so zero out the values and continue
for (dwThisCounter = 0; dwThisCounter < PerfObj->NumCounters; dwThisCounter++ ) { hPropHandle = pClassMap->GetPropHandle( CM_MAKE_PerfObjectId(CurCntr->CounterNameTitleIndex, CurCntr->CounterType)); if (hPropHandle != 0) { if ((CurCntr->CounterType & 0x300) == 0) { hRes = pInst->WriteDWORD(hPropHandle, 0); } else if ((CurCntr->CounterType & 0x300) == 0x100) { hRes = pInst->WriteQWORD(hPropHandle, 0); } else { // This shouldn't happen
assert (FALSE); } }
// Get next counter.
// =================
CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr + CurCntr->ByteLength); }
// update the timestamp
if (pClassMap->m_dwPerfTimeStampHandle) { // save system timer tick
pInst->WriteQWORD(pClassMap->m_dwPerfTimeStampHandle , 0); // use system 100 NS timer
pInst->WriteQWORD(pClassMap->m_dw100NsTimeStampHandle, 0); // use timer from object
pInst->WriteQWORD(pClassMap->m_dwObjectTimeStampHandle, 0); } } // Get the next instance.
// =====================
dwThisInstanceIndex++; } } else if (PerfObj->NumInstances == PERF_NO_INSTANCES && NULL != pThisCacheEl->m_pSingleton ) {
// Check that the singleton instance did not get cleared
// due to no references.
// only a single instance so get the properties and
// update them
// Get the first counter.
// 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.
// =================================================================================
pInst = pThisCacheEl->m_pSingleton;
// ======================
PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj + PerfObj->DefinitionLength );
// Retrieve all counters if the instance is one we are supposed to be refreshing.
// ==============================================================================
for( dwThisCounter=0; dwThisCounter < PerfObj->NumCounters; dwThisCounter++ ) { // Get the property handle for the counter.
// ========================================
hPropHandle = pClassMap->GetPropHandle( CM_MAKE_PerfObjectId(PerfCntr->CounterNameTitleIndex, PerfCntr->CounterType)); if (hPropHandle != 0) { // update the data values based on the datatype
if ((PerfCntr->CounterType & 0x300) == 0) { pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset)); hRes = pInst->WriteDWORD(hPropHandle, *pdwVal); } else if ((PerfCntr->CounterType & 0x300) == 0x100){ pullVal = (ULONGLONG *)((LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset)); llVal = Assign64((PLARGE_INTEGER) pullVal); hRes = pInst->WriteQWORD(hPropHandle, llVal); } else { // this shouldn't happen
assert (FALSE); } }
// get next counter definition
PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr + PerfCntr->ByteLength); } // update the timestamp
if (pClassMap->m_dwPerfTimeStampHandle) { UpdateTimers(pClassMap, pInst, PerfData, PerfObj); } } else { // this object could have instances but doesn't so
// skip
} } else { // desired object not found in data
}
// Get the next refresher object
// =========================
dwThisCacheEntryIndex++; } }
//***************************************************************************
//
// 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( CPerfObjectAccess *pPerfObj, CClassMapInfo *pClassMap, IWbemObjectSink *pSink ) { DWORD dwBufSize = 0; LPBYTE pBuf = NULL; LONG lStatus; BOOL bReturn = FALSE; WCHAR szValueNum[WBEMPERF_STRING_SIZE]; for (;;) { dwBufSize += 0x10000; // 64K
assert (dwBufSize< 0x100000); // make sure we don't do this forever
pBuf = new BYTE[dwBufSize]; assert (pBuf != NULL);
if (pBuf != NULL) { // either do a global or a costly query depending on the
// object being queried
if (pClassMap->GetObjectId() > 0) { _ultow (pClassMap->GetObjectId(), (LPWSTR)szValueNum, 10); } else if (pClassMap->IsCostly()) { StringCchCopyW( szValueNum, WBEMPERF_STRING_SIZE, cszCostly); } else { StringCchCopyW(szValueNum, WBEMPERF_STRING_SIZE, cszGlobal); } lStatus = pPerfObj->CollectData (pBuf, &dwBufSize, szValueNum); if (lStatus == ERROR_MORE_DATA) { // toss the old buffer as it's not useful
delete pBuf; continue; } else if (lStatus == ERROR_SUCCESS) { bReturn = TRUE; } break; } else { // memory allocation failure
break; } }
if (bReturn && (pBuf != NULL)) { // a good buffer was returned so
// Decode the instances and send them back.
// ========================================
GetInstances(pBuf, pClassMap, pSink); }
// Cleanup.
// ========
if (pBuf != NULL) delete pBuf;
return bReturn; }
//***************************************************************************
//
// RefreshInstances
//
// Used to refresh a set of instances.
//
//***************************************************************************
//
BOOL PerfHelper::RefreshInstances( CNt5Refresher *pRef ) { DWORD dwBufSize = 0; LPBYTE pBuf = NULL; LONG lStatus; BOOL bReturn = FALSE;
for (;;) { dwBufSize += 0x10000; // 64K
assert (dwBufSize< 0x100000); // make sure we don't do this forever
pBuf = new BYTE[dwBufSize]; assert (pBuf != NULL);
if (pBuf != NULL) { lStatus = pRef->m_PerfObj.CollectData (pBuf, &dwBufSize); if (lStatus == ERROR_MORE_DATA) { // toss the old buffer as it's not useful
delete pBuf; continue; } else if (lStatus == ERROR_SUCCESS) { bReturn = TRUE; } break; } else { // memory allocation failure
break; } }
if (bReturn && (pBuf != NULL)) { // update the instances and send them back.
// ========================================
RefreshInstances(pBuf, pRef); } // Cleanup.
// ========
if (pBuf != NULL) delete pBuf;
return bReturn; }
VOID PerfHelper::UpdateTimers( CClassMapInfo *pClassMap, IWbemObjectAccess *pInst, PPERF_DATA_BLOCK PerfData, PPERF_OBJECT_TYPE PerfObj ) { LONG64 llVal;
// save system timer tick
llVal = Assign64(&PerfData->PerfTime); pInst->WriteQWORD( pClassMap->m_dwPerfTimeStampHandle , llVal ); // use timer from object
llVal = Assign64(&PerfObj->PerfTime); pInst->WriteQWORD( pClassMap->m_dwObjectTimeStampHandle, llVal ); // use system 100 NS timer
llVal = Assign64(&PerfData->PerfTime100nSec); pInst->WriteQWORD( pClassMap->m_dw100NsTimeStampHandle, llVal ); // save system timer freq
llVal = Assign64(&PerfData->PerfFreq); pInst->WriteQWORD( pClassMap->m_dwPerfFrequencyHandle , llVal ); // use timer from object
llVal = Assign64(&PerfObj->PerfFreq); pInst->WriteQWORD( pClassMap->m_dwObjectFrequencyHandle, llVal ); // use system 100 NS Freq
pInst->WriteQWORD( pClassMap->m_dw100NsFrequencyHandle, (LONGLONG)10000000); }
|