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.

617 lines
16 KiB

  1. // Dialogs.cpp - Create all of our dialogs to get data from the user.
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation
  4. #include <afxdlgs.h>
  5. #include <afxwin.h>
  6. #include <shlobj.h>
  7. #include "StdAfx.h"
  8. #include "Dialogs.h"
  9. #include "DataObj.h"
  10. #include "CompData.h"
  11. #include "Resource.h"
  12. #include "resrc1.h"
  13. // These are the lists of file type for the Save/Open Common Control Dialogs.
  14. CString strMSInfoSaveFileTypes;
  15. CString strMSInfoOpenFileTypes;
  16. CString strMSInfoReportTypes;
  17. // These are the default file types
  18. CString strMSInfoSaveType;
  19. CString strMSInfoReportType;
  20. // This is to implement a change to load the strings for file types, etc.,
  21. // from resources. This is called by the app init.
  22. void LoadDialogResources()
  23. {
  24. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  25. strMSInfoSaveFileTypes.LoadString(IDS_SAVE_FILE_TYPES);
  26. strMSInfoOpenFileTypes.LoadString(IDS_OPEN_FILE_TYPES);
  27. strMSInfoReportTypes.LoadString(IDS_REPORT_TYPES);
  28. strMSInfoSaveType.LoadString(IDS_SAVE_TYPE);
  29. strMSInfoReportType.LoadString(IDS_REPORT_TYPE);
  30. }
  31. // The custom message number we use to
  32. UINT CFindDialog::WM_MSINFO_FIND = WM_USER + 0x119;
  33. // static data members must be initialized at file scope
  34. TCHAR CMSInfoFileDialog::m_szCurrentDirectory[MAX_PATH] = _T("My Documents");
  35. /*
  36. * GetPathFromIDList - Copy the path from the iilFolder to szPathBuffer.
  37. *
  38. * History: a-jsari 10/31/97 Initial version
  39. */
  40. inline void GetBasePath(HWND hOwner, LPTSTR szPathBuffer)
  41. {
  42. LPITEMIDLIST iilFolder;
  43. HRESULT hResult;
  44. hResult = SHGetSpecialFolderLocation(hOwner, CSIDL_PERSONAL, &iilFolder);
  45. ASSERT(hResult == NOERROR);
  46. VERIFY(SHGetPathFromIDList(iilFolder, szPathBuffer));
  47. }
  48. /*
  49. * CMSInfoFileDialog - Brings up the CFileDialog window, with a few of our
  50. * own specifications.
  51. *
  52. * History: a-jsari 10/24/97 Initial version
  53. */
  54. CMSInfoFileDialog::CMSInfoFileDialog(
  55. BOOL bDialogIsOpen,
  56. HWND hOwner,
  57. LPCTSTR lpszDefaultExtension,
  58. LPCTSTR lpszExtensionFilters)
  59. :CFileDialog(bDialogIsOpen, // Open dialog or Save dialog?
  60. lpszDefaultExtension, // Default file extension
  61. NULL, // File name (don't specify)
  62. OFN_EXPLORER, // OPN Flags
  63. lpszExtensionFilters) // Filetype filter string.
  64. {
  65. m_ofn.hwndOwner = hOwner;
  66. m_ofn.nFilterIndex = 0;
  67. // default to "My Documents"
  68. GetBasePath(hOwner, m_szCurrentDirectory);
  69. m_ofn.lpstrInitialDir = m_szCurrentDirectory;
  70. }
  71. /*
  72. * we override DoModal so we can keep track of where the file was last opened from
  73. *
  74. *
  75. */
  76. INT_PTR CMSInfoFileDialog::DoModal()
  77. {
  78. INT_PTR iRC;
  79. m_ofn.lpstrInitialDir = m_szCurrentDirectory;
  80. iRC = CFileDialog::DoModal();
  81. // remember path user browsed to
  82. TCHAR szDir[MAX_PATH];
  83. TCHAR szDrive[10];
  84. int iLen;
  85. _tsplitpath(GetPathName(), szDrive, szDir, NULL, NULL);
  86. _tmakepath( m_szCurrentDirectory, szDrive, szDir, NULL, NULL);
  87. iLen = _tcslen( CMSInfoFileDialog::m_szCurrentDirectory);
  88. if ( m_szCurrentDirectory[iLen-1] == '\\' )
  89. m_szCurrentDirectory[iLen-1] = 0;
  90. return iRC;
  91. }
  92. /*
  93. * CMSInfoReportDialog - Apply settings specific to the report dialog
  94. *
  95. * History: a-jsari 10/24/97 Initial version
  96. */
  97. CMSInfoReportDialog::CMSInfoReportDialog(HWND hOwner)
  98. :CMSInfoSaveDialog(hOwner, strMSInfoReportType, strMSInfoReportTypes)
  99. {
  100. m_ofn.Flags |= OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  101. }
  102. /*
  103. * CMSInfoSaveDialog - Apply settings specific to the save dialog
  104. *
  105. * History: a-jsari 10/24/97 Initial version
  106. */
  107. CMSInfoSaveDialog::CMSInfoSaveDialog(HWND hOwner, LPCTSTR lpszDefaultExtension,
  108. LPCTSTR lpszExtensionFilters)
  109. :CMSInfoFileDialog(FALSE, hOwner, lpszDefaultExtension, lpszExtensionFilters)
  110. {
  111. m_ofn.Flags |= OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  112. }
  113. /*
  114. * CMSInfoOpenDialog - Apply settings specific to the open dialog.
  115. *
  116. * History: a-jsari 10/24/97 Initial version
  117. */
  118. CMSInfoOpenDialog::CMSInfoOpenDialog(HWND hOwner)
  119. :CMSInfoFileDialog(TRUE, hOwner, strMSInfoSaveType, strMSInfoOpenFileTypes)
  120. {
  121. m_ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  122. }
  123. /*
  124. * CMSInfoPrintDialog - Create the Print dialog
  125. *
  126. * History: a-jsari 12/8/97 Initial version
  127. */
  128. CMSInfoPrintDialog::CMSInfoPrintDialog(HWND hOwner)
  129. :CPrintDialog(FALSE, PD_SELECTION | PD_USEDEVMODECOPIES | PD_HIDEPRINTTOFILE)
  130. {
  131. m_pd.hwndOwner = hOwner;
  132. }
  133. /////////////////////////////////////////////////////////////////////////////
  134. // CFindDialog dialog
  135. /*
  136. * CFindDialog - Create the modal find dialog (which we will run in its own
  137. * thread, to make it appear modeless.
  138. *
  139. * History: a-jsari 11/28/97 Initial version.
  140. */
  141. CFindDialog::CFindDialog(CSystemInfoScope *pScope, HWND hPostWindow, HWND hwndMMCWindow)
  142. :CDialog(IDD, NULL),
  143. m_pScope(pScope),
  144. m_hPostWindow(hPostWindow),
  145. m_hMMCWindow(hwndMMCWindow),
  146. m_strSearch(_T("")),
  147. m_fRunning(FALSE)
  148. {
  149. }
  150. /*
  151. * ~CFindDialog - Destroy the find dialog.
  152. *
  153. * History: a-jsari 11/28/97 Initial version.
  154. */
  155. CFindDialog::~CFindDialog()
  156. {
  157. OnCancel();
  158. if (m_iTimer)
  159. {
  160. KillTimer(m_iTimer);
  161. m_iTimer = 0;
  162. }
  163. }
  164. /*
  165. * Create - Creates the dialog box.
  166. *
  167. * History: a-jsari 1/21/98 Initial version.
  168. */
  169. BOOL CFindDialog::Create()
  170. {
  171. DoModal();
  172. return FALSE;
  173. }
  174. /*
  175. * SetFocus - Set focus to our Search window.
  176. *
  177. * History: a-jsari 12/17/97 Initial version
  178. */
  179. CWnd *CFindDialog::SetFocus()
  180. {
  181. CWnd *pwFind;
  182. pwFind = GetDlgItem(IDC_SEARCHTERM);
  183. ASSERT(pwFind != NULL);
  184. return pwFind->SetFocus();
  185. }
  186. /*
  187. * OnInitDialog - ClassWizard generated function
  188. *
  189. * History: a-jsari 12/2/97
  190. */
  191. BOOL CFindDialog::OnInitDialog()
  192. {
  193. CDialog::OnInitDialog();
  194. ::SetWindowPos(GetSafeHwnd(), m_hPostWindow, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
  195. m_iTimer = SetTimer(1, 150, NULL);
  196. return TRUE;// return TRUE unless you set the focus to a control
  197. // EXCEPTION: OCX Property Pages should return FALSE
  198. }
  199. BEGIN_MESSAGE_MAP(CFindDialog, CDialog)
  200. //{{AFX_MSG_MAP(CFindDialog)
  201. ON_EN_CHANGE(IDC_SEARCHTERM, OnSearchTerm)
  202. ON_COMMAND(IDC_FINDNEXT, OnFindNext)
  203. ON_COMMAND(IDC_STOPFIND, OnStopFind)
  204. ON_COMMAND(IDC_NEWSEARCH, OnNewSearch)
  205. ON_WM_ACTIVATE()
  206. ON_WM_HELPINFO()
  207. ON_WM_TIMER()
  208. ON_MESSAGE(WM_HELP, OnHelp)
  209. ON_MESSAGE(WM_CONTEXTMENU, OnContextMenu)
  210. ON_WM_SETCURSOR()
  211. //}}AFX_MSG_MAP
  212. END_MESSAGE_MAP()
  213. /////////////////////////////////////////////////////////////////////////////
  214. // CFindDialog message handlers
  215. /*
  216. * OnActivate - Set our window position when we activate.
  217. *
  218. * History: a-jsari 3/4/98 Initial version
  219. */
  220. afx_msg void CFindDialog::OnActivate(UINT, CWnd *, BOOL bMinimized)
  221. {
  222. // If we aren't minimized
  223. if (bMinimized == FALSE)
  224. {
  225. // Don't do this - it makes us stay on top of ALL the windows...
  226. //
  227. // SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  228. }
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Catch the WM_HELPINFO message, so we can show context sensitive help on
  232. // the controls in the dialog box.
  233. //-----------------------------------------------------------------------------
  234. #include <afxpriv.h>
  235. static DWORD helparray[] =
  236. {
  237. IDC_SEARCHTERM, 1000001,
  238. IDC_FINDIN, 1000002,
  239. IDC_CATEGORYCHECK, 1000003,
  240. IDC_FINDNEXT, 1000004,
  241. IDC_STOPFIND, 1000005,
  242. IDC_NEWSEARCH, 1000006,
  243. IDCANCEL, 1000007,
  244. 0, 0
  245. };
  246. afx_msg BOOL CFindDialog::OnHelpInfo(HELPINFO * pHelpInfo)
  247. {
  248. if (pHelpInfo && (pHelpInfo->iContextType == HELPINFO_WINDOW))
  249. ::WinHelp((HWND)pHelpInfo->hItemHandle, TEXT("msinfo32.hlp"), HELP_WM_HELP, (DWORD_PTR)helparray);
  250. return TRUE;
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Every time we get a timer message, check to see if the find window is
  254. // behind the MMC window. If it is, bring it forward. What we really want
  255. // is an application always on top effect, but this seems to be the way to
  256. // get this (since we can't change MMC).
  257. //
  258. // I hate this.
  259. //-----------------------------------------------------------------------------
  260. afx_msg void CFindDialog::OnTimer(UINT)
  261. {
  262. if (m_hMMCWindow == NULL)
  263. return;
  264. for (HWND hwndWalk = GetSafeHwnd(); hwndWalk != NULL; hwndWalk = ::GetNextWindow(hwndWalk, GW_HWNDPREV))
  265. if (hwndWalk == m_hMMCWindow)
  266. {
  267. // This is how we bring the find window to the top. Using wndTop with
  268. // SetWindowPos doesn't seem to do anything.
  269. SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  270. SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
  271. break;
  272. }
  273. }
  274. LONG CFindDialog::OnHelp(WPARAM wParam, LPARAM lParam)
  275. {
  276. LONG lResult = 0;
  277. if (lParam)
  278. ::WinHelp((HWND)(((LPHELPINFO)lParam)->hItemHandle), TEXT("msinfo32.hlp"), HELP_WM_HELP, (DWORD_PTR)helparray);
  279. return lResult;
  280. }
  281. LONG CFindDialog::OnContextMenu(WPARAM wParam, LPARAM lParam)
  282. {
  283. LONG lResult = 0;
  284. ::WinHelp((HWND)wParam, TEXT("msinfo32.hlp"), HELP_CONTEXTMENU,(DWORD_PTR)helparray);
  285. return lResult;
  286. }
  287. /*
  288. * OnSetCursor - Set our cursor depending on whether we are executing the find.
  289. *
  290. * History: a-jsari 3/21/98 Initial version
  291. */
  292. afx_msg BOOL CFindDialog::OnSetCursor(CWnd *pWndOther, UINT nHitTest, UINT message)
  293. {
  294. static HCURSOR hcPointerHourglass = NULL;
  295. // Set the pointer & hourglass cursor.
  296. if (m_fRunning) {
  297. if (hcPointerHourglass == NULL) {
  298. hcPointerHourglass = ::LoadCursor(NULL, IDC_APPSTARTING);
  299. #ifdef DEBUG
  300. DWORD dwError = ::GetLastError();
  301. #endif
  302. ASSERT(hcPointerHourglass != NULL);
  303. }
  304. ::SetCursor(hcPointerHourglass);
  305. return TRUE;
  306. } else return CDialog::OnSetCursor(pWndOther, nHitTest, message);
  307. }
  308. /*
  309. * OnCancel - Destroy the window when the cancel button is selected.
  310. *
  311. * History: a-jsari 12/2/97
  312. */
  313. afx_msg void CFindDialog::OnCancel()
  314. {
  315. OnStopFind();
  316. ::PostQuitMessage(0);
  317. // Exit the containing UI thread.
  318. m_pScope->CloseFindWindow();
  319. }
  320. /*
  321. * OnFindNext - Execute the find next operation, when the "Find Next" button
  322. * is clicked or when a return is hit in the "Find In".
  323. *
  324. * History: a-jsari 12/11/97
  325. */
  326. afx_msg void CFindDialog::OnFindNext()
  327. {
  328. int wCount;
  329. long lFindState;
  330. // Save our last search.
  331. CString strLast = m_strSearch;
  332. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  333. // Save our current search
  334. wCount = GetDlgItemText(IDC_SEARCHTERM, m_strSearch);
  335. ASSERT(wCount != 0);
  336. // Enable the Stop button (Disabled in FindComplete).
  337. CButton *pwStop = reinterpret_cast<CButton *>(GetDlgItem(IDC_STOPFIND));
  338. ASSERT(pwStop != NULL);
  339. pwStop->EnableWindow(TRUE);
  340. // Disable our button so we can't activate it while we're running.
  341. // (Enabled in FindComplete)
  342. CButton *pwFindNext = reinterpret_cast<CButton *>(GetDlgItem(IDC_FINDNEXT));
  343. ASSERT(pwFindNext != NULL);
  344. pwFindNext->EnableWindow(FALSE);
  345. // Set the flag indicating whether we search only category names.
  346. CButton *pwCheck = reinterpret_cast<CButton *>(GetDlgItem(IDC_CATEGORYCHECK));
  347. ASSERT(pwCheck != NULL);
  348. lFindState = pwCheck->GetCheck() ? CDataSource::FIND_OPTION_CATEGORY_ONLY : 0;
  349. // Set the flag indicating whether we search the selected category alone.
  350. pwCheck = reinterpret_cast<CButton *>(GetDlgItem(IDC_FINDIN));
  351. ASSERT(pwCheck != NULL);
  352. lFindState |= (pwCheck->GetCheck()) ? CDataSource::FIND_OPTION_ONE_CATEGORY : 0;
  353. // Set the flag indicating whether we are repeating a previous search.
  354. if (::_tcsicmp((LPCTSTR)strLast, (LPCTSTR)m_strSearch) == 0)
  355. lFindState |= CDataSource::FIND_OPTION_REPEAT_SEARCH;
  356. m_fRunning = TRUE;
  357. // In order to perform the find multi-threaded and allow a stop operation,
  358. // we post a custom message to a hidden window attached to the main MMC window
  359. // created in CSystemInfoScope::Initialize
  360. // Our custom WindowProc processes this message, running Find in the main
  361. // window's UI thread.
  362. ::PostMessage(m_hPostWindow, WM_MSINFO_FIND, (WPARAM)m_pScope, (LPARAM) lFindState);
  363. }
  364. /*
  365. * OnNewSearch - Clear the controls
  366. *
  367. * History: a-jsari 12/11/97
  368. */
  369. afx_msg void CFindDialog::OnNewSearch()
  370. {
  371. ResetSearch();
  372. // Clear the text box.
  373. SetDlgItemText(IDC_SEARCHTERM, _T(""));
  374. // Clear the category check box.
  375. CButton *pwCheck = (CButton *) GetDlgItem(IDC_CATEGORYCHECK);
  376. ASSERT(pwCheck != NULL);
  377. pwCheck->SetCheck(0);
  378. // Clear the Restrict Search check box
  379. pwCheck = (CButton *) GetDlgItem(IDC_FINDIN);
  380. ASSERT(pwCheck != NULL);
  381. pwCheck->SetCheck(0);
  382. // Refocus on the text box.
  383. SetFocus();
  384. }
  385. /*
  386. * OnSearchTerm - Callback for when the Search edit box is changed.
  387. *
  388. * History: a-jsari 12/11/97 Initial version.
  389. */
  390. afx_msg void CFindDialog::OnSearchTerm()
  391. {
  392. CString strSearch;
  393. CWnd *wControl;
  394. int wSearch;
  395. // Get the length of the text box text.
  396. wSearch = GetDlgItemText(IDC_SEARCHTERM, strSearch);
  397. wControl = GetDlgItem(IDC_FINDNEXT);
  398. wControl->EnableWindow(wSearch > 0);
  399. wControl = GetDlgItem(IDC_SEARCHTERM);
  400. wControl->SetFocus();
  401. }
  402. /*
  403. * OnStopFind - MULTI-THREADED Callback for the "Stop Find" button, intended
  404. * to be called while the find is running in the main window thread.
  405. *
  406. * History: a-jsari 1/19/98 Initial version
  407. */
  408. afx_msg void CFindDialog::OnStopFind()
  409. {
  410. // This will abort the find operation in the main thread which will
  411. // then call FindComplete.
  412. m_pScope->StopFind();
  413. }
  414. /*
  415. * FindComplete - Reset the find dialog upon completion, either by abort or
  416. * by normal completion.
  417. *
  418. * History: a-jsari 2/4/98 Initial version.
  419. */
  420. void CFindDialog::FindComplete()
  421. {
  422. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  423. m_fRunning = FALSE;
  424. // Enable our Find Button
  425. CButton *pwFindNext = reinterpret_cast<CButton *>(GetDlgItem(IDC_FINDNEXT));
  426. ASSERT(pwFindNext != NULL);
  427. CString strSearch;
  428. int wSearch = GetDlgItemText(IDC_SEARCHTERM, strSearch);
  429. pwFindNext->EnableWindow(wSearch > 0);
  430. // Disable the Stop Button
  431. CButton *pwStop = reinterpret_cast<CButton *>(GetDlgItem(IDC_STOPFIND));
  432. ASSERT(pwStop != NULL);
  433. pwStop->EnableWindow(FALSE);
  434. OnActivate(0, NULL, FALSE);
  435. }
  436. /*
  437. * ResetSearch - Resets the search so that the next search will register as
  438. * new.
  439. *
  440. * History: a-jsari 2/20/98 Initial version.
  441. */
  442. void CFindDialog::ResetSearch()
  443. {
  444. m_strSearch = _T("");
  445. }
  446. IMPLEMENT_DYNCREATE(CFindThread, CWinThread)
  447. /*
  448. * CFindThread - Default constructor
  449. *
  450. * History: a-jsari 1/19/98 Initial version.
  451. */
  452. CFindThread::CFindThread()
  453. :m_pdlgFind(NULL), m_pScope(NULL), m_pDataSource(NULL)
  454. {
  455. }
  456. /*
  457. * ~CFindThread - Our destructor.
  458. *
  459. * History: a-jsari 1/19/98 Initial version.
  460. */
  461. CFindThread::~CFindThread()
  462. {
  463. }
  464. /*
  465. * SetScope - Sets the scope item for the Find Dialog.
  466. *
  467. * History: a-jsari 1/21/98 Initial version.
  468. */
  469. void CFindThread::SetScope(CSystemInfoScope *pScope)
  470. {
  471. ASSERT(pScope != NULL);
  472. m_pScope = pScope;
  473. }
  474. /*
  475. * SetParent - Sets the parent window for the Find Dialog.
  476. *
  477. * History: a-jsari 1/21/98 Initial version.
  478. */
  479. void CFindThread::SetParent(HWND hParent, HWND hMMC)
  480. {
  481. m_hParentWindow = hParent;
  482. m_hMMCWindow = hMMC;
  483. }
  484. /*
  485. * Activate - Reactivate the thread after it's been deselected.
  486. *
  487. * History: a-jsari 1/22/98 Initial version.
  488. */
  489. void CFindThread::Activate()
  490. {
  491. ASSERT(m_pdlgFind != NULL);
  492. m_pdlgFind->OnActivate(0, NULL, FALSE);
  493. }
  494. /*
  495. * InitInstance - Starts the thread and the dialog object.
  496. *
  497. * History: a-jsari 1/19/98 Initial version
  498. */
  499. BOOL CFindThread::InitInstance()
  500. {
  501. // else increment some instance pointer?
  502. // Create our new Modal find dialog.
  503. m_pdlgFind = new CFindDialog(m_pScope, m_hParentWindow, m_hMMCWindow);
  504. ASSERT(m_pdlgFind != NULL);
  505. if (m_pdlgFind == NULL) ::AfxThrowMemoryException();
  506. m_pdlgFind->Create();
  507. // We won't get here until our dialog is exiting, since create calls
  508. // DoModal(), which blocks.
  509. return TRUE;
  510. }
  511. /*
  512. * ExitInstance - Ends the thread, destroying the dialog object.
  513. *
  514. * History: a-jsari 1/19/98 Inital version
  515. */
  516. int CFindThread::ExitInstance()
  517. {
  518. delete m_pdlgFind;
  519. m_pdlgFind = NULL;
  520. return CWinThread::ExitInstance();
  521. }
  522. /*
  523. * RemoteQuit - Ends the thread from an alternate thread, by sending the appropriate
  524. * message to our dialog, waiting for its exit.
  525. *
  526. * History: a-jsari 1/29/98 Initial version
  527. */
  528. void CFindThread::RemoteQuit()
  529. {
  530. const DWORD dwWaitTimeout = 100000; // 100 ms, Presumably long enough.
  531. DWORD dwResult;
  532. m_pdlgFind->SendMessage(WM_COMMAND, IDCANCEL);
  533. // Wait for the thread to exit, avoiding its using an object destroyed
  534. // by our main thread in CSystemInfoScope.
  535. dwResult = ::WaitForSingleObject(m_hThread, dwWaitTimeout);
  536. ASSERT(dwResult == WAIT_OBJECT_0);
  537. }