|
|
//=============================================================================
// This file contains code to implement the CMSInfoCategory derived class for
// showing live WMI data.
//=============================================================================
#include "stdafx.h"
#include "resource.h"
#include "category.h"
#include "datasource.h"
#include "dataset.h"
#include "refreshthread.h"
#include "refreshdialog.h"
#include "wbemcli.h"
#include "version5extension.h"
#include "filestuff.h"
#include "historyparser.h"
//=============================================================================
// CLiveDataSource
//
// TBD - need methods to look at deltas. How will this work?
//=============================================================================
CLiveDataSource::CLiveDataSource() : m_hwnd(NULL), m_pThread(NULL), m_strMachine(_T("")), m_pHistoryRoot(NULL), m_iDeltaIndex(-1) { }
//-----------------------------------------------------------------------------
// The default constructor will take care of deleting the tree.
//-----------------------------------------------------------------------------
CLiveDataSource::~CLiveDataSource() { if (m_pThread) delete m_pThread; }
//-----------------------------------------------------------------------------
// Creating a live data source consists of making the WMI connection to the
// appropriate machine (most likely this one). We'll also need to load the
// tree with default categories.
//
// TBD - also load extensions
//-----------------------------------------------------------------------------
extern CMSInfoLiveCategory catSystemSummary; extern CMSInfoHistoryCategory catHistorySystemSummary;
HRESULT CLiveDataSource::Create(LPCTSTR szMachine, HWND hwnd, LPCTSTR szFilter) { // Build the tree. The default categories are stored in a static
// set of structures - the base of which is catSystemSummary.
m_pHistoryRoot = &catHistorySystemSummary; m_pRoot = &catSystemSummary; m_fStaticTree = TRUE;
// Load any extensions to the live data.
AddExtensions();
// If there is a string containing a filter of what categories
// to show, apply that filter.
if (szFilter && szFilter[0]) ApplyCategoryFilter(szFilter);
// Save the machine name we are remoting to.
m_strMachine = szMachine; SetMachineForCategories((CMSInfoLiveCategory *) m_pRoot);
// Create the refresh thread for the live data source.
m_pThread = new CRefreshThread(hwnd); if (m_pThread) m_pThread->m_strMachine = szMachine;
m_hwnd = hwnd;
return S_OK; }
//-----------------------------------------------------------------------------
// Apply the set of filters to the categories. If the filter string is not
// empty, we should start out showing none of the categories, and only add in
// the ones specified by the filter (this is to match a feature in 5.0).
//-----------------------------------------------------------------------------
void CLiveDataSource::ApplyCategoryFilter(LPCTSTR szFilter) { m_pRoot->SetShowCategory(FALSE);
CString strNode, strFilter(szFilter); strFilter.TrimLeft(_T(" \"=:")); strFilter.TrimRight(_T(" \"=:"));
while (!strFilter.IsEmpty()) { BOOL fAdd = (strFilter[0] == _T('+')); strFilter = strFilter.Mid(1);
if (!strFilter.IsEmpty()) { strNode = strFilter.SpanExcluding(_T("+-")); strFilter = strFilter.Mid(strNode.GetLength());
if (!strNode.IsEmpty()) { CMSInfoLiveCategory * pNode;
if (strNode.CompareNoCase(_T("all")) == 0) pNode = (CMSInfoLiveCategory *) m_pRoot; else pNode = GetNodeByName(strNode, (CMSInfoLiveCategory *) m_pRoot);
if (pNode) pNode->SetShowCategory(fAdd); } } } }
//-----------------------------------------------------------------------------
// Add version 5.0 extensions to the m_pRoot category tree.
//
// Note - we only want to do this once. And we only want to delete the nodes
// we added once (when we're unloading). So we'll create a simple class to
// manage this lifetime.
//
// THIS CLASS IS DANGEROUS (and this should probably be redesigned). It should
// only be used to add extensions to a static tree, that won't be deleted
// any time before the app exits. This class assumes the responsibility for
// deleting the dynamic nodes inserted into the tree.
//-----------------------------------------------------------------------------
class CManageExtensionCategories { public: CManageExtensionCategories() : m_pRoot(NULL) {}; ~CManageExtensionCategories() { DeleteTree(m_pRoot); }; BOOL ExtensionsAdded(CMSInfoLiveCategory * pRoot) { if (m_pRoot) return TRUE; m_pRoot = pRoot; return FALSE; }
private: CMSInfoLiveCategory * m_pRoot;
void DeleteTree(CMSInfoLiveCategory * pRoot) { if (pRoot == NULL) return;
for (CMSInfoLiveCategory * pChild = (CMSInfoLiveCategory *) pRoot->GetFirstChild(); pChild;) { CMSInfoLiveCategory * pNext = (CMSInfoLiveCategory *) pChild->GetNextSibling(); DeleteTree(pChild); pChild = pNext; }
// If the tree is static, then don't actually delete, just reset
// some state variables (possibly).
if (pRoot->m_fDynamicColumns) delete pRoot; } }; CManageExtensionCategories gManageExtensionCategories;
extern BOOL FileExists(const CString & strFile); void CLiveDataSource::AddExtensions() { if (gManageExtensionCategories.ExtensionsAdded((CMSInfoLiveCategory *) m_pRoot)) return;
CStringList strlistExtensions;
GetExtensionSet(strlistExtensions); while (!strlistExtensions.IsEmpty()) { CString strExtension = strlistExtensions.RemoveHead(); if (FileExists(strExtension)) { CMapWordToPtr mapVersion5Categories;
DWORD dwRootID = CTemplateFileFunctions::ParseTemplateIntoVersion5Categories(strExtension, mapVersion5Categories); ConvertVersion5Categories(mapVersion5Categories, dwRootID, (CMSInfoLiveCategory *) m_pRoot); } } }
//-----------------------------------------------------------------------------
// Look for all of the version 5.0 style extension. These will be located as
// values under the msinfo\templates registry key.
//-----------------------------------------------------------------------------
void CLiveDataSource::GetExtensionSet(CStringList & strlistExtensions) { strlistExtensions.RemoveAll();
TCHAR szBaseKey[] = _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo\\templates"); HKEY hkeyBase;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBaseKey, 0, KEY_READ, &hkeyBase)) { TCHAR szName[64], szValue[MAX_PATH]; DWORD dwIndex = 0; DWORD dwLength = sizeof(szName) / sizeof(TCHAR); while (ERROR_SUCCESS == RegEnumKeyEx(hkeyBase, dwIndex++, szName, &dwLength, NULL, NULL, NULL, NULL)) { dwLength = sizeof(szValue) / sizeof(TCHAR); if (ERROR_SUCCESS == RegQueryValue(hkeyBase, szName, szValue, (long *)&dwLength)) if (*szValue) strlistExtensions.AddTail(szValue); dwLength = sizeof(szName) / sizeof(TCHAR); }
RegCloseKey(hkeyBase); } }
//-----------------------------------------------------------------------------
// Convert the categories from version 5.0 format (in the map) to our
// format in the tree structure.
//-----------------------------------------------------------------------------
extern CMSInfoLiveCategory catSystemSummary;
void CLiveDataSource::ConvertVersion5Categories(CMapWordToPtr & mapVersion5Categories, DWORD dwRootID, CMSInfoLiveCategory * m_pRoot) { WORD wMapID; INTERNAL_CATEGORY * pCategory; POSITION pos; DWORD dwID = dwRootID; CMSInfoLiveCategory * pInsertCat;
while ((pCategory = CTemplateFileFunctions::GetInternalRep(mapVersion5Categories, dwID)) != NULL) { INTERNAL_CATEGORY * pPrev = CTemplateFileFunctions::GetInternalRep(mapVersion5Categories, pCategory->m_dwPrevID); if (pPrev && (pInsertCat = GetNodeByName(pPrev->m_strIdentifier, m_pRoot))) { CMSInfoLiveCategory * pNewCat = MakeVersion6Category(pCategory); pNewCat->m_pPrevSibling = pInsertCat; pNewCat->m_pNextSibling = pInsertCat->m_pNextSibling; pNewCat->m_pParent = pInsertCat->m_pParent; pInsertCat->m_pNextSibling = pNewCat; if (pNewCat->m_pNextSibling) pNewCat->m_pNextSibling->m_pPrevSibling = pNewCat; } else { INTERNAL_CATEGORY * pParent = CTemplateFileFunctions::GetInternalRep(mapVersion5Categories, pCategory->m_dwParentID); CString strIdentifier; if (pParent) strIdentifier = pParent->m_strIdentifier; else catSystemSummary.GetNames(NULL, &strIdentifier);
if ((pInsertCat = GetNodeByName(strIdentifier, m_pRoot)) != NULL) { CMSInfoLiveCategory * pNewCat = MakeVersion6Category(pCategory);
if (pInsertCat->m_pFirstChild == NULL) { pNewCat->m_pPrevSibling = NULL; pNewCat->m_pNextSibling = NULL; pNewCat->m_pParent = pInsertCat; pInsertCat->m_pFirstChild = pNewCat; } else { CMSInfoLiveCategory * pInsertAfter = (CMSInfoLiveCategory *) pInsertCat->m_pFirstChild; while (pInsertAfter->m_pNextSibling) pInsertAfter = (CMSInfoLiveCategory *) pInsertAfter->m_pNextSibling;
pNewCat->m_pPrevSibling = pInsertAfter; pNewCat->m_pNextSibling = NULL; pNewCat->m_pParent = pInsertAfter->m_pParent; pInsertAfter->m_pNextSibling = pNewCat; } } }
dwID += 1; }
for (pos = mapVersion5Categories.GetStartPosition(); pos != NULL;) { mapVersion5Categories.GetNextAssoc(pos, wMapID, (void * &) pCategory); if (pCategory) delete pCategory; }
mapVersion5Categories.RemoveAll(); }
//-----------------------------------------------------------------------------
// Look for a node in the tree with the specified name.
//-----------------------------------------------------------------------------
CMSInfoLiveCategory * CLiveDataSource::GetNodeByName(const CString & strSearch, CMSInfoLiveCategory * pRoot) { if (pRoot == NULL) return NULL;
CString strName; pRoot->GetNames(NULL, &strName);
if (strName.CompareNoCase(strSearch) == 0) return pRoot;
CMSInfoLiveCategory * pSearch = GetNodeByName(strSearch, (CMSInfoLiveCategory *) pRoot->m_pNextSibling); if (pSearch) return pSearch;
pSearch = GetNodeByName(strSearch, (CMSInfoLiveCategory *) pRoot->m_pFirstChild); if (pSearch) return pSearch;
return NULL; }
//-----------------------------------------------------------------------------
// Create a version 6.0 category structure out of a version 5.0 category
// structure.
//-----------------------------------------------------------------------------
CMSInfoLiveCategory * CLiveDataSource::MakeVersion6Category(INTERNAL_CATEGORY * pCategory5) { CMSInfoLiveCategory * pCategory6 = new CMSInfoLiveCategory(pCategory5); return pCategory6; }
//-----------------------------------------------------------------------------
// Propagate the machine name through the entire category tree.
//-----------------------------------------------------------------------------
void CLiveDataSource::SetMachineForCategories(CMSInfoLiveCategory * pCategory) { if (pCategory) { for (CMSInfoLiveCategory * pChild = (CMSInfoLiveCategory *) pCategory->GetFirstChild(); pChild;) { CMSInfoLiveCategory * pNext = (CMSInfoLiveCategory *) pChild->GetNextSibling(); SetMachineForCategories(pChild); pChild = pNext; }
pCategory->SetMachine(m_strMachine); } }
//-----------------------------------------------------------------------------
// Update the category tree to show delta information. Also changes which
// tree should be returned.
//
// An index of -1 means show current system information.
//
// If the function returns TRUE, then the tree doesn't need to be rebuild
// (although the selected category needs to be refreshed).
//-----------------------------------------------------------------------------
BOOL CLiveDataSource::ShowDeltas(int iDeltaIndex) { BOOL fUpdateTree = FALSE;
if (m_iDeltaIndex != iDeltaIndex) {
if (m_iDeltaIndex == -1 || iDeltaIndex == -1) fUpdateTree = TRUE; #ifdef A_STEPHL
/*CString strMSG;
strMSG.Format("iDeltaIndex= %d, m_iDeltaIndex =%d \n",iDeltaIndex,m_iDeltaIndex); ::MessageBox(NULL,strMSG,"",MB_OK);*/ #endif
m_iDeltaIndex = iDeltaIndex; if (m_iDeltaIndex != -1) { // The user has selected a new delta period, and it's different
// than the last one. We need to mark the categories in the tree
// as not refreshed, and set the delta index.
if (m_pHistoryRoot) m_pHistoryRoot->UpdateDeltaIndex(m_iDeltaIndex); } } else { #ifdef A_STEPHL2
::MessageBox(NULL,"m_iDeltaIndex == iDeltaIndex","",MB_OK); #endif
return TRUE; }
return !fUpdateTree; }
//-----------------------------------------------------------------------------
// Populate the list of available deltas.
//-----------------------------------------------------------------------------
BOOL CLiveDataSource::GetDeltaList(CStringList * pstrlist) { ASSERT(pstrlist); if (pstrlist == NULL) return FALSE;
pstrlist->RemoveAll();
if (m_pHistoryRoot == NULL) { ASSERT(0 && "Root node is not yet created"); }
CComPtr<IXMLDOMDocument> pXMLDoc = GetXMLDoc(); CComPtr<IXMLDOMNode> pDCNode; HRESULT hr = GetDataCollectionNode( pXMLDoc,pDCNode); if (FAILED(hr) || !pDCNode) { return FALSE; } CComPtr<IXMLDOMNodeList> pList; hr = pDCNode->selectNodes(L"Delta",&pList); if (FAILED(hr) || !pList) { ASSERT(0 && "could not get list of delta nodes"); return FALSE; } long lListLen; hr = pList->get_length(&lListLen); if (lListLen == 0) { //we may have an incident file, which capitalizes "DELTA"
pList.Release(); hr = pDCNode->selectNodes(L"DELTA",&pList); if (FAILED(hr) || !pList) { ASSERT(0 && "could not get list of delta nodes"); return FALSE; } hr = pList->get_length(&lListLen); } if (lListLen > 0) { CComPtr<IXMLDOMNode> pDeltaNode; CString strDate(_T("")); TCHAR szBuffer[MAX_PATH]; // seems plenty big
for(long i = 0 ;i < lListLen;i++) { hr = pList->nextNode(&pDeltaNode); if (FAILED(hr) || !pDeltaNode) { ASSERT(0 && "could not get next node from list"); break; } CComVariant varTS; CComPtr<IXMLDOMElement> pTimestampElement; hr = pDeltaNode->QueryInterface(IID_IXMLDOMElement,(void**) &pTimestampElement); pDeltaNode.Release(); if (FAILED(hr) || !pTimestampElement) { ASSERT(0 && "could not get attribute element"); break; } hr = pTimestampElement->getAttribute(L"Timestamp_T0",&varTS); if (FAILED(hr) ) { ASSERT(0 && "could not get timestamp value from attribute"); } //now get time zone (number of seconds difference between local time and UTC)
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; } USES_CONVERSION;
pTimestampElement.Release(); CString strTimestamp = OLE2A(varTS.bstrVal); CTime tm1 = GetDateFromString(strTimestamp,varTzoneDeltaSeconds.intVal); COleDateTime olDate(tm1.GetTime());
// Try to get the date in the localized format.
strDate.Empty(); SYSTEMTIME systime; if (olDate.GetAsSystemTime(systime)) { DWORD dwLayout = 0; ::GetProcessDefaultLayout(&dwLayout);
// For some reason, in HEB we don't want to use the DATE_RTLREADING flag. Bug 434802.
if (LANG_HEBREW == PRIMARYLANGID(::GetUserDefaultUILanguage())) dwLayout &= ~LAYOUT_RTL; // force the non-use of DATE_RTLREADING
if (::GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE | (((dwLayout & LAYOUT_RTL) != 0) ? DATE_RTLREADING : 0), &systime, NULL, szBuffer, MAX_PATH)) { strDate = szBuffer; if (::GetTimeFormat(LOCALE_USER_DEFAULT, 0, &systime, NULL, szBuffer, MAX_PATH)) strDate += CString(_T(" ")) + CString(szBuffer); } }
// Fall back on our old (partially incorrect) method.
if (strDate.IsEmpty()) strDate = olDate.Format(0, LOCALE_USER_DEFAULT);
pstrlist->AddTail(strDate); } }
return TRUE; }
//-----------------------------------------------------------------------------
// Return an HRESULT indicating whether or not this is a valid data source.
// This is primarily useful when we're remoting to a machine and we want to
// determine if the network name is accessible.
//-----------------------------------------------------------------------------
HRESULT CLiveDataSource::ValidDataSource() { if (m_pThread == NULL) return E_FAIL;
return (m_pThread->CheckWMIConnection()); }
//=============================================================================
// CMSInfoLiveCategory
//=============================================================================
//-----------------------------------------------------------------------------
// The constructor needs to initialize some member variables, and make sure
// that the category is inserted into the tree correctly.
//-----------------------------------------------------------------------------
CMSInfoLiveCategory::CMSInfoLiveCategory(UINT uiCaption, LPCTSTR szName, RefreshFunction pFunction, DWORD dwRefreshIndex, CMSInfoCategory * pParent, CMSInfoCategory * pPrevious, const CString & strHelpTopic, CMSInfoColumn * pColumns, BOOL fDynamicColumns, CategoryEnvironment environment) : CMSInfoCategory(uiCaption, szName, pParent, pPrevious, pColumns, fDynamicColumns, environment), m_pRefreshFunction(pFunction), m_dwLastRefresh(0), m_dwRefreshIndex(dwRefreshIndex), m_strMachine(_T("")), m_strHelpTopic(strHelpTopic) { // Insert ourselves into the category tree. This means making sure that
// our parent and previous sibling point to us.
if (m_pParent && m_pParent->m_pFirstChild == NULL) m_pParent->m_pFirstChild = this;
if (m_pPrevSibling) { if (m_pPrevSibling->m_pNextSibling == NULL) m_pPrevSibling->m_pNextSibling = this; else { CMSInfoCategory * pScan = m_pPrevSibling->m_pNextSibling; while (pScan->m_pNextSibling) pScan = pScan->m_pNextSibling; pScan->m_pNextSibling = this; } } }
CMSInfoLiveCategory::~CMSInfoLiveCategory() { }
//-----------------------------------------------------------------------------
// The copy constructor will copy the members, but not allocate a new sub-tree
// (the new category has the same children and siblings as the original).
//-----------------------------------------------------------------------------
CMSInfoLiveCategory::CMSInfoLiveCategory(CMSInfoLiveCategory & copyfrom) : m_dwLastRefresh(0), m_dwRefreshIndex(copyfrom.m_dwRefreshIndex), m_pRefreshFunction(copyfrom.m_pRefreshFunction) { m_strMachine = copyfrom.m_strMachine; m_strHelpTopic = copyfrom.m_strHelpTopic; m_uiCaption = copyfrom.m_uiCaption; m_pParent = copyfrom.m_pParent; m_pPrevSibling = copyfrom.m_pPrevSibling; m_pFirstChild = copyfrom.m_pFirstChild; m_pNextSibling = copyfrom.m_pNextSibling;
m_astrData = NULL; m_adwData = NULL; m_afRowAdvanced = NULL;
m_strName = copyfrom.m_strName; m_hrError = S_OK; m_acolumns = copyfrom.m_acolumns; m_fDynamicColumns = FALSE;
m_iRowCount = 0; m_iColCount = copyfrom.m_iColCount;
m_iSortColumn = copyfrom.m_iSortColumn; m_hti = NULL;
m_fSkipCategory = copyfrom.m_fSkipCategory; }
//-----------------------------------------------------------------------------
// Constructs a category from an old (version 5.0) category structure.
//-----------------------------------------------------------------------------
extern HRESULT RefreshExtensions(CWMIHelper * pWMI, DWORD dwIndex, volatile BOOL * pfCancel, CPtrList * aColValues, int iColCount, void ** ppCache); CMSInfoLiveCategory::CMSInfoLiveCategory(INTERNAL_CATEGORY * pinternalcat) { ASSERT(pinternalcat); if (pinternalcat == NULL) return;
m_dwLastRefresh = 0; m_strMachine = CString(_T("")); m_strHelpTopic = CString(_T("")); // Graft on a help topic for the IE extension (bug 479839).
if (pinternalcat->m_strIdentifier.CompareNoCase(_T("InternetSettings")) == 0) m_strHelpTopic = _T("msinfo_internet_settings.htm");
m_strCaption = pinternalcat->m_fieldName.m_strFormat; m_strName = pinternalcat->m_strIdentifier;
m_iRowCount = 0; m_iColCount = 0;
GATH_FIELD * pField = pinternalcat->m_pColSpec; while (pField) { m_iColCount += 1; pField = pField->m_pNext; }
if (m_iColCount) { m_acolumns = new CMSInfoColumn[m_iColCount]; if (m_acolumns && pinternalcat->m_pColSpec) { m_fDynamicColumns = TRUE; pField = pinternalcat->m_pColSpec;
for (int iCol = 0; iCol < m_iColCount && pField != NULL; iCol++) { m_acolumns[iCol].m_fAdvanced = (pField->m_datacomplexity == ADVANCED); m_acolumns[iCol].m_strCaption = pField->m_strFormat; m_acolumns[iCol].m_uiWidth = pField->m_usWidth; m_acolumns[iCol].m_fSorts = (pField->m_sort != NOSORT); m_acolumns[iCol].m_fLexical = (pField->m_sort == LEXICAL);
pField = pField->m_pNext; } } }
// Insert the information needed to refresh the extension category (such
// as line specs) into a map, indexed by a DWORD. That DWORD will be saved
// for the category, so we can look up the refresh data later.
if (pinternalcat->m_pLineSpec) { m_dwRefreshIndex = gmapExtensionRefreshData.Insert(pinternalcat->m_pLineSpec); pinternalcat->m_pLineSpec = NULL; // keep this from being deleted
m_pRefreshFunction = &RefreshExtensions; } else { m_dwRefreshIndex = 0; m_pRefreshFunction = NULL; }
if (m_dwRefreshIndex) gmapExtensionRefreshData.InsertString(m_dwRefreshIndex, pinternalcat->m_strNoInstances); }
//-----------------------------------------------------------------------------
// Start a refresh (starts the thread, which will send a message when it's
// done).
//-----------------------------------------------------------------------------
BOOL CMSInfoLiveCategory::Refresh(CLiveDataSource * pSource, BOOL fRecursive) { if (pSource && pSource->m_pThread) pSource->m_pThread->StartRefresh(this, fRecursive);
return TRUE; }
//-----------------------------------------------------------------------------
// Start a synchronous refresh. This function won't return until the refresh
// has been completed.
//-----------------------------------------------------------------------------
BOOL CMSInfoLiveCategory::RefreshSynchronous(CLiveDataSource * pSource, BOOL fRecursive) { if (pSource && pSource->m_pThread) { pSource->m_pThread->StartRefresh(this, fRecursive); pSource->m_pThread->WaitForRefresh(); }
return TRUE; }
//-----------------------------------------------------------------------------
// Refreshes the current category (and possibly the children) while presenting
// the user with a UI. A dialog box is presented to the user with the specified
// mesage. If the user clicks cancel, the refresh is cancelled and this
// function returns false. Otherwise, when the refresh is done the dialog box
// will be removed, and this funcion returns true.
//-----------------------------------------------------------------------------
BOOL CMSInfoLiveCategory::RefreshSynchronousUI(CLiveDataSource * pSource, BOOL fRecursive, UINT uiMessage, HWND hwnd) { if (pSource && pSource->m_pThread) { pSource->m_pThread->StartRefresh(this, fRecursive);
::AfxSetResourceHandle(_Module.GetResourceInstance()); CWnd * pWnd = CWnd::FromHandle(hwnd); // CRefreshDialog refreshdialog(pWnd);
// refreshdialog.DoModal();
if (pSource->m_pThread->IsRefreshing()) { pSource->m_pThread->CancelRefresh(); return FALSE; } }
return TRUE; }
//-----------------------------------------------------------------------------
// Get the error strings for this category (subclasses should override this).
//-----------------------------------------------------------------------------
void CMSInfoLiveCategory::GetErrorText(CString * pstrTitle, CString * pstrMessage) { if (SUCCEEDED(m_hrError)) { ASSERT(0 && "why call GetErrorText for no error?"); CMSInfoCategory::GetErrorText(pstrTitle, pstrMessage); return; }
if (pstrTitle) pstrTitle->LoadString(IDS_CANTCOLLECT);
if (pstrMessage) { switch (m_hrError) { case WBEM_E_OUT_OF_MEMORY: pstrMessage->LoadString(IDS_OUTOFMEMERROR); break;
case WBEM_E_ACCESS_DENIED: if (m_strMachine.IsEmpty()) pstrMessage->LoadString(IDS_GATHERACCESS_LOCAL); else pstrMessage->Format(IDS_GATHERACCESS, m_strMachine); break;
case WBEM_E_INVALID_NAMESPACE: if (m_strMachine.IsEmpty()) pstrMessage->LoadString(IDS_BADSERVER_LOCAL); else pstrMessage->Format(IDS_BADSERVER, m_strMachine); break;
case 0x800706BA: // RPC Server Unavailable
case WBEM_E_TRANSPORT_FAILURE: if (m_strMachine.IsEmpty()) pstrMessage->LoadString(IDS_NETWORKERROR_LOCAL); else pstrMessage->Format(IDS_NETWORKERROR, m_strMachine); break;
case WBEM_E_FAILED: case WBEM_E_INVALID_PARAMETER: default: pstrMessage->LoadString(IDS_UNEXPECTED); }
#ifdef _DEBUG
{ CString strTemp; strTemp.Format(_T("\n\r\n\rDebug Version Only: [HRESULT = 0x%08X]"), m_hrError); *pstrMessage += strTemp; } #endif
} }
//=============================================================================
// CMSInfoHistoryCategory
//=============================================================================
//-----------------------------------------------------------------------------
// This refresh overrides the live category refresh (which starts a WMI refresh
// using another thread). This version just fills in the variables from the
// base classes (like m_astrData) based on which category we're view in
// history mode.
//-----------------------------------------------------------------------------
extern CMSInfoHistoryCategory catHistorySystemSummary; extern CMSInfoHistoryCategory catHistoryResources; extern CMSInfoHistoryCategory catHistoryComponents; extern CMSInfoHistoryCategory catHistorySWEnv;
BOOL CMSInfoHistoryCategory::Refresh(CLiveDataSource * pSource, BOOL fRecursive) { HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); if (pSource->GetXMLDoc()) { CHistoryParser HParser(pSource->GetXMLDoc()); HRESULT hr = HParser.Refresh(this, pSource->m_iDeltaIndex ); if (HParser.AreThereChangeLines() == TRUE) { //commitlines doesn't like it if there are no change lines
this->CommitLines(); }
if (pSource->m_hwnd) ::PostMessage(pSource->m_hwnd, WM_MSINFODATAREADY, 0, (LPARAM)this); m_dwLastRefresh = ::GetTickCount(); if (fRecursive) { for(CMSInfoCategory* pChildCat = (CMSInfoCategory*) this->GetFirstChild();pChildCat != NULL;pChildCat = (CMSInfoCategory*) pChildCat->GetNextSibling()) { if(pChildCat->GetDataSourceType() == LIVE_DATA) { if (!((CMSInfoHistoryCategory*)pChildCat)->Refresh(pSource,fRecursive)) { ::SetCursor(hc); return FALSE; } } }
} } ::SetCursor(hc); return TRUE; }
//-----------------------------------------------------------------------------
// Call ClearLines before lines are inserted in the output.
//-----------------------------------------------------------------------------
void CMSInfoHistoryCategory::ClearLines() { DeleteContent(); for (int iCol = 0; iCol < 5; iCol++) while (!m_aValList[iCol].IsEmpty()) delete (CMSIValue *) m_aValList[iCol].RemoveHead(); }
//-----------------------------------------------------------------------------
// Call CommitLines after all of the Insert operations are completed. This will
// transfer the values from the lists of CMSIValues to the data arrays.
//-----------------------------------------------------------------------------
void CMSInfoHistoryCategory::CommitLines() { int iRowCount = (int)m_aValList[0].GetCount();
#ifdef _DEBUG
for (int i = 0; i < 5; i++) ASSERT(iRowCount == m_aValList[i].GetCount()); #endif
if (iRowCount) AllocateContent(iRowCount);
for (int j = 0; j < 5; j++) for (int i = 0; i < m_iRowCount; i++) { CMSIValue * pValue = (CMSIValue *) m_aValList[j].RemoveHead(); if (j < 4 || this != &catHistorySystemSummary) SetData(i, j, pValue->m_strValue, pValue->m_dwValue); // Set the advanced flag for either the first column, or
// for any column which is advanced (any cell in a row
// being advanced makes the whole row advanced).
if (j == 0 || pValue->m_fAdvanced) SetAdvancedFlag(i, pValue->m_fAdvanced);
delete pValue; } }
//-----------------------------------------------------------------------------
// Various functions to insert different types of events in the history.
//-----------------------------------------------------------------------------
void CMSInfoHistoryCategory::InsertChangeLine(CTime tm, LPCTSTR szType, LPCTSTR szName, LPCTSTR szProperty, LPCTSTR szFromVal, LPCTSTR szToVal) { CString strDetails;
strDetails.Format(IDS_DELTACHANGE, szProperty, szFromVal, szToVal); CString strCaption; strCaption.LoadString(IDS_HISTORYCHANGE); InsertLine(tm, strCaption, szType, szName, strDetails); }
void CMSInfoHistoryCategory::InsertAddLine(CTime tm, LPCTSTR szType, LPCTSTR szName) { CString strCaption; strCaption.LoadString(IDS_HISTORYADDED); InsertLine(tm, strCaption, szType, szName); }
void CMSInfoHistoryCategory::InsertRemoveLine(CTime tm, LPCTSTR szType, LPCTSTR szName) { CString strCaption; strCaption.LoadString(IDS_HISTORYREMOVED); InsertLine(tm, strCaption, szType, szName); }
void CMSInfoHistoryCategory::InsertLine(CTime tm, LPCTSTR szOperation, LPCTSTR szType, LPCTSTR szName, LPCTSTR szDetails) { AFX_MANAGE_STATE(::AfxGetStaticModuleState());
/*CString strTime;
if (nDays >= 0) { strTime.Format(IDS_DAYSAGO, nDays + 1); } else { //-1 indicates no changes
strTime = ""; }*/ COleDateTime olTime; CString strTime; if (-1 == (int) tm.GetTime()) {
strTime.LoadString(IDS_NOHISTORY_AVAILABLE); } else { olTime = tm.GetTime(); strTime = olTime.Format();
} CMSIValue * pValue = new CMSIValue(strTime, (DWORD)olTime.m_dt); m_aValList[0].AddTail((void *) pValue);
pValue = new CMSIValue(szOperation, 0); m_aValList[1].AddTail((void *) pValue);
pValue = new CMSIValue(szName, 0); m_aValList[2].AddTail((void *) pValue);
if (szDetails) pValue = new CMSIValue(szDetails, 0); else pValue = new CMSIValue(_T(""), 0); m_aValList[3].AddTail((void *) pValue);
pValue = new CMSIValue(szType, 0); m_aValList[4].AddTail((void *) pValue); }
/*void CMSInfoHistoryCategory::InsertChangeLine(int nDays, LPCTSTR szType, LPCTSTR szName, LPCTSTR szProperty, LPCTSTR szFromVal, LPCTSTR szToVal)
{ CString strDetails;
strDetails.Format(IDS_DELTACHANGE, szProperty, szFromVal, szToVal); InsertLine(nDays, _T("CHANGED"), szType, szName, strDetails); }
void CMSInfoHistoryCategory::InsertAddLine(int nDays, LPCTSTR szType, LPCTSTR szName) { InsertLine(nDays, _T("ADDED"), szType, szName); }
void CMSInfoHistoryCategory::InsertRemoveLine(int nDays, LPCTSTR szType, LPCTSTR szName) { InsertLine(nDays, _T("REMOVED"), szType, szName); }
void CMSInfoHistoryCategory::InsertLine(int nDays, LPCTSTR szOperation, LPCTSTR szType, LPCTSTR szName, LPCTSTR szDetails) { AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CString strTime; if (nDays >= 0) { strTime.Format(IDS_DAYSAGO, nDays + 1); } else { //-1 indicates no changes
strTime = ""; }
CMSIValue * pValue = new CMSIValue(strTime, (DWORD)nDays); m_aValList[0].AddTail((void *) pValue);
pValue = new CMSIValue(szOperation, 0); m_aValList[1].AddTail((void *) pValue);
pValue = new CMSIValue(szName, 0); m_aValList[2].AddTail((void *) pValue);
if (szDetails) pValue = new CMSIValue(szDetails, 0); else pValue = new CMSIValue(_T(""), 0); m_aValList[3].AddTail((void *) pValue);
pValue = new CMSIValue(szType, 0); m_aValList[4].AddTail((void *) pValue); } */
|