1881 lines
57 KiB
C
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_
|