|
|
/*****************************************************************************
* * Grafdata.c - This module handles the non-drawing functions of the graph, * such as allocating linked structures and their memory, freeing it, * unlinking, starting and stopping the timer, * setting up the first graph (CPU), and all the numeric functions for * the different counter types. * * Microsoft Confidential * Copyright (c) 1992-1993 Microsoft Corporation * * ****************************************************************************/
//==========================================================================//
// Includes //
//==========================================================================//
#include <stdio.h> // for sprintf
#include "perfmon.h" // main perfmon declarations
#include "grafdata.h" // external declarations for this file
#include <float.h> // for FLT_MAX constant
#include "addline.h" // for AddLine, EditLine
#include "counters.h" // for CounterEntry
#include "graph.h" // for SizeGraphComponents
#include "pmemory.h" // for MemoryXXX (mallloc-type) routines
#include "perfdata.h" // for UpdateLines
#include "playback.h" // for PlayingBackLog, PlaybackLines
#include "legend.h"
#include "system.h" // for SystemGet
#include "utils.h"
#include "line.h" // for LineFree
#include "valuebar.h" // for StatusTimer
#include "fileopen.h" // for FileGetName
#include "fileutil.h" // for FileRead...
#include "menuids.h" // for IDM_VIEWCHART
#include "perfmops.h" // for ExportFileHeader
#include "status.h" // for StatusLineReady
extern BOOL SaveFileHandler(HWND hWnd,DWORD type) ;
// this macro is used in doing a simple DDA (Digital Differential Analyzer)
// * 10 + 5 is to make the result round up with .5
#define DDA_DISTRIBUTE(TotalTics, numOfData) \
((TotalTics * 10 / numOfData) + 5) / 10
#define szSmallValueFormat TEXT("%10.3f")
#define szLargeValueFormat TEXT("%10.0f")
//==========================================================================//
// Local Data //
//==========================================================================//
//==========================================================================//
// Local Functions //
//==========================================================================//
/****************************************************************************
* eUpdateMinMaxAve - ****************************************************************************/ void eUpdateMinMaxAve (FLOAT eValue, PLINESTRUCT pLineStruct, INT iValidValues, INT iTotalValidPoints, INT iDataPoint, INT gMaxPoints) { INT i ; INT iDataNum = iTotalValidPoints ; FLOAT eMin, eMax, eSum, eNewValue ;
eMax = eMin = eValue ;
if (PlayingBackLog()) { eSum = (FLOAT) 0.0 ; } else { eSum = eValue ; }
if (iValidValues == iTotalValidPoints) { for (i=0 ; i < iValidValues ; i++) { if (i == iDataPoint) { // skip the data point we are going to replace
continue ; }
eNewValue = pLineStruct->lnValues[i] ; eSum += eNewValue ;
if (eNewValue > eMax) { eMax = eNewValue ; }
if (eNewValue < eMin) { eMin = eNewValue ; } } } else { // special case when we start the new line in the middle of the chart
for (i = iDataPoint, iTotalValidPoints-- ; iTotalValidPoints > 0 ; iTotalValidPoints-- ) { i-- ; if (i < 0) { // for the wrap-around case..
i = gMaxPoints - 1 ; }
if (i == iDataPoint) { // skip the data point we are going to replace
continue ; } eNewValue = pLineStruct->lnValues[i] ;
eSum += eNewValue ;
if (eNewValue > eMax) { eMax = eNewValue ; }
if (eNewValue < eMin) { eMin = eNewValue ; } } }
pLineStruct->lnMinValue = eMin ; pLineStruct->lnMaxValue = eMax ;
if (iDataNum) { pLineStruct->lnAveValue = eSum / (FLOAT) iDataNum ; } else { pLineStruct->lnAveValue = (FLOAT) 0.0 ; }
//clean up bogus (negative)values
if (pLineStruct->lnMinValue < (FLOAT)0.0) { pLineStruct->lnMinValue = (FLOAT)0.0; } if (pLineStruct->lnMaxValue < (FLOAT)0.0) { pLineStruct->lnMaxValue = (FLOAT)0.0; } if (pLineStruct->lnAveValue < (FLOAT) 0.0) { pLineStruct->lnAveValue = (FLOAT) 0.0 ; } }
// UpdateValueBarData is used to update the value bar data
// It is called when the user switches to a diff. line from
// the legned window.
VOID UpdateValueBarData (PGRAPHSTRUCT pGraph) { PLINESTRUCT pCurrentGraphLine ; INT KnownValue, MaxValues, iValidValues, iDataPoint ; FLOAT eValue ; pCurrentGraphLine = CurrentGraphLine (hWndGraph) ;
if (!pCurrentGraphLine || pCurrentGraphLine->bFirstTime) { // we have not collect enough samples
return ; }
KnownValue = pGraph->gKnownValue ; MaxValues = pGraph->gMaxValues ;
// The valid values is the number of valid entries in the
// data buffer. After we wrap the buffer, all the values are
// valid.
iValidValues = pGraph->gTimeLine.iValidValues ;
// Get the index to the data point we are updating.
iDataPoint = KnownValue % MaxValues ; eValue = pCurrentGraphLine->lnValues[iDataPoint] ;
// get the statistical data for this line
eUpdateMinMaxAve(eValue, pCurrentGraphLine, iValidValues, pCurrentGraphLine->lnValidValues, iDataPoint, MaxValues) ; } // UpdateValueBarData
VOID UpdateLGData (PGRAPHSTRUCT pGraph) { PLINESTRUCT pLine ; PLINESTRUCT pCurrentGraphLine ; INT KnownValue, MaxValues, iValidValues, iDataPoint ; FLOAT eValue ; // Known Value is the where data is placed in the buffer.
pGraph->gKnownValue++;
KnownValue = pGraph->gKnownValue ;
// Update the high water mark for valid data in the lnValues
// (aka DataPoint) buffer.
MaxValues = pGraph->gMaxValues ;
// The valid values is the number of valid entries in the
// data buffer. After we wrap the buffer, all the values are
// valid.
iValidValues = pGraph->gTimeLine.iValidValues ;
if (iValidValues < MaxValues) iValidValues = (KnownValue % MaxValues) + 1 ;
pGraph->gTimeLine.iValidValues = iValidValues ;
// Get the index to the data point we are updating.
iDataPoint = KnownValue % MaxValues ;
// loop through lines,
// If one of the lines is highlighted then do the calculations
// for average, min, & max on that line.
pCurrentGraphLine = CurrentGraphLine (hWndGraph) ;
for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext) { // for
if (pLine->bFirstTime) { // skip until we have collect enough samples to plot the first data
continue ; }
if (pLine->lnValidValues < MaxValues) { (pLine->lnValidValues)++ ; } // Get the new value for this line.
eValue = CounterEntry (pLine) ;
if (pLine == pCurrentGraphLine) { // if
// get the statistical data for this line
eUpdateMinMaxAve (eValue, pLine, iValidValues, pLine->lnValidValues, iDataPoint, MaxValues) ; } // if
// Now put the new value into the data array
pLine->lnValues[iDataPoint] = eValue ; } GetLocalTime (&(pGraph->pDataTime[iDataPoint])) ; } // UpdateLGData
BOOL HandleGraphTimer (void) { PGRAPHSTRUCT pGraph;
//NOTE: get a strategy for these "no-go" states
if (!(pGraph = pGraphs) || !pGraphs->pSystemFirst) return(FALSE);
if (!UpdateLines(&(pGraphs->pSystemFirst), pGraphs->pLineFirst)) return (TRUE) ;
UpdateLGData(pGraph);
return(TRUE); }
VOID ClearGraphTimer(PGRAPHSTRUCT pGraph) { KillTimer(pGraph->hWnd, GRAPH_TIMER_ID); }
VOID SetGraphTimer(PGRAPHSTRUCT pGraph) { SetTimer(pGraph->hWnd, GRAPH_TIMER_ID, pGraph->gInterval, NULL) ; }
VOID ResetGraphTimer(PGRAPHSTRUCT pGraph) { KillTimer(pGraph->hWnd, GRAPH_TIMER_ID); SetGraphTimer(pGraph); }
VOID GetGraphConfig(PGRAPHSTRUCT pGraph) {
LoadRefreshSettings(pGraph); LoadLineGraphSettings(pGraph);
// Init the structure
pGraph->pLineFirst = NULL;
//NOTE: put the rest of this in Config
pGraph->gOptions.bLegendChecked = TRUE; pGraph->gOptions.bMenuChecked = TRUE; pGraph->gOptions.bLabelsChecked = TRUE; pGraph->gOptions.bVertGridChecked = FALSE; pGraph->gOptions.bHorzGridChecked = FALSE; pGraph->gOptions.bStatusBarChecked = TRUE; pGraph->gOptions.GraphVGrid = TRUE; pGraph->gOptions.GraphHGrid = TRUE; pGraph->gOptions.HistVGrid = TRUE; pGraph->gOptions.HistHGrid = TRUE;
pGraph->gOptions.iGraphOrHistogram = LINE_GRAPH; // vs. BAR_GRAPH
pGraph->gOptions.iVertMax = DEF_GRAPH_VMAX;
return; }
BOOL InsertGraph (HWND hWnd) { PGRAPHSTRUCT pGraph;
pGraph = MemoryAllocate (sizeof (GRAPHSTRUCT)) ; if (!pGraph) return (FALSE) ;
pGraphs = pGraph;
GetGraphConfig(pGraph); pGraph->bManualRefresh = FALSE ;
// there's at least one place where the [DEFAULT_MAX_VALUES] entry is
// accessed when the index should stop at [DEFAULT_MAX_VALUES -1].
// rather than try to find all the places this index is used it's easier
// and safer just to make the array large enough to accomodate this
// "oversight"
pGraph->gMaxValues = DEFAULT_MAX_VALUES; pGraph->pptDataPoints = (PPOINT) MemoryAllocate (sizeof (POINT) * (pGraph->gMaxValues + 1)) ;
pGraph->pDataTime = (SYSTEMTIME *) MemoryAllocate (sizeof(SYSTEMTIME) * (pGraph->gMaxValues + 1)) ;
pGraph->hWnd = hWnd ; pGraph->bModified = FALSE ;
pGraph->Visual.iColorIndex = 0 ; pGraph->Visual.iWidthIndex = 0 ; pGraph->Visual.iStyleIndex = 0 ;
return(TRUE) ; }
void PlaybackSetGraphLines (HWND hWndChart, PLINE pLineFirst, int iDisplayTic, int iLogTic, BOOL CalcData) { PLINE pLine ; FLOAT eValue ;
for (pLine = pLineFirst ; pLine ; pLine = pLine->pLineNext) { // for
eValue = CounterEntry (pLine) ; pLine->lnValues[iDisplayTic] = eValue ; pLine->aiLogIndexes[iDisplayTic] = iLogTic ;
// only need to do this on request.
if (CalcData) { eUpdateMinMaxAve (eValue, pLine, iDisplayTic, iDisplayTic, iDisplayTic, iDisplayTic) ; } // if
} // for
} // PlaybackSetGraphLines
BOOL ChartInsertLine (PGRAPHSTRUCT pGraph, PLINE pLine) /*
Effect: Insert the line pLine into the graph pGraph and allocate space for the graph's number of values.
Returns: Whether the line could be added and space allocated.
See Also: LineAllocate (line.c), ChartDeleteLine. */ { // ChartInsertLine
PLINE pLineEquivalent ; INT i ; FLOAT *pTempPts; HPEN tempPen ;
pGraph->bModified = TRUE ;
pLineEquivalent = FindEquivalentLine (pLine, pGraph->pLineFirst) ; if (pLineEquivalent) { if (bMonitorDuplicateInstances) { pLine->dwInstanceIndex = pLineEquivalent->dwInstanceIndex + 1; } else { pLineEquivalent->Visual = pLine->Visual ; pLineEquivalent->iScaleIndex = pLine->iScaleIndex ; pLineEquivalent->eScale = pLine->eScale ;
tempPen = pLineEquivalent->hPen ; pLineEquivalent->hPen = pLine->hPen ; pLine->hPen = tempPen ; return FALSE ; } }
if (!pGraph->pLineFirst && !PlayingBackLog()) { SetGraphTimer (pGraph) ; }
if (!SystemAdd (&pGraph->pSystemFirst, pLine->lnSystemName,pGraph->hWnd)) return FALSE;
LineAppend (&pGraph->pLineFirst, pLine) ;
pLine->lnMinValue = FLT_MAX ; pLine->lnMaxValue = - FLT_MAX ; pLine->lnAveValue = 0.0F ; pLine->lnValidValues = 0 ;
pLine->lnValues = (FLOAT *) MemoryAllocate (sizeof (FLOAT) * (pGraph->gMaxValues + 1)) ; for (i = pGraph->gMaxValues, pTempPts = pLine->lnValues ; (i > 0) && (pTempPts != NULL) ; i-- ) { *pTempPts++ = (FLOAT) 0.0 ; }
if (PlayingBackLog ()) { pLine->aiLogIndexes = (int *) MemoryAllocate (sizeof (LONG) * (pGraph->gMaxValues + 1)) ; }
// Add the line to the legend, resize the legend window, and then
// select the new line as the current legend item. Do it in this
// sequence to avoid the legend scroll bar momentarily appearing and
// then disappearing, since the resize will obviate the scroll bar.
LegendAddItem (hWndGraphLegend, pLine) ;
if (!bDelayAddAction) { SizeGraphComponents (hWndGraph) ; LegendSetSelection (hWndGraphLegend, LegendNumItems (hWndGraphLegend) - 1) ;
if (PlayingBackLog ()) PlaybackChart (pGraph->hWnd) ; }
return (TRUE) ; } // ChartInsertLine
VOID ChartDeleteLine (PGRAPHSTRUCT pGraph, PLINESTRUCT pLine) { PLINESTRUCT npLine;
pGraph->bModified = TRUE ;
if (pGraph->pLineFirst == pLine) pGraph->pLineFirst = pLine->pLineNext; else { for (npLine = pGraph->pLineFirst; npLine; npLine = npLine->pLineNext) { if (npLine->pLineNext == pLine) npLine->pLineNext = pLine->pLineNext; } }
if (!pGraph->pLineFirst) { ResetGraph (pGraph) ; } else { BuildValueListForSystems ( pGraph->pSystemFirst, pGraph->pLineFirst) ; }
// Delete the legend entry for this line.
// If the line was highlighted then this will undo the highlight.
LegendDeleteItem (hWndGraphLegend, pLine) ;
LineFree (pLine) ;
SizeGraphComponents (hWndGraph) ;
}
void ClearGraphDisplay (PGRAPHSTRUCT pGraph) { PLINESTRUCT pLine;
// reset the timeline data
// pGraph->gKnownValue = -1 ;
pGraph->gKnownValue = 0 ; pGraph->gTimeLine.iValidValues = 0 ; pGraph->gTimeLine.xLastTime = 0 ; memset (pGraph->pDataTime, 0, sizeof(SYSTEMTIME) * (pGraph->gMaxValues + 1)) ;
// loop through lines,
// If one of the lines is highlighted then do the calculations
// for average, min, & max on that line.
for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext) { // for
pLine->bFirstTime = 2 ; pLine->lnMinValue = FLT_MAX ; pLine->lnMaxValue = - FLT_MAX ; pLine->lnAveValue = 0.0F ; pLine->lnValidValues = 0 ; memset (pLine->lnValues, 0, sizeof(FLOAT) * (pGraph->gMaxValues + 1)) ; }
StatusTimer (hWndGraphStatus, TRUE) ; WindowInvalidate (hWndGraphDisplay) ; }
void ResetGraphView (HWND hWndGraph) { PGRAPHSTRUCT pGraph ;
pGraph = GraphData (hWndGraph) ;
if (!pGraph) { return ; }
ChangeSaveFileName (NULL, IDM_VIEWCHART) ;
if (pGraph->pSystemFirst) { ResetGraph (pGraph) ; } } // ResetGraphView
void ResetGraph (PGRAPHSTRUCT pGraph) { ClearGraphTimer (pGraph) ; ClearLegend (hWndGraphLegend) ; if (pGraph->pLineFirst) { FreeLines (pGraph->pLineFirst) ; pGraph->pLineFirst = NULL ; }
if (pGraph->pSystemFirst) { FreeSystems (pGraph->pSystemFirst) ; pGraph->pSystemFirst = NULL ; } // pGraph->gKnownValue = -1 ;
pGraph->gKnownValue = 0 ; pGraph->gTimeLine.iValidValues = 0 ; pGraph->gTimeLine.xLastTime = 0 ;
// reset visual data
pGraph->Visual.iColorIndex = 0 ; pGraph->Visual.iWidthIndex = 0 ; pGraph->Visual.iStyleIndex = 0 ;
memset (pGraph->pDataTime, 0, sizeof(SYSTEMTIME) * (pGraph->gMaxValues + 1)) ;
SizeGraphComponents (hWndGraph) ; InvalidateRect(hWndGraph, NULL, TRUE) ; }
void PlaybackChart (HWND hWndChart) { // PlaybackChart
int iDisplayTics ; // num visual points to display
int iDisplayTic ; int iLogTic ; int iLogTicsMove ; BOOL bFirstTime = TRUE; int iLogTicsRemaining ;
if (!pGraphs->pLineFirst) { // no line to playback
return ; }
iLogTicsRemaining = PlaybackLog.iSelectedTics ;
// we only have iDisplayTics-1 points since
// we have to use the first two sample points to
// get the first data points.
if (iLogTicsRemaining <= pGraphs->gMaxValues) { iDisplayTics = iLogTicsRemaining ; pGraphs->gTimeLine.iValidValues = iDisplayTics - 1 ; } else { iDisplayTics = pGraphs->gMaxValues ; pGraphs->gTimeLine.iValidValues = iDisplayTics ; }
iDisplayTic = -1 ; iLogTic = PlaybackLog.StartIndexPos.iPosition ;
while (iDisplayTics) {
PlaybackLines (pGraphs->pSystemFirst, pGraphs->pLineFirst, iLogTic) ;
if (bFirstTime) { bFirstTime = FALSE ;
// get the second sample data to form the first data point
iLogTic++ ; iLogTicsRemaining-- ; PlaybackLines (pGraphs->pSystemFirst, pGraphs->pLineFirst, iLogTic) ; } iDisplayTic++ ; PlaybackSetGraphLines (hWndChart, pGraphs->pLineFirst, iDisplayTic, iLogTic, (iDisplayTics == 1)) ;
// setup DDA to get the index of the next sample point
iLogTicsMove = DDA_DISTRIBUTE (iLogTicsRemaining, iDisplayTics) ; iLogTicsRemaining -= iLogTicsMove ; iLogTic += iLogTicsMove ;
iDisplayTics-- ;
} // while
// point to the last value for valuebar display
pGraphs->gKnownValue = iDisplayTic ;
} // PlaybackChart
#if 0
PLINESTRUCT CurrentGraphLine (HWND hWndGraph) { // CurrentGraphLine
UNREFERENCED_PARAMETER (hWndGraph) ;
return (LegendCurrentLine (hWndGraphLegend)) ; } #endif
BOOL AddChart (HWND hWndParent) { PLINE pCurrentLine = CurrentGraphLine (hWndGraph) ;
return (AddLine (hWndParent, &(pGraphs->pSystemFirst), &(pGraphs->Visual), pCurrentLine ? pCurrentLine->lnSystemName : NULL, LineTypeChart)) ; }
BOOL EditChart (HWND hWndParent) { // EditChart
return (EditLine (hWndParent, &(pGraphs->pSystemFirst), CurrentGraphLine (hWndGraph), LineTypeChart)) ; }
void GraphAddAction () { PGRAPHSTRUCT pGraph ;
pGraph = GraphData (hWndGraph) ;
SizeGraphComponents (hWndGraph) ; LegendSetSelection (hWndGraphLegend, LegendNumItems (hWndGraphLegend) - 1) ;
if (PlayingBackLog ()) PlaybackChart (pGraph->hWnd) ; }
BOOL OpenChartVer1 (HANDLE hFile, DISKCHART *pDiskChart, PGRAPHSTRUCT pGraph) { // OpenChartVer1
bDelayAddAction = TRUE ; pGraph->Visual = pDiskChart->Visual ; pGraph->gOptions = pDiskChart->gOptions ; pGraph->gMaxValues = pDiskChart->gMaxValues ; pGraph->bManualRefresh = pDiskChart->bManualRefresh ; pGraphs->gInterval = (INT) (pGraph->gOptions.eTimeInterval * (FLOAT) 1000.0) ; ReadLines (hFile, pDiskChart->dwNumLines, &(pGraph->pSystemFirst), &(pGraph->pLineFirst), IDM_VIEWCHART) ; bDelayAddAction = FALSE ;
GraphAddAction () ;
return (TRUE) ; } // OpenChartVer1
BOOL OpenChart (HWND hWndGraph, HANDLE hFile, DWORD dwMajorVersion, DWORD dwMinorVersion, BOOL bChartFile) { // OpenChart
PGRAPHSTRUCT pGraph ; DISKCHART DiskChart ; BOOL bSuccess = TRUE ;
pGraph = pGraphs ; if (!pGraph) { bSuccess = FALSE ; goto Exit0 ; }
if (!FileRead (hFile, &DiskChart, sizeof (DISKCHART))) { bSuccess = FALSE ; goto Exit0 ; }
switch (dwMajorVersion) { case (1):
SetHourglassCursor() ; ResetGraphView (hWndGraph) ;
OpenChartVer1 (hFile, &DiskChart, pGraph) ;
// change to chart view if we are opening a
// chart file
if (bChartFile && iPerfmonView != IDM_VIEWCHART) { SendMessage (hWndMain, WM_COMMAND, (LONG)IDM_VIEWCHART, 0L) ; }
if (iPerfmonView == IDM_VIEWCHART) { SetPerfmonOptions (&DiskChart.perfmonOptions) ; } SetArrowCursor() ;
break ; } // switch
Exit0:
if (bChartFile) { CloseHandle (hFile) ; }
return (bSuccess) ; } // OpenChart
BOOL SaveChart (HWND hWndGraph, HANDLE hInputFile, BOOL bGetFileName) { PGRAPHSTRUCT pGraph ; PLINE pLine ; HANDLE hFile ; DISKCHART DiskChart ; PERFFILEHEADER FileHeader ; TCHAR szFileName [256] ; BOOL newFileName = FALSE ;
if (hInputFile) { // use the input file handle if it is available
// this is the case for saving workspace data
hFile = hInputFile ; } else { if (pChartFullFileName) { lstrcpy (szFileName, pChartFullFileName) ; } if (bGetFileName || pChartFullFileName == NULL) { // if (!pChartFullFileName)
// {
// StringLoad (IDS_GRAPH_FNAME, szFileName) ;
// }
if (!FileGetName (hWndGraph, IDS_CHARTFILE, szFileName)) { return (FALSE) ; } newFileName = TRUE ; }
hFile = FileHandleCreate (szFileName) ;
if (hFile && hFile != INVALID_HANDLE_VALUE && newFileName) { ChangeSaveFileName (szFileName, IDM_VIEWCHART) ; } else if (!hFile || hFile == INVALID_HANDLE_VALUE) { DlgErrorBox (hWndGraph, ERR_CANT_OPEN, szFileName) ; } }
if (!hFile || hFile == INVALID_HANDLE_VALUE) return (FALSE) ;
pGraph = pGraphs ; if (!pGraph) { if (!hInputFile || hInputFile == INVALID_HANDLE_VALUE) { CloseHandle (hFile) ; } return (FALSE) ; }
if (!hInputFile || hInputFile == INVALID_HANDLE_VALUE) { // only need to write file header if not workspace
memset (&FileHeader, 0, sizeof (FileHeader)) ; lstrcpy (FileHeader.szSignature, szPerfChartSignature) ; FileHeader.dwMajorVersion = ChartMajorVersion ; FileHeader.dwMinorVersion = ChartMinorVersion ; if (!FileWrite (hFile, &FileHeader, sizeof (PERFFILEHEADER))) { goto Exit0 ; } }
DiskChart.Visual = pGraph->Visual ; DiskChart.gOptions = pGraph->gOptions ; DiskChart.gMaxValues = pGraph->gMaxValues ; DiskChart.dwNumLines = NumLines (pGraph->pLineFirst) ; DiskChart.bManualRefresh = pGraph->bManualRefresh ; DiskChart.perfmonOptions = Options ;
if (!FileWrite (hFile, &DiskChart, sizeof (DISKCHART))) { goto Exit0 ; }
for (pLine = pGraph->pLineFirst ; pLine ; pLine = pLine->pLineNext) { // for
if (!WriteLine (pLine, hFile)) { goto Exit0 ; } } // for
if (!hInputFile || hInputFile == INVALID_HANDLE_VALUE) { CloseHandle (hFile) ; }
return (TRUE) ;
Exit0: if (!hInputFile || hInputFile == INVALID_HANDLE_VALUE) { CloseHandle (hFile) ;
// only need to report error if not workspace
DlgErrorBox (hWndGraph, ERR_SETTING_FILE, szFileName) ; } return (FALSE) ;
} // SaveChart
#define TIME_TO_WRITE 2
BOOL ExportChartLabels (HANDLE hFile, PGRAPHSTRUCT pGraph) { TCHAR UnicodeBuff [LongTextLen] ; CHAR TempBuff [LongTextLen * 2] ; int StringLen ; PLINESTRUCT pLine; int TimeToWriteFile ; int iIndex ; LPTSTR lpItem = NULL;
for (iIndex = 0 ; iIndex < 5 ; iIndex++) { // for iIndex == 0, get counter name
// for iIndex == 1, get instance name
// for iIndex == 2, get parent name
// for iIndex == 3, get object name
// for iIndex == 4, get computer name
if (iIndex == 4) { // the last label field, write date/time labels
strcpy (TempBuff, LineEndStr) ; StringLen = strlen (TempBuff) ; StringLoad (IDS_EXPORT_DATE, UnicodeBuff) ; ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ; strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ; StringLoad (IDS_EXPORT_TIME, UnicodeBuff) ; ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ; strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ; } else { strcpy (TempBuff, LineEndStr) ; strcat (TempBuff, pDelimiter) ; strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ; }
TimeToWriteFile = 0 ;
for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext) { switch (iIndex) { case 0: lpItem = (LPTSTR) pLine->lnCounterName ; break ;
case 1: lpItem = (LPTSTR) pLine->lnInstanceName ; break ;
case 2: lpItem = (LPTSTR) pLine->lnPINName ; break ;
case 3: lpItem = (LPTSTR) pLine->lnObjectName ; break ;
case 4: lpItem = (LPTSTR) pLine->lnSystemName ; break ; }
if (lpItem) { ConvertUnicodeStr (&TempBuff[StringLen], lpItem) ; } else { TempBuff[StringLen] = '\0' ; } strcat (TempBuff, pDelimiter); StringLen = strlen (TempBuff) ; if (++TimeToWriteFile > TIME_TO_WRITE) { // better write the buffers before they overflow.
// there are better ways to check for overflow
// but this is good enough
if (!FileWrite (hFile, TempBuff, StringLen)) { goto Exit0 ; } StringLen = TimeToWriteFile = 0 ; } } // for each line
if (StringLen) { // write the last block of data
if (!FileWrite (hFile, TempBuff, StringLen)) { goto Exit0 ; } } } // for iIndex
return (TRUE) ;
Exit0: return (FALSE) ;
} // ExportChartLabels
BOOL ExportLogChart (HANDLE hFile, PGRAPHSTRUCT pGraph) { TCHAR UnicodeBuff [LongTextLen] ; CHAR TempBuff [LongTextLen * 2] ; int StringLen ; PLINESTRUCT pLine; int TimeToWriteFile ; FLOAT eValue ; int iLogTic ; BOOL bFirstTime = TRUE ; SYSTEMTIME LogSystemTime ; LOGPOSITION LogPosition ;
iLogTic = PlaybackLog.StartIndexPos.iPosition ;
// we have to export every point from the log file
for ( ; iLogTic <= PlaybackLog.StopIndexPos.iPosition ; iLogTic++) {
PlaybackLines (pGraphs->pSystemFirst, pGraphs->pLineFirst, iLogTic) ;
if (!bFirstTime) { // export the values
TimeToWriteFile = 0 ;
if (!LogPositionN (iLogTic, &LogPosition)) { goto Exit0 ; }
LogPositionSystemTime (&LogPosition, &LogSystemTime) ;
strcpy (TempBuff, LineEndStr) ; StringLen = strlen (TempBuff) ;
SystemTimeDateString (&LogSystemTime, UnicodeBuff) ; ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ; strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ;
SystemTimeTimeString (&LogSystemTime, UnicodeBuff, FALSE) ; ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ; strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ;
for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext) { eValue = CounterEntry (pLine) ;
TSPRINTF (UnicodeBuff, eValue > (FLOAT)999999.0 ? szLargeValueFormat : szSmallValueFormat, eValue) ; ConvertDecimalPoint (UnicodeBuff) ; ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ; strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ;
if (++TimeToWriteFile > TIME_TO_WRITE) { if (!FileWrite (hFile, TempBuff, StringLen)) { goto Exit0 ; } StringLen = TimeToWriteFile = 0 ; TempBuff[0] = '\0' ; } }
if (StringLen) { if (!FileWrite (hFile, TempBuff, StringLen)) { goto Exit0 ; } } } else { // skip the first data point since we
// need 2 points to form the first value
bFirstTime = FALSE ; } }
return (TRUE) ;
Exit0: return (FALSE) ;
} // ExportLogChart
BOOL ExportLineValue (HANDLE hFile, PGRAPHSTRUCT pGraph, int CurrentIndex, int iDataPoint) { TCHAR UnicodeBuff [MiscTextLen] ; CHAR TempBuff [LongTextLen] ; int StringLen ; PLINESTRUCT pLine; int MaxValues ; int TimeToWriteFile ; SYSTEMTIME *pSystemTime ; BOOL ValidValue ;
pSystemTime = pGraph->pDataTime ; pSystemTime += CurrentIndex ;
if (pSystemTime->wYear == 0 && pSystemTime->wYear == 0) { // ignore value that has 0 system time
return (TRUE) ; }
MaxValues = pGraph->gMaxValues ; strcpy (TempBuff, LineEndStr) ; StringLen = strlen (TempBuff) ;
SystemTimeDateString (pSystemTime, UnicodeBuff) ; ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ; strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ;
SystemTimeTimeString (pSystemTime, UnicodeBuff, FALSE) ; ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ; strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ;
TimeToWriteFile = 0 ; for (pLine=pGraph->pLineFirst; pLine; pLine=pLine->pLineNext) { if (!pLine->bFirstTime) { ValidValue = FALSE ; // check if this is a valid value
if (pLine->lnValidValues == MaxValues) { // this is the simple case where we have filled up
// the whole buffer
ValidValue = TRUE ; } else if (pLine->lnValidValues <= iDataPoint) { if (CurrentIndex <= iDataPoint && CurrentIndex > iDataPoint - pLine->lnValidValues) { ValidValue = TRUE ; } } else { if (CurrentIndex <= iDataPoint || CurrentIndex > (MaxValues - pLine->lnValidValues + iDataPoint)) { // this is the case when we start the new line in the middle
// and data buffer has been wrap-around.
ValidValue = TRUE ; } }
// only export the data when we determine it is valid
if (ValidValue) { TSPRINTF (UnicodeBuff, pLine->lnValues[CurrentIndex] > (FLOAT)999999.0 ? szLargeValueFormat : szSmallValueFormat, pLine->lnValues[CurrentIndex]) ; ConvertDecimalPoint (UnicodeBuff) ; ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ; } } strcat (TempBuff, pDelimiter) ; StringLen = strlen (TempBuff) ;
if (++TimeToWriteFile > TIME_TO_WRITE) { // better write the buffers before they overflow.
// there are better ways to check for overflow
// but this is good enough
if (!FileWrite (hFile, TempBuff, StringLen)) { goto Exit0 ; } StringLen = TimeToWriteFile = 0 ; TempBuff[0] = '\0' ; } }
if (StringLen) { // write the last block of data
if (!FileWrite (hFile, TempBuff, StringLen)) { goto Exit0 ; } }
return (TRUE) ;
Exit0: return (FALSE) ;
} // ExportLineValue
BOOL ExportCurrentChart (HANDLE hFile, PGRAPHSTRUCT pGraph) { int KnownValue, MaxValues, iValidValues, iDataPoint ; BOOL SimpleCase = FALSE ; int iIndex ;
MaxValues = pGraph->gMaxValues ; KnownValue = pGraph->gKnownValue ; iValidValues = pGraph->gTimeLine.iValidValues ;
if (iValidValues < MaxValues) { // data have not wrapped around, so the oldest time
// is started at 0.
SimpleCase = TRUE ; iValidValues = (KnownValue % MaxValues) + 1 ; }
iDataPoint = KnownValue % MaxValues ;
if (!SimpleCase) { for (iIndex = iDataPoint+1 ; iIndex < MaxValues ; iIndex++) { if (!ExportLineValue (hFile, pGraph, iIndex, iDataPoint)) { goto Exit0 ; } } }
for (iIndex = 0 ; iIndex <= iDataPoint ; iIndex++) { if (!ExportLineValue (hFile, pGraph, iIndex, iDataPoint)) { goto Exit0 ; } }
return (TRUE) ;
Exit0: return (FALSE) ;
} // ExportCurrentChart
void ExportChart (void) {
PGRAPHSTRUCT pGraph ; HANDLE hFile = 0 ; LPTSTR pFileName = NULL ; INT ErrCode = 0 ;
if (!(pGraph = pGraphs)) { return ; }
// see if there is anything to export..
if (!(pGraph->pLineFirst)) { return ; }
SetHourglassCursor() ; if (ErrCode = ExportFileOpen (hWndGraph, &hFile, pGraph->gInterval, &pFileName)) { goto Exit0 ; }
if (!pFileName) { // this is the case when user cancel.
goto Exit0 ; }
// export the column labels
if (!ExportChartLabels (hFile, pGraph)) { ErrCode = ERR_EXPORT_FILE ; goto Exit0 ; }
// export the lines
if (PlayingBackLog()) { if (!ExportLogChart (hFile, pGraph)) { ErrCode = ERR_EXPORT_FILE ; goto Exit0 ; } } else { if (!ExportCurrentChart (hFile, pGraph)) { ErrCode = ERR_EXPORT_FILE ; goto Exit0 ; } } Exit0:
SetArrowCursor() ;
if (hFile) { CloseHandle (hFile) ; }
if (pFileName) { if (ErrCode) { DlgErrorBox (hWndGraph, ErrCode, pFileName) ; }
MemoryFree (pFileName) ; }
} // ExportChart
typedef struct CHARTDATAPOINTSTRUCT { int iLogIndex ; int xDispDataPoint ; } CHARTDATAPOINT, *PCHARTDATAPOINT ;
void PlaybackChartDataPoint (PCHARTDATAPOINT pChartDataPoint) { // PlaybackChartDataPoint
int iDisplayTics ; // num visual points to display
int iDisplayTic ; int iLogTic ; int iLogTicsMove ; BOOL bFirstTime = TRUE; int iLogTicsRemaining ; int numOfData, xDispDataPoint, rectWidth, xPos ; PGRAPHSTRUCT pGraph ;
pGraph = GraphData (hWndGraph) ;
iLogTicsRemaining = PlaybackLog.iSelectedTics ;
// we only have iDisplayTics-1 points since
// we have to use the first two sample points to
// get the first data points.
if (iLogTicsRemaining <= pGraphs->gMaxValues) { iDisplayTics = iLogTicsRemaining ; } else { iDisplayTics = pGraphs->gMaxValues ; }
iDisplayTic = -1 ; iLogTic = PlaybackLog.StartIndexPos.iPosition ;
numOfData = pGraph->gMaxValues - 1 ; rectWidth = pGraph->rectData.right - pGraph->rectData.left ; xDispDataPoint = pGraph->rectData.left ;
while (iDisplayTics && numOfData) {
if (!bFirstTime) { iDisplayTic++ ; } else { bFirstTime = FALSE ;
// get the second sample data to form the first data point
iLogTic++ ; iLogTicsRemaining-- ;
iDisplayTic++ ; }
pChartDataPoint[iDisplayTic].iLogIndex = iLogTic ; pChartDataPoint[iDisplayTic].xDispDataPoint = xDispDataPoint ;
// setup DDA to get the index of the next sample point
iLogTicsMove = DDA_DISTRIBUTE (iLogTicsRemaining, iDisplayTics) ; iLogTicsRemaining -= iLogTicsMove ; iLogTic += iLogTicsMove ;
xPos = DDA_DISTRIBUTE (rectWidth, numOfData) ; xDispDataPoint += xPos ; numOfData-- ; rectWidth -= xPos ;
iDisplayTics-- ;
} // while
} // PlaybackChartDataPoint
|