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.

777 lines
22 KiB

  1. //==========================================================================//
  2. // Includes //
  3. //==========================================================================//
  4. #include "perfmon.h"
  5. #include "playback.h" // external declarations for this module
  6. #include "bookmark.h" // for BookmarkAppend
  7. #include "grafdata.h" // for ResetGraph
  8. #include "perfdata.h" // for UpdateLinesForSystem
  9. #include "perfmops.h" // for SystemTimeDateString
  10. #include "log.h"
  11. #include "pmemory.h" // for MemoryAllocate
  12. #include "fileutil.h"
  13. #include "utils.h"
  14. #include "alert.h" // for ResetAlert
  15. #include "report.h" // for ResetReport
  16. NTSTATUS
  17. AddNamesToArray (
  18. LPTSTR pNames,
  19. DWORD dwLastID,
  20. LPWSTR *lpCounterId
  21. );
  22. void
  23. PlaybackAddCounterName (
  24. PLOGINDEX pIndex
  25. );
  26. //==========================================================================//
  27. // Macros //
  28. //==========================================================================//
  29. #define PointerSeek(pBase, lFileOffset) \
  30. ((PVOID) ((PBYTE) pBase + lFileOffset))
  31. //==========================================================================//
  32. // Local Functions //
  33. //==========================================================================//
  34. PVOID
  35. PlaybackSeek (
  36. long lFileOffset
  37. )
  38. {
  39. return (PointerSeek (PlaybackLog.pHeader, lFileOffset)) ;
  40. }
  41. PLOGINDEXBLOCK
  42. FirstIndexBlock (
  43. PLOGHEADER pLogHeader
  44. )
  45. {
  46. return ((PLOGINDEXBLOCK) PointerSeek (pLogHeader, pLogHeader->iLength)) ;
  47. }
  48. PLOGINDEX
  49. IndexFromPosition (
  50. PLOGPOSITION pLogPosition
  51. )
  52. {
  53. return (&pLogPosition->pIndexBlock->aIndexes [pLogPosition->iIndex]) ;
  54. }
  55. PPERFDATA
  56. DataFromIndex (
  57. PLOGINDEX pLogIndex,
  58. LPTSTR lpszSystemName
  59. )
  60. {
  61. PPERFDATA pPerfData;
  62. TCHAR szLoggedComputerName[MAX_PATH + 3] ;
  63. int iNumSystem ;
  64. // Note: NULL lpszSystemName means return first logged system name
  65. // at the specified index.
  66. pPerfData = PlaybackSeek (pLogIndex->lDataOffset) ;
  67. for (iNumSystem = 0;
  68. iNumSystem < pLogIndex->iSystemsLogged;
  69. iNumSystem++) {
  70. if ( pPerfData &&
  71. pPerfData->Signature[0] == (WCHAR)'P' &&
  72. pPerfData->Signature[1] == (WCHAR)'E' &&
  73. pPerfData->Signature[2] == (WCHAR)'R' &&
  74. pPerfData->Signature[3] == (WCHAR)'F' ) {
  75. GetPerfComputerName(pPerfData, szLoggedComputerName) ;
  76. if (!lpszSystemName || strsamei(lpszSystemName, szLoggedComputerName)) {
  77. return pPerfData ;
  78. }
  79. pPerfData = (PPERFDATA)((PBYTE) pPerfData +
  80. pPerfData->TotalByteLength) ;
  81. } else {
  82. break ;
  83. }
  84. }
  85. return NULL ;
  86. }
  87. PPERFDATA
  88. DataFromIndexPosition (
  89. PLOGPOSITION pLogPosition,
  90. LPTSTR lpszSystemName
  91. )
  92. {
  93. PLOGINDEX pLogIndex ;
  94. // long lDataFileOffset ;
  95. pLogIndex = IndexFromPosition (pLogPosition) ;
  96. return (DataFromIndex (pLogIndex, lpszSystemName)) ;
  97. }
  98. BOOL
  99. NextLogPosition (
  100. IN OUT PLOGPOSITION pLogPosition
  101. )
  102. {
  103. PLOGINDEXBLOCK pIndexBlock ;
  104. if (pLogPosition->pIndexBlock->iNumIndexes == 0) {
  105. // no data in this index block. This is most likely
  106. // a corrupted log file caused by system failure...
  107. return (FALSE) ;
  108. }
  109. if (pLogPosition->iIndex == pLogPosition->pIndexBlock->iNumIndexes - 1) {
  110. if (pLogPosition->pIndexBlock->lNextBlockOffset) {
  111. pIndexBlock =
  112. PlaybackSeek (pLogPosition->pIndexBlock->lNextBlockOffset) ;
  113. if (pIndexBlock->iNumIndexes == 0) {
  114. // no data in the next index block. This is most likely
  115. // a corrupted log file caused by system failure...
  116. return (FALSE) ;
  117. } else {
  118. pLogPosition->pIndexBlock = pIndexBlock ;
  119. pLogPosition->iIndex = 0 ;
  120. return (TRUE) ;
  121. }
  122. } else
  123. return (FALSE) ;
  124. } else {
  125. pLogPosition->iIndex++ ;
  126. return (TRUE) ;
  127. }
  128. }
  129. BOOL
  130. NextIndexPosition (
  131. IN OUT PLOGPOSITION pLogPosition,
  132. BOOL bCheckForNonDataIndexes
  133. )
  134. /*
  135. Effect: Set pLogPosition to the next log position from
  136. the current position of pLogPosition if there is one.
  137. Returns: Whether there was a next log position.
  138. */
  139. {
  140. LOGPOSITION LP ;
  141. PLOGINDEX pIndex ;
  142. PBOOKMARK pBookmarkDisk, pBookmark ;
  143. // LONG lFilePosition ;
  144. pIndex = IndexFromPosition (pLogPosition) ;
  145. LP = *pLogPosition ;
  146. pBookmark = NULL ;
  147. while (TRUE) {
  148. if (!NextLogPosition (&LP))
  149. return (FALSE) ;
  150. pIndex = IndexFromPosition (&LP) ;
  151. if (pIndex && bCheckForNonDataIndexes && IsCounterNameIndex (pIndex)) {
  152. PlaybackAddCounterName (pIndex) ;
  153. }
  154. if (pIndex && bCheckForNonDataIndexes && IsBookmarkIndex (pIndex)) {
  155. if (pBookmark) {
  156. // this is the case when several bookmarks are
  157. // found before any data index...
  158. pBookmark->iTic = PlaybackLog.iTotalTics ;
  159. BookmarkAppend (&PlaybackLog.pBookmarkFirst, pBookmark) ;
  160. }
  161. pBookmarkDisk = PlaybackSeek (pIndex->lDataOffset) ;
  162. pBookmark = MemoryAllocate (sizeof (BOOKMARK)) ;
  163. if (pBookmark) {
  164. *pBookmark = *pBookmarkDisk;
  165. pBookmark->pBookmarkNext = NULL ;
  166. }
  167. else return (FALSE);
  168. }
  169. if (pIndex && IsDataIndex (pIndex)) {
  170. LP.iPosition++ ;
  171. *pLogPosition = LP ;
  172. if (pBookmark) {
  173. pBookmark->iTic = PlaybackLog.iTotalTics ;
  174. BookmarkAppend (&PlaybackLog.pBookmarkFirst, pBookmark) ;
  175. }
  176. return (TRUE) ;
  177. }
  178. }
  179. }
  180. BOOL
  181. NextReLogIndexPosition (
  182. IN OUT PLOGPOSITION pLogPosition
  183. )
  184. /*
  185. Effect: Set pLogPosition to the next log position from
  186. the current position of pLogPosition if there is one.
  187. Will return bookmarks, counternames, or data.
  188. Returns: Whether there was a next relog position.
  189. */
  190. {
  191. LOGPOSITION LP ;
  192. PLOGINDEX pIndex ;
  193. // LONG lFilePosition ;
  194. pIndex = IndexFromPosition (pLogPosition) ;
  195. LP = *pLogPosition ;
  196. if (!NextLogPosition (&LP))
  197. return (FALSE) ;
  198. pIndex = IndexFromPosition (&LP) ;
  199. if (pIndex && IsDataIndex (pIndex)) {
  200. LP.iPosition++ ;
  201. }
  202. *pLogPosition = LP ;
  203. return (TRUE) ;
  204. }
  205. //==========================================================================//
  206. // Exported Functions //
  207. //==========================================================================//
  208. void
  209. PlaybackInitializeInstance (void)
  210. {
  211. PlaybackLog.iStatus = iPMStatusClosed ;
  212. PlaybackLog.hFile = NULL ;
  213. PlaybackLog.szFilePath = MemoryAllocate (FilePathLen * sizeof (TCHAR)) ;
  214. if (PlaybackLog.szFilePath) {
  215. lstrcpy (PlaybackLog.szFilePath, szDefaultLogFileName) ;
  216. }
  217. PlaybackLog.szFileTitle = MemoryAllocate (FilePathLen * sizeof (TCHAR)) ;
  218. if (PlaybackLog.szFileTitle) {
  219. lstrcpy (PlaybackLog.szFileTitle, szDefaultLogFileName) ;
  220. }
  221. }
  222. INT
  223. OpenPlayback (
  224. LPTSTR lpszFilePath,
  225. LPTSTR lpszFileTitle
  226. )
  227. {
  228. BOOL bFirstTime = TRUE ;
  229. lstrcpy (PlaybackLog.szFilePath, lpszFilePath) ;
  230. lstrcpy (PlaybackLog.szFileTitle, lpszFileTitle) ;
  231. PlaybackLog.hFile = FileHandleReadOnly (lpszFilePath) ;
  232. if (!PlaybackLog.hFile || PlaybackLog.hFile == INVALID_HANDLE_VALUE) {
  233. return (ERR_CANT_OPEN) ;
  234. }
  235. PlaybackLog.pHeader = (PLOGHEADER) FileMap (PlaybackLog.hFile,
  236. &PlaybackLog.hMapHandle) ;
  237. if (!PlaybackLog.pHeader) {
  238. if (PlaybackLog.hMapHandle) {
  239. CloseHandle (PlaybackLog.hMapHandle) ;
  240. }
  241. CloseHandle (PlaybackLog.hFile) ;
  242. return (ERR_CANT_OPEN) ;
  243. }
  244. if (!strsame (PlaybackLog.pHeader->szSignature, LogFileSignature)) {
  245. FileUnMap((LPVOID)PlaybackLog.pHeader, PlaybackLog.hMapHandle) ;
  246. CloseHandle (PlaybackLog.hFile) ;
  247. return (ERR_BAD_LOG_FILE) ;
  248. }
  249. PlaybackLog.BeginIndexPos.pIndexBlock = FirstIndexBlock (PlaybackLog.pHeader) ;
  250. PlaybackLog.BeginIndexPos.iIndex = 0 ;
  251. PlaybackLog.BeginIndexPos.iPosition = 0 ;
  252. PlaybackLog.pBookmarkFirst = NULL ;
  253. PlaybackLog.iTotalTics = 1 ;
  254. PlaybackLog.EndIndexPos = PlaybackLog.BeginIndexPos ;
  255. while (NextIndexPosition (&PlaybackLog.EndIndexPos, TRUE)) {
  256. if (bFirstTime) {
  257. // set the begin index to the first data index
  258. bFirstTime = FALSE ;
  259. PlaybackLog.BeginIndexPos.iIndex =
  260. PlaybackLog.EndIndexPos.iIndex ;
  261. } else {
  262. PlaybackLog.iTotalTics++ ;
  263. }
  264. }
  265. if (PlaybackLog.iTotalTics == 1 ) {
  266. // no data inside the log file. It must be a corrupted
  267. // log file
  268. FileUnMap((LPVOID)PlaybackLog.pHeader, PlaybackLog.hMapHandle) ;
  269. CloseHandle (PlaybackLog.hFile) ;
  270. return (ERR_CORRUPT_LOG) ;
  271. }
  272. // PlaybackLog.StartIndexPos = PlaybackLog.BeginIndexPos ;
  273. // getthe first data index
  274. if (!LogPositionN (1, &(PlaybackLog.StartIndexPos))) {
  275. PlaybackLog.StartIndexPos = PlaybackLog.BeginIndexPos ;
  276. }
  277. PlaybackLog.StopIndexPos = PlaybackLog.EndIndexPos ;
  278. PlaybackLog.StopIndexPos.iPosition =
  279. min (PlaybackLog.StopIndexPos.iPosition,
  280. PlaybackLog.iTotalTics - 1 ) ;
  281. PlaybackLog.iSelectedTics = PlaybackLog.iTotalTics ;
  282. PlaybackLog.iStatus = iPMStatusPlaying ;
  283. return (0) ;
  284. }
  285. void
  286. CloseInputLog (
  287. HWND hWndParent
  288. )
  289. {
  290. PBOOKMARK pBookmark, pNextBookmark ;
  291. BOOL retCode, retCode1 ;
  292. PLOGCOUNTERNAME pLogCounterName, pNextCounterName ;
  293. UNREFERENCED_PARAMETER (hWndParent) ;
  294. // free the bookmark list
  295. for (pBookmark = PlaybackLog.pBookmarkFirst ;
  296. pBookmark ;
  297. pBookmark = pNextBookmark ) {
  298. // save next bookmark and free current bookmark
  299. pNextBookmark = pBookmark->pBookmarkNext ;
  300. MemoryFree (pBookmark) ;
  301. }
  302. PlaybackLog.pBookmarkFirst = NULL ;
  303. // free all counter names stuff
  304. if (PlaybackLog.pBaseCounterNames) {
  305. MemoryFree (PlaybackLog.pBaseCounterNames) ;
  306. }
  307. PlaybackLog.pBaseCounterNames = NULL ;
  308. PlaybackLog.lBaseCounterNameSize = 0 ;
  309. PlaybackLog.lBaseCounterNameOffset = 0 ;
  310. for (pLogCounterName = PlaybackLog.pLogCounterNameFirst ;
  311. pLogCounterName ;
  312. pLogCounterName = pNextCounterName) {
  313. pNextCounterName = pLogCounterName->pCounterNameNext ;
  314. MemoryFree (pLogCounterName->pRemainNames) ;
  315. MemoryFree (pLogCounterName) ;
  316. }
  317. PlaybackLog.pLogCounterNameFirst = NULL ;
  318. retCode1 = FileUnMap((LPVOID)PlaybackLog.pHeader, PlaybackLog.hMapHandle) ;
  319. retCode = CloseHandle (PlaybackLog.hFile) ;
  320. PlaybackLog.iStatus = iPMStatusClosed ;
  321. ResetGraphView (hWndGraph) ;
  322. ResetAlertView (hWndAlert) ;
  323. ResetLogView (hWndLog) ;
  324. ResetReportView (hWndReport) ;
  325. }
  326. BOOL
  327. LogPositionN (
  328. int iIndex,
  329. PLOGPOSITION pLP
  330. )
  331. {
  332. LOGPOSITION LP ;
  333. int i ;
  334. LP = PlaybackLog.BeginIndexPos ;
  335. for (i = 0 ;
  336. i < iIndex ;
  337. i++) {
  338. if (!NextIndexPosition (&LP, FALSE))
  339. return (FALSE) ;
  340. }
  341. *pLP = LP ;
  342. return (TRUE) ;
  343. }
  344. PLOGINDEX
  345. PlaybackIndexN (
  346. int iIndex
  347. )
  348. {
  349. LOGPOSITION LP ;
  350. int i ;
  351. LP = PlaybackLog.BeginIndexPos ;
  352. for (i = 0 ;
  353. i < iIndex ;
  354. i++) {
  355. if (!NextIndexPosition (&LP, FALSE))
  356. return (NULL) ;
  357. }
  358. return (IndexFromPosition (&LP)) ;
  359. }
  360. BOOL
  361. PlaybackLines (
  362. PPERFSYSTEM pSystemFirst,
  363. PLINE pLineFirst,
  364. int iLogTic
  365. )
  366. {
  367. PLOGINDEX pLogIndex ;
  368. PPERFDATA pPerfData ;
  369. PPERFSYSTEM pSystem ;
  370. BOOL bAnyFound ;
  371. pLogIndex = PlaybackIndexN (iLogTic) ;
  372. if (!pLogIndex)
  373. return (FALSE) ;
  374. bAnyFound = FALSE ;
  375. for (pSystem = pSystemFirst ;
  376. pSystem ;
  377. pSystem = pSystem->pSystemNext) { // for
  378. pPerfData = DataFromIndex (pLogIndex, pSystem->sysName) ;
  379. if (pPerfData) {
  380. UpdateLinesForSystem (pSystem->sysName,
  381. pPerfData,
  382. pLineFirst,
  383. NULL) ;
  384. bAnyFound = TRUE ;
  385. } else {
  386. FailedLinesForSystem (pSystem->sysName,
  387. pPerfData,
  388. pLineFirst) ;
  389. }
  390. }
  391. return (bAnyFound) ;
  392. }
  393. PPERFDATA
  394. LogDataFromPosition (
  395. PPERFSYSTEM pSystem,
  396. PLOGPOSITION pLogPosition
  397. )
  398. {
  399. PLOGINDEX pLogIndex ;
  400. if (!pLogPosition)
  401. return (NULL) ;
  402. pLogIndex = IndexFromPosition (pLogPosition) ;
  403. if (!pLogIndex)
  404. return (NULL) ;
  405. return (DataFromIndex (pLogIndex, pSystem->sysName)) ;
  406. }
  407. BOOL
  408. LogPositionSystemTime (
  409. PLOGPOSITION pLP,
  410. SYSTEMTIME *pSystemTime
  411. )
  412. /*
  413. Effect: Given a logposition, get the index entry for that position
  414. and return the system time stored therein.
  415. */
  416. {
  417. PLOGINDEX pLogIndex ;
  418. pLogIndex = IndexFromPosition (pLP) ;
  419. if (!pLogIndex)
  420. return (FALSE) ;
  421. *pSystemTime = pLogIndex->SystemTime ;
  422. return TRUE;
  423. }
  424. int
  425. LogPositionIntervalSeconds (
  426. PLOGPOSITION pLPStart,
  427. PLOGPOSITION pLPStop
  428. )
  429. /*
  430. Effect: Return the time difference (in seconds) between the
  431. system times of the two specified log positions.
  432. */
  433. {
  434. SYSTEMTIME SystemTimeStart ;
  435. SYSTEMTIME SystemTimeStop ;
  436. if (LogPositionSystemTime (pLPStart, &SystemTimeStart) &&
  437. LogPositionSystemTime (pLPStop, &SystemTimeStop))
  438. return (SystemTimeDifference (&SystemTimeStart,
  439. &SystemTimeStop, TRUE)) ;
  440. else
  441. return (0) ;
  442. }
  443. int
  444. PlaybackSelectedSeconds (void)
  445. {
  446. return (LogPositionIntervalSeconds (&PlaybackLog.StartIndexPos,
  447. &PlaybackLog.StopIndexPos)) ;
  448. }
  449. void
  450. BuildLogComputerList (
  451. HWND hDlg,
  452. int DlgID
  453. )
  454. {
  455. PPERFDATA pPerfData;
  456. int iNumSystem ;
  457. HWND hListBox = GetDlgItem (hDlg, DlgID) ;
  458. PLOGINDEX pLogIndex ;
  459. TCHAR szLoggedComputerName[MAX_PATH + 3] ;
  460. pLogIndex = IndexFromPosition (&(PlaybackLog.StartIndexPos)) ;
  461. pPerfData = PlaybackSeek (pLogIndex->lDataOffset) ;
  462. for (iNumSystem = 0; iNumSystem < pLogIndex->iSystemsLogged; iNumSystem++) {
  463. if ( pPerfData &&
  464. pPerfData->Signature[0] == (WCHAR)'P' &&
  465. pPerfData->Signature[1] == (WCHAR)'E' &&
  466. pPerfData->Signature[2] == (WCHAR)'R' &&
  467. pPerfData->Signature[3] == (WCHAR)'F' ) {
  468. GetPerfComputerName(pPerfData, szLoggedComputerName) ;
  469. if (LBFind (hListBox, szLoggedComputerName) != LB_ERR) {
  470. // computer name already exist, we must have reach the next
  471. // block of perfdata
  472. break ;
  473. }
  474. LBAdd (hListBox, szLoggedComputerName) ;
  475. pPerfData = (PPERFDATA)((PBYTE) pPerfData + pPerfData->TotalByteLength) ;
  476. } else {
  477. break;
  478. }
  479. }
  480. }
  481. void
  482. PlaybackAddCounterName (
  483. PLOGINDEX pIndex
  484. )
  485. {
  486. PLOGCOUNTERNAME pLogCounterName = NULL,
  487. pListCounterName = NULL;
  488. PLOGFILECOUNTERNAME pDiskCounterName ;
  489. PVOID pCounterData ;
  490. BOOL bExist = FALSE ;
  491. pDiskCounterName = PlaybackSeek (pIndex->lDataOffset) ;
  492. // check we have a record for this system
  493. for (pListCounterName = PlaybackLog.pLogCounterNameFirst ;
  494. pListCounterName ;
  495. pListCounterName = pListCounterName->pCounterNameNext) {
  496. if (strsamei(pDiskCounterName->szComputer,
  497. pListCounterName->CounterName.szComputer)) {
  498. // found!
  499. pLogCounterName = pListCounterName ;
  500. bExist = TRUE ;
  501. break ;
  502. }
  503. }
  504. if (!bExist) {
  505. // new counter name record
  506. if (!(pLogCounterName = MemoryAllocate (sizeof(LOGCOUNTERNAME)))) {
  507. return ;
  508. }
  509. } else {
  510. // free old memory in previous counter name record.
  511. if (pLogCounterName->pRemainNames) {
  512. MemoryFree (pLogCounterName->pRemainNames) ;
  513. }
  514. pLogCounterName->pRemainNames = NULL ;
  515. }
  516. pLogCounterName->CounterName = *pDiskCounterName ;
  517. if (pDiskCounterName->lBaseCounterNameOffset == 0) {
  518. // this is the base counter names,
  519. // get the master copy of the counter names
  520. if (!(pCounterData =
  521. MemoryAllocate (pDiskCounterName->lUnmatchCounterNames))) {
  522. MemoryFree (pLogCounterName) ;
  523. return ;
  524. }
  525. // free the old one if it exists.
  526. if (PlaybackLog.pBaseCounterNames) {
  527. MemoryFree (PlaybackLog.pBaseCounterNames) ;
  528. }
  529. PlaybackLog.pBaseCounterNames = pCounterData ;
  530. pCounterData =
  531. PlaybackSeek (pDiskCounterName->lCurrentCounterNameOffset) ;
  532. memcpy (PlaybackLog.pBaseCounterNames,
  533. pCounterData,
  534. pDiskCounterName->lUnmatchCounterNames) ;
  535. PlaybackLog.lBaseCounterNameSize =
  536. pDiskCounterName->lUnmatchCounterNames ;
  537. PlaybackLog.lBaseCounterNameOffset =
  538. pDiskCounterName->lBaseCounterNameOffset ;
  539. } else if (pDiskCounterName->lUnmatchCounterNames) {
  540. // this is not a based system and it has extra counter names
  541. // allocate a buffer to hold them
  542. pLogCounterName->pRemainNames =
  543. MemoryAllocate (pDiskCounterName->lUnmatchCounterNames) ;
  544. if (pLogCounterName->pRemainNames) {
  545. pCounterData =
  546. PlaybackSeek (pDiskCounterName->lCurrentCounterNameOffset) ;
  547. memcpy(pLogCounterName->pRemainNames,
  548. pCounterData,
  549. pDiskCounterName->lUnmatchCounterNames) ;
  550. }
  551. }
  552. if (!bExist) {
  553. // now add the new counter name record to the linked list
  554. if (!PlaybackLog.pLogCounterNameFirst) {
  555. PlaybackLog.pLogCounterNameFirst = pLogCounterName ;
  556. } else {
  557. for (pListCounterName = PlaybackLog.pLogCounterNameFirst ;
  558. pListCounterName->pCounterNameNext ;
  559. pListCounterName = pListCounterName->pCounterNameNext) {
  560. // do nothing until we get to the end of the list
  561. ;
  562. }
  563. pListCounterName->pCounterNameNext = pLogCounterName ;
  564. }
  565. }
  566. } // PlaybackAddCounterName
  567. LPWSTR *
  568. LogBuildNameTable (
  569. PPERFSYSTEM pSysInfo
  570. )
  571. {
  572. DWORD dwArraySize ;
  573. PLOGCOUNTERNAME pCounterName ;
  574. LPWSTR *lpCounterId = NULL ;
  575. LPWSTR lpCounterNames ;
  576. NTSTATUS Status ;
  577. for (pCounterName = PlaybackLog.pLogCounterNameFirst ;
  578. pCounterName ;
  579. pCounterName = pCounterName->pCounterNameNext) {
  580. if (strsamei (pSysInfo->sysName, pCounterName->CounterName.szComputer)) {
  581. // found the right system
  582. break ;
  583. }
  584. }
  585. if (!pCounterName) {
  586. goto ERROR_EXIT ;
  587. }
  588. dwArraySize = (pCounterName->CounterName.dwLastCounterId + 1)
  589. * sizeof (LPWSTR) ;
  590. lpCounterId = MemoryAllocate (dwArraySize +
  591. pCounterName->CounterName.lMatchLength +
  592. pCounterName->CounterName.lUnmatchCounterNames ) ;
  593. if (!lpCounterId) {
  594. goto ERROR_EXIT ;
  595. }
  596. // initialize pointers into buffer
  597. lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
  598. if (pCounterName->CounterName.lBaseCounterNameOffset == 0) {
  599. // this is the base system
  600. memcpy(lpCounterNames,
  601. PlaybackLog.pBaseCounterNames,
  602. PlaybackLog.lBaseCounterNameSize) ;
  603. } else {
  604. // copy the matched portion from the base system
  605. memcpy(lpCounterNames,
  606. PlaybackLog.pBaseCounterNames,
  607. pCounterName->CounterName.lMatchLength) ;
  608. // copy the unmatched portion
  609. if (pCounterName->CounterName.lUnmatchCounterNames) {
  610. memcpy(((PBYTE)lpCounterNames +
  611. pCounterName->CounterName.lMatchLength),
  612. pCounterName->pRemainNames,
  613. pCounterName->CounterName.lUnmatchCounterNames) ;
  614. }
  615. }
  616. Status = AddNamesToArray (lpCounterNames,
  617. pCounterName->CounterName.dwLastCounterId,
  618. lpCounterId) ;
  619. if (Status != ERROR_SUCCESS) {
  620. goto ERROR_EXIT ;
  621. }
  622. pSysInfo->CounterInfo.dwLastId =
  623. pCounterName->CounterName.dwLastCounterId ;
  624. pSysInfo->CounterInfo.dwLangId =
  625. pCounterName->CounterName.dwLangId ;
  626. pSysInfo->CounterInfo.dwHelpSize = 0 ;
  627. pSysInfo->CounterInfo.dwCounterSize =
  628. pCounterName->CounterName.lMatchLength +
  629. pCounterName->CounterName.lUnmatchCounterNames ;
  630. return (lpCounterId) ;
  631. ERROR_EXIT:
  632. if (lpCounterId) {
  633. MemoryFree (lpCounterId) ;
  634. }
  635. return (NULL) ;
  636. }