|
|
//=============================================================================
// MSInfo.cpp : Implementation of CMSInfo
//
// Contains implementation for some of the functions in the CMSInfo class
// (the ones which aren't inline).
//=============================================================================
#include "stdafx.h"
#include "Msinfo32.h"
#include "MSInfo.h"
#include "cabfunc.h"
#include "msictrl.h"
#include "MSInfo4Category.h"
#include "remotedialog.h"
#include "filestuff.h"
#include <afxole.h>
//a-kjaw
#include "dataset.h"
//a-kjaw
WNDPROC CMSInfo::m_wndprocParent = NULL; CMSInfo * CMSInfo::m_pControl = NULL;
extern CMSInfoHistoryCategory catHistorySystemSummary; extern CMSInfoHistoryCategory catHistoryResources; extern CMSInfoHistoryCategory catHistoryComponents; extern CMSInfoHistoryCategory catHistorySWEnv;
//=========================================================================
// Here's a very simple class to show a message when the data is
// being refreshed.
//=========================================================================
class CWaitForRefreshDialog : public CDialogImpl<CWaitForRefreshDialog> { public: enum { IDD = IDD_WAITFORREFRESHDIALOG };
//-------------------------------------------------------------------------
// Refresh the specified category using the specified source.
//-------------------------------------------------------------------------
int DoRefresh(CLiveDataSource * pSource, CMSInfoLiveCategory * pLiveCategory) { m_pSource = pSource; m_pLiveCategory = pLiveCategory; m_nCategories = pLiveCategory->GetCategoryCount(); if (m_nCategories == 0) m_nCategories = 1; // should never happen
return (int)DoModal(); };
//-------------------------------------------------------------------------
// When the dialog initializes, the source and category pointers should
// have already been set. Start the refresh and create a timer to control
// the update of information on the dialog. The timer is set to 500ms.
//-------------------------------------------------------------------------
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_pSource && m_pSource->m_pThread && m_pLiveCategory) m_pSource->m_pThread->StartRefresh(m_pLiveCategory, TRUE); m_iTimer = (UINT)SetTimer(1, 500); return 0; }
//-------------------------------------------------------------------------
// Every time the timer fires, check to see if the refresh is done. If
// it is, close the dialog. Otherwise, update the progress bar and
// refreshing category string.
//-------------------------------------------------------------------------
LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_pSource == NULL) return 0;
if (!m_pSource->m_pThread->IsRefreshing()) { KillTimer(m_iTimer); EndDialog(0); return 0; }
CString strCurrent; LONG nCount;
m_pSource->m_pThread->GetRefreshStatus(&nCount, &strCurrent); if (nCount > 0) nCount -= 1; // this number is incremented before the refresh is complete
UpdateProgress((nCount * 100) / m_nCategories, strCurrent); return 0; }
//-------------------------------------------------------------------------
// Update the percentage complete and the refreshing category name.
//-------------------------------------------------------------------------
void UpdateProgress(int iPercent, const CString & strCurrent = _T("")) { HWND hwnd = GetDlgItem(IDC_REFRESHPROGRESS); if (hwnd != NULL) { if (iPercent < 0) iPercent = 0; if (iPercent > 100) iPercent = 100;
::SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); ::SendMessage(hwnd, PBM_SETPOS, iPercent, 0); }
if (!strCurrent.IsEmpty()) { hwnd = GetDlgItem(IDC_REFRESHCAT); if (hwnd != NULL) ::SetWindowText(hwnd, strCurrent); } }
private: CLiveDataSource * m_pSource; CMSInfoLiveCategory * m_pLiveCategory; int m_nCategories; UINT m_iTimer;
BEGIN_MSG_MAP(CWaitForRefreshDialog) MESSAGE_HANDLER(WM_TIMER, OnTimer) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) END_MSG_MAP() };
UINT HistoryRefreshDlgThreadProc( LPVOID pParam ) { CMSInfo* pInfo = (CMSInfo*) pParam; if (WAIT_OBJECT_0 != WaitForSingleObject(pInfo->m_hEvtHistoryComplete,60*60*10/*10 minutes*/)) { ASSERT(0 && "Wait Abandoned or timed out"); } pInfo->m_HistoryProgressDlg.EndDialog(MB_OK);//use if dlg was create with DoModal()
return 0; }
//=========================================================================
// A function to check if a file is a version 4.x (compound document) file
// (for bug 582973). It checks this by opening the file, opening the
// "MSInfo" stream and checking the version number.
//=========================================================================
BOOL IsVersion4File(const CString & strFilename) { BOOL fReturn = FALSE; DWORD grfMode = STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE; CComBSTR bstrFileName(strFilename); CComPtr<IStorage> pStorage;
if (SUCCEEDED(StgOpenStorage(bstrFileName, NULL, grfMode, NULL, 0, &pStorage))) { CComPtr<IStream> pStream; CComBSTR bstrMSIStream(_T("MSInfo"));
if (SUCCEEDED(pStorage->OpenStream(bstrMSIStream, NULL, grfMode, 0, &pStream))) { const DWORD MSI_FILE_VER = 0x03000000; COleStreamFile * pOStream; DWORD dwVersion; ULONG ulCount;
pOStream = new COleStreamFile(pStream); if (pOStream->Read((void *) &dwVersion, sizeof(DWORD)) == sizeof(DWORD)) fReturn = (dwVersion == MSI_FILE_VER); delete pOStream; } } return fReturn; }
//=========================================================================
// Dispatch a command from the user (such as a menu bar selection).
//=========================================================================
BOOL CMSInfo::DispatchCommand(int iCommand) { BOOL fHandledCommand = TRUE;
// Can't do any command while the find is in progress.
if (m_fInFind) { CancelFind(); SelectCategory(GetCurrentCategory()); }
// Before we execute a command, make sure that any refreshes currently
// in progress are finished.
CMSInfoCategory * pCategory = GetCurrentCategory(); if (pCategory && pCategory->GetDataSourceType() == LIVE_DATA) { CLiveDataSource * pLiveDataSource = (CLiveDataSource *) m_pCurrData; HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); pLiveDataSource->WaitForRefresh(); ::SetCursor(hc); }
// Check to see if the selected command is a tool that we added to the
// tools menu.
CMSInfoTool * pTool; if (m_mapIDToTool.Lookup((WORD) iCommand, (void * &) pTool)) { ASSERT(pTool); if (pTool) pTool->Execute(); return TRUE; }
switch (iCommand) { case ID_FILE_OPENNFO: if (m_fFindVisible) DispatchCommand(ID_EDIT_FIND); OpenNFO(); break;
case ID_FILE_SAVENFO: SaveNFO(); break; case ID_FILE_CLOSE: if (m_fFindVisible) DispatchCommand(ID_EDIT_FIND); CloseFile(); break;
case ID_FILE_EXPORT: Export(); break;
case ID_FILE_PRINT: DoPrint(); break;
case ID_FILE_EXIT: if (NULL != m_hwndParent) ::PostMessage(m_hwndParent, WM_CLOSE, 0, 0); break;
case ID_EDIT_COPY: EditCopy(); break;
case ID_EDIT_PASTE: if (GetFocus() == m_wndFindWhat.m_hWnd && m_wndFindWhat.IsWindowVisible() && m_wndFindWhat.IsWindowEnabled()) { BOOL fHandled = FALSE; if (::OpenClipboard(m_hWnd)) { if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) { HANDLE h = ::GetClipboardData(CF_UNICODETEXT); if (h != NULL) { LPWSTR szData = (LPWSTR)GlobalLock(h); if (szData != NULL) { // If the user tries to paste a tab character, replace it with spaces.
CString strTemp(szData); if (strTemp.Find(_T('\t')) != -1) strTemp.Replace(_T('\t'), _T(' '));
SETTEXTEX st; st.flags = ST_SELECTION; st.codepage = 1200; // Unicode
m_wndFindWhat.SendMessage(EM_SETTEXTEX, (WPARAM)&st, (LPARAM)(LPCTSTR)strTemp); fHandled = TRUE; GlobalUnlock(h); } } }
::CloseClipboard(); }
if (!fHandled) m_wndFindWhat.SendMessage(WM_PASTE); } break;
case ID_EDIT_SELECTALL: EditSelectAll(); break;
case ID_EDIT_FIND: m_fFindVisible = !m_fFindVisible;
m_fFindNext = FALSE; m_pcatFind = NULL; m_fCancelFind = FALSE; m_fInFind = FALSE; ShowFindControls(); LayoutControl(); SetMenuItems(); UpdateFindControls(); if (m_fFindVisible) GotoDlgCtrl(m_wndFindWhat.m_hWnd); break;
case ID_VIEW_REFRESH: MSInfoRefresh(); break;
case ID_VIEW_BASIC: if (m_fAdvanced) { m_fAdvanced = FALSE; RefillListView(FALSE); SetMenuItems(); } break;
case ID_VIEW_ADVANCED: if (!m_fAdvanced) { m_fAdvanced = TRUE; RefillListView(FALSE); SetMenuItems(); } break;
case ID_VIEW_REMOTE_COMPUTER: ShowRemoteDialog(); break;
case ID_VIEW_CURRENT: case ID_VIEW_HISTORY: { int iShow = (iCommand == ID_VIEW_HISTORY) ? SW_SHOW : SW_HIDE; /* v-stlowe 2/27/2001:
problem: if history was loaded from file after combo has been populated, combo doesn't get updated. So update each time we switch to history view if (iCommand == ID_VIEW_HISTORY && m_history.SendMessage(CB_GETCURSEL, 0, 0) == CB_ERR) */ if (iCommand == ID_VIEW_HISTORY) FillHistoryCombo();
//v-stlowe 3/04/2001
//if (!this->m_pHistoryStream)
//{
if (this->m_pDCO && !((CLiveDataSource *)m_pLiveData)->GetXMLDoc() && ID_VIEW_HISTORY == iCommand) { VERIFY(m_pDCO && "NULL datacollection object"); if (m_pDCO) { HRESULT hr; HWND hWnd = m_HistoryProgressDlg.GetDlgItem(IDC_PROGRESS1); if(::IsWindow(hWnd)) { ::SendMessage(hWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); ::SendMessage(hWnd,PBM_SETPOS,0,0); ::SendMessage(hWnd, PBM_DELTAPOS, 0, 0L); } m_pDCO->ExecuteAsync(); //m_HistoryProgressDlg.Create(m_hWnd);
ResetEvent(m_hEvtHistoryComplete); AfxBeginThread((AFX_THREADPROC) HistoryRefreshDlgThreadProc,this); m_HistoryProgressDlg.DoModal(m_hWnd);
} } else {
} //end v-stlowe 12/17/00
m_history.ShowWindow(iShow); m_historylabel.ShowWindow(iShow); LayoutControl();
HTREEITEM htiToSelect = NULL;
if (iCommand == ID_VIEW_HISTORY) { m_pLastCurrentCategory = GetCurrentCategory();
int iIndex = (int)m_history.SendMessage(CB_GETCURSEL, 0, 0); if (iIndex == CB_ERR) { iIndex = 0; m_history.SendMessage(CB_SETCURSEL, (WPARAM)iIndex, 0); } ChangeHistoryView(iIndex);
// Select the appropriate history category based on the current info category.
CMSInfoHistoryCategory * pHistoryCat = NULL; CString strName;
m_pLastCurrentCategory->GetNames(NULL, &strName); if (!strName.IsEmpty()) { // This is a little kludgy:
//todo: append file name if XML stream was opened from a file
if (strName.Left(13) == CString(_T("SystemSummary"))) pHistoryCat = &catHistorySystemSummary; else if (strName.Left(9) == CString(_T("Resources"))) pHistoryCat = &catHistoryResources; else if (strName.Left(10) == CString(_T("Components"))) pHistoryCat = &catHistoryComponents; else if (strName.Left(5) == CString(_T("SWEnv"))) pHistoryCat = &catHistorySWEnv; }
if (pHistoryCat) htiToSelect = pHistoryCat->GetHTREEITEM(); } else { ChangeHistoryView(-1);
// Changing to always select the system summary category when
// switching back from history view.
//
// if (m_pLastCurrentCategory)
// htiToSelect = m_pLastCurrentCategory->GetHTREEITEM();
htiToSelect = TreeView_GetRoot(m_tree.m_hWnd); }
if (htiToSelect != NULL) { TreeView_EnsureVisible(m_tree.m_hWnd, htiToSelect); TreeView_SelectItem(m_tree.m_hWnd, htiToSelect); }
SetMenuItems(); } break;
case ID_TOOLS_PLACEHOLDER: break;
case ID_HELP_ABOUT: { CSimpleDialog<IDD_ABOUTBOX> dlg; dlg.DoModal(); } break;
case ID_HELP_CONTENTS: //::HtmlHelp(m_hWnd, _T("msinfo32.chm"), HH_DISPLAY_TOPIC, 0);
ShowHSCHelp(_T("msinfo_overview.htm")); break;
case ID_HELP_TOPIC: ShowCategoryHelp(GetCurrentCategory()); break;
default: fHandledCommand = FALSE; break; }
return fHandledCommand; }
//=========================================================================
// Called to allow the user to remote to a different computer.
//=========================================================================
void CMSInfo::ShowRemoteDialog() { AFX_MANAGE_STATE(::AfxGetStaticModuleState());
CRemoteDialog dlg; dlg.SetRemoteDialogValues(m_hWnd, !m_strMachine.IsEmpty(), m_strMachine); if (dlg.DoModal() == IDOK) { HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); CString strMachine; BOOL fRemote;
dlg.GetRemoteDialogValues(&fRemote, &strMachine); if (!fRemote) strMachine.Empty();
if (strMachine.CompareNoCase(m_strMachine) != 0) DoRemote(strMachine);
::SetCursor(hc); } }
void CMSInfo::DoRemote(LPCTSTR szMachine) { CString strMachine(szMachine);
// The user has changed the machine name. We need to recreate the
// current data source object with the new machine name. Also, make
// sure we aren't showing history data.
if (m_history.IsWindowVisible()) DispatchCommand(ID_VIEW_CURRENT);
CLiveDataSource * pLiveData = new CLiveDataSource; if (pLiveData) { HRESULT hr = pLiveData->Create(strMachine, m_hWnd, m_strCategories); if (FAILED(hr)) { // bad news, report an error
delete pLiveData; } else { // Check to see if the pLiveData works. If it doesn't (for example,
// if it's to a non-existent machine), don't change the data source.
HRESULT hr = pLiveData->ValidDataSource(); if (SUCCEEDED(hr)) { pLiveData->m_pHistoryStream = ((CLiveDataSource *)m_pLiveData)->m_pHistoryStream; pLiveData->m_pXMLDoc = ((CLiveDataSource *)m_pLiveData)->m_pXMLDoc;
if (m_pLiveData) delete m_pLiveData; m_pLiveData = pLiveData; m_strMachine = strMachine; SelectDataSource(m_pLiveData); } else { // Report the error for the bad connection.
CString strMessage;
if (strMachine.IsEmpty()) strMessage.LoadString(IDS_REMOTEERRORLOCAL); else strMessage.Format(IDS_REMOTEERRORREMOTE, strMachine);
MSInfoMessageBox(strMessage); delete pLiveData; } } } else { // bad news - no memory
} }
//=========================================================================
// Functions for managing the displayed data.
//=========================================================================
void CMSInfo::SelectDataSource(CDataSource * pDataSource) { ASSERT(pDataSource); if (pDataSource == NULL || m_pCurrData == pDataSource) return; m_pCurrData = pDataSource; m_pCategory = NULL;
// Clear the existing categories in the tree.
TreeClearItems();
// Load the contents of the tree from the data source.
CMSInfoCategory * pRoot = m_pCurrData->GetRootCategory(); if (pRoot) { BuildTree(TVI_ROOT, TVI_LAST, pRoot); TreeView_Expand(m_tree.m_hWnd, TreeView_GetRoot(m_tree.m_hWnd), TVE_EXPAND); TreeView_SelectItem(m_tree.m_hWnd, TreeView_GetRoot(m_tree.m_hWnd)); }
SetMenuItems(); }
//-------------------------------------------------------------------------
// Select the specified category.
//
// TBD - better to check columns for being the same
//-------------------------------------------------------------------------
void CMSInfo::SelectCategory(CMSInfoCategory * pCategory, BOOL fRefreshDataOnly) { ASSERT(pCategory); if (pCategory == NULL) return;
// If there's a currently selected category, save some information
// for it (such as the widths of the columns that the user might
// have changed).
if (m_pCategory && !fRefreshDataOnly && m_pCategory->GetDataSourceType() != NFO_410) { int iWidth;
ASSERT(m_iCategoryColNumberLen <= 64); for (int iListViewCol = 0; iListViewCol < m_iCategoryColNumberLen; iListViewCol++) { iWidth = ListView_GetColumnWidth(m_list.m_hWnd, iListViewCol); m_pCategory->SetColumnWidth(m_aiCategoryColNumber[iListViewCol], iWidth); } }
ListClearItems(); if (!fRefreshDataOnly && pCategory && pCategory->GetDataSourceType() != NFO_410) { ListClearColumns(); m_iCategoryColNumberLen = 0; int iColCount; if (pCategory->GetCategoryDimensions(&iColCount, NULL)) { CString strCaption; UINT uiWidth; int iListViewCol = 0;
for (int iCategoryCol = 0; iCategoryCol < iColCount; iCategoryCol++) { if (!m_fAdvanced && pCategory->IsColumnAdvanced(iCategoryCol)) continue;
if (pCategory->GetColumnInfo(iCategoryCol, &strCaption, &uiWidth, NULL, NULL)) // TBD - faster to return reference to string
{ // Save what the actual column number (for the category) was.
ASSERT(iListViewCol < 64); m_aiCategoryColNumber[iListViewCol] = iCategoryCol; ListInsertColumn(iListViewCol++, (int)uiWidth, strCaption); m_iCategoryColNumberLen = iListViewCol; } } } }
// If the currently displayed category is from a 4.10 NFO file, and we're showing a
// new category, then hide the existing category.
if (m_pCategory && m_pCategory != pCategory && m_pCategory->GetDataSourceType() == NFO_410) ((CMSInfo4Category *) m_pCategory)->ShowControl(m_hWnd, this->GetOCXRect(), FALSE);
// Save the currently displayed category.
m_pCategory = pCategory;
// If this is live data and has never been refreshed, refresh and return.
// Refresh will send a message causing this function to be executed again.
if (pCategory->GetDataSourceType() == LIVE_DATA) { CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *) pCategory; if (!pLiveCategory->EverBeenRefreshed()) { SetMessage((m_history.IsWindowVisible()) ? IDS_REFRESHHISTORYMESSAGE : IDS_REFRESHMESSAGE, 0, TRUE);
CLiveDataSource * pLiveDataSource = (CLiveDataSource *) m_pCurrData; if (pLiveDataSource->InRefresh()) { HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); pLiveCategory->Refresh((CLiveDataSource *) m_pCurrData, FALSE); ::SetCursor(hc); } else pLiveCategory->Refresh((CLiveDataSource *) m_pCurrData, FALSE); return; } } else if (pCategory->GetDataSourceType() == NFO_410) { this->m_list.ShowWindow(SW_HIDE);
CMSInfo4Category * p4Cat = (CMSInfo4Category *) pCategory; if (!p4Cat->IsDisplayableCategory()) SetMessage(IDS_SELECTCATEGORY, 0, TRUE); else if (FAILED(p4Cat->ShowControl(m_hWnd,this->GetOCXRect()))) SetMessage(IDS_NOOCX, IDS_NOOCXDETAIL, TRUE); return; } else if (pCategory->GetDataSourceType() == XML_SNAPSHOT) { ((CXMLSnapshotCategory*)pCategory)->Refresh((CXMLDataSource*) m_pCurrData, FALSE); CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *) pCategory; // Any category that has children (besides the root category) doesn't display
// information. So put up a message to that effect.
if (pLiveCategory->GetFirstChild() != NULL && pLiveCategory->GetParent() != NULL) { SetMessage(IDS_SELECTCATEGORY, 0, TRUE); return; } else if (!pLiveCategory->EverBeenRefreshed()) { SetMessage((m_history.IsWindowVisible()) ? IDS_REFRESHHISTORYMESSAGE : IDS_REFRESHMESSAGE, 0, TRUE); return; }
} // Set the columns and fill the rows with the data for this category.
// Note, if this is live data we need to lock it (so we don't have
// a threading problem with the refresh).
CLiveDataSource * pLiveDataSource = NULL; if (pCategory->GetDataSourceType() == LIVE_DATA) pLiveDataSource = (CLiveDataSource *) m_pCurrData; if (pLiveDataSource) pLiveDataSource->LockData();
if (SUCCEEDED(pCategory->GetHRESULT())) { int iColCount, iRowCount; if (pCategory->GetCategoryDimensions(&iColCount, &iRowCount)) { CString * pstrData , strCaption , cstring; DWORD dwData; int iListViewCol, iListViewRow = 0;
for (int iCategoryRow = 0; iCategoryRow < iRowCount; iCategoryRow++) { if (!m_fAdvanced && pCategory->IsRowAdvanced(iCategoryRow)) continue;
iListViewCol = 0; for (int iCategoryCol = 0; iCategoryCol < iColCount; iCategoryCol++) { if (!m_fAdvanced && pCategory->IsColumnAdvanced(iCategoryCol)) continue;
if (pCategory->GetData(iCategoryRow, iCategoryCol, &pstrData, &dwData)) { //a-kjaw
if(pstrData->IsEmpty()) { pCategory->GetColumnInfo(iCategoryCol, &strCaption, NULL , NULL, NULL); cstring.LoadString(IDS_SERVERNAME); if( strCaption == cstring ) pstrData->LoadString(IDS_LOCALSERVER);
} //a-kjaw
ListInsertItem(iListViewRow, iListViewCol++, *pstrData, iCategoryRow); } }
iListViewRow += 1; } }
// Return the sorting to how it was last set.
if (pCategory->m_iSortColumn != -1) ListView_SortItems(m_list.m_hWnd, (PFNLVCOMPARE) ListSortFunc, (LPARAM) pCategory);
if (iColCount == 0 || (iRowCount == 0 && pCategory->GetFirstChild() != NULL)) SetMessage(IDS_SELECTCATEGORY, 0, TRUE); else SetMessage(0); } else { // The HRESULT for this category indicates some sort of failure. We should display
// an error message instead of the list view.
CString strTitle, strMessage; pCategory->GetErrorText(&strTitle, &strMessage); SetMessage(strTitle, strMessage, TRUE); }
if (pLiveDataSource) pLiveDataSource->UnlockData();
SetMenuItems(); }
//-------------------------------------------------------------------------
// Get the currently selected category.
//-------------------------------------------------------------------------
CMSInfoCategory * CMSInfo::GetCurrentCategory() { HTREEITEM hti = TreeView_GetSelection(m_tree.m_hWnd); if (hti) { TVITEM tvi; tvi.mask = TVIF_PARAM; tvi.hItem = hti;
if (TreeView_GetItem(m_tree.m_hWnd, &tvi)) { ASSERT(tvi.lParam); ASSERT(tvi.lParam == (LPARAM)m_pCategory); return (CMSInfoCategory *) tvi.lParam; } }
return NULL; }
//-------------------------------------------------------------------------
// Refresh the displayed data.
//-------------------------------------------------------------------------
void CMSInfo::MSInfoRefresh() { CMSInfoCategory * pCategory = GetCurrentCategory(); if (pCategory && pCategory->GetDataSourceType() == LIVE_DATA) { CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *)pCategory; ListClearItems(); SetMessage(IDS_REFRESHMESSAGE); pLiveCategory->Refresh((CLiveDataSource *) m_pCurrData, FALSE); } else if (pCategory && pCategory->GetDataSourceType() == NFO_410) { CMSInfo4Category* p4Category = (CMSInfo4Category*) pCategory; p4Category->Refresh(); } }
//-------------------------------------------------------------------------
// Present the user with a dialog box to select a file to open.
//-------------------------------------------------------------------------
void CMSInfo::OpenNFO() { // Display the dialog box and let the user select a file.
TCHAR szBuffer[MAX_PATH] = _T(""); TCHAR szFilter[MAX_PATH]; TCHAR szDefaultExtension[4];
::LoadString(_Module.GetResourceInstance(), IDS_OPENFILTER, szFilter, MAX_PATH); ::LoadString(_Module.GetResourceInstance(), IDS_DEFAULTEXTENSION, szDefaultExtension, 4); for (int i = 0; szFilter[i]; i++) if (szFilter[i] == _T('|')) szFilter[i] = _T('\0');
OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrCustomFilter = NULL; ofn.lpstrFile = szBuffer; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = NULL; // maybe use later?
ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = szDefaultExtension;
if (!::GetOpenFileName(&ofn)) return; // user cancelled
OpenMSInfoFile(ofn.lpstrFile, ofn.nFileExtension); }
//-------------------------------------------------------------------------
// SaveNFO allows the user to select a filename, and saves the current
// data to an NFO file.
//-------------------------------------------------------------------------
void CMSInfo::SaveNFO() { // Present the user with a dialog box to select a name for saving.
TCHAR szBuffer[MAX_PATH] = _T(""); TCHAR szFilter[MAX_PATH]; TCHAR szDefaultExtension[4];
//v-stlowe 3/19/2001 if (m_fHistoryAvailable && m_strMachine.IsEmpty())
if (m_fHistorySaveAvailable && m_strMachine.IsEmpty()) ::LoadString(_Module.GetResourceInstance(), IDS_SAVEBOTHFILTER, szFilter, MAX_PATH); else ::LoadString(_Module.GetResourceInstance(), IDS_SAVENFOFILTER, szFilter, MAX_PATH);
::LoadString(_Module.GetResourceInstance(), IDS_DEFAULTEXTENSION, szDefaultExtension, 4);
for (int i = 0; szFilter[i]; i++) if (szFilter[i] == _T('|')) szFilter[i] = _T('\0');
OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 0; ofn.lpstrCustomFilter = NULL; ofn.lpstrFile = szBuffer; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = NULL; // maybe use later?
ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = NULL; ofn.Flags = OFN_OVERWRITEPROMPT; ofn.lpstrDefExt = szDefaultExtension;
if (!::GetSaveFileName(&ofn)) return; // user cancelled
HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
CString strFileName(ofn.lpstrFile); if (strFileName.Right(4).CompareNoCase(_T(".xml")) == 0) SaveXML(strFileName); else SaveMSInfoFile(strFileName, ofn.nFilterIndex);
::SetCursor(hc); }
//-------------------------------------------------------------------------
// Actually saves the current information to an NFO file.
//-------------------------------------------------------------------------
void CMSInfo::SaveMSInfoFile(LPCTSTR szFilename, DWORD dwFilterIndex) { ASSERT(m_pCurrData);
if (m_history.IsWindowVisible()) DispatchCommand(ID_VIEW_CURRENT);
if (m_pCurrData) { CMSInfoCategory * pCategory = m_pCurrData->GetRootCategory(); if (pCategory) { HANDLE hFile = ::CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { if (pCategory->GetDataSourceType() == LIVE_DATA) { CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *) pCategory;
if (m_fNoUI) pLiveCategory->RefreshSynchronous((CLiveDataSource *) m_pCurrData, TRUE); else RefreshData((CLiveDataSource *)m_pCurrData, pLiveCategory); } else if (pCategory->GetDataSourceType() == XML_SNAPSHOT) ((CXMLSnapshotCategory *)pCategory)->Refresh((CXMLDataSource *)m_pCurrData, TRUE);
//PENDING dependence on filter order. Always add new filters to the end.
if (dwFilterIndex == 1)//NFO_700
pCategory->SaveXML(hFile); else pCategory->SaveNFO(hFile, pCategory, TRUE); ::CloseHandle(hFile); } else { DWORD dwError = ::GetLastError();
LPVOID lpMsgBuf; ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL);
// TBD Process any inserts in lpMsgBuf.
CString strCaption; ::AfxSetResourceHandle(_Module.GetResourceInstance()); strCaption.LoadString(IDS_SYSTEMINFO); ::MessageBox(m_hWnd, (LPCTSTR) lpMsgBuf, strCaption, MB_ICONEXCLAMATION | MB_OK); ::LocalFree(lpMsgBuf); } } } }
//-------------------------------------------------------------------------
// Save an XML file containing the history information.
//-------------------------------------------------------------------------
void CMSInfo::SaveXML(const CString & strFileName) { if (m_pHistoryStream == NULL) { MSInfoMessageBox(IDS_XMLSAVEERR); return; }
// get the stream status, so we can determine the size of the stream
STATSTG streamStat; HRESULT hr = m_pHistoryStream->Stat(&streamStat,STATFLAG_NONAME ); if (FAILED(hr)) { ASSERT(0 && "couldn't get stream statistics"); MSInfoMessageBox(IDS_XMLSAVEERR); return; } // allocate buffer of appropriate size
BYTE* pBuffer = new BYTE[streamStat.cbSize.LowPart]; ULONG ulRead;
// seek to beginning of stream
ULARGE_INTEGER uliSeekPtr; LARGE_INTEGER liSeekLoc; liSeekLoc.QuadPart = 0; hr = m_pHistoryStream->Seek(liSeekLoc,0,&uliSeekPtr); if (FAILED(hr)) { MSInfoMessageBox(IDS_XMLSAVEERR); if (pBuffer) delete [] pBuffer; return; } hr = m_pHistoryStream->Read(pBuffer,streamStat.cbSize.LowPart,&ulRead); if (FAILED(hr) || !pBuffer) { MSInfoMessageBox(IDS_XMLSAVEERR); if (pBuffer) delete [] pBuffer; return; } if(ulRead != streamStat.cbSize.LowPart) { ASSERT(0 && "Not enough bytes read from stream"); MSInfoMessageBox(IDS_XMLSAVEERR); if (pBuffer) delete [] pBuffer; return; } CFile file; try { file.Open(strFileName, CFile::modeCreate | CFile::modeWrite); file.Write(pBuffer,ulRead); } catch (CFileException * pException) { pException->ReportError(); pException->Delete(); } catch (...) { ::AfxSetResourceHandle(_Module.GetResourceInstance()); CString strCaption, strMessage; strCaption.LoadString(IDS_SYSTEMINFO); strMessage.LoadString(IDS_XMLSAVEERR); ::MessageBox(NULL,strMessage, strCaption,MB_OK); } delete [] pBuffer; }
//-------------------------------------------------------------------------
// Export allows the user to select a filename, and saves the current
// data to a text or XML file.
//-------------------------------------------------------------------------
void CMSInfo::Export() { // Present the user with a dialog box to select a name for saving.
TCHAR szBuffer[MAX_PATH] = _T(""); TCHAR szFilter[MAX_PATH]; TCHAR szTitle[MAX_PATH] = _T(""); TCHAR szDefaultExtension[4];
::LoadString(_Module.GetResourceInstance(), IDS_EXPORTFILTER, szFilter, MAX_PATH); // TBD - add XML
::LoadString(_Module.GetResourceInstance(), IDS_DEFAULTEXPORTEXTENSION, szDefaultExtension, 4); ::LoadString(_Module.GetResourceInstance(), IDS_EXPORTDIALOGTITLE, szTitle, MAX_PATH);
for (int i = 0; szFilter[i]; i++) if (szFilter[i] == _T('|')) szFilter[i] = _T('\0');
OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 0; ofn.lpstrCustomFilter = NULL; ofn.lpstrFile = szBuffer; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = NULL; // maybe use later?
ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = (szTitle[0] == _T('\0')) ? NULL : szTitle; ofn.Flags = OFN_OVERWRITEPROMPT; ofn.lpstrDefExt = szDefaultExtension;
if (!::GetSaveFileName(&ofn)) return; // user cancelled
HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); ExportFile(ofn.lpstrFile, ofn.nFileExtension); ::SetCursor(hc); }
//-------------------------------------------------------------------------
// Open the specified file (it might be XML, NFO, CAB, etc.). If the open
// succeeds, we should show the contents of the file.
//-------------------------------------------------------------------------
HRESULT CMSInfo::OpenMSInfoFile(LPCTSTR szFilename, int nFileExtension) { if (m_pFileData != NULL && m_strFileName.Right(4).CompareNoCase(_T(".xml")) == 0) CloseFile();
HRESULT hr = S_OK; CDataSource * pOldOpenFile = m_pFileData;
::AfxSetResourceHandle(_Module.GetResourceInstance()); /* v-stlowe 3/04/2001...we don't want to automatically switch from history
in the event we're opening XML. if (m_history.IsWindowVisible()) DispatchCommand(ID_VIEW_CURRENT);*/
// Open the file.
LPCTSTR szExtension = szFilename + nFileExtension;
if (_tcsicmp(szExtension, _T("NFO")) == 0) { // If this is a version 4 NFO, check to see if that's enabled. Bug 582973.
if (IsVersion4File(szFilename)) { HKEY hkey; BOOL fDisabled = TRUE;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_READ, &hkey)) { DWORD dwType = REG_DWORD, dwValue, dwSize = sizeof(DWORD); if (ERROR_SUCCESS == RegQueryValueEx(hkey, _T("AllowVersion4NFO"), NULL, &dwType, (LPBYTE)&dwValue, &dwSize)) fDisabled = (dwValue == 0); RegCloseKey(hkey); }
if (fDisabled) { MSInfoMessageBox(IDS_VER4NFODISABLED); return E_FAIL; } }
// First, try opening it as a 4.x file.
CNFO4DataSource* pMSI4Source = new CNFO4DataSource(); hr = pMSI4Source->Create(szFilename); if (SUCCEEDED(hr)) { m_pFileData = pMSI4Source; } else { delete pMSI4Source;
if (STG_E_ACCESSDENIED == hr || STG_E_SHAREVIOLATION == hr || STG_E_LOCKVIOLATION == hr) { MSInfoMessageBox(IDS_OLDNFOSHARINGVIOLATION); return E_FAIL;
} }
// If that failed, then try opening it as a 5.0/6.0 file.
if (FAILED(hr)) { HANDLE h = ::CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (INVALID_HANDLE_VALUE == h) { MSInfoMessageBox(IDS_BADNFOFILE); return E_FAIL; } CNFO6DataSource * p60Source = new CNFO6DataSource; if (p60Source) { hr = p60Source->Create(h, szFilename); if (FAILED(hr)) { delete p60Source; //MSInfoMessageBox(IDS_BADNFOFILE);
} else m_pFileData = p60Source; } else hr = E_FAIL; // TBD no memory
::CloseHandle(h); }
//Try 7.0
if (FAILED(hr)) { CNFO7DataSource * p70Source = new CNFO7DataSource; if (!p70Source) hr = E_FAIL; else { hr = p70Source->Create(szFilename);//blocks while parsing
if (FAILED(hr)) { delete p70Source; MSInfoMessageBox(IDS_BADNFOFILE); } else m_pFileData = p70Source; } }
} else if (_tcsicmp(szExtension, _T("CAB")) == 0) { CString strDest;
GetCABExplodeDir(strDest, TRUE, _T("")); if (!strDest.IsEmpty()) { if (OpenCABFile(szFilename, strDest)) { LoadGlobalToolsetWithOpenCAB(m_mapIDToTool, strDest); UpdateToolsMenu(); CString strFileInCAB; //first, look for xml files (the incident file specified in the registry, and (possibly) dataspec.xml
//Get default incident file name from registry (create it if it's not there)
CString strIncidentFileName; HKEY hkey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_ALL_ACCESS, &hkey)) { TCHAR szBuffer[MAX_PATH]; DWORD dwType, dwSize = MAX_PATH * sizeof(TCHAR); long lErr = RegQueryValueEx(hkey, _T("incidentfilename"), NULL, &dwType, (LPBYTE)szBuffer, &dwSize); if (ERROR_SUCCESS == lErr) { if (dwType == REG_SZ) {
strIncidentFileName = szBuffer; } else { ASSERT(0 && "invalid incidentfilename reg key"); return E_FAIL; } } //check lErr to make sure it's appropriate error for value not existing
else if (2 == lErr) { //create registry key.
CString strDefaultValue = _T("Incident.xml"); lErr = RegSetValueEx(hkey,_T("incidentfilename"),NULL,REG_SZ,(BYTE*) strDefaultValue.GetBuffer(strDefaultValue.GetLength()),strDefaultValue.GetLength() * sizeof(TCHAR)); strIncidentFileName = strDefaultValue; } } if (IsIncidentXMLFilePresent(strDest,strIncidentFileName)) { strFileInCAB = strDest + "\\"; strFileInCAB += strIncidentFileName; OpenMSInfoFile(strFileInCAB,strFileInCAB.Find(_T(".xml")) +1); return S_OK; } //if there are no xml incident files
FindFileToOpen(strDest, strFileInCAB);
if (!strFileInCAB.IsEmpty()) { int iExtension = strFileInCAB.GetLength() - 1; while (iExtension && strFileInCAB[iExtension] != _T('.')) iExtension--; if (iExtension) return OpenMSInfoFile(strFileInCAB, iExtension + 1 /* skip the dot */); else { ASSERT(0 && "couldn't find dot in file name"); } } } } else { // TBD - do something about the error.
ASSERT(0 && "could get not CAB destination directory"); } MSInfoMessageBox(IDS_BADCABFILE); return E_FAIL; } else if (_tcsicmp(szExtension, _T("XML")) == 0) { /* v-stlowe 3/04/2001
CXMLDataSource* pSSDataSource = new CXMLDataSource(); hr = pSSDataSource->Create(szFilename,(CMSInfoLiveCategory *) this->m_pLiveData->GetRootCategory(),m_hWnd); CXMLSnapshotCategory* pRootXML = (CXMLSnapshotCategory*) pSSDataSource->GetRootCategory(); pRootXML->AppendFilenameToCaption(szFilename); if (SUCCEEDED(hr)) { m_pFileData = pSSDataSource; } else { delete pSSDataSource; }*/ try { hr = ((CLiveDataSource *)m_pLiveData)->LoadXMLDoc(szFilename); m_pFileData = m_pLiveData; this->m_strFileName = szFilename; //trigger refresh
CMSInfoCategory * pCategory = GetCurrentCategory(); if (pCategory) ChangeHistoryView(((CMSInfoHistoryCategory*) pCategory)->m_iDeltaIndex); if (FAILED(hr))//v-stlowe 3/9/2001 || !varBSuccess)
{ ASSERT(0 && "unable to load xml document"); return E_FAIL; } } catch(...) { return E_FAIL; }
DispatchCommand(ID_VIEW_HISTORY);
} else { // Report that we can't open this kind of file.
MSInfoMessageBox(IDS_UNKNOWNFILETYPE); hr = E_FAIL; }
// It succeeded, so we should show the new data and update the menu
// for the new state.
if (SUCCEEDED(hr)) { if (pOldOpenFile && pOldOpenFile != m_pFileData) delete pOldOpenFile;
SelectDataSource(m_pFileData); } else ; // report the error
return hr; }
//-------------------------------------------------------------------------
// Export to the specified file. This will be either a TXT or an XML file.
//-------------------------------------------------------------------------
void CMSInfo::ExportFile(LPCTSTR szFilename, int nFileExtension) { ASSERT(m_pCurrData);
if (m_pCurrData) { // If there is a selected category, export that node only (bug 185305).
CMSInfoCategory * pCategory = (m_pCategory) ? m_pCategory : m_pCurrData->GetRootCategory(); if (pCategory) { if (pCategory->GetDataSourceType() == LIVE_DATA) { if (m_history.IsWindowVisible() == TRUE) { ((CMSInfoHistoryCategory*)pCategory)->Refresh((CLiveDataSource*)m_pCurrData,TRUE); } else { CMSInfoLiveCategory * pLiveCategory = (CMSInfoLiveCategory *) pCategory;
if (m_fNoUI) pLiveCategory->RefreshSynchronous((CLiveDataSource *) m_pCurrData, TRUE); else RefreshData((CLiveDataSource *)m_pCurrData, pLiveCategory); } } else if (pCategory->GetDataSourceType() == NFO_410) { ((CMSInfo4Category *) pCategory)->RefreshAllForPrint(m_hWnd,this->GetOCXRect()); } else if (pCategory->GetDataSourceType() == XML_SNAPSHOT) { ((CXMLSnapshotCategory *) pCategory)->Refresh((CXMLDataSource *)m_pCurrData,TRUE); }
/*HANDLE hFile = ::CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) { pCategory->SaveAsText(hFile, TRUE); ::CloseHandle(hFile); } else { // TBD - handle the error
}*/ //a-stephl: Fixing OSR4.1 bug #133823, not displaying message when saving to write-protected diskette
try { HANDLE hFile = ::CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1; LPTSTR lpMachineName = new TCHAR[dwSize]; GetMachineName(lpMachineName, &dwSize);
/*a-kjaw To implement save as XML
if( _tcsicmp(szFilename + nFileExtension , _T("XML")) == 0) { pCategory->SaveAsXml(hFile, TRUE); } //a-kjaw */
// else
// {
pCategory->SaveAsText(hFile, TRUE, lpMachineName); // }
delete [] lpMachineName; ::CloseHandle(hFile); } else { DWORD dwError = ::GetLastError();
LPVOID lpMsgBuf; ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL);
// TBD Process any inserts in lpMsgBuf.
CString strCaption; ::AfxSetResourceHandle(_Module.GetResourceInstance()); strCaption.LoadString(IDS_SYSTEMINFO); ::MessageBox(m_hWnd, (LPCTSTR) lpMsgBuf, strCaption, MB_ICONEXCLAMATION | MB_OK); ::LocalFree(lpMsgBuf); } } catch (CFileException * pException) { pException->ReportError(); pException->Delete(); } catch (CException * pException) { pException->ReportError(); pException->Delete(); } catch (...) { DWORD dwError = ::GetLastError();
LPVOID lpMsgBuf; ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL);
// TBD Process any inserts in lpMsgBuf.
CString strCaption; ::AfxSetResourceHandle(_Module.GetResourceInstance()); strCaption.LoadString(IDS_SYSTEMINFO); ::MessageBox(m_hWnd, (LPCTSTR) lpMsgBuf, strCaption, MB_ICONEXCLAMATION | MB_OK); ::LocalFree(lpMsgBuf); } } //end a-stephl: Fixing OSR4.1 bug #133823, not displaying message when saving to write-protected diskette
} }
//-------------------------------------------------------------------------
// Close the currently open file (if there is one). Displays the current
// system information.
//-------------------------------------------------------------------------
void CMSInfo::CloseFile() { ASSERT(m_pFileData); //v-stlowe 3/12/2001
SelectDataSource(m_pLiveData); if (m_strFileName.Right(4).CompareNoCase(_T(".xml")) == 0) { ((CLiveDataSource *)m_pLiveData)->RevertToLiveXML(); } if (m_pFileData) { //v-stlowe: so we can use livedata as filedata when opening history xml
if (m_pFileData != this->m_pLiveData) { delete m_pFileData; } m_pFileData = NULL; } if (!m_history.IsWindowVisible()) { DispatchCommand(ID_VIEW_CURRENT); } else { DispatchCommand(ID_VIEW_HISTORY); } SetMenuItems(); }
//-------------------------------------------------------------------------
// Enable or disable menu items based on the current state.
//-------------------------------------------------------------------------
void CMSInfo::SetMenuItems() { if (NULL == m_hmenu || NULL == m_hwndParent) return;
// This struct will be used a bunch in this function to set menu item states.
MENUITEMINFO mii; mii.cbSize = sizeof(MENUITEMINFO);
// The type of data being displayed will also be used frequently.
DataSourceType datatype = LIVE_DATA; if (m_pCurrData) { CMSInfoCategory * pCategory = m_pCurrData->GetRootCategory(); if (pCategory) datatype = pCategory->GetDataSourceType(); }
// Enable or disable items in the File menu.
HMENU hmenuFile = ::GetSubMenu(m_hmenu, 0); if (hmenuFile) { mii.fMask = MIIM_STATE; mii.fState = (m_pFileData == m_pCurrData) ? MFS_ENABLED : MFS_GRAYED; ::SetMenuItemInfo(hmenuFile, ID_FILE_CLOSE, FALSE, &mii);
mii.fState = MFS_ENABLED; // Was: (m_pFileData != m_pCurrData) ? MFS_ENABLED : MFS_GRAYED;
::SetMenuItemInfo(hmenuFile, ID_FILE_OPENNFO, FALSE, &mii);
mii.fState = (datatype == LIVE_DATA || datatype == XML_SNAPSHOT) ? MFS_ENABLED : MFS_GRAYED; ::SetMenuItemInfo(hmenuFile, ID_FILE_SAVENFO, FALSE, &mii);
//mii.fState = MFS_ENABLED;
mii.fState = (datatype != NFO_410) ? MFS_ENABLED : MFS_GRAYED;; ::SetMenuItemInfo(hmenuFile, ID_FILE_EXPORT, FALSE, &mii);
mii.fState = MFS_ENABLED; ::SetMenuItemInfo(hmenuFile, ID_FILE_PRINT, FALSE, &mii);
if (NULL == m_hwndParent) { // Remove the last two items (the exit command and the divider).
int nItems = ::GetMenuItemCount(hmenuFile); if (ID_FILE_EXIT == ::GetMenuItemID(hmenuFile, nItems - 1)) { ::RemoveMenu(hmenuFile, nItems - 1, MF_BYPOSITION); ::RemoveMenu(hmenuFile, nItems - 2, MF_BYPOSITION); } } }
// Enable or disable items in the Edit menu.
HMENU hmenuEdit = ::GetSubMenu(m_hmenu, 1); if (hmenuEdit) { mii.fMask = MIIM_STATE;
if (datatype == NFO_410 || ListView_GetNextItem(m_list.m_hWnd, -1, LVNI_SELECTED) != -1) mii.fState = MFS_ENABLED; else mii.fState = MFS_GRAYED;
// Disable copy if the list view is not visible.
if (!m_list.IsWindowVisible()) mii.fState = MFS_GRAYED;
// If the find control has focus, enable copy based on that control.
if (GetFocus() == m_wndFindWhat.m_hWnd && m_wndFindWhat.IsWindowVisible() && m_wndFindWhat.IsWindowEnabled()) mii.fState = MFS_ENABLED;
::SetMenuItemInfo(hmenuEdit, ID_EDIT_COPY, FALSE, &mii);
mii.fState = (m_list.IsWindowVisible()) ? MFS_ENABLED : MFS_GRAYED; ::SetMenuItemInfo(hmenuEdit, ID_EDIT_SELECTALL, FALSE, &mii);
mii.fState = (datatype != NFO_410) ? MFS_ENABLED : MFS_GRAYED; mii.fState |= ((!m_fFindVisible) ? MFS_CHECKED : MFS_UNCHECKED); ::SetMenuItemInfo(hmenuEdit, ID_EDIT_FIND, FALSE, &mii); }
// Enable or disable items in the View menu.
HMENU hmenuView = ::GetSubMenu(m_hmenu, 2); if (hmenuView) { mii.fMask = MIIM_STATE; mii.fState = (datatype == LIVE_DATA && !m_history.IsWindowVisible()) ? MFS_ENABLED : MFS_GRAYED; ::SetMenuItemInfo(hmenuView, ID_VIEW_REFRESH, FALSE, &mii);
mii.fState = MFS_ENABLED | ((!m_fAdvanced) ? MFS_CHECKED : MFS_UNCHECKED); ::SetMenuItemInfo(hmenuView, ID_VIEW_BASIC, FALSE, &mii);
mii.fState = MFS_ENABLED | ((m_fAdvanced) ? MFS_CHECKED : MFS_UNCHECKED); ::SetMenuItemInfo(hmenuView, ID_VIEW_ADVANCED, FALSE, &mii);
// Set the menu item for the current system view or snapshot, depending on whether
// or not there is an XML file open.
BOOL fEnableHistoryLive = FALSE; if (datatype == LIVE_DATA && m_fHistoryAvailable && m_strMachine.IsEmpty()) fEnableHistoryLive = TRUE;
BOOL fEnableHistoryXML = FALSE; if (m_pFileData) { CMSInfoCategory * pCategory = m_pFileData->GetRootCategory(); if (pCategory && (pCategory->GetDataSourceType() == XML_SNAPSHOT || pCategory == &catHistorySystemSummary)) fEnableHistoryXML = TRUE; }
BOOL fShowingHistory = FALSE; if (m_pCurrData) { CMSInfoCategory * pCategory = m_pCurrData->GetRootCategory(); if (pCategory == &catHistorySystemSummary) fShowingHistory = TRUE; }
// Whether or not you can remote depends on if you are showing live data.
mii.fState = (datatype == LIVE_DATA && !fEnableHistoryXML) ? MFS_ENABLED : MFS_GRAYED; ::SetMenuItemInfo(hmenuView, ID_VIEW_REMOTE_COMPUTER, FALSE, &mii);
// Enabling the menu items to switch between current (or snapshot) and history
// are based on whether history is available.
mii.fState = (fEnableHistoryLive || fEnableHistoryXML) ? MFS_ENABLED : MFS_GRAYED; mii.fState |= (!m_history.IsWindowVisible()) ? MFS_CHECKED : MFS_UNCHECKED; ::SetMenuItemInfo(hmenuView, ID_VIEW_CURRENT, FALSE, &mii); mii.fState = (fEnableHistoryLive || fEnableHistoryXML) ? MFS_ENABLED : MFS_GRAYED; mii.fState |= (m_history.IsWindowVisible()) ? MFS_CHECKED : MFS_UNCHECKED; ::SetMenuItemInfo(hmenuView, ID_VIEW_HISTORY, FALSE, &mii);
// Set the menu item text (for system snapshot/current system information) based on
// whether or not we have an XML file open.
UINT uiMenuCaption = IDS_VIEWCURRENTSYSTEMINFO; if (m_pFileData) { CMSInfoCategory * pCategory = m_pCurrData->GetRootCategory(); // v-stlowe 6/26/2001...pCategory && (pCategory->GetDataSourceType() == XML_SNAPSHOT no longer possible... if (pCategory && (pCategory->GetDataSourceType() == XML_SNAPSHOT || pCategory == &catHistorySystemSummary))
if (pCategory && (pCategory == &catHistorySystemSummary)) { //v-stlowe 6/26/2001: we need to remove "snapshot" uiMenuCaption = IDS_VIEWSYSTEMSNAPSHOT;
uiMenuCaption = IDS_VIEWCURRENTSYSTEMINFO; } }
CString strMenuItem; strMenuItem.LoadString(uiMenuCaption);
MENUITEMINFO miiName; miiName.cbSize = sizeof(MENUITEMINFO); miiName.fMask = MIIM_TYPE; miiName.fType = MFT_STRING; miiName.dwTypeData = (LPTSTR)(LPCTSTR)strMenuItem; ::SetMenuItemInfo(hmenuView, ID_VIEW_CURRENT, FALSE, &miiName); }
// Enable or disable items in the Help menu.
HMENU hmenuHelp = ::GetSubMenu(m_hmenu, 4); if (hmenuHelp) { mii.fMask = MIIM_STATE; mii.fState = MFS_ENABLED; ::SetMenuItemInfo(hmenuHelp, ID_HELP_ABOUT, FALSE, &mii); } }
//-------------------------------------------------------------------------
// Set a message in the right hand pane (hiding the list view).
//-------------------------------------------------------------------------
void CMSInfo::SetMessage(const CString & strTitle, const CString & strMessage, BOOL fRedraw) { m_strMessTitle = strTitle; m_strMessText = strMessage;
if (strTitle.IsEmpty() && strMessage.IsEmpty()) { m_list.ShowWindow(SW_SHOW); return; }
m_list.ShowWindow(SW_HIDE);
if (fRedraw) { RECT rectList; m_list.GetWindowRect(&rectList); ScreenToClient(&rectList); InvalidateRect(&rectList, TRUE); UpdateWindow(); } }
void CMSInfo::SetMessage(UINT uiTitle, UINT uiMessage, BOOL fRedraw) { CString strTitle(_T("")); CString strMessage(_T(""));
::AfxSetResourceHandle(_Module.GetResourceInstance());
if (uiTitle) strTitle.LoadString(uiTitle);
if (uiMessage) strMessage.LoadString(uiMessage);
SetMessage(strTitle, strMessage, fRedraw); }
//---------------------------------------------------------------------------
// This function is used to sort the list by a specified column.
//---------------------------------------------------------------------------
int CALLBACK ListSortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int iReturn = 0; CMSInfoCategory * pCategory = (CMSInfoCategory *) lParamSort;
if (pCategory) { CString * pstrFirst; CString * pstrSecond; DWORD dwFirst = 0, dwSecond = 0;
pCategory->GetData((int)lParam1, pCategory->m_iSortColumn, &pstrFirst, &dwFirst); pCategory->GetData((int)lParam2, pCategory->m_iSortColumn, &pstrSecond, &dwSecond);
//a-kjaw . To fix bug "Sort order style for an nfo file differs from that of live data."
if(pCategory->GetDataSourceType() == NFO_500/*|| pCategory->GetDataSourceType() == NFO_410 */) //BugBug
if(pstrFirst->Left(3) == _T("IRQ"))//Very weird fix. Need Loc?
{ LPTSTR strIrq = pstrFirst->GetBuffer(pstrFirst->GetLength() + 1); dwFirst = _ttoi(strIrq + 4 ); pstrFirst->ReleaseBuffer();
strIrq = pstrSecond->GetBuffer(pstrSecond->GetLength() + 1); dwSecond = _ttoi(strIrq + 4 ); pstrSecond->ReleaseBuffer();
} //a-kjaw
if (pCategory->m_fSortLexical) iReturn = pstrFirst->Collate(*pstrSecond); else iReturn = (dwFirst < dwSecond) ? -1 : (dwFirst == dwSecond) ? 0 : 1;
if (!pCategory->m_fSortAscending) iReturn *= -1; }
return iReturn; }
//---------------------------------------------------------------------------
// Copy selected text from the list view into the clipboard.
//---------------------------------------------------------------------------
void CMSInfo::EditCopy() { if (GetFocus() == m_wndFindWhat.m_hWnd && m_wndFindWhat.IsWindowVisible() && m_wndFindWhat.IsWindowEnabled()) { m_wndFindWhat.SendMessage(WM_COPY); return; }
CString strClipboardText(_T(""));
CMSInfoCategory * pCategory = GetCurrentCategory(); if (pCategory == NULL) return;
if (pCategory && pCategory->GetDataSourceType() == NFO_410) { CMSInfo4Category * pCategory4 = (CMSInfo4Category *) pCategory; CMSIControl * p4Ctrl = NULL;
if (CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(pCategory4->m_strCLSID, p4Ctrl) && p4Ctrl) p4Ctrl->MSInfoCopy();
return; }
int iRowCount, iColCount; pCategory->GetCategoryDimensions(&iColCount, &iRowCount);
// Build the string to put in the clipboard by finding all of the
// selected lines in the list view.
LVITEM lvi; lvi.mask = LVIF_PARAM; lvi.iSubItem = 0;
CString * pstrCell; int iSelected = ListView_GetNextItem(m_list.m_hWnd, -1, LVNI_SELECTED); while (iSelected != -1) { lvi.iItem = iSelected; if (ListView_GetItem(m_list.m_hWnd, &lvi)) { ASSERT(lvi.lParam < iRowCount); if (lvi.lParam < iRowCount) for (int iCol = 0; iCol < iColCount; iCol++) if (SUCCEEDED(pCategory->GetData((int)lvi.lParam, iCol, &pstrCell, NULL))) { if (iCol) strClipboardText += _T("\t"); strClipboardText += *pstrCell; } strClipboardText += _T("\r\n"); }
iSelected = ListView_GetNextItem(m_list.m_hWnd, iSelected, LVNI_SELECTED); }
// Put the string in the clipboard.
if (OpenClipboard()) { if (EmptyClipboard()) { DWORD dwSize = (strClipboardText.GetLength() + 1) * sizeof(TCHAR); HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dwSize);
if (hMem) { LPVOID lpvoid = ::GlobalLock(hMem); if (lpvoid) { memcpy(lpvoid, (LPCTSTR) strClipboardText, dwSize); ::GlobalUnlock(hMem); SetClipboardData(CF_UNICODETEXT, hMem); } } } CloseClipboard(); } }
//---------------------------------------------------------------------------
// Select all of the text in the list view.
//---------------------------------------------------------------------------
void CMSInfo::EditSelectAll() { CMSInfoCategory * pCategory = GetCurrentCategory();
if (pCategory && pCategory->GetDataSourceType() == NFO_410) { CMSInfo4Category * pCategory4 = (CMSInfo4Category *) pCategory; CMSIControl * p4Ctrl = NULL;
if (CMSInfo4Category::s_pNfo4DataSource->GetControlFromCLSID(pCategory4->m_strCLSID, p4Ctrl) && p4Ctrl) p4Ctrl->MSInfoSelectAll(); } else { int iCount = ListView_GetItemCount(m_list.m_hWnd); for (int i = 0; i < iCount; i++) ListView_SetItemState(m_list.m_hWnd, i, LVIS_SELECTED, LVIS_SELECTED); } }
void CMSInfo::GetMachineName(LPTSTR lpBuffer, LPDWORD lpnSize) { if (_tcslen(m_strMachine) == 0) GetComputerName(lpBuffer, lpnSize); else _tcsncpy(lpBuffer, m_strMachine, *lpnSize); }
//---------------------------------------------------------------------------
// Print the currently displayed information.
//---------------------------------------------------------------------------
void CMSInfo::DoPrint(BOOL fNoUI) { if (m_pCurrData == NULL) return;
CMSInfoCategory * pRootCategory = m_pCurrData->GetRootCategory(); CMSInfoCategory * pSelectedCategory = GetCurrentCategory(); if (pRootCategory == NULL) return;
DWORD dwFlags = PD_CURRENTPAGE | PD_NOPAGENUMS | PD_RETURNDC | PD_HIDEPRINTTOFILE | PD_USEDEVMODECOPIESANDCOLLATE; if (pSelectedCategory == NULL) dwFlags |= PD_NOCURRENTPAGE | PD_NOSELECTION | PD_ALLPAGES;
PRINTDLGEX pd; ::ZeroMemory(&pd, sizeof(PRINTDLGEX)); pd.Flags = dwFlags; pd.lStructSize = sizeof(PRINTDLGEX); pd.hwndOwner = this->m_hWnd; pd.ExclusionFlags = PD_EXCL_COPIESANDCOLLATE; pd.nStartPage = START_PAGE_GENERAL;
if (fNoUI) pd.Flags |= PD_RETURNDEFAULT; if (SUCCEEDED(::PrintDlgEx(&pd)) && pd.dwResultAction == PD_RESULT_PRINT) { BOOL fPrintCategory = ((pd.Flags & PD_SELECTION) != 0) || ((pd.Flags & PD_CURRENTPAGE) != 0); BOOL fPrintRecursive = ((pd.Flags & PD_CURRENTPAGE) == 0);
CMSInfoCategory * pPrintCategory = (fPrintCategory) ? pSelectedCategory : pRootCategory; if (pPrintCategory) { if (pPrintCategory->GetDataSourceType() == LIVE_DATA) { RefreshData((CLiveDataSource *)m_pCurrData, (CMSInfoLiveCategory *)pPrintCategory); } else if (pPrintCategory->GetDataSourceType() == NFO_410) { ((CMSInfo4Category *) pPrintCategory)->RefreshAllForPrint(m_hWnd,this->GetOCXRect()); } else if (pPrintCategory->GetDataSourceType() == XML_SNAPSHOT) { ((CXMLSnapshotCategory*) pPrintCategory)->Refresh((CXMLDataSource*) m_pCurrData, TRUE); } DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1; LPTSTR lpMachineName = new TCHAR[dwSize]; GetMachineName(lpMachineName, &dwSize); pPrintCategory->Print(pd.hDC, fPrintRecursive, -1, -1, lpMachineName); // -1's to include all pages
delete [] lpMachineName; } } }
//---------------------------------------------------------------------------
// Update the tools menu to match the contents of the tools map.
//---------------------------------------------------------------------------
void CMSInfo::UpdateToolsMenu() { if (NULL == m_hmenu) return;
HMENU hmenuTool = ::GetSubMenu(m_hmenu, 3); if (hmenuTool) { // Remove all the current tools in the menu.
while (DeleteMenu(hmenuTool, 0, MF_BYPOSITION));
// Add the tools from the map. This will add the top level tools.
WORD wCommand; CMSInfoTool * pTool;
for (POSITION pos = m_mapIDToTool.GetStartPosition(); pos != NULL; ) { m_mapIDToTool.GetNextAssoc(pos, wCommand, (void * &) pTool); if (pTool && pTool->GetParentID() == 0) { if (!pTool->HasSubitems()) InsertMenu(hmenuTool, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, (UINT) pTool->GetID(), pTool->GetName()); else { HMENU hmenuNew = CreatePopupMenu(); InsertMenu(hmenuTool, 0xFFFFFFFF, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT_PTR) hmenuNew, pTool->GetName()); pTool->SetHMENU(hmenuNew); } } }
// Now add the second level tools (the subitems).
for (pos = m_mapIDToTool.GetStartPosition(); pos != NULL; ) { m_mapIDToTool.GetNextAssoc(pos, wCommand, (void * &) pTool); if (pTool && pTool->GetParentID()) { CMSInfoTool * pParentTool;
if (m_mapIDToTool.Lookup((WORD) pTool->GetParentID(), (void * &) pParentTool)) InsertMenu(pParentTool->GetHMENU(), 0xFFFFFFFF, MF_BYPOSITION | MF_STRING, (UINT) pTool->GetID(), pTool->GetName()); } } } }
//---------------------------------------------------------------------------
// Gets the right pane rect in which to display a MSInfo 4.x OCX.
//---------------------------------------------------------------------------
CRect CMSInfo::GetOCXRect() { CRect rectList;
m_list.GetWindowRect(&rectList); ScreenToClient(&rectList); rectList.DeflateRect(1, 1, 2, 2);
return rectList; }
//=============================================================================
// Find Functionality
//=============================================================================
//-------------------------------------------------------------------------
// CancelFind does what is says. It also waits until the find is done
// before returning.
//-------------------------------------------------------------------------
void CMSInfo::CancelFind() { if (m_fInFind) { m_fCancelFind = TRUE; m_fFindNext = FALSE; GotoDlgCtrl(m_wndStopFind.m_hWnd); UpdateFindControls();
if (m_pcatFind && m_pcatFind->GetDataSourceType() == LIVE_DATA) { CLiveDataSource * pLiveDataSource = (CLiveDataSource *) m_pCurrData; HCURSOR hc = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); pLiveDataSource->WaitForRefresh(); ::SetCursor(hc); } } }
//-------------------------------------------------------------------------
// When the user clicks on Stop Find, it will either cancel the current
// find operation (if there is one in progress) or hide the find controls
// (if there is no find in progress).
//-------------------------------------------------------------------------
LRESULT CMSInfo::OnStopFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { if (m_fInFind) { m_fCancelFind = TRUE; m_fFindNext = FALSE; GotoDlgCtrl(m_wndStopFind.m_hWnd); UpdateFindControls(); } else { m_fFindNext = FALSE; DispatchCommand(ID_EDIT_FIND); } return 0; }
//-------------------------------------------------------------------------
// UpdateFindControls updates the state of the controls (the text and
// enabling/disabling) based on the settings of the find member vars.
//-------------------------------------------------------------------------
void CMSInfo::UpdateFindControls() { if (!m_fFindVisible) return;
::AfxSetResourceHandle(_Module.GetResourceInstance());
m_wndCancelFind.ShowWindow(m_fInFind ? SW_SHOW : SW_HIDE); m_wndStopFind.ShowWindow(m_fInFind ? SW_HIDE : SW_SHOW); m_wndFindNext.ShowWindow(m_fFindNext ? SW_SHOW : SW_HIDE); m_wndStartFind.ShowWindow(m_fFindNext ? SW_HIDE : SW_SHOW);
m_wndStopFind.EnableWindow(!m_fInFind && ((m_fInFind && !m_fCancelFind) || !m_fInFind)); m_wndCancelFind.EnableWindow(m_fInFind && ((m_fInFind && !m_fCancelFind) || !m_fInFind)); m_wndStartFind.EnableWindow(!m_fFindNext && (!m_fInFind && !m_strFind.IsEmpty())); m_wndFindNext.EnableWindow(m_fFindNext && (!m_fInFind && !m_strFind.IsEmpty()));
m_wndFindWhatLabel.EnableWindow(!m_fInFind); m_wndFindWhat.EnableWindow(!m_fInFind); m_wndSearchSelected.EnableWindow(!m_fInFind); m_wndSearchCategories.EnableWindow(!m_fInFind); }
//-------------------------------------------------------------------------
// When the user changes the text in the find what edit box, we need to
// make sure we keep track of the string, and that we are in "find" (rather
// than "find next") mode.
//-------------------------------------------------------------------------
LRESULT CMSInfo::OnChangeFindWhat(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { m_fFindNext = FALSE;
// Get the find text from the rich edit control (use EM_GETTEXTEX
// to preserve its Unicode-ness).
TCHAR szBuffer[MAX_PATH]; GETTEXTEX gte;
gte.cb = MAX_PATH; gte.flags = GT_DEFAULT; gte.codepage = 1200; // Unicode
gte.lpDefaultChar = NULL; gte.lpUsedDefChar = NULL; m_wndFindWhat.SendMessage(EM_GETTEXTEX, (WPARAM)>e, (LPARAM)szBuffer); m_strFind = szBuffer;
UpdateFindControls(); SetMenuItems(); return 0; }
//-------------------------------------------------------------------------
// When the user clicks on Find, it will either be for a "Find" or a
// "Find Next".
//-------------------------------------------------------------------------
LRESULT CMSInfo::OnFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { m_fSearchCatNamesOnly = IsDlgButtonChecked(IDC_CHECKSEARCHCATSONLY); m_fSearchSelectedCatOnly = IsDlgButtonChecked(IDC_CHECKSEARCHSELECTED);
if (!m_fFindNext) { m_fInFind = TRUE; m_fCancelFind = FALSE; m_fFindNext = TRUE; m_iFindLine = -2;
// Based on the user's setting of "Search selected category only", start
// with either the selected category or the root category.
if (m_fSearchSelectedCatOnly) m_pcatFind = GetCurrentCategory(); else m_pcatFind = m_pCurrData->GetRootCategory();
UpdateFindControls(); ::SetFocus(m_wndCancelFind.m_hWnd); } else { if (FindInCurrentCategory()) return 0;
m_fInFind = TRUE; m_fCancelFind = FALSE; UpdateFindControls(); ::SetFocus(m_wndCancelFind.m_hWnd); }
// The refresh will post a message that data is ready, so we can search the
// specified category. If we aren't going to refresh the category, we'll just
// post the message ourselves.
if (m_pcatFind) { SetMessage(IDS_SEARCHMESSAGE, 0, TRUE); if (m_pcatFind->GetDataSourceType() == LIVE_DATA && !m_fSearchCatNamesOnly) ((CMSInfoLiveCategory *) m_pcatFind)->Refresh((CLiveDataSource *) m_pCurrData, FALSE); else PostMessage(WM_MSINFODATAREADY, 0, (LPARAM)m_pcatFind); }
return 0; }
//-------------------------------------------------------------------------
// This is the function that's called when the data ready message is
// received by the window. Look for the data in the current find category.
// If there is a match, it will be shown and the find operation stopped.
// Otherwise (unless the option's been selected to search only the current
// category) continue the find operation with the next category.
//-------------------------------------------------------------------------
void CMSInfo::FindRefreshComplete() { if (m_fCancelFind) { m_fInFind = FALSE; m_fFindNext = FALSE; GotoDlgCtrl(m_wndStopFind.m_hWnd); // SetMessage(0);
SelectCategory(GetCurrentCategory()); UpdateFindControls(); ::SetFocus(m_wndStartFind.m_hWnd); return; }
if (FindInCurrentCategory()) return;
// If the user checked "Search selected category only", then we should
// not look through any additional categories.
if (m_fSearchSelectedCatOnly) m_pcatFind = NULL; else { m_iFindLine = -2;
CMSInfoCategory * pNextCategory; pNextCategory = m_pcatFind->GetFirstChild(); if (pNextCategory == NULL) while (m_pcatFind) { pNextCategory = m_pcatFind->GetNextSibling(); if (pNextCategory) break;
m_pcatFind = m_pcatFind->GetParent(); }
m_pcatFind = pNextCategory; }
// If the category is NULL, there are no more matches. Return the
// controls to a normal state and notify the user.
if (m_pcatFind == NULL) { m_fInFind = FALSE; m_fFindNext = FALSE; UpdateFindControls(); MSInfoMessageBox(IDS_NOMOREMATCHES); SelectCategory(GetCurrentCategory()); GotoDlgCtrl(m_wndStopFind.m_hWnd);
return; }
SetMessage(IDS_SEARCHMESSAGE); if (m_pcatFind->GetDataSourceType() == LIVE_DATA && !m_fSearchCatNamesOnly) ((CMSInfoLiveCategory *) m_pcatFind)->Refresh((CLiveDataSource *) m_pCurrData, FALSE); else PostMessage(WM_MSINFODATAREADY, 0, (LPARAM)m_pcatFind); }
//-------------------------------------------------------------------------
// Look for the string in the current category. This function will be
// called when data is avaible for the category. If there is a match, show
// it and return TRUE, otherwise return FALSE.
//
// m_iFindLine contains the list view row number of the last match. If it
// is -1, it means we are just starting on this category (since we would
// start looking at row 0). If it is -2, then we should look for the string
// in the category name. (Note - this might be all we do, depending on the
// setting for m_fSearchCatNamesOnly.)
//-------------------------------------------------------------------------
BOOL CMSInfo::FindInCurrentCategory() { if (m_pcatFind == NULL) return FALSE;
// The search is case insensitive, so convert our search string to lower case.
CString strLookFor(m_strFind); strLookFor.TrimLeft(_T("\t\r\n ")); strLookFor.TrimRight(_T("\t\r\n ")); strLookFor.MakeLower();
// If m_iFindLine is -2, then we should look at the category name for a match.
if (m_iFindLine == -2) { m_iFindLine += 1;
CString strCatName; m_pcatFind->GetNames(&strCatName, NULL); strCatName.MakeLower(); if (strCatName.Find(strLookFor) != -1) { // There was a match. Get the HTREEITEM for the category and select it.
HTREEITEM hti = m_pcatFind->GetHTREEITEM(); if (hti) { m_fInFind = FALSE; m_fFindNext = TRUE; TreeView_EnsureVisible(m_tree.m_hWnd, hti); TreeView_SelectItem(m_tree.m_hWnd, hti); SetMessage(0); UpdateFindControls(); GotoDlgCtrl(m_wndFindNext.m_hWnd); return TRUE; } } }
// If we are search category names only, then we stop here (before looking
// through the data for this category).
if (m_fSearchCatNamesOnly) return FALSE;
// If m_iFindLine is -1, then we need to look in the data for this category
// to see if there is a match. If there is, then we select the category and
// start looking through the lines of the list view (we can't use the index
// we found looking through the data directly, because if the list view is
// sorted we would be searching out of order).
int iRow, iCol, iRowCount, iColCount; if (!m_pcatFind->GetCategoryDimensions(&iColCount, &iRowCount)) return FALSE;
if (m_iFindLine == -1) { CString * pstrCell, strCell; BOOL fFound = FALSE; for (iRow = 0; iRow < iRowCount && !fFound; iRow++) if (m_fAdvanced || !m_pcatFind->IsRowAdvanced(iRow)) for (iCol = 0; iCol < iColCount && !fFound; iCol++) if (m_fAdvanced || !m_pcatFind->IsColumnAdvanced(iCol)) if (m_pcatFind->GetData(iRow, iCol, &pstrCell, NULL)) { strCell = *pstrCell; strCell.MakeLower(); if (strCell.Find(strLookFor) != -1) fFound = TRUE; }
if (!fFound) return FALSE;
// We found data in this category. Select it so it populates the list view.
HTREEITEM hti = m_pcatFind->GetHTREEITEM(); if (hti) { TreeView_EnsureVisible(m_tree.m_hWnd, hti); TreeView_SelectItem(m_tree.m_hWnd, hti); SetMessage(0); } }
// If we get here, m_iFindLine will be >= -1, and represents the line in the
// list view after which we should start searching.
m_iFindLine += 1;
CString strData; int iListRowCount = ListView_GetItemCount(m_list.m_hWnd); int iListColCount = 0;
// Determine the number of columns in the list view.
for (iCol = 0; iCol < iColCount; iCol++) if (m_fAdvanced || !m_pcatFind->IsColumnAdvanced(iCol)) iListColCount += 1;
while (m_iFindLine < iListRowCount) { for (iCol = 0; iCol < iListColCount; iCol++) { ListView_GetItemText(m_list.m_hWnd, m_iFindLine, iCol, strData.GetBuffer(MAX_PATH), MAX_PATH); strData.ReleaseBuffer(); if (strData.GetLength()) { strData.MakeLower(); if (strData.Find(strLookFor) != -1) { // We found a match. The category should already be selected,
// so all we need to do is select the line (and make sure
// all the other lines are not selected).
for (int iRow = 0; iRow < iListRowCount; iRow++) if (iRow == m_iFindLine) { ListView_EnsureVisible(m_list.m_hWnd, iRow, TRUE); ListView_SetItemState(m_list.m_hWnd, iRow, LVIS_SELECTED, LVIS_SELECTED); } else { ListView_SetItemState(m_list.m_hWnd, iRow, 0, LVIS_SELECTED); }
m_fInFind = FALSE; m_fFindNext = TRUE; SetMessage(0); UpdateFindControls(); GotoDlgCtrl(m_wndFindNext.m_hWnd); return TRUE; } } } m_iFindLine += 1; }
// If we fall through to here, then there were no more matches in the
// list view. Return FALSE.
return FALSE; }
//-------------------------------------------------------------------------
// ShowFindControls is called to show or hide the dialog controls used
// for find.
//-------------------------------------------------------------------------
void CMSInfo::ShowFindControls() { int iShowCommand = (m_fFindVisible) ? SW_SHOW : SW_HIDE;
if (m_fFindVisible) PositionFindControls();
m_wndFindWhatLabel.ShowWindow(iShowCommand); m_wndFindWhat.ShowWindow(iShowCommand); m_wndSearchSelected.ShowWindow(iShowCommand); m_wndSearchCategories.ShowWindow(iShowCommand); m_wndStartFind.ShowWindow(iShowCommand); m_wndStopFind.ShowWindow(iShowCommand); m_wndFindNext.ShowWindow(iShowCommand); m_wndCancelFind.ShowWindow(iShowCommand);
if (iShowCommand == SW_HIDE) { m_wndFindWhatLabel.EnableWindow(FALSE); m_wndFindWhat.EnableWindow(FALSE); m_wndSearchSelected.EnableWindow(FALSE); m_wndSearchCategories.EnableWindow(FALSE); m_wndStartFind.EnableWindow(FALSE); m_wndStopFind.EnableWindow(FALSE); m_wndFindNext.EnableWindow(FALSE); m_wndCancelFind.EnableWindow(FALSE); }
if (!m_fFindVisible) return; }
//-------------------------------------------------------------------------
// Position the find controls on the control surface. This will be called
// when the find controls are shown, or when the control is resized.
//-------------------------------------------------------------------------
int CMSInfo::PositionFindControls() { if (!m_fFindVisible) return 0;
// Get some useful sizes of the various controls we need to move around
// the window.
CRect rectFindWhatLabel, rectFindWhat, rectSearchSelected, rectSearchCategories; CRect rectStartFind, rectStopFind, rectClient;
GetClientRect(&rectClient); m_wndFindWhatLabel.GetWindowRect(&rectFindWhatLabel); m_wndFindWhat.GetWindowRect(&rectFindWhat); m_wndStartFind.GetWindowRect(&rectStartFind); m_wndStopFind.GetWindowRect(&rectStopFind); m_wndSearchSelected.GetWindowRect(&rectSearchSelected); m_wndSearchCategories.GetWindowRect(&rectSearchCategories); int iSpacer = 5;
// The control rect is the space we have to work with for placing the controls.
CRect rectControl(rectClient); rectControl.DeflateRect(iSpacer, iSpacer);
// Determine if we have enough room to lay out the controls
// horizontally, or if we need to stack them. Horizontally, it looks like:
//
// <spacer><Find What label><spacer><Find What edit><spacer><Start Find><spacer><Stop Find><spacer>
// <spacer><Search Selected check><spacer><Search Cats check><spacer>
int cxTopLine = iSpacer * 5 + rectFindWhatLabel.Width() * 2 + rectStartFind.Width() + rectStopFind.Width(); int cxBottomLine = iSpacer * 3 + rectSearchSelected.Width() + rectSearchCategories.Width(); BOOL fHorizontal = (cxTopLine <= rectClient.Width() && cxBottomLine <= rectClient.Width());
// If it get's wider than a certain size, it becomes less usable. So put a reasonable
// limit on the width:
int cxMaxWidth = iSpacer * 5 + rectFindWhatLabel.Width() + rectSearchSelected.Width() + rectSearchCategories.Width() + rectStartFind.Width() + rectStopFind.Width(); if (fHorizontal && rectControl.Width() > cxMaxWidth) rectControl.DeflateRect((rectControl.Width() - cxMaxWidth) / 2, 0);
// Figure the height of the control rectangle.
int cyControlRectHeight = rectStartFind.Height() + ((fHorizontal) ? 0 : rectStopFind.Height() + iSpacer); int cyLeftSideHeight;
if (fHorizontal) cyLeftSideHeight = rectFindWhat.Height() + iSpacer + rectSearchSelected.Height(); else cyLeftSideHeight = rectFindWhat.Height() + iSpacer * 2 + rectSearchSelected.Height() * 2;
if (cyControlRectHeight < cyLeftSideHeight) cyControlRectHeight = cyLeftSideHeight;
rectControl.top = rectControl.bottom - cyControlRectHeight;
// Position the buttons appropriately.
if (fHorizontal) { rectStopFind.OffsetRect(rectControl.right - rectStopFind.right, rectControl.top - rectStopFind.top); rectStartFind.OffsetRect(rectStopFind.left - rectStartFind.right - iSpacer, rectControl.top - rectStartFind.top); } else { rectStartFind.OffsetRect(rectControl.right - rectStartFind.right, rectControl.top - rectStartFind.top); rectStopFind.OffsetRect(rectControl.right - rectStopFind.right, rectStartFind.bottom + iSpacer - rectStopFind.top); }
// Position the find label and the find edit box.
rectFindWhatLabel.OffsetRect(rectControl.left - rectFindWhatLabel.left, rectControl.top - rectFindWhatLabel.top + (rectFindWhat.Height() - rectFindWhatLabel.Height()) / 2); rectFindWhat.OffsetRect(rectFindWhatLabel.right - rectFindWhat.left + iSpacer, rectControl.top - rectFindWhat.top); rectFindWhat.right = rectStartFind.left - iSpacer;
// Position the check boxes.
rectSearchSelected.OffsetRect(rectControl.left - rectSearchSelected.left, rectFindWhat.bottom - rectSearchSelected.top + iSpacer);
if (fHorizontal) rectSearchCategories.OffsetRect(rectSearchSelected.right - rectSearchCategories.left + iSpacer, rectSearchSelected.top - rectSearchCategories.top); else rectSearchCategories.OffsetRect(rectControl.left - rectSearchCategories.left, rectSearchSelected.bottom - rectSearchCategories.top + iSpacer);
// If the check boxes are going to overlap the buttons (we'd be very narrow), adjust the button
// position (which might end up off the control, but what're ya gonna do?).
int iRightMostCheckboxEdge = rectSearchCategories.right; if (iRightMostCheckboxEdge < rectSearchSelected.right) iRightMostCheckboxEdge = rectSearchSelected.right; iRightMostCheckboxEdge += iSpacer;
if (!fHorizontal && rectStopFind.left < iRightMostCheckboxEdge) { rectStopFind.OffsetRect(iRightMostCheckboxEdge - rectStopFind.left, 0); rectStartFind.OffsetRect(rectStopFind.left - rectStartFind.left, 0); rectFindWhat.right = rectStartFind.left - iSpacer; }
m_wndStopFind.MoveWindow(&rectStopFind); m_wndStartFind.MoveWindow(&rectStartFind); m_wndFindNext.MoveWindow(&rectStartFind); m_wndCancelFind.MoveWindow(&rectStopFind); m_wndFindWhatLabel.MoveWindow(&rectFindWhatLabel); m_wndFindWhat.MoveWindow(&rectFindWhat); m_wndSearchSelected.MoveWindow(&rectSearchSelected); m_wndSearchCategories.MoveWindow(&rectSearchCategories);
return (rectControl.Height() + iSpacer * 2); }
//-------------------------------------------------------------------------
// Refresh all of the data prior to saving, exporting, printing. This will
// present a dialog box with the refresh message and a progress bar, but
// will not return until the refresh is completed.
//-------------------------------------------------------------------------
void CMSInfo::RefreshData(CLiveDataSource * pSource, CMSInfoLiveCategory * pLiveCategory) { if (pSource == NULL || pSource->m_pThread == NULL) return;
// Create the dialog with the refresh message and progress
// bar, and display it.
CWaitForRefreshDialog dlg; dlg.DoRefresh(pSource, pLiveCategory); }
//=============================================================================
// Functions for managing the DCO (the object providing history).
//=============================================================================
STDMETHODIMP CMSInfo::UpdateDCOProgress(VARIANT varPctDone) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) //V-stlowe 1/30/2001
VERIFY(SUCCEEDED(VariantChangeType(&varPctDone,&varPctDone,0,VT_INT))); if (this->m_HistoryProgressDlg.IsWindow())//todo: is there a better state function to determine if dlg is modal?
{ HWND hWnd = m_HistoryProgressDlg.GetDlgItem(IDC_PROGRESS1); if(::IsWindow(hWnd)) { //int nOffset = varPctDone.iVal - (int) ::SendMessage(m_hWnd, PBM_GETPOS, 0, 0);
//To do: don't rely on 3 (current SAF progress step); find way to get offset.
::SendMessage(hWnd, PBM_DELTAPOS,3, 0L); } } return S_OK; }
STDMETHODIMP CMSInfo::SetHistoryStream(IStream *pStream) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); #ifdef A_STEPHL
ASSERT(0); #endif
//v-stlowe 2/23/2001 shut down progress bar dialog
SetEvent(m_hEvtHistoryComplete); HRESULT hr = pStream->QueryInterface(IID_IStream,(void**) &m_pHistoryStream); if (FAILED(hr) || !m_pHistoryStream) { m_pHistoryStream = NULL; return E_FAIL; }
if (m_pLiveData) ((CLiveDataSource *)m_pLiveData)->SetHistoryStream(m_pHistoryStream);
// When the history stream is available, we need to modify the UI to allow
// the user to select the history.
if (!m_fHistoryAvailable) { m_fHistoryAvailable = TRUE;//actually this should already be true...
SetMenuItems(); } m_fHistorySaveAvailable = TRUE; FillHistoryCombo(); //if history window is current view, refresh
if (m_history.IsWindowVisible()) { CMSInfoCategory * pCategory = GetCurrentCategory(); if (pCategory != NULL && pCategory->GetDataSourceType() == LIVE_DATA) { m_pLastCurrentCategory = GetCurrentCategory();
int iIndex = (int)m_history.SendMessage(CB_GETCURSEL, 0, 0); if (iIndex == CB_ERR) { iIndex = 0; m_history.SendMessage(CB_SETCURSEL, (WPARAM)iIndex, 0); } ChangeHistoryView(iIndex);
} } else if (m_fShowPCH && !m_history.IsWindowVisible() && m_strMachine.IsEmpty()) { // If m_fShowPCH is set, then the command line option to launch into
// the history view was selected.
DispatchCommand(ID_VIEW_HISTORY); } #ifdef A_STEPHL
//STATSTG streamStat;
//hr = m_pHistoryStream->Stat(&streamStat,STATFLAG_NONAME );
//ASSERT(SUCCEEDED(hr) && "couldn't get stream statistics");
//BYTE* pBuffer = new BYTE[streamStat.cbSize.LowPart];
//ULONG ulRead;
//m_pHistoryStream->Read(pBuffer,streamStat.cbSize.LowPart,&ulRead);
// CFile file;
//file.Open("c:\\history.xml", CFile::modeCreate | CFile::modeWrite);
// file.Write(pBuffer,ulRead);
// delete pBuffer;
#endif
return S_OK; }
STDMETHODIMP CMSInfo::get_DCO_IUnknown(IUnknown **pVal) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (m_pDCO == NULL) return E_FAIL;
return (m_pDCO->QueryInterface(IID_IUnknown,(void**) pVal)); }
STDMETHODIMP CMSInfo::put_DCO_IUnknown(IUnknown *newVal) { //v-stlowe 2/23/2001
//beware situation where put_DCO_IUnknown gets called before control is finished initializing.
WaitForSingleObject(m_evtControlInit,INFINITE); AFX_MANAGE_STATE(AfxGetStaticModuleState());
HRESULT hr = newVal->QueryInterface( __uuidof(ISAFDataCollection), (void**)&m_pDCO ); if (FAILED(hr)) return E_FAIL; //end v-stlowe 2/23/2001
TCHAR szDataspecPath[MAX_PATH]; if (ExpandEnvironmentStrings(_T("%windir%\\pchealth\\helpctr\\config\\dataspec.xml"), szDataspecPath, MAX_PATH)) { CComBSTR bstrPath(szDataspecPath);
if (m_pDCO != NULL && (BSTR)bstrPath != NULL) { hr = m_pDCO->put_MachineData_DataSpec(bstrPath); hr = m_pDCO->put_History_DataSpec(bstrPath); } // This is done by the script now: m_pDCO->ExecuteAsync();
}
// Have to put this after the calls made using the DCO, so that the /pch
// flag (which is to start MSInfo with history showing) works.
if (!m_fHistoryAvailable) { m_fHistoryAvailable = TRUE; if (m_fShowPCH && !m_history.IsWindowVisible() && m_strMachine.IsEmpty()) DispatchCommand(ID_VIEW_HISTORY); SetMenuItems(); }
return S_OK; }
//=============================================================================
// Interface methods to do a silent save of a file.
//=============================================================================
STDMETHODIMP CMSInfo::SaveFile(BSTR filename, BSTR computer, BSTR category) { AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString strFilename(filename); CString strComputer(computer); CString strCategory(category);
HRESULT hr = E_FAIL;
::AfxSetResourceHandle(_Module.GetResourceInstance()); CLiveDataSource * pSilentSource = new CLiveDataSource; if (pSilentSource) hr = pSilentSource->Create(strComputer, NULL, strCategory);
if (SUCCEEDED(hr)) { m_fNoUI = TRUE;
CDataSource * pOldSource = m_pCurrData; m_pCurrData = pSilentSource; if (strFilename.Right(4).CompareNoCase(CString(_T(".nfo"))) == 0) SaveMSInfoFile(strFilename); else ExportFile(strFilename, 0); m_pCurrData = pOldSource;
delete pSilentSource;
m_fNoUI = FALSE; }
return hr; }
LRESULT CHistoryRefreshDlg::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return 1; // Let the system set the focus
}
|