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.

749 lines
30 KiB

  1. //
  2. // BrowseDir.cpp
  3. //
  4. // Functionality for the "Browse Directory" dialog.
  5. // Requires dialog resource IDD_BROWSEDIRECTORY.
  6. //
  7. // History:
  8. //
  9. // 10/04/95 KenSh Created
  10. // 10/09/95 KenSh Fixed bugs, removed globals and statics
  11. //
  12. #include "stdafx.h"
  13. #include <dlgs.h>
  14. #include <direct.h>
  15. //*** Custom window messages
  16. //
  17. #define CM_UPDATEEDIT (WM_USER + 42) // Update text in the edit (sent to the dialog)
  18. //*** Dialog control IDs
  19. //
  20. #define IDC_FILENAME edt1 // Edit box w/ current directory
  21. #define IDC_FILELIST lst2 // Listbox with current directory hierarchy
  22. #define IDC_DRIVECOMBO cmb2 // Combo-box with current drive
  23. #define IDC_NETWORK psh14 // Network button (added at runtime)
  24. //*** Window property names
  25. //
  26. const TCHAR c_szOFNProp[] = _T("OFNStruct");
  27. const TCHAR c_szRedrawProp[] = _T("Redraw");
  28. //*** Globals
  29. //
  30. // Note: Use of thse globals assumes that any multiple threads using
  31. // our subclass at the same time always have the same original edit/
  32. // combo window procs. I think this is true.
  33. //
  34. WNDPROC g_pfnPrevEditProc; // original edit proc (before subclass)
  35. WNDPROC g_pfnPrevComboProc; // original combo proc (before subclass)
  36. //*** Local function declarations
  37. //
  38. BOOL CALLBACK BrowseDirDlgHook( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
  39. BOOL BrowseDir_OnOK( HWND hwnd );
  40. // This struct is used internally and kept as a window property,
  41. // in lieu of using static variables or MFC.
  42. typedef struct _OFNINFO
  43. {
  44. OPENFILENAME ofn; // OFN struct passed to GetOpenFileName
  45. TCHAR szLastDirName[_MAX_PATH]; // last known good directory
  46. BOOL fAllowSetText; // should we allow WM_SETTEXT for the Edit
  47. // BOOL fNetworking; // is Connect Network Drive dialog open
  48. } OFNINFO, *LPOFNINFO;
  49. //----------------------------------------------------------------------------
  50. // Procedure BrowseForDirectory
  51. //
  52. // Purpose Displays a dialog that lets the user choose a directory
  53. // name, either local or UNC.
  54. //
  55. // Parameters hwndParent Parent window for the dialog
  56. // pszInitialDir Directory to use as the default
  57. // pszBuf Where to store the answer
  58. // cchBuf Number of characters in this buffer
  59. // pszDialogTitle Title for the dialog
  60. //
  61. // Returns nonzero if successful, zero if not. If successful, pszBuf
  62. // will be filled with the full pathname of the chosen directory.
  63. //
  64. // History 10/06/95 KenSh Created
  65. // 10/09/95 KenSh Use lCustData member instead of global
  66. //
  67. CString strSelectDir;
  68. BOOL BrowseForDirectory(
  69. HWND hwndParent,
  70. LPCTSTR pszInitialDir,
  71. LPTSTR pszBuf,
  72. int cchBuf,
  73. LPCTSTR pszDialogTitle,
  74. BOOL bRemoveTrailingBackslash )
  75. {
  76. TCHAR szInitialDir[MAX_PATH];
  77. OFNINFO ofnInfo;
  78. pszBuf[0] = _T('\0');
  79. // Prepare the initial directory... add a backslash if it's
  80. // a 2-character path
  81. _tcscpy( szInitialDir, pszInitialDir );
  82. if( !szInitialDir[2] )
  83. {
  84. szInitialDir[2] = _T('\\');
  85. szInitialDir[3] = _T('\0');
  86. }
  87. if( pszDialogTitle )
  88. {
  89. ofnInfo.ofn.lpstrTitle = pszDialogTitle;
  90. }
  91. else
  92. {
  93. MyLoadString( IDS_SELECT_DIR, strSelectDir );
  94. ofnInfo.ofn.lpstrTitle = (LPCTSTR)strSelectDir;
  95. }
  96. ofnInfo.ofn.lStructSize = sizeof(OPENFILENAME);
  97. ofnInfo.ofn.hwndOwner = hwndParent;
  98. ofnInfo.ofn.hInstance = (HINSTANCE) g_MyModuleHandle;
  99. ofnInfo.ofn.lpstrFilter = NULL;
  100. ofnInfo.ofn.lpstrCustomFilter = NULL;
  101. ofnInfo.ofn.nMaxCustFilter = 0;
  102. ofnInfo.ofn.nFilterIndex = 0;
  103. ofnInfo.ofn.lpstrFile = pszBuf;
  104. ofnInfo.ofn.nMaxFile = cchBuf;
  105. ofnInfo.ofn.lpstrFileTitle = NULL;
  106. ofnInfo.ofn.nMaxFileTitle = 0;
  107. ofnInfo.ofn.lpstrInitialDir = szInitialDir;
  108. ofnInfo.ofn.nFileOffset = 0;
  109. ofnInfo.ofn.nFileExtension = 0;
  110. ofnInfo.ofn.lpstrDefExt = NULL;
  111. ofnInfo.ofn.lCustData = (LPARAM)&ofnInfo;
  112. ofnInfo.ofn.lpfnHook = (LPOFNHOOKPROC)BrowseDirDlgHook;
  113. ofnInfo.ofn.lpTemplateName = MAKEINTRESOURCE( IDD_BROWSEDIRECTORY );
  114. ofnInfo.ofn.Flags = OFN_ENABLEHOOK | OFN_PATHMUSTEXIST |
  115. OFN_NONETWORKBUTTON | OFN_ENABLETEMPLATE |
  116. OFN_HIDEREADONLY;
  117. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("comdlg32:GetOpenFileName().Start.")));
  118. int nResult = ::GetOpenFileName( &ofnInfo.ofn );
  119. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("comdlg32:GetOpenFileName().End.")));
  120. DWORD dw = 0;
  121. if (nResult == 0)
  122. {
  123. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("comdlg32:CommDlgExtendedError().Start.")));
  124. dw = CommDlgExtendedError();
  125. iisDebugOut((LOG_TYPE_TRACE_WIN32_API, _T("comdlg32:CommDlgExtendedError().End.")));
  126. }
  127. return (BOOL)( IDOK == nResult );
  128. }
  129. //----------------------------------------------------------------------------
  130. // Procedure pszSkipDriveSpec
  131. //
  132. // Purpose Returns a pointer to whatever comes after the drive part
  133. // of a filename. For example:
  134. // c:\foo\bar.bat \\server\share\file.txt
  135. // ^ ^
  136. //
  137. // Returns Pointer to the appropriate part of the string, or a pointer
  138. // to the end of the string if it's not in the right format
  139. //
  140. // History 10/06/95 KenSh Created
  141. //
  142. LPTSTR pszSkipDriveSpec( LPTSTR pszPathName )
  143. {
  144. LPTSTR pch = NULL;
  145. if( pszPathName[0] == _T('\\') && pszPathName[1] == _T('\\') )
  146. {
  147. pch = _tcschr(pszPathName+2, _T('\\'));
  148. if( NULL != pch)
  149. {
  150. LPTSTR pchResult;
  151. pchResult = _tcschr( pch, _T('\\') );
  152. if( pchResult )
  153. {
  154. pchResult = _tcschr( pchResult+1, _T('\\') );
  155. }
  156. if( pchResult )
  157. {
  158. return pchResult;
  159. }
  160. else
  161. {
  162. return _tcschr( pch, _T('\0') );
  163. }
  164. }
  165. else
  166. {
  167. return _tcschr( pszPathName, _T('\0') );
  168. }
  169. }
  170. else
  171. {
  172. pch = _tcschr( pszPathName, _T(':') );
  173. if( pch )
  174. {
  175. return _tcsinc(pch);
  176. }
  177. else
  178. {
  179. return _tcschr( pszPathName, _T('\0') );
  180. }
  181. }
  182. }
  183. //----------------------------------------------------------------------------
  184. // Procedure BrowseDirEditProc
  185. //
  186. // Purpose Subclassed window proc for the edit control in the Browse
  187. // for Directory dialog. We override the WM_SETTEXT message
  188. // to control when the window text can be programatically
  189. // changed.
  190. //
  191. // Parameters standard
  192. //
  193. // Returns standard
  194. //
  195. // History 10/06/95 KenSh Created
  196. // 10/09/95 KenSh Moved most code into UpdateEditText()
  197. //
  198. LRESULT CALLBACK BrowseDirEditProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
  199. {
  200. switch( message )
  201. {
  202. // In order to prevent default functionality from setting the Edit's text
  203. // to strings like "*.*", we capture WM_SETTEXT and only allow it to occur
  204. // if the fAllowSetText flag is specified in the OFNINFO struct.
  205. case WM_SETTEXT:
  206. {
  207. LPOFNINFO lpOFNInfo = (LPOFNINFO)GetProp( GetParent(hwnd), c_szOFNProp );
  208. if( lpOFNInfo->fAllowSetText )
  209. {
  210. break; // default processing
  211. }
  212. else
  213. {
  214. return 0L; // suppress the urge to change the text
  215. }
  216. }
  217. default:
  218. break;
  219. }
  220. return CallWindowProc( g_pfnPrevEditProc, hwnd, message, wParam, lParam );
  221. }
  222. //----------------------------------------------------------------------------
  223. // Procedure BrowseDirComboProc
  224. //
  225. // Purpose Subclassed window proc for the combo box in the Browse
  226. // Directory dialog. We need to subclass so we can catch the
  227. // change to selection after the Network button is used to
  228. // switch drives.
  229. //
  230. // Parameters standard
  231. //
  232. // Returns standard
  233. //
  234. // History 10/09/95 KenSh Created
  235. //
  236. LRESULT CALLBACK BrowseDirComboProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
  237. {
  238. switch( message )
  239. {
  240. // We catch the WM_SETREDRAW message so that we ignore CB_SETCURSEL
  241. // messages when the combo is not supposed to be updated. This is
  242. // pretty much of a hack due to the ordering of messages after the
  243. // Network button is clicked.
  244. case WM_SETREDRAW:
  245. {
  246. if( wParam )
  247. {
  248. SetProp( hwnd, c_szRedrawProp, (HANDLE)1 );
  249. }
  250. else
  251. {
  252. if( GetProp( hwnd, c_szRedrawProp ) )
  253. {
  254. RemoveProp( hwnd, c_szRedrawProp );
  255. }
  256. }
  257. break; // continue with default processing
  258. }
  259. // We catch CB_SETCURSEL and use it to update our edit box after the
  260. // Network button has been pressed.
  261. case CB_SETCURSEL:
  262. {
  263. LPOFNINFO lpOFNInfo = (LPOFNINFO)GetProp( GetParent(hwnd), c_szOFNProp );
  264. #ifdef NEVER
  265. // If "Network" was pressed and redraw has been re-enabled...
  266. if( lpOFNInfo->fNetworking && GetProp( hwnd, c_szRedrawProp ) )
  267. {
  268. TCHAR szBuf[_MAX_PATH];
  269. LRESULT lResult = CallWindowProc( g_pfnPrevComboProc, hwnd, message, wParam, lParam );
  270. // Turn off the networking flag
  271. lpOFNInfo->fNetworking = FALSE;
  272. // Force the selected drive to be the current drive and
  273. // get the current directory on that drive
  274. GetWindowText( hwnd, szBuf, _MAX_PATH );
  275. _chdrive( _totupper(szBuf[0]) - 'A' + 1 );
  276. GetCurrentDirectory( _MAX_PATH, szBuf );
  277. // Update the edit box with the new text.
  278. lpOFNInfo->fAllowSetText = TRUE;
  279. SetDlgItemText( GetParent(hwnd), IDC_FILENAME, szBuf );
  280. lpOFNInfo->fAllowSetText = FALSE;
  281. SendDlgItemMessage( GetParent(hwnd), IDC_FILENAME, EM_SETSEL, 0, (LPARAM)-1 );
  282. return lResult;
  283. }
  284. #endif
  285. break;
  286. }
  287. case WM_DESTROY:
  288. {
  289. if( GetProp( hwnd, c_szRedrawProp ) )
  290. {
  291. RemoveProp( hwnd, c_szRedrawProp );
  292. }
  293. break; // continue with default processing
  294. }
  295. default:
  296. break;
  297. }
  298. return CallWindowProc( g_pfnPrevComboProc, hwnd, message, wParam, lParam );
  299. }
  300. //----------------------------------------------------------------------------
  301. // Procedure UpdateEditText
  302. //
  303. // Purpose Based on which control has focus and the current state of
  304. // the edit control, calculates the new "current directory" and
  305. // sets the Edit control's text to match.
  306. //
  307. // Parameters hwndDlg handle to the dialog window. This function will
  308. // access the lpOFNInfo window property.
  309. //
  310. // Returns nothing
  311. //
  312. // History 10/09/95 KenSh Created
  313. //
  314. VOID UpdateEditText( HWND hwndDlg )
  315. {
  316. HWND hwndLB = GetDlgItem(hwndDlg, IDC_FILELIST);
  317. int nCurSel = (int)SendMessage(hwndLB, LB_GETCURSEL, 0, 0);
  318. TCHAR szDirName[_MAX_PATH];
  319. LPTSTR pchStart = NULL;
  320. LPOFNINFO lpOFNInfo = (LPOFNINFO)GetProp( hwndDlg, c_szOFNProp );
  321. int i;
  322. HWND hwndFocus = GetFocus();
  323. int idFocus = GetDlgCtrlID( hwndFocus );
  324. if( idFocus == IDC_FILELIST )
  325. // Listbox: build name up through current LB selection
  326. {
  327. // First get the top entry in the listbox, this will tell us
  328. // if it's a connected drive or a UNC drive
  329. SendMessage( hwndLB, LB_GETTEXT, 0, (LPARAM)szDirName );
  330. // Run down the entries in the listbox appending them
  331. // and stop when we get to the current selection.
  332. if( szDirName[0] == _T('\\') && szDirName[1] == _T('\\') )
  333. pchStart = _tcschr(szDirName+2, _T('\0'));
  334. else
  335. pchStart = _tcsinc(szDirName) + 1; // skip 2 chars, first may be MBCS
  336. if (NULL != pchStart)
  337. {
  338. for( i = 1; i <= nCurSel; i++ )
  339. {
  340. if( *pchStart != _T('\\') )
  341. *pchStart = _T('\\');
  342. pchStart = _tcsinc(pchStart);
  343. SendMessage( hwndLB, LB_GETTEXT, i, (LPARAM)pchStart );
  344. pchStart = _tcschr(pchStart, _T('\0'));
  345. }
  346. }
  347. }
  348. else if( idFocus == IDC_DRIVECOMBO )
  349. // Combo box: use current working directory
  350. {
  351. GetCurrentDirectory( _MAX_PATH, szDirName );
  352. }
  353. else if( idFocus == IDC_FILENAME )
  354. // Edit control: build the new path using the edit contents
  355. {
  356. TCHAR szBuf[_MAX_PATH];
  357. GetDlgItemText( hwndDlg, IDC_FILENAME, szBuf, _MAX_PATH );
  358. if( szBuf[0] == _T('\\') )
  359. {
  360. if( szBuf[1] == _T('\\') )
  361. // full UNC path was specified
  362. {
  363. _tcscpy( szDirName, szBuf );
  364. }
  365. else
  366. // new directory on the current drive
  367. {
  368. _tcscpy( szDirName, lpOFNInfo->szLastDirName );
  369. LPTSTR pch = pszSkipDriveSpec(szDirName);
  370. _tcscpy( pch, szBuf );
  371. }
  372. }
  373. else if( *_tcsinc(szBuf) == _T(':') )
  374. {
  375. // Change to the requested drive and use the current directory
  376. // on that drive.
  377. if( 0 == _chdrive( _totupper(szBuf[0]) - 'A' + 1 ) &&
  378. szBuf[2] != _T('\\') )
  379. {
  380. // It's a legal drive and no directory was specified,
  381. // so use the current default.
  382. GetCurrentDirectory( _MAX_PATH, szDirName );
  383. }
  384. else
  385. {
  386. // A directory was specified or the drive does not exist.
  387. // Copy the text verbatim to test it and possibly display
  388. // an error message.
  389. _tcscpy( szDirName, szBuf );
  390. }
  391. }
  392. else
  393. // Subdirectory of the current directory
  394. {
  395. // Start with the current directory
  396. _tcscpy( szDirName, lpOFNInfo->szLastDirName );
  397. // Append a backslash if there isn't already one there
  398. LPTSTR pch = _tcsrchr( szDirName, _T('\\') );
  399. if (pch)
  400. {
  401. if( *_tcsinc(pch) )
  402. {
  403. pch = _tcschr( pch, _T('\0') );
  404. if (pch)
  405. {
  406. *pch = _T('\\');
  407. }
  408. }
  409. pch = _tcsinc(pch);
  410. // Append the new directory name
  411. _tcscpy( pch, szBuf );
  412. }
  413. // Attempt to change into the new directory
  414. if( SetCurrentDirectory(szDirName) )
  415. {
  416. // The directory exists, get the official name and use that
  417. // instead of whatever we're using now
  418. GetCurrentDirectory( _MAX_PATH, szDirName );
  419. }
  420. }
  421. }
  422. else
  423. {
  424. // Some other control, likely an error message is going on
  425. _tcscpy( szDirName, lpOFNInfo->szLastDirName );
  426. }
  427. lpOFNInfo->fAllowSetText = TRUE;
  428. SetDlgItemText( hwndDlg, IDC_FILENAME, szDirName );
  429. lpOFNInfo->fAllowSetText = FALSE;
  430. }
  431. //----------------------------------------------------------------------------
  432. // Procedure BrowseDirDlgHook
  433. //
  434. // Purpose Dialog proc for the Browse for Directory subclassed common
  435. // dialog. We spend most of our effort trying to get the right
  436. // string into the edit control (IDC_FILENAME).
  437. //
  438. // Parameters standard
  439. //
  440. // Returns TRUE to halt further processing, FALSE to do the default.
  441. //
  442. // History 10/06/95 KenSh Created
  443. //
  444. BOOL CALLBACK BrowseDirDlgHook( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
  445. {
  446. switch(message)
  447. {
  448. case WM_INITDIALOG:
  449. {
  450. LPOFNINFO lpOFNInfo = (LPOFNINFO)((LPOPENFILENAME)lParam)->lCustData;
  451. // Store the OFN struct pointer as a window property
  452. SetProp( hwnd, c_szOFNProp, (HANDLE)lpOFNInfo );
  453. // Initialize the OFNInfo struct
  454. _tcscpy( lpOFNInfo->szLastDirName, lpOFNInfo->ofn.lpstrInitialDir );
  455. lpOFNInfo->fAllowSetText = FALSE;
  456. //lpOFNInfo->fNetworking = FALSE;
  457. // Start our edit off with the initial directory
  458. SetDlgItemText( hwnd, IDC_FILENAME, lpOFNInfo->ofn.lpstrInitialDir );
  459. // Subclass the edit to let us display only what we want to display
  460. g_pfnPrevEditProc = (WNDPROC)SetWindowLongPtr(
  461. GetDlgItem(hwnd, IDC_FILENAME),
  462. GWLP_WNDPROC,
  463. (LONG_PTR)BrowseDirEditProc );
  464. // Subclass the combo so we know when the Network button has been used.
  465. g_pfnPrevComboProc = (WNDPROC)SetWindowLongPtr(
  466. GetDlgItem(hwnd, IDC_DRIVECOMBO),
  467. GWLP_WNDPROC,
  468. (LONG_PTR)BrowseDirComboProc );
  469. return TRUE; // set default focus
  470. }
  471. case WM_DESTROY:
  472. {
  473. // Clean up.
  474. RemoveProp( hwnd, c_szOFNProp );
  475. return FALSE; // continue with default processing
  476. }
  477. case WM_COMMAND:
  478. {
  479. switch( LOWORD(wParam) )
  480. {
  481. case IDOK:
  482. {
  483. return BrowseDir_OnOK( hwnd );
  484. }
  485. case IDC_FILELIST: //directory listbox.
  486. {
  487. if( HIWORD(wParam) == LBN_DBLCLK )
  488. {
  489. // Post this message telling us to change the edit box.
  490. PostMessage( hwnd, CM_UPDATEEDIT, 0, 0L );
  491. }
  492. return FALSE; // continue with default processing.
  493. }
  494. case IDC_DRIVECOMBO: // drive combo box:
  495. {
  496. if( HIWORD(wParam) == CBN_SELCHANGE )
  497. {
  498. // Post this message telling us to change the edit box.
  499. PostMessage( hwnd, CM_UPDATEEDIT, 0, 0L );
  500. }
  501. return FALSE; // continue with default processing.
  502. }
  503. #ifdef NEVER
  504. case IDC_NETWORK: // "Network..." button
  505. {
  506. // Set the fNetworking flag which the combo box looks for when
  507. // processing CB_SETCURSEL.
  508. LPOFNINFO lpOFNInfo = (LPOFNINFO)GetProp( hwnd, c_szOFNProp );
  509. lpOFNInfo->fNetworking = TRUE;
  510. return FALSE; // default processing.
  511. }
  512. #endif
  513. default:
  514. return FALSE; // default processing.
  515. }
  516. }
  517. case CM_UPDATEEDIT: //update edit box with directory
  518. {
  519. LPOFNINFO lpOFNInfo = (LPOFNINFO)GetProp( hwnd, c_szOFNProp );
  520. // Change the text of the edit control.
  521. UpdateEditText( hwnd );
  522. SendDlgItemMessage( hwnd, IDC_FILENAME, EM_SETSEL, 0, (LPARAM)(INT)-1 );
  523. // Store this text as the "last known good" directory
  524. GetDlgItemText( hwnd, IDC_FILENAME, lpOFNInfo->szLastDirName, _MAX_PATH );
  525. return TRUE;
  526. }
  527. default:
  528. return FALSE; //default processing
  529. }
  530. }
  531. //----------------------------------------------------------------------------
  532. // Procedure BrowseDir_OnOK
  533. //
  534. // Purpose Handles a click of the OK button in the Browse Directory
  535. // dialog. We have to do some sneaky stuff here with checking
  536. // which control has focus, because we want the dialog to go
  537. // away enter when the OK button is clicked directly (i.e. just
  538. // hitting Enter doesn't count).
  539. //
  540. // Parameters hwnd The dialog window
  541. //
  542. // Returns TRUE if processing should halt, FALSE if default processing
  543. // should still happen.
  544. //
  545. // History 10/09/95 KenSh Created
  546. //
  547. BOOL BrowseDir_OnOK( HWND hwnd )
  548. {
  549. LPOFNINFO lpOFNInfo = (LPOFNINFO)GetProp( hwnd, c_szOFNProp );
  550. HWND hwndFocus = GetFocus();
  551. int idFocus = GetDlgCtrlID(hwndFocus);
  552. if( idFocus != IDC_FILENAME && idFocus != IDC_FILELIST && idFocus != IDC_DRIVECOMBO )
  553. {
  554. ASSERT( lpOFNInfo->ofn.lpstrFile != NULL );
  555. //UpdateEditText( hwnd );
  556. GetDlgItemText( hwnd, IDC_FILENAME, lpOFNInfo->ofn.lpstrFile, lpOFNInfo->ofn.nMaxFile );
  557. EndDialog( hwnd, IDOK );
  558. return TRUE; // halt processing here.
  559. }
  560. else
  561. {
  562. // We don't want the dialog to go away at this point.
  563. // Because the default functionality is expecting
  564. // a file to be found, not a directory, we must make
  565. // sure what's been typed in is actually a directory
  566. // before we hand this message to the default handler.
  567. TCHAR szBuf[_MAX_PATH];
  568. // Calculate the new current directory and put it into the Edit
  569. UpdateEditText( hwnd );
  570. // Read the newly generated directory name
  571. GetDlgItemText( hwnd, IDC_FILENAME, szBuf, _MAX_PATH );
  572. // Update our "last good" directory
  573. _tcscpy( lpOFNInfo->szLastDirName, szBuf );
  574. // Post this message to update the edit after the default handler
  575. // updates the list box
  576. PostMessage( hwnd, CM_UPDATEEDIT, 0, 0 );
  577. return FALSE; // let the original common dialog handle it.
  578. }
  579. }
  580. BOOL BrowseForFile(
  581. HWND hwndParent,
  582. LPCTSTR pszInitialDir,
  583. LPTSTR pszBuf,
  584. int cchBuf)
  585. {
  586. TCHAR szInitialDir[MAX_PATH];
  587. TCHAR szFileExtension[_MAX_PATH] = _T("");
  588. LPTSTR p = NULL;
  589. TCHAR szFileFilter[_MAX_PATH];
  590. CString csTitle;
  591. OFNINFO ofnInfo;
  592. // Prepare the initial directory... add a backslash if it's
  593. // a 2-character path
  594. _tcscpy( szInitialDir, pszInitialDir );
  595. if( !szInitialDir[2] )
  596. {
  597. szInitialDir[2] = _T('\\');
  598. szInitialDir[3] = _T('\0');
  599. }
  600. // calculate file extension
  601. p = _tcsrchr(pszBuf, _T('.'));
  602. if (p) {
  603. p = _tcsinc(p);
  604. if (*p) {
  605. _tcscpy(szFileExtension, _T("*."));
  606. _tcscat(szFileExtension, p);
  607. }
  608. }
  609. memset( (PVOID)szFileFilter, 0, sizeof(szFileFilter));
  610. p = szFileFilter;
  611. if (*szFileExtension) {
  612. _tcscpy(p, szFileExtension);
  613. p = _tcsninc(p, _tcslen(szFileExtension) + 1);
  614. _tcscpy(p, szFileExtension);
  615. p = _tcsninc(p, _tcslen(szFileExtension) + 1);
  616. }
  617. _tcscpy(p, _T("*.*"));
  618. p = _tcsninc(p, _tcslen(_T("*.*")) + 1);
  619. _tcscpy(p, _T("*.*"));
  620. // dialog title "Locate File"
  621. MyLoadString(IDS_LOCATE_FILE, csTitle);
  622. // fill in the OFNINFO struct
  623. ofnInfo.ofn.lStructSize = sizeof(OPENFILENAME);
  624. ofnInfo.ofn.hwndOwner = hwndParent;
  625. ofnInfo.ofn.hInstance = (HINSTANCE) g_MyModuleHandle;
  626. ofnInfo.ofn.lpstrFilter = szFileFilter; // extention of the file we're looking for
  627. ofnInfo.ofn.lpstrCustomFilter = NULL;
  628. ofnInfo.ofn.nMaxCustFilter = 0;
  629. ofnInfo.ofn.nFilterIndex = 1;
  630. ofnInfo.ofn.lpstrFile = pszBuf; // Buffer for file name
  631. ofnInfo.ofn.nMaxFile = cchBuf;
  632. ofnInfo.ofn.lpstrFileTitle = NULL;
  633. ofnInfo.ofn.nMaxFileTitle = 0;
  634. ofnInfo.ofn.lpstrInitialDir = szInitialDir;
  635. ofnInfo.ofn.lpstrTitle = (LPCTSTR)csTitle;
  636. ofnInfo.ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER |
  637. OFN_NOCHANGEDIR | OFN_LONGNAMES | OFN_NONETWORKBUTTON;
  638. ofnInfo.ofn.nFileOffset = 0;
  639. ofnInfo.ofn.nFileExtension = 0;
  640. ofnInfo.ofn.lpstrDefExt = NULL;
  641. ofnInfo.ofn.lCustData = (LPARAM)&ofnInfo;
  642. ofnInfo.ofn.lpfnHook = NULL;
  643. ofnInfo.ofn.lpTemplateName = NULL;
  644. int nResult = ::GetOpenFileName( &ofnInfo.ofn );
  645. DWORD dw = 0;
  646. if (nResult == 0) {
  647. dw = CommDlgExtendedError();
  648. }
  649. if (nResult == IDOK) {
  650. iisDebugOut((LOG_TYPE_TRACE, _T("pszBuf=%s\n"), pszBuf));
  651. *(pszBuf + ofnInfo.ofn.nFileOffset - 1) = _T('\0');
  652. }
  653. return (BOOL)( IDOK == nResult );
  654. }