Windows-Server-2003/sdktools/pdh/pdhdll/cutils.c

1873 lines
82 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;
}