|
|
//=============================================================================
// File: refresh.cpp
// Author: a-jammar
// Covers: CRefreshFunctions
//
// Copyright (c) 1998-1999 Microsoft Corporation
//
// This file contains functions useful for refreshing the internal data
// categories. The CRefreshFunctions class just has static functions, and
// is used to group the functions together.
//=============================================================================
#include "stdafx.h"
#include "gather.h"
#include "gathint.h"
#include "resrc1.h"
//-----------------------------------------------------------------------------
// This method takes the information in a GATH_FIELD struct and uses it to
// generate a current GATH_VALUE struct.
//-----------------------------------------------------------------------------
BOOL CRefreshFunctions::RefreshValue(CDataGatherer * pGatherer, GATH_VALUE * pVal, GATH_FIELD * pField) { TCHAR szFormatFragment[MAX_PATH]; const TCHAR *pSourceChar; TCHAR *pDestinationChar; TCHAR cFormat = _T('\0'); BOOL fReadPercent = FALSE; BOOL fReturnValue = TRUE; CString strResult, strTemp; int iArgNumber = 0; DWORD dwValue = 0L;
// Process the format string. Because of the difficulty caused by having
// variable number of arguments to be inserted (like printf), we'll need
// to break the format string into chunks and do the sprintf function
// for each format flag we come across.
pSourceChar = (LPCTSTR) pField->m_strFormat; pDestinationChar = szFormatFragment;
while (*pSourceChar) { if (fReadPercent) { // If we read a percent sign, we should be looking for a valid flag.
// We are using some additional flags to printf (and not supporting
// others). If we read another percent, just insert a single percent.
switch (*pSourceChar) { case _T('%'): fReadPercent = FALSE; break;
case _T('b'): case _T('B'): case _T('l'): case _T('L'): case _T('u'): case _T('U'): case _T('s'): case _T('S'): fReadPercent = FALSE; cFormat = *pSourceChar; *pDestinationChar = _T('s'); break;
case _T('t'): case _T('T'): fReadPercent = FALSE; cFormat = *pSourceChar; *pDestinationChar = _T('s'); break;
case _T('x'): case _T('X'): case _T('d'): case _T('D'): fReadPercent = FALSE; cFormat = _T('d'); *pDestinationChar = *pSourceChar; break;
case _T('q'): case _T('Q'): fReadPercent = FALSE; cFormat = _T('q'); *pDestinationChar = _T('s'); break;
case _T('z'): case _T('Z'): fReadPercent = FALSE; cFormat = _T('z'); *pDestinationChar = _T('s'); break;
case _T('y'): case _T('Y'): fReadPercent = FALSE; cFormat = _T('y'); *pDestinationChar = _T('s'); break;
case _T('v'): case _T('V'): fReadPercent = FALSE; cFormat = _T('v'); *pDestinationChar = _T('s'); break;
case _T('f'): case _T('F'): fReadPercent = FALSE; cFormat = *pSourceChar; *pDestinationChar = *pSourceChar; break;
default: *pDestinationChar = *pSourceChar; } } else if (*pSourceChar == _T('%')) { *pDestinationChar = _T('%'); fReadPercent = TRUE; } else *pDestinationChar = *pSourceChar;
pSourceChar++; pDestinationChar++;
// If a format flag is set or we are at the end of the source string,
// then we have a complete fragment and we should produce some output,
// which will be concatenated to the strResult string.
if (cFormat || *pSourceChar == _T('\0')) { *pDestinationChar = _T('\0'); if (cFormat) { // Based on the format type, get a value from the provider for
// the next argument. Format the result using the formatting
// fragment we extracted, and concatenate it.
if (GetValue(pGatherer, cFormat, szFormatFragment, strTemp, dwValue, pField, iArgNumber++)) { strResult += strTemp; cFormat = _T('\0'); } else { strResult = strTemp; break; } } else { // There was no format flag, but we are at the end of the string.
// Add the fragment we got to the result string.
strResult += CString(szFormatFragment); }
pDestinationChar = szFormatFragment; } }
// Assign the values we generated to the GATH_VALUE structure. Important note:
// the dwValue variable will only have ONE value, even though multiple values
// might have been generated to build the strResult string. Only the last
// value will be saved in dwValue. This is OK, because this value is only
// used for sorting a column when the column is marked for non-lexical sorting.
// In that case, there should be only one value used to generat the string.
pVal->m_strText = strResult; pVal->m_dwValue = dwValue;
return fReturnValue; }
//-----------------------------------------------------------------------------
// Return a string with delimiters added for the number.
//-----------------------------------------------------------------------------
CString DelimitNumber(double dblValue) { NUMBERFMT fmt; TCHAR szResult[MAX_PATH] = _T(""); TCHAR szDelimiter[4] = _T(",");
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szDelimiter, 4);
memset(&fmt, 0, sizeof(NUMBERFMT)); fmt.Grouping = 3; fmt.lpDecimalSep = _T(""); // doesn't matter - there aren't decimal digits
fmt.lpThousandSep = szDelimiter;
CString strValue; strValue.Format(_T("%.0f"), dblValue); GetNumberFormat(LOCALE_USER_DEFAULT, 0, strValue, &fmt, szResult, MAX_PATH);
return CString(szResult); }
//-----------------------------------------------------------------------------
// This method gets a single value from the provider, based on the format
// character from the template file. It formats the results using the
// format string szFormatFragment, which should only take one argument.
//-----------------------------------------------------------------------------
BOOL CRefreshFunctions::GetValue(CDataGatherer *pGatherer, TCHAR cFormat, TCHAR *szFormatFragment, CString &strResult, DWORD &dwResult, GATH_FIELD *pField, int iArgNumber) { CString strTemp; COleDateTime datetimeTemp; double dblValue;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
strResult.Empty(); dwResult = 0L;
if (!pField->m_strSource.IsEmpty() && pField->m_strSource.CompareNoCase(CString(STATIC_SOURCE)) != 0) { CDataProvider * pProvider = pGatherer->GetProvider();
if (!pProvider) return FALSE;
// Find the right argument for this formatting (indicated by the iArgNumber
// parameter.
GATH_VALUE * pArg = pField->m_pArgs; while (iArgNumber && pArg) { pArg = pArg->m_pNext; iArgNumber--; }
if (pArg == NULL) return FALSE;
switch (cFormat) { case 'b': case 'B': // This is a boolean type. Show either true or false, depending on
// the numeric value.
if (pProvider->QueryValueDWORD(pField->m_strSource, pArg->m_strText, dwResult, strTemp)) { strTemp = (dwResult) ? pProvider->m_strTrue : pProvider->m_strFalse; strResult.Format(szFormatFragment, strTemp); return TRUE; } else { strResult = strTemp; return FALSE; } break;
case 'd': case 'D': // This is the numeric type.
if (pProvider->QueryValueDWORD(pField->m_strSource, pArg->m_strText, dwResult, strTemp)) { strResult.Format(szFormatFragment, dwResult); return TRUE; } else { strResult = strTemp; return FALSE; } break;
case 'f': case 'F': // This is the double floating point type.
if (pProvider->QueryValueDoubleFloat(pField->m_strSource, pArg->m_strText, dblValue, strTemp)) { strResult.Format(szFormatFragment, dblValue); return TRUE; } else { strResult = strTemp; return FALSE; } break;
case 't': case 'T': // This is the OLE date and time type. Format the date and time into the
// string result, and return the date part in the DWORD (the day number is
// to the left of the decimal in the DATE type).
if (pProvider->QueryValueDateTime(pField->m_strSource, pArg->m_strText, datetimeTemp, strTemp)) { strResult = datetimeTemp.Format(); dwResult = (DWORD)(DATE)datetimeTemp; return TRUE; } else { strResult = strTemp; return FALSE; } break;
case 'l': case 'L': // This is a string type, with the string converted to lower case.
if (pProvider->QueryValue(pField->m_strSource, pArg->m_strText, strTemp)) { strTemp.MakeLower(); strResult.Format(szFormatFragment, strTemp); return TRUE; } else { strResult = strTemp; return FALSE; } break;
case 'u': case 'U': // This is a string type, with the string converted to upper case.
if (pProvider->QueryValue(pField->m_strSource, pArg->m_strText, strTemp)) { strTemp.MakeUpper(); strResult.Format(szFormatFragment, strTemp); return TRUE; } else { strResult = strTemp; return FALSE; } break;
case 's': case 'S': // This is the string type (string is the default type).
if (pProvider->QueryValue(pField->m_strSource, pArg->m_strText, strTemp)) { strResult.Format(szFormatFragment, strTemp);
// We only need to do this when the value returned is a number
// and is going in a column that we want to sort numerically.
// This won't break the case where a numeric string is to be
// sorted as a string because dwResult will be ignored.
if (iswdigit( strTemp[0])) dwResult = _ttol( (LPCTSTR)strTemp);
return TRUE; } else { strResult = strTemp; return FALSE; } break;
case 'q': case 'Q': // This is a specialized type for the Win32_BIOS class. We want to show
// the "Version" property - if it isn't there, then we want to show
// the "Name" property and "ReleaseDate" properties concatenated
// together.
if (pProvider->QueryValue(pField->m_strSource, CString(_T("Version")), strTemp)) { strResult = strTemp; return TRUE; } else { if (pProvider->QueryValue(pField->m_strSource, CString(_T("Name")), strTemp)) strResult = strTemp;
if (pProvider->QueryValueDateTime(pField->m_strSource, CString(_T("ReleaseDate")), datetimeTemp, strTemp)) strResult += CString(_T(" ")) + datetimeTemp.Format();
return TRUE; } break;
case 'z': case 'Z': // This is a specialized size type, where the value is a numeric count
// of bytes. We want to convert it into the best possible units for
// display (for example, display "4.20 MB (4,406,292 bytes)").
if (pProvider->QueryValueDoubleFloat(pField->m_strSource, pArg->m_strText, dblValue, strTemp)) { double dValue = (double) dblValue; DWORD dwDivisor = 1;
// Reduce the dValue to the smallest possible number (with a larger unit).
while (dValue > 1024.0 && dwDivisor < (1024 * 1024 * 1024)) { dwDivisor *= 1024; dValue /= 1024.0; }
if (dwDivisor == 1) strResult.Format(IDS_SIZEBYTES, DelimitNumber(dblValue)); else if (dwDivisor == (1024)) strResult.Format(IDS_SIZEKB_BYTES, dValue, DelimitNumber(dblValue)); else if (dwDivisor == (1024 * 1024)) strResult.Format(IDS_SIZEMB_BYTES, dValue, DelimitNumber(dblValue)); else if (dwDivisor == (1024 * 1024 * 1024)) strResult.Format(IDS_SIZEGB_BYTES, dValue, DelimitNumber(dblValue));
dwResult = (DWORD) dblValue; // So we can sort on this value (bug 391127).
} else { strResult = strTemp; return FALSE; } break;
case 'y': case 'Y': // This is a specialized size type, where the value is a numeric count
// of bytes, already in KB. If it's big enough, show it in MB or GB.
if (pProvider->QueryValueDoubleFloat(pField->m_strSource, pArg->m_strText, dblValue, strTemp)) { strResult.Format(IDS_SIZEKB, DelimitNumber(dblValue)); dwResult = (DWORD) dblValue; // So we can sort on this value (bug 391127).
} else { strResult = strTemp; return FALSE; } break;
case 'v': case 'V': // This is a specialized type, assumed to be an LCID (locale ID). Show the
// locale.
if (pProvider->QueryValue(pField->m_strSource, pArg->m_strText, strTemp)) { // strTemp contains a string locale ID (like "0409"). Convert it into
// and actual LCID.
LCID lcid = (LCID) _tcstoul(strTemp, NULL, 16); TCHAR szCountry[MAX_PATH]; if (GetLocaleInfo(lcid, LOCALE_SCOUNTRY, szCountry, MAX_PATH)) strResult = szCountry; else strResult = strTemp; } else { strResult = strTemp; return FALSE; } break;
default: ASSERT(FALSE); // unknown formatting flag
return TRUE; } }
return FALSE; }
//-----------------------------------------------------------------------------
// Refresh the list of columns based on the list of column fields. We'll also
// need to set the number of columns.
//-----------------------------------------------------------------------------
BOOL CRefreshFunctions::RefreshColumns(CDataGatherer * pGatherer, INTERNAL_CATEGORY * pInternal) { ASSERT(pInternal); GATH_FIELD * pField = pInternal->m_pColSpec;
// Count the number of columns.
pInternal->m_dwColCount = 0; while (pField) { pInternal->m_dwColCount++; pField = pField->m_pNext; }
// Allocate the array of column values.
if (pInternal->m_aCols) delete [] pInternal->m_aCols;
if (pInternal->m_dwColCount == 0) return TRUE;
pInternal->m_aCols = new GATH_VALUE[pInternal->m_dwColCount]; if (pInternal->m_aCols == NULL) return FALSE;
// Finally get each column name based on the column field.
pField = pInternal->m_pColSpec; for (DWORD dwIndex = 0; dwIndex < pInternal->m_dwColCount; dwIndex++) { if (!RefreshValue(pGatherer, &pInternal->m_aCols[dwIndex], pField)) return FALSE; pField = pField->m_pNext; }
return TRUE; }
//-----------------------------------------------------------------------------
// Refresh the list of lines based on the list of line fields. We'll also
// need to set the number of lines. The list of lines is generated based on
// the pLineSpec pointer and dwColumns variables. The generated lines are
// returned in the listLinePtrs parameter.
//-----------------------------------------------------------------------------
BOOL CRefreshFunctions::RefreshLines(CDataGatherer * pGatherer, GATH_LINESPEC * pLineSpec, DWORD dwColumns, CPtrList & listLinePtrs, volatile BOOL * pfCancel) { BOOL bReturn = TRUE;
// Traverse the list of line specifiers to generate the list of lines.
GATH_LINESPEC * pCurrentLineSpec = pLineSpec; GATH_LINE * pLine = NULL;
while (pCurrentLineSpec && (pfCancel == NULL || *pfCancel == FALSE)) { // Check if the current line spec is for a single line or an enumerated group.
if (pCurrentLineSpec->m_strEnumerateClass.IsEmpty() || pCurrentLineSpec->m_strEnumerateClass.CompareNoCase(CString(STATIC_SOURCE)) == 0) { // This is for a single line. Allocate a new line structure and fill it
// in with the data generated from the line spec.
pLine = new GATH_LINE; if (pLine == NULL) { bReturn = FALSE; break; }
if (RefreshOneLine(pGatherer, pLine, pCurrentLineSpec, dwColumns)) listLinePtrs.AddTail((void *) pLine); else { bReturn = FALSE; break; } } else { // This line represents an enumerated group of lines. We need to enumerate
// the class and call RefreshLines for the group of enumerated lines, once
// for each class instance.
CDataProvider * pProvider = pGatherer->GetProvider(); if (pProvider && pProvider->ResetClass(pCurrentLineSpec->m_strEnumerateClass, pCurrentLineSpec->m_pConstraintFields)) do { if (!RefreshLines(pGatherer, pCurrentLineSpec->m_pEnumeratedGroup, dwColumns, listLinePtrs)) break; } while (pProvider->EnumClass(pCurrentLineSpec->m_strEnumerateClass, pCurrentLineSpec->m_pConstraintFields)); }
pCurrentLineSpec = pCurrentLineSpec->m_pNext; }
if (pfCancel && *pfCancel) return FALSE;
// If there was a failure generating the lines, clean up after ourselves.
if (!bReturn) { if (pLine) delete pLine;
for (POSITION pos = listLinePtrs.GetHeadPosition(); pos != NULL;) { pLine = (GATH_LINE *) listLinePtrs.GetNext(pos) ; if (pLine) delete pLine; }
listLinePtrs.RemoveAll(); return FALSE; }
return TRUE; }
//-----------------------------------------------------------------------------
// Refresh a line based on a line spec.
//-----------------------------------------------------------------------------
BOOL CRefreshFunctions::RefreshOneLine(CDataGatherer * pGatherer, GATH_LINE * pLine, GATH_LINESPEC * pLineSpec, DWORD dwColCount) { // Allocate the new array of values.
if (pLine->m_aValue) delete [] pLine->m_aValue;
pLine->m_aValue = new GATH_VALUE[dwColCount]; if (pLine->m_aValue == NULL) return FALSE;
// Set the data complexity for the line based on the line spec.
pLine->m_datacomplexity = pLineSpec->m_datacomplexity;
// Compute each of the values for the fields.
GATH_FIELD * pField = pLineSpec->m_pFields; for (DWORD dwIndex = 0; dwIndex < dwColCount; dwIndex++) { if (pField == NULL) return FALSE; if (!RefreshValue(pGatherer, &pLine->m_aValue[dwIndex], pField)) return FALSE; pField = pField->m_pNext; }
return TRUE; }
|