/*++ 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 // for INT_MAX #include #include #ifdef _WIN32_IE #if _WIN32_IE < 0x0400 #undef _WIN32_IE #define _WIN32_IE 0x0400 // for NMTBCUSTOMDRAW #endif // < 0x0400 #endif // defined #include #include #include #include #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; iDisprawValue[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; iNonDispnMaxSamples; 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((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(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; }