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.
605 lines
17 KiB
605 lines
17 KiB
//=============================================================================
|
|
// 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);
|
|
}
|