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.

1045 lines
32 KiB

  1. //=============================================================================
  2. // This file contains code to implement the CMSInfoCategory derived class for
  3. // showing live WMI data.
  4. //=============================================================================
  5. #include "stdafx.h"
  6. #include "resource.h"
  7. #include "category.h"
  8. #include "datasource.h"
  9. #include "dataset.h"
  10. #include "refreshthread.h"
  11. #include "refreshdialog.h"
  12. #include "wbemcli.h"
  13. #include "version5extension.h"
  14. #include "filestuff.h"
  15. #include "historyparser.h"
  16. //=============================================================================
  17. // CLiveDataSource
  18. //
  19. // TBD - need methods to look at deltas. How will this work?
  20. //=============================================================================
  21. CLiveDataSource::CLiveDataSource() : m_hwnd(NULL), m_pThread(NULL), m_strMachine(_T("")), m_pHistoryRoot(NULL), m_iDeltaIndex(-1)
  22. {
  23. }
  24. //-----------------------------------------------------------------------------
  25. // The default constructor will take care of deleting the tree.
  26. //-----------------------------------------------------------------------------
  27. CLiveDataSource::~CLiveDataSource()
  28. {
  29. if (m_pThread)
  30. delete m_pThread;
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Creating a live data source consists of making the WMI connection to the
  34. // appropriate machine (most likely this one). We'll also need to load the
  35. // tree with default categories.
  36. //
  37. // TBD - also load extensions
  38. //-----------------------------------------------------------------------------
  39. extern CMSInfoLiveCategory catSystemSummary;
  40. extern CMSInfoHistoryCategory catHistorySystemSummary;
  41. HRESULT CLiveDataSource::Create(LPCTSTR szMachine, HWND hwnd, LPCTSTR szFilter)
  42. {
  43. // Build the tree. The default categories are stored in a static
  44. // set of structures - the base of which is catSystemSummary.
  45. m_pHistoryRoot = &catHistorySystemSummary;
  46. m_pRoot = &catSystemSummary;
  47. m_fStaticTree = TRUE;
  48. // Load any extensions to the live data.
  49. AddExtensions();
  50. // If there is a string containing a filter of what categories
  51. // to show, apply that filter.
  52. if (szFilter && szFilter[0])
  53. ApplyCategoryFilter(szFilter);
  54. // Save the machine name we are remoting to.
  55. m_strMachine = szMachine;
  56. SetMachineForCategories((CMSInfoLiveCategory *) m_pRoot);
  57. // Create the refresh thread for the live data source.
  58. m_pThread = new CRefreshThread(hwnd);
  59. if (m_pThread)
  60. m_pThread->m_strMachine = szMachine;
  61. m_hwnd = hwnd;
  62. return S_OK;
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Apply the set of filters to the categories. If the filter string is not
  66. // empty, we should start out showing none of the categories, and only add in
  67. // the ones specified by the filter (this is to match a feature in 5.0).
  68. //-----------------------------------------------------------------------------
  69. void CLiveDataSource::ApplyCategoryFilter(LPCTSTR szFilter)
  70. {
  71. m_pRoot->SetShowCategory(FALSE);
  72. CString strNode, strFilter(szFilter);
  73. strFilter.TrimLeft(_T(" \"=:"));
  74. strFilter.TrimRight(_T(" \"=:"));
  75. while (!strFilter.IsEmpty())
  76. {
  77. BOOL fAdd = (strFilter[0] == _T('+'));
  78. strFilter = strFilter.Mid(1);
  79. if (!strFilter.IsEmpty())
  80. {
  81. strNode = strFilter.SpanExcluding(_T("+-"));
  82. strFilter = strFilter.Mid(strNode.GetLength());
  83. if (!strNode.IsEmpty())
  84. {
  85. CMSInfoLiveCategory * pNode;
  86. if (strNode.CompareNoCase(_T("all")) == 0)
  87. pNode = (CMSInfoLiveCategory *) m_pRoot;
  88. else
  89. pNode = GetNodeByName(strNode, (CMSInfoLiveCategory *) m_pRoot);
  90. if (pNode)
  91. pNode->SetShowCategory(fAdd);
  92. }
  93. }
  94. }
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Add version 5.0 extensions to the m_pRoot category tree.
  98. //
  99. // Note - we only want to do this once. And we only want to delete the nodes
  100. // we added once (when we're unloading). So we'll create a simple class to
  101. // manage this lifetime.
  102. //
  103. // THIS CLASS IS DANGEROUS (and this should probably be redesigned). It should
  104. // only be used to add extensions to a static tree, that won't be deleted
  105. // any time before the app exits. This class assumes the responsibility for
  106. // deleting the dynamic nodes inserted into the tree.
  107. //-----------------------------------------------------------------------------
  108. class CManageExtensionCategories
  109. {
  110. public:
  111. CManageExtensionCategories() : m_pRoot(NULL) {};
  112. ~CManageExtensionCategories() { DeleteTree(m_pRoot); };
  113. BOOL ExtensionsAdded(CMSInfoLiveCategory * pRoot)
  114. {
  115. if (m_pRoot)
  116. return TRUE;
  117. m_pRoot = pRoot;
  118. return FALSE;
  119. }
  120. private:
  121. CMSInfoLiveCategory * m_pRoot;
  122. void DeleteTree(CMSInfoLiveCategory * pRoot)
  123. {
  124. if (pRoot == NULL)
  125. return;
  126. for (CMSInfoLiveCategory * pChild = (CMSInfoLiveCategory *) pRoot->GetFirstChild(); pChild;)
  127. {
  128. CMSInfoLiveCategory * pNext = (CMSInfoLiveCategory *) pChild->GetNextSibling();
  129. DeleteTree(pChild);
  130. pChild = pNext;
  131. }
  132. // If the tree is static, then don't actually delete, just reset
  133. // some state variables (possibly).
  134. if (pRoot->m_fDynamicColumns)
  135. delete pRoot;
  136. }
  137. };
  138. CManageExtensionCategories gManageExtensionCategories;
  139. extern BOOL FileExists(const CString & strFile);
  140. void CLiveDataSource::AddExtensions()
  141. {
  142. if (gManageExtensionCategories.ExtensionsAdded((CMSInfoLiveCategory *) m_pRoot))
  143. return;
  144. CStringList strlistExtensions;
  145. GetExtensionSet(strlistExtensions);
  146. while (!strlistExtensions.IsEmpty())
  147. {
  148. CString strExtension = strlistExtensions.RemoveHead();
  149. if (FileExists(strExtension))
  150. {
  151. CMapWordToPtr mapVersion5Categories;
  152. DWORD dwRootID = CTemplateFileFunctions::ParseTemplateIntoVersion5Categories(strExtension, mapVersion5Categories);
  153. ConvertVersion5Categories(mapVersion5Categories, dwRootID, (CMSInfoLiveCategory *) m_pRoot);
  154. }
  155. }
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Look for all of the version 5.0 style extension. These will be located as
  159. // values under the msinfo\templates registry key.
  160. //-----------------------------------------------------------------------------
  161. void CLiveDataSource::GetExtensionSet(CStringList & strlistExtensions)
  162. {
  163. strlistExtensions.RemoveAll();
  164. TCHAR szBaseKey[] = _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo\\templates");
  165. HKEY hkeyBase;
  166. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBaseKey, 0, KEY_READ, &hkeyBase))
  167. {
  168. TCHAR szName[64], szValue[MAX_PATH];
  169. DWORD dwIndex = 0;
  170. DWORD dwLength = sizeof(szName) / sizeof(TCHAR);
  171. while (ERROR_SUCCESS == RegEnumKeyEx(hkeyBase, dwIndex++, szName, &dwLength, NULL, NULL, NULL, NULL))
  172. {
  173. dwLength = sizeof(szValue) / sizeof(TCHAR);
  174. if (ERROR_SUCCESS == RegQueryValue(hkeyBase, szName, szValue, (long *)&dwLength))
  175. if (*szValue)
  176. strlistExtensions.AddTail(szValue);
  177. dwLength = sizeof(szName) / sizeof(TCHAR);
  178. }
  179. RegCloseKey(hkeyBase);
  180. }
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Convert the categories from version 5.0 format (in the map) to our
  184. // format in the tree structure.
  185. //-----------------------------------------------------------------------------
  186. extern CMSInfoLiveCategory catSystemSummary;
  187. void CLiveDataSource::ConvertVersion5Categories(CMapWordToPtr & mapVersion5Categories, DWORD dwRootID, CMSInfoLiveCategory * m_pRoot)
  188. {
  189. WORD wMapID;
  190. INTERNAL_CATEGORY * pCategory;
  191. POSITION pos;
  192. DWORD dwID = dwRootID;
  193. CMSInfoLiveCategory * pInsertCat;
  194. while ((pCategory = CTemplateFileFunctions::GetInternalRep(mapVersion5Categories, dwID)) != NULL)
  195. {
  196. INTERNAL_CATEGORY * pPrev = CTemplateFileFunctions::GetInternalRep(mapVersion5Categories, pCategory->m_dwPrevID);
  197. if (pPrev && (pInsertCat = GetNodeByName(pPrev->m_strIdentifier, m_pRoot)))
  198. {
  199. CMSInfoLiveCategory * pNewCat = MakeVersion6Category(pCategory);
  200. pNewCat->m_pPrevSibling = pInsertCat;
  201. pNewCat->m_pNextSibling = pInsertCat->m_pNextSibling;
  202. pNewCat->m_pParent = pInsertCat->m_pParent;
  203. pInsertCat->m_pNextSibling = pNewCat;
  204. if (pNewCat->m_pNextSibling)
  205. pNewCat->m_pNextSibling->m_pPrevSibling = pNewCat;
  206. }
  207. else
  208. {
  209. INTERNAL_CATEGORY * pParent = CTemplateFileFunctions::GetInternalRep(mapVersion5Categories, pCategory->m_dwParentID);
  210. CString strIdentifier;
  211. if (pParent)
  212. strIdentifier = pParent->m_strIdentifier;
  213. else
  214. catSystemSummary.GetNames(NULL, &strIdentifier);
  215. if ((pInsertCat = GetNodeByName(strIdentifier, m_pRoot)) != NULL)
  216. {
  217. CMSInfoLiveCategory * pNewCat = MakeVersion6Category(pCategory);
  218. if (pInsertCat->m_pFirstChild == NULL)
  219. {
  220. pNewCat->m_pPrevSibling = NULL;
  221. pNewCat->m_pNextSibling = NULL;
  222. pNewCat->m_pParent = pInsertCat;
  223. pInsertCat->m_pFirstChild = pNewCat;
  224. }
  225. else
  226. {
  227. CMSInfoLiveCategory * pInsertAfter = (CMSInfoLiveCategory *) pInsertCat->m_pFirstChild;
  228. while (pInsertAfter->m_pNextSibling)
  229. pInsertAfter = (CMSInfoLiveCategory *) pInsertAfter->m_pNextSibling;
  230. pNewCat->m_pPrevSibling = pInsertAfter;
  231. pNewCat->m_pNextSibling = NULL;
  232. pNewCat->m_pParent = pInsertAfter->m_pParent;
  233. pInsertAfter->m_pNextSibling = pNewCat;
  234. }
  235. }
  236. }
  237. dwID += 1;
  238. }
  239. for (pos = mapVersion5Categories.GetStartPosition(); pos != NULL;)
  240. {
  241. mapVersion5Categories.GetNextAssoc(pos, wMapID, (void * &) pCategory);
  242. if (pCategory)
  243. delete pCategory;
  244. }
  245. mapVersion5Categories.RemoveAll();
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Look for a node in the tree with the specified name.
  249. //-----------------------------------------------------------------------------
  250. CMSInfoLiveCategory * CLiveDataSource::GetNodeByName(const CString & strSearch, CMSInfoLiveCategory * pRoot)
  251. {
  252. if (pRoot == NULL)
  253. return NULL;
  254. CString strName;
  255. pRoot->GetNames(NULL, &strName);
  256. if (strName.CompareNoCase(strSearch) == 0)
  257. return pRoot;
  258. CMSInfoLiveCategory * pSearch = GetNodeByName(strSearch, (CMSInfoLiveCategory *) pRoot->m_pNextSibling);
  259. if (pSearch)
  260. return pSearch;
  261. pSearch = GetNodeByName(strSearch, (CMSInfoLiveCategory *) pRoot->m_pFirstChild);
  262. if (pSearch)
  263. return pSearch;
  264. return NULL;
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Create a version 6.0 category structure out of a version 5.0 category
  268. // structure.
  269. //-----------------------------------------------------------------------------
  270. CMSInfoLiveCategory * CLiveDataSource::MakeVersion6Category(INTERNAL_CATEGORY * pCategory5)
  271. {
  272. CMSInfoLiveCategory * pCategory6 = new CMSInfoLiveCategory(pCategory5);
  273. return pCategory6;
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Propagate the machine name through the entire category tree.
  277. //-----------------------------------------------------------------------------
  278. void CLiveDataSource::SetMachineForCategories(CMSInfoLiveCategory * pCategory)
  279. {
  280. if (pCategory)
  281. {
  282. for (CMSInfoLiveCategory * pChild = (CMSInfoLiveCategory *) pCategory->GetFirstChild(); pChild;)
  283. {
  284. CMSInfoLiveCategory * pNext = (CMSInfoLiveCategory *) pChild->GetNextSibling();
  285. SetMachineForCategories(pChild);
  286. pChild = pNext;
  287. }
  288. pCategory->SetMachine(m_strMachine);
  289. }
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Update the category tree to show delta information. Also changes which
  293. // tree should be returned.
  294. //
  295. // An index of -1 means show current system information.
  296. //
  297. // If the function returns TRUE, then the tree doesn't need to be rebuild
  298. // (although the selected category needs to be refreshed).
  299. //-----------------------------------------------------------------------------
  300. BOOL CLiveDataSource::ShowDeltas(int iDeltaIndex)
  301. {
  302. BOOL fUpdateTree = FALSE;
  303. if (m_iDeltaIndex != iDeltaIndex)
  304. {
  305. if (m_iDeltaIndex == -1 || iDeltaIndex == -1)
  306. fUpdateTree = TRUE;
  307. #ifdef A_STEPHL
  308. /*CString strMSG;
  309. strMSG.Format("iDeltaIndex= %d, m_iDeltaIndex =%d \n",iDeltaIndex,m_iDeltaIndex);
  310. ::MessageBox(NULL,strMSG,"",MB_OK);*/
  311. #endif
  312. m_iDeltaIndex = iDeltaIndex;
  313. if (m_iDeltaIndex != -1)
  314. {
  315. // The user has selected a new delta period, and it's different
  316. // than the last one. We need to mark the categories in the tree
  317. // as not refreshed, and set the delta index.
  318. if (m_pHistoryRoot)
  319. m_pHistoryRoot->UpdateDeltaIndex(m_iDeltaIndex);
  320. }
  321. }
  322. else
  323. {
  324. #ifdef A_STEPHL2
  325. ::MessageBox(NULL,"m_iDeltaIndex == iDeltaIndex","",MB_OK);
  326. #endif
  327. return TRUE;
  328. }
  329. return !fUpdateTree;
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Populate the list of available deltas.
  333. //-----------------------------------------------------------------------------
  334. BOOL CLiveDataSource::GetDeltaList(CStringList * pstrlist)
  335. {
  336. ASSERT(pstrlist);
  337. if (pstrlist == NULL)
  338. return FALSE;
  339. pstrlist->RemoveAll();
  340. if (m_pHistoryRoot == NULL)
  341. {
  342. ASSERT(0 && "Root node is not yet created");
  343. }
  344. CComPtr<IXMLDOMDocument> pXMLDoc = GetXMLDoc();
  345. CComPtr<IXMLDOMNode> pDCNode;
  346. HRESULT hr = GetDataCollectionNode( pXMLDoc,pDCNode);
  347. if (FAILED(hr) || !pDCNode)
  348. {
  349. return FALSE;
  350. }
  351. CComPtr<IXMLDOMNodeList> pList;
  352. hr = pDCNode->selectNodes(L"Delta",&pList);
  353. if (FAILED(hr) || !pList)
  354. {
  355. ASSERT(0 && "could not get list of delta nodes");
  356. return FALSE;
  357. }
  358. long lListLen;
  359. hr = pList->get_length(&lListLen);
  360. if (lListLen == 0)
  361. {
  362. //we may have an incident file, which capitalizes "DELTA"
  363. pList.Release();
  364. hr = pDCNode->selectNodes(L"DELTA",&pList);
  365. if (FAILED(hr) || !pList)
  366. {
  367. ASSERT(0 && "could not get list of delta nodes");
  368. return FALSE;
  369. }
  370. hr = pList->get_length(&lListLen);
  371. }
  372. if (lListLen > 0)
  373. {
  374. CComPtr<IXMLDOMNode> pDeltaNode;
  375. CString strDate(_T(""));
  376. TCHAR szBuffer[MAX_PATH]; // seems plenty big
  377. for(long i = 0 ;i < lListLen;i++)
  378. {
  379. hr = pList->nextNode(&pDeltaNode);
  380. if (FAILED(hr) || !pDeltaNode)
  381. {
  382. ASSERT(0 && "could not get next node from list");
  383. break;
  384. }
  385. CComVariant varTS;
  386. CComPtr<IXMLDOMElement> pTimestampElement;
  387. hr = pDeltaNode->QueryInterface(IID_IXMLDOMElement,(void**) &pTimestampElement);
  388. pDeltaNode.Release();
  389. if (FAILED(hr) || !pTimestampElement)
  390. {
  391. ASSERT(0 && "could not get attribute element");
  392. break;
  393. }
  394. hr = pTimestampElement->getAttribute(L"Timestamp_T0",&varTS);
  395. if (FAILED(hr) )
  396. {
  397. ASSERT(0 && "could not get timestamp value from attribute");
  398. }
  399. //now get time zone (number of seconds difference between local time and UTC)
  400. CComVariant varTzoneDeltaSeconds;
  401. hr = pTimestampElement->getAttribute(L"TimeZone",&varTzoneDeltaSeconds);
  402. if (FAILED(hr) ) //this will happen when loading WinME xml, which has no timezone info
  403. {
  404. varTzoneDeltaSeconds = 0;
  405. }
  406. //make sure we have an integer type
  407. hr = varTzoneDeltaSeconds.ChangeType(VT_INT);
  408. if (FAILED(hr) )
  409. {
  410. varTzoneDeltaSeconds = 0;
  411. }
  412. USES_CONVERSION;
  413. pTimestampElement.Release();
  414. CString strTimestamp = OLE2A(varTS.bstrVal);
  415. CTime tm1 = GetDateFromString(strTimestamp,varTzoneDeltaSeconds.intVal);
  416. COleDateTime olDate(tm1.GetTime());
  417. // Try to get the date in the localized format.
  418. strDate.Empty();
  419. SYSTEMTIME systime;
  420. if (olDate.GetAsSystemTime(systime))
  421. {
  422. DWORD dwLayout = 0;
  423. ::GetProcessDefaultLayout(&dwLayout);
  424. // For some reason, in HEB we don't want to use the DATE_RTLREADING flag. Bug 434802.
  425. if (LANG_HEBREW == PRIMARYLANGID(::GetUserDefaultUILanguage()))
  426. dwLayout &= ~LAYOUT_RTL; // force the non-use of DATE_RTLREADING
  427. if (::GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE | (((dwLayout & LAYOUT_RTL) != 0) ? DATE_RTLREADING : 0), &systime, NULL, szBuffer, MAX_PATH))
  428. {
  429. strDate = szBuffer;
  430. if (::GetTimeFormat(LOCALE_USER_DEFAULT, 0, &systime, NULL, szBuffer, MAX_PATH))
  431. strDate += CString(_T(" ")) + CString(szBuffer);
  432. }
  433. }
  434. // Fall back on our old (partially incorrect) method.
  435. if (strDate.IsEmpty())
  436. strDate = olDate.Format(0, LOCALE_USER_DEFAULT);
  437. pstrlist->AddTail(strDate);
  438. }
  439. }
  440. return TRUE;
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Return an HRESULT indicating whether or not this is a valid data source.
  444. // This is primarily useful when we're remoting to a machine and we want to
  445. // determine if the network name is accessible.
  446. //-----------------------------------------------------------------------------
  447. HRESULT CLiveDataSource::ValidDataSource()
  448. {
  449. if (m_pThread == NULL)
  450. return E_FAIL;
  451. return (m_pThread->CheckWMIConnection());
  452. }
  453. //=============================================================================
  454. // CMSInfoLiveCategory
  455. //=============================================================================
  456. //-----------------------------------------------------------------------------
  457. // The constructor needs to initialize some member variables, and make sure
  458. // that the category is inserted into the tree correctly.
  459. //-----------------------------------------------------------------------------
  460. CMSInfoLiveCategory::CMSInfoLiveCategory(UINT uiCaption, LPCTSTR szName, RefreshFunction pFunction, DWORD dwRefreshIndex, CMSInfoCategory * pParent, CMSInfoCategory * pPrevious, const CString & strHelpTopic, CMSInfoColumn * pColumns, BOOL fDynamicColumns, CategoryEnvironment environment) :
  461. CMSInfoCategory(uiCaption, szName, pParent, pPrevious, pColumns, fDynamicColumns, environment),
  462. m_pRefreshFunction(pFunction),
  463. m_dwLastRefresh(0),
  464. m_dwRefreshIndex(dwRefreshIndex),
  465. m_strMachine(_T("")),
  466. m_strHelpTopic(strHelpTopic)
  467. {
  468. // Insert ourselves into the category tree. This means making sure that
  469. // our parent and previous sibling point to us.
  470. if (m_pParent && m_pParent->m_pFirstChild == NULL)
  471. m_pParent->m_pFirstChild = this;
  472. if (m_pPrevSibling)
  473. {
  474. if (m_pPrevSibling->m_pNextSibling == NULL)
  475. m_pPrevSibling->m_pNextSibling = this;
  476. else
  477. {
  478. CMSInfoCategory * pScan = m_pPrevSibling->m_pNextSibling;
  479. while (pScan->m_pNextSibling)
  480. pScan = pScan->m_pNextSibling;
  481. pScan->m_pNextSibling = this;
  482. }
  483. }
  484. }
  485. CMSInfoLiveCategory::~CMSInfoLiveCategory()
  486. {
  487. }
  488. //-----------------------------------------------------------------------------
  489. // The copy constructor will copy the members, but not allocate a new sub-tree
  490. // (the new category has the same children and siblings as the original).
  491. //-----------------------------------------------------------------------------
  492. CMSInfoLiveCategory::CMSInfoLiveCategory(CMSInfoLiveCategory & copyfrom) :
  493. m_dwLastRefresh(0),
  494. m_dwRefreshIndex(copyfrom.m_dwRefreshIndex),
  495. m_pRefreshFunction(copyfrom.m_pRefreshFunction)
  496. {
  497. m_strMachine = copyfrom.m_strMachine;
  498. m_strHelpTopic = copyfrom.m_strHelpTopic;
  499. m_uiCaption = copyfrom.m_uiCaption;
  500. m_pParent = copyfrom.m_pParent;
  501. m_pPrevSibling = copyfrom.m_pPrevSibling;
  502. m_pFirstChild = copyfrom.m_pFirstChild;
  503. m_pNextSibling = copyfrom.m_pNextSibling;
  504. m_astrData = NULL;
  505. m_adwData = NULL;
  506. m_afRowAdvanced = NULL;
  507. m_strName = copyfrom.m_strName;
  508. m_hrError = S_OK;
  509. m_acolumns = copyfrom.m_acolumns;
  510. m_fDynamicColumns = FALSE;
  511. m_iRowCount = 0;
  512. m_iColCount = copyfrom.m_iColCount;
  513. m_iSortColumn = copyfrom.m_iSortColumn;
  514. m_hti = NULL;
  515. m_fSkipCategory = copyfrom.m_fSkipCategory;
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Constructs a category from an old (version 5.0) category structure.
  519. //-----------------------------------------------------------------------------
  520. extern HRESULT RefreshExtensions(CWMIHelper * pWMI, DWORD dwIndex, volatile BOOL * pfCancel, CPtrList * aColValues, int iColCount, void ** ppCache);
  521. CMSInfoLiveCategory::CMSInfoLiveCategory(INTERNAL_CATEGORY * pinternalcat)
  522. {
  523. ASSERT(pinternalcat);
  524. if (pinternalcat == NULL)
  525. return;
  526. m_dwLastRefresh = 0;
  527. m_strMachine = CString(_T(""));
  528. m_strHelpTopic = CString(_T(""));
  529. // Graft on a help topic for the IE extension (bug 479839).
  530. if (pinternalcat->m_strIdentifier.CompareNoCase(_T("InternetSettings")) == 0)
  531. m_strHelpTopic = _T("msinfo_internet_settings.htm");
  532. m_strCaption = pinternalcat->m_fieldName.m_strFormat;
  533. m_strName = pinternalcat->m_strIdentifier;
  534. m_iRowCount = 0;
  535. m_iColCount = 0;
  536. GATH_FIELD * pField = pinternalcat->m_pColSpec;
  537. while (pField)
  538. {
  539. m_iColCount += 1;
  540. pField = pField->m_pNext;
  541. }
  542. if (m_iColCount)
  543. {
  544. m_acolumns = new CMSInfoColumn[m_iColCount];
  545. if (m_acolumns && pinternalcat->m_pColSpec)
  546. {
  547. m_fDynamicColumns = TRUE;
  548. pField = pinternalcat->m_pColSpec;
  549. for (int iCol = 0; iCol < m_iColCount && pField != NULL; iCol++)
  550. {
  551. m_acolumns[iCol].m_fAdvanced = (pField->m_datacomplexity == ADVANCED);
  552. m_acolumns[iCol].m_strCaption = pField->m_strFormat;
  553. m_acolumns[iCol].m_uiWidth = pField->m_usWidth;
  554. m_acolumns[iCol].m_fSorts = (pField->m_sort != NOSORT);
  555. m_acolumns[iCol].m_fLexical = (pField->m_sort == LEXICAL);
  556. pField = pField->m_pNext;
  557. }
  558. }
  559. }
  560. // Insert the information needed to refresh the extension category (such
  561. // as line specs) into a map, indexed by a DWORD. That DWORD will be saved
  562. // for the category, so we can look up the refresh data later.
  563. if (pinternalcat->m_pLineSpec)
  564. {
  565. m_dwRefreshIndex = gmapExtensionRefreshData.Insert(pinternalcat->m_pLineSpec);
  566. pinternalcat->m_pLineSpec = NULL; // keep this from being deleted
  567. m_pRefreshFunction = &RefreshExtensions;
  568. }
  569. else
  570. {
  571. m_dwRefreshIndex = 0;
  572. m_pRefreshFunction = NULL;
  573. }
  574. if (m_dwRefreshIndex)
  575. gmapExtensionRefreshData.InsertString(m_dwRefreshIndex, pinternalcat->m_strNoInstances);
  576. }
  577. //-----------------------------------------------------------------------------
  578. // Start a refresh (starts the thread, which will send a message when it's
  579. // done).
  580. //-----------------------------------------------------------------------------
  581. BOOL CMSInfoLiveCategory::Refresh(CLiveDataSource * pSource, BOOL fRecursive)
  582. {
  583. if (pSource && pSource->m_pThread)
  584. pSource->m_pThread->StartRefresh(this, fRecursive);
  585. return TRUE;
  586. }
  587. //-----------------------------------------------------------------------------
  588. // Start a synchronous refresh. This function won't return until the refresh
  589. // has been completed.
  590. //-----------------------------------------------------------------------------
  591. BOOL CMSInfoLiveCategory::RefreshSynchronous(CLiveDataSource * pSource, BOOL fRecursive)
  592. {
  593. if (pSource && pSource->m_pThread)
  594. {
  595. pSource->m_pThread->StartRefresh(this, fRecursive);
  596. pSource->m_pThread->WaitForRefresh();
  597. }
  598. return TRUE;
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Refreshes the current category (and possibly the children) while presenting
  602. // the user with a UI. A dialog box is presented to the user with the specified
  603. // mesage. If the user clicks cancel, the refresh is cancelled and this
  604. // function returns false. Otherwise, when the refresh is done the dialog box
  605. // will be removed, and this funcion returns true.
  606. //-----------------------------------------------------------------------------
  607. BOOL CMSInfoLiveCategory::RefreshSynchronousUI(CLiveDataSource * pSource, BOOL fRecursive, UINT uiMessage, HWND hwnd)
  608. {
  609. if (pSource && pSource->m_pThread)
  610. {
  611. pSource->m_pThread->StartRefresh(this, fRecursive);
  612. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  613. CWnd * pWnd = CWnd::FromHandle(hwnd);
  614. // CRefreshDialog refreshdialog(pWnd);
  615. // refreshdialog.DoModal();
  616. if (pSource->m_pThread->IsRefreshing())
  617. {
  618. pSource->m_pThread->CancelRefresh();
  619. return FALSE;
  620. }
  621. }
  622. return TRUE;
  623. }
  624. //-----------------------------------------------------------------------------
  625. // Get the error strings for this category (subclasses should override this).
  626. //-----------------------------------------------------------------------------
  627. void CMSInfoLiveCategory::GetErrorText(CString * pstrTitle, CString * pstrMessage)
  628. {
  629. if (SUCCEEDED(m_hrError))
  630. {
  631. ASSERT(0 && "why call GetErrorText for no error?");
  632. CMSInfoCategory::GetErrorText(pstrTitle, pstrMessage);
  633. return;
  634. }
  635. if (pstrTitle)
  636. pstrTitle->LoadString(IDS_CANTCOLLECT);
  637. if (pstrMessage)
  638. {
  639. switch (m_hrError)
  640. {
  641. case WBEM_E_OUT_OF_MEMORY:
  642. pstrMessage->LoadString(IDS_OUTOFMEMERROR);
  643. break;
  644. case WBEM_E_ACCESS_DENIED:
  645. if (m_strMachine.IsEmpty())
  646. pstrMessage->LoadString(IDS_GATHERACCESS_LOCAL);
  647. else
  648. pstrMessage->Format(IDS_GATHERACCESS, m_strMachine);
  649. break;
  650. case WBEM_E_INVALID_NAMESPACE:
  651. if (m_strMachine.IsEmpty())
  652. pstrMessage->LoadString(IDS_BADSERVER_LOCAL);
  653. else
  654. pstrMessage->Format(IDS_BADSERVER, m_strMachine);
  655. break;
  656. case 0x800706BA: // RPC Server Unavailable
  657. case WBEM_E_TRANSPORT_FAILURE:
  658. if (m_strMachine.IsEmpty())
  659. pstrMessage->LoadString(IDS_NETWORKERROR_LOCAL);
  660. else
  661. pstrMessage->Format(IDS_NETWORKERROR, m_strMachine);
  662. break;
  663. case WBEM_E_FAILED:
  664. case WBEM_E_INVALID_PARAMETER:
  665. default:
  666. pstrMessage->LoadString(IDS_UNEXPECTED);
  667. }
  668. #ifdef _DEBUG
  669. {
  670. CString strTemp;
  671. strTemp.Format(_T("\n\r\n\rDebug Version Only: [HRESULT = 0x%08X]"), m_hrError);
  672. *pstrMessage += strTemp;
  673. }
  674. #endif
  675. }
  676. }
  677. //=============================================================================
  678. // CMSInfoHistoryCategory
  679. //=============================================================================
  680. //-----------------------------------------------------------------------------
  681. // This refresh overrides the live category refresh (which starts a WMI refresh
  682. // using another thread). This version just fills in the variables from the
  683. // base classes (like m_astrData) based on which category we're view in
  684. // history mode.
  685. //-----------------------------------------------------------------------------
  686. extern CMSInfoHistoryCategory catHistorySystemSummary;
  687. extern CMSInfoHistoryCategory catHistoryResources;
  688. extern CMSInfoHistoryCategory catHistoryComponents;
  689. extern CMSInfoHistoryCategory catHistorySWEnv;
  690. BOOL CMSInfoHistoryCategory::Refresh(CLiveDataSource * pSource, BOOL fRecursive)
  691. {
  692. HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  693. if (pSource->GetXMLDoc())
  694. {
  695. CHistoryParser HParser(pSource->GetXMLDoc());
  696. HRESULT hr = HParser.Refresh(this, pSource->m_iDeltaIndex );
  697. if (HParser.AreThereChangeLines() == TRUE)
  698. {
  699. //commitlines doesn't like it if there are no change lines
  700. this->CommitLines();
  701. }
  702. if (pSource->m_hwnd)
  703. ::PostMessage(pSource->m_hwnd, WM_MSINFODATAREADY, 0, (LPARAM)this);
  704. m_dwLastRefresh = ::GetTickCount();
  705. if (fRecursive)
  706. {
  707. for(CMSInfoCategory* pChildCat = (CMSInfoCategory*) this->GetFirstChild();pChildCat != NULL;pChildCat = (CMSInfoCategory*) pChildCat->GetNextSibling())
  708. {
  709. if(pChildCat->GetDataSourceType() == LIVE_DATA)
  710. {
  711. if (!((CMSInfoHistoryCategory*)pChildCat)->Refresh(pSource,fRecursive))
  712. {
  713. ::SetCursor(hc);
  714. return FALSE;
  715. }
  716. }
  717. }
  718. }
  719. }
  720. ::SetCursor(hc);
  721. return TRUE;
  722. }
  723. //-----------------------------------------------------------------------------
  724. // Call ClearLines before lines are inserted in the output.
  725. //-----------------------------------------------------------------------------
  726. void CMSInfoHistoryCategory::ClearLines()
  727. {
  728. DeleteContent();
  729. for (int iCol = 0; iCol < 5; iCol++)
  730. while (!m_aValList[iCol].IsEmpty())
  731. delete (CMSIValue *) m_aValList[iCol].RemoveHead();
  732. }
  733. //-----------------------------------------------------------------------------
  734. // Call CommitLines after all of the Insert operations are completed. This will
  735. // transfer the values from the lists of CMSIValues to the data arrays.
  736. //-----------------------------------------------------------------------------
  737. void CMSInfoHistoryCategory::CommitLines()
  738. {
  739. int iRowCount = (int)m_aValList[0].GetCount();
  740. #ifdef _DEBUG
  741. for (int i = 0; i < 5; i++)
  742. ASSERT(iRowCount == m_aValList[i].GetCount());
  743. #endif
  744. if (iRowCount)
  745. AllocateContent(iRowCount);
  746. for (int j = 0; j < 5; j++)
  747. for (int i = 0; i < m_iRowCount; i++)
  748. {
  749. CMSIValue * pValue = (CMSIValue *) m_aValList[j].RemoveHead();
  750. if (j < 4 || this != &catHistorySystemSummary)
  751. SetData(i, j, pValue->m_strValue, pValue->m_dwValue);
  752. // Set the advanced flag for either the first column, or
  753. // for any column which is advanced (any cell in a row
  754. // being advanced makes the whole row advanced).
  755. if (j == 0 || pValue->m_fAdvanced)
  756. SetAdvancedFlag(i, pValue->m_fAdvanced);
  757. delete pValue;
  758. }
  759. }
  760. //-----------------------------------------------------------------------------
  761. // Various functions to insert different types of events in the history.
  762. //-----------------------------------------------------------------------------
  763. void CMSInfoHistoryCategory::InsertChangeLine(CTime tm, LPCTSTR szType, LPCTSTR szName, LPCTSTR szProperty, LPCTSTR szFromVal, LPCTSTR szToVal)
  764. {
  765. CString strDetails;
  766. strDetails.Format(IDS_DELTACHANGE, szProperty, szFromVal, szToVal);
  767. CString strCaption;
  768. strCaption.LoadString(IDS_HISTORYCHANGE);
  769. InsertLine(tm, strCaption, szType, szName, strDetails);
  770. }
  771. void CMSInfoHistoryCategory::InsertAddLine(CTime tm, LPCTSTR szType, LPCTSTR szName)
  772. {
  773. CString strCaption;
  774. strCaption.LoadString(IDS_HISTORYADDED);
  775. InsertLine(tm, strCaption, szType, szName);
  776. }
  777. void CMSInfoHistoryCategory::InsertRemoveLine(CTime tm, LPCTSTR szType, LPCTSTR szName)
  778. {
  779. CString strCaption;
  780. strCaption.LoadString(IDS_HISTORYREMOVED);
  781. InsertLine(tm, strCaption, szType, szName);
  782. }
  783. void CMSInfoHistoryCategory::InsertLine(CTime tm, LPCTSTR szOperation, LPCTSTR szType, LPCTSTR szName, LPCTSTR szDetails)
  784. {
  785. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  786. /*CString strTime;
  787. if (nDays >= 0)
  788. {
  789. strTime.Format(IDS_DAYSAGO, nDays + 1);
  790. }
  791. else
  792. {
  793. //-1 indicates no changes
  794. strTime = "";
  795. }*/
  796. COleDateTime olTime;
  797. CString strTime;
  798. if (-1 == (int) tm.GetTime())
  799. {
  800. strTime.LoadString(IDS_NOHISTORY_AVAILABLE);
  801. }
  802. else
  803. {
  804. olTime = tm.GetTime();
  805. strTime = olTime.Format();
  806. }
  807. CMSIValue * pValue = new CMSIValue(strTime, (DWORD)olTime.m_dt);
  808. m_aValList[0].AddTail((void *) pValue);
  809. pValue = new CMSIValue(szOperation, 0);
  810. m_aValList[1].AddTail((void *) pValue);
  811. pValue = new CMSIValue(szName, 0);
  812. m_aValList[2].AddTail((void *) pValue);
  813. if (szDetails)
  814. pValue = new CMSIValue(szDetails, 0);
  815. else
  816. pValue = new CMSIValue(_T(""), 0);
  817. m_aValList[3].AddTail((void *) pValue);
  818. pValue = new CMSIValue(szType, 0);
  819. m_aValList[4].AddTail((void *) pValue);
  820. }
  821. /*void CMSInfoHistoryCategory::InsertChangeLine(int nDays, LPCTSTR szType, LPCTSTR szName, LPCTSTR szProperty, LPCTSTR szFromVal, LPCTSTR szToVal)
  822. {
  823. CString strDetails;
  824. strDetails.Format(IDS_DELTACHANGE, szProperty, szFromVal, szToVal);
  825. InsertLine(nDays, _T("CHANGED"), szType, szName, strDetails);
  826. }
  827. void CMSInfoHistoryCategory::InsertAddLine(int nDays, LPCTSTR szType, LPCTSTR szName)
  828. {
  829. InsertLine(nDays, _T("ADDED"), szType, szName);
  830. }
  831. void CMSInfoHistoryCategory::InsertRemoveLine(int nDays, LPCTSTR szType, LPCTSTR szName)
  832. {
  833. InsertLine(nDays, _T("REMOVED"), szType, szName);
  834. }
  835. void CMSInfoHistoryCategory::InsertLine(int nDays, LPCTSTR szOperation, LPCTSTR szType, LPCTSTR szName, LPCTSTR szDetails)
  836. {
  837. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  838. CString strTime;
  839. if (nDays >= 0)
  840. {
  841. strTime.Format(IDS_DAYSAGO, nDays + 1);
  842. }
  843. else
  844. {
  845. //-1 indicates no changes
  846. strTime = "";
  847. }
  848. CMSIValue * pValue = new CMSIValue(strTime, (DWORD)nDays);
  849. m_aValList[0].AddTail((void *) pValue);
  850. pValue = new CMSIValue(szOperation, 0);
  851. m_aValList[1].AddTail((void *) pValue);
  852. pValue = new CMSIValue(szName, 0);
  853. m_aValList[2].AddTail((void *) pValue);
  854. if (szDetails)
  855. pValue = new CMSIValue(szDetails, 0);
  856. else
  857. pValue = new CMSIValue(_T(""), 0);
  858. m_aValList[3].AddTail((void *) pValue);
  859. pValue = new CMSIValue(szType, 0);
  860. m_aValList[4].AddTail((void *) pValue);
  861. }
  862. */