Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1688 lines
59 KiB

  1. #include "stdafx.h"
  2. #include "specfldr.h"
  3. #include "hostutil.h"
  4. #include "rcids.h" // for IDM_PROGRAMS etc.
  5. #include "ras.h"
  6. #include "raserror.h"
  7. #include "netcon.h"
  8. #include "netconp.h"
  9. #include <cowsite.h>
  10. //
  11. // This definition is stolen from shell32\unicpp\dcomp.h
  12. //
  13. #define REGSTR_PATH_HIDDEN_DESKTOP_ICONS_STARTPANEL \
  14. REGSTR_PATH_EXPLORER TEXT("\\HideDesktopIcons\\NewStartPanel")
  15. HRESULT CRecentShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  16. HRESULT CNoSubdirShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  17. HRESULT CMyComputerShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  18. HRESULT CNoFontsShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  19. HRESULT CConnectToShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  20. LPTSTR _Static_LoadString(const struct SpecialFolderDesc *pdesc);
  21. BOOL ShouldShowWindowsSecurity();
  22. BOOL ShouldShowOEMLink();
  23. typedef HRESULT (CALLBACK *CREATESHELLMENUCALLBACK)(IShellMenuCallback **ppsmc);
  24. typedef BOOL (CALLBACK *SHOULDSHOWFOLDERCALLBACK)();
  25. EXTERN_C HINSTANCE hinstCabinet;
  26. void ShowFolder(UINT csidl);
  27. BOOL IsNetConPidlRAS(IShellFolder2 *psfNetCon, LPCITEMIDLIST pidlNetConItem);
  28. //****************************************************************************
  29. //
  30. // SpecialFolderDesc
  31. //
  32. // Describes a special folder.
  33. //
  34. #define SFD_SEPARATOR ((LPTSTR)-1)
  35. // Flags for SpecialFolderDesc._uFlags
  36. enum {
  37. // These values are collectively known as the
  38. // "display mode" and match the values set by regtreeop.
  39. SFD_HIDE = 0x0000,
  40. SFD_SHOW = 0x0001,
  41. SFD_CASCADE = 0x0002,
  42. SFD_MODEMASK = 0x0003,
  43. SFD_DROPTARGET = 0x0004,
  44. SFD_CANCASCADE = 0x0008,
  45. SFD_FORCECASCADE = 0x0010,
  46. SFD_BOLD = 0x0020,
  47. SFD_WASSHOWN = 0x0040,
  48. SFD_PREFIX = 0x0080,
  49. SFD_USEBGTHREAD = 0x0100,
  50. };
  51. struct SpecialFolderDesc {
  52. typedef BOOL (SpecialFolderDesc::*CUSTOMFOLDERNAMECALLBACK)(LPTSTR *ppsz) const;
  53. LPCTSTR _pszTarget; // or MAKEINTRESOURCE(csidl)
  54. RESTRICTIONS _rest; // optional restriction
  55. LPCTSTR _pszShow; // REGSTR_EXPLORER_ADVANCED!_pszShow
  56. UINT _uFlags; // SFD_* values
  57. CREATESHELLMENUCALLBACK _CreateShellMenuCallback; // Which IShellMenuCallback do we want?
  58. LPCTSTR _pszCustomizeKey; // Optional location where customizations are saved
  59. DWORD _dwShellFolderFlags; // Optional restrictions for cascading folder
  60. UINT _idsCustomName; // Optional override (CUSTOMFOLDERNAMECALLBACK)
  61. UINT _iToolTip; // Optional resource ID for a custom tooltip
  62. CUSTOMFOLDERNAMECALLBACK _CustomName; // Over-ride the filesys name
  63. SHOULDSHOWFOLDERCALLBACK _ShowFolder;
  64. LPCTSTR _pszCanHideOnDesktop; // Optional {guid} that controls desktop visibility
  65. DWORD GetDisplayMode(BOOL *pbIgnoreRule) const;
  66. void AdjustForSKU();
  67. void SetDefaultDisplayMode(UINT iNewMode)
  68. {
  69. _uFlags = (_uFlags & ~SFD_MODEMASK) | iNewMode;
  70. }
  71. BOOL IsDropTarget() const { return _uFlags & SFD_DROPTARGET; }
  72. BOOL IsCacheable() const { return _uFlags & SFD_USEBGTHREAD; }
  73. int IsCSIDL() const { return IS_INTRESOURCE(_pszTarget); }
  74. BOOL IsBold() const { return _uFlags & SFD_BOLD; }
  75. int IsSeparator() const { return _pszTarget == SFD_SEPARATOR; }
  76. int GetCSIDL() const {
  77. ASSERT(IsCSIDL());
  78. return (short)PtrToLong(_pszTarget);
  79. }
  80. HRESULT CreateShellMenuCallback(IShellMenuCallback **ppsmc) const {
  81. return _CreateShellMenuCallback ? _CreateShellMenuCallback(ppsmc) : S_OK;
  82. }
  83. BOOL GetCustomName(LPTSTR *ppsz) const {
  84. if (_CustomName)
  85. return (this->*_CustomName)(ppsz);
  86. else
  87. return FALSE;
  88. }
  89. LPWSTR GetShowCacheRegName() const;
  90. BOOL LoadStringAsOLESTR(LPTSTR *ppsz) const;
  91. BOOL ConnectToName(LPTSTR *ppsz) const;
  92. };
  93. static SpecialFolderDesc s_rgsfd[] = {
  94. /* My Documents */
  95. {
  96. MAKEINTRESOURCE(CSIDL_PERSONAL), // pszTarget
  97. REST_NOSMMYDOCS, // restriction
  98. REGSTR_VAL_DV2_SHOWMYDOCS,
  99. SFD_SHOW | SFD_DROPTARGET | SFD_CANCASCADE | SFD_BOLD,
  100. // show by default, is drop target
  101. NULL, // no custom cascade
  102. NULL, // no drag/drop customization
  103. 0, // no special flags for cascaded menu
  104. 0, // (no custom name)
  105. IDS_CUSTOMTIP_MYDOCS,
  106. NULL, // (no custom name)
  107. NULL, // (no custom display rule)
  108. TEXT("{450D8FBA-AD25-11D0-98A8-0800361B1103}"), // desktop visibility control
  109. },
  110. /* Recent */
  111. {
  112. MAKEINTRESOURCE(CSIDL_RECENT), // pszTarget
  113. REST_NORECENTDOCSMENU, // restriction
  114. REGSTR_VAL_DV2_SHOWRECDOCS, // customize show
  115. SFD_HIDE | SFD_CANCASCADE | SFD_BOLD | SFD_PREFIX, // hide by default
  116. CRecentShellMenuCallback_CreateInstance, // custom callback
  117. NULL, // no drag/drop customization
  118. SMINIT_RESTRICT_DRAGDROP, // disallow drag/drop in cascaded menu
  119. IDS_STARTPANE_RECENT, // override filesys name
  120. IDS_CUSTOMTIP_RECENT,
  121. &SpecialFolderDesc::LoadStringAsOLESTR, // override filesys name with _idsCustomName
  122. NULL, // (no custom display rule)
  123. NULL, // (no desktop visibility control)
  124. },
  125. /* My Pictures */
  126. {
  127. MAKEINTRESOURCE(CSIDL_MYPICTURES), // pszTarget
  128. REST_NOSMMYPICS, // restriction
  129. REGSTR_VAL_DV2_SHOWMYPICS,
  130. SFD_SHOW | SFD_DROPTARGET | SFD_CANCASCADE | SFD_BOLD,
  131. // show by default, is drop target
  132. NULL, // no custom cascade
  133. NULL, // no drag/drop customization
  134. 0, // no special flags for cascaded menu
  135. 0, // (no custom name)
  136. IDS_CUSTOMTIP_MYPICS,
  137. NULL, // (no custom name)
  138. NULL, // (no custom display rule)
  139. NULL, // (no desktop visibility control)
  140. },
  141. /* My Music */
  142. {
  143. MAKEINTRESOURCE(CSIDL_MYMUSIC), // pszTarget
  144. REST_NOSMMYMUSIC, // restriction
  145. REGSTR_VAL_DV2_SHOWMYMUSIC,
  146. SFD_SHOW | SFD_DROPTARGET | SFD_CANCASCADE | SFD_BOLD,
  147. // show by default, is drop target
  148. NULL, // no custom cascade
  149. NULL, // no drag/drop customization
  150. 0, // no special flags for cascaded menu
  151. 0, // (no custom name)
  152. IDS_CUSTOMTIP_MYMUSIC,
  153. NULL, // (no custom name)
  154. NULL, // (no custom display rule)
  155. NULL, // (no desktop visibility control)
  156. },
  157. /* Favorites */
  158. {
  159. MAKEINTRESOURCE(CSIDL_FAVORITES), // pszTarget
  160. REST_NOFAVORITESMENU, // restriction
  161. REGSTR_VAL_DV2_FAVORITES, // customize show (shared w/classic)
  162. SFD_HIDE | SFD_DROPTARGET |
  163. SFD_CANCASCADE | SFD_FORCECASCADE | SFD_BOLD | SFD_PREFIX,
  164. // hide by default, is drop target
  165. NULL, // unrestricted cascading
  166. STRREG_FAVORITES, // drag/drop customization key
  167. 0, // no special flags for cascaded menu
  168. IDS_STARTPANE_FAVORITES, // override filesys name
  169. 0, // no custom tip
  170. &SpecialFolderDesc::LoadStringAsOLESTR, // override filesys name with _idsCustomName
  171. NULL, // (no custom display rule)
  172. NULL, // (no desktop visibility control)
  173. },
  174. /* My Computer */
  175. {
  176. MAKEINTRESOURCE(CSIDL_DRIVES), // pszTarget
  177. REST_NOMYCOMPUTERICON, // restriction
  178. REGSTR_VAL_DV2_SHOWMC, // customize show
  179. SFD_SHOW | SFD_CANCASCADE | SFD_BOLD, // show by default
  180. CMyComputerShellMenuCallback_CreateInstance, // custom callback
  181. NULL, // no drag/drop customization
  182. 0, // no special flags for cascaded menu
  183. 0, // (no custom name)
  184. IDS_CUSTOMTIP_MYCOMP,
  185. NULL, // (no custom name)
  186. NULL, // (no custom display rule)
  187. TEXT("{20D04FE0-3AEA-1069-A2D8-08002B30309D}"), // desktop visibility control
  188. },
  189. /* My Network Places */
  190. {
  191. MAKEINTRESOURCE(CSIDL_NETWORK), // pszTarget
  192. REST_NOSMNETWORKPLACES, // restriction
  193. REGSTR_VAL_DV2_SHOWNETPL, // customize show
  194. SFD_SHOW | SFD_CANCASCADE | SFD_BOLD | SFD_USEBGTHREAD, // show by default
  195. CNoSubdirShellMenuCallback_CreateInstance, // only cascade one level
  196. NULL, // no drag/drop customization
  197. 0, // no special flags for cascaded menu
  198. 0, // (no custom name)
  199. IDS_CUSTOMTIP_MYNETPLACES,
  200. NULL, // (no custom name)
  201. ShouldShowNetPlaces,
  202. TEXT("{208D2C60-3AEA-1069-A2D7-08002B30309D}"), // desktop visibility control
  203. },
  204. /* Separator line */
  205. {
  206. SFD_SEPARATOR, // separator
  207. REST_NONE, // no restriction
  208. NULL, // no customize show
  209. SFD_SHOW, // show by default
  210. NULL, // (not cascadable)
  211. NULL, // (not cascadable)
  212. 0, // (not cascadable)
  213. 0, // (no custom name)
  214. 0, // no custom tip
  215. NULL, // (no custom name)
  216. NULL, // (no custom display rule)
  217. NULL, // (no desktop visibility control)
  218. },
  219. /* Control Panel */
  220. {
  221. MAKEINTRESOURCE(CSIDL_CONTROLS), // pszTarget
  222. REST_NOCONTROLPANEL, // restriction
  223. REGSTR_VAL_DV2_SHOWCPL,
  224. SFD_SHOW | SFD_CANCASCADE | SFD_PREFIX, // show by default
  225. CNoFontsShellMenuCallback_CreateInstance, // custom callback
  226. NULL, // no drag/drop customization
  227. 0, // no special flags for cascaded menu
  228. IDS_STARTPANE_CONTROLPANEL, // override filesys name
  229. IDS_CUSTOMTIP_CTRLPANEL, // no custom tip
  230. &SpecialFolderDesc::LoadStringAsOLESTR, // override filesys name with _idsCustomName
  231. NULL, // (no custom display rule)
  232. NULL, // (no desktop visibility control)
  233. },
  234. /* Admin Tools */
  235. {
  236. // Using the ::{guid} gets the icon right
  237. TEXT("shell:::{D20EA4E1-3957-11d2-A40B-0C5020524153}"), // pszTarget
  238. REST_NONE, // no restriction
  239. REGSTR_VAL_DV2_ADMINTOOLSROOT,
  240. SFD_HIDE | SFD_CANCASCADE | SFD_FORCECASCADE, // hide by default, force to cascade
  241. NULL, // no custom callback
  242. NULL, // no drag/drop customization
  243. 0, // no special flags for cascaded menu
  244. NULL, // no custom name
  245. NULL, // no custom tip
  246. NULL, // no custom name
  247. NULL, // (no custom display rule)
  248. NULL, // (no desktop visibility control)
  249. },
  250. /* Network Connections */
  251. {
  252. MAKEINTRESOURCE(CSIDL_CONNECTIONS), // pszTarget
  253. REST_NONETWORKCONNECTIONS, // restriction
  254. REGSTR_VAL_DV2_SHOWNETCONN, // customize show
  255. SFD_CASCADE | SFD_CANCASCADE | SFD_PREFIX | SFD_USEBGTHREAD, // cascade by default
  256. CConnectToShellMenuCallback_CreateInstance, // do special Connect To filtering
  257. NULL, // no drag/drop customization
  258. 0, // no special flags for cascaded menu
  259. IDS_STARTPANE_CONNECTTO, // override filesys name
  260. IDS_CUSTOMTIP_CONNECTTO,
  261. &SpecialFolderDesc::ConnectToName, // override filesys name with _idsCustomName
  262. ShouldShowConnectTo, // see if we should be shown
  263. NULL, // (no desktop visibility control)
  264. },
  265. /* Printers */
  266. {
  267. MAKEINTRESOURCE(CSIDL_PRINTERS), // pszTarget
  268. REST_NONE, // no restriction
  269. REGSTR_VAL_DV2_SHOWPRINTERS, // customize show
  270. SFD_HIDE, // hide by default, can't cascade
  271. NULL, // (not cascadable)
  272. NULL, // no drag/drop customization
  273. 0, // no special flags for cascaded menu
  274. 0, // (no custom name)
  275. 0, // no custom tip
  276. NULL, // (no custom name)
  277. NULL, // (no custom display rule)
  278. NULL, // (no desktop visibility control)
  279. },
  280. /* Separator line */
  281. {
  282. SFD_SEPARATOR, // separator
  283. REST_NONE, // no restriction
  284. NULL, // no customize show
  285. SFD_SHOW, // show by default
  286. NULL, // (not cascadable)
  287. NULL, // (not cascadable)
  288. 0, // (not cascadable)
  289. 0, // (no custom name)
  290. 0, // no custom tip
  291. NULL, // (no custom name)
  292. NULL, // (no custom display rule)
  293. NULL, // (no desktop visibility control)
  294. },
  295. /* Help */
  296. {
  297. TEXT("shell:::{2559a1f1-21d7-11d4-bdaf-00c04f60b9f0}"), // pszTarget
  298. REST_NOSMHELP, // restriction
  299. REGSTR_VAL_DV2_SHOWHELP, // customize show
  300. SFD_SHOW | SFD_PREFIX, // show by default, use & prefix
  301. NULL, // (not cascadable)
  302. NULL, // (not cascadable)
  303. 0, // (not cascadable)
  304. 0, // (no custom name)
  305. 0, // no custom tip
  306. NULL, // (no custom name)
  307. NULL, // (no custom display rule)
  308. NULL, // (no desktop visibility control)
  309. },
  310. /* Search */
  311. {
  312. TEXT("shell:::{2559a1f0-21d7-11d4-bdaf-00c04f60b9f0}"), // pszTarget
  313. REST_NOFIND, // restriction
  314. REGSTR_VAL_DV2_SHOWSEARCH, // customize show
  315. SFD_SHOW | SFD_PREFIX, // show by default, use & prefix
  316. NULL, // (not cascadable)
  317. NULL, // (not cascadable)
  318. 0, // (not cascadable)
  319. 0, // (no custom name)
  320. 0, // no custom tip
  321. NULL, // (no custom name)
  322. NULL, // (no custom display rule)
  323. NULL, // (no desktop visibility control)
  324. },
  325. /* Run */
  326. {
  327. TEXT("shell:::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}"), // pszTarget
  328. REST_NORUN, // restriction
  329. REGSTR_VAL_DV2_SHOWRUN, // customize show
  330. SFD_SHOW | SFD_PREFIX, // show by default, use & prefix
  331. NULL, // (not cascadable)
  332. NULL, // (not cascadable)
  333. 0, // (not cascadable)
  334. 0, // (no custom name)
  335. 0, // no custom tip
  336. NULL, // (no custom name)
  337. NULL, // (no custom display rule)
  338. NULL, // (no desktop visibility control)
  339. },
  340. /* Separator line */
  341. {
  342. SFD_SEPARATOR, // separator
  343. REST_NONE, // no restriction
  344. NULL, // no customize show
  345. SFD_SHOW, // show by default
  346. NULL, // (not cascadable)
  347. NULL, // (not cascadable)
  348. 0, // (not cascadable)
  349. 0, // (no custom name)
  350. 0, // no custom tip
  351. NULL, // (no custom name)
  352. NULL, // (no custom display rule)
  353. NULL, // (no desktop visibility control)
  354. },
  355. /* Windows Security */
  356. {
  357. TEXT("shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}"), // pszTarget
  358. REST_NOSECURITY, // restriction
  359. NULL, // not customizable
  360. SFD_SHOW | SFD_PREFIX, // show by default, use & prefix
  361. NULL, // (not cascadable)
  362. NULL, // (not cascadable)
  363. 0, // (not cascadable)
  364. 0, // (no custom name)
  365. 0, // no custom tip
  366. NULL, // (no custom name)
  367. ShouldShowWindowsSecurity, // custom display rule
  368. NULL, // (no desktop visibility control)
  369. },
  370. /* OEM Command */
  371. {
  372. TEXT("shell:::{2559a1f6-21d7-11d4-bdaf-00c04f60b9f0}"), // pszTarget
  373. REST_NONE, // no restriction
  374. REGSTR_VAL_DV2_SHOWOEM, // customizable
  375. SFD_SHOW | SFD_PREFIX, // show by default, use & prefix
  376. NULL, // (not cascadable)
  377. NULL, // (not cascadable)
  378. 0, // (not cascadable)
  379. 0, // (no custom name)
  380. 0, // no custom tip
  381. NULL, // (no custom name)
  382. ShouldShowOEMLink, // custom display rule
  383. NULL, // (no desktop visibility control)
  384. },
  385. };
  386. //
  387. // These are the items whose defaults change depending on the SKU.
  388. // Changing the defaults for the SKU means chasing down all the
  389. // places defaults are computed (here, the property sheets,
  390. // the regtreeop) and updating them all. Someday, they should
  391. // be reduced down to one.
  392. //
  393. void SpecialFolderDesc::AdjustForSKU()
  394. {
  395. if (IsCSIDL())
  396. {
  397. switch (GetCSIDL())
  398. {
  399. case CSIDL_MYPICTURES:
  400. case CSIDL_MYMUSIC:
  401. SetDefaultDisplayMode(IsOS(OS_ANYSERVER) ? SFD_HIDE : SFD_SHOW);
  402. break;
  403. case CSIDL_RECENT:
  404. SetDefaultDisplayMode(IsOS(OS_PERSONAL) ? SFD_HIDE : SFD_CASCADE);
  405. break;
  406. case CSIDL_PRINTERS:
  407. SetDefaultDisplayMode(IsOS(OS_PERSONAL) ? SFD_HIDE : SFD_SHOW);
  408. break;
  409. }
  410. }
  411. }
  412. LPWSTR SpecialFolderDesc::GetShowCacheRegName() const
  413. {
  414. const WCHAR szCached[] = L"_ShouldShow";
  415. WCHAR *pszShowCache = (WCHAR *)LocalAlloc(LPTR, ((lstrlenW(_pszShow)+1) * sizeof (WCHAR)) + sizeof(szCached));
  416. if (pszShowCache)
  417. {
  418. StrCpy(pszShowCache, _pszShow);
  419. StrCat(pszShowCache, szCached);
  420. }
  421. return pszShowCache;
  422. }
  423. //
  424. // First try to read the display mode from the registry.
  425. // Failing that, use the default value.
  426. // Also fill in whether to ignore the custom display rule or not
  427. //
  428. DWORD SpecialFolderDesc::GetDisplayMode(BOOL *pbIgnoreRule) const
  429. {
  430. *pbIgnoreRule = FALSE;
  431. // Restrictions always take top priority
  432. if (SHRestricted(_rest))
  433. {
  434. return SFD_HIDE;
  435. }
  436. DWORD dwMode = _uFlags & SFD_MODEMASK;
  437. // See if there is a user setting to override
  438. if (_pszShow)
  439. {
  440. DWORD dwNewMode, cb = sizeof(DWORD);
  441. if (SHRegGetUSValue(REGSTR_EXPLORER_ADVANCED, _pszShow, NULL, &dwNewMode, &cb, FALSE, NULL, 0) == ERROR_SUCCESS)
  442. {
  443. // User has forced show or forced no-show
  444. // Do not call the custom show logic
  445. dwMode = dwNewMode;
  446. *pbIgnoreRule = TRUE;
  447. }
  448. else
  449. {
  450. WCHAR *pszShowCache = GetShowCacheRegName();
  451. if (pszShowCache)
  452. {
  453. if (SHGetValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED, pszShowCache, NULL, &dwNewMode, &cb) == ERROR_SUCCESS)
  454. {
  455. dwMode = dwNewMode;
  456. }
  457. LocalFree(pszShowCache);
  458. }
  459. }
  460. }
  461. //
  462. // Some items are cascade-only (Favorites).
  463. // Others never cascade (Run).
  464. //
  465. // Enforce those rules here.
  466. //
  467. if (dwMode == SFD_CASCADE && !(_uFlags & SFD_CANCASCADE))
  468. {
  469. dwMode = SFD_SHOW;
  470. }
  471. else if (dwMode == SFD_SHOW && (_uFlags & SFD_FORCECASCADE))
  472. {
  473. dwMode = SFD_CASCADE;
  474. }
  475. return dwMode;
  476. }
  477. //****************************************************************************
  478. //
  479. // SpecialFolderListItem
  480. //
  481. // A PaneItem for the benefit of SFTBarHost.
  482. //
  483. class SpecialFolderListItem : public PaneItem
  484. {
  485. public:
  486. LPITEMIDLIST _pidl; // Full Pidl to each item
  487. const SpecialFolderDesc *_psfd; // Describes this item
  488. TCHAR _chMnem; // Keyboard accelerator
  489. LPTSTR _pszDispName; // Display name
  490. HICON _hIcon; // Icon
  491. SpecialFolderListItem(const SpecialFolderDesc *psfd) : _pidl(NULL), _psfd(psfd)
  492. {
  493. if (_psfd->IsSeparator())
  494. {
  495. // Make sure that SFD_SEPARATOR isn't accidentally recognized
  496. // as a separator.
  497. ASSERT(!_psfd->IsCSIDL());
  498. _iPinPos = PINPOS_SEPARATOR;
  499. }
  500. else if (_psfd->IsCSIDL())
  501. {
  502. SHGetSpecialFolderLocation(NULL, _psfd->GetCSIDL(), &_pidl);
  503. }
  504. else
  505. {
  506. SHILCreateFromPath(_psfd->_pszTarget, &_pidl, NULL);
  507. }
  508. };
  509. ~SpecialFolderListItem()
  510. {
  511. ILFree(_pidl);
  512. if (_hIcon)
  513. {
  514. DestroyIcon(_hIcon);
  515. }
  516. SHFree(_pszDispName);
  517. };
  518. void ReplaceLastPidlElement(LPITEMIDLIST pidlNew)
  519. {
  520. ASSERT(ILFindLastID(pidlNew) == pidlNew); // the ILAppend below won't work otherwise
  521. ILRemoveLastID(_pidl);
  522. LPITEMIDLIST pidlCombined = ILAppendID(_pidl, &pidlNew->mkid, TRUE);
  523. if (pidlCombined)
  524. _pidl = pidlCombined;
  525. }
  526. //
  527. // Values that are derived from CSIDL values need to be revalidated
  528. // because the user can rename a special folder, and we need to track
  529. // it to its new location.
  530. //
  531. BOOL IsStillValid()
  532. {
  533. BOOL fValid = TRUE;
  534. if (_psfd->IsCSIDL())
  535. {
  536. LPITEMIDLIST pidlNew;
  537. if (SHGetSpecialFolderLocation(NULL, _psfd->GetCSIDL(), &pidlNew) == S_OK)
  538. {
  539. UINT cbSizeNew = ILGetSize(pidlNew);
  540. if (cbSizeNew != ILGetSize(_pidl) ||
  541. memcmp(_pidl, pidlNew, cbSizeNew) != 0)
  542. {
  543. fValid = FALSE;
  544. }
  545. ILFree(pidlNew);
  546. }
  547. }
  548. return fValid;
  549. }
  550. };
  551. SpecialFolderList::~SpecialFolderList()
  552. {
  553. }
  554. HRESULT SpecialFolderList::Initialize()
  555. {
  556. for(int i=0;i < ARRAYSIZE(s_rgsfd); i++)
  557. s_rgsfd[i].AdjustForSKU();
  558. return S_OK;
  559. }
  560. // return TRUE if there are the requisite number of kids
  561. BOOL MinKidsHelper(UINT csidl, BOOL bOnlyRASCON, DWORD dwMinKids)
  562. {
  563. DWORD dwCount = 0;
  564. IShellFolder2 *psf;
  565. LPITEMIDLIST pidlBind = NULL;
  566. if (SHGetSpecialFolderLocation(NULL, csidl, &pidlBind) == S_OK)
  567. {
  568. if (SUCCEEDED(SHBindToObjectEx(NULL, pidlBind, NULL, IID_PPV_ARG(IShellFolder2, &psf))))
  569. {
  570. IEnumIDList *penum;
  571. if (S_OK == psf->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &penum))
  572. {
  573. LPITEMIDLIST pidl;
  574. ULONG celt;
  575. while (S_OK == penum->Next(1, &pidl, &celt))
  576. {
  577. if (bOnlyRASCON)
  578. {
  579. ASSERT(csidl == CSIDL_CONNECTIONS); // we better be in the net con folder
  580. if (IsNetConPidlRAS(psf, pidl))
  581. dwCount++;
  582. }
  583. else
  584. dwCount++;
  585. SHFree(pidl);
  586. if (dwCount >= dwMinKids)
  587. break;
  588. }
  589. penum->Release();
  590. }
  591. psf->Release();
  592. }
  593. ILFree(pidlBind);
  594. }
  595. return dwCount >= dwMinKids;
  596. }
  597. BOOL ShouldShowNetPlaces()
  598. {
  599. return MinKidsHelper(CSIDL_NETHOOD, FALSE, 1); // see bug 317893 for details on when to show net places
  600. }
  601. BOOL ShouldShowConnectTo()
  602. {
  603. return MinKidsHelper(CSIDL_CONNECTIONS, TRUE, 1); // see bug 226855 (and the associated spec) for when to show Connect To
  604. }
  605. BOOL ShouldShowWindowsSecurity()
  606. {
  607. return SHGetMachineInfo(GMI_TSCLIENT);
  608. }
  609. BOOL ShouldShowOEMLink()
  610. {
  611. // Only show the OEM link if the OPK tool has added the appropriate registry entries...
  612. BOOL bRet = FALSE;
  613. HKEY hk;
  614. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID\\{2559a1f6-21d7-11d4-bdaf-00c04f60b9f0}"), 0, KEY_READ, &hk))
  615. {
  616. DWORD cb;
  617. // Check to make sure its got a name, and a the parameter is registered properly...
  618. if (ERROR_SUCCESS == RegQueryValue(hk, NULL, NULL, (LONG*) &cb) &&
  619. ERROR_SUCCESS == SHGetValue(hk, TEXT("Instance\\InitPropertyBag"), TEXT("Param1"), NULL, NULL, &cb))
  620. {
  621. bRet = TRUE;
  622. }
  623. RegCloseKey(hk);
  624. }
  625. return bRet;
  626. }
  627. DWORD WINAPI SpecialFolderList::_HasEnoughChildrenThreadProc(void *pvData)
  628. {
  629. SpecialFolderList *pThis = reinterpret_cast<SpecialFolderList *>(pvData);
  630. HRESULT hr = SHCoInitialize();
  631. if (SUCCEEDED(hr))
  632. {
  633. DWORD dwIndex;
  634. for (dwIndex = 0; dwIndex < ARRAYSIZE(s_rgsfd); dwIndex++)
  635. {
  636. const SpecialFolderDesc *pdesc = &s_rgsfd[dwIndex];
  637. BOOL bIgnoreRule;
  638. DWORD dwMode = pdesc->GetDisplayMode(&bIgnoreRule);
  639. if (pdesc->IsCacheable() && pdesc->_ShowFolder)
  640. {
  641. ASSERT(pdesc->_pszShow);
  642. // We need to recount now
  643. if (!bIgnoreRule && pdesc->_ShowFolder())
  644. {
  645. // We have enough kids
  646. // Let's see if the state changed from last time
  647. if (!(dwMode & SFD_WASSHOWN))
  648. {
  649. WCHAR *pszShowCache = pdesc->GetShowCacheRegName();
  650. if (pszShowCache)
  651. {
  652. dwMode |= SFD_WASSHOWN;
  653. SHSetValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED, pszShowCache, REG_DWORD, &dwMode, sizeof(dwMode));
  654. pThis->Invalidate();
  655. LocalFree(pszShowCache);
  656. }
  657. }
  658. continue;
  659. }
  660. // just create the item to get a pidl for it....
  661. SpecialFolderListItem *pitem = new SpecialFolderListItem(pdesc);
  662. if (pitem && pitem->_pidl)
  663. {
  664. // We don't have enough kids but we might gain them dynamically.
  665. // Register for notifications that can indicate that there are new
  666. // items.
  667. ASSERT(pThis->_cNotify < SFTHOST_MAXNOTIFY);
  668. if (pThis->RegisterNotify(pThis->_cNotify, SHCNE_CREATE | SHCNE_MKDIR | SHCNE_UPDATEDIR,
  669. pitem->_pidl, FALSE))
  670. {
  671. pThis->_cNotify++;
  672. }
  673. }
  674. delete pitem;
  675. // Let's see if the state changed from last time
  676. if (dwMode & SFD_WASSHOWN)
  677. {
  678. // Reset it to the default
  679. WCHAR *pszShowCache = pdesc->GetShowCacheRegName();
  680. if (pszShowCache)
  681. {
  682. SHDeleteValue(HKEY_CURRENT_USER, REGSTR_EXPLORER_ADVANCED, pszShowCache);
  683. pThis->Invalidate();
  684. LocalFree(pszShowCache);
  685. }
  686. }
  687. }
  688. }
  689. pThis->Release();
  690. }
  691. SHCoUninitialize(hr);
  692. return 0;
  693. }
  694. BOOL ShouldShowItem(const SpecialFolderDesc *pdesc, BOOL bIgnoreRule, DWORD dwMode)
  695. {
  696. if (bIgnoreRule)
  697. return TRUE; // registry is over-riding whatever special rules exist...
  698. // if we've got a special rule, then the background thread will check it, so return false for now unless we showed it last time
  699. if (pdesc->_ShowFolder)
  700. {
  701. if (pdesc->IsCacheable())
  702. {
  703. if (dwMode & SFD_WASSHOWN)
  704. {
  705. // Last time we looked, there were enough kids so let's assume it hasn't changed for now
  706. return TRUE;
  707. }
  708. return FALSE;
  709. }
  710. else
  711. {
  712. return pdesc->_ShowFolder();
  713. }
  714. }
  715. return TRUE;
  716. }
  717. void SpecialFolderList::EnumItems()
  718. {
  719. // Clean out any previous register notifies.
  720. UINT id;
  721. for (id = 0; id < _cNotify; id++)
  722. {
  723. UnregisterNotify(id);
  724. }
  725. _cNotify = 0;
  726. // Start background enum for the MinKids since they can get hung up on the network
  727. AddRef();
  728. if (!SHQueueUserWorkItem(SpecialFolderList::_HasEnoughChildrenThreadProc, this, 0, 0, NULL, NULL, 0))
  729. {
  730. Release();
  731. }
  732. DWORD dwIndex;
  733. // Restrictions may result in an entire section disappearing,
  734. // so don't create two separators in a row. Preinitialize to TRUE
  735. // so we don't get separators at the top of the list.
  736. BOOL fIgnoreSeparators = TRUE;
  737. int iItems=0;
  738. for (dwIndex = 0; dwIndex < ARRAYSIZE(s_rgsfd); dwIndex++)
  739. {
  740. const SpecialFolderDesc *pdesc = &s_rgsfd[dwIndex];
  741. BOOL bIgnoreRule;
  742. DWORD dwMode = pdesc->GetDisplayMode(&bIgnoreRule);
  743. if (dwMode != SFD_HIDE)
  744. {
  745. SpecialFolderListItem *pitem = new SpecialFolderListItem(pdesc);
  746. if (pitem)
  747. {
  748. if ((pitem->IsSeparator() && !fIgnoreSeparators) ||
  749. (pitem->_pidl && ShouldShowItem(pdesc, bIgnoreRule, dwMode)))
  750. {
  751. if ((dwMode & SFD_MODEMASK) == SFD_CASCADE)
  752. {
  753. pitem->EnableCascade();
  754. }
  755. if (pdesc->IsDropTarget())
  756. {
  757. pitem->EnableDropTarget();
  758. }
  759. // Get the icon and display name now.
  760. if (!pitem->IsSeparator())
  761. {
  762. IShellFolder *psf;
  763. LPCITEMIDLIST pidlItem;
  764. HRESULT hr = SHBindToIDListParent(pitem->_pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlItem);
  765. if (SUCCEEDED(hr))
  766. {
  767. if (!pitem->_psfd->GetCustomName(&pitem->_pszDispName))
  768. pitem->_pszDispName = _DisplayNameOf(psf, pidlItem, SHGDN_NORMAL);
  769. pitem->_hIcon = _IconOf(psf, pidlItem, _cxIcon);
  770. psf->Release();
  771. }
  772. }
  773. fIgnoreSeparators = pitem->IsSeparator();
  774. // add the item
  775. AddItem(pitem, NULL, pitem->_pidl);
  776. if (!pitem->IsSeparator())
  777. iItems++;
  778. }
  779. else
  780. delete pitem;
  781. }
  782. }
  783. }
  784. SetDesiredSize(0, iItems);
  785. }
  786. int SpecialFolderList::AddImageForItem(PaneItem *p, IShellFolder *psf, LPCITEMIDLIST pidl, int iPos)
  787. {
  788. int iIcon = -1; // assume no icon
  789. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  790. if (pitem->_hIcon)
  791. {
  792. iIcon = AddImage(pitem->_hIcon);
  793. DestroyIcon(pitem->_hIcon);
  794. pitem->_hIcon = NULL;
  795. }
  796. return iIcon;
  797. }
  798. LPTSTR SpecialFolderList::DisplayNameOfItem(PaneItem *p, IShellFolder *psf, LPCITEMIDLIST pidlItem, SHGNO shgno)
  799. {
  800. LPTSTR psz = NULL;
  801. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  802. if (shgno == SHGDN_NORMAL && pitem->_pszDispName)
  803. {
  804. // We are going to transfer ownership
  805. psz = pitem->_pszDispName;
  806. pitem->_pszDispName = NULL;
  807. }
  808. else
  809. {
  810. if (!pitem->_psfd->GetCustomName(&psz))
  811. {
  812. psz = SFTBarHost::DisplayNameOfItem(p, psf, pidlItem, shgno);
  813. }
  814. }
  815. if ((pitem->_psfd->_uFlags & SFD_PREFIX) && psz)
  816. {
  817. SHFree(pitem->_pszAccelerator);
  818. pitem->_pszAccelerator = NULL;
  819. SHStrDup(psz, &pitem->_pszAccelerator); // if it fails, then tough, no mnemonic
  820. pitem->_chMnem = CharUpperChar(SHStripMneumonic(psz));
  821. }
  822. return psz;
  823. }
  824. int SpecialFolderList::CompareItems(PaneItem *p1, PaneItem *p2)
  825. {
  826. // SpecialFolderListItem *pitem1 = static_cast<SpecialFolderListItem *>(p1);
  827. // SpecialFolderListItem *pitem2 = static_cast<SpecialFolderListItem *>(p2);
  828. return 0; // we added them in the right order the first time
  829. }
  830. HRESULT SpecialFolderList::GetFolderAndPidl(PaneItem *p,
  831. IShellFolder **ppsfOut, LPCITEMIDLIST *ppidlOut)
  832. {
  833. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  834. return SHBindToIDListParent(pitem->_pidl, IID_PPV_ARG(IShellFolder, ppsfOut), ppidlOut);
  835. }
  836. void SpecialFolderList::GetItemInfoTip(PaneItem *p, LPTSTR pszText, DWORD cch)
  837. {
  838. SpecialFolderListItem *pitem = (SpecialFolderListItem*)p;
  839. if (pitem->_psfd->_iToolTip)
  840. LoadString(_Module.GetResourceInstance(), pitem->_psfd->_iToolTip, pszText, cch);
  841. else
  842. SFTBarHost::GetItemInfoTip(p, pszText, cch); // call the base class
  843. }
  844. HRESULT SpecialFolderList::ContextMenuRenameItem(PaneItem *p, LPCTSTR ptszNewName)
  845. {
  846. SpecialFolderListItem *pitem = (SpecialFolderListItem*)p;
  847. IShellFolder *psf;
  848. LPCITEMIDLIST pidlItem;
  849. HRESULT hr = GetFolderAndPidl(pitem, &psf, &pidlItem);
  850. if (SUCCEEDED(hr))
  851. {
  852. LPITEMIDLIST pidlNew;
  853. hr = psf->SetNameOf(_hwnd, pidlItem, ptszNewName, SHGDN_INFOLDER, &pidlNew);
  854. if (SUCCEEDED(hr))
  855. {
  856. pitem->ReplaceLastPidlElement(pidlNew);
  857. }
  858. psf->Release();
  859. }
  860. return hr;
  861. }
  862. //
  863. // If we get any changenotify, it means that somebody added (or thought about
  864. // adding) an item to one of our minkids folders, so we'll have to look to see
  865. // if it crossed the minkids threshold.
  866. //
  867. void SpecialFolderList::OnChangeNotify(UINT id, LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  868. {
  869. Invalidate();
  870. for (id = 0; id < _cNotify; id++)
  871. {
  872. UnregisterNotify(id);
  873. }
  874. _cNotify = 0;
  875. PostMessage(_hwnd, SFTBM_REFRESH, TRUE, 0);
  876. }
  877. BOOL SpecialFolderList::IsItemStillValid(PaneItem *p)
  878. {
  879. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  880. return pitem->IsStillValid();
  881. }
  882. BOOL SpecialFolderList::IsBold(PaneItem *p)
  883. {
  884. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  885. return pitem->_psfd->IsBold();
  886. }
  887. HRESULT SpecialFolderList::GetCascadeMenu(PaneItem *p, IShellMenu **ppsm)
  888. {
  889. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  890. IShellFolder *psf;
  891. HRESULT hr = SHBindToObjectEx(NULL, pitem->_pidl, NULL, IID_PPV_ARG(IShellFolder, &psf));
  892. if (SUCCEEDED(hr))
  893. {
  894. IShellMenu *psm;
  895. hr = CoCreateInstance(CLSID_MenuBand, NULL, CLSCTX_INPROC_SERVER,
  896. IID_PPV_ARG(IShellMenu, &psm));
  897. if (SUCCEEDED(hr))
  898. {
  899. //
  900. // Recent Documents requires special treatment.
  901. //
  902. IShellMenuCallback *psmc = NULL;
  903. hr = pitem->_psfd->CreateShellMenuCallback(&psmc);
  904. if (SUCCEEDED(hr))
  905. {
  906. DWORD dwFlags = SMINIT_TOPLEVEL | SMINIT_VERTICAL | pitem->_psfd->_dwShellFolderFlags;
  907. if (IsRestrictedOrUserSetting(HKEY_CURRENT_USER, REST_NOCHANGESTARMENU,
  908. TEXT("Advanced"), TEXT("Start_EnableDragDrop"),
  909. ROUS_DEFAULTALLOW | ROUS_KEYALLOWS))
  910. {
  911. dwFlags |= SMINIT_RESTRICT_DRAGDROP | SMINIT_RESTRICT_CONTEXTMENU;
  912. }
  913. psm->Initialize(psmc, 0, 0, dwFlags);
  914. HKEY hkCustom = NULL;
  915. if (pitem->_psfd->_pszCustomizeKey)
  916. {
  917. RegCreateKeyEx(HKEY_CURRENT_USER, pitem->_psfd->_pszCustomizeKey,
  918. NULL, NULL, REG_OPTION_NON_VOLATILE,
  919. KEY_READ | KEY_WRITE, NULL, &hkCustom, NULL);
  920. }
  921. dwFlags = SMSET_USEBKICONEXTRACTION;
  922. hr = psm->SetShellFolder(psf, pitem->_pidl, hkCustom, dwFlags);
  923. if (SUCCEEDED(hr))
  924. {
  925. // SetShellFolder takes ownership of hkCustom
  926. *ppsm = psm;
  927. psm->AddRef();
  928. }
  929. else
  930. {
  931. // Clean up the registry key since SetShellFolder
  932. // did not take ownership
  933. if (hkCustom)
  934. {
  935. RegCloseKey(hkCustom);
  936. }
  937. }
  938. ATOMICRELEASE(psmc); // psmc can be NULL
  939. }
  940. psm->Release();
  941. }
  942. psf->Release();
  943. }
  944. return hr;
  945. }
  946. TCHAR SpecialFolderList::GetItemAccelerator(PaneItem *p, int iItemStart)
  947. {
  948. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  949. if (pitem->_chMnem)
  950. {
  951. return pitem->_chMnem;
  952. }
  953. else
  954. {
  955. // Default: First letter is accelerator.
  956. return SFTBarHost::GetItemAccelerator(p, iItemStart);
  957. }
  958. }
  959. LRESULT SpecialFolderList::OnWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  960. {
  961. switch (uMsg)
  962. {
  963. case WM_NOTIFY:
  964. switch (((NMHDR*)(lParam))->code)
  965. {
  966. // When the user connects/disconnects via TS, we need to recalc
  967. // the "Windows Security" item
  968. case SMN_REFRESHLOGOFF:
  969. Invalidate();
  970. break;
  971. }
  972. }
  973. // Else fall back to parent implementation
  974. return SFTBarHost::OnWndProc(hwnd, uMsg, wParam, lParam);
  975. }
  976. BOOL _IsItemHiddenOnDesktop(LPCTSTR pszGuid)
  977. {
  978. return SHRegGetBoolUSValue(REGSTR_PATH_HIDDEN_DESKTOP_ICONS_STARTPANEL,
  979. pszGuid, FALSE, FALSE);
  980. }
  981. UINT SpecialFolderList::AdjustDeleteMenuItem(PaneItem *p, UINT *puiFlags)
  982. {
  983. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  984. if (pitem->_psfd->_pszCanHideOnDesktop)
  985. {
  986. // Set MF_CHECKED if the item is visible on the desktop
  987. if (!_IsItemHiddenOnDesktop(pitem->_psfd->_pszCanHideOnDesktop))
  988. {
  989. // Item is visible - show the checkbox
  990. *puiFlags |= MF_CHECKED;
  991. }
  992. return IDS_SFTHOST_SHOWONDESKTOP;
  993. }
  994. else
  995. {
  996. return 0; // not deletable
  997. }
  998. }
  999. HRESULT SpecialFolderList::ContextMenuInvokeItem(PaneItem *p, IContextMenu *pcm, CMINVOKECOMMANDINFOEX *pici, LPCTSTR pszVerb)
  1000. {
  1001. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  1002. HRESULT hr;
  1003. if (StrCmpIC(pszVerb, TEXT("delete")) == 0)
  1004. {
  1005. ASSERT(pitem->_psfd->_pszCanHideOnDesktop);
  1006. // Toggle the hide/unhide state
  1007. DWORD dwHide = !_IsItemHiddenOnDesktop(pitem->_psfd->_pszCanHideOnDesktop);
  1008. LONG lErr = SHRegSetUSValue(REGSTR_PATH_HIDDEN_DESKTOP_ICONS_STARTPANEL,
  1009. pitem->_psfd->_pszCanHideOnDesktop,
  1010. REG_DWORD, &dwHide, sizeof(dwHide),
  1011. SHREGSET_FORCE_HKCU);
  1012. hr = HRESULT_FROM_WIN32(lErr);
  1013. if (SUCCEEDED(hr))
  1014. {
  1015. // explorer\rcids.h and shell32\unicpp\resource.h have DIFFERENT
  1016. // VALUES FOR FCIDM_REFRESH! We want the one in unicpp\resource.h
  1017. // because that's the correct one...
  1018. #define FCIDM_REFRESH_REAL 0x0a220
  1019. PostMessage(GetShellWindow(), WM_COMMAND, FCIDM_REFRESH_REAL, 0); // refresh desktop
  1020. }
  1021. }
  1022. else
  1023. {
  1024. hr = SFTBarHost::ContextMenuInvokeItem(pitem, pcm, pici, pszVerb);
  1025. }
  1026. return hr;
  1027. }
  1028. HRESULT SpecialFolderList::_GetUIObjectOfItem(PaneItem *p, REFIID riid, LPVOID *ppv)
  1029. {
  1030. SpecialFolderListItem *pitem = static_cast<SpecialFolderListItem *>(p);
  1031. if (pitem->_psfd->IsCSIDL() && (CSIDL_RECENT == pitem->_psfd->GetCSIDL()))
  1032. {
  1033. *ppv = NULL;
  1034. return E_NOTIMPL;
  1035. }
  1036. return SFTBarHost::_GetUIObjectOfItem(p, riid, ppv);
  1037. }
  1038. //****************************************************************************
  1039. //
  1040. // IShellMenuCallback helper for Recent Documents
  1041. //
  1042. // We want to restrict to the first MAXRECDOCS items.
  1043. //
  1044. class CRecentShellMenuCallback
  1045. : public CUnknown
  1046. , public IShellMenuCallback
  1047. {
  1048. public:
  1049. // *** IUnknown ***
  1050. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  1051. STDMETHODIMP_(ULONG) AddRef(void) { return CUnknown::AddRef(); }
  1052. STDMETHODIMP_(ULONG) Release(void) { return CUnknown::Release(); }
  1053. // *** IShellMenuCallback ***
  1054. STDMETHODIMP CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1055. private:
  1056. friend HRESULT CRecentShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  1057. HRESULT _FilterRecentPidl(IShellFolder *psf, LPCITEMIDLIST pidlItem);
  1058. int _nShown;
  1059. int _iMaxRecentDocs;
  1060. };
  1061. HRESULT CRecentShellMenuCallback::QueryInterface(REFIID riid, void **ppvObj)
  1062. {
  1063. static const QITAB qit[] =
  1064. {
  1065. QITABENT(CRecentShellMenuCallback, IShellMenuCallback),
  1066. { 0 },
  1067. };
  1068. return QISearch(this, qit, riid, ppvObj);
  1069. }
  1070. HRESULT CRecentShellMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1071. {
  1072. switch (uMsg)
  1073. {
  1074. case SMC_BEGINENUM:
  1075. _nShown = 0;
  1076. _iMaxRecentDocs = SHRestricted(REST_MaxRecentDocs);
  1077. if (_iMaxRecentDocs < 1)
  1078. _iMaxRecentDocs = 15; // default from shell32\recdocs.h
  1079. return S_OK;
  1080. case SMC_FILTERPIDL:
  1081. ASSERT(psmd->dwMask & SMDM_SHELLFOLDER);
  1082. return _FilterRecentPidl(psmd->psf, psmd->pidlItem);
  1083. }
  1084. return S_FALSE;
  1085. }
  1086. //
  1087. // Return S_FALSE to allow the item to show, S_OK to hide it
  1088. //
  1089. HRESULT CRecentShellMenuCallback::_FilterRecentPidl(IShellFolder *psf, LPCITEMIDLIST pidlItem)
  1090. {
  1091. HRESULT hrRc = S_OK; // Assume hidden
  1092. if (_nShown < _iMaxRecentDocs)
  1093. {
  1094. IShellLink *psl;
  1095. if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidlItem, IID_X_PPV_ARG(IShellLink, NULL, &psl))))
  1096. {
  1097. LPITEMIDLIST pidlTarget;
  1098. if (SUCCEEDED(psl->GetIDList(&pidlTarget)) && pidlTarget)
  1099. {
  1100. DWORD dwAttr = SFGAO_FOLDER;
  1101. if (SUCCEEDED(SHGetAttributesOf(pidlTarget, &dwAttr)) &&
  1102. !(dwAttr & SFGAO_FOLDER))
  1103. {
  1104. // We found a shortcut to a nonfolder - keep it!
  1105. _nShown++;
  1106. hrRc = S_FALSE;
  1107. }
  1108. ILFree(pidlTarget);
  1109. }
  1110. psl->Release();
  1111. }
  1112. }
  1113. return hrRc;
  1114. }
  1115. HRESULT CRecentShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc)
  1116. {
  1117. *ppsmc = new CRecentShellMenuCallback;
  1118. return *ppsmc ? S_OK : E_OUTOFMEMORY;
  1119. }
  1120. //****************************************************************************
  1121. //
  1122. // IShellMenuCallback helper that disallows cascading into subfolders
  1123. //
  1124. class CNoSubdirShellMenuCallback
  1125. : public CUnknown
  1126. , public IShellMenuCallback
  1127. {
  1128. public:
  1129. // *** IUnknown ***
  1130. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  1131. STDMETHODIMP_(ULONG) AddRef(void) { return CUnknown::AddRef(); }
  1132. STDMETHODIMP_(ULONG) Release(void) { return CUnknown::Release(); }
  1133. // *** IShellMenuCallback ***
  1134. STDMETHODIMP CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1135. private:
  1136. friend HRESULT CNoSubdirShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  1137. };
  1138. HRESULT CNoSubdirShellMenuCallback::QueryInterface(REFIID riid, void **ppvObj)
  1139. {
  1140. static const QITAB qit[] =
  1141. {
  1142. QITABENT(CNoSubdirShellMenuCallback, IShellMenuCallback),
  1143. { 0 },
  1144. };
  1145. return QISearch(this, qit, riid, ppvObj);
  1146. }
  1147. HRESULT CNoSubdirShellMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1148. {
  1149. switch (uMsg)
  1150. {
  1151. case SMC_GETSFINFO:
  1152. {
  1153. // Turn off the SMIF_SUBMENU flag on everybody. This
  1154. // prevents us from cascading more than one level deel.
  1155. SMINFO *psminfo = reinterpret_cast<SMINFO *>(lParam);
  1156. psminfo->dwFlags &= ~SMIF_SUBMENU;
  1157. return S_OK;
  1158. }
  1159. }
  1160. return S_FALSE;
  1161. }
  1162. HRESULT CNoSubdirShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc)
  1163. {
  1164. *ppsmc = new CNoSubdirShellMenuCallback;
  1165. return *ppsmc ? S_OK : E_OUTOFMEMORY;
  1166. }
  1167. //****************************************************************************
  1168. //
  1169. // IShellMenuCallback helper for My Computer
  1170. //
  1171. // Disallow cascading into subfolders and also force the default
  1172. // drag/drop effect to DROPEFFECT_LINK.
  1173. //
  1174. class CMyComputerShellMenuCallback
  1175. : public CNoSubdirShellMenuCallback
  1176. {
  1177. public:
  1178. typedef CNoSubdirShellMenuCallback super;
  1179. // *** IShellMenuCallback ***
  1180. STDMETHODIMP CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1181. private:
  1182. friend HRESULT CMyComputerShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  1183. };
  1184. HRESULT CMyComputerShellMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1185. {
  1186. switch (uMsg)
  1187. {
  1188. case SMC_BEGINDRAG:
  1189. *(DWORD*)wParam = DROPEFFECT_LINK;
  1190. return S_OK;
  1191. }
  1192. return super::CallbackSM(psmd, uMsg, wParam, lParam);
  1193. }
  1194. HRESULT CMyComputerShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc)
  1195. {
  1196. *ppsmc = new CMyComputerShellMenuCallback;
  1197. return *ppsmc ? S_OK : E_OUTOFMEMORY;
  1198. }
  1199. //****************************************************************************
  1200. //
  1201. // IShellMenuCallback helper that prevents Fonts from cascading
  1202. // Used by Control Panel.
  1203. //
  1204. class CNoFontsShellMenuCallback
  1205. : public CUnknown
  1206. , public IShellMenuCallback
  1207. {
  1208. public:
  1209. // *** IUnknown ***
  1210. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  1211. STDMETHODIMP_(ULONG) AddRef(void) { return CUnknown::AddRef(); }
  1212. STDMETHODIMP_(ULONG) Release(void) { return CUnknown::Release(); }
  1213. // *** IShellMenuCallback ***
  1214. STDMETHODIMP CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1215. private:
  1216. friend HRESULT CNoFontsShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  1217. };
  1218. HRESULT CNoFontsShellMenuCallback::QueryInterface(REFIID riid, void **ppvObj)
  1219. {
  1220. static const QITAB qit[] =
  1221. {
  1222. QITABENT(CNoFontsShellMenuCallback, IShellMenuCallback),
  1223. { 0 },
  1224. };
  1225. return QISearch(this, qit, riid, ppvObj);
  1226. }
  1227. BOOL _IsFontsFolderShortcut(IShellFolder *psf, LPCITEMIDLIST pidl)
  1228. {
  1229. TCHAR sz[MAX_PATH];
  1230. return SUCCEEDED(DisplayNameOf(psf, pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, sz, ARRAYSIZE(sz))) &&
  1231. lstrcmpi(sz, TEXT("::{D20EA4E1-3957-11d2-A40B-0C5020524152}")) == 0;
  1232. }
  1233. HRESULT CNoFontsShellMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1234. {
  1235. switch (uMsg)
  1236. {
  1237. case SMC_GETSFINFO:
  1238. {
  1239. // If this is the Fonts item, then remove the SUBMENU attribute.
  1240. SMINFO *psminfo = reinterpret_cast<SMINFO *>(lParam);
  1241. if ((psminfo->dwMask & SMIM_FLAGS) &&
  1242. (psminfo->dwFlags & SMIF_SUBMENU) &&
  1243. _IsFontsFolderShortcut(psmd->psf, psmd->pidlItem))
  1244. {
  1245. psminfo->dwFlags &= ~SMIF_SUBMENU;
  1246. }
  1247. return S_OK;
  1248. }
  1249. }
  1250. return S_FALSE;
  1251. }
  1252. HRESULT CNoFontsShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc)
  1253. {
  1254. *ppsmc = new CNoFontsShellMenuCallback;
  1255. return *ppsmc ? S_OK : E_OUTOFMEMORY;
  1256. }
  1257. //****************************************************************************
  1258. //
  1259. // IShellMenuCallback helper that filters the "connect to" menu
  1260. //
  1261. class CConnectToShellMenuCallback
  1262. : public CUnknown
  1263. , public IShellMenuCallback
  1264. , public CObjectWithSite
  1265. {
  1266. public:
  1267. // *** IUnknown ***
  1268. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  1269. STDMETHODIMP_(ULONG) AddRef(void) { return CUnknown::AddRef(); }
  1270. STDMETHODIMP_(ULONG) Release(void) { return CUnknown::Release(); }
  1271. // *** IShellMenuCallback ***
  1272. STDMETHODIMP CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1273. // *** IObjectWithSite ***
  1274. // inherited from CObjectWithSite
  1275. private:
  1276. HRESULT _OnGetSFInfo(SMDATA *psmd, SMINFO *psminfo);
  1277. HRESULT _OnGetInfo(SMDATA *psmd, SMINFO *psminfo);
  1278. HRESULT _OnEndEnum(SMDATA *psmd);
  1279. friend HRESULT CConnectToShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc);
  1280. BOOL _bAnyRAS;
  1281. };
  1282. #define ICOL_NETCONMEDIATYPE 0x101 // from netshell
  1283. #define ICOL_NETCONSUBMEDIATYPE 0x102 // from netshell
  1284. #define ICOL_NETCONSTATUS 0x103 // from netshell
  1285. #define ICOL_NETCONCHARACTERISTICS 0x104 // from netshell
  1286. BOOL IsMediaRASType(NETCON_MEDIATYPE ncm)
  1287. {
  1288. return (ncm == NCM_DIRECT || ncm == NCM_ISDN || ncm == NCM_PHONE || ncm == NCM_TUNNEL || ncm == NCM_PPPOE); // REVIEW DIRECT correct?
  1289. }
  1290. BOOL IsNetConPidlRAS(IShellFolder2 *psfNetCon, LPCITEMIDLIST pidlNetConItem)
  1291. {
  1292. BOOL bRet = FALSE;
  1293. SHCOLUMNID scidMediaType, scidSubMediaType, scidCharacteristics;
  1294. VARIANT v;
  1295. scidMediaType.fmtid = GUID_NETSHELL_PROPS;
  1296. scidMediaType.pid = ICOL_NETCONMEDIATYPE;
  1297. scidSubMediaType.fmtid = GUID_NETSHELL_PROPS;
  1298. scidSubMediaType.pid = ICOL_NETCONSUBMEDIATYPE;
  1299. scidCharacteristics.fmtid = GUID_NETSHELL_PROPS;
  1300. scidCharacteristics.pid = ICOL_NETCONCHARACTERISTICS;
  1301. if (SUCCEEDED(psfNetCon->GetDetailsEx(pidlNetConItem, &scidMediaType, &v)))
  1302. {
  1303. // Is this a RAS connection
  1304. if (IsMediaRASType((NETCON_MEDIATYPE)v.lVal))
  1305. {
  1306. VariantClear(&v);
  1307. // Make sure it's not incoming
  1308. if (SUCCEEDED(psfNetCon->GetDetailsEx(pidlNetConItem, &scidCharacteristics, &v)))
  1309. {
  1310. if (!(NCCF_INCOMING_ONLY & v.lVal))
  1311. bRet = TRUE;
  1312. }
  1313. }
  1314. // Is this a Wireless LAN connection?
  1315. if (NCM_LAN == (NETCON_MEDIATYPE)v.lVal)
  1316. {
  1317. VariantClear(&v);
  1318. if (SUCCEEDED(psfNetCon->GetDetailsEx(pidlNetConItem, &scidSubMediaType, &v)))
  1319. {
  1320. if (NCSM_WIRELESS == (NETCON_SUBMEDIATYPE)v.lVal)
  1321. bRet = TRUE;
  1322. }
  1323. }
  1324. VariantClear(&v);
  1325. }
  1326. return bRet;
  1327. }
  1328. HRESULT CConnectToShellMenuCallback::_OnGetInfo(SMDATA *psmd, SMINFO *psminfo)
  1329. {
  1330. HRESULT hr = S_FALSE;
  1331. if (psminfo->dwMask & SMIM_ICON)
  1332. {
  1333. if (psmd->uId == IDM_OPENCONFOLDER)
  1334. {
  1335. LPITEMIDLIST pidl = SHCloneSpecialIDList(NULL, CSIDL_CONNECTIONS, FALSE);
  1336. if (pidl)
  1337. {
  1338. LPCITEMIDLIST pidlObject;
  1339. IShellFolder *psf;
  1340. hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlObject);
  1341. if (SUCCEEDED(hr))
  1342. {
  1343. SHMapPIDLToSystemImageListIndex(psf, pidlObject, &psminfo->iIcon);
  1344. psminfo->dwFlags |= SMIF_ICON;
  1345. psf->Release();
  1346. }
  1347. ILFree(pidl);
  1348. }
  1349. }
  1350. }
  1351. return hr;
  1352. }
  1353. HRESULT CConnectToShellMenuCallback::_OnGetSFInfo(SMDATA *psmd, SMINFO *psminfo)
  1354. {
  1355. IShellFolder2 *psf2;
  1356. ASSERT(psminfo->dwMask & SMIM_FLAGS); // ??
  1357. psminfo->dwFlags &= ~SMIF_SUBMENU;
  1358. if (SUCCEEDED(psmd->psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2))))
  1359. {
  1360. if (!IsNetConPidlRAS(psf2, psmd->pidlItem))
  1361. psminfo->dwFlags |= SMIF_HIDDEN;
  1362. else
  1363. _bAnyRAS = TRUE;
  1364. psf2->Release();
  1365. }
  1366. return S_OK;
  1367. }
  1368. HRESULT CConnectToShellMenuCallback::_OnEndEnum(SMDATA *psmd)
  1369. {
  1370. HRESULT hr = S_FALSE;
  1371. IShellMenu* psm;
  1372. if (psmd->punk && SUCCEEDED(hr = psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &psm))))
  1373. {
  1374. // load the static portion of the connect to menu, and add it to the bottom
  1375. HMENU hmStatic = LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(MENU_CONNECTTO));
  1376. if (hmStatic)
  1377. {
  1378. // if there aren't any dynamic items (RAS connections), then delete the separator
  1379. if (!_bAnyRAS)
  1380. DeleteMenu(hmStatic, 0, MF_BYPOSITION);
  1381. HWND hwnd = NULL;
  1382. IUnknown *punk;
  1383. if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SMenuPopup, IID_PPV_ARG(IUnknown, &punk))))
  1384. {
  1385. IUnknown_GetWindow(punk, &hwnd);
  1386. punk->Release();
  1387. }
  1388. psm->SetMenu(hmStatic, hwnd, SMSET_NOEMPTY | SMSET_BOTTOM);
  1389. }
  1390. psm->Release();
  1391. }
  1392. return hr;
  1393. }
  1394. HRESULT CConnectToShellMenuCallback::QueryInterface(REFIID riid, void **ppvObj)
  1395. {
  1396. static const QITAB qit[] =
  1397. {
  1398. QITABENT(CConnectToShellMenuCallback, IShellMenuCallback),
  1399. QITABENT(CConnectToShellMenuCallback, IObjectWithSite),
  1400. { 0 },
  1401. };
  1402. return QISearch(this, qit, riid, ppvObj);
  1403. }
  1404. HRESULT CConnectToShellMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1405. {
  1406. switch (uMsg)
  1407. {
  1408. case SMC_GETINFO:
  1409. return _OnGetInfo(psmd, (SMINFO *)lParam);
  1410. case SMC_GETSFINFO:
  1411. return _OnGetSFInfo(psmd, (SMINFO *)lParam);
  1412. case SMC_BEGINENUM:
  1413. _bAnyRAS = FALSE;
  1414. case SMC_ENDENUM:
  1415. return _OnEndEnum(psmd);
  1416. case SMC_EXEC:
  1417. switch (psmd->uId)
  1418. {
  1419. case IDM_OPENCONFOLDER:
  1420. ShowFolder(CSIDL_CONNECTIONS);
  1421. return S_OK;
  1422. }
  1423. break;
  1424. }
  1425. return S_FALSE;
  1426. }
  1427. HRESULT CConnectToShellMenuCallback_CreateInstance(IShellMenuCallback **ppsmc)
  1428. {
  1429. *ppsmc = new CConnectToShellMenuCallback;
  1430. return *ppsmc ? S_OK : E_OUTOFMEMORY;
  1431. }
  1432. BOOL SpecialFolderDesc::LoadStringAsOLESTR(LPTSTR *ppsz) const
  1433. {
  1434. BOOL bRet = FALSE;
  1435. TCHAR szTmp[MAX_PATH];
  1436. if (_idsCustomName && LoadString(_Module.GetResourceInstance(), _idsCustomName, szTmp, ARRAYSIZE(szTmp)))
  1437. {
  1438. if (ppsz)
  1439. SHStrDup(szTmp, ppsz);
  1440. bRet = TRUE;
  1441. }
  1442. return bRet;
  1443. }
  1444. BOOL SpecialFolderDesc::ConnectToName(LPTSTR *ppsz) const
  1445. {
  1446. BOOL bIgnoreRule;
  1447. DWORD dwMode = GetDisplayMode(&bIgnoreRule);
  1448. // if Connect To is displayed as a link, then don't over-ride the name (i.e. use Network Connections)
  1449. if ((dwMode & SFD_MODEMASK) == SFD_SHOW)
  1450. return FALSE;
  1451. else
  1452. return LoadStringAsOLESTR(ppsz);
  1453. }
  1454. void ShowFolder(UINT csidl)
  1455. {
  1456. LPITEMIDLIST pidl;
  1457. if (SUCCEEDED(SHGetFolderLocation(NULL, csidl, NULL, 0, &pidl)))
  1458. {
  1459. SHELLEXECUTEINFO shei = { 0 };
  1460. shei.cbSize = sizeof(shei);
  1461. shei.fMask = SEE_MASK_IDLIST;
  1462. shei.nShow = SW_SHOWNORMAL;
  1463. shei.lpVerb = TEXT("open");
  1464. shei.lpIDList = pidl;
  1465. ShellExecuteEx(&shei);
  1466. ILFree(pidl);
  1467. }
  1468. }