windows-nt/Source/XPSP1/NT/sdktools/pdh/tests/bvt/perfval.c

2597 lines
93 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
perfval.c
Abstract:
Program to test the extensible counter dll's
Author:
Bob Watson (bobw) 8 Feb 99
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winperf.h>
#include <stdio.h>
#include <stdlib.h>
#include <pdhmsg.h>
#include "strings.h"
#include "perfval.h"
#define MAX_BUF_SIZE ((DWORD)(1024 * 1024))
typedef struct _LOCAL_THREAD_DATA {
LPWSTR szServiceName;
LPWSTR szQueryString;
DWORD dwThreadID;
DWORD dwCycleCount;
DWORD dwLoopCount;
BOOL bTestContents;
BOOL bDisplay;
FILE *pOutput;
LPWSTR *pNameTable;
DWORD dwLastIndex;
} LOCAL_THREAD_DATA, *PLOCAL_THREAD_DATA;
HANDLE hEventLog = NULL;
HANDLE hProcessHeap = NULL;
HANDLE hTestHeap = NULL;
LONG lEventLogLevel = LOG_DEBUG;
LONG lExtCounterTestLevel = EXT_TEST_ALL;
#define PERFVAL_NOCONFIG 0
#define PERFVAL_PASS 1
#define PERFVAL_FAIL 2
#define PERFVAL_TIMEOUT 3
LPCWSTR szContact = (LPCWSTR)L"jenlc";
LPCWSTR szMgrContact = (LPCWSTR)L"jeepang";
LPCWSTR szDevPrime = (LPCWSTR)L"http://ntperformance/perftools/perfctrs.htm";
LPCWSTR szDevAlt= (LPCWSTR)L"jeepang";
LPCWSTR szTestPrime = (LPCWSTR)L"ashokkum";
LPCWSTR szTestAlt = (LPCWSTR)L"a-chrila";
static const WCHAR cszDefaultLangId[] = {L"009"};
static const WCHAR cszNamesKey[] = {L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"};
static const WCHAR cszLastHelp[] = {L"Last Help"};
static const WCHAR cszLastCounter[] = {L"Last Counter"};
static const WCHAR cszVersionName[] = {L"Version"};
static const WCHAR cszCounterName[] = {L"Counter "};
static const WCHAR cszHelpName[] = {L"Explain "};
static const WCHAR cszCounters[] = {L"Counters"};
static const WCHAR cszNotFound[] = {L"*** NOT FOUND ***"};
LPWSTR szTestErrorMessage = NULL;
#define MAX_BUF_SIZE ((DWORD)(1024 * 1024))
#define PERFLIB_TIMER_INTERVAL 200 // 200 ms Timer
static
BOOL
IsMsService (LPCWSTR pServiceName)
{
WCHAR szLocalServiceName[MAX_PATH * 2];
lstrcpyW (szLocalServiceName, pServiceName);
_wcslwr (szLocalServiceName);
// for now this just compares known DLL names. valid as of
// NT v4.0
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"tcpip") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nwlnkspx") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nwlnknb") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nwlnkipx") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nbf") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"remoteaccess") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nm") == 0) return TRUE;
// if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"winsctrs.dll") == 0) return TRUE;
// if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"sfmctrs.dll") == 0) return TRUE;
// if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"atkctrs.dll") == 0) return TRUE;
// NT v5.0
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"perfdisk") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"perfos") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"perfproc") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"perfnet") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"spooler") == 0) return TRUE;
if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"tapisrv") == 0) return TRUE;
return FALSE;
}
DWORD
OpenLibrary (
LPCWSTR szRegistryKey, // service key in registry
EXT_OBJECT **pCreatedObj // structure allocated, init'd and returned by this structure
)
{
DWORD Status = ERROR_SUCCESS;
DWORD dwOpenEvent;
DWORD dwType;
DWORD dwSize;
UINT nErrorMode;
// check to see if the library has already been opened
HKEY hServicesKey = NULL;
HKEY hPerfKey = NULL;
LPWSTR szServiceName;
HKEY hKeyLinkage;
BOOL bUseQueryFn = FALSE;
EXT_OBJECT *pReturnObject = NULL;
EXT_OBJECT *pObj = NULL;
DWORD dwFlags = 0;
DWORD dwKeep;
DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION];
DWORD dwObjIndex = 0;
DWORD dwMemBlockSize = sizeof(EXT_OBJECT);
DWORD dwLinkageStringLen = 0;
CHAR szOpenProcName[MAX_PATH];
CHAR szCollectProcName[MAX_PATH];
CHAR szCloseProcName[MAX_PATH];
WCHAR szLibraryString[MAX_PATH];
WCHAR szLibraryExpPath[MAX_PATH];
WCHAR mszObjectList[MAX_PATH];
WCHAR szLinkageKeyPath[MAX_PATH];
WCHAR szLinkageString[MAX_PATH];
DWORD dwOpenTimeout = 0;
DWORD dwCollectTimeout = 0;
LPWSTR szThisObject;
LPWSTR szThisChar;
LPSTR pNextStringA;
LPWSTR pNextStringW;
WCHAR szServicePath[MAX_PATH];
WCHAR szMutexName[MAX_PATH];
WCHAR szPID[32];
LARGE_INTEGER liStartTime, liEndTime, liFreq;
OPEN_PROC_WAIT_INFO opwInfo;
if (szRegistryKey != NULL) {
lstrcpyW (szServicePath, cszHklmServicesKey);
Status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, szServicePath,
0, KEY_READ, &hServicesKey);
lstrcpyW (szServicePath, szRegistryKey);
lstrcatW (szServicePath, cszPerformance);
Status = RegOpenKeyExW (hServicesKey, szServicePath,
0, KEY_READ, &hPerfKey);
szServiceName = (LPWSTR)szRegistryKey;
// read the performance DLL name
dwType = 0;
dwSize = sizeof(szLibraryString);
memset (szLibraryString, 0, sizeof(szLibraryString));
memset (szLibraryString, 0, sizeof(szLibraryExpPath));
Status = RegQueryValueExW (hPerfKey,
cszDLLValue,
NULL,
&dwType,
(LPBYTE)szLibraryString,
&dwSize);
if (Status == ERROR_SUCCESS) {
if (dwType == REG_EXPAND_SZ) {
// expand any environment vars
dwSize = ExpandEnvironmentStringsW(
szLibraryString,
szLibraryExpPath,
MAX_PATH);
if ((dwSize > MAX_PATH) || (dwSize == 0)) {
Status = ERROR_INVALID_DLL;
} else {
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
}
} else if (dwType == REG_SZ) {
// look for dll and save full file Path
dwSize = SearchPathW (
NULL, // use standard system search path
szLibraryString,
NULL,
MAX_PATH,
szLibraryExpPath,
NULL);
if ((dwSize > MAX_PATH) || (dwSize == 0)) {
Status = ERROR_INVALID_DLL;
} else {
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
}
} else {
Status = ERROR_INVALID_DLL;
}
if (Status == ERROR_SUCCESS) {
// we have the DLL name so get the procedure names
dwType = 0;
dwSize = sizeof(szOpenProcName);
memset (szOpenProcName, 0, sizeof(szOpenProcName));
Status = RegQueryValueExA (hPerfKey,
caszOpenValue,
NULL,
&dwType,
(LPBYTE)szOpenProcName,
&dwSize);
}
if (Status == ERROR_SUCCESS) {
// add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// we have the procedure name so get the timeout value
dwType = 0;
dwSize = sizeof(dwOpenTimeout);
Status = RegQueryValueExW (hPerfKey,
cszOpenTimeout,
NULL,
&dwType,
(LPBYTE)&dwOpenTimeout,
&dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
dwOpenTimeout = 10000;
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
// get next string
dwType = 0;
dwSize = sizeof(szCloseProcName);
memset (szCloseProcName, 0, sizeof(szCloseProcName));
Status = RegQueryValueExA (hPerfKey,
caszCloseValue,
NULL,
&dwType,
(LPBYTE)szCloseProcName,
&dwSize);
}
if (Status == ERROR_SUCCESS) {
// add in size of previous string
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// try to look up the query function which is the
// preferred interface if it's not found, then
// try the collect function name. If that's not found,
// then bail
dwType = 0;
dwSize = sizeof(szCollectProcName);
memset (szCollectProcName, 0, sizeof(szCollectProcName));
Status = RegQueryValueExA (hPerfKey,
caszQueryValue,
NULL,
&dwType,
(LPBYTE)szCollectProcName,
&dwSize);
if (Status == ERROR_SUCCESS) {
// add in size of the Query Function Name
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// get next string
bUseQueryFn = TRUE;
// the query function can support a static object list
// so look it up
} else {
// the QueryFunction wasn't found so look up the
// Collect Function name instead
dwType = 0;
dwSize = sizeof(szCollectProcName);
memset (szCollectProcName, 0, sizeof(szCollectProcName));
Status = RegQueryValueExA (hPerfKey,
caszCollectValue,
NULL,
&dwType,
(LPBYTE)szCollectProcName,
&dwSize);
if (Status == ERROR_SUCCESS) {
// add in size of Collect Function Name
// the size value includes the Term. NULL
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
}
}
if (Status == ERROR_SUCCESS) {
// we have the procedure name so get the timeout value
dwType = 0;
dwSize = sizeof(dwCollectTimeout);
Status = RegQueryValueExW (hPerfKey,
cszCollectTimeout,
NULL,
&dwType,
(LPBYTE)&dwCollectTimeout,
&dwSize);
// if error, then apply default
if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
dwCollectTimeout = 10000;
Status = ERROR_SUCCESS;
}
}
// get the list of supported objects if provided by the registry
dwType = 0;
dwSize = sizeof(mszObjectList);
memset (mszObjectList, 0, sizeof(mszObjectList));
Status = RegQueryValueExW (hPerfKey,
cszObjListValue,
NULL,
&dwType,
(LPBYTE)mszObjectList,
&dwSize);
if (Status == ERROR_SUCCESS) {
if (dwType != REG_MULTI_SZ) {
// convert space delimited list to msz
for (szThisChar = mszObjectList; *szThisChar != 0; szThisChar++) {
if (*szThisChar == L' ') *szThisChar = L'\0';
}
++szThisChar;
*szThisChar = 0; // add MSZ term Null
}
for (szThisObject = mszObjectList, dwObjIndex = 0;
(*szThisObject != 0) && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION);
szThisObject += lstrlenW(szThisObject) + 1) {
dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
dwObjIndex++;
}
if (*szThisObject != 0) {
// BUGBUG: log error idicating too many object ID's are
// in the list.
}
} else {
// reset status since not having this is
// not a showstopper
Status = ERROR_SUCCESS;
}
if (Status == ERROR_SUCCESS) {
dwType = 0;
dwKeep = 0;
dwSize = sizeof(dwKeep);
Status = RegQueryValueExW (hPerfKey,
cszKeepResident,
NULL,
&dwType,
(LPBYTE)&dwKeep,
&dwSize);
if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
if (dwKeep == 1) {
dwFlags |= PERF_EO_KEEP_RESIDENT;
} else {
// no change.
}
} else {
// not fatal, just use the defaults.
Status = ERROR_SUCCESS;
}
}
}
}
if (Status == ERROR_SUCCESS) {
memset (szLinkageString, 0, sizeof(szLinkageString));
lstrcpyW (szLinkageKeyPath, szServiceName);
lstrcatW (szLinkageKeyPath, cszLinkageKey);
Status = RegOpenKeyExW (
hServicesKey,
szLinkageKeyPath,
0L,
KEY_READ,
&hKeyLinkage);
if (Status == ERROR_SUCCESS) {
// look up export value string
dwSize = sizeof(szLinkageString);
dwType = 0;
Status = RegQueryValueExW (
hKeyLinkage,
cszExportValue,
NULL,
&dwType,
(LPBYTE)&szLinkageString,
&dwSize);
if ((Status != ERROR_SUCCESS) ||
((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
// clear buffer
memset (szLinkageString, 0, sizeof(szLinkageString));
dwLinkageStringLen = 0;
// not finding a linkage key is not fatal so correct
// status
Status = ERROR_SUCCESS;
} else {
// add size of linkage string to buffer
// the size value includes the Term. NULL
dwLinkageStringLen = dwSize;
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
}
RegCloseKey (hKeyLinkage);
} else {
// not finding a linkage key is not fatal so correct
// status
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS) {
// add in size of service name
dwSize = lstrlenW (szServiceName);
dwSize += 1;
dwSize *= sizeof(WCHAR);
dwMemBlockSize += DWORD_MULTIPLE(dwSize);
// allocate and initialize a new ext. object block
pReturnObject = (EXT_OBJECT *)HeapAlloc(hTestHeap,
HEAP_ZERO_MEMORY, dwMemBlockSize);
if (pReturnObject != NULL) {
// copy values to new buffer (all others are NULL)
pNextStringA = (LPSTR)&pReturnObject[1];
// copy Open Procedure Name
pReturnObject->szOpenProcName = pNextStringA;
lstrcpyA (pNextStringA, szOpenProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
pReturnObject->dwOpenTimeout = dwOpenTimeout;
// copy collect function or query function, depending
pReturnObject->szCollectProcName = pNextStringA;
lstrcpyA (pNextStringA, szCollectProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
pReturnObject->dwCollectTimeout = dwCollectTimeout;
// copy Close Procedure Name
pReturnObject->szCloseProcName = pNextStringA;
lstrcpyA (pNextStringA, szCloseProcName);
pNextStringA += lstrlenA (pNextStringA) + 1;
pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
// copy Library path
pNextStringW = (LPWSTR)pNextStringA;
pReturnObject->szLibraryName = pNextStringW;
lstrcpyW (pNextStringW, szLibraryExpPath);
pNextStringW += lstrlenW (pNextStringW) + 1;
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
// copy Linkage String if there is one
if (*szLinkageString != 0) {
pReturnObject->szLinkageString = pNextStringW;
memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
// length includes extra NULL char and is in BYTES
pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
}
// copy Service name
pReturnObject->szServiceName = pNextStringW;
lstrcpyW (pNextStringW, szServiceName);
pNextStringW += lstrlenW (pNextStringW) + 1;
pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
// load flags
if (bUseQueryFn) {
dwFlags |= PERF_EO_QUERY_FUNC;
}
pReturnObject->dwFlags = dwFlags;
pReturnObject->hPerfKey = hPerfKey;
// load Object array
if (dwObjIndex > 0) {
pReturnObject->dwNumObjects = dwObjIndex;
memcpy (pReturnObject->dwObjList,
dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0])));
}
pReturnObject->llLastUsedTime = 0;
// create Mutex name
lstrcpyW (szMutexName, szRegistryKey);
lstrcatW (szMutexName, (LPCWSTR)L"_Perf_Library_Lock_PID_");
_ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
lstrcatW (szMutexName, szPID);
pReturnObject->hMutex = CreateMutexW (NULL, FALSE, szMutexName);
} else {
Status = ERROR_OUTOFMEMORY;
}
}
if (Status != ERROR_SUCCESS) {
SetLastError (Status);
if (pReturnObject != NULL) {
// release the new block
HeapFree (hTestHeap, 0, pReturnObject);
}
} else {
if (pReturnObject != NULL) {
pObj = pReturnObject;
// then load library & look up functions
nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS);
pObj->hLibrary = LoadLibraryExW (pObj->szLibraryName,
NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (pObj->hLibrary != NULL) {
// lookup function names
pObj->OpenProc = (OPENPROC)GetProcAddress(
pObj->hLibrary, pObj->szOpenProcName);
if (pObj->OpenProc == NULL) {
wprintf ((LPCWSTR)L"\nOpen Procedure \"%s\" not found in \"%s\"",
pObj->szOpenProcName, pObj->szLibraryName);
}
} else {
// unable to load library
Status = GetLastError();
}
if (Status == ERROR_SUCCESS) {
if (pObj->dwFlags & PERF_EO_QUERY_FUNC) {
pObj->QueryProc = (QUERYPROC)GetProcAddress (
pObj->hLibrary, pObj->szCollectProcName);
pObj->CollectProc = (COLLECTPROC)pObj->QueryProc;
} else {
pObj->CollectProc = (COLLECTPROC)GetProcAddress (
pObj->hLibrary, pObj->szCollectProcName);
pObj->QueryProc = (QUERYPROC)pObj->CollectProc;
}
if (pObj->CollectProc == NULL) {
wprintf ((LPCWSTR)L"\nCollect Procedure \"%s\" not found in \"%s\"",
pObj->szCollectProcName, pObj->szLibraryName);
}
}
if (Status == ERROR_SUCCESS) {
pObj->CloseProc = (CLOSEPROC)GetProcAddress (
pObj->hLibrary, pObj->szCloseProcName);
if (pObj->CloseProc == NULL) {
wprintf ((LPCWSTR)L"\nClose Procedure \"%s\" not found in \"%s\"",
pObj->szCloseProcName, pObj->szLibraryName);
}
}
if (Status == ERROR_SUCCESS) {
__try {
// start timer
opwInfo.pNext = NULL;
opwInfo.szLibraryName = pObj->szLibraryName;
opwInfo.szServiceName = pObj->szServiceName;
opwInfo.dwWaitTime = pObj->dwOpenTimeout;
opwInfo.dwEventMsg = ERROR_TIMEOUT;
opwInfo.pData = (LPVOID)pObj;
WAIT_FOR_AND_LOCK_MUTEX (pObj->hMutex);
QueryPerformanceCounter (&liStartTime);
// call open procedure to initialize DLL
Status = (*pObj->OpenProc)(pObj->szLinkageString);
// release the lock
RELEASE_MUTEX (pObj->hMutex);
// check the result.
if (Status != ERROR_SUCCESS) {
dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE;
} else {
InterlockedIncrement((LONG *)&pObj->dwOpenCount);
QueryPerformanceCounter (&liEndTime);
pObj->llFunctionTime = liEndTime.QuadPart - liStartTime.QuadPart;
pObj->llOpenTime += pObj->llFunctionTime;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
dwOpenEvent = WBEMPERF_OPEN_PROC_EXCEPTION;
}
}
QueryPerformanceFrequency (&liFreq);
pObj->llTimeBase = liFreq.QuadPart;
if (Status != ERROR_SUCCESS) {
// clear fields
pObj->OpenProc = NULL;
pObj->CollectProc = NULL;
pObj->QueryProc = NULL;
pObj->CloseProc = NULL;
if (pObj->hLibrary != NULL) {
FreeLibrary (pObj->hLibrary);
pObj->hLibrary = NULL;
}
} else {
GetSystemTimeAsFileTime ((FILETIME *)&pObj->llLastUsedTime);
}
} // else no buffer returned
*pCreatedObj = pObj;
}
if (hServicesKey != NULL) RegCloseKey (hServicesKey);
} else {
Status = ERROR_INVALID_PARAMETER;
}
return Status;
}
//***************************************************************************
//
// CollectData (LPBYTE pBuffer,
// LPDWORD pdwBufferSize,
// LPWSTR pszItemList)
//
// Collects data from the perf objects and libraries added to the access
// object
//
// Inputs:
//
// pBuffer - pointer to start of data block
// where data is being collected
//
// pdwBufferSize - pointer to size of data buffer
//
// pszItemList - string to pass to ext DLL
//
// Outputs:
//
// *lppDataDefinition - set to location for next Type
// Definition if successful
//
// Returns:
//
// 0 if successful, else Win 32 error code of failure
//
//
//***************************************************************************
//
DWORD
CollectData (EXT_OBJECT *pThisExtObj,
LPBYTE pBuffer,
LPDWORD pdwBufferSize,
LPCWSTR pszItemList
)
{
LPWSTR lpValueName = NULL;
LPBYTE lpData = pBuffer;
LPDWORD lpcbData = pdwBufferSize;
LPVOID lpDataDefinition = pBuffer;
DWORD Win32Error=ERROR_SUCCESS; // Failure code
DWORD BytesLeft;
DWORD InitialBytesLeft = 0;
DWORD NumObjectTypes;
LPVOID lpExtDataBuffer = NULL;
LPVOID lpCallBuffer = NULL;
LPVOID lpLowGuardPage = NULL;
LPVOID lpHiGuardPage = NULL;
LPVOID lpEndPointer = NULL;
LPVOID lpBufferBefore = NULL;
LPVOID lpBufferAfter = NULL;
LPDWORD lpCheckPointer;
LARGE_INTEGER liStartTime = {0,0};
LARGE_INTEGER liEndTime = {0,0};
HANDLE hPerflibFuncTimer;
OPEN_PROC_WAIT_INFO opwInfo;
BOOL bGuardPageOK;
BOOL bBufferOK;
BOOL bException;
BOOL bUseSafeBuffer = TRUE;
BOOL bUnlockObjData = FALSE;
LONG lReturnValue = ERROR_SUCCESS;
LONG lInstIndex;
PERF_OBJECT_TYPE *pObject, *pNextObject;
PERF_INSTANCE_DEFINITION *pInstance;
PERF_DATA_BLOCK *pPerfData;
BOOL bForeignDataBuffer;
DWORD dwObjectBufSize;
DWORD dwIndex;
DOUBLE dMs;
// use the one passed by the caller
lpValueName = (LPWSTR)pszItemList;
// initialize values to pass to the extensible counter function
NumObjectTypes = 0;
BytesLeft = (DWORD) (*lpcbData - ((LPBYTE)lpDataDefinition - lpData));
bException = FALSE;
// allocate a local block of memory to pass to the
// extensible counter function.
if (bUseSafeBuffer) {
lpExtDataBuffer = HeapAlloc (hTestHeap,
HEAP_ZERO_MEMORY, BytesLeft + (2*GUARD_PAGE_SIZE));
} else {
lpExtDataBuffer =
lpCallBuffer = lpDataDefinition;
}
if (lpExtDataBuffer != NULL) {
if (bUseSafeBuffer) {
// set buffer pointers
lpLowGuardPage = lpExtDataBuffer;
lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE;
lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft;
lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE;
lpBufferBefore = lpCallBuffer;
lpBufferAfter = NULL;
// initialize GuardPage Data
memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
}
__try {
//
// Collect data from extesible objects
//
hPerflibFuncTimer = NULL;
bUnlockObjData = FALSE;
if (pThisExtObj->hMutex != NULL) {
Win32Error = WaitForSingleObject (
pThisExtObj->hMutex,
pThisExtObj->dwCollectTimeout);
if ((Win32Error != WAIT_TIMEOUT) &&
(pThisExtObj->CollectProc != NULL)) {
bUnlockObjData = TRUE;
opwInfo.pNext = NULL;
opwInfo.szLibraryName = pThisExtObj->szLibraryName;
opwInfo.szServiceName = pThisExtObj->szServiceName;
opwInfo.dwWaitTime = pThisExtObj->dwCollectTimeout;
opwInfo.dwEventMsg = ERROR_TIMEOUT;
opwInfo.pData = (LPVOID)pThisExtObj;
InitialBytesLeft = BytesLeft;
QueryPerformanceCounter (&liStartTime);
Win32Error = (*pThisExtObj->CollectProc) (
lpValueName,
&lpCallBuffer,
&BytesLeft,
&NumObjectTypes);
QueryPerformanceCounter (&liEndTime);
GetSystemTimeAsFileTime(
(FILETIME*)&pThisExtObj->llLastUsedTime);
ReleaseMutex (pThisExtObj->hMutex);
bUnlockObjData = FALSE;
} else {
pThisExtObj->dwLockoutCount++;
}
} else {
Win32Error = ERROR_LOCK_FAILED;
}
if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) {
if (BytesLeft > InitialBytesLeft) {
pThisExtObj->dwBufferSizeErrors++;
// memory error
Win32Error = ERROR_INVALID_PARAMETER;
}
// increment perf counters
InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount);
pThisExtObj->llFunctionTime = liEndTime.QuadPart - liStartTime.QuadPart;
pThisExtObj->llCollectTime += pThisExtObj->llFunctionTime;
// check the time spent in this function
dMs = (DOUBLE)pThisExtObj->llFunctionTime;
dMs /= (DOUBLE)pThisExtObj->llTimeBase;
dMs *= 1000.0;
if (dMs > (DOUBLE)pThisExtObj->dwCollectTimeout) {
Win32Error = ERROR_TIMEOUT;
} else if (BytesLeft & 0x00000007) {
pThisExtObj->dwAlignmentErrors++;
Win32Error = ERROR_INVALID_DATA;
}
pThisExtObj->dwNumObjectsRet = NumObjectTypes;
pThisExtObj->dwRetBufSize = BytesLeft;
if ((bUseSafeBuffer) && (Win32Error == ERROR_SUCCESS)) {
// a data buffer was returned and
// the function returned OK so see how things
// turned out...
//
lpBufferAfter = lpCallBuffer;
//
// check for buffer corruption here
//
bBufferOK = TRUE; // assume it's ok until a check fails
//
if (lExtCounterTestLevel <= EXT_TEST_BASIC) {
//
// check 1: bytes left should be the same as
// new data buffer ptr - orig data buffer ptr
//
if (BytesLeft != (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore)) {
pThisExtObj->dwBadPointers++;
// we'll keep the buffer, since the returned bytes left
// value is ignored anyway, in order to make the
// rest of this function work, we'll fix it here
BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
Win32Error = ERROR_INVALID_DATA;
}
//
// check 2: buffer after ptr should be < hi Guard page ptr
//
if (((LPBYTE)lpBufferAfter >= (LPBYTE)lpHiGuardPage) && bBufferOK) {
// see if they exceeded the allocated memory
if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) {
pThisExtObj->dwBufferSizeErrors++;
bBufferOK = FALSE;
// since the DLL overran the buffer, the buffer
// must be too small (no comments about the DLL
// will be made here) so the status will be
// changed to ERROR_MORE_DATA and the function
// will return.
Win32Error = ERROR_INVALID_DATA;
}
}
//
// check 3: check lo guard page for corruption
//
if (bBufferOK) {
bGuardPageOK = TRUE;
for (lpCheckPointer = (LPDWORD)lpLowGuardPage;
lpCheckPointer < (LPDWORD)lpBufferBefore;
lpCheckPointer++) {
if (*lpCheckPointer != GUARD_PAGE_DWORD) {
bGuardPageOK = FALSE;
break;
}
}
if (!bGuardPageOK) {
pThisExtObj->dwLowerGPViolations++;
Win32Error = ERROR_INVALID_DATA;
bBufferOK = FALSE;
}
}
//
// check 4: check hi guard page for corruption
//
if (bBufferOK) {
bGuardPageOK = TRUE;
for (lpCheckPointer = (LPDWORD)lpHiGuardPage;
lpCheckPointer < (LPDWORD)lpEndPointer;
lpCheckPointer++) {
if (*lpCheckPointer != GUARD_PAGE_DWORD) {
bGuardPageOK = FALSE;
break;
}
}
if (!bGuardPageOK) {
pThisExtObj->dwUpperGPViolations++;
bBufferOK = FALSE;
Win32Error = ERROR_INVALID_DATA;
}
}
//
if ((lExtCounterTestLevel <= EXT_TEST_ALL) && bBufferOK) {
//
// Internal consistency checks
//
//
// Check 5: Check object length field values
//
// first test to see if this is a foreign
// computer data block or not
//
pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore;
if ((pPerfData->Signature[0] == (WCHAR)'P') &&
(pPerfData->Signature[1] == (WCHAR)'E') &&
(pPerfData->Signature[2] == (WCHAR)'R') &&
(pPerfData->Signature[3] == (WCHAR)'F')) {
// if this is a foreign computer data block, then the
// first object is after the header
pObject = (PERF_OBJECT_TYPE *) (
(LPBYTE)pPerfData + pPerfData->HeaderLength);
bForeignDataBuffer = TRUE;
} else {
// otherwise, if this is just a buffer from
// an extensible counter, the object starts
// at the beginning of the buffer
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
bForeignDataBuffer = FALSE;
}
// go to where the pointers say the end of the
// buffer is and then see if it's where it
// should be
dwObjectBufSize = 0;
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
dwObjectBufSize += pObject->TotalByteLength;
pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
pObject->TotalByteLength);
}
if (((LPBYTE)pObject != (LPBYTE)lpCallBuffer) ||
(dwObjectBufSize > BytesLeft)) {
// then a length field is incorrect. This is FATAL
// since it can corrupt the rest of the buffer
// and render the buffer unusable.
pThisExtObj->dwObjectSizeErrors++;
bBufferOK = FALSE;
Win32Error = ERROR_INVALID_DATA;
}
//
// Test 6: Test instance field size values
//
if (bBufferOK) {
// set object pointer
if (bForeignDataBuffer) {
pObject = (PERF_OBJECT_TYPE *) (
(LPBYTE)pPerfData + pPerfData->HeaderLength);
} else {
// otherwise, if this is just a buffer from
// an extensible counter, the object starts
// at the beginning of the buffer
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
}
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
pObject->TotalByteLength);
if (pObject->NumInstances != PERF_NO_INSTANCES) {
pInstance = (PERF_INSTANCE_DEFINITION *)
((LPBYTE)pObject + pObject->DefinitionLength);
lInstIndex = 0;
while (lInstIndex < pObject->NumInstances) {
PERF_COUNTER_BLOCK *pCounterBlock;
pCounterBlock = (PERF_COUNTER_BLOCK *)
((PCHAR) pInstance + pInstance->ByteLength);
pInstance = (PERF_INSTANCE_DEFINITION *)
((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
lInstIndex++;
}
if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
bBufferOK = FALSE;
Win32Error = ERROR_INVALID_DATA;
}
}
if (!bBufferOK) {
Win32Error = ERROR_INVALID_DATA;
break;
} else {
pObject = pNextObject;
}
}
if (!bBufferOK) {
pThisExtObj->dwInstanceSizeErrors++;
Win32Error = ERROR_INVALID_DATA;
}
}
//
// Test 7: Test instance field size values
//
if (bBufferOK) {
// set object pointer
if (bForeignDataBuffer) {
pObject = (PERF_OBJECT_TYPE *) (
(LPBYTE)pPerfData + pPerfData->HeaderLength);
} else {
// otherwise, if this is just a buffer from
// an extensible counter, the object starts
// at the beginning of the buffer
pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
}
for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
pObject->TotalByteLength);
if (pObject->NumInstances != PERF_NO_INSTANCES) {
pInstance = (PERF_INSTANCE_DEFINITION *)
((LPBYTE)pObject + pObject->DefinitionLength);
lInstIndex = 0;
while (lInstIndex < pObject->NumInstances) {
PERF_COUNTER_BLOCK *pCounterBlock;
pCounterBlock = (PERF_COUNTER_BLOCK *)
((PCHAR) pInstance + pInstance->ByteLength);
pInstance = (PERF_INSTANCE_DEFINITION *)
((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
lInstIndex++;
}
if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
bBufferOK = FALSE;
Win32Error = ERROR_INVALID_DATA;
}
}
if (!bBufferOK) {
Win32Error = ERROR_INVALID_DATA;
break;
} else {
pObject = pNextObject;
}
}
if (!bBufferOK) {
Win32Error = ERROR_INVALID_DATA;
pThisExtObj->dwInstanceNameErrors++;
}
}
}
}
//
// if all the tests pass,then copy the data to the
// original buffer and update the pointers
if (bBufferOK) {
RtlMoveMemory (lpDataDefinition,
lpBufferBefore,
BytesLeft); // returned buffer size
} else {
NumObjectTypes = 0; // since this buffer was tossed
}
} else {
// function already copied data to caller's buffer
// so no further action is necessary
}
lpDataDefinition = (LPVOID)((LPBYTE)(lpDataDefinition) + BytesLeft); // update data pointer
} else {
if (Win32Error != ERROR_SUCCESS) {
if (Win32Error != WAIT_TIMEOUT) {
// don't count timeouts as function errors
InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
}
}
if (bUnlockObjData) {
ReleaseMutex (pThisExtObj->hMutex);
}
NumObjectTypes = 0; // clear counter
}// end if function returned successfully
} __except (EXCEPTION_EXECUTE_HANDLER) {
Win32Error = GetExceptionCode();
InterlockedIncrement ((LONG *)&pThisExtObj->dwExceptionCount);
bException = TRUE;
if (bUnlockObjData) {
ReleaseMutex (pThisExtObj->hMutex);
bUnlockObjData = FALSE;
}
}
if (bUseSafeBuffer) {
HeapFree (hTestHeap, 0, lpExtDataBuffer);
}
} else {
// unable to allocate memory so set error value
Win32Error = ERROR_OUTOFMEMORY;
} // end if temp buffer allocated successfully
RELEASE_MUTEX (pThisExtObj->hMutex);
lReturnValue = Win32Error;
return lReturnValue;
}
DWORD
CloseLibrary (
EXT_OBJECT *pInfo
)
{
DWORD lStatus;
if (pInfo != NULL) {
// if there's a close proc to call, then
// call close procedure to close anything that may have
// been allocated by the library
WAIT_FOR_AND_LOCK_MUTEX (pInfo->hMutex);
if (pInfo->CloseProc != NULL) {
lStatus = (*pInfo->CloseProc) ();
}
RELEASE_MUTEX (pInfo->hMutex);
// then close everything
if (pInfo->hMutex != NULL) {
CloseHandle (pInfo->hMutex);
pInfo->hMutex = NULL;
}
if (pInfo->hLibrary != NULL) {
FreeLibrary (pInfo->hLibrary);
pInfo->hLibrary = NULL;
}
if (pInfo->hPerfKey != NULL) {
RegCloseKey (pInfo->hPerfKey);
pInfo->hPerfKey = NULL;
}
HeapFree (hTestHeap, 0, pInfo);
}
return ERROR_SUCCESS;
}
static
LPWSTR
*BuildNameTable(
LPCWSTR szMachineName,
LPCWSTR lpszLangIdArg, // unicode value of Language subkey
PDWORD pdwLastItem, // size of array in elements
PDWORD pdwIdArray // array for index ID's
)
/*++
BuildNameTable
Arguments:
hKeyRegistry
Handle to an open registry (this can be local or remote.) and
is the value returned by RegConnectRegistry or a default key.
lpszLangId
The unicode id of the language to look up. (default is 409)
Return Value:
pointer to an allocated table. (the caller must MemoryFree it when finished!)
the table is an array of pointers to zero terminated strings. NULL is
returned if an error occured.
--*/
{
HKEY hKeyRegistry; // handle to registry db with counter names
LPWSTR *lpReturnValue;
LPCWSTR lpszLangId;
LPWSTR *lpCounterId;
LPWSTR lpCounterNames;
LPWSTR lpHelpText;
LPWSTR lpThisName;
LONG lWin32Status;
DWORD dwValueType;
DWORD dwArraySize;
DWORD dwBufferSize;
DWORD dwCounterSize;
DWORD dwHelpSize;
DWORD dwThisCounter;
DWORD dwLastId;
DWORD dwLastHelpId;
DWORD dwLastCounterIdUsed;
DWORD dwLastHelpIdUsed;
HKEY hKeyValue;
HKEY hKeyNames;
LPWSTR lpValueNameString;
WCHAR CounterNameBuffer [50];
WCHAR HelpNameBuffer [50];
SetLastError (ERROR_SUCCESS);
szTestErrorMessage = NULL;
if (szMachineName != NULL) {
lWin32Status = RegConnectRegistryW (szMachineName,
HKEY_LOCAL_MACHINE,
&hKeyRegistry);
} else {
lWin32Status = ERROR_SUCCESS;
hKeyRegistry = HKEY_LOCAL_MACHINE;
}
lpValueNameString = NULL; //initialize to NULL
lpReturnValue = NULL;
hKeyValue = NULL;
hKeyNames = NULL;
// check for null arguments and insert defaults if necessary
if (!lpszLangIdArg) {
lpszLangId = cszDefaultLangId;
} else {
lpszLangId = lpszLangIdArg;
}
// open registry to get number of items for computing array size
lWin32Status = RegOpenKeyExW (
hKeyRegistry,
cszNamesKey,
0L,
KEY_READ,
&hKeyValue);
if (lWin32Status != ERROR_SUCCESS) {
szTestErrorMessage = (LPWSTR)L"Unable to Open Perflib key";
goto BNT_BAILOUT;
}
// get config info
dwValueType = 0;
dwBufferSize = sizeof (pdwIdArray[4]);
lWin32Status = RegQueryValueExW (
hKeyValue,
(LPCWSTR)L"Disable Performance Counters",
0L,
&dwValueType,
(LPBYTE)&pdwIdArray[4],
&dwBufferSize);
if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
if (lWin32Status == ERROR_FILE_NOT_FOUND) {
// this is OK since the value need not be present
pdwIdArray[4] = (DWORD)-1;
lWin32Status = ERROR_SUCCESS;
} else {
szTestErrorMessage = (LPWSTR)L"Unable to read Disable Performance Counters value";
goto BNT_BAILOUT;
}
}
dwValueType = 0;
dwBufferSize = sizeof (pdwIdArray[5]);
lWin32Status = RegQueryValueExW (
hKeyValue,
(LPCWSTR)L"ExtCounterTestLevel",
0L,
&dwValueType,
(LPBYTE)&pdwIdArray[5],
&dwBufferSize);
if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
if (lWin32Status == ERROR_FILE_NOT_FOUND) {
// this is OK since the value need not be present
pdwIdArray[5] = (DWORD)-1;
lWin32Status = ERROR_SUCCESS;
} else {
szTestErrorMessage = (LPWSTR)L"Unable to read ExCounterTestLevel value";
goto BNT_BAILOUT;
}
}
dwValueType = 0;
dwBufferSize = sizeof (pdwIdArray[6]);
lWin32Status = RegQueryValueExW (
hKeyValue,
(LPCWSTR)L"Base Index",
0L,
&dwValueType,
(LPBYTE)&pdwIdArray[6],
&dwBufferSize);
if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
szTestErrorMessage = (LPWSTR)L"Unable to read Base Index value";
goto BNT_BAILOUT;
}
// get number of items
dwBufferSize = sizeof (dwLastHelpId);
lWin32Status = RegQueryValueExW (
hKeyValue,
cszLastHelp,
0L,
&dwValueType,
(LPBYTE)&dwLastHelpId,
&dwBufferSize);
if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
szTestErrorMessage = (LPWSTR)L"Unable to read Last Help value";
goto BNT_BAILOUT;
}
pdwIdArray[2] = dwLastHelpId;
// get number of items
dwBufferSize = sizeof (dwLastId);
lWin32Status = RegQueryValueExW (
hKeyValue,
cszLastCounter,
0L,
&dwValueType,
(LPBYTE)&dwLastId,
&dwBufferSize);
if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
szTestErrorMessage = (LPWSTR)L"Unable to read Last Counter value";
goto BNT_BAILOUT;
}
pdwIdArray[0] = dwLastId;
if (dwLastId < dwLastHelpId)
dwLastId = dwLastHelpId;
dwArraySize = dwLastId * sizeof(LPWSTR);
// get Perflib system version
if (szMachineName[0] == 0) {
hKeyNames = HKEY_PERFORMANCE_DATA;
} else {
lWin32Status = RegConnectRegistryW (szMachineName,
HKEY_PERFORMANCE_DATA,
&hKeyNames);
}
lstrcpyW (CounterNameBuffer, cszCounterName);
lstrcatW (CounterNameBuffer, lpszLangId);
lstrcpyW (HelpNameBuffer, cszHelpName);
lstrcatW (HelpNameBuffer, lpszLangId);
// get size of counter names and add that to the arrays
dwBufferSize = 0;
lWin32Status = RegQueryValueExW (
hKeyNames,
CounterNameBuffer,
0L,
&dwValueType,
NULL,
&dwBufferSize);
if (lWin32Status != ERROR_SUCCESS) {
szTestErrorMessage = (LPWSTR)L"Unable to query counter string size";
goto BNT_BAILOUT;
}
dwCounterSize = dwBufferSize;
// get size of counter names and add that to the arrays
if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
dwBufferSize = 0;
lWin32Status = RegQueryValueExW (
hKeyNames,
HelpNameBuffer,
0L,
&dwValueType,
NULL,
&dwBufferSize);
if (lWin32Status != ERROR_SUCCESS) {
szTestErrorMessage = (LPWSTR)L"Unable to query help string size";
goto BNT_BAILOUT;
}
dwHelpSize = dwBufferSize;
lpReturnValue = (LPWSTR *)HeapAlloc (hTestHeap, 0,dwArraySize + dwCounterSize + dwHelpSize);
if (!lpReturnValue) {
lWin32Status = ERROR_OUTOFMEMORY;
szTestErrorMessage = (LPWSTR)L"Unable to allocate name string buffer";
goto BNT_BAILOUT;
}
// initialize pointers into buffer
lpCounterId = lpReturnValue;
lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
lpHelpText = (LPWSTR)((LPBYTE)lpCounterNames + dwCounterSize);
// read counters into memory
dwBufferSize = dwCounterSize;
lWin32Status = RegQueryValueExW (
hKeyNames,
CounterNameBuffer,
0L,
&dwValueType,
(LPBYTE)lpCounterNames,
&dwBufferSize);
if (lWin32Status != ERROR_SUCCESS) {
szTestErrorMessage = (LPWSTR)L"Unable to query counter string contents";
goto BNT_BAILOUT;
}
dwBufferSize = dwHelpSize;
lWin32Status = RegQueryValueExW (
hKeyNames,
HelpNameBuffer,
0L,
&dwValueType,
(LPBYTE)lpHelpText,
&dwBufferSize);
if (lWin32Status != ERROR_SUCCESS) {
szTestErrorMessage = (LPWSTR)L"Unable to query help string contents";
goto BNT_BAILOUT;
}
dwLastCounterIdUsed = 0;
dwLastHelpIdUsed = 0;
// load counter array items
for (lpThisName = lpCounterNames;
*lpThisName;
lpThisName += (lstrlenW(lpThisName)+1) ) {
// first string should be an integer (in decimal unicode digits)
dwThisCounter = wcstoul (lpThisName, NULL, 10);
if (dwThisCounter == 0) {
lWin32Status = ERROR_BADKEY;
szTestErrorMessage = (LPWSTR)L"Bad counter string entry, CONFIG_String_LastCounter is last valid counter string index";
goto BNT_BAILOUT; // bad entry
}
// point to corresponding counter name
lpThisName += (lstrlenW(lpThisName)+1);
// and load array element;
lpCounterId[dwThisCounter] = lpThisName;
if (dwThisCounter > dwLastCounterIdUsed) dwLastCounterIdUsed = dwThisCounter;
}
pdwIdArray[1] = dwLastCounterIdUsed;
for (lpThisName = lpHelpText;
*lpThisName;
lpThisName += (lstrlenW(lpThisName)+1) ) {
// first string should be an integer (in decimal unicode digits)
dwThisCounter = wcstoul (lpThisName, NULL, 10);
if (dwThisCounter == 0) {
lWin32Status = ERROR_BADKEY;
szTestErrorMessage = (LPWSTR)L"Bad help string entry, CONFIG_String_LastHelp is last valid counter string index";
goto BNT_BAILOUT; // bad entry
}
// point to corresponding counter name
lpThisName += (lstrlenW(lpThisName)+1);
// and load array element;
lpCounterId[dwThisCounter] = lpThisName;
if (dwThisCounter > dwLastHelpIdUsed) dwLastHelpIdUsed= dwThisCounter;
}
pdwIdArray[3] = dwLastHelpIdUsed;
dwLastId = dwLastHelpIdUsed;
if (dwLastId < dwLastCounterIdUsed) dwLastId = dwLastCounterIdUsed;
if (pdwLastItem) *pdwLastItem = dwLastId;
HeapFree (hTestHeap, 0, (LPVOID)lpValueNameString);
RegCloseKey (hKeyValue);
RegCloseKey (hKeyNames);
return lpReturnValue;
BNT_BAILOUT:
if (lWin32Status != ERROR_SUCCESS) {
SetLastError (lWin32Status);
}
if (lpValueNameString) {
HeapFree (hTestHeap, 0, (LPVOID)lpValueNameString);
}
if (lpReturnValue) {
HeapFree (hTestHeap, 0, (LPVOID)lpValueNameString);
}
if (hKeyValue) RegCloseKey (hKeyValue);
RegCloseKey (hKeyNames);
return NULL;
}
DWORD
CycleTest (
DWORD dwThreadId,
PLOCAL_THREAD_DATA pData
)
{
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwRetStatus = ERROR_SUCCESS;
EXT_OBJECT *pObj = NULL;
LPWSTR szValueString = pData->szQueryString;
LPCWSTR szServiceName = pData->szServiceName;
DWORD dwLoopCount = pData->dwLoopCount;
LPBYTE pBuffer = NULL;
LPBYTE pThisBuffer;
DWORD dwBufSize = 0;
DWORD dwThisBufSize;
DWORD dwMemorySizeIncrement = 0x100;
FILE *pOutput = pData->pOutput;
DOUBLE dMs;
LPWSTR *pNameTable = pData->pNameTable;
DWORD dwLastId = pData->dwLastIndex;
PERF_OBJECT_TYPE * pObjDef;
PERF_COUNTER_DEFINITION * pCtrDef;
DWORD nObjIdx, nCtrIdx;
UNREFERENCED_PARAMETER (dwThreadId);
dwStatus = OpenLibrary (szServiceName, &pObj);
if (pObj != NULL) {
// an object info block was returned
dMs = (DOUBLE)pObj->llOpenTime; // ticks used
dMs /= (DOUBLE)pObj->llTimeBase; // ticks/sec
dMs *= 1000.0; // ms/Sec
fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_OpenProcTime: \t%12.5f mSec", dMs);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_OpenProcTimeout: \t%6d.00000 mSec", pObj->dwOpenTimeout);
// check for timeout
if (dMs > (DOUBLE)pObj->dwOpenTimeout) {
dwRetStatus = ERROR_TIMEOUT;
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR: \tOpen procedure exceeded timeout");
}
} else {
// no object block returned
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR: \tUnable to open Library");
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORCODE:\t0x%8.8x (%dL)", dwStatus, dwStatus);
dwRetStatus = dwStatus;
}
if (dwRetStatus == ERROR_SUCCESS) {
HeapValidate (hTestHeap, 0, NULL);
// get the buffer size
dwStatus = ERROR_MORE_DATA;
do {
if (pBuffer != NULL) HeapFree (hTestHeap, 0, pBuffer);
dwBufSize += dwMemorySizeIncrement;
dwMemorySizeIncrement *= 2;
pBuffer = (LPBYTE) HeapAlloc (hTestHeap, HEAP_ZERO_MEMORY, dwBufSize);
if (pBuffer != NULL) {
// init the args
pThisBuffer = pBuffer;
dwThisBufSize = dwBufSize;
HeapValidate (hTestHeap, 0, NULL);
dwStatus = CollectData (pObj,
pThisBuffer,
&dwThisBufSize,
szValueString);
}
} while ((dwStatus == ERROR_MORE_DATA) && (dwBufSize < MAX_BUF_SIZE));
if (dwBufSize >= MAX_BUF_SIZE) {
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR: \tCollectFunction requires a buffer > %d bytes", MAX_BUF_SIZE);
if (pBuffer != NULL) HeapFree (hTestHeap, 0, pBuffer);
dwStatus = ERROR_INVALID_PARAMETER;
} else if (pBuffer == NULL) {
dwStatus = ERROR_OUTOFMEMORY;
} else {
// call collect function
do {
// init the args
pThisBuffer = pBuffer;
dwThisBufSize = dwBufSize;
// get the data
dwStatus = CollectData (pObj,
pThisBuffer,
&dwThisBufSize,
szValueString);
while ((dwStatus == ERROR_MORE_DATA) && (dwBufSize < MAX_BUF_SIZE)) {
if (pBuffer != NULL) HeapFree (hTestHeap, 0, pBuffer);
dwBufSize += dwMemorySizeIncrement;
dwMemorySizeIncrement *= 2;
pBuffer = (LPBYTE) HeapAlloc (hTestHeap, HEAP_ZERO_MEMORY, dwBufSize);
if (pBuffer != NULL) {
// init the args
pThisBuffer = pBuffer;
dwThisBufSize = dwBufSize;
// get the data again
dwStatus = CollectData (pObj,
pThisBuffer,
&dwThisBufSize,
szValueString);
if ((dwStatus == ERROR_SUCCESS) && (pData->bTestContents)) {
pObjDef = (PERF_OBJECT_TYPE *)pThisBuffer;
for (nObjIdx = 0; nObjIdx < pObj->dwNumObjectsRet; nObjIdx++) {
// test object name & help
if ((pObjDef->ObjectNameTitleIndex <= dwLastId) &&
(pObjDef->ObjectNameTitleIndex > 0)) {
if (pNameTable[pObjDef->ObjectNameTitleIndex ] == NULL) {
// no string
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tNo Display String for index %d", pObjDef->ObjectNameTitleIndex );
dwStatus = ERROR_BADKEY;
} else {
// probably ok
}
} else {
// id out of range
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tObject Name Index values are bad or missing");
dwStatus = ERROR_BADKEY;
}
// test counter defs
if ((pObjDef->ObjectHelpTitleIndex <= dwLastId) &&
(pObjDef->ObjectHelpTitleIndex> 0)) {
if (pNameTable[pObjDef->ObjectHelpTitleIndex] == NULL) {
// no string
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tNo Display String for index %d", pObjDef->ObjectHelpTitleIndex );
dwStatus = ERROR_BADKEY;
} else {
// probably ok
}
} else {
// id out of range
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tObject Help Index values are bad or missing");
dwStatus = ERROR_BADKEY;
}
pCtrDef = FirstCounter (pObjDef);
for (nCtrIdx = 0; nCtrIdx < pObjDef->NumCounters; nCtrIdx++) {
pCtrDef = NextCounter (pCtrDef);
if ((pCtrDef->CounterNameTitleIndex <= dwLastId) &&
(pCtrDef->CounterNameTitleIndex > 0)) {
if (pNameTable[pCtrDef->CounterNameTitleIndex ] == NULL) {
// no string
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tNo Display String for index %d", pCtrDef->CounterNameTitleIndex );
dwStatus = ERROR_BADKEY;
} else {
// probably ok
}
} else {
// id out of range
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tCounter Name Index values are bad or missing");
dwStatus = ERROR_BADKEY;
}
// test counter defs
if ((pCtrDef->CounterHelpTitleIndex <= dwLastId) &&
(pCtrDef->CounterHelpTitleIndex> 0)) {
if (pNameTable[pCtrDef->CounterHelpTitleIndex] == NULL) {
// no string
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tNo Display String for index %d", pCtrDef->CounterHelpTitleIndex );
dwStatus = ERROR_BADKEY;
} else {
// probably ok
}
} else {
// id out of range
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tCounter Help Index values are bad or missing");
dwStatus = ERROR_BADKEY;
}
}
pObjDef = NextObject (pObjDef);
}
}
HeapValidate (hTestHeap, 0, NULL);
}
}
if (dwStatus != ERROR_SUCCESS) {
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR: \tCollect procedure returned an error");
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORCODE:\t0x%8.8x (%dL)", dwStatus, dwStatus);
// output the contents of the info buffer
if (dwStatus == ERROR_TIMEOUT) {
// dump collect fn stats.
dMs = (DOUBLE)pObj->llFunctionTime;
dMs /= (DOUBLE)pObj->llTimeBase;
dMs *= 1000.0;
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CollectProcTime:\t%12.5f mSec", dMs);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CollectTimeout: \t%6d.00000 mSec", pObj->dwCollectTimeout);
}
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CollectTime: \t%I64u", pObj->llCollectTime);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CollectCount:\t%d", pObj->dwCollectCount);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_OpenCount: \t%d", pObj->dwOpenCount);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CloseCount: \t%d", pObj->dwCloseCount);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_LockoutCount:\t%d", pObj->dwLockoutCount);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_ErrorCount: \t%d", pObj->dwErrorCount);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_Exceptions: \t%d", pObj->dwExceptionCount);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_LowerGPErrs: \t%d", pObj->dwLowerGPViolations);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_UpperGPErrs: \t%d", pObj->dwUpperGPViolations);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_BadPointers: \t%d", pObj->dwBadPointers);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_BufSizeErrs: \t%d", pObj->dwBufferSizeErrors);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_AlignErrors: \t%d", pObj->dwAlignmentErrors);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_ObjSizeErrs: \t%d", pObj->dwObjectSizeErrors);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_InstSizeErrs:\t%d", pObj->dwInstanceSizeErrors);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_TimeBase: \t%I64u", pObj->llTimeBase);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_FunctionTime:\t%I64u", pObj->llFunctionTime);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_ObjectsRet: \t%d", pObj->dwNumObjectsRet);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_RetBuffSize: \t%d", pObj->dwRetBufSize);
break;
}
} while (--dwLoopCount > 0);
if (dwStatus == ERROR_SUCCESS) {
// dump collect fn stats.
if ((pObj->dwCollectCount > 0) && (pObj->dwNumObjectsRet > 0)){
// don't compute time if no objects were returned
dMs = (DOUBLE)pObj->llCollectTime;
dMs /= (DOUBLE)pObj->llTimeBase;
dMs *= 1000.0;
dMs /= (DOUBLE)pObj->dwCollectCount;
fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_AvgCollectProcTime: \t%12.5f mSec", dMs);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_CollectProcTimeout: \t%6d.00000 mSec", pObj->dwCollectTimeout);
}
fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_ObjectsRet: \t%d", pObj->dwNumObjectsRet);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_RetBuffSize: \t%d", pObj->dwRetBufSize);
}
HeapFree (hTestHeap, 0, pBuffer);
}
dwRetStatus = dwStatus;
// close
CloseLibrary (pObj);
} // unable to open library
HeapValidate (hTestHeap, 0, NULL);
return dwStatus;
}
DWORD
CycleThreadProc (
LPVOID lpThreadArg
)
{
DWORD dwStatus = ERROR_SUCCESS;
PLOCAL_THREAD_DATA pData= (PLOCAL_THREAD_DATA)lpThreadArg;
DWORD dwCycleCount = pData->dwCycleCount;
DWORD dwThisThread = GetCurrentThreadId();
HeapValidate (hTestHeap, 0, NULL);
do {
// argv[1] is the name of the
dwStatus = CycleTest(dwThisThread, pData);
} while (--dwCycleCount > 0);
HeapValidate (hTestHeap, 0, NULL);
return dwStatus;
}
int
WriteTestResultHeader(
FILE *pOutput
)
{
OSVERSIONINFOW osInfo;
WCHAR szMachineName[MAX_PATH];
DWORD dwSize;
SYSTEMTIME stStart;
memset (&osInfo, 0, sizeof(osInfo));
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
memset (szMachineName, 0, sizeof(szMachineName));
memset (&stStart, 0, sizeof(stStart));
GetVersionExW (&osInfo);
dwSize = sizeof(szMachineName) / sizeof (szMachineName[0]);
GetComputerNameW (&szMachineName[0], &dwSize);
GetLocalTime (&stStart);
fwprintf (pOutput, (LPCWSTR)L"\n[TESTRESULT]");
fwprintf (pOutput, (LPCWSTR)L"\n\tTEST: \tPerf Counter DLL Validation");
fwprintf (pOutput, (LPCWSTR)L"\n\tBUILD: \t%d", osInfo.dwBuildNumber);
fwprintf (pOutput, (LPCWSTR)L"\n\tMACHINE:\t%s", szMachineName);
fwprintf (pOutput, (LPCWSTR)L"\n\tCONTACT:\t%s", szContact);
fwprintf (pOutput, (LPCWSTR)L"\n\tMGR CONTACT:\t%s", szMgrContact);
fwprintf (pOutput, (LPCWSTR)L"\n\tDEV PRIME:\t%s", szDevPrime);
fwprintf (pOutput, (LPCWSTR)L"\n\tDEV ALT:\t%s", szDevAlt);
fwprintf (pOutput, (LPCWSTR)L"\n\tTEST PRIME:\t%s", szTestPrime);
fwprintf (pOutput, (LPCWSTR)L"\n\tTEST ALT:\t%s", szTestAlt);
fwprintf (pOutput, (LPCWSTR)L"\n\tSTART TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d",
stStart.wMonth, stStart.wDay, stStart.wYear % 100,
stStart.wHour, stStart.wMinute, stStart.wSecond );
return 0;
}
int
WriteTestConfigData(
FILE *pOutput,
LPDWORD pdwIdInfo
)
{
fwprintf (pOutput, (LPCWSTR)L"\n\t");
fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_Perflib_LastCounter:\t%d", pdwIdInfo[0]);
fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_String_LastCounter: \t%d", pdwIdInfo[1]);
fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_Perflib_LastHelp: \t%d", pdwIdInfo[2]);
fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_String_LastHelp: \t%d", pdwIdInfo[3]);
fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_Disabled: \t%d", pdwIdInfo[4]);
fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_ExtCounterTestLevel:\t%d", pdwIdInfo[5]);
fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_BaseIndex: \t%d", pdwIdInfo[6]);
// fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_BaseOsObject : \t%d", pdwIdInfo[7]);
return 0;
}
DWORD
WriteGroupConfig(
FILE *pOutput,
HKEY hKeyPerfSubKey,
DWORD *pIds
)
{
DWORD nRetStatus = (int)ERROR_SUCCESS;
DWORD lStatus;
DWORD dwData;
DWORD dwBufferSize;
DWORD dwValueType;
WCHAR szStringBuffer[MAX_PATH*2];
dwBufferSize = sizeof(szStringBuffer);
dwValueType = 0;
memset (szStringBuffer, 0, sizeof(szStringBuffer));
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Library",
0L,
&dwValueType,
(LPBYTE)&szStringBuffer[0],
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Library:\t%s",
(lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
if (lStatus != ERROR_SUCCESS) nRetStatus = lStatus;
dwBufferSize = sizeof(szStringBuffer);
dwValueType = 0;
memset (szStringBuffer, 0, sizeof(szStringBuffer));
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Open",
0L,
&dwValueType,
(LPBYTE)&szStringBuffer[0],
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Open:\t%s",
(lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
if (lStatus != ERROR_SUCCESS) nRetStatus = lStatus;
dwBufferSize = sizeof(szStringBuffer);
dwValueType = 0;
memset (szStringBuffer, 0, sizeof(szStringBuffer));
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Collect",
0L,
&dwValueType,
(LPBYTE)&szStringBuffer[0],
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Collect:\t%s",
(lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
if (lStatus != ERROR_SUCCESS) nRetStatus = lStatus;
dwBufferSize = sizeof(szStringBuffer);
dwValueType = 0;
memset (szStringBuffer, 0, sizeof(szStringBuffer));
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Object List",
0L,
&dwValueType,
(LPBYTE)&szStringBuffer[0],
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Object List:\t%s",
(lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
dwBufferSize = sizeof(szStringBuffer);
dwValueType = 0;
memset (szStringBuffer, 0, sizeof(szStringBuffer));
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Close",
0L,
&dwValueType,
(LPBYTE)&szStringBuffer[0],
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Close:\t%s",
(lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
if (lStatus != ERROR_SUCCESS) nRetStatus = lStatus;
dwBufferSize = sizeof(dwData);
dwValueType = 0;
dwData = 0;
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"First Counter",
0L,
&dwValueType,
(LPBYTE)&dwData,
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_First Counter:\t%d",
(lStatus == ERROR_SUCCESS ? dwData : (DWORD)-1));
if (lStatus != ERROR_SUCCESS) {
if (lStatus == ERROR_FILE_NOT_FOUND) {
if (!pIds[4]) {
// then this hasn't been installed yet
nRetStatus = ERROR_SERVICE_DISABLED;
} else {
// then this is a base OS service
nRetStatus = ERROR_SUCCESS;
}
} else {
// some other error so return
nRetStatus = lStatus;
}
pIds[0] = (DWORD)-1;
} else {
pIds[0] = dwData;
}
dwBufferSize = sizeof(dwData);
dwValueType = 0;
dwData = 0;
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Last Counter",
0L,
&dwValueType,
(LPBYTE)&dwData,
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Last Counter:\t%d",
(lStatus == ERROR_SUCCESS ? dwData : (DWORD)-1));
if (lStatus != ERROR_SUCCESS) {
if (lStatus == ERROR_FILE_NOT_FOUND) {
if (!pIds[4]) {
// then this hasn't been installed yet
nRetStatus = ERROR_SERVICE_DISABLED;
} else {
// then this is a base OS service
nRetStatus = ERROR_SUCCESS;
}
} else {
// some other error so return
nRetStatus = lStatus;
}
pIds[1] = (DWORD)-1;
} else {
pIds[1] = dwData;
}
dwBufferSize = sizeof(dwData);
dwValueType = 0;
dwData = 0;
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"First Help",
0L,
&dwValueType,
(LPBYTE)&dwData,
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_First Help:\t%d",
(lStatus == ERROR_SUCCESS ? dwData : (DWORD)-1));
if (lStatus != ERROR_SUCCESS) {
if (lStatus == ERROR_FILE_NOT_FOUND) {
if (!pIds[4]) {
// then this hasn't been installed yet
nRetStatus = ERROR_SERVICE_DISABLED;
} else {
// then this is a base OS service
nRetStatus = ERROR_SUCCESS;
}
} else {
// some other error so return
nRetStatus = lStatus;
}
pIds[2] = (DWORD)-1;
} else {
pIds[2] = dwData;
}
dwBufferSize = sizeof(dwData);
dwValueType = 0;
dwData = 0;
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Last Help",
0L,
&dwValueType,
(LPBYTE)&dwData,
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Last Help:\t%d",
(lStatus == ERROR_SUCCESS ? dwData : (DWORD)-1));
if (lStatus != ERROR_SUCCESS) {
if (lStatus == ERROR_FILE_NOT_FOUND) {
if (!pIds[4]) {
// then this hasn't been installed yet
nRetStatus = ERROR_SERVICE_DISABLED;
} else {
// then this is a base OS service
nRetStatus = ERROR_SUCCESS;
}
} else {
// some other error so return
nRetStatus = lStatus;
}
pIds[3] = (DWORD)-1;
} else {
pIds[3] = dwData;
}
dwBufferSize = sizeof(dwData);
dwValueType = 0;
dwData = 0;
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Open Timeout",
0L,
&dwValueType,
(LPBYTE)&dwData,
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Open Timeout:\t%d",
(lStatus == ERROR_SUCCESS ? dwData : (DWORD)10000));
dwBufferSize = sizeof(dwData);
dwValueType = 0;
dwData = 0;
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Collect Timeout",
0L,
&dwValueType,
(LPBYTE)&dwData,
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Collect Timeout:\t%d",
(lStatus == ERROR_SUCCESS ? dwData : (DWORD)10000));
dwBufferSize = sizeof(dwData);
dwValueType = 0;
dwData = 0;
lStatus = RegQueryValueExW (
hKeyPerfSubKey,
(LPCWSTR)L"Disable Performance Counters",
0L,
&dwValueType,
(LPBYTE)&dwData,
&dwBufferSize);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Disable Performance Counters:\t%d",
(lStatus == ERROR_SUCCESS ? dwData : (DWORD)0));
if ((lStatus == ERROR_SUCCESS) && (dwData != 0)){
nRetStatus = ERROR_SERVICE_DISABLED;
}
return nRetStatus;
}
int
WriteTestResultTrailer(
FILE *pOutput,
DWORD dwTestResult
)
{
SYSTEMTIME stEnd;
LPWSTR szResult;
memset (&stEnd, 0, sizeof(stEnd));
GetLocalTime (&stEnd);
switch (dwTestResult) {
case PERFVAL_PASS:
szResult = (LPWSTR)L"PASS"; break;
case PERFVAL_FAIL:
szResult = (LPWSTR)L"FAIL"; break;
case PERFVAL_TIMEOUT:
szResult = (LPWSTR)L"TIMEOUT"; break;
case PERFVAL_NOCONFIG:
default:
szResult = (LPWSTR)L"NOCONFIG"; break;
}
fwprintf (pOutput, (LPCWSTR)L"\n\n\tRESULT: \t%s", szResult);
fwprintf (pOutput, (LPCWSTR)L"\n\tEND TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d",
stEnd.wMonth, stEnd.wDay, stEnd.wYear % 100,
stEnd.wHour, stEnd.wMinute, stEnd.wSecond);
fwprintf (pOutput, (LPCWSTR)L"\n[/TESTRESULT]");
fwprintf (pOutput, (LPCWSTR)L"\n");
return 0;
}
int
WriteGroupHeader(FILE *pOutput, LPCWSTR szGroupName)
{
SYSTEMTIME stStart;
memset (&stStart, 0, sizeof(stStart));
GetLocalTime (&stStart);
fwprintf (pOutput, (LPCWSTR)L"\n\n\t[GROUP: %s]", szGroupName);
fwprintf (pOutput, (LPCWSTR)L"\n\t\tSTART TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d.%3.3d",
stStart.wMonth, stStart.wDay, stStart.wYear % 100,
stStart.wHour, stStart.wMinute, stStart.wSecond, stStart.wMilliseconds );
return 0;
}
int
WriteGroupTrailer(FILE *pOutput, DWORD dwTestResult)
{
LPWSTR szResult;
SYSTEMTIME stEnd;
memset (&stEnd, 0, sizeof(stEnd));
GetLocalTime (&stEnd);
switch (dwTestResult) {
case PERFVAL_PASS:
szResult = (LPWSTR)L"PASS"; break;
case PERFVAL_FAIL:
szResult = (LPWSTR)L"FAIL"; break;
case PERFVAL_TIMEOUT:
szResult = (LPWSTR)L"TIMEOUT"; break;
case PERFVAL_NOCONFIG:
default:
szResult = (LPWSTR)L"NOCONFIG"; break;
}
fwprintf (pOutput, (LPCWSTR)L"\n\t\tEND TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d.%3.3d",
stEnd.wMonth, stEnd.wDay, stEnd.wYear % 100,
stEnd.wHour, stEnd.wMinute, stEnd.wSecond, stEnd.wMilliseconds );
fwprintf (pOutput, (LPCWSTR)L"\n\t\tRESULT: %s", szResult);
fwprintf (pOutput, (LPCWSTR)L"\n\t[/GROUP]");
return 0;
}
int
PerfVal_ConfigTestFunction (
FILE *pOutput,
LPDWORD pdwIdInfo
)
{
DWORD dwReturn = ERROR_SUCCESS;
UNREFERENCED_PARAMETER (pOutput);
// configuration tests:
// LAST COUNTER in registry >= Last counter string index
// LAST HELP in registry >= Last help string index
// BASE INDEX == 1847
SetLastError (ERROR_SUCCESS);
szTestErrorMessage = NULL;
if (pdwIdInfo[0] < pdwIdInfo[1]) {
dwReturn = ERROR_INVALID_INDEX;
szTestErrorMessage = (LPWSTR)L"Counter String has too many entries";
}
if (pdwIdInfo[2] < pdwIdInfo[3]) {
dwReturn = ERROR_INVALID_INDEX;
szTestErrorMessage = (LPWSTR)L"Help String has too many entries";
}
if (pdwIdInfo[6] != 1847) {
dwReturn = ERROR_INVALID_PARAMETER;
szTestErrorMessage = (LPWSTR)L"Base Index is incorrect";
}
return dwReturn;
}
int
PerfVal_ServiceTestConfig (
FILE *pOutput,
LPDWORD dwNameIds,
LPCWSTR *pNameTable,
DWORD dwLastId
)
{
DWORD dwServiceTestResult = ERROR_SUCCESS;
DWORD dwIdIdx = 0;
// check counter strings
if ((dwNameIds[0] != (DWORD)-1) && (dwNameIds[1] != (DWORD)-1)) {
if (((dwNameIds[0] <= dwLastId) && (dwNameIds[1] <= dwLastId)) &&
(dwNameIds[0] < dwNameIds[1])){
for (dwIdIdx = dwNameIds[0]; dwIdIdx <= dwNameIds[1]; dwIdIdx += 2) {
if (pNameTable[dwIdIdx] == NULL) {
// no string
fwprintf (pOutput, (LPCWSTR)L"\n\t\tWARNING:\tNo Display String for index %d", dwIdIdx);
dwServiceTestResult = ERROR_BADKEY;
} else {
// probably ok
}
}
} else {
// id out of range
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tCounter Index values are bad or missing");
dwServiceTestResult = ERROR_BADKEY;
}
} else {
// not installed or a base counter
}
// check help strings
if ((dwNameIds[2] != (DWORD)-1) && (dwNameIds[3] != (DWORD)-1)) {
if (((dwNameIds[2] <= dwLastId) && (dwNameIds[3] <= dwLastId)) &&
(dwNameIds[2] < dwNameIds[3])){
for (dwIdIdx = dwNameIds[2]; dwIdIdx <= dwNameIds[3]; dwIdIdx += 2) {
if (pNameTable[dwIdIdx] == NULL) {
// no string
fwprintf (pOutput, (LPCWSTR)L"\n\t\tWARNING:\tNo Display String for index %d", dwIdIdx);
dwServiceTestResult = ERROR_BADKEY;
} else {
// probably ok
}
}
} else {
// id out of range
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tCounter Index values are bad or missing");
dwServiceTestResult = ERROR_BADKEY;
}
} else {
// not installed or a base counter
}
return dwServiceTestResult ;
}
DWORD
PerfVal_ServiceTestFunction (
FILE *pOutput,
LPCWSTR szServiceName,
HKEY hKeyPerfSubKey,
BOOL bTestContents,
LPWSTR *pNameTable,
DWORD dwLastEntry
)
{
DWORD dwLoopCount = 1;
DWORD dwCycleCount = 1;
DWORD dwThreadCount = 0;
LOCAL_THREAD_DATA LTData;
HANDLE hThreads[MAXIMUM_WAIT_OBJECTS];
DWORD dwThisThread;
DWORD dwTimeout;
DWORD dwId;
DWORD dwStatus;
UNREFERENCED_PARAMETER (hKeyPerfSubKey);
LTData.szServiceName = (LPWSTR)szServiceName;
LTData.szQueryString = (LPWSTR)L"Global";
LTData.dwCycleCount = dwCycleCount;
LTData.dwLoopCount = dwLoopCount;
LTData.bDisplay = FALSE;//(dwThreadCount <= 1 ? TRUE : FALSE);
LTData.pOutput = pOutput;
LTData.bTestContents = bTestContents;
LTData.pNameTable = pNameTable;
LTData.dwLastIndex = dwLastEntry;
if (dwThreadCount == 0) {
dwStatus = CycleThreadProc ((LPVOID)&LTData);
} else {
// create threads
for (dwThisThread = 0; dwThisThread < dwThreadCount; dwThisThread++) {
hThreads[dwThisThread] = CreateThread(
NULL, 0L, CycleThreadProc, (LPVOID)&LTData, 0L, &dwId);
}
dwTimeout = 60000 * dwCycleCount; // allow 1 minute per cycle
dwStatus = WaitForMultipleObjects (dwThreadCount, hThreads, TRUE, dwTimeout);
if (dwStatus != WAIT_TIMEOUT) {
dwStatus = ERROR_SUCCESS;
} else {
fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tWait for test cycles to complete exceeded 60 seconds");
}
for (dwThisThread = 0; dwThisThread < dwThreadCount; dwThisThread++) {
CloseHandle (hThreads[dwThisThread]);
}
}
return dwStatus;
}
int
WriteTestError (
FILE *pOutput,
DWORD dwTabLevel,
DWORD dwStatus
)
{
DWORD dwIndent;
fwprintf (pOutput, (LPCWSTR)L"\n");
for (dwIndent = 0; dwIndent < dwTabLevel; dwIndent++) {
fwprintf (pOutput, (LPCWSTR)L"\t");
}
fwprintf (pOutput, (LPCWSTR)L"ERROR: \t%s", (szTestErrorMessage != NULL ? szTestErrorMessage : (LPCWSTR)L"No Error"));
fwprintf (pOutput, (LPCWSTR)L"\n");
for (dwIndent = 0; dwIndent < dwTabLevel; dwIndent++) {
fwprintf (pOutput, (LPCWSTR)L"\t");
}
fwprintf (pOutput, (LPCWSTR)L"ERRORCODE:\t0x%8.8x (%d)", dwStatus, dwStatus);
return 0;
}
int
__cdecl
wmain(
int argc,
WCHAR *argv[]
)
{
DWORD dwStatus = ERROR_SUCCESS;
LONG lStatus = ERROR_SUCCESS;
LONG lEnumStatus = ERROR_SUCCESS;
DWORD dwServiceIndex;
WCHAR szServiceSubKeyName[MAX_PATH];
WCHAR szPerfSubKeyName[MAX_PATH+20];
DWORD dwNameSize;
HKEY hKeyPerformance;
DWORD dwLastElement = 0;
DWORD dwIdArray[8];
DWORD dwServiceIds[8];
HKEY hKeyServices;
HKEY hKeyMachine = HKEY_LOCAL_MACHINE;
DWORD dwRegAccessMask = KEY_READ;
DWORD dwTestResult = PERFVAL_NOCONFIG;
DWORD dwGroupTestResult = PERFVAL_NOCONFIG;
BOOL bTestContents;
FILE *pOutput = stdout;
LPWSTR *pNameTable = NULL;
UNREFERENCED_PARAMETER (argc);
UNREFERENCED_PARAMETER (argv);
// enumerate the services to find those with performance counters
hProcessHeap = GetProcessHeap();
hTestHeap = HeapCreate (HEAP_GENERATE_EXCEPTIONS, 0x10000, 0);
if (hTestHeap == NULL) return (ERROR_OUTOFMEMORY);
WriteTestResultHeader(pOutput);
memset (&dwIdArray[0], 0, sizeof(dwIdArray));
pNameTable = BuildNameTable (
(LPCWSTR)L"",
(LPCWSTR)L"009",
&dwLastElement, // size of array in elements
&dwIdArray[0]);
WriteTestConfigData(pOutput, &dwIdArray[0]);
if (pNameTable == NULL) {
// check for name table errors
lStatus = GetLastError(); // so we don't continue
dwTestResult = PERFVAL_FAIL;
WriteTestError (pOutput, 1, lStatus);
} else {
// test config data
lStatus = PerfVal_ConfigTestFunction (pOutput, &dwIdArray[0]);
if (lStatus != ERROR_SUCCESS) {
dwTestResult = PERFVAL_FAIL;
WriteTestError (pOutput, 1, lStatus);
} else {
// assume pass until something fails
dwTestResult = PERFVAL_PASS;
// continue with the test
lStatus = RegOpenKeyExW (hKeyMachine,
cszServiceKeyName,
0L,
dwRegAccessMask,
&hKeyServices);
if (lStatus != ERROR_SUCCESS) {
dwTestResult = PERFVAL_FAIL;
szTestErrorMessage = (LPWSTR)L"Unable to open the HKLM\\SYSTEM\\CurrentControlSet\\Services key";
WriteTestError (pOutput, 1, lStatus);
} else {
// continue processing
dwServiceIndex = 0;
dwNameSize = MAX_PATH;
while ((lEnumStatus = RegEnumKeyExW (
hKeyServices,
dwServiceIndex,
szServiceSubKeyName,
&dwNameSize,
NULL,
NULL,
NULL,
NULL)) == ERROR_SUCCESS) {
// assume pass until something fails
dwGroupTestResult = PERFVAL_PASS;
//try to open the perfkey under this key.
lstrcpyW (szPerfSubKeyName, szServiceSubKeyName);
lstrcatW (szPerfSubKeyName, cszPerformance);
lStatus = RegOpenKeyExW (
hKeyServices,
szPerfSubKeyName,
0L,
dwRegAccessMask,
&hKeyPerformance);
if (lStatus == ERROR_SUCCESS) {
WriteGroupHeader (pOutput, szServiceSubKeyName);
if (IsMsService (szServiceSubKeyName)) {
dwServiceIds[4] = 1;
} else {
dwServiceIds[4] = 0;
}
lStatus = WriteGroupConfig (pOutput, hKeyPerformance, &dwServiceIds[0]);
if (lStatus == ERROR_SUCCESS) {
// test this service
lStatus = PerfVal_ServiceTestConfig (pOutput,
&dwServiceIds[0], pNameTable, dwLastElement);
}
if ((lStatus == ERROR_SUCCESS) || (lStatus == ERROR_BADKEY)){
bTestContents = (lStatus == ERROR_BADKEY ? TRUE : FALSE);
lStatus = PerfVal_ServiceTestFunction (pOutput,
szServiceSubKeyName, hKeyPerformance, bTestContents, pNameTable, dwLastElement);
}
if (lStatus != ERROR_SUCCESS) {
if (lStatus != ERROR_SERVICE_DISABLED) {
// if the service is disabled, then it's a pass,
// otherwise it's failed in the configuration.
dwGroupTestResult = PERFVAL_FAIL;
dwTestResult = PERFVAL_FAIL;
} else {
dwGroupTestResult = PERFVAL_NOCONFIG;
}
}
WriteGroupTrailer(pOutput, dwGroupTestResult);
RegCloseKey (hKeyPerformance);
}
// reset for next loop
dwServiceIndex++;
dwNameSize = MAX_PATH;
}
RegCloseKey (hKeyServices);
}
}
}
WriteTestResultTrailer(pOutput, dwTestResult);
HeapDestroy (hTestHeap);
return (int)dwStatus;
}