Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6993 lines
230 KiB

/*++
Copyright (C) 1996-1999 Microsoft Corporation
Module Name:
smonctrl.cpp
Abstract:
This module handles the graphing window.
--*/
#pragma warning ( disable : 4127 )
#ifndef _LOG_INCLUDE_DATA
#define _LOG_INCLUDE_DATA 0
#endif
//==========================================================================//
// Includes //
//==========================================================================//
#include "polyline.h"
#include <limits.h> // for INT_MAX
#include <strsafe.h>
#include <cderr.h>
#ifdef _WIN32_IE
#if _WIN32_IE < 0x0400
#undef _WIN32_IE
#define _WIN32_IE 0x0400 // for NMTBCUSTOMDRAW
#endif // < 0x0400
#endif // defined
#include <commctrl.h>
#include <htmlhelp.h>
#include <shellapi.h>
#include <pdhp.h>
#include "cntrtree.h"
#include "commdlg.h"
#include "unihelpr.h"
#include "winperf.h"
#include "pdhmsg.h"
#include "smonmsg.h"
#include "visuals.h"
#include "statbar.h"
#include "snapbar.h"
#include "legend.h"
#include "toolbar.h"
#include "grphdsp.h"
#include "report.h"
#include "browser.h"
#include "appmema.h"
#include "ipropbag.h"
#include "logsrc.h"
#include "smonmsg.h"
#include "smonid.h"
#include "smonctrl.h"
#include "strnoloc.h"
#include "grphitem.h"
#include "winhelpr.h"
//==========================================================================//
// Constants //
//==========================================================================//
extern CCounterTree g_tree;
extern DWORD g_dwScriptPolicy;
#define DBG_SHOW_STATUS_PRINTS 1
//=============================//
// Graph Class //
//=============================//
static DWORD dwDbgPrintLevel = 0;
static WCHAR szSysmonCtrlWndClass[] = L"SysmonCtrl";
static WCHAR LineEndStr[] = TEXT("\n") ;
static WCHAR SpaceStr[] = TEXT(" ");
typedef struct {
CSysmonControl *pCtrl;
PCGraphItem pFirstItem;
} ENUM_ADD_COUNTER_CALLBACK_INFO;
BOOL
APIENTRY
SaveDataDlgHookProc (
HWND hDlg,
UINT iMessage,
WPARAM wParam,
LPARAM lParam
)
{
BOOL bHandled;
CSysmonControl *pCtrl;
LONG lFilterValue;
BOOL bGoodNumber = FALSE;
UNREFERENCED_PARAMETER (wParam);
// lparam = CSysmonControl class pointer
bHandled = FALSE ;
switch (iMessage) {
case WM_INITDIALOG:
// initialize the filter edit control with the current value
OPENFILENAME *pOfn;
pOfn= (OPENFILENAME *)lParam;
if ( NULL != pOfn ) {
// get the control class pointer from the OPENFILENAME struct
pCtrl = (CSysmonControl *)pOfn->lCustData;
// save the pointer to the control class as a DLG data word
SetWindowLongPtr (hDlg, DWLP_USER, (LONG_PTR)pCtrl);
lFilterValue = pCtrl->GetSaveDataFilter();
SetDlgItemInt (hDlg, IDC_SAVEDATA_EDIT, (UINT)lFilterValue, FALSE);
// limit reduction to 1/9999 records
SendDlgItemMessage (hDlg, IDC_SAVEDATA_EDIT, EM_LIMITTEXT, (WPARAM)4, (LPARAM)0);
bHandled = TRUE ;
}
break ;
case WM_DESTROY:
// the user has closed the dialog box so get the relog filter value
// (note: this should be ignored if the user cancels the dialog)
pCtrl = (CSysmonControl *)GetWindowLongPtr (hDlg, DWLP_USER);
lFilterValue = GetDlgItemInt (hDlg, IDC_SAVEDATA_EDIT, &bGoodNumber, FALSE);
if (bGoodNumber) {
pCtrl->SetSaveDataFilter( lFilterValue );
}
bHandled = TRUE ;
break ;
case WM_NOTIFY:
{
LPOFNOTIFY pOFNotify;
pOFNotify = (LPOFNOTIFY) lParam;
if (pOFNotify) {
if (pOFNotify->hdr.code == CDN_FILEOK) {
lFilterValue = GetDlgItemInt (hDlg, IDC_SAVEDATA_EDIT, &bGoodNumber, FALSE);
if (!bGoodNumber || lFilterValue == 0) {
MessageBox(hDlg,
ResourceString(IDS_FILTER_VALUE_ERR),
ResourceString(IDS_APP_NAME),
MB_OK | MB_ICONSTOP);
::SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
bHandled = TRUE;
}
}
}
break;
}
default:
break;
}
return bHandled;
}
HRESULT
AddCounterCallback (
LPWSTR pszPathName,
DWORD_PTR lpUserData,
DWORD dwFlags
)
{
ENUM_ADD_COUNTER_CALLBACK_INFO *pInfo = (ENUM_ADD_COUNTER_CALLBACK_INFO*)lpUserData;
CSysmonControl *pCtrl = pInfo->pCtrl;
PCGraphItem pGraphItem = NULL;
HRESULT hr;
hr = pCtrl->AddSingleCounter(pszPathName, &pGraphItem);
if (SUCCEEDED(hr)) {
if (dwFlags & BROWSE_WILDCARD)
pGraphItem->m_fGenerated = TRUE;
if ( NULL == pInfo->pFirstItem ) {
// Keep the reference count if returning the pointer.
pInfo->pFirstItem = pGraphItem;
} else {
pGraphItem->Release();
}
}
return hr;
}
#pragma warning( disable : 4355 ) // "this" use in initializer list
CSysmonControl::CSysmonControl(
PCPolyline pObj )
: m_OleFont(this),
m_pObj(pObj), // Pointer back to owner.
m_fInitialized(FALSE),
m_fViewInitialized(FALSE),
m_hWnd(NULL),
m_pLegend(NULL),
m_pGraphDisp(NULL),
m_pStatsBar(NULL),
m_pSnapBar(NULL),
m_pReport(NULL),
m_pToolbar(NULL),
m_hQuery(NULL),
m_TimerID(0),
m_fPendingUpdate(FALSE),
m_fPendingSizeChg(FALSE),
m_fPendingFontChg(FALSE),
m_fPendingLogViewChg(FALSE),
m_fPendingLogCntrChg(FALSE),
m_pSelectedItem(NULL),
m_fUIDead(FALSE),
m_fRTL(FALSE),
m_fUserMode(FALSE),
m_hAccel(NULL),
m_bLogFileSource(FALSE),
m_bSampleDataLoaded(FALSE),
m_bLoadingCounters(FALSE),
m_bSettingsLoaded(FALSE),
m_szErrorPathList ( NULL ),
m_dwErrorPathListLen ( 0 ),
m_dwErrorPathBufLen ( 0 ),
// Default attributes
m_iColorIndex(0),
m_iWidthIndex(0),
m_iStyleIndex(0),
m_iScaleFactor(INT_MAX),
m_iAppearance(eAppear3D),
m_iBorderStyle(eBorderNone),
m_dZoomFactor(1.0),
m_lcidCurrent ( LOCALE_USER_DEFAULT )
{
PGRAPH_OPTIONS pOptions;
m_LoadedVersion.iMajor = SMONCTRL_MAJ_VERSION;
m_LoadedVersion.iMinor = SMONCTRL_MIN_VERSION;
m_clrBackCtl = GetSysColor(COLOR_BTNFACE);
m_clrFgnd = GetSysColor(COLOR_BTNTEXT);
m_clrBackPlot = GetSysColor(COLOR_WINDOW);
m_clrGrid = RGB(128,128,128); // Medium gray
m_clrTimeBar = RGB(255,0,0); // Red
m_lSaveDataToLogFilterValue = 1; // default save data to log filter is 1
// Init graph parameters
pOptions = &pObj->m_Graph.Options;
pOptions->bLegendChecked = TRUE;
pOptions->bToolbarChecked = TRUE;
pOptions->bLabelsChecked = TRUE;
pOptions->bVertGridChecked = FALSE;
pOptions->bHorzGridChecked = FALSE;
pOptions->bValueBarChecked = TRUE;
pOptions->bManualUpdate = FALSE;
pOptions->bHighlight = FALSE;
pOptions->bReadOnly = FALSE;
pOptions->bMonitorDuplicateInstances = TRUE;
pOptions->bAmbientFont = TRUE;
pOptions->iVertMax = 100;
pOptions->iVertMin = 0;
pOptions->fUpdateInterval = (float)1.0;
pOptions->iDisplayFilter = 1;
pOptions->iDisplayType = sysmonLineGraph;
pOptions->iReportValueType = sysmonDefaultValue;
pOptions->pszGraphTitle = NULL;
pOptions->pszYaxisTitle = NULL;
pOptions->clrBackCtl = ( 0x80000000 | COLOR_BTNFACE );
pOptions->clrGrid = m_clrGrid;
pOptions->clrTimeBar = m_clrTimeBar;
pOptions->clrFore = NULL_COLOR;
pOptions->clrBackPlot = NULL_COLOR;
pOptions->iAppearance = NULL_APPEARANCE;
pOptions->iBorderStyle = eBorderNone;
pOptions->iDataSourceType = sysmonCurrentActivity;
// Init data source info
memset ( &m_DataSourceInfo, 0, sizeof ( m_DataSourceInfo ) );
m_DataSourceInfo.llStartDisp = MIN_TIME_VALUE;
m_DataSourceInfo.llStopDisp = MAX_TIME_VALUE;
// Init collection thread info
m_CollectInfo.hThread = NULL;
m_CollectInfo.hEvent = NULL;
m_CollectInfo.iMode = COLLECT_SUSPEND;
// Cache pointer to object's history control
m_pHistCtrl = &pObj->m_Graph.History;
assert ( NULL != pObj );
pObj->m_Graph.LogViewTempStart = MIN_TIME_VALUE;
pObj->m_Graph.LogViewTempStop = MAX_TIME_VALUE;
// Init the log view and time steppers. They might be used before
// SizeComponents is called, for example when a property bag is loaded.
// The width has not been calculated yet, is initialized here
// to an arbitrary number.
pObj->m_Graph.TimeStepper.Init( MAX_GRAPH_SAMPLES, MAX_GRAPH_SAMPLES - 2 );
pObj->m_Graph.LogViewStartStepper.Init( MAX_GRAPH_SAMPLES, MAX_GRAPH_SAMPLES - 2 );
pObj->m_Graph.LogViewStopStepper.Init( MAX_GRAPH_SAMPLES, MAX_GRAPH_SAMPLES - 2 );
m_pHistCtrl->bLogSource = FALSE;
m_pHistCtrl->nMaxSamples = MAX_GRAPH_SAMPLES;
m_pHistCtrl->iCurrent = 0;
m_pHistCtrl->nSamples = 0;
m_pHistCtrl->nBacklog = 0;
// Keep record of current size to avoide unnecessary calls to SizeComponents
SetRect ( &m_rectCurrentClient,0,0,0,0 );
}
BOOL
CSysmonControl::AllocateSubcomponents( void )
{
BOOL bResult = TRUE;
//
// Initialize the critical section here rather than in
// the constructor because it can throw an exception.
//
try {
InitializeCriticalSection(&m_CounterDataLock);
} catch (...) {
bResult = FALSE;
}
if ( bResult ) {
m_pLegend = new CLegend;
m_pGraphDisp = new CGraphDisp;
m_pStatsBar = new CStatsBar;
m_pSnapBar = new CSnapBar;
m_pReport = new CReport;
m_pToolbar = new CSysmonToolbar;
}
if (m_pLegend == NULL ||
m_pGraphDisp == NULL ||
m_pStatsBar == NULL ||
m_pSnapBar == NULL ||
m_pReport == NULL ||
m_pToolbar == NULL) {
bResult = FALSE;
}
if (!bResult) {
DeInit();
return bResult;
}
if ( FAILED(m_OleFont.Init()) )
bResult = FALSE;
return bResult;
}
CSysmonControl::~CSysmonControl( void )
{
PCGraphItem pItem;
PCGraphItem pNext;
PCLogFileItem pLogFile;
PCLogFileItem pNextLogFile;
CloseQuery();
DeInit();
DeleteCriticalSection(&m_CounterDataLock);
// Release all graph items
pItem = FirstCounter();
while ( NULL != pItem ) {
pNext = pItem->Next();
pItem->Release();
pItem = pNext;
}
// Release all log file items
pLogFile = FirstLogFile();
while ( NULL != pLogFile ) {
pNextLogFile = pLogFile->Next();
pLogFile->Release();
pLogFile = pNextLogFile;
}
if (m_DataSourceInfo.szSqlDsnName != NULL) {
delete [] m_DataSourceInfo.szSqlDsnName;
m_DataSourceInfo.szSqlDsnName = NULL;
}
if (m_DataSourceInfo.szSqlLogSetName != NULL) {
delete [] m_DataSourceInfo.szSqlLogSetName;
m_DataSourceInfo.szSqlLogSetName = NULL;
}
if (m_hWnd != NULL)
DestroyWindow(m_hWnd);
if (m_pObj->m_Graph.Options.pszGraphTitle != NULL)
delete [] m_pObj->m_Graph.Options.pszGraphTitle;
if (m_pObj->m_Graph.Options.pszYaxisTitle != NULL)
delete [] m_pObj->m_Graph.Options.pszYaxisTitle;
ClearErrorPathList();
}
void CSysmonControl::DeInit( void )
{
if (m_pLegend) {
delete m_pLegend;
m_pLegend = NULL;
}
if (m_pGraphDisp) {
delete m_pGraphDisp;
m_pGraphDisp = NULL;
}
if (m_pStatsBar) {
delete m_pStatsBar;
m_pStatsBar = NULL;
}
if (m_pSnapBar) {
delete m_pSnapBar;
m_pSnapBar = NULL;
}
if (m_pReport) {
delete m_pReport;
m_pReport = NULL;
}
if (m_pToolbar) {
delete m_pToolbar;
m_pToolbar = NULL;
}
ClearErrorPathList();
}
void CSysmonControl::ApplyChanges( HDC hAttribDC )
{
if ( m_fPendingUpdate ) {
// Clear the master update flag
m_fPendingUpdate = FALSE;
// set the toolbar state
m_pToolbar->ShowToolbar(m_pObj->m_Graph.Options.bToolbarChecked);
// If log view changed or counters added
// we need to resample the log file
if (m_fPendingLogViewChg || m_fPendingLogCntrChg) {
SampleLogFile(m_fPendingLogViewChg);
// Must init time steppers before calling ResetLogViewTempTimeRange
ResetLogViewTempTimeRange ( );
m_fPendingLogViewChg = FALSE;
m_fPendingLogCntrChg = FALSE;
}
if (m_fPendingFontChg || m_fPendingSizeChg) {
if (NULL != hAttribDC ) {
if (m_fPendingFontChg) {
m_pLegend->ChangeFont(hAttribDC);
m_pStatsBar->ChangeFont(hAttribDC);
m_pGraphDisp->ChangeFont(hAttribDC);
m_fPendingFontChg = FALSE;
}
SizeComponents( hAttribDC );
m_fPendingSizeChg = FALSE;
}
}
m_pToolbar->SyncToolbar();
}
}
void
CSysmonControl::DrawBorder ( HDC hDC )
{
if ( eBorderSingle == m_iBorderStyle ) {
RECT rectClient;
//
// Get dimensions of window
//
GetClientRect (m_hWnd, &rectClient) ;
if ( eAppear3D == m_iAppearance ) {
DrawEdge(hDC, &rectClient, EDGE_RAISED, BF_RECT);
} else {
SelectBrush (hDC, GetStockObject (HOLLOW_BRUSH)) ;
SelectPen (hDC, GetStockObject (BLACK_PEN)) ;
Rectangle (hDC, rectClient.left, rectClient.top, rectClient.right, rectClient.bottom );
}
}
}
void CSysmonControl::Paint ( void )
{
HDC hDC ;
PAINTSTRUCT ps ;
hDC = BeginPaint (m_hWnd, &ps) ;
//
// ApplyChanges does some work even if hDC is NULL.
//
ApplyChanges( hDC ) ;
if ( m_fViewInitialized && NULL != hDC ) {
m_pStatsBar->Draw(hDC, hDC, &ps.rcPaint);
m_pGraphDisp->Draw(hDC, hDC, FALSE, FALSE, &ps.rcPaint);
DrawBorder( hDC );
}
EndPaint (m_hWnd, &ps) ;
}
void
CSysmonControl::OnDblClick(INT x, INT y)
{
if ( REPORT_GRAPH != m_pObj->m_Graph.Options.iDisplayType ) {
PCGraphItem pItem = m_pGraphDisp->GetItem ( x,y );
if ( NULL != pItem ) {
SelectCounter( pItem );
DblClickCounter ( pItem );
}
} else {
assert ( FALSE );
}
}
DWORD
CSysmonControl::ProcessCommandLine ( )
{
DWORD dwStatus = ERROR_SUCCESS;
HRESULT hr = S_OK;
LPCWSTR pszNext;
LPWSTR pszWmi = NULL;
LPWSTR pszSettings = NULL;
LPWSTR* pszArgList = NULL;
INT iNumArgs;
INT iArgIndex;
LPWSTR pszNextArg = NULL;
LPWSTR pszThisArg = NULL;
LPWSTR szFileName = NULL;
LPWSTR szTemp = NULL;
LPWSTR pszToken = NULL;
size_t sizeArgLen = 0;
BOOL bDisplayMessage = FALSE;
LPWSTR szSystemMessage = NULL;
static const size_t ciArgMaxLen = MAX_PATH + 1;
//
// Maximum argument length is for file path, which is restricted to MAX_PATH.
//
pszWmi = ResourceString ( IDS_CMDARG_WMI );
pszSettings = ResourceString ( IDS_CMDARG_SETTINGS );
pszNext = GetCommandLineW();
pszArgList = CommandLineToArgvW ( pszNext, &iNumArgs );
if ( NULL != pszArgList ) {
for ( iArgIndex = 0; SUCCEEDED(hr) && (iArgIndex < iNumArgs); iArgIndex++ ) {
pszNextArg = (LPWSTR)pszArgList[iArgIndex];
pszThisArg = pszNextArg;
while ( 0 != *pszThisArg ) {
if ( *pszThisArg++ == L'/' ) { // argument found
hr = StringCchLength ( pszThisArg, ciArgMaxLen, &sizeArgLen );
if ( SUCCEEDED(hr) ) {
szTemp = new WCHAR [sizeArgLen + 1];
if ( NULL != szTemp ) {
// No StringCchCopy failure because StringCchLen calculated above.
StringCchCopy (
szTemp,
(sizeArgLen + 1),
pszThisArg );
pszToken = wcstok ( szTemp, L"/ =\"" );
if ( 0 == lstrcmpiW ( pszToken, pszWmi ) ) {
//
// Ignore PDH errors. The only possible error is that the default data source has
// already been set for this process.
//
PdhSetDefaultRealTimeDataSource ( DATA_SOURCE_WBEM );
pszThisArg += sizeArgLen;
} else if ( 0 == lstrcmpiW ( pszToken, pszSettings ) ) {
//
// Strip the initial non-token characters for string comparison.
//
pszThisArg = _wcsspnp ( pszNextArg, L"/ =\"" );
if ( 0 == lstrcmpiW ( pszThisArg, pszSettings ) ) {
//
// Get the next argument (the file name)
//
iArgIndex++;
pszNextArg = (LPWSTR)pszArgList[iArgIndex];
pszThisArg = pszNextArg;
} else {
//
// File was created by Windows 2000 perfmon5.exe,
// so file name is part of the arg.
//
pszThisArg += lstrlen ( pszSettings );
hr = StringCchLength ( pszThisArg, ciArgMaxLen, &sizeArgLen );
if ( SUCCEEDED ( hr ) ) {
szFileName = new WCHAR[sizeArgLen + 1];
if ( NULL != szFileName ) {
//
// No StringCchCopy failure because StringCchLen calculated above.
//
StringCchCopy (
szFileName,
(sizeArgLen + 1),
pszThisArg );
pszThisArg = wcstok ( szFileName, L"=\"" );
} else {
hr = E_OUTOFMEMORY;
bDisplayMessage = TRUE;
}
} else {
bDisplayMessage = TRUE;
}
}
if ( SUCCEEDED (hr) ) {
hr = LoadFromFile( pszThisArg, TRUE );
if ( SMON_STATUS_NO_SYSMON_OBJECT != (DWORD)hr ) {
if ( SUCCEEDED ( hr ) ) {
m_bSettingsLoaded = TRUE;
} // else LoadFromFile displays messages for other errors
} else {
// SMON_STATUS_NO_SYSMON_OBJECT == hr
MessageBox(
m_hWnd,
ResourceString(IDS_NOSYSMONOBJECT_ERR ),
ResourceString(IDS_APP_NAME),
MB_OK | MB_ICONERROR);
}
pszThisArg += lstrlen ( pszThisArg );
}
}
}
if ( NULL != szTemp ) {
delete [] szTemp;
szTemp = NULL;
}
if ( NULL != szFileName ) {
delete [] szFileName;
szFileName = NULL;
}
} else {
bDisplayMessage = TRUE;
}
}
}
}
}
if ( FAILED(hr) && bDisplayMessage ) {
if ( STRSAFE_E_INVALID_PARAMETER == hr ) {
dwStatus = ERROR_INVALID_PARAMETER;
} else if ( E_OUTOFMEMORY == hr ) {
dwStatus = ERROR_OUTOFMEMORY;
} else {
dwStatus = HRESULT_CODE (hr);
}
szSystemMessage = new WCHAR[MAX_MESSAGE_LEN];
if ( NULL != szSystemMessage ) {
if ( FormatSystemMessage (
dwStatus,
szSystemMessage,
MAX_MESSAGE_LEN ) )
{
MessageBox(
m_hWnd,
szSystemMessage,
ResourceString(IDS_APP_NAME),
MB_OK | MB_ICONERROR);
}
delete [] szSystemMessage;
}
}
if ( NULL != pszArgList ) {
GlobalFree ( pszArgList );
}
return dwStatus;
}
HRESULT
CSysmonControl::LoadFromFile ( LPWSTR szFileName, BOOL bAllData )
{
HRESULT hr = E_OUTOFMEMORY;
LPWSTR szLocalName = NULL;
LPWSTR pFileNameStart;
HANDLE hFindFile = NULL;
WIN32_FIND_DATA FindFileInfo;
INT iNameOffset;
DWORD dwMsgStatus = ERROR_SUCCESS;
HANDLE hOpenFile = NULL;
size_t sizeCharCount;
szLocalName = new WCHAR [MAX_PATH + 1];
if ( NULL != szLocalName ) {
hr = StringCchCopy ( szLocalName, MAX_PATH, szFileName );
if ( SUCCEEDED ( hr ) ) {
//
// Find the filename offset within the path buffer.
//
pFileNameStart = ExtractFileName (szLocalName) ;
iNameOffset = (INT)(pFileNameStart - szLocalName);
//
// Convert short filename to long NTFS filename if necessary.
//
hFindFile = FindFirstFile ( szLocalName, &FindFileInfo) ;
if (hFindFile && hFindFile != INVALID_HANDLE_VALUE) {
if ( ConfirmSampleDataOverwrite ( ) ) {
//
// Append the NTFS file name back to the path name, if different.
//
if ( 0 != lstrcmpiW ( FindFileInfo.cFileName, pFileNameStart ) ) {
hr = StringCchLength ( FindFileInfo.cFileName, MAX_PATH, &sizeCharCount );
if ( SUCCEEDED ( hr ) ) {
//
// No StringCchCopy failure, because truncation found by StringCchLength
//
StringCchCopy (
&szLocalName[iNameOffset],
(MAX_PATH+1) - iNameOffset,
FindFileInfo.cFileName );
} else {
//
// STRSAFE_E_INSUFFICIENT_BUFFER indicates filename truncation.
//
dwMsgStatus = ERROR_BUFFER_OVERFLOW;
hr = HRESULT_FROM_WIN32(dwMsgStatus);
}
}
if ( SUCCEEDED( hr ) ) {
//
// Open the file
//
hOpenFile = CreateFile (
szLocalName,
GENERIC_READ,
0, // Not shared
NULL, // Security attributes
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if ( hOpenFile && hOpenFile != INVALID_HANDLE_VALUE ) {
DWORD dwFileSize;
DWORD dwFileSizeHigh;
DWORD dwFileSizeRead;
LPWSTR pszData = NULL;
//
// Read the file contents into a memory buffer.
//
dwFileSize = GetFileSize ( hOpenFile, &dwFileSizeHigh );
assert ( 0 == dwFileSizeHigh );
if ( 0 == dwFileSizeHigh ) {
//
// Restrict file size to DWORD length.
//
pszData = new WCHAR[(dwFileSize + sizeof(WCHAR))/sizeof(WCHAR)];
if ( NULL != pszData ) {
if ( ReadFile ( hOpenFile, pszData, dwFileSize, &dwFileSizeRead, NULL ) ) {
// Paste all settings from the memory buffer.
hr = PasteFromBuffer ( pszData, bAllData );
if ( E_OUTOFMEMORY == hr ) {
dwMsgStatus = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
dwMsgStatus = GetLastError();
hr = HRESULT_FROM_WIN32(dwMsgStatus);
}
delete [] pszData;
} else {
dwMsgStatus = ERROR_NOT_ENOUGH_MEMORY;
hr = E_OUTOFMEMORY;
}
} else {
// Todo: Sysmon-specific message re: file too large.
dwMsgStatus = ERROR_DS_OBJ_TOO_LARGE;
hr = HRESULT_FROM_WIN32(ERROR_DS_OBJ_TOO_LARGE);
}
CloseHandle ( hOpenFile );
} else {
//
// Return file system error.
//
assert (FALSE);
dwMsgStatus = GetLastError();
hr = HRESULT_FROM_WIN32(dwMsgStatus);
}
}
}
FindClose (hFindFile) ;
} else {
dwMsgStatus = GetLastError();
HRESULT_FROM_WIN32(dwMsgStatus);
}
} else {
//
// STRSAFE_E_INSUFFICIENT_BUFFER indicates filename truncation.
//
dwMsgStatus = ERROR_BUFFER_OVERFLOW;
hr = HRESULT_FROM_WIN32(dwMsgStatus);
}
} else {
hr = E_OUTOFMEMORY;
dwMsgStatus = ERROR_OUTOFMEMORY;
}
if ( ERROR_SUCCESS != dwMsgStatus ) {
LPWSTR szMessage = NULL;
LPWSTR szSystemMessage = NULL;
INT cchBufLen;
cchBufLen = lstrlen(szLocalName) + MAX_MESSAGE_LEN + RESOURCE_STRING_BUF_LEN + 1;
szMessage = new WCHAR [cchBufLen];
szSystemMessage = new WCHAR [MAX_MESSAGE_LEN + 1];
if ( NULL != szMessage && NULL != szSystemMessage ) {
StringCchPrintf (
szMessage,
cchBufLen,
ResourceString(IDS_READFILE_ERR),
szLocalName );
FormatSystemMessage ( dwMsgStatus, szSystemMessage, MAX_MESSAGE_LEN + 1 );
StringCchCat(szMessage, cchBufLen, szSystemMessage );
MessageBox(Window(), szMessage, ResourceString(IDS_APP_NAME), MB_OK | MB_ICONSTOP);
}
if ( NULL != szMessage ) {
delete [] szMessage;
}
if ( NULL != szSystemMessage ) {
delete [] szSystemMessage;
}
}
if ( NULL != szLocalName ) {
delete [] szLocalName;
}
return hr;
}
void
CSysmonControl::OnDropFile ( WPARAM wParam )
{
LPWSTR szFileName = NULL;
INT iFileCount = 0;
HRESULT hr = S_OK;
UINT uiCchFileName;
iFileCount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0) ;
if ( iFileCount > 0 ) {
//
// Open only the first file.
//
uiCchFileName = DragQueryFile((HDROP) wParam, 0, NULL,0 );
szFileName = new WCHAR[uiCchFileName + 1];
if ( NULL != szFileName ) {
uiCchFileName = DragQueryFile((HDROP) wParam, 0, szFileName, uiCchFileName + 1 );
//
// LoadFromFile handles file name errors.
//
hr = LoadFromFile ( szFileName, FALSE );
if ( SMON_STATUS_NO_SYSMON_OBJECT == (DWORD)hr ) {
MessageBox(
m_hWnd,
ResourceString(IDS_NOSYSMONOBJECT_ERR ),
ResourceString(IDS_APP_NAME),
MB_OK | MB_ICONERROR);
} // else LoadFromFile displays messages for other errors
delete [] szFileName;
}
}
DragFinish ((HDROP) wParam) ;
}
void
CSysmonControl::DisplayContextMenu(short x, short y)
{
HMENU hMenu;
HMENU hMenuPopup;
RECT clntRect;
int iPosx=0;
int iPosy=0;
int iLocalx;
int iLocaly;
GetWindowRect(m_hWnd,&clntRect);
if (x==0){
iPosx = ((clntRect.right - clntRect.left)/2) ;
}else{
iPosx = x - clntRect.left;
}
if (y==0){
iPosy = ((clntRect.bottom - clntRect.top)/2) ;
}else{
iPosy = y - clntRect.top;
}
iLocalx = clntRect.left + iPosx ;
iLocaly = clntRect.top + iPosy ;
if ( ConfirmSampleDataOverwrite () ) {
if ( !IsReadOnly() ) {
UINT uEnable;
// Get the menu for the pop-up menu from the resource file.
hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_CONTEXT));
if (!hMenu) {
return;
}
// enable/disable SaveData option depending on data source
uEnable = (IsLogSource() ? MF_ENABLED : MF_GRAYED);
uEnable |= MF_BYCOMMAND;
EnableMenuItem (hMenu, IDM_SAVEDATA, uEnable);
// Get the first submenu in it for TrackPopupMenu.
hMenuPopup = GetSubMenu(hMenu, 0);
// Draw and track the "floating" pop-up menu.
TrackPopupMenu(hMenuPopup, TPM_RIGHTBUTTON,
iLocalx, iLocaly, 0, m_hWnd, NULL);
// Destroy the menu.
DestroyMenu(hMenu);
}
}
}
HRESULT CSysmonControl::DisplayProperties ( DISPID dispID )
{
HRESULT hr;
CAUUID caGUID;
OCPFIPARAMS params;
// Give container a chance to show properties
if (NULL!=m_pObj->m_pIOleControlSite) {
hr=m_pObj->m_pIOleControlSite->ShowPropertyFrame();
if (NOERROR == hr)
return hr;
}
//Put up our property pages.
ZeroMemory ( &params, sizeof ( OCPFIPARAMS ) );
hr = m_pObj->m_pImpISpecifyPP->GetPages(&caGUID);
if (FAILED(hr)) {
return hr;
}
params.cbStructSize = sizeof ( OCPFIPARAMS );
params.hWndOwner = m_hWnd;
params.x = 10;
params.y = 10;
params.lpszCaption = ResourceString(IDS_PROPFRM_TITLE);
params.cObjects = 1;
params.lplpUnk = (IUnknown **)&m_pObj,
params.cPages = caGUID.cElems;
params.lpPages = caGUID.pElems;
params.lcid = m_lcidCurrent;
params.dispidInitialProperty = dispID;
hr = OleCreatePropertyFrameIndirect ( &params );
//Free the GUIDs
CoTaskMemFree((void *)caGUID.pElems);
// Make sure correct window has the focus
AssignFocus();
return hr;
}
HRESULT
CSysmonControl::AddCounter(
LPWSTR pszPath,
PCGraphItem *pGItem)
/*++
Routine Description:
AddCounter returns a pointer to the created counter item, or
to the first created counter item if multiple created for a wildcard
path.
EnumExpandedPath calls the AddCallback function for each new counter.
AddCallback passes the counter path on to the AddSingleCounter method.
Arguments:
None.
Return Value:
None.
--*/
{
HRESULT hr;
ENUM_ADD_COUNTER_CALLBACK_INFO CallbackInfo;
if (pszPath == NULL || lstrlen(pszPath) > PDH_MAX_COUNTER_PATH) {
return E_INVALIDARG;
}
CallbackInfo.pCtrl = this;
CallbackInfo.pFirstItem = NULL;
*pGItem = NULL;
hr = EnumExpandedPath(GetDataSourceHandle(), pszPath, AddCounterCallback, &CallbackInfo);
*pGItem = CallbackInfo.pFirstItem;
return hr;
}
HRESULT
CSysmonControl::AddCounters (
VOID
)
/*++
Routine Description:
AddCounters invokes the counter browser to select new counters.
The browser calls the AddCallback function for each new counter.
AddCallback passes the counter path on to the AddCounter method.
Arguments:
None.
Return Value:
None.
--*/
{
ENUM_ADD_COUNTER_CALLBACK_INFO CallbackInfo;
HRESULT hr;
CallbackInfo.pCtrl = this;
CallbackInfo.pFirstItem = NULL;
//
// Browse counters, calling AddCallback for each selected counter.
//
hr = BrowseCounters(
GetDataSourceHandle(),
PERF_DETAIL_WIZARD,
m_hWnd,
AddCounterCallback,
&CallbackInfo,
m_pObj->m_Graph.Options.bMonitorDuplicateInstances);
// Make sure correct window has the focus
AssignFocus();
return hr;
}
HRESULT
CSysmonControl::SaveAs (
VOID
)
/*++
Routine Description:
SaveAs writes the current configuration to an HTML file.
Arguments:
None.
Return Value:
None.
--*/
{
HRESULT hr = S_OK;
INT iReturn = IDCANCEL;
INT i;
OPENFILENAME ofn;
WCHAR szFileName[MAX_PATH+1];
WCHAR szExt[MAX_PATH+1];
WCHAR szFileFilter[RESOURCE_STRING_BUF_LEN];
WCHAR szDefExtension[RESOURCE_STRING_BUF_LEN];
HANDLE hFile = NULL;
DWORD dwMsgStatus = ERROR_SUCCESS;
DWORD dwCreateError;
INT iOverwrite = IDNO;
LPWSTR szMessage = NULL;
size_t cchMessageBuf;
LPWSTR pszTemp = NULL;
WCHAR szByteOrderMark[2];
BOOL bStatus;
DWORD dwByteCount;
//
// Initial directory is the current directory
//
szFileName[0] = L'\0';
ZeroMemory(szFileFilter, sizeof ( szFileFilter ) );
ZeroMemory(&ofn, sizeof(ofn));
StringCchCopy(szFileFilter,
RESOURCE_STRING_BUF_LEN,
ResourceString (IDS_HTML_FILE));
StringCchCopy(szDefExtension,
RESOURCE_STRING_BUF_LEN,
ResourceString (IDS_DEF_EXT));
for( i = 0; szFileFilter[i]; i++ ){
if( szFileFilter[i] == L'|' ){
szFileFilter[i] = L'\0';
}
}
for( i = 0; szDefExtension[i]; i++ ){
if( szDefExtension[i] == L'|' ){
szDefExtension[i] = L'\0';
}
}
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = Window();
ofn.hInstance = NULL ; // Ignored if no template argument
ofn.lpstrFilter = szFileFilter;
ofn.lpstrDefExt = szDefExtension;
ofn.nFilterIndex = 1; // nFilterIndex is 1-based
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.nMaxFileTitle = 0;
ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
iReturn = GetSaveFileName (&ofn);
//
// Differentiate between *.htm and *.tsv
//
_wsplitpath(szFileName,NULL,NULL,NULL,szExt);
if ( IDOK == iReturn ) {
//
// Create a file.
//
hFile = CreateFile (
szFileName,
GENERIC_READ | GENERIC_WRITE,
0, // Not shared
NULL, // Security attributes
CREATE_NEW, // Query the user if file already exists.
FILE_ATTRIBUTE_NORMAL,
NULL );
if ( INVALID_HANDLE_VALUE == hFile ) {
dwCreateError = GetLastError();
if ( ERROR_SUCCESS != dwCreateError ) {
//
// Confirm file overwrite.
//
cchMessageBuf = lstrlen(szFileName) + RESOURCE_STRING_BUF_LEN + 1;
szMessage = new WCHAR [cchMessageBuf];
if ( NULL != szMessage ) {
StringCchPrintf(
szMessage,
cchMessageBuf,
ResourceString(IDS_HTML_FILE_OVERWRITE),
szFileName );
iOverwrite = MessageBox(
Window(),
szMessage,
ResourceString(IDS_APP_NAME),
MB_YESNO );
delete [] szMessage;
if ( IDYES == iOverwrite ) {
hFile = CreateFile (
szFileName,
GENERIC_READ | GENERIC_WRITE,
0, // Not shared
NULL, // Security attributes
CREATE_ALWAYS, // Overwrite any existing file.
FILE_ATTRIBUTE_NORMAL,
NULL );
}
}
}
}
if ( INVALID_HANDLE_VALUE != hFile ) {
CWaitCursor cursorWait;
// Save the current configuration to the file.
if( (!_wcsicmp(szExt,ResourceString(IDS_HTM_EXTENSION)))
|| (!_wcsicmp(szExt,ResourceString(IDS_HTML_EXTENSION))) ) {
// Html file
szByteOrderMark[0] = 0xFEFF;
szByteOrderMark[1] = L'\0';
bStatus = FileWrite ( hFile, szByteOrderMark, sizeof(WCHAR) );
if ( bStatus ) {
if (m_fRTL || (GetWindowLongPtr(Window(), GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ) {
bStatus = FileWrite ( hFile, (PVOID)CGlobalString::m_cszHtmlFileHeaderRTL , lstrlen (CGlobalString::m_cszHtmlFileHeaderRTL ) * sizeof(WCHAR) );
}
else {
bStatus = FileWrite ( hFile, (PVOID)CGlobalString::m_cszHtmlFileHeader , lstrlen (CGlobalString::m_cszHtmlFileHeader ) * sizeof(WCHAR) );
}
}
if ( bStatus ) {
hr = CopyToBuffer ( pszTemp, dwByteCount );
if ( SUCCEEDED ( hr ) ) {
assert ( NULL != pszTemp );
assert ( 0 != dwByteCount );
bStatus = FileWrite ( hFile, pszTemp, dwByteCount );
delete [] pszTemp;
} else {
bStatus = FALSE;
SetLastError ( ERROR_OUTOFMEMORY );
}
}
if ( bStatus ) {
bStatus = FileWrite ( hFile, (PVOID)CGlobalString::m_cszHtmlFileFooter, lstrlen (CGlobalString::m_cszHtmlFileFooter) * sizeof(WCHAR) );
}
if ( !bStatus ) {
dwMsgStatus = GetLastError();
}
} else if (!_wcsicmp(szExt,ResourceString(IDS_TSV_EXTENSION))){
// Tsv file
bStatus = WriteFileReportHeader(hFile);
if (bStatus){
bStatus = m_pReport->WriteFileReport(hFile);
}
if (!bStatus){
dwMsgStatus = GetLastError();
}
}
bStatus = CloseHandle ( hFile );
} else {
dwMsgStatus = GetLastError();
}
if ( ERROR_SUCCESS != dwMsgStatus ) {
LPWSTR szSystemMessage = NULL;
cchMessageBuf = lstrlen(szFileName) + MAX_MESSAGE_LEN + RESOURCE_STRING_BUF_LEN + 1;
szSystemMessage = new WCHAR[MAX_MESSAGE_LEN + 1];
szMessage = new WCHAR [ cchMessageBuf ];
if ( NULL != szMessage && NULL != szSystemMessage ) {
StringCchPrintf(
szMessage,
cchMessageBuf,
ResourceString(IDS_SAVEAS_ERR),
szFileName );
FormatSystemMessage ( dwMsgStatus, szSystemMessage, MAX_MESSAGE_LEN );
StringCchCat(szMessage, cchMessageBuf, szSystemMessage );
MessageBox(Window(), szMessage, ResourceString(IDS_APP_NAME), MB_OK | MB_ICONSTOP);
}
if ( NULL != szMessage ) {
delete [] szMessage;
}
if ( NULL != szSystemMessage ) {
delete [] szSystemMessage;
}
}
} // else ignore if they canceled out
// Make sure correct window has the focus
AssignFocus();
return hr;
}
HRESULT
CSysmonControl::SaveData (
VOID
)
/*++
Routine Description:
SaveData writes the data from the display to a binary log file for
later input as a data source.
Arguments:
None.
Return Value:
None.
--*/
{
HRESULT hr = S_OK;
DWORD dwStatus = ERROR_SUCCESS;
INT iReturn = IDCANCEL;
INT i;
OPENFILENAME ofn;
WCHAR szFileName[MAX_PATH+1];
WCHAR szFileFilter[RESOURCE_STRING_BUF_LEN];
WCHAR szDefExtension[RESOURCE_STRING_BUF_LEN];
WCHAR szDialogCaption[RESOURCE_STRING_BUF_LEN];
LONG lOrigFilterValue;
LPWSTR szSystemMessage = NULL;
//
// Initial directory is the current directory
//
szFileName[0] = TEXT('\0');
ZeroMemory(szFileFilter, sizeof ( szFileFilter ) );
ZeroMemory(&ofn, sizeof(ofn));
StringCchCopy(szFileFilter,
RESOURCE_STRING_BUF_LEN,
ResourceString (IDS_LOG_FILE));
StringCchCopy (szDefExtension,
RESOURCE_STRING_BUF_LEN,
ResourceString (IDS_LOG_FILE_EXTENSION));
StringCchCopy (szDialogCaption,
RESOURCE_STRING_BUF_LEN,
ResourceString (IDS_SAVE_DATA_CAPTION));
for( i = 0; szFileFilter[i]; i++ ){
if( szFileFilter[i] == TEXT('|') ){
szFileFilter[i] = 0;
}
}
for( i = 0; szDefExtension[i]; i++ ){
if( szDefExtension[i] == TEXT('|') ){
szDefExtension[i] = 0;
}
}
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = Window();
ofn.hInstance = GetModuleHandle((LPCWSTR)TEXT("sysmon.ocx")) ; // Ignored if no template argument
ofn.lpstrFilter = szFileFilter;
ofn.lpstrDefExt = szDefExtension;
ofn.nFilterIndex = 1; // nFilterIndex is 1-based
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.nMaxFileTitle = 0;
ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY |
OFN_OVERWRITEPROMPT | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
ofn.lpstrTitle = szDialogCaption;
ofn.lCustData = (DWORD_PTR)this;
ofn.lpfnHook = (LPOFNHOOKPROC) SaveDataDlgHookProc ;
ofn.lpTemplateName = MAKEINTRESOURCE(IDD_SAVEDATA_DLG) ;
lOrigFilterValue = GetSaveDataFilter ();
iReturn = GetSaveFileName (&ofn);
if ( IDOK == iReturn ) {
DWORD dwOutputLogType = PDH_LOG_TYPE_BINARY;
DWORD dwFilterCount; // copy all records within the timerange
PDH_TIME_INFO TimeInfo;
// get log type from file name
if (ofn.nFileExtension > 0) {
if (ofn.lpstrFile[ofn.nFileExtension] != 0) {
if (lstrcmpi (&ofn.lpstrFile[ofn.nFileExtension-1], ResourceString (IDS_CSV_EXTENSION)) == 0) {
dwOutputLogType = PDH_LOG_TYPE_CSV;
} else if (lstrcmpi (&ofn.lpstrFile[ofn.nFileExtension-1], ResourceString (IDS_TSV_EXTENSION)) == 0) {
dwOutputLogType = PDH_LOG_TYPE_TSV;
} // else use binary log format as default
} // else use binary log format as default
} // else use binary log format as default
// get timerange for this log
TimeInfo.StartTime = m_DataSourceInfo.llStartDisp;
TimeInfo.EndTime = m_DataSourceInfo.llStopDisp;
dwFilterCount = GetSaveDataFilter();
//
// Double check the filter count is not 0
//
if (dwFilterCount == 0) {
dwFilterCount = 1;
}
// now relog the data
dwStatus = RelogLogData ( ofn.lpstrFile, dwOutputLogType, TimeInfo, dwFilterCount);
} else {
dwStatus = CommDlgExtendedError();
if ( ERROR_SUCCESS != dwStatus ) {
if ( FNERR_BUFFERTOOSMALL == dwStatus ) {
dwStatus = ERROR_BUFFER_OVERFLOW;
} else {
dwStatus = ERROR_OUTOFMEMORY;
}
szSystemMessage = new WCHAR[MAX_MESSAGE_LEN];
if ( NULL != szSystemMessage ) {
if ( FormatSystemMessage (
dwStatus,
szSystemMessage,
MAX_MESSAGE_LEN ) )
{
MessageBox(
m_hWnd,
szSystemMessage,
ResourceString(IDS_APP_NAME),
MB_OK | MB_ICONERROR);
}
delete [] szSystemMessage;
}
}
//
// They canceled out or error occurred, so restore filter value
//
SetSaveDataFilter (lOrigFilterValue);
}
// Make sure correct window has the focus
AssignFocus();
return hr;
}
DWORD
CSysmonControl::RelogLogData (
LPCWSTR szOutputFile,
DWORD dwOutputLogType,
PDH_TIME_INFO pdhTimeInfo,
DWORD dwFilterCount
)
{
PDH_STATUS pdhStatus;
PDH_RELOG_INFO RelogInfo;
HLOG hLogIn;
//
// Initialize the relog information structure
//
ZeroMemory( &RelogInfo, sizeof(PDH_RELOG_INFO) );
RelogInfo.TimeInfo.StartTime = pdhTimeInfo.StartTime;
RelogInfo.TimeInfo.EndTime = pdhTimeInfo.EndTime;;
RelogInfo.TimeInfo.SampleCount = dwFilterCount;
RelogInfo.dwFileFormat = dwOutputLogType;
RelogInfo.dwFlags = PDH_LOG_WRITE_ACCESS | PDH_LOG_CREATE_ALWAYS;
RelogInfo.strLog = (LPWSTR)szOutputFile;
//
// Set query time range
//
PdhSetQueryTimeRange(m_hQuery, &pdhTimeInfo);
//
// Get the input data source
//
hLogIn = GetDataSourceHandle();
//
// Collect the performance data and write them into output file
//
pdhStatus = PdhRelog( hLogIn, &RelogInfo );
return pdhStatus;
}
BOOL
CSysmonControl::WriteFileReportHeader(HANDLE hFile){
BOOL bStatus = FALSE;
HRESULT hr = S_OK;
DWORD dwStatus = ERROR_SUCCESS;
SYSTEMTIME SysTime;
DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1 ;
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
LPWSTR szHeader = NULL;
LPWSTR szDateTime = NULL;
LPWSTR szDataSource = NULL;
LPWSTR szTime = NULL;
LPWSTR szDate = NULL;
LPWSTR szValue = NULL;
LPWSTR szMiscBuf = NULL;
DWORD dwValueId = IDS_DEFAULT;
WCHAR szByteOrderMark[2];
ULONG ulLogListBufLen = 0;
INT cchTimeBufLen = 0;
INT cchDateBufLen = 0;
INT cchHeaderBufLen = 0;
INT cchMiscBufLen = 0;
//
// Computer name
//
if (!GetComputerName(szComputerName,&dwSize)){
szComputerName[0] = L'\0';
}
//
// Current date and time
//
GetLocalTime(&SysTime);
cchTimeBufLen = GetTimeFormat (m_lcidCurrent, 0, &SysTime, NULL, NULL, 0 ) ;
if ( 0 != cchTimeBufLen ) {
szTime = new WCHAR[cchTimeBufLen];
if ( NULL != szTime ) {
if ( 0 != GetTimeFormat (m_lcidCurrent, 0, &SysTime, NULL, szTime, cchTimeBufLen) ) {
bStatus = TRUE;
}
}
}
if ( bStatus ) {
bStatus = FALSE;
cchDateBufLen = GetDateFormat (m_lcidCurrent, DATE_SHORTDATE, &SysTime, NULL, NULL, 0 ) ;
if ( 0 != cchDateBufLen ) {
szDate = new WCHAR[cchDateBufLen];
if ( NULL != szTime ) {
if ( 0 != GetDateFormat (m_lcidCurrent, DATE_SHORTDATE, &SysTime, NULL, szDate, cchDateBufLen) ) {
bStatus = TRUE;
}
}
}
}
if ( bStatus ) {
bStatus = FALSE;
//
// Subtract 1 for extra null.
//
cchMiscBufLen = RESOURCE_STRING_BUF_LEN + cchDateBufLen + cchTimeBufLen - 1;
szDateTime = new WCHAR [cchMiscBufLen];
if ( NULL != szDateTime ) {
hr = StringCchPrintf(
szDateTime,
cchMiscBufLen,
ResourceString( IDS_REPORT_DATE_TIME ),
szDate,
szTime );
if ( SUCCEEDED ( hr ) ) {
bStatus = TRUE;
}
}
}
//
// Report value type
//
if ( bStatus ) {
bStatus = FALSE;
switch ( m_pObj->m_Graph.Options.iReportValueType ) {
case sysmonCurrentValue:
dwValueId = IDS_LAST;
break;
case sysmonAverage:
dwValueId = IDS_AVERAGE;
break;
case sysmonMinimum:
dwValueId = IDS_MINIMUM;
break;
case sysmonMaximum:
dwValueId = IDS_MAXIMUM;
break;
default:
dwValueId = IDS_DEFAULT;
}
//
// Add 1 for null.
//
cchMiscBufLen = ( RESOURCE_STRING_BUF_LEN * 2 ) + 1;
szValue = new WCHAR [cchMiscBufLen];
if ( NULL != szValue ) {
hr = StringCchPrintf(
szValue,
cchMiscBufLen,
ResourceString ( IDS_REPORT_VALUE_TYPE ),
ResourceString ( dwValueId ) );
if ( SUCCEEDED ( hr ) ) {
bStatus = TRUE;
}
}
}
//
// Data source
//
if ( bStatus ) {
bStatus = FALSE;
cchMiscBufLen = RESOURCE_STRING_BUF_LEN + 1;
if ( sysmonCurrentActivity == m_pObj->m_Graph.Options.iDataSourceType ) {
szDataSource = new WCHAR [cchMiscBufLen];
if ( NULL != szDataSource ) {
hr = StringCchCopy(
szDataSource,
cchMiscBufLen,
ResourceString(IDS_REPORT_REAL_TIME));
if ( SUCCEEDED ( hr ) ) {
bStatus = TRUE;
}
}
} else if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType ) {
dwStatus = BuildLogFileList (
NULL,
TRUE,
&ulLogListBufLen );
szDataSource = new WCHAR [ulLogListBufLen];
if ( NULL != szDataSource ) {
dwStatus = BuildLogFileList (
szDataSource,
TRUE,
&ulLogListBufLen );
if ( ERROR_SUCCESS == dwStatus ) {
bStatus = TRUE;
}
}
} else if ( sysmonSqlLog == m_pObj->m_Graph.Options.iDataSourceType ) {
dwStatus = FormatSqlDataSourceName (
m_DataSourceInfo.szSqlDsnName,
m_DataSourceInfo.szSqlLogSetName,
NULL,
&ulLogListBufLen );
if ( ERROR_SUCCESS == dwStatus ) {
szDataSource = new WCHAR [ulLogListBufLen];
if ( NULL != szDataSource ) {
dwStatus = FormatSqlDataSourceName (
m_DataSourceInfo.szSqlDsnName,
m_DataSourceInfo.szSqlLogSetName,
szDataSource,
&ulLogListBufLen );
if ( ERROR_SUCCESS == dwStatus ) {
bStatus = TRUE;
}
}
}
}
}
//
// Header
//
if ( bStatus ) {
bStatus = FALSE;
cchHeaderBufLen = lstrlenW(szComputerName)
+ lstrlenW(szDateTime)
+ lstrlenW(szValue)
+ lstrlenW(szDataSource);
cchHeaderBufLen += RESOURCE_STRING_BUF_LEN; // IDS_REPORT_HEADER;
cchHeaderBufLen += RESOURCE_STRING_BUF_LEN; // IDS_REPORT_INTERVAL
cchHeaderBufLen += 10; // Max interval text length
cchHeaderBufLen += RESOURCE_STRING_BUF_LEN; // IDS_REPORT_LOG_START
cchHeaderBufLen += (cchDateBufLen + cchTimeBufLen); // Includes space, line end
cchHeaderBufLen += RESOURCE_STRING_BUF_LEN; // IDS_REPORT_LOG_STOP
cchHeaderBufLen += (cchDateBufLen + cchTimeBufLen); // Includes space
cchHeaderBufLen += (1 + 1); // Line end, NULL
szHeader = new WCHAR [cchHeaderBufLen];
if ( NULL != szHeader ) {
hr = StringCchPrintf(
szHeader,
cchHeaderBufLen,
ResourceString(IDS_REPORT_HEADER),
szComputerName,
szDateTime,
szValue,
szDataSource );
if ( SUCCEEDED ( hr ) ) {
bStatus = TRUE;
}
}
}
if ( bStatus ) {
bStatus = FALSE;
if ( sysmonCurrentActivity == m_pObj->m_Graph.Options.iDataSourceType ) {
//
// Sample interval, only for realtime data source.
//
cchMiscBufLen = RESOURCE_STRING_BUF_LEN + 10 + 1,
szMiscBuf = new WCHAR [cchMiscBufLen];
if ( NULL != szMiscBuf ) {
StringCchPrintf(
szMiscBuf,
cchMiscBufLen,
ResourceString(IDS_REPORT_INTERVAL),
m_pObj->m_Graph.Options.fUpdateInterval );
StringCchCat(szHeader, cchHeaderBufLen, szMiscBuf);
}
bStatus = TRUE;
} else if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType
|| sysmonSqlLog == m_pObj->m_Graph.Options.iDataSourceType )
{
//
// Add start and stop string for log files or Sql logs.
//
cchMiscBufLen = RESOURCE_STRING_BUF_LEN * 2
+ cchDateBufLen * 2
+ cchTimeBufLen * 2
+ 1 + 1;
szMiscBuf = new WCHAR [ cchMiscBufLen ];
if ( NULL != szMiscBuf ) {
FormatDateTime(m_DataSourceInfo.llStartDisp,szDate,szTime);
StringCchPrintf(
szMiscBuf,
cchMiscBufLen,
TEXT("%s%s %s\n"),
ResourceString(IDS_REPORT_LOG_START),
szDate,
szTime );
FormatDateTime(m_DataSourceInfo.llStopDisp,szDate,szTime);
StringCchCat(szMiscBuf, cchMiscBufLen, ResourceString(IDS_REPORT_LOG_STOP));
FormatDateTime(m_DataSourceInfo.llStopDisp,szDate,szTime);
StringCchCat(szMiscBuf, cchMiscBufLen, szDate);
StringCchCat(szMiscBuf, cchMiscBufLen, SpaceStr);
StringCchCat(szMiscBuf, cchMiscBufLen, szTime);
StringCchCat(szMiscBuf, cchMiscBufLen, LineEndStr);
StringCchCat(szHeader, cchHeaderBufLen, szMiscBuf);
bStatus = TRUE;
}
}
}
if ( bStatus ) {
szByteOrderMark[0] = 0xFEFF;
szByteOrderMark[1] = L'\0';
bStatus = FileWrite ( hFile, szByteOrderMark, sizeof(WCHAR) );
bStatus = FileWrite ( hFile, szHeader, lstrlen (szHeader) * sizeof(WCHAR) );
}
if ( NULL != szTime ) {
delete [] szTime;
}
if ( NULL != szDate ) {
delete [] szDate;
}
if ( NULL != szDateTime ) {
delete [] szDateTime;
}
if ( NULL != szValue ) {
delete [] szValue;
}
if ( NULL != szDataSource ) {
delete [] szDataSource;
}
if ( NULL != szHeader ) {
delete [] szHeader;
}
if ( NULL != szMiscBuf ) {
delete [] szMiscBuf;
}
return bStatus;
}
BOOL CSysmonControl::InitView (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 don't worry about the size here, as this window
will be resized whenever the main window is resized.
Note: This method initializes the control for rendering.
*/
{
PCGraphItem pItem;
WNDCLASS wc ;
// Protect against multiple initializations
if (m_fViewInitialized)
return TRUE;
BEGIN_CRITICAL_SECTION
// Register the window class once
if (pstrRegisteredClasses[SYSMONCTRL_WNDCLASS] == NULL) {
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = SysmonCtrlWndProc ;
wc.hInstance = g_hInstance ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = sizeof (PSYSMONCTRL) ;
wc.hIcon = NULL ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wc.hbrBackground = NULL ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = szSysmonCtrlWndClass ;
if (RegisterClass (&wc)) {
pstrRegisteredClasses[SYSMONCTRL_WNDCLASS] = szSysmonCtrlWndClass;
}
}
END_CRITICAL_SECTION
if (pstrRegisteredClasses[SYSMONCTRL_WNDCLASS] == NULL)
return FALSE;
// Create our control window
m_hWnd = CreateWindow (szSysmonCtrlWndClass, // window class
NULL, // caption
WS_CHILD | WS_VISIBLE, // style for window
0, 0, // initial position
m_pObj->m_RectExt.right, // width
m_pObj->m_RectExt.bottom, // height
hWndParent, // parent
NULL, // menu
g_hInstance, // program instance
(LPVOID)this) ; // user-supplied data
if (m_hWnd == NULL) {
// DWORD err = GetLastError();
return FALSE;
}
DragAcceptFiles (m_hWnd, TRUE) ;
// Subcomponents are allocated in AllocateSubcomponents
// Init the legend
if ( !m_pLegend
|| !m_pGraphDisp
|| !m_pStatsBar
|| !m_pSnapBar
|| !m_pToolbar
|| !m_pReport )
{
return FALSE;
}
if (!m_pLegend->Init(this, m_hWnd))
return FALSE;
// Init the graph display
if (!m_pGraphDisp->Init(this, &m_pObj->m_Graph))
return FALSE;
// Init the statistics bar
if (!m_pStatsBar->Init(this, m_hWnd))
return FALSE;
// Init the snapshot bar
if (!m_pSnapBar->Init(this, m_hWnd))
return FALSE;
if (!m_pToolbar->Init(this, m_hWnd))
return FALSE;
// Init the report view
if (!m_pReport->Init(this, m_hWnd))
return FALSE;
m_fViewInitialized = TRUE;
// If counters are present
if ((pItem = FirstCounter()) != NULL) {
// Add counters to the legend and report view
while (pItem != NULL) {
m_pLegend->AddItem(pItem);
m_pReport->AddItem(pItem);
pItem = pItem->Next();
}
if ( NULL != m_pSelectedItem ) {
SelectCounter(m_pSelectedItem);
} else {
SelectCounter(FirstCounter());
}
if ( !m_bLogFileSource ) {
// Pass new time span to statistics bar. This must
// be done after initializing the stats bar.
m_pStatsBar->SetTimeSpan (
m_pObj->m_Graph.Options.fUpdateInterval
* m_pObj->m_Graph.Options.iDisplayFilter
* m_pHistCtrl->nMaxSamples );
}
}
// Processing the command line can add counters from the property bag.
// Add the counters after the counter addition and selection code above
// so that counters do not get added twice.
//
// Continue on failure of ProcessCommandLine. Error messages are displayed in that method.
//
ProcessCommandLine ( );
return TRUE;
}
BOOL CSysmonControl::Init (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 don't worry about the size here, as this window
will be resized whenever the main window is resized.
*/
{
PCGraphItem pItem;
BOOL bResult = TRUE;
// Protect against multiple initializations
if (!m_fInitialized) {
bResult = InitView( hWndParent );
if ( !m_bSampleDataLoaded ) {
if ( bResult ) {
m_fInitialized = TRUE;
// When loaded from property bag or stream, the log file name is
// already set. If realtime query, the Pdh query might
// not have been opened.
if ( sysmonCurrentActivity == m_pObj->m_Graph.Options.iDataSourceType ) {
put_DataSourceType ( sysmonCurrentActivity );
}
// Load the accelerator table
m_hAccel = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(ID_SMONACCEL));
// If counters are present
if ((pItem = FirstCounter()) != NULL) {
if ( ERROR_SUCCESS != ActivateQuery() ) {
m_fInitialized = FALSE;
return FALSE;
}
}
}
}
}
//sync the toolbar last
if ( bResult ) {
m_pToolbar->SyncToolbar();
}
return bResult;
}
HRESULT CSysmonControl::LoadFromStream(LPSTREAM pIStream)
{
typedef struct _DATA_LIST_ELEM
{
GRAPHITEM_DATA3 itemData;
LPWSTR szCounterPath;
struct _DATA_LIST_ELEM* pNext;
} DATA_LIST_ELEM, *PDATA_LIST_ELEM;
HRESULT hr = S_OK;
ULONG bc;
GRAPH_OPTIONS *pOptions = &m_pObj->m_Graph.Options;
RECT RectExt;
SMONCTRL_VERSION_DATA VersionData;
LPWSTR szLogFilePath = NULL;
INT32 iLocalDataSourceType = (INT32)sysmonNullDataSource;
GRAPHCTRL_DATA3 CtrlData3;
ENUM_ADD_COUNTER_CALLBACK_INFO CallbackInfo;
PDATA_LIST_ELEM pFirstElem = NULL;
PDATA_LIST_ELEM pLastElem = NULL;
PDATA_LIST_ELEM pNewElem = NULL;
LPWSTR pszCounterPath = NULL;
LPWSTR szLocaleBuf = NULL;
DWORD dwLocaleBufSize = 0;
LPWSTR pszPath = NULL;
USES_CONVERSION
if (g_dwScriptPolicy == URLPOLICY_DISALLOW) {
return E_ACCESSDENIED;
}
if ( !m_bSettingsLoaded ) {
// Read in parameters
hr = pIStream->Read(&VersionData, sizeof(VersionData), &bc);
if (FAILED(hr))
return hr;
if (bc != sizeof(VersionData))
return E_FAIL;
//
// Windows2000 shipped as 3.3.
// XP shipped as 3.6.
//
// The code below assumes that Sysmon version is 3.6.
//
assert ( 3 == SMONCTRL_MAJ_VERSION );
assert ( 6 == SMONCTRL_MIN_VERSION );
// Read version 3 streams only.
if ( VersionData.iMajor < SMONCTRL_MAJ_VERSION )
return E_FAIL;
// Update the current loaded version number in order
// to warn the user appropriately when saving to stream.
m_LoadedVersion.iMajor = VersionData.iMajor;
m_LoadedVersion.iMinor = VersionData.iMinor;
assert( 256 == sizeof(CtrlData3) );
ZeroMemory ( &CtrlData3, sizeof ( CtrlData3 ) );
hr = pIStream->Read(&CtrlData3, sizeof(CtrlData3), &bc);
if (FAILED(hr))
return hr;
if (bc != sizeof(CtrlData3))
return E_FAIL;
// Setup extent info
SetRect(&RectExt, 0, 0, CtrlData3.iWidth, CtrlData3.iHeight);
m_pObj->RectConvertMappings(&RectExt, TRUE); // Convert from HIMETRIC
m_pObj->m_RectExt = RectExt;
SetCurrentClientRect( &RectExt );
// Load options settings in graph structure
pOptions->iVertMax = CtrlData3.iScaleMax;
pOptions->iVertMin = CtrlData3.iScaleMin;
pOptions->bLegendChecked = CtrlData3.bLegend;
pOptions->bToolbarChecked = CtrlData3.bToolbar;
pOptions->bLabelsChecked = CtrlData3.bLabels;
pOptions->bHorzGridChecked = CtrlData3.bHorzGrid;
pOptions->bVertGridChecked = CtrlData3.bVertGrid;
pOptions->bValueBarChecked = CtrlData3.bValueBar;
pOptions->bManualUpdate = CtrlData3.bManualUpdate;
pOptions->bHighlight = CtrlData3.bHighlight; // New for 3.1, default = 0
pOptions->bReadOnly = CtrlData3.bReadOnly; // New for 3.1+, default = 0
pOptions->bAmbientFont = CtrlData3.bAmbientFont; // New for 3.3+, new default = 1, but 0 for old files.
pOptions->bMonitorDuplicateInstances = CtrlData3.bMonitorDuplicateInstances;
pOptions->fUpdateInterval = CtrlData3.fUpdateInterval;
pOptions->iDisplayType = CtrlData3.iDisplayType;
pOptions->clrBackCtl = CtrlData3.clrBackCtl;
pOptions->clrFore = CtrlData3.clrFore;
pOptions->clrBackPlot = CtrlData3.clrBackPlot;
pOptions->iAppearance = CtrlData3.iAppearance;
pOptions->iBorderStyle = CtrlData3.iBorderStyle;
pOptions->iReportValueType = CtrlData3.iReportValueType; // New for 3.1+, default = 0
pOptions->iDisplayFilter = CtrlData3.iDisplayFilter; // New for 3.4, default = 1, 0 is invalid
iLocalDataSourceType = CtrlData3.iDataSourceType; // New for 3.4, default = 1, 0 is invalid
// Pre-3.4, set based on presence of log file name // Set pOptions->iDataSourceType below
if ( 0 == pOptions->iDisplayFilter ) {
// New for 3.4
assert ( ( SMONCTRL_MIN_VERSION - 2 ) > VersionData.iMinor );
pOptions->iDisplayFilter = 1;
}
// Grid and TimeBar saved to file as of version 3.1.
pOptions->clrGrid = CtrlData3.clrGrid;
pOptions->clrTimeBar = CtrlData3.clrTimeBar;
// Load font info if not using ambient font
if ( !pOptions->bAmbientFont ) {
hr = m_OleFont.LoadFromStream(pIStream);
if (FAILED(hr))
return hr;
}
// Read titles and log file name
// As of Version 3.2, title and log file name strings stored as Wide characters
// Log file name
hr = WideStringFromStream(pIStream, &szLogFilePath, CtrlData3.nFileNameLen);
if (FAILED(hr))
return hr;
// Graph title
hr = WideStringFromStream(pIStream, &pOptions->pszGraphTitle, CtrlData3.nGraphTitleLen);
if (FAILED(hr))
return hr;
// Y axis label
hr = WideStringFromStream(pIStream, &pOptions->pszYaxisTitle, CtrlData3.nYaxisTitleLen);
if (FAILED(hr))
return hr;
// Read display range
m_DataSourceInfo.llStartDisp = CtrlData3.llStartDisp;
m_DataSourceInfo.llStopDisp = CtrlData3.llStopDisp;
// Must put actual data source type after loading display range, before adding counters.
// Always set data source to null data source before adding data source names.
hr = put_DataSourceType ( sysmonNullDataSource );
if ( SUCCEEDED ( hr ) && NULL != szLogFilePath ) {
assert ( 0 == NumLogFiles() );
if ( L'\0' != szLogFilePath[0] ) {
if ( ( SMONCTRL_MIN_VERSION - 1 ) > VersionData.iMinor ) {
// 3.4 writes a single log file.
hr = AddSingleLogFile ( szLogFilePath );
} else {
// 3.5+ writes a multi_sz
hr = LoadLogFilesFromMultiSz ( szLogFilePath );
}
}
}
if ( NULL != szLogFilePath ) {
delete [] szLogFilePath;
}
// If version < 3.4, set data source type based on presence of log files.
if ( ( SMONCTRL_MIN_VERSION - 2 ) > VersionData.iMinor ) {
// DataSourceType is new for 3.4
if ( 0 == NumLogFiles() ) {
iLocalDataSourceType = sysmonCurrentActivity;
} else {
iLocalDataSourceType = sysmonLogFiles;
}
}
// Set scale max and min
m_pObj->m_Graph.Scale.SetMaxValue(pOptions->iVertMax);
m_pObj->m_Graph.Scale.SetMinValue(pOptions->iVertMin);
// Convert non-null OLE colors to real colors
if (pOptions->clrFore != NULL_COLOR)
OleTranslateColor(pOptions->clrFore, NULL, &m_clrFgnd);
if (pOptions->clrBackPlot != NULL_COLOR)
OleTranslateColor(pOptions->clrBackPlot, NULL, &m_clrBackPlot);
// NT 5 Beta 1 BackCtlColor can be NULL.
if (pOptions->clrBackCtl != NULL_COLOR)
OleTranslateColor(pOptions->clrBackCtl, NULL, &m_clrBackCtl);
OleTranslateColor(pOptions->clrGrid, NULL, &m_clrGrid);
OleTranslateColor(pOptions->clrTimeBar, NULL, &m_clrTimeBar);
// Handle other ambient properties
if ( NULL_APPEARANCE != pOptions->iAppearance )
put_Appearance( pOptions->iAppearance, FALSE );
if ( NULL_BORDERSTYLE != pOptions->iBorderStyle )
put_BorderStyle( pOptions->iBorderStyle, FALSE );
// Read legend data
hr = m_pLegend->LoadFromStream(pIStream);
if (FAILED(hr))
return hr;
//Load the counters
hr = S_OK;
// Load the counters into temporary storage, so that they can be added after the
// SQL name and future items are loaded
while (TRUE) {
pNewElem = new ( DATA_LIST_ELEM );
if ( NULL != pNewElem ) {
ZeroMemory ( pNewElem, sizeof ( DATA_LIST_ELEM ) );
// Add to end of list
pNewElem->pNext = NULL;
if ( NULL == pFirstElem ) {
pFirstElem = pNewElem;
pLastElem = pFirstElem;
} else if ( NULL == pLastElem ) {
pLastElem = pNewElem;
} else {
pLastElem->pNext = pNewElem;
pLastElem = pNewElem;
}
// Read in parameters
hr = pIStream->Read(&pNewElem->itemData, sizeof(GRAPHITEM_DATA3), &bc);
if ( SUCCEEDED ( hr ) ) {
if (bc == sizeof(GRAPHITEM_DATA3)) {
// Stop on null item (indicated by no path name)
if (pNewElem->itemData.m_nPathLength == 0) {
break;
}
} else {
hr = E_FAIL;
}
}
} else {
hr = E_OUTOFMEMORY;
}
if ( SUCCEEDED ( hr ) ) {
// As of Version 3.2, title and log file name strings stored as Wide characters
// Read in path name
hr = WideStringFromStream(pIStream, &pszCounterPath, pNewElem->itemData.m_nPathLength);
}
if ( SUCCEEDED ( hr ) ) {
pNewElem->szCounterPath = pszCounterPath;
pszCounterPath = NULL;
}
}
if ( NULL != pszCounterPath ) {
delete [] pszCounterPath;
pszCounterPath = NULL;
}
if ( FAILED ( hr ) ) {
while ( NULL != pFirstElem ) {
pNewElem = pFirstElem->pNext;
if ( NULL != pFirstElem->szCounterPath ) {
delete [] pFirstElem->szCounterPath;
}
delete pFirstElem;
pFirstElem = pNewElem;
}
return hr;
}
// Load SQL names from the stream
hr = WideStringFromStream(pIStream, &m_DataSourceInfo.szSqlDsnName, CtrlData3.iSqlDsnLen);
if ( FAILED ( hr ) )
return hr;
hr = WideStringFromStream(pIStream, &m_DataSourceInfo.szSqlLogSetName, CtrlData3.iSqlLogSetNameLen);
if (FAILED(hr))
return hr;
// Set the data source
hr = put_DataSourceType ( iLocalDataSourceType );
if (FAILED(hr)) {
if ( SMON_STATUS_LOG_FILE_SIZE_LIMIT == (DWORD)hr ) {
// TodoLogFiles: Check log file type. Only perfmon and circular
// binary logs are still limited to 1 GB.
// TodoLogFiles: Current query is already closed,
// so what can be done here?
} else {
DWORD dwStatus;
LPWSTR szLogFileList = NULL;
ULONG ulLogListBufLen= 0;
if ( sysmonLogFiles == iLocalDataSourceType ) {
dwStatus = BuildLogFileList ( NULL, TRUE, &ulLogListBufLen );
szLogFileList = new WCHAR[ulLogListBufLen];
if ( NULL != szLogFileList ) {
dwStatus = BuildLogFileList ( szLogFileList, TRUE, &ulLogListBufLen );
}
}
dwStatus = DisplayDataSourceError (
m_hWnd,
(DWORD)hr,
iLocalDataSourceType,
szLogFileList,
m_DataSourceInfo.szSqlDsnName,
m_DataSourceInfo.szSqlLogSetName );
if ( NULL != szLogFileList ) {
delete [] szLogFileList;
}
}
}
m_bLogFileSource = ( sysmonCurrentActivity != m_pObj->m_Graph.Options.iDataSourceType );
hr = S_OK;
// Load the counters from the temporary data storage.
m_bLoadingCounters = TRUE;
for ( pNewElem = pFirstElem; NULL != pNewElem; pNewElem = pNewElem->pNext ) {
DWORD dwBufSize;
LPWSTR pNewBuf;
PDH_STATUS pdhStatus;
CallbackInfo.pCtrl = this;
CallbackInfo.pFirstItem = NULL;
// Stop on null item (indicated by no path name)
if ( 0 == pNewElem->itemData.m_nPathLength ) {
break;
}
// Set up properties so AddCounter can use them
m_clrCounter = pNewElem->itemData.m_rgbColor;
m_iColorIndex = ColorToIndex (pNewElem->itemData.m_rgbColor);
m_iWidthIndex = WidthToIndex (pNewElem->itemData.m_iWidth);
m_iStyleIndex = StyleToIndex (pNewElem->itemData.m_iStyle);
m_iScaleFactor = pNewElem->itemData.m_iScaleFactor;
pszPath = pNewElem->szCounterPath;
//
// Initialize the locale path buffer
//
if (dwLocaleBufSize == 0) {
dwLocaleBufSize = PDH_MAX_COUNTER_PATH + 1;
szLocaleBuf = (LPWSTR) malloc(dwLocaleBufSize * sizeof(WCHAR));
if (szLocaleBuf == NULL) {
dwLocaleBufSize = 0;
}
}
if (szLocaleBuf != NULL) {
//
// Translate counter name from English to Localization
//
dwBufSize = dwLocaleBufSize;
pdhStatus = PdhTranslateLocaleCounter(
pNewElem->szCounterPath,
szLocaleBuf,
&dwBufSize);
if (pdhStatus == PDH_MORE_DATA) {
pNewBuf = (LPWSTR) realloc(szLocaleBuf, dwBufSize * sizeof(WCHAR));
if (pNewBuf != NULL) {
szLocaleBuf = pNewBuf;
dwLocaleBufSize = dwBufSize;
pdhStatus = PdhTranslateLocaleCounter(
pNewElem->szCounterPath,
szLocaleBuf,
&dwBufSize);
}
}
if (pdhStatus == ERROR_SUCCESS) {
pszPath = szLocaleBuf;
}
}
// Add new counter to control
EnumExpandedPath (GetDataSourceHandle(),
pszPath,
AddCounterCallback,
&CallbackInfo );
}
if (szLocaleBuf != NULL) {
free(szLocaleBuf);
}
m_bLoadingCounters = FALSE;
while ( NULL != pFirstElem ) {
pNewElem = pFirstElem->pNext;
if ( NULL != pFirstElem->szCounterPath ) {
delete [] pFirstElem->szCounterPath;
}
delete pFirstElem;
pFirstElem = pNewElem;
}
if ( SMONCTRL_MAJ_VERSION == VersionData.iMajor
&& SMONCTRL_MIN_VERSION == VersionData.iMinor ) {
m_pObj->m_fDirty=FALSE;
} else {
m_pObj->m_fDirty=TRUE;
}
if ( SMONCTRL_MIN_VERSION == VersionData.iMinor ) {
// New for 3.6: Save visuals to the stream
// These must be loaded after the counters are loaded.
m_iColorIndex = CtrlData3.iColorIndex;
m_iWidthIndex = CtrlData3.iWidthIndex;
m_iStyleIndex = CtrlData3.iStyleIndex;
}
} // Settings not loaded yet.
return hr;
}
HRESULT
CSysmonControl::SaveToStream(LPSTREAM pIStream)
{
HRESULT hr = NOERROR;
DWORD dwStatus = ERROR_SUCCESS;
GRAPH_OPTIONS *pOptions = &m_pObj->m_Graph.Options;
RECT RectExt;
SMONCTRL_VERSION_DATA VersionData;
LPWSTR pszWideGraphTitle;
LPWSTR pszWideYaxisTitle;
PCMachineNode pMachine;
PCObjectNode pObject;
PCInstanceNode pInstance;
PCGraphItem pItem;
PCCounterNode pCounter;
ULONG ulLogFileListLen = 0;
LPWSTR szLogFileList = NULL;
GRAPHCTRL_DATA3 CtrlData3;
USES_CONVERSION
assert( 256 == sizeof(CtrlData3) );
ZeroMemory( &CtrlData3, 256 );
//Store extent data in HIMETRIC format
RectExt = m_pObj->m_RectExt;
m_pObj->RectConvertMappings(&RectExt, FALSE);
CtrlData3.iWidth = RectExt.right - RectExt.left;
CtrlData3.iHeight = RectExt.bottom - RectExt.top;
// Store options settings in structure
CtrlData3.iScaleMax = pOptions->iVertMax;
CtrlData3.iScaleMin = pOptions->iVertMin;
CtrlData3.bLegend = pOptions->bLegendChecked;
CtrlData3.bToolbar = pOptions->bToolbarChecked;
CtrlData3.bLabels = pOptions->bLabelsChecked;
CtrlData3.bHorzGrid = pOptions->bHorzGridChecked;
CtrlData3.bVertGrid = pOptions->bVertGridChecked;
CtrlData3.bValueBar = pOptions->bValueBarChecked;
CtrlData3.bManualUpdate = pOptions->bManualUpdate;
CtrlData3.bHighlight = pOptions->bHighlight;
CtrlData3.bReadOnly = pOptions->bReadOnly;
CtrlData3.bMonitorDuplicateInstances = pOptions->bMonitorDuplicateInstances;
CtrlData3.bAmbientFont = pOptions->bAmbientFont;
CtrlData3.fUpdateInterval = pOptions->fUpdateInterval;
CtrlData3.iDisplayType = pOptions->iDisplayType;
CtrlData3.iReportValueType = pOptions->iReportValueType;
CtrlData3.clrBackCtl = pOptions->clrBackCtl;
CtrlData3.clrFore = pOptions->clrFore;
CtrlData3.clrBackPlot = pOptions->clrBackPlot;
CtrlData3.iAppearance = pOptions->iAppearance;
CtrlData3.iBorderStyle = pOptions->iBorderStyle;
CtrlData3.clrGrid = pOptions->clrGrid;
CtrlData3.clrTimeBar = pOptions->clrTimeBar;
CtrlData3.iDisplayFilter = pOptions->iDisplayFilter;
CtrlData3.iDataSourceType = pOptions->iDataSourceType;
// Store the visuals in pOptions if they become visible
// via the programming interface.
CtrlData3.iColorIndex = m_iColorIndex;
CtrlData3.iWidthIndex = m_iWidthIndex;
CtrlData3.iStyleIndex = m_iStyleIndex;
// NT 5 Beta 1 BackColorCtl can be NULL.
if ( NULL_COLOR == pOptions->clrBackCtl )
CtrlData3.clrBackCtl = m_clrBackCtl;
// Save number of samples to keep
CtrlData3.nSamples = m_pHistCtrl->nMaxSamples;
// Store Wide string lengths
pszWideGraphTitle = pOptions->pszGraphTitle;
CtrlData3.nGraphTitleLen = (pszWideGraphTitle == NULL) ?
0 : lstrlen(pszWideGraphTitle);
pszWideYaxisTitle = pOptions->pszYaxisTitle;
CtrlData3.nYaxisTitleLen = (pszWideYaxisTitle == NULL) ?
0 : lstrlen(pszWideYaxisTitle);
BuildLogFileList ( NULL, FALSE, &ulLogFileListLen );
CtrlData3.nFileNameLen = (INT32) ulLogFileListLen;
CtrlData3.iSqlDsnLen = 0;
if ( NULL != m_DataSourceInfo.szSqlDsnName ) {
CtrlData3.iSqlDsnLen = lstrlen ( m_DataSourceInfo.szSqlDsnName );
}
CtrlData3.iSqlLogSetNameLen = 0;
if ( NULL != m_DataSourceInfo.szSqlLogSetName ) {
CtrlData3.iSqlLogSetNameLen = lstrlen ( m_DataSourceInfo.szSqlLogSetName );
}
// Store other file info
CtrlData3.llStartDisp = m_DataSourceInfo.llStartDisp;
CtrlData3.llStopDisp = m_DataSourceInfo.llStopDisp;
// Write version info
VersionData.iMajor = SMONCTRL_MAJ_VERSION;
VersionData.iMinor = SMONCTRL_MIN_VERSION;
hr = pIStream->Write(&VersionData, sizeof(VersionData), NULL);
if (FAILED(hr))
return hr;
// Write control data
hr = pIStream->Write(&CtrlData3, sizeof(CtrlData3), NULL);
if (FAILED(hr))
return hr;
// Write font info if not using ambient font
if ( !pOptions->bAmbientFont ) {
hr = m_OleFont.SaveToStream(pIStream, TRUE);
if (FAILED(hr))
return hr;
}
// Write log file name
if (CtrlData3.nFileNameLen != 0) {
szLogFileList = new WCHAR[ulLogFileListLen];
if ( NULL != szLogFileList ) {
dwStatus = BuildLogFileList (
szLogFileList,
FALSE,
&ulLogFileListLen );
if ( ERROR_SUCCESS != dwStatus ) {
hr = E_FAIL;
}
} else {
hr = E_OUTOFMEMORY;
}
if ( SUCCEEDED ( hr ) ) {
hr = pIStream->Write(szLogFileList, CtrlData3.nFileNameLen*sizeof(WCHAR), NULL);
}
if ( NULL != szLogFileList ) {
delete [] szLogFileList;
szLogFileList = NULL;
}
if (FAILED(hr))
return hr;
}
// Write titles
if (CtrlData3.nGraphTitleLen != 0) {
hr = pIStream->Write(pszWideGraphTitle, CtrlData3.nGraphTitleLen*sizeof(WCHAR), NULL);
if (FAILED(hr))
return hr;
}
if (CtrlData3.nYaxisTitleLen != 0) {
hr = pIStream->Write(pszWideYaxisTitle, CtrlData3.nYaxisTitleLen*sizeof(WCHAR), NULL);
if (FAILED(hr))
return hr;
}
// Write legend data
hr = m_pLegend->SaveToStream(pIStream);
if (FAILED(hr))
return hr;
// Save all counter info
// Explicit counters first, followed by "All Instance" groups
for ( pMachine = CounterTree()->FirstMachine();
pMachine;
pMachine = pMachine->Next()) {
for ( pObject = pMachine->FirstObject();
pObject;
pObject = pObject->Next()) {
// Clear generated pointer for all object's counters
for ( pCounter = pObject->FirstCounter();
pCounter;
pCounter = pCounter->Next()) {
pCounter->m_pFirstGenerated = NULL;
}
for ( pInstance = pObject->FirstInstance();
pInstance;
pInstance = pInstance->Next()) {
for ( pItem = pInstance->FirstItem();
pItem;
pItem = pItem->m_pNextItem) {
// If item is the first generated one for this counter
// then save it as the wild card model for this counter
if (pItem->m_fGenerated) {
if (pItem->Counter()->m_pFirstGenerated == NULL)
pItem->Counter()->m_pFirstGenerated = pItem;
}
else {
// else save it explictly
hr = pItem->SaveToStream(pIStream, FALSE, VersionData.iMajor, VersionData.iMinor);
if (FAILED(hr))
return hr;
}
}
}
// Now go through counters again and store a wildcard path
// for any that have genererated counters
for (pCounter = pObject->FirstCounter();
pCounter;
pCounter = pCounter->Next()) {
if (pCounter->m_pFirstGenerated) {
hr = pCounter->m_pFirstGenerated->SaveToStream(pIStream, TRUE, VersionData.iMajor, VersionData.iMinor);
if (FAILED(hr))
return hr;
}
}
}
}
// Write null item to mark end of counter items
hr = CGraphItem::NullItemToStream(pIStream, VersionData.iMajor, VersionData.iMinor);
// Write Sql data source names
if (CtrlData3.iSqlDsnLen != 0) {
hr = pIStream->Write(m_DataSourceInfo.szSqlDsnName, CtrlData3.iSqlDsnLen*sizeof(WCHAR), NULL);
}
if (CtrlData3.iSqlLogSetNameLen != 0) {
hr = pIStream->Write(m_DataSourceInfo.szSqlLogSetName, CtrlData3.iSqlLogSetNameLen*sizeof(WCHAR), NULL);
}
return hr;
}
HRESULT
CSysmonControl::LoadLogFilesFromPropertyBag (
IPropertyBag* pIPropBag,
IErrorLog* pIErrorLog )
{
HRESULT hr = S_OK;
HRESULT hrErr = S_OK;
INT iLogFileCount = 0;
INT iIndex;
INT iBufSize = 0;
INT iPrevBufSize = 0;
LPWSTR pszLogFilePath = NULL;
INT iLogFilePathBufSize = 0;
WCHAR szLogFilePropName[32];
eDataSourceTypeConstant ePrevDataSourceType;
DWORD dwErrorPathListLen;
LPCWSTR szErrorPathList = NULL;
LPWSTR szMessage = NULL;
get_DataSourceType ( ePrevDataSourceType );
ClearErrorPathList();
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszLogFileName, NULL, iBufSize );
if ( SUCCEEDED(hr) &&
iBufSize > 0 ) {
pszLogFilePath = new WCHAR[iBufSize + 1];
if ( NULL != pszLogFilePath ) {
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszLogFileName, pszLogFilePath, iBufSize );
} else {
hr = E_OUTOFMEMORY;
}
if ( SUCCEEDED ( hr ) ) {
// Always set the log source to null data source before modifying the log file list.
// TodoLogFiles: This can leave the user with state different than before, in the
// case of log file load failure.
hr = put_DataSourceType ( sysmonNullDataSource );
if ( SUCCEEDED ( hr ) ) {
assert ( 0 == NumLogFiles() );
hr = AddSingleLogFile ( pszLogFilePath );
}
}
if ( FAILED ( hr ) && NULL != pszLogFilePath ) {
hrErr = hr;
AddToErrorPathList ( pszLogFilePath );
}
if ( NULL != pszLogFilePath ) {
delete [] pszLogFilePath;
pszLogFilePath = NULL;
}
} else {
hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszLogFileCount, iLogFileCount );
if ( SUCCEEDED( hr ) && 0 < iLogFileCount ) {
assert ( 0 == NumLogFiles() );
for ( iIndex = 1; iIndex <= iLogFileCount; iIndex++ ) {
// Todo: log file list error message, as for counters
// If one of the log files fails to load, continue loading others.
hr = NOERROR;
StringCchPrintf(szLogFilePropName,
32,
CGlobalString::m_cszLogNameFormat,
CGlobalString::m_cszLogFileName,
iIndex );
iPrevBufSize = iBufSize;
hr = StringFromPropertyBag (
pIPropBag,
pIErrorLog,
szLogFilePropName,
pszLogFilePath,
iBufSize );
if ( iBufSize > iPrevBufSize ) {
if ( NULL == pszLogFilePath || (iBufSize > iLogFilePathBufSize) ) {
if ( NULL != pszLogFilePath ) {
delete [] pszLogFilePath;
pszLogFilePath = 0;
}
pszLogFilePath = new WCHAR[iBufSize];
if ( NULL != pszLogFilePath ) {
iLogFilePathBufSize = iBufSize;
}
}
if ( NULL != pszLogFilePath ) {
hr = StringFromPropertyBag (
pIPropBag,
pIErrorLog,
szLogFilePropName,
pszLogFilePath,
iBufSize );
} else {
hr = E_OUTOFMEMORY;
}
}
if ( SUCCEEDED(hr)
&& MAX_PATH >= lstrlen(pszLogFilePath) ) {
hr = put_DataSourceType ( sysmonNullDataSource );
if ( SUCCEEDED ( hr ) ) {
hr = AddSingleLogFile ( pszLogFilePath );
}
}
if ( FAILED (hr) && SMON_STATUS_DUPL_LOG_FILE_PATH != (DWORD)hr )
{
if ( S_OK == hrErr ) {
hrErr = hr;
}
AddToErrorPathList ( pszLogFilePath );
}
}
}
}
if ( NULL != pszLogFilePath ) {
delete [] pszLogFilePath;
pszLogFilePath = NULL;
}
if ( SMON_STATUS_DUPL_LOG_FILE_PATH != (DWORD)hr ) {
szErrorPathList = GetErrorPathList ( &dwErrorPathListLen );
if ( NULL != szErrorPathList ) {
// Report error, but continue.
szMessage = new WCHAR [dwErrorPathListLen + RESOURCE_STRING_BUF_LEN + 1];
if ( NULL != szMessage ) {
StringCchPrintf(szMessage,
dwErrorPathListLen + MAX_PATH,
ResourceString(IDS_ADD_LOG_FILE_ERR),
szErrorPathList );
MessageBox (
m_hWnd,
szMessage,
ResourceString(IDS_APP_NAME),
MB_OK | MB_ICONEXCLAMATION );
delete [] szMessage;
}
}
}
ClearErrorPathList();
return hrErr;
}
HRESULT
CSysmonControl::LoadCountersFromPropertyBag (
IPropertyBag* pIPropBag,
IErrorLog* pIErrorLog,
BOOL bLoadData )
{
HRESULT hr = S_OK;
HRESULT hrErr = S_OK;
INT iCounterCount = 0;
INT iSampleCount = 0;
INT intValue;
INT iIndex;
INT iBufSize = 0;
INT iPrevBufSize = 0;
LPWSTR pszCounterPath = NULL;
INT iCounterPathBufSize = 0;
LPWSTR szSelected = NULL;
INT nBufferSize = 0;
WCHAR szPathPropName[32];
LPWSTR szEnglishBuf = NULL;
DWORD dwEnglishBufSize = 0;
LPWSTR pszPath = NULL;
DWORD dwBufSize;
LPWSTR pNewBuf;
PDH_STATUS pdhStatus;
PCGraphItem pItem = NULL;
DWORD dwCounterListLen = 0;
LPCWSTR szCounterList = NULL;
hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszCounterCount, iCounterCount );
if ( SUCCEEDED( hr ) && 0 < iCounterCount ) {
szSelected = NULL;
do {
if (szSelected) {
delete [] szSelected;
szSelected = NULL;
nBufferSize = iBufSize;
}
else {
nBufferSize = PDH_MAX_COUNTER_PATH + 1;
iBufSize = nBufferSize;
}
szSelected = new WCHAR [nBufferSize];
if (szSelected == NULL) {
return E_OUTOFMEMORY;
}
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszSelected, szSelected, iBufSize );
} while (SUCCEEDED(hr) && iBufSize > nBufferSize);
if( SUCCEEDED( hr ) ){
//
// Initialize the locale path buffer
//
if (dwEnglishBufSize == 0) {
dwEnglishBufSize = PDH_MAX_COUNTER_PATH + 1;
szEnglishBuf = (LPWSTR) malloc(dwEnglishBufSize * sizeof(WCHAR));
if (szEnglishBuf == NULL) {
dwEnglishBufSize = 0;
}
}
if (szEnglishBuf != NULL) {
//
// Translate counter name from Localization into English
//
dwBufSize = dwEnglishBufSize;
pdhStatus = PdhTranslate009Counter(
szSelected,
szEnglishBuf,
&dwBufSize);
if (pdhStatus == PDH_MORE_DATA) {
pNewBuf = (LPWSTR)realloc(szEnglishBuf, dwBufSize * sizeof(WCHAR));
if (pNewBuf != NULL) {
szEnglishBuf = pNewBuf;
dwEnglishBufSize = dwBufSize;
pdhStatus = PdhTranslate009Counter(
szSelected,
szEnglishBuf,
&dwBufSize);
}
}
if (pdhStatus == ERROR_SUCCESS && (LONG)dwBufSize < lstrlen(szSelected) ) {
StringCchCopy(szSelected, nBufferSize, szEnglishBuf);
}
}
}
}
if ( bLoadData ) {
hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszSampleCount, iSampleCount );
if ( SUCCEEDED(hr) && ( 0 < iSampleCount ) ) {
intValue = 0;
hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszSampleIndex, intValue );
if ( SUCCEEDED(hr) && intValue > 0 && intValue <= iSampleCount ) {
INT iStepNum;
hr = IntegerFromPropertyBag (
pIPropBag,
pIErrorLog,
CGlobalString::m_cszStepNumber, iStepNum );
if ( SUCCEEDED(hr) ) {
// If data has been passed, freeze the view.
// These values are set only if all three values are present in the property bag.
put_ManualUpdate( TRUE );
// MaxSamples hardcoded for NT5
m_pHistCtrl->nSamples = iSampleCount;
m_pHistCtrl->iCurrent = intValue;
m_pObj->m_Graph.TimeStepper.StepTo(iStepNum);
m_bSampleDataLoaded = TRUE;
}
}
}
} else {
iSampleCount = 0;
}
iBufSize = 0;
ClearErrorPathList();
for ( iIndex = 1; iIndex <= iCounterCount; iIndex++ ) {
// If one of the counters fails to load, continue loading others.
hr = NOERROR;
StringCchPrintf(szPathPropName, 32, L"%s%05d.Path", CGlobalString::m_cszCounter, iIndex );
iPrevBufSize = iBufSize;
hr = StringFromPropertyBag (
pIPropBag,
pIErrorLog,
szPathPropName,
pszCounterPath,
iBufSize );
if ( iBufSize > iPrevBufSize ) {
if ( NULL == pszCounterPath || (iBufSize > iCounterPathBufSize) ) {
if ( NULL != pszCounterPath ) {
delete [] pszCounterPath;
iCounterPathBufSize = 0;
}
pszCounterPath = new WCHAR[iBufSize];
if ( NULL != pszCounterPath ) {
iCounterPathBufSize = iBufSize;
}
}
if ( NULL != pszCounterPath ) {
hr = StringFromPropertyBag (
pIPropBag,
pIErrorLog,
szPathPropName,
pszCounterPath,
iBufSize );
} else {
hr = E_OUTOFMEMORY;
}
}
pszPath = pszCounterPath;
if ( SUCCEEDED(hr) ) {
//
// Translate English counter name into localized counter name
//
if (dwEnglishBufSize == 0) {
dwEnglishBufSize = PDH_MAX_COUNTER_PATH + 1;
szEnglishBuf = (LPWSTR) malloc(dwEnglishBufSize * sizeof(WCHAR));
if (szEnglishBuf == NULL) {
dwEnglishBufSize = 0;
}
}
if (szEnglishBuf != NULL) {
//
// Translate counter name from English to Localization
//
dwBufSize = dwEnglishBufSize;
pdhStatus = PdhTranslateLocaleCounter(
pszCounterPath,
szEnglishBuf,
&dwBufSize);
if (pdhStatus == PDH_MORE_DATA) {
pNewBuf = (LPWSTR) realloc(szEnglishBuf, dwBufSize * sizeof(WCHAR));
if (pNewBuf != NULL) {
szEnglishBuf = pNewBuf;
dwEnglishBufSize = dwBufSize;
pdhStatus = PdhTranslateLocaleCounter(
pszCounterPath,
szEnglishBuf,
&dwBufSize);
}
}
if (pdhStatus == ERROR_SUCCESS) {
pszPath = szEnglishBuf;
}
}
hr = AddCounter ( pszPath, &pItem );
// Return status of the first failed counter.
if ( FAILED ( hr ) && SMON_STATUS_DUPL_COUNTER_PATH != (DWORD)hr ) {
if ( S_OK == hrErr ) {
hrErr = hr;
}
}
} else {
hr = E_FAIL;
if ( S_OK == hrErr ) {
hrErr = E_FAIL;
}
}
if ( SUCCEEDED(hr) ) {
assert ( NULL != pItem );
if ( 0 == lstrcmpi ( pszPath, szSelected ) ) {
SelectCounter( pItem );
}
if ( SUCCEEDED(hr) ) {
assert ( NULL != pItem );
// Only pass sample count if all sample properties exist
// in the property bag.
hr = pItem->LoadFromPropertyBag (
pIPropBag,
pIErrorLog,
iIndex,
SMONCTRL_MAJ_VERSION,
SMONCTRL_MIN_VERSION,
m_bSampleDataLoaded ? iSampleCount : 0 );
}
} else {
if ( SMON_STATUS_DUPL_COUNTER_PATH != (DWORD)hr ) {
AddToErrorPathList ( pszPath );
}
}
}
if (szSelected != NULL){
delete [] szSelected;
}
if (szEnglishBuf != NULL) {
free(szEnglishBuf);
}
if ( NULL != pszCounterPath ) {
delete [] pszCounterPath;
}
szCounterList = GetErrorPathList ( &dwCounterListLen );
if ( NULL != szCounterList ) {
LPWSTR szMessage = NULL;
// Report error, but continue.
szMessage = new WCHAR [dwCounterListLen + RESOURCE_STRING_BUF_LEN + 1];
if ( NULL != szMessage ) {
StringCchPrintf(szMessage,
dwCounterListLen + RESOURCE_STRING_BUF_LEN + 1,
ResourceString(IDS_ADD_COUNTER_ERR),
szCounterList );
MessageBox (
m_hWnd,
szMessage,
ResourceString(IDS_APP_NAME),
MB_OK | MB_ICONEXCLAMATION);
delete [] szMessage;
}
ClearErrorPathList();
}
return hrErr;
}
HRESULT
CSysmonControl::LoadFromPropertyBag (
IPropertyBag* pIPropBag,
IErrorLog* pIErrorLog )
{
HRESULT hr = S_OK;
GRAPH_OPTIONS *pOptions = &m_pObj->m_Graph.Options;
ISystemMonitor *pObj = m_pObj->m_pImpISystemMonitor;
INT iExtentX;
INT iExtentY;
INT intValue;
BOOL bValue;
FLOAT fValue;
OLE_COLOR clrValue;
INT iBufSize;
SMONCTRL_VERSION_DATA VersionData;
INT nLogType = SMON_CTRL_LOG;
// Version info
if (g_dwScriptPolicy == URLPOLICY_DISALLOW) {
return E_ACCESSDENIED;
}
VersionData.dwVersion = 0;
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszVersion, (INT&)VersionData.dwVersion );
assert ( SMONCTRL_MAJ_VERSION >= VersionData.iMajor );
m_LoadedVersion.dwVersion = VersionData.dwVersion;
hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszLogType, nLogType);
if(SUCCEEDED(hr) && (nLogType == SLQ_TRACE_LOG)) {
// This is a WMI/WDM event trace log files, bail out immediately.
//
MessageBox(m_hWnd,
ResourceString(IDS_TRACE_LOG_ERR_MSG),
ResourceString(IDS_APP_NAME),
MB_OK);
return NOERROR;
}
// When loading properties, continue even if errors. On error, the value will
// remain default value.
// Extent data
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszExtentX, iExtentX );
if ( SUCCEEDED( hr ) ){
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszExtentY, iExtentY );
if ( SUCCEEDED( hr ) ) {
RECT RectExt;
SetRect(&RectExt, 0, 0, iExtentX, iExtentY);
m_pObj->RectConvertMappings(&RectExt, TRUE); // Convert from HIMETRIC
m_pObj->m_RectExt = RectExt;
}
}
// Options settings. Where possible, options are added through the vtable
// interface, for validation.
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszDisplayType, intValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_DisplayType ( (eDisplayTypeConstant)intValue );
}
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszReportValueType, intValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ReportValueType ( (eReportValueTypeConstant)intValue );
}
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszMaximumScale, intValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_MaximumScale ( intValue );
}
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszMinimumScale, intValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_MinimumScale ( intValue );
}
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszAppearance, intValue );
if ( SUCCEEDED(hr) ) {
if ( NULL_COLOR == intValue ) {
pOptions->iAppearance = intValue;
} else {
hr = pObj->put_Appearance ( intValue );
}
}
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszBorderStyle, intValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_BorderStyle ( intValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowLegend, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ShowLegend ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowToolBar, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ShowToolbar ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowValueBar, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ShowValueBar ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowScaleLabels, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ShowScaleLabels ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowHorizontalGrid, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ShowHorizontalGrid ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowVerticalGrid, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ShowVerticalGrid ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszHighLight, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_Highlight ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszManualUpdate, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ManualUpdate ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszReadOnly, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_ReadOnly ( (SHORT)bValue );
}
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszMonitorDuplicateInstance, bValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_MonitorDuplicateInstances ( (SHORT)bValue );
}
hr = FloatFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszUpdateInterval, fValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_UpdateInterval ( fValue );
}
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszDisplayFilter, intValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_DisplayFilter ( intValue );
}
hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszBackColorCtl, clrValue );
if ( SUCCEEDED(hr) ) {
if ( NULL_COLOR == clrValue ) {
pOptions->clrBackCtl = clrValue;
} else {
hr = pObj->put_BackColorCtl ( clrValue );
}
}
hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszBackColor, clrValue );
if ( SUCCEEDED(hr) ) {
if ( NULL_COLOR == clrValue ) {
pOptions->clrBackPlot = clrValue;
} else {
hr = pObj->put_BackColor ( clrValue );
}
}
hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszForeColor, clrValue );
if ( SUCCEEDED(hr) ) {
if ( NULL_COLOR == clrValue ) {
pOptions->clrFore = clrValue;
} else {
hr = pObj->put_ForeColor ( clrValue );
}
}
hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszGridColor, clrValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_GridColor ( clrValue );
}
hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszTimeBarColor, clrValue );
if ( SUCCEEDED(hr) ) {
hr = pObj->put_TimeBarColor ( clrValue );
}
// Titles
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszGraphTitle, NULL, iBufSize );
if ( SUCCEEDED(hr) &&
iBufSize > 0 ) {
pOptions->pszGraphTitle = new WCHAR[iBufSize];
if ( NULL != pOptions->pszGraphTitle ) {
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszGraphTitle, pOptions->pszGraphTitle, iBufSize );
}
}
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszYAxisLabel, NULL, iBufSize );
if ( SUCCEEDED(hr) &&
iBufSize > 0 ) {
pOptions->pszYaxisTitle = new WCHAR[iBufSize];
if ( NULL != pOptions->pszYaxisTitle ) {
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszYAxisLabel, pOptions->pszYaxisTitle, iBufSize );
}
}
// SQL DSN and logset info
//
hr = StringFromPropertyBag(
pIPropBag, pIErrorLog, CGlobalString::m_cszSqlDsnName, NULL, iBufSize);
if (SUCCEEDED(hr) && iBufSize > 0) {
if (m_DataSourceInfo.szSqlDsnName) {
delete [] m_DataSourceInfo.szSqlDsnName;
m_DataSourceInfo.szSqlDsnName = NULL;
}
m_DataSourceInfo.szSqlDsnName = new WCHAR[iBufSize + 1];
if (m_DataSourceInfo.szSqlDsnName) {
hr = StringFromPropertyBag(pIPropBag,
pIErrorLog,
CGlobalString::m_cszSqlDsnName,
m_DataSourceInfo.szSqlDsnName,
iBufSize);
}
if (SUCCEEDED(hr)) {
hr = StringFromPropertyBag(
pIPropBag, pIErrorLog, CGlobalString::m_cszSqlLogSetName, NULL, iBufSize);
if (SUCCEEDED(hr) && iBufSize > 0) {
if (m_DataSourceInfo.szSqlLogSetName) {
delete [] m_DataSourceInfo.szSqlLogSetName;
m_DataSourceInfo.szSqlLogSetName = NULL;
}
m_DataSourceInfo.szSqlLogSetName = new WCHAR[iBufSize + 1];
if (m_DataSourceInfo.szSqlLogSetName) {
hr = StringFromPropertyBag(pIPropBag,
pIErrorLog,
CGlobalString::m_cszSqlLogSetName,
m_DataSourceInfo.szSqlLogSetName,
iBufSize);
}
}
}
if (SUCCEEDED(hr)) {
hr = LLTimeFromPropertyBag(pIPropBag,
pIErrorLog,
CGlobalString::m_cszLogViewStart,
m_DataSourceInfo.llStartDisp);
}
if (SUCCEEDED(hr)) {
hr = LLTimeFromPropertyBag(pIPropBag,
pIErrorLog,
CGlobalString::m_cszLogViewStop,
m_DataSourceInfo.llStopDisp);
}
}
// Log file info
hr = LoadLogFilesFromPropertyBag ( pIPropBag, pIErrorLog );
// Must put log file name after display range, before adding counters.
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszDataSourceType, intValue );
if (FAILED (hr)) {
//
// If DataSourceType flag is missing, set data source type based on
// presence of log files.
//
intValue = sysmonCurrentActivity;
if (NumLogFiles() > 0) {
intValue = sysmonLogFiles;
}
else if ( m_DataSourceInfo.szSqlDsnName && m_DataSourceInfo.szSqlLogSetName ) {
if ( m_DataSourceInfo.szSqlDsnName[0] != L'\0' && m_DataSourceInfo.szSqlLogSetName[0] != L'\0') {
intValue = sysmonSqlLog;
}
}
}
// Load log view start and stop times if the data source is not realtime.
if ( sysmonSqlLog == intValue || sysmonLogFiles == intValue ) {
hr = LLTimeFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszLogViewStart, m_DataSourceInfo.llStartDisp );
hr = LLTimeFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszLogViewStop, m_DataSourceInfo.llStopDisp );
}
hr = pObj->put_DataSourceType ( (eDataSourceTypeConstant)intValue );
if( FAILED(hr) ) {
if ( SMON_STATUS_LOG_FILE_SIZE_LIMIT == (DWORD)hr ) {
// TodoLogFiles: Check log file type. Only perfmon and circular
// binary logs are still limited to 1 GB.
// TodoLogFiles: Current query is already closed,
// so what can be done here?
} else {
DWORD dwStatus;
LPWSTR szLogFileList = NULL;
ULONG ulLogListBufLen= 0;
if ( sysmonLogFiles == intValue ) {
dwStatus = BuildLogFileList ( NULL, TRUE, &ulLogListBufLen );
szLogFileList = new WCHAR[ulLogListBufLen];
if ( NULL != szLogFileList ) {
dwStatus = BuildLogFileList (
szLogFileList,
TRUE,
&ulLogListBufLen );
}
}
dwStatus = DisplayDataSourceError (
m_hWnd,
(DWORD)hr,
intValue,
szLogFileList,
m_DataSourceInfo.szSqlDsnName,
m_DataSourceInfo.szSqlLogSetName );
if ( NULL != szLogFileList ) {
delete [] szLogFileList;
szLogFileList = NULL;
}
}
}
// Font info
hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszAmbientFont, bValue );
if (SUCCEEDED(hr)) {
pOptions->bAmbientFont = bValue;
}
// Load property bag values if they exist, overriding any specified aspect of ambient font.
hr = m_OleFont.LoadFromPropertyBag ( pIPropBag, pIErrorLog );
// Legend
hr = m_pLegend->LoadFromPropertyBag ( pIPropBag, pIErrorLog );
// Counters
m_bLoadingCounters = TRUE;
hr = LoadCountersFromPropertyBag ( pIPropBag, pIErrorLog, TRUE );
m_bLoadingCounters = FALSE;
// Load the Visuals after loading all counters.
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszNextCounterColor, intValue );
if ( SUCCEEDED(hr) && ( intValue < NumStandardColorIndices() ) ) {
m_iColorIndex = intValue;
}
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszNextCounterWidth, intValue );
if ( SUCCEEDED(hr) && ( intValue < NumWidthIndices() ) ) {
m_iWidthIndex = intValue;
}
hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszNextCounterLineStyle, intValue );
if ( SUCCEEDED(hr) && ( intValue < NumStyleIndices() ) ) {
m_iStyleIndex = intValue;
}
return NOERROR;
}
HRESULT
CSysmonControl::SaveToPropertyBag (
IPropertyBag* pIPropBag,
BOOL fSaveAllProps )
{
HRESULT hr = NOERROR;
GRAPH_OPTIONS *pOptions = &m_pObj->m_Graph.Options;
PCMachineNode pMachine;
PCObjectNode pObject;
PCInstanceNode pInstance;
PCGraphItem pItem;
PCLogFileItem pLogFile = NULL;
INT iCounterIndex = 0;
INT iLogFileIndex = 0;
RECT RectExt;
SMONCTRL_VERSION_DATA VersionData;
WCHAR szLogFileName[16];
LPWSTR szEnglishBuf = NULL;
DWORD dwEnglishBufSize = 0;
LPWSTR pszPath = NULL;
PDH_STATUS pdhStatus;
// Version info
VersionData.iMajor = SMONCTRL_MAJ_VERSION;
VersionData.iMinor = SMONCTRL_MIN_VERSION;
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszVersion, VersionData.dwVersion );
// Extent data in HIMETRIC format
if ( SUCCEEDED( hr ) ){
RectExt = m_pObj->m_RectExt;
m_pObj->RectConvertMappings(&RectExt, FALSE);
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszExtentX, RectExt.right - RectExt.left );
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszExtentY, RectExt.bottom - RectExt.top );
}
}
// Options settings
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszDisplayType, pOptions->iDisplayType );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszReportValueType, pOptions->iReportValueType );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszMaximumScale, pOptions->iVertMax );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszMinimumScale, pOptions->iVertMin );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowLegend, pOptions->bLegendChecked );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowToolBar, pOptions->bToolbarChecked );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowScaleLabels, pOptions->bLabelsChecked );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowHorizontalGrid, pOptions->bHorzGridChecked );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowVerticalGrid, pOptions->bVertGridChecked );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowValueBar, pOptions->bValueBarChecked );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszManualUpdate, pOptions->bManualUpdate );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszHighLight, pOptions->bHighlight );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszReadOnly, pOptions->bReadOnly );
}
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszMonitorDuplicateInstance, pOptions->bMonitorDuplicateInstances );
}
if ( SUCCEEDED( hr ) ){
hr = FloatToPropertyBag ( pIPropBag, CGlobalString::m_cszUpdateInterval, pOptions->fUpdateInterval );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszDisplayFilter, pOptions->iDisplayFilter );
}
if ( SUCCEEDED( hr ) ){
hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszBackColorCtl, pOptions->clrBackCtl );
}
if ( SUCCEEDED( hr ) ){
hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszForeColor, pOptions->clrFore );
}
if ( SUCCEEDED( hr ) ){
hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszBackColor, pOptions->clrBackPlot );
}
if ( SUCCEEDED( hr ) ){
hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszGridColor, pOptions->clrGrid );
}
if ( SUCCEEDED( hr ) ){
hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszTimeBarColor, pOptions->clrTimeBar );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszAppearance, pOptions->iAppearance );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszBorderStyle, pOptions->iBorderStyle );
}
// Visuals are stored directly in the control. Move to pOptions if made part
// of the programming interface.
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszNextCounterColor, m_iColorIndex );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszNextCounterWidth, m_iWidthIndex );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszNextCounterLineStyle, m_iStyleIndex );
}
// Titles
if ( SUCCEEDED( hr ) ){
hr = StringToPropertyBag ( pIPropBag, CGlobalString::m_cszGraphTitle, pOptions->pszGraphTitle );
}
if ( SUCCEEDED( hr ) ){
hr = StringToPropertyBag ( pIPropBag, CGlobalString::m_cszYAxisLabel, pOptions->pszYaxisTitle );
}
// Data source info
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszDataSourceType, pOptions->iDataSourceType );
}
if ( SUCCEEDED( hr ) &&
( sysmonLogFiles == pOptions->iDataSourceType
|| sysmonSqlLog == pOptions->iDataSourceType ) )
{
hr = LLTimeToPropertyBag ( pIPropBag, CGlobalString::m_cszLogViewStart, m_DataSourceInfo.llStartDisp );
if ( SUCCEEDED( hr ) ){
hr = LLTimeToPropertyBag ( pIPropBag, CGlobalString::m_cszLogViewStop, m_DataSourceInfo.llStopDisp );
}
}
// SQL data source
if (SUCCEEDED(hr)) {
hr = StringToPropertyBag(pIPropBag,
CGlobalString::m_cszSqlDsnName,
m_DataSourceInfo.szSqlDsnName);
}
if (SUCCEEDED(hr)) {
hr = StringToPropertyBag(pIPropBag,
CGlobalString::m_cszSqlLogSetName,
m_DataSourceInfo.szSqlLogSetName);
}
// Log files
if ( SUCCEEDED( hr ) ){
iLogFileIndex = 0;
for (pLogFile = FirstLogFile(); NULL != pLogFile; pLogFile = pLogFile->Next() ) {
StringCchPrintf ( szLogFileName,
16,
CGlobalString::m_cszLogNameFormat,
CGlobalString::m_cszLogFileName,
++iLogFileIndex );
hr = StringToPropertyBag ( pIPropBag, szLogFileName, pLogFile->GetPath() );
}
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszLogFileCount, iLogFileIndex );
}
}
// Font info
if ( SUCCEEDED( hr ) ){
hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszAmbientFont, pOptions->bAmbientFont );
if ( FAILED( hr ) || !pOptions->bAmbientFont ){
hr = m_OleFont.SaveToPropertyBag ( pIPropBag, TRUE, fSaveAllProps );
}
}
// Legend
if ( SUCCEEDED( hr ) ){
hr = m_pLegend->SaveToPropertyBag ( pIPropBag, TRUE, fSaveAllProps );
}
// Save counter count and sample data
LockCounterData();
if ( SUCCEEDED( hr ) ){
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszCounterCount, CounterTree()->NumCounters() );
}
if ( SUCCEEDED(hr) ) {
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszMaximumSamples, m_pHistCtrl->nMaxSamples );
}
if ( SUCCEEDED(hr) ) {
INT iSampleCount;
if ( !m_fUserMode ) {
iSampleCount = 0;
#if !_LOG_INCLUDE_DATA
} else if ( m_bLogFileSource ) {
iSampleCount = 0;
#endif
} else {
iSampleCount = m_pHistCtrl->nSamples;
}
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszSampleCount, iSampleCount );
if ( SUCCEEDED(hr) && ( 0 < iSampleCount )) {
#if _LOG_INCLUDE_DATA
INT iTemp;
iTemp = ( 0 < m_pHistCtrl->iCurrent ? m_pHistCtrl->iCurrent : 1 );
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszSampleIndex, iTemp );
if ( SUCCEEDED(hr) ) {
iTemp = ( 0 < m_pObj->m_Graph.TimeStepper.StepNum() ? m_pObj->m_Graph.TimeStepper.StepNum() : 1 );
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszStepNumber, iTemp );
}
#else
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszSampleIndex, m_pHistCtrl->iCurrent );
if ( SUCCEEDED(hr) ) {
hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszStepNumber, m_pObj->m_Graph.TimeStepper.StepNum() );
}
#endif
}
}
for ( pMachine = CounterTree()->FirstMachine();
pMachine;
pMachine = pMachine->Next()) {
for ( pObject = pMachine->FirstObject();
pObject;
pObject = pObject->Next()) {
for ( pInstance = pObject->FirstInstance();
pInstance;
pInstance = pInstance->Next()) {
for ( pItem = pInstance->FirstItem();
pItem;
pItem = pItem->m_pNextItem) {
// Save all counters explicitly, even if wildcard
iCounterIndex++;
hr = pItem->SaveToPropertyBag (
pIPropBag,
iCounterIndex,
m_fUserMode,
SMONCTRL_MAJ_VERSION,
SMONCTRL_MIN_VERSION);
if (FAILED(hr))
return hr;
}
}
}
}
assert ( iCounterIndex == CounterTree()->NumCounters() );
// Selection
if ( NULL != m_pSelectedItem ) {
VARIANT vValue;
DWORD dwBufSize;
LPWSTR pNewBuf;
VariantInit( &vValue );
vValue.vt = VT_BSTR;
// get this counter path
hr = m_pSelectedItem->get_Path( &vValue.bstrVal );
if( SUCCEEDED(hr) ){
pszPath = vValue.bstrVal;
//
// Initialize the locale path buffer
//
if (dwEnglishBufSize == 0) {
dwEnglishBufSize = PDH_MAX_COUNTER_PATH + 1;
szEnglishBuf = (LPWSTR) malloc(dwEnglishBufSize * sizeof(WCHAR));
if (szEnglishBuf == NULL) {
dwEnglishBufSize = 0;
}
}
if (szEnglishBuf != NULL) {
//
// Translate counter name from Localization into English
//
dwBufSize = dwEnglishBufSize;
pdhStatus = PdhTranslate009Counter(
vValue.bstrVal,
szEnglishBuf,
&dwBufSize);
if (pdhStatus == PDH_MORE_DATA) {
pNewBuf = (LPWSTR)realloc(szEnglishBuf, dwBufSize * sizeof(WCHAR));
if (pNewBuf != NULL) {
szEnglishBuf = pNewBuf;
dwEnglishBufSize = dwBufSize;
pdhStatus = PdhTranslate009Counter(
vValue.bstrVal,
szEnglishBuf,
&dwBufSize);
}
}
if (pdhStatus == ERROR_SUCCESS) {
pszPath = szEnglishBuf;
}
}
if( SUCCEEDED(hr) ) {
VariantClear( &vValue );
vValue.bstrVal = SysAllocString( pszPath );
if( vValue.bstrVal != NULL ){
vValue.vt = VT_BSTR;
}
}else{
//translation failed, write current value
hr = ERROR_SUCCESS;
}
}
if ( SUCCEEDED ( hr ) ) {
hr = pIPropBag->Write(CGlobalString::m_cszSelected, &vValue );
VariantClear ( &vValue );
}
}
if (szEnglishBuf != NULL) {
free(szEnglishBuf);
}
UnlockCounterData();
return hr;
}
DWORD
CSysmonControl::InitializeQuery (
void )
{
DWORD dwStat = ERROR_SUCCESS;
PCGraphItem pItem;
// Query must be opened before this method is called.
if ( NULL != m_hQuery ) {
m_pHistCtrl->nMaxSamples = MAX_GRAPH_SAMPLES;
m_pHistCtrl->iCurrent = 0;
m_pHistCtrl->nSamples = 0;
m_pHistCtrl->nBacklog = 0;
m_pObj->m_Graph.TimeStepper.Reset();
m_pObj->m_Graph.LogViewStartStepper.Reset();
m_pObj->m_Graph.LogViewStopStepper.Reset();
m_pHistCtrl->bLogSource = m_bLogFileSource;
} else {
dwStat = PDH_INVALID_HANDLE;
}
if ( ERROR_SUCCESS == dwStat ) {
// Add counters to the query, to initialize scale factors
if ((pItem = FirstCounter()) != NULL) {
while (pItem != NULL) {
pItem->AddToQuery(m_hQuery);
pItem = pItem->Next();
}
}
}
return dwStat;
}
DWORD
CSysmonControl::ActivateQuery (
void )
{
DWORD dwStat = ERROR_SUCCESS;
DWORD dwThreadID;
// if real-time source
if (!IsLogSource()
&& m_fInitialized
&& IsUserMode() ) {
if ( NULL == m_CollectInfo.hEvent ) {
// Create a collection event
if ((m_CollectInfo.hEvent = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) {
dwStat = GetLastError();
} else
// Create the collection thread
if ( ( m_CollectInfo.hThread
= CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CollectProc, this, 0, &dwThreadID)) == NULL) {
dwStat = GetLastError();
}
if ( ERROR_SUCCESS == dwStat ) {
SetThreadPriority ( m_CollectInfo.hThread, THREAD_PRIORITY_TIME_CRITICAL );
}
}
if ( ERROR_SUCCESS == dwStat ) {
// Start the data collection
if ( FirstCounter() != NULL) {
SetIntervalTimer();
}
}
}
if ( ERROR_SUCCESS != dwStat ) {
// If failure, close query to clean up then exit
CloseQuery();
}
return dwStat;
}
void
CSysmonControl::CloseQuery (
void )
{
PCGraphItem pItem;
// Terminate the collection thread
if ( NULL != m_CollectInfo.hThread ) {
m_CollectInfo.iMode = COLLECT_QUIT;
SetEvent(m_CollectInfo.hEvent);
WaitForSingleObject(m_CollectInfo.hThread, INFINITE);
CloseHandle(m_CollectInfo.hThread);
m_CollectInfo.hThread = NULL;
}
// Release the collection event
if ( NULL != m_CollectInfo.hEvent ) {
CloseHandle(m_CollectInfo.hEvent);
m_CollectInfo.hEvent = NULL;
}
LockCounterData();
// Remove counters from the query
pItem = FirstCounter();
while ( NULL != pItem ) {
pItem->RemoveFromQuery();
pItem = pItem->Next();
}
UnlockCounterData();
// Delete the query
if ( NULL != m_hQuery ) {
PdhCloseQuery ( m_hQuery );
if ( (m_DataSourceInfo.hDataSource != H_REALTIME_DATASOURCE)
&& (m_DataSourceInfo.hDataSource != H_WBEM_DATASOURCE)) {
PdhCloseLog(m_DataSourceInfo.hDataSource, 0);
m_DataSourceInfo.hDataSource = H_REALTIME_DATASOURCE;
}
m_hQuery = NULL;
}
}
void CSysmonControl::SizeComponents ( HDC hDC )
/*
Effect: Move and show the various components of the graph to
fill the size (xWidth x yHeight). Take into account
whether the user wants to show the legend or status
bars. Also take into account if we have room for these
items.
Internals: If the user doesn't want the status or legend windows,
they aren't shown. Also, if the user wanted the status
window but not the legend window, the status window is
not shown.
We may disregard the user's desire for the legend or
status bar if there is not room. In particular, a legend
window has a minimum width (LegendMinWidth ()) and a
minimum height (LegendMinHeight ()). These values are
fixed for a given session of perfmon. It also has a
preferred height, which takes into consideration the
size of the graph window and the number of items in
the legend. This value is returned by LegendHeight().
We don't show the legend if its minimum height would
take up more than half the graph height.
If we feel we don't have room for the legend, we don't
show the status window either.
See Also: LegendMinWidth, LegendMinHeight, LegendHeight,
ValuebarHeight.
Called By: OnSize, any other function that may remove or add one
of the graph components.
*/
{
RECT rectClient;
RECT rectComponent;
RECT rectToolbar;
INT xWidth;
INT yHeight;
INT yGraphHeight = 0;
INT ySnapHeight = 0;
INT yStatsHeight = 0;
INT yLegendHeight = 0;
INT yToolbarHeight = 0;
#define CTRL_BORDER 10
// If not inited, there's noting to size
if (!m_fViewInitialized)
return;
// Get dimensions of window
// GetClientRect (m_hWnd, &rectClient) ;
// *** - Use extent. It is the 'natural' size of the control.
// This draws the control correctly when zoom = 100%
// It also makes print size correct at all zoom levels.
SetCurrentClientRect ( GetNewClientRect() );
rectClient = *GetCurrentClientRect();
switch (m_pObj->m_Graph.Options.iDisplayType) {
case REPORT_GRAPH:
// Toolbar
// Toolbar not available through IViewObect, so leave it out.
if (m_pObj->m_Graph.Options.bToolbarChecked
&& m_fViewInitialized ) {
rectToolbar = rectClient;
// Determine height of toolbar after sizing it, to handle Wrap.
m_pToolbar->SizeComponents(&rectToolbar);
yToolbarHeight = m_pToolbar->Height();
} else {
memset (&rectToolbar, 0, sizeof(RECT));
yToolbarHeight = 0;
}
if (yToolbarHeight > 0) {
rectClient.top += yToolbarHeight;
rectToolbar.bottom = rectToolbar.top + yToolbarHeight;
}
// Give report the entire client area except for toolbar
m_pReport->SizeComponents(&rectClient);
// Hide the other view components
SetRect(&rectClient,0,0,0,0);
m_pGraphDisp->SizeComponents(hDC, &rectClient);
m_pSnapBar->SizeComponents(&rectClient);
m_pStatsBar->SizeComponents(&rectClient);
m_pLegend->SizeComponents(&rectClient);
break;
case LINE_GRAPH:
case BAR_GRAPH:
// Subtract border area
rectComponent = rectClient;
InflateRect(&rectComponent, -CTRL_BORDER, -CTRL_BORDER);
xWidth = rectComponent.right - rectComponent.left ;
yHeight = rectComponent.bottom - rectComponent.top ;
// if the window has no area, forget it
if (xWidth == 0 || yHeight == 0)
return ;
// Reserve top fourth of window for graph
yGraphHeight = yHeight / 4;
yHeight -= yGraphHeight;
// Allocate space to each enabled component
// Toolbar
if (m_pObj->m_Graph.Options.bToolbarChecked
&& m_fViewInitialized ) {
rectToolbar = rectComponent;
m_pToolbar->SizeComponents(&rectToolbar);
yToolbarHeight = m_pToolbar->Height();
} else {
memset (&rectToolbar, 0, sizeof(RECT));
yToolbarHeight = 0;
}
if (yToolbarHeight > 0) {
yHeight -= yToolbarHeight;
rectToolbar.bottom = rectToolbar.top + yToolbarHeight;
rectComponent.top += yToolbarHeight;
}
// Legend (Start with minimum size)
if (m_pObj->m_Graph.Options.bLegendChecked) {
yLegendHeight = m_pLegend->MinHeight(yHeight - CTRL_BORDER);
if (yLegendHeight > 0)
yHeight -= yLegendHeight + CTRL_BORDER;
}
// Statistics bar
if (m_pObj->m_Graph.Options.bValueBarChecked) {
yStatsHeight = m_pStatsBar->Height(yHeight - CTRL_BORDER, xWidth);
if (yStatsHeight > 0)
yHeight -= yStatsHeight + CTRL_BORDER;
}
// Snap bar
// only if tool bar is not displayed
if ((m_pObj->m_Graph.Options.bManualUpdate) &&
(!m_pObj->m_Graph.Options.bToolbarChecked)) {
ySnapHeight = m_pSnapBar->Height(yHeight - CTRL_BORDER);
if (ySnapHeight > 0)
yHeight -= ySnapHeight + CTRL_BORDER;
}
// If legend is visible give it a chance to use remaining space
// Rest goes to graph
if (yLegendHeight != 0) {
yHeight += yLegendHeight;
yLegendHeight = m_pLegend->Height(yHeight);
yGraphHeight += yHeight - yLegendHeight;
}
else
yGraphHeight += yHeight;
// Assign rectangle to each component
// Toolbar assigned earlier, to handle wrap.
// Graph display
rectComponent.bottom = rectComponent.top + yGraphHeight;
m_pGraphDisp->SizeComponents(hDC, &rectComponent);
rectComponent.top += yGraphHeight + CTRL_BORDER;
// Snap bar
rectComponent.bottom = rectComponent.top + ySnapHeight;
m_pSnapBar->SizeComponents(&rectComponent);
if (ySnapHeight != 0)
rectComponent.top += ySnapHeight + CTRL_BORDER;
// Statistics bar
rectComponent.bottom = rectComponent.top + yStatsHeight;
m_pStatsBar->SizeComponents(&rectComponent);
if (yStatsHeight != 0)
rectComponent.top += yStatsHeight + CTRL_BORDER;
// Legend window
rectComponent.bottom = rectComponent.top + yLegendHeight;
m_pLegend->SizeComponents(&rectComponent);
rectComponent.top += yLegendHeight;
// Force redraw of window
// Optimize: SizeComponents only called within Paint or Render,
// so remove this extra window invalidation.
WindowInvalidate(m_hWnd);
// Hide report window
SetRect(&rectClient,0,0,0,0);
m_pReport->SizeComponents(&rectComponent);
break;
}
}
void CSysmonControl::put_Highlight(BOOL bState)
{
// If no change, just return
if ( m_pObj->m_Graph.Options.bHighlight == bState )
return;
m_pObj->m_Graph.Options.bHighlight = bState;
// if no selected item, state doesn't matter
if (m_pSelectedItem == NULL)
return;
// Update graph display's highlighted item
if ( m_pObj->m_Graph.Options.bHighlight )
m_pGraphDisp->HiliteItem(m_pSelectedItem);
else
m_pGraphDisp->HiliteItem(NULL);
// Cause redraw
UpdateGraph(UPDGRPH_PLOT);
}
void
CSysmonControl::put_ManualUpdate(BOOL bManual)
{
m_pObj->m_Graph.Options.bManualUpdate = bManual;
if ( m_bSampleDataLoaded ) {
UpdateCounterValues(FALSE);
} else {
SetIntervalTimer();
UpdateGraph(UPDGRPH_LAYOUT);
}
}
VOID CSysmonControl::AssignFocus (
VOID
)
{
if (m_pObj->m_Graph.Options.iDisplayType == REPORT_GRAPH)
SetFocus(m_pReport->Window());
else
SetFocus(m_pLegend->Window());
}
HRESULT CSysmonControl::TranslateAccelerators( LPMSG pMsg )
{
INT iStat;
if (m_hWnd == NULL || m_hAccel == NULL)
return S_FALSE;
// If this is a cursor key down event, process it here, or the container may grab it first
// I need to be sure that it reaches the legend listbox
if (pMsg->message == WM_KEYDOWN &&
( pMsg->wParam == VK_UP || pMsg->wParam == VK_DOWN ||
pMsg->wParam == VK_HOME || pMsg->wParam == VK_END ) ) {
::TranslateMessage(pMsg);
::DispatchMessage(pMsg);
return S_OK;
}
iStat = ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg);
return iStat ? S_OK : S_FALSE;
}
//==========================================================================//
// Message Handlers //
//==========================================================================//
BOOL
CSysmonControl::DisplayHelp ( HWND hwndSelf )
{
WCHAR pszHelpFilePath[2*MAX_PATH + 1];
UINT nLen;
if ( NULL != hwndSelf ) {
nLen = ::GetWindowsDirectory(pszHelpFilePath, 2*MAX_PATH + 1);
if ( nLen == 0 ) {
// Report error.
return FALSE;
}
StringCchCat(pszHelpFilePath, 2*MAX_PATH + 1, L"\\help\\sysmon.chm");
HtmlHelp ( hwndSelf, pszHelpFilePath, HH_DISPLAY_TOPIC, 0 );
}
return TRUE;
}
LRESULT APIENTRY SysmonCtrlWndProc (HWND hWnd,
UINT uiMsg,
WPARAM wParam,
LPARAM lParam)
{
RECT rect;
PSYSMONCTRL pCtrl = (PSYSMONCTRL)GetWindowLongPtr(hWnd ,0);
INT iUpdate;
switch (uiMsg) {
case WM_NOTIFY:
{
NMHDR *pnmHdr;
NMTTDISPINFO *pnmInfo;
LONG_PTR lStrId;
pnmHdr = (NMHDR *)lParam;
switch (pnmHdr->code) {
case TTN_NEEDTEXT:
pnmInfo = (NMTTDISPINFO *)lParam;
// cast ID as a string for this arg
lStrId = (LONG_PTR)(wParam - IDM_TOOLBAR);
lStrId += IDS_TB_BASE;
pnmInfo->lpszText = (LPWSTR)lStrId;
pnmInfo->hinst = g_hInstance;
break;
default:
return DefWindowProc (hWnd, uiMsg, wParam, lParam);
}
}
break;
case WM_CREATE:
pCtrl = (PSYSMONCTRL)((CREATESTRUCT*)lParam)->lpCreateParams;
SetWindowLongPtr(hWnd,0,(INT_PTR)pCtrl);
break;
case WM_DESTROY:
pCtrl->m_hWnd = NULL;
break;
case WM_CONTEXTMENU:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
//We become UI Active with mouse action
if (!pCtrl->m_fUIDead) {
pCtrl->m_pObj->UIActivate();
pCtrl->AssignFocus();
if (uiMsg == WM_CONTEXTMENU) {
if (LOWORD(lParam)!= 0xffff || HIWORD(lParam) != 0xffff){
pCtrl->DisplayContextMenu(LOWORD(lParam), HIWORD(lParam));
}else{
pCtrl->DisplayContextMenu(0,0);
}
} else if (uiMsg == WM_LBUTTONDBLCLK) {
pCtrl->OnDblClick(LOWORD(lParam), HIWORD(lParam));
}
}
break;
case WM_COMMAND:
if (pCtrl->m_fUIDead)
break;
switch (LOWORD(wParam)) {
case IDM_TB_PROPERTIES:
pCtrl->DisplayProperties();
break;
case IDM_PROPERTIES:
pCtrl->DisplayProperties ( DISPID_VALUE );
break;
case IDM_TB_ADD:
case IDM_ADDCOUNTERS:
pCtrl->AddCounters();
break;
case IDM_TB_DELETE:
case IDM_DELETE:
{
CWaitCursor cursorWait;
if (pCtrl->m_pObj->m_Graph.Options.iDisplayType == REPORT_GRAPH) {
pCtrl->m_pReport->DeleteSelection();
} else {
if ( SUCCEEDED(pCtrl->DeleteCounter ( pCtrl->m_pSelectedItem, TRUE )) ) {
pCtrl->UpdateGraph(UPDGRPH_DELCNTR);
}
}
}
break;
case IDM_TB_REALTIME:
if ( sysmonCurrentActivity != pCtrl->m_pObj->m_Graph.Options.iDataSourceType ) {
CWaitCursor cursorWait;
pCtrl->put_DataSourceType ( sysmonCurrentActivity );
pCtrl->Clear();
} else {
// Nothing changed, so resync the toolbar to
// handle state of realtime button.
pCtrl->m_pToolbar->SyncToolbar();
}
break;
case IDM_TB_LOGFILE:
{
pCtrl->DisplayProperties( DISPID_SYSMON_DATASOURCETYPE );
// Resync the toolbar in case the log file is invalid.
pCtrl->m_pToolbar->SyncToolbar();
}
break;
case IDM_SAVEAS:
pCtrl->SaveAs();
break;
case IDM_SAVEDATA:
pCtrl->SaveData();
break;
case IDC_SNAPBTN:
case IDM_TB_UPDATE:
case IDM_UPDATE:
{
CWaitCursor cursorWait;
pCtrl->UpdateCounterValues(TRUE);
}
break;
case IDM_TB_CLEAR:
{
CWaitCursor cursorWait;
pCtrl->Clear();
}
break;
case IDM_TB_FREEZE:
// Confirm the data overwrite before changing the state of the freeze button.
if ( pCtrl->ConfirmSampleDataOverwrite() ) {
pCtrl->put_ManualUpdate ( !pCtrl->m_pObj->m_Graph.Options.bManualUpdate );
} else {
// Nothing changed, so resync the toolbar to
// handle state of the freeze button.
pCtrl->m_pToolbar->SyncToolbar();
}
break;
case IDM_TB_HIGHLIGHT:
case IDM_HIGHLITE:
pCtrl->put_Highlight(!pCtrl->m_pObj->m_Graph.Options.bHighlight );
break;
case ID_HATCHWINDOW:
if (HIWORD(wParam) == HWN_RESIZEREQUESTED)
pCtrl->m_pObj->m_pIOleIPSite->OnPosRectChange((LPRECT)lParam);
break;
case IDM_TB_CHART:
if (pCtrl->m_pObj->m_Graph.Options.iDisplayType != sysmonLineGraph) {
CWaitCursor cursorWait;
if (pCtrl->m_pObj->m_Graph.Options.iDisplayType == REPORT_GRAPH)
iUpdate = UPDGRPH_VIEW;
else
iUpdate = UPDGRPH_PLOT;
pCtrl->m_pObj->m_Graph.Options.iDisplayType = LINE_GRAPH;
InvalidateRect(pCtrl->m_hWnd, NULL, TRUE);
pCtrl->UpdateGraph(iUpdate);
}
break;
case IDM_TB_HISTOGRAM:
if (pCtrl->m_pObj->m_Graph.Options.iDisplayType != sysmonHistogram) {
CWaitCursor cursorWait;
if (pCtrl->m_pObj->m_Graph.Options.iDisplayType == REPORT_GRAPH)
iUpdate = UPDGRPH_VIEW;
else
iUpdate = UPDGRPH_PLOT;
pCtrl->m_pObj->m_Graph.Options.iDisplayType = BAR_GRAPH;
InvalidateRect(pCtrl->m_hWnd, NULL, TRUE);
pCtrl->UpdateGraph(iUpdate);
}
break;
case IDM_TB_REPORT:
if (pCtrl->m_pObj->m_Graph.Options.iDisplayType != sysmonReport) {
CWaitCursor cursorWait;
pCtrl->m_pObj->m_Graph.Options.iDisplayType = REPORT_GRAPH;
InvalidateRect(pCtrl->m_hWnd, NULL, TRUE);
pCtrl->UpdateGraph(UPDGRPH_VIEW);
}
break;
case IDM_TB_PASTE:
{
HRESULT hr = S_OK;
{
CWaitCursor cursorWait;
hr = pCtrl->Paste();
}
if ( SMON_STATUS_NO_SYSMON_OBJECT == (DWORD)hr ) {
MessageBox(
pCtrl->m_hWnd,
ResourceString(IDS_NOSYSMONOBJECT_ERR ),
ResourceString(IDS_APP_NAME),
MB_OK | MB_ICONERROR);
}
}
break;
case IDM_TB_COPY:
{
CWaitCursor cursorWait;
pCtrl->Copy();
}
break;
case IDM_TB_NEW:
{
CWaitCursor cursorWait;
pCtrl->Reset();
}
break;
case IDM_TB_HELP:
{
return pCtrl->DisplayHelp ( hWnd );
}
default:
return DefWindowProc (hWnd, uiMsg, wParam, lParam);
}
break;
case WM_DROPFILES:
{
CWaitCursor cursorWait;
pCtrl->OnDropFile (wParam) ;
}
return (0) ;
case WM_ERASEBKGND:
GetClientRect(hWnd, &rect);
Fill((HDC)wParam, pCtrl->clrBackCtl(), &rect);
return TRUE;
case WM_SYSCOLORCHANGE:
pCtrl->UpdateNonAmbientSysColors();
case WM_PAINT:
pCtrl->Paint();
break ;
case WM_SIZE:
if (pCtrl != NULL) {
// Avoid extra cases of (SetDirty()) if size has not changed.
if ( !EqualRect ( pCtrl->GetCurrentClientRect(), pCtrl->GetNewClientRect() ) ) {
pCtrl->UpdateGraph(UPDGRPH_LAYOUT);
}
}
break ;
case WM_TIMER:
pCtrl->UpdateCounterValues(FALSE);
break;
case WM_SETFOCUS:
pCtrl->AssignFocus();
break;
case WM_VALUES_UPDATED:
pCtrl->OnValuesUpdated();
break;
case WM_GRAPH_UPDATE:
pCtrl->UpdateGraphData();
break;
case WM_HELP:
{
return pCtrl->DisplayHelp ( hWnd );
}
default:
return DefWindowProc (hWnd, uiMsg, wParam, lParam) ;
}
return (0);
}
HWND CSysmonControl::Window( VOID )
{
return m_hWnd;
}
void CSysmonControl::UpdateGraph( INT nUpdateType )
{
RECT rectStats;
RECT rectGraph;
PRECT prectUpdate = NULL;
RECT rectClient;
// Based on type of change either force redraw or resize components
switch (nUpdateType) {
case UPDGRPH_ADDCNTR:
case UPDGRPH_DELCNTR:
if ( m_bLogFileSource )
m_fPendingLogCntrChg = TRUE;
m_fPendingSizeChg = TRUE;
break;
case UPDGRPH_FONT:
m_fPendingFontChg = TRUE;
break;
case UPDGRPH_LOGVIEW:
m_fPendingLogViewChg = TRUE;
if (m_hWnd && m_pStatsBar ) {
m_pStatsBar->GetUpdateRect(&rectStats);
prectUpdate = &rectStats;
}
// Fall into plot area case
case UPDGRPH_PLOT:
if ( REPORT_GRAPH != m_pObj->m_Graph.Options.iDisplayType ) {
if (m_hWnd && m_pGraphDisp) {
m_pGraphDisp->GetPlotRect(&rectGraph);
if ( NULL == prectUpdate ) {
prectUpdate = &rectGraph;
} else {
::UnionRect( prectUpdate, &rectStats, &rectGraph);
}
}
} else {
GetClientRect (m_hWnd, &rectClient);
prectUpdate = &rectClient;
}
break;
case UPDGRPH_COLOR:
//update the toolbar color
m_pToolbar->SetBackgroundColor ( clrBackCtl() );
m_fPendingSizeChg = TRUE;
break;
case UPDGRPH_LAYOUT:
case UPDGRPH_VIEW:
m_fPendingSizeChg = TRUE;
break;
}
// Set change pending flag to enable ApplyChanges
m_fPendingUpdate = TRUE;
// If we're ready to do updates
if (m_fViewInitialized) {
// Invalidate window to force redraw
InvalidateRect(m_hWnd, prectUpdate, TRUE);
// Notify container of change
m_pObj->SendAdvise(OBJECTCODE_DATACHANGED);
}
}
void
CSysmonControl::OnValuesUpdated ( VOID )
{
// If event sync present, send notification from the
// main thread, outside of lock.
m_pObj->SendEvent(eEventOnSampleCollected, 0);
}
void
CSysmonControl::UpdateGraphData( VOID )
{
HDC hDC = NULL;
PGRAPHDATA pGraph = &m_pObj->m_Graph;
OnValuesUpdated();
if (m_fViewInitialized) {
UpdateAppPerfTimeData (TD_UPDATE_TIME, TD_BEGIN);
hDC = GetDC(m_hWnd);
// Update statistics if active
// Statistics are updated before the graph display in case the
// graph display selects a clipping region.
if (pGraph->Options.bValueBarChecked &&m_pSelectedItem != NULL) {
// The stats bar doesn't always use the hDC, so passing NULL
// hDC is okay.
m_pStatsBar->Update(hDC, m_pSelectedItem);
}
if ( NULL != hDC ) {
// Update graph display
m_pGraphDisp->Update(hDC);
m_pReport->Update();
ReleaseDC(m_hWnd, hDC);
}
UpdateAppPerfTimeData (TD_UPDATE_TIME, TD_END);
}
}
void CSysmonControl::Render(
HDC hDC,
HDC hAttribDC,
BOOL fMetafile,
BOOL fEntire,
LPRECT pRect )
{
HDC hLocalAttribDC = NULL;
// If not inited, return.
if ( m_fViewInitialized ) {
if ( NULL == hAttribDC ) {
hLocalAttribDC = GetDC(m_hWnd);
} else {
hLocalAttribDC = hAttribDC;
}
// Make sure layout is up to date.
ApplyChanges( hLocalAttribDC );
if ( NULL != hDC && NULL != hLocalAttribDC ) {
if ( REPORT_GRAPH == m_pObj->m_Graph.Options.iDisplayType ) {
m_pReport->Render( hDC, hLocalAttribDC, fMetafile, fEntire, pRect );
} else {
// Fill with background color
SetBkColor(hDC, clrBackCtl());
ClearRect(hDC, pRect);
m_pStatsBar->Draw(hDC, hLocalAttribDC, pRect);
m_pGraphDisp->Draw(hDC, hLocalAttribDC, fMetafile, fEntire, pRect );
m_pLegend->Render(hDC, hLocalAttribDC, fMetafile, fEntire, pRect);
}
if ( eBorderSingle == m_iBorderStyle ) {
if ( eAppear3D == m_iAppearance ) {
DrawEdge(hDC, pRect, EDGE_RAISED, BF_RECT);
} else {
SelectBrush (hDC, GetStockObject (HOLLOW_BRUSH)) ;
SelectPen (hDC, GetStockObject (BLACK_PEN)) ;
Rectangle (hDC, pRect->left, pRect->top, pRect->right, pRect->bottom );
}
}
}
if ( NULL != hLocalAttribDC && hAttribDC != hLocalAttribDC ) {
ReleaseDC ( m_hWnd, hLocalAttribDC );
}
}
}
void CSysmonControl::SetIntervalTimer()
{
HDC hDC = NULL;
PGRAPHDATA pGraph = &m_pObj->m_Graph;
// if not initialized or counter source is a log file, nothing to do
if (!m_fInitialized || IsLogSource() || !IsUserMode() )
return;
// Update statistics bar
m_pStatsBar->SetTimeSpan(
m_pObj->m_Graph.Options.fUpdateInterval
* m_pObj->m_Graph.Options.iDisplayFilter
* m_pHistCtrl->nMaxSamples );
hDC = GetDC(m_hWnd);
if ( NULL != hDC ) {
m_pStatsBar->Update(hDC, m_pSelectedItem);
ReleaseDC(m_hWnd,hDC);
}
// If conditions right for sampling, start new time interval.
// Otherwise, suspend the collection.
if (!pGraph->Options.bManualUpdate
&& pGraph->Options.fUpdateInterval >= 0.001 // ??
&& pGraph->CounterTree.NumCounters() != 0
&& IsUserMode() ) {
m_CollectInfo.dwInterval= (DWORD)(pGraph->Options.fUpdateInterval * 1000);
m_CollectInfo.dwSampleTime = GetTickCount();
m_CollectInfo.iMode = COLLECT_ACTIVE;
}
else {
m_CollectInfo.iMode = COLLECT_SUSPEND;
}
assert ( NULL != m_CollectInfo.hEvent );
// Signal the collection thread
SetEvent(m_CollectInfo.hEvent);
// If no counters, reset sample time to start
if (pGraph->CounterTree.NumCounters() == 0) {
m_pHistCtrl->iCurrent = 0;
m_pHistCtrl->nSamples = 0;
pGraph->TimeStepper.Reset();
}
}
HRESULT CSysmonControl::AddSingleCounter(LPWSTR pszPath, PCGraphItem *pGItem)
{
PCGraphItem pGraphItem;
PGRAPHDATA pGraph = &m_pObj->m_Graph;
HRESULT hr;
BOOL bAddSuccessful = FALSE;
INT iCounterIndex = 0;
*pGItem = NULL;
// Create graph item
pGraphItem = new CGraphItem(this);
if (pGraphItem == NULL)
return E_OUTOFMEMORY;
LockCounterData();
// Add it to the counter tree
hr = pGraph->CounterTree.AddCounterItem(
pszPath,
pGraphItem,
pGraph->Options.bMonitorDuplicateInstances);
if (SUCCEEDED(hr)) {
// AddRef once for ourself
pGraphItem->AddRef();
// Set default attributes
pGraphItem->put_Color(IndexToStandardColor(m_iColorIndex));
pGraphItem->put_Width(IndexToWidth(m_iWidthIndex));
pGraphItem->put_LineStyle(IndexToStyle(m_iStyleIndex));
pGraphItem->put_ScaleFactor(m_iScaleFactor);
// Increment and reset for next counter
IncrementVisuals();
m_iScaleFactor = INT_MAX;
// Add item to graph's query
if ( NULL != m_hQuery ) {
hr = pGraphItem->AddToQuery(m_hQuery);
} else {
hr = E_FAIL;
}
if (SUCCEEDED(hr)) {
hr = pGraph->CounterTree.IndexFromCounter( pGraphItem, &iCounterIndex );
if ( SUCCEEDED ( hr ) ) {
bAddSuccessful = TRUE;
// If control is initialized
if (m_fViewInitialized) {
// Add item to chart legend
m_pLegend->AddItem(pGraphItem);
m_pReport->AddItem(pGraphItem);
}
}
else {
// remove the item from the tree
pGraphItem->Instance()->RemoveItem(pGraphItem);
}
} else {
// remove the item from the tree
pGraphItem->Instance()->RemoveItem(pGraphItem);
}
// If OK, Addref the returned interface
if (SUCCEEDED(hr)) {
pGraphItem->AddRef();
*pGItem = pGraphItem;
} // else released by RemoveItem above.
// Update messages seem to be combined, so histogram sometimes updates instead of
// repainting each entire bar. This forces total repaint.
if ( m_pGraphDisp) {
m_pGraphDisp->SetBarConfigChanged();
}
} else {
// AddCounterItem failed
delete pGraphItem;
}
UnlockCounterData();
// Send events outside of locks.
if ( bAddSuccessful ) {
// If first counter
if (pGraph->CounterTree.NumCounters() == 1) {
// Make it the selected counter and send event.
SelectCounter(pGraphItem);
// Start data collection
if ( ERROR_SUCCESS != ActivateQuery() ) {
hr = E_FAIL;
}
}
// Redraw the graph
UpdateGraph(UPDGRPH_ADDCNTR);
m_pObj->SendEvent(eEventOnCounterAdded, iCounterIndex );
}
return hr;
}
PCCounterTree
CSysmonControl::CounterTree(
VOID
)
{
return &(m_pObj->m_Graph.CounterTree);
}
PCGraphItem
CSysmonControl::FirstCounter(
VOID
)
{
return m_pObj->m_Graph.CounterTree.FirstCounter();
}
PCGraphItem
CSysmonControl::LastCounter(
VOID
)
{
PCGraphItem pItem;
PCGraphItem pItemNext;
if (FirstCounter() == NULL)
return NULL;
// Locate last graph item
pItem = FirstCounter();
while ((pItemNext = pItem->Next()) != NULL)
pItem = pItemNext;
return pItem;
}
BOOL
CSysmonControl::IsLogSource(
VOID
)
{
return m_pHistCtrl->bLogSource;
}
BOOL
CSysmonControl::IsReadOnly(
VOID
)
{
BOOL bReturn = TRUE;
if (m_fInitialized ) {
bReturn = m_pObj->m_Graph.Options.bReadOnly;
}
return bReturn;
}
eReportValueTypeConstant
CSysmonControl::ReportValueType(
VOID
)
{
return ( (eReportValueTypeConstant) m_pObj->m_Graph.Options.iReportValueType );
}
INT CSysmonControl::CounterIndex(PCGraphItem pItem)
{
PCGraphItem pItemLoc;
INT iIndex;
// Traverse linked list until item matched
pItemLoc = FirstCounter();
iIndex = 1;
while (pItemLoc != pItem && pItemLoc != NULL) {
pItemLoc = pItemLoc->Next();
iIndex++;
}
return (pItemLoc == NULL) ? -1 : iIndex;
}
HRESULT CSysmonControl::DeleteCounter(PCGraphItem pItem, BOOL bPropagateUp)
{
PGRAPHDATA pGraph = &m_pObj->m_Graph;
if (pItem == NULL)
return E_INVALIDARG;
// Send event
m_pObj->SendEvent(eEventOnCounterDeleted, CounterIndex(pItem));
LockCounterData();
// If this is the selected counter, change selection to NULL
if (pItem == m_pSelectedItem)
m_pSelectedItem = NULL;
if (m_fViewInitialized) {
// Remove from legend and report
m_pLegend->DeleteItem(pItem);
m_pReport->DeleteItem(pItem);
// Remove from query
pItem->RemoveFromQuery();
}
// Proagate deletion up the tree if requested
if (bPropagateUp) {
pItem->Instance()->RemoveItem(pItem);
}
// If last counter, stop interval timer
if (pGraph->CounterTree.NumCounters() == 0)
SetIntervalTimer();
// Update messages seem to be combined, so histogram sometimes updates instead of
// repainting each entire bar. This forces total repaint.
if ( m_pGraphDisp) {
m_pGraphDisp->SetBarConfigChanged();
}
UnlockCounterData();
if ( m_fViewInitialized ) {
UpdateGraph(UPDGRPH_DELCNTR);
}
return NOERROR;
}
void CSysmonControl::SelectCounter(PCGraphItem pItem)
{
HDC hDC = NULL;
INT iIndex;
// Selection in the graph view is maintained independently
// of the selection in the report view.
if ( REPORT_GRAPH != m_pObj->m_Graph.Options.iDisplayType ) {
// Save as current item
m_pSelectedItem = pItem;
if (m_fViewInitialized) {
// Inform Legend
m_pLegend->SelectItem(pItem);
// Highlight selected item in graph display
if (m_pObj->m_Graph.Options.bHighlight) {
m_pGraphDisp->HiliteItem(pItem);
UpdateGraph(UPDGRPH_PLOT);
}
// Update statistics bar
if ( m_fViewInitialized )
hDC = GetDC(m_hWnd);
m_pStatsBar->Update(hDC, pItem);
if ( NULL != hDC )
ReleaseDC(m_hWnd,hDC);
}
}
// Send event
iIndex = (pItem == NULL) ? 0 : CounterIndex(pItem);
m_pObj->SendEvent(eEventOnCounterSelected, iIndex);
}
HRESULT
CSysmonControl::PasteFromBuffer( LPWSTR pszData, BOOL bAllData )
{
HRESULT hr = NOERROR;
CImpIPropertyBag IPropBag;
hr = IPropBag.LoadData( pszData );
if ( SUCCEEDED ( hr ) ) {
INT nLogType = SMON_CTRL_LOG;
//get the log type from the pPropBag and compare it with service(cookie) type
//Determine log type from property bag. Default to -1 SMON_CTRL_LOG
hr = IntegerFromPropertyBag (
&IPropBag,
NULL,
CGlobalString::m_cszLogType,
nLogType);
if(nLogType == SLQ_TRACE_LOG){
MessageBox(
m_hWnd,
ResourceString(IDS_TRACE_LOG_ERR_MSG),
ResourceString(IDS_APP_NAME),
MB_OK
);
} else {
if ( bAllData ) {
hr = LoadFromPropertyBag( &IPropBag, NULL );
} else {
// Do not load sample data for Paste or Drop File.
hr = LoadCountersFromPropertyBag (&IPropBag, NULL, FALSE );
}
}
}
return hr;
}
HRESULT CSysmonControl::Paste()
{
HRESULT hResReturn = NOERROR;
HANDLE hMemClipboard;
// get the clipboard
if (OpenClipboard (Window())) {
// read the CF_TEXT or CF_UNICODE data from the clipboard to the local buffer
hMemClipboard = GetClipboardData (
#if UNICODE
CF_UNICODETEXT); // UNICODE text in the clipboard
#else
CF_TEXT); // ANSI text in the clipboard
#endif
if (hMemClipboard != NULL) {
LPWSTR pszData;
if ( ConfirmSampleDataOverwrite ( ) ) {
pszData = (LPWSTR)GlobalLock (hMemClipboard);// (LPWSTR)hMemClipboard;
if ( NULL != pszData ) {
hResReturn = PasteFromBuffer ( pszData, FALSE );
GlobalUnlock ( hMemClipboard );
}
}
}
// release the clipboard
CloseClipboard();
} else {
// unable to open the clipboard
hResReturn = HRESULT_FROM_WIN32(GetLastError());
}
return hResReturn;
}
HRESULT
CSysmonControl::CopyToBuffer ( LPWSTR& rpszData, DWORD& rdwBufferSize )
{
HRESULT hr = S_OK;
CImpIPropertyBag IPropBag;
assert ( NULL == rpszData );
rdwBufferSize = 0;
if (NULL!=m_pObj->m_pImpIPersistPropertyBag) {
hr = m_pObj->m_pImpIPersistPropertyBag->Save (&IPropBag, FALSE, TRUE );
}
if ( SUCCEEDED ( hr ) ) {
DWORD dwBufferLength;
LPWSTR pszConfig;
pszConfig = IPropBag.GetData();
if ( NULL != pszConfig ) {
//
// Buffer length includes 1 for NULL terminator.
//
dwBufferLength = lstrlen ( CGlobalString::m_cszHtmlObjectHeader ) + lstrlen ( CGlobalString::m_cszHtmlObjectFooter ) + lstrlen ( pszConfig ) + 1;
rpszData = new WCHAR[dwBufferLength];
if ( NULL == rpszData ) {
hr = E_OUTOFMEMORY;
} else {
rdwBufferSize = dwBufferLength * sizeof(WCHAR);
rpszData[0] = L'\0';
StringCchCopy(rpszData, dwBufferLength, CGlobalString::m_cszHtmlObjectHeader );
StringCchCat(rpszData, dwBufferLength, pszConfig );
StringCchCat(rpszData, dwBufferLength, CGlobalString::m_cszHtmlObjectFooter );
}
} else {
hr = E_UNEXPECTED;
}
}
return hr;
}
HRESULT CSysmonControl::Copy()
{
HGLOBAL hBuffer = NULL;
HRESULT hResReturn = S_OK;
LPWSTR pszBuffer = NULL;
DWORD dwBufferSize;
HANDLE hMemClipboard;
LPWSTR pszGlobalBuffer = NULL;
hResReturn = CopyToBuffer( pszBuffer, dwBufferSize);
if ( SUCCEEDED ( hResReturn ) && ( NULL != pszBuffer ) ) {
hBuffer = GlobalAlloc ((GMEM_MOVEABLE | GMEM_DDESHARE), dwBufferSize);
if ( NULL != hBuffer ) {
pszGlobalBuffer = (LPWSTR)GlobalLock (hBuffer);
if ( NULL != pszGlobalBuffer ) {
StringCchCopy (pszGlobalBuffer, dwBufferSize, pszBuffer );
GlobalUnlock (hBuffer);
} else {
// allocation or lock failed so bail out
hResReturn = E_OUTOFMEMORY;
}
}
}
if ( NULL != pszBuffer ) {
delete [] pszBuffer;
}
if ( NULL != hBuffer && SUCCEEDED ( hResReturn ) ) {
// then there's something to copy so...
// get the clipboard
if (OpenClipboard (m_hWnd)) {
// copy the counter list to the clipboard
if (EmptyClipboard()) {
hMemClipboard = SetClipboardData (
#if UNICODE
CF_UNICODETEXT, // UNICODE text in the clipboard
#else
CF_TEXT, // ANSI text in the clipboard
#endif
hBuffer);
if (hMemClipboard == NULL) {
// unable to set data in the clipboard
hResReturn = HRESULT_FROM_WIN32(GetLastError());
}
} else {
// unable to empty the clipboard
hResReturn = HRESULT_FROM_WIN32(GetLastError());
}
// release the clipboard
CloseClipboard();
} else {
// unable to open the clipboard
hResReturn = HRESULT_FROM_WIN32(GetLastError());
}
}
if ( NULL != hBuffer ) {
GlobalFree ( hBuffer ) ;
}
return hResReturn;
}
HRESULT CSysmonControl::Reset()
{
PCGraphItem pItem;
// Request each counter from the control, to compute
// required buffer size
while ((pItem = FirstCounter())!= NULL) {
// delete this counter
DeleteCounter (pItem, TRUE);
}
m_iColorIndex = 0;
m_iWidthIndex = 0;
m_iStyleIndex = 0;
return NOERROR;
}
void CSysmonControl::DblClickCounter(PCGraphItem pItem)
{
INT iIndex;
// Send event
iIndex = (pItem == NULL) ? 0 : CounterIndex(pItem);
m_pObj->SendEvent(eEventOnDblClick, iIndex);
}
BOOL
CSysmonControl::ConfirmSampleDataOverwrite ( )
{
BOOL bOverwrite = TRUE;
if ( m_bSampleDataLoaded ) {
// Confirm overwrite of view-only data.
INT iOverwrite = IDNO;
assert ( FALSE == m_fInitialized );
iOverwrite = MessageBox(
Window(),
ResourceString(IDS_SAMPLE_DATA_OVERWRITE),
ResourceString(IDS_APP_NAME),
MB_YESNO );
if ( IDYES == iOverwrite ) {
m_bSampleDataLoaded = FALSE;
bOverwrite = Init ( g_hWndFoster );
UpdateGraph(UPDGRPH_LAYOUT); // If toolbar enabled, must resize
// Also clears the graph
} else {
bOverwrite = FALSE;
}
}
return bOverwrite;
}
void
CSysmonControl::Clear ( void )
{
if ( ConfirmSampleDataOverwrite() ) {
PCGraphItem pItem;
m_pHistCtrl->nMaxSamples = MAX_GRAPH_SAMPLES;
m_pHistCtrl->iCurrent = 0;
m_pHistCtrl->nSamples = 0;
m_pHistCtrl->nBacklog = 0;
m_pObj->m_Graph.TimeStepper.Reset();
m_pStatsBar->Clear();
// Reset history for all counters
for (pItem = FirstCounter(); pItem != NULL; pItem = pItem->Next()) {
pItem->ClearHistory();
}
// Repaint the graph and value bar
UpdateGraph(UPDGRPH_VIEW);
}
}
PDH_STATUS
CSysmonControl::UpdateCounterValues ( BOOL fValidSample )
{
PDH_STATUS stat = ERROR_SUCCESS;
PCGraphItem pItem;
PGRAPHDATA pGraph = &m_pObj->m_Graph;
// If no query or no counters assign, nothing to do
if ( NULL == m_hQuery
|| pGraph->CounterTree.NumCounters() == 0
|| !IsUserMode() ) {
stat = ERROR_SUCCESS;
} else {
if ( ConfirmSampleDataOverwrite () ) {
// If valid sample, collect the data
if (fValidSample) {
UpdateAppPerfTimeData (TD_P_QUERY_TIME, TD_BEGIN);
stat = PdhCollectQueryData(m_hQuery);
UpdateAppPerfTimeData (TD_P_QUERY_TIME, TD_END);
}
if ( ERROR_SUCCESS == stat ) {
UpdateAppPerfTimeData (TD_S_QUERY_TIME, TD_BEGIN);
LockCounterData();
// Update history control and all counter history arrays
m_pHistCtrl->iCurrent++;
if (m_pHistCtrl->iCurrent == m_pHistCtrl->nMaxSamples)
m_pHistCtrl->iCurrent = 0;
if (m_pHistCtrl->nSamples < m_pHistCtrl->nMaxSamples)
m_pHistCtrl->nSamples++;
// Update history for all counters
for (pItem = FirstCounter(); pItem != NULL; pItem = pItem->Next()) {
pItem->UpdateHistory(fValidSample);
}
// If we're initialized and have at least two samples
if (m_fInitialized && m_pHistCtrl->nSamples >= 2) {
// If no backlogged updates, post an update message
// Ensure that OnSampleCollected event is triggered in any case.
if (m_pHistCtrl->nBacklog == 0) {
PostMessage(m_hWnd, WM_GRAPH_UPDATE, 0, 0);
} else {
PostMessage(m_hWnd, WM_VALUES_UPDATED, 0, 0);
}
m_pHistCtrl->nBacklog++;
}
UnlockCounterData();
UpdateAppPerfTimeData (TD_S_QUERY_TIME, TD_END);
}
}
}
return ERROR_SUCCESS;
}
void CSysmonControl::Activate( VOID )
{
if (!m_fUIDead) {
m_pObj->UIActivate();
}
}
void CSysmonControl::put_Appearance(INT iAppearance, BOOL fAmbient)
{
INT iLocalAppearance;
if (fAmbient && m_pObj->m_Graph.Options.iAppearance != NULL_APPEARANCE)
return;
if (!fAmbient) {
m_pObj->m_Graph.Options.iAppearance = iAppearance;
}
// Any non-zero value translates to 3D. In ambient case, the high bits are sometimes set.
if ( iAppearance ) {
iLocalAppearance = eAppear3D;
} else {
iLocalAppearance = eAppearFlat;
}
m_iAppearance = iLocalAppearance;
UpdateGraph(UPDGRPH_COLOR);
}
void CSysmonControl::put_BorderStyle(INT iBorderStyle, BOOL fAmbient)
{
if (fAmbient && m_pObj->m_Graph.Options.iBorderStyle != NULL_BORDERSTYLE)
return;
if (!fAmbient) {
m_pObj->m_Graph.Options.iBorderStyle = iBorderStyle;
}
m_iBorderStyle = iBorderStyle;
UpdateGraph(UPDGRPH_COLOR);
}
void CSysmonControl::put_BackCtlColor(OLE_COLOR Color)
{
m_pObj->m_Graph.Options.clrBackCtl = Color;
OleTranslateColor(Color, NULL, &m_clrBackCtl);
UpdateGraph(UPDGRPH_COLOR);
}
void CSysmonControl::put_FgndColor (
OLE_COLOR Color,
BOOL fAmbient
)
{
if (fAmbient && m_pObj->m_Graph.Options.clrFore != NULL_COLOR)
return;
if (!fAmbient)
m_pObj->m_Graph.Options.clrFore = Color;
OleTranslateColor(Color, NULL, &m_clrFgnd);
UpdateGraph(UPDGRPH_COLOR);
}
void CSysmonControl::put_BackPlotColor (
OLE_COLOR Color,
BOOL fAmbient
)
{
if (fAmbient && m_pObj->m_Graph.Options.clrBackPlot != NULL_COLOR)
return;
if (!fAmbient)
m_pObj->m_Graph.Options.clrBackPlot = Color;
OleTranslateColor(Color, NULL, &m_clrBackPlot);
UpdateGraph(UPDGRPH_PLOT);
}
void CSysmonControl::put_GridColor (
OLE_COLOR Color
)
{
// Options color is the OLE_COLOR.
// Color in control is translated from OLE_COLOR.
m_pObj->m_Graph.Options.clrGrid = Color;
OleTranslateColor(Color, NULL, &m_clrGrid);
UpdateGraph(UPDGRPH_PLOT);
}
void CSysmonControl::put_TimeBarColor (
OLE_COLOR Color
)
{
// Options color is the OLE_COLOR.
// Color in control is translated from OLE_COLOR.
m_pObj->m_Graph.Options.clrTimeBar = Color;
OleTranslateColor(Color, NULL, &m_clrTimeBar);
UpdateGraph(UPDGRPH_PLOT);
}
HRESULT CSysmonControl::put_Font (
LPFONT pIFont,
BOOL fAmbient
)
{
HRESULT hr = NOERROR;
if ( NULL == pIFont ) {
hr = E_INVALIDARG;
} else {
if ( fAmbient && FALSE == m_pObj->m_Graph.Options.bAmbientFont ) {
hr = NOERROR;
} else {
if (!fAmbient) {
m_pObj->m_Graph.Options.bAmbientFont = FALSE;
}
hr = m_OleFont.SetIFont(pIFont);
}
}
return hr;
}
void CSysmonControl::FontChanged(
void
)
{
m_pReport->ChangeFont();
UpdateGraph(UPDGRPH_FONT);
}
DWORD WINAPI
CollectProc (
IN PSYSMONCTRL pCtrl
)
{
DWORD dwElapsedTime;
DWORD dwTimeout = INFINITE;
COLLECT_PROC_INFO *pCollectInfo = &pCtrl->m_CollectInfo;
while (TRUE) {
// Wait for event or next sample period
WaitForSingleObject(pCollectInfo->hEvent, dwTimeout);
// If quit request, exit loop
if (pCollectInfo->iMode == COLLECT_QUIT)
break;
// If suspended, wait for an event
if (pCollectInfo->iMode == COLLECT_SUSPEND) {
dwTimeout = INFINITE;
continue;
}
// Take a sample
pCtrl->UpdateCounterValues(TRUE);
// Get elapsed time from last sample time
dwElapsedTime = GetTickCount() - pCollectInfo->dwSampleTime;
if (dwElapsedTime > 100000)
dwElapsedTime = 0;
// Have we missed any sample times?
while (dwElapsedTime > pCollectInfo->dwInterval) {
// By how much?
dwElapsedTime -= pCollectInfo->dwInterval;
// If less than 1/2 an interval, take the sample now
// otherwise record a missed one
if (dwElapsedTime < pCollectInfo->dwInterval/2) {
pCtrl->UpdateCounterValues(TRUE);
} else {
pCtrl->UpdateCounterValues(FALSE);
}
// Advance to next sample time
pCollectInfo->dwSampleTime += pCollectInfo->dwInterval;
}
// Set timeout to wait until next sample time
dwTimeout = pCollectInfo->dwInterval - dwElapsedTime;
pCollectInfo->dwSampleTime += pCollectInfo->dwInterval;
}
return 0;
}
HRESULT
CSysmonControl::InitLogFileIntervals ( void )
{
HRESULT hr = S_OK;
PDH_STATUS pdhstat;
DWORD nLogEntries = 0;
DWORD nBufSize;
PDH_TIME_INFO TimeInfo;
if ( m_bLogFileSource ) {
// Get time and sample count info
nBufSize = sizeof(TimeInfo);
pdhstat = PdhGetDataSourceTimeRangeH(GetDataSourceHandle(),
& nLogEntries,
& TimeInfo,
& nBufSize );
if ( ERROR_SUCCESS != pdhstat ) {
if ( ERROR_NOT_ENOUGH_MEMORY == pdhstat ) {
pdhstat = SMON_STATUS_LOG_FILE_SIZE_LIMIT;
}
hr = (HRESULT)pdhstat;
} else if ( 2 > TimeInfo.SampleCount ) {
hr = (HRESULT)SMON_STATUS_TOO_FEW_SAMPLES;
m_DataSourceInfo.llInterval = 1;
} else {
// Setup time range info
m_DataSourceInfo.llBeginTime = TimeInfo.StartTime;
m_DataSourceInfo.llEndTime = TimeInfo.EndTime;
// The start or stop time might no longer be valid, so check for
// relationship between the them as well as for start/begin, stop/end.
if ( (m_DataSourceInfo.llStartDisp < m_DataSourceInfo.llBeginTime)
|| (m_DataSourceInfo.llStartDisp > m_DataSourceInfo.llEndTime) )
m_DataSourceInfo.llStartDisp = m_DataSourceInfo.llBeginTime;
if ( (m_DataSourceInfo.llStopDisp > m_DataSourceInfo.llEndTime)
|| (m_DataSourceInfo.llStopDisp < m_DataSourceInfo.llStartDisp) )
m_DataSourceInfo.llStopDisp = m_DataSourceInfo.llEndTime;
m_DataSourceInfo.nSamples = TimeInfo.SampleCount;
m_DataSourceInfo.llInterval = (m_DataSourceInfo.llEndTime - m_DataSourceInfo.llBeginTime + m_DataSourceInfo.nSamples/2) / (m_DataSourceInfo.nSamples - 1);
UpdateGraph(UPDGRPH_LOGVIEW);
}
} else {
assert ( FALSE );
hr = E_FAIL;
}
return hr;
}
HRESULT
CSysmonControl::AddSingleLogFile(
LPCWSTR pszPath,
CLogFileItem** ppLogFile )
{
HRESULT hr = NOERROR;
CLogFileItem* pLogFile = NULL;
CLogFileItem* pLocalLogFileItem = NULL;
if ( NULL != pszPath ) {
//
// Check whether the file name is too long
//
if (lstrlen(pszPath) > MAX_PATH) {
return E_INVALIDARG;
}
if ( NULL != ppLogFile ) {
*ppLogFile = NULL;
}
// Check to ensure that current data source is NOT log files.
if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType ) {
hr = SMON_STATUS_LOG_FILE_DATA_SOURCE;
} else {
// Check for duplicate log file name.
pLogFile = FirstLogFile();
while ( NULL != pLogFile ) {
if ( 0 == lstrcmpi ( pszPath, pLogFile->GetPath() ) ) {
hr = SMON_STATUS_DUPL_LOG_FILE_PATH;
break;
}
pLogFile = pLogFile->Next();
}
if (SUCCEEDED(hr)) {
// Create log file item
pLocalLogFileItem = new CLogFileItem ( this );
if ( NULL == pLocalLogFileItem ) {
hr = E_OUTOFMEMORY;
} else {
hr = pLocalLogFileItem->Initialize ( pszPath, &m_DataSourceInfo.pFirstLogFile );
}
// TodoLogFiles: ??? Test log file type? Or leave that up to the "SetDataSource" time?
// TodoLogFiles: Add log file type to the data source info structure
// TodoLogFiles: If allow the user to add files while data source set to log files,
// then check that condition here. If log file data source, then resample with
// new log file.
// If OK, Addref the returned interface
if (SUCCEEDED(hr)) {
// AddRef once for ourselves
pLocalLogFileItem->AddRef();
m_DataSourceInfo.lLogFileCount++;
if ( NULL != ppLogFile ) {
// AddRef the returned interface
pLocalLogFileItem->AddRef();
*ppLogFile = pLocalLogFileItem;
}
}
else {
if (pLocalLogFileItem != NULL) {
delete pLocalLogFileItem;
pLocalLogFileItem = NULL;
}
}
}
}
} else {
hr = E_INVALIDARG;
}
return hr;
}
HRESULT
CSysmonControl::RemoveSingleLogFile (
CLogFileItem* pLogFile )
{
HRESULT hr = ERROR_SUCCESS;
CLogFileItem* pNext;
CLogFileItem* pPrevious;
// Check to ensure that current data source is NOT log files.
if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType ) {
hr = SMON_STATUS_LOG_FILE_DATA_SOURCE;
} else {
pNext = FirstLogFile();
if ( pNext == pLogFile ) {
m_DataSourceInfo.pFirstLogFile = pNext->Next();
} else {
do {
pPrevious = pNext;
pNext = pNext->Next();
if ( pNext == pLogFile ) {
break;
}
} while ( NULL != pNext );
if ( NULL != pNext ) {
pPrevious->SetNext ( pNext->Next() );
} else {
// Something is wrong with the list.
assert ( FALSE );
hr = E_FAIL;
}
}
m_DataSourceInfo.lLogFileCount--;
pLogFile->Release();
}
return hr;
}
HRESULT
CSysmonControl::ProcessDataSourceType (
LPCWSTR szDataSourceName,
INT iDataSourceType )
{
HRESULT hr = NOERROR;
HQUERY hTestQuery = NULL;
PDH_STATUS pdhStatus = ERROR_SUCCESS;
HLOG hTestLog = H_REALTIME_DATASOURCE;
if ( sysmonNullDataSource != iDataSourceType ) {
// Open the new query
if (iDataSourceType == sysmonLogFiles ||
iDataSourceType == sysmonSqlLog) {
pdhStatus = PdhBindInputDataSource(& hTestLog, szDataSourceName);
}
else if (iDataSourceType == sysmonCurrentActivity) {
m_DataSourceInfo.hDataSource = H_REALTIME_DATASOURCE;
}
else {
pdhStatus = PDH_INVALID_HANDLE;
}
if (pdhStatus == ERROR_SUCCESS) {
pdhStatus = PdhOpenQueryH (hTestLog, 1, & hTestQuery );
}
}
if ( ERROR_SUCCESS != pdhStatus ) {
if ( ERROR_NOT_ENOUGH_MEMORY == pdhStatus ) {
hr = (HRESULT)SMON_STATUS_LOG_FILE_SIZE_LIMIT;
} else {
hr = (HRESULT)pdhStatus;
}
} else {
// Close the current query
CloseQuery();
// At this point, the previous query no longer exists.
// If any problems with the new query, close it and
// reset the data source to realtime.
// Set the data source type
// The previous log file name is deleted in CloseQuery()
// For sysmonNullDataSource, the current query is closed,
// and the query handle is set to NULL.
m_pObj->m_Graph.Options.iDataSourceType = iDataSourceType;
// TodoLogFiles: Eliminate use of m_bLogFileSource,
// using m_pObj->m_Graph.Options.iDataSourceType instead.
m_bLogFileSource = ( sysmonLogFiles == iDataSourceType
|| sysmonSqlLog == iDataSourceType);
m_hQuery = hTestQuery;
m_DataSourceInfo.hDataSource = hTestLog;
if ( m_bLogFileSource ) {
hr = InitLogFileIntervals();
}
if ( SUCCEEDED ( hr ) && sysmonNullDataSource != iDataSourceType ) {
// Initialize the new query. For log files, this can be done after
// InitLogFileIntervals because the methods operate on different fields.
if ( ERROR_SUCCESS != InitializeQuery() ) {
hr = E_FAIL;
} else {
if ( m_fInitialized ) {
if ( ERROR_SUCCESS != ActivateQuery() )
hr = E_FAIL;
}
}
if ( SUCCEEDED ( hr ) && !m_bLogFileSource ) {
// If note log file data source, pass new time span to statistics bar.
m_pStatsBar->SetTimeSpan (
m_pObj->m_Graph.Options.fUpdateInterval
* m_pObj->m_Graph.Options.iDisplayFilter
* m_pHistCtrl->nMaxSamples);
}
}
}
if ( FAILED ( hr ) ) {
if ( sysmonLogFiles == iDataSourceType
|| sysmonSqlLog == iDataSourceType )
{
// If failed with log file query, retry with realtime query.
assert ( m_bLogFileSource );
// Status returned is for the original query, not the realtime query.
// TodoLogFiles: Need to activate query?
put_DataSourceType ( sysmonCurrentActivity );
} else {
// This leaves the control in an odd state with no active query.
// TodoLogFiles: At least message to user
CloseQuery();
put_DataSourceType ( sysmonNullDataSource );
}
}
return hr;
}
HRESULT
CSysmonControl::get_DataSourceType (
eDataSourceTypeConstant& reDataSourceType )
{
HRESULT hr = NOERROR;
reDataSourceType = (eDataSourceTypeConstant)m_pObj->m_Graph.Options.iDataSourceType;
return hr;
}
HRESULT
CSysmonControl::put_DataSourceType (
INT iDataSourceType )
{
HRESULT hr = NOERROR;
DWORD dwStatus = ERROR_SUCCESS;
LPWSTR szDataSourceName = NULL;
// TodoLogFiles: Implement multi-file.
// TodoLogFiles: Use single data source name?
//
if (sysmonLogFiles == iDataSourceType) {
CLogFileItem * pLogFile = FirstLogFile();
ULONG ulListLen = 0;
if (pLogFile == NULL) {
hr = E_INVALIDARG;
}
else {
dwStatus = BuildLogFileList ( NULL, FALSE, &ulListLen );
szDataSourceName = (LPWSTR) malloc(ulListLen * sizeof(WCHAR));
if ( NULL != szDataSourceName ) {
dwStatus = BuildLogFileList ( szDataSourceName, FALSE, &ulListLen );
} else {
hr = E_OUTOFMEMORY;
}
}
}
else if (sysmonSqlLog == iDataSourceType) {
if ( m_DataSourceInfo.szSqlDsnName && m_DataSourceInfo.szSqlLogSetName ) {
if ( m_DataSourceInfo.szSqlDsnName[0] != _T('\0') && m_DataSourceInfo.szSqlLogSetName[0] != _T('\0')) {
ULONG ulLogFileNameLen = 0;
dwStatus = FormatSqlDataSourceName (
m_DataSourceInfo.szSqlDsnName,
m_DataSourceInfo.szSqlLogSetName,
NULL,
&ulLogFileNameLen );
if ( ERROR_SUCCESS == dwStatus ) {
szDataSourceName = (LPWSTR) malloc(ulLogFileNameLen * sizeof(WCHAR));
if (szDataSourceName == NULL) {
hr = E_OUTOFMEMORY;
} else {
dwStatus = FormatSqlDataSourceName (
m_DataSourceInfo.szSqlDsnName,
m_DataSourceInfo.szSqlLogSetName,
szDataSourceName,
&ulLogFileNameLen );
}
}
}
}
else {
hr = E_INVALIDARG;
}
}
if (SUCCEEDED(hr)) {
hr = ProcessDataSourceType((LPCWSTR) szDataSourceName, iDataSourceType);
}
if (szDataSourceName) {
free(szDataSourceName);
}
return hr;
}
void
CSysmonControl::IncrementVisuals (
void
)
{
// Increment the visual indices in color, width, style order
if (++m_iColorIndex >= NumStandardColorIndices()) {
m_iColorIndex = 0;
if (++m_iWidthIndex >= NumWidthIndices()) {
m_iWidthIndex = 0;
if (++m_iStyleIndex < NumStyleIndices()) {
m_iStyleIndex = 0;
}
}
}
}
void
CSysmonControl::SampleLogFile (
BOOL bViewChange
)
{
typedef struct {
PCGraphItem pItem;
double dMin;
double dMax;
double dAvg;
INT nAvgCnt;
BOOL bFirstSample;
PDH_RAW_COUNTER rawValue[1];
} LogWorkBuf, *PLogWorkBuf;
INT nCounters;
INT nLogSamples;
INT nDispSamples;
INT iNonDisp;
INT iFinalValidSample = 0;
PCGraphItem pItem;
#define LLTIME_TICS_PER_SECOND (10000000)
if ( NULL != m_hQuery ) {
// Determine number of counters to update
nCounters = 0;
// If log view change, we have to update all counters
if (bViewChange) {
for (pItem = FirstCounter(); pItem; pItem = pItem->Next()) {
pItem->m_bUpdateLog = TRUE;
nCounters++;
}
}
// otherwise, just any new counters
else {
for (pItem = FirstCounter(); pItem; pItem = pItem->Next()) {
if (pItem->m_bUpdateLog)
nCounters++;
}
}
// If none, nothing to do
if ( nCounters > 0) {
// Number of log samples in displayed interval
// Add 1 extra at the beginning. PdhSetQueryTimeRange returns one sample
// before the specified start time, if it exists.
// Add extra 1 because ?
if (m_DataSourceInfo.nSamples > 1) {
assert ( 0 != m_DataSourceInfo.llInterval );
nLogSamples = (INT)((m_DataSourceInfo.llStopDisp - m_DataSourceInfo.llStartDisp) / m_DataSourceInfo.llInterval) + 2;
} else {
nLogSamples = m_DataSourceInfo.nSamples;
}
// Number of display samples
nDispSamples = min(nLogSamples, m_pHistCtrl->nMaxSamples);
// Setup history control
m_pHistCtrl->nSamples = nDispSamples;
m_pHistCtrl->iCurrent = 0;
m_pHistCtrl->nBacklog = 0;
if ( nDispSamples > 1 ) {
INT nCompSamples;
INT nPasses = 0;
INT iComp;
INT iCtr;
INT iDisp;
DOUBLE dSamplesPerInterval = 0.0;
INT iTotalSamplesProcessed = 0;
DOUBLE dTotalSamplesCalc = 0;
BOOL bRemainder;
PLogWorkBuf pWorkBuffers;
PLogWorkBuf pWorkBuf;
INT nWorkBufSize;
PDH_TIME_INFO TimeInfo;
PDH_STATISTICS Statistics;
DWORD dwCtrType;
PDH_STATUS stat;
// Number of log samples to compress to one display values
// Add an extra 1 for rate counters becuase it takes 2 raw sample to get one formatted value.
// The first sample of each buffer is ignored for non-rate counters.
//
// If nLogsamples / nDispSamples has a remainder, then an extra 1 is needed because some
// intervals will include one more sample to make the total come out even at the end
// (e.g. 10 samples divided among 3 intervals = (3, 4, 3))
//
nCompSamples = (nLogSamples + m_pHistCtrl->nMaxSamples - 1) / m_pHistCtrl->nMaxSamples;
nCompSamples += 1;
// Length of one work buffer
nWorkBufSize = sizeof(LogWorkBuf) + (( nCompSamples ) * sizeof(PDH_RAW_COUNTER));
// Allocate work buffers of nCompSamples samples for each counter
pWorkBuffers = (PLogWorkBuf)malloc( nCounters * nWorkBufSize);
if (pWorkBuffers == NULL)
return;
// Place selected counter item pointers in work buffers
// and init statistics
pWorkBuf = pWorkBuffers;
for (pItem = FirstCounter(); pItem; pItem = pItem->Next()) {
if (pItem->m_bUpdateLog) {
pWorkBuf->pItem = pItem;
pWorkBuf->dMin = (double)10e8;
pWorkBuf->dMax = (double)-10e8;
pWorkBuf->dAvg = 0.0;
pWorkBuf->nAvgCnt = 0;
pWorkBuf->bFirstSample = TRUE;
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
}
// Set time range for pdh
TimeInfo.StartTime = m_DataSourceInfo.llStartDisp;
TimeInfo.EndTime = m_DataSourceInfo.llStopDisp;
PdhSetQueryTimeRange(m_hQuery, &TimeInfo);
bRemainder = ( 0 < ( nLogSamples % nDispSamples ) );
if ( bRemainder ) {
// Initialize the differential calc variables
dSamplesPerInterval = (double)nLogSamples / (double)nDispSamples;
iTotalSamplesProcessed = 0;
dTotalSamplesCalc = 0;
} else {
nPasses = nCompSamples;
}
for (iDisp = 0; iDisp<nDispSamples; iDisp++) {
if ( bRemainder ) {
// Do the differential calc to see if it's time for an extra sample
dTotalSamplesCalc += dSamplesPerInterval;
nPasses = (int)(dTotalSamplesCalc - iTotalSamplesProcessed);
iTotalSamplesProcessed += nPasses;
// Add 1 to nPasses because the first buffer is blank or from the previous interval.
nPasses ++;
}
// Fill the work buffers with a set of samples
// Set bad status for sample zero first time through.
// Sample zero is only used for rate counters.
// Other passes will reuse last sample of previous pass.
iComp = 0;
if ( 0 == iDisp ) {
// Special handling for the first sample.
// Set bad status for each
pWorkBuf = pWorkBuffers;
for (iCtr=0; iCtr < nCounters; iCtr++) {
pWorkBuf->rawValue[0].CStatus = PDH_CSTATUS_INVALID_DATA;
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
// If iDisp == 0, Query the data and check the timestamp for the first raw data value.
// If that timestamp is before the official Start time, store it in buffer 0
// Otherwise, put that data in buffer 1 and skip the first sample collection of the
// regular loop below.
stat = PdhCollectQueryData(m_hQuery);
if (stat == 0) {
PDH_RAW_COUNTER rawSingleValue;
// Get a raw sample for each counter. Check the timestamp of the first counter to
// determine which buffer to use.
pWorkBuf = pWorkBuffers;
iCtr = 0;
PdhGetRawCounterValue(pWorkBuf->pItem->Handle(), &dwCtrType, &rawSingleValue);
// Increment the buffer index to 1 if the time stamp is after Start time.
// Otherwise, write the data to buffer 0, which is only used to process rate counters.
if ( *((LONGLONG*)&rawSingleValue.TimeStamp) >= m_DataSourceInfo.llStartDisp ) {
iComp = 1;
}
pWorkBuf->rawValue[iComp] = rawSingleValue;
// Increment to the next counter, and continue normal processing for the first sample,
// using iComp buffer index.
iCtr++;
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
for ( ; iCtr < nCounters; iCtr++) {
PdhGetRawCounterValue(pWorkBuf->pItem->Handle(), &dwCtrType, &pWorkBuf->rawValue[iComp]);
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
} // else bad status already set in 0 buffer for each counter.
}
// Only rate counter values use work buffer 0
// Buffer 0 is set to value from previous sample, except when iDisp 0, in which case it might have
// been filled in the (if 0 == iDisp) clause above.
// Skip past any special handling for the first iDisp pass above. If buffer 1 is not filled by that
// special handling, then iComp is set to 1.
iComp++;
for ( ; iComp < nPasses; iComp++) {
stat = PdhCollectQueryData(m_hQuery);
if (stat == 0) {
// Get a raw sample for each counter
pWorkBuf = pWorkBuffers;
for (iCtr = 0; iCtr < nCounters; iCtr++) {
PdhGetRawCounterValue(pWorkBuf->pItem->Handle(), &dwCtrType, &pWorkBuf->rawValue[iComp]);
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
}
else {
// Set bad status for each
pWorkBuf = pWorkBuffers;
for (iCtr=0; iCtr < nCounters; iCtr++) {
pWorkBuf->rawValue[iComp].CStatus = PDH_CSTATUS_INVALID_DATA;
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
}
}
// generate one display sample by averaging each compression buffer
pWorkBuf = pWorkBuffers;
for (iCtr=0; iCtr < nCounters; iCtr++) {
INT iPassesThisCounter;
INT iWorkBufIndex;
if ( pWorkBuf->pItem->CalcRequiresMultipleSamples() ) {
iPassesThisCounter = nPasses;
iWorkBufIndex = 0;
} else {
// Non-rate counters do not use the first sample buffer.
iPassesThisCounter = nPasses - 1;
iWorkBufIndex = 1;
}
stat = PdhComputeCounterStatistics (pWorkBuf->pItem->Handle(), PDH_FMT_DOUBLE | PDH_FMT_NOCAP100,
0, iPassesThisCounter, &pWorkBuf->rawValue[iWorkBufIndex], &Statistics );
if (stat == 0 && Statistics.mean.CStatus == PDH_CSTATUS_VALID_DATA) {
LONGLONG llTruncatedTimeStamp = 0;
LONGLONG llTmpTimeStamp = 0;
pWorkBuf->pItem->SetLogEntry(iDisp, Statistics.min.doubleValue,
Statistics.max.doubleValue,
Statistics.mean.doubleValue);
// Use the final sample timestamp. It is valid for both rates and numbers.
llTmpTimeStamp = MAKELONGLONG(
pWorkBuf->rawValue[nPasses - 1].TimeStamp.dwLowDateTime,
pWorkBuf->rawValue[nPasses - 1].TimeStamp.dwHighDateTime);
TruncateLLTime(llTmpTimeStamp, & llTruncatedTimeStamp);
pWorkBuf->pItem->SetLogEntryTimeStamp ( iDisp, *((FILETIME*)&llTruncatedTimeStamp) );
//
// Set the minimum and maximum values correctly the first time through.
//
if ( pWorkBuf->bFirstSample ) {
pWorkBuf->dMin = Statistics.min.doubleValue;
pWorkBuf->dMax = Statistics.max.doubleValue;
pWorkBuf->bFirstSample = FALSE;
} else {
if (Statistics.min.doubleValue < pWorkBuf->dMin) {
pWorkBuf->dMin = Statistics.min.doubleValue;
}
if (Statistics.max.doubleValue > pWorkBuf->dMax) {
pWorkBuf->dMax = Statistics.max.doubleValue;
}
}
pWorkBuf->dAvg += Statistics.mean.doubleValue;
pWorkBuf->nAvgCnt++;
iFinalValidSample = iDisp;
}
else {
pWorkBuf->pItem->SetLogEntry(iDisp, -1.0, -1.0, -1.0);
}
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
// If a rate counter, move last sample to first sample
// for next compress interval
pWorkBuf = pWorkBuffers;
for (iCtr=0; iCtr < nCounters; iCtr++) {
if ( pWorkBuf->pItem->CalcRequiresMultipleSamples() ) {
pWorkBuf->rawValue[0] = pWorkBuf->rawValue[nPasses-1];
}
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
}
// Reset the history control to point to the last valid sample.
m_pHistCtrl->nSamples = iFinalValidSample;
// Set the log statistics for empty samples.
for (iNonDisp = nDispSamples; iNonDisp<m_pHistCtrl->nMaxSamples; iNonDisp++) {
pWorkBuf = pWorkBuffers;
for (iCtr=0; iCtr < nCounters; iCtr++) {
pWorkBuf->pItem->SetLogEntry(iNonDisp, -1.0, -1.0, -1.0);
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
}
// Store the final statistics and clear the update flags
pWorkBuf = pWorkBuffers;
for (iCtr=0; iCtr < nCounters; iCtr++) {
pWorkBuf->pItem->m_bUpdateLog = FALSE;
if (pWorkBuf->nAvgCnt) {
pWorkBuf->dAvg /= pWorkBuf->nAvgCnt;
pWorkBuf->pItem->SetLogStats(pWorkBuf->dMin, pWorkBuf->dMax, pWorkBuf->dAvg, PDH_CSTATUS_VALID_DATA);
}
pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
}
// Free the work buffers
free(pWorkBuffers);
} else {
// No data to display. Clear the history buffers by setting all status to Invalid.
for (pItem = FirstCounter(); pItem; pItem = pItem->Next()) {
for (iNonDisp = 0; iNonDisp < m_pHistCtrl->nMaxSamples; iNonDisp++) {
pItem->SetLogEntry(iNonDisp, -1.0, -1.0, -1.0);
}
}
}
// Update statistics bar
m_pStatsBar->SetTimeSpan((double)(m_DataSourceInfo.llStopDisp - m_DataSourceInfo.llStartDisp) / LLTIME_TICS_PER_SECOND);
m_pStatsBar->Update(NULL, m_pSelectedItem);
}
}
}
void
CSysmonControl::CalcZoomFactor ( void )
{
RECT rectPos;
RECT rectExtent;
double dHeightPos;
double dHeightExtent;
// Calculate zoom factor based on height.
// The Zoom calculation is prcPos (set by container) divided by the extent.
// See technical note 40 - TN040.
rectExtent = m_pObj->m_RectExt;
GetClientRect ( m_hWnd, &rectPos );
dHeightPos = rectPos.bottom - rectPos.top;
dHeightExtent = rectExtent.bottom - rectExtent.top;
m_dZoomFactor = ( dHeightPos ) / ( dHeightExtent );
}
void
CSysmonControl::ResetLogViewTempTimeRange ()
/*++
Routine Description:
Reset the log view temporary time range steppers to the ends of the visible
part of the log file.
Arguments:
Return Value:
--*/
{
assert ( IsLogSource() );
if ( IsLogSource() ) {
INT iNewStopStepNum = 0;
m_pObj->m_Graph.LogViewStartStepper.Reset();
m_pObj->m_Graph.LogViewStopStepper.Reset();
if ( FirstCounter() ) {
GetNewLogViewStepNum( m_DataSourceInfo.llStopDisp, iNewStopStepNum );
m_pObj->m_Graph.LogViewStopStepper.StepTo( iNewStopStepNum );
}
}
}
void
CSysmonControl::FindNextValidStepNum (
BOOL bDecrease,
PCGraphItem pItem,
LONGLONG llNewTime,
INT& riNewStepNum,
DWORD& rdwStatus )
{
DWORD dwPdhStatus = ERROR_SUCCESS;
DWORD dwLocalStatus = ERROR_SUCCESS;
LONGLONG llNextTimeStamp = 0;
INT iLocalStepNum;
INT iTempLocalStepNum;
assert ( NULL != pItem );
if ( NULL != pItem ) {
iLocalStepNum = riNewStepNum;
iTempLocalStepNum = iLocalStepNum;
dwLocalStatus = rdwStatus;
if ( bDecrease ) {
// Start by decreasing steps to find first valid step.
while ( ( ERROR_SUCCESS == dwPdhStatus )
&& ( ERROR_SUCCESS != dwLocalStatus )
&& ( iLocalStepNum > 0 ) ) {
iTempLocalStepNum = iLocalStepNum;
iTempLocalStepNum--;
dwPdhStatus = pItem->GetLogEntryTimeStamp( iTempLocalStepNum, llNextTimeStamp, &dwLocalStatus );
iLocalStepNum = iTempLocalStepNum;
}
// Subtract 1 from nSamples because stepper is 0-based,
while ( ( ERROR_SUCCESS == dwPdhStatus )
&& ( ERROR_SUCCESS != dwLocalStatus )
&& ( iLocalStepNum < m_pHistCtrl->nSamples - 1 ) ) {
iTempLocalStepNum++;
dwPdhStatus = pItem->GetLogEntryTimeStamp( iTempLocalStepNum, llNextTimeStamp, &dwLocalStatus );
iLocalStepNum = iTempLocalStepNum;
}
} else {
// Start by increasing steps to find first valid step.
// Subtract 1 from nSamples because stepper is 0-based,
while ( ( ERROR_SUCCESS == dwPdhStatus )
&& ( ERROR_SUCCESS != dwLocalStatus )
&& ( iLocalStepNum < m_pHistCtrl->nSamples - 1 ) ) {
iTempLocalStepNum++;
dwPdhStatus = pItem->GetLogEntryTimeStamp( iTempLocalStepNum, llNextTimeStamp, &dwLocalStatus );
iLocalStepNum = iTempLocalStepNum;
}
while ( ( ERROR_SUCCESS == dwPdhStatus )
&& ( ERROR_SUCCESS != dwLocalStatus )
&& ( iLocalStepNum > 0 ) ) {
iTempLocalStepNum = iLocalStepNum;
iTempLocalStepNum--;
dwPdhStatus = pItem->GetLogEntryTimeStamp( iTempLocalStepNum, llNextTimeStamp, &dwLocalStatus );
iLocalStepNum = iTempLocalStepNum;
}
}
if ( ERROR_SUCCESS == dwLocalStatus ) {
riNewStepNum = iLocalStepNum;
llNewTime = llNextTimeStamp;
rdwStatus = dwLocalStatus;
}
}
return;
}
void
CSysmonControl::GetNewLogViewStepNum (
LONGLONG llNewTime,
INT& riNewStepNum )
/*++
Routine Description:
Given the new time and original stepnum, find the stepnum that matches
the new time.
Arguments:
llNewTime New time stamp to match
riNewStepNum (IN) Current step num
(OUT) Step num that matches the new time stamp.
Return Value:
--*/
{
PCGraphItem pItem = NULL;
LONGLONG llNextTimeStamp = 0;
PDH_STATUS dwPdhStatus = ERROR_SUCCESS;
DWORD dwStatus = ERROR_SUCCESS;
INT iLocalStepNum = 0;
assert ( IsLogSource() );
iLocalStepNum = riNewStepNum;
// Check only the first counter for log file time stamp data.
pItem = FirstCounter();
if ( NULL != pItem ) {
dwPdhStatus = pItem->GetLogEntryTimeStamp( iLocalStepNum, llNextTimeStamp, &dwStatus );
// If the stepper is positioned on a sample with bad status,
// move n steps in either direction to find a valid sample to start with.
if ( ( ERROR_SUCCESS == dwPdhStatus ) && ( ERROR_SUCCESS != dwStatus ) ) {
FindNextValidStepNum ( FALSE, pItem, llNextTimeStamp, iLocalStepNum, dwStatus );
}
if ( ERROR_SUCCESS == dwStatus ) {
if ( ( llNewTime < llNextTimeStamp ) || ( MAX_TIME_VALUE == llNextTimeStamp ) ) {
while ( iLocalStepNum > 0 ) {
iLocalStepNum--;
pItem->GetLogEntryTimeStamp( iLocalStepNum, llNextTimeStamp, &dwStatus );
if ( ERROR_SUCCESS == dwStatus ) {
if ( llNewTime == llNextTimeStamp ) {
break;
} else if ( llNewTime > llNextTimeStamp ) {
iLocalStepNum++;
break;
}
}
}
} else if ( llNewTime > llNextTimeStamp ) {
// Subtract 1 from nSamples because stepper is 0-based,
while ( iLocalStepNum < m_pHistCtrl->nSamples - 1 ) {
iLocalStepNum++;
pItem->GetLogEntryTimeStamp( iLocalStepNum, llNextTimeStamp, &dwStatus );
if ( ERROR_SUCCESS == dwStatus ) {
if ( llNewTime <= llNextTimeStamp ) {
break;
}
}
}
}
riNewStepNum = iLocalStepNum;
} // else if NO valid samples, leave the start/stop time stepper where it is.
} // Non-null FirstCounter()
return;
}
void
CSysmonControl::SetLogViewTempTimeRange (
LONGLONG llStart,
LONGLONG llStop
)
/*++
Routine Description:
Set the log view temporary time range. This routine provides the Source
property page a way to give range to the control, so that the control
can draw temporary timeline guides on the line graph.
Arguments:
llStart Temporary log view start time (FILETIME format)
llEnd Temporary log view end time (FILETIME format)
Return Value:
--*/
{
assert ( llStart <= llStop );
if ( IsLogSource() && ( llStart <= llStop ) ) {
INT iNewStepNum;
// No time range to modify if no counters selected.
if ( NULL != FirstCounter() ) {
// Start/Stop time range bars are turned off if llStart and llStop are set
// to MIN and MAX values, so no need to update steppers.
if ( MIN_TIME_VALUE != llStart ) {
// Search through sample values to find the appropriate step for the start bar.
if ( llStart != m_pObj->m_Graph.LogViewTempStart ) {
// Start with current position.
iNewStepNum = m_pObj->m_Graph.LogViewStartStepper.StepNum();
GetNewLogViewStepNum ( llStart, iNewStepNum );
if ( iNewStepNum != m_pObj->m_Graph.LogViewStartStepper.StepNum() ) {
m_pObj->m_Graph.LogViewStartStepper.StepTo ( iNewStepNum );
}
}
}
if ( MAX_TIME_VALUE != llStop ) {
// Search through sample values to find the appropriate step for the stop bar.
if ( llStop != m_pObj->m_Graph.LogViewTempStop ) {
// Start with current position.
iNewStepNum = m_pObj->m_Graph.LogViewStopStepper.StepNum();
GetNewLogViewStepNum ( llStop, iNewStepNum );
if ( iNewStepNum != m_pObj->m_Graph.LogViewStopStepper.StepNum() ) {
m_pObj->m_Graph.LogViewStopStepper.StepTo ( iNewStepNum );
}
}
}
}
}
if ( ( m_pObj->m_Graph.LogViewTempStart != llStart )
|| ( m_pObj->m_Graph.LogViewTempStop != llStop ) ) {
m_pObj->m_Graph.LogViewTempStart = llStart;
m_pObj->m_Graph.LogViewTempStop = llStop;
if ( sysmonLineGraph == m_pObj->m_Graph.Options.iDisplayType ) {
// Cause redraw
UpdateGraph(UPDGRPH_PLOT);
}
}
}
PRECT
CSysmonControl::GetNewClientRect ( void )
{
return &m_pObj->m_RectExt;
}
PRECT
CSysmonControl::GetCurrentClientRect ( void )
{
return &m_rectCurrentClient;
}
void
CSysmonControl::SetCurrentClientRect ( PRECT prectNew )
{
m_rectCurrentClient = *prectNew;
}
void
CSysmonControl::UpdateNonAmbientSysColors ( void )
{
HRESULT hr;
COLORREF newColor;
PGRAPH_OPTIONS pOptions = &m_pObj->m_Graph.Options;
hr = OleTranslateColor(pOptions->clrBackCtl, NULL, &newColor);
if ( SUCCEEDED( hr ) ) {
m_clrBackCtl = newColor;
}
if (pOptions->clrBackPlot != NULL_COLOR) {
hr = OleTranslateColor(pOptions->clrBackPlot, NULL, &newColor);
if ( SUCCEEDED( hr ) ) {
m_clrBackPlot = newColor;
}
}
if (pOptions->clrFore != NULL_COLOR) {
hr = OleTranslateColor(pOptions->clrFore, NULL, &newColor);
if ( SUCCEEDED( hr ) ) {
m_clrFgnd = newColor;
}
}
hr = OleTranslateColor(pOptions->clrGrid, NULL, &newColor);
if ( SUCCEEDED( hr ) ) {
m_clrGrid = newColor;
}
hr = OleTranslateColor(pOptions->clrTimeBar, NULL, &newColor);
if ( SUCCEEDED( hr ) ) {
m_clrTimeBar = newColor;
}
}
LPCWSTR
CSysmonControl::GetDataSourceName ( void )
{
LPWSTR szReturn = NULL;
CLogFileItem* pLogFile = NULL;
if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType ) {
pLogFile = FirstLogFile();
if ( NULL != pLogFile ) {
szReturn = const_cast<LPWSTR>((LPCWSTR)pLogFile->GetPath());
}
}
// TodoLogFiles: Use the m_DataSourceInfo.szDataSourceName field? When multi-file?
return szReturn;
}
HRESULT
CSysmonControl::GetSelectedCounter ( CGraphItem** ppItem )
{
HRESULT hr = E_POINTER;
if ( NULL != ppItem ) {
*ppItem = m_pSelectedItem;
hr = NOERROR;
}
return hr;
}
DWORD
CSysmonControl::BuildLogFileList (
LPWSTR szLogFileList,
BOOL bIsCommaDelimiter,
ULONG* pulBufLen )
{
DWORD dwStatus = ERROR_SUCCESS;
ULONG ulListLen;
CLogFileItem* pLogFile = FirstLogFile();
LPCWSTR szThisLogFile = NULL;
LPWSTR szLogFileCurrent = NULL;
const WCHAR cwComma = L',';
if ( NULL != pulBufLen ) {
ulListLen = 0;
while (pLogFile != NULL) {
szThisLogFile= pLogFile->GetPath();
ulListLen += (lstrlen(szThisLogFile) + 1);
pLogFile = pLogFile->Next();
}
ulListLen ++; // for the single final NULL character.
if ( ulListLen <= *pulBufLen ) {
if ( NULL != szLogFileList ) {
ZeroMemory(szLogFileList, (ulListLen * sizeof(WCHAR)));
pLogFile = FirstLogFile();
szLogFileCurrent = (LPWSTR) szLogFileList;
while (pLogFile != NULL) {
szThisLogFile = pLogFile->GetPath();
//
// Here we are sure we have enough space to hold string
//
StringCchCopy(szLogFileCurrent, lstrlen(szThisLogFile) + 1, szThisLogFile);
szLogFileCurrent += lstrlen(szThisLogFile);
*szLogFileCurrent = L'\0';
pLogFile = pLogFile->Next();
if ( bIsCommaDelimiter && NULL != pLogFile ) {
// If comma delimited, replace the NULL char with a comma
*szLogFileCurrent = cwComma;
}
szLogFileCurrent ++;
}
if ( !bIsCommaDelimiter ) {
*szLogFileCurrent = L'\0';
}
}
} else if ( NULL != szLogFileList ) {
dwStatus = ERROR_MORE_DATA;
}
*pulBufLen = ulListLen;
} else {
dwStatus = ERROR_INVALID_PARAMETER;
assert ( FALSE );
}
return dwStatus;
}
HRESULT
CSysmonControl::LoadLogFilesFromMultiSz (
LPCWSTR szLogFileList )
{
HRESULT hr = NOERROR;
LPWSTR szNext = NULL;
szNext = const_cast<LPWSTR>(szLogFileList);
while ( NULL != szNext ) {
hr = AddSingleLogFile ( szNext );
if ( FAILED ( hr ) ) {
break;
}
szNext += lstrlen (szNext) + 1;
}
return hr;
}
void
CSysmonControl::ClearErrorPathList ( void )
{
if ( NULL != m_szErrorPathList ) {
delete [] m_szErrorPathList;
}
m_szErrorPathList = NULL;
m_dwErrorPathListLen = 0;
m_dwErrorPathBufLen = 0;
}
LPCWSTR
CSysmonControl::GetErrorPathList ( DWORD* pdwListLen )
{
if ( NULL != pdwListLen ) {
*pdwListLen = m_dwErrorPathListLen;
}
return m_szErrorPathList;
}
DWORD
CSysmonControl::AddToErrorPathList ( LPCWSTR szPath )
{
DWORD dwStatus = ERROR_SUCCESS;
DWORD dwPathLen = 0;
LPWSTR szNewBuffer = NULL;
LPWSTR szNextCounter = NULL;
//
// cdwAddLen is an arbitrary number, larger than most counter strings.
// Longer counter paths are handled dwPathLen below.
//
const DWORD cdwAddLen = 2048;
const LPCWSTR cszNewLine = L"\n";
if ( NULL != szPath ) {
//
// Include 1 for the possible newline character or null.
//
dwPathLen = lstrlen ( szPath ) + 1;
//
// If not enough space, allocate a bigger buffer.
//
if ( m_dwErrorPathBufLen < m_dwErrorPathListLen + dwPathLen ) {
m_dwErrorPathBufLen += max ( cdwAddLen, dwPathLen );
szNewBuffer = new WCHAR[m_dwErrorPathBufLen];
if ( NULL != szNewBuffer ) {
if ( NULL != m_szErrorPathList ) {
memcpy ( szNewBuffer, m_szErrorPathList, m_dwErrorPathListLen * sizeof(WCHAR) );
delete [] m_szErrorPathList;
}
m_szErrorPathList = szNewBuffer;
} else {
dwStatus = ERROR_OUTOFMEMORY;
}
}
if ( ERROR_SUCCESS == dwStatus ) {
//
// Point to current ending null character.
//
szNextCounter = m_szErrorPathList;
if ( 0 < m_dwErrorPathListLen ) {
szNextCounter += m_dwErrorPathListLen - 1;
memcpy ( szNextCounter, cszNewLine, sizeof(cszNewLine) );
szNextCounter++;
//
// No need to increment m_dwErrorPathListLen because the newline
// replaces the ending null of the previous string.
//
}
//
// We are sure we have enough space to hold the string
//
StringCchCopy(szNextCounter, dwPathLen, szPath);
m_dwErrorPathListLen += dwPathLen;
}
} else {
dwStatus = ERROR_INVALID_PARAMETER;
}
return dwStatus;
}