/*++ Copyright (c) 1998 Microsoft Corporation Module Name: ctrtest.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 "strings.h" #include "ctrtest.h" /////////////////////////////////////////////////////////////////////////////////////// // // Data Structures // /////////////////////////////////////////////////////////////////////////////////////// typedef struct _LOCAL_THREAD_DATA { DWORD dwNumObjects; DWORD dwCycleCount; DWORD dwLoopCount; BOOL bTestContents; BOOL bDisplay; BOOL bStopOnError; } LOCAL_THREAD_DATA, *PLOCAL_THREAD_DATA; /////////////////////////////////////////////////////////////////////////////////////// // // Globals & Constants // /////////////////////////////////////////////////////////////////////////////////////// HANDLE g_hEvent; EXT_OBJECT* g_pExtObjects = NULL; LOCAL_THREAD_DATA g_LTData; BOOL g_fRand = FALSE; FILE* g_pOutput = NULL; LPWSTR* g_pNameTable; DWORD g_dwLastIndex; HANDLE g_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 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 * 8)) #define PERFLIB_TIMER_INTERVAL 200 // 200 ms Timer /////////////////////////////////////////////////////////////////////////////////////// // // Code // /////////////////////////////////////////////////////////////////////////////////////// DWORD InitializeExtObj(EXT_OBJECT* pExtObj) { DWORD dwStatus = ERROR_SUCCESS; BOOL bUseQueryFn = FALSE; DWORD dwType; DWORD dwSize; DWORD dwMemBlockSize = 0; //sizeof(EXT_OBJECT); DWORD dwOpenTimeout; DWORD dwCollectTimeout; DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION]; DWORD dwObjIndex = 0; DWORD dwLinkageStringLen = 0; DWORD dwFlags = 0; DWORD dwKeep; 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]; WCHAR szServicePath[MAX_PATH]; WCHAR szMutexName[MAX_PATH]; WCHAR szPID[32]; LPBYTE szStringBlock; LPSTR pNextStringA; LPWSTR pNextStringW; LPWSTR szThisChar; LPWSTR szThisObject; HKEY hServicesKey = NULL; HKEY hPerfKey = NULL; LPWSTR szServiceName; HKEY hKeyLinkage; HeapValidate (g_hTestHeap, 0, NULL); if (pExtObj == NULL) { dwStatus = ERROR_INVALID_DATA; } else { // Open the performance subkey lstrcpyW (szServicePath, cszHklmServicesKey); dwStatus = RegOpenKeyExW (HKEY_LOCAL_MACHINE, szServicePath, 0, KEY_READ, &hServicesKey); lstrcpyW (szServicePath, pExtObj->szServiceName); lstrcatW (szServicePath, cszPerformance); dwStatus = RegOpenKeyExW (hServicesKey, szServicePath, 0, KEY_READ, &hPerfKey); szServiceName = (LPWSTR)pExtObj->szServiceName; if ( ERROR_SUCCESS != dwStatus ) { dwStatus = ERROR_INVALID_DATA; } // Read the performance DLL name if (dwStatus == ERROR_SUCCESS) { dwType = 0; dwSize = sizeof(szLibraryString); memset (szLibraryString, 0, sizeof(szLibraryString)); memset (szLibraryExpPath, 0, sizeof(szLibraryExpPath)); dwStatus = RegQueryValueExW (hPerfKey, cszDLLValue, NULL, &dwType, (LPBYTE)szLibraryString, &dwSize); if (dwStatus == ERROR_SUCCESS) { if (dwType == REG_EXPAND_SZ) { // expand any environment vars dwSize = ExpandEnvironmentStringsW( szLibraryString, szLibraryExpPath, MAX_PATH); if ((dwSize > MAX_PATH) || (dwSize == 0)) { dwStatus = 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)) { dwStatus = ERROR_INVALID_DLL; } else { dwSize += 1; dwSize *= sizeof(WCHAR); dwMemBlockSize += DWORD_MULTIPLE(dwSize); } } else { dwStatus = ERROR_INVALID_DLL; } } } // Open Function if (dwStatus == ERROR_SUCCESS) { dwType = 0; dwSize = sizeof(szOpenProcName); memset (szOpenProcName, 0, sizeof(szOpenProcName)); dwStatus = RegQueryValueExA (hPerfKey, caszOpenValue, NULL, &dwType, (LPBYTE)szOpenProcName, &dwSize); } // Open Timeout if (dwStatus == 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); dwStatus = RegQueryValueExW (hPerfKey, cszOpenTimeout, NULL, &dwType, (LPBYTE)&dwOpenTimeout, &dwSize); // if error, then apply default if ((dwStatus != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwOpenTimeout = 10000; dwStatus = ERROR_SUCCESS; } } // Close Function if (dwStatus == ERROR_SUCCESS) { dwType = 0; dwSize = sizeof(szCloseProcName); memset (szCloseProcName, 0, sizeof(szCloseProcName)); dwStatus = RegQueryValueExA (hPerfKey, caszCloseValue, NULL, &dwType, (LPBYTE)szCloseProcName, &dwSize); } // Collect Function if (dwStatus == 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)); dwStatus = RegQueryValueExA (hPerfKey, caszQueryValue, NULL, &dwType, (LPBYTE)szCollectProcName, &dwSize); if (dwStatus == 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)); dwStatus = RegQueryValueExA (hPerfKey, caszCollectValue, NULL, &dwType, (LPBYTE)szCollectProcName, &dwSize); if (dwStatus == ERROR_SUCCESS) { // add in size of Collect Function Name // the size value includes the Term. NULL dwMemBlockSize += DWORD_MULTIPLE(dwSize); } } } // Collect Timeout if (dwStatus == ERROR_SUCCESS) { // we have the procedure name so get the timeout value dwType = 0; dwSize = sizeof(dwCollectTimeout); dwStatus = RegQueryValueExW (hPerfKey, cszCollectTimeout, NULL, &dwType, (LPBYTE)&dwCollectTimeout, &dwSize); // if error, then apply default if ((dwStatus != ERROR_SUCCESS) || (dwType != REG_DWORD)) { dwCollectTimeout = 10000; dwStatus = ERROR_SUCCESS; } } // Object List if (dwStatus == ERROR_SUCCESS) { dwType = 0; dwSize = sizeof(mszObjectList); memset (mszObjectList, 0, sizeof(mszObjectList)); dwStatus = RegQueryValueExW (hPerfKey, cszObjListValue, NULL, &dwType, (LPBYTE)mszObjectList, &dwSize); if (dwStatus == 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 dwStatus = ERROR_SUCCESS; } } // Keep Resident if (dwStatus == ERROR_SUCCESS) { dwType = 0; dwKeep = 0; dwSize = sizeof(dwKeep); dwStatus = RegQueryValueExW (hPerfKey, cszKeepResident, NULL, &dwType, (LPBYTE)&dwKeep, &dwSize); if ((dwStatus == ERROR_SUCCESS) && (dwType == REG_DWORD)) { if (dwKeep == 1) { dwFlags |= PERF_EO_KEEP_RESIDENT; } else { // no change. } } else { // not fatal, just use the defaults. dwStatus = ERROR_SUCCESS; } } // Linkage if (dwStatus == ERROR_SUCCESS) { memset (szLinkageString, 0, sizeof(szLinkageString)); lstrcpyW (szLinkageKeyPath, szServiceName); lstrcatW (szLinkageKeyPath, cszLinkageKey); dwStatus = RegOpenKeyExW ( hServicesKey, szLinkageKeyPath, 0L, KEY_READ, &hKeyLinkage); if (dwStatus == ERROR_SUCCESS) { // look up export value string dwSize = sizeof(szLinkageString); dwType = 0; dwStatus = RegQueryValueExW ( hKeyLinkage, cszExportValue, NULL, &dwType, (LPBYTE)&szLinkageString, &dwSize); if ((dwStatus != 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 dwStatus = 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 dwStatus = ERROR_SUCCESS; } } if (hServicesKey != NULL) RegCloseKey (hServicesKey); if (hPerfKey != NULL) RegCloseKey (hPerfKey); // Copy data to Performance Library Data Structure if (dwStatus == ERROR_SUCCESS) { // allocate and initialize a new ext. object block szStringBlock = (LPBYTE)HeapAlloc(g_hTestHeap, HEAP_ZERO_MEMORY, dwMemBlockSize); if (szStringBlock != NULL) { // copy values to new buffer (all others are NULL) pNextStringA = (LPSTR)szStringBlock; // copy Open Procedure Name pExtObj->szOpenProcName = pNextStringA; lstrcpyA (pNextStringA, szOpenProcName); pNextStringA += lstrlenA (pNextStringA) + 1; pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA); pExtObj->dwOpenTimeout = dwOpenTimeout; // copy collect function or query function, depending pExtObj->szCollectProcName = pNextStringA; lstrcpyA (pNextStringA, szCollectProcName); pNextStringA += lstrlenA (pNextStringA) + 1; pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA); pExtObj->dwCollectTimeout = dwCollectTimeout; // copy Close Procedure Name pExtObj->szCloseProcName = pNextStringA; lstrcpyA (pNextStringA, szCloseProcName); pNextStringA += lstrlenA (pNextStringA) + 1; pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA); // copy Library path pNextStringW = (LPWSTR)pNextStringA; pExtObj->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) { pExtObj->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); } // load flags if (bUseQueryFn) { dwFlags |= PERF_EO_QUERY_FUNC; } pExtObj->dwFlags = dwFlags; // load Object array if (dwObjIndex > 0) { pExtObj->dwNumObjects = dwObjIndex; memcpy (pExtObj->dwObjList, dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0]))); } pExtObj->llLastUsedTime = 0; // create Mutex name lstrcpyW (szMutexName, pExtObj->szServiceName); lstrcatW (szMutexName, (LPCWSTR)L"_Perf_Library_Lock_PID_"); _ultow ((ULONG)GetCurrentProcessId(), szPID, 16); lstrcatW (szMutexName, szPID); pExtObj->hMutex = CreateMutexW (NULL, FALSE, szMutexName); pExtObj->bValid = TRUE; } else { dwStatus = ERROR_OUTOFMEMORY; } } } HeapValidate (g_hTestHeap, 0, NULL); if (ERROR_SUCCESS != dwStatus) { pExtObj->bValid = FALSE; } return dwStatus; } DWORD FinializeExtObj(PEXT_OBJECT pInfo) { DWORD dwStatus = ERROR_SUCCESS; // then close everything if (pInfo->hMutex != NULL) { CloseHandle (pInfo->hMutex); pInfo->hMutex = NULL; } if ( NULL != pInfo->szOpenProcName ) HeapFree(g_hTestHeap, 0, pInfo->szOpenProcName); if ( NULL != pInfo->szServiceName ) HeapFree(g_hTestHeap, 0, pInfo->szServiceName); if ( NULL != pInfo->szQueryString ) HeapFree(g_hTestHeap, 0, pInfo->szQueryString); return dwStatus; } DWORD OpenLibrary ( EXT_OBJECT *pExtObj) { DWORD dwStatus = ERROR_SUCCESS; DWORD dwOpenEvent; UINT nErrorMode; // check to see if the library has already been opened LARGE_INTEGER liStartTime, liEndTime, liFreq; if (pExtObj != NULL) { // then load library & look up functions nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS); pExtObj->hLibrary = LoadLibraryExW (pExtObj->szLibraryName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (pExtObj->hLibrary != NULL) { // lookup function names pExtObj->OpenProc = (OPENPROC)GetProcAddress( pExtObj->hLibrary, pExtObj->szOpenProcName); if (pExtObj->OpenProc == NULL) { wprintf ((LPCWSTR)L"\nOpen Procedure \"%s\" not found in \"%s\"", pExtObj->szOpenProcName, pExtObj->szLibraryName); } } else { // unable to load library fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tLoadLibraryEx Failed for the \"%s\" Performance Library", GetCurrentThreadId(), pExtObj->szServiceName); dwStatus = GetLastError(); } if (dwStatus == ERROR_SUCCESS) { if (pExtObj->dwFlags & PERF_EO_QUERY_FUNC) { pExtObj->QueryProc = (QUERYPROC)GetProcAddress ( pExtObj->hLibrary, pExtObj->szCollectProcName); pExtObj->CollectProc = (COLLECTPROC)pExtObj->QueryProc; } else { pExtObj->CollectProc = (COLLECTPROC)GetProcAddress ( pExtObj->hLibrary, pExtObj->szCollectProcName); pExtObj->QueryProc = (QUERYPROC)pExtObj->CollectProc; } if (pExtObj->CollectProc == NULL) { wprintf ((LPCWSTR)L"\nCollect Procedure \"%s\" not found in \"%s\"", pExtObj->szCollectProcName, pExtObj->szLibraryName); } } if (dwStatus == ERROR_SUCCESS) { pExtObj->CloseProc = (CLOSEPROC)GetProcAddress ( pExtObj->hLibrary, pExtObj->szCloseProcName); if (pExtObj->CloseProc == NULL) { wprintf ((LPCWSTR)L"\nClose Procedure \"%s\" not found in \"%s\"", pExtObj->szCloseProcName, pExtObj->szLibraryName); } } if (dwStatus == ERROR_SUCCESS) { __try { if ((pExtObj->hMutex != NULL) && (pExtObj->OpenProc != NULL)){ dwStatus = WaitForSingleObject ( pExtObj->hMutex, pExtObj->dwOpenTimeout); if (dwStatus != WAIT_TIMEOUT) { QueryPerformanceCounter (&liStartTime); // dwStatus = (*pExtObj->OpenProc)(pExtObj->szLinkageString); QueryPerformanceCounter (&liEndTime); // release the lock ReleaseMutex(pExtObj->hMutex); if ( dwStatus != ERROR_SUCCESS ) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \t%S failed for the \"%s\" Performance Library: 0x%X", GetCurrentThreadId(), pExtObj->szOpenProcName, pExtObj->szServiceName, dwStatus); } } else { pExtObj->dwLockoutCount++; } } else { dwStatus = ERROR_LOCK_FAILED; } // check the result. if (dwStatus != ERROR_SUCCESS) { dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE; } else { InterlockedIncrement((LONG *)&pExtObj->dwOpenCount); pExtObj->llFunctionTime = liEndTime.QuadPart - liStartTime.QuadPart; pExtObj->llOpenTime += pExtObj->llFunctionTime; } } __except (EXCEPTION_EXECUTE_HANDLER) { dwStatus = GetExceptionCode(); dwOpenEvent = WBEMPERF_OPEN_PROC_EXCEPTION; } } QueryPerformanceFrequency (&liFreq); pExtObj->llTimeBase = liFreq.QuadPart; if (dwStatus != ERROR_SUCCESS) { // clear fields pExtObj->OpenProc = NULL; pExtObj->CollectProc = NULL; pExtObj->QueryProc = NULL; pExtObj->CloseProc = NULL; if (pExtObj->hLibrary != NULL) { FreeLibrary (pExtObj->hLibrary); pExtObj->hLibrary = NULL; } } else { GetSystemTimeAsFileTime ((FILETIME *)&pExtObj->llLastUsedTime); } } // else no buffer returned return dwStatus; } DWORD ClearSafeBuffer( PSAFE_BUFFER pSafeBufferBlock ) { DWORD dwStatus = ERROR_SUCCESS; if (pSafeBufferBlock != NULL) { if (pSafeBufferBlock->lpBuffer != NULL) HeapFree (g_hTestHeap, 0, pSafeBufferBlock->lpBuffer); pSafeBufferBlock->lpLowGuardPage = NULL; pSafeBufferBlock->lpHiGuardPage = NULL; pSafeBufferBlock->lpEndPointer = NULL; pSafeBufferBlock->lpBuffer = NULL; pSafeBufferBlock->lpSafeBuffer = NULL; pSafeBufferBlock->lpCallBuffer = NULL; } else { dwStatus = ERROR_INVALID_DATA; } return dwStatus; } DWORD CreateSafeBuffer( PSAFE_BUFFER pSafeBufferBlock ) { DWORD dwStatus = ERROR_SUCCESS; if (NULL == pSafeBufferBlock) { dwStatus = ERROR_INVALID_DATA; } if (dwStatus == ERROR_SUCCESS) { if (pSafeBufferBlock->lpBuffer != NULL) HeapFree (g_hTestHeap, 0, pSafeBufferBlock->lpBuffer); pSafeBufferBlock->dwBufSize += pSafeBufferBlock->dwBufSizeIncrement; pSafeBufferBlock->dwCallBufSize = pSafeBufferBlock->dwBufSize; pSafeBufferBlock->lpBuffer = HeapAlloc (g_hTestHeap, HEAP_ZERO_MEMORY, pSafeBufferBlock->dwBufSize + (2*GUARD_PAGE_SIZE)); if (NULL != pSafeBufferBlock->lpBuffer) { // set buffer pointers pSafeBufferBlock->lpLowGuardPage = pSafeBufferBlock->lpBuffer; pSafeBufferBlock->lpSafeBuffer = (LPBYTE)pSafeBufferBlock->lpBuffer + GUARD_PAGE_SIZE; pSafeBufferBlock->lpCallBuffer = pSafeBufferBlock->lpSafeBuffer; pSafeBufferBlock->lpHiGuardPage = (LPBYTE)pSafeBufferBlock->lpCallBuffer + pSafeBufferBlock->dwBufSize; pSafeBufferBlock->lpEndPointer = (LPBYTE)pSafeBufferBlock->lpHiGuardPage + GUARD_PAGE_SIZE; memset (pSafeBufferBlock->lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE); memset (pSafeBufferBlock->lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE); } else { dwStatus = ERROR_OUTOFMEMORY; } } if (dwStatus != ERROR_SUCCESS) { dwStatus = ClearSafeBuffer( pSafeBufferBlock ); } return dwStatus; } DWORD CheckGuardBytes( PSAFE_BUFFER pSafeBufferBlock, PEXT_OBJECT pObj ) { DWORD dwStatus = ERROR_SUCCESS; LPDWORD lpCheckPointer; // // check for buffer corruption here // if (lExtCounterTestLevel <= EXT_TEST_BASIC) { // // check 1: bytes left should be the same as // new data buffer ptr - orig data buffer ptr // if (pSafeBufferBlock->dwCallBufSize != (DWORD)((LPBYTE)pSafeBufferBlock->lpCallBuffer - (LPBYTE)pSafeBufferBlock->lpSafeBuffer)) { pObj->dwBadPointers++; dwStatus = ERROR_INVALID_DATA; } // // check 2: buffer after ptr should be < hi Guard page ptr // if ((dwStatus == ERROR_SUCCESS) && ((LPBYTE)pSafeBufferBlock->lpCallBuffer >= (LPBYTE)pSafeBufferBlock->lpHiGuardPage)) { // see if they exceeded the allocated memory if ((LPBYTE)pSafeBufferBlock->lpCallBuffer >= (LPBYTE)pSafeBufferBlock->lpEndPointer) { // even worse!! } pObj->dwBufferSizeErrors++; dwStatus = ERROR_INVALID_DATA; } // // check 3: check lo guard page for corruption // if (dwStatus == ERROR_SUCCESS ) { for (lpCheckPointer = (LPDWORD)pSafeBufferBlock->lpLowGuardPage; lpCheckPointer < (LPDWORD)pSafeBufferBlock->lpSafeBuffer; lpCheckPointer++) { if (*lpCheckPointer != GUARD_PAGE_DWORD) { pObj->dwLowerGPViolations++; dwStatus = ERROR_INVALID_DATA; break; } } } // // check 4: check hi guard page for corruption // if (dwStatus == ERROR_SUCCESS) { for (lpCheckPointer = (LPDWORD)pSafeBufferBlock->lpHiGuardPage; lpCheckPointer < (LPDWORD)pSafeBufferBlock->lpEndPointer; lpCheckPointer++) { if (*lpCheckPointer != GUARD_PAGE_DWORD) { pObj->dwUpperGPViolations++; dwStatus = ERROR_INVALID_DATA; break; } } } } if (dwStatus != ERROR_SUCCESS) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tGuardbyte violation for the \"%s\" Performance Library: 0x%X", GetCurrentThreadId(), pObj->szServiceName, dwStatus); } return dwStatus; } DWORD ValidateBuffer( PSAFE_BUFFER pSafeBufferBlock, EXT_OBJECT *pThisExtObj ) { DWORD dwStatus = ERROR_SUCCESS; DWORD dwObjectBufSize; DWORD dwIndex; LONG lInstIndex; PERF_OBJECT_TYPE *pObject, *pNextObject; PERF_INSTANCE_DEFINITION *pInstance; PERF_DATA_BLOCK *pPerfData; BOOL bForeignDataBuffer; if (NULL == pSafeBufferBlock) { dwStatus = ERROR_INVALID_DATA; } // Validate the blob size if ( dwStatus == ERROR_SUCCESS ) { if (( pSafeBufferBlock->dwCallBufSize < 0 ) || ( pSafeBufferBlock->dwCallBufSize > pSafeBufferBlock->dwBufSize )) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tBuffer size parameter does not match the buffer displacement in the data returned for the \"%s\" performance library", GetCurrentThreadId(), pThisExtObj->szServiceName); pThisExtObj->dwBufferSizeErrors++; dwStatus = ERROR_INVALID_PARAMETER; } } // Validate the byte alignment if (dwStatus == ERROR_SUCCESS) { if (pSafeBufferBlock->dwCallBufSize & 0x00000007) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tByte Allignment Error in the data returned for the \"%s\" performance library", GetCurrentThreadId(), pThisExtObj->szServiceName); pThisExtObj->dwAlignmentErrors++; dwStatus = ERROR_INVALID_DATA; } } if ( dwStatus == ERROR_SUCCESS ) { dwStatus = CheckGuardBytes( pSafeBufferBlock, pThisExtObj ); } if ((lExtCounterTestLevel <= EXT_TEST_ALL) && (dwStatus == ERROR_SUCCESS)) { // // 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 *)pSafeBufferBlock->lpSafeBuffer; 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 *)pSafeBufferBlock->lpSafeBuffer; 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 < pThisExtObj->dwNumObjectsRet; dwIndex++) { dwObjectBufSize += pObject->TotalByteLength; pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject + pObject->TotalByteLength); } if (((LPBYTE)pObject != (LPBYTE)pSafeBufferBlock->lpCallBuffer) || (dwObjectBufSize > pSafeBufferBlock->dwCallBufSize)) { // then a length field is incorrect. This is FATAL // since it can corrupt the rest of the buffer // and render the buffer unusable. fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tObject in blob overruns the buffer boundary in the data returned for the \"%s\" Performance Library", GetCurrentThreadId(), pThisExtObj->szServiceName); pThisExtObj->dwObjectSizeErrors++; dwStatus = ERROR_INVALID_DATA; } // // Test 6: Test instance field size values // if (dwStatus == ERROR_SUCCESS) { // 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 *)pSafeBufferBlock->lpSafeBuffer; } for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjectsRet; 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; // NOTE: this does not walk the instance/counter block, nor does it check the validity of the addresses pCounterBlock = (PERF_COUNTER_BLOCK *) ((PCHAR) pInstance + pInstance->ByteLength); pInstance = (PERF_INSTANCE_DEFINITION *) ((PCHAR) pCounterBlock + pCounterBlock->ByteLength); lInstIndex++; } if ((LPBYTE)pInstance > (LPBYTE)pNextObject) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tInsatnce data overruns the following object data in the data returned for the \"%s\" Performance Library", GetCurrentThreadId(), pThisExtObj->szServiceName); dwStatus = ERROR_INVALID_DATA; } } if (dwStatus != ERROR_SUCCESS) { break; } else { pObject = pNextObject; } } if (dwStatus != ERROR_SUCCESS) { pThisExtObj->dwInstanceSizeErrors++; } } } return dwStatus; } DWORD ValidateBlob( PSAFE_BUFFER pSafeBufferBlock, EXT_OBJECT *pThisExtObj ) { DWORD dwStatus = ERROR_SUCCESS; DWORD nObjIdx, nCtrIdx; DWORD dwLastId = g_dwLastIndex; PERF_OBJECT_TYPE * pObjDef = NULL; PERF_COUNTER_DEFINITION * pCtrDef; // Validate the data // ================= if (pSafeBufferBlock->dwBufSize >= MAX_BUF_SIZE) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tCollectFunction for %s requires a buffer > %d bytes", GetCurrentThreadId(), pThisExtObj->szServiceName, MAX_BUF_SIZE); if (pSafeBufferBlock->lpBuffer != NULL) HeapFree (g_hTestHeap, 0, pSafeBufferBlock->lpBuffer); dwStatus = ERROR_INVALID_PARAMETER; } else if (pSafeBufferBlock->lpBuffer == NULL) { dwStatus = ERROR_OUTOFMEMORY; } else { // Validate the objects // ==================== pObjDef = (PERF_OBJECT_TYPE *)pSafeBufferBlock->lpSafeBuffer; for (nObjIdx = 0; nObjIdx < pThisExtObj->dwNumObjectsRet; nObjIdx++) { // test object name & help if ((pObjDef->ObjectNameTitleIndex <= dwLastId) && (pObjDef->ObjectNameTitleIndex > 0)) { if (g_pNameTable[pObjDef->ObjectNameTitleIndex ] == NULL) { // no string fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR:\tNo Object Name Display String for index %d", GetCurrentThreadId(), pObjDef->ObjectNameTitleIndex ); dwStatus = ERROR_BADKEY; } else { // probably ok } } else { // id out of range fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR:\tObject Name Index values are bad or missing", GetCurrentThreadId()); dwStatus = ERROR_BADKEY; } if ((pObjDef->ObjectHelpTitleIndex <= dwLastId) && (pObjDef->ObjectHelpTitleIndex> 0)) { if (g_pNameTable[pObjDef->ObjectHelpTitleIndex] == NULL) { // no string fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR:\tNo Object Help Display String for index %d", GetCurrentThreadId(), pObjDef->ObjectHelpTitleIndex ); dwStatus = ERROR_BADKEY; } else { // probably ok } } else { // id out of range fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR:\tObject Help Index values are bad or missing", GetCurrentThreadId()); dwStatus = ERROR_BADKEY; } // Validate the counters // ===================== pCtrDef = FirstCounter (pObjDef); for (nCtrIdx = 0; nCtrIdx < pObjDef->NumCounters; nCtrIdx++) { if ((pCtrDef->CounterNameTitleIndex <= dwLastId) && (pCtrDef->CounterNameTitleIndex > 0)) { if ((g_pNameTable[pCtrDef->CounterNameTitleIndex ] == NULL) && ((pCtrDef->CounterType & PERF_COUNTER_BASE) == 0)) { // no string fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR:\tNo Counter Name Display String for index %d", GetCurrentThreadId(), pCtrDef->CounterNameTitleIndex ); dwStatus = ERROR_BADKEY; } else { // probably ok } } else { // id out of range fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR:\tCounter Name Index values are bad or missing", GetCurrentThreadId()); dwStatus = ERROR_BADKEY; } // test counter defs if ((pCtrDef->CounterHelpTitleIndex <= dwLastId) && (pCtrDef->CounterHelpTitleIndex> 0)) { if ((g_pNameTable[pCtrDef->CounterHelpTitleIndex] == NULL) && ((pCtrDef->CounterType & PERF_COUNTER_BASE) == 0)) { // no string fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR:\tNo Counter Help Display String for index %d", GetCurrentThreadId(), pCtrDef->CounterHelpTitleIndex ); dwStatus = ERROR_BADKEY; } else { // probably ok } } else { // id out of range fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR:\tCounter Help Index values are bad or missing", GetCurrentThreadId()); dwStatus = ERROR_BADKEY; } if (nCtrIdx < ( pObjDef->NumCounters - 1 ) ) pCtrDef = NextCounter (pCtrDef); } if ( nObjIdx < ( pThisExtObj->dwNumObjectsRet - 1 ) ) pObjDef = NextObject (pObjDef); } } return dwStatus; } DWORD Validate( PSAFE_BUFFER pSafeBufferBlock, EXT_OBJECT *pThisExtObj ) { DWORD dwStatus = ERROR_SUCCESS; dwStatus = ValidateBuffer( pSafeBufferBlock, pThisExtObj ); if (dwStatus == ERROR_SUCCESS) { dwStatus = ValidateBlob( pSafeBufferBlock, pThisExtObj ); if ( dwStatus != ERROR_SUCCESS ) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tBlob Data Validation failed for the \"%s\" Performance Library: 0x%X", GetCurrentThreadId(), pThisExtObj->szServiceName, dwStatus); } } else { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tBuffer Validation failed for the \"%s\" Performance Library: 0x%X", GetCurrentThreadId(), pThisExtObj->szServiceName, dwStatus); } return dwStatus; } //*************************************************************************** // // 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) { DWORD dwStatus = ERROR_SUCCESS; // Failure code SAFE_BUFFER SafeBufferBlock; // Buffer block DWORD NumObjectTypes = 0; // Number of object returned from collection function LARGE_INTEGER liStartTime, // Collect start time liEndTime, // Collect end time liFreq; // Timer frequency DOUBLE dMs = 0; // Timer data memset(&SafeBufferBlock, 0, sizeof(SAFE_BUFFER)); SafeBufferBlock.dwBufSize = 4098; SafeBufferBlock.dwBufSizeIncrement = 1024; // Collect the data // ================ dwStatus = ERROR_MORE_DATA; while ((dwStatus == ERROR_MORE_DATA) && (SafeBufferBlock.dwBufSize < MAX_BUF_SIZE)) { // allocate a local block of memory to pass to the // extensible counter function. dwStatus = CreateSafeBuffer( &SafeBufferBlock ); if ( dwStatus == ERROR_SUCCESS ) { // initialize values to pass to the extensible counter function NumObjectTypes = 0; if ((pThisExtObj->hMutex != NULL) && (pThisExtObj->CollectProc != NULL)) { dwStatus = WaitForSingleObject ( pThisExtObj->hMutex, pThisExtObj->dwCollectTimeout); if (dwStatus != WAIT_TIMEOUT) { __try { QueryPerformanceCounter (&liStartTime); { LPBYTE pBuffer = SafeBufferBlock.lpCallBuffer; DWORD dwBufSize = SafeBufferBlock.dwCallBufSize; dwStatus = (*pThisExtObj->CollectProc) ( (LPWSTR)pThisExtObj->szQueryString, &pBuffer, &dwBufSize, &NumObjectTypes); SafeBufferBlock.dwCallBufSize = dwBufSize; SafeBufferBlock.lpCallBuffer = pBuffer; } QueryPerformanceCounter (&liEndTime); if (( dwStatus != ERROR_SUCCESS ) && ( dwStatus != ERROR_MORE_DATA )) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \t%S failed for the \"%s\" Performance Library: 0x%X", GetCurrentThreadId(), pThisExtObj->szCollectProcName, pThisExtObj->szServiceName, dwStatus); } } __except (EXCEPTION_EXECUTE_HANDLER) { dwStatus = GetExceptionCode(); InterlockedIncrement ((LONG *)&pThisExtObj->dwExceptionCount); } ReleaseMutex (pThisExtObj->hMutex); } else { pThisExtObj->dwLockoutCount++; } } else { dwStatus = ERROR_LOCK_FAILED; } } // if CreateSafeBuffer() } // While // Copy the data // ============= if (dwStatus == ERROR_SUCCESS) { // Validate the collection time if (dwStatus == ERROR_SUCCESS) { liFreq.QuadPart = 0; QueryPerformanceFrequency (&liFreq); pThisExtObj->llTimeBase = liFreq.QuadPart; 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) { dwStatus = ERROR_TIMEOUT; } } // Copy the data if (dwStatus == ERROR_SUCCESS) { // External object data GetSystemTimeAsFileTime((FILETIME*)&pThisExtObj->llLastUsedTime); pThisExtObj->dwNumObjectsRet = NumObjectTypes; pThisExtObj->dwRetBufSize = SafeBufferBlock.dwCallBufSize; // increment perf counters InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount); } // Validate the data if ((dwStatus == ERROR_SUCCESS) && (g_LTData.bTestContents)) { dwStatus = Validate( &SafeBufferBlock, pThisExtObj ); } } ClearSafeBuffer(&SafeBufferBlock); if ((dwStatus != ERROR_SUCCESS) && (dwStatus != WAIT_TIMEOUT)) // don't count timeouts as function errors { InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount); } return dwStatus; } DWORD CloseLibrary ( EXT_OBJECT *pInfo ) { DWORD dwStatus = ERROR_SUCCESS; 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 if ((pInfo->hMutex != NULL) && (pInfo->CloseProc != NULL)){ dwStatus = WaitForSingleObject ( pInfo->hMutex, pInfo->dwOpenTimeout); if (dwStatus != WAIT_TIMEOUT) { if (pInfo->CloseProc != NULL) { dwStatus = (*pInfo->CloseProc) (); if ( dwStatus != ERROR_SUCCESS ) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \t%S failed for the \"%s\" Performance Library: 0x%X", GetCurrentThreadId(), pInfo->szCloseProcName, pInfo->szServiceName, dwStatus); } } ReleaseMutex(pInfo->hMutex); } else { pInfo->dwLockoutCount++; } } else { dwStatus = ERROR_LOCK_FAILED; } if (pInfo->hLibrary != NULL) { FreeLibrary (pInfo->hLibrary); pInfo->hLibrary = NULL; } } return dwStatus; } 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 (g_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 (g_hTestHeap, 0, (LPVOID)lpValueNameString); RegCloseKey (hKeyValue); RegCloseKey (hKeyNames); RegCloseKey(hKeyRegistry); return lpReturnValue; BNT_BAILOUT: if (lWin32Status != ERROR_SUCCESS) { SetLastError (lWin32Status); } if (lpValueNameString) { HeapFree (g_hTestHeap, 0, (LPVOID)lpValueNameString); } if (lpReturnValue) { HeapFree (g_hTestHeap, 0, (LPVOID)lpValueNameString); } if (hKeyValue) RegCloseKey (hKeyValue); if (hKeyNames) RegCloseKey (hKeyNames); if (hKeyRegistry) RegCloseKey(hKeyRegistry); return NULL; } DWORD CycleTest ( DWORD dwThreadId, PEXT_OBJECT pObj ) { DWORD dwStatus = ERROR_SUCCESS; DWORD dwLoopCount = g_LTData.dwLoopCount; BOOL bPrintData = g_LTData.bDisplay; DOUBLE dMs; UNREFERENCED_PARAMETER (dwThreadId); // Open the Library // ================ dwStatus = OpenLibrary (pObj); if ((dwStatus == ERROR_SUCCESS) && (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:INFO_OpenServiceName: \t%s", GetCurrentThreadId(), pObj->szServiceName); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:INFO_OpenProcTime: \t%12.5f mSec", GetCurrentThreadId(), dMs); // fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:INFO_OpenProcTimeout: \t%6d.00000 mSec", GetCurrentThreadId(), pObj->dwOpenTimeout); // check for timeout if (dMs > (DOUBLE)pObj->dwOpenTimeout) { dwStatus = ERROR_TIMEOUT; fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tOpen procedure exceeded timeout", GetCurrentThreadId()); CloseLibrary (pObj); } } else { // no object block returned fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tUnable to open the \"%s\" Performance Library", GetCurrentThreadId(), pObj->szServiceName); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORCODE:\t0x%8.8x (%dL)", GetCurrentThreadId(), dwStatus, dwStatus); } // Collect Data for "dwLoopCount" times // ==================================== if (dwStatus == ERROR_SUCCESS) { HeapValidate (g_hTestHeap, 0, NULL); // call collect function do { // get the data again dwStatus = CollectData (pObj); HeapValidate (g_hTestHeap, 0, NULL); } while (--dwLoopCount > 0); // Close Library // ============= // Even if we get an error, we should try to close the library // =========================================================== CloseLibrary (pObj); // Report Status // ============= if (dwStatus == ERROR_SUCCESS) { // dump collect fn stats. fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:INFO_ServiceName: \t%s", GetCurrentThreadId(), pObj->szServiceName); 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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:INFO_AvgCollectProcTime: \t%12.5f mSec", GetCurrentThreadId(), dMs); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:INFO_CollectProcTimeout: \t%6d.00000 mSec", GetCurrentThreadId(), pObj->dwCollectTimeout); } fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:INFO_ObjectsRet: \t%d", GetCurrentThreadId(), pObj->dwNumObjectsRet); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:INFO_RetBuffSize: \t%d", GetCurrentThreadId(), pObj->dwRetBufSize); } else { fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERROR: \tCollect procedure returned an error", GetCurrentThreadId()); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORCODE:\t0x%8.8x (%dL)", GetCurrentThreadId(), 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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_CollectService: \t%s", GetCurrentThreadId(), pObj->szServiceName); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_CollectProcTime:\t%12.5f mSec", GetCurrentThreadId(), dMs); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_CollectTimeout: \t%6d.00000 mSec", GetCurrentThreadId(), pObj->dwCollectTimeout); } fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_CollectService: \t%s", GetCurrentThreadId(), pObj->szServiceName); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_CollectTime: \t%I64u", GetCurrentThreadId(), pObj->llCollectTime); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_CollectCount:\t%d", GetCurrentThreadId(), pObj->dwCollectCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_OpenCount: \t%d", GetCurrentThreadId(), pObj->dwOpenCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_CloseCount: \t%d", GetCurrentThreadId(), pObj->dwCloseCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_LockoutCount:\t%d", GetCurrentThreadId(), pObj->dwLockoutCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_ErrorCount: \t%d", GetCurrentThreadId(), pObj->dwErrorCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_Exceptions: \t%d", GetCurrentThreadId(), pObj->dwExceptionCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_LowerGPErrs: \t%d", GetCurrentThreadId(), pObj->dwLowerGPViolations); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_UpperGPErrs: \t%d", GetCurrentThreadId(), pObj->dwUpperGPViolations); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_BadPointers: \t%d", GetCurrentThreadId(), pObj->dwBadPointers); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_BufSizeErrs: \t%d", GetCurrentThreadId(), pObj->dwBufferSizeErrors); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_AlignErrors: \t%d", GetCurrentThreadId(), pObj->dwAlignmentErrors); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_ObjSizeErrs: \t%d", GetCurrentThreadId(), pObj->dwObjectSizeErrors); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_InstSizeErrs:\t%d", GetCurrentThreadId(), pObj->dwInstanceSizeErrors); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_TimeBase: \t%I64u", GetCurrentThreadId(), pObj->llTimeBase); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_FunctionTime:\t%I64u", GetCurrentThreadId(), pObj->llFunctionTime); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_ObjectsRet: \t%d", GetCurrentThreadId(), pObj->dwNumObjectsRet); fwprintf (g_pOutput, (LPCWSTR)L"\n\t\t%d:ERRORINFO_RetBuffSize: \t%d", GetCurrentThreadId(), pObj->dwRetBufSize); } } HeapValidate (g_hTestHeap, 0, NULL); return dwStatus; } unsigned __stdcall CycleThreadProc( void * lpThreadArg ) { DWORD dwStatus = ERROR_SUCCESS; DWORD dwCycleCount = g_LTData.dwCycleCount; DWORD dwThreadNum = *((DWORD*)lpThreadArg); PEXT_OBJECT pObj = NULL; EXT_OBJECT ThreadObj; DWORD dwThisThread = GetCurrentThreadId(); HeapValidate (g_hTestHeap, 0, NULL); srand( GetTickCount() ); do { // If the rand flag is set, randomly choose an object to hit if (g_fRand) { pObj = &g_pExtObjects[rand()%g_LTData.dwNumObjects]; } else { pObj = &g_pExtObjects[dwThreadNum]; } if ( pObj->bValid ) { memcpy(&ThreadObj, pObj, sizeof(EXT_OBJECT)); dwStatus = CycleTest(dwThisThread, &ThreadObj); // What error handling mode are we using? if (g_LTData.bStopOnError) { if (( ERROR_SUCCESS != dwStatus ) && (ERROR_INVALID_DATA != dwStatus)) { SetEvent( g_hEvent ); } else { if ( WAIT_OBJECT_0 == WaitForSingleObject( g_hEvent, 0 ) ) break; dwStatus = ERROR_SUCCESS; } } } } while (--dwCycleCount > 0); HeapValidate (g_hTestHeap, 0, NULL); return dwStatus; } DWORD Initialize( WCHAR* szIniFileName, DWORD* pdwThreadCount ) { DWORD dwStatus = ERROR_SUCCESS; BOOL bStatus = FALSE; WCHAR wcsReturnBuff[256]; WCHAR wcsKeyName[256]; DWORD dwCtr = 0; fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_INI_File_Name:\t%s", szIniFileName); fwprintf (g_pOutput, (LPCWSTR)L"\n"); // LTData GetPrivateProfileStringW( L"Main", L"NumObjects", L"0", wcsReturnBuff, 256, szIniFileName ); g_LTData.dwNumObjects = wcstoul(wcsReturnBuff, NULL, 10); GetPrivateProfileStringW( L"Main", L"CycleCount", L"0", wcsReturnBuff, 256, szIniFileName ); g_LTData.dwCycleCount = wcstoul(wcsReturnBuff, NULL, 10); GetPrivateProfileStringW( L"Main", L"LoopCount", L"0", wcsReturnBuff, 256, szIniFileName ); g_LTData.dwLoopCount = wcstoul(wcsReturnBuff, NULL, 10); GetPrivateProfileStringW( L"Main", L"StopOnError", L"0", wcsReturnBuff, 256, szIniFileName ); g_LTData.bStopOnError = wcstoul(wcsReturnBuff, NULL, 10); g_LTData.bDisplay = TRUE; g_LTData.bTestContents = TRUE; // Other GetPrivateProfileStringW( L"Main", L"NumThreads", L"0", wcsReturnBuff, 256, szIniFileName ); *pdwThreadCount = wcstoul(wcsReturnBuff, NULL, 10); if ( *pdwThreadCount < g_LTData.dwNumObjects ) { *pdwThreadCount = g_LTData.dwNumObjects; } GetPrivateProfileStringW( L"Main", L"Random", L"0", wcsReturnBuff, 256, szIniFileName ); g_fRand = wcstoul(wcsReturnBuff, NULL, 10); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Number_Of_Perf_Objects: \t%d", g_LTData.dwNumObjects); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Number_Of_Test_Cycles: \t%d", g_LTData.dwCycleCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Number_Of_Collects_Per_Cycle:\t%d", g_LTData.dwLoopCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Display_Results: \t%s", (g_LTData.bDisplay?L"Yes":L"No")); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Validate_Data: \t%s", (g_LTData.bTestContents?L"Yes":L"No")); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Number_Of_Threads: \t%d", *pdwThreadCount); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Randomize_Perf_Objects: \t%s", (g_fRand?L"Yes":L"No")); fwprintf (g_pOutput, (LPCWSTR)L"\n"); g_pExtObjects = (EXT_OBJECT*) HeapAlloc(g_hTestHeap, HEAP_ZERO_MEMORY, g_LTData.dwNumObjects * sizeof(EXT_OBJECT)); if ( NULL != g_pExtObjects ) { for( dwCtr = 0; dwCtr < g_LTData.dwNumObjects; dwCtr++ ) { // Service name swprintf( wcsKeyName, L"Object%d", dwCtr ); GetPrivateProfileStringW( L"Main", wcsKeyName, L"PerfProc", wcsReturnBuff, 256, szIniFileName ); g_pExtObjects[dwCtr].szServiceName = (WCHAR*) HeapAlloc( g_hTestHeap, 0, ( wcslen( wcsReturnBuff ) + 1 ) * sizeof(WCHAR) ); wcscpy( g_pExtObjects[dwCtr].szServiceName, wcsReturnBuff ); // Query string swprintf( wcsKeyName, L"Counter%d", dwCtr ); GetPrivateProfileStringW( L"Main", wcsKeyName, L"Global", wcsReturnBuff, 256, szIniFileName ); g_pExtObjects[dwCtr].szQueryString = (WCHAR*) HeapAlloc( g_hTestHeap, 0, ( wcslen( wcsReturnBuff ) + 1 ) * sizeof(WCHAR) ); wcscpy( g_pExtObjects[dwCtr].szQueryString, wcsReturnBuff ); // At least one object has to succeed bStatus = ( ( ERROR_SUCCESS == InitializeExtObj( &g_pExtObjects[dwCtr] )) || bStatus); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Perf_Object: \t%s : %s",g_pExtObjects[dwCtr].szServiceName, (g_pExtObjects[dwCtr].bValid?L"Active":L"Inactive")); } } fwprintf (g_pOutput, (LPCWSTR)L"\n"); if (!bStatus) { dwStatus = ERROR_INVALID_DATA; } return dwStatus; } int WriteTestResultHeader() { 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 (g_pOutput, (LPCWSTR)L"\n[TESTRESULT]"); fwprintf (g_pOutput, (LPCWSTR)L"\n\tTEST: \tPerf Counter DLL Validation"); fwprintf (g_pOutput, (LPCWSTR)L"\n\tBUILD: \t%d", osInfo.dwBuildNumber); fwprintf (g_pOutput, (LPCWSTR)L"\n\tMACHINE:\t%s", szMachineName); fwprintf (g_pOutput, (LPCWSTR)L"\n\t%d:START TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d", GetCurrentThreadId(), stStart.wMonth, stStart.wDay, stStart.wYear % 100, stStart.wHour, stStart.wMinute, stStart.wSecond ); return 0; } int WriteTestConfigData( LPDWORD pdwIdInfo ) { fwprintf (g_pOutput, (LPCWSTR)L"\n\t"); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Perflib_LastCounter:\t%d", pdwIdInfo[0]); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_String_LastCounter: \t%d", pdwIdInfo[1]); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Perflib_LastHelp: \t%d", pdwIdInfo[2]); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_String_LastHelp: \t%d", pdwIdInfo[3]); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_Disabled: \t%d", pdwIdInfo[4]); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_ExtCounterTestLevel:\t%d", pdwIdInfo[5]); fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_BaseIndex: \t%d", pdwIdInfo[6]); // fwprintf (g_pOutput, (LPCWSTR)L"\n\tCONFIG_BaseOsObject : \t%d", pdwIdInfo[7]); return 0; } DWORD WriteGroupConfig( 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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:ONFIG_Library:\t%s", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Open:\t%s", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Collect:\t%s", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Object List:\t%s", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Close:\t%s", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_First Counter:\t%d", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Last Counter:\t%d", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_First Help:\t%d", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Last Help:\t%d", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Open Timeout:\t%d", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Collect Timeout:\t%d", GetCurrentThreadId(), (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 (g_pOutput, (LPCWSTR)L"\n\t\t%d:CONFIG_Disable Performance Counters:\t%d", GetCurrentThreadId(), (lStatus == ERROR_SUCCESS ? dwData : (DWORD)0)); if ((lStatus == ERROR_SUCCESS) && (dwData != 0)){ nRetStatus = ERROR_SERVICE_DISABLED; } return nRetStatus; } int WriteTestResultTrailer( 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 (g_pOutput, (LPCWSTR)L"\n\n\tRESULT: \t%s", szResult); fwprintf (g_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 (g_pOutput, (LPCWSTR)L"\n[/TESTRESULT]"); fwprintf (g_pOutput, (LPCWSTR)L"\n"); return 0; } int WriteGroupHeader( LPCWSTR szGroupName ) { SYSTEMTIME stStart; memset (&stStart, 0, sizeof(stStart)); GetLocalTime (&stStart); fwprintf (g_pOutput, (LPCWSTR)L"\n\n\t[GROUP: %s]", szGroupName); fwprintf (g_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( 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 (g_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 (g_pOutput, (LPCWSTR)L"\n\t\tRESULT: %s", szResult); fwprintf (g_pOutput, (LPCWSTR)L"\n\t[/GROUP]"); return 0; } int WriteTestError ( DWORD dwTabLevel, DWORD dwStatus ) { DWORD dwIndent; fwprintf (g_pOutput, (LPCWSTR)L"\n"); for (dwIndent = 0; dwIndent < dwTabLevel; dwIndent++) { fwprintf (g_pOutput, (LPCWSTR)L"\t"); } fwprintf (g_pOutput, (LPCWSTR)L"%d:ERROR: \t%s", GetCurrentThreadId(), (szTestErrorMessage != NULL ? szTestErrorMessage : (LPCWSTR)L"No Error")); fwprintf (g_pOutput, (LPCWSTR)L"\n"); for (dwIndent = 0; dwIndent < dwTabLevel; dwIndent++) { fwprintf (g_pOutput, (LPCWSTR)L"\t"); } fwprintf (g_pOutput, (LPCWSTR)L"%d:ERRORCODE:\t0x%8.8x (%d)", GetCurrentThreadId(), dwStatus, dwStatus); return 0; } int __cdecl wmain( int argc, WCHAR *argv[] ) { DWORD dwStatus; DWORD dwLastElement = 0; DWORD dwIdArray[8]; DWORD dwTID = 0; DWORD dwObj; DWORD dwTestResult = PERFVAL_NOCONFIG; DWORD dwThreadCount = 0; LOCAL_THREAD_DATA* pCurLTData = NULL; HANDLE hThreads[MAXIMUM_WAIT_OBJECTS]; DWORD dwThisThread; WCHAR* pwcsINIFile = L".\\ctrtest.ini"; BOOL fRand = FALSE; int nIndex = 0; // Set up environment g_hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); if ( NULL == g_hEvent ) return ERROR_INVALID_ACCESS; g_pOutput = stdout; g_hTestHeap = HeapCreate (HEAP_GENERATE_EXCEPTIONS, 0x10000, 0); if (g_hTestHeap == NULL) return (ERROR_OUTOFMEMORY); WriteTestResultHeader(g_pOutput); memset (&dwIdArray[0], 0, sizeof(dwIdArray)); g_pNameTable = BuildNameTable ( (LPCWSTR)L"", (LPCWSTR)L"009", &dwLastElement, // size of array in elements &dwIdArray[0]); g_dwLastIndex = dwLastElement; WriteTestConfigData(&dwIdArray[0]); if (g_pNameTable == NULL) { // check for name table errors dwStatus = GetLastError(); // so we don't continue dwTestResult = PERFVAL_FAIL; WriteTestError (1, dwStatus); } else { if ( argc > 1 ) { pwcsINIFile = argv[1]; } // Load up object/ctr data dwStatus = Initialize( pwcsINIFile, &dwThreadCount ); if ( ERROR_SUCCESS == dwStatus ) { srand( GetTickCount() ); // create threads for (dwThisThread = 0; dwThisThread < dwThreadCount; dwThisThread++) { hThreads[dwThisThread] = (HANDLE) _beginthreadex( NULL, 0, CycleThreadProc, (void*) &dwThisThread, 0, &dwTID ); } // Let these all run through dwStatus = WaitForMultipleObjects (dwThreadCount, hThreads, TRUE, INFINITE); if (dwStatus != WAIT_TIMEOUT) dwStatus = ERROR_SUCCESS; for (dwThisThread = 0; dwThisThread < dwThreadCount; dwThisThread++) { CloseHandle (hThreads[dwThisThread]); } } } WriteTestResultTrailer(dwTestResult); for (dwObj = 0; dwObj < g_LTData.dwNumObjects; dwObj++) { FinializeExtObj(&g_pExtObjects[dwObj]); } if ( NULL != g_pNameTable ) HeapFree(g_hTestHeap, 0, g_pNameTable); if ( NULL != g_pExtObjects ) HeapFree(g_hTestHeap, 0, g_pExtObjects); if ( NULL != g_hTestHeap ) HeapDestroy (g_hTestHeap); CloseHandle( g_hEvent ); return (int)dwStatus; }