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.

710 lines
15 KiB

  1. /*++
  2. Copyright (c) 1994-1998 Microsoft Corporation
  3. Module Name :
  4. dirbrows.cpp
  5. Abstract:
  6. Directory Browser Dialog. Allow browsing for directories only.
  7. optionally allows UNC conversions for remote paths.
  8. Author:
  9. Ronald Meijer (ronaldm)
  10. Project:
  11. Internet Services Manager
  12. Revision History:
  13. --*/
  14. //
  15. // Include Files
  16. //
  17. #include "stdafx.h"
  18. #include "comprop.h"
  19. #include "dirbrows.h"
  20. #include <dlgs.h>
  21. #ifdef _DEBUG
  22. #undef THIS_FILE
  23. static char BASED_CODE THIS_FILE[] = __FILE__;
  24. #endif
  25. static
  26. int
  27. BrowseCallbackProc(
  28. IN HWND hwnd,
  29. IN UINT uMsg,
  30. IN LPARAM lParam,
  31. IN LPARAM lpData
  32. )
  33. /*++
  34. Routine Description:
  35. Callback function for the folder browser
  36. Arguments:
  37. hwnd : Handle to the browse dialog box. The callback function can
  38. send the following messages to this window:
  39. BFFM_ENABLEOK Enables the OK button if the wParam parameter
  40. is nonzero or disables it if wParam is zero.
  41. BFFM_SETSELECTION Selects the specified folder. The lParam
  42. parameter is the PIDL of the folder to select
  43. if wParam is FALSE, or it is the path of the
  44. folder otherwise.
  45. BFFM_SETSTATUSTEXT Sets the status text to the null-terminated
  46. string specified by the lParam parameter.
  47. uMsg : Value identifying the event. This parameter can be one of the
  48. following values:
  49. 0 Initialize dir path. lParam is the path.
  50. BFFM_INITIALIZED The browse dialog box has finished
  51. initializing. lpData is NULL.
  52. BFFM_SELCHANGED The selection has changed. lpData
  53. is a pointer to the item identifier list for
  54. the newly selected folder.
  55. lParam : Message-specific value. For more information, see the
  56. description of uMsg.
  57. lpData : Application-defined value that was specified in the lParam
  58. member of the BROWSEINFO structure.
  59. Return Value:
  60. 0
  61. --*/
  62. {
  63. static LPCTSTR lpstrDir = NULL;
  64. switch(uMsg)
  65. {
  66. case 0:
  67. lpstrDir = (LPCTSTR)lParam;
  68. break;
  69. case BFFM_INITIALIZED:
  70. //
  71. // Dialog initialized -- select desired folder
  72. //
  73. if (lpstrDir != NULL)
  74. {
  75. ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrDir);
  76. }
  77. break;
  78. }
  79. return 0;
  80. }
  81. CDirBrowseDlg::CDirBrowseDlg(
  82. IN CWnd * pParent OPTIONAL,
  83. IN LPCTSTR lpszInitialDir OPTIONAL
  84. )
  85. /*++
  86. Routine Description:
  87. Constructor for directory browser dialog
  88. Arguments:
  89. CWnd * pParent : Parent window or NULL
  90. LPCTSTR lpszInitialDir : Initial directory, or NULL for current directory
  91. Return Value:
  92. N/A
  93. --*/
  94. : m_strInitialDir(lpszInitialDir)
  95. {
  96. VERIFY(m_strTitle.LoadString(IDS_BROWSE_DIRECTORY));
  97. m_bi.pidlRoot = NULL;
  98. m_bi.hwndOwner = pParent ? pParent->m_hWnd : NULL;
  99. m_bi.pszDisplayName = m_szBuffer;
  100. m_bi.lpszTitle = m_strTitle;
  101. m_bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS,
  102. m_bi.lpfn = BrowseCallbackProc;
  103. m_bi.lParam = 0;
  104. //
  105. // Let the callback function know the default dir is
  106. //
  107. lpszInitialDir = !m_strInitialDir.IsEmpty()
  108. ? (LPCTSTR)m_strInitialDir
  109. : NULL;
  110. BrowseCallbackProc(m_bi.hwndOwner, 0, (LPARAM)lpszInitialDir, NULL);
  111. }
  112. CDirBrowseDlg::~CDirBrowseDlg()
  113. /*++
  114. Routine Description:
  115. Destructor for directory browser dialog
  116. Arguments:
  117. N/A
  118. Return Value:
  119. N/A
  120. --*/
  121. {
  122. if (m_bi.pidlRoot != NULL)
  123. {
  124. LPITEMIDLIST pidl = (LPITEMIDLIST)m_bi.pidlRoot;
  125. //
  126. // Free using shell allocator
  127. //
  128. LPMALLOC pMalloc;
  129. if (::SHGetMalloc(&pMalloc) == NOERROR)
  130. {
  131. pMalloc->Free(pidl);
  132. pMalloc->Release();
  133. }
  134. }
  135. }
  136. /* virtual */
  137. int
  138. CDirBrowseDlg::DoModal()
  139. /*++
  140. Routine Description:
  141. Display the browser dialog, and fill in the selected directory path.
  142. Arguments:
  143. None
  144. Return Value:
  145. IDOK if the OK button was pressed, IDCANCEL otherwise.
  146. --*/
  147. {
  148. BOOL fSelectionMade = FALSE;
  149. //
  150. // Get the Shell's default allocator
  151. //
  152. LPMALLOC pMalloc;
  153. if (::SHGetMalloc(&pMalloc) == NOERROR)
  154. {
  155. LPITEMIDLIST pidl;
  156. if ((pidl = ::SHBrowseForFolder(&m_bi)) != NULL)
  157. {
  158. if (::SHGetPathFromIDList(pidl, m_szBuffer))
  159. {
  160. fSelectionMade = TRUE;
  161. }
  162. else
  163. {
  164. //
  165. // OK Pressed, but no path found
  166. //
  167. ::AfxMessageBox(IDS_BAD_BROWSE);
  168. }
  169. //
  170. // Free the PIDL allocated by SHBrowseForFolder.
  171. //
  172. pMalloc->Free(pidl);
  173. }
  174. //
  175. // Release the shell's allocator.
  176. //
  177. pMalloc->Release();
  178. }
  179. return fSelectionMade ? IDOK : IDCANCEL;
  180. }
  181. LPCTSTR
  182. CDirBrowseDlg::GetFullPath(
  183. OUT CString & strName,
  184. IN BOOL fConvertToUNC
  185. ) const
  186. /*++
  187. Routine Description:
  188. Get the full path selected. Optionally allow a remote path to be
  189. converted to a UNC path.
  190. Arguments:
  191. CString & strName : String in which to return the directory path
  192. BOOL fConvertToUNC : If TRUE, then if the drive selected is a network
  193. drive, convert the path to a UNC path.
  194. Return Value:
  195. A pointer to the directory path string or NULL in case of error.
  196. Notes:
  197. This function should be called only after the dialog has been dismissed.
  198. --*/
  199. {
  200. LPCTSTR lp = NULL;
  201. try
  202. {
  203. strName = m_szBuffer;
  204. lp = strName;
  205. if (fConvertToUNC && lp != NULL)
  206. {
  207. //
  208. // If it's network drive, convert it to a UNC path
  209. //
  210. CString strDrive, strUNC;
  211. if (IsNetworkPath(strName, &strDrive, &strUNC))
  212. {
  213. strUNC += (lp + 2);
  214. strName = strUNC;
  215. }
  216. /*
  217. ASSERT(strName[1] == _T(':'));
  218. if (strName[1] == _T(':'))
  219. {
  220. TCHAR szDrive[] = _T("?:");
  221. //
  222. // Fill in actual drive letter
  223. //
  224. szDrive[0] = strName[0];
  225. if (::GetDriveType(szDrive) == DRIVE_REMOTE)
  226. {
  227. //
  228. // Yes, it's remote. Replace drive letter
  229. // with UNC path
  230. //
  231. TCHAR szUNC[_MAX_PATH + 1];
  232. DWORD dwSize = _MAX_PATH;
  233. TRACEEOLID("Converting drive path to UNC");
  234. if (::WNetGetConnection(szDrive,
  235. szUNC, &dwSize) == NO_ERROR)
  236. {
  237. ::_tcscat(szUNC, lp + 2);
  238. strName = szUNC;
  239. }
  240. }
  241. }
  242. */
  243. lp = strName;
  244. }
  245. }
  246. catch(CMemoryException * e)
  247. {
  248. TRACEEOLID("!!!exception getting path");
  249. strName.Empty();
  250. e->ReportError();
  251. e->Delete();
  252. }
  253. return lp;
  254. }
  255. #if 0
  256. // ***************************************************************************
  257. // * *
  258. // * The code below is pre-WIN95 shell directory browsing. It is OBSOLETE *
  259. // * *
  260. // ***************************************************************************
  261. //
  262. // new look commdlg style (not defined on older systems)
  263. //
  264. #ifndef OFN_EXPLORER
  265. #define OFN_EXPLORER 0x00080000
  266. #endif // OFN_EXPLORER
  267. #ifndef _COMSTATIC
  268. //
  269. // Externally available DLL handle
  270. //
  271. extern HINSTANCE hDLLInstance;
  272. #endif // _COMSTATIC
  273. CDirBrowseDlg::CDirBrowseDlg(
  274. IN CWnd * pParent OPTIONAL,
  275. IN LPCTSTR lpszInitialDir OPTIONAL,
  276. IN BOOL bOpenFileDialog,
  277. IN LPCTSTR lpszDefExt OPTIONAL,
  278. IN DWORD dwFlags,
  279. IN LPCTSTR lpszFilter OPTIONAL
  280. )
  281. /*++
  282. Routine Description:
  283. Constructor for directory browser dialog
  284. Arguments:
  285. CWnd * pParent : Parent window or NULL
  286. LPCTSTR lpszInitialDir : Initial directory, or NULL for current directory
  287. BOOL bOpenFileDialog : TRUE for open dialog, FALSE for save dialog
  288. LPCTSTR lpszDefExt : Default extention string or NULL
  289. DWORD dwFlags : OPENFILE flags
  290. LPCTSTR lpszFilter : File filters
  291. Return Value:
  292. N/A
  293. --*/
  294. //
  295. // Use a dummy filename here to allow CFileOpenDialog to
  296. // dismiss itself. If this matches an existing directory
  297. // name we're in trouble, so make that an unlikely event.
  298. // It would be nice if there were a file name that
  299. // cannot exist as a directory name.
  300. //
  301. : CFileDialog(
  302. bOpenFileDialog,
  303. lpszDefExt,
  304. _T(" JU$NK#\t^"),
  305. dwFlags,
  306. lpszFilter,
  307. pParent
  308. ),
  309. m_strNewDirectoryName()
  310. {
  311. #if 0 // Keep Class Wizard happy
  312. //{{AFX_DATA_INIT(CDirBrowseDlg)
  313. m_strNewDirectoryName = _T("");
  314. //}}AFX_DATA_INIT
  315. #endif // 0
  316. m_ofn.Flags |= OFN_ENABLETEMPLATE | OFN_NONETWORKBUTTON;
  317. #ifdef _COMSTATIC
  318. m_ofn.hInstance = ::AfxGetResourceHandle();
  319. #else
  320. m_ofn.hInstance = hDLLInstance;
  321. #endif // _COMSTATIC
  322. m_ofn.lpstrInitialDir = lpszInitialDir;
  323. m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_DIRBROWSE);
  324. //
  325. // Explicitly re-set the explorer flag which is set by
  326. // default
  327. //
  328. m_ofn.Flags &= (~OFN_EXPLORER);
  329. }
  330. CDirBrowseDlg::~CDirBrowseDlg()
  331. /*++
  332. Routine Description:
  333. Destructor for directory browser dialog
  334. Arguments:
  335. N/A
  336. Return Value:
  337. N/A
  338. --*/
  339. {
  340. }
  341. /* protected */
  342. void
  343. CDirBrowseDlg::DoDataExchange(
  344. IN CDataExchange * pDX
  345. )
  346. /*++
  347. Routine Description:
  348. Initialise/Store control data
  349. Arguments:
  350. CDataExchange * pDX - DDX/DDV control structure
  351. Return Value:
  352. None
  353. --*/
  354. {
  355. CFileDialog::DoDataExchange(pDX);
  356. //{{AFX_DATA_MAP(CDirBrowseDlg)
  357. DDX_Control(pDX, IDC_EDIT_NEW_DIRECTORY_NAME, m_edit_NewDirectoryName);
  358. DDX_Control(pDX, stc1, m_static_stc1);
  359. DDX_Control(pDX, IDC_STATIC_DIR_NAME, m_static_stc2);
  360. DDX_Text(pDX, IDC_EDIT_NEW_DIRECTORY_NAME, m_strNewDirectoryName);
  361. DDV_MaxChars(pDX, m_strNewDirectoryName, _MAX_PATH);
  362. //}}AFX_DATA_MAP
  363. }
  364. //
  365. // Message Map
  366. //
  367. BEGIN_MESSAGE_MAP(CDirBrowseDlg, CFileDialog)
  368. //{{AFX_MSG_MAP(CDirBrowseDlg)
  369. //}}AFX_MSG_MAP
  370. END_MESSAGE_MAP()
  371. //
  372. // Message Handlers
  373. //
  374. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  375. BOOL
  376. CDirBrowseDlg::OnInitDialog()
  377. /*++
  378. Routine Description:
  379. WM_INITDIALOG handler. Initialize the dialog.
  380. Arguments:
  381. None.
  382. Return Value:
  383. TRUE if no focus is to be set automatically, FALSE if the focus
  384. is already set.
  385. --*/
  386. {
  387. CFileDialog::OnInitDialog();
  388. return TRUE;
  389. }
  390. LPCTSTR
  391. CDirBrowseDlg::GetFullPath(
  392. OUT CString & strName,
  393. IN BOOL fConvertToUNC
  394. ) const
  395. /*++
  396. Routine Description:
  397. Get the full path selected.
  398. Arguments:
  399. CString & strName : String in which to return the directory path
  400. BOOL fConvertToUNC : If TRUE, then if the drive selected is a network
  401. drive, convert the path to a UNC path.
  402. Return Value:
  403. A pointer to the directory path string or NULL in case of error.
  404. Notes:
  405. This function should be called only after the dialog has been dismissed.
  406. --*/
  407. {
  408. LPCTSTR lp = NULL;
  409. try
  410. {
  411. m_ofn.lpstrFile[m_ofn.nFileOffset-1] = _T('\0');
  412. strName = m_ofn.lpstrFile;
  413. if (!m_strNewDirectoryName.IsEmpty())
  414. {
  415. //
  416. // Append the name of the newly created directory, unless
  417. // it has a colon or backslash in it, in which case it is
  418. // treated as a fully qualified path name
  419. //
  420. if (m_strNewDirectoryName.Find(_T(':')) != -1 ||
  421. m_strNewDirectoryName.Find(_T('\\')) != -1)
  422. {
  423. strName = m_strNewDirectoryName;
  424. }
  425. else
  426. {
  427. strName += _T("\\");
  428. strName += m_strNewDirectoryName;
  429. }
  430. }
  431. lp = strName;
  432. if (fConvertToUNC && lp != NULL)
  433. {
  434. //
  435. // If it's network drive, convert it to a UNC path
  436. //
  437. CString strDrive, strUNC;
  438. if (IsNetworkPath(strName, &strDrive, &strUNC))
  439. {
  440. strUNC += (lp + 2);
  441. strName = strUNC;
  442. }
  443. /*
  444. ASSERT(strName[1] == _T(':'));
  445. if (strName[1] == _T(':'))
  446. {
  447. TCHAR szDrive[] = _T("?:");
  448. //
  449. // Fill in actual drive letter
  450. //
  451. szDrive[0] = strName[0];
  452. if (::GetDriveType(szDrive) == DRIVE_REMOTE)
  453. {
  454. //
  455. // Yes, it's remote. Replace drive letter
  456. // with UNC path
  457. //
  458. TCHAR szUNC[_MAX_PATH + 1];
  459. DWORD dwSize = _MAX_PATH;
  460. TRACEEOLID("Converting drive path to UNC");
  461. if (::WNetGetConnection(szDrive,
  462. szUNC, &dwSize) == NO_ERROR)
  463. {
  464. ::_tcscat(szUNC, lp + 2);
  465. strName = szUNC;
  466. }
  467. }
  468. }
  469. */
  470. lp = strName;
  471. }
  472. }
  473. catch(CMemoryException * e)
  474. {
  475. TRACEEOLID("!!!exception getting path");
  476. strName.Empty();
  477. e->ReportError();
  478. e->Delete();
  479. }
  480. return lp;
  481. }
  482. /* protected */
  483. void
  484. CDirBrowseDlg::OnOK()
  485. /*++
  486. Routine Description:
  487. Handler for IDOK. Called when the OK button has been pressed.
  488. At this point, set the directory path string to the selected
  489. string. If a new directory is entered, create it now. Do not
  490. dismiss the dialog if the path is invalid.
  491. Arguments:
  492. None
  493. Return Value:
  494. None
  495. --*/
  496. {
  497. //
  498. // Update control data
  499. //
  500. if (UpdateData())
  501. {
  502. //
  503. // If a new directory name was entered, create it
  504. // here.
  505. //
  506. if (!m_strNewDirectoryName.IsEmpty())
  507. {
  508. if (!::CreateDirectory(m_strNewDirectoryName, NULL))
  509. {
  510. //
  511. // Failed to create the directory -- let the user
  512. // know why, and don't dismiss the dialog box
  513. //
  514. ::DisplayMessage(::GetLastError());
  515. m_edit_NewDirectoryName.SetSel(0,-1);
  516. return;
  517. }
  518. }
  519. //
  520. // Dismiss the dialog.
  521. //
  522. CFileDialog::OnOK();
  523. }
  524. }
  525. #endif // 0 (Obsolete)