2597 lines
93 KiB
C
2597 lines
93 KiB
C
/*++
|
||
|
||
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)<Data);
|
||
} else {
|
||
// create threads
|
||
for (dwThisThread = 0; dwThisThread < dwThreadCount; dwThisThread++) {
|
||
hThreads[dwThisThread] = CreateThread(
|
||
NULL, 0L, CycleThreadProc, (LPVOID)<Data, 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;
|
||
}
|