Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2811 lines
84 KiB

//=============================================================================
// 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)&gte, (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
}