|
|
/*++
Copyright (C) 1996-1999 Microsoft Corporation
Module Name:
grphitem.cpp
Abstract:
<abstract>
--*/
#ifndef _LOG_INCLUDE_DATA
#define _LOG_INCLUDE_DATA 0
#endif
#include <math.h>
#include <limits.h> // for INT_MAX
#include <pdhp.h>
#include "polyline.h"
#include "visuals.h"
#include "grphitem.h"
#include "unihelpr.h"
#include "utils.h"
#include "pdhmsg.h"
#define MAX_DOUBLE_TEXT_SIZE (64)
// Construction/Destruction
CGraphItem::CGraphItem ( CSysmonControl *pCtrl ) : m_cRef ( 0 ), m_pCtrl ( pCtrl ), m_hCounter ( NULL ), m_hPen ( NULL ), m_hBrush ( NULL ), m_pCounter ( NULL ), m_pInstance ( NULL), m_pRawCtr ( NULL ), m_pFmtCtr ( NULL ), m_dFmtMax ( 0 ), m_dFmtMin ( 0 ), m_dFmtAvg ( 0 ), m_lFmtStatus ( 0 ),
m_pLogData ( NULL ), m_pImpIDispatch ( NULL ),
m_rgbColor ( RGB(0,0,0) ), m_iWidth ( 1 ), m_iStyle ( 0 ), m_iScaleFactor ( INT_MAX ), m_dScale ( (double)1.0 ),
m_pNextItem ( NULL ), m_bUpdateLog ( TRUE ), m_fGenerated ( FALSE ) /*++
Routine Description:
Constructor for the CGraphItem class. It initializes the member variables.
Arguments:
None.
Return Value:
None.
--*/ { ZeroMemory ( &m_CounterInfo, sizeof (m_CounterInfo ) ); m_CounterInfo.CStatus = PDH_CSTATUS_INVALID_DATA; return; }
CGraphItem::~CGraphItem ( VOID ) /*++
Routine Description:
Destructor for the CGraphItem class. It frees any objects, storage, and interfaces that were created. If the item is part of a query it is removed from the query.
Arguments:
None.
Return Value:
None.
--*/ { if (m_hCounter != NULL) RemoveFromQuery();
if (m_hPen != NULL) DeleteObject(m_hPen);
if (m_hBrush != NULL) DeleteObject(m_hBrush);
if (m_pImpIDispatch != NULL) delete m_pImpIDispatch; }
HRESULT CGraphItem::SaveToStream ( IN LPSTREAM pIStream, IN BOOL fWildCard, IN INT iVersMaj, IN INT // iVersMin
) /*++
Routine Description:
SaveToStream writes the graph item's properties to the provided stream.
Arguments:
pIStream - Pointer to stream interface pszPath - Path name to save item under
Return Value:
HRESULT - S_OK or stream error
--*/ { LPWSTR pszWidePath; TCHAR szPath[MAX_PATH]; LPTSTR szEnglishBuf = NULL; DWORD dwEnglishBufSize = 0; LPTSTR pNewBuf; DWORD dwBufSize; LPTSTR pszPath; HRESULT hr = S_OK; PDH_STATUS pdhStatus;
USES_CONVERSION
// Get Ansi path name
FormPath(szPath, fWildCard ); pszPath = szPath; //
// Initialize the locale path buffer
//
if (dwEnglishBufSize == 0) { dwEnglishBufSize = (MAX_PATH + 1) * sizeof(TCHAR);
szEnglishBuf = (LPTSTR) malloc(dwEnglishBufSize); if (szEnglishBuf == NULL) { dwEnglishBufSize = 0; } }
if (szEnglishBuf != NULL) { //
// Translate counter name from Localization into English
//
dwBufSize = dwEnglishBufSize;
pdhStatus = PdhTranslate009Counter( szPath, szEnglishBuf, &dwBufSize);
if (pdhStatus == PDH_MORE_DATA) { pNewBuf = (LPTSTR)realloc(szEnglishBuf, dwBufSize); if (pNewBuf != NULL) { szEnglishBuf = pNewBuf; dwEnglishBufSize = dwBufSize;
pdhStatus = PdhTranslate009Counter( szPath, szEnglishBuf, &dwBufSize); } }
if (pdhStatus == ERROR_SUCCESS) { pszPath = szEnglishBuf; } }
pszWidePath = T2W(pszPath);
if ( SMONCTRL_MAJ_VERSION == iVersMaj ) { GRAPHITEM_DATA3 ItemData;
// Move properties to storage structure
ItemData.m_rgbColor = m_rgbColor; ItemData.m_iWidth = m_iWidth; ItemData.m_iStyle = m_iStyle; ItemData.m_iScaleFactor = m_iScaleFactor; assert( 0 < lstrlen(pszWidePath ) ); ItemData.m_nPathLength = lstrlen(pszWidePath); // Write structure to stream
hr = pIStream->Write(&ItemData, sizeof(ItemData), NULL); if (FAILED(hr)) { goto ErrorOut; }
// Write path name to stream
hr = pIStream->Write(pszWidePath, ItemData.m_nPathLength*sizeof(WCHAR), NULL); if (FAILED(hr)) { goto ErrorOut; } }
ErrorOut: if (szEnglishBuf != NULL) { free(szEnglishBuf); } return hr; }
HRESULT CGraphItem::NullItemToStream ( IN LPSTREAM pIStream, IN INT,// iVersMaj,
IN INT // iVersMin
) /*++
Routine Description:
NulItemToStream writes a graph item structiure with a null path name to the stream. This is used to marked the end of the counter data in the control's saved state.
Arguments:
pIStream - Pointer to stream interface
Return Value:
HRESULT - S_OK or stream error
--*/ { GRAPHITEM_DATA3 ItemData;
// Zero path length, other fields needn't be initialized
ItemData.m_nPathLength = 0;
// Write structure to stream
return pIStream->Write(&ItemData, sizeof(ItemData), NULL); }
HRESULT CGraphItem::SaveToPropertyBag ( IN IPropertyBag* pIPropBag, IN INT iIndex, IN BOOL bUserMode, IN INT, // iVersMaj,
IN INT // iVersMin
) /*++
Routine Description:
SaveToPropertyBag writes the graph item's properties to the provided property bag interface. The history data is saved as part of the properties.
Arguments:
pIPropBag - Pointer to property bag interface fWildCard iVersMaj iVersMin
Return Value:
HRESULT - S_OK or property bag error
--*/ { HRESULT hr = S_OK;
TCHAR szPath[MAX_PATH]; PHIST_CONTROL pHistCtrl; VARIANT vValue; TCHAR szCounterName[16]; TCHAR szPropertyName[16+16]; DWORD dwCounterNameBytes; DWORD dwCounterNameLength; LPTSTR pszNext; LPTSTR szEnglishBuf = NULL; DWORD dwEnglishBufSize = 0; LPTSTR pszPath; DWORD dwBufSize; LPTSTR pNewBuf; PDH_STATUS pdhStatus;
USES_CONVERSION
// Write properties
// Write path name
_stprintf ( szCounterName, _T("%s%05d."), _T("Counter"), iIndex ); dwCounterNameLength = lstrlen (szCounterName); dwCounterNameBytes = dwCounterNameLength * sizeof (TCHAR);
//
// Generate full path name. (machine\object\instance\counter format)
//
FormPath(szPath, FALSE);
pszPath = szPath; //
// Initialize the locale path buffer
//
if (dwEnglishBufSize == 0) { dwEnglishBufSize = (MAX_PATH + 1) * sizeof(TCHAR);
szEnglishBuf = (LPTSTR) malloc(dwEnglishBufSize); if (szEnglishBuf == NULL) { dwEnglishBufSize = 0; } }
if (szEnglishBuf != NULL) { //
// Translate counter name from Localization into English
//
dwBufSize = dwEnglishBufSize;
pdhStatus = PdhTranslate009Counter( szPath, szEnglishBuf, &dwBufSize);
if (pdhStatus == PDH_MORE_DATA) { pNewBuf = (LPTSTR)realloc(szEnglishBuf, dwBufSize); if (pNewBuf != NULL) { szEnglishBuf = pNewBuf; dwEnglishBufSize = dwBufSize;
pdhStatus = PdhTranslate009Counter( szPath, szEnglishBuf, &dwBufSize); } }
if (pdhStatus == ERROR_SUCCESS) { pszPath = szEnglishBuf; } }
//
// Save the counter path into property bag
//
memcpy ( szPropertyName, szCounterName, dwCounterNameBytes ); pszNext = szPropertyName + dwCounterNameLength; lstrcpy ( pszNext, _T("Path") ); hr = StringToPropertyBag ( pIPropBag, szPropertyName, pszPath );
if (szEnglishBuf != NULL) { free(szEnglishBuf); }
// Write visual properties
if ( SUCCEEDED( hr ) ){ lstrcpy ( pszNext, _T("Color") );
hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, m_rgbColor ); }
if ( SUCCEEDED( hr ) ){ lstrcpy ( pszNext, _T("Width") );
hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, m_iWidth ); }
if ( SUCCEEDED( hr ) ){ lstrcpy ( pszNext, _T("LineStyle") );
hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, m_iStyle ); }
if ( SUCCEEDED( hr ) ){ INT iLocalFactor = m_iScaleFactor; lstrcpy ( pszNext, _T("ScaleFactor") ); if ( INT_MAX == iLocalFactor ) { // Save actual scale factor in case the counter cannot be
// validated when the property bag file is opened.
// lDefaultScale is 0 if never initialized.
iLocalFactor = m_CounterInfo.lDefaultScale; } hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, iLocalFactor ); }
// Write history data only if live display, data exists and not in design mode.
// Log data is rebuilt from the log file.
pHistCtrl = m_pCtrl->HistoryControl();
if ( ( pHistCtrl->nSamples > 0) #if !_LOG_INCLUDE_DATA
&& ( !pHistCtrl->bLogSource ) #endif
&& bUserMode ) { LPTSTR pszData = NULL; DWORD dwMaxStrLen = ( pHistCtrl->nMaxSamples * MAX_DOUBLE_TEXT_SIZE ) + 1; pszData = new TCHAR[ dwMaxStrLen ]; if ( NULL == pszData ) { hr = E_OUTOFMEMORY; }
// Write the current statistics.
if ( SUCCEEDED(hr) ) {
double dMin; double dMax; double dAvg; LONG lStatus;
hr = GetStatistics ( &dMax, &dMin, &dAvg, &lStatus );
if (SUCCEEDED(hr) && IsSuccessSeverity(lStatus)) { lstrcpy ( pszNext, _T("Minimum") );
hr = DoubleToPropertyBag ( pIPropBag, szPropertyName, dMin );
if ( SUCCEEDED(hr) ) { lstrcpy ( pszNext, _T("Maximum") );
hr = DoubleToPropertyBag ( pIPropBag, szPropertyName, dMax ); } if ( SUCCEEDED(hr) ) { lstrcpy ( pszNext, _T("Average") );
hr = DoubleToPropertyBag ( pIPropBag, szPropertyName, dAvg ); } if ( SUCCEEDED(hr) ) { lstrcpy ( pszNext, _T("StatisticStatus") );
hr = IntegerToPropertyBag ( pIPropBag, szPropertyName, lStatus ); } } } if ( SUCCEEDED(hr) ) {
INT i; LPTSTR pszTemp; HRESULT hrConvert = S_OK; double dblValue; DWORD dwTmpStat; DWORD dwCurrentDataLength; DWORD dwTempLength; LPTSTR pszDataNext;
lstrcpy ( pszData, _T("") ); dwCurrentDataLength = 0; pszDataNext = pszData;
for ( i = 0; ( S_OK == hrConvert ) && ( i < pHistCtrl->nSamples ); i++ ) { if ( ERROR_SUCCESS != HistoryValue(i, &dblValue, &dwTmpStat) ) { dblValue = -1.0; } else if (!IsSuccessSeverity(dwTmpStat)) { dblValue = -1.0; }
VariantInit( &vValue ); vValue.vt = VT_R8; vValue.dblVal = dblValue;
hrConvert = VariantChangeTypeEx( &vValue, &vValue, LCID_SCRIPT, VARIANT_NOUSEROVERRIDE, VT_BSTR ); pszTemp = W2T( vValue.bstrVal); dwTempLength = lstrlen ( pszTemp ); // Extra TCHAR for NULL terminator
if ( dwTempLength + dwCurrentDataLength + sizeof(TCHAR) > dwMaxStrLen ) { TCHAR* pszNewData; dwMaxStrLen *= 2; // Allocate a new buffer
pszNewData = new TCHAR[ dwMaxStrLen ]; if ( NULL != pszNewData ) { memcpy ( pszNewData, pszData, dwCurrentDataLength * sizeof (TCHAR) ); delete pszData; pszData = pszNewData; pszDataNext = pszData; } else { hr = E_OUTOFMEMORY; } }
if ( SUCCEEDED(hr)) { if ( i > 0 ) { lstrcpy ( pszDataNext, _T("\t") ); dwCurrentDataLength += 1; // char count for _T("\t");
pszDataNext += 1; } memcpy ( pszDataNext, pszTemp, dwTempLength * sizeof(TCHAR) ); dwCurrentDataLength += dwTempLength; pszDataNext += dwTempLength; }
VariantClear( &vValue ); } lstrcpy ( pszDataNext, _T("") ); }
lstrcpy ( pszNext, _T("Data") );
hr = StringToPropertyBag ( pIPropBag, szPropertyName, pszData ); if ( NULL != pszData ) { delete ( pszData ); } }
return hr; }
HRESULT CGraphItem::LoadFromPropertyBag ( IN IPropertyBag* pIPropBag, IN IErrorLog* pIErrorLog, IN INT iIndex, IN INT, // iVersMaj,
IN INT, // iVersMin
IN INT iSampleCount ) /*++
Routine Description:
LoadFromPropertyBag loads the graph item's properties from the provided property bag interface. Arguments:
pIPropBag - Pointer to property bag interface iVersMaj iVersMin
Return Value:
HRESULT - S_OK or property bag error
--*/ { HRESULT hr = S_OK;
TCHAR szCounterName[16]; TCHAR szPropertyName[16+16]; OLE_COLOR clrValue; INT iValue; LPTSTR pszData = NULL; int iBufSizeCurrent = 0; int iBufSize;
USES_CONVERSION
_stprintf ( szCounterName, _T("%s%05d."), _T("Counter"), iIndex );
// Read visual properties
lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("Color") ); hr = OleColorFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, clrValue ); if ( SUCCEEDED(hr) ) { hr = put_Color ( clrValue ); }
lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("Width") ); hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, iValue ); if ( SUCCEEDED(hr) ) { hr = put_Width ( iValue ); }
lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("LineStyle") ); hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, iValue ); if ( SUCCEEDED(hr) ) { hr = put_LineStyle ( iValue ); } lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("ScaleFactor") ); hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, iValue ); if ( SUCCEEDED(hr) ) { hr = put_ScaleFactor ( iValue ); }
if ( 0 < iSampleCount ) { if ( NULL != m_pFmtCtr ) delete m_pFmtCtr;
m_pFmtCtr = new double[MAX_GRAPH_SAMPLES]; if ( NULL == m_pFmtCtr ) { hr = E_OUTOFMEMORY; } else { INT iFmtIndex; for (iFmtIndex = 0; iFmtIndex < MAX_GRAPH_SAMPLES; iFmtIndex++ ) { m_pFmtCtr[iFmtIndex] = -1.0; } }
if ( SUCCEEDED(hr) ) { lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("Data") );
iBufSize = iBufSizeCurrent;
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, pszData, iBufSize );
if ( SUCCEEDED(hr) && iBufSize > iBufSizeCurrent ) { if ( NULL != pszData ) { delete pszData; } pszData = new TCHAR[ iBufSize ];
if ( NULL == pszData ) { hr = E_OUTOFMEMORY; } else { lstrcpy ( pszData, _T("") ); iBufSizeCurrent = iBufSize;
hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, pszData, iBufSize ); } } }
// Read the samples in buffer order.
if ( NULL != pszData && SUCCEEDED ( hr ) ) { INT iDataIndex; double dValue = 0; TCHAR* pNextData; TCHAR* pDataEnd; pNextData = pszData; pDataEnd = pszData + lstrlen(pszData);
for ( iDataIndex = 0; iDataIndex < iSampleCount; iDataIndex++ ) { if ( pNextData < pDataEnd ) { hr = GetNextValue ( pNextData, dValue ); } else { hr = E_FAIL; }
if ( SUCCEEDED(hr) ) { SetHistoryValue ( iDataIndex, dValue ); } else { SetHistoryValue ( iDataIndex, -1.0 ); // iSampleCount = 0;
// Control loaded fine, just no data.
hr = NOERROR; } } } if ( NULL != pszData ) { delete pszData; } // Read the current statistics.
lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("Maximum") ); hr = DoubleFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, m_dFmtMax );
lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("Minimum") ); hr = DoubleFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, m_dFmtMin );
lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("Average") ); hr = DoubleFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, m_dFmtAvg );
lstrcpy ( szPropertyName, szCounterName ); lstrcat ( szPropertyName, _T("StatisticStatus") ); hr = IntegerFromPropertyBag ( pIPropBag, pIErrorLog, szPropertyName, (INT&)m_lFmtStatus ); }
return hr; }
HRESULT CGraphItem::AddToQuery ( IN HQUERY hQuery ) /*++
Routine Description:
AddToQuery adds a counter to the provided query based on the item's pathname. It also allocates an array of raw counter value structures for holding the counter's sample history.
Arguments:
hQuery - Handle to query
Return Value:
Boolean status - TRUE = success
--*/ { HCOUNTER hCounter; INT i; HRESULT hr; TCHAR achPath[MAX_PATH]; PDH_COUNTER_INFO ci; DWORD size;
PHIST_CONTROL pHistCtrl = m_pCtrl->HistoryControl();
// Can't add if already in query
if (m_hCounter != NULL) return E_FAIL;
// Allocate memory for maximum sample count
if (pHistCtrl->nMaxSamples > 0) {
// if log data
if (pHistCtrl->bLogSource) {
// allocate space for formatted values
m_pLogData = new LOG_ENTRY_DATA[pHistCtrl->nMaxSamples]; if (m_pLogData == NULL) return E_OUTOFMEMORY;
// Clear the statistics
m_dLogMax = 0.0; m_dLogMin = 0.0; m_dLogAvg = 0.0; } else { // else allocate raw value space
m_pRawCtr = new PDH_RAW_COUNTER[pHistCtrl->nMaxSamples]; if ( NULL == m_pRawCtr ) return E_OUTOFMEMORY;
// Clear all status flags
for (i=0; i < pHistCtrl->nMaxSamples; i++) m_pRawCtr[i].CStatus = PDH_CSTATUS_INVALID_DATA; } }
// Create the counter object
FormPath(achPath, FALSE); hr = PdhAddCounter(hQuery, achPath, 0, &hCounter); if (IsErrorSeverity(hr)) { delete m_pRawCtr; m_pRawCtr = NULL; return hr; }
size = sizeof(ci); hr = PdhGetCounterInfo ( hCounter, FALSE, &size, &ci);
if (hr == ERROR_SUCCESS) { m_CounterInfo = ci; if ( INT_MAX == m_iScaleFactor ) { m_dScale = pow ((double)10.0f, (double)ci.lDefaultScale); } }
m_hCounter = hCounter;
return NOERROR; }
HRESULT CGraphItem::RemoveFromQuery ( VOID ) /*++
Routine Description:
RemoveFromQuery deletes the item's counter and releases its history array.
Arguments:
None.
Return Value:
Boolean status - TRUE = success
--*/ { // If no counter handle, not attached to query
if (m_hCounter == NULL) return S_FALSE;
// Delete the counter
PdhRemoveCounter(m_hCounter); m_hCounter = NULL;
// Free the buffers
if (m_pLogData) { delete m_pLogData; m_pLogData = NULL; }
if (m_pRawCtr) { delete m_pRawCtr; m_pRawCtr = NULL; }
if (m_pFmtCtr) { delete m_pFmtCtr; m_pFmtCtr = NULL; }
return NOERROR; }
void CGraphItem::ClearHistory ( void ) /*++
Routine Description:
ClearHistory resets the raw counter buffer values to Invalid.
Arguments: None.
Return Value: None. --*/ { INT i;
// Clear all status flags
if ( NULL != m_pRawCtr ) { for (i=0; i < m_pCtrl->HistoryControl()->nMaxSamples; i++) { m_pRawCtr[i].CStatus = PDH_CSTATUS_INVALID_DATA; } } }
VOID CGraphItem::UpdateHistory ( IN BOOL bValidSample ) /*++
Routine Description:
UpdateHistory reads the raw value for the counter and stores it in the history slot specified by the history control.
Arguments:
bValidSample - True if raw value is available, False if missed sample
Return Value:
None.
--*/ { DWORD dwCtrType;
// Make sure there is a counter handle
if (m_hCounter == NULL) return;
if (bValidSample) { // Read the raw value
if ( NULL != m_pRawCtr ) { PdhGetRawCounterValue(m_hCounter, &dwCtrType, &m_pRawCtr[m_pCtrl->HistoryControl()->iCurrent]); } } else { // Mark value failed
if ( NULL != m_pRawCtr ) { m_pRawCtr[m_pCtrl->HistoryControl()->iCurrent].CStatus = PDH_CSTATUS_INVALID_DATA; } } }
PDH_STATUS CGraphItem::HistoryValue ( IN INT iIndex, OUT double *pdValue, OUT DWORD *pdwStatus ) /*++
Routine Description:
HistoryValue computes a formated sample value from the selected raw history sample. The calculation is actually based on the the specified sample plus the preceding sample.
Arguments: iIndex - Index of desired sample (0 = current, 1 = previous, ...) pdValue - Pointer to return value pdwStatus - Pointer to return counter status (PDH_CSTATUS_...)
Return Value:
Error status
--*/ { PDH_STATUS stat = ERROR_INVALID_PARAMETER; INT iPrevIndex; INT iCurrIndex; PDH_FMT_COUNTERVALUE FmtValue; PHIST_CONTROL pHistCtrl = m_pCtrl->HistoryControl();
// Check for negative index
if ( iIndex >= 0 ) { // If sample not available from cache or data, return invalid data status
if ( NULL == m_pFmtCtr && ( m_hCounter == NULL || iIndex + 1 >= pHistCtrl->nSamples ) ) { *pdwStatus = PDH_CSTATUS_INVALID_DATA; *pdValue = 0.0; stat = ERROR_SUCCESS; } else { // if log source, index back from last sample
if (m_pCtrl->IsLogSource()) { *pdValue = m_pLogData[pHistCtrl->nSamples - iIndex - 1].m_dAvg; *pdwStatus = (*pdValue >= 0.0) ? PDH_CSTATUS_VALID_DATA : PDH_CSTATUS_INVALID_DATA; stat = ERROR_SUCCESS; } else { // Determine history array index of sample
iCurrIndex = pHistCtrl->iCurrent - iIndex; if (iCurrIndex < 0) iCurrIndex += pHistCtrl->nMaxSamples;
// Check to determine if loading from property bag
if ( NULL == m_pFmtCtr ) { // Need previous sample as well
if (iCurrIndex > 0) iPrevIndex = iCurrIndex - 1; else iPrevIndex = pHistCtrl->nMaxSamples - 1;
// Compute the formatted value
if ( NULL != m_pRawCtr ) { stat = PdhCalculateCounterFromRawValue(m_hCounter, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, &m_pRawCtr[iCurrIndex], &m_pRawCtr[iPrevIndex], &FmtValue); // Return value and status
*pdValue = FmtValue.doubleValue; *pdwStatus = FmtValue.CStatus; } else { stat = ERROR_GEN_FAILURE; // Todo: More specific error
} } else { // Loading from property bag
*pdValue = m_pFmtCtr[iCurrIndex]; if ( 0 <= m_pFmtCtr[iCurrIndex] ) { *pdwStatus = ERROR_SUCCESS; } else { *pdwStatus = PDH_CSTATUS_INVALID_DATA; } stat = ERROR_SUCCESS; } } } } return stat; }
void CGraphItem::SetHistoryValue ( IN INT iIndex, OUT double dValue ) /*++
Routine Description:
SetHistoryValue loads a formated sample value for the specified sample index. This method is used when loading the control from a property bag.
Arguments: iIndex - Index of desired sample (0 = current, 1 = previous, ...) dValue - Value
Return Value:
Error status
--*/ { PHIST_CONTROL pHistCtrl = m_pCtrl->HistoryControl(); INT iRealIndex;
// Check for negative index
if ( (iIndex < 0) || ( iIndex >= pHistCtrl->nMaxSamples) ) { return; }
if ( NULL == m_pFmtCtr ) { return; } // if log source, index back from last sample
if (m_pCtrl->IsLogSource()) { return; } else { // Determine history array index of sample
iRealIndex = pHistCtrl->iCurrent - iIndex; if (iRealIndex < 0) iRealIndex += pHistCtrl->nSamples;
m_pFmtCtr[iRealIndex] = dValue; }
return; }
PDH_STATUS CGraphItem::GetLogEntry( const INT iIndex, double *dMin, double *dMax, double *dAvg, DWORD *pdwStatus ) { INT iLocIndex = iIndex;
*dMin = -1.0; *dMax = -1.0; *dAvg = -1.0; *pdwStatus = PDH_CSTATUS_INVALID_DATA;
if (m_pLogData == NULL) return PDH_NO_DATA;
if (iLocIndex < 0 || iLocIndex >= m_pCtrl->HistoryControl()->nMaxSamples) return PDH_INVALID_ARGUMENT;
// Subtract 1 because array is zero-based
// Subtract another 1 because ??
iLocIndex = ( m_pCtrl->HistoryControl()->nMaxSamples - 2 ) - iIndex;
if (m_pLogData[iLocIndex].m_dMax < 0.0) { *pdwStatus = PDH_CSTATUS_INVALID_DATA; } else { *dMin = m_pLogData[iLocIndex].m_dMin; *dMax = m_pLogData[iLocIndex].m_dMax; *dAvg = m_pLogData[iLocIndex].m_dAvg; *pdwStatus = PDH_CSTATUS_VALID_DATA; }
return ERROR_SUCCESS; }
PDH_STATUS CGraphItem::GetLogEntryTimeStamp( const INT iIndex, LONGLONG& rLastTimeStamp, DWORD *pdwStatus ) { INT iLocIndex = iIndex;
rLastTimeStamp = 0; *pdwStatus = PDH_CSTATUS_INVALID_DATA;
if (m_pLogData == NULL) return PDH_NO_DATA;
if (iIndex < 0 || iIndex >= m_pCtrl->HistoryControl()->nMaxSamples) return PDH_INVALID_ARGUMENT;
if ( ( MIN_TIME_VALUE == *((LONGLONG*)&m_pLogData[iLocIndex].m_LastTimeStamp) ) || ( 0 > *((LONGLONG*)&m_pLogData[iLocIndex].m_dMax) ) ) { *pdwStatus = PDH_CSTATUS_INVALID_DATA; } else { *pdwStatus = PDH_CSTATUS_VALID_DATA; }
rLastTimeStamp = *((LONGLONG*)&m_pLogData[iLocIndex].m_LastTimeStamp);
return ERROR_SUCCESS; }
void CGraphItem::SetLogEntry( const INT iIndex, const double dMin, const double dMax, const double dAvg ) { if (m_pLogData) { m_pLogData[iIndex].m_dMin = dMin; m_pLogData[iIndex].m_dMax = dMax; m_pLogData[iIndex].m_dAvg = dAvg; } }
void CGraphItem::SetLogEntryTimeStamp ( const INT iIndex, const FILETIME& rLastTimeStamp ) { if (m_pLogData) { m_pLogData[iIndex].m_LastTimeStamp.dwLowDateTime = rLastTimeStamp.dwLowDateTime; m_pLogData[iIndex].m_LastTimeStamp.dwHighDateTime = rLastTimeStamp.dwHighDateTime; } }
HRESULT CGraphItem::GetValue( OUT double *pdValue, OUT long *plStat ) /*++
Routine Description:
get_Value returns the most recent sample value for the counter.
Arguments: pdValue - Pointer to returned value dlStatus - Pointer to returned counter status (PDH_CSTATUS_...)
Return Value:
HRESULT
--*/ { DWORD dwTmpStat;
// Convert PDH status to HRESULT
if (HistoryValue(0, pdValue, &dwTmpStat) != 0) return E_FAIL;
*plStat = dwTmpStat; return NOERROR; }
HRESULT CGraphItem::GetStatistics ( OUT double *pdMax, OUT double *pdMin, OUT double *pdAvg, OUT LONG *plStatus ) /*++
Routine Description:
GetStatistics computes the max, min, and average values for the sample history.
Arguments:
pdMax - Pointer to returned max value pdMax - Pointer to returned min value pdMax - Pointer to returned average value plStatus - Pointer to return counter status (PDH_CSTATUS_...)
Return Value:
HRESULT
--*/ { HRESULT hr = NOERROR; PDH_STATUS stat = ERROR_SUCCESS; PDH_STATISTICS StatData; INT iFirst; PHIST_CONTROL pHistCtrl;
// If no data collected, return invalid data status
if ( NULL == m_hCounter ) { *plStatus = PDH_CSTATUS_INVALID_DATA; } else { if (m_pCtrl->IsLogSource()) {
if (m_pLogData) { *pdMax = m_dLogMax; *pdMin = m_dLogMin; *pdAvg = m_dLogAvg;
*plStatus = PDH_CSTATUS_VALID_DATA; } else { *plStatus = PDH_CSTATUS_INVALID_DATA; } } else {
if ( NULL == m_pFmtCtr ) { pHistCtrl = m_pCtrl->HistoryControl();
ZeroMemory ( &StatData, sizeof ( PDH_STATISTICS ) );
// Determine index of oldest sample
if (pHistCtrl->iCurrent < pHistCtrl->nSamples - 1) { iFirst = pHistCtrl->iCurrent + 1; } else { iFirst = 0; }
// Compute statistics over all samples
// Note that max sample count is passed (i.e., buffer length)
// not the number of actual samples
if ( NULL != m_pRawCtr ) { stat = PdhComputeCounterStatistics (m_hCounter, PDH_FMT_DOUBLE | PDH_FMT_NOCAP100, iFirst, pHistCtrl->nMaxSamples, m_pRawCtr, &StatData ); if ( 0 != stat ) hr = E_FAIL; } else { hr = E_FAIL; } if ( SUCCEEDED ( hr ) ) { *plStatus = StatData.mean.CStatus; *pdMin = StatData.min.doubleValue; *pdMax = StatData.max.doubleValue; *pdAvg = StatData.mean.doubleValue; } } else { // Data is cached from property bag.
*pdMax = m_dFmtMax; *pdMin = m_dFmtMin; *pdAvg = m_dFmtAvg; *plStatus = m_lFmtStatus; } } }
return hr; }
void CGraphItem::SetStatistics ( IN double dMax, IN double dMin, IN double dAvg, IN LONG lStatus ) /*++
Routine Description:
SetStatistics sets the max, min, and average values for the sample history. It is used by LoadFromPropertyBag only.
Arguments:
dMax - max value dMin - min value dAvg - average value lStatus - counter status (PDH_CSTATUS_...)
Return Value:
HRESULT
--*/ { if (!m_pCtrl->IsLogSource()) { m_dFmtMax = dMax; m_dFmtMin = dMin; m_dFmtAvg = dAvg; m_lFmtStatus = lStatus; } }
/*
* CGraphItem::QueryInterface * CGraphItem::AddRef * CGraphItem::Release */
STDMETHODIMP CGraphItem::QueryInterface(REFIID riid , LPVOID *ppv) {
*ppv = NULL;
if (riid == IID_ICounterItem || riid == IID_IUnknown) { *ppv = this; } else if (riid == DIID_DICounterItem) { if (m_pImpIDispatch == NULL) { m_pImpIDispatch = new CImpIDispatch(this, this); if (m_pImpIDispatch == NULL) return E_OUTOFMEMORY;
m_pImpIDispatch->SetInterface(DIID_DICounterItem, this); *ppv = m_pImpIDispatch; } else { *ppv = m_pImpIDispatch; } } else { return E_NOINTERFACE; }
((LPUNKNOWN)*ppv)->AddRef(); return NOERROR; }
STDMETHODIMP_(ULONG) CGraphItem::AddRef(void) { return ++m_cRef; }
STDMETHODIMP_(ULONG) CGraphItem::Release(void) { if (--m_cRef == 0) { delete this; return 0; }
return m_cRef; }
// Get/Put Color
STDMETHODIMP CGraphItem::put_Color ( IN OLE_COLOR Color ) { COLORREF rgbColor; HRESULT hReturn;
hReturn = OleTranslateColor(Color, NULL, &rgbColor);
if ( S_OK == hReturn ) { m_rgbColor = rgbColor;
InvalidatePen(); InvalidateBrush(); }
return hReturn; }
STDMETHODIMP CGraphItem::get_Color ( OUT OLE_COLOR *pColor ) { *pColor = m_rgbColor; return NOERROR; }
// Get/Put Width
STDMETHODIMP CGraphItem::put_Width ( IN INT iWidthInPixels) { if ( ( iWidthInPixels > 0 ) && (iWidthInPixels <= NumWidthIndices() ) ) { m_iWidth = iWidthInPixels; InvalidatePen(); return NOERROR; } else { return E_INVALIDARG; } }
STDMETHODIMP CGraphItem::get_Width ( OUT INT* piWidthInPixels ) { *piWidthInPixels = m_iWidth; return NOERROR; }
// Get/Put Line Style
STDMETHODIMP CGraphItem::put_LineStyle ( IN INT iLineStyle ) { if ( ( iLineStyle >= 0 ) && (iLineStyle < NumStyleIndices() ) ) { m_iStyle = iLineStyle; InvalidatePen(); return NOERROR; } else { return E_INVALIDARG; } }
STDMETHODIMP CGraphItem::get_LineStyle ( OUT INT* piLineStyle ) { *piLineStyle = m_iStyle; return NOERROR; }
// Get/Put Scale
STDMETHODIMP CGraphItem::put_ScaleFactor ( IN INT iScaleFactor ) { HRESULT hr = NOERROR;
if ( ( INT_MAX == iScaleFactor ) || ( ( iScaleFactor >= PDH_MIN_SCALE ) && (iScaleFactor <= PDH_MAX_SCALE) ) ) { PDH_COUNTER_INFO ci; DWORD size;
m_iScaleFactor = iScaleFactor;
if ( INT_MAX == iScaleFactor ) { if ( NULL != Handle() ) { size = sizeof(ci); hr = PdhGetCounterInfo ( Handle(), FALSE, &size, &ci);
if (hr == ERROR_SUCCESS) { m_dScale = pow ((double)10.0f, (double)ci.lDefaultScale); m_CounterInfo = ci; } } else { // m_dScale remains at previous value (default=1)
hr = PDH_INVALID_HANDLE; } } else { m_dScale = pow ((double)10.0, (double)iScaleFactor); hr = NOERROR; } } else { hr = E_INVALIDARG; }
return hr; }
STDMETHODIMP CGraphItem::get_ScaleFactor ( OUT INT* piScaleFactor ) { *piScaleFactor = m_iScaleFactor; return NOERROR; }
STDMETHODIMP CGraphItem::get_Path ( OUT BSTR* pstrPath ) { TCHAR achPath[MAX_PATH];
USES_CONVERSION
FormPath(achPath, FALSE); *pstrPath = SysAllocString(T2W(achPath));
if ( NULL == *pstrPath ) { return E_OUTOFMEMORY; } else { return NOERROR; } }
STDMETHODIMP CGraphItem::get_Value ( OUT double* pdValue ) { DWORD dwTmpStat; double dValue;
// Convert PDH status to HRESULT
if (HistoryValue(0, &dValue, &dwTmpStat) != 0) { dValue = -1.0; } else if (!IsSuccessSeverity(dwTmpStat)) { dValue = -1.0; }
*pdValue = dValue;
return NOERROR; }
HPEN CGraphItem::Pen(void) { // if pen not valid
if (m_hPen == NULL) { // create a new one based on current attributes
m_hPen = CreatePen(m_iStyle, m_iWidth, m_rgbColor);
// if can't do it, use a stock object (this can't fail)
if (m_hPen == NULL) m_hPen = (HPEN)GetStockObject(BLACK_PEN); }
return m_hPen; }
HBRUSH CGraphItem::Brush(void) { // if brush is not valid
if (m_hBrush == NULL) { m_hBrush = CreateSolidBrush(m_rgbColor);
if (m_hBrush == NULL) m_hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH); }
return m_hBrush; }
void CGraphItem::InvalidatePen(void) { if (m_hPen != NULL) { DeleteObject(m_hPen); m_hPen = NULL; } }
void CGraphItem::InvalidateBrush(void) { if (m_hBrush != NULL) { DeleteObject(m_hBrush); m_hBrush = NULL; } }
CGraphItem* CGraphItem::Next ( void ) { PCInstanceNode pInstance; PCObjectNode pObject; PCMachineNode pMachine;
if (m_pNextItem) return m_pNextItem; else if ( NULL != m_pInstance->Next()) { pInstance = m_pInstance->Next(); return pInstance->FirstItem(); } else if ( NULL != m_pInstance->m_pObject->Next()) { pObject = m_pInstance->m_pObject->Next(); return pObject->FirstInstance()->FirstItem(); } else if ( NULL != m_pInstance->m_pObject->m_pMachine->Next()) { pMachine = m_pInstance->m_pObject->m_pMachine->Next(); return pMachine->FirstObject()->FirstInstance()->FirstItem(); } else { return NULL; } }
void CGraphItem::FormPath ( LPTSTR pszPath, BOOL fWildCard ) { LPTSTR pszNext = pszPath;
if ( m_fLocalMachine ) pszPath[0] = 0; else lstrcpy ( pszPath, Machine()->Name() ); pszNext = pszNext + lstrlen ( pszPath );
lstrcpy ( pszNext, _T("\\") ); pszNext += 1; // Length of _T("\\");
lstrcpy ( pszNext, Object()->Name() ); pszNext += lstrlen ( Object()->Name() );
if (fWildCard) { lstrcpy ( pszNext,_T("(*)") ); pszNext += 3; // Length of _T("(*)");
} else if ( Instance()->Name()[0] ) { lstrcpy ( pszNext,_T("(")); pszNext += 1; // Length of _T("(");
lstrcpy ( pszNext,Instance()->Name() ); pszNext += lstrlen ( Instance()->Name() );
lstrcpy ( pszNext,_T(")") ); pszNext += 1; // Length of _T("(");
}
lstrcpy ( pszNext, _T("\\") ); pszNext += 1; // Length of _T("\\");
lstrcpy ( pszNext,Counter()->Name() ); }
void CGraphItem::Delete ( BOOL bPropogateUp ) //
// This method just provides a convenient access to the DeleteCounter method
// of the control when you only have a pointer to the graph item.
//
{ m_pCtrl->DeleteCounter(this, bPropogateUp); }
HRESULT CGraphItem::GetNextValue ( TCHAR*& pszNext, double& rdValue ) { HRESULT hr = NOERROR; TCHAR szValue[MAX_DOUBLE_TEXT_SIZE + 1]; INT iDataLen; INT iLen;
VARIANT vValue; rdValue = -1.0;
iDataLen = wcscspn (pszNext, L"\t");
iLen = min ( iDataLen, MAX_DOUBLE_TEXT_SIZE );
lstrcpyn ( szValue, pszNext, iLen + 1 );
szValue[iLen] = L'\0';
VariantInit( &vValue ); vValue.vt = VT_BSTR;
vValue.bstrVal = SysAllocString ( szValue ); hr = VariantChangeTypeEx( &vValue, &vValue, LCID_SCRIPT, VARIANT_NOUSEROVERRIDE, VT_R8 );
if ( SUCCEEDED(hr) ) { rdValue = vValue.dblVal; }
pszNext += iDataLen + 1 ; VariantClear( &vValue );
return hr;
}
BOOL CGraphItem::IsRateCounter ( void ) { BOOL bReturn = FALSE; DWORD dwRateMask = PERF_TYPE_COUNTER | PERF_COUNTER_RATE; DWORD dwFractionMask = PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION;
if ( dwRateMask == ( m_CounterInfo.dwType & dwRateMask ) ) { bReturn = TRUE; } else if ( dwFractionMask == ( m_CounterInfo.dwType & dwFractionMask ) ) { bReturn = TRUE; }
return bReturn; }
|