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.

1165 lines
35 KiB

  1. // HistoryParser.cpp: implementation of the CHistoryParser class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "resource.h"
  6. #include "HistoryParser.h"
  7. #include "Filestuff.h"
  8. #ifdef _DEBUG
  9. #undef THIS_FILE
  10. static char THIS_FILE[]=__FILE__;
  11. #define new DEBUG_NEW
  12. #endif
  13. extern CMSInfoHistoryCategory catHistorySystemSummary;
  14. extern CMSInfoHistoryCategory catHistoryResources;
  15. extern CMSInfoHistoryCategory catHistoryComponents;
  16. extern CMSInfoHistoryCategory catHistorySWEnv;
  17. //////////////////////////////////////////////////////////////////////
  18. // Construction/Destruction
  19. //////////////////////////////////////////////////////////////////////
  20. CHistoryParser::CHistoryParser(CComPtr<IXMLDOMDocument> pDoc) : m_pDoc(pDoc)
  21. {
  22. }
  23. void CHistoryParser::DeleteAllInstances()
  24. {
  25. for(POSITION pos = this->m_listInstances.GetHeadPosition();pos;)
  26. {
  27. if (!pos)
  28. {
  29. return;
  30. }
  31. CInstance* pInci = (CInstance*) m_listInstances.GetNext(pos);
  32. delete pInci;
  33. }
  34. m_listInstances.RemoveAll();
  35. }
  36. CHistoryParser::~CHistoryParser()
  37. {
  38. DeleteAllInstances();
  39. }
  40. //////////////////////////////////////////////////////////////////////
  41. // Construction/Destruction
  42. // takes a CTime, which comes from timestamp element of the Delta or Snaphot
  43. // node of which pInstanceNode is a child; an Instance node, and a string
  44. // containing the WMI class of the Instance
  45. //////////////////////////////////////////////////////////////////////
  46. CInstance::CInstance(CTime tmstmp, CComPtr<IXMLDOMNode> pInstanceNode,CString strClass) : m_tmstamp(tmstmp), m_strClassName(strClass)
  47. {
  48. CComPtr<IXMLDOMNodeList> pPropList;
  49. HRESULT hr;
  50. //Get node data, add each PROPERTY name and VALUE to m_mapNameValue
  51. if (strClass.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0)
  52. {
  53. hr = ProcessPNPAllocatedResource(pInstanceNode);
  54. ASSERT(SUCCEEDED(hr) && "failed to process Win32_PNPAllocatedResource");
  55. return;
  56. }
  57. hr = pInstanceNode->selectNodes(CComBSTR("PROPERTY"),&pPropList);
  58. if (FAILED(hr) || !pPropList)
  59. {
  60. ASSERT(0 && "could not get property list from Instance node");
  61. return;
  62. }
  63. long lListLen;
  64. hr = pPropList->get_length(&lListLen);
  65. CComPtr<IXMLDOMNode> pVNode;
  66. CComBSTR bstrValue;
  67. CComVariant varName;
  68. for(long i = 0; i < lListLen; i++)
  69. {
  70. hr = pPropList->nextNode(&pVNode);
  71. if (FAILED(hr) || !pVNode)
  72. {
  73. return;
  74. }
  75. CComPtr<IXMLDOMElement> pElement;
  76. hr = pVNode->QueryInterface(IID_IXMLDOMElement,(void**) &pElement);
  77. if (FAILED(hr) || !pElement)
  78. {
  79. return;
  80. }
  81. hr = pElement->getAttribute(L"NAME",&varName);
  82. ASSERT(SUCCEEDED(hr));
  83. hr = pVNode->get_text(&bstrValue);
  84. ASSERT(SUCCEEDED(hr));
  85. USES_CONVERSION;
  86. m_mapNameValue.SetAt(OLE2T(varName.bstrVal) ,OLE2T(bstrValue));
  87. pVNode.Release();
  88. }
  89. pPropList.Release();
  90. return;
  91. }
  92. //////////////////////////////////////////////////////////////////////////////////////////
  93. //Refresh is called for selected category when category selection or delta range changes
  94. //////////////////////////////////////////////////////////////////////////////////////////
  95. HRESULT CHistoryParser::Refresh(CMSInfoHistoryCategory* pHistCat,int nDeltasBack)
  96. {
  97. nDeltasBack++;
  98. this->m_fChangeLines = FALSE;// v-stlowe 2/28/2001
  99. DeleteAllInstances();
  100. m_pHistCat = pHistCat;
  101. CComPtr<IXMLDOMNodeList> pDeltaList;
  102. HRESULT hr;
  103. hr = this->GetDeltaAndSnapshotNodes(pDeltaList);
  104. if (FAILED(hr) || !pDeltaList)
  105. {
  106. return E_FAIL;
  107. }
  108. if (pHistCat == &catHistoryComponents)
  109. {
  110. DeleteAllInstances();
  111. hr = ProcessDeltas(pDeltaList,"Win32_DriverVXD",nDeltasBack);
  112. ASSERT(SUCCEEDED(hr));
  113. DeleteAllInstances();
  114. pDeltaList->reset();
  115. hr = ProcessDeltas(pDeltaList,"Win32_CodecFile",nDeltasBack);
  116. ASSERT(SUCCEEDED(hr));
  117. DeleteAllInstances();
  118. pDeltaList->reset();
  119. hr = ProcessDeltas(pDeltaList,"Win32_LogicalDisk",nDeltasBack);
  120. DeleteAllInstances();
  121. pDeltaList->reset();
  122. ASSERT(SUCCEEDED(hr));
  123. hr = ProcessDeltas(pDeltaList,"Win32_NetworkProtocol",nDeltasBack);
  124. DeleteAllInstances();
  125. pDeltaList->reset();
  126. ASSERT(SUCCEEDED(hr));
  127. hr = ProcessDeltas(pDeltaList,"Win32_Printer",nDeltasBack);
  128. DeleteAllInstances();
  129. pDeltaList->reset();
  130. ASSERT(SUCCEEDED(hr));
  131. hr = ProcessDeltas(pDeltaList,"Win32_PortResource",nDeltasBack);
  132. DeleteAllInstances();
  133. pDeltaList->reset();
  134. ASSERT(SUCCEEDED(hr));
  135. hr = ProcessDeltas(pDeltaList,"Win32_PnPEntity",nDeltasBack);
  136. DeleteAllInstances();
  137. pDeltaList->reset();
  138. ASSERT(SUCCEEDED(hr));
  139. }
  140. else if (pHistCat == &catHistorySystemSummary)
  141. {
  142. DeleteAllInstances();
  143. hr = ProcessDeltas(pDeltaList,"Win32_ComputerSystem",nDeltasBack);
  144. DeleteAllInstances();
  145. pDeltaList->reset();
  146. ASSERT(SUCCEEDED(hr));
  147. hr = ProcessDeltas(pDeltaList,"Win32_OperatingSystem",nDeltasBack);
  148. DeleteAllInstances();
  149. pDeltaList->reset();
  150. ASSERT(SUCCEEDED(hr));
  151. //hr = ProcessDeltas(pDeltaList,"Win32_Win32_LogicalMemoryConfiguration",nDeltasBack);
  152. hr = ProcessDeltas(pDeltaList,"Win32_LogicalMemoryConfiguration",nDeltasBack); //v-stlowe 2/28/2001
  153. DeleteAllInstances();
  154. pDeltaList->reset();
  155. ASSERT(SUCCEEDED(hr));
  156. }
  157. else if(pHistCat == &catHistoryResources)
  158. {
  159. DeleteAllInstances();
  160. hr = ProcessDeltas(pDeltaList,"Win32_PNPAllocatedResource",nDeltasBack);
  161. DeleteAllInstances();
  162. pDeltaList->reset();
  163. ASSERT(SUCCEEDED(hr));
  164. }
  165. else if (pHistCat == &catHistorySWEnv)
  166. {
  167. DeleteAllInstances();
  168. hr = ProcessDeltas(pDeltaList,"Win32_ProgramGroup",nDeltasBack);
  169. DeleteAllInstances();
  170. pDeltaList->reset();
  171. hr = ProcessDeltas(pDeltaList,"Win32_StartupCommand",nDeltasBack);
  172. DeleteAllInstances();
  173. pDeltaList->reset();
  174. }
  175. if (!m_fChangeLines)
  176. {
  177. #ifdef A_STEPHL2
  178. ::MessageBox(NULL,"!m_fChangeLines)","",MB_OK);
  179. #endif
  180. m_fChangeLines = TRUE;
  181. CString strMSG;
  182. strMSG.LoadString(IDS_DELTANOCHANGES);//this would be the place to change messaging for situation where summary has no changes
  183. m_pHistCat->InsertLine(-1, strMSG, _T(""), _T(""), _T(""));
  184. }
  185. pDeltaList.Release();
  186. return hr;
  187. }
  188. //////////////////////////////////////////////////////////////////////////////////////////
  189. //Gets the value appropriate to use as a description for the class
  190. //////////////////////////////////////////////////////////////////////////////////////////
  191. CString CInstance::GetInstanceDescription()
  192. {
  193. CString strDescName = GetDescriptionForClass(m_strClassName);
  194. CString strInstDesc;
  195. VERIFY(m_mapNameValue.Lookup(strDescName,strInstDesc));
  196. return strInstDesc;
  197. }
  198. //////////////////////////////////////////////////////////////////////////////////////////
  199. //Gets the value that can be used to uniquely identify a specific instance of a class
  200. //////////////////////////////////////////////////////////////////////////////////////////
  201. CString CInstance::GetInstanceID()
  202. {
  203. CString strIDName = GetIDForClass(m_strClassName);
  204. CString strInstID;
  205. VERIFY(m_mapNameValue.Lookup(strIDName,strInstID));
  206. return strInstID;
  207. }
  208. //////////////////////////////////////////////////////////////////////////////////////////
  209. //used to deal with antecedent\dependant relationship classes in Win32_PNPAllocatedResource classes
  210. //////////////////////////////////////////////////////////////////////////////////////////
  211. HRESULT CInstance::ProcessPropertyDotReferenceNodes(CComPtr<IXMLDOMNode> pInstanceNameNode,CString* pstrClassName, CString* pstrKeyName,CString* pstrKeyValue)
  212. {
  213. USES_CONVERSION;
  214. HRESULT hr;
  215. CComPtr<IXMLDOMElement> pNameElement;
  216. hr = pInstanceNameNode->QueryInterface(IID_IXMLDOMElement,(void**) &pNameElement);
  217. if (FAILED(hr) | !pNameElement)
  218. {
  219. ASSERT(0 && "could not QI pNode for Element");
  220. return E_FAIL;
  221. }
  222. CComVariant varClassName;
  223. hr = pNameElement->getAttribute(L"CLASSNAME",&varClassName);
  224. pNameElement.Release();
  225. if (FAILED(hr))
  226. {
  227. ASSERT(0 && "could not get CLASSNAME element");
  228. }
  229. *pstrClassName = OLE2T(varClassName.bstrVal);
  230. CComPtr<IXMLDOMNode> pKeybindingNode;
  231. hr = pInstanceNameNode->selectSingleNode(CComBSTR("KEYBINDING"),&pKeybindingNode);
  232. if (FAILED(hr) || !pKeybindingNode)
  233. {
  234. ASSERT(0 && "could not get antecedent node");
  235. }
  236. CComBSTR bstrKeyValue;
  237. hr = pKeybindingNode->get_text(&bstrKeyValue);
  238. ASSERT(SUCCEEDED(hr) && "failed to get keybinding value");
  239. *pstrKeyValue = OLE2T(bstrKeyValue);
  240. hr = pKeybindingNode->QueryInterface(IID_IXMLDOMElement,(void**) &pNameElement);
  241. if (FAILED(hr) | !pNameElement)
  242. {
  243. ASSERT(0 && "could not QI pNode for Element");
  244. return E_FAIL;
  245. }
  246. CComVariant varKeybindingName;
  247. hr = pNameElement->getAttribute(CComBSTR("NAME"),&varKeybindingName);
  248. if (FAILED(hr))
  249. {
  250. ASSERT(0 && "could not get NAME attribute from pNameElement");
  251. }
  252. *pstrKeyName = OLE2T(varKeybindingName.bstrVal);
  253. return hr;
  254. }
  255. //////////////////////////////////////////////////////////////////////////////////////////
  256. //used to deal with antecedent\dependant relationship classes in Win32_PNPAllocatedResource classes
  257. //////////////////////////////////////////////////////////////////////////////////////////
  258. HRESULT CInstance::ProcessPNPAllocatedResource(CComPtr<IXMLDOMNode> pInstanceNode)
  259. {
  260. HRESULT hr;
  261. CComPtr<IXMLDOMNodeList> pPropDotRefList;
  262. hr = pInstanceNode->selectNodes(CComBSTR("PROPERTY.REFERENCE/VALUE.REFERENCE/INSTANCEPATH/INSTANCENAME"),&pPropDotRefList);
  263. if (FAILED(hr) || !pPropDotRefList)
  264. {
  265. ASSERT(0 && "PROPERTY.REFERENCE nodes not found");
  266. return E_FAIL;
  267. }
  268. //get antecedent node
  269. CComPtr<IXMLDOMNode> pInstanceNameNode;
  270. hr = pPropDotRefList->nextNode(&pInstanceNameNode);
  271. if (FAILED(hr) || !pInstanceNameNode)
  272. {
  273. ASSERT(0 && "could not get antecedent node");
  274. }
  275. CString strAntecedentName,strResourceName,strResourceValue;
  276. hr = ProcessPropertyDotReferenceNodes(pInstanceNameNode,&strAntecedentName,&strResourceName,&strResourceValue);
  277. m_mapNameValue.SetAt(_T("ANTECEDENT"),strAntecedentName);
  278. m_mapNameValue.SetAt(strResourceName,strResourceValue);
  279. if (FAILED(hr))
  280. {
  281. return hr;
  282. }
  283. CString strPNPEntity,strKeyname,strDeviceIDval;
  284. pInstanceNameNode.Release();
  285. hr = pPropDotRefList->nextNode(&pInstanceNameNode);
  286. if (FAILED(hr) || !pInstanceNameNode)
  287. {
  288. return hr;
  289. }
  290. hr = ProcessPropertyDotReferenceNodes(pInstanceNameNode,&strPNPEntity,&strKeyname,&strDeviceIDval);
  291. CComPtr<IXMLDOMDocument> pDoc;
  292. hr = pInstanceNode->get_ownerDocument(&pDoc);
  293. if (FAILED(hr) || !pDoc)
  294. {
  295. ASSERT(0 && "could not get owner doc from pInstanceNode");
  296. return E_FAIL;
  297. }
  298. CString strPNPDeviceName = GetPNPNameByID(pDoc,CComBSTR(strDeviceIDval));
  299. if (FAILED(hr))
  300. {
  301. return hr;
  302. }
  303. ASSERT(strPNPEntity.CompareNoCase("Win32_PnPEntity") == 0 && "unexpected value for Dependent classname");
  304. ASSERT(strKeyname.CompareNoCase("DeviceID") == 0 && "unexpected value for Dependent Keybinding name");
  305. //we will create an arificial attribute "ASSOCNAME", which will be used to identify this device.
  306. m_mapNameValue.SetAt(_T("ASSOCNAME"),strAntecedentName + ":" + strDeviceIDval);
  307. m_mapNameValue.SetAt(_T("DeviceID"),strDeviceIDval);
  308. m_mapNameValue.SetAt(_T("DeviceName"),strPNPDeviceName);
  309. return hr;
  310. }
  311. //////////////////////////////////////////////////////////////////////////////////////////
  312. //Retrives a value used to select appropriate description value for the class
  313. //////////////////////////////////////////////////////////////////////////////////////////
  314. CString CInstance::GetDescriptionForClass(CString strClass)
  315. {
  316. //lookup a key which can uniquely identify an instance of a given class
  317. //for example, DeviceID for Printers
  318. if (strClass.CompareNoCase(_T("Win32_LogicalDisk")) == 0)
  319. {
  320. return "DeviceID";
  321. }
  322. if (strClass.CompareNoCase(_T("Win32_CodecFile")) == 0)
  323. {
  324. return "Description";
  325. }
  326. if (strClass.CompareNoCase(_T("Win32_ComputerSystem")) == 0)
  327. {
  328. return "Name";
  329. }
  330. if (strClass.CompareNoCase(_T("Win32_OperatingSystem")) == 0)
  331. {
  332. return "Caption";
  333. }
  334. if (strClass.CompareNoCase(_T("Win32_LogicalMemoryConfiguration")) == 0)
  335. {
  336. return "TotalPhysicalMemory";
  337. }
  338. if (strClass.CompareNoCase(_T("Win32_PortResource")) == 0)
  339. {
  340. return "Name";
  341. }
  342. if (strClass.CompareNoCase(_T("Win32_NetworkProtocol")) == 0)
  343. {
  344. return "Name";
  345. }
  346. if (strClass.CompareNoCase(_T("Win32_Printer")) == 0)
  347. {
  348. return "DeviceID";
  349. }
  350. if (strClass.CompareNoCase(_T("Win32_PnPEntity")) == 0)
  351. {
  352. return "Description";
  353. }
  354. if (strClass.CompareNoCase(_T("Win32_StartupCommand")) == 0)
  355. {
  356. return "Command";
  357. }
  358. if (strClass.CompareNoCase(_T("Win32_ProgramGroup")) == 0)
  359. {
  360. return "GroupName";
  361. }
  362. if (strClass.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0)
  363. {
  364. //this is an artificial string created in CInstance::ProcessPNPAllocatedResource
  365. return "DeviceName";
  366. }
  367. if (strClass.CompareNoCase(_T("Win32_DriverVXD")) == 0)
  368. {
  369. return "Name";
  370. }
  371. return "";
  372. }
  373. //////////////////////////////////////////////////////////////////////////////////////////
  374. //used to determine which mapped value to use to ID instances of the clas
  375. //////////////////////////////////////////////////////////////////////////////////////////
  376. CString CInstance::GetIDForClass(CString strClass)
  377. {
  378. //lookup a key which can uniquely identify an instance of a given class
  379. //for example, DeviceID for Printers
  380. if (strClass.CompareNoCase(_T("Win32_LogicalDisk")) == 0)
  381. {
  382. return "DeviceID";
  383. }
  384. if (strClass.CompareNoCase(_T("Win32_CodecFile")) == 0)
  385. {
  386. return "Description";
  387. }
  388. if (strClass.CompareNoCase(_T("Win32_OperatingSystem")) == 0)
  389. {
  390. return "Caption";
  391. }
  392. if (strClass.CompareNoCase(_T("Win32_LogicalMemoryConfiguration")) == 0)
  393. {
  394. return "TotalPhysicalMemory";
  395. }
  396. if (strClass.CompareNoCase(_T("Win32_ComputerSystem")) == 0)
  397. {
  398. return "Name";
  399. }
  400. if (strClass.CompareNoCase(_T("Win32_PortResource")) == 0)
  401. {
  402. return "Name";
  403. }
  404. if (strClass.CompareNoCase(_T("Win32_NetworkProtocol")) == 0)
  405. {
  406. return "Name";
  407. }
  408. if (strClass.CompareNoCase(_T("Win32_Printer")) == 0)
  409. {
  410. return "DeviceID";
  411. }
  412. if (strClass.CompareNoCase(_T("Win32_PnPEntity")) == 0)
  413. {
  414. return "DeviceID";
  415. }
  416. if (strClass.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0)
  417. {
  418. //this is an artificial string created in CInstance::ProcessPNPAllocatedResource
  419. return "ASSOCNAME";
  420. }
  421. if (strClass.CompareNoCase(_T("Win32_ProgramGroup")) == 0)
  422. {
  423. return "GroupName";
  424. }
  425. if (strClass.CompareNoCase(_T("Win32_StartupCommand")) == 0)
  426. {
  427. return "Command";
  428. }
  429. if (strClass.CompareNoCase(_T("Win32_DriverVXD")) == 0)
  430. {
  431. return "Name";
  432. }
  433. return "";
  434. }
  435. //////////////////////////////////////////////////////////////////////////////////////////
  436. //used when rolling back through history list, to find previous instance of a given class
  437. //////////////////////////////////////////////////////////////////////////////////////////
  438. CInstance* CHistoryParser::FindPreviousInstance(CInstance* pNewInstance)
  439. {
  440. //for each existing instance pOld
  441. for(POSITION pos = m_listInstances.GetHeadPosition( );;)
  442. {
  443. if (!pos)
  444. {
  445. return NULL;
  446. }
  447. CInstance* pOld = (CInstance*) m_listInstances.GetNext(pos);
  448. if (pOld->GetClassName() == pNewInstance->GetClassName())
  449. {
  450. if (pOld->GetInstanceID() == pNewInstance->GetInstanceID())
  451. {
  452. return pOld;
  453. }
  454. }
  455. }
  456. return NULL;
  457. }
  458. void CHistoryParser::CreateChangeStrings(CInstance* pOld, CInstance* pNew)
  459. {
  460. CTimeSpan tmsDelta;
  461. COleDateTime olTime(pNew->m_tmstamp.GetTime());
  462. if (!pOld )
  463. {
  464. ASSERT(pNew );
  465. tmsDelta = CTime::GetCurrentTime() - pNew->m_tmstamp;
  466. //change string should be "Delete"
  467. m_pHistCat->InsertRemoveLine(pNew->m_tmstamp ,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription());
  468. m_fChangeLines = TRUE;
  469. return;
  470. }
  471. else if (!pNew)
  472. {
  473. ASSERT(pOld);
  474. tmsDelta = CTime::GetCurrentTime() - pOld->m_tmstamp;
  475. //change string should be "New"
  476. m_pHistCat->InsertAddLine(pNew->m_tmstamp,pOld->GetClassFriendlyName(),pOld->GetInstanceDescription());
  477. //v-stlowe 3/12/2001
  478. m_fChangeLines = TRUE;
  479. return;
  480. }
  481. else
  482. {
  483. ASSERT(pOld && pNew && "both pointers can't be null");
  484. tmsDelta = CTime::GetCurrentTime() - pNew->m_tmstamp;
  485. //for each Name&Value pair, get the name, and then use it to examine
  486. //the associated value in pCompare's map
  487. CString strName, strValue,strCompareValue;
  488. if (pNew->GetChangeType().CompareNoCase(_T("New")) == 0)
  489. {
  490. tmsDelta = CTime::GetCurrentTime() - pNew->m_tmstamp;
  491. //change string should be "added"
  492. m_pHistCat->InsertAddLine(pNew->m_tmstamp ,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription());
  493. m_fChangeLines = TRUE;
  494. return;
  495. }
  496. else if (pNew->GetChangeType().CompareNoCase(_T("Delete")) == 0)
  497. {
  498. tmsDelta = CTime::GetCurrentTime() - pNew->m_tmstamp;
  499. //change string should be "Deleted"
  500. m_pHistCat->InsertRemoveLine(pNew->m_tmstamp,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription());
  501. m_fChangeLines = TRUE;
  502. return;
  503. }
  504. for(POSITION pos = pNew->m_mapNameValue.GetStartPosition();;pNew->m_mapNameValue.GetNextAssoc(pos,strName, strValue))
  505. {
  506. strCompareValue = _T("");
  507. if (!pOld->m_mapNameValue.Lookup(strName,strCompareValue))
  508. {
  509. //ASSERT(0 && "value not found in delta");
  510. //return E_FAIL;
  511. if (strName.CompareNoCase(_T("Change")) == 0)
  512. {
  513. VERIFY(pNew->m_mapNameValue.Lookup(strName,strCompareValue));
  514. if (strCompareValue.CompareNoCase(_T("New")) == 0)
  515. {
  516. m_pHistCat->InsertAddLine(pNew->m_tmstamp,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription());
  517. m_fChangeLines = TRUE;
  518. }
  519. ASSERT(1);
  520. }
  521. continue;
  522. }
  523. else
  524. {
  525. pOld->m_mapNameValue.RemoveKey(strName);
  526. }
  527. if (strValue != strCompareValue)
  528. {
  529. m_pHistCat->InsertChangeLine(pNew->m_tmstamp,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription(),strName,strValue,strCompareValue);
  530. m_fChangeLines = TRUE;
  531. }
  532. if(!pos)
  533. {
  534. break;
  535. }
  536. }
  537. //handle values that are mapOldInstance, and not the other map
  538. if (!pOld->m_mapNameValue.IsEmpty())
  539. {
  540. for(pos = pOld->m_mapNameValue.GetStartPosition();;pOld->m_mapNameValue.GetNextAssoc(pos,strName, strValue))
  541. {
  542. pOld->m_mapNameValue.GetNextAssoc(pos,strName, strValue);
  543. pNew->m_mapNameValue.SetAt(strName,strValue);
  544. if (!pos)
  545. {
  546. break;
  547. }
  548. }
  549. }
  550. }
  551. }
  552. //////////////////////////////////////////////////////////////////////////////////////////
  553. //once the previous instance has been processed, previous instance should be removed and this instance should be added to list
  554. //////////////////////////////////////////////////////////////////////////////////////////
  555. void CHistoryParser::ResetInstance(CInstance* pOld, CInstance* pNew)
  556. {
  557. POSITION pos = this->m_listInstances.Find(pOld);
  558. m_listInstances.SetAt(pos,pNew);
  559. delete pOld;
  560. }
  561. //////////////////////////////////////////////////////////////////////////////////////////
  562. //Used to process a single instance from either history or snapshot
  563. //////////////////////////////////////////////////////////////////////////////////////////
  564. void CHistoryParser::ProcessInstance(CInstance* pNewInstance)
  565. {
  566. //see if instance is in list of instances
  567. CInstance* pOld = FindPreviousInstance(pNewInstance);
  568. if (pOld)
  569. {
  570. CreateChangeStrings(pOld,pNewInstance);
  571. ResetInstance(pOld,pNewInstance);
  572. }
  573. //if this is from a Snapshot, just add it
  574. //if it is from a Delta, it should have a change type of "add", and we
  575. //want to create a change string for it.
  576. else
  577. {
  578. CString strChange;
  579. if (pNewInstance->GetValueFromMap(_T("Change"),strChange))
  580. {
  581. //we have new Delta instance
  582. CreateChangeStrings(NULL,pNewInstance);
  583. m_listInstances.AddTail(pNewInstance);
  584. }
  585. else
  586. {
  587. //Instance is in snapshot, so we don't generate change lines
  588. m_listInstances.AddTail(pNewInstance);
  589. }
  590. }
  591. }
  592. /**************************************************************************
  593. returns list of deltas and the snapshot node
  594. /**************************************************************************/
  595. HRESULT CHistoryParser::GetDeltaAndSnapshotNodes(CComPtr<IXMLDOMNodeList>& pDeltaList)
  596. {
  597. CComPtr<IXMLDOMNode> pDataCollNode;
  598. HRESULT hr;
  599. hr = GetDataCollectionNode(m_pDoc,pDataCollNode);
  600. if (FAILED(hr) || !pDataCollNode)
  601. {
  602. //ASSERT(0 && "could not get datacollection node");
  603. return E_FAIL;
  604. }
  605. //all nodes directly under DATACOLLECTION should be either deltas or the snapshot
  606. hr = pDataCollNode->selectNodes(CComBSTR("*"),&pDeltaList);
  607. if (FAILED(hr) || !pDeltaList)
  608. {
  609. ASSERT(0 && "could not get pDeltaList");
  610. return E_FAIL;
  611. }
  612. #ifndef _DEBUG
  613. return hr;
  614. #endif
  615. long ll;
  616. hr = pDeltaList->get_length(&ll);
  617. return hr;
  618. }
  619. //////////////////////////////////////////////////////////////////////////////////////////
  620. //gets IXMLDOMNodeList of instances from a specific delta or snapshot node
  621. //////////////////////////////////////////////////////////////////////////////////////////
  622. HRESULT CHistoryParser::GetInstanceNodeList(CString strClass,CComPtr<IXMLDOMNode> pDeltaNode, CComPtr<IXMLDOMNodeList>& pInstanceList)
  623. {
  624. HRESULT hr;
  625. //CComBSTR bstrQuery;
  626. // the query will have to be in the form:
  627. // CIM/DECLARATION/DECLGROUP.WITHPATH/VALUE.OBJECTWITHPATH/INSTANCE[@CLASSNAME $ieq$ "WIN32_CODECFILE"]
  628. // or
  629. // CIM/DECLARATION/DECLGROUP.WITHPATH/VALUE.OBJECTWITHPATH/INSTANCE[@CLASSNAME $ieq$ "Win32_ComputerSystem"]
  630. // because we are querying a node, rather than a document (with which we could get
  631. // away with specifying only INSTANCE in the query
  632. //v-stlowe 1/29/2001 to fix Prefix whistler bug #279519
  633. //bstrQuery += "CIM/DECLARATION/DECLGROUP.WITHPATH/VALUE.OBJECTWITHPATH/INSTANCE[@CLASSNAME $ieq$ ";
  634. CComBSTR bstrQuery("CIM/DECLARATION/DECLGROUP.WITHPATH/VALUE.OBJECTWITHPATH/INSTANCE[@CLASSNAME $ieq$ ");
  635. //end v-stlowe
  636. bstrQuery += "\"";
  637. bstrQuery += CComBSTR(strClass);
  638. bstrQuery += "\"]";
  639. hr = pDeltaNode->selectNodes(bstrQuery,&pInstanceList);
  640. if (FAILED(hr) || !pInstanceList)
  641. {
  642. ASSERT(0 && "Could not get node list");
  643. return E_FAIL;
  644. }
  645. if (FAILED(hr))
  646. {
  647. ASSERT(0 && "Could not get node list length");
  648. }
  649. return hr;
  650. }
  651. //for a given Snapshot or Delta node, get all instances of a given class
  652. HRESULT CHistoryParser::ProcessDeltaNode(CComPtr<IXMLDOMNode> pDeltaNode,CString strClass)
  653. {
  654. CString strTime;
  655. HRESULT hr;
  656. int nTimeZone;
  657. hr = GetTimeStampFromFromD_or_SNodeNode(pDeltaNode, &strTime,nTimeZone);
  658. ASSERT(SUCCEEDED(hr) && "error getting timestamp for node");
  659. CTime tmDelta = GetDateFromString(strTime,nTimeZone);
  660. //TD: check for valid time range...
  661. //get list of all nodes of given class
  662. CComPtr<IXMLDOMNodeList> pInstanceNodeList;
  663. hr = GetInstanceNodeList(strClass,pDeltaNode,pInstanceNodeList);
  664. if (FAILED(hr) | ! pInstanceNodeList)
  665. {
  666. ASSERT(0 && "could not get instance list from Delta node");
  667. return E_FAIL;
  668. }
  669. //step through list, getting each instance
  670. long lListLen;
  671. hr = pInstanceNodeList->get_length(&lListLen);
  672. for(long i = 0;i < lListLen;i++)
  673. {
  674. CComPtr<IXMLDOMNode> pInstanceNode;
  675. hr = pInstanceNodeList->nextNode(&pInstanceNode);
  676. if (FAILED(hr) || ! pInstanceNode)
  677. {
  678. ASSERT(0 && "could not get node from instance list");
  679. return E_FAIL;
  680. }
  681. CInstance * pInstance = new CInstance(tmDelta,pInstanceNode,strClass);
  682. ProcessInstance(pInstance);
  683. }
  684. return hr;
  685. }
  686. //*************************************************************************
  687. //Takes a list of delta nodes, and the name of a class
  688. //**************************************************************************
  689. HRESULT CHistoryParser::ProcessDeltas(CComPtr<IXMLDOMNodeList> pDeltaList,CString strClassName,int nDeltasBack)
  690. {
  691. //for each node in list pNode
  692. long lListLen;
  693. HRESULT hr;
  694. hr = pDeltaList->get_length(&lListLen);
  695. if (FAILED(hr))
  696. {
  697. ASSERT(0 && "couldn't get list length");
  698. }
  699. if (0 == lListLen)
  700. {
  701. pDeltaList.Release();
  702. return S_FALSE;
  703. }
  704. for (long i = 0;i < lListLen && i <= nDeltasBack;i++)
  705. {
  706. CComPtr<IXMLDOMNode> pNode;
  707. hr= pDeltaList->nextNode(&pNode);
  708. if (FAILED(hr) || !pNode)
  709. {
  710. ASSERT(0 && "could not get next delta node");
  711. pDeltaList.Release();
  712. return E_FAIL;
  713. }
  714. // here's problem If we're using nDeltasBack method, do we need to compare dates?
  715. /* CTime tmDelta = GetDeltaTime(pNode);
  716. if (GetDeltaTime(pNode) >= this->m_tmBack)
  717. {
  718. */
  719. hr = ProcessDeltaNode(pNode,strClassName);
  720. if (FAILED(hr))
  721. {
  722. pDeltaList.Release();
  723. return hr;
  724. }
  725. // }
  726. }
  727. pDeltaList.Release();
  728. return S_OK;
  729. }
  730. //*************************************************************************
  731. //Gets the DATACOLLECTION node, beneath which both the SNAPSHOT and the DELTA nodes reside
  732. //**************************************************************************
  733. HRESULT GetDataCollectionNode(CComPtr<IXMLDOMDocument> pXMLDoc,CComPtr<IXMLDOMNode>& pDCNode)
  734. {
  735. //TD: find a way to do case-insensitive queries.
  736. HRESULT hr;
  737. if (!pXMLDoc)
  738. {
  739. return S_FALSE;
  740. }
  741. CComPtr<IXMLDOMNodeList> pNodeList;
  742. //find a change property; that way we know we have a delta
  743. hr = pXMLDoc->getElementsByTagName(CComBSTR("PROPERTY[@NAME $ieq$ \"CHANGE\"]"),&pNodeList);
  744. if (FAILED(hr) || !pNodeList)
  745. {
  746. ASSERT(0 && "Could not get node list");
  747. return E_FAIL;
  748. }
  749. CComPtr<IXMLDOMNode> pNode;
  750. hr = pNodeList->nextNode(&pNode);
  751. if (FAILED(hr) || !pNode)
  752. {
  753. // ASSERT(0 && "Could not get node from node list");
  754. return E_FAIL;
  755. }
  756. //loop till we get a node called "DATACOLLECTION"
  757. CComPtr<IXMLDOMNode> pParentNode;
  758. for(int i = 0;;i++)
  759. {
  760. hr = pNode->get_parentNode(&pParentNode);
  761. if (FAILED(hr) || !pParentNode)
  762. {
  763. ASSERT(0 && "Could not find DATACOLLECTION node");
  764. pDCNode = NULL;
  765. return E_FAIL;
  766. }
  767. pNode.Release();
  768. CComBSTR bstrName;
  769. pParentNode->get_nodeName(&bstrName);
  770. USES_CONVERSION;
  771. if (CString(bstrName).CompareNoCase(_T("DATACOLLECTION")) == 0)
  772. {
  773. pDCNode = pParentNode;
  774. return S_OK;
  775. }
  776. pNode = pParentNode;
  777. pParentNode.Release();
  778. }
  779. return S_OK;
  780. }
  781. //////////////////////////////////////////////////////////////////////////////////////////
  782. //get timestamp of a delta or snapshot node
  783. //////////////////////////////////////////////////////////////////////////////////////////
  784. CTime GetDeltaTime(CComPtr<IXMLDOMNode> pDorSNode)
  785. {
  786. CString strTime;
  787. int nTimeZone;
  788. GetTimeStampFromFromD_or_SNodeNode(pDorSNode,&strTime,nTimeZone);
  789. return GetDateFromString(strTime,nTimeZone);
  790. }
  791. //////////////////////////////////////////////////////////////////////////////////////////
  792. //takes string format used in XML blob, creates a CTime
  793. //////////////////////////////////////////////////////////////////////////////////////////
  794. HRESULT GetTimeStampFromFromD_or_SNodeNode(CComPtr<IXMLDOMNode> pDorSNode,CString* pString, int& nTimeZone)
  795. {
  796. HRESULT hr;
  797. CComVariant varTS;
  798. CComPtr<IXMLDOMElement> pTimestampElement;
  799. hr = pDorSNode->QueryInterface(IID_IXMLDOMElement,(void**) &pTimestampElement);
  800. if (FAILED(hr) || !pTimestampElement)
  801. {
  802. ASSERT(0 && "could not get attribute element");
  803. }
  804. hr = pTimestampElement->getAttribute(L"Timestamp_T0",&varTS);
  805. if (FAILED(hr) )
  806. {
  807. ASSERT(0 && "could not get timestamp value from attribute");
  808. }
  809. if (1 == hr)
  810. {
  811. //this may be snapshot node...try "Timestamp"
  812. hr = pTimestampElement->getAttribute(L"Timestamp",&varTS);
  813. if (FAILED(hr) )
  814. {
  815. ASSERT(0 && "could not get timestamp value from attribute");
  816. }
  817. }
  818. CComVariant varTzoneDeltaSeconds;
  819. hr = pTimestampElement->getAttribute(L"TimeZone",&varTzoneDeltaSeconds);
  820. if (FAILED(hr) ) //this will happen when loading WinME xml, which has no timezone info
  821. {
  822. varTzoneDeltaSeconds = 0;
  823. }
  824. //make sure we have an integer type
  825. hr = varTzoneDeltaSeconds.ChangeType(VT_INT);
  826. if (FAILED(hr) )
  827. {
  828. varTzoneDeltaSeconds = 0;
  829. }
  830. nTimeZone = varTzoneDeltaSeconds.intVal;
  831. USES_CONVERSION;
  832. pTimestampElement.Release();
  833. *pString = OLE2T(varTS.bstrVal);
  834. return hr;
  835. }
  836. //////////////////////////////////////////////////////////////////////
  837. // utility functions
  838. //////////////////////////////////////////////////////////////////////
  839. CTime GetDateFromString(const CString& strDate, int nTimeZone)
  840. {
  841. //requires linking to Shlwapi.lib
  842. CString strDateCopy(strDate);
  843. CString strDateSegment;
  844. //year is the 4 leftmost digits of date string
  845. strDateSegment = strDateCopy.Left(4);
  846. int nYear;
  847. VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nYear));
  848. // ASSERT(nYear == 1999 || nYear == 2000);
  849. strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 4);
  850. //month is now the 2 leftmost digits of remaining date string
  851. int nMonth;
  852. strDateSegment = strDateCopy.Left(2);
  853. VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nMonth));
  854. ASSERT(nMonth >= 1 && nMonth <= 12);
  855. strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2);
  856. //day is now the 2 leftmost digits of remaining date string
  857. int nDay;
  858. strDateSegment = strDateCopy.Left(2);
  859. VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nDay));
  860. ASSERT(nDay >= 1 && nDay <= 31);
  861. strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2);
  862. //hour is now the 2 leftmost digits of remaining date string
  863. int nHour;
  864. strDateSegment = strDateCopy.Left(2);
  865. VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nHour));
  866. ASSERT(nHour >= 0 && nHour <= 24);
  867. strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2);
  868. //Minute is now the 2 leftmost digits of remaining date string
  869. int nMin;
  870. strDateSegment = strDateCopy.Left(2);
  871. VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nMin));
  872. ASSERT(nMin >= 0 && nMin <= 59);
  873. strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2);
  874. //Minute is now the 2 leftmost digits of remaining date string
  875. int nSec;
  876. strDateSegment = strDateCopy.Left(2);
  877. VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nSec));
  878. ASSERT(nSec >= 0 && nSec <= 59);
  879. strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2);
  880. CTime tmTime(nYear,nMonth,nDay,nHour,nMin,nSec);
  881. #ifdef _V_STLOWE
  882. CString strFMT;
  883. CString strTime;
  884. strFMT.LoadString(IDS_TIME_FORMAT);
  885. strTime =tmTime.FormatGmt("%A, %B %d, %Y");
  886. #endif
  887. //Adjust for time zone
  888. CTimeSpan tspan(0,0,nTimeZone,0);
  889. tmTime -= tspan;
  890. #ifdef _V_STLOWE
  891. strFMT.LoadString(IDS_TIME_FORMAT);
  892. strTime =tmTime.FormatGmt("%A, %B %d, %Y");
  893. #endif
  894. return tmTime;
  895. }
  896. //////////////////////////////////////////////////////////////////////////////////////////
  897. //finds timestamp string for a given delta or snapshot node
  898. //////////////////////////////////////////////////////////////////////////////////////////
  899. CString GetPNPNameByID(CComPtr<IXMLDOMDocument> pDoc,CComBSTR bstrPNPID)
  900. {
  901. HRESULT hr;
  902. CComPtr<IXMLDOMNodeList> pNodeList;
  903. CComBSTR bstrQuery("INSTANCE[@CLASSNAME $ieq$ \"WIN32_PNPeNTITY\"] /PROPERTY[@NAME $ieq$ \"Description\"]");
  904. hr = pDoc->getElementsByTagName(bstrQuery,&pNodeList);
  905. if (FAILED(hr) || !pNodeList)
  906. {
  907. ASSERT(0 && "WIN32_PNPeNTITY error getting node list");
  908. return "";
  909. }
  910. long lListLen;
  911. hr = pNodeList->get_length(&lListLen);
  912. ASSERT(lListLen > 0 && "No WIN32_PNPeNTITY nodes found to match query");
  913. for(long i = 0; i < lListLen;i++)
  914. {
  915. CComPtr<IXMLDOMNode> pNode;
  916. hr = pNodeList->nextNode(&pNode);
  917. if (FAILED(hr) || !pNode)
  918. {
  919. ASSERT(0 && "could not get next node from list");
  920. return "";
  921. }
  922. USES_CONVERSION;
  923. CComPtr<IXMLDOMNode> pIDNode;
  924. hr = pNode->get_nextSibling(&pIDNode);
  925. if (FAILED(hr) || !pNode)
  926. {
  927. ASSERT(0 && "could not get next node from list");
  928. return "";
  929. }
  930. //see if node's DeviceID subnode matches bstrPNPID
  931. CComBSTR bstrDeviceID;
  932. hr = pIDNode->get_text(&bstrDeviceID);
  933. ASSERT(SUCCEEDED(hr) && "could not get text from ID node");
  934. if (bstrDeviceID == bstrPNPID)
  935. {
  936. CComBSTR bstrDeviceDesc;
  937. hr = pNode->get_text(&bstrDeviceDesc);
  938. ASSERT(SUCCEEDED(hr) && "could not get text from Desc node");
  939. return OLE2T(bstrDeviceDesc);
  940. }
  941. }
  942. return "";
  943. }
  944. //////////////////////////////////////////////////////////////////////////////////////////
  945. //returns true if any changes have been entered into CMSInfocategory data
  946. //////////////////////////////////////////////////////////////////////////////////////////
  947. BOOL CHistoryParser::AreThereChangeLines()
  948. {
  949. return this->m_fChangeLines;
  950. }
  951. //////////////////////////////////////////////////////////////////////////////////////////
  952. //gets (from resources strings) a human-readable name for a the class wrapped the the instance
  953. //////////////////////////////////////////////////////////////////////////////////////////
  954. CString CInstance::GetClassFriendlyName()
  955. {
  956. CString strClassName = GetClassName();
  957. if (strClassName.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0)
  958. {
  959. VERIFY(m_mapNameValue.Lookup(_T("ANTECEDENT"),strClassName) && _T("Could not find antecedent"));
  960. }
  961. CString strFriendlyName;
  962. if (strClassName.CompareNoCase(_T("Win32_CodecFile")) == 0)
  963. {
  964. VERIFY(strFriendlyName.LoadString(IDS_CODEC_DESC) && _T("could not find string resource"));
  965. return strFriendlyName;
  966. }
  967. if (strClassName.CompareNoCase(_T("Win32_ComputerSystem")) == 0)
  968. {
  969. VERIFY(strFriendlyName.LoadString(IDS_COMPUTERSYSTEM_DESC) && _T("could not find string resource"));
  970. return strFriendlyName;
  971. }
  972. if (strClassName.CompareNoCase(_T("Win32_LogicalMemoryConfiguration")) == 0)
  973. {
  974. VERIFY(strFriendlyName.LoadString(IDS_LOGICALMEMEORY_DESC) && _T("could not find string resource"));
  975. return strFriendlyName;
  976. }
  977. if (strClassName.CompareNoCase(_T("Win32_LogicalDisk")) == 0)
  978. {
  979. VERIFY(strFriendlyName.LoadString(IDS_LOGICALDISK_DESC) && _T("could not find string resource"));
  980. return strFriendlyName;
  981. }
  982. if (strClassName.CompareNoCase(_T("Win32_IRQResource")) == 0)
  983. {
  984. VERIFY(strFriendlyName.LoadString(IDS_IRQRESOURCE_DESC) && _T("could not find string resource"));
  985. return strFriendlyName;
  986. }
  987. if (strClassName.CompareNoCase(_T("Win32_DriverVXD")) == 0)
  988. {
  989. VERIFY(strFriendlyName.LoadString(IDS_DRIVERVXD_DESC) && _T("could not find string resource"));
  990. return strFriendlyName;
  991. }
  992. if (strClassName.CompareNoCase(_T("Win32_DMAChannel")) == 0)
  993. {
  994. VERIFY(strFriendlyName.LoadString(IDS_DMACHANNEL_DESC) && _T("could not find string resource"));
  995. return strFriendlyName;
  996. }
  997. if (strClassName.CompareNoCase(_T("Win32_DeviceMemoryAddress")) == 0)
  998. {
  999. VERIFY(strFriendlyName.LoadString(IDS_DEVICEMEMORYADDRESS_DESC) && _T("could not find string resource"));
  1000. return strFriendlyName;
  1001. }
  1002. if (strClassName.CompareNoCase(_T("Win32_NetworkProtocol")) == 0)
  1003. {
  1004. VERIFY(strFriendlyName.LoadString(IDS_NETWORKPROTOCOL_DESC) && _T("could not find string resource"));
  1005. return strFriendlyName;
  1006. }
  1007. if (strClassName.CompareNoCase(_T("Win32_OperatingSystem")) == 0)
  1008. {
  1009. VERIFY(strFriendlyName.LoadString(IDS_OPERATINGSYSTEM_DESC) && _T("could not find string resource"));
  1010. return strFriendlyName;
  1011. }
  1012. if (strClassName.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0)
  1013. {
  1014. VERIFY(strFriendlyName.LoadString(IDS_PNPALLOCATEDRESOURCE_DESC) && _T("could not find string resource"));
  1015. return strFriendlyName;
  1016. }
  1017. if (strClassName.CompareNoCase(_T("Win32_PNPEntity")) == 0)
  1018. {
  1019. VERIFY(strFriendlyName.LoadString(IDS_PNPENTITY_DESC) && _T("could not find string resource"));
  1020. return strFriendlyName;
  1021. }
  1022. if (strClassName.CompareNoCase(_T("Win32_PortResource")) == 0)
  1023. {
  1024. VERIFY(strFriendlyName.LoadString(IDS_PORTRESOURCE_DESC) && _T("could not find string resource"));
  1025. return strFriendlyName;
  1026. }
  1027. if (strClassName.CompareNoCase(_T("Win32_Printer")) == 0)
  1028. {
  1029. VERIFY(strFriendlyName.LoadString(IDS_PRINTER_DESC) && _T("could not find string resource"));
  1030. return strFriendlyName;
  1031. }
  1032. if (strClassName.CompareNoCase(_T("Win32_ProgramGroup")) == 0)
  1033. {
  1034. VERIFY(strFriendlyName.LoadString(IDS_PROGRAMGROUP_DESC) && _T("could not find string resource"));
  1035. return strFriendlyName;
  1036. }
  1037. if (strClassName.CompareNoCase(_T("Win32_StartupCommand")) == 0)
  1038. {
  1039. VERIFY(strFriendlyName.LoadString(IDS_STARTUPCOMMAND_DESC) && _T("could not find string resource"));
  1040. return strFriendlyName;
  1041. }
  1042. ASSERT(0 && "Unknown strClassName");
  1043. return "";
  1044. }