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.

2361 lines
71 KiB

  1. //==========================================================================//
  2. // Includes //
  3. //==========================================================================//
  4. #include <string.h> // strupr
  5. #include <stdio.h> // for sprintf.
  6. #include "setedit.h"
  7. #include "utils.h"
  8. #include "pmemory.h" // for MemoryXXX (mallloc-type) routines
  9. #include "perfdata.h" // external declarations for this file
  10. #include "system.h" // for DeleteUnusedSystems
  11. //==========================================================================//
  12. // Constants //
  13. //==========================================================================//
  14. TCHAR NamesKey[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
  15. TCHAR Counters[] = L"Counters";
  16. TCHAR Help[] = L"Help";
  17. TCHAR LastHelp[] = L"Last Help";
  18. TCHAR LastCounter[] = L"Last Counter";
  19. TCHAR SysVersion[] = L"Version";
  20. TCHAR CounterNameStr[] = L"Counter ";
  21. TCHAR ExplainNameStr[] = L"Explain ";
  22. #define szPerfSubkey (NULL)
  23. TCHAR NULL_NAME[] = L" ";
  24. #define RESERVED 0L
  25. TCHAR DefaultLangId[4] ;
  26. TCHAR EnglishLangId[4] ;
  27. static HANDLE *lpHandles ;
  28. static int NumberOfHandles = 0 ;
  29. //==========================================================================//
  30. // Macros //
  31. //==========================================================================//
  32. //==========================================================================//
  33. // Local Data //
  34. //==========================================================================//
  35. // When the conversion of this code is complete, this will be the *only*
  36. // allocated copy of the performance data. It will monotonically grow
  37. // to hold the largest of the system's performance data.
  38. // PPERFDATA pGlobalPerfData ;
  39. //==========================================================================//
  40. // Local Functions //
  41. //==========================================================================//
  42. NTSTATUS
  43. AddNamesToArray (
  44. LPTSTR pNames,
  45. DWORD dwLastID,
  46. LPWSTR *lpCounterId
  47. ) ;
  48. //======================================//
  49. // Object Accessors //
  50. //======================================//
  51. void
  52. ObjectName (
  53. PPERFSYSTEM pSystem,
  54. PPERFOBJECT pObject,
  55. LPTSTR lpszName,
  56. int iLen
  57. )
  58. { // ObjectName
  59. strclr (lpszName) ;
  60. QueryPerformanceName (pSystem,
  61. pObject->ObjectNameTitleIndex,
  62. 0, iLen, lpszName, FALSE) ;
  63. } // ObjectName
  64. //======================================//
  65. // Counter Accessors //
  66. //======================================//
  67. PERF_INSTANCE_DEFINITION *
  68. FirstInstance(
  69. PERF_OBJECT_TYPE UNALIGNED *pObjectDef
  70. )
  71. {
  72. return (PERF_INSTANCE_DEFINITION *)
  73. ((PCHAR) pObjectDef + pObjectDef->DefinitionLength);
  74. }
  75. PERF_INSTANCE_DEFINITION *
  76. NextInstance(
  77. PERF_INSTANCE_DEFINITION *pInstDef
  78. )
  79. {
  80. PERF_COUNTER_BLOCK *pCounterBlock;
  81. pCounterBlock = (PERF_COUNTER_BLOCK *)
  82. ((PCHAR) pInstDef + pInstDef->ByteLength);
  83. return (PERF_INSTANCE_DEFINITION *)
  84. ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  85. }
  86. LPTSTR
  87. GetInstanceName(
  88. PPERFINSTANCEDEF pInstDef)
  89. {
  90. return (LPTSTR) ((PCHAR) pInstDef + pInstDef->NameOffset);
  91. }
  92. void
  93. GetInstanceNameStr (
  94. PPERFINSTANCEDEF pInstance,
  95. LPTSTR lpszInstance
  96. )
  97. {
  98. // This function used to test for ansi names, but
  99. // instance names should ALWAYS be wide character
  100. // strings so this is removed (especially since
  101. // looking for a null byte is a bogus test in the
  102. // first place)
  103. LPTSTR pSource;
  104. pSource = (LPTSTR) GetInstanceName(pInstance) ;
  105. wcsncpy (lpszInstance,
  106. (LPTSTR)pSource,
  107. pInstance->NameLength);
  108. }
  109. void
  110. GetPerfComputerName(
  111. PPERFDATA pPerfData,
  112. LPTSTR lpszComputerName
  113. )
  114. {
  115. lstrcpy(lpszComputerName, szComputerPrefix) ;
  116. if (pPerfData) {
  117. wcsncpy (&lpszComputerName[2],
  118. (LPWSTR)((PBYTE) pPerfData + pPerfData->SystemNameOffset),
  119. pPerfData->SystemNameLength/sizeof(WCHAR)) ;
  120. } else {
  121. lpszComputerName[0] = TEXT('\0') ;
  122. }
  123. }
  124. //==========================================================================//
  125. // Exported Functions //
  126. //==========================================================================//
  127. int CounterIndex (PPERFCOUNTERDEF pCounterToFind,
  128. PERF_OBJECT_TYPE UNALIGNED *pObject)
  129. /*
  130. Effect: Return the index ("counter number") of pCounterToFind
  131. within pObject. If the counter doesnt belong to pObject,
  132. return -1.
  133. */
  134. { // CounterIndex
  135. PPERFCOUNTERDEF pCounter ;
  136. UINT iCounter ;
  137. for (iCounter = 0, pCounter = FirstCounter (pObject) ;
  138. iCounter < pObject->NumCounters ;
  139. iCounter++, pCounter = NextCounter (pCounter)) { // for
  140. if (pCounter->CounterNameTitleIndex ==
  141. pCounterToFind->CounterNameTitleIndex)
  142. return (iCounter) ;
  143. } // for
  144. return (-1) ;
  145. } // CounterIndex
  146. HKEY
  147. OpenSystemPerfData (
  148. IN LPCTSTR lpszSystem
  149. )
  150. { // OpenSystemPerfData
  151. HKEY hKey = NULL;
  152. LONG lStatus;
  153. lStatus = ERROR_CANTOPEN; // default error if none is returned
  154. if (IsLocalComputer(lpszSystem)) {
  155. bCloseLocalMachine = TRUE ;
  156. SetLastError (ERROR_SUCCESS);
  157. return HKEY_PERFORMANCE_DATA;
  158. } else if (lstrlen (lpszSystem) < MAX_COMPUTERNAME_LENGTH+3) {
  159. // Must be a remote system
  160. try {
  161. lStatus = RegConnectRegistry (
  162. (LPTSTR)lpszSystem,
  163. HKEY_PERFORMANCE_DATA,
  164. &hKey);
  165. }finally {
  166. if (lStatus != ERROR_SUCCESS) {
  167. SetLastError (lStatus);
  168. hKey = NULL;
  169. }
  170. }
  171. }
  172. return (hKey);
  173. } // OpenSystemPerfData
  174. LPWSTR
  175. *AddNewName(
  176. HKEY hKeyNames,
  177. PCOUNTERTEXT pCounterInfo,
  178. LPWSTR CounterBuffer,
  179. LPWSTR HelpBuffer,
  180. DWORD dwLastId,
  181. DWORD dwCounterSize,
  182. DWORD dwHelpSize,
  183. LANGID LangIdUsed
  184. )
  185. {
  186. LPWSTR *lpReturnValue;
  187. LPWSTR *lpCounterId;
  188. LPWSTR lpCounterNames;
  189. LPWSTR lpHelpText;
  190. DWORD dwArraySize;
  191. DWORD dwBufferSize;
  192. DWORD dwValueType;
  193. LONG lWin32Status;
  194. NTSTATUS Status;
  195. DWORD dwLastError;
  196. dwArraySize = (dwLastId + 1 ) * sizeof(LPWSTR);
  197. lpReturnValue = MemoryAllocate (dwArraySize + dwCounterSize + dwHelpSize);
  198. if (!lpReturnValue) {
  199. lWin32Status = ERROR_NOT_ENOUGH_MEMORY;
  200. goto ERROR_EXIT;
  201. }
  202. // initialize pointers into buffer
  203. lpCounterId = lpReturnValue;
  204. lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
  205. lpHelpText = (LPWSTR)((LPBYTE)lpCounterNames + dwCounterSize);
  206. // read counters into memory
  207. dwBufferSize = dwCounterSize;
  208. lWin32Status = RegQueryValueEx (
  209. hKeyNames,
  210. CounterBuffer,
  211. RESERVED,
  212. &dwValueType,
  213. (LPVOID)lpCounterNames,
  214. &dwBufferSize);
  215. if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT;
  216. if (bExplainTextButtonHit) {
  217. dwBufferSize = dwHelpSize;
  218. lWin32Status = RegQueryValueEx (
  219. hKeyNames,
  220. HelpBuffer,
  221. RESERVED,
  222. &dwValueType,
  223. (LPVOID)lpHelpText,
  224. &dwBufferSize);
  225. if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT;
  226. }
  227. // load counter array items
  228. Status = AddNamesToArray (lpCounterNames, dwLastId, lpCounterId);
  229. if (Status != ERROR_SUCCESS) goto ERROR_EXIT;
  230. if (bExplainTextButtonHit) {
  231. Status = AddNamesToArray (lpHelpText, dwLastId, lpCounterId);
  232. }
  233. if (Status != ERROR_SUCCESS) goto ERROR_EXIT;
  234. if (pCounterInfo) {
  235. pCounterInfo->dwLastId = dwLastId;
  236. pCounterInfo->dwLangId = LangIdUsed;
  237. pCounterInfo->dwHelpSize = dwHelpSize;
  238. pCounterInfo->dwCounterSize = dwCounterSize;
  239. }
  240. return lpReturnValue;
  241. ERROR_EXIT:
  242. if (lWin32Status != ERROR_SUCCESS) {
  243. dwLastError = GetLastError();
  244. }
  245. if (lpReturnValue) {
  246. MemoryFree ((LPVOID)lpReturnValue);
  247. }
  248. return NULL;
  249. }
  250. LPWSTR
  251. *BuildNewNameTable(
  252. PPERFSYSTEM pSystem,
  253. LPWSTR lpszLangId, // unicode value of Language subkey
  254. PCOUNTERTEXT pCounterInfo,
  255. LANGID iLangId, // lang ID of the lpszLangId
  256. DWORD dwLastId
  257. )
  258. /*++
  259. BuildNewNameTable
  260. Arguments:
  261. lpszLangId
  262. The unicode id of the language to look up. (English is 0x409)
  263. Return Value:
  264. pointer to an allocated table. (the caller must free it when finished!)
  265. the table is an array of pointers to zero terminated strings. NULL is
  266. returned if an error occured.
  267. --*/
  268. {
  269. LONG lWin32Status;
  270. DWORD dwValueType;
  271. DWORD dwLastError;
  272. DWORD dwBufferSize;
  273. DWORD dwCounterSize;
  274. DWORD dwHelpSize;
  275. HKEY hKeyNames;
  276. TCHAR CounterBuffer [MiscTextLen] ;
  277. TCHAR ExplainBuffer [MiscTextLen] ;
  278. TCHAR subLangId [ShortTextLen] ;
  279. LANGID LangIdUsed = iLangId;
  280. //initialize local variables
  281. hKeyNames = pSystem->sysDataKey;
  282. // check for null arguments and insert defaults if necessary
  283. if (!lpszLangId) {
  284. lpszLangId = DefaultLangId;
  285. LangIdUsed = iLanguage ;
  286. }
  287. // get size of counter names and add that to the arrays
  288. lstrcpy (CounterBuffer, CounterNameStr);
  289. lstrcat (CounterBuffer, lpszLangId);
  290. lstrcpy (ExplainBuffer, ExplainNameStr);
  291. lstrcat (ExplainBuffer, lpszLangId);
  292. dwBufferSize = 0;
  293. lWin32Status = RegQueryValueEx (
  294. hKeyNames,
  295. CounterBuffer,
  296. RESERVED,
  297. &dwValueType,
  298. NULL,
  299. &dwBufferSize);
  300. if (lWin32Status != ERROR_SUCCESS) {
  301. // check for ACCESS_DENIED error first since if it's here
  302. // it will be returned on all subsequent calls, we might as well
  303. // bail out now.
  304. if (lWin32Status == ERROR_ACCESS_DENIED) {
  305. goto BNT_BAILOUT;
  306. }
  307. // try take out the country ID
  308. LangIdUsed = MAKELANGID (LangIdUsed & 0x0ff, LANG_NEUTRAL);
  309. TSPRINTF (subLangId, TEXT("%03x"), LangIdUsed);
  310. lstrcpy (CounterBuffer, CounterNameStr);
  311. lstrcat (CounterBuffer, subLangId);
  312. lstrcpy (ExplainBuffer, ExplainNameStr);
  313. lstrcpy (ExplainBuffer, subLangId);
  314. dwBufferSize = 0;
  315. lWin32Status = RegQueryValueEx (
  316. hKeyNames,
  317. CounterBuffer,
  318. RESERVED,
  319. &dwValueType,
  320. NULL,
  321. &dwBufferSize);
  322. }
  323. if (lWin32Status != ERROR_SUCCESS) {
  324. // try the EnglishLangId
  325. if (!strsame(EnglishLangId, subLangId)) {
  326. lstrcpy (CounterBuffer, CounterNameStr);
  327. lstrcat (CounterBuffer, EnglishLangId);
  328. lstrcpy (ExplainBuffer, ExplainNameStr);
  329. lstrcpy (ExplainBuffer, EnglishLangId);
  330. LangIdUsed = iEnglishLanguage ;
  331. dwBufferSize = 0;
  332. lWin32Status = RegQueryValueEx (
  333. hKeyNames,
  334. CounterBuffer,
  335. RESERVED,
  336. &dwValueType,
  337. NULL,
  338. &dwBufferSize);
  339. }
  340. }
  341. // Fail, too bad...
  342. if (lWin32Status != ERROR_SUCCESS) {
  343. goto BNT_BAILOUT;
  344. }
  345. dwCounterSize = dwBufferSize;
  346. // If ExplainText is needed, then
  347. // get size of help text and add that to the arrays
  348. if (bExplainTextButtonHit) {
  349. dwBufferSize = 0;
  350. lWin32Status = RegQueryValueEx (
  351. hKeyNames,
  352. ExplainBuffer,
  353. RESERVED,
  354. &dwValueType,
  355. NULL,
  356. &dwBufferSize);
  357. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  358. dwHelpSize = dwBufferSize;
  359. } else {
  360. dwHelpSize = 0;
  361. }
  362. return (AddNewName(
  363. hKeyNames,
  364. pCounterInfo,
  365. CounterBuffer,
  366. ExplainBuffer,
  367. dwLastId,
  368. dwCounterSize,
  369. dwHelpSize,
  370. LangIdUsed));
  371. BNT_BAILOUT:
  372. if (lWin32Status != ERROR_SUCCESS) {
  373. dwLastError = GetLastError();
  374. // set the LastError value since a null pointer will
  375. // be returned which doesn't tell much to the caller
  376. SetLastError (lWin32Status);
  377. }
  378. return NULL;
  379. }
  380. LPWSTR
  381. *BuildOldNameTable(
  382. HKEY hKeyRegistry, // handle to registry db with counter names
  383. LPWSTR lpszLangId, // unicode value of Language subkey
  384. PCOUNTERTEXT pCounterInfo,
  385. LANGID iLangId, // lang ID of the lpszLangId
  386. DWORD dwLastId
  387. )
  388. /*++
  389. BuildOldNameTable
  390. Arguments:
  391. hKeyRegistry
  392. Handle to an open registry (this can be local or remote.) and
  393. is the value returned by RegConnectRegistry or a default key.
  394. lpszLangId
  395. The unicode id of the language to look up. (English is 0x409)
  396. Return Value:
  397. pointer to an allocated table. (the caller must free it when finished!)
  398. the table is an array of pointers to zero terminated strings. NULL is
  399. returned if an error occured.
  400. --*/
  401. {
  402. LPWSTR *lpReturnValue = NULL;
  403. LONG lWin32Status;
  404. DWORD dwValueType;
  405. DWORD dwLastError;
  406. DWORD dwBufferSize;
  407. DWORD dwCounterSize;
  408. DWORD dwHelpSize;
  409. HKEY hKeyNames;
  410. TCHAR tempBuffer [MiscTextLen] ;
  411. TCHAR subLangId [ShortTextLen] ;
  412. LPWSTR lpValueNameString;
  413. LANGID LangIdUsed = iLangId;
  414. TCHAR Slash[2];
  415. //initialize local variables
  416. hKeyNames = NULL;
  417. Slash[0] = L'\\';
  418. Slash[1] = L'\0';
  419. // check for null arguments and insert defaults if necessary
  420. if (!lpszLangId) {
  421. lpszLangId = DefaultLangId;
  422. LangIdUsed = iLanguage ;
  423. }
  424. // get size of string buffer
  425. lpValueNameString = tempBuffer ;
  426. lstrcpy (lpValueNameString, NamesKey);
  427. lstrcat (lpValueNameString, Slash);
  428. lstrcat (lpValueNameString, lpszLangId);
  429. lWin32Status = RegOpenKeyEx (
  430. hKeyRegistry,
  431. lpValueNameString,
  432. RESERVED,
  433. KEY_READ,
  434. &hKeyNames);
  435. if (lWin32Status != ERROR_SUCCESS) {
  436. // check for ACCESS_DENIED error first since if it's here
  437. // it will be returned on all subsequent calls, we might as well
  438. // bail out now.
  439. if (lWin32Status == ERROR_ACCESS_DENIED) {
  440. goto BNT_BAILOUT;
  441. }
  442. // try take out the country ID
  443. LangIdUsed = MAKELANGID (LangIdUsed & 0x0ff, LANG_NEUTRAL);
  444. TSPRINTF (subLangId, TEXT("%03x"), LangIdUsed);
  445. lstrcpy (lpValueNameString, NamesKey);
  446. lstrcat (lpValueNameString, Slash);
  447. lstrcat (lpValueNameString, subLangId);
  448. lWin32Status = RegOpenKeyEx (
  449. hKeyRegistry,
  450. lpValueNameString,
  451. RESERVED,
  452. KEY_READ,
  453. &hKeyNames);
  454. }
  455. if (lWin32Status != ERROR_SUCCESS) {
  456. // try the EnglishLangId
  457. if (!strsame(EnglishLangId, subLangId)) {
  458. lstrcpy (lpValueNameString, NamesKey);
  459. lstrcat (lpValueNameString, Slash);
  460. lstrcat (lpValueNameString, EnglishLangId);
  461. LangIdUsed = iEnglishLanguage ;
  462. lWin32Status = RegOpenKeyEx (
  463. hKeyRegistry,
  464. lpValueNameString,
  465. RESERVED,
  466. KEY_READ,
  467. &hKeyNames);
  468. }
  469. }
  470. // Fail, too bad...
  471. if (lWin32Status != ERROR_SUCCESS) {
  472. goto BNT_BAILOUT;
  473. }
  474. // get size of counter names and add that to the arrays
  475. dwBufferSize = 0;
  476. lWin32Status = RegQueryValueEx (
  477. hKeyNames,
  478. Counters,
  479. RESERVED,
  480. &dwValueType,
  481. NULL,
  482. &dwBufferSize);
  483. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  484. dwCounterSize = dwBufferSize;
  485. // If ExplainText is needed, then
  486. // get size of help text and add that to the arrays
  487. if (bExplainTextButtonHit) {
  488. dwBufferSize = 0;
  489. lWin32Status = RegQueryValueEx (
  490. hKeyNames,
  491. Help,
  492. RESERVED,
  493. &dwValueType,
  494. NULL,
  495. &dwBufferSize);
  496. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  497. dwHelpSize = dwBufferSize;
  498. } else {
  499. dwHelpSize = 0;
  500. }
  501. lpReturnValue = AddNewName(
  502. hKeyNames,
  503. pCounterInfo,
  504. Counters,
  505. Help,
  506. dwLastId,
  507. dwCounterSize,
  508. dwHelpSize,
  509. LangIdUsed);
  510. RegCloseKey (hKeyNames);
  511. return lpReturnValue;
  512. BNT_BAILOUT:
  513. if (lWin32Status != ERROR_SUCCESS) {
  514. dwLastError = GetLastError();
  515. // set the LastError value since a null pointer will
  516. // be returned which doesn't tell much to the caller
  517. SetLastError (lWin32Status);
  518. }
  519. if (lpReturnValue) {
  520. MemoryFree ((LPVOID)lpReturnValue);
  521. }
  522. if (hKeyNames) RegCloseKey (hKeyNames);
  523. return NULL;
  524. }
  525. LPWSTR
  526. *BuildNameTable(
  527. PPERFSYSTEM pSysInfo,
  528. HKEY hKeyRegistry, // handle to registry db with counter names
  529. LPWSTR lpszLangId, // unicode value of Language subkey
  530. PCOUNTERTEXT pCounterInfo,
  531. LANGID iLangId // lang ID of the lpszLangId
  532. )
  533. /*++
  534. BuildNameTable
  535. Arguments:
  536. hKeyRegistry
  537. Handle to an open registry (this can be local or remote.) and
  538. is the value returned by RegConnectRegistry or a default key.
  539. lpszLangId
  540. The unicode id of the language to look up. (English is 0x409)
  541. Return Value:
  542. pointer to an allocated table. (the caller must free it when finished!)
  543. the table is an array of pointers to zero terminated strings. NULL is
  544. returned if an error occured.
  545. --*/
  546. {
  547. LPWSTR *lpReturnValue;
  548. LONG lWin32Status;
  549. DWORD dwLastError;
  550. DWORD dwValueType;
  551. DWORD dwLastHelp;
  552. DWORD dwLastCounter;
  553. DWORD dwLastId;
  554. DWORD dwBufferSize;
  555. HKEY hKeyValue;
  556. DWORD dwSystemVersion;
  557. //initialize local variables
  558. lpReturnValue = NULL;
  559. hKeyValue = NULL;
  560. // open registry to get number of items for computing array size
  561. lWin32Status = RegOpenKeyEx (
  562. hKeyRegistry,
  563. NamesKey,
  564. RESERVED,
  565. KEY_READ,
  566. &hKeyValue);
  567. if (lWin32Status != ERROR_SUCCESS) {
  568. goto BNT_BAILOUT;
  569. }
  570. // get number of items
  571. dwBufferSize = sizeof (dwLastHelp);
  572. lWin32Status = RegQueryValueEx (
  573. hKeyValue,
  574. LastHelp,
  575. RESERVED,
  576. &dwValueType,
  577. (LPBYTE)&dwLastHelp,
  578. &dwBufferSize);
  579. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  580. goto BNT_BAILOUT;
  581. }
  582. dwBufferSize = sizeof (dwLastCounter);
  583. lWin32Status = RegQueryValueEx (
  584. hKeyValue,
  585. LastCounter,
  586. RESERVED,
  587. &dwValueType,
  588. (LPBYTE)&dwLastCounter,
  589. &dwBufferSize);
  590. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  591. goto BNT_BAILOUT;
  592. }
  593. if (dwLastCounter >= dwLastHelp) {
  594. dwLastId = dwLastCounter;
  595. } else {
  596. dwLastId = dwLastHelp;
  597. }
  598. // get system version
  599. dwBufferSize = sizeof (dwSystemVersion);
  600. lWin32Status = RegQueryValueEx (
  601. hKeyValue,
  602. SysVersion,
  603. RESERVED,
  604. &dwValueType,
  605. (LPBYTE)&dwSystemVersion,
  606. &dwBufferSize);
  607. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  608. pSysInfo->SysVersion = 0x10000;
  609. } else {
  610. pSysInfo->SysVersion = dwSystemVersion;
  611. }
  612. if (pSysInfo->SysVersion <= 0x10000) {
  613. lpReturnValue = BuildOldNameTable (
  614. hKeyRegistry,
  615. lpszLangId,
  616. pCounterInfo,
  617. iLangId,
  618. dwLastId) ;
  619. } else {
  620. lpReturnValue = BuildNewNameTable (
  621. pSysInfo,
  622. lpszLangId,
  623. pCounterInfo,
  624. iLangId,
  625. dwLastId) ;
  626. }
  627. RegCloseKey (hKeyValue);
  628. return lpReturnValue;
  629. BNT_BAILOUT:
  630. if (lWin32Status != ERROR_SUCCESS) {
  631. dwLastError = GetLastError();
  632. // set the LastError value since a null pointer will
  633. // be returned which doesn't tell much to the caller
  634. SetLastError (lWin32Status);
  635. }
  636. if (hKeyValue) RegCloseKey (hKeyValue);
  637. return NULL;
  638. }
  639. DWORD
  640. GetSystemKey (
  641. PPERFSYSTEM pSysInfo,
  642. HKEY *phKeyMachine
  643. )
  644. {
  645. DWORD dwStatus;
  646. *phKeyMachine = HKEY_LOCAL_MACHINE;
  647. // connect to system registry
  648. if (IsLocalComputer(pSysInfo->sysName)) {
  649. *phKeyMachine = HKEY_LOCAL_MACHINE;
  650. } else if (lstrlen(pSysInfo->sysName) < MAX_COMPUTERNAME_LENGTH+3) {
  651. try {
  652. dwStatus = RegConnectRegistry (
  653. pSysInfo->sysName,
  654. HKEY_LOCAL_MACHINE,
  655. phKeyMachine);
  656. if (dwStatus != ERROR_SUCCESS) {
  657. // return dwStatus;
  658. // comnputer name not found, use the local system's registry
  659. *phKeyMachine = HKEY_LOCAL_MACHINE;
  660. return 0;
  661. }
  662. }finally {
  663. ; // nothing
  664. }
  665. }
  666. return 0;
  667. }
  668. DWORD
  669. GetSystemNames(
  670. PPERFSYSTEM pSysInfo
  671. )
  672. {
  673. HKEY hKeyMachine = 0;
  674. DWORD dwStatus;
  675. if (dwStatus = GetSystemKey (pSysInfo, &hKeyMachine)) {
  676. return dwStatus;
  677. }
  678. // if here, then hKeyMachine is an open key to the system's
  679. // HKEY_LOCAL_MACHINE registry database
  680. // only one language is supported by this approach.
  681. // multiple language support would:
  682. // 1. enumerate language keys
  683. // and for each key:
  684. // 2. allocate memory for structures
  685. // 3. call BuildNameTable for each lang key.
  686. pSysInfo->CounterInfo.pNextTable = NULL;
  687. pSysInfo->CounterInfo.dwLangId = iLanguage ; // default Lang ID
  688. pSysInfo->CounterInfo.TextString = BuildNameTable (
  689. pSysInfo,
  690. hKeyMachine,
  691. NULL, // use default
  692. &pSysInfo->CounterInfo,
  693. 0);
  694. if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) {
  695. RegCloseKey (hKeyMachine) ;
  696. }
  697. if (pSysInfo->CounterInfo.TextString == NULL) {
  698. return GetLastError();
  699. } else {
  700. return ERROR_SUCCESS;
  701. }
  702. }
  703. BOOL
  704. GetHelpText(
  705. PPERFSYSTEM pSysInfo
  706. )
  707. {
  708. LPWSTR *lpCounterId;
  709. LPWSTR lpHelpText;
  710. LONG lWin32Status;
  711. DWORD dwValueType;
  712. DWORD dwArraySize;
  713. DWORD dwBufferSize;
  714. DWORD dwCounterSize;
  715. DWORD dwHelpSize;
  716. NTSTATUS Status;
  717. DWORD dwLastId;
  718. TCHAR Slash[2];
  719. HKEY hKeyNames;
  720. TCHAR SysLangId [ShortTextLen] ;
  721. TCHAR ValueNameString [MiscTextLen] ;
  722. HKEY hKeyMachine = 0;
  723. DWORD dwStatus;
  724. SetHourglassCursor() ;
  725. //initialize local variables
  726. lpHelpText = NULL;
  727. hKeyNames = hKeyMachine = NULL;
  728. Slash[0] = L'\\';
  729. Slash[1] = L'\0';
  730. dwBufferSize = 0;
  731. TSPRINTF (SysLangId, TEXT("%03x"), pSysInfo->CounterInfo.dwLangId) ;
  732. if (pSysInfo->SysVersion <= 0x10000) {
  733. // old version, get help from registry
  734. if (dwStatus = GetSystemKey (pSysInfo, &hKeyMachine)) {
  735. goto ERROR_EXIT;
  736. }
  737. lstrcpy (ValueNameString, NamesKey);
  738. lstrcat (ValueNameString, Slash);
  739. lstrcat (ValueNameString, SysLangId);
  740. lWin32Status = RegOpenKeyEx (
  741. hKeyMachine,
  742. ValueNameString,
  743. RESERVED,
  744. KEY_READ,
  745. &hKeyNames);
  746. if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT;
  747. } else {
  748. // new system version, get it from the HKEY_PERFORMANCE
  749. hKeyNames = pSysInfo->sysDataKey;
  750. lstrcpy (ValueNameString, ExplainNameStr);
  751. lstrcat (ValueNameString, SysLangId);
  752. }
  753. dwHelpSize = 0;
  754. lWin32Status = RegQueryValueEx (
  755. hKeyNames,
  756. pSysInfo->SysVersion <= 0x010000 ? Help : ValueNameString,
  757. RESERVED,
  758. &dwValueType,
  759. NULL,
  760. &dwHelpSize);
  761. if (lWin32Status != ERROR_SUCCESS || dwHelpSize == 0) goto ERROR_EXIT;
  762. dwLastId = pSysInfo->CounterInfo.dwLastId;
  763. dwArraySize = (dwLastId + 1) * sizeof (LPWSTR);
  764. dwCounterSize = pSysInfo->CounterInfo.dwCounterSize;
  765. // allocate another memory to get the help text
  766. lpHelpText = MemoryAllocate (dwHelpSize);
  767. if (!lpHelpText) goto ERROR_EXIT;
  768. dwBufferSize = dwHelpSize;
  769. lWin32Status = RegQueryValueEx (
  770. hKeyNames,
  771. pSysInfo->SysVersion <= 0x010000 ? Help : ValueNameString,
  772. RESERVED,
  773. &dwValueType,
  774. (LPVOID)lpHelpText,
  775. &dwBufferSize);
  776. if (lWin32Status != ERROR_SUCCESS) goto ERROR_EXIT;
  777. // setup the help text pointers
  778. lpCounterId = pSysInfo->CounterInfo.TextString;
  779. Status = AddNamesToArray (lpHelpText, dwLastId, lpCounterId) ;
  780. if (Status != ERROR_SUCCESS) goto ERROR_EXIT;
  781. pSysInfo->CounterInfo.dwHelpSize = dwHelpSize;
  782. if (pSysInfo->SysVersion <= 0x010000)
  783. RegCloseKey (hKeyNames);
  784. if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) {
  785. RegCloseKey (hKeyMachine) ;
  786. }
  787. pSysInfo->CounterInfo.HelpTextString = lpHelpText;
  788. SetArrowCursor() ;
  789. return TRUE;
  790. ERROR_EXIT:
  791. SetArrowCursor() ;
  792. if (lpHelpText) {
  793. MemoryFree ((LPVOID)lpHelpText);
  794. }
  795. if (hKeyNames) {
  796. RegCloseKey (hKeyNames);
  797. }
  798. if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) {
  799. RegCloseKey (hKeyMachine) ;
  800. }
  801. return FALSE;
  802. }
  803. //
  804. // QueryPerformanceName - Get a title, given an index
  805. //
  806. // Inputs:
  807. //
  808. // pSysInfo - Pointer to sysinfo struct for the
  809. // system in question
  810. //
  811. // dwTitleIndex - Index of Title entry
  812. //
  813. // LangID - language in which title should be displayed
  814. //
  815. // cbTitle - # of char in the lpTitle buffer
  816. //
  817. // lpTitle - pointer to a buffer to receive the
  818. // Title
  819. //
  820. // Help - TRUE is help is desired, else counter or
  821. // object is assumed
  822. DWORD
  823. QueryPerformanceName(
  824. PPERFSYSTEM pSysInfo,
  825. DWORD dwTitleIndex,
  826. LANGID LangID,
  827. DWORD cbTitle,
  828. LPTSTR lpTitle,
  829. BOOL Help
  830. )
  831. {
  832. LPWSTR lpTitleFound;
  833. NTSTATUS Status;
  834. BOOL bGetTextSuccess = TRUE ;
  835. DBG_UNREFERENCED_PARAMETER(LangID);
  836. if (Help && pSysInfo->CounterInfo.dwHelpSize == 0) {
  837. // we have not get the help text yet, go get it
  838. bGetTextSuccess = GetHelpText (pSysInfo);
  839. }
  840. if (!bGetTextSuccess) {
  841. Status = ERROR_INVALID_NAME;
  842. goto ErrorExit;
  843. }
  844. if ((dwTitleIndex > 0) && (dwTitleIndex <= pSysInfo->CounterInfo.dwLastId)) {
  845. // then title should be found in the array
  846. lpTitleFound = pSysInfo->CounterInfo.TextString[dwTitleIndex];
  847. if (!lpTitleFound) {
  848. // no entry for this index
  849. Status = ERROR_INVALID_NAME;
  850. } else if ((DWORD)lstrlen(lpTitleFound) < cbTitle) {
  851. lstrcpy (lpTitle, lpTitleFound);
  852. return (ERROR_SUCCESS);
  853. } else {
  854. Status = ERROR_MORE_DATA;
  855. }
  856. } else {
  857. Status = ERROR_INVALID_NAME;
  858. }
  859. ErrorExit:
  860. // if here, then an error occured, so return a blank
  861. if ((DWORD)lstrlen (NULL_NAME) < cbTitle) {
  862. lstrcpy (lpTitle, NULL_NAME);
  863. }
  864. return Status; // title not returned
  865. }
  866. LONG
  867. GetSystemPerfData (
  868. IN HKEY hKeySystem,
  869. IN LPTSTR lpszValue,
  870. OUT PPERFDATA pPerfData,
  871. OUT SIZE_T * pdwPerfDataLen
  872. )
  873. { // GetSystemPerfData
  874. LONG lError ;
  875. DWORD Type ;
  876. // have to pass in a Type to RegQueryValueEx(W) or else it
  877. // will crash
  878. lError = RegQueryValueEx (hKeySystem, lpszValue, NULL, &Type,
  879. (LPSTR) pPerfData, (DWORD *)pdwPerfDataLen) ;
  880. return (lError) ;
  881. } // GetSystemPerfData
  882. BOOL
  883. CloseSystemPerfData (
  884. HKEY hKeySystem
  885. )
  886. { // CloseSystemPerfData
  887. return (TRUE) ;
  888. } // CloseSystemPerfData
  889. int
  890. CBLoadObjects (
  891. HWND hWndCB,
  892. PPERFDATA pPerfData,
  893. PPERFSYSTEM pSysInfo,
  894. DWORD dwDetailLevel,
  895. LPTSTR lpszDefaultObject,
  896. BOOL bIncludeAll
  897. )
  898. /*
  899. Effect: Load into the combo box CB one item for each Object in
  900. pPerfData. For each item, look up the object's name in
  901. the registry strings associated with pSysInfo, and
  902. attach the object to the data field of the CB item.
  903. Dont add those objects that are more detailed than
  904. dwDetailLevel.
  905. Set the current selected CB item to the object named
  906. lpszDefaultObject, or to the default object specified in
  907. pPerfData if lpszDefaultObject is NULL.
  908. */
  909. { // CBLoadObjects
  910. UINT i ;
  911. INT_PTR iIndex ;
  912. PPERFOBJECT pObject ;
  913. TCHAR szObject [PerfObjectLen + 1] ;
  914. TCHAR szDefaultObject [PerfObjectLen + 1] ;
  915. CBReset (hWndCB) ;
  916. strclr (szDefaultObject) ;
  917. pObject = FirstObject (pPerfData) ;
  918. for (i = 0, pObject = FirstObject (pPerfData) ;
  919. i < pPerfData->NumObjectTypes ;
  920. i++, pObject = NextObject (pObject)) { // for
  921. if (pObject->DetailLevel <= dwDetailLevel) { // if
  922. strclr (szObject) ;
  923. QueryPerformanceName (pSysInfo, pObject->ObjectNameTitleIndex,
  924. 0, PerfObjectLen, szObject, FALSE) ;
  925. // if szObject not empty, add it to the Combo-box
  926. if (!strsame(szObject, NULL_NAME)) {
  927. iIndex = CBAdd (hWndCB, szObject) ;
  928. CBSetData (hWndCB, iIndex, (DWORD_PTR) pObject) ;
  929. if ((LONG)pObject->ObjectNameTitleIndex == pPerfData->DefaultObject)
  930. lstrcpy (szDefaultObject, szObject) ;
  931. } // if szObject not empty
  932. } // if
  933. } // for
  934. if (bIncludeAll) {
  935. StringLoad (IDS_ALLOBJECTS, szObject) ;
  936. CBInsert (hWndCB, 0, szObject) ;
  937. // assume "ALL" is default unless overridden
  938. lstrcpy (szDefaultObject, szObject) ;
  939. }
  940. if (lpszDefaultObject)
  941. lstrcpy (szDefaultObject, lpszDefaultObject) ;
  942. iIndex = CBFind (hWndCB, szDefaultObject) ;
  943. CBSetSelection (hWndCB, (iIndex != CB_ERR) ? iIndex : 0) ;
  944. return (i) ;
  945. } // CBLoadObjects
  946. int
  947. LBLoadObjects (
  948. HWND hWndLB,
  949. PPERFDATA pPerfData,
  950. PPERFSYSTEM pSysInfo,
  951. DWORD dwDetailLevel,
  952. LPTSTR lpszDefaultObject,
  953. BOOL bIncludeAll
  954. )
  955. /*
  956. Effect: Load into the list box LB one item for each Object in
  957. pPerfData. For each item, look up the object's name in
  958. the registry strings associated with pSysInfo, and
  959. attach the object to the data field of the LB item.
  960. Dont add those objects that are more detailed than
  961. dwDetailLevel.
  962. Set the current selected LB item to the object named
  963. lpszDefaultObject, or to the default object specified in
  964. pPerfData if lpszDefaultObject is NULL.
  965. */
  966. { // LBLoadObjects
  967. UINT i ;
  968. INT_PTR iIndex ;
  969. PPERFOBJECT pObject ;
  970. TCHAR szObject [PerfObjectLen + 1] ;
  971. TCHAR szDefaultObject [PerfObjectLen + 1] ;
  972. LBReset (hWndLB) ;
  973. strclr (szDefaultObject) ;
  974. pObject = FirstObject (pPerfData) ;
  975. for (i = 0, pObject = FirstObject (pPerfData) ;
  976. i < pPerfData->NumObjectTypes ;
  977. i++, pObject = NextObject (pObject)) { // for
  978. if (pObject->DetailLevel <= dwDetailLevel) { // if
  979. strclr (szObject) ;
  980. QueryPerformanceName (pSysInfo, pObject->ObjectNameTitleIndex,
  981. 0, PerfObjectLen, szObject, FALSE) ;
  982. // if szObject is not empty, add it to the listbox
  983. if (!strsame(szObject, NULL_NAME)) {
  984. iIndex = LBAdd (hWndLB, szObject) ;
  985. LBSetData (hWndLB, iIndex, (DWORD_PTR) pObject) ;
  986. if ((LONG)pObject->ObjectNameTitleIndex == pPerfData->DefaultObject)
  987. lstrcpy (szDefaultObject, szObject) ;
  988. } // if szObject is not empty
  989. }
  990. } // for
  991. if (bIncludeAll) {
  992. StringLoad (IDS_ALLOBJECTS, szObject) ;
  993. LBInsert (hWndLB, 0, szObject) ;
  994. LBSetData (hWndLB, iIndex, 0) ;
  995. // assume "ALL" is default unless overridden
  996. lstrcpy (szDefaultObject, szObject) ;
  997. }
  998. if (lpszDefaultObject)
  999. lstrcpy (szDefaultObject, lpszDefaultObject) ;
  1000. iIndex = LBFind (hWndLB, szDefaultObject) ;
  1001. LBSetSelection (hWndLB, (iIndex != LB_ERR) ? iIndex : 0) ;
  1002. return (i) ;
  1003. } // LBLoadObjects
  1004. /***************************************************************************\
  1005. * GetObjectDef()
  1006. *
  1007. * Entry: pointer to data block and the number of the object type
  1008. * Exit: returns a pointer to the specified object type definition
  1009. *
  1010. \***************************************************************************/
  1011. PERF_OBJECT_TYPE *
  1012. GetObjectDef(
  1013. PERF_DATA_BLOCK *pDataBlock,
  1014. DWORD NumObjectType
  1015. )
  1016. {
  1017. DWORD NumTypeDef;
  1018. PERF_OBJECT_TYPE *pObjectDef;
  1019. pObjectDef = FirstObject(pDataBlock);
  1020. for ( NumTypeDef = 0;
  1021. NumTypeDef < pDataBlock->NumObjectTypes;
  1022. NumTypeDef++ ) {
  1023. if ( NumTypeDef == NumObjectType ) {
  1024. return pObjectDef;
  1025. }
  1026. pObjectDef = NextObject(pObjectDef);
  1027. }
  1028. return 0;
  1029. }
  1030. /***************************************************************************\
  1031. * GetObjectDefByTitleIndex()
  1032. *
  1033. * Entry: pointer to data block and the title index of the object type
  1034. * Exit: returns a pointer to the specified object type definition
  1035. *
  1036. \***************************************************************************/
  1037. PERF_OBJECT_TYPE *
  1038. GetObjectDefByTitleIndex(
  1039. PERF_DATA_BLOCK *pDataBlock,
  1040. DWORD ObjectTypeTitleIndex
  1041. )
  1042. {
  1043. DWORD NumTypeDef;
  1044. PERF_OBJECT_TYPE *pObjectDef;
  1045. pObjectDef = FirstObject(pDataBlock);
  1046. for ( NumTypeDef = 0;
  1047. NumTypeDef < pDataBlock->NumObjectTypes;
  1048. NumTypeDef++ ) {
  1049. if ( pObjectDef->ObjectNameTitleIndex == ObjectTypeTitleIndex ) {
  1050. return pObjectDef;
  1051. }
  1052. pObjectDef = NextObject(pObjectDef);
  1053. }
  1054. return 0;
  1055. }
  1056. /***************************************************************************\
  1057. * GetObjectDefByName()
  1058. *
  1059. * Entry: pointer to data block and the name of the object type
  1060. * Exit: returns a pointer to the specified object type definition
  1061. *
  1062. \***************************************************************************/
  1063. PERF_OBJECT_TYPE *
  1064. GetObjectDefByName(
  1065. PPERFSYSTEM pSystem,
  1066. PERF_DATA_BLOCK *pDataBlock,
  1067. LPTSTR pObjectName
  1068. )
  1069. {
  1070. DWORD NumTypeDef;
  1071. TCHAR szObjectName [PerfObjectLen + 1] ;
  1072. PERF_OBJECT_TYPE *pObjectDef;
  1073. pObjectDef = FirstObject(pDataBlock);
  1074. for ( NumTypeDef = 0;
  1075. NumTypeDef < pDataBlock->NumObjectTypes;
  1076. NumTypeDef++ ) {
  1077. ObjectName (pSystem, pObjectDef, szObjectName, PerfObjectLen) ;
  1078. if (strsame (szObjectName, pObjectName) ) {
  1079. return pObjectDef;
  1080. }
  1081. pObjectDef = NextObject(pObjectDef);
  1082. }
  1083. return 0;
  1084. }
  1085. /***************************************************************************\
  1086. * GetCounterDef()
  1087. *
  1088. * Entry: pointer to object type definition the number of the Counter
  1089. * definition
  1090. * Exit: returns a pointer to the specified Counter definition
  1091. *
  1092. \***************************************************************************/
  1093. PERF_COUNTER_DEFINITION *
  1094. GetCounterDef(
  1095. PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
  1096. DWORD NumCounter
  1097. )
  1098. {
  1099. DWORD NumCtrDef;
  1100. PERF_COUNTER_DEFINITION *pCounterDef;
  1101. pCounterDef = FirstCounter(pObjectDef);
  1102. for ( NumCtrDef = 0;
  1103. NumCtrDef < pObjectDef->NumCounters;
  1104. NumCtrDef++ ) {
  1105. if ( NumCtrDef == NumCounter ) {
  1106. return pCounterDef;
  1107. }
  1108. pCounterDef = NextCounter(pCounterDef);
  1109. }
  1110. return 0;
  1111. }
  1112. /***************************************************************************\
  1113. * GetCounterNumByTitleIndex()
  1114. *
  1115. * Entry: pointer to object type definition and the title index of
  1116. * the name of the Counter definition
  1117. * Exit: returns the number of the specified Counter definition
  1118. *
  1119. \***************************************************************************/
  1120. LONG
  1121. GetCounterNumByTitleIndex(
  1122. PERF_OBJECT_TYPE *pObjectDef,
  1123. DWORD CounterTitleIndex
  1124. )
  1125. {
  1126. DWORD NumCtrDef;
  1127. PERF_COUNTER_DEFINITION *pCounterDef;
  1128. pCounterDef = FirstCounter(pObjectDef);
  1129. for ( NumCtrDef = 0;
  1130. NumCtrDef < pObjectDef->NumCounters;
  1131. NumCtrDef++ ) {
  1132. if ( pCounterDef->CounterNameTitleIndex == CounterTitleIndex ) {
  1133. return NumCtrDef;
  1134. }
  1135. pCounterDef = NextCounter(pCounterDef);
  1136. }
  1137. return 0;
  1138. }
  1139. /***************************************************************************\
  1140. * GetCounterData()
  1141. *
  1142. * Entry: pointer to object definition and number of counter, must be
  1143. * an object with no instances
  1144. * Exit: returns a pointer to the data
  1145. *
  1146. \***************************************************************************/
  1147. PVOID
  1148. GetCounterData(
  1149. PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
  1150. PERF_COUNTER_DEFINITION *pCounterDef
  1151. )
  1152. {
  1153. PERF_COUNTER_BLOCK *pCtrBlock;
  1154. pCtrBlock = (PERF_COUNTER_BLOCK *)((PCHAR)pObjectDef +
  1155. pObjectDef->DefinitionLength);
  1156. return (PVOID)((PCHAR)pCtrBlock + pCounterDef->CounterOffset);
  1157. }
  1158. /***************************************************************************\
  1159. * GetInstanceCounterData()
  1160. *
  1161. * Entry: pointer to object definition and number of counter, and a pointer
  1162. * to the instance for which the data is to be retrieved
  1163. * Exit: returns a pointer to the data
  1164. *
  1165. \***************************************************************************/
  1166. PVOID
  1167. GetInstanceCounterData(
  1168. PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
  1169. PERF_INSTANCE_DEFINITION *pInstanceDef,
  1170. PERF_COUNTER_DEFINITION *pCounterDef
  1171. )
  1172. {
  1173. PERF_COUNTER_BLOCK *pCtrBlock;
  1174. pCtrBlock = (PERF_COUNTER_BLOCK *)((PCHAR)pInstanceDef +
  1175. pInstanceDef->ByteLength);
  1176. return (PVOID)((PCHAR)pCtrBlock + pCounterDef->CounterOffset);
  1177. }
  1178. /***************************************************************************\
  1179. * GetNextInstance()
  1180. *
  1181. * Entry: pointer to instance definition
  1182. * Exit: returns a pointer to the next instance definition. If none,
  1183. * points to byte past this instance
  1184. *
  1185. \***************************************************************************/
  1186. PERF_INSTANCE_DEFINITION *
  1187. GetNextInstance(
  1188. PERF_INSTANCE_DEFINITION *pInstDef
  1189. )
  1190. {
  1191. PERF_COUNTER_BLOCK *pCtrBlock;
  1192. pCtrBlock = (PERF_COUNTER_BLOCK *)
  1193. ((PCHAR) pInstDef + pInstDef->ByteLength);
  1194. return (PERF_INSTANCE_DEFINITION *)
  1195. ((PCHAR) pCtrBlock + pCtrBlock->ByteLength);
  1196. }
  1197. /***************************************************************************\
  1198. * GetInstance()
  1199. *
  1200. * Entry: pointer to object type definition, the name of the instance,
  1201. * the name of the parent object type, and the parent instance index.
  1202. * The name of the parent object type is NULL if no parent.
  1203. * Exit: returns a pointer to the specified instance definition
  1204. *
  1205. \***************************************************************************/
  1206. PERF_INSTANCE_DEFINITION *
  1207. GetInstance(
  1208. PERF_OBJECT_TYPE *pObjectDef,
  1209. LONG InstanceNumber
  1210. )
  1211. {
  1212. PERF_INSTANCE_DEFINITION *pInstanceDef;
  1213. LONG NumInstance;
  1214. if (!pObjectDef) {
  1215. return 0;
  1216. }
  1217. pInstanceDef = FirstInstance(pObjectDef);
  1218. for ( NumInstance = 0;
  1219. NumInstance < pObjectDef->NumInstances;
  1220. NumInstance++ ) {
  1221. if ( InstanceNumber == NumInstance ) {
  1222. return pInstanceDef;
  1223. }
  1224. pInstanceDef = GetNextInstance(pInstanceDef);
  1225. }
  1226. return 0;
  1227. }
  1228. /***************************************************************************\
  1229. * GetInstanceByUniqueID()
  1230. *
  1231. * Entry: pointer to object type definition, and
  1232. * the unique ID of the instance.
  1233. * Exit: returns a pointer to the specified instance definition
  1234. *
  1235. \***************************************************************************/
  1236. PERF_INSTANCE_DEFINITION *
  1237. GetInstanceByUniqueID(
  1238. PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
  1239. LONG UniqueID,
  1240. DWORD dwIndex
  1241. )
  1242. {
  1243. PERF_INSTANCE_DEFINITION *pInstanceDef;
  1244. DWORD dwLocalIndex;
  1245. LONG NumInstance;
  1246. pInstanceDef = FirstInstance(pObjectDef);
  1247. dwLocalIndex = dwIndex;
  1248. for ( NumInstance = 0;
  1249. NumInstance < pObjectDef->NumInstances;
  1250. NumInstance++ ) {
  1251. if ( pInstanceDef->UniqueID == UniqueID ) {
  1252. if (dwLocalIndex == 0) {
  1253. return pInstanceDef;
  1254. } else {
  1255. --dwLocalIndex;
  1256. }
  1257. }
  1258. pInstanceDef = GetNextInstance(pInstanceDef);
  1259. }
  1260. return 0;
  1261. }
  1262. /***************************************************************************\
  1263. * GetInstanceByNameUsingParentTitleIndex()
  1264. *
  1265. * Entry: pointer to object type definition, the name of the instance,
  1266. * and the name of the parent instance.
  1267. * The name of the parent instance is NULL if no parent.
  1268. * Exit: returns a pointer to the specified instance definition
  1269. *
  1270. \***************************************************************************/
  1271. PERF_INSTANCE_DEFINITION *
  1272. GetInstanceByNameUsingParentTitleIndex(
  1273. PERF_DATA_BLOCK *pDataBlock,
  1274. PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
  1275. LPTSTR pInstanceName,
  1276. LPTSTR pParentName,
  1277. DWORD dwIndex
  1278. )
  1279. {
  1280. BOOL fHaveParent;
  1281. PERF_OBJECT_TYPE *pParentObj;
  1282. PERF_INSTANCE_DEFINITION *pParentInst,
  1283. *pInstanceDef;
  1284. LONG NumInstance;
  1285. TCHAR InstanceName[256];
  1286. DWORD dwLocalIndex;
  1287. fHaveParent = FALSE;
  1288. pInstanceDef = FirstInstance(pObjectDef);
  1289. dwLocalIndex = dwIndex;
  1290. for ( NumInstance = 0;
  1291. NumInstance < pObjectDef->NumInstances;
  1292. NumInstance++ ) {
  1293. GetInstanceNameStr(pInstanceDef,InstanceName);
  1294. if ( lstrcmpi(InstanceName, pInstanceName) == 0 ) {
  1295. // Instance name matches
  1296. if ( pParentName == NULL ) {
  1297. // No parent, we're done if this is the right "copy"
  1298. if (dwLocalIndex == 0) {
  1299. return pInstanceDef;
  1300. } else {
  1301. --dwLocalIndex;
  1302. }
  1303. } else {
  1304. // Must match parent as well
  1305. pParentObj = GetObjectDefByTitleIndex(
  1306. pDataBlock,
  1307. pInstanceDef->ParentObjectTitleIndex);
  1308. if (!pParentObj) {
  1309. // can't locate the parent, forget it
  1310. break ;
  1311. }
  1312. // Object type of parent found; now find parent
  1313. // instance
  1314. pParentInst = GetInstance(pParentObj,
  1315. pInstanceDef->ParentObjectInstance);
  1316. if (!pParentInst) {
  1317. // can't locate the parent instance, forget it
  1318. break ;
  1319. }
  1320. GetInstanceNameStr(pParentInst,InstanceName);
  1321. if ( lstrcmpi(InstanceName, pParentName) == 0 ) {
  1322. // Parent Instance Name matches that passed in
  1323. if (dwLocalIndex == 0) {
  1324. return pInstanceDef;
  1325. } else {
  1326. --dwLocalIndex;
  1327. }
  1328. }
  1329. }
  1330. }
  1331. pInstanceDef = GetNextInstance(pInstanceDef);
  1332. }
  1333. return 0;
  1334. }
  1335. /***************************************************************************\
  1336. * GetInstanceByName()
  1337. *
  1338. * Entry: pointer to object type definition, the name of the instance,
  1339. * and the name of the parent instance.
  1340. * The name of the parent instance is NULL if no parent.
  1341. * Exit: returns a pointer to the specified instance definition
  1342. *
  1343. \***************************************************************************/
  1344. PERF_INSTANCE_DEFINITION *
  1345. GetInstanceByName(
  1346. PERF_DATA_BLOCK *pDataBlock,
  1347. PERF_OBJECT_TYPE UNALIGNED *pObjectDef,
  1348. LPTSTR pInstanceName,
  1349. LPTSTR pParentName,
  1350. DWORD dwIndex
  1351. )
  1352. {
  1353. BOOL fHaveParent;
  1354. PERF_OBJECT_TYPE *pParentObj;
  1355. PERF_INSTANCE_DEFINITION *pParentInst,
  1356. *pInstanceDef;
  1357. LONG NumInstance;
  1358. TCHAR InstanceName[256];
  1359. DWORD dwLocalIndex;
  1360. fHaveParent = FALSE;
  1361. pInstanceDef = FirstInstance(pObjectDef);
  1362. dwLocalIndex = dwIndex;
  1363. for ( NumInstance = 0;
  1364. NumInstance < pObjectDef->NumInstances;
  1365. NumInstance++ ) {
  1366. GetInstanceNameStr(pInstanceDef,InstanceName);
  1367. if ( lstrcmpi(InstanceName, pInstanceName) == 0 ) {
  1368. // Instance name matches
  1369. if ( !pInstanceDef->ParentObjectTitleIndex ) {
  1370. // No parent, we're done
  1371. if (dwLocalIndex == 0) {
  1372. return pInstanceDef;
  1373. } else {
  1374. --dwLocalIndex;
  1375. }
  1376. } else {
  1377. // Must match parent as well
  1378. pParentObj = GetObjectDefByTitleIndex(
  1379. pDataBlock,
  1380. pInstanceDef->ParentObjectTitleIndex);
  1381. // Object type of parent found; now find parent
  1382. // instance
  1383. if (pParentObj == NULL)
  1384. break;
  1385. pParentInst = GetInstance(pParentObj,
  1386. pInstanceDef->ParentObjectInstance);
  1387. if (pParentInst == NULL)
  1388. break;
  1389. GetInstanceNameStr(pParentInst,InstanceName);
  1390. if ( lstrcmpi(InstanceName, pParentName) == 0 ) {
  1391. // Parent Instance Name matches that passed in
  1392. if (dwLocalIndex == 0) {
  1393. return pInstanceDef;
  1394. } else {
  1395. --dwLocalIndex;
  1396. }
  1397. }
  1398. }
  1399. }
  1400. pInstanceDef = GetNextInstance(pInstanceDef);
  1401. }
  1402. return 0;
  1403. } // GetInstanceByName
  1404. BOOL
  1405. FailedLineData (
  1406. PPERFDATA pPerfData,
  1407. PLINE pLine
  1408. )
  1409. /*
  1410. This routine handles the case where there is no data for a
  1411. system.
  1412. */
  1413. { // FailedLineData
  1414. LARGE_INTEGER liDummy ;
  1415. // System no longer exists.
  1416. liDummy.LowPart = liDummy.HighPart = 0;
  1417. if (pLine->lnCounterType == PERF_COUNTER_TIMER_INV) {
  1418. // Timer inverse with Performance Counter as timer
  1419. pLine->lnaOldCounterValue[0] = pLine->lnOldTime ;
  1420. pLine->lnaCounterValue[0] = pLine->lnNewTime ;
  1421. } else if (pLine->lnCounterType == PERF_100NSEC_TIMER_INV ||
  1422. pLine->lnCounterType == PERF_100NSEC_MULTI_TIMER_INV) {
  1423. // Timer inverse with System Time as timer
  1424. pLine->lnaOldCounterValue[0] = pLine->lnOldTime100Ns ;
  1425. pLine->lnaCounterValue[0] = pLine->lnNewTime100Ns ;
  1426. } else {
  1427. // Normal timer
  1428. pLine->lnaOldCounterValue[0] =
  1429. pLine->lnaCounterValue[0] =
  1430. pLine->lnaOldCounterValue[1] =
  1431. pLine->lnaCounterValue[1] = liDummy ;
  1432. }
  1433. return TRUE ;
  1434. } // FailedLineData
  1435. BOOL
  1436. UpdateLineData (
  1437. PPERFDATA pPerfData,
  1438. PLINE pLine,
  1439. PPERFSYSTEM pSystem
  1440. )
  1441. /*
  1442. Assert: pPerfData holds the performance data for the same
  1443. system as pLine.
  1444. */
  1445. { // UpdateLineData
  1446. PERF_OBJECT_TYPE UNALIGNED *pObject ;
  1447. PPERFINSTANCEDEF pInstanceDef ;
  1448. PPERFCOUNTERDEF pCounterDef ;
  1449. PPERFCOUNTERDEF pCounterDef2 ;
  1450. PDWORD pCounterValue ;
  1451. PDWORD pCounterValue2 ;
  1452. UINT iCounterIndex ;
  1453. LARGE_INTEGER liDummy[2] ;
  1454. // Use Object time units if available, otherwise use system
  1455. // performance timer
  1456. pLine->lnOldTime = pLine->lnNewTime;
  1457. pLine->lnOldTime100Ns = pLine->lnNewTime100Ns;
  1458. pLine->lnNewTime100Ns = pPerfData->PerfTime100nSec;
  1459. pLine->lnPerfFreq = pPerfData->PerfFreq ;
  1460. pObject = GetObjectDefByTitleIndex(
  1461. pPerfData,
  1462. pLine->lnObject.ObjectNameTitleIndex);
  1463. if (!pObject) {
  1464. // Object Type no longer exists. This is possible if we are
  1465. // looking at a log file which has not always collected all
  1466. // the same data, such as appending measurements of different
  1467. // object types.
  1468. pCounterValue =
  1469. pCounterValue2 = (PDWORD) liDummy;
  1470. liDummy[0].LowPart = liDummy[0].HighPart = 0;
  1471. pLine->lnNewTime = pPerfData->PerfTime;
  1472. if (pLine->lnCounterType == PERF_COUNTER_TIMER_INV) {
  1473. // Timer inverse with Performance Counter as timer
  1474. pLine->lnaOldCounterValue[0] = pLine->lnOldTime ;
  1475. pLine->lnaCounterValue[0] = pLine->lnNewTime ;
  1476. } else if (pLine->lnCounterType == PERF_100NSEC_TIMER_INV ||
  1477. pLine->lnCounterType == PERF_100NSEC_MULTI_TIMER_INV) {
  1478. // Timer inverse with System Time as timer
  1479. pLine->lnaOldCounterValue[0] = pLine->lnOldTime100Ns ;
  1480. pLine->lnaCounterValue[0] = pLine->lnNewTime100Ns ;
  1481. } else {
  1482. // Normal timer or counter
  1483. pLine->lnaOldCounterValue[0] =
  1484. pLine->lnaCounterValue[0] =
  1485. pLine->lnaOldCounterValue[1] =
  1486. pLine->lnaCounterValue[1] = liDummy[0] ;
  1487. }
  1488. return TRUE ;
  1489. } else {
  1490. pCounterDef = &pLine->lnCounterDef ;
  1491. // if (pObject->PerfFreq.QuadPart > 0 ) {
  1492. if (pCounterDef->CounterType & PERF_OBJECT_TIMER) {
  1493. pLine->lnNewTime = pObject->PerfTime;
  1494. } else {
  1495. pLine->lnNewTime = pPerfData->PerfTime;
  1496. }
  1497. iCounterIndex = CounterIndex (pCounterDef, pObject) ;
  1498. // Get second counter, only if we are not at
  1499. // the end of the counters; some computations
  1500. // require a second counter
  1501. if (iCounterIndex < pObject->NumCounters-1 && iCounterIndex != -1) {
  1502. pCounterDef2 = GetCounterDef(pObject, iCounterIndex+1);
  1503. } else {
  1504. pCounterDef2 = NULL;
  1505. }
  1506. if (pObject->NumInstances > 0) {
  1507. if ( pLine->lnUniqueID != PERF_NO_UNIQUE_ID ) {
  1508. pInstanceDef = GetInstanceByUniqueID(pObject,
  1509. pLine->lnUniqueID,
  1510. pLine->dwInstanceIndex);
  1511. } else {
  1512. pInstanceDef =
  1513. GetInstanceByNameUsingParentTitleIndex(
  1514. pPerfData,
  1515. pObject,
  1516. pLine->lnInstanceName,
  1517. pLine->lnPINName,
  1518. pLine->dwInstanceIndex);
  1519. }
  1520. if (pInstanceDef) {
  1521. pLine->lnInstanceDef = *pInstanceDef;
  1522. pCounterValue = GetInstanceCounterData(pObject,
  1523. pInstanceDef,
  1524. pCounterDef);
  1525. if ( pCounterDef2 ) {
  1526. pCounterValue2 = GetInstanceCounterData(pObject,
  1527. pInstanceDef,
  1528. pCounterDef2);
  1529. }
  1530. } else {
  1531. pCounterValue =
  1532. pCounterValue2 = (PDWORD) liDummy;
  1533. liDummy[0].LowPart = liDummy[0].HighPart = 0;
  1534. liDummy[1].LowPart = liDummy[1].HighPart = 0;
  1535. }
  1536. // Got everything...
  1537. } // instances exist, look at them for counter blocks
  1538. else {
  1539. pCounterValue = GetCounterData(pObject, pCounterDef);
  1540. if (pCounterDef2) {
  1541. pCounterValue2 = GetCounterData(pObject, pCounterDef2);
  1542. }
  1543. } // counter def search when no instances
  1544. }
  1545. pLine->lnaOldCounterValue[0] = pLine->lnaCounterValue[0] ;
  1546. if (pLine->lnCounterLength <= 4) {
  1547. // HighPart was initialize to 0
  1548. pLine->lnaCounterValue[0].LowPart = *pCounterValue;
  1549. } else {
  1550. pLine->lnaCounterValue[0] = *(LARGE_INTEGER UNALIGNED *) pCounterValue;
  1551. }
  1552. // Get second counter, only if we are not at
  1553. // the end of the counters; some computations
  1554. // require a second counter
  1555. if ( pCounterDef2 ) {
  1556. pLine->lnaOldCounterValue[1] =
  1557. pLine->lnaCounterValue[1] ;
  1558. if (pCounterDef2->CounterSize <= 4) {
  1559. // HighPart was initialize to 0
  1560. pLine->lnaCounterValue[1].LowPart = *pCounterValue2;
  1561. } else
  1562. pLine->lnaCounterValue[1] =
  1563. *((LARGE_INTEGER UNALIGNED *) pCounterValue2);
  1564. }
  1565. return (TRUE) ;
  1566. } // UpdateLineData
  1567. BOOL
  1568. UpdateSystemData (
  1569. PPERFSYSTEM pSystem,
  1570. PPERFDATA *ppPerfData
  1571. )
  1572. { // UpdateSystemData
  1573. #define PERF_SYSTEM_TIMEOUT (60L * 1000L)
  1574. long lError ;
  1575. DWORD Status ;
  1576. SIZE_T Size;
  1577. if (!ppPerfData)
  1578. return (FALSE) ;
  1579. while (TRUE) {
  1580. if (pSystem->FailureTime) {
  1581. if (GetTickCount() > pSystem->FailureTime + PERF_SYSTEM_TIMEOUT) {
  1582. // free any memory hanging off this system
  1583. SystemFree (pSystem, FALSE) ;
  1584. // get the registry info
  1585. pSystem->sysDataKey = OpenSystemPerfData(pSystem->sysName) ;
  1586. Status = !ERROR_SUCCESS ;
  1587. if (pSystem->sysDataKey) {
  1588. Status = GetSystemNames(pSystem);
  1589. }
  1590. if (Status != ERROR_SUCCESS) {
  1591. // something wrong in getting the registry info,
  1592. // remote system must be still down (??)
  1593. pSystem->FailureTime = GetTickCount();
  1594. // Free any memory that may have created
  1595. SystemFree (pSystem, FALSE) ;
  1596. return (FALSE) ;
  1597. }
  1598. // time to check again
  1599. pSystem->FailureTime = 0 ;
  1600. } else {
  1601. // not time to check again
  1602. return (FALSE) ;
  1603. }
  1604. }
  1605. if (pSystem->FailureTime == 0 ) {
  1606. Size = MemorySize (*ppPerfData);
  1607. lError = GetSystemPerfData (pSystem->sysDataKey,
  1608. pSystem->lpszValue,
  1609. *ppPerfData,
  1610. &Size) ;
  1611. if ((!lError) &&
  1612. (Size > 0) &&
  1613. (*ppPerfData)->Signature[0] == (WCHAR)'P' &&
  1614. (*ppPerfData)->Signature[1] == (WCHAR)'E' &&
  1615. (*ppPerfData)->Signature[2] == (WCHAR)'R' &&
  1616. (*ppPerfData)->Signature[3] == (WCHAR)'F' )
  1617. return (TRUE) ;
  1618. if (lError == ERROR_MORE_DATA) {
  1619. *ppPerfData = MemoryResize (*ppPerfData,
  1620. MemorySize (*ppPerfData) +
  1621. dwPerfDataIncrease) ;
  1622. if (!*ppPerfData) {
  1623. pSystem->FailureTime = GetTickCount();
  1624. return (FALSE) ;
  1625. }
  1626. } else {
  1627. pSystem->FailureTime = GetTickCount();
  1628. return (FALSE) ;
  1629. } // else
  1630. } // if
  1631. } // while
  1632. } // UpdateSystemData
  1633. BOOL
  1634. FailedLinesForSystem (
  1635. LPTSTR lpszSystem,
  1636. PPERFDATA pPerfData,
  1637. PLINE pLineFirst
  1638. )
  1639. { // FailedLinesForSystem
  1640. PLINE pLine ;
  1641. BOOL bMatchFound = FALSE ; // no line from this system
  1642. for (pLine = pLineFirst ;
  1643. pLine ;
  1644. pLine = pLine->pLineNext) { // for pLine
  1645. if (strsamei (lpszSystem, pLine->lnSystemName)) {
  1646. FailedLineData (pPerfData, pLine) ;
  1647. if (pLine->bFirstTime) {
  1648. pLine->bFirstTime-- ;
  1649. }
  1650. bMatchFound = TRUE ; // one or more lines from this system
  1651. }
  1652. } // for pLine
  1653. return (bMatchFound) ;
  1654. }
  1655. BOOL
  1656. UpdateLinesForSystem (
  1657. LPTSTR lpszSystem,
  1658. PPERFDATA pPerfData,
  1659. PLINE pLineFirst,
  1660. PPERFSYSTEM pSystem
  1661. )
  1662. { // UpdateLinesForSystem
  1663. PLINE pLine ;
  1664. BOOL bMatchFound = FALSE ; // no line from this system
  1665. for (pLine = pLineFirst ;
  1666. pLine ;
  1667. pLine = pLine->pLineNext) { // for pLine
  1668. if (strsamei (lpszSystem, pLine->lnSystemName)) {
  1669. UpdateLineData (pPerfData, pLine, pSystem) ;
  1670. if (pLine->bFirstTime) {
  1671. pLine->bFirstTime-- ;
  1672. }
  1673. bMatchFound = TRUE ; // one or more lines from this system
  1674. }
  1675. } // for pLine
  1676. return (bMatchFound) ;
  1677. }
  1678. BOOL
  1679. PerfDataInitializeInstance (void)
  1680. {
  1681. // pPerfData = MemoryAllocate (STARTING_SYSINFO_SIZE) ;
  1682. // return (pPerfData != NULL) ;
  1683. return (TRUE);
  1684. }
  1685. NTSTATUS
  1686. AddNamesToArray (
  1687. LPTSTR lpNames,
  1688. DWORD dwLastId,
  1689. LPWSTR *lpCounterId
  1690. )
  1691. {
  1692. LPWSTR lpThisName;
  1693. LPWSTR lpStopString;
  1694. DWORD dwThisCounter;
  1695. NTSTATUS Status = ERROR_SUCCESS;
  1696. for (lpThisName = lpNames;
  1697. *lpThisName;
  1698. lpThisName += (lstrlen(lpThisName)+1) ) {
  1699. // first string should be an integer (in decimal unicode digits)
  1700. dwThisCounter = wcstoul(lpThisName, &lpStopString, 10);
  1701. if ((dwThisCounter == 0) || (dwThisCounter == ULONG_MAX)) {
  1702. Status += 1;
  1703. goto ADD_BAILOUT; // bad entry
  1704. }
  1705. // point to corresponding counter name
  1706. lpThisName += (lstrlen(lpThisName)+1);
  1707. if (dwThisCounter <= dwLastId) {
  1708. // and load array element;
  1709. lpCounterId[dwThisCounter] = lpThisName;
  1710. }
  1711. }
  1712. ADD_BAILOUT:
  1713. return (Status) ;
  1714. }
  1715. // try the new way of getting data...
  1716. BOOL
  1717. UpdateLines (
  1718. PPPERFSYSTEM ppSystemFirst,
  1719. PLINE pLineFirst
  1720. )
  1721. {
  1722. PPERFSYSTEM pSystem ;
  1723. int iNoUseSystemDetected = 0 ;
  1724. int NumberOfSystems = 0 ;
  1725. DWORD WaitStatus ;
  1726. HANDLE *lpPacketHandles ;
  1727. // allocate the handle array for multiple wait
  1728. if (NumberOfHandles == 0) {
  1729. NumberOfHandles = MAXIMUM_WAIT_OBJECTS ;
  1730. lpHandles = (HANDLE *) MemoryAllocate (NumberOfHandles * sizeof (HANDLE)) ;
  1731. if (!lpHandles) {
  1732. // out of memory, can't go on
  1733. NumberOfHandles = 0 ;
  1734. return FALSE ;
  1735. }
  1736. }
  1737. for (pSystem = *ppSystemFirst ;
  1738. pSystem ;
  1739. pSystem = pSystem->pSystemNext) { // for
  1740. // lock the state data mutex, should be quick unless this thread
  1741. // is still getting data from last time
  1742. if (pSystem->hStateDataMutex == 0)
  1743. continue ;
  1744. WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L);
  1745. if (WaitStatus == WAIT_OBJECT_0) {
  1746. ResetEvent (pSystem->hPerfDataEvent) ;
  1747. pSystem->StateData = WAIT_FOR_PERF_DATA ;
  1748. // add this to the wait
  1749. if (NumberOfSystems >= NumberOfHandles) {
  1750. NumberOfHandles += MAXIMUM_WAIT_OBJECTS ;
  1751. lpHandles = (HANDLE *) MemoryResize (
  1752. lpHandles,
  1753. NumberOfHandles * sizeof (HANDLE)) ;
  1754. if (!lpHandles) {
  1755. // out of memory, can't go on
  1756. NumberOfHandles = 0 ;
  1757. return FALSE ;
  1758. }
  1759. }
  1760. lpHandles [NumberOfSystems] = pSystem->hPerfDataEvent ;
  1761. NumberOfSystems++ ;
  1762. // Send Message to thread to take a data sample
  1763. PostThreadMessage (
  1764. pSystem->dwThreadID,
  1765. WM_GET_PERF_DATA,
  1766. (WPARAM)0,
  1767. (LPARAM)0) ;
  1768. ReleaseMutex(pSystem->hStateDataMutex);
  1769. }
  1770. }
  1771. // wait for all the data
  1772. if (NumberOfSystems) {
  1773. // increase timeout if we are monitoring lots of systems
  1774. // For every additional 5 systems, add 5 more seconds
  1775. lpPacketHandles = lpHandles ;
  1776. do {
  1777. WaitStatus = WaitForMultipleObjects (
  1778. min (NumberOfSystems, MAXIMUM_WAIT_OBJECTS),
  1779. lpPacketHandles,
  1780. TRUE, // wait for all objects
  1781. DataTimeOut + (NumberOfSystems / 5) * DEFAULT_DATA_TIMEOUT);
  1782. if (WaitStatus == WAIT_TIMEOUT ||
  1783. NumberOfSystems <= MAXIMUM_WAIT_OBJECTS) {
  1784. //if (WaitStatus == WAIT_TIMEOUT)
  1785. // mike2(TEXT("WaitTimeOut for %ld systems\n"), NumberOfSystems) ;
  1786. break ;
  1787. }
  1788. // more systems --> more to wait
  1789. NumberOfSystems -= MAXIMUM_WAIT_OBJECTS ;
  1790. lpPacketHandles += MAXIMUM_WAIT_OBJECTS ;
  1791. } while (TRUE) ;
  1792. for (pSystem = *ppSystemFirst ;
  1793. pSystem ;
  1794. pSystem = pSystem->pSystemNext) { // for
  1795. if (pSystem->hStateDataMutex == 0)
  1796. continue ;
  1797. // lock the state data mutex
  1798. WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L);
  1799. if (WaitStatus == WAIT_OBJECT_0) {
  1800. if (pSystem->StateData != PERF_DATA_READY) {
  1801. if (!FailedLinesForSystem (pSystem->sysName,
  1802. pSystem->pSystemPerfData,
  1803. pLineFirst)) {
  1804. if (!bAddLineInProgress) {
  1805. // mark this system as no-longer-needed
  1806. iNoUseSystemDetected++ ;
  1807. pSystem->bSystemNoLongerNeeded = TRUE ;
  1808. }
  1809. }
  1810. } else {
  1811. if (!UpdateLinesForSystem (pSystem->sysName,
  1812. pSystem->pSystemPerfData,
  1813. pLineFirst,
  1814. pSystem)) {
  1815. if (!bAddLineInProgress) {
  1816. // mark this system as no-longer-needed
  1817. iNoUseSystemDetected++ ;
  1818. pSystem->bSystemNoLongerNeeded = TRUE ;
  1819. }
  1820. }
  1821. }
  1822. pSystem->StateData = IDLE_STATE ;
  1823. ReleaseMutex(pSystem->hStateDataMutex);
  1824. } else {
  1825. if (!FailedLinesForSystem (pSystem->sysName,
  1826. pSystem->pSystemPerfData,
  1827. pLineFirst)) {
  1828. if (!bAddLineInProgress) {
  1829. // mark this system as no-longer-needed
  1830. iNoUseSystemDetected++ ;
  1831. pSystem->bSystemNoLongerNeeded = TRUE ;
  1832. }
  1833. }
  1834. }
  1835. }
  1836. // check for un-used systems
  1837. if (iNoUseSystemDetected) {
  1838. // some unused system(s) detected.
  1839. DeleteUnusedSystems (ppSystemFirst, iNoUseSystemDetected) ;
  1840. }
  1841. }
  1842. return (TRUE) ;
  1843. } // UpdateLines
  1844. void
  1845. PerfDataThread (
  1846. PPERFSYSTEM pSystem
  1847. )
  1848. {
  1849. MSG msg ;
  1850. BOOL bGetPerfData ;
  1851. DWORD WaitStatus ;
  1852. while (GetMessage (&msg, NULL, 0, 0)) {
  1853. if (LOWORD(msg.message) == WM_GET_PERF_DATA) {
  1854. // this system has been marked as no long used,
  1855. // forget about getting data and continue until
  1856. // we get to the WM_FREE_SYSTEM msg
  1857. if (pSystem->bSystemNoLongerNeeded)
  1858. continue ;
  1859. bGetPerfData = FALSE ;
  1860. if (!bAddLineInProgress ||
  1861. (pSystem->lpszValue &&
  1862. !strsame (pSystem->lpszValue, L"Global"))) {
  1863. bGetPerfData = UpdateSystemData (pSystem, &(pSystem->pSystemPerfData)) ;
  1864. }
  1865. WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 1000L);
  1866. if (WaitStatus == WAIT_OBJECT_0) {
  1867. if (pSystem->StateData == WAIT_FOR_PERF_DATA) {
  1868. pSystem->StateData = bGetPerfData ?
  1869. PERF_DATA_READY : PERF_DATA_FAIL ;
  1870. } else {
  1871. //mike2(TEXT("Thread - System = %s, WaitStatus = %d\n"),
  1872. //pSystem->sysName, WaitStatus) ;
  1873. }
  1874. ReleaseMutex(pSystem->hStateDataMutex);
  1875. SetEvent (pSystem->hPerfDataEvent) ;
  1876. }
  1877. } // WM_GET_PERF_DATA MSG
  1878. else if (LOWORD(msg.message) == WM_FREE_SYSTEM) {
  1879. //mike2(TEXT("Thread - System = %s closing\n"),
  1880. //pSystem->sysName) ;
  1881. // do the memory cleanup during SystemFree stage
  1882. // cleanup all the data collection variables
  1883. if (pSystem->hPerfDataEvent)
  1884. CloseHandle (pSystem->hPerfDataEvent) ;
  1885. if (pSystem->hStateDataMutex)
  1886. CloseHandle (pSystem->hStateDataMutex) ;
  1887. if (pSystem->pSystemPerfData)
  1888. MemoryFree (pSystem->pSystemPerfData);
  1889. if (pSystem->lpszValue) {
  1890. MemoryFree (pSystem->lpszValue);
  1891. pSystem->lpszValue = NULL ;
  1892. }
  1893. CloseHandle (pSystem->hThread);
  1894. MemoryFree (pSystem) ;
  1895. break ; // get out of message loop
  1896. } // WM_FREE_SYSTEM MSG
  1897. } // GetMessage Loop
  1898. ExitThread (TRUE) ;
  1899. } // PerfDataThread