REPORT.C

/***************************************************************************** 
*
* Report.c - This file contains the report window handler. Some of the
* support routines are in RptFct.c
*
* Microsoft Confidential
* Copyright 1992 - 1998 Microsoft Corporation
*
* Author -
*
* Hon-Wah Chan
*
****************************************************************************/

#include "perfmon.h"
#include <stdio.h> // for sprintf
#include <string.h> // for strncpy
#include "report.h" // Exported declarations for this file

#include "addline.h" // for AddLine, EditLine
#include "perferr.h" // for PostError
#include "fileutil.h" // for FileHandleCreate
#include "line.h" // for LineAppend
#include "pmemory.h" // for MemoryXXX (mallloc-type) routines
#include "perfdata.h" // for UpdateLines
#include "perfmops.h" // for DoWindowDrag
#include "playback.h" // for PlaybackLines, PlayingBackLog
#include "system.h" // for SystemGet
#include "utils.h"
#include "menuids.h" // for IDM_VIEWREPORT
#include "fileopen.h" // for FileGetName
#include "counters.h" // for CounterEntry


//==========================================================================//
// Local Data //
//==========================================================================//

TCHAR szSystemFormat [ResourceStringLen] ;
TCHAR szObjectFormat [ResourceStringLen] ;


//=============================//
// Report Class //
//=============================//


TCHAR szReportWindowClass[] = TEXT("PerfRpt") ;
#define dwReportClassStyle (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS)
#define iReportClassExtra (0)
#define iReportWindowExtra (0)
#define dwReportWindowStyle (WS_CHILD | WS_VSCROLL | WS_HSCROLL)


#define szValuePlaceholder TEXT("-999999999.999")
#define szValueLargeHexPlaceholder TEXT(" xBBBBBBBBDDDDDDDD")

#define szHexFormat TEXT("x%08lX")
#define szLargeHexFormat TEXT("x%08lX%08lX")
#define szLargeValueFormat TEXT("%12.0f")
#define eStatusLargeValueMax ((FLOAT) 999999999.0)
#define szValueFormat TEXT("%12.3f")


//==========================================================================//
// Local Functions //
//==========================================================================//


PREPORT AllocateReportData (HWND hWndReport)
{
PREPORT pReport ;

pReport = ReportData (hWndReport) ;

pReport->hWnd = hWndReport ;
pReport->iStatus = iPMStatusClosed ;
pReport->bManualRefresh = FALSE ;
pReport->bModified = FALSE ;

pReport->Visual.iColorIndex = 0 ;
pReport->Visual.iWidthIndex = -1 ;
pReport->Visual.iStyleIndex = -1 ;

pReport->iIntervalMSecs = iDefaultReportIntervalSecs * 1000 ;
pReport->pSystemFirst = NULL ;
pReport->pLineFirst = NULL ;

pReport->CurrentItemType = REPORT_TYPE_NOTHING ;
pReport->CurrentItem.pLine = NULL ;

return (pReport) ;
} // AllocateReportData


void FreeReportData (PREPORT pReport)
{ // FreeReportData
} // FreeReportData



BOOL LineCounterRemove (PPLINE ppLineFirst,
PLINE pLineRemove)
{
PLINE pLine ;

if (*ppLineFirst == pLineRemove)
{
*ppLineFirst = (*ppLineFirst)->pLineCounterNext ;
return (TRUE) ;
}

for (pLine = *ppLineFirst ;
pLine->pLineCounterNext ;
pLine = pLine->pLineCounterNext)
{ // for
if (pLine->pLineCounterNext == pLineRemove)
{
pLine->pLineCounterNext = pLineRemove->pLineCounterNext ;
return (TRUE) ;
} // if
} // for

return (FALSE) ;
} // LineCounterRemove



void DrawCounter (HDC hDC, PREPORT pReport,
PCOUNTERGROUP pCounterGroup)
{ // DrawCounter

RECT Rect ;


if (!pCounterGroup->pLineFirst)
return ;

SelectFont (hDC, pReport->hFont) ;
TextOut (hDC, xCounterMargin, pCounterGroup->yLine,
pCounterGroup->pLineFirst->lnCounterName,
lstrlen (pCounterGroup->pLineFirst->lnCounterName)) ;

if (pCounterGroup == pReport->CurrentItem.pCounter)
{
ReportCounterRect (pReport, pCounterGroup, &Rect) ;
DrawFocusRect (hDC, &Rect) ;
}

} // DrawCounter


void DrawObject (HDC hDC, PREPORT pReport,
POBJECTGROUP pObjectGroup)
{ // DrawObject
TCHAR szLine [LongTextLen] ;
PCOUNTERGROUP pCounterGroup ;
PCOLUMNGROUP pColumnGroup ;

if (!pObjectGroup->pCounterGroupFirst)
{
return ;
}

SelectFont (hDC, pReport->hFontHeaders) ;

SetTextAlign (hDC, TA_RIGHT) ;

for (pColumnGroup = pObjectGroup->pColumnGroupFirst ;
pColumnGroup ;
pColumnGroup = pColumnGroup->pColumnGroupNext)
{ // for
// Draw Parent
if (pColumnGroup->lpszParentName)
TextOut (hDC,
ValueMargin (pReport) +
pColumnGroup->xPos + pColumnGroup->xWidth,
pObjectGroup->yFirstLine - pReport->yLineHeight,
pColumnGroup->lpszParentName,
lstrlen (pColumnGroup->lpszParentName)) ;

// Draw Instance
if (pColumnGroup->lpszInstanceName)
{
TextOut (hDC,
ValueMargin (pReport) +
pColumnGroup->xPos + pColumnGroup->xWidth,
pObjectGroup->yFirstLine,
pColumnGroup->lpszInstanceName,
lstrlen (pColumnGroup->lpszInstanceName)) ;
}

if (pColumnGroup == pReport->CurrentItem.pColumn)
{
RECT Rect ;

ReportColumnRect (pReport, pColumnGroup, &Rect) ;
DrawFocusRect (hDC, &Rect) ;
}

} // for
SetTextAlign (hDC, TA_LEFT) ;

TSPRINTF (szLine, szObjectFormat, pObjectGroup->lpszObjectName) ;
TextOut (hDC,
xObjectMargin, pObjectGroup->yFirstLine,
szLine, lstrlen (szLine)) ;

if (pObjectGroup == pReport->CurrentItem.pObject)
{
RECT Rect ;

ReportObjectRect (pReport, pObjectGroup, &Rect) ;
DrawFocusRect (hDC, &Rect) ;
}

SelectFont (hDC, pReport->hFont) ;

for (pCounterGroup = pObjectGroup->pCounterGroupFirst ;
pCounterGroup ;
pCounterGroup = pCounterGroup->pCounterGroupNext)
{ // for
DrawCounter (hDC, pReport, pCounterGroup) ;
} // for

} // DrawObject


void DrawSystem (HDC hDC, PREPORT pReport, PSYSTEMGROUP pSystemGroup)
{ // DrawSystem
TCHAR szLine [LongTextLen] ;
POBJECTGROUP pObjectGroup ;

SelectFont (hDC, pReport->hFontHeaders) ;

if (!pSystemGroup->pObjectGroupFirst)
return ;

SetTextAlign (hDC, TA_LEFT) ;
TSPRINTF (szLine, szSystemFormat, pSystemGroup->lpszSystemName) ;
TextOut (hDC,
xSystemMargin, pSystemGroup->yFirstLine,
szLine, lstrlen (szLine)) ;

if (pSystemGroup == pReport->CurrentItem.pSystem)
{
RECT Rect ;

ReportSystemRect (pReport, pSystemGroup, &Rect) ;
DrawFocusRect (hDC, &Rect) ;
}

for (pObjectGroup = pSystemGroup->pObjectGroupFirst ;
pObjectGroup ;
pObjectGroup = pObjectGroup->pObjectGroupNext)
{ // for
DrawObject (hDC, pReport, pObjectGroup) ;
} // for
} // DrawSystem

void DrawReportValue (HDC hDC, PREPORT pReport, PLINE pLine)
{ // DrawReportValue
TCHAR szValue [20] ;
FLOAT eValue ;
RECT rectValue ;

// skip until we have collect enough samples for the first data
if (pLine->bFirstTime == 0)
{
eValue = CounterEntry (pLine) ;
if (pLine->lnCounterType == PERF_COUNTER_RAWCOUNT_HEX ||
pLine->lnCounterType == PERF_COUNTER_LARGE_RAWCOUNT_HEX)
{
DWORD LowValue ;
DWORD HighValue ;

LowValue = (DWORD) (pLine->lnaCounterValue[0]) ;
HighValue = (DWORD) (pLine->lnaCounterValue[0] >> 32);

if (pLine->lnCounterType == PERF_COUNTER_RAWCOUNT_HEX ||
HighValue == 0)
{
TSPRINTF (szValue,
szHexFormat,
LowValue) ;
}
else
{

TSPRINTF (szValue,
szLargeHexFormat,
HighValue,
LowValue) ;
}
}
else
{
TSPRINTF (szValue,
(eValue > eStatusLargeValueMax) ?
szLargeValueFormat : szValueFormat,
eValue) ;
ConvertDecimalPoint (szValue) ;
}
}
else
{
// draw "- - - -"
lstrcpy(szValue, DashLine);
}

ReportLineValueRect (pReport, pLine, &rectValue) ;

ExtTextOut (hDC,
rectValue.right - 2, rectValue.top,
ETO_CLIPPED | ETO_OPAQUE,
&rectValue,
szValue, lstrlen (szValue), NULL) ;

if (pReport->CurrentItemType == REPORT_TYPE_LINE &&
pLine == pReport->CurrentItem.pLine)
{
DrawFocusRect (hDC, &rectValue) ;
}
} // DrawReportValue


void DrawReportValues (HDC hDC, PREPORT pReport)
{
PSYSTEMGROUP pSystemGroup ;
POBJECTGROUP pObjectGroup ;
PCOUNTERGROUP pCounterGroup ;
PLINE pLine ;

SelectFont (hDC, pReport->hFont) ;
SetTextAlign (hDC, TA_RIGHT) ;

for (pSystemGroup = pReport->pSystemGroupFirst ;
pSystemGroup ;
pSystemGroup = pSystemGroup->pSystemGroupNext)
{ // for System...
for (pObjectGroup = pSystemGroup->pObjectGroupFirst ;
pObjectGroup ;
pObjectGroup = pObjectGroup->pObjectGroupNext)
{ // for Object...
for (pCounterGroup = pObjectGroup->pCounterGroupFirst ;
pCounterGroup ;
pCounterGroup = pCounterGroup->pCounterGroupNext)
{ // for Counter...
for (pLine = pCounterGroup->pLineFirst ;
pLine ;
pLine = pLine->pLineCounterNext)
{ // for Line...
DrawReportValue (hDC, pReport, pLine) ;
} // for Line...
} // for Counter...
} // for Object
} // for System...

}


void DrawReportHeaders (HDC hDC, PREPORT pReport)
{ // DrawReportHeaders
PSYSTEMGROUP pSystemGroup ;

for (pSystemGroup = pReport->pSystemGroupFirst ;
pSystemGroup ;
pSystemGroup = pSystemGroup->pSystemGroupNext)
{ // for
DrawSystem (hDC, pReport, pSystemGroup) ;
} // for
} // DrawReportHeaders


void DrawReport (HDC hDC, PREPORT pReport)
{
SetBkColor (hDC, GetSysColor(COLOR_WINDOW)) ;
DrawReportHeaders (hDC, pReport) ;
//UpdateLines (&(pReport->pSystemFirst), pReport->pLineFirst) ;
DrawReportValues (hDC, pReport) ;
}



void SetLinePosition (HDC hDC,
PREPORT pReport,
POBJECTGROUP pObjectGroup,
PLINE pLine)
{ // SetLinePositions
PCOLUMNGROUP pColumnGroup ;

pColumnGroup = GetColumnGroup (pReport, pObjectGroup, pLine) ;
if (!pColumnGroup)
{
pLine->xReportPos = 0 ;
pLine->iReportColumn = -1 ;
}
else
{
pLine->xReportPos = pColumnGroup->xPos ;
pLine->iReportColumn = pColumnGroup->ColumnNumber ;
}
} // SetLinePosition


void SetCounterPositions (HDC hDC,
PREPORT pReport,
POBJECTGROUP pObjectGroup,
PCOUNTERGROUP pCounterGroup,
int yLine)
{ // SetCounterPositions
PLINE pLine ;
int yPos ;


if (!pCounterGroup->pLineFirst)
return ;

yPos = pCounterGroup->yLine ;

SelectFont (hDC, pReport->hFontHeaders) ;

for (pLine = pCounterGroup->pLineFirst ;
pLine ;
pLine = pLine->pLineCounterNext)
{ // for
SetLinePosition (hDC, pReport, pObjectGroup, pLine) ;
pLine->yReportPos = yPos ;
} // for
} // SetCounterPositions


void SetColumnPositions (HDC hDC,
PREPORT pReport,
POBJECTGROUP pObjectGroup)
{ // SetColumnPositions
int xPos ;
PCOLUMNGROUP pColumnGroup ;

xPos = 0 ;
for (pColumnGroup = pObjectGroup->pColumnGroupFirst ;
pColumnGroup ;
pColumnGroup = pColumnGroup->pColumnGroupNext)
{ // for
pColumnGroup->xWidth = max (max (pColumnGroup->ParentNameTextWidth,
pColumnGroup->InstanceNameTextWidth),
pReport->xValueWidth) ;
pColumnGroup->xPos = xPos ;
pColumnGroup->yFirstLine = pObjectGroup->yFirstLine ;
xPos += (pColumnGroup->xWidth + xColumnMargin) ;
} // for
} // SetColumnPositions


void SetObjectPositions (HDC hDC,
PREPORT pReport,
POBJECTGROUP pObjectGroup,
int yLine)
/*
Effect: Determine and set the logical coordinates for the
object pObject within the report pReport.

For each instance x counter, determine the appropriate
column, adding a column description to the object if
needed.

Called By: SetSystemPositions only.

See Also: SetSystemPositions, SetCounterPositions, ColumnGroup.
*/
{ // SetObjectPositions
PCOUNTERGROUP pCounterGroup ;
int yPos ;
PLINE pLine ;

// check if there is parnet name for this object type
// if so, need to add extra space for the parent name
if (pObjectGroup->pCounterGroupFirst)
{
pCounterGroup = pObjectGroup->pCounterGroupFirst ;
pLine = pCounterGroup->pLineFirst ;
if (pLine && LineParentName(pLine))
{
pObjectGroup->yFirstLine += yLine ;
}
}

SetColumnPositions (hDC, pReport, pObjectGroup) ;

yPos = pObjectGroup->yFirstLine + yLine ;

for (pCounterGroup = pObjectGroup->pCounterGroupFirst ;
pCounterGroup ;
pCounterGroup = pCounterGroup->pCounterGroupNext)
{ // for
pCounterGroup->yLine = yPos + yLine ;

SetCounterPositions (hDC, pReport, pObjectGroup, pCounterGroup, yLine) ;

yPos = pCounterGroup->yLine ;
} // for

pObjectGroup->yLastLine = yPos + yLine ;
} // SetObjectPositions


void SetSystemPositions (HDC hDC,
PREPORT pReport,
PSYSTEMGROUP pSystemGroup,
int yLine)
{ // SetSystemPositions
POBJECTGROUP pObjectGroup ;
int yPos ;

yPos = pSystemGroup->yFirstLine ;

for (pObjectGroup = pSystemGroup->pObjectGroupFirst ;
pObjectGroup ;
pObjectGroup = pObjectGroup->pObjectGroupNext)
{ // for
pObjectGroup->yFirstLine = yPos + yLine ;

SetObjectPositions (hDC, pReport, pObjectGroup, yLine) ;

yPos = pObjectGroup->yLastLine ;
} // for

pSystemGroup->yLastLine = yPos + yLine ;
} // SetSystemPositions


void static SetScrollRanges (HWND hWnd)
{ // SetScrollRanges
PREPORT pReport ;
RECT rectClient ;
int xWidth, yHeight ;

GetClientRect (hWnd, &rectClient) ;
xWidth = rectClient.right - rectClient.left ;
yHeight = rectClient.bottom - rectClient.top ;

pReport = ReportData (hWnd) ;

SetScrollRange (hWnd, SB_VERT,
0, max (0, pReport->yHeight - yHeight),
TRUE) ;
SetScrollRange (hWnd, SB_HORZ,
0, max (0, pReport->xWidth - xWidth),
TRUE) ;
} // SetScrollRanges

//==========================================================================//
// Message Handlers //
//==========================================================================//


void static OnCreate (HWND hWnd)
{ // OnCreate
HDC hDC ;
PREPORT pReport ;

pReport = AllocateReportData (hWnd) ;
if (!pReport)
return ;

pReport->hFont = hFontScales ;
pReport->hFontHeaders = hFontScalesBold ;

pReport->pLineFirst = NULL ;
pReport->pSystemFirst = NULL ;

pReport->pSystemGroupFirst = NULL ;

hDC = GetDC (hWnd) ;

SelectFont (hDC, pReport->hFont) ;


pReport->yLineHeight = FontHeight (hDC, TRUE) ;
pReport->xValueWidth = TextWidth (hDC, szValuePlaceholder) ;
ReleaseDC (hWnd, hDC) ;

pReport->xWidth = 0 ;
pReport->yHeight = 0 ;

StringLoad (IDS_SYSTEMFORMAT, szSystemFormat) ;
StringLoad (IDS_OBJECTFORMAT, szObjectFormat) ;
} // OnCreate


void static OnPaint (HWND hWnd)
{
HDC hDC ;
PAINTSTRUCT ps ;
PREPORT pReport ;



pReport = ReportData (hWnd) ;

hDC = BeginPaint (hWnd, &ps) ;
//hDC = hReportDC ;
SetWindowOrgEx (hDC,
GetScrollPos (hWnd, SB_HORZ),
GetScrollPos (hWnd, SB_VERT),
NULL) ;

DrawReport (hDC, pReport) ;

EndPaint (hWnd, &ps) ;
}


void static UpdateReportValues (PREPORT pReport)
/*
Effect: Redraw all the visible report values of pReport.
Since drawing the values completely covers any
previous values, there is no need to erase (or flicker)
between updating values.

Called By: ReportTimer, OnVScroll, OnHScroll.
*/
{ // UpdateReportValues
HDC hDC ;

hDC = GetDC (pReport->hWnd) ;

SetBkColor (hDC, GetSysColor(COLOR_WINDOW)) ;
SetWindowOrgEx (hDC,
GetScrollPos (pReport->hWnd, SB_HORZ),
GetScrollPos (pReport->hWnd, SB_VERT),
NULL) ;

DrawReportValues (hDC, pReport) ;
ReleaseDC (pReport->hWnd, hDC) ;

} // UpdateReportValues



void static OnHScroll (HWND hWnd,
int iScrollCode,
int iScrollNewPos)
{ // OnHScroll
PREPORT pReport ;
int iScrollAmt, iScrollPos, iScrollRange ;
int iScrollLo ;
RECT rectClient ;
int xWidth ;

pReport = ReportData (hWnd) ;

GetClientRect (hWnd, &rectClient) ;
xWidth = rectClient.right - rectClient.left ;

if (pReport->xWidth <= xWidth)
{
// no horz scroll bar, forget it
return ;
}

iScrollPos = GetScrollPos (hWnd, SB_HORZ) ;

GetScrollRange (hWnd, SB_HORZ, &iScrollLo, &iScrollRange) ;


switch (iScrollCode)
{
case SB_LINEUP:
iScrollAmt = - Report.yLineHeight ;
break ;

case SB_LINEDOWN:
iScrollAmt = Report.yLineHeight ;
break ;

case SB_PAGEUP:
iScrollAmt = - (rectClient.right - rectClient.left) / 2 ;
break ;

case SB_PAGEDOWN:
iScrollAmt = (rectClient.right - rectClient.left) / 2 ;
break ;

case SB_THUMBPOSITION:
iScrollAmt = iScrollNewPos - iScrollPos ;
break ;

default:
iScrollAmt = 0 ;
} // switch

iScrollAmt = PinInclusive (iScrollAmt,
-iScrollPos,
iScrollRange - iScrollPos) ;
if (iScrollAmt)
{
iScrollPos += iScrollAmt ;
ScrollWindow (hWnd, -iScrollAmt, 0, NULL, NULL) ;
SetScrollPos (hWnd, SB_HORZ, iScrollPos, TRUE) ;
UpdateWindow (hWnd) ;
#if 0
UpdateReportValues (pReport) ;
#endif
}
} // OnHScroll



void static OnVScroll (HWND hWnd,
int iScrollCode,
int iScrollNewPos)
{ // OnVScroll
PREPORT pReport ;
int iScrollAmt, iScrollPos, iScrollRange ;
int iScrollLo ;
RECT rectClient ;

pReport = ReportData (hWnd) ;

iScrollPos = GetScrollPos (hWnd, SB_VERT) ;
GetScrollRange (hWnd, SB_VERT, &iScrollLo, &iScrollRange) ;

GetClientRect (hWnd, &rectClient) ;

switch (iScrollCode)
{
case SB_LINEUP:
iScrollAmt = - Report.yLineHeight ;
break ;

case SB_LINEDOWN:
iScrollAmt = Report.yLineHeight ;
break ;

case SB_PAGEUP:
iScrollAmt = - (rectClient.bottom - rectClient.top) / 2 ;
break ;

case SB_PAGEDOWN:
iScrollAmt = (rectClient.bottom - rectClient.top) / 2 ;
break ;

case SB_THUMBPOSITION:
iScrollAmt = iScrollNewPos - iScrollPos ;
break ;

default:
iScrollAmt = 0 ;
} // switch

iScrollAmt = PinInclusive (iScrollAmt,
-iScrollPos,
iScrollRange - iScrollPos) ;
if (iScrollAmt)
{
iScrollPos += iScrollAmt ;
ScrollWindow (hWnd, 0, -iScrollAmt, NULL, NULL) ;
SetScrollPos (hWnd, SB_VERT, iScrollPos, TRUE) ;

// WindowInvalidate (hWnd) ;
UpdateWindow (hWnd) ;
#if 0
UpdateReportValues (pReport) ;
#endif
}
} // OnVScroll

void static OnKeyDown (HWND hWnd, DWORD wParam)
{
switch (wParam)
{
case VK_UP:
OnVScroll (hWnd, SB_LINEUP, 0) ;
break ;

case VK_DOWN:
OnVScroll (hWnd, SB_LINEDOWN, 0) ;
break ;

case VK_LEFT:
OnHScroll (hWnd, SB_LINEUP, 0) ;
break ;

case VK_RIGHT:
OnHScroll (hWnd, SB_LINEDOWN, 0) ;
break ;

case VK_PRIOR:
OnVScroll (hWnd, SB_PAGEUP, 0) ;
break ;

case VK_NEXT:
OnVScroll (hWnd, SB_PAGEDOWN, 0) ;
break ;
}
} // OnKeyDown


LRESULT APIENTRY ReportWndProc (HWND hWnd,
WORD wMsg,
DWORD wParam,
LONG lParam)
{ // ReportWndProc
BOOL bCallDefProc ;
LRESULT lReturnValue ;

bCallDefProc = FALSE ;
lReturnValue = 0L ;

switch (wMsg)
{ // switch
case WM_CREATE:
OnCreate (hWnd) ;
break ;

case WM_LBUTTONDOWN:

if (!OnReportLButtonDown (hWnd, LOWORD (lParam), HIWORD (lParam)))
{
// mouse click do not hit on any entries, see if we
// need to drag Perfmon
if (!(Options.bMenubar))
{
DoWindowDrag (hWnd, lParam) ;
}
}
break ;

case WM_LBUTTONDBLCLK:
SendMessage (hWndMain, WM_LBUTTONDBLCLK, wParam, lParam) ;
break ;

case WM_PAINT:
OnPaint (hWnd) ;
break ;

case WM_SIZE:
SetScrollRanges (hWnd) ;
break ;

case WM_HSCROLL:
OnHScroll (hWnd, LOWORD (wParam), HIWORD (wParam)) ;
break ;

case WM_VSCROLL:
OnVScroll (hWnd, LOWORD (wParam), HIWORD (wParam)) ;
break ;

case WM_TIMER:
ReportTimer (hWnd, FALSE) ;
break ;

case WM_KEYDOWN:
OnKeyDown (hWnd, wParam) ;
break ;

case WM_DESTROY:
KillTimer (hWnd, ReportTimerID) ;
break ;

default:
bCallDefProc = TRUE ;
} // switch


if (bCallDefProc)
lReturnValue = DefWindowProc (hWnd, wMsg, wParam, lParam) ;

return (lReturnValue);
} // ReportWndProc



//==========================================================================//
// Exported Functions //
//==========================================================================//

#if 0
PREPORT ReportData (HWND hWndReport)
{
return (&Report) ;
}
#endif

void SetReportTimer (PREPORT pReport)
{
if (pReport->iStatus == iPMStatusCollecting)
KillTimer (pReport->hWnd, ReportTimerID) ;

SetTimer (pReport->hWnd, ReportTimerID,
pReport->iIntervalMSecs , NULL) ;
pReport->iStatus = iPMStatusCollecting ;
}


void ClearReportTimer (PREPORT pReport)
{
pReport->iStatus = iPMStatusClosed ;
KillTimer (pReport->hWnd, ReportTimerID) ;
}


BOOL ReportInitializeApplication (void)
{ // ReportInitializeApplication
BOOL bSuccess ;
WNDCLASS wc ;

//=============================//
// Register ReportWindow class //
//=============================//


wc.style = dwReportClassStyle ;
wc.lpfnWndProc = (WNDPROC) ReportWndProc ;
wc.hInstance = hInstance ;
wc.cbClsExtra = iReportWindowExtra ;
wc.cbWndExtra = iReportClassExtra ;
wc.hIcon = NULL ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
// wc.hbrBackground = GetStockObject (WHITE_BRUSH) ;
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = szReportWindowClass ;

bSuccess = RegisterClass (&wc) ;


//=============================//
// Register Child classes //
//=============================//

return (bSuccess) ;
} // ReportInitializeApplication





HWND CreateReportWindow (HWND hWndParent)
/*
Effect: Create the graph window. This window is a child of
hWndMain and is a container for the graph data,
graph label, graph legend, and graph status windows.

Note: We dont worry about the size here, as this window
will be resized whenever the main window is resized.

*/
{
return (CreateWindow (szReportWindowClass, // window class
NULL, // caption
dwReportWindowStyle, // style for window
0, 0, // initial position
0, 0, // initial size
hWndParent, // parent
NULL, // menu
hInstance, // program instance
NULL)) ; // user-supplied data
} // CreateReportWindow



void SetReportPositions (HDC hDC,
PREPORT pReport)
{
PSYSTEMGROUP pSystemGroup ;
int yLine ;
int yPos ;


// pReport->xMaxCounterWidth = 0 ;

yLine = pReport->yLineHeight ;
yPos = 2 * yLine ;

for (pSystemGroup = pReport->pSystemGroupFirst ;
pSystemGroup ;
pSystemGroup = pSystemGroup->pSystemGroupNext)
{ // for
pSystemGroup->yFirstLine = yPos + yLine ;

SetSystemPositions (hDC, pReport, pSystemGroup, yLine) ;

yPos = pSystemGroup->yLastLine ;
} // for

pReport->yHeight = yPos ;

SetScrollRanges (pReport->hWnd) ;
} // SetReportPositions



void PlaybackReport (HWND hWndReport)
{ // PlaybackReport
PREPORT pReport ;

pReport = ReportData (hWndReport) ;

PlaybackLines (pReport->pSystemFirst,
pReport->pLineFirst,
PlaybackLog.StartIndexPos.iPosition) ;
PlaybackLines (pReport->pSystemFirst,
pReport->pLineFirst,
PlaybackLog.StopIndexPos.iPosition) ;
} // PlaybackReport


BOOL CurrentReportItem (HWND hWndReport)
{ // CurrentReportItem
PREPORT pReport ;

pReport = ReportData (hWndReport) ;
if (!pReport)
return (FALSE) ;

return (pReport->CurrentItemType != REPORT_TYPE_NOTHING) ;
} // CurrentReportItem




BOOL AddReport (HWND hWndParent)
{
PREPORT pReport ;
LPTSTR pCurrentSystem ;
POBJECTGROUP pParentObject ;

pReport = ReportData (hWndReport) ;

if (pReport->CurrentItemType == REPORT_TYPE_LINE)
{
pCurrentSystem = pReport->CurrentItem.pLine->lnSystemName ;
}
else if (pReport->CurrentItemType == REPORT_TYPE_SYSTEM)
{
pCurrentSystem = pReport->CurrentItem.pSystem->lpszSystemName ;
}
else if (pReport->CurrentItemType == REPORT_TYPE_OBJECT)
{
pCurrentSystem = pReport->CurrentItem.pObject->pParentSystem->lpszSystemName ;
}
else if (pReport->CurrentItemType == REPORT_TYPE_COLUMN)
{
pParentObject = pReport->CurrentItem.pColumn->pParentObject ;
pCurrentSystem = pParentObject->pParentSystem->lpszSystemName ;
}
else if (pReport->CurrentItemType == REPORT_TYPE_COUNTER)
{
pParentObject = pReport->CurrentItem.pCounter->pParentObject ;
pCurrentSystem = pParentObject->pParentSystem->lpszSystemName ;
}
else
{
pCurrentSystem = NULL ;
}


return (AddLine (hWndParent,
&(pReport->pSystemFirst),
&(pReport->Visual),
pCurrentSystem,
LineTypeReport)) ;
}


BOOL ToggleReportRefresh (HWND hWnd)
{ // ToggleReportRefresh
PREPORT pReport ;

pReport = ReportData (hWnd) ;

if (pReport->bManualRefresh)
SetReportTimer (pReport) ;
else
ClearReportTimer (pReport) ;

pReport->bManualRefresh = !pReport->bManualRefresh ;
return (pReport->bManualRefresh) ;
} // ToggleReportRefresh

BOOL ReportRefresh (HWND hWnd)
{ // ReportRefresh
PREPORT pReport ;

pReport = ReportData (hWnd) ;

return (pReport->bManualRefresh) ;
} // ReportRefresh



void ReportTimer (HWND hWnd, BOOL bForce)
{
PREPORT pReport ;

pReport = ReportData (hWnd) ;

if (PlayingBackLog () || !pReport)
{
return;
}

if (bForce || !pReport->bManualRefresh)
{ // if
UpdateLines (&(pReport->pSystemFirst), pReport->pLineFirst) ;
if (iPerfmonView == IDM_VIEWREPORT && !bPerfmonIconic)
{
// only need to draw the data when we are viewing it...
UpdateReportValues (pReport) ;
}
} // if
} // ReportTimer

BOOL SaveReport (HWND hWndReport, HANDLE hInputFile, BOOL bGetFileName)
{
PREPORT pReport ;
PLINE pLine ;
HANDLE hFile ;
DISKREPORT DiskReport ;
PERFFILEHEADER FileHeader ;
TCHAR szFileName [256] ;
BOOL newFileName = FALSE ;

pReport = ReportData (hWndReport) ;
if (!pReport)
{
return (FALSE) ;
}

if (hInputFile)
{
// use the input file handle if it is available
// this is the case for saving workspace data
hFile = hInputFile ;
}
else
{
if (pReportFullFileName)
{
lstrcpy (szFileName, pReportFullFileName) ;
}
if (bGetFileName || pReportFullFileName == NULL)
{
if (!FileGetName (hWndReport, IDS_REPORTFILE, szFileName))
{
return (FALSE) ;
}
newFileName = TRUE ;
}

hFile = FileHandleCreate (szFileName) ;

if (hFile && newFileName)
{
ChangeSaveFileName (szFileName, IDM_VIEWREPORT) ;
}
else if (!hFile)
{
DlgErrorBox (hWndReport, ERR_CANT_OPEN, szFileName) ;
}
}


if (!hFile)
return (FALSE) ;


if (!hInputFile)
{
memset (&FileHeader, 0, sizeof (FileHeader)) ;
lstrcpy (FileHeader.szSignature, szPerfReportSignature) ;
FileHeader.dwMajorVersion = ReportMajorVersion ;
FileHeader.dwMinorVersion = ReportMinorVersion ;

if (!FileWrite (hFile, &FileHeader, sizeof (PERFFILEHEADER)))
{
goto Exit0 ;
}
}

DiskReport.Visual = pReport->Visual ;
DiskReport.bManualRefresh = pReport->bManualRefresh ;
DiskReport.dwIntervalSecs = pReport->iIntervalMSecs ;
DiskReport.dwNumLines = NumLines (pReport->pLineFirst) ;
DiskReport.perfmonOptions = Options ;

if (!FileWrite (hFile, &DiskReport, sizeof (DISKREPORT)))
{
goto Exit0 ;
}

for (pLine = pReport->pLineFirst ;
pLine ;
pLine = pLine->pLineNext)
{ // for
if (!WriteLine (pLine, hFile))
{
goto Exit0 ;
}
} // for

if (!hInputFile)
{
CloseHandle (hFile) ;
}

return (TRUE) ;

Exit0:
if (!hInputFile)
{
CloseHandle (hFile) ;

// only need to report error if not workspace
DlgErrorBox (hWndReport, ERR_SETTING_FILE, szFileName) ;
}
return (FALSE) ;
} // SaveReport


void ReportAddAction (PREPORT pReport)
{
HDC hDC ;

//=============================//
// Calculate report positions //
//=============================//

hDC = GetDC (hWndReport) ;
SetReportPositions (hDC, pReport) ;
ReleaseDC (hWndReport, hDC) ;

if (PlayingBackLog ())
{
PlaybackReport (hWndReport) ;
}
else if (pReport->iStatus == iPMStatusClosed)
{
SetReportTimer (pReport) ;
}

WindowInvalidate (hWndReport) ;
}


BOOL OpenReportVer1 (HANDLE hFile,
DISKREPORT *pDiskReport,
PREPORT pReport,
DWORD dwMinorVersion)
{
HDC hDC ;

pReport->Visual = pDiskReport->Visual ;
pReport->iIntervalMSecs = pDiskReport->dwIntervalSecs ;
if (dwMinorVersion < 3)
{
// convert this to msec
pReport->iIntervalMSecs *= 1000 ;
}
pReport->bManualRefresh = pDiskReport->bManualRefresh ;

bDelayAddAction = TRUE ;
ReadLines (hFile, pDiskReport->dwNumLines,
&(pReport->pSystemFirst), &(pReport->pLineFirst), IDM_VIEWREPORT) ;

if (pReport->pLineFirst)
{
// set focus on the first line
pReport->CurrentItem.pLine = pReport->pLineFirst ;
pReport->CurrentItemType = REPORT_TYPE_LINE ;
}
bDelayAddAction = FALSE ;

//=============================//
// Calculate report positions //
//=============================//

hDC = GetDC (hWndReport) ;
SetReportPositions (hDC, pReport) ;
ReleaseDC (hWndReport, hDC) ;

if (PlayingBackLog ())

{
PlaybackReport (hWndReport) ;
}
else if (pReport->iStatus == iPMStatusClosed)
{
SetReportTimer (pReport) ;
}

WindowInvalidate (hWndReport) ;

return (TRUE) ;
} // OpenReportVer1



BOOL OpenReport (HWND hWndReport,
HANDLE hFile,
DWORD dwMajorVersion,
DWORD dwMinorVersion,
BOOL bReportFile)
{
PREPORT pReport ;
DISKREPORT DiskReport ;
BOOL bSuccess = TRUE ;

pReport = ReportData (hWndReport) ;
if (!pReport)
{
bSuccess = FALSE ;
goto Exit0 ;
}

if (!FileRead (hFile, &DiskReport, sizeof (DISKREPORT)))
{
bSuccess = FALSE ;
goto Exit0 ;
}


switch (dwMajorVersion)
{
case (1):

SetHourglassCursor() ;

ResetReportView (hWndReport) ;

OpenReportVer1 (hFile, &DiskReport, pReport, dwMinorVersion) ;

// change to report view if we are opening a
// report file
if (bReportFile && iPerfmonView != IDM_VIEWREPORT)
{
SendMessage (hWndMain, WM_COMMAND, (LONG)IDM_VIEWREPORT, 0L) ;
}

if (iPerfmonView == IDM_VIEWREPORT)
{
SetPerfmonOptions (&DiskReport.perfmonOptions) ;
}

SetArrowCursor() ;

break ;
} // switch

Exit0:

if (bReportFile)
{
CloseHandle (hFile) ;
}

return (bSuccess) ;
} // OpenReport

void ResetReportView (HWND hWndReport)
{ // ResetReportView
PREPORT pReport ;

pReport = ReportData (hWndReport) ;

if (!pReport)
{
return ;
}

ChangeSaveFileName (NULL, IDM_VIEWREPORT) ;

if (pReport->pSystemGroupFirst)
{
ResetReport (hWndReport) ;
}
} // ResetReportView


void ResetReport (HWND hWndReport)
{ // ResetReport
PREPORT pReport ;
PSYSTEMGROUP pSystemGroup, pSystemGroupDelete ;
POBJECTGROUP pObjectGroup, pObjectGroupDelete ;
PCOUNTERGROUP pCounterGroup, pCounterGroupDelete ;
HDC hDC ;

pReport = ReportData (hWndReport) ;
if (!pReport)
return ;

ClearReportTimer (pReport) ;

pSystemGroup = pReport->pSystemGroupFirst ;
while (pSystemGroup)
{
pObjectGroup = pSystemGroup->pObjectGroupFirst ;
while (pObjectGroup)
{
pCounterGroup = pObjectGroup->pCounterGroupFirst ;
while (pCounterGroup)
{
pCounterGroupDelete = pCounterGroup ;
pCounterGroup = pCounterGroup->pCounterGroupNext ;
MemoryFree (pCounterGroupDelete) ;
} // while pCounter...

pObjectGroupDelete = pObjectGroup ;
pObjectGroup = pObjectGroup->pObjectGroupNext ;
ColumnGroupRemove (pObjectGroupDelete->pColumnGroupFirst) ;
MemoryFree (pObjectGroupDelete->lpszObjectName) ;
MemoryFree (pObjectGroupDelete) ;
} // while pObject

pSystemGroupDelete = pSystemGroup ;
pSystemGroup = pSystemGroup->pSystemGroupNext ;
MemoryFree (pSystemGroupDelete->lpszSystemName) ;
MemoryFree (pSystemGroupDelete) ;
} // while pSystem...

FreeLines (pReport->pLineFirst) ;
pReport->pLineFirst = NULL ;

FreeSystems (pReport->pSystemFirst) ;
pReport->pSystemFirst = NULL ;

pReport->pSystemGroupFirst = NULL ;
pReport->CurrentItemType = REPORT_TYPE_NOTHING ;
pReport->CurrentItem.pLine = NULL ;

// reset scrolling ranges
pReport->xWidth = 0 ;
pReport->yHeight = 0 ;
pReport->xMaxCounterWidth = 0 ;
hDC = GetDC (hWndReport) ;
SetReportPositions (hDC, pReport) ;

SelectFont (hDC, pReport->hFont) ;
pReport->xValueWidth = TextWidth (hDC, szValuePlaceholder) ;

ReleaseDC (hWndReport, hDC) ;

WindowInvalidate (hWndReport) ;
} // ResetReport

void ClearReportDisplay (HWND hWndReport)
{ // ResetReport
PREPORT pReport ;
PLINE pLine;

if (PlayingBackLog())
{
return ;
}

pReport = ReportData (hWndReport) ;
if (!pReport || !pReport->pLineFirst)
return ;

for (pLine = pReport->pLineFirst ;
pLine ;
pLine = pLine->pLineNext)
{
// reset the new data counts
pLine->bFirstTime = 2 ;
}

// re-draw the values
UpdateReportValues (pReport) ;

} // ClearReportDisplay

//=========================================
// we don't print. we just export
//
// if need printing, define KEEP_PRINT
//=========================================
#ifdef KEEP_PRINT
BOOL PrintReportDisplay (HDC hDC,
PREPORT pReport)
{
SetReportPositions (hDC, pReport) ;
DrawReport (hDC, pReport) ;
return TRUE ;
} // PrintReportDisplay



BOOL PrintReport (HWND hWndParent,
HWND hWndReport)
{
PREPORT pReport ;
HDC hDC ;
int xPageWidth ;
int yPageHeight ;
int xValueWidth ;

HFONT hFont, hFontHeaders ;
int yLineHeight ;

pReport = ReportData (hWndReport) ;
if (!pReport)
return (FALSE) ;

hDC = PrintDC () ;
if (!hDC)
{
PostError () ;
return (FALSE) ;
}

xPageWidth = GetDeviceCaps (hDC, HORZRES) ;
yPageHeight = GetDeviceCaps (hDC, VERTRES) ;


StartJob (hDC, TEXT("Performance Monitor Report")) ;
StartPage (hDC) ;


hFont = pReport->hFont ;
hFontHeaders = pReport->hFontHeaders ;
yLineHeight = pReport->yLineHeight ;
xValueWidth = pReport->xValueWidth ;

pReport->hFont = hFontPrinterScales ;
pReport->hFontHeaders = hFontPrinterScalesBold ;

SelectFont (hDC, pReport->hFont) ;
pReport->yLineHeight = FontHeight (hDC, TRUE) ;

pReport->xValueWidth = TextWidth (hDC, szValuePlaceholder) ;

PrintReportDisplay (hDC, pReport) ;

EndPage (hDC) ;
EndJob (hDC) ;

DeleteDC (hDC) ;


pReport->hFont = hFont ;
pReport->hFontHeaders = hFontHeaders ;
pReport->yLineHeight = yLineHeight ;

pReport->xValueWidth = xValueWidth ;

hDC = GetDC (hWndReport) ;
SetReportPositions (hDC, pReport) ;
ReleaseDC (hWndReport, hDC) ;

return (FALSE) ;
} // PrintReport

// we don't print. we just export
#endif



BOOL ReportInsertLine (HWND hWnd, PLINE pLine)
/*
Effect: Insert the line pLine into the data structures for the
Report of window hWnd. The line is added to the list of
lines, and also added to the report structure in the
appropriate System, Object, and Counter.

Returns: Whether the function was successful. If this function
returns FALSE, the line was not added.
*/
{ // ReportInsertLine
HDC hDC ;
PREPORT pReport ;
PSYSTEMGROUP pSystemGroup ;
POBJECTGROUP pObjectGroup ;
PCOUNTERGROUP pCounterGroup ;
PLINE pLineEquivalent ;
int OldCounterWidth ;
BOOL bNewCounterGroup ;

pReport = ReportData (hWnd) ;
pReport->bModified = TRUE ;

pLineEquivalent = FindEquivalentLine (pLine, pReport->pLineFirst) ;
if (pLineEquivalent)
{
return (FALSE) ;
}
else
{
//=============================//
// Add line, line's system //
//=============================//

LineAppend (&pReport->pLineFirst, pLine) ;
SystemAdd (&pReport->pSystemFirst, pLine->lnSystemName) ;


//=============================//
// Find correct spot; add line //
//=============================//

pSystemGroup = GetSystemGroup (pReport, pLine->lnSystemName) ;
pObjectGroup = GetObjectGroup (pSystemGroup, pLine->lnObjectName) ;
pCounterGroup = GetCounterGroup (pObjectGroup,
pLine->lnCounterDef.CounterNameTitleIndex,
&bNewCounterGroup,
pLine->lnCounterName) ;

if (!pCounterGroup)
return (FALSE) ;

LineCounterAppend (&pCounterGroup->pLineFirst, pLine) ;

//=============================//
// Calculate report positions //
//=============================//
hDC = GetDC (hWnd) ;
SelectFont (hDC, pReport->hFontHeaders) ;

if (bNewCounterGroup)
{
// re-calc. the max. counter group width
OldCounterWidth = pReport->xMaxCounterWidth ;
pReport->xMaxCounterWidth =
max (pReport->xMaxCounterWidth,
TextWidth (hDC, pLine->lnCounterName)) ;
if (OldCounterWidth < pReport->xMaxCounterWidth)
{
// adjust the report width with the new counter width
pReport->xWidth +=
(pReport->xMaxCounterWidth - OldCounterWidth);
}
}

if (pLine->lnCounterType == PERF_COUNTER_LARGE_RAWCOUNT_HEX)
{
SelectFont (hDC, pReport->hFont) ;
pReport->xValueWidth = TextWidth (hDC, szValueLargeHexPlaceholder) ;
}

if (!bDelayAddAction)
{
SetReportPositions (hDC, pReport) ;
}
ReleaseDC (hWnd, hDC) ;

pReport->CurrentItem.pLine = pLine ;
pReport->CurrentItemType = REPORT_TYPE_LINE ;

if (!bDelayAddAction)
{
if (PlayingBackLog ())
{
PlaybackReport (hWndReport) ;
}
else if (pReport->iStatus == iPMStatusClosed)
{
SetReportTimer (pReport) ;
}

WindowInvalidate (hWnd) ;
}
} // else

return (TRUE) ;
} // ReportInsertLine


BOOL ExportComputerName (HANDLE hFile, PSYSTEMGROUP pSystemGroup)
{
int StringLen ;
BOOL bWriteSuccess = TRUE ;

CHAR TempBuff [LongTextLen * 2] ;

TCHAR UnicodeBuff [LongTextLen] ;

// export computer name
strcpy (TempBuff, LineEndStr) ;
strcat (TempBuff, LineEndStr) ;
StringLen = strlen (TempBuff) ;
TSPRINTF (UnicodeBuff, szSystemFormat, pSystemGroup->lpszSystemName) ;
ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
strcat (TempBuff, LineEndStr) ;

if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
{
bWriteSuccess = FALSE ;
}

return (bWriteSuccess) ;
} // ExportComputerName

#define WRITE_FILE_TIME 2
BOOL ExportObjectName (HANDLE hFile, POBJECTGROUP pObjectGroup, int *pColNum)
{
int StringLen ;
BOOL bNeedToExport ;
BOOL bWriteSuccess = TRUE ;
PCOLUMNGROUP pColumnGroup ;
int ParentNum, InstanceNum ;
int TimeToWrite ;

CHAR TempBuff [512 * 2] ;

TCHAR UnicodeBuff [512] ;

ParentNum = InstanceNum = 0 ;

if (pColNum)
{
*pColNum = 0 ;
}

// export object name
strcpy (TempBuff, LineEndStr) ;
StringLen = strlen (TempBuff) ;
TSPRINTF (UnicodeBuff, szObjectFormat, pObjectGroup->lpszObjectName) ;
ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
strcat (TempBuff, LineEndStr) ;

if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
{
goto Exit0 ;
}


TimeToWrite = 0 ;

// export column group
if (pObjectGroup->pColumnGroupFirst)
{
strcpy (TempBuff, pDelimiter) ;
strcat (TempBuff, pDelimiter) ;
StringLen = strlen (TempBuff) ;

bNeedToExport = FALSE ;

// export Parent Names
for (pColumnGroup = pObjectGroup->pColumnGroupFirst ;
pColumnGroup ;
pColumnGroup = pColumnGroup->pColumnGroupNext)
{ // for

if (pColumnGroup->lpszParentName)
{
ParentNum++ ;
bNeedToExport = TRUE ;
ConvertUnicodeStr (&TempBuff[StringLen],
pColumnGroup->lpszParentName) ;
StringLen = strlen (TempBuff) ;
}

strcat (&TempBuff[StringLen], pDelimiter) ;
StringLen = strlen (TempBuff) ;

// check if we need to export this line before it is filled up
TimeToWrite++ ;
if (TimeToWrite > WRITE_FILE_TIME)
{
if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
{
goto Exit0 ;
}
TimeToWrite = 0 ;
StringLen = 0 ;
TempBuff[0] = TEXT('\0') ;
}
}

// write the line delimiter
strcpy (&TempBuff[StringLen], LineEndStr) ;
if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
{
goto Exit0 ;
}

if (!bNeedToExport)
{
ParentNum = 0 ;
}


// setup to export Instances
strcpy (TempBuff, pDelimiter) ;
strcat (TempBuff, pDelimiter) ;
StringLen = strlen (TempBuff) ;
bNeedToExport = FALSE ;
TimeToWrite = 0 ;

// export Instance Names
for (pColumnGroup = pObjectGroup->pColumnGroupFirst ;
pColumnGroup ;
pColumnGroup = pColumnGroup->pColumnGroupNext)
{ // for

if (pColumnGroup->lpszInstanceName)
{
InstanceNum++ ;
bNeedToExport = TRUE ;
ConvertUnicodeStr (&TempBuff[StringLen],
pColumnGroup->lpszInstanceName) ;
StringLen = strlen (TempBuff) ;
}

strcat (&TempBuff[StringLen], pDelimiter) ;
StringLen = strlen (TempBuff) ;

// check if we need to export this line before it is filled up
TimeToWrite++ ;
if (TimeToWrite > WRITE_FILE_TIME)
{
if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
{
goto Exit0 ;
}
TimeToWrite = 0 ;
StringLen = 0 ;
TempBuff[0] = TEXT('\0') ;
}
}

// write the line delimiter
strcpy (&TempBuff[StringLen], LineEndStr) ;
if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
{
goto Exit0 ;
}

if (!bNeedToExport)
{
InstanceNum = 0 ;
}
}

if (pColNum)
{
*pColNum = max (ParentNum, InstanceNum) ;
}

return (TRUE) ;

Exit0:
return (FALSE) ;

} // ExportObjectName

BOOL ExportLineName (HANDLE hFile, PLINE pLine, int *pExportCounterName)
{
FLOAT eValue ;
int StringLen ;
BOOL bWriteSuccess = TRUE ;

CHAR TempBuff [LongTextLen * 2] ;

TCHAR UnicodeBuff [LongTextLen] ;


strcpy (TempBuff, pDelimiter) ;

if (*pExportCounterName)
{
StringLen = strlen (TempBuff) ;
ConvertUnicodeStr (&TempBuff[StringLen], pLine->lnCounterName) ;
strcat (TempBuff, pDelimiter) ;
*pExportCounterName = FALSE ;
}
StringLen = strlen (TempBuff) ;

if (pLine->bFirstTime == 0)
{
eValue = CounterEntry (pLine) ;

if (pLine->lnCounterType == PERF_COUNTER_RAWCOUNT_HEX ||
pLine->lnCounterType == PERF_COUNTER_LARGE_RAWCOUNT_HEX)
{
DWORD LowValue ;
DWORD HighValue ;

LowValue = (DWORD) (pLine->lnaCounterValue[0]) ;
HighValue = (DWORD) (pLine->lnaCounterValue[0] >> 32);

if (pLine->lnCounterType == PERF_COUNTER_RAWCOUNT_HEX ||
HighValue == 0)
{
TSPRINTF (UnicodeBuff,
szHexFormat,
LowValue) ;
}
else
{
TSPRINTF (UnicodeBuff,
szLargeHexFormat,
HighValue,
LowValue) ;
}
}
else
{
TSPRINTF (UnicodeBuff,
(eValue > eStatusLargeValueMax) ?
szLargeValueFormat : szValueFormat,
eValue) ;
ConvertDecimalPoint (UnicodeBuff) ;
}
ConvertUnicodeStr (&TempBuff[StringLen], UnicodeBuff) ;
}
else
{
// export "----" for unstable values
strcat (&TempBuff[StringLen], "----");
}

// write the line value
if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
{
goto Exit0 ;
}

return (TRUE) ;


Exit0:
return (FALSE) ;
} // ExportLineName


// This routine is need to insert the line values into its
// column location. It is needed because not all the instances (columns)
// are available for the same line.
void SaveColumnLineData (PLINE pLine, LPSTR pColumnLineData)
{
FLOAT eValue ;
LPSTR pColumnLine ;

CHAR TempBuff [LongTextLen * 2] ;

TCHAR UnicodeBuff [LongTextLen] ;

if (!pColumnLineData || pLine->iReportColumn < 0)
{
return ;
}

// find the offset into the pColumnLineData buffer for current line
pColumnLine = pColumnLineData + pLine->iReportColumn * ShortTextLen ;

if (pLine->bFirstTime == 0)
{

eValue = CounterEntry (pLine) ;


if (pLine->lnCounterType == PERF_COUNTER_RAWCOUNT_HEX ||
pLine->lnCounterType == PERF_COUNTER_LARGE_RAWCOUNT_HEX)
{
DWORD LowValue ;
DWORD HighValue ;

LowValue = (DWORD) (pLine->lnaCounterValue[0]) ;
HighValue = (DWORD) (pLine->lnaCounterValue[0] >> 32);

if (pLine->lnCounterType == PERF_COUNTER_RAWCOUNT_HEX ||
HighValue == 0)
{
TSPRINTF (UnicodeBuff,
szHexFormat,
LowValue) ;
}
else
{
TSPRINTF (UnicodeBuff,
szLargeHexFormat,
HighValue,
LowValue) ;
}
}
else
{
TSPRINTF (UnicodeBuff,
(eValue > eStatusLargeValueMax) ?
szLargeValueFormat : szValueFormat,
eValue) ;
ConvertDecimalPoint (UnicodeBuff) ;
}
ConvertUnicodeStr (TempBuff, UnicodeBuff) ;
strncpy (pColumnLine, TempBuff, ShortTextLen) ;
*(pColumnLine + ShortTextLen - 1) = '\0' ;
}
else
{
// export "----" for unstable values
strcpy (pColumnLine, "----");
}
} // SaveColumnLineData

BOOL ExportColumnLineData (HANDLE hFile,
int ColumnTotal,
PCOUNTERGROUP pCounterGroup,
LPSTR pColumnLineData)
{
int iIndex ;
int StringLen ;
CHAR TempBuff [LongTextLen] ;
LPSTR pCurrentLineData ;

// export the counter name
strcpy (TempBuff, pDelimiter) ;
StringLen = strlen (TempBuff) ;
ConvertUnicodeStr (&TempBuff[StringLen], pCounterGroup->pLineFirst->lnCounterName) ;
strcat (TempBuff, pDelimiter) ;
if (!FileWrite (hFile, TempBuff, strlen(TempBuff)))
{
goto Exit0 ;
}

// go thru each column and export the line value if it has been stored
for (iIndex = 0, pCurrentLineData = pColumnLineData ;
iIndex < ColumnTotal ;
iIndex++, pCurrentLineData += ShortTextLen )
{
if (*pCurrentLineData != 0)
{
// data available for this column
if (!FileWrite (hFile, pCurrentLineData, strlen(pCurrentLineData)))
{
goto Exit0 ;
}
}

if (!FileWrite (hFile, pDelimiter, strlen(pDelimiter)))
{
goto Exit0 ;
}
}

if (!FileWrite (hFile, LineEndStr, strlen(LineEndStr)))
{
goto Exit0 ;
}

return (TRUE) ;


Exit0:
return (FALSE) ;

} // ExportColumnLineData

void ExportReport (void)
{
HANDLE hFile = 0 ;
PREPORT pReport ;
PSYSTEMGROUP pSystemGroup ;
POBJECTGROUP pObjectGroup ;
PCOUNTERGROUP pCounterGroup ;
PLINE pLine ;
BOOL bExportComputer ;
BOOL bExportObject ;
BOOL bExportCounterName ;
int ColumnTotal = 0 ;
LPSTR pColumnLineData = NULL ;
LPTSTR pFileName = NULL ;
INT ErrCode = 0 ;

if (!(pReport = ReportData (hWndReport)))
{
return ;
}

// see if there is anything to export..
if (!(pReport->pSystemGroupFirst))
{
return ;
}

SetHourglassCursor() ;

if (ErrCode = ExportFileOpen (hWndReport, &hFile,
pReport->iIntervalMSecs, &pFileName))
{
goto Exit0 ;
}

if (!pFileName)
{
// the case when user cancel
goto Exit0 ;
}

// export each system group

for (pSystemGroup = pReport->pSystemGroupFirst ;
pSystemGroup ;
pSystemGroup = pSystemGroup->pSystemGroupNext)
{ // for System...

bExportComputer = TRUE ;

for (pObjectGroup = pSystemGroup->pObjectGroupFirst ;

pObjectGroup ; 
pObjectGroup = pObjectGroup->pObjectGroupNext)
{ // for Object...

bExportObject = TRUE ;

for (pCounterGroup = pObjectGroup->pCounterGroupFirst ;
pCounterGroup ;
pCounterGroup = pCounterGroup->pCounterGroupNext)
{ // for Counter...

bExportCounterName = TRUE ;

// Column data buffer has been allocated for this object type,
// zero out the buffer and prepare for next round.

if (pColumnLineData)
{
memset (pColumnLineData, 0, ColumnTotal * ShortTextLen) ;
}

for (pLine = pCounterGroup->pLineFirst ;
pLine ;
pLine = pLine->pLineCounterNext)
{ // for Line...

if (bExportComputer)
{
// only need to do this for the first object
bExportComputer = FALSE ;
if (!ExportComputerName (hFile, pSystemGroup))
{
ErrCode = ERR_EXPORT_FILE ;
goto Exit0 ;
}
}

if (bExportObject)
{
// only need to do this for the first counter group
bExportObject = FALSE ;
if (!ExportObjectName (hFile, pObjectGroup, &ColumnTotal))
{
ErrCode = ERR_EXPORT_FILE ;
goto Exit0 ;
}

if (ColumnTotal > 1)
{
// special case to setup a column array and export
// the line values later
pColumnLineData = MemoryAllocate (ColumnTotal * ShortTextLen) ;
if (!pColumnLineData)
{
ErrCode = ERR_EXPORT_FILE ;
goto Exit0 ;
}
}
}

if (ColumnTotal > 1)
{
// save the line value into its column & export later
SaveColumnLineData (pLine, pColumnLineData) ;
}
else
{
// simple case, export the line now
if (!ExportLineName (hFile, pLine, &bExportCounterName))
{
ErrCode = ERR_EXPORT_FILE ;
goto Exit0 ;
}
}
} // for Line...

if (!bExportCounterName)
{
// export the line end
if (!FileWrite (hFile, LineEndStr, strlen(LineEndStr)))
{
ErrCode = ERR_EXPORT_FILE ;
goto Exit0 ;
}
}

if (pColumnLineData)
{
// now, do the actual export
if (!ExportColumnLineData (hFile,
ColumnTotal,
pCounterGroup,
pColumnLineData))
{
ErrCode = ERR_EXPORT_FILE ;
goto Exit0 ;
}
}
} // for Counter...

// done with the object, done with the buffer
if (pColumnLineData)
{
MemoryFree (pColumnLineData) ;
ColumnTotal = 0 ;
pColumnLineData = NULL ;
}
} // for Object


} // for System...

Exit0:

SetArrowCursor() ;

if (pColumnLineData)
{
MemoryFree (pColumnLineData) ;
}

if (hFile)
{
CloseHandle (hFile) ;
}

if (pFileName)
{
if (ErrCode)
{
DlgErrorBox (hWndGraph, ErrCode, pFileName) ;
}

MemoryFree (pFileName) ;
}

} // ExportReport