|
|
/*==========================================================================*\
Module: exprfdll.cpp
Copyright Microsoft Corporation 1998, All Rights Reserved.
Author: WayneC
Descriptions: This is the implementation for exprfdll, a perf dll. This is for the dll that runs in perfmon. It supports multiple libraries (monitored services.)
\*==========================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
// Includes
//
///////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <winperf.h>
#include "snprflib.h"
#include "exprfdll.h"
#include <stdlib.h>
#include "exchmem.h"
///////////////////////////////////////////////////////////////////////////////
//
// Declare Global variables
//
///////////////////////////////////////////////////////////////////////////////
LPCWSTR g_wszPrefixGlobal = L"Global\\"; WCHAR g_rgszLibraries[MAX_PERF_LIBS][MAX_PERF_NAME]; // Names of the libraries we are monitoring
BOOL g_rgfInitOk[MAX_PERF_LIBS] = {FALSE}; // Flags to indicate if initialization was a success
// index for g_rgszLibraries & g_rgfInitOk
enum LibIndex { LIB_NTFSDRV = 0 };
///////////////////////////////////////////////////////////////////////////////
//
// Forward declaration of shared memory functions.
//
///////////////////////////////////////////////////////////////////////////////
BOOL FOpenFileMapping (SharedMemorySegment * pSMS, LPCWSTR pcwstrInstanceName, DWORD dwIndex);
void CloseFileMapping (SharedMemorySegment * pSMS);
///////////////////////////////////////////////////////////////////////////////
//
// PerfLibraryData class implementation
//
///////////////////////////////////////////////////////////////////////////////
PerfLibraryData::PerfLibraryData() { m_hShMem = 0; m_pbShMem = 0; m_dwObjects = 0; }
PerfLibraryData::~PerfLibraryData() { Close(); }
BOOL PerfLibraryData::GetPerformanceStatistics (LPCWSTR pcwstrLibrary) { BOOL fRet = FALSE; DWORD i = 0;
//
// Open the mapping for the perf library information
//
m_hShMem = OpenFileMappingW (FILE_MAP_READ, FALSE, pcwstrLibrary); if (!m_hShMem) goto Exit;
m_pbShMem = (BYTE*) MapViewOfFile (m_hShMem, FILE_MAP_READ, 0, 0, 0); if (!m_pbShMem) goto Exit;
//
// Get the number of objects in the shared memory
//
m_dwObjects = *(DWORD*) m_pbShMem; m_prgObjectNames = (OBJECTNAME*) (m_pbShMem + sizeof(DWORD));
//
// Loop through objects and get perf data for each
//
for (i = 0; i < m_dwObjects; i++) { if(!m_rgObjectData[i].GetPerformanceStatistics (m_prgObjectNames[i])) goto Exit; }
fRet = TRUE;
Exit: if (!fRet) { if (m_pbShMem) { UnmapViewOfFile ((PVOID)m_pbShMem); m_pbShMem = NULL; }
if (m_hShMem) { CloseHandle (m_hShMem); m_hShMem = NULL; } }
return fRet; }
VOID PerfLibraryData::Close (VOID) { if (m_pbShMem) { UnmapViewOfFile ((PVOID) m_pbShMem); m_pbShMem = 0; }
if (m_hShMem) { CloseHandle (m_hShMem); m_hShMem = 0; }
for (DWORD i = 0; i < m_dwObjects; i++) m_rgObjectData[i].Close(); }
DWORD PerfLibraryData::SpaceNeeded (DWORD dwQueryType, LPCWSTR lpwstrObjects) { DWORD dwSpaceNeeded = 0;
for (DWORD i = 0; i < m_dwObjects; i++) dwSpaceNeeded += m_rgObjectData[i].SpaceNeeded (dwQueryType, lpwstrObjects);
return dwSpaceNeeded; }
VOID PerfLibraryData::SavePerformanceData (PVOID* ppv, DWORD* pdwBytes, DWORD* pdwObjects ) { for (DWORD i = 0; i < m_dwObjects; i++) m_rgObjectData[i].SavePerformanceData (ppv, pdwBytes, pdwObjects); }
///////////////////////////////////////////////////////////////////////////////
//
// PerfObjectData class implementation
//
///////////////////////////////////////////////////////////////////////////////
PerfObjectData::PerfObjectData() { m_fObjectRequested = FALSE; m_dwSpaceNeeded = 0; m_pSMS = NULL; m_wszObjectName[0] = L'\0'; }
PerfObjectData::~PerfObjectData() { Close(); }
BOOL PerfObjectData::GetPerformanceStatistics (LPCWSTR pcwstrObjectName) { DWORD dwPerInstanceData = 0; DWORD dwShmemMappingSize = SHMEM_MAPPING_SIZE; BOOL fSuccess = FALSE;
// Remember the object name
wcsncpy (m_wszObjectName, pcwstrObjectName, MAX_OBJECT_NAME); m_wszObjectName[MAX_OBJECT_NAME-1] = L'\0'; // Ensure NULL Terminated
// Open the 1st shared memory segment
m_pSMS = new SharedMemorySegment; if (!m_pSMS) goto Exit;
if (!FOpenFileMapping (m_pSMS, pcwstrObjectName, 0)) goto Exit;
// First in the shared memory is the PERF_OBJECT_TYPE
m_pObjType = (PERF_OBJECT_TYPE*) m_pSMS->m_pbMap;
// Then an array of PERF_COUNTER_DEFINITION
m_prgCounterDef = (PERF_COUNTER_DEFINITION*) (m_pObjType + 1);
// Then a DWORD that tells the size of each counter block
m_pdwCounterData = (DWORD*) (m_pSMS->m_pbMap + sizeof(PERF_OBJECT_TYPE) + (m_pObjType->NumCounters * sizeof(PERF_COUNTER_DEFINITION)));
if (m_pObjType->NumInstances == PERF_NO_INSTANCES) { m_pCounterBlock = (PERF_COUNTER_BLOCK*) (m_pdwCounterData+1); m_pbCounterBlockTotal = NULL; } else { m_pCounterBlock = NULL; m_pbCounterBlockTotal = (PBYTE)(m_pdwCounterData+1) + sizeof(INSTANCE_DATA); }
// Compute the size of per instance data & object definition.
dwPerInstanceData = sizeof(INSTANCE_DATA) + *m_pdwCounterData; m_dwDefinitionLength = sizeof(PERF_OBJECT_TYPE) + m_pObjType->NumCounters * sizeof(PERF_COUNTER_DEFINITION) + sizeof(DWORD);
// Make sure our memory mapping is large enough.
while (dwShmemMappingSize < dwPerInstanceData || dwShmemMappingSize < m_dwDefinitionLength) dwShmemMappingSize *= 2;
// Compute the number of instances can be stored in one shmem mapping.
m_dwInstancesPerMapping = (DWORD)(dwShmemMappingSize / dwPerInstanceData); m_dwInstances1stMapping = (DWORD)((dwShmemMappingSize - m_dwDefinitionLength) / dwPerInstanceData);
fSuccess = TRUE;
Exit: if (!fSuccess && m_pSMS) { CloseFileMapping (m_pSMS); delete m_pSMS; m_pSMS = NULL; }
return fSuccess; }
VOID PerfObjectData::Close (VOID) { SharedMemorySegment *pSMS, *pSMSNext;
pSMS = m_pSMS; m_pSMS = NULL;
while (pSMS) { pSMSNext = pSMS->m_pSMSNext; CloseFileMapping (pSMS); delete pSMS; pSMS = pSMSNext; } }
DWORD PerfObjectData::SpaceNeeded (DWORD dwQueryType, LPCWSTR lpwstrObjects) { DWORD dwSpaceNeeded = 0;
if (dwQueryType == QUERY_GLOBAL || IsNumberInUnicodeList (m_pObjType->ObjectNameTitleIndex, lpwstrObjects)) { // Remember for later that this object was requested.
m_fObjectRequested = TRUE;
// Compute space needed... always need enough for the object def. and
// all the counter defs
dwSpaceNeeded = sizeof(PERF_OBJECT_TYPE) + (m_pObjType->NumCounters * sizeof(PERF_COUNTER_DEFINITION));
// It is a bit different depending on if there are multiple instances
if( m_pObjType->NumInstances != PERF_NO_INSTANCES ) { // If multi-instance, we have one instance def, one instance name
// plus the counter data for each instance
dwSpaceNeeded += m_pObjType->NumInstances * (sizeof(PERF_INSTANCE_DEFINITION) + sizeof(INSTANCENAME) + *m_pdwCounterData); } else { // Else we just have the counter data
dwSpaceNeeded += *m_pdwCounterData; } }
m_dwSpaceNeeded = dwSpaceNeeded;
return dwSpaceNeeded; }
void PerfObjectData::SavePerformanceData (VOID** ppv, DWORD* pdwBytes, DWORD* pdwObjects) { BYTE* pb; INSTANCE_DATA* pInst; DWORD dwBytes = 0; PERF_OBJECT_TYPE* pobj; PERF_COUNTER_BLOCK* pcb; PERF_COUNTER_BLOCK* pcbTotalCounter = NULL; SharedMemorySegment* pSMS = NULL; SharedMemorySegment* pSMSNext = NULL; DWORD dwMapping = 0; DWORD dwInstances = 0; DWORD dwInstIndex = 0; BYTE* pbTotal = NULL; BYTE* pbCounterData = NULL; INSTANCE_DATA* pInstTotal = NULL; DWORD dwInstancesCopied = 0; DWORD dwInstanceSize = 0;
//
// If this object wasn't requested (as determined by SpaceNeeded()), then
// we don't do anything.
//
if (!m_fObjectRequested) return;
// Get pointer to output buffer
pb = (BYTE*) *ppv ;
//
// Copy the performance data to the output buffer
//
// Copy a PERF_OBJECT_TYPE structure
CopyMemory (pb, m_pObjType, sizeof(PERF_OBJECT_TYPE)); pobj = (PERF_OBJECT_TYPE*) pb;
pb += sizeof(PERF_OBJECT_TYPE); dwBytes += sizeof(PERF_OBJECT_TYPE);
// Copy the counter definitions
CopyMemory (pb, m_prgCounterDef, pobj->NumCounters * sizeof(PERF_COUNTER_DEFINITION));
pb += pobj->NumCounters * sizeof(PERF_COUNTER_DEFINITION) ; dwBytes += pobj->NumCounters * sizeof(PERF_COUNTER_DEFINITION) ;
if (pobj->NumInstances == PERF_NO_INSTANCES) { // Copy the counter block
CopyMemory (pb, m_pCounterBlock, *m_pdwCounterData);
// Fixup the length, because when no instances have been created it
// will not be correct.
pcb = (PERF_COUNTER_BLOCK*) pb; pcb->ByteLength = *m_pdwCounterData;
pb += *m_pdwCounterData; dwBytes += *m_pdwCounterData; } else { // Enumerate through all the instances and copy them out
pSMS = m_pSMS; dwInstancesCopied = 0;
for (dwMapping = 0; ; dwMapping++) { if (0 == dwMapping) { //
// If this is the 1st mapping, we have to offset pInst by m_dwDefinitionLength.
//
pInst = (INSTANCE_DATA*)((char *)(pSMS->m_pbMap) + m_dwDefinitionLength); dwInstances = m_dwInstances1stMapping; } else { //
// Otherwise, open the next memory mapping and point pInst to the begging of that mapping.
//
pSMSNext = new SharedMemorySegment; if (!pSMSNext) goto Exit;
if (!FOpenFileMapping (pSMSNext, m_wszObjectName, dwMapping)) { delete pSMSNext; goto Exit; }
pSMS->m_pSMSNext = pSMSNext; pSMS = pSMSNext;
pInst = (INSTANCE_DATA*)(pSMS->m_pbMap); dwInstances = m_dwInstancesPerMapping; }
for (dwInstIndex = 0; dwInstIndex < dwInstances && dwInstancesCopied < (DWORD) (pobj->NumInstances); dwInstIndex++) { if (pInst->fActive) { //
// pcb is a pointer in shared-memory pointing to the start of the
// PERF_COUNTER_BLOCK and followed by the raw data for the counters.
//
pcb = (PERF_COUNTER_BLOCK *)((PBYTE)pInst + sizeof(INSTANCE_DATA));
//
// dwInstanceSize = Size of output data for this instance that will
// be copied to pb. For _Total, the data is summed (AddTotal) rather
// than copied.
//
dwInstanceSize = sizeof(PERF_INSTANCE_DEFINITION) + pInst->perfInstDef.NameLength + pcb->ByteLength;
if (0 == dwInstancesCopied) { //
// The first instance is the _Total instance. The perf-library
// does not write _Total counters to shared memory. Instead, we
// (ther perf-dll) must calculate these counters by adding the
// counter data from the instance counter-data and returning that
// data to perfmon.
//
//
// The headers for the _Total instance should be written to pbTotal.
// This is done by CopyInstanceData which copies the
// PERF_INSTANCE_DEFINITION, PERF_INSTANCE_NAME and PERF_COUNTER_BLOCK
// for _Total.
//
pbTotal = pb; pInstTotal = pInst; CopyInstanceData(pbTotal, pInstTotal);
//
// pcbTotalCounter points to the area of memory to which the
// PERF_COUNTER_BLOCK followed by counter data for _Total should
// be written. Each counter is calculated by adding up the
// corresponding counters for the other instances.
//
pcbTotalCounter = (PERF_COUNTER_BLOCK *) (pb + sizeof(PERF_INSTANCE_DEFINITION) + pInst->perfInstDef.NameLength);
// Zero out the counter values for _Total (excluding PERF_COUNTER_BLOCK)
ZeroMemory( (PBYTE)pcbTotalCounter + sizeof(PERF_COUNTER_BLOCK), pcb->ByteLength - sizeof(PERF_COUNTER_BLOCK));
} else { //
// Add the values for the counter data for this instance from shared
// memory, to the running total being maintained in the output buffer,
// pcbTotalCounter.
//
if(pbTotal) AddToTotal (pcbTotalCounter, pcb);
//
// Copy the headers: PERF_INSTANCE_DEFINITION, PERF_INSTANCE_NAME
// and PERF_COUNTER_BLOCK for this instance
//
CopyInstanceData(pb, pInst);
//
// Copy the counter data from shared memory to the output buffer
// PERF_COUNTER_BLOCK has already been copied by CopyInstanceData
// so we exclude that.
//
pbCounterData = pb + sizeof(PERF_INSTANCE_DEFINITION) + pInst->perfInstDef.NameLength + sizeof(PERF_COUNTER_BLOCK);
CopyMemory( pbCounterData, (PBYTE)pcb + sizeof(PERF_COUNTER_BLOCK), pcb->ByteLength - sizeof(PERF_COUNTER_BLOCK));
}
pb += dwInstanceSize; dwBytes += dwInstanceSize;
dwInstancesCopied++; }
pInst = (INSTANCE_DATA*)(((char*)pInst) + sizeof(INSTANCE_DATA) + *m_pdwCounterData); } } }
Exit: // dwBytes must be aligned on an 8-byte boundary
dwBytes = QWORD_MULTIPLE(dwBytes);
// Update parameters in the output buffer
pobj->TotalByteLength = dwBytes;
// Update buffer pointer, count of bytes and count of objects.
*ppv = ((PBYTE) *ppv) + dwBytes; *pdwBytes += dwBytes;
(*pdwObjects)++; }
//------------------------------------------------------------------------------
// Description:
// Extracts and copies the PERF_INSTANCE_DEFINITION, perf-instance-name
// and PERF_COUNTER_BLOCK structures given the INSTANCE_DATA pointer within
// shared memory to the output buffer to perfmon.
// Arguments:
// OUT PBYTE pb - Output buffer to perfmon
// IN INSTANCE_DATA *pInst - Pointer within shared-memory segment to the
// INSTANCE_DATA structure. This structure is immediately followed by
// a PERF_COUNTER_BLOCK structure.
// Returns:
// Nothing.
//------------------------------------------------------------------------------
void PerfObjectData::CopyInstanceData(PBYTE pb, INSTANCE_DATA *pInst) { PERF_COUNTER_BLOCK *pcb = NULL; DWORD cbInstanceName = 0;
//
// The first bytes in shared memory are the INSTANCE_DEFINITION
// structure. Copy the PERF_INSTANCE_DEFINITION member of this
// structure into the output buffer.
//
CopyMemory(pb, &(pInst->perfInstDef), sizeof(PERF_INSTANCE_DEFINITION)); pb += sizeof(PERF_INSTANCE_DEFINITION);
//
// Next, within INSTANCE_DEFINITION, there is a buffer sized
// MAX_INSTANCE_NAME. Copy the instance name, which is a NULL
// terminated unicode string in this buffer. The length in bytes
// to be copied is given by PERF_INSTANCE_DEFINITION.NameLength.
// This includes length includes the terminating NULL and possibly
// an extra padding-byte to 32-bit align the end of the buffer.
//
cbInstanceName = pInst->perfInstDef.NameLength; CopyMemory(pb, (char *)(pInst->wszInstanceName), cbInstanceName); pb += cbInstanceName;
// Finally there is a PERF_COUNTER_BLOCK structure after the INSTANCE_DATA
pcb = (PERF_COUNTER_BLOCK *)((PBYTE)pInst + sizeof(INSTANCE_DATA)); CopyMemory(pb, pcb, sizeof(PERF_COUNTER_BLOCK)); }
void PerfObjectData::AddToTotal( PERF_COUNTER_BLOCK *pcbTotalCounters, PERF_COUNTER_BLOCK *pcbInstCounters) { DWORD i; PBYTE pbTotalCounter = NULL; PBYTE pbInstCounter = NULL;
for (i = 0; i < m_pObjType->NumCounters; i++) { // Offset pointers to the first byte of the actual counter
pbTotalCounter = (PBYTE)(pcbTotalCounters) + m_prgCounterDef[i].CounterOffset; pbInstCounter = (PBYTE)(pcbInstCounters) + m_prgCounterDef[i].CounterOffset;
// If this is a 'rate' counter, it is referencing some other 'raw' counter.
// In this case, we should not add that raw counter again.
if ((m_prgCounterDef[i].CounterType & PERF_TYPE_COUNTER) && (m_prgCounterDef[i].CounterType & PERF_COUNTER_RATE)) continue;
/* we only have LARGE_INTEGER and DWORD counters as of PT 3728 */ if ((m_prgCounterDef[i].CounterType & PERF_TYPE_NUMBER) && (m_prgCounterDef[i].CounterType & PERF_SIZE_LARGE)) { ((LARGE_INTEGER*)pbTotalCounter)->LowPart += ((LARGE_INTEGER*)pbInstCounter)->LowPart; ((LARGE_INTEGER*)pbTotalCounter)->HighPart += ((LARGE_INTEGER*)pbInstCounter)->LowPart; } else { *(DWORD*)pbTotalCounter += *(DWORD*)pbInstCounter; } } }
///////////////////////////////////////////////////////////////////////////////
//
// Shared Memory Functions
//
///////////////////////////////////////////////////////////////////////////////
BOOL FOpenFileMapping (SharedMemorySegment * pSMS, LPCWSTR pcwstrInstanceName, DWORD dwIndex) { WCHAR pwstrShMem[MAX_PATH]; WCHAR pwstrIndex[MAX_PATH]; HANDLE hMap = NULL; PVOID pvMap = NULL; BOOL fSuccess = FALSE;
if (!pSMS) goto Exit;
pSMS->m_hMap = NULL; pSMS->m_pbMap = NULL; pSMS->m_pSMSNext = NULL;
_ultow (dwIndex, pwstrIndex, 16);
if (wcslen (g_wszPrefixGlobal) + wcslen (pcwstrInstanceName) + wcslen (pwstrIndex) >= MAX_PATH) goto Exit;
wcscpy (pwstrShMem, g_wszPrefixGlobal); wcscat (pwstrShMem, pcwstrInstanceName); wcscat (pwstrShMem, pwstrIndex);
hMap = OpenFileMappingW (FILE_MAP_READ, FALSE, pwstrShMem); if (!hMap) goto Exit;
pvMap = MapViewOfFile (hMap, FILE_MAP_READ, 0, 0, 0); if (!pvMap) goto Exit;
pSMS->m_hMap = hMap; pSMS->m_pbMap = (BYTE *)pvMap;
fSuccess = TRUE;
Exit: if (!fSuccess) { if (pvMap) UnmapViewOfFile (pvMap);
if (hMap) CloseHandle (hMap); }
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; } }
///////////////////////////////////////////////////////////////////////////////
//
// Utility Functions
//
///////////////////////////////////////////////////////////////////////////////
//
// IsPrefix()
// returns TRUE if s1 is a prefix of s2
//
BOOL IsPrefix (WCHAR* s1, WCHAR* s2) { while (*s1 && *s2) { if (*s1++ != *s2++) { return FALSE; } }
return (*s1 == 0); }
//
// GetQueryType()
//
// returns the type of query described in the lpValue string so that
// the appropriate processing method may be used
//
// Return Value
//
// QUERY_GLOBAL
// if lpValue == 0 (null pointer)
// lpValue == pointer to Null string
// lpValue == pointer to "Global" string
//
// QUERY_FOREIGN
// if lpValue == pointer to "Foreign" string
//
// QUERY_COSTLY
// if lpValue == pointer to "Costly" string
//
// otherwise:
//
// QUERY_ITEMS
//
DWORD GetQueryType (LPWSTR lpValue) { if (lpValue == 0 || *lpValue == 0 || IsPrefix( L"Global", lpValue)) return QUERY_GLOBAL; else if (IsPrefix (L"Foreign", lpValue)) return QUERY_FOREIGN; else if (IsPrefix (L"Costly" , lpValue)) return QUERY_COSTLY; else return QUERY_ITEMS; }
int inline EvalThisChar (WCHAR c, WCHAR d) { if (c == d || c == L'\0') return DELIMITER; else if (L'0' <= c && c <= L'9') return DIGIT; else return INVALID; }
BOOL IsNumberInUnicodeList (DWORD dwNumber, LPCWSTR lpwszUnicodeList) { DWORD dwThisNumber = 0; const WCHAR* pwcThisChar = lpwszUnicodeList; BOOL bValidNumber = FALSE; BOOL bNewItem = TRUE; WCHAR wcDelimiter = L' ';
// If null pointer, number not found
if (lpwszUnicodeList == 0) return FALSE;
//
// Loop until done...
//
for(;;) { switch (EvalThisChar(*pwcThisChar, wcDelimiter)) { case DIGIT: //
// If this is the first digit after a delimiter, then
// set flags to start computing the new number
//
if (bNewItem) { bNewItem = FALSE; bValidNumber = TRUE; } if (bValidNumber) { dwThisNumber *= 10; dwThisNumber += (*pwcThisChar - L'0'); } break;
case DELIMITER: //
// A delimiter is either the delimiter character or the
// end of the string ('\0') if when the delimiter has been
// reached a valid number was found, then compare it to the
// number from the argument list. if this is the end of the
// string and no match was found, then return.
//
if (bValidNumber) { if (dwThisNumber == dwNumber) return TRUE; bValidNumber = FALSE; }
if (*pwcThisChar == 0) { return FALSE; } else { bNewItem = TRUE; dwThisNumber = 0; }
break;
case INVALID: //
// If an invalid character was encountered, ignore all
// characters up to the next delimiter and then start fresh.
// the invalid number is not compared.
//
bValidNumber = FALSE; break;
default: break; }
pwcThisChar++; } }
///////////////////////////////////////////////////////////////////////////////
//
// Utility functions called by the exported perfmon APIs
//
///////////////////////////////////////////////////////////////////////////////
DWORD Open (LibIndex iLib, LPCWSTR pcwstrLib) { HANDLE hMHeap = NULL;
hMHeap = ExchMHeapCreate (0, 0, 100 * 1024, 0); if (NULL == hMHeap) goto Exit;
lstrcpyW (g_rgszLibraries[iLib], g_wszPrefixGlobal); lstrcatW (g_rgszLibraries[iLib], pcwstrLib); g_rgfInitOk[iLib] = TRUE;
Exit: return ERROR_SUCCESS; }
DWORD Collect (LibIndex iLib, LPWSTR lpwszValue, void** ppdata, DWORD* pdwBytes, DWORD* pdwObjectTypes) { DWORD dwQueryType; DWORD dwBytesIn; DWORD dwSpaceNeeded = 0; // Space needed for counters
DWORD dwRet = ERROR_SUCCESS; // Our return value
PerfLibraryData rgld;
//
// Save the number of bytes in before overwriting it
//
dwBytesIn = *pdwBytes;
//
// Set up the out parameters to indicate an error. We will change them
// later upon success
//
*pdwBytes = 0; *pdwObjectTypes = 0;
if (!g_rgfInitOk[iLib]) { //
// Only acceptable error return is ERROR_MORE_DATA. anything else
// should return ERROR_SUCCESS, but set the out parameters to indicate
// that no data is being returned
//
goto Exit; }
dwQueryType = GetQueryType (lpwszValue); if (dwQueryType == QUERY_FOREIGN) { //
// This routine does not service requests for data from
// Non-NT computers.
//
goto Exit; }
//
// Enumerate through all the libraries we know of and get their
// performance statistices
//
if (!rgld.GetPerformanceStatistics (g_rgszLibraries[iLib])) goto Exit;
//
// Compute the space needed
//
dwSpaceNeeded = rgld.SpaceNeeded (dwQueryType, lpwszValue);
// Round up to a multiple of 4.
dwSpaceNeeded = QWORD_MULTIPLE (dwSpaceNeeded);
//
// See if the caller-provided buffer is large enough
//
if (dwBytesIn < dwSpaceNeeded) { //
// Not enough space was provided by the caller
//
dwRet = ERROR_MORE_DATA; goto Exit; }
//
// Copy the performance data into the buffer
//
rgld.SavePerformanceData (ppdata, pdwBytes, pdwObjectTypes);
Exit: return dwRet; }
DWORD Close (LibIndex iLib) { if (g_rgfInitOk[iLib]) { //
// Release the reference to the global ExchMHeap.
//
ExchMHeapDestroy (); }
return ERROR_SUCCESS; }
///////////////////////////////////////////////////////////////////////////////
// PerfMon API functions
// the following functions are exported from this DLL as the entry points
// for a performance monitoring application
///////////////////////////////////////////////////////////////////////////////
//
// XXXXOpen
// Called by performance monitor to initialize performance gathering.
// The LPWSTR parameter contains the names of monitored devices. This
// is for device driver performance DLL's and is not used by our DLL.
//
// XXXXXCollect
// Called by the performance monitor to retrieve a block of performance
// statistics.
//
// XXXXClose
// Called by the performance monitor to terminate performance gathering
//
/* NTFSDrv */ EXTERN_C DWORD APIENTRY NTFSDrvOpen (LPWSTR) { return Open (LIB_NTFSDRV, L"NTFSDrv"); }
EXTERN_C DWORD APIENTRY NTFSDrvCollect (LPWSTR lpwszValue, void** ppdata, DWORD* pdwBytes, DWORD* pdwObjectTypes) { return Collect (LIB_NTFSDRV, lpwszValue, ppdata, pdwBytes, pdwObjectTypes); }
EXTERN_C DWORD APIENTRY NTFSDrvClose (void) { return Close (LIB_NTFSDRV); }
|