Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1880 lines
57 KiB

  1. // MSInfo.h : Declaration of the CMSInfo
  2. #ifndef __MSINFO_H_
  3. #define __MSINFO_H_
  4. #include <commdlg.h>
  5. #include "resource.h" // main symbols
  6. #include <atlctl.h>
  7. #include "pseudomenu.h"
  8. #include "datasource.h"
  9. #include "category.h"
  10. #include "msinfotool.h"
  11. #include "msinfo4category.h"
  12. #include "htmlhelp.h"
  13. #include <afxdlgs.h>
  14. #include "dataset.h"
  15. //
  16. // From HelpServiceTypeLib.idl
  17. //
  18. #include <HelpServiceTypeLib.h>
  19. extern void StringReplace(CString & str, LPCTSTR szLookFor, LPCTSTR szReplaceWith);
  20. extern BOOL gfEndingSession;
  21. //v-stlowe History progress dialog
  22. //member variable of CMSInfo so it can be updated by CMSInfo::UpdateDCOProgress
  23. // CHistoryRefreshDlg dialog
  24. //=========================================================================
  25. //
  26. //=========================================================================
  27. #include "HistoryParser.h" // Added by ClassView
  28. #include <afxcmn.h>
  29. #include <afxmt.h>
  30. class CHistoryRefreshDlg : public CDialogImpl<CHistoryRefreshDlg>
  31. {
  32. public:
  33. enum { IDD = IDD_HISTORYREFRESHPROGRESS };
  34. CWindow m_wndProgressBar;
  35. BEGIN_MSG_MAP(CWaitForRefreshDialog)
  36. MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
  37. END_MSG_MAP()
  38. LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
  39. };
  40. /////////////////////////////////////////////////////////////////////////////
  41. // CMSInfo
  42. class ATL_NO_VTABLE CMSInfo :
  43. public CComObjectRootEx<CComSingleThreadModel>,
  44. public CStockPropImpl<CMSInfo, IMSInfo, &IID_IMSInfo, &LIBID_MSINFO32Lib>,
  45. public CComCompositeControl<CMSInfo>,
  46. public IPersistStreamInitImpl<CMSInfo>,
  47. public IOleControlImpl<CMSInfo>,
  48. public IOleObjectImpl<CMSInfo>,
  49. public IOleInPlaceActiveObjectImpl<CMSInfo>,
  50. public IViewObjectExImpl<CMSInfo>,
  51. public IOleInPlaceObjectWindowlessImpl<CMSInfo>,
  52. public IPersistStorageImpl<CMSInfo>,
  53. public ISpecifyPropertyPagesImpl<CMSInfo>,
  54. public IQuickActivateImpl<CMSInfo>,
  55. public IDataObjectImpl<CMSInfo>,
  56. public IProvideClassInfo2Impl<&CLSID_MSInfo, NULL, &LIBID_MSINFO32Lib>,
  57. public CComCoClass<CMSInfo, &CLSID_MSInfo>
  58. {
  59. public:
  60. CMSInfo() :m_fHistoryAvailable(FALSE),m_pCurrData(NULL),m_fHistorySaveAvailable(FALSE)
  61. {
  62. m_bWindowOnly = TRUE;
  63. CalcExtent(m_sizeExtent);
  64. //v-stlowe 2/23/01 synchronization for put_DCO_IUnknown
  65. m_evtControlInit = CreateEvent(NULL,TRUE,FALSE,CString(_T("MSInfoControlInitialized")));
  66. //create history event, to signal when DCO has finished.
  67. m_hEvtHistoryComplete = CreateEvent(NULL,TRUE,FALSE,CString(_T("MSInfoHistoryDone")));
  68. }
  69. DECLARE_REGISTRY_RESOURCEID(IDR_MSINFO)
  70. DECLARE_PROTECT_FINAL_CONSTRUCT()
  71. BEGIN_COM_MAP(CMSInfo)
  72. COM_INTERFACE_ENTRY(IMSInfo)
  73. COM_INTERFACE_ENTRY(IDispatch)
  74. COM_INTERFACE_ENTRY(IViewObjectEx)
  75. COM_INTERFACE_ENTRY(IViewObject2)
  76. COM_INTERFACE_ENTRY(IViewObject)
  77. COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
  78. COM_INTERFACE_ENTRY(IOleInPlaceObject)
  79. COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
  80. COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
  81. COM_INTERFACE_ENTRY(IOleControl)
  82. COM_INTERFACE_ENTRY(IOleObject)
  83. COM_INTERFACE_ENTRY(IPersistStreamInit)
  84. COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
  85. COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
  86. COM_INTERFACE_ENTRY(IQuickActivate)
  87. COM_INTERFACE_ENTRY(IPersistStorage)
  88. COM_INTERFACE_ENTRY(IDataObject)
  89. COM_INTERFACE_ENTRY(IProvideClassInfo)
  90. COM_INTERFACE_ENTRY(IProvideClassInfo2)
  91. END_COM_MAP()
  92. BEGIN_PROP_MAP(CMSInfo)
  93. PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
  94. PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
  95. PROP_ENTRY("Appearance", DISPID_APPEARANCE, CLSID_NULL)
  96. PROP_ENTRY("AutoSize", DISPID_AUTOSIZE, CLSID_NULL)
  97. PROP_ENTRY("BackColor", DISPID_BACKCOLOR, CLSID_StockColorPage)
  98. PROP_ENTRY("BackStyle", DISPID_BACKSTYLE, CLSID_NULL)
  99. PROP_ENTRY("BorderColor", DISPID_BORDERCOLOR, CLSID_StockColorPage)
  100. PROP_ENTRY("BorderStyle", DISPID_BORDERSTYLE, CLSID_NULL)
  101. PROP_ENTRY("BorderVisible", DISPID_BORDERVISIBLE, CLSID_NULL)
  102. PROP_ENTRY("BorderWidth", DISPID_BORDERWIDTH, CLSID_NULL)
  103. PROP_ENTRY("Font", DISPID_FONT, CLSID_StockFontPage)
  104. PROP_ENTRY("ForeColor", DISPID_FORECOLOR, CLSID_StockColorPage)
  105. PROP_ENTRY("HWND", DISPID_HWND, CLSID_NULL)
  106. // Example entries
  107. // PROP_ENTRY("Property Description", dispid, clsid)
  108. // PROP_PAGE(CLSID_StockColorPage)
  109. END_PROP_MAP()
  110. BEGIN_MSG_MAP(CMSInfo)
  111. MESSAGE_HANDLER(WM_CTLCOLORDLG, OnDialogColor)
  112. MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnDialogColor)
  113. CHAIN_MSG_MAP(CComCompositeControl<CMSInfo>)
  114. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  115. MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
  116. MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  117. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  118. MESSAGE_HANDLER(WM_SIZE, OnSize)
  119. MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
  120. MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP)
  121. MESSAGE_HANDLER(WM_MSINFODATAREADY, OnMSInfoDataReady)
  122. NOTIFY_HANDLER(IDC_TREE, TVN_SELCHANGED, OnSelChangedTree)
  123. NOTIFY_HANDLER(IDC_LIST, LVN_COLUMNCLICK, OnColumnClick)
  124. NOTIFY_HANDLER(IDC_LIST, LVN_ITEMCHANGED, OnListItemChanged)
  125. NOTIFY_HANDLER(IDC_TREE, TVN_ITEMEXPANDING, OnItemExpandingTree)
  126. COMMAND_HANDLER(IDSTOPFIND, BN_CLICKED, OnStopFind)
  127. COMMAND_HANDLER(IDCANCELFIND, BN_CLICKED, OnStopFind)
  128. COMMAND_HANDLER(IDC_EDITFINDWHAT, EN_CHANGE, OnChangeFindWhat)
  129. COMMAND_HANDLER(IDSTARTFIND, BN_CLICKED, OnFind)
  130. COMMAND_HANDLER(IDFINDNEXT, BN_CLICKED, OnFind)
  131. COMMAND_HANDLER(IDC_HISTORYCOMBO, CBN_SELCHANGE, OnHistorySelection)
  132. COMMAND_HANDLER(IDC_CHECKSEARCHSELECTED, BN_CLICKED, OnClickedSearchSelected)
  133. COMMAND_HANDLER(IDC_CHECKSEARCHCATSONLY, BN_CLICKED, OnClickedSearchCatsOnly)
  134. MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange)
  135. NOTIFY_HANDLER(IDC_LIST, NM_SETFOCUS, OnSetFocusList)
  136. NOTIFY_HANDLER(IDC_LIST, LVN_GETINFOTIP, OnInfoTipList)
  137. NOTIFY_HANDLER(IDC_TREE, NM_RCLICK, OnRClickTree)
  138. COMMAND_HANDLER(IDC_EDITFINDWHAT, EN_SETFOCUS, OnSetFocusEditFindWhat)
  139. COMMAND_HANDLER(IDC_EDITFINDWHAT, EN_KILLFOCUS, OnKillFocusEditFindWhat)
  140. END_MSG_MAP()
  141. // Handler prototypes:
  142. // LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
  143. // LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
  144. // LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
  145. BEGIN_SINK_MAP(CMSInfo)
  146. //Make sure the Event Handlers have __stdcall calling convention
  147. END_SINK_MAP()
  148. STDMETHOD(OnAmbientPropertyChange)(DISPID dispid)
  149. {
  150. if (dispid == DISPID_AMBIENT_BACKCOLOR)
  151. {
  152. // Don't respond to ambient color changes (yet).
  153. //
  154. // SetBackgroundColorFromAmbient();
  155. // FireViewChange();
  156. }
  157. return IOleControlImpl<CMSInfo>::OnAmbientPropertyChange(dispid);
  158. }
  159. // IViewObjectEx
  160. DECLARE_VIEW_STATUS(0)
  161. // IMSInfo
  162. public:
  163. STDMETHOD(SaveFile)(BSTR filename, BSTR computer, BSTR category);
  164. STDMETHOD(get_DCO_IUnknown)(/*[out, retval]*/ IUnknown* *pVal);
  165. STDMETHOD(put_DCO_IUnknown)(/*[in]*/ IUnknown* newVal);
  166. STDMETHOD(SetHistoryStream)(IStream * pStream);
  167. STDMETHOD(UpdateDCOProgress)(VARIANT nPctDone);
  168. //=========================================================================
  169. // Member variables generated by the wizard.
  170. //=========================================================================
  171. //v-stlowe 2/23/2001
  172. CHistoryRefreshDlg m_HistoryProgressDlg;
  173. //v-stlowe 2/27/2001 - filename needed when loading XML files,
  174. //and switching between snapshot and history view
  175. CString m_strFileName;
  176. short m_nAppearance;
  177. OLE_COLOR m_clrBackColor;
  178. LONG m_nBackStyle;
  179. OLE_COLOR m_clrBorderColor;
  180. LONG m_nBorderStyle;
  181. BOOL m_bBorderVisible;
  182. LONG m_nBorderWidth;
  183. CComPtr<IFontDisp> m_pFont;
  184. OLE_COLOR m_clrForeColor;
  185. //v-stlowe 2/23/01 synchronization for put_DCO_IUnknown
  186. HANDLE m_evtControlInit;
  187. //v-stlowe 2/24/01 synchronization for History DCO progress dlg, so it can be destroyed
  188. //even if DCO never returns from collecting history
  189. HANDLE m_hEvtHistoryComplete;
  190. UINT HistoryRefreshDlgDlgThreadProc(LPVOID pParamNotUsed );
  191. enum { IDD = IDD_MSINFO };
  192. //=========================================================================
  193. // MSInfo member variables (initialized in OnInitDialog()).
  194. //=========================================================================
  195. BOOL m_fDoNotRun; // if this is TRUE, don't allow the control to do anything
  196. CString m_strDoNotRun; // message to display if we don't run
  197. CString m_strMachine; // if empty, local machine, otherwise network name
  198. CWindow m_tree; // set to refer to the tree view
  199. CWindow m_list; // set to refer to the list view
  200. int m_iTreeRatio; // the tree is x% the size of the list view
  201. BOOL m_fFirstPaint; // flag so we can initialize some paint things, once
  202. CDataSource * m_pLiveData; // data source for current data from WMI
  203. CDataSource * m_pFileData; // data source for an open NFO, XML snapshot
  204. CDataSource * m_pCurrData; // copy of one of the previous two (don't need to delete this)
  205. CMSInfoCategory * m_pCategory; // currently selected category
  206. BOOL m_fMouseCapturedForSplitter; // mouse currently being looked at by splitter
  207. BOOL m_fTrackingSplitter; // does the user have the LBUTTON down, resizing panes
  208. RECT m_rectSplitter; // current splitter rect (for hit tests)
  209. RECT m_rectLastSplitter; // last rect in DrawFocusRect
  210. int m_cxOffset; // offset from mouse position to left side of splitter
  211. BOOL m_fAdvanced; // currently showing advanced data?
  212. CString m_strMessTitle; // title for message to display in results
  213. CString m_strMessText; // text for message to display in results
  214. BOOL m_fNoUI; // true if doing a silent save
  215. int m_aiCategoryColNumber[64]; // contains category column for each list view column
  216. int m_iCategoryColNumberLen;
  217. CMapWordToPtr m_mapIDToTool; // a map from menu ID to a CMSInfoTool pointer
  218. TCHAR m_szCurrentDir[MAX_PATH]; // current directory when control starts (should restore)
  219. // Find member variables.
  220. BOOL m_fFindVisible; // are the find controls visible?
  221. CWindow m_wndFindWhatLabel; // windows for the various find controls
  222. CWindow m_wndFindWhat;
  223. CWindow m_wndSearchSelected;
  224. CWindow m_wndSearchCategories;
  225. CWindow m_wndStartFind;
  226. CWindow m_wndStopFind;
  227. CWindow m_wndFindNext;
  228. CWindow m_wndCancelFind;
  229. BOOL m_fInFind;
  230. BOOL m_fCancelFind;
  231. BOOL m_fFindNext;
  232. BOOL m_fSearchCatNamesOnly;
  233. BOOL m_fSearchSelectedCatOnly;
  234. CString m_strFind;
  235. CMSInfoCategory * m_pcatFind;
  236. int m_iFindLine;
  237. // History member variables.
  238. CWindow m_history;
  239. CWindow m_historylabel;
  240. BOOL m_fHistoryAvailable;
  241. BOOL m_fHistorySaveAvailable;
  242. CMSInfoCategory * m_pLastCurrentCategory;
  243. CComPtr<ISAFDataCollection> m_pDCO;
  244. CComPtr<IStream> m_pHistoryStream;
  245. // Member variables set from the command line parameters.
  246. CString m_strOpenFile;
  247. CString m_strPrintFile;
  248. CString m_strCategory;
  249. CString m_strCategories;
  250. CString m_strComputer;
  251. BOOL m_fShowPCH;
  252. BOOL m_fShowCategories;
  253. //=========================================================================
  254. // A member variable and a function to hook into the windows procedure
  255. // of the parent window of the control (so we can put a menu on it).
  256. //=========================================================================
  257. HMENU m_hmenu;
  258. HWND m_hwndParent;
  259. static CMSInfo * m_pControl;
  260. static WNDPROC m_wndprocParent;
  261. static LRESULT CALLBACK MenuWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  262. {
  263. if (uMsg == WM_COMMAND && m_pControl && m_pControl->DispatchCommand(LOWORD(wParam)))
  264. return 0;
  265. // We want to know if the session is ending (so we can set the timeout for
  266. // waiting for WMI to finish to something smaller).
  267. if (uMsg == WM_ENDSESSION || uMsg == WM_QUERYENDSESSION)
  268. gfEndingSession = TRUE;
  269. return CallWindowProc(m_wndprocParent, hwnd, uMsg, wParam, lParam);
  270. }
  271. //=========================================================================
  272. // Functions for initializing and destroying the dialog. A good place to
  273. // initialize variables and free memory.
  274. //=========================================================================
  275. LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  276. {
  277. m_list.Attach(GetDlgItem(IDC_LIST));
  278. m_tree.Attach(GetDlgItem(IDC_TREE));
  279. m_history.Attach(GetDlgItem(IDC_HISTORYCOMBO));
  280. m_historylabel.Attach(GetDlgItem(IDC_HISTORYLABEL));
  281. // Determine if we are being loaded from within Help Center. Do this
  282. // by getting IOleContainer, which gives us IHTMLDocument2, which will
  283. // give us the URL loading us.
  284. m_fDoNotRun = TRUE;
  285. m_strDoNotRun.Empty();
  286. CString strParams;
  287. CComPtr<IOleContainer> spContainer;
  288. m_spClientSite->GetContainer(&spContainer);
  289. CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> spHTMLDocument(spContainer);
  290. if (spHTMLDocument)
  291. {
  292. CComBSTR bstrURL;
  293. if (SUCCEEDED(spHTMLDocument->get_URL(&bstrURL)))
  294. {
  295. CComBSTR bstrEscapedUrl(bstrURL);
  296. USES_CONVERSION;
  297. if(SUCCEEDED(UrlUnescape(OLE2T(bstrEscapedUrl), NULL, NULL, URL_UNESCAPE_INPLACE)))
  298. bstrURL = bstrEscapedUrl;
  299. bstrEscapedUrl.Empty();
  300. CString strURL(bstrURL);
  301. int iQuestionMark = strURL.Find(_T("?"));
  302. if (iQuestionMark != -1)
  303. strParams = strURL.Mid(iQuestionMark + 1);
  304. strURL.MakeLower();
  305. if (strURL.Left(4) == CString(_T("hcp:")))
  306. m_fDoNotRun = FALSE;
  307. // Include the following when we want to test the control
  308. // using a local URL.
  309. #ifdef MSINFO_TEST_WORKFROMLOCALURLS
  310. if (strURL.Left(5) == CString(_T("file:")))
  311. m_fDoNotRun = FALSE;
  312. #endif
  313. }
  314. }
  315. if (m_fDoNotRun)
  316. {
  317. m_list.ShowWindow(SW_HIDE);
  318. m_tree.ShowWindow(SW_HIDE);
  319. return 0;
  320. }
  321. ::GetCurrentDirectory(MAX_PATH, m_szCurrentDir);
  322. m_strMachine.Empty();
  323. m_fNoUI = FALSE;
  324. // Find the parent window for MSInfo. We want to add a menu bar to it.
  325. // We find the window by walking up the chain of parents until we get
  326. // to one with a caption. That window must also be top level (no parent),
  327. // and must not already have a menu.
  328. TCHAR szBuff[MAX_PATH];
  329. HWND hwnd = this->m_hWnd;
  330. m_hmenu = NULL;
  331. m_hwndParent = NULL;
  332. m_wndprocParent = NULL;
  333. while (hwnd != NULL)
  334. {
  335. if (::GetWindowText(hwnd, szBuff, MAX_PATH) && NULL == ::GetParent(hwnd) && NULL == ::GetMenu(hwnd))
  336. {
  337. // Update the window title. [This is done by the msinfo.xml file now.]
  338. //
  339. // CString strNewCaption;
  340. // ::AfxSetResourceHandle(_Module.GetResourceInstance());
  341. // strNewCaption.LoadString(IDS_SYSTEMINFO);
  342. // ::SetWindowText(hwnd, strNewCaption);
  343. // We've found the window. Load the menu bar for it.
  344. m_hmenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MENUBAR));
  345. if (m_hmenu)
  346. {
  347. ::SetMenu(hwnd, m_hmenu);
  348. // To catch the commands from the menu, we need to replace that
  349. // window's WndProc with our own. Ours will catch and menu command
  350. // that we implement, and pass the rest of the messages along.
  351. m_wndprocParent = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC);
  352. ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (ULONG_PTR)(WNDPROC)&MenuWndProc);
  353. m_pControl = this; // set a static member variable so the MenuWndProc can access it
  354. m_hwndParent = hwnd;
  355. }
  356. break;
  357. }
  358. hwnd = ::GetParent(hwnd);
  359. }
  360. m_fFirstPaint = TRUE;
  361. ListView_SetExtendedListViewStyle(m_list.m_hWnd, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
  362. m_strMessTitle.Empty();
  363. m_strMessText.Empty();
  364. m_fMouseCapturedForSplitter = FALSE;
  365. m_fTrackingSplitter = FALSE;
  366. ::SetRect(&m_rectSplitter, 0, 0, 0, 0);
  367. m_iTreeRatio = 33;
  368. // Set the history state variables (including whether or not history is available,
  369. // based on the presence of the DCO).
  370. #ifdef MSINFO_TEST_HISTORYFROMFILE
  371. m_fHistoryAvailable = TRUE;
  372. #else
  373. // m_fHistoryAvailable = (m_pDCO != NULL);
  374. #endif
  375. m_pLastCurrentCategory = NULL;
  376. // Removing the Advanced/Basic view menu items (Whistler 207638). Should
  377. // always default to Advanced now.
  378. m_fAdvanced = TRUE; // was FALSE;
  379. m_fFindVisible = TRUE; // used to be FALSE, before we decided to show find on startup
  380. m_wndFindWhatLabel.Attach(GetDlgItem(IDC_FINDWHATLABEL));
  381. m_wndFindWhat.Attach(GetDlgItem(IDC_EDITFINDWHAT));
  382. m_wndSearchSelected.Attach(GetDlgItem(IDC_CHECKSEARCHSELECTED));
  383. m_wndSearchCategories.Attach(GetDlgItem(IDC_CHECKSEARCHCATSONLY));
  384. // We need to set the event mask for the rich edit control
  385. // so we get EN_CHANGE notifications.
  386. m_wndFindWhat.SendMessage(EM_SETEVENTMASK, 0, (LPARAM)ENM_CHANGE);
  387. m_wndFindWhat.SendMessage(EM_SETTEXTMODE, TM_PLAINTEXT, 0);
  388. m_wndStartFind.Attach(GetDlgItem(IDSTARTFIND));
  389. m_wndStopFind.Attach(GetDlgItem(IDSTOPFIND));
  390. m_wndFindNext.Attach(GetDlgItem(IDFINDNEXT));
  391. m_wndCancelFind.Attach(GetDlgItem(IDCANCELFIND));
  392. // The pairs (start & find next, stop & cancel find) need to be matched
  393. // in size. The heights should already be the same.
  394. CRect rectStart, rectNext, rectStop, rectCancel;
  395. m_wndStartFind.GetWindowRect(&rectStart);
  396. m_wndFindNext.GetWindowRect(&rectNext);
  397. m_wndStopFind.GetWindowRect(&rectStop);
  398. m_wndCancelFind.GetWindowRect(&rectCancel);
  399. if (rectStart.Width() > rectNext.Width())
  400. rectNext = rectStart;
  401. else
  402. rectStart = rectNext;
  403. if (rectStop.Width() > rectCancel.Width())
  404. rectCancel = rectStop;
  405. else
  406. rectStop = rectCancel;
  407. m_wndStartFind.MoveWindow(&rectStart);
  408. m_wndFindNext.MoveWindow(&rectNext);
  409. m_wndStopFind.MoveWindow(&rectStop);
  410. m_wndCancelFind.MoveWindow(&rectCancel);
  411. // Initialize the find function member variables.
  412. m_fInFind = FALSE;
  413. m_fCancelFind = FALSE;
  414. m_fFindNext = FALSE;
  415. m_strFind = CString(_T(""));
  416. m_pcatFind = NULL;
  417. m_fSearchCatNamesOnly = FALSE;
  418. m_fSearchSelectedCatOnly = FALSE;
  419. // Show the appropriate find controls.
  420. ShowFindControls();
  421. UpdateFindControls();
  422. m_iCategoryColNumberLen = 0;
  423. // Parse the parameters out of the URL.
  424. m_strOpenFile = _T("");
  425. m_strPrintFile = _T("");
  426. m_strCategory = _T("");
  427. m_strComputer = _T("");
  428. m_strCategories = _T("");
  429. m_fShowCategories = FALSE;
  430. m_fShowPCH = FALSE;
  431. CString strTemp;
  432. while (!strParams.IsEmpty())
  433. {
  434. while (strParams[0] == _T(','))
  435. strParams = strParams.Mid(1);
  436. strTemp = strParams.SpanExcluding(_T(",="));
  437. if (strTemp.CompareNoCase(CString(_T("pch"))) == 0)
  438. {
  439. m_fShowPCH = TRUE;
  440. strParams = strParams.Mid(strTemp.GetLength());
  441. }
  442. else if (strTemp.CompareNoCase(CString(_T("showcategories"))) == 0)
  443. {
  444. m_fShowCategories = TRUE;
  445. strParams = strParams.Mid(strTemp.GetLength());
  446. }
  447. else if (strTemp.CompareNoCase(CString(_T("open"))) == 0)
  448. {
  449. strParams = strParams.Mid(strTemp.GetLength());
  450. if (strParams[0] == _T('='))
  451. strParams = strParams.Mid(1);
  452. m_strOpenFile = strParams.SpanExcluding(_T(","));
  453. strParams = strParams.Mid(m_strOpenFile.GetLength());
  454. }
  455. else if (strTemp.CompareNoCase(CString(_T("print"))) == 0)
  456. {
  457. strParams = strParams.Mid(strTemp.GetLength());
  458. if (strParams[0] == _T('='))
  459. strParams = strParams.Mid(1);
  460. m_strPrintFile = strParams.SpanExcluding(_T(","));
  461. strParams = strParams.Mid(m_strPrintFile.GetLength());
  462. }
  463. else if (strTemp.CompareNoCase(CString(_T("computer"))) == 0)
  464. {
  465. strParams = strParams.Mid(strTemp.GetLength());
  466. if (strParams[0] == _T('='))
  467. strParams = strParams.Mid(1);
  468. m_strComputer = strParams.SpanExcluding(_T(","));
  469. strParams = strParams.Mid(m_strComputer.GetLength());
  470. }
  471. else if (strTemp.CompareNoCase(CString(_T("category"))) == 0)
  472. {
  473. strParams = strParams.Mid(strTemp.GetLength());
  474. if (strParams[0] == _T('='))
  475. strParams = strParams.Mid(1);
  476. m_strCategory = strParams.SpanExcluding(_T(","));
  477. strParams = strParams.Mid(m_strCategory.GetLength());
  478. }
  479. else if (strTemp.CompareNoCase(CString(_T("categories"))) == 0)
  480. {
  481. strParams = strParams.Mid(strTemp.GetLength());
  482. if (strParams[0] == _T('='))
  483. strParams = strParams.Mid(1);
  484. m_strCategories = strParams.SpanExcluding(_T(","));
  485. strParams = strParams.Mid(m_strCategories.GetLength());
  486. }
  487. else
  488. strParams = strParams.Mid(strTemp.GetLength());
  489. }
  490. // Initialize the data sources.
  491. m_pLiveData = NULL;
  492. CLiveDataSource * pLiveData = new CLiveDataSource;
  493. if (pLiveData)
  494. {
  495. HRESULT hr = pLiveData->Create(_T(""), m_hWnd, m_strCategories); // create a data source for this machine
  496. if (FAILED(hr))
  497. {
  498. // bad news, report an error
  499. delete pLiveData;
  500. }
  501. else
  502. m_pLiveData = pLiveData;
  503. }
  504. else
  505. {
  506. // bad news - no memory
  507. }
  508. m_pFileData = NULL;
  509. m_pCategory = NULL;
  510. // Load the initial tool set.
  511. LoadGlobalToolset(m_mapIDToTool);
  512. UpdateToolsMenu();
  513. //a-sanka 03/29/01 Moved here before any model MessageBox.
  514. //v-stlowe 2/23/01 synchronization for put_DCO_IUnknown
  515. SetEvent(m_evtControlInit);
  516. // Handle the command line parameters.
  517. if (!m_strPrintFile.IsEmpty())
  518. m_strOpenFile = m_strPrintFile;
  519. HRESULT hrOpen = E_FAIL;
  520. if (!m_strOpenFile.IsEmpty())
  521. {
  522. LPCTSTR szBuffer = m_strOpenFile;
  523. int nFileExtension = _tcsclen(szBuffer) - 1;
  524. while (nFileExtension >= 0 && szBuffer[nFileExtension] != _T('.'))
  525. nFileExtension -= 1;
  526. if (nFileExtension >= 0)
  527. hrOpen = OpenMSInfoFile(szBuffer, nFileExtension + 1);
  528. }
  529. // Check to see if we should initially display a file as we open. Also look up whether
  530. // the user was showing advanced data last time.
  531. HKEY hkey;
  532. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_ALL_ACCESS, &hkey))
  533. {
  534. TCHAR szBuffer[MAX_PATH];
  535. DWORD dwType, dwSize = MAX_PATH * sizeof(TCHAR);
  536. if (ERROR_SUCCESS == RegQueryValueEx(hkey, _T("openfile"), NULL, &dwType, (LPBYTE)szBuffer, &dwSize))
  537. if (dwType == REG_SZ)
  538. {
  539. RegDeleteValue(hkey, _T("openfile"));
  540. int nFileExtension = _tcsclen(szBuffer) - 1;
  541. while (nFileExtension >= 0 && szBuffer[nFileExtension] != _T('.'))
  542. nFileExtension -= 1;
  543. if (nFileExtension >= 0)
  544. hrOpen = OpenMSInfoFile(szBuffer, nFileExtension + 1);
  545. }
  546. // Removing the Advanced/Basic view menu items (Whistler 207638)
  547. //
  548. // dwSize = MAX_PATH * sizeof(TCHAR);
  549. // if (ERROR_SUCCESS == RegQueryValueEx(hkey, _T("advanced"), NULL, &dwType, (LPBYTE)szBuffer, &dwSize))
  550. // if (dwType == REG_SZ && szBuffer[0] == _T('1'))
  551. // m_fAdvanced = TRUE;
  552. RegCloseKey(hkey);
  553. }
  554. if (FAILED(hrOpen) && m_pLiveData)
  555. SelectDataSource(m_pLiveData);
  556. if (FAILED(hrOpen) && m_pLiveData)
  557. SelectDataSource(m_pLiveData);
  558. if (!m_strPrintFile.IsEmpty())
  559. DoPrint(TRUE);
  560. if (!m_strComputer.IsEmpty())
  561. DoRemote(m_strComputer);
  562. if (!m_strCategory.IsEmpty() && m_pCurrData)
  563. {
  564. HTREEITEM hti = m_pCurrData->GetNodeByName(m_strCategory);
  565. if (hti != NULL)
  566. {
  567. TreeView_EnsureVisible(m_tree.m_hWnd, hti);
  568. TreeView_SelectItem(m_tree.m_hWnd, hti);
  569. }
  570. }
  571. if (m_fShowPCH && m_fHistoryAvailable && m_strMachine.IsEmpty())
  572. {
  573. DispatchCommand(ID_VIEW_HISTORY);
  574. SetMenuItems();
  575. }
  576. // Load the table of accelerator keys (used in our override of TranslateAccelerator).
  577. m_hAccTable = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_ACCELERATOR1));
  578. // Set the focus to the control, so we can process keystrokes immediately.
  579. ::SetFocus(m_hWnd);
  580. return 0;
  581. }
  582. LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  583. {
  584. if (m_fDoNotRun)
  585. return 0;
  586. // Restore the window's wndproc.
  587. if (m_wndprocParent && m_hwndParent)
  588. {
  589. ::SetWindowLongPtr(m_hwndParent, GWLP_WNDPROC, (ULONG_PTR)m_wndprocParent);
  590. m_wndprocParent = NULL;
  591. m_hwndParent = NULL;
  592. }
  593. // When the window is closing, make sure we don't send any more messages
  594. // from the refresh thread.
  595. /* THIS HASN'T BEEN TESTED ENOUGH FOR THIS CHECKIN
  596. if (m_pCurrData)
  597. {
  598. CMSInfoCategory * pCat = m_pCurrData->GetRootCategory();
  599. if (pCat && pCat->GetDataSourceType() == LIVE_DATA)
  600. {
  601. CLiveDataSource * pLiveDataSource = (CLiveDataSource *) m_pCurrData;
  602. if (pLiveDataSource->m_pThread)
  603. pLiveDataSource->m_pThread->AbortMessaging();
  604. }
  605. }
  606. */
  607. ::SetCurrentDirectory(m_szCurrentDir);
  608. if (m_pLiveData)
  609. {
  610. if (m_pFileData == m_pLiveData)
  611. m_pFileData = NULL;
  612. delete m_pLiveData;
  613. m_pLiveData = NULL;
  614. }
  615. if (m_pFileData)
  616. {
  617. delete m_pFileData;
  618. m_pFileData = NULL;
  619. }
  620. RemoveToolset(m_mapIDToTool);
  621. // Save the complexity of the view to the registry (so we can default to
  622. // it next time).
  623. //
  624. // Removing the Advanced/Basic view menu items (Whistler 207638). Should
  625. // always default to Advanced now.
  626. // HKEY hkey;
  627. // if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Shared Tools\\MSInfo"), 0, KEY_ALL_ACCESS, &hkey))
  628. // {
  629. // TCHAR szBuffer[] = _T("0");
  630. //
  631. // if (m_fAdvanced)
  632. // szBuffer[0] = _T('1');
  633. //
  634. // RegSetValueEx(hkey, _T("advanced"), 0, REG_SZ, (LPBYTE)szBuffer, 2 * sizeof(TCHAR));
  635. // RegCloseKey(hkey);
  636. // }
  637. if (m_pDCO)
  638. m_pDCO->Abort();
  639. m_fDoNotRun = TRUE;
  640. return 0;
  641. }
  642. //=========================================================================
  643. // These functions process mouse movements, which we may respond to in
  644. // different ways. For instance, if the mouse is over the menu bar, then
  645. // we may want to highlight a menu. If the mouse is over the splitter,
  646. // we'll want to change the cursor into a resizer.
  647. //
  648. // This is complicated by the fact that we need to capture the mouse,
  649. // to make sure we know when it leaves so we can update appropriately.
  650. //=========================================================================
  651. LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  652. {
  653. if (m_fDoNotRun)
  654. return 0;
  655. int xPos = LOWORD(lParam); int yPos = HIWORD(lParam);
  656. if (m_fTrackingSplitter)
  657. UpdateSplitterPosition(xPos, yPos);
  658. else
  659. CheckHover(xPos, yPos);
  660. return 0;
  661. }
  662. void CheckHover(int xPos, int yPos)
  663. {
  664. // Check to see if the mouse is hover over the splitter.
  665. if (::PtInRect(&m_rectSplitter, CPoint(xPos, yPos)))
  666. {
  667. if (!m_fMouseCapturedForSplitter)
  668. {
  669. SetCapture();
  670. m_fMouseCapturedForSplitter = TRUE;
  671. }
  672. ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE));
  673. return;
  674. }
  675. else if (m_fMouseCapturedForSplitter)
  676. {
  677. ReleaseCapture();
  678. m_fMouseCapturedForSplitter = FALSE;
  679. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  680. CheckHover(xPos, yPos); // give the other areas a chance
  681. return;
  682. }
  683. }
  684. //=========================================================================
  685. // These functions process mouse clicks and releases. This might entail
  686. // showing a menu, or resizing the panes using the splitter.
  687. //=========================================================================
  688. LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  689. {
  690. if (m_fDoNotRun)
  691. return 0;
  692. int xPos = LOWORD(lParam); int yPos = HIWORD(lParam);
  693. SetFocus();
  694. CheckSplitterClick(xPos, yPos);
  695. return 0;
  696. }
  697. LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  698. {
  699. if (m_fDoNotRun)
  700. return 0;
  701. if (m_fTrackingSplitter)
  702. EndSplitterDrag();
  703. return 0;
  704. }
  705. //-------------------------------------------------------------------------
  706. // If the user clicked on the splitter (the area between the list view and
  707. // the tree view), start tracking the movement of it. Use the DrawFocusRect
  708. // API to give feedback.
  709. //-------------------------------------------------------------------------
  710. void CheckSplitterClick(int xPos, int yPos)
  711. {
  712. if (::PtInRect(&m_rectSplitter, CPoint(xPos, yPos)))
  713. {
  714. ASSERT(!m_fTrackingSplitter);
  715. m_fTrackingSplitter = TRUE;
  716. ::CopyRect(&m_rectLastSplitter, &m_rectSplitter);
  717. DrawSplitter();
  718. m_cxOffset = xPos - m_rectLastSplitter.left;
  719. ASSERT(m_cxOffset >= 0);
  720. }
  721. }
  722. //=========================================================================
  723. // Functions for handling the user interaction with the splitter control.
  724. //
  725. // TBD - bug if you drag splitter and release button with the cursor over
  726. // a menu.
  727. //=========================================================================
  728. void DrawSplitter()
  729. {
  730. InvalidateRect(&m_rectLastSplitter, FALSE);
  731. PAINTSTRUCT ps;
  732. HDC hdc = BeginPaint(&ps);
  733. ::DrawFocusRect(hdc, &m_rectLastSplitter);
  734. EndPaint(&ps);
  735. }
  736. void UpdateSplitterPosition(int xPos, int yPos)
  737. {
  738. // If the user attempts to drag the splitter outside of the window, don't
  739. // allow it.
  740. RECT rectClient;
  741. GetClientRect(&rectClient);
  742. if (!::PtInRect(&rectClient, CPoint(xPos, yPos)))
  743. return;
  744. DrawSplitter(); // remove the current focus rect
  745. int cxDelta = xPos - (m_rectLastSplitter.left + m_cxOffset);
  746. m_rectLastSplitter.left += cxDelta;
  747. m_rectLastSplitter.right += cxDelta;
  748. DrawSplitter();
  749. }
  750. void EndSplitterDrag()
  751. {
  752. DrawSplitter(); // remove the focus rect
  753. // Compute the new tree and list rectangles based on the last splitter position.
  754. RECT rectTree, rectList;
  755. m_tree.GetWindowRect(&rectTree);
  756. m_list.GetWindowRect(&rectList);
  757. ScreenToClient(&rectTree);
  758. ScreenToClient(&rectList);
  759. // First, check to see if the coordinates are reversed (possibly on a bi-directional locale). The
  760. // first case is that standard, left to right case.
  761. if (rectTree.right > rectTree.left || (rectTree.right == rectTree.left && rectList.right > rectList.left))
  762. {
  763. rectTree.right = m_rectLastSplitter.left;
  764. rectList.left = m_rectLastSplitter.right;
  765. // Move the tree and list controls based on the new rects.
  766. m_tree.MoveWindow(rectTree.left, rectTree.top, rectTree.right - rectTree.left, rectTree.bottom - rectTree.top, TRUE);
  767. m_list.MoveWindow(rectList.left, rectList.top, rectList.right - rectList.left, rectList.bottom - rectList.top, TRUE);
  768. }
  769. else
  770. {
  771. // Here's the case where the coordinates are right to left.
  772. rectList.right = m_rectLastSplitter.right;
  773. rectTree.left = m_rectLastSplitter.left;
  774. // Move the tree and list controls based on the new rects.
  775. m_tree.MoveWindow(rectTree.right, rectTree.top, rectTree.left - rectTree.right, rectTree.bottom - rectTree.top, TRUE);
  776. m_list.MoveWindow(rectList.right, rectList.top, rectList.left - rectList.right, rectList.bottom - rectList.top, TRUE);
  777. }
  778. // If we're currently showing a category from a 4.10 NFO file, resize the OCX.
  779. CMSInfoCategory * pCategory = GetCurrentCategory();
  780. if (pCategory && pCategory->GetDataSourceType() == NFO_410)
  781. {
  782. CMSInfo4Category * p4Cat = (CMSInfo4Category*) pCategory;
  783. p4Cat->ResizeControl(this->GetOCXRect());
  784. }
  785. // If nothing data is showing and there is a message string, invalidate the window so
  786. // that it redraws based on the new rect.
  787. if (!m_list.IsWindowVisible() && (!m_strMessTitle.IsEmpty() || !m_strMessText.IsEmpty()))
  788. {
  789. RECT rectNewList;
  790. m_list.GetWindowRect(&rectNewList);
  791. ScreenToClient(&rectNewList);
  792. InvalidateRect(&rectNewList, TRUE);
  793. }
  794. // Figure the size ratio between the list view and tree view, and save it. Take into account
  795. // that the left coordinate might be greater than the right coordinate on a rect (if the
  796. // coordinates are from a RTL locale).
  797. RECT rectClient;
  798. GetClientRect(&rectClient);
  799. if (rectTree.right > rectTree.left)
  800. m_iTreeRatio = ((rectTree.right - rectTree.left) * 100) / (rectClient.right - rectClient.left);
  801. else if (rectTree.right < rectTree.left)
  802. m_iTreeRatio = ((rectTree.left - rectTree.right) * 100) / (rectClient.right - rectClient.left);
  803. else
  804. m_iTreeRatio = 100;
  805. // Update the splitter tracking variables.
  806. m_fTrackingSplitter = FALSE;
  807. ::CopyRect(&m_rectSplitter, &m_rectLastSplitter);
  808. // Invalidate the splitter itself (so that it will repaint).
  809. InvalidateRect(&m_rectSplitter);
  810. // Release the mouse capture and restore the cursor.
  811. ReleaseCapture();
  812. m_fMouseCapturedForSplitter = FALSE;
  813. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  814. }
  815. //=========================================================================
  816. // Rendering functions, including handling the WM_PAINT message.
  817. //=========================================================================
  818. LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  819. {
  820. // We're having some redraw issues when brought back from a locked
  821. // system. It seems that even though the updated rect is the same
  822. // as the client rect, it doesn't include all the necessary regions
  823. // to repaint.
  824. RECT rectUpdate, rectClient;
  825. if (GetClientRect(&rectClient) && GetUpdateRect(&rectUpdate) && ::EqualRect(&rectClient, &rectUpdate))
  826. Invalidate(FALSE);
  827. PAINTSTRUCT ps;
  828. HDC hdc = BeginPaint(&ps);
  829. GetClientRect(&rectClient);
  830. ::SetTextColor(hdc, ::GetSysColor(COLOR_BTNFACE));
  831. if (m_fFirstPaint)
  832. {
  833. m_hbrBackground = CreateSolidBrush(::GetSysColor(COLOR_BTNFACE /* COLOR_MENU */));
  834. if (!m_fDoNotRun)
  835. SetMenuItems();
  836. m_fFirstPaint = FALSE;
  837. }
  838. FillRect(hdc, &rectClient, m_hbrBackground);
  839. if (m_fDoNotRun)
  840. {
  841. if (m_strDoNotRun.IsEmpty())
  842. {
  843. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  844. m_strDoNotRun.LoadString(IDS_ONLYINHELPCTR);
  845. }
  846. CDC dc;
  847. dc.Attach(hdc);
  848. dc.SetBkMode(TRANSPARENT);
  849. dc.DrawText(m_strDoNotRun, &rectClient, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  850. dc.Detach();
  851. EndPaint(&ps);
  852. return 0;
  853. }
  854. if (!m_list.IsWindowVisible())
  855. {
  856. RECT rectList;
  857. m_list.GetWindowRect(&rectList);
  858. ScreenToClient(&rectList);
  859. // If the list window is hidden, we should probably be displaying a message. First,
  860. // draw the 3D rectangle.
  861. CDC dc;
  862. dc.Attach(hdc);
  863. dc.Draw3dRect(&rectList, ::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DHILIGHT));
  864. // For some reason, DrawText wants left < right (even on RTL systems, like ARA).
  865. if (rectList.left > rectList.right)
  866. {
  867. int iSwap = rectList.left;
  868. rectList.left = rectList.right;
  869. rectList.right = iSwap;
  870. }
  871. // Next, if there is text, draw it.
  872. if (!m_strMessTitle.IsEmpty() || !m_strMessText.IsEmpty())
  873. {
  874. ::InflateRect(&rectList, -10, -10);
  875. CGdiObject * pFontOld = dc.SelectStockObject(DEFAULT_GUI_FONT);
  876. COLORREF crTextOld = dc.SetTextColor(::GetSysColor(COLOR_MENUTEXT));
  877. int nBkModeOld = dc.SetBkMode(TRANSPARENT);
  878. if (!m_strMessTitle.IsEmpty())
  879. {
  880. // We want to make a bigger version of the same font. Select the font
  881. // again (to get a pointer to the original font). Get it's LOGFONT,
  882. // make it bigger, and create a new font for selection.
  883. CFont * pNormalFont = (CFont *) dc.SelectStockObject(DEFAULT_GUI_FONT);
  884. LOGFONT lf;
  885. pNormalFont->GetLogFont(&lf);
  886. lf.lfHeight = (lf.lfHeight * 3) / 2;
  887. lf.lfWeight = FW_BOLD;
  888. CFont fontDoubleSize;
  889. fontDoubleSize.CreateFontIndirect(&lf);
  890. dc.SelectObject(&fontDoubleSize);
  891. RECT rectTemp;
  892. ::CopyRect(&rectTemp, &rectList);
  893. int iHeight = dc.DrawText(m_strMessTitle, &rectTemp, DT_LEFT | DT_TOP | DT_WORDBREAK | DT_CALCRECT);
  894. dc.DrawText(m_strMessTitle, &rectList, DT_LEFT | DT_TOP | DT_WORDBREAK);
  895. rectList.top += iHeight + 5;
  896. dc.SelectObject(pNormalFont);
  897. }
  898. if (!m_strMessText.IsEmpty())
  899. {
  900. dc.DrawText(m_strMessText, &rectList, DT_LEFT | DT_TOP | DT_WORDBREAK);
  901. }
  902. dc.SelectObject(pFontOld);
  903. dc.SetTextColor(crTextOld);
  904. dc.SetBkMode(nBkModeOld);
  905. }
  906. dc.Detach();
  907. }
  908. EndPaint(&ps);
  909. return 0;
  910. }
  911. LRESULT OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  912. {
  913. m_fFirstPaint = TRUE;
  914. Invalidate();
  915. UpdateWindow();
  916. return 0;
  917. }
  918. LRESULT OnDialogColor(UINT, WPARAM w, LPARAM, BOOL&)
  919. {
  920. HDC dc = (HDC) w;
  921. LOGBRUSH lb;
  922. ::GetObject(m_hbrBackground, sizeof(lb), (void*)&lb);
  923. ::SetBkColor(dc, lb.lbColor);
  924. ::SetTextColor(dc, ::GetSysColor(COLOR_BTNTEXT));
  925. ::SetBkMode(dc, TRANSPARENT);
  926. return (LRESULT)m_hbrBackground;
  927. }
  928. //=========================================================================
  929. // Handle the WM_SIZE message. This involves a bit of cleverness to avoid
  930. // ugly updates: if the user has moved the splitter bar, preserve
  931. // the ratio of sizes to the two windows.
  932. //=========================================================================
  933. LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  934. {
  935. if (m_fDoNotRun)
  936. {
  937. RECT rectClient;
  938. GetClientRect(&rectClient);
  939. InvalidateRect(&rectClient, FALSE);
  940. return 0;
  941. }
  942. LayoutControl();
  943. return 0;
  944. }
  945. void LayoutControl()
  946. {
  947. const int cBorder = 3;
  948. const int cxSplitter = 3;
  949. RECT rectClient;
  950. GetClientRect(&rectClient);
  951. int cyMenuHeight = cBorder;
  952. int cyFindControlHeight = PositionFindControls();
  953. if (m_history.IsWindowVisible())
  954. {
  955. CRect rectHistory, rectHistorylabel;
  956. m_history.GetWindowRect(&rectHistory);
  957. m_historylabel.GetWindowRect(&rectHistorylabel);
  958. rectHistory.OffsetRect(rectClient.right - cBorder - rectHistory.right, rectClient.top + cBorder - rectHistory.top);
  959. rectHistorylabel.OffsetRect(rectHistory.left - cBorder / 2 - rectHistorylabel.right, rectClient.top + cBorder + ((rectHistory.Height() - rectHistorylabel.Height()) / 2) - rectHistorylabel.top);
  960. if (rectHistorylabel.left < 0) // TBD
  961. {
  962. rectHistory += CPoint(0 - rectHistorylabel.left, 0);
  963. rectHistorylabel += CPoint(0 - rectHistorylabel.left, 0);
  964. }
  965. m_history.MoveWindow(&rectHistory);
  966. m_historylabel.MoveWindow(&rectHistorylabel);
  967. if (rectHistory.Height() + cBorder * 2 > cyMenuHeight)
  968. {
  969. cyMenuHeight = rectHistory.Height() + cBorder * 2 - 1;
  970. CPoint ptMenu(cBorder, (cyMenuHeight - 0) / 2 + 2);
  971. }
  972. }
  973. else
  974. {
  975. CPoint ptMenu(5, 5);
  976. }
  977. RECT rectTree;
  978. ::CopyRect(&rectTree, &rectClient);
  979. rectTree.left += cBorder;
  980. rectTree.top += cyMenuHeight + cxSplitter / 2;
  981. rectTree.bottom -= ((cyFindControlHeight) ? cyFindControlHeight : cBorder);
  982. rectTree.right = ((rectClient.right - rectClient.left) * m_iTreeRatio) / 100 + rectClient.left;
  983. m_tree.MoveWindow(rectTree.left, rectTree.top, rectTree.right - rectTree.left, rectTree.bottom - rectTree.top, FALSE);
  984. RECT rectList;
  985. ::CopyRect(&rectList, &rectClient);
  986. rectList.left = rectTree.right + cxSplitter;
  987. rectList.top = rectTree.top;
  988. rectList.bottom = rectTree.bottom;
  989. rectList.right -= cBorder;
  990. m_list.MoveWindow(rectList.left, rectList.top, rectList.right - rectList.left, rectList.bottom - rectList.top, FALSE);
  991. // Get the rectangle for the splitter, and save it.
  992. m_tree.GetWindowRect(&rectTree);
  993. m_list.GetWindowRect(&rectList);
  994. ScreenToClient(&rectTree);
  995. ScreenToClient(&rectList);
  996. // Check whether the coordinate system is LTR (eg. English) or RTL.
  997. if (rectTree.left < rectTree.right || (rectTree.left == rectTree.right && rectList.left < rectList.right))
  998. {
  999. // Nominal (LTR) case.
  1000. int cxLeft = (rectTree.right < rectList.left) ? rectTree.right : rectList.left - cxSplitter;
  1001. ::SetRect(&m_rectSplitter, cxLeft, rectTree.top, cxLeft + cxSplitter, rectTree.bottom);
  1002. }
  1003. else
  1004. {
  1005. // Special case for RTL locales.
  1006. int cxLeft = (rectTree.left < rectList.right) ? rectList.right : rectTree.left - cxSplitter;
  1007. ::SetRect(&m_rectSplitter, cxLeft - cxSplitter, rectTree.top, cxLeft, rectTree.bottom);
  1008. }
  1009. CMSInfoCategory * pCategory = GetCurrentCategory();
  1010. if (pCategory && pCategory->GetDataSourceType() == NFO_410)
  1011. {
  1012. CMSInfo4Category * p4Cat = (CMSInfo4Category*) pCategory;
  1013. p4Cat->ResizeControl(this->GetOCXRect());
  1014. }
  1015. InvalidateRect(&rectClient, FALSE);
  1016. }
  1017. //=========================================================================
  1018. // Respond to the user clicking the tree or list.
  1019. //=========================================================================
  1020. LRESULT OnSelChangedTree(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
  1021. {
  1022. if (m_fDoNotRun)
  1023. return 0;
  1024. LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW) pnmh;
  1025. if (lpnmtv)
  1026. {
  1027. CMSInfoCategory * pCategory = (CMSInfoCategory *) lpnmtv->itemNew.lParam;
  1028. ASSERT(pCategory);
  1029. if (pCategory)
  1030. {
  1031. CancelFind();
  1032. SelectCategory(pCategory);
  1033. }
  1034. }
  1035. return 0;
  1036. }
  1037. LRESULT OnColumnClick(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
  1038. {
  1039. if (m_fDoNotRun)
  1040. return 0;
  1041. LPNMLISTVIEW pnmv = (LPNMLISTVIEW) pnmh;
  1042. CMSInfoCategory * pCategory = GetCurrentCategory();
  1043. if (pnmv && pCategory)
  1044. {
  1045. BOOL fSorts, fLexical;
  1046. // Get the internal column number (in BASIC view, this might be different
  1047. // than the column indicated.
  1048. int iCol;
  1049. if (m_fAdvanced)
  1050. iCol = pnmv->iSubItem;
  1051. else
  1052. {
  1053. ASSERT(pnmv->iSubItem < m_iCategoryColNumberLen);
  1054. if (pnmv->iSubItem >= m_iCategoryColNumberLen)
  1055. return 0;
  1056. iCol = m_aiCategoryColNumber[pnmv->iSubItem];
  1057. }
  1058. if (pCategory->GetColumnInfo(iCol, NULL, NULL, &fSorts, &fLexical))
  1059. {
  1060. if (!fSorts)
  1061. return 0;
  1062. if (iCol == pCategory->m_iSortColumn)
  1063. pCategory->m_fSortAscending = !pCategory->m_fSortAscending;
  1064. else
  1065. pCategory->m_fSortAscending = TRUE;
  1066. pCategory->m_iSortColumn = iCol;
  1067. pCategory->m_fSortLexical = fLexical;
  1068. CLiveDataSource * pLiveDataSource = NULL;
  1069. if (pCategory->GetDataSourceType() == LIVE_DATA)
  1070. pLiveDataSource = (CLiveDataSource *) m_pCurrData;
  1071. if (pLiveDataSource)
  1072. pLiveDataSource->LockData();
  1073. ListView_SortItems(m_list.m_hWnd, (PFNLVCOMPARE) ListSortFunc, (LPARAM) pCategory);
  1074. if (pLiveDataSource)
  1075. pLiveDataSource->UnlockData();
  1076. }
  1077. }
  1078. return 0;
  1079. }
  1080. LRESULT OnListItemChanged(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
  1081. {
  1082. if (m_fDoNotRun)
  1083. return 0;
  1084. SetMenuItems();
  1085. return 0;
  1086. }
  1087. //-------------------------------------------------------------------------
  1088. // Don't allow the user to collapse the root node of the tree.
  1089. //-------------------------------------------------------------------------
  1090. LRESULT OnItemExpandingTree(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
  1091. {
  1092. LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW) pnmh;
  1093. if (lpnmtv && (lpnmtv->action & TVE_COLLAPSE))
  1094. {
  1095. CMSInfoCategory * pCategory = (CMSInfoCategory *) lpnmtv->itemNew.lParam;
  1096. if (pCategory && pCategory->GetParent() == NULL)
  1097. return 1;
  1098. }
  1099. return 0;
  1100. }
  1101. //=========================================================================
  1102. // Called when we're being notified by the worker thread that a refresh
  1103. // is complete and data should be displayed.
  1104. //
  1105. // TBD - check whether is category is still selected
  1106. //=========================================================================
  1107. LRESULT OnMSInfoDataReady(UINT /* uMsg */, WPARAM /* wParam */, LPARAM lParam, BOOL& /* bHandled */)
  1108. {
  1109. if (m_fDoNotRun)
  1110. return 0;
  1111. ASSERT(lParam);
  1112. if (lParam == 0)
  1113. return 0;
  1114. if (m_fInFind && lParam == (LPARAM)m_pcatFind)
  1115. {
  1116. FindRefreshComplete();
  1117. return 0;
  1118. }
  1119. HTREEITEM hti = TreeView_GetSelection(m_tree.m_hWnd);
  1120. if (hti)
  1121. {
  1122. TVITEM tvi;
  1123. tvi.mask = TVIF_PARAM;
  1124. tvi.hItem = hti;
  1125. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  1126. if (tvi.lParam == lParam)
  1127. {
  1128. CMSInfoCategory * pCategory = (CMSInfoCategory *) lParam;
  1129. ASSERT(pCategory->GetDataSourceType() == LIVE_DATA);
  1130. SelectCategory(pCategory, TRUE);
  1131. }
  1132. }
  1133. return 0;
  1134. }
  1135. //=========================================================================
  1136. // Functions for managing the list view and the tree view. Note - the
  1137. // dwItem can only be set for the row (when iCol == 0).
  1138. //=========================================================================
  1139. void ListInsertItem(int iRow, int iCol, LPCTSTR szItem, DWORD dwItem)
  1140. {
  1141. LVITEM lvi;
  1142. lvi.mask = LVIF_TEXT | ((iCol == 0) ? LVIF_PARAM : 0);
  1143. lvi.iItem = iRow;
  1144. lvi.iSubItem = iCol;
  1145. lvi.pszText = (LPTSTR) szItem;
  1146. lvi.lParam = (LPARAM) dwItem;
  1147. if (iCol == 0)
  1148. ListView_InsertItem(m_list.m_hWnd, &lvi);
  1149. else
  1150. ListView_SetItem(m_list.m_hWnd, &lvi);
  1151. }
  1152. void ListInsertColumn(int iCol, int cxWidth, LPCTSTR szCaption)
  1153. {
  1154. LVCOLUMN lvc;
  1155. lvc.mask = LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  1156. lvc.cx = cxWidth;
  1157. lvc.pszText = (LPTSTR) szCaption;
  1158. lvc.iOrder = iCol;
  1159. ListView_InsertColumn(m_list.m_hWnd, iCol, &lvc);
  1160. }
  1161. void ListClearItems()
  1162. {
  1163. ListView_DeleteAllItems(m_list.m_hWnd);
  1164. }
  1165. void ListClearColumns()
  1166. {
  1167. while (ListView_DeleteColumn(m_list.m_hWnd, 0));
  1168. }
  1169. void TreeClearItems()
  1170. {
  1171. TreeView_DeleteAllItems(m_tree.m_hWnd);
  1172. }
  1173. HTREEITEM TreeInsertItem(HTREEITEM hParent, HTREEITEM hInsertAfter, LPTSTR szName, LPARAM lParam)
  1174. {
  1175. TVINSERTSTRUCT tvis;
  1176. tvis.hParent = hParent;
  1177. tvis.hInsertAfter = hInsertAfter;
  1178. tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
  1179. tvis.item.pszText = szName;
  1180. tvis.item.lParam = lParam;
  1181. return TreeView_InsertItem(m_tree.m_hWnd, &tvis);
  1182. }
  1183. void BuildTree(HTREEITEM htiParent, HTREEITEM htiPrevious, CMSInfoCategory * pCategory)
  1184. {
  1185. ASSERT(pCategory);
  1186. CString strCaption(_T(""));
  1187. // If the user specified the /showcategories flag, we should show the name of
  1188. // each category in the tree (which is unlocalized). Otherwise show the caption.
  1189. if (!m_fShowCategories)
  1190. pCategory->GetNames(&strCaption, NULL);
  1191. else
  1192. pCategory->GetNames(NULL, &strCaption);
  1193. if (pCategory->GetDataSourceType() == LIVE_DATA && htiParent == TVI_ROOT && !m_strMachine.IsEmpty() && pCategory != &catHistorySystemSummary)
  1194. {
  1195. CString strMachine(m_strMachine);
  1196. strMachine.MakeLower();
  1197. strMachine.TrimLeft(_T("\\"));
  1198. // Changed this to use a Format() with a string resource, instead of
  1199. // appending the machine name to the string. This should solve some
  1200. // problems with oddities on RTL languages.
  1201. strCaption.Format(IDS_SYSTEMSUMMARYMACHINENAME, strMachine);
  1202. }
  1203. HTREEITEM htiCategory = TreeInsertItem(htiParent, htiPrevious, (LPTSTR)(LPCTSTR)strCaption, (LPARAM)pCategory);
  1204. pCategory->SetHTREEITEM(htiCategory);
  1205. for (CMSInfoCategory * pChild = pCategory->GetFirstChild(); pChild; pChild = pChild->GetNextSibling())
  1206. BuildTree(htiCategory, TVI_LAST, pChild);
  1207. }
  1208. void RefillListView(BOOL fRefreshDataOnly = TRUE)
  1209. {
  1210. HTREEITEM hti = TreeView_GetSelection(m_tree.m_hWnd);
  1211. if (hti)
  1212. {
  1213. TVITEM tvi;
  1214. tvi.mask = TVIF_PARAM;
  1215. tvi.hItem = hti;
  1216. if (TreeView_GetItem(m_tree.m_hWnd, &tvi))
  1217. if (tvi.lParam)
  1218. {
  1219. CMSInfoCategory * pCategory = (CMSInfoCategory *) tvi.lParam;
  1220. SelectCategory(pCategory, fRefreshDataOnly);
  1221. }
  1222. }
  1223. }
  1224. //=========================================================================
  1225. // If the user presses a key, we should check to see if it's something
  1226. // we need to deal with (accelerators, ALT-?, etc.).
  1227. //=========================================================================
  1228. HACCEL m_hAccTable;
  1229. STDMETHODIMP TranslateAccelerator(MSG * pMsg)
  1230. {
  1231. if (m_hwndParent && m_hAccTable && (GetAsyncKeyState(VK_CONTROL) < 0 || (WORD)pMsg->wParam == VK_F1) && ::TranslateAccelerator(m_hwndParent, m_hAccTable, pMsg))
  1232. return S_OK;
  1233. if (m_fFindVisible && (WORD)pMsg->wParam == VK_RETURN && pMsg->message != WM_KEYUP)
  1234. {
  1235. // If the focus is on the stop find button, do so.
  1236. if (GetFocus() == m_wndStopFind.m_hWnd || GetFocus() == m_wndCancelFind.m_hWnd)
  1237. {
  1238. BOOL bHandled;
  1239. OnStopFind(0, 0, NULL, bHandled);
  1240. return S_OK;
  1241. }
  1242. // Otherwise, if the find or find next button is showing, execute
  1243. // that command.
  1244. if (m_wndStartFind.IsWindowEnabled() || m_wndFindNext.IsWindowEnabled())
  1245. {
  1246. BOOL bHandled;
  1247. OnFind(0, 0, NULL, bHandled);
  1248. return S_OK;
  1249. }
  1250. }
  1251. return IOleInPlaceActiveObjectImpl<CMSInfo>::TranslateAccelerator(pMsg);
  1252. }
  1253. void MSInfoMessageBox(UINT uiMessageID, UINT uiTitleID = IDS_SYSTEMINFO)
  1254. {
  1255. CString strCaption, strMessage;
  1256. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  1257. strCaption.LoadString(uiTitleID);
  1258. strMessage.LoadString(uiMessageID);
  1259. MessageBox(strMessage, strCaption);
  1260. }
  1261. void MSInfoMessageBox(const CString & strMessage, UINT uiTitleID = IDS_SYSTEMINFO)
  1262. {
  1263. CString strCaption;
  1264. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  1265. strCaption.LoadString(uiTitleID);
  1266. MessageBox(strMessage, strCaption);
  1267. }
  1268. //=========================================================================
  1269. // Functions implemented in the CPP file.
  1270. //=========================================================================
  1271. BOOL DispatchCommand(int iCommand);
  1272. void SelectDataSource(CDataSource * pDataSource);
  1273. void SelectCategory(CMSInfoCategory * pCategory, BOOL fRefreshDataOnly = FALSE);
  1274. void MSInfoRefresh();
  1275. void OpenNFO();
  1276. void SaveNFO();
  1277. void Export();
  1278. void CloseFile();
  1279. void SaveMSInfoFile(LPCTSTR szFilename, DWORD dwFilterIndex = 1);//new format by default
  1280. HRESULT OpenMSInfoFile(LPCTSTR szFilename, int nFileExtension);
  1281. void ExportFile(LPCTSTR szFilename, int nFileExtension);
  1282. CMSInfoCategory * GetCurrentCategory();
  1283. void SetMenuItems();
  1284. void SetMessage(const CString & strTitle, const CString & strMessage = CString(_T("")), BOOL fRedraw = FALSE);
  1285. void SetMessage(UINT uiTitle, UINT uiMessage = 0, BOOL fRedraw = FALSE);
  1286. void EditCopy();
  1287. void EditSelectAll();
  1288. void DoPrint(BOOL fNoUI = FALSE);
  1289. void UpdateToolsMenu();
  1290. CRect GetOCXRect();
  1291. void CancelFind();
  1292. LRESULT OnStopFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
  1293. void UpdateFindControls();
  1294. LRESULT OnChangeFindWhat(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
  1295. LRESULT OnFind(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
  1296. void FindRefreshComplete();
  1297. BOOL FindInCurrentCategory();
  1298. void ShowFindControls();
  1299. int PositionFindControls();
  1300. void ShowRemoteDialog();
  1301. void DoRemote(LPCTSTR szMachine);
  1302. void SaveXML(const CString & strFileName);
  1303. void GetMachineName(LPTSTR lpBuffer, LPDWORD lpnSize);
  1304. void RefreshData(CLiveDataSource * pSource, CMSInfoLiveCategory * pLiveCategory);
  1305. //-------------------------------------------------------------------------
  1306. // Fill our combo box with the available history deltas.
  1307. //-------------------------------------------------------------------------
  1308. void FillHistoryCombo()
  1309. {
  1310. m_history.SendMessage(CB_RESETCONTENT, 0, 0);
  1311. CMSInfoCategory * pCategory = GetCurrentCategory();
  1312. if (pCategory == NULL || (pCategory->GetDataSourceType() != LIVE_DATA && pCategory->GetDataSourceType() != XML_SNAPSHOT))
  1313. return;
  1314. CLiveDataSource * pLiveSource = (CLiveDataSource *) m_pCurrData;
  1315. CStringList strlistDeltas;
  1316. CString strItem;
  1317. CDC dc;
  1318. CSize size;
  1319. int cxMaxWidth = 0;
  1320. HDC hdc = GetDC();
  1321. dc.Attach(hdc);
  1322. dc.SelectObject(CFont::FromHandle((HFONT)m_history.SendMessage(WM_GETFONT, 0, 0)));
  1323. if (pLiveSource->GetDeltaList(&strlistDeltas))
  1324. while (!strlistDeltas.IsEmpty())
  1325. {
  1326. strItem = strlistDeltas.RemoveHead();
  1327. m_history.SendMessage(CB_INSERTSTRING, -1, (LPARAM)(LPCTSTR)strItem);
  1328. size = dc.GetTextExtent(strItem);
  1329. if (size.cx > cxMaxWidth)
  1330. cxMaxWidth = size.cx;
  1331. }
  1332. //else
  1333. //TD: what if no history is available?
  1334. CRect rectClient, rectHistory;
  1335. GetClientRect(&rectClient);
  1336. m_history.GetWindowRect(&rectHistory);
  1337. if (cxMaxWidth > rectHistory.Width() && cxMaxWidth < rectClient.Width())
  1338. {
  1339. rectHistory.InflateRect((cxMaxWidth - (rectHistory.Width() - GetSystemMetrics(SM_CXHSCROLL))) / 2 + 5, 0);
  1340. m_history.MoveWindow(&rectHistory);
  1341. LayoutControl();
  1342. }
  1343. dc.Detach();
  1344. ReleaseDC(hdc);
  1345. }
  1346. //-------------------------------------------------------------------------
  1347. // If the user selects a history delta to view, we need to mark all of the
  1348. // categories as unrefreshed (so the new data will be generated).
  1349. //-------------------------------------------------------------------------
  1350. LRESULT OnHistorySelection(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  1351. {
  1352. int iSelection = (int)m_history.SendMessage(CB_GETCURSEL, 0, 0);
  1353. #ifdef A_STEPHL
  1354. /* CString strMSG;
  1355. strMSG.Format("iSelection= %d",iSelection);
  1356. ::MessageBox(NULL,strMSG,"",MB_OK);*/
  1357. #endif
  1358. if (iSelection == CB_ERR)
  1359. {
  1360. return 0;
  1361. }
  1362. ChangeHistoryView(iSelection);
  1363. return 0;
  1364. }
  1365. void ChangeHistoryView(int iIndex)
  1366. {
  1367. CMSInfoCategory * pCategory = GetCurrentCategory();
  1368. if (pCategory == NULL)
  1369. {
  1370. ASSERT(FALSE && "NULL pCategory");
  1371. return;
  1372. }
  1373. else if (pCategory->GetDataSourceType() == LIVE_DATA || pCategory->GetDataSourceType() == XML_SNAPSHOT)
  1374. {
  1375. pCategory->ResetCategory();
  1376. if (((CMSInfoHistoryCategory*) pCategory)->m_iDeltaIndex == iIndex)
  1377. {
  1378. // return;
  1379. }
  1380. CLiveDataSource * pLiveSource = (CLiveDataSource *) m_pCurrData;
  1381. if (pLiveSource->ShowDeltas(iIndex))
  1382. {
  1383. SetMessage(IDS_REFRESHHISTORYMESSAGE, 0, TRUE);
  1384. MSInfoRefresh();
  1385. #ifdef A_STEPHL
  1386. /* CString strMSG;
  1387. strMSG.Format("niIndex= %d",iIndex);
  1388. ::MessageBox(NULL,strMSG,"",MB_OK);*/
  1389. #endif
  1390. }
  1391. else
  1392. {
  1393. // Clear the existing categories in the tree.
  1394. TreeClearItems();
  1395. // Load the contents of the tree from the data source.
  1396. CMSInfoCategory * pRoot = m_pCurrData->GetRootCategory();
  1397. if (pRoot)
  1398. {
  1399. BuildTree(TVI_ROOT, TVI_LAST, pRoot);
  1400. TreeView_Expand(m_tree.m_hWnd, TreeView_GetRoot(m_tree.m_hWnd), TVE_EXPAND);
  1401. TreeView_SelectItem(m_tree.m_hWnd, TreeView_GetRoot(m_tree.m_hWnd));
  1402. }
  1403. }
  1404. }
  1405. else
  1406. {
  1407. ASSERT(FALSE && "shouldn't be showing history dropdown with this data source");
  1408. return;
  1409. }
  1410. }
  1411. //-------------------------------------------------------------------------
  1412. // If the user sets the focus to the list, and there is no previously
  1413. // selected item, then select the first item in the list (so the user can
  1414. // see the focus).
  1415. //-------------------------------------------------------------------------
  1416. LRESULT OnSetFocusList(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
  1417. {
  1418. if (ListView_GetSelectedCount(m_list.m_hWnd) == 0)
  1419. ListView_SetItemState(m_list.m_hWnd, 0, LVIS_SELECTED, LVIS_SELECTED);
  1420. return 0;
  1421. }
  1422. //-------------------------------------------------------------------------
  1423. // If the hovers on a cell in the list view, show the contents
  1424. // of that cell as an infotip. This is helpful for extremely long items.
  1425. //-------------------------------------------------------------------------
  1426. LRESULT OnInfoTipList(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
  1427. {
  1428. TCHAR szBuf[MAX_PATH * 3] = _T("");
  1429. LPNMLVGETINFOTIP pGetInfoTip = (LPNMLVGETINFOTIP)pnmh;
  1430. if(NULL != pGetInfoTip)
  1431. {
  1432. ListView_GetItemText(m_list.m_hWnd, pGetInfoTip->iItem, pGetInfoTip->iSubItem, szBuf, MAX_PATH * 3);
  1433. pGetInfoTip->cchTextMax = _tcslen(szBuf);
  1434. pGetInfoTip->pszText = szBuf;
  1435. }
  1436. return 0;
  1437. }
  1438. //-------------------------------------------------------------------------
  1439. // Is the user right clicks on the tree, we should show a context menu
  1440. // with the "What's This?" item in it. If the user selects the menu
  1441. // item, we should launch help with the topic for the category.
  1442. //-------------------------------------------------------------------------
  1443. LRESULT OnRClickTree(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
  1444. {
  1445. // Determine if the right click was on a category in the tree view.
  1446. CMSInfoCategory * pCategory = NULL;
  1447. DWORD dwPoint = GetMessagePos();
  1448. TVHITTESTINFO tvhti;
  1449. tvhti.pt.x = ((int)(short)LOWORD(dwPoint));
  1450. tvhti.pt.y = ((int)(short)HIWORD(dwPoint));
  1451. ::ScreenToClient(m_tree.m_hWnd, &tvhti.pt);
  1452. // If it's on a tree view item, get the category pointer.
  1453. HTREEITEM hti = TreeView_HitTest(m_tree.m_hWnd, &tvhti);
  1454. if (hti != NULL)
  1455. {
  1456. TVITEM tvi;
  1457. tvi.mask = TVIF_PARAM;
  1458. tvi.hItem = hti;
  1459. if (TreeView_GetItem(m_tree.m_hWnd, &tvi) && tvi.lParam)
  1460. pCategory = (CMSInfoCategory *) tvi.lParam;
  1461. }
  1462. if (pCategory != NULL)
  1463. {
  1464. const UINT uFlags = TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_RIGHTBUTTON;
  1465. ::AfxSetResourceHandle(_Module.GetResourceInstance());
  1466. HMENU hmenu = ::LoadMenu(_Module.GetResourceInstance(), _T("IDR_WHAT_IS_THIS_MENU"));
  1467. HMENU hmenuSub = ::GetSubMenu(hmenu, 0);
  1468. if (hmenuSub)
  1469. if (::TrackPopupMenu(hmenuSub, uFlags, ((int)(short)LOWORD(dwPoint)), ((int)(short)HIWORD(dwPoint)), 0, m_hWnd, NULL))
  1470. ShowCategoryHelp(pCategory);
  1471. ::DestroyMenu(hmenu);
  1472. }
  1473. return 0;
  1474. }
  1475. LRESULT OnClickedSearchSelected(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  1476. {
  1477. if (IsDlgButtonChecked(IDC_CHECKSEARCHSELECTED) == BST_CHECKED)
  1478. CheckDlgButton(IDC_CHECKSEARCHCATSONLY, BST_UNCHECKED);
  1479. return 0;
  1480. }
  1481. LRESULT OnClickedSearchCatsOnly(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  1482. {
  1483. if (IsDlgButtonChecked(IDC_CHECKSEARCHCATSONLY) == BST_CHECKED)
  1484. CheckDlgButton(IDC_CHECKSEARCHSELECTED, BST_UNCHECKED);
  1485. return 0;
  1486. }
  1487. //-------------------------------------------------------------------------
  1488. // Display the help file with the topic for the specified category shown.
  1489. // If the category doesn't have a topic, check its parent categories. If
  1490. // There are no topics all the way to the root, just show the help without
  1491. // a specific topic.
  1492. //-------------------------------------------------------------------------
  1493. void ShowCategoryHelp(CMSInfoCategory * pCategory)
  1494. {
  1495. CString strTopic(_T(""));
  1496. while (pCategory != NULL && strTopic.IsEmpty())
  1497. {
  1498. strTopic = pCategory->GetHelpTopic();
  1499. pCategory = pCategory->GetParent();
  1500. }
  1501. if (strTopic.IsEmpty())
  1502. ::HtmlHelp(m_hWnd, _T("msinfo32.chm"), HH_DISPLAY_TOPIC, NULL);
  1503. else
  1504. ::HtmlHelp(m_hWnd, _T("msinfo32.chm"), HH_DISPLAY_TOPIC, (DWORD_PTR)(LPCTSTR)strTopic);
  1505. }
  1506. //-------------------------------------------------------------------------
  1507. // If the user sets the focus to the edit control, we should turn on the
  1508. // copy command in the menu.
  1509. //-------------------------------------------------------------------------
  1510. LRESULT OnSetFocusEditFindWhat(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  1511. {
  1512. if (m_fDoNotRun)
  1513. return 0;
  1514. SetMenuItems();
  1515. return 0;
  1516. }
  1517. LRESULT OnKillFocusEditFindWhat(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
  1518. {
  1519. if (m_fDoNotRun)
  1520. return 0;
  1521. SetMenuItems();
  1522. return 0;
  1523. }
  1524. };
  1525. #endif //__MSINFO_H_