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.

12199 lines
342 KiB

  1. /*++
  2. Copyright (c) 1990-1998, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. filenew.cpp
  5. Abstract:
  6. This module implements the Win32 explorer fileopen dialogs.
  7. --*/
  8. //
  9. // Include Files.
  10. //
  11. // precompiled headers
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "cdids.h"
  15. #include "fileopen.h"
  16. #include "d32tlog.h"
  17. #include "filenew.h"
  18. #include "filemru.h"
  19. #include "util.h"
  20. #include "uxtheme.h"
  21. #ifndef ASSERT
  22. #define ASSERT Assert
  23. #endif
  24. //
  25. // Constant Declarations.
  26. //
  27. #define IDOI_SHARE 1
  28. #define CDM_SETSAVEBUTTON (CDM_LAST + 100)
  29. #define CDM_FSNOTIFY (CDM_LAST + 101)
  30. #define CDM_SELCHANGE (CDM_LAST + 102)
  31. #define TIMER_FSCHANGE 100
  32. #define NODE_DESKTOP 0
  33. #define NODE_DRIVES 1
  34. #define DEREFMACRO(x) x
  35. #define FILE_PADDING 10
  36. #define MAX_URL_STRING INTERNET_MAX_URL_LENGTH
  37. #define MAXDOSFILENAMELEN (12 + 1) // 8.3 filename + 1 for NULL
  38. //
  39. // IShellView::MenuHelp flags.
  40. //
  41. #define MH_DONE 0x0001
  42. // MH_LONGHELP
  43. #define MH_MERGEITEM 0x0004
  44. #define MH_SYSITEM 0x0008
  45. #define MH_POPUP 0x0010
  46. #define MH_TOOLBAR 0x0020
  47. #define MH_TOOLTIP 0x0040
  48. //
  49. // IShellView::MenuHelp return values.
  50. //
  51. #define MH_NOTHANDLED 0
  52. #define MH_STRINGFILLED 1
  53. #define MH_ALLHANDLED 2
  54. #define MYCBN_DRAW 0x8000
  55. #define MAX_DRIVELIST_STRING_LEN (64 + 4)
  56. #define REGSTR_PATH_PLACESBAR TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\comdlg32\\Placesbar")
  57. #define MAXPLACESBARITEMS 5
  58. //
  59. // Macro Definitions.
  60. //
  61. #define IsServer(psz) (IsUNC(psz) && !StrChr((psz) + 2, CHAR_BSLASH))
  62. #define LPIDL_GetIDList(_pida,n) \
  63. (LPCITEMIDLIST)(((LPBYTE)(_pida)) + (_pida)->aoffset[n])
  64. #define RECTWIDTH(_rc) ((_rc).right - (_rc).left)
  65. #define RECTHEIGHT(_rc) ((_rc).bottom - (_rc).top)
  66. #define IsVisible(_hwnd) (GetWindowLong(_hwnd, GWL_STYLE) & WS_VISIBLE)
  67. #define HwndToBrowser(_hwnd) (CFileOpenBrowser *)GetWindowLongPtr(_hwnd, DWLP_USER)
  68. #define StoreBrowser(_hwnd, _pbrs) \
  69. SetWindowLongPtr(_hwnd, DWLP_USER, (LONG_PTR)_pbrs);
  70. //
  71. // Typedef Declarations.
  72. //
  73. typedef struct _OFNINITINFO
  74. {
  75. LPOPENFILEINFO lpOFI;
  76. BOOL bSave;
  77. BOOL bEnableSizing;
  78. HRESULT hrOleInit;
  79. } OFNINITINFO, *LPOFNINITINFO;
  80. #define VC_NEWFOLDER 0
  81. #define VC_VIEWLIST 1
  82. #define VC_VIEWDETAILS 2
  83. //
  84. // Global Variables.
  85. //
  86. HWND gp_hwndActiveOpen = NULL;
  87. HACCEL gp_haccOpen = NULL;
  88. HACCEL gp_haccOpenView = NULL;
  89. HHOOK gp_hHook = NULL;
  90. int gp_nHookRef = -1;
  91. UINT gp_uQueryCancelAutoPlay = 0;
  92. static int g_cxSmIcon = 0 ;
  93. static int g_cySmIcon = 0 ;
  94. static int g_cxGrip;
  95. static int g_cyGrip;
  96. const LPCSTR c_szCommandsA[] =
  97. {
  98. CMDSTR_NEWFOLDERA,
  99. CMDSTR_VIEWLISTA,
  100. CMDSTR_VIEWDETAILSA,
  101. };
  102. const LPCWSTR c_szCommandsW[] =
  103. {
  104. CMDSTR_NEWFOLDERW,
  105. CMDSTR_VIEWLISTW,
  106. CMDSTR_VIEWDETAILSW,
  107. };
  108. extern "C"
  109. {
  110. extern RECT g_rcDlg;
  111. }
  112. //
  113. // Function Prototypes.
  114. //
  115. LRESULT CALLBACK
  116. OKSubclass(
  117. HWND hOK,
  118. UINT msg,
  119. WPARAM wParam,
  120. LPARAM lParam);
  121. void
  122. GetControlsArea(
  123. HWND hDlg,
  124. HWND hwndExclude,
  125. HWND hwndGrip,
  126. POINT *pPtSize,
  127. LPINT pTop);
  128. BOOL_PTR CALLBACK
  129. OpenDlgProc(
  130. HWND hDlg,
  131. UINT message,
  132. WPARAM wParam,
  133. LPARAM lParam);
  134. //
  135. // Context Help IDs.
  136. //
  137. DWORD aFileOpenHelpIDs[] =
  138. {
  139. stc2, IDH_OPEN_FILETYPE, // The positions of these array elements
  140. cmb1, IDH_OPEN_FILETYPE, // shouldn't be changed without updating
  141. stc4, IDH_OPEN_LOCATION, // InitSaveAsControls().
  142. cmb2, IDH_OPEN_LOCATION,
  143. stc1, IDH_OPEN_FILES32,
  144. lst2, IDH_OPEN_FILES32, // defview
  145. stc3, IDH_OPEN_FILENAME,
  146. edt1, IDH_OPEN_FILENAME,
  147. cmb13, IDH_OPEN_FILENAME,
  148. chx1, IDH_OPEN_READONLY,
  149. IDOK, IDH_OPEN_BUTTON,
  150. ctl1, IDH_OPEN_SHORTCUT_BAR,
  151. 0, 0
  152. };
  153. DWORD aFileSaveHelpIDs[] =
  154. {
  155. stc2, IDH_SAVE_FILETYPE, // The positions of these array elements
  156. cmb1, IDH_SAVE_FILETYPE, // shouldn't be changed without updating
  157. stc4, IDH_OPEN_LOCATION, // InitSaveAsControls().
  158. cmb2, IDH_OPEN_LOCATION,
  159. stc1, IDH_OPEN_FILES32,
  160. lst2, IDH_OPEN_FILES32, // defview
  161. stc3, IDH_OPEN_FILENAME,
  162. edt1, IDH_OPEN_FILENAME,
  163. cmb13, IDH_OPEN_FILENAME,
  164. chx1, IDH_OPEN_READONLY,
  165. IDOK, IDH_SAVE_BUTTON,
  166. ctl1, IDH_OPEN_SHORTCUT_BAR,
  167. 0, 0
  168. };
  169. ////////////////////////////////////////////////////////////////////////////
  170. //
  171. // CD_SendShareMsg
  172. //
  173. ////////////////////////////////////////////////////////////////////////////
  174. WORD CD_SendShareMsg(
  175. HWND hwnd,
  176. LPTSTR szFile,
  177. UINT ApiType)
  178. {
  179. if (ApiType == COMDLG_ANSI)
  180. {
  181. CHAR szFileA[MAX_PATH + 1];
  182. SHUnicodeToAnsi(szFile,szFileA,SIZECHARS(szFileA));
  183. return ((WORD)SendMessage(hwnd,
  184. msgSHAREVIOLATIONA,
  185. 0,
  186. (LONG_PTR)(LPSTR)(szFileA)));
  187. }
  188. else
  189. {
  190. return ((WORD)SendMessage(hwnd,
  191. msgSHAREVIOLATIONW,
  192. 0,
  193. (LONG_PTR)(LPTSTR)(szFile)));
  194. }
  195. }
  196. ////////////////////////////////////////////////////////////////////////////
  197. //
  198. // CD_SendHelpMsg
  199. //
  200. ////////////////////////////////////////////////////////////////////////////
  201. VOID CD_SendHelpMsg(
  202. LPOPENFILENAME pOFN,
  203. HWND hwndDlg,
  204. UINT ApiType)
  205. {
  206. if (ApiType == COMDLG_ANSI)
  207. {
  208. if (msgHELPA && pOFN->hwndOwner)
  209. {
  210. SendMessage(pOFN->hwndOwner,
  211. msgHELPA,
  212. (WPARAM)hwndDlg,
  213. (LPARAM)pOFN);
  214. }
  215. }
  216. else
  217. {
  218. if (msgHELPW && pOFN->hwndOwner)
  219. {
  220. SendMessage(pOFN->hwndOwner,
  221. msgHELPW,
  222. (WPARAM)hwndDlg,
  223. (LPARAM)pOFN);
  224. }
  225. }
  226. }
  227. ////////////////////////////////////////////////////////////////////////////
  228. //
  229. // CD_SendOKMsg
  230. //
  231. ////////////////////////////////////////////////////////////////////////////
  232. LRESULT CD_SendOKMsg(
  233. HWND hwnd,
  234. LPOPENFILENAME pOFN,
  235. LPOPENFILEINFO pOFI)
  236. {
  237. LRESULT Result;
  238. if (pOFI->ApiType == COMDLG_ANSI)
  239. {
  240. ThunkOpenFileNameW2A(pOFI);
  241. Result = SendMessage(hwnd, msgFILEOKA, 0, (LPARAM)(pOFI->pOFNA));
  242. //
  243. // For apps that side-effect pOFNA stuff and expect it to
  244. // be preserved through dialog exit, update internal
  245. // struct after the hook proc is called.
  246. //
  247. ThunkOpenFileNameA2W(pOFI);
  248. }
  249. else
  250. {
  251. Result = SendMessage(hwnd, msgFILEOKW, 0, (LPARAM)(pOFN));
  252. }
  253. return (Result);
  254. }
  255. ////////////////////////////////////////////////////////////////////////////
  256. //
  257. // CD_SendLBChangeMsg
  258. //
  259. ////////////////////////////////////////////////////////////////////////////
  260. LRESULT CD_SendLBChangeMsg(
  261. HWND hwnd,
  262. int Id,
  263. short Index,
  264. short Code,
  265. UINT ApiType)
  266. {
  267. if (ApiType == COMDLG_ANSI)
  268. {
  269. return (SendMessage(hwnd, msgLBCHANGEA, Id, MAKELONG(Index, Code)));
  270. }
  271. else
  272. {
  273. return (SendMessage(hwnd, msgLBCHANGEW, Id, MAKELONG(Index, Code)));
  274. }
  275. }
  276. ////////////////////////////////////////////////////////////////////////////
  277. //
  278. // Macro calls to SendOFNotify
  279. //
  280. ////////////////////////////////////////////////////////////////////////////
  281. #define CD_SendShareNotify(_hwndTo, _hwndFrom, _szFile, _pofn, _pofi) \
  282. (WORD)SendOFNotify(_hwndTo, _hwndFrom, CDN_SHAREVIOLATION, _szFile, _pofn, _pofi)
  283. #define CD_SendHelpNotify(_hwndTo, _hwndFrom, _pofn, _pofi) \
  284. SendOFNotify(_hwndTo, _hwndFrom, CDN_HELP, NULL, _pofn, _pofi)
  285. #define CD_SendOKNotify(_hwndTo, _hwndFrom, _pofn, _pofi) \
  286. SendOFNotify(_hwndTo, _hwndFrom, CDN_FILEOK, NULL, _pofn, _pofi)
  287. #define CD_SendTypeChangeNotify(_hwndTo, _hwndFrom, _pofn, _pofi) \
  288. SendOFNotify(_hwndTo, _hwndFrom, CDN_TYPECHANGE, NULL, _pofn, _pofi)
  289. #define CD_SendInitDoneNotify(_hwndTo, _hwndFrom, _pofn, _pofi) \
  290. SendOFNotify(_hwndTo, _hwndFrom, CDN_INITDONE, NULL, _pofn, _pofi)
  291. #define CD_SendSelChangeNotify(_hwndTo, _hwndFrom, _pofn, _pofi) \
  292. SendOFNotify(_hwndTo, _hwndFrom, CDN_SELCHANGE, NULL, _pofn, _pofi)
  293. #define CD_SendFolderChangeNotify(_hwndTo, _hwndFrom, _pofn, _pofi) \
  294. SendOFNotify(_hwndTo, _hwndFrom, CDN_FOLDERCHANGE, NULL, _pofn, _pofi)
  295. #define CD_SendIncludeItemNotify(_hwndTo, _hwndFrom, _psf, _pidl, _pofn, _pofi) \
  296. SendOFNotifyEx(_hwndTo, _hwndFrom, CDN_INCLUDEITEM, (void *)_psf, (void *)_pidl, _pofn, _pofi)
  297. ////////////////////////////////////////////////////////////////////////////
  298. //
  299. // SendOFNotifyEx
  300. //
  301. ////////////////////////////////////////////////////////////////////////////
  302. LRESULT SendOFNotifyEx(
  303. HWND hwndTo,
  304. HWND hwndFrom,
  305. UINT code,
  306. void * psf,
  307. void * pidl,
  308. LPOPENFILENAME pOFN,
  309. LPOPENFILEINFO pOFI)
  310. {
  311. OFNOTIFYEX ofnex;
  312. if (pOFI->ApiType == COMDLG_ANSI)
  313. {
  314. OFNOTIFYEXA ofnexA;
  315. LRESULT Result;
  316. ofnexA.psf = psf;
  317. ofnexA.pidl = pidl;
  318. //
  319. // Convert the OFN from Unicode to Ansi.
  320. //
  321. ThunkOpenFileNameW2A(pOFI);
  322. ofnexA.lpOFN = pOFI->pOFNA;
  323. #ifdef NEED_WOWGETNOTIFYSIZE_HELPER
  324. ASSERT(WOWGetNotifySize(code) == sizeof(OFNOTIFYEXA));
  325. #endif
  326. Result = SendNotify(hwndTo, hwndFrom, code, &ofnexA.hdr);
  327. //
  328. // For apps that side-effect pOFNA stuff and expect it to
  329. // be preserved through dialog exit, update internal
  330. // struct after the hook proc is called.
  331. //
  332. ThunkOpenFileNameA2W(pOFI);
  333. return (Result);
  334. }
  335. else
  336. {
  337. ofnex.psf = psf;
  338. ofnex.pidl = pidl;
  339. ofnex.lpOFN = pOFN;
  340. #ifdef NEED_WOWGETNOTIFYSIZE_HELPER
  341. ASSERT(WOWGetNotifySize(code) == sizeof(OFNOTIFYEXW));
  342. #endif
  343. return (SendNotify(hwndTo, hwndFrom, code, &ofnex.hdr));
  344. }
  345. }
  346. ////////////////////////////////////////////////////////////////////////////
  347. //
  348. // SendOFNotify
  349. //
  350. ////////////////////////////////////////////////////////////////////////////
  351. LRESULT SendOFNotify(
  352. HWND hwndTo,
  353. HWND hwndFrom,
  354. UINT code,
  355. LPTSTR szFile,
  356. LPOPENFILENAME pOFN,
  357. LPOPENFILEINFO pOFI)
  358. {
  359. OFNOTIFY ofn;
  360. if (pOFI->ApiType == COMDLG_ANSI)
  361. {
  362. OFNOTIFYA ofnA;
  363. LRESULT Result;
  364. //
  365. // Convert the file name from Unicode to Ansi.
  366. //
  367. if (szFile)
  368. {
  369. CHAR szFileA[MAX_PATH + 1];
  370. SHUnicodeToAnsi(szFile,szFileA,SIZECHARS(szFileA));
  371. ofnA.pszFile = szFileA;
  372. }
  373. else
  374. {
  375. ofnA.pszFile = NULL;
  376. }
  377. //
  378. // Convert the OFN from Unicode to Ansi.
  379. //
  380. ThunkOpenFileNameW2A(pOFI);
  381. ofnA.lpOFN = pOFI->pOFNA;
  382. #ifdef NEED_WOWGETNOTIFYSIZE_HELPER
  383. ASSERT(WOWGetNotifySize(code) == sizeof(OFNOTIFYA));
  384. #endif
  385. Result = SendNotify(hwndTo, hwndFrom, code, &ofnA.hdr);
  386. //
  387. // For apps that side-effect pOFNA stuff and expect it to
  388. // be preserved through dialog exit, update internal
  389. // struct after the hook proc is called.
  390. //
  391. ThunkOpenFileNameA2W(pOFI);
  392. return (Result);
  393. }
  394. else
  395. {
  396. ofn.pszFile = szFile;
  397. ofn.lpOFN = pOFN;
  398. #ifdef NEED_WOWGETNOTIFYSIZE_HELPER
  399. ASSERT(WOWGetNotifySize(code) == sizeof(OFNOTIFY));
  400. #endif
  401. return (SendNotify(hwndTo, hwndFrom, code, &ofn.hdr));
  402. }
  403. }
  404. ////////////////////////////////////////////////////////////////////////////
  405. //
  406. // TEMPMEM::Resize
  407. //
  408. ////////////////////////////////////////////////////////////////////////////
  409. BOOL TEMPMEM::Resize(
  410. UINT cb)
  411. {
  412. UINT uOldSize = m_uSize;
  413. m_uSize = cb;
  414. if (!cb)
  415. {
  416. if (m_pMem)
  417. {
  418. LocalFree(m_pMem);
  419. m_pMem = NULL;
  420. }
  421. return TRUE;
  422. }
  423. if (!m_pMem)
  424. {
  425. m_pMem = LocalAlloc(LPTR, cb);
  426. return (m_pMem != NULL);
  427. }
  428. void * pTemp = LocalReAlloc(m_pMem, cb, LHND);
  429. if (pTemp)
  430. {
  431. m_pMem = pTemp;
  432. return TRUE;
  433. }
  434. m_uSize = uOldSize;
  435. return FALSE;
  436. }
  437. ////////////////////////////////////////////////////////////////////////////
  438. //
  439. // TEMPSTR::TSStrCpy
  440. //
  441. ////////////////////////////////////////////////////////////////////////////
  442. BOOL TEMPSTR::TSStrCpy(
  443. LPCTSTR pszText)
  444. {
  445. if (!pszText)
  446. {
  447. TSStrSize(0);
  448. return TRUE;
  449. }
  450. UINT uNewSize = lstrlen(pszText) + 1;
  451. if (!TSStrSize(uNewSize))
  452. {
  453. return FALSE;
  454. }
  455. EVAL(SUCCEEDED(StringCchCopy(*this, uNewSize, pszText)));
  456. return TRUE;
  457. }
  458. ////////////////////////////////////////////////////////////////////////////
  459. //
  460. // TEMPSTR::TSStrCat
  461. //
  462. ////////////////////////////////////////////////////////////////////////////
  463. BOOL TEMPSTR::TSStrCat(
  464. LPCTSTR pszText)
  465. {
  466. if (!(LPTSTR)*this)
  467. {
  468. //
  469. // This should 0 init.
  470. //
  471. if (!TSStrSize(MAX_PATH))
  472. {
  473. return FALSE;
  474. }
  475. }
  476. UINT uNewSize = lstrlen(*this) + lstrlen(pszText) + 1;
  477. if (m_uSize < uNewSize * sizeof(TCHAR))
  478. {
  479. //
  480. // Add on some more so we do not ReAlloc too often.
  481. //
  482. uNewSize += MAX_PATH;
  483. if (!TSStrSize(uNewSize))
  484. {
  485. return FALSE;
  486. }
  487. }
  488. EVAL(SUCCEEDED(StringCchCat(*this, uNewSize, pszText)));
  489. return TRUE;
  490. }
  491. ////////////////////////////////////////////////////////////////////////////
  492. //
  493. // IsVolumeLFN
  494. //
  495. ////////////////////////////////////////////////////////////////////////////
  496. BOOL IsVolumeLFN(LPCTSTR pszRoot)
  497. {
  498. DWORD dwVolumeSerialNumber;
  499. DWORD dwMaximumComponentLength;
  500. DWORD dwFileSystemFlags;
  501. //
  502. // We need to find out what kind of a drive we are running
  503. // on in order to determine if spaces are valid in a filename
  504. // or not.
  505. //
  506. if (GetVolumeInformation(pszRoot,
  507. NULL,
  508. 0,
  509. &dwVolumeSerialNumber,
  510. &dwMaximumComponentLength,
  511. &dwFileSystemFlags,
  512. NULL,
  513. 0))
  514. {
  515. if (dwMaximumComponentLength != (MAXDOSFILENAMELEN - 1))
  516. return TRUE;
  517. }
  518. return FALSE;
  519. }
  520. ////////////////////////////////////////////////////////////////////////////
  521. //
  522. // CDMessageBox
  523. //
  524. ////////////////////////////////////////////////////////////////////////////
  525. int _cdecl CDMessageBox(
  526. HWND hwndParent,
  527. UINT idText,
  528. UINT uFlags,
  529. ...)
  530. {
  531. TCHAR szText[MAX_PATH + WARNINGMSGLENGTH];
  532. TCHAR szTitle[WARNINGMSGLENGTH];
  533. va_list ArgList;
  534. CDLoadString(g_hinst, idText, szTitle, ARRAYSIZE(szTitle));
  535. va_start(ArgList, uFlags);
  536. StringCchVPrintf(szText, ARRAYSIZE(szText), szTitle, ArgList); // for display, ignoring return value
  537. va_end(ArgList);
  538. GetWindowText(hwndParent, szTitle, ARRAYSIZE(szTitle));
  539. return (MessageBox(hwndParent, szText, szTitle, uFlags));
  540. }
  541. int OFErrFromHresult(HRESULT hr)
  542. {
  543. switch (hr)
  544. {
  545. case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
  546. return OF_FILENOTFOUND;
  547. case E_ACCESSDENIED:
  548. return OF_ACCESSDENIED;
  549. default:
  550. return -1;
  551. }
  552. }
  553. BOOL CFileOpenBrowser::_SaveAccessDenied(LPCTSTR pszFile)
  554. {
  555. if (CDMessageBox(_hwndDlg, iszDirSaveAccessDenied, MB_YESNO | MB_ICONEXCLAMATION, pszFile) == IDYES)
  556. {
  557. LPITEMIDLIST pidl;
  558. if (SUCCEEDED(SHGetFolderLocation(_hwndDlg, CSIDL_PERSONAL, NULL, 0, &pidl)))
  559. {
  560. JumpToIDList(pidl);
  561. ILFree(pidl);
  562. }
  563. }
  564. return FALSE;
  565. }
  566. ////////////////////////////////////////////////////////////////////////////
  567. //
  568. // InvalidFileWarningNew
  569. //
  570. ////////////////////////////////////////////////////////////////////////////
  571. VOID InvalidFileWarningNew(
  572. HWND hWnd,
  573. LPCTSTR pszFile,
  574. int wErrCode)
  575. {
  576. int isz;
  577. BOOL bDriveLetter = FALSE;
  578. switch (wErrCode)
  579. {
  580. case (OF_ACCESSDENIED) :
  581. {
  582. isz = iszFileAccessDenied;
  583. break;
  584. }
  585. case (ERROR_NOT_READY) :
  586. {
  587. isz = iszNoDiskInDrive;
  588. bDriveLetter = TRUE;
  589. break;
  590. }
  591. case (OF_NODRIVE) :
  592. {
  593. isz = iszDriveDoesNotExist;
  594. bDriveLetter = TRUE;
  595. break;
  596. }
  597. case (OF_NOFILEHANDLES) :
  598. {
  599. isz = iszNoFileHandles;
  600. break;
  601. }
  602. case (OF_PATHNOTFOUND) :
  603. {
  604. isz = iszPathNotFound;
  605. break;
  606. }
  607. case (OF_FILENOTFOUND) :
  608. {
  609. isz = iszFileNotFound;
  610. break;
  611. }
  612. case (OF_DISKFULL) :
  613. case (OF_DISKFULL2) :
  614. {
  615. isz = iszDiskFull;
  616. bDriveLetter = TRUE;
  617. break;
  618. }
  619. case (OF_WRITEPROTECTION) :
  620. {
  621. isz = iszWriteProtection;
  622. bDriveLetter = TRUE;
  623. break;
  624. }
  625. case (OF_SHARINGVIOLATION) :
  626. {
  627. isz = iszSharingViolation;
  628. break;
  629. }
  630. case (OF_CREATENOMODIFY) :
  631. {
  632. isz = iszCreateNoModify;
  633. break;
  634. }
  635. case (OF_NETACCESSDENIED) :
  636. {
  637. isz = iszNetworkAccessDenied;
  638. break;
  639. }
  640. case (OF_PORTNAME) :
  641. {
  642. isz = iszPortName;
  643. break;
  644. }
  645. case (OF_LAZYREADONLY) :
  646. {
  647. isz = iszReadOnly;
  648. break;
  649. }
  650. case (OF_INT24FAILURE) :
  651. {
  652. isz = iszInt24Error;
  653. break;
  654. }
  655. case (OF_BUFFERTRUNCATED) : // Due to limitations of the fileopen dialog - however, this means it was over MAX_PATH
  656. default :
  657. {
  658. isz = iszInvalidFileName;
  659. break;
  660. }
  661. }
  662. if (bDriveLetter)
  663. {
  664. CDMessageBox(hWnd, isz, MB_OK | MB_ICONEXCLAMATION, *pszFile);
  665. }
  666. else
  667. {
  668. CDMessageBox(hWnd, isz, MB_OK | MB_ICONEXCLAMATION, pszFile);
  669. }
  670. if (isz == iszInvalidFileName)
  671. {
  672. CFileOpenBrowser *pDlgStruct = HwndToBrowser(hWnd);
  673. if (pDlgStruct && pDlgStruct->_bUseCombo)
  674. {
  675. PostMessage(hWnd, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hWnd, cmb13), 1);
  676. }
  677. else
  678. {
  679. PostMessage(hWnd, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hWnd, edt1), 1);
  680. }
  681. }
  682. }
  683. ////////////////////////////////////////////////////////////////////////////
  684. //
  685. // GetControlRect
  686. //
  687. ////////////////////////////////////////////////////////////////////////////
  688. void GetControlRect(
  689. HWND hwndDlg,
  690. UINT idOldCtrl,
  691. LPRECT lprc)
  692. {
  693. HWND hwndOldCtrl = GetDlgItem(hwndDlg, idOldCtrl);
  694. GetWindowRect(hwndOldCtrl, lprc);
  695. MapWindowRect(HWND_DESKTOP, hwndDlg, lprc);
  696. }
  697. ////////////////////////////////////////////////////////////////////////////
  698. //
  699. // HideControl
  700. //
  701. // Subroutine to hide a dialog control.
  702. //
  703. // WARNING WARNING WARNING: Some code in the new look depends on hidden
  704. // controls remaining where they originally were, even when disabled,
  705. // because they're templates for where to create new controls (the toolbar,
  706. // or the main list). Therefore, HideControl() must not MOVE the control
  707. // being hidden - it may only hide and disable it. If this needs to change,
  708. // there must be a separate hiding subroutine used for template controls.
  709. //
  710. ////////////////////////////////////////////////////////////////////////////
  711. void HideControl(
  712. HWND hwndDlg,
  713. UINT idControl)
  714. {
  715. HWND hCtrl = ::GetDlgItem(hwndDlg, idControl);
  716. ::ShowWindow(hCtrl, SW_HIDE);
  717. ::EnableWindow(hCtrl, FALSE);
  718. }
  719. ////////////////////////////////////////////////////////////////////////////
  720. //
  721. // SelectEditText
  722. //
  723. ////////////////////////////////////////////////////////////////////////////
  724. void SelectEditText(
  725. HWND hwndDlg)
  726. {
  727. CFileOpenBrowser *pDlgStruct = HwndToBrowser(hwndDlg);
  728. if (pDlgStruct && pDlgStruct->_bUseCombo)
  729. {
  730. HWND hwndEdit = (HWND)SendMessage(GetDlgItem(hwndDlg, cmb13), CBEM_GETEDITCONTROL, 0, 0L);
  731. Edit_SetSel(hwndEdit, 0, -1);
  732. }
  733. else
  734. {
  735. Edit_SetSel(GetDlgItem(hwndDlg, edt1), 0, -1);
  736. }
  737. }
  738. ////////////////////////////////////////////////////////////////////////////
  739. //
  740. // GetPathFromLocation
  741. //
  742. ////////////////////////////////////////////////////////////////////////////
  743. BOOL GetPathFromLocation(
  744. MYLISTBOXITEM *pLocation,
  745. LPTSTR pszBuf)
  746. {
  747. BOOL fRet = FALSE;
  748. //
  749. // Zero out the return buffer in case of error.
  750. //
  751. *pszBuf = 0;
  752. //
  753. // Try normal channels first.
  754. //
  755. //See if the IShellFolder we have is a shorcut if so get path from shortcut
  756. if (pLocation->psfSub)
  757. {
  758. IShellLink *psl;
  759. if (SUCCEEDED(pLocation->psfSub->QueryInterface(IID_PPV_ARG(IShellLink, &psl))))
  760. {
  761. fRet = SUCCEEDED(psl->GetPath(pszBuf, MAX_PATH, 0, 0));
  762. psl->Release();
  763. }
  764. }
  765. if (!fRet)
  766. fRet = SHGetPathFromIDList(pLocation->pidlFull, pszBuf);
  767. if (!fRet)
  768. {
  769. //
  770. // Call GetDisplayNameOf with empty pidl.
  771. //
  772. if (pLocation->psfSub)
  773. {
  774. STRRET str;
  775. ITEMIDLIST idNull = {0};
  776. if (SUCCEEDED(pLocation->psfSub->GetDisplayNameOf(&idNull,
  777. SHGDN_FORPARSING,
  778. &str)))
  779. {
  780. fRet = TRUE;
  781. StrRetToBuf(&str, &idNull, pszBuf, MAX_PATH);
  782. }
  783. }
  784. }
  785. //
  786. // Return the result.
  787. //
  788. return (fRet);
  789. }
  790. inline _IsSaveContainer(SFGAOF f)
  791. {
  792. return ((f & (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR)) == (SFGAO_FOLDER | SFGAO_FILESYSANCESTOR));
  793. }
  794. inline _IsOpenContainer(SFGAOF f)
  795. {
  796. return ((f & SFGAO_FOLDER) && (f & (SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR)));
  797. }
  798. inline _IncludeSaveItem(SFGAOF f)
  799. {
  800. return (f & (SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM));
  801. }
  802. inline _IncludeOpenItem(SFGAOF f)
  803. {
  804. return (f & (SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STREAM | SFGAO_FILESYSTEM));
  805. }
  806. inline _IsFolderShortcut(SFGAOF f)
  807. {
  808. return ((f & (SFGAO_FOLDER | SFGAO_LINK)) == (SFGAO_FOLDER | SFGAO_LINK));
  809. }
  810. inline _IsStream(SFGAOF f)
  811. {
  812. return ((f & SFGAO_STREAM) || ((f & SFGAO_FILESYSTEM) && !(f & SFGAO_FILESYSANCESTOR)));
  813. }
  814. inline _IsCollection(SFGAOF f)
  815. {
  816. return ((f & (SFGAO_STREAM | SFGAO_FOLDER)) == (SFGAO_STREAM | SFGAO_FOLDER));
  817. }
  818. #define MLBI_PERMANENT 0x0001
  819. #define MLBI_PSFFROMPARENT 0x0002
  820. MYLISTBOXITEM::MYLISTBOXITEM() : _cRef(1)
  821. {
  822. }
  823. // This is a special Case Init Function for Initializing Recent Files folder at the top
  824. // of namespace in the look in control.
  825. BOOL MYLISTBOXITEM::Init(
  826. HWND hwndCmb,
  827. IShellFolder *psf,
  828. LPCITEMIDLIST pidl,
  829. DWORD c,
  830. DWORD f,
  831. DWORD dwAttribs,
  832. int iImg,
  833. int iSelImg)
  834. {
  835. _hwndCmb = hwndCmb;
  836. cIndent = c;
  837. dwFlags = f;
  838. pidlThis = ILClone(pidl);
  839. pidlFull = ILClone(pidl);
  840. psfSub = psf;
  841. psfSub->AddRef();
  842. dwAttrs = dwAttribs;
  843. iImage = iImg;
  844. iSelectedImage = iSelImg;
  845. if (pidlThis && pidlFull)
  846. {
  847. return TRUE;
  848. }
  849. else
  850. {
  851. return FALSE;
  852. }
  853. }
  854. BOOL MYLISTBOXITEM::Init(
  855. HWND hwndCmb,
  856. MYLISTBOXITEM *pParentItem,
  857. IShellFolder *psf,
  858. LPCITEMIDLIST pidl,
  859. DWORD c,
  860. DWORD f,
  861. IShellTaskScheduler* pScheduler)
  862. {
  863. if (psf == NULL)
  864. {
  865. // Invalid parameter passed.
  866. return FALSE;
  867. }
  868. _hwndCmb = hwndCmb;
  869. cIndent = c;
  870. dwFlags = f;
  871. pidlThis = ILClone(pidl);
  872. if (pParentItem == NULL)
  873. {
  874. pidlFull = ILClone(pidl);
  875. }
  876. else
  877. {
  878. pidlFull = ILCombine(pParentItem->pidlFull, pidl);
  879. }
  880. if (pidlThis == NULL || pidlFull == NULL)
  881. {
  882. psfSub = NULL;
  883. }
  884. if (dwFlags & MLBI_PSFFROMPARENT)
  885. {
  886. psfParent = psf;
  887. }
  888. else
  889. {
  890. psfSub = psf;
  891. }
  892. psf->AddRef();
  893. dwAttrs = SHGetAttributes(psf, pidl, SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STREAM | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_SHARE);
  894. AddRef();
  895. if (E_PENDING != SHMapIDListToImageListIndexAsync(pScheduler, psf, pidl, 0,
  896. _AsyncIconTaskCallback, this, NULL, &iImage, &iSelectedImage))
  897. {
  898. Release();
  899. }
  900. if (pidlFull && pidlThis)
  901. {
  902. return TRUE;
  903. }
  904. else
  905. {
  906. return FALSE;
  907. }
  908. }
  909. ULONG MYLISTBOXITEM::AddRef()
  910. {
  911. return InterlockedIncrement(&_cRef);
  912. }
  913. ULONG MYLISTBOXITEM::Release()
  914. {
  915. ASSERT( 0 != _cRef );
  916. ULONG cRef = InterlockedDecrement(&_cRef);
  917. if ( 0 == cRef )
  918. {
  919. delete this;
  920. }
  921. return cRef;
  922. }
  923. MYLISTBOXITEM::~MYLISTBOXITEM()
  924. {
  925. if (psfSub != NULL)
  926. {
  927. psfSub->Release();
  928. }
  929. if (psfParent != NULL)
  930. {
  931. psfParent->Release();
  932. }
  933. if (pidlThis != NULL)
  934. {
  935. SHFree(pidlThis);
  936. }
  937. if (pidlFull != NULL)
  938. {
  939. SHFree(pidlFull);
  940. }
  941. }
  942. void MYLISTBOXITEM::_AsyncIconTaskCallback(LPCITEMIDLIST pidl, void * pvData,
  943. void * pvHint, INT iIconIndex, INT iOpenIconIndex)
  944. {
  945. MYLISTBOXITEM *plbItem = (MYLISTBOXITEM *)pvData;
  946. plbItem->iImage = iIconIndex;
  947. plbItem->iSelectedImage = iOpenIconIndex;
  948. // Make sure the combobox redraws.
  949. if (plbItem->_hwndCmb)
  950. {
  951. RECT rc;
  952. if (GetClientRect(plbItem->_hwndCmb, &rc))
  953. {
  954. InvalidateRect(plbItem->_hwndCmb, &rc, FALSE);
  955. }
  956. }
  957. plbItem->Release();
  958. }
  959. BOOL IsContainer(
  960. IShellFolder *psf,
  961. LPCITEMIDLIST pidl)
  962. {
  963. return _IsOpenContainer(SHGetAttributes(psf, pidl, SFGAO_FOLDER | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR));
  964. }
  965. BOOL IsLink(
  966. IShellFolder *psf,
  967. LPCITEMIDLIST pidl)
  968. {
  969. return SHGetAttributes(psf, pidl, SFGAO_LINK);
  970. }
  971. IShellFolder *MYLISTBOXITEM::GetShellFolder()
  972. {
  973. if (!psfSub)
  974. {
  975. HRESULT hr;
  976. if (ILIsEmpty(pidlThis)) // Some caller passes an empty pidl
  977. hr = psfParent->QueryInterface(IID_PPV_ARG(IShellFolder, &psfSub));
  978. else
  979. hr = psfParent->BindToObject(pidlThis, NULL, IID_PPV_ARG(IShellFolder, &psfSub));
  980. if (FAILED(hr))
  981. {
  982. psfSub = NULL;
  983. }
  984. else
  985. {
  986. psfParent->Release();
  987. psfParent = NULL;
  988. }
  989. }
  990. return (psfSub);
  991. }
  992. ////////////////////////////////////////////////////////////////////////////
  993. //
  994. // MYLISTBOXITEM::SwitchCurrentDirectory
  995. //
  996. ////////////////////////////////////////////////////////////////////////////
  997. void MYLISTBOXITEM::SwitchCurrentDirectory(
  998. ICurrentWorkingDirectory * pcwd)
  999. {
  1000. TCHAR szDir[MAX_PATH + 1];
  1001. if (!pidlFull)
  1002. {
  1003. SHGetSpecialFolderPath(NULL, szDir, CSIDL_DESKTOPDIRECTORY, FALSE);
  1004. }
  1005. else
  1006. {
  1007. GetPathFromLocation(this, szDir);
  1008. }
  1009. if (szDir[0])
  1010. {
  1011. SetCurrentDirectory(szDir);
  1012. //
  1013. // Let AutoComplete know our Current Working Directory.
  1014. //
  1015. if (pcwd)
  1016. pcwd->SetDirectory(szDir);
  1017. }
  1018. }
  1019. ////////////////////////////////////////////////////////////////////////////
  1020. //
  1021. // ShouldIncludeObject
  1022. //
  1023. ////////////////////////////////////////////////////////////////////////////
  1024. BOOL ShouldIncludeObject(
  1025. CFileOpenBrowser *that,
  1026. LPSHELLFOLDER psfParent,
  1027. LPCITEMIDLIST pidl,
  1028. DWORD dwFlags)
  1029. {
  1030. BOOL fInclude = FALSE;
  1031. DWORD dwAttrs = SHGetAttributes(psfParent, pidl, SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STREAM | SFGAO_FILESYSTEM);
  1032. if (dwAttrs)
  1033. {
  1034. if ((dwFlags & OFN_ENABLEINCLUDENOTIFY) && that)
  1035. {
  1036. fInclude = BOOLFROMPTR(CD_SendIncludeItemNotify(that->_hSubDlg,
  1037. that->_hwndDlg,
  1038. psfParent,
  1039. pidl,
  1040. that->_pOFN,
  1041. that->_pOFI));
  1042. }
  1043. if (!fInclude)
  1044. {
  1045. fInclude = that->_bSave ? _IncludeSaveItem(dwAttrs) : _IncludeOpenItem(dwAttrs);
  1046. }
  1047. }
  1048. return (fInclude);
  1049. }
  1050. ////////////////////////////////////////////////////////////////////////////
  1051. //
  1052. // CFileOpenBrowser::EnableFileMRU
  1053. //
  1054. //
  1055. ////////////////////////////////////////////////////////////////////////////
  1056. void CFileOpenBrowser::EnableFileMRU(BOOL fEnable)
  1057. {
  1058. HWND hwnd = NULL;
  1059. if (fEnable)
  1060. {
  1061. HWND hwndCombo;
  1062. //Make sure combobox is there
  1063. hwndCombo = GetDlgItem(_hwndDlg, cmb13);
  1064. if (hwndCombo)
  1065. {
  1066. // if we are using the combobox then remove the edit box
  1067. _bUseCombo = TRUE;
  1068. SetFocus(hwndCombo);
  1069. hwnd = GetDlgItem(_hwndDlg,edt1);
  1070. }
  1071. else
  1072. {
  1073. goto UseEdit;
  1074. }
  1075. }
  1076. else
  1077. {
  1078. UseEdit:
  1079. //We are not going to use combobox.
  1080. _bUseCombo = FALSE;
  1081. //SetFocus to the edit window
  1082. SetFocus(GetDlgItem(_hwndDlg,edt1));
  1083. //Destroy the combo box
  1084. hwnd = GetDlgItem(_hwndDlg, cmb13);
  1085. }
  1086. if (hwnd)
  1087. {
  1088. DestroyWindow(hwnd);
  1089. }
  1090. }
  1091. ////////////////////////////////////////////////////////////////////////////
  1092. //
  1093. // CFileOpenBrowser::CreateToolbar
  1094. //
  1095. // CreateToolbar member function.
  1096. // creates and initializes the places bar in the dialog
  1097. //
  1098. //
  1099. ////////////////////////////////////////////////////////////////////////////
  1100. BOOL CFileOpenBrowser::CreateToolbar()
  1101. {
  1102. TBBUTTON atbButtons[] =
  1103. {
  1104. { 0, IDC_BACK, 0, BTNS_BUTTON, { 0, 0 }, 0, -1 },
  1105. { VIEW_PARENTFOLDER, IDC_PARENT, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, -1 },
  1106. { VIEW_NEWFOLDER, IDC_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, -1 },
  1107. { VIEW_LIST, IDC_VIEWMENU, TBSTATE_ENABLED, BTNS_WHOLEDROPDOWN, { 0, 0 }, 0, -1 },
  1108. };
  1109. TBBUTTON atbButtonsNT4[] =
  1110. {
  1111. { 0, 0, 0, BTNS_SEP, { 0, 0 }, 0, 0 },
  1112. { VIEW_PARENTFOLDER, IDC_PARENT, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, -1 },
  1113. { 0, 0, 0, BTNS_SEP, { 0, 0 }, 0, 0 },
  1114. { VIEW_NEWFOLDER, IDC_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, -1 },
  1115. { 0, 0, 0, BTNS_SEP, { 0, 0 }, 0, 0 },
  1116. { VIEW_LIST, IDC_VIEWLIST, TBSTATE_ENABLED | TBSTATE_CHECKED, BTNS_CHECKGROUP, { 0, 0 }, 0, -1 },
  1117. { VIEW_DETAILS, IDC_VIEWDETAILS, TBSTATE_ENABLED, BTNS_CHECKGROUP, { 0, 0 }, 0, -1 }
  1118. };
  1119. LPTBBUTTON lpButton = atbButtons;
  1120. int iNumButtons = ARRAYSIZE(atbButtons);
  1121. RECT rcToolbar;
  1122. BOOL bBogusCtrlID = SHGetAppCompatFlags(ACF_FILEOPENBOGUSCTRLID) & ACF_FILEOPENBOGUSCTRLID;
  1123. DWORD dwStyle = WS_TABSTOP | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | WS_CHILD | CCS_NORESIZE |WS_GROUP | CCS_NODIVIDER;
  1124. // If app wants toolbar to have bogus ctrl ID, make it not a tabstop.
  1125. if (bBogusCtrlID)
  1126. dwStyle &= ~WS_TABSTOP;
  1127. BOOL bAppHack = (CDGetAppCompatFlags() & CDACF_NT40TOOLBAR) ? TRUE : FALSE;
  1128. if (bAppHack)
  1129. {
  1130. lpButton = atbButtonsNT4;
  1131. iNumButtons =ARRAYSIZE(atbButtonsNT4);
  1132. dwStyle &= ~TBSTYLE_FLAT;
  1133. }
  1134. GetControlRect(_hwndDlg, stc1, &rcToolbar);
  1135. _hwndToolbar = CreateToolbarEx(_hwndDlg,
  1136. dwStyle,
  1137. // stc1: use static text ctrlID
  1138. // For apps that expect the old bad way, use IDOK.
  1139. bBogusCtrlID ? IDOK : stc1,
  1140. 12,
  1141. HINST_COMMCTRL,
  1142. IDB_VIEW_SMALL_COLOR,
  1143. lpButton,
  1144. iNumButtons,
  1145. 0,
  1146. 0,
  1147. 0,
  1148. 0,
  1149. sizeof(TBBUTTON));
  1150. if (_hwndToolbar)
  1151. {
  1152. TBADDBITMAP ab;
  1153. SendMessage(_hwndToolbar, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_DRAWDDARROWS, TBSTYLE_EX_DRAWDDARROWS);
  1154. //Documentation says that we need to send TB_BUTTONSTRUCTSIZE before we add bitmaps
  1155. SendMessage(_hwndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), (LPARAM)0);
  1156. SendMessage(_hwndToolbar, TB_SETMAXTEXTROWS, (WPARAM)0, (LPARAM)0);
  1157. if (!bAppHack)
  1158. {
  1159. if (!IsRestricted(REST_NOBACKBUTTON))
  1160. {
  1161. //Add the back/forward navigation buttons
  1162. ab.hInst = HINST_COMMCTRL;
  1163. ab.nID = IDB_HIST_SMALL_COLOR;
  1164. int iIndex = (int) SendMessage(_hwndToolbar, TB_ADDBITMAP, 5, (LPARAM)&ab);
  1165. //Now set the image index for back button
  1166. TBBUTTONINFO tbbi;
  1167. tbbi.cbSize = sizeof(TBBUTTONINFO);
  1168. tbbi.dwMask = TBIF_IMAGE | TBIF_BYINDEX;
  1169. SendMessage(_hwndToolbar, TB_GETBUTTONINFO, (WPARAM)0, (LPARAM)&tbbi);
  1170. tbbi.iImage = iIndex + HIST_BACK;
  1171. SendMessage(_hwndToolbar, TB_SETBUTTONINFO, (WPARAM)0, (LPARAM)&tbbi);
  1172. }
  1173. else
  1174. {
  1175. //Back button is restricted. Delete the back button from the toolbar
  1176. SendMessage(_hwndToolbar, TB_DELETEBUTTON, (WPARAM)0, (LPARAM)0);
  1177. }
  1178. }
  1179. ::SetWindowPos(_hwndToolbar,
  1180. // Place it after its static control (unless app expects old way)
  1181. bBogusCtrlID ? NULL : GetDlgItem(_hwndDlg, stc1),
  1182. rcToolbar.left,
  1183. rcToolbar.top,
  1184. rcToolbar.right - rcToolbar.left,
  1185. rcToolbar.bottom - rcToolbar.top,
  1186. SWP_NOACTIVATE | SWP_SHOWWINDOW | (bBogusCtrlID ? SWP_NOZORDER : 0));
  1187. return TRUE;
  1188. }
  1189. return FALSE;
  1190. }
  1191. ////////////////////////////////////////////////////////////////////////////
  1192. //
  1193. // CFileOpenBrowser::_GetPBItemFromCSIDL(DWORD csidl, SHFILEINFO * psfi, LPITEMIDLIST *ppidl)
  1194. // Gets a SHFileInfo and pidl for a CSIDL which is used in the places bar
  1195. ////////////////////////////////////////////////////////////////////////////
  1196. BOOL CFileOpenBrowser::_GetPBItemFromCSIDL(DWORD csidl, SHFILEINFO * psfi, LPITEMIDLIST *ppidl)
  1197. {
  1198. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidl, ppidl)))
  1199. {
  1200. // Are there restrictions on mydocuments or mycomputer? Check for SFGAO_NONENUMERATED
  1201. // This is for the policies that hide mydocs and mycomputer.
  1202. if ((csidl == CSIDL_PERSONAL) || (csidl == CSIDL_DRIVES))
  1203. {
  1204. DWORD dwAttr = SFGAO_NONENUMERATED;
  1205. if (SUCCEEDED(SHGetAttributesOf(*ppidl, &dwAttr)) && (dwAttr & SFGAO_NONENUMERATED))
  1206. {
  1207. // We won't create a placesbar item for this guy.
  1208. ILFree(*ppidl);
  1209. return FALSE;
  1210. }
  1211. }
  1212. return SHGetFileInfo((LPCTSTR)*ppidl, 0, psfi, sizeof(*psfi), SHGFI_SYSICONINDEX | SHGFI_PIDL | SHGFI_DISPLAYNAME);
  1213. }
  1214. return FALSE;
  1215. }
  1216. typedef struct
  1217. {
  1218. LPCWSTR pszToken;
  1219. int nFolder; //CSIDL
  1220. } STRINGTOCSIDLMAP;
  1221. static const STRINGTOCSIDLMAP g_rgStringToCSIDL[] =
  1222. {
  1223. { L"MyDocuments", CSIDL_PERSONAL },
  1224. { L"MyMusic", CSIDL_MYMUSIC },
  1225. { L"MyPictures", CSIDL_MYPICTURES },
  1226. { L"MyVideo", CSIDL_MYVIDEO },
  1227. { L"CommonDocuments", CSIDL_COMMON_DOCUMENTS },
  1228. { L"CommonPictures", CSIDL_COMMON_PICTURES },
  1229. { L"CommonMusic", CSIDL_COMMON_MUSIC },
  1230. { L"CommonVideo", CSIDL_COMMON_VIDEO },
  1231. { L"Desktop", CSIDL_DESKTOP },
  1232. { L"Recent", CSIDL_RECENT },
  1233. { L"MyNetworkPlaces", CSIDL_NETHOOD },
  1234. { L"MyFavorites", CSIDL_FAVORITES },
  1235. { L"MyComputer", CSIDL_DRIVES },
  1236. { L"Printers", CSIDL_PRINTERS },
  1237. { L"ProgramFiles", CSIDL_PROGRAM_FILES },
  1238. };
  1239. ////////////////////////////////////////////////////////////////////////////
  1240. //
  1241. // CFileOpenBrowser::_GetPBItemFromTokenStrings(LPTSTR lpszPath, SHFILEINFO * psfi, LPITEMIDLIST *ppidl)
  1242. // Gets a SHFileInfo and pidl for a path which is used in the places bar
  1243. ////////////////////////////////////////////////////////////////////////////
  1244. BOOL CFileOpenBrowser::_GetPBItemFromTokenStrings(LPTSTR lpszPath, SHFILEINFO * psfi, LPITEMIDLIST *ppidl)
  1245. {
  1246. for (int i = 0; i < ARRAYSIZE(g_rgStringToCSIDL); i++)
  1247. {
  1248. if (StrCmpI(lpszPath, g_rgStringToCSIDL[i].pszToken) == 0)
  1249. {
  1250. return _GetPBItemFromCSIDL(g_rgStringToCSIDL[i].nFolder, psfi, ppidl);
  1251. }
  1252. }
  1253. return FALSE;
  1254. }
  1255. ////////////////////////////////////////////////////////////////////////////
  1256. //
  1257. // CFileOpenBrowser::_GetPBItemFromPath(LPTSTR lpszPath, SHFILEINFO * psfi, LPITEMIDLIST *ppidl)
  1258. // Gets a SHFileInfo and pidl for a path which is used in the places bar
  1259. ////////////////////////////////////////////////////////////////////////////
  1260. BOOL CFileOpenBrowser::_GetPBItemFromPath(LPTSTR lpszPath, size_t cchPath, SHFILEINFO * psfi, LPITEMIDLIST *ppidl)
  1261. {
  1262. TCHAR szTemp[MAX_PATH];
  1263. BOOL bRet = FALSE;
  1264. //Expand environment strings if any
  1265. if (ExpandEnvironmentStrings(lpszPath, szTemp, SIZECHARS(szTemp)))
  1266. {
  1267. bRet = SUCCEEDED(StringCchCopy(lpszPath, cchPath, szTemp));
  1268. }
  1269. if (bRet)
  1270. {
  1271. SHGetFileInfo(lpszPath,0,psfi,sizeof(*psfi), SHGFI_ICON|SHGFI_LARGEICON | SHGFI_DISPLAYNAME);
  1272. SHILCreateFromPath(lpszPath, ppidl, NULL);
  1273. }
  1274. return bRet;
  1275. }
  1276. ////////////////////////////////////////////////////////////////////////////
  1277. //
  1278. // CFileOpenBrowser::_EnumPlacesBarItem(HKEY, int, SHFILEINFO)
  1279. // Enumerates the Place bar item in the registry
  1280. ////////////////////////////////////////////////////////////////////////////
  1281. BOOL CFileOpenBrowser::_EnumPlacesBarItem(HKEY hkey, int i , SHFILEINFO * psfi, LPITEMIDLIST *ppidl)
  1282. {
  1283. BOOL bRet = FALSE;
  1284. if (hkey == NULL)
  1285. {
  1286. static const int aPlaces[] =
  1287. {
  1288. CSIDL_RECENT,
  1289. CSIDL_DESKTOP,
  1290. CSIDL_PERSONAL,
  1291. CSIDL_DRIVES,
  1292. CSIDL_NETWORK,
  1293. };
  1294. if (i >= 0 && i < MAXPLACESBARITEMS)
  1295. {
  1296. bRet = _GetPBItemFromCSIDL(aPlaces[i], psfi, ppidl);
  1297. }
  1298. }
  1299. else
  1300. {
  1301. TCHAR szName[MAX_PATH];
  1302. TCHAR szValue[MAX_PATH];
  1303. DWORD cbValue;
  1304. DWORD dwType;
  1305. cbValue = sizeof(szValue); // Byte size, not character size.
  1306. StringCchPrintf(szName, ARRAYSIZE(szName), L"Place%d", i);
  1307. if (SHRegGetValue(hkey, NULL, szName, SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND | SRRF_RT_DWORD, &dwType, (LPBYTE)szValue, &cbValue) == ERROR_SUCCESS)
  1308. {
  1309. if ((dwType != REG_DWORD) && (dwType != REG_EXPAND_SZ) && (dwType != REG_SZ))
  1310. {
  1311. return FALSE;
  1312. }
  1313. if (dwType == REG_DWORD)
  1314. {
  1315. bRet = _GetPBItemFromCSIDL((DWORD)*szValue, psfi, ppidl);
  1316. }
  1317. else
  1318. {
  1319. if (dwType == REG_SZ)
  1320. {
  1321. // Check for special strings that indicate places.
  1322. bRet = _GetPBItemFromTokenStrings(szValue, psfi, ppidl);
  1323. }
  1324. if (!bRet)
  1325. {
  1326. bRet = _GetPBItemFromPath(szValue, ARRAYSIZE(szValue), psfi, ppidl);
  1327. }
  1328. }
  1329. }
  1330. }
  1331. return bRet;
  1332. }
  1333. ////////////////////////////////////////////////////////////////////////////
  1334. //
  1335. // CFileOpenBrowser::_GetPlacesBarItemToolTip
  1336. //
  1337. ////////////////////////////////////////////////////////////////////////////
  1338. BOOL CFileOpenBrowser::_GetPlacesBarItemToolTip(int idCmd, LPTSTR pText, DWORD dwSize)
  1339. {
  1340. TBBUTTONINFO tbbi;
  1341. LPITEMIDLIST pidl;
  1342. BOOL bRet = FALSE;
  1343. // Return null string in case anything goes wrong
  1344. pText[0] = TEXT('\0');
  1345. tbbi.cbSize = SIZEOF(tbbi);
  1346. tbbi.lParam = 0;
  1347. tbbi.dwMask = TBIF_LPARAM;
  1348. if (SendMessage(_hwndPlacesbar, TB_GETBUTTONINFO, idCmd, (LPARAM)&tbbi) < 0)
  1349. return FALSE;
  1350. pidl = (LPITEMIDLIST)tbbi.lParam;
  1351. if (pidl)
  1352. {
  1353. IShellFolder *psf;
  1354. LPITEMIDLIST pidlLast;
  1355. HRESULT hres = CDBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), (LPCITEMIDLIST *)&pidlLast);
  1356. if (SUCCEEDED(hres))
  1357. {
  1358. IQueryInfo *pqi;
  1359. if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST *)&pidlLast, IID_IQueryInfo, NULL, (void**)&pqi)))
  1360. {
  1361. WCHAR *pwszTip;
  1362. if (SUCCEEDED(pqi->GetInfoTip(0, &pwszTip)) && pwszTip)
  1363. {
  1364. SHUnicodeToTChar(pwszTip, pText, dwSize);
  1365. SHFree(pwszTip);
  1366. bRet = TRUE;
  1367. }
  1368. pqi->Release();
  1369. }
  1370. psf->Release();
  1371. }
  1372. }
  1373. return bRet;
  1374. }
  1375. ///////////////////////////////////////////////////////////////////////////
  1376. //
  1377. // CFileOpenBrorwser::_RecreatePlacesbar
  1378. //
  1379. // called when something changes that requires the placesbar be recreated (e.g. icons change)
  1380. //
  1381. ///////////////////////////////////////////////////////////////////////////
  1382. void CFileOpenBrowser::_RecreatePlacesbar()
  1383. {
  1384. if (_hwndPlacesbar)
  1385. {
  1386. // Free any pidls in the places bar
  1387. _CleanupPlacesbar();
  1388. // Remove all buttons in places bar
  1389. int cButtons = (int)SendMessage(_hwndPlacesbar, TB_BUTTONCOUNT, 0, 0);
  1390. for (int i = 0; i < cButtons; i++)
  1391. {
  1392. SendMessage(_hwndPlacesbar, TB_DELETEBUTTON, 0, 0);
  1393. }
  1394. // Put them back in, with potentially new images.
  1395. _FillPlacesbar(_hwndPlacesbar);
  1396. }
  1397. }
  1398. ////////////////////////////////////////////////////////////////////////////
  1399. //
  1400. // CFileOpenBrowser::CreatePlacesBar
  1401. //
  1402. // CreatePlacesBar member function.
  1403. // creates and initializes the places bar in the dialog
  1404. //
  1405. //
  1406. ////////////////////////////////////////////////////////////////////////////
  1407. HWND CFileOpenBrowser::CreatePlacesbar(HWND hwndDlg)
  1408. {
  1409. HWND hwndTB = GetDlgItem(hwndDlg, ctl1);
  1410. if (hwndTB)
  1411. {
  1412. //Set the version for the toolbar
  1413. SendMessage(hwndTB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  1414. // Sets the size of the TBBUTTON structure.
  1415. SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  1416. SetWindowTheme(hwndTB, L"Placesbar", NULL);
  1417. SendMessage(hwndTB, TB_SETMAXTEXTROWS, 2, 0); // Try to set toolbar to show 2 rows
  1418. // For themes, we'll change the default padding, so we need to save it
  1419. // off in case we need to restore it.
  1420. _dwPlacesbarPadding = SendMessage(hwndTB, TB_GETPADDING, 0, 0);
  1421. _FillPlacesbar(hwndTB);
  1422. }
  1423. return hwndTB;
  1424. }
  1425. void CFileOpenBrowser::_FillPlacesbar(HWND hwndPlacesbar)
  1426. {
  1427. HKEY hkey = NULL;
  1428. int i;
  1429. TBBUTTON tbb;
  1430. SHFILEINFO sfi;
  1431. LPITEMIDLIST pidl;
  1432. HIMAGELIST himl;
  1433. //See if Places bar key is available
  1434. RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_PLACESBAR, 0, KEY_READ, &hkey);
  1435. Shell_GetImageLists(&himl, NULL);
  1436. for (i=0; i < MAXPLACESBARITEMS; i++)
  1437. {
  1438. if (_EnumPlacesBarItem(hkey, i, &sfi, &pidl))
  1439. {
  1440. //Now Add the item to the toolbar
  1441. tbb.iBitmap = sfi.iIcon;
  1442. tbb.fsState = TBSTATE_ENABLED;
  1443. tbb.fsStyle = BTNS_BUTTON;
  1444. tbb.idCommand = IDC_PLACESBAR_BASE + _iCommandID;
  1445. tbb.iString = (INT_PTR)&sfi.szDisplayName;
  1446. tbb.dwData = (INT_PTR)pidl;
  1447. SendMessage(hwndPlacesbar, TB_ADDBUTTONS, (UINT)1, (LPARAM)&tbb);
  1448. //Increment the command ID
  1449. _iCommandID++;
  1450. }
  1451. }
  1452. //Close the reg key
  1453. if (hkey)
  1454. {
  1455. RegCloseKey(hkey);
  1456. }
  1457. HIMAGELIST himlOld = (HIMAGELIST) SendMessage(hwndPlacesbar, TB_SETIMAGELIST, 0, (LPARAM)himl);
  1458. // Destroy the old imagelist only the first time. After this, the imagelist we get back is the
  1459. // one we've set, the system imagelist.
  1460. if ((himlOld != NULL) && _bDestroyPlacesbarImageList)
  1461. {
  1462. ImageList_Destroy(himlOld);
  1463. }
  1464. _bDestroyPlacesbarImageList = FALSE;
  1465. OnThemeActive(_hwndDlg, IsAppThemed());
  1466. // Add the buttons
  1467. SendMessage(hwndPlacesbar, TB_AUTOSIZE, (WPARAM)0, (LPARAM)0);
  1468. }
  1469. void CFileOpenBrowser::_CleanupPlacesbar()
  1470. {
  1471. if (_hwndPlacesbar)
  1472. {
  1473. TBBUTTONINFO tbbi;
  1474. LPITEMIDLIST pidl;
  1475. for (int i=0; i < MAXPLACESBARITEMS; i++)
  1476. {
  1477. tbbi.cbSize = SIZEOF(tbbi);
  1478. tbbi.lParam = 0;
  1479. tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX;
  1480. if (SendMessage(_hwndPlacesbar, TB_GETBUTTONINFO, i, (LPARAM)&tbbi) >= 0)
  1481. {
  1482. pidl = (LPITEMIDLIST)tbbi.lParam;
  1483. if (pidl)
  1484. {
  1485. ILFree(pidl);
  1486. }
  1487. }
  1488. }
  1489. }
  1490. }
  1491. // Less padding for themes
  1492. #define PLACESBAR_THEMEPADDING MAKELPARAM(2, 2)
  1493. void CFileOpenBrowser::OnThemeActive(HWND hwndDlg, BOOL bActive)
  1494. {
  1495. HWND hwndPlacesBar = GetDlgItem(hwndDlg, ctl1);
  1496. if (hwndPlacesBar)
  1497. {
  1498. // For themes, use the default colour scheme for the places toolbar:
  1499. COLORSCHEME cs;
  1500. cs.dwSize = SIZEOF(cs);
  1501. cs.clrBtnHighlight = bActive ? CLR_DEFAULT : GetSysColor(COLOR_BTNHIGHLIGHT);
  1502. cs.clrBtnShadow = bActive ? CLR_DEFAULT : GetSysColor(COLOR_3DDKSHADOW);
  1503. SendMessage(hwndPlacesBar, TB_SETCOLORSCHEME, 0, (LPARAM) &cs);
  1504. // For themes, we have a background, so make the toolbar background non-transparent
  1505. // (the resource specifies TBSTYLE_FLAT, which includes TBSTYLE_TRANSPARENT)
  1506. DWORD_PTR dwTBStyle = SendMessage(hwndPlacesBar, TB_GETSTYLE, 0, 0);
  1507. SendMessage(hwndPlacesBar, TB_SETSTYLE, 0, bActive ? (dwTBStyle & ~TBSTYLE_TRANSPARENT) : (dwTBStyle | TBSTYLE_TRANSPARENT));
  1508. // Special padding for themes on comctlv6 only (RAID #424528)
  1509. if (SendMessage(hwndPlacesBar, CCM_GETVERSION, 0, 0) >= 0x600)
  1510. {
  1511. SendMessage(hwndPlacesBar, TB_SETPADDING, 0, bActive? PLACESBAR_THEMEPADDING : _dwPlacesbarPadding);
  1512. }
  1513. // Remove the clientedge extended style for themes
  1514. LONG_PTR dwPlacesExStyle = GetWindowLongPtr(hwndPlacesBar, GWL_EXSTYLE);
  1515. SetWindowLongPtr(hwndPlacesBar, GWL_EXSTYLE, bActive ? (dwPlacesExStyle & ~WS_EX_CLIENTEDGE) : (dwPlacesExStyle | WS_EX_CLIENTEDGE));
  1516. // And apply these frame style changes...
  1517. SetWindowPos(hwndPlacesBar, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
  1518. // Ensure buttons go right to edge of client area (client area has changed)
  1519. RECT rc;
  1520. GetClientRect(hwndPlacesBar, &rc);
  1521. SendMessage(hwndPlacesBar, TB_SETBUTTONWIDTH, 0, (LPARAM)MAKELONG(RECTWIDTH(rc), RECTWIDTH(rc)));
  1522. }
  1523. }
  1524. ////////////////////////////////////////////////////////////////////////////
  1525. //
  1526. // CFileOpenBrowser::CFileOpenBrowser
  1527. //
  1528. // CFileOpenBrowser constructor.
  1529. // Minimal construction of the object. Much more construction in
  1530. // InitLocation.
  1531. //
  1532. ////////////////////////////////////////////////////////////////////////////
  1533. CFileOpenBrowser::CFileOpenBrowser(
  1534. HWND hDlg,
  1535. BOOL fIsSaveAs)
  1536. : _cRef(1),
  1537. _iCurrentLocation(-1),
  1538. _iVersion(OPENFILEVERSION),
  1539. _pCurrentLocation(NULL),
  1540. _psv(NULL),
  1541. _hwndDlg(hDlg),
  1542. _hwndView(NULL),
  1543. _hwndToolbar(NULL),
  1544. _psfCurrent(NULL),
  1545. _bSave(fIsSaveAs),
  1546. _iComboIndex(-1),
  1547. _hwndTips(NULL),
  1548. _ptlog(NULL),
  1549. _iCheckedButton(-1),
  1550. _pidlSelection(NULL),
  1551. _lpOKProc(NULL)
  1552. {
  1553. _iNodeDesktop = NODE_DESKTOP;
  1554. _iNodeDrives = NODE_DRIVES;
  1555. _szLastFilter[0] = CHAR_NULL;
  1556. _bEnableSizing = FALSE;
  1557. _bUseCombo = TRUE;
  1558. _hwndGrip = NULL;
  1559. _ptLastSize.x = 0;
  1560. _ptLastSize.y = 0;
  1561. _sizeView.cx = 0;
  1562. _bUseSizeView = FALSE;
  1563. _bAppRedrawn = FALSE;
  1564. _bDestroyPlacesbarImageList = TRUE;
  1565. HMENU hMenu;
  1566. hMenu = GetSystemMenu(hDlg, FALSE);
  1567. DeleteMenu(hMenu, SC_MINIMIZE, MF_BYCOMMAND);
  1568. DeleteMenu(hMenu, SC_MAXIMIZE, MF_BYCOMMAND);
  1569. DeleteMenu(hMenu, SC_RESTORE, MF_BYCOMMAND);
  1570. Shell_GetImageLists(NULL, &_himl);
  1571. //
  1572. // This setting could change on the fly, but I really don't care
  1573. // about that rare case.
  1574. //
  1575. SHELLSTATE ss;
  1576. SHGetSetSettings(&ss, SSF_SHOWEXTENSIONS, FALSE);
  1577. _fShowExtensions = ss.fShowExtensions;
  1578. _pScheduler = NULL;
  1579. CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC, IID_PPV_ARG(IShellTaskScheduler, &_pScheduler));
  1580. }
  1581. ////////////////////////////////////////////////////////////////////////////
  1582. //
  1583. // CFileOpenBrowser::~CFileOpenBrowser
  1584. //
  1585. // CFileOpenBrowser destructor.
  1586. //
  1587. ////////////////////////////////////////////////////////////////////////////
  1588. CFileOpenBrowser::~CFileOpenBrowser()
  1589. {
  1590. if (_uRegister)
  1591. {
  1592. SHChangeNotifyDeregister(_uRegister);
  1593. _uRegister = 0;
  1594. }
  1595. //
  1596. // Ensure that we discard the tooltip window.
  1597. //
  1598. if (_hwndTips)
  1599. {
  1600. DestroyWindow(_hwndTips);
  1601. _hwndTips = NULL; // handle is no longer valid
  1602. }
  1603. if (_hwndGrip)
  1604. {
  1605. DestroyWindow(_hwndGrip);
  1606. _hwndGrip = NULL;
  1607. }
  1608. _CleanupPlacesbar();
  1609. if (_pcwd)
  1610. {
  1611. _pcwd->Release();
  1612. }
  1613. if (_ptlog)
  1614. {
  1615. _ptlog->Release();
  1616. }
  1617. Pidl_Set(&_pidlSelection,NULL);
  1618. if (_pScheduler)
  1619. _pScheduler->Release();
  1620. }
  1621. HRESULT CFileOpenBrowser::QueryInterface(REFIID riid, void **ppvObj)
  1622. {
  1623. static const QITAB qit[] = {
  1624. QITABENT(CFileOpenBrowser, IShellBrowser), // IID_IShellBrowser
  1625. QITABENT(CFileOpenBrowser, ICommDlgBrowser2), // IID_ICommDlgBrowser2
  1626. QITABENTMULTI(CFileOpenBrowser, ICommDlgBrowser, ICommDlgBrowser2), // IID_ICommDlgBrowser
  1627. QITABENT(CFileOpenBrowser, IServiceProvider), // IID_IServiceProvider
  1628. { 0 },
  1629. };
  1630. return QISearch(this, qit, riid, ppvObj);
  1631. }
  1632. ULONG CFileOpenBrowser::AddRef()
  1633. {
  1634. return InterlockedIncrement(&_cRef);
  1635. }
  1636. ULONG CFileOpenBrowser::Release()
  1637. {
  1638. ASSERT( 0 != _cRef );
  1639. ULONG cRef = InterlockedDecrement(&_cRef);
  1640. if ( 0 == cRef )
  1641. {
  1642. delete this;
  1643. }
  1644. return cRef;
  1645. }
  1646. STDMETHODIMP CFileOpenBrowser::GetWindow(HWND *phwnd)
  1647. {
  1648. *phwnd = _hwndDlg;
  1649. return S_OK;
  1650. }
  1651. ////////////////////////////////////////////////////////////////////////////
  1652. //
  1653. // CFileOpenBrowser::ContextSensitiveHelp
  1654. //
  1655. ////////////////////////////////////////////////////////////////////////////
  1656. STDMETHODIMP CFileOpenBrowser::ContextSensitiveHelp(
  1657. BOOL fEnable)
  1658. {
  1659. //
  1660. // Shouldn't need in a common dialog.
  1661. //
  1662. return S_OK;
  1663. }
  1664. ////////////////////////////////////////////////////////////////////////////
  1665. //
  1666. // CFileOpenBrowser::SetStatusTextSB
  1667. //
  1668. ////////////////////////////////////////////////////////////////////////////
  1669. STDMETHODIMP CFileOpenBrowser::SetStatusTextSB(
  1670. LPCOLESTR pwch)
  1671. {
  1672. //
  1673. // We don't have any status bar.
  1674. //
  1675. return S_OK;
  1676. }
  1677. ////////////////////////////////////////////////////////////////////////////
  1678. //
  1679. // GetFocusedChild
  1680. //
  1681. ////////////////////////////////////////////////////////////////////////////
  1682. HWND GetFocusedChild(
  1683. HWND hwndDlg,
  1684. HWND hwndFocus)
  1685. {
  1686. HWND hwndParent;
  1687. if (!hwndDlg)
  1688. {
  1689. return (NULL);
  1690. }
  1691. if (!hwndFocus)
  1692. {
  1693. hwndFocus = ::GetFocus();
  1694. }
  1695. //
  1696. // Go up the parent chain until the parent is the main dialog.
  1697. //
  1698. while ((hwndParent = ::GetParent(hwndFocus)) != hwndDlg)
  1699. {
  1700. if (!hwndParent)
  1701. {
  1702. return (NULL);
  1703. }
  1704. hwndFocus = hwndParent;
  1705. }
  1706. return (hwndFocus);
  1707. }
  1708. ////////////////////////////////////////////////////////////////////////////
  1709. //
  1710. // CFileOpenBrowser::EnableModelessSB
  1711. //
  1712. ////////////////////////////////////////////////////////////////////////////
  1713. typedef struct
  1714. {
  1715. UINT idExcept;
  1716. BOOL fEnable;
  1717. } ENABLEKIDS;
  1718. #define PROP_WASDISABLED TEXT("Comdlg32_WasDisabled")
  1719. BOOL CALLBACK _EnableKidsEnum(HWND hwnd, LPARAM lp)
  1720. {
  1721. ENABLEKIDS *pek = (ENABLEKIDS *)lp;
  1722. if (pek->idExcept != GetDlgCtrlID(hwnd))
  1723. {
  1724. if (pek->fEnable)
  1725. {
  1726. // When re-enabling, don't re-enable windows that were
  1727. // previously disabled
  1728. if (!RemoveProp(hwnd, PROP_WASDISABLED))
  1729. {
  1730. EnableWindow(hwnd, TRUE);
  1731. }
  1732. }
  1733. else
  1734. {
  1735. // When disabling, remember whether the window was already
  1736. // disabled so we don't accidentally re-enable it
  1737. if (EnableWindow(hwnd, pek->fEnable))
  1738. {
  1739. SetProp(hwnd, PROP_WASDISABLED, IntToPtr(TRUE));
  1740. }
  1741. }
  1742. }
  1743. return TRUE;
  1744. }
  1745. void EnableChildrenWithException(HWND hwndDlg, UINT idExcept, BOOL fEnable)
  1746. {
  1747. ENABLEKIDS ek = {idExcept, fEnable};
  1748. ::EnumChildWindows(hwndDlg, _EnableKidsEnum, (LPARAM)&ek);
  1749. }
  1750. STDMETHODIMP CFileOpenBrowser::EnableModelessSB(BOOL fEnable)
  1751. {
  1752. LONG cBefore = _cRefCannotNavigate;
  1753. if (fEnable)
  1754. {
  1755. _cRefCannotNavigate--;
  1756. }
  1757. else
  1758. {
  1759. _cRefCannotNavigate++;
  1760. }
  1761. ASSERT(_cRefCannotNavigate >= 0);
  1762. if (!cBefore || !_cRefCannotNavigate)
  1763. {
  1764. // we changed state
  1765. if (!fEnable)
  1766. _hwndModelessFocus = GetFocusedChild(_hwndDlg, NULL);
  1767. EnableChildrenWithException(_hwndDlg, IDCANCEL, fEnable);
  1768. if (fEnable && _hwndModelessFocus)
  1769. SetFocus(_hwndModelessFocus);
  1770. }
  1771. return S_OK;
  1772. }
  1773. ////////////////////////////////////////////////////////////////////////////
  1774. //
  1775. // CFileOpenBrowser::TranslateAcceleratorSB
  1776. //
  1777. ////////////////////////////////////////////////////////////////////////////
  1778. STDMETHODIMP CFileOpenBrowser::TranslateAcceleratorSB(
  1779. LPMSG pmsg,
  1780. WORD wID)
  1781. {
  1782. //
  1783. // We don't use the Key Stroke.
  1784. //
  1785. return S_FALSE;
  1786. }
  1787. ////////////////////////////////////////////////////////////////////////////
  1788. //
  1789. // CFileOpenBrowser::BrowseObject
  1790. //
  1791. ////////////////////////////////////////////////////////////////////////////
  1792. STDMETHODIMP CFileOpenBrowser::BrowseObject(
  1793. LPCITEMIDLIST pidl,
  1794. UINT wFlags)
  1795. {
  1796. return JumpToIDList(pidl);
  1797. }
  1798. BOOL _IsRecentFolder(LPCITEMIDLIST pidl)
  1799. {
  1800. ASSERT(pidl);
  1801. BOOL fRet = FALSE;
  1802. LPITEMIDLIST pidlRecent = SHCloneSpecialIDList(NULL, CSIDL_RECENT, TRUE);
  1803. if (pidlRecent)
  1804. {
  1805. fRet = ILIsEqual(pidlRecent, pidl);
  1806. ILFree(pidlRecent);
  1807. }
  1808. return fRet;
  1809. }
  1810. // My Pictures or My Videos
  1811. BOOL CFileOpenBrowser::_IsThumbnailFolder(LPCITEMIDLIST pidl)
  1812. {
  1813. BOOL fThumbnailFolder = FALSE;
  1814. WCHAR szPath[MAX_PATH + 1];
  1815. if (SHGetPathFromIDList(pidl, szPath))
  1816. {
  1817. fThumbnailFolder = PathIsEqualOrSubFolder(MAKEINTRESOURCE(CSIDL_MYPICTURES), szPath) ||
  1818. PathIsEqualOrSubFolder(MAKEINTRESOURCE(CSIDL_MYVIDEO), szPath);
  1819. }
  1820. return fThumbnailFolder;
  1821. }
  1822. static const GUID CLSID_WIA_FOLDER1 =
  1823. { 0xe211b736, 0x43fd, 0x11d1, { 0x9e, 0xfb, 0x00, 0x00, 0xf8, 0x75, 0x7f, 0xcd} };
  1824. static const GUID CLSID_WIA_FOLDER2 =
  1825. { 0xFB0C9C8A, 0x6C50, 0x11D1, { 0x9F, 0x1D, 0x00, 0x00, 0xf8, 0x75, 0x7f, 0xcd} };
  1826. LOCTYPE CFileOpenBrowser::_GetLocationType(MYLISTBOXITEM *pLocation)
  1827. {
  1828. if (_IsRecentFolder(pLocation->pidlFull))
  1829. return LOCTYPE_RECENT_FOLDER;
  1830. if (_IsThumbnailFolder(pLocation->pidlFull))
  1831. return LOCTYPE_MYPICTURES_FOLDER;
  1832. IShellFolder *psf = pLocation->GetShellFolder(); // Note: this is a MYLISTBOXITEM member variable, don't need to Release()
  1833. if (_IsWIAFolder(psf))
  1834. {
  1835. return LOCTYPE_WIA_FOLDER;
  1836. }
  1837. return LOCTYPE_OTHERS;
  1838. }
  1839. // Is it a windows image acquisition folder?
  1840. BOOL CFileOpenBrowser::_IsWIAFolder(IShellFolder *psf)
  1841. {
  1842. CLSID clsid;
  1843. return (psf &&
  1844. SUCCEEDED(IUnknown_GetClassID(psf, &clsid)) &&
  1845. (IsEqualGUID(clsid, CLSID_WIA_FOLDER1) || IsEqualGUID(clsid, CLSID_WIA_FOLDER2)));
  1846. }
  1847. ////////////////////////////////////////////////////////////////////////////
  1848. //
  1849. // CFileOpenBrowser::GetViewStateStream
  1850. //
  1851. ////////////////////////////////////////////////////////////////////////////
  1852. STDMETHODIMP CFileOpenBrowser::GetViewStateStream(
  1853. DWORD grfMode,
  1854. LPSTREAM *pStrm)
  1855. {
  1856. //
  1857. // FEATURE: We should implement this so there is some persistence
  1858. // for the file open dailog.
  1859. //
  1860. ASSERT(_pCurrentLocation);
  1861. ASSERT(pStrm);
  1862. *pStrm = NULL;
  1863. if ((grfMode == STGM_READ) && _IsRecentFolder(_pCurrentLocation->pidlFull))
  1864. {
  1865. // we want to open the stream from the registry...
  1866. *pStrm = SHOpenRegStream(HKEY_LOCAL_MACHINE, TEXT("Software\\microsoft\\windows\\currentversion\\explorer\\recentdocs"),
  1867. TEXT("ViewStream"), grfMode);
  1868. }
  1869. return (*pStrm ? S_OK : E_FAIL);
  1870. }
  1871. ////////////////////////////////////////////////////////////////////////////
  1872. //
  1873. // CFileOpenBrowser::GetControlWindow
  1874. //
  1875. // Get the handles of the various windows in the File Cabinet.
  1876. //
  1877. ////////////////////////////////////////////////////////////////////////////
  1878. STDMETHODIMP CFileOpenBrowser::GetControlWindow(
  1879. UINT id,
  1880. HWND *lphwnd)
  1881. {
  1882. if (id == FCW_TOOLBAR)
  1883. {
  1884. *lphwnd = _hwndToolbar;
  1885. return S_OK;
  1886. }
  1887. return (E_NOTIMPL);
  1888. }
  1889. ////////////////////////////////////////////////////////////////////////////
  1890. //
  1891. // CFileOpenBrowser::SendControlMsg
  1892. //
  1893. ////////////////////////////////////////////////////////////////////////////
  1894. STDMETHODIMP CFileOpenBrowser::SendControlMsg(
  1895. UINT id,
  1896. UINT uMsg,
  1897. WPARAM wParam,
  1898. LPARAM lParam,
  1899. LRESULT *pret)
  1900. {
  1901. LRESULT lres = 0;
  1902. if (id == FCW_TOOLBAR)
  1903. {
  1904. //
  1905. // We need to translate messages from defview intended for these
  1906. // buttons to our own.
  1907. //
  1908. switch (uMsg)
  1909. {
  1910. case (TB_CHECKBUTTON) :
  1911. {
  1912. #if 0 // we don't do this anymore because we use the viewmenu dropdown
  1913. switch (wParam)
  1914. {
  1915. case (SFVIDM_VIEW_DETAILS) :
  1916. {
  1917. wParam = IDC_VIEWDETAILS;
  1918. break;
  1919. }
  1920. case (SFVIDM_VIEW_LIST) :
  1921. {
  1922. wParam = IDC_VIEWLIST;
  1923. break;
  1924. }
  1925. default :
  1926. {
  1927. goto Bail;
  1928. }
  1929. }
  1930. break;
  1931. #endif
  1932. }
  1933. default :
  1934. {
  1935. goto Bail;
  1936. break;
  1937. }
  1938. }
  1939. lres = SendMessage(_hwndToolbar, uMsg, wParam, lParam);
  1940. }
  1941. Bail:
  1942. if (pret)
  1943. {
  1944. *pret = lres;
  1945. }
  1946. return S_OK;
  1947. }
  1948. ////////////////////////////////////////////////////////////////////////////
  1949. //
  1950. // CFileOpenBrowser::QueryActiveShellView
  1951. //
  1952. ////////////////////////////////////////////////////////////////////////////
  1953. STDMETHODIMP CFileOpenBrowser::QueryActiveShellView(
  1954. LPSHELLVIEW *ppsv)
  1955. {
  1956. if (_psv)
  1957. {
  1958. *ppsv = _psv;
  1959. _psv->AddRef();
  1960. return S_OK;
  1961. }
  1962. *ppsv = NULL;
  1963. return (E_NOINTERFACE);
  1964. }
  1965. ////////////////////////////////////////////////////////////////////////////
  1966. //
  1967. // CFileOpenBrowser::OnViewWindowActive
  1968. //
  1969. ////////////////////////////////////////////////////////////////////////////
  1970. STDMETHODIMP CFileOpenBrowser::OnViewWindowActive(
  1971. LPSHELLVIEW _psv)
  1972. {
  1973. //
  1974. // No need to process this. We don't do menus.
  1975. //
  1976. return S_OK;
  1977. }
  1978. ////////////////////////////////////////////////////////////////////////////
  1979. //
  1980. // CFileOpenBrowser::InsertMenusSB
  1981. //
  1982. ////////////////////////////////////////////////////////////////////////////
  1983. STDMETHODIMP CFileOpenBrowser::InsertMenusSB(
  1984. HMENU hmenuShared,
  1985. LPOLEMENUGROUPWIDTHS lpMenuWidths)
  1986. {
  1987. return (E_NOTIMPL);
  1988. }
  1989. ////////////////////////////////////////////////////////////////////////////
  1990. //
  1991. // CFileOpenBrowser::SetMenuSB
  1992. //
  1993. ////////////////////////////////////////////////////////////////////////////
  1994. STDMETHODIMP CFileOpenBrowser::SetMenuSB(
  1995. HMENU hmenuShared,
  1996. HOLEMENU holemenu,
  1997. HWND hwndActiveObject)
  1998. {
  1999. return (E_NOTIMPL);
  2000. }
  2001. ////////////////////////////////////////////////////////////////////////////
  2002. //
  2003. // CFileOpenBrowser::RemoveMenusSB
  2004. //
  2005. ////////////////////////////////////////////////////////////////////////////
  2006. STDMETHODIMP CFileOpenBrowser::RemoveMenusSB(
  2007. HMENU hmenuShared)
  2008. {
  2009. return (E_NOTIMPL);
  2010. }
  2011. ////////////////////////////////////////////////////////////////////////////
  2012. //
  2013. // CFileOpenBrowser::SetToolbarItems
  2014. //
  2015. ////////////////////////////////////////////////////////////////////////////
  2016. STDMETHODIMP CFileOpenBrowser::SetToolbarItems(
  2017. LPTBBUTTON lpButtons,
  2018. UINT nButtons,
  2019. UINT uFlags)
  2020. {
  2021. //
  2022. // We don't let containers customize our toolbar.
  2023. //
  2024. return S_OK;
  2025. }
  2026. ////////////////////////////////////////////////////////////////////////////
  2027. //
  2028. // CFileOpenBrowser::OnDefaultCommand
  2029. //
  2030. // Process a double-click or Enter keystroke in the view control.
  2031. //
  2032. ////////////////////////////////////////////////////////////////////////////
  2033. STDMETHODIMP CFileOpenBrowser::OnDefaultCommand(
  2034. struct IShellView *ppshv)
  2035. {
  2036. if (ppshv != _psv)
  2037. {
  2038. return (E_INVALIDARG);
  2039. }
  2040. OnDblClick(FALSE);
  2041. return S_OK;
  2042. }
  2043. ///////////////////////////////////
  2044. // *** IServiceProvider methods ***
  2045. ///////////////////////////////////
  2046. HRESULT CFileOpenBrowser::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
  2047. {
  2048. HRESULT hr = E_FAIL;
  2049. *ppvObj = NULL;
  2050. if (IsEqualGUID(guidService, SID_SCommDlgBrowser))
  2051. {
  2052. hr = QueryInterface(riid, ppvObj);
  2053. }
  2054. return hr;
  2055. }
  2056. ////////////////////////////////////////////////////////////////////////////
  2057. //
  2058. // CFileOpenBrowser::SetCurrentFilter
  2059. //
  2060. // note: pszFilter must fit in a buffer of MAXPATH+1
  2061. ////////////////////////////////////////////////////////////////////////////
  2062. void CFileOpenBrowser::SetCurrentFilter(
  2063. LPCTSTR pszFilter,
  2064. OKBUTTONFLAGS Flags)
  2065. {
  2066. LPTSTR lpNext;
  2067. //
  2068. // Don't do anything if it's the same filter.
  2069. //
  2070. if (lstrcmp(_szLastFilter, pszFilter) == 0)
  2071. {
  2072. return;
  2073. }
  2074. EVAL(SUCCEEDED(StringCchCopy(_szLastFilter, ARRAYSIZE(_szLastFilter), pszFilter))); // The filter should always fit in _szLastFilter
  2075. int nLeft = ARRAYSIZE(_szLastFilter) - lstrlen(_szLastFilter) - 1;
  2076. //
  2077. // Do nothing if quoted.
  2078. //
  2079. if (Flags & OKBUTTON_QUOTED)
  2080. {
  2081. return;
  2082. }
  2083. //
  2084. // If pszFilter matches a filter spec, select that spec.
  2085. //
  2086. HWND hCmb = GetDlgItem(_hwndDlg, cmb1);
  2087. if (hCmb)
  2088. {
  2089. int nMax = ComboBox_GetCount(hCmb);
  2090. int n;
  2091. BOOL bCustomFilter = _pOFN->lpstrCustomFilter && *_pOFN->lpstrCustomFilter;
  2092. for (n = 0; n < nMax; n++)
  2093. {
  2094. LPTSTR pFilter = (LPTSTR)ComboBox_GetItemData(hCmb, n);
  2095. if (pFilter && pFilter != (LPTSTR)CB_ERR)
  2096. {
  2097. if (!lstrcmpi(pFilter, pszFilter))
  2098. {
  2099. if (n != ComboBox_GetCurSel(hCmb))
  2100. {
  2101. ComboBox_SetCurSel(hCmb, n);
  2102. }
  2103. break;
  2104. }
  2105. }
  2106. }
  2107. }
  2108. //
  2109. // For LFNs, tack on a '*' after non-wild extensions.
  2110. //
  2111. for (lpNext = _szLastFilter; nLeft > 0;)
  2112. {
  2113. // Turning any kind of ';' separated list into a NULL-char separated list.
  2114. LPTSTR lpSemiColon = StrChr(lpNext, CHAR_SEMICOLON);
  2115. if (!lpSemiColon)
  2116. {
  2117. lpSemiColon = lpNext + lstrlen(lpNext);
  2118. }
  2119. TCHAR cTemp = *lpSemiColon;
  2120. *lpSemiColon = CHAR_NULL;
  2121. LPTSTR lpDot = StrChr(lpNext, CHAR_DOT);
  2122. //
  2123. // See if there is an extension that is not wild.
  2124. //
  2125. if (lpDot && *(lpDot + 1) && !IsWild(lpDot))
  2126. {
  2127. //
  2128. // Tack on a star.
  2129. // We know there is still enough room because nLeft > 0.
  2130. //
  2131. if (cTemp != CHAR_NULL)
  2132. {
  2133. MoveMemory(lpSemiColon + 2,
  2134. lpSemiColon + 1,
  2135. (lstrlen(lpSemiColon + 1) + 1) * sizeof(TCHAR)); // plus 1 for terminating NULL
  2136. }
  2137. *lpSemiColon = CHAR_STAR;
  2138. ++lpSemiColon;
  2139. --nLeft;
  2140. }
  2141. *lpSemiColon = cTemp;
  2142. if (cTemp == CHAR_NULL)
  2143. {
  2144. break;
  2145. }
  2146. else
  2147. {
  2148. lpNext = lpSemiColon + 1;
  2149. }
  2150. }
  2151. }
  2152. ////////////////////////////////////////////////////////////////////////////
  2153. //
  2154. // CFileOpenBrowser::SwitchView
  2155. //
  2156. // Switch the view control to a new container.
  2157. //
  2158. ////////////////////////////////////////////////////////////////////////////
  2159. HRESULT CFileOpenBrowser::SwitchView(
  2160. IShellFolder *psfNew,
  2161. LPCITEMIDLIST pidlNew,
  2162. FOLDERSETTINGS *pfs,
  2163. SHELLVIEWID const *pvid,
  2164. BOOL fUseDefaultView)
  2165. {
  2166. IShellView *psvNew;
  2167. IShellView2 *psv2New;
  2168. RECT rc;
  2169. if (!psfNew)
  2170. {
  2171. return (E_INVALIDARG);
  2172. }
  2173. GetControlRect(_hwndDlg, lst1, &rc);
  2174. if (_bEnableSizing)
  2175. {
  2176. if (_hwndView)
  2177. {
  2178. //
  2179. // Don't directly use the rect but instead use the size as
  2180. // applications like VB may move the window off the screen.
  2181. //
  2182. RECT rcView;
  2183. GetWindowRect(_hwndView, &rcView);
  2184. _sizeView.cx = rcView.right - rcView.left;
  2185. _sizeView.cy = rcView.bottom - rcView.top;
  2186. rc.right = rc.left + _sizeView.cx;
  2187. rc.bottom = rc.top + _sizeView.cy;
  2188. }
  2189. else if (_bUseSizeView && _sizeView.cx)
  2190. {
  2191. //
  2192. // If we previously failed then use cached size.
  2193. //
  2194. rc.right = rc.left + _sizeView.cx;
  2195. rc.bottom = rc.top + _sizeView.cy;
  2196. }
  2197. }
  2198. HRESULT hres = psfNew->CreateViewObject(_hwndDlg, IID_PPV_ARG(IShellView, &psvNew));
  2199. if (FAILED(hres))
  2200. {
  2201. return hres;
  2202. }
  2203. IShellView *psvOld;
  2204. HWND hwndNew;
  2205. WAIT_CURSOR w(this);
  2206. //
  2207. // The view window itself won't take the focus. But we can set
  2208. // focus there and see if it bounces to the same place it is
  2209. // currently. If that's the case, we want the new view window
  2210. // to get the focus; otherwise, we put it back where it was.
  2211. //
  2212. BOOL bViewFocus = (GetFocusedChild(_hwndDlg, NULL) == _hwndView);
  2213. psvOld = _psv;
  2214. //
  2215. // We attempt to blow off drawing on the main dialog. Note that
  2216. // we should leave in SETREDRAW stuff to minimize flicker in case
  2217. // this fails.
  2218. //
  2219. BOOL bLocked = LockWindowUpdate(_hwndDlg);
  2220. //
  2221. // We need to kill the current _psv before creating the new one in case
  2222. // the current one has a background thread going that is trying to
  2223. // call us back (IncludeObject).
  2224. //
  2225. if (psvOld)
  2226. {
  2227. SendMessage(_hwndView, WM_SETREDRAW, FALSE, 0);
  2228. psvOld->DestroyViewWindow();
  2229. _hwndView = NULL;
  2230. _psv = NULL;
  2231. //
  2232. // Don't release yet. We will pass this to CreateViewWindow().
  2233. //
  2234. }
  2235. //
  2236. // At this point, there should be no background processing happening.
  2237. //
  2238. _psfCurrent = psfNew;
  2239. SHGetPathFromIDList(pidlNew, _szCurDir);
  2240. //
  2241. // New windows (like the view window about to be created) show up at
  2242. // the bottom of the Z order, so I need to disable drawing of the
  2243. // subdialog while creating the view window; drawing will be enabled
  2244. // after the Z-order has been set properly.
  2245. //
  2246. if (_hSubDlg)
  2247. {
  2248. SendMessage(_hSubDlg, WM_SETREDRAW, FALSE, 0);
  2249. }
  2250. //
  2251. // _psv must be set before creating the view window since we
  2252. // validate it on the IncludeObject callback.
  2253. //
  2254. _psv = psvNew;
  2255. if ((pvid || fUseDefaultView) && SUCCEEDED(psvNew->QueryInterface(IID_PPV_ARG(IShellView2, &psv2New))))
  2256. {
  2257. SV2CVW2_PARAMS cParams;
  2258. SHELLVIEWID vidCurrent = {0};
  2259. cParams.cbSize = SIZEOF(SV2CVW2_PARAMS);
  2260. cParams.psvPrev = psvOld;
  2261. cParams.pfs = pfs;
  2262. cParams.psbOwner = this;
  2263. cParams.prcView = &rc;
  2264. if (pvid)
  2265. cParams.pvid = pvid; // View id; for example, &CLSID_ThumbnailViewExt;
  2266. else
  2267. {
  2268. psv2New->GetView(&vidCurrent, SV2GV_DEFAULTVIEW);
  2269. // We don't want filmstrip view in fileopen, so we'll switch that to thumbnail.
  2270. if (IsEqualIID(VID_ThumbStrip, vidCurrent))
  2271. cParams.pvid = &VID_Thumbnails;
  2272. else
  2273. cParams.pvid = &vidCurrent;
  2274. }
  2275. hres = psv2New->CreateViewWindow2(&cParams);
  2276. hwndNew = cParams.hwndView;
  2277. psv2New->Release();
  2278. }
  2279. else
  2280. hres = _psv->CreateViewWindow(psvOld, pfs, this, &rc, &hwndNew);
  2281. _bUseSizeView = FAILED(hres);
  2282. if (SUCCEEDED(hres))
  2283. {
  2284. hres = psvNew->UIActivate(SVUIA_INPLACEACTIVATE);
  2285. }
  2286. if (psvOld)
  2287. {
  2288. psvOld->Release();
  2289. }
  2290. if (_hSubDlg)
  2291. {
  2292. //
  2293. // Turn REDRAW back on before changing the focus in case the
  2294. // SubDlg has the focus.
  2295. //
  2296. SendMessage(_hSubDlg, WM_SETREDRAW, TRUE, 0);
  2297. }
  2298. if (SUCCEEDED(hres))
  2299. {
  2300. DWORD dwAttr = SFGAO_STORAGE | SFGAO_READONLY;
  2301. SHGetAttributesOf(pidlNew, &dwAttr);
  2302. BOOL bNewFolder = (dwAttr & SFGAO_STORAGE) && !(dwAttr & SFGAO_READONLY);
  2303. ::SendMessage(_hwndToolbar, TB_ENABLEBUTTON, IDC_NEWFOLDER, bNewFolder);
  2304. _hwndView = hwndNew;
  2305. //
  2306. // Move the view window to the right spot in the Z (tab) order.
  2307. //
  2308. SetWindowPos(hwndNew,
  2309. GetDlgItem(_hwndDlg, lst1),
  2310. 0,
  2311. 0,
  2312. 0,
  2313. 0,
  2314. SWP_NOMOVE | SWP_NOSIZE);
  2315. //
  2316. // Give it the right window ID for WinHelp.
  2317. //
  2318. SetWindowLong(hwndNew, GWL_ID, lst2);
  2319. ::RedrawWindow(_hwndView,
  2320. NULL,
  2321. NULL,
  2322. RDW_INVALIDATE | RDW_ERASE |
  2323. RDW_ALLCHILDREN | RDW_UPDATENOW);
  2324. if (bViewFocus)
  2325. {
  2326. ::SetFocus(_hwndView);
  2327. }
  2328. }
  2329. else
  2330. {
  2331. _psv = NULL;
  2332. psvNew->Release();
  2333. }
  2334. //
  2335. // Let's draw again!
  2336. //
  2337. if (bLocked)
  2338. {
  2339. LockWindowUpdate(NULL);
  2340. }
  2341. return hres;
  2342. }
  2343. void CFileOpenBrowser::_WaitCursor(BOOL fWait)
  2344. {
  2345. if (fWait)
  2346. _cWaitCursor++;
  2347. else
  2348. _cWaitCursor--;
  2349. SetCursor(LoadCursor(NULL, _cWaitCursor ? IDC_WAIT : IDC_ARROW));
  2350. }
  2351. BOOL CFileOpenBrowser::OnSetCursor()
  2352. {
  2353. if (_cWaitCursor)
  2354. {
  2355. SetCursor(LoadCursor(NULL, IDC_WAIT));
  2356. return TRUE;
  2357. }
  2358. return FALSE;
  2359. }
  2360. ////////////////////////////////////////////////////////////////////////////
  2361. //
  2362. // JustGetToolTipText
  2363. //
  2364. ////////////////////////////////////////////////////////////////////////////
  2365. void JustGetToolTipText(
  2366. UINT idCommand,
  2367. LPTOOLTIPTEXT pTtt)
  2368. {
  2369. if (!CDLoadString(::g_hinst,
  2370. idCommand + MH_TOOLTIPBASE,
  2371. pTtt->szText,
  2372. ARRAYSIZE(pTtt->szText)))
  2373. {
  2374. *pTtt->lpszText = 0;
  2375. }
  2376. }
  2377. ////////////////////////////////////////////////////////////////////////////
  2378. //
  2379. // CFileOpenBrowser::OnNotify
  2380. //
  2381. // Process notify messages from the view -- for tooltips.
  2382. //
  2383. ////////////////////////////////////////////////////////////////////////////
  2384. LRESULT CFileOpenBrowser::OnNotify(
  2385. LPNMHDR pnm)
  2386. {
  2387. LRESULT lres = 0;
  2388. switch (pnm->code)
  2389. {
  2390. case (TTN_NEEDTEXT) :
  2391. {
  2392. HWND hCtrl = GetDlgItem(_hwndDlg, cmb2);
  2393. LPTOOLTIPTEXT lptt = (LPTOOLTIPTEXT)pnm;
  2394. int iTemp;
  2395. //
  2396. // If this is the combo control which shows the current drive,
  2397. // then convert this into a suitable tool-tip message giving
  2398. // the 'full' path to this object.
  2399. //
  2400. if (pnm->idFrom == (UINT_PTR)hCtrl)
  2401. {
  2402. //
  2403. // iTemp will contain index of first path element.
  2404. //
  2405. GetDirectoryFromLB(_szTipBuf, &iTemp);
  2406. lptt->lpszText = _szTipBuf;
  2407. lptt->szText[0] = CHAR_NULL;
  2408. lptt->hinst = NULL; // no instance needed
  2409. }
  2410. else if (IsInRange(pnm->idFrom, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST))
  2411. {
  2412. if (_hwndView)
  2413. {
  2414. lres = ::SendMessage(_hwndView, WM_NOTIFY, 0, (LPARAM)pnm);
  2415. }
  2416. }
  2417. else if (IsInRange(pnm->idFrom, IDC_PLACESBAR_BASE, IDC_PLACESBAR_BASE + _iCommandID))
  2418. {
  2419. _GetPlacesBarItemToolTip((int)pnm->idFrom, _szTipBuf, ARRAYSIZE(_szTipBuf));
  2420. lptt->lpszText = _szTipBuf;
  2421. }
  2422. else
  2423. {
  2424. JustGetToolTipText((UINT) pnm->idFrom, lptt);
  2425. }
  2426. lres = TRUE;
  2427. break;
  2428. }
  2429. case (NM_STARTWAIT) :
  2430. case (NM_ENDWAIT) :
  2431. {
  2432. //
  2433. // What we really want is for the user to simulate a mouse
  2434. // move/setcursor.
  2435. //
  2436. _WaitCursor(pnm->code == NM_STARTWAIT);
  2437. break;
  2438. }
  2439. case (TBN_DROPDOWN) :
  2440. {
  2441. RECT r;
  2442. VARIANT v = {VT_INT_PTR};
  2443. TBNOTIFY *ptbn = (TBNOTIFY*)pnm;
  2444. DFVCMDDATA cd;
  2445. // v.vt = VT_I4;
  2446. v.byref = &r;
  2447. SendMessage(_hwndToolbar, TB_GETRECT, ptbn->iItem, (LPARAM)&r);
  2448. MapWindowRect(_hwndToolbar, HWND_DESKTOP, &r);
  2449. cd.pva = &v;
  2450. cd.hwnd = _hwndToolbar;
  2451. cd.nCmdIDTranslated = 0;
  2452. SendMessage(_hwndView, WM_COMMAND, SFVIDM_VIEW_VIEWMENU, (LONG_PTR)&cd);
  2453. break;
  2454. }
  2455. case (NM_CUSTOMDRAW) :
  2456. if (!IsAppThemed())
  2457. {
  2458. LPNMTBCUSTOMDRAW lpcust = (LPNMTBCUSTOMDRAW)pnm;
  2459. //Make sure its from places bar
  2460. if (lpcust->nmcd.hdr.hwndFrom == _hwndPlacesbar)
  2461. {
  2462. switch (lpcust->nmcd.dwDrawStage)
  2463. {
  2464. case (CDDS_PREERASE) :
  2465. {
  2466. HDC hdc = (HDC)lpcust->nmcd.hdc;
  2467. RECT rc;
  2468. GetClientRect(_hwndPlacesbar, &rc);
  2469. SHFillRectClr(hdc, &rc, GetSysColor(COLOR_BTNSHADOW));
  2470. lres = CDRF_SKIPDEFAULT;
  2471. SetDlgMsgResult(_hwndDlg, WM_NOTIFY, lres);
  2472. break;
  2473. }
  2474. case (CDDS_PREPAINT) :
  2475. {
  2476. lres = CDRF_NOTIFYITEMDRAW;
  2477. SetDlgMsgResult(_hwndDlg, WM_NOTIFY, lres);
  2478. break;
  2479. }
  2480. case (CDDS_ITEMPREPAINT) :
  2481. {
  2482. //Set the text color to window
  2483. lpcust->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  2484. lpcust->clrBtnFace = GetSysColor(COLOR_BTNSHADOW);
  2485. lpcust->nStringBkMode = TRANSPARENT;
  2486. lres = CDRF_DODEFAULT;
  2487. if (lpcust->nmcd.uItemState & CDIS_CHECKED)
  2488. {
  2489. lpcust->hbrMonoDither = NULL;
  2490. }
  2491. SetDlgMsgResult(_hwndDlg, WM_NOTIFY, lres);
  2492. break;
  2493. }
  2494. }
  2495. }
  2496. }
  2497. }
  2498. return (lres);
  2499. }
  2500. // Get the display name of a shell object.
  2501. void GetViewItemText(IShellFolder *psf, LPCITEMIDLIST pidl, LPTSTR pBuf, UINT cchBuf, DWORD flags = SHGDN_INFOLDER | SHGDN_FORPARSING)
  2502. {
  2503. DisplayNameOf(psf, pidl, flags, pBuf, cchBuf);
  2504. }
  2505. ////////////////////////////////////////////////////////////////////////////
  2506. //
  2507. // GetListboxItem
  2508. //
  2509. // Get a MYLISTBOXITEM object out of the location dropdown.
  2510. //
  2511. ////////////////////////////////////////////////////////////////////////////
  2512. MYLISTBOXITEM *GetListboxItem(
  2513. HWND hCtrl,
  2514. WPARAM iItem)
  2515. {
  2516. MYLISTBOXITEM *p = (MYLISTBOXITEM *)SendMessage(hCtrl,
  2517. CB_GETITEMDATA,
  2518. iItem,
  2519. NULL);
  2520. if (p == (MYLISTBOXITEM *)CB_ERR)
  2521. {
  2522. return NULL;
  2523. }
  2524. else
  2525. {
  2526. return p;
  2527. }
  2528. }
  2529. ////////////////////////////////////////////////////////////////////////////
  2530. //
  2531. // _ReleaseStgMedium
  2532. //
  2533. ////////////////////////////////////////////////////////////////////////////
  2534. HRESULT _ReleaseStgMedium(
  2535. LPSTGMEDIUM pmedium)
  2536. {
  2537. if (pmedium->pUnkForRelease)
  2538. {
  2539. pmedium->pUnkForRelease->Release();
  2540. }
  2541. else
  2542. {
  2543. switch (pmedium->tymed)
  2544. {
  2545. case (TYMED_HGLOBAL) :
  2546. {
  2547. GlobalFree(pmedium->hGlobal);
  2548. break;
  2549. }
  2550. default :
  2551. {
  2552. //
  2553. // Not fully implemented.
  2554. //
  2555. MessageBeep(0);
  2556. break;
  2557. }
  2558. }
  2559. }
  2560. return S_OK;
  2561. }
  2562. ////////////////////////////////////////////////////////////////////////////
  2563. //
  2564. // CFileOpenBrowser::SetSaveButton
  2565. //
  2566. ////////////////////////////////////////////////////////////////////////////
  2567. void CFileOpenBrowser::SetSaveButton(
  2568. UINT idSaveButton)
  2569. {
  2570. PostMessage(_hwndDlg, CDM_SETSAVEBUTTON, idSaveButton, 0);
  2571. }
  2572. ////////////////////////////////////////////////////////////////////////////
  2573. //
  2574. // CFileOpenBrowser::RealSetSaveButton
  2575. //
  2576. ////////////////////////////////////////////////////////////////////////////
  2577. void CFileOpenBrowser::RealSetSaveButton(
  2578. UINT idSaveButton)
  2579. {
  2580. MSG msg;
  2581. if (PeekMessage(&msg,
  2582. _hwndDlg,
  2583. CDM_SETSAVEBUTTON,
  2584. CDM_SETSAVEBUTTON,
  2585. PM_NOREMOVE))
  2586. {
  2587. //
  2588. // There is another SETSAVEBUTTON message in the queue, so blow off
  2589. // this one.
  2590. //
  2591. return;
  2592. }
  2593. if (_bSave)
  2594. {
  2595. TCHAR szTemp[40];
  2596. LPTSTR pszTemp = _tszDefSave;
  2597. //
  2598. // Load the string if not the "Save" string or there is no
  2599. // app-specified default.
  2600. //
  2601. if ((idSaveButton != iszFileSaveButton) || !pszTemp)
  2602. {
  2603. CDLoadString(g_hinst, idSaveButton, szTemp, ARRAYSIZE(szTemp));
  2604. pszTemp = szTemp;
  2605. }
  2606. GetDlgItemText(_hwndDlg, IDOK, _szBuf, ARRAYSIZE(_szBuf));
  2607. if (lstrcmp(_szBuf, pszTemp))
  2608. {
  2609. //
  2610. // Avoid some flicker.
  2611. //
  2612. SetDlgItemText(_hwndDlg, IDOK, pszTemp);
  2613. }
  2614. }
  2615. }
  2616. ////////////////////////////////////////////////////////////////////////////
  2617. //
  2618. // CFileOpenBrowser::SetEditFile
  2619. //
  2620. ////////////////////////////////////////////////////////////////////////////
  2621. void CFileOpenBrowser::SetEditFile(
  2622. LPCTSTR pszFile,
  2623. LPCTSTR pszFriendlyName,
  2624. BOOL bShowExt,
  2625. BOOL bSaveNullExt)
  2626. {
  2627. BOOL bHasHiddenExt = FALSE;
  2628. //
  2629. // Save the whole file name.
  2630. //
  2631. if (!_pszHideExt.TSStrCpy(pszFile))
  2632. {
  2633. _pszHideExt.TSStrCpy(NULL);
  2634. bShowExt = TRUE;
  2635. }
  2636. //
  2637. // FEATURE: This is bogus -- we only want to hide KNOWN extensions,
  2638. // not all extensions.
  2639. //
  2640. if (!bShowExt && !IsWild(pszFile) && !pszFriendlyName)
  2641. {
  2642. LPTSTR pszExt = PathFindExtension(pszFile);
  2643. if (*pszExt)
  2644. {
  2645. //
  2646. // If there was an extension, hide it.
  2647. //
  2648. *pszExt = 0;
  2649. bHasHiddenExt = TRUE;
  2650. }
  2651. }
  2652. else if (pszFriendlyName)
  2653. {
  2654. // A friendly name was provided. Use it.
  2655. pszFile = pszFriendlyName;
  2656. // Not technically true, but this bit indicates that an app sends a CDM_GETSPEC, we give the for-parsing
  2657. // value in _pszHideExt, not the "friendly name" in the edit box
  2658. bHasHiddenExt = TRUE;
  2659. }
  2660. if (_bUseCombo)
  2661. {
  2662. HWND hwndEdit = (HWND)SendMessage(GetDlgItem(_hwndDlg, cmb13), CBEM_GETEDITCONTROL, 0, 0L);
  2663. SetWindowText(hwndEdit, pszFile);
  2664. }
  2665. else
  2666. {
  2667. SetDlgItemText(_hwndDlg, edt1, pszFile);
  2668. }
  2669. //
  2670. // If the initial file name has no extension, we want to do our normal
  2671. // extension finding stuff. Any other time we get a file with no
  2672. // extension, we should not do this.
  2673. //
  2674. _bUseHideExt = (LPTSTR)_pszHideExt
  2675. ? (bSaveNullExt ? TRUE : bHasHiddenExt)
  2676. : FALSE;
  2677. }
  2678. ////////////////////////////////////////////////////////////////////////////
  2679. //
  2680. // FindEOF
  2681. //
  2682. ////////////////////////////////////////////////////////////////////////////
  2683. LPWSTR FindEOF(
  2684. LPWSTR pszFiles)
  2685. {
  2686. BOOL bQuoted;
  2687. LPWSTR pszCurrent = pszFiles;
  2688. while (*pszCurrent == CHAR_SPACE)
  2689. {
  2690. ++pszCurrent;
  2691. }
  2692. //
  2693. // Note that we always assume a quoted string, even if no quotes exist,
  2694. // so the only file delimiters are '"' and '\0'. This allows somebody to
  2695. // type <Start Menu> or <My Document> in the edit control and the right
  2696. // thing happens.
  2697. //
  2698. bQuoted = TRUE;
  2699. if (*pszCurrent == CHAR_QUOTE)
  2700. {
  2701. ++pszCurrent;
  2702. }
  2703. //Remove the quote from the file list if one exist
  2704. StringCopyOverlap(pszFiles, pszCurrent);
  2705. //
  2706. // Find the end of the filename (first quote or unquoted space).
  2707. //
  2708. for (; ; pszFiles = CharNext(pszFiles))
  2709. {
  2710. switch (*pszFiles)
  2711. {
  2712. case (CHAR_NULL) :
  2713. {
  2714. return (pszFiles);
  2715. }
  2716. case (CHAR_SPACE) :
  2717. {
  2718. if (!bQuoted)
  2719. {
  2720. return (pszFiles);
  2721. }
  2722. break;
  2723. }
  2724. case (CHAR_QUOTE) :
  2725. {
  2726. //
  2727. // Note we only support '"' at the very beginning and very
  2728. // end of a file name.
  2729. //
  2730. return (pszFiles);
  2731. }
  2732. default :
  2733. {
  2734. break;
  2735. }
  2736. }
  2737. }
  2738. }
  2739. ////////////////////////////////////////////////////////////////////////////
  2740. //
  2741. // ConvertToNULLTerm
  2742. //
  2743. ////////////////////////////////////////////////////////////////////////////
  2744. DWORD ConvertToNULLTerm(
  2745. LPTSTR pchRead)
  2746. {
  2747. DWORD cFiles = 0;
  2748. // The input string is of the form "file1.ext" "file2.ext" ... "filen.ext"
  2749. // convert this string of this form into doubly null terminated string
  2750. // ie file1.ext\0file2.ext\0....filen.ext\0\0
  2751. for (; ;)
  2752. {
  2753. // Finds the end of the first file name in the list of
  2754. // remaining file names. Also this function removes the initial
  2755. // quote character, and any preceding spaces (so it generally shifts a portion
  2756. // of the string to the left by 2 characters)
  2757. LPTSTR pchEnd = FindEOF(pchRead);
  2758. //
  2759. // Mark the end of the filename with a NULL.
  2760. //
  2761. if (*pchEnd)
  2762. {
  2763. *pchEnd = CHAR_NULL;
  2764. cFiles++;
  2765. pchRead = pchEnd + 1;
  2766. }
  2767. else
  2768. {
  2769. //
  2770. // Found EOL. Make sure we did not end with spaces.
  2771. //
  2772. if (*pchRead)
  2773. {
  2774. pchRead = pchEnd + 1;
  2775. cFiles++;
  2776. }
  2777. break;
  2778. }
  2779. }
  2780. //
  2781. // Double-NULL terminate.
  2782. //
  2783. *pchRead = CHAR_NULL;
  2784. return (cFiles);
  2785. }
  2786. ////////////////////////////////////////////////////////////////////////////
  2787. //
  2788. // SelFocusEnumCB
  2789. //
  2790. ////////////////////////////////////////////////////////////////////////////
  2791. typedef struct _SELFOCUS
  2792. {
  2793. BOOL bSelChange;
  2794. UINT idSaveButton;
  2795. int nSel;
  2796. TEMPSTR sHidden;
  2797. TEMPSTR sDisplayed;
  2798. } SELFOCUS;
  2799. BOOL SelFocusEnumCB(
  2800. CFileOpenBrowser *that,
  2801. LPCITEMIDLIST pidl,
  2802. LPARAM lParam)
  2803. {
  2804. if (!pidl)
  2805. {
  2806. return TRUE;
  2807. }
  2808. SELFOCUS *psf = (SELFOCUS *)lParam;
  2809. TCHAR szBuf[MAX_PATH + 1];
  2810. TCHAR szBufFriendly[MAX_PATH + 1];
  2811. DWORD dwAttrs = SHGetAttributes(that->_psfCurrent, pidl, SFGAO_STORAGECAPMASK);
  2812. if (dwAttrs)
  2813. {
  2814. if (_IsOpenContainer(dwAttrs))
  2815. {
  2816. psf->idSaveButton = iszFileOpenButton;
  2817. }
  2818. else
  2819. {
  2820. if (psf->bSelChange && (((that->_pOFN->Flags & OFN_ENABLEINCLUDENOTIFY) &&
  2821. (that->_bSelIsObject =
  2822. CD_SendIncludeItemNotify(that->_hSubDlg,
  2823. that->_hwndDlg,
  2824. that->_psfCurrent,
  2825. pidl,
  2826. that->_pOFN,
  2827. that->_pOFI))) ||
  2828. (_IsStream(dwAttrs))))
  2829. {
  2830. ++psf->nSel;
  2831. if (that->_pOFN->Flags & OFN_ALLOWMULTISELECT)
  2832. {
  2833. //
  2834. // Mark if this is an OBJECT we just selected.
  2835. //
  2836. if (that->_bSelIsObject)
  2837. {
  2838. ITEMIDLIST idl;
  2839. idl.mkid.cb = 0;
  2840. //
  2841. // Get full path to this folder.
  2842. //
  2843. GetViewItemText(that->_psfCurrent, &idl, szBuf, ARRAYSIZE(szBuf), SHGDN_FORPARSING);
  2844. if (szBuf[0])
  2845. {
  2846. that->_pszObjectCurDir.TSStrCpy(szBuf); // Ok if it fails?
  2847. }
  2848. //
  2849. // Get full path to this item (in case we only get one
  2850. // selection).
  2851. //
  2852. GetViewItemText(that->_psfCurrent, pidl, szBuf, ARRAYSIZE(szBuf), SHGDN_FORPARSING);
  2853. that->_pszObjectPath.TSStrCpy(szBuf);
  2854. }
  2855. *szBuf = CHAR_QUOTE;
  2856. GetViewItemText(that->_psfCurrent, pidl, szBuf + 1, ARRAYSIZE(szBuf) - 3);
  2857. EVAL(SUCCEEDED(StringCchCat(szBuf, ARRAYSIZE(szBuf), L"\" "))); // Should always be enough room
  2858. if (!psf->sHidden.TSStrCat(szBuf))
  2859. {
  2860. psf->nSel = -1;
  2861. return FALSE;
  2862. }
  2863. if (!that->_fShowExtensions)
  2864. {
  2865. LPTSTR pszExt = PathFindExtension(szBuf + 1);
  2866. if (*pszExt)
  2867. {
  2868. *pszExt = 0; // Get rid of the file extension.
  2869. EVAL(SUCCEEDED(StringCchCat(szBuf, ARRAYSIZE(szBuf), L"\" "))); // Should always be enough room - see GetViewItemText
  2870. }
  2871. }
  2872. if (!psf->sDisplayed.TSStrCat(szBuf))
  2873. {
  2874. psf->nSel = -1;
  2875. return FALSE;
  2876. }
  2877. }
  2878. else
  2879. {
  2880. SHTCUTINFO info;
  2881. info.dwAttr = SFGAO_FOLDER;
  2882. info.fReSolve = FALSE;
  2883. info.pszLinkFile = NULL;
  2884. info.cchFile = 0;
  2885. info.ppidl = NULL;
  2886. if ((that->GetLinkStatus(pidl, &info)) &&
  2887. (info.dwAttr & SFGAO_FOLDER))
  2888. {
  2889. // This means that the pidl is a link and the link points to a folder
  2890. // in this case We Should not update the edit box and treat the link like
  2891. // a directory
  2892. psf->idSaveButton = iszFileOpenButton;
  2893. }
  2894. else
  2895. {
  2896. TCHAR *pszFriendlyName = NULL;
  2897. GetViewItemText(that->_psfCurrent, pidl, szBuf, ARRAYSIZE(szBuf));
  2898. // Special case WIA folders. They want friendly names. Might want to do this for all
  2899. // folders, but that might cause app compat nightmare.
  2900. if (that->_IsWIAFolder(that->_psfCurrent))
  2901. {
  2902. GetViewItemText(that->_psfCurrent, pidl, szBufFriendly, ARRAYSIZE(szBufFriendly), SHGDN_INFOLDER);
  2903. pszFriendlyName = szBufFriendly;
  2904. }
  2905. else
  2906. {
  2907. IShellFolder *psfItem;
  2908. if (SUCCEEDED(that->_psfCurrent->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfItem))))
  2909. {
  2910. if (that->_IsWIAFolder(psfItem))
  2911. {
  2912. GetViewItemText(that->_psfCurrent, pidl, szBufFriendly, ARRAYSIZE(szBufFriendly), SHGDN_INFOLDER);
  2913. pszFriendlyName = szBufFriendly;
  2914. }
  2915. psfItem->Release();
  2916. }
  2917. }
  2918. that->SetEditFile(szBuf, pszFriendlyName, that->_fShowExtensions);
  2919. if (that->_bSelIsObject)
  2920. {
  2921. GetViewItemText(that->_psfCurrent, pidl, szBuf, ARRAYSIZE(szBuf), SHGDN_FORPARSING);
  2922. that->_pszObjectPath.TSStrCpy(szBuf);
  2923. }
  2924. }
  2925. }
  2926. }
  2927. }
  2928. }
  2929. //if there is an item selected then cache that items pidl
  2930. Pidl_Set(&that->_pidlSelection,pidl);
  2931. return TRUE;
  2932. }
  2933. ////////////////////////////////////////////////////////////////////////////
  2934. //
  2935. // CFileOpenBrowser::SelFocusChange
  2936. //
  2937. ////////////////////////////////////////////////////////////////////////////
  2938. void CFileOpenBrowser::SelFocusChange(
  2939. BOOL bSelChange)
  2940. {
  2941. SELFOCUS sf;
  2942. sf.bSelChange = bSelChange;
  2943. sf.idSaveButton = iszFileSaveButton;
  2944. sf.nSel = 0;
  2945. _bSelIsObject = FALSE;
  2946. EnumItemObjects(SVGIO_SELECTION, SelFocusEnumCB, (LPARAM)&sf);
  2947. if (_pOFN->Flags & OFN_ALLOWMULTISELECT)
  2948. {
  2949. switch (sf.nSel)
  2950. {
  2951. case (-1) :
  2952. {
  2953. //
  2954. // Oops! We ran out of memory.
  2955. //
  2956. MessageBeep(0);
  2957. return;
  2958. }
  2959. case (0) :
  2960. {
  2961. //
  2962. // No files selected; do not change edit control.
  2963. //
  2964. break;
  2965. }
  2966. case (1) :
  2967. {
  2968. //
  2969. // Strip off quotes so the single file case looks OK.
  2970. //
  2971. ConvertToNULLTerm(sf.sHidden);
  2972. LPITEMIDLIST pidlSel = ILClone(_pidlSelection);
  2973. SetEditFile(sf.sHidden, NULL, _fShowExtensions);
  2974. if (pidlSel)
  2975. {
  2976. // The SetEditFile above will nuke any _pidlSelection that was set as a result
  2977. // of EnumItemObjects, by causing a CBN_EDITCHANGE notification (edit box changed, so we
  2978. // think we should nuked the _pidlSelection - doh!).
  2979. // So here we restore it, if there was one set.
  2980. Pidl_Set(&_pidlSelection, pidlSel);
  2981. ILFree(pidlSel);
  2982. }
  2983. sf.idSaveButton = iszFileSaveButton;
  2984. break;
  2985. }
  2986. default :
  2987. {
  2988. SetEditFile(sf.sDisplayed, NULL, TRUE);
  2989. _pszHideExt.TSStrCpy(sf.sHidden);
  2990. sf.idSaveButton = iszFileSaveButton;
  2991. //More than one item selected so free selected item pidl
  2992. Pidl_Set(&_pidlSelection,NULL);;
  2993. break;
  2994. }
  2995. }
  2996. }
  2997. SetSaveButton(sf.idSaveButton);
  2998. }
  2999. ////////////////////////////////////////////////////////////////////////////
  3000. //
  3001. // SelRenameCB
  3002. //
  3003. ////////////////////////////////////////////////////////////////////////////
  3004. BOOL SelRenameCB(
  3005. CFileOpenBrowser *that,
  3006. LPCITEMIDLIST pidl,
  3007. LPARAM lParam)
  3008. {
  3009. if (!pidl)
  3010. {
  3011. return TRUE;
  3012. }
  3013. Pidl_Set(&that->_pidlSelection, pidl);
  3014. if (!SHGetAttributes(that->_psfCurrent, pidl, SFGAO_FOLDER))
  3015. {
  3016. //
  3017. // If it is not a folder then set the selection to nothing
  3018. // so that whatever is in the edit box will be used.
  3019. //
  3020. that->_psv->SelectItem(NULL, SVSI_DESELECTOTHERS);
  3021. }
  3022. return FALSE;
  3023. }
  3024. ////////////////////////////////////////////////////////////////////////////
  3025. //
  3026. // CFileOpenBrowser::SelRename
  3027. //
  3028. ////////////////////////////////////////////////////////////////////////////
  3029. void CFileOpenBrowser::SelRename(void)
  3030. {
  3031. EnumItemObjects(SVGIO_SELECTION, SelRenameCB, NULL);
  3032. }
  3033. ////////////////////////////////////////////////////////////////////////////
  3034. //
  3035. // CFileOpenBrowser::OnStateChange
  3036. //
  3037. // Process selection change in the view control.
  3038. //
  3039. ////////////////////////////////////////////////////////////////////////////
  3040. STDMETHODIMP CFileOpenBrowser::OnStateChange(
  3041. struct IShellView *ppshv,
  3042. ULONG uChange)
  3043. {
  3044. if (ppshv != _psv)
  3045. {
  3046. return (E_INVALIDARG);
  3047. }
  3048. switch (uChange)
  3049. {
  3050. case (CDBOSC_SETFOCUS) :
  3051. {
  3052. if (_bSave)
  3053. {
  3054. SelFocusChange(FALSE);
  3055. }
  3056. break;
  3057. }
  3058. case (CDBOSC_KILLFOCUS) :
  3059. {
  3060. SetSaveButton(iszFileSaveButton);
  3061. break;
  3062. }
  3063. case (CDBOSC_SELCHANGE) :
  3064. {
  3065. //
  3066. // Post one of these messages, since we seem to get a whole bunch
  3067. // of them.
  3068. //
  3069. if (!_fSelChangedPending)
  3070. {
  3071. _fSelChangedPending = TRUE;
  3072. PostMessage(_hwndDlg, CDM_SELCHANGE, 0, 0);
  3073. }
  3074. break;
  3075. }
  3076. case (CDBOSC_RENAME) :
  3077. {
  3078. SelRename();
  3079. break;
  3080. }
  3081. default :
  3082. {
  3083. return (E_NOTIMPL);
  3084. }
  3085. }
  3086. return S_OK;
  3087. }
  3088. ////////////////////////////////////////////////////////////////////////////
  3089. //
  3090. // CFileOpenBrowser::IncludeObject
  3091. //
  3092. // Tell the view control which objects to include in its enumerations.
  3093. //
  3094. ////////////////////////////////////////////////////////////////////////////
  3095. STDMETHODIMP CFileOpenBrowser::IncludeObject(
  3096. struct IShellView *ppshv,
  3097. LPCITEMIDLIST pidl)
  3098. {
  3099. if (ppshv != _psv)
  3100. {
  3101. return (E_INVALIDARG);
  3102. }
  3103. BOOL bIncludeItem = FALSE;
  3104. //
  3105. // See if the callback is enabled.
  3106. //
  3107. if (_pOFN->Flags & OFN_ENABLEINCLUDENOTIFY)
  3108. {
  3109. //
  3110. // See what the callback says.
  3111. //
  3112. bIncludeItem = BOOLFROMPTR(CD_SendIncludeItemNotify(_hSubDlg,
  3113. _hwndDlg,
  3114. _psfCurrent,
  3115. pidl,
  3116. _pOFN,
  3117. _pOFI));
  3118. }
  3119. if (!bIncludeItem)
  3120. {
  3121. DWORD dwAttrs = SHGetAttributes(_psfCurrent, pidl, SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STREAM | SFGAO_FILESYSTEM | SFGAO_FOLDER);
  3122. bIncludeItem = _bSave ? _IncludeSaveItem(dwAttrs) : _IncludeOpenItem(dwAttrs);
  3123. if (!bIncludeItem)
  3124. {
  3125. return (S_FALSE);
  3126. }
  3127. // Apply filter if this thing is filesystem or canmoniker, except:
  3128. // If it is an item that contains filesystem items (SFGAO_STORAGEANCESTOR - typical folder)
  3129. // OR if it is a folder that canmoniker (ftp folder)
  3130. if (bIncludeItem && *_szLastFilter)
  3131. {
  3132. BOOL fContainer = _bSave ? _IsSaveContainer(dwAttrs) : _IsOpenContainer(dwAttrs);
  3133. if (!fContainer)
  3134. {
  3135. GetViewItemText(_psfCurrent, (LPITEMIDLIST)pidl, _szBuf, ARRAYSIZE(_szBuf));
  3136. if (!LinkMatchSpec(pidl, _szLastFilter) &&
  3137. !PathMatchSpec(_szBuf, _szLastFilter))
  3138. {
  3139. return (S_FALSE);
  3140. }
  3141. }
  3142. }
  3143. }
  3144. return S_OK;
  3145. }
  3146. ////////////////////////////////////////////////////////////////////////////
  3147. //
  3148. // CFileOpenBrowser::Notify
  3149. //
  3150. // Notification to decide whether or not a printer should be selected.
  3151. //
  3152. ////////////////////////////////////////////////////////////////////////////
  3153. STDMETHODIMP CFileOpenBrowser::Notify(
  3154. struct IShellView *ppshv,
  3155. DWORD dwNotify)
  3156. {
  3157. return S_FALSE;
  3158. }
  3159. ////////////////////////////////////////////////////////////////////////////
  3160. //
  3161. // CFileOpenBrowser::GetDefaultMenuText
  3162. //
  3163. // Returns the default menu text.
  3164. //
  3165. ////////////////////////////////////////////////////////////////////////////
  3166. STDMETHODIMP CFileOpenBrowser::GetDefaultMenuText(
  3167. struct IShellView *ppshv,
  3168. WCHAR *pszText,
  3169. INT cchMax)
  3170. {
  3171. return S_FALSE;
  3172. }
  3173. ////////////////////////////////////////////////////////////////////////////
  3174. //
  3175. // CFileOpenBrowser::GetViewFlags
  3176. //
  3177. // Returns Flags to customize the view .
  3178. //
  3179. ////////////////////////////////////////////////////////////////////////////
  3180. STDMETHODIMP CFileOpenBrowser::GetViewFlags(DWORD *pdwFlags)
  3181. {
  3182. DWORD dwFlags = 0;
  3183. if (pdwFlags)
  3184. {
  3185. if (_pOFN->Flags & OFN_FORCESHOWHIDDEN)
  3186. {
  3187. dwFlags |= CDB2GVF_SHOWALLFILES;
  3188. }
  3189. *pdwFlags = dwFlags;
  3190. }
  3191. return S_OK;
  3192. }
  3193. // Insert a single item into the location dropdown.
  3194. BOOL InsertItem(HWND hCtrl, int iItem, MYLISTBOXITEM *pItem, TCHAR *pszName)
  3195. {
  3196. LPTSTR pszChar;
  3197. for (pszChar = pszName; *pszChar != CHAR_NULL; pszChar = CharNext(pszChar))
  3198. {
  3199. if (pszChar - pszName >= MAX_DRIVELIST_STRING_LEN - 1)
  3200. {
  3201. *pszChar = CHAR_NULL;
  3202. break;
  3203. }
  3204. }
  3205. if (SendMessage(hCtrl, CB_INSERTSTRING, iItem, (LPARAM)(LPCTSTR)pszName) == CB_ERR)
  3206. {
  3207. return FALSE;
  3208. }
  3209. SendMessage(hCtrl, CB_SETITEMDATA, iItem, (LPARAM)pItem);
  3210. return TRUE;
  3211. }
  3212. int CALLBACK LBItemCompareProc(void * p1, void * p2, LPARAM lParam)
  3213. {
  3214. IShellFolder *psfParent = (IShellFolder *)lParam;
  3215. MYLISTBOXITEM *pItem1 = (MYLISTBOXITEM *)p1;
  3216. MYLISTBOXITEM *pItem2 = (MYLISTBOXITEM *)p2;
  3217. HRESULT hres = psfParent->CompareIDs(0, pItem1->pidlThis, pItem2->pidlThis);
  3218. return (short)SCODE_CODE(GetScode(hres));
  3219. }
  3220. ////////////////////////////////////////////////////////////////////////////
  3221. //
  3222. // CFileOpenBrowser::UpdateLevel
  3223. //
  3224. // Insert the contents of a shell container into the location dropdown.
  3225. //
  3226. ////////////////////////////////////////////////////////////////////////////
  3227. void CFileOpenBrowser::UpdateLevel(
  3228. HWND hwndLB,
  3229. int iInsert,
  3230. MYLISTBOXITEM *pParentItem)
  3231. {
  3232. if (!pParentItem)
  3233. {
  3234. return;
  3235. }
  3236. LPENUMIDLIST penum;
  3237. HDPA hdpa;
  3238. DWORD cIndent = pParentItem->cIndent + 1;
  3239. IShellFolder *psfParent = pParentItem->GetShellFolder();
  3240. if (!psfParent)
  3241. {
  3242. return;
  3243. }
  3244. hdpa = DPA_Create(4);
  3245. if (!hdpa)
  3246. {
  3247. //
  3248. // No memory: Cannot enum this level.
  3249. //
  3250. return;
  3251. }
  3252. if (S_OK == psfParent->EnumObjects(hwndLB, SHCONTF_FOLDERS, &penum))
  3253. {
  3254. ULONG celt;
  3255. LPITEMIDLIST pidl;
  3256. while (penum->Next(1, &pidl, &celt) == S_OK && celt == 1)
  3257. {
  3258. //
  3259. // Note: We need to avoid creation of pItem if this is not
  3260. // a file system object (or ancestor) to avoid extra
  3261. // bindings.
  3262. //
  3263. if (ShouldIncludeObject(this, psfParent, pidl, _pOFN->Flags))
  3264. {
  3265. MYLISTBOXITEM *pItem = new MYLISTBOXITEM();
  3266. if (pItem)
  3267. {
  3268. if (pItem->Init(GetDlgItem(_hwndDlg, cmb2), pParentItem, psfParent, pidl, cIndent, MLBI_PERMANENT | MLBI_PSFFROMPARENT, _pScheduler) &&
  3269. (DPA_AppendPtr(hdpa, pItem) >= 0))
  3270. {
  3271. //empty body
  3272. }
  3273. else
  3274. {
  3275. pItem->Release();
  3276. }
  3277. }
  3278. }
  3279. SHFree(pidl);
  3280. }
  3281. penum->Release();
  3282. }
  3283. DPA_Sort(hdpa, LBItemCompareProc, (LPARAM)psfParent);
  3284. int nLBIndex, nDPAIndex, nDPAItems;
  3285. BOOL bCurItemGone;
  3286. nDPAItems = DPA_GetPtrCount(hdpa);
  3287. nLBIndex = iInsert;
  3288. bCurItemGone = FALSE;
  3289. //
  3290. // Make sure the user is not playing with the selection right now.
  3291. //
  3292. ComboBox_ShowDropdown(hwndLB, FALSE);
  3293. //
  3294. // We're all sorted, so now we can do a merge.
  3295. //
  3296. for (nDPAIndex = 0; ; ++nDPAIndex)
  3297. {
  3298. MYLISTBOXITEM *pNewItem;
  3299. TCHAR szBuf[MAX_DRIVELIST_STRING_LEN];
  3300. MYLISTBOXITEM *pOldItem;
  3301. if (nDPAIndex < nDPAItems)
  3302. {
  3303. pNewItem = (MYLISTBOXITEM *)DPA_FastGetPtr(hdpa, nDPAIndex);
  3304. }
  3305. else
  3306. {
  3307. //
  3308. // Signal that we got to the end of the list.
  3309. //
  3310. pNewItem = NULL;
  3311. }
  3312. for (pOldItem = GetListboxItem(hwndLB, nLBIndex);
  3313. pOldItem != NULL;
  3314. pOldItem = GetListboxItem(hwndLB, ++nLBIndex))
  3315. {
  3316. int nCmp;
  3317. if (pOldItem->cIndent < cIndent)
  3318. {
  3319. //
  3320. // We went up a level, so insert here.
  3321. //
  3322. break;
  3323. }
  3324. else if (pOldItem->cIndent > cIndent)
  3325. {
  3326. //
  3327. // We went down a level so ignore this.
  3328. //
  3329. continue;
  3330. }
  3331. //
  3332. // Set this to 1 at the end of the DPA to clear out deleted items
  3333. // at the end.
  3334. //
  3335. nCmp = !pNewItem
  3336. ? 1
  3337. : LBItemCompareProc(pNewItem,
  3338. pOldItem,
  3339. (LPARAM)psfParent);
  3340. if (nCmp < 0)
  3341. {
  3342. //
  3343. // We found the first item greater than the new item, so
  3344. // add it in.
  3345. //
  3346. break;
  3347. }
  3348. else if (nCmp > 0)
  3349. {
  3350. //
  3351. // Oops! It looks like this item no longer exists, so
  3352. // delete it.
  3353. //
  3354. for (; ;)
  3355. {
  3356. if (pOldItem == _pCurrentLocation)
  3357. {
  3358. bCurItemGone = TRUE;
  3359. _pCurrentLocation = NULL;
  3360. }
  3361. pOldItem->Release();
  3362. SendMessage(hwndLB, CB_DELETESTRING, nLBIndex, NULL);
  3363. pOldItem = GetListboxItem(hwndLB, nLBIndex);
  3364. if (!pOldItem || pOldItem->cIndent <= cIndent)
  3365. {
  3366. break;
  3367. }
  3368. }
  3369. //
  3370. // We need to continue from the current position, not the
  3371. // next.
  3372. //
  3373. --nLBIndex;
  3374. }
  3375. else
  3376. {
  3377. //
  3378. // This item already exists, so no need to add it.
  3379. // Make sure we do not check this LB item again.
  3380. //
  3381. pOldItem->dwFlags |= MLBI_PERMANENT;
  3382. ++nLBIndex;
  3383. goto NotThisItem;
  3384. }
  3385. }
  3386. if (!pNewItem)
  3387. {
  3388. //
  3389. // Got to the end of the list.
  3390. //
  3391. break;
  3392. }
  3393. GetViewItemText(psfParent, pNewItem->pidlThis, szBuf, ARRAYSIZE(szBuf), SHGDN_NORMAL);
  3394. if (szBuf[0] && InsertItem(hwndLB, nLBIndex, pNewItem, szBuf))
  3395. {
  3396. ++nLBIndex;
  3397. }
  3398. else
  3399. {
  3400. NotThisItem:
  3401. pNewItem->Release();
  3402. }
  3403. }
  3404. DPA_Destroy(hdpa);
  3405. if (bCurItemGone)
  3406. {
  3407. //
  3408. // If we deleted the current selection, go back to the desktop.
  3409. //
  3410. ComboBox_SetCurSel(hwndLB, 0);
  3411. OnSelChange(-1, TRUE);
  3412. }
  3413. _iCurrentLocation = ComboBox_GetCurSel(hwndLB);
  3414. }
  3415. ////////////////////////////////////////////////////////////////////////////
  3416. //
  3417. // ClearListbox
  3418. //
  3419. // Clear the location dropdown and delete all entries.
  3420. //
  3421. ////////////////////////////////////////////////////////////////////////////
  3422. void ClearListbox(
  3423. HWND hwndList)
  3424. {
  3425. SendMessage(hwndList, WM_SETREDRAW, FALSE, NULL);
  3426. int cItems = (int) SendMessage(hwndList, CB_GETCOUNT, NULL, NULL);
  3427. while (cItems--)
  3428. {
  3429. MYLISTBOXITEM *pItem = GetListboxItem(hwndList, 0);
  3430. if (pItem)
  3431. pItem->Release();
  3432. SendMessage(hwndList, CB_DELETESTRING, 0, NULL);
  3433. }
  3434. SendMessage(hwndList, WM_SETREDRAW, TRUE, NULL);
  3435. InvalidateRect(hwndList, NULL, FALSE);
  3436. }
  3437. ////////////////////////////////////////////////////////////////////////////
  3438. //
  3439. // InitFilterBox
  3440. //
  3441. // Places the double null terminated list of filters in the combo box.
  3442. //
  3443. // The list consists of pairs of null terminated strings, with an
  3444. // additional null terminating the list.
  3445. //
  3446. ////////////////////////////////////////////////////////////////////////////
  3447. DWORD InitFilterBox(
  3448. HWND hDlg,
  3449. LPCTSTR lpszFilter)
  3450. {
  3451. DWORD nIndex = 0;
  3452. UINT nLen;
  3453. HWND hCmb = GetDlgItem(hDlg, cmb1);
  3454. if (hCmb)
  3455. {
  3456. while (*lpszFilter)
  3457. {
  3458. //
  3459. // First string put in as string to show.
  3460. //
  3461. nIndex = ComboBox_AddString(hCmb, lpszFilter);
  3462. nLen = lstrlen(lpszFilter) + 1;
  3463. lpszFilter += nLen;
  3464. //
  3465. // Second string put in as itemdata.
  3466. //
  3467. ComboBox_SetItemData(hCmb, nIndex, lpszFilter);
  3468. //
  3469. // Advance to next element.
  3470. //
  3471. nLen = lstrlen(lpszFilter) + 1;
  3472. lpszFilter += nLen;
  3473. }
  3474. }
  3475. //
  3476. // nIndex could be CB_ERR, which could cause problems.
  3477. //
  3478. if (nIndex == CB_ERR)
  3479. {
  3480. nIndex = 0;
  3481. }
  3482. return (nIndex);
  3483. }
  3484. ////////////////////////////////////////////////////////////////////////////
  3485. //
  3486. // MoveControls
  3487. //
  3488. ////////////////////////////////////////////////////////////////////////////
  3489. void MoveControls(
  3490. HWND hDlg,
  3491. BOOL bBelow,
  3492. int nStart,
  3493. int nXMove,
  3494. int nYMove)
  3495. {
  3496. HWND hwnd;
  3497. RECT rcWnd;
  3498. if (nXMove == 0 && nYMove == 0)
  3499. {
  3500. //
  3501. // Quick out if nothing to do.
  3502. //
  3503. return;
  3504. }
  3505. for (hwnd = GetWindow(hDlg, GW_CHILD);
  3506. hwnd;
  3507. hwnd = GetWindow(hwnd, GW_HWNDNEXT))
  3508. {
  3509. GetWindowRect(hwnd, &rcWnd);
  3510. MapWindowRect(HWND_DESKTOP, hDlg, &rcWnd);
  3511. if (bBelow)
  3512. {
  3513. if (rcWnd.top < nStart)
  3514. {
  3515. continue;
  3516. }
  3517. }
  3518. else
  3519. {
  3520. if (rcWnd.left < nStart)
  3521. {
  3522. continue;
  3523. }
  3524. }
  3525. SetWindowPos(hwnd,
  3526. NULL,
  3527. rcWnd.left + nXMove,
  3528. rcWnd.top + nYMove,
  3529. 0,
  3530. 0,
  3531. SWP_NOZORDER | SWP_NOSIZE);
  3532. }
  3533. }
  3534. ////////////////////////////////////////////////////////////////////////////
  3535. //
  3536. // DummyDlgProc
  3537. //
  3538. ////////////////////////////////////////////////////////////////////////////
  3539. BOOL_PTR CALLBACK DummyDlgProc(
  3540. HWND hDlg,
  3541. UINT uMsg,
  3542. WPARAM wParam,
  3543. LPARAM lParam)
  3544. {
  3545. switch (uMsg)
  3546. {
  3547. case (WM_INITDIALOG) :
  3548. {
  3549. break;
  3550. }
  3551. default :
  3552. {
  3553. return FALSE;
  3554. }
  3555. }
  3556. return TRUE;
  3557. }
  3558. /*
  3559. --------
  3560. | Cancel |
  3561. -------- --
  3562. |
  3563. -------- |
  3564. x Open As Read | Help | | Height by which all controls below view needs to be moved
  3565. -------- | and also height by which View window height should be increased.
  3566. --
  3567. */
  3568. void CFileOpenBrowser::ReAdjustDialog()
  3569. {
  3570. int iDelta = 0;
  3571. RECT rc1,rc2;
  3572. //Make sure all our assumptions are valid
  3573. if ((_iVersion < OPENFILEVERSION_NT5) || //if this dialog version is less than NT5 or
  3574. IsWindowEnabled(GetDlgItem(_hwndDlg, chx1)) || // if Open As Read Only is still enabled or
  3575. IsWindowEnabled(GetDlgItem(_hwndDlg, pshHelp))) // If the Help button is still enabled then
  3576. {
  3577. //Dont do anything
  3578. return ;
  3579. }
  3580. GetWindowRect(GetDlgItem(_hwndDlg, pshHelp), &rc1);
  3581. GetWindowRect(GetDlgItem(_hwndDlg, IDCANCEL), &rc2);
  3582. //Add the height of the button
  3583. iDelta += RECTHEIGHT(rc1);
  3584. //Add the gap between buttons
  3585. iDelta += rc1.top - rc2.bottom;
  3586. RECT rcView;
  3587. GetWindowRect(GetDlgItem(_hwndDlg, lst1), &rcView);
  3588. MapWindowRect(HWND_DESKTOP, _hwndDlg, &rcView);
  3589. HDWP hdwp;
  3590. hdwp = BeginDeferWindowPos(10);
  3591. HWND hwnd;
  3592. RECT rc;
  3593. hwnd = ::GetWindow(_hwndDlg, GW_CHILD);
  3594. while (hwnd && hdwp)
  3595. {
  3596. GetWindowRect(hwnd, &rc);
  3597. MapWindowRect(HWND_DESKTOP, _hwndDlg, &rc);
  3598. switch (GetDlgCtrlID(hwnd))
  3599. {
  3600. case pshHelp:
  3601. case chx1:
  3602. break;
  3603. default :
  3604. //
  3605. // See if the control needs to be adjusted.
  3606. //
  3607. if (rc.top > rcView.bottom)
  3608. {
  3609. //Move Y position of these controls
  3610. hdwp = DeferWindowPos(hdwp,
  3611. hwnd,
  3612. NULL,
  3613. rc.left,
  3614. rc.top + iDelta,
  3615. RECTWIDTH(rc),
  3616. RECTHEIGHT(rc),
  3617. SWP_NOZORDER);
  3618. }
  3619. }
  3620. hwnd = ::GetWindow(hwnd, GW_HWNDNEXT);
  3621. }
  3622. //Adjust the size of the view window
  3623. if (hdwp)
  3624. {
  3625. hdwp = DeferWindowPos(hdwp,
  3626. GetDlgItem(_hwndDlg, lst1),
  3627. NULL,
  3628. rcView.left,
  3629. rcView.top,
  3630. RECTWIDTH(rcView),
  3631. RECTHEIGHT(rcView) + iDelta,
  3632. SWP_NOZORDER);
  3633. }
  3634. EndDeferWindowPos(hdwp);
  3635. }
  3636. ////////////////////////////////////////////////////////////////////////////
  3637. //
  3638. // CFileOpenBrowser::ResetDialogHeight
  3639. //
  3640. // Hack for Borland JBuilder Professional (pah!)
  3641. //
  3642. // These guys relied on a bug in Win95/NT4's Comdlg32 that we fixed in IE4.
  3643. // So instead of reintroducing the bug, we detect that they are relying
  3644. // on the bug and hack around them.
  3645. //
  3646. // These guys do a SetWindowLong(GWL_STYLE) on the dialog box and
  3647. // then reparent it! Unfortunately, they didn't quite get their
  3648. // bookkeeping right: They forgot to do a RedrawWindow after removing
  3649. // the WS_CAPTION style. You see, just editing the style doesn't do
  3650. // anything - the style changes don't take effect until the next
  3651. // RedrawWindow. When they scratched their heads ("Hey, why is
  3652. // the caption still there?"), they decided to brute-force the
  3653. // solution: They slide the window so the caption goes "off the screen".
  3654. //
  3655. // Problem: We fixed a bug for IE4 where ResetDialogHeight would screw
  3656. // up and not resize the dialog when it should've, if the app did a
  3657. // SetWindowPos on the window to change its vertical position downward
  3658. // by more than the amount we needed to grow.
  3659. //
  3660. // So now when we resize it properly, this generates an internal
  3661. // RedrawWindow, which means that Borland's brute-force hack tries
  3662. // to fix a problem that no longer exists!
  3663. //
  3664. // Therefore, ResetDialogHeight now checks if the app has
  3665. //
  3666. // 1. Changed the dialog window style,
  3667. // 2. Moved the dialog downward by more than we needed to grow,
  3668. // 3. Forgotten to call RedrawWindow.
  3669. //
  3670. // If so, then we temporarily restore the original dialog window style,
  3671. // do the (correct) resize, then restore the window style. Reverting
  3672. // the window style means that all the non-client stuff retains its old
  3673. // (incorrect, but what the app is expecting) size.
  3674. //
  3675. ////////////////////////////////////////////////////////////////////////////
  3676. void CFileOpenBrowser::ResetDialogHeight(
  3677. HWND hDlg,
  3678. HWND hwndExclude,
  3679. HWND hwndGrip,
  3680. int nCtlsBottom)
  3681. {
  3682. POINT ptCurrent;
  3683. int topNew;
  3684. GetControlsArea(hDlg, hwndExclude, hwndGrip, &ptCurrent, &topNew);
  3685. int nDiffBottom = nCtlsBottom - ptCurrent.y;
  3686. if (nDiffBottom > 0)
  3687. {
  3688. RECT rcFull;
  3689. int Height;
  3690. GetWindowRect(hDlg, &rcFull);
  3691. Height = RECTHEIGHT(rcFull) - nDiffBottom;
  3692. if (Height >= ptCurrent.y)
  3693. {
  3694. // Borland JBuilder hack! This SetWindowPos will generate
  3695. // a RedrawWindow which the app might not be expecting.
  3696. // Detect this case and create a set of temporary styles
  3697. // which will neutralize the frame recalc implicit in the
  3698. // RedrawWindow.
  3699. //
  3700. LONG lStylePrev;
  3701. BOOL bBorlandHack = FALSE;
  3702. if (!_bAppRedrawn && // App didn't call RedrawWindow
  3703. _topOrig + nCtlsBottom <= topNew + ptCurrent.y) // Win95 didn't resize
  3704. {
  3705. // Since the app didn't call RedrawWindow, it still
  3706. // thinks that there is a WS_CAPTION. So put the caption
  3707. // back while we do frame recalcs.
  3708. bBorlandHack = TRUE;
  3709. lStylePrev = GetWindowLong(hDlg, GWL_STYLE);
  3710. SetWindowLong(hDlg, GWL_STYLE, lStylePrev | WS_CAPTION);
  3711. }
  3712. SetWindowPos(hDlg,
  3713. NULL,
  3714. 0,
  3715. 0,
  3716. RECTWIDTH(rcFull),
  3717. Height,
  3718. SWP_NOZORDER | SWP_NOMOVE);
  3719. if (bBorlandHack)
  3720. {
  3721. // Restore the original style after we temporarily
  3722. // messed with it.
  3723. SetWindowLong(hDlg, GWL_STYLE, lStylePrev);
  3724. }
  3725. }
  3726. }
  3727. }
  3728. ////////////////////////////////////////////////////////////////////////////
  3729. //
  3730. // CFileOpenBrowser::CreateHookDialog
  3731. //
  3732. ////////////////////////////////////////////////////////////////////////////
  3733. BOOL CFileOpenBrowser::CreateHookDialog(
  3734. POINT *pPtSize)
  3735. {
  3736. DWORD Flags = _pOFN->Flags;
  3737. BOOL bRet = FALSE;
  3738. HANDLE hTemplate;
  3739. HINSTANCE hinst;
  3740. LPCTSTR lpDlg;
  3741. HWND hCtlCmn;
  3742. RECT rcReal, rcSub, rcToolbar, rcAppToolbar;
  3743. int nXMove, nXRoom, nYMove, nYRoom, nXStart, nYStart;
  3744. DWORD dwStyle;
  3745. DLGPROC lpfnHookProc;
  3746. if (!(Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
  3747. {
  3748. //
  3749. // No hook or template; nothing to do.
  3750. //
  3751. ResetDialogHeight(_hwndDlg, NULL, _hwndGrip, pPtSize->y);
  3752. GetWindowRect(_hwndDlg, &rcReal);
  3753. _ptLastSize.x = rcReal.right - rcReal.left;
  3754. _ptLastSize.y = rcReal.bottom - rcReal.top;
  3755. return TRUE;
  3756. }
  3757. if (Flags & OFN_ENABLETEMPLATEHANDLE)
  3758. {
  3759. hTemplate = _pOFN->hInstance;
  3760. hinst = ::g_hinst;
  3761. }
  3762. else
  3763. {
  3764. if (Flags & OFN_ENABLETEMPLATE)
  3765. {
  3766. if (!_pOFN->lpTemplateName)
  3767. {
  3768. StoreExtendedError(CDERR_NOTEMPLATE);
  3769. return FALSE;
  3770. }
  3771. if (!_pOFN->hInstance)
  3772. {
  3773. StoreExtendedError(CDERR_NOHINSTANCE);
  3774. return FALSE;
  3775. }
  3776. lpDlg = _pOFN->lpTemplateName;
  3777. hinst = _pOFN->hInstance;
  3778. }
  3779. else
  3780. {
  3781. hinst = ::g_hinst;
  3782. lpDlg = MAKEINTRESOURCE(DUMMYFILEOPENORD);
  3783. }
  3784. HRSRC hRes = FindResource(hinst, lpDlg, RT_DIALOG);
  3785. if (hRes == NULL)
  3786. {
  3787. StoreExtendedError(CDERR_FINDRESFAILURE);
  3788. return FALSE;
  3789. }
  3790. if ((hTemplate = LoadResource(hinst, hRes)) == NULL)
  3791. {
  3792. StoreExtendedError(CDERR_LOADRESFAILURE);
  3793. return FALSE;
  3794. }
  3795. }
  3796. if (!LockResource(hTemplate))
  3797. {
  3798. StoreExtendedError(CDERR_LOADRESFAILURE);
  3799. return FALSE;
  3800. }
  3801. dwStyle = ((LPDLGTEMPLATE)hTemplate)->style;
  3802. if (!(dwStyle & WS_CHILD))
  3803. {
  3804. //
  3805. // I don't want to go poking in their template, and I don't want to
  3806. // make a copy, so I will just fail. This also helps us weed out
  3807. // "old-style" templates that were accidentally used.
  3808. //
  3809. StoreExtendedError(CDERR_DIALOGFAILURE);
  3810. return FALSE;
  3811. }
  3812. if (Flags & OFN_ENABLEHOOK)
  3813. {
  3814. lpfnHookProc = (DLGPROC)GETHOOKFN(_pOFN);
  3815. }
  3816. else
  3817. {
  3818. lpfnHookProc = DummyDlgProc;
  3819. }
  3820. //
  3821. // WOW apps are not allowed to get the new explorer look, so there
  3822. // is no need to do any special WOW checking before calling the create
  3823. // dialog function.
  3824. //
  3825. if (_pOFI->ApiType == COMDLG_ANSI)
  3826. {
  3827. ThunkOpenFileNameW2A(_pOFI);
  3828. _hSubDlg = CreateDialogIndirectParamA(hinst,
  3829. (LPDLGTEMPLATE)hTemplate,
  3830. _hwndDlg,
  3831. lpfnHookProc,
  3832. (LPARAM)(_pOFI->pOFNA));
  3833. ThunkOpenFileNameA2W(_pOFI);
  3834. }
  3835. else
  3836. {
  3837. _hSubDlg = CreateDialogIndirectParam(hinst,
  3838. (LPDLGTEMPLATE)hTemplate,
  3839. _hwndDlg,
  3840. lpfnHookProc,
  3841. (LPARAM)_pOFN);
  3842. }
  3843. if (!_hSubDlg)
  3844. {
  3845. StoreExtendedError(CDERR_DIALOGFAILURE);
  3846. return FALSE;
  3847. }
  3848. //
  3849. // We reset the height of the dialog after creating the hook dialog so
  3850. // the hook can hide controls in its WM_INITDIALOG message.
  3851. //
  3852. ResetDialogHeight(_hwndDlg, _hSubDlg, _hwndGrip, pPtSize->y);
  3853. //
  3854. // Now move all of the controls around.
  3855. //
  3856. GetClientRect(_hwndDlg, &rcReal);
  3857. GetClientRect(_hSubDlg, &rcSub);
  3858. hCtlCmn = GetDlgItem(_hSubDlg, stc32);
  3859. if (hCtlCmn)
  3860. {
  3861. RECT rcCmn;
  3862. GetWindowRect(hCtlCmn, &rcCmn);
  3863. MapWindowRect(HWND_DESKTOP, _hSubDlg, &rcCmn);
  3864. //
  3865. // Move the controls in our dialog to make room for the hook's
  3866. // controls above and to the left.
  3867. //
  3868. MoveControls(_hwndDlg, FALSE, 0, rcCmn.left, rcCmn.top);
  3869. //
  3870. // Calculate how far sub dialog controls need to move, and how much
  3871. // more room our dialog needs.
  3872. //
  3873. nXStart = rcCmn.right;
  3874. nYStart = rcCmn.bottom;
  3875. //See how far part the cotrols are in the template
  3876. nXMove = (rcReal.right - rcReal.left) - (rcCmn.right - rcCmn.left);
  3877. nYMove = (rcReal.bottom - rcReal.top) - (rcCmn.bottom - rcCmn.top);
  3878. //See how much room we need to leave at the bottom and right
  3879. // for the sub dialog controls at the botton and right
  3880. nXRoom = rcSub.right - (rcCmn.right - rcCmn.left);
  3881. nYRoom = rcSub.bottom - (rcCmn.bottom - rcCmn.top);
  3882. if (nXMove < 0)
  3883. {
  3884. //
  3885. // If the template size is too big, we need more room in the
  3886. // dialog.
  3887. //
  3888. nXRoom -= nXMove;
  3889. nXMove = 0;
  3890. }
  3891. if (nYMove < 0)
  3892. {
  3893. //
  3894. // If the template size is too big, we need more room in the
  3895. // dialog.
  3896. //
  3897. nYRoom -= nYMove;
  3898. nYMove = 0;
  3899. }
  3900. //
  3901. // Resize the "template" control so the hook knows the size of our
  3902. // stuff.
  3903. //
  3904. SetWindowPos(hCtlCmn,
  3905. NULL,
  3906. 0,
  3907. 0,
  3908. rcReal.right - rcReal.left,
  3909. rcReal.bottom - rcReal.top,
  3910. SWP_NOMOVE | SWP_NOZORDER);
  3911. }
  3912. else
  3913. {
  3914. //
  3915. // Extra controls go on the bottom by default.
  3916. //
  3917. nXStart = nYStart = nXMove = nXRoom = 0;
  3918. nYMove = rcReal.bottom;
  3919. nYRoom = rcSub.bottom;
  3920. }
  3921. MoveControls(_hSubDlg, FALSE, nXStart, nXMove, 0);
  3922. MoveControls(_hSubDlg, TRUE, nYStart, 0, nYMove);
  3923. //
  3924. // Resize our dialog and the sub dialog.
  3925. // FEATURE: We need to check whether part of the dialog is off screen.
  3926. //
  3927. GetWindowRect(_hwndDlg, &rcReal);
  3928. _ptLastSize.x = (rcReal.right - rcReal.left) + nXRoom;
  3929. _ptLastSize.y = (rcReal.bottom - rcReal.top) + nYRoom;
  3930. SetWindowPos(_hwndDlg,
  3931. NULL,
  3932. 0,
  3933. 0,
  3934. _ptLastSize.x,
  3935. _ptLastSize.y,
  3936. SWP_NOZORDER | SWP_NOMOVE);
  3937. //
  3938. // Note that we are moving this to (0,0) and the bottom of the Z order.
  3939. //
  3940. GetWindowRect(_hSubDlg, &rcReal);
  3941. SetWindowPos(_hSubDlg,
  3942. HWND_BOTTOM,
  3943. 0,
  3944. 0,
  3945. (rcReal.right - rcReal.left) + nXMove,
  3946. (rcReal.bottom - rcReal.top) + nYMove,
  3947. 0);
  3948. ShowWindow(_hSubDlg, SW_SHOW);
  3949. CD_SendInitDoneNotify(_hSubDlg, _hwndDlg, _pOFN, _pOFI);
  3950. //
  3951. // Make sure the toolbar is still large enough. Apps like Visio move
  3952. // the toolbar control and may make it too small now that we added the
  3953. // View Desktop toolbar button.
  3954. //
  3955. if (_hwndToolbar && IsVisible(_hwndToolbar))
  3956. {
  3957. LONG Width;
  3958. //
  3959. // Get the default toolbar coordinates.
  3960. //
  3961. GetControlRect(_hwndDlg, stc1, &rcToolbar);
  3962. //
  3963. // Get the app adjusted toolbar coordinates.
  3964. //
  3965. GetWindowRect(_hwndToolbar, &rcAppToolbar);
  3966. MapWindowRect(HWND_DESKTOP, _hwndDlg, &rcAppToolbar);
  3967. //
  3968. // See if the default toolbar size is greater than the current
  3969. // toolbar size.
  3970. //
  3971. Width = rcToolbar.right - rcToolbar.left;
  3972. if (Width > (rcAppToolbar.right - rcAppToolbar.left))
  3973. {
  3974. //
  3975. // Set rcToolbar to be the new toolbar rectangle.
  3976. //
  3977. rcToolbar.left = rcAppToolbar.left;
  3978. rcToolbar.top = rcAppToolbar.top;
  3979. rcToolbar.right = rcAppToolbar.left + Width;
  3980. rcToolbar.bottom = rcAppToolbar.bottom;
  3981. //
  3982. // Get the dialog coordinates.
  3983. //
  3984. GetWindowRect(_hwndDlg, &rcReal);
  3985. MapWindowRect(HWND_DESKTOP, _hwndDlg, &rcReal);
  3986. //
  3987. // Make sure the new toolbar doesn't go off the end of
  3988. // the dialog.
  3989. //
  3990. if (rcToolbar.right < rcReal.right)
  3991. {
  3992. //
  3993. // Make sure there are no controls to the right of the
  3994. // toolbar that overlap the new toolbar.
  3995. //
  3996. for (hCtlCmn = ::GetWindow(_hwndDlg, GW_CHILD);
  3997. hCtlCmn;
  3998. hCtlCmn = ::GetWindow(hCtlCmn, GW_HWNDNEXT))
  3999. {
  4000. if ((hCtlCmn != _hwndToolbar) && IsVisible(hCtlCmn))
  4001. {
  4002. RECT rcTemp;
  4003. //
  4004. // Get the coordinates of the window.
  4005. //
  4006. GetWindowRect(hCtlCmn, &rcSub);
  4007. MapWindowRect(HWND_DESKTOP, _hwndDlg, &rcSub);
  4008. //
  4009. // If the App's toolbar rectangle does not
  4010. // intersect the window and the the new toolbar
  4011. // does intersect the window, then we cannot
  4012. // increase the size of the toolbar.
  4013. //
  4014. if (!IntersectRect(&rcTemp, &rcAppToolbar, &rcSub) &&
  4015. IntersectRect(&rcTemp, &rcToolbar, &rcSub))
  4016. {
  4017. break;
  4018. }
  4019. }
  4020. }
  4021. //
  4022. // Reset the size of the toolbar if there were no conflicts.
  4023. //
  4024. if (!hCtlCmn)
  4025. {
  4026. ::SetWindowPos(_hwndToolbar,
  4027. NULL,
  4028. rcToolbar.left,
  4029. rcToolbar.top,
  4030. Width,
  4031. rcToolbar.bottom - rcToolbar.top,
  4032. SWP_NOACTIVATE | SWP_NOZORDER |
  4033. SWP_SHOWWINDOW);
  4034. }
  4035. }
  4036. }
  4037. }
  4038. bRet = TRUE;
  4039. return (bRet);
  4040. }
  4041. ////////////////////////////////////////////////////////////////////////////
  4042. //
  4043. // InitSaveAsControls
  4044. //
  4045. // Change the captions of a bunch of controls to say saveas-like things.
  4046. //
  4047. ////////////////////////////////////////////////////////////////////////////
  4048. const struct
  4049. {
  4050. UINT idControl;
  4051. UINT idString;
  4052. } aSaveAsControls[] =
  4053. {
  4054. { (UINT)-1, iszFileSaveTitle }, // -1 means the dialog itself
  4055. { stc2, iszSaveAsType },
  4056. { IDOK, iszFileSaveButton },
  4057. { stc4, iszFileSaveIn }
  4058. };
  4059. void InitSaveAsControls(
  4060. HWND hDlg)
  4061. {
  4062. for (UINT iControl = 0; iControl < ARRAYSIZE(aSaveAsControls); iControl++)
  4063. {
  4064. HWND hwnd = hDlg;
  4065. TCHAR szText[80];
  4066. if (aSaveAsControls[iControl].idControl != -1)
  4067. {
  4068. hwnd = GetDlgItem(hDlg, aSaveAsControls[iControl].idControl);
  4069. }
  4070. CDLoadString(g_hinst,
  4071. aSaveAsControls[iControl].idString,
  4072. szText,
  4073. ARRAYSIZE(szText));
  4074. SetWindowText(hwnd, szText);
  4075. }
  4076. }
  4077. ////////////////////////////////////////////////////////////////////////////
  4078. //
  4079. // GetControlsArea
  4080. //
  4081. // Returns the leftmost edge and bottom-most edge of the
  4082. // controls farthest right and down (in screen coordinates).
  4083. //
  4084. ////////////////////////////////////////////////////////////////////////////
  4085. void
  4086. GetControlsArea(
  4087. HWND hDlg,
  4088. HWND hwndExclude,
  4089. HWND hwndGrip,
  4090. POINT *pPtSize,
  4091. LPINT pTop)
  4092. {
  4093. RECT rc;
  4094. HWND hwnd;
  4095. int uBottom;
  4096. int uRight;
  4097. uBottom = 0x80000000;
  4098. uRight = 0x80000000;
  4099. for (hwnd = GetWindow(hDlg, GW_CHILD);
  4100. hwnd;
  4101. hwnd = GetWindow(hwnd, GW_HWNDNEXT))
  4102. {
  4103. //
  4104. // Note we cannot use IsWindowVisible, since the parent is not visible.
  4105. // We do not want the magic static to be included.
  4106. //
  4107. if (!IsVisible(hwnd) || (hwnd == hwndExclude) || (hwnd == hwndGrip))
  4108. {
  4109. continue;
  4110. }
  4111. GetWindowRect(hwnd, &rc);
  4112. if (uRight < rc.right)
  4113. {
  4114. uRight = rc.right;
  4115. }
  4116. if (uBottom < rc.bottom)
  4117. {
  4118. uBottom = rc.bottom;
  4119. }
  4120. }
  4121. GetWindowRect(hDlg, &rc);
  4122. pPtSize->x = uRight - rc.left;
  4123. pPtSize->y = uBottom - rc.top;
  4124. if (pTop)
  4125. *pTop = rc.top;
  4126. }
  4127. // Initializes the Look In Drop Down combobox
  4128. BOOL CFileOpenBrowser::InitLookIn(HWND hDlg)
  4129. {
  4130. TCHAR szScratch[MAX_PATH];
  4131. LPITEMIDLIST pidl;
  4132. IShellFolder *psf;
  4133. HWND hCtrl = GetDlgItem(hDlg, cmb2);
  4134. // Add the History Location.
  4135. if (_iVersion >= OPENFILEVERSION_NT5)
  4136. {
  4137. int iImage, iSelectedImage;
  4138. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_RECENT, &pidl)))
  4139. {
  4140. LPITEMIDLIST pidlLast;
  4141. IShellFolder *psfParent;
  4142. HRESULT hr = CDBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psfParent), (LPCITEMIDLIST *)&pidlLast);
  4143. if (SUCCEEDED(hr))
  4144. {
  4145. DWORD dwAttribs = SHGetAttributes(psfParent, pidlLast, SFGAO_STORAGECAPMASK | SFGAO_SHARE);
  4146. //Get the image corresponding to this pidl
  4147. iImage = SHMapPIDLToSystemImageListIndex(psfParent, pidlLast, &iSelectedImage);
  4148. hr = psfParent->BindToObject(pidlLast, NULL, IID_PPV_ARG(IShellFolder, &psf));
  4149. if (SUCCEEDED(hr))
  4150. {
  4151. MYLISTBOXITEM *pItem = new MYLISTBOXITEM();
  4152. if (pItem)
  4153. {
  4154. BOOL bAdded = FALSE;
  4155. if (pItem->Init(GetDlgItem(_hwndDlg, cmb2), psf, pidl, 0, MLBI_PERMANENT, dwAttribs, iImage, iSelectedImage))
  4156. {
  4157. DisplayNameOf(psfParent, pidlLast, SHGDN_INFOLDER, szScratch, ARRAYSIZE(szScratch));
  4158. if (InsertItem(hCtrl, 0, pItem, szScratch))
  4159. {
  4160. //Update the index of Desktop in Look In dropdown from 0 to 1
  4161. _iNodeDesktop = 1;
  4162. bAdded = TRUE;
  4163. }
  4164. }
  4165. if (!bAdded)
  4166. {
  4167. pItem->Release();
  4168. }
  4169. }
  4170. psf->Release();
  4171. }
  4172. psfParent->Release();
  4173. }
  4174. SHFree(pidl);
  4175. }
  4176. }
  4177. BOOL bRet = FALSE;
  4178. // Insert the Desktop in the Lookin dropdown
  4179. if (SUCCEEDED(SHGetDesktopFolder(&psf)))
  4180. {
  4181. pidl = SHCloneSpecialIDList(hDlg, CSIDL_DESKTOP, FALSE);
  4182. if (pidl)
  4183. {
  4184. // Add the desktop item
  4185. MYLISTBOXITEM *pItem = new MYLISTBOXITEM();
  4186. if (pItem)
  4187. {
  4188. if (pItem->Init(GetDlgItem(_hwndDlg, cmb2), NULL, psf, pidl, 0, MLBI_PERMANENT, _pScheduler))
  4189. {
  4190. GetViewItemText(psf, NULL, szScratch, ARRAYSIZE(szScratch));
  4191. if (InsertItem(hCtrl, _iNodeDesktop, pItem, szScratch))
  4192. {
  4193. pItem->AddRef();
  4194. _pCurrentLocation = pItem;
  4195. bRet = TRUE;
  4196. }
  4197. }
  4198. pItem->Release();
  4199. }
  4200. SHFree(pidl);
  4201. }
  4202. psf->Release();
  4203. }
  4204. if (!bRet)
  4205. {
  4206. ClearListbox(hCtrl);
  4207. }
  4208. return bRet;
  4209. }
  4210. // Main initialization (WM_INITDIALOG phase).
  4211. BOOL InitLocation(HWND hDlg, LPOFNINITINFO poii)
  4212. {
  4213. HWND hCtrl = GetDlgItem(hDlg, cmb2);
  4214. LPOPENFILENAME lpOFN = poii->lpOFI->pOFN;
  4215. BOOL fIsSaveAs = poii->bSave;
  4216. POINT ptSize;
  4217. GetControlsArea(hDlg, NULL, NULL, &ptSize, NULL);
  4218. CFileOpenBrowser *pDlgStruct = new CFileOpenBrowser(hDlg, FALSE);
  4219. if (pDlgStruct == NULL)
  4220. {
  4221. StoreExtendedError(CDERR_INITIALIZATION);
  4222. return FALSE;
  4223. }
  4224. StoreBrowser(hDlg, pDlgStruct);
  4225. if ((poii->lpOFI->iVersion < OPENFILEVERSION_NT5) &&
  4226. (poii->lpOFI->pOFN->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
  4227. {
  4228. pDlgStruct->_iVersion = OPENFILEVERSION_NT4;
  4229. }
  4230. //See if we need to use dropdown combobox or edit box for filename
  4231. if (pDlgStruct->_iVersion >= OPENFILEVERSION_NT5)
  4232. {
  4233. pDlgStruct->EnableFileMRU(!IsRestricted(REST_NOFILEMRU));
  4234. }
  4235. else
  4236. {
  4237. pDlgStruct->EnableFileMRU(FALSE);
  4238. }
  4239. pDlgStruct->CreateToolbar();
  4240. GetControlsArea(hDlg, NULL, NULL, &ptSize, &pDlgStruct->_topOrig);
  4241. if (!pDlgStruct->InitLookIn(hDlg))
  4242. {
  4243. StoreExtendedError(CDERR_INITIALIZATION);
  4244. return FALSE;
  4245. }
  4246. pDlgStruct->_pOFN = lpOFN;
  4247. pDlgStruct->_bSave = fIsSaveAs;
  4248. pDlgStruct->_pOFI = poii->lpOFI;
  4249. pDlgStruct->_pszDefExt.TSStrCpy(lpOFN->lpstrDefExt);
  4250. //
  4251. // Here follows all the caller-parameter-based initialization.
  4252. //
  4253. pDlgStruct->_lpOKProc = (WNDPROC)::SetWindowLongPtr(::GetDlgItem(hDlg, IDOK),
  4254. GWLP_WNDPROC,
  4255. (LONG_PTR)OKSubclass);
  4256. if (lpOFN->Flags & OFN_CREATEPROMPT)
  4257. {
  4258. lpOFN->Flags |= (OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST);
  4259. }
  4260. else if (lpOFN->Flags & OFN_FILEMUSTEXIST)
  4261. {
  4262. lpOFN->Flags |= OFN_PATHMUSTEXIST;
  4263. }
  4264. //
  4265. // We need to make sure the Ansi flags are up to date.
  4266. //
  4267. if (poii->lpOFI->ApiType == COMDLG_ANSI)
  4268. {
  4269. poii->lpOFI->pOFNA->Flags = lpOFN->Flags;
  4270. }
  4271. //
  4272. // Limit the text to the maximum path length instead of limiting it to
  4273. // the buffer length. This allows users to type ..\..\.. and move
  4274. // around when the app gives an extremely small buffer.
  4275. //
  4276. if (pDlgStruct->_bUseCombo)
  4277. {
  4278. SendDlgItemMessage(hDlg, cmb13, CB_LIMITTEXT, MAX_PATH -1, 0);
  4279. }
  4280. else
  4281. {
  4282. SendDlgItemMessage(hDlg, edt1, EM_LIMITTEXT, MAX_PATH - 1, 0);
  4283. }
  4284. SendDlgItemMessage(hDlg, cmb2, CB_SETEXTENDEDUI, 1, 0);
  4285. SendDlgItemMessage(hDlg, cmb1, CB_SETEXTENDEDUI, 1, 0);
  4286. //
  4287. // Save original directory for later restoration, if necessary.
  4288. //
  4289. pDlgStruct->_szStartDir[0] = TEXT('\0');
  4290. GetCurrentDirectory(ARRAYSIZE(pDlgStruct->_szStartDir),
  4291. pDlgStruct->_szStartDir);
  4292. //
  4293. // Initialize all provided filters.
  4294. //
  4295. if (lpOFN->lpstrCustomFilter && *lpOFN->lpstrCustomFilter)
  4296. {
  4297. SendDlgItemMessage(hDlg,
  4298. cmb1,
  4299. CB_INSERTSTRING,
  4300. 0,
  4301. (LONG_PTR)lpOFN->lpstrCustomFilter);
  4302. SendDlgItemMessage(hDlg,
  4303. cmb1,
  4304. CB_SETITEMDATA,
  4305. 0,
  4306. (LPARAM)(lpOFN->lpstrCustomFilter +
  4307. lstrlen(lpOFN->lpstrCustomFilter) + 1));
  4308. SendDlgItemMessage(hDlg,
  4309. cmb1,
  4310. CB_LIMITTEXT,
  4311. (WPARAM)(lpOFN->nMaxCustFilter),
  4312. 0L);
  4313. }
  4314. else
  4315. {
  4316. //
  4317. // Given no custom filter, the index will be off by one.
  4318. //
  4319. if (lpOFN->nFilterIndex != 0)
  4320. {
  4321. lpOFN->nFilterIndex--;
  4322. }
  4323. }
  4324. //
  4325. // Listed filters next.
  4326. //
  4327. if (lpOFN->lpstrFilter)
  4328. {
  4329. if (lpOFN->nFilterIndex > InitFilterBox(hDlg, lpOFN->lpstrFilter))
  4330. {
  4331. lpOFN->nFilterIndex = 0;
  4332. }
  4333. }
  4334. else
  4335. {
  4336. lpOFN->nFilterIndex = 0;
  4337. }
  4338. //
  4339. // If an entry exists, select the one indicated by nFilterIndex.
  4340. //
  4341. if ((lpOFN->lpstrFilter) ||
  4342. (lpOFN->lpstrCustomFilter && *lpOFN->lpstrCustomFilter))
  4343. {
  4344. HWND hCmb1 = GetDlgItem(hDlg, cmb1);
  4345. ComboBox_SetCurSel(hCmb1, lpOFN->nFilterIndex);
  4346. pDlgStruct->RefreshFilter(hCmb1);
  4347. }
  4348. //Check if this Object Open Dialog
  4349. if (lpOFN->Flags & OFN_ENABLEINCLUDENOTIFY)
  4350. {
  4351. //Yes, change the text so that it looks like a object open
  4352. TCHAR szTemp[256];
  4353. //Change the File &Name: to Object &Name:
  4354. CDLoadString((HINSTANCE)g_hinst, iszObjectName, (LPTSTR)szTemp, ARRAYSIZE(szTemp));
  4355. SetWindowText(GetDlgItem(hDlg, stc3), szTemp);
  4356. //Change the Files of &type: to Objects of &type:
  4357. CDLoadString((HINSTANCE)g_hinst, iszObjectType, (LPTSTR)szTemp, ARRAYSIZE(szTemp));
  4358. SetWindowText(GetDlgItem(hDlg, stc2), szTemp);
  4359. }
  4360. //
  4361. // Make sure to do this before checking if there is a title specified.
  4362. //
  4363. if (fIsSaveAs)
  4364. {
  4365. //
  4366. // Note we can do this even if there is a hook/template.
  4367. //
  4368. InitSaveAsControls(hDlg);
  4369. // In Save As Dialog there is no need for Open As Read Only.
  4370. HideControl(hDlg, chx1);
  4371. }
  4372. if (lpOFN->lpstrTitle && *lpOFN->lpstrTitle)
  4373. {
  4374. SetWindowText(hDlg, lpOFN->lpstrTitle);
  4375. }
  4376. // BOOL Variables to check whether both the Hide Read only and Help button
  4377. // are being hidden. if so we need to readjust the dialog to reclaim the space
  4378. // occupied by these two controls
  4379. BOOL fNoReadOnly = FALSE;
  4380. BOOL fNoHelp = FALSE;
  4381. if (lpOFN->Flags & OFN_HIDEREADONLY)
  4382. {
  4383. HideControl(hDlg, chx1);
  4384. fNoReadOnly = TRUE;
  4385. }
  4386. else
  4387. {
  4388. CheckDlgButton(hDlg, chx1, (lpOFN->Flags & OFN_READONLY) ? 1 : 0);
  4389. }
  4390. if (!(lpOFN->Flags & OFN_SHOWHELP))
  4391. {
  4392. HideControl(hDlg, pshHelp);
  4393. fNoHelp = TRUE;
  4394. }
  4395. if (fNoReadOnly && fNoHelp)
  4396. {
  4397. //Readjust the dialog to reclaim space occupied by the Open as Read Only and Help Button controls
  4398. pDlgStruct->ReAdjustDialog();
  4399. }
  4400. RECT rc;
  4401. ::GetClientRect(hDlg, &rc);
  4402. //
  4403. // If sizing is enabled, then we need to create the sizing grip.
  4404. //
  4405. if (pDlgStruct->_bEnableSizing = poii->bEnableSizing)
  4406. {
  4407. pDlgStruct->_hwndGrip =
  4408. CreateWindow(TEXT("Scrollbar"),
  4409. NULL,
  4410. WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_GROUP |
  4411. WS_CLIPCHILDREN | SBS_BOTTOMALIGN | SBS_SIZEGRIP |
  4412. SBS_SIZEBOXBOTTOMRIGHTALIGN,
  4413. rc.right - g_cxGrip,
  4414. rc.bottom - g_cyGrip,
  4415. g_cxGrip,
  4416. g_cyGrip,
  4417. hDlg,
  4418. (HMENU)-1,
  4419. g_hinst,
  4420. NULL);
  4421. }
  4422. if (!pDlgStruct->CreateHookDialog(&ptSize))
  4423. {
  4424. return FALSE;
  4425. }
  4426. // Create Placebar right after Creating Hook Dialog as we need to get information
  4427. // from the Hook Procedure if any customization needs to be done
  4428. if ((pDlgStruct->_iVersion >= OPENFILEVERSION_NT5) &&
  4429. (!IsRestricted(REST_NOPLACESBAR)) && (!IS_NEW_OFN(lpOFN) || !(lpOFN->FlagsEx & OFN_EX_NOPLACESBAR))
  4430. )
  4431. {
  4432. pDlgStruct->_hwndPlacesbar = pDlgStruct->CreatePlacesbar(pDlgStruct->_hwndDlg);
  4433. }
  4434. else
  4435. {
  4436. pDlgStruct->_hwndPlacesbar = NULL;
  4437. }
  4438. GetWindowRect(pDlgStruct->_hwndDlg, &rc);
  4439. pDlgStruct->_ptMinTrack.x = rc.right - rc.left;
  4440. pDlgStruct->_ptMinTrack.y = rc.bottom - rc.top;
  4441. if (pDlgStruct->_bUseCombo)
  4442. {
  4443. HWND hwndComboBox = GetDlgItem(hDlg, cmb13);
  4444. if (hwndComboBox)
  4445. {
  4446. HWND hwndEdit = (HWND)SendMessage(hwndComboBox, CBEM_GETEDITCONTROL, 0, 0L);
  4447. AutoComplete(hwndEdit, &(pDlgStruct->_pcwd), 0);
  4448. //
  4449. // Explicitly set the focus since this is no longer the first item
  4450. // in the dialog template and it will start AutoComplete.
  4451. //
  4452. SetFocus(hwndComboBox);
  4453. }
  4454. }
  4455. else
  4456. {
  4457. HWND hwndEdit = GetDlgItem(hDlg, edt1);
  4458. if (hwndEdit)
  4459. {
  4460. AutoComplete(hwndEdit, &(pDlgStruct->_pcwd), 0);
  4461. //
  4462. // Explicitly set the focus since this is no longer the first item
  4463. // in the dialog template and it will start AutoComplete.
  4464. //
  4465. SetFocus(hwndEdit);
  4466. }
  4467. }
  4468. // Before jumping to a particular directory, Create the travel log
  4469. Create_TravelLog(&pDlgStruct->_ptlog);
  4470. // jump to the first ShellFolder
  4471. LPCTSTR lpInitialText = pDlgStruct->JumpToInitialLocation(lpOFN->lpstrInitialDir, lpOFN->lpstrFile);
  4472. // make sure we jumped somewhere.
  4473. if (!pDlgStruct->_psv)
  4474. {
  4475. //
  4476. // This would be very bad.
  4477. //
  4478. // DO NOT CALL StoreExtendedError() here! Corel Envoy relies
  4479. // on receiving exactly FNERR_INVALIDFILENAME when it passes
  4480. // an invalid filename.
  4481. //
  4482. ASSERT(GetStoredExtendedError());
  4483. return FALSE;
  4484. }
  4485. //
  4486. // Read the cabinet state. If the full title is enabled, then add
  4487. // the tooltip. Otherwise, don't bother as they obviously don't care.
  4488. //
  4489. CABINETSTATE cCabState;
  4490. //
  4491. // Will set defaults if cannot read registry.
  4492. //
  4493. ReadCabinetState(&cCabState, SIZEOF(cCabState));
  4494. if (cCabState.fFullPathTitle)
  4495. {
  4496. pDlgStruct->_hwndTips = CreateWindow(TOOLTIPS_CLASS,
  4497. NULL,
  4498. WS_POPUP | WS_GROUP | TTS_NOPREFIX,
  4499. CW_USEDEFAULT,
  4500. CW_USEDEFAULT,
  4501. CW_USEDEFAULT,
  4502. CW_USEDEFAULT,
  4503. hDlg,
  4504. NULL,
  4505. ::g_hinst,
  4506. NULL);
  4507. if (pDlgStruct->_hwndTips)
  4508. {
  4509. TOOLINFO ti;
  4510. ti.cbSize = sizeof(ti);
  4511. ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  4512. ti.hwnd = hDlg;
  4513. ti.uId = (UINT_PTR)hCtrl;
  4514. ti.hinst = NULL;
  4515. ti.lpszText = LPSTR_TEXTCALLBACK;
  4516. SendMessage(pDlgStruct->_hwndTips,
  4517. TTM_ADDTOOL,
  4518. 0,
  4519. (LPARAM)&ti);
  4520. }
  4521. }
  4522. //
  4523. // Show the window after creating the ShellView so we do not get a
  4524. // big ugly gray spot.
  4525. // if we have cached in the size of previously opened dialog then use
  4526. // the size and position of that window.
  4527. if (pDlgStruct->_bEnableSizing && (g_rcDlg.right > g_rcDlg.left))
  4528. {
  4529. ::SetWindowPos(hDlg,
  4530. NULL,
  4531. g_rcDlg.left,
  4532. g_rcDlg.top,
  4533. g_rcDlg.right - g_rcDlg.left,
  4534. g_rcDlg.bottom - g_rcDlg.top,
  4535. 0);
  4536. }
  4537. else
  4538. {
  4539. ::ShowWindow(hDlg, SW_SHOW);
  4540. ::UpdateWindow(hDlg);
  4541. }
  4542. if (lpInitialText)
  4543. {
  4544. //
  4545. // This is the one time I will show a file spec, since it would be
  4546. // too strange to have "All Files" showing in the Type box, while
  4547. // only text files are in the view.
  4548. //
  4549. pDlgStruct->SetEditFile(lpInitialText, NULL, pDlgStruct->_fShowExtensions, FALSE);
  4550. SelectEditText(hDlg);
  4551. }
  4552. return TRUE;
  4553. }
  4554. BOOL _IsValidPathComDlg(LPCTSTR pszPath)
  4555. {
  4556. TCHAR szPath[MAX_PATH];
  4557. BOOL bRet = FALSE;
  4558. if (SUCCEEDED(StringCchCopy(szPath, ARRAYSIZE(szPath), pszPath)))
  4559. {
  4560. int nFileOffset = ParseFileNew(szPath, NULL, FALSE, TRUE);
  4561. //
  4562. // Is the filename valid?
  4563. //
  4564. bRet = ((nFileOffset >= 0) || (nFileOffset == PARSE_EMPTYSTRING));
  4565. }
  4566. return bRet;
  4567. }
  4568. BOOL CFileOpenBrowser::_IsRestrictedDrive(LPCTSTR pszPath, LPCITEMIDLIST pidl)
  4569. {
  4570. TCHAR szDrivePath[5]; // Don't need much... just want a drive letter.
  4571. BOOL bRet = FALSE;
  4572. DWORD dwRest = SHRestricted(REST_NOVIEWONDRIVE);
  4573. if (dwRest)
  4574. {
  4575. // There are some drive restrictions.
  4576. // Convert pidl, if supplied, to full path.
  4577. if (pidl)
  4578. {
  4579. if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szDrivePath, ARRAYSIZE(szDrivePath), NULL)))
  4580. {
  4581. pszPath = szDrivePath;
  4582. }
  4583. }
  4584. if (pszPath)
  4585. {
  4586. int iDrive = PathGetDriveNumber(pszPath);
  4587. if (iDrive != -1)
  4588. {
  4589. // is the drive restricted
  4590. if (dwRest & (1 << iDrive))
  4591. {
  4592. bRet = TRUE;
  4593. }
  4594. }
  4595. }
  4596. }
  4597. return bRet;
  4598. }
  4599. // When the dialog first appears, we want to prevent the the pop message that appears from
  4600. // CFSFolder if you try to navigate to a drive that has been restricted due to group policy.
  4601. // So in these cases, we do the group policy check before attempting to navigate there.
  4602. void CFileOpenBrowser::JumpToLocationIfUnrestricted(LPCTSTR pszPath, LPCITEMIDLIST pidl, BOOL bTranslate)
  4603. {
  4604. if (!_IsRestrictedDrive(pszPath, pidl))
  4605. {
  4606. if (pszPath)
  4607. {
  4608. JumpToPath(pszPath, bTranslate);
  4609. }
  4610. else if (pidl)
  4611. {
  4612. JumpToIDList(pidl, bTranslate);
  4613. }
  4614. }
  4615. }
  4616. LPCTSTR CFileOpenBrowser::JumpToInitialLocation(LPCTSTR pszDir, LPTSTR pszFile)
  4617. {
  4618. //
  4619. // Check out if the filename contains a path. If so, override whatever
  4620. // is contained in pszDir. Chop off the path and put up only
  4621. // the filename.
  4622. //
  4623. TCHAR szDir[MAX_PATH];
  4624. LPCTSTR pszRet = NULL;
  4625. BOOL fFileIsTemp = PathIsTemporary(pszFile);
  4626. szDir[0] = 0;
  4627. //If we have a Directory specified then use that Directory.
  4628. if (pszDir)
  4629. {
  4630. ExpandEnvironmentStrings(pszDir, szDir, ARRAYSIZE(szDir));
  4631. }
  4632. //Check to see if the pszFile contains a Path.
  4633. if (pszFile && *pszFile)
  4634. {
  4635. // clean up the path a little
  4636. PathRemoveBlanks(pszFile);
  4637. // WARNING - this must me some kind of APPCOMPAT thing - ZekeL - 13-AUG-98
  4638. // Apps that are not UNC-aware often pass <C:\\server\share> and
  4639. // we want to change it to the prettier <\\server\share>. - raymondc
  4640. if (DBL_BSLASH(pszFile + 2) &&
  4641. (*(pszFile + 1) == CHAR_COLON))
  4642. {
  4643. StringCopyOverlap(pszFile, pszFile + 2);
  4644. }
  4645. pszRet = PathFindFileName(pszFile);
  4646. if (_IsValidPathComDlg(pszFile))
  4647. {
  4648. if (IsWild(pszRet))
  4649. {
  4650. SetCurrentFilter(pszRet);
  4651. }
  4652. if (!fFileIsTemp)
  4653. {
  4654. DWORD cch = pszRet ? (unsigned long) (pszRet-pszFile) : ARRAYSIZE(szDir);
  4655. cch = min(cch, ARRAYSIZE(szDir));
  4656. // this will null terminate for us on
  4657. // the backslash if pszRet was true
  4658. StringCchCopy(szDir, cch, pszFile); // Don't check return value. Truncation is desired in the case when pszRet != NULL
  4659. }
  4660. }
  4661. else if (!(_pOFN->Flags & OFN_NOVALIDATE))
  4662. {
  4663. // Failed validation and app wanted validation
  4664. StoreExtendedError(FNERR_INVALIDFILENAME);
  4665. return NULL;
  4666. }
  4667. else
  4668. {
  4669. // Failed validation but app suppressed validation,
  4670. // so continue onward with the "filename" part of the
  4671. // pszFile (even though it's not valid).
  4672. }
  4673. }
  4674. // if we have a directory then use that directory
  4675. if (*szDir)
  4676. {
  4677. JumpToLocationIfUnrestricted(szDir, NULL, TRUE);
  4678. }
  4679. // See if this application contains a entry in the registry for the last visited Directory
  4680. if (!_psv)
  4681. {
  4682. // Change the return value to full incoming name.
  4683. if (!fFileIsTemp)
  4684. pszRet = pszFile;
  4685. if (GetPathFromLastVisitedMRU(szDir, ARRAYSIZE(szDir)))
  4686. {
  4687. JumpToLocationIfUnrestricted(szDir, NULL, TRUE);
  4688. }
  4689. }
  4690. // Try Current Directory
  4691. if (!_psv)
  4692. {
  4693. //Does current directory contain any files that match the filter ?
  4694. if (GetCurrentDirectory(ARRAYSIZE(szDir), szDir)
  4695. && !PathIsTemporary(szDir) && FoundFilterMatch(_szLastFilter, IsVolumeLFN(NULL)))
  4696. {
  4697. //Yes. Jump to Current Directory.
  4698. JumpToLocationIfUnrestricted(szDir, NULL, TRUE);
  4699. }
  4700. }
  4701. // Try My Documents
  4702. if (!_psv)
  4703. {
  4704. LPITEMIDLIST pidl;
  4705. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl)))
  4706. {
  4707. JumpToLocationIfUnrestricted(NULL, pidl, FALSE);
  4708. ILFree(pidl);
  4709. }
  4710. }
  4711. // finally try the desktop - don't check for restriction here.
  4712. if (!_psv)
  4713. {
  4714. ITEMIDLIST idl = { 0 };
  4715. // Do not try to translate this.
  4716. JumpToIDList(&idl, FALSE);
  4717. }
  4718. // If nothing worked, then set the error code so our parent knows.
  4719. if (!_psv)
  4720. {
  4721. StoreExtendedError(CDERR_INITIALIZATION);
  4722. }
  4723. //Add the initial directory where we jumped to the travel log
  4724. if (_ptlog && _pCurrentLocation && _pCurrentLocation->pidlFull)
  4725. {
  4726. _ptlog->AddEntry(_pCurrentLocation->pidlFull);
  4727. }
  4728. return pszRet;
  4729. }
  4730. ////////////////////////////////////////////////////////////////////////////
  4731. //
  4732. // _CleanupDialog
  4733. //
  4734. // Dialog cleanup, memory deallocation.
  4735. //
  4736. ////////////////////////////////////////////////////////////////////////////
  4737. void CFileOpenBrowser::_CleanupDialog(BOOL fRet)
  4738. {
  4739. ASSERT(!_cRefCannotNavigate);
  4740. if (_pOFN->lpstrCustomFilter)
  4741. {
  4742. UINT len = lstrlen(_pOFN->lpstrCustomFilter) + 1;
  4743. UINT sCount = lstrlen(_szLastFilter);
  4744. if (_pOFN->nMaxCustFilter > sCount + len)
  4745. {
  4746. EVAL(SUCCEEDED(StringCchCopy(_pOFN->lpstrCustomFilter + len, _pOFN->nMaxCustFilter - len, _szLastFilter)));
  4747. }
  4748. }
  4749. if ((fRet == TRUE) && _hSubDlg &&
  4750. (CD_SendOKNotify(_hSubDlg, _hwndDlg, _pOFN, _pOFI) ||
  4751. CD_SendOKMsg(_hSubDlg, _pOFN, _pOFI)))
  4752. {
  4753. // Give the hook a chance to validate the file name.
  4754. return;
  4755. }
  4756. // We need to make sure the IShellBrowser is still around during
  4757. // destruction.
  4758. if (_psv)
  4759. {
  4760. _psv->DestroyViewWindow();
  4761. ATOMICRELEASE(_psv);
  4762. }
  4763. if (((_pOFN->Flags & OFN_NOCHANGEDIR) || g_bUserPressedCancel) &&
  4764. (*_szStartDir))
  4765. {
  4766. SetCurrentDirectory(_szStartDir);
  4767. }
  4768. ::EndDialog(_hwndDlg, fRet);
  4769. }
  4770. ////////////////////////////////////////////////////////////////////////////
  4771. //
  4772. // GetParentItem
  4773. //
  4774. // Given an item index in the location dropdown, get its parent item.
  4775. //
  4776. ////////////////////////////////////////////////////////////////////////////
  4777. MYLISTBOXITEM *GetParentItem(HWND hwndCombo, int *piItem)
  4778. {
  4779. int iItem = *piItem;
  4780. MYLISTBOXITEM *pItem = GetListboxItem(hwndCombo, iItem);
  4781. if (pItem)
  4782. {
  4783. for (--iItem; iItem >= 0; iItem--)
  4784. {
  4785. MYLISTBOXITEM *pPrev = GetListboxItem(hwndCombo, iItem);
  4786. if (pPrev && pPrev->cIndent < pItem->cIndent)
  4787. {
  4788. *piItem = iItem;
  4789. return (pPrev);
  4790. }
  4791. }
  4792. }
  4793. return (NULL);
  4794. }
  4795. ////////////////////////////////////////////////////////////////////////////
  4796. //
  4797. // GetFullPathEnumCB
  4798. //
  4799. ////////////////////////////////////////////////////////////////////////////
  4800. BOOL GetFullPathEnumCB(
  4801. CFileOpenBrowser *that,
  4802. LPCITEMIDLIST pidl,
  4803. LPARAM lParam)
  4804. {
  4805. if (pidl)
  4806. {
  4807. LPITEMIDLIST pidlFull = ILCombine(that->_pCurrentLocation->pidlFull, pidl);
  4808. if (pidlFull)
  4809. {
  4810. SHGetPathFromIDList(pidlFull, (LPTSTR)lParam);
  4811. ILFree(pidlFull);
  4812. }
  4813. return FALSE;
  4814. }
  4815. return TRUE;
  4816. }
  4817. ////////////////////////////////////////////////////////////////////////////
  4818. //
  4819. // CFileOpenBrowser::GetFullPath
  4820. //
  4821. // Calculate the full path to the selected object in the view.
  4822. //
  4823. ////////////////////////////////////////////////////////////////////////////
  4824. void CFileOpenBrowser::GetFullPath(
  4825. LPTSTR pszBuf)
  4826. {
  4827. *pszBuf = CHAR_NULL;
  4828. EnumItemObjects(SVGIO_SELECTION, GetFullPathEnumCB, (LPARAM)pszBuf);
  4829. }
  4830. ////////////////////////////////////////////////////////////////////////////
  4831. //
  4832. // CFileOpenBrowser::RemoveOldPath
  4833. //
  4834. // Removes old path elements from the location dropdown. *piNewSel is the
  4835. // listbox index of the leaf item which the caller wants to save. All non-
  4836. // permanent items that are not ancestors of that item are deleted. The
  4837. // index is updated appropriately if any items before it are deleted.
  4838. //
  4839. ////////////////////////////////////////////////////////////////////////////
  4840. void CFileOpenBrowser::RemoveOldPath(
  4841. int *piNewSel)
  4842. {
  4843. HWND hwndCombo = ::GetDlgItem(_hwndDlg, cmb2);
  4844. int iStart = *piNewSel;
  4845. int iItem;
  4846. UINT cIndent = 0;
  4847. int iSubOnDel = 0;
  4848. //
  4849. // Flush all non-permanent non-ancestor items before this one.
  4850. //
  4851. for (iItem = ComboBox_GetCount(hwndCombo) - 1; iItem >= 0; --iItem)
  4852. {
  4853. MYLISTBOXITEM *pItem = GetListboxItem(hwndCombo, iItem);
  4854. if (iItem == iStart)
  4855. {
  4856. //
  4857. // Begin looking for ancestors and adjusting the sel position.
  4858. //
  4859. iSubOnDel = 1;
  4860. cIndent = pItem->cIndent;
  4861. continue;
  4862. }
  4863. if (pItem->cIndent < cIndent)
  4864. {
  4865. //
  4866. // We went back a level, so this must be an ancestor of the
  4867. // selected item.
  4868. //
  4869. cIndent = pItem->cIndent;
  4870. continue;
  4871. }
  4872. //
  4873. // Make sure to check this after adjusting cIndent.
  4874. //
  4875. if (pItem->dwFlags & MLBI_PERMANENT)
  4876. {
  4877. continue;
  4878. }
  4879. SendMessage(hwndCombo, CB_DELETESTRING, iItem, NULL);
  4880. pItem->Release();
  4881. *piNewSel -= iSubOnDel;
  4882. }
  4883. }
  4884. ////////////////////////////////////////////////////////////////////////////
  4885. //
  4886. // FindLocation
  4887. //
  4888. // Given a listbox item, find the index.
  4889. // Just a linear search, but we shouldn't have more than ~10-20 items.
  4890. //
  4891. ////////////////////////////////////////////////////////////////////////////
  4892. int FindLocation(
  4893. HWND hwndCombo,
  4894. MYLISTBOXITEM *pFindItem)
  4895. {
  4896. int iItem;
  4897. for (iItem = ComboBox_GetCount(hwndCombo) - 1; iItem >= 0; --iItem)
  4898. {
  4899. MYLISTBOXITEM *pItem = GetListboxItem(hwndCombo, iItem);
  4900. if (pItem == pFindItem)
  4901. {
  4902. break;
  4903. }
  4904. }
  4905. return (iItem);
  4906. }
  4907. ////////////////////////////////////////////////////////////////////////////
  4908. //
  4909. // CFileOpenBrowser::OnSelChange
  4910. //
  4911. // Process the selection change in the location dropdown.
  4912. //
  4913. // Chief useful feature is that it removes the items for the old path.
  4914. // Returns TRUE only if it was possible to switch to the specified item.
  4915. //
  4916. ////////////////////////////////////////////////////////////////////////////
  4917. BOOL CFileOpenBrowser::OnSelChange(
  4918. int iItem,
  4919. BOOL bForceUpdate)
  4920. {
  4921. HWND hwndCombo = GetDlgItem(_hwndDlg, cmb2);
  4922. BOOL bRet = TRUE;
  4923. if (iItem == -1)
  4924. {
  4925. iItem = (int) SendMessage(hwndCombo, CB_GETCURSEL, NULL, NULL);
  4926. }
  4927. MYLISTBOXITEM *pNewLocation = GetListboxItem(hwndCombo, iItem);
  4928. MYLISTBOXITEM *pOldLocation = _pCurrentLocation;
  4929. BOOL bFirstTry = TRUE;
  4930. BOOL bSwitchedBack = FALSE;
  4931. if (bForceUpdate || (pNewLocation != pOldLocation))
  4932. {
  4933. FOLDERSETTINGS fs;
  4934. if (_psv)
  4935. {
  4936. _psv->GetCurrentInfo(&fs);
  4937. }
  4938. else
  4939. {
  4940. fs.ViewMode = FVM_LIST;
  4941. fs.fFlags = _pOFN->Flags & OFN_ALLOWMULTISELECT ? 0 : FWF_SINGLESEL;
  4942. }
  4943. // we always want the recent folder to come up
  4944. // in details mode
  4945. // We also want the My Pictures folder and it's subfolders to comeup in ThumbView.
  4946. // So, let's detect if the current and new locations are any of these special folders.
  4947. LOCTYPE NewLocType = (pNewLocation ? _GetLocationType(pNewLocation) : LOCTYPE_OTHERS);
  4948. LOCTYPE CurLocType = (_pCurrentLocation ? _GetLocationType(_pCurrentLocation) : LOCTYPE_OTHERS);
  4949. const SHELLVIEWID *pvid = NULL; //Most of the time this will continue to be null;
  4950. SHELLVIEWID vidCurrent = {0};
  4951. BOOL fUseDefaultView = FALSE;
  4952. switch (NewLocType)
  4953. {
  4954. case LOCTYPE_MYPICTURES_FOLDER:
  4955. if (CurLocType == LOCTYPE_MYPICTURES_FOLDER)
  4956. {
  4957. IShellView2 *psv2;
  4958. //We need to get the current pvid
  4959. //Note: the end-user could have changed this view.
  4960. pvid = &VID_Thumbnails; //Assume this by default.
  4961. if (SUCCEEDED(_psv->QueryInterface(IID_PPV_ARG(IShellView2, &psv2))))
  4962. {
  4963. if (SUCCEEDED(psv2->GetView(&vidCurrent, SV2GV_CURRENTVIEW)))
  4964. pvid = &vidCurrent;
  4965. psv2->Release();
  4966. }
  4967. }
  4968. else
  4969. {
  4970. //We are moving to My pictures folder or sub-folder; set the thumb nail view.
  4971. pvid = &VID_Thumbnails;
  4972. //If we are moving from other folders, save the ViewMode.
  4973. if (CurLocType == LOCTYPE_OTHERS)
  4974. {
  4975. _CachedViewMode = fs.ViewMode;
  4976. _fCachedViewFlags = fs.fFlags;
  4977. }
  4978. }
  4979. break;
  4980. case LOCTYPE_RECENT_FOLDER:
  4981. //We are moving to Recent folder.
  4982. if (CurLocType == LOCTYPE_OTHERS)
  4983. {
  4984. _CachedViewMode = fs.ViewMode;
  4985. _fCachedViewFlags = fs.fFlags;
  4986. }
  4987. fs.ViewMode = FVM_DETAILS;
  4988. break;
  4989. case LOCTYPE_WIA_FOLDER:
  4990. if (CurLocType == LOCTYPE_OTHERS)
  4991. {
  4992. _CachedViewMode = fs.ViewMode;
  4993. _fCachedViewFlags = fs.fFlags;
  4994. }
  4995. // ask view for default view for WIA extentions
  4996. fUseDefaultView = TRUE;
  4997. break;
  4998. case LOCTYPE_OTHERS:
  4999. //Check if we are coming from Recent, My Pictures, or WIA folders,
  5000. // and restore the viewmode we had before that.
  5001. if (CurLocType != LOCTYPE_OTHERS)
  5002. {
  5003. fs.ViewMode = _CachedViewMode;
  5004. fs.fFlags = _fCachedViewFlags;
  5005. }
  5006. break;
  5007. }
  5008. _iCurrentLocation = iItem;
  5009. _pCurrentLocation = pNewLocation;
  5010. OnSelChange_TryAgain:
  5011. if (!_pCurrentLocation || FAILED(SwitchView(_pCurrentLocation->GetShellFolder(),
  5012. _pCurrentLocation->pidlFull,
  5013. &fs,
  5014. pvid,
  5015. fUseDefaultView)))
  5016. {
  5017. //
  5018. // We could not create the view for this location.
  5019. //
  5020. bRet = FALSE;
  5021. //
  5022. // Try the previous folder.
  5023. //
  5024. if (bFirstTry)
  5025. {
  5026. bFirstTry = FALSE;
  5027. _pCurrentLocation = pOldLocation;
  5028. int iOldItem = FindLocation(hwndCombo, pOldLocation);
  5029. if (iOldItem >= 0)
  5030. {
  5031. _iCurrentLocation = iOldItem;
  5032. ComboBox_SetCurSel(hwndCombo, _iCurrentLocation);
  5033. if (_psv)
  5034. {
  5035. bSwitchedBack = TRUE;
  5036. goto SwitchedBack;
  5037. }
  5038. else
  5039. {
  5040. goto OnSelChange_TryAgain;
  5041. }
  5042. }
  5043. }
  5044. //
  5045. // Try the parent of the old item.
  5046. //
  5047. if (_iCurrentLocation)
  5048. {
  5049. _pCurrentLocation = GetParentItem(hwndCombo, &_iCurrentLocation);
  5050. if (_pCurrentLocation)
  5051. {
  5052. ComboBox_SetCurSel(hwndCombo, _iCurrentLocation);
  5053. goto OnSelChange_TryAgain;
  5054. }
  5055. }
  5056. //
  5057. // We cannot create the Desktop view. I think we are in
  5058. // real trouble. We had better bail out.
  5059. //
  5060. StoreExtendedError(CDERR_DIALOGFAILURE);
  5061. _CleanupDialog(FALSE);
  5062. return FALSE;
  5063. }
  5064. //if _iCurrentLocation is _iNodeDesktop then it means we are at Desktop so disable the IDC_PARENT button
  5065. ::SendMessage(_hwndToolbar,
  5066. TB_SETSTATE,
  5067. IDC_PARENT,
  5068. ((_iCurrentLocation == _iNodeDesktop) || (_iCurrentLocation == 0)) ? 0 :TBSTATE_ENABLED);
  5069. if (_IsSaveContainer(_pCurrentLocation->dwAttrs))
  5070. {
  5071. _pCurrentLocation->SwitchCurrentDirectory(_pcwd);
  5072. }
  5073. TCHAR szFile[MAX_PATH + 1];
  5074. int nFileOffset;
  5075. //
  5076. // We've changed folders; we'd better strip whatever is in the edit
  5077. // box down to the file name.
  5078. //
  5079. if (_bUseCombo)
  5080. {
  5081. HWND hwndEdit = (HWND)SendMessage(GetDlgItem(_hwndDlg, cmb13), CBEM_GETEDITCONTROL, 0, 0L);
  5082. GetWindowText(hwndEdit, szFile, ARRAYSIZE(szFile));
  5083. }
  5084. else
  5085. {
  5086. GetDlgItemText(_hwndDlg, edt1, szFile, ARRAYSIZE(szFile));
  5087. }
  5088. nFileOffset = ParseFileNew(szFile, NULL, FALSE, TRUE);
  5089. if (nFileOffset > 0 && !IsDirectory(szFile))
  5090. {
  5091. //
  5092. // The user may have typed an extension, so make sure to show it.
  5093. //
  5094. SetEditFile(szFile + nFileOffset, NULL, TRUE);
  5095. }
  5096. SetSaveButton(iszFileSaveButton);
  5097. SwitchedBack:
  5098. RemoveOldPath(&_iCurrentLocation);
  5099. }
  5100. if (!bSwitchedBack && _hSubDlg)
  5101. {
  5102. CD_SendFolderChangeNotify(_hSubDlg, _hwndDlg, _pOFN, _pOFI);
  5103. }
  5104. return (bRet);
  5105. }
  5106. ////////////////////////////////////////////////////////////////////////////
  5107. //
  5108. // CFileOpenBrowser::OnDotDot
  5109. //
  5110. // Process the open-parent-folder button on the toolbar.
  5111. //
  5112. ////////////////////////////////////////////////////////////////////////////
  5113. void CFileOpenBrowser::OnDotDot()
  5114. {
  5115. HWND hwndCombo = GetDlgItem(_hwndDlg, cmb2);
  5116. int iItem = ComboBox_GetCurSel(hwndCombo);
  5117. MYLISTBOXITEM *pItem = GetParentItem(hwndCombo, &iItem);
  5118. SendMessage(hwndCombo, CB_SETCURSEL, iItem, NULL);
  5119. //
  5120. // Delete old path from combo.
  5121. //
  5122. OnSelChange();
  5123. UpdateNavigation();
  5124. }
  5125. ////////////////////////////////////////////////////////////////////////////
  5126. //
  5127. // DblClkEnumCB
  5128. //
  5129. ////////////////////////////////////////////////////////////////////////////
  5130. #define PIDL_NOTHINGSEL (LPCITEMIDLIST)0
  5131. #define PIDL_MULTIPLESEL (LPCITEMIDLIST)-1
  5132. #define PIDL_FOLDERSEL (LPCITEMIDLIST)-2
  5133. BOOL DblClkEnumCB(
  5134. CFileOpenBrowser *that,
  5135. LPCITEMIDLIST pidl,
  5136. LPARAM lParam)
  5137. {
  5138. MYLISTBOXITEM *pLoc = that->_pCurrentLocation;
  5139. LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)lParam;
  5140. if (!pidl)
  5141. {
  5142. pidl = *ppidl;
  5143. if (pidl == PIDL_NOTHINGSEL)
  5144. {
  5145. //
  5146. // Nothing selected.
  5147. //
  5148. return FALSE;
  5149. }
  5150. if (pidl == PIDL_MULTIPLESEL)
  5151. {
  5152. //
  5153. // More than one thing selected.
  5154. //
  5155. return FALSE;
  5156. }
  5157. // check if the pidl is a container (ie, a folder)
  5158. if (IsContainer(that->_psfCurrent, pidl))
  5159. {
  5160. LPITEMIDLIST pidlDest = ILCombine(pLoc->pidlFull,pidl);
  5161. if (pidlDest)
  5162. {
  5163. that->JumpToIDList(pidlDest);
  5164. SHFree(pidlDest);
  5165. }
  5166. *ppidl = PIDL_FOLDERSEL;
  5167. }
  5168. else if (IsLink(that->_psfCurrent,pidl))
  5169. {
  5170. //
  5171. // This link might be pointing to a folder in which case
  5172. // we want to go ahead and open it. If the link points
  5173. // to a file then its taken care of in ProcessEdit command.
  5174. //
  5175. SHTCUTINFO info;
  5176. LPITEMIDLIST pidlLinkTarget = NULL;
  5177. info.dwAttr = SFGAO_FOLDER;
  5178. info.fReSolve = FALSE;
  5179. info.pszLinkFile = NULL;
  5180. info.cchFile = 0;
  5181. info.ppidl = &pidlLinkTarget;
  5182. //psf can be NULL in which case ResolveLink uses _psfCurrent IShellFolder
  5183. if (SUCCEEDED(that->ResolveLink(pidl, &info, that->_psfCurrent)))
  5184. {
  5185. if (info.dwAttr & SFGAO_FOLDER)
  5186. {
  5187. that->JumpToIDList(pidlLinkTarget);
  5188. *ppidl = PIDL_FOLDERSEL;
  5189. }
  5190. Pidl_Set(&pidlLinkTarget, NULL);
  5191. }
  5192. }
  5193. return FALSE;
  5194. }
  5195. if (*ppidl)
  5196. {
  5197. //
  5198. // More than one thing selected.
  5199. //
  5200. *ppidl = PIDL_MULTIPLESEL;
  5201. return FALSE;
  5202. }
  5203. *ppidl = pidl;
  5204. return TRUE;
  5205. }
  5206. ////////////////////////////////////////////////////////////////////////////
  5207. //
  5208. // CFileOpenBrowser::OnDblClick
  5209. //
  5210. // Process a double-click in the view control, either by choosing the
  5211. // selected non-container object or by opening the selected container.
  5212. //
  5213. ////////////////////////////////////////////////////////////////////////////
  5214. void CFileOpenBrowser::OnDblClick(
  5215. BOOL bFromOKButton)
  5216. {
  5217. LPCITEMIDLIST pidlFirst = PIDL_NOTHINGSEL;
  5218. //if we have a saved pidl then use it instead
  5219. if (_pidlSelection && _ProcessPidlSelection())
  5220. {
  5221. return;
  5222. }
  5223. if (_psv)
  5224. {
  5225. EnumItemObjects(SVGIO_SELECTION, DblClkEnumCB, (LPARAM)&pidlFirst);
  5226. }
  5227. if (pidlFirst == PIDL_NOTHINGSEL)
  5228. {
  5229. //
  5230. // Nothing selected.
  5231. //
  5232. if (bFromOKButton)
  5233. {
  5234. //
  5235. // This means we got an IDOK when the focus was in the view,
  5236. // but nothing was selected. Let's get the edit text and go
  5237. // from there.
  5238. //
  5239. ProcessEdit();
  5240. }
  5241. }
  5242. else if (pidlFirst != PIDL_FOLDERSEL)
  5243. {
  5244. //
  5245. // This will change the edit box, but that's OK, since it probably
  5246. // already has. This should take care of files with no extension.
  5247. //
  5248. SelFocusChange(TRUE);
  5249. //
  5250. // This part will take care of resolving links.
  5251. //
  5252. ProcessEdit();
  5253. }
  5254. }
  5255. ////////////////////////////////////////////////////////////////////////////
  5256. //
  5257. // CFileOpenBrowser::JumpToPath
  5258. //
  5259. // Refocus the entire dialog on a different directory.
  5260. //
  5261. ////////////////////////////////////////////////////////////////////////////
  5262. BOOL CFileOpenBrowser::JumpToPath(LPCTSTR pszDirectory, BOOL bTranslate)
  5263. {
  5264. TCHAR szTemp[MAX_PATH + 1];
  5265. TCHAR szCurDir[MAX_PATH + 1];
  5266. BOOL bRet = FALSE;
  5267. //
  5268. // This should do the whole job of canonicalizing the directory.
  5269. //
  5270. GetCurrentDirectory(ARRAYSIZE(szCurDir), szCurDir);
  5271. if (PathCombine(szTemp, szCurDir, pszDirectory))
  5272. {
  5273. LPITEMIDLIST pidlNew = ILCreateFromPath(szTemp);
  5274. if (pidlNew)
  5275. {
  5276. //
  5277. // Need to make sure the pidl points to a folder. If not, then remove
  5278. // items from the end until we find one that is.
  5279. // This must be done before the translation.
  5280. //
  5281. DWORD dwAttrib;
  5282. do
  5283. {
  5284. dwAttrib = SFGAO_FOLDER;
  5285. SHGetAttributesOf(pidlNew, &dwAttrib);
  5286. if (!(dwAttrib & SFGAO_FOLDER))
  5287. {
  5288. ILRemoveLastID(pidlNew);
  5289. }
  5290. } while(!(dwAttrib & SFGAO_FOLDER) && !ILIsEmpty(pidlNew));
  5291. if (!(dwAttrib & SFGAO_FOLDER))
  5292. {
  5293. bRet = FALSE;
  5294. }
  5295. else
  5296. {
  5297. bRet = JumpToIDList(pidlNew, bTranslate);
  5298. }
  5299. SHFree(pidlNew);
  5300. }
  5301. }
  5302. return bRet;
  5303. }
  5304. ////////////////////////////////////////////////////////////////////////////
  5305. //
  5306. // CFileOpenBrowser::JumpTOIDList
  5307. //
  5308. // Refocus the entire dialog on a different IDList.
  5309. //
  5310. // Parameter:
  5311. // bTranslate specifies whether the given pidl should be translated to
  5312. // logical pidl
  5313. // bAddToNavStack specifies whether the pidl given for jumping should be
  5314. // added to the back/forward navigation stack
  5315. //
  5316. ////////////////////////////////////////////////////////////////////////////
  5317. BOOL CFileOpenBrowser::JumpToIDList(
  5318. LPCITEMIDLIST pidlNew,
  5319. BOOL bTranslate,
  5320. BOOL bAddToNavStack)
  5321. {
  5322. LPITEMIDLIST pidlLog = NULL;
  5323. if (bTranslate)
  5324. {
  5325. //
  5326. // Translate IDList's on the Desktop into the appropriate
  5327. // logical IDList.
  5328. //
  5329. pidlLog = SHLogILFromFSIL(pidlNew);
  5330. if (pidlLog)
  5331. {
  5332. pidlNew = pidlLog;
  5333. }
  5334. }
  5335. //
  5336. // Find the entry in the location dropdown that is the closest parent
  5337. // to the new location.
  5338. //
  5339. HWND hwndCombo = ::GetDlgItem(_hwndDlg, cmb2);
  5340. MYLISTBOXITEM *pBestParent = GetListboxItem(hwndCombo, 0);
  5341. int iBestParent = 0;
  5342. LPCITEMIDLIST pidlRelative = pidlNew;
  5343. UINT cIndent = 0;
  5344. BOOL fExact = FALSE;
  5345. for (UINT iItem = 0; ; iItem++)
  5346. {
  5347. MYLISTBOXITEM *pNextItem = GetListboxItem(hwndCombo, iItem);
  5348. if (pNextItem == NULL)
  5349. {
  5350. break;
  5351. }
  5352. if (pNextItem->cIndent != cIndent)
  5353. {
  5354. //
  5355. // Not the depth we want.
  5356. //
  5357. continue;
  5358. }
  5359. if (ILIsEqual(pNextItem->pidlFull, pidlNew))
  5360. {
  5361. // Never treat FTP Pidls as Equal because the username/password may
  5362. // have changed so we need to do the navigation. The two pidls
  5363. // still pass ILIsEqual() because the server name is the same.
  5364. // This is required for a different back compat bug.
  5365. if (!ILIsFTP(pidlNew))
  5366. fExact = TRUE;
  5367. break;
  5368. }
  5369. LPCITEMIDLIST pidlChild = ILFindChild(pNextItem->pidlFull, pidlNew);
  5370. if (pidlChild != NULL)
  5371. {
  5372. pBestParent = pNextItem;
  5373. iBestParent = iItem;
  5374. cIndent++;
  5375. pidlRelative = pidlChild;
  5376. }
  5377. }
  5378. //
  5379. // The path provided might have matched an existing item exactly. In
  5380. // that case, just select the item.
  5381. //
  5382. if (fExact)
  5383. {
  5384. goto FoundIDList;
  5385. }
  5386. //
  5387. // Now, pBestParent is the closest parent to the item, iBestParent is
  5388. // its index, and cIndent is the next appropriate indent level. Begin
  5389. // creating new items for the rest of the path.
  5390. //
  5391. iBestParent++; // begin inserting after parent item
  5392. for (; ;)
  5393. {
  5394. LPITEMIDLIST pidlFirst = ILCloneFirst(pidlRelative);
  5395. if (pidlFirst == NULL)
  5396. {
  5397. break;
  5398. }
  5399. MYLISTBOXITEM *pNewItem = new MYLISTBOXITEM();
  5400. if (pNewItem)
  5401. {
  5402. if (!pNewItem->Init(GetDlgItem(_hwndDlg, cmb2),
  5403. pBestParent,
  5404. pBestParent->GetShellFolder(),
  5405. pidlFirst,
  5406. cIndent,
  5407. MLBI_PSFFROMPARENT,
  5408. _pScheduler))
  5409. {
  5410. pNewItem->Release();
  5411. pNewItem = NULL;
  5412. //iBestParent is off by 1 in error case . Correct it
  5413. iBestParent--;
  5414. break;
  5415. }
  5416. }
  5417. else
  5418. {
  5419. //iBestParent is off by 1 in error case . Correct it
  5420. iBestParent--;
  5421. break;
  5422. }
  5423. GetViewItemText(pBestParent->psfSub, pidlFirst, _szBuf, ARRAYSIZE(_szBuf), SHGDN_NORMAL);
  5424. InsertItem(hwndCombo, iBestParent, pNewItem, _szBuf);
  5425. SHFree(pidlFirst);
  5426. pidlRelative = ILGetNext(pidlRelative);
  5427. if (ILIsEmpty(pidlRelative))
  5428. {
  5429. break;
  5430. }
  5431. cIndent++; // next one is indented one more level
  5432. iBestParent++; // and inserted after this one
  5433. pBestParent = pNewItem; // and is a child of the one we just inserted
  5434. }
  5435. iItem = iBestParent;
  5436. FoundIDList:
  5437. if (pidlLog)
  5438. {
  5439. SHFree(pidlLog);
  5440. }
  5441. SendMessage(hwndCombo, CB_SETCURSEL, iItem, NULL);
  5442. BOOL bRet = OnSelChange(iItem, TRUE);
  5443. //Update our Navigation stack
  5444. if (bRet && bAddToNavStack)
  5445. {
  5446. UpdateNavigation();
  5447. }
  5448. //We naviagated to a new location so invalidate the cached Pidl
  5449. Pidl_Set(&_pidlSelection,NULL);
  5450. return bRet;
  5451. }
  5452. ////////////////////////////////////////////////////////////////////////////
  5453. //
  5454. // CFileOpenBrowser::ViewCommand
  5455. //
  5456. // Process the new-folder button on the toolbar.
  5457. //
  5458. ////////////////////////////////////////////////////////////////////////////
  5459. void CFileOpenBrowser::ViewCommand(
  5460. UINT uIndex)
  5461. {
  5462. IContextMenu *pcm;
  5463. if (SUCCEEDED(_psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARG(IContextMenu, &pcm))))
  5464. {
  5465. CMINVOKECOMMANDINFOEX ici = {0};
  5466. ici.cbSize = sizeof(ici);
  5467. ici.fMask = 0L;
  5468. ici.hwnd = _hwndDlg;
  5469. ici.lpVerb = ::c_szCommandsA[uIndex];
  5470. ici.lpParameters = NULL;
  5471. ici.lpDirectory = NULL;
  5472. ici.nShow = SW_NORMAL;
  5473. ici.lpParametersW = NULL;
  5474. ici.lpDirectoryW = NULL;
  5475. ici.lpVerbW = ::c_szCommandsW[uIndex];
  5476. ici.fMask |= CMIC_MASK_UNICODE;
  5477. IObjectWithSite *pObjSite = NULL;
  5478. if (SUCCEEDED(pcm->QueryInterface(IID_IObjectWithSite, (void**)&pObjSite)))
  5479. {
  5480. pObjSite->SetSite(SAFECAST(_psv,IShellView*));
  5481. }
  5482. HMENU hmContext = CreatePopupMenu();
  5483. pcm->QueryContextMenu(hmContext, 0, 1, 256, 0);
  5484. pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)(&ici));
  5485. if (pObjSite)
  5486. {
  5487. pObjSite->SetSite(NULL);
  5488. pObjSite->Release();
  5489. }
  5490. DestroyMenu(hmContext);
  5491. pcm->Release();
  5492. }
  5493. }
  5494. //
  5495. HRESULT CFileOpenBrowser::ResolveLink(LPCITEMIDLIST pidl, PSHTCUTINFO pinfo, IShellFolder *psf)
  5496. {
  5497. BOOL fSetPidl = TRUE;
  5498. //Do we have IShellFolder passed to us ?
  5499. if (!psf)
  5500. {
  5501. //No use our current shell folder.
  5502. psf = _psfCurrent;
  5503. }
  5504. //Get the IShellLink interface pointer corresponding to given file
  5505. IShellLink *psl;
  5506. HRESULT hres = psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IShellLink, 0, &psl));
  5507. if (SUCCEEDED(hres))
  5508. {
  5509. //Resolve the link
  5510. if (pinfo->fReSolve)
  5511. {
  5512. hres = psl->Resolve(_hwndDlg, 0);
  5513. //If the resolve failed then we can't get correct pidl
  5514. if (hres == S_FALSE)
  5515. {
  5516. fSetPidl = FALSE;
  5517. }
  5518. }
  5519. if (SUCCEEDED(hres))
  5520. {
  5521. LPITEMIDLIST pidl;
  5522. if (SUCCEEDED(psl->GetIDList(&pidl)) && pidl)
  5523. {
  5524. if (pinfo->dwAttr)
  5525. hres = SHGetAttributesOf(pidl, &pinfo->dwAttr);
  5526. if (SUCCEEDED(hres) && pinfo->pszLinkFile)
  5527. {
  5528. // caller wants the path, this may be empty
  5529. hres = psl->GetPath(pinfo->pszLinkFile, pinfo->cchFile, 0, 0);
  5530. }
  5531. if (pinfo->ppidl && fSetPidl)
  5532. *(pinfo->ppidl) = pidl;
  5533. else
  5534. ILFree(pidl);
  5535. }
  5536. else
  5537. hres = E_FAIL; // gota have a pidl
  5538. }
  5539. psl->Release();
  5540. }
  5541. if (FAILED(hres))
  5542. {
  5543. if (pinfo->pszLinkFile)
  5544. *pinfo->pszLinkFile = 0;
  5545. if (pinfo->ppidl && *pinfo->ppidl)
  5546. {
  5547. ILFree(*pinfo->ppidl);
  5548. *pinfo->ppidl = NULL;
  5549. }
  5550. pinfo->dwAttr = 0;
  5551. }
  5552. return hres;
  5553. }
  5554. //
  5555. // This function checks to see if the pidl given is a link and if so resolves the
  5556. // link
  5557. // PARAMETERS :
  5558. //
  5559. // LPCITEMIDLIST pidl - the pidl which we want to check for link
  5560. // LPTSTR pszLinkFile - if the pidl points to a link then this contains the resolved file
  5561. // name
  5562. // UINT cchFile - size of the buffer pointed by the pszLinkFile
  5563. //
  5564. // RETURN VALUE :
  5565. // returns TRUE if the pidl is link and was able to resolve the link successfully
  5566. // returns FALSE if the pidl is not link or if the link was not able to resolve successfully.
  5567. // In this case pszLinkFile and pfd are not valid.
  5568. BOOL CFileOpenBrowser::GetLinkStatus(LPCITEMIDLIST pidl, PSHTCUTINFO pinfo)
  5569. {
  5570. if (IsLink(_psfCurrent, pidl))
  5571. {
  5572. return SUCCEEDED(ResolveLink(pidl, pinfo));
  5573. }
  5574. return FALSE;
  5575. }
  5576. ////////////////////////////////////////////////////////////////////////////
  5577. //
  5578. // CFileOpenBrowser::LinkMatchSpec
  5579. //
  5580. ////////////////////////////////////////////////////////////////////////////
  5581. BOOL CFileOpenBrowser::LinkMatchSpec(LPCITEMIDLIST pidl, LPCTSTR pszSpec)
  5582. {
  5583. TCHAR szFile[MAX_PATH];
  5584. SHTCUTINFO info;
  5585. info.dwAttr = SFGAO_FOLDER;
  5586. info.fReSolve = FALSE;
  5587. info.pszLinkFile = szFile;
  5588. info.cchFile = ARRAYSIZE(szFile);
  5589. info.ppidl = NULL;
  5590. if (GetLinkStatus(pidl, &info))
  5591. {
  5592. if ((info.dwAttr & SFGAO_FOLDER) ||
  5593. (szFile[0] && PathMatchSpec(szFile, pszSpec)))
  5594. {
  5595. return TRUE;
  5596. }
  5597. }
  5598. return FALSE;
  5599. }
  5600. ////////////////////////////////////////////////////////////////////////////
  5601. //
  5602. // MeasureDriveItems
  5603. //
  5604. // Standard owner-draw code for the location dropdown.
  5605. //
  5606. ////////////////////////////////////////////////////////////////////////////
  5607. #define MINIDRIVE_MARGIN 4
  5608. #define MINIDRIVE_WIDTH (g_cxSmIcon)
  5609. #define MINIDRIVE_HEIGHT (g_cySmIcon)
  5610. #define DRIVELIST_BORDER 3
  5611. void MeasureDriveItems(
  5612. HWND hwndDlg,
  5613. MEASUREITEMSTRUCT *lpmi)
  5614. {
  5615. HDC hdc;
  5616. HFONT hfontOld;
  5617. int dyDriveItem;
  5618. SIZE siz;
  5619. hdc = GetDC(NULL);
  5620. hfontOld = (HFONT)SelectObject(hdc,
  5621. (HFONT)SendMessage(hwndDlg,
  5622. WM_GETFONT,
  5623. 0,
  5624. 0));
  5625. GetTextExtentPoint(hdc, TEXT("W"), 1, &siz);
  5626. dyDriveItem = siz.cy;
  5627. if (hfontOld)
  5628. {
  5629. SelectObject(hdc, hfontOld);
  5630. }
  5631. ReleaseDC(NULL, hdc);
  5632. dyDriveItem += DRIVELIST_BORDER;
  5633. if (dyDriveItem < MINIDRIVE_HEIGHT)
  5634. {
  5635. dyDriveItem = MINIDRIVE_HEIGHT;
  5636. }
  5637. lpmi->itemHeight = dyDriveItem;
  5638. }
  5639. ////////////////////////////////////////////////////////////////////////////
  5640. //
  5641. // CFileOpenBrowser::PaintDriveLine
  5642. //
  5643. ////////////////////////////////////////////////////////////////////////////
  5644. void CFileOpenBrowser::PaintDriveLine(
  5645. DRAWITEMSTRUCT *lpdis)
  5646. {
  5647. HDC hdc = lpdis->hDC;
  5648. RECT rc = lpdis->rcItem;
  5649. TCHAR szText[MAX_DRIVELIST_STRING_LEN];
  5650. int offset = 0;
  5651. int xString, yString, xMiniDrive, dyString;
  5652. SIZE siz;
  5653. if ((int)lpdis->itemID < 0)
  5654. {
  5655. return;
  5656. }
  5657. MYLISTBOXITEM *pItem = GetListboxItem(lpdis->hwndItem, lpdis->itemID);
  5658. if (pItem)
  5659. {
  5660. // Note: don't need to call CB_GETLBTEXTLEN, we know our buffer is big enough.
  5661. // The items in the combobox passed through InsertItem()
  5662. ::SendDlgItemMessage(_hwndDlg,
  5663. cmb2,
  5664. CB_GETLBTEXT,
  5665. lpdis->itemID,
  5666. (LPARAM)szText);
  5667. //
  5668. // Before doing anything, calculate the actual rectangle for the text.
  5669. //
  5670. if (!(lpdis->itemState & ODS_COMBOBOXEDIT))
  5671. {
  5672. offset = 10 * pItem->cIndent;
  5673. }
  5674. xMiniDrive = rc.left + DRIVELIST_BORDER + offset;
  5675. rc.left = xString = xMiniDrive + MINIDRIVE_WIDTH + MINIDRIVE_MARGIN;
  5676. GetTextExtentPoint(hdc, szText, lstrlen(szText), &siz);
  5677. dyString = siz.cy;
  5678. rc.right = rc.left + siz.cx;
  5679. rc.left--;
  5680. rc.right++;
  5681. if (lpdis->itemAction != ODA_FOCUS)
  5682. {
  5683. FillRect(hdc, &lpdis->rcItem, GetSysColorBrush(COLOR_WINDOW));
  5684. yString = rc.top + (rc.bottom - rc.top - dyString) / 2;
  5685. SetBkColor(hdc,
  5686. GetSysColor((lpdis->itemState & ODS_SELECTED)
  5687. ? COLOR_HIGHLIGHT
  5688. : COLOR_WINDOW));
  5689. SetTextColor(hdc,
  5690. GetSysColor((lpdis->itemState & ODS_SELECTED)
  5691. ? COLOR_HIGHLIGHTTEXT
  5692. : COLOR_WINDOWTEXT));
  5693. if ((lpdis->itemState & ODS_COMBOBOXEDIT) &&
  5694. (rc.right > lpdis->rcItem.right))
  5695. {
  5696. //
  5697. // Need to clip as user does not!
  5698. //
  5699. rc.right = lpdis->rcItem.right;
  5700. ExtTextOut(hdc,
  5701. xString,
  5702. yString,
  5703. ETO_OPAQUE | ETO_CLIPPED,
  5704. &rc,
  5705. szText,
  5706. lstrlen(szText),
  5707. NULL);
  5708. }
  5709. else
  5710. {
  5711. ExtTextOut(hdc,
  5712. xString,
  5713. yString,
  5714. ETO_OPAQUE,
  5715. &rc,
  5716. szText,
  5717. lstrlen(szText),
  5718. NULL);
  5719. }
  5720. ImageList_Draw(_himl,
  5721. (lpdis->itemID == (UINT)_iCurrentLocation)
  5722. ? pItem->iSelectedImage
  5723. : pItem->iImage,
  5724. hdc,
  5725. xMiniDrive,
  5726. rc.top + (rc.bottom - rc.top - MINIDRIVE_HEIGHT) / 2,
  5727. (pItem->IsShared()
  5728. ? INDEXTOOVERLAYMASK(IDOI_SHARE)
  5729. : 0) |
  5730. ((lpdis->itemState & ODS_SELECTED)
  5731. ? (ILD_SELECTED | ILD_FOCUS | ILD_TRANSPARENT)
  5732. : ILD_TRANSPARENT));
  5733. }
  5734. }
  5735. if (lpdis->itemAction == ODA_FOCUS ||
  5736. (lpdis->itemState & ODS_FOCUS))
  5737. {
  5738. DrawFocusRect(hdc, &rc);
  5739. }
  5740. }
  5741. ////////////////////////////////////////////////////////////////////////////
  5742. //
  5743. // CFileOpenBrowser::RefreshFilter
  5744. //
  5745. // Refresh the view given any change in the user's choice of wildcard
  5746. // filter.
  5747. //
  5748. ////////////////////////////////////////////////////////////////////////////
  5749. void CFileOpenBrowser::RefreshFilter(
  5750. HWND hwndFilter)
  5751. {
  5752. WAIT_CURSOR w(this);
  5753. _pOFN->Flags &= ~OFN_FILTERDOWN;
  5754. short nIndex = (short) SendMessage(hwndFilter, CB_GETCURSEL, 0, 0L);
  5755. if (nIndex < 0)
  5756. {
  5757. //
  5758. // No current selection.
  5759. //
  5760. return;
  5761. }
  5762. BOOL bCustomFilter = _pOFN->lpstrCustomFilter && *_pOFN->lpstrCustomFilter;
  5763. _pOFN->nFilterIndex = nIndex;
  5764. if (!bCustomFilter)
  5765. {
  5766. _pOFN->nFilterIndex++;
  5767. }
  5768. LPTSTR lpFilter;
  5769. //
  5770. // Must also check if filter contains anything.
  5771. //
  5772. lpFilter = (LPTSTR)ComboBox_GetItemData(hwndFilter, nIndex);
  5773. if (*lpFilter)
  5774. {
  5775. SetCurrentFilter(lpFilter);
  5776. //
  5777. // Provide dynamic _pszDefExt updating when lpstrDefExt is app
  5778. // initialized.
  5779. //
  5780. if (!_bNoInferDefExt && _pOFN->lpstrDefExt)
  5781. {
  5782. //
  5783. // We are looking for "foo*.ext[;...]". We will grab ext as the
  5784. // default extension. If not of this form, use the default
  5785. // extension passed in.
  5786. //
  5787. LPTSTR lpDot = StrChr(lpFilter, CHAR_DOT);
  5788. //
  5789. // Skip past the CHAR_DOT.
  5790. //
  5791. if (lpDot && _pszDefExt.TSStrCpy(lpDot + 1))
  5792. {
  5793. LPTSTR lpSemiColon = StrChr(_pszDefExt, CHAR_SEMICOLON);
  5794. if (lpSemiColon)
  5795. {
  5796. *lpSemiColon = CHAR_NULL;
  5797. }
  5798. if (IsWild(_pszDefExt))
  5799. {
  5800. _pszDefExt.TSStrCpy(_pOFN->lpstrDefExt);
  5801. }
  5802. }
  5803. else
  5804. {
  5805. _pszDefExt.TSStrCpy(_pOFN->lpstrDefExt);
  5806. }
  5807. }
  5808. if (_bUseCombo)
  5809. {
  5810. HWND hwndEdit = (HWND)SendMessage(GetDlgItem(_hwndDlg, cmb13), CBEM_GETEDITCONTROL, 0, 0L);
  5811. GetWindowText(hwndEdit, _szBuf, ARRAYSIZE(_szBuf));
  5812. }
  5813. else
  5814. {
  5815. GetDlgItemText(_hwndDlg, edt1, _szBuf, ARRAYSIZE(_szBuf));
  5816. }
  5817. if (IsWild(_szBuf))
  5818. {
  5819. //
  5820. // We should not show a filter that we are not using.
  5821. //
  5822. *_szBuf = CHAR_NULL;
  5823. SetEditFile(_szBuf, NULL, TRUE);
  5824. }
  5825. if (_psv)
  5826. {
  5827. _psv->Refresh();
  5828. }
  5829. }
  5830. if (_hSubDlg)
  5831. {
  5832. if (!CD_SendTypeChangeNotify(_hSubDlg, _hwndDlg, _pOFN, _pOFI))
  5833. {
  5834. CD_SendLBChangeMsg(_hSubDlg, cmb1, nIndex, CD_LBSELCHANGE, _pOFI->ApiType);
  5835. }
  5836. }
  5837. }
  5838. ////////////////////////////////////////////////////////////////////////////
  5839. //
  5840. // CFileOpenBrowser::GetDirectoryFromLB
  5841. //
  5842. // Return the dropdown's directory and its length.
  5843. // Set *pichRoot to the start of the path (C:\ or \\server\share\).
  5844. //
  5845. // pszBuf is assumed to be at least MAX_PATH in length
  5846. //
  5847. ////////////////////////////////////////////////////////////////////////////
  5848. UINT CFileOpenBrowser::GetDirectoryFromLB(
  5849. LPTSTR pszBuf,
  5850. int *pichRoot)
  5851. {
  5852. *pszBuf = 0;
  5853. if (_pCurrentLocation->pidlFull != NULL)
  5854. {
  5855. GetPathFromLocation(_pCurrentLocation, pszBuf);
  5856. }
  5857. if (*pszBuf)
  5858. {
  5859. if (PathAddBackslash(pszBuf))
  5860. {
  5861. LPTSTR pszBackslash = StrChr(pszBuf + 2, CHAR_BSLASH);
  5862. if (pszBackslash != NULL)
  5863. {
  5864. //
  5865. // For UNC paths, the "root" is on the next backslash.
  5866. //
  5867. if (DBL_BSLASH(pszBuf))
  5868. {
  5869. pszBackslash = StrChr(pszBackslash + 1, CHAR_BSLASH);
  5870. }
  5871. UINT cchRet = lstrlen(pszBuf);
  5872. *pichRoot = (pszBackslash != NULL) ? (int)(pszBackslash - pszBuf) : cchRet;
  5873. return (cchRet);
  5874. }
  5875. }
  5876. }
  5877. *pichRoot = 0;
  5878. return (0);
  5879. }
  5880. ////////////////////////////////////////////////////////////////////////////
  5881. //
  5882. // CFileOpenBrowser::EnumItemObjects
  5883. //
  5884. ////////////////////////////////////////////////////////////////////////////
  5885. typedef BOOL (*EIOCALLBACK)(
  5886. CFileOpenBrowser *that,
  5887. LPCITEMIDLIST pidl,
  5888. LPARAM lParam);
  5889. BOOL CFileOpenBrowser::EnumItemObjects(
  5890. UINT uItem,
  5891. EIOCALLBACK pfnCallBack,
  5892. LPARAM lParam)
  5893. {
  5894. FORMATETC fmte = { (CLIPFORMAT) g_cfCIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  5895. BOOL bRet = FALSE;
  5896. LPCITEMIDLIST pidl;
  5897. LPIDA pida;
  5898. int cItems, i;
  5899. IDataObject *pdtobj;
  5900. STGMEDIUM medium;
  5901. if (!_psv || FAILED(_psv->GetItemObject(uItem,
  5902. IID_PPV_ARG(IDataObject, &pdtobj))))
  5903. {
  5904. goto Error0;
  5905. }
  5906. if (FAILED(pdtobj->GetData(&fmte, &medium)))
  5907. {
  5908. goto Error1;
  5909. }
  5910. pida = (LPIDA)GlobalLock(medium.hGlobal);
  5911. cItems = pida->cidl;
  5912. for (i = 1; ; ++i)
  5913. {
  5914. if (i > cItems)
  5915. {
  5916. //
  5917. // We got to the end of the list without a failure.
  5918. // Call back one last time with NULL.
  5919. //
  5920. bRet = pfnCallBack(this, NULL, lParam);
  5921. break;
  5922. }
  5923. pidl = LPIDL_GetIDList(pida, i);
  5924. if (!pfnCallBack(this, pidl, lParam))
  5925. {
  5926. break;
  5927. }
  5928. }
  5929. GlobalUnlock(medium.hGlobal);
  5930. _ReleaseStgMedium(&medium);
  5931. Error1:
  5932. pdtobj->Release();
  5933. Error0:
  5934. return (bRet);
  5935. }
  5936. ////////////////////////////////////////////////////////////////////////////
  5937. //
  5938. // FindNameEnumCB
  5939. //
  5940. ////////////////////////////////////////////////////////////////////////////
  5941. #define FE_INVALID_VALUE 0x0000
  5942. #define FE_OUTOFMEM 0x0001
  5943. #define FE_TOOMANY 0x0002
  5944. #define FE_CHANGEDDIR 0x0003
  5945. #define FE_FILEERR 0x0004
  5946. #define FE_FOUNDNAME 0x0005
  5947. typedef struct _FINDNAMESTRUCT
  5948. {
  5949. LPTSTR pszFile;
  5950. UINT uRet;
  5951. LPCITEMIDLIST pidlFound;
  5952. } FINDNAMESTRUCT;
  5953. BOOL FindNameEnumCB(
  5954. CFileOpenBrowser *that,
  5955. LPCITEMIDLIST pidl,
  5956. LPARAM lParam)
  5957. {
  5958. SHFILEINFO sfi;
  5959. FINDNAMESTRUCT *pfns = (FINDNAMESTRUCT *)lParam;
  5960. if (!pidl)
  5961. {
  5962. if (!pfns->pidlFound)
  5963. {
  5964. return FALSE;
  5965. }
  5966. GetViewItemText(that->_psfCurrent, pfns->pidlFound, pfns->pszFile, MAX_PATH);
  5967. if (IsContainer(that->_psfCurrent, pfns->pidlFound))
  5968. {
  5969. LPITEMIDLIST pidlFull = ILCombine(that->_pCurrentLocation->pidlFull,
  5970. pfns->pidlFound);
  5971. if (pidlFull)
  5972. {
  5973. if (that->JumpToIDList(pidlFull))
  5974. {
  5975. pfns->uRet = FE_CHANGEDDIR;
  5976. }
  5977. else if (!that->_psv)
  5978. {
  5979. pfns->uRet = FE_OUTOFMEM;
  5980. }
  5981. SHFree(pidlFull);
  5982. if (pfns->uRet != FE_INVALID_VALUE)
  5983. {
  5984. return TRUE;
  5985. }
  5986. }
  5987. }
  5988. pfns->uRet = FE_FOUNDNAME;
  5989. return TRUE;
  5990. }
  5991. if (!SHGetFileInfo((LPCTSTR)pidl,
  5992. 0,
  5993. &sfi,
  5994. sizeof(sfi),
  5995. SHGFI_DISPLAYNAME | SHGFI_PIDL))
  5996. {
  5997. //
  5998. // This will never happen, right?
  5999. //
  6000. return TRUE;
  6001. }
  6002. if (lstrcmpi(sfi.szDisplayName, pfns->pszFile) != 0)
  6003. {
  6004. //
  6005. // Continue the enumeration.
  6006. //
  6007. return TRUE;
  6008. }
  6009. if (!pfns->pidlFound)
  6010. {
  6011. pfns->pidlFound = pidl;
  6012. //
  6013. // Continue looking for more matches.
  6014. //
  6015. return TRUE;
  6016. }
  6017. //
  6018. // We already found a match, so select the first one and stop the search.
  6019. //
  6020. // The focus must be set to _hwndView before changing selection or
  6021. // the GetItemObject may not work.
  6022. //
  6023. FORWARD_WM_NEXTDLGCTL(that->_hwndDlg, that->_hwndView, 1, SendMessage);
  6024. that->_psv->SelectItem(pfns->pidlFound,
  6025. SVSI_SELECT | SVSI_DESELECTOTHERS |
  6026. SVSI_ENSUREVISIBLE | SVSI_FOCUSED);
  6027. pfns->pidlFound = NULL;
  6028. pfns->uRet = FE_TOOMANY;
  6029. //
  6030. // Stop enumerating.
  6031. //
  6032. return FALSE;
  6033. }
  6034. ////////////////////////////////////////////////////////////////////////////
  6035. //
  6036. // CDPathQualify
  6037. //
  6038. ////////////////////////////////////////////////////////////////////////////
  6039. BOOL CDPathQualify(
  6040. LPCTSTR lpFile,
  6041. LPTSTR pszPathName)
  6042. {
  6043. BOOL bRet = FALSE;
  6044. TCHAR szCurDir[MAX_PATH + 1];
  6045. //
  6046. // This should do the whole job of canonicalizing the directory.
  6047. //
  6048. if (GetCurrentDirectory(ARRAYSIZE(szCurDir), szCurDir))
  6049. {
  6050. bRet = PathCombine(pszPathName, szCurDir, lpFile) ? TRUE : FALSE;
  6051. }
  6052. return bRet;
  6053. }
  6054. ////////////////////////////////////////////////////////////////////////////
  6055. //
  6056. // VerifyOpen
  6057. //
  6058. // Returns: 0 success
  6059. // !0 dos error code
  6060. //
  6061. ////////////////////////////////////////////////////////////////////////////
  6062. int VerifyOpen(
  6063. LPCTSTR lpFile,
  6064. LPTSTR pszPathName)
  6065. {
  6066. HANDLE hf;
  6067. int nError = OF_BUFFERTRUNCATED;
  6068. if (CDPathQualify(lpFile, pszPathName))
  6069. {
  6070. hf = CreateFile(pszPathName,
  6071. GENERIC_READ,
  6072. FILE_SHARE_READ | FILE_SHARE_WRITE,
  6073. NULL,
  6074. OPEN_EXISTING,
  6075. FILE_ATTRIBUTE_NORMAL,
  6076. NULL);
  6077. if (hf == INVALID_HANDLE_VALUE)
  6078. {
  6079. nError = GetLastError();
  6080. }
  6081. else
  6082. {
  6083. CloseHandle(hf);
  6084. nError = 0;
  6085. }
  6086. }
  6087. return nError;
  6088. }
  6089. ////////////////////////////////////////////////////////////////////////////
  6090. //
  6091. // CFileOpenBrowser::IsKnownExtension
  6092. //
  6093. ////////////////////////////////////////////////////////////////////////////
  6094. BOOL CFileOpenBrowser::IsKnownExtension(
  6095. LPCTSTR pszExtension)
  6096. {
  6097. if ((LPTSTR)_pszDefExt && lstrcmpi(pszExtension + 1, _pszDefExt) == 0)
  6098. {
  6099. //
  6100. // It's the default extension, so no need to add it again.
  6101. //
  6102. return TRUE;
  6103. }
  6104. if (lstrcmp(_szLastFilter, szStarDotStar) == 0)
  6105. {
  6106. //Current Filter is *.*, so allow whatever extension user enters.
  6107. return TRUE;
  6108. }
  6109. if (RegQueryValue(HKEY_CLASSES_ROOT, pszExtension, NULL, 0) == ERROR_SUCCESS)
  6110. {
  6111. //
  6112. // It's a registered extension, so the user is trying to force
  6113. // the type.
  6114. //
  6115. return TRUE;
  6116. }
  6117. if (_pOFN->lpstrFilter)
  6118. {
  6119. LPCTSTR pFilter = _pOFN->lpstrFilter;
  6120. while (*pFilter)
  6121. {
  6122. //
  6123. // Skip visual.
  6124. //
  6125. pFilter = pFilter + lstrlen(pFilter) + 1;
  6126. //
  6127. // Search extension list.
  6128. //
  6129. while (*pFilter)
  6130. {
  6131. //
  6132. // Check extensions of the form '*.ext' only.
  6133. //
  6134. if (*pFilter == CHAR_STAR && *(++pFilter) == CHAR_DOT)
  6135. {
  6136. LPCTSTR pExt = pszExtension + 1;
  6137. pFilter++;
  6138. while (*pExt && *pExt == *pFilter)
  6139. {
  6140. pExt++;
  6141. pFilter++;
  6142. }
  6143. if (!*pExt && (*pFilter == CHAR_SEMICOLON || !*pFilter))
  6144. {
  6145. //
  6146. // We have a match.
  6147. //
  6148. return TRUE;
  6149. }
  6150. }
  6151. //
  6152. // Skip to next extension.
  6153. //
  6154. while (*pFilter)
  6155. {
  6156. TCHAR ch = *pFilter;
  6157. pFilter = CharNext(pFilter);
  6158. if (ch == CHAR_SEMICOLON)
  6159. {
  6160. break;
  6161. }
  6162. }
  6163. }
  6164. //
  6165. // Skip extension string's terminator.
  6166. //
  6167. pFilter++;
  6168. }
  6169. }
  6170. return FALSE;
  6171. }
  6172. BOOL CFileOpenBrowser::_IsNoDereferenceLinks(LPCWSTR pszFile, IShellItem *psi)
  6173. {
  6174. if (_pOFN->Flags & OFN_NODEREFERENCELINKS)
  6175. return TRUE;
  6176. LPWSTR psz = NULL;
  6177. if (!pszFile)
  6178. {
  6179. psi->GetDisplayName(SIGDN_PARENTRELATIVEPARSING, &psz);
  6180. pszFile = psz;
  6181. }
  6182. // if the filter equals what ever we are looking at
  6183. // we assume the caller is actually looking for
  6184. // this file.
  6185. BOOL fRet = (NULL == StrStr(_szLastFilter, TEXT(".*"))) && PathMatchSpec(pszFile, _szLastFilter);
  6186. if (psz)
  6187. CoTaskMemFree(psz);
  6188. return fRet;
  6189. }
  6190. ////////////////////////////////////////////////////////////////////////////
  6191. //
  6192. // CFileOpenBrowser::FindNameInView
  6193. //
  6194. // We will only resolve a link once. If you have a link to a link, then
  6195. // we will return the second link.
  6196. //
  6197. // If nExtOffset is non-zero, it is the offset to the character following
  6198. // the dot.
  6199. //
  6200. // Note: pszFile buffer must be MAX_PATH in length.
  6201. //
  6202. ////////////////////////////////////////////////////////////////////////////
  6203. #define NUM_LINKLOOPS 1
  6204. UINT CFileOpenBrowser::FindNameInView(
  6205. LPTSTR pszFile,
  6206. OKBUTTONFLAGS Flags,
  6207. LPTSTR pszPathName,
  6208. int nFileOffset,
  6209. int nExtOffset,
  6210. int *pnErrCode,
  6211. BOOL bTryAsDir)
  6212. {
  6213. UINT uRet;
  6214. FINDNAMESTRUCT fns =
  6215. {
  6216. pszFile,
  6217. FE_INVALID_VALUE,
  6218. NULL,
  6219. };
  6220. BOOL bGetOut = TRUE;
  6221. BOOL bAddExt = FALSE;
  6222. BOOL bHasExt = nExtOffset;
  6223. TCHAR szTemp[MAX_PATH + 1];
  6224. int nNewExt = lstrlen(pszFile);
  6225. //
  6226. // If no extension, point at the end of the file name.
  6227. //
  6228. if (!nExtOffset)
  6229. {
  6230. nExtOffset = nNewExt;
  6231. }
  6232. //
  6233. // HACK: We could have a link that points to another link that points to
  6234. // another link, ..., that points back to the original file. We will not
  6235. // loop more than NUM_LINKLOOPS times before giving up.
  6236. int nLoop = NUM_LINKLOOPS;
  6237. if (Flags & (OKBUTTON_NODEFEXT | OKBUTTON_QUOTED))
  6238. {
  6239. goto VerifyTheName;
  6240. }
  6241. if (bHasExt)
  6242. {
  6243. if (IsKnownExtension(pszFile + nExtOffset))
  6244. {
  6245. goto VerifyTheName;
  6246. }
  6247. //
  6248. // Don't attempt 2 extensions on SFN volume.
  6249. //
  6250. if (!CDPathQualify(pszFile, pszPathName)) // This can fail if we end up with something larger than MAX_PATH
  6251. {
  6252. *pnErrCode = OF_BUFFERTRUNCATED;
  6253. return FE_FILEERR;
  6254. }
  6255. if (!IsLFNDrive(pszPathName))
  6256. {
  6257. goto VerifyTheName;
  6258. }
  6259. }
  6260. bGetOut = FALSE;
  6261. if ((LPTSTR)_pszDefExt &&
  6262. ((DWORD)nNewExt + lstrlen(_pszDefExt) < _pOFN->nMaxFile))
  6263. {
  6264. bAddExt = TRUE;
  6265. //
  6266. // Note that we check lpstrDefExt to see if they want an automatic
  6267. // extension, but actually copy _pszDefExt.
  6268. //
  6269. if (!AppendExt(pszFile, MAX_PATH, _pszDefExt, FALSE))
  6270. {
  6271. *pnErrCode = OF_BUFFERTRUNCATED;
  6272. return (FE_FILEERR); // Not enough buffer room for default extension
  6273. }
  6274. //
  6275. // So we've added the default extension. If there's a directory
  6276. // that matches this name, all attempts to open/create the file
  6277. // will fail, so simply change to the directory as if they had
  6278. // typed it in. Note that by putting this test here, if there
  6279. // was a directory without the extension, we would have already
  6280. // switched to it.
  6281. //
  6282. VerifyTheName:
  6283. //
  6284. // Note that this also works for a UNC name, even on a net that
  6285. // does not support using UNC's directly. It will also do the
  6286. // right thing for links to things. We do not validate if we
  6287. // have not dereferenced any links, since that should have
  6288. // already been done.
  6289. //
  6290. if (bTryAsDir && SetDirRetry(pszFile, nLoop == NUM_LINKLOOPS))
  6291. {
  6292. return (FE_CHANGEDDIR);
  6293. }
  6294. *pnErrCode = VerifyOpen(pszFile, pszPathName);
  6295. if (*pnErrCode == 0 || *pnErrCode == OF_SHARINGVIOLATION)
  6296. {
  6297. //
  6298. // This may be a link to something, so we should try to
  6299. // resolve it.
  6300. //
  6301. if (!_IsNoDereferenceLinks(pszFile, NULL) && nLoop > 0)
  6302. {
  6303. --nLoop;
  6304. LPITEMIDLIST pidl;
  6305. IShellFolder *psf = NULL;
  6306. DWORD dwAttr = SFGAO_LINK;
  6307. HRESULT hRes;
  6308. //
  6309. // ILCreateFromPath is slow (especially on a Net path),
  6310. // so just try to parse the name in the current folder if
  6311. // possible.
  6312. //
  6313. if (nFileOffset || nLoop < NUM_LINKLOOPS - 1)
  6314. {
  6315. LPITEMIDLIST pidlTemp;
  6316. hRes = SHILCreateFromPath(pszPathName, &pidlTemp, &dwAttr);
  6317. //We are getting a pidl corresponding to a path. Get the IShellFolder corresponding to this pidl
  6318. // to pass it to ResolveLink
  6319. if (SUCCEEDED(hRes))
  6320. {
  6321. LPCITEMIDLIST pidlLast;
  6322. hRes = CDBindToIDListParent(pidlTemp, IID_PPV_ARG(IShellFolder, &psf), (LPCITEMIDLIST *)&pidlLast);
  6323. if (SUCCEEDED(hRes))
  6324. {
  6325. //Get the child pidl relative to the IShellFolder
  6326. pidl = ILClone(pidlLast);
  6327. }
  6328. ILFree(pidlTemp);
  6329. }
  6330. }
  6331. else
  6332. {
  6333. WCHAR wszDisplayName[MAX_PATH + 1];
  6334. ULONG chEaten;
  6335. SHTCharToUnicode(pszFile, wszDisplayName , ARRAYSIZE(wszDisplayName));
  6336. hRes = _psfCurrent->ParseDisplayName(NULL,
  6337. NULL,
  6338. wszDisplayName,
  6339. &chEaten,
  6340. &pidl,
  6341. &dwAttr);
  6342. }
  6343. if (SUCCEEDED(hRes))
  6344. {
  6345. if (dwAttr & SFGAO_LINK)
  6346. {
  6347. SHTCUTINFO info;
  6348. info.dwAttr = 0;
  6349. info.fReSolve = FALSE;
  6350. info.pszLinkFile = szTemp;
  6351. info.cchFile = ARRAYSIZE(szTemp);
  6352. info.ppidl = NULL;
  6353. //psf can be NULL in which case ResolveLink uses _psfCurrent IShellFolder
  6354. if (SUCCEEDED(ResolveLink(pidl, &info, psf)) && szTemp[0])
  6355. {
  6356. //
  6357. // It was a link, and it "dereferenced" to something,
  6358. // so we should try again with that new file.
  6359. //
  6360. EVAL(SUCCEEDED(StringCchCopy(pszFile, MAX_PATH, szTemp)));
  6361. if (pidl)
  6362. {
  6363. SHFree(pidl);
  6364. }
  6365. if (psf)
  6366. {
  6367. psf->Release();
  6368. psf = NULL;
  6369. }
  6370. goto VerifyTheName;
  6371. }
  6372. }
  6373. if (pidl)
  6374. {
  6375. SHFree(pidl);
  6376. }
  6377. if (psf)
  6378. {
  6379. psf->Release();
  6380. psf = NULL;
  6381. }
  6382. }
  6383. }
  6384. return (FE_FOUNDNAME);
  6385. }
  6386. else if (*pnErrCode == OF_BUFFERTRUNCATED)
  6387. {
  6388. bGetOut = TRUE;
  6389. }
  6390. if (bGetOut ||
  6391. (*pnErrCode != OF_FILENOTFOUND && *pnErrCode != OF_PATHNOTFOUND))
  6392. {
  6393. return (FE_FILEERR);
  6394. }
  6395. if (_bSave)
  6396. {
  6397. //
  6398. // Do no more work if creating a new file.
  6399. //
  6400. return (FE_FOUNDNAME);
  6401. }
  6402. }
  6403. //
  6404. // Make sure we do not loop forever.
  6405. //
  6406. bGetOut = TRUE;
  6407. if (_bSave)
  6408. {
  6409. //
  6410. // Do no more work if creating a new file.
  6411. //
  6412. goto VerifyTheName;
  6413. }
  6414. pszFile[nNewExt] = CHAR_NULL;
  6415. if (bTryAsDir && (nFileOffset > 0))
  6416. {
  6417. TCHAR cSave = *(pszFile + nFileOffset); // Save off the filename.
  6418. *(pszFile + nFileOffset) = CHAR_NULL; // Chop it off.
  6419. //
  6420. // We need to have the view on the dir with the file to do the
  6421. // next steps.
  6422. //
  6423. BOOL bOK = JumpToPath(pszFile);
  6424. *(pszFile + nFileOffset) = cSave; // Put it back.
  6425. if (!_psv)
  6426. {
  6427. //
  6428. // We're dead.
  6429. //
  6430. return (FE_OUTOFMEM);
  6431. }
  6432. if (bOK)
  6433. {
  6434. // We've moved to the directory. Now just put the filename in the edit box.
  6435. StringCopyOverlap(pszFile, pszFile + nFileOffset);
  6436. nNewExt -= nFileOffset;
  6437. SetEditFile(pszFile, NULL, TRUE);
  6438. }
  6439. else
  6440. {
  6441. *pnErrCode = OF_PATHNOTFOUND;
  6442. return (FE_FILEERR);
  6443. }
  6444. }
  6445. EnumItemObjects(SVGIO_ALLVIEW, FindNameEnumCB, (LPARAM)&fns);
  6446. switch (fns.uRet)
  6447. {
  6448. case (FE_INVALID_VALUE) :
  6449. {
  6450. break;
  6451. }
  6452. case (FE_FOUNDNAME) :
  6453. {
  6454. goto VerifyTheName;
  6455. }
  6456. default :
  6457. {
  6458. uRet = fns.uRet;
  6459. goto VerifyAndRet;
  6460. }
  6461. }
  6462. if (bAddExt)
  6463. {
  6464. //
  6465. // Before we fail, check to see if the file typed sans default
  6466. // extension exists.
  6467. //
  6468. *pnErrCode = VerifyOpen(pszFile, pszPathName);
  6469. if (*pnErrCode == 0 || *pnErrCode == OF_SHARINGVIOLATION)
  6470. {
  6471. //
  6472. // We will never hit this case for links (because they
  6473. // have registered extensions), so we don't need
  6474. // to goto VerifyTheName (which also calls VerifyOpen again).
  6475. //
  6476. return (FE_FOUNDNAME);
  6477. }
  6478. //
  6479. // I still can't find it? Try adding the default extension and
  6480. // return failure.
  6481. //
  6482. EVAL(AppendExt(pszFile, MAX_PATH, _pszDefExt, FALSE));
  6483. }
  6484. uRet = FE_FILEERR;
  6485. VerifyAndRet:
  6486. *pnErrCode = VerifyOpen(pszFile, pszPathName);
  6487. return (uRet);
  6488. }
  6489. ////////////////////////////////////////////////////////////////////////////
  6490. //
  6491. // CFileOpenBrowser::SetDirRetry
  6492. //
  6493. ////////////////////////////////////////////////////////////////////////////
  6494. BOOL CFileOpenBrowser::SetDirRetry(
  6495. LPTSTR pszDir,
  6496. BOOL bNoValidate)
  6497. {
  6498. if (SetCurrentDirectory(pszDir))
  6499. {
  6500. JumpThere:
  6501. JumpToPath(TEXT("."));
  6502. return TRUE;
  6503. }
  6504. if (bNoValidate || !IsUNC(pszDir))
  6505. {
  6506. return FALSE;
  6507. }
  6508. //
  6509. // It may have been a password problem, so try to add the connection.
  6510. // Note that if we are on a net that does not support CD'ing to UNC's
  6511. // directly, this call will connect it to a drive letter.
  6512. //
  6513. if (!SHValidateUNC(_hwndDlg, pszDir, 0))
  6514. {
  6515. switch (GetLastError())
  6516. {
  6517. case ERROR_CANCELLED:
  6518. {
  6519. //
  6520. // We don't want to put up an error message if they
  6521. // canceled the password dialog.
  6522. //
  6523. return TRUE;
  6524. }
  6525. case ERROR_NETWORK_UNREACHABLE:
  6526. {
  6527. LPTSTR lpMsgBuf;
  6528. TCHAR szTitle[MAX_PATH];
  6529. FormatMessage(
  6530. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  6531. FORMAT_MESSAGE_FROM_SYSTEM |
  6532. FORMAT_MESSAGE_IGNORE_INSERTS,
  6533. NULL,
  6534. GetLastError(),
  6535. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  6536. (LPTSTR) &lpMsgBuf,
  6537. 0,
  6538. NULL);
  6539. GetWindowText(_hwndDlg, szTitle, ARRAYSIZE(szTitle));
  6540. MessageBox(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONINFORMATION);
  6541. // Free the buffer.
  6542. LocalFree(lpMsgBuf);
  6543. return TRUE;
  6544. }
  6545. default:
  6546. {
  6547. //
  6548. // Some other error we don't know about.
  6549. //
  6550. return FALSE;
  6551. }
  6552. }
  6553. }
  6554. //
  6555. // We connected to it, so try to switch to it again.
  6556. //
  6557. if (SetCurrentDirectory(pszDir))
  6558. {
  6559. goto JumpThere;
  6560. }
  6561. return FALSE;
  6562. }
  6563. ////////////////////////////////////////////////////////////////////////////
  6564. //
  6565. // CFileOpenBrowser::MultiSelectOKButton
  6566. //
  6567. ////////////////////////////////////////////////////////////////////////////
  6568. BOOL CFileOpenBrowser::MultiSelectOKButton(
  6569. LPCTSTR pszFiles,
  6570. OKBUTTONFLAGS Flags)
  6571. {
  6572. TCHAR szPathName[MAX_PATH];
  6573. int nErrCode;
  6574. LPTSTR pchRead, pchWrite, lpCurDir;
  6575. UINT cch, cchCurDir, cchFiles;
  6576. WAIT_CURSOR w(this);
  6577. //
  6578. // This doesn't really mean anything for multiselection.
  6579. //
  6580. _pOFN->nFileExtension = 0;
  6581. if (!_pOFN->lpstrFile)
  6582. {
  6583. return TRUE;
  6584. }
  6585. //
  6586. // Check for space for first full path element.
  6587. //
  6588. if ((_pOFN->Flags & OFN_ENABLEINCLUDENOTIFY) && lstrlen(_pszObjectCurDir))
  6589. {
  6590. lpCurDir = _pszObjectCurDir;
  6591. }
  6592. else
  6593. {
  6594. lpCurDir = _szCurDir;
  6595. }
  6596. cchCurDir = lstrlen(lpCurDir) + 1;
  6597. cchFiles = lstrlen(pszFiles) + 1;
  6598. cch = cchCurDir + cchFiles;
  6599. if (cch > (UINT)_pOFN->nMaxFile)
  6600. {
  6601. //
  6602. // Buffer is too small, so return the size of the buffer
  6603. // required to hold the string.
  6604. //
  6605. // cch is not really the number of characters needed, but it
  6606. // should be close.
  6607. //
  6608. StoreFileSizeInOFN(_pOFN, cch);
  6609. return TRUE;
  6610. }
  6611. TEMPSTR psFiles(cchFiles + FILE_PADDING);
  6612. pchRead = psFiles;
  6613. int cchRead = cchFiles + FILE_PADDING;
  6614. if (!pchRead)
  6615. {
  6616. //
  6617. // Out of memory.
  6618. // FEATURE There should be some sort of error message here.
  6619. //
  6620. return FALSE;
  6621. }
  6622. //
  6623. // Copy in the full path as the first element.
  6624. //
  6625. EVAL(SUCCEEDED(StringCchCopy(_pOFN->lpstrFile, _pOFN->nMaxFile, lpCurDir)));
  6626. //
  6627. // Set nFileOffset to 1st file.
  6628. //
  6629. _pOFN->nFileOffset = (WORD) cchCurDir;
  6630. pchWrite = _pOFN->lpstrFile + cchCurDir;
  6631. int cchRemaining = _pOFN->nMaxFile - cchCurDir;
  6632. //
  6633. // We know there is enough room for the whole string.
  6634. //
  6635. EVAL(SUCCEEDED(StringCchCopy(pchRead, cchRead, pszFiles)));
  6636. //
  6637. // This should only compact the string (converting to NULL terminated list of strings)
  6638. //
  6639. if (!ConvertToNULLTerm(pchRead))
  6640. {
  6641. return FALSE;
  6642. }
  6643. for (; *pchRead; pchRead += lstrlen(pchRead) + 1)
  6644. {
  6645. int nFileOffset, nExtOffset;
  6646. TCHAR szBasicPath[MAX_PATH];
  6647. EVAL(SUCCEEDED(StringCchCopy(szBasicPath, ARRAYSIZE(szBasicPath), pchRead))); // Impossible for filename to be longer than MAX_PATH
  6648. nFileOffset = ParseFileNew(szBasicPath, &nExtOffset, FALSE, TRUE);
  6649. if (nFileOffset < 0)
  6650. {
  6651. InvalidFileWarningNew(_hwndDlg, pchRead, nFileOffset);
  6652. return FALSE;
  6653. }
  6654. //
  6655. // Pass in 0 for the file offset to make sure we do not switch
  6656. // to another folder.
  6657. //
  6658. switch (FindNameInView(szBasicPath,
  6659. Flags,
  6660. szPathName,
  6661. nFileOffset,
  6662. nExtOffset,
  6663. &nErrCode,
  6664. FALSE))
  6665. {
  6666. case (FE_OUTOFMEM) :
  6667. case (FE_CHANGEDDIR) :
  6668. {
  6669. return FALSE;
  6670. }
  6671. case (FE_TOOMANY) :
  6672. {
  6673. CDMessageBox(_hwndDlg,
  6674. iszTooManyFiles,
  6675. MB_OK | MB_ICONEXCLAMATION,
  6676. pchRead);
  6677. return FALSE;
  6678. }
  6679. default :
  6680. {
  6681. break;
  6682. }
  6683. }
  6684. if (nErrCode &&
  6685. ((_pOFN->Flags & OFN_FILEMUSTEXIST) ||
  6686. (nErrCode != OF_FILENOTFOUND)) &&
  6687. ((_pOFN->Flags & OFN_PATHMUSTEXIST) ||
  6688. (nErrCode != OF_PATHNOTFOUND)) &&
  6689. (!(_pOFN->Flags & OFN_SHAREAWARE) ||
  6690. (nErrCode != OF_SHARINGVIOLATION)))
  6691. {
  6692. if ((nErrCode == OF_SHARINGVIOLATION) && _hSubDlg)
  6693. {
  6694. int nShareCode = CD_SendShareNotify(_hSubDlg,
  6695. _hwndDlg,
  6696. szPathName,
  6697. _pOFN,
  6698. _pOFI);
  6699. if (nShareCode == OFN_SHARENOWARN)
  6700. {
  6701. return FALSE;
  6702. }
  6703. else if (nShareCode == OFN_SHAREFALLTHROUGH)
  6704. {
  6705. goto EscapedThroughShare;
  6706. }
  6707. else
  6708. {
  6709. //
  6710. // They might not have handled the notification, so try
  6711. // the registered message.
  6712. //
  6713. nShareCode = CD_SendShareMsg(_hSubDlg, szPathName, _pOFI->ApiType);
  6714. if (nShareCode == OFN_SHARENOWARN)
  6715. {
  6716. return FALSE;
  6717. }
  6718. else if (nShareCode == OFN_SHAREFALLTHROUGH)
  6719. {
  6720. goto EscapedThroughShare;
  6721. }
  6722. }
  6723. }
  6724. else if (nErrCode == OF_ACCESSDENIED)
  6725. {
  6726. szPathName[0] |= 0x60;
  6727. if (GetDriveType(szPathName) != DRIVE_REMOVABLE)
  6728. {
  6729. nErrCode = OF_NETACCESSDENIED;
  6730. }
  6731. }
  6732. //
  6733. // These will never be set.
  6734. //
  6735. if ((nErrCode == OF_WRITEPROTECTION) ||
  6736. (nErrCode == OF_DISKFULL) ||
  6737. (nErrCode == OF_DISKFULL2) ||
  6738. (nErrCode == OF_ACCESSDENIED))
  6739. {
  6740. *pchRead = szPathName[0];
  6741. }
  6742. MultiWarning:
  6743. InvalidFileWarningNew(_hwndDlg, pchRead, nErrCode);
  6744. return FALSE;
  6745. }
  6746. EscapedThroughShare:
  6747. if (nErrCode == 0)
  6748. {
  6749. if (!_ValidateSelectedFile(szPathName, &nErrCode))
  6750. {
  6751. if (nErrCode)
  6752. {
  6753. goto MultiWarning;
  6754. }
  6755. else
  6756. {
  6757. return FALSE;
  6758. }
  6759. }
  6760. }
  6761. //
  6762. // Add some more in case the file name got larger.
  6763. //
  6764. cch += lstrlen(szBasicPath) - lstrlen(pchRead);
  6765. if (cch > (UINT)_pOFN->nMaxFile)
  6766. {
  6767. StoreFileSizeInOFN(_pOFN, cch);
  6768. return TRUE;
  6769. }
  6770. //
  6771. // We already know we have anough room.
  6772. //
  6773. EVAL(SUCCEEDED(StringCchCopy(pchWrite, cchRemaining, szBasicPath)));
  6774. pchWrite += lstrlen(pchWrite) + 1;
  6775. }
  6776. //
  6777. // double-NULL terminate.
  6778. //
  6779. *pchWrite = CHAR_NULL;
  6780. return TRUE;
  6781. }
  6782. ////////////////////////////////////////////////////////////////////////////
  6783. //
  6784. // CFileOpenBrowser::CheckForRestrictedFolder
  6785. //
  6786. ////////////////////////////////////////////////////////////////////////////
  6787. BOOL CFileOpenBrowser::CheckForRestrictedFolder(LPCTSTR lpszPath, int nFileOffset)
  6788. {
  6789. TCHAR szPath[MAX_PATH];
  6790. TCHAR szTemp[MAX_PATH];
  6791. LPITEMIDLIST pidl;
  6792. BOOL bPidlAllocated = FALSE;
  6793. BOOL bRet = FALSE;
  6794. DWORD dwAttrib = SFGAO_FILESYSTEM;
  6795. HRESULT hr = S_OK;
  6796. if (nFileOffset > 0)
  6797. {
  6798. //There's a path in the given filename. Get the directory part of the filename.
  6799. ASSERT(nFileOffset < ARRAYSIZE(szTemp));
  6800. StringCchCopy(szTemp, nFileOffset, lpszPath); // Truncation at nFileOffset is desired.
  6801. //The directory path might be a relative path. Resolve it to get fully qualified path.
  6802. CDPathQualify(szTemp, szPath);
  6803. //Create the pidl for this path as well as get the attributes.
  6804. hr = SHILCreateFromPath(szPath, &pidl, &dwAttrib);
  6805. if (SUCCEEDED(hr))
  6806. {
  6807. bPidlAllocated = TRUE;
  6808. }
  6809. else
  6810. {
  6811. // WE are failing b'cos the user might have typed some path which doesn't exist.
  6812. // if the path doesn't exist then it can't be one of the directory we are trying restrict.
  6813. // let's bail out and let the code that checks for valid path take care of it
  6814. return bRet;
  6815. }
  6816. }
  6817. else
  6818. {
  6819. IShellLink *psl;
  6820. pidl = _pCurrentLocation->pidlFull;
  6821. if (SUCCEEDED(CDGetUIObjectFromFullPIDL(pidl,_hwndDlg, IID_PPV_ARG(IShellLink, &psl))))
  6822. {
  6823. LPITEMIDLIST pidlTarget;
  6824. if (S_OK == psl->GetIDList(&pidlTarget))
  6825. {
  6826. SHGetAttributesOf(pidlTarget, &dwAttrib);
  6827. ILFree(pidlTarget);
  6828. }
  6829. psl->Release();
  6830. }
  6831. else
  6832. {
  6833. SHGetAttributesOf(pidl, &dwAttrib);
  6834. }
  6835. }
  6836. // 1. We cannot save to the non file system folders.
  6837. // 2. We should not allow user to save in recent files folder as the file might get deleted.
  6838. if (!(dwAttrib & SFGAO_FILESYSTEM) || _IsRecentFolder(pidl))
  6839. {
  6840. int iMessage = UrlIs(lpszPath, URLIS_URL) ? iszNoSaveToURL : iszSaveRestricted;
  6841. HCURSOR hcurOld = SetCursor(LoadCursor(NULL, IDC_ARROW));
  6842. CDMessageBox(_hwndDlg, iMessage, MB_OK | MB_ICONEXCLAMATION);
  6843. SetCursor(hcurOld);
  6844. bRet = TRUE;
  6845. }
  6846. if (bPidlAllocated)
  6847. {
  6848. ILFree(pidl);
  6849. }
  6850. return bRet;
  6851. }
  6852. STDAPI_(LPITEMIDLIST) GetIDListFromFolder(IShellFolder *psf)
  6853. {
  6854. LPITEMIDLIST pidl = NULL;
  6855. IPersistFolder2 *ppf;
  6856. if (psf && SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf))))
  6857. {
  6858. ppf->GetCurFolder(&pidl);
  6859. ppf->Release();
  6860. }
  6861. return pidl;
  6862. }
  6863. ////////////////////////////////////////////////////////////////////////////
  6864. //
  6865. // CFileOpenBrowser::OKButtonPressed
  6866. //
  6867. // Process the OK button being pressed. This may involve jumping to a path,
  6868. // changing the filter, actually choosing a file to open or save as, or who
  6869. // knows what else.
  6870. //
  6871. // Note: There are 4 cases for validation of a file name:
  6872. // 1) OFN_NOVALIDATE Allows invalid characters
  6873. // 2) No validation flags No invalid characters, but path need not exist
  6874. // 3) OFN_PATHMUSTEXIST No invalid characters, path must exist
  6875. // 4) OFN_FILEMUSTEXIST No invalid characters, path & file must exist
  6876. //
  6877. ////////////////////////////////////////////////////////////////////////////
  6878. BOOL CFileOpenBrowser::OKButtonPressed(
  6879. LPCTSTR pszFile,
  6880. OKBUTTONFLAGS Flags)
  6881. {
  6882. TCHAR szExpFile[MAX_PATH];
  6883. TCHAR szPathName[MAX_PATH];
  6884. TCHAR szBasicPath[MAX_PATH];
  6885. LPTSTR pExpFile = NULL;
  6886. LPTSTR pFree = NULL;
  6887. int nErrCode;
  6888. ECODE eCode = ECODE_S_OK;
  6889. DWORD cch;
  6890. int nFileOffset, nExtOffset, nOldExt;
  6891. TCHAR ch;
  6892. BOOL bAddExt = FALSE;
  6893. BOOL bUNCName = FALSE;
  6894. int nTempOffset;
  6895. BOOL bIsDir;
  6896. BOOL bRet = FALSE;
  6897. WAIT_CURSOR w(this);
  6898. EnableModelessSB(FALSE);
  6899. if (_bSelIsObject)
  6900. {
  6901. StorePathOrFileSizeInOFN(_pOFN, _pszObjectPath);
  6902. }
  6903. //
  6904. // Expand any environment variables.
  6905. //
  6906. cch = _pOFN->nMaxFile;
  6907. if (cch > MAX_PATH)
  6908. {
  6909. pExpFile = pFree = (LPTSTR)LocalAlloc(LPTR, (cch * sizeof(TCHAR)));
  6910. }
  6911. if (!pExpFile)
  6912. {
  6913. pExpFile = szExpFile;
  6914. cch = MAX_PATH;
  6915. }
  6916. pExpFile[0] = 0; pExpFile[1] = 0;
  6917. ExpandEnvironmentStrings(pszFile, pExpFile, cch);
  6918. pExpFile[cch - 1] = 0;
  6919. //
  6920. // See if we're in Multi Select mode.
  6921. //
  6922. if (StrChr(pExpFile, CHAR_QUOTE) && (_pOFN->Flags & OFN_ALLOWMULTISELECT))
  6923. {
  6924. bRet = MultiSelectOKButton(pExpFile, Flags);
  6925. goto ReturnFromOKButtonPressed;
  6926. }
  6927. //
  6928. // We've only got a single selection...if we're in
  6929. // multi-select mode & it's an object, we need to do a little
  6930. // work before continuing...
  6931. //
  6932. if ((_pOFN->Flags & OFN_ALLOWMULTISELECT) && _bSelIsObject)
  6933. {
  6934. pExpFile = _pszObjectPath;
  6935. }
  6936. if ((pExpFile[1] == CHAR_COLON) || DBL_BSLASH(pExpFile))
  6937. {
  6938. //
  6939. // If a drive or UNC was specified, use it.
  6940. //
  6941. if (FAILED(StringCchCopy(szBasicPath, ARRAYSIZE(szBasicPath) - 1, pExpFile))) // ARRAYSIZE - 1?
  6942. {
  6943. // (pExpFile can potentially be larger than ARRAYSIZE(szBasicPAth))
  6944. nErrCode = OF_BUFFERTRUNCATED;
  6945. goto Warning;
  6946. }
  6947. nTempOffset = 0;
  6948. }
  6949. else
  6950. {
  6951. //
  6952. // Grab the directory from the listbox.
  6953. //
  6954. cch = GetDirectoryFromLB(szBasicPath, &nTempOffset);
  6955. if (pExpFile[0] == CHAR_BSLASH)
  6956. {
  6957. //
  6958. // If a directory from the root was given, put it
  6959. // immediately off the root (\\server\share or a:).
  6960. //
  6961. if (FAILED(StringCchCopy(szBasicPath + nTempOffset, ARRAYSIZE(szBasicPath) - nTempOffset - 1, pExpFile)))
  6962. {
  6963. nErrCode = OF_BUFFERTRUNCATED;
  6964. goto Warning;
  6965. }
  6966. }
  6967. else
  6968. {
  6969. //
  6970. // Tack the file to the end of the path.
  6971. //
  6972. if (FAILED(StringCchCopy(szBasicPath + cch, ARRAYSIZE(szBasicPath) - cch - 1, pExpFile)))
  6973. {
  6974. nErrCode = OF_BUFFERTRUNCATED;
  6975. goto Warning;
  6976. }
  6977. }
  6978. }
  6979. nFileOffset = ParseFileOld(szBasicPath, &nExtOffset, &nOldExt, FALSE, TRUE);
  6980. if (nFileOffset == PARSE_EMPTYSTRING)
  6981. {
  6982. if (_psv)
  6983. {
  6984. _psv->Refresh();
  6985. }
  6986. goto ReturnFromOKButtonPressed;
  6987. }
  6988. else if ((nFileOffset != PARSE_DIRECTORYNAME) &&
  6989. (_pOFN->Flags & OFN_NOVALIDATE))
  6990. {
  6991. if (_bSelIsObject)
  6992. {
  6993. _pOFN->nFileOffset = _pOFN->nFileExtension = 0;
  6994. }
  6995. else
  6996. {
  6997. _pOFN->nFileOffset = (WORD)(nFileOffset > 0 ? nFileOffset : lstrlen(szBasicPath)); // point at the NULL terminator in error cases
  6998. _pOFN->nFileExtension = (WORD)nOldExt;
  6999. }
  7000. StorePathOrFileSizeInOFN(_pOFN, szBasicPath);
  7001. bRet = TRUE;
  7002. goto ReturnFromOKButtonPressed;
  7003. }
  7004. else if (nFileOffset == PARSE_DIRECTORYNAME)
  7005. {
  7006. //
  7007. // See if it ends in slash.
  7008. //
  7009. if (nExtOffset > 0)
  7010. {
  7011. if (ISBACKSLASH(szBasicPath, nExtOffset - 1))
  7012. {
  7013. //
  7014. // "\\server\share\" and "c:\" keep the trailing backslash,
  7015. // all other paths remove the trailing backslash. Note that
  7016. // we don't remove the slash if the user typed the path directly
  7017. // (nTempOffset is 0 in that case).
  7018. //
  7019. if ((nExtOffset != 1) &&
  7020. (szBasicPath[nExtOffset - 2] != CHAR_COLON) &&
  7021. (nExtOffset != nTempOffset + 1))
  7022. {
  7023. szBasicPath[nExtOffset - 1] = CHAR_NULL;
  7024. }
  7025. }
  7026. else if ((szBasicPath[nExtOffset - 1] == CHAR_DOT) &&
  7027. ((szBasicPath[nExtOffset - 2] == CHAR_DOT) ||
  7028. ISBACKSLASH(szBasicPath, nExtOffset - 2)) &&
  7029. IsUNC(szBasicPath))
  7030. {
  7031. //
  7032. // Add a trailing slash to UNC paths ending with ".." or "\."
  7033. //
  7034. szBasicPath[nExtOffset] = CHAR_BSLASH;
  7035. szBasicPath[nExtOffset + 1] = CHAR_NULL;
  7036. }
  7037. }
  7038. //
  7039. // Fall through to Directory Checking.
  7040. //
  7041. }
  7042. else if (nFileOffset < 0)
  7043. {
  7044. nErrCode = nFileOffset;
  7045. //
  7046. // I don't recognize this, so try to jump there.
  7047. // This is where servers get processed.
  7048. //
  7049. if (JumpToPath(szBasicPath))
  7050. {
  7051. goto ReturnFromOKButtonPressed;
  7052. }
  7053. //
  7054. // Fall through to the rest of the processing to warn the user.
  7055. //
  7056. Warning:
  7057. if (bUNCName)
  7058. {
  7059. cch = lstrlen(szBasicPath) - 1;
  7060. if ((szBasicPath[cch] == CHAR_BSLASH) &&
  7061. (szBasicPath[cch - 1] == CHAR_DOT) &&
  7062. (ISBACKSLASH(szBasicPath, cch - 2)))
  7063. {
  7064. szBasicPath[cch - 2] = CHAR_NULL;
  7065. }
  7066. }
  7067. // For file names of form c:filename.txt , we hacked and changed it to c:.\filename.txt
  7068. // check for that hack and if so change the file name back as it was given by user.
  7069. else if ((nFileOffset == 2) && (szBasicPath[2] == CHAR_DOT))
  7070. {
  7071. StringCchCopyOverlap(szBasicPath + 2, ARRAYSIZE(szBasicPath) - 2, szBasicPath + 4);
  7072. }
  7073. // If the disk is not a floppy and they tell me there's no
  7074. // disk in the drive, don't believe them. Instead, put up the
  7075. // error message that they should have given us. (Note that the
  7076. // error message is checked first since checking the drive type
  7077. // is slower.)
  7078. //
  7079. //
  7080. // I will assume that if we get error 0 or 1 or removable
  7081. // that we will assume removable.
  7082. //
  7083. if (nErrCode == OF_ACCESSDENIED)
  7084. {
  7085. TCHAR szD[4];
  7086. szPathName[0] |= 0x60;
  7087. szD[0] = *szBasicPath;
  7088. szD[1] = CHAR_COLON;
  7089. szD[2] = CHAR_BSLASH;
  7090. szD[3] = 0;
  7091. if (bUNCName || GetDriveType(szD) <= DRIVE_REMOVABLE)
  7092. {
  7093. nErrCode = OF_NETACCESSDENIED;
  7094. }
  7095. }
  7096. if ((nErrCode == OF_WRITEPROTECTION) ||
  7097. (nErrCode == OF_DISKFULL) ||
  7098. (nErrCode == OF_DISKFULL2) ||
  7099. (nErrCode == OF_ACCESSDENIED))
  7100. {
  7101. szBasicPath[0] = szPathName[0];
  7102. }
  7103. HRESULT hr = E_FAIL;
  7104. if (_bSave)
  7105. {
  7106. hr = CheckForRestrictedFolder(pszFile, 0) ? S_FALSE : E_FAIL;
  7107. }
  7108. // we might only want use ShellItem's for some errors
  7109. if (FAILED(hr) && nErrCode != OF_BUFFERTRUNCATED/*&& (nErrCode == OF_FILENOTFOUND || (nErrCode == OF_PATHNOTFOUND))*/)
  7110. {
  7111. IShellItem *psi;
  7112. hr = _ParseShellItem(pszFile, &psi, TRUE);
  7113. if (S_OK == hr)
  7114. {
  7115. hr = _ProcessItemAsFile(psi);
  7116. psi->Release();
  7117. }
  7118. }
  7119. if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_CANCELLED))
  7120. {
  7121. // Special case
  7122. // If the error was ACCESS_DENIED in a save dialog.
  7123. if (_bSave && (nErrCode == OF_ACCESSDENIED))
  7124. {
  7125. // Ask if the user wants to switch to My Documents.
  7126. _SaveAccessDenied(pszFile);
  7127. }
  7128. else
  7129. {
  7130. InvalidFileWarningNew(_hwndDlg, pszFile, nErrCode);
  7131. }
  7132. }
  7133. else if (S_OK == hr)
  7134. {
  7135. bRet = TRUE;
  7136. }
  7137. goto ReturnFromOKButtonPressed;
  7138. }
  7139. //
  7140. // We either have a file pattern or a real file.
  7141. // If it's a UNC name
  7142. // (1) Fall through to file name testing
  7143. // Else if it's a directory
  7144. // (1) Add on default pattern
  7145. // (2) Act like it's a pattern (goto pattern (1))
  7146. // Else if it's a pattern
  7147. // (1) Update everything
  7148. // (2) display files in whatever dir we're now in
  7149. // Else if it's a file name!
  7150. // (1) Check out the syntax
  7151. // (2) End the dialog given OK
  7152. // (3) Beep/message otherwise
  7153. //
  7154. //
  7155. // Directory ?? this must succeed for relative paths.
  7156. // NOTE: It won't succeed for relative paths that walk off the root.
  7157. //
  7158. bIsDir = SetDirRetry(szBasicPath);
  7159. //
  7160. // We need to parse again in case SetDirRetry changed a UNC path to use
  7161. // a drive letter.
  7162. //
  7163. nFileOffset = ParseFileOld(szBasicPath, &nExtOffset, &nOldExt, FALSE, TRUE);
  7164. nTempOffset = nFileOffset;
  7165. if (bIsDir)
  7166. {
  7167. goto ReturnFromOKButtonPressed;
  7168. }
  7169. else if (IsUNC(szBasicPath))
  7170. {
  7171. //
  7172. // UNC Name.
  7173. //
  7174. bUNCName = TRUE;
  7175. }
  7176. else if (nFileOffset > 0)
  7177. {
  7178. TCHAR szBuf[MAX_PATH];
  7179. //
  7180. // There is a path in the string.
  7181. //
  7182. if ((nFileOffset > 1) &&
  7183. (szBasicPath[nFileOffset - 1] != CHAR_COLON) &&
  7184. (szBasicPath[nFileOffset - 2] != CHAR_COLON))
  7185. {
  7186. nTempOffset--;
  7187. }
  7188. GetCurrentDirectory(ARRAYSIZE(szBuf), szBuf);
  7189. ch = szBasicPath[nTempOffset];
  7190. szBasicPath[nTempOffset] = 0;
  7191. if (SetCurrentDirectory(szBasicPath))
  7192. {
  7193. SetCurrentDirectory(szBuf);
  7194. }
  7195. else
  7196. {
  7197. switch (GetLastError())
  7198. {
  7199. case (ERROR_NOT_READY) :
  7200. {
  7201. eCode = ECODE_BADDRIVE;
  7202. break;
  7203. }
  7204. default :
  7205. {
  7206. eCode = ECODE_BADPATH;
  7207. break;
  7208. }
  7209. }
  7210. }
  7211. szBasicPath[nTempOffset] = ch;
  7212. }
  7213. else if (nFileOffset == PARSE_DIRECTORYNAME)
  7214. {
  7215. TCHAR szD[4];
  7216. szD[0] = *szBasicPath;
  7217. szD[1] = CHAR_COLON;
  7218. szD[2] = CHAR_BSLASH;
  7219. szD[3] = 0;
  7220. if (PathFileExists(szD))
  7221. {
  7222. eCode = ECODE_BADPATH;
  7223. }
  7224. else
  7225. {
  7226. eCode = ECODE_BADDRIVE;
  7227. }
  7228. }
  7229. //
  7230. // Was there a path and did it fail?
  7231. //
  7232. if (!bUNCName &&
  7233. nFileOffset &&
  7234. eCode != ECODE_S_OK &&
  7235. (_pOFN->Flags & OFN_PATHMUSTEXIST))
  7236. {
  7237. if (eCode == ECODE_BADPATH)
  7238. {
  7239. nErrCode = OF_PATHNOTFOUND;
  7240. }
  7241. else if (eCode == ECODE_BADDRIVE)
  7242. {
  7243. TCHAR szD[4];
  7244. //
  7245. // We can get here without performing an OpenFile call. As
  7246. // such the szPathName can be filled with random garbage.
  7247. // Since we only need one character for the error message,
  7248. // set szPathName[0] to the drive letter.
  7249. //
  7250. szPathName[0] = szD[0] = *szBasicPath;
  7251. szD[1] = CHAR_COLON;
  7252. szD[2] = CHAR_BSLASH;
  7253. szD[3] = 0;
  7254. switch (GetDriveType(szD))
  7255. {
  7256. case (DRIVE_REMOVABLE) :
  7257. {
  7258. nErrCode = ERROR_NOT_READY;
  7259. break;
  7260. }
  7261. case (1) :
  7262. {
  7263. //
  7264. // Drive does not exist.
  7265. //
  7266. nErrCode = OF_NODRIVE;
  7267. break;
  7268. }
  7269. default :
  7270. {
  7271. nErrCode = OF_PATHNOTFOUND;
  7272. }
  7273. }
  7274. }
  7275. else
  7276. {
  7277. nErrCode = OF_FILENOTFOUND;
  7278. }
  7279. goto Warning;
  7280. }
  7281. // From here on out, if there's an error, set nFileOffset to some
  7282. // valid position in szBasicPath, so let's treat the string as one full filename
  7283. if (nFileOffset < 0)
  7284. nFileOffset = 0;
  7285. // nFileOffset still needs to be in range
  7286. ASSERT(nFileOffset < ARRAYSIZE(szBasicPath));
  7287. //
  7288. // Full pattern?
  7289. //
  7290. if (IsWild(szBasicPath + nFileOffset))
  7291. {
  7292. if (!bUNCName)
  7293. {
  7294. SetCurrentFilter(szBasicPath + nFileOffset, Flags);
  7295. if (nTempOffset)
  7296. {
  7297. szBasicPath[nTempOffset] = 0;
  7298. JumpToPath(szBasicPath, TRUE);
  7299. }
  7300. else if (_psv)
  7301. {
  7302. _psv->Refresh();
  7303. }
  7304. goto ReturnFromOKButtonPressed;
  7305. }
  7306. else
  7307. {
  7308. SetCurrentFilter(szBasicPath + nFileOffset, Flags);
  7309. szBasicPath[nFileOffset] = CHAR_NULL;
  7310. JumpToPath(szBasicPath);
  7311. goto ReturnFromOKButtonPressed;
  7312. }
  7313. }
  7314. if (PortName(szBasicPath + nFileOffset))
  7315. {
  7316. nErrCode = OF_PORTNAME;
  7317. goto Warning;
  7318. }
  7319. // In save as dialog check to see if the folder user trying to save a file is
  7320. // a restricted folder (Network Folder). if so bail out
  7321. if (_bSave && CheckForRestrictedFolder(szBasicPath, nFileOffset))
  7322. {
  7323. goto ReturnFromOKButtonPressed;
  7324. }
  7325. //
  7326. // Check if we've received a string in the form "C:filename.ext".
  7327. // If we have, convert it to the form "C:.\filename.ext". This is done
  7328. // because the kernel will search the entire path, ignoring the drive
  7329. // specification after the initial search. Making it include a slash
  7330. // causes kernel to only search at that location.
  7331. //
  7332. // Note: Only increment nExtOffset, not nFileOffset. This is done
  7333. // because only nExtOffset is used later, and nFileOffset can then be
  7334. // used at the Warning: label to determine if this hack has occurred,
  7335. // and thus it can strip out the ".\" when putting up the error.
  7336. //
  7337. if ((nFileOffset == 2) && (szBasicPath[1] == CHAR_COLON))
  7338. {
  7339. if (SUCCEEDED(StringCchCopyOverlap(szBasicPath + 4, ARRAYSIZE(szBasicPath) - 4, szBasicPath + 2)))
  7340. {
  7341. szBasicPath[2] = CHAR_DOT;
  7342. szBasicPath[3] = CHAR_BSLASH;
  7343. nExtOffset += 2;
  7344. }
  7345. else
  7346. {
  7347. // Not enough room in our buffer.
  7348. nErrCode = OF_BUFFERTRUNCATED;
  7349. goto Warning;
  7350. }
  7351. }
  7352. //
  7353. // Add the default extension unless filename ends with period or no
  7354. // default extension exists. If the file exists, consider asking
  7355. // permission to overwrite the file.
  7356. //
  7357. // NOTE: When no extension given, default extension is tried 1st.
  7358. // FindNameInView calls VerifyOpen before returning.
  7359. //
  7360. szPathName[0] = 0;
  7361. switch (FindNameInView(szBasicPath,
  7362. Flags,
  7363. szPathName,
  7364. nFileOffset,
  7365. nExtOffset,
  7366. &nErrCode))
  7367. {
  7368. case (FE_OUTOFMEM) :
  7369. case (FE_CHANGEDDIR) :
  7370. {
  7371. goto ReturnFromOKButtonPressed;
  7372. }
  7373. case (FE_TOOMANY) :
  7374. {
  7375. SetCursor(LoadCursor(NULL, IDC_ARROW));
  7376. CDMessageBox(_hwndDlg,
  7377. iszTooManyFiles,
  7378. MB_OK | MB_ICONEXCLAMATION,
  7379. szBasicPath);
  7380. goto ReturnFromOKButtonPressed;
  7381. }
  7382. default :
  7383. {
  7384. break;
  7385. }
  7386. }
  7387. switch (nErrCode)
  7388. {
  7389. case (0) :
  7390. {
  7391. if (!_ValidateSelectedFile(szPathName, &nErrCode))
  7392. {
  7393. if (nErrCode)
  7394. {
  7395. goto Warning;
  7396. }
  7397. else
  7398. {
  7399. goto ReturnFromOKButtonPressed;
  7400. }
  7401. }
  7402. break;
  7403. }
  7404. case (OF_SHARINGVIOLATION) :
  7405. {
  7406. //
  7407. // If the app is "share aware", fall through.
  7408. // Otherwise, ask the hook function.
  7409. //
  7410. if (!(_pOFN->Flags & OFN_SHAREAWARE))
  7411. {
  7412. if (_hSubDlg)
  7413. {
  7414. int nShareCode = CD_SendShareNotify(_hSubDlg,
  7415. _hwndDlg,
  7416. szPathName,
  7417. _pOFN,
  7418. _pOFI);
  7419. if (nShareCode == OFN_SHARENOWARN)
  7420. {
  7421. goto ReturnFromOKButtonPressed;
  7422. }
  7423. else if (nShareCode != OFN_SHAREFALLTHROUGH)
  7424. {
  7425. //
  7426. // They might not have handled the notification,
  7427. // so try the registered message.
  7428. //
  7429. nShareCode = CD_SendShareMsg(_hSubDlg, szPathName, _pOFI->ApiType);
  7430. if (nShareCode == OFN_SHARENOWARN)
  7431. {
  7432. goto ReturnFromOKButtonPressed;
  7433. }
  7434. else if (nShareCode != OFN_SHAREFALLTHROUGH)
  7435. {
  7436. goto Warning;
  7437. }
  7438. }
  7439. }
  7440. else
  7441. {
  7442. goto Warning;
  7443. }
  7444. }
  7445. break;
  7446. }
  7447. case (OF_FILENOTFOUND) :
  7448. case (OF_PATHNOTFOUND) :
  7449. {
  7450. if (!_bSave)
  7451. {
  7452. //
  7453. // The file or path wasn't found.
  7454. // If this is a save dialog, we're ok, but if it's not,
  7455. // we're toast.
  7456. //
  7457. if (_pOFN->Flags & OFN_FILEMUSTEXIST)
  7458. {
  7459. if (_pOFN->Flags & OFN_CREATEPROMPT)
  7460. {
  7461. int nCreateCode = CreateFileDlg(_hwndDlg, szBasicPath);
  7462. if (nCreateCode != IDYES)
  7463. {
  7464. goto ReturnFromOKButtonPressed;
  7465. }
  7466. }
  7467. else
  7468. {
  7469. goto Warning;
  7470. }
  7471. }
  7472. }
  7473. goto VerifyPath;
  7474. }
  7475. case (OF_BUFFERTRUNCATED) :
  7476. {
  7477. // The desired path was truncated because of the size of our internal buffers,
  7478. // meaning the pathname was over maxpath.
  7479. goto Warning;
  7480. }
  7481. default :
  7482. {
  7483. if (!_bSave)
  7484. {
  7485. goto Warning;
  7486. }
  7487. //
  7488. // The file doesn't exist. Can it be created? This is needed
  7489. // because there are many extended characters which are invalid
  7490. // which won't be caught by ParseFile.
  7491. //
  7492. // Two more good reasons: Write-protected disks & full disks.
  7493. //
  7494. // BUT, if they don't want the test creation, they can request
  7495. // that we not do it using the OFN_NOTESTFILECREATE flag. If
  7496. // they want to create files on a share that has
  7497. // create-but-no-modify privileges, they should set this flag
  7498. // but be ready for failures that couldn't be caught, such as
  7499. // no create privileges, invalid extended characters, a full
  7500. // disk, etc.
  7501. //
  7502. VerifyPath:
  7503. //
  7504. // Verify the path.
  7505. //
  7506. if (_pOFN->Flags & OFN_PATHMUSTEXIST)
  7507. {
  7508. if (!(_pOFN->Flags & OFN_NOTESTFILECREATE))
  7509. {
  7510. HANDLE hf = CreateFile(szBasicPath,
  7511. GENERIC_WRITE,
  7512. FILE_SHARE_READ | FILE_SHARE_WRITE,
  7513. NULL,
  7514. CREATE_NEW,
  7515. FILE_ATTRIBUTE_NORMAL,
  7516. NULL);
  7517. if (hf != INVALID_HANDLE_VALUE)
  7518. {
  7519. CloseHandle(hf);
  7520. //
  7521. // This test is here to see if we were able to
  7522. // create it, but couldn't delete it. If so,
  7523. // warn the user that the network admin has given
  7524. // him create-but-no-modify privileges. As such,
  7525. // the file has just been created, but we can't
  7526. // do anything with it, it's of 0 size.
  7527. //
  7528. if (!DeleteFile(szBasicPath))
  7529. {
  7530. nErrCode = OF_CREATENOMODIFY;
  7531. goto Warning;
  7532. }
  7533. }
  7534. else
  7535. {
  7536. //
  7537. // Unable to create it.
  7538. //
  7539. // If it's not write-protection, a full disk,
  7540. // network protection, or the user popping the
  7541. // drive door open, assume that the filename is
  7542. // invalid.
  7543. //
  7544. nErrCode = GetLastError();
  7545. switch (nErrCode)
  7546. {
  7547. case (OF_WRITEPROTECTION) :
  7548. case (OF_DISKFULL) :
  7549. case (OF_DISKFULL2) :
  7550. case (OF_NETACCESSDENIED) :
  7551. case (OF_ACCESSDENIED) :
  7552. {
  7553. break;
  7554. }
  7555. default :
  7556. {
  7557. nErrCode = 0;
  7558. break;
  7559. }
  7560. }
  7561. goto Warning;
  7562. }
  7563. }
  7564. }
  7565. }
  7566. }
  7567. DWORD dwError;
  7568. nFileOffset = _CopyFileNameToOFN(szPathName, &dwError);
  7569. ASSERT(nFileOffset >= 0 && nFileOffset < ARRAYSIZE(szPathName));
  7570. _CopyTitleToOFN(szPathName + nFileOffset);
  7571. if (dwError == 0)
  7572. {
  7573. // Only PostProcess if there was no error in copying the info to the OFN struct.
  7574. _PostProcess(szPathName);
  7575. }
  7576. bRet = TRUE;
  7577. ReturnFromOKButtonPressed:
  7578. EnableModelessSB(TRUE);
  7579. if (pFree)
  7580. LocalFree(pFree);
  7581. return (bRet);
  7582. }
  7583. void CFileOpenBrowser::_CopyTitleToOFN(LPCTSTR pszTitle)
  7584. {
  7585. //
  7586. // File Title.
  7587. // Note that it's cut off at whatever the buffer length
  7588. // is, so if the buffer's too small, no notice is given.
  7589. // (Notice is only given to the app if lpstrFile is of insufficient size).
  7590. //
  7591. if (_pOFN->lpstrFileTitle)
  7592. {
  7593. StringCchCopy(_pOFN->lpstrFileTitle, _pOFN->nMaxFileTitle, pszTitle);
  7594. }
  7595. }
  7596. int CFileOpenBrowser::_CopyFileNameToOFN(LPTSTR pszFile, DWORD *pdwError)
  7597. {
  7598. int nExtOffset, nOldExt, nFileOffset = ParseFileOld(pszFile, &nExtOffset, &nOldExt, FALSE, TRUE);
  7599. //NULL can be passed in to this function if we don't care about the error condition!
  7600. if (pdwError)
  7601. *pdwError = 0; //Assume no error.
  7602. _pOFN->nFileOffset = (WORD) (nFileOffset > 0 ? nFileOffset : lstrlen(pszFile)); // point at the NULL terminator in error cases
  7603. _pOFN->nFileExtension = (WORD) nOldExt;
  7604. _pOFN->Flags &= ~OFN_EXTENSIONDIFFERENT;
  7605. if (_pOFN->lpstrDefExt && _pOFN->nFileExtension)
  7606. {
  7607. WCHAR szPrivateExt[4];
  7608. //
  7609. // Check against _pOFN->lpstrDefExt, not _pszDefExt.
  7610. //
  7611. StringCchCopy(szPrivateExt, ARRAYSIZE(szPrivateExt), _pOFN->lpstrDefExt); // truncation desired
  7612. if (lstrcmpi(szPrivateExt, pszFile + nOldExt))
  7613. {
  7614. _pOFN->Flags |= OFN_EXTENSIONDIFFERENT;
  7615. }
  7616. }
  7617. if (_pOFN->lpstrFile)
  7618. {
  7619. DWORD cch = lstrlen(pszFile) + 1;
  7620. if (_pOFN->Flags & OFN_ALLOWMULTISELECT)
  7621. {
  7622. //
  7623. // Extra room for double-NULL.
  7624. //
  7625. ++cch;
  7626. }
  7627. if (cch <= _pOFN->nMaxFile)
  7628. {
  7629. EVAL(SUCCEEDED(StringCchCopy(_pOFN->lpstrFile, _pOFN->nMaxFile, pszFile))); // We've already verified there's enough room.
  7630. if (_pOFN->Flags & OFN_ALLOWMULTISELECT)
  7631. {
  7632. //
  7633. // Double-NULL terminate.
  7634. //
  7635. *(_pOFN->lpstrFile + cch - 1) = CHAR_NULL;
  7636. }
  7637. if (!(_pOFN->Flags & OFN_NOCHANGEDIR) && !PathIsUNC(pszFile) && (nFileOffset > 0))
  7638. {
  7639. TCHAR ch = _pOFN->lpstrFile[nFileOffset];
  7640. _pOFN->lpstrFile[nFileOffset] = CHAR_NULL;
  7641. SetCurrentDirectory(_pOFN->lpstrFile);
  7642. _pOFN->lpstrFile[nFileOffset] = ch;
  7643. }
  7644. }
  7645. else
  7646. {
  7647. //
  7648. // Buffer is too small, so return the size of the buffer
  7649. // required to hold the string.
  7650. //
  7651. StoreFileSizeInOFN(_pOFN, cch);
  7652. if (pdwError)
  7653. *pdwError = FNERR_BUFFERTOOSMALL; //This is an error!
  7654. }
  7655. }
  7656. return nFileOffset;
  7657. }
  7658. HRESULT CFileOpenBrowser::_MakeFakeCopy(IShellItem *psi, LPWSTR *ppszPath)
  7659. {
  7660. //
  7661. // now we have to create a temp file
  7662. // to pass back to the client.
  7663. // we will do this in the internet cache.
  7664. //
  7665. // FEATURE - this should be a service in shell32 - zekel 11-AUG-98
  7666. // we should create a dependancy on wininet from
  7667. // comdlg32. this should really be some sort of
  7668. // service in shell32 that we call. CreateShellItemTempFile()..
  7669. //
  7670. ILocalCopy *plc;
  7671. HRESULT hr = psi->BindToHandler(NULL, BHID_LocalCopyHelper, IID_PPV_ARG(ILocalCopy, &plc));
  7672. if (SUCCEEDED(hr))
  7673. {
  7674. IBindCtx *pbc = NULL;
  7675. // hr = SIAddBindCtxOfProgressUI(_hwndDlg, NULL, NULL, &pbc);
  7676. if (SUCCEEDED(hr))
  7677. {
  7678. hr = plc->Download(LCDOWN_READONLY, pbc, ppszPath);
  7679. }
  7680. plc->Release();
  7681. }
  7682. return hr;
  7683. }
  7684. class CAsyncParseHelper
  7685. {
  7686. public:
  7687. CAsyncParseHelper(IUnknown *punkSite, IBindCtx *pbc);
  7688. STDMETHODIMP_(ULONG) AddRef()
  7689. {
  7690. return InterlockedIncrement(&_cRef);
  7691. }
  7692. STDMETHODIMP_(ULONG) Release()
  7693. {
  7694. ASSERT( 0 != _cRef );
  7695. ULONG cRef = InterlockedDecrement(&_cRef);
  7696. if ( 0 == cRef )
  7697. {
  7698. delete this;
  7699. }
  7700. return cRef;
  7701. }
  7702. HRESULT ParseAsync(IShellFolder *psf, LPCWSTR pszName, LPITEMIDLIST *ppidl, ULONG *pdwAttribs);
  7703. protected: // methods
  7704. ~CAsyncParseHelper();
  7705. static DWORD WINAPI CAsyncParseHelper::s_ThreadProc(void *pv);
  7706. HRESULT _Prepare(IShellFolder *psf, LPCWSTR pszName);
  7707. HRESULT _GetFolder(IShellFolder **ppsf);
  7708. void _Parse();
  7709. HRESULT _Pump();
  7710. protected: // members
  7711. LONG _cRef;
  7712. IUnknown *_punkSite;
  7713. IBindCtx *_pbc;
  7714. LPWSTR _pszName;
  7715. DWORD _dwAttribs;
  7716. HWND _hwnd;
  7717. HANDLE _hEvent;
  7718. LPITEMIDLIST _pidl;
  7719. HRESULT _hrParse;
  7720. IShellFolder *_psfFree; // is alright dropping between threads
  7721. LPITEMIDLIST _pidlFolder; // bind to it in the right thread
  7722. };
  7723. CAsyncParseHelper::~CAsyncParseHelper()
  7724. {
  7725. if (_pszName)
  7726. LocalFree(_pszName);
  7727. if (_punkSite)
  7728. _punkSite->Release();
  7729. if (_psfFree)
  7730. _psfFree->Release();
  7731. if (_pbc)
  7732. _pbc->Release();
  7733. if (_hEvent)
  7734. CloseHandle(_hEvent);
  7735. ILFree(_pidl);
  7736. ILFree(_pidlFolder);
  7737. }
  7738. CAsyncParseHelper::CAsyncParseHelper(IUnknown *punkSite, IBindCtx *pbc)
  7739. : _cRef(1), _hrParse(E_UNEXPECTED)
  7740. {
  7741. if (punkSite)
  7742. {
  7743. _punkSite = punkSite;
  7744. punkSite->AddRef();
  7745. IUnknown_GetWindow(_punkSite, &_hwnd);
  7746. }
  7747. if (pbc)
  7748. {
  7749. _pbc = pbc;
  7750. pbc->AddRef();
  7751. }
  7752. }
  7753. HRESULT CAsyncParseHelper::_GetFolder(IShellFolder **ppsf)
  7754. {
  7755. HRESULT hr;
  7756. if (_psfFree)
  7757. {
  7758. _psfFree->AddRef();
  7759. *ppsf = _psfFree;
  7760. hr = S_OK;
  7761. }
  7762. else if (_pidlFolder)
  7763. {
  7764. hr = SHBindToObjectEx(NULL, _pidlFolder, NULL, IID_PPV_ARG(IShellFolder, ppsf));
  7765. }
  7766. else
  7767. hr = SHGetDesktopFolder(ppsf);
  7768. return hr;
  7769. }
  7770. void CAsyncParseHelper::_Parse()
  7771. {
  7772. IShellFolder *psf;
  7773. _hrParse = _GetFolder(&psf);
  7774. if (SUCCEEDED(_hrParse))
  7775. {
  7776. _hrParse = IShellFolder_ParseDisplayName(psf, _hwnd, _pbc, _pszName, NULL, &_pidl, _dwAttribs ? &_dwAttribs : NULL);
  7777. psf->Release();
  7778. }
  7779. SetEvent(_hEvent);
  7780. }
  7781. DWORD WINAPI CAsyncParseHelper::s_ThreadProc(void *pv)
  7782. {
  7783. CAsyncParseHelper *paph = (CAsyncParseHelper *)pv;
  7784. paph->_Parse();
  7785. paph->Release();
  7786. return 0;
  7787. }
  7788. HRESULT CAsyncParseHelper::_Prepare(IShellFolder *psf, LPCWSTR pszName)
  7789. {
  7790. _pszName = StrDupW(pszName);
  7791. _hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  7792. HRESULT hr = _pszName && _hEvent ? S_OK : E_OUTOFMEMORY;
  7793. if (SUCCEEDED(hr) && psf)
  7794. {
  7795. IPersistFreeThreadedObject *pfto;
  7796. hr = psf->QueryInterface(IID_PPV_ARG(IPersistFreeThreadedObject, &pfto));
  7797. if (SUCCEEDED(hr))
  7798. {
  7799. _psfFree = psf;
  7800. psf->AddRef();
  7801. pfto->Release();
  7802. }
  7803. else
  7804. {
  7805. hr = SHGetIDListFromUnk(psf, &_pidlFolder);
  7806. }
  7807. }
  7808. return hr;
  7809. }
  7810. HRESULT CAsyncParseHelper::ParseAsync(IShellFolder *psf, LPCWSTR pszName, LPITEMIDLIST *ppidl, ULONG *pdwAttribs)
  7811. {
  7812. HRESULT hr = _Prepare(psf, pszName);
  7813. if (pdwAttribs)
  7814. _dwAttribs = *pdwAttribs;
  7815. // take one for the thread
  7816. AddRef();
  7817. if (SUCCEEDED(hr) && SHCreateThread(CAsyncParseHelper::s_ThreadProc, this, CTF_COINIT, NULL))
  7818. {
  7819. // lets go modal
  7820. IUnknown_EnableModeless(_punkSite, FALSE);
  7821. hr = _Pump();
  7822. IUnknown_EnableModeless(_punkSite, TRUE);
  7823. if (SUCCEEDED(hr))
  7824. {
  7825. ASSERT(_pidl);
  7826. *ppidl = _pidl;
  7827. _pidl = NULL;
  7828. if (pdwAttribs)
  7829. *pdwAttribs = _dwAttribs;
  7830. }
  7831. else
  7832. {
  7833. ASSERT(!_pidl);
  7834. }
  7835. }
  7836. else
  7837. {
  7838. // release because the thread wont
  7839. Release();
  7840. // hr = IShellFolder_ParseDisplayName(_psf, _hwnd, _pbc, pszName, NULL, ppidl, pdwAttribs);
  7841. }
  7842. if (FAILED(hr))
  7843. *ppidl = NULL;
  7844. return hr;
  7845. }
  7846. HRESULT CAsyncParseHelper::_Pump()
  7847. {
  7848. BOOL fCancelled = FALSE;
  7849. while (!fCancelled)
  7850. {
  7851. DWORD dwWaitResult = MsgWaitForMultipleObjects(1, &_hEvent, FALSE,
  7852. INFINITE, QS_ALLINPUT);
  7853. if (dwWaitResult != (DWORD)-1)
  7854. {
  7855. if (dwWaitResult == WAIT_OBJECT_0)
  7856. {
  7857. // our event was triggered
  7858. // that means that we have finished
  7859. break;
  7860. }
  7861. else
  7862. {
  7863. // there is a message
  7864. MSG msg;
  7865. // There was some message put in our queue, so we need to dispose
  7866. // of it
  7867. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  7868. {
  7869. // maybe there should be a flag to allow this??
  7870. if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
  7871. {
  7872. fCancelled = TRUE;
  7873. break;
  7874. }
  7875. else
  7876. {
  7877. TranslateMessage(&msg);
  7878. DispatchMessage(&msg);
  7879. }
  7880. if (g_bUserPressedCancel)
  7881. {
  7882. fCancelled = TRUE;
  7883. break;
  7884. }
  7885. }
  7886. }
  7887. }
  7888. else
  7889. {
  7890. ASSERT(FAILED(_hrParse));
  7891. break;
  7892. }
  7893. }
  7894. if (fCancelled)
  7895. {
  7896. // Better NULL the pidl out. ParseAsync expects a NULL _pidl if _Pump returns an error code.
  7897. ILFree(_pidl);
  7898. _pidl = NULL;
  7899. // clear this for the parse
  7900. g_bUserPressedCancel = FALSE;
  7901. return HRESULT_FROM_WIN32(ERROR_CANCELLED);
  7902. }
  7903. else
  7904. return _hrParse;
  7905. }
  7906. STDAPI SHParseNameAsync(IShellFolder *psf, IBindCtx *pbc, LPCWSTR pszName, IUnknown *punkSite, LPITEMIDLIST *ppidl, DWORD *pdwAttribs)
  7907. {
  7908. HRESULT hr = E_OUTOFMEMORY;
  7909. CAsyncParseHelper *paph = new CAsyncParseHelper(punkSite, pbc);
  7910. if (paph)
  7911. {
  7912. hr = paph->ParseAsync(psf, pszName, ppidl, pdwAttribs);
  7913. paph->Release();
  7914. }
  7915. return hr;
  7916. }
  7917. //
  7918. // _ParseName()
  7919. // psf = the shell folder to bind/parse with if NULL, use desktop
  7920. // pszIn= the string that should parsed into a ppmk
  7921. // ppmk = the IShellItem * that is returned with S_OK
  7922. //
  7923. // WARNING: this will jumpto a folder if that was what was passed in...
  7924. //
  7925. // returns S_OK if it got an IShellItem for the item with the specified folder
  7926. // S_FALSE if it was the wrong shellfolder; try again with a different one
  7927. // ERROR for any problems
  7928. //
  7929. HRESULT CFileOpenBrowser::_ParseName(LPCITEMIDLIST pidlParent, IShellFolder *psf, IBindCtx *pbc, LPCOLESTR psz, IShellItem **ppsi)
  7930. {
  7931. IBindCtx *pbcLocal;
  7932. HRESULT hr = BindCtx_RegisterObjectParam(pbc, STR_PARSE_PREFER_FOLDER_BROWSING, SAFECAST(this, IShellBrowser *), &pbcLocal);
  7933. *ppsi = NULL;
  7934. if (SUCCEEDED(hr))
  7935. {
  7936. LPITEMIDLIST pidl = NULL;
  7937. hr = SHParseNameAsync(psf, pbcLocal, psz, SAFECAST(this, IShellBrowser *), &pidl, NULL);
  7938. if (SUCCEEDED(hr))
  7939. {
  7940. ASSERT(pidl);
  7941. hr = SHCreateShellItem(pidlParent, pidlParent ? psf : NULL, pidl, ppsi);
  7942. ILFree(pidl);
  7943. }
  7944. else if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
  7945. {
  7946. hr = S_FALSE;
  7947. }
  7948. else if (psf && !pbc)
  7949. {
  7950. if (SUCCEEDED(pbcLocal->RegisterObjectParam(STR_DONT_PARSE_RELATIVE, psf)))
  7951. {
  7952. // try to hit it from the desktop
  7953. HRESULT hrNew = _ParseName(NULL, NULL, pbcLocal, psz, ppsi);
  7954. // else prop back the original error
  7955. hr = SUCCEEDED(hrNew) ? hrNew : hr;
  7956. }
  7957. }
  7958. pbcLocal->Release();
  7959. }
  7960. return hr;
  7961. }
  7962. BOOL CFileOpenBrowser::_OpenAsContainer(IShellItem *psi, SFGAOF sfgao)
  7963. {
  7964. BOOL fRet = _bSave ? _IsSaveContainer(sfgao) : _IsOpenContainer(sfgao);
  7965. if (fRet && (sfgao & SFGAO_STREAM))
  7966. {
  7967. // this is really both a folder and a file
  7968. // we guess which the caller wants by looking
  7969. // at the extension
  7970. LPWSTR psz;
  7971. if (SUCCEEDED(psi->GetDisplayName(SIGDN_PARENTRELATIVEPARSING, &psz)))
  7972. {
  7973. // if the filter equals what ever we are looking at
  7974. // we assume the caller is actually looking for
  7975. // this file.
  7976. fRet = !PathMatchSpec(psz, _szLastFilter);
  7977. CoTaskMemFree(psz);
  7978. }
  7979. }
  7980. return fRet;
  7981. }
  7982. HRESULT CFileOpenBrowser::_TestShellItem(IShellItem *psi, BOOL fAllowJump, IShellItem **ppsiReal)
  7983. {
  7984. SFGAOF flags;
  7985. psi->GetAttributes(SFGAO_STORAGECAPMASK, &flags);
  7986. HRESULT hr = E_ACCESSDENIED;
  7987. *ppsiReal = NULL;
  7988. if (_OpenAsContainer(psi, flags))
  7989. {
  7990. // we have a subfolder that has been selected.
  7991. // jumpto it instead
  7992. if (fAllowJump)
  7993. {
  7994. LPITEMIDLIST pidl;
  7995. if (SUCCEEDED(SHGetIDListFromUnk(psi, &pidl)))
  7996. {
  7997. JumpToIDList(pidl);
  7998. ILFree(pidl);
  7999. }
  8000. }
  8001. hr = S_FALSE;
  8002. }
  8003. else if ((flags & SFGAO_LINK) && ((flags & SFGAO_FOLDER) || !_IsNoDereferenceLinks(NULL, psi)))
  8004. {
  8005. // If this is a link, and (we should dereference links, or it's also a folder [folder shortcut])
  8006. IShellItem *psiTarget;
  8007. if (SUCCEEDED(psi->BindToHandler(NULL, BHID_LinkTargetItem, IID_PPV_ARG(IShellItem, &psiTarget))))
  8008. {
  8009. hr = _TestShellItem(psiTarget, fAllowJump, ppsiReal);
  8010. psiTarget->Release();
  8011. }
  8012. }
  8013. else if (_IsStream(flags))
  8014. {
  8015. *ppsiReal = psi;
  8016. psi->AddRef();
  8017. hr = S_OK;
  8018. }
  8019. return hr;
  8020. }
  8021. HRESULT CFileOpenBrowser::_ParseNameAndTest(LPCOLESTR pszIn, IBindCtx *pbc, IShellItem **ppsi, BOOL fAllowJump)
  8022. {
  8023. IShellItem *psi;
  8024. HRESULT hr = _ParseName(_pCurrentLocation->pidlFull, _psfCurrent, pbc, pszIn, &psi);
  8025. if (S_OK == hr)
  8026. {
  8027. hr = _TestShellItem(psi, fAllowJump, ppsi);
  8028. psi->Release();
  8029. }
  8030. return hr;
  8031. }
  8032. BOOL _FailedBadPath(HRESULT hr)
  8033. {
  8034. switch (hr)
  8035. {
  8036. case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
  8037. case HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND):
  8038. case HRESULT_FROM_WIN32(ERROR_BAD_NET_NAME):
  8039. case HRESULT_FROM_WIN32(ERROR_BAD_NETPATH):
  8040. return TRUE;
  8041. }
  8042. return FALSE;
  8043. }
  8044. #define STR_ACTIONPROGRESS L"ActionProgress"
  8045. STDAPI BindCtx_BeginActionProgress(IBindCtx *pbc, SPACTION action, SPBEGINF flags, IActionProgress **ppap)
  8046. {
  8047. HRESULT hr = E_NOINTERFACE; // default to no
  8048. IUnknown *punk;
  8049. *ppap = NULL;
  8050. if (pbc && SUCCEEDED(pbc->GetObjectParam(STR_ACTIONPROGRESS, &punk)))
  8051. {
  8052. IActionProgress *pap;
  8053. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IActionProgress, &pap))))
  8054. {
  8055. hr = pap->Begin(action, flags);
  8056. if (SUCCEEDED(hr))
  8057. *ppap = pap;
  8058. else
  8059. pap->Release();
  8060. }
  8061. punk->Release();
  8062. }
  8063. return hr;
  8064. }
  8065. HRESULT CFileOpenBrowser::_ParseShellItem(LPCOLESTR pszIn, IShellItem **ppsi, BOOL fAllowJump)
  8066. {
  8067. WAIT_CURSOR w(this);
  8068. EnableModelessSB(FALSE);
  8069. HRESULT hr = _ParseNameAndTest(pszIn, NULL, ppsi, fAllowJump);
  8070. if (_FailedBadPath(hr))
  8071. {
  8072. // If no extension was included, and we have a default extension, try it with that.
  8073. WCHAR szPath[MAX_PATH];
  8074. if ((LPTSTR)_pszDefExt && (0 == *(PathFindExtension(pszIn))))
  8075. {
  8076. if (SUCCEEDED(StringCchCopy(szPath, ARRAYSIZE(szPath), pszIn)))
  8077. {
  8078. if (AppendExt(szPath, ARRAYSIZE(szPath), _pszDefExt, FALSE))
  8079. {
  8080. pszIn = szPath;
  8081. hr = _ParseNameAndTest(pszIn, NULL, ppsi, fAllowJump);
  8082. }
  8083. }
  8084. }
  8085. if (_FailedBadPath(hr) && _bSave)
  8086. {
  8087. // when we are saving, then we
  8088. // try to force the creation of this item
  8089. IBindCtx *pbc;
  8090. if (SUCCEEDED(CreateBindCtx(0, &pbc)))
  8091. {
  8092. BIND_OPTS bo = {0};
  8093. bo.cbStruct = SIZEOF(bo);
  8094. bo.grfMode = STGM_CREATE;
  8095. pbc->SetBindOptions(&bo);
  8096. hr = _ParseNameAndTest(pszIn, pbc, ppsi, fAllowJump);
  8097. pbc->Release();
  8098. }
  8099. }
  8100. }
  8101. EnableModelessSB(TRUE);
  8102. return hr;
  8103. }
  8104. class CShellItemList : IEnumShellItems
  8105. {
  8106. public:
  8107. CShellItemList() : _cRef(1) {}
  8108. // IUnknown methods
  8109. STDMETHODIMP QueryInterface(REFIID riid, void **ppvOut);
  8110. STDMETHODIMP_(ULONG) AddRef();
  8111. STDMETHODIMP_(ULONG) Release();
  8112. STDMETHODIMP Next(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched);
  8113. STDMETHODIMP Skip(ULONG celt);
  8114. STDMETHODIMP Reset();
  8115. STDMETHODIMP Clone(IEnumShellItems **ppenum);
  8116. HRESULT Add(IShellItem *psi);
  8117. private: // methods
  8118. ~CShellItemList();
  8119. BOOL _NextOne(IShellItem **ppsi);
  8120. private: // members
  8121. LONG _cRef;
  8122. CDPA<IShellItem> _dpaItems;
  8123. int _iItem;
  8124. };
  8125. STDMETHODIMP CShellItemList::QueryInterface(REFIID riid, void **ppv)
  8126. {
  8127. static const QITAB qit[] =
  8128. {
  8129. QITABENT(CShellItemList, IEnumShellItems),
  8130. { 0 },
  8131. };
  8132. return QISearch(this, qit, riid, ppv);
  8133. }
  8134. STDMETHODIMP_(ULONG) CShellItemList::AddRef()
  8135. {
  8136. return InterlockedIncrement(&_cRef);
  8137. }
  8138. STDMETHODIMP_(ULONG) CShellItemList::Release()
  8139. {
  8140. ASSERT( 0 != _cRef );
  8141. ULONG cRef = InterlockedDecrement(&_cRef);
  8142. if ( 0 == cRef )
  8143. {
  8144. delete this;
  8145. }
  8146. return cRef;
  8147. }
  8148. STDMETHODIMP CShellItemList::Next(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched)
  8149. {
  8150. HRESULT hr = S_FALSE;
  8151. ULONG cFetched = 0;
  8152. while (celt-- && SUCCEEDED(hr))
  8153. {
  8154. if (_NextOne(&rgelt[cFetched]))
  8155. cFetched++;
  8156. else
  8157. break;
  8158. }
  8159. if (cFetched)
  8160. {
  8161. *pceltFetched = cFetched;
  8162. hr = S_OK;
  8163. }
  8164. else
  8165. hr = S_FALSE;
  8166. return hr;
  8167. }
  8168. STDMETHODIMP CShellItemList::Skip(ULONG celt)
  8169. {
  8170. _iItem += celt;
  8171. return S_OK;
  8172. }
  8173. STDMETHODIMP CShellItemList::Reset()
  8174. {
  8175. _iItem = 0;
  8176. return S_OK;
  8177. }
  8178. STDMETHODIMP CShellItemList::Clone(IEnumShellItems **ppenum)
  8179. {
  8180. return E_NOTIMPL;
  8181. }
  8182. HRESULT CShellItemList::Add(IShellItem *psi)
  8183. {
  8184. HRESULT hr = E_OUTOFMEMORY;
  8185. if (!_dpaItems)
  8186. {
  8187. _dpaItems.Create(4);
  8188. }
  8189. if (_dpaItems)
  8190. {
  8191. if (-1 != _dpaItems.AppendPtr(psi))
  8192. {
  8193. psi->AddRef();
  8194. hr = S_OK;
  8195. }
  8196. }
  8197. return hr;
  8198. }
  8199. CShellItemList::~CShellItemList()
  8200. {
  8201. if (_dpaItems)
  8202. {
  8203. for (int i = 0; i < _dpaItems.GetPtrCount(); i++)
  8204. {
  8205. _dpaItems.FastGetPtr(i)->Release();
  8206. }
  8207. _dpaItems.Destroy();
  8208. }
  8209. }
  8210. BOOL CShellItemList::_NextOne(IShellItem **ppsi)
  8211. {
  8212. if (_dpaItems && _iItem < _dpaItems.GetPtrCount())
  8213. {
  8214. *ppsi = _dpaItems.GetPtr(_iItem);
  8215. if (*ppsi)
  8216. {
  8217. (*ppsi)->AddRef();
  8218. _iItem++;
  8219. return TRUE;
  8220. }
  8221. }
  8222. return FALSE;
  8223. }
  8224. #ifdef RETURN_SHELLITEMS
  8225. HRESULT CFileOpenBrowser::_ItemOKButtonPressed(LPCWSTR pszFile, OKBUTTONFLAGS Flags)
  8226. {
  8227. CShellItemList *psil = new CShellItemList();
  8228. HRESULT hr = psil ? S_OK : E_OUTOFMEMORY;
  8229. ASSERT(IS_NEW_OFN(_pOFN));
  8230. if (SUCCEEDED(hr))
  8231. {
  8232. SHSTR str;
  8233. hr = str.SetSize(lstrlen(pszFile) * 2);
  8234. if (SUCCEEDED(hr))
  8235. {
  8236. WAIT_CURSOR w(this);
  8237. DWORD cFiles = 1;
  8238. SHExpandEnvironmentStrings(pszFile, str, str.GetSize());
  8239. if ((_pOFN->Flags & OFN_ALLOWMULTISELECT) && StrChr(str, CHAR_QUOTE))
  8240. {
  8241. // need to handle MULTISEL here...
  8242. // str points to a bunch of quoted strings.
  8243. // alloc enough for the strings and an extra NULL terminator
  8244. hr = str.SetSize(str.GetLen() + 1);
  8245. if (SUCCEEDED(hr))
  8246. {
  8247. cFiles = ConvertToNULLTerm(str);
  8248. }
  8249. }
  8250. if (SUCCEEDED(hr))
  8251. {
  8252. BOOL fSingle = cFiles == 1;
  8253. LPTSTR pch = str;
  8254. for (; cFiles; cFiles--)
  8255. {
  8256. IShellItem *psi;
  8257. hr = _ParseShellItem(pch, &psi, fSingle);
  8258. // go to the next item
  8259. if (S_OK == hr)
  8260. {
  8261. hr = psil->Add(psi);
  8262. psi->Release();
  8263. }
  8264. else // S_FALSE or failure we stop parsing
  8265. {
  8266. if (FAILED(hr))
  8267. InvalidFileWarningNew(_hwndDlg, pch, OFErrFromHresult(hr));
  8268. break;
  8269. }
  8270. // goto the next string
  8271. pch += lstrlen(pch) + 1;
  8272. }
  8273. // we have added everything to our list
  8274. if (hr == S_OK)
  8275. {
  8276. hr = psil->QueryInterface(IID_PPV_ARG(IEnumShellItems, &(_pOFN->penum)));
  8277. }
  8278. }
  8279. }
  8280. psil->Release();
  8281. }
  8282. return hr;
  8283. }
  8284. #endif RETURN_SHELLITEMS
  8285. ////////////////////////////////////////////////////////////////////////////
  8286. //
  8287. // DriveList_OpenClose
  8288. //
  8289. // Change the state of a drive list.
  8290. //
  8291. ////////////////////////////////////////////////////////////////////////////
  8292. #define OCDL_TOGGLE 0x0000
  8293. #define OCDL_OPEN 0x0001
  8294. #define OCDL_CLOSE 0x0002
  8295. void DriveList_OpenClose(
  8296. UINT uAction,
  8297. HWND hwndDriveList)
  8298. {
  8299. if (!hwndDriveList || !IsWindowVisible(hwndDriveList))
  8300. {
  8301. return;
  8302. }
  8303. OpenClose_TryAgain:
  8304. switch (uAction)
  8305. {
  8306. case (OCDL_TOGGLE) :
  8307. {
  8308. uAction = SendMessage(hwndDriveList, CB_GETDROPPEDSTATE, 0, 0L)
  8309. ? OCDL_CLOSE
  8310. : OCDL_OPEN;
  8311. goto OpenClose_TryAgain;
  8312. break;
  8313. }
  8314. case (OCDL_OPEN) :
  8315. {
  8316. SetFocus(hwndDriveList);
  8317. SendMessage(hwndDriveList, CB_SHOWDROPDOWN, TRUE, 0);
  8318. break;
  8319. }
  8320. case (OCDL_CLOSE) :
  8321. {
  8322. if (SHIsChildOrSelf(hwndDriveList,GetFocus()) == S_OK)
  8323. {
  8324. SendMessage(hwndDriveList, CB_SHOWDROPDOWN, FALSE, 0);
  8325. }
  8326. break;
  8327. }
  8328. }
  8329. }
  8330. ////////////////////////////////////////////////////////////////////////////
  8331. //
  8332. // CFileOpenBrowser::GetFullEditName
  8333. //
  8334. // Returns the number of characters needed to get the full path, including
  8335. // the NULL.
  8336. //
  8337. ////////////////////////////////////////////////////////////////////////////
  8338. UINT CFileOpenBrowser::GetFullEditName(
  8339. LPTSTR pszBuf,
  8340. UINT cchBuf,
  8341. TEMPSTR *pTempStr,
  8342. BOOL *pbNoDefExt)
  8343. {
  8344. UINT cTotalLen;
  8345. HWND hwndEdit;
  8346. if (_bUseHideExt)
  8347. {
  8348. cTotalLen = lstrlen(_pszHideExt) + 1;
  8349. }
  8350. else
  8351. {
  8352. if (_bUseCombo)
  8353. {
  8354. hwndEdit = (HWND)SendMessage(GetDlgItem(_hwndDlg, cmb13), CBEM_GETEDITCONTROL, 0, 0L);
  8355. }
  8356. else
  8357. {
  8358. hwndEdit = GetDlgItem(_hwndDlg, edt1);
  8359. }
  8360. cTotalLen = GetWindowTextLength(hwndEdit) + 1;
  8361. }
  8362. if (pTempStr)
  8363. {
  8364. if (!pTempStr->TSStrSize(cTotalLen))
  8365. {
  8366. return ((UINT)-1);
  8367. }
  8368. pszBuf = *pTempStr;
  8369. cchBuf = cTotalLen;
  8370. }
  8371. if (_bUseHideExt)
  8372. {
  8373. StringCchCopy(pszBuf, cchBuf, _pszHideExt); // Truncate, and return buffer size required.
  8374. }
  8375. else
  8376. {
  8377. GetWindowText(hwndEdit, pszBuf, cchBuf);
  8378. }
  8379. if (pbNoDefExt)
  8380. {
  8381. *pbNoDefExt = _bUseHideExt;
  8382. }
  8383. return (cTotalLen);
  8384. }
  8385. ////////////////////////////////////////////////////////////////////////////
  8386. //
  8387. // CFileOpenBrowser::ProcessEdit
  8388. //
  8389. ////////////////////////////////////////////////////////////////////////////
  8390. void CFileOpenBrowser::ProcessEdit()
  8391. {
  8392. TEMPSTR pMultiSel;
  8393. LPTSTR pszFile;
  8394. BOOL bNoDefExt = TRUE;
  8395. OKBUTTONFLAGS Flags = OKBUTTON_NONE;
  8396. TCHAR szBuf[MAX_PATH + 4];
  8397. //if we have a saved pidl then use it instead
  8398. if (_pidlSelection && _ProcessPidlSelection())
  8399. {
  8400. return;
  8401. }
  8402. if (_pOFN->Flags & OFN_ALLOWMULTISELECT)
  8403. {
  8404. if (GetFullEditName(szBuf,
  8405. ARRAYSIZE(szBuf),
  8406. &pMultiSel,
  8407. &bNoDefExt) == (UINT)-1)
  8408. {
  8409. //
  8410. // FEATURE There should be some error message here.
  8411. //
  8412. return;
  8413. }
  8414. pszFile = pMultiSel;
  8415. }
  8416. else
  8417. {
  8418. if (_bSelIsObject)
  8419. {
  8420. pszFile = _pszObjectPath;
  8421. }
  8422. else
  8423. {
  8424. GetFullEditName(szBuf, ARRAYSIZE(szBuf), NULL, &bNoDefExt);
  8425. pszFile = szBuf;
  8426. PathRemoveBlanks(pszFile);
  8427. int nLen = lstrlen(pszFile);
  8428. if (*pszFile == CHAR_QUOTE)
  8429. {
  8430. LPTSTR pPrev = CharPrev(pszFile, pszFile + nLen);
  8431. if (*pPrev == CHAR_QUOTE && pszFile != pPrev)
  8432. {
  8433. Flags |= OKBUTTON_QUOTED;
  8434. //
  8435. // Strip the quotes.
  8436. //
  8437. *pPrev = CHAR_NULL;
  8438. StringCopyOverlap(pszFile, pszFile + 1);
  8439. }
  8440. }
  8441. }
  8442. }
  8443. if (bNoDefExt)
  8444. {
  8445. Flags |= OKBUTTON_NODEFEXT;
  8446. }
  8447. //
  8448. // Visual Basic passes in an uninitialized lpDefExts string.
  8449. // Since we only have to use it in OKButtonPressed, update
  8450. // lpstrDefExts here along with whatever else is only needed
  8451. // in OKButtonPressed.
  8452. //
  8453. if (_pOFI->ApiType == COMDLG_ANSI)
  8454. {
  8455. ThunkOpenFileNameA2WDelayed(_pOFI);
  8456. }
  8457. // handle special case parsing right here.
  8458. // our current folder and the desktop both failed
  8459. // to figure out what this is.
  8460. if (PathIsDotOrDotDot(pszFile))
  8461. {
  8462. if (pszFile[1] == CHAR_DOT)
  8463. {
  8464. // this is ".."
  8465. LPITEMIDLIST pidl = GetIDListFromFolder(_psfCurrent);
  8466. if (pidl)
  8467. {
  8468. ILRemoveLastID(pidl);
  8469. JumpToIDList(pidl);
  8470. ILFree(pidl);
  8471. }
  8472. }
  8473. }
  8474. else if (OKButtonPressed(pszFile, Flags))
  8475. {
  8476. BOOL bReturn = TRUE;
  8477. if (_pOFN->lpstrFile)
  8478. {
  8479. if (!(_pOFN->Flags & OFN_NOVALIDATE))
  8480. {
  8481. if (_pOFN->nMaxFile >= 3)
  8482. {
  8483. if ((_pOFN->lpstrFile[0] == 0) ||
  8484. (_pOFN->lpstrFile[1] == 0) ||
  8485. (_pOFN->lpstrFile[2] == 0))
  8486. {
  8487. bReturn = FALSE;
  8488. StoreExtendedError(FNERR_BUFFERTOOSMALL);
  8489. }
  8490. }
  8491. else
  8492. {
  8493. bReturn = FALSE;
  8494. StoreExtendedError(FNERR_BUFFERTOOSMALL);
  8495. }
  8496. }
  8497. }
  8498. _CleanupDialog(bReturn);
  8499. }
  8500. }
  8501. ////////////////////////////////////////////////////////////////////////////
  8502. //
  8503. // CFileOpenBrowser::InitializeDropDown
  8504. //
  8505. ////////////////////////////////////////////////////////////////////////////
  8506. void CFileOpenBrowser::InitializeDropDown(HWND hwndCtl)
  8507. {
  8508. if (!_bDropped)
  8509. {
  8510. MYLISTBOXITEM *pParentItem;
  8511. SHChangeNotifyEntry fsne[2];
  8512. //
  8513. // Expand the Desktop item.
  8514. //
  8515. pParentItem = GetListboxItem(hwndCtl, _iNodeDesktop);
  8516. if (pParentItem)
  8517. {
  8518. UpdateLevel(hwndCtl, _iNodeDesktop + 1, pParentItem);
  8519. fsne[0].pidl = pParentItem->pidlFull;
  8520. fsne[0].fRecursive = FALSE;
  8521. //
  8522. // Look for the My Computer item, since it may not necessarily
  8523. // be the next one after the Desktop.
  8524. //
  8525. LPITEMIDLIST pidlDrives;
  8526. if (SHGetFolderLocation(NULL, CSIDL_DRIVES, NULL, 0, &pidlDrives) == S_OK)
  8527. {
  8528. int iNode = _iNodeDesktop;
  8529. while (pParentItem = GetListboxItem(hwndCtl, iNode))
  8530. {
  8531. if (ILIsEqual(pParentItem->pidlFull, pidlDrives))
  8532. {
  8533. _iNodeDrives = iNode;
  8534. break;
  8535. }
  8536. iNode++;
  8537. }
  8538. ILFree(pidlDrives);
  8539. }
  8540. //
  8541. // Make sure My Computer was found. If not, then just assume it's
  8542. // in the first spot after the desktop (this shouldn't happen).
  8543. //
  8544. if (pParentItem == NULL)
  8545. {
  8546. pParentItem = GetListboxItem(hwndCtl, _iNodeDesktop + 1);
  8547. _iNodeDrives = _iNodeDesktop +1;
  8548. }
  8549. if (pParentItem)
  8550. {
  8551. //
  8552. // Expand the My Computer item.
  8553. //
  8554. UpdateLevel(hwndCtl, _iNodeDrives + 1, pParentItem);
  8555. _bDropped = TRUE;
  8556. fsne[1].pidl = pParentItem->pidlFull;
  8557. fsne[1].fRecursive = FALSE;
  8558. }
  8559. _uRegister = SHChangeNotifyRegister(
  8560. _hwndDlg,
  8561. SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_NewDelivery,
  8562. SHCNE_ALLEVENTS &
  8563. ~(SHCNE_CREATE | SHCNE_DELETE | SHCNE_RENAMEITEM),
  8564. CDM_FSNOTIFY, pParentItem ? ARRAYSIZE(fsne) : ARRAYSIZE(fsne) - 1,
  8565. fsne);
  8566. }
  8567. }
  8568. }
  8569. ////////////////////////////////////////////////////////////////////////////
  8570. //
  8571. // CFileOpenBrowser::OnCommandMessage
  8572. //
  8573. // Process a WM_COMMAND message for the dialog.
  8574. //
  8575. ////////////////////////////////////////////////////////////////////////////
  8576. LRESULT CFileOpenBrowser::OnCommandMessage(
  8577. WPARAM wParam,
  8578. LPARAM lParam)
  8579. {
  8580. int idCmd = GET_WM_COMMAND_ID(wParam, lParam);
  8581. switch (idCmd)
  8582. {
  8583. case (edt1) :
  8584. {
  8585. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  8586. {
  8587. case (EN_CHANGE) :
  8588. {
  8589. _bUseHideExt = FALSE;
  8590. Pidl_Set(&_pidlSelection,NULL);;
  8591. break;
  8592. }
  8593. }
  8594. break;
  8595. }
  8596. case (cmb13) :
  8597. {
  8598. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  8599. {
  8600. case (CBN_EDITCHANGE) :
  8601. {
  8602. _bUseHideExt = FALSE;
  8603. Pidl_Set(&_pidlSelection,NULL);;
  8604. break;
  8605. }
  8606. case (CBN_DROPDOWN) :
  8607. {
  8608. LoadMRU(_szLastFilter,
  8609. GET_WM_COMMAND_HWND(wParam, lParam),
  8610. MAX_MRU);
  8611. break;
  8612. }
  8613. case (CBN_SETFOCUS) :
  8614. {
  8615. SetModeBias(MODEBIASMODE_FILENAME);
  8616. break;
  8617. }
  8618. case (CBN_KILLFOCUS) :
  8619. {
  8620. SetModeBias(MODEBIASMODE_DEFAULT);
  8621. break;
  8622. }
  8623. }
  8624. break;
  8625. }
  8626. case (cmb2) :
  8627. {
  8628. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  8629. {
  8630. case (CBN_CLOSEUP) :
  8631. {
  8632. OnSelChange();
  8633. UpdateNavigation();
  8634. SelectEditText(_hwndDlg);
  8635. return TRUE;
  8636. }
  8637. case (CBN_DROPDOWN) :
  8638. {
  8639. InitializeDropDown(GET_WM_COMMAND_HWND(wParam, lParam));
  8640. break;
  8641. }
  8642. }
  8643. break;
  8644. }
  8645. case (cmb1) :
  8646. {
  8647. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  8648. {
  8649. case (CBN_DROPDOWN) :
  8650. {
  8651. _iComboIndex = (int) SendMessage(GET_WM_COMMAND_HWND(wParam, lParam),
  8652. CB_GETCURSEL,
  8653. NULL,
  8654. NULL);
  8655. break;
  8656. }
  8657. //
  8658. // We're trying to see if anything changed after
  8659. // (and only after) the user is done scrolling through the
  8660. // drop down. When the user tabs away from the combobox, we
  8661. // do not get a CBN_SELENDOK.
  8662. // Why not just use CBN_SELCHANGE? Because then we'd refresh
  8663. // the view (very slow) as the user scrolls through the
  8664. // combobox.
  8665. //
  8666. case (CBN_CLOSEUP) :
  8667. case (CBN_SELENDOK) :
  8668. {
  8669. //
  8670. // Did anything change?
  8671. //
  8672. if (_iComboIndex >= 0 &&
  8673. _iComboIndex == SendMessage(GET_WM_COMMAND_HWND(wParam, lParam),
  8674. CB_GETCURSEL,
  8675. NULL,
  8676. NULL))
  8677. {
  8678. break;
  8679. }
  8680. }
  8681. case (MYCBN_DRAW) :
  8682. {
  8683. RefreshFilter(GET_WM_COMMAND_HWND(wParam, lParam));
  8684. _iComboIndex = -1;
  8685. return TRUE;
  8686. }
  8687. default :
  8688. {
  8689. break;
  8690. }
  8691. }
  8692. break;
  8693. }
  8694. case (IDC_PARENT) :
  8695. {
  8696. OnDotDot();
  8697. SelectEditText(_hwndDlg);
  8698. break;
  8699. }
  8700. case (IDC_NEWFOLDER) :
  8701. {
  8702. ViewCommand(VC_NEWFOLDER);
  8703. break;
  8704. }
  8705. case (IDC_VIEWLIST) :
  8706. {
  8707. SendMessage(_hwndView, WM_COMMAND, (WPARAM)SFVIDM_VIEW_LIST, 0);
  8708. break;
  8709. }
  8710. case (IDC_VIEWDETAILS) :
  8711. {
  8712. SendMessage(_hwndView, WM_COMMAND, (WPARAM)SFVIDM_VIEW_DETAILS,0);
  8713. break;
  8714. }
  8715. case (IDC_VIEWMENU) :
  8716. {
  8717. //
  8718. // Pass off the nCmdID to the view for processing / translation.
  8719. //
  8720. DFVCMDDATA cd;
  8721. cd.pva = NULL;
  8722. cd.hwnd = _hwndDlg;
  8723. cd.nCmdIDTranslated = 0;
  8724. SendMessage(_hwndView, WM_COMMAND, SFVIDM_VIEW_VIEWMENU, (LONG_PTR)&cd);
  8725. break;
  8726. }
  8727. case (IDOK) :
  8728. {
  8729. HWND hwndFocus = ::GetFocus();
  8730. if (hwndFocus == ::GetDlgItem(_hwndDlg, IDOK))
  8731. {
  8732. hwndFocus = _hwndLastFocus;
  8733. }
  8734. hwndFocus = GetFocusedChild(_hwndDlg, hwndFocus);
  8735. if (hwndFocus == _hwndView)
  8736. {
  8737. OnDblClick(TRUE);
  8738. }
  8739. else if (_hwndPlacesbar && (hwndFocus == _hwndPlacesbar))
  8740. {
  8741. //Places bar has the focus. Get the current hot item.
  8742. INT_PTR i = SendMessage(_hwndPlacesbar, TB_GETHOTITEM, 0,0);
  8743. if (i >= 0)
  8744. {
  8745. //Get the Pidl for this button.
  8746. TBBUTTONINFO tbbi;
  8747. tbbi.cbSize = SIZEOF(tbbi);
  8748. tbbi.lParam = 0;
  8749. tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX;
  8750. if (SendMessage(_hwndPlacesbar, TB_GETBUTTONINFO, i, (LPARAM)&tbbi) >= 0)
  8751. {
  8752. LPITEMIDLIST pidl= (LPITEMIDLIST)tbbi.lParam;
  8753. if (pidl)
  8754. {
  8755. //Jump to the location corresponding to this Button
  8756. JumpToIDList(pidl, FALSE, TRUE);
  8757. }
  8758. }
  8759. }
  8760. }
  8761. else
  8762. {
  8763. ProcessEdit();
  8764. }
  8765. SelectEditText(_hwndDlg);
  8766. break;
  8767. }
  8768. case (IDCANCEL) :
  8769. {
  8770. // the parse async can listen for this
  8771. g_bUserPressedCancel = TRUE;
  8772. _hwndModelessFocus = NULL;
  8773. if (!_cRefCannotNavigate)
  8774. {
  8775. _CleanupDialog(FALSE);
  8776. }
  8777. return TRUE;
  8778. }
  8779. case (pshHelp) :
  8780. {
  8781. if (_hSubDlg)
  8782. {
  8783. CD_SendHelpNotify(_hSubDlg, _hwndDlg, _pOFN, _pOFI);
  8784. }
  8785. if (_pOFN->hwndOwner)
  8786. {
  8787. CD_SendHelpMsg(_pOFN, _hwndDlg, _pOFI->ApiType);
  8788. }
  8789. break;
  8790. }
  8791. case (IDC_DROPDRIVLIST) : // VK_F4
  8792. {
  8793. //
  8794. // If focus is on the "File of type" combobox,
  8795. // then F4 should open that combobox, not the "Look in" one.
  8796. //
  8797. HWND hwnd = GetFocus();
  8798. if (_bUseCombo &&
  8799. (SHIsChildOrSelf(GetDlgItem(_hwndDlg, cmb13), hwnd) == S_OK)
  8800. )
  8801. {
  8802. hwnd = GetDlgItem(_hwndDlg, cmb13);
  8803. }
  8804. if ((hwnd != GetDlgItem(_hwndDlg, cmb1)) &&
  8805. (hwnd != GetDlgItem(_hwndDlg, cmb13))
  8806. )
  8807. {
  8808. //
  8809. // We shipped Win95 where F4 *always* opens the "Look in"
  8810. // combobox, so keep F4 opening that even when it shouldn't.
  8811. //
  8812. hwnd = GetDlgItem(_hwndDlg, cmb2);
  8813. }
  8814. DriveList_OpenClose(OCDL_TOGGLE, hwnd);
  8815. break;
  8816. }
  8817. case (IDC_REFRESH) :
  8818. {
  8819. if (_psv)
  8820. {
  8821. _psv->Refresh();
  8822. }
  8823. break;
  8824. }
  8825. case (IDC_PREVIOUSFOLDER) :
  8826. {
  8827. OnDotDot();
  8828. break;
  8829. }
  8830. //Back Navigation
  8831. case (IDC_BACK) :
  8832. // Try to travel in the directtion
  8833. if (_ptlog && SUCCEEDED(_ptlog->Travel(TRAVEL_BACK)))
  8834. {
  8835. LPITEMIDLIST pidl;
  8836. //Able to travel in the given direction.
  8837. //Now Get the new pidl
  8838. _ptlog->GetCurrent(&pidl);
  8839. //Update the UI to reflect the current state
  8840. UpdateUI(pidl);
  8841. //Jump to the new location
  8842. // second paremeter is whether to translate to logical pidl
  8843. // and third parameter is whether to add to the navigation stack
  8844. // since this pidl comes from the stack , we should not add this to
  8845. // the navigation stack
  8846. JumpToIDList(pidl, FALSE, FALSE);
  8847. ILFree(pidl);
  8848. }
  8849. break;
  8850. }
  8851. if ((idCmd >= IDC_PLACESBAR_BASE) && (idCmd <= (IDC_PLACESBAR_BASE + _iCommandID)))
  8852. {
  8853. TBBUTTONINFO tbbi;
  8854. LPITEMIDLIST pidl;
  8855. tbbi.cbSize = SIZEOF(tbbi);
  8856. tbbi.lParam = 0;
  8857. tbbi.dwMask = TBIF_LPARAM;
  8858. if (SendMessage(_hwndPlacesbar, TB_GETBUTTONINFO, idCmd, (LPARAM)&tbbi) >= 0)
  8859. {
  8860. pidl = (LPITEMIDLIST)tbbi.lParam;
  8861. if (pidl)
  8862. {
  8863. JumpToIDList(pidl, FALSE, TRUE);
  8864. }
  8865. }
  8866. }
  8867. return FALSE;
  8868. }
  8869. ////////////////////////////////////////////////////////////////////////////
  8870. //
  8871. // CFileOpenBrowser::OnCDMessage
  8872. //
  8873. // Process a special CommDlg message for the dialog.
  8874. //
  8875. ////////////////////////////////////////////////////////////////////////////
  8876. BOOL CFileOpenBrowser::OnCDMessage(
  8877. UINT uMsg,
  8878. WPARAM wParam,
  8879. LPARAM lParam)
  8880. {
  8881. LONG lResult = -1;
  8882. LPCITEMIDLIST pidl;
  8883. LPTSTR pBuf = (LPTSTR)lParam;
  8884. LPWSTR pBufW = NULL;
  8885. int cbLen;
  8886. // we should make some better thunk wrappers for COMDLG_ANSI
  8887. // like OnCDMessageAorW() calls OnCDMessage()
  8888. switch (uMsg)
  8889. {
  8890. case (CDM_GETSPEC) :
  8891. case (CDM_GETFILEPATH) :
  8892. case (CDM_GETFOLDERPATH) :
  8893. {
  8894. if (_pOFI->ApiType == COMDLG_ANSI)
  8895. {
  8896. if (pBufW = (LPWSTR)LocalAlloc(LPTR,
  8897. (int)wParam * sizeof(WCHAR)))
  8898. {
  8899. pBuf = pBufW;
  8900. }
  8901. else
  8902. {
  8903. break;
  8904. }
  8905. }
  8906. if (uMsg == CDM_GETSPEC)
  8907. {
  8908. lResult = GetFullEditName(pBuf, (UINT) wParam, NULL, NULL);
  8909. break;
  8910. }
  8911. // else, fall thru...
  8912. }
  8913. case (CDM_GETFOLDERIDLIST) :
  8914. {
  8915. TCHAR szDir[MAX_PATH];
  8916. pidl = _pCurrentLocation->pidlFull;
  8917. if (uMsg == CDM_GETFILEPATH)
  8918. {
  8919. // We can't necessarily use the (current folder) + (edit box name) thing in this case
  8920. // because the (current folder) could be incorrect, for example in the case
  8921. // where the current folder is the desktop folder. Items _could_ be in the
  8922. // All Users desktop folder - in which case we want to return All Users\Desktop\file, not
  8923. // <username>\Desktop\file
  8924. // So we'll key off _pidlSelection... if that doesn't work, we fall back to the old
  8925. // behaviour, which could be incorrect in some cases.
  8926. if (pidl && _pidlSelection)
  8927. {
  8928. LPITEMIDLIST pidlFull = ILCombine(pidl, _pidlSelection);
  8929. if (pidlFull)
  8930. {
  8931. if (SHGetPathFromIDList(pidlFull, szDir))
  8932. {
  8933. goto CopyAndReturn;
  8934. }
  8935. ILFree(pidlFull);
  8936. }
  8937. }
  8938. }
  8939. lResult = ILGetSize(pidl);
  8940. if (uMsg == CDM_GETFOLDERIDLIST)
  8941. {
  8942. if ((LONG)wParam < lResult)
  8943. {
  8944. break;
  8945. }
  8946. CopyMemory((LPBYTE)pBuf, (LPBYTE)pidl, lResult);
  8947. break;
  8948. }
  8949. if (!SHGetPathFromIDList(pidl, szDir))
  8950. {
  8951. *szDir = 0;
  8952. }
  8953. if (!*szDir)
  8954. {
  8955. lResult = -1;
  8956. break;
  8957. }
  8958. if (uMsg == CDM_GETFOLDERPATH)
  8959. {
  8960. CopyAndReturn:
  8961. lResult = lstrlen(szDir) + 1;
  8962. if ((LONG)wParam >= lResult)
  8963. {
  8964. // Ok to ignore failure. Spec calls for return value to be req'd buffer size
  8965. // if the buffer isn't big enough.
  8966. StringCchCopy(pBuf, lResult, szDir);
  8967. }
  8968. if (_pOFI->ApiType == COMDLG_ANSI)
  8969. {
  8970. lResult = WideCharToMultiByte(CP_ACP,
  8971. 0,
  8972. szDir,
  8973. -1,
  8974. NULL,
  8975. 0,
  8976. NULL,
  8977. NULL);
  8978. }
  8979. if ((int)wParam > lResult)
  8980. {
  8981. wParam = lResult;
  8982. }
  8983. break;
  8984. }
  8985. //
  8986. // We'll just fall through to the error case for now, since
  8987. // doing the full combine is not an easy thing.
  8988. //
  8989. TCHAR szFile[MAX_PATH];
  8990. if (GetFullEditName(szFile, ARRAYSIZE(szFile), NULL, NULL) <= ARRAYSIZE(szFile) - 5)
  8991. {
  8992. if (PathCombine(szDir, szDir, szFile))
  8993. {
  8994. goto CopyAndReturn;
  8995. }
  8996. // else the path was larger than maxpath!
  8997. }
  8998. // else we filled our buffer!
  8999. lResult = -1;
  9000. break;
  9001. }
  9002. case (CDM_SETCONTROLTEXT) :
  9003. {
  9004. if (_pOFI->ApiType == COMDLG_ANSI)
  9005. {
  9006. //
  9007. // Need to convert pBuf (lParam) to Unicode.
  9008. //
  9009. cbLen = lstrlenA((LPSTR)pBuf) + 1;
  9010. if (pBufW = (LPWSTR)LocalAlloc(LPTR, (cbLen * sizeof(WCHAR))))
  9011. {
  9012. SHAnsiToUnicode((LPSTR)pBuf,pBufW,cbLen);
  9013. pBuf = pBufW;
  9014. }
  9015. }
  9016. //Are we using combobox and the control they are setting is edit box?
  9017. if (_bUseCombo && wParam == edt1)
  9018. {
  9019. //Change it to combo box.
  9020. wParam = cmb13;
  9021. }
  9022. if (_bSave && wParam == IDOK)
  9023. {
  9024. _tszDefSave.TSStrCpy(pBuf);
  9025. //
  9026. // Do this to set the OK button correctly.
  9027. //
  9028. SelFocusChange(TRUE);
  9029. }
  9030. else
  9031. {
  9032. SetDlgItemText(_hwndDlg, (int) wParam, pBuf);
  9033. }
  9034. break;
  9035. }
  9036. case (CDM_HIDECONTROL) :
  9037. {
  9038. //Make sure the control id is not zero (0 is child dialog)
  9039. if ((int)wParam != 0)
  9040. {
  9041. ShowWindow(GetDlgItem(_hwndDlg, (int) wParam), SW_HIDE);
  9042. }
  9043. break;
  9044. }
  9045. case (CDM_SETDEFEXT) :
  9046. {
  9047. if (_pOFI->ApiType == COMDLG_ANSI)
  9048. {
  9049. //
  9050. // Need to convert pBuf (lParam) to Unicode.
  9051. //
  9052. cbLen = lstrlenA((LPSTR)pBuf) + 1;
  9053. if (pBufW = (LPWSTR)LocalAlloc(LPTR, (cbLen * sizeof(WCHAR))))
  9054. {
  9055. SHAnsiToUnicode((LPSTR)pBuf,pBufW,cbLen);
  9056. pBuf = pBufW;
  9057. }
  9058. }
  9059. _pszDefExt.TSStrCpy(pBuf);
  9060. _bNoInferDefExt = TRUE;
  9061. break;
  9062. }
  9063. default:
  9064. {
  9065. lResult = -1;
  9066. break;
  9067. }
  9068. }
  9069. SetWindowLongPtr(_hwndDlg, DWLP_MSGRESULT, lResult);
  9070. if (_pOFI->ApiType == COMDLG_ANSI)
  9071. {
  9072. switch (uMsg)
  9073. {
  9074. case (CDM_GETSPEC) :
  9075. case (CDM_GETFILEPATH) :
  9076. case (CDM_GETFOLDERPATH) :
  9077. {
  9078. //
  9079. // Need to convert pBuf (pBufW) to Ansi and store in lParam.
  9080. //
  9081. if (wParam && lParam)
  9082. {
  9083. SHUnicodeToAnsi(pBuf,(LPSTR)lParam,(int) wParam);
  9084. }
  9085. break;
  9086. }
  9087. }
  9088. if (pBufW)
  9089. {
  9090. LocalFree(pBufW);
  9091. }
  9092. }
  9093. return TRUE;
  9094. }
  9095. ////////////////////////////////////////////////////////////////////////////
  9096. //
  9097. // OKSubclass
  9098. //
  9099. // Subclass window proc for the OK button.
  9100. //
  9101. // The OK button is subclassed so we know which control had focus before
  9102. // the user clicked OK. This in turn lets us know whether to process OK
  9103. // based on the current selection in the listview, or the current text
  9104. // in the edit control.
  9105. //
  9106. ////////////////////////////////////////////////////////////////////////////
  9107. LRESULT CALLBACK OKSubclass(
  9108. HWND hOK,
  9109. UINT msg,
  9110. WPARAM wParam,
  9111. LPARAM lParam)
  9112. {
  9113. HWND hwndDlg = ::GetParent(hOK);
  9114. CFileOpenBrowser *pDlgStruct = HwndToBrowser(hwndDlg);
  9115. WNDPROC pOKProc = pDlgStruct ? pDlgStruct->_lpOKProc : NULL;
  9116. if (pDlgStruct)
  9117. {
  9118. switch (msg)
  9119. {
  9120. case WM_SETFOCUS:
  9121. pDlgStruct->_hwndLastFocus = (HWND)wParam;
  9122. break;
  9123. }
  9124. }
  9125. return ::CallWindowProc(pOKProc, hOK, msg, wParam, lParam);
  9126. }
  9127. ////////////////////////////////////////////////////////////////////////////
  9128. //
  9129. // CFileOpenBrowser::GetNodeFromIDList
  9130. //
  9131. ////////////////////////////////////////////////////////////////////////////
  9132. int CFileOpenBrowser::GetNodeFromIDList(
  9133. LPCITEMIDLIST pidl)
  9134. {
  9135. int i;
  9136. HWND hwndCB = GetDlgItem(_hwndDlg, cmb2);
  9137. Assert(this->_bDropped);
  9138. //
  9139. // Just check DRIVES and DESKTOP.
  9140. //
  9141. for (i = _iNodeDrives; i >= NODE_DESKTOP; --i)
  9142. {
  9143. MYLISTBOXITEM *pItem = GetListboxItem(hwndCB, i);
  9144. if (pItem && ILIsEqual(pidl, pItem->pidlFull))
  9145. {
  9146. break;
  9147. }
  9148. }
  9149. return (i);
  9150. }
  9151. ////////////////////////////////////////////////////////////////////////////
  9152. //
  9153. // CFileOpenBrowser::FSChange
  9154. //
  9155. ////////////////////////////////////////////////////////////////////////////
  9156. BOOL CFileOpenBrowser::FSChange(
  9157. LONG lNotification,
  9158. LPCITEMIDLIST *ppidl)
  9159. {
  9160. int iNode = -1;
  9161. LPCITEMIDLIST pidl = ppidl[0];
  9162. switch (lNotification)
  9163. {
  9164. case (SHCNE_RENAMEFOLDER) :
  9165. {
  9166. LPCITEMIDLIST pidlExtra = ppidl[1];
  9167. //
  9168. // Rename is special. We need to invalidate both
  9169. // the pidl and the pidlExtra, so we call ourselves.
  9170. //
  9171. FSChange(0, &pidlExtra);
  9172. }
  9173. case (0) :
  9174. case (SHCNE_MKDIR) :
  9175. case (SHCNE_RMDIR) :
  9176. {
  9177. LPITEMIDLIST pidlClone = ILClone(pidl);
  9178. if (!pidlClone)
  9179. {
  9180. break;
  9181. }
  9182. ILRemoveLastID(pidlClone);
  9183. iNode = GetNodeFromIDList(pidlClone);
  9184. ILFree(pidlClone);
  9185. break;
  9186. }
  9187. case (SHCNE_UPDATEITEM) :
  9188. case (SHCNE_NETSHARE) :
  9189. case (SHCNE_NETUNSHARE) :
  9190. case (SHCNE_UPDATEDIR) :
  9191. {
  9192. iNode = GetNodeFromIDList(pidl);
  9193. break;
  9194. }
  9195. case (SHCNE_DRIVEREMOVED) :
  9196. case (SHCNE_DRIVEADD) :
  9197. case (SHCNE_MEDIAINSERTED) :
  9198. case (SHCNE_MEDIAREMOVED) :
  9199. case (SHCNE_DRIVEADDGUI) :
  9200. {
  9201. iNode = _iNodeDrives;
  9202. break;
  9203. }
  9204. }
  9205. if (iNode >= 0)
  9206. {
  9207. //
  9208. // We want to delay the processing a little because we always do
  9209. // a full update, so we should accumulate.
  9210. //
  9211. SetTimer(_hwndDlg, TIMER_FSCHANGE + iNode, 100, NULL);
  9212. }
  9213. return FALSE;
  9214. }
  9215. ////////////////////////////////////////////////////////////////////////////
  9216. //
  9217. // CFileOpenBrowser::Timer
  9218. //
  9219. ////////////////////////////////////////////////////////////////////////////
  9220. void CFileOpenBrowser::Timer(
  9221. WPARAM wID)
  9222. {
  9223. KillTimer(_hwndDlg, (UINT) wID);
  9224. wID -= TIMER_FSCHANGE;
  9225. ASSERT(this->_bDropped);
  9226. HWND hwndCB;
  9227. MYLISTBOXITEM *pParentItem;
  9228. hwndCB = GetDlgItem(_hwndDlg, cmb2);
  9229. pParentItem = GetListboxItem(hwndCB, wID);
  9230. UpdateLevel(hwndCB, (int) wID + 1, pParentItem);
  9231. }
  9232. ////////////////////////////////////////////////////////////////////////////
  9233. //
  9234. // CFileOpenBrowser::OnGetMinMax
  9235. //
  9236. ////////////////////////////////////////////////////////////////////////////
  9237. void CFileOpenBrowser::OnGetMinMax(
  9238. LPMINMAXINFO pmmi)
  9239. {
  9240. if ((_ptMinTrack.x != 0) || (_ptMinTrack.y != 0))
  9241. {
  9242. pmmi->ptMinTrackSize = _ptMinTrack;
  9243. }
  9244. }
  9245. ////////////////////////////////////////////////////////////////////////////
  9246. //
  9247. // CFileOpenBrowser::OnSize
  9248. //
  9249. ////////////////////////////////////////////////////////////////////////////
  9250. void CFileOpenBrowser::OnSize(
  9251. int width,
  9252. int height)
  9253. {
  9254. RECT rcMaster;
  9255. RECT rcView;
  9256. RECT rc;
  9257. HWND hwnd;
  9258. HDWP hdwp;
  9259. int dx;
  9260. int dy;
  9261. //
  9262. // Set the sizing grip to the correct location.
  9263. //
  9264. SetWindowPos(_hwndGrip,
  9265. NULL,
  9266. width - g_cxGrip,
  9267. height - g_cyGrip,
  9268. g_cxGrip,
  9269. g_cyGrip,
  9270. SWP_NOZORDER | SWP_NOACTIVATE);
  9271. //
  9272. // Ignore sizing until we are initialized.
  9273. //
  9274. if ((_ptLastSize.x == 0) && (_ptLastSize.y == 0))
  9275. {
  9276. return;
  9277. }
  9278. GetWindowRect(_hwndDlg, &rcMaster);
  9279. //
  9280. // Calculate the deltas in the x and y positions that we need to move
  9281. // each of the child controls.
  9282. //
  9283. dx = (rcMaster.right - rcMaster.left) - _ptLastSize.x;
  9284. dy = (rcMaster.bottom - rcMaster.top) - _ptLastSize.y;
  9285. //Dont do anything if the size remains the same
  9286. if ((dx == 0) && (dy == 0))
  9287. {
  9288. return;
  9289. }
  9290. //
  9291. // Update the new size.
  9292. //
  9293. _ptLastSize.x = rcMaster.right - rcMaster.left;
  9294. _ptLastSize.y = rcMaster.bottom - rcMaster.top;
  9295. //
  9296. // Size the view.
  9297. //
  9298. GetWindowRect(_hwndView, &rcView);
  9299. MapWindowRect(HWND_DESKTOP, _hwndDlg, &rcView);
  9300. hdwp = BeginDeferWindowPos(10);
  9301. if (hdwp)
  9302. {
  9303. hdwp = DeferWindowPos(hdwp,
  9304. _hwndGrip,
  9305. NULL,
  9306. width - g_cxGrip,
  9307. height - g_cyGrip,
  9308. g_cxGrip,
  9309. g_cyGrip,
  9310. SWP_NOZORDER | SWP_NOACTIVATE);
  9311. if (hdwp)
  9312. {
  9313. hdwp = DeferWindowPos(hdwp,
  9314. _hwndView,
  9315. NULL,
  9316. 0,
  9317. 0,
  9318. rcView.right - rcView.left + dx, // resize x
  9319. rcView.bottom - rcView.top + dy, // resize y
  9320. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  9321. }
  9322. #if 0
  9323. //
  9324. // Can't do this because some sub-dialogs are dependent on the
  9325. // original size of this control. Instead we just try to rely on
  9326. // the size of the _hwndView above.
  9327. //
  9328. hwnd = GetDlgItem(_hwndDlg, lst1);
  9329. if (hdwp)
  9330. {
  9331. hdwp = DeferWindowPos(hdwp,
  9332. hwnd,
  9333. NULL,
  9334. 0,
  9335. 0,
  9336. rcView.right - rcView.left + dx, // resize x
  9337. rcView.bottom - rcView.top + dy, // resize y
  9338. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  9339. }
  9340. #endif
  9341. }
  9342. //
  9343. // Move the controls.
  9344. //
  9345. hwnd = ::GetWindow(_hwndDlg, GW_CHILD);
  9346. while (hwnd && hdwp)
  9347. {
  9348. if ((hwnd != _hSubDlg) && (hwnd != _hwndGrip) && (hdwp))
  9349. {
  9350. GetWindowRect(hwnd, &rc);
  9351. MapWindowRect(HWND_DESKTOP, _hwndDlg, &rc);
  9352. //
  9353. // See if the control needs to be adjusted.
  9354. //
  9355. if (rc.top > rcView.bottom)
  9356. {
  9357. switch (GetDlgCtrlID(hwnd))
  9358. {
  9359. case (edt1) :
  9360. case (cmb13) :
  9361. case (cmb1) :
  9362. {
  9363. //Increase the width of these controls
  9364. hdwp = DeferWindowPos(hdwp,
  9365. hwnd,
  9366. NULL,
  9367. rc.left,
  9368. rc.top + dy,
  9369. RECTWIDTH(rc) + dx,
  9370. RECTHEIGHT(rc),
  9371. SWP_NOZORDER);
  9372. break;
  9373. }
  9374. case (IDOK):
  9375. case (IDCANCEL):
  9376. case (pshHelp):
  9377. {
  9378. //Move these controls to the right
  9379. hdwp = DeferWindowPos(hdwp,
  9380. hwnd,
  9381. NULL,
  9382. rc.left + dx,
  9383. rc.top + dy,
  9384. 0,
  9385. 0,
  9386. SWP_NOZORDER | SWP_NOSIZE);
  9387. break;
  9388. }
  9389. default :
  9390. {
  9391. //
  9392. // The control is below the view, so adjust the y
  9393. // coordinate appropriately.
  9394. //
  9395. hdwp = DeferWindowPos(hdwp,
  9396. hwnd,
  9397. NULL,
  9398. rc.left,
  9399. rc.top + dy,
  9400. 0,
  9401. 0,
  9402. SWP_NOZORDER | SWP_NOSIZE);
  9403. }
  9404. }
  9405. }
  9406. else if (rc.left > rcView.right)
  9407. {
  9408. //
  9409. // The control is to the right of the view, so adjust the
  9410. // x coordinate appropriately.
  9411. //
  9412. hdwp = DeferWindowPos(hdwp,
  9413. hwnd,
  9414. NULL,
  9415. rc.left + dx,
  9416. rc.top,
  9417. 0,
  9418. 0,
  9419. SWP_NOZORDER | SWP_NOSIZE);
  9420. }
  9421. else
  9422. {
  9423. int id = GetDlgCtrlID(hwnd);
  9424. switch (id)
  9425. {
  9426. case (cmb2) :
  9427. {
  9428. //
  9429. // Size this one larger.
  9430. //
  9431. hdwp = DeferWindowPos(hdwp,
  9432. hwnd,
  9433. NULL,
  9434. 0,
  9435. 0,
  9436. RECTWIDTH(rc) + dx,
  9437. RECTHEIGHT(rc),
  9438. SWP_NOZORDER | SWP_NOMOVE);
  9439. break;
  9440. }
  9441. case ( IDOK) :
  9442. if ((SHGetAppCompatFlags(ACF_FILEOPENBOGUSCTRLID) & ACF_FILEOPENBOGUSCTRLID) == 0)
  9443. break;
  9444. // else continue through - toolbar bar has ctrlid == IDOK, so we will resize that.
  9445. case ( stc1 ) :
  9446. //
  9447. // Move the toolbar right by dx.
  9448. //
  9449. hdwp = DeferWindowPos(hdwp,
  9450. hwnd,
  9451. NULL,
  9452. rc.left + dx,
  9453. rc.top,
  9454. 0,
  9455. 0,
  9456. SWP_NOZORDER | SWP_NOSIZE);
  9457. break;
  9458. case ( ctl1 ) :
  9459. {
  9460. // Size the places bar vertically
  9461. hdwp = DeferWindowPos(hdwp,
  9462. hwnd,
  9463. NULL,
  9464. 0,
  9465. 0,
  9466. RECTWIDTH(rc),
  9467. RECTHEIGHT(rc) + dy,
  9468. SWP_NOZORDER | SWP_NOMOVE);
  9469. break;
  9470. }
  9471. }
  9472. }
  9473. }
  9474. hwnd = ::GetWindow(hwnd, GW_HWNDNEXT);
  9475. }
  9476. if (!hdwp)
  9477. {
  9478. return;
  9479. }
  9480. EndDeferWindowPos(hdwp);
  9481. if (_hSubDlg)
  9482. {
  9483. hdwp = NULL;
  9484. hwnd = ::GetWindow(_hSubDlg, GW_CHILD);
  9485. while (hwnd)
  9486. {
  9487. GetWindowRect(hwnd, &rc);
  9488. MapWindowRect(HWND_DESKTOP, _hSubDlg, &rc);
  9489. //
  9490. // See if the control needs to be adjusted.
  9491. //
  9492. if (rc.top > rcView.bottom)
  9493. {
  9494. //
  9495. // The control is below the view, so adjust the y
  9496. // coordinate appropriately.
  9497. //
  9498. if (hdwp == NULL)
  9499. {
  9500. hdwp = BeginDeferWindowPos(10);
  9501. }
  9502. if (hdwp)
  9503. {
  9504. hdwp = DeferWindowPos(hdwp,
  9505. hwnd,
  9506. NULL,
  9507. rc.left,
  9508. rc.top + dy,
  9509. 0,
  9510. 0,
  9511. SWP_NOZORDER | SWP_NOSIZE);
  9512. }
  9513. }
  9514. else if (rc.left > rcView.right)
  9515. {
  9516. //
  9517. // The control is to the right of the view, so adjust the
  9518. // x coordinate appropriately.
  9519. //
  9520. if (hdwp == NULL)
  9521. {
  9522. hdwp = BeginDeferWindowPos(10);
  9523. }
  9524. if (hdwp)
  9525. {
  9526. hdwp = DeferWindowPos(hdwp,
  9527. hwnd,
  9528. NULL,
  9529. rc.left + dx,
  9530. rc.top,
  9531. 0,
  9532. 0,
  9533. SWP_NOZORDER | SWP_NOSIZE);
  9534. }
  9535. }
  9536. hwnd = ::GetWindow(hwnd, GW_HWNDNEXT);
  9537. }
  9538. if (hdwp)
  9539. {
  9540. EndDeferWindowPos(hdwp);
  9541. //
  9542. // Size the sub dialog.
  9543. //
  9544. SetWindowPos(_hSubDlg,
  9545. NULL,
  9546. 0,
  9547. 0,
  9548. _ptLastSize.x, // make it the same
  9549. _ptLastSize.y, // make it the same
  9550. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  9551. }
  9552. }
  9553. }
  9554. ////////////////////////////////////////////////////////////////////////////
  9555. //
  9556. // CFileOpenBrowser::VerifyListViewPosition
  9557. //
  9558. ////////////////////////////////////////////////////////////////////////////
  9559. void CFileOpenBrowser::VerifyListViewPosition()
  9560. {
  9561. RECT rcList, rcView;
  9562. FOLDERSETTINGS fs;
  9563. //
  9564. // Get the rectangle for both the list view and the hidden list box.
  9565. //
  9566. GetControlRect(_hwndDlg, lst1, &rcList);
  9567. rcView.left = 0;
  9568. if ((!GetWindowRect(_hwndView, &rcView)) ||
  9569. (!MapWindowRect(HWND_DESKTOP, _hwndDlg, &rcView)))
  9570. {
  9571. return;
  9572. }
  9573. //
  9574. // See if the list view is off the screen and the list box is not.
  9575. //
  9576. if ((rcView.left < 0) && (rcList.left >= 0))
  9577. {
  9578. //
  9579. // Reset the list view to the list box position.
  9580. //
  9581. if (_pCurrentLocation)
  9582. {
  9583. if (_psv)
  9584. {
  9585. _psv->GetCurrentInfo(&fs);
  9586. }
  9587. else
  9588. {
  9589. fs.ViewMode = FVM_LIST;
  9590. fs.fFlags = _pOFN->Flags & OFN_ALLOWMULTISELECT ? 0 : FWF_SINGLESEL;
  9591. }
  9592. SwitchView(_pCurrentLocation->GetShellFolder(),
  9593. _pCurrentLocation->pidlFull,
  9594. &fs,
  9595. NULL,
  9596. FALSE);
  9597. }
  9598. }
  9599. }
  9600. ////////////////////////////////////////////////////////////////////////////
  9601. //
  9602. // CFileOpenBrowser::UpdateNavigation
  9603. // This function updates the navigation stack by adding the current
  9604. // pidl to the stack
  9605. ////////////////////////////////////////////////////////////////////////////
  9606. void CFileOpenBrowser::UpdateNavigation()
  9607. {
  9608. WPARAM iItem;
  9609. HWND hwndCombo = GetDlgItem(_hwndDlg, cmb2);
  9610. iItem = SendMessage(hwndCombo, CB_GETCURSEL, NULL, NULL);
  9611. MYLISTBOXITEM *pNewLocation = GetListboxItem(hwndCombo, iItem);
  9612. if (_ptlog && pNewLocation && pNewLocation->pidlFull)
  9613. {
  9614. LPITEMIDLIST pidl;
  9615. _ptlog->GetCurrent(&pidl);
  9616. if (pidl && (!ILIsEqual(pNewLocation->pidlFull, pidl)))
  9617. {
  9618. _ptlog->AddEntry(pNewLocation->pidlFull);
  9619. }
  9620. if (pidl)
  9621. {
  9622. ILFree(pidl);
  9623. }
  9624. }
  9625. //Update the UI
  9626. UpdateUI(_pCurrentLocation ? _pCurrentLocation->pidlFull : NULL);
  9627. }
  9628. ////////////////////////////////////////////////////////////////////////////
  9629. //
  9630. // CFileOpenBrowser::UpdateUI
  9631. //
  9632. ////////////////////////////////////////////////////////////////////////////
  9633. void CFileOpenBrowser::UpdateUI(LPITEMIDLIST pidlNew)
  9634. {
  9635. TBBUTTONINFO tbbi;
  9636. LPITEMIDLIST pidl;
  9637. ::SendMessage(_hwndToolbar, TB_ENABLEBUTTON, IDC_BACK, _ptlog ? _ptlog->CanTravel(TRAVEL_BACK) : 0);
  9638. if (_iCheckedButton >= 0)
  9639. {
  9640. //Reset the Hot Button
  9641. ::SendMessage(_hwndPlacesbar, TB_CHECKBUTTON, (WPARAM)_iCheckedButton, MAKELONG(FALSE,0));
  9642. _iCheckedButton = -1;
  9643. }
  9644. if (pidlNew)
  9645. {
  9646. //Get Each Toolbar Buttons pidl and see if the current pidl matches
  9647. for (int i=0; i < MAXPLACESBARITEMS; i++)
  9648. {
  9649. tbbi.cbSize = SIZEOF(tbbi);
  9650. tbbi.lParam = 0;
  9651. tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX | TBIF_COMMAND;
  9652. if (SendMessage(_hwndPlacesbar, TB_GETBUTTONINFO, i, (LPARAM)&tbbi) >= 0)
  9653. {
  9654. pidl = (LPITEMIDLIST)tbbi.lParam;
  9655. if (pidl && ILIsEqual(pidlNew, pidl))
  9656. {
  9657. _iCheckedButton = tbbi.idCommand;
  9658. break;
  9659. }
  9660. }
  9661. }
  9662. if (_iCheckedButton >= 0)
  9663. {
  9664. ::SendMessage(_hwndPlacesbar, TB_CHECKBUTTON, (WPARAM)_iCheckedButton, MAKELONG(TRUE,0));
  9665. }
  9666. }
  9667. }
  9668. ////////////////////////////////////////////////////////////////////////////
  9669. //
  9670. // OpenDlgProc
  9671. //
  9672. // Main dialog procedure for file open dialogs.
  9673. //
  9674. ////////////////////////////////////////////////////////////////////////////
  9675. BOOL_PTR CALLBACK OpenDlgProc(
  9676. HWND hDlg, // window handle of the dialog box
  9677. UINT message, // type of message
  9678. WPARAM wParam, // message-specific information
  9679. LPARAM lParam)
  9680. {
  9681. CFileOpenBrowser *pDlgStruct = HwndToBrowser(hDlg);
  9682. // we divide the message processing into two switch statments:
  9683. // those who don't use pDlgStruct first and then those who do.
  9684. switch (message)
  9685. {
  9686. case WM_INITDIALOG:
  9687. {
  9688. //
  9689. // Initialize dialog box.
  9690. //
  9691. LPOFNINITINFO poii = (LPOFNINITINFO)lParam;
  9692. if (CDGetAppCompatFlags() & CDACF_MATHCAD)
  9693. {
  9694. if (FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)))
  9695. ::EndDialog(hDlg, FALSE);
  9696. }
  9697. poii->hrOleInit = SHOleInitialize(0);
  9698. if (!InitLocation(hDlg, poii))
  9699. {
  9700. ::EndDialog(hDlg, FALSE);
  9701. }
  9702. if (!gp_uQueryCancelAutoPlay)
  9703. {
  9704. // try to register for autoplay messages
  9705. gp_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
  9706. }
  9707. //
  9708. // Always return FALSE to indicate we have already set the focus.
  9709. //
  9710. return FALSE;
  9711. }
  9712. break;
  9713. case WM_DESTROY:
  9714. {
  9715. RECT r;
  9716. //Cache in this dialogs size and position so that new
  9717. //dialog are created at this location and size
  9718. GetWindowRect(hDlg, &r);
  9719. if (pDlgStruct && (pDlgStruct->_bEnableSizing))
  9720. {
  9721. g_rcDlg = r;
  9722. }
  9723. //
  9724. // Make sure we do not respond to any more messages.
  9725. //
  9726. StoreBrowser(hDlg, NULL);
  9727. ClearListbox(GetDlgItem(hDlg, cmb2));
  9728. // Unsubclass the ok button now, otherwise we leak the button control,
  9729. // because in OkSubclass we won't be able to forward the WM_NCDESTORY since
  9730. // the original wndproc will have been nuked in pDlgStruct->_lpOKProc
  9731. if (pDlgStruct)
  9732. {
  9733. SetWindowLongPtr(::GetDlgItem(hDlg, IDOK), GWLP_WNDPROC, (LONG_PTR)pDlgStruct->_lpOKProc);
  9734. }
  9735. if (pDlgStruct)
  9736. {
  9737. pDlgStruct->Release();
  9738. }
  9739. return FALSE;
  9740. }
  9741. break;
  9742. case WM_ACTIVATE:
  9743. {
  9744. if (wParam == WA_INACTIVE)
  9745. {
  9746. //
  9747. // Make sure some other Open dialog has not already grabbed
  9748. // the focus. This is a process global, so it should not
  9749. // need to be protected.
  9750. //
  9751. if (gp_hwndActiveOpen == hDlg)
  9752. {
  9753. gp_hwndActiveOpen = NULL;
  9754. }
  9755. }
  9756. else
  9757. {
  9758. gp_hwndActiveOpen = hDlg;
  9759. }
  9760. return FALSE;
  9761. }
  9762. break;
  9763. case WM_MEASUREITEM:
  9764. {
  9765. if (!g_cxSmIcon && !g_cySmIcon)
  9766. {
  9767. HIMAGELIST himl;
  9768. Shell_GetImageLists(NULL, &himl);
  9769. ImageList_GetIconSize(himl, &g_cxSmIcon, &g_cySmIcon);
  9770. }
  9771. MeasureDriveItems(hDlg, (MEASUREITEMSTRUCT*)lParam);
  9772. return TRUE;
  9773. }
  9774. break;
  9775. case CWM_GETISHELLBROWSER:
  9776. {
  9777. ::SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LRESULT)pDlgStruct);
  9778. return TRUE;
  9779. }
  9780. break;
  9781. case WM_DEVICECHANGE:
  9782. {
  9783. if (DBT_DEVICEARRIVAL == wParam)
  9784. {
  9785. // and refresh our view in case this was a notification for the folder
  9786. // we are viewing. avoids making the user do a manual refresh
  9787. DEV_BROADCAST_VOLUME *pbv = (DEV_BROADCAST_VOLUME *)lParam;
  9788. if (pbv->dbcv_flags & DBTF_MEDIA)
  9789. {
  9790. int chRoot;
  9791. TCHAR szPath[MAX_PATH];
  9792. if (pDlgStruct->GetDirectoryFromLB(szPath, &chRoot))
  9793. {
  9794. int iDrive = PathGetDriveNumber(szPath);
  9795. if (iDrive != -1 && ((1 << iDrive) & pbv->dbcv_unitmask))
  9796. {
  9797. // refresh incase this was this folder
  9798. PostMessage(hDlg, WM_COMMAND, IDC_REFRESH, 0);
  9799. }
  9800. }
  9801. }
  9802. }
  9803. return TRUE;
  9804. }
  9805. break;
  9806. default:
  9807. if (message == gp_uQueryCancelAutoPlay)
  9808. {
  9809. // cancel the autoplay
  9810. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 1);
  9811. return TRUE;
  9812. }
  9813. break;
  9814. }
  9815. // NOTE:
  9816. // all of the messages below require that we have a valid pDlgStruct. if you
  9817. // don't refrence pDlgStruct, then add your msg to the switch statement above.
  9818. if (pDlgStruct)
  9819. {
  9820. switch (message)
  9821. {
  9822. case WM_COMMAND:
  9823. {
  9824. return ((BOOL_PTR)pDlgStruct->OnCommandMessage(wParam, lParam));
  9825. }
  9826. break;
  9827. case WM_DRAWITEM:
  9828. {
  9829. pDlgStruct->PaintDriveLine((DRAWITEMSTRUCT *)lParam);
  9830. //
  9831. // Make sure the list view is in the same place as the
  9832. // list box. Apps like VB move the list box off of the
  9833. // dialog. If the list view is placed on the list box
  9834. // before the list box gets moved back to the dialog, we
  9835. // end up with an ugly gray spot.
  9836. //
  9837. pDlgStruct->VerifyListViewPosition();
  9838. return TRUE;
  9839. }
  9840. break;
  9841. case WM_NOTIFY:
  9842. {
  9843. return (BOOL_PTR)pDlgStruct->OnNotify((LPNMHDR)lParam);
  9844. }
  9845. break;
  9846. case WM_SETCURSOR:
  9847. {
  9848. if (pDlgStruct->OnSetCursor())
  9849. {
  9850. SetDlgMsgResult(hDlg, message, (LRESULT)TRUE);
  9851. return TRUE;
  9852. }
  9853. }
  9854. break;
  9855. case WM_HELP:
  9856. {
  9857. HWND hwndItem = (HWND)((LPHELPINFO)lParam)->hItemHandle;
  9858. if (hwndItem != pDlgStruct->_hwndToolbar)
  9859. {
  9860. HWND hwndItem = (HWND)((LPHELPINFO)lParam)->hItemHandle;
  9861. // We assume that the defview has one child window that
  9862. // covers the entire defview window.
  9863. HWND hwndDefView = GetDlgItem(hDlg, lst2);
  9864. if (GetParent(hwndItem) == hwndDefView)
  9865. {
  9866. hwndItem = hwndDefView;
  9867. }
  9868. WinHelp(hwndItem,
  9869. NULL,
  9870. HELP_WM_HELP,
  9871. (ULONG_PTR)(LPTSTR)(pDlgStruct->_bSave ? aFileSaveHelpIDs : aFileOpenHelpIDs));
  9872. }
  9873. return TRUE;
  9874. }
  9875. break;
  9876. case WM_CONTEXTMENU:
  9877. {
  9878. if ((HWND)wParam != pDlgStruct->_hwndToolbar)
  9879. {
  9880. WinHelp((HWND)wParam,
  9881. NULL,
  9882. HELP_CONTEXTMENU,
  9883. (ULONG_PTR)(void *)(pDlgStruct->_bSave ? aFileSaveHelpIDs : aFileOpenHelpIDs));
  9884. }
  9885. return TRUE;
  9886. }
  9887. break;
  9888. case CDM_SETSAVEBUTTON:
  9889. {
  9890. pDlgStruct->RealSetSaveButton((UINT)wParam);
  9891. }
  9892. break;
  9893. case CDM_FSNOTIFY:
  9894. {
  9895. LPITEMIDLIST *ppidl;
  9896. LONG lEvent;
  9897. BOOL bRet;
  9898. LPSHChangeNotificationLock pLock;
  9899. // Get the change notification info from the shared memory
  9900. // block identified by the handle passed in the wParam.
  9901. pLock = SHChangeNotification_Lock((HANDLE)wParam,
  9902. (DWORD)lParam,
  9903. &ppidl,
  9904. &lEvent);
  9905. if (pLock == NULL)
  9906. {
  9907. pDlgStruct->_bDropped = FALSE;
  9908. return FALSE;
  9909. }
  9910. bRet = pDlgStruct->FSChange(lEvent, (LPCITEMIDLIST *)ppidl);
  9911. // Release the shared block.
  9912. SHChangeNotification_Unlock(pLock);
  9913. return bRet;
  9914. }
  9915. break;
  9916. case CDM_SELCHANGE:
  9917. {
  9918. pDlgStruct->_fSelChangedPending = FALSE;
  9919. pDlgStruct->SelFocusChange(TRUE);
  9920. if (pDlgStruct->_hSubDlg)
  9921. {
  9922. CD_SendSelChangeNotify(pDlgStruct->_hSubDlg,
  9923. hDlg,
  9924. pDlgStruct->_pOFN,
  9925. pDlgStruct->_pOFI);
  9926. }
  9927. }
  9928. break;
  9929. case WM_TIMER:
  9930. {
  9931. pDlgStruct->Timer(wParam);
  9932. }
  9933. break;
  9934. case WM_GETMINMAXINFO:
  9935. {
  9936. if (pDlgStruct->_bEnableSizing)
  9937. {
  9938. pDlgStruct->OnGetMinMax((LPMINMAXINFO)lParam);
  9939. return FALSE;
  9940. }
  9941. }
  9942. break;
  9943. case WM_SIZE:
  9944. {
  9945. if (pDlgStruct->_bEnableSizing)
  9946. {
  9947. pDlgStruct->OnSize(LOWORD(lParam), HIWORD(lParam));
  9948. return TRUE;
  9949. }
  9950. }
  9951. break;
  9952. case WM_NCCALCSIZE:
  9953. {
  9954. // AppHack for Borland JBuilder: Need to keep track of whether
  9955. // any redraw requests have come in.
  9956. pDlgStruct->_bAppRedrawn = TRUE;
  9957. }
  9958. break;
  9959. case WM_THEMECHANGED:
  9960. {
  9961. // Need to change some parameters on the placesbar for this.
  9962. pDlgStruct->OnThemeActive(hDlg, IsAppThemed());
  9963. return TRUE;
  9964. }
  9965. break;
  9966. case WM_SETTINGCHANGE:
  9967. {
  9968. // If icon size has changed, we need to regenerate the places bar.
  9969. pDlgStruct->_RecreatePlacesbar();
  9970. return FALSE;
  9971. }
  9972. break;
  9973. default:
  9974. {
  9975. if (IsInRange(message, CDM_FIRST, CDM_LAST) && pDlgStruct)
  9976. {
  9977. return pDlgStruct->OnCDMessage(message, wParam, lParam);
  9978. }
  9979. }
  9980. }
  9981. }
  9982. // Did not process the message.
  9983. return FALSE;
  9984. }
  9985. ////////////////////////////////////////////////////////////////////////////
  9986. //
  9987. // OpenFileHookProc
  9988. //
  9989. ////////////////////////////////////////////////////////////////////////////
  9990. LRESULT CALLBACK OpenFileHookProc(
  9991. int nCode,
  9992. WPARAM wParam,
  9993. LPARAM lParam)
  9994. {
  9995. MSG *lpMsg;
  9996. if (nCode < 0)
  9997. {
  9998. return (DefHookProc(nCode, wParam, lParam, &gp_hHook));
  9999. }
  10000. if (nCode != MSGF_DIALOGBOX)
  10001. {
  10002. return (0);
  10003. }
  10004. lpMsg = (MSG *)lParam;
  10005. //
  10006. // Check if this message is for the last active OpenDialog in this
  10007. // process.
  10008. //
  10009. // Note: This is only done for WM_KEY* messages so that we do not slow
  10010. // down this window too much.
  10011. //
  10012. if (IsInRange(lpMsg->message, WM_KEYFIRST, WM_KEYLAST))
  10013. {
  10014. HWND hwndActiveOpen = gp_hwndActiveOpen;
  10015. HWND hwndFocus = GetFocusedChild(hwndActiveOpen, lpMsg->hwnd);
  10016. CFileOpenBrowser *pDlgStruct;
  10017. if (hwndFocus &&
  10018. (pDlgStruct = HwndToBrowser(hwndActiveOpen)) != NULL)
  10019. {
  10020. if (pDlgStruct->_psv && (hwndFocus == pDlgStruct->_hwndView))
  10021. {
  10022. if (pDlgStruct->_psv->TranslateAccelerator(lpMsg) == S_OK)
  10023. {
  10024. return (1);
  10025. }
  10026. if (gp_haccOpenView &&
  10027. TranslateAccelerator(hwndActiveOpen, gp_haccOpenView, lpMsg))
  10028. {
  10029. return (1);
  10030. }
  10031. }
  10032. else
  10033. {
  10034. if (gp_haccOpen &&
  10035. TranslateAccelerator(hwndActiveOpen, gp_haccOpen, lpMsg))
  10036. {
  10037. return (1);
  10038. }
  10039. //
  10040. // Note that the view won't be allowed to translate when the
  10041. // focus is not there.
  10042. //
  10043. }
  10044. }
  10045. }
  10046. return (0);
  10047. }
  10048. ////////////////////////////////////////////////////////////////////////////
  10049. //
  10050. // NewGetFileName
  10051. //
  10052. ////////////////////////////////////////////////////////////////////////////
  10053. BOOL NewGetFileName(
  10054. LPOPENFILEINFO lpOFI,
  10055. BOOL bSave)
  10056. {
  10057. OFNINITINFO oii = { lpOFI, bSave, FALSE, -1};
  10058. LPOPENFILENAME lpOFN = lpOFI->pOFN;
  10059. BOOL bHooked = FALSE;
  10060. WORD wErrorMode;
  10061. HRSRC hResInfo;
  10062. HGLOBAL hDlgTemplate;
  10063. LPDLGTEMPLATE pDlgTemplate;
  10064. int nRet;
  10065. LANGID LangID;
  10066. //Initialize the common controls
  10067. INITCOMMONCONTROLSEX icc;
  10068. icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  10069. icc.dwICC = ICC_USEREX_CLASSES; //ComboBoxEx class
  10070. InitCommonControlsEx(&icc);
  10071. if ((lpOFN->lStructSize != sizeof(OPENFILENAME)) &&
  10072. (lpOFN->lStructSize != OPENFILENAME_SIZE_VERSION_400)
  10073. )
  10074. {
  10075. StoreExtendedError(CDERR_STRUCTSIZE);
  10076. return FALSE;
  10077. }
  10078. //
  10079. // OFN_ENABLEINCLUDENOTIFY requires OFN_EXPLORER and OFN_ENABLEHOOK.
  10080. //
  10081. if (lpOFN->Flags & OFN_ENABLEINCLUDENOTIFY)
  10082. {
  10083. if ((!(lpOFN->Flags & OFN_EXPLORER)) ||
  10084. (!(lpOFN->Flags & OFN_ENABLEHOOK)))
  10085. {
  10086. StoreExtendedError(CDERR_INITIALIZATION);
  10087. return FALSE;
  10088. }
  10089. }
  10090. wErrorMode = (WORD)SetErrorMode(SEM_NOERROR);
  10091. SetErrorMode(SEM_NOERROR | wErrorMode);
  10092. //
  10093. // There ought to be a better way. I am compelled to keep the hHook in a
  10094. // global because my callback needs it, but I have no lData where I could
  10095. // possibly store it.
  10096. // Note that we initialize nHookRef to -1 so we know when the first
  10097. // increment is.
  10098. //
  10099. if (InterlockedIncrement((LPLONG)&gp_nHookRef) == 0)
  10100. {
  10101. gp_hHook = SetWindowsHookEx(WH_MSGFILTER,
  10102. OpenFileHookProc,
  10103. 0,
  10104. GetCurrentThreadId());
  10105. if (gp_hHook)
  10106. {
  10107. bHooked = TRUE;
  10108. }
  10109. else
  10110. {
  10111. --gp_nHookRef;
  10112. }
  10113. }
  10114. else
  10115. {
  10116. bHooked = TRUE;
  10117. }
  10118. if (!gp_haccOpen)
  10119. {
  10120. gp_haccOpen = LoadAccelerators(g_hinst,
  10121. MAKEINTRESOURCE(IDA_OPENFILE));
  10122. }
  10123. if (!gp_haccOpenView)
  10124. {
  10125. gp_haccOpenView = LoadAccelerators(g_hinst,
  10126. MAKEINTRESOURCE(IDA_OPENFILEVIEW));
  10127. }
  10128. g_cxGrip = GetSystemMetrics(SM_CXVSCROLL);
  10129. g_cyGrip = GetSystemMetrics(SM_CYHSCROLL);
  10130. //
  10131. // Get the dialog resource and load it.
  10132. //
  10133. nRet = FALSE;
  10134. WORD wResID;
  10135. // if the version of the structure passed is older than the current version and the application
  10136. // has specified hook or template or template handle then use template corresponding to that version
  10137. // else use the new file open template
  10138. if (((lpOFI->iVersion < OPENFILEVERSION) &&
  10139. (lpOFI->pOFN->Flags & (OFN_ENABLEHOOK | OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE))) ||
  10140. (IsRestricted(REST_NOPLACESBAR)) || (IS_NEW_OFN(lpOFI->pOFN) && (lpOFI->pOFN->FlagsEx & OFN_EX_NOPLACESBAR))
  10141. )
  10142. {
  10143. wResID = NEWFILEOPENORD;
  10144. }
  10145. else
  10146. {
  10147. wResID = NEWFILEOPENV2ORD;
  10148. }
  10149. LangID = GetDialogLanguage(lpOFN->hwndOwner, NULL);
  10150. //
  10151. // Warning! Warning! Warning!
  10152. //
  10153. // We have to set g_tlsLangID before any call for CDLoadString
  10154. //
  10155. TlsSetValue(g_tlsLangID, (void *) LangID);
  10156. if ((hResInfo = FindResourceExFallback(::g_hinst,
  10157. RT_DIALOG,
  10158. MAKEINTRESOURCE(wResID),
  10159. LangID)) &&
  10160. (hDlgTemplate = LoadResource(::g_hinst, hResInfo)) &&
  10161. (pDlgTemplate = (LPDLGTEMPLATE)LockResource(hDlgTemplate)))
  10162. {
  10163. ULONG cbTemplate = SizeofResource(::g_hinst, hResInfo);
  10164. LPDLGTEMPLATE pDTCopy = (LPDLGTEMPLATE)LocalAlloc(LPTR, cbTemplate);
  10165. if (pDTCopy)
  10166. {
  10167. CopyMemory(pDTCopy, pDlgTemplate, cbTemplate);
  10168. UnlockResource(hDlgTemplate);
  10169. FreeResource(hDlgTemplate);
  10170. if ((lpOFN->Flags & OFN_ENABLESIZING) ||
  10171. (!(lpOFN->Flags & (OFN_ENABLEHOOK |
  10172. OFN_ENABLETEMPLATE |
  10173. OFN_ENABLETEMPLATEHANDLE))))
  10174. {
  10175. if (((LPDLGTEMPLATE2)pDTCopy)->wSignature == 0xFFFF)
  10176. {
  10177. //This is a dialogex template
  10178. ((LPDLGTEMPLATE2)pDTCopy)->style |= WS_SIZEBOX;
  10179. }
  10180. else
  10181. {
  10182. //This is a dialog template
  10183. ((LPDLGTEMPLATE)pDTCopy)->style |= WS_SIZEBOX;
  10184. }
  10185. oii.bEnableSizing = TRUE;
  10186. }
  10187. oii.hrOleInit = E_FAIL;
  10188. nRet = (BOOL)DialogBoxIndirectParam(::g_hinst,
  10189. pDTCopy,
  10190. lpOFN->hwndOwner,
  10191. OpenDlgProc,
  10192. (LPARAM)(LPOFNINITINFO)&oii);
  10193. //Unintialize OLE
  10194. SHOleUninitialize(oii.hrOleInit);
  10195. if (CDGetAppCompatFlags() & CDACF_MATHCAD)
  10196. {
  10197. CoUninitialize();
  10198. }
  10199. LocalFree(pDTCopy);
  10200. }
  10201. }
  10202. if (bHooked)
  10203. {
  10204. //
  10205. // Put this in a local so we don't need a critical section.
  10206. //
  10207. HHOOK hHook = gp_hHook;
  10208. if (InterlockedDecrement((LPLONG)&gp_nHookRef) < 0)
  10209. {
  10210. UnhookWindowsHookEx(hHook);
  10211. }
  10212. }
  10213. switch (nRet)
  10214. {
  10215. case (TRUE) :
  10216. {
  10217. break;
  10218. }
  10219. case (FALSE) :
  10220. {
  10221. if ((!g_bUserPressedCancel) && (!GetStoredExtendedError()))
  10222. {
  10223. StoreExtendedError(CDERR_DIALOGFAILURE);
  10224. }
  10225. break;
  10226. }
  10227. default :
  10228. {
  10229. StoreExtendedError(CDERR_DIALOGFAILURE);
  10230. nRet = FALSE;
  10231. break;
  10232. }
  10233. }
  10234. //
  10235. //
  10236. // There is a race condition here where we free dlls but a thread
  10237. // using this stuff still hasn't terminated so we page fault.
  10238. // FreeImports();
  10239. SetErrorMode(wErrorMode);
  10240. return (nRet);
  10241. }
  10242. extern "C" {
  10243. ////////////////////////////////////////////////////////////////////////////
  10244. //
  10245. // NewGetOpenFileName
  10246. //
  10247. ////////////////////////////////////////////////////////////////////////////
  10248. BOOL NewGetOpenFileName(
  10249. LPOPENFILEINFO lpOFI)
  10250. {
  10251. return (NewGetFileName(lpOFI, FALSE));
  10252. }
  10253. ////////////////////////////////////////////////////////////////////////////
  10254. //
  10255. // NewGetSaveFileName
  10256. //
  10257. ////////////////////////////////////////////////////////////////////////////
  10258. BOOL NewGetSaveFileName(
  10259. LPOPENFILEINFO lpOFI)
  10260. {
  10261. return (NewGetFileName(lpOFI, TRUE));
  10262. }
  10263. } // extern "C"
  10264. ////////////////////////////////////////////////////////////////////////////
  10265. //
  10266. // CFileOpenBrowser::_ValidateSelectedFile
  10267. //
  10268. ////////////////////////////////////////////////////////////////////////////
  10269. BOOL CFileOpenBrowser::_ValidateSelectedFile(LPCTSTR pszFile, int *pErrCode)
  10270. {
  10271. //
  10272. // Successfully opened.
  10273. //
  10274. // Note: (pfortier) If/when IShellItem is removed from this version of comdlg, the
  10275. // following if statement should probably revert to
  10276. // if ((_pOFN->Flags & OFN_NOREADONLYRETURN) &&
  10277. // and the next one to
  10278. // if (_bSave || (_pOFN->Flags & OFN_NOREADONLYRETURN))
  10279. //
  10280. // These were changed in order to be consistent with w2k behaviour regarding
  10281. // message box errors that appear when OFN_NOREADONLYRETURN is specified and
  10282. // the user selects a readonly file - the point of contention is that errors were
  10283. // not shown in win2k when it was an OpenFile dialog. IShellItem changes modified
  10284. // the codepath such that errors were now produced when in an OpenFile dialog.
  10285. // To compensate, the logic has been changed here.
  10286. DWORD dwAttrib = GetFileAttributes(pszFile);
  10287. if ((_pOFN->Flags & OFN_NOREADONLYRETURN) && _bSave &&
  10288. (0xFFFFFFFF != dwAttrib) && (dwAttrib & FILE_ATTRIBUTE_READONLY))
  10289. {
  10290. *pErrCode = OF_LAZYREADONLY;
  10291. return FALSE;
  10292. }
  10293. if (_bSave)
  10294. {
  10295. *pErrCode = WriteProtectedDirCheck((LPTSTR)pszFile);
  10296. if (*pErrCode)
  10297. {
  10298. return FALSE;
  10299. }
  10300. }
  10301. if (_pOFN->Flags & OFN_OVERWRITEPROMPT)
  10302. {
  10303. if (_bSave && PathFileExists(pszFile) && !FOkToWriteOver(_hwndDlg, (LPTSTR)pszFile))
  10304. {
  10305. if (_bUseCombo)
  10306. {
  10307. PostMessage(_hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(_hwndDlg, cmb13), 1);
  10308. }
  10309. else
  10310. {
  10311. PostMessage(_hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(_hwndDlg, edt1), 1);
  10312. }
  10313. return FALSE;
  10314. }
  10315. }
  10316. return TRUE;
  10317. }
  10318. ////////////////////////////////////////////////////////////////////////////
  10319. //
  10320. // CFileOpenBrowser::_ProcessPidlSelection
  10321. //
  10322. ////////////////////////////////////////////////////////////////////////////
  10323. BOOL CFileOpenBrowser::_ProcessPidlSelection()
  10324. {
  10325. IShellItem *psi;
  10326. if (SUCCEEDED(SHCreateShellItem(_pCurrentLocation->pidlFull, _psfCurrent, _pidlSelection, &psi)))
  10327. {
  10328. IShellItem *psiReal;
  10329. HRESULT hr = _TestShellItem(psi, TRUE, &psiReal);
  10330. if (S_OK == hr)
  10331. {
  10332. hr = _ProcessItemAsFile(psiReal);
  10333. psiReal->Release();
  10334. }
  10335. psi->Release();
  10336. // if there was any kind of error then we fall back
  10337. // to the old code to show errors and the like
  10338. return SUCCEEDED(hr);
  10339. }
  10340. return FALSE;
  10341. }
  10342. ///////////////////////////////////////////////////////////////////////////
  10343. //
  10344. // CFileOpenBrowser::_ProcessItemAsFile
  10345. //
  10346. ////////////////////////////////////////////////////////////////////////////
  10347. HRESULT CFileOpenBrowser::_ProcessItemAsFile(IShellItem *psi)
  10348. {
  10349. LPTSTR pszPath;
  10350. HRESULT hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
  10351. if (FAILED(hr))
  10352. {
  10353. hr = _MakeFakeCopy(psi, &pszPath);
  10354. }
  10355. if (SUCCEEDED(hr))
  10356. {
  10357. int nErrCode;
  10358. hr = E_FAIL;
  10359. if (_ValidateSelectedFile(pszPath, &nErrCode))
  10360. {
  10361. DWORD dwError = 0;
  10362. int nFileOffset = _CopyFileNameToOFN(pszPath, &dwError);
  10363. ASSERT(nFileOffset >= 0);
  10364. _CopyTitleToOFN(pszPath+nFileOffset);
  10365. if (dwError)
  10366. {
  10367. StoreExtendedError(dwError);
  10368. }
  10369. else
  10370. {
  10371. // Only PostProcess is there was no error copying our info to the OFN (e.g. buffers not big enough)
  10372. _PostProcess(pszPath);
  10373. }
  10374. _CleanupDialog((dwError == NOERROR));
  10375. hr = S_OK;
  10376. }
  10377. else
  10378. {
  10379. //Check to see if there is an error in the file or user pressed no for overwrite prompt
  10380. // if user pressed no to overwritte prompt then return true
  10381. if (nErrCode == 0)
  10382. hr = S_FALSE; // Otherwise, return failure.
  10383. }
  10384. CoTaskMemFree(pszPath);
  10385. }
  10386. return hr;
  10387. }
  10388. ///////////////////////////////////////////////////////////////////////////
  10389. //
  10390. // CFileOpenBrowser::_ProcessPidlAsShellItem
  10391. //
  10392. ////////////////////////////////////////////////////////////////////////////
  10393. #ifdef RETURN_SHELLITEMS
  10394. HRESULT CFileOpenBrowser::_ProcessShellItem(IShellItem *psi)
  10395. {
  10396. CShellItemList *psil = new CShellItemList();
  10397. HRESULT hr = E_OUTOFMEMORY;
  10398. ASSERT(IS_NEW_OFN(_pOFN));
  10399. if (psil)
  10400. {
  10401. hr = psil->Add(psi);
  10402. // we have added everything to our list
  10403. if (SUCCEEDED(hr))
  10404. {
  10405. hr = psil->QueryInterface(IID_PPV_ARG(IEnumShellItems, &(_pOFN->penum)));
  10406. }
  10407. psil->Release();
  10408. }
  10409. return hr;
  10410. }
  10411. #endif RETURN_SHELLITEMS
  10412. ///////////////////////////////////////////////////////////////////////////
  10413. //
  10414. // CFileOpenBrowser::_PostProcess
  10415. //
  10416. // This functions does all the bookkeeping operations that needs to be
  10417. // done when File Open/Save Dialog closes.
  10418. ////////////////////////////////////////////////////////////////////////////
  10419. BOOL CFileOpenBrowser::_PostProcess(LPTSTR pszFile)
  10420. {
  10421. int nFileOffset = ParseFileNew(pszFile, NULL, FALSE, TRUE);
  10422. //Set the last visited directory for this application.
  10423. //We should this all the time regardless of how we opened b'cos app may specify an initial
  10424. //directory(many apps do this in Save As case) but the user might decide to save it in a differnt directory
  10425. //in this case we need to save the directory where user saved.
  10426. AddToLastVisitedMRU(pszFile, nFileOffset);
  10427. //Add to recent documents.
  10428. if (!(_pOFN->Flags & OFN_DONTADDTORECENT))
  10429. {
  10430. SHAddToRecentDocs(SHARD_PATH, pszFile);
  10431. //Add to the file mru
  10432. AddToMRU(_pOFN);
  10433. }
  10434. // Check to see if we need to set Read only bit or not
  10435. if (!(_pOFN->Flags & OFN_HIDEREADONLY))
  10436. {
  10437. //
  10438. // Read-only checkbox visible?
  10439. //
  10440. if (IsDlgButtonChecked(_hwndDlg, chx1))
  10441. {
  10442. _pOFN->Flags |= OFN_READONLY;
  10443. }
  10444. else
  10445. {
  10446. _pOFN->Flags &= ~OFN_READONLY;
  10447. }
  10448. }
  10449. return TRUE;
  10450. }