|
|
// 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 BOOL FileExists(const CString & strFile); 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.
//
// This code is outdated - removing it (bug 577659),
//
// 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 using HelpCtr.exe
//-------------------------------------------------------------------------
void ShowHSCHelp(CString strTopic) { TCHAR szCommandLine[2000]; PROCESS_INFORMATION ProcessInfo; STARTUPINFO StartUpInfo;
TCHAR szWinDir[2048]; GetWindowsDirectory(szWinDir, 2048);
ZeroMemory((LPVOID)&StartUpInfo, sizeof(STARTUPINFO)); StartUpInfo.cb = sizeof(STARTUPINFO); CString strCommandLine(szWinDir); strCommandLine = CString(_T("\"")) + strCommandLine; strCommandLine += _T("\\pchealth\\helpctr\\binaries\\helpctr.exe\" -FromStartHelp -url \"hcp:"); strCommandLine += _T("//mk:@MSITStore:");
// Try to find a localized help file to open (bug 463878). It should be
// located in %windir%\help\mui\<LANGID>.
TCHAR szHelpPath[MAX_PATH] = _T(""); CString strLanguageIDPath; if (::ExpandEnvironmentStrings(_T("%SystemRoot%\\help\\mui"), szHelpPath, MAX_PATH)) { LANGID langid = GetUserDefaultUILanguage(); strLanguageIDPath.Format(_T("%s\\%04x\\msinfo32.chm"), szHelpPath, langid);
if (!FileExists(strLanguageIDPath)) { ::ExpandEnvironmentStrings(_T("%windir%\\help\\msinfo32.chm"), szHelpPath, MAX_PATH); strLanguageIDPath = szHelpPath; } } strCommandLine += strLanguageIDPath;
if (strTopic.IsEmpty()) { strTopic = _T("msinfo_overview.htm"); } strCommandLine += _T("::/"); strCommandLine += strTopic; strCommandLine += _T("\"");
// Replaces: wsprintf(szCommandLine,strCommandLine);
::ZeroMemory(szCommandLine, sizeof(szCommandLine)); _tcsncpy(szCommandLine, (LPCTSTR)strCommandLine, (sizeof(szCommandLine) / sizeof(TCHAR)) - 1); CreateProcess(NULL, szCommandLine,NULL,NULL,TRUE,CREATE_NEW_PROCESS_GROUP,NULL,&szWinDir[0],&StartUpInfo,&ProcessInfo); }
//-------------------------------------------------------------------------
// 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(); } ShowHSCHelp(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_
|