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

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