Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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