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
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 ( ¶ms, 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 ( ¶ms );
|
|
|
|
//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;
|
|
}
|