// HistoryParser.cpp: implementation of the CHistoryParser class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "resource.h" #include "HistoryParser.h" #include "Filestuff.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif extern CMSInfoHistoryCategory catHistorySystemSummary; extern CMSInfoHistoryCategory catHistoryResources; extern CMSInfoHistoryCategory catHistoryComponents; extern CMSInfoHistoryCategory catHistorySWEnv; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CHistoryParser::CHistoryParser(CComPtr pDoc) : m_pDoc(pDoc) { } void CHistoryParser::DeleteAllInstances() { for(POSITION pos = this->m_listInstances.GetHeadPosition();pos;) { if (!pos) { return; } CInstance* pInci = (CInstance*) m_listInstances.GetNext(pos); delete pInci; } m_listInstances.RemoveAll(); } CHistoryParser::~CHistoryParser() { DeleteAllInstances(); } ////////////////////////////////////////////////////////////////////// // Construction/Destruction // takes a CTime, which comes from timestamp element of the Delta or Snaphot // node of which pInstanceNode is a child; an Instance node, and a string // containing the WMI class of the Instance ////////////////////////////////////////////////////////////////////// CInstance::CInstance(CTime tmstmp, CComPtr pInstanceNode,CString strClass) : m_tmstamp(tmstmp), m_strClassName(strClass) { CComPtr pPropList; HRESULT hr; //Get node data, add each PROPERTY name and VALUE to m_mapNameValue if (strClass.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0) { hr = ProcessPNPAllocatedResource(pInstanceNode); ASSERT(SUCCEEDED(hr) && "failed to process Win32_PNPAllocatedResource"); return; } hr = pInstanceNode->selectNodes(CComBSTR("PROPERTY"),&pPropList); if (FAILED(hr) || !pPropList) { ASSERT(0 && "could not get property list from Instance node"); return; } long lListLen; hr = pPropList->get_length(&lListLen); CComPtr pVNode; CComBSTR bstrValue; CComVariant varName; for(long i = 0; i < lListLen; i++) { hr = pPropList->nextNode(&pVNode); if (FAILED(hr) || !pVNode) { return; } CComPtr pElement; hr = pVNode->QueryInterface(IID_IXMLDOMElement,(void**) &pElement); if (FAILED(hr) || !pElement) { return; } hr = pElement->getAttribute(L"NAME",&varName); ASSERT(SUCCEEDED(hr)); hr = pVNode->get_text(&bstrValue); ASSERT(SUCCEEDED(hr)); USES_CONVERSION; m_mapNameValue.SetAt(OLE2T(varName.bstrVal) ,OLE2T(bstrValue)); pVNode.Release(); } pPropList.Release(); return; } ////////////////////////////////////////////////////////////////////////////////////////// //Refresh is called for selected category when category selection or delta range changes ////////////////////////////////////////////////////////////////////////////////////////// HRESULT CHistoryParser::Refresh(CMSInfoHistoryCategory* pHistCat,int nDeltasBack) { nDeltasBack++; this->m_fChangeLines = FALSE;// v-stlowe 2/28/2001 DeleteAllInstances(); m_pHistCat = pHistCat; CComPtr pDeltaList; HRESULT hr; hr = this->GetDeltaAndSnapshotNodes(pDeltaList); if (FAILED(hr) || !pDeltaList) { return E_FAIL; } if (pHistCat == &catHistoryComponents) { DeleteAllInstances(); hr = ProcessDeltas(pDeltaList,"Win32_DriverVXD",nDeltasBack); ASSERT(SUCCEEDED(hr)); DeleteAllInstances(); pDeltaList->reset(); hr = ProcessDeltas(pDeltaList,"Win32_CodecFile",nDeltasBack); ASSERT(SUCCEEDED(hr)); DeleteAllInstances(); pDeltaList->reset(); hr = ProcessDeltas(pDeltaList,"Win32_LogicalDisk",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); hr = ProcessDeltas(pDeltaList,"Win32_NetworkProtocol",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); hr = ProcessDeltas(pDeltaList,"Win32_Printer",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); hr = ProcessDeltas(pDeltaList,"Win32_PortResource",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); hr = ProcessDeltas(pDeltaList,"Win32_PnPEntity",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); } else if (pHistCat == &catHistorySystemSummary) { DeleteAllInstances(); hr = ProcessDeltas(pDeltaList,"Win32_ComputerSystem",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); hr = ProcessDeltas(pDeltaList,"Win32_OperatingSystem",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); //hr = ProcessDeltas(pDeltaList,"Win32_Win32_LogicalMemoryConfiguration",nDeltasBack); hr = ProcessDeltas(pDeltaList,"Win32_LogicalMemoryConfiguration",nDeltasBack); //v-stlowe 2/28/2001 DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); } else if(pHistCat == &catHistoryResources) { DeleteAllInstances(); hr = ProcessDeltas(pDeltaList,"Win32_PNPAllocatedResource",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); ASSERT(SUCCEEDED(hr)); } else if (pHistCat == &catHistorySWEnv) { DeleteAllInstances(); hr = ProcessDeltas(pDeltaList,"Win32_ProgramGroup",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); hr = ProcessDeltas(pDeltaList,"Win32_StartupCommand",nDeltasBack); DeleteAllInstances(); pDeltaList->reset(); } if (!m_fChangeLines) { #ifdef A_STEPHL2 ::MessageBox(NULL,"!m_fChangeLines)","",MB_OK); #endif m_fChangeLines = TRUE; CString strMSG; strMSG.LoadString(IDS_DELTANOCHANGES);//this would be the place to change messaging for situation where summary has no changes m_pHistCat->InsertLine(-1, strMSG, _T(""), _T(""), _T("")); } pDeltaList.Release(); return hr; } ////////////////////////////////////////////////////////////////////////////////////////// //Gets the value appropriate to use as a description for the class ////////////////////////////////////////////////////////////////////////////////////////// CString CInstance::GetInstanceDescription() { CString strDescName = GetDescriptionForClass(m_strClassName); CString strInstDesc; VERIFY(m_mapNameValue.Lookup(strDescName,strInstDesc)); return strInstDesc; } ////////////////////////////////////////////////////////////////////////////////////////// //Gets the value that can be used to uniquely identify a specific instance of a class ////////////////////////////////////////////////////////////////////////////////////////// CString CInstance::GetInstanceID() { CString strIDName = GetIDForClass(m_strClassName); CString strInstID; VERIFY(m_mapNameValue.Lookup(strIDName,strInstID)); return strInstID; } ////////////////////////////////////////////////////////////////////////////////////////// //used to deal with antecedent\dependant relationship classes in Win32_PNPAllocatedResource classes ////////////////////////////////////////////////////////////////////////////////////////// HRESULT CInstance::ProcessPropertyDotReferenceNodes(CComPtr pInstanceNameNode,CString* pstrClassName, CString* pstrKeyName,CString* pstrKeyValue) { USES_CONVERSION; HRESULT hr; CComPtr pNameElement; hr = pInstanceNameNode->QueryInterface(IID_IXMLDOMElement,(void**) &pNameElement); if (FAILED(hr) | !pNameElement) { ASSERT(0 && "could not QI pNode for Element"); return E_FAIL; } CComVariant varClassName; hr = pNameElement->getAttribute(L"CLASSNAME",&varClassName); pNameElement.Release(); if (FAILED(hr)) { ASSERT(0 && "could not get CLASSNAME element"); } *pstrClassName = OLE2T(varClassName.bstrVal); CComPtr pKeybindingNode; hr = pInstanceNameNode->selectSingleNode(CComBSTR("KEYBINDING"),&pKeybindingNode); if (FAILED(hr) || !pKeybindingNode) { ASSERT(0 && "could not get antecedent node"); } CComBSTR bstrKeyValue; hr = pKeybindingNode->get_text(&bstrKeyValue); ASSERT(SUCCEEDED(hr) && "failed to get keybinding value"); *pstrKeyValue = OLE2T(bstrKeyValue); hr = pKeybindingNode->QueryInterface(IID_IXMLDOMElement,(void**) &pNameElement); if (FAILED(hr) | !pNameElement) { ASSERT(0 && "could not QI pNode for Element"); return E_FAIL; } CComVariant varKeybindingName; hr = pNameElement->getAttribute(CComBSTR("NAME"),&varKeybindingName); if (FAILED(hr)) { ASSERT(0 && "could not get NAME attribute from pNameElement"); } *pstrKeyName = OLE2T(varKeybindingName.bstrVal); return hr; } ////////////////////////////////////////////////////////////////////////////////////////// //used to deal with antecedent\dependant relationship classes in Win32_PNPAllocatedResource classes ////////////////////////////////////////////////////////////////////////////////////////// HRESULT CInstance::ProcessPNPAllocatedResource(CComPtr pInstanceNode) { HRESULT hr; CComPtr pPropDotRefList; hr = pInstanceNode->selectNodes(CComBSTR("PROPERTY.REFERENCE/VALUE.REFERENCE/INSTANCEPATH/INSTANCENAME"),&pPropDotRefList); if (FAILED(hr) || !pPropDotRefList) { ASSERT(0 && "PROPERTY.REFERENCE nodes not found"); return E_FAIL; } //get antecedent node CComPtr pInstanceNameNode; hr = pPropDotRefList->nextNode(&pInstanceNameNode); if (FAILED(hr) || !pInstanceNameNode) { ASSERT(0 && "could not get antecedent node"); } CString strAntecedentName,strResourceName,strResourceValue; hr = ProcessPropertyDotReferenceNodes(pInstanceNameNode,&strAntecedentName,&strResourceName,&strResourceValue); m_mapNameValue.SetAt(_T("ANTECEDENT"),strAntecedentName); m_mapNameValue.SetAt(strResourceName,strResourceValue); if (FAILED(hr)) { return hr; } CString strPNPEntity,strKeyname,strDeviceIDval; pInstanceNameNode.Release(); hr = pPropDotRefList->nextNode(&pInstanceNameNode); if (FAILED(hr) || !pInstanceNameNode) { return hr; } hr = ProcessPropertyDotReferenceNodes(pInstanceNameNode,&strPNPEntity,&strKeyname,&strDeviceIDval); CComPtr pDoc; hr = pInstanceNode->get_ownerDocument(&pDoc); if (FAILED(hr) || !pDoc) { ASSERT(0 && "could not get owner doc from pInstanceNode"); return E_FAIL; } CString strPNPDeviceName = GetPNPNameByID(pDoc,CComBSTR(strDeviceIDval)); if (FAILED(hr)) { return hr; } ASSERT(strPNPEntity.CompareNoCase("Win32_PnPEntity") == 0 && "unexpected value for Dependent classname"); ASSERT(strKeyname.CompareNoCase("DeviceID") == 0 && "unexpected value for Dependent Keybinding name"); //we will create an arificial attribute "ASSOCNAME", which will be used to identify this device. m_mapNameValue.SetAt(_T("ASSOCNAME"),strAntecedentName + ":" + strDeviceIDval); m_mapNameValue.SetAt(_T("DeviceID"),strDeviceIDval); m_mapNameValue.SetAt(_T("DeviceName"),strPNPDeviceName); return hr; } ////////////////////////////////////////////////////////////////////////////////////////// //Retrives a value used to select appropriate description value for the class ////////////////////////////////////////////////////////////////////////////////////////// CString CInstance::GetDescriptionForClass(CString strClass) { //lookup a key which can uniquely identify an instance of a given class //for example, DeviceID for Printers if (strClass.CompareNoCase(_T("Win32_LogicalDisk")) == 0) { return "DeviceID"; } if (strClass.CompareNoCase(_T("Win32_CodecFile")) == 0) { return "Description"; } if (strClass.CompareNoCase(_T("Win32_ComputerSystem")) == 0) { return "Name"; } if (strClass.CompareNoCase(_T("Win32_OperatingSystem")) == 0) { return "Caption"; } if (strClass.CompareNoCase(_T("Win32_LogicalMemoryConfiguration")) == 0) { return "TotalPhysicalMemory"; } if (strClass.CompareNoCase(_T("Win32_PortResource")) == 0) { return "Name"; } if (strClass.CompareNoCase(_T("Win32_NetworkProtocol")) == 0) { return "Name"; } if (strClass.CompareNoCase(_T("Win32_Printer")) == 0) { return "DeviceID"; } if (strClass.CompareNoCase(_T("Win32_PnPEntity")) == 0) { return "Description"; } if (strClass.CompareNoCase(_T("Win32_StartupCommand")) == 0) { return "Command"; } if (strClass.CompareNoCase(_T("Win32_ProgramGroup")) == 0) { return "GroupName"; } if (strClass.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0) { //this is an artificial string created in CInstance::ProcessPNPAllocatedResource return "DeviceName"; } if (strClass.CompareNoCase(_T("Win32_DriverVXD")) == 0) { return "Name"; } return ""; } ////////////////////////////////////////////////////////////////////////////////////////// //used to determine which mapped value to use to ID instances of the clas ////////////////////////////////////////////////////////////////////////////////////////// CString CInstance::GetIDForClass(CString strClass) { //lookup a key which can uniquely identify an instance of a given class //for example, DeviceID for Printers if (strClass.CompareNoCase(_T("Win32_LogicalDisk")) == 0) { return "DeviceID"; } if (strClass.CompareNoCase(_T("Win32_CodecFile")) == 0) { return "Description"; } if (strClass.CompareNoCase(_T("Win32_OperatingSystem")) == 0) { return "Caption"; } if (strClass.CompareNoCase(_T("Win32_LogicalMemoryConfiguration")) == 0) { return "TotalPhysicalMemory"; } if (strClass.CompareNoCase(_T("Win32_ComputerSystem")) == 0) { return "Name"; } if (strClass.CompareNoCase(_T("Win32_PortResource")) == 0) { return "Name"; } if (strClass.CompareNoCase(_T("Win32_NetworkProtocol")) == 0) { return "Name"; } if (strClass.CompareNoCase(_T("Win32_Printer")) == 0) { return "DeviceID"; } if (strClass.CompareNoCase(_T("Win32_PnPEntity")) == 0) { return "DeviceID"; } if (strClass.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0) { //this is an artificial string created in CInstance::ProcessPNPAllocatedResource return "ASSOCNAME"; } if (strClass.CompareNoCase(_T("Win32_ProgramGroup")) == 0) { return "GroupName"; } if (strClass.CompareNoCase(_T("Win32_StartupCommand")) == 0) { return "Command"; } if (strClass.CompareNoCase(_T("Win32_DriverVXD")) == 0) { return "Name"; } return ""; } ////////////////////////////////////////////////////////////////////////////////////////// //used when rolling back through history list, to find previous instance of a given class ////////////////////////////////////////////////////////////////////////////////////////// CInstance* CHistoryParser::FindPreviousInstance(CInstance* pNewInstance) { //for each existing instance pOld for(POSITION pos = m_listInstances.GetHeadPosition( );;) { if (!pos) { return NULL; } CInstance* pOld = (CInstance*) m_listInstances.GetNext(pos); if (pOld->GetClassName() == pNewInstance->GetClassName()) { if (pOld->GetInstanceID() == pNewInstance->GetInstanceID()) { return pOld; } } } return NULL; } void CHistoryParser::CreateChangeStrings(CInstance* pOld, CInstance* pNew) { CTimeSpan tmsDelta; COleDateTime olTime(pNew->m_tmstamp.GetTime()); if (!pOld ) { ASSERT(pNew ); tmsDelta = CTime::GetCurrentTime() - pNew->m_tmstamp; //change string should be "Delete" m_pHistCat->InsertRemoveLine(pNew->m_tmstamp ,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription()); m_fChangeLines = TRUE; return; } else if (!pNew) { ASSERT(pOld); tmsDelta = CTime::GetCurrentTime() - pOld->m_tmstamp; //change string should be "New" m_pHistCat->InsertAddLine(pNew->m_tmstamp,pOld->GetClassFriendlyName(),pOld->GetInstanceDescription()); //v-stlowe 3/12/2001 m_fChangeLines = TRUE; return; } else { ASSERT(pOld && pNew && "both pointers can't be null"); tmsDelta = CTime::GetCurrentTime() - pNew->m_tmstamp; //for each Name&Value pair, get the name, and then use it to examine //the associated value in pCompare's map CString strName, strValue,strCompareValue; if (pNew->GetChangeType().CompareNoCase(_T("New")) == 0) { tmsDelta = CTime::GetCurrentTime() - pNew->m_tmstamp; //change string should be "added" m_pHistCat->InsertAddLine(pNew->m_tmstamp ,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription()); m_fChangeLines = TRUE; return; } else if (pNew->GetChangeType().CompareNoCase(_T("Delete")) == 0) { tmsDelta = CTime::GetCurrentTime() - pNew->m_tmstamp; //change string should be "Deleted" m_pHistCat->InsertRemoveLine(pNew->m_tmstamp,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription()); m_fChangeLines = TRUE; return; } for(POSITION pos = pNew->m_mapNameValue.GetStartPosition();;pNew->m_mapNameValue.GetNextAssoc(pos,strName, strValue)) { strCompareValue = _T(""); if (!pOld->m_mapNameValue.Lookup(strName,strCompareValue)) { //ASSERT(0 && "value not found in delta"); //return E_FAIL; if (strName.CompareNoCase(_T("Change")) == 0) { VERIFY(pNew->m_mapNameValue.Lookup(strName,strCompareValue)); if (strCompareValue.CompareNoCase(_T("New")) == 0) { m_pHistCat->InsertAddLine(pNew->m_tmstamp,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription()); m_fChangeLines = TRUE; } ASSERT(1); } continue; } else { pOld->m_mapNameValue.RemoveKey(strName); } if (strValue != strCompareValue) { m_pHistCat->InsertChangeLine(pNew->m_tmstamp,pNew->GetClassFriendlyName(),pNew->GetInstanceDescription(),strName,strValue,strCompareValue); m_fChangeLines = TRUE; } if(!pos) { break; } } //handle values that are mapOldInstance, and not the other map if (!pOld->m_mapNameValue.IsEmpty()) { for(pos = pOld->m_mapNameValue.GetStartPosition();;pOld->m_mapNameValue.GetNextAssoc(pos,strName, strValue)) { pOld->m_mapNameValue.GetNextAssoc(pos,strName, strValue); pNew->m_mapNameValue.SetAt(strName,strValue); if (!pos) { break; } } } } } ////////////////////////////////////////////////////////////////////////////////////////// //once the previous instance has been processed, previous instance should be removed and this instance should be added to list ////////////////////////////////////////////////////////////////////////////////////////// void CHistoryParser::ResetInstance(CInstance* pOld, CInstance* pNew) { POSITION pos = this->m_listInstances.Find(pOld); m_listInstances.SetAt(pos,pNew); delete pOld; } ////////////////////////////////////////////////////////////////////////////////////////// //Used to process a single instance from either history or snapshot ////////////////////////////////////////////////////////////////////////////////////////// void CHistoryParser::ProcessInstance(CInstance* pNewInstance) { //see if instance is in list of instances CInstance* pOld = FindPreviousInstance(pNewInstance); if (pOld) { CreateChangeStrings(pOld,pNewInstance); ResetInstance(pOld,pNewInstance); } //if this is from a Snapshot, just add it //if it is from a Delta, it should have a change type of "add", and we //want to create a change string for it. else { CString strChange; if (pNewInstance->GetValueFromMap(_T("Change"),strChange)) { //we have new Delta instance CreateChangeStrings(NULL,pNewInstance); m_listInstances.AddTail(pNewInstance); } else { //Instance is in snapshot, so we don't generate change lines m_listInstances.AddTail(pNewInstance); } } } /************************************************************************** returns list of deltas and the snapshot node /**************************************************************************/ HRESULT CHistoryParser::GetDeltaAndSnapshotNodes(CComPtr& pDeltaList) { CComPtr pDataCollNode; HRESULT hr; hr = GetDataCollectionNode(m_pDoc,pDataCollNode); if (FAILED(hr) || !pDataCollNode) { //ASSERT(0 && "could not get datacollection node"); return E_FAIL; } //all nodes directly under DATACOLLECTION should be either deltas or the snapshot hr = pDataCollNode->selectNodes(CComBSTR("*"),&pDeltaList); if (FAILED(hr) || !pDeltaList) { ASSERT(0 && "could not get pDeltaList"); return E_FAIL; } #ifndef _DEBUG return hr; #endif long ll; hr = pDeltaList->get_length(&ll); return hr; } ////////////////////////////////////////////////////////////////////////////////////////// //gets IXMLDOMNodeList of instances from a specific delta or snapshot node ////////////////////////////////////////////////////////////////////////////////////////// HRESULT CHistoryParser::GetInstanceNodeList(CString strClass,CComPtr pDeltaNode, CComPtr& pInstanceList) { HRESULT hr; //CComBSTR bstrQuery; // the query will have to be in the form: // CIM/DECLARATION/DECLGROUP.WITHPATH/VALUE.OBJECTWITHPATH/INSTANCE[@CLASSNAME $ieq$ "WIN32_CODECFILE"] // or // CIM/DECLARATION/DECLGROUP.WITHPATH/VALUE.OBJECTWITHPATH/INSTANCE[@CLASSNAME $ieq$ "Win32_ComputerSystem"] // because we are querying a node, rather than a document (with which we could get // away with specifying only INSTANCE in the query //v-stlowe 1/29/2001 to fix Prefix whistler bug #279519 //bstrQuery += "CIM/DECLARATION/DECLGROUP.WITHPATH/VALUE.OBJECTWITHPATH/INSTANCE[@CLASSNAME $ieq$ "; CComBSTR bstrQuery("CIM/DECLARATION/DECLGROUP.WITHPATH/VALUE.OBJECTWITHPATH/INSTANCE[@CLASSNAME $ieq$ "); //end v-stlowe bstrQuery += "\""; bstrQuery += CComBSTR(strClass); bstrQuery += "\"]"; hr = pDeltaNode->selectNodes(bstrQuery,&pInstanceList); if (FAILED(hr) || !pInstanceList) { ASSERT(0 && "Could not get node list"); return E_FAIL; } if (FAILED(hr)) { ASSERT(0 && "Could not get node list length"); } return hr; } //for a given Snapshot or Delta node, get all instances of a given class HRESULT CHistoryParser::ProcessDeltaNode(CComPtr pDeltaNode,CString strClass) { CString strTime; HRESULT hr; int nTimeZone; hr = GetTimeStampFromFromD_or_SNodeNode(pDeltaNode, &strTime,nTimeZone); ASSERT(SUCCEEDED(hr) && "error getting timestamp for node"); CTime tmDelta = GetDateFromString(strTime,nTimeZone); //TD: check for valid time range... //get list of all nodes of given class CComPtr pInstanceNodeList; hr = GetInstanceNodeList(strClass,pDeltaNode,pInstanceNodeList); if (FAILED(hr) | ! pInstanceNodeList) { ASSERT(0 && "could not get instance list from Delta node"); return E_FAIL; } //step through list, getting each instance long lListLen; hr = pInstanceNodeList->get_length(&lListLen); for(long i = 0;i < lListLen;i++) { CComPtr pInstanceNode; hr = pInstanceNodeList->nextNode(&pInstanceNode); if (FAILED(hr) || ! pInstanceNode) { ASSERT(0 && "could not get node from instance list"); return E_FAIL; } CInstance * pInstance = new CInstance(tmDelta,pInstanceNode,strClass); ProcessInstance(pInstance); } return hr; } //************************************************************************* //Takes a list of delta nodes, and the name of a class //************************************************************************** HRESULT CHistoryParser::ProcessDeltas(CComPtr pDeltaList,CString strClassName,int nDeltasBack) { //for each node in list pNode long lListLen; HRESULT hr; hr = pDeltaList->get_length(&lListLen); if (FAILED(hr)) { ASSERT(0 && "couldn't get list length"); } if (0 == lListLen) { pDeltaList.Release(); return S_FALSE; } for (long i = 0;i < lListLen && i <= nDeltasBack;i++) { CComPtr pNode; hr= pDeltaList->nextNode(&pNode); if (FAILED(hr) || !pNode) { ASSERT(0 && "could not get next delta node"); pDeltaList.Release(); return E_FAIL; } // here's problem If we're using nDeltasBack method, do we need to compare dates? /* CTime tmDelta = GetDeltaTime(pNode); if (GetDeltaTime(pNode) >= this->m_tmBack) { */ hr = ProcessDeltaNode(pNode,strClassName); if (FAILED(hr)) { pDeltaList.Release(); return hr; } // } } pDeltaList.Release(); return S_OK; } //************************************************************************* //Gets the DATACOLLECTION node, beneath which both the SNAPSHOT and the DELTA nodes reside //************************************************************************** HRESULT GetDataCollectionNode(CComPtr pXMLDoc,CComPtr& pDCNode) { //TD: find a way to do case-insensitive queries. HRESULT hr; if (!pXMLDoc) { return S_FALSE; } CComPtr pNodeList; //find a change property; that way we know we have a delta hr = pXMLDoc->getElementsByTagName(CComBSTR("PROPERTY[@NAME $ieq$ \"CHANGE\"]"),&pNodeList); if (FAILED(hr) || !pNodeList) { ASSERT(0 && "Could not get node list"); return E_FAIL; } CComPtr pNode; hr = pNodeList->nextNode(&pNode); if (FAILED(hr) || !pNode) { // ASSERT(0 && "Could not get node from node list"); return E_FAIL; } //loop till we get a node called "DATACOLLECTION" CComPtr pParentNode; for(int i = 0;;i++) { hr = pNode->get_parentNode(&pParentNode); if (FAILED(hr) || !pParentNode) { ASSERT(0 && "Could not find DATACOLLECTION node"); pDCNode = NULL; return E_FAIL; } pNode.Release(); CComBSTR bstrName; pParentNode->get_nodeName(&bstrName); USES_CONVERSION; if (CString(bstrName).CompareNoCase(_T("DATACOLLECTION")) == 0) { pDCNode = pParentNode; return S_OK; } pNode = pParentNode; pParentNode.Release(); } return S_OK; } ////////////////////////////////////////////////////////////////////////////////////////// //get timestamp of a delta or snapshot node ////////////////////////////////////////////////////////////////////////////////////////// CTime GetDeltaTime(CComPtr pDorSNode) { CString strTime; int nTimeZone; GetTimeStampFromFromD_or_SNodeNode(pDorSNode,&strTime,nTimeZone); return GetDateFromString(strTime,nTimeZone); } ////////////////////////////////////////////////////////////////////////////////////////// //takes string format used in XML blob, creates a CTime ////////////////////////////////////////////////////////////////////////////////////////// HRESULT GetTimeStampFromFromD_or_SNodeNode(CComPtr pDorSNode,CString* pString, int& nTimeZone) { HRESULT hr; CComVariant varTS; CComPtr pTimestampElement; hr = pDorSNode->QueryInterface(IID_IXMLDOMElement,(void**) &pTimestampElement); if (FAILED(hr) || !pTimestampElement) { ASSERT(0 && "could not get attribute element"); } hr = pTimestampElement->getAttribute(L"Timestamp_T0",&varTS); if (FAILED(hr) ) { ASSERT(0 && "could not get timestamp value from attribute"); } if (1 == hr) { //this may be snapshot node...try "Timestamp" hr = pTimestampElement->getAttribute(L"Timestamp",&varTS); if (FAILED(hr) ) { ASSERT(0 && "could not get timestamp value from attribute"); } } CComVariant varTzoneDeltaSeconds; hr = pTimestampElement->getAttribute(L"TimeZone",&varTzoneDeltaSeconds); if (FAILED(hr) ) //this will happen when loading WinME xml, which has no timezone info { varTzoneDeltaSeconds = 0; } //make sure we have an integer type hr = varTzoneDeltaSeconds.ChangeType(VT_INT); if (FAILED(hr) ) { varTzoneDeltaSeconds = 0; } nTimeZone = varTzoneDeltaSeconds.intVal; USES_CONVERSION; pTimestampElement.Release(); *pString = OLE2T(varTS.bstrVal); return hr; } ////////////////////////////////////////////////////////////////////// // utility functions ////////////////////////////////////////////////////////////////////// CTime GetDateFromString(const CString& strDate, int nTimeZone) { //requires linking to Shlwapi.lib CString strDateCopy(strDate); CString strDateSegment; //year is the 4 leftmost digits of date string strDateSegment = strDateCopy.Left(4); int nYear; VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nYear)); // ASSERT(nYear == 1999 || nYear == 2000); strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 4); //month is now the 2 leftmost digits of remaining date string int nMonth; strDateSegment = strDateCopy.Left(2); VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nMonth)); ASSERT(nMonth >= 1 && nMonth <= 12); strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2); //day is now the 2 leftmost digits of remaining date string int nDay; strDateSegment = strDateCopy.Left(2); VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nDay)); ASSERT(nDay >= 1 && nDay <= 31); strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2); //hour is now the 2 leftmost digits of remaining date string int nHour; strDateSegment = strDateCopy.Left(2); VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nHour)); ASSERT(nHour >= 0 && nHour <= 24); strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2); //Minute is now the 2 leftmost digits of remaining date string int nMin; strDateSegment = strDateCopy.Left(2); VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nMin)); ASSERT(nMin >= 0 && nMin <= 59); strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2); //Minute is now the 2 leftmost digits of remaining date string int nSec; strDateSegment = strDateCopy.Left(2); VERIFY(StrToIntEx(strDateSegment,STIF_DEFAULT ,&nSec)); ASSERT(nSec >= 0 && nSec <= 59); strDateCopy = strDateCopy.Right(strDateCopy.GetLength() - 2); CTime tmTime(nYear,nMonth,nDay,nHour,nMin,nSec); #ifdef _V_STLOWE CString strFMT; CString strTime; strFMT.LoadString(IDS_TIME_FORMAT); strTime =tmTime.FormatGmt("%A, %B %d, %Y"); #endif //Adjust for time zone CTimeSpan tspan(0,0,nTimeZone,0); tmTime -= tspan; #ifdef _V_STLOWE strFMT.LoadString(IDS_TIME_FORMAT); strTime =tmTime.FormatGmt("%A, %B %d, %Y"); #endif return tmTime; } ////////////////////////////////////////////////////////////////////////////////////////// //finds timestamp string for a given delta or snapshot node ////////////////////////////////////////////////////////////////////////////////////////// CString GetPNPNameByID(CComPtr pDoc,CComBSTR bstrPNPID) { HRESULT hr; CComPtr pNodeList; CComBSTR bstrQuery("INSTANCE[@CLASSNAME $ieq$ \"WIN32_PNPeNTITY\"] /PROPERTY[@NAME $ieq$ \"Description\"]"); hr = pDoc->getElementsByTagName(bstrQuery,&pNodeList); if (FAILED(hr) || !pNodeList) { ASSERT(0 && "WIN32_PNPeNTITY error getting node list"); return ""; } long lListLen; hr = pNodeList->get_length(&lListLen); ASSERT(lListLen > 0 && "No WIN32_PNPeNTITY nodes found to match query"); for(long i = 0; i < lListLen;i++) { CComPtr pNode; hr = pNodeList->nextNode(&pNode); if (FAILED(hr) || !pNode) { ASSERT(0 && "could not get next node from list"); return ""; } USES_CONVERSION; CComPtr pIDNode; hr = pNode->get_nextSibling(&pIDNode); if (FAILED(hr) || !pNode) { ASSERT(0 && "could not get next node from list"); return ""; } //see if node's DeviceID subnode matches bstrPNPID CComBSTR bstrDeviceID; hr = pIDNode->get_text(&bstrDeviceID); ASSERT(SUCCEEDED(hr) && "could not get text from ID node"); if (bstrDeviceID == bstrPNPID) { CComBSTR bstrDeviceDesc; hr = pNode->get_text(&bstrDeviceDesc); ASSERT(SUCCEEDED(hr) && "could not get text from Desc node"); return OLE2T(bstrDeviceDesc); } } return ""; } ////////////////////////////////////////////////////////////////////////////////////////// //returns true if any changes have been entered into CMSInfocategory data ////////////////////////////////////////////////////////////////////////////////////////// BOOL CHistoryParser::AreThereChangeLines() { return this->m_fChangeLines; } ////////////////////////////////////////////////////////////////////////////////////////// //gets (from resources strings) a human-readable name for a the class wrapped the the instance ////////////////////////////////////////////////////////////////////////////////////////// CString CInstance::GetClassFriendlyName() { CString strClassName = GetClassName(); if (strClassName.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0) { VERIFY(m_mapNameValue.Lookup(_T("ANTECEDENT"),strClassName) && _T("Could not find antecedent")); } CString strFriendlyName; if (strClassName.CompareNoCase(_T("Win32_CodecFile")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_CODEC_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_ComputerSystem")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_COMPUTERSYSTEM_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_LogicalMemoryConfiguration")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_LOGICALMEMEORY_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_LogicalDisk")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_LOGICALDISK_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_IRQResource")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_IRQRESOURCE_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_DriverVXD")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_DRIVERVXD_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_DMAChannel")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_DMACHANNEL_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_DeviceMemoryAddress")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_DEVICEMEMORYADDRESS_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_NetworkProtocol")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_NETWORKPROTOCOL_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_OperatingSystem")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_OPERATINGSYSTEM_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_PNPAllocatedResource")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_PNPALLOCATEDRESOURCE_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_PNPEntity")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_PNPENTITY_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_PortResource")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_PORTRESOURCE_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_Printer")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_PRINTER_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_ProgramGroup")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_PROGRAMGROUP_DESC) && _T("could not find string resource")); return strFriendlyName; } if (strClassName.CompareNoCase(_T("Win32_StartupCommand")) == 0) { VERIFY(strFriendlyName.LoadString(IDS_STARTUPCOMMAND_DESC) && _T("could not find string resource")); return strFriendlyName; } ASSERT(0 && "Unknown strClassName"); return ""; }