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.

2636 lines
82 KiB

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