Source code of Windows XP (NT5)
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.

1740 lines
41 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. grphitem.cpp
  5. Abstract:
  6. <abstract>
  7. --*/
  8. #ifndef _LOG_INCLUDE_DATA
  9. #define _LOG_INCLUDE_DATA 0
  10. #endif
  11. #include <math.h>
  12. #include <limits.h> // for INT_MAX
  13. #include <pdhp.h>
  14. #include "polyline.h"
  15. #include "visuals.h"
  16. #include "grphitem.h"
  17. #include "unihelpr.h"
  18. #include "utils.h"
  19. #include "pdhmsg.h"
  20. #define MAX_DOUBLE_TEXT_SIZE (64)
  21. // Construction/Destruction
  22. CGraphItem::CGraphItem (
  23. CSysmonControl *pCtrl )
  24. : m_cRef ( 0 ),
  25. m_pCtrl ( pCtrl ),
  26. m_hCounter ( NULL ),
  27. m_hPen ( NULL ),
  28. m_hBrush ( NULL ),
  29. m_pCounter ( NULL ),
  30. m_pInstance ( NULL),
  31. m_pRawCtr ( NULL ),
  32. m_pFmtCtr ( NULL ),
  33. m_dFmtMax ( 0 ),
  34. m_dFmtMin ( 0 ),
  35. m_dFmtAvg ( 0 ),
  36. m_lFmtStatus ( 0 ),
  37. m_pLogData ( NULL ),
  38. m_pImpIDispatch ( NULL ),
  39. m_rgbColor ( RGB(0,0,0) ),
  40. m_iWidth ( 1 ),
  41. m_iStyle ( 0 ),
  42. m_iScaleFactor ( INT_MAX ),
  43. m_dScale ( (double)1.0 ),
  44. m_pNextItem ( NULL ),
  45. m_bUpdateLog ( TRUE ),
  46. m_fGenerated ( FALSE )
  47. /*++
  48. Routine Description:
  49. Constructor for the CGraphItem class. It initializes the member variables.
  50. Arguments:
  51. None.
  52. Return Value:
  53. None.
  54. --*/
  55. {
  56. ZeroMemory ( &m_CounterInfo, sizeof (m_CounterInfo ) );
  57. m_CounterInfo.CStatus = PDH_CSTATUS_INVALID_DATA;
  58. return;
  59. }
  60. CGraphItem::~CGraphItem (
  61. VOID
  62. )
  63. /*++
  64. Routine Description:
  65. Destructor for the CGraphItem class. It frees any objects, storage, and
  66. interfaces that were created. If the item is part of a query it is removed
  67. from the query.
  68. Arguments:
  69. None.
  70. Return Value:
  71. None.
  72. --*/
  73. {
  74. if (m_hCounter != NULL)
  75. RemoveFromQuery();
  76. if (m_hPen != NULL)
  77. DeleteObject(m_hPen);
  78. if (m_hBrush != NULL)
  79. DeleteObject(m_hBrush);
  80. if (m_pImpIDispatch != NULL)
  81. delete m_pImpIDispatch;
  82. }
  83. HRESULT
  84. CGraphItem::SaveToStream (
  85. IN LPSTREAM pIStream,
  86. IN BOOL fWildCard,
  87. IN INT iVersMaj,
  88. IN INT // iVersMin
  89. )
  90. /*++
  91. Routine Description:
  92. SaveToStream writes the graph item's properties to the provided stream.
  93. Arguments:
  94. pIStream - Pointer to stream interface
  95. pszPath - Path name to save item under
  96. Return Value:
  97. HRESULT - S_OK or stream error
  98. --*/
  99. {
  100. LPWSTR pszWidePath;
  101. TCHAR szPath[MAX_PATH];
  102. LPTSTR szEnglishBuf = NULL;
  103. DWORD dwEnglishBufSize = 0;
  104. LPTSTR pNewBuf;
  105. DWORD dwBufSize;
  106. LPTSTR pszPath;
  107. HRESULT hr = S_OK;
  108. PDH_STATUS pdhStatus;
  109. USES_CONVERSION
  110. // Get Ansi path name
  111. FormPath(szPath, fWildCard );
  112. pszPath = szPath;
  113. //
  114. // Initialize the locale path buffer
  115. //
  116. if (dwEnglishBufSize == 0) {
  117. dwEnglishBufSize = (MAX_PATH + 1) * sizeof(TCHAR);
  118. szEnglishBuf = (LPTSTR) malloc(dwEnglishBufSize);
  119. if (szEnglishBuf == NULL) {
  120. dwEnglishBufSize = 0;
  121. }
  122. }
  123. if (szEnglishBuf != NULL) {
  124. //
  125. // Translate counter name from Localization into English
  126. //
  127. dwBufSize = dwEnglishBufSize;
  128. pdhStatus = PdhTranslate009Counter(
  129. szPath,
  130. szEnglishBuf,
  131. &dwBufSize);
  132. if (pdhStatus == PDH_MORE_DATA) {
  133. pNewBuf = (LPTSTR)realloc(szEnglishBuf, dwBufSize);
  134. if (pNewBuf != NULL) {
  135. szEnglishBuf = pNewBuf;
  136. dwEnglishBufSize = dwBufSize;
  137. pdhStatus = PdhTranslate009Counter(
  138. szPath,
  139. szEnglishBuf,
  140. &dwBufSize);
  141. }
  142. }
  143. if (pdhStatus == ERROR_SUCCESS) {
  144. pszPath = szEnglishBuf;
  145. }
  146. }
  147. pszWidePath = T2W(pszPath);
  148. if ( SMONCTRL_MAJ_VERSION == iVersMaj ) {
  149. GRAPHITEM_DATA3 ItemData;
  150. // Move properties to storage structure
  151. ItemData.m_rgbColor = m_rgbColor;
  152. ItemData.m_iWidth = m_iWidth;
  153. ItemData.m_iStyle = m_iStyle;
  154. ItemData.m_iScaleFactor = m_iScaleFactor;
  155. assert( 0 < lstrlen(pszWidePath ) );
  156. ItemData.m_nPathLength = lstrlen(pszWidePath);
  157. // Write structure to stream
  158. hr = pIStream->Write(&ItemData, sizeof(ItemData), NULL);
  159. if (FAILED(hr)) {
  160. goto ErrorOut;
  161. }
  162. // Write path name to stream
  163. hr = pIStream->Write(pszWidePath, ItemData.m_nPathLength*sizeof(WCHAR), NULL);
  164. if (FAILED(hr)) {
  165. goto ErrorOut;
  166. }
  167. }
  168. ErrorOut:
  169. if (szEnglishBuf != NULL) {
  170. free(szEnglishBuf);
  171. }
  172. return hr;
  173. }
  174. HRESULT
  175. CGraphItem::NullItemToStream (
  176. IN LPSTREAM pIStream,
  177. IN INT,// iVersMaj,
  178. IN INT // iVersMin
  179. )
  180. /*++
  181. Routine Description:
  182. NulItemToStream writes a graph item structiure with a null path name
  183. to the stream. This is used to marked the end of the counter data in
  184. the control's saved state.
  185. Arguments:
  186. pIStream - Pointer to stream interface
  187. Return Value:
  188. HRESULT - S_OK or stream error
  189. --*/
  190. {
  191. GRAPHITEM_DATA3 ItemData;
  192. // Zero path length, other fields needn't be initialized
  193. ItemData.m_nPathLength = 0;
  194. // Write structure to stream
  195. return pIStream->Write(&ItemData, sizeof(ItemData), NULL);
  196. }
  197. HRESULT
  198. CGraphItem::SaveToPropertyBag (
  199. IN IPropertyBag* pIPropBag,
  200. IN INT iIndex,
  201. IN BOOL bUserMode,
  202. IN INT, // iVersMaj,
  203. IN INT // iVersMin
  204. )
  205. /*++
  206. Routine Description:
  207. SaveToPropertyBag writes the graph item's properties to the provided property bag
  208. interface. The history data is saved as part of the properties.
  209. Arguments:
  210. pIPropBag - Pointer to property bag interface
  211. fWildCard
  212. iVersMaj
  213. iVersMin
  214. Return Value:
  215. HRESULT - S_OK or property bag error
  216. --*/
  217. {
  218. HRESULT hr = S_OK;
  219. TCHAR szPath[MAX_PATH];
  220. PHIST_CONTROL pHistCtrl;
  221. VARIANT vValue;
  222. TCHAR szCounterName[16];
  223. TCHAR szPropertyName[16+16];
  224. DWORD dwCounterNameBytes;
  225. DWORD dwCounterNameLength;
  226. LPTSTR pszNext;
  227. LPTSTR szEnglishBuf = NULL;
  228. DWORD dwEnglishBufSize = 0;
  229. LPTSTR pszPath;
  230. DWORD dwBufSize;
  231. LPTSTR pNewBuf;
  232. PDH_STATUS pdhStatus;
  233. USES_CONVERSION
  234. // Write properties
  235. // Write path name
  236. _stprintf ( szCounterName, _T("%s%05d."), _T("Counter"), iIndex );
  237. dwCounterNameLength = lstrlen (szCounterName);
  238. dwCounterNameBytes = dwCounterNameLength * sizeof (TCHAR);
  239. //
  240. // Generate full path name. (machine\object\instance\counter format)
  241. //
  242. FormPath(szPath, FALSE);
  243. pszPath = szPath;
  244. //
  245. // Initialize the locale path buffer
  246. //
  247. if (dwEnglishBufSize == 0) {
  248. dwEnglishBufSize = (MAX_PATH + 1) * sizeof(TCHAR);
  249. szEnglishBuf = (LPTSTR) malloc(dwEnglishBufSize);
  250. if (szEnglishBuf == NULL) {
  251. dwEnglishBufSize = 0;
  252. }
  253. }
  254. if (szEnglishBuf != NULL) {
  255. //
  256. // Translate counter name from Localization into English
  257. //
  258. dwBufSize = dwEnglishBufSize;
  259. pdhStatus = PdhTranslate009Counter(
  260. szPath,
  261. szEnglishBuf,
  262. &dwBufSize);
  263. if (pdhStatus == PDH_MORE_DATA) {
  264. pNewBuf = (LPTSTR)realloc(szEnglishBuf, dwBufSize);
  265. if (pNewBuf != NULL) {
  266. szEnglishBuf = pNewBuf;
  267. dwEnglishBufSize = dwBufSize;
  268. pdhStatus = PdhTranslate009Counter(
  269. szPath,
  270. szEnglishBuf,
  271. &dwBufSize);
  272. }
  273. }
  274. if (pdhStatus == ERROR_SUCCESS) {
  275. pszPath = szEnglishBuf;
  276. }
  277. }
  278. //
  279. // Save the counter path into property bag
  280. //
  281. memcpy ( szPropertyName, szCounterName, dwCounterNameBytes );
  282. pszNext = szPropertyName + dwCounterNameLength;
  283. lstrcpy ( pszNext, _T("Path") );
  284. hr = StringToPropertyBag (
  285. pIPropBag,
  286. szPropertyName,
  287. pszPath );
  288. if (szEnglishBuf != NULL) {
  289. free(szEnglishBuf);
  290. }
  291. // Write visual properties
  292. if ( SUCCEEDED( hr ) ){
  293. lstrcpy ( pszNext, _T("Color") );
  294. hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, m_rgbColor );
  295. }
  296. if ( SUCCEEDED( hr ) ){
  297. lstrcpy ( pszNext, _T("Width") );
  298. hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, m_iWidth );
  299. }
  300. if ( SUCCEEDED( hr ) ){
  301. lstrcpy ( pszNext, _T("LineStyle") );
  302. hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, m_iStyle );
  303. }
  304. if ( SUCCEEDED( hr ) ){
  305. INT iLocalFactor = m_iScaleFactor;
  306. lstrcpy ( pszNext, _T("ScaleFactor") );
  307. if ( INT_MAX == iLocalFactor ) {
  308. // Save actual scale factor in case the counter cannot be
  309. // validated when the property bag file is opened.
  310. // lDefaultScale is 0 if never initialized.
  311. iLocalFactor = m_CounterInfo.lDefaultScale;
  312. }
  313. hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, iLocalFactor );
  314. }
  315. // Write history data only if live display, data exists and not in design mode.
  316. // Log data is rebuilt from the log file.
  317. pHistCtrl = m_pCtrl->HistoryControl();
  318. if ( ( pHistCtrl->nSamples > 0)
  319. #if !_LOG_INCLUDE_DATA
  320. && ( !pHistCtrl->bLogSource )
  321. #endif
  322. && bUserMode ) {
  323. LPTSTR pszData = NULL;
  324. DWORD dwMaxStrLen = ( pHistCtrl->nMaxSamples * MAX_DOUBLE_TEXT_SIZE ) + 1;
  325. pszData = new TCHAR[ dwMaxStrLen ];
  326. if ( NULL == pszData ) {
  327. hr = E_OUTOFMEMORY;
  328. }
  329. // Write the current statistics.
  330. if ( SUCCEEDED(hr) ) {
  331. double dMin;
  332. double dMax;
  333. double dAvg;
  334. LONG lStatus;
  335. hr = GetStatistics ( &dMax, &dMin, &dAvg, &lStatus );
  336. if (SUCCEEDED(hr) && IsSuccessSeverity(lStatus)) {
  337. lstrcpy ( pszNext, _T("Minimum") );
  338. hr = DoubleToPropertyBag ( pIPropBag, szPropertyName, dMin );
  339. if ( SUCCEEDED(hr) ) {
  340. lstrcpy ( pszNext, _T("Maximum") );
  341. hr = DoubleToPropertyBag ( pIPropBag, szPropertyName, dMax );
  342. }
  343. if ( SUCCEEDED(hr) ) {
  344. lstrcpy ( pszNext, _T("Average") );
  345. hr = DoubleToPropertyBag ( pIPropBag, szPropertyName, dAvg );
  346. }
  347. if ( SUCCEEDED(hr) ) {
  348. lstrcpy ( pszNext, _T("StatisticStatus") );
  349. hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, lStatus );
  350. }
  351. }
  352. }
  353. if ( SUCCEEDED(hr) ) {
  354. INT i;
  355. LPTSTR pszTemp;
  356. HRESULT hrConvert = S_OK;
  357. double dblValue;
  358. DWORD dwTmpStat;
  359. DWORD dwCurrentDataLength;
  360. DWORD dwTempLength;
  361. LPTSTR pszDataNext;
  362. lstrcpy ( pszData, _T("") );
  363. dwCurrentDataLength = 0;
  364. pszDataNext = pszData;
  365. for ( i = 0;
  366. ( S_OK == hrConvert ) && ( i < pHistCtrl->nSamples );
  367. i++ ) {
  368. if ( ERROR_SUCCESS != HistoryValue(i, &dblValue, &dwTmpStat) ) {
  369. dblValue = -1.0;
  370. } else if (!IsSuccessSeverity(dwTmpStat)) {
  371. dblValue = -1.0;
  372. }
  373. VariantInit( &vValue );
  374. vValue.vt = VT_R8;
  375. vValue.dblVal = dblValue;
  376. hrConvert = VariantChangeTypeEx( &vValue, &vValue, LCID_SCRIPT, VARIANT_NOUSEROVERRIDE, VT_BSTR );
  377. pszTemp = W2T( vValue.bstrVal);
  378. dwTempLength = lstrlen ( pszTemp );
  379. // Extra TCHAR for NULL terminator
  380. if ( dwTempLength + dwCurrentDataLength + sizeof(TCHAR) > dwMaxStrLen ) {
  381. TCHAR* pszNewData;
  382. dwMaxStrLen *= 2;
  383. // Allocate a new buffer
  384. pszNewData = new TCHAR[ dwMaxStrLen ];
  385. if ( NULL != pszNewData ) {
  386. memcpy ( pszNewData, pszData, dwCurrentDataLength * sizeof (TCHAR) );
  387. delete pszData;
  388. pszData = pszNewData;
  389. pszDataNext = pszData;
  390. } else {
  391. hr = E_OUTOFMEMORY;
  392. }
  393. }
  394. if ( SUCCEEDED(hr)) {
  395. if ( i > 0 ) {
  396. lstrcpy ( pszDataNext, _T("\t") );
  397. dwCurrentDataLength += 1; // char count for _T("\t");
  398. pszDataNext += 1;
  399. }
  400. memcpy ( pszDataNext, pszTemp, dwTempLength * sizeof(TCHAR) );
  401. dwCurrentDataLength += dwTempLength;
  402. pszDataNext += dwTempLength;
  403. }
  404. VariantClear( &vValue );
  405. }
  406. lstrcpy ( pszDataNext, _T("") );
  407. }
  408. lstrcpy ( pszNext, _T("Data") );
  409. hr = StringToPropertyBag (
  410. pIPropBag,
  411. szPropertyName,
  412. pszData );
  413. if ( NULL != pszData ) {
  414. delete ( pszData );
  415. }
  416. }
  417. return hr;
  418. }
  419. HRESULT
  420. CGraphItem::LoadFromPropertyBag (
  421. IN IPropertyBag* pIPropBag,
  422. IN IErrorLog* pIErrorLog,
  423. IN INT iIndex,
  424. IN INT, // iVersMaj,
  425. IN INT, // iVersMin
  426. IN INT iSampleCount
  427. )
  428. /*++
  429. Routine Description:
  430. LoadFromPropertyBag loads the graph item's properties from the provided property bag
  431. interface.
  432. Arguments:
  433. pIPropBag - Pointer to property bag interface
  434. iVersMaj
  435. iVersMin
  436. Return Value:
  437. HRESULT - S_OK or property bag error
  438. --*/
  439. {
  440. HRESULT hr = S_OK;
  441. TCHAR szCounterName[16];
  442. TCHAR szPropertyName[16+16];
  443. OLE_COLOR clrValue;
  444. INT iValue;
  445. LPTSTR pszData = NULL;
  446. int iBufSizeCurrent = 0;
  447. int iBufSize;
  448. USES_CONVERSION
  449. _stprintf ( szCounterName, _T("%s%05d."), _T("Counter"), iIndex );
  450. // Read visual properties
  451. lstrcpy ( szPropertyName, szCounterName );
  452. lstrcat ( szPropertyName, _T("Color") );
  453. hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, clrValue );
  454. if ( SUCCEEDED(hr) ) {
  455. hr = put_Color ( clrValue );
  456. }
  457. lstrcpy ( szPropertyName, szCounterName );
  458. lstrcat ( szPropertyName, _T("Width") );
  459. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, iValue );
  460. if ( SUCCEEDED(hr) ) {
  461. hr = put_Width ( iValue );
  462. }
  463. lstrcpy ( szPropertyName, szCounterName );
  464. lstrcat ( szPropertyName, _T("LineStyle") );
  465. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, iValue );
  466. if ( SUCCEEDED(hr) ) {
  467. hr = put_LineStyle ( iValue );
  468. }
  469. lstrcpy ( szPropertyName, szCounterName );
  470. lstrcat ( szPropertyName, _T("ScaleFactor") );
  471. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, iValue );
  472. if ( SUCCEEDED(hr) ) {
  473. hr = put_ScaleFactor ( iValue );
  474. }
  475. if ( 0 < iSampleCount ) {
  476. if ( NULL != m_pFmtCtr )
  477. delete m_pFmtCtr;
  478. m_pFmtCtr = new double[MAX_GRAPH_SAMPLES];
  479. if ( NULL == m_pFmtCtr ) {
  480. hr = E_OUTOFMEMORY;
  481. } else {
  482. INT iFmtIndex;
  483. for (iFmtIndex = 0; iFmtIndex < MAX_GRAPH_SAMPLES; iFmtIndex++ ) {
  484. m_pFmtCtr[iFmtIndex] = -1.0;
  485. }
  486. }
  487. if ( SUCCEEDED(hr) ) {
  488. lstrcpy ( szPropertyName, szCounterName );
  489. lstrcat ( szPropertyName, _T("Data") );
  490. iBufSize = iBufSizeCurrent;
  491. hr = StringFromPropertyBag (
  492. pIPropBag,
  493. pIErrorLog,
  494. szPropertyName,
  495. pszData,
  496. iBufSize );
  497. if ( SUCCEEDED(hr) &&
  498. iBufSize > iBufSizeCurrent ) {
  499. if ( NULL != pszData ) {
  500. delete pszData;
  501. }
  502. pszData = new TCHAR[ iBufSize ];
  503. if ( NULL == pszData ) {
  504. hr = E_OUTOFMEMORY;
  505. } else {
  506. lstrcpy ( pszData, _T("") );
  507. iBufSizeCurrent = iBufSize;
  508. hr = StringFromPropertyBag (
  509. pIPropBag,
  510. pIErrorLog,
  511. szPropertyName,
  512. pszData,
  513. iBufSize );
  514. }
  515. }
  516. }
  517. // Read the samples in buffer order.
  518. if ( NULL != pszData && SUCCEEDED ( hr ) ) {
  519. INT iDataIndex;
  520. double dValue = 0;
  521. TCHAR* pNextData;
  522. TCHAR* pDataEnd;
  523. pNextData = pszData;
  524. pDataEnd = pszData + lstrlen(pszData);
  525. for ( iDataIndex = 0; iDataIndex < iSampleCount; iDataIndex++ ) {
  526. if ( pNextData < pDataEnd ) {
  527. hr = GetNextValue ( pNextData, dValue );
  528. } else {
  529. hr = E_FAIL;
  530. }
  531. if ( SUCCEEDED(hr) ) {
  532. SetHistoryValue ( iDataIndex, dValue );
  533. } else {
  534. SetHistoryValue ( iDataIndex, -1.0 );
  535. // iSampleCount = 0;
  536. // Control loaded fine, just no data.
  537. hr = NOERROR;
  538. }
  539. }
  540. }
  541. if ( NULL != pszData ) {
  542. delete pszData;
  543. }
  544. // Read the current statistics.
  545. lstrcpy ( szPropertyName, szCounterName );
  546. lstrcat ( szPropertyName, _T("Maximum") );
  547. hr = DoubleFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, m_dFmtMax );
  548. lstrcpy ( szPropertyName, szCounterName );
  549. lstrcat ( szPropertyName, _T("Minimum") );
  550. hr = DoubleFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, m_dFmtMin );
  551. lstrcpy ( szPropertyName, szCounterName );
  552. lstrcat ( szPropertyName, _T("Average") );
  553. hr = DoubleFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, m_dFmtAvg );
  554. lstrcpy ( szPropertyName, szCounterName );
  555. lstrcat ( szPropertyName, _T("StatisticStatus") );
  556. hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, (INT&)m_lFmtStatus );
  557. }
  558. return hr;
  559. }
  560. HRESULT
  561. CGraphItem::AddToQuery (
  562. IN HQUERY hQuery
  563. )
  564. /*++
  565. Routine Description:
  566. AddToQuery adds a counter to the provided query based on the item's
  567. pathname. It also allocates an array of raw counter value structures for
  568. holding the counter's sample history.
  569. Arguments:
  570. hQuery - Handle to query
  571. Return Value:
  572. Boolean status - TRUE = success
  573. --*/
  574. {
  575. HCOUNTER hCounter;
  576. INT i;
  577. HRESULT hr;
  578. TCHAR achPath[MAX_PATH];
  579. PDH_COUNTER_INFO ci;
  580. DWORD size;
  581. PHIST_CONTROL pHistCtrl = m_pCtrl->HistoryControl();
  582. // Can't add if already in query
  583. if (m_hCounter != NULL)
  584. return E_FAIL;
  585. // Allocate memory for maximum sample count
  586. if (pHistCtrl->nMaxSamples > 0) {
  587. // if log data
  588. if (pHistCtrl->bLogSource) {
  589. // allocate space for formatted values
  590. m_pLogData = new LOG_ENTRY_DATA[pHistCtrl->nMaxSamples];
  591. if (m_pLogData == NULL)
  592. return E_OUTOFMEMORY;
  593. // Clear the statistics
  594. m_dLogMax = 0.0;
  595. m_dLogMin = 0.0;
  596. m_dLogAvg = 0.0;
  597. }
  598. else {
  599. // else allocate raw value space
  600. m_pRawCtr = new PDH_RAW_COUNTER[pHistCtrl->nMaxSamples];
  601. if ( NULL == m_pRawCtr )
  602. return E_OUTOFMEMORY;
  603. // Clear all status flags
  604. for (i=0; i < pHistCtrl->nMaxSamples; i++)
  605. m_pRawCtr[i].CStatus = PDH_CSTATUS_INVALID_DATA;
  606. }
  607. }
  608. // Create the counter object
  609. FormPath(achPath, FALSE);
  610. hr = PdhAddCounter(hQuery, achPath, 0, &hCounter);
  611. if (IsErrorSeverity(hr)) {
  612. delete m_pRawCtr;
  613. m_pRawCtr = NULL;
  614. return hr;
  615. }
  616. size = sizeof(ci);
  617. hr = PdhGetCounterInfo (
  618. hCounter,
  619. FALSE,
  620. &size,
  621. &ci);
  622. if (hr == ERROR_SUCCESS) {
  623. m_CounterInfo = ci;
  624. if ( INT_MAX == m_iScaleFactor ) {
  625. m_dScale = pow ((double)10.0f, (double)ci.lDefaultScale);
  626. }
  627. }
  628. m_hCounter = hCounter;
  629. return NOERROR;
  630. }
  631. HRESULT
  632. CGraphItem::RemoveFromQuery (
  633. VOID
  634. )
  635. /*++
  636. Routine Description:
  637. RemoveFromQuery deletes the item's counter and releases its history array.
  638. Arguments:
  639. None.
  640. Return Value:
  641. Boolean status - TRUE = success
  642. --*/
  643. {
  644. // If no counter handle, not attached to query
  645. if (m_hCounter == NULL)
  646. return S_FALSE;
  647. // Delete the counter
  648. PdhRemoveCounter(m_hCounter);
  649. m_hCounter = NULL;
  650. // Free the buffers
  651. if (m_pLogData) {
  652. delete m_pLogData;
  653. m_pLogData = NULL;
  654. }
  655. if (m_pRawCtr) {
  656. delete m_pRawCtr;
  657. m_pRawCtr = NULL;
  658. }
  659. if (m_pFmtCtr) {
  660. delete m_pFmtCtr;
  661. m_pFmtCtr = NULL;
  662. }
  663. return NOERROR;
  664. }
  665. void
  666. CGraphItem::ClearHistory ( void )
  667. /*++
  668. Routine Description:
  669. ClearHistory resets the raw counter buffer values to Invalid.
  670. Arguments:
  671. None.
  672. Return Value:
  673. None.
  674. --*/
  675. {
  676. INT i;
  677. // Clear all status flags
  678. if ( NULL != m_pRawCtr ) {
  679. for (i=0; i < m_pCtrl->HistoryControl()->nMaxSamples; i++) {
  680. m_pRawCtr[i].CStatus = PDH_CSTATUS_INVALID_DATA;
  681. }
  682. }
  683. }
  684. VOID
  685. CGraphItem::UpdateHistory (
  686. IN BOOL bValidSample
  687. )
  688. /*++
  689. Routine Description:
  690. UpdateHistory reads the raw value for the counter and stores it in the
  691. history slot specified by the history control.
  692. Arguments:
  693. bValidSample - True if raw value is available, False if missed sample
  694. Return Value:
  695. None.
  696. --*/
  697. {
  698. DWORD dwCtrType;
  699. // Make sure there is a counter handle
  700. if (m_hCounter == NULL)
  701. return;
  702. if (bValidSample) {
  703. // Read the raw value
  704. if ( NULL != m_pRawCtr ) {
  705. PdhGetRawCounterValue(m_hCounter, &dwCtrType,
  706. &m_pRawCtr[m_pCtrl->HistoryControl()->iCurrent]);
  707. }
  708. } else {
  709. // Mark value failed
  710. if ( NULL != m_pRawCtr ) {
  711. m_pRawCtr[m_pCtrl->HistoryControl()->iCurrent].CStatus = PDH_CSTATUS_INVALID_DATA;
  712. }
  713. }
  714. }
  715. PDH_STATUS
  716. CGraphItem::HistoryValue (
  717. IN INT iIndex,
  718. OUT double *pdValue,
  719. OUT DWORD *pdwStatus
  720. )
  721. /*++
  722. Routine Description:
  723. HistoryValue computes a formated sample value from the selected raw history
  724. sample. The calculation is actually based on the the specified sample plus
  725. the preceding sample.
  726. Arguments:
  727. iIndex - Index of desired sample (0 = current, 1 = previous, ...)
  728. pdValue - Pointer to return value
  729. pdwStatus - Pointer to return counter status (PDH_CSTATUS_...)
  730. Return Value:
  731. Error status
  732. --*/
  733. {
  734. PDH_STATUS stat = ERROR_INVALID_PARAMETER;
  735. INT iPrevIndex;
  736. INT iCurrIndex;
  737. PDH_FMT_COUNTERVALUE FmtValue;
  738. PHIST_CONTROL pHistCtrl = m_pCtrl->HistoryControl();
  739. // Check for negative index
  740. if ( iIndex >= 0 ) {
  741. // If sample not available from cache or data, return invalid data status
  742. if ( NULL == m_pFmtCtr
  743. && ( m_hCounter == NULL || iIndex + 1 >= pHistCtrl->nSamples ) )
  744. {
  745. *pdwStatus = PDH_CSTATUS_INVALID_DATA;
  746. *pdValue = 0.0;
  747. stat = ERROR_SUCCESS;
  748. } else {
  749. // if log source, index back from last sample
  750. if (m_pCtrl->IsLogSource()) {
  751. *pdValue = m_pLogData[pHistCtrl->nSamples - iIndex - 1].m_dAvg;
  752. *pdwStatus = (*pdValue >= 0.0) ? PDH_CSTATUS_VALID_DATA : PDH_CSTATUS_INVALID_DATA;
  753. stat = ERROR_SUCCESS;
  754. } else {
  755. // Determine history array index of sample
  756. iCurrIndex = pHistCtrl->iCurrent - iIndex;
  757. if (iCurrIndex < 0)
  758. iCurrIndex += pHistCtrl->nMaxSamples;
  759. // Check to determine if loading from property bag
  760. if ( NULL == m_pFmtCtr ) {
  761. // Need previous sample as well
  762. if (iCurrIndex > 0)
  763. iPrevIndex = iCurrIndex - 1;
  764. else
  765. iPrevIndex = pHistCtrl->nMaxSamples - 1;
  766. // Compute the formatted value
  767. if ( NULL != m_pRawCtr ) {
  768. stat = PdhCalculateCounterFromRawValue(m_hCounter, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100,
  769. &m_pRawCtr[iCurrIndex], &m_pRawCtr[iPrevIndex],
  770. &FmtValue);
  771. // Return value and status
  772. *pdValue = FmtValue.doubleValue;
  773. *pdwStatus = FmtValue.CStatus;
  774. } else {
  775. stat = ERROR_GEN_FAILURE; // Todo: More specific error
  776. }
  777. } else {
  778. // Loading from property bag
  779. *pdValue = m_pFmtCtr[iCurrIndex];
  780. if ( 0 <= m_pFmtCtr[iCurrIndex] ) {
  781. *pdwStatus = ERROR_SUCCESS;
  782. } else {
  783. *pdwStatus = PDH_CSTATUS_INVALID_DATA;
  784. }
  785. stat = ERROR_SUCCESS;
  786. }
  787. }
  788. }
  789. }
  790. return stat;
  791. }
  792. void
  793. CGraphItem::SetHistoryValue (
  794. IN INT iIndex,
  795. OUT double dValue
  796. )
  797. /*++
  798. Routine Description:
  799. SetHistoryValue loads a formated sample value for the specified sample index.
  800. This method is used when loading the control from a property bag.
  801. Arguments:
  802. iIndex - Index of desired sample (0 = current, 1 = previous, ...)
  803. dValue - Value
  804. Return Value:
  805. Error status
  806. --*/
  807. {
  808. PHIST_CONTROL pHistCtrl = m_pCtrl->HistoryControl();
  809. INT iRealIndex;
  810. // Check for negative index
  811. if ( (iIndex < 0) || ( iIndex >= pHistCtrl->nMaxSamples) ) {
  812. return;
  813. }
  814. if ( NULL == m_pFmtCtr ) {
  815. return;
  816. }
  817. // if log source, index back from last sample
  818. if (m_pCtrl->IsLogSource()) {
  819. return;
  820. } else {
  821. // Determine history array index of sample
  822. iRealIndex = pHistCtrl->iCurrent - iIndex;
  823. if (iRealIndex < 0)
  824. iRealIndex += pHistCtrl->nSamples;
  825. m_pFmtCtr[iRealIndex] = dValue;
  826. }
  827. return;
  828. }
  829. PDH_STATUS
  830. CGraphItem::GetLogEntry(
  831. const INT iIndex,
  832. double *dMin,
  833. double *dMax,
  834. double *dAvg,
  835. DWORD *pdwStatus
  836. )
  837. {
  838. INT iLocIndex = iIndex;
  839. *dMin = -1.0;
  840. *dMax = -1.0;
  841. *dAvg = -1.0;
  842. *pdwStatus = PDH_CSTATUS_INVALID_DATA;
  843. if (m_pLogData == NULL)
  844. return PDH_NO_DATA;
  845. if (iLocIndex < 0 || iLocIndex >= m_pCtrl->HistoryControl()->nMaxSamples)
  846. return PDH_INVALID_ARGUMENT;
  847. // Subtract 1 because array is zero-based
  848. // Subtract another 1 because ??
  849. iLocIndex = ( m_pCtrl->HistoryControl()->nMaxSamples - 2 ) - iIndex;
  850. if (m_pLogData[iLocIndex].m_dMax < 0.0) {
  851. *pdwStatus = PDH_CSTATUS_INVALID_DATA;
  852. } else {
  853. *dMin = m_pLogData[iLocIndex].m_dMin;
  854. *dMax = m_pLogData[iLocIndex].m_dMax;
  855. *dAvg = m_pLogData[iLocIndex].m_dAvg;
  856. *pdwStatus = PDH_CSTATUS_VALID_DATA;
  857. }
  858. return ERROR_SUCCESS;
  859. }
  860. PDH_STATUS
  861. CGraphItem::GetLogEntryTimeStamp(
  862. const INT iIndex,
  863. LONGLONG& rLastTimeStamp,
  864. DWORD *pdwStatus
  865. )
  866. {
  867. INT iLocIndex = iIndex;
  868. rLastTimeStamp = 0;
  869. *pdwStatus = PDH_CSTATUS_INVALID_DATA;
  870. if (m_pLogData == NULL)
  871. return PDH_NO_DATA;
  872. if (iIndex < 0 || iIndex >= m_pCtrl->HistoryControl()->nMaxSamples)
  873. return PDH_INVALID_ARGUMENT;
  874. if ( ( MIN_TIME_VALUE == *((LONGLONG*)&m_pLogData[iLocIndex].m_LastTimeStamp) )
  875. || ( 0 > *((LONGLONG*)&m_pLogData[iLocIndex].m_dMax) ) ) {
  876. *pdwStatus = PDH_CSTATUS_INVALID_DATA;
  877. } else {
  878. *pdwStatus = PDH_CSTATUS_VALID_DATA;
  879. }
  880. rLastTimeStamp = *((LONGLONG*)&m_pLogData[iLocIndex].m_LastTimeStamp);
  881. return ERROR_SUCCESS;
  882. }
  883. void
  884. CGraphItem::SetLogEntry(
  885. const INT iIndex,
  886. const double dMin,
  887. const double dMax,
  888. const double dAvg )
  889. {
  890. if (m_pLogData) {
  891. m_pLogData[iIndex].m_dMin = dMin;
  892. m_pLogData[iIndex].m_dMax = dMax;
  893. m_pLogData[iIndex].m_dAvg = dAvg;
  894. }
  895. }
  896. void
  897. CGraphItem::SetLogEntryTimeStamp (
  898. const INT iIndex,
  899. const FILETIME& rLastTimeStamp )
  900. {
  901. if (m_pLogData) {
  902. m_pLogData[iIndex].m_LastTimeStamp.dwLowDateTime = rLastTimeStamp.dwLowDateTime;
  903. m_pLogData[iIndex].m_LastTimeStamp.dwHighDateTime = rLastTimeStamp.dwHighDateTime;
  904. }
  905. }
  906. HRESULT
  907. CGraphItem::GetValue(
  908. OUT double *pdValue,
  909. OUT long *plStat
  910. )
  911. /*++
  912. Routine Description:
  913. get_Value returns the most recent sample value for the counter.
  914. Arguments:
  915. pdValue - Pointer to returned value
  916. dlStatus - Pointer to returned counter status (PDH_CSTATUS_...)
  917. Return Value:
  918. HRESULT
  919. --*/
  920. {
  921. DWORD dwTmpStat;
  922. // Convert PDH status to HRESULT
  923. if (HistoryValue(0, pdValue, &dwTmpStat) != 0)
  924. return E_FAIL;
  925. *plStat = dwTmpStat;
  926. return NOERROR;
  927. }
  928. HRESULT
  929. CGraphItem::GetStatistics (
  930. OUT double *pdMax,
  931. OUT double *pdMin,
  932. OUT double *pdAvg,
  933. OUT LONG *plStatus
  934. )
  935. /*++
  936. Routine Description:
  937. GetStatistics computes the max, min, and average values for the sample
  938. history.
  939. Arguments:
  940. pdMax - Pointer to returned max value
  941. pdMax - Pointer to returned min value
  942. pdMax - Pointer to returned average value
  943. plStatus - Pointer to return counter status (PDH_CSTATUS_...)
  944. Return Value:
  945. HRESULT
  946. --*/
  947. {
  948. HRESULT hr = NOERROR;
  949. PDH_STATUS stat = ERROR_SUCCESS;
  950. PDH_STATISTICS StatData;
  951. INT iFirst;
  952. PHIST_CONTROL pHistCtrl;
  953. // If no data collected, return invalid data status
  954. if ( NULL == m_hCounter ) {
  955. *plStatus = PDH_CSTATUS_INVALID_DATA;
  956. } else {
  957. if (m_pCtrl->IsLogSource()) {
  958. if (m_pLogData) {
  959. *pdMax = m_dLogMax;
  960. *pdMin = m_dLogMin;
  961. *pdAvg = m_dLogAvg;
  962. *plStatus = PDH_CSTATUS_VALID_DATA;
  963. } else {
  964. *plStatus = PDH_CSTATUS_INVALID_DATA;
  965. }
  966. } else {
  967. if ( NULL == m_pFmtCtr ) {
  968. pHistCtrl = m_pCtrl->HistoryControl();
  969. ZeroMemory ( &StatData, sizeof ( PDH_STATISTICS ) );
  970. // Determine index of oldest sample
  971. if (pHistCtrl->iCurrent < pHistCtrl->nSamples - 1) {
  972. iFirst = pHistCtrl->iCurrent + 1;
  973. } else {
  974. iFirst = 0;
  975. }
  976. // Compute statistics over all samples
  977. // Note that max sample count is passed (i.e., buffer length)
  978. // not the number of actual samples
  979. if ( NULL != m_pRawCtr ) {
  980. stat = PdhComputeCounterStatistics (m_hCounter, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100,
  981. iFirst, pHistCtrl->nMaxSamples, m_pRawCtr, &StatData );
  982. if ( 0 != stat )
  983. hr = E_FAIL;
  984. } else {
  985. hr = E_FAIL;
  986. }
  987. if ( SUCCEEDED ( hr ) ) {
  988. *plStatus = StatData.mean.CStatus;
  989. *pdMin = StatData.min.doubleValue;
  990. *pdMax = StatData.max.doubleValue;
  991. *pdAvg = StatData.mean.doubleValue;
  992. }
  993. } else {
  994. // Data is cached from property bag.
  995. *pdMax = m_dFmtMax;
  996. *pdMin = m_dFmtMin;
  997. *pdAvg = m_dFmtAvg;
  998. *plStatus = m_lFmtStatus;
  999. }
  1000. }
  1001. }
  1002. return hr;
  1003. }
  1004. void
  1005. CGraphItem::SetStatistics (
  1006. IN double dMax,
  1007. IN double dMin,
  1008. IN double dAvg,
  1009. IN LONG lStatus
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. SetStatistics sets the max, min, and average values for the sample
  1014. history. It is used by LoadFromPropertyBag only.
  1015. Arguments:
  1016. dMax - max value
  1017. dMin - min value
  1018. dAvg - average value
  1019. lStatus - counter status (PDH_CSTATUS_...)
  1020. Return Value:
  1021. HRESULT
  1022. --*/
  1023. {
  1024. if (!m_pCtrl->IsLogSource()) {
  1025. m_dFmtMax = dMax;
  1026. m_dFmtMin = dMin;
  1027. m_dFmtAvg = dAvg;
  1028. m_lFmtStatus = lStatus;
  1029. }
  1030. }
  1031. /*
  1032. * CGraphItem::QueryInterface
  1033. * CGraphItem::AddRef
  1034. * CGraphItem::Release
  1035. */
  1036. STDMETHODIMP CGraphItem::QueryInterface(REFIID riid
  1037. , LPVOID *ppv)
  1038. {
  1039. *ppv = NULL;
  1040. if (riid == IID_ICounterItem || riid == IID_IUnknown)
  1041. {
  1042. *ppv = this;
  1043. }
  1044. else if (riid == DIID_DICounterItem)
  1045. {
  1046. if (m_pImpIDispatch == NULL)
  1047. {
  1048. m_pImpIDispatch = new CImpIDispatch(this, this);
  1049. if (m_pImpIDispatch == NULL)
  1050. return E_OUTOFMEMORY;
  1051. m_pImpIDispatch->SetInterface(DIID_DICounterItem, this);
  1052. *ppv = m_pImpIDispatch;
  1053. }
  1054. else
  1055. {
  1056. *ppv = m_pImpIDispatch;
  1057. }
  1058. }
  1059. else
  1060. {
  1061. return E_NOINTERFACE;
  1062. }
  1063. ((LPUNKNOWN)*ppv)->AddRef();
  1064. return NOERROR;
  1065. }
  1066. STDMETHODIMP_(ULONG) CGraphItem::AddRef(void)
  1067. {
  1068. return ++m_cRef;
  1069. }
  1070. STDMETHODIMP_(ULONG) CGraphItem::Release(void)
  1071. {
  1072. if (--m_cRef == 0)
  1073. {
  1074. delete this;
  1075. return 0;
  1076. }
  1077. return m_cRef;
  1078. }
  1079. // Get/Put Color
  1080. STDMETHODIMP CGraphItem::put_Color (
  1081. IN OLE_COLOR Color
  1082. )
  1083. {
  1084. COLORREF rgbColor;
  1085. HRESULT hReturn;
  1086. hReturn = OleTranslateColor(Color, NULL, &rgbColor);
  1087. if ( S_OK == hReturn ) {
  1088. m_rgbColor = rgbColor;
  1089. InvalidatePen();
  1090. InvalidateBrush();
  1091. }
  1092. return hReturn;
  1093. }
  1094. STDMETHODIMP CGraphItem::get_Color (
  1095. OUT OLE_COLOR *pColor
  1096. )
  1097. {
  1098. *pColor = m_rgbColor;
  1099. return NOERROR;
  1100. }
  1101. // Get/Put Width
  1102. STDMETHODIMP CGraphItem::put_Width (
  1103. IN INT iWidthInPixels)
  1104. {
  1105. if ( ( iWidthInPixels > 0 ) && (iWidthInPixels <= NumWidthIndices() ) ) {
  1106. m_iWidth = iWidthInPixels;
  1107. InvalidatePen();
  1108. return NOERROR;
  1109. } else {
  1110. return E_INVALIDARG;
  1111. }
  1112. }
  1113. STDMETHODIMP CGraphItem::get_Width (
  1114. OUT INT* piWidthInPixels
  1115. )
  1116. {
  1117. *piWidthInPixels = m_iWidth;
  1118. return NOERROR;
  1119. }
  1120. // Get/Put Line Style
  1121. STDMETHODIMP CGraphItem::put_LineStyle (
  1122. IN INT iLineStyle
  1123. )
  1124. {
  1125. if ( ( iLineStyle >= 0 ) && (iLineStyle < NumStyleIndices() ) ) {
  1126. m_iStyle = iLineStyle;
  1127. InvalidatePen();
  1128. return NOERROR;
  1129. } else {
  1130. return E_INVALIDARG;
  1131. }
  1132. }
  1133. STDMETHODIMP CGraphItem::get_LineStyle (
  1134. OUT INT* piLineStyle
  1135. )
  1136. {
  1137. *piLineStyle = m_iStyle;
  1138. return NOERROR;
  1139. }
  1140. // Get/Put Scale
  1141. STDMETHODIMP CGraphItem::put_ScaleFactor (
  1142. IN INT iScaleFactor
  1143. )
  1144. {
  1145. HRESULT hr = NOERROR;
  1146. if ( ( INT_MAX == iScaleFactor )
  1147. || ( ( iScaleFactor >= PDH_MIN_SCALE ) && (iScaleFactor <= PDH_MAX_SCALE) ) ) {
  1148. PDH_COUNTER_INFO ci;
  1149. DWORD size;
  1150. m_iScaleFactor = iScaleFactor;
  1151. if ( INT_MAX == iScaleFactor )
  1152. {
  1153. if ( NULL != Handle() ) {
  1154. size = sizeof(ci);
  1155. hr = PdhGetCounterInfo (
  1156. Handle(),
  1157. FALSE,
  1158. &size,
  1159. &ci);
  1160. if (hr == ERROR_SUCCESS) {
  1161. m_dScale = pow ((double)10.0f, (double)ci.lDefaultScale);
  1162. m_CounterInfo = ci;
  1163. }
  1164. } else {
  1165. // m_dScale remains at previous value (default=1)
  1166. hr = PDH_INVALID_HANDLE;
  1167. }
  1168. }
  1169. else
  1170. {
  1171. m_dScale = pow ((double)10.0, (double)iScaleFactor);
  1172. hr = NOERROR;
  1173. }
  1174. } else {
  1175. hr = E_INVALIDARG;
  1176. }
  1177. return hr;
  1178. }
  1179. STDMETHODIMP CGraphItem::get_ScaleFactor (
  1180. OUT INT* piScaleFactor
  1181. )
  1182. {
  1183. *piScaleFactor = m_iScaleFactor;
  1184. return NOERROR;
  1185. }
  1186. STDMETHODIMP CGraphItem::get_Path (
  1187. OUT BSTR* pstrPath
  1188. )
  1189. {
  1190. TCHAR achPath[MAX_PATH];
  1191. USES_CONVERSION
  1192. FormPath(achPath, FALSE);
  1193. *pstrPath = SysAllocString(T2W(achPath));
  1194. if ( NULL == *pstrPath ) {
  1195. return E_OUTOFMEMORY;
  1196. } else {
  1197. return NOERROR;
  1198. }
  1199. }
  1200. STDMETHODIMP CGraphItem::get_Value (
  1201. OUT double* pdValue
  1202. )
  1203. {
  1204. DWORD dwTmpStat;
  1205. double dValue;
  1206. // Convert PDH status to HRESULT
  1207. if (HistoryValue(0, &dValue, &dwTmpStat) != 0) {
  1208. dValue = -1.0;
  1209. }
  1210. else
  1211. if (!IsSuccessSeverity(dwTmpStat)) {
  1212. dValue = -1.0;
  1213. }
  1214. *pdValue = dValue;
  1215. return NOERROR;
  1216. }
  1217. HPEN CGraphItem::Pen(void)
  1218. {
  1219. // if pen not valid
  1220. if (m_hPen == NULL)
  1221. {
  1222. // create a new one based on current attributes
  1223. m_hPen = CreatePen(m_iStyle, m_iWidth, m_rgbColor);
  1224. // if can't do it, use a stock object (this can't fail)
  1225. if (m_hPen == NULL)
  1226. m_hPen = (HPEN)GetStockObject(BLACK_PEN);
  1227. }
  1228. return m_hPen;
  1229. }
  1230. HBRUSH CGraphItem::Brush(void)
  1231. {
  1232. // if brush is not valid
  1233. if (m_hBrush == NULL)
  1234. {
  1235. m_hBrush = CreateSolidBrush(m_rgbColor);
  1236. if (m_hBrush == NULL)
  1237. m_hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
  1238. }
  1239. return m_hBrush;
  1240. }
  1241. void CGraphItem::InvalidatePen(void)
  1242. {
  1243. if (m_hPen != NULL)
  1244. {
  1245. DeleteObject(m_hPen);
  1246. m_hPen = NULL;
  1247. }
  1248. }
  1249. void CGraphItem::InvalidateBrush(void)
  1250. {
  1251. if (m_hBrush != NULL)
  1252. {
  1253. DeleteObject(m_hBrush);
  1254. m_hBrush = NULL;
  1255. }
  1256. }
  1257. CGraphItem*
  1258. CGraphItem::Next (
  1259. void
  1260. )
  1261. {
  1262. PCInstanceNode pInstance;
  1263. PCObjectNode pObject;
  1264. PCMachineNode pMachine;
  1265. if (m_pNextItem)
  1266. return m_pNextItem;
  1267. else if ( NULL != m_pInstance->Next()) {
  1268. pInstance = m_pInstance->Next();
  1269. return pInstance->FirstItem();
  1270. } else if ( NULL != m_pInstance->m_pObject->Next()) {
  1271. pObject = m_pInstance->m_pObject->Next();
  1272. return pObject->FirstInstance()->FirstItem();
  1273. } else if ( NULL != m_pInstance->m_pObject->m_pMachine->Next()) {
  1274. pMachine = m_pInstance->m_pObject->m_pMachine->Next();
  1275. return pMachine->FirstObject()->FirstInstance()->FirstItem();
  1276. } else {
  1277. return NULL;
  1278. }
  1279. }
  1280. void
  1281. CGraphItem::FormPath (
  1282. LPTSTR pszPath,
  1283. BOOL fWildCard
  1284. )
  1285. {
  1286. LPTSTR pszNext = pszPath;
  1287. if ( m_fLocalMachine )
  1288. pszPath[0] = 0;
  1289. else
  1290. lstrcpy ( pszPath, Machine()->Name() );
  1291. pszNext = pszNext + lstrlen ( pszPath );
  1292. lstrcpy ( pszNext, _T("\\") );
  1293. pszNext += 1; // Length of _T("\\");
  1294. lstrcpy ( pszNext, Object()->Name() );
  1295. pszNext += lstrlen ( Object()->Name() );
  1296. if (fWildCard) {
  1297. lstrcpy ( pszNext,_T("(*)") );
  1298. pszNext += 3; // Length of _T("(*)");
  1299. }
  1300. else if ( Instance()->Name()[0] ) {
  1301. lstrcpy ( pszNext,_T("("));
  1302. pszNext += 1; // Length of _T("(");
  1303. lstrcpy ( pszNext,Instance()->Name() );
  1304. pszNext += lstrlen ( Instance()->Name() );
  1305. lstrcpy ( pszNext,_T(")") );
  1306. pszNext += 1; // Length of _T("(");
  1307. }
  1308. lstrcpy ( pszNext, _T("\\") );
  1309. pszNext += 1; // Length of _T("\\");
  1310. lstrcpy ( pszNext,Counter()->Name() );
  1311. }
  1312. void
  1313. CGraphItem::Delete (
  1314. BOOL bPropogateUp
  1315. )
  1316. //
  1317. // This method just provides a convenient access to the DeleteCounter method
  1318. // of the control when you only have a pointer to the graph item.
  1319. //
  1320. {
  1321. m_pCtrl->DeleteCounter(this, bPropogateUp);
  1322. }
  1323. HRESULT
  1324. CGraphItem::GetNextValue (
  1325. TCHAR*& pszNext,
  1326. double& rdValue )
  1327. {
  1328. HRESULT hr = NOERROR;
  1329. TCHAR szValue[MAX_DOUBLE_TEXT_SIZE + 1];
  1330. INT iDataLen;
  1331. INT iLen;
  1332. VARIANT vValue;
  1333. rdValue = -1.0;
  1334. iDataLen = wcscspn (pszNext, L"\t");
  1335. iLen = min ( iDataLen, MAX_DOUBLE_TEXT_SIZE );
  1336. lstrcpyn ( szValue, pszNext, iLen + 1 );
  1337. szValue[iLen] = L'\0';
  1338. VariantInit( &vValue );
  1339. vValue.vt = VT_BSTR;
  1340. vValue.bstrVal = SysAllocString ( szValue );
  1341. hr = VariantChangeTypeEx( &vValue, &vValue, LCID_SCRIPT, VARIANT_NOUSEROVERRIDE, VT_R8 );
  1342. if ( SUCCEEDED(hr) ) {
  1343. rdValue = vValue.dblVal;
  1344. }
  1345. pszNext += iDataLen + 1 ;
  1346. VariantClear( &vValue );
  1347. return hr;
  1348. }
  1349. BOOL
  1350. CGraphItem::IsRateCounter ( void )
  1351. {
  1352. BOOL bReturn = FALSE;
  1353. DWORD dwRateMask = PERF_TYPE_COUNTER | PERF_COUNTER_RATE;
  1354. DWORD dwFractionMask = PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION;
  1355. if ( dwRateMask == ( m_CounterInfo.dwType & dwRateMask ) ) {
  1356. bReturn = TRUE;
  1357. }
  1358. else if ( dwFractionMask == ( m_CounterInfo.dwType & dwFractionMask ) ) {
  1359. bReturn = TRUE;
  1360. }
  1361. return bReturn;
  1362. }