2025-04-27 07:49:33 -04:00

313 lines
10 KiB
C++

/************************************************************
* FILE: CPerfMan.cpp
* PURPOSE: Implementation of the CPerfMan class
* HISTORY:
* // t-JeffS 970810 15:14:43: Created
************************************************************/
#include <windows.h>
#include <crtdbg.h>
#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;
}