|
|
//=============================================================================
// Contains the functions for the base WMI helper class.
//=============================================================================
#include "stdafx.h"
#include "category.h"
#include "wmiabstraction.h"
#include "resource.h"
#include "dataset.h"
//-----------------------------------------------------------------------------
// Loads the string identified by uiResourceID, and parses it into the columns
// in aColValues. The string should be of the form "www|xxx|yyy|zzz" - this
// will be parsed into two rows: www,xxx and yyy,zzz. Values will be inserted
// into the aColValues array of pointer lists of CMSIValue structs.
//-----------------------------------------------------------------------------
void CWMIHelper::LoadColumnsFromResource(UINT uiResourceID, CPtrList * aColValues, int iColCount) { AfxSetResourceHandle(_Module.GetResourceInstance());
CString strResource; if (strResource.LoadString(uiResourceID)) { CMSIValue * pValue; int iCol = 0;
while (!strResource.IsEmpty()) { pValue = new CMSIValue(strResource.SpanExcluding(_T("|\n")), 0); if (pValue) { ASSERT(!pValue->m_strValue.IsEmpty()); strResource = strResource.Right(strResource.GetLength() - pValue->m_strValue.GetLength() - 1);
aColValues[iCol].AddTail((void *) pValue); iCol += 1; if (iCol == iColCount) iCol = 0; } else strResource.Empty(); } } }
//-----------------------------------------------------------------------------
// Same as the previous, but uses a string instead of a resource ID.
//-----------------------------------------------------------------------------
void CWMIHelper::LoadColumnsFromString(LPCTSTR szColumns, CPtrList * aColValues, int iColCount) { if (szColumns != NULL) { CString strColumns(szColumns); CMSIValue * pValue; int iCol = 0;
while (!strColumns.IsEmpty()) { pValue = new CMSIValue(strColumns.SpanExcluding(_T("|\n")), 0); if (pValue) { ASSERT(!pValue->m_strValue.IsEmpty()); strColumns = strColumns.Right(strColumns.GetLength() - pValue->m_strValue.GetLength() - 1);
aColValues[iCol].AddTail((void *) pValue); iCol += 1; if (iCol == iColCount) iCol = 0; } else strColumns.Empty(); } } }
//-----------------------------------------------------------------------------
// Return the first object of the specified class.
//-----------------------------------------------------------------------------
CWMIObject * CWMIHelper::GetSingleObject(LPCTSTR szClass, LPCTSTR szProperties) { ASSERT(szClass);
CWMIObjectCollection * pCollection = NULL; CWMIObject * pObject = NULL;
if (SUCCEEDED(Enumerate(szClass, &pCollection, szProperties))) { if (FAILED(pCollection->GetNext(&pObject))) pObject = NULL; delete pCollection; }
return pObject; }
//-----------------------------------------------------------------------------
// Delimit the specified number.
//-----------------------------------------------------------------------------
CString DelimitNumber(double dblValue, int iDecimalDigits = 0) { NUMBERFMT fmt; TCHAR szResult[MAX_PATH] = _T(""); TCHAR szDelimiter[4] = _T(","); TCHAR szDecimal[4] = _T(".");
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szDelimiter, 4); GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimal, 4);
memset(&fmt, 0, sizeof(NUMBERFMT)); fmt.Grouping = 3; fmt.lpDecimalSep = (iDecimalDigits) ? szDecimal : _T(""); fmt.NumDigits = iDecimalDigits; fmt.lpThousandSep = szDelimiter;
CString strValue; CString strFormatString; strFormatString.Format(_T("%%.%df"), iDecimalDigits); strValue.Format(strFormatString, dblValue);
// GetNumberFormat requires the decimal to be a '.', while CString::Format
// uses the locale value. So we need to go back and replace it.
StringReplace(strValue, szDecimal, _T(".")); GetNumberFormat(LOCALE_USER_DEFAULT, 0, strValue, &fmt, szResult, MAX_PATH);
return CString(szResult); }
//-----------------------------------------------------------------------------
// Return the requested value from the object, as a string and/or a DWORD.
// Use the chFormat flag to determine how to format the results.
//
// The return result is the actual format character to use for displaying the
// results in a string.
//
// TBD - do something better with the HRESULTs returned.
//-----------------------------------------------------------------------------
CString gstrYes; // global string "yes" (will be localized)
CString gstrNo; // global string "no" (will be localized)
CString gstrBytes; // global string "bytes" (will be localized)
CString gstrKB; // global string "KB" (will be localized)
CString gstrMB; // global string "MB" (will be localized)
CString gstrGB; // global string "GB" (will be localized)
CString gstrTB; // global string "TB" (will be localized)
HRESULT CWMIObject::GetInterpretedValue(LPCTSTR szProperty, LPCTSTR szFormat, TCHAR chFormat, CString * pstrValue, DWORD * pdwValue) { HRESULT hr = E_FAIL; CString strValue(_T("")); DWORD dwValue = 0;
::AfxSetResourceHandle(_Module.GetResourceInstance());
switch (chFormat) { case _T('s'): case _T('u'): case _T('l'): { hr = GetValueString(szProperty, &strValue); if (SUCCEEDED(hr)) { if (chFormat == _T('u')) strValue.MakeUpper(); else if (chFormat == _T('l')) strValue.MakeLower(); strValue.TrimRight(); } } break;
case _T('v'): { hr = GetValueValueMap(szProperty, &strValue); } break;
case _T('d'): case _T('x'): { hr = GetValueDWORD(szProperty, &dwValue); if (SUCCEEDED(hr)) { strValue.Format(szFormat, dwValue); } } break;
case _T('f'): { double dblValue; hr = GetValueDoubleFloat(szProperty, &dblValue); if (SUCCEEDED(hr)) { strValue.Format(szFormat, dblValue); dwValue = (DWORD) dblValue; } } break;
case _T('b'): { if (gstrYes.IsEmpty()) gstrYes.LoadString(IDS_YES);
if (gstrNo.IsEmpty()) gstrNo.LoadString(IDS_NO);
hr = GetValueDWORD(szProperty, &dwValue); if (SUCCEEDED(hr)) { strValue = (dwValue) ? gstrYes : gstrNo; } } break;
case _T('w'): case _T('y'): case _T('z'): { if (gstrBytes.IsEmpty()) gstrBytes.LoadString(IDS_BYTES);
if (gstrKB.IsEmpty()) gstrKB.LoadString(IDS_KB);
if (gstrMB.IsEmpty()) gstrMB.LoadString(IDS_MB);
if (gstrGB.IsEmpty()) gstrGB.LoadString(IDS_GB);
if (gstrTB.IsEmpty()) gstrTB.LoadString(IDS_TB);
double dblValue; hr = GetValueDoubleFloat(szProperty, &dblValue); if (SUCCEEDED(hr)) { CString strFormattedNumber;
dwValue = (DWORD) dblValue; // TBD potential loss of digits
if (chFormat == _T('w')) strFormattedNumber = DelimitNumber(dblValue); else { int iDivTimes = (chFormat == _T('y')) ? 1 : 0; double dblWorking(dblValue); for (; iDivTimes <= 4 && dblWorking >= 1024.0; iDivTimes++) dblWorking /= 1024.0;
strFormattedNumber = DelimitNumber(dblWorking, (iDivTimes) ? 2 : 0); switch (iDivTimes) { case 0: strFormattedNumber += _T(" ") + gstrBytes; break;
case 1: strFormattedNumber += _T(" ") + gstrKB; break;
case 2: strFormattedNumber += _T(" ") + gstrMB; break;
case 3: strFormattedNumber += _T(" ") + gstrGB; break;
case 4: strFormattedNumber += _T(" ") + gstrTB; break; }
if (chFormat == _T('z') && iDivTimes) strFormattedNumber += _T(" (") + DelimitNumber(dblValue) + _T(" ") + gstrBytes + _T(")"); }
strValue = strFormattedNumber; } } break;
case _T('t'): { COleDateTime oledatetime; SYSTEMTIME systimeValue;
hr = GetValueTime(szProperty, &systimeValue); oledatetime = (COleDateTime) systimeValue; if (SUCCEEDED(hr)) { dwValue = (DWORD)(DATE)oledatetime;
// Try to get the date in the localized format.
strValue.Empty(); TCHAR szBuffer[MAX_PATH]; // seems plenty big
if (::GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systimeValue, NULL, szBuffer, MAX_PATH)) { strValue = szBuffer; if (::GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &systimeValue, NULL, szBuffer, MAX_PATH)) strValue += CString(_T(" ")) + CString(szBuffer); }
// Fall back on our old (partially incorrect) method.
if (strValue.IsEmpty()) strValue = oledatetime.Format(0, LOCALE_USER_DEFAULT); } } break;
case _T('c'): { COleDateTime oledatetime; SYSTEMTIME systimeValue;
hr = GetValueTime(szProperty, &systimeValue); oledatetime = (COleDateTime) systimeValue; if (SUCCEEDED(hr)) { dwValue = (DWORD)(DATE)oledatetime;
// Try to get the date in the localized format.
strValue.Empty(); TCHAR szBuffer[MAX_PATH]; // seems plenty big
if (::GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systimeValue, NULL, szBuffer, MAX_PATH)) strValue = szBuffer;
// Fall back on our old (partially incorrect) method.
if (strValue.IsEmpty()) strValue = oledatetime.Format(0, LOCALE_USER_DEFAULT); } } break;
case _T('a'): { hr = GetValueString(szProperty, &strValue); if (SUCCEEDED(hr)) { // strValue contains a string locale ID (like "0409"). Convert it into
// and actual LCID.
LCID lcid = (LCID) _tcstoul(strValue, NULL, 16); TCHAR szCountry[MAX_PATH]; if (GetLocaleInfo(lcid, LOCALE_SCOUNTRY, szCountry, MAX_PATH)) strValue = szCountry; } } break;
default: break; // Just continue with the loop.
}
if (SUCCEEDED(hr)) { if (pstrValue) { if (chFormat == _T('d') || chFormat == _T('x') || chFormat == _T('f')) *pstrValue = strValue; else { CString strFormat(szFormat);
int iPercent = strFormat.Find(_T("%")); int iLength = strFormat.GetLength(); if (iPercent != -1) { while (iPercent < iLength && strFormat[iPercent] != chFormat) iPercent++;
if (iPercent < iLength) { strFormat.SetAt(iPercent, _T('s')); pstrValue->Format(strFormat, strValue); } } } }
if (pdwValue) *pdwValue = dwValue; } else { if (pstrValue) *pstrValue = GetMSInfoHRESULTString(hr); if (pdwValue) *pdwValue = 0; }
return hr; }
//-----------------------------------------------------------------------------
// These functions implement features found in the new versions of MFC (new
// than what we're currently building with).
//-----------------------------------------------------------------------------
int StringFind(CString & str, LPCTSTR szLookFor, int iStartFrom) { CString strWorking(str.Right(str.GetLength() - iStartFrom)); int iFind = strWorking.Find(szLookFor);
if (iFind != -1) iFind += iStartFrom;
return iFind; }
//-----------------------------------------------------------------------------
// Process the specified string. It will contain a format string with one
// or more flags (flags specific to MSInfo). We need to replace is flag with
// a properly formatted value from pObject, determined by the next property
// in pstrProperties.
//-----------------------------------------------------------------------------
BOOL ProcessColumnString(CMSIValue * pValue, CWMIObject * pObject, CString * pstrProperties) { CString strPropertyValue, strProperty, strFragment; CString strResults(_T("")); CString strFormatString(pValue->m_strValue); DWORD dwResults; BOOL fAdvanced = FALSE; BOOL fAllPiecesFailed = TRUE; HRESULT hr = S_OK;
while (!strFormatString.IsEmpty() && SUCCEEDED(hr)) { // Get the next fragment of the format string with a single format specifier.
int iPercent = strFormatString.Find(_T("%")); if (iPercent == -1) { strResults += strFormatString; break; }
int iSecondPercent = StringFind(strFormatString, _T("%"), iPercent + 1); if (iSecondPercent == -1) { strFragment = strFormatString; strFormatString.Empty(); } else { strFragment = strFormatString.Left(iSecondPercent); strFormatString = strFormatString.Right(strFormatString.GetLength() - iSecondPercent); }
// Find the format character for this fragment.
TCHAR chFormat; do chFormat = strFragment[++iPercent]; while (!_istalpha(chFormat));
// Get the property name for this fragment.
int iComma = pstrProperties->Find(_T(",")); if (iComma != -1) { strProperty = pstrProperties->Left(iComma); *pstrProperties = pstrProperties->Right(pstrProperties->GetLength() - iComma - 1); } else { strProperty = *pstrProperties; pstrProperties->Empty(); } strProperty.TrimLeft(); strProperty.TrimRight();
if (strProperty.Left(11) == CString(_T("MSIAdvanced"))) { fAdvanced = TRUE; strProperty = strProperty.Right(strProperty.GetLength() - 11); }
// Get the actual value the property and add it to the string.
hr = pObject->GetInterpretedValue(strProperty, strFragment, chFormat, &strPropertyValue, &dwResults); if (SUCCEEDED(hr)) { fAllPiecesFailed = FALSE; strResults += strPropertyValue; } else strResults += GetMSInfoHRESULTString(hr); }
if (!fAllPiecesFailed) { pValue->m_strValue = strResults; pValue->m_dwValue = dwResults; } else { pValue->m_strValue = GetMSInfoHRESULTString(hr); pValue->m_dwValue = 0; } pValue->m_fAdvanced = fAdvanced;
return TRUE; }
//-----------------------------------------------------------------------------
// A general purpose function to add the contents of object pObject to the
// columns, based on the properties in szProperties and the string referenced
// by uiColumns.
//-----------------------------------------------------------------------------
void CWMIHelper::AddObjectToOutput(CPtrList * aColValues, int iColCount, CWMIObject * pObject, LPCTSTR szProperties, UINT uiColumns) { POSITION aPositions[32]; // should never be more than 32 columns
ASSERT(iColCount < 32);
CString strProperties(szProperties);
// Save the starting position for the new entries we're adding from the resoure.
int iColListStart = (int)aColValues[0].GetCount(); LoadColumnsFromResource(uiColumns, aColValues, iColCount);
// Look through each of the new cells. For each string in a cell, if we
// find a formatting flag (like %s), get the next property out of the
// property list and format the string.
for (int iCol = 0; iCol < iColCount; iCol++) aPositions[iCol] = aColValues[iCol].FindIndex(iColListStart);
while (aPositions[0]) for (iCol = 0; iCol < iColCount; iCol++) { ASSERT(aPositions[iCol]); if (aPositions[iCol]) { CMSIValue * pValue = (CMSIValue *) aColValues[iCol].GetNext(aPositions[iCol]); if (pValue && pValue->m_strValue.Find(_T("%")) != -1) ProcessColumnString(pValue, pObject, &strProperties); } } }
//-----------------------------------------------------------------------------
// Same as previous, but takes a string instead of a resource ID.
//-----------------------------------------------------------------------------
void CWMIHelper::AddObjectToOutput(CPtrList * aColValues, int iColCount, CWMIObject * pObject, LPCTSTR szProperties, LPCTSTR szColumns) { POSITION aPositions[32]; // should never be more than 32 columns
ASSERT(iColCount < 32);
CString strProperties(szProperties);
// Save the starting position for the new entries we're adding from the resoure.
int iColListStart = (int)aColValues[0].GetCount(); LoadColumnsFromString(szColumns, aColValues, iColCount);
// Look through each of the new cells. For each string in a cell, if we
// find a formatting flag (like %s), get the next property out of the
// property list and format the string.
for (int iCol = 0; iCol < iColCount; iCol++) aPositions[iCol] = aColValues[iCol].FindIndex(iColListStart);
while (aPositions[0]) for (iCol = 0; iCol < iColCount; iCol++) { ASSERT(aPositions[iCol]); if (aPositions[iCol]) { CMSIValue * pValue = (CMSIValue *) aColValues[iCol].GetNext(aPositions[iCol]); if (pValue && pValue->m_strValue.Find(_T("%")) != -1) ProcessColumnString(pValue, pObject, &strProperties); } } }
void CWMIHelper::AppendBlankLine(CPtrList * aColValues, int iColCount, BOOL fOnlyIfNotEmpty) { if (aColValues[0].GetCount() || fOnlyIfNotEmpty == FALSE) for (int iCol = 0; iCol < iColCount; iCol++) AppendCell(aColValues[iCol], _T(""), 0); }
void CWMIHelper::AppendCell(CPtrList & listColumns, const CString & strValue, DWORD dwValue, BOOL fAdvanced) { CMSIValue * pValue = new CMSIValue(strValue, dwValue, fAdvanced); if (pValue) listColumns.AddTail((void *) pValue); }
|