/*++ Copyright (C) 1997-2001 Microsoft Corporation Module Name: Abstract: History: --*/ //*************************************************************************** // // PERFHELP.CPP // // Registry-based performance counter reading helper // //*************************************************************************** #include "precomp.h" #include #include #include #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: // The perf blob retrieved from HKEY_PERFORMANCE_DATA. // A map object of the class required. // 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 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; }