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

6993 lines
230 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. smonctrl.cpp
  5. Abstract:
  6. This module handles the graphing window.
  7. --*/
  8. #pragma warning ( disable : 4127 )
  9. #ifndef _LOG_INCLUDE_DATA
  10. #define _LOG_INCLUDE_DATA 0
  11. #endif
  12. //==========================================================================//
  13. // Includes //
  14. //==========================================================================//
  15. #include "polyline.h"
  16. #include <limits.h> // for INT_MAX
  17. #include <strsafe.h>
  18. #include <cderr.h>
  19. #ifdef _WIN32_IE
  20. #if _WIN32_IE < 0x0400
  21. #undef _WIN32_IE
  22. #define _WIN32_IE 0x0400 // for NMTBCUSTOMDRAW
  23. #endif // < 0x0400
  24. #endif // defined
  25. #include <commctrl.h>
  26. #include <htmlhelp.h>
  27. #include <shellapi.h>
  28. #include <pdhp.h>
  29. #include "cntrtree.h"
  30. #include "commdlg.h"
  31. #include "unihelpr.h"
  32. #include "winperf.h"
  33. #include "pdhmsg.h"
  34. #include "smonmsg.h"
  35. #include "visuals.h"
  36. #include "statbar.h"
  37. #include "snapbar.h"
  38. #include "legend.h"
  39. #include "toolbar.h"
  40. #include "grphdsp.h"
  41. #include "report.h"
  42. #include "browser.h"
  43. #include "appmema.h"
  44. #include "ipropbag.h"
  45. #include "logsrc.h"
  46. #include "smonmsg.h"
  47. #include "smonid.h"
  48. #include "smonctrl.h"
  49. #include "strnoloc.h"
  50. #include "grphitem.h"
  51. #include "winhelpr.h"
  52. //==========================================================================//
  53. // Constants //
  54. //==========================================================================//
  55. extern CCounterTree g_tree;
  56. extern DWORD g_dwScriptPolicy;
  57. #define DBG_SHOW_STATUS_PRINTS 1
  58. //=============================//
  59. // Graph Class //
  60. //=============================//
  61. static DWORD dwDbgPrintLevel = 0;
  62. static WCHAR szSysmonCtrlWndClass[] = L"SysmonCtrl";
  63. static WCHAR LineEndStr[] = TEXT("\n") ;
  64. static WCHAR SpaceStr[] = TEXT(" ");
  65. typedef struct {
  66. CSysmonControl *pCtrl;
  67. PCGraphItem pFirstItem;
  68. } ENUM_ADD_COUNTER_CALLBACK_INFO;
  69. BOOL
  70. APIENTRY
  71. SaveDataDlgHookProc (
  72. HWND hDlg,
  73. UINT iMessage,
  74. WPARAM wParam,
  75. LPARAM lParam
  76. )
  77. {
  78. BOOL bHandled;
  79. CSysmonControl *pCtrl;
  80. LONG lFilterValue;
  81. BOOL bGoodNumber = FALSE;
  82. UNREFERENCED_PARAMETER (wParam);
  83. // lparam = CSysmonControl class pointer
  84. bHandled = FALSE ;
  85. switch (iMessage) {
  86. case WM_INITDIALOG:
  87. // initialize the filter edit control with the current value
  88. OPENFILENAME *pOfn;
  89. pOfn= (OPENFILENAME *)lParam;
  90. if ( NULL != pOfn ) {
  91. // get the control class pointer from the OPENFILENAME struct
  92. pCtrl = (CSysmonControl *)pOfn->lCustData;
  93. // save the pointer to the control class as a DLG data word
  94. SetWindowLongPtr (hDlg, DWLP_USER, (LONG_PTR)pCtrl);
  95. lFilterValue = pCtrl->GetSaveDataFilter();
  96. SetDlgItemInt (hDlg, IDC_SAVEDATA_EDIT, (UINT)lFilterValue, FALSE);
  97. // limit reduction to 1/9999 records
  98. SendDlgItemMessage (hDlg, IDC_SAVEDATA_EDIT, EM_LIMITTEXT, (WPARAM)4, (LPARAM)0);
  99. bHandled = TRUE ;
  100. }
  101. break ;
  102. case WM_DESTROY:
  103. // the user has closed the dialog box so get the relog filter value
  104. // (note: this should be ignored if the user cancels the dialog)
  105. pCtrl = (CSysmonControl *)GetWindowLongPtr (hDlg, DWLP_USER);
  106. lFilterValue = GetDlgItemInt (hDlg, IDC_SAVEDATA_EDIT, &bGoodNumber, FALSE);
  107. if (bGoodNumber) {
  108. pCtrl->SetSaveDataFilter( lFilterValue );
  109. }
  110. bHandled = TRUE ;
  111. break ;
  112. case WM_NOTIFY:
  113. {
  114. LPOFNOTIFY pOFNotify;
  115. pOFNotify = (LPOFNOTIFY) lParam;
  116. if (pOFNotify) {
  117. if (pOFNotify->hdr.code == CDN_FILEOK) {
  118. lFilterValue = GetDlgItemInt (hDlg, IDC_SAVEDATA_EDIT, &bGoodNumber, FALSE);
  119. if (!bGoodNumber || lFilterValue == 0) {
  120. MessageBox(hDlg,
  121. ResourceString(IDS_FILTER_VALUE_ERR),
  122. ResourceString(IDS_APP_NAME),
  123. MB_OK | MB_ICONSTOP);
  124. ::SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
  125. bHandled = TRUE;
  126. }
  127. }
  128. }
  129. break;
  130. }
  131. default:
  132. break;
  133. }
  134. return bHandled;
  135. }
  136. HRESULT
  137. AddCounterCallback (
  138. LPWSTR pszPathName,
  139. DWORD_PTR lpUserData,
  140. DWORD dwFlags
  141. )
  142. {
  143. ENUM_ADD_COUNTER_CALLBACK_INFO *pInfo = (ENUM_ADD_COUNTER_CALLBACK_INFO*)lpUserData;
  144. CSysmonControl *pCtrl = pInfo->pCtrl;
  145. PCGraphItem pGraphItem = NULL;
  146. HRESULT hr;
  147. hr = pCtrl->AddSingleCounter(pszPathName, &pGraphItem);
  148. if (SUCCEEDED(hr)) {
  149. if (dwFlags & BROWSE_WILDCARD)
  150. pGraphItem->m_fGenerated = TRUE;
  151. if ( NULL == pInfo->pFirstItem ) {
  152. // Keep the reference count if returning the pointer.
  153. pInfo->pFirstItem = pGraphItem;
  154. } else {
  155. pGraphItem->Release();
  156. }
  157. }
  158. return hr;
  159. }
  160. #pragma warning( disable : 4355 ) // "this" use in initializer list
  161. CSysmonControl::CSysmonControl(
  162. PCPolyline pObj )
  163. : m_OleFont(this),
  164. m_pObj(pObj), // Pointer back to owner.
  165. m_fInitialized(FALSE),
  166. m_fViewInitialized(FALSE),
  167. m_hWnd(NULL),
  168. m_pLegend(NULL),
  169. m_pGraphDisp(NULL),
  170. m_pStatsBar(NULL),
  171. m_pSnapBar(NULL),
  172. m_pReport(NULL),
  173. m_pToolbar(NULL),
  174. m_hQuery(NULL),
  175. m_TimerID(0),
  176. m_fPendingUpdate(FALSE),
  177. m_fPendingSizeChg(FALSE),
  178. m_fPendingFontChg(FALSE),
  179. m_fPendingLogViewChg(FALSE),
  180. m_fPendingLogCntrChg(FALSE),
  181. m_pSelectedItem(NULL),
  182. m_fUIDead(FALSE),
  183. m_fRTL(FALSE),
  184. m_fUserMode(FALSE),
  185. m_hAccel(NULL),
  186. m_bLogFileSource(FALSE),
  187. m_bSampleDataLoaded(FALSE),
  188. m_bLoadingCounters(FALSE),
  189. m_bSettingsLoaded(FALSE),
  190. m_szErrorPathList ( NULL ),
  191. m_dwErrorPathListLen ( 0 ),
  192. m_dwErrorPathBufLen ( 0 ),
  193. // Default attributes
  194. m_iColorIndex(0),
  195. m_iWidthIndex(0),
  196. m_iStyleIndex(0),
  197. m_iScaleFactor(INT_MAX),
  198. m_iAppearance(eAppear3D),
  199. m_iBorderStyle(eBorderNone),
  200. m_dZoomFactor(1.0),
  201. m_lcidCurrent ( LOCALE_USER_DEFAULT )
  202. {
  203. PGRAPH_OPTIONS pOptions;
  204. m_LoadedVersion.iMajor = SMONCTRL_MAJ_VERSION;
  205. m_LoadedVersion.iMinor = SMONCTRL_MIN_VERSION;
  206. m_clrBackCtl = GetSysColor(COLOR_BTNFACE);
  207. m_clrFgnd = GetSysColor(COLOR_BTNTEXT);
  208. m_clrBackPlot = GetSysColor(COLOR_WINDOW);
  209. m_clrGrid = RGB(128,128,128); // Medium gray
  210. m_clrTimeBar = RGB(255,0,0); // Red
  211. m_lSaveDataToLogFilterValue = 1; // default save data to log filter is 1
  212. // Init graph parameters
  213. pOptions = &pObj->m_Graph.Options;
  214. pOptions->bLegendChecked = TRUE;
  215. pOptions->bToolbarChecked = TRUE;
  216. pOptions->bLabelsChecked = TRUE;
  217. pOptions->bVertGridChecked = FALSE;
  218. pOptions->bHorzGridChecked = FALSE;
  219. pOptions->bValueBarChecked = TRUE;
  220. pOptions->bManualUpdate = FALSE;
  221. pOptions->bHighlight = FALSE;
  222. pOptions->bReadOnly = FALSE;
  223. pOptions->bMonitorDuplicateInstances = TRUE;
  224. pOptions->bAmbientFont = TRUE;
  225. pOptions->iVertMax = 100;
  226. pOptions->iVertMin = 0;
  227. pOptions->fUpdateInterval = (float)1.0;
  228. pOptions->iDisplayFilter = 1;
  229. pOptions->iDisplayType = sysmonLineGraph;
  230. pOptions->iReportValueType = sysmonDefaultValue;
  231. pOptions->pszGraphTitle = NULL;
  232. pOptions->pszYaxisTitle = NULL;
  233. pOptions->clrBackCtl = ( 0x80000000 | COLOR_BTNFACE );
  234. pOptions->clrGrid = m_clrGrid;
  235. pOptions->clrTimeBar = m_clrTimeBar;
  236. pOptions->clrFore = NULL_COLOR;
  237. pOptions->clrBackPlot = NULL_COLOR;
  238. pOptions->iAppearance = NULL_APPEARANCE;
  239. pOptions->iBorderStyle = eBorderNone;
  240. pOptions->iDataSourceType = sysmonCurrentActivity;
  241. // Init data source info
  242. memset ( &m_DataSourceInfo, 0, sizeof ( m_DataSourceInfo ) );
  243. m_DataSourceInfo.llStartDisp = MIN_TIME_VALUE;
  244. m_DataSourceInfo.llStopDisp = MAX_TIME_VALUE;
  245. // Init collection thread info
  246. m_CollectInfo.hThread = NULL;
  247. m_CollectInfo.hEvent = NULL;
  248. m_CollectInfo.iMode = COLLECT_SUSPEND;
  249. // Cache pointer to object's history control
  250. m_pHistCtrl = &pObj->m_Graph.History;
  251. assert ( NULL != pObj );
  252. pObj->m_Graph.LogViewTempStart = MIN_TIME_VALUE;
  253. pObj->m_Graph.LogViewTempStop = MAX_TIME_VALUE;
  254. // Init the log view and time steppers. They might be used before
  255. // SizeComponents is called, for example when a property bag is loaded.
  256. // The width has not been calculated yet, is initialized here
  257. // to an arbitrary number.
  258. pObj->m_Graph.TimeStepper.Init( MAX_GRAPH_SAMPLES, MAX_GRAPH_SAMPLES - 2 );
  259. pObj->m_Graph.LogViewStartStepper.Init( MAX_GRAPH_SAMPLES, MAX_GRAPH_SAMPLES - 2 );
  260. pObj->m_Graph.LogViewStopStepper.Init( MAX_GRAPH_SAMPLES, MAX_GRAPH_SAMPLES - 2 );
  261. m_pHistCtrl->bLogSource = FALSE;
  262. m_pHistCtrl->nMaxSamples = MAX_GRAPH_SAMPLES;
  263. m_pHistCtrl->iCurrent = 0;
  264. m_pHistCtrl->nSamples = 0;
  265. m_pHistCtrl->nBacklog = 0;
  266. // Keep record of current size to avoide unnecessary calls to SizeComponents
  267. SetRect ( &m_rectCurrentClient,0,0,0,0 );
  268. }
  269. BOOL
  270. CSysmonControl::AllocateSubcomponents( void )
  271. {
  272. BOOL bResult = TRUE;
  273. //
  274. // Initialize the critical section here rather than in
  275. // the constructor because it can throw an exception.
  276. //
  277. try {
  278. InitializeCriticalSection(&m_CounterDataLock);
  279. } catch (...) {
  280. bResult = FALSE;
  281. }
  282. if ( bResult ) {
  283. m_pLegend = new CLegend;
  284. m_pGraphDisp = new CGraphDisp;
  285. m_pStatsBar = new CStatsBar;
  286. m_pSnapBar = new CSnapBar;
  287. m_pReport = new CReport;
  288. m_pToolbar = new CSysmonToolbar;
  289. }
  290. if (m_pLegend == NULL ||
  291. m_pGraphDisp == NULL ||
  292. m_pStatsBar == NULL ||
  293. m_pSnapBar == NULL ||
  294. m_pReport == NULL ||
  295. m_pToolbar == NULL) {
  296. bResult = FALSE;
  297. }
  298. if (!bResult) {
  299. DeInit();
  300. return bResult;
  301. }
  302. if ( FAILED(m_OleFont.Init()) )
  303. bResult = FALSE;
  304. return bResult;
  305. }
  306. CSysmonControl::~CSysmonControl( void )
  307. {
  308. PCGraphItem pItem;
  309. PCGraphItem pNext;
  310. PCLogFileItem pLogFile;
  311. PCLogFileItem pNextLogFile;
  312. CloseQuery();
  313. DeInit();
  314. DeleteCriticalSection(&m_CounterDataLock);
  315. // Release all graph items
  316. pItem = FirstCounter();
  317. while ( NULL != pItem ) {
  318. pNext = pItem->Next();
  319. pItem->Release();
  320. pItem = pNext;
  321. }
  322. // Release all log file items
  323. pLogFile = FirstLogFile();
  324. while ( NULL != pLogFile ) {
  325. pNextLogFile = pLogFile->Next();
  326. pLogFile->Release();
  327. pLogFile = pNextLogFile;
  328. }
  329. if (m_DataSourceInfo.szSqlDsnName != NULL) {
  330. delete [] m_DataSourceInfo.szSqlDsnName;
  331. m_DataSourceInfo.szSqlDsnName = NULL;
  332. }
  333. if (m_DataSourceInfo.szSqlLogSetName != NULL) {
  334. delete [] m_DataSourceInfo.szSqlLogSetName;
  335. m_DataSourceInfo.szSqlLogSetName = NULL;
  336. }
  337. if (m_hWnd != NULL)
  338. DestroyWindow(m_hWnd);
  339. if (m_pObj->m_Graph.Options.pszGraphTitle != NULL)
  340. delete [] m_pObj->m_Graph.Options.pszGraphTitle;
  341. if (m_pObj->m_Graph.Options.pszYaxisTitle != NULL)
  342. delete [] m_pObj->m_Graph.Options.pszYaxisTitle;
  343. ClearErrorPathList();
  344. }
  345. void CSysmonControl::DeInit( void )
  346. {
  347. if (m_pLegend) {
  348. delete m_pLegend;
  349. m_pLegend = NULL;
  350. }
  351. if (m_pGraphDisp) {
  352. delete m_pGraphDisp;
  353. m_pGraphDisp = NULL;
  354. }
  355. if (m_pStatsBar) {
  356. delete m_pStatsBar;
  357. m_pStatsBar = NULL;
  358. }
  359. if (m_pSnapBar) {
  360. delete m_pSnapBar;
  361. m_pSnapBar = NULL;
  362. }
  363. if (m_pReport) {
  364. delete m_pReport;
  365. m_pReport = NULL;
  366. }
  367. if (m_pToolbar) {
  368. delete m_pToolbar;
  369. m_pToolbar = NULL;
  370. }
  371. ClearErrorPathList();
  372. }
  373. void CSysmonControl::ApplyChanges( HDC hAttribDC )
  374. {
  375. if ( m_fPendingUpdate ) {
  376. // Clear the master update flag
  377. m_fPendingUpdate = FALSE;
  378. // set the toolbar state
  379. m_pToolbar->ShowToolbar(m_pObj->m_Graph.Options.bToolbarChecked);
  380. // If log view changed or counters added
  381. // we need to resample the log file
  382. if (m_fPendingLogViewChg || m_fPendingLogCntrChg) {
  383. SampleLogFile(m_fPendingLogViewChg);
  384. // Must init time steppers before calling ResetLogViewTempTimeRange
  385. ResetLogViewTempTimeRange ( );
  386. m_fPendingLogViewChg = FALSE;
  387. m_fPendingLogCntrChg = FALSE;
  388. }
  389. if (m_fPendingFontChg || m_fPendingSizeChg) {
  390. if (NULL != hAttribDC ) {
  391. if (m_fPendingFontChg) {
  392. m_pLegend->ChangeFont(hAttribDC);
  393. m_pStatsBar->ChangeFont(hAttribDC);
  394. m_pGraphDisp->ChangeFont(hAttribDC);
  395. m_fPendingFontChg = FALSE;
  396. }
  397. SizeComponents( hAttribDC );
  398. m_fPendingSizeChg = FALSE;
  399. }
  400. }
  401. m_pToolbar->SyncToolbar();
  402. }
  403. }
  404. void
  405. CSysmonControl::DrawBorder ( HDC hDC )
  406. {
  407. if ( eBorderSingle == m_iBorderStyle ) {
  408. RECT rectClient;
  409. //
  410. // Get dimensions of window
  411. //
  412. GetClientRect (m_hWnd, &rectClient) ;
  413. if ( eAppear3D == m_iAppearance ) {
  414. DrawEdge(hDC, &rectClient, EDGE_RAISED, BF_RECT);
  415. } else {
  416. SelectBrush (hDC, GetStockObject (HOLLOW_BRUSH)) ;
  417. SelectPen (hDC, GetStockObject (BLACK_PEN)) ;
  418. Rectangle (hDC, rectClient.left, rectClient.top, rectClient.right, rectClient.bottom );
  419. }
  420. }
  421. }
  422. void CSysmonControl::Paint ( void )
  423. {
  424. HDC hDC ;
  425. PAINTSTRUCT ps ;
  426. hDC = BeginPaint (m_hWnd, &ps) ;
  427. //
  428. // ApplyChanges does some work even if hDC is NULL.
  429. //
  430. ApplyChanges( hDC ) ;
  431. if ( m_fViewInitialized && NULL != hDC ) {
  432. m_pStatsBar->Draw(hDC, hDC, &ps.rcPaint);
  433. m_pGraphDisp->Draw(hDC, hDC, FALSE, FALSE, &ps.rcPaint);
  434. DrawBorder( hDC );
  435. }
  436. EndPaint (m_hWnd, &ps) ;
  437. }
  438. void
  439. CSysmonControl::OnDblClick(INT x, INT y)
  440. {
  441. if ( REPORT_GRAPH != m_pObj->m_Graph.Options.iDisplayType ) {
  442. PCGraphItem pItem = m_pGraphDisp->GetItem ( x,y );
  443. if ( NULL != pItem ) {
  444. SelectCounter( pItem );
  445. DblClickCounter ( pItem );
  446. }
  447. } else {
  448. assert ( FALSE );
  449. }
  450. }
  451. DWORD
  452. CSysmonControl::ProcessCommandLine ( )
  453. {
  454. DWORD dwStatus = ERROR_SUCCESS;
  455. HRESULT hr = S_OK;
  456. LPCWSTR pszNext;
  457. LPWSTR pszWmi = NULL;
  458. LPWSTR pszSettings = NULL;
  459. LPWSTR* pszArgList = NULL;
  460. INT iNumArgs;
  461. INT iArgIndex;
  462. LPWSTR pszNextArg = NULL;
  463. LPWSTR pszThisArg = NULL;
  464. LPWSTR szFileName = NULL;
  465. LPWSTR szTemp = NULL;
  466. LPWSTR pszToken = NULL;
  467. size_t sizeArgLen = 0;
  468. BOOL bDisplayMessage = FALSE;
  469. LPWSTR szSystemMessage = NULL;
  470. static const size_t ciArgMaxLen = MAX_PATH + 1;
  471. //
  472. // Maximum argument length is for file path, which is restricted to MAX_PATH.
  473. //
  474. pszWmi = ResourceString ( IDS_CMDARG_WMI );
  475. pszSettings = ResourceString ( IDS_CMDARG_SETTINGS );
  476. pszNext = GetCommandLineW();
  477. pszArgList = CommandLineToArgvW ( pszNext, &iNumArgs );
  478. if ( NULL != pszArgList ) {
  479. for ( iArgIndex = 0; SUCCEEDED(hr) && (iArgIndex < iNumArgs); iArgIndex++ ) {
  480. pszNextArg = (LPWSTR)pszArgList[iArgIndex];
  481. pszThisArg = pszNextArg;
  482. while ( 0 != *pszThisArg ) {
  483. if ( *pszThisArg++ == L'/' ) { // argument found
  484. hr = StringCchLength ( pszThisArg, ciArgMaxLen, &sizeArgLen );
  485. if ( SUCCEEDED(hr) ) {
  486. szTemp = new WCHAR [sizeArgLen + 1];
  487. if ( NULL != szTemp ) {
  488. // No StringCchCopy failure because StringCchLen calculated above.
  489. StringCchCopy (
  490. szTemp,
  491. (sizeArgLen + 1),
  492. pszThisArg );
  493. pszToken = wcstok ( szTemp, L"/ =\"" );
  494. if ( 0 == lstrcmpiW ( pszToken, pszWmi ) ) {
  495. //
  496. // Ignore PDH errors. The only possible error is that the default data source has
  497. // already been set for this process.
  498. //
  499. PdhSetDefaultRealTimeDataSource ( DATA_SOURCE_WBEM );
  500. pszThisArg += sizeArgLen;
  501. } else if ( 0 == lstrcmpiW ( pszToken, pszSettings ) ) {
  502. //
  503. // Strip the initial non-token characters for string comparison.
  504. //
  505. pszThisArg = _wcsspnp ( pszNextArg, L"/ =\"" );
  506. if ( 0 == lstrcmpiW ( pszThisArg, pszSettings ) ) {
  507. //
  508. // Get the next argument (the file name)
  509. //
  510. iArgIndex++;
  511. pszNextArg = (LPWSTR)pszArgList[iArgIndex];
  512. pszThisArg = pszNextArg;
  513. } else {
  514. //
  515. // File was created by Windows 2000 perfmon5.exe,
  516. // so file name is part of the arg.
  517. //
  518. pszThisArg += lstrlen ( pszSettings );
  519. hr = StringCchLength ( pszThisArg, ciArgMaxLen, &sizeArgLen );
  520. if ( SUCCEEDED ( hr ) ) {
  521. szFileName = new WCHAR[sizeArgLen + 1];
  522. if ( NULL != szFileName ) {
  523. //
  524. // No StringCchCopy failure because StringCchLen calculated above.
  525. //
  526. StringCchCopy (
  527. szFileName,
  528. (sizeArgLen + 1),
  529. pszThisArg );
  530. pszThisArg = wcstok ( szFileName, L"=\"" );
  531. } else {
  532. hr = E_OUTOFMEMORY;
  533. bDisplayMessage = TRUE;
  534. }
  535. } else {
  536. bDisplayMessage = TRUE;
  537. }
  538. }
  539. if ( SUCCEEDED (hr) ) {
  540. hr = LoadFromFile( pszThisArg, TRUE );
  541. if ( SMON_STATUS_NO_SYSMON_OBJECT != (DWORD)hr ) {
  542. if ( SUCCEEDED ( hr ) ) {
  543. m_bSettingsLoaded = TRUE;
  544. } // else LoadFromFile displays messages for other errors
  545. } else {
  546. // SMON_STATUS_NO_SYSMON_OBJECT == hr
  547. MessageBox(
  548. m_hWnd,
  549. ResourceString(IDS_NOSYSMONOBJECT_ERR ),
  550. ResourceString(IDS_APP_NAME),
  551. MB_OK | MB_ICONERROR);
  552. }
  553. pszThisArg += lstrlen ( pszThisArg );
  554. }
  555. }
  556. }
  557. if ( NULL != szTemp ) {
  558. delete [] szTemp;
  559. szTemp = NULL;
  560. }
  561. if ( NULL != szFileName ) {
  562. delete [] szFileName;
  563. szFileName = NULL;
  564. }
  565. } else {
  566. bDisplayMessage = TRUE;
  567. }
  568. }
  569. }
  570. }
  571. }
  572. if ( FAILED(hr) && bDisplayMessage ) {
  573. if ( STRSAFE_E_INVALID_PARAMETER == hr ) {
  574. dwStatus = ERROR_INVALID_PARAMETER;
  575. } else if ( E_OUTOFMEMORY == hr ) {
  576. dwStatus = ERROR_OUTOFMEMORY;
  577. } else {
  578. dwStatus = HRESULT_CODE (hr);
  579. }
  580. szSystemMessage = new WCHAR[MAX_MESSAGE_LEN];
  581. if ( NULL != szSystemMessage ) {
  582. if ( FormatSystemMessage (
  583. dwStatus,
  584. szSystemMessage,
  585. MAX_MESSAGE_LEN ) )
  586. {
  587. MessageBox(
  588. m_hWnd,
  589. szSystemMessage,
  590. ResourceString(IDS_APP_NAME),
  591. MB_OK | MB_ICONERROR);
  592. }
  593. delete [] szSystemMessage;
  594. }
  595. }
  596. if ( NULL != pszArgList ) {
  597. GlobalFree ( pszArgList );
  598. }
  599. return dwStatus;
  600. }
  601. HRESULT
  602. CSysmonControl::LoadFromFile ( LPWSTR szFileName, BOOL bAllData )
  603. {
  604. HRESULT hr = E_OUTOFMEMORY;
  605. LPWSTR szLocalName = NULL;
  606. LPWSTR pFileNameStart;
  607. HANDLE hFindFile = NULL;
  608. WIN32_FIND_DATA FindFileInfo;
  609. INT iNameOffset;
  610. DWORD dwMsgStatus = ERROR_SUCCESS;
  611. HANDLE hOpenFile = NULL;
  612. size_t sizeCharCount;
  613. szLocalName = new WCHAR [MAX_PATH + 1];
  614. if ( NULL != szLocalName ) {
  615. hr = StringCchCopy ( szLocalName, MAX_PATH, szFileName );
  616. if ( SUCCEEDED ( hr ) ) {
  617. //
  618. // Find the filename offset within the path buffer.
  619. //
  620. pFileNameStart = ExtractFileName (szLocalName) ;
  621. iNameOffset = (INT)(pFileNameStart - szLocalName);
  622. //
  623. // Convert short filename to long NTFS filename if necessary.
  624. //
  625. hFindFile = FindFirstFile ( szLocalName, &FindFileInfo) ;
  626. if (hFindFile && hFindFile != INVALID_HANDLE_VALUE) {
  627. if ( ConfirmSampleDataOverwrite ( ) ) {
  628. //
  629. // Append the NTFS file name back to the path name, if different.
  630. //
  631. if ( 0 != lstrcmpiW ( FindFileInfo.cFileName, pFileNameStart ) ) {
  632. hr = StringCchLength ( FindFileInfo.cFileName, MAX_PATH, &sizeCharCount );
  633. if ( SUCCEEDED ( hr ) ) {
  634. //
  635. // No StringCchCopy failure, because truncation found by StringCchLength
  636. //
  637. StringCchCopy (
  638. &szLocalName[iNameOffset],
  639. (MAX_PATH+1) - iNameOffset,
  640. FindFileInfo.cFileName );
  641. } else {
  642. //
  643. // STRSAFE_E_INSUFFICIENT_BUFFER indicates filename truncation.
  644. //
  645. dwMsgStatus = ERROR_BUFFER_OVERFLOW;
  646. hr = HRESULT_FROM_WIN32(dwMsgStatus);
  647. }
  648. }
  649. if ( SUCCEEDED( hr ) ) {
  650. //
  651. // Open the file
  652. //
  653. hOpenFile = CreateFile (
  654. szLocalName,
  655. GENERIC_READ,
  656. 0, // Not shared
  657. NULL, // Security attributes
  658. OPEN_EXISTING,
  659. FILE_ATTRIBUTE_NORMAL,
  660. NULL );
  661. if ( hOpenFile && hOpenFile != INVALID_HANDLE_VALUE ) {
  662. DWORD dwFileSize;
  663. DWORD dwFileSizeHigh;
  664. DWORD dwFileSizeRead;
  665. LPWSTR pszData = NULL;
  666. //
  667. // Read the file contents into a memory buffer.
  668. //
  669. dwFileSize = GetFileSize ( hOpenFile, &dwFileSizeHigh );
  670. assert ( 0 == dwFileSizeHigh );
  671. if ( 0 == dwFileSizeHigh ) {
  672. //
  673. // Restrict file size to DWORD length.
  674. //
  675. pszData = new WCHAR[(dwFileSize + sizeof(WCHAR))/sizeof(WCHAR)];
  676. if ( NULL != pszData ) {
  677. if ( ReadFile ( hOpenFile, pszData, dwFileSize, &dwFileSizeRead, NULL ) ) {
  678. // Paste all settings from the memory buffer.
  679. hr = PasteFromBuffer ( pszData, bAllData );
  680. if ( E_OUTOFMEMORY == hr ) {
  681. dwMsgStatus = ERROR_NOT_ENOUGH_MEMORY;
  682. }
  683. } else {
  684. dwMsgStatus = GetLastError();
  685. hr = HRESULT_FROM_WIN32(dwMsgStatus);
  686. }
  687. delete [] pszData;
  688. } else {
  689. dwMsgStatus = ERROR_NOT_ENOUGH_MEMORY;
  690. hr = E_OUTOFMEMORY;
  691. }
  692. } else {
  693. // Todo: Sysmon-specific message re: file too large.
  694. dwMsgStatus = ERROR_DS_OBJ_TOO_LARGE;
  695. hr = HRESULT_FROM_WIN32(ERROR_DS_OBJ_TOO_LARGE);
  696. }
  697. CloseHandle ( hOpenFile );
  698. } else {
  699. //
  700. // Return file system error.
  701. //
  702. assert (FALSE);
  703. dwMsgStatus = GetLastError();
  704. hr = HRESULT_FROM_WIN32(dwMsgStatus);
  705. }
  706. }
  707. }
  708. FindClose (hFindFile) ;
  709. } else {
  710. dwMsgStatus = GetLastError();
  711. HRESULT_FROM_WIN32(dwMsgStatus);
  712. }
  713. } else {
  714. //
  715. // STRSAFE_E_INSUFFICIENT_BUFFER indicates filename truncation.
  716. //
  717. dwMsgStatus = ERROR_BUFFER_OVERFLOW;
  718. hr = HRESULT_FROM_WIN32(dwMsgStatus);
  719. }
  720. } else {
  721. hr = E_OUTOFMEMORY;
  722. dwMsgStatus = ERROR_OUTOFMEMORY;
  723. }
  724. if ( ERROR_SUCCESS != dwMsgStatus ) {
  725. LPWSTR szMessage = NULL;
  726. LPWSTR szSystemMessage = NULL;
  727. INT cchBufLen;
  728. cchBufLen = lstrlen(szLocalName) + MAX_MESSAGE_LEN + RESOURCE_STRING_BUF_LEN + 1;
  729. szMessage = new WCHAR [cchBufLen];
  730. szSystemMessage = new WCHAR [MAX_MESSAGE_LEN + 1];
  731. if ( NULL != szMessage && NULL != szSystemMessage ) {
  732. StringCchPrintf (
  733. szMessage,
  734. cchBufLen,
  735. ResourceString(IDS_READFILE_ERR),
  736. szLocalName );
  737. FormatSystemMessage ( dwMsgStatus, szSystemMessage, MAX_MESSAGE_LEN + 1 );
  738. StringCchCat(szMessage, cchBufLen, szSystemMessage );
  739. MessageBox(Window(), szMessage, ResourceString(IDS_APP_NAME), MB_OK | MB_ICONSTOP);
  740. }
  741. if ( NULL != szMessage ) {
  742. delete [] szMessage;
  743. }
  744. if ( NULL != szSystemMessage ) {
  745. delete [] szSystemMessage;
  746. }
  747. }
  748. if ( NULL != szLocalName ) {
  749. delete [] szLocalName;
  750. }
  751. return hr;
  752. }
  753. void
  754. CSysmonControl::OnDropFile ( WPARAM wParam )
  755. {
  756. LPWSTR szFileName = NULL;
  757. INT iFileCount = 0;
  758. HRESULT hr = S_OK;
  759. UINT uiCchFileName;
  760. iFileCount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0) ;
  761. if ( iFileCount > 0 ) {
  762. //
  763. // Open only the first file.
  764. //
  765. uiCchFileName = DragQueryFile((HDROP) wParam, 0, NULL,0 );
  766. szFileName = new WCHAR[uiCchFileName + 1];
  767. if ( NULL != szFileName ) {
  768. uiCchFileName = DragQueryFile((HDROP) wParam, 0, szFileName, uiCchFileName + 1 );
  769. //
  770. // LoadFromFile handles file name errors.
  771. //
  772. hr = LoadFromFile ( szFileName, FALSE );
  773. if ( SMON_STATUS_NO_SYSMON_OBJECT == (DWORD)hr ) {
  774. MessageBox(
  775. m_hWnd,
  776. ResourceString(IDS_NOSYSMONOBJECT_ERR ),
  777. ResourceString(IDS_APP_NAME),
  778. MB_OK | MB_ICONERROR);
  779. } // else LoadFromFile displays messages for other errors
  780. delete [] szFileName;
  781. }
  782. }
  783. DragFinish ((HDROP) wParam) ;
  784. }
  785. void
  786. CSysmonControl::DisplayContextMenu(short x, short y)
  787. {
  788. HMENU hMenu;
  789. HMENU hMenuPopup;
  790. RECT clntRect;
  791. int iPosx=0;
  792. int iPosy=0;
  793. int iLocalx;
  794. int iLocaly;
  795. GetWindowRect(m_hWnd,&clntRect);
  796. if (x==0){
  797. iPosx = ((clntRect.right - clntRect.left)/2) ;
  798. }else{
  799. iPosx = x - clntRect.left;
  800. }
  801. if (y==0){
  802. iPosy = ((clntRect.bottom - clntRect.top)/2) ;
  803. }else{
  804. iPosy = y - clntRect.top;
  805. }
  806. iLocalx = clntRect.left + iPosx ;
  807. iLocaly = clntRect.top + iPosy ;
  808. if ( ConfirmSampleDataOverwrite () ) {
  809. if ( !IsReadOnly() ) {
  810. UINT uEnable;
  811. // Get the menu for the pop-up menu from the resource file.
  812. hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_CONTEXT));
  813. if (!hMenu) {
  814. return;
  815. }
  816. // enable/disable SaveData option depending on data source
  817. uEnable = (IsLogSource() ? MF_ENABLED : MF_GRAYED);
  818. uEnable |= MF_BYCOMMAND;
  819. EnableMenuItem (hMenu, IDM_SAVEDATA, uEnable);
  820. // Get the first submenu in it for TrackPopupMenu.
  821. hMenuPopup = GetSubMenu(hMenu, 0);
  822. // Draw and track the "floating" pop-up menu.
  823. TrackPopupMenu(hMenuPopup, TPM_RIGHTBUTTON,
  824. iLocalx, iLocaly, 0, m_hWnd, NULL);
  825. // Destroy the menu.
  826. DestroyMenu(hMenu);
  827. }
  828. }
  829. }
  830. HRESULT CSysmonControl::DisplayProperties ( DISPID dispID )
  831. {
  832. HRESULT hr;
  833. CAUUID caGUID;
  834. OCPFIPARAMS params;
  835. // Give container a chance to show properties
  836. if (NULL!=m_pObj->m_pIOleControlSite) {
  837. hr=m_pObj->m_pIOleControlSite->ShowPropertyFrame();
  838. if (NOERROR == hr)
  839. return hr;
  840. }
  841. //Put up our property pages.
  842. ZeroMemory ( &params, sizeof ( OCPFIPARAMS ) );
  843. hr = m_pObj->m_pImpISpecifyPP->GetPages(&caGUID);
  844. if (FAILED(hr)) {
  845. return hr;
  846. }
  847. params.cbStructSize = sizeof ( OCPFIPARAMS );
  848. params.hWndOwner = m_hWnd;
  849. params.x = 10;
  850. params.y = 10;
  851. params.lpszCaption = ResourceString(IDS_PROPFRM_TITLE);
  852. params.cObjects = 1;
  853. params.lplpUnk = (IUnknown **)&m_pObj,
  854. params.cPages = caGUID.cElems;
  855. params.lpPages = caGUID.pElems;
  856. params.lcid = m_lcidCurrent;
  857. params.dispidInitialProperty = dispID;
  858. hr = OleCreatePropertyFrameIndirect ( &params );
  859. //Free the GUIDs
  860. CoTaskMemFree((void *)caGUID.pElems);
  861. // Make sure correct window has the focus
  862. AssignFocus();
  863. return hr;
  864. }
  865. HRESULT
  866. CSysmonControl::AddCounter(
  867. LPWSTR pszPath,
  868. PCGraphItem *pGItem)
  869. /*++
  870. Routine Description:
  871. AddCounter returns a pointer to the created counter item, or
  872. to the first created counter item if multiple created for a wildcard
  873. path.
  874. EnumExpandedPath calls the AddCallback function for each new counter.
  875. AddCallback passes the counter path on to the AddSingleCounter method.
  876. Arguments:
  877. None.
  878. Return Value:
  879. None.
  880. --*/
  881. {
  882. HRESULT hr;
  883. ENUM_ADD_COUNTER_CALLBACK_INFO CallbackInfo;
  884. if (pszPath == NULL || lstrlen(pszPath) > PDH_MAX_COUNTER_PATH) {
  885. return E_INVALIDARG;
  886. }
  887. CallbackInfo.pCtrl = this;
  888. CallbackInfo.pFirstItem = NULL;
  889. *pGItem = NULL;
  890. hr = EnumExpandedPath(GetDataSourceHandle(), pszPath, AddCounterCallback, &CallbackInfo);
  891. *pGItem = CallbackInfo.pFirstItem;
  892. return hr;
  893. }
  894. HRESULT
  895. CSysmonControl::AddCounters (
  896. VOID
  897. )
  898. /*++
  899. Routine Description:
  900. AddCounters invokes the counter browser to select new counters.
  901. The browser calls the AddCallback function for each new counter.
  902. AddCallback passes the counter path on to the AddCounter method.
  903. Arguments:
  904. None.
  905. Return Value:
  906. None.
  907. --*/
  908. {
  909. ENUM_ADD_COUNTER_CALLBACK_INFO CallbackInfo;
  910. HRESULT hr;
  911. CallbackInfo.pCtrl = this;
  912. CallbackInfo.pFirstItem = NULL;
  913. //
  914. // Browse counters, calling AddCallback for each selected counter.
  915. //
  916. hr = BrowseCounters(
  917. GetDataSourceHandle(),
  918. PERF_DETAIL_WIZARD,
  919. m_hWnd,
  920. AddCounterCallback,
  921. &CallbackInfo,
  922. m_pObj->m_Graph.Options.bMonitorDuplicateInstances);
  923. // Make sure correct window has the focus
  924. AssignFocus();
  925. return hr;
  926. }
  927. HRESULT
  928. CSysmonControl::SaveAs (
  929. VOID
  930. )
  931. /*++
  932. Routine Description:
  933. SaveAs writes the current configuration to an HTML file.
  934. Arguments:
  935. None.
  936. Return Value:
  937. None.
  938. --*/
  939. {
  940. HRESULT hr = S_OK;
  941. INT iReturn = IDCANCEL;
  942. INT i;
  943. OPENFILENAME ofn;
  944. WCHAR szFileName[MAX_PATH+1];
  945. WCHAR szExt[MAX_PATH+1];
  946. WCHAR szFileFilter[RESOURCE_STRING_BUF_LEN];
  947. WCHAR szDefExtension[RESOURCE_STRING_BUF_LEN];
  948. HANDLE hFile = NULL;
  949. DWORD dwMsgStatus = ERROR_SUCCESS;
  950. DWORD dwCreateError;
  951. INT iOverwrite = IDNO;
  952. LPWSTR szMessage = NULL;
  953. size_t cchMessageBuf;
  954. LPWSTR pszTemp = NULL;
  955. WCHAR szByteOrderMark[2];
  956. BOOL bStatus;
  957. DWORD dwByteCount;
  958. //
  959. // Initial directory is the current directory
  960. //
  961. szFileName[0] = L'\0';
  962. ZeroMemory(szFileFilter, sizeof ( szFileFilter ) );
  963. ZeroMemory(&ofn, sizeof(ofn));
  964. StringCchCopy(szFileFilter,
  965. RESOURCE_STRING_BUF_LEN,
  966. ResourceString (IDS_HTML_FILE));
  967. StringCchCopy(szDefExtension,
  968. RESOURCE_STRING_BUF_LEN,
  969. ResourceString (IDS_DEF_EXT));
  970. for( i = 0; szFileFilter[i]; i++ ){
  971. if( szFileFilter[i] == L'|' ){
  972. szFileFilter[i] = L'\0';
  973. }
  974. }
  975. for( i = 0; szDefExtension[i]; i++ ){
  976. if( szDefExtension[i] == L'|' ){
  977. szDefExtension[i] = L'\0';
  978. }
  979. }
  980. ofn.lStructSize = sizeof(ofn);
  981. ofn.hwndOwner = Window();
  982. ofn.hInstance = NULL ; // Ignored if no template argument
  983. ofn.lpstrFilter = szFileFilter;
  984. ofn.lpstrDefExt = szDefExtension;
  985. ofn.nFilterIndex = 1; // nFilterIndex is 1-based
  986. ofn.lpstrFile = szFileName;
  987. ofn.nMaxFile = MAX_PATH;
  988. ofn.nMaxFileTitle = 0;
  989. ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  990. iReturn = GetSaveFileName (&ofn);
  991. //
  992. // Differentiate between *.htm and *.tsv
  993. //
  994. _wsplitpath(szFileName,NULL,NULL,NULL,szExt);
  995. if ( IDOK == iReturn ) {
  996. //
  997. // Create a file.
  998. //
  999. hFile = CreateFile (
  1000. szFileName,
  1001. GENERIC_READ | GENERIC_WRITE,
  1002. 0, // Not shared
  1003. NULL, // Security attributes
  1004. CREATE_NEW, // Query the user if file already exists.
  1005. FILE_ATTRIBUTE_NORMAL,
  1006. NULL );
  1007. if ( INVALID_HANDLE_VALUE == hFile ) {
  1008. dwCreateError = GetLastError();
  1009. if ( ERROR_SUCCESS != dwCreateError ) {
  1010. //
  1011. // Confirm file overwrite.
  1012. //
  1013. cchMessageBuf = lstrlen(szFileName) + RESOURCE_STRING_BUF_LEN + 1;
  1014. szMessage = new WCHAR [cchMessageBuf];
  1015. if ( NULL != szMessage ) {
  1016. StringCchPrintf(
  1017. szMessage,
  1018. cchMessageBuf,
  1019. ResourceString(IDS_HTML_FILE_OVERWRITE),
  1020. szFileName );
  1021. iOverwrite = MessageBox(
  1022. Window(),
  1023. szMessage,
  1024. ResourceString(IDS_APP_NAME),
  1025. MB_YESNO );
  1026. delete [] szMessage;
  1027. if ( IDYES == iOverwrite ) {
  1028. hFile = CreateFile (
  1029. szFileName,
  1030. GENERIC_READ | GENERIC_WRITE,
  1031. 0, // Not shared
  1032. NULL, // Security attributes
  1033. CREATE_ALWAYS, // Overwrite any existing file.
  1034. FILE_ATTRIBUTE_NORMAL,
  1035. NULL );
  1036. }
  1037. }
  1038. }
  1039. }
  1040. if ( INVALID_HANDLE_VALUE != hFile ) {
  1041. CWaitCursor cursorWait;
  1042. // Save the current configuration to the file.
  1043. if( (!_wcsicmp(szExt,ResourceString(IDS_HTM_EXTENSION)))
  1044. || (!_wcsicmp(szExt,ResourceString(IDS_HTML_EXTENSION))) ) {
  1045. // Html file
  1046. szByteOrderMark[0] = 0xFEFF;
  1047. szByteOrderMark[1] = L'\0';
  1048. bStatus = FileWrite ( hFile, szByteOrderMark, sizeof(WCHAR) );
  1049. if ( bStatus ) {
  1050. if (m_fRTL || (GetWindowLongPtr(Window(), GWL_EXSTYLE) & WS_EX_LAYOUTRTL) ) {
  1051. bStatus = FileWrite ( hFile, (PVOID)CGlobalString::m_cszHtmlFileHeaderRTL , lstrlen (CGlobalString::m_cszHtmlFileHeaderRTL ) * sizeof(WCHAR) );
  1052. }
  1053. else {
  1054. bStatus = FileWrite ( hFile, (PVOID)CGlobalString::m_cszHtmlFileHeader , lstrlen (CGlobalString::m_cszHtmlFileHeader ) * sizeof(WCHAR) );
  1055. }
  1056. }
  1057. if ( bStatus ) {
  1058. hr = CopyToBuffer ( pszTemp, dwByteCount );
  1059. if ( SUCCEEDED ( hr ) ) {
  1060. assert ( NULL != pszTemp );
  1061. assert ( 0 != dwByteCount );
  1062. bStatus = FileWrite ( hFile, pszTemp, dwByteCount );
  1063. delete [] pszTemp;
  1064. } else {
  1065. bStatus = FALSE;
  1066. SetLastError ( ERROR_OUTOFMEMORY );
  1067. }
  1068. }
  1069. if ( bStatus ) {
  1070. bStatus = FileWrite ( hFile, (PVOID)CGlobalString::m_cszHtmlFileFooter, lstrlen (CGlobalString::m_cszHtmlFileFooter) * sizeof(WCHAR) );
  1071. }
  1072. if ( !bStatus ) {
  1073. dwMsgStatus = GetLastError();
  1074. }
  1075. } else if (!_wcsicmp(szExt,ResourceString(IDS_TSV_EXTENSION))){
  1076. // Tsv file
  1077. bStatus = WriteFileReportHeader(hFile);
  1078. if (bStatus){
  1079. bStatus = m_pReport->WriteFileReport(hFile);
  1080. }
  1081. if (!bStatus){
  1082. dwMsgStatus = GetLastError();
  1083. }
  1084. }
  1085. bStatus = CloseHandle ( hFile );
  1086. } else {
  1087. dwMsgStatus = GetLastError();
  1088. }
  1089. if ( ERROR_SUCCESS != dwMsgStatus ) {
  1090. LPWSTR szSystemMessage = NULL;
  1091. cchMessageBuf = lstrlen(szFileName) + MAX_MESSAGE_LEN + RESOURCE_STRING_BUF_LEN + 1;
  1092. szSystemMessage = new WCHAR[MAX_MESSAGE_LEN + 1];
  1093. szMessage = new WCHAR [ cchMessageBuf ];
  1094. if ( NULL != szMessage && NULL != szSystemMessage ) {
  1095. StringCchPrintf(
  1096. szMessage,
  1097. cchMessageBuf,
  1098. ResourceString(IDS_SAVEAS_ERR),
  1099. szFileName );
  1100. FormatSystemMessage ( dwMsgStatus, szSystemMessage, MAX_MESSAGE_LEN );
  1101. StringCchCat(szMessage, cchMessageBuf, szSystemMessage );
  1102. MessageBox(Window(), szMessage, ResourceString(IDS_APP_NAME), MB_OK | MB_ICONSTOP);
  1103. }
  1104. if ( NULL != szMessage ) {
  1105. delete [] szMessage;
  1106. }
  1107. if ( NULL != szSystemMessage ) {
  1108. delete [] szSystemMessage;
  1109. }
  1110. }
  1111. } // else ignore if they canceled out
  1112. // Make sure correct window has the focus
  1113. AssignFocus();
  1114. return hr;
  1115. }
  1116. HRESULT
  1117. CSysmonControl::SaveData (
  1118. VOID
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. SaveData writes the data from the display to a binary log file for
  1123. later input as a data source.
  1124. Arguments:
  1125. None.
  1126. Return Value:
  1127. None.
  1128. --*/
  1129. {
  1130. HRESULT hr = S_OK;
  1131. DWORD dwStatus = ERROR_SUCCESS;
  1132. INT iReturn = IDCANCEL;
  1133. INT i;
  1134. OPENFILENAME ofn;
  1135. WCHAR szFileName[MAX_PATH+1];
  1136. WCHAR szFileFilter[RESOURCE_STRING_BUF_LEN];
  1137. WCHAR szDefExtension[RESOURCE_STRING_BUF_LEN];
  1138. WCHAR szDialogCaption[RESOURCE_STRING_BUF_LEN];
  1139. LONG lOrigFilterValue;
  1140. LPWSTR szSystemMessage = NULL;
  1141. //
  1142. // Initial directory is the current directory
  1143. //
  1144. szFileName[0] = TEXT('\0');
  1145. ZeroMemory(szFileFilter, sizeof ( szFileFilter ) );
  1146. ZeroMemory(&ofn, sizeof(ofn));
  1147. StringCchCopy(szFileFilter,
  1148. RESOURCE_STRING_BUF_LEN,
  1149. ResourceString (IDS_LOG_FILE));
  1150. StringCchCopy (szDefExtension,
  1151. RESOURCE_STRING_BUF_LEN,
  1152. ResourceString (IDS_LOG_FILE_EXTENSION));
  1153. StringCchCopy (szDialogCaption,
  1154. RESOURCE_STRING_BUF_LEN,
  1155. ResourceString (IDS_SAVE_DATA_CAPTION));
  1156. for( i = 0; szFileFilter[i]; i++ ){
  1157. if( szFileFilter[i] == TEXT('|') ){
  1158. szFileFilter[i] = 0;
  1159. }
  1160. }
  1161. for( i = 0; szDefExtension[i]; i++ ){
  1162. if( szDefExtension[i] == TEXT('|') ){
  1163. szDefExtension[i] = 0;
  1164. }
  1165. }
  1166. ofn.lStructSize = sizeof(ofn);
  1167. ofn.hwndOwner = Window();
  1168. ofn.hInstance = GetModuleHandle((LPCWSTR)TEXT("sysmon.ocx")) ; // Ignored if no template argument
  1169. ofn.lpstrFilter = szFileFilter;
  1170. ofn.lpstrDefExt = szDefExtension;
  1171. ofn.nFilterIndex = 1; // nFilterIndex is 1-based
  1172. ofn.lpstrFile = szFileName;
  1173. ofn.nMaxFile = MAX_PATH;
  1174. ofn.nMaxFileTitle = 0;
  1175. ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY |
  1176. OFN_OVERWRITEPROMPT | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
  1177. ofn.lpstrTitle = szDialogCaption;
  1178. ofn.lCustData = (DWORD_PTR)this;
  1179. ofn.lpfnHook = (LPOFNHOOKPROC) SaveDataDlgHookProc ;
  1180. ofn.lpTemplateName = MAKEINTRESOURCE(IDD_SAVEDATA_DLG) ;
  1181. lOrigFilterValue = GetSaveDataFilter ();
  1182. iReturn = GetSaveFileName (&ofn);
  1183. if ( IDOK == iReturn ) {
  1184. DWORD dwOutputLogType = PDH_LOG_TYPE_BINARY;
  1185. DWORD dwFilterCount; // copy all records within the timerange
  1186. PDH_TIME_INFO TimeInfo;
  1187. // get log type from file name
  1188. if (ofn.nFileExtension > 0) {
  1189. if (ofn.lpstrFile[ofn.nFileExtension] != 0) {
  1190. if (lstrcmpi (&ofn.lpstrFile[ofn.nFileExtension-1], ResourceString (IDS_CSV_EXTENSION)) == 0) {
  1191. dwOutputLogType = PDH_LOG_TYPE_CSV;
  1192. } else if (lstrcmpi (&ofn.lpstrFile[ofn.nFileExtension-1], ResourceString (IDS_TSV_EXTENSION)) == 0) {
  1193. dwOutputLogType = PDH_LOG_TYPE_TSV;
  1194. } // else use binary log format as default
  1195. } // else use binary log format as default
  1196. } // else use binary log format as default
  1197. // get timerange for this log
  1198. TimeInfo.StartTime = m_DataSourceInfo.llStartDisp;
  1199. TimeInfo.EndTime = m_DataSourceInfo.llStopDisp;
  1200. dwFilterCount = GetSaveDataFilter();
  1201. //
  1202. // Double check the filter count is not 0
  1203. //
  1204. if (dwFilterCount == 0) {
  1205. dwFilterCount = 1;
  1206. }
  1207. // now relog the data
  1208. dwStatus = RelogLogData ( ofn.lpstrFile, dwOutputLogType, TimeInfo, dwFilterCount);
  1209. } else {
  1210. dwStatus = CommDlgExtendedError();
  1211. if ( ERROR_SUCCESS != dwStatus ) {
  1212. if ( FNERR_BUFFERTOOSMALL == dwStatus ) {
  1213. dwStatus = ERROR_BUFFER_OVERFLOW;
  1214. } else {
  1215. dwStatus = ERROR_OUTOFMEMORY;
  1216. }
  1217. szSystemMessage = new WCHAR[MAX_MESSAGE_LEN];
  1218. if ( NULL != szSystemMessage ) {
  1219. if ( FormatSystemMessage (
  1220. dwStatus,
  1221. szSystemMessage,
  1222. MAX_MESSAGE_LEN ) )
  1223. {
  1224. MessageBox(
  1225. m_hWnd,
  1226. szSystemMessage,
  1227. ResourceString(IDS_APP_NAME),
  1228. MB_OK | MB_ICONERROR);
  1229. }
  1230. delete [] szSystemMessage;
  1231. }
  1232. }
  1233. //
  1234. // They canceled out or error occurred, so restore filter value
  1235. //
  1236. SetSaveDataFilter (lOrigFilterValue);
  1237. }
  1238. // Make sure correct window has the focus
  1239. AssignFocus();
  1240. return hr;
  1241. }
  1242. DWORD
  1243. CSysmonControl::RelogLogData (
  1244. LPCWSTR szOutputFile,
  1245. DWORD dwOutputLogType,
  1246. PDH_TIME_INFO pdhTimeInfo,
  1247. DWORD dwFilterCount
  1248. )
  1249. {
  1250. PDH_STATUS pdhStatus;
  1251. PDH_RELOG_INFO RelogInfo;
  1252. HLOG hLogIn;
  1253. //
  1254. // Initialize the relog information structure
  1255. //
  1256. ZeroMemory( &RelogInfo, sizeof(PDH_RELOG_INFO) );
  1257. RelogInfo.TimeInfo.StartTime = pdhTimeInfo.StartTime;
  1258. RelogInfo.TimeInfo.EndTime = pdhTimeInfo.EndTime;;
  1259. RelogInfo.TimeInfo.SampleCount = dwFilterCount;
  1260. RelogInfo.dwFileFormat = dwOutputLogType;
  1261. RelogInfo.dwFlags = PDH_LOG_WRITE_ACCESS | PDH_LOG_CREATE_ALWAYS;
  1262. RelogInfo.strLog = (LPWSTR)szOutputFile;
  1263. //
  1264. // Set query time range
  1265. //
  1266. PdhSetQueryTimeRange(m_hQuery, &pdhTimeInfo);
  1267. //
  1268. // Get the input data source
  1269. //
  1270. hLogIn = GetDataSourceHandle();
  1271. //
  1272. // Collect the performance data and write them into output file
  1273. //
  1274. pdhStatus = PdhRelog( hLogIn, &RelogInfo );
  1275. return pdhStatus;
  1276. }
  1277. BOOL
  1278. CSysmonControl::WriteFileReportHeader(HANDLE hFile){
  1279. BOOL bStatus = FALSE;
  1280. HRESULT hr = S_OK;
  1281. DWORD dwStatus = ERROR_SUCCESS;
  1282. SYSTEMTIME SysTime;
  1283. DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1 ;
  1284. WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1285. LPWSTR szHeader = NULL;
  1286. LPWSTR szDateTime = NULL;
  1287. LPWSTR szDataSource = NULL;
  1288. LPWSTR szTime = NULL;
  1289. LPWSTR szDate = NULL;
  1290. LPWSTR szValue = NULL;
  1291. LPWSTR szMiscBuf = NULL;
  1292. DWORD dwValueId = IDS_DEFAULT;
  1293. WCHAR szByteOrderMark[2];
  1294. ULONG ulLogListBufLen = 0;
  1295. INT cchTimeBufLen = 0;
  1296. INT cchDateBufLen = 0;
  1297. INT cchHeaderBufLen = 0;
  1298. INT cchMiscBufLen = 0;
  1299. //
  1300. // Computer name
  1301. //
  1302. if (!GetComputerName(szComputerName,&dwSize)){
  1303. szComputerName[0] = L'\0';
  1304. }
  1305. //
  1306. // Current date and time
  1307. //
  1308. GetLocalTime(&SysTime);
  1309. cchTimeBufLen = GetTimeFormat (m_lcidCurrent, 0, &SysTime, NULL, NULL, 0 ) ;
  1310. if ( 0 != cchTimeBufLen ) {
  1311. szTime = new WCHAR[cchTimeBufLen];
  1312. if ( NULL != szTime ) {
  1313. if ( 0 != GetTimeFormat (m_lcidCurrent, 0, &SysTime, NULL, szTime, cchTimeBufLen) ) {
  1314. bStatus = TRUE;
  1315. }
  1316. }
  1317. }
  1318. if ( bStatus ) {
  1319. bStatus = FALSE;
  1320. cchDateBufLen = GetDateFormat (m_lcidCurrent, DATE_SHORTDATE, &SysTime, NULL, NULL, 0 ) ;
  1321. if ( 0 != cchDateBufLen ) {
  1322. szDate = new WCHAR[cchDateBufLen];
  1323. if ( NULL != szTime ) {
  1324. if ( 0 != GetDateFormat (m_lcidCurrent, DATE_SHORTDATE, &SysTime, NULL, szDate, cchDateBufLen) ) {
  1325. bStatus = TRUE;
  1326. }
  1327. }
  1328. }
  1329. }
  1330. if ( bStatus ) {
  1331. bStatus = FALSE;
  1332. //
  1333. // Subtract 1 for extra null.
  1334. //
  1335. cchMiscBufLen = RESOURCE_STRING_BUF_LEN + cchDateBufLen + cchTimeBufLen - 1;
  1336. szDateTime = new WCHAR [cchMiscBufLen];
  1337. if ( NULL != szDateTime ) {
  1338. hr = StringCchPrintf(
  1339. szDateTime,
  1340. cchMiscBufLen,
  1341. ResourceString( IDS_REPORT_DATE_TIME ),
  1342. szDate,
  1343. szTime );
  1344. if ( SUCCEEDED ( hr ) ) {
  1345. bStatus = TRUE;
  1346. }
  1347. }
  1348. }
  1349. //
  1350. // Report value type
  1351. //
  1352. if ( bStatus ) {
  1353. bStatus = FALSE;
  1354. switch ( m_pObj->m_Graph.Options.iReportValueType ) {
  1355. case sysmonCurrentValue:
  1356. dwValueId = IDS_LAST;
  1357. break;
  1358. case sysmonAverage:
  1359. dwValueId = IDS_AVERAGE;
  1360. break;
  1361. case sysmonMinimum:
  1362. dwValueId = IDS_MINIMUM;
  1363. break;
  1364. case sysmonMaximum:
  1365. dwValueId = IDS_MAXIMUM;
  1366. break;
  1367. default:
  1368. dwValueId = IDS_DEFAULT;
  1369. }
  1370. //
  1371. // Add 1 for null.
  1372. //
  1373. cchMiscBufLen = ( RESOURCE_STRING_BUF_LEN * 2 ) + 1;
  1374. szValue = new WCHAR [cchMiscBufLen];
  1375. if ( NULL != szValue ) {
  1376. hr = StringCchPrintf(
  1377. szValue,
  1378. cchMiscBufLen,
  1379. ResourceString ( IDS_REPORT_VALUE_TYPE ),
  1380. ResourceString ( dwValueId ) );
  1381. if ( SUCCEEDED ( hr ) ) {
  1382. bStatus = TRUE;
  1383. }
  1384. }
  1385. }
  1386. //
  1387. // Data source
  1388. //
  1389. if ( bStatus ) {
  1390. bStatus = FALSE;
  1391. cchMiscBufLen = RESOURCE_STRING_BUF_LEN + 1;
  1392. if ( sysmonCurrentActivity == m_pObj->m_Graph.Options.iDataSourceType ) {
  1393. szDataSource = new WCHAR [cchMiscBufLen];
  1394. if ( NULL != szDataSource ) {
  1395. hr = StringCchCopy(
  1396. szDataSource,
  1397. cchMiscBufLen,
  1398. ResourceString(IDS_REPORT_REAL_TIME));
  1399. if ( SUCCEEDED ( hr ) ) {
  1400. bStatus = TRUE;
  1401. }
  1402. }
  1403. } else if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType ) {
  1404. dwStatus = BuildLogFileList (
  1405. NULL,
  1406. TRUE,
  1407. &ulLogListBufLen );
  1408. szDataSource = new WCHAR [ulLogListBufLen];
  1409. if ( NULL != szDataSource ) {
  1410. dwStatus = BuildLogFileList (
  1411. szDataSource,
  1412. TRUE,
  1413. &ulLogListBufLen );
  1414. if ( ERROR_SUCCESS == dwStatus ) {
  1415. bStatus = TRUE;
  1416. }
  1417. }
  1418. } else if ( sysmonSqlLog == m_pObj->m_Graph.Options.iDataSourceType ) {
  1419. dwStatus = FormatSqlDataSourceName (
  1420. m_DataSourceInfo.szSqlDsnName,
  1421. m_DataSourceInfo.szSqlLogSetName,
  1422. NULL,
  1423. &ulLogListBufLen );
  1424. if ( ERROR_SUCCESS == dwStatus ) {
  1425. szDataSource = new WCHAR [ulLogListBufLen];
  1426. if ( NULL != szDataSource ) {
  1427. dwStatus = FormatSqlDataSourceName (
  1428. m_DataSourceInfo.szSqlDsnName,
  1429. m_DataSourceInfo.szSqlLogSetName,
  1430. szDataSource,
  1431. &ulLogListBufLen );
  1432. if ( ERROR_SUCCESS == dwStatus ) {
  1433. bStatus = TRUE;
  1434. }
  1435. }
  1436. }
  1437. }
  1438. }
  1439. //
  1440. // Header
  1441. //
  1442. if ( bStatus ) {
  1443. bStatus = FALSE;
  1444. cchHeaderBufLen = lstrlenW(szComputerName)
  1445. + lstrlenW(szDateTime)
  1446. + lstrlenW(szValue)
  1447. + lstrlenW(szDataSource);
  1448. cchHeaderBufLen += RESOURCE_STRING_BUF_LEN; // IDS_REPORT_HEADER;
  1449. cchHeaderBufLen += RESOURCE_STRING_BUF_LEN; // IDS_REPORT_INTERVAL
  1450. cchHeaderBufLen += 10; // Max interval text length
  1451. cchHeaderBufLen += RESOURCE_STRING_BUF_LEN; // IDS_REPORT_LOG_START
  1452. cchHeaderBufLen += (cchDateBufLen + cchTimeBufLen); // Includes space, line end
  1453. cchHeaderBufLen += RESOURCE_STRING_BUF_LEN; // IDS_REPORT_LOG_STOP
  1454. cchHeaderBufLen += (cchDateBufLen + cchTimeBufLen); // Includes space
  1455. cchHeaderBufLen += (1 + 1); // Line end, NULL
  1456. szHeader = new WCHAR [cchHeaderBufLen];
  1457. if ( NULL != szHeader ) {
  1458. hr = StringCchPrintf(
  1459. szHeader,
  1460. cchHeaderBufLen,
  1461. ResourceString(IDS_REPORT_HEADER),
  1462. szComputerName,
  1463. szDateTime,
  1464. szValue,
  1465. szDataSource );
  1466. if ( SUCCEEDED ( hr ) ) {
  1467. bStatus = TRUE;
  1468. }
  1469. }
  1470. }
  1471. if ( bStatus ) {
  1472. bStatus = FALSE;
  1473. if ( sysmonCurrentActivity == m_pObj->m_Graph.Options.iDataSourceType ) {
  1474. //
  1475. // Sample interval, only for realtime data source.
  1476. //
  1477. cchMiscBufLen = RESOURCE_STRING_BUF_LEN + 10 + 1,
  1478. szMiscBuf = new WCHAR [cchMiscBufLen];
  1479. if ( NULL != szMiscBuf ) {
  1480. StringCchPrintf(
  1481. szMiscBuf,
  1482. cchMiscBufLen,
  1483. ResourceString(IDS_REPORT_INTERVAL),
  1484. m_pObj->m_Graph.Options.fUpdateInterval );
  1485. StringCchCat(szHeader, cchHeaderBufLen, szMiscBuf);
  1486. }
  1487. bStatus = TRUE;
  1488. } else if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType
  1489. || sysmonSqlLog == m_pObj->m_Graph.Options.iDataSourceType )
  1490. {
  1491. //
  1492. // Add start and stop string for log files or Sql logs.
  1493. //
  1494. cchMiscBufLen = RESOURCE_STRING_BUF_LEN * 2
  1495. + cchDateBufLen * 2
  1496. + cchTimeBufLen * 2
  1497. + 1 + 1;
  1498. szMiscBuf = new WCHAR [ cchMiscBufLen ];
  1499. if ( NULL != szMiscBuf ) {
  1500. FormatDateTime(m_DataSourceInfo.llStartDisp,szDate,szTime);
  1501. StringCchPrintf(
  1502. szMiscBuf,
  1503. cchMiscBufLen,
  1504. TEXT("%s%s %s\n"),
  1505. ResourceString(IDS_REPORT_LOG_START),
  1506. szDate,
  1507. szTime );
  1508. FormatDateTime(m_DataSourceInfo.llStopDisp,szDate,szTime);
  1509. StringCchCat(szMiscBuf, cchMiscBufLen, ResourceString(IDS_REPORT_LOG_STOP));
  1510. FormatDateTime(m_DataSourceInfo.llStopDisp,szDate,szTime);
  1511. StringCchCat(szMiscBuf, cchMiscBufLen, szDate);
  1512. StringCchCat(szMiscBuf, cchMiscBufLen, SpaceStr);
  1513. StringCchCat(szMiscBuf, cchMiscBufLen, szTime);
  1514. StringCchCat(szMiscBuf, cchMiscBufLen, LineEndStr);
  1515. StringCchCat(szHeader, cchHeaderBufLen, szMiscBuf);
  1516. bStatus = TRUE;
  1517. }
  1518. }
  1519. }
  1520. if ( bStatus ) {
  1521. szByteOrderMark[0] = 0xFEFF;
  1522. szByteOrderMark[1] = L'\0';
  1523. bStatus = FileWrite ( hFile, szByteOrderMark, sizeof(WCHAR) );
  1524. bStatus = FileWrite ( hFile, szHeader, lstrlen (szHeader) * sizeof(WCHAR) );
  1525. }
  1526. if ( NULL != szTime ) {
  1527. delete [] szTime;
  1528. }
  1529. if ( NULL != szDate ) {
  1530. delete [] szDate;
  1531. }
  1532. if ( NULL != szDateTime ) {
  1533. delete [] szDateTime;
  1534. }
  1535. if ( NULL != szValue ) {
  1536. delete [] szValue;
  1537. }
  1538. if ( NULL != szDataSource ) {
  1539. delete [] szDataSource;
  1540. }
  1541. if ( NULL != szHeader ) {
  1542. delete [] szHeader;
  1543. }
  1544. if ( NULL != szMiscBuf ) {
  1545. delete [] szMiscBuf;
  1546. }
  1547. return bStatus;
  1548. }
  1549. BOOL CSysmonControl::InitView (HWND hWndParent)
  1550. /*
  1551. Effect: Create the graph window. This window is a child of
  1552. hWndMain and is a container for the graph data,
  1553. graph label, graph legend, and graph status windows.
  1554. Note: We don't worry about the size here, as this window
  1555. will be resized whenever the main window is resized.
  1556. Note: This method initializes the control for rendering.
  1557. */
  1558. {
  1559. PCGraphItem pItem;
  1560. WNDCLASS wc ;
  1561. // Protect against multiple initializations
  1562. if (m_fViewInitialized)
  1563. return TRUE;
  1564. BEGIN_CRITICAL_SECTION
  1565. // Register the window class once
  1566. if (pstrRegisteredClasses[SYSMONCTRL_WNDCLASS] == NULL) {
  1567. wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
  1568. wc.lpfnWndProc = SysmonCtrlWndProc ;
  1569. wc.hInstance = g_hInstance ;
  1570. wc.cbClsExtra = 0 ;
  1571. wc.cbWndExtra = sizeof (PSYSMONCTRL) ;
  1572. wc.hIcon = NULL ;
  1573. wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
  1574. wc.hbrBackground = NULL ;
  1575. wc.lpszMenuName = NULL ;
  1576. wc.lpszClassName = szSysmonCtrlWndClass ;
  1577. if (RegisterClass (&wc)) {
  1578. pstrRegisteredClasses[SYSMONCTRL_WNDCLASS] = szSysmonCtrlWndClass;
  1579. }
  1580. }
  1581. END_CRITICAL_SECTION
  1582. if (pstrRegisteredClasses[SYSMONCTRL_WNDCLASS] == NULL)
  1583. return FALSE;
  1584. // Create our control window
  1585. m_hWnd = CreateWindow (szSysmonCtrlWndClass, // window class
  1586. NULL, // caption
  1587. WS_CHILD | WS_VISIBLE, // style for window
  1588. 0, 0, // initial position
  1589. m_pObj->m_RectExt.right, // width
  1590. m_pObj->m_RectExt.bottom, // height
  1591. hWndParent, // parent
  1592. NULL, // menu
  1593. g_hInstance, // program instance
  1594. (LPVOID)this) ; // user-supplied data
  1595. if (m_hWnd == NULL) {
  1596. // DWORD err = GetLastError();
  1597. return FALSE;
  1598. }
  1599. DragAcceptFiles (m_hWnd, TRUE) ;
  1600. // Subcomponents are allocated in AllocateSubcomponents
  1601. // Init the legend
  1602. if ( !m_pLegend
  1603. || !m_pGraphDisp
  1604. || !m_pStatsBar
  1605. || !m_pSnapBar
  1606. || !m_pToolbar
  1607. || !m_pReport )
  1608. {
  1609. return FALSE;
  1610. }
  1611. if (!m_pLegend->Init(this, m_hWnd))
  1612. return FALSE;
  1613. // Init the graph display
  1614. if (!m_pGraphDisp->Init(this, &m_pObj->m_Graph))
  1615. return FALSE;
  1616. // Init the statistics bar
  1617. if (!m_pStatsBar->Init(this, m_hWnd))
  1618. return FALSE;
  1619. // Init the snapshot bar
  1620. if (!m_pSnapBar->Init(this, m_hWnd))
  1621. return FALSE;
  1622. if (!m_pToolbar->Init(this, m_hWnd))
  1623. return FALSE;
  1624. // Init the report view
  1625. if (!m_pReport->Init(this, m_hWnd))
  1626. return FALSE;
  1627. m_fViewInitialized = TRUE;
  1628. // If counters are present
  1629. if ((pItem = FirstCounter()) != NULL) {
  1630. // Add counters to the legend and report view
  1631. while (pItem != NULL) {
  1632. m_pLegend->AddItem(pItem);
  1633. m_pReport->AddItem(pItem);
  1634. pItem = pItem->Next();
  1635. }
  1636. if ( NULL != m_pSelectedItem ) {
  1637. SelectCounter(m_pSelectedItem);
  1638. } else {
  1639. SelectCounter(FirstCounter());
  1640. }
  1641. if ( !m_bLogFileSource ) {
  1642. // Pass new time span to statistics bar. This must
  1643. // be done after initializing the stats bar.
  1644. m_pStatsBar->SetTimeSpan (
  1645. m_pObj->m_Graph.Options.fUpdateInterval
  1646. * m_pObj->m_Graph.Options.iDisplayFilter
  1647. * m_pHistCtrl->nMaxSamples );
  1648. }
  1649. }
  1650. // Processing the command line can add counters from the property bag.
  1651. // Add the counters after the counter addition and selection code above
  1652. // so that counters do not get added twice.
  1653. //
  1654. // Continue on failure of ProcessCommandLine. Error messages are displayed in that method.
  1655. //
  1656. ProcessCommandLine ( );
  1657. return TRUE;
  1658. }
  1659. BOOL CSysmonControl::Init (HWND hWndParent)
  1660. /*
  1661. Effect: Create the graph window. This window is a child of
  1662. hWndMain and is a container for the graph data,
  1663. graph label, graph legend, and graph status windows.
  1664. Note: We don't worry about the size here, as this window
  1665. will be resized whenever the main window is resized.
  1666. */
  1667. {
  1668. PCGraphItem pItem;
  1669. BOOL bResult = TRUE;
  1670. // Protect against multiple initializations
  1671. if (!m_fInitialized) {
  1672. bResult = InitView( hWndParent );
  1673. if ( !m_bSampleDataLoaded ) {
  1674. if ( bResult ) {
  1675. m_fInitialized = TRUE;
  1676. // When loaded from property bag or stream, the log file name is
  1677. // already set. If realtime query, the Pdh query might
  1678. // not have been opened.
  1679. if ( sysmonCurrentActivity == m_pObj->m_Graph.Options.iDataSourceType ) {
  1680. put_DataSourceType ( sysmonCurrentActivity );
  1681. }
  1682. // Load the accelerator table
  1683. m_hAccel = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(ID_SMONACCEL));
  1684. // If counters are present
  1685. if ((pItem = FirstCounter()) != NULL) {
  1686. if ( ERROR_SUCCESS != ActivateQuery() ) {
  1687. m_fInitialized = FALSE;
  1688. return FALSE;
  1689. }
  1690. }
  1691. }
  1692. }
  1693. }
  1694. //sync the toolbar last
  1695. if ( bResult ) {
  1696. m_pToolbar->SyncToolbar();
  1697. }
  1698. return bResult;
  1699. }
  1700. HRESULT CSysmonControl::LoadFromStream(LPSTREAM pIStream)
  1701. {
  1702. typedef struct _DATA_LIST_ELEM
  1703. {
  1704. GRAPHITEM_DATA3 itemData;
  1705. LPWSTR szCounterPath;
  1706. struct _DATA_LIST_ELEM* pNext;
  1707. } DATA_LIST_ELEM, *PDATA_LIST_ELEM;
  1708. HRESULT hr = S_OK;
  1709. ULONG bc;
  1710. GRAPH_OPTIONS *pOptions = &m_pObj->m_Graph.Options;
  1711. RECT RectExt;
  1712. SMONCTRL_VERSION_DATA VersionData;
  1713. LPWSTR szLogFilePath = NULL;
  1714. INT32 iLocalDataSourceType = (INT32)sysmonNullDataSource;
  1715. GRAPHCTRL_DATA3 CtrlData3;
  1716. ENUM_ADD_COUNTER_CALLBACK_INFO CallbackInfo;
  1717. PDATA_LIST_ELEM pFirstElem = NULL;
  1718. PDATA_LIST_ELEM pLastElem = NULL;
  1719. PDATA_LIST_ELEM pNewElem = NULL;
  1720. LPWSTR pszCounterPath = NULL;
  1721. LPWSTR szLocaleBuf = NULL;
  1722. DWORD dwLocaleBufSize = 0;
  1723. LPWSTR pszPath = NULL;
  1724. USES_CONVERSION
  1725. if (g_dwScriptPolicy == URLPOLICY_DISALLOW) {
  1726. return E_ACCESSDENIED;
  1727. }
  1728. if ( !m_bSettingsLoaded ) {
  1729. // Read in parameters
  1730. hr = pIStream->Read(&VersionData, sizeof(VersionData), &bc);
  1731. if (FAILED(hr))
  1732. return hr;
  1733. if (bc != sizeof(VersionData))
  1734. return E_FAIL;
  1735. //
  1736. // Windows2000 shipped as 3.3.
  1737. // XP shipped as 3.6.
  1738. //
  1739. // The code below assumes that Sysmon version is 3.6.
  1740. //
  1741. assert ( 3 == SMONCTRL_MAJ_VERSION );
  1742. assert ( 6 == SMONCTRL_MIN_VERSION );
  1743. // Read version 3 streams only.
  1744. if ( VersionData.iMajor < SMONCTRL_MAJ_VERSION )
  1745. return E_FAIL;
  1746. // Update the current loaded version number in order
  1747. // to warn the user appropriately when saving to stream.
  1748. m_LoadedVersion.iMajor = VersionData.iMajor;
  1749. m_LoadedVersion.iMinor = VersionData.iMinor;
  1750. assert( 256 == sizeof(CtrlData3) );
  1751. ZeroMemory ( &CtrlData3, sizeof ( CtrlData3 ) );
  1752. hr = pIStream->Read(&CtrlData3, sizeof(CtrlData3), &bc);
  1753. if (FAILED(hr))
  1754. return hr;
  1755. if (bc != sizeof(CtrlData3))
  1756. return E_FAIL;
  1757. // Setup extent info
  1758. SetRect(&RectExt, 0, 0, CtrlData3.iWidth, CtrlData3.iHeight);
  1759. m_pObj->RectConvertMappings(&RectExt, TRUE); // Convert from HIMETRIC
  1760. m_pObj->m_RectExt = RectExt;
  1761. SetCurrentClientRect( &RectExt );
  1762. // Load options settings in graph structure
  1763. pOptions->iVertMax = CtrlData3.iScaleMax;
  1764. pOptions->iVertMin = CtrlData3.iScaleMin;
  1765. pOptions->bLegendChecked = CtrlData3.bLegend;
  1766. pOptions->bToolbarChecked = CtrlData3.bToolbar;
  1767. pOptions->bLabelsChecked = CtrlData3.bLabels;
  1768. pOptions->bHorzGridChecked = CtrlData3.bHorzGrid;
  1769. pOptions->bVertGridChecked = CtrlData3.bVertGrid;
  1770. pOptions->bValueBarChecked = CtrlData3.bValueBar;
  1771. pOptions->bManualUpdate = CtrlData3.bManualUpdate;
  1772. pOptions->bHighlight = CtrlData3.bHighlight; // New for 3.1, default = 0
  1773. pOptions->bReadOnly = CtrlData3.bReadOnly; // New for 3.1+, default = 0
  1774. pOptions->bAmbientFont = CtrlData3.bAmbientFont; // New for 3.3+, new default = 1, but 0 for old files.
  1775. pOptions->bMonitorDuplicateInstances = CtrlData3.bMonitorDuplicateInstances;
  1776. pOptions->fUpdateInterval = CtrlData3.fUpdateInterval;
  1777. pOptions->iDisplayType = CtrlData3.iDisplayType;
  1778. pOptions->clrBackCtl = CtrlData3.clrBackCtl;
  1779. pOptions->clrFore = CtrlData3.clrFore;
  1780. pOptions->clrBackPlot = CtrlData3.clrBackPlot;
  1781. pOptions->iAppearance = CtrlData3.iAppearance;
  1782. pOptions->iBorderStyle = CtrlData3.iBorderStyle;
  1783. pOptions->iReportValueType = CtrlData3.iReportValueType; // New for 3.1+, default = 0
  1784. pOptions->iDisplayFilter = CtrlData3.iDisplayFilter; // New for 3.4, default = 1, 0 is invalid
  1785. iLocalDataSourceType = CtrlData3.iDataSourceType; // New for 3.4, default = 1, 0 is invalid
  1786. // Pre-3.4, set based on presence of log file name // Set pOptions->iDataSourceType below
  1787. if ( 0 == pOptions->iDisplayFilter ) {
  1788. // New for 3.4
  1789. assert ( ( SMONCTRL_MIN_VERSION - 2 ) > VersionData.iMinor );
  1790. pOptions->iDisplayFilter = 1;
  1791. }
  1792. // Grid and TimeBar saved to file as of version 3.1.
  1793. pOptions->clrGrid = CtrlData3.clrGrid;
  1794. pOptions->clrTimeBar = CtrlData3.clrTimeBar;
  1795. // Load font info if not using ambient font
  1796. if ( !pOptions->bAmbientFont ) {
  1797. hr = m_OleFont.LoadFromStream(pIStream);
  1798. if (FAILED(hr))
  1799. return hr;
  1800. }
  1801. // Read titles and log file name
  1802. // As of Version 3.2, title and log file name strings stored as Wide characters
  1803. // Log file name
  1804. hr = WideStringFromStream(pIStream, &szLogFilePath, CtrlData3.nFileNameLen);
  1805. if (FAILED(hr))
  1806. return hr;
  1807. // Graph title
  1808. hr = WideStringFromStream(pIStream, &pOptions->pszGraphTitle, CtrlData3.nGraphTitleLen);
  1809. if (FAILED(hr))
  1810. return hr;
  1811. // Y axis label
  1812. hr = WideStringFromStream(pIStream, &pOptions->pszYaxisTitle, CtrlData3.nYaxisTitleLen);
  1813. if (FAILED(hr))
  1814. return hr;
  1815. // Read display range
  1816. m_DataSourceInfo.llStartDisp = CtrlData3.llStartDisp;
  1817. m_DataSourceInfo.llStopDisp = CtrlData3.llStopDisp;
  1818. // Must put actual data source type after loading display range, before adding counters.
  1819. // Always set data source to null data source before adding data source names.
  1820. hr = put_DataSourceType ( sysmonNullDataSource );
  1821. if ( SUCCEEDED ( hr ) && NULL != szLogFilePath ) {
  1822. assert ( 0 == NumLogFiles() );
  1823. if ( L'\0' != szLogFilePath[0] ) {
  1824. if ( ( SMONCTRL_MIN_VERSION - 1 ) > VersionData.iMinor ) {
  1825. // 3.4 writes a single log file.
  1826. hr = AddSingleLogFile ( szLogFilePath );
  1827. } else {
  1828. // 3.5+ writes a multi_sz
  1829. hr = LoadLogFilesFromMultiSz ( szLogFilePath );
  1830. }
  1831. }
  1832. }
  1833. if ( NULL != szLogFilePath ) {
  1834. delete [] szLogFilePath;
  1835. }
  1836. // If version < 3.4, set data source type based on presence of log files.
  1837. if ( ( SMONCTRL_MIN_VERSION - 2 ) > VersionData.iMinor ) {
  1838. // DataSourceType is new for 3.4
  1839. if ( 0 == NumLogFiles() ) {
  1840. iLocalDataSourceType = sysmonCurrentActivity;
  1841. } else {
  1842. iLocalDataSourceType = sysmonLogFiles;
  1843. }
  1844. }
  1845. // Set scale max and min
  1846. m_pObj->m_Graph.Scale.SetMaxValue(pOptions->iVertMax);
  1847. m_pObj->m_Graph.Scale.SetMinValue(pOptions->iVertMin);
  1848. // Convert non-null OLE colors to real colors
  1849. if (pOptions->clrFore != NULL_COLOR)
  1850. OleTranslateColor(pOptions->clrFore, NULL, &m_clrFgnd);
  1851. if (pOptions->clrBackPlot != NULL_COLOR)
  1852. OleTranslateColor(pOptions->clrBackPlot, NULL, &m_clrBackPlot);
  1853. // NT 5 Beta 1 BackCtlColor can be NULL.
  1854. if (pOptions->clrBackCtl != NULL_COLOR)
  1855. OleTranslateColor(pOptions->clrBackCtl, NULL, &m_clrBackCtl);
  1856. OleTranslateColor(pOptions->clrGrid, NULL, &m_clrGrid);
  1857. OleTranslateColor(pOptions->clrTimeBar, NULL, &m_clrTimeBar);
  1858. // Handle other ambient properties
  1859. if ( NULL_APPEARANCE != pOptions->iAppearance )
  1860. put_Appearance( pOptions->iAppearance, FALSE );
  1861. if ( NULL_BORDERSTYLE != pOptions->iBorderStyle )
  1862. put_BorderStyle( pOptions->iBorderStyle, FALSE );
  1863. // Read legend data
  1864. hr = m_pLegend->LoadFromStream(pIStream);
  1865. if (FAILED(hr))
  1866. return hr;
  1867. //Load the counters
  1868. hr = S_OK;
  1869. // Load the counters into temporary storage, so that they can be added after the
  1870. // SQL name and future items are loaded
  1871. while (TRUE) {
  1872. pNewElem = new ( DATA_LIST_ELEM );
  1873. if ( NULL != pNewElem ) {
  1874. ZeroMemory ( pNewElem, sizeof ( DATA_LIST_ELEM ) );
  1875. // Add to end of list
  1876. pNewElem->pNext = NULL;
  1877. if ( NULL == pFirstElem ) {
  1878. pFirstElem = pNewElem;
  1879. pLastElem = pFirstElem;
  1880. } else if ( NULL == pLastElem ) {
  1881. pLastElem = pNewElem;
  1882. } else {
  1883. pLastElem->pNext = pNewElem;
  1884. pLastElem = pNewElem;
  1885. }
  1886. // Read in parameters
  1887. hr = pIStream->Read(&pNewElem->itemData, sizeof(GRAPHITEM_DATA3), &bc);
  1888. if ( SUCCEEDED ( hr ) ) {
  1889. if (bc == sizeof(GRAPHITEM_DATA3)) {
  1890. // Stop on null item (indicated by no path name)
  1891. if (pNewElem->itemData.m_nPathLength == 0) {
  1892. break;
  1893. }
  1894. } else {
  1895. hr = E_FAIL;
  1896. }
  1897. }
  1898. } else {
  1899. hr = E_OUTOFMEMORY;
  1900. }
  1901. if ( SUCCEEDED ( hr ) ) {
  1902. // As of Version 3.2, title and log file name strings stored as Wide characters
  1903. // Read in path name
  1904. hr = WideStringFromStream(pIStream, &pszCounterPath, pNewElem->itemData.m_nPathLength);
  1905. }
  1906. if ( SUCCEEDED ( hr ) ) {
  1907. pNewElem->szCounterPath = pszCounterPath;
  1908. pszCounterPath = NULL;
  1909. }
  1910. }
  1911. if ( NULL != pszCounterPath ) {
  1912. delete [] pszCounterPath;
  1913. pszCounterPath = NULL;
  1914. }
  1915. if ( FAILED ( hr ) ) {
  1916. while ( NULL != pFirstElem ) {
  1917. pNewElem = pFirstElem->pNext;
  1918. if ( NULL != pFirstElem->szCounterPath ) {
  1919. delete [] pFirstElem->szCounterPath;
  1920. }
  1921. delete pFirstElem;
  1922. pFirstElem = pNewElem;
  1923. }
  1924. return hr;
  1925. }
  1926. // Load SQL names from the stream
  1927. hr = WideStringFromStream(pIStream, &m_DataSourceInfo.szSqlDsnName, CtrlData3.iSqlDsnLen);
  1928. if ( FAILED ( hr ) )
  1929. return hr;
  1930. hr = WideStringFromStream(pIStream, &m_DataSourceInfo.szSqlLogSetName, CtrlData3.iSqlLogSetNameLen);
  1931. if (FAILED(hr))
  1932. return hr;
  1933. // Set the data source
  1934. hr = put_DataSourceType ( iLocalDataSourceType );
  1935. if (FAILED(hr)) {
  1936. if ( SMON_STATUS_LOG_FILE_SIZE_LIMIT == (DWORD)hr ) {
  1937. // TodoLogFiles: Check log file type. Only perfmon and circular
  1938. // binary logs are still limited to 1 GB.
  1939. // TodoLogFiles: Current query is already closed,
  1940. // so what can be done here?
  1941. } else {
  1942. DWORD dwStatus;
  1943. LPWSTR szLogFileList = NULL;
  1944. ULONG ulLogListBufLen= 0;
  1945. if ( sysmonLogFiles == iLocalDataSourceType ) {
  1946. dwStatus = BuildLogFileList ( NULL, TRUE, &ulLogListBufLen );
  1947. szLogFileList = new WCHAR[ulLogListBufLen];
  1948. if ( NULL != szLogFileList ) {
  1949. dwStatus = BuildLogFileList ( szLogFileList, TRUE, &ulLogListBufLen );
  1950. }
  1951. }
  1952. dwStatus = DisplayDataSourceError (
  1953. m_hWnd,
  1954. (DWORD)hr,
  1955. iLocalDataSourceType,
  1956. szLogFileList,
  1957. m_DataSourceInfo.szSqlDsnName,
  1958. m_DataSourceInfo.szSqlLogSetName );
  1959. if ( NULL != szLogFileList ) {
  1960. delete [] szLogFileList;
  1961. }
  1962. }
  1963. }
  1964. m_bLogFileSource = ( sysmonCurrentActivity != m_pObj->m_Graph.Options.iDataSourceType );
  1965. hr = S_OK;
  1966. // Load the counters from the temporary data storage.
  1967. m_bLoadingCounters = TRUE;
  1968. for ( pNewElem = pFirstElem; NULL != pNewElem; pNewElem = pNewElem->pNext ) {
  1969. DWORD dwBufSize;
  1970. LPWSTR pNewBuf;
  1971. PDH_STATUS pdhStatus;
  1972. CallbackInfo.pCtrl = this;
  1973. CallbackInfo.pFirstItem = NULL;
  1974. // Stop on null item (indicated by no path name)
  1975. if ( 0 == pNewElem->itemData.m_nPathLength ) {
  1976. break;
  1977. }
  1978. // Set up properties so AddCounter can use them
  1979. m_clrCounter = pNewElem->itemData.m_rgbColor;
  1980. m_iColorIndex = ColorToIndex (pNewElem->itemData.m_rgbColor);
  1981. m_iWidthIndex = WidthToIndex (pNewElem->itemData.m_iWidth);
  1982. m_iStyleIndex = StyleToIndex (pNewElem->itemData.m_iStyle);
  1983. m_iScaleFactor = pNewElem->itemData.m_iScaleFactor;
  1984. pszPath = pNewElem->szCounterPath;
  1985. //
  1986. // Initialize the locale path buffer
  1987. //
  1988. if (dwLocaleBufSize == 0) {
  1989. dwLocaleBufSize = PDH_MAX_COUNTER_PATH + 1;
  1990. szLocaleBuf = (LPWSTR) malloc(dwLocaleBufSize * sizeof(WCHAR));
  1991. if (szLocaleBuf == NULL) {
  1992. dwLocaleBufSize = 0;
  1993. }
  1994. }
  1995. if (szLocaleBuf != NULL) {
  1996. //
  1997. // Translate counter name from English to Localization
  1998. //
  1999. dwBufSize = dwLocaleBufSize;
  2000. pdhStatus = PdhTranslateLocaleCounter(
  2001. pNewElem->szCounterPath,
  2002. szLocaleBuf,
  2003. &dwBufSize);
  2004. if (pdhStatus == PDH_MORE_DATA) {
  2005. pNewBuf = (LPWSTR) realloc(szLocaleBuf, dwBufSize * sizeof(WCHAR));
  2006. if (pNewBuf != NULL) {
  2007. szLocaleBuf = pNewBuf;
  2008. dwLocaleBufSize = dwBufSize;
  2009. pdhStatus = PdhTranslateLocaleCounter(
  2010. pNewElem->szCounterPath,
  2011. szLocaleBuf,
  2012. &dwBufSize);
  2013. }
  2014. }
  2015. if (pdhStatus == ERROR_SUCCESS) {
  2016. pszPath = szLocaleBuf;
  2017. }
  2018. }
  2019. // Add new counter to control
  2020. EnumExpandedPath (GetDataSourceHandle(),
  2021. pszPath,
  2022. AddCounterCallback,
  2023. &CallbackInfo );
  2024. }
  2025. if (szLocaleBuf != NULL) {
  2026. free(szLocaleBuf);
  2027. }
  2028. m_bLoadingCounters = FALSE;
  2029. while ( NULL != pFirstElem ) {
  2030. pNewElem = pFirstElem->pNext;
  2031. if ( NULL != pFirstElem->szCounterPath ) {
  2032. delete [] pFirstElem->szCounterPath;
  2033. }
  2034. delete pFirstElem;
  2035. pFirstElem = pNewElem;
  2036. }
  2037. if ( SMONCTRL_MAJ_VERSION == VersionData.iMajor
  2038. && SMONCTRL_MIN_VERSION == VersionData.iMinor ) {
  2039. m_pObj->m_fDirty=FALSE;
  2040. } else {
  2041. m_pObj->m_fDirty=TRUE;
  2042. }
  2043. if ( SMONCTRL_MIN_VERSION == VersionData.iMinor ) {
  2044. // New for 3.6: Save visuals to the stream
  2045. // These must be loaded after the counters are loaded.
  2046. m_iColorIndex = CtrlData3.iColorIndex;
  2047. m_iWidthIndex = CtrlData3.iWidthIndex;
  2048. m_iStyleIndex = CtrlData3.iStyleIndex;
  2049. }
  2050. } // Settings not loaded yet.
  2051. return hr;
  2052. }
  2053. HRESULT
  2054. CSysmonControl::SaveToStream(LPSTREAM pIStream)
  2055. {
  2056. HRESULT hr = NOERROR;
  2057. DWORD dwStatus = ERROR_SUCCESS;
  2058. GRAPH_OPTIONS *pOptions = &m_pObj->m_Graph.Options;
  2059. RECT RectExt;
  2060. SMONCTRL_VERSION_DATA VersionData;
  2061. LPWSTR pszWideGraphTitle;
  2062. LPWSTR pszWideYaxisTitle;
  2063. PCMachineNode pMachine;
  2064. PCObjectNode pObject;
  2065. PCInstanceNode pInstance;
  2066. PCGraphItem pItem;
  2067. PCCounterNode pCounter;
  2068. ULONG ulLogFileListLen = 0;
  2069. LPWSTR szLogFileList = NULL;
  2070. GRAPHCTRL_DATA3 CtrlData3;
  2071. USES_CONVERSION
  2072. assert( 256 == sizeof(CtrlData3) );
  2073. ZeroMemory( &CtrlData3, 256 );
  2074. //Store extent data in HIMETRIC format
  2075. RectExt = m_pObj->m_RectExt;
  2076. m_pObj->RectConvertMappings(&RectExt, FALSE);
  2077. CtrlData3.iWidth = RectExt.right - RectExt.left;
  2078. CtrlData3.iHeight = RectExt.bottom - RectExt.top;
  2079. // Store options settings in structure
  2080. CtrlData3.iScaleMax = pOptions->iVertMax;
  2081. CtrlData3.iScaleMin = pOptions->iVertMin;
  2082. CtrlData3.bLegend = pOptions->bLegendChecked;
  2083. CtrlData3.bToolbar = pOptions->bToolbarChecked;
  2084. CtrlData3.bLabels = pOptions->bLabelsChecked;
  2085. CtrlData3.bHorzGrid = pOptions->bHorzGridChecked;
  2086. CtrlData3.bVertGrid = pOptions->bVertGridChecked;
  2087. CtrlData3.bValueBar = pOptions->bValueBarChecked;
  2088. CtrlData3.bManualUpdate = pOptions->bManualUpdate;
  2089. CtrlData3.bHighlight = pOptions->bHighlight;
  2090. CtrlData3.bReadOnly = pOptions->bReadOnly;
  2091. CtrlData3.bMonitorDuplicateInstances = pOptions->bMonitorDuplicateInstances;
  2092. CtrlData3.bAmbientFont = pOptions->bAmbientFont;
  2093. CtrlData3.fUpdateInterval = pOptions->fUpdateInterval;
  2094. CtrlData3.iDisplayType = pOptions->iDisplayType;
  2095. CtrlData3.iReportValueType = pOptions->iReportValueType;
  2096. CtrlData3.clrBackCtl = pOptions->clrBackCtl;
  2097. CtrlData3.clrFore = pOptions->clrFore;
  2098. CtrlData3.clrBackPlot = pOptions->clrBackPlot;
  2099. CtrlData3.iAppearance = pOptions->iAppearance;
  2100. CtrlData3.iBorderStyle = pOptions->iBorderStyle;
  2101. CtrlData3.clrGrid = pOptions->clrGrid;
  2102. CtrlData3.clrTimeBar = pOptions->clrTimeBar;
  2103. CtrlData3.iDisplayFilter = pOptions->iDisplayFilter;
  2104. CtrlData3.iDataSourceType = pOptions->iDataSourceType;
  2105. // Store the visuals in pOptions if they become visible
  2106. // via the programming interface.
  2107. CtrlData3.iColorIndex = m_iColorIndex;
  2108. CtrlData3.iWidthIndex = m_iWidthIndex;
  2109. CtrlData3.iStyleIndex = m_iStyleIndex;
  2110. // NT 5 Beta 1 BackColorCtl can be NULL.
  2111. if ( NULL_COLOR == pOptions->clrBackCtl )
  2112. CtrlData3.clrBackCtl = m_clrBackCtl;
  2113. // Save number of samples to keep
  2114. CtrlData3.nSamples = m_pHistCtrl->nMaxSamples;
  2115. // Store Wide string lengths
  2116. pszWideGraphTitle = pOptions->pszGraphTitle;
  2117. CtrlData3.nGraphTitleLen = (pszWideGraphTitle == NULL) ?
  2118. 0 : lstrlen(pszWideGraphTitle);
  2119. pszWideYaxisTitle = pOptions->pszYaxisTitle;
  2120. CtrlData3.nYaxisTitleLen = (pszWideYaxisTitle == NULL) ?
  2121. 0 : lstrlen(pszWideYaxisTitle);
  2122. BuildLogFileList ( NULL, FALSE, &ulLogFileListLen );
  2123. CtrlData3.nFileNameLen = (INT32) ulLogFileListLen;
  2124. CtrlData3.iSqlDsnLen = 0;
  2125. if ( NULL != m_DataSourceInfo.szSqlDsnName ) {
  2126. CtrlData3.iSqlDsnLen = lstrlen ( m_DataSourceInfo.szSqlDsnName );
  2127. }
  2128. CtrlData3.iSqlLogSetNameLen = 0;
  2129. if ( NULL != m_DataSourceInfo.szSqlLogSetName ) {
  2130. CtrlData3.iSqlLogSetNameLen = lstrlen ( m_DataSourceInfo.szSqlLogSetName );
  2131. }
  2132. // Store other file info
  2133. CtrlData3.llStartDisp = m_DataSourceInfo.llStartDisp;
  2134. CtrlData3.llStopDisp = m_DataSourceInfo.llStopDisp;
  2135. // Write version info
  2136. VersionData.iMajor = SMONCTRL_MAJ_VERSION;
  2137. VersionData.iMinor = SMONCTRL_MIN_VERSION;
  2138. hr = pIStream->Write(&VersionData, sizeof(VersionData), NULL);
  2139. if (FAILED(hr))
  2140. return hr;
  2141. // Write control data
  2142. hr = pIStream->Write(&CtrlData3, sizeof(CtrlData3), NULL);
  2143. if (FAILED(hr))
  2144. return hr;
  2145. // Write font info if not using ambient font
  2146. if ( !pOptions->bAmbientFont ) {
  2147. hr = m_OleFont.SaveToStream(pIStream, TRUE);
  2148. if (FAILED(hr))
  2149. return hr;
  2150. }
  2151. // Write log file name
  2152. if (CtrlData3.nFileNameLen != 0) {
  2153. szLogFileList = new WCHAR[ulLogFileListLen];
  2154. if ( NULL != szLogFileList ) {
  2155. dwStatus = BuildLogFileList (
  2156. szLogFileList,
  2157. FALSE,
  2158. &ulLogFileListLen );
  2159. if ( ERROR_SUCCESS != dwStatus ) {
  2160. hr = E_FAIL;
  2161. }
  2162. } else {
  2163. hr = E_OUTOFMEMORY;
  2164. }
  2165. if ( SUCCEEDED ( hr ) ) {
  2166. hr = pIStream->Write(szLogFileList, CtrlData3.nFileNameLen*sizeof(WCHAR), NULL);
  2167. }
  2168. if ( NULL != szLogFileList ) {
  2169. delete [] szLogFileList;
  2170. szLogFileList = NULL;
  2171. }
  2172. if (FAILED(hr))
  2173. return hr;
  2174. }
  2175. // Write titles
  2176. if (CtrlData3.nGraphTitleLen != 0) {
  2177. hr = pIStream->Write(pszWideGraphTitle, CtrlData3.nGraphTitleLen*sizeof(WCHAR), NULL);
  2178. if (FAILED(hr))
  2179. return hr;
  2180. }
  2181. if (CtrlData3.nYaxisTitleLen != 0) {
  2182. hr = pIStream->Write(pszWideYaxisTitle, CtrlData3.nYaxisTitleLen*sizeof(WCHAR), NULL);
  2183. if (FAILED(hr))
  2184. return hr;
  2185. }
  2186. // Write legend data
  2187. hr = m_pLegend->SaveToStream(pIStream);
  2188. if (FAILED(hr))
  2189. return hr;
  2190. // Save all counter info
  2191. // Explicit counters first, followed by "All Instance" groups
  2192. for ( pMachine = CounterTree()->FirstMachine();
  2193. pMachine;
  2194. pMachine = pMachine->Next()) {
  2195. for ( pObject = pMachine->FirstObject();
  2196. pObject;
  2197. pObject = pObject->Next()) {
  2198. // Clear generated pointer for all object's counters
  2199. for ( pCounter = pObject->FirstCounter();
  2200. pCounter;
  2201. pCounter = pCounter->Next()) {
  2202. pCounter->m_pFirstGenerated = NULL;
  2203. }
  2204. for ( pInstance = pObject->FirstInstance();
  2205. pInstance;
  2206. pInstance = pInstance->Next()) {
  2207. for ( pItem = pInstance->FirstItem();
  2208. pItem;
  2209. pItem = pItem->m_pNextItem) {
  2210. // If item is the first generated one for this counter
  2211. // then save it as the wild card model for this counter
  2212. if (pItem->m_fGenerated) {
  2213. if (pItem->Counter()->m_pFirstGenerated == NULL)
  2214. pItem->Counter()->m_pFirstGenerated = pItem;
  2215. }
  2216. else {
  2217. // else save it explictly
  2218. hr = pItem->SaveToStream(pIStream, FALSE, VersionData.iMajor, VersionData.iMinor);
  2219. if (FAILED(hr))
  2220. return hr;
  2221. }
  2222. }
  2223. }
  2224. // Now go through counters again and store a wildcard path
  2225. // for any that have genererated counters
  2226. for (pCounter = pObject->FirstCounter();
  2227. pCounter;
  2228. pCounter = pCounter->Next()) {
  2229. if (pCounter->m_pFirstGenerated) {
  2230. hr = pCounter->m_pFirstGenerated->SaveToStream(pIStream, TRUE, VersionData.iMajor, VersionData.iMinor);
  2231. if (FAILED(hr))
  2232. return hr;
  2233. }
  2234. }
  2235. }
  2236. }
  2237. // Write null item to mark end of counter items
  2238. hr = CGraphItem::NullItemToStream(pIStream, VersionData.iMajor, VersionData.iMinor);
  2239. // Write Sql data source names
  2240. if (CtrlData3.iSqlDsnLen != 0) {
  2241. hr = pIStream->Write(m_DataSourceInfo.szSqlDsnName, CtrlData3.iSqlDsnLen*sizeof(WCHAR), NULL);
  2242. }
  2243. if (CtrlData3.iSqlLogSetNameLen != 0) {
  2244. hr = pIStream->Write(m_DataSourceInfo.szSqlLogSetName, CtrlData3.iSqlLogSetNameLen*sizeof(WCHAR), NULL);
  2245. }
  2246. return hr;
  2247. }
  2248. HRESULT
  2249. CSysmonControl::LoadLogFilesFromPropertyBag (
  2250. IPropertyBag* pIPropBag,
  2251. IErrorLog* pIErrorLog )
  2252. {
  2253. HRESULT hr = S_OK;
  2254. HRESULT hrErr = S_OK;
  2255. INT iLogFileCount = 0;
  2256. INT iIndex;
  2257. INT iBufSize = 0;
  2258. INT iPrevBufSize = 0;
  2259. LPWSTR pszLogFilePath = NULL;
  2260. INT iLogFilePathBufSize = 0;
  2261. WCHAR szLogFilePropName[32];
  2262. eDataSourceTypeConstant ePrevDataSourceType;
  2263. DWORD dwErrorPathListLen;
  2264. LPCWSTR szErrorPathList = NULL;
  2265. LPWSTR szMessage = NULL;
  2266. get_DataSourceType ( ePrevDataSourceType );
  2267. ClearErrorPathList();
  2268. hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszLogFileName, NULL, iBufSize );
  2269. if ( SUCCEEDED(hr) &&
  2270. iBufSize > 0 ) {
  2271. pszLogFilePath = new WCHAR[iBufSize + 1];
  2272. if ( NULL != pszLogFilePath ) {
  2273. hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszLogFileName, pszLogFilePath, iBufSize );
  2274. } else {
  2275. hr = E_OUTOFMEMORY;
  2276. }
  2277. if ( SUCCEEDED ( hr ) ) {
  2278. // Always set the log source to null data source before modifying the log file list.
  2279. // TodoLogFiles: This can leave the user with state different than before, in the
  2280. // case of log file load failure.
  2281. hr = put_DataSourceType ( sysmonNullDataSource );
  2282. if ( SUCCEEDED ( hr ) ) {
  2283. assert ( 0 == NumLogFiles() );
  2284. hr = AddSingleLogFile ( pszLogFilePath );
  2285. }
  2286. }
  2287. if ( FAILED ( hr ) && NULL != pszLogFilePath ) {
  2288. hrErr = hr;
  2289. AddToErrorPathList ( pszLogFilePath );
  2290. }
  2291. if ( NULL != pszLogFilePath ) {
  2292. delete [] pszLogFilePath;
  2293. pszLogFilePath = NULL;
  2294. }
  2295. } else {
  2296. hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszLogFileCount, iLogFileCount );
  2297. if ( SUCCEEDED( hr ) && 0 < iLogFileCount ) {
  2298. assert ( 0 == NumLogFiles() );
  2299. for ( iIndex = 1; iIndex <= iLogFileCount; iIndex++ ) {
  2300. // Todo: log file list error message, as for counters
  2301. // If one of the log files fails to load, continue loading others.
  2302. hr = NOERROR;
  2303. StringCchPrintf(szLogFilePropName,
  2304. 32,
  2305. CGlobalString::m_cszLogNameFormat,
  2306. CGlobalString::m_cszLogFileName,
  2307. iIndex );
  2308. iPrevBufSize = iBufSize;
  2309. hr = StringFromPropertyBag (
  2310. pIPropBag,
  2311. pIErrorLog,
  2312. szLogFilePropName,
  2313. pszLogFilePath,
  2314. iBufSize );
  2315. if ( iBufSize > iPrevBufSize ) {
  2316. if ( NULL == pszLogFilePath || (iBufSize > iLogFilePathBufSize) ) {
  2317. if ( NULL != pszLogFilePath ) {
  2318. delete [] pszLogFilePath;
  2319. pszLogFilePath = 0;
  2320. }
  2321. pszLogFilePath = new WCHAR[iBufSize];
  2322. if ( NULL != pszLogFilePath ) {
  2323. iLogFilePathBufSize = iBufSize;
  2324. }
  2325. }
  2326. if ( NULL != pszLogFilePath ) {
  2327. hr = StringFromPropertyBag (
  2328. pIPropBag,
  2329. pIErrorLog,
  2330. szLogFilePropName,
  2331. pszLogFilePath,
  2332. iBufSize );
  2333. } else {
  2334. hr = E_OUTOFMEMORY;
  2335. }
  2336. }
  2337. if ( SUCCEEDED(hr)
  2338. && MAX_PATH >= lstrlen(pszLogFilePath) ) {
  2339. hr = put_DataSourceType ( sysmonNullDataSource );
  2340. if ( SUCCEEDED ( hr ) ) {
  2341. hr = AddSingleLogFile ( pszLogFilePath );
  2342. }
  2343. }
  2344. if ( FAILED (hr) && SMON_STATUS_DUPL_LOG_FILE_PATH != (DWORD)hr )
  2345. {
  2346. if ( S_OK == hrErr ) {
  2347. hrErr = hr;
  2348. }
  2349. AddToErrorPathList ( pszLogFilePath );
  2350. }
  2351. }
  2352. }
  2353. }
  2354. if ( NULL != pszLogFilePath ) {
  2355. delete [] pszLogFilePath;
  2356. pszLogFilePath = NULL;
  2357. }
  2358. if ( SMON_STATUS_DUPL_LOG_FILE_PATH != (DWORD)hr ) {
  2359. szErrorPathList = GetErrorPathList ( &dwErrorPathListLen );
  2360. if ( NULL != szErrorPathList ) {
  2361. // Report error, but continue.
  2362. szMessage = new WCHAR [dwErrorPathListLen + RESOURCE_STRING_BUF_LEN + 1];
  2363. if ( NULL != szMessage ) {
  2364. StringCchPrintf(szMessage,
  2365. dwErrorPathListLen + MAX_PATH,
  2366. ResourceString(IDS_ADD_LOG_FILE_ERR),
  2367. szErrorPathList );
  2368. MessageBox (
  2369. m_hWnd,
  2370. szMessage,
  2371. ResourceString(IDS_APP_NAME),
  2372. MB_OK | MB_ICONEXCLAMATION );
  2373. delete [] szMessage;
  2374. }
  2375. }
  2376. }
  2377. ClearErrorPathList();
  2378. return hrErr;
  2379. }
  2380. HRESULT
  2381. CSysmonControl::LoadCountersFromPropertyBag (
  2382. IPropertyBag* pIPropBag,
  2383. IErrorLog* pIErrorLog,
  2384. BOOL bLoadData )
  2385. {
  2386. HRESULT hr = S_OK;
  2387. HRESULT hrErr = S_OK;
  2388. INT iCounterCount = 0;
  2389. INT iSampleCount = 0;
  2390. INT intValue;
  2391. INT iIndex;
  2392. INT iBufSize = 0;
  2393. INT iPrevBufSize = 0;
  2394. LPWSTR pszCounterPath = NULL;
  2395. INT iCounterPathBufSize = 0;
  2396. LPWSTR szSelected = NULL;
  2397. INT nBufferSize = 0;
  2398. WCHAR szPathPropName[32];
  2399. LPWSTR szEnglishBuf = NULL;
  2400. DWORD dwEnglishBufSize = 0;
  2401. LPWSTR pszPath = NULL;
  2402. DWORD dwBufSize;
  2403. LPWSTR pNewBuf;
  2404. PDH_STATUS pdhStatus;
  2405. PCGraphItem pItem = NULL;
  2406. DWORD dwCounterListLen = 0;
  2407. LPCWSTR szCounterList = NULL;
  2408. hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszCounterCount, iCounterCount );
  2409. if ( SUCCEEDED( hr ) && 0 < iCounterCount ) {
  2410. szSelected = NULL;
  2411. do {
  2412. if (szSelected) {
  2413. delete [] szSelected;
  2414. szSelected = NULL;
  2415. nBufferSize = iBufSize;
  2416. }
  2417. else {
  2418. nBufferSize = PDH_MAX_COUNTER_PATH + 1;
  2419. iBufSize = nBufferSize;
  2420. }
  2421. szSelected = new WCHAR [nBufferSize];
  2422. if (szSelected == NULL) {
  2423. return E_OUTOFMEMORY;
  2424. }
  2425. hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszSelected, szSelected, iBufSize );
  2426. } while (SUCCEEDED(hr) && iBufSize > nBufferSize);
  2427. if( SUCCEEDED( hr ) ){
  2428. //
  2429. // Initialize the locale path buffer
  2430. //
  2431. if (dwEnglishBufSize == 0) {
  2432. dwEnglishBufSize = PDH_MAX_COUNTER_PATH + 1;
  2433. szEnglishBuf = (LPWSTR) malloc(dwEnglishBufSize * sizeof(WCHAR));
  2434. if (szEnglishBuf == NULL) {
  2435. dwEnglishBufSize = 0;
  2436. }
  2437. }
  2438. if (szEnglishBuf != NULL) {
  2439. //
  2440. // Translate counter name from Localization into English
  2441. //
  2442. dwBufSize = dwEnglishBufSize;
  2443. pdhStatus = PdhTranslate009Counter(
  2444. szSelected,
  2445. szEnglishBuf,
  2446. &dwBufSize);
  2447. if (pdhStatus == PDH_MORE_DATA) {
  2448. pNewBuf = (LPWSTR)realloc(szEnglishBuf, dwBufSize * sizeof(WCHAR));
  2449. if (pNewBuf != NULL) {
  2450. szEnglishBuf = pNewBuf;
  2451. dwEnglishBufSize = dwBufSize;
  2452. pdhStatus = PdhTranslate009Counter(
  2453. szSelected,
  2454. szEnglishBuf,
  2455. &dwBufSize);
  2456. }
  2457. }
  2458. if (pdhStatus == ERROR_SUCCESS && (LONG)dwBufSize < lstrlen(szSelected) ) {
  2459. StringCchCopy(szSelected, nBufferSize, szEnglishBuf);
  2460. }
  2461. }
  2462. }
  2463. }
  2464. if ( bLoadData ) {
  2465. hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszSampleCount, iSampleCount );
  2466. if ( SUCCEEDED(hr) && ( 0 < iSampleCount ) ) {
  2467. intValue = 0;
  2468. hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszSampleIndex, intValue );
  2469. if ( SUCCEEDED(hr) && intValue > 0 && intValue <= iSampleCount ) {
  2470. INT iStepNum;
  2471. hr = IntegerFromPropertyBag (
  2472. pIPropBag,
  2473. pIErrorLog,
  2474. CGlobalString::m_cszStepNumber, iStepNum );
  2475. if ( SUCCEEDED(hr) ) {
  2476. // If data has been passed, freeze the view.
  2477. // These values are set only if all three values are present in the property bag.
  2478. put_ManualUpdate( TRUE );
  2479. // MaxSamples hardcoded for NT5
  2480. m_pHistCtrl->nSamples = iSampleCount;
  2481. m_pHistCtrl->iCurrent = intValue;
  2482. m_pObj->m_Graph.TimeStepper.StepTo(iStepNum);
  2483. m_bSampleDataLoaded = TRUE;
  2484. }
  2485. }
  2486. }
  2487. } else {
  2488. iSampleCount = 0;
  2489. }
  2490. iBufSize = 0;
  2491. ClearErrorPathList();
  2492. for ( iIndex = 1; iIndex <= iCounterCount; iIndex++ ) {
  2493. // If one of the counters fails to load, continue loading others.
  2494. hr = NOERROR;
  2495. StringCchPrintf(szPathPropName, 32, L"%s%05d.Path", CGlobalString::m_cszCounter, iIndex );
  2496. iPrevBufSize = iBufSize;
  2497. hr = StringFromPropertyBag (
  2498. pIPropBag,
  2499. pIErrorLog,
  2500. szPathPropName,
  2501. pszCounterPath,
  2502. iBufSize );
  2503. if ( iBufSize > iPrevBufSize ) {
  2504. if ( NULL == pszCounterPath || (iBufSize > iCounterPathBufSize) ) {
  2505. if ( NULL != pszCounterPath ) {
  2506. delete [] pszCounterPath;
  2507. iCounterPathBufSize = 0;
  2508. }
  2509. pszCounterPath = new WCHAR[iBufSize];
  2510. if ( NULL != pszCounterPath ) {
  2511. iCounterPathBufSize = iBufSize;
  2512. }
  2513. }
  2514. if ( NULL != pszCounterPath ) {
  2515. hr = StringFromPropertyBag (
  2516. pIPropBag,
  2517. pIErrorLog,
  2518. szPathPropName,
  2519. pszCounterPath,
  2520. iBufSize );
  2521. } else {
  2522. hr = E_OUTOFMEMORY;
  2523. }
  2524. }
  2525. pszPath = pszCounterPath;
  2526. if ( SUCCEEDED(hr) ) {
  2527. //
  2528. // Translate English counter name into localized counter name
  2529. //
  2530. if (dwEnglishBufSize == 0) {
  2531. dwEnglishBufSize = PDH_MAX_COUNTER_PATH + 1;
  2532. szEnglishBuf = (LPWSTR) malloc(dwEnglishBufSize * sizeof(WCHAR));
  2533. if (szEnglishBuf == NULL) {
  2534. dwEnglishBufSize = 0;
  2535. }
  2536. }
  2537. if (szEnglishBuf != NULL) {
  2538. //
  2539. // Translate counter name from English to Localization
  2540. //
  2541. dwBufSize = dwEnglishBufSize;
  2542. pdhStatus = PdhTranslateLocaleCounter(
  2543. pszCounterPath,
  2544. szEnglishBuf,
  2545. &dwBufSize);
  2546. if (pdhStatus == PDH_MORE_DATA) {
  2547. pNewBuf = (LPWSTR) realloc(szEnglishBuf, dwBufSize * sizeof(WCHAR));
  2548. if (pNewBuf != NULL) {
  2549. szEnglishBuf = pNewBuf;
  2550. dwEnglishBufSize = dwBufSize;
  2551. pdhStatus = PdhTranslateLocaleCounter(
  2552. pszCounterPath,
  2553. szEnglishBuf,
  2554. &dwBufSize);
  2555. }
  2556. }
  2557. if (pdhStatus == ERROR_SUCCESS) {
  2558. pszPath = szEnglishBuf;
  2559. }
  2560. }
  2561. hr = AddCounter ( pszPath, &pItem );
  2562. // Return status of the first failed counter.
  2563. if ( FAILED ( hr ) && SMON_STATUS_DUPL_COUNTER_PATH != (DWORD)hr ) {
  2564. if ( S_OK == hrErr ) {
  2565. hrErr = hr;
  2566. }
  2567. }
  2568. } else {
  2569. hr = E_FAIL;
  2570. if ( S_OK == hrErr ) {
  2571. hrErr = E_FAIL;
  2572. }
  2573. }
  2574. if ( SUCCEEDED(hr) ) {
  2575. assert ( NULL != pItem );
  2576. if ( 0 == lstrcmpi ( pszPath, szSelected ) ) {
  2577. SelectCounter( pItem );
  2578. }
  2579. if ( SUCCEEDED(hr) ) {
  2580. assert ( NULL != pItem );
  2581. // Only pass sample count if all sample properties exist
  2582. // in the property bag.
  2583. hr = pItem->LoadFromPropertyBag (
  2584. pIPropBag,
  2585. pIErrorLog,
  2586. iIndex,
  2587. SMONCTRL_MAJ_VERSION,
  2588. SMONCTRL_MIN_VERSION,
  2589. m_bSampleDataLoaded ? iSampleCount : 0 );
  2590. }
  2591. } else {
  2592. if ( SMON_STATUS_DUPL_COUNTER_PATH != (DWORD)hr ) {
  2593. AddToErrorPathList ( pszPath );
  2594. }
  2595. }
  2596. }
  2597. if (szSelected != NULL){
  2598. delete [] szSelected;
  2599. }
  2600. if (szEnglishBuf != NULL) {
  2601. free(szEnglishBuf);
  2602. }
  2603. if ( NULL != pszCounterPath ) {
  2604. delete [] pszCounterPath;
  2605. }
  2606. szCounterList = GetErrorPathList ( &dwCounterListLen );
  2607. if ( NULL != szCounterList ) {
  2608. LPWSTR szMessage = NULL;
  2609. // Report error, but continue.
  2610. szMessage = new WCHAR [dwCounterListLen + RESOURCE_STRING_BUF_LEN + 1];
  2611. if ( NULL != szMessage ) {
  2612. StringCchPrintf(szMessage,
  2613. dwCounterListLen + RESOURCE_STRING_BUF_LEN + 1,
  2614. ResourceString(IDS_ADD_COUNTER_ERR),
  2615. szCounterList );
  2616. MessageBox (
  2617. m_hWnd,
  2618. szMessage,
  2619. ResourceString(IDS_APP_NAME),
  2620. MB_OK | MB_ICONEXCLAMATION);
  2621. delete [] szMessage;
  2622. }
  2623. ClearErrorPathList();
  2624. }
  2625. return hrErr;
  2626. }
  2627. HRESULT
  2628. CSysmonControl::LoadFromPropertyBag (
  2629. IPropertyBag* pIPropBag,
  2630. IErrorLog* pIErrorLog )
  2631. {
  2632. HRESULT hr = S_OK;
  2633. GRAPH_OPTIONS *pOptions = &m_pObj->m_Graph.Options;
  2634. ISystemMonitor *pObj = m_pObj->m_pImpISystemMonitor;
  2635. INT iExtentX;
  2636. INT iExtentY;
  2637. INT intValue;
  2638. BOOL bValue;
  2639. FLOAT fValue;
  2640. OLE_COLOR clrValue;
  2641. INT iBufSize;
  2642. SMONCTRL_VERSION_DATA VersionData;
  2643. INT nLogType = SMON_CTRL_LOG;
  2644. // Version info
  2645. if (g_dwScriptPolicy == URLPOLICY_DISALLOW) {
  2646. return E_ACCESSDENIED;
  2647. }
  2648. VersionData.dwVersion = 0;
  2649. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszVersion, (INT&)VersionData.dwVersion );
  2650. assert ( SMONCTRL_MAJ_VERSION >= VersionData.iMajor );
  2651. m_LoadedVersion.dwVersion = VersionData.dwVersion;
  2652. hr = IntegerFromPropertyBag (pIPropBag, pIErrorLog, CGlobalString::m_cszLogType, nLogType);
  2653. if(SUCCEEDED(hr) && (nLogType == SLQ_TRACE_LOG)) {
  2654. // This is a WMI/WDM event trace log files, bail out immediately.
  2655. //
  2656. MessageBox(m_hWnd,
  2657. ResourceString(IDS_TRACE_LOG_ERR_MSG),
  2658. ResourceString(IDS_APP_NAME),
  2659. MB_OK);
  2660. return NOERROR;
  2661. }
  2662. // When loading properties, continue even if errors. On error, the value will
  2663. // remain default value.
  2664. // Extent data
  2665. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszExtentX, iExtentX );
  2666. if ( SUCCEEDED( hr ) ){
  2667. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszExtentY, iExtentY );
  2668. if ( SUCCEEDED( hr ) ) {
  2669. RECT RectExt;
  2670. SetRect(&RectExt, 0, 0, iExtentX, iExtentY);
  2671. m_pObj->RectConvertMappings(&RectExt, TRUE); // Convert from HIMETRIC
  2672. m_pObj->m_RectExt = RectExt;
  2673. }
  2674. }
  2675. // Options settings. Where possible, options are added through the vtable
  2676. // interface, for validation.
  2677. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszDisplayType, intValue );
  2678. if ( SUCCEEDED(hr) ) {
  2679. hr = pObj->put_DisplayType ( (eDisplayTypeConstant)intValue );
  2680. }
  2681. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszReportValueType, intValue );
  2682. if ( SUCCEEDED(hr) ) {
  2683. hr = pObj->put_ReportValueType ( (eReportValueTypeConstant)intValue );
  2684. }
  2685. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszMaximumScale, intValue );
  2686. if ( SUCCEEDED(hr) ) {
  2687. hr = pObj->put_MaximumScale ( intValue );
  2688. }
  2689. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszMinimumScale, intValue );
  2690. if ( SUCCEEDED(hr) ) {
  2691. hr = pObj->put_MinimumScale ( intValue );
  2692. }
  2693. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszAppearance, intValue );
  2694. if ( SUCCEEDED(hr) ) {
  2695. if ( NULL_COLOR == intValue ) {
  2696. pOptions->iAppearance = intValue;
  2697. } else {
  2698. hr = pObj->put_Appearance ( intValue );
  2699. }
  2700. }
  2701. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszBorderStyle, intValue );
  2702. if ( SUCCEEDED(hr) ) {
  2703. hr = pObj->put_BorderStyle ( intValue );
  2704. }
  2705. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowLegend, bValue );
  2706. if ( SUCCEEDED(hr) ) {
  2707. hr = pObj->put_ShowLegend ( (SHORT)bValue );
  2708. }
  2709. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowToolBar, bValue );
  2710. if ( SUCCEEDED(hr) ) {
  2711. hr = pObj->put_ShowToolbar ( (SHORT)bValue );
  2712. }
  2713. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowValueBar, bValue );
  2714. if ( SUCCEEDED(hr) ) {
  2715. hr = pObj->put_ShowValueBar ( (SHORT)bValue );
  2716. }
  2717. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowScaleLabels, bValue );
  2718. if ( SUCCEEDED(hr) ) {
  2719. hr = pObj->put_ShowScaleLabels ( (SHORT)bValue );
  2720. }
  2721. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowHorizontalGrid, bValue );
  2722. if ( SUCCEEDED(hr) ) {
  2723. hr = pObj->put_ShowHorizontalGrid ( (SHORT)bValue );
  2724. }
  2725. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszShowVerticalGrid, bValue );
  2726. if ( SUCCEEDED(hr) ) {
  2727. hr = pObj->put_ShowVerticalGrid ( (SHORT)bValue );
  2728. }
  2729. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszHighLight, bValue );
  2730. if ( SUCCEEDED(hr) ) {
  2731. hr = pObj->put_Highlight ( (SHORT)bValue );
  2732. }
  2733. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszManualUpdate, bValue );
  2734. if ( SUCCEEDED(hr) ) {
  2735. hr = pObj->put_ManualUpdate ( (SHORT)bValue );
  2736. }
  2737. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszReadOnly, bValue );
  2738. if ( SUCCEEDED(hr) ) {
  2739. hr = pObj->put_ReadOnly ( (SHORT)bValue );
  2740. }
  2741. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszMonitorDuplicateInstance, bValue );
  2742. if ( SUCCEEDED(hr) ) {
  2743. hr = pObj->put_MonitorDuplicateInstances ( (SHORT)bValue );
  2744. }
  2745. hr = FloatFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszUpdateInterval, fValue );
  2746. if ( SUCCEEDED(hr) ) {
  2747. hr = pObj->put_UpdateInterval ( fValue );
  2748. }
  2749. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszDisplayFilter, intValue );
  2750. if ( SUCCEEDED(hr) ) {
  2751. hr = pObj->put_DisplayFilter ( intValue );
  2752. }
  2753. hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszBackColorCtl, clrValue );
  2754. if ( SUCCEEDED(hr) ) {
  2755. if ( NULL_COLOR == clrValue ) {
  2756. pOptions->clrBackCtl = clrValue;
  2757. } else {
  2758. hr = pObj->put_BackColorCtl ( clrValue );
  2759. }
  2760. }
  2761. hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszBackColor, clrValue );
  2762. if ( SUCCEEDED(hr) ) {
  2763. if ( NULL_COLOR == clrValue ) {
  2764. pOptions->clrBackPlot = clrValue;
  2765. } else {
  2766. hr = pObj->put_BackColor ( clrValue );
  2767. }
  2768. }
  2769. hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszForeColor, clrValue );
  2770. if ( SUCCEEDED(hr) ) {
  2771. if ( NULL_COLOR == clrValue ) {
  2772. pOptions->clrFore = clrValue;
  2773. } else {
  2774. hr = pObj->put_ForeColor ( clrValue );
  2775. }
  2776. }
  2777. hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszGridColor, clrValue );
  2778. if ( SUCCEEDED(hr) ) {
  2779. hr = pObj->put_GridColor ( clrValue );
  2780. }
  2781. hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszTimeBarColor, clrValue );
  2782. if ( SUCCEEDED(hr) ) {
  2783. hr = pObj->put_TimeBarColor ( clrValue );
  2784. }
  2785. // Titles
  2786. hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszGraphTitle, NULL, iBufSize );
  2787. if ( SUCCEEDED(hr) &&
  2788. iBufSize > 0 ) {
  2789. pOptions->pszGraphTitle = new WCHAR[iBufSize];
  2790. if ( NULL != pOptions->pszGraphTitle ) {
  2791. hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszGraphTitle, pOptions->pszGraphTitle, iBufSize );
  2792. }
  2793. }
  2794. hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszYAxisLabel, NULL, iBufSize );
  2795. if ( SUCCEEDED(hr) &&
  2796. iBufSize > 0 ) {
  2797. pOptions->pszYaxisTitle = new WCHAR[iBufSize];
  2798. if ( NULL != pOptions->pszYaxisTitle ) {
  2799. hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszYAxisLabel, pOptions->pszYaxisTitle, iBufSize );
  2800. }
  2801. }
  2802. // SQL DSN and logset info
  2803. //
  2804. hr = StringFromPropertyBag(
  2805. pIPropBag, pIErrorLog, CGlobalString::m_cszSqlDsnName, NULL, iBufSize);
  2806. if (SUCCEEDED(hr) && iBufSize > 0) {
  2807. if (m_DataSourceInfo.szSqlDsnName) {
  2808. delete [] m_DataSourceInfo.szSqlDsnName;
  2809. m_DataSourceInfo.szSqlDsnName = NULL;
  2810. }
  2811. m_DataSourceInfo.szSqlDsnName = new WCHAR[iBufSize + 1];
  2812. if (m_DataSourceInfo.szSqlDsnName) {
  2813. hr = StringFromPropertyBag(pIPropBag,
  2814. pIErrorLog,
  2815. CGlobalString::m_cszSqlDsnName,
  2816. m_DataSourceInfo.szSqlDsnName,
  2817. iBufSize);
  2818. }
  2819. if (SUCCEEDED(hr)) {
  2820. hr = StringFromPropertyBag(
  2821. pIPropBag, pIErrorLog, CGlobalString::m_cszSqlLogSetName, NULL, iBufSize);
  2822. if (SUCCEEDED(hr) && iBufSize > 0) {
  2823. if (m_DataSourceInfo.szSqlLogSetName) {
  2824. delete [] m_DataSourceInfo.szSqlLogSetName;
  2825. m_DataSourceInfo.szSqlLogSetName = NULL;
  2826. }
  2827. m_DataSourceInfo.szSqlLogSetName = new WCHAR[iBufSize + 1];
  2828. if (m_DataSourceInfo.szSqlLogSetName) {
  2829. hr = StringFromPropertyBag(pIPropBag,
  2830. pIErrorLog,
  2831. CGlobalString::m_cszSqlLogSetName,
  2832. m_DataSourceInfo.szSqlLogSetName,
  2833. iBufSize);
  2834. }
  2835. }
  2836. }
  2837. if (SUCCEEDED(hr)) {
  2838. hr = LLTimeFromPropertyBag(pIPropBag,
  2839. pIErrorLog,
  2840. CGlobalString::m_cszLogViewStart,
  2841. m_DataSourceInfo.llStartDisp);
  2842. }
  2843. if (SUCCEEDED(hr)) {
  2844. hr = LLTimeFromPropertyBag(pIPropBag,
  2845. pIErrorLog,
  2846. CGlobalString::m_cszLogViewStop,
  2847. m_DataSourceInfo.llStopDisp);
  2848. }
  2849. }
  2850. // Log file info
  2851. hr = LoadLogFilesFromPropertyBag ( pIPropBag, pIErrorLog );
  2852. // Must put log file name after display range, before adding counters.
  2853. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszDataSourceType, intValue );
  2854. if (FAILED (hr)) {
  2855. //
  2856. // If DataSourceType flag is missing, set data source type based on
  2857. // presence of log files.
  2858. //
  2859. intValue = sysmonCurrentActivity;
  2860. if (NumLogFiles() > 0) {
  2861. intValue = sysmonLogFiles;
  2862. }
  2863. else if ( m_DataSourceInfo.szSqlDsnName && m_DataSourceInfo.szSqlLogSetName ) {
  2864. if ( m_DataSourceInfo.szSqlDsnName[0] != L'\0' && m_DataSourceInfo.szSqlLogSetName[0] != L'\0') {
  2865. intValue = sysmonSqlLog;
  2866. }
  2867. }
  2868. }
  2869. // Load log view start and stop times if the data source is not realtime.
  2870. if ( sysmonSqlLog == intValue || sysmonLogFiles == intValue ) {
  2871. hr = LLTimeFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszLogViewStart, m_DataSourceInfo.llStartDisp );
  2872. hr = LLTimeFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszLogViewStop, m_DataSourceInfo.llStopDisp );
  2873. }
  2874. hr = pObj->put_DataSourceType ( (eDataSourceTypeConstant)intValue );
  2875. if( FAILED(hr) ) {
  2876. if ( SMON_STATUS_LOG_FILE_SIZE_LIMIT == (DWORD)hr ) {
  2877. // TodoLogFiles: Check log file type. Only perfmon and circular
  2878. // binary logs are still limited to 1 GB.
  2879. // TodoLogFiles: Current query is already closed,
  2880. // so what can be done here?
  2881. } else {
  2882. DWORD dwStatus;
  2883. LPWSTR szLogFileList = NULL;
  2884. ULONG ulLogListBufLen= 0;
  2885. if ( sysmonLogFiles == intValue ) {
  2886. dwStatus = BuildLogFileList ( NULL, TRUE, &ulLogListBufLen );
  2887. szLogFileList = new WCHAR[ulLogListBufLen];
  2888. if ( NULL != szLogFileList ) {
  2889. dwStatus = BuildLogFileList (
  2890. szLogFileList,
  2891. TRUE,
  2892. &ulLogListBufLen );
  2893. }
  2894. }
  2895. dwStatus = DisplayDataSourceError (
  2896. m_hWnd,
  2897. (DWORD)hr,
  2898. intValue,
  2899. szLogFileList,
  2900. m_DataSourceInfo.szSqlDsnName,
  2901. m_DataSourceInfo.szSqlLogSetName );
  2902. if ( NULL != szLogFileList ) {
  2903. delete [] szLogFileList;
  2904. szLogFileList = NULL;
  2905. }
  2906. }
  2907. }
  2908. // Font info
  2909. hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszAmbientFont, bValue );
  2910. if (SUCCEEDED(hr)) {
  2911. pOptions->bAmbientFont = bValue;
  2912. }
  2913. // Load property bag values if they exist, overriding any specified aspect of ambient font.
  2914. hr = m_OleFont.LoadFromPropertyBag ( pIPropBag, pIErrorLog );
  2915. // Legend
  2916. hr = m_pLegend->LoadFromPropertyBag ( pIPropBag, pIErrorLog );
  2917. // Counters
  2918. m_bLoadingCounters = TRUE;
  2919. hr = LoadCountersFromPropertyBag ( pIPropBag, pIErrorLog, TRUE );
  2920. m_bLoadingCounters = FALSE;
  2921. // Load the Visuals after loading all counters.
  2922. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszNextCounterColor, intValue );
  2923. if ( SUCCEEDED(hr) && ( intValue < NumStandardColorIndices() ) ) {
  2924. m_iColorIndex = intValue;
  2925. }
  2926. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszNextCounterWidth, intValue );
  2927. if ( SUCCEEDED(hr) && ( intValue < NumWidthIndices() ) ) {
  2928. m_iWidthIndex = intValue;
  2929. }
  2930. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, CGlobalString::m_cszNextCounterLineStyle, intValue );
  2931. if ( SUCCEEDED(hr) && ( intValue < NumStyleIndices() ) ) {
  2932. m_iStyleIndex = intValue;
  2933. }
  2934. return NOERROR;
  2935. }
  2936. HRESULT
  2937. CSysmonControl::SaveToPropertyBag (
  2938. IPropertyBag* pIPropBag,
  2939. BOOL fSaveAllProps )
  2940. {
  2941. HRESULT hr = NOERROR;
  2942. GRAPH_OPTIONS *pOptions = &m_pObj->m_Graph.Options;
  2943. PCMachineNode pMachine;
  2944. PCObjectNode pObject;
  2945. PCInstanceNode pInstance;
  2946. PCGraphItem pItem;
  2947. PCLogFileItem pLogFile = NULL;
  2948. INT iCounterIndex = 0;
  2949. INT iLogFileIndex = 0;
  2950. RECT RectExt;
  2951. SMONCTRL_VERSION_DATA VersionData;
  2952. WCHAR szLogFileName[16];
  2953. LPWSTR szEnglishBuf = NULL;
  2954. DWORD dwEnglishBufSize = 0;
  2955. LPWSTR pszPath = NULL;
  2956. PDH_STATUS pdhStatus;
  2957. // Version info
  2958. VersionData.iMajor = SMONCTRL_MAJ_VERSION;
  2959. VersionData.iMinor = SMONCTRL_MIN_VERSION;
  2960. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszVersion, VersionData.dwVersion );
  2961. // Extent data in HIMETRIC format
  2962. if ( SUCCEEDED( hr ) ){
  2963. RectExt = m_pObj->m_RectExt;
  2964. m_pObj->RectConvertMappings(&RectExt, FALSE);
  2965. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszExtentX, RectExt.right - RectExt.left );
  2966. if ( SUCCEEDED( hr ) ){
  2967. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszExtentY, RectExt.bottom - RectExt.top );
  2968. }
  2969. }
  2970. // Options settings
  2971. if ( SUCCEEDED( hr ) ){
  2972. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszDisplayType, pOptions->iDisplayType );
  2973. }
  2974. if ( SUCCEEDED( hr ) ){
  2975. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszReportValueType, pOptions->iReportValueType );
  2976. }
  2977. if ( SUCCEEDED( hr ) ){
  2978. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszMaximumScale, pOptions->iVertMax );
  2979. }
  2980. if ( SUCCEEDED( hr ) ){
  2981. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszMinimumScale, pOptions->iVertMin );
  2982. }
  2983. if ( SUCCEEDED( hr ) ){
  2984. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowLegend, pOptions->bLegendChecked );
  2985. }
  2986. if ( SUCCEEDED( hr ) ){
  2987. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowToolBar, pOptions->bToolbarChecked );
  2988. }
  2989. if ( SUCCEEDED( hr ) ){
  2990. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowScaleLabels, pOptions->bLabelsChecked );
  2991. }
  2992. if ( SUCCEEDED( hr ) ){
  2993. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowHorizontalGrid, pOptions->bHorzGridChecked );
  2994. }
  2995. if ( SUCCEEDED( hr ) ){
  2996. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowVerticalGrid, pOptions->bVertGridChecked );
  2997. }
  2998. if ( SUCCEEDED( hr ) ){
  2999. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszShowValueBar, pOptions->bValueBarChecked );
  3000. }
  3001. if ( SUCCEEDED( hr ) ){
  3002. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszManualUpdate, pOptions->bManualUpdate );
  3003. }
  3004. if ( SUCCEEDED( hr ) ){
  3005. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszHighLight, pOptions->bHighlight );
  3006. }
  3007. if ( SUCCEEDED( hr ) ){
  3008. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszReadOnly, pOptions->bReadOnly );
  3009. }
  3010. if ( SUCCEEDED( hr ) ){
  3011. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszMonitorDuplicateInstance, pOptions->bMonitorDuplicateInstances );
  3012. }
  3013. if ( SUCCEEDED( hr ) ){
  3014. hr = FloatToPropertyBag ( pIPropBag, CGlobalString::m_cszUpdateInterval, pOptions->fUpdateInterval );
  3015. }
  3016. if ( SUCCEEDED( hr ) ){
  3017. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszDisplayFilter, pOptions->iDisplayFilter );
  3018. }
  3019. if ( SUCCEEDED( hr ) ){
  3020. hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszBackColorCtl, pOptions->clrBackCtl );
  3021. }
  3022. if ( SUCCEEDED( hr ) ){
  3023. hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszForeColor, pOptions->clrFore );
  3024. }
  3025. if ( SUCCEEDED( hr ) ){
  3026. hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszBackColor, pOptions->clrBackPlot );
  3027. }
  3028. if ( SUCCEEDED( hr ) ){
  3029. hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszGridColor, pOptions->clrGrid );
  3030. }
  3031. if ( SUCCEEDED( hr ) ){
  3032. hr = OleColorToPropertyBag ( pIPropBag, CGlobalString::m_cszTimeBarColor, pOptions->clrTimeBar );
  3033. }
  3034. if ( SUCCEEDED( hr ) ){
  3035. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszAppearance, pOptions->iAppearance );
  3036. }
  3037. if ( SUCCEEDED( hr ) ){
  3038. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszBorderStyle, pOptions->iBorderStyle );
  3039. }
  3040. // Visuals are stored directly in the control. Move to pOptions if made part
  3041. // of the programming interface.
  3042. if ( SUCCEEDED( hr ) ){
  3043. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszNextCounterColor, m_iColorIndex );
  3044. }
  3045. if ( SUCCEEDED( hr ) ){
  3046. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszNextCounterWidth, m_iWidthIndex );
  3047. }
  3048. if ( SUCCEEDED( hr ) ){
  3049. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszNextCounterLineStyle, m_iStyleIndex );
  3050. }
  3051. // Titles
  3052. if ( SUCCEEDED( hr ) ){
  3053. hr = StringToPropertyBag ( pIPropBag, CGlobalString::m_cszGraphTitle, pOptions->pszGraphTitle );
  3054. }
  3055. if ( SUCCEEDED( hr ) ){
  3056. hr = StringToPropertyBag ( pIPropBag, CGlobalString::m_cszYAxisLabel, pOptions->pszYaxisTitle );
  3057. }
  3058. // Data source info
  3059. if ( SUCCEEDED( hr ) ){
  3060. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszDataSourceType, pOptions->iDataSourceType );
  3061. }
  3062. if ( SUCCEEDED( hr ) &&
  3063. ( sysmonLogFiles == pOptions->iDataSourceType
  3064. || sysmonSqlLog == pOptions->iDataSourceType ) )
  3065. {
  3066. hr = LLTimeToPropertyBag ( pIPropBag, CGlobalString::m_cszLogViewStart, m_DataSourceInfo.llStartDisp );
  3067. if ( SUCCEEDED( hr ) ){
  3068. hr = LLTimeToPropertyBag ( pIPropBag, CGlobalString::m_cszLogViewStop, m_DataSourceInfo.llStopDisp );
  3069. }
  3070. }
  3071. // SQL data source
  3072. if (SUCCEEDED(hr)) {
  3073. hr = StringToPropertyBag(pIPropBag,
  3074. CGlobalString::m_cszSqlDsnName,
  3075. m_DataSourceInfo.szSqlDsnName);
  3076. }
  3077. if (SUCCEEDED(hr)) {
  3078. hr = StringToPropertyBag(pIPropBag,
  3079. CGlobalString::m_cszSqlLogSetName,
  3080. m_DataSourceInfo.szSqlLogSetName);
  3081. }
  3082. // Log files
  3083. if ( SUCCEEDED( hr ) ){
  3084. iLogFileIndex = 0;
  3085. for (pLogFile = FirstLogFile(); NULL != pLogFile; pLogFile = pLogFile->Next() ) {
  3086. StringCchPrintf ( szLogFileName,
  3087. 16,
  3088. CGlobalString::m_cszLogNameFormat,
  3089. CGlobalString::m_cszLogFileName,
  3090. ++iLogFileIndex );
  3091. hr = StringToPropertyBag ( pIPropBag, szLogFileName, pLogFile->GetPath() );
  3092. }
  3093. if ( SUCCEEDED( hr ) ){
  3094. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszLogFileCount, iLogFileIndex );
  3095. }
  3096. }
  3097. // Font info
  3098. if ( SUCCEEDED( hr ) ){
  3099. hr = BOOLToPropertyBag ( pIPropBag, CGlobalString::m_cszAmbientFont, pOptions->bAmbientFont );
  3100. if ( FAILED( hr ) || !pOptions->bAmbientFont ){
  3101. hr = m_OleFont.SaveToPropertyBag ( pIPropBag, TRUE, fSaveAllProps );
  3102. }
  3103. }
  3104. // Legend
  3105. if ( SUCCEEDED( hr ) ){
  3106. hr = m_pLegend->SaveToPropertyBag ( pIPropBag, TRUE, fSaveAllProps );
  3107. }
  3108. // Save counter count and sample data
  3109. LockCounterData();
  3110. if ( SUCCEEDED( hr ) ){
  3111. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszCounterCount, CounterTree()->NumCounters() );
  3112. }
  3113. if ( SUCCEEDED(hr) ) {
  3114. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszMaximumSamples, m_pHistCtrl->nMaxSamples );
  3115. }
  3116. if ( SUCCEEDED(hr) ) {
  3117. INT iSampleCount;
  3118. if ( !m_fUserMode ) {
  3119. iSampleCount = 0;
  3120. #if !_LOG_INCLUDE_DATA
  3121. } else if ( m_bLogFileSource ) {
  3122. iSampleCount = 0;
  3123. #endif
  3124. } else {
  3125. iSampleCount = m_pHistCtrl->nSamples;
  3126. }
  3127. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszSampleCount, iSampleCount );
  3128. if ( SUCCEEDED(hr) && ( 0 < iSampleCount )) {
  3129. #if _LOG_INCLUDE_DATA
  3130. INT iTemp;
  3131. iTemp = ( 0 < m_pHistCtrl->iCurrent ? m_pHistCtrl->iCurrent : 1 );
  3132. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszSampleIndex, iTemp );
  3133. if ( SUCCEEDED(hr) ) {
  3134. iTemp = ( 0 < m_pObj->m_Graph.TimeStepper.StepNum() ? m_pObj->m_Graph.TimeStepper.StepNum() : 1 );
  3135. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszStepNumber, iTemp );
  3136. }
  3137. #else
  3138. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszSampleIndex, m_pHistCtrl->iCurrent );
  3139. if ( SUCCEEDED(hr) ) {
  3140. hr = IntegerToPropertyBag ( pIPropBag, CGlobalString::m_cszStepNumber, m_pObj->m_Graph.TimeStepper.StepNum() );
  3141. }
  3142. #endif
  3143. }
  3144. }
  3145. for ( pMachine = CounterTree()->FirstMachine();
  3146. pMachine;
  3147. pMachine = pMachine->Next()) {
  3148. for ( pObject = pMachine->FirstObject();
  3149. pObject;
  3150. pObject = pObject->Next()) {
  3151. for ( pInstance = pObject->FirstInstance();
  3152. pInstance;
  3153. pInstance = pInstance->Next()) {
  3154. for ( pItem = pInstance->FirstItem();
  3155. pItem;
  3156. pItem = pItem->m_pNextItem) {
  3157. // Save all counters explicitly, even if wildcard
  3158. iCounterIndex++;
  3159. hr = pItem->SaveToPropertyBag (
  3160. pIPropBag,
  3161. iCounterIndex,
  3162. m_fUserMode,
  3163. SMONCTRL_MAJ_VERSION,
  3164. SMONCTRL_MIN_VERSION);
  3165. if (FAILED(hr))
  3166. return hr;
  3167. }
  3168. }
  3169. }
  3170. }
  3171. assert ( iCounterIndex == CounterTree()->NumCounters() );
  3172. // Selection
  3173. if ( NULL != m_pSelectedItem ) {
  3174. VARIANT vValue;
  3175. DWORD dwBufSize;
  3176. LPWSTR pNewBuf;
  3177. VariantInit( &vValue );
  3178. vValue.vt = VT_BSTR;
  3179. // get this counter path
  3180. hr = m_pSelectedItem->get_Path( &vValue.bstrVal );
  3181. if( SUCCEEDED(hr) ){
  3182. pszPath = vValue.bstrVal;
  3183. //
  3184. // Initialize the locale path buffer
  3185. //
  3186. if (dwEnglishBufSize == 0) {
  3187. dwEnglishBufSize = PDH_MAX_COUNTER_PATH + 1;
  3188. szEnglishBuf = (LPWSTR) malloc(dwEnglishBufSize * sizeof(WCHAR));
  3189. if (szEnglishBuf == NULL) {
  3190. dwEnglishBufSize = 0;
  3191. }
  3192. }
  3193. if (szEnglishBuf != NULL) {
  3194. //
  3195. // Translate counter name from Localization into English
  3196. //
  3197. dwBufSize = dwEnglishBufSize;
  3198. pdhStatus = PdhTranslate009Counter(
  3199. vValue.bstrVal,
  3200. szEnglishBuf,
  3201. &dwBufSize);
  3202. if (pdhStatus == PDH_MORE_DATA) {
  3203. pNewBuf = (LPWSTR)realloc(szEnglishBuf, dwBufSize * sizeof(WCHAR));
  3204. if (pNewBuf != NULL) {
  3205. szEnglishBuf = pNewBuf;
  3206. dwEnglishBufSize = dwBufSize;
  3207. pdhStatus = PdhTranslate009Counter(
  3208. vValue.bstrVal,
  3209. szEnglishBuf,
  3210. &dwBufSize);
  3211. }
  3212. }
  3213. if (pdhStatus == ERROR_SUCCESS) {
  3214. pszPath = szEnglishBuf;
  3215. }
  3216. }
  3217. if( SUCCEEDED(hr) ) {
  3218. VariantClear( &vValue );
  3219. vValue.bstrVal = SysAllocString( pszPath );
  3220. if( vValue.bstrVal != NULL ){
  3221. vValue.vt = VT_BSTR;
  3222. }
  3223. }else{
  3224. //translation failed, write current value
  3225. hr = ERROR_SUCCESS;
  3226. }
  3227. }
  3228. if ( SUCCEEDED ( hr ) ) {
  3229. hr = pIPropBag->Write(CGlobalString::m_cszSelected, &vValue );
  3230. VariantClear ( &vValue );
  3231. }
  3232. }
  3233. if (szEnglishBuf != NULL) {
  3234. free(szEnglishBuf);
  3235. }
  3236. UnlockCounterData();
  3237. return hr;
  3238. }
  3239. DWORD
  3240. CSysmonControl::InitializeQuery (
  3241. void )
  3242. {
  3243. DWORD dwStat = ERROR_SUCCESS;
  3244. PCGraphItem pItem;
  3245. // Query must be opened before this method is called.
  3246. if ( NULL != m_hQuery ) {
  3247. m_pHistCtrl->nMaxSamples = MAX_GRAPH_SAMPLES;
  3248. m_pHistCtrl->iCurrent = 0;
  3249. m_pHistCtrl->nSamples = 0;
  3250. m_pHistCtrl->nBacklog = 0;
  3251. m_pObj->m_Graph.TimeStepper.Reset();
  3252. m_pObj->m_Graph.LogViewStartStepper.Reset();
  3253. m_pObj->m_Graph.LogViewStopStepper.Reset();
  3254. m_pHistCtrl->bLogSource = m_bLogFileSource;
  3255. } else {
  3256. dwStat = PDH_INVALID_HANDLE;
  3257. }
  3258. if ( ERROR_SUCCESS == dwStat ) {
  3259. // Add counters to the query, to initialize scale factors
  3260. if ((pItem = FirstCounter()) != NULL) {
  3261. while (pItem != NULL) {
  3262. pItem->AddToQuery(m_hQuery);
  3263. pItem = pItem->Next();
  3264. }
  3265. }
  3266. }
  3267. return dwStat;
  3268. }
  3269. DWORD
  3270. CSysmonControl::ActivateQuery (
  3271. void )
  3272. {
  3273. DWORD dwStat = ERROR_SUCCESS;
  3274. DWORD dwThreadID;
  3275. // if real-time source
  3276. if (!IsLogSource()
  3277. && m_fInitialized
  3278. && IsUserMode() ) {
  3279. if ( NULL == m_CollectInfo.hEvent ) {
  3280. // Create a collection event
  3281. if ((m_CollectInfo.hEvent = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) {
  3282. dwStat = GetLastError();
  3283. } else
  3284. // Create the collection thread
  3285. if ( ( m_CollectInfo.hThread
  3286. = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CollectProc, this, 0, &dwThreadID)) == NULL) {
  3287. dwStat = GetLastError();
  3288. }
  3289. if ( ERROR_SUCCESS == dwStat ) {
  3290. SetThreadPriority ( m_CollectInfo.hThread, THREAD_PRIORITY_TIME_CRITICAL );
  3291. }
  3292. }
  3293. if ( ERROR_SUCCESS == dwStat ) {
  3294. // Start the data collection
  3295. if ( FirstCounter() != NULL) {
  3296. SetIntervalTimer();
  3297. }
  3298. }
  3299. }
  3300. if ( ERROR_SUCCESS != dwStat ) {
  3301. // If failure, close query to clean up then exit
  3302. CloseQuery();
  3303. }
  3304. return dwStat;
  3305. }
  3306. void
  3307. CSysmonControl::CloseQuery (
  3308. void )
  3309. {
  3310. PCGraphItem pItem;
  3311. // Terminate the collection thread
  3312. if ( NULL != m_CollectInfo.hThread ) {
  3313. m_CollectInfo.iMode = COLLECT_QUIT;
  3314. SetEvent(m_CollectInfo.hEvent);
  3315. WaitForSingleObject(m_CollectInfo.hThread, INFINITE);
  3316. CloseHandle(m_CollectInfo.hThread);
  3317. m_CollectInfo.hThread = NULL;
  3318. }
  3319. // Release the collection event
  3320. if ( NULL != m_CollectInfo.hEvent ) {
  3321. CloseHandle(m_CollectInfo.hEvent);
  3322. m_CollectInfo.hEvent = NULL;
  3323. }
  3324. LockCounterData();
  3325. // Remove counters from the query
  3326. pItem = FirstCounter();
  3327. while ( NULL != pItem ) {
  3328. pItem->RemoveFromQuery();
  3329. pItem = pItem->Next();
  3330. }
  3331. UnlockCounterData();
  3332. // Delete the query
  3333. if ( NULL != m_hQuery ) {
  3334. PdhCloseQuery ( m_hQuery );
  3335. if ( (m_DataSourceInfo.hDataSource != H_REALTIME_DATASOURCE)
  3336. && (m_DataSourceInfo.hDataSource != H_WBEM_DATASOURCE)) {
  3337. PdhCloseLog(m_DataSourceInfo.hDataSource, 0);
  3338. m_DataSourceInfo.hDataSource = H_REALTIME_DATASOURCE;
  3339. }
  3340. m_hQuery = NULL;
  3341. }
  3342. }
  3343. void CSysmonControl::SizeComponents ( HDC hDC )
  3344. /*
  3345. Effect: Move and show the various components of the graph to
  3346. fill the size (xWidth x yHeight). Take into account
  3347. whether the user wants to show the legend or status
  3348. bars. Also take into account if we have room for these
  3349. items.
  3350. Internals: If the user doesn't want the status or legend windows,
  3351. they aren't shown. Also, if the user wanted the status
  3352. window but not the legend window, the status window is
  3353. not shown.
  3354. We may disregard the user's desire for the legend or
  3355. status bar if there is not room. In particular, a legend
  3356. window has a minimum width (LegendMinWidth ()) and a
  3357. minimum height (LegendMinHeight ()). These values are
  3358. fixed for a given session of perfmon. It also has a
  3359. preferred height, which takes into consideration the
  3360. size of the graph window and the number of items in
  3361. the legend. This value is returned by LegendHeight().
  3362. We don't show the legend if its minimum height would
  3363. take up more than half the graph height.
  3364. If we feel we don't have room for the legend, we don't
  3365. show the status window either.
  3366. See Also: LegendMinWidth, LegendMinHeight, LegendHeight,
  3367. ValuebarHeight.
  3368. Called By: OnSize, any other function that may remove or add one
  3369. of the graph components.
  3370. */
  3371. {
  3372. RECT rectClient;
  3373. RECT rectComponent;
  3374. RECT rectToolbar;
  3375. INT xWidth;
  3376. INT yHeight;
  3377. INT yGraphHeight = 0;
  3378. INT ySnapHeight = 0;
  3379. INT yStatsHeight = 0;
  3380. INT yLegendHeight = 0;
  3381. INT yToolbarHeight = 0;
  3382. #define CTRL_BORDER 10
  3383. // If not inited, there's noting to size
  3384. if (!m_fViewInitialized)
  3385. return;
  3386. // Get dimensions of window
  3387. // GetClientRect (m_hWnd, &rectClient) ;
  3388. // *** - Use extent. It is the 'natural' size of the control.
  3389. // This draws the control correctly when zoom = 100%
  3390. // It also makes print size correct at all zoom levels.
  3391. SetCurrentClientRect ( GetNewClientRect() );
  3392. rectClient = *GetCurrentClientRect();
  3393. switch (m_pObj->m_Graph.Options.iDisplayType) {
  3394. case REPORT_GRAPH:
  3395. // Toolbar
  3396. // Toolbar not available through IViewObect, so leave it out.
  3397. if (m_pObj->m_Graph.Options.bToolbarChecked
  3398. && m_fViewInitialized ) {
  3399. rectToolbar = rectClient;
  3400. // Determine height of toolbar after sizing it, to handle Wrap.
  3401. m_pToolbar->SizeComponents(&rectToolbar);
  3402. yToolbarHeight = m_pToolbar->Height();
  3403. } else {
  3404. memset (&rectToolbar, 0, sizeof(RECT));
  3405. yToolbarHeight = 0;
  3406. }
  3407. if (yToolbarHeight > 0) {
  3408. rectClient.top += yToolbarHeight;
  3409. rectToolbar.bottom = rectToolbar.top + yToolbarHeight;
  3410. }
  3411. // Give report the entire client area except for toolbar
  3412. m_pReport->SizeComponents(&rectClient);
  3413. // Hide the other view components
  3414. SetRect(&rectClient,0,0,0,0);
  3415. m_pGraphDisp->SizeComponents(hDC, &rectClient);
  3416. m_pSnapBar->SizeComponents(&rectClient);
  3417. m_pStatsBar->SizeComponents(&rectClient);
  3418. m_pLegend->SizeComponents(&rectClient);
  3419. break;
  3420. case LINE_GRAPH:
  3421. case BAR_GRAPH:
  3422. // Subtract border area
  3423. rectComponent = rectClient;
  3424. InflateRect(&rectComponent, -CTRL_BORDER, -CTRL_BORDER);
  3425. xWidth = rectComponent.right - rectComponent.left ;
  3426. yHeight = rectComponent.bottom - rectComponent.top ;
  3427. // if the window has no area, forget it
  3428. if (xWidth == 0 || yHeight == 0)
  3429. return ;
  3430. // Reserve top fourth of window for graph
  3431. yGraphHeight = yHeight / 4;
  3432. yHeight -= yGraphHeight;
  3433. // Allocate space to each enabled component
  3434. // Toolbar
  3435. if (m_pObj->m_Graph.Options.bToolbarChecked
  3436. && m_fViewInitialized ) {
  3437. rectToolbar = rectComponent;
  3438. m_pToolbar->SizeComponents(&rectToolbar);
  3439. yToolbarHeight = m_pToolbar->Height();
  3440. } else {
  3441. memset (&rectToolbar, 0, sizeof(RECT));
  3442. yToolbarHeight = 0;
  3443. }
  3444. if (yToolbarHeight > 0) {
  3445. yHeight -= yToolbarHeight;
  3446. rectToolbar.bottom = rectToolbar.top + yToolbarHeight;
  3447. rectComponent.top += yToolbarHeight;
  3448. }
  3449. // Legend (Start with minimum size)
  3450. if (m_pObj->m_Graph.Options.bLegendChecked) {
  3451. yLegendHeight = m_pLegend->MinHeight(yHeight - CTRL_BORDER);
  3452. if (yLegendHeight > 0)
  3453. yHeight -= yLegendHeight + CTRL_BORDER;
  3454. }
  3455. // Statistics bar
  3456. if (m_pObj->m_Graph.Options.bValueBarChecked) {
  3457. yStatsHeight = m_pStatsBar->Height(yHeight - CTRL_BORDER, xWidth);
  3458. if (yStatsHeight > 0)
  3459. yHeight -= yStatsHeight + CTRL_BORDER;
  3460. }
  3461. // Snap bar
  3462. // only if tool bar is not displayed
  3463. if ((m_pObj->m_Graph.Options.bManualUpdate) &&
  3464. (!m_pObj->m_Graph.Options.bToolbarChecked)) {
  3465. ySnapHeight = m_pSnapBar->Height(yHeight - CTRL_BORDER);
  3466. if (ySnapHeight > 0)
  3467. yHeight -= ySnapHeight + CTRL_BORDER;
  3468. }
  3469. // If legend is visible give it a chance to use remaining space
  3470. // Rest goes to graph
  3471. if (yLegendHeight != 0) {
  3472. yHeight += yLegendHeight;
  3473. yLegendHeight = m_pLegend->Height(yHeight);
  3474. yGraphHeight += yHeight - yLegendHeight;
  3475. }
  3476. else
  3477. yGraphHeight += yHeight;
  3478. // Assign rectangle to each component
  3479. // Toolbar assigned earlier, to handle wrap.
  3480. // Graph display
  3481. rectComponent.bottom = rectComponent.top + yGraphHeight;
  3482. m_pGraphDisp->SizeComponents(hDC, &rectComponent);
  3483. rectComponent.top += yGraphHeight + CTRL_BORDER;
  3484. // Snap bar
  3485. rectComponent.bottom = rectComponent.top + ySnapHeight;
  3486. m_pSnapBar->SizeComponents(&rectComponent);
  3487. if (ySnapHeight != 0)
  3488. rectComponent.top += ySnapHeight + CTRL_BORDER;
  3489. // Statistics bar
  3490. rectComponent.bottom = rectComponent.top + yStatsHeight;
  3491. m_pStatsBar->SizeComponents(&rectComponent);
  3492. if (yStatsHeight != 0)
  3493. rectComponent.top += yStatsHeight + CTRL_BORDER;
  3494. // Legend window
  3495. rectComponent.bottom = rectComponent.top + yLegendHeight;
  3496. m_pLegend->SizeComponents(&rectComponent);
  3497. rectComponent.top += yLegendHeight;
  3498. // Force redraw of window
  3499. // Optimize: SizeComponents only called within Paint or Render,
  3500. // so remove this extra window invalidation.
  3501. WindowInvalidate(m_hWnd);
  3502. // Hide report window
  3503. SetRect(&rectClient,0,0,0,0);
  3504. m_pReport->SizeComponents(&rectComponent);
  3505. break;
  3506. }
  3507. }
  3508. void CSysmonControl::put_Highlight(BOOL bState)
  3509. {
  3510. // If no change, just return
  3511. if ( m_pObj->m_Graph.Options.bHighlight == bState )
  3512. return;
  3513. m_pObj->m_Graph.Options.bHighlight = bState;
  3514. // if no selected item, state doesn't matter
  3515. if (m_pSelectedItem == NULL)
  3516. return;
  3517. // Update graph display's highlighted item
  3518. if ( m_pObj->m_Graph.Options.bHighlight )
  3519. m_pGraphDisp->HiliteItem(m_pSelectedItem);
  3520. else
  3521. m_pGraphDisp->HiliteItem(NULL);
  3522. // Cause redraw
  3523. UpdateGraph(UPDGRPH_PLOT);
  3524. }
  3525. void
  3526. CSysmonControl::put_ManualUpdate(BOOL bManual)
  3527. {
  3528. m_pObj->m_Graph.Options.bManualUpdate = bManual;
  3529. if ( m_bSampleDataLoaded ) {
  3530. UpdateCounterValues(FALSE);
  3531. } else {
  3532. SetIntervalTimer();
  3533. UpdateGraph(UPDGRPH_LAYOUT);
  3534. }
  3535. }
  3536. VOID CSysmonControl::AssignFocus (
  3537. VOID
  3538. )
  3539. {
  3540. if (m_pObj->m_Graph.Options.iDisplayType == REPORT_GRAPH)
  3541. SetFocus(m_pReport->Window());
  3542. else
  3543. SetFocus(m_pLegend->Window());
  3544. }
  3545. HRESULT CSysmonControl::TranslateAccelerators( LPMSG pMsg )
  3546. {
  3547. INT iStat;
  3548. if (m_hWnd == NULL || m_hAccel == NULL)
  3549. return S_FALSE;
  3550. // If this is a cursor key down event, process it here, or the container may grab it first
  3551. // I need to be sure that it reaches the legend listbox
  3552. if (pMsg->message == WM_KEYDOWN &&
  3553. ( pMsg->wParam == VK_UP || pMsg->wParam == VK_DOWN ||
  3554. pMsg->wParam == VK_HOME || pMsg->wParam == VK_END ) ) {
  3555. ::TranslateMessage(pMsg);
  3556. ::DispatchMessage(pMsg);
  3557. return S_OK;
  3558. }
  3559. iStat = ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg);
  3560. return iStat ? S_OK : S_FALSE;
  3561. }
  3562. //==========================================================================//
  3563. // Message Handlers //
  3564. //==========================================================================//
  3565. BOOL
  3566. CSysmonControl::DisplayHelp ( HWND hwndSelf )
  3567. {
  3568. WCHAR pszHelpFilePath[2*MAX_PATH + 1];
  3569. UINT nLen;
  3570. if ( NULL != hwndSelf ) {
  3571. nLen = ::GetWindowsDirectory(pszHelpFilePath, 2*MAX_PATH + 1);
  3572. if ( nLen == 0 ) {
  3573. // Report error.
  3574. return FALSE;
  3575. }
  3576. StringCchCat(pszHelpFilePath, 2*MAX_PATH + 1, L"\\help\\sysmon.chm");
  3577. HtmlHelp ( hwndSelf, pszHelpFilePath, HH_DISPLAY_TOPIC, 0 );
  3578. }
  3579. return TRUE;
  3580. }
  3581. LRESULT APIENTRY SysmonCtrlWndProc (HWND hWnd,
  3582. UINT uiMsg,
  3583. WPARAM wParam,
  3584. LPARAM lParam)
  3585. {
  3586. RECT rect;
  3587. PSYSMONCTRL pCtrl = (PSYSMONCTRL)GetWindowLongPtr(hWnd ,0);
  3588. INT iUpdate;
  3589. switch (uiMsg) {
  3590. case WM_NOTIFY:
  3591. {
  3592. NMHDR *pnmHdr;
  3593. NMTTDISPINFO *pnmInfo;
  3594. LONG_PTR lStrId;
  3595. pnmHdr = (NMHDR *)lParam;
  3596. switch (pnmHdr->code) {
  3597. case TTN_NEEDTEXT:
  3598. pnmInfo = (NMTTDISPINFO *)lParam;
  3599. // cast ID as a string for this arg
  3600. lStrId = (LONG_PTR)(wParam - IDM_TOOLBAR);
  3601. lStrId += IDS_TB_BASE;
  3602. pnmInfo->lpszText = (LPWSTR)lStrId;
  3603. pnmInfo->hinst = g_hInstance;
  3604. break;
  3605. default:
  3606. return DefWindowProc (hWnd, uiMsg, wParam, lParam);
  3607. }
  3608. }
  3609. break;
  3610. case WM_CREATE:
  3611. pCtrl = (PSYSMONCTRL)((CREATESTRUCT*)lParam)->lpCreateParams;
  3612. SetWindowLongPtr(hWnd,0,(INT_PTR)pCtrl);
  3613. break;
  3614. case WM_DESTROY:
  3615. pCtrl->m_hWnd = NULL;
  3616. break;
  3617. case WM_CONTEXTMENU:
  3618. case WM_LBUTTONDOWN:
  3619. case WM_LBUTTONDBLCLK:
  3620. //We become UI Active with mouse action
  3621. if (!pCtrl->m_fUIDead) {
  3622. pCtrl->m_pObj->UIActivate();
  3623. pCtrl->AssignFocus();
  3624. if (uiMsg == WM_CONTEXTMENU) {
  3625. if (LOWORD(lParam)!= 0xffff || HIWORD(lParam) != 0xffff){
  3626. pCtrl->DisplayContextMenu(LOWORD(lParam), HIWORD(lParam));
  3627. }else{
  3628. pCtrl->DisplayContextMenu(0,0);
  3629. }
  3630. } else if (uiMsg == WM_LBUTTONDBLCLK) {
  3631. pCtrl->OnDblClick(LOWORD(lParam), HIWORD(lParam));
  3632. }
  3633. }
  3634. break;
  3635. case WM_COMMAND:
  3636. if (pCtrl->m_fUIDead)
  3637. break;
  3638. switch (LOWORD(wParam)) {
  3639. case IDM_TB_PROPERTIES:
  3640. pCtrl->DisplayProperties();
  3641. break;
  3642. case IDM_PROPERTIES:
  3643. pCtrl->DisplayProperties ( DISPID_VALUE );
  3644. break;
  3645. case IDM_TB_ADD:
  3646. case IDM_ADDCOUNTERS:
  3647. pCtrl->AddCounters();
  3648. break;
  3649. case IDM_TB_DELETE:
  3650. case IDM_DELETE:
  3651. {
  3652. CWaitCursor cursorWait;
  3653. if (pCtrl->m_pObj->m_Graph.Options.iDisplayType == REPORT_GRAPH) {
  3654. pCtrl->m_pReport->DeleteSelection();
  3655. } else {
  3656. if ( SUCCEEDED(pCtrl->DeleteCounter ( pCtrl->m_pSelectedItem, TRUE )) ) {
  3657. pCtrl->UpdateGraph(UPDGRPH_DELCNTR);
  3658. }
  3659. }
  3660. }
  3661. break;
  3662. case IDM_TB_REALTIME:
  3663. if ( sysmonCurrentActivity != pCtrl->m_pObj->m_Graph.Options.iDataSourceType ) {
  3664. CWaitCursor cursorWait;
  3665. pCtrl->put_DataSourceType ( sysmonCurrentActivity );
  3666. pCtrl->Clear();
  3667. } else {
  3668. // Nothing changed, so resync the toolbar to
  3669. // handle state of realtime button.
  3670. pCtrl->m_pToolbar->SyncToolbar();
  3671. }
  3672. break;
  3673. case IDM_TB_LOGFILE:
  3674. {
  3675. pCtrl->DisplayProperties( DISPID_SYSMON_DATASOURCETYPE );
  3676. // Resync the toolbar in case the log file is invalid.
  3677. pCtrl->m_pToolbar->SyncToolbar();
  3678. }
  3679. break;
  3680. case IDM_SAVEAS:
  3681. pCtrl->SaveAs();
  3682. break;
  3683. case IDM_SAVEDATA:
  3684. pCtrl->SaveData();
  3685. break;
  3686. case IDC_SNAPBTN:
  3687. case IDM_TB_UPDATE:
  3688. case IDM_UPDATE:
  3689. {
  3690. CWaitCursor cursorWait;
  3691. pCtrl->UpdateCounterValues(TRUE);
  3692. }
  3693. break;
  3694. case IDM_TB_CLEAR:
  3695. {
  3696. CWaitCursor cursorWait;
  3697. pCtrl->Clear();
  3698. }
  3699. break;
  3700. case IDM_TB_FREEZE:
  3701. // Confirm the data overwrite before changing the state of the freeze button.
  3702. if ( pCtrl->ConfirmSampleDataOverwrite() ) {
  3703. pCtrl->put_ManualUpdate ( !pCtrl->m_pObj->m_Graph.Options.bManualUpdate );
  3704. } else {
  3705. // Nothing changed, so resync the toolbar to
  3706. // handle state of the freeze button.
  3707. pCtrl->m_pToolbar->SyncToolbar();
  3708. }
  3709. break;
  3710. case IDM_TB_HIGHLIGHT:
  3711. case IDM_HIGHLITE:
  3712. pCtrl->put_Highlight(!pCtrl->m_pObj->m_Graph.Options.bHighlight );
  3713. break;
  3714. case ID_HATCHWINDOW:
  3715. if (HIWORD(wParam) == HWN_RESIZEREQUESTED)
  3716. pCtrl->m_pObj->m_pIOleIPSite->OnPosRectChange((LPRECT)lParam);
  3717. break;
  3718. case IDM_TB_CHART:
  3719. if (pCtrl->m_pObj->m_Graph.Options.iDisplayType != sysmonLineGraph) {
  3720. CWaitCursor cursorWait;
  3721. if (pCtrl->m_pObj->m_Graph.Options.iDisplayType == REPORT_GRAPH)
  3722. iUpdate = UPDGRPH_VIEW;
  3723. else
  3724. iUpdate = UPDGRPH_PLOT;
  3725. pCtrl->m_pObj->m_Graph.Options.iDisplayType = LINE_GRAPH;
  3726. InvalidateRect(pCtrl->m_hWnd, NULL, TRUE);
  3727. pCtrl->UpdateGraph(iUpdate);
  3728. }
  3729. break;
  3730. case IDM_TB_HISTOGRAM:
  3731. if (pCtrl->m_pObj->m_Graph.Options.iDisplayType != sysmonHistogram) {
  3732. CWaitCursor cursorWait;
  3733. if (pCtrl->m_pObj->m_Graph.Options.iDisplayType == REPORT_GRAPH)
  3734. iUpdate = UPDGRPH_VIEW;
  3735. else
  3736. iUpdate = UPDGRPH_PLOT;
  3737. pCtrl->m_pObj->m_Graph.Options.iDisplayType = BAR_GRAPH;
  3738. InvalidateRect(pCtrl->m_hWnd, NULL, TRUE);
  3739. pCtrl->UpdateGraph(iUpdate);
  3740. }
  3741. break;
  3742. case IDM_TB_REPORT:
  3743. if (pCtrl->m_pObj->m_Graph.Options.iDisplayType != sysmonReport) {
  3744. CWaitCursor cursorWait;
  3745. pCtrl->m_pObj->m_Graph.Options.iDisplayType = REPORT_GRAPH;
  3746. InvalidateRect(pCtrl->m_hWnd, NULL, TRUE);
  3747. pCtrl->UpdateGraph(UPDGRPH_VIEW);
  3748. }
  3749. break;
  3750. case IDM_TB_PASTE:
  3751. {
  3752. HRESULT hr = S_OK;
  3753. {
  3754. CWaitCursor cursorWait;
  3755. hr = pCtrl->Paste();
  3756. }
  3757. if ( SMON_STATUS_NO_SYSMON_OBJECT == (DWORD)hr ) {
  3758. MessageBox(
  3759. pCtrl->m_hWnd,
  3760. ResourceString(IDS_NOSYSMONOBJECT_ERR ),
  3761. ResourceString(IDS_APP_NAME),
  3762. MB_OK | MB_ICONERROR);
  3763. }
  3764. }
  3765. break;
  3766. case IDM_TB_COPY:
  3767. {
  3768. CWaitCursor cursorWait;
  3769. pCtrl->Copy();
  3770. }
  3771. break;
  3772. case IDM_TB_NEW:
  3773. {
  3774. CWaitCursor cursorWait;
  3775. pCtrl->Reset();
  3776. }
  3777. break;
  3778. case IDM_TB_HELP:
  3779. {
  3780. return pCtrl->DisplayHelp ( hWnd );
  3781. }
  3782. default:
  3783. return DefWindowProc (hWnd, uiMsg, wParam, lParam);
  3784. }
  3785. break;
  3786. case WM_DROPFILES:
  3787. {
  3788. CWaitCursor cursorWait;
  3789. pCtrl->OnDropFile (wParam) ;
  3790. }
  3791. return (0) ;
  3792. case WM_ERASEBKGND:
  3793. GetClientRect(hWnd, &rect);
  3794. Fill((HDC)wParam, pCtrl->clrBackCtl(), &rect);
  3795. return TRUE;
  3796. case WM_SYSCOLORCHANGE:
  3797. pCtrl->UpdateNonAmbientSysColors();
  3798. case WM_PAINT:
  3799. pCtrl->Paint();
  3800. break ;
  3801. case WM_SIZE:
  3802. if (pCtrl != NULL) {
  3803. // Avoid extra cases of (SetDirty()) if size has not changed.
  3804. if ( !EqualRect ( pCtrl->GetCurrentClientRect(), pCtrl->GetNewClientRect() ) ) {
  3805. pCtrl->UpdateGraph(UPDGRPH_LAYOUT);
  3806. }
  3807. }
  3808. break ;
  3809. case WM_TIMER:
  3810. pCtrl->UpdateCounterValues(FALSE);
  3811. break;
  3812. case WM_SETFOCUS:
  3813. pCtrl->AssignFocus();
  3814. break;
  3815. case WM_VALUES_UPDATED:
  3816. pCtrl->OnValuesUpdated();
  3817. break;
  3818. case WM_GRAPH_UPDATE:
  3819. pCtrl->UpdateGraphData();
  3820. break;
  3821. case WM_HELP:
  3822. {
  3823. return pCtrl->DisplayHelp ( hWnd );
  3824. }
  3825. default:
  3826. return DefWindowProc (hWnd, uiMsg, wParam, lParam) ;
  3827. }
  3828. return (0);
  3829. }
  3830. HWND CSysmonControl::Window( VOID )
  3831. {
  3832. return m_hWnd;
  3833. }
  3834. void CSysmonControl::UpdateGraph( INT nUpdateType )
  3835. {
  3836. RECT rectStats;
  3837. RECT rectGraph;
  3838. PRECT prectUpdate = NULL;
  3839. RECT rectClient;
  3840. // Based on type of change either force redraw or resize components
  3841. switch (nUpdateType) {
  3842. case UPDGRPH_ADDCNTR:
  3843. case UPDGRPH_DELCNTR:
  3844. if ( m_bLogFileSource )
  3845. m_fPendingLogCntrChg = TRUE;
  3846. m_fPendingSizeChg = TRUE;
  3847. break;
  3848. case UPDGRPH_FONT:
  3849. m_fPendingFontChg = TRUE;
  3850. break;
  3851. case UPDGRPH_LOGVIEW:
  3852. m_fPendingLogViewChg = TRUE;
  3853. if (m_hWnd && m_pStatsBar ) {
  3854. m_pStatsBar->GetUpdateRect(&rectStats);
  3855. prectUpdate = &rectStats;
  3856. }
  3857. // Fall into plot area case
  3858. case UPDGRPH_PLOT:
  3859. if ( REPORT_GRAPH != m_pObj->m_Graph.Options.iDisplayType ) {
  3860. if (m_hWnd && m_pGraphDisp) {
  3861. m_pGraphDisp->GetPlotRect(&rectGraph);
  3862. if ( NULL == prectUpdate ) {
  3863. prectUpdate = &rectGraph;
  3864. } else {
  3865. ::UnionRect( prectUpdate, &rectStats, &rectGraph);
  3866. }
  3867. }
  3868. } else {
  3869. GetClientRect (m_hWnd, &rectClient);
  3870. prectUpdate = &rectClient;
  3871. }
  3872. break;
  3873. case UPDGRPH_COLOR:
  3874. //update the toolbar color
  3875. m_pToolbar->SetBackgroundColor ( clrBackCtl() );
  3876. m_fPendingSizeChg = TRUE;
  3877. break;
  3878. case UPDGRPH_LAYOUT:
  3879. case UPDGRPH_VIEW:
  3880. m_fPendingSizeChg = TRUE;
  3881. break;
  3882. }
  3883. // Set change pending flag to enable ApplyChanges
  3884. m_fPendingUpdate = TRUE;
  3885. // If we're ready to do updates
  3886. if (m_fViewInitialized) {
  3887. // Invalidate window to force redraw
  3888. InvalidateRect(m_hWnd, prectUpdate, TRUE);
  3889. // Notify container of change
  3890. m_pObj->SendAdvise(OBJECTCODE_DATACHANGED);
  3891. }
  3892. }
  3893. void
  3894. CSysmonControl::OnValuesUpdated ( VOID )
  3895. {
  3896. // If event sync present, send notification from the
  3897. // main thread, outside of lock.
  3898. m_pObj->SendEvent(eEventOnSampleCollected, 0);
  3899. }
  3900. void
  3901. CSysmonControl::UpdateGraphData( VOID )
  3902. {
  3903. HDC hDC = NULL;
  3904. PGRAPHDATA pGraph = &m_pObj->m_Graph;
  3905. OnValuesUpdated();
  3906. if (m_fViewInitialized) {
  3907. UpdateAppPerfTimeData (TD_UPDATE_TIME, TD_BEGIN);
  3908. hDC = GetDC(m_hWnd);
  3909. // Update statistics if active
  3910. // Statistics are updated before the graph display in case the
  3911. // graph display selects a clipping region.
  3912. if (pGraph->Options.bValueBarChecked &&m_pSelectedItem != NULL) {
  3913. // The stats bar doesn't always use the hDC, so passing NULL
  3914. // hDC is okay.
  3915. m_pStatsBar->Update(hDC, m_pSelectedItem);
  3916. }
  3917. if ( NULL != hDC ) {
  3918. // Update graph display
  3919. m_pGraphDisp->Update(hDC);
  3920. m_pReport->Update();
  3921. ReleaseDC(m_hWnd, hDC);
  3922. }
  3923. UpdateAppPerfTimeData (TD_UPDATE_TIME, TD_END);
  3924. }
  3925. }
  3926. void CSysmonControl::Render(
  3927. HDC hDC,
  3928. HDC hAttribDC,
  3929. BOOL fMetafile,
  3930. BOOL fEntire,
  3931. LPRECT pRect )
  3932. {
  3933. HDC hLocalAttribDC = NULL;
  3934. // If not inited, return.
  3935. if ( m_fViewInitialized ) {
  3936. if ( NULL == hAttribDC ) {
  3937. hLocalAttribDC = GetDC(m_hWnd);
  3938. } else {
  3939. hLocalAttribDC = hAttribDC;
  3940. }
  3941. // Make sure layout is up to date.
  3942. ApplyChanges( hLocalAttribDC );
  3943. if ( NULL != hDC && NULL != hLocalAttribDC ) {
  3944. if ( REPORT_GRAPH == m_pObj->m_Graph.Options.iDisplayType ) {
  3945. m_pReport->Render( hDC, hLocalAttribDC, fMetafile, fEntire, pRect );
  3946. } else {
  3947. // Fill with background color
  3948. SetBkColor(hDC, clrBackCtl());
  3949. ClearRect(hDC, pRect);
  3950. m_pStatsBar->Draw(hDC, hLocalAttribDC, pRect);
  3951. m_pGraphDisp->Draw(hDC, hLocalAttribDC, fMetafile, fEntire, pRect );
  3952. m_pLegend->Render(hDC, hLocalAttribDC, fMetafile, fEntire, pRect);
  3953. }
  3954. if ( eBorderSingle == m_iBorderStyle ) {
  3955. if ( eAppear3D == m_iAppearance ) {
  3956. DrawEdge(hDC, pRect, EDGE_RAISED, BF_RECT);
  3957. } else {
  3958. SelectBrush (hDC, GetStockObject (HOLLOW_BRUSH)) ;
  3959. SelectPen (hDC, GetStockObject (BLACK_PEN)) ;
  3960. Rectangle (hDC, pRect->left, pRect->top, pRect->right, pRect->bottom );
  3961. }
  3962. }
  3963. }
  3964. if ( NULL != hLocalAttribDC && hAttribDC != hLocalAttribDC ) {
  3965. ReleaseDC ( m_hWnd, hLocalAttribDC );
  3966. }
  3967. }
  3968. }
  3969. void CSysmonControl::SetIntervalTimer()
  3970. {
  3971. HDC hDC = NULL;
  3972. PGRAPHDATA pGraph = &m_pObj->m_Graph;
  3973. // if not initialized or counter source is a log file, nothing to do
  3974. if (!m_fInitialized || IsLogSource() || !IsUserMode() )
  3975. return;
  3976. // Update statistics bar
  3977. m_pStatsBar->SetTimeSpan(
  3978. m_pObj->m_Graph.Options.fUpdateInterval
  3979. * m_pObj->m_Graph.Options.iDisplayFilter
  3980. * m_pHistCtrl->nMaxSamples );
  3981. hDC = GetDC(m_hWnd);
  3982. if ( NULL != hDC ) {
  3983. m_pStatsBar->Update(hDC, m_pSelectedItem);
  3984. ReleaseDC(m_hWnd,hDC);
  3985. }
  3986. // If conditions right for sampling, start new time interval.
  3987. // Otherwise, suspend the collection.
  3988. if (!pGraph->Options.bManualUpdate
  3989. && pGraph->Options.fUpdateInterval >= 0.001 // ??
  3990. && pGraph->CounterTree.NumCounters() != 0
  3991. && IsUserMode() ) {
  3992. m_CollectInfo.dwInterval= (DWORD)(pGraph->Options.fUpdateInterval * 1000);
  3993. m_CollectInfo.dwSampleTime = GetTickCount();
  3994. m_CollectInfo.iMode = COLLECT_ACTIVE;
  3995. }
  3996. else {
  3997. m_CollectInfo.iMode = COLLECT_SUSPEND;
  3998. }
  3999. assert ( NULL != m_CollectInfo.hEvent );
  4000. // Signal the collection thread
  4001. SetEvent(m_CollectInfo.hEvent);
  4002. // If no counters, reset sample time to start
  4003. if (pGraph->CounterTree.NumCounters() == 0) {
  4004. m_pHistCtrl->iCurrent = 0;
  4005. m_pHistCtrl->nSamples = 0;
  4006. pGraph->TimeStepper.Reset();
  4007. }
  4008. }
  4009. HRESULT CSysmonControl::AddSingleCounter(LPWSTR pszPath, PCGraphItem *pGItem)
  4010. {
  4011. PCGraphItem pGraphItem;
  4012. PGRAPHDATA pGraph = &m_pObj->m_Graph;
  4013. HRESULT hr;
  4014. BOOL bAddSuccessful = FALSE;
  4015. INT iCounterIndex = 0;
  4016. *pGItem = NULL;
  4017. // Create graph item
  4018. pGraphItem = new CGraphItem(this);
  4019. if (pGraphItem == NULL)
  4020. return E_OUTOFMEMORY;
  4021. LockCounterData();
  4022. // Add it to the counter tree
  4023. hr = pGraph->CounterTree.AddCounterItem(
  4024. pszPath,
  4025. pGraphItem,
  4026. pGraph->Options.bMonitorDuplicateInstances);
  4027. if (SUCCEEDED(hr)) {
  4028. // AddRef once for ourself
  4029. pGraphItem->AddRef();
  4030. // Set default attributes
  4031. pGraphItem->put_Color(IndexToStandardColor(m_iColorIndex));
  4032. pGraphItem->put_Width(IndexToWidth(m_iWidthIndex));
  4033. pGraphItem->put_LineStyle(IndexToStyle(m_iStyleIndex));
  4034. pGraphItem->put_ScaleFactor(m_iScaleFactor);
  4035. // Increment and reset for next counter
  4036. IncrementVisuals();
  4037. m_iScaleFactor = INT_MAX;
  4038. // Add item to graph's query
  4039. if ( NULL != m_hQuery ) {
  4040. hr = pGraphItem->AddToQuery(m_hQuery);
  4041. } else {
  4042. hr = E_FAIL;
  4043. }
  4044. if (SUCCEEDED(hr)) {
  4045. hr = pGraph->CounterTree.IndexFromCounter( pGraphItem, &iCounterIndex );
  4046. if ( SUCCEEDED ( hr ) ) {
  4047. bAddSuccessful = TRUE;
  4048. // If control is initialized
  4049. if (m_fViewInitialized) {
  4050. // Add item to chart legend
  4051. m_pLegend->AddItem(pGraphItem);
  4052. m_pReport->AddItem(pGraphItem);
  4053. }
  4054. }
  4055. else {
  4056. // remove the item from the tree
  4057. pGraphItem->Instance()->RemoveItem(pGraphItem);
  4058. }
  4059. } else {
  4060. // remove the item from the tree
  4061. pGraphItem->Instance()->RemoveItem(pGraphItem);
  4062. }
  4063. // If OK, Addref the returned interface
  4064. if (SUCCEEDED(hr)) {
  4065. pGraphItem->AddRef();
  4066. *pGItem = pGraphItem;
  4067. } // else released by RemoveItem above.
  4068. // Update messages seem to be combined, so histogram sometimes updates instead of
  4069. // repainting each entire bar. This forces total repaint.
  4070. if ( m_pGraphDisp) {
  4071. m_pGraphDisp->SetBarConfigChanged();
  4072. }
  4073. } else {
  4074. // AddCounterItem failed
  4075. delete pGraphItem;
  4076. }
  4077. UnlockCounterData();
  4078. // Send events outside of locks.
  4079. if ( bAddSuccessful ) {
  4080. // If first counter
  4081. if (pGraph->CounterTree.NumCounters() == 1) {
  4082. // Make it the selected counter and send event.
  4083. SelectCounter(pGraphItem);
  4084. // Start data collection
  4085. if ( ERROR_SUCCESS != ActivateQuery() ) {
  4086. hr = E_FAIL;
  4087. }
  4088. }
  4089. // Redraw the graph
  4090. UpdateGraph(UPDGRPH_ADDCNTR);
  4091. m_pObj->SendEvent(eEventOnCounterAdded, iCounterIndex );
  4092. }
  4093. return hr;
  4094. }
  4095. PCCounterTree
  4096. CSysmonControl::CounterTree(
  4097. VOID
  4098. )
  4099. {
  4100. return &(m_pObj->m_Graph.CounterTree);
  4101. }
  4102. PCGraphItem
  4103. CSysmonControl::FirstCounter(
  4104. VOID
  4105. )
  4106. {
  4107. return m_pObj->m_Graph.CounterTree.FirstCounter();
  4108. }
  4109. PCGraphItem
  4110. CSysmonControl::LastCounter(
  4111. VOID
  4112. )
  4113. {
  4114. PCGraphItem pItem;
  4115. PCGraphItem pItemNext;
  4116. if (FirstCounter() == NULL)
  4117. return NULL;
  4118. // Locate last graph item
  4119. pItem = FirstCounter();
  4120. while ((pItemNext = pItem->Next()) != NULL)
  4121. pItem = pItemNext;
  4122. return pItem;
  4123. }
  4124. BOOL
  4125. CSysmonControl::IsLogSource(
  4126. VOID
  4127. )
  4128. {
  4129. return m_pHistCtrl->bLogSource;
  4130. }
  4131. BOOL
  4132. CSysmonControl::IsReadOnly(
  4133. VOID
  4134. )
  4135. {
  4136. BOOL bReturn = TRUE;
  4137. if (m_fInitialized ) {
  4138. bReturn = m_pObj->m_Graph.Options.bReadOnly;
  4139. }
  4140. return bReturn;
  4141. }
  4142. eReportValueTypeConstant
  4143. CSysmonControl::ReportValueType(
  4144. VOID
  4145. )
  4146. {
  4147. return ( (eReportValueTypeConstant) m_pObj->m_Graph.Options.iReportValueType );
  4148. }
  4149. INT CSysmonControl::CounterIndex(PCGraphItem pItem)
  4150. {
  4151. PCGraphItem pItemLoc;
  4152. INT iIndex;
  4153. // Traverse linked list until item matched
  4154. pItemLoc = FirstCounter();
  4155. iIndex = 1;
  4156. while (pItemLoc != pItem && pItemLoc != NULL) {
  4157. pItemLoc = pItemLoc->Next();
  4158. iIndex++;
  4159. }
  4160. return (pItemLoc == NULL) ? -1 : iIndex;
  4161. }
  4162. HRESULT CSysmonControl::DeleteCounter(PCGraphItem pItem, BOOL bPropagateUp)
  4163. {
  4164. PGRAPHDATA pGraph = &m_pObj->m_Graph;
  4165. if (pItem == NULL)
  4166. return E_INVALIDARG;
  4167. // Send event
  4168. m_pObj->SendEvent(eEventOnCounterDeleted, CounterIndex(pItem));
  4169. LockCounterData();
  4170. // If this is the selected counter, change selection to NULL
  4171. if (pItem == m_pSelectedItem)
  4172. m_pSelectedItem = NULL;
  4173. if (m_fViewInitialized) {
  4174. // Remove from legend and report
  4175. m_pLegend->DeleteItem(pItem);
  4176. m_pReport->DeleteItem(pItem);
  4177. // Remove from query
  4178. pItem->RemoveFromQuery();
  4179. }
  4180. // Proagate deletion up the tree if requested
  4181. if (bPropagateUp) {
  4182. pItem->Instance()->RemoveItem(pItem);
  4183. }
  4184. // If last counter, stop interval timer
  4185. if (pGraph->CounterTree.NumCounters() == 0)
  4186. SetIntervalTimer();
  4187. // Update messages seem to be combined, so histogram sometimes updates instead of
  4188. // repainting each entire bar. This forces total repaint.
  4189. if ( m_pGraphDisp) {
  4190. m_pGraphDisp->SetBarConfigChanged();
  4191. }
  4192. UnlockCounterData();
  4193. if ( m_fViewInitialized ) {
  4194. UpdateGraph(UPDGRPH_DELCNTR);
  4195. }
  4196. return NOERROR;
  4197. }
  4198. void CSysmonControl::SelectCounter(PCGraphItem pItem)
  4199. {
  4200. HDC hDC = NULL;
  4201. INT iIndex;
  4202. // Selection in the graph view is maintained independently
  4203. // of the selection in the report view.
  4204. if ( REPORT_GRAPH != m_pObj->m_Graph.Options.iDisplayType ) {
  4205. // Save as current item
  4206. m_pSelectedItem = pItem;
  4207. if (m_fViewInitialized) {
  4208. // Inform Legend
  4209. m_pLegend->SelectItem(pItem);
  4210. // Highlight selected item in graph display
  4211. if (m_pObj->m_Graph.Options.bHighlight) {
  4212. m_pGraphDisp->HiliteItem(pItem);
  4213. UpdateGraph(UPDGRPH_PLOT);
  4214. }
  4215. // Update statistics bar
  4216. if ( m_fViewInitialized )
  4217. hDC = GetDC(m_hWnd);
  4218. m_pStatsBar->Update(hDC, pItem);
  4219. if ( NULL != hDC )
  4220. ReleaseDC(m_hWnd,hDC);
  4221. }
  4222. }
  4223. // Send event
  4224. iIndex = (pItem == NULL) ? 0 : CounterIndex(pItem);
  4225. m_pObj->SendEvent(eEventOnCounterSelected, iIndex);
  4226. }
  4227. HRESULT
  4228. CSysmonControl::PasteFromBuffer( LPWSTR pszData, BOOL bAllData )
  4229. {
  4230. HRESULT hr = NOERROR;
  4231. CImpIPropertyBag IPropBag;
  4232. hr = IPropBag.LoadData( pszData );
  4233. if ( SUCCEEDED ( hr ) ) {
  4234. INT nLogType = SMON_CTRL_LOG;
  4235. //get the log type from the pPropBag and compare it with service(cookie) type
  4236. //Determine log type from property bag. Default to -1 SMON_CTRL_LOG
  4237. hr = IntegerFromPropertyBag (
  4238. &IPropBag,
  4239. NULL,
  4240. CGlobalString::m_cszLogType,
  4241. nLogType);
  4242. if(nLogType == SLQ_TRACE_LOG){
  4243. MessageBox(
  4244. m_hWnd,
  4245. ResourceString(IDS_TRACE_LOG_ERR_MSG),
  4246. ResourceString(IDS_APP_NAME),
  4247. MB_OK
  4248. );
  4249. } else {
  4250. if ( bAllData ) {
  4251. hr = LoadFromPropertyBag( &IPropBag, NULL );
  4252. } else {
  4253. // Do not load sample data for Paste or Drop File.
  4254. hr = LoadCountersFromPropertyBag (&IPropBag, NULL, FALSE );
  4255. }
  4256. }
  4257. }
  4258. return hr;
  4259. }
  4260. HRESULT CSysmonControl::Paste()
  4261. {
  4262. HRESULT hResReturn = NOERROR;
  4263. HANDLE hMemClipboard;
  4264. // get the clipboard
  4265. if (OpenClipboard (Window())) {
  4266. // read the CF_TEXT or CF_UNICODE data from the clipboard to the local buffer
  4267. hMemClipboard = GetClipboardData (
  4268. #if UNICODE
  4269. CF_UNICODETEXT); // UNICODE text in the clipboard
  4270. #else
  4271. CF_TEXT); // ANSI text in the clipboard
  4272. #endif
  4273. if (hMemClipboard != NULL) {
  4274. LPWSTR pszData;
  4275. if ( ConfirmSampleDataOverwrite ( ) ) {
  4276. pszData = (LPWSTR)GlobalLock (hMemClipboard);// (LPWSTR)hMemClipboard;
  4277. if ( NULL != pszData ) {
  4278. hResReturn = PasteFromBuffer ( pszData, FALSE );
  4279. GlobalUnlock ( hMemClipboard );
  4280. }
  4281. }
  4282. }
  4283. // release the clipboard
  4284. CloseClipboard();
  4285. } else {
  4286. // unable to open the clipboard
  4287. hResReturn = HRESULT_FROM_WIN32(GetLastError());
  4288. }
  4289. return hResReturn;
  4290. }
  4291. HRESULT
  4292. CSysmonControl::CopyToBuffer ( LPWSTR& rpszData, DWORD& rdwBufferSize )
  4293. {
  4294. HRESULT hr = S_OK;
  4295. CImpIPropertyBag IPropBag;
  4296. assert ( NULL == rpszData );
  4297. rdwBufferSize = 0;
  4298. if (NULL!=m_pObj->m_pImpIPersistPropertyBag) {
  4299. hr = m_pObj->m_pImpIPersistPropertyBag->Save (&IPropBag, FALSE, TRUE );
  4300. }
  4301. if ( SUCCEEDED ( hr ) ) {
  4302. DWORD dwBufferLength;
  4303. LPWSTR pszConfig;
  4304. pszConfig = IPropBag.GetData();
  4305. if ( NULL != pszConfig ) {
  4306. //
  4307. // Buffer length includes 1 for NULL terminator.
  4308. //
  4309. dwBufferLength = lstrlen ( CGlobalString::m_cszHtmlObjectHeader ) + lstrlen ( CGlobalString::m_cszHtmlObjectFooter ) + lstrlen ( pszConfig ) + 1;
  4310. rpszData = new WCHAR[dwBufferLength];
  4311. if ( NULL == rpszData ) {
  4312. hr = E_OUTOFMEMORY;
  4313. } else {
  4314. rdwBufferSize = dwBufferLength * sizeof(WCHAR);
  4315. rpszData[0] = L'\0';
  4316. StringCchCopy(rpszData, dwBufferLength, CGlobalString::m_cszHtmlObjectHeader );
  4317. StringCchCat(rpszData, dwBufferLength, pszConfig );
  4318. StringCchCat(rpszData, dwBufferLength, CGlobalString::m_cszHtmlObjectFooter );
  4319. }
  4320. } else {
  4321. hr = E_UNEXPECTED;
  4322. }
  4323. }
  4324. return hr;
  4325. }
  4326. HRESULT CSysmonControl::Copy()
  4327. {
  4328. HGLOBAL hBuffer = NULL;
  4329. HRESULT hResReturn = S_OK;
  4330. LPWSTR pszBuffer = NULL;
  4331. DWORD dwBufferSize;
  4332. HANDLE hMemClipboard;
  4333. LPWSTR pszGlobalBuffer = NULL;
  4334. hResReturn = CopyToBuffer( pszBuffer, dwBufferSize);
  4335. if ( SUCCEEDED ( hResReturn ) && ( NULL != pszBuffer ) ) {
  4336. hBuffer = GlobalAlloc ((GMEM_MOVEABLE | GMEM_DDESHARE), dwBufferSize);
  4337. if ( NULL != hBuffer ) {
  4338. pszGlobalBuffer = (LPWSTR)GlobalLock (hBuffer);
  4339. if ( NULL != pszGlobalBuffer ) {
  4340. StringCchCopy (pszGlobalBuffer, dwBufferSize, pszBuffer );
  4341. GlobalUnlock (hBuffer);
  4342. } else {
  4343. // allocation or lock failed so bail out
  4344. hResReturn = E_OUTOFMEMORY;
  4345. }
  4346. }
  4347. }
  4348. if ( NULL != pszBuffer ) {
  4349. delete [] pszBuffer;
  4350. }
  4351. if ( NULL != hBuffer && SUCCEEDED ( hResReturn ) ) {
  4352. // then there's something to copy so...
  4353. // get the clipboard
  4354. if (OpenClipboard (m_hWnd)) {
  4355. // copy the counter list to the clipboard
  4356. if (EmptyClipboard()) {
  4357. hMemClipboard = SetClipboardData (
  4358. #if UNICODE
  4359. CF_UNICODETEXT, // UNICODE text in the clipboard
  4360. #else
  4361. CF_TEXT, // ANSI text in the clipboard
  4362. #endif
  4363. hBuffer);
  4364. if (hMemClipboard == NULL) {
  4365. // unable to set data in the clipboard
  4366. hResReturn = HRESULT_FROM_WIN32(GetLastError());
  4367. }
  4368. } else {
  4369. // unable to empty the clipboard
  4370. hResReturn = HRESULT_FROM_WIN32(GetLastError());
  4371. }
  4372. // release the clipboard
  4373. CloseClipboard();
  4374. } else {
  4375. // unable to open the clipboard
  4376. hResReturn = HRESULT_FROM_WIN32(GetLastError());
  4377. }
  4378. }
  4379. if ( NULL != hBuffer ) {
  4380. GlobalFree ( hBuffer ) ;
  4381. }
  4382. return hResReturn;
  4383. }
  4384. HRESULT CSysmonControl::Reset()
  4385. {
  4386. PCGraphItem pItem;
  4387. // Request each counter from the control, to compute
  4388. // required buffer size
  4389. while ((pItem = FirstCounter())!= NULL) {
  4390. // delete this counter
  4391. DeleteCounter (pItem, TRUE);
  4392. }
  4393. m_iColorIndex = 0;
  4394. m_iWidthIndex = 0;
  4395. m_iStyleIndex = 0;
  4396. return NOERROR;
  4397. }
  4398. void CSysmonControl::DblClickCounter(PCGraphItem pItem)
  4399. {
  4400. INT iIndex;
  4401. // Send event
  4402. iIndex = (pItem == NULL) ? 0 : CounterIndex(pItem);
  4403. m_pObj->SendEvent(eEventOnDblClick, iIndex);
  4404. }
  4405. BOOL
  4406. CSysmonControl::ConfirmSampleDataOverwrite ( )
  4407. {
  4408. BOOL bOverwrite = TRUE;
  4409. if ( m_bSampleDataLoaded ) {
  4410. // Confirm overwrite of view-only data.
  4411. INT iOverwrite = IDNO;
  4412. assert ( FALSE == m_fInitialized );
  4413. iOverwrite = MessageBox(
  4414. Window(),
  4415. ResourceString(IDS_SAMPLE_DATA_OVERWRITE),
  4416. ResourceString(IDS_APP_NAME),
  4417. MB_YESNO );
  4418. if ( IDYES == iOverwrite ) {
  4419. m_bSampleDataLoaded = FALSE;
  4420. bOverwrite = Init ( g_hWndFoster );
  4421. UpdateGraph(UPDGRPH_LAYOUT); // If toolbar enabled, must resize
  4422. // Also clears the graph
  4423. } else {
  4424. bOverwrite = FALSE;
  4425. }
  4426. }
  4427. return bOverwrite;
  4428. }
  4429. void
  4430. CSysmonControl::Clear ( void )
  4431. {
  4432. if ( ConfirmSampleDataOverwrite() ) {
  4433. PCGraphItem pItem;
  4434. m_pHistCtrl->nMaxSamples = MAX_GRAPH_SAMPLES;
  4435. m_pHistCtrl->iCurrent = 0;
  4436. m_pHistCtrl->nSamples = 0;
  4437. m_pHistCtrl->nBacklog = 0;
  4438. m_pObj->m_Graph.TimeStepper.Reset();
  4439. m_pStatsBar->Clear();
  4440. // Reset history for all counters
  4441. for (pItem = FirstCounter(); pItem != NULL; pItem = pItem->Next()) {
  4442. pItem->ClearHistory();
  4443. }
  4444. // Repaint the graph and value bar
  4445. UpdateGraph(UPDGRPH_VIEW);
  4446. }
  4447. }
  4448. PDH_STATUS
  4449. CSysmonControl::UpdateCounterValues ( BOOL fValidSample )
  4450. {
  4451. PDH_STATUS stat = ERROR_SUCCESS;
  4452. PCGraphItem pItem;
  4453. PGRAPHDATA pGraph = &m_pObj->m_Graph;
  4454. // If no query or no counters assign, nothing to do
  4455. if ( NULL == m_hQuery
  4456. || pGraph->CounterTree.NumCounters() == 0
  4457. || !IsUserMode() ) {
  4458. stat = ERROR_SUCCESS;
  4459. } else {
  4460. if ( ConfirmSampleDataOverwrite () ) {
  4461. // If valid sample, collect the data
  4462. if (fValidSample) {
  4463. UpdateAppPerfTimeData (TD_P_QUERY_TIME, TD_BEGIN);
  4464. stat = PdhCollectQueryData(m_hQuery);
  4465. UpdateAppPerfTimeData (TD_P_QUERY_TIME, TD_END);
  4466. }
  4467. if ( ERROR_SUCCESS == stat ) {
  4468. UpdateAppPerfTimeData (TD_S_QUERY_TIME, TD_BEGIN);
  4469. LockCounterData();
  4470. // Update history control and all counter history arrays
  4471. m_pHistCtrl->iCurrent++;
  4472. if (m_pHistCtrl->iCurrent == m_pHistCtrl->nMaxSamples)
  4473. m_pHistCtrl->iCurrent = 0;
  4474. if (m_pHistCtrl->nSamples < m_pHistCtrl->nMaxSamples)
  4475. m_pHistCtrl->nSamples++;
  4476. // Update history for all counters
  4477. for (pItem = FirstCounter(); pItem != NULL; pItem = pItem->Next()) {
  4478. pItem->UpdateHistory(fValidSample);
  4479. }
  4480. // If we're initialized and have at least two samples
  4481. if (m_fInitialized && m_pHistCtrl->nSamples >= 2) {
  4482. // If no backlogged updates, post an update message
  4483. // Ensure that OnSampleCollected event is triggered in any case.
  4484. if (m_pHistCtrl->nBacklog == 0) {
  4485. PostMessage(m_hWnd, WM_GRAPH_UPDATE, 0, 0);
  4486. } else {
  4487. PostMessage(m_hWnd, WM_VALUES_UPDATED, 0, 0);
  4488. }
  4489. m_pHistCtrl->nBacklog++;
  4490. }
  4491. UnlockCounterData();
  4492. UpdateAppPerfTimeData (TD_S_QUERY_TIME, TD_END);
  4493. }
  4494. }
  4495. }
  4496. return ERROR_SUCCESS;
  4497. }
  4498. void CSysmonControl::Activate( VOID )
  4499. {
  4500. if (!m_fUIDead) {
  4501. m_pObj->UIActivate();
  4502. }
  4503. }
  4504. void CSysmonControl::put_Appearance(INT iAppearance, BOOL fAmbient)
  4505. {
  4506. INT iLocalAppearance;
  4507. if (fAmbient && m_pObj->m_Graph.Options.iAppearance != NULL_APPEARANCE)
  4508. return;
  4509. if (!fAmbient) {
  4510. m_pObj->m_Graph.Options.iAppearance = iAppearance;
  4511. }
  4512. // Any non-zero value translates to 3D. In ambient case, the high bits are sometimes set.
  4513. if ( iAppearance ) {
  4514. iLocalAppearance = eAppear3D;
  4515. } else {
  4516. iLocalAppearance = eAppearFlat;
  4517. }
  4518. m_iAppearance = iLocalAppearance;
  4519. UpdateGraph(UPDGRPH_COLOR);
  4520. }
  4521. void CSysmonControl::put_BorderStyle(INT iBorderStyle, BOOL fAmbient)
  4522. {
  4523. if (fAmbient && m_pObj->m_Graph.Options.iBorderStyle != NULL_BORDERSTYLE)
  4524. return;
  4525. if (!fAmbient) {
  4526. m_pObj->m_Graph.Options.iBorderStyle = iBorderStyle;
  4527. }
  4528. m_iBorderStyle = iBorderStyle;
  4529. UpdateGraph(UPDGRPH_COLOR);
  4530. }
  4531. void CSysmonControl::put_BackCtlColor(OLE_COLOR Color)
  4532. {
  4533. m_pObj->m_Graph.Options.clrBackCtl = Color;
  4534. OleTranslateColor(Color, NULL, &m_clrBackCtl);
  4535. UpdateGraph(UPDGRPH_COLOR);
  4536. }
  4537. void CSysmonControl::put_FgndColor (
  4538. OLE_COLOR Color,
  4539. BOOL fAmbient
  4540. )
  4541. {
  4542. if (fAmbient && m_pObj->m_Graph.Options.clrFore != NULL_COLOR)
  4543. return;
  4544. if (!fAmbient)
  4545. m_pObj->m_Graph.Options.clrFore = Color;
  4546. OleTranslateColor(Color, NULL, &m_clrFgnd);
  4547. UpdateGraph(UPDGRPH_COLOR);
  4548. }
  4549. void CSysmonControl::put_BackPlotColor (
  4550. OLE_COLOR Color,
  4551. BOOL fAmbient
  4552. )
  4553. {
  4554. if (fAmbient && m_pObj->m_Graph.Options.clrBackPlot != NULL_COLOR)
  4555. return;
  4556. if (!fAmbient)
  4557. m_pObj->m_Graph.Options.clrBackPlot = Color;
  4558. OleTranslateColor(Color, NULL, &m_clrBackPlot);
  4559. UpdateGraph(UPDGRPH_PLOT);
  4560. }
  4561. void CSysmonControl::put_GridColor (
  4562. OLE_COLOR Color
  4563. )
  4564. {
  4565. // Options color is the OLE_COLOR.
  4566. // Color in control is translated from OLE_COLOR.
  4567. m_pObj->m_Graph.Options.clrGrid = Color;
  4568. OleTranslateColor(Color, NULL, &m_clrGrid);
  4569. UpdateGraph(UPDGRPH_PLOT);
  4570. }
  4571. void CSysmonControl::put_TimeBarColor (
  4572. OLE_COLOR Color
  4573. )
  4574. {
  4575. // Options color is the OLE_COLOR.
  4576. // Color in control is translated from OLE_COLOR.
  4577. m_pObj->m_Graph.Options.clrTimeBar = Color;
  4578. OleTranslateColor(Color, NULL, &m_clrTimeBar);
  4579. UpdateGraph(UPDGRPH_PLOT);
  4580. }
  4581. HRESULT CSysmonControl::put_Font (
  4582. LPFONT pIFont,
  4583. BOOL fAmbient
  4584. )
  4585. {
  4586. HRESULT hr = NOERROR;
  4587. if ( NULL == pIFont ) {
  4588. hr = E_INVALIDARG;
  4589. } else {
  4590. if ( fAmbient && FALSE == m_pObj->m_Graph.Options.bAmbientFont ) {
  4591. hr = NOERROR;
  4592. } else {
  4593. if (!fAmbient) {
  4594. m_pObj->m_Graph.Options.bAmbientFont = FALSE;
  4595. }
  4596. hr = m_OleFont.SetIFont(pIFont);
  4597. }
  4598. }
  4599. return hr;
  4600. }
  4601. void CSysmonControl::FontChanged(
  4602. void
  4603. )
  4604. {
  4605. m_pReport->ChangeFont();
  4606. UpdateGraph(UPDGRPH_FONT);
  4607. }
  4608. DWORD WINAPI
  4609. CollectProc (
  4610. IN PSYSMONCTRL pCtrl
  4611. )
  4612. {
  4613. DWORD dwElapsedTime;
  4614. DWORD dwTimeout = INFINITE;
  4615. COLLECT_PROC_INFO *pCollectInfo = &pCtrl->m_CollectInfo;
  4616. while (TRUE) {
  4617. // Wait for event or next sample period
  4618. WaitForSingleObject(pCollectInfo->hEvent, dwTimeout);
  4619. // If quit request, exit loop
  4620. if (pCollectInfo->iMode == COLLECT_QUIT)
  4621. break;
  4622. // If suspended, wait for an event
  4623. if (pCollectInfo->iMode == COLLECT_SUSPEND) {
  4624. dwTimeout = INFINITE;
  4625. continue;
  4626. }
  4627. // Take a sample
  4628. pCtrl->UpdateCounterValues(TRUE);
  4629. // Get elapsed time from last sample time
  4630. dwElapsedTime = GetTickCount() - pCollectInfo->dwSampleTime;
  4631. if (dwElapsedTime > 100000)
  4632. dwElapsedTime = 0;
  4633. // Have we missed any sample times?
  4634. while (dwElapsedTime > pCollectInfo->dwInterval) {
  4635. // By how much?
  4636. dwElapsedTime -= pCollectInfo->dwInterval;
  4637. // If less than 1/2 an interval, take the sample now
  4638. // otherwise record a missed one
  4639. if (dwElapsedTime < pCollectInfo->dwInterval/2) {
  4640. pCtrl->UpdateCounterValues(TRUE);
  4641. } else {
  4642. pCtrl->UpdateCounterValues(FALSE);
  4643. }
  4644. // Advance to next sample time
  4645. pCollectInfo->dwSampleTime += pCollectInfo->dwInterval;
  4646. }
  4647. // Set timeout to wait until next sample time
  4648. dwTimeout = pCollectInfo->dwInterval - dwElapsedTime;
  4649. pCollectInfo->dwSampleTime += pCollectInfo->dwInterval;
  4650. }
  4651. return 0;
  4652. }
  4653. HRESULT
  4654. CSysmonControl::InitLogFileIntervals ( void )
  4655. {
  4656. HRESULT hr = S_OK;
  4657. PDH_STATUS pdhstat;
  4658. DWORD nLogEntries = 0;
  4659. DWORD nBufSize;
  4660. PDH_TIME_INFO TimeInfo;
  4661. if ( m_bLogFileSource ) {
  4662. // Get time and sample count info
  4663. nBufSize = sizeof(TimeInfo);
  4664. pdhstat = PdhGetDataSourceTimeRangeH(GetDataSourceHandle(),
  4665. & nLogEntries,
  4666. & TimeInfo,
  4667. & nBufSize );
  4668. if ( ERROR_SUCCESS != pdhstat ) {
  4669. if ( ERROR_NOT_ENOUGH_MEMORY == pdhstat ) {
  4670. pdhstat = SMON_STATUS_LOG_FILE_SIZE_LIMIT;
  4671. }
  4672. hr = (HRESULT)pdhstat;
  4673. } else if ( 2 > TimeInfo.SampleCount ) {
  4674. hr = (HRESULT)SMON_STATUS_TOO_FEW_SAMPLES;
  4675. m_DataSourceInfo.llInterval = 1;
  4676. } else {
  4677. // Setup time range info
  4678. m_DataSourceInfo.llBeginTime = TimeInfo.StartTime;
  4679. m_DataSourceInfo.llEndTime = TimeInfo.EndTime;
  4680. // The start or stop time might no longer be valid, so check for
  4681. // relationship between the them as well as for start/begin, stop/end.
  4682. if ( (m_DataSourceInfo.llStartDisp < m_DataSourceInfo.llBeginTime)
  4683. || (m_DataSourceInfo.llStartDisp > m_DataSourceInfo.llEndTime) )
  4684. m_DataSourceInfo.llStartDisp = m_DataSourceInfo.llBeginTime;
  4685. if ( (m_DataSourceInfo.llStopDisp > m_DataSourceInfo.llEndTime)
  4686. || (m_DataSourceInfo.llStopDisp < m_DataSourceInfo.llStartDisp) )
  4687. m_DataSourceInfo.llStopDisp = m_DataSourceInfo.llEndTime;
  4688. m_DataSourceInfo.nSamples = TimeInfo.SampleCount;
  4689. m_DataSourceInfo.llInterval = (m_DataSourceInfo.llEndTime - m_DataSourceInfo.llBeginTime + m_DataSourceInfo.nSamples/2) / (m_DataSourceInfo.nSamples - 1);
  4690. UpdateGraph(UPDGRPH_LOGVIEW);
  4691. }
  4692. } else {
  4693. assert ( FALSE );
  4694. hr = E_FAIL;
  4695. }
  4696. return hr;
  4697. }
  4698. HRESULT
  4699. CSysmonControl::AddSingleLogFile(
  4700. LPCWSTR pszPath,
  4701. CLogFileItem** ppLogFile )
  4702. {
  4703. HRESULT hr = NOERROR;
  4704. CLogFileItem* pLogFile = NULL;
  4705. CLogFileItem* pLocalLogFileItem = NULL;
  4706. if ( NULL != pszPath ) {
  4707. //
  4708. // Check whether the file name is too long
  4709. //
  4710. if (lstrlen(pszPath) > MAX_PATH) {
  4711. return E_INVALIDARG;
  4712. }
  4713. if ( NULL != ppLogFile ) {
  4714. *ppLogFile = NULL;
  4715. }
  4716. // Check to ensure that current data source is NOT log files.
  4717. if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType ) {
  4718. hr = SMON_STATUS_LOG_FILE_DATA_SOURCE;
  4719. } else {
  4720. // Check for duplicate log file name.
  4721. pLogFile = FirstLogFile();
  4722. while ( NULL != pLogFile ) {
  4723. if ( 0 == lstrcmpi ( pszPath, pLogFile->GetPath() ) ) {
  4724. hr = SMON_STATUS_DUPL_LOG_FILE_PATH;
  4725. break;
  4726. }
  4727. pLogFile = pLogFile->Next();
  4728. }
  4729. if (SUCCEEDED(hr)) {
  4730. // Create log file item
  4731. pLocalLogFileItem = new CLogFileItem ( this );
  4732. if ( NULL == pLocalLogFileItem ) {
  4733. hr = E_OUTOFMEMORY;
  4734. } else {
  4735. hr = pLocalLogFileItem->Initialize ( pszPath, &m_DataSourceInfo.pFirstLogFile );
  4736. }
  4737. // TodoLogFiles: ??? Test log file type? Or leave that up to the "SetDataSource" time?
  4738. // TodoLogFiles: Add log file type to the data source info structure
  4739. // TodoLogFiles: If allow the user to add files while data source set to log files,
  4740. // then check that condition here. If log file data source, then resample with
  4741. // new log file.
  4742. // If OK, Addref the returned interface
  4743. if (SUCCEEDED(hr)) {
  4744. // AddRef once for ourselves
  4745. pLocalLogFileItem->AddRef();
  4746. m_DataSourceInfo.lLogFileCount++;
  4747. if ( NULL != ppLogFile ) {
  4748. // AddRef the returned interface
  4749. pLocalLogFileItem->AddRef();
  4750. *ppLogFile = pLocalLogFileItem;
  4751. }
  4752. }
  4753. else {
  4754. if (pLocalLogFileItem != NULL) {
  4755. delete pLocalLogFileItem;
  4756. pLocalLogFileItem = NULL;
  4757. }
  4758. }
  4759. }
  4760. }
  4761. } else {
  4762. hr = E_INVALIDARG;
  4763. }
  4764. return hr;
  4765. }
  4766. HRESULT
  4767. CSysmonControl::RemoveSingleLogFile (
  4768. CLogFileItem* pLogFile )
  4769. {
  4770. HRESULT hr = ERROR_SUCCESS;
  4771. CLogFileItem* pNext;
  4772. CLogFileItem* pPrevious;
  4773. // Check to ensure that current data source is NOT log files.
  4774. if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType ) {
  4775. hr = SMON_STATUS_LOG_FILE_DATA_SOURCE;
  4776. } else {
  4777. pNext = FirstLogFile();
  4778. if ( pNext == pLogFile ) {
  4779. m_DataSourceInfo.pFirstLogFile = pNext->Next();
  4780. } else {
  4781. do {
  4782. pPrevious = pNext;
  4783. pNext = pNext->Next();
  4784. if ( pNext == pLogFile ) {
  4785. break;
  4786. }
  4787. } while ( NULL != pNext );
  4788. if ( NULL != pNext ) {
  4789. pPrevious->SetNext ( pNext->Next() );
  4790. } else {
  4791. // Something is wrong with the list.
  4792. assert ( FALSE );
  4793. hr = E_FAIL;
  4794. }
  4795. }
  4796. m_DataSourceInfo.lLogFileCount--;
  4797. pLogFile->Release();
  4798. }
  4799. return hr;
  4800. }
  4801. HRESULT
  4802. CSysmonControl::ProcessDataSourceType (
  4803. LPCWSTR szDataSourceName,
  4804. INT iDataSourceType )
  4805. {
  4806. HRESULT hr = NOERROR;
  4807. HQUERY hTestQuery = NULL;
  4808. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  4809. HLOG hTestLog = H_REALTIME_DATASOURCE;
  4810. if ( sysmonNullDataSource != iDataSourceType ) {
  4811. // Open the new query
  4812. if (iDataSourceType == sysmonLogFiles ||
  4813. iDataSourceType == sysmonSqlLog) {
  4814. pdhStatus = PdhBindInputDataSource(& hTestLog, szDataSourceName);
  4815. }
  4816. else if (iDataSourceType == sysmonCurrentActivity) {
  4817. m_DataSourceInfo.hDataSource = H_REALTIME_DATASOURCE;
  4818. }
  4819. else {
  4820. pdhStatus = PDH_INVALID_HANDLE;
  4821. }
  4822. if (pdhStatus == ERROR_SUCCESS) {
  4823. pdhStatus = PdhOpenQueryH (hTestLog, 1, & hTestQuery );
  4824. }
  4825. }
  4826. if ( ERROR_SUCCESS != pdhStatus ) {
  4827. if ( ERROR_NOT_ENOUGH_MEMORY == pdhStatus ) {
  4828. hr = (HRESULT)SMON_STATUS_LOG_FILE_SIZE_LIMIT;
  4829. } else {
  4830. hr = (HRESULT)pdhStatus;
  4831. }
  4832. } else {
  4833. // Close the current query
  4834. CloseQuery();
  4835. // At this point, the previous query no longer exists.
  4836. // If any problems with the new query, close it and
  4837. // reset the data source to realtime.
  4838. // Set the data source type
  4839. // The previous log file name is deleted in CloseQuery()
  4840. // For sysmonNullDataSource, the current query is closed,
  4841. // and the query handle is set to NULL.
  4842. m_pObj->m_Graph.Options.iDataSourceType = iDataSourceType;
  4843. // TodoLogFiles: Eliminate use of m_bLogFileSource,
  4844. // using m_pObj->m_Graph.Options.iDataSourceType instead.
  4845. m_bLogFileSource = ( sysmonLogFiles == iDataSourceType
  4846. || sysmonSqlLog == iDataSourceType);
  4847. m_hQuery = hTestQuery;
  4848. m_DataSourceInfo.hDataSource = hTestLog;
  4849. if ( m_bLogFileSource ) {
  4850. hr = InitLogFileIntervals();
  4851. }
  4852. if ( SUCCEEDED ( hr ) && sysmonNullDataSource != iDataSourceType ) {
  4853. // Initialize the new query. For log files, this can be done after
  4854. // InitLogFileIntervals because the methods operate on different fields.
  4855. if ( ERROR_SUCCESS != InitializeQuery() ) {
  4856. hr = E_FAIL;
  4857. } else {
  4858. if ( m_fInitialized ) {
  4859. if ( ERROR_SUCCESS != ActivateQuery() )
  4860. hr = E_FAIL;
  4861. }
  4862. }
  4863. if ( SUCCEEDED ( hr ) && !m_bLogFileSource ) {
  4864. // If note log file data source, pass new time span to statistics bar.
  4865. m_pStatsBar->SetTimeSpan (
  4866. m_pObj->m_Graph.Options.fUpdateInterval
  4867. * m_pObj->m_Graph.Options.iDisplayFilter
  4868. * m_pHistCtrl->nMaxSamples);
  4869. }
  4870. }
  4871. }
  4872. if ( FAILED ( hr ) ) {
  4873. if ( sysmonLogFiles == iDataSourceType
  4874. || sysmonSqlLog == iDataSourceType )
  4875. {
  4876. // If failed with log file query, retry with realtime query.
  4877. assert ( m_bLogFileSource );
  4878. // Status returned is for the original query, not the realtime query.
  4879. // TodoLogFiles: Need to activate query?
  4880. put_DataSourceType ( sysmonCurrentActivity );
  4881. } else {
  4882. // This leaves the control in an odd state with no active query.
  4883. // TodoLogFiles: At least message to user
  4884. CloseQuery();
  4885. put_DataSourceType ( sysmonNullDataSource );
  4886. }
  4887. }
  4888. return hr;
  4889. }
  4890. HRESULT
  4891. CSysmonControl::get_DataSourceType (
  4892. eDataSourceTypeConstant& reDataSourceType )
  4893. {
  4894. HRESULT hr = NOERROR;
  4895. reDataSourceType = (eDataSourceTypeConstant)m_pObj->m_Graph.Options.iDataSourceType;
  4896. return hr;
  4897. }
  4898. HRESULT
  4899. CSysmonControl::put_DataSourceType (
  4900. INT iDataSourceType )
  4901. {
  4902. HRESULT hr = NOERROR;
  4903. DWORD dwStatus = ERROR_SUCCESS;
  4904. LPWSTR szDataSourceName = NULL;
  4905. // TodoLogFiles: Implement multi-file.
  4906. // TodoLogFiles: Use single data source name?
  4907. //
  4908. if (sysmonLogFiles == iDataSourceType) {
  4909. CLogFileItem * pLogFile = FirstLogFile();
  4910. ULONG ulListLen = 0;
  4911. if (pLogFile == NULL) {
  4912. hr = E_INVALIDARG;
  4913. }
  4914. else {
  4915. dwStatus = BuildLogFileList ( NULL, FALSE, &ulListLen );
  4916. szDataSourceName = (LPWSTR) malloc(ulListLen * sizeof(WCHAR));
  4917. if ( NULL != szDataSourceName ) {
  4918. dwStatus = BuildLogFileList ( szDataSourceName, FALSE, &ulListLen );
  4919. } else {
  4920. hr = E_OUTOFMEMORY;
  4921. }
  4922. }
  4923. }
  4924. else if (sysmonSqlLog == iDataSourceType) {
  4925. if ( m_DataSourceInfo.szSqlDsnName && m_DataSourceInfo.szSqlLogSetName ) {
  4926. if ( m_DataSourceInfo.szSqlDsnName[0] != _T('\0') && m_DataSourceInfo.szSqlLogSetName[0] != _T('\0')) {
  4927. ULONG ulLogFileNameLen = 0;
  4928. dwStatus = FormatSqlDataSourceName (
  4929. m_DataSourceInfo.szSqlDsnName,
  4930. m_DataSourceInfo.szSqlLogSetName,
  4931. NULL,
  4932. &ulLogFileNameLen );
  4933. if ( ERROR_SUCCESS == dwStatus ) {
  4934. szDataSourceName = (LPWSTR) malloc(ulLogFileNameLen * sizeof(WCHAR));
  4935. if (szDataSourceName == NULL) {
  4936. hr = E_OUTOFMEMORY;
  4937. } else {
  4938. dwStatus = FormatSqlDataSourceName (
  4939. m_DataSourceInfo.szSqlDsnName,
  4940. m_DataSourceInfo.szSqlLogSetName,
  4941. szDataSourceName,
  4942. &ulLogFileNameLen );
  4943. }
  4944. }
  4945. }
  4946. }
  4947. else {
  4948. hr = E_INVALIDARG;
  4949. }
  4950. }
  4951. if (SUCCEEDED(hr)) {
  4952. hr = ProcessDataSourceType((LPCWSTR) szDataSourceName, iDataSourceType);
  4953. }
  4954. if (szDataSourceName) {
  4955. free(szDataSourceName);
  4956. }
  4957. return hr;
  4958. }
  4959. void
  4960. CSysmonControl::IncrementVisuals (
  4961. void
  4962. )
  4963. {
  4964. // Increment the visual indices in color, width, style order
  4965. if (++m_iColorIndex >= NumStandardColorIndices()) {
  4966. m_iColorIndex = 0;
  4967. if (++m_iWidthIndex >= NumWidthIndices()) {
  4968. m_iWidthIndex = 0;
  4969. if (++m_iStyleIndex < NumStyleIndices()) {
  4970. m_iStyleIndex = 0;
  4971. }
  4972. }
  4973. }
  4974. }
  4975. void
  4976. CSysmonControl::SampleLogFile (
  4977. BOOL bViewChange
  4978. )
  4979. {
  4980. typedef struct {
  4981. PCGraphItem pItem;
  4982. double dMin;
  4983. double dMax;
  4984. double dAvg;
  4985. INT nAvgCnt;
  4986. BOOL bFirstSample;
  4987. PDH_RAW_COUNTER rawValue[1];
  4988. } LogWorkBuf, *PLogWorkBuf;
  4989. INT nCounters;
  4990. INT nLogSamples;
  4991. INT nDispSamples;
  4992. INT iNonDisp;
  4993. INT iFinalValidSample = 0;
  4994. PCGraphItem pItem;
  4995. #define LLTIME_TICS_PER_SECOND (10000000)
  4996. if ( NULL != m_hQuery ) {
  4997. // Determine number of counters to update
  4998. nCounters = 0;
  4999. // If log view change, we have to update all counters
  5000. if (bViewChange) {
  5001. for (pItem = FirstCounter(); pItem; pItem = pItem->Next()) {
  5002. pItem->m_bUpdateLog = TRUE;
  5003. nCounters++;
  5004. }
  5005. }
  5006. // otherwise, just any new counters
  5007. else {
  5008. for (pItem = FirstCounter(); pItem; pItem = pItem->Next()) {
  5009. if (pItem->m_bUpdateLog)
  5010. nCounters++;
  5011. }
  5012. }
  5013. // If none, nothing to do
  5014. if ( nCounters > 0) {
  5015. // Number of log samples in displayed interval
  5016. // Add 1 extra at the beginning. PdhSetQueryTimeRange returns one sample
  5017. // before the specified start time, if it exists.
  5018. // Add extra 1 because ?
  5019. if (m_DataSourceInfo.nSamples > 1) {
  5020. assert ( 0 != m_DataSourceInfo.llInterval );
  5021. nLogSamples = (INT)((m_DataSourceInfo.llStopDisp - m_DataSourceInfo.llStartDisp) / m_DataSourceInfo.llInterval) + 2;
  5022. } else {
  5023. nLogSamples = m_DataSourceInfo.nSamples;
  5024. }
  5025. // Number of display samples
  5026. nDispSamples = min(nLogSamples, m_pHistCtrl->nMaxSamples);
  5027. // Setup history control
  5028. m_pHistCtrl->nSamples = nDispSamples;
  5029. m_pHistCtrl->iCurrent = 0;
  5030. m_pHistCtrl->nBacklog = 0;
  5031. if ( nDispSamples > 1 ) {
  5032. INT nCompSamples;
  5033. INT nPasses = 0;
  5034. INT iComp;
  5035. INT iCtr;
  5036. INT iDisp;
  5037. DOUBLE dSamplesPerInterval = 0.0;
  5038. INT iTotalSamplesProcessed = 0;
  5039. DOUBLE dTotalSamplesCalc = 0;
  5040. BOOL bRemainder;
  5041. PLogWorkBuf pWorkBuffers;
  5042. PLogWorkBuf pWorkBuf;
  5043. INT nWorkBufSize;
  5044. PDH_TIME_INFO TimeInfo;
  5045. PDH_STATISTICS Statistics;
  5046. DWORD dwCtrType;
  5047. PDH_STATUS stat;
  5048. // Number of log samples to compress to one display values
  5049. // Add an extra 1 for rate counters becuase it takes 2 raw sample to get one formatted value.
  5050. // The first sample of each buffer is ignored for non-rate counters.
  5051. //
  5052. // If nLogsamples / nDispSamples has a remainder, then an extra 1 is needed because some
  5053. // intervals will include one more sample to make the total come out even at the end
  5054. // (e.g. 10 samples divided among 3 intervals = (3, 4, 3))
  5055. //
  5056. nCompSamples = (nLogSamples + m_pHistCtrl->nMaxSamples - 1) / m_pHistCtrl->nMaxSamples;
  5057. nCompSamples += 1;
  5058. // Length of one work buffer
  5059. nWorkBufSize = sizeof(LogWorkBuf) + (( nCompSamples ) * sizeof(PDH_RAW_COUNTER));
  5060. // Allocate work buffers of nCompSamples samples for each counter
  5061. pWorkBuffers = (PLogWorkBuf)malloc( nCounters * nWorkBufSize);
  5062. if (pWorkBuffers == NULL)
  5063. return;
  5064. // Place selected counter item pointers in work buffers
  5065. // and init statistics
  5066. pWorkBuf = pWorkBuffers;
  5067. for (pItem = FirstCounter(); pItem; pItem = pItem->Next()) {
  5068. if (pItem->m_bUpdateLog) {
  5069. pWorkBuf->pItem = pItem;
  5070. pWorkBuf->dMin = (double)10e8;
  5071. pWorkBuf->dMax = (double)-10e8;
  5072. pWorkBuf->dAvg = 0.0;
  5073. pWorkBuf->nAvgCnt = 0;
  5074. pWorkBuf->bFirstSample = TRUE;
  5075. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5076. }
  5077. }
  5078. // Set time range for pdh
  5079. TimeInfo.StartTime = m_DataSourceInfo.llStartDisp;
  5080. TimeInfo.EndTime = m_DataSourceInfo.llStopDisp;
  5081. PdhSetQueryTimeRange(m_hQuery, &TimeInfo);
  5082. bRemainder = ( 0 < ( nLogSamples % nDispSamples ) );
  5083. if ( bRemainder ) {
  5084. // Initialize the differential calc variables
  5085. dSamplesPerInterval = (double)nLogSamples / (double)nDispSamples;
  5086. iTotalSamplesProcessed = 0;
  5087. dTotalSamplesCalc = 0;
  5088. } else {
  5089. nPasses = nCompSamples;
  5090. }
  5091. for (iDisp = 0; iDisp<nDispSamples; iDisp++) {
  5092. if ( bRemainder ) {
  5093. // Do the differential calc to see if it's time for an extra sample
  5094. dTotalSamplesCalc += dSamplesPerInterval;
  5095. nPasses = (int)(dTotalSamplesCalc - iTotalSamplesProcessed);
  5096. iTotalSamplesProcessed += nPasses;
  5097. // Add 1 to nPasses because the first buffer is blank or from the previous interval.
  5098. nPasses ++;
  5099. }
  5100. // Fill the work buffers with a set of samples
  5101. // Set bad status for sample zero first time through.
  5102. // Sample zero is only used for rate counters.
  5103. // Other passes will reuse last sample of previous pass.
  5104. iComp = 0;
  5105. if ( 0 == iDisp ) {
  5106. // Special handling for the first sample.
  5107. // Set bad status for each
  5108. pWorkBuf = pWorkBuffers;
  5109. for (iCtr=0; iCtr < nCounters; iCtr++) {
  5110. pWorkBuf->rawValue[0].CStatus = PDH_CSTATUS_INVALID_DATA;
  5111. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5112. }
  5113. // If iDisp == 0, Query the data and check the timestamp for the first raw data value.
  5114. // If that timestamp is before the official Start time, store it in buffer 0
  5115. // Otherwise, put that data in buffer 1 and skip the first sample collection of the
  5116. // regular loop below.
  5117. stat = PdhCollectQueryData(m_hQuery);
  5118. if (stat == 0) {
  5119. PDH_RAW_COUNTER rawSingleValue;
  5120. // Get a raw sample for each counter. Check the timestamp of the first counter to
  5121. // determine which buffer to use.
  5122. pWorkBuf = pWorkBuffers;
  5123. iCtr = 0;
  5124. PdhGetRawCounterValue(pWorkBuf->pItem->Handle(), &dwCtrType, &rawSingleValue);
  5125. // Increment the buffer index to 1 if the time stamp is after Start time.
  5126. // Otherwise, write the data to buffer 0, which is only used to process rate counters.
  5127. if ( *((LONGLONG*)&rawSingleValue.TimeStamp) >= m_DataSourceInfo.llStartDisp ) {
  5128. iComp = 1;
  5129. }
  5130. pWorkBuf->rawValue[iComp] = rawSingleValue;
  5131. // Increment to the next counter, and continue normal processing for the first sample,
  5132. // using iComp buffer index.
  5133. iCtr++;
  5134. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5135. for ( ; iCtr < nCounters; iCtr++) {
  5136. PdhGetRawCounterValue(pWorkBuf->pItem->Handle(), &dwCtrType, &pWorkBuf->rawValue[iComp]);
  5137. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5138. }
  5139. } // else bad status already set in 0 buffer for each counter.
  5140. }
  5141. // Only rate counter values use work buffer 0
  5142. // Buffer 0 is set to value from previous sample, except when iDisp 0, in which case it might have
  5143. // been filled in the (if 0 == iDisp) clause above.
  5144. // Skip past any special handling for the first iDisp pass above. If buffer 1 is not filled by that
  5145. // special handling, then iComp is set to 1.
  5146. iComp++;
  5147. for ( ; iComp < nPasses; iComp++) {
  5148. stat = PdhCollectQueryData(m_hQuery);
  5149. if (stat == 0) {
  5150. // Get a raw sample for each counter
  5151. pWorkBuf = pWorkBuffers;
  5152. for (iCtr = 0; iCtr < nCounters; iCtr++) {
  5153. PdhGetRawCounterValue(pWorkBuf->pItem->Handle(), &dwCtrType, &pWorkBuf->rawValue[iComp]);
  5154. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5155. }
  5156. }
  5157. else {
  5158. // Set bad status for each
  5159. pWorkBuf = pWorkBuffers;
  5160. for (iCtr=0; iCtr < nCounters; iCtr++) {
  5161. pWorkBuf->rawValue[iComp].CStatus = PDH_CSTATUS_INVALID_DATA;
  5162. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5163. }
  5164. }
  5165. }
  5166. // generate one display sample by averaging each compression buffer
  5167. pWorkBuf = pWorkBuffers;
  5168. for (iCtr=0; iCtr < nCounters; iCtr++) {
  5169. INT iPassesThisCounter;
  5170. INT iWorkBufIndex;
  5171. if ( pWorkBuf->pItem->CalcRequiresMultipleSamples() ) {
  5172. iPassesThisCounter = nPasses;
  5173. iWorkBufIndex = 0;
  5174. } else {
  5175. // Non-rate counters do not use the first sample buffer.
  5176. iPassesThisCounter = nPasses - 1;
  5177. iWorkBufIndex = 1;
  5178. }
  5179. stat = PdhComputeCounterStatistics (pWorkBuf->pItem->Handle(), PDH_FMT_DOUBLE | PDH_FMT_NOCAP100,
  5180. 0, iPassesThisCounter, &pWorkBuf->rawValue[iWorkBufIndex], &Statistics );
  5181. if (stat == 0 && Statistics.mean.CStatus == PDH_CSTATUS_VALID_DATA) {
  5182. LONGLONG llTruncatedTimeStamp = 0;
  5183. LONGLONG llTmpTimeStamp = 0;
  5184. pWorkBuf->pItem->SetLogEntry(iDisp, Statistics.min.doubleValue,
  5185. Statistics.max.doubleValue,
  5186. Statistics.mean.doubleValue);
  5187. // Use the final sample timestamp. It is valid for both rates and numbers.
  5188. llTmpTimeStamp = MAKELONGLONG(
  5189. pWorkBuf->rawValue[nPasses - 1].TimeStamp.dwLowDateTime,
  5190. pWorkBuf->rawValue[nPasses - 1].TimeStamp.dwHighDateTime);
  5191. TruncateLLTime(llTmpTimeStamp, & llTruncatedTimeStamp);
  5192. pWorkBuf->pItem->SetLogEntryTimeStamp ( iDisp, *((FILETIME*)&llTruncatedTimeStamp) );
  5193. //
  5194. // Set the minimum and maximum values correctly the first time through.
  5195. //
  5196. if ( pWorkBuf->bFirstSample ) {
  5197. pWorkBuf->dMin = Statistics.min.doubleValue;
  5198. pWorkBuf->dMax = Statistics.max.doubleValue;
  5199. pWorkBuf->bFirstSample = FALSE;
  5200. } else {
  5201. if (Statistics.min.doubleValue < pWorkBuf->dMin) {
  5202. pWorkBuf->dMin = Statistics.min.doubleValue;
  5203. }
  5204. if (Statistics.max.doubleValue > pWorkBuf->dMax) {
  5205. pWorkBuf->dMax = Statistics.max.doubleValue;
  5206. }
  5207. }
  5208. pWorkBuf->dAvg += Statistics.mean.doubleValue;
  5209. pWorkBuf->nAvgCnt++;
  5210. iFinalValidSample = iDisp;
  5211. }
  5212. else {
  5213. pWorkBuf->pItem->SetLogEntry(iDisp, -1.0, -1.0, -1.0);
  5214. }
  5215. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5216. }
  5217. // If a rate counter, move last sample to first sample
  5218. // for next compress interval
  5219. pWorkBuf = pWorkBuffers;
  5220. for (iCtr=0; iCtr < nCounters; iCtr++) {
  5221. if ( pWorkBuf->pItem->CalcRequiresMultipleSamples() ) {
  5222. pWorkBuf->rawValue[0] = pWorkBuf->rawValue[nPasses-1];
  5223. }
  5224. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5225. }
  5226. }
  5227. // Reset the history control to point to the last valid sample.
  5228. m_pHistCtrl->nSamples = iFinalValidSample;
  5229. // Set the log statistics for empty samples.
  5230. for (iNonDisp = nDispSamples; iNonDisp<m_pHistCtrl->nMaxSamples; iNonDisp++) {
  5231. pWorkBuf = pWorkBuffers;
  5232. for (iCtr=0; iCtr < nCounters; iCtr++) {
  5233. pWorkBuf->pItem->SetLogEntry(iNonDisp, -1.0, -1.0, -1.0);
  5234. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5235. }
  5236. }
  5237. // Store the final statistics and clear the update flags
  5238. pWorkBuf = pWorkBuffers;
  5239. for (iCtr=0; iCtr < nCounters; iCtr++) {
  5240. pWorkBuf->pItem->m_bUpdateLog = FALSE;
  5241. if (pWorkBuf->nAvgCnt) {
  5242. pWorkBuf->dAvg /= pWorkBuf->nAvgCnt;
  5243. pWorkBuf->pItem->SetLogStats(pWorkBuf->dMin, pWorkBuf->dMax, pWorkBuf->dAvg, PDH_CSTATUS_VALID_DATA);
  5244. }
  5245. pWorkBuf = (PLogWorkBuf)((CHAR*)pWorkBuf + nWorkBufSize);
  5246. }
  5247. // Free the work buffers
  5248. free(pWorkBuffers);
  5249. } else {
  5250. // No data to display. Clear the history buffers by setting all status to Invalid.
  5251. for (pItem = FirstCounter(); pItem; pItem = pItem->Next()) {
  5252. for (iNonDisp = 0; iNonDisp < m_pHistCtrl->nMaxSamples; iNonDisp++) {
  5253. pItem->SetLogEntry(iNonDisp, -1.0, -1.0, -1.0);
  5254. }
  5255. }
  5256. }
  5257. // Update statistics bar
  5258. m_pStatsBar->SetTimeSpan((double)(m_DataSourceInfo.llStopDisp - m_DataSourceInfo.llStartDisp) / LLTIME_TICS_PER_SECOND);
  5259. m_pStatsBar->Update(NULL, m_pSelectedItem);
  5260. }
  5261. }
  5262. }
  5263. void
  5264. CSysmonControl::CalcZoomFactor ( void )
  5265. {
  5266. RECT rectPos;
  5267. RECT rectExtent;
  5268. double dHeightPos;
  5269. double dHeightExtent;
  5270. // Calculate zoom factor based on height.
  5271. // The Zoom calculation is prcPos (set by container) divided by the extent.
  5272. // See technical note 40 - TN040.
  5273. rectExtent = m_pObj->m_RectExt;
  5274. GetClientRect ( m_hWnd, &rectPos );
  5275. dHeightPos = rectPos.bottom - rectPos.top;
  5276. dHeightExtent = rectExtent.bottom - rectExtent.top;
  5277. m_dZoomFactor = ( dHeightPos ) / ( dHeightExtent );
  5278. }
  5279. void
  5280. CSysmonControl::ResetLogViewTempTimeRange ()
  5281. /*++
  5282. Routine Description:
  5283. Reset the log view temporary time range steppers to the ends of the visible
  5284. part of the log file.
  5285. Arguments:
  5286. Return Value:
  5287. --*/
  5288. {
  5289. assert ( IsLogSource() );
  5290. if ( IsLogSource() ) {
  5291. INT iNewStopStepNum = 0;
  5292. m_pObj->m_Graph.LogViewStartStepper.Reset();
  5293. m_pObj->m_Graph.LogViewStopStepper.Reset();
  5294. if ( FirstCounter() ) {
  5295. GetNewLogViewStepNum( m_DataSourceInfo.llStopDisp, iNewStopStepNum );
  5296. m_pObj->m_Graph.LogViewStopStepper.StepTo( iNewStopStepNum );
  5297. }
  5298. }
  5299. }
  5300. void
  5301. CSysmonControl::FindNextValidStepNum (
  5302. BOOL bDecrease,
  5303. PCGraphItem pItem,
  5304. LONGLONG llNewTime,
  5305. INT& riNewStepNum,
  5306. DWORD& rdwStatus )
  5307. {
  5308. DWORD dwPdhStatus = ERROR_SUCCESS;
  5309. DWORD dwLocalStatus = ERROR_SUCCESS;
  5310. LONGLONG llNextTimeStamp = 0;
  5311. INT iLocalStepNum;
  5312. INT iTempLocalStepNum;
  5313. assert ( NULL != pItem );
  5314. if ( NULL != pItem ) {
  5315. iLocalStepNum = riNewStepNum;
  5316. iTempLocalStepNum = iLocalStepNum;
  5317. dwLocalStatus = rdwStatus;
  5318. if ( bDecrease ) {
  5319. // Start by decreasing steps to find first valid step.
  5320. while ( ( ERROR_SUCCESS == dwPdhStatus )
  5321. && ( ERROR_SUCCESS != dwLocalStatus )
  5322. && ( iLocalStepNum > 0 ) ) {
  5323. iTempLocalStepNum = iLocalStepNum;
  5324. iTempLocalStepNum--;
  5325. dwPdhStatus = pItem->GetLogEntryTimeStamp( iTempLocalStepNum, llNextTimeStamp, &dwLocalStatus );
  5326. iLocalStepNum = iTempLocalStepNum;
  5327. }
  5328. // Subtract 1 from nSamples because stepper is 0-based,
  5329. while ( ( ERROR_SUCCESS == dwPdhStatus )
  5330. && ( ERROR_SUCCESS != dwLocalStatus )
  5331. && ( iLocalStepNum < m_pHistCtrl->nSamples - 1 ) ) {
  5332. iTempLocalStepNum++;
  5333. dwPdhStatus = pItem->GetLogEntryTimeStamp( iTempLocalStepNum, llNextTimeStamp, &dwLocalStatus );
  5334. iLocalStepNum = iTempLocalStepNum;
  5335. }
  5336. } else {
  5337. // Start by increasing steps to find first valid step.
  5338. // Subtract 1 from nSamples because stepper is 0-based,
  5339. while ( ( ERROR_SUCCESS == dwPdhStatus )
  5340. && ( ERROR_SUCCESS != dwLocalStatus )
  5341. && ( iLocalStepNum < m_pHistCtrl->nSamples - 1 ) ) {
  5342. iTempLocalStepNum++;
  5343. dwPdhStatus = pItem->GetLogEntryTimeStamp( iTempLocalStepNum, llNextTimeStamp, &dwLocalStatus );
  5344. iLocalStepNum = iTempLocalStepNum;
  5345. }
  5346. while ( ( ERROR_SUCCESS == dwPdhStatus )
  5347. && ( ERROR_SUCCESS != dwLocalStatus )
  5348. && ( iLocalStepNum > 0 ) ) {
  5349. iTempLocalStepNum = iLocalStepNum;
  5350. iTempLocalStepNum--;
  5351. dwPdhStatus = pItem->GetLogEntryTimeStamp( iTempLocalStepNum, llNextTimeStamp, &dwLocalStatus );
  5352. iLocalStepNum = iTempLocalStepNum;
  5353. }
  5354. }
  5355. if ( ERROR_SUCCESS == dwLocalStatus ) {
  5356. riNewStepNum = iLocalStepNum;
  5357. llNewTime = llNextTimeStamp;
  5358. rdwStatus = dwLocalStatus;
  5359. }
  5360. }
  5361. return;
  5362. }
  5363. void
  5364. CSysmonControl::GetNewLogViewStepNum (
  5365. LONGLONG llNewTime,
  5366. INT& riNewStepNum )
  5367. /*++
  5368. Routine Description:
  5369. Given the new time and original stepnum, find the stepnum that matches
  5370. the new time.
  5371. Arguments:
  5372. llNewTime New time stamp to match
  5373. riNewStepNum (IN) Current step num
  5374. (OUT) Step num that matches the new time stamp.
  5375. Return Value:
  5376. --*/
  5377. {
  5378. PCGraphItem pItem = NULL;
  5379. LONGLONG llNextTimeStamp = 0;
  5380. PDH_STATUS dwPdhStatus = ERROR_SUCCESS;
  5381. DWORD dwStatus = ERROR_SUCCESS;
  5382. INT iLocalStepNum = 0;
  5383. assert ( IsLogSource() );
  5384. iLocalStepNum = riNewStepNum;
  5385. // Check only the first counter for log file time stamp data.
  5386. pItem = FirstCounter();
  5387. if ( NULL != pItem ) {
  5388. dwPdhStatus = pItem->GetLogEntryTimeStamp( iLocalStepNum, llNextTimeStamp, &dwStatus );
  5389. // If the stepper is positioned on a sample with bad status,
  5390. // move n steps in either direction to find a valid sample to start with.
  5391. if ( ( ERROR_SUCCESS == dwPdhStatus ) && ( ERROR_SUCCESS != dwStatus ) ) {
  5392. FindNextValidStepNum ( FALSE, pItem, llNextTimeStamp, iLocalStepNum, dwStatus );
  5393. }
  5394. if ( ERROR_SUCCESS == dwStatus ) {
  5395. if ( ( llNewTime < llNextTimeStamp ) || ( MAX_TIME_VALUE == llNextTimeStamp ) ) {
  5396. while ( iLocalStepNum > 0 ) {
  5397. iLocalStepNum--;
  5398. pItem->GetLogEntryTimeStamp( iLocalStepNum, llNextTimeStamp, &dwStatus );
  5399. if ( ERROR_SUCCESS == dwStatus ) {
  5400. if ( llNewTime == llNextTimeStamp ) {
  5401. break;
  5402. } else if ( llNewTime > llNextTimeStamp ) {
  5403. iLocalStepNum++;
  5404. break;
  5405. }
  5406. }
  5407. }
  5408. } else if ( llNewTime > llNextTimeStamp ) {
  5409. // Subtract 1 from nSamples because stepper is 0-based,
  5410. while ( iLocalStepNum < m_pHistCtrl->nSamples - 1 ) {
  5411. iLocalStepNum++;
  5412. pItem->GetLogEntryTimeStamp( iLocalStepNum, llNextTimeStamp, &dwStatus );
  5413. if ( ERROR_SUCCESS == dwStatus ) {
  5414. if ( llNewTime <= llNextTimeStamp ) {
  5415. break;
  5416. }
  5417. }
  5418. }
  5419. }
  5420. riNewStepNum = iLocalStepNum;
  5421. } // else if NO valid samples, leave the start/stop time stepper where it is.
  5422. } // Non-null FirstCounter()
  5423. return;
  5424. }
  5425. void
  5426. CSysmonControl::SetLogViewTempTimeRange (
  5427. LONGLONG llStart,
  5428. LONGLONG llStop
  5429. )
  5430. /*++
  5431. Routine Description:
  5432. Set the log view temporary time range. This routine provides the Source
  5433. property page a way to give range to the control, so that the control
  5434. can draw temporary timeline guides on the line graph.
  5435. Arguments:
  5436. llStart Temporary log view start time (FILETIME format)
  5437. llEnd Temporary log view end time (FILETIME format)
  5438. Return Value:
  5439. --*/
  5440. {
  5441. assert ( llStart <= llStop );
  5442. if ( IsLogSource() && ( llStart <= llStop ) ) {
  5443. INT iNewStepNum;
  5444. // No time range to modify if no counters selected.
  5445. if ( NULL != FirstCounter() ) {
  5446. // Start/Stop time range bars are turned off if llStart and llStop are set
  5447. // to MIN and MAX values, so no need to update steppers.
  5448. if ( MIN_TIME_VALUE != llStart ) {
  5449. // Search through sample values to find the appropriate step for the start bar.
  5450. if ( llStart != m_pObj->m_Graph.LogViewTempStart ) {
  5451. // Start with current position.
  5452. iNewStepNum = m_pObj->m_Graph.LogViewStartStepper.StepNum();
  5453. GetNewLogViewStepNum ( llStart, iNewStepNum );
  5454. if ( iNewStepNum != m_pObj->m_Graph.LogViewStartStepper.StepNum() ) {
  5455. m_pObj->m_Graph.LogViewStartStepper.StepTo ( iNewStepNum );
  5456. }
  5457. }
  5458. }
  5459. if ( MAX_TIME_VALUE != llStop ) {
  5460. // Search through sample values to find the appropriate step for the stop bar.
  5461. if ( llStop != m_pObj->m_Graph.LogViewTempStop ) {
  5462. // Start with current position.
  5463. iNewStepNum = m_pObj->m_Graph.LogViewStopStepper.StepNum();
  5464. GetNewLogViewStepNum ( llStop, iNewStepNum );
  5465. if ( iNewStepNum != m_pObj->m_Graph.LogViewStopStepper.StepNum() ) {
  5466. m_pObj->m_Graph.LogViewStopStepper.StepTo ( iNewStepNum );
  5467. }
  5468. }
  5469. }
  5470. }
  5471. }
  5472. if ( ( m_pObj->m_Graph.LogViewTempStart != llStart )
  5473. || ( m_pObj->m_Graph.LogViewTempStop != llStop ) ) {
  5474. m_pObj->m_Graph.LogViewTempStart = llStart;
  5475. m_pObj->m_Graph.LogViewTempStop = llStop;
  5476. if ( sysmonLineGraph == m_pObj->m_Graph.Options.iDisplayType ) {
  5477. // Cause redraw
  5478. UpdateGraph(UPDGRPH_PLOT);
  5479. }
  5480. }
  5481. }
  5482. PRECT
  5483. CSysmonControl::GetNewClientRect ( void )
  5484. {
  5485. return &m_pObj->m_RectExt;
  5486. }
  5487. PRECT
  5488. CSysmonControl::GetCurrentClientRect ( void )
  5489. {
  5490. return &m_rectCurrentClient;
  5491. }
  5492. void
  5493. CSysmonControl::SetCurrentClientRect ( PRECT prectNew )
  5494. {
  5495. m_rectCurrentClient = *prectNew;
  5496. }
  5497. void
  5498. CSysmonControl::UpdateNonAmbientSysColors ( void )
  5499. {
  5500. HRESULT hr;
  5501. COLORREF newColor;
  5502. PGRAPH_OPTIONS pOptions = &m_pObj->m_Graph.Options;
  5503. hr = OleTranslateColor(pOptions->clrBackCtl, NULL, &newColor);
  5504. if ( SUCCEEDED( hr ) ) {
  5505. m_clrBackCtl = newColor;
  5506. }
  5507. if (pOptions->clrBackPlot != NULL_COLOR) {
  5508. hr = OleTranslateColor(pOptions->clrBackPlot, NULL, &newColor);
  5509. if ( SUCCEEDED( hr ) ) {
  5510. m_clrBackPlot = newColor;
  5511. }
  5512. }
  5513. if (pOptions->clrFore != NULL_COLOR) {
  5514. hr = OleTranslateColor(pOptions->clrFore, NULL, &newColor);
  5515. if ( SUCCEEDED( hr ) ) {
  5516. m_clrFgnd = newColor;
  5517. }
  5518. }
  5519. hr = OleTranslateColor(pOptions->clrGrid, NULL, &newColor);
  5520. if ( SUCCEEDED( hr ) ) {
  5521. m_clrGrid = newColor;
  5522. }
  5523. hr = OleTranslateColor(pOptions->clrTimeBar, NULL, &newColor);
  5524. if ( SUCCEEDED( hr ) ) {
  5525. m_clrTimeBar = newColor;
  5526. }
  5527. }
  5528. LPCWSTR
  5529. CSysmonControl::GetDataSourceName ( void )
  5530. {
  5531. LPWSTR szReturn = NULL;
  5532. CLogFileItem* pLogFile = NULL;
  5533. if ( sysmonLogFiles == m_pObj->m_Graph.Options.iDataSourceType ) {
  5534. pLogFile = FirstLogFile();
  5535. if ( NULL != pLogFile ) {
  5536. szReturn = const_cast<LPWSTR>((LPCWSTR)pLogFile->GetPath());
  5537. }
  5538. }
  5539. // TodoLogFiles: Use the m_DataSourceInfo.szDataSourceName field? When multi-file?
  5540. return szReturn;
  5541. }
  5542. HRESULT
  5543. CSysmonControl::GetSelectedCounter ( CGraphItem** ppItem )
  5544. {
  5545. HRESULT hr = E_POINTER;
  5546. if ( NULL != ppItem ) {
  5547. *ppItem = m_pSelectedItem;
  5548. hr = NOERROR;
  5549. }
  5550. return hr;
  5551. }
  5552. DWORD
  5553. CSysmonControl::BuildLogFileList (
  5554. LPWSTR szLogFileList,
  5555. BOOL bIsCommaDelimiter,
  5556. ULONG* pulBufLen )
  5557. {
  5558. DWORD dwStatus = ERROR_SUCCESS;
  5559. ULONG ulListLen;
  5560. CLogFileItem* pLogFile = FirstLogFile();
  5561. LPCWSTR szThisLogFile = NULL;
  5562. LPWSTR szLogFileCurrent = NULL;
  5563. const WCHAR cwComma = L',';
  5564. if ( NULL != pulBufLen ) {
  5565. ulListLen = 0;
  5566. while (pLogFile != NULL) {
  5567. szThisLogFile= pLogFile->GetPath();
  5568. ulListLen += (lstrlen(szThisLogFile) + 1);
  5569. pLogFile = pLogFile->Next();
  5570. }
  5571. ulListLen ++; // for the single final NULL character.
  5572. if ( ulListLen <= *pulBufLen ) {
  5573. if ( NULL != szLogFileList ) {
  5574. ZeroMemory(szLogFileList, (ulListLen * sizeof(WCHAR)));
  5575. pLogFile = FirstLogFile();
  5576. szLogFileCurrent = (LPWSTR) szLogFileList;
  5577. while (pLogFile != NULL) {
  5578. szThisLogFile = pLogFile->GetPath();
  5579. //
  5580. // Here we are sure we have enough space to hold string
  5581. //
  5582. StringCchCopy(szLogFileCurrent, lstrlen(szThisLogFile) + 1, szThisLogFile);
  5583. szLogFileCurrent += lstrlen(szThisLogFile);
  5584. *szLogFileCurrent = L'\0';
  5585. pLogFile = pLogFile->Next();
  5586. if ( bIsCommaDelimiter && NULL != pLogFile ) {
  5587. // If comma delimited, replace the NULL char with a comma
  5588. *szLogFileCurrent = cwComma;
  5589. }
  5590. szLogFileCurrent ++;
  5591. }
  5592. if ( !bIsCommaDelimiter ) {
  5593. *szLogFileCurrent = L'\0';
  5594. }
  5595. }
  5596. } else if ( NULL != szLogFileList ) {
  5597. dwStatus = ERROR_MORE_DATA;
  5598. }
  5599. *pulBufLen = ulListLen;
  5600. } else {
  5601. dwStatus = ERROR_INVALID_PARAMETER;
  5602. assert ( FALSE );
  5603. }
  5604. return dwStatus;
  5605. }
  5606. HRESULT
  5607. CSysmonControl::LoadLogFilesFromMultiSz (
  5608. LPCWSTR szLogFileList )
  5609. {
  5610. HRESULT hr = NOERROR;
  5611. LPWSTR szNext = NULL;
  5612. szNext = const_cast<LPWSTR>(szLogFileList);
  5613. while ( NULL != szNext ) {
  5614. hr = AddSingleLogFile ( szNext );
  5615. if ( FAILED ( hr ) ) {
  5616. break;
  5617. }
  5618. szNext += lstrlen (szNext) + 1;
  5619. }
  5620. return hr;
  5621. }
  5622. void
  5623. CSysmonControl::ClearErrorPathList ( void )
  5624. {
  5625. if ( NULL != m_szErrorPathList ) {
  5626. delete [] m_szErrorPathList;
  5627. }
  5628. m_szErrorPathList = NULL;
  5629. m_dwErrorPathListLen = 0;
  5630. m_dwErrorPathBufLen = 0;
  5631. }
  5632. LPCWSTR
  5633. CSysmonControl::GetErrorPathList ( DWORD* pdwListLen )
  5634. {
  5635. if ( NULL != pdwListLen ) {
  5636. *pdwListLen = m_dwErrorPathListLen;
  5637. }
  5638. return m_szErrorPathList;
  5639. }
  5640. DWORD
  5641. CSysmonControl::AddToErrorPathList ( LPCWSTR szPath )
  5642. {
  5643. DWORD dwStatus = ERROR_SUCCESS;
  5644. DWORD dwPathLen = 0;
  5645. LPWSTR szNewBuffer = NULL;
  5646. LPWSTR szNextCounter = NULL;
  5647. //
  5648. // cdwAddLen is an arbitrary number, larger than most counter strings.
  5649. // Longer counter paths are handled dwPathLen below.
  5650. //
  5651. const DWORD cdwAddLen = 2048;
  5652. const LPCWSTR cszNewLine = L"\n";
  5653. if ( NULL != szPath ) {
  5654. //
  5655. // Include 1 for the possible newline character or null.
  5656. //
  5657. dwPathLen = lstrlen ( szPath ) + 1;
  5658. //
  5659. // If not enough space, allocate a bigger buffer.
  5660. //
  5661. if ( m_dwErrorPathBufLen < m_dwErrorPathListLen + dwPathLen ) {
  5662. m_dwErrorPathBufLen += max ( cdwAddLen, dwPathLen );
  5663. szNewBuffer = new WCHAR[m_dwErrorPathBufLen];
  5664. if ( NULL != szNewBuffer ) {
  5665. if ( NULL != m_szErrorPathList ) {
  5666. memcpy ( szNewBuffer, m_szErrorPathList, m_dwErrorPathListLen * sizeof(WCHAR) );
  5667. delete [] m_szErrorPathList;
  5668. }
  5669. m_szErrorPathList = szNewBuffer;
  5670. } else {
  5671. dwStatus = ERROR_OUTOFMEMORY;
  5672. }
  5673. }
  5674. if ( ERROR_SUCCESS == dwStatus ) {
  5675. //
  5676. // Point to current ending null character.
  5677. //
  5678. szNextCounter = m_szErrorPathList;
  5679. if ( 0 < m_dwErrorPathListLen ) {
  5680. szNextCounter += m_dwErrorPathListLen - 1;
  5681. memcpy ( szNextCounter, cszNewLine, sizeof(cszNewLine) );
  5682. szNextCounter++;
  5683. //
  5684. // No need to increment m_dwErrorPathListLen because the newline
  5685. // replaces the ending null of the previous string.
  5686. //
  5687. }
  5688. //
  5689. // We are sure we have enough space to hold the string
  5690. //
  5691. StringCchCopy(szNextCounter, dwPathLen, szPath);
  5692. m_dwErrorPathListLen += dwPathLen;
  5693. }
  5694. } else {
  5695. dwStatus = ERROR_INVALID_PARAMETER;
  5696. }
  5697. return dwStatus;
  5698. }