|
|
/*++
Copyright (C) 1995-2001 Microsoft Corporation
Module Name:
PROVPERF.CPP
Abstract:
Defines the acutal "Put" and "Get" functions for the performance counter provider. The format of the mapping string is; machine|Object|counter[|instance] Examples; local|memory|available bytes a-davj2|LogicalDisk|Free Megabytes|C:
History:
a-davj 9-27-95 Created.
--*/
#include "precomp.h"
#include "provperf.h"
#include "cvariant.h"
// maximum amount of time to wait for exclusive access
#define MAX_EXEC_WAIT 5000
//***************************************************************************
//
// AddTesterDetails
//
// DESCRIPTION:
//
// This function is used add the counter type to the property and is useful
// to wbem testers. Normal users dont want the overhead caused by this.
//
// PARAMETERS:
//
// pClassInt Object being refreshed
// PropName Property Name
// dwCtrType counter type
//
// RETURN VALUE:
//
// always 0
//
//***************************************************************************
void AddTesterDetails(IWbemClassObject FAR * pClassInt,BSTR PropName,DWORD dwCtrType) { // Get the qualifier pointer for the property
IWbemQualifierSet * pQualifier = NULL;
// Get an Qualifier set interface.
SCODE sc = pClassInt->GetPropertyQualifierSet(PropName,&pQualifier); // Get prop attribute
if(FAILED(sc)) return;
WCHAR wcName[40];
switch(dwCtrType) { case PERF_COUNTER_COUNTER: wcsncpy(wcName,L"PERF_COUNTER_COUNTER", 39); break;
case PERF_COUNTER_TIMER: wcsncpy(wcName,L"PERF_COUNTER_TIMER", 39); break;
case PERF_COUNTER_QUEUELEN_TYPE: wcsncpy(wcName,L"PERF_COUNTER_QUEUELEN_TYPE", 39); break;
case PERF_COUNTER_LARGE_QUEUELEN_TYPE: wcsncpy(wcName,L"PERF_COUNTER_LARGE_QUEUELEN_TYPE", 39); break;
case PERF_COUNTER_BULK_COUNT: wcsncpy(wcName,L"PERF_COUNTER_BULK_COUNT", 39); break;
case PERF_COUNTER_TEXT: wcsncpy(wcName,L"PERF_COUNTER_TEXT", 39); break;
case PERF_COUNTER_RAWCOUNT: wcsncpy(wcName,L"PERF_COUNTER_RAWCOUNT", 39); break;
case PERF_COUNTER_LARGE_RAWCOUNT: wcsncpy(wcName,L"PERF_COUNTER_LARGE_RAWCOUNT", 39); break;
case PERF_COUNTER_RAWCOUNT_HEX: wcsncpy(wcName,L"PERF_COUNTER_RAWCOUNT_HEX", 39); break;
case PERF_COUNTER_LARGE_RAWCOUNT_HEX: wcsncpy(wcName,L"PERF_COUNTER_LARGE_RAWCOUNT_HEX", 39); break;
case PERF_SAMPLE_FRACTION: wcsncpy(wcName,L"PERF_SAMPLE_FRACTION", 39); break;
case PERF_SAMPLE_COUNTER: wcsncpy(wcName,L"PERF_SAMPLE_COUNTER", 39); break;
case PERF_COUNTER_NODATA: wcsncpy(wcName,L"PERF_COUNTER_NODATA", 39); break;
case PERF_COUNTER_TIMER_INV: wcsncpy(wcName,L"PERF_COUNTER_TIMER_INV", 39); break;
case PERF_SAMPLE_BASE: wcsncpy(wcName,L"PERF_SAMPLE_BASE", 39); break;
case PERF_AVERAGE_TIMER: wcsncpy(wcName,L"PERF_AVERAGE_TIMER", 39); break;
case PERF_AVERAGE_BASE: wcsncpy(wcName,L"PERF_AVERAGE_BASE", 39); break;
case PERF_AVERAGE_BULK: wcsncpy(wcName,L"PERF_AVERAGE_BULK", 39); break;
case PERF_100NSEC_TIMER: wcsncpy(wcName,L"PERF_100NSEC_TIMER", 39); break;
case PERF_100NSEC_TIMER_INV: wcsncpy(wcName,L"PERF_100NSEC_TIMER_INV", 39); break;
case PERF_COUNTER_MULTI_TIMER: wcsncpy(wcName,L"PERF_COUNTER_MULTI_TIMER", 39); break;
case PERF_COUNTER_MULTI_TIMER_INV: wcsncpy(wcName,L"PERF_COUNTER_MULTI_TIMER_INV", 39); break;
case PERF_COUNTER_MULTI_BASE: wcsncpy(wcName,L"PERF_COUNTER_MULTI_BASE", 39); break;
case PERF_100NSEC_MULTI_TIMER: wcsncpy(wcName,L"PERF_100NSEC_MULTI_TIMER", 39); break;
case PERF_100NSEC_MULTI_TIMER_INV: wcsncpy(wcName,L"PERF_100NSEC_MULTI_TIMER_INV", 39); break;
case PERF_RAW_FRACTION: wcsncpy(wcName,L"PERF_RAW_FRACTION", 39); break;
case PERF_RAW_BASE: wcsncpy(wcName,L"PERF_RAW_BASE", 39); break;
case PERF_ELAPSED_TIME: wcsncpy(wcName,L"PERF_ELAPSED_TIME", 39); break;
case PERF_COUNTER_HISTOGRAM_TYPE: wcsncpy(wcName,L"PERF_COUNTER_HISTOGRAM_TYPE", 39); break;
case PERF_COUNTER_DELTA: wcsncpy(wcName,L"PERF_COUNTER_DELTA", 39); break;
case PERF_COUNTER_LARGE_DELTA: wcsncpy(wcName,L"PERF_COUNTER_LARGE_DELTA", 39); break;
default: StringCchPrintfW(wcName, sizeof(wcName)/sizeof(WCHAR), L"0x%x", dwCtrType); } wcName[39] = 0; CVariant var(wcName); BSTR bstr = SysAllocString(L"CounterType"); if(bstr) { sc = pQualifier->Put(bstr, var.GetVarPtr(), 0); SysFreeString(bstr); } pQualifier->Release();
}
//***************************************************************************
//
// CImpPerf::CImpPerf
//
// DESCRIPTION:
//
// Constuctor.
//
// PARAMETERS:
//
//***************************************************************************
CImpPerf::CImpPerf() { StringCchCopyW(wcCLSID, sizeof(wcCLSID)/sizeof(WCHAR), L"{F00B4404-F8F1-11CE-A5B6-00AA00680C3F}"); sMachine = TEXT("local"); hKeyMachine = HKEY_LOCAL_MACHINE; dwLastTimeUsed = 0; hKeyPerf = HKEY_PERFORMANCE_DATA; m_TitleBuffer = NULL; m_Size = 0; m_pCounter = NULL; hExec = CreateMutex(NULL, false, NULL); m_hTermEvent = CreateEvent(NULL,TRUE,FALSE,NULL); return; }
//***************************************************************************
//
// CImpPerf::~CImpPerf
//
// DESCRIPTION:
//
// Destructor.
//
//***************************************************************************
CImpPerf::~CImpPerf() { bool bGotMutex = false; if(hExec) { DWORD dwRet = WaitForSingleObject(hExec,2*MAX_EXEC_WAIT); if(dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED) bGotMutex = true; } if(bGotMutex) ReleaseMutex(hExec); FreeStuff(); sMachine.Empty(); if(hExec) CloseHandle(hExec); if(m_hTermEvent) CloseHandle(m_hTermEvent); }
//***************************************************************************
//
// SCODE CImpPerf::LoadData
//
// DESCRIPTION:
//
// Loads up the perf monitor data.
//
// PARAMETERS:
//
// ProvObj Object containing the property context string.
// pls Where to put the data
// piObject Identifies the perf mon object
// piCounter Identifies the perf mon counter
// **ppNew Created data block
// bJustGettingInstances Flag which indicates that we are actully
// looking for the instance names.
//
// RETURN VALUE:
//
// WBEM_E_INVALID_PARAMETER Bad context string
// WBEM_E_OUT_OF_MEMORY low memory
// otherwise error from called function
//
//***************************************************************************
SCODE CImpPerf::LoadData( CProvObj & ProvObj, LINESTRUCT * pls, int * piObject, int * piCounter, PERF_DATA_BLOCK **ppNew, BOOL bJustGettingInstances) { SCODE sc; BOOL bChange; if( ( ProvObj.sGetToken(0) == NULL ) || ( piObject == NULL ) || ( piCounter == NULL ) ) return WBEM_E_INVALID_PARAMETER; //BAD MAPPING STRING
// Determine if there has been a change in the machine being
// accessed. Save the current machine and get the handles if
// there was a change.
bChange = lstrcmpi(sMachine,ProvObj.sGetToken(0)); sMachine = ProvObj.sGetToken(0);
if(bChange) { sc = dwGetRegHandles(ProvObj.sGetToken(0)); if(sc != S_OK) return sc; }
// build up a table of the performance strings and
// their corresponding indexes. This only needs to be done
// when the buffer is empty or when the machine changes.
if(bChange || (m_TitleBuffer == NULL && m_pCounter == NULL)) { sc = GetPerfTitleSz (); if(sc != S_OK) return sc; }
// get the indexs for the object and counter names
dwLastTimeUsed = GetCurrentTime(); *piObject = iGetTitleIndex(ProvObj.sGetToken(1), FALSE); if(bJustGettingInstances) *piCounter = 0; else *piCounter = iGetTitleIndex(ProvObj.sGetToken(2), TRUE); if(*piObject == -1 || *piCounter == -1) { return WBEM_E_INVALID_PARAMETER; // bad mapping string
}
// Using the index for the object, get the perf counter data
// data.
sc = Cache.dwGetNew(ProvObj.sGetToken(0),*piObject,(LPSTR *)ppNew,pls); return sc; }
//***************************************************************************
//
// SCODE CImpPerf::RefreshProperty
//
// DESCRIPTION:
//
// Gets the value of a single property from the NT performance
// counter data.
//
// PARAMETERS:
//
// lFlags flags. Not currently used
// pClassInt Instance object
// PropName Property name
// ProvObj Object containing the property context string.
// pPackage Caching object
// pVar Points to value to set
// bTesterDetails Provide extra info for testers
// RETURN VALUE:
//
// S_OK all is well
// else probably set by LoadData or FindData.
//
//***************************************************************************
SCODE CImpPerf::RefreshProperty( IN long lFlags, IN IWbemClassObject FAR * pClassInt, IN BSTR PropName, IN CProvObj & ProvObj, OUT IN CObject * pPackage, OUT CVariant * pVar, BOOL bTesterDetails) { DWORD dwCtrType; float fRet; SCODE sc; int iObject,iCounter; PERF_DATA_BLOCK * pNew, * pOld; DWORD dwSize; LINESTRUCT ls; void * pCountData, *pIgnore; CVariant vPerf;
// The perf counter provider keeps some rather expensive data and
// so it doesnt support complete reentrancy.
if(hExec) { DWORD dwRet; dwRet = WaitForSingleObject(hExec,MAX_EXEC_WAIT); if(dwRet != WAIT_ABANDONED && dwRet != WAIT_OBJECT_0) return WBEM_E_FAILED; } else return WBEM_E_FAILED;
// Load up the data
sc = LoadData(ProvObj,&ls,&iObject,&iCounter,&pNew,FALSE); if(sc != S_OK) goto Done;
// Find the desired data.
sc = FindData(pNew,iObject,iCounter,ProvObj,&dwSize,&pCountData, &ls,TRUE,NULL); // find data sets the error in pMo!
if(sc != S_OK) goto Done;
// determine what type of counter it is
dwCtrType = ls.lnCounterType & 0xc00;
if(dwCtrType == PERF_TYPE_COUNTER) { // This type of counter requires time average data. Get the cache to
// get two buffers which are separated by a minimum amount of time
sc = Cache.dwGetPair(ProvObj.sGetToken(0),iObject, (LPSTR *)&pOld,(LPSTR *)&pNew,&ls); if(sc != S_OK) goto Done; sc = FindData(pNew,iObject,iCounter,ProvObj,&dwSize,&pCountData,&ls,TRUE,NULL); if(sc != S_OK) goto Done; sc = FindData(pOld,iObject,iCounter,ProvObj,&dwSize,&pIgnore,&ls,FALSE,NULL); if(sc != S_OK) goto Done; fRet = CounterEntry(&ls); vPerf.SetData(&fRet,VT_R4); } else if(dwCtrType == PERF_TYPE_NUMBER) { // Simple counter.
fRet = CounterEntry(&ls); vPerf.SetData(&fRet,VT_R4); } else if(dwCtrType == PERF_TYPE_TEXT) { // Text. Allocate enough space to hold the text and
// copy the text into temp WCHAR buffer since it is not
// clear from the documentation if the data in the block
// is null terminated.
WCHAR * pNew = (WCHAR *)CoTaskMemAlloc(dwSize+2); if(pNew == NULL) { sc = WBEM_E_OUT_OF_MEMORY; goto Done; } memset(pNew,0,dwSize+2); if(ls.lnCounterType & 0x10000) mbstowcs(pNew,(char *)pCountData,dwSize); else memcpy(pNew,pCountData,dwSize);
VARIANT * pVar = vPerf.GetVarPtr(); VariantClear(pVar); pVar->vt = VT_BSTR; pVar->bstrVal = SysAllocString(pNew); if(pVar->bstrVal == NULL) sc = WBEM_E_OUT_OF_MEMORY; CoTaskMemFree(pNew); if(sc != S_OK) { goto Done; } } // Convert the data into the desired form
sc = vPerf.DoPut(lFlags,pClassInt,PropName,pVar);
if(bTesterDetails) AddTesterDetails(pClassInt, PropName, dwCtrType);
Done: if(hExec) ReleaseMutex(hExec); return sc; }
//***************************************************************************
//
// SCODE CImpPerf::UpdateProperty
//
// DESCRIPTION:
//
// Normally this routine is used to save properties, but NT
// performance counter data is Read only.
//
// PARAMETERS:
//
// lFlags N/A
// pClassInt N/A
// PropName N/A
// ProvObj N/A
// pPackage N/A
// pVar N/A
//
// RETURN VALUE:
//
// E_NOTIMPL
//
//***************************************************************************
SCODE CImpPerf::UpdateProperty( long lFlags, IWbemClassObject FAR * pClassInt, BSTR PropName, CProvObj & ProvObj, CObject * pPackage, CVariant * pVar) { return E_NOTIMPL; }
//***************************************************************************
//
// void CImpPerf::FreeStuff
//
// DESCRIPTION:
//
// Used to free up memory that is no longer needed as well as
// freeing up registry handles.
//
//***************************************************************************
void CImpPerf::FreeStuff(void) { if(hKeyMachine != HKEY_LOCAL_MACHINE) { RegCloseKey(hKeyMachine); hKeyMachine = NULL; } if(hKeyPerf != HKEY_PERFORMANCE_DATA) { RegCloseKey(hKeyPerf); hKeyPerf = NULL; }
if(m_TitleBuffer) { delete [] m_TitleBuffer; m_TitleBuffer = NULL; } if (m_pCounter) { delete [] m_pCounter; m_pCounter = NULL; } m_Size = 0; m_IndexCache.Empty();
return; }
//***************************************************************************
//
// DWORD CImpPerf::GetPerfTitleSz
//
// DESCRIPTION:
//
// Retrieves the performance data title strings.
// This call retrieves english version of the title strings.
//
// RETURN VALUE:
//
// 0 if OK
// WBEM_E_OUT_OF_MEMORY if low memory
// else set by RegOpenKeyEx
//
//***************************************************************************
DWORD CImpPerf::GetPerfTitleSz () { HKEY hKey1; DWORD Type; DWORD dwR;
// Free any existing stuff
if(m_TitleBuffer) { delete [] m_TitleBuffer; m_TitleBuffer = NULL; } if (m_pCounter) { delete [] m_pCounter; m_pCounter = NULL; } m_Size = 0; m_IndexCache.Empty();
DWORD DataSize = 65536; DWORD nChars = DataSize/sizeof(WCHAR);
wmilib::auto_buffer<WCHAR> pTitleBuffer( new WCHAR[nChars]); if (NULL == pTitleBuffer.get()) return WBEM_E_OUT_OF_MEMORY; // Find out the size of the data.
dwR = RegQueryValueExW(HKEY_PERFORMANCE_TEXT, TEXT("Counter"), 0, &Type, (BYTE *)pTitleBuffer.get(), &DataSize); if (ERROR_MORE_DATA == dwR) { // Allocate more memory
//
nChars = DataSize/sizeof(WCHAR); pTitleBuffer.reset( new WCHAR[nChars]); if (NULL == pTitleBuffer.get()) return WBEM_E_OUT_OF_MEMORY;
// Query the data
//
dwR = RegQueryValueEx (HKEY_PERFORMANCE_TEXT, TEXT("Counter"), 0, &Type, (BYTE *)pTitleBuffer.get(), &DataSize); }
if(dwR == ERROR_ACCESS_DENIED) return WBEM_E_ACCESS_DENIED; if (dwR) return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwR);
//
// now parse the string, and set-up the arrays
// string will be parsed backwards
// expected fomat is
// L"12345678\0description\0\0"
//
WCHAR * pEnd = pTitleBuffer.get()+nChars; // points to the last char
pEnd--; while (*pEnd == L'\0') pEnd--; while (*pEnd) pEnd--; // past the zero after the last index
pEnd--; while (*pEnd) pEnd--; // this should point to the last index as a string
pEnd++; DWORD LastValidIndex = _wtoi(pEnd);
if (0 == LastValidIndex) return WBEM_E_FAILED;
LastValidIndex+=2; // just to be safe
wmilib::auto_buffer<WCHAR *> pCounter( new WCHAR*[LastValidIndex]); if (NULL == pCounter.get()) return WBEM_E_OUT_OF_MEMORY;
memset(pCounter.get(),0,LastValidIndex*sizeof(WCHAR *));
DWORD IndexCounter; WCHAR * pStartCounter = pTitleBuffer.get();
WCHAR * LimitMultiCounter = pTitleBuffer.get() + nChars;
while ((*pStartCounter) && (pStartCounter < LimitMultiCounter)) { IndexCounter = _wtoi(pStartCounter); while(*pStartCounter) pStartCounter++; pStartCounter++; // points to the string
if (IndexCounter && (IndexCounter < LastValidIndex)) { pCounter[IndexCounter] = (WCHAR *)(((ULONG_PTR)pStartCounter)|1); } // skip the string
while(*pStartCounter) pStartCounter++; pStartCounter++; // points to the next number
}
m_TitleBuffer = pTitleBuffer.release(); m_pCounter = pCounter.release(); m_Size = LastValidIndex;
EliminateRanges(); return dwR; }
void CImpPerf::EliminateRanges() { // the index1 is the span of the system reserved indexes
WCHAR * pString = m_pCounter[1]; DWORD SystemIndexes = 0; if (pString) { SystemIndexes = 1 + _wtoi((WCHAR *)((ULONG_PTR)pString & (~1))); } for (DWORD i = 0; i<min(SystemIndexes,m_Size); i++) { ULONG_PTR p = (ULONG_PTR)m_pCounter[i]; if (p) { p &= (~1L); m_pCounter[i] = (WCHAR *)p; } }
OnDeleteObjIf0<CImpPerf,void(CImpPerf:: *)(void),&CImpPerf::MakeAllValid> AllValid(this);
HKEY hKey; LONG lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services", 0, KEY_ENUMERATE_SUB_KEYS, &hKey); if (ERROR_SUCCESS != lRet) return; OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> regClMe(hKey);
DWORD BaseSize = 256; wmilib::auto_buffer<WCHAR> pKeyName(new WCHAR[BaseSize]); if (NULL == pKeyName.get()) return;
DWORD FullKeySize = 256 + 13; // add length_of "\\performance"
wmilib::auto_buffer<WCHAR> pFullKeyName(new WCHAR[FullKeySize]); if (NULL == pFullKeyName.get()) return; DWORD dwEnumIndex = 0; LONG lRes; while (TRUE) { DWORD dwRequiredSize = BaseSize; lRes = RegEnumKeyExW(hKey,dwEnumIndex,pKeyName.get(),&dwRequiredSize, NULL, NULL, NULL, NULL); if (ERROR_SUCCESS == lRes) { if (BaseSize > FullKeySize) { pFullKeyName.reset(new WCHAR[BaseSize + 13]); if (NULL == pFullKeyName.get()) return; FullKeySize = BaseSize + 13; } StringCchCopyW(pFullKeyName.get(),FullKeySize,pKeyName.get()); StringCchCatW(pFullKeyName.get(),FullKeySize,L"\\Performance");
HKEY hKeySec; LONG lResInner = RegOpenKeyExW(hKey,pFullKeyName.get(), 0, KEY_READ, &hKeySec); if (ERROR_SUCCESS != lResInner) { //DbgPrintfA(0,"KEY: %S ERR: %08x\n",pFullKeyName.get(),lResInner);
dwEnumIndex++; continue; } OnDelete<HKEY,LONG(*)(HKEY),RegCloseKey> regClMe2(hKeySec);
DWORD FirstCounter; DWORD LastCounter; DWORD dwSize = sizeof(DWORD); DWORD dwType; lResInner = RegQueryValueExW(hKeySec, L"First Counter", 0, &dwType, (BYTE*)&FirstCounter, &dwSize); if (ERROR_SUCCESS != lResInner || REG_DWORD != dwType) goto end_internal;
dwSize = sizeof(DWORD); lResInner = RegQueryValueExW(hKeySec, L"Last Counter", 0, &dwType, (BYTE*)&LastCounter, &dwSize); if (ERROR_SUCCESS != lResInner || REG_DWORD != dwType) goto end_internal;
//DbgPrintfA(0,"PerfLib %S First %d Last %d\n",pKeyName.get(),FirstCounter,LastCounter);
if (FirstCounter > m_Size) goto end_internal; if (LastCounter > m_Size) goto end_internal;
for (DWORD i=FirstCounter; i<=LastCounter;i++) { ULONG_PTR p = (ULONG_PTR)m_pCounter[i]; if (p) { p &= (~1L); m_pCounter[i] = (WCHAR *)p; } }; end_internal: dwEnumIndex++; continue; } else if (ERROR_MORE_DATA == lRes) { BaseSize += 256; pKeyName.reset(new WCHAR[BaseSize]); if (NULL == pKeyName.get()) return; // fall back to the regular case
continue; } else if (ERROR_NO_MORE_ITEMS == lRes) { break; // exit the loop;
} else { return; // not a known error
} } AllValid.dismiss();
/*
for (DWORD i = 0; i< m_Size; i++) { ULONG_PTR p = (ULONG_PTR)m_pCounter[i]; if (p) { if ((ULONG_PTR)p & 1L) { DbgPrintfA(0,"Eliminated Index %d - %S\n",i,(WCHAR *)((ULONG_PTR)p & (~1))); } } } */ }
//
// this function is used if we cannot estabilish which indexes are valid
//
////////////////////////////////////////////////////////////
void CImpPerf::MakeAllValid() { for (DWORD i = 0; i< m_Size; i++) { ULONG_PTR p = (ULONG_PTR)m_pCounter[i]; if (p) { p &= (~1L); m_pCounter[i] = (WCHAR *)p; } } }
//***************************************************************************
//
// DWORD CImpPerf::dwGetRegHandles
//
// DESCRIPTION:
//
// Sets the handles for the local computer and the performance
// information.
//
// PARAMETERS:
//
// pMachine Machine name
//
// RETURN VALUE:
//
// S_OK all is well
// otherwise return is from RegConnectRegistry
//***************************************************************************
DWORD CImpPerf::dwGetRegHandles( const TCHAR * pMachine) { DWORD dwRet; TCHAR pTemp[256]; if(pMachine == NULL) return WBEM_E_INVALID_PARAMETER; StringCchCopyW(pTemp, 256, pMachine);
// if the current handles are to a remote machine, then free them
if(!lstrcmpi(sMachine,TEXT("local"))) { if(hKeyPerf && hKeyPerf != HKEY_PERFORMANCE_DATA) RegCloseKey(hKeyPerf); if(hKeyMachine) RegCloseKey(hKeyMachine); hKeyPerf = hKeyMachine = NULL; }
// Determine if the target is remote or local
if(lstrcmpi(pMachine,TEXT("local"))) { // Remote, connect up
dwRet = RegConnectRegistry(pTemp,HKEY_PERFORMANCE_DATA, &hKeyPerf); if(dwRet != S_OK) // could not remote connect
return dwRet;
dwRet = RegConnectRegistry(pTemp,HKEY_LOCAL_MACHINE, &hKeyMachine); if(dwRet != S_OK) { RegCloseKey(hKeyPerf); hKeyPerf = hKeyMachine = NULL; return dwRet; } } else { hKeyMachine = HKEY_LOCAL_MACHINE; hKeyPerf = HKEY_PERFORMANCE_DATA; } return 0; }
//***************************************************************************
//
// int CImpPerf::iGetTitleIndex
//
// DESCRIPTION:
//
// Looks for the name in the buffer containing the names and
// returns the index. The buffer is a series of strings with a double
// null at the end. Each counter or object is represented by a pair of
// strings with the first having the number and the second having the
// text. This code goes through the pairs, storing the number string and
// checking the text vs the input. If a match, then the number is returned.
//
// PARAMETERS:
//
// pSearch String to be found in buffer
//
// RETURN VALUE:
//
// integer that goes with the string. -1 if not found
//
//***************************************************************************
int CImpPerf::iGetTitleIndex( const TCHAR * pSearch, BOOL addDups) { int iRet = -1; if(pSearch == NULL) return -1; DWORD Index = m_IndexCache.Find(pSearch); if(Index != -1) return Index; for (DWORD i = 0; i< m_Size; i++) { ULONG_PTR p = (ULONG_PTR)m_pCounter[i]; if (p) { if (!(p & 1)) // a pointer is valid if it DOES NOT have the low bit set
{ if (0 == wbem_wcsicmp(pSearch,m_pCounter[i])) { m_IndexCache.Add(m_pCounter[i], i); //DbgPrintfA(0,"%d - %S\n",i,m_pCounter[i]);
if(addDups == FALSE) return i; if(iRet == -1) iRet = i; } } } } return iRet; }
//***************************************************************************
//
// SCODE CImpPerf::FindData
//
// DESCRIPTION:
//
// Finds the counter in the data block. Note that the steps are quite
// involved and an understanding of the structure of performance data
// is probably required. See chap 66 of the Win32 Programmers Ref.
//
//
// PARAMETERS:
//
// pData Data block to be searched
// iObj Int which identifies the object
// iCount Int which identifies the counter
// ProvObj Object containing the parsed context string
// pdwSize Size of data
// **ppRetData points to data
// pls Line structure
// bNew If true, indicates that we are searching the newest
// sample of data.
// pInfo If set, points to an collection object which
// contains a list of instance names. By being set
// the function doesnt look for actual data, instead
// it is used just to get the instance names.
//
// RETURN VALUE:
//
// S_OK all is well
// WBEM_E_FAILED couldnt find the data in the block
//
//***************************************************************************
SCODE CImpPerf::FindData( IN PERF_DATA_BLOCK * pData, IN int iObj, IN int iCount, IN CProvObj & ProvObj, OUT DWORD * pdwSize, OUT void **ppRetData, OUT PLINESTRUCT pls, IN BOOL bNew, OUT CEnumPerfInfo * pInfo) { try { int iIndex; BOOL bEqual; DWORD dwSize = 0; DWORD dwType,dwTypeBase = 0; *ppRetData = NULL; void * pVoid = NULL, * pVoidBase = NULL; PPERF_OBJECT_TYPE pObj = NULL; PPERF_COUNTER_DEFINITION pCount = NULL; PPERF_COUNTER_DEFINITION pCountBase= NULL; PPERF_INSTANCE_DEFINITION pInst = NULL;
// Some objects, such as disks, have what are called instances and in
// that case the provider string will have an extra token with the
// instance name in it.
WCHAR wInstName[MAX_PATH]; wInstName[0] = 0; WCHAR * pwInstName = wInstName; long lDuplicateNum = 0;
// If there is an instance name, convert it to WCHAR. Also, the
// instance name may be of the for "[123]chars" and in this case the
// didits between "[]" are converted to a number and the actual name
// starts after the ']'.
if(ProvObj.iGetNumTokens() > 3) { if(lstrlen(ProvObj.sGetToken(3)) > MAX_PATH -1) return WBEM_E_FAILED; #ifdef UNICODE
StringCchCopyW(wInstName, MAX_PATH, ProvObj.sGetToken(3)); #else
mbstowcs(wInstName, ProvObj.sGetToken(3), MAX_PATH-1); #endif
if(wInstName[0] == L'[') { lDuplicateNum = _wtol(&wInstName[1]); for(pwInstName = &wInstName[1]; *pwInstName && *pwInstName != L']'; pwInstName++); // INTENTIONAL SEMI!
if(*pwInstName == L']') pwInstName++; } } else { // if there is not an instance name and the argument for enumeration is null, then we have a
// bad path
if(pInfo == NULL) return WBEM_E_INVALID_OBJECT_PATH; }
// Go through the list of objects and find the one
// that matches iObj
pObj = (PPERF_OBJECT_TYPE)((PBYTE)pData + pData->HeaderLength); for(iIndex = 0; iIndex < (int)pData->NumObjectTypes; iIndex++) { if((int)pObj->ObjectNameTitleIndex == iObj) break; // found it!
pObj = (PPERF_OBJECT_TYPE)((PBYTE)pObj + pObj->TotalByteLength); } if(iIndex == (int)pData->NumObjectTypes) return WBEM_E_FAILED; // never found object in the block
// Object was found, set the object type data
if(bNew) { pls->ObjPerfFreq = *(LONGLONG UNALIGNED *)(&pObj->PerfFreq); pls->ObjCounterTimeNew = *(LONGLONG UNALIGNED *)(&pObj->PerfTime); } else pls->ObjCounterTimeOld = *(LONGLONG UNALIGNED *)(&pObj->PerfTime);
// Go through the list of counters for the object and find the one that
// matches iCount. Note that some counter names may be have more than
// one id. Therefore, try the other ids if the intial one doesnt work.
bool bFound = false; bool bEndOfList = false; int lTry = 0; // how may times we have tried
do {
pCount = (PPERF_COUNTER_DEFINITION)((PBYTE)pObj + pObj->HeaderLength); for(iIndex = 0; iIndex < (int)pObj->NumCounters; iIndex++) { if((int)pCount->CounterNameTitleIndex == iCount || pInfo) { bFound = true; break; // found it!
} pCount = (PPERF_COUNTER_DEFINITION)((PBYTE)pCount + pCount->ByteLength); } if(bFound == false) { lTry++; iCount = m_IndexCache.Find(ProvObj.sGetToken(2), lTry); if(iCount == -1) bEndOfList = true; } } while (bFound == false && bEndOfList == false);
if(bFound == false) { return WBEM_E_FAILED; // never found object in the block
}
// The counter was found, save the counter information
// If the counter is not the last one in the object, then the
// next one might be the base which is used for certain calculations
dwType = pCount->CounterType; pls->lnCounterType = pCount->CounterType; if(iIndex < (int)pObj->NumCounters - 1) {
// might be the base
pCountBase = (PPERF_COUNTER_DEFINITION)((PBYTE)pCount + pCount->ByteLength); dwTypeBase = pCountBase->CounterType; }
// Get a pointer to the start of the perf counter block
// There are two cases: If there are no instances, then
// the data starts after the last counter descriptor.
// If there are instances, each instance has it's own block.
pVoid = NULL; if(pObj->NumInstances == -1) { // The object is a singleton
if(pInfo) // If we are enumerating instances
{ pInfo->AddEntry(L"@"); return S_OK; }
// easy case, get offset into data, add offset
// for particular counter.
pVoid = (PBYTE)pObj + pObj->DefinitionLength + pCount->CounterOffset; if(pCountBase) pVoidBase = (PBYTE)pObj + pObj->DefinitionLength + pCountBase->CounterOffset; } else if(pObj->NumInstances > 0) {
WCHAR wNum[12]; // hard case, got a list of instaces, start off
// by getting a pointer to the first one.
long lNumDupsSoFar = 0; pInst= (PPERF_INSTANCE_DEFINITION)((PBYTE)pObj + pObj->DefinitionLength); for(iIndex = 0; iIndex < (int)pObj->NumInstances; iIndex++) {
// Each instance has a unicode name, get it and
// compare it against the name passed in the
// provider string.
PPERF_COUNTER_BLOCK pCtrBlk; WCHAR * pwName; if(pInst->UniqueID == PERF_NO_UNIQUE_ID) pwName = (WCHAR *)((PBYTE)pInst + pInst->NameOffset); else { _ltow (pInst->UniqueID, wNum, 10); pwName = wNum; } if(pInfo) { // We we are mearly getting the instance names, just add the
// instance name to the list. If the instance name is a
// duplicate, prepend "[num]" to the name.
if(wcslen(pwName) > 240) continue; // should never happen but just in case!
int iRet = pInfo->GetNumDuplicates(pwName); if(iRet > 0) { StringCchPrintfW (wInstName, MAX_PATH, L"[%ld]", iRet); StringCchCatW(wInstName, MAX_PATH, pwName); } else StringCchCopyW(wInstName, MAX_PATH, pwName); pInfo->AddEntry(wInstName); } else { // for now the code assumes that the first instance
// will be retrieved if the instance is not specified
if(wcslen(pwInstName) == 0) bEqual = TRUE; else { bEqual = !wbem_wcsicmp(pwName ,pwInstName); if(lDuplicateNum > lNumDupsSoFar && bEqual) { bEqual = FALSE; lNumDupsSoFar++; } } if(bEqual) { // we found the instance !!!! Data is found
// in data block following instance offset
// appropriatly for this counter.
pVoid = (PBYTE)pInst + pInst->ByteLength + pCount->CounterOffset; if(pCountBase) pVoidBase = (PBYTE)pInst + pInst->ByteLength + pCountBase->CounterOffset; break; } } // not found yet, next instance is after this
// instance + this instance's counter data
pCtrBlk = (PPERF_COUNTER_BLOCK)((PBYTE)pInst + pInst->ByteLength); pInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)pInst + pInst->ByteLength + pCtrBlk->ByteLength); } }
// Bail out if data was never found or if we were just looking for instances
if(pInfo) return pInfo->GetStatus();
if(pVoid == NULL) { return WBEM_E_FAILED; // never found object in the block
}
// Move the counter data and possibly the base data into the structure
// Note that text is handled via the ppRetData pointer and is not
// done here.
DWORD dwSizeField = dwType & 0x300; void * pDest = (bNew) ? &pls->lnaCounterValue[0] : &pls->lnaOldCounterValue[0]; if(dwSizeField == PERF_SIZE_DWORD) { memset(pDest,0,sizeof(LONGLONG)); // zero out unused portions
dwSize = sizeof(DWORD); memcpy(pDest,pVoid,dwSize); } else if(dwSizeField == PERF_SIZE_LARGE) { dwSize = sizeof(LONGLONG); memcpy(pDest,pVoid,dwSize); } else if(dwSizeField == PERF_SIZE_VARIABLE_LEN) dwSize = pCount->CounterSize; // this sets it for text
else { return WBEM_E_FAILED; // never found object in the block
}
// possibly do the base now.
dwSizeField = dwTypeBase & 0x300; pDest = (bNew) ? &pls->lnaCounterValue[1] : &pls->lnaOldCounterValue[1]; if(dwSizeField == PERF_SIZE_DWORD && pVoidBase) { memset(pDest,0,sizeof(LONGLONG)); memcpy(pDest,pVoidBase,sizeof(DWORD)); } else if(dwSizeField == PERF_SIZE_LARGE && pVoidBase) memcpy(pDest,pVoidBase,sizeof(LONGLONG));
*ppRetData = pVoid; // Set to return data
*pdwSize = dwSize; return S_OK; } catch(...) { return WBEM_E_FAILED; } }
//***************************************************************************
//
// SCODE CImpPerf::MakeEnum
//
// DESCRIPTION:
//
// Creates a CEnumPerfInfo object which can be used for enumeration
//
// PARAMETERS:
//
// pClass Pointer to the class object.
// ProvObj Object containing the property context string.
// ppInfo Set to point to an collection object which has
// the keynames of the instances.
//
// RETURN VALUE:
//
// S_OK all is well,
// else set by LoadData or FindData
//
//***************************************************************************
SCODE CImpPerf::MakeEnum( IN IWbemClassObject * pClass, IN CProvObj & ProvObj, OUT CEnumInfo ** ppInfo) { SCODE sc; int iObject,iCounter; PERF_DATA_BLOCK * pNew; DWORD dwSize; LINESTRUCT ls; void * pCountData; CVariant vPerf; CEnumPerfInfo * pInfo = NULL; *ppInfo = NULL;
// The perf counter provider keeps some rather expensive data and
// so it doesnt support complete reentrancy.
if(hExec) { DWORD dwRet; dwRet = WaitForSingleObject(hExec,MAX_EXEC_WAIT); if(dwRet != WAIT_ABANDONED && dwRet != WAIT_OBJECT_0) return WBEM_E_FAILED; } else return WBEM_E_FAILED;
// Load up the data
sc = LoadData(ProvObj,&ls,&iObject,&iCounter,&pNew,TRUE); if(sc != S_OK) goto DoneMakeEnum; // Create a new CEnumPerfInfo object. Its entries will be filled
// in by Find Data.
pInfo = new CEnumPerfInfo(); if(pInfo == NULL) { sc = WBEM_E_OUT_OF_MEMORY; goto DoneMakeEnum; } sc = FindData(pNew,iObject,iCounter,ProvObj,&dwSize,&pCountData, &ls,TRUE,pInfo); if(sc != S_OK) delete pInfo;
DoneMakeEnum: if(sc == S_OK) *ppInfo = pInfo; if(hExec) ReleaseMutex(hExec); return sc; } //***************************************************************************
//
// SCODE CImpPerf::GetKey
//
// DESCRIPTION:
//
// Gets the key name of an entry in the enumeration list.
//
// PARAMETERS:
//
// pInfo Collection list
// iIndex Index in the collection
// ppKey Set to the string. MUST BE FREED with "delete"
//
// RETURN VALUE:
//
// S_OK if all is well
// WBEM_E_INVALID_PARAMETER bad index
// WBEM_E_OUT_OF_MEMORY
//***************************************************************************
SCODE CImpPerf::GetKey( IN CEnumInfo * pInfo, IN int iIndex, OUT LPWSTR * ppKey) { DWORD dwLen; CEnumPerfInfo * pPerfInfo = (CEnumPerfInfo *)pInfo; LPWSTR pEntry = pPerfInfo->GetEntry(iIndex); if(pEntry == NULL) return WBEM_E_INVALID_PARAMETER; dwLen = wcslen(pEntry)+1; *ppKey = new WCHAR[dwLen]; if(*ppKey == NULL) return WBEM_E_OUT_OF_MEMORY; StringCchCopyW(*ppKey, dwLen,pEntry); return S_OK; }
//***************************************************************************
//
// SCODE CImpPerf::MergeStrings
//
// DESCRIPTION:
//
// Combines the Class Context, Key, and Property Context strings.
//
// PARAMETERS:
//
// ppOut Output string. MUST BE FREED VIA "delete"
// pClassContext Class context
// pKey Key property value
// pPropContext Property context
//
// RETURN VALUE:
//
// S_OK if all is well
// WBEM_E_INVALID_PARAMETER context string
// WBEM_E_OUT_OF_MEMORY
//
//***************************************************************************
SCODE CImpPerf::MergeStrings( OUT LPWSTR * ppOut, IN LPWSTR pClassContext, IN LPWSTR pKey, IN LPWSTR pPropContext) { // Allocate space for output
int iLen = 3; if(pClassContext) iLen += wcslen(pClassContext); if(pKey) iLen += wcslen(pKey); if(pPropContext) iLen += wcslen(pPropContext); else return WBEM_E_INVALID_PARAMETER; // should always have this!
*ppOut = new WCHAR[iLen]; if(*ppOut == NULL) return WBEM_E_OUT_OF_MEMORY;
//todo todo, remove this demo specical
if(pPropContext[0] == L'@') { StringCchCopyW(*ppOut, iLen, pPropContext+1); return S_OK; } //todo todo, remove this demo specical
// simplecase is that everything is in the property context. That would
// be the case when the provider is being used as a simple dynamic
// property provider
if(pClassContext == NULL || pKey == NULL) { StringCchCopyW(*ppOut, iLen, pPropContext); return S_OK; }
// Copy the class context, property, and finally the key
StringCchCopyW(*ppOut, iLen, pClassContext); StringCchCatW(*ppOut, iLen, L"|"); StringCchCatW(*ppOut, iLen, pPropContext); StringCchCatW(*ppOut, iLen, L"|"); StringCchCatW(*ppOut, iLen, pKey); return S_OK; }
//***************************************************************************
//
// CEnumPerfInfo::CEnumPerfInfo
//
// DESCRIPTION:
//
// Constructor.
//
//***************************************************************************
CEnumPerfInfo::CEnumPerfInfo() { m_iNumUniChar = 0; m_iNumEntries = 0; m_pBuffer = NULL; m_status = S_OK; }
//***************************************************************************
//
// CEnumPerfInfo::~CEnumPerfInfo
//
// DESCRIPTION:
//
// Destructor.
//
//***************************************************************************
CEnumPerfInfo::~CEnumPerfInfo() { if(m_pBuffer) delete m_pBuffer; }
//***************************************************************************
//
// void CEnumPerfInfo::AddEntry
//
// DESCRIPTION:
//
// Adds an entry to the enumeration list.
//
// PARAMETERS:
//
// pNew String to add to collection.
//
//***************************************************************************
void CEnumPerfInfo::AddEntry( LPWSTR pNew) { if(m_status != S_OK) return; // already had memory problems.
int iNewSize = wcslen(pNew) + 1 + m_iNumUniChar; LPWSTR pNewBuff = new WCHAR[iNewSize]; if(pNewBuff == NULL) { m_status = WBEM_E_OUT_OF_MEMORY; return; } StringCchCopyW(&pNewBuff[m_iNumUniChar], iNewSize - m_iNumUniChar,pNew); if(m_pBuffer) { memcpy(pNewBuff,m_pBuffer,m_iNumUniChar*2); delete m_pBuffer; } m_iNumEntries++; m_iNumUniChar = iNewSize; m_pBuffer = pNewBuff; }
//***************************************************************************
//
// int CEnumPerfInfo::GetNumDuplicates
//
// DESCRIPTION:
//
// Checks the list to find duplicate entries.
//
// PARAMETERS:
//
// pwcTest string to test for duplicates
//
// RETURN VALUE:
//
// number of matching strings in the collection.
//
//***************************************************************************
int CEnumPerfInfo::GetNumDuplicates( LPWSTR pwcTest) { int iRet = 0; int iCnt; LPWSTR pVal = m_pBuffer; for(iCnt = 0; iCnt < m_iNumEntries; iCnt++) { WCHAR * pwcText = pVal;
// If the string is of the form "[number]text", skip the "[number]"
// part.
if(*pVal == L'[') { for(pwcText = pVal+1; *pwcText && *pwcText != L']';pwcText++); if(*pwcText == L']') pVal = pwcText+1; } if(!wbem_wcsicmp(pwcTest, pVal)) iRet++; pVal += wcslen(pVal) + 1; } return iRet; }
//***************************************************************************
//
// LPWSTR CEnumPerfInfo::GetEntry
//
// DESCRIPTION:
//
// Gets a list entry.
//
// PARAMETERS:
//
// iIndex collection index
//
// RETURN VALUE:
//
// pointer to string in index. Should NOT be freed.
// NULL if bad index
//
//***************************************************************************
LPWSTR CEnumPerfInfo::GetEntry( IN int iIndex) { // fist check for bad conditions
if(m_status != S_OK || iIndex < 0 || iIndex >= m_iNumEntries) return NULL; int iCnt; LPWSTR pRet = m_pBuffer; for(iCnt = 0; iCnt < iIndex; iCnt++) pRet += wcslen(pRet) + 1; return pRet; }
//***************************************************************************
//
// CImpPerfProp::CImpPerfProp
//
// DESCRIPTION:
//
// Constructor.
//
//***************************************************************************
CImpPerfProp::CImpPerfProp() { m_pImpDynProv = new CImpPerf(); }
//***************************************************************************
//
// CImpPerfProp::~CImpPerfProp
//
// DESCRIPTION:
//
// Destructor.
//
//***************************************************************************
CImpPerfProp::~CImpPerfProp() { if(m_pImpDynProv) delete m_pImpDynProv; }
|