/*++ 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 #include #include #include #include #include #include #include #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; }