home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / perfmon / log.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  77KB  |  2,699 lines

  1. /*****************************************************************************
  2.  *
  3.  *  Log.c - This module handles the Logging.
  4.  *
  5.  *  Microsoft Confidential
  6.  *  Copyright (c) 1992-1997 Microsoft Corporation
  7.  *
  8.  *
  9.  ****************************************************************************/
  10.  
  11.  
  12. //==========================================================================//
  13. //                                  Includes                                //
  14. //==========================================================================//
  15.  
  16. #include <stdio.h>
  17.  
  18. #include "perfmon.h"
  19. #include "log.h"
  20.  
  21. #include "fileutil.h"
  22. #include "owndraw.h"
  23. #include "pmemory.h"       // for MemoryXXX (mallloc-type) routines
  24. #include "perfmops.h"      // for SystemAdd
  25. #include "perfdata.h"
  26. #include "playback.h"      // for PlayingBackLog
  27. #include "status.h"        // for StatusUpdateIcons
  28. #include "system.h"        // for SystemAdd
  29. #include "utils.h"
  30. #include "fileopen.h"      // for FileGetName
  31. #include "command.h"
  32.  
  33. extern TCHAR LOCAL_SYS_CODE_NAME[] ;
  34.  
  35. //==========================================================================//
  36. //                              Funtion Prototypes                          //
  37. //==========================================================================//
  38.  
  39.  
  40. BOOL LogWriteStartBookmark (HWND hWnd, SYSTEMTIME *pSystemTime) ;
  41. BOOL LogWriteBookmarkData (HWND hWnd, PBOOKMARK pBookMark) ;
  42. BOOL LogWriteSystemBookmark (HWND hWnd, LPTSTR SysName, BOOL DisConnect, SYSTEMTIME *pSystemTime) ;
  43.  
  44.  
  45. //==========================================================================//
  46. //                                  Constants                               //
  47. //==========================================================================//
  48.  
  49.  
  50.  
  51. #define LogNameMinLen             15
  52. #define LogObjectMinLen           20
  53.  
  54. // This is set to 1 min
  55. #define LARGE_INTERVAL            60
  56.  
  57. //=============================//
  58. // Log Class                   //
  59. //=============================//
  60.  
  61.  
  62. #define dwLogClassStyle           (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS)
  63. #define iLogClassExtra            (0)
  64. #define iLogWindowExtra           (0)
  65. #define dwLogWindowStyle          (WS_CHILD)
  66.  
  67.  
  68. //==========================================================================//
  69. //                                Local Data                                //
  70. //==========================================================================//
  71.  
  72.  
  73.  
  74. int            xStatusWidth ;
  75. int            xNameMinWidth ;
  76.  
  77. TCHAR          szClosed [ShortTextLen] ;
  78. TCHAR          szCollecting [ShortTextLen] ;
  79. // TCHAR          szPaused [ControlStringLen + 1] ;
  80.  
  81.  
  82.  
  83. LOGINDEXBLOCK  *pLogIndexBlock ;
  84.  
  85. #define WM_START_LOGGING  WM_USER+2
  86.  
  87. //==========================================================================//
  88. //                                   Macros                                 //
  89. //==========================================================================//
  90.  
  91.  
  92. #define LogEntryN(hWndLogEntries, iIndex)        \
  93.    ((PLOGENTRY) LBData (hWndLogEntries, iIndex))
  94.  
  95.  
  96. //==========================================================================//
  97. //                              Local Functions                             //
  98. //==========================================================================//
  99.  
  100. void LogAddEntryToList (PLOGENTRY *ppLogEntryFirst, PLOGENTRY pLogNewEntry)
  101. {
  102.    // insert the new entry at the beginning
  103.    pLogNewEntry->pNextLogEntry = *ppLogEntryFirst ;
  104.    *ppLogEntryFirst = pLogNewEntry ;
  105. }
  106.  
  107. void LogDeleteEntryFromList (PLOGENTRY *ppLogEntryFirst, PLOGENTRY pLogEntryDel)
  108. {
  109.    PLOGENTRY   pLogEntry ;
  110.  
  111.    if (*ppLogEntryFirst == pLogEntryDel)
  112.       {
  113.       *ppLogEntryFirst = pLogEntryDel->pNextLogEntry ;
  114.       }
  115.    else
  116.       {
  117.       for (pLogEntry = *ppLogEntryFirst ;
  118.          pLogEntry ;
  119.          pLogEntry = pLogEntry->pNextLogEntry)
  120.          {
  121.          if (pLogEntry->pNextLogEntry == pLogEntryDel)
  122.             {
  123.             // found, remove this entry from the list
  124.             pLogEntry->pNextLogEntry =
  125.                pLogEntryDel->pNextLogEntry ;
  126.             break ;
  127.             }
  128.          }
  129.       }
  130. }
  131.  
  132.  
  133. // LogDeleteIndex - delete the log entry specified by iIndex
  134. // and do memory clean-up
  135. void static LogDeleteIndex (HWND hWndLogEntries, int iIndex)
  136. {
  137.    PLOGENTRY   pLogEntry ;
  138.    PLOG        pLog ;
  139.  
  140.    pLogEntry = (PLOGENTRY) LBData(hWndLogEntries, iIndex) ;
  141.  
  142.    
  143.    if (pLogEntry && pLogEntry != (PLOGENTRY)LB_ERR)
  144.       {
  145.       pLog = LogData (hWndLog) ;
  146.  
  147.       if (pLog->pLogEntryFirst)
  148.          {
  149.          LogDeleteEntryFromList (&(pLog->pLogEntryFirst), pLogEntry) ;
  150.          }
  151.  
  152.       MemoryFree (pLogEntry) ;
  153.       }
  154.       
  155.    LBDelete (hWndLogEntries, iIndex) ;
  156. }
  157.  
  158.  
  159. void LogEntriesChanged (HWND hWndLogEntries)
  160. /*
  161.    Effect:        Perform any actions needed when an entry has been added or
  162.                   removed from the log. In particular, determine if a new
  163.                   "Object" column width is appropriate. If it is, then
  164.                   change the width and redraw the log entries list.
  165. */
  166.    {  // LogEntriesChanged
  167.    int         iIndex ;
  168.    int         iIndexNum ;
  169.    int         xCol1Width ;
  170.    HDC         hDC ;
  171.    PLOG        pLog ;
  172.    PLOGENTRY   pLogEntry ;
  173.    PPERFSYSTEM pSystem;
  174.  
  175.    pLog = LogData (hWndLog) ;
  176.    xCol1Width = 0 ;
  177.  
  178.    hDC = GetDC (hWndLog) ;
  179.    iIndexNum = LBNumItems (hWndLogEntries) ;
  180.     
  181.     // clear value Strings for all systems
  182.  
  183.     for (pSystem = pLog->pSystemFirst;
  184.          pSystem;
  185.          pSystem = pSystem->pSystemNext) {
  186.         if (pSystem && pSystem->FailureTime == 0) {
  187.             RemoveObjectsFromSystem (pSystem);
  188.         }
  189.     }
  190.  
  191.    for (iIndex = 0 ;
  192.         iIndex < iIndexNum ;
  193.         iIndex++)
  194.       {  // for all items in the list
  195.       pLogEntry = LogEntryN (hWndLogEntries, iIndex) ;
  196.       xCol1Width = max (TextWidth (hDC, pLogEntry->szObject), 
  197.                         xCol1Width) ;
  198.  
  199.       pSystem = SystemGet (pLog->pSystemFirst, pLogEntry->szComputer);
  200.       if (pSystem && pSystem->FailureTime == 0) {
  201.          AppendObjectToValueList (
  202.                 pLogEntry->ObjectTitleIndex,
  203.                 pSystem->lpszValue);
  204.          } 
  205.       }  // for
  206.  
  207.    xCol1Width += 2 * xScrollWidth ;
  208.    xCol1Width = max (xCol1Width, 
  209.                      TextAvgWidth (hDC, LogObjectMinLen)) ;
  210.    if (xCol1Width != pLog->xCol1Width)
  211.       {
  212.       pLog->xCol1Width = xCol1Width ;
  213.       WindowInvalidate (hWndLogEntries) ;
  214.       }
  215.    ReleaseDC (hWndLog, hDC) ;
  216.    }  // LogEntriesChanged
  217.  
  218.  
  219. LPTSTR StatusText (int iPMStatus)
  220. /*
  221.    Effect:        Return a string representation of the log status
  222.                   iPMStatus.
  223.  
  224.    Note:          Since these are globals, we can just return a pointer
  225.                   to them. The user of this routine should not free
  226.                   these pointers or modify the string.
  227. */
  228.    {
  229.    switch (iPMStatus)
  230.       {  // switch
  231.       case iPMStatusClosed:
  232.          return (szClosed) ;
  233.  
  234.       case iPMStatusCollecting:
  235.          return (szCollecting) ;
  236.  
  237. //      case iPMStatusPaused:
  238. //         return (szPaused) ;
  239.  
  240.       default:
  241.          return (szClosed) ;
  242.       }  // switch
  243.    }  // StatusText
  244.  
  245.  
  246. PLOG AllocateLogData (HWND hWndLog)
  247.    {
  248.    PLOG           pLog ;
  249.  
  250.    pLog = LogData (hWndLog) ;
  251.  
  252.    pLog->iStatus = iPMStatusClosed ;
  253.    pLog->bManualRefresh = FALSE ;
  254.  
  255.    // let's not give it a filename
  256.  
  257. /*!!
  258.    FileCombine (pLog->szFilePath, 
  259.                 szDefaultLogDirectory, szDefaultLogFileName) ;
  260. !!*/
  261.    strclr (pLog->szFilePath) ;
  262.  
  263.    pLog->pSystemFirst = NULL;
  264.    pLog->lFileSize = 0L ;
  265.    pLog->iIntervalMSecs = iDefaultLogIntervalSecs * 1000 ;
  266.  
  267.    pLog->pLogData = (PPERFDATA) MemoryAllocate (STARTING_SYSINFO_SIZE) ;
  268.    pLog->dwDetailLevel = PERF_DETAIL_WIZARD ;
  269.    LogEntriesChanged (hWndLogEntries) ;
  270.  
  271.    return (pLog) ;
  272.    }  // AllocateLogData
  273.  
  274.  
  275. void FreeLogData (PLOG pLog)
  276.    {  // FreeLogData
  277.    MemoryFree (pLog->pLogData) ;
  278.    }  // FreeLogData
  279.  
  280.  
  281. void UpdateLogSize (HWND hWnd)
  282. /*
  283.    Effect:        Set the size value to the current size.  Also change the
  284.                   size entry in the status line.
  285. */
  286.    {  // UpdateLogSize
  287.    PLOG           pLog ;
  288.    TCHAR          szSize [ShortTextLen + 1] ;
  289.  
  290.    pLog = LogData (hWnd) ;
  291.    
  292.    LongToCommaString (pLog->lFileSize, szSize) ;
  293.    SetDlgItemText (hWnd, IDD_LOGSIZE, szSize) ;
  294.  
  295.    if (!PlayingBackLog())
  296.       {
  297.       StatusUpdateIcons (hWndStatus) ;
  298.       }
  299.    }  // UpdateLogSize
  300.  
  301.  
  302. HANDLE LogAppendSetup(PLOG pLog, PLOGHEADER pLogFileHeader)
  303.    {  // LogAppendSetup
  304.    PLOGHEADER     pHeader ;
  305.    LOGPOSITION    LP ;
  306.    DWORD          lPreviousIndexBlock ;
  307.    DWORD          lNextIndexBlock ;
  308.    PLOGHEADER     pPlaybackLogHeader ;
  309.    HANDLE         hMapHandle ;
  310.  
  311.    pHeader = (PLOGHEADER) FileMap(pLog->hFile, &hMapHandle) ;
  312.    if (!pHeader ||
  313.        !strsame(pHeader->szSignature, LogFileSignature) ||
  314.        pHeader->wVersion != LogFileVersion ||
  315.        pHeader->wRevision != LogFileRevision)
  316.       {
  317.       if (pHeader)
  318.          {
  319.          FileUnMap((LPVOID)pHeader, hMapHandle) ;
  320.          }
  321.       return 0 ;
  322.       }
  323.  
  324.    *pLogFileHeader = *pHeader ;
  325.  
  326.  
  327.    LP.pIndexBlock = FirstIndexBlock(pHeader) ;
  328.    LP.iIndex = 0 ;
  329.    LP.iPosition = 0 ;
  330.    lPreviousIndexBlock = pHeader->iLength ;
  331.    lNextIndexBlock = LP.pIndexBlock->lNextBlockOffset ;
  332.  
  333.    // since inside NextReLogIndexPosition would eventually call
  334.    // PlaybackSeek for large log file, we have to temporarily
  335.    // setup PlaybackLog.pHeader.   Not a good fix but it works...
  336.    pPlaybackLogHeader = PlaybackLog.pHeader ;
  337.    PlaybackLog.pHeader = pHeader ;
  338.    while (NextReLogIndexPosition(&LP))
  339.       {
  340.       if (LP.pIndexBlock->lNextBlockOffset != lNextIndexBlock)
  341.          {
  342.          lPreviousIndexBlock = lNextIndexBlock ;
  343.          lNextIndexBlock = LP.pIndexBlock->lNextBlockOffset ;
  344.          }
  345.       }
  346.  
  347.    // get the last system time from this log file
  348.    if (LP.iIndex > 0)
  349.       {
  350.       SYSTEMTIME localSystemTime ;
  351.  
  352.       if (LogPositionSystemTime (&LP, &localSystemTime))
  353.          {
  354.          pLog->LastLogTime = localSystemTime ;
  355.          }
  356.       }
  357.  
  358.    PlaybackLog.pHeader = pPlaybackLogHeader ;
  359.    if (!pLogIndexBlock)
  360.       {
  361.       pLogIndexBlock = (LOGINDEXBLOCK *) MemoryAllocate (sizeof(LOGINDEXBLOCK)) ;
  362.       }
  363.    *pLogIndexBlock = *LP.pIndexBlock ;
  364.    pLog->lIndexBlockOffset = lPreviousIndexBlock ;
  365.    pLog->iIndex = ++LP.iIndex ;
  366.    pLog->lFileSize = FileSeekEnd(pLog->hFile, 0) ;
  367.  
  368.    FileUnMap((LPVOID)pHeader, hMapHandle) ;
  369.    return pLog->hFile ;
  370.    }  // LogAppendSetup
  371.  
  372. void LogRemoveCounterName (PLOG pLog)
  373.    {
  374.    PPERFSYSTEM    pSystem ;
  375.  
  376.    if (pLog->pBaseCounterName)
  377.       {
  378.       MemoryFree (pLog->pBaseCounterName) ;
  379.       }
  380.    pLog->pBaseCounterName = 0 ;
  381.    pLog->lBaseCounterNameSize = 0 ;
  382.    pLog->lBaseCounterNameOffset = 0 ;
  383.  
  384.    // clear all the system marker to indicate they have not been 
  385.    // saved
  386.    for (pSystem = pLog->pSystemFirst ;
  387.       pSystem ;
  388.       pSystem = pSystem->pSystemNext)
  389.       {
  390.       pSystem->bSystemCounterNameSaved = FALSE ;
  391.       }
  392.    }
  393.  
  394. int CreateLogFile (PLOG pLog, BOOL bCreateFile, BOOL bSameFile)
  395.    {  // CreateLogFile
  396.    HANDLE               returnHandle ;
  397.    LOGHEADER            LogFileHeader ;
  398.    long                 lCurPosition ;
  399.    LOGFILECOUNTERNAME   CounterNameRecord ;
  400.  
  401.    pLog->lFileSize = 0 ;
  402.    memset (&(pLog->LastLogTime), 0, sizeof(SYSTEMTIME)) ;
  403.  
  404.    if (!pLogIndexBlock)
  405.       {
  406.       pLogIndexBlock = (LOGINDEXBLOCK *) MemoryAllocate (sizeof(LOGINDEXBLOCK)) ;
  407.       }
  408.  
  409.    lstrcpy (pLogIndexBlock->szSignature, LogIndexSignature) ;
  410.    pLog->hFile = FileHandleOpen (pLog->szFilePath) ;
  411.    if (pLog->hFile != INVALID_HANDLE_VALUE)
  412.       {
  413.       // if this is a pre-existing log file, set up to append to it
  414.       returnHandle = LogAppendSetup(pLog, &LogFileHeader) ;
  415.       if (!returnHandle)
  416.          {
  417.          // this is not a log file...
  418.          CloseHandle (pLog->hFile) ;
  419.          return (ERR_BAD_LOG_FILE) ;
  420.          }
  421.       
  422.       pLog->hFile = returnHandle ;
  423.       }
  424.  
  425.    if (bCreateFile && (!pLog->hFile || pLog->hFile == INVALID_HANDLE_VALUE))
  426.       {
  427.       // Create a new log file if needed.
  428.       pLog->hFile = FileHandleCreate (pLog->szFilePath) ;
  429.       if (!pLog->hFile || pLog->hFile == INVALID_HANDLE_VALUE)
  430.          return (ERR_LOG_FILE) ;
  431.       lstrcpy (LogFileHeader.szSignature, LogFileSignature) ;
  432.       LogFileHeader.wVersion = LogFileVersion ;
  433.       LogFileHeader.wRevision = LogFileRevision ;
  434.       LogFileHeader.iLength = sizeof (LOGHEADER) ;
  435.       LogFileHeader.lBaseCounterNameOffset = 0 ;
  436.       if (!FileWrite (pLog->hFile, &LogFileHeader, sizeof (LogFileHeader)))
  437.          {
  438.          CloseHandle (pLog->hFile) ;
  439.          return (ERR_LOG_FILE) ;
  440.          }
  441.  
  442.       pLog->iIndex = 0 ;
  443.       pLog->lIndexBlockOffset = FileTell (pLog->hFile) ;
  444.       FileSeekCurrent (pLog->hFile, sizeof (LOGINDEXBLOCK)) ;
  445.       pLog->lFileSize = sizeof(LOGHEADER) + sizeof (LOGINDEXBLOCK) ;
  446.       pLogIndexBlock->iNumIndexes = 0 ;
  447.       pLogIndexBlock->lNextBlockOffset = 0 ;
  448.  
  449.       // get rid of any previous counter names and get ready for start
  450. //      if (!bSameFile)
  451. //         {
  452. //         LogRemoveCounterName (pLog) ;
  453. //         }
  454.       LogRemoveCounterName (pLog) ;
  455.       }
  456.    else if (bCreateFile)
  457.       {
  458.       // this is an existing log file, setup the counter names
  459.       // LogFileHeader already has the header info filled in
  460.       // by LogAppendSetup
  461.       if (!bSameFile || !pLog->pBaseCounterName)
  462.          {
  463.          // get rid of any previous counter names
  464.          LogRemoveCounterName (pLog) ;
  465.  
  466.          // read the new names and get ready for start
  467.          lCurPosition = FileTell (pLog->hFile) ;
  468.  
  469.          FileSeekBegin (pLog->hFile,
  470.             LogFileHeader.lBaseCounterNameOffset) ;
  471.  
  472.          if (!(FileRead (pLog->hFile,
  473.             &CounterNameRecord,
  474.             sizeof (CounterNameRecord))))
  475.             {
  476.             FileSeekBegin (pLog->hFile,
  477.                lCurPosition) ;
  478.             goto EXIT ;
  479.             }
  480.  
  481.          FileSeekBegin (pLog->hFile,
  482.             CounterNameRecord.lCurrentCounterNameOffset) ;
  483.  
  484.          if (!(pLog->pBaseCounterName = MemoryAllocate (
  485.             CounterNameRecord.lUnmatchCounterNames)))
  486.             {
  487.             FileSeekBegin (pLog->hFile,
  488.                lCurPosition) ;
  489.             goto EXIT ;
  490.             }
  491.          if (!(FileRead (pLog->hFile,
  492.             pLog->pBaseCounterName,
  493.             CounterNameRecord.lUnmatchCounterNames)))
  494.             {
  495.             MemoryFree (pLog->pBaseCounterName) ;
  496.             pLog->pBaseCounterName = NULL ;
  497.             FileSeekBegin (pLog->hFile,
  498.                lCurPosition) ;
  499.             goto EXIT ;
  500.             }
  501.          // we got the data, fill in other info
  502.          pLog->lBaseCounterNameSize =
  503.             CounterNameRecord.lUnmatchCounterNames ;
  504.          pLog->lBaseCounterNameOffset =
  505.             LogFileHeader.lBaseCounterNameOffset ;
  506.                
  507.          FileSeekBegin (pLog->hFile,
  508.             lCurPosition) ;
  509.          }
  510.       }
  511.  
  512. EXIT:
  513.  
  514.    return (0) ;
  515.  
  516.    }  // CreateLogFile
  517.  
  518. void LogWriteIndexBlock (PLOG pLog)
  519.    {
  520.    FileSeekBegin (pLog->hFile, 
  521.                   pLog->lIndexBlockOffset) ;
  522.    pLogIndexBlock->lNextBlockOffset = 0 ;
  523.    FileWrite (pLog->hFile,
  524.               (LPSTR) pLogIndexBlock,
  525.               sizeof (LOGINDEXBLOCK)) ;
  526.    }  // LogWriteIndexBlock
  527.  
  528.  
  529. BOOL LogWriteIndex (PLOG pLog,
  530.                     UINT uFlags,
  531.                     SYSTEMTIME *pSystemTime,
  532.                     LONG lDataOffset,
  533.                     int iSystemsLogged) 
  534.    {  // LogWriteIndex
  535.    LOGINDEX       Index ;
  536.    long           lNextBlockOffset ;
  537.    BOOL           WriteOK ;
  538.    //=============================//
  539.    // Add Index Block Entry       //
  540.    //=============================//
  541.    //=============================//
  542.    // Index Block Full?           //
  543.    //=============================//
  544.  
  545.    WriteOK = TRUE ;
  546.  
  547.    if (pLog->iIndex == LogFileBlockMaxIndexes - 1)
  548.       {
  549.       lNextBlockOffset = FileTell (pLog->hFile) ;
  550.       pLogIndexBlock->lNextBlockOffset = lNextBlockOffset ;
  551.       FileSeekBegin (pLog->hFile, 
  552.                      pLog->lIndexBlockOffset) ;
  553.       WriteOK = FileWrite (pLog->hFile,
  554.                            (LPSTR) pLogIndexBlock,
  555.                            sizeof (LOGINDEXBLOCK)) ;
  556.       if (WriteOK)
  557.          {
  558.          FileSeekBegin (pLog->hFile,
  559.                         lNextBlockOffset) ;
  560.          // Fake file end until we really write the block
  561.          pLogIndexBlock->iNumIndexes = 0 ;
  562.          pLogIndexBlock->lNextBlockOffset = 0 ;
  563.          WriteOK = FileWrite (pLog->hFile,
  564.                               (LPSTR) pLogIndexBlock,
  565.                               sizeof (LOGINDEXBLOCK)) ;
  566.          if (WriteOK)
  567.             {
  568.             pLog->lIndexBlockOffset = lNextBlockOffset ;
  569.             pLog->iIndex = 0 ;
  570.             pLog->lFileSize += sizeof (LOGINDEXBLOCK) ;
  571.             }
  572.          }
  573.       }  // if
  574.  
  575.    //=============================//
  576.    // Add Index Block Entry       //
  577.    //=============================//
  578.  
  579.    Index.uFlags = uFlags ;
  580.    Index.SystemTime = *pSystemTime ;
  581.    Index.lDataOffset = lDataOffset ;
  582.    Index.iSystemsLogged = iSystemsLogged ;
  583.     
  584.    pLogIndexBlock->aIndexes [pLog->iIndex] = Index ;
  585.    pLog->iIndex++ ;
  586.    pLogIndexBlock->iNumIndexes++ ;
  587.  
  588.    // write out the index block if the log interval if too large
  589.    if (pLog->iIntervalMSecs >= LARGE_INTERVAL * 1000 )
  590.       {
  591.       LONG           lCurPosition ;
  592.    
  593.       // save the current file position
  594.       lCurPosition = FileTell (pLog->hFile) ;
  595.  
  596.       // flush the index block to the file
  597.       LogWriteIndexBlock (pLog) ;
  598.  
  599.       // restore previous file position since
  600.       // LogWriteIndexBlock has messed it up
  601.       FileSeekBegin (pLog->hFile, lCurPosition) ;
  602.       }
  603.    return (WriteOK) ;
  604.    }  // LogWriteIndex
  605.  
  606.  
  607.  
  608. BOOL LogWritePerfData (HWND hWnd,
  609.                        PLOG pLog,
  610.                        PPERFDATA pPerfData,
  611.                        SYSTEMTIME *pSystemTime,
  612.                        DWORD iNumSystems,
  613.                        BOOL bWriteIndex)
  614.    {  // LogWritePerfData
  615.    LONG           lSize ;
  616.    BOOL           WriteOK ;
  617.    LONG           lCurPosition ;
  618.    
  619.    lSize = pPerfData->TotalByteLength ;
  620.  
  621.    lCurPosition = FileTell (pLog->hFile) ;
  622.  
  623.    //=============================//
  624.    // Write Perf Data             //
  625.    //=============================//
  626.  
  627.    WriteOK = FileWrite (pLog->hFile, (LPSTR) pPerfData, lSize) ;
  628.    if (WriteOK)
  629.       {
  630.       pLog->lFileSize += lSize ;
  631.  
  632.       if (bWriteIndex)
  633.          {
  634.          WriteOK = LogWriteIndex (pLog,
  635.                                   LogFileIndexData,
  636.                                   pSystemTime,
  637.                                   lCurPosition,
  638.                                   iNumSystems) ;
  639.          }
  640.       }
  641.    if ( !WriteOK )
  642.       {
  643.       CloseLog (hWnd, pLog) ;
  644.       PrepareMenu (GetMenu (hWndMain)) ;
  645.       UpdateLogDisplay (hWnd) ;   
  646.       DlgErrorBox (hWnd, ERR_LOG_FILE, pLog->szFilePath) ;
  647.       }
  648.    return (WriteOK) ;
  649.    }  // LogWritePerfData
  650.  
  651.  
  652. //==========================================================================//
  653. //                              Message Handlers                            //
  654. //==========================================================================//
  655.  
  656.  
  657. void static OnSize (HWND hDlg,
  658.                     int xWidth,
  659.                     int yHeight)
  660. /*
  661.    Effect:        Perform any actions necessary when the log window (dialog)
  662.                   is resized. In particular, move and resize some of the
  663.                   dialogs controls.
  664.  
  665.    Internals:     The rightmost control, the log status, contains one of
  666.                   only several values. These values are all within 
  667.                   xStatusWidth, computed at init time. Put this control
  668.                   one scroll width away from the right edge at fixed
  669.                   width. Move its associated text prompt with it. Then
  670.                   use the remaining space for the filename control, which
  671.                   can probably use it.
  672.  
  673.    To Do:         Need to consider minimum first.
  674. */
  675.    {  // OnSize
  676.    int            xStatusPos ;
  677.    int            xStatusTextPos ;
  678.    int            xNameWidth ;
  679.    int            xMinWidth ;
  680.  
  681.    //=============================//
  682.    // Enough space for minimums?  //
  683.    //=============================//
  684.  
  685.    xMinWidth = 
  686.       xScrollWidth +                         // margin before prompt
  687.       DialogWidth (hDlg, IDD_LOGFILETEXT) +  // width of prompt
  688.       xNameMinWidth +                        // width of name
  689.       xScrollWidth +
  690.       DialogWidth (hDlg, IDD_LOGSTATUSTEXT) +
  691.       DialogWidth (hDlg, IDD_LOGSTATUS) + 
  692.       xScrollWidth ;
  693.  
  694.  
  695.    xStatusPos = xWidth - xStatusWidth - xScrollWidth ;   
  696.    DialogMove (hDlg, IDD_LOGSTATUS,
  697.                xStatusPos, NOCHANGE,
  698.                xStatusWidth, NOCHANGE) ;
  699.  
  700.    xStatusTextPos = xStatusPos - 
  701.                     DialogWidth (hDlg, IDD_LOGSTATUSTEXT) - 
  702.                     xScrollWidth ;
  703.    DialogMove (hDlg, IDD_LOGSTATUSTEXT, 
  704.                xStatusTextPos, NOCHANGE,
  705.                NOCHANGE, NOCHANGE) ;
  706.  
  707.    xNameWidth = xStatusTextPos - 
  708.                 DialogWidth (hDlg, IDD_LOGFILETEXT) -
  709.                 2 * xScrollWidth ;
  710.    DialogMove (hDlg, IDD_LOGFILE,
  711.                NOCHANGE, NOCHANGE,
  712.                xNameWidth, NOCHANGE) ;
  713.  
  714.    DialogMove (hDlg, IDD_LOGSIZE,
  715.                DialogXPos (hDlg, IDD_LOGFILE), NOCHANGE,
  716.                DialogWidth (hDlg, IDD_LOGFILE), NOCHANGE) ;
  717.  
  718.    DialogMove (hDlg, IDD_LOGINTERVALTEXT,
  719.                DialogXPos (hDlg, IDD_LOGSTATUSTEXT), NOCHANGE,
  720.                DialogWidth (hDlg, IDD_LOGSTATUSTEXT), NOCHANGE) ;
  721.  
  722.    DialogMove (hDlg, IDD_LOGINTERVAL,
  723.                DialogXPos (hDlg, IDD_LOGSTATUS), NOCHANGE,
  724.                DialogWidth (hDlg, IDD_LOGSTATUS), NOCHANGE) ;
  725.  
  726.    DialogMove (hDlg, IDD_LOGENTRIESTEXT,
  727.                xScrollWidth, NOCHANGE, NOCHANGE, NOCHANGE) ;
  728.  
  729.    DialogMove (hDlg, IDD_LOGENTRIES, 
  730.                xScrollWidth, NOCHANGE,
  731.                xWidth - 2 * xScrollWidth,
  732.                yHeight - DialogYPos (hDlg, IDD_LOGENTRIES) - yScrollHeight) ;
  733.    WindowInvalidate (hDlg) ;
  734.    }  // OnSize
  735.  
  736.  
  737. int OnCtlColor (HWND hDlg,
  738.                        HDC hDC)
  739.    {
  740.    SetTextColor (hDC, crBlack) ;
  741.    SetBkColor (hDC, crLightGray) ;
  742.    return ((int) hbLightGray) ;
  743.    }
  744.  
  745.  
  746. void static OnInitDialog (HWND hDlg)
  747.    {
  748.    HDC            hDC ;
  749.    PLOG           pLog ;
  750.  
  751.    hWndLogEntries = DialogControl (hDlg, IDD_LOGENTRIES) ;
  752.  
  753.    pLog = AllocateLogData (hDlg) ;
  754.    if (!pLog)
  755.       return ;
  756.  
  757.    StringLoad (IDS_CLOSED, szClosed) ;
  758. //   StringLoad (IDS_PAUSED, szPaused) ;
  759.    StringLoad (IDS_COLLECTING, szCollecting) ;
  760.    UpdateLogDisplay (hDlg) ;
  761.  
  762.    hDC = GetDC (hDlg) ;
  763.    xStatusWidth = max (TextWidth (hDC, szClosed), 
  764.                        TextWidth (hDC, szCollecting)) ;
  765. //                       max (TextWidth (hDC, szPaused),
  766. //                            TextWidth (hDC, szCollecting))) ;
  767.    xStatusWidth += xScrollWidth ;
  768.  
  769.    xNameMinWidth = TextAvgWidth (hDC, LogNameMinLen) ;
  770.    ReleaseDC (hDlg, hDC) ;
  771.    }
  772.  
  773.  
  774.  
  775. void static OnDestroy (HWND hWnd)
  776. /*
  777.    Effect:        Perform any actions necessary when a LogDisplay window
  778.                   is being destroyed. In particular, free the instance
  779.                   data for the log.  
  780.  
  781.                   Since we really only have one log window and one global
  782.                   log data structure, we don't free the structure. We do,
  783.                   however, delete the objects allocated within the structure.
  784. */
  785.    {  // OnDestroy
  786.    PLOG           pLog ;
  787.  
  788.    pLog = LogData (hWnd) ;
  789.    FreeLogData (pLog) ;
  790.    }  // OnDestroy
  791.  
  792.  
  793. void static OnDrawItem (HWND hWnd, LPDRAWITEMSTRUCT lpDI)
  794.    {  // OnDrawItem
  795.    HDC            hDC ;
  796.    RECT           rectComputer, rectObject ;
  797.    PLOGENTRY      pLogEntry ;
  798.    PLOG           pLog ;
  799.    COLORREF       preBkColor ;
  800.    COLORREF       preTextColor ;
  801.  
  802.    pLog = LogData (hWnd) ;
  803.  
  804.    pLogEntry = LogEntryN (hWndLogEntries, DIIndex (lpDI)) ;
  805.  
  806.    // LogEntryN (SendMessage) will return LB_ERR for error, have to
  807.    // check for that case
  808.    if (!pLogEntry || pLogEntry == (PLOGENTRY)LB_ERR)
  809.       {
  810.       return ;
  811.       }
  812.  
  813.    hDC = lpDI->hDC ;
  814.  
  815.    SelectFont (hDC, hFontScales) ;
  816.  
  817.    if (DISelected (lpDI)) 
  818.       {  // if
  819.       preTextColor = SetTextColor (hDC, GetSysColor (COLOR_HIGHLIGHTTEXT)) ;
  820.       preBkColor = SetBkColor (hDC, GetSysColor (COLOR_HIGHLIGHT)) ;
  821.       }  // if
  822.  
  823.    rectObject.left = lpDI->rcItem.left ;
  824.    rectObject.top = lpDI->rcItem.top ;
  825.    rectObject.right = rectObject.left + pLog->xCol1Width ;
  826.    rectObject.bottom = lpDI->rcItem.bottom ;
  827.  
  828.    ExtTextOut (hDC,  
  829.                rectObject.left + xScrollWidth, rectObject.top,   
  830.                ETO_OPAQUE,
  831.                &rectObject,
  832.                pLogEntry->szObject,
  833.                lstrlen (pLogEntry->szObject),
  834.                NULL) ;
  835.  
  836.  
  837.    rectComputer.left = rectObject.right ;
  838.    rectComputer.top = lpDI->rcItem.top ;
  839.    rectComputer.right = lpDI->rcItem.right ;
  840.    rectComputer.bottom = lpDI->rcItem.bottom ;
  841.  
  842.    ExtTextOut (hDC,  
  843.                rectComputer.left, rectComputer.top,
  844.                ETO_OPAQUE,
  845.                &rectComputer,
  846.                pLogEntry->szComputer,
  847.                lstrlen (pLogEntry->szComputer),
  848.                NULL) ;
  849.  
  850.    if (DIFocus (lpDI))
  851.       DrawFocusRect (hDC, &(lpDI->rcItem)) ;
  852.  
  853.    if (DISelected (lpDI))
  854.       {  // if
  855.       preTextColor = SetTextColor (hDC, preTextColor) ;
  856.       preBkColor = SetBkColor (hDC, preBkColor) ;
  857.       }  // if
  858. //   RestoreDC (hDC, -1) ;
  859.    }  // OnDrawItem
  860.  
  861.  
  862.    
  863. //==========================================================================//
  864. //                             Exported Functions                           //
  865. //==========================================================================//
  866.  
  867.  
  868. int APIENTRY LogDisplayDlgProc (HWND hDlg,
  869.                                 unsigned iMessage,
  870.                                 WPARAM wParam,
  871.                                 LONG lParam)
  872. /*
  873.    Note:          This function must be exported in the application's
  874.                   linker-definition file, perfmon.def.
  875. */
  876.    {  // LogDisplayDlgProc
  877. //   HDC            hDC ;
  878.  
  879.    switch (iMessage)
  880.       {
  881.       case WM_INITDIALOG:
  882.          OnInitDialog (hDlg) ;
  883.          break ;
  884.  
  885.       case WM_CTLCOLORDLG:
  886.       case WM_CTLCOLOREDIT:
  887.       case WM_CTLCOLORBTN:
  888.       case WM_CTLCOLORSTATIC:
  889.          return (OnCtlColor (hDlg, (HDC) wParam)) ;
  890.          break ;
  891.  
  892.       case WM_DRAWITEM:
  893.          OnDrawItem (hDlg, (LPDRAWITEMSTRUCT) lParam) ;
  894.          break ;
  895.  
  896.       case WM_LBUTTONDBLCLK:
  897.          SendMessage (hWndMain, WM_LBUTTONDBLCLK, wParam, lParam) ;
  898.          break ;
  899.  
  900.       case WM_LBUTTONDOWN:
  901.          DoWindowDrag (hDlg, lParam) ;
  902.          break ;
  903.  
  904.       case WM_SIZE:
  905.          OnSize (hDlg, LOWORD (lParam), HIWORD (lParam)) ;
  906.          break ;
  907.  
  908.       case WM_TIMER:
  909.          LogTimer (hDlg, FALSE) ;
  910.          break ;
  911.  
  912.       case WM_SETFOCUS:
  913.          SetFocus (hWndLogEntries) ;
  914.          break ;
  915.  
  916.       case WM_START_LOGGING:
  917.          {
  918.          PLOG        pLog ;
  919.  
  920.          pLog = LogData (hDlg) ;
  921.          if (StartLog (hDlg, pLog, FALSE))
  922.             {
  923.             UpdateLogDisplay (hDlg) ;
  924.             PrepareMenu (GetMenu (hWndMain)) ;
  925.             }
  926.          }
  927.          break ;
  928.  
  929.       case WM_DESTROY:
  930.          OnDestroy (hDlg) ;
  931.          return (FALSE) ;
  932.          break ;
  933.  
  934.       default:
  935.          return (FALSE) ;
  936.       } // switch
  937.  
  938.    return (TRUE) ;
  939.    }  // LogDisplayDlgProc
  940.  
  941.  
  942. #if 0
  943. PLOG LogData (HWND hWndLog)
  944.    {
  945.    return (&Log) ;
  946.    }
  947. #endif
  948.  
  949. HWND CreateLogWindow (HWND hWndParent)
  950. /*
  951.    Effect:        Create the Log window. This window is a child of 
  952.                   hWndMain.
  953.  
  954.    Note:          We dont worry about the size here, as this window
  955.                   will be resized whenever the main window is resized.
  956.  
  957. */
  958.    {  // CreateLogWindow
  959.    HWND           hWnd ;
  960.    hWnd = CreateDialog (hInstance,
  961.                         MAKEINTRESOURCE (idDlgLogDisplay),
  962.                         hWndParent,
  963.                         (DLGPROC) LogDisplayDlgProc) ;
  964.  
  965.    return (hWnd) ;
  966.    }  // CreateLogWindow
  967.  
  968.  
  969.  
  970. void UpdateLogDisplay (HWND hWnd)
  971. /*
  972.    Effect:        Set the values for the various controls in the log
  973.                   display.
  974.  
  975.    Called By:     OnInitDialog, any other routines that change these
  976.                   values.
  977. */
  978.    {  // UpdateLogDisplay
  979.    PLOG           pLog ;
  980.    WCHAR          szSize [MiscTextLen + 1] ;
  981.  
  982.    pLog = LogData (hWnd) ;
  983.  
  984.    DialogSetString (hWnd, IDD_LOGFILE, pLog->szFilePath) ;
  985.  
  986.    // position the cursor at the end of the text
  987.    EditSetTextEndPos (hWnd, IDD_LOGFILE) ;
  988.  
  989.  
  990.    DialogSetString (hWnd, IDD_LOGSTATUS, StatusText (pLog->iStatus)) ;
  991.  
  992.    LongToCommaString (pLog->lFileSize, szSize) ;
  993.    DialogSetString (hWnd, IDD_LOGSIZE, szSize) ;
  994.  
  995.    DialogSetInterval (hWnd, IDD_LOGINTERVAL, pLog->iIntervalMSecs) ;
  996.    }  // UpdateLogDisplay
  997.  
  998.  
  999. BOOL LogInitializeApplication (void)
  1000.    {
  1001.    return (TRUE) ;
  1002.    }  // LogInitializeApplication
  1003.  
  1004.  
  1005. void SetLogTimer (HWND hWnd,
  1006.                   int iIntervalMSecs)
  1007.    {
  1008.    PLOG           pLog ;
  1009.  
  1010.    pLog = LogData (hWnd) ;
  1011.    pLog->iIntervalMSecs = iIntervalMSecs ;
  1012.  
  1013.    KillTimer (hWnd, LogTimerID) ;
  1014.    SetTimer (hWnd, LogTimerID, pLog->iIntervalMSecs, NULL) ;
  1015.    }
  1016.  
  1017.  
  1018. void ClearLogTimer (HWND hWnd)
  1019.    {
  1020.    KillTimer (hWnd, LogTimerID) ;
  1021.    }
  1022.  
  1023.  
  1024.  
  1025. BOOL CloseLogStopTimer (HWND hWnd, PLOG pLog)
  1026.    {
  1027.    CloseHandle (pLog->hFile) ;
  1028.  
  1029.    pLog->hFile = 0 ;
  1030.    pLog->iStatus = iPMStatusClosed ;
  1031.  
  1032.    ClearLogTimer (hWnd) ;
  1033.  
  1034.    return (TRUE) ;
  1035.    }
  1036.  
  1037.  
  1038. BOOL CloseLog (HWND hWnd, PLOG pLog)
  1039.    {  // CloseLog
  1040.    LogWriteIndexBlock (pLog) ;
  1041.    CloseLogStopTimer (hWnd, pLog) ;
  1042.    WindowInvalidate (hWndStatus) ;
  1043.    return (TRUE) ;
  1044.    } // CloseLog
  1045.  
  1046. BOOL StartLog (HWND hWnd, PLOG pLog, BOOL bSameFile)
  1047.    {
  1048.    int            RetCode ;
  1049.    SYSTEMTIME     SystemTime ; 
  1050.  
  1051.    if ((RetCode = CreateLogFile (pLog, TRUE, bSameFile)) == 0)
  1052.       {
  1053.       pLog->iStatus = iPMStatusCollecting ;
  1054.  
  1055.       GetLocalTime (&SystemTime) ;
  1056.  
  1057.       // write a dummy record.
  1058.       // this is needed because when playingback log
  1059.       // it will skip the first index from the first
  1060.       // index block.
  1061.       LogWriteIndex (pLog, 0, &SystemTime, 0, 0) ;
  1062.  
  1063.       if (!PlayingBackLog())
  1064.          {
  1065.          // write out a bookmark to indicate start of new data
  1066.          if (!LogWriteStartBookmark (hWnd, &SystemTime))
  1067.             {
  1068.             RetCode = 0 ;
  1069.             goto ErrorExit ;
  1070.             }
  1071.          
  1072.          if (!(pLog->bManualRefresh))
  1073.             {
  1074.             SetLogTimer (hWnd, pLog->iIntervalMSecs) ;
  1075.             WindowInvalidate (hWndStatus) ;
  1076.             }
  1077.          }
  1078.       else
  1079.          {
  1080.          // check if time if OK
  1081.          LOGPOSITION    LP ;
  1082.          SYSTEMTIME     FirstSystemTime ;
  1083.          int            TimeDiff ;
  1084.  
  1085.          LP = PlaybackLog.StartIndexPos ;
  1086.  
  1087.          if (LogPositionSystemTime (&LP, &FirstSystemTime))
  1088.             {
  1089.             // we don't want to append data to the log file if
  1090.             // the time is not in order.  So, forget it if the
  1091.             // last log time in the Log file is greater than the First
  1092.             // log time of the playback log file.
  1093.             TimeDiff = SystemTimeDifference (&(FirstSystemTime),
  1094.                                              &(pLog->LastLogTime)) ;
  1095.             if (TimeDiff > 0)
  1096.                {
  1097.                // error , time not in order
  1098.                CloseHandle (pLog->hFile) ;
  1099.                RetCode = ERR_CANT_RELOG_DATA ;
  1100.                }
  1101.             }
  1102.          }
  1103.       
  1104.       if (RetCode == 0)
  1105.          {
  1106.          // write counter names if needed
  1107.          LogWriteSystemCounterNames (hWnd, pLog) ;
  1108.          return (TRUE) ;
  1109.          }
  1110.       }
  1111.  
  1112. ErrorExit:
  1113.    pLog->hFile = 0 ;
  1114.    CloseLogStopTimer(hWnd, pLog);
  1115.    PrepareMenu (GetMenu (hWndMain)) ;
  1116.    UpdateLogDisplay (hWnd) ;
  1117.    if (RetCode)
  1118.       {
  1119.       DlgErrorBox (hWnd, RetCode, pLog->szFilePath);
  1120.       }
  1121.    return (FALSE) ;
  1122.    }
  1123.  
  1124.  
  1125.  
  1126. DWORD LogFindEntry(LPTSTR lpszComputer, DWORD ObjectTitleIndex)
  1127. /*
  1128.    Effect:         Returns the index of the specified Computer/Object
  1129.                    if it already exists in the Entries List Box,
  1130.                    otherwise returns LOG_ENTRY_NOT_FOUND
  1131. */
  1132.    {
  1133.    DWORD          iLogEntry ;
  1134.    DWORD          iLogNum ;
  1135.    PLOGENTRY      pLogEntry ;
  1136.  
  1137.    iLogNum = (DWORD) LBNumItems(hWndLogEntries) ;
  1138.    for (iLogEntry = 0;
  1139.         iLogEntry < iLogNum ;
  1140.         iLogEntry++)
  1141.       {
  1142.       pLogEntry = (PLOGENTRY) LBData(hWndLogEntries, iLogEntry) ;
  1143.       if (pLogEntry->ObjectTitleIndex == ObjectTitleIndex &&
  1144.           strsamei(pLogEntry->szComputer, lpszComputer))
  1145.          {
  1146.          return iLogEntry ;
  1147.          }
  1148.       }
  1149.    return (DWORD) LOG_ENTRY_NOT_FOUND;
  1150.    }
  1151.  
  1152.  
  1153.  
  1154. BOOL LogAddEntry (HWND hWndLog,
  1155.                   LPTSTR lpszComputer,
  1156.                   LPTSTR lpszObject,
  1157.                   DWORD ObjectTitleIndex,
  1158.                   BOOL  bGetObjectTitleIndex)
  1159. /*
  1160.    Effect:        Add an entry in the log structure for the computer and
  1161.                   object to be logged.
  1162.  
  1163.    Returns:       Whether the operation could be performed.
  1164. */
  1165.    {  // LogAddEntry
  1166.    PLOG           pLog ;
  1167.    PLOGENTRY      pLogEntry ;
  1168.    UINT           iIndex ;
  1169.    PPERFSYSTEM    pCurrentSystem = NULL ;
  1170.    DWORD          CurrentObjectTitleIndex ;
  1171.  
  1172.  
  1173.    pLog = LogData (hWndLog) ;
  1174.    
  1175.    pCurrentSystem = SystemAdd (&(pLog->pSystemFirst), lpszComputer) ;
  1176.  
  1177.    pLogEntry = MemoryAllocate (sizeof (LOGENTRY)) ;
  1178.    if (!pLogEntry)
  1179.       return (FALSE) ;
  1180.  
  1181.    lstrcpy (pLogEntry->szComputer, lpszComputer) ;
  1182.    lstrcpy (pLogEntry->szObject, lpszObject) ;
  1183.  
  1184.    pLogEntry->ObjectTitleIndex = ObjectTitleIndex ;
  1185.  
  1186.    // if reading from a log setting file, get the 
  1187.    // latest Object index by the perfdata itself.
  1188.    // There may be case that the id has been changed
  1189.    if (bGetObjectTitleIndex &&
  1190.       pCurrentSystem &&
  1191.       pCurrentSystem->pSystemPerfData)
  1192.       {
  1193.       if (pCurrentSystem->pSystemPerfData->Signature[0] == TEXT('\0'))
  1194.          {
  1195.          UpdateSystemData (
  1196.             pCurrentSystem,
  1197.             &(pCurrentSystem->pSystemPerfData)) ;
  1198.          }
  1199.  
  1200.       if (CurrentObjectTitleIndex = GetObjectIdByName(
  1201.          pCurrentSystem,
  1202.          pCurrentSystem->pSystemPerfData,
  1203.          lpszObject))
  1204.          {
  1205.          pLogEntry->ObjectTitleIndex = CurrentObjectTitleIndex ;
  1206.          }
  1207.       }
  1208.  
  1209.    iIndex = LBAdd (hWndLogEntries, pLogEntry) ;
  1210.  
  1211.    if (!bDelayAddAction)
  1212.       {
  1213.       if (iIndex == LB_ERR)
  1214.          {
  1215.          iIndex = 0 ;
  1216.          }
  1217.  
  1218.       LBSetSelection (hWndLogEntries, iIndex) ;
  1219.       LBSetVisible (hWndLogEntries, iIndex) ;
  1220.  
  1221.       LogEntriesChanged (hWndLogEntries) ;
  1222.       }
  1223.  
  1224.    LogAddEntryToList (&(pLog->pLogEntryFirst), pLogEntry) ;
  1225.  
  1226.  
  1227.    }  // LogAddEntry
  1228.  
  1229.  
  1230.  
  1231.  
  1232. BOOL ToggleLogRefresh (HWND hWnd)
  1233.    {  // ToggleLogRefresh
  1234.    PLOG        pLog ;
  1235.  
  1236.    pLog = LogData (hWnd) ;
  1237.  
  1238.    if (pLog->bManualRefresh)
  1239.       SetLogTimer (hWnd, pLog->iIntervalMSecs) ;
  1240.    else
  1241.       ClearLogTimer (hWnd) ;
  1242.  
  1243.    pLog->bManualRefresh = !pLog->bManualRefresh ;
  1244.    return (pLog->bManualRefresh) ;
  1245.    }  // ToggleLogRefresh
  1246.  
  1247. BOOL LogRefresh (HWND hWnd)
  1248.    {  // LogRefresh
  1249.    PLOG        pLog ;
  1250.  
  1251.    pLog = LogData (hWnd) ;
  1252.  
  1253.    return (pLog->bManualRefresh) ;
  1254.    }  // LogRefresh
  1255.  
  1256. BOOL  CheckUnusedSystem (LPTSTR      lpszComputer)
  1257. {
  1258.    BOOL  bStillUse = FALSE ;
  1259.    PLOGENTRY      pLogEntry ;
  1260.    PLOG           pLog ;
  1261.  
  1262.    pLog = LogData (hWndLog) ;
  1263.  
  1264.    for (pLogEntry = pLog->pLogEntryFirst ;
  1265.         pLogEntry ;
  1266.         pLogEntry = pLogEntry->pNextLogEntry)
  1267.       { // for
  1268.       if (strsamei(pLogEntry->szComputer, lpszComputer))
  1269.          {
  1270.          bStillUse = TRUE ;
  1271.          break ;
  1272.          }
  1273.       }
  1274.    return (bStillUse) ;
  1275. }
  1276.  
  1277. int SelectLogObjects(LPTSTR      lpszComputer,
  1278.                      PPERFDATA   pPerfData,
  1279.                      PPERFDATA   *ppLogData)
  1280. /*
  1281.    Effect:        This routine copies the header from pPerfData
  1282.                   to pLogData and initializes the byte length and the
  1283.                   number of objects.  It then copies the previously
  1284.                   selected objects from pPerfData to pLogData.  If
  1285.                   pLogData must be enlarged to accomodate the new data,
  1286.                   this routine will enlarge it.
  1287.  
  1288.    Returns:       An updated pLogData, and TRUE if at least one object
  1289.                   was copied.
  1290.  
  1291. */
  1292.  
  1293.    {
  1294.    PLOGENTRY      pLogEntry ;
  1295.    PPERF_OBJECT_TYPE
  1296.                   pObject ;
  1297.    DWORD          TotalBytes ;
  1298.    DWORD          NumObjects ;
  1299.    PBYTE          pNextObject ;
  1300.    DWORD          MaxLogDataSize ;
  1301.    PLOG           pLog ;
  1302.  
  1303.    if (!*ppLogData || !pPerfData)
  1304.       return -1 ;
  1305.  
  1306.    memcpy (*ppLogData, pPerfData, pPerfData->HeaderLength) ;
  1307.    TotalBytes = pPerfData->HeaderLength ;
  1308.    MaxLogDataSize = MemorySize(*ppLogData) ;
  1309.    NumObjects = 0;
  1310.  
  1311.    
  1312.    pLog = LogData (hWndLog) ;
  1313.  
  1314.    for (pLogEntry = pLog->pLogEntryFirst ;
  1315.         pLogEntry ;
  1316.         pLogEntry = pLogEntry->pNextLogEntry)
  1317.       { // for
  1318.       if (strsamei(pLogEntry->szComputer, lpszComputer))
  1319.          {
  1320.          pObject = GetObjectDefByTitleIndex(pPerfData,
  1321.             pLogEntry->ObjectTitleIndex) ;
  1322.  
  1323.          if (pObject)
  1324.             {
  1325.             if (MaxLogDataSize < TotalBytes + pObject->TotalByteLength)
  1326.                {
  1327.                *ppLogData = MemoryResize(*ppLogData,
  1328.                                          TotalBytes + pObject->TotalByteLength) ;
  1329.                if (!*ppLogData)
  1330.                   return -1 ;
  1331.  
  1332.                }
  1333.  
  1334.             pNextObject = (PBYTE) *ppLogData + TotalBytes ;
  1335.             memcpy (pNextObject, pObject, pObject->TotalByteLength);
  1336.             TotalBytes += pObject->TotalByteLength ;
  1337.             NumObjects++;
  1338.             }
  1339.          else
  1340.             {
  1341.             }
  1342.          }
  1343.       } // for
  1344.  
  1345.    if (!NumObjects)
  1346.       return 1 ;
  1347.  
  1348.    (*ppLogData)->TotalByteLength = TotalBytes ;
  1349.    (*ppLogData)->NumObjectTypes = NumObjects ;
  1350.  
  1351.    return 0 ;
  1352.    }
  1353.  
  1354.  
  1355. void LogTimer (HWND hWnd, BOOL bForce)
  1356. /*
  1357.    Effect:        Perform all actions necessary when the log window 
  1358.                   receives a timer tic. In particular, if we are
  1359.                   collecting data, get a new perf_data_block and add a 
  1360.                   header entry. If the header block is full, write the
  1361.                   data to disk.
  1362.  
  1363.    Called By:     LogDisplayDlgProc, in response to a WM_TIMER message.
  1364. */
  1365.    {  // OnTimer
  1366.    PLOG           pLog ;
  1367.    PPERFSYSTEM       pSystem ;
  1368.    BOOL           bWriteIndex ;
  1369.    DWORD          iNumSystems ;
  1370.    SYSTEMTIME     SystemTime ;
  1371.    int            iNoUseSystemDetected = 0 ;
  1372.  
  1373.    int               NumberOfSystems = 0 ;
  1374.    DWORD             WaitStatus ;
  1375.    BOOL              bNeedToStoreName = FALSE ;
  1376.    HANDLE            *lpPacketHandles ;
  1377.  
  1378.  
  1379.    pLog = LogData (hWnd) ;
  1380.  
  1381.    if (pLog->iStatus != iPMStatusCollecting)
  1382.       return ;
  1383.  
  1384.    if (bForce || !pLog->bManualRefresh) 
  1385.       {
  1386.       if (pLog->NumberOfHandles == 0)
  1387.          {
  1388.          pLog->NumberOfHandles = MAXIMUM_WAIT_OBJECTS ;
  1389.          pLog->lpHandles = (HANDLE *) MemoryAllocate (pLog->NumberOfHandles * sizeof (HANDLE)) ;
  1390.          if (!pLog->lpHandles)
  1391.             {
  1392.             // out of memory, can't go on
  1393.             pLog->NumberOfHandles = 0 ;
  1394.             return ;
  1395.             }
  1396.          }
  1397.  
  1398.       iNumSystems = SystemCount(pLog->pSystemFirst) ;
  1399.       bWriteIndex = TRUE ;
  1400.  
  1401.       for (pSystem = pLog->pSystemFirst ;
  1402.            pSystem ;
  1403.            pSystem = pSystem->pSystemNext)
  1404.          {  // for
  1405.       
  1406.          if (pSystem->hStateDataMutex == 0)
  1407.             continue ;
  1408.  
  1409.          // lock the state data mutex
  1410.          WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L);
  1411.          if (WaitStatus == WAIT_OBJECT_0)
  1412.             {
  1413.             ResetEvent (pSystem->hPerfDataEvent) ;
  1414.             pSystem->StateData = WAIT_FOR_PERF_DATA ;
  1415.  
  1416.             if (NumberOfSystems >= pLog->NumberOfHandles)
  1417.                {
  1418.                pLog->NumberOfHandles += MAXIMUM_WAIT_OBJECTS ;
  1419.                pLog->lpHandles = (HANDLE *) MemoryResize (
  1420.                   pLog->lpHandles,
  1421.                   pLog->NumberOfHandles * sizeof (HANDLE)) ;
  1422.                if (!pLog->lpHandles)
  1423.                   {
  1424.                   // out of memory, can't go on
  1425.                   pLog->NumberOfHandles = 0 ;
  1426.                   return ;
  1427.                   }
  1428.                }
  1429.  
  1430.             // add this to the wait
  1431.             pLog->lpHandles [NumberOfSystems] = pSystem->hPerfDataEvent ;
  1432.             NumberOfSystems++ ;
  1433.             }
  1434.  
  1435.          // Send Message to thread to take a data sample
  1436.          PostThreadMessage (
  1437.             pSystem->dwThreadID,
  1438.             WM_GET_PERF_DATA,
  1439.             (WPARAM)0,
  1440.             (LPARAM)0) ;
  1441.  
  1442.          ReleaseMutex(pSystem->hStateDataMutex);
  1443.          }  // for each system
  1444.  
  1445.       // wait for all the data 
  1446.       if (NumberOfSystems)
  1447.          {
  1448.          // increase timeout if we are monitoring lots of systems
  1449.          // For every additional 5 systems, add five more seconds
  1450.          lpPacketHandles = pLog->lpHandles ;
  1451.          do
  1452.             {
  1453.             WaitStatus = WaitForMultipleObjects (
  1454.                min (NumberOfSystems, MAXIMUM_WAIT_OBJECTS),
  1455.                lpPacketHandles,
  1456.                TRUE,       // wait for all objects
  1457.                DataTimeOut + (NumberOfSystems / 5) * DEFAULT_DATA_TIMEOUT);
  1458.          
  1459.             if (WaitStatus == WAIT_TIMEOUT ||
  1460.                NumberOfSystems <= MAXIMUM_WAIT_OBJECTS)
  1461.                {
  1462. //if (WaitStatus == WAIT_TIMEOUT)
  1463. //mike2(TEXT("WaitTimeOut for %ld systems\n"), NumberOfSystems) ;
  1464.                break ;
  1465.                }
  1466.  
  1467.             // more systems --> more to wait
  1468.             NumberOfSystems -= MAXIMUM_WAIT_OBJECTS ;
  1469.             lpPacketHandles += MAXIMUM_WAIT_OBJECTS ;
  1470.             } while (TRUE) ;
  1471.  
  1472.  
  1473.          for (pSystem = pLog->pSystemFirst ;
  1474.               pSystem ;
  1475.               pSystem = pSystem->pSystemNext)
  1476.             {  // for
  1477.       
  1478.             if (pSystem->hStateDataMutex == 0)
  1479.                continue ;
  1480.  
  1481.             // lock the state data mutex
  1482.             WaitStatus = WaitForSingleObject(pSystem->hStateDataMutex, 100L);
  1483.             if (WaitStatus == WAIT_OBJECT_0)
  1484.                {
  1485.                // check for system disconnect/reconnect
  1486.                if (pSystem->dwSystemState == SYSTEM_DOWN ||
  1487.                    pSystem->dwSystemState == SYSTEM_RECONNECT)
  1488.                   {
  1489.                   BOOL  bDisconnected ;
  1490.  
  1491.                   GetLocalTime (&SystemTime) ;
  1492.                   if (bDisconnected = (pSystem->dwSystemState == SYSTEM_DOWN))
  1493.                      {
  1494.                      pSystem->dwSystemState = SYSTEM_DOWN_RPT ;
  1495.                      }
  1496.                   else
  1497.                      {
  1498.                      pSystem->dwSystemState = SYSTEM_RECONNECT_RPT ;
  1499.                      }
  1500.                   if (!LogWriteSystemBookmark (
  1501.                      hWnd,
  1502.                      pSystem->sysName,
  1503.                      bDisconnected,
  1504.                      &SystemTime))
  1505.                      {
  1506.                      pSystem->StateData = IDLE_STATE ;
  1507.                      ReleaseMutex(pSystem->hStateDataMutex);
  1508.                      return ;
  1509.                      }
  1510.                   }
  1511.  
  1512.                if (pSystem->StateData == PERF_DATA_READY)
  1513.                   {
  1514.                   if (pSystem->bSystemCounterNameSaved == FALSE)
  1515.                      {
  1516.                      // we have not written the system name to log file.  This
  1517.                      // is the case when this system is down when we first
  1518.                      // start logging data...
  1519.                      bNeedToStoreName = TRUE ;
  1520.                      }
  1521.  
  1522.                   if (bWriteIndex)
  1523.                      {
  1524.                      GetLocalTime (&SystemTime) ;
  1525.                      }
  1526.  
  1527.                   if (SelectLogObjects(pSystem->sysName,
  1528.                      pSystem->pSystemPerfData,
  1529.                      &pLog->pLogData) == 0)
  1530.                      {
  1531.                      if ( !LogWritePerfData (hWnd, pLog, pLog->pLogData, &SystemTime,
  1532.                         iNumSystems, bWriteIndex) )
  1533.                         {
  1534.                         CloseLogStopTimer(hWnd, pLog) ;
  1535.  
  1536.                         pSystem->StateData = IDLE_STATE ;
  1537.                         ReleaseMutex(pSystem->hStateDataMutex);
  1538.  
  1539.                         return ;
  1540.                         }
  1541.                      // write an index for only the first system
  1542.                      bWriteIndex = FALSE ;
  1543.                      }
  1544.                   else
  1545.                      {
  1546.                      if (!bAddLineInProgress)
  1547.                         {
  1548.                         pSystem->bSystemNoLongerNeeded = TRUE ;
  1549.                         iNoUseSystemDetected ++ ;
  1550.                         }
  1551.                      }
  1552.                   }  // if PERF_DATA_READY
  1553.                else if (!bAddLineInProgress &&
  1554.                   CheckUnusedSystem (pSystem->sysName) == FALSE)
  1555.                   {
  1556.                   // we don't need this system any more
  1557.                   pSystem->bSystemNoLongerNeeded = TRUE ;
  1558.                   iNoUseSystemDetected ++ ;
  1559.                   }
  1560.  
  1561.                pSystem->StateData = IDLE_STATE ;
  1562.                ReleaseMutex(pSystem->hStateDataMutex);
  1563.                }  // wait for StateDataMutex
  1564.             }  // For each system
  1565.          }  // if NumberOfSystems
  1566.  
  1567.       if (!bWriteIndex)
  1568.          {
  1569.          UpdateLogSize (hWnd) ;
  1570.          }
  1571.       }  // if
  1572.  
  1573.    if (iNoUseSystemDetected)
  1574.       {
  1575.       DeleteUnusedSystems (&(pLog->pSystemFirst), iNoUseSystemDetected) ;
  1576.       }
  1577.  
  1578.    if (bNeedToStoreName == TRUE)
  1579.       {
  1580.       LogWriteSystemCounterNames (hWnd, pLog) ;
  1581.       }
  1582.    }  // LogTimer
  1583.  
  1584.  
  1585.  
  1586. BOOL NextIntervalIndexPosition (PLOG pLog, PLOGPOSITION pLP, int *pNumTics)
  1587.    { 
  1588.    SYSTEMTIME     SystemTime1 ;
  1589.    SYSTEMTIME     SystemTime2 ;
  1590.    LOGPOSITION    LP ;
  1591.    PLOGINDEX      pIndex ;
  1592.    DWORD          TimeDiff ;
  1593.  
  1594.    LogPositionSystemTime (pLP, &SystemTime1) ;
  1595.  
  1596.    LP = *pLP ;
  1597.  
  1598.    while (NextReLogIndexPosition (&LP))
  1599.       {  // while
  1600.  
  1601.       *pNumTics = *pNumTics - 1 ;
  1602.  
  1603.       pIndex = IndexFromPosition (&LP) ;
  1604.       if (pIndex && IsBookmarkIndex (pIndex))
  1605.          {
  1606.          *pLP = LP ;
  1607.          return TRUE ;
  1608.          }
  1609.       LogPositionSystemTime (&LP, &SystemTime2) ;
  1610.       TimeDiff = (DWORD) SystemTimeDifference (&SystemTime1, &SystemTime2) ;
  1611.       if (TimeDiff * 1000 >= pLog->iIntervalMSecs)
  1612.          {  // if
  1613.          *pLP = LP ;
  1614.          return (TRUE) ;
  1615.          }  // if
  1616.       }  // while
  1617.  
  1618.    return (FALSE) ;
  1619.    }  // NextIntervalIndexPosition
  1620.  
  1621.  
  1622.  
  1623. BOOL ReLogTimer (HWND hWnd,
  1624.                  PLOG pLog,
  1625.                  LOGPOSITION lp,
  1626.                  BOOL *pWriteBookmark)
  1627.    {  // ReLogTimer
  1628.    PPERFSYSTEM    pSystem ;
  1629.    BOOL           bWriteIndex ;
  1630.    DWORD          iNumSystems ;
  1631.    SYSTEMTIME     SystemTime ;
  1632.    PPERFDATA      pPerfData ;
  1633.  
  1634.    bWriteIndex = TRUE ;
  1635.  
  1636.    // First count number of systems to be logged
  1637.  
  1638.    iNumSystems = 0;
  1639.  
  1640.    for (pSystem = pLog->pSystemFirst ;
  1641.         pSystem ;
  1642.         pSystem = pSystem->pSystemNext)
  1643.       {  // for
  1644.       pPerfData = LogDataFromPosition (pSystem, &lp) ;
  1645.       if (pPerfData)
  1646.          {
  1647.          if (SelectLogObjects(pSystem->sysName,
  1648.                               pPerfData,
  1649.                               &pLog->pLogData) == 0)
  1650.             {
  1651.             iNumSystems++;
  1652.             }
  1653.          }
  1654.       }  // for
  1655.  
  1656.    // Now we can log the data
  1657.  
  1658.    for (pSystem = pLog->pSystemFirst ;
  1659.         pSystem ;
  1660.         pSystem = pSystem->pSystemNext)
  1661.       {  // for
  1662.       pPerfData = LogDataFromPosition (pSystem, &lp) ;
  1663.       if (pPerfData)
  1664.          {
  1665.          // write an index for only the first system
  1666.          LogPositionSystemTime (&lp, &SystemTime) ;
  1667.          if (SelectLogObjects(pSystem->sysName,
  1668.                               pPerfData,
  1669.                               &pLog->pLogData) == 0)
  1670.             {
  1671.             if (*pWriteBookmark)
  1672.                {
  1673.                // only need to write the start bookmark once.
  1674.                *pWriteBookmark = FALSE ;
  1675.                LogWriteStartBookmark (hWnd, &SystemTime) ;
  1676.                }
  1677.             if ( !LogWritePerfData (hWnd, pLog, pLog->pLogData, &SystemTime,
  1678.                                     iNumSystems, bWriteIndex) )
  1679.                {
  1680.                CloseLogStopTimer(hWnd, pLog) ;
  1681.                return FALSE ;
  1682.                }
  1683.             else
  1684.                {
  1685.                // write the index for only the first system logged
  1686.                bWriteIndex = FALSE ;
  1687.                }
  1688.             }
  1689.          }
  1690.       }  // for
  1691.  
  1692.    return TRUE ;
  1693.    }  // ReLogTimer
  1694.  
  1695.  
  1696. void ReLog (HWND hWndLog, BOOL bSameFile)
  1697.    {  // PlaybackLog
  1698.    PLOG           pLog ;
  1699.    LOGPOSITION    lp ;
  1700. //   SYSTEMTIME     SystemTime ;
  1701.    PLOGINDEX      pIndex ;
  1702.    PBOOKMARK      pBookmark;
  1703.    int            iDisplayTics ;
  1704.  
  1705.    // bWriteBookmark tell relogtimer to write start bookmark
  1706.    BOOL           bWriteBookmark = TRUE ;    
  1707.  
  1708.    pLog = LogData (hWndLog) ;
  1709.    if (StartLog (hWndLog, pLog, bSameFile) == FALSE)
  1710.       {
  1711.       return ;
  1712.       }
  1713.  
  1714.    lp = PlaybackLog.StartIndexPos ;
  1715.    iDisplayTics = PlaybackLog.iSelectedTics;
  1716.  
  1717.    while (iDisplayTics > 0)
  1718.       {
  1719.       pIndex = IndexFromPosition (&lp) ;
  1720.       if (pIndex)
  1721.          {
  1722.          if (IsBookmarkIndex (pIndex))
  1723.             {
  1724.             pBookmark = (PBOOKMARK) PlaybackSeek (pIndex->lDataOffset) ;
  1725.             if (!LogWriteBookmarkData (hWndLog, pBookmark))
  1726.                break;
  1727.             }
  1728.          else if (!ReLogTimer (hWndLog, pLog, lp, &bWriteBookmark))
  1729.             break ;
  1730.          }
  1731.       
  1732.       if (!NextIntervalIndexPosition (pLog, &lp, &iDisplayTics))
  1733.          break ;
  1734.       
  1735.       }  // while
  1736.    UpdateLogSize (hWndLog) ;
  1737.    CloseLog (hWndLog, pLog) ;
  1738.    }  // ReLog
  1739.  
  1740. // SaveLog is diff than other because we are not saving a "Line"
  1741. // We are actually saving an entry in the hWndLogEntries listbox.
  1742. // It only contains the system & object name.
  1743. BOOL SaveLog (HWND hWndLog, HANDLE hInputFile, BOOL bGetFileName)
  1744.    {
  1745.    int         iIndex, iIndexNum ;
  1746.    PLOG        pLog ;
  1747.    PLOGENTRY   pLogEntry ;
  1748.    LOGENTRY       tempLogEntry ;
  1749.    HANDLE         hFile ;
  1750.    DISKLOG        DiskLog ;
  1751.    PERFFILEHEADER FileHeader ;
  1752.    TCHAR          szFileName [256] ;
  1753.    BOOL           newFileName = FALSE ;
  1754.  
  1755.    pLog = LogData (hWndLog) ;
  1756.    if (!pLog)
  1757.       {
  1758.       return (FALSE) ;
  1759.       }
  1760.  
  1761.    if (hInputFile)
  1762.       {
  1763.       // use the input file handle if it is available
  1764.       // this is the case for saving workspace data
  1765.       hFile = hInputFile ;
  1766.       }
  1767.    else
  1768.       {
  1769.       if (pLogFullFileName)
  1770.          {
  1771.          lstrcpy (szFileName, pLogFullFileName) ;
  1772.          }
  1773.       if (bGetFileName || pLogFullFileName == NULL)
  1774.          {
  1775. //         if (pLogFullFileName == NULL)
  1776. //            {
  1777. //            StringLoad (IDS_LOG_FNAME, szFileName) ;
  1778. //            }
  1779.  
  1780.          if (!FileGetName (hWndLog, IDS_LOGFILE, szFileName))
  1781.             {
  1782.             return (FALSE) ;
  1783.             }
  1784.          newFileName = TRUE ;
  1785.          }
  1786.  
  1787.       hFile = FileHandleCreate (szFileName) ;
  1788.  
  1789.       if (hFile && newFileName)
  1790.          {
  1791.          ChangeSaveFileName (szFileName, IDM_VIEWLOG) ;
  1792.          }
  1793.       else if (!hFile)
  1794.          {
  1795.          DlgErrorBox (hWndLog, ERR_CANT_OPEN, szFileName) ;
  1796.          }
  1797.       }
  1798.  
  1799.    if (!hFile)
  1800.       return (FALSE) ;
  1801.  
  1802.    iIndexNum = LBNumItems (hWndLogEntries) ;
  1803.  
  1804.    if (!hInputFile)
  1805.       {
  1806.       memset (&FileHeader, 0, sizeof (FileHeader)) ;
  1807.       lstrcpy (FileHeader.szSignature, szPerfLogSignature) ;
  1808.       FileHeader.dwMajorVersion = LogMajorVersion ;
  1809.       FileHeader.dwMinorVersion = LogMinorVersion ;
  1810.    
  1811.       if (!FileWrite (hFile, &FileHeader, sizeof (PERFFILEHEADER)))
  1812.          {
  1813.          goto Exit0 ;
  1814.          }
  1815.       }
  1816.  
  1817.    DiskLog.dwIntervalSecs = pLog->iIntervalMSecs ;
  1818.    DiskLog.dwNumLines = iIndexNum ;
  1819.    DiskLog.bManualRefresh = pLog->bManualRefresh ;
  1820.    DiskLog.perfmonOptions = Options ;
  1821.    lstrcpy(DiskLog.LogFileName, pLog->szFilePath) ;
  1822.  
  1823.    if (!FileWrite (hFile, &DiskLog, sizeof (DISKLOG)))
  1824.       {
  1825.       goto Exit0 ;
  1826.       }
  1827.  
  1828.    for (iIndex = 0 ;
  1829.         iIndex < iIndexNum ;
  1830.         iIndex++)
  1831.       {  // for
  1832.       pLogEntry = LogEntryN (hWndLogEntries, iIndex) ;
  1833.       if (pstrsamei (pLogEntry->szComputer, LocalComputerName))
  1834.          {
  1835.          tempLogEntry = *pLogEntry ;
  1836.          lstrcpy (tempLogEntry.szComputer, LOCAL_SYS_CODE_NAME) ;
  1837.          if (!FileWrite (hFile,
  1838.                &tempLogEntry,
  1839.                sizeof(LOGENTRY)-sizeof(pLogEntry->pNextLogEntry)))
  1840.             {
  1841.             goto Exit0 ;
  1842.             }
  1843.          }
  1844.       else
  1845.          {
  1846.          if (!FileWrite (hFile,
  1847.                pLogEntry,
  1848.                sizeof(LOGENTRY)-sizeof(pLogEntry->pNextLogEntry)))
  1849.             {
  1850.             goto Exit0 ;
  1851.             }
  1852.          }
  1853.       }  // for
  1854.  
  1855.    if (!hInputFile)
  1856.       {
  1857.       CloseHandle (hFile) ;
  1858.       }
  1859.  
  1860.    return (TRUE) ;
  1861.  
  1862. Exit0:
  1863.    if (!hInputFile)
  1864.       {
  1865.       CloseHandle (hFile) ;
  1866.  
  1867.       // only need to report error if not workspace 
  1868.       DlgErrorBox (hWndLog, ERR_SETTING_FILE, szFileName) ;
  1869.       }
  1870.    return (FALSE) ;
  1871.    }
  1872.  
  1873. BOOL OpenLogVer1 (HWND hWndLog, HANDLE hFile, DISKLOG *pDiskLog, PLOG
  1874.    pLog, DWORD dwMinorVersion)
  1875.    {
  1876.    int            iIndex, iIndexNum ;
  1877.    PLOGENTRY      pLogEntry ;
  1878.    LOGENTRY       LogEntry ;
  1879.    PPERFSYSTEM    pSystem;
  1880.  
  1881.    pLog->iIntervalMSecs = pDiskLog->dwIntervalSecs ;
  1882.    if (dwMinorVersion < 3)
  1883.       {
  1884.       pLog->iIntervalMSecs *= 1000 ;
  1885.       }
  1886.  
  1887.    pLog->lFileSize = 0L ;
  1888.    if (dwMinorVersion >= 5)
  1889.       {
  1890.       lstrcpy (pLog->szFilePath, pDiskLog->LogFileName) ;
  1891.       }
  1892.    else
  1893.       {
  1894.       strclr (pLog->szFilePath) ;
  1895.  
  1896.       // fixed the file pointer for backward compatible with older version.
  1897. //      FileSeekCurrent (hFile, -((int) (sizeof (pDiskLog->LogFileName)))) ;
  1898.       }
  1899.  
  1900.    pLog->bManualRefresh = pDiskLog->bManualRefresh ;
  1901.    iIndexNum = pDiskLog->dwNumLines ;
  1902.  
  1903.    LBSetRedraw (hWndLogEntries, FALSE) ;
  1904.  
  1905.    bDelayAddAction = TRUE ;
  1906.  
  1907.    for (iIndex = 0 ; iIndex < iIndexNum ; iIndex++)
  1908.       {
  1909.       if (!FileRead (hFile,
  1910.             &LogEntry,
  1911.             sizeof(LOGENTRY)-sizeof(LogEntry.pNextLogEntry)))
  1912.          {
  1913.          break ;
  1914.          }
  1915.  
  1916.       if (pstrsame (LogEntry.szComputer, LOCAL_SYS_CODE_NAME))
  1917.          {
  1918.          // convert it back to the local name
  1919.          lstrcpy (LogEntry.szComputer, LocalComputerName) ;
  1920.          }
  1921.  
  1922.       LogAddEntry (hWndLog,
  1923.                   LogEntry.szComputer,
  1924.                   LogEntry.szObject,
  1925.                   LogEntry.ObjectTitleIndex,
  1926.                   TRUE) ;
  1927.       }
  1928.    
  1929.    bDelayAddAction = FALSE ;
  1930.  
  1931.    LBSetSelection (hWndLogEntries, 0) ;
  1932.    LBSetVisible (hWndLogEntries, 0) ;
  1933.  
  1934.    LogEntriesChanged (hWndLogEntries) ;
  1935.  
  1936.    LBSetRedraw (hWndLogEntries, TRUE) ;
  1937.  
  1938.    for (pSystem = pLog->pSystemFirst ;
  1939.       pSystem ;
  1940.       pSystem = pSystem->pSystemNext)
  1941.       {
  1942.       if (pSystem)
  1943.          {
  1944.          RemoveObjectsFromSystem (pSystem);
  1945.          }
  1946.       }
  1947.  
  1948.  
  1949.    for (iIndex = 0 ;
  1950.         iIndex < iIndexNum ;
  1951.         iIndex++)
  1952.       {  // for all items in the list
  1953.       pLogEntry = LogEntryN (hWndLogEntries, iIndex) ;
  1954.  
  1955.       pSystem = SystemGet (pLog->pSystemFirst, pLogEntry->szComputer);
  1956.       if (pSystem)
  1957.          {
  1958.          AppendObjectToValueList (
  1959.                 pLogEntry->ObjectTitleIndex,
  1960.                 pSystem->lpszValue);
  1961.          } 
  1962.       }  // for
  1963.  
  1964.    if (!strempty(pLog->szFilePath))
  1965.       {
  1966.       if (pLog->pLogEntryFirst &&
  1967.           pLog->pSystemFirst)
  1968.          {
  1969.          // PostMessage so it will start logging
  1970.          PostMessage (
  1971.             hWndLog,
  1972.             WM_START_LOGGING,
  1973.             0,
  1974.             0) ;
  1975.          }
  1976.       else
  1977.          {
  1978.          HANDLE   hLogFile ;
  1979.  
  1980.          // get the file size.
  1981.          hLogFile = FileHandleOpen (pLog->szFilePath) ;
  1982.  
  1983.          if (hLogFile && hLogFile != INVALID_HANDLE_VALUE)
  1984.             {
  1985.             pLog->lFileSize = GetFileSize (hLogFile, NULL);
  1986.             CloseHandle (hLogFile) ;
  1987.             }
  1988.          }
  1989.       }
  1990.  
  1991.    return (TRUE) ;
  1992.    }
  1993.  
  1994. BOOL OpenLog (HWND hWndLog,
  1995.               HANDLE hFile,
  1996.               DWORD dwMajorVersion,
  1997.               DWORD dwMinorVersion,
  1998.               BOOL bLogFile)
  1999.    {
  2000.    PLOG        pLog ;
  2001.    DISKLOG     DiskLog ;
  2002.    BOOL        bSuccess = TRUE ;
  2003.  
  2004.    pLog = LogData (hWndLog) ;
  2005.    if (!pLog)
  2006.       {
  2007.       bSuccess = FALSE ;
  2008.       goto Exit0 ;
  2009.       }
  2010.  
  2011.    if (!FileRead (hFile, &DiskLog, sizeof (DISKLOG) - sizeof(DiskLog.LogFileName)))
  2012.       {
  2013.       bSuccess = FALSE ;
  2014.       goto Exit0 ;
  2015.       }
  2016.  
  2017.    if (dwMajorVersion == 1 && dwMinorVersion >= 5 ||
  2018.       dwMajorVersion > 1)
  2019.       {
  2020.       // read LogFileName
  2021.       if (!FileRead (hFile, DiskLog.LogFileName, sizeof (DiskLog.LogFileName)))
  2022.          {
  2023.          bSuccess = FALSE ;
  2024.          goto Exit0 ;
  2025.          }
  2026.       }
  2027.  
  2028.    switch (dwMajorVersion)
  2029.       {  
  2030.       case (1):
  2031.  
  2032.          SetHourglassCursor() ;
  2033.          
  2034.          ResetLogView (hWndLog) ;
  2035.  
  2036.          OpenLogVer1 (hWndLog, hFile, &DiskLog, pLog, dwMinorVersion) ;
  2037.  
  2038.          // change to log view if we are opening a 
  2039.          // log file
  2040.          if (bLogFile && iPerfmonView != IDM_VIEWLOG)
  2041.             {
  2042.             SendMessage (hWndMain, WM_COMMAND, (LONG)IDM_VIEWLOG, 0L) ;
  2043.             }
  2044.  
  2045.          if (iPerfmonView == IDM_VIEWLOG)
  2046.             {
  2047.             SetPerfmonOptions (&DiskLog.perfmonOptions) ;
  2048.             }
  2049.          
  2050.          UpdateLogDisplay (hWndLog) ;   
  2051.          
  2052.          SetArrowCursor() ;
  2053.          
  2054.          break ;
  2055.       }
  2056.  
  2057. Exit0:
  2058.  
  2059.    if (bLogFile)
  2060.       {
  2061.       CloseHandle (hFile) ;
  2062.       }
  2063.  
  2064.    return (bSuccess) ;
  2065.    }  // OpenLog
  2066.  
  2067.  
  2068. BOOL LogCollecting (HWND hWndLog)
  2069. /*
  2070.    Effect:        Return whether the log associated with hWndLog is currently
  2071.                   collecting data (writing performance values to disk).
  2072. */
  2073.    {  // LogCollecting
  2074.    PLOG           pLog ;
  2075.  
  2076.    pLog = LogData (hWndLog) ;
  2077.  
  2078.    return (pLog->iStatus == iPMStatusCollecting) ;
  2079.    }  // LogCollecting
  2080.  
  2081.  
  2082. int LogFileSize (HWND hWndLog)
  2083.    {
  2084.    PLOG           pLog ;
  2085.  
  2086.    pLog = LogData (hWndLog) ;
  2087.  
  2088.    return (pLog->lFileSize) ;
  2089.    }
  2090.  
  2091. BOOL LogWriteSystemBookmark (
  2092.    HWND     hWnd,
  2093.    LPTSTR   lpSystemName,
  2094.    BOOL     bDisconnected,
  2095.    SYSTEMTIME *pSystemTime)
  2096.    {
  2097.    BOOKMARK       Bookmark ;
  2098.    TCHAR    NewSystemBookmark [MiscTextLen * 2] ;
  2099.  
  2100.    memset (&Bookmark, 0, sizeof (BOOKMARK)) ;
  2101.  
  2102.    NewSystemBookmark [0] = TEXT('\0') ;
  2103.    StringLoad (
  2104.       bDisconnected ?
  2105.          IDS_SYSTEM_DOWN :
  2106.          IDS_SYSTEM_UP,
  2107.       NewSystemBookmark) ;
  2108.  
  2109.    lstrcat (NewSystemBookmark, TEXT(" - ")) ;
  2110.    lstrcat (NewSystemBookmark, lpSystemName) ;
  2111.    Bookmark.SystemTime = *pSystemTime ;
  2112.    lstrcpy (Bookmark.szComment, NewSystemBookmark) ;
  2113.  
  2114.    return (LogWriteBookmarkData (hWndLog, &Bookmark)) ;
  2115.    }
  2116.  
  2117. BOOL LogWriteStartBookmark (HWND hWnd, SYSTEMTIME *pSystemTime)
  2118.    {
  2119.    BOOKMARK       Bookmark ;
  2120.    TCHAR    NewDataBookmark [MiscTextLen] ;
  2121.  
  2122.    memset (&Bookmark, 0, sizeof (BOOKMARK)) ;
  2123.  
  2124.    NewDataBookmark [0] = TEXT('\0') ;
  2125.    StringLoad (IDS_NEWDATA_BOOKMARK, NewDataBookmark) ;
  2126.    Bookmark.SystemTime = *pSystemTime ;
  2127.    lstrcpy (Bookmark.szComment, NewDataBookmark) ;
  2128.  
  2129.    return (LogWriteBookmarkData (hWndLog, &Bookmark)) ;
  2130.    }
  2131.  
  2132. BOOL LogWriteBookmarkData (HWND hWnd, PBOOKMARK pBookmark)
  2133.    {
  2134.    PLOG           pLog ;
  2135.    LONG           lDataOffset ;
  2136.    BOOL           WriteOK ;
  2137.  
  2138.    pLog = LogData (hWndLog) ;
  2139.    if (!pLog)
  2140.       return (FALSE) ;
  2141.  
  2142.    lDataOffset = FileTell (pLog->hFile) ;
  2143.    WriteOK = FileWrite (pLog->hFile, pBookmark, sizeof (BOOKMARK)) ;
  2144.    if ( WriteOK )
  2145.       {
  2146.       pLog->lFileSize += sizeof (BOOKMARK) ;
  2147.       UpdateLogSize (hWndLog) ;
  2148.  
  2149.       WriteOK = LogWriteIndex (pLog, LogFileIndexBookmark,
  2150.                                &(pBookmark->SystemTime),
  2151.                                lDataOffset,
  2152.                                0) ;
  2153.       }
  2154.    if ( !WriteOK )
  2155.       {
  2156.       CloseLog (hWndLog, pLog) ;
  2157.       PrepareMenu (GetMenu (hWndMain)) ;
  2158.       UpdateLogDisplay (hWndLog) ;   
  2159.       DlgErrorBox (hWndLog, ERR_LOG_FILE, pLog->szFilePath);
  2160.       }
  2161.    return WriteOK ;
  2162.    }
  2163.  
  2164.  
  2165.  
  2166. BOOL LogWriteBookmark (HWND hWndLog,
  2167.                        LPCTSTR lpszComment)
  2168.    {  // LogWriteBookmark
  2169.    BOOKMARK       Bookmark ;
  2170.  
  2171.    memset (&Bookmark, 0, sizeof (BOOKMARK)) ;
  2172.  
  2173.    GetLocalTime (&Bookmark.SystemTime) ;
  2174.    lstrcpy (Bookmark.szComment, lpszComment) ;
  2175.  
  2176.    return (LogWriteBookmarkData (hWndLog, &Bookmark)) ;
  2177.    }  // LogWriteBookmark
  2178.    
  2179.  
  2180. BOOL AnyLogLine (void)
  2181. {  // CurrentLogLine
  2182.    int iIndex ;
  2183.  
  2184.    iIndex = LBSelection (hWndLogEntries) ;
  2185.    if (iIndex == LB_ERR)
  2186.       {
  2187.       return (FALSE) ;
  2188.       }
  2189.    else
  2190.       {
  2191.       return (TRUE) ;
  2192.       }
  2193. }
  2194.  
  2195. void ResetLogView (HWND hWndLog)
  2196. {
  2197.    PLOG        pLog ;
  2198.  
  2199.    pLog = LogData (hWndLog) ;
  2200.  
  2201.    ChangeSaveFileName (NULL, IDM_VIEWLOG) ;
  2202.  
  2203.    if (pLog && pLog->pSystemFirst)
  2204.       {
  2205.       ResetLog (hWndLog) ;
  2206.       }
  2207. }  // ResetLogView
  2208.  
  2209. BOOL ResetLog (HWND hWndLog)
  2210. {
  2211.    int         iIndex ;
  2212.    PLOG        pLog ;
  2213.    int         iEntriesNum ;
  2214.  
  2215.    pLog = LogData (hWndLog) ;
  2216.  
  2217.    if (LogCollecting (hWndLog))
  2218.       {
  2219.       CloseLog (hWndLog, pLog) ;
  2220.       }
  2221.  
  2222.    LBSetRedraw (hWndLogEntries, FALSE) ;
  2223.    iEntriesNum = LBNumItems (hWndLogEntries) ;
  2224.  
  2225.    // only need to zero out the list head
  2226.    // each item will be deleted by LogDeleteIndex via the listbox
  2227.    pLog->pLogEntryFirst = NULL ;
  2228.  
  2229.    // delete each line
  2230.    for (iIndex = iEntriesNum - 1 ;
  2231.         iIndex >= 0 ;
  2232.         iIndex-- )
  2233.       {
  2234.       LogDeleteIndex (hWndLogEntries, iIndex) ;
  2235.       }
  2236.  
  2237.    LBSetRedraw (hWndLogEntries, TRUE) ;
  2238.  
  2239.    if (pLog->pSystemFirst)
  2240.       {
  2241.       FreeSystems (pLog->pSystemFirst) ;
  2242.       pLog->pSystemFirst = NULL ;
  2243.       }
  2244.  
  2245.    MemoryFree (pLog->pLogData) ;
  2246.  
  2247.    pLog->pLogData = (PPERFDATA) MemoryAllocate (STARTING_SYSINFO_SIZE) ;
  2248.  
  2249.    LogEntriesChanged (hWndLogEntries) ;
  2250.  
  2251.    pLog->iStatus = iPMStatusClosed ;
  2252.    UpdateLogDisplay (hWndLog) ;
  2253.  
  2254.    return (TRUE) ;
  2255. }
  2256.  
  2257. BOOL LogDeleteEntry (HWND hWndLog)
  2258. {
  2259.    int         iIndex ;
  2260.    PLOG        pLog ;
  2261.    BOOL        retCode ;
  2262.    int         iEntriesNum ;
  2263.  
  2264.    pLog = LogData (hWndLog) ;
  2265.  
  2266.    iIndex = LBSelection (hWndLogEntries) ;
  2267.  
  2268.    if (iIndex == LB_ERR)
  2269.       {
  2270.       retCode = FALSE ;
  2271.       }
  2272.    else
  2273.       {
  2274.       // remove the current selection
  2275.       LogDeleteIndex (hWndLogEntries, iIndex) ;
  2276.  
  2277.       iEntriesNum = LBNumItems (hWndLogEntries) ;
  2278.  
  2279.       if (iEntriesNum == 0 || iEntriesNum == LB_ERR)
  2280.          {
  2281.          // delete the last line or something bad happened, 
  2282.          // then reset the window.
  2283.          ResetLog (hWndLog) ;
  2284.          }
  2285.       else
  2286.          {
  2287.          // set selection on the item above the deleted item.
  2288.          iIndex-- ;
  2289.          if (iIndex < 0)
  2290.             {
  2291.             iIndex = 0 ;
  2292.             }
  2293.          LBSetSelection (hWndLogEntries, iIndex) ;
  2294.          LBSetVisible (hWndLogEntries, iIndex) ;
  2295.          }
  2296.  
  2297.       LogEntriesChanged (hWndLogEntries) ;
  2298.       retCode = TRUE ;
  2299.       }
  2300.    return (retCode) ;
  2301. }
  2302.  
  2303.  
  2304. void ExportLog (void)
  2305. {
  2306.    HANDLE      hFile ;
  2307.    PLOG        pLog ;
  2308.    PLOGENTRY   pLogEntry ;
  2309.    int         iIndex ;
  2310.    int         iIndexNum ;
  2311.    CHAR        TempBuff [LongTextLen * 2] ;
  2312.    TCHAR       UnicodeBuff [LongTextLen] ;
  2313.    TCHAR       UnicodeBuff1 [MiscTextLen] ;
  2314.    int         StringLen ;
  2315.    LPTSTR      pFileName = NULL ;
  2316.    INT         ErrCode = 0 ;
  2317.  
  2318.    if (!(pLog = LogData (hWndLog)))
  2319.       {
  2320.       return ;
  2321.       }
  2322.  
  2323.    // see if there is anything to export..
  2324.    iIndexNum = LBNumItems (hWndLogEntries) ;
  2325.    if (iIndexNum == 0 || iIndexNum == LB_ERR)
  2326.       {
  2327.       return ;
  2328.       }
  2329.  
  2330.    if (!FileGetName (hWndLog, IDS_EXPORTFILE, UnicodeBuff))
  2331.       {
  2332.       // user cancel 
  2333.       return ;
  2334.       }
  2335.  
  2336.    pFileName = StringAllocate (UnicodeBuff) ;
  2337.  
  2338.    // open the file..
  2339.    if (!(hFile = FileHandleCreate (UnicodeBuff)))
  2340.       {
  2341.       // can't open the file
  2342.       ErrCode = ERR_CANT_OPEN ;
  2343.       return ;
  2344.       }
  2345.  
  2346.  
  2347.    SetHourglassCursor() ;
  2348.  
  2349.    // get header
  2350.    StringLoad (IDS_REPORT_HEADER, UnicodeBuff) ;
  2351.    ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  2352.    StringLen = strlen (TempBuff) ;
  2353.    ConvertUnicodeStr (&TempBuff[StringLen], LocalComputerName) ;
  2354.    strcat (TempBuff, LineEndStr) ;
  2355.  
  2356.    if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
  2357.       {
  2358.       ErrCode = ERR_EXPORT_FILE ;
  2359.       goto Exit0 ;
  2360.       }
  2361.  
  2362.    if (!(strempty(pLog->szFilePath)))
  2363.       {
  2364.       // export filename is there is one
  2365.       StringLoad (IDS_REPORT_LOGFILE, UnicodeBuff) ;
  2366.       ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  2367.       StringLen = strlen (TempBuff) ;
  2368.       ConvertUnicodeStr (&TempBuff[StringLen], pLog->szFilePath) ;
  2369.       strcat (TempBuff, LineEndStr) ;
  2370.  
  2371.       if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
  2372.          {
  2373.          ErrCode = ERR_EXPORT_FILE ;
  2374.          goto Exit0 ;
  2375.          }
  2376.       }
  2377.  
  2378.    // export interval 
  2379.    StringLoad (IDS_CHARTINT_FORMAT, UnicodeBuff1) ;
  2380.    TSPRINTF (UnicodeBuff, UnicodeBuff1,
  2381.        (FLOAT) pLog->iIntervalMSecs / (FLOAT) 1000.0) ;
  2382.    ConvertDecimalPoint (UnicodeBuff) ;
  2383.    ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  2384.    strcat (TempBuff, LineEndStr) ;
  2385.    strcat (TempBuff, LineEndStr) ;
  2386.  
  2387.    if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
  2388.       {
  2389.       ErrCode = ERR_EXPORT_FILE ;
  2390.       goto Exit0 ;
  2391.       }
  2392.  
  2393.    // export Labels
  2394.    StringLoad (IDS_LABELOBJECT, UnicodeBuff) ;
  2395.    ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  2396.    strcat (TempBuff, pDelimiter) ;
  2397.  
  2398.    if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
  2399.       {
  2400.       ErrCode = ERR_EXPORT_FILE ;
  2401.       goto Exit0 ;
  2402.       }
  2403.  
  2404.    StringLoad (IDS_LABELSYSTEM, UnicodeBuff) ;
  2405.    ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
  2406.    strcat (TempBuff, LineEndStr) ;
  2407.  
  2408.    if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
  2409.       {
  2410.       ErrCode = ERR_EXPORT_FILE ;
  2411.       goto Exit0 ;
  2412.       }
  2413.  
  2414.  
  2415.    // export each counter
  2416.    for (iIndex = 0 ; iIndex < iIndexNum ; iIndex++)
  2417.       {  // for
  2418.       
  2419.       pLogEntry = LogEntryN (hWndLogEntries, iIndex) ;
  2420.       
  2421.       if (!pLogEntry || pLogEntry == (PLOGENTRY)LB_ERR)
  2422.          {
  2423.          continue ;
  2424.          }
  2425.  
  2426.       ConvertUnicodeStr (TempBuff, pLogEntry->szObject) ;
  2427.       strcat (TempBuff, pDelimiter) ;
  2428.  
  2429.       if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
  2430.          {
  2431.          ErrCode = ERR_EXPORT_FILE ;
  2432.          break ;
  2433.          }
  2434.  
  2435.       ConvertUnicodeStr (TempBuff, pLogEntry->szComputer) ;
  2436.       strcat (TempBuff, LineEndStr) ;
  2437.  
  2438.       if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
  2439.          {
  2440.          ErrCode = ERR_EXPORT_FILE ;
  2441.          break ;
  2442.          }
  2443.       }
  2444.  
  2445. Exit0:
  2446.  
  2447.    SetArrowCursor() ;
  2448.    CloseHandle (hFile) ;
  2449.  
  2450.    if (pFileName)
  2451.       {
  2452.       if (ErrCode)
  2453.          {
  2454.          DlgErrorBox (hWndGraph, ErrCode, pFileName) ;
  2455.          }
  2456.       MemoryFree (pFileName) ;
  2457.       }
  2458.  
  2459. }  // ExportLog
  2460.  
  2461.  
  2462. LPTSTR   MatchSystemCounters (LPTSTR pBaseSysCounter,
  2463.    long   lBaseSysSize,
  2464.    LPTSTR pSysCounter,
  2465.    long   lSysSize,
  2466.    long   *pMatchPortion)
  2467. {
  2468.    LPTSTR   pNotMatch = NULL ;
  2469.    long     i, lSizeToCompare ;
  2470.  
  2471.    *pMatchPortion = 0 ;
  2472.    lSizeToCompare = min (lBaseSysSize, lSysSize) / sizeof (TCHAR) ;
  2473.  
  2474.    for (i = 0 ; i < lSizeToCompare ; i++, pBaseSysCounter++, pSysCounter++)
  2475.       {
  2476.       if (*pBaseSysCounter != *pSysCounter)
  2477.          {
  2478.          pNotMatch = pSysCounter ;
  2479.          break ;
  2480.          }
  2481.       }
  2482.  
  2483.    if (pNotMatch == NULL)
  2484.       {
  2485.       if (lBaseSysSize < lSysSize)
  2486.          {
  2487.          // the new system has longer counter names than base system
  2488.          // setup the extra portion.
  2489.          pNotMatch = pSysCounter ;
  2490.          }
  2491.       else
  2492.          {
  2493.          // new system counter name is shorter than or equal to
  2494.          // the base system counter names
  2495.          *pMatchPortion = lSysSize ;
  2496.          }
  2497.       }
  2498.  
  2499.    return (pNotMatch) ;
  2500.  
  2501. }
  2502.  
  2503. void LogWriteSystemCounterNames (HWND hWnd, PLOG pLog)
  2504.    {
  2505.    long           dwArraySize ;
  2506.    PPERFSYSTEM    pSystem = pLog->pSystemFirst ;
  2507.    LPTSTR         pMatchLen ;
  2508.    LPTSTR         pCounterName ;
  2509.    long           lMatchLen, lMatchPortion ;
  2510.  
  2511.    for (pSystem = pLog->pSystemFirst ;
  2512.         pSystem ;
  2513.         pSystem = pSystem->pSystemNext)
  2514.       {
  2515.       if (pSystem->bSystemCounterNameSaved == TRUE ||
  2516.           pSystem->CounterInfo.dwLastId == 0)
  2517.          {
  2518.          // we have either wrote out the counter name for 
  2519.          // this system, or this system is not connect when
  2520.          // reading in the setting file,  skip it then.
  2521.          continue ;
  2522.          }
  2523.  
  2524.       dwArraySize = (pSystem->CounterInfo.dwLastId + 1 ) ;
  2525.  
  2526.       if (!pLog->lBaseCounterNameOffset)
  2527.          {
  2528.          LogWriteCounterName (hWnd, pSystem, pLog,
  2529.             (LPTSTR)(pSystem->CounterInfo.TextString + dwArraySize),
  2530.             0,
  2531.             pSystem->CounterInfo.dwCounterSize,
  2532.             0 ) ;
  2533.          }
  2534.       else
  2535.          {
  2536.          // check for matched characters between this system and the 
  2537.          // base system
  2538.          pCounterName = (LPTSTR)(pSystem->CounterInfo.TextString + dwArraySize) ;
  2539.          pMatchLen = MatchSystemCounters (pLog->pBaseCounterName,
  2540.                         pLog->lBaseCounterNameSize,
  2541.                         pCounterName,
  2542.                         pSystem->CounterInfo.dwCounterSize,
  2543.                         &lMatchPortion) ;
  2544.  
  2545.          if (pMatchLen)
  2546.             {
  2547.             // This system matches part of the base system
  2548.             // (all if it has more names)
  2549.             lMatchLen = (long) (pMatchLen - pCounterName) * sizeof (TCHAR) ;
  2550.             LogWriteCounterName (hWnd, pSystem, pLog,
  2551.                pMatchLen,
  2552.                lMatchLen,
  2553.                pSystem->CounterInfo.dwCounterSize - lMatchLen,
  2554.                0 ) ;
  2555.             }
  2556.          else
  2557.             {
  2558.             // This system matches the based system
  2559.             LogWriteCounterName (hWnd, pSystem, pLog,
  2560.                NULL,
  2561.                lMatchPortion,
  2562.                0,
  2563.                0 ) ;
  2564.             }
  2565.          }
  2566.       }
  2567.    } // LogWriteSystemCounterNames
  2568.  
  2569.  
  2570. BOOL LogWriteCounterName (HWND hWnd,
  2571.                           PPERFSYSTEM pSystem,
  2572.                           PLOG   pLog,
  2573.                           LPTSTR pCounterName,
  2574.                           long sizeMatched,
  2575.                           long sizeOfData,
  2576.                           BOOL bBaseCounterName)
  2577.    {
  2578.    BOOL                 ReadOK ;
  2579.    BOOL                 WriteOK ;
  2580.    SYSTEMTIME           SystemTime ;
  2581.    LOGFILECOUNTERNAME   CounterNameRecord ;
  2582.    LOGHEADER            LogFileHeader ;
  2583.    long                 lDataOffset, lCurPosition ;
  2584.    TCHAR                Dummy [sizeof(DWORD)] ;
  2585.    int                  PatchBytes ;
  2586.  
  2587.    if (pSystem->bSystemCounterNameSaved == TRUE)
  2588.       return FALSE ;
  2589.  
  2590.    GetLocalTime (&SystemTime) ;
  2591.  
  2592.    lCurPosition = FileTell (pLog->hFile) ;
  2593.    
  2594.    lstrcpy (CounterNameRecord.szComputer, pSystem->sysName) ;
  2595.    CounterNameRecord.lBaseCounterNameOffset = pLog->lBaseCounterNameOffset ;
  2596.    CounterNameRecord.lCurrentCounterNameOffset =
  2597.       lCurPosition + sizeof (LOGFILECOUNTERNAME) ;
  2598.    CounterNameRecord.lMatchLength = sizeMatched ;
  2599.    CounterNameRecord.lUnmatchCounterNames = sizeOfData ;
  2600.    CounterNameRecord.dwLastCounterId = pSystem->CounterInfo.dwLastId ;
  2601.    CounterNameRecord.dwLangId = pSystem->CounterInfo.dwLangId ;
  2602.    WriteOK = FileWrite (pLog->hFile, &CounterNameRecord,
  2603.       sizeof (CounterNameRecord)) ;
  2604.  
  2605.    if (WriteOK)
  2606.       {
  2607.       pLog->lFileSize += sizeof (LOGFILECOUNTERNAME) ;
  2608.  
  2609.       if (sizeOfData)
  2610.          {
  2611.       
  2612.          WriteOK = FileWrite (pLog->hFile, pCounterName, sizeOfData) ;
  2613.          
  2614.          if (WriteOK && (PatchBytes = sizeOfData % sizeof(DWORD)) > 0)
  2615.             {
  2616.             // ensure the file is in DWORD boundary.
  2617.             WriteOK = FileWrite (pLog->hFile, Dummy, PatchBytes) ;
  2618.             }
  2619.  
  2620.          if (WriteOK)
  2621.             {
  2622.             pLog->lFileSize += sizeOfData + PatchBytes ;
  2623.  
  2624.             if (!pLog->lBaseCounterNameOffset)
  2625.                {
  2626.                // this is the first counter name data block
  2627.                // then update the log file header
  2628.                lDataOffset = FileTell (pLog->hFile) ;
  2629.  
  2630.                FileSeekBegin (pLog->hFile, 0L) ;
  2631.  
  2632.                ReadOK = FileRead (pLog->hFile,
  2633.                   &LogFileHeader,
  2634.                   sizeof (LogFileHeader)) ;
  2635.  
  2636.                if (ReadOK)
  2637.                   {
  2638.                   LogFileHeader.lBaseCounterNameOffset = lCurPosition ;
  2639.                   FileSeekBegin (pLog->hFile, 0L) ;
  2640.                   WriteOK = FileWrite (pLog->hFile,
  2641.                      &LogFileHeader,
  2642.                      sizeof (LogFileHeader)) ;
  2643.                   }
  2644.                else
  2645.                   {
  2646.                   // flag an error
  2647.                   WriteOK = FALSE ; 
  2648.                   }
  2649.  
  2650.                // retore back to current file position
  2651.                FileSeekBegin (pLog->hFile, lDataOffset) ;
  2652.  
  2653.                if (ReadOK && WriteOK)
  2654.                   {
  2655.                   // allocate memory to save the base system counter names
  2656.                   if (pLog->pBaseCounterName)
  2657.                      {
  2658.                      MemoryFree (pLog->pBaseCounterName) ;
  2659.                      }
  2660.                   if (pLog->pBaseCounterName = MemoryAllocate (sizeOfData))
  2661.                      {
  2662.                      memcpy (pLog->pBaseCounterName,
  2663.                         pCounterName,
  2664.                         sizeOfData) ;
  2665.                      pLog->lBaseCounterNameOffset = lCurPosition ;
  2666.                      pLog->lBaseCounterNameSize = sizeOfData ;
  2667.                      }
  2668.                   }
  2669.                }  // if (!pLog->lBaseCounterNameOffset)
  2670.             }
  2671.          }  // if (sizeOfData)
  2672.       }
  2673.  
  2674.    if ( WriteOK )
  2675.       {
  2676.       WriteOK = LogWriteIndex (pLog, LogFileIndexCounterName,
  2677.                                &SystemTime,
  2678.                                lCurPosition,
  2679.                                0) ;
  2680.       }
  2681.  
  2682.    if ( !WriteOK )
  2683.       {
  2684.       CloseLog (hWndLog, pLog) ;
  2685.       PrepareMenu (GetMenu (hWndMain)) ;
  2686.       UpdateLogDisplay (hWndLog) ;   
  2687.       DlgErrorBox (hWndLog, ERR_LOG_FILE, pLog->szFilePath);
  2688.       }
  2689.    else
  2690.       {
  2691.       UpdateLogSize (hWnd) ;
  2692.       pSystem->bSystemCounterNameSaved = TRUE ;
  2693.       }
  2694.  
  2695.    return (TRUE) ;
  2696.    }
  2697.  
  2698.      
  2699.