1806 lines
78 KiB
C
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)
|