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.

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