Leaked source code of windows server 2003
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

  1. //=============================================================================
  2. // Contains the functions for the base WMI helper class.
  3. //=============================================================================
  4. #include "stdafx.h"
  5. #include "category.h"
  6. #include "wmiabstraction.h"
  7. #include "resource.h"
  8. #include "dataset.h"
  9. //-----------------------------------------------------------------------------
  10. // Loads the string identified by uiResourceID, and parses it into the columns
  11. // in aColValues. The string should be of the form "www|xxx|yyy|zzz" - this
  12. // will be parsed into two rows: www,xxx and yyy,zzz. Values will be inserted
  13. // into the aColValues array of pointer lists of CMSIValue structs.
  14. //-----------------------------------------------------------------------------
  15. void CWMIHelper::LoadColumnsFromResource(UINT uiResourceID, CPtrList * aColValues, int iColCount)
  16. {
  17. AfxSetResourceHandle(_Module.GetResourceInstance());
  18. CString strResource;
  19. if (strResource.LoadString(uiResourceID))
  20. {
  21. CMSIValue * pValue;
  22. int iCol = 0;
  23. while (!strResource.IsEmpty())
  24. {
  25. pValue = new CMSIValue(strResource.SpanExcluding(_T("|\n")), 0);
  26. if (pValue)
  27. {
  28. ASSERT(!pValue->m_strValue.IsEmpty());
  29. strResource = strResource.Right(strResource.GetLength() - pValue->m_strValue.GetLength() - 1);
  30. aColValues[iCol].AddTail((void *) pValue);
  31. iCol += 1;
  32. if (iCol == iColCount)
  33. iCol = 0;
  34. }
  35. else
  36. strResource.Empty();
  37. }
  38. }
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Same as the previous, but uses a string instead of a resource ID.
  42. //-----------------------------------------------------------------------------
  43. void CWMIHelper::LoadColumnsFromString(LPCTSTR szColumns, CPtrList * aColValues, int iColCount)
  44. {
  45. if (szColumns != NULL)
  46. {
  47. CString strColumns(szColumns);
  48. CMSIValue * pValue;
  49. int iCol = 0;
  50. while (!strColumns.IsEmpty())
  51. {
  52. pValue = new CMSIValue(strColumns.SpanExcluding(_T("|\n")), 0);
  53. if (pValue)
  54. {
  55. ASSERT(!pValue->m_strValue.IsEmpty());
  56. strColumns = strColumns.Right(strColumns.GetLength() - pValue->m_strValue.GetLength() - 1);
  57. aColValues[iCol].AddTail((void *) pValue);
  58. iCol += 1;
  59. if (iCol == iColCount)
  60. iCol = 0;
  61. }
  62. else
  63. strColumns.Empty();
  64. }
  65. }
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Return the first object of the specified class.
  69. //-----------------------------------------------------------------------------
  70. CWMIObject * CWMIHelper::GetSingleObject(LPCTSTR szClass, LPCTSTR szProperties)
  71. {
  72. ASSERT(szClass);
  73. CWMIObjectCollection * pCollection = NULL;
  74. CWMIObject * pObject = NULL;
  75. if (SUCCEEDED(Enumerate(szClass, &pCollection, szProperties)))
  76. {
  77. if (FAILED(pCollection->GetNext(&pObject)))
  78. pObject = NULL;
  79. delete pCollection;
  80. }
  81. return pObject;
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Delimit the specified number.
  85. //-----------------------------------------------------------------------------
  86. CString DelimitNumber(double dblValue, int iDecimalDigits = 0)
  87. {
  88. NUMBERFMT fmt;
  89. TCHAR szResult[MAX_PATH] = _T("");
  90. TCHAR szDelimiter[4] = _T(",");
  91. TCHAR szDecimal[4] = _T(".");
  92. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szDelimiter, 4);
  93. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szDecimal, 4);
  94. memset(&fmt, 0, sizeof(NUMBERFMT));
  95. fmt.Grouping = 3;
  96. fmt.lpDecimalSep = (iDecimalDigits) ? szDecimal : _T("");
  97. fmt.NumDigits = iDecimalDigits;
  98. fmt.lpThousandSep = szDelimiter;
  99. CString strValue;
  100. CString strFormatString;
  101. strFormatString.Format(_T("%%.%df"), iDecimalDigits);
  102. strValue.Format(strFormatString, dblValue);
  103. // GetNumberFormat requires the decimal to be a '.', while CString::Format
  104. // uses the locale value. So we need to go back and replace it.
  105. StringReplace(strValue, szDecimal, _T("."));
  106. GetNumberFormat(LOCALE_USER_DEFAULT, 0, strValue, &fmt, szResult, MAX_PATH);
  107. return CString(szResult);
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Return the requested value from the object, as a string and/or a DWORD.
  111. // Use the chFormat flag to determine how to format the results.
  112. //
  113. // The return result is the actual format character to use for displaying the
  114. // results in a string.
  115. //
  116. // TBD - do something better with the HRESULTs returned.
  117. //-----------------------------------------------------------------------------
  118. CString gstrYes; // global string "yes" (will be localized)
  119. CString gstrNo; // global string "no" (will be localized)
  120. CString gstrBytes; // global string "bytes" (will be localized)
  121. CString gstrKB; // global string "KB" (will be localized)
  122. CString gstrMB; // global string "MB" (will be localized)
  123. CString gstrGB; // global string "GB" (will be localized)
  124. CString gstrTB; // global string "TB" (will be localized)
  125. HRESULT CWMIObject::GetInterpretedValue(LPCTSTR szProperty, LPCTSTR szFormat, TCHAR chFormat, CString * pstrValue, DWORD * pdwValue)
  126. {
  127. HRESULT hr = E_FAIL;
  128. CString strValue(_T(""));
  129. DWORD dwValue = 0;
  130. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  131. switch (chFormat)
  132. {
  133. case _T('s'):
  134. case _T('u'):
  135. case _T('l'):
  136. {
  137. hr = GetValueString(szProperty, &strValue);
  138. if (SUCCEEDED(hr))
  139. {
  140. if (chFormat == _T('u'))
  141. strValue.MakeUpper();
  142. else if (chFormat == _T('l'))
  143. strValue.MakeLower();
  144. strValue.TrimRight();
  145. }
  146. }
  147. break;
  148. case _T('v'):
  149. {
  150. hr = GetValueValueMap(szProperty, &strValue);
  151. }
  152. break;
  153. case _T('d'):
  154. case _T('x'):
  155. {
  156. hr = GetValueDWORD(szProperty, &dwValue);
  157. if (SUCCEEDED(hr))
  158. {
  159. strValue.Format(szFormat, dwValue);
  160. }
  161. }
  162. break;
  163. case _T('f'):
  164. {
  165. double dblValue;
  166. hr = GetValueDoubleFloat(szProperty, &dblValue);
  167. if (SUCCEEDED(hr))
  168. {
  169. strValue.Format(szFormat, dblValue);
  170. dwValue = (DWORD) dblValue;
  171. }
  172. }
  173. break;
  174. case _T('b'):
  175. {
  176. if (gstrYes.IsEmpty())
  177. gstrYes.LoadString(IDS_YES);
  178. if (gstrNo.IsEmpty())
  179. gstrNo.LoadString(IDS_NO);
  180. hr = GetValueDWORD(szProperty, &dwValue);
  181. if (SUCCEEDED(hr))
  182. {
  183. strValue = (dwValue) ? gstrYes : gstrNo;
  184. }
  185. }
  186. break;
  187. case _T('w'):
  188. case _T('y'):
  189. case _T('z'):
  190. {
  191. if (gstrBytes.IsEmpty())
  192. gstrBytes.LoadString(IDS_BYTES);
  193. if (gstrKB.IsEmpty())
  194. gstrKB.LoadString(IDS_KB);
  195. if (gstrMB.IsEmpty())
  196. gstrMB.LoadString(IDS_MB);
  197. if (gstrGB.IsEmpty())
  198. gstrGB.LoadString(IDS_GB);
  199. if (gstrTB.IsEmpty())
  200. gstrTB.LoadString(IDS_TB);
  201. double dblValue;
  202. hr = GetValueDoubleFloat(szProperty, &dblValue);
  203. if (SUCCEEDED(hr))
  204. {
  205. CString strFormattedNumber;
  206. dwValue = (DWORD) dblValue; // TBD potential loss of digits
  207. if (chFormat == _T('w'))
  208. strFormattedNumber = DelimitNumber(dblValue);
  209. else
  210. {
  211. int iDivTimes = (chFormat == _T('y')) ? 1 : 0;
  212. double dblWorking(dblValue);
  213. for (; iDivTimes <= 4 && dblWorking >= 1024.0; iDivTimes++)
  214. dblWorking /= 1024.0;
  215. strFormattedNumber = DelimitNumber(dblWorking, (iDivTimes) ? 2 : 0);
  216. switch (iDivTimes)
  217. {
  218. case 0:
  219. strFormattedNumber += _T(" ") + gstrBytes;
  220. break;
  221. case 1:
  222. strFormattedNumber += _T(" ") + gstrKB;
  223. break;
  224. case 2:
  225. strFormattedNumber += _T(" ") + gstrMB;
  226. break;
  227. case 3:
  228. strFormattedNumber += _T(" ") + gstrGB;
  229. break;
  230. case 4:
  231. strFormattedNumber += _T(" ") + gstrTB;
  232. break;
  233. }
  234. if (chFormat == _T('z') && iDivTimes)
  235. strFormattedNumber += _T(" (") + DelimitNumber(dblValue) + _T(" ") + gstrBytes + _T(")");
  236. }
  237. strValue = strFormattedNumber;
  238. }
  239. }
  240. break;
  241. case _T('t'):
  242. {
  243. COleDateTime oledatetime;
  244. SYSTEMTIME systimeValue;
  245. hr = GetValueTime(szProperty, &systimeValue);
  246. oledatetime = (COleDateTime) systimeValue;
  247. if (SUCCEEDED(hr))
  248. {
  249. dwValue = (DWORD)(DATE)oledatetime;
  250. // Try to get the date in the localized format.
  251. strValue.Empty();
  252. TCHAR szBuffer[MAX_PATH]; // seems plenty big
  253. if (::GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systimeValue, NULL, szBuffer, MAX_PATH))
  254. {
  255. strValue = szBuffer;
  256. if (::GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &systimeValue, NULL, szBuffer, MAX_PATH))
  257. strValue += CString(_T(" ")) + CString(szBuffer);
  258. }
  259. // Fall back on our old (partially incorrect) method.
  260. if (strValue.IsEmpty())
  261. strValue = oledatetime.Format(0, LOCALE_USER_DEFAULT);
  262. }
  263. }
  264. break;
  265. case _T('c'):
  266. {
  267. COleDateTime oledatetime;
  268. SYSTEMTIME systimeValue;
  269. hr = GetValueTime(szProperty, &systimeValue);
  270. oledatetime = (COleDateTime) systimeValue;
  271. if (SUCCEEDED(hr))
  272. {
  273. dwValue = (DWORD)(DATE)oledatetime;
  274. // Try to get the date in the localized format.
  275. strValue.Empty();
  276. TCHAR szBuffer[MAX_PATH]; // seems plenty big
  277. if (::GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systimeValue, NULL, szBuffer, MAX_PATH))
  278. strValue = szBuffer;
  279. // Fall back on our old (partially incorrect) method.
  280. if (strValue.IsEmpty())
  281. strValue = oledatetime.Format(0, LOCALE_USER_DEFAULT);
  282. }
  283. }
  284. break;
  285. case _T('a'):
  286. {
  287. hr = GetValueString(szProperty, &strValue);
  288. if (SUCCEEDED(hr))
  289. {
  290. // strValue contains a string locale ID (like "0409"). Convert it into
  291. // and actual LCID.
  292. LCID lcid = (LCID) _tcstoul(strValue, NULL, 16);
  293. TCHAR szCountry[MAX_PATH];
  294. if (GetLocaleInfo(lcid, LOCALE_SCOUNTRY, szCountry, MAX_PATH))
  295. strValue = szCountry;
  296. }
  297. }
  298. break;
  299. default:
  300. break;
  301. // Just continue with the loop.
  302. }
  303. if (SUCCEEDED(hr))
  304. {
  305. if (pstrValue)
  306. {
  307. if (chFormat == _T('d') || chFormat == _T('x') || chFormat == _T('f'))
  308. *pstrValue = strValue;
  309. else
  310. {
  311. CString strFormat(szFormat);
  312. int iPercent = strFormat.Find(_T("%"));
  313. int iLength = strFormat.GetLength();
  314. if (iPercent != -1)
  315. {
  316. while (iPercent < iLength && strFormat[iPercent] != chFormat)
  317. iPercent++;
  318. if (iPercent < iLength)
  319. {
  320. strFormat.SetAt(iPercent, _T('s'));
  321. pstrValue->Format(strFormat, strValue);
  322. }
  323. }
  324. }
  325. }
  326. if (pdwValue)
  327. *pdwValue = dwValue;
  328. }
  329. else
  330. {
  331. if (pstrValue)
  332. *pstrValue = GetMSInfoHRESULTString(hr);
  333. if (pdwValue)
  334. *pdwValue = 0;
  335. }
  336. return hr;
  337. }
  338. //-----------------------------------------------------------------------------
  339. // These functions implement features found in the new versions of MFC (new
  340. // than what we're currently building with).
  341. //-----------------------------------------------------------------------------
  342. int StringFind(CString & str, LPCTSTR szLookFor, int iStartFrom)
  343. {
  344. CString strWorking(str.Right(str.GetLength() - iStartFrom));
  345. int iFind = strWorking.Find(szLookFor);
  346. if (iFind != -1)
  347. iFind += iStartFrom;
  348. return iFind;
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Process the specified string. It will contain a format string with one
  352. // or more flags (flags specific to MSInfo). We need to replace is flag with
  353. // a properly formatted value from pObject, determined by the next property
  354. // in pstrProperties.
  355. //-----------------------------------------------------------------------------
  356. BOOL ProcessColumnString(CMSIValue * pValue, CWMIObject * pObject, CString * pstrProperties)
  357. {
  358. CString strPropertyValue, strProperty, strFragment;
  359. CString strResults(_T(""));
  360. CString strFormatString(pValue->m_strValue);
  361. DWORD dwResults;
  362. BOOL fAdvanced = FALSE;
  363. BOOL fAllPiecesFailed = TRUE;
  364. HRESULT hr = S_OK;
  365. while (!strFormatString.IsEmpty() && SUCCEEDED(hr))
  366. {
  367. // Get the next fragment of the format string with a single format specifier.
  368. int iPercent = strFormatString.Find(_T("%"));
  369. if (iPercent == -1)
  370. {
  371. strResults += strFormatString;
  372. break;
  373. }
  374. int iSecondPercent = StringFind(strFormatString, _T("%"), iPercent + 1);
  375. if (iSecondPercent == -1)
  376. {
  377. strFragment = strFormatString;
  378. strFormatString.Empty();
  379. }
  380. else
  381. {
  382. strFragment = strFormatString.Left(iSecondPercent);
  383. strFormatString = strFormatString.Right(strFormatString.GetLength() - iSecondPercent);
  384. }
  385. // Find the format character for this fragment.
  386. TCHAR chFormat;
  387. do
  388. chFormat = strFragment[++iPercent];
  389. while (!_istalpha(chFormat));
  390. // Get the property name for this fragment.
  391. int iComma = pstrProperties->Find(_T(","));
  392. if (iComma != -1)
  393. {
  394. strProperty = pstrProperties->Left(iComma);
  395. *pstrProperties = pstrProperties->Right(pstrProperties->GetLength() - iComma - 1);
  396. }
  397. else
  398. {
  399. strProperty = *pstrProperties;
  400. pstrProperties->Empty();
  401. }
  402. strProperty.TrimLeft();
  403. strProperty.TrimRight();
  404. if (strProperty.Left(11) == CString(_T("MSIAdvanced")))
  405. {
  406. fAdvanced = TRUE;
  407. strProperty = strProperty.Right(strProperty.GetLength() - 11);
  408. }
  409. // Get the actual value the property and add it to the string.
  410. hr = pObject->GetInterpretedValue(strProperty, strFragment, chFormat, &strPropertyValue, &dwResults);
  411. if (SUCCEEDED(hr))
  412. {
  413. fAllPiecesFailed = FALSE;
  414. strResults += strPropertyValue;
  415. }
  416. else
  417. strResults += GetMSInfoHRESULTString(hr);
  418. }
  419. if (!fAllPiecesFailed)
  420. {
  421. pValue->m_strValue = strResults;
  422. pValue->m_dwValue = dwResults;
  423. }
  424. else
  425. {
  426. pValue->m_strValue = GetMSInfoHRESULTString(hr);
  427. pValue->m_dwValue = 0;
  428. }
  429. pValue->m_fAdvanced = fAdvanced;
  430. return TRUE;
  431. }
  432. //-----------------------------------------------------------------------------
  433. // A general purpose function to add the contents of object pObject to the
  434. // columns, based on the properties in szProperties and the string referenced
  435. // by uiColumns.
  436. //-----------------------------------------------------------------------------
  437. void CWMIHelper::AddObjectToOutput(CPtrList * aColValues, int iColCount, CWMIObject * pObject, LPCTSTR szProperties, UINT uiColumns)
  438. {
  439. POSITION aPositions[32]; // should never be more than 32 columns
  440. ASSERT(iColCount < 32);
  441. CString strProperties(szProperties);
  442. // Save the starting position for the new entries we're adding from the resoure.
  443. int iColListStart = (int)aColValues[0].GetCount();
  444. LoadColumnsFromResource(uiColumns, aColValues, iColCount);
  445. // Look through each of the new cells. For each string in a cell, if we
  446. // find a formatting flag (like %s), get the next property out of the
  447. // property list and format the string.
  448. for (int iCol = 0; iCol < iColCount; iCol++)
  449. aPositions[iCol] = aColValues[iCol].FindIndex(iColListStart);
  450. while (aPositions[0])
  451. for (iCol = 0; iCol < iColCount; iCol++)
  452. {
  453. ASSERT(aPositions[iCol]);
  454. if (aPositions[iCol])
  455. {
  456. CMSIValue * pValue = (CMSIValue *) aColValues[iCol].GetNext(aPositions[iCol]);
  457. if (pValue && pValue->m_strValue.Find(_T("%")) != -1)
  458. ProcessColumnString(pValue, pObject, &strProperties);
  459. }
  460. }
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Same as previous, but takes a string instead of a resource ID.
  464. //-----------------------------------------------------------------------------
  465. void CWMIHelper::AddObjectToOutput(CPtrList * aColValues, int iColCount, CWMIObject * pObject, LPCTSTR szProperties, LPCTSTR szColumns)
  466. {
  467. POSITION aPositions[32]; // should never be more than 32 columns
  468. ASSERT(iColCount < 32);
  469. CString strProperties(szProperties);
  470. // Save the starting position for the new entries we're adding from the resoure.
  471. int iColListStart = (int)aColValues[0].GetCount();
  472. LoadColumnsFromString(szColumns, aColValues, iColCount);
  473. // Look through each of the new cells. For each string in a cell, if we
  474. // find a formatting flag (like %s), get the next property out of the
  475. // property list and format the string.
  476. for (int iCol = 0; iCol < iColCount; iCol++)
  477. aPositions[iCol] = aColValues[iCol].FindIndex(iColListStart);
  478. while (aPositions[0])
  479. for (iCol = 0; iCol < iColCount; iCol++)
  480. {
  481. ASSERT(aPositions[iCol]);
  482. if (aPositions[iCol])
  483. {
  484. CMSIValue * pValue = (CMSIValue *) aColValues[iCol].GetNext(aPositions[iCol]);
  485. if (pValue && pValue->m_strValue.Find(_T("%")) != -1)
  486. ProcessColumnString(pValue, pObject, &strProperties);
  487. }
  488. }
  489. }
  490. void CWMIHelper::AppendBlankLine(CPtrList * aColValues, int iColCount, BOOL fOnlyIfNotEmpty)
  491. {
  492. if (aColValues[0].GetCount() || fOnlyIfNotEmpty == FALSE)
  493. for (int iCol = 0; iCol < iColCount; iCol++)
  494. AppendCell(aColValues[iCol], _T(""), 0);
  495. }
  496. void CWMIHelper::AppendCell(CPtrList & listColumns, const CString & strValue, DWORD dwValue, BOOL fAdvanced)
  497. {
  498. CMSIValue * pValue = new CMSIValue(strValue, dwValue, fAdvanced);
  499. if (pValue)
  500. listColumns.AddTail((void *) pValue);
  501. }