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.

2471 lines
73 KiB

  1. /*****************************************************************************
  2. *
  3. * Log.c - This module handles the Logging.
  4. *
  5. * Microsoft Confidential
  6. * Copyright (c) 1992-1993 Microsoft Corporation
  7. *
  8. *
  9. ****************************************************************************/
  10. //==========================================================================//
  11. // Includes //
  12. //==========================================================================//
  13. #include <stdio.h>
  14. #include "perfmon.h"
  15. #include "log.h"
  16. #include "fileutil.h"
  17. #include "owndraw.h"
  18. #include "pmemory.h" // for MemoryXXX (mallloc-type) routines
  19. #include "perfmops.h" // for SystemAdd
  20. #include "perfdata.h"
  21. #include "playback.h" // for PlayingBackLog
  22. #include "status.h" // for StatusUpdateIcons
  23. #include "system.h" // for SystemAdd
  24. #include "utils.h"
  25. #include "fileopen.h" // for FileGetName
  26. #include "command.h"
  27. extern TCHAR LOCAL_SYS_CODE_NAME[] ;
  28. //==========================================================================//
  29. // Funtion Prototypes //
  30. //==========================================================================//
  31. BOOL LogWriteStartBookmark (HWND hWnd, SYSTEMTIME *pSystemTime) ;
  32. BOOL LogWriteBookmarkData (HWND hWnd, PBOOKMARK pBookMark) ;
  33. BOOL LogWriteSystemBookmark (HWND hWnd, LPTSTR SysName, BOOL DisConnect, SYSTEMTIME *pSystemTime) ;
  34. //==========================================================================//
  35. // Constants //
  36. //==========================================================================//
  37. #define LogNameMinLen 15
  38. #define LogObjectMinLen 20
  39. // This is set to 1 min
  40. #define LARGE_INTERVAL 60
  41. //=============================//
  42. // Log Class //
  43. //=============================//
  44. #define dwLogClassStyle (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS)
  45. #define iLogClassExtra (0)
  46. #define iLogWindowExtra (0)
  47. #define dwLogWindowStyle (WS_CHILD)
  48. //==========================================================================//
  49. // Local Data //
  50. //==========================================================================//
  51. int xStatusWidth ;
  52. int xNameMinWidth ;
  53. TCHAR szClosed [ShortTextLen] ;
  54. TCHAR szCollecting [ShortTextLen] ;
  55. // TCHAR szPaused [ControlStringLen + 1] ;
  56. LOGINDEXBLOCK *pLogIndexBlock ;
  57. #define WM_START_LOGGING WM_USER+2
  58. //==========================================================================//
  59. // Macros //
  60. //==========================================================================//
  61. #define LogEntryN(hWndLogEntries, iIndex) \
  62. ((PLOGENTRY) LBData (hWndLogEntries, iIndex))
  63. //==========================================================================//
  64. // Local Functions //
  65. //==========================================================================//
  66. void LogAddEntryToList (PLOGENTRY *ppLogEntryFirst, PLOGENTRY pLogNewEntry)
  67. {
  68. // insert the new entry at the beginning
  69. pLogNewEntry->pNextLogEntry = *ppLogEntryFirst ;
  70. *ppLogEntryFirst = pLogNewEntry ;
  71. }
  72. void LogDeleteEntryFromList (PLOGENTRY *ppLogEntryFirst, PLOGENTRY pLogEntryDel)
  73. {
  74. PLOGENTRY pLogEntry ;
  75. if (*ppLogEntryFirst == pLogEntryDel) {
  76. *ppLogEntryFirst = pLogEntryDel->pNextLogEntry ;
  77. } else {
  78. for (pLogEntry = *ppLogEntryFirst ;
  79. pLogEntry ;
  80. pLogEntry = pLogEntry->pNextLogEntry) {
  81. if (pLogEntry->pNextLogEntry == pLogEntryDel) {
  82. // found, remove this entry from the list
  83. pLogEntry->pNextLogEntry =
  84. pLogEntryDel->pNextLogEntry ;
  85. break ;
  86. }
  87. }
  88. }
  89. }
  90. // LogDeleteIndex - delete the log entry specified by iIndex
  91. // and do memory clean-up
  92. void static LogDeleteIndex (HWND hWndLogEntries, INT_PTR iIndex)
  93. {
  94. PLOGENTRY pLogEntry ;
  95. PLOG pLog ;
  96. pLogEntry = (PLOGENTRY) LBData(hWndLogEntries, iIndex) ;
  97. if (pLogEntry && pLogEntry != (PLOGENTRY)LB_ERR) {
  98. pLog = LogData (hWndLog) ;
  99. if (pLog->pLogEntryFirst) {
  100. LogDeleteEntryFromList (&(pLog->pLogEntryFirst), pLogEntry) ;
  101. }
  102. MemoryFree (pLogEntry) ;
  103. }
  104. LBDelete (hWndLogEntries, iIndex) ;
  105. }
  106. void LogEntriesChanged (HWND hWndLogEntries)
  107. /*
  108. Effect: Perform any actions needed when an entry has been added or
  109. removed from the log. In particular, determine if a new
  110. "Object" column width is appropriate. If it is, then
  111. change the width and redraw the log entries list.
  112. */
  113. {
  114. int iIndex ;
  115. int iIndexNum ;
  116. int xCol1Width ;
  117. HDC hDC ;
  118. PLOG pLog ;
  119. PLOGENTRY pLogEntry ;
  120. PPERFSYSTEM pSystem;
  121. pLog = LogData (hWndLog) ;
  122. xCol1Width = 0 ;
  123. hDC = GetDC (hWndLog) ;
  124. iIndexNum = LBNumItems (hWndLogEntries) ;
  125. // clear value Strings for all systems
  126. for (pSystem = pLog->pSystemFirst;
  127. pSystem;
  128. pSystem = pSystem->pSystemNext) {
  129. if (pSystem && pSystem->FailureTime == 0) {
  130. RemoveObjectsFromSystem (pSystem);
  131. }
  132. }
  133. for (iIndex = 0; iIndex < iIndexNum; iIndex++) {
  134. pLogEntry = LogEntryN (hWndLogEntries, iIndex) ;
  135. xCol1Width = max (TextWidth (hDC, pLogEntry->szObject),
  136. xCol1Width) ;
  137. pSystem = SystemGet (pLog->pSystemFirst, pLogEntry->szComputer);
  138. if (pSystem && pSystem->FailureTime == 0) {
  139. AppendObjectToValueList (
  140. pLogEntry->ObjectTitleIndex,
  141. pSystem->lpszValue);
  142. }
  143. }
  144. xCol1Width += 2 * xScrollWidth ;
  145. xCol1Width = max (xCol1Width,
  146. TextAvgWidth (hDC, LogObjectMinLen)) ;
  147. if (xCol1Width != pLog->xCol1Width) {
  148. pLog->xCol1Width = xCol1Width ;
  149. WindowInvalidate (hWndLogEntries) ;
  150. }
  151. ReleaseDC (hWndLog, hDC) ;
  152. }
  153. LPTSTR StatusText (int iPMStatus)
  154. /*
  155. Effect: Return a string representation of the log status
  156. iPMStatus.
  157. Note: Since these are globals, we can just return a pointer
  158. to them. The user of this routine should not free
  159. these pointers or modify the string.
  160. */
  161. {
  162. switch (iPMStatus) {
  163. case iPMStatusClosed:
  164. return (szClosed) ;
  165. case iPMStatusCollecting:
  166. return (szCollecting) ;
  167. // case iPMStatusPaused:
  168. // return (szPaused) ;
  169. default:
  170. return (szClosed) ;
  171. }
  172. }
  173. PLOG AllocateLogData (HWND hWndLog)
  174. {
  175. PLOG pLog ;
  176. pLog = LogData (hWndLog) ;
  177. pLog->iStatus = iPMStatusClosed ;
  178. pLog->bManualRefresh = FALSE ;
  179. // let's not give it a filename
  180. /*!!
  181. FileCombine (pLog->szFilePath,
  182. szDefaultLogDirectory, szDefaultLogFileName) ;
  183. !!*/
  184. strclr (pLog->szFilePath) ;
  185. pLog->pSystemFirst = NULL;
  186. pLog->lFileSize = 0L ;
  187. pLog->iIntervalMSecs = iDefaultLogIntervalSecs * 1000 ;
  188. pLog->pLogData = (PPERFDATA) MemoryAllocate (STARTING_SYSINFO_SIZE) ;
  189. pLog->dwDetailLevel = PERF_DETAIL_WIZARD ;
  190. LogEntriesChanged (hWndLogEntries) ;
  191. return (pLog) ;
  192. }
  193. void FreeLogData (PLOG pLog)
  194. {
  195. MemoryFree ((LPMEMORY)pLog->pLogData) ;
  196. }
  197. void UpdateLogSize (HWND hWnd)
  198. /*
  199. Effect: Set the size value to the current size. Also change the
  200. size entry in the status line.
  201. */
  202. {
  203. PLOG pLog ;
  204. TCHAR szSize [ShortTextLen + 1] ;
  205. pLog = LogData (hWnd) ;
  206. LongToCommaString (pLog->lFileSize, szSize) ;
  207. SetDlgItemText (hWnd, IDD_LOGSIZE, szSize) ;
  208. if (!PlayingBackLog()) {
  209. StatusUpdateIcons (hWndStatus) ;
  210. }
  211. }
  212. HANDLE LogAppendSetup(PLOG pLog, PLOGHEADER pLogFileHeader)
  213. {
  214. PLOGHEADER pHeader ;
  215. LOGPOSITION LP ;
  216. DWORD lPreviousIndexBlock ;
  217. DWORD lNextIndexBlock ;
  218. PLOGHEADER pPlaybackLogHeader ;
  219. HANDLE hMapHandle ;
  220. pHeader = (PLOGHEADER) FileMap(pLog->hFile, &hMapHandle) ;
  221. if (!pHeader ||
  222. !strsame(pHeader->szSignature, LogFileSignature) ||
  223. pHeader->wVersion != LogFileVersion ||
  224. pHeader->wRevision != LogFileRevision) {
  225. if (pHeader) {
  226. FileUnMap((LPVOID)pHeader, hMapHandle) ;
  227. }
  228. return 0 ;
  229. }
  230. *pLogFileHeader = *pHeader ;
  231. LP.pIndexBlock = FirstIndexBlock(pHeader) ;
  232. LP.iIndex = 0 ;
  233. LP.iPosition = 0 ;
  234. lPreviousIndexBlock = pHeader->iLength ;
  235. lNextIndexBlock = LP.pIndexBlock->lNextBlockOffset ;
  236. // since inside NextReLogIndexPosition would eventually call
  237. // PlaybackSeek for large log file, we have to temporarily
  238. // setup PlaybackLog.pHeader. Not a good fix but it works...
  239. pPlaybackLogHeader = PlaybackLog.pHeader ;
  240. PlaybackLog.pHeader = pHeader ;
  241. while (NextReLogIndexPosition(&LP)) {
  242. if (LP.pIndexBlock->lNextBlockOffset != lNextIndexBlock) {
  243. lPreviousIndexBlock = lNextIndexBlock ;
  244. lNextIndexBlock = LP.pIndexBlock->lNextBlockOffset ;
  245. }
  246. }
  247. // get the last system time from this log file
  248. if (LP.iIndex > 0) {
  249. SYSTEMTIME localSystemTime ;
  250. if (LogPositionSystemTime (&LP, &localSystemTime)) {
  251. pLog->LastLogTime = localSystemTime ;
  252. }
  253. }
  254. PlaybackLog.pHeader = pPlaybackLogHeader ;
  255. if (!pLogIndexBlock) {
  256. pLogIndexBlock = (LOGINDEXBLOCK *) MemoryAllocate (sizeof(LOGINDEXBLOCK)) ;
  257. }
  258. if (pLogIndexBlock) {
  259. *pLogIndexBlock = *LP.pIndexBlock ;
  260. }
  261. pLog->lIndexBlockOffset = lPreviousIndexBlock ;
  262. pLog->iIndex = ++LP.iIndex ;
  263. pLog->lFileSize = FileSeekEnd(pLog->hFile, 0) ;
  264. FileUnMap((LPVOID)pHeader, hMapHandle) ;
  265. return pLog->hFile ;
  266. }
  267. void LogRemoveCounterName (PLOG pLog)
  268. {
  269. PPERFSYSTEM pSystem ;
  270. if (pLog->pBaseCounterName) {
  271. MemoryFree (pLog->pBaseCounterName) ;
  272. }
  273. pLog->pBaseCounterName = 0 ;
  274. pLog->lBaseCounterNameSize = 0 ;
  275. pLog->lBaseCounterNameOffset = 0 ;
  276. // clear all the system marker to indicate they have not been
  277. // saved
  278. for (pSystem = pLog->pSystemFirst ;
  279. pSystem ;
  280. pSystem = pSystem->pSystemNext) {
  281. pSystem->bSystemCounterNameSaved = FALSE ;
  282. }
  283. }
  284. int CreateLogFile (PLOG pLog, BOOL bCreateFile, BOOL bSameFile)
  285. {
  286. HANDLE returnHandle ;
  287. LOGHEADER LogFileHeader ;
  288. long lCurPosition ;
  289. LOGFILECOUNTERNAME CounterNameRecord ;
  290. pLog->lFileSize = 0 ;
  291. memset (&(pLog->LastLogTime), 0, sizeof(SYSTEMTIME)) ;
  292. if (!pLogIndexBlock) {
  293. pLogIndexBlock = (LOGINDEXBLOCK *) MemoryAllocate (sizeof(LOGINDEXBLOCK)) ;
  294. }
  295. if (pLogIndexBlock) {
  296. lstrcpy (pLogIndexBlock->szSignature, LogIndexSignature) ;
  297. }
  298. else
  299. return ERROR_NOT_ENOUGH_MEMORY;
  300. pLog->hFile = FileHandleOpen (pLog->szFilePath) ;
  301. if (pLog->hFile != INVALID_HANDLE_VALUE) {
  302. // if this is a pre-existing log file, set up to append to it
  303. returnHandle = LogAppendSetup(pLog, &LogFileHeader) ;
  304. if (!returnHandle) {
  305. // this is not a log file...
  306. CloseHandle (pLog->hFile) ;
  307. return (ERR_BAD_LOG_FILE) ;
  308. }
  309. pLog->hFile = returnHandle ;
  310. }
  311. if (bCreateFile && (!pLog->hFile || pLog->hFile == INVALID_HANDLE_VALUE)) {
  312. // Create a new log file if needed.
  313. pLog->hFile = FileHandleCreate (pLog->szFilePath) ;
  314. if (!pLog->hFile || pLog->hFile == INVALID_HANDLE_VALUE)
  315. return (ERR_LOG_FILE) ;
  316. lstrcpy (LogFileHeader.szSignature, LogFileSignature) ;
  317. LogFileHeader.wVersion = LogFileVersion ;
  318. LogFileHeader.wRevision = LogFileRevision ;
  319. LogFileHeader.iLength = sizeof (LOGHEADER) ;
  320. LogFileHeader.lBaseCounterNameOffset = 0 ;
  321. if (!FileWrite (pLog->hFile, &LogFileHeader, sizeof (LogFileHeader))) {
  322. CloseHandle (pLog->hFile) ;
  323. return (ERR_LOG_FILE) ;
  324. }
  325. pLog->iIndex = 0 ;
  326. pLog->lIndexBlockOffset = FileTell (pLog->hFile) ;
  327. FileSeekCurrent (pLog->hFile, sizeof (LOGINDEXBLOCK)) ;
  328. pLog->lFileSize = sizeof(LOGHEADER) + sizeof (LOGINDEXBLOCK) ;
  329. pLogIndexBlock->iNumIndexes = 0 ;
  330. pLogIndexBlock->lNextBlockOffset = 0 ;
  331. // get rid of any previous counter names and get ready for start
  332. // if (!bSameFile)
  333. // {
  334. // LogRemoveCounterName (pLog) ;
  335. // }
  336. LogRemoveCounterName (pLog) ;
  337. } else if (bCreateFile) {
  338. // this is an existing log file, setup the counter names
  339. // LogFileHeader already has the header info filled in
  340. // by LogAppendSetup
  341. if (!bSameFile || !pLog->pBaseCounterName) {
  342. // get rid of any previous counter names
  343. LogRemoveCounterName (pLog) ;
  344. // read the new names and get ready for start
  345. lCurPosition = FileTell (pLog->hFile) ;
  346. FileSeekBegin (pLog->hFile,
  347. LogFileHeader.lBaseCounterNameOffset) ;
  348. if (!(FileRead (pLog->hFile,
  349. &CounterNameRecord,
  350. sizeof (CounterNameRecord)))) {
  351. FileSeekBegin (pLog->hFile,
  352. lCurPosition) ;
  353. goto EXIT ;
  354. }
  355. FileSeekBegin (pLog->hFile,
  356. CounterNameRecord.lCurrentCounterNameOffset) ;
  357. if (!(pLog->pBaseCounterName = MemoryAllocate (
  358. CounterNameRecord.lUnmatchCounterNames))) {
  359. FileSeekBegin (pLog->hFile,
  360. lCurPosition) ;
  361. goto EXIT ;
  362. }
  363. if (!(FileRead (pLog->hFile,
  364. pLog->pBaseCounterName,
  365. CounterNameRecord.lUnmatchCounterNames))) {
  366. MemoryFree (pLog->pBaseCounterName) ;
  367. pLog->pBaseCounterName = NULL ;
  368. FileSeekBegin (pLog->hFile,
  369. lCurPosition) ;
  370. goto EXIT ;
  371. }
  372. // we got the data, fill in other info
  373. pLog->lBaseCounterNameSize =
  374. CounterNameRecord.lUnmatchCounterNames ;
  375. pLog->lBaseCounterNameOffset =
  376. LogFileHeader.lBaseCounterNameOffset ;
  377. FileSeekBegin (pLog->hFile,
  378. lCurPosition) ;
  379. }
  380. }
  381. EXIT:
  382. return (0) ;
  383. }
  384. void LogWriteIndexBlock (PLOG pLog)
  385. {
  386. FileSeekBegin (pLog->hFile,
  387. pLog->lIndexBlockOffset) ;
  388. pLogIndexBlock->lNextBlockOffset = 0 ;
  389. FileWrite (pLog->hFile,
  390. (LPSTR) pLogIndexBlock,
  391. sizeof (LOGINDEXBLOCK)) ;
  392. }
  393. BOOL LogWriteIndex (PLOG pLog,
  394. UINT uFlags,
  395. SYSTEMTIME *pSystemTime,
  396. LONG lDataOffset,
  397. int iSystemsLogged)
  398. {
  399. LOGINDEX Index ;
  400. long lNextBlockOffset ;
  401. BOOL WriteOK ;
  402. //=============================//
  403. // Add Index Block Entry //
  404. //=============================//
  405. //=============================//
  406. // Index Block Full? //
  407. //=============================//
  408. WriteOK = TRUE ;
  409. if (pLog->iIndex == LogFileBlockMaxIndexes - 1) {
  410. lNextBlockOffset = FileTell (pLog->hFile) ;
  411. pLogIndexBlock->lNextBlockOffset = lNextBlockOffset ;
  412. FileSeekBegin (pLog->hFile,
  413. pLog->lIndexBlockOffset) ;
  414. WriteOK = FileWrite (pLog->hFile,
  415. (LPSTR) pLogIndexBlock,
  416. sizeof (LOGINDEXBLOCK)) ;
  417. if (WriteOK) {
  418. FileSeekBegin (pLog->hFile,
  419. lNextBlockOffset) ;
  420. // Fake file end until we really write the block
  421. pLogIndexBlock->iNumIndexes = 0 ;
  422. pLogIndexBlock->lNextBlockOffset = 0 ;
  423. WriteOK = FileWrite (pLog->hFile,
  424. (LPSTR) pLogIndexBlock,
  425. sizeof (LOGINDEXBLOCK)) ;
  426. if (WriteOK) {
  427. pLog->lIndexBlockOffset = lNextBlockOffset ;
  428. pLog->iIndex = 0 ;
  429. pLog->lFileSize += sizeof (LOGINDEXBLOCK) ;
  430. }
  431. }
  432. }
  433. //=============================//
  434. // Add Index Block Entry //
  435. //=============================//
  436. Index.uFlags = uFlags ;
  437. Index.SystemTime = *pSystemTime ;
  438. Index.lDataOffset = lDataOffset ;
  439. Index.iSystemsLogged = iSystemsLogged ;
  440. pLogIndexBlock->aIndexes [pLog->iIndex] = Index ;
  441. pLog->iIndex++ ;
  442. pLogIndexBlock->iNumIndexes++ ;
  443. // write out the index block if the log interval if too large
  444. if (pLog->iIntervalMSecs >= LARGE_INTERVAL * 1000 ) {
  445. LONG lCurPosition ;
  446. // save the current file position
  447. lCurPosition = FileTell (pLog->hFile) ;
  448. // flush the index block to the file
  449. LogWriteIndexBlock (pLog) ;
  450. // restore previous file position since
  451. // LogWriteIndexBlock has messed it up
  452. FileSeekBegin (pLog->hFile, lCurPosition) ;
  453. }
  454. return (WriteOK) ;
  455. }
  456. BOOL LogWritePerfData (HWND hWnd,
  457. PLOG pLog,
  458. PPERFDATA pPerfData,
  459. SYSTEMTIME *pSystemTime,
  460. DWORD iNumSystems,
  461. BOOL bWriteIndex)
  462. {
  463. LONG lSize ;
  464. BOOL WriteOK ;
  465. LONG lCurPosition ;
  466. lSize = pPerfData->TotalByteLength ;
  467. lCurPosition = FileTell (pLog->hFile) ;
  468. //=============================//
  469. // Write Perf Data //
  470. //=============================//
  471. WriteOK = FileWrite (pLog->hFile, (LPSTR) pPerfData, lSize) ;
  472. if (WriteOK) {
  473. pLog->lFileSize += lSize ;
  474. if (bWriteIndex) {
  475. WriteOK = LogWriteIndex (pLog,
  476. LogFileIndexData,
  477. pSystemTime,
  478. lCurPosition,
  479. iNumSystems) ;
  480. }
  481. }
  482. if ( !WriteOK ) {
  483. CloseLog (hWnd, pLog) ;
  484. PrepareMenu (GetMenu (hWndMain)) ;
  485. UpdateLogDisplay (hWnd) ;
  486. DlgErrorBox (hWnd, ERR_LOG_FILE, pLog->szFilePath) ;
  487. }
  488. return (WriteOK) ;
  489. }
  490. //==========================================================================//
  491. // Message Handlers //
  492. //==========================================================================//
  493. void static OnSize (HWND hDlg,
  494. int xWidth,
  495. int yHeight)
  496. /*
  497. Effect: Perform any actions necessary when the log window (dialog)
  498. is resized. In particular, move and resize some of the
  499. dialogs controls.
  500. Internals: The rightmost control, the log status, contains one of
  501. only several values. These values are all within
  502. xStatusWidth, computed at init time. Put this control
  503. one scroll width away from the right edge at fixed
  504. width. Move its associated text prompt with it. Then
  505. use the remaining space for the filename control, which
  506. can probably use it.
  507. To Do: Need to consider minimum first.
  508. */
  509. {
  510. int xStatusPos ;
  511. int xStatusTextPos ;
  512. int xNameWidth ;
  513. int xMinWidth ;
  514. //=============================//
  515. // Enough space for minimums? //
  516. //=============================//
  517. xMinWidth =
  518. xScrollWidth + // margin before prompt
  519. DialogWidth (hDlg, IDD_LOGFILETEXT) + // width of prompt
  520. xNameMinWidth + // width of name
  521. xScrollWidth +
  522. DialogWidth (hDlg, IDD_LOGSTATUSTEXT) +
  523. DialogWidth (hDlg, IDD_LOGSTATUS) +
  524. xScrollWidth ;
  525. xStatusPos = xWidth - xStatusWidth - xScrollWidth ;
  526. DialogMove (hDlg, IDD_LOGSTATUS,
  527. xStatusPos, NOCHANGE,
  528. xStatusWidth, NOCHANGE) ;
  529. xStatusTextPos = xStatusPos -
  530. DialogWidth (hDlg, IDD_LOGSTATUSTEXT) -
  531. xScrollWidth ;
  532. DialogMove (hDlg, IDD_LOGSTATUSTEXT,
  533. xStatusTextPos, NOCHANGE,
  534. NOCHANGE, NOCHANGE) ;
  535. xNameWidth = xStatusTextPos -
  536. DialogWidth (hDlg, IDD_LOGFILETEXT) -
  537. 2 * xScrollWidth ;
  538. DialogMove (hDlg, IDD_LOGFILE,
  539. NOCHANGE, NOCHANGE,
  540. xNameWidth, NOCHANGE) ;
  541. DialogMove (hDlg, IDD_LOGSIZE,
  542. DialogXPos (hDlg, IDD_LOGFILE), NOCHANGE,
  543. DialogWidth (hDlg, IDD_LOGFILE), NOCHANGE) ;
  544. DialogMove (hDlg, IDD_LOGINTERVALTEXT,
  545. DialogXPos (hDlg, IDD_LOGSTATUSTEXT), NOCHANGE,
  546. DialogWidth (hDlg, IDD_LOGSTATUSTEXT), NOCHANGE) ;
  547. DialogMove (hDlg, IDD_LOGINTERVAL,
  548. DialogXPos (hDlg, IDD_LOGSTATUS), NOCHANGE,
  549. DialogWidth (hDlg, IDD_LOGSTATUS), NOCHANGE) ;
  550. DialogMove (hDlg, IDD_LOGENTRIESTEXT,
  551. xScrollWidth, NOCHANGE, NOCHANGE, NOCHANGE) ;
  552. DialogMove (hDlg, IDD_LOGENTRIES,
  553. xScrollWidth, NOCHANGE,
  554. xWidth - 2 * xScrollWidth,
  555. yHeight - DialogYPos (hDlg, IDD_LOGENTRIES) - yScrollHeight) ;
  556. WindowInvalidate (hDlg) ;
  557. }
  558. INT_PTR
  559. OnCtlColor (
  560. HWND hDlg,
  561. HDC hDC
  562. )
  563. {
  564. SetTextColor (hDC, crBlack) ;
  565. // SetBkColor (hDC, crLightGray) ;
  566. // return ((int) hbLightGray) ;
  567. SetBkColor (hDC, ColorBtnFace) ;
  568. return ((INT_PTR) hBrushFace) ;
  569. }
  570. void static OnInitDialog (HWND hDlg)
  571. {
  572. HDC hDC ;
  573. PLOG pLog ;
  574. hWndLogEntries = DialogControl (hDlg, IDD_LOGENTRIES) ;
  575. pLog = AllocateLogData (hDlg) ;
  576. if (!pLog)
  577. return ;
  578. StringLoad (IDS_CLOSED, szClosed) ;
  579. // StringLoad (IDS_PAUSED, szPaused) ;
  580. StringLoad (IDS_COLLECTING, szCollecting) ;
  581. UpdateLogDisplay (hDlg) ;
  582. hDC = GetDC (hDlg) ;
  583. xStatusWidth = max (TextWidth (hDC, szClosed),
  584. TextWidth (hDC, szCollecting)) ;
  585. // max (TextWidth (hDC, szPaused),
  586. // TextWidth (hDC, szCollecting))) ;
  587. xStatusWidth += xScrollWidth ;
  588. xNameMinWidth = TextAvgWidth (hDC, LogNameMinLen) ;
  589. ReleaseDC (hDlg, hDC) ;
  590. }
  591. void static OnDestroy (HWND hWnd)
  592. /*
  593. Effect: Perform any actions necessary when a LogDisplay window
  594. is being destroyed. In particular, free the instance
  595. data for the log.
  596. Since we really only have one log window and one global
  597. log data structure, we don't free the structure. We do,
  598. however, delete the objects allocated within the structure.
  599. */
  600. {
  601. PLOG pLog ;
  602. pLog = LogData (hWnd) ;
  603. FreeLogData (pLog) ;
  604. }
  605. void static OnDrawItem (HWND hWnd, LPDRAWITEMSTRUCT lpDI)
  606. {
  607. HDC hDC ;
  608. RECT rectComputer, rectObject ;
  609. PLOGENTRY pLogEntry ;
  610. PLOG pLog ;
  611. COLORREF preBkColor = 0;
  612. COLORREF preTextColor = 0;
  613. pLog = LogData (hWnd) ;
  614. pLogEntry = LogEntryN (hWndLogEntries, DIIndex (lpDI)) ;
  615. // LogEntryN (SendMessage) will return LB_ERR for error, have to
  616. // check for that case
  617. if (!pLogEntry || pLogEntry == (PLOGENTRY)LB_ERR) {
  618. return ;
  619. }
  620. hDC = lpDI->hDC ;
  621. SelectFont (hDC, hFontScales) ;
  622. if (DISelected (lpDI)) {
  623. preTextColor = SetTextColor (hDC, GetSysColor (COLOR_HIGHLIGHTTEXT)) ;
  624. preBkColor = SetBkColor (hDC, GetSysColor (COLOR_HIGHLIGHT)) ;
  625. }
  626. rectObject.left = lpDI->rcItem.left ;
  627. rectObject.top = lpDI->rcItem.top ;
  628. rectObject.right = rectObject.left + pLog->xCol1Width ;
  629. rectObject.bottom = lpDI->rcItem.bottom ;
  630. ExtTextOut (hDC,
  631. rectObject.left + xScrollWidth, rectObject.top,
  632. ETO_OPAQUE,
  633. &rectObject,
  634. pLogEntry->szObject,
  635. lstrlen (pLogEntry->szObject),
  636. NULL) ;
  637. rectComputer.left = rectObject.right ;
  638. rectComputer.top = lpDI->rcItem.top ;
  639. rectComputer.right = lpDI->rcItem.right ;
  640. rectComputer.bottom = lpDI->rcItem.bottom ;
  641. ExtTextOut (hDC,
  642. rectComputer.left, rectComputer.top,
  643. ETO_OPAQUE,
  644. &rectComputer,
  645. pLogEntry->szComputer,
  646. lstrlen (pLogEntry->szComputer),
  647. NULL) ;
  648. if (DIFocus (lpDI))
  649. DrawFocusRect (hDC, &(lpDI->rcItem)) ;
  650. if (DISelected (lpDI)) {
  651. preTextColor = SetTextColor (hDC, preTextColor) ;
  652. preBkColor = SetBkColor (hDC, preBkColor) ;
  653. }
  654. // RestoreDC (hDC, -1) ;
  655. }
  656. //==========================================================================//
  657. // Exported Functions //
  658. //==========================================================================//
  659. INT_PTR
  660. APIENTRY
  661. LogDisplayDlgProc (
  662. HWND hDlg,
  663. UINT iMessage,
  664. WPARAM wParam,
  665. LPARAM lParam)
  666. /*
  667. Note: This function must be exported in the application's
  668. linker-definition file, perfmon.def.
  669. */
  670. {
  671. switch (iMessage) {
  672. case WM_INITDIALOG:
  673. OnInitDialog (hDlg) ;
  674. break ;
  675. case WM_CTLCOLORDLG:
  676. case WM_CTLCOLOREDIT:
  677. case WM_CTLCOLORBTN:
  678. case WM_CTLCOLORSTATIC:
  679. return (OnCtlColor (hDlg, (HDC) wParam)) ;
  680. break ;
  681. case WM_DRAWITEM:
  682. OnDrawItem (hDlg, (LPDRAWITEMSTRUCT) lParam) ;
  683. break ;
  684. case WM_LBUTTONDBLCLK:
  685. SendMessage (hWndMain, WM_LBUTTONDBLCLK, wParam, lParam) ;
  686. break ;
  687. case WM_LBUTTONDOWN:
  688. DoWindowDrag (hDlg, lParam) ;
  689. break ;
  690. case WM_SIZE:
  691. OnSize (hDlg, LOWORD (lParam), HIWORD (lParam)) ;
  692. break ;
  693. case WM_TIMER:
  694. LogTimer (hDlg, FALSE) ;
  695. break ;
  696. case WM_SETFOCUS:
  697. SetFocus (hWndLogEntries) ;
  698. break ;
  699. case WM_START_LOGGING:
  700. {
  701. PLOG pLog ;
  702. pLog = LogData (hDlg) ;
  703. if (StartLog (hDlg, pLog, FALSE)) {
  704. UpdateLogDisplay (hDlg) ;
  705. PrepareMenu (GetMenu (hWndMain)) ;
  706. }
  707. }
  708. break ;
  709. case WM_DESTROY:
  710. OnDestroy (hDlg) ;
  711. return (FALSE) ;
  712. break ;
  713. default:
  714. return (FALSE) ;
  715. }
  716. return (TRUE) ;
  717. }
  718. HWND CreateLogWindow (HWND hWndParent)
  719. /*
  720. Effect: Create the Log window. This window is a child of
  721. hWndMain.
  722. Note: We dont worry about the size here, as this window
  723. will be resized whenever the main window is resized.
  724. */
  725. {
  726. HWND hWnd ;
  727. hWnd = CreateDialog (hInstance,
  728. MAKEINTRESOURCE (idDlgLogDisplay),
  729. hWndParent,
  730. LogDisplayDlgProc) ;
  731. return (hWnd) ;
  732. }
  733. void UpdateLogDisplay (HWND hWnd)
  734. /*
  735. Effect: Set the values for the various controls in the log
  736. display.
  737. Called By: OnInitDialog, any other routines that change these
  738. values.
  739. */
  740. {
  741. PLOG pLog ;
  742. WCHAR szSize [MiscTextLen + 1] ;
  743. pLog = LogData (hWnd) ;
  744. DialogSetString (hWnd, IDD_LOGFILE, pLog->szFilePath) ;
  745. // position the cursor at the end of the text
  746. EditSetTextEndPos (hWnd, IDD_LOGFILE) ;
  747. DialogSetString (hWnd, IDD_LOGSTATUS, StatusText (pLog->iStatus)) ;
  748. LongToCommaString (pLog->lFileSize, szSize) ;
  749. DialogSetString (hWnd, IDD_LOGSIZE, szSize) ;
  750. DialogSetInterval (hWnd, IDD_LOGINTERVAL, pLog->iIntervalMSecs) ;
  751. }
  752. BOOL LogInitializeApplication (void)
  753. {
  754. return (TRUE) ;
  755. }
  756. void SetLogTimer (HWND hWnd,
  757. int iIntervalMSecs)
  758. {
  759. PLOG pLog ;
  760. pLog = LogData (hWnd) ;
  761. pLog->iIntervalMSecs = iIntervalMSecs ;
  762. KillTimer (hWnd, LogTimerID) ;
  763. SetTimer (hWnd, LogTimerID, pLog->iIntervalMSecs, NULL) ;
  764. }
  765. void ClearLogTimer (HWND hWnd)
  766. {
  767. KillTimer (hWnd, LogTimerID) ;
  768. }
  769. BOOL CloseLogStopTimer (HWND hWnd, PLOG pLog)
  770. {
  771. CloseHandle (pLog->hFile) ;
  772. pLog->hFile = 0 ;
  773. pLog->iStatus = iPMStatusClosed ;
  774. ClearLogTimer (hWnd) ;
  775. return (TRUE) ;
  776. }
  777. BOOL CloseLog (HWND hWnd, PLOG pLog)
  778. {
  779. LogWriteIndexBlock (pLog) ;
  780. CloseLogStopTimer (hWnd, pLog) ;
  781. WindowInvalidate (hWndStatus) ;
  782. return (TRUE) ;
  783. }
  784. BOOL StartLog (HWND hWnd, PLOG pLog, BOOL bSameFile)
  785. {
  786. int RetCode ;
  787. SYSTEMTIME SystemTime ;
  788. if ((RetCode = CreateLogFile (pLog, TRUE, bSameFile)) == 0) {
  789. pLog->iStatus = iPMStatusCollecting ;
  790. GetLocalTime (&SystemTime) ;
  791. // write a dummy record.
  792. // this is needed because when playingback log
  793. // it will skip the first index from the first
  794. // index block.
  795. LogWriteIndex (pLog, 0, &SystemTime, 0, 0) ;
  796. if (!PlayingBackLog()) {
  797. // write out a bookmark to indicate start of new data
  798. if (!LogWriteStartBookmark (hWnd, &SystemTime)) {
  799. RetCode = 0 ;
  800. goto ErrorExit ;
  801. }
  802. if (!(pLog->bManualRefresh)) {
  803. SetLogTimer (hWnd, pLog->iIntervalMSecs) ;
  804. WindowInvalidate (hWndStatus) ;
  805. }
  806. } else {
  807. // check if time if OK
  808. LOGPOSITION LP ;
  809. SYSTEMTIME FirstSystemTime ;
  810. int TimeDiff ;
  811. LP = PlaybackLog.StartIndexPos ;
  812. if (LogPositionSystemTime (&LP, &FirstSystemTime)) {
  813. // we don't want to append data to the log file if
  814. // the time is not in order. So, forget it if the
  815. // last log time in the Log file is greater than the First
  816. // log time of the playback log file.
  817. TimeDiff = SystemTimeDifference (&(pLog->LastLogTime),
  818. &(FirstSystemTime), FALSE) ;
  819. if (TimeDiff < 0) {
  820. // error , time not in order
  821. CloseHandle (pLog->hFile) ;
  822. RetCode = ERR_CANT_RELOG_DATA ;
  823. }
  824. }
  825. }
  826. if (RetCode == 0) {
  827. // write counter names if needed
  828. LogWriteSystemCounterNames (hWnd, pLog) ;
  829. return (TRUE) ;
  830. }
  831. }
  832. ErrorExit:
  833. pLog->hFile = 0 ;
  834. CloseLogStopTimer(hWnd, pLog);
  835. PrepareMenu (GetMenu (hWndMain)) ;
  836. UpdateLogDisplay (hWnd) ;
  837. if (RetCode) {
  838. DlgErrorBox (hWnd, RetCode, pLog->szFilePath);
  839. }
  840. return (FALSE) ;
  841. }
  842. DWORD LogFindEntry(LPTSTR lpszComputer, DWORD ObjectTitleIndex)
  843. /*
  844. Effect: Returns the index of the specified Computer/Object
  845. if it already exists in the Entries List Box,
  846. otherwise returns LOG_ENTRY_NOT_FOUND
  847. */
  848. {
  849. DWORD iLogEntry ;
  850. DWORD iLogNum ;
  851. PLOGENTRY pLogEntry ;
  852. iLogNum = (DWORD) LBNumItems(hWndLogEntries) ;
  853. for (iLogEntry = 0;
  854. iLogEntry < iLogNum ;
  855. iLogEntry++) {
  856. pLogEntry = (PLOGENTRY) LBData(hWndLogEntries, iLogEntry) ;
  857. if (pLogEntry->ObjectTitleIndex == ObjectTitleIndex &&
  858. strsamei(pLogEntry->szComputer, lpszComputer)) {
  859. return iLogEntry ;
  860. }
  861. }
  862. return (DWORD) LOG_ENTRY_NOT_FOUND;
  863. }
  864. BOOL LogAddEntry (HWND hWndLog,
  865. LPTSTR lpszComputer,
  866. LPTSTR lpszObject,
  867. DWORD ObjectTitleIndex,
  868. BOOL bGetObjectTitleIndex)
  869. /*
  870. Effect: Add an entry in the log structure for the computer and
  871. object to be logged.
  872. Returns: Whether the operation could be performed.
  873. */
  874. {
  875. PLOG pLog ;
  876. PLOGENTRY pLogEntry ;
  877. SIZE_T iIndex ;
  878. PPERFSYSTEM pCurrentSystem = NULL ;
  879. DWORD CurrentObjectTitleIndex ;
  880. pLog = LogData (hWndLog) ;
  881. pCurrentSystem = SystemAdd (&(pLog->pSystemFirst), lpszComputer, hWndLog) ;
  882. pLogEntry = MemoryAllocate (sizeof (LOGENTRY)) ;
  883. if (!pLogEntry)
  884. return (FALSE) ;
  885. lstrcpy (pLogEntry->szComputer, lpszComputer) ;
  886. lstrcpy (pLogEntry->szObject, lpszObject) ;
  887. pLogEntry->ObjectTitleIndex = ObjectTitleIndex ;
  888. // if reading from a log setting file, get the
  889. // latest Object index by the perfdata itself.
  890. // There may be case that the id has been changed
  891. if (bGetObjectTitleIndex &&
  892. pCurrentSystem &&
  893. pCurrentSystem->pSystemPerfData) {
  894. if (pCurrentSystem->pSystemPerfData->Signature[0] == TEXT('\0')) {
  895. UpdateSystemData (
  896. pCurrentSystem,
  897. &(pCurrentSystem->pSystemPerfData)) ;
  898. }
  899. if (CurrentObjectTitleIndex = GetObjectIdByName(
  900. pCurrentSystem,
  901. pCurrentSystem->pSystemPerfData,
  902. lpszObject)) {
  903. pLogEntry->ObjectTitleIndex = CurrentObjectTitleIndex ;
  904. }
  905. }
  906. iIndex = LBAdd (hWndLogEntries, pLogEntry) ;
  907. if (!bDelayAddAction) {
  908. if (iIndex == LB_ERR) {
  909. iIndex = 0 ;
  910. }
  911. LBSetSelection (hWndLogEntries, iIndex) ;
  912. LBSetVisible (hWndLogEntries, iIndex) ;
  913. LogEntriesChanged (hWndLogEntries) ;
  914. }
  915. LogAddEntryToList (&(pLog->pLogEntryFirst), pLogEntry) ;
  916. return TRUE;
  917. }
  918. BOOL ToggleLogRefresh (HWND hWnd)
  919. {
  920. PLOG pLog ;
  921. pLog = LogData (hWnd) ;
  922. if (pLog->bManualRefresh)
  923. SetLogTimer (hWnd, pLog->iIntervalMSecs) ;
  924. else
  925. ClearLogTimer (hWnd) ;
  926. pLog->bManualRefresh = !pLog->bManualRefresh ;
  927. return (pLog->bManualRefresh) ;
  928. }
  929. BOOL LogRefresh (HWND hWnd)
  930. {
  931. PLOG pLog ;
  932. pLog = LogData (hWnd) ;
  933. return (pLog->bManualRefresh) ;
  934. }
  935. BOOL CheckUnusedSystem (LPTSTR lpszComputer)
  936. {
  937. BOOL bStillUse = FALSE ;
  938. PLOGENTRY pLogEntry ;
  939. PLOG pLog ;
  940. pLog = LogData (hWndLog) ;
  941. for (pLogEntry = pLog->pLogEntryFirst; pLogEntry; pLogEntry = pLogEntry->pNextLogEntry)
  942. {
  943. if (strsamei(pLogEntry->szComputer, lpszComputer)) {
  944. bStillUse = TRUE ;
  945. break ;
  946. }
  947. }
  948. return (bStillUse) ;
  949. }
  950. int SelectLogObjects(LPTSTR lpszComputer,
  951. PPERFDATA pPerfData,
  952. PPERFDATA *ppLogData)
  953. /*
  954. Effect: This routine copies the header from pPerfData
  955. to pLogData and initializes the byte length and the
  956. number of objects. It then copies the previously
  957. selected objects from pPerfData to pLogData. If
  958. pLogData must be enlarged to accomodate the new data,
  959. this routine will enlarge it.
  960. Returns: An updated pLogData, and TRUE if at least one object
  961. was copied.
  962. */
  963. {
  964. PLOGENTRY pLogEntry ;
  965. PPERFOBJECT pObject ;
  966. DWORD TotalBytes ;
  967. DWORD NumObjects ;
  968. PBYTE pNextObject ;
  969. DWORD MaxLogDataSize ;
  970. PLOG pLog ;
  971. if (!*ppLogData || !pPerfData)
  972. return -1 ;
  973. memcpy ((LPVOID)*ppLogData, (LPVOID)pPerfData, pPerfData->HeaderLength) ;
  974. TotalBytes = pPerfData->HeaderLength ;
  975. MaxLogDataSize = MemorySize((LPMEMORY)*ppLogData) ;
  976. NumObjects = 0;
  977. pLog = LogData (hWndLog) ;
  978. for (pLogEntry = pLog->pLogEntryFirst ;
  979. pLogEntry ;
  980. pLogEntry = pLogEntry->pNextLogEntry)
  981. {
  982. if (strsamei(pLogEntry->szComputer, lpszComputer)) {
  983. pObject = GetObjectDefByTitleIndex(pPerfData,
  984. pLogEntry->ObjectTitleIndex) ;
  985. if (pObject) {
  986. if (MaxLogDataSize < TotalBytes + pObject->TotalByteLength) {
  987. *ppLogData = MemoryResize((LPMEMORY)*ppLogData,
  988. TotalBytes + pObject->TotalByteLength) ;
  989. if (!*ppLogData)
  990. return -1 ;
  991. }
  992. pNextObject = (PBYTE) *ppLogData + TotalBytes ;
  993. memcpy ((LPVOID)pNextObject, (LPVOID)pObject, pObject->TotalByteLength);
  994. TotalBytes += pObject->TotalByteLength ;
  995. NumObjects++;
  996. } else {
  997. }
  998. }
  999. }
  1000. if (!NumObjects)
  1001. return 1 ;
  1002. (*ppLogData)->TotalByteLength = TotalBytes ;
  1003. (*ppLogData)->NumObjectTypes = NumObjects ;
  1004. return 0 ;
  1005. }
  1006. void LogTimer (HWND hWnd, BOOL bForce)
  1007. /*
  1008. Effect: Perform all actions necessary when the log window
  1009. receives a timer tic. In particular, if we are
  1010. collecting data, get a new perf_data_block and add a
  1011. header entry. If the header block is full, write the
  1012. data to disk.
  1013. Called By: LogDisplayDlgProc, in response to a WM_TIMER message.
  1014. */
  1015. {
  1016. PLOG pLog ;
  1017. PPERFSYSTEM pSystem ;
  1018. BOOL bWriteIndex ;
  1019. DWORD iNumSystems ;
  1020. SYSTEMTIME SystemTime ;
  1021. int iNoUseSystemDetected = 0 ;
  1022. int NumberOfSystems = 0 ;
  1023. DWORD WaitStatus ;
  1024. BOOL bNeedToStoreName = FALSE ;
  1025. HANDLE *lpPacketHandles ;
  1026. pLog = LogData (hWnd) ;
  1027. if (pLog->iStatus != iPMStatusCollecting)
  1028. return ;
  1029. if (bForce || !pLog->bManualRefresh) {
  1030. if (pLog->NumberOfHandles == 0) {
  1031. pLog->NumberOfHandles = MAXIMUM_WAIT_OBJECTS ;
  1032. pLog->lpHandles = (HANDLE *) MemoryAllocate (pLog->NumberOfHandles * sizeof (HANDLE)) ;
  1033. if (!pLog->lpHandles) {
  1034. // out of memory, can't go on
  1035. pLog->NumberOfHandles = 0 ;
  1036. return ;
  1037. }
  1038. }
  1039. iNumSystems = SystemCount(pLog->pSystemFirst) ;
  1040. bWriteIndex = TRUE ;
  1041. for (pSystem = pLog->pSystemFirst; pSystem; pSystem = pSystem->pSystemNext) {
  1042. if (pSystem->hStateDataMutex == 0)
  1043. continue ;
  1044. // lock the state data mutex
  1045. WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L);
  1046. if (WaitStatus == WAIT_OBJECT_0) {
  1047. ResetEvent (pSystem->hPerfDataEvent) ;
  1048. pSystem->StateData = WAIT_FOR_PERF_DATA ;
  1049. if (NumberOfSystems >= pLog->NumberOfHandles) {
  1050. pLog->NumberOfHandles += MAXIMUM_WAIT_OBJECTS ;
  1051. pLog->lpHandles = (HANDLE *) MemoryResize (
  1052. pLog->lpHandles,
  1053. pLog->NumberOfHandles * sizeof (HANDLE)) ;
  1054. if (!pLog->lpHandles) {
  1055. // out of memory, can't go on
  1056. pLog->NumberOfHandles = 0 ;
  1057. return ;
  1058. }
  1059. }
  1060. // add this to the wait
  1061. pLog->lpHandles [NumberOfSystems] = pSystem->hPerfDataEvent ;
  1062. NumberOfSystems++ ;
  1063. }
  1064. // Send Message to thread to take a data sample
  1065. PostThreadMessage (
  1066. pSystem->dwThreadID,
  1067. WM_GET_PERF_DATA,
  1068. (WPARAM)0,
  1069. (LPARAM)0) ;
  1070. ReleaseMutex(pSystem->hStateDataMutex);
  1071. }
  1072. Sleep (50);
  1073. // wait for all the data
  1074. if (NumberOfSystems) {
  1075. // increase timeout if we are monitoring lots of systems
  1076. // For every additional 5 systems, add five more seconds
  1077. lpPacketHandles = pLog->lpHandles ;
  1078. do {
  1079. WaitStatus = WaitForMultipleObjects (
  1080. min (NumberOfSystems, MAXIMUM_WAIT_OBJECTS),
  1081. lpPacketHandles,
  1082. TRUE, // wait for all objects
  1083. DataTimeOut + (NumberOfSystems / 5) * DEFAULT_DATA_TIMEOUT);
  1084. if (WaitStatus == WAIT_TIMEOUT ||
  1085. NumberOfSystems <= MAXIMUM_WAIT_OBJECTS) {
  1086. //if (WaitStatus == WAIT_TIMEOUT)
  1087. //mike2(TEXT("WaitTimeOut for %ld systems\n"), NumberOfSystems) ;
  1088. break ;
  1089. }
  1090. // more systems --> more to wait
  1091. NumberOfSystems -= MAXIMUM_WAIT_OBJECTS ;
  1092. lpPacketHandles += MAXIMUM_WAIT_OBJECTS ;
  1093. } while (TRUE) ;
  1094. for (pSystem = pLog->pSystemFirst ;
  1095. pSystem ;
  1096. pSystem = pSystem->pSystemNext)
  1097. {
  1098. if (pSystem->hStateDataMutex == 0)
  1099. continue ;
  1100. // lock the state data mutex
  1101. WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L);
  1102. if (WaitStatus == WAIT_OBJECT_0) {
  1103. // check for system disconnect/reconnect
  1104. if (pSystem->dwSystemState == SYSTEM_DOWN ||
  1105. pSystem->dwSystemState == SYSTEM_RECONNECT) {
  1106. BOOL bDisconnected ;
  1107. GetLocalTime (&SystemTime) ;
  1108. if (bDisconnected = (pSystem->dwSystemState == SYSTEM_DOWN)) {
  1109. pSystem->dwSystemState = SYSTEM_DOWN_RPT ;
  1110. } else {
  1111. pSystem->dwSystemState = SYSTEM_RECONNECT_RPT ;
  1112. }
  1113. if (!LogWriteSystemBookmark (
  1114. hWnd,
  1115. pSystem->sysName,
  1116. bDisconnected,
  1117. &SystemTime)) {
  1118. pSystem->StateData = IDLE_STATE ;
  1119. ReleaseMutex(pSystem->hStateDataMutex);
  1120. return ;
  1121. }
  1122. }
  1123. if (pSystem->StateData == PERF_DATA_READY) {
  1124. if (pSystem->bSystemCounterNameSaved == FALSE) {
  1125. // we have not written the system name to log file. This
  1126. // is the case when this system is down when we first
  1127. // start logging data...
  1128. bNeedToStoreName = TRUE ;
  1129. }
  1130. if (bWriteIndex) {
  1131. GetLocalTime (&SystemTime) ;
  1132. }
  1133. if (SelectLogObjects(pSystem->sysName,
  1134. pSystem->pSystemPerfData,
  1135. &pLog->pLogData) == 0) {
  1136. if ( !LogWritePerfData (hWnd, pLog, pLog->pLogData, &SystemTime,
  1137. iNumSystems, bWriteIndex) ) {
  1138. CloseLogStopTimer(hWnd, pLog) ;
  1139. pSystem->StateData = IDLE_STATE ;
  1140. ReleaseMutex(pSystem->hStateDataMutex);
  1141. return ;
  1142. }
  1143. // write an index for only the first system
  1144. bWriteIndex = FALSE ;
  1145. } else {
  1146. if (!bAddLineInProgress) {
  1147. pSystem->bSystemNoLongerNeeded = TRUE ;
  1148. iNoUseSystemDetected ++ ;
  1149. }
  1150. }
  1151. } // if PERF_DATA_READY
  1152. else if (!bAddLineInProgress &&
  1153. CheckUnusedSystem (pSystem->sysName) == FALSE) {
  1154. // we don't need this system any more
  1155. pSystem->bSystemNoLongerNeeded = TRUE ;
  1156. iNoUseSystemDetected ++ ;
  1157. }
  1158. pSystem->StateData = IDLE_STATE ;
  1159. ReleaseMutex(pSystem->hStateDataMutex);
  1160. } // wait for StateDataMutex
  1161. } // For each system
  1162. } // if NumberOfSystems
  1163. if (!bWriteIndex) {
  1164. UpdateLogSize (hWnd) ;
  1165. }
  1166. }
  1167. if (iNoUseSystemDetected) {
  1168. DeleteUnusedSystems (&(pLog->pSystemFirst), iNoUseSystemDetected) ;
  1169. }
  1170. if (bNeedToStoreName == TRUE) {
  1171. LogWriteSystemCounterNames (hWnd, pLog) ;
  1172. }
  1173. }
  1174. BOOL NextIntervalIndexPosition (PLOG pLog, PLOGPOSITION pLP, int *pNumTics)
  1175. {
  1176. SYSTEMTIME SystemTime1 ;
  1177. SYSTEMTIME SystemTime2 ;
  1178. LOGPOSITION LP ;
  1179. PLOGINDEX pIndex ;
  1180. DWORD TimeDiff ;
  1181. LogPositionSystemTime (pLP, &SystemTime1) ;
  1182. LP = *pLP ;
  1183. while (NextReLogIndexPosition (&LP)) {
  1184. *pNumTics = *pNumTics - 1 ;
  1185. pIndex = IndexFromPosition (&LP) ;
  1186. if (pIndex && IsBookmarkIndex (pIndex)) {
  1187. *pLP = LP ;
  1188. return TRUE ;
  1189. }
  1190. LogPositionSystemTime (&LP, &SystemTime2) ;
  1191. TimeDiff = (DWORD) SystemTimeDifference (&SystemTime1,
  1192. &SystemTime2, TRUE) ;
  1193. if (TimeDiff * 1000 >= pLog->iIntervalMSecs) {
  1194. *pLP = LP ;
  1195. return (TRUE) ;
  1196. }
  1197. }
  1198. return (FALSE) ;
  1199. }
  1200. BOOL ReLogTimer (HWND hWnd,
  1201. PLOG pLog,
  1202. LOGPOSITION lp,
  1203. BOOL *pWriteBookmark)
  1204. {
  1205. PPERFSYSTEM pSystem ;
  1206. BOOL bWriteIndex ;
  1207. DWORD iNumSystems ;
  1208. SYSTEMTIME SystemTime ;
  1209. PPERFDATA pPerfData ;
  1210. bWriteIndex = TRUE ;
  1211. // First count number of systems to be logged
  1212. iNumSystems = 0;
  1213. for (pSystem = pLog->pSystemFirst; pSystem; pSystem = pSystem->pSystemNext) {
  1214. pPerfData = LogDataFromPosition (pSystem, &lp) ;
  1215. if (pPerfData) {
  1216. if (SelectLogObjects(pSystem->sysName,
  1217. pPerfData,
  1218. &pLog->pLogData) == 0) {
  1219. iNumSystems++;
  1220. }
  1221. }
  1222. }
  1223. // Now we can log the data
  1224. for (pSystem = pLog->pSystemFirst ;
  1225. pSystem ;
  1226. pSystem = pSystem->pSystemNext) { // for
  1227. pPerfData = LogDataFromPosition (pSystem, &lp) ;
  1228. if (pPerfData) {
  1229. // write an index for only the first system
  1230. LogPositionSystemTime (&lp, &SystemTime) ;
  1231. if (SelectLogObjects(pSystem->sysName,
  1232. pPerfData,
  1233. &pLog->pLogData) == 0) {
  1234. if (*pWriteBookmark) {
  1235. // only need to write the start bookmark once.
  1236. *pWriteBookmark = FALSE ;
  1237. LogWriteStartBookmark (hWnd, &SystemTime) ;
  1238. }
  1239. if ( !LogWritePerfData (hWnd, pLog, pLog->pLogData, &SystemTime,
  1240. iNumSystems, bWriteIndex) ) {
  1241. CloseLogStopTimer(hWnd, pLog) ;
  1242. return FALSE ;
  1243. } else {
  1244. // write the index for only the first system logged
  1245. bWriteIndex = FALSE ;
  1246. }
  1247. }
  1248. }
  1249. }
  1250. return TRUE ;
  1251. }
  1252. void ReLog (HWND hWndLog, BOOL bSameFile)
  1253. {
  1254. PLOG pLog ;
  1255. LOGPOSITION lp ;
  1256. // SYSTEMTIME SystemTime ;
  1257. PLOGINDEX pIndex ;
  1258. PBOOKMARK pBookmark;
  1259. int iDisplayTics ;
  1260. // bWriteBookmark tell relogtimer to write start bookmark
  1261. BOOL bWriteBookmark = TRUE ;
  1262. pLog = LogData (hWndLog) ;
  1263. if (StartLog (hWndLog, pLog, bSameFile) == FALSE) {
  1264. return ;
  1265. }
  1266. lp = PlaybackLog.StartIndexPos ;
  1267. iDisplayTics = PlaybackLog.iSelectedTics;
  1268. while (iDisplayTics > 0) {
  1269. pIndex = IndexFromPosition (&lp) ;
  1270. if (pIndex) {
  1271. if (IsBookmarkIndex (pIndex)) {
  1272. pBookmark = (PBOOKMARK) PlaybackSeek (pIndex->lDataOffset) ;
  1273. if (!LogWriteBookmarkData (hWndLog, pBookmark))
  1274. break;
  1275. } else if (!ReLogTimer (hWndLog, pLog, lp, &bWriteBookmark))
  1276. break ;
  1277. }
  1278. if (!NextIntervalIndexPosition (pLog, &lp, &iDisplayTics))
  1279. break ;
  1280. }
  1281. UpdateLogSize (hWndLog) ;
  1282. CloseLog (hWndLog, pLog) ;
  1283. }
  1284. // SaveLog is diff than other because we are not saving a "Line"
  1285. // We are actually saving an entry in the hWndLogEntries listbox.
  1286. // It only contains the system & object name.
  1287. BOOL SaveLog (HWND hWndLog, HANDLE hInputFile, BOOL bGetFileName)
  1288. {
  1289. int iIndex, iIndexNum ;
  1290. PLOG pLog ;
  1291. PLOGENTRY pLogEntry ;
  1292. LOGENTRY tempLogEntry ;
  1293. HANDLE hFile ;
  1294. DISKLOG DiskLog ;
  1295. PERFFILEHEADER FileHeader ;
  1296. TCHAR szFileName [256] ;
  1297. BOOL newFileName = FALSE ;
  1298. pLog = LogData (hWndLog) ;
  1299. if (!pLog) {
  1300. return (FALSE) ;
  1301. }
  1302. if (hInputFile) {
  1303. // use the input file handle if it is available
  1304. // this is the case for saving workspace data
  1305. hFile = hInputFile ;
  1306. } else {
  1307. if (pLogFullFileName) {
  1308. lstrcpy (szFileName, pLogFullFileName) ;
  1309. }
  1310. if (bGetFileName || pLogFullFileName == NULL) {
  1311. // if (pLogFullFileName == NULL)
  1312. // {
  1313. // StringLoad (IDS_LOG_FNAME, szFileName) ;
  1314. // }
  1315. if (!FileGetName (hWndLog, IDS_LOGFILE, szFileName)) {
  1316. return (FALSE) ;
  1317. }
  1318. newFileName = TRUE ;
  1319. }
  1320. hFile = FileHandleCreate (szFileName) ;
  1321. if (hFile && hFile != INVALID_HANDLE_VALUE && newFileName) {
  1322. ChangeSaveFileName (szFileName, IDM_VIEWLOG) ;
  1323. } else if (!hFile) {
  1324. DlgErrorBox (hWndLog, ERR_CANT_OPEN, szFileName) ;
  1325. }
  1326. }
  1327. if (!hFile || hFile == INVALID_HANDLE_VALUE)
  1328. return (FALSE) ;
  1329. iIndexNum = LBNumItems (hWndLogEntries) ;
  1330. if (!hInputFile) {
  1331. memset (&FileHeader, 0, sizeof (FileHeader)) ;
  1332. lstrcpy (FileHeader.szSignature, szPerfLogSignature) ;
  1333. FileHeader.dwMajorVersion = LogMajorVersion ;
  1334. FileHeader.dwMinorVersion = LogMinorVersion ;
  1335. if (!FileWrite (hFile, &FileHeader, sizeof (PERFFILEHEADER))) {
  1336. goto Exit0 ;
  1337. }
  1338. }
  1339. DiskLog.dwIntervalSecs = pLog->iIntervalMSecs ;
  1340. DiskLog.dwNumLines = iIndexNum ;
  1341. DiskLog.bManualRefresh = pLog->bManualRefresh ;
  1342. DiskLog.perfmonOptions = Options ;
  1343. lstrcpy(DiskLog.LogFileName, pLog->szFilePath) ;
  1344. if (!FileWrite (hFile, &DiskLog, sizeof (DISKLOG))) {
  1345. goto Exit0 ;
  1346. }
  1347. for (iIndex = 0; iIndex < iIndexNum; iIndex++) {
  1348. pLogEntry = LogEntryN (hWndLogEntries, iIndex) ;
  1349. if (pstrsamei (pLogEntry->szComputer, LocalComputerName)) {
  1350. tempLogEntry = *pLogEntry ;
  1351. lstrcpy (tempLogEntry.szComputer, LOCAL_SYS_CODE_NAME) ;
  1352. if (!FileWrite (hFile,
  1353. &tempLogEntry,
  1354. sizeof(LOGENTRY)-sizeof(pLogEntry->pNextLogEntry))) {
  1355. goto Exit0 ;
  1356. }
  1357. } else {
  1358. if (!FileWrite (hFile,
  1359. pLogEntry,
  1360. sizeof(LOGENTRY)-sizeof(pLogEntry->pNextLogEntry))) {
  1361. goto Exit0 ;
  1362. }
  1363. }
  1364. }
  1365. if (!hInputFile) {
  1366. CloseHandle (hFile) ;
  1367. }
  1368. return (TRUE) ;
  1369. Exit0:
  1370. if (!hInputFile) {
  1371. CloseHandle (hFile) ;
  1372. // only need to report error if not workspace
  1373. DlgErrorBox (hWndLog, ERR_SETTING_FILE, szFileName) ;
  1374. }
  1375. return (FALSE) ;
  1376. }
  1377. BOOL OpenLogVer1 (HWND hWndLog, HANDLE hFile, DISKLOG *pDiskLog, PLOG
  1378. pLog, DWORD dwMinorVersion)
  1379. {
  1380. int iIndex, iIndexNum ;
  1381. PLOGENTRY pLogEntry ;
  1382. LOGENTRY LogEntry ;
  1383. PPERFSYSTEM pSystem;
  1384. pLog->iIntervalMSecs = pDiskLog->dwIntervalSecs ;
  1385. if (dwMinorVersion < 3) {
  1386. pLog->iIntervalMSecs *= 1000 ;
  1387. }
  1388. pLog->lFileSize = 0L ;
  1389. if (dwMinorVersion >= 5) {
  1390. lstrcpy (pLog->szFilePath, pDiskLog->LogFileName) ;
  1391. } else {
  1392. strclr (pLog->szFilePath) ;
  1393. // fixed the file pointer for backward compatible with older version.
  1394. // FileSeekCurrent (hFile, -((int) (sizeof (pDiskLog->LogFileName)))) ;
  1395. }
  1396. pLog->bManualRefresh = pDiskLog->bManualRefresh ;
  1397. iIndexNum = pDiskLog->dwNumLines ;
  1398. LBSetRedraw (hWndLogEntries, FALSE) ;
  1399. bDelayAddAction = TRUE ;
  1400. for (iIndex = 0 ; iIndex < iIndexNum ; iIndex++) {
  1401. if (!FileRead (hFile,
  1402. &LogEntry,
  1403. sizeof(LOGENTRY)-sizeof(LogEntry.pNextLogEntry))) {
  1404. break ;
  1405. }
  1406. if (pstrsame (LogEntry.szComputer, LOCAL_SYS_CODE_NAME)) {
  1407. // convert it back to the local name
  1408. lstrcpy (LogEntry.szComputer, LocalComputerName) ;
  1409. }
  1410. LogAddEntry (hWndLog,
  1411. LogEntry.szComputer,
  1412. LogEntry.szObject,
  1413. LogEntry.ObjectTitleIndex,
  1414. TRUE) ;
  1415. }
  1416. bDelayAddAction = FALSE ;
  1417. LBSetSelection (hWndLogEntries, 0) ;
  1418. LBSetVisible (hWndLogEntries, 0) ;
  1419. LogEntriesChanged (hWndLogEntries) ;
  1420. LBSetRedraw (hWndLogEntries, TRUE) ;
  1421. for (pSystem = pLog->pSystemFirst ;
  1422. pSystem ;
  1423. pSystem = pSystem->pSystemNext) {
  1424. if (pSystem) {
  1425. RemoveObjectsFromSystem (pSystem);
  1426. }
  1427. }
  1428. for (iIndex = 0 ;
  1429. iIndex < iIndexNum ;
  1430. iIndex++)
  1431. {
  1432. pLogEntry = LogEntryN (hWndLogEntries, iIndex) ;
  1433. pSystem = SystemGet (pLog->pSystemFirst, pLogEntry->szComputer);
  1434. if (pSystem) {
  1435. AppendObjectToValueList (
  1436. pLogEntry->ObjectTitleIndex,
  1437. pSystem->lpszValue);
  1438. }
  1439. }
  1440. if (!strempty(pLog->szFilePath)) {
  1441. if (pLog->pLogEntryFirst &&
  1442. pLog->pSystemFirst) {
  1443. // PostMessage so it will start logging
  1444. PostMessage (
  1445. hWndLog,
  1446. WM_START_LOGGING,
  1447. 0,
  1448. 0) ;
  1449. } else {
  1450. HANDLE hLogFile ;
  1451. // get the file size.
  1452. hLogFile = FileHandleOpen (pLog->szFilePath) ;
  1453. if (hLogFile && hLogFile != INVALID_HANDLE_VALUE) {
  1454. pLog->lFileSize = GetFileSize (hLogFile, NULL);
  1455. CloseHandle (hLogFile) ;
  1456. }
  1457. }
  1458. }
  1459. return (TRUE) ;
  1460. }
  1461. BOOL OpenLog (HWND hWndLog,
  1462. HANDLE hFile,
  1463. DWORD dwMajorVersion,
  1464. DWORD dwMinorVersion,
  1465. BOOL bLogFile)
  1466. {
  1467. PLOG pLog ;
  1468. DISKLOG DiskLog ;
  1469. BOOL bSuccess = TRUE ;
  1470. pLog = LogData (hWndLog) ;
  1471. if (!pLog) {
  1472. bSuccess = FALSE ;
  1473. goto Exit0 ;
  1474. }
  1475. if (!FileRead (hFile, &DiskLog, sizeof (DISKLOG) - sizeof(DiskLog.LogFileName))) {
  1476. bSuccess = FALSE ;
  1477. goto Exit0 ;
  1478. }
  1479. if (dwMajorVersion == 1 && dwMinorVersion >= 5 ||
  1480. dwMajorVersion > 1) {
  1481. // read LogFileName
  1482. if (!FileRead (hFile, DiskLog.LogFileName, sizeof (DiskLog.LogFileName))) {
  1483. bSuccess = FALSE ;
  1484. goto Exit0 ;
  1485. }
  1486. }
  1487. switch (dwMajorVersion) {
  1488. case (1):
  1489. SetHourglassCursor() ;
  1490. ResetLogView (hWndLog) ;
  1491. OpenLogVer1 (hWndLog, hFile, &DiskLog, pLog, dwMinorVersion) ;
  1492. // change to log view if we are opening a
  1493. // log file
  1494. if (bLogFile && iPerfmonView != IDM_VIEWLOG) {
  1495. SendMessage (hWndMain, WM_COMMAND, (LONG)IDM_VIEWLOG, 0L) ;
  1496. }
  1497. if (iPerfmonView == IDM_VIEWLOG) {
  1498. SetPerfmonOptions (&DiskLog.perfmonOptions) ;
  1499. }
  1500. UpdateLogDisplay (hWndLog) ;
  1501. SetArrowCursor() ;
  1502. break ;
  1503. }
  1504. Exit0:
  1505. if (bLogFile) {
  1506. CloseHandle (hFile) ;
  1507. }
  1508. return (bSuccess) ;
  1509. }
  1510. BOOL LogCollecting (HWND hWndLog)
  1511. /*
  1512. Effect: Return whether the log associated with hWndLog is currently
  1513. collecting data (writing performance values to disk).
  1514. */
  1515. {
  1516. PLOG pLog ;
  1517. pLog = LogData (hWndLog) ;
  1518. return (pLog->iStatus == iPMStatusCollecting) ;
  1519. }
  1520. int LogFileSize (HWND hWndLog)
  1521. {
  1522. PLOG pLog ;
  1523. pLog = LogData (hWndLog) ;
  1524. return (pLog->lFileSize) ;
  1525. }
  1526. BOOL LogWriteSystemBookmark (
  1527. HWND hWnd,
  1528. LPTSTR lpSystemName,
  1529. BOOL bDisconnected,
  1530. SYSTEMTIME *pSystemTime)
  1531. {
  1532. BOOKMARK Bookmark ;
  1533. TCHAR NewSystemBookmark [MiscTextLen * 2] ;
  1534. memset (&Bookmark, 0, sizeof (BOOKMARK)) ;
  1535. NewSystemBookmark [0] = TEXT('\0') ;
  1536. StringLoad (
  1537. bDisconnected ?
  1538. IDS_SYSTEM_DOWN :
  1539. IDS_SYSTEM_UP,
  1540. NewSystemBookmark) ;
  1541. lstrcat (NewSystemBookmark, TEXT(" - ")) ;
  1542. lstrcat (NewSystemBookmark, lpSystemName) ;
  1543. Bookmark.SystemTime = *pSystemTime ;
  1544. lstrcpy (Bookmark.szComment, NewSystemBookmark) ;
  1545. return (LogWriteBookmarkData (hWndLog, &Bookmark)) ;
  1546. }
  1547. BOOL LogWriteStartBookmark (HWND hWnd, SYSTEMTIME *pSystemTime)
  1548. {
  1549. BOOKMARK Bookmark ;
  1550. TCHAR NewDataBookmark [MiscTextLen] ;
  1551. memset (&Bookmark, 0, sizeof (BOOKMARK)) ;
  1552. NewDataBookmark [0] = TEXT('\0') ;
  1553. StringLoad (IDS_NEWDATA_BOOKMARK, NewDataBookmark) ;
  1554. Bookmark.SystemTime = *pSystemTime ;
  1555. lstrcpy (Bookmark.szComment, NewDataBookmark) ;
  1556. return (LogWriteBookmarkData (hWndLog, &Bookmark)) ;
  1557. }
  1558. BOOL LogWriteBookmarkData (HWND hWnd, PBOOKMARK pBookmark)
  1559. {
  1560. PLOG pLog ;
  1561. LONG lDataOffset ;
  1562. BOOL WriteOK ;
  1563. pLog = LogData (hWndLog) ;
  1564. if (!pLog)
  1565. return (FALSE) ;
  1566. lDataOffset = FileTell (pLog->hFile) ;
  1567. WriteOK = FileWrite (pLog->hFile, pBookmark, sizeof (BOOKMARK)) ;
  1568. if ( WriteOK ) {
  1569. pLog->lFileSize += sizeof (BOOKMARK) ;
  1570. UpdateLogSize (hWndLog) ;
  1571. WriteOK = LogWriteIndex (pLog, LogFileIndexBookmark,
  1572. &(pBookmark->SystemTime),
  1573. lDataOffset,
  1574. 0) ;
  1575. }
  1576. if ( !WriteOK ) {
  1577. CloseLog (hWndLog, pLog) ;
  1578. PrepareMenu (GetMenu (hWndMain)) ;
  1579. UpdateLogDisplay (hWndLog) ;
  1580. DlgErrorBox (hWndLog, ERR_LOG_FILE, pLog->szFilePath);
  1581. }
  1582. return WriteOK ;
  1583. }
  1584. BOOL LogWriteBookmark (HWND hWndLog,
  1585. LPCTSTR lpszComment)
  1586. {
  1587. BOOKMARK Bookmark ;
  1588. memset (&Bookmark, 0, sizeof (BOOKMARK)) ;
  1589. GetLocalTime (&Bookmark.SystemTime) ;
  1590. lstrcpy (Bookmark.szComment, lpszComment) ;
  1591. return (LogWriteBookmarkData (hWndLog, &Bookmark)) ;
  1592. }
  1593. BOOL AnyLogLine (void)
  1594. {
  1595. if (LBSelection (hWndLogEntries) == LB_ERR) {
  1596. return (FALSE) ;
  1597. } else {
  1598. return (TRUE) ;
  1599. }
  1600. }
  1601. void ResetLogView (HWND hWndLog)
  1602. {
  1603. PLOG pLog ;
  1604. pLog = LogData (hWndLog) ;
  1605. ChangeSaveFileName (NULL, IDM_VIEWLOG) ;
  1606. if (pLog && pLog->pSystemFirst) {
  1607. ResetLog (hWndLog) ;
  1608. }
  1609. }
  1610. BOOL ResetLog (HWND hWndLog)
  1611. {
  1612. INT_PTR iIndex ;
  1613. PLOG pLog ;
  1614. INT_PTR iEntriesNum ;
  1615. pLog = LogData (hWndLog) ;
  1616. if (LogCollecting (hWndLog)) {
  1617. CloseLog (hWndLog, pLog) ;
  1618. }
  1619. LBSetRedraw (hWndLogEntries, FALSE) ;
  1620. iEntriesNum = LBNumItems (hWndLogEntries) ;
  1621. // only need to zero out the list head
  1622. // each item will be deleted by LogDeleteIndex via the listbox
  1623. pLog->pLogEntryFirst = NULL ;
  1624. // delete each line
  1625. for (iIndex = iEntriesNum - 1; iIndex >= 0; iIndex-- )
  1626. {
  1627. LogDeleteIndex (hWndLogEntries, iIndex) ;
  1628. }
  1629. LBSetRedraw (hWndLogEntries, TRUE) ;
  1630. if (pLog->pSystemFirst) {
  1631. FreeSystems (pLog->pSystemFirst) ;
  1632. pLog->pSystemFirst = NULL ;
  1633. }
  1634. MemoryFree ((LPMEMORY)pLog->pLogData) ;
  1635. pLog->pLogData = (PPERFDATA) MemoryAllocate (STARTING_SYSINFO_SIZE) ;
  1636. LogEntriesChanged (hWndLogEntries) ;
  1637. pLog->iStatus = iPMStatusClosed ;
  1638. UpdateLogDisplay (hWndLog) ;
  1639. return (TRUE) ;
  1640. }
  1641. BOOL LogDeleteEntry (HWND hWndLog)
  1642. {
  1643. INT_PTR iIndex ;
  1644. PLOG pLog ;
  1645. BOOL retCode ;
  1646. int iEntriesNum ;
  1647. pLog = LogData (hWndLog) ;
  1648. iIndex = LBSelection (hWndLogEntries) ;
  1649. if (iIndex == LB_ERR) {
  1650. retCode = FALSE ;
  1651. } else {
  1652. // remove the current selection
  1653. LogDeleteIndex (hWndLogEntries, iIndex) ;
  1654. iEntriesNum = LBNumItems (hWndLogEntries) ;
  1655. if (iEntriesNum == 0 || iEntriesNum == LB_ERR) {
  1656. // delete the last line or something bad happened,
  1657. // then reset the window.
  1658. ResetLog (hWndLog) ;
  1659. } else {
  1660. // set selection on the item above the deleted item.
  1661. iIndex-- ;
  1662. if (iIndex < 0) {
  1663. iIndex = 0 ;
  1664. }
  1665. LBSetSelection (hWndLogEntries, iIndex) ;
  1666. LBSetVisible (hWndLogEntries, iIndex) ;
  1667. }
  1668. LogEntriesChanged (hWndLogEntries) ;
  1669. retCode = TRUE ;
  1670. }
  1671. return (retCode) ;
  1672. }
  1673. void ExportLog (void)
  1674. {
  1675. HANDLE hFile ;
  1676. PLOG pLog ;
  1677. PLOGENTRY pLogEntry ;
  1678. int iIndex ;
  1679. int iIndexNum ;
  1680. CHAR TempBuff [LongTextLen * 2] ;
  1681. TCHAR UnicodeBuff [LongTextLen] ;
  1682. TCHAR UnicodeBuff1 [MiscTextLen] ;
  1683. int StringLen ;
  1684. LPTSTR pFileName = NULL ;
  1685. INT ErrCode = 0 ;
  1686. if (!(pLog = LogData (hWndLog))) {
  1687. return ;
  1688. }
  1689. // see if there is anything to export..
  1690. iIndexNum = LBNumItems (hWndLogEntries) ;
  1691. if (iIndexNum == 0 || iIndexNum == LB_ERR) {
  1692. return ;
  1693. }
  1694. if (!FileGetName (hWndLog, IDS_EXPORTFILE, UnicodeBuff)) {
  1695. // user cancel
  1696. return ;
  1697. }
  1698. pFileName = StringAllocate (UnicodeBuff) ;
  1699. // open the file..
  1700. hFile = FileHandleCreate (UnicodeBuff);
  1701. if (hFile == INVALID_HANDLE_VALUE) {
  1702. // can't open the file
  1703. ErrCode = ERR_CANT_OPEN ;
  1704. return ;
  1705. }
  1706. SetHourglassCursor() ;
  1707. // get header
  1708. StringLoad (IDS_REPORT_HEADER, UnicodeBuff) ;
  1709. ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  1710. StringLen = strlen (TempBuff) ;
  1711. ConvertUnicodeStr (&TempBuff[StringLen], LocalComputerName) ;
  1712. strcat (TempBuff, LineEndStr) ;
  1713. if (!FileWrite (hFile, TempBuff, strlen(TempBuff))) {
  1714. ErrCode = ERR_EXPORT_FILE ;
  1715. goto Exit0 ;
  1716. }
  1717. if (!(strempty(pLog->szFilePath))) {
  1718. // export filename is there is one
  1719. StringLoad (IDS_REPORT_LOGFILE, UnicodeBuff) ;
  1720. ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  1721. StringLen = strlen (TempBuff) ;
  1722. ConvertUnicodeStr (&TempBuff[StringLen], pLog->szFilePath) ;
  1723. strcat (TempBuff, LineEndStr) ;
  1724. if (!FileWrite (hFile, TempBuff, strlen(TempBuff))) {
  1725. ErrCode = ERR_EXPORT_FILE ;
  1726. goto Exit0 ;
  1727. }
  1728. }
  1729. // export interval
  1730. StringLoad (IDS_CHARTINT_FORMAT, UnicodeBuff1) ;
  1731. TSPRINTF (UnicodeBuff, UnicodeBuff1,
  1732. (FLOAT) pLog->iIntervalMSecs / (FLOAT) 1000.0) ;
  1733. ConvertDecimalPoint (UnicodeBuff) ;
  1734. ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  1735. strcat (TempBuff, LineEndStr) ;
  1736. strcat (TempBuff, LineEndStr) ;
  1737. if (!FileWrite (hFile, TempBuff, strlen(TempBuff))) {
  1738. ErrCode = ERR_EXPORT_FILE ;
  1739. goto Exit0 ;
  1740. }
  1741. // export Labels
  1742. StringLoad (IDS_LABELOBJECT, UnicodeBuff) ;
  1743. ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  1744. strcat (TempBuff, pDelimiter) ;
  1745. if (!FileWrite (hFile, TempBuff, strlen(TempBuff))) {
  1746. ErrCode = ERR_EXPORT_FILE ;
  1747. goto Exit0 ;
  1748. }
  1749. StringLoad (IDS_LABELSYSTEM, UnicodeBuff) ;
  1750. ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  1751. strcat (TempBuff, LineEndStr) ;
  1752. if (!FileWrite (hFile, TempBuff, strlen(TempBuff))) {
  1753. ErrCode = ERR_EXPORT_FILE ;
  1754. goto Exit0 ;
  1755. }
  1756. // export each counter
  1757. for (iIndex = 0 ; iIndex < iIndexNum ; iIndex++) { // for
  1758. pLogEntry = LogEntryN (hWndLogEntries, iIndex) ;
  1759. if (!pLogEntry || pLogEntry == (PLOGENTRY)LB_ERR) {
  1760. continue ;
  1761. }
  1762. ConvertUnicodeStr (TempBuff, pLogEntry->szObject) ;
  1763. strcat (TempBuff, pDelimiter) ;
  1764. if (!FileWrite (hFile, TempBuff, strlen(TempBuff))) {
  1765. ErrCode = ERR_EXPORT_FILE ;
  1766. break ;
  1767. }
  1768. ConvertUnicodeStr (TempBuff, pLogEntry->szComputer) ;
  1769. strcat (TempBuff, LineEndStr) ;
  1770. if (!FileWrite (hFile, TempBuff, strlen(TempBuff))) {
  1771. ErrCode = ERR_EXPORT_FILE ;
  1772. break ;
  1773. }
  1774. }
  1775. Exit0:
  1776. SetArrowCursor() ;
  1777. CloseHandle (hFile) ;
  1778. if (pFileName) {
  1779. if (ErrCode) {
  1780. DlgErrorBox (hWndGraph, ErrCode, pFileName) ;
  1781. }
  1782. MemoryFree (pFileName) ;
  1783. }
  1784. }
  1785. LPTSTR MatchSystemCounters (LPTSTR pBaseSysCounter,
  1786. long lBaseSysSize,
  1787. LPTSTR pSysCounter,
  1788. long lSysSize,
  1789. long *pMatchPortion)
  1790. {
  1791. LPTSTR pNotMatch = NULL ;
  1792. long i, lSizeToCompare ;
  1793. *pMatchPortion = 0 ;
  1794. lSizeToCompare = min (lBaseSysSize, lSysSize) / sizeof (TCHAR) ;
  1795. for (i = 0 ; i < lSizeToCompare ; i++, pBaseSysCounter++, pSysCounter++) {
  1796. if (*pBaseSysCounter != *pSysCounter) {
  1797. pNotMatch = pSysCounter ;
  1798. break ;
  1799. }
  1800. }
  1801. if (pNotMatch == NULL) {
  1802. if (lBaseSysSize < lSysSize) {
  1803. // the new system has longer counter names than base system
  1804. // setup the extra portion.
  1805. pNotMatch = pSysCounter ;
  1806. } else {
  1807. // new system counter name is shorter than or equal to
  1808. // the base system counter names
  1809. *pMatchPortion = lSysSize ;
  1810. }
  1811. }
  1812. return (pNotMatch) ;
  1813. }
  1814. void LogWriteSystemCounterNames (HWND hWnd, PLOG pLog)
  1815. {
  1816. long dwArraySize ;
  1817. PPERFSYSTEM pSystem = pLog->pSystemFirst ;
  1818. LPTSTR pMatchLen ;
  1819. LPTSTR pCounterName ;
  1820. long lMatchLen, lMatchPortion ;
  1821. for (pSystem = pLog->pSystemFirst ;
  1822. pSystem ;
  1823. pSystem = pSystem->pSystemNext) {
  1824. if (pSystem->bSystemCounterNameSaved == TRUE ||
  1825. pSystem->CounterInfo.dwLastId == 0) {
  1826. // we have either wrote out the counter name for
  1827. // this system, or this system is not connect when
  1828. // reading in the setting file, skip it then.
  1829. continue ;
  1830. }
  1831. dwArraySize = (pSystem->CounterInfo.dwLastId + 1 ) ;
  1832. if (!pLog->lBaseCounterNameOffset) {
  1833. LogWriteCounterName (hWnd, pSystem, pLog,
  1834. (LPTSTR)(pSystem->CounterInfo.TextString + dwArraySize),
  1835. 0,
  1836. pSystem->CounterInfo.dwCounterSize,
  1837. 0 ) ;
  1838. } else {
  1839. // check for matched characters between this system and the
  1840. // base system
  1841. pCounterName = (LPTSTR)(pSystem->CounterInfo.TextString + dwArraySize) ;
  1842. pMatchLen = MatchSystemCounters (pLog->pBaseCounterName,
  1843. pLog->lBaseCounterNameSize,
  1844. pCounterName,
  1845. pSystem->CounterInfo.dwCounterSize,
  1846. &lMatchPortion) ;
  1847. if (pMatchLen) {
  1848. // This system matches part of the base system
  1849. // (all if it has more names)
  1850. lMatchLen = (long) (pMatchLen - pCounterName) * sizeof (TCHAR) ;
  1851. LogWriteCounterName (hWnd, pSystem, pLog,
  1852. pMatchLen,
  1853. lMatchLen,
  1854. pSystem->CounterInfo.dwCounterSize - lMatchLen,
  1855. 0 ) ;
  1856. } else {
  1857. // This system matches the based system
  1858. LogWriteCounterName (hWnd, pSystem, pLog,
  1859. NULL,
  1860. lMatchPortion,
  1861. 0,
  1862. 0 ) ;
  1863. }
  1864. }
  1865. }
  1866. }
  1867. BOOL LogWriteCounterName (HWND hWnd,
  1868. PPERFSYSTEM pSystem,
  1869. PLOG pLog,
  1870. LPTSTR pCounterName,
  1871. long sizeMatched,
  1872. long sizeOfData,
  1873. BOOL bBaseCounterName)
  1874. {
  1875. BOOL ReadOK ;
  1876. BOOL WriteOK ;
  1877. SYSTEMTIME SystemTime ;
  1878. LOGFILECOUNTERNAME CounterNameRecord ;
  1879. LOGHEADER LogFileHeader ;
  1880. long lDataOffset, lCurPosition ;
  1881. TCHAR Dummy [sizeof(DWORD)] ;
  1882. int PatchBytes = 0;
  1883. if (pSystem->bSystemCounterNameSaved == TRUE)
  1884. return FALSE ;
  1885. GetLocalTime (&SystemTime) ;
  1886. lCurPosition = FileTell (pLog->hFile) ;
  1887. lstrcpy (CounterNameRecord.szComputer, pSystem->sysName) ;
  1888. CounterNameRecord.lBaseCounterNameOffset = pLog->lBaseCounterNameOffset ;
  1889. CounterNameRecord.lCurrentCounterNameOffset =
  1890. lCurPosition + sizeof (LOGFILECOUNTERNAME) ;
  1891. CounterNameRecord.lMatchLength = sizeMatched ;
  1892. CounterNameRecord.lUnmatchCounterNames = sizeOfData ;
  1893. CounterNameRecord.dwLastCounterId = pSystem->CounterInfo.dwLastId ;
  1894. CounterNameRecord.dwLangId = pSystem->CounterInfo.dwLangId ;
  1895. WriteOK = FileWrite (pLog->hFile, &CounterNameRecord,
  1896. sizeof (CounterNameRecord)) ;
  1897. if (WriteOK) {
  1898. pLog->lFileSize += sizeof (LOGFILECOUNTERNAME) ;
  1899. if (sizeOfData) {
  1900. WriteOK = FileWrite (pLog->hFile, pCounterName, sizeOfData) ;
  1901. if (WriteOK && (PatchBytes = sizeOfData % sizeof(DWORD)) > 0) {
  1902. // ensure the file is in DWORD boundary.
  1903. WriteOK = FileWrite (pLog->hFile, Dummy, PatchBytes) ;
  1904. }
  1905. if (WriteOK) {
  1906. pLog->lFileSize += sizeOfData + PatchBytes ;
  1907. if (!pLog->lBaseCounterNameOffset) {
  1908. // this is the first counter name data block
  1909. // then update the log file header
  1910. lDataOffset = FileTell (pLog->hFile) ;
  1911. FileSeekBegin (pLog->hFile, 0L) ;
  1912. ReadOK = FileRead (pLog->hFile,
  1913. &LogFileHeader,
  1914. sizeof (LogFileHeader)) ;
  1915. if (ReadOK) {
  1916. LogFileHeader.lBaseCounterNameOffset = lCurPosition ;
  1917. FileSeekBegin (pLog->hFile, 0L) ;
  1918. WriteOK = FileWrite (pLog->hFile,
  1919. &LogFileHeader,
  1920. sizeof (LogFileHeader)) ;
  1921. } else {
  1922. // flag an error
  1923. WriteOK = FALSE ;
  1924. }
  1925. // retore back to current file position
  1926. FileSeekBegin (pLog->hFile, lDataOffset) ;
  1927. if (ReadOK && WriteOK) {
  1928. // allocate memory to save the base system counter names
  1929. if (pLog->pBaseCounterName) {
  1930. MemoryFree (pLog->pBaseCounterName) ;
  1931. }
  1932. if (pLog->pBaseCounterName = MemoryAllocate (sizeOfData)) {
  1933. memcpy (pLog->pBaseCounterName,
  1934. pCounterName,
  1935. sizeOfData) ;
  1936. pLog->lBaseCounterNameOffset = lCurPosition ;
  1937. pLog->lBaseCounterNameSize = sizeOfData ;
  1938. }
  1939. }
  1940. }
  1941. }
  1942. }
  1943. }
  1944. if ( WriteOK ) {
  1945. WriteOK = LogWriteIndex (pLog, LogFileIndexCounterName,
  1946. &SystemTime,
  1947. lCurPosition,
  1948. 0) ;
  1949. }
  1950. if ( !WriteOK ) {
  1951. CloseLog (hWndLog, pLog) ;
  1952. PrepareMenu (GetMenu (hWndMain)) ;
  1953. UpdateLogDisplay (hWndLog) ;
  1954. DlgErrorBox (hWndLog, ERR_LOG_FILE, pLog->szFilePath);
  1955. } else {
  1956. UpdateLogSize (hWnd) ;
  1957. pSystem->bSystemCounterNameSaved = TRUE ;
  1958. }
  1959. return (TRUE) ;
  1960. }