1873 lines
84 KiB
C
1873 lines
84 KiB
C
/*++
|
|
Copyright (C) 1995-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
cutils.c
|
|
|
|
Abstract:
|
|
Counter management utility functions
|
|
--*/
|
|
|
|
#include <windows.h>
|
|
#include <math.h>
|
|
#include "strsafe.h"
|
|
#include <pdh.h>
|
|
#include "pdhitype.h"
|
|
#include "pdhidef.h"
|
|
#include "perftype.h"
|
|
#include "perfdata.h"
|
|
#include "pdhmsg.h"
|
|
#include "strings.h"
|
|
|
|
BOOL
|
|
IsValidCounter(
|
|
HCOUNTER hCounter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
examines the counter handle to verify it is a valid counter. For now
|
|
the test amounts to:
|
|
the Handle is NOT NULL
|
|
the memory is accessible (i.e. it doesn't AV)
|
|
the signature array is valid
|
|
the size field is correct
|
|
|
|
if any tests fail, the handle is presumed to be invalid
|
|
|
|
Arguments:
|
|
IN HCOUNTER hCounter
|
|
the handle of the counter to test
|
|
|
|
Return Value:
|
|
TRUE the handle passes all the tests
|
|
FALSE one of the test's failed and the handle is not a valid counter
|
|
--*/
|
|
{
|
|
BOOL bReturn = FALSE; // assume it's not a valid query
|
|
PPDHI_COUNTER pCounter;
|
|
LONG lStatus = ERROR_SUCCESS;
|
|
|
|
__try {
|
|
if (hCounter != NULL) {
|
|
// see if a valid signature
|
|
pCounter = (PPDHI_COUNTER) hCounter;
|
|
if ((* (DWORD *) & pCounter->signature[0] == SigCounter) &&
|
|
(pCounter->dwLength == sizeof (PDHI_COUNTER))) {
|
|
bReturn = TRUE;
|
|
}
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
// something failed miserably so we can assume this is invalid
|
|
lStatus = GetExceptionCode();
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL
|
|
InitCounter(
|
|
PPDHI_COUNTER pCounter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Initialized the counter data structure by:
|
|
Allocating the memory block to contain the counter structure
|
|
and all the associated data fields. If this allocation
|
|
is successful, then the fields are initialized by
|
|
verifying the counter is valid.
|
|
|
|
Arguments:
|
|
IN PPDHI_COUNTER pCounter
|
|
pointer of the counter to initialize using the system data
|
|
|
|
Return Value:
|
|
TRUE if the counter was successfully initialized
|
|
FALSE if a problem was encountered
|
|
|
|
In either case, the CStatus field of the structure is updated to
|
|
indicate the status of the operation.
|
|
--*/
|
|
{
|
|
PPERF_MACHINE pMachine = NULL;
|
|
DWORD dwBufferSize = MEDIUM_BUFFER_SIZE;
|
|
DWORD dwOldSize;
|
|
BOOL bInstances = FALSE;
|
|
LPVOID pLocalCounterPath = NULL;
|
|
BOOL bReturn = TRUE;
|
|
LONG lOffset;
|
|
|
|
// reset the last error value
|
|
pCounter->ThisValue.CStatus = ERROR_SUCCESS;
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
if (pCounter->szFullName != NULL) {
|
|
// allocate counter path buffer
|
|
if (pCounter->pCounterPath != NULL) {
|
|
__try {
|
|
G_FREE(pCounter->pCounterPath);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
// no need to do anything
|
|
}
|
|
pCounter->pCounterPath = NULL;
|
|
}
|
|
pLocalCounterPath = G_ALLOC(dwBufferSize);
|
|
if (pLocalCounterPath == NULL) {
|
|
// could not allocate string buffer
|
|
pCounter->ThisValue.CStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
bReturn = FALSE;
|
|
}
|
|
else {
|
|
dwOldSize = dwBufferSize;
|
|
if (ParseFullPathNameW(pCounter->szFullName, & dwBufferSize, pLocalCounterPath, FALSE)) {
|
|
// resize to only the space required
|
|
if (dwOldSize < dwBufferSize) {
|
|
pCounter->pCounterPath = G_REALLOC(pLocalCounterPath, dwBufferSize);
|
|
}
|
|
else {
|
|
pCounter->pCounterPath = pLocalCounterPath;
|
|
}
|
|
|
|
if (pCounter->pCounterPath != NULL) {
|
|
if (pLocalCounterPath != pCounter->pCounterPath) { // ???
|
|
// the memory block moved so
|
|
// correct addresses inside structure
|
|
lOffset = (LONG) ((ULONG_PTR) pCounter->pCounterPath - (ULONG_PTR) pLocalCounterPath);
|
|
if (lOffset != 0 && pCounter->pCounterPath->szMachineName != NULL) {
|
|
pCounter->pCounterPath->szMachineName = (LPWSTR) (
|
|
(LPBYTE)pCounter->pCounterPath->szMachineName + lOffset);
|
|
}
|
|
if (lOffset != 0 && pCounter->pCounterPath->szObjectName != NULL) {
|
|
pCounter->pCounterPath->szObjectName = (LPWSTR) (
|
|
(LPBYTE)pCounter->pCounterPath->szObjectName + lOffset);
|
|
}
|
|
if (lOffset != 0 && pCounter->pCounterPath->szInstanceName != NULL) {
|
|
pCounter->pCounterPath->szInstanceName = (LPWSTR) (
|
|
(LPBYTE)pCounter->pCounterPath->szInstanceName + lOffset);
|
|
}
|
|
if (lOffset != 0 && pCounter->pCounterPath->szParentName != NULL) {
|
|
pCounter->pCounterPath->szParentName = (LPWSTR) (
|
|
(LPBYTE)pCounter->pCounterPath->szParentName + lOffset);
|
|
}
|
|
if (lOffset != 0 && pCounter->pCounterPath->szCounterName != NULL) {
|
|
pCounter->pCounterPath->szCounterName = (LPWSTR) (
|
|
(LPBYTE)pCounter->pCounterPath->szCounterName + lOffset);
|
|
}
|
|
}
|
|
|
|
if (pCounter->pOwner->hLog == NULL) {
|
|
// validate realtime counter
|
|
// try to connect to machine and get machine pointer
|
|
pMachine = GetMachine(pCounter->pCounterPath->szMachineName, 0, PDH_GM_UPDATE_PERFNAME_ONLY);
|
|
if (pMachine == NULL) {
|
|
// unable to find machine
|
|
pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_MACHINE;
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
else if (pMachine->szPerfStrings == NULL || pMachine->typePerfStrings == NULL) {
|
|
// a machine entry was found, but the machine is not available
|
|
pMachine->dwRefCount --;
|
|
RELEASE_MUTEX(pMachine->hMutex);
|
|
pCounter->ThisValue.CStatus = pMachine->dwStatus;
|
|
if (pMachine->dwStatus == PDH_ACCESS_DENIED) {
|
|
// then don't add this counter since the machine
|
|
// won't let us in
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
// init raw counter value
|
|
ZeroMemory(& pCounter->ThisValue, sizeof(PDH_RAW_COUNTER));
|
|
ZeroMemory(& pCounter->LastValue, sizeof(PDH_RAW_COUNTER));
|
|
|
|
// look up object name
|
|
pCounter->plCounterInfo.dwObjectId = GetObjectId(pMachine,
|
|
pCounter->pCounterPath->szObjectName,
|
|
& bInstances);
|
|
if (pCounter->plCounterInfo.dwObjectId == (DWORD) -1) {
|
|
// unable to lookup object on this machine
|
|
pCounter->plCounterInfo.dwObjectId = (DWORD) -1;
|
|
pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_OBJECT;
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
else {
|
|
// update instanceName look up instances if necessary
|
|
if (bInstances) {
|
|
if (pCounter->pCounterPath->szInstanceName != NULL) {
|
|
if (* pCounter->pCounterPath->szInstanceName != SPLAT_L) {
|
|
if (! GetInstanceByNameMatch(pMachine, pCounter)) {
|
|
// unable to lookup instance
|
|
pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_INSTANCE;
|
|
// keep the counter since the instance may return
|
|
}
|
|
}
|
|
else {
|
|
// this is a wild card query so don't look
|
|
// for any instances yet
|
|
pCounter->dwFlags |= PDHIC_MULTI_INSTANCE;
|
|
}
|
|
}
|
|
else {
|
|
// the path for this object should include an instance name
|
|
// and doesn't so return an error
|
|
// this is an unrecoverable error so indicate that it's finished
|
|
//
|
|
pCounter->ThisValue.CStatus = PDH_CSTATUS_BAD_COUNTERNAME;
|
|
pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
|
|
}
|
|
pMachine->dwRefCount --;
|
|
RELEASE_MUTEX(pMachine->hMutex);
|
|
|
|
if (bReturn) {
|
|
// look up counter
|
|
if (*pCounter->pCounterPath->szCounterName != SPLAT_L) {
|
|
pCounter->plCounterInfo.dwCounterId = GetCounterId(
|
|
pMachine,
|
|
pCounter->plCounterInfo.dwObjectId,
|
|
pCounter->pCounterPath->szCounterName);
|
|
if (pCounter->plCounterInfo.dwCounterId != (DWORD) -1) {
|
|
// load and initialize remaining counter values
|
|
if (AddMachineToQueryLists(pMachine, pCounter)) {
|
|
if (InitPerflibCounterInfo(pCounter)) {
|
|
// assign the appropriate calculation function
|
|
bReturn = AssignCalcFunction(
|
|
pCounter->plCounterInfo.dwCounterType,
|
|
& pCounter->CalcFunc,
|
|
& pCounter->StatFunc);
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_CUTILS,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
ERROR_SUCCESS,
|
|
TRACE_WSTR(pCounter->szFullName),
|
|
TRACE_DWORD(pCounter->plCounterInfo.dwCounterType),
|
|
NULL));
|
|
if (! bReturn) {
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
}
|
|
}
|
|
else {
|
|
// unable to initialize this counter
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
// machine could not be added, error is already
|
|
// in "LastError" so free string buffer and leave
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
// unable to lookup counter
|
|
pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_COUNTER;
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
if (AddMachineToQueryLists(pMachine, pCounter)) {
|
|
pCounter->dwFlags |= PDHIC_COUNTER_OBJECT;
|
|
pCounter->pThisObject = NULL;
|
|
pCounter->pLastObject = NULL;
|
|
}
|
|
else {
|
|
// machine could not be added, error is already
|
|
// in "LastError" so free string buffer and leave
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
PDH_STATUS pdhStatus;
|
|
// validate counter from log file
|
|
pdhStatus = PdhiGetLogCounterInfo(pCounter->pOwner->hLog, pCounter);
|
|
if (pdhStatus == ERROR_SUCCESS) {
|
|
// finish initializing the counter
|
|
//
|
|
pCounter->ThisValue.TimeStamp.dwLowDateTime = 0;
|
|
pCounter->ThisValue.TimeStamp.dwHighDateTime = 0;
|
|
pCounter->ThisValue.MultiCount = 1;
|
|
pCounter->ThisValue.FirstValue = 0;
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
//
|
|
pCounter->LastValue.TimeStamp.dwLowDateTime = 0;
|
|
pCounter->LastValue.TimeStamp.dwHighDateTime = 0;
|
|
pCounter->LastValue.MultiCount = 1;
|
|
pCounter->LastValue.FirstValue = 0;
|
|
pCounter->LastValue.SecondValue = 0;
|
|
//
|
|
// lastly update status
|
|
//
|
|
pCounter->ThisValue.CStatus = PDH_CSTATUS_VALID_DATA;
|
|
pCounter->LastValue.CStatus = PDH_CSTATUS_VALID_DATA;
|
|
// assign the appropriate calculation function
|
|
bReturn = AssignCalcFunction(pCounter->plCounterInfo.dwCounterType,
|
|
& pCounter->CalcFunc,
|
|
& pCounter->StatFunc);
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_CUTILS,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1),
|
|
ERROR_SUCCESS,
|
|
TRACE_WSTR(pCounter->szFullName),
|
|
TRACE_DWORD(pCounter->plCounterInfo.dwCounterType),
|
|
NULL));
|
|
}
|
|
else {
|
|
// set the counter status to the error returned
|
|
pCounter->ThisValue.CStatus = pdhStatus;
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
|
|
}
|
|
if (! bReturn) {
|
|
//free string buffer
|
|
G_FREE(pCounter->pCounterPath);
|
|
pCounter->pCounterPath = NULL;
|
|
}
|
|
}
|
|
else {
|
|
G_FREE(pLocalCounterPath);
|
|
// unable to realloc
|
|
pCounter->ThisValue.CStatus = PDH_MEMORY_ALLOCATION_FAILURE;
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
// unable to parse counter name
|
|
pCounter->ThisValue.CStatus = PDH_CSTATUS_BAD_COUNTERNAME;
|
|
pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
G_FREE(pLocalCounterPath);
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// no counter name
|
|
pCounter->ThisValue.CStatus = PDH_CSTATUS_NO_COUNTERNAME;
|
|
pCounter->dwFlags &= ~PDHIC_COUNTER_NOT_INIT;
|
|
pCounter->dwFlags |= PDHIC_COUNTER_INVALID;
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
if (! bReturn && pCounter->ThisValue.CStatus != ERROR_SUCCESS) {
|
|
SetLastError(pCounter->ThisValue.CStatus);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL
|
|
ParseInstanceName(
|
|
LPCWSTR szInstanceString,
|
|
LPWSTR szInstanceName,
|
|
LPWSTR szParentName,
|
|
DWORD dwName,
|
|
LPDWORD lpIndex
|
|
)
|
|
/*
|
|
parses the instance name formatted as follows
|
|
|
|
[parent/]instance[#index]
|
|
|
|
parent is optional and if present, is delimited by a forward slash
|
|
index is optional and if present, is delimited by a colon
|
|
|
|
parent and instance may be any legal file name character except a
|
|
delimeter character "/#\()" Index must be a string composed of
|
|
decimal digit characters (0-9), less than 10 characters in length, and
|
|
equate to a value between 0 and 2**32-1 (inclusive).
|
|
|
|
This function assumes that the instance name and parent name buffers
|
|
are of sufficient size.
|
|
|
|
NOTE: szInstanceName and szInstanceString can be the same buffer
|
|
*/
|
|
{
|
|
LPWSTR szSrcChar = (LPWSTR) szInstanceString;
|
|
LPWSTR szDestChar = (LPWSTR) szInstanceName;
|
|
LPWSTR szLastPound = NULL;
|
|
BOOL bReturn = FALSE;
|
|
DWORD dwIndex = 0;
|
|
DWORD dwInstCount = 0;
|
|
|
|
szDestChar = (LPWSTR) szInstanceName;
|
|
szSrcChar = (LPWSTR) szInstanceString;
|
|
|
|
__try {
|
|
do {
|
|
* szDestChar = * szSrcChar;
|
|
if (* szDestChar == POUNDSIGN_L) szLastPound = szDestChar;
|
|
szDestChar ++;
|
|
szSrcChar ++;
|
|
dwInstCount ++;
|
|
}
|
|
while (dwInstCount <= dwName && (* szSrcChar != L'\0') && (* szSrcChar != SLASH_L));
|
|
|
|
if (dwInstCount <= dwName) {
|
|
// see if that was really the parent or not
|
|
if (* szSrcChar == SLASH_L) {
|
|
// terminate destination after test in case they are the same buffer
|
|
* szDestChar = L'\0';
|
|
szSrcChar ++; // and move source pointer past delimter
|
|
// it was the parent name so copy it to the parent
|
|
StringCchCopyW(szParentName, dwName, szInstanceName);
|
|
// and copy the rest of the string after the "/" to the
|
|
// instance name field
|
|
szDestChar = szInstanceName;
|
|
dwInstCount = 0;
|
|
do {
|
|
* szDestChar = * szSrcChar;
|
|
if (* szDestChar == POUNDSIGN_L) szLastPound = szDestChar;
|
|
szDestChar ++;
|
|
szSrcChar ++;
|
|
dwInstCount ++;
|
|
}
|
|
while (dwInstCount <= dwName && (* szSrcChar != L'\0'));
|
|
}
|
|
else {
|
|
// that was the only element so load an empty string for the parent
|
|
* szParentName = L'\0';
|
|
}
|
|
if (dwInstCount <= dwName) {
|
|
// if szLastPound is NOT null and is inside the instance string, then
|
|
// see if it points to a decimal number. If it does, then it's an index
|
|
// otherwise it's part of the instance name
|
|
* szDestChar = L'\0'; // terminate the destination string
|
|
dwIndex = 0;
|
|
if (szLastPound != NULL) {
|
|
if (szLastPound > szInstanceName) {
|
|
// there's a pound sign in the instance name
|
|
// see if it's preceded by a non-space char
|
|
szLastPound --;
|
|
if (* szLastPound > SPACE_L) {
|
|
szLastPound ++;
|
|
// see if it's followed by a digit
|
|
szLastPound ++;
|
|
if ((* szLastPound >= L'0') && (*szLastPound <= L'9')) {
|
|
dwIndex = wcstoul(szLastPound, NULL, 10);
|
|
szLastPound --;
|
|
* szLastPound = L'\0'; // terminate the name at the pound sign
|
|
}
|
|
}
|
|
}
|
|
}
|
|
* lpIndex = dwIndex;
|
|
bReturn = TRUE;
|
|
}
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
// unable to move strings
|
|
bReturn = FALSE;
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL
|
|
ParseFullPathNameW(
|
|
LPCWSTR szFullCounterPath,
|
|
PDWORD pdwBufferSize,
|
|
PPDHI_COUNTER_PATH pCounter,
|
|
BOOL bWbemSyntax
|
|
)
|
|
/*
|
|
interprets counter path string as either a
|
|
|
|
\\machine\object(instance)\counter
|
|
|
|
or if bWbemSyntax == TRUE
|
|
|
|
\\machine\namespace:ClassName(InstanceName)\CounterName
|
|
|
|
and returns the component in the counter path structure
|
|
|
|
\\machine or \\machine\namespace may be omitted on the local machine
|
|
(instance) may be omitted on counters with no instance structures
|
|
if object or counter is missing, then FALSE is returned, otherwise
|
|
TRUE is returned if the parsing was successful
|
|
*/
|
|
{
|
|
LPWSTR szWorkMachine = NULL;
|
|
LPWSTR szWorkObject = NULL;
|
|
LPWSTR szWorkInstance = NULL;
|
|
LPWSTR szWorkParent = NULL;
|
|
LPWSTR szWorkCounter = NULL;
|
|
DWORD dwBufferSize = lstrlenW(szFullCounterPath) + 1;
|
|
BOOL bReturn = FALSE;
|
|
LPWSTR szSrcChar, szDestChar;
|
|
DWORD dwBufferLength = 0;
|
|
DWORD dwWorkMachineLength = 0;
|
|
DWORD dwWorkObjectLength = 0;
|
|
DWORD dwWorkInstanceLength = 0;
|
|
DWORD dwWorkParentLength = 0;
|
|
DWORD dwWorkCounterLength = 0;
|
|
DWORD dwWorkIndex = 0;
|
|
DWORD dwParenDepth = 0;
|
|
WCHAR wDelimiter = 0;
|
|
LPWSTR pszBsDelim[2] = {0,0};
|
|
LPWSTR szThisChar;
|
|
DWORD dwParenCount = 0;
|
|
LPWSTR szLastParen = NULL;
|
|
|
|
if (dwBufferSize < MAX_PATH) dwBufferSize = MAX_PATH;
|
|
|
|
szWorkMachine = G_ALLOC(dwBufferSize * sizeof(WCHAR));
|
|
szWorkObject = G_ALLOC(dwBufferSize * sizeof(WCHAR));
|
|
szWorkInstance = G_ALLOC(dwBufferSize * sizeof(WCHAR));
|
|
szWorkParent = G_ALLOC(dwBufferSize * sizeof(WCHAR));
|
|
szWorkCounter = G_ALLOC(dwBufferSize * sizeof(WCHAR));
|
|
|
|
if (szWorkMachine != NULL && szWorkObject != NULL && szWorkInstance != NULL
|
|
&& szWorkParent != NULL && szWorkCounter != NULL) {
|
|
// get machine name from counter path
|
|
szSrcChar = (LPWSTR) szFullCounterPath;
|
|
|
|
//define the delimiter char between the machine and the object
|
|
// or in WBEM parlance, the server & namespace and the Class name
|
|
if (bWbemSyntax) {
|
|
wDelimiter = COLON_L;
|
|
}
|
|
else {
|
|
wDelimiter = BACKSLASH_L;
|
|
// if this is backslash delimited string, then find the
|
|
// backslash the denotes the end of the machine and start of the
|
|
// object by walking down the string and finding the 2nd to the last
|
|
// backslash.
|
|
// this is necessary since a WBEM machine\namespace path can have
|
|
// multiple backslashes in it while there will ALWAYS be two at
|
|
// the end, one at the start of the object name and one at the start
|
|
// of the counter name
|
|
dwParenDepth = 0;
|
|
for (szThisChar = szSrcChar; * szThisChar != L'\0'; szThisChar++) {
|
|
if (* szThisChar == LEFTPAREN_L) {
|
|
if (dwParenDepth == 0) dwParenCount ++;
|
|
dwParenDepth ++;
|
|
}
|
|
else if (* szThisChar == RIGHTPAREN_L) {
|
|
if (dwParenDepth > 0) dwParenDepth --;
|
|
}
|
|
else {
|
|
if (dwParenDepth == 0) {
|
|
// ignore delimiters inside parenthesis
|
|
if (* szThisChar == wDelimiter) {
|
|
pszBsDelim[0] = pszBsDelim[1];
|
|
pszBsDelim[1] = szThisChar;
|
|
}
|
|
// ignore it and go to the next character
|
|
}
|
|
}
|
|
}
|
|
if ((dwParenCount > 0) && (pszBsDelim[0] != NULL) && (pszBsDelim[1] != NULL)) {
|
|
dwParenDepth = 0;
|
|
for (szThisChar = pszBsDelim[0]; ((* szThisChar != L'\0') && (szThisChar < pszBsDelim[1])); szThisChar ++) {
|
|
if (* szThisChar == LEFTPAREN_L) {
|
|
if (dwParenDepth == 0) {
|
|
// see if the preceeding char is whitespace
|
|
-- szThisChar;
|
|
if (* szThisChar > SPACE_L) {
|
|
// then this could be an instance delim
|
|
szLastParen = ++ szThisChar;
|
|
}
|
|
else {
|
|
// else it's probably part of the instance name
|
|
++ szThisChar;
|
|
}
|
|
}
|
|
dwParenDepth ++;
|
|
}
|
|
else if (* szThisChar == RIGHTPAREN_L) {
|
|
if (dwParenDepth > 0) dwParenDepth --;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// see if this is really a machine name by looking for leading "\\"
|
|
if ((szSrcChar[0] == BACKSLASH_L) && (szSrcChar[1] == BACKSLASH_L)) {
|
|
szDestChar = szWorkMachine;
|
|
* szDestChar ++ = * szSrcChar ++;
|
|
* szDestChar ++ = * szSrcChar ++;
|
|
dwWorkMachineLength = 2;
|
|
// must be a machine name so find the object delimiter and zero terminate
|
|
// it there
|
|
while (* szSrcChar != L'\0') {
|
|
if (pszBsDelim[0] != NULL) {
|
|
// then go to this pointer
|
|
if (szSrcChar == pszBsDelim[0]) break;
|
|
}
|
|
else {
|
|
// go to the next delimiter
|
|
if (* szSrcChar != wDelimiter) break;
|
|
}
|
|
* szDestChar ++ = * szSrcChar ++;
|
|
dwWorkMachineLength ++;
|
|
}
|
|
if (* szSrcChar == L'\0') {
|
|
// no other required fields
|
|
goto Cleanup;
|
|
}
|
|
else {
|
|
// null terminate and continue
|
|
* szDestChar ++ = L'\0';
|
|
}
|
|
}
|
|
else {
|
|
// no machine name, so they must have skipped that field
|
|
// which is OK. We'll insert the local machine name here
|
|
StringCchCopyW(szWorkMachine, dwBufferSize, szStaticLocalMachineName);
|
|
dwWorkMachineLength = lstrlenW(szWorkMachine);
|
|
}
|
|
// szSrcChar should be pointing to the backslash preceeding the
|
|
// object name now.
|
|
if (szSrcChar[0] == wDelimiter) {
|
|
szSrcChar ++; // to move past backslash
|
|
szDestChar = szWorkObject;
|
|
// copy until:
|
|
// a) the end of the source string is reached
|
|
// b) the instance delimiter is found "("
|
|
// c) the counter delimiter is found "\"
|
|
// d) a non-printable, non-space char is found
|
|
while ((* szSrcChar != L'\0') && (szSrcChar != szLastParen)
|
|
&& (* szSrcChar != BACKSLASH_L) && (* szSrcChar >= SPACE_L)) {
|
|
dwWorkObjectLength ++;
|
|
* szDestChar ++ = * szSrcChar ++;
|
|
}
|
|
// see why it ended:
|
|
if (* szSrcChar < SPACE_L) {
|
|
// ran of source string
|
|
goto Cleanup;
|
|
}
|
|
else if (szSrcChar == szLastParen) {
|
|
dwParenDepth = 1;
|
|
// there's an instance so copy that to the instance field
|
|
* szDestChar = L'\0'; // terminate destination string
|
|
szDestChar = szWorkInstance;
|
|
// skip past open paren
|
|
++ szSrcChar;
|
|
// copy until:
|
|
// a) the end of the source string is reached
|
|
// b) the instance delimiter is found "("
|
|
while ((* szSrcChar != L'\0') && (dwParenDepth > 0)) {
|
|
if (* szSrcChar == RIGHTPAREN_L) {
|
|
dwParenDepth --;
|
|
}
|
|
else if (* szSrcChar == LEFTPAREN_L) {
|
|
dwParenDepth ++;
|
|
}
|
|
if (dwParenDepth > 0) {
|
|
// copy all parenthesis except the last one
|
|
dwWorkInstanceLength ++;
|
|
* szDestChar ++ = * szSrcChar ++;
|
|
}
|
|
}
|
|
// see why it ended:
|
|
if (* szSrcChar == L'\0') {
|
|
// ran of source string
|
|
goto Cleanup;
|
|
}
|
|
else {
|
|
// move source to object delimiter
|
|
if (* ++ szSrcChar != BACKSLASH_L) {
|
|
// bad format
|
|
goto Cleanup;
|
|
}
|
|
else {
|
|
* szDestChar = L'\0';
|
|
// check instance string for a parent
|
|
if (ParseInstanceName(
|
|
szWorkInstance, szWorkInstance, szWorkParent, dwBufferSize, & dwWorkIndex)) {
|
|
dwWorkInstanceLength = lstrlenW(szWorkInstance);
|
|
dwWorkParentLength = lstrlenW(szWorkParent);
|
|
}
|
|
else {
|
|
// instance string not formatted correctly
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// terminate the destination string
|
|
* szDestChar = L'\0';
|
|
}
|
|
// finally copy the counter name
|
|
szSrcChar ++; // to move past backslash
|
|
szDestChar = szWorkCounter;
|
|
// copy until:
|
|
// a) the end of the source string is reached
|
|
while (* szSrcChar != L'\0') {
|
|
dwWorkCounterLength ++;
|
|
* szDestChar ++ = * szSrcChar ++;
|
|
}
|
|
* szDestChar = L'\0';
|
|
// now to see if all this will fit in the users's buffer
|
|
dwBufferLength = sizeof(PDHI_COUNTER_PATH) - sizeof(BYTE);
|
|
dwBufferLength += DWORD_MULTIPLE((dwWorkMachineLength + 1) * sizeof(WCHAR));
|
|
dwBufferLength += DWORD_MULTIPLE((dwWorkObjectLength + 1) * sizeof(WCHAR));
|
|
if (dwWorkInstanceLength > 0) {
|
|
dwBufferLength += DWORD_MULTIPLE((dwWorkInstanceLength + 1) * sizeof(WCHAR));
|
|
}
|
|
if (dwWorkParentLength > 0) {
|
|
dwBufferLength += DWORD_MULTIPLE((dwWorkParentLength + 1) * sizeof(WCHAR));
|
|
}
|
|
dwBufferLength += DWORD_MULTIPLE((dwWorkCounterLength + 1) * sizeof(WCHAR));
|
|
|
|
TRACE((PDH_DBG_TRACE_INFO),
|
|
(__LINE__,
|
|
PDH_CUTILS,
|
|
ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_WSTR, 2)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 3)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 4)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 5)
|
|
| ARG_DEF(ARG_TYPE_WSTR, 6),
|
|
ERROR_SUCCESS,
|
|
TRACE_WSTR(szFullCounterPath),
|
|
TRACE_WSTR(szWorkMachine),
|
|
TRACE_WSTR(szWorkObject),
|
|
TRACE_WSTR(szWorkCounter),
|
|
TRACE_WSTR(szWorkInstance),
|
|
TRACE_WSTR(szWorkParent),
|
|
TRACE_DWORD(dwWorkIndex),
|
|
TRACE_DWORD(dwBufferLength),
|
|
NULL));
|
|
|
|
if (dwBufferLength < * pdwBufferSize) {
|
|
// it looks like it'll fit so start filling things in
|
|
szDestChar = (LPWSTR) & pCounter->pBuffer[0];
|
|
|
|
if (dwWorkMachineLength != 0) {
|
|
pCounter->szMachineName = szDestChar;
|
|
StringCchCopyW(szDestChar, dwWorkMachineLength + 1, szWorkMachine);
|
|
szDestChar += dwWorkMachineLength + 1;
|
|
szDestChar = ALIGN_ON_DWORD(szDestChar);
|
|
}
|
|
else {
|
|
pCounter->szMachineName = NULL;
|
|
}
|
|
pCounter->szObjectName = szDestChar;
|
|
StringCchCopyW(szDestChar, dwWorkObjectLength + 1, szWorkObject);
|
|
szDestChar += dwWorkObjectLength + 1;
|
|
szDestChar = ALIGN_ON_DWORD(szDestChar);
|
|
|
|
if (dwWorkInstanceLength != 0) {
|
|
pCounter->szInstanceName = szDestChar;
|
|
StringCchCopyW(szDestChar, dwWorkInstanceLength + 1, szWorkInstance);
|
|
szDestChar += dwWorkInstanceLength + 1;
|
|
szDestChar = ALIGN_ON_DWORD(szDestChar);
|
|
}
|
|
else {
|
|
pCounter->szInstanceName = NULL;
|
|
}
|
|
|
|
if (dwWorkParentLength != 0) {
|
|
pCounter->szParentName = szDestChar;
|
|
StringCchCopyW(szDestChar, dwWorkParentLength + 1, szWorkParent);
|
|
szDestChar += dwWorkParentLength + 1;
|
|
szDestChar = ALIGN_ON_DWORD(szDestChar);
|
|
}
|
|
else {
|
|
pCounter->szParentName = NULL;
|
|
}
|
|
pCounter->dwIndex = dwWorkIndex;
|
|
|
|
pCounter->szCounterName = szDestChar;
|
|
StringCchCopyW(szDestChar, dwWorkCounterLength + 1, szWorkCounter);
|
|
|
|
szDestChar += dwWorkCounterLength + 1;
|
|
szDestChar = ALIGN_ON_DWORD(szDestChar);
|
|
|
|
* pdwBufferSize = dwBufferLength;
|
|
bReturn = TRUE;
|
|
}
|
|
else {
|
|
//insufficient buffer
|
|
}
|
|
}
|
|
else {
|
|
// no object found so return
|
|
}
|
|
}
|
|
else {
|
|
// incoming string is too long
|
|
}
|
|
|
|
Cleanup:
|
|
G_FREE(szWorkMachine);
|
|
G_FREE(szWorkObject);
|
|
G_FREE(szWorkInstance);
|
|
G_FREE(szWorkParent);
|
|
G_FREE(szWorkCounter);
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL
|
|
FreeCounter(
|
|
PPDHI_COUNTER pThisCounter
|
|
)
|
|
{
|
|
// NOTE:
|
|
// This function assumes the query containing
|
|
// this counter has already been locked by the calling
|
|
// function.
|
|
|
|
PPDHI_COUNTER pPrevCounter;
|
|
PPDHI_COUNTER pNextCounter;
|
|
PPDHI_QUERY pParentQuery;
|
|
|
|
// define pointers
|
|
pPrevCounter = pThisCounter->next.blink;
|
|
pNextCounter = pThisCounter->next.flink;
|
|
pParentQuery = pThisCounter->pOwner;
|
|
|
|
// decrement machine reference counter if a machine has been assigned
|
|
if (pThisCounter->pQMachine != NULL) {
|
|
if (pThisCounter->pQMachine->pMachine != NULL) {
|
|
if (--pThisCounter->pQMachine->pMachine->dwRefCount == 0) {
|
|
// then this is the last counter so remove machine
|
|
// freeing the machine in this call causes all kinds of
|
|
// multi-threading problems so we'll keep it around until
|
|
// the DLL unloads.
|
|
// FreeMachine (pThisCounter->pQMachine->pMachine, FALSE);
|
|
pThisCounter->pQMachine->pMachine = NULL;
|
|
}
|
|
else {
|
|
// the ref count is non-zero so leave the pointer alone
|
|
}
|
|
}
|
|
else {
|
|
// the pointer has already been cleared
|
|
}
|
|
}
|
|
else {
|
|
// there's no machine
|
|
}
|
|
|
|
// free allocated memory in the counter
|
|
G_FREE(pThisCounter->pCounterPath);
|
|
pThisCounter->pCounterPath = NULL;
|
|
|
|
G_FREE(pThisCounter->szFullName);
|
|
pThisCounter->szFullName = NULL;
|
|
|
|
if (pParentQuery != NULL) {
|
|
if (pParentQuery->hLog == NULL) {
|
|
G_FREE(pThisCounter->pThisObject);
|
|
pThisCounter->pThisObject = NULL;
|
|
G_FREE(pThisCounter->pLastObject);
|
|
pThisCounter->pLastObject = NULL;
|
|
G_FREE(pThisCounter->pThisRawItemList);
|
|
pThisCounter->pThisRawItemList = NULL;
|
|
G_FREE(pThisCounter->pLastRawItemList);
|
|
pThisCounter->pLastRawItemList = NULL;
|
|
}
|
|
}
|
|
|
|
// check for WBEM items
|
|
|
|
if ((pThisCounter->dwFlags & PDHIC_WBEM_COUNTER) && (pThisCounter->pOwner != NULL)) {
|
|
PdhiCloseWbemCounter(pThisCounter);
|
|
}
|
|
|
|
// update pointers if they've been assigned
|
|
if ((pPrevCounter != NULL) && (pNextCounter != NULL)) {
|
|
if ((pPrevCounter != pThisCounter) && (pNextCounter != pThisCounter)) {
|
|
// update query list pointers
|
|
pPrevCounter->next.flink = pNextCounter;
|
|
pNextCounter->next.blink = pPrevCounter;
|
|
}
|
|
else {
|
|
// this is the only counter entry in the list
|
|
// so the caller must deal with updating the head pointer
|
|
}
|
|
}
|
|
// delete this counter
|
|
G_FREE(pThisCounter);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
UpdateCounterValue(
|
|
PPDHI_COUNTER pCounter,
|
|
PPERF_DATA_BLOCK pPerfData
|
|
)
|
|
{
|
|
DWORD LocalCStatus = 0;
|
|
DWORD LocalCType = 0;
|
|
LPVOID pData = NULL;
|
|
PDWORD pdwData;
|
|
UNALIGNED LONGLONG * pllData;
|
|
PPERF_OBJECT_TYPE pPerfObject = NULL;
|
|
BOOL bReturn = FALSE;
|
|
|
|
pData = GetPerfCounterDataPtr(pPerfData,
|
|
pCounter->pCounterPath,
|
|
& pCounter->plCounterInfo,
|
|
0,
|
|
& pPerfObject,
|
|
& LocalCStatus);
|
|
pCounter->ThisValue.CStatus = LocalCStatus;
|
|
if (IsSuccessSeverity(LocalCStatus)) {
|
|
// assume success
|
|
bReturn = TRUE;
|
|
// load counter value based on counter type
|
|
LocalCType = pCounter->plCounterInfo.dwCounterType;
|
|
switch (LocalCType) {
|
|
//
|
|
// these counter types are loaded as:
|
|
// Numerator = Counter data from perf data block
|
|
// Denominator = Perf Time from perf data block
|
|
// (the time base is the PerfFreq)
|
|
//
|
|
case PERF_COUNTER_COUNTER:
|
|
case PERF_COUNTER_QUEUELEN_TYPE:
|
|
case PERF_SAMPLE_COUNTER:
|
|
pCounter->ThisValue.FirstValue = (LONGLONG) (* (DWORD *) pData);
|
|
pCounter->ThisValue.SecondValue = pPerfData->PerfTime.QuadPart;
|
|
break;
|
|
|
|
case PERF_OBJ_TIME_TIMER:
|
|
pCounter->ThisValue.FirstValue = (LONGLONG) (* (DWORD *) pData);
|
|
pCounter->ThisValue.SecondValue = pPerfObject->PerfTime.QuadPart;
|
|
break;
|
|
|
|
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
pCounter->ThisValue.SecondValue = pPerfData->PerfTime100nSec.QuadPart;
|
|
break;
|
|
|
|
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
pCounter->ThisValue.SecondValue = pPerfObject->PerfTime.QuadPart;
|
|
break;
|
|
|
|
case PERF_COUNTER_TIMER:
|
|
case PERF_COUNTER_TIMER_INV:
|
|
case PERF_COUNTER_BULK_COUNT:
|
|
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
pCounter->ThisValue.SecondValue = pPerfData->PerfTime.QuadPart;
|
|
if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
|
|
pCounter->ThisValue.MultiCount = (DWORD) * ++ pllData;
|
|
}
|
|
break;
|
|
//
|
|
// this is a hack to make the PDH work like PERFMON for
|
|
// this counter type
|
|
//
|
|
case PERF_COUNTER_MULTI_TIMER:
|
|
case PERF_COUNTER_MULTI_TIMER_INV:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
// begin hack code
|
|
pCounter->ThisValue.FirstValue *= (DWORD) pPerfData->PerfFreq.QuadPart;
|
|
// end hack code
|
|
pCounter->ThisValue.SecondValue = pPerfData->PerfTime.QuadPart;
|
|
if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
|
|
pCounter->ThisValue.MultiCount = (DWORD) * ++ pllData;
|
|
}
|
|
break;
|
|
//
|
|
// These counters do not use any time reference
|
|
//
|
|
case PERF_COUNTER_RAWCOUNT:
|
|
case PERF_COUNTER_RAWCOUNT_HEX:
|
|
case PERF_COUNTER_DELTA:
|
|
pCounter->ThisValue.FirstValue = (LONGLONG) (* (DWORD *) pData);
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
break;
|
|
|
|
case PERF_COUNTER_LARGE_RAWCOUNT:
|
|
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
|
|
case PERF_COUNTER_LARGE_DELTA:
|
|
pCounter->ThisValue.FirstValue = * (LONGLONG *) pData;
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
break;
|
|
//
|
|
// These counters use the 100 Ns time base in thier calculation
|
|
//
|
|
case PERF_100NSEC_TIMER:
|
|
case PERF_100NSEC_TIMER_INV:
|
|
case PERF_100NSEC_MULTI_TIMER:
|
|
case PERF_100NSEC_MULTI_TIMER_INV:
|
|
pllData = (UNALIGNED LONGLONG *)pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
pCounter->ThisValue.SecondValue = pPerfData->PerfTime100nSec.QuadPart;
|
|
if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
|
|
++ pllData;
|
|
pCounter->ThisValue.MultiCount = * (DWORD *) pllData;
|
|
}
|
|
break;
|
|
//
|
|
// These counters use two data points, the one pointed to by
|
|
// pData and the one immediately after
|
|
//
|
|
case PERF_SAMPLE_FRACTION:
|
|
case PERF_RAW_FRACTION:
|
|
pdwData = (DWORD *) pData;
|
|
pCounter->ThisValue.FirstValue = (LONGLONG) (* pdwData);
|
|
// find the pointer to the base value in the structure
|
|
pData = GetPerfCounterDataPtr(pPerfData,
|
|
pCounter->pCounterPath,
|
|
& pCounter->plCounterInfo,
|
|
GPCDP_GET_BASE_DATA,
|
|
NULL,
|
|
& LocalCStatus);
|
|
if (IsSuccessSeverity(LocalCStatus)) {
|
|
pdwData = (DWORD *) pData;
|
|
pCounter->ThisValue.SecondValue = (LONGLONG) (* pdwData);
|
|
}
|
|
else {
|
|
// unable to locate base value
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
pCounter->ThisValue.CStatus = LocalCStatus;
|
|
bReturn = FALSE;
|
|
}
|
|
break;
|
|
|
|
case PERF_LARGE_RAW_FRACTION:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
pData = GetPerfCounterDataPtr(pPerfData,
|
|
pCounter->pCounterPath,
|
|
& pCounter->plCounterInfo,
|
|
GPCDP_GET_BASE_DATA,
|
|
NULL,
|
|
& LocalCStatus);
|
|
if (IsSuccessSeverity(LocalCStatus)) {
|
|
pllData = (LONGLONG *) pData;
|
|
pCounter->ThisValue.SecondValue = * pllData;
|
|
}
|
|
else {
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
pCounter->ThisValue.CStatus = LocalCStatus;
|
|
bReturn = FALSE;
|
|
}
|
|
break;
|
|
|
|
case PERF_PRECISION_SYSTEM_TIMER:
|
|
case PERF_PRECISION_100NS_TIMER:
|
|
case PERF_PRECISION_OBJECT_TIMER:
|
|
pllData = (LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
// find the pointer to the base value in the structure
|
|
pData = GetPerfCounterDataPtr(pPerfData,
|
|
pCounter->pCounterPath,
|
|
& pCounter->plCounterInfo,
|
|
GPCDP_GET_BASE_DATA,
|
|
NULL,
|
|
& LocalCStatus);
|
|
if (IsSuccessSeverity(LocalCStatus)) {
|
|
pllData = (LONGLONG *) pData;
|
|
pCounter->ThisValue.SecondValue = * pllData;
|
|
}
|
|
else {
|
|
// unable to locate base value
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
pCounter->ThisValue.CStatus = LocalCStatus;
|
|
bReturn = FALSE;
|
|
}
|
|
break;
|
|
|
|
case PERF_AVERAGE_TIMER:
|
|
case PERF_AVERAGE_BULK:
|
|
// counter (numerator) is a LONGLONG, while the
|
|
// denominator is just a DWORD
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
pData = GetPerfCounterDataPtr(pPerfData,
|
|
pCounter->pCounterPath,
|
|
& pCounter->plCounterInfo,
|
|
GPCDP_GET_BASE_DATA,
|
|
NULL,
|
|
& LocalCStatus);
|
|
if (IsSuccessSeverity(LocalCStatus)) {
|
|
pdwData = (DWORD *) pData;
|
|
pCounter->ThisValue.SecondValue = * pdwData;
|
|
} else {
|
|
// unable to locate base value
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
pCounter->ThisValue.CStatus = LocalCStatus;
|
|
bReturn = FALSE;
|
|
}
|
|
break;
|
|
//
|
|
// These counters are used as the part of another counter
|
|
// and as such should not be used, but in case they are
|
|
// they'll be handled here.
|
|
//
|
|
case PERF_SAMPLE_BASE:
|
|
case PERF_AVERAGE_BASE:
|
|
case PERF_COUNTER_MULTI_BASE:
|
|
case PERF_RAW_BASE:
|
|
case PERF_LARGE_RAW_BASE:
|
|
pCounter->ThisValue.FirstValue = 0;
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
break;
|
|
|
|
case PERF_ELAPSED_TIME:
|
|
// this counter type needs the object perf data as well
|
|
if (GetObjectPerfInfo(pPerfData,
|
|
pCounter->plCounterInfo.dwObjectId,
|
|
& pCounter->ThisValue.SecondValue,
|
|
& pCounter->TimeBase)) {
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
}
|
|
else {
|
|
pCounter->ThisValue.FirstValue = 0;
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
}
|
|
break;
|
|
//
|
|
// These counters are not supported by this function (yet)
|
|
//
|
|
case PERF_COUNTER_TEXT:
|
|
case PERF_COUNTER_NODATA:
|
|
case PERF_COUNTER_HISTOGRAM_TYPE:
|
|
pCounter->ThisValue.FirstValue = 0;
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
break;
|
|
|
|
default:
|
|
// an unidentified counter was returned so
|
|
pCounter->ThisValue.FirstValue = 0;
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
bReturn = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
// else this counter is not valid so this value == 0
|
|
pCounter->ThisValue.FirstValue = pCounter->LastValue.FirstValue;
|
|
pCounter->ThisValue.SecondValue = pCounter->LastValue.SecondValue;
|
|
pCounter->ThisValue.CStatus = LocalCStatus;
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL
|
|
UpdateRealTimeCounterValue(
|
|
PPDHI_COUNTER pCounter
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
DWORD LocalCStatus = 0;
|
|
FILETIME GmtFileTime;
|
|
|
|
// move current value to last value buffer
|
|
pCounter->LastValue = pCounter->ThisValue;
|
|
// and clear the old value
|
|
pCounter->ThisValue.MultiCount = 1;
|
|
pCounter->ThisValue.FirstValue = 0;
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
|
|
// don't process if the counter has not been initialized
|
|
if (!(pCounter->dwFlags & PDHIC_COUNTER_UNUSABLE)) {
|
|
// get the counter's machine status first. There's no point in
|
|
// contuning if the machine is offline
|
|
LocalCStatus = pCounter->pQMachine->lQueryStatus;
|
|
if (IsSuccessSeverity(LocalCStatus) && pCounter->pQMachine->pPerfData != NULL) {
|
|
// update timestamp
|
|
SystemTimeToFileTime(& pCounter->pQMachine->pPerfData->SystemTime, & GmtFileTime);
|
|
FileTimeToLocalFileTime(& GmtFileTime, & pCounter->ThisValue.TimeStamp);
|
|
bResult = UpdateCounterValue(pCounter, pCounter->pQMachine->pPerfData);
|
|
}
|
|
else {
|
|
// unable to read data from this counter's machine so use the
|
|
// query's timestamp
|
|
//
|
|
pCounter->ThisValue.TimeStamp.dwLowDateTime = LODWORD(pCounter->pQMachine->llQueryTime);
|
|
pCounter->ThisValue.TimeStamp.dwHighDateTime = HIDWORD(pCounter->pQMachine->llQueryTime);
|
|
// all other data fields remain un-changed
|
|
pCounter->ThisValue.CStatus = LocalCStatus; // save counter status
|
|
}
|
|
}
|
|
else {
|
|
if (pCounter->dwFlags & PDHIC_COUNTER_NOT_INIT) {
|
|
// try to init it
|
|
InitCounter (pCounter);
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
BOOL
|
|
UpdateMultiInstanceCounterValue(
|
|
PPDHI_COUNTER pCounter,
|
|
PPERF_DATA_BLOCK pPerfData,
|
|
LONGLONG TimeStamp
|
|
)
|
|
{
|
|
PPERF_OBJECT_TYPE pPerfObject = NULL;
|
|
PPERF_INSTANCE_DEFINITION pPerfInstance = NULL;
|
|
PPERF_OBJECT_TYPE pParentObject = NULL;
|
|
PPERF_INSTANCE_DEFINITION pThisParentInstance = NULL;
|
|
PPERF_COUNTER_DEFINITION pNumPerfCounter = NULL;
|
|
PPERF_COUNTER_DEFINITION pDenPerfCounter = NULL;
|
|
DWORD LocalCStatus = 0;
|
|
DWORD LocalCType = 0;
|
|
LPVOID pData = NULL;
|
|
PDWORD pdwData;
|
|
UNALIGNED LONGLONG * pllData;
|
|
FILETIME GmtFileTime;
|
|
DWORD dwSize;
|
|
DWORD dwFinalSize;
|
|
LONG nThisInstanceIndex;
|
|
LONG nParentInstanceIndex;
|
|
LPWSTR szNextNameString;
|
|
DWORD dwStrSize;
|
|
PPDHI_RAW_COUNTER_ITEM pThisItem;
|
|
BOOL bReturn = FALSE;
|
|
|
|
pPerfObject = GetObjectDefByTitleIndex(pPerfData, pCounter->plCounterInfo.dwObjectId);
|
|
|
|
if (pPerfObject != NULL) {
|
|
// this should be caught during the AddCounter operation
|
|
//
|
|
// allocate a new buffer for the current data
|
|
// this should be large enough to handle the header,
|
|
// all instances and thier name strings
|
|
//
|
|
dwSize = sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK) - sizeof(PDHI_RAW_COUNTER_ITEM);
|
|
dwStrSize = 0;
|
|
|
|
pPerfInstance = FirstInstance(pPerfObject);
|
|
// make sure pointer is still within the same instance
|
|
|
|
for (nThisInstanceIndex = 0;
|
|
pPerfInstance != NULL && nThisInstanceIndex < pPerfObject->NumInstances;
|
|
nThisInstanceIndex ++) {
|
|
// this should only fail in dire cases
|
|
if (pPerfInstance == NULL) break;
|
|
// for this instance add the size of the data item
|
|
dwSize += sizeof(PDHI_RAW_COUNTER_ITEM);
|
|
// and the size of the name string
|
|
dwSize += pPerfInstance->NameLength + sizeof(WCHAR);
|
|
dwStrSize += pPerfInstance->NameLength / sizeof(WCHAR) + 1;
|
|
// to the required buffer size
|
|
|
|
// if this instance has a parent, see how long it's string
|
|
// is
|
|
|
|
// first see if we've already got the pointer to the parent
|
|
|
|
if (pPerfInstance->ParentObjectTitleIndex != 0) {
|
|
// then include the parent instance name
|
|
if (pParentObject == NULL) {
|
|
// get parent object
|
|
pParentObject = GetObjectDefByTitleIndex(pPerfData, pPerfInstance->ParentObjectTitleIndex);
|
|
}
|
|
else {
|
|
if (pParentObject->ObjectNameTitleIndex != pPerfInstance->ParentObjectTitleIndex) {
|
|
pParentObject = GetObjectDefByTitleIndex(pPerfData, pPerfInstance->ParentObjectTitleIndex);
|
|
}
|
|
}
|
|
if (pParentObject == NULL) break;
|
|
|
|
// now go to the corresponding instance entry
|
|
pThisParentInstance = FirstInstance(pParentObject);
|
|
// make sure pointer is still within the same instance
|
|
|
|
if (pThisParentInstance != NULL) {
|
|
if (pPerfInstance->ParentObjectInstance < (DWORD) pParentObject->NumInstances) {
|
|
for (nParentInstanceIndex = 0;
|
|
(DWORD) nParentInstanceIndex != pPerfInstance->ParentObjectInstance;
|
|
nParentInstanceIndex ++) {
|
|
pThisParentInstance = NextInstance(pParentObject, pThisParentInstance);
|
|
if (pThisParentInstance == NULL) break;
|
|
}
|
|
|
|
if (pThisParentInstance != NULL) {
|
|
// found it so add in it's string length
|
|
dwSize += pThisParentInstance->NameLength + sizeof(WCHAR);
|
|
dwStrSize += pThisParentInstance->NameLength / sizeof(WCHAR) + 1;
|
|
}
|
|
}
|
|
else {
|
|
// the index is not in the parent
|
|
pThisParentInstance = NULL;
|
|
// so don't change the size required field
|
|
}
|
|
}
|
|
}
|
|
// round up to the next DWORD address
|
|
dwSize = DWORD_MULTIPLE(dwSize);
|
|
// and go to the next instance
|
|
pPerfInstance = NextInstance(pPerfObject, pPerfInstance);
|
|
}
|
|
//
|
|
//
|
|
pCounter->pThisRawItemList = G_ALLOC(dwSize);
|
|
if (pCounter->pThisRawItemList != NULL) {
|
|
pCounter->pThisRawItemList->dwLength = dwSize;
|
|
pNumPerfCounter = GetCounterDefByTitleIndex(pPerfObject, 0, pCounter->plCounterInfo.dwCounterId);
|
|
|
|
// just in case we need it later
|
|
pDenPerfCounter = pNumPerfCounter + 1;
|
|
// fill in the counter data
|
|
pCounter->pThisRawItemList->dwItemCount = pPerfObject->NumInstances;
|
|
pCounter->pThisRawItemList->CStatus = LocalCStatus;
|
|
|
|
// update timestamp
|
|
SystemTimeToFileTime(& pPerfData->SystemTime, & GmtFileTime);
|
|
FileTimeToLocalFileTime(& GmtFileTime, & pCounter->pThisRawItemList->TimeStamp);
|
|
pThisItem = & pCounter->pThisRawItemList->pItemArray[0];
|
|
szNextNameString = (LPWSTR) & (pCounter->pThisRawItemList->pItemArray[pPerfObject->NumInstances]);
|
|
pPerfInstance = FirstInstance(pPerfObject);
|
|
if (pPerfInstance != NULL) {
|
|
// make sure pointer is still within the same instance
|
|
// for each instance log the raw data values for this counter
|
|
for (nThisInstanceIndex = 0;
|
|
pPerfInstance != NULL && nThisInstanceIndex < pPerfObject->NumInstances;
|
|
nThisInstanceIndex ++) {
|
|
// make sure pointe is still within the same instance
|
|
// make a new instance entry
|
|
|
|
// get the name of this instance
|
|
pThisItem->szName = (DWORD) (((LPBYTE) szNextNameString) - ((LPBYTE) pCounter->pThisRawItemList));
|
|
if (dwStrSize == 0) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
bReturn = FALSE;
|
|
break;
|
|
}
|
|
dwSize = GetFullInstanceNameStr(pPerfData, pPerfObject, pPerfInstance, szNextNameString, dwStrSize);
|
|
if (dwSize == 0) {
|
|
// unable to read instance name
|
|
// so make one up (and assert in DBG builds)
|
|
_ltow(nThisInstanceIndex, szNextNameString, 10);
|
|
dwSize = lstrlenW(szNextNameString);
|
|
}
|
|
|
|
if (dwSize + 1 > dwStrSize) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
bReturn = FALSE;
|
|
break;
|
|
}
|
|
szNextNameString += dwSize + 1;
|
|
dwStrSize -= (dwSize + 1);
|
|
|
|
// get the pointer to the counter data
|
|
pData = GetPerfCounterDataPtr(pPerfData,
|
|
pCounter->pCounterPath,
|
|
& pCounter->plCounterInfo,
|
|
0,
|
|
NULL,
|
|
& LocalCStatus);
|
|
if (pNumPerfCounter != NULL) {
|
|
pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pNumPerfCounter);
|
|
}
|
|
if (pData == NULL) {
|
|
SetLastError(PDH_CSTATUS_NO_INSTANCE);
|
|
bReturn = FALSE;
|
|
break;
|
|
}
|
|
bReturn = TRUE; // assume success
|
|
// load counter value based on counter type
|
|
LocalCType = pCounter->plCounterInfo.dwCounterType;
|
|
switch (LocalCType) {
|
|
//
|
|
// these counter types are loaded as:
|
|
// Numerator = Counter data from perf data block
|
|
// Denominator = Perf Time from perf data block
|
|
// (the time base is the PerfFreq)
|
|
//
|
|
case PERF_COUNTER_COUNTER:
|
|
case PERF_COUNTER_QUEUELEN_TYPE:
|
|
case PERF_SAMPLE_COUNTER:
|
|
pThisItem->FirstValue = (LONGLONG) (* (DWORD *) pData);
|
|
pThisItem->SecondValue = pPerfData->PerfTime.QuadPart;
|
|
break;
|
|
|
|
case PERF_OBJ_TIME_TIMER:
|
|
pThisItem->FirstValue = (LONGLONG) (* (DWORD *) pData);
|
|
pThisItem->SecondValue = pPerfObject->PerfTime.QuadPart;
|
|
break;
|
|
|
|
case PERF_COUNTER_100NS_QUEUELEN_TYPE:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pThisItem->FirstValue = * pllData;
|
|
pThisItem->SecondValue = pPerfData->PerfTime100nSec.QuadPart;
|
|
break;
|
|
|
|
case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pThisItem->FirstValue = * pllData;
|
|
pThisItem->SecondValue = pPerfObject->PerfTime.QuadPart;
|
|
break;
|
|
|
|
case PERF_COUNTER_TIMER:
|
|
case PERF_COUNTER_TIMER_INV:
|
|
case PERF_COUNTER_BULK_COUNT:
|
|
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pThisItem->FirstValue = * pllData;
|
|
pThisItem->SecondValue = pPerfData->PerfTime.QuadPart;
|
|
if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
|
|
pThisItem->MultiCount = (DWORD) * ++pllData;
|
|
}
|
|
break;
|
|
|
|
case PERF_COUNTER_MULTI_TIMER:
|
|
case PERF_COUNTER_MULTI_TIMER_INV:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pThisItem->FirstValue = * pllData;
|
|
// begin hack code
|
|
pThisItem->FirstValue *= (DWORD) pPerfData->PerfFreq.QuadPart;
|
|
// end hack code
|
|
pThisItem->SecondValue = pPerfData->PerfTime.QuadPart;
|
|
if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
|
|
pThisItem->MultiCount = (DWORD) * ++ pllData;
|
|
}
|
|
break;
|
|
//
|
|
// These counters do not use any time reference
|
|
//
|
|
case PERF_COUNTER_RAWCOUNT:
|
|
case PERF_COUNTER_RAWCOUNT_HEX:
|
|
case PERF_COUNTER_DELTA:
|
|
pThisItem->FirstValue = (LONGLONG) (* (DWORD *) pData);
|
|
pThisItem->SecondValue = 0;
|
|
break;
|
|
|
|
case PERF_COUNTER_LARGE_RAWCOUNT:
|
|
case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
|
|
case PERF_COUNTER_LARGE_DELTA:
|
|
pThisItem->FirstValue = * (LONGLONG *) pData;
|
|
pThisItem->SecondValue = 0;
|
|
break;
|
|
//
|
|
// These counters use the 100 Ns time base in thier calculation
|
|
//
|
|
case PERF_100NSEC_TIMER:
|
|
case PERF_100NSEC_TIMER_INV:
|
|
case PERF_100NSEC_MULTI_TIMER:
|
|
case PERF_100NSEC_MULTI_TIMER_INV:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pThisItem->FirstValue = * pllData;
|
|
pThisItem->SecondValue = pPerfData->PerfTime100nSec.QuadPart;
|
|
if ((LocalCType & PERF_MULTI_COUNTER) == PERF_MULTI_COUNTER) {
|
|
++ pllData;
|
|
pThisItem->MultiCount = * (DWORD *) pllData;
|
|
}
|
|
break;
|
|
//
|
|
// These counters use two data points, the one pointed to by
|
|
// pData and the one pointed by the definition following
|
|
// immediately after
|
|
//
|
|
case PERF_SAMPLE_FRACTION:
|
|
case PERF_RAW_FRACTION:
|
|
pdwData = (DWORD *) pData;
|
|
pThisItem->FirstValue = (LONGLONG)(* pdwData);
|
|
pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pDenPerfCounter);
|
|
pdwData = (DWORD *) pData;
|
|
pThisItem->SecondValue = (LONGLONG) (* pdwData);
|
|
break;
|
|
|
|
case PERF_LARGE_RAW_FRACTION:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pCounter->ThisValue.FirstValue = * pllData;
|
|
pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pDenPerfCounter);
|
|
if (pData) {
|
|
pllData = (LONGLONG *) pData;
|
|
pCounter->ThisValue.SecondValue = * pllData;
|
|
}
|
|
else {
|
|
pCounter->ThisValue.SecondValue = 0;
|
|
bReturn = FALSE;
|
|
}
|
|
break;
|
|
|
|
case PERF_PRECISION_SYSTEM_TIMER:
|
|
case PERF_PRECISION_100NS_TIMER:
|
|
case PERF_PRECISION_OBJECT_TIMER:
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pThisItem->FirstValue = * pllData;
|
|
// find the pointer to the base value in the structure
|
|
pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pDenPerfCounter);
|
|
pllData = (LONGLONG *) pData;
|
|
pThisItem->SecondValue = * pllData;
|
|
break;
|
|
|
|
case PERF_AVERAGE_TIMER:
|
|
case PERF_AVERAGE_BULK:
|
|
// counter (numerator) is a LONGLONG, while the
|
|
// denominator is just a DWORD
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pThisItem->FirstValue = * pllData;
|
|
pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pDenPerfCounter);
|
|
pdwData = (DWORD *) pData;
|
|
pThisItem->SecondValue = (LONGLONG) * pdwData;
|
|
break;
|
|
//
|
|
// These counters are used as the part of another counter
|
|
// and as such should not be used, but in case they are
|
|
// they'll be handled here.
|
|
//
|
|
case PERF_SAMPLE_BASE:
|
|
case PERF_AVERAGE_BASE:
|
|
case PERF_COUNTER_MULTI_BASE:
|
|
case PERF_RAW_BASE:
|
|
case PERF_LARGE_RAW_BASE:
|
|
pThisItem->FirstValue = 0;
|
|
pThisItem->SecondValue = 0;
|
|
break;
|
|
|
|
case PERF_ELAPSED_TIME:
|
|
// this counter type needs the object perf data as well
|
|
if (GetObjectPerfInfo(pPerfData,
|
|
pCounter->plCounterInfo.dwObjectId,
|
|
& pThisItem->SecondValue,
|
|
& pCounter->TimeBase)) {
|
|
pllData = (UNALIGNED LONGLONG *) pData;
|
|
pThisItem->FirstValue = * pllData;
|
|
}
|
|
else {
|
|
pThisItem->FirstValue = 0;
|
|
pThisItem->SecondValue = 0;
|
|
}
|
|
break;
|
|
//
|
|
// These counters are not supported by this function (yet)
|
|
//
|
|
case PERF_COUNTER_TEXT:
|
|
case PERF_COUNTER_NODATA:
|
|
case PERF_COUNTER_HISTOGRAM_TYPE:
|
|
pThisItem->FirstValue = 0;
|
|
pThisItem->SecondValue = 0;
|
|
break;
|
|
|
|
default:
|
|
// an unrecognized counter type was returned
|
|
pThisItem->FirstValue = 0;
|
|
pThisItem->SecondValue = 0;
|
|
bReturn = FALSE;
|
|
break;
|
|
}
|
|
pThisItem ++; // go to the next entry
|
|
|
|
// go to the next instance data block
|
|
pPerfInstance = NextInstance(pPerfObject, pPerfInstance);
|
|
} // end for each instance
|
|
}
|
|
else {
|
|
// no instance found so ignore
|
|
}
|
|
// measure the memory block used
|
|
dwFinalSize = (DWORD)((LPBYTE)szNextNameString - (LPBYTE) pCounter->pThisRawItemList);
|
|
}
|
|
else {
|
|
// unable to allocate a new buffer so return error
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
pCounter->pThisRawItemList = G_ALLOC(sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK));
|
|
if (pCounter->pThisRawItemList != NULL) {
|
|
pCounter->pThisRawItemList->dwLength = sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK);
|
|
pCounter->pThisRawItemList->dwItemCount = 0;
|
|
pCounter->pThisRawItemList->CStatus = LocalCStatus;
|
|
pCounter->pThisRawItemList->TimeStamp.dwLowDateTime = LODWORD(TimeStamp);
|
|
pCounter->pThisRawItemList->TimeStamp.dwHighDateTime = HIDWORD(TimeStamp);
|
|
}
|
|
else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL
|
|
UpdateRealTimeMultiInstanceCounterValue(
|
|
PPDHI_COUNTER pCounter
|
|
)
|
|
{
|
|
BOOL bResult = TRUE;
|
|
DWORD LocalCStatus = 0;
|
|
|
|
if (pCounter->pThisRawItemList != NULL) {
|
|
// free old counter buffer list
|
|
if (pCounter->pLastRawItemList && pCounter->pLastRawItemList != pCounter->pThisRawItemList) {
|
|
G_FREE(pCounter->pLastRawItemList);
|
|
}
|
|
pCounter->pLastRawItemList = pCounter->pThisRawItemList;
|
|
pCounter->pThisRawItemList = NULL;
|
|
}
|
|
|
|
// don't process if the counter has not been initialized
|
|
if (!(pCounter->dwFlags & PDHIC_COUNTER_UNUSABLE)) {
|
|
|
|
// get the counter's machine status first. There's no point in
|
|
// contuning if the machine is offline
|
|
|
|
LocalCStatus = pCounter->pQMachine->lQueryStatus;
|
|
if (IsSuccessSeverity(LocalCStatus)) {
|
|
bResult = UpdateMultiInstanceCounterValue(pCounter,
|
|
pCounter->pQMachine->pPerfData,
|
|
pCounter->pQMachine->llQueryTime);
|
|
}
|
|
else {
|
|
// unable to read data from this counter's machine so use the
|
|
// query's timestamp
|
|
pCounter->pThisRawItemList = G_ALLOC(sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK));
|
|
if (pCounter->pThisRawItemList != NULL) {
|
|
pCounter->pThisRawItemList->dwLength = sizeof(PDHI_RAW_COUNTER_ITEM_BLOCK);
|
|
pCounter->pThisRawItemList->dwItemCount = 0;
|
|
pCounter->pThisRawItemList->CStatus = LocalCStatus;
|
|
pCounter->pThisRawItemList->TimeStamp.dwLowDateTime = LODWORD(pCounter->pQMachine->llQueryTime);
|
|
pCounter->pThisRawItemList->TimeStamp.dwHighDateTime = HIDWORD(pCounter->pQMachine->llQueryTime);
|
|
}
|
|
else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
bResult = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (pCounter->dwFlags & PDHIC_COUNTER_NOT_INIT) {
|
|
// try to init is
|
|
InitCounter(pCounter);
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
BOOL
|
|
UpdateCounterObject(
|
|
PPDHI_COUNTER pCounter
|
|
)
|
|
{
|
|
BOOL bReturn = TRUE;
|
|
PPERF_OBJECT_TYPE pPerfObject = NULL;
|
|
PPERF_OBJECT_TYPE pLogPerfObj;
|
|
DWORD dwBufferSize = sizeof(PERF_DATA_BLOCK);
|
|
FILETIME ftGmtTime;
|
|
FILETIME ftLocTime;
|
|
|
|
if (pCounter == NULL) {
|
|
SetLastError(PDH_INVALID_ARGUMENT);
|
|
bReturn = FALSE;
|
|
}
|
|
else {
|
|
if (pCounter->pThisObject != NULL) {
|
|
if (pCounter->pLastObject && pCounter->pThisObject != pCounter->pLastObject) {
|
|
G_FREE(pCounter->pLastObject);
|
|
}
|
|
pCounter->pLastObject = pCounter->pThisObject;
|
|
pCounter->pThisObject = NULL;
|
|
}
|
|
|
|
// don't process if the counter has not been initialized
|
|
if (!(pCounter->dwFlags & PDHIC_COUNTER_UNUSABLE)) {
|
|
if (IsSuccessSeverity(pCounter->pQMachine->lQueryStatus)) {
|
|
pPerfObject = GetObjectDefByTitleIndex(pCounter->pQMachine->pPerfData,
|
|
pCounter->plCounterInfo.dwObjectId);
|
|
dwBufferSize = pCounter->pQMachine->pPerfData->HeaderLength;
|
|
dwBufferSize += ((pPerfObject == NULL) ? sizeof(PERF_OBJECT_TYPE) : pPerfObject->TotalByteLength);
|
|
pCounter->pThisObject = G_ALLOC(dwBufferSize);
|
|
if (pCounter->pThisObject != NULL) {
|
|
RtlCopyMemory(pCounter->pThisObject,
|
|
pCounter->pQMachine->pPerfData,
|
|
pCounter->pQMachine->pPerfData->HeaderLength);
|
|
pCounter->pThisObject->TotalByteLength = dwBufferSize;
|
|
pCounter->pThisObject->NumObjectTypes = 1;
|
|
|
|
SystemTimeToFileTime(& pCounter->pThisObject->SystemTime, & ftGmtTime);
|
|
FileTimeToLocalFileTime(& ftGmtTime, & ftLocTime);
|
|
FileTimeToSystemTime(& ftLocTime, & pCounter->pThisObject->SystemTime);
|
|
pLogPerfObj = (PPERF_OBJECT_TYPE)
|
|
((LPBYTE) pCounter->pThisObject + pCounter->pQMachine->pPerfData->HeaderLength);
|
|
if (pPerfObject != NULL) {
|
|
RtlCopyMemory(pLogPerfObj, pPerfObject, pPerfObject->TotalByteLength);
|
|
}
|
|
else {
|
|
ZeroMemory(pLogPerfObj, sizeof(PERF_OBJECT_TYPE));
|
|
pLogPerfObj->TotalByteLength = sizeof(PERF_OBJECT_TYPE);
|
|
pLogPerfObj->DefinitionLength = sizeof(PERF_OBJECT_TYPE);
|
|
pLogPerfObj->HeaderLength = sizeof(PERF_OBJECT_TYPE);
|
|
pLogPerfObj->ObjectNameTitleIndex = pCounter->plCounterInfo.dwObjectId;
|
|
pLogPerfObj->ObjectHelpTitleIndex = pCounter->plCounterInfo.dwObjectId + 1;
|
|
}
|
|
}
|
|
else {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
pCounter->pThisObject = G_ALLOC(sizeof(PERF_DATA_BLOCK));
|
|
if (pCounter->pThisObject == NULL) {
|
|
pCounter->pThisObject = pCounter->pLastObject;
|
|
}
|
|
else {
|
|
pCounter->pThisObject->Signature[0] = L'P';
|
|
pCounter->pThisObject->Signature[1] = L'E';
|
|
pCounter->pThisObject->Signature[2] = L'R';
|
|
pCounter->pThisObject->Signature[3] = L'F';
|
|
pCounter->pThisObject->LittleEndian = TRUE;
|
|
pCounter->pThisObject->Version = PERF_DATA_VERSION;
|
|
pCounter->pThisObject->Revision = PERF_DATA_REVISION;
|
|
pCounter->pThisObject->TotalByteLength = sizeof(PERF_DATA_BLOCK);
|
|
pCounter->pThisObject->NumObjectTypes = 1;
|
|
pCounter->pThisObject->DefaultObject = pCounter->plCounterInfo.dwObjectId;
|
|
pCounter->pThisObject->SystemNameLength = 0;
|
|
pCounter->pThisObject->SystemNameOffset = 0;
|
|
pCounter->pThisObject->HeaderLength = sizeof(PERF_DATA_BLOCK);
|
|
pCounter->pThisObject->PerfTime.QuadPart = 0;
|
|
pCounter->pThisObject->PerfFreq.QuadPart = 0;
|
|
pCounter->pThisObject->PerfTime100nSec.QuadPart = 0;
|
|
GetLocalTime(& pCounter->pThisObject->SystemTime);
|
|
}
|
|
SetLastError(PDH_CSTATUS_INVALID_DATA);
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else {
|
|
if (pCounter->dwFlags & PDHIC_COUNTER_NOT_INIT) {
|
|
InitCounter(pCounter);
|
|
}
|
|
pCounter->pThisObject = pCounter->pLastObject;
|
|
SetLastError(PDH_CSTATUS_INVALID_DATA);
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
PVOID
|
|
GetPerfCounterDataPtr(
|
|
PPERF_DATA_BLOCK pPerfData,
|
|
PPDHI_COUNTER_PATH pPath,
|
|
PPERFLIB_COUNTER pplCtr ,
|
|
DWORD dwFlags,
|
|
PPERF_OBJECT_TYPE *pPerfObjectArg,
|
|
PDWORD pStatus
|
|
)
|
|
{
|
|
PPERF_OBJECT_TYPE pPerfObject = NULL;
|
|
PPERF_INSTANCE_DEFINITION pPerfInstance = NULL;
|
|
PPERF_COUNTER_DEFINITION pPerfCounter = NULL;
|
|
DWORD dwTestValue = 0;
|
|
PVOID pData = NULL;
|
|
DWORD dwCStatus = PDH_CSTATUS_INVALID_DATA;
|
|
|
|
pPerfObject = GetObjectDefByTitleIndex(pPerfData, pplCtr->dwObjectId);
|
|
|
|
if (pPerfObject != NULL) {
|
|
if (pPerfObjectArg != NULL) * pPerfObjectArg = pPerfObject;
|
|
if (pPerfObject->NumInstances == PERF_NO_INSTANCES) {
|
|
// then just look up the counter
|
|
pPerfCounter = GetCounterDefByTitleIndex(pPerfObject,
|
|
((dwFlags & GPCDP_GET_BASE_DATA) ? TRUE : FALSE),
|
|
pplCtr->dwCounterId);
|
|
if (pPerfCounter != NULL) {
|
|
// get data and return it
|
|
pData = GetCounterDataPtr(pPerfObject, pPerfCounter);
|
|
if (pData != NULL) {
|
|
// test the pointer to see if it fails
|
|
__try {
|
|
dwTestValue = * (DWORD *) pData;
|
|
dwCStatus = PDH_CSTATUS_VALID_DATA;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
pData = NULL;
|
|
dwCStatus = PDH_CSTATUS_INVALID_DATA;
|
|
}
|
|
}
|
|
else {
|
|
dwCStatus = PDH_CSTATUS_INVALID_DATA;
|
|
}
|
|
}
|
|
else {
|
|
// unable to find counter
|
|
dwCStatus = PDH_CSTATUS_NO_COUNTER;
|
|
}
|
|
}
|
|
else {
|
|
// find instance
|
|
if (pplCtr->lInstanceId == PERF_NO_UNIQUE_ID && pPath->szInstanceName != NULL) {
|
|
pPerfInstance = GetInstanceByName(pPerfData,
|
|
pPerfObject,
|
|
pPath->szInstanceName,
|
|
pPath->szParentName,
|
|
pPath->dwIndex);
|
|
if (pPerfInstance == NULL && pPath->szInstanceName[0] >= L'0' && pPath->szInstanceName[0] <= L'9') {
|
|
LONG lInstanceId = (LONG) _wtoi(pPath->szInstanceName);
|
|
pPerfInstance = GetInstanceByUniqueId(pPerfObject, lInstanceId);
|
|
}
|
|
}
|
|
else {
|
|
pPerfInstance = GetInstanceByUniqueId(pPerfObject, pplCtr->lInstanceId);
|
|
}
|
|
if (pPerfInstance != NULL) {
|
|
// instance found so find pointer to counter data
|
|
pPerfCounter = GetCounterDefByTitleIndex(pPerfObject,
|
|
((dwFlags & GPCDP_GET_BASE_DATA) ? TRUE : FALSE),
|
|
pplCtr->dwCounterId);
|
|
if (pPerfCounter != NULL) {
|
|
// counter found so get data pointer
|
|
pData = GetInstanceCounterDataPtr(pPerfObject, pPerfInstance, pPerfCounter);
|
|
if (pData != NULL) {
|
|
// test the pointer to see if it's valid
|
|
__try {
|
|
dwTestValue = * (DWORD *) pData;
|
|
dwCStatus = PDH_CSTATUS_VALID_DATA;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
pData = NULL;
|
|
dwCStatus = PDH_CSTATUS_INVALID_DATA;
|
|
}
|
|
}
|
|
else {
|
|
dwCStatus = PDH_CSTATUS_INVALID_DATA;
|
|
}
|
|
}
|
|
else {
|
|
// counter not found
|
|
dwCStatus = PDH_CSTATUS_NO_COUNTER;
|
|
}
|
|
}
|
|
else {
|
|
// instance not found
|
|
dwCStatus = PDH_CSTATUS_NO_INSTANCE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// unable to find object
|
|
dwCStatus = PDH_CSTATUS_NO_OBJECT;
|
|
}
|
|
if (pStatus != NULL) {
|
|
__try {
|
|
* pStatus = dwCStatus;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
// ?
|
|
}
|
|
}
|
|
return pData;
|
|
}
|