Windows2003-3790/sdktools/pdh/pdhdll/counter.c
2020-09-30 16:53:55 +02:00

1806 lines
78 KiB
C

/*++
Copyright (C) 1996-1999 Microsoft Corporation
Module Name:
counter.c
Abstract:
counter processing functions exposed in pdh.dll
--*/
#include <windows.h>
#include <stdlib.h>
#include <math.h>
#include <mbctype.h>
#include "strsafe.h"
#include <pdh.h>
#include "pdhitype.h"
#include "pdhidef.h"
#include "pdhmsg.h"
#include "strings.h"
__inline
DWORD
PdhiGetStringLength(
LPWSTR szString,
BOOL bUnicode
)
{
DWORD dwReturn = 0;
if (bUnicode) {
dwReturn = lstrlenW(szString);
}
else {
dwReturn = WideCharToMultiByte(_getmbcp(), 0, szString, lstrlenW(szString), NULL, 0, NULL, NULL);
}
return dwReturn;
}
STATIC_PDH_FUNCTION
PdhiGetFormattedCounterArray(
PPDHI_COUNTER pCounter,
DWORD dwFormat,
LPDWORD lpdwBufferSize,
LPDWORD lpdwItemCount,
LPVOID ItemBuffer,
BOOL bWideArgs
)
{
PDH_STATUS PdhStatus = ERROR_SUCCESS;
PDH_STATUS PdhFnStatus = ERROR_SUCCESS;
DWORD dwRequiredSize = 0;
WCHAR wszInstanceName[32];
PPDHI_RAW_COUNTER_ITEM pThisItem = NULL;
PPDHI_RAW_COUNTER_ITEM pLastItem = NULL;
PDH_RAW_COUNTER ThisRawCounter;
PDH_RAW_COUNTER LastRawCounter;
LPWSTR szThisItem;
LPWSTR szLastItem;
PPDH_RAW_COUNTER pThisRawCounter;
PPDH_RAW_COUNTER pLastRawCounter;
PPDH_FMT_COUNTERVALUE_ITEM_W pThisFmtItem;
DWORD dwThisItemIndex;
LPWSTR wszNextString;
DWORD dwNameLength;
DWORD dwRetItemCount = 0;
PdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
if (PdhStatus != ERROR_SUCCESS) {
return PdhStatus;
}
// compute required buffer size
if (pCounter->dwFlags & PDHIC_MULTI_INSTANCE) {
if (ItemBuffer != NULL) {
pThisFmtItem = (PPDH_FMT_COUNTERVALUE_ITEM_W) ItemBuffer;
if( pCounter->pThisRawItemList == NULL) {
PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
goto Cleanup;
}
wszNextString = (LPWSTR)((LPBYTE) ItemBuffer + (sizeof (PDH_FMT_COUNTERVALUE_ITEM_W) *
pCounter->pThisRawItemList->dwItemCount));
// verify 8 byte alignment
}
else {
pThisFmtItem = NULL;
wszNextString = NULL;
}
// for multi structs, the buffer required
dwThisItemIndex = 0;
dwRequiredSize += (DWORD)(pCounter->pThisRawItemList->dwItemCount) *
(bWideArgs ? sizeof (PDH_FMT_COUNTERVALUE_ITEM_W) : sizeof (PDH_FMT_COUNTERVALUE_ITEM_A));
for (pThisItem = & (pCounter->pThisRawItemList->pItemArray[0]);
dwThisItemIndex < pCounter->pThisRawItemList->dwItemCount;
dwThisItemIndex ++, pThisItem ++, pLastItem ++) {
szThisItem = (LPWSTR) (((LPBYTE) pCounter->pThisRawItemList) + pThisItem->szName);
if (bWideArgs) {
dwNameLength = lstrlenW(szThisItem) + 1;
dwRequiredSize += dwNameLength * sizeof(WCHAR);
if ((dwRequiredSize <= * lpdwBufferSize) && (wszNextString != NULL)) {
// this is the only field that is type dependent (i.e.
// wide vs ansi chars.
pThisFmtItem->szName = wszNextString;
StringCchCopyW(wszNextString, dwNameLength, szThisItem);
wszNextString += dwNameLength;
PdhStatus = ERROR_SUCCESS;
}
else {
PdhStatus = PDH_MORE_DATA;
}
}
else {
DWORD dwSize = (* lpdwBufferSize < dwRequiredSize) ? (0) : (* lpdwBufferSize - dwRequiredSize);
PdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(), szThisItem, (LPSTR) wszNextString, & dwSize);
if (wszNextString && PdhStatus == ERROR_SUCCESS) {
pThisFmtItem->szName = wszNextString;
wszNextString = (LPWSTR) ((LPSTR) wszNextString + dwSize);
}
dwRequiredSize += (dwSize * sizeof(CHAR));
}
if (PdhStatus == ERROR_SUCCESS) {
//
// COMPUTE FORMATTED VALUE HERE!!!
//
if (pCounter->pThisRawItemList != NULL) {
ThisRawCounter.CStatus = pCounter->pThisRawItemList->CStatus;
ThisRawCounter.TimeStamp = pCounter->pThisRawItemList->TimeStamp;
ThisRawCounter.FirstValue = pThisItem->FirstValue;
ThisRawCounter.SecondValue = pThisItem->SecondValue;
ThisRawCounter.MultiCount = pThisItem->MultiCount;
pThisRawCounter = & ThisRawCounter;
}
else {
ZeroMemory(& ThisRawCounter, sizeof(ThisRawCounter));
pThisRawCounter = NULL;
}
if (pCounter->pLastRawItemList != NULL) {
// test to see if "This" buffer has more entries than "last" buffer
if (dwThisItemIndex < pCounter->pLastRawItemList->dwItemCount) {
pLastItem = &(pCounter->pLastRawItemList->pItemArray[dwThisItemIndex]);
szLastItem = (LPWSTR) (((LPBYTE) pCounter->pLastRawItemList) + pLastItem->szName);
if (lstrcmpiW(szThisItem, szLastItem) == 0) {
// the names match so we'll assume this is the correct instance
LastRawCounter.CStatus = pCounter->pLastRawItemList->CStatus;
LastRawCounter.TimeStamp = pCounter->pLastRawItemList->TimeStamp;
LastRawCounter.FirstValue = pLastItem->FirstValue;
LastRawCounter.SecondValue = pLastItem->SecondValue;
LastRawCounter.MultiCount = pLastItem->MultiCount;
pLastRawCounter = & LastRawCounter;
}
else {
// the names DON'T match so we'll try the calc on just
// one value. This will work for some (e.g. instantaneous)
// counters, but not all
ZeroMemory(& LastRawCounter, sizeof(LastRawCounter));
pLastRawCounter = NULL;
}
}
else {
// the new buffer is larger than the old one so
// we'll try the calc function on just
// one value. This will work for some (e.g. instantaneous)
// counters, but not all
ZeroMemory(& LastRawCounter, sizeof(LastRawCounter));
pLastRawCounter = NULL;
}
}
else {
// there is no "previous" counter entry for this counter
ZeroMemory(& LastRawCounter, sizeof(LastRawCounter));
pLastRawCounter = NULL;
}
PdhFnStatus = PdhiComputeFormattedValue(pCounter->CalcFunc,
pCounter->plCounterInfo.dwCounterType,
pCounter->lScale,
dwFormat,
pThisRawCounter,
pLastRawCounter,
& pCounter->TimeBase,
0L,
& pThisFmtItem->FmtValue);
if (PdhFnStatus != ERROR_SUCCESS) {
// save the last error encountered for return to the caller
PdhStatus = PdhFnStatus;
// error in calculation so set the status for this
// counter item
pThisFmtItem->FmtValue.CStatus = PDH_CSTATUS_INVALID_DATA;
// clear the value
pThisFmtItem->FmtValue.largeValue = 0;
}
// update pointers
pThisFmtItem ++;
}
}
dwRetItemCount = dwThisItemIndex;
}
else {
if (ItemBuffer != NULL) {
pThisFmtItem = (PPDH_FMT_COUNTERVALUE_ITEM_W) ItemBuffer;
wszNextString = (LPWSTR)((LPBYTE)ItemBuffer +
(bWideArgs ? sizeof (PDH_FMT_COUNTERVALUE_ITEM_W) : sizeof (PDH_FMT_COUNTERVALUE_ITEM_A)));
// verify 8 byte alignment
}
else {
pThisFmtItem = NULL;
wszNextString = NULL;
}
// this is a single instance counter so the size required is:
// the size of the instance name +
// the size of the parent name +
// the size of any index parameter +
// the size of the value buffer
//
if (pCounter->pCounterPath->szInstanceName != NULL) {
dwRequiredSize += PdhiGetStringLength(pCounter->pCounterPath->szInstanceName, bWideArgs);
if (pCounter->pCounterPath->szParentName != NULL) {
dwRequiredSize += 1 + PdhiGetStringLength(pCounter->pCounterPath->szParentName, bWideArgs);
}
if (pCounter->pCounterPath->dwIndex > 0) {
double dIndex, dLen;
dIndex = (double) pCounter->pCounterPath->dwIndex; // cast to float
dLen = floor(log10(dIndex)); // get integer log
dwRequiredSize = (DWORD) dLen; // cast to integer
dwRequiredSize += 2; // increment for brackets
}
// add in length of null character
dwRequiredSize += 1;
}
// adjust size of required buffer by size of text character
dwRequiredSize *= ((bWideArgs) ? (sizeof(WCHAR)) : (sizeof(CHAR)));
// add in length of data structure
dwRequiredSize += (bWideArgs ? sizeof(PDH_FMT_COUNTERVALUE_ITEM_W) : sizeof(PDH_FMT_COUNTERVALUE_ITEM_A));
if ((dwRequiredSize <= * lpdwBufferSize) & (wszNextString != NULL)) {
pThisFmtItem->szName = wszNextString;
if (pCounter->pCounterPath->szInstanceName != NULL) {
if (bWideArgs) {
dwNameLength = dwRequiredSize - sizeof(PDH_FMT_COUNTERVALUE_ITEM_W);
if (pCounter->pCounterPath->szParentName != NULL) {
StringCbPrintfW(wszNextString, dwNameLength, L"%ws%ws%ws",
pCounter->pCounterPath->szParentName,
cszSlash,
pCounter->pCounterPath->szInstanceName);
}
else {
StringCbCopyW(wszNextString, dwNameLength, pCounter->pCounterPath->szInstanceName);
}
if (pCounter->pCounterPath->dwIndex > 0) {
_ltow(pCounter->pCounterPath->dwIndex, wszInstanceName, 10);
StringCbCatW(wszNextString, dwNameLength, cszPoundSign);
StringCbCatW(wszNextString, dwNameLength, wszInstanceName);
}
// update pointers
wszNextString += lstrlenW(wszNextString) + 1;
}
else {
if (pCounter->pCounterPath->szParentName != NULL) {
dwNameLength = lstrlenW(pCounter->pCounterPath->szParentName) + 1;
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szParentName,
-1,
(LPSTR) wszNextString,
dwNameLength,
NULL,
NULL);
wszNextString = (LPWSTR) ((LPSTR) wszNextString + lstrlenA((LPSTR) wszNextString));
dwNameLength = lstrlenW(cszSlash) + 1;
WideCharToMultiByte(_getmbcp(),
0,
cszSlash,
-1,
(LPSTR) wszNextString,
dwNameLength,
NULL,
NULL);
wszNextString = (LPWSTR) ((LPSTR) wszNextString + lstrlenA((LPSTR) wszNextString));
}
dwNameLength = lstrlenW(pCounter->pCounterPath->szInstanceName) + 1;
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szInstanceName,
-1,
(LPSTR) wszNextString,
dwNameLength,
NULL,
NULL);
wszNextString = (LPWSTR) ((LPSTR) wszNextString + lstrlenA((LPSTR) wszNextString));
if (pCounter->pCounterPath->dwIndex > 0) {
dwNameLength = dwRequiredSize - sizeof(PDH_FMT_COUNTERVALUE_ITEM_A);
_ltoa(pCounter->pCounterPath->dwIndex, (LPSTR) wszInstanceName, 10);
StringCbCatA((LPSTR) pThisFmtItem->szName, dwNameLength, caszPoundSign);
StringCbCatA((LPSTR) pThisFmtItem->szName, dwNameLength, (LPSTR) wszInstanceName);
}
// null terminate the string
* ((LPSTR) wszNextString) = '\0';
wszNextString = (LPWSTR) ((LPBYTE) wszNextString + 1);
// insure alignment on the appropriate boundry
}
}
else if (bWideArgs) {
* wszNextString = L'\0';
}
else {
* ((LPSTR) wszNextString) = '\0';
}
PdhFnStatus = PdhiComputeFormattedValue(pCounter->CalcFunc,
pCounter->plCounterInfo.dwCounterType,
pCounter->lScale,
dwFormat,
& pCounter->ThisValue,
& pCounter->LastValue,
& pCounter->TimeBase,
0L,
& pThisFmtItem->FmtValue);
if (PdhFnStatus != ERROR_SUCCESS) {
PdhStatus = PdhFnStatus;
// error in calculation so set the status for this
// counter item
pThisFmtItem->FmtValue.CStatus = PDH_CSTATUS_INVALID_DATA;
// clear the value
pThisFmtItem->FmtValue.largeValue = 0;
// and return the status to the caller
}
}
else {
// then this was a real data request so return
PdhStatus = PDH_MORE_DATA;
}
dwRetItemCount = 1;
}
Cleanup:
RELEASE_MUTEX(pCounter->pOwner->hMutex);
if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
// update buffer size and item count buffers
* lpdwBufferSize = dwRequiredSize;
* lpdwItemCount = dwRetItemCount;
}
return PdhStatus;
}
PDH_FUNCTION
PdhGetFormattedCounterArrayA(
IN PDH_HCOUNTER hCounter,
IN DWORD dwFormat,
IN LPDWORD lpdwBufferSize,
IN LPDWORD lpdwItemCount,
IN PPDH_FMT_COUNTERVALUE_ITEM_A ItemBuffer
)
{
PDH_STATUS PdhStatus = ERROR_SUCCESS;
DWORD dwBufferSize;
DWORD dwItemCount;
DWORD dwTest;
LPBYTE pByte;
if (lpdwBufferSize == NULL || lpdwItemCount == NULL) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
else if (! IsValidCounter(hCounter)) {
PdhStatus = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse (hCounter)) {
PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
// validate arguments
__try {
// test argument for Read and Write access
dwBufferSize = * lpdwBufferSize;
// test argument for Read and Write access
dwItemCount = * lpdwItemCount;
if (dwBufferSize > 0) {
// then the buffer must be valid
if (ItemBuffer != NULL) {
// NULL is a valid value for this parameter
// test both ends of the buffer passed in
pByte = (LPBYTE) ItemBuffer;
dwTest = (DWORD) pByte[0];
pByte[0] = 0;
pByte[0] = (BYTE) (dwTest & 0x000000FF);
dwTest = (DWORD) pByte[dwBufferSize -1];
pByte[dwBufferSize -1] = 0;
pByte[dwBufferSize -1] = (BYTE) (dwTest & 0x000000FF);
}
else {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
// check for disallowed format options
if ((dwFormat & PDH_FMT_RAW) || (dwFormat & PDH_FMT_ANSI) ||
(dwFormat & PDH_FMT_UNICODE) || (dwFormat & PDH_FMT_NODATA)) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (PdhStatus == ERROR_SUCCESS) {
PdhStatus = PdhiGetFormattedCounterArray((PPDHI_COUNTER) hCounter,
dwFormat,
& dwBufferSize,
& dwItemCount,
(LPVOID) ItemBuffer,
FALSE);
}
if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
__try {
* lpdwBufferSize = dwBufferSize;
* lpdwItemCount = dwItemCount;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
return PdhStatus;
}
PDH_FUNCTION
PdhGetFormattedCounterArrayW(
IN PDH_HCOUNTER hCounter,
IN DWORD dwFormat,
IN LPDWORD lpdwBufferSize,
IN LPDWORD lpdwItemCount,
IN PPDH_FMT_COUNTERVALUE_ITEM_W ItemBuffer
)
{
PDH_STATUS PdhStatus = ERROR_SUCCESS;
DWORD dwBufferSize;
DWORD dwItemCount;
DWORD dwTest;
LPBYTE pByte;
if (lpdwBufferSize == NULL || lpdwItemCount == NULL) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
else if (! IsValidCounter(hCounter)) {
PdhStatus = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse (hCounter)) {
PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
// validate arguments
__try {
// test argument for Read and Write access
dwBufferSize = * lpdwBufferSize;
// test argument for Read and Write access
dwItemCount = * lpdwItemCount;
if (dwBufferSize > 0) {
// then the buffer must be valid
if (ItemBuffer != NULL) {
// NULL is a valid value for this parameter
// test both ends of the buffer passed in
pByte = (LPBYTE) ItemBuffer;
dwTest = (DWORD) pByte[0];
pByte[0] = 0;
pByte[0] = (BYTE) (dwTest & 0x000000FF);
dwTest = (DWORD) pByte[dwBufferSize -1];
pByte[dwBufferSize -1] = 0;
pByte[dwBufferSize -1] = (BYTE) (dwTest & 0x000000FF);
}
else {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
// check for disallowed format options
if ((dwFormat & PDH_FMT_RAW) || (dwFormat & PDH_FMT_ANSI) ||
(dwFormat & PDH_FMT_UNICODE) || (dwFormat & PDH_FMT_NODATA)) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (PdhStatus == ERROR_SUCCESS) {
PdhStatus = PdhiGetFormattedCounterArray((PPDHI_COUNTER) hCounter,
dwFormat,
& dwBufferSize,
& dwItemCount,
(LPVOID) ItemBuffer,
TRUE);
}
if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
__try {
* lpdwBufferSize = dwBufferSize;
* lpdwItemCount = dwItemCount;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
return PdhStatus;
}
STATIC_PDH_FUNCTION
PdhiGetRawCounterArray(
PPDHI_COUNTER pCounter,
LPDWORD lpdwBufferSize,
LPDWORD lpdwItemCount,
LPVOID ItemBuffer,
BOOL bWideArgs
)
{
PDH_STATUS PdhStatus = ERROR_SUCCESS;
DWORD dwRequiredSize = 0;
WCHAR wszInstanceName[32];
PPDHI_RAW_COUNTER_ITEM pThisItem;
LPWSTR szThisItem;
PPDH_RAW_COUNTER_ITEM_W pThisRawItem;
DWORD dwThisItemIndex;
LPWSTR wszNextString;
DWORD dwNameLength;
DWORD dwRetItemCount = 0;
PdhStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
if (PdhStatus != ERROR_SUCCESS) {
return PdhStatus;
}
// compute required buffer size
if (pCounter->dwFlags & PDHIC_MULTI_INSTANCE) {
if (ItemBuffer != NULL) {
pThisRawItem = (PPDH_RAW_COUNTER_ITEM_W) ItemBuffer;
wszNextString = (LPWSTR)((LPBYTE)ItemBuffer + (sizeof(PDH_RAW_COUNTER_ITEM_W) *
pCounter->pThisRawItemList->dwItemCount));
// verify 8 byte alignment
}
else {
pThisRawItem = NULL;
wszNextString = NULL;
}
// for multi structs, the buffer required
dwThisItemIndex = 0;
dwRequiredSize += pCounter->pThisRawItemList->dwItemCount *
(bWideArgs ? sizeof (PDH_RAW_COUNTER_ITEM_W) : sizeof (PDH_RAW_COUNTER_ITEM_A));
for (pThisItem = &(pCounter->pThisRawItemList->pItemArray[0]);
dwThisItemIndex < pCounter->pThisRawItemList->dwItemCount;
dwThisItemIndex ++, pThisItem ++) {
szThisItem = (LPWSTR) (((LPBYTE) pCounter->pThisRawItemList) + pThisItem->szName);
if (pThisRawItem != NULL) {
pThisRawItem->szName = wszNextString;
}
else {
PdhStatus = PDH_MORE_DATA;
}
if (bWideArgs) {
dwNameLength = lstrlenW(szThisItem) + 1;
dwRequiredSize += dwNameLength * sizeof(WCHAR);
if ((dwRequiredSize <= * lpdwBufferSize) && (wszNextString != NULL)) {
StringCchCopyW(wszNextString, dwNameLength, szThisItem);
wszNextString += dwNameLength;
}
else {
PdhStatus = PDH_MORE_DATA;
if (pThisRawItem != NULL) pThisRawItem->szName = NULL;
}
}
else {
dwNameLength = (dwRequiredSize <= * lpdwBufferSize) ? (* lpdwBufferSize - dwRequiredSize) : (0);
PdhStatus = PdhiConvertUnicodeToAnsi(_getmbcp(), szThisItem, (LPSTR) wszNextString, & dwNameLength);
if (PdhStatus == ERROR_SUCCESS) {
wszNextString = (LPWSTR) (((LPSTR) wszNextString) + dwNameLength);
}
else if (pThisRawItem != NULL) {
pThisRawItem->szName = NULL;
}
dwRequiredSize += (dwNameLength * sizeof(CHAR));
}
if (PdhStatus == ERROR_SUCCESS) {
pThisRawItem->RawValue.CStatus = pCounter->pThisRawItemList->CStatus;
pThisRawItem->RawValue.TimeStamp = pCounter->pThisRawItemList->TimeStamp;
pThisRawItem->RawValue.FirstValue = pThisItem->FirstValue;
pThisRawItem->RawValue.SecondValue = pThisItem->SecondValue;
pThisRawItem->RawValue.MultiCount = pThisItem->MultiCount;
// update pointers
pThisRawItem ++;
}
}
dwRetItemCount = dwThisItemIndex;
}
else {
if (ItemBuffer != NULL) {
pThisRawItem = (PPDH_RAW_COUNTER_ITEM_W)ItemBuffer;
wszNextString = (LPWSTR)((LPBYTE)ItemBuffer +
(bWideArgs ? sizeof (PDH_RAW_COUNTER_ITEM_W) : sizeof (PDH_RAW_COUNTER_ITEM_A)));
// verify 8 byte alignment
}
else {
pThisRawItem = NULL;
wszNextString = NULL;
}
// this is a single instance counter so the size required is:
// the size of the instance name +
// the size of the parent name +
// the size of any index parameter +
// the size of the value buffer
//
if (pCounter->pCounterPath->szInstanceName != NULL) {
dwRequiredSize += PdhiGetStringLength(pCounter->pCounterPath->szInstanceName, bWideArgs);
if (pCounter->pCounterPath->szParentName != NULL) {
dwRequiredSize += 1 + PdhiGetStringLength(pCounter->pCounterPath->szParentName, bWideArgs);
}
if (pCounter->pCounterPath->dwIndex > 0) {
double dIndex, dLen;
dIndex = (double)pCounter->pCounterPath->dwIndex; // cast to float
dLen = floor(log10(dIndex)); // get integer log
dwRequiredSize = (DWORD)dLen; // cast to integer
dwRequiredSize += 1; // increment for pound sign
}
// add in length of two null characters
// this still has to look like an MSZ even if there is
// is only one string in the buffer
dwRequiredSize += 1;
}
// adjust size of required buffer by size of text character
dwRequiredSize *= ((bWideArgs) ? (sizeof(WCHAR)) : (sizeof(CHAR)));
// add in length of data structure
dwRequiredSize += (bWideArgs ? sizeof (PDH_RAW_COUNTER_ITEM_W) : sizeof (PDH_RAW_COUNTER_ITEM_A));
if ((dwRequiredSize <= * lpdwBufferSize) && (wszNextString != NULL)) {
pThisRawItem->szName = wszNextString;
if (pCounter->pCounterPath->szInstanceName != NULL) {
if (bWideArgs) {
dwNameLength = dwRequiredSize - sizeof(PDH_RAW_COUNTER_ITEM_W);
if (pCounter->pCounterPath->szParentName != NULL) {
StringCbPrintfW(wszNextString, dwNameLength, L"%ws%ws%ws",
pCounter->pCounterPath->szParentName,
cszSlash,
pCounter->pCounterPath->szInstanceName);
}
else {
StringCbCopyW(wszNextString, dwNameLength, pCounter->pCounterPath->szInstanceName);
}
if (pCounter->pCounterPath->dwIndex > 0) {
_ltow (pCounter->pCounterPath->dwIndex, wszInstanceName, 10);
StringCbCatW(wszNextString, dwNameLength, cszPoundSign);
StringCbCatW(wszNextString, dwNameLength, wszInstanceName);
}
dwNameLength = lstrlenW(pThisRawItem->szName) + 1;
wszNextString += dwNameLength;
}
else {
if (pCounter->pCounterPath->szParentName != NULL) {
dwNameLength = lstrlenW(pCounter->pCounterPath->szParentName) + 1;
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szParentName,
-1,
(LPSTR) wszNextString,
dwNameLength,
NULL,
NULL);
wszNextString = (LPWSTR) ((LPSTR) wszNextString + lstrlenA((LPSTR) wszNextString));
dwNameLength = lstrlenW(cszSlash) + 1;
WideCharToMultiByte(_getmbcp(),
0,
cszSlash,
-1,
(LPSTR) wszNextString,
dwNameLength,
NULL,
NULL);
wszNextString = (LPWSTR) ((LPSTR) wszNextString + lstrlenA((LPSTR) wszNextString));
}
dwNameLength = lstrlenW(pCounter->pCounterPath->szInstanceName) + 1;
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szInstanceName,
-1,
(LPSTR) wszNextString,
dwNameLength,
NULL,
NULL);
wszNextString = (LPWSTR) ((LPSTR) wszNextString + lstrlenA((LPSTR) wszNextString));
if (pCounter->pCounterPath->dwIndex > 0) {
dwNameLength = dwRequiredSize - sizeof(PDH_FMT_COUNTERVALUE_ITEM_A);
_ltoa (pCounter->pCounterPath->dwIndex, (LPSTR)wszInstanceName, 10);
StringCbCatA((LPSTR) wszNextString, dwNameLength, caszPoundSign);
StringCbCatA((LPSTR) wszNextString, dwNameLength, (LPSTR) wszInstanceName);
dwNameLength = lstrlenA((LPSTR) wszNextString) + 1;
wszNextString = (LPWSTR)((LPSTR) wszNextString + dwNameLength);
}
// null terminate the string
* ((LPSTR) wszNextString) = '\0';
wszNextString = (LPWSTR) ((LPBYTE) wszNextString + 1);
}
}
else if (bWideArgs) {
* wszNextString = L'\0';
}
else {
* ((LPSTR) wszNextString) = '\0';
}
pThisRawItem->RawValue = pCounter->ThisValue;
}
else {
// then this was a real data request so return
PdhStatus = PDH_MORE_DATA;
}
dwRetItemCount = 1;
}
RELEASE_MUTEX(pCounter->pOwner->hMutex);
if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
// update buffer size and item count buffers
* lpdwBufferSize = dwRequiredSize;
* lpdwItemCount = dwRetItemCount;
}
return PdhStatus;
}
PDH_FUNCTION
PdhGetRawCounterArrayA(
IN PDH_HCOUNTER hCounter,
IN LPDWORD lpdwBufferSize,
IN LPDWORD lpdwItemCount,
IN PPDH_RAW_COUNTER_ITEM_A ItemBuffer
)
{
PDH_STATUS PdhStatus = ERROR_SUCCESS;
DWORD dwBufferSize;
DWORD dwItemCount;
DWORD dwTest;
LPBYTE pByte;
if (lpdwBufferSize == NULL || lpdwItemCount == NULL) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
else if (! IsValidCounter(hCounter)) {
PdhStatus = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse (hCounter)) {
PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
} else {
// validate arguments
__try {
// test argument for Read and Write access
dwBufferSize = * lpdwBufferSize;
// test argument for Read and Write access
dwItemCount = * lpdwItemCount;
if (dwBufferSize > 0) {
if (ItemBuffer != NULL) {
// NULL is a valid value for this parameter
// test both ends of the buffer passed in
pByte = (LPBYTE) ItemBuffer;
dwTest = (DWORD) pByte[0];
pByte[0] = 0;
pByte[0] = (BYTE) (dwTest & 0x000000FF);
dwTest = (DWORD) pByte[dwBufferSize -1];
pByte[dwBufferSize -1] = 0;
pByte[dwBufferSize -1] = (BYTE) (dwTest & 0x000000FF);
}
else {
// if the buffer size is > 0, then a pointer
// must be non-null & valid
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (PdhStatus == ERROR_SUCCESS) {
PdhStatus = PdhiGetRawCounterArray((PPDHI_COUNTER) hCounter,
& dwBufferSize,
& dwItemCount,
(LPVOID) ItemBuffer,
FALSE);
}
if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
__try {
* lpdwBufferSize = dwBufferSize;
* lpdwItemCount = dwItemCount;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
return PdhStatus;
}
PDH_FUNCTION
PdhGetRawCounterArrayW(
IN PDH_HCOUNTER hCounter,
IN LPDWORD lpdwBufferSize,
IN LPDWORD lpdwItemCount,
IN PPDH_RAW_COUNTER_ITEM_W ItemBuffer
)
{
PDH_STATUS PdhStatus = ERROR_SUCCESS;
DWORD dwBufferSize;
DWORD dwItemCount;
DWORD dwTest;
LPBYTE pByte;
// TODO: Post W2K1 Capture lpdw* to local variables. Capture ItemBuffer
if (lpdwBufferSize == NULL || lpdwItemCount == NULL) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
else if (! IsValidCounter(hCounter)) {
PdhStatus = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse (hCounter)) {
PdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
// validate arguments
__try {
// test argument for Read and Write access
dwBufferSize = * lpdwBufferSize;
// test argument for Read and Write access
dwItemCount = * lpdwItemCount;
if (dwBufferSize > 0) {
if (ItemBuffer != NULL) {
// NULL is a valid value for this parameter
// test both ends of the buffer passed in
pByte = (LPBYTE) ItemBuffer;
dwTest = (DWORD) pByte[0];
pByte[0] = 0;
pByte[0] = (BYTE) (dwTest & 0x000000FF);
dwTest = (DWORD) pByte[dwBufferSize -1];
pByte[dwBufferSize -1] = 0;
pByte[dwBufferSize -1] = (BYTE) (dwTest & 0x000000FF);
}
else {
// if the buffer size is > 0, then a pointer
// must be non-null & valid
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
if (PdhStatus == ERROR_SUCCESS) {
PdhStatus = PdhiGetRawCounterArray((PPDHI_COUNTER) hCounter,
& dwBufferSize,
& dwItemCount,
(LPVOID) ItemBuffer,
TRUE);
}
if (PdhStatus == ERROR_SUCCESS || PdhStatus == PDH_MORE_DATA) {
__try {
* lpdwBufferSize = dwBufferSize;
* lpdwItemCount = dwItemCount;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
PdhStatus = PDH_INVALID_ARGUMENT;
}
}
return PdhStatus;
}
PDH_FUNCTION
PdhGetFormattedCounterValue(
IN PDH_HCOUNTER hCounter,
IN DWORD dwFormat,
IN LPDWORD lpdwType,
IN PPDH_FMT_COUNTERVALUE pValue
)
/*++
Routine Description:
Function to retrieve, computer and format the specified counter's
current value. The values used are those currently in the counter
buffer. (The data is not collected by this routine.)
Arguments:
IN HCOUNTER hCounter
the handle to the counter whose value should be returned
IN DWORD dwFormat
the format flags that define how the counter value should be
formatted prior for return. These flags are defined in the
PDH.H header file.
IN LPDWORD lpdwType
an optional buffer in which the counter type value can be returned.
For the prototype, the flag values are defined in WINPERF.H
IN PPDH_FMT_COUNTERVALUE pValue
the pointer to the data buffer passed by the caller to receive
the data requested.
Return Value:
The WIN32 Error status of the function's operation. Common values
returned are:
ERROR_SUCCESS when all requested data is returned
PDH_INVALID_HANDLE if the handle is not recognized as valid
PDH_INVALID_ARGUMENT if an argument is not correct or is
incorrectly formatted.
PDH_INVALID_DATA if the counter does not contain valid data
or a successful status code
--*/
{
PPDHI_COUNTER pCounter;
PDH_STATUS lStatus = ERROR_SUCCESS;
PDH_FMT_COUNTERVALUE LocalCounterValue;
DWORD dwTypeMask;
// TODO: Why bother with testing for NON-NULL stuff in mutex?
// Check for obvious lpdwType != NULL & pValue != NULL before mutex.
if (pValue == NULL) {
lStatus = PDH_INVALID_ARGUMENT;
}
else {
__try {
pValue->CStatus = (DWORD) -1;
pValue->longValue = (LONGLONG) 0;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
lStatus = PDH_INVALID_ARGUMENT;
}
}
if (lStatus == ERROR_SUCCESS) {
lStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
if (lStatus == ERROR_SUCCESS) {
if (! IsValidCounter(hCounter)) {
lStatus = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse(hCounter)) {
lStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
// validate format flags:
// only one of the following can be set at a time
dwTypeMask = dwFormat & (PDH_FMT_LONG | PDH_FMT_DOUBLE | PDH_FMT_LARGE);
if (! ((dwTypeMask == PDH_FMT_LONG) || (dwTypeMask == PDH_FMT_DOUBLE) ||
(dwTypeMask == PDH_FMT_LARGE))) {
lStatus = PDH_INVALID_ARGUMENT;
}
}
if (lStatus == ERROR_SUCCESS) {
// get counter pointer
pCounter = (PPDHI_COUNTER) hCounter;
// lock query while reading the data
lStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
if (lStatus == ERROR_SUCCESS) {
// compute and format current value
lStatus = PdhiComputeFormattedValue(pCounter->CalcFunc,
pCounter->plCounterInfo.dwCounterType,
pCounter->lScale,
dwFormat,
& pCounter->ThisValue,
& pCounter->LastValue,
& pCounter->TimeBase,
0L,
& LocalCounterValue);
RELEASE_MUTEX(pCounter->pOwner->hMutex);
__try {
if (lpdwType != NULL) {
* lpdwType = pCounter->plCounterInfo.dwCounterType;
} // NULL is OK, the counter type will not be returned, though
* pValue = LocalCounterValue;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
lStatus = PDH_INVALID_ARGUMENT;
}
}
}
RELEASE_MUTEX (hPdhDataMutex);
}
}
return lStatus;
}
PDH_FUNCTION
PdhGetRawCounterValue(
IN PDH_HCOUNTER hCounter,
IN LPDWORD lpdwType,
IN PPDH_RAW_COUNTER pValue
)
/*++
Routine Description:
Function to retrieve the specified counter's current raw value.
The values used are those currently in the counter
buffer. (The data is not collected by this routine.)
Arguments:
IN HCOUNTER hCounter
the handle to the counter whose value should be returned
IN LPDWORD lpdwType
an optional buffer in which the counter type value can be returned.
This value must be NULL if this info is not desired.
For the prototype, the flag values are defined in WINPERF.H
IN PPDH_RAW_COUNTER pValue
the pointer to the data buffer passed by the caller to receive
the data requested.
Return Value:
The WIN32 Error status of the function's operation. Common values
returned are:
ERROR_SUCCESS when all requested data is returned
PDH_INVALID_HANDLE if the handle is not recognized as valid
PDH_INVALID_ARGUMENT if an argument is formatted incorrectly
--*/
{
PDH_STATUS Status = ERROR_SUCCESS;
PPDHI_COUNTER pCounter;
if (pValue == NULL) {
Status = PDH_INVALID_ARGUMENT;
}
else {
Status = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
if (Status == ERROR_SUCCESS) {
// validate arguments before retrieving the data
if (! IsValidCounter(hCounter)) {
Status = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse(hCounter)) {
Status = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
// the handle is good so try the rest of the args
pCounter = (PPDHI_COUNTER) hCounter;
Status = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
if (Status == ERROR_SUCCESS) {
__try {
// try to write to the arguments passed in
* pValue = pCounter->ThisValue;
if (lpdwType != NULL) {
* lpdwType = pCounter->plCounterInfo.dwCounterType;
} // NULL is OK
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = PDH_INVALID_ARGUMENT;
}
RELEASE_MUTEX(pCounter->pOwner->hMutex);
}
}
RELEASE_MUTEX(hPdhDataMutex);
}
}
return Status;
}
PDH_FUNCTION
PdhCalculateCounterFromRawValue(
IN PDH_HCOUNTER hCounter,
IN DWORD dwFormat,
IN PPDH_RAW_COUNTER rawValue1,
IN PPDH_RAW_COUNTER rawValue2,
IN PPDH_FMT_COUNTERVALUE fmtValue
)
/*++
Routine Description:
Calculates the formatted counter value using the data in the RawValue
buffer in the format requested by the format field using the
calculation functions of the counter type defined by the dwType
field.
Arguments:
IN HCOUNTER hCounter
The handle of the counter to use in order to determine the
calculation functions for interpretation of the raw value buffer
IN DWORD dwFormat
Format in which the requested data should be returned. The
values for this field are described in the PDH.H header
file.
IN PPDH_RAW_COUNTER rawValue1
pointer to the buffer that contains the first raw value structure
IN PPDH_RAW_COUNTER rawValue2
pointer to the buffer that contains the second raw value structure.
This argument may be null if only one value is required for the
computation.
IN PPDH_FMT_COUNTERVALUE fmtValue
the pointer to the data buffer passed by the caller to receive
the data requested. If the counter requires 2 values, (as in the
case of a rate counter), rawValue1 is assumed to be the most
recent value and rawValue2, the older value.
Return Value:
The WIN32 Error status of the function's operation. Common values
returned are:
ERROR_SUCCESS when all requested data is returned
PDH_INVALID_HANDLE if the counter handle is incorrect
PDH_INVALID_ARGUMENT if an argument is incorrect
--*/
{
PDH_STATUS lStatus = ERROR_SUCCESS;
PPDHI_COUNTER pCounter;
DWORD dwTypeMask;
PDH_FMT_COUNTERVALUE pdhLocalCounterValue;
if (fmtValue == NULL) {
lStatus = PDH_INVALID_ARGUMENT;
}
else {
lStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
}
if (lStatus == ERROR_SUCCESS) {
// validate arguments
if (! IsValidCounter(hCounter)) {
lStatus = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse(hCounter)) {
lStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
// the handle is valid so check the rest of the arguments
// validate format flags:
dwTypeMask = dwFormat & (PDH_FMT_LONG | PDH_FMT_DOUBLE | PDH_FMT_LARGE);
// only one of the following can be set at a time
if (! ((dwTypeMask == PDH_FMT_LONG) || (dwTypeMask == PDH_FMT_DOUBLE) || (dwTypeMask == PDH_FMT_LARGE))) {
lStatus = PDH_INVALID_ARGUMENT;
}
}
if (lStatus == ERROR_SUCCESS) {
pCounter = (PPDHI_COUNTER) hCounter;
lStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
if (lStatus == ERROR_SUCCESS) {
__try {
lStatus = PdhiComputeFormattedValue((((PPDHI_COUNTER) hCounter)->CalcFunc),
(((PPDHI_COUNTER) hCounter)->plCounterInfo.dwCounterType),
(((PPDHI_COUNTER) hCounter)->lScale),
dwFormat,
rawValue1,
rawValue2,
&((PPDHI_COUNTER)hCounter)->TimeBase,
0L,
&pdhLocalCounterValue);
* fmtValue = pdhLocalCounterValue;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
lStatus = PDH_INVALID_ARGUMENT;
}
RELEASE_MUTEX(pCounter->pOwner->hMutex);
}
}
RELEASE_MUTEX(hPdhDataMutex);
}
return lStatus;
}
PDH_FUNCTION
PdhComputeCounterStatistics(
IN HCOUNTER hCounter,
IN DWORD dwFormat,
IN DWORD dwFirstEntry,
IN DWORD dwNumEntries,
IN PPDH_RAW_COUNTER lpRawValueArray,
IN PPDH_STATISTICS data
)
/*++
Routine Description:
Reads an array of raw value structures of the counter type specified in
the dwType field, computes the counter values of each and formats
and returns a statistics structure that contains the following
statistical data from the counter information:
Minimum The smallest value of the computed counter values
Maximum The largest value of the computed counter values
Mean The arithmetic mean (average) of the computed values
Median The median value of the computed counter values
Arguments:
IN HCOUNTER hCounter
The handle of the counter to use in order to determine the
calculation functions for interpretation of the raw value buffer
IN DWORD dwFormat
Format in which the requested data should be returned. The
values for this field are described in the PDH.H header
file.
IN DWORD dwNumEntries
the number of raw value entries for the specified counter type
IN PPDH_RAW_COUNTER lpRawValueArray
pointer to the array of raw value entries to be evaluated
IN PPDH_STATISTICS data
the pointer to the data buffer passed by the caller to receive
the data requested.
Return Value:
The WIN32 Error status of the function's operation. Note that the
function can return successfully even though no data was calc-
ulated. The status value in the statistics data buffer must be
tested to insure the data is valid before it's used by an
application. Common values returned are:
ERROR_SUCCESS when all requested data is returned
PDH_INVALID_HANDLE if the counter handle is incorrect
PDH_INVALID_ARGUMENT if an argument is incorrect
--*/
{
PPDHI_COUNTER pCounter;
PDH_STATUS Status = ERROR_SUCCESS;
DWORD dwTypeMask;
if (lpRawValueArray == NULL || data == NULL) {
Status = PDH_INVALID_ARGUMENT;
}
else {
Status = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
}
if (Status == ERROR_SUCCESS) {
if (! IsValidCounter(hCounter)) {
Status = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse(hCounter)) {
Status = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
// counter handle is valid so test the rest of the
// arguments
// validate format flags:
// only one of the following can be set at a time
dwTypeMask = dwFormat & (PDH_FMT_LONG | PDH_FMT_DOUBLE | PDH_FMT_LARGE);
if (! ((dwTypeMask == PDH_FMT_LONG) || (dwTypeMask == PDH_FMT_DOUBLE) || (dwTypeMask == PDH_FMT_LARGE))) {
Status = PDH_INVALID_ARGUMENT;
}
}
if (Status == ERROR_SUCCESS) {
pCounter = (PPDHI_COUNTER) hCounter;
Status = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
if (Status == ERROR_SUCCESS) {
__try {
// we should have read access to the Raw Data
DWORD dwTest = * ((DWORD volatile *) & lpRawValueArray->CStatus);
if (dwFirstEntry >= dwNumEntries) {
Status = PDH_INVALID_ARGUMENT;
}
else {
// call satistical function for this counter
Status = (* pCounter->StatFunc)
(pCounter, dwFormat, dwFirstEntry, dwNumEntries, lpRawValueArray, data);
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = PDH_INVALID_ARGUMENT;
}
RELEASE_MUTEX(pCounter->pOwner->hMutex);
}
}
RELEASE_MUTEX(hPdhDataMutex);
}
return Status;
}
STATIC_PDH_FUNCTION
PdhiGetCounterInfo(
PDH_HCOUNTER hCounter,
BOOLEAN bRetrieveExplainText,
LPDWORD pdwBufferSize,
PPDH_COUNTER_INFO_W lpBuffer,
BOOL bUnicode
)
/*++
Routine Description:
Examines the specified counter and returns the configuration and
status information of the counter.
Arguments:
IN HCOUNTER hCounter
Handle to the desired counter.
IN BOOLEAN bRetrieveExplainText
TRUE will fill in the explain text structure
FALSE will return a null pointer in the explain text
IN LPDWORD pcchBufferSize
The address of the buffer that contains the size of the data buffer
passed by the caller. On entry, the value in the buffer is the
size of the data buffer in bytes. On return, this value is the size
of the buffer returned. If the buffer is not large enough, then
this value is the size that the buffer needs to be in order to
hold the requested data.
IN LPPDH_COUNTER_INFO_W lpBuffer
the pointer to the data buffer passed by the caller to receive
the data requested.
IN BOOL bUnicode
TRUE if wide character strings should be returned
FALSE if ANSI strings should be returned
Return Value:
The WIN32 Error status of the function's operation. Common values
returned are:
ERROR_SUCCESS when all requested data is returned
PDH_MORE_DATA when the buffer passed by the caller is too small
PDH_INVALID_HANDLE if the handle is not recognized as valid
PDH_INVALID_ARGUMENT if an argument is invalid or incorrect
--*/
{
PDH_STATUS Status = ERROR_SUCCESS;
DWORD dwSizeRequired = 0;
DWORD dwPathLength;
DWORD dwMachineLength;
DWORD dwObjectLength;
DWORD dwInstanceLength;
DWORD dwParentLength;
DWORD dwNameLength = 0;
DWORD dwHelpLength = 0;
PPDHI_COUNTER pCounter;
DWORD dwBufferSize = 0;
Status = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
if (Status == ERROR_SUCCESS) {
if (! IsValidCounter(hCounter)) {
Status = PDH_INVALID_HANDLE;
}
else if (! CounterIsOkToUse(hCounter)) {
Status = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
// the counter is valid so test the remaining arguments
__try {
if (pdwBufferSize != NULL) {
// test read & write access
dwBufferSize = * pdwBufferSize;
}
else {
// this cannot be NULL
Status = PDH_INVALID_ARGUMENT;
}
if (Status == ERROR_SUCCESS) {
// test return buffer for write access at
// both ends of the buffer
if (lpBuffer != NULL && dwBufferSize > 0) {
* (LPBYTE) lpBuffer = 0;
((LPBYTE) lpBuffer)[dwBufferSize - 1] = 0;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = PDH_INVALID_ARGUMENT;
}
}
if (Status == ERROR_SUCCESS) {
pCounter = (PPDHI_COUNTER) hCounter;
Status = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
if (Status == ERROR_SUCCESS) {
// check for a "no string" request
if (lpBuffer != NULL && dwBufferSize == sizeof(PDH_COUNTER_INFO_W)) {
// then return all but the strings
// room for the basic structure so load it
lpBuffer->dwLength = dwSizeRequired; // this will be updated later
lpBuffer->dwType = pCounter->plCounterInfo.dwCounterType;
lpBuffer->CVersion = pCounter->CVersion;
lpBuffer->CStatus = pCounter->ThisValue.CStatus;
lpBuffer->lScale = pCounter->lScale;
lpBuffer->lDefaultScale = pCounter->plCounterInfo.lDefaultScale;
lpBuffer->dwUserData = pCounter->dwUserData;
lpBuffer->dwQueryUserData = pCounter->pOwner->dwUserData;
lpBuffer->szFullPath = NULL;
lpBuffer->szMachineName = NULL;
lpBuffer->szObjectName = NULL;
lpBuffer->szInstanceName = NULL;
lpBuffer->szParentInstance = NULL;
lpBuffer->dwInstanceIndex = 0L;
lpBuffer->szCounterName = NULL;
lpBuffer->szExplainText = NULL;
lpBuffer->DataBuffer[0] = 0;
// the size value is ok to leave as is
}
else {
// this is a size/full request so continue
// compute size of data to return
dwSizeRequired = sizeof (PDH_COUNTER_INFO_W) - sizeof(DWORD); // size of struct
// this should already end on a DWORD boundry
dwPathLength = 1 + PdhiGetStringLength(pCounter->szFullName, bUnicode);
dwPathLength *= (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
dwPathLength = DWORD_MULTIPLE(dwPathLength);
dwSizeRequired += dwPathLength;
dwMachineLength = 1 + PdhiGetStringLength(pCounter->pCounterPath->szMachineName, bUnicode);
dwMachineLength *= (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
dwMachineLength = DWORD_MULTIPLE(dwMachineLength);
dwSizeRequired += dwMachineLength;
dwObjectLength = 1 + PdhiGetStringLength(pCounter->pCounterPath->szObjectName, bUnicode);
dwObjectLength *= (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
dwObjectLength = DWORD_MULTIPLE(dwObjectLength);
dwSizeRequired += dwObjectLength;
if (pCounter->pCounterPath->szInstanceName != NULL) {
dwInstanceLength = 1 + PdhiGetStringLength(pCounter->pCounterPath->szInstanceName, bUnicode);
dwInstanceLength *= (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
dwInstanceLength = DWORD_MULTIPLE(dwInstanceLength);
dwSizeRequired += dwInstanceLength;
}
else {
dwInstanceLength = 0;
}
if (pCounter->pCounterPath->szParentName != NULL) {
dwParentLength = 1 + PdhiGetStringLength(pCounter->pCounterPath->szParentName, bUnicode);
dwParentLength *= (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
dwParentLength = DWORD_MULTIPLE(dwParentLength);
dwSizeRequired += dwParentLength;
}
else {
dwParentLength = 0;
}
dwNameLength = 1 + PdhiGetStringLength(pCounter->pCounterPath->szCounterName, bUnicode);
dwNameLength *= (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
dwNameLength = DWORD_MULTIPLE(dwNameLength);
dwSizeRequired += dwNameLength;
if (bRetrieveExplainText) {
if (pCounter->szExplainText != NULL) {
dwHelpLength = 1 + PdhiGetStringLength(pCounter->szExplainText, bUnicode);
dwHelpLength *= (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
dwHelpLength = DWORD_MULTIPLE(dwHelpLength);
dwSizeRequired += dwHelpLength;
}
else {
dwHelpLength = 0;
}
}
if (lpBuffer != NULL && dwSizeRequired <= dwBufferSize) {
// should be enough room in the buffer, so continue
lpBuffer->dwLength = dwSizeRequired;
lpBuffer->dwType = pCounter->plCounterInfo.dwCounterType;
lpBuffer->CVersion = pCounter->CVersion;
lpBuffer->CStatus = pCounter->ThisValue.CStatus;
lpBuffer->lScale = pCounter->lScale;
lpBuffer->lDefaultScale = pCounter->plCounterInfo.lDefaultScale;
lpBuffer->dwUserData = pCounter->dwUserData;
lpBuffer->dwQueryUserData = pCounter->pOwner->dwUserData;
// do string data now
lpBuffer->szFullPath = (LPWSTR)& lpBuffer->DataBuffer[0];
if (bUnicode) {
StringCbCopyW(lpBuffer->szFullPath,
dwPathLength,
pCounter->szFullName);
}
else {
WideCharToMultiByte(_getmbcp(),
0,
pCounter->szFullName,
-1,
(LPSTR) lpBuffer->szFullPath,
dwPathLength,
NULL,
NULL);
}
lpBuffer->szMachineName = (LPWSTR)((LPBYTE) lpBuffer->szFullPath + dwPathLength);
if (bUnicode) {
StringCbCopyW(lpBuffer->szMachineName,
dwMachineLength,
pCounter->pCounterPath->szMachineName);
}
else {
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szMachineName,
-1,
(LPSTR) lpBuffer->szMachineName,
dwMachineLength,
NULL,
NULL);
}
lpBuffer->szObjectName = (LPWSTR)((LPBYTE) lpBuffer->szMachineName + dwMachineLength);
if (bUnicode){
StringCbCopyW(lpBuffer->szObjectName,
dwObjectLength,
pCounter->pCounterPath->szObjectName);
}
else {
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szObjectName,
-1,
(LPSTR) lpBuffer->szObjectName,
dwObjectLength,
NULL,
NULL);
}
lpBuffer->szInstanceName = (LPWSTR)((LPBYTE) lpBuffer->szObjectName + dwObjectLength);
if (dwInstanceLength > 0) {
if (bUnicode) {
StringCbCopyW(lpBuffer->szInstanceName,
dwInstanceLength,
pCounter->pCounterPath->szInstanceName);
}
else {
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szInstanceName,
-1,
(LPSTR) lpBuffer->szInstanceName,
dwInstanceLength,
NULL,
NULL);
}
lpBuffer->szParentInstance = (LPWSTR)((LPBYTE)lpBuffer->szInstanceName + dwInstanceLength);
}
else {
lpBuffer->szParentInstance = lpBuffer->szInstanceName;
lpBuffer->szInstanceName = NULL;
}
if (dwParentLength > 0) {
if (bUnicode) {
StringCbCopyW(lpBuffer->szParentInstance,
dwParentLength,
pCounter->pCounterPath->szParentName);
}
else {
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szParentName,
-1,
(LPSTR) lpBuffer->szParentInstance,
dwParentLength,
NULL,
NULL);
}
lpBuffer->szCounterName = (LPWSTR)((LPBYTE) lpBuffer->szParentInstance + dwParentLength);
}
else {
lpBuffer->szCounterName = lpBuffer->szParentInstance;
lpBuffer->szParentInstance = NULL;
}
lpBuffer->dwInstanceIndex = pCounter->pCounterPath->dwIndex;
if (bUnicode) {
StringCbCopyW(lpBuffer->szCounterName,
dwNameLength,
pCounter->pCounterPath->szCounterName);
}
else {
WideCharToMultiByte(_getmbcp(),
0,
pCounter->pCounterPath->szCounterName,
-1,
(LPSTR) lpBuffer->szCounterName,
dwNameLength,
NULL,
NULL);
}
if ((pCounter->szExplainText != NULL) && bRetrieveExplainText) {
// copy explain text
lpBuffer->szExplainText = (LPWSTR)((LPBYTE) lpBuffer->szCounterName + dwNameLength);
if (bUnicode) {
StringCbCopyW(lpBuffer->szExplainText, dwHelpLength, pCounter->szExplainText);
}
else {
WideCharToMultiByte(_getmbcp(),
0,
pCounter->szExplainText,
-1,
(LPSTR) lpBuffer->szExplainText,
dwHelpLength,
NULL,
NULL);
}
}
else {
lpBuffer->szExplainText = NULL;
}
}
else {
// either way, no data will be transferred
Status = PDH_MORE_DATA;
}
__try {
* pdwBufferSize = dwSizeRequired;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = PDH_INVALID_ARGUMENT;
}
}
RELEASE_MUTEX(pCounter->pOwner->hMutex);
}
}
RELEASE_MUTEX(hPdhDataMutex);
}
return Status;
}
PDH_FUNCTION
PdhGetCounterInfoW(
IN PDH_HCOUNTER hCounter,
IN BOOLEAN bRetrieveExplainText,
IN LPDWORD pdwBufferSize,
IN PPDH_COUNTER_INFO_W lpBuffer
)
/*++
Routine Description:
Examines the specified counter and returns the configuration and
status information of the counter.
Arguments:
IN HCOUNTER hCounter
Handle to the desired counter.
IN BOOLEAN bRetrieveExplainText
TRUE will fill in the explain text structure
FALSE will return a null pointer in the explain text
IN LPDWORD pcchBufferSize
The address of the buffer that contains the size of the data buffer
passed by the caller. On entry, the value in the buffer is the
size of the data buffer in bytes. On return, this value is the size
of the buffer returned. If the buffer is not large enough, then
this value is the size that the buffer needs to be in order to
hold the requested data.
IN LPPDH_COUNTER_INFO_W lpBuffer
the pointer to the data buffer passed by the caller to receive
the data requested.
Return Value:
The WIN32 Error status of the function's operation. Common values
returned are:
ERROR_SUCCESS when all requested data is returned
PDH_MORE_DATA when the buffer passed by the caller is too small
PDH_INVALID_HANDLE if the handle is not recognized as valid
PDH_INVALID_ARGUMENT if an argument is invalid or incorrect
--*/
{
return PdhiGetCounterInfo(hCounter, bRetrieveExplainText, pdwBufferSize, lpBuffer, TRUE);
}
PDH_FUNCTION
PdhGetCounterInfoA(
IN PDH_HCOUNTER hCounter,
IN BOOLEAN bRetrieveExplainText,
IN LPDWORD pdwBufferSize,
IN PPDH_COUNTER_INFO_A lpBuffer
)
/*++
Routine Description:
Examines the specified counter and returns the configuration and
status information of the counter.
Arguments:
IN HCOUNTER hCounter
Handle to the desired counter.
IN BOOLEAN bRetrieveExplainText
TRUE will fill in the explain text structure
FALSE will return a null pointer in the explain text
IN LPDWORD pcchBufferSize
The address of the buffer that contains the size of the data buffer
passed by the caller. On entry, the value in the buffer is the
size of the data buffer in bytes. On return, this value is the size
of the buffer returned. If the buffer is not large enough, then
this value is the size that the buffer needs to be in order to
hold the requested data.
IN LPPDH_COUNTER_INFO_A lpBuffer
the pointer to the data buffer passed by the caller to receive
the data requested.
Return Value:
The WIN32 Error status of the function's operation. Common values
returned are:
ERROR_SUCCESS when all requested data is returned
PDH_MORE_DATA when the buffer passed by the caller is too small
PDH_INVALID_HANDLE if the handle is not recognized as valid
PDH_INVALID_ARGUMENT if an argument is invalid or incorrect
--*/
{
return PdhiGetCounterInfo(hCounter, bRetrieveExplainText, pdwBufferSize, (PPDH_COUNTER_INFO_W) lpBuffer, FALSE);
}
PDH_FUNCTION
PdhSetCounterScaleFactor(
IN PDH_HCOUNTER hCounter,
IN LONG lFactor
)
/*++
Routine Description:
sets the counter multiplication scale factor used in computing formatted
counter values. The legal range of values is -7 to +7 which equates
to a factor of .0000007 to 10,000,000.
Arguments:
IN HCOUNTER hCounter
handle of the counter to update
IN LONG lFactor
integer value of the exponent of the factor (i.e. the multiplier is
10 ** lFactor.)
Return Value:
The WIN32 Error status of the function's operation. Common values
returned are:
ERROR_SUCCESS when all requested data is returned
PDH_INVALID_ARGUMENT if the scale value is out of range
PDH_INVALID_HANDLE if the handle is not recognized as valid
--*/
{
PPDHI_COUNTER pCounter;
PDH_STATUS retStatus = ERROR_SUCCESS;
retStatus = WAIT_FOR_AND_LOCK_MUTEX(hPdhDataMutex);
if (retStatus == ERROR_SUCCESS) {
if (! IsValidCounter(hCounter)) {
// not a valid counter
retStatus = PDH_INVALID_HANDLE;
}
else if (lFactor > PDH_MAX_SCALE || lFactor < PDH_MIN_SCALE) {
retStatus = PDH_INVALID_ARGUMENT;
}
else if (! CounterIsOkToUse(hCounter)) {
retStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
pCounter = (PPDHI_COUNTER) hCounter;
retStatus = WAIT_FOR_AND_LOCK_MUTEX(pCounter->pOwner->hMutex);
if (retStatus == ERROR_SUCCESS) {
__try {
pCounter->lScale = lFactor;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
retStatus = PDH_INVALID_ARGUMENT;
}
RELEASE_MUTEX(pCounter->pOwner->hMutex);
retStatus = ERROR_SUCCESS;
}
}
RELEASE_MUTEX (hPdhDataMutex);
}
return retStatus;
}
#pragma optimize ("", off)
PDH_FUNCTION
PdhGetCounterTimeBase(
IN PDH_HCOUNTER hCounter,
IN LONGLONG * pTimeBase
)
/*++
Routine Description:
retrieves the value of the timebase used in the computation
of the formatted version of this counter.
Arguments:
IN HCOUNTER hCounter
handle of the counter to query
IN LONGLONG pTimeBase
pointer to the longlong value that will receive the value of the
timebase used by the counter. The Timebase is the frequency of the
timer used to measure the specified.
Return Value:
The WIN32 Error status of the function's operation. Common values
returned are:
ERROR_SUCCESS when all requested data is returned
PDH_INVALID_ARGUMENT if the scale value is out of range
PDH_INVALID_HANDLE if the handle is not recognized as valid
--*/
{
PPDHI_COUNTER pCounter;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
if (pTimeBase != NULL) {
if (IsValidCounter(hCounter)) {
if (! CounterIsOkToUse(hCounter)) {
pdhStatus = PDH_CSTATUS_ITEM_NOT_VALIDATED;
}
else {
pCounter = (PPDHI_COUNTER) hCounter;
__try {
* pTimeBase = pCounter->TimeBase;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
pdhStatus = PDH_INVALID_ARGUMENT;
}
}
}
else {
pdhStatus = PDH_INVALID_HANDLE;
}
}
else {
pdhStatus = PDH_INVALID_ARGUMENT;
}
return pdhStatus;
}
#pragma optimize ("", on)