/************************************************************ * FILE: CPerfMan.cpp * PURPOSE: Implementation of the CPerfMan class * HISTORY: * // t-JeffS 970810 15:14:43: Created ************************************************************/ #include #include #include "cperfman.h" #include "perfskel.h" extern "C" { #include "perfutil.h" } /************************************************************ * CLASS: CPerfMan * PURPOSE: Perform all the generic work an NT perf DLL normaly does. ************************************************************/ /************************************************************ * FUNCTION: CPerfMan::CPerfMan * PURPOSE: Initialize CPerfMan private data * HISTORY: * // t-JeffS 970810 15:15:44: Created ************************************************************/ CPerfMan::CPerfMan() : m_dwNumCounters(0), m_pszAppName(NULL), m_lRefCount(0), m_pObjectType(NULL), m_pCounterDefs(NULL), m_cbDataDef(0) { InitializeCriticalSection( &m_cs ); } /************************************************************ * FUNCTION: CPerfMan::~CPerfMan * PURPOSE: Cleanup member data * HISTORY: * // t-JeffS 970810 15:15:44: Created ************************************************************/ CPerfMan::~CPerfMan() { DeleteCriticalSection( &m_cs ); if( m_pszAppName ) { delete m_pszAppName; } } /************************************************************ * FUNCTION: CPerfMan::Initialize * PURPOSE: Initialize and be ready for perf calls * PARAMETERS: szAppName: Unique name for each user of this class * pDataDef: Pointer to a skeleton data definition struct * for this group of counters. See below for * general form of this struct * dwNumCounters: Number of perf counters for this object. * * example data definition struct: * typedef struct _AB_DATA_DEFINITON { * PERF_OBJECT_TYPE ABObjType; * PERF_COUNTER_DEFINITION AB_Resolves_Counter; * PERF_COUNTER_DEFINITION AB_ResolveCalls_Counter; * PERF_COUNTER_DEFINITION AB_PassCalls_Counter; * PERF_COUNTER_DEFINITION AB_FailCalls_Counter; * }; * And in this case, dwNumCounters = 4; * Caller should initialize all offsets in * PERF_COUNTER_DEFINITION blocks to be relative to object * type (see dataab.h/dataab.cpp in abook for an example) * Also assumes each counter size is sizeof(DWORD) * HISTORY: * // t-JeffS 970810 15:15:44: Created ************************************************************/ BOOL CPerfMan::Initialize( LPTSTR szAppName, PVOID pDataDef, DWORD dwNumCounters ) { _ASSERT( szAppName ); _ASSERT( pDataDef ); _ASSERT( dwNumCounters > 0 ); m_pszAppName = new TCHAR[ lstrlen( szAppName) + 1]; if(! m_pszAppName ) { // Set error out of memory return FALSE; } lstrcpy( m_pszAppName, szAppName ); m_dwNumCounters = dwNumCounters; m_pObjectType = (PPERF_OBJECT_TYPE) pDataDef; m_pCounterDefs = (PPERF_COUNTER_DEFINITION) &m_pObjectType[1]; m_cbDataDef = sizeof(PERF_OBJECT_TYPE) + (dwNumCounters * sizeof(PERF_COUNTER_DEFINITION)); return SetOffsets(); } /************************************************************ * Function: CPerfMan::SetOffsets() * Purpose: Increment offsets in data definition block * Arguments: None; uses member data. * History: * // t-JeffS 970810 15:40:33: Created ************************************************************/ BOOL CPerfMan::SetOffsets() { // Get stuff from registry // get counter and help index base values from registry // Open key to registry entry // read First Counter and First Help values // update static data structures by adding base to // offset value in structure HKEY hRegKey; TCHAR szRegKey[256]; lstrcpy(szRegKey, TEXT("SYSTEM\\CurrentControlSet\\Services\\")); lstrcat(szRegKey, m_pszAppName ); lstrcat(szRegKey, TEXT("\\Performance")); if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szRegKey, 0L, KEY_ALL_ACCESS, &hRegKey ) != ERROR_SUCCESS) { return FALSE; } DWORD dwFirstCounter; DWORD dwFirstHelp; DWORD dwsize = sizeof(DWORD); DWORD dwtype; if( RegQueryValueEx( hRegKey, TEXT("First Counter"), 0L, &dwtype, (LPBYTE)&dwFirstCounter, &dwsize ) != ERROR_SUCCESS) { return FALSE; } dwsize = sizeof(DWORD); if( RegQueryValueEx( hRegKey, "First Help", 0L, &dwtype, (LPBYTE)&dwFirstHelp, &dwsize ) != ERROR_SUCCESS) { return FALSE; } // // Now adjust the perf datadef structure // m_pObjectType->ObjectNameTitleIndex += dwFirstCounter; m_pObjectType->ObjectHelpTitleIndex += dwFirstHelp; DWORD dwCount; for(dwCount = 0; dwCount < m_dwNumCounters; dwCount++) { m_pCounterDefs[dwCount].CounterNameTitleIndex += dwFirstCounter; m_pCounterDefs[dwCount].CounterHelpTitleIndex += dwFirstHelp; } RegCloseKey(hRegKey); return TRUE; } /************************************************************ * FUNCTION: CPerfMan::OpenPerformanceData * PURPOSE: Do leg work of a generic openperfdata call * ARGUMENTS: lpDeviceNames: * HISTORY: Pointer to object ID of each device to be opened ( not used here) * // t-JeffS 970810 16:19:10: Created ************************************************************/ DWORD CPerfMan::OpenPerformanceData( LPWSTR lpDeviceNames ) { //EnterCriticalSection( &m_cs ); if( m_lRefCount == 0) { // We're the first instance to use this, initialize stuff if( ! m_cShare.Initialize( m_pszAppName, FALSE, m_dwNumCounters * sizeof(DWORD)) ) { // Init failed //LeaveCriticalSection( &m_cs ); return ERROR_SERVICE_DOES_NOT_EXIST; } } m_lRefCount++; //LeaveCriticalSection( &m_cs ); return ERROR_SUCCESS; } /************************************************************ * FUNCTION: CPerfMan::CollectPerformanceData * PURPOSE: Do leg work of collecting performance data from shared mem * ARGUMENTS: lpValueName: The name of the value to retrieve * lppData: On entry contains a pointer to the buffer to * receive the completed PerfDataBlock & subordinate * structures. On exit, points to the first bytes * *after* the data structures added by this routine. * lpcbTotalBytes: On entry contains a pointer to the * size (in BYTEs) of the buffer referenced by lppData. * On exit, contains the number of BYTEs added by this * routine. * lpNumObjectTypes: Receives the number of objects added * by this routine. ************************************************************/ DWORD CPerfMan::CollectPerformanceData( IN LPWSTR lpValueName, IN OUT LPVOID *lppData, IN OUT LPDWORD lpcbTotalBytes, OUT LPDWORD lpNumObjectTypes) { DWORD dwQueryType; dwQueryType = GetQueryType(lpValueName); if (dwQueryType == QUERY_FOREIGN ) { // this routine doesn't service requests for data from // foreign computers *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } // // check to see if this object is requested // if (dwQueryType == QUERY_ITEMS) { if ( !(IsNumberInUnicodeList( m_pObjectType->ObjectNameTitleIndex, lpValueName ) ) ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_SUCCESS; } } ULONG ulSpaceNeeded = m_cbDataDef + ( SizeOfPerformanceData() ); if ( *lpcbTotalBytes < ulSpaceNeeded ) { *lpcbTotalBytes = (DWORD) 0; *lpNumObjectTypes = (DWORD) 0; return ERROR_MORE_DATA; } // // have a local pointer point to the buffer // PVOID pDataDef = *lppData; // // copy the pre-prepared constant data to the buffer // CopyMemory( pDataDef, m_pObjectType, m_cbDataDef); // // Format and collect data from shared memory // PPERF_COUNTER_BLOCK pPerfCounterBlock = (PERF_COUNTER_BLOCK *) ((PBYTE)pDataDef + m_cbDataDef); pPerfCounterBlock->ByteLength = SizeOfPerformanceData(); PBYTE pbCounter = (PBYTE)(&pPerfCounterBlock[1]); // Get all the counters direct from shared memory if( !m_cShare.GetMem( 0, pbCounter, SizeOfPerformanceData() - sizeof(DWORD) )) { return GetLastError(); // some error } // Update arguments before returning *lppData = (PVOID) (pbCounter + SizeOfPerformanceData() - sizeof(DWORD)); *lpNumObjectTypes = 1; *lpcbTotalBytes = (PBYTE) *lppData - (PBYTE) pDataDef; return ERROR_SUCCESS; } /************************************************************ * FUNCTION: CPerfMan::ClosePerformanceData * PURPOSE: Do the leg work of closing performance data * ARGUMENTS: None * HISTORY: * // t-JeffS 970810 17:00:03: Created ************************************************************/ DWORD CPerfMan::ClosePerformanceData() { //EnterCriticalSection( &m_cs ); if( m_lRefCount == 1) { // Clean up. // okay...uh...nothing to do. } m_lRefCount--; //LeaveCriticalSection( &m_cs ); return ERROR_SUCCESS; }