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.

567 lines
17 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include "stdenum.h"
  4. #define DM_SDFOLDER 0
  5. class CShellFolderView : public IShellFolderViewDual2,
  6. public IShellService,
  7. public IServiceProvider,
  8. public CObjectSafety,
  9. public CObjectWithSite,
  10. protected CImpIConnectionPointContainer,
  11. protected CImpIExpDispSupport,
  12. protected CImpIDispatch
  13. {
  14. public:
  15. CShellFolderView(void);
  16. // IUnknown
  17. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  18. STDMETHODIMP_(ULONG) AddRef(void);
  19. STDMETHODIMP_(ULONG) Release(void);
  20. // IDispatch
  21. STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
  22. { return CImpIDispatch::GetTypeInfoCount(pctinfo); }
  23. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  24. { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
  25. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
  26. { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
  27. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr);
  28. // IServiceProvider
  29. STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppvObj);
  30. // IShellFolderViewDual2
  31. STDMETHODIMP get_Application(IDispatch **ppid);
  32. STDMETHODIMP get_Parent(IDispatch **ppid);
  33. STDMETHODIMP get_Folder(Folder **ppid);
  34. STDMETHODIMP SelectedItems(FolderItems **ppid);
  35. STDMETHODIMP get_FocusedItem(FolderItem **ppid);
  36. STDMETHODIMP SelectItem(VARIANT *pvfi, int dwFlags);
  37. STDMETHODIMP PopupItemMenu(FolderItem * pfi, VARIANT vx, VARIANT vy, BSTR * pbs);
  38. STDMETHODIMP get_Script(IDispatch **ppid);
  39. STDMETHODIMP get_ViewOptions(long *plSetting);
  40. STDMETHODIMP get_CurrentViewMode(UINT *pViewMode);
  41. STDMETHODIMP put_CurrentViewMode(UINT ViewMode);
  42. STDMETHODIMP SelectItemRelative(int iRelative);
  43. // IShellService
  44. STDMETHODIMP SetOwner(IUnknown* punkOwner);
  45. // CImpIConnectionPoint
  46. STDMETHODIMP EnumConnectionPoints(LPENUMCONNECTIONPOINTS * ppEnum);
  47. // CObjectWithSite overriding
  48. STDMETHODIMP SetSite(IUnknown *punkSite);
  49. private:
  50. HRESULT _IsSafe()
  51. {
  52. return (0 == _dwSafetyOptions) ? S_OK : IsSafePage(_punkSite);
  53. }
  54. ~CShellFolderView(void);
  55. HRESULT _GetFolder();
  56. // CImpIExpDispSupport
  57. virtual CConnectionPoint* _FindCConnectionPointNoRef(BOOL fdisp, REFIID iid);
  58. LONG _cRef;
  59. CFolder *_psdf; // The shell folder we talk to ...
  60. IUnknown *_punkOwner; // back link to defview (owner object of us...)
  61. IShellFolderView *_psfvOwner; // The owners Shell folder view...
  62. HWND _hwnd; // the hwnd for the window...
  63. // Embed our Connection Point object - implmentation in cnctnpt.cpp
  64. CConnectionPoint _cpEvents;
  65. };
  66. // implementation of CLSID_ShellFolderView, class factory is in shell32 (and was in mars, but that project is dead)
  67. STDAPI CShellFolderView_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppvOut)
  68. {
  69. *ppvOut = NULL;
  70. HRESULT hr = E_OUTOFMEMORY;
  71. CShellFolderView* psfv = new CShellFolderView();
  72. if (psfv)
  73. {
  74. hr = psfv->QueryInterface(riid, ppvOut);
  75. psfv->Release();
  76. }
  77. return hr;
  78. }
  79. CShellFolderView::CShellFolderView(void) :
  80. CImpIDispatch(SDSPATCH_TYPELIB, IID_IShellFolderViewDual2), _cRef(1), _psdf(NULL)
  81. {
  82. DllAddRef();
  83. _cpEvents.SetOwner((IUnknown*)SAFECAST(this, IShellFolderViewDual2*), &DIID_DShellFolderViewEvents);
  84. }
  85. CShellFolderView::~CShellFolderView(void)
  86. {
  87. // if we ever grabbed a shell folder for this window release it also
  88. if (_psdf)
  89. {
  90. _psdf->SetSite(NULL);
  91. _psdf->SetOwner(NULL);
  92. _psdf->Release();
  93. }
  94. ASSERT(_punkOwner == NULL);
  95. ASSERT(_psfvOwner == NULL);
  96. ASSERT(_punkSite == NULL);
  97. DllRelease();
  98. }
  99. STDMETHODIMP CShellFolderView::QueryInterface(REFIID riid, void **ppv)
  100. {
  101. static const QITAB qit[] = {
  102. QITABENT(CShellFolderView, IShellFolderViewDual),
  103. QITABENT(CShellFolderView, IShellFolderViewDual2),
  104. QITABENTMULTI(CShellFolderView, IDispatch, IShellFolderViewDual),
  105. QITABENTMULTI(CShellFolderView, IDispatch, IShellFolderViewDual2),
  106. QITABENT(CShellFolderView, IShellService),
  107. QITABENT(CShellFolderView, IConnectionPointContainer),
  108. QITABENT(CShellFolderView, IExpDispSupport),
  109. QITABENT(CShellFolderView, IObjectSafety),
  110. QITABENT(CShellFolderView, IObjectWithSite),
  111. QITABENT(CShellFolderView, IServiceProvider),
  112. { 0 },
  113. };
  114. return QISearch(this, qit, riid, ppv);
  115. }
  116. STDMETHODIMP_(ULONG) CShellFolderView::AddRef(void)
  117. {
  118. return InterlockedIncrement(&_cRef);
  119. }
  120. STDMETHODIMP_(ULONG) CShellFolderView::Release(void)
  121. {
  122. ASSERT( 0 != _cRef );
  123. ULONG cRef = InterlockedDecrement(&_cRef);
  124. if ( 0 == cRef )
  125. {
  126. delete this;
  127. }
  128. return cRef;
  129. }
  130. //The ShellWindow implementation
  131. // let folder we have handle this. Probably won't work for webviews as this object
  132. // is not secure...
  133. STDMETHODIMP CShellFolderView::get_Application(IDispatch **ppid)
  134. {
  135. if (S_OK != _IsSafe())
  136. return E_ACCESSDENIED;
  137. HRESULT hres = _GetFolder();
  138. if (SUCCEEDED(hres))
  139. hres = _psdf->get_Application(ppid);
  140. return hres;
  141. }
  142. STDMETHODIMP CShellFolderView::get_Parent(IDispatch **ppid)
  143. {
  144. *ppid = NULL;
  145. return E_FAIL;
  146. }
  147. HRESULT CShellFolderView::_GetFolder()
  148. {
  149. if (_psdf)
  150. return S_OK;
  151. HRESULT hr;
  152. LPITEMIDLIST pidl = NULL;
  153. IShellFolder *psf = NULL;
  154. if (_psfvOwner)
  155. {
  156. IFolderView *pfv;
  157. if (SUCCEEDED(_psfvOwner->QueryInterface(IID_PPV_ARG(IFolderView, &pfv))))
  158. {
  159. if (SUCCEEDED(pfv->GetFolder(IID_PPV_ARG(IShellFolder, &psf))))
  160. {
  161. if (SHGetIDListFromUnk(psf, &pidl) != S_OK)
  162. {
  163. psf->Release();
  164. psf = NULL;
  165. }
  166. }
  167. pfv->Release();
  168. }
  169. if (!pidl)
  170. {
  171. LPCITEMIDLIST pidlT;
  172. // dsheldon - the -42 is a hack that says "give me the folder pidl"
  173. hr = GetObjectSafely(_psfvOwner, &pidlT, (UINT)-42);
  174. if (SUCCEEDED(hr))
  175. {
  176. pidl = ILClone(pidlT);
  177. }
  178. }
  179. }
  180. if (pidl)
  181. {
  182. hr = CFolder_Create2(_hwnd, pidl, psf, &_psdf);
  183. if (SUCCEEDED(hr))
  184. {
  185. _psdf->SetSite(_punkSite);
  186. _psdf->SetOwner(_punkOwner);
  187. if (_dwSafetyOptions)
  188. hr = MakeSafeForScripting((IUnknown**)&_psdf);
  189. }
  190. if (psf)
  191. psf->Release();
  192. ILFree(pidl);
  193. }
  194. else
  195. hr = E_FAIL;
  196. return hr;
  197. }
  198. STDMETHODIMP CShellFolderView::SetSite(IUnknown *punkSite)
  199. {
  200. if (_psdf)
  201. _psdf->SetSite(punkSite);
  202. return CObjectWithSite::SetSite(punkSite);
  203. }
  204. STDMETHODIMP CShellFolderView::get_Folder(Folder **ppid)
  205. {
  206. if (S_OK != _IsSafe())
  207. return E_ACCESSDENIED;
  208. *ppid = NULL;
  209. HRESULT hr = _GetFolder();
  210. if (SUCCEEDED(hr))
  211. hr = _psdf->QueryInterface(IID_PPV_ARG(Folder, ppid));
  212. return hr;
  213. }
  214. STDMETHODIMP CShellFolderView::SelectedItems(FolderItems **ppid)
  215. {
  216. if (S_OK != _IsSafe())
  217. return E_ACCESSDENIED;
  218. HRESULT hr = _GetFolder();
  219. if (SUCCEEDED(hr))
  220. {
  221. hr = CFolderItems_Create(_psdf, TRUE, ppid);
  222. if (SUCCEEDED(hr))
  223. {
  224. IUnknown_SetSite(*ppid, _punkSite);
  225. if (_dwSafetyOptions)
  226. {
  227. hr = MakeSafeForScripting((IUnknown**)ppid);
  228. }
  229. }
  230. }
  231. return hr;
  232. }
  233. // NOTE: this returns an alias pointer, it is not allocated
  234. HRESULT GetObjectSafely(IShellFolderView *psfv, LPCITEMIDLIST *ppidl, UINT iType)
  235. {
  236. // cast needed because GetObject() returns an alias!
  237. HRESULT hr = psfv->GetObject((LPITEMIDLIST *)ppidl, iType);
  238. if (SUCCEEDED(hr))
  239. {
  240. // On the off chance this is coppied across process boundries...
  241. __try
  242. {
  243. // force a full deref this PIDL to generate a fault if cross process
  244. if (ILGetSize(*ppidl) > 0)
  245. hr = S_OK;
  246. // Don't free it as it was not cloned...
  247. }
  248. __except(SetErrorMode(SEM_NOGPFAULTERRORBOX), UnhandledExceptionFilter(GetExceptionInformation()))
  249. {
  250. *ppidl = NULL;
  251. hr = E_FAIL;
  252. }
  253. }
  254. return hr;
  255. }
  256. STDMETHODIMP CShellFolderView::get_FocusedItem(FolderItem **ppid)
  257. {
  258. if (S_OK != _IsSafe())
  259. return E_ACCESSDENIED;
  260. HRESULT hr = _GetFolder();
  261. if (SUCCEEDED(hr))
  262. {
  263. *ppid = NULL;
  264. hr = S_FALSE;
  265. if (_psfvOwner)
  266. {
  267. // Warning:
  268. // It is common for the following function to fail (which means no item has the focus).
  269. // So, do not save the return code from GetObjectSafely() into "hr" that will ruin the
  270. // S_FALSE value already stored there and result in script errors. (Bug #301306)
  271. //
  272. LPCITEMIDLIST pidl;
  273. // dsheldon - the -2 is a hack that says "give me the selected pidl"
  274. if (SUCCEEDED(GetObjectSafely(_psfvOwner, &pidl, (UINT)-2)))
  275. {
  276. hr = CFolderItem_Create(_psdf, pidl, ppid);
  277. if (_dwSafetyOptions && SUCCEEDED(hr))
  278. hr = MakeSafeForScripting((IUnknown**)ppid);
  279. }
  280. }
  281. else
  282. hr = E_FAIL;
  283. }
  284. return hr;
  285. }
  286. STDMETHODIMP CShellFolderView::get_CurrentViewMode(UINT *pViewMode)
  287. {
  288. if (S_OK != _IsSafe())
  289. return E_ACCESSDENIED;
  290. HRESULT hr = S_FALSE;
  291. IFolderView *pfv;
  292. if (_punkOwner && SUCCEEDED(_punkOwner->QueryInterface(IID_PPV_ARG(IFolderView, &pfv))))
  293. {
  294. hr = pfv->GetCurrentViewMode(pViewMode);
  295. pfv->Release();
  296. }
  297. return hr;
  298. }
  299. STDMETHODIMP CShellFolderView::put_CurrentViewMode(UINT ViewMode)
  300. {
  301. if (S_OK != _IsSafe())
  302. return E_ACCESSDENIED;
  303. HRESULT hr = S_FALSE;
  304. IFolderView *pfv;
  305. if (_punkOwner && SUCCEEDED(_punkOwner->QueryInterface(IID_PPV_ARG(IFolderView, &pfv))))
  306. {
  307. hr = pfv->SetCurrentViewMode(ViewMode);
  308. pfv->Release();
  309. }
  310. return hr;
  311. }
  312. STDMETHODIMP CShellFolderView::SelectItemRelative(int iRelative)
  313. {
  314. if (S_OK != _IsSafe())
  315. return E_ACCESSDENIED;
  316. HRESULT hr = S_FALSE;
  317. IFolderView *pfv;
  318. if (_punkOwner && SUCCEEDED(_punkOwner->QueryInterface(IID_PPV_ARG(IFolderView, &pfv))))
  319. {
  320. int iCurrent, cItems;
  321. if (SUCCEEDED(pfv->ItemCount(SVGIO_ALLVIEW, &cItems)) && (cItems > 1) &&
  322. SUCCEEDED(pfv->GetSelectionMarkedItem(&iCurrent)))
  323. {
  324. int iToSelect = iCurrent + iRelative;
  325. if (iToSelect < 0)
  326. iToSelect = 0;
  327. else if (iToSelect > cItems - 1)
  328. iToSelect = cItems - 1;
  329. hr = pfv->SelectItem(iToSelect, SVSI_SELECTIONMARK | SVSI_SELECT | SVSI_ENSUREVISIBLE | SVSI_DESELECTOTHERS);
  330. }
  331. pfv->Release();
  332. }
  333. return hr;
  334. }
  335. // pvfi should be a "FolderItem" IDispatch
  336. STDMETHODIMP CShellFolderView::SelectItem(VARIANT *pvfi, int dwFlags)
  337. {
  338. if (S_OK != _IsSafe())
  339. return E_ACCESSDENIED;
  340. HRESULT hr = E_FAIL;
  341. LPITEMIDLIST pidl = VariantToIDList(pvfi);
  342. // if pvfi is NULL that means all items in the folder...
  343. if (pidl || (pvfi && pvfi->vt == VT_NULL))
  344. {
  345. IShellView *psv; // use this to select the item...
  346. if (_punkOwner && SUCCEEDED(_punkOwner->QueryInterface(IID_PPV_ARG(IShellView, &psv))))
  347. {
  348. // ILFindLastID checks for NULL...
  349. hr = psv->SelectItem(ILFindLastID(pidl), dwFlags);
  350. psv->Release();
  351. }
  352. ILFree(pidl);
  353. }
  354. return hr;
  355. }
  356. STDMETHODIMP CShellFolderView::PopupItemMenu(FolderItem *pfi, VARIANT vx, VARIANT vy, BSTR * pbs)
  357. {
  358. return E_NOTIMPL;
  359. }
  360. STDMETHODIMP CShellFolderView::get_Script(IDispatch **ppid)
  361. {
  362. *ppid = NULL; // Say that we got nothing...
  363. if (!_punkOwner)
  364. return S_FALSE;
  365. IShellView *psv;
  366. HRESULT hres = _punkOwner->QueryInterface(IID_PPV_ARG(IShellView, &psv));
  367. if (SUCCEEDED(hres))
  368. {
  369. // lets see if there is a IHTMLDocument that is below us now...
  370. IHTMLDocument *phtmld;
  371. hres = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARG(IHTMLDocument, &phtmld));
  372. if (SUCCEEDED(hres))
  373. {
  374. if (_dwSafetyOptions)
  375. hres = MakeSafeForScripting((IUnknown **)&phtmld);
  376. if (SUCCEEDED(hres))
  377. {
  378. hres = phtmld->get_Script(ppid);
  379. }
  380. phtmld->Release();
  381. }
  382. psv->Release();
  383. }
  384. return hres;
  385. }
  386. // Helper function that can be used to get the current view options...
  387. // (ripped out of dvoc.cpp)
  388. DWORD GetViewOptionsForDispatch()
  389. {
  390. SHELLSTATE ss = {0};
  391. DWORD dwSetting = 0;
  392. // Get the view options to return...
  393. SHGetSetSettings(&ss,
  394. SSF_SHOWALLOBJECTS|SSF_SHOWEXTENSIONS|SSF_SHOWCOMPCOLOR|
  395. SSF_SHOWSYSFILES|SSF_DOUBLECLICKINWEBVIEW|SSF_DESKTOPHTML|SSF_WIN95CLASSIC,
  396. FALSE);
  397. // Aarg: mnuch the Bool:1 fields into a dword...
  398. if (ss.fShowAllObjects) dwSetting |= SFVVO_SHOWALLOBJECTS;
  399. if (ss.fShowExtensions) dwSetting |= SFVVO_SHOWEXTENSIONS;
  400. if (ss.fShowCompColor) dwSetting |= SFVVO_SHOWCOMPCOLOR;
  401. if (ss.fShowSysFiles) dwSetting |= SFVVO_SHOWSYSFILES;
  402. if (ss.fDoubleClickInWebView) dwSetting |= SFVVO_DOUBLECLICKINWEBVIEW;
  403. if (ss.fDesktopHTML) dwSetting |= SFVVO_DESKTOPHTML;
  404. if (ss.fWin95Classic) dwSetting |= SFVVO_WIN95CLASSIC;
  405. return dwSetting;
  406. }
  407. STDMETHODIMP CShellFolderView::get_ViewOptions(long *plSetting)
  408. {
  409. if (S_OK != _IsSafe())
  410. return E_ACCESSDENIED;
  411. *plSetting = (LONG)GetViewOptionsForDispatch();
  412. return S_OK;
  413. }
  414. STDMETHODIMP CShellFolderView::SetOwner(IUnknown* punkOwner)
  415. {
  416. if (_psdf)
  417. _psdf->SetOwner(punkOwner);
  418. IUnknown_Set((IUnknown **)&_psfvOwner, NULL); // free cached interface
  419. IUnknown_Set(&_punkOwner, punkOwner); // hold this guy
  420. if (_punkOwner)
  421. {
  422. _punkOwner->QueryInterface(IID_PPV_ARG(IShellFolderView, &_psfvOwner));
  423. if (!_hwnd)
  424. {
  425. IShellView *psv;
  426. // this is gross, until we can merge the two models, create one of our
  427. // Window objects.
  428. if (SUCCEEDED(_punkOwner->QueryInterface(IID_PPV_ARG(IShellView, &psv))))
  429. {
  430. HWND hwndFldr;
  431. psv->GetWindow(&hwndFldr);
  432. // Really gross, but assume parent HWND is the HWND we are after...
  433. _hwnd = GetParent(hwndFldr);
  434. psv->Release();
  435. }
  436. }
  437. }
  438. return S_OK;
  439. }
  440. STDMETHODIMP CShellFolderView::EnumConnectionPoints(IEnumConnectionPoints **ppEnum)
  441. {
  442. return CreateInstance_IEnumConnectionPoints(ppEnum, 1, _cpEvents.CastToIConnectionPoint());
  443. }
  444. CConnectionPoint* CShellFolderView::_FindCConnectionPointNoRef(BOOL fdisp, REFIID iid)
  445. {
  446. if (IsEqualIID(iid, DIID_DShellFolderViewEvents) || (fdisp && IsEqualIID(iid, IID_IDispatch)))
  447. return &_cpEvents;
  448. return NULL;
  449. }
  450. HRESULT CShellFolderView::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
  451. {
  452. HRESULT hr;
  453. if (dispidMember == DISPID_READYSTATE)
  454. return DISP_E_MEMBERNOTFOUND; // perf: what typeinfo would return.
  455. if (dispidMember == DISPID_WINDOWOBJECT)
  456. {
  457. IDispatch *pdisp;
  458. if (SUCCEEDED(get_Script(&pdisp)))
  459. {
  460. hr = pdisp->Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  461. pdisp->Release();
  462. }
  463. else
  464. {
  465. hr = DISP_E_MEMBERNOTFOUND;
  466. }
  467. }
  468. else
  469. hr = CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  470. return hr;
  471. }
  472. HRESULT CShellFolderView::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  473. {
  474. HRESULT hr = IUnknown_QueryService(_punkOwner, guidService, riid, ppv);
  475. if (FAILED(hr))
  476. hr = IUnknown_QueryService(_punkSite, guidService, riid, ppv);
  477. return hr;
  478. }