Source code of Windows XP (NT5)
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.

621 lines
17 KiB

  1. //=============================================================================
  2. // File: refresh.cpp
  3. // Author: a-jammar
  4. // Covers: CRefreshFunctions
  5. //
  6. // Copyright (c) 1998-1999 Microsoft Corporation
  7. //
  8. // This file contains functions useful for refreshing the internal data
  9. // categories. The CRefreshFunctions class just has static functions, and
  10. // is used to group the functions together.
  11. //=============================================================================
  12. #include "stdafx.h"
  13. #include "gather.h"
  14. #include "gathint.h"
  15. #include "resrc1.h"
  16. //-----------------------------------------------------------------------------
  17. // This method takes the information in a GATH_FIELD struct and uses it to
  18. // generate a current GATH_VALUE struct.
  19. //-----------------------------------------------------------------------------
  20. BOOL CRefreshFunctions::RefreshValue(CDataGatherer * pGatherer, GATH_VALUE * pVal, GATH_FIELD * pField)
  21. {
  22. TCHAR szFormatFragment[MAX_PATH];
  23. const TCHAR *pSourceChar;
  24. TCHAR *pDestinationChar;
  25. TCHAR cFormat = _T('\0');
  26. BOOL fReadPercent = FALSE;
  27. BOOL fReturnValue = TRUE;
  28. CString strResult, strTemp;
  29. int iArgNumber = 0;
  30. DWORD dwValue = 0L;
  31. // Process the format string. Because of the difficulty caused by having
  32. // variable number of arguments to be inserted (like printf), we'll need
  33. // to break the format string into chunks and do the sprintf function
  34. // for each format flag we come across.
  35. pSourceChar = (LPCTSTR) pField->m_strFormat;
  36. pDestinationChar = szFormatFragment;
  37. while (*pSourceChar)
  38. {
  39. if (fReadPercent)
  40. {
  41. // If we read a percent sign, we should be looking for a valid flag.
  42. // We are using some additional flags to printf (and not supporting
  43. // others). If we read another percent, just insert a single percent.
  44. switch (*pSourceChar)
  45. {
  46. case _T('%'):
  47. fReadPercent = FALSE;
  48. break;
  49. case _T('b'): case _T('B'):
  50. case _T('l'): case _T('L'):
  51. case _T('u'): case _T('U'):
  52. case _T('s'): case _T('S'):
  53. fReadPercent = FALSE;
  54. cFormat = *pSourceChar;
  55. *pDestinationChar = _T('s');
  56. break;
  57. case _T('t'): case _T('T'):
  58. fReadPercent = FALSE;
  59. cFormat = *pSourceChar;
  60. *pDestinationChar = _T('s');
  61. break;
  62. case _T('x'): case _T('X'):
  63. case _T('d'): case _T('D'):
  64. fReadPercent = FALSE;
  65. cFormat = _T('d');
  66. *pDestinationChar = *pSourceChar;
  67. break;
  68. case _T('q'): case _T('Q'):
  69. fReadPercent = FALSE;
  70. cFormat = _T('q');
  71. *pDestinationChar = _T('s');
  72. break;
  73. case _T('z'): case _T('Z'):
  74. fReadPercent = FALSE;
  75. cFormat = _T('z');
  76. *pDestinationChar = _T('s');
  77. break;
  78. case _T('y'): case _T('Y'):
  79. fReadPercent = FALSE;
  80. cFormat = _T('y');
  81. *pDestinationChar = _T('s');
  82. break;
  83. case _T('v'): case _T('V'):
  84. fReadPercent = FALSE;
  85. cFormat = _T('v');
  86. *pDestinationChar = _T('s');
  87. break;
  88. case _T('f'): case _T('F'):
  89. fReadPercent = FALSE;
  90. cFormat = *pSourceChar;
  91. *pDestinationChar = *pSourceChar;
  92. break;
  93. default:
  94. *pDestinationChar = *pSourceChar;
  95. }
  96. }
  97. else if (*pSourceChar == _T('%'))
  98. {
  99. *pDestinationChar = _T('%');
  100. fReadPercent = TRUE;
  101. }
  102. else
  103. *pDestinationChar = *pSourceChar;
  104. pSourceChar++;
  105. pDestinationChar++;
  106. // If a format flag is set or we are at the end of the source string,
  107. // then we have a complete fragment and we should produce some output,
  108. // which will be concatenated to the strResult string.
  109. if (cFormat || *pSourceChar == _T('\0'))
  110. {
  111. *pDestinationChar = _T('\0');
  112. if (cFormat)
  113. {
  114. // Based on the format type, get a value from the provider for
  115. // the next argument. Format the result using the formatting
  116. // fragment we extracted, and concatenate it.
  117. if (GetValue(pGatherer, cFormat, szFormatFragment, strTemp, dwValue, pField, iArgNumber++))
  118. {
  119. strResult += strTemp;
  120. cFormat = _T('\0');
  121. }
  122. else
  123. {
  124. strResult = strTemp;
  125. break;
  126. }
  127. }
  128. else
  129. {
  130. // There was no format flag, but we are at the end of the string.
  131. // Add the fragment we got to the result string.
  132. strResult += CString(szFormatFragment);
  133. }
  134. pDestinationChar = szFormatFragment;
  135. }
  136. }
  137. // Assign the values we generated to the GATH_VALUE structure. Important note:
  138. // the dwValue variable will only have ONE value, even though multiple values
  139. // might have been generated to build the strResult string. Only the last
  140. // value will be saved in dwValue. This is OK, because this value is only
  141. // used for sorting a column when the column is marked for non-lexical sorting.
  142. // In that case, there should be only one value used to generat the string.
  143. pVal->m_strText = strResult;
  144. pVal->m_dwValue = dwValue;
  145. return fReturnValue;
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Return a string with delimiters added for the number.
  149. //-----------------------------------------------------------------------------
  150. CString DelimitNumber(double dblValue)
  151. {
  152. NUMBERFMT fmt;
  153. TCHAR szResult[MAX_PATH] = _T("");
  154. TCHAR szDelimiter[4] = _T(",");
  155. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szDelimiter, 4);
  156. memset(&fmt, 0, sizeof(NUMBERFMT));
  157. fmt.Grouping = 3;
  158. fmt.lpDecimalSep = _T(""); // doesn't matter - there aren't decimal digits
  159. fmt.lpThousandSep = szDelimiter;
  160. CString strValue;
  161. strValue.Format(_T("%.0f"), dblValue);
  162. GetNumberFormat(LOCALE_USER_DEFAULT, 0, strValue, &fmt, szResult, MAX_PATH);
  163. return CString(szResult);
  164. }
  165. //-----------------------------------------------------------------------------
  166. // This method gets a single value from the provider, based on the format
  167. // character from the template file. It formats the results using the
  168. // format string szFormatFragment, which should only take one argument.
  169. //-----------------------------------------------------------------------------
  170. BOOL CRefreshFunctions::GetValue(CDataGatherer *pGatherer, TCHAR cFormat, TCHAR *szFormatFragment, CString &strResult, DWORD &dwResult, GATH_FIELD *pField, int iArgNumber)
  171. {
  172. CString strTemp;
  173. COleDateTime datetimeTemp;
  174. double dblValue;
  175. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  176. strResult.Empty();
  177. dwResult = 0L;
  178. if (!pField->m_strSource.IsEmpty() && pField->m_strSource.CompareNoCase(CString(STATIC_SOURCE)) != 0)
  179. {
  180. CDataProvider * pProvider = pGatherer->GetProvider();
  181. if (!pProvider)
  182. return FALSE;
  183. // Find the right argument for this formatting (indicated by the iArgNumber
  184. // parameter.
  185. GATH_VALUE * pArg = pField->m_pArgs;
  186. while (iArgNumber && pArg)
  187. {
  188. pArg = pArg->m_pNext;
  189. iArgNumber--;
  190. }
  191. if (pArg == NULL)
  192. return FALSE;
  193. switch (cFormat)
  194. {
  195. case 'b': case 'B':
  196. // This is a boolean type. Show either true or false, depending on
  197. // the numeric value.
  198. if (pProvider->QueryValueDWORD(pField->m_strSource, pArg->m_strText, dwResult, strTemp))
  199. {
  200. strTemp = (dwResult) ? pProvider->m_strTrue : pProvider->m_strFalse;
  201. strResult.Format(szFormatFragment, strTemp);
  202. return TRUE;
  203. }
  204. else
  205. {
  206. strResult = strTemp;
  207. return FALSE;
  208. }
  209. break;
  210. case 'd': case 'D':
  211. // This is the numeric type.
  212. if (pProvider->QueryValueDWORD(pField->m_strSource, pArg->m_strText, dwResult, strTemp))
  213. {
  214. strResult.Format(szFormatFragment, dwResult);
  215. return TRUE;
  216. }
  217. else
  218. {
  219. strResult = strTemp;
  220. return FALSE;
  221. }
  222. break;
  223. case 'f': case 'F':
  224. // This is the double floating point type.
  225. if (pProvider->QueryValueDoubleFloat(pField->m_strSource, pArg->m_strText, dblValue, strTemp))
  226. {
  227. strResult.Format(szFormatFragment, dblValue);
  228. return TRUE;
  229. }
  230. else
  231. {
  232. strResult = strTemp;
  233. return FALSE;
  234. }
  235. break;
  236. case 't': case 'T':
  237. // This is the OLE date and time type. Format the date and time into the
  238. // string result, and return the date part in the DWORD (the day number is
  239. // to the left of the decimal in the DATE type).
  240. if (pProvider->QueryValueDateTime(pField->m_strSource, pArg->m_strText, datetimeTemp, strTemp))
  241. {
  242. strResult = datetimeTemp.Format();
  243. dwResult = (DWORD)(DATE)datetimeTemp;
  244. return TRUE;
  245. }
  246. else
  247. {
  248. strResult = strTemp;
  249. return FALSE;
  250. }
  251. break;
  252. case 'l': case 'L':
  253. // This is a string type, with the string converted to lower case.
  254. if (pProvider->QueryValue(pField->m_strSource, pArg->m_strText, strTemp))
  255. {
  256. strTemp.MakeLower();
  257. strResult.Format(szFormatFragment, strTemp);
  258. return TRUE;
  259. }
  260. else
  261. {
  262. strResult = strTemp;
  263. return FALSE;
  264. }
  265. break;
  266. case 'u': case 'U':
  267. // This is a string type, with the string converted to upper case.
  268. if (pProvider->QueryValue(pField->m_strSource, pArg->m_strText, strTemp))
  269. {
  270. strTemp.MakeUpper();
  271. strResult.Format(szFormatFragment, strTemp);
  272. return TRUE;
  273. }
  274. else
  275. {
  276. strResult = strTemp;
  277. return FALSE;
  278. }
  279. break;
  280. case 's': case 'S':
  281. // This is the string type (string is the default type).
  282. if (pProvider->QueryValue(pField->m_strSource, pArg->m_strText, strTemp))
  283. {
  284. strResult.Format(szFormatFragment, strTemp);
  285. // We only need to do this when the value returned is a number
  286. // and is going in a column that we want to sort numerically.
  287. // This won't break the case where a numeric string is to be
  288. // sorted as a string because dwResult will be ignored.
  289. if (iswdigit( strTemp[0]))
  290. dwResult = _ttol( (LPCTSTR)strTemp);
  291. return TRUE;
  292. }
  293. else
  294. {
  295. strResult = strTemp;
  296. return FALSE;
  297. }
  298. break;
  299. case 'q': case 'Q':
  300. // This is a specialized type for the Win32_BIOS class. We want to show
  301. // the "Version" property - if it isn't there, then we want to show
  302. // the "Name" property and "ReleaseDate" properties concatenated
  303. // together.
  304. if (pProvider->QueryValue(pField->m_strSource, CString(_T("Version")), strTemp))
  305. {
  306. strResult = strTemp;
  307. return TRUE;
  308. }
  309. else
  310. {
  311. if (pProvider->QueryValue(pField->m_strSource, CString(_T("Name")), strTemp))
  312. strResult = strTemp;
  313. if (pProvider->QueryValueDateTime(pField->m_strSource, CString(_T("ReleaseDate")), datetimeTemp, strTemp))
  314. strResult += CString(_T(" ")) + datetimeTemp.Format();
  315. return TRUE;
  316. }
  317. break;
  318. case 'z': case 'Z':
  319. // This is a specialized size type, where the value is a numeric count
  320. // of bytes. We want to convert it into the best possible units for
  321. // display (for example, display "4.20 MB (4,406,292 bytes)").
  322. if (pProvider->QueryValueDoubleFloat(pField->m_strSource, pArg->m_strText, dblValue, strTemp))
  323. {
  324. double dValue = (double) dblValue;
  325. DWORD dwDivisor = 1;
  326. // Reduce the dValue to the smallest possible number (with a larger unit).
  327. while (dValue > 1024.0 && dwDivisor < (1024 * 1024 * 1024))
  328. {
  329. dwDivisor *= 1024;
  330. dValue /= 1024.0;
  331. }
  332. if (dwDivisor == 1)
  333. strResult.Format(IDS_SIZEBYTES, DelimitNumber(dblValue));
  334. else if (dwDivisor == (1024))
  335. strResult.Format(IDS_SIZEKB_BYTES, dValue, DelimitNumber(dblValue));
  336. else if (dwDivisor == (1024 * 1024))
  337. strResult.Format(IDS_SIZEMB_BYTES, dValue, DelimitNumber(dblValue));
  338. else if (dwDivisor == (1024 * 1024 * 1024))
  339. strResult.Format(IDS_SIZEGB_BYTES, dValue, DelimitNumber(dblValue));
  340. dwResult = (DWORD) dblValue; // So we can sort on this value (bug 391127).
  341. }
  342. else
  343. {
  344. strResult = strTemp;
  345. return FALSE;
  346. }
  347. break;
  348. case 'y': case 'Y':
  349. // This is a specialized size type, where the value is a numeric count
  350. // of bytes, already in KB. If it's big enough, show it in MB or GB.
  351. if (pProvider->QueryValueDoubleFloat(pField->m_strSource, pArg->m_strText, dblValue, strTemp))
  352. {
  353. strResult.Format(IDS_SIZEKB, DelimitNumber(dblValue));
  354. dwResult = (DWORD) dblValue; // So we can sort on this value (bug 391127).
  355. }
  356. else
  357. {
  358. strResult = strTemp;
  359. return FALSE;
  360. }
  361. break;
  362. case 'v': case 'V':
  363. // This is a specialized type, assumed to be an LCID (locale ID). Show the
  364. // locale.
  365. if (pProvider->QueryValue(pField->m_strSource, pArg->m_strText, strTemp))
  366. {
  367. // strTemp contains a string locale ID (like "0409"). Convert it into
  368. // and actual LCID.
  369. LCID lcid = (LCID) _tcstoul(strTemp, NULL, 16);
  370. TCHAR szCountry[MAX_PATH];
  371. if (GetLocaleInfo(lcid, LOCALE_SCOUNTRY, szCountry, MAX_PATH))
  372. strResult = szCountry;
  373. else
  374. strResult = strTemp;
  375. }
  376. else
  377. {
  378. strResult = strTemp;
  379. return FALSE;
  380. }
  381. break;
  382. default:
  383. ASSERT(FALSE); // unknown formatting flag
  384. return TRUE;
  385. }
  386. }
  387. return FALSE;
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Refresh the list of columns based on the list of column fields. We'll also
  391. // need to set the number of columns.
  392. //-----------------------------------------------------------------------------
  393. BOOL CRefreshFunctions::RefreshColumns(CDataGatherer * pGatherer, INTERNAL_CATEGORY * pInternal)
  394. {
  395. ASSERT(pInternal);
  396. GATH_FIELD * pField = pInternal->m_pColSpec;
  397. // Count the number of columns.
  398. pInternal->m_dwColCount = 0;
  399. while (pField)
  400. {
  401. pInternal->m_dwColCount++;
  402. pField = pField->m_pNext;
  403. }
  404. // Allocate the array of column values.
  405. if (pInternal->m_aCols)
  406. delete [] pInternal->m_aCols;
  407. if (pInternal->m_dwColCount == 0)
  408. return TRUE;
  409. pInternal->m_aCols = new GATH_VALUE[pInternal->m_dwColCount];
  410. if (pInternal->m_aCols == NULL)
  411. return FALSE;
  412. // Finally get each column name based on the column field.
  413. pField = pInternal->m_pColSpec;
  414. for (DWORD dwIndex = 0; dwIndex < pInternal->m_dwColCount; dwIndex++)
  415. {
  416. if (!RefreshValue(pGatherer, &pInternal->m_aCols[dwIndex], pField))
  417. return FALSE;
  418. pField = pField->m_pNext;
  419. }
  420. return TRUE;
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Refresh the list of lines based on the list of line fields. We'll also
  424. // need to set the number of lines. The list of lines is generated based on
  425. // the pLineSpec pointer and dwColumns variables. The generated lines are
  426. // returned in the listLinePtrs parameter.
  427. //-----------------------------------------------------------------------------
  428. BOOL CRefreshFunctions::RefreshLines(CDataGatherer * pGatherer, GATH_LINESPEC * pLineSpec, DWORD dwColumns, CPtrList & listLinePtrs, volatile BOOL * pfCancel)
  429. {
  430. BOOL bReturn = TRUE;
  431. // Traverse the list of line specifiers to generate the list of lines.
  432. GATH_LINESPEC * pCurrentLineSpec = pLineSpec;
  433. GATH_LINE * pLine = NULL;
  434. while (pCurrentLineSpec && (pfCancel == NULL || *pfCancel == FALSE))
  435. {
  436. // Check if the current line spec is for a single line or an enumerated group.
  437. if (pCurrentLineSpec->m_strEnumerateClass.IsEmpty() || pCurrentLineSpec->m_strEnumerateClass.CompareNoCase(CString(STATIC_SOURCE)) == 0)
  438. {
  439. // This is for a single line. Allocate a new line structure and fill it
  440. // in with the data generated from the line spec.
  441. pLine = new GATH_LINE;
  442. if (pLine == NULL)
  443. {
  444. bReturn = FALSE;
  445. break;
  446. }
  447. if (RefreshOneLine(pGatherer, pLine, pCurrentLineSpec, dwColumns))
  448. listLinePtrs.AddTail((void *) pLine);
  449. else
  450. {
  451. bReturn = FALSE;
  452. break;
  453. }
  454. }
  455. else
  456. {
  457. // This line represents an enumerated group of lines. We need to enumerate
  458. // the class and call RefreshLines for the group of enumerated lines, once
  459. // for each class instance.
  460. CDataProvider * pProvider = pGatherer->GetProvider();
  461. if (pProvider && pProvider->ResetClass(pCurrentLineSpec->m_strEnumerateClass, pCurrentLineSpec->m_pConstraintFields))
  462. do
  463. {
  464. if (!RefreshLines(pGatherer, pCurrentLineSpec->m_pEnumeratedGroup, dwColumns, listLinePtrs))
  465. break;
  466. } while (pProvider->EnumClass(pCurrentLineSpec->m_strEnumerateClass, pCurrentLineSpec->m_pConstraintFields));
  467. }
  468. pCurrentLineSpec = pCurrentLineSpec->m_pNext;
  469. }
  470. if (pfCancel && *pfCancel)
  471. return FALSE;
  472. // If there was a failure generating the lines, clean up after ourselves.
  473. if (!bReturn)
  474. {
  475. if (pLine)
  476. delete pLine;
  477. for (POSITION pos = listLinePtrs.GetHeadPosition(); pos != NULL;)
  478. {
  479. pLine = (GATH_LINE *) listLinePtrs.GetNext(pos) ;
  480. if (pLine)
  481. delete pLine;
  482. }
  483. listLinePtrs.RemoveAll();
  484. return FALSE;
  485. }
  486. return TRUE;
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Refresh a line based on a line spec.
  490. //-----------------------------------------------------------------------------
  491. BOOL CRefreshFunctions::RefreshOneLine(CDataGatherer * pGatherer, GATH_LINE * pLine, GATH_LINESPEC * pLineSpec, DWORD dwColCount)
  492. {
  493. // Allocate the new array of values.
  494. if (pLine->m_aValue)
  495. delete [] pLine->m_aValue;
  496. pLine->m_aValue = new GATH_VALUE[dwColCount];
  497. if (pLine->m_aValue == NULL)
  498. return FALSE;
  499. // Set the data complexity for the line based on the line spec.
  500. pLine->m_datacomplexity = pLineSpec->m_datacomplexity;
  501. // Compute each of the values for the fields.
  502. GATH_FIELD * pField = pLineSpec->m_pFields;
  503. for (DWORD dwIndex = 0; dwIndex < dwColCount; dwIndex++)
  504. {
  505. if (pField == NULL)
  506. return FALSE;
  507. if (!RefreshValue(pGatherer, &pLine->m_aValue[dwIndex], pField))
  508. return FALSE;
  509. pField = pField->m_pNext;
  510. }
  511. return TRUE;
  512. }