windows-nt/Source/XPSP1/NT/admin/pchealth/sysinfo/control/msinfo.h
2020-09-26 16:20:57 +08:00

1881 lines
57 KiB
C++

// MSInfo.h : Declaration of the CMSInfo
#ifndef __MSINFO_H_
#define __MSINFO_H_
#include <commdlg.h>
#include "resource.h" // main symbols
#include <atlctl.h>
#include "pseudomenu.h"
#include "datasource.h"
#include "category.h"
#include "msinfotool.h"
#include "msinfo4category.h"
#include "htmlhelp.h"
#include <afxdlgs.h>
#include "dataset.h"
//
// From HelpServiceTypeLib.idl
//
#include <HelpServiceTypeLib.h>
extern void StringReplace(CString & str, LPCTSTR szLookFor, LPCTSTR szReplaceWith);
extern BOOL gfEndingSession;
//v-stlowe History progress dialog
//member variable of CMSInfo so it can be updated by CMSInfo::UpdateDCOProgress
// CHistoryRefreshDlg dialog
//=========================================================================
//
//=========================================================================
#include "HistoryParser.h" // Added by ClassView
#include <afxcmn.h>
#include <afxmt.h>
class CHistoryRefreshDlg : public CDialogImpl<CHistoryRefreshDlg>
{
public:
enum { IDD = IDD_HISTORYREFRESHPROGRESS };
CWindow m_wndProgressBar;
BEGIN_MSG_MAP(CWaitForRefreshDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
END_MSG_MAP()
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
};
/////////////////////////////////////////////////////////////////////////////
// CMSInfo
class ATL_NO_VTABLE CMSInfo :
public CComObjectRootEx<CComSingleThreadModel>,
public CStockPropImpl<CMSInfo, IMSInfo, &IID_IMSInfo, &LIBID_MSINFO32Lib>,
public CComCompositeControl<CMSInfo>,
public IPersistStreamInitImpl<CMSInfo>,
public IOleControlImpl<CMSInfo>,
public IOleObjectImpl<CMSInfo>,
public IOleInPlaceActiveObjectImpl<CMSInfo>,
public IViewObjectExImpl<CMSInfo>,
public IOleInPlaceObjectWindowlessImpl<CMSInfo>,
public IPersistStorageImpl<CMSInfo>,
public ISpecifyPropertyPagesImpl<CMSInfo>,
public IQuickActivateImpl<CMSInfo>,
public IDataObjectImpl<CMSInfo>,
public IProvideClassInfo2Impl<&CLSID_MSInfo, NULL, &LIBID_MSINFO32Lib>,
public CComCoClass<CMSInfo, &CLSID_MSInfo>
{
public:
CMSInfo() :m_fHistoryAvailable(FALSE),m_pCurrData(NULL),m_fHistorySaveAvailable(FALSE)
{
m_bWindowOnly = TRUE;
CalcExtent(m_sizeExtent);
//v-stlowe 2/23/01 synchronization for put_DCO_IUnknown
m_evtControlInit = CreateEvent(NULL,TRUE,FALSE,CString(_T("MSInfoControlInitialized")));
//create history event, to signal when DCO has finished.
m_hEvtHistoryComplete = CreateEvent(NULL,TRUE,FALSE,CString(_T("MSInfoHistoryDone")));
}
DECLARE_REGISTRY_RESOURCEID(IDR_MSINFO)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMSInfo)
COM_INTERFACE_ENTRY(IMSInfo)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IViewObjectEx)
COM_INTERFACE_ENTRY(IViewObject2)
COM_INTERFACE_ENTRY(IViewObject)
COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY(IOleInPlaceObject)
COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
COM_INTERFACE_ENTRY(IOleControl)
COM_INTERFACE_ENTRY(IOleObject)
COM_INTERFACE_ENTRY(IPersistStreamInit)
COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
COM_INTERFACE_ENTRY(IQuickActivate)
COM_INTERFACE_ENTRY(IPersistStorage)
COM_INTERFACE_ENTRY(IDataObject)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
END_COM_MAP()
BEGIN_PROP_MAP(CMSInfo)
PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
PROP_ENTRY("Appearance", DISPID_APPEARANCE, CLSID_NULL)
PROP_ENTRY("AutoSize", DISPID_AUTOSIZE, CLSID_NULL)
PROP_ENTRY("BackColor", DISPID_BACKCOLOR, CLSID_StockColorPage)
PROP_ENTRY("BackStyle", DISPID_BACKSTYLE, CLSID_NULL)
PROP_ENTRY("BorderColor", DISPID_BORDERCOLOR, CLSID_StockColorPage)
PROP_ENTRY("BorderStyle", DISPID_BORDERSTYLE, CLSID_NULL)
PROP_ENTRY("BorderVisible", DISPID_BORDERVISIBLE, CLSID_NULL)
PROP_ENTRY("BorderWidth", DISPID_BORDERWIDTH, CLSID_NULL)
PROP_ENTRY("Font", DISPID_FONT, CLSID_StockFontPage)
PROP_ENTRY("ForeColor", DISPID_FORECOLOR, CLSID_StockColorPage)
PROP_ENTRY("HWND", DISPID_HWND, CLSID_NULL)
// Example entries
// PROP_ENTRY("Property Description", dispid, clsid)
// PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()
BEGIN_MSG_MAP(CMSInfo)
MESSAGE_HANDLER(WM_CTLCOLORDLG, OnDialogColor)
MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnDialogColor)
CHAIN_MSG_MAP(CComCompositeControl<CMSInfo>)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP)
MESSAGE_HANDLER(WM_MSINFODATAREADY, OnMSInfoDataReady)
NOTIFY_HANDLER(IDC_TREE, TVN_SELCHANGED, OnSelChangedTree)
NOTIFY_HANDLER(IDC_LIST, LVN_COLUMNCLICK, OnColumnClick)
NOTIFY_HANDLER(IDC_LIST, LVN_ITEMCHANGED, OnListItemChanged)
NOTIFY_HANDLER(IDC_TREE, TVN_ITEMEXPANDING, OnItemExpandingTree)
COMMAND_HANDLER(IDSTOPFIND, BN_CLICKED, OnStopFind)
COMMAND_HANDLER(IDCANCELFIND, BN_CLICKED, OnStopFind)
COMMAND_HANDLER(IDC_EDITFINDWHAT, EN_CHANGE, OnChangeFindWhat)
COMMAND_HANDLER(IDSTARTFIND, BN_CLICKED, OnFind)
COMMAND_HANDLER(IDFINDNEXT, BN_CLICKED, OnFind)
COMMAND_HANDLER(IDC_HISTORYCOMBO, CBN_SELCHANGE, OnHistorySelection)
COMMAND_HANDLER(IDC_CHECKSEARCHSELECTED, BN_CLICKED, OnClickedSearchSelected)
COMMAND_HANDLER(IDC_CHECKSEARCHCATSONLY, BN_CLICKED, OnClickedSearchCatsOnly)
MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange)
NOTIFY_HANDLER(IDC_LIST, NM_SETFOCUS, OnSetFocusList)
NOTIFY_HANDLER(IDC_LIST, LVN_GETINFOTIP, OnInfoTipList)
NOTIFY_HANDLER(IDC_TREE, NM_RCLICK, OnRClickTree)
COMMAND_HANDLER(IDC_EDITFINDWHAT, EN_SETFOCUS, OnSetFocusEditFindWhat)
COMMAND_HANDLER(IDC_EDITFINDWHAT, EN_KILLFOCUS, OnKillFocusEditFindWhat)
END_MSG_MAP()
// Handler prototypes:
// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
BEGIN_SINK_MAP(CMSInfo)
//Make sure the Event Handlers have __stdcall calling convention
END_SINK_MAP()
STDMETHOD(OnAmbientPropertyChange)(DISPID dispid)
{
if (dispid == DISPID_AMBIENT_BACKCOLOR)
{
// Don't respond to ambient color changes (yet).
//
// SetBackgroundColorFromAmbient();
// FireViewChange();
}
return IOleControlImpl<CMSInfo>::OnAmbientPropertyChange(dispid);
}
// IViewObjectEx
DECLARE_VIEW_STATUS(0)
// IMSInfo
public:
STDMETHOD(SaveFile)(BSTR filename, BSTR computer, BSTR category);
STDMETHOD(get_DCO_IUnknown)(/*[out, retval]*/ IUnknown* *pVal);
STDMETHOD(put_DCO_IUnknown)(/*[in]*/ IUnknown* newVal);
STDMETHOD(SetHistoryStream)(IStream * pStream);
STDMETHOD(UpdateDCOProgress)(VARIANT nPctDone);
//=========================================================================
// Member variables generated by the wizard.
//=========================================================================
//v-stlowe 2/23/2001
CHistoryRefreshDlg m_HistoryProgressDlg;
//v-stlowe 2/27/2001 - filename needed when loading XML files,
//and switching between snapshot and history view
CString m_strFileName;
short m_nAppearance;
OLE_COLOR m_clrBackColor;
LONG m_nBackStyle;
OLE_COLOR m_clrBorderColor;
LONG m_nBorderStyle;
BOOL m_bBorderVisible;
LONG m_nBorderWidth;
CComPtr<IFontDisp> m_pFont;
OLE_COLOR m_clrForeColor;
//v-stlowe 2/23/01 synchronization for put_DCO_IUnknown
HANDLE m_evtControlInit;
//v-stlowe 2/24/01 synchronization for History DCO progress dlg, so it can be destroyed
//even if DCO never returns from collecting history
HANDLE m_hEvtHistoryComplete;
UINT HistoryRefreshDlgDlgThreadProc(LPVOID pParamNotUsed );
enum { IDD = IDD_MSINFO };
//=========================================================================
// MSInfo member variables (initialized in OnInitDialog()).
//=========================================================================
BOOL m_fDoNotRun; // if this is TRUE, don't allow the control to do anything
CString m_strDoNotRun; // message to display if we don't run
CString m_strMachine; // if empty, local machine, otherwise network name
CWindow m_tree; // set to refer to the tree view
CWindow m_list; // set to refer to the list view
int m_iTreeRatio; // the tree is x% the size of the list view
BOOL m_fFirstPaint; // flag so we can initialize some paint things, once
CDataSource * m_pLiveData; // data source for current data from WMI
CDataSource * m_pFileData; // data source for an open NFO, XML snapshot
CDataSource * m_pCurrData; // copy of one of the previous two (don't need to delete this)
CMSInfoCategory * m_pCategory; // currently selected category
BOOL m_fMouseCapturedForSplitter; // mouse currently being looked at by splitter
BOOL m_fTrackingSplitter; // does the user have the LBUTTON down, resizing panes
RECT m_rectSplitter; // current splitter rect (for hit tests)
RECT m_rectLastSplitter; // last rect in DrawFocusRect
int m_cxOffset; // offset from mouse position to left side of splitter
BOOL m_fAdvanced; // currently showing advanced data?
CString m_strMessTitle; // title for message to display in results
CString m_strMessText; // text for message to display in results
BOOL m_fNoUI; // true if doing a silent save
int m_aiCategoryColNumber[64]; // contains category column for each list view column
int m_iCategoryColNumberLen;
CMapWordToPtr m_mapIDToTool; // a map from menu ID to a CMSInfoTool pointer
TCHAR m_szCurrentDir[MAX_PATH]; // current directory when control starts (should restore)
// Find member variables.
BOOL m_fFindVisible; // are the find controls visible?
CWindow m_wndFindWhatLabel; // windows for the various find controls
CWindow m_wndFindWhat;
CWindow m_wndSearchSelected;
CWindow m_wndSearchCategories;
CWindow m_wndStartFind;
CWindow m_wndStopFind;
CWindow m_wndFindNext;
CWindow m_wndCancelFind;
BOOL m_fInFind;
BOOL m_fCancelFind;
BOOL m_fFindNext;
BOOL m_fSearchCatNamesOnly;
BOOL m_fSearchSelectedCatOnly;
CString m_strFind;
CMSInfoCategory * m_pcatFind;
int m_iFindLine;
// History member variables.
CWindow m_history;
CWindow m_historylabel;
BOOL m_fHistoryAvailable;
BOOL m_fHistorySaveAvailable;
CMSInfoCategory * m_pLastCurrentCategory;
CComPtr<ISAFDataCollection> m_pDCO;
CComPtr<IStream> m_pHistoryStream;
// Member variables set from the command line parameters.
CString m_strOpenFile;
CString m_strPrintFile;
CString m_strCategory;
CString m_strCategories;
CString m_strComputer;
BOOL m_fShowPCH;
BOOL m_fShowCategories;
//=========================================================================
// A member variable and a function to hook into the windows procedure
// of the parent window of the control (so we can put a menu on it).
//=========================================================================
HMENU m_hmenu;
HWND m_hwndParent;
static CMSInfo * m_pControl;
static WNDPROC m_wndprocParent;
static LRESULT CALLBACK MenuWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_COMMAND && m_pControl && m_pControl->DispatchCommand(LOWORD(wParam)))
return 0;
// We want to know if the session is ending (so we can set the timeout for
// waiting for WMI to finish to something smaller).
if (uMsg == WM_ENDSESSION || uMsg == WM_QUERYENDSESSION)
gfEndingSession = TRUE;
return CallWindowProc(m_wndprocParent, hwnd, uMsg, wParam, lParam);
}
//=========================================================================
// Functions for initializing and destroying the dialog. A good place to
// initialize variables and free memory.
//=========================================================================
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_list.Attach(GetDlgItem(IDC_LIST));
m_tree.Attach(GetDlgItem(IDC_TREE));
m_history.Attach(GetDlgItem(IDC_HISTORYCOMBO));
m_historylabel.Attach(GetDlgItem(IDC_HISTORYLABEL));
// Determine if we are being loaded from within Help Center. Do this
// by getting IOleContainer, which gives us IHTMLDocument2, which will
// give us the URL loading us.
m_fDoNotRun = TRUE;
m_strDoNotRun.Empty();
CString strParams;
CComPtr<IOleContainer> spContainer;
m_spClientSite->GetContainer(&spContainer);
CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> spHTMLDocument(spContainer);
if (spHTMLDocument)
{
CComBSTR bstrURL;
if (SUCCEEDED(spHTMLDocument->get_URL(&bstrURL)))
{
CComBSTR bstrEscapedUrl(bstrURL);
USES_CONVERSION;
if(SUCCEEDED(UrlUnescape(OLE2T(bstrEscapedUrl), NULL, NULL, URL_UNESCAPE_INPLACE)))
bstrURL = bstrEscapedUrl;
bstrEscapedUrl.Empty();
CString strURL(bstrURL);
int iQuestionMark = strURL.Find(_T("?"));
if (iQuestionMark != -1)
strParams = strURL.Mid(iQuestionMark + 1);
strURL.MakeLower();
if (strURL.Left(4) == CString(_T("hcp:")))
m_fDoNotRun = FALSE;
// Include the following when we want to test the control
// using a local URL.
#ifdef MSINFO_TEST_WORKFROMLOCALURLS
if (strURL.Left(5) == CString(_T("file:")))
m_fDoNotRun = FALSE;
#endif
}
}
if (m_fDoNotRun)
{
m_list.ShowWindow(SW_HIDE);
m_tree.ShowWindow(SW_HIDE);
return 0;
}
::GetCurrentDirectory(MAX_PATH, m_szCurrentDir);
m_strMachine.Empty();
m_fNoUI = FALSE;
// Find the parent window for MSInfo. We want to add a menu bar to it.
// We find the window by walking up the chain of parents until we get
// to one with a caption. That window must also be top level (no parent),
// and must not already have a menu.
TCHAR szBuff[MAX_PATH];
HWND hwnd = this->m_hWnd;
m_hmenu = NULL;
m_hwndParent = NULL;
m_wndprocParent = NULL;
while (hwnd != NULL)
{
if (::GetWindowText(hwnd, szBuff, MAX_PATH) && NULL == ::GetParent(hwnd) && NULL == ::GetMenu(hwnd))
{
// Update the window title. [This is done by the msinfo.xml file now.]
//
// CString strNewCaption;
// ::AfxSetResourceHandle(_Module.GetResourceInstance());
// strNewCaption.LoadString(IDS_SYSTEMINFO);
// ::SetWindowText(hwnd, strNewCaption);
// We've found the window. Load the menu bar for it.
m_hmenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MENUBAR));
if (m_hmenu)
{
::SetMenu(hwnd, m_hmenu);
// To catch the commands from the menu, we need to replace that
// window's WndProc with our own. Ours will catch and menu command
// that we implement, and pass the rest of the messages along.
m_wndprocParent = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC);
::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (ULONG_PTR)(WNDPROC)&MenuWndProc);
m_pControl = this; // set a static member variable so the MenuWndProc can access it
m_hwndParent = hwnd;
}
break;
}
hwnd = ::GetParent(hwnd);
}
m_fFirstPaint = TRUE;
ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
m_strMessTitle.Empty();
m_strMessText.Empty();
m_fMouseCapturedForSplitter = FALSE;
m_fTrackingSplitter = FALSE;
::SetRect(&m_rectSplitter, 0, 0, 0, 0);
m_iTreeRatio = 33;
// Set the history state variables (including whether or not history is available,
// based on the presence of the DCO).
#ifdef MSINFO_TEST_HISTORYFROMFILE
m_fHistoryAvailable = TRUE;
#else
// m_fHistoryAvailable = (m_pDCO != NULL);
#endif
m_pLastCurrentCategory = NULL;
// Removing the Advanced/Basic view menu items (Whistler 207638). Should
// always default to Advanced now.
m_fAdvanced = TRUE; // was FALSE;
m_fFindVisible = TRUE; // used to be FALSE, before we decided to show find on startup
m_wndFindWhatLabel.Attach(GetDlgItem(IDC_FINDWHATLABEL));
m_wndFindWhat.Attach(GetDlgItem(IDC_EDITFINDWHAT));
m_wndSearchSelected.Attach(GetDlgItem(IDC_CHECKSEARCHSELECTED));
m_wndSearchCategories.Attach(GetDlgItem(IDC_CHECKSEARCHCATSONLY));
// We need to set the event mask for the rich edit control
// so we get EN_CHANGE notifications.
m_wndFindWhat.SendMessage(EM_SETEVENTMASK, 0, (LPARAM)ENM_CHANGE);
m_wndFindWhat.SendMessage(EM_SETTEXTMODE, TM_PLAINTEXT, 0);
m_wndStartFind.Attach(GetDlgItem(IDSTARTFIND));
m_wndStopFind.Attach(GetDlgItem(IDSTOPFIND));
m_wndFindNext.Attach(GetDlgItem(IDFINDNEXT));
m_wndCancelFind.Attach(GetDlgItem(IDCANCELFIND));
// The pairs (start & find next, stop & cancel find) need to be matched
// in size. The heights should already be the same.
CRect rectStart, rectNext, rectStop, rectCancel;
m_wndStartFind.GetWindowRect(&rectStart);
m_wndFindNext.GetWindowRect(&rectNext);
m_wndStopFind.GetWindowRect(&rectStop);
m_wndCancelFind.GetWindowRect(&rectCancel);
if (rectStart.Width() > rectNext.Width())
rectNext = rectStart;
else
rectStart = rectNext;
if (rectStop.Width() > rectCancel.Width())
rectCancel = rectStop;
else
rectStop = rectCancel;
m_wndStartFind.MoveWindow(&rectStart);
m_wndFindNext.MoveWindow(&rectNext);
m_wndStopFind.MoveWindow(&rectStop);
m_wndCancelFind.MoveWindow(&rectCancel);
// Initialize the find function member variables.
m_fInFind = FALSE;
m_fCancelFind = FALSE;
m_fFindNext = FALSE;
m_strFind = CString(_T(""));
m_pcatFind = NULL;
m_fSearchCatNamesOnly = FALSE;
m_fSearchSelectedCatOnly = FALSE;
// Show the appropriate find controls.
ShowFindControls();
UpdateFindControls();
m_iCategoryColNumberLen = 0;
// Parse the parameters out of the URL.
m_strOpenFile = _T("");
m_strPrintFile = _T("");
m_strCategory = _T("");
m_strComputer = _T("");
m_strCategories = _T("");
m_fShowCategories = FALSE;
m_fShowPCH = FALSE;
CString strTemp;
while (!strParams.IsEmpty())
{
while (strParams[0] == _T(','))
strParams = strParams.Mid(1);
strTemp = strParams.SpanExcluding(_T(",="));
if (strTemp.CompareNoCase(CString(_T("pch"))) == 0)
{
m_fShowPCH = TRUE;
strParams = strParams.Mid(strTemp.GetLength());
}
else if (strTemp.CompareNoCase(CString(_T("showcategories"))) == 0)
{
m_fShowCategories = TRUE;
strParams = strParams.Mid(strTemp.GetLength());
}
else if (strTemp.CompareNoCase(CString(_T("open"))) == 0)
{
strParams = strParams.Mid(strTemp.GetLength());
if (strParams[0] == _T('='))
strParams = strParams.Mid(1);
m_strOpenFile = strParams.SpanExcluding(_T(","));
strParams = strParams.Mid(m_strOpenFile.GetLength());
}
else if (strTemp.CompareNoCase(CString(_T("print"))) == 0)
{
strParams = strParams.Mid(strTemp.GetLength());
if (strParams[0] == _T('='))
strParams = strParams.Mid(1);
m_strPrintFile = strParams.SpanExcluding(_T(","));
strParams = strParams.Mid(m_strPrintFile.GetLength());
}
else if (strTemp.CompareNoCase(CString(_T("computer"))) == 0)
{
strParams = strParams.Mid(strTemp.GetLength());
if (strParams[0] == _T('='))
strParams = strParams.Mid(1);
m_strComputer = strParams.SpanExcluding(_T(","));
strParams = strParams.Mid(m_strComputer.GetLength());
}
else if (strTemp.CompareNoCase(CString(_T("category"))) == 0)
{
strParams = strParams.Mid(strTemp.GetLength());
if (strParams[0] == _T('='))
strParams = strParams.Mid(1);
m_strCategory = strParams.SpanExcluding(_T(","));
strParams = strParams.Mid(m_strCategory.GetLength());
}
else if (strTemp.CompareNoCase(CString(_T("categories"))) == 0)
{
strParams = strParams.Mid(strTemp.GetLength());
if (strParams[0] == _T('='))
strParams = strParams.Mid(1);
m_strCategories = strParams.SpanExcluding(_T(","));
strParams = strParams.Mid(m_strCategories.GetLength());
}
else
strParams = strParams.Mid(strTemp.GetLength());
}
// Initialize the data sources.
m_pLiveData = NULL;
CLiveDataSource * pLiveData = new CLiveDataSource;
if (pLiveData)
{
HRESULT hr = pLiveData->Create(_T(""), m_hWnd, m_strCategories); // create a data source for this machine
if (FAILED(hr))
{
// bad news, report an error
delete pLiveData;
}
else
m_pLiveData = pLiveData;
}
else
{
// bad news - no memory
}
m_pFileData = NULL;
m_pCategory = NULL;
// Load the initial tool set.
LoadGlobalToolset(m_mapIDToTool);
UpdateToolsMenu();
//a-sanka 03/29/01 Moved here before any model MessageBox.
//v-stlowe 2/23/01 synchronization for put_DCO_IUnknown
SetEvent(m_evtControlInit);
// Handle the command line parameters.
if (!m_strPrintFile.IsEmpty())
m_strOpenFile = m_strPrintFile;
HRESULT hrOpen = E_FAIL;
if (!m_strOpenFile.IsEmpty())
{
LPCTSTR szBuffer = m_strOpenFile;
int nFileExtension = _tcsclen(szBuffer) - 1;
while (nFileExtension >= 0 && szBuffer[nFileExtension] != _T('.'))
nFileExtension -= 1;
if (nFileExtension >= 0)
hrOpen = OpenMSInfoFile(szBuffer, nFileExtension + 1);
}
// Check to see if we should initially display a file as we open. Also look up whether
// the user was showing advanced data last time.
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);
if (ERROR_SUCCESS == RegQueryValueEx(hkey, _T("openfile"), NULL, &dwType, (LPBYTE)szBuffer, &dwSize))
if (dwType == REG_SZ)
{
RegDeleteValue(hkey, _T("openfile"));
int nFileExtension = _tcsclen(szBuffer) - 1;
while (nFileExtension >= 0 && szBuffer[nFileExtension] != _T('.'))
nFileExtension -= 1;
if (nFileExtension >= 0)
hrOpen = OpenMSInfoFile(szBuffer, nFileExtension + 1);
}
// Removing the Advanced/Basic view menu items (Whistler 207638)
//
// dwSize = MAX_PATH * sizeof(TCHAR);
// if (ERROR_SUCCESS == RegQueryValueEx(hkey, _T("advanced"), NULL, &dwType, (LPBYTE)szBuffer, &dwSize))
// if (dwType == REG_SZ && szBuffer[0] == _T('1'))
// m_fAdvanced = TRUE;
RegCloseKey(hkey);
}
if (FAILED(hrOpen) && m_pLiveData)
SelectDataSource(m_pLiveData);
if (FAILED(hrOpen) && m_pLiveData)
SelectDataSource(m_pLiveData);
if (!m_strPrintFile.IsEmpty())
DoPrint(TRUE);
if (!m_strComputer.IsEmpty())
DoRemote(m_strComputer);
if (!m_strCategory.IsEmpty() && m_pCurrData)
{
HTREEITEM hti = m_pCurrData->GetNodeByName(m_strCategory);
if (hti != NULL)
{
TreeView_EnsureVisible(m_tree.m_hWnd, hti);
TreeView_SelectItem(m_tree.m_hWnd, hti);
}
}
if (m_fShowPCH && m_fHistoryAvailable && m_strMachine.IsEmpty())
{
DispatchCommand(ID_VIEW_HISTORY);
SetMenuItems();
}
// Load the table of accelerator keys (used in our override of TranslateAccelerator).
m_hAccTable = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_ACCELERATOR1));
// Set the focus to the control, so we can process keystrokes immediately.
::SetFocus(m_hWnd);
return 0;
}
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
// Restore the window's wndproc.
if (m_wndprocParent && m_hwndParent)
{
::SetWindowLongPtr(m_hwndParent, GWLP_WNDPROC, (ULONG_PTR)m_wndprocParent);
m_wndprocParent = NULL;
m_hwndParent = NULL;
}
// When the window is closing, make sure we don't send any more messages
// from the refresh thread.
/* THIS HASN'T BEEN TESTED ENOUGH FOR THIS CHECKIN
if (m_pCurrData)
{
CMSInfoCategory * pCat = m_pCurrData->GetRootCategory();
if (pCat && pCat->GetDataSourceType() == LIVE_DATA)
{
CLiveDataSource * pLiveDataSource = (CLiveDataSource *) m_pCurrData;
if (pLiveDataSource->m_pThread)
pLiveDataSource->m_pThread->AbortMessaging();
}
}
*/
::SetCurrentDirectory(m_szCurrentDir);
if (m_pLiveData)
{
if (m_pFileData == m_pLiveData)
m_pFileData = NULL;
delete m_pLiveData;
m_pLiveData = NULL;
}
if (m_pFileData)
{
delete m_pFileData;
m_pFileData = NULL;
}
RemoveToolset(m_mapIDToTool);
// Save the complexity of the view to the registry (so we can default to
// it next time).
//
// Removing the Advanced/Basic view menu items (Whistler 207638). Should
// always default to Advanced now.
// HKEY hkey;
// if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_ALL_ACCESS, &hkey))
// {
// TCHAR szBuffer[] = _T("0");
//
// if (m_fAdvanced)
// szBuffer[0] = _T('1');
//
// RegSetValueEx(hkey, _T("advanced"), 0, REG_SZ, (LPBYTE)szBuffer, 2 * sizeof(TCHAR));
// RegCloseKey(hkey);
// }
if (m_pDCO)
m_pDCO->Abort();
m_fDoNotRun = TRUE;
return 0;
}
//=========================================================================
// These functions process mouse movements, which we may respond to in
// different ways. For instance, if the mouse is over the menu bar, then
// we may want to highlight a menu. If the mouse is over the splitter,
// we'll want to change the cursor into a resizer.
//
// This is complicated by the fact that we need to capture the mouse,
// to make sure we know when it leaves so we can update appropriately.
//=========================================================================
LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
int xPos = LOWORD(lParam); int yPos = HIWORD(lParam);
if (m_fTrackingSplitter)
UpdateSplitterPosition(xPos, yPos);
else
CheckHover(xPos, yPos);
return 0;
}
void CheckHover(int xPos, int yPos)
{
// Check to see if the mouse is hover over the splitter.
if (::PtInRect(&m_rectSplitter, CPoint(xPos, yPos)))
{
if (!m_fMouseCapturedForSplitter)
{
SetCapture();
m_fMouseCapturedForSplitter = TRUE;
}
::SetCursor(::LoadCursor(NULL, IDC_SIZEWE));
return;
}
else if (m_fMouseCapturedForSplitter)
{
ReleaseCapture();
m_fMouseCapturedForSplitter = FALSE;
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
CheckHover(xPos, yPos); // give the other areas a chance
return;
}
}
//=========================================================================
// These functions process mouse clicks and releases. This might entail
// showing a menu, or resizing the panes using the splitter.
//=========================================================================
LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
int xPos = LOWORD(lParam); int yPos = HIWORD(lParam);
SetFocus();
CheckSplitterClick(xPos, yPos);
return 0;
}
LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
if (m_fTrackingSplitter)
EndSplitterDrag();
return 0;
}
//-------------------------------------------------------------------------
// If the user clicked on the splitter (the area between the list view and
// the tree view), start tracking the movement of it. Use the DrawFocusRect
// API to give feedback.
//-------------------------------------------------------------------------
void CheckSplitterClick(int xPos, int yPos)
{
if (::PtInRect(&m_rectSplitter, CPoint(xPos, yPos)))
{
ASSERT(!m_fTrackingSplitter);
m_fTrackingSplitter = TRUE;
::CopyRect(&m_rectLastSplitter, &m_rectSplitter);
DrawSplitter();
m_cxOffset = xPos - m_rectLastSplitter.left;
ASSERT(m_cxOffset >= 0);
}
}
//=========================================================================
// Functions for handling the user interaction with the splitter control.
//
// TBD - bug if you drag splitter and release button with the cursor over
// a menu.
//=========================================================================
void DrawSplitter()
{
InvalidateRect(&m_rectLastSplitter, FALSE);
PAINTSTRUCT ps;
HDC hdc = BeginPaint(&ps);
::DrawFocusRect(hdc, &m_rectLastSplitter);
EndPaint(&ps);
}
void UpdateSplitterPosition(int xPos, int yPos)
{
// If the user attempts to drag the splitter outside of the window, don't
// allow it.
RECT rectClient;
GetClientRect(&rectClient);
if (!::PtInRect(&rectClient, CPoint(xPos, yPos)))
return;
DrawSplitter(); // remove the current focus rect
int cxDelta = xPos - (m_rectLastSplitter.left + m_cxOffset);
m_rectLastSplitter.left += cxDelta;
m_rectLastSplitter.right += cxDelta;
DrawSplitter();
}
void EndSplitterDrag()
{
DrawSplitter(); // remove the focus rect
// Compute the new tree and list rectangles based on the last splitter position.
RECT rectTree, rectList;
m_tree.GetWindowRect(&rectTree);
m_list.GetWindowRect(&rectList);
ScreenToClient(&rectTree);
ScreenToClient(&rectList);
// First, check to see if the coordinates are reversed (possibly on a bi-directional locale). The
// first case is that standard, left to right case.
if (rectTree.right > rectTree.left || (rectTree.right == rectTree.left && rectList.right > rectList.left))
{
rectTree.right = m_rectLastSplitter.left;
rectList.left = m_rectLastSplitter.right;
// Move the tree and list controls based on the new rects.
m_tree.MoveWindow(rectTree.left, rectTree.top, rectTree.right - rectTree.left, rectTree.bottom - rectTree.top, TRUE);
m_list.MoveWindow(rectList.left, rectList.top, rectList.right - rectList.left, rectList.bottom - rectList.top, TRUE);
}
else
{
// Here's the case where the coordinates are right to left.
rectList.right = m_rectLastSplitter.right;
rectTree.left = m_rectLastSplitter.left;
// Move the tree and list controls based on the new rects.
m_tree.MoveWindow(rectTree.right, rectTree.top, rectTree.left - rectTree.right, rectTree.bottom - rectTree.top, TRUE);
m_list.MoveWindow(rectList.right, rectList.top, rectList.left - rectList.right, rectList.bottom - rectList.top, TRUE);
}
// If we're currently showing a category from a 4.10 NFO file, resize the OCX.
CMSInfoCategory * pCategory = GetCurrentCategory();
if (pCategory && pCategory->GetDataSourceType() == NFO_410)
{
CMSInfo4Category * p4Cat = (CMSInfo4Category*) pCategory;
p4Cat->ResizeControl(this->GetOCXRect());
}
// If nothing data is showing and there is a message string, invalidate the window so
// that it redraws based on the new rect.
if (!m_list.IsWindowVisible() && (!m_strMessTitle.IsEmpty() || !m_strMessText.IsEmpty()))
{
RECT rectNewList;
m_list.GetWindowRect(&rectNewList);
ScreenToClient(&rectNewList);
InvalidateRect(&rectNewList, TRUE);
}
// Figure the size ratio between the list view and tree view, and save it. Take into account
// that the left coordinate might be greater than the right coordinate on a rect (if the
// coordinates are from a RTL locale).
RECT rectClient;
GetClientRect(&rectClient);
if (rectTree.right > rectTree.left)
m_iTreeRatio = ((rectTree.right - rectTree.left) * 100) / (rectClient.right - rectClient.left);
else if (rectTree.right < rectTree.left)
m_iTreeRatio = ((rectTree.left - rectTree.right) * 100) / (rectClient.right - rectClient.left);
else
m_iTreeRatio = 100;
// Update the splitter tracking variables.
m_fTrackingSplitter = FALSE;
::CopyRect(&m_rectSplitter, &m_rectLastSplitter);
// Invalidate the splitter itself (so that it will repaint).
InvalidateRect(&m_rectSplitter);
// Release the mouse capture and restore the cursor.
ReleaseCapture();
m_fMouseCapturedForSplitter = FALSE;
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
}
//=========================================================================
// Rendering functions, including handling the WM_PAINT message.
//=========================================================================
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// We're having some redraw issues when brought back from a locked
// system. It seems that even though the updated rect is the same
// as the client rect, it doesn't include all the necessary regions
// to repaint.
RECT rectUpdate, rectClient;
if (GetClientRect(&rectClient) && GetUpdateRect(&rectUpdate) && ::EqualRect(&rectClient, &rectUpdate))
Invalidate(FALSE);
PAINTSTRUCT ps;
HDC hdc = BeginPaint(&ps);
GetClientRect(&rectClient);
::SetTextColor(hdc, ::GetSysColor(COLOR_BTNFACE));
if (m_fFirstPaint)
{
m_hbrBackground = CreateSolidBrush(::GetSysColor(COLOR_BTNFACE /* COLOR_MENU */));
if (!m_fDoNotRun)
SetMenuItems();
m_fFirstPaint = FALSE;
}
FillRect(hdc, &rectClient, m_hbrBackground);
if (m_fDoNotRun)
{
if (m_strDoNotRun.IsEmpty())
{
::AfxSetResourceHandle(_Module.GetResourceInstance());
m_strDoNotRun.LoadString(IDS_ONLYINHELPCTR);
}
CDC dc;
dc.Attach(hdc);
dc.SetBkMode(TRANSPARENT);
dc.DrawText(m_strDoNotRun, &rectClient, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
dc.Detach();
EndPaint(&ps);
return 0;
}
if (!m_list.IsWindowVisible())
{
RECT rectList;
m_list.GetWindowRect(&rectList);
ScreenToClient(&rectList);
// If the list window is hidden, we should probably be displaying a message. First,
// draw the 3D rectangle.
CDC dc;
dc.Attach(hdc);
dc.Draw3dRect(&rectList, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DHILIGHT));
// For some reason, DrawText wants left < right (even on RTL systems, like ARA).
if (rectList.left > rectList.right)
{
int iSwap = rectList.left;
rectList.left = rectList.right;
rectList.right = iSwap;
}
// Next, if there is text, draw it.
if (!m_strMessTitle.IsEmpty() || !m_strMessText.IsEmpty())
{
::InflateRect(&rectList, -10, -10);
CGdiObject * pFontOld = dc.SelectStockObject(DEFAULT_GUI_FONT);
COLORREF crTextOld = dc.SetTextColor(::GetSysColor(COLOR_MENUTEXT));
int nBkModeOld = dc.SetBkMode(TRANSPARENT);
if (!m_strMessTitle.IsEmpty())
{
// We want to make a bigger version of the same font. Select the font
// again (to get a pointer to the original font). Get it's LOGFONT,
// make it bigger, and create a new font for selection.
CFont * pNormalFont = (CFont *) dc.SelectStockObject(DEFAULT_GUI_FONT);
LOGFONT lf;
pNormalFont->GetLogFont(&lf);
lf.lfHeight = (lf.lfHeight * 3) / 2;
lf.lfWeight = FW_BOLD;
CFont fontDoubleSize;
fontDoubleSize.CreateFontIndirect(&lf);
dc.SelectObject(&fontDoubleSize);
RECT rectTemp;
::CopyRect(&rectTemp, &rectList);
int iHeight = dc.DrawText(m_strMessTitle, &rectTemp, DT_LEFT | DT_TOP | DT_WORDBREAK | DT_CALCRECT);
dc.DrawText(m_strMessTitle, &rectList, DT_LEFT | DT_TOP | DT_WORDBREAK);
rectList.top += iHeight + 5;
dc.SelectObject(pNormalFont);
}
if (!m_strMessText.IsEmpty())
{
dc.DrawText(m_strMessText, &rectList, DT_LEFT | DT_TOP | DT_WORDBREAK);
}
dc.SelectObject(pFontOld);
dc.SetTextColor(crTextOld);
dc.SetBkMode(nBkModeOld);
}
dc.Detach();
}
EndPaint(&ps);
return 0;
}
LRESULT OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_fFirstPaint = TRUE;
Invalidate();
UpdateWindow();
return 0;
}
LRESULT OnDialogColor(UINT, WPARAM w, LPARAM, BOOL&)
{
HDC dc = (HDC) w;
LOGBRUSH lb;
::GetObject(m_hbrBackground, sizeof(lb), (void*)&lb);
::SetBkColor(dc, lb.lbColor);
::SetTextColor(dc, ::GetSysColor(COLOR_BTNTEXT));
::SetBkMode(dc, TRANSPARENT);
return (LRESULT)m_hbrBackground;
}
//=========================================================================
// Handle the WM_SIZE message. This involves a bit of cleverness to avoid
// ugly updates: if the user has moved the splitter bar, preserve
// the ratio of sizes to the two windows.
//=========================================================================
LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_fDoNotRun)
{
RECT rectClient;
GetClientRect(&rectClient);
InvalidateRect(&rectClient, FALSE);
return 0;
}
LayoutControl();
return 0;
}
void LayoutControl()
{
const int cBorder = 3;
const int cxSplitter = 3;
RECT rectClient;
GetClientRect(&rectClient);
int cyMenuHeight = cBorder;
int cyFindControlHeight = PositionFindControls();
if (m_history.IsWindowVisible())
{
CRect rectHistory, rectHistorylabel;
m_history.GetWindowRect(&rectHistory);
m_historylabel.GetWindowRect(&rectHistorylabel);
rectHistory.OffsetRect(rectClient.right - cBorder - rectHistory.right, rectClient.top + cBorder - rectHistory.top);
rectHistorylabel.OffsetRect(rectHistory.left - cBorder / 2 - rectHistorylabel.right, rectClient.top + cBorder + ((rectHistory.Height() - rectHistorylabel.Height()) / 2) - rectHistorylabel.top);
if (rectHistorylabel.left < 0) // TBD
{
rectHistory += CPoint(0 - rectHistorylabel.left, 0);
rectHistorylabel += CPoint(0 - rectHistorylabel.left, 0);
}
m_history.MoveWindow(&rectHistory);
m_historylabel.MoveWindow(&rectHistorylabel);
if (rectHistory.Height() + cBorder * 2 > cyMenuHeight)
{
cyMenuHeight = rectHistory.Height() + cBorder * 2 - 1;
CPoint ptMenu(cBorder, (cyMenuHeight - 0) / 2 + 2);
}
}
else
{
CPoint ptMenu(5, 5);
}
RECT rectTree;
::CopyRect(&rectTree, &rectClient);
rectTree.left += cBorder;
rectTree.top += cyMenuHeight + cxSplitter / 2;
rectTree.bottom -= ((cyFindControlHeight) ? cyFindControlHeight : cBorder);
rectTree.right = ((rectClient.right - rectClient.left) * m_iTreeRatio) / 100 + rectClient.left;
m_tree.MoveWindow(rectTree.left, rectTree.top, rectTree.right - rectTree.left, rectTree.bottom - rectTree.top, FALSE);
RECT rectList;
::CopyRect(&rectList, &rectClient);
rectList.left = rectTree.right + cxSplitter;
rectList.top = rectTree.top;
rectList.bottom = rectTree.bottom;
rectList.right -= cBorder;
m_list.MoveWindow(rectList.left, rectList.top, rectList.right - rectList.left, rectList.bottom - rectList.top, FALSE);
// Get the rectangle for the splitter, and save it.
m_tree.GetWindowRect(&rectTree);
m_list.GetWindowRect(&rectList);
ScreenToClient(&rectTree);
ScreenToClient(&rectList);
// Check whether the coordinate system is LTR (eg. English) or RTL.
if (rectTree.left < rectTree.right || (rectTree.left == rectTree.right && rectList.left < rectList.right))
{
// Nominal (LTR) case.
int cxLeft = (rectTree.right < rectList.left) ? rectTree.right : rectList.left - cxSplitter;
::SetRect(&m_rectSplitter, cxLeft, rectTree.top, cxLeft + cxSplitter, rectTree.bottom);
}
else
{
// Special case for RTL locales.
int cxLeft = (rectTree.left < rectList.right) ? rectList.right : rectTree.left - cxSplitter;
::SetRect(&m_rectSplitter, cxLeft - cxSplitter, rectTree.top, cxLeft, rectTree.bottom);
}
CMSInfoCategory * pCategory = GetCurrentCategory();
if (pCategory && pCategory->GetDataSourceType() == NFO_410)
{
CMSInfo4Category * p4Cat = (CMSInfo4Category*) pCategory;
p4Cat->ResizeControl(this->GetOCXRect());
}
InvalidateRect(&rectClient, FALSE);
}
//=========================================================================
// Respond to the user clicking the tree or list.
//=========================================================================
LRESULT OnSelChangedTree(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW) pnmh;
if (lpnmtv)
{
CMSInfoCategory * pCategory = (CMSInfoCategory *) lpnmtv->itemNew.lParam;
ASSERT(pCategory);
if (pCategory)
{
CancelFind();
SelectCategory(pCategory);
}
}
return 0;
}
LRESULT OnColumnClick(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
LPNMLISTVIEW pnmv = (LPNMLISTVIEW) pnmh;
CMSInfoCategory * pCategory = GetCurrentCategory();
if (pnmv && pCategory)
{
BOOL fSorts, fLexical;
// Get the internal column number (in BASIC view, this might be different
// than the column indicated.
int iCol;
if (m_fAdvanced)
iCol = pnmv->iSubItem;
else
{
ASSERT(pnmv->iSubItem < m_iCategoryColNumberLen);
if (pnmv->iSubItem >= m_iCategoryColNumberLen)
return 0;
iCol = m_aiCategoryColNumber[pnmv->iSubItem];
}
if (pCategory->GetColumnInfo(iCol, NULL, NULL, &fSorts, &fLexical))
{
if (!fSorts)
return 0;
if (iCol == pCategory->m_iSortColumn)
pCategory->m_fSortAscending = !pCategory->m_fSortAscending;
else
pCategory->m_fSortAscending = TRUE;
pCategory->m_iSortColumn = iCol;
pCategory->m_fSortLexical = fLexical;
CLiveDataSource * pLiveDataSource = NULL;
if (pCategory->GetDataSourceType() == LIVE_DATA)
pLiveDataSource = (CLiveDataSource *) m_pCurrData;
if (pLiveDataSource)
pLiveDataSource->LockData();
ListView_SortItems(m_list.m_hWnd, (PFNLVCOMPARE) ListSortFunc, (LPARAM) pCategory);
if (pLiveDataSource)
pLiveDataSource->UnlockData();
}
}
return 0;
}
LRESULT OnListItemChanged(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
SetMenuItems();
return 0;
}
//-------------------------------------------------------------------------
// Don't allow the user to collapse the root node of the tree.
//-------------------------------------------------------------------------
LRESULT OnItemExpandingTree(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW) pnmh;
if (lpnmtv && (lpnmtv->action & TVE_COLLAPSE))
{
CMSInfoCategory * pCategory = (CMSInfoCategory *) lpnmtv->itemNew.lParam;
if (pCategory && pCategory->GetParent() == NULL)
return 1;
}
return 0;
}
//=========================================================================
// Called when we're being notified by the worker thread that a refresh
// is complete and data should be displayed.
//
// TBD - check whether is category is still selected
//=========================================================================
LRESULT OnMSInfoDataReady(UINT /* uMsg */, WPARAM /* wParam */, LPARAM lParam, BOOL& /* bHandled */)
{
if (m_fDoNotRun)
return 0;
ASSERT(lParam);
if (lParam == 0)
return 0;
if (m_fInFind && lParam == (LPARAM)m_pcatFind)
{
FindRefreshComplete();
return 0;
}
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))
if (tvi.lParam == lParam)
{
CMSInfoCategory * pCategory = (CMSInfoCategory *) lParam;
ASSERT(pCategory->GetDataSourceType() == LIVE_DATA);
SelectCategory(pCategory, TRUE);
}
}
return 0;
}
//=========================================================================
// Functions for managing the list view and the tree view. Note - the
// dwItem can only be set for the row (when iCol == 0).
//=========================================================================
void ListInsertItem(int iRow, int iCol, LPCTSTR szItem, DWORD dwItem)
{
LVITEM lvi;
lvi.mask = LVIF_TEXT | ((iCol == 0) ? LVIF_PARAM : 0);
lvi.iItem = iRow;
lvi.iSubItem = iCol;
lvi.pszText = (LPTSTR) szItem;
lvi.lParam = (LPARAM) dwItem;
if (iCol == 0)
ListView_InsertItem(m_list.m_hWnd, &lvi);
else
ListView_SetItem(m_list.m_hWnd, &lvi);
}
void ListInsertColumn(int iCol, int cxWidth, LPCTSTR szCaption)
{
LVCOLUMN lvc;
lvc.mask = LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
lvc.cx = cxWidth;
lvc.pszText = (LPTSTR) szCaption;
lvc.iOrder = iCol;
ListView_InsertColumn(m_list.m_hWnd, iCol, &lvc);
}
void ListClearItems()
{
ListView_DeleteAllItems(m_list.m_hWnd);
}
void ListClearColumns()
{
while (ListView_DeleteColumn(m_list.m_hWnd, 0));
}
void TreeClearItems()
{
TreeView_DeleteAllItems(m_tree.m_hWnd);
}
HTREEITEM TreeInsertItem(HTREEITEM hParent, HTREEITEM hInsertAfter, LPTSTR szName, LPARAM lParam)
{
TVINSERTSTRUCT tvis;
tvis.hParent = hParent;
tvis.hInsertAfter = hInsertAfter;
tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
tvis.item.pszText = szName;
tvis.item.lParam = lParam;
return TreeView_InsertItem(m_tree.m_hWnd, &tvis);
}
void BuildTree(HTREEITEM htiParent, HTREEITEM htiPrevious, CMSInfoCategory * pCategory)
{
ASSERT(pCategory);
CString strCaption(_T(""));
// If the user specified the /showcategories flag, we should show the name of
// each category in the tree (which is unlocalized). Otherwise show the caption.
if (!m_fShowCategories)
pCategory->GetNames(&strCaption, NULL);
else
pCategory->GetNames(NULL, &strCaption);
if (pCategory->GetDataSourceType() == LIVE_DATA && htiParent == TVI_ROOT && !m_strMachine.IsEmpty() && pCategory != &catHistorySystemSummary)
{
CString strMachine(m_strMachine);
strMachine.MakeLower();
strMachine.TrimLeft(_T("\\"));
// Changed this to use a Format() with a string resource, instead of
// appending the machine name to the string. This should solve some
// problems with oddities on RTL languages.
strCaption.Format(IDS_SYSTEMSUMMARYMACHINENAME, strMachine);
}
HTREEITEM htiCategory = TreeInsertItem(htiParent, htiPrevious, (LPTSTR)(LPCTSTR)strCaption, (LPARAM)pCategory);
pCategory->SetHTREEITEM(htiCategory);
for (CMSInfoCategory * pChild = pCategory->GetFirstChild(); pChild; pChild = pChild->GetNextSibling())
BuildTree(htiCategory, TVI_LAST, pChild);
}
void RefillListView(BOOL fRefreshDataOnly = TRUE)
{
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))
if (tvi.lParam)
{
CMSInfoCategory * pCategory = (CMSInfoCategory *) tvi.lParam;
SelectCategory(pCategory, fRefreshDataOnly);
}
}
}
//=========================================================================
// If the user presses a key, we should check to see if it's something
// we need to deal with (accelerators, ALT-?, etc.).
//=========================================================================
HACCEL m_hAccTable;
STDMETHODIMP TranslateAccelerator(MSG * pMsg)
{
if (m_hwndParent && m_hAccTable && (GetAsyncKeyState(VK_CONTROL) < 0 || (WORD)pMsg->wParam == VK_F1) && ::TranslateAccelerator(m_hwndParent, m_hAccTable, pMsg))
return S_OK;
if (m_fFindVisible && (WORD)pMsg->wParam == VK_RETURN && pMsg->message != WM_KEYUP)
{
// If the focus is on the stop find button, do so.
if (GetFocus() == m_wndStopFind.m_hWnd || GetFocus() == m_wndCancelFind.m_hWnd)
{
BOOL bHandled;
OnStopFind(0, 0, NULL, bHandled);
return S_OK;
}
// Otherwise, if the find or find next button is showing, execute
// that command.
if (m_wndStartFind.IsWindowEnabled() || m_wndFindNext.IsWindowEnabled())
{
BOOL bHandled;
OnFind(0, 0, NULL, bHandled);
return S_OK;
}
}
return IOleInPlaceActiveObjectImpl<CMSInfo>::TranslateAccelerator(pMsg);
}
void MSInfoMessageBox(UINT uiMessageID, UINT uiTitleID = IDS_SYSTEMINFO)
{
CString strCaption, strMessage;
::AfxSetResourceHandle(_Module.GetResourceInstance());
strCaption.LoadString(uiTitleID);
strMessage.LoadString(uiMessageID);
MessageBox(strMessage, strCaption);
}
void MSInfoMessageBox(const CString & strMessage, UINT uiTitleID = IDS_SYSTEMINFO)
{
CString strCaption;
::AfxSetResourceHandle(_Module.GetResourceInstance());
strCaption.LoadString(uiTitleID);
MessageBox(strMessage, strCaption);
}
//=========================================================================
// Functions implemented in the CPP file.
//=========================================================================
BOOL DispatchCommand(int iCommand);
void SelectDataSource(CDataSource * pDataSource);
void SelectCategory(CMSInfoCategory * pCategory, BOOL fRefreshDataOnly = FALSE);
void MSInfoRefresh();
void OpenNFO();
void SaveNFO();
void Export();
void CloseFile();
void SaveMSInfoFile(LPCTSTR szFilename, DWORD dwFilterIndex = 1);//new format by default
HRESULT OpenMSInfoFile(LPCTSTR szFilename, int nFileExtension);
void ExportFile(LPCTSTR szFilename, int nFileExtension);
CMSInfoCategory * GetCurrentCategory();
void SetMenuItems();
void SetMessage(const CString & strTitle, const CString & strMessage = CString(_T("")), BOOL fRedraw = FALSE);
void SetMessage(UINT uiTitle, UINT uiMessage = 0, BOOL fRedraw = FALSE);
void EditCopy();
void EditSelectAll();
void DoPrint(BOOL fNoUI = FALSE);
void UpdateToolsMenu();
CRect GetOCXRect();
void CancelFind();
LRESULT OnStopFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
void UpdateFindControls();
LRESULT OnChangeFindWhat(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
LRESULT OnFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
void FindRefreshComplete();
BOOL FindInCurrentCategory();
void ShowFindControls();
int PositionFindControls();
void ShowRemoteDialog();
void DoRemote(LPCTSTR szMachine);
void SaveXML(const CString & strFileName);
void GetMachineName(LPTSTR lpBuffer, LPDWORD lpnSize);
void RefreshData(CLiveDataSource * pSource, CMSInfoLiveCategory * pLiveCategory);
//-------------------------------------------------------------------------
// Fill our combo box with the available history deltas.
//-------------------------------------------------------------------------
void FillHistoryCombo()
{
m_history.SendMessage(CB_RESETCONTENT, 0, 0);
CMSInfoCategory * pCategory = GetCurrentCategory();
if (pCategory == NULL || (pCategory->GetDataSourceType() != LIVE_DATA && pCategory->GetDataSourceType() != XML_SNAPSHOT))
return;
CLiveDataSource * pLiveSource = (CLiveDataSource *) m_pCurrData;
CStringList strlistDeltas;
CString strItem;
CDC dc;
CSize size;
int cxMaxWidth = 0;
HDC hdc = GetDC();
dc.Attach(hdc);
dc.SelectObject(CFont::FromHandle((HFONT)m_history.SendMessage(WM_GETFONT, 0, 0)));
if (pLiveSource->GetDeltaList(&strlistDeltas))
while (!strlistDeltas.IsEmpty())
{
strItem = strlistDeltas.RemoveHead();
m_history.SendMessage(CB_INSERTSTRING, -1, (LPARAM)(LPCTSTR)strItem);
size = dc.GetTextExtent(strItem);
if (size.cx > cxMaxWidth)
cxMaxWidth = size.cx;
}
//else
//TD: what if no history is available?
CRect rectClient, rectHistory;
GetClientRect(&rectClient);
m_history.GetWindowRect(&rectHistory);
if (cxMaxWidth > rectHistory.Width() && cxMaxWidth < rectClient.Width())
{
rectHistory.InflateRect((cxMaxWidth - (rectHistory.Width() - GetSystemMetrics(SM_CXHSCROLL))) / 2 + 5, 0);
m_history.MoveWindow(&rectHistory);
LayoutControl();
}
dc.Detach();
ReleaseDC(hdc);
}
//-------------------------------------------------------------------------
// If the user selects a history delta to view, we need to mark all of the
// categories as unrefreshed (so the new data will be generated).
//-------------------------------------------------------------------------
LRESULT OnHistorySelection(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
int iSelection = (int)m_history.SendMessage(CB_GETCURSEL, 0, 0);
#ifdef A_STEPHL
/* CString strMSG;
strMSG.Format("iSelection= %d",iSelection);
::MessageBox(NULL,strMSG,"",MB_OK);*/
#endif
if (iSelection == CB_ERR)
{
return 0;
}
ChangeHistoryView(iSelection);
return 0;
}
void ChangeHistoryView(int iIndex)
{
CMSInfoCategory * pCategory = GetCurrentCategory();
if (pCategory == NULL)
{
ASSERT(FALSE && "NULL pCategory");
return;
}
else if (pCategory->GetDataSourceType() == LIVE_DATA || pCategory->GetDataSourceType() == XML_SNAPSHOT)
{
pCategory->ResetCategory();
if (((CMSInfoHistoryCategory*) pCategory)->m_iDeltaIndex == iIndex)
{
// return;
}
CLiveDataSource * pLiveSource = (CLiveDataSource *) m_pCurrData;
if (pLiveSource->ShowDeltas(iIndex))
{
SetMessage(IDS_REFRESHHISTORYMESSAGE, 0, TRUE);
MSInfoRefresh();
#ifdef A_STEPHL
/* CString strMSG;
strMSG.Format("niIndex= %d",iIndex);
::MessageBox(NULL,strMSG,"",MB_OK);*/
#endif
}
else
{
// 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));
}
}
}
else
{
ASSERT(FALSE && "shouldn't be showing history dropdown with this data source");
return;
}
}
//-------------------------------------------------------------------------
// If the user sets the focus to the list, and there is no previously
// selected item, then select the first item in the list (so the user can
// see the focus).
//-------------------------------------------------------------------------
LRESULT OnSetFocusList(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
if (ListView_GetSelectedCount(m_list.m_hWnd) == 0)
ListView_SetItemState(m_list.m_hWnd, 0, LVIS_SELECTED, LVIS_SELECTED);
return 0;
}
//-------------------------------------------------------------------------
// If the hovers on a cell in the list view, show the contents
// of that cell as an infotip. This is helpful for extremely long items.
//-------------------------------------------------------------------------
LRESULT OnInfoTipList(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
TCHAR szBuf[MAX_PATH * 3] = _T("");
LPNMLVGETINFOTIP pGetInfoTip = (LPNMLVGETINFOTIP)pnmh;
if(NULL != pGetInfoTip)
{
ListView_GetItemText(m_list.m_hWnd, pGetInfoTip->iItem, pGetInfoTip->iSubItem, szBuf, MAX_PATH * 3);
pGetInfoTip->cchTextMax = _tcslen(szBuf);
pGetInfoTip->pszText = szBuf;
}
return 0;
}
//-------------------------------------------------------------------------
// Is the user right clicks on the tree, we should show a context menu
// with the "What's This?" item in it. If the user selects the menu
// item, we should launch help with the topic for the category.
//-------------------------------------------------------------------------
LRESULT OnRClickTree(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
{
// Determine if the right click was on a category in the tree view.
CMSInfoCategory * pCategory = NULL;
DWORD dwPoint = GetMessagePos();
TVHITTESTINFO tvhti;
tvhti.pt.x = ((int)(short)LOWORD(dwPoint));
tvhti.pt.y = ((int)(short)HIWORD(dwPoint));
::ScreenToClient(m_tree.m_hWnd, &tvhti.pt);
// If it's on a tree view item, get the category pointer.
HTREEITEM hti = TreeView_HitTest(m_tree.m_hWnd, &tvhti);
if (hti != NULL)
{
TVITEM tvi;
tvi.mask = TVIF_PARAM;
tvi.hItem = hti;
if (TreeView_GetItem(m_tree.m_hWnd, &tvi) && tvi.lParam)
pCategory = (CMSInfoCategory *) tvi.lParam;
}
if (pCategory != NULL)
{
const UINT uFlags = TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_RIGHTBUTTON;
::AfxSetResourceHandle(_Module.GetResourceInstance());
HMENU hmenu = ::LoadMenu(_Module.GetResourceInstance(), _T("IDR_WHAT_IS_THIS_MENU"));
HMENU hmenuSub = ::GetSubMenu(hmenu, 0);
if (hmenuSub)
if (::TrackPopupMenu(hmenuSub, uFlags, ((int)(short)LOWORD(dwPoint)), ((int)(short)HIWORD(dwPoint)), 0, m_hWnd, NULL))
ShowCategoryHelp(pCategory);
::DestroyMenu(hmenu);
}
return 0;
}
LRESULT OnClickedSearchSelected(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
if (IsDlgButtonChecked(IDC_CHECKSEARCHSELECTED) == BST_CHECKED)
CheckDlgButton(IDC_CHECKSEARCHCATSONLY, BST_UNCHECKED);
return 0;
}
LRESULT OnClickedSearchCatsOnly(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
if (IsDlgButtonChecked(IDC_CHECKSEARCHCATSONLY) == BST_CHECKED)
CheckDlgButton(IDC_CHECKSEARCHSELECTED, BST_UNCHECKED);
return 0;
}
//-------------------------------------------------------------------------
// Display the help file with the topic for the specified category shown.
// If the category doesn't have a topic, check its parent categories. If
// There are no topics all the way to the root, just show the help without
// a specific topic.
//-------------------------------------------------------------------------
void ShowCategoryHelp(CMSInfoCategory * pCategory)
{
CString strTopic(_T(""));
while (pCategory != NULL && strTopic.IsEmpty())
{
strTopic = pCategory->GetHelpTopic();
pCategory = pCategory->GetParent();
}
if (strTopic.IsEmpty())
::HtmlHelp(m_hWnd, _T("msinfo32.chm"), HH_DISPLAY_TOPIC, NULL);
else
::HtmlHelp(m_hWnd, _T("msinfo32.chm"), HH_DISPLAY_TOPIC, (DWORD_PTR)(LPCTSTR)strTopic);
}
//-------------------------------------------------------------------------
// If the user sets the focus to the edit control, we should turn on the
// copy command in the menu.
//-------------------------------------------------------------------------
LRESULT OnSetFocusEditFindWhat(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
SetMenuItems();
return 0;
}
LRESULT OnKillFocusEditFindWhat(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
if (m_fDoNotRun)
return 0;
SetMenuItems();
return 0;
}
};
#endif //__MSINFO_H_