Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2596 lines
93 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. perfval.c
  5. Abstract:
  6. Program to test the extensible counter dll's
  7. Author:
  8. Bob Watson (bobw) 8 Feb 99
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <winperf.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <pdhmsg.h>
  19. #include "strings.h"
  20. #include "perfval.h"
  21. #define MAX_BUF_SIZE ((DWORD)(1024 * 1024))
  22. typedef struct _LOCAL_THREAD_DATA {
  23. LPWSTR szServiceName;
  24. LPWSTR szQueryString;
  25. DWORD dwThreadID;
  26. DWORD dwCycleCount;
  27. DWORD dwLoopCount;
  28. BOOL bTestContents;
  29. BOOL bDisplay;
  30. FILE *pOutput;
  31. LPWSTR *pNameTable;
  32. DWORD dwLastIndex;
  33. } LOCAL_THREAD_DATA, *PLOCAL_THREAD_DATA;
  34. HANDLE hEventLog = NULL;
  35. HANDLE hProcessHeap = NULL;
  36. HANDLE hTestHeap = NULL;
  37. LONG lEventLogLevel = LOG_DEBUG;
  38. LONG lExtCounterTestLevel = EXT_TEST_ALL;
  39. #define PERFVAL_NOCONFIG 0
  40. #define PERFVAL_PASS 1
  41. #define PERFVAL_FAIL 2
  42. #define PERFVAL_TIMEOUT 3
  43. LPCWSTR szContact = (LPCWSTR)L"jenlc";
  44. LPCWSTR szMgrContact = (LPCWSTR)L"jeepang";
  45. LPCWSTR szDevPrime = (LPCWSTR)L"http://ntperformance/perftools/perfctrs.htm";
  46. LPCWSTR szDevAlt= (LPCWSTR)L"jeepang";
  47. LPCWSTR szTestPrime = (LPCWSTR)L"ashokkum";
  48. LPCWSTR szTestAlt = (LPCWSTR)L"a-chrila";
  49. static const WCHAR cszDefaultLangId[] = {L"009"};
  50. static const WCHAR cszNamesKey[] = {L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"};
  51. static const WCHAR cszLastHelp[] = {L"Last Help"};
  52. static const WCHAR cszLastCounter[] = {L"Last Counter"};
  53. static const WCHAR cszVersionName[] = {L"Version"};
  54. static const WCHAR cszCounterName[] = {L"Counter "};
  55. static const WCHAR cszHelpName[] = {L"Explain "};
  56. static const WCHAR cszCounters[] = {L"Counters"};
  57. static const WCHAR cszNotFound[] = {L"*** NOT FOUND ***"};
  58. LPWSTR szTestErrorMessage = NULL;
  59. #define MAX_BUF_SIZE ((DWORD)(1024 * 1024))
  60. #define PERFLIB_TIMER_INTERVAL 200 // 200 ms Timer
  61. static
  62. BOOL
  63. IsMsService (LPCWSTR pServiceName)
  64. {
  65. WCHAR szLocalServiceName[MAX_PATH * 2];
  66. lstrcpyW (szLocalServiceName, pServiceName);
  67. _wcslwr (szLocalServiceName);
  68. // for now this just compares known DLL names. valid as of
  69. // NT v4.0
  70. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"tcpip") == 0) return TRUE;
  71. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nwlnkspx") == 0) return TRUE;
  72. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nwlnknb") == 0) return TRUE;
  73. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nwlnkipx") == 0) return TRUE;
  74. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nbf") == 0) return TRUE;
  75. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"remoteaccess") == 0) return TRUE;
  76. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"nm") == 0) return TRUE;
  77. // if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"winsctrs.dll") == 0) return TRUE;
  78. // if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"sfmctrs.dll") == 0) return TRUE;
  79. // if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"atkctrs.dll") == 0) return TRUE;
  80. // NT v5.0
  81. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"perfdisk") == 0) return TRUE;
  82. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"perfos") == 0) return TRUE;
  83. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"perfproc") == 0) return TRUE;
  84. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"perfnet") == 0) return TRUE;
  85. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"spooler") == 0) return TRUE;
  86. if (lstrcmpW(szLocalServiceName, (LPCWSTR)L"tapisrv") == 0) return TRUE;
  87. return FALSE;
  88. }
  89. DWORD
  90. OpenLibrary (
  91. LPCWSTR szRegistryKey, // service key in registry
  92. EXT_OBJECT **pCreatedObj // structure allocated, init'd and returned by this structure
  93. )
  94. {
  95. DWORD Status = ERROR_SUCCESS;
  96. DWORD dwOpenEvent;
  97. DWORD dwType;
  98. DWORD dwSize;
  99. UINT nErrorMode;
  100. // check to see if the library has already been opened
  101. HKEY hServicesKey = NULL;
  102. HKEY hPerfKey = NULL;
  103. LPWSTR szServiceName;
  104. HKEY hKeyLinkage;
  105. BOOL bUseQueryFn = FALSE;
  106. EXT_OBJECT *pReturnObject = NULL;
  107. EXT_OBJECT *pObj = NULL;
  108. DWORD dwFlags = 0;
  109. DWORD dwKeep;
  110. DWORD dwObjectArray[MAX_PERF_OBJECTS_IN_QUERY_FUNCTION];
  111. DWORD dwObjIndex = 0;
  112. DWORD dwMemBlockSize = sizeof(EXT_OBJECT);
  113. DWORD dwLinkageStringLen = 0;
  114. CHAR szOpenProcName[MAX_PATH];
  115. CHAR szCollectProcName[MAX_PATH];
  116. CHAR szCloseProcName[MAX_PATH];
  117. WCHAR szLibraryString[MAX_PATH];
  118. WCHAR szLibraryExpPath[MAX_PATH];
  119. WCHAR mszObjectList[MAX_PATH];
  120. WCHAR szLinkageKeyPath[MAX_PATH];
  121. WCHAR szLinkageString[MAX_PATH];
  122. DWORD dwOpenTimeout = 0;
  123. DWORD dwCollectTimeout = 0;
  124. LPWSTR szThisObject;
  125. LPWSTR szThisChar;
  126. LPSTR pNextStringA;
  127. LPWSTR pNextStringW;
  128. WCHAR szServicePath[MAX_PATH];
  129. WCHAR szMutexName[MAX_PATH];
  130. WCHAR szPID[32];
  131. LARGE_INTEGER liStartTime, liEndTime, liFreq;
  132. OPEN_PROC_WAIT_INFO opwInfo;
  133. if (szRegistryKey != NULL) {
  134. lstrcpyW (szServicePath, cszHklmServicesKey);
  135. Status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, szServicePath,
  136. 0, KEY_READ, &hServicesKey);
  137. lstrcpyW (szServicePath, szRegistryKey);
  138. lstrcatW (szServicePath, cszPerformance);
  139. Status = RegOpenKeyExW (hServicesKey, szServicePath,
  140. 0, KEY_READ, &hPerfKey);
  141. szServiceName = (LPWSTR)szRegistryKey;
  142. // read the performance DLL name
  143. dwType = 0;
  144. dwSize = sizeof(szLibraryString);
  145. memset (szLibraryString, 0, sizeof(szLibraryString));
  146. memset (szLibraryString, 0, sizeof(szLibraryExpPath));
  147. Status = RegQueryValueExW (hPerfKey,
  148. cszDLLValue,
  149. NULL,
  150. &dwType,
  151. (LPBYTE)szLibraryString,
  152. &dwSize);
  153. if (Status == ERROR_SUCCESS) {
  154. if (dwType == REG_EXPAND_SZ) {
  155. // expand any environment vars
  156. dwSize = ExpandEnvironmentStringsW(
  157. szLibraryString,
  158. szLibraryExpPath,
  159. MAX_PATH);
  160. if ((dwSize > MAX_PATH) || (dwSize == 0)) {
  161. Status = ERROR_INVALID_DLL;
  162. } else {
  163. dwSize += 1;
  164. dwSize *= sizeof(WCHAR);
  165. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  166. }
  167. } else if (dwType == REG_SZ) {
  168. // look for dll and save full file Path
  169. dwSize = SearchPathW (
  170. NULL, // use standard system search path
  171. szLibraryString,
  172. NULL,
  173. MAX_PATH,
  174. szLibraryExpPath,
  175. NULL);
  176. if ((dwSize > MAX_PATH) || (dwSize == 0)) {
  177. Status = ERROR_INVALID_DLL;
  178. } else {
  179. dwSize += 1;
  180. dwSize *= sizeof(WCHAR);
  181. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  182. }
  183. } else {
  184. Status = ERROR_INVALID_DLL;
  185. }
  186. if (Status == ERROR_SUCCESS) {
  187. // we have the DLL name so get the procedure names
  188. dwType = 0;
  189. dwSize = sizeof(szOpenProcName);
  190. memset (szOpenProcName, 0, sizeof(szOpenProcName));
  191. Status = RegQueryValueExA (hPerfKey,
  192. caszOpenValue,
  193. NULL,
  194. &dwType,
  195. (LPBYTE)szOpenProcName,
  196. &dwSize);
  197. }
  198. if (Status == ERROR_SUCCESS) {
  199. // add in size of previous string
  200. // the size value includes the Term. NULL
  201. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  202. // we have the procedure name so get the timeout value
  203. dwType = 0;
  204. dwSize = sizeof(dwOpenTimeout);
  205. Status = RegQueryValueExW (hPerfKey,
  206. cszOpenTimeout,
  207. NULL,
  208. &dwType,
  209. (LPBYTE)&dwOpenTimeout,
  210. &dwSize);
  211. // if error, then apply default
  212. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  213. dwOpenTimeout = 10000;
  214. Status = ERROR_SUCCESS;
  215. }
  216. }
  217. if (Status == ERROR_SUCCESS) {
  218. // get next string
  219. dwType = 0;
  220. dwSize = sizeof(szCloseProcName);
  221. memset (szCloseProcName, 0, sizeof(szCloseProcName));
  222. Status = RegQueryValueExA (hPerfKey,
  223. caszCloseValue,
  224. NULL,
  225. &dwType,
  226. (LPBYTE)szCloseProcName,
  227. &dwSize);
  228. }
  229. if (Status == ERROR_SUCCESS) {
  230. // add in size of previous string
  231. // the size value includes the Term. NULL
  232. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  233. // try to look up the query function which is the
  234. // preferred interface if it's not found, then
  235. // try the collect function name. If that's not found,
  236. // then bail
  237. dwType = 0;
  238. dwSize = sizeof(szCollectProcName);
  239. memset (szCollectProcName, 0, sizeof(szCollectProcName));
  240. Status = RegQueryValueExA (hPerfKey,
  241. caszQueryValue,
  242. NULL,
  243. &dwType,
  244. (LPBYTE)szCollectProcName,
  245. &dwSize);
  246. if (Status == ERROR_SUCCESS) {
  247. // add in size of the Query Function Name
  248. // the size value includes the Term. NULL
  249. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  250. // get next string
  251. bUseQueryFn = TRUE;
  252. // the query function can support a static object list
  253. // so look it up
  254. } else {
  255. // the QueryFunction wasn't found so look up the
  256. // Collect Function name instead
  257. dwType = 0;
  258. dwSize = sizeof(szCollectProcName);
  259. memset (szCollectProcName, 0, sizeof(szCollectProcName));
  260. Status = RegQueryValueExA (hPerfKey,
  261. caszCollectValue,
  262. NULL,
  263. &dwType,
  264. (LPBYTE)szCollectProcName,
  265. &dwSize);
  266. if (Status == ERROR_SUCCESS) {
  267. // add in size of Collect Function Name
  268. // the size value includes the Term. NULL
  269. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  270. }
  271. }
  272. if (Status == ERROR_SUCCESS) {
  273. // we have the procedure name so get the timeout value
  274. dwType = 0;
  275. dwSize = sizeof(dwCollectTimeout);
  276. Status = RegQueryValueExW (hPerfKey,
  277. cszCollectTimeout,
  278. NULL,
  279. &dwType,
  280. (LPBYTE)&dwCollectTimeout,
  281. &dwSize);
  282. // if error, then apply default
  283. if ((Status != ERROR_SUCCESS) || (dwType != REG_DWORD)) {
  284. dwCollectTimeout = 10000;
  285. Status = ERROR_SUCCESS;
  286. }
  287. }
  288. // get the list of supported objects if provided by the registry
  289. dwType = 0;
  290. dwSize = sizeof(mszObjectList);
  291. memset (mszObjectList, 0, sizeof(mszObjectList));
  292. Status = RegQueryValueExW (hPerfKey,
  293. cszObjListValue,
  294. NULL,
  295. &dwType,
  296. (LPBYTE)mszObjectList,
  297. &dwSize);
  298. if (Status == ERROR_SUCCESS) {
  299. if (dwType != REG_MULTI_SZ) {
  300. // convert space delimited list to msz
  301. for (szThisChar = mszObjectList; *szThisChar != 0; szThisChar++) {
  302. if (*szThisChar == L' ') *szThisChar = L'\0';
  303. }
  304. ++szThisChar;
  305. *szThisChar = 0; // add MSZ term Null
  306. }
  307. for (szThisObject = mszObjectList, dwObjIndex = 0;
  308. (*szThisObject != 0) && (dwObjIndex < MAX_PERF_OBJECTS_IN_QUERY_FUNCTION);
  309. szThisObject += lstrlenW(szThisObject) + 1) {
  310. dwObjectArray[dwObjIndex] = wcstoul(szThisObject, NULL, 10);
  311. dwObjIndex++;
  312. }
  313. if (*szThisObject != 0) {
  314. // BUGBUG: log error idicating too many object ID's are
  315. // in the list.
  316. }
  317. } else {
  318. // reset status since not having this is
  319. // not a showstopper
  320. Status = ERROR_SUCCESS;
  321. }
  322. if (Status == ERROR_SUCCESS) {
  323. dwType = 0;
  324. dwKeep = 0;
  325. dwSize = sizeof(dwKeep);
  326. Status = RegQueryValueExW (hPerfKey,
  327. cszKeepResident,
  328. NULL,
  329. &dwType,
  330. (LPBYTE)&dwKeep,
  331. &dwSize);
  332. if ((Status == ERROR_SUCCESS) && (dwType == REG_DWORD)) {
  333. if (dwKeep == 1) {
  334. dwFlags |= PERF_EO_KEEP_RESIDENT;
  335. } else {
  336. // no change.
  337. }
  338. } else {
  339. // not fatal, just use the defaults.
  340. Status = ERROR_SUCCESS;
  341. }
  342. }
  343. }
  344. }
  345. if (Status == ERROR_SUCCESS) {
  346. memset (szLinkageString, 0, sizeof(szLinkageString));
  347. lstrcpyW (szLinkageKeyPath, szServiceName);
  348. lstrcatW (szLinkageKeyPath, cszLinkageKey);
  349. Status = RegOpenKeyExW (
  350. hServicesKey,
  351. szLinkageKeyPath,
  352. 0L,
  353. KEY_READ,
  354. &hKeyLinkage);
  355. if (Status == ERROR_SUCCESS) {
  356. // look up export value string
  357. dwSize = sizeof(szLinkageString);
  358. dwType = 0;
  359. Status = RegQueryValueExW (
  360. hKeyLinkage,
  361. cszExportValue,
  362. NULL,
  363. &dwType,
  364. (LPBYTE)&szLinkageString,
  365. &dwSize);
  366. if ((Status != ERROR_SUCCESS) ||
  367. ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))) {
  368. // clear buffer
  369. memset (szLinkageString, 0, sizeof(szLinkageString));
  370. dwLinkageStringLen = 0;
  371. // not finding a linkage key is not fatal so correct
  372. // status
  373. Status = ERROR_SUCCESS;
  374. } else {
  375. // add size of linkage string to buffer
  376. // the size value includes the Term. NULL
  377. dwLinkageStringLen = dwSize;
  378. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  379. }
  380. RegCloseKey (hKeyLinkage);
  381. } else {
  382. // not finding a linkage key is not fatal so correct
  383. // status
  384. Status = ERROR_SUCCESS;
  385. }
  386. }
  387. if (Status == ERROR_SUCCESS) {
  388. // add in size of service name
  389. dwSize = lstrlenW (szServiceName);
  390. dwSize += 1;
  391. dwSize *= sizeof(WCHAR);
  392. dwMemBlockSize += DWORD_MULTIPLE(dwSize);
  393. // allocate and initialize a new ext. object block
  394. pReturnObject = (EXT_OBJECT *)HeapAlloc(hTestHeap,
  395. HEAP_ZERO_MEMORY, dwMemBlockSize);
  396. if (pReturnObject != NULL) {
  397. // copy values to new buffer (all others are NULL)
  398. pNextStringA = (LPSTR)&pReturnObject[1];
  399. // copy Open Procedure Name
  400. pReturnObject->szOpenProcName = pNextStringA;
  401. lstrcpyA (pNextStringA, szOpenProcName);
  402. pNextStringA += lstrlenA (pNextStringA) + 1;
  403. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  404. pReturnObject->dwOpenTimeout = dwOpenTimeout;
  405. // copy collect function or query function, depending
  406. pReturnObject->szCollectProcName = pNextStringA;
  407. lstrcpyA (pNextStringA, szCollectProcName);
  408. pNextStringA += lstrlenA (pNextStringA) + 1;
  409. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  410. pReturnObject->dwCollectTimeout = dwCollectTimeout;
  411. // copy Close Procedure Name
  412. pReturnObject->szCloseProcName = pNextStringA;
  413. lstrcpyA (pNextStringA, szCloseProcName);
  414. pNextStringA += lstrlenA (pNextStringA) + 1;
  415. pNextStringA = (LPSTR)ALIGN_ON_DWORD(pNextStringA);
  416. // copy Library path
  417. pNextStringW = (LPWSTR)pNextStringA;
  418. pReturnObject->szLibraryName = pNextStringW;
  419. lstrcpyW (pNextStringW, szLibraryExpPath);
  420. pNextStringW += lstrlenW (pNextStringW) + 1;
  421. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  422. // copy Linkage String if there is one
  423. if (*szLinkageString != 0) {
  424. pReturnObject->szLinkageString = pNextStringW;
  425. memcpy (pNextStringW, szLinkageString, dwLinkageStringLen);
  426. // length includes extra NULL char and is in BYTES
  427. pNextStringW += (dwLinkageStringLen / sizeof (WCHAR));
  428. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  429. }
  430. // copy Service name
  431. pReturnObject->szServiceName = pNextStringW;
  432. lstrcpyW (pNextStringW, szServiceName);
  433. pNextStringW += lstrlenW (pNextStringW) + 1;
  434. pNextStringW = (LPWSTR)ALIGN_ON_DWORD(pNextStringW);
  435. // load flags
  436. if (bUseQueryFn) {
  437. dwFlags |= PERF_EO_QUERY_FUNC;
  438. }
  439. pReturnObject->dwFlags = dwFlags;
  440. pReturnObject->hPerfKey = hPerfKey;
  441. // load Object array
  442. if (dwObjIndex > 0) {
  443. pReturnObject->dwNumObjects = dwObjIndex;
  444. memcpy (pReturnObject->dwObjList,
  445. dwObjectArray, (dwObjIndex * sizeof(dwObjectArray[0])));
  446. }
  447. pReturnObject->llLastUsedTime = 0;
  448. // create Mutex name
  449. lstrcpyW (szMutexName, szRegistryKey);
  450. lstrcatW (szMutexName, (LPCWSTR)L"_Perf_Library_Lock_PID_");
  451. _ultow ((ULONG)GetCurrentProcessId(), szPID, 16);
  452. lstrcatW (szMutexName, szPID);
  453. pReturnObject->hMutex = CreateMutexW (NULL, FALSE, szMutexName);
  454. } else {
  455. Status = ERROR_OUTOFMEMORY;
  456. }
  457. }
  458. if (Status != ERROR_SUCCESS) {
  459. SetLastError (Status);
  460. if (pReturnObject != NULL) {
  461. // release the new block
  462. HeapFree (hTestHeap, 0, pReturnObject);
  463. }
  464. } else {
  465. if (pReturnObject != NULL) {
  466. pObj = pReturnObject;
  467. // then load library & look up functions
  468. nErrorMode = SetErrorMode (SEM_FAILCRITICALERRORS);
  469. pObj->hLibrary = LoadLibraryExW (pObj->szLibraryName,
  470. NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  471. if (pObj->hLibrary != NULL) {
  472. // lookup function names
  473. pObj->OpenProc = (OPENPROC)GetProcAddress(
  474. pObj->hLibrary, pObj->szOpenProcName);
  475. if (pObj->OpenProc == NULL) {
  476. wprintf ((LPCWSTR)L"\nOpen Procedure \"%s\" not found in \"%s\"",
  477. pObj->szOpenProcName, pObj->szLibraryName);
  478. }
  479. } else {
  480. // unable to load library
  481. Status = GetLastError();
  482. }
  483. if (Status == ERROR_SUCCESS) {
  484. if (pObj->dwFlags & PERF_EO_QUERY_FUNC) {
  485. pObj->QueryProc = (QUERYPROC)GetProcAddress (
  486. pObj->hLibrary, pObj->szCollectProcName);
  487. pObj->CollectProc = (COLLECTPROC)pObj->QueryProc;
  488. } else {
  489. pObj->CollectProc = (COLLECTPROC)GetProcAddress (
  490. pObj->hLibrary, pObj->szCollectProcName);
  491. pObj->QueryProc = (QUERYPROC)pObj->CollectProc;
  492. }
  493. if (pObj->CollectProc == NULL) {
  494. wprintf ((LPCWSTR)L"\nCollect Procedure \"%s\" not found in \"%s\"",
  495. pObj->szCollectProcName, pObj->szLibraryName);
  496. }
  497. }
  498. if (Status == ERROR_SUCCESS) {
  499. pObj->CloseProc = (CLOSEPROC)GetProcAddress (
  500. pObj->hLibrary, pObj->szCloseProcName);
  501. if (pObj->CloseProc == NULL) {
  502. wprintf ((LPCWSTR)L"\nClose Procedure \"%s\" not found in \"%s\"",
  503. pObj->szCloseProcName, pObj->szLibraryName);
  504. }
  505. }
  506. if (Status == ERROR_SUCCESS) {
  507. __try {
  508. // start timer
  509. opwInfo.pNext = NULL;
  510. opwInfo.szLibraryName = pObj->szLibraryName;
  511. opwInfo.szServiceName = pObj->szServiceName;
  512. opwInfo.dwWaitTime = pObj->dwOpenTimeout;
  513. opwInfo.dwEventMsg = ERROR_TIMEOUT;
  514. opwInfo.pData = (LPVOID)pObj;
  515. WAIT_FOR_AND_LOCK_MUTEX (pObj->hMutex);
  516. QueryPerformanceCounter (&liStartTime);
  517. // call open procedure to initialize DLL
  518. Status = (*pObj->OpenProc)(pObj->szLinkageString);
  519. // release the lock
  520. RELEASE_MUTEX (pObj->hMutex);
  521. // check the result.
  522. if (Status != ERROR_SUCCESS) {
  523. dwOpenEvent = WBEMPERF_OPEN_PROC_FAILURE;
  524. } else {
  525. InterlockedIncrement((LONG *)&pObj->dwOpenCount);
  526. QueryPerformanceCounter (&liEndTime);
  527. pObj->llFunctionTime = liEndTime.QuadPart - liStartTime.QuadPart;
  528. pObj->llOpenTime += pObj->llFunctionTime;
  529. }
  530. } __except (EXCEPTION_EXECUTE_HANDLER) {
  531. Status = GetExceptionCode();
  532. dwOpenEvent = WBEMPERF_OPEN_PROC_EXCEPTION;
  533. }
  534. }
  535. QueryPerformanceFrequency (&liFreq);
  536. pObj->llTimeBase = liFreq.QuadPart;
  537. if (Status != ERROR_SUCCESS) {
  538. // clear fields
  539. pObj->OpenProc = NULL;
  540. pObj->CollectProc = NULL;
  541. pObj->QueryProc = NULL;
  542. pObj->CloseProc = NULL;
  543. if (pObj->hLibrary != NULL) {
  544. FreeLibrary (pObj->hLibrary);
  545. pObj->hLibrary = NULL;
  546. }
  547. } else {
  548. GetSystemTimeAsFileTime ((FILETIME *)&pObj->llLastUsedTime);
  549. }
  550. } // else no buffer returned
  551. *pCreatedObj = pObj;
  552. }
  553. if (hServicesKey != NULL) RegCloseKey (hServicesKey);
  554. } else {
  555. Status = ERROR_INVALID_PARAMETER;
  556. }
  557. return Status;
  558. }
  559. //***************************************************************************
  560. //
  561. // CollectData (LPBYTE pBuffer,
  562. // LPDWORD pdwBufferSize,
  563. // LPWSTR pszItemList)
  564. //
  565. // Collects data from the perf objects and libraries added to the access
  566. // object
  567. //
  568. // Inputs:
  569. //
  570. // pBuffer - pointer to start of data block
  571. // where data is being collected
  572. //
  573. // pdwBufferSize - pointer to size of data buffer
  574. //
  575. // pszItemList - string to pass to ext DLL
  576. //
  577. // Outputs:
  578. //
  579. // *lppDataDefinition - set to location for next Type
  580. // Definition if successful
  581. //
  582. // Returns:
  583. //
  584. // 0 if successful, else Win 32 error code of failure
  585. //
  586. //
  587. //***************************************************************************
  588. //
  589. DWORD
  590. CollectData (EXT_OBJECT *pThisExtObj,
  591. LPBYTE pBuffer,
  592. LPDWORD pdwBufferSize,
  593. LPCWSTR pszItemList
  594. )
  595. {
  596. LPWSTR lpValueName = NULL;
  597. LPBYTE lpData = pBuffer;
  598. LPDWORD lpcbData = pdwBufferSize;
  599. LPVOID lpDataDefinition = pBuffer;
  600. DWORD Win32Error=ERROR_SUCCESS; // Failure code
  601. DWORD BytesLeft;
  602. DWORD InitialBytesLeft = 0;
  603. DWORD NumObjectTypes;
  604. LPVOID lpExtDataBuffer = NULL;
  605. LPVOID lpCallBuffer = NULL;
  606. LPVOID lpLowGuardPage = NULL;
  607. LPVOID lpHiGuardPage = NULL;
  608. LPVOID lpEndPointer = NULL;
  609. LPVOID lpBufferBefore = NULL;
  610. LPVOID lpBufferAfter = NULL;
  611. LPDWORD lpCheckPointer;
  612. LARGE_INTEGER liStartTime = {0,0};
  613. LARGE_INTEGER liEndTime = {0,0};
  614. HANDLE hPerflibFuncTimer;
  615. OPEN_PROC_WAIT_INFO opwInfo;
  616. BOOL bGuardPageOK;
  617. BOOL bBufferOK;
  618. BOOL bException;
  619. BOOL bUseSafeBuffer = TRUE;
  620. BOOL bUnlockObjData = FALSE;
  621. LONG lReturnValue = ERROR_SUCCESS;
  622. LONG lInstIndex;
  623. PERF_OBJECT_TYPE *pObject, *pNextObject;
  624. PERF_INSTANCE_DEFINITION *pInstance;
  625. PERF_DATA_BLOCK *pPerfData;
  626. BOOL bForeignDataBuffer;
  627. DWORD dwObjectBufSize;
  628. DWORD dwIndex;
  629. DOUBLE dMs;
  630. // use the one passed by the caller
  631. lpValueName = (LPWSTR)pszItemList;
  632. // initialize values to pass to the extensible counter function
  633. NumObjectTypes = 0;
  634. BytesLeft = (DWORD) (*lpcbData - ((LPBYTE)lpDataDefinition - lpData));
  635. bException = FALSE;
  636. // allocate a local block of memory to pass to the
  637. // extensible counter function.
  638. if (bUseSafeBuffer) {
  639. lpExtDataBuffer = HeapAlloc (hTestHeap,
  640. HEAP_ZERO_MEMORY, BytesLeft + (2*GUARD_PAGE_SIZE));
  641. } else {
  642. lpExtDataBuffer =
  643. lpCallBuffer = lpDataDefinition;
  644. }
  645. if (lpExtDataBuffer != NULL) {
  646. if (bUseSafeBuffer) {
  647. // set buffer pointers
  648. lpLowGuardPage = lpExtDataBuffer;
  649. lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE;
  650. lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft;
  651. lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE;
  652. lpBufferBefore = lpCallBuffer;
  653. lpBufferAfter = NULL;
  654. // initialize GuardPage Data
  655. memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  656. memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  657. }
  658. __try {
  659. //
  660. // Collect data from extesible objects
  661. //
  662. hPerflibFuncTimer = NULL;
  663. bUnlockObjData = FALSE;
  664. if (pThisExtObj->hMutex != NULL) {
  665. Win32Error = WaitForSingleObject (
  666. pThisExtObj->hMutex,
  667. pThisExtObj->dwCollectTimeout);
  668. if ((Win32Error != WAIT_TIMEOUT) &&
  669. (pThisExtObj->CollectProc != NULL)) {
  670. bUnlockObjData = TRUE;
  671. opwInfo.pNext = NULL;
  672. opwInfo.szLibraryName = pThisExtObj->szLibraryName;
  673. opwInfo.szServiceName = pThisExtObj->szServiceName;
  674. opwInfo.dwWaitTime = pThisExtObj->dwCollectTimeout;
  675. opwInfo.dwEventMsg = ERROR_TIMEOUT;
  676. opwInfo.pData = (LPVOID)pThisExtObj;
  677. InitialBytesLeft = BytesLeft;
  678. QueryPerformanceCounter (&liStartTime);
  679. Win32Error = (*pThisExtObj->CollectProc) (
  680. lpValueName,
  681. &lpCallBuffer,
  682. &BytesLeft,
  683. &NumObjectTypes);
  684. QueryPerformanceCounter (&liEndTime);
  685. GetSystemTimeAsFileTime(
  686. (FILETIME*)&pThisExtObj->llLastUsedTime);
  687. ReleaseMutex (pThisExtObj->hMutex);
  688. bUnlockObjData = FALSE;
  689. } else {
  690. pThisExtObj->dwLockoutCount++;
  691. }
  692. } else {
  693. Win32Error = ERROR_LOCK_FAILED;
  694. }
  695. if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) {
  696. if (BytesLeft > InitialBytesLeft) {
  697. pThisExtObj->dwBufferSizeErrors++;
  698. // memory error
  699. Win32Error = ERROR_INVALID_PARAMETER;
  700. }
  701. // increment perf counters
  702. InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount);
  703. pThisExtObj->llFunctionTime = liEndTime.QuadPart - liStartTime.QuadPart;
  704. pThisExtObj->llCollectTime += pThisExtObj->llFunctionTime;
  705. // check the time spent in this function
  706. dMs = (DOUBLE)pThisExtObj->llFunctionTime;
  707. dMs /= (DOUBLE)pThisExtObj->llTimeBase;
  708. dMs *= 1000.0;
  709. if (dMs > (DOUBLE)pThisExtObj->dwCollectTimeout) {
  710. Win32Error = ERROR_TIMEOUT;
  711. } else if (BytesLeft & 0x00000007) {
  712. pThisExtObj->dwAlignmentErrors++;
  713. Win32Error = ERROR_INVALID_DATA;
  714. }
  715. pThisExtObj->dwNumObjectsRet = NumObjectTypes;
  716. pThisExtObj->dwRetBufSize = BytesLeft;
  717. if ((bUseSafeBuffer) && (Win32Error == ERROR_SUCCESS)) {
  718. // a data buffer was returned and
  719. // the function returned OK so see how things
  720. // turned out...
  721. //
  722. lpBufferAfter = lpCallBuffer;
  723. //
  724. // check for buffer corruption here
  725. //
  726. bBufferOK = TRUE; // assume it's ok until a check fails
  727. //
  728. if (lExtCounterTestLevel <= EXT_TEST_BASIC) {
  729. //
  730. // check 1: bytes left should be the same as
  731. // new data buffer ptr - orig data buffer ptr
  732. //
  733. if (BytesLeft != (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore)) {
  734. pThisExtObj->dwBadPointers++;
  735. // we'll keep the buffer, since the returned bytes left
  736. // value is ignored anyway, in order to make the
  737. // rest of this function work, we'll fix it here
  738. BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  739. Win32Error = ERROR_INVALID_DATA;
  740. }
  741. //
  742. // check 2: buffer after ptr should be < hi Guard page ptr
  743. //
  744. if (((LPBYTE)lpBufferAfter >= (LPBYTE)lpHiGuardPage) && bBufferOK) {
  745. // see if they exceeded the allocated memory
  746. if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) {
  747. pThisExtObj->dwBufferSizeErrors++;
  748. bBufferOK = FALSE;
  749. // since the DLL overran the buffer, the buffer
  750. // must be too small (no comments about the DLL
  751. // will be made here) so the status will be
  752. // changed to ERROR_MORE_DATA and the function
  753. // will return.
  754. Win32Error = ERROR_INVALID_DATA;
  755. }
  756. }
  757. //
  758. // check 3: check lo guard page for corruption
  759. //
  760. if (bBufferOK) {
  761. bGuardPageOK = TRUE;
  762. for (lpCheckPointer = (LPDWORD)lpLowGuardPage;
  763. lpCheckPointer < (LPDWORD)lpBufferBefore;
  764. lpCheckPointer++) {
  765. if (*lpCheckPointer != GUARD_PAGE_DWORD) {
  766. bGuardPageOK = FALSE;
  767. break;
  768. }
  769. }
  770. if (!bGuardPageOK) {
  771. pThisExtObj->dwLowerGPViolations++;
  772. Win32Error = ERROR_INVALID_DATA;
  773. bBufferOK = FALSE;
  774. }
  775. }
  776. //
  777. // check 4: check hi guard page for corruption
  778. //
  779. if (bBufferOK) {
  780. bGuardPageOK = TRUE;
  781. for (lpCheckPointer = (LPDWORD)lpHiGuardPage;
  782. lpCheckPointer < (LPDWORD)lpEndPointer;
  783. lpCheckPointer++) {
  784. if (*lpCheckPointer != GUARD_PAGE_DWORD) {
  785. bGuardPageOK = FALSE;
  786. break;
  787. }
  788. }
  789. if (!bGuardPageOK) {
  790. pThisExtObj->dwUpperGPViolations++;
  791. bBufferOK = FALSE;
  792. Win32Error = ERROR_INVALID_DATA;
  793. }
  794. }
  795. //
  796. if ((lExtCounterTestLevel <= EXT_TEST_ALL) && bBufferOK) {
  797. //
  798. // Internal consistency checks
  799. //
  800. //
  801. // Check 5: Check object length field values
  802. //
  803. // first test to see if this is a foreign
  804. // computer data block or not
  805. //
  806. pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore;
  807. if ((pPerfData->Signature[0] == (WCHAR)'P') &&
  808. (pPerfData->Signature[1] == (WCHAR)'E') &&
  809. (pPerfData->Signature[2] == (WCHAR)'R') &&
  810. (pPerfData->Signature[3] == (WCHAR)'F')) {
  811. // if this is a foreign computer data block, then the
  812. // first object is after the header
  813. pObject = (PERF_OBJECT_TYPE *) (
  814. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  815. bForeignDataBuffer = TRUE;
  816. } else {
  817. // otherwise, if this is just a buffer from
  818. // an extensible counter, the object starts
  819. // at the beginning of the buffer
  820. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  821. bForeignDataBuffer = FALSE;
  822. }
  823. // go to where the pointers say the end of the
  824. // buffer is and then see if it's where it
  825. // should be
  826. dwObjectBufSize = 0;
  827. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  828. dwObjectBufSize += pObject->TotalByteLength;
  829. pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  830. pObject->TotalByteLength);
  831. }
  832. if (((LPBYTE)pObject != (LPBYTE)lpCallBuffer) ||
  833. (dwObjectBufSize > BytesLeft)) {
  834. // then a length field is incorrect. This is FATAL
  835. // since it can corrupt the rest of the buffer
  836. // and render the buffer unusable.
  837. pThisExtObj->dwObjectSizeErrors++;
  838. bBufferOK = FALSE;
  839. Win32Error = ERROR_INVALID_DATA;
  840. }
  841. //
  842. // Test 6: Test instance field size values
  843. //
  844. if (bBufferOK) {
  845. // set object pointer
  846. if (bForeignDataBuffer) {
  847. pObject = (PERF_OBJECT_TYPE *) (
  848. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  849. } else {
  850. // otherwise, if this is just a buffer from
  851. // an extensible counter, the object starts
  852. // at the beginning of the buffer
  853. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  854. }
  855. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  856. pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  857. pObject->TotalByteLength);
  858. if (pObject->NumInstances != PERF_NO_INSTANCES) {
  859. pInstance = (PERF_INSTANCE_DEFINITION *)
  860. ((LPBYTE)pObject + pObject->DefinitionLength);
  861. lInstIndex = 0;
  862. while (lInstIndex < pObject->NumInstances) {
  863. PERF_COUNTER_BLOCK *pCounterBlock;
  864. pCounterBlock = (PERF_COUNTER_BLOCK *)
  865. ((PCHAR) pInstance + pInstance->ByteLength);
  866. pInstance = (PERF_INSTANCE_DEFINITION *)
  867. ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  868. lInstIndex++;
  869. }
  870. if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
  871. bBufferOK = FALSE;
  872. Win32Error = ERROR_INVALID_DATA;
  873. }
  874. }
  875. if (!bBufferOK) {
  876. Win32Error = ERROR_INVALID_DATA;
  877. break;
  878. } else {
  879. pObject = pNextObject;
  880. }
  881. }
  882. if (!bBufferOK) {
  883. pThisExtObj->dwInstanceSizeErrors++;
  884. Win32Error = ERROR_INVALID_DATA;
  885. }
  886. }
  887. //
  888. // Test 7: Test instance field size values
  889. //
  890. if (bBufferOK) {
  891. // set object pointer
  892. if (bForeignDataBuffer) {
  893. pObject = (PERF_OBJECT_TYPE *) (
  894. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  895. } else {
  896. // otherwise, if this is just a buffer from
  897. // an extensible counter, the object starts
  898. // at the beginning of the buffer
  899. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  900. }
  901. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  902. pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  903. pObject->TotalByteLength);
  904. if (pObject->NumInstances != PERF_NO_INSTANCES) {
  905. pInstance = (PERF_INSTANCE_DEFINITION *)
  906. ((LPBYTE)pObject + pObject->DefinitionLength);
  907. lInstIndex = 0;
  908. while (lInstIndex < pObject->NumInstances) {
  909. PERF_COUNTER_BLOCK *pCounterBlock;
  910. pCounterBlock = (PERF_COUNTER_BLOCK *)
  911. ((PCHAR) pInstance + pInstance->ByteLength);
  912. pInstance = (PERF_INSTANCE_DEFINITION *)
  913. ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  914. lInstIndex++;
  915. }
  916. if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
  917. bBufferOK = FALSE;
  918. Win32Error = ERROR_INVALID_DATA;
  919. }
  920. }
  921. if (!bBufferOK) {
  922. Win32Error = ERROR_INVALID_DATA;
  923. break;
  924. } else {
  925. pObject = pNextObject;
  926. }
  927. }
  928. if (!bBufferOK) {
  929. Win32Error = ERROR_INVALID_DATA;
  930. pThisExtObj->dwInstanceNameErrors++;
  931. }
  932. }
  933. }
  934. }
  935. //
  936. // if all the tests pass,then copy the data to the
  937. // original buffer and update the pointers
  938. if (bBufferOK) {
  939. RtlMoveMemory (lpDataDefinition,
  940. lpBufferBefore,
  941. BytesLeft); // returned buffer size
  942. } else {
  943. NumObjectTypes = 0; // since this buffer was tossed
  944. }
  945. } else {
  946. // function already copied data to caller's buffer
  947. // so no further action is necessary
  948. }
  949. lpDataDefinition = (LPVOID)((LPBYTE)(lpDataDefinition) + BytesLeft); // update data pointer
  950. } else {
  951. if (Win32Error != ERROR_SUCCESS) {
  952. if (Win32Error != WAIT_TIMEOUT) {
  953. // don't count timeouts as function errors
  954. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  955. }
  956. }
  957. if (bUnlockObjData) {
  958. ReleaseMutex (pThisExtObj->hMutex);
  959. }
  960. NumObjectTypes = 0; // clear counter
  961. }// end if function returned successfully
  962. } __except (EXCEPTION_EXECUTE_HANDLER) {
  963. Win32Error = GetExceptionCode();
  964. InterlockedIncrement ((LONG *)&pThisExtObj->dwExceptionCount);
  965. bException = TRUE;
  966. if (bUnlockObjData) {
  967. ReleaseMutex (pThisExtObj->hMutex);
  968. bUnlockObjData = FALSE;
  969. }
  970. }
  971. if (bUseSafeBuffer) {
  972. HeapFree (hTestHeap, 0, lpExtDataBuffer);
  973. }
  974. } else {
  975. // unable to allocate memory so set error value
  976. Win32Error = ERROR_OUTOFMEMORY;
  977. } // end if temp buffer allocated successfully
  978. RELEASE_MUTEX (pThisExtObj->hMutex);
  979. lReturnValue = Win32Error;
  980. return lReturnValue;
  981. }
  982. DWORD
  983. CloseLibrary (
  984. EXT_OBJECT *pInfo
  985. )
  986. {
  987. DWORD lStatus;
  988. if (pInfo != NULL) {
  989. // if there's a close proc to call, then
  990. // call close procedure to close anything that may have
  991. // been allocated by the library
  992. WAIT_FOR_AND_LOCK_MUTEX (pInfo->hMutex);
  993. if (pInfo->CloseProc != NULL) {
  994. lStatus = (*pInfo->CloseProc) ();
  995. }
  996. RELEASE_MUTEX (pInfo->hMutex);
  997. // then close everything
  998. if (pInfo->hMutex != NULL) {
  999. CloseHandle (pInfo->hMutex);
  1000. pInfo->hMutex = NULL;
  1001. }
  1002. if (pInfo->hLibrary != NULL) {
  1003. FreeLibrary (pInfo->hLibrary);
  1004. pInfo->hLibrary = NULL;
  1005. }
  1006. if (pInfo->hPerfKey != NULL) {
  1007. RegCloseKey (pInfo->hPerfKey);
  1008. pInfo->hPerfKey = NULL;
  1009. }
  1010. HeapFree (hTestHeap, 0, pInfo);
  1011. }
  1012. return ERROR_SUCCESS;
  1013. }
  1014. static
  1015. LPWSTR
  1016. *BuildNameTable(
  1017. LPCWSTR szMachineName,
  1018. LPCWSTR lpszLangIdArg, // unicode value of Language subkey
  1019. PDWORD pdwLastItem, // size of array in elements
  1020. PDWORD pdwIdArray // array for index ID's
  1021. )
  1022. /*++
  1023. BuildNameTable
  1024. Arguments:
  1025. hKeyRegistry
  1026. Handle to an open registry (this can be local or remote.) and
  1027. is the value returned by RegConnectRegistry or a default key.
  1028. lpszLangId
  1029. The unicode id of the language to look up. (default is 409)
  1030. Return Value:
  1031. pointer to an allocated table. (the caller must MemoryFree it when finished!)
  1032. the table is an array of pointers to zero terminated strings. NULL is
  1033. returned if an error occured.
  1034. --*/
  1035. {
  1036. HKEY hKeyRegistry; // handle to registry db with counter names
  1037. LPWSTR *lpReturnValue;
  1038. LPCWSTR lpszLangId;
  1039. LPWSTR *lpCounterId;
  1040. LPWSTR lpCounterNames;
  1041. LPWSTR lpHelpText;
  1042. LPWSTR lpThisName;
  1043. LONG lWin32Status;
  1044. DWORD dwValueType;
  1045. DWORD dwArraySize;
  1046. DWORD dwBufferSize;
  1047. DWORD dwCounterSize;
  1048. DWORD dwHelpSize;
  1049. DWORD dwThisCounter;
  1050. DWORD dwLastId;
  1051. DWORD dwLastHelpId;
  1052. DWORD dwLastCounterIdUsed;
  1053. DWORD dwLastHelpIdUsed;
  1054. HKEY hKeyValue;
  1055. HKEY hKeyNames;
  1056. LPWSTR lpValueNameString;
  1057. WCHAR CounterNameBuffer [50];
  1058. WCHAR HelpNameBuffer [50];
  1059. SetLastError (ERROR_SUCCESS);
  1060. szTestErrorMessage = NULL;
  1061. if (szMachineName != NULL) {
  1062. lWin32Status = RegConnectRegistryW (szMachineName,
  1063. HKEY_LOCAL_MACHINE,
  1064. &hKeyRegistry);
  1065. } else {
  1066. lWin32Status = ERROR_SUCCESS;
  1067. hKeyRegistry = HKEY_LOCAL_MACHINE;
  1068. }
  1069. lpValueNameString = NULL; //initialize to NULL
  1070. lpReturnValue = NULL;
  1071. hKeyValue = NULL;
  1072. hKeyNames = NULL;
  1073. // check for null arguments and insert defaults if necessary
  1074. if (!lpszLangIdArg) {
  1075. lpszLangId = cszDefaultLangId;
  1076. } else {
  1077. lpszLangId = lpszLangIdArg;
  1078. }
  1079. // open registry to get number of items for computing array size
  1080. lWin32Status = RegOpenKeyExW (
  1081. hKeyRegistry,
  1082. cszNamesKey,
  1083. 0L,
  1084. KEY_READ,
  1085. &hKeyValue);
  1086. if (lWin32Status != ERROR_SUCCESS) {
  1087. szTestErrorMessage = (LPWSTR)L"Unable to Open Perflib key";
  1088. goto BNT_BAILOUT;
  1089. }
  1090. // get config info
  1091. dwValueType = 0;
  1092. dwBufferSize = sizeof (pdwIdArray[4]);
  1093. lWin32Status = RegQueryValueExW (
  1094. hKeyValue,
  1095. (LPCWSTR)L"Disable Performance Counters",
  1096. 0L,
  1097. &dwValueType,
  1098. (LPBYTE)&pdwIdArray[4],
  1099. &dwBufferSize);
  1100. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  1101. if (lWin32Status == ERROR_FILE_NOT_FOUND) {
  1102. // this is OK since the value need not be present
  1103. pdwIdArray[4] = (DWORD)-1;
  1104. lWin32Status = ERROR_SUCCESS;
  1105. } else {
  1106. szTestErrorMessage = (LPWSTR)L"Unable to read Disable Performance Counters value";
  1107. goto BNT_BAILOUT;
  1108. }
  1109. }
  1110. dwValueType = 0;
  1111. dwBufferSize = sizeof (pdwIdArray[5]);
  1112. lWin32Status = RegQueryValueExW (
  1113. hKeyValue,
  1114. (LPCWSTR)L"ExtCounterTestLevel",
  1115. 0L,
  1116. &dwValueType,
  1117. (LPBYTE)&pdwIdArray[5],
  1118. &dwBufferSize);
  1119. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  1120. if (lWin32Status == ERROR_FILE_NOT_FOUND) {
  1121. // this is OK since the value need not be present
  1122. pdwIdArray[5] = (DWORD)-1;
  1123. lWin32Status = ERROR_SUCCESS;
  1124. } else {
  1125. szTestErrorMessage = (LPWSTR)L"Unable to read ExCounterTestLevel value";
  1126. goto BNT_BAILOUT;
  1127. }
  1128. }
  1129. dwValueType = 0;
  1130. dwBufferSize = sizeof (pdwIdArray[6]);
  1131. lWin32Status = RegQueryValueExW (
  1132. hKeyValue,
  1133. (LPCWSTR)L"Base Index",
  1134. 0L,
  1135. &dwValueType,
  1136. (LPBYTE)&pdwIdArray[6],
  1137. &dwBufferSize);
  1138. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  1139. szTestErrorMessage = (LPWSTR)L"Unable to read Base Index value";
  1140. goto BNT_BAILOUT;
  1141. }
  1142. // get number of items
  1143. dwBufferSize = sizeof (dwLastHelpId);
  1144. lWin32Status = RegQueryValueExW (
  1145. hKeyValue,
  1146. cszLastHelp,
  1147. 0L,
  1148. &dwValueType,
  1149. (LPBYTE)&dwLastHelpId,
  1150. &dwBufferSize);
  1151. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  1152. szTestErrorMessage = (LPWSTR)L"Unable to read Last Help value";
  1153. goto BNT_BAILOUT;
  1154. }
  1155. pdwIdArray[2] = dwLastHelpId;
  1156. // get number of items
  1157. dwBufferSize = sizeof (dwLastId);
  1158. lWin32Status = RegQueryValueExW (
  1159. hKeyValue,
  1160. cszLastCounter,
  1161. 0L,
  1162. &dwValueType,
  1163. (LPBYTE)&dwLastId,
  1164. &dwBufferSize);
  1165. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  1166. szTestErrorMessage = (LPWSTR)L"Unable to read Last Counter value";
  1167. goto BNT_BAILOUT;
  1168. }
  1169. pdwIdArray[0] = dwLastId;
  1170. if (dwLastId < dwLastHelpId)
  1171. dwLastId = dwLastHelpId;
  1172. dwArraySize = dwLastId * sizeof(LPWSTR);
  1173. // get Perflib system version
  1174. if (szMachineName[0] == 0) {
  1175. hKeyNames = HKEY_PERFORMANCE_DATA;
  1176. } else {
  1177. lWin32Status = RegConnectRegistryW (szMachineName,
  1178. HKEY_PERFORMANCE_DATA,
  1179. &hKeyNames);
  1180. }
  1181. lstrcpyW (CounterNameBuffer, cszCounterName);
  1182. lstrcatW (CounterNameBuffer, lpszLangId);
  1183. lstrcpyW (HelpNameBuffer, cszHelpName);
  1184. lstrcatW (HelpNameBuffer, lpszLangId);
  1185. // get size of counter names and add that to the arrays
  1186. dwBufferSize = 0;
  1187. lWin32Status = RegQueryValueExW (
  1188. hKeyNames,
  1189. CounterNameBuffer,
  1190. 0L,
  1191. &dwValueType,
  1192. NULL,
  1193. &dwBufferSize);
  1194. if (lWin32Status != ERROR_SUCCESS) {
  1195. szTestErrorMessage = (LPWSTR)L"Unable to query counter string size";
  1196. goto BNT_BAILOUT;
  1197. }
  1198. dwCounterSize = dwBufferSize;
  1199. // get size of counter names and add that to the arrays
  1200. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  1201. dwBufferSize = 0;
  1202. lWin32Status = RegQueryValueExW (
  1203. hKeyNames,
  1204. HelpNameBuffer,
  1205. 0L,
  1206. &dwValueType,
  1207. NULL,
  1208. &dwBufferSize);
  1209. if (lWin32Status != ERROR_SUCCESS) {
  1210. szTestErrorMessage = (LPWSTR)L"Unable to query help string size";
  1211. goto BNT_BAILOUT;
  1212. }
  1213. dwHelpSize = dwBufferSize;
  1214. lpReturnValue = (LPWSTR *)HeapAlloc (hTestHeap, 0,dwArraySize + dwCounterSize + dwHelpSize);
  1215. if (!lpReturnValue) {
  1216. lWin32Status = ERROR_OUTOFMEMORY;
  1217. szTestErrorMessage = (LPWSTR)L"Unable to allocate name string buffer";
  1218. goto BNT_BAILOUT;
  1219. }
  1220. // initialize pointers into buffer
  1221. lpCounterId = lpReturnValue;
  1222. lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
  1223. lpHelpText = (LPWSTR)((LPBYTE)lpCounterNames + dwCounterSize);
  1224. // read counters into memory
  1225. dwBufferSize = dwCounterSize;
  1226. lWin32Status = RegQueryValueExW (
  1227. hKeyNames,
  1228. CounterNameBuffer,
  1229. 0L,
  1230. &dwValueType,
  1231. (LPBYTE)lpCounterNames,
  1232. &dwBufferSize);
  1233. if (lWin32Status != ERROR_SUCCESS) {
  1234. szTestErrorMessage = (LPWSTR)L"Unable to query counter string contents";
  1235. goto BNT_BAILOUT;
  1236. }
  1237. dwBufferSize = dwHelpSize;
  1238. lWin32Status = RegQueryValueExW (
  1239. hKeyNames,
  1240. HelpNameBuffer,
  1241. 0L,
  1242. &dwValueType,
  1243. (LPBYTE)lpHelpText,
  1244. &dwBufferSize);
  1245. if (lWin32Status != ERROR_SUCCESS) {
  1246. szTestErrorMessage = (LPWSTR)L"Unable to query help string contents";
  1247. goto BNT_BAILOUT;
  1248. }
  1249. dwLastCounterIdUsed = 0;
  1250. dwLastHelpIdUsed = 0;
  1251. // load counter array items
  1252. for (lpThisName = lpCounterNames;
  1253. *lpThisName;
  1254. lpThisName += (lstrlenW(lpThisName)+1) ) {
  1255. // first string should be an integer (in decimal unicode digits)
  1256. dwThisCounter = wcstoul (lpThisName, NULL, 10);
  1257. if (dwThisCounter == 0) {
  1258. lWin32Status = ERROR_BADKEY;
  1259. szTestErrorMessage = (LPWSTR)L"Bad counter string entry, CONFIG_String_LastCounter is last valid counter string index";
  1260. goto BNT_BAILOUT; // bad entry
  1261. }
  1262. // point to corresponding counter name
  1263. lpThisName += (lstrlenW(lpThisName)+1);
  1264. // and load array element;
  1265. lpCounterId[dwThisCounter] = lpThisName;
  1266. if (dwThisCounter > dwLastCounterIdUsed) dwLastCounterIdUsed = dwThisCounter;
  1267. }
  1268. pdwIdArray[1] = dwLastCounterIdUsed;
  1269. for (lpThisName = lpHelpText;
  1270. *lpThisName;
  1271. lpThisName += (lstrlenW(lpThisName)+1) ) {
  1272. // first string should be an integer (in decimal unicode digits)
  1273. dwThisCounter = wcstoul (lpThisName, NULL, 10);
  1274. if (dwThisCounter == 0) {
  1275. lWin32Status = ERROR_BADKEY;
  1276. szTestErrorMessage = (LPWSTR)L"Bad help string entry, CONFIG_String_LastHelp is last valid counter string index";
  1277. goto BNT_BAILOUT; // bad entry
  1278. }
  1279. // point to corresponding counter name
  1280. lpThisName += (lstrlenW(lpThisName)+1);
  1281. // and load array element;
  1282. lpCounterId[dwThisCounter] = lpThisName;
  1283. if (dwThisCounter > dwLastHelpIdUsed) dwLastHelpIdUsed= dwThisCounter;
  1284. }
  1285. pdwIdArray[3] = dwLastHelpIdUsed;
  1286. dwLastId = dwLastHelpIdUsed;
  1287. if (dwLastId < dwLastCounterIdUsed) dwLastId = dwLastCounterIdUsed;
  1288. if (pdwLastItem) *pdwLastItem = dwLastId;
  1289. HeapFree (hTestHeap, 0, (LPVOID)lpValueNameString);
  1290. RegCloseKey (hKeyValue);
  1291. RegCloseKey (hKeyNames);
  1292. return lpReturnValue;
  1293. BNT_BAILOUT:
  1294. if (lWin32Status != ERROR_SUCCESS) {
  1295. SetLastError (lWin32Status);
  1296. }
  1297. if (lpValueNameString) {
  1298. HeapFree (hTestHeap, 0, (LPVOID)lpValueNameString);
  1299. }
  1300. if (lpReturnValue) {
  1301. HeapFree (hTestHeap, 0, (LPVOID)lpValueNameString);
  1302. }
  1303. if (hKeyValue) RegCloseKey (hKeyValue);
  1304. RegCloseKey (hKeyNames);
  1305. return NULL;
  1306. }
  1307. DWORD
  1308. CycleTest (
  1309. DWORD dwThreadId,
  1310. PLOCAL_THREAD_DATA pData
  1311. )
  1312. {
  1313. DWORD dwStatus = ERROR_SUCCESS;
  1314. DWORD dwRetStatus = ERROR_SUCCESS;
  1315. EXT_OBJECT *pObj = NULL;
  1316. LPWSTR szValueString = pData->szQueryString;
  1317. LPCWSTR szServiceName = pData->szServiceName;
  1318. DWORD dwLoopCount = pData->dwLoopCount;
  1319. LPBYTE pBuffer = NULL;
  1320. LPBYTE pThisBuffer;
  1321. DWORD dwBufSize = 0;
  1322. DWORD dwThisBufSize;
  1323. DWORD dwMemorySizeIncrement = 0x100;
  1324. FILE *pOutput = pData->pOutput;
  1325. DOUBLE dMs;
  1326. LPWSTR *pNameTable = pData->pNameTable;
  1327. DWORD dwLastId = pData->dwLastIndex;
  1328. PERF_OBJECT_TYPE * pObjDef;
  1329. PERF_COUNTER_DEFINITION * pCtrDef;
  1330. DWORD nObjIdx, nCtrIdx;
  1331. UNREFERENCED_PARAMETER (dwThreadId);
  1332. dwStatus = OpenLibrary (szServiceName, &pObj);
  1333. if (pObj != NULL) {
  1334. // an object info block was returned
  1335. dMs = (DOUBLE)pObj->llOpenTime; // ticks used
  1336. dMs /= (DOUBLE)pObj->llTimeBase; // ticks/sec
  1337. dMs *= 1000.0; // ms/Sec
  1338. fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_OpenProcTime: \t%12.5f mSec", dMs);
  1339. fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_OpenProcTimeout: \t%6d.00000 mSec", pObj->dwOpenTimeout);
  1340. // check for timeout
  1341. if (dMs > (DOUBLE)pObj->dwOpenTimeout) {
  1342. dwRetStatus = ERROR_TIMEOUT;
  1343. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR: \tOpen procedure exceeded timeout");
  1344. }
  1345. } else {
  1346. // no object block returned
  1347. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR: \tUnable to open Library");
  1348. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORCODE:\t0x%8.8x (%dL)", dwStatus, dwStatus);
  1349. dwRetStatus = dwStatus;
  1350. }
  1351. if (dwRetStatus == ERROR_SUCCESS) {
  1352. HeapValidate (hTestHeap, 0, NULL);
  1353. // get the buffer size
  1354. dwStatus = ERROR_MORE_DATA;
  1355. do {
  1356. if (pBuffer != NULL) HeapFree (hTestHeap, 0, pBuffer);
  1357. dwBufSize += dwMemorySizeIncrement;
  1358. dwMemorySizeIncrement *= 2;
  1359. pBuffer = (LPBYTE) HeapAlloc (hTestHeap, HEAP_ZERO_MEMORY, dwBufSize);
  1360. if (pBuffer != NULL) {
  1361. // init the args
  1362. pThisBuffer = pBuffer;
  1363. dwThisBufSize = dwBufSize;
  1364. HeapValidate (hTestHeap, 0, NULL);
  1365. dwStatus = CollectData (pObj,
  1366. pThisBuffer,
  1367. &dwThisBufSize,
  1368. szValueString);
  1369. }
  1370. } while ((dwStatus == ERROR_MORE_DATA) && (dwBufSize < MAX_BUF_SIZE));
  1371. if (dwBufSize >= MAX_BUF_SIZE) {
  1372. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR: \tCollectFunction requires a buffer > %d bytes", MAX_BUF_SIZE);
  1373. if (pBuffer != NULL) HeapFree (hTestHeap, 0, pBuffer);
  1374. dwStatus = ERROR_INVALID_PARAMETER;
  1375. } else if (pBuffer == NULL) {
  1376. dwStatus = ERROR_OUTOFMEMORY;
  1377. } else {
  1378. // call collect function
  1379. do {
  1380. // init the args
  1381. pThisBuffer = pBuffer;
  1382. dwThisBufSize = dwBufSize;
  1383. // get the data
  1384. dwStatus = CollectData (pObj,
  1385. pThisBuffer,
  1386. &dwThisBufSize,
  1387. szValueString);
  1388. while ((dwStatus == ERROR_MORE_DATA) && (dwBufSize < MAX_BUF_SIZE)) {
  1389. if (pBuffer != NULL) HeapFree (hTestHeap, 0, pBuffer);
  1390. dwBufSize += dwMemorySizeIncrement;
  1391. dwMemorySizeIncrement *= 2;
  1392. pBuffer = (LPBYTE) HeapAlloc (hTestHeap, HEAP_ZERO_MEMORY, dwBufSize);
  1393. if (pBuffer != NULL) {
  1394. // init the args
  1395. pThisBuffer = pBuffer;
  1396. dwThisBufSize = dwBufSize;
  1397. // get the data again
  1398. dwStatus = CollectData (pObj,
  1399. pThisBuffer,
  1400. &dwThisBufSize,
  1401. szValueString);
  1402. if ((dwStatus == ERROR_SUCCESS) && (pData->bTestContents)) {
  1403. pObjDef = (PERF_OBJECT_TYPE *)pThisBuffer;
  1404. for (nObjIdx = 0; nObjIdx < pObj->dwNumObjectsRet; nObjIdx++) {
  1405. // test object name & help
  1406. if ((pObjDef->ObjectNameTitleIndex <= dwLastId) &&
  1407. (pObjDef->ObjectNameTitleIndex > 0)) {
  1408. if (pNameTable[pObjDef->ObjectNameTitleIndex ] == NULL) {
  1409. // no string
  1410. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tNo Display String for index %d", pObjDef->ObjectNameTitleIndex );
  1411. dwStatus = ERROR_BADKEY;
  1412. } else {
  1413. // probably ok
  1414. }
  1415. } else {
  1416. // id out of range
  1417. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tObject Name Index values are bad or missing");
  1418. dwStatus = ERROR_BADKEY;
  1419. }
  1420. // test counter defs
  1421. if ((pObjDef->ObjectHelpTitleIndex <= dwLastId) &&
  1422. (pObjDef->ObjectHelpTitleIndex> 0)) {
  1423. if (pNameTable[pObjDef->ObjectHelpTitleIndex] == NULL) {
  1424. // no string
  1425. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tNo Display String for index %d", pObjDef->ObjectHelpTitleIndex );
  1426. dwStatus = ERROR_BADKEY;
  1427. } else {
  1428. // probably ok
  1429. }
  1430. } else {
  1431. // id out of range
  1432. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tObject Help Index values are bad or missing");
  1433. dwStatus = ERROR_BADKEY;
  1434. }
  1435. pCtrDef = FirstCounter (pObjDef);
  1436. for (nCtrIdx = 0; nCtrIdx < pObjDef->NumCounters; nCtrIdx++) {
  1437. pCtrDef = NextCounter (pCtrDef);
  1438. if ((pCtrDef->CounterNameTitleIndex <= dwLastId) &&
  1439. (pCtrDef->CounterNameTitleIndex > 0)) {
  1440. if (pNameTable[pCtrDef->CounterNameTitleIndex ] == NULL) {
  1441. // no string
  1442. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tNo Display String for index %d", pCtrDef->CounterNameTitleIndex );
  1443. dwStatus = ERROR_BADKEY;
  1444. } else {
  1445. // probably ok
  1446. }
  1447. } else {
  1448. // id out of range
  1449. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tCounter Name Index values are bad or missing");
  1450. dwStatus = ERROR_BADKEY;
  1451. }
  1452. // test counter defs
  1453. if ((pCtrDef->CounterHelpTitleIndex <= dwLastId) &&
  1454. (pCtrDef->CounterHelpTitleIndex> 0)) {
  1455. if (pNameTable[pCtrDef->CounterHelpTitleIndex] == NULL) {
  1456. // no string
  1457. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tNo Display String for index %d", pCtrDef->CounterHelpTitleIndex );
  1458. dwStatus = ERROR_BADKEY;
  1459. } else {
  1460. // probably ok
  1461. }
  1462. } else {
  1463. // id out of range
  1464. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tCounter Help Index values are bad or missing");
  1465. dwStatus = ERROR_BADKEY;
  1466. }
  1467. }
  1468. pObjDef = NextObject (pObjDef);
  1469. }
  1470. }
  1471. HeapValidate (hTestHeap, 0, NULL);
  1472. }
  1473. }
  1474. if (dwStatus != ERROR_SUCCESS) {
  1475. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR: \tCollect procedure returned an error");
  1476. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORCODE:\t0x%8.8x (%dL)", dwStatus, dwStatus);
  1477. // output the contents of the info buffer
  1478. if (dwStatus == ERROR_TIMEOUT) {
  1479. // dump collect fn stats.
  1480. dMs = (DOUBLE)pObj->llFunctionTime;
  1481. dMs /= (DOUBLE)pObj->llTimeBase;
  1482. dMs *= 1000.0;
  1483. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CollectProcTime:\t%12.5f mSec", dMs);
  1484. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CollectTimeout: \t%6d.00000 mSec", pObj->dwCollectTimeout);
  1485. }
  1486. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CollectTime: \t%I64u", pObj->llCollectTime);
  1487. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CollectCount:\t%d", pObj->dwCollectCount);
  1488. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_OpenCount: \t%d", pObj->dwOpenCount);
  1489. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_CloseCount: \t%d", pObj->dwCloseCount);
  1490. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_LockoutCount:\t%d", pObj->dwLockoutCount);
  1491. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_ErrorCount: \t%d", pObj->dwErrorCount);
  1492. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_Exceptions: \t%d", pObj->dwExceptionCount);
  1493. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_LowerGPErrs: \t%d", pObj->dwLowerGPViolations);
  1494. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_UpperGPErrs: \t%d", pObj->dwUpperGPViolations);
  1495. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_BadPointers: \t%d", pObj->dwBadPointers);
  1496. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_BufSizeErrs: \t%d", pObj->dwBufferSizeErrors);
  1497. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_AlignErrors: \t%d", pObj->dwAlignmentErrors);
  1498. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_ObjSizeErrs: \t%d", pObj->dwObjectSizeErrors);
  1499. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_InstSizeErrs:\t%d", pObj->dwInstanceSizeErrors);
  1500. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_TimeBase: \t%I64u", pObj->llTimeBase);
  1501. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_FunctionTime:\t%I64u", pObj->llFunctionTime);
  1502. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_ObjectsRet: \t%d", pObj->dwNumObjectsRet);
  1503. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERRORINFO_RetBuffSize: \t%d", pObj->dwRetBufSize);
  1504. break;
  1505. }
  1506. } while (--dwLoopCount > 0);
  1507. if (dwStatus == ERROR_SUCCESS) {
  1508. // dump collect fn stats.
  1509. if ((pObj->dwCollectCount > 0) && (pObj->dwNumObjectsRet > 0)){
  1510. // don't compute time if no objects were returned
  1511. dMs = (DOUBLE)pObj->llCollectTime;
  1512. dMs /= (DOUBLE)pObj->llTimeBase;
  1513. dMs *= 1000.0;
  1514. dMs /= (DOUBLE)pObj->dwCollectCount;
  1515. fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_AvgCollectProcTime: \t%12.5f mSec", dMs);
  1516. fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_CollectProcTimeout: \t%6d.00000 mSec", pObj->dwCollectTimeout);
  1517. }
  1518. fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_ObjectsRet: \t%d", pObj->dwNumObjectsRet);
  1519. fwprintf (pOutput, (LPCWSTR)L"\n\t\tINFO_RetBuffSize: \t%d", pObj->dwRetBufSize);
  1520. }
  1521. HeapFree (hTestHeap, 0, pBuffer);
  1522. }
  1523. dwRetStatus = dwStatus;
  1524. // close
  1525. CloseLibrary (pObj);
  1526. } // unable to open library
  1527. HeapValidate (hTestHeap, 0, NULL);
  1528. return dwStatus;
  1529. }
  1530. DWORD
  1531. CycleThreadProc (
  1532. LPVOID lpThreadArg
  1533. )
  1534. {
  1535. DWORD dwStatus = ERROR_SUCCESS;
  1536. PLOCAL_THREAD_DATA pData= (PLOCAL_THREAD_DATA)lpThreadArg;
  1537. DWORD dwCycleCount = pData->dwCycleCount;
  1538. DWORD dwThisThread = GetCurrentThreadId();
  1539. HeapValidate (hTestHeap, 0, NULL);
  1540. do {
  1541. // argv[1] is the name of the
  1542. dwStatus = CycleTest(dwThisThread, pData);
  1543. } while (--dwCycleCount > 0);
  1544. HeapValidate (hTestHeap, 0, NULL);
  1545. return dwStatus;
  1546. }
  1547. int
  1548. WriteTestResultHeader(
  1549. FILE *pOutput
  1550. )
  1551. {
  1552. OSVERSIONINFOW osInfo;
  1553. WCHAR szMachineName[MAX_PATH];
  1554. DWORD dwSize;
  1555. SYSTEMTIME stStart;
  1556. memset (&osInfo, 0, sizeof(osInfo));
  1557. osInfo.dwOSVersionInfoSize = sizeof(osInfo);
  1558. memset (szMachineName, 0, sizeof(szMachineName));
  1559. memset (&stStart, 0, sizeof(stStart));
  1560. GetVersionExW (&osInfo);
  1561. dwSize = sizeof(szMachineName) / sizeof (szMachineName[0]);
  1562. GetComputerNameW (&szMachineName[0], &dwSize);
  1563. GetLocalTime (&stStart);
  1564. fwprintf (pOutput, (LPCWSTR)L"\n[TESTRESULT]");
  1565. fwprintf (pOutput, (LPCWSTR)L"\n\tTEST: \tPerf Counter DLL Validation");
  1566. fwprintf (pOutput, (LPCWSTR)L"\n\tBUILD: \t%d", osInfo.dwBuildNumber);
  1567. fwprintf (pOutput, (LPCWSTR)L"\n\tMACHINE:\t%s", szMachineName);
  1568. fwprintf (pOutput, (LPCWSTR)L"\n\tCONTACT:\t%s", szContact);
  1569. fwprintf (pOutput, (LPCWSTR)L"\n\tMGR CONTACT:\t%s", szMgrContact);
  1570. fwprintf (pOutput, (LPCWSTR)L"\n\tDEV PRIME:\t%s", szDevPrime);
  1571. fwprintf (pOutput, (LPCWSTR)L"\n\tDEV ALT:\t%s", szDevAlt);
  1572. fwprintf (pOutput, (LPCWSTR)L"\n\tTEST PRIME:\t%s", szTestPrime);
  1573. fwprintf (pOutput, (LPCWSTR)L"\n\tTEST ALT:\t%s", szTestAlt);
  1574. fwprintf (pOutput, (LPCWSTR)L"\n\tSTART TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d",
  1575. stStart.wMonth, stStart.wDay, stStart.wYear % 100,
  1576. stStart.wHour, stStart.wMinute, stStart.wSecond );
  1577. return 0;
  1578. }
  1579. int
  1580. WriteTestConfigData(
  1581. FILE *pOutput,
  1582. LPDWORD pdwIdInfo
  1583. )
  1584. {
  1585. fwprintf (pOutput, (LPCWSTR)L"\n\t");
  1586. fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_Perflib_LastCounter:\t%d", pdwIdInfo[0]);
  1587. fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_String_LastCounter: \t%d", pdwIdInfo[1]);
  1588. fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_Perflib_LastHelp: \t%d", pdwIdInfo[2]);
  1589. fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_String_LastHelp: \t%d", pdwIdInfo[3]);
  1590. fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_Disabled: \t%d", pdwIdInfo[4]);
  1591. fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_ExtCounterTestLevel:\t%d", pdwIdInfo[5]);
  1592. fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_BaseIndex: \t%d", pdwIdInfo[6]);
  1593. // fwprintf (pOutput, (LPCWSTR)L"\n\tCONFIG_BaseOsObject : \t%d", pdwIdInfo[7]);
  1594. return 0;
  1595. }
  1596. DWORD
  1597. WriteGroupConfig(
  1598. FILE *pOutput,
  1599. HKEY hKeyPerfSubKey,
  1600. DWORD *pIds
  1601. )
  1602. {
  1603. DWORD nRetStatus = (int)ERROR_SUCCESS;
  1604. DWORD lStatus;
  1605. DWORD dwData;
  1606. DWORD dwBufferSize;
  1607. DWORD dwValueType;
  1608. WCHAR szStringBuffer[MAX_PATH*2];
  1609. dwBufferSize = sizeof(szStringBuffer);
  1610. dwValueType = 0;
  1611. memset (szStringBuffer, 0, sizeof(szStringBuffer));
  1612. lStatus = RegQueryValueExW (
  1613. hKeyPerfSubKey,
  1614. (LPCWSTR)L"Library",
  1615. 0L,
  1616. &dwValueType,
  1617. (LPBYTE)&szStringBuffer[0],
  1618. &dwBufferSize);
  1619. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Library:\t%s",
  1620. (lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
  1621. if (lStatus != ERROR_SUCCESS) nRetStatus = lStatus;
  1622. dwBufferSize = sizeof(szStringBuffer);
  1623. dwValueType = 0;
  1624. memset (szStringBuffer, 0, sizeof(szStringBuffer));
  1625. lStatus = RegQueryValueExW (
  1626. hKeyPerfSubKey,
  1627. (LPCWSTR)L"Open",
  1628. 0L,
  1629. &dwValueType,
  1630. (LPBYTE)&szStringBuffer[0],
  1631. &dwBufferSize);
  1632. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Open:\t%s",
  1633. (lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
  1634. if (lStatus != ERROR_SUCCESS) nRetStatus = lStatus;
  1635. dwBufferSize = sizeof(szStringBuffer);
  1636. dwValueType = 0;
  1637. memset (szStringBuffer, 0, sizeof(szStringBuffer));
  1638. lStatus = RegQueryValueExW (
  1639. hKeyPerfSubKey,
  1640. (LPCWSTR)L"Collect",
  1641. 0L,
  1642. &dwValueType,
  1643. (LPBYTE)&szStringBuffer[0],
  1644. &dwBufferSize);
  1645. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Collect:\t%s",
  1646. (lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
  1647. if (lStatus != ERROR_SUCCESS) nRetStatus = lStatus;
  1648. dwBufferSize = sizeof(szStringBuffer);
  1649. dwValueType = 0;
  1650. memset (szStringBuffer, 0, sizeof(szStringBuffer));
  1651. lStatus = RegQueryValueExW (
  1652. hKeyPerfSubKey,
  1653. (LPCWSTR)L"Object List",
  1654. 0L,
  1655. &dwValueType,
  1656. (LPBYTE)&szStringBuffer[0],
  1657. &dwBufferSize);
  1658. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Object List:\t%s",
  1659. (lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
  1660. dwBufferSize = sizeof(szStringBuffer);
  1661. dwValueType = 0;
  1662. memset (szStringBuffer, 0, sizeof(szStringBuffer));
  1663. lStatus = RegQueryValueExW (
  1664. hKeyPerfSubKey,
  1665. (LPCWSTR)L"Close",
  1666. 0L,
  1667. &dwValueType,
  1668. (LPBYTE)&szStringBuffer[0],
  1669. &dwBufferSize);
  1670. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Close:\t%s",
  1671. (lStatus == ERROR_SUCCESS ? szStringBuffer : cszNotFound));
  1672. if (lStatus != ERROR_SUCCESS) nRetStatus = lStatus;
  1673. dwBufferSize = sizeof(dwData);
  1674. dwValueType = 0;
  1675. dwData = 0;
  1676. lStatus = RegQueryValueExW (
  1677. hKeyPerfSubKey,
  1678. (LPCWSTR)L"First Counter",
  1679. 0L,
  1680. &dwValueType,
  1681. (LPBYTE)&dwData,
  1682. &dwBufferSize);
  1683. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_First Counter:\t%d",
  1684. (lStatus == ERROR_SUCCESS ? dwData : (DWORD)-1));
  1685. if (lStatus != ERROR_SUCCESS) {
  1686. if (lStatus == ERROR_FILE_NOT_FOUND) {
  1687. if (!pIds[4]) {
  1688. // then this hasn't been installed yet
  1689. nRetStatus = ERROR_SERVICE_DISABLED;
  1690. } else {
  1691. // then this is a base OS service
  1692. nRetStatus = ERROR_SUCCESS;
  1693. }
  1694. } else {
  1695. // some other error so return
  1696. nRetStatus = lStatus;
  1697. }
  1698. pIds[0] = (DWORD)-1;
  1699. } else {
  1700. pIds[0] = dwData;
  1701. }
  1702. dwBufferSize = sizeof(dwData);
  1703. dwValueType = 0;
  1704. dwData = 0;
  1705. lStatus = RegQueryValueExW (
  1706. hKeyPerfSubKey,
  1707. (LPCWSTR)L"Last Counter",
  1708. 0L,
  1709. &dwValueType,
  1710. (LPBYTE)&dwData,
  1711. &dwBufferSize);
  1712. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Last Counter:\t%d",
  1713. (lStatus == ERROR_SUCCESS ? dwData : (DWORD)-1));
  1714. if (lStatus != ERROR_SUCCESS) {
  1715. if (lStatus == ERROR_FILE_NOT_FOUND) {
  1716. if (!pIds[4]) {
  1717. // then this hasn't been installed yet
  1718. nRetStatus = ERROR_SERVICE_DISABLED;
  1719. } else {
  1720. // then this is a base OS service
  1721. nRetStatus = ERROR_SUCCESS;
  1722. }
  1723. } else {
  1724. // some other error so return
  1725. nRetStatus = lStatus;
  1726. }
  1727. pIds[1] = (DWORD)-1;
  1728. } else {
  1729. pIds[1] = dwData;
  1730. }
  1731. dwBufferSize = sizeof(dwData);
  1732. dwValueType = 0;
  1733. dwData = 0;
  1734. lStatus = RegQueryValueExW (
  1735. hKeyPerfSubKey,
  1736. (LPCWSTR)L"First Help",
  1737. 0L,
  1738. &dwValueType,
  1739. (LPBYTE)&dwData,
  1740. &dwBufferSize);
  1741. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_First Help:\t%d",
  1742. (lStatus == ERROR_SUCCESS ? dwData : (DWORD)-1));
  1743. if (lStatus != ERROR_SUCCESS) {
  1744. if (lStatus == ERROR_FILE_NOT_FOUND) {
  1745. if (!pIds[4]) {
  1746. // then this hasn't been installed yet
  1747. nRetStatus = ERROR_SERVICE_DISABLED;
  1748. } else {
  1749. // then this is a base OS service
  1750. nRetStatus = ERROR_SUCCESS;
  1751. }
  1752. } else {
  1753. // some other error so return
  1754. nRetStatus = lStatus;
  1755. }
  1756. pIds[2] = (DWORD)-1;
  1757. } else {
  1758. pIds[2] = dwData;
  1759. }
  1760. dwBufferSize = sizeof(dwData);
  1761. dwValueType = 0;
  1762. dwData = 0;
  1763. lStatus = RegQueryValueExW (
  1764. hKeyPerfSubKey,
  1765. (LPCWSTR)L"Last Help",
  1766. 0L,
  1767. &dwValueType,
  1768. (LPBYTE)&dwData,
  1769. &dwBufferSize);
  1770. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Last Help:\t%d",
  1771. (lStatus == ERROR_SUCCESS ? dwData : (DWORD)-1));
  1772. if (lStatus != ERROR_SUCCESS) {
  1773. if (lStatus == ERROR_FILE_NOT_FOUND) {
  1774. if (!pIds[4]) {
  1775. // then this hasn't been installed yet
  1776. nRetStatus = ERROR_SERVICE_DISABLED;
  1777. } else {
  1778. // then this is a base OS service
  1779. nRetStatus = ERROR_SUCCESS;
  1780. }
  1781. } else {
  1782. // some other error so return
  1783. nRetStatus = lStatus;
  1784. }
  1785. pIds[3] = (DWORD)-1;
  1786. } else {
  1787. pIds[3] = dwData;
  1788. }
  1789. dwBufferSize = sizeof(dwData);
  1790. dwValueType = 0;
  1791. dwData = 0;
  1792. lStatus = RegQueryValueExW (
  1793. hKeyPerfSubKey,
  1794. (LPCWSTR)L"Open Timeout",
  1795. 0L,
  1796. &dwValueType,
  1797. (LPBYTE)&dwData,
  1798. &dwBufferSize);
  1799. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Open Timeout:\t%d",
  1800. (lStatus == ERROR_SUCCESS ? dwData : (DWORD)10000));
  1801. dwBufferSize = sizeof(dwData);
  1802. dwValueType = 0;
  1803. dwData = 0;
  1804. lStatus = RegQueryValueExW (
  1805. hKeyPerfSubKey,
  1806. (LPCWSTR)L"Collect Timeout",
  1807. 0L,
  1808. &dwValueType,
  1809. (LPBYTE)&dwData,
  1810. &dwBufferSize);
  1811. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Collect Timeout:\t%d",
  1812. (lStatus == ERROR_SUCCESS ? dwData : (DWORD)10000));
  1813. dwBufferSize = sizeof(dwData);
  1814. dwValueType = 0;
  1815. dwData = 0;
  1816. lStatus = RegQueryValueExW (
  1817. hKeyPerfSubKey,
  1818. (LPCWSTR)L"Disable Performance Counters",
  1819. 0L,
  1820. &dwValueType,
  1821. (LPBYTE)&dwData,
  1822. &dwBufferSize);
  1823. fwprintf (pOutput, (LPCWSTR)L"\n\t\tCONFIG_Disable Performance Counters:\t%d",
  1824. (lStatus == ERROR_SUCCESS ? dwData : (DWORD)0));
  1825. if ((lStatus == ERROR_SUCCESS) && (dwData != 0)){
  1826. nRetStatus = ERROR_SERVICE_DISABLED;
  1827. }
  1828. return nRetStatus;
  1829. }
  1830. int
  1831. WriteTestResultTrailer(
  1832. FILE *pOutput,
  1833. DWORD dwTestResult
  1834. )
  1835. {
  1836. SYSTEMTIME stEnd;
  1837. LPWSTR szResult;
  1838. memset (&stEnd, 0, sizeof(stEnd));
  1839. GetLocalTime (&stEnd);
  1840. switch (dwTestResult) {
  1841. case PERFVAL_PASS:
  1842. szResult = (LPWSTR)L"PASS"; break;
  1843. case PERFVAL_FAIL:
  1844. szResult = (LPWSTR)L"FAIL"; break;
  1845. case PERFVAL_TIMEOUT:
  1846. szResult = (LPWSTR)L"TIMEOUT"; break;
  1847. case PERFVAL_NOCONFIG:
  1848. default:
  1849. szResult = (LPWSTR)L"NOCONFIG"; break;
  1850. }
  1851. fwprintf (pOutput, (LPCWSTR)L"\n\n\tRESULT: \t%s", szResult);
  1852. fwprintf (pOutput, (LPCWSTR)L"\n\tEND TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d",
  1853. stEnd.wMonth, stEnd.wDay, stEnd.wYear % 100,
  1854. stEnd.wHour, stEnd.wMinute, stEnd.wSecond);
  1855. fwprintf (pOutput, (LPCWSTR)L"\n[/TESTRESULT]");
  1856. fwprintf (pOutput, (LPCWSTR)L"\n");
  1857. return 0;
  1858. }
  1859. int
  1860. WriteGroupHeader(FILE *pOutput, LPCWSTR szGroupName)
  1861. {
  1862. SYSTEMTIME stStart;
  1863. memset (&stStart, 0, sizeof(stStart));
  1864. GetLocalTime (&stStart);
  1865. fwprintf (pOutput, (LPCWSTR)L"\n\n\t[GROUP: %s]", szGroupName);
  1866. fwprintf (pOutput, (LPCWSTR)L"\n\t\tSTART TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d.%3.3d",
  1867. stStart.wMonth, stStart.wDay, stStart.wYear % 100,
  1868. stStart.wHour, stStart.wMinute, stStart.wSecond, stStart.wMilliseconds );
  1869. return 0;
  1870. }
  1871. int
  1872. WriteGroupTrailer(FILE *pOutput, DWORD dwTestResult)
  1873. {
  1874. LPWSTR szResult;
  1875. SYSTEMTIME stEnd;
  1876. memset (&stEnd, 0, sizeof(stEnd));
  1877. GetLocalTime (&stEnd);
  1878. switch (dwTestResult) {
  1879. case PERFVAL_PASS:
  1880. szResult = (LPWSTR)L"PASS"; break;
  1881. case PERFVAL_FAIL:
  1882. szResult = (LPWSTR)L"FAIL"; break;
  1883. case PERFVAL_TIMEOUT:
  1884. szResult = (LPWSTR)L"TIMEOUT"; break;
  1885. case PERFVAL_NOCONFIG:
  1886. default:
  1887. szResult = (LPWSTR)L"NOCONFIG"; break;
  1888. }
  1889. fwprintf (pOutput, (LPCWSTR)L"\n\t\tEND TIME:\t%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d.%3.3d",
  1890. stEnd.wMonth, stEnd.wDay, stEnd.wYear % 100,
  1891. stEnd.wHour, stEnd.wMinute, stEnd.wSecond, stEnd.wMilliseconds );
  1892. fwprintf (pOutput, (LPCWSTR)L"\n\t\tRESULT: %s", szResult);
  1893. fwprintf (pOutput, (LPCWSTR)L"\n\t[/GROUP]");
  1894. return 0;
  1895. }
  1896. int
  1897. PerfVal_ConfigTestFunction (
  1898. FILE *pOutput,
  1899. LPDWORD pdwIdInfo
  1900. )
  1901. {
  1902. DWORD dwReturn = ERROR_SUCCESS;
  1903. UNREFERENCED_PARAMETER (pOutput);
  1904. // configuration tests:
  1905. // LAST COUNTER in registry >= Last counter string index
  1906. // LAST HELP in registry >= Last help string index
  1907. // BASE INDEX == 1847
  1908. SetLastError (ERROR_SUCCESS);
  1909. szTestErrorMessage = NULL;
  1910. if (pdwIdInfo[0] < pdwIdInfo[1]) {
  1911. dwReturn = ERROR_INVALID_INDEX;
  1912. szTestErrorMessage = (LPWSTR)L"Counter String has too many entries";
  1913. }
  1914. if (pdwIdInfo[2] < pdwIdInfo[3]) {
  1915. dwReturn = ERROR_INVALID_INDEX;
  1916. szTestErrorMessage = (LPWSTR)L"Help String has too many entries";
  1917. }
  1918. if (pdwIdInfo[6] != 1847) {
  1919. dwReturn = ERROR_INVALID_PARAMETER;
  1920. szTestErrorMessage = (LPWSTR)L"Base Index is incorrect";
  1921. }
  1922. return dwReturn;
  1923. }
  1924. int
  1925. PerfVal_ServiceTestConfig (
  1926. FILE *pOutput,
  1927. LPDWORD dwNameIds,
  1928. LPCWSTR *pNameTable,
  1929. DWORD dwLastId
  1930. )
  1931. {
  1932. DWORD dwServiceTestResult = ERROR_SUCCESS;
  1933. DWORD dwIdIdx = 0;
  1934. // check counter strings
  1935. if ((dwNameIds[0] != (DWORD)-1) && (dwNameIds[1] != (DWORD)-1)) {
  1936. if (((dwNameIds[0] <= dwLastId) && (dwNameIds[1] <= dwLastId)) &&
  1937. (dwNameIds[0] < dwNameIds[1])){
  1938. for (dwIdIdx = dwNameIds[0]; dwIdIdx <= dwNameIds[1]; dwIdIdx += 2) {
  1939. if (pNameTable[dwIdIdx] == NULL) {
  1940. // no string
  1941. fwprintf (pOutput, (LPCWSTR)L"\n\t\tWARNING:\tNo Display String for index %d", dwIdIdx);
  1942. dwServiceTestResult = ERROR_BADKEY;
  1943. } else {
  1944. // probably ok
  1945. }
  1946. }
  1947. } else {
  1948. // id out of range
  1949. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tCounter Index values are bad or missing");
  1950. dwServiceTestResult = ERROR_BADKEY;
  1951. }
  1952. } else {
  1953. // not installed or a base counter
  1954. }
  1955. // check help strings
  1956. if ((dwNameIds[2] != (DWORD)-1) && (dwNameIds[3] != (DWORD)-1)) {
  1957. if (((dwNameIds[2] <= dwLastId) && (dwNameIds[3] <= dwLastId)) &&
  1958. (dwNameIds[2] < dwNameIds[3])){
  1959. for (dwIdIdx = dwNameIds[2]; dwIdIdx <= dwNameIds[3]; dwIdIdx += 2) {
  1960. if (pNameTable[dwIdIdx] == NULL) {
  1961. // no string
  1962. fwprintf (pOutput, (LPCWSTR)L"\n\t\tWARNING:\tNo Display String for index %d", dwIdIdx);
  1963. dwServiceTestResult = ERROR_BADKEY;
  1964. } else {
  1965. // probably ok
  1966. }
  1967. }
  1968. } else {
  1969. // id out of range
  1970. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tCounter Index values are bad or missing");
  1971. dwServiceTestResult = ERROR_BADKEY;
  1972. }
  1973. } else {
  1974. // not installed or a base counter
  1975. }
  1976. return dwServiceTestResult ;
  1977. }
  1978. DWORD
  1979. PerfVal_ServiceTestFunction (
  1980. FILE *pOutput,
  1981. LPCWSTR szServiceName,
  1982. HKEY hKeyPerfSubKey,
  1983. BOOL bTestContents,
  1984. LPWSTR *pNameTable,
  1985. DWORD dwLastEntry
  1986. )
  1987. {
  1988. DWORD dwLoopCount = 1;
  1989. DWORD dwCycleCount = 1;
  1990. DWORD dwThreadCount = 0;
  1991. LOCAL_THREAD_DATA LTData;
  1992. HANDLE hThreads[MAXIMUM_WAIT_OBJECTS];
  1993. DWORD dwThisThread;
  1994. DWORD dwTimeout;
  1995. DWORD dwId;
  1996. DWORD dwStatus;
  1997. UNREFERENCED_PARAMETER (hKeyPerfSubKey);
  1998. LTData.szServiceName = (LPWSTR)szServiceName;
  1999. LTData.szQueryString = (LPWSTR)L"Global";
  2000. LTData.dwCycleCount = dwCycleCount;
  2001. LTData.dwLoopCount = dwLoopCount;
  2002. LTData.bDisplay = FALSE;//(dwThreadCount <= 1 ? TRUE : FALSE);
  2003. LTData.pOutput = pOutput;
  2004. LTData.bTestContents = bTestContents;
  2005. LTData.pNameTable = pNameTable;
  2006. LTData.dwLastIndex = dwLastEntry;
  2007. if (dwThreadCount == 0) {
  2008. dwStatus = CycleThreadProc ((LPVOID)&LTData);
  2009. } else {
  2010. // create threads
  2011. for (dwThisThread = 0; dwThisThread < dwThreadCount; dwThisThread++) {
  2012. hThreads[dwThisThread] = CreateThread(
  2013. NULL, 0L, CycleThreadProc, (LPVOID)&LTData, 0L, &dwId);
  2014. }
  2015. dwTimeout = 60000 * dwCycleCount; // allow 1 minute per cycle
  2016. dwStatus = WaitForMultipleObjects (dwThreadCount, hThreads, TRUE, dwTimeout);
  2017. if (dwStatus != WAIT_TIMEOUT) {
  2018. dwStatus = ERROR_SUCCESS;
  2019. } else {
  2020. fwprintf (pOutput, (LPCWSTR)L"\n\t\tERROR:\tWait for test cycles to complete exceeded 60 seconds");
  2021. }
  2022. for (dwThisThread = 0; dwThisThread < dwThreadCount; dwThisThread++) {
  2023. CloseHandle (hThreads[dwThisThread]);
  2024. }
  2025. }
  2026. return dwStatus;
  2027. }
  2028. int
  2029. WriteTestError (
  2030. FILE *pOutput,
  2031. DWORD dwTabLevel,
  2032. DWORD dwStatus
  2033. )
  2034. {
  2035. DWORD dwIndent;
  2036. fwprintf (pOutput, (LPCWSTR)L"\n");
  2037. for (dwIndent = 0; dwIndent < dwTabLevel; dwIndent++) {
  2038. fwprintf (pOutput, (LPCWSTR)L"\t");
  2039. }
  2040. fwprintf (pOutput, (LPCWSTR)L"ERROR: \t%s", (szTestErrorMessage != NULL ? szTestErrorMessage : (LPCWSTR)L"No Error"));
  2041. fwprintf (pOutput, (LPCWSTR)L"\n");
  2042. for (dwIndent = 0; dwIndent < dwTabLevel; dwIndent++) {
  2043. fwprintf (pOutput, (LPCWSTR)L"\t");
  2044. }
  2045. fwprintf (pOutput, (LPCWSTR)L"ERRORCODE:\t0x%8.8x (%d)", dwStatus, dwStatus);
  2046. return 0;
  2047. }
  2048. int
  2049. __cdecl
  2050. wmain(
  2051. int argc,
  2052. WCHAR *argv[]
  2053. )
  2054. {
  2055. DWORD dwStatus = ERROR_SUCCESS;
  2056. LONG lStatus = ERROR_SUCCESS;
  2057. LONG lEnumStatus = ERROR_SUCCESS;
  2058. DWORD dwServiceIndex;
  2059. WCHAR szServiceSubKeyName[MAX_PATH];
  2060. WCHAR szPerfSubKeyName[MAX_PATH+20];
  2061. DWORD dwNameSize;
  2062. HKEY hKeyPerformance;
  2063. DWORD dwLastElement = 0;
  2064. DWORD dwIdArray[8];
  2065. DWORD dwServiceIds[8];
  2066. HKEY hKeyServices;
  2067. HKEY hKeyMachine = HKEY_LOCAL_MACHINE;
  2068. DWORD dwRegAccessMask = KEY_READ;
  2069. DWORD dwTestResult = PERFVAL_NOCONFIG;
  2070. DWORD dwGroupTestResult = PERFVAL_NOCONFIG;
  2071. BOOL bTestContents;
  2072. FILE *pOutput = stdout;
  2073. LPWSTR *pNameTable = NULL;
  2074. UNREFERENCED_PARAMETER (argc);
  2075. UNREFERENCED_PARAMETER (argv);
  2076. // enumerate the services to find those with performance counters
  2077. hProcessHeap = GetProcessHeap();
  2078. hTestHeap = HeapCreate (HEAP_GENERATE_EXCEPTIONS, 0x10000, 0);
  2079. if (hTestHeap == NULL) return (ERROR_OUTOFMEMORY);
  2080. WriteTestResultHeader(pOutput);
  2081. memset (&dwIdArray[0], 0, sizeof(dwIdArray));
  2082. pNameTable = BuildNameTable (
  2083. (LPCWSTR)L"",
  2084. (LPCWSTR)L"009",
  2085. &dwLastElement, // size of array in elements
  2086. &dwIdArray[0]);
  2087. WriteTestConfigData(pOutput, &dwIdArray[0]);
  2088. if (pNameTable == NULL) {
  2089. // check for name table errors
  2090. lStatus = GetLastError(); // so we don't continue
  2091. dwTestResult = PERFVAL_FAIL;
  2092. WriteTestError (pOutput, 1, lStatus);
  2093. } else {
  2094. // test config data
  2095. lStatus = PerfVal_ConfigTestFunction (pOutput, &dwIdArray[0]);
  2096. if (lStatus != ERROR_SUCCESS) {
  2097. dwTestResult = PERFVAL_FAIL;
  2098. WriteTestError (pOutput, 1, lStatus);
  2099. } else {
  2100. // assume pass until something fails
  2101. dwTestResult = PERFVAL_PASS;
  2102. // continue with the test
  2103. lStatus = RegOpenKeyExW (hKeyMachine,
  2104. cszServiceKeyName,
  2105. 0L,
  2106. dwRegAccessMask,
  2107. &hKeyServices);
  2108. if (lStatus != ERROR_SUCCESS) {
  2109. dwTestResult = PERFVAL_FAIL;
  2110. szTestErrorMessage = (LPWSTR)L"Unable to open the HKLM\\SYSTEM\\CurrentControlSet\\Services key";
  2111. WriteTestError (pOutput, 1, lStatus);
  2112. } else {
  2113. // continue processing
  2114. dwServiceIndex = 0;
  2115. dwNameSize = MAX_PATH;
  2116. while ((lEnumStatus = RegEnumKeyExW (
  2117. hKeyServices,
  2118. dwServiceIndex,
  2119. szServiceSubKeyName,
  2120. &dwNameSize,
  2121. NULL,
  2122. NULL,
  2123. NULL,
  2124. NULL)) == ERROR_SUCCESS) {
  2125. // assume pass until something fails
  2126. dwGroupTestResult = PERFVAL_PASS;
  2127. //try to open the perfkey under this key.
  2128. lstrcpyW (szPerfSubKeyName, szServiceSubKeyName);
  2129. lstrcatW (szPerfSubKeyName, cszPerformance);
  2130. lStatus = RegOpenKeyExW (
  2131. hKeyServices,
  2132. szPerfSubKeyName,
  2133. 0L,
  2134. dwRegAccessMask,
  2135. &hKeyPerformance);
  2136. if (lStatus == ERROR_SUCCESS) {
  2137. WriteGroupHeader (pOutput, szServiceSubKeyName);
  2138. if (IsMsService (szServiceSubKeyName)) {
  2139. dwServiceIds[4] = 1;
  2140. } else {
  2141. dwServiceIds[4] = 0;
  2142. }
  2143. lStatus = WriteGroupConfig (pOutput, hKeyPerformance, &dwServiceIds[0]);
  2144. if (lStatus == ERROR_SUCCESS) {
  2145. // test this service
  2146. lStatus = PerfVal_ServiceTestConfig (pOutput,
  2147. &dwServiceIds[0], pNameTable, dwLastElement);
  2148. }
  2149. if ((lStatus == ERROR_SUCCESS) || (lStatus == ERROR_BADKEY)){
  2150. bTestContents = (lStatus == ERROR_BADKEY ? TRUE : FALSE);
  2151. lStatus = PerfVal_ServiceTestFunction (pOutput,
  2152. szServiceSubKeyName, hKeyPerformance, bTestContents, pNameTable, dwLastElement);
  2153. }
  2154. if (lStatus != ERROR_SUCCESS) {
  2155. if (lStatus != ERROR_SERVICE_DISABLED) {
  2156. // if the service is disabled, then it's a pass,
  2157. // otherwise it's failed in the configuration.
  2158. dwGroupTestResult = PERFVAL_FAIL;
  2159. dwTestResult = PERFVAL_FAIL;
  2160. } else {
  2161. dwGroupTestResult = PERFVAL_NOCONFIG;
  2162. }
  2163. }
  2164. WriteGroupTrailer(pOutput, dwGroupTestResult);
  2165. RegCloseKey (hKeyPerformance);
  2166. }
  2167. // reset for next loop
  2168. dwServiceIndex++;
  2169. dwNameSize = MAX_PATH;
  2170. }
  2171. RegCloseKey (hKeyServices);
  2172. }
  2173. }
  2174. }
  2175. WriteTestResultTrailer(pOutput, dwTestResult);
  2176. HeapDestroy (hTestHeap);
  2177. return (int)dwStatus;
  2178. }