/*++ Copyright (C) 1996-1999 Microsoft Corporation Module Name: counter.c Abstract: counter processing functions exposed in pdh.dll --*/ #include #include #include #include #include "strsafe.h" #include #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)