//============================================================================= // 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 //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 { 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 pStorage; if (SUCCEEDED(StgOpenStorage(bstrFileName, NULL, grfMode, NULL, 0, &pStorage))) { CComPtr 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 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: // // // 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 }