You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1101 lines
31 KiB
1101 lines
31 KiB
/*==========================================================================*\
|
|
|
|
Module: exprflib.cpp
|
|
|
|
Copyright Microsoft Corporation 1998, All Rights Reserved.
|
|
|
|
Author: WayneC
|
|
|
|
Descriptions: This is the implentation for exprflib, a perf library. This
|
|
is the code that runs in the app exporting the counters.
|
|
|
|
\*==========================================================================*/
|
|
#include "stdlib.h"
|
|
#include "snprflib.h"
|
|
#include "dbgtrace.h"
|
|
|
|
DWORD InitializeBasicSecurityDescriptor (PSECURITY_DESCRIPTOR *ppSd);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Forward declaration of shared memory functions.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL FCreateFileMapping (SharedMemorySegment * pSMS,
|
|
LPCWSTR pcwstrInstanceName,
|
|
DWORD dwIndex,
|
|
DWORD cbSize);
|
|
|
|
void CloseFileMapping (SharedMemorySegment * pSMS);
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PerfLibrary class declaration. There is one perf library instance per linkee.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
PerfLibrary::PerfLibrary (LPCWSTR pcwstrPerfName)
|
|
{
|
|
wcsncpy (m_wszPerfName, pcwstrPerfName, MAX_PERF_NAME);
|
|
|
|
m_wszPerfName[MAX_PERF_NAME-1] = L'\0'; // Ensure NULL termination
|
|
|
|
ZeroMemory (m_rgpObjDef, sizeof (m_rgpObjDef));
|
|
m_dwObjDef = 0;
|
|
m_hMap = 0;
|
|
m_pbMap = 0;
|
|
}
|
|
|
|
PerfLibrary::~PerfLibrary (void)
|
|
{
|
|
DeInit ();
|
|
}
|
|
|
|
void
|
|
PerfLibrary::DeInit (void)
|
|
{
|
|
DWORD i;
|
|
|
|
// Destroy the PerfObjectDefinition's we owned.
|
|
for (i = 0; i < m_dwObjDef; i++)
|
|
{
|
|
delete m_rgpObjDef[i];
|
|
m_rgpObjDef[i] = NULL;
|
|
}
|
|
|
|
m_dwObjDef = 0;
|
|
|
|
// Destroy our shared memory mapping.
|
|
if (m_pbMap)
|
|
{
|
|
UnmapViewOfFile ((void*) m_pbMap);
|
|
m_pbMap = 0;
|
|
}
|
|
|
|
if (m_hMap)
|
|
{
|
|
CloseHandle (m_hMap);
|
|
m_hMap = 0;
|
|
}
|
|
}
|
|
|
|
PerfObjectDefinition*
|
|
PerfLibrary::AddPerfObjectDefinition (LPCWSTR pcwstrObjectName,
|
|
DWORD dwObjectNameIndex,
|
|
BOOL fInstances)
|
|
{
|
|
PerfObjectDefinition* ppod = NULL;
|
|
|
|
if (m_dwObjDef < MAX_PERF_OBJECTS)
|
|
{
|
|
ppod = new PerfObjectDefinition (pcwstrObjectName,
|
|
dwObjectNameIndex,
|
|
fInstances);
|
|
if (NULL == ppod)
|
|
goto Exit;
|
|
|
|
m_rgpObjDef[m_dwObjDef++] = ppod;
|
|
}
|
|
|
|
Exit:
|
|
return ppod;
|
|
}
|
|
|
|
BOOL
|
|
PerfLibrary::Init (void)
|
|
{
|
|
DWORD i = 0;
|
|
WCHAR wszPerformanceKey[256] = {L'\0'};
|
|
HKEY hKey = NULL;
|
|
LONG status = 0;
|
|
DWORD size, type = 0;
|
|
BOOL fRet = FALSE;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PSECURITY_DESCRIPTOR pSd = NULL;
|
|
SECURITY_ATTRIBUTES sa;
|
|
|
|
//
|
|
// Get counter and help index base values from registry and
|
|
// update static data structures by adding base to offset values
|
|
// that are statically defined in the structure initialization
|
|
//
|
|
swprintf (wszPerformanceKey,
|
|
L"SYSTEM\\CurrentControlSet\\Services\\%s\\Performance",
|
|
m_wszPerfName );
|
|
|
|
status = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
|
|
wszPerformanceKey,
|
|
0L,
|
|
KEY_READ,
|
|
&hKey);
|
|
if (status != ERROR_SUCCESS)
|
|
goto Exit;
|
|
|
|
//
|
|
// Get FirstCounter RegValue
|
|
//
|
|
size = sizeof(DWORD);
|
|
status = RegQueryValueEx (hKey,
|
|
"First Counter",
|
|
0L,
|
|
&type,
|
|
(LPBYTE)&m_dwFirstCounter,
|
|
&size);
|
|
if (status != ERROR_SUCCESS)
|
|
goto Exit;
|
|
|
|
|
|
//
|
|
// Get FirstHelp RegValue
|
|
//
|
|
size = sizeof(DWORD);
|
|
status = RegQueryValueEx( hKey,
|
|
"First Help",
|
|
0L,
|
|
&type,
|
|
(LPBYTE)&m_dwFirstHelp,
|
|
&size);
|
|
if (status != ERROR_SUCCESS)
|
|
goto Exit;
|
|
|
|
//
|
|
// Initialize the security descriptor with completely open access
|
|
//
|
|
dwErr = InitializeBasicSecurityDescriptor (&pSd);
|
|
if (dwErr) {
|
|
fRet = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = pSd;
|
|
sa.bInheritHandle = TRUE;
|
|
//
|
|
// Create the shared memory object for the list of object names.
|
|
// Return error if it already exists as we cannot operate if this
|
|
// is the second instance of the app.
|
|
//
|
|
m_hMap = CreateFileMappingW (INVALID_HANDLE_VALUE,
|
|
&sa,
|
|
PAGE_READWRITE,
|
|
0,
|
|
(MAX_PERF_OBJECTS * MAX_OBJECT_NAME *
|
|
sizeof (WCHAR) + sizeof (DWORD)),
|
|
m_wszPerfName);
|
|
if (m_hMap == NULL || GetLastError() == ERROR_ALREADY_EXISTS)
|
|
goto Exit;
|
|
|
|
//
|
|
// Map the file into memory
|
|
//
|
|
m_pbMap = (BYTE*) MapViewOfFile (m_hMap, FILE_MAP_WRITE, 0, 0, 0);
|
|
if (!m_pbMap)
|
|
goto Exit;
|
|
|
|
//
|
|
// Assign pointers into the shared memory region
|
|
//
|
|
m_pdwObjectNames = (DWORD*) m_pbMap;
|
|
m_prgObjectNames = (OBJECTNAME*) (m_pbMap+sizeof(DWORD));
|
|
|
|
//
|
|
// Copy the object names into the shared memory
|
|
//
|
|
*m_pdwObjectNames = m_dwObjDef;
|
|
|
|
for (i = 0; i < m_dwObjDef; i++)
|
|
{
|
|
if (m_rgpObjDef[i]->Init( this ))
|
|
wcscpy (m_prgObjectNames[i], m_rgpObjDef[i]->m_wszObjectName);
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
Exit:
|
|
if (hKey)
|
|
RegCloseKey (hKey);
|
|
|
|
if (!fRet)
|
|
{
|
|
if (m_pbMap)
|
|
{
|
|
UnmapViewOfFile ((PVOID)m_pbMap);
|
|
m_pbMap = 0;
|
|
}
|
|
|
|
if (m_hMap)
|
|
{
|
|
CloseHandle (m_hMap);
|
|
m_hMap = 0;
|
|
}
|
|
}
|
|
|
|
if (pSd)
|
|
delete [] (BYTE *) pSd;
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PerfObjectDefinition class implementation. There is one of these for each
|
|
// perfmon object exported. Generally there is just one, but not neccessarily.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
PerfObjectDefinition::PerfObjectDefinition (LPCWSTR pcwstrObjectName,
|
|
DWORD dwObjectNameIndex,
|
|
BOOL fInstances) :
|
|
m_dwObjectNameIndex (dwObjectNameIndex),
|
|
m_fInstances (fInstances),
|
|
m_dwCounters (0)
|
|
{
|
|
wcsncpy (m_wszObjectName, pcwstrObjectName, MAX_OBJECT_NAME);
|
|
m_wszObjectName[MAX_OBJECT_NAME-1] = L'\0'; // Ensure NULL Terminated
|
|
|
|
ZeroMemory (m_rgpCounterDef, sizeof(m_rgpCounterDef));
|
|
m_dwActiveInstances = 0;
|
|
m_pSMS = NULL;
|
|
m_dwShmemMappingSize = SHMEM_MAPPING_SIZE;
|
|
m_fCSInit = FALSE;
|
|
m_pPoiTotal = NULL;
|
|
m_pPerfObjectType = NULL;
|
|
}
|
|
|
|
PerfObjectDefinition::~PerfObjectDefinition (void)
|
|
{
|
|
DeInit();
|
|
}
|
|
|
|
void
|
|
PerfObjectDefinition::DeInit (void)
|
|
{
|
|
SharedMemorySegment *pSMS, *pSMSNext;
|
|
DWORD i;
|
|
|
|
// First destroy the _Total instance.
|
|
if (m_pPoiTotal)
|
|
{
|
|
delete m_pPoiTotal;
|
|
m_pPoiTotal = NULL;
|
|
}
|
|
|
|
//
|
|
// Reset these values in the shared memory so that before we unmap the memory,
|
|
// perfmon won't think that we still have instances & counters running.
|
|
//
|
|
if (m_pPerfObjectType)
|
|
{
|
|
m_pPerfObjectType->NumCounters = 0;
|
|
m_pPerfObjectType->NumInstances = 0;
|
|
}
|
|
|
|
// Destroy the PerfCounterDefinition's we owned.
|
|
for (i = 0; i < m_dwCounters; i++)
|
|
{
|
|
delete m_rgpCounterDef[i];
|
|
m_rgpCounterDef[i] = NULL;
|
|
}
|
|
|
|
pSMS = m_pSMS;
|
|
m_pSMS = NULL;
|
|
|
|
// Enumerate through all the memory mappings we created and destroy them.
|
|
while (pSMS)
|
|
{
|
|
pSMSNext = pSMS->m_pSMSNext;
|
|
CloseFileMapping (pSMS);
|
|
delete (pSMS);
|
|
pSMS = pSMSNext;
|
|
}
|
|
|
|
// Destroy the critical section.
|
|
if (m_fCSInit)
|
|
{
|
|
m_fCSInit = FALSE;
|
|
DeleteCriticalSection (&m_csPerfObjInst);
|
|
}
|
|
}
|
|
|
|
PerfCounterDefinition*
|
|
PerfObjectDefinition::AddPerfCounterDefinition (
|
|
DWORD dwCounterNameIndex,
|
|
DWORD dwCounterType,
|
|
LONG lDefaultScale)
|
|
{
|
|
PerfCounterDefinition* ppcd = NULL;
|
|
|
|
if (m_dwCounters < MAX_OBJECT_COUNTERS)
|
|
{
|
|
ppcd = new PerfCounterDefinition (dwCounterNameIndex,
|
|
dwCounterType,
|
|
lDefaultScale);
|
|
if (NULL == ppcd)
|
|
goto Exit;
|
|
|
|
m_rgpCounterDef[m_dwCounters++] = ppcd;
|
|
}
|
|
|
|
Exit:
|
|
return ppcd;
|
|
}
|
|
|
|
PerfCounterDefinition*
|
|
PerfObjectDefinition::AddPerfCounterDefinition (
|
|
PerfCounterDefinition* pCtrRef,
|
|
DWORD dwCounterNameIndex,
|
|
DWORD dwCounterType,
|
|
LONG lDefaultScale)
|
|
{
|
|
PerfCounterDefinition* ppcd = NULL;
|
|
|
|
if (m_dwCounters < MAX_OBJECT_COUNTERS)
|
|
{
|
|
ppcd = new PerfCounterDefinition (pCtrRef,
|
|
dwCounterNameIndex,
|
|
dwCounterType,
|
|
lDefaultScale);
|
|
if (NULL == ppcd)
|
|
goto Exit;
|
|
|
|
m_rgpCounterDef[m_dwCounters++] = ppcd;
|
|
}
|
|
|
|
Exit:
|
|
return ppcd;
|
|
}
|
|
|
|
BOOL
|
|
PerfObjectDefinition::Init (PerfLibrary* pPerfLib)
|
|
{
|
|
DWORD i = 0;
|
|
DWORD dwOffset = 0;
|
|
DWORD dwDefinitionLength= 0;
|
|
BOOL fRet = FALSE;
|
|
|
|
//
|
|
// Compute the size of the shared memory for this object definition
|
|
//
|
|
|
|
// Start with the basics:
|
|
// we need a PERF_OBJECT_TYPE for the object information and
|
|
// we need a PERF_COUNTER_DEFINITION for each counter in the object
|
|
dwDefinitionLength = (sizeof(PERF_OBJECT_TYPE) +
|
|
m_dwCounters * sizeof(PERF_COUNTER_DEFINITION));
|
|
// We also keep a DWORD in the shared memory to give the DLL
|
|
// our pre-computed value for m_dwCounterData
|
|
m_dwDefinitionLength = dwDefinitionLength + sizeof(DWORD);
|
|
|
|
// Compute the counter data space
|
|
m_dwCounterData = sizeof(PERF_COUNTER_BLOCK);
|
|
for (i = 0; i < m_dwCounters; i++)
|
|
{
|
|
m_dwCounterData += m_rgpCounterDef[i]->m_dwCounterSize;
|
|
}
|
|
|
|
// Compute the per instance space
|
|
m_dwPerInstanceData = (sizeof(INSTANCE_DATA) + m_dwCounterData);
|
|
|
|
// Make sure our memory mapping is large enough
|
|
while (m_dwShmemMappingSize < m_dwDefinitionLength || m_dwShmemMappingSize < m_dwPerInstanceData)
|
|
m_dwShmemMappingSize *= 2;
|
|
|
|
// Compute the number of instances can be stored in one shmem mapping.
|
|
m_dwInstancesPerMapping = (DWORD)(m_dwShmemMappingSize / m_dwPerInstanceData);
|
|
m_dwInstances1stMapping = (DWORD)((m_dwShmemMappingSize - m_dwDefinitionLength) / m_dwPerInstanceData);
|
|
|
|
//
|
|
// Create the shared memory object for the list of object names. If it
|
|
// already exists, abort!
|
|
//
|
|
m_pSMS = new SharedMemorySegment;
|
|
if (!m_pSMS)
|
|
goto Exit;
|
|
|
|
if (!FCreateFileMapping (m_pSMS, m_wszObjectName, 0, m_dwShmemMappingSize))
|
|
goto Exit;
|
|
|
|
//
|
|
// Set the pointers to the PERF API structures
|
|
//
|
|
m_pPerfObjectType = (PERF_OBJECT_TYPE*) m_pSMS->m_pbMap;
|
|
m_rgPerfCounterDefinition =
|
|
(PERF_COUNTER_DEFINITION*) (m_pPerfObjectType+1);
|
|
|
|
//
|
|
// Initialize the PERF API structures
|
|
//
|
|
m_pPerfObjectType->TotalByteLength = dwDefinitionLength;
|
|
m_pPerfObjectType->DefinitionLength = dwDefinitionLength;
|
|
m_pPerfObjectType->HeaderLength = sizeof (PERF_OBJECT_TYPE);
|
|
m_pPerfObjectType->ObjectNameTitleIndex = m_dwObjectNameIndex +
|
|
pPerfLib->m_dwFirstCounter ;
|
|
m_pPerfObjectType->ObjectNameTitle = 0;
|
|
m_pPerfObjectType->ObjectHelpTitleIndex = m_dwObjectNameIndex +
|
|
pPerfLib->m_dwFirstHelp;
|
|
m_pPerfObjectType->ObjectHelpTitle = 0;
|
|
m_pPerfObjectType->DetailLevel = PERF_DETAIL_NOVICE;
|
|
m_pPerfObjectType->NumCounters = m_dwCounters;
|
|
m_pPerfObjectType->CodePage = (DWORD) 0xffffffff;
|
|
m_pPerfObjectType->DefaultCounter = 0;
|
|
if( !m_fInstances )
|
|
m_pPerfObjectType->NumInstances = PERF_NO_INSTANCES;
|
|
else
|
|
m_pPerfObjectType->NumInstances = 0;
|
|
|
|
//
|
|
// Have all of the PerfCounterDefinition's in this object intialize their
|
|
// PERF_COUNTER_DEFINITION structures in the shared memory
|
|
//
|
|
dwOffset = sizeof (PERF_COUNTER_BLOCK);
|
|
for (i = 0; i < m_dwCounters; i++)
|
|
m_rgpCounterDef[i]->Init(pPerfLib, m_rgPerfCounterDefinition + i, &dwOffset);
|
|
|
|
// Save value for dwCounterData in shared memory for DLL
|
|
*((DWORD*) (m_pSMS->m_pbMap + dwDefinitionLength)) = m_dwCounterData;
|
|
|
|
//
|
|
// Initialzie the critical section to protects the creation/deletion of
|
|
// perf object instances. Use AndSpinCount variation to avoid exception
|
|
// handling.
|
|
//
|
|
if (!InitializeCriticalSectionAndSpinCount(&m_csPerfObjInst, 0x80000000))
|
|
goto Exit;
|
|
|
|
m_fCSInit = TRUE;
|
|
|
|
// Create the _Total instance as the 1st instance if there will be multiple instances
|
|
if (m_fInstances)
|
|
{
|
|
m_pPoiTotal = AddPerfObjectInstance (L"_Total");
|
|
if (!m_pPoiTotal)
|
|
goto Exit;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
|
|
Exit:
|
|
if (!fRet)
|
|
{
|
|
if (m_pPoiTotal)
|
|
{
|
|
delete m_pPoiTotal;
|
|
m_pPoiTotal = NULL;
|
|
}
|
|
|
|
if (m_fCSInit)
|
|
{
|
|
DeleteCriticalSection (&m_csPerfObjInst);
|
|
m_fCSInit = FALSE;
|
|
}
|
|
|
|
if (m_pSMS)
|
|
{
|
|
CloseFileMapping (m_pSMS);
|
|
delete (m_pSMS);
|
|
m_pSMS = NULL;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
DWORD
|
|
PerfObjectDefinition::GetCounterOffset (DWORD dwId)
|
|
{
|
|
for (DWORD i = 0; i < m_dwCounters; i++)
|
|
if (m_rgpCounterDef[i]->m_dwCounterNameIndex == dwId)
|
|
return m_rgpCounterDef[i]->m_dwOffset;
|
|
|
|
return 0;
|
|
}
|
|
|
|
PerfObjectInstance*
|
|
PerfObjectDefinition::AddPerfObjectInstance (LPCWSTR pwcstrInstanceName)
|
|
{
|
|
PerfObjectInstance* ppoi = NULL;
|
|
char* pCounterData = NULL;
|
|
INSTANCE_DATA* pInstData = 0;
|
|
LONG lID = 0;
|
|
SharedMemorySegment* pSMS = NULL;
|
|
SharedMemorySegment* pSMSPrev = NULL;
|
|
SharedMemorySegment* pSMSNew = NULL;
|
|
DWORD dwInstances = 0;
|
|
DWORD dwInstIndex = 0;
|
|
DWORD dwSMS = 0;
|
|
BOOL fCSEntered = FALSE;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//
|
|
// Make sure we've been initialized
|
|
//
|
|
if (!m_pSMS || !m_fCSInit)
|
|
goto Exit;
|
|
|
|
//
|
|
// Instances may be created in different threads. Need to protect the following code.
|
|
//
|
|
EnterCriticalSection (&m_csPerfObjInst);
|
|
fCSEntered = TRUE;
|
|
|
|
if (!m_fInstances)
|
|
{
|
|
// See if we have already created the single instance of this object
|
|
if (m_dwActiveInstances != 0)
|
|
goto Exit;
|
|
|
|
pCounterData = (char *)(m_pSMS->m_pbMap) + m_dwDefinitionLength;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Find a free instance in current mapped segments.
|
|
//
|
|
pSMS = m_pSMS;
|
|
lID = 0;
|
|
|
|
while (pSMS)
|
|
{
|
|
if (0 == dwSMS++)
|
|
{
|
|
//
|
|
// If this is the first mapping, offset pCounterData by m_dwDefinitionLength.
|
|
//
|
|
pCounterData = (char *)(pSMS->m_pbMap) + m_dwDefinitionLength;
|
|
dwInstances = m_dwInstances1stMapping;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise, pCounterData starts from the 1st byte of the mapping.
|
|
//
|
|
pCounterData = (char *)(pSMS->m_pbMap);
|
|
dwInstances = m_dwInstancesPerMapping;
|
|
}
|
|
|
|
for (dwInstIndex = 0;
|
|
dwInstIndex < dwInstances;
|
|
pCounterData += sizeof (INSTANCE_DATA) + m_dwCounterData, dwInstIndex++)
|
|
{
|
|
if (!((INSTANCE_DATA*) pCounterData)->fActive)
|
|
{
|
|
pInstData = (INSTANCE_DATA*) pCounterData;
|
|
pCounterData = pCounterData + sizeof (INSTANCE_DATA);
|
|
goto Found;
|
|
}
|
|
|
|
lID++;
|
|
}
|
|
|
|
pSMSPrev = pSMS;
|
|
pSMS = pSMS->m_pSMSNext;
|
|
}
|
|
|
|
//
|
|
// If cannot find a free instance, create a new segment.
|
|
//
|
|
pSMSNew = new SharedMemorySegment;
|
|
if (!pSMSNew)
|
|
goto Exit;
|
|
|
|
if (!FCreateFileMapping (pSMSNew, m_wszObjectName, dwSMS, m_dwShmemMappingSize))
|
|
goto Exit;
|
|
|
|
pInstData = (INSTANCE_DATA*) (pSMSNew->m_pbMap);
|
|
pCounterData = (char*) (pSMSNew->m_pbMap) + sizeof (INSTANCE_DATA);
|
|
|
|
//
|
|
// Add the new segment to our segment linked list.
|
|
//
|
|
pSMSPrev->m_pSMSNext = pSMSNew;
|
|
}
|
|
|
|
Found:
|
|
//
|
|
// We successfully found a free space for new instance.
|
|
//
|
|
ppoi = new PerfObjectInstance (this, pwcstrInstanceName);
|
|
if (!ppoi)
|
|
goto Exit;
|
|
|
|
ppoi->Init(pCounterData, pInstData, lID);
|
|
|
|
m_pPerfObjectType->NumInstances++;
|
|
m_dwActiveInstances++;
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
if (fCSEntered)
|
|
LeaveCriticalSection (&m_csPerfObjInst);
|
|
|
|
if (!fSuccess)
|
|
{
|
|
if (pSMSNew)
|
|
{
|
|
CloseFileMapping (pSMSNew);
|
|
delete (pSMSNew);
|
|
}
|
|
|
|
if (ppoi)
|
|
{
|
|
delete ppoi;
|
|
ppoi = NULL;
|
|
}
|
|
}
|
|
|
|
return ppoi;
|
|
}
|
|
|
|
|
|
void PerfObjectDefinition::DeletePerfObjectInstance ()
|
|
{
|
|
EnterCriticalSection (&m_csPerfObjInst);
|
|
|
|
m_dwActiveInstances--;
|
|
m_pPerfObjectType->NumInstances--;
|
|
|
|
LeaveCriticalSection (&m_csPerfObjInst);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PerfCounterDefinition class declaration. There is one of these per counter.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
PerfCounterDefinition::PerfCounterDefinition (DWORD dwCounterNameIndex,
|
|
DWORD dwCounterType,
|
|
LONG lDefaultScale) :
|
|
m_pCtrRef (NULL),
|
|
m_dwCounterNameIndex (dwCounterNameIndex),
|
|
m_lDefaultScale (lDefaultScale),
|
|
m_dwCounterType (dwCounterType)
|
|
{
|
|
if (m_dwCounterType & PERF_SIZE_LARGE)
|
|
m_dwCounterSize = sizeof (LARGE_INTEGER);
|
|
else
|
|
m_dwCounterSize = sizeof (DWORD);
|
|
}
|
|
|
|
|
|
PerfCounterDefinition::PerfCounterDefinition (PerfCounterDefinition* pCtrRef,
|
|
DWORD dwCounterNameIndex,
|
|
DWORD dwCounterType,
|
|
LONG lDefaultScale) :
|
|
m_pCtrRef (pCtrRef),
|
|
m_dwCounterNameIndex (dwCounterNameIndex),
|
|
m_lDefaultScale (lDefaultScale),
|
|
m_dwCounterType (dwCounterType),
|
|
m_dwCounterSize (0)
|
|
{
|
|
}
|
|
|
|
void
|
|
PerfCounterDefinition::Init (PerfLibrary* pPerfLib,
|
|
PERF_COUNTER_DEFINITION* pdef, PDWORD pdwOffset)
|
|
{
|
|
pdef->ByteLength = sizeof (PERF_COUNTER_DEFINITION);
|
|
pdef->CounterNameTitleIndex = m_dwCounterNameIndex +
|
|
pPerfLib->m_dwFirstCounter ;
|
|
pdef->CounterNameTitle = 0;
|
|
pdef->CounterHelpTitleIndex = m_dwCounterNameIndex +
|
|
pPerfLib->m_dwFirstHelp ;
|
|
pdef->CounterHelpTitle = 0;
|
|
pdef->DefaultScale = m_lDefaultScale;
|
|
pdef->DetailLevel = PERF_DETAIL_NOVICE;
|
|
pdef->CounterType = m_dwCounterType;
|
|
|
|
if (m_pCtrRef)
|
|
{
|
|
//
|
|
// This counter uses the data of another counter.
|
|
//
|
|
pdef->CounterSize = m_pCtrRef->m_dwCounterSize;
|
|
pdef->CounterOffset = m_pCtrRef->m_dwOffset;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This counter has its own data.
|
|
//
|
|
pdef->CounterSize = m_dwCounterSize;
|
|
pdef->CounterOffset = *pdwOffset;
|
|
|
|
// Save offset
|
|
m_dwOffset = *pdwOffset;
|
|
|
|
// Increment offset for next counter definition
|
|
*pdwOffset += m_dwCounterSize;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PerfObjectInstance class implementation. There is one of these per instance
|
|
// of an object. There is one if there are no instances (the global instance.)
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
PerfObjectInstance::PerfObjectInstance (PerfObjectDefinition* pObjDef,
|
|
LPCWSTR pcwstrInstanceName)
|
|
{
|
|
m_pObjDef = pObjDef;
|
|
|
|
if (pcwstrInstanceName)
|
|
{
|
|
wcsncpy (m_wszInstanceName, pcwstrInstanceName, MAX_INSTANCE_NAME);
|
|
m_wszInstanceName[MAX_INSTANCE_NAME-1] = L'\0'; // Ensure NULL termination!
|
|
}
|
|
else
|
|
*m_wszInstanceName = L'\0';
|
|
|
|
m_fInitialized = FALSE;
|
|
}
|
|
|
|
void
|
|
PerfObjectInstance::Init (char* pCounterData, INSTANCE_DATA* pInstData, LONG lID)
|
|
{
|
|
int cchNameLength = 0;
|
|
|
|
m_pCounterData = pCounterData;
|
|
m_pInstanceData = pInstData;
|
|
|
|
// Clear all the counter data
|
|
ZeroMemory( m_pCounterData, m_pObjDef->m_dwCounterData );
|
|
|
|
// Set the counter block length
|
|
((PERF_COUNTER_BLOCK*)m_pCounterData)->ByteLength =
|
|
m_pObjDef->m_dwCounterData;
|
|
|
|
if (m_pInstanceData)
|
|
{
|
|
m_pInstanceData->perfInstDef.ByteLength = sizeof (PERF_INSTANCE_DEFINITION);
|
|
m_pInstanceData->perfInstDef.ParentObjectTitleIndex = 0;
|
|
m_pInstanceData->perfInstDef.ParentObjectInstance = 0;
|
|
m_pInstanceData->perfInstDef.UniqueID = PERF_NO_UNIQUE_ID;
|
|
m_pInstanceData->perfInstDef.NameOffset =
|
|
sizeof (PERF_INSTANCE_DEFINITION);
|
|
|
|
//
|
|
// The instance-name is copied to wszInstanceName. This is a variable
|
|
// length NULL terminated unicode string. wszInstanceName must end on
|
|
// a 32-bit boundary, so that the perf-data that follows this string
|
|
// is 32-bit aligned. Therefore, if wszInstance contains an odd number
|
|
// of WCHARS, we add an extra WCHAR to 32-bit align it. The length of
|
|
// the instance name in bytes, including the terminating NULL and the
|
|
// padding byte (if present) is written to perfInstDef.NameLength.
|
|
//
|
|
|
|
cchNameLength = wcslen(m_wszInstanceName) + 1;
|
|
|
|
if(cchNameLength > MAX_INSTANCE_NAME)
|
|
{
|
|
// MAX_INSTANCE_NAME is already 32 bit aligned
|
|
_ASSERT(0 == (MAX_INSTANCE_NAME & 1));
|
|
cchNameLength = MAX_INSTANCE_NAME;
|
|
}
|
|
else if(cchNameLength & 1)
|
|
{
|
|
cchNameLength++;
|
|
}
|
|
|
|
m_pInstanceData->perfInstDef.NameLength = cchNameLength * sizeof(WCHAR);
|
|
m_pInstanceData->perfInstDef.ByteLength += cchNameLength * sizeof(WCHAR);
|
|
|
|
CopyMemory(m_pInstanceData->wszInstanceName, m_wszInstanceName,
|
|
cchNameLength * sizeof(WCHAR));
|
|
|
|
// If the name got truncated, there may not have been a terminating NULL
|
|
m_pInstanceData->wszInstanceName[MAX_INSTANCE_NAME - 1] = L'\0';
|
|
m_pInstanceData->fActive = TRUE;
|
|
}
|
|
|
|
m_fInitialized = TRUE;
|
|
}
|
|
|
|
VOID
|
|
PerfObjectInstance::DeInit (void)
|
|
{
|
|
if (m_fInitialized)
|
|
{
|
|
m_fInitialized = FALSE;
|
|
if (m_pInstanceData)
|
|
{
|
|
m_pInstanceData->fActive = FALSE;
|
|
m_pInstanceData = NULL;
|
|
}
|
|
}
|
|
|
|
m_pObjDef->DeletePerfObjectInstance();
|
|
}
|
|
|
|
DWORD* PerfObjectInstance::GetDwordCounter (DWORD dwId)
|
|
{
|
|
DWORD dwOffset;
|
|
|
|
if (m_fInitialized)
|
|
{
|
|
if (dwOffset = m_pObjDef->GetCounterOffset(dwId))
|
|
return (DWORD*) (m_pCounterData + dwOffset);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LARGE_INTEGER* PerfObjectInstance::GetLargeIntegerCounter (DWORD dwId)
|
|
{
|
|
DWORD dwOffset;
|
|
|
|
if (m_fInitialized)
|
|
{
|
|
if (dwOffset = m_pObjDef->GetCounterOffset(dwId))
|
|
return (LARGE_INTEGER*) (m_pCounterData + dwOffset);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QWORD* PerfObjectInstance::GetQwordCounter (DWORD dwId)
|
|
{
|
|
DWORD dwOffset;
|
|
|
|
if (m_fInitialized)
|
|
{
|
|
if (dwOffset = m_pObjDef->GetCounterOffset(dwId))
|
|
return (QWORD*) (m_pCounterData + dwOffset);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Description:
|
|
// Allocates and returns a SECURITY_DESCRIPTOR structure initialized to
|
|
// allow all users access. This security descriptor is used to set the
|
|
// security for the shared memory objects created by snprflib.
|
|
// Arguments:
|
|
// OUT pSd Pass in a pointer to SECURITY_DESCRIPTOR, on success this will
|
|
// be set to a suitably initialized SECURITY_DESCRIPTOR. Caller frees
|
|
// memory pointed to by pSd.
|
|
// Returns:
|
|
// ERROR_SUCCESS on success.
|
|
// Win32 error to indicate failure.
|
|
//---------------------------------------------------------------------------
|
|
DWORD InitializeBasicSecurityDescriptor (PSECURITY_DESCRIPTOR *ppSd)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
PSID pSidWorld = NULL;
|
|
PSID pSidCreator = NULL;
|
|
SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
|
SID_IDENTIFIER_AUTHORITY CreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY;
|
|
ACL *pAcl = NULL;
|
|
DWORD dwAclSize = 0;
|
|
|
|
*ppSd = NULL;
|
|
if (!AllocateAndInitializeSid (
|
|
&WorldAuthority,
|
|
1,
|
|
SECURITY_WORLD_RID,
|
|
0,0,0,0,0,0,0,
|
|
&pSidWorld)){
|
|
|
|
dwErr = GetLastError ();
|
|
goto Exit;
|
|
}
|
|
|
|
if (!AllocateAndInitializeSid (
|
|
&CreatorAuthority,
|
|
1,
|
|
SECURITY_CREATOR_OWNER_RID,
|
|
0,0,0,0,0,0,0,
|
|
&pSidCreator)){
|
|
|
|
dwErr = GetLastError ();
|
|
goto Exit;
|
|
}
|
|
|
|
dwAclSize = sizeof (ACL) +
|
|
(sizeof (ACCESS_ALLOWED_ACE) - sizeof (LONG)) +
|
|
GetLengthSid (pSidWorld) +
|
|
(sizeof (ACCESS_ALLOWED_ACE) - sizeof (LONG)) +
|
|
GetLengthSid (pSidCreator);
|
|
|
|
//
|
|
// Allocate SD and ACL with a single alloc
|
|
//
|
|
|
|
*ppSd = (PSECURITY_DESCRIPTOR) new BYTE [SECURITY_DESCRIPTOR_MIN_LENGTH + dwAclSize];
|
|
|
|
if (!*ppSd) {
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!InitializeSecurityDescriptor (*ppSd, SECURITY_DESCRIPTOR_REVISION)) {
|
|
dwErr = GetLastError ();
|
|
goto Exit;
|
|
}
|
|
|
|
pAcl = (ACL *) ((BYTE *) *ppSd + SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
|
|
if (!InitializeAcl (
|
|
pAcl,
|
|
dwAclSize,
|
|
ACL_REVISION)) {
|
|
|
|
dwErr = GetLastError ();
|
|
goto Exit;
|
|
}
|
|
|
|
if (!AddAccessAllowedAce (
|
|
pAcl,
|
|
ACL_REVISION,
|
|
GENERIC_WRITE,
|
|
pSidCreator)
|
|
|
|
||
|
|
|
|
!AddAccessAllowedAce (
|
|
pAcl,
|
|
ACL_REVISION,
|
|
GENERIC_READ,
|
|
pSidWorld)) {
|
|
|
|
dwErr = GetLastError ();
|
|
goto Exit;
|
|
}
|
|
|
|
if (!SetSecurityDescriptorDacl (*ppSd, TRUE, pAcl, FALSE))
|
|
dwErr = GetLastError ();
|
|
|
|
Exit:
|
|
if (pSidWorld)
|
|
FreeSid (pSidWorld);
|
|
|
|
if (pSidCreator)
|
|
FreeSid (pSidCreator);
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Shared memory management functions
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL FCreateFileMapping (SharedMemorySegment * pSMS,
|
|
LPCWSTR pcwstrInstanceName,
|
|
DWORD dwIndex,
|
|
DWORD cbSize)
|
|
{
|
|
WCHAR pwstrShMem[MAX_PATH];
|
|
WCHAR pwstrIndex[MAX_PATH];
|
|
PSECURITY_DESCRIPTOR pSd = NULL;
|
|
SECURITY_ATTRIBUTES sa;
|
|
HANDLE hMap = NULL;
|
|
PVOID pvMap = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Check parameter
|
|
//
|
|
if (!pSMS)
|
|
goto Exit;
|
|
|
|
pSMS->m_hMap = NULL;
|
|
pSMS->m_pbMap = NULL;
|
|
pSMS->m_pSMSNext = NULL;
|
|
|
|
//
|
|
// Append dwIndex to instance name.
|
|
//
|
|
_ultow (dwIndex, pwstrIndex, 16);
|
|
|
|
if (wcslen (pcwstrInstanceName) + wcslen (pwstrIndex) >= MAX_PATH)
|
|
goto Exit;
|
|
|
|
wcscpy (pwstrShMem, pcwstrInstanceName);
|
|
wcscat (pwstrShMem, pwstrIndex);
|
|
|
|
dwErr = InitializeBasicSecurityDescriptor (&pSd);
|
|
if (dwErr)
|
|
goto Exit;
|
|
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = pSd;
|
|
sa.bInheritHandle = TRUE;
|
|
|
|
//
|
|
// Create the shared memory object. If it already exists, abort!
|
|
//
|
|
hMap = CreateFileMappingW (INVALID_HANDLE_VALUE,
|
|
&sa,
|
|
PAGE_READWRITE,
|
|
0,
|
|
cbSize,
|
|
pwstrShMem);
|
|
|
|
if (hMap == NULL || GetLastError() == ERROR_ALREADY_EXISTS)
|
|
goto Exit;
|
|
|
|
//
|
|
// Map the file into memory
|
|
//
|
|
pvMap = MapViewOfFile (hMap, FILE_MAP_WRITE, 0, 0, 0);
|
|
if (!pvMap)
|
|
goto Exit;
|
|
|
|
ZeroMemory (pvMap, cbSize);
|
|
|
|
//
|
|
// Succeeds. Now store the results into pSMS.
|
|
//
|
|
pSMS->m_hMap = hMap;
|
|
pSMS->m_pbMap = (BYTE *)pvMap;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
if (!fSuccess)
|
|
{
|
|
if (pvMap)
|
|
UnmapViewOfFile (pvMap);
|
|
|
|
if (hMap)
|
|
CloseHandle (hMap);
|
|
}
|
|
if (pSd)
|
|
delete [] (BYTE *) pSd;
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
void CloseFileMapping (SharedMemorySegment * pSMS)
|
|
{
|
|
if (pSMS)
|
|
{
|
|
if (pSMS->m_pbMap)
|
|
{
|
|
UnmapViewOfFile ((PVOID)pSMS->m_pbMap);
|
|
pSMS->m_pbMap = NULL;
|
|
}
|
|
|
|
if (pSMS->m_hMap)
|
|
{
|
|
CloseHandle (pSMS->m_hMap);
|
|
pSMS->m_hMap = NULL;
|
|
}
|
|
|
|
pSMS->m_pSMSNext = NULL;
|
|
}
|
|
}
|