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.

939 lines
26 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <dobjutil.h>
  4. #include <regstr.h>
  5. #include "cputil.h"
  6. #define REGSTR_EXPLORER_ADVANCED (REGSTR_PATH_EXPLORER TEXT("\\Advanced"))
  7. HRESULT CFolder_Create2(HWND hwnd, LPCITEMIDLIST pidl, IShellFolder *psf, CFolder **ppsdf)
  8. {
  9. HRESULT hr;
  10. CFolder *psdf = new CFolder(hwnd);
  11. if (psdf)
  12. {
  13. hr = psdf->Init(pidl, psf);
  14. if (SUCCEEDED(hr))
  15. *ppsdf = psdf;
  16. else
  17. {
  18. psdf->Release();
  19. psdf = NULL;
  20. }
  21. }
  22. else
  23. hr = E_OUTOFMEMORY;
  24. return hr;
  25. }
  26. HRESULT CFolder_Create(HWND hwnd, LPCITEMIDLIST pidl, IShellFolder *psf, REFIID riid, void **ppv)
  27. {
  28. *ppv = NULL;
  29. CFolder *psdf;
  30. HRESULT hr = CFolder_Create2(hwnd, pidl, psf, &psdf);
  31. if (SUCCEEDED(hr))
  32. {
  33. hr = psdf->QueryInterface(riid, ppv);
  34. psdf->Release();
  35. }
  36. return hr;
  37. }
  38. // HRESULT CFolder_Create(HWND hwnd, LPITEMIDLIST pidl, IShellFolder *psf, CFolder **ppsdf)
  39. CFolder::CFolder(HWND hwnd) :
  40. _cRef(1), _hwnd(hwnd), _pidl(NULL), _psf(NULL), _psf2(NULL),
  41. CImpIDispatch(SDSPATCH_TYPELIB, IID_Folder3)
  42. {
  43. _fmt = 0;
  44. // Be sure that the OS is supporting the flags DATE_LTRREADING and DATE_RTLREADING
  45. if (g_bBiDiPlatform)
  46. {
  47. // Get the date format reading order
  48. LCID locale = GetUserDefaultLCID();
  49. if ( (PRIMARYLANGID(LANGIDFROMLCID(locale)) == LANG_ARABIC))
  50. {
  51. //Get the real list view windows ExStyle.
  52. // [msadek]; we shouldn't check for either WS_EX_RTLREADING OR RTL_MIRRORED_WINDOW
  53. // on localized builds we have both of them to display dirve letters,..etc correctly
  54. // on enabled builds we have none of them. let's check on RTL_MIRRORED_WINDOW only
  55. DWORD dwExStyle = GetWindowLong(_hwnd, GWL_EXSTYLE);
  56. if (dwExStyle & RTL_MIRRORED_WINDOW)
  57. _fmt = LVCFMT_RIGHT_TO_LEFT;
  58. else
  59. _fmt = LVCFMT_LEFT_TO_RIGHT;
  60. }
  61. }
  62. DllAddRef();
  63. }
  64. CFolder::~CFolder(void)
  65. {
  66. ATOMICRELEASE(_psd);
  67. ATOMICRELEASE(_psf2);
  68. ATOMICRELEASE(_psf);
  69. ATOMICRELEASE(_punkOwner);
  70. if (_pidl)
  71. ILFree(_pidl);
  72. // If we created an Application object release its site object...
  73. if (_pidApp)
  74. {
  75. IUnknown_SetSite(SAFECAST(_pidApp, IUnknown*), NULL);
  76. _pidApp->Release();
  77. }
  78. DllRelease();
  79. }
  80. STDMETHODIMP CFolder::SetSite(IUnknown *punkSite)
  81. {
  82. IUnknown_SetSite(SAFECAST(_pidApp, IUnknown*), punkSite);
  83. return CObjectWithSite::SetSite(punkSite);
  84. }
  85. STDMETHODIMP CFolder::SetOwner(IUnknown* punkOwner)
  86. {
  87. IUnknown_Set(&_punkOwner, punkOwner);
  88. return S_OK;
  89. }
  90. HRESULT CFolder::Init(LPCITEMIDLIST pidl, IShellFolder *psf)
  91. {
  92. HRESULT hr = SHILClone(pidl, &_pidl);
  93. if (SUCCEEDED(hr))
  94. {
  95. _psf = psf;
  96. if (_psf)
  97. _psf->AddRef();
  98. else
  99. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, _pidl, &_psf));
  100. if (_psf)
  101. _psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf2));
  102. }
  103. return hr;
  104. }
  105. STDMETHODIMP CFolder::QueryInterface(REFIID riid, void **ppv)
  106. {
  107. static const QITAB qit[] = {
  108. QITABENT(CFolder, Folder3),
  109. QITABENTMULTI(CFolder, Folder, Folder3),
  110. QITABENTMULTI(CFolder, Folder2, Folder3),
  111. QITABENTMULTI(CFolder, IDispatch, Folder3),
  112. QITABENTMULTI(CFolder, IPersist, IPersistFolder2),
  113. QITABENTMULTI(CFolder, IPersistFolder, IPersistFolder2),
  114. QITABENT(CFolder, IPersistFolder2),
  115. QITABENT(CFolder, IObjectSafety),
  116. QITABENT(CFolder, IObjectWithSite),
  117. QITABENT(CFolder, IShellService),
  118. { 0 },
  119. };
  120. return QISearch(this, qit, riid, ppv);
  121. }
  122. STDMETHODIMP_(ULONG) CFolder::AddRef(void)
  123. {
  124. return InterlockedIncrement(&_cRef);
  125. }
  126. STDMETHODIMP_(ULONG) CFolder::Release(void)
  127. {
  128. if (InterlockedDecrement(&_cRef))
  129. return _cRef;
  130. delete this;
  131. return 0;
  132. }
  133. HRESULT CFolder::_Application(IDispatch **ppid)
  134. {
  135. HRESULT hr = _SecurityCheck();
  136. if (SUCCEEDED(hr))
  137. {
  138. hr = CShellDispatch_CreateInstance(NULL, IID_PPV_ARG(IDispatch, ppid));
  139. if (SUCCEEDED(hr))
  140. {
  141. IUnknown_SetSite(*ppid, _punkSite);
  142. if (_dwSafetyOptions)
  143. hr = MakeSafeForScripting((IUnknown**)ppid);
  144. }
  145. }
  146. return hr;
  147. }
  148. // Folder implementation
  149. STDMETHODIMP CFolder::get_Application(IDispatch **ppid)
  150. {
  151. *ppid = NULL;
  152. if (!_pidApp)
  153. _Application(&_pidApp);
  154. return _pidApp ? _pidApp->QueryInterface(IID_PPV_ARG(IDispatch, ppid)) : E_FAIL;
  155. }
  156. STDMETHODIMP CFolder::get_Parent(IDispatch **ppid)
  157. {
  158. *ppid = NULL;
  159. return E_NOTIMPL;
  160. }
  161. // returns:
  162. // S_OK - success
  163. // S_FALSE - failure, but not a script error
  164. STDMETHODIMP CFolder::_ParentFolder(Folder **ppdf)
  165. {
  166. *ppdf = NULL; // assume error
  167. if (ILIsEmpty(_pidl))
  168. return S_FALSE; // automation compat, let script check error
  169. LPITEMIDLIST pidl;
  170. HRESULT hr = SHILClone(_pidl, &pidl);
  171. if (SUCCEEDED(hr))
  172. {
  173. ILRemoveLastID(pidl);
  174. hr = CFolder_Create(_hwnd, pidl, NULL, IID_PPV_ARG(Folder, ppdf));
  175. if (SUCCEEDED(hr))
  176. {
  177. IUnknown_SetSite(*ppdf, _punkSite);
  178. if (_dwSafetyOptions)
  179. {
  180. hr = MakeSafeForScripting((IUnknown**)ppdf);
  181. }
  182. }
  183. ILFree(pidl);
  184. }
  185. return hr;
  186. }
  187. HRESULT CFolder::_SecurityCheck()
  188. {
  189. return (!_dwSafetyOptions || (IsSafePage(_punkSite) == S_OK)) ? S_OK : E_ACCESSDENIED;
  190. }
  191. STDMETHODIMP CFolder::get_ParentFolder(Folder **ppdf)
  192. {
  193. *ppdf = NULL; // assume error
  194. HRESULT hr = _SecurityCheck();
  195. if (SUCCEEDED(hr))
  196. {
  197. hr = _ParentFolder(ppdf);
  198. }
  199. return hr;
  200. }
  201. STDMETHODIMP CFolder::get_Title(BSTR *pbs)
  202. {
  203. *pbs = NULL;
  204. HRESULT hr = _SecurityCheck();
  205. if (SUCCEEDED(hr))
  206. {
  207. SHFILEINFO sfi;
  208. if (SHGetFileInfo((LPCTSTR)_pidl, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME | SHGFI_PIDL))
  209. *pbs = SysAllocStringT(sfi.szDisplayName);
  210. hr = S_OK;
  211. }
  212. return hr;
  213. }
  214. IShellDetails * CFolder::_GetShellDetails(void)
  215. {
  216. if (!_psd)
  217. {
  218. if (_psf)
  219. _psf->CreateViewObject(_hwnd, IID_PPV_ARG(IShellDetails, &_psd));
  220. }
  221. return _psd;
  222. }
  223. STDMETHODIMP CFolder::Items(FolderItems **ppid)
  224. {
  225. *ppid = NULL;
  226. HRESULT hr = _SecurityCheck();
  227. if (SUCCEEDED(hr))
  228. {
  229. hr = CFolderItems_Create(this, FALSE, ppid);
  230. if (SUCCEEDED(hr))
  231. {
  232. IUnknown_SetSite(*ppid, _punkSite);
  233. if (_dwSafetyOptions)
  234. {
  235. hr = MakeSafeForScripting((IUnknown**)ppid);
  236. }
  237. }
  238. }
  239. return hr;
  240. }
  241. STDMETHODIMP CFolder::ParseName(BSTR bName, FolderItem **ppfi)
  242. {
  243. *ppfi = NULL;
  244. // lets be strict here and not allow them to do much...
  245. HRESULT hr = _SecurityCheck();
  246. if (SUCCEEDED(hr))
  247. {
  248. ULONG chEaten;
  249. LPITEMIDLIST pidl;
  250. hr = _psf->ParseDisplayName(_hwnd, NULL, bName, &chEaten, &pidl, NULL);
  251. if (SUCCEEDED(hr))
  252. {
  253. LPITEMIDLIST pidlLast = ILFindLastID(pidl);
  254. if (pidlLast == pidl)
  255. {
  256. hr = CFolderItem_Create(this, pidl, ppfi);
  257. }
  258. else
  259. {
  260. LPITEMIDLIST pidlFull = ILCombine(_pidl, pidl);
  261. if (pidlFull)
  262. {
  263. CFolderItem_CreateFromIDList(_hwnd, pidlFull, ppfi);
  264. ILFree(pidlFull);
  265. }
  266. else
  267. hr = E_OUTOFMEMORY;
  268. }
  269. ILFree(pidl);
  270. }
  271. if (hr != S_OK) // Scripts barf on errors returned
  272. {
  273. ppfi = NULL;
  274. hr = S_FALSE;
  275. }
  276. }
  277. return hr;
  278. }
  279. STDMETHODIMP CFolder::NewFolder(BSTR bName, VARIANT vOptions)
  280. {
  281. HRESULT hr = _SecurityCheck();
  282. if (SUCCEEDED(hr))
  283. {
  284. IStorage *pstg;
  285. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IStorage, _pidl, &pstg));
  286. if (SUCCEEDED(hr))
  287. {
  288. IStorage *pstgNew;
  289. hr = pstg->CreateStorage(bName, STGM_FAILIFTHERE, 0, 0, &pstgNew);
  290. if (SUCCEEDED(hr))
  291. {
  292. pstgNew->Release();
  293. }
  294. else if (STG_E_FILEALREADYEXISTS == hr)
  295. {
  296. hr = S_OK;
  297. }
  298. pstg->Release();
  299. }
  300. }
  301. return hr;
  302. }
  303. STDMETHODIMP CFolder::MoveHere(VARIANT vItem, VARIANT vOptions)
  304. {
  305. return _MoveOrCopy(TRUE, vItem, vOptions);
  306. }
  307. STDMETHODIMP CFolder::CopyHere(VARIANT vItem, VARIANT vOptions)
  308. {
  309. return _MoveOrCopy(FALSE, vItem, vOptions);
  310. }
  311. // get the IDList for an item from a VARIANT that is a FolderItem dispatch object
  312. STDMETHODIMP CFolder::GetDetailsOf(VARIANT vItem, int iColumn, BSTR *pbs)
  313. {
  314. *pbs = NULL;
  315. HRESULT hr = _SecurityCheck();
  316. if (SUCCEEDED(hr))
  317. {
  318. TCHAR szBuf[INFOTIPSIZE];
  319. szBuf[0] = 0;
  320. LPCITEMIDLIST pidl = CFolderItem::_GetIDListFromVariant(&vItem); // returns an ALIAS
  321. if (iColumn == -1) // infotip for the item
  322. {
  323. if (pidl)
  324. GetInfoTipHelp(_psf, pidl, szBuf, ARRAYSIZE(szBuf));
  325. }
  326. else
  327. {
  328. BOOL bUseDetails;
  329. SHELLDETAILS sd;
  330. sd.fmt = _fmt;
  331. sd.str.uType = STRRET_CSTR;
  332. sd.str.cStr[0] = 0;
  333. if (_psf2)
  334. bUseDetails = (E_NOTIMPL == _psf2->GetDetailsOf(pidl, iColumn, &sd));
  335. else
  336. bUseDetails = TRUE;
  337. if (bUseDetails)
  338. {
  339. IShellDetails* psd = _GetShellDetails();
  340. if (psd)
  341. psd->GetDetailsOf(pidl, iColumn, &sd);
  342. }
  343. StrRetToBuf(&sd.str, pidl, szBuf, ARRAYSIZE(szBuf));
  344. }
  345. *pbs = SysAllocStringT(szBuf);
  346. hr = *pbs ? S_OK : E_OUTOFMEMORY;
  347. }
  348. return hr;
  349. }
  350. HRESULT CFolder::get_Self(FolderItem **ppfi)
  351. {
  352. *ppfi = NULL;
  353. HRESULT hr = _SecurityCheck();
  354. if (SUCCEEDED(hr))
  355. {
  356. Folder *psdf;
  357. if (ILIsEmpty(_pidl))
  358. {
  359. psdf = this;
  360. psdf->AddRef();
  361. hr = S_OK;
  362. }
  363. else
  364. hr = _ParentFolder(&psdf);
  365. if (SUCCEEDED(hr))
  366. {
  367. hr = CFolderItem_Create((CFolder*)psdf, ILFindLastID(_pidl), ppfi);
  368. if (SUCCEEDED(hr) && _dwSafetyOptions)
  369. hr = MakeSafeForScripting((IUnknown**)ppfi);
  370. psdf->Release();
  371. }
  372. else
  373. *ppfi = NULL;
  374. }
  375. return hr;
  376. }
  377. BOOL _VerifyUNC(LPTSTR psz, ULONG cch)
  378. {
  379. if (PathIsUNC(psz))
  380. {
  381. return TRUE;
  382. }
  383. else if (psz[1] == TEXT(':'))
  384. {
  385. TCHAR szLocalName[3] = { psz[0], psz[1], TEXT('\0') };
  386. // Call GetDriveType before WNetGetConnection, to avoid loading
  387. // MPR.DLL unless absolutely necessary.
  388. if (DRIVE_REMOTE == GetDriveType(szLocalName) &&
  389. S_OK == WNetGetConnection(szLocalName, psz, &cch))
  390. {
  391. return TRUE;
  392. }
  393. }
  394. return FALSE;
  395. }
  396. HRESULT GetSharePath(LPCITEMIDLIST pidl, LPTSTR psz, ULONG cch)
  397. {
  398. HRESULT hr = E_FAIL;
  399. if (SHGetPathFromIDList(pidl, psz))
  400. {
  401. if (_VerifyUNC(psz, cch))
  402. hr = S_OK;
  403. else
  404. {
  405. // check for folder shortcuts.
  406. IShellFolder *psf;
  407. if (SUCCEEDED(SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidl, &psf))))
  408. {
  409. IShellLink *psl;
  410. if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IShellLink, &psl))))
  411. {
  412. if (SUCCEEDED(psl->GetPath(psz, cch, NULL, 0))
  413. && _VerifyUNC(psz, cch))
  414. hr = S_OK;
  415. psl->Release();
  416. }
  417. psf->Release();
  418. }
  419. }
  420. if (SUCCEEDED(hr))
  421. PathStripToRoot(psz);
  422. }
  423. return hr;
  424. }
  425. #include <cscuiext.h>
  426. STDMETHODIMP CFolder::get_OfflineStatus(LONG *pul)
  427. {
  428. HRESULT hr = _SecurityCheck();
  429. if (SUCCEEDED(hr))
  430. {
  431. TCHAR szShare[MAX_PATH];
  432. *pul = OFS_INACTIVE; // default
  433. // Make sure we have a UNC \\server\share path. Do this before
  434. // checking whether CSC is enabled, to avoid loading CSCDLL.DLL
  435. // unless absolutely necessary.
  436. if (SUCCEEDED(GetSharePath(_pidl, szShare, ARRAYSIZE(szShare))))
  437. {
  438. *pul = GetOfflineShareStatus(szShare);
  439. }
  440. hr = S_OK;
  441. }
  442. return hr;
  443. }
  444. STDMETHODIMP CFolder::Synchronize(void)
  445. {
  446. HRESULT hr = _SecurityCheck();
  447. if (SUCCEEDED(hr))
  448. {
  449. HWND hwndCSCUI = FindWindow(STR_CSCHIDDENWND_CLASSNAME, STR_CSCHIDDENWND_TITLE);
  450. if (hwndCSCUI)
  451. PostMessage(hwndCSCUI, CSCWM_SYNCHRONIZE, 0, 0);
  452. hr = S_OK;
  453. }
  454. return hr;
  455. }
  456. #define REGSTR_WEBVIEW_BARRICADEDFOLDERS (REGSTR_PATH_EXPLORER TEXT("\\WebView\\BarricadedFolders"))
  457. #define REGSTR_VALUE_BARRICADE TEXT("WebViewBarricade")
  458. BOOL GetBarricadeValueNameFromPidl(LPCITEMIDLIST pidl, LPTSTR pszValueName, UINT cch)
  459. {
  460. pszValueName[0] = TEXT('\0');
  461. TCHAR szPath[MAX_PATH];
  462. if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL)))
  463. {
  464. if (!MakeShellURLFromPath(szPath, pszValueName, cch))
  465. {
  466. if (lstrcmp(szPath, TEXT("EntireNetwork")) == 0)
  467. {
  468. lstrcpyn(pszValueName, TEXT("shell:EntireNetwork"), cch);
  469. }
  470. else if (PathIsRoot(szPath))
  471. {
  472. TCHAR szSystemDir[MAX_PATH];
  473. szSystemDir[0] = TEXT('\0');
  474. GetWindowsDirectory(szSystemDir, ARRAYSIZE(szSystemDir));
  475. if (PathIsSameRoot(szPath, szSystemDir))
  476. {
  477. lstrcpyn(pszValueName, TEXT("shell:SystemDriveRootFolder"), cch);
  478. }
  479. }
  480. else
  481. {
  482. LPITEMIDLIST pidlTemp = NULL;
  483. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlTemp)))
  484. {
  485. if (ILIsEqual(pidl, pidlTemp))
  486. {
  487. lstrcpyn(pszValueName, TEXT("shell:ControlPanelFolder"), cch);
  488. }
  489. ILFree(pidlTemp);
  490. }
  491. }
  492. }
  493. }
  494. return BOOLIFY(pszValueName[0]);
  495. }
  496. BOOL IsBarricadeGloballyOff()
  497. {
  498. return SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, REGSTR_VALUE_BARRICADE, FALSE, FALSE);
  499. }
  500. VARIANT_BOOL GetBarricadeStatus(LPCTSTR pszValueName)
  501. {
  502. VARIANT_BOOL bShowBarricade;
  503. if (!SHRegGetBoolUSValue(REGSTR_WEBVIEW_BARRICADEDFOLDERS, pszValueName, FALSE, TRUE))
  504. {
  505. bShowBarricade = VARIANT_FALSE; // ==> Don't show the barricade
  506. }
  507. else
  508. {
  509. bShowBarricade = VARIANT_TRUE;
  510. }
  511. return bShowBarricade;
  512. }
  513. STDMETHODIMP CFolder::get_ShowWebViewBarricade(VARIANT_BOOL *pbShowWebViewBarricade)
  514. {
  515. HRESULT hr = _SecurityCheck();
  516. if (SUCCEEDED(hr))
  517. {
  518. VARIANT_BOOL bShowBarricade = VARIANT_FALSE;
  519. //
  520. // Control panel is a special case.
  521. // The barricade is used to represent 'category view' which can
  522. // be turned on/off by the user and also by global webview settings.
  523. // To determine the true barricade status, we ask the control panel
  524. // code if the new 'category' view is active.
  525. //
  526. BOOL bIsControlPanel = FALSE;
  527. LPITEMIDLIST pidlControlPanel;
  528. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlControlPanel)))
  529. {
  530. bIsControlPanel = ILIsEqual(_pidl, pidlControlPanel);
  531. ILFree (pidlControlPanel);
  532. }
  533. if (bIsControlPanel)
  534. {
  535. //
  536. // When someone wants' to know if control panel's barricade is on,
  537. // they really want to know if it's configured for 'category' view.
  538. //
  539. if (CPL::CategoryViewIsActive(NULL))
  540. {
  541. bShowBarricade = VARIANT_TRUE;
  542. }
  543. }
  544. else
  545. {
  546. TCHAR szValueName[MAX_PATH];
  547. if (GetBarricadeValueNameFromPidl(_pidl, szValueName, ARRAYSIZE(szValueName)))
  548. {
  549. bShowBarricade = GetBarricadeStatus(szValueName);
  550. }
  551. }
  552. *pbShowWebViewBarricade = bShowBarricade;
  553. hr = S_OK;
  554. }
  555. return hr;
  556. }
  557. STDMETHODIMP CFolder::get_HaveToShowWebViewBarricade(VARIANT_BOOL *pbHaveToShowWebViewBarricade)
  558. {
  559. return get_ShowWebViewBarricade(pbHaveToShowWebViewBarricade);
  560. }
  561. HRESULT SetBarricadeStatus(LPCTSTR pszValueName, VARIANT_BOOL bShowBarricade)
  562. {
  563. HRESULT hr = E_FAIL;
  564. DWORD dwBarricade = (bShowBarricade == VARIANT_FALSE) ? 0 : 1;
  565. if (dwBarricade)
  566. {
  567. DWORD dw = 0; // Unset "Barricade off for all folders" key
  568. SHRegSetUSValue(REGSTR_EXPLORER_ADVANCED, REGSTR_VALUE_BARRICADE, REG_DWORD, (void *)&dw, sizeof(dw), SHREGSET_FORCE_HKCU);
  569. }
  570. if (SHRegSetUSValue(REGSTR_WEBVIEW_BARRICADEDFOLDERS, pszValueName, REG_DWORD, (void *)&dwBarricade, sizeof(dwBarricade), SHREGSET_FORCE_HKCU) == ERROR_SUCCESS)
  571. {
  572. hr = S_OK;
  573. }
  574. return hr;
  575. }
  576. STDMETHODIMP CFolder::put_ShowWebViewBarricade(VARIANT_BOOL bShowWebViewBarricade)
  577. {
  578. HRESULT hr = _SecurityCheck();
  579. if (SUCCEEDED(hr))
  580. {
  581. // First, see if it is the root of the system drive
  582. TCHAR szValueName[MAX_PATH];
  583. if (GetBarricadeValueNameFromPidl(_pidl, szValueName, ARRAYSIZE(szValueName)))
  584. {
  585. SetBarricadeStatus(szValueName, bShowWebViewBarricade);
  586. }
  587. }
  588. return hr;
  589. }
  590. STDMETHODIMP CFolder::DismissedWebViewBarricade()
  591. {
  592. return put_ShowWebViewBarricade(VARIANT_FALSE);
  593. }
  594. HRESULT GetUIObjectFromVariant(VARIANT vItems, HWND hwnd, REFIID riid, void **ppv)
  595. {
  596. *ppv = NULL;
  597. HRESULT hr = E_FAIL;
  598. LPITEMIDLIST pidl = VariantToIDList(&vItems);
  599. if (pidl)
  600. {
  601. hr = SHGetUIObjectFromFullPIDL(pidl, hwnd, riid, ppv);
  602. ILFree(pidl);
  603. }
  604. else
  605. {
  606. if (vItems.vt == (VT_BYREF | VT_VARIANT) && vItems.pvarVal)
  607. vItems = *vItems.pvarVal;
  608. FolderItems *pfis;
  609. if ((VT_DISPATCH == vItems.vt) && vItems.pdispVal &&
  610. SUCCEEDED(vItems.pdispVal->QueryInterface(IID_PPV_ARG(FolderItems, &pfis))))
  611. {
  612. long cItems;
  613. if (S_OK == pfis->get_Count(&cItems) && cItems)
  614. {
  615. LPITEMIDLIST *ppidl = (LPITEMIDLIST *)LocalAlloc(LPTR, sizeof(*ppidl) * cItems);
  616. if (ppidl)
  617. {
  618. IShellFolder *psf = NULL;
  619. VARIANT v = {VT_I4};
  620. for (v.lVal = 0; v.lVal < cItems; v.lVal++)
  621. {
  622. FolderItem *pfi;
  623. if (SUCCEEDED(pfis->Item(v, &pfi)) && pfi)
  624. {
  625. IParentAndItem *pfai;
  626. if (SUCCEEDED(pfi->QueryInterface(IID_PPV_ARG(IParentAndItem, &pfai))))
  627. {
  628. pfai->GetParentAndItem(NULL, 0 == v.lVal ? &psf : NULL, &(ppidl[v.lVal]));
  629. pfai->Release();
  630. }
  631. pfi->Release();
  632. }
  633. }
  634. if (psf)
  635. {
  636. hr = psf->GetUIObjectOf(hwnd, cItems, (LPCITEMIDLIST *)ppidl, riid, NULL, ppv);
  637. psf->Release();
  638. }
  639. for (v.lVal = 0; v.lVal < cItems; v.lVal++)
  640. {
  641. ILFree(ppidl[v.lVal]);
  642. }
  643. LocalFree(ppidl);
  644. }
  645. }
  646. pfis->Release();
  647. }
  648. }
  649. return hr;
  650. }
  651. DWORD VariantToDWORD(VARIANT vOptions)
  652. {
  653. DWORD dw = 0;
  654. if (vOptions.vt == (VT_BYREF | VT_VARIANT) && vOptions.pvarVal)
  655. vOptions = *vOptions.pvarVal;
  656. // We need to get the source files out of the variant.
  657. // Currently support string, or IDispatch (Either FolderItem or FolderItems)
  658. switch (vOptions.vt)
  659. {
  660. case VT_I2:
  661. dw = (FILEOP_FLAGS)vOptions.iVal;
  662. break;
  663. case VT_I4:
  664. dw = (FILEOP_FLAGS)vOptions.lVal;
  665. break;
  666. }
  667. return dw;
  668. }
  669. // Main function to do Move or Copy
  670. HRESULT CFolder::_MoveOrCopy(BOOL bMove, VARIANT vItems, VARIANT vOptions)
  671. {
  672. HRESULT hr = _SecurityCheck();
  673. if (SUCCEEDED(hr))
  674. {
  675. IDropTarget *pdtgt;
  676. hr = _psf->CreateViewObject(_hwnd, IID_PPV_ARG(IDropTarget, &pdtgt));
  677. if (SUCCEEDED(hr))
  678. {
  679. IUnknown_SetSite(pdtgt, _punkSite);
  680. IDataObject *pdtobj;
  681. hr = GetUIObjectFromVariant(vItems, _hwnd, IID_PPV_ARG(IDataObject, &pdtobj));
  682. if (SUCCEEDED(hr))
  683. {
  684. FILEOP_FLAGS fof = (FILEOP_FLAGS)VariantToDWORD(vOptions);
  685. if (fof)
  686. {
  687. static UINT s_cfFileOpFlags = 0;
  688. if (0 == s_cfFileOpFlags)
  689. s_cfFileOpFlags = RegisterClipboardFormat(TEXT("FileOpFlags"));
  690. DataObj_SetDWORD(pdtobj, s_cfFileOpFlags, fof);
  691. }
  692. DWORD grfKeyState = bMove ? MK_SHIFT | MK_LBUTTON : MK_CONTROL | MK_LBUTTON;
  693. hr = SHSimulateDrop(pdtgt, pdtobj, grfKeyState, NULL, NULL);
  694. pdtobj->Release();
  695. }
  696. IUnknown_SetSite(pdtgt, NULL);
  697. pdtgt->Release();
  698. }
  699. hr = SUCCEEDED(hr) ? S_OK : S_FALSE;
  700. }
  701. return hr;
  702. }
  703. STDMETHODIMP CFolder::GetClassID(CLSID *pClassID)
  704. {
  705. return E_NOTIMPL;
  706. }
  707. STDMETHODIMP CFolder::Initialize(LPCITEMIDLIST pidl)
  708. {
  709. return E_NOTIMPL;
  710. }
  711. STDMETHODIMP CFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  712. {
  713. return SHILClone(_pidl, ppidl);
  714. }
  715. HRESULT CFolder::InvokeVerbHelper(VARIANT vVerb, VARIANT vArgs, LPCITEMIDLIST *ppidl, int cItems, DWORD dwSafetyOptions)
  716. {
  717. if (!dwSafetyOptions || (_SecurityCheck() == S_OK))
  718. {
  719. BOOL fDefaultVerb = TRUE;
  720. TCHAR szCmd[128];
  721. switch (vVerb.vt)
  722. {
  723. case VT_BSTR:
  724. fDefaultVerb = FALSE;
  725. SHUnicodeToTChar(vVerb.bstrVal, szCmd, ARRAYSIZE(szCmd));
  726. break;
  727. }
  728. HRESULT hr = S_OK;
  729. IContextMenu *pcm;
  730. if (SUCCEEDED(_psf->GetUIObjectOf(_hwnd, cItems, ppidl, IID_PPV_ARG_NULL(IContextMenu, &pcm))))
  731. {
  732. IShellFolderView *psfv;
  733. if (SUCCEEDED(GetShellFolderView(&psfv)))
  734. {
  735. IUnknown_SetSite(pcm, psfv);
  736. }
  737. else
  738. {
  739. ASSERT(NULL == psfv);
  740. }
  741. MENUITEMINFO mii;
  742. HMENU hmenu = CreatePopupMenu();
  743. if (NULL != hmenu)
  744. {
  745. pcm->QueryContextMenu(hmenu, 0, CONTEXTMENU_IDCMD_FIRST, CONTEXTMENU_IDCMD_LAST, fDefaultVerb ? CMF_DEFAULTONLY : CMF_CANRENAME);
  746. int idCmd = 0;
  747. if (fDefaultVerb)
  748. idCmd = GetMenuDefaultItem(hmenu, MF_BYCOMMAND, 0);
  749. else
  750. {
  751. // REVIEW: this should never have been done this way. Can we rip it out?
  752. //
  753. // find a verb that matches name by display name (ugly)
  754. for (int i = GetMenuItemCount(hmenu) - 1; i >= 0; i--)
  755. {
  756. TCHAR szText[128]; // should be big enough for this
  757. mii.cbSize = sizeof(MENUITEMINFO);
  758. mii.dwTypeData = szText;
  759. mii.fMask = MIIM_ID | MIIM_TYPE;
  760. mii.cch = ARRAYSIZE(szText);
  761. mii.fType = MFT_SEPARATOR; // to avoid ramdom result.
  762. mii.dwItemData = 0;
  763. GetMenuItemInfo(hmenu, i, TRUE, &mii);
  764. if (lstrcmpi(szText, szCmd) == 0)
  765. {
  766. idCmd = mii.wID;
  767. break;
  768. }
  769. }
  770. }
  771. if (!idCmd)
  772. {
  773. // that didn't work, find it the right way by the canonical verb name
  774. int iItem = GetMenuIndexForCanonicalVerb(hmenu, pcm, CONTEXTMENU_IDCMD_FIRST, vVerb.bstrVal);
  775. if (-1 != iItem)
  776. {
  777. mii.cbSize = sizeof(MENUITEMINFO);
  778. mii.fMask = MIIM_ID;
  779. if (GetMenuItemInfo(hmenu, iItem, MF_BYPOSITION, &mii))
  780. idCmd = mii.wID;
  781. }
  782. }
  783. if (idCmd)
  784. {
  785. CMINVOKECOMMANDINFO ici = {
  786. sizeof(CMINVOKECOMMANDINFO),
  787. 0L,
  788. _hwnd,
  789. NULL,
  790. NULL, NULL,
  791. SW_SHOWNORMAL,
  792. };
  793. ici.lpVerb = (LPSTR)MAKEINTRESOURCE(idCmd - CONTEXTMENU_IDCMD_FIRST);
  794. char szArgs[MAX_PATH]; // max size we will currently use.
  795. // See if we are supposed to pass any arguments on the command line
  796. switch (vArgs.vt)
  797. {
  798. case VT_BSTR:
  799. SHUnicodeToAnsi(vArgs.bstrVal, szArgs, ARRAYSIZE(szArgs));
  800. ici.lpParameters = szArgs;
  801. break;
  802. }
  803. // Finally invoke the command
  804. pcm->InvokeCommand(&ici);
  805. }
  806. DestroyMenu(hmenu);
  807. }
  808. else
  809. {
  810. hr = E_OUTOFMEMORY;
  811. }
  812. if (psfv)
  813. {
  814. IUnknown_SetSite(pcm, NULL);
  815. psfv->Release();
  816. }
  817. pcm->Release();
  818. }
  819. return hr;
  820. }
  821. return E_ACCESSDENIED;
  822. }
  823. HRESULT CFolder::GetShellFolderView(IShellFolderView **ppsfv)
  824. {
  825. return IUnknown_QueryService(_punkOwner, SID_DefView, IID_PPV_ARG(IShellFolderView, ppsfv));
  826. }