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.

1147 lines
29 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. // BUGBUG: from shell32\prop.cpp
  4. STDAPI_(BOOL) ParseSCIDString(LPCTSTR pszString, SHCOLUMNID *pscid, UINT *pidRes);
  5. #define TF_SHELLAUTO TF_CUSTOM1
  6. #define DEFINE_FLOAT_STUFF // Do this because DATE is being used below
  7. class CFolderItemVerbs;
  8. class CEnumFolderItemVerbs;
  9. class CFolderItemVerb;
  10. class CFolderItemVerbs : public FolderItemVerbs,
  11. public CObjectSafety,
  12. protected CImpIDispatch,
  13. protected CObjectWithSite
  14. {
  15. friend class CEnumFolderItemVerbs;
  16. friend class CFolderItemVerb;
  17. public:
  18. CFolderItemVerbs(IContextMenu *pcm);
  19. BOOL Init(void);
  20. // IUnknown
  21. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  22. STDMETHODIMP_(ULONG) AddRef(void);
  23. STDMETHODIMP_(ULONG) Release(void);
  24. // IDispatch
  25. STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
  26. { return CImpIDispatch::GetTypeInfoCount(pctinfo); }
  27. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  28. { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
  29. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
  30. { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
  31. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
  32. { return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }
  33. // FolderItemVerbs
  34. STDMETHODIMP get_Application(IDispatch **ppid);
  35. STDMETHODIMP get_Parent(IDispatch **ppid);
  36. STDMETHODIMP get_Count(long *plCount);
  37. STDMETHODIMP Item(VARIANT, FolderItemVerb**);
  38. STDMETHODIMP _NewEnum(IUnknown **);
  39. private:
  40. ~CFolderItemVerbs(void);
  41. HRESULT _SecurityCheck();
  42. LONG _cRef;
  43. HMENU _hmenu;
  44. IContextMenu *_pcm;
  45. };
  46. class CEnumFolderItemVerbs : public IEnumVARIANT,
  47. public CObjectSafety
  48. {
  49. public:
  50. CEnumFolderItemVerbs(CFolderItemVerbs *psdfiv);
  51. BOOL Init();
  52. // IUnknown
  53. STDMETHODIMP QueryInterface(REFIID, void **);
  54. STDMETHODIMP_(ULONG) AddRef(void);
  55. STDMETHODIMP_(ULONG) Release(void);
  56. // IEnumFORMATETC
  57. STDMETHODIMP Next(ULONG, VARIANT *, ULONG *);
  58. STDMETHODIMP Skip(ULONG);
  59. STDMETHODIMP Reset(void);
  60. STDMETHODIMP Clone(IEnumVARIANT **);
  61. private:
  62. ~CEnumFolderItemVerbs();
  63. LONG _cRef;
  64. int _iCur;
  65. CFolderItemVerbs *_psdfiv;
  66. };
  67. HRESULT CFolderItemVerb_Create(CFolderItemVerbs *psdfivs, UINT id, FolderItemVerb **pfiv);
  68. class CFolderItemVerb :
  69. public FolderItemVerb,
  70. public CObjectSafety,
  71. protected CImpIDispatch
  72. {
  73. friend class CFolderItemVerbs;
  74. public:
  75. CFolderItemVerb(CFolderItemVerbs *psdfivs, UINT id);
  76. // IUnknown
  77. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  78. STDMETHODIMP_(ULONG) AddRef(void);
  79. STDMETHODIMP_(ULONG) Release(void);
  80. // IDispatch
  81. STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
  82. { return CImpIDispatch::GetTypeInfoCount(pctinfo); }
  83. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  84. { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
  85. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
  86. { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
  87. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
  88. { return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }
  89. // FolderItemVerbs
  90. STDMETHODIMP get_Application(IDispatch **ppid);
  91. STDMETHODIMP get_Parent(IDispatch **ppid);
  92. STDMETHODIMP get_Name(BSTR *pbs);
  93. STDMETHODIMP DoIt();
  94. private:
  95. ~CFolderItemVerb(void);
  96. LONG _cRef;
  97. CFolderItemVerbs *_psdfivs;
  98. UINT _id;
  99. };
  100. // in:
  101. // psdf folder that contains pidl
  102. // pidl pidl retlative to psdf (the item in this folder)
  103. HRESULT CFolderItem_Create(CFolder *psdf, LPCITEMIDLIST pidl, FolderItem **ppid)
  104. {
  105. *ppid = NULL;
  106. HRESULT hr = E_OUTOFMEMORY;
  107. CFolderItem* psdfi = new CFolderItem();
  108. if (psdfi)
  109. {
  110. hr = psdfi->Init(psdf, pidl);
  111. if (SUCCEEDED(hr))
  112. hr = psdfi->QueryInterface(IID_PPV_ARG(FolderItem, ppid));
  113. psdfi->Release();
  114. }
  115. return hr;
  116. }
  117. STDAPI CFolderItem_CreateInstance(IUnknown *punk, REFIID riid, void **ppv)
  118. {
  119. HRESULT hr = E_OUTOFMEMORY;
  120. *ppv = NULL;
  121. CFolderItem *pfi = new CFolderItem();
  122. if (pfi)
  123. {
  124. hr = pfi->QueryInterface(riid, ppv);
  125. pfi->Release();
  126. }
  127. return hr;
  128. }
  129. // in:
  130. // pidl fully qualified pidl
  131. // hwnd hacks
  132. HRESULT CFolderItem_CreateFromIDList(HWND hwnd, LPCITEMIDLIST pidl, FolderItem **ppfi)
  133. {
  134. LPITEMIDLIST pidlParent;
  135. HRESULT hr = SHILClone(pidl, &pidlParent);
  136. if (SUCCEEDED(hr))
  137. {
  138. ILRemoveLastID(pidlParent);
  139. CFolder *psdf;
  140. hr = CFolder_Create2(hwnd, pidlParent, NULL, &psdf);
  141. if (SUCCEEDED(hr))
  142. {
  143. hr = CFolderItem_Create(psdf, ILFindLastID(pidl), ppfi);
  144. psdf->Release();
  145. }
  146. ILFree(pidlParent);
  147. }
  148. return hr;
  149. }
  150. CFolderItem::CFolderItem() :
  151. _cRef(1), _psdf(NULL), _pidl(NULL),
  152. CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItem2)
  153. {
  154. DllAddRef();
  155. }
  156. CFolderItem::~CFolderItem(void)
  157. {
  158. if (_pidl)
  159. ILFree(_pidl);
  160. if (_psdf)
  161. _psdf->Release();
  162. DllRelease();
  163. }
  164. HRESULT GetItemFolder(CFolder *psdfRoot, LPCITEMIDLIST pidl, CFolder **ppsdf)
  165. {
  166. HRESULT hr = S_OK;
  167. ASSERT(psdfRoot);
  168. if (ILFindLastID(pidl) != pidl)
  169. {
  170. LPITEMIDLIST pidlIn = ILClone(pidl);
  171. hr = E_OUTOFMEMORY;
  172. if (pidlIn && ILRemoveLastID(pidlIn))
  173. {
  174. LPITEMIDLIST pidlParent;
  175. LPITEMIDLIST pidlFolder = NULL;
  176. hr = psdfRoot->GetCurFolder(&pidlFolder);
  177. if (SUCCEEDED(hr))
  178. {
  179. pidlParent = ILCombine(pidlFolder, pidlIn);
  180. if (pidlParent)
  181. {
  182. hr = CFolder_Create2(NULL, pidlParent, NULL, ppsdf);
  183. ILFree(pidlParent);
  184. }
  185. ILFree(pidlFolder);
  186. }
  187. }
  188. ILFree(pidlIn);// ilfree does null check
  189. }
  190. else
  191. {
  192. *ppsdf = psdfRoot;
  193. psdfRoot->AddRef();
  194. }
  195. return hr;
  196. }
  197. HRESULT CFolderItem::Init(CFolder *psdf, LPCITEMIDLIST pidl)
  198. {
  199. HRESULT hr = GetItemFolder(psdf, pidl, &_psdf);
  200. if (SUCCEEDED(hr))
  201. {
  202. hr = SHILClone(ILFindLastID(pidl), &_pidl);
  203. }
  204. return hr;
  205. }
  206. STDMETHODIMP CFolderItem::QueryInterface(REFIID riid, void **ppv)
  207. {
  208. static const QITAB qit[] = {
  209. QITABENT(CFolderItem, FolderItem2),
  210. QITABENTMULTI(CFolderItem, FolderItem, FolderItem2),
  211. QITABENTMULTI(CFolderItem, IDispatch, FolderItem2),
  212. QITABENTMULTI(CFolderItem, IPersist, IPersistFolder2),
  213. QITABENTMULTI(CFolderItem, IPersistFolder, IPersistFolder2),
  214. QITABENT(CFolderItem, IPersistFolder2),
  215. QITABENT(CFolderItem, IObjectSafety),
  216. QITABENT(CFolderItem, IParentAndItem),
  217. { 0 },
  218. };
  219. HRESULT hr = QISearch(this, qit, riid, ppv);
  220. if (FAILED(hr) && IsEqualGUID(CLSID_ShellFolderItem, riid))
  221. {
  222. *ppv = (CFolderItem *)this; // unrefed
  223. hr = S_OK;
  224. }
  225. return hr;
  226. }
  227. STDMETHODIMP_(ULONG) CFolderItem::AddRef(void)
  228. {
  229. return InterlockedIncrement(&_cRef);
  230. }
  231. STDMETHODIMP_(ULONG) CFolderItem::Release(void)
  232. {
  233. if (InterlockedDecrement(&_cRef))
  234. return _cRef;
  235. delete this;
  236. return 0;
  237. }
  238. //The FolderItem implementation
  239. STDMETHODIMP CFolderItem::get_Application(IDispatch **ppid)
  240. {
  241. // Let the folder object handle security and reference counting of site, etc
  242. return _psdf->get_Application(ppid);
  243. }
  244. STDMETHODIMP CFolderItem::get_Parent(IDispatch **ppid)
  245. {
  246. // Assume that the Folder object is the parent of this object...
  247. HRESULT hr = _psdf->QueryInterface(IID_PPV_ARG(IDispatch, ppid));
  248. if (SUCCEEDED(hr) && _dwSafetyOptions)
  249. hr = MakeSafeForScripting((IUnknown**)ppid);
  250. return hr;
  251. }
  252. HRESULT CFolderItem::_ItemName(UINT dwFlags, BSTR *pbs)
  253. {
  254. HRESULT hr;
  255. STRRET strret;
  256. if (SUCCEEDED(_psdf->_psf->GetDisplayNameOf(_pidl, dwFlags, &strret)))
  257. {
  258. hr = StrRetToBSTR(&strret, _pidl, pbs);
  259. }
  260. else
  261. {
  262. *pbs = SysAllocString(L"");
  263. hr = (*pbs) ? S_FALSE : E_OUTOFMEMORY;
  264. }
  265. return hr;
  266. }
  267. STDMETHODIMP CFolderItem::get_Name(BSTR *pbs)
  268. {
  269. *pbs = NULL;
  270. HRESULT hr = _SecurityCheck();
  271. if (SUCCEEDED(hr))
  272. {
  273. hr = _ItemName(SHGDN_INFOLDER, pbs);
  274. }
  275. return hr;
  276. }
  277. STDMETHODIMP CFolderItem::put_Name(BSTR bs)
  278. {
  279. HRESULT hr = _SecurityCheck();
  280. if (SUCCEEDED(hr))
  281. {
  282. LPITEMIDLIST pidlOut;
  283. hr = _psdf->_psf->SetNameOf(_psdf->_hwnd, _pidl, bs, SHGDN_INFOLDER, &pidlOut);
  284. if (SUCCEEDED(hr))
  285. {
  286. ILFree(_pidl);
  287. _pidl = pidlOut;
  288. }
  289. }
  290. return hr;
  291. }
  292. // BUGBUG: this should validate that the path is a file system
  293. // object (SFGAO_FILESYSTEM)
  294. STDMETHODIMP CFolderItem::get_Path(BSTR *pbs)
  295. {
  296. *pbs = NULL;
  297. HRESULT hr = _SecurityCheck();
  298. if (SUCCEEDED(hr))
  299. {
  300. hr = _ItemName(SHGDN_FORPARSING, pbs);
  301. }
  302. return hr;
  303. }
  304. STDMETHODIMP CFolderItem::get_GetLink(IDispatch **ppid)
  305. {
  306. *ppid = NULL;
  307. HRESULT hr = _SecurityCheck();
  308. if (SUCCEEDED(hr))
  309. {
  310. hr = CShortcut_CreateIDispatch(_psdf->_hwnd, _psdf->_psf, _pidl, ppid);
  311. if (SUCCEEDED(hr) && _dwSafetyOptions)
  312. {
  313. hr = MakeSafeForScripting((IUnknown**)ppid);
  314. }
  315. }
  316. return hr;
  317. }
  318. // BUGBUG:: this should return Folder **...
  319. STDMETHODIMP CFolderItem::get_GetFolder(IDispatch **ppid /* Folder **ppf */)
  320. {
  321. *ppid = NULL;
  322. // If in Safe mode we fail this one...
  323. HRESULT hr = _SecurityCheck();
  324. if (SUCCEEDED(hr))
  325. {
  326. LPITEMIDLIST pidl;
  327. hr = SHILCombine(_psdf->_pidl, _pidl, &pidl);
  328. if (SUCCEEDED(hr))
  329. {
  330. hr = CFolder_Create(NULL, pidl, NULL, IID_PPV_ARG(IDispatch, ppid));
  331. if (SUCCEEDED(hr))
  332. {
  333. if (_dwSafetyOptions)
  334. {
  335. // note, this is created without a site so script safety checks will fail
  336. hr = MakeSafeForScripting((IUnknown**)ppid);
  337. }
  338. }
  339. ILFree(pidl);
  340. }
  341. }
  342. return hr;
  343. }
  344. HRESULT CFolderItem::_CheckAttribute(ULONG ulAttrIn, VARIANT_BOOL * pb)
  345. {
  346. HRESULT hr = _SecurityCheck();
  347. if (SUCCEEDED(hr))
  348. {
  349. ULONG ulAttr = ulAttrIn;
  350. hr = _psdf->_psf->GetAttributesOf(1, (LPCITEMIDLIST*)&_pidl, &ulAttr);
  351. *pb = (SUCCEEDED(hr) && (ulAttr & ulAttrIn)) ? VARIANT_TRUE : VARIANT_FALSE;
  352. }
  353. return hr;
  354. }
  355. HRESULT CFolderItem::_GetUIObjectOf(REFIID riid, void **ppv)
  356. {
  357. return _psdf->_psf->GetUIObjectOf(_psdf->_hwnd, 1, (LPCITEMIDLIST*)&_pidl, riid, NULL, ppv);
  358. }
  359. HRESULT CFolderItem::_SecurityCheck()
  360. {
  361. if (!_dwSafetyOptions)
  362. return S_OK;
  363. return _psdf->_SecurityCheck();
  364. }
  365. // allow friend classes to get the IDList for a CFolderItem automation object
  366. LPCITEMIDLIST CFolderItem::_GetIDListFromVariant(const VARIANT *pv)
  367. {
  368. LPCITEMIDLIST pidl = NULL;
  369. if (pv)
  370. {
  371. VARIANT v;
  372. if (pv->vt == (VT_BYREF | VT_VARIANT) && pv->pvarVal)
  373. v = *pv->pvarVal;
  374. else
  375. v = *pv;
  376. switch (v.vt)
  377. {
  378. case VT_DISPATCH | VT_BYREF:
  379. if (v.ppdispVal == NULL)
  380. break;
  381. v.pdispVal = *v.ppdispVal;
  382. // fall through...
  383. case VT_DISPATCH:
  384. CFolderItem *pfi;
  385. if (v.pdispVal && SUCCEEDED(v.pdispVal->QueryInterface(CLSID_ShellFolderItem, (void **)&pfi)))
  386. {
  387. pidl = pfi->_pidl; // alias
  388. }
  389. break;
  390. }
  391. }
  392. return pidl;
  393. }
  394. STDMETHODIMP CFolderItem::get_IsLink(VARIANT_BOOL * pb)
  395. {
  396. return _CheckAttribute(SFGAO_LINK, pb);
  397. }
  398. STDMETHODIMP CFolderItem::get_IsFolder(VARIANT_BOOL * pb)
  399. {
  400. return _CheckAttribute(SFGAO_FOLDER, pb);
  401. }
  402. STDMETHODIMP CFolderItem::get_IsFileSystem(VARIANT_BOOL * pb)
  403. {
  404. return _CheckAttribute(SFGAO_FILESYSTEM, pb);
  405. }
  406. STDMETHODIMP CFolderItem::get_IsBrowsable(VARIANT_BOOL * pb)
  407. {
  408. return _CheckAttribute(SFGAO_BROWSABLE, pb);
  409. }
  410. STDMETHODIMP CFolderItem::get_ModifyDate(DATE *pdt)
  411. {
  412. HRESULT hr = _SecurityCheck();
  413. if (SUCCEEDED(hr))
  414. {
  415. WIN32_FIND_DATA finddata;
  416. if (SUCCEEDED(SHGetDataFromIDList(_psdf->_psf, _pidl, SHGDFIL_FINDDATA, &finddata, sizeof(finddata))))
  417. {
  418. WORD wDosDate, wDosTime;
  419. FILETIME filetime;
  420. FileTimeToLocalFileTime(&finddata.ftLastWriteTime, &filetime);
  421. FileTimeToDosDateTime(&filetime, &wDosDate, &wDosTime);
  422. DosDateTimeToVariantTime(wDosDate, wDosTime, pdt);
  423. }
  424. hr = S_OK;
  425. }
  426. return hr;
  427. }
  428. STDMETHODIMP CFolderItem::put_ModifyDate(DATE dt)
  429. {
  430. HRESULT hr = _SecurityCheck();
  431. if (SUCCEEDED(hr))
  432. {
  433. hr = S_FALSE;
  434. SYSTEMTIME st;
  435. FILETIME ftLocal, ft;
  436. BSTR bstrPath;
  437. if (SUCCEEDED(VariantTimeToSystemTime(dt, &st)) && SystemTimeToFileTime(&st, &ftLocal)
  438. && LocalFileTimeToFileTime(&ftLocal, &ft) && SUCCEEDED(get_Path(&bstrPath)))
  439. {
  440. TCHAR szPath[MAX_PATH];
  441. SHUnicodeToTChar(bstrPath, szPath, ARRAYSIZE(szPath));
  442. SysFreeString(bstrPath);
  443. HANDLE hFile = CreateFile(szPath, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ,
  444. NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OPEN_NO_RECALL, NULL);
  445. if (hFile != INVALID_HANDLE_VALUE)
  446. {
  447. if (SetFileTime(hFile, NULL, NULL, &ft))
  448. {
  449. hr = S_OK;
  450. }
  451. CloseHandle(hFile);
  452. }
  453. }
  454. }
  455. return hr;
  456. }
  457. // BUGBUG:: Should see about getting larger numbers through
  458. STDMETHODIMP CFolderItem::get_Size(LONG *pul)
  459. {
  460. HRESULT hr =_SecurityCheck();
  461. if (SUCCEEDED(hr))
  462. {
  463. WIN32_FIND_DATA finddata;
  464. if (SUCCEEDED(SHGetDataFromIDList(_psdf->_psf, _pidl, SHGDFIL_FINDDATA, &finddata, sizeof(finddata))))
  465. {
  466. *pul = (LONG)finddata.nFileSizeLow;
  467. }
  468. else
  469. {
  470. *pul = 0L;
  471. }
  472. hr = S_OK; // Scripts don't like error return values
  473. }
  474. return hr;
  475. }
  476. STDMETHODIMP CFolderItem::get_Type(BSTR *pbs)
  477. {
  478. *pbs = NULL;
  479. HRESULT hr = _SecurityCheck();
  480. if (SUCCEEDED(hr))
  481. {
  482. VARIANT var;
  483. var.vt = VT_EMPTY;
  484. if (SUCCEEDED(ExtendedProperty(L"Type", &var)) && (var.vt == VT_BSTR))
  485. {
  486. *pbs = SysAllocString(var.bstrVal);
  487. }
  488. else
  489. {
  490. *pbs = SysAllocString(L"");
  491. }
  492. VariantClear(&var);
  493. hr = *pbs ? S_OK : E_OUTOFMEMORY;
  494. }
  495. return hr;
  496. }
  497. STDMETHODIMP CFolderItem::ExtendedProperty(BSTR bstrPropName, VARIANT *pvRet)
  498. {
  499. HRESULT hr = _SecurityCheck();
  500. if (SUCCEEDED(hr))
  501. {
  502. hr = E_FAIL;
  503. VariantInit(pvRet);
  504. // currently, MCNL is 80, guidstr is 39, and 6 is the width of an int
  505. if (StrCmpIW(bstrPropName, L"infotip") == 0)
  506. {
  507. // They want the info tip for the item.
  508. if (_pidl && _psdf)
  509. {
  510. TCHAR szInfo[INFOTIPSIZE];
  511. GetInfoTipHelp(_psdf->_psf, _pidl, szInfo, ARRAYSIZE(szInfo));
  512. hr = InitVariantFromStr(pvRet, szInfo);
  513. }
  514. }
  515. else if (_psdf->_psf2)
  516. {
  517. SHCOLUMNID scid;
  518. TCHAR szTemp[128];
  519. SHUnicodeToTChar(bstrPropName, szTemp, ARRAYSIZE(szTemp));
  520. if (ParseSCIDString(szTemp, &scid, NULL))
  521. {
  522. // Note that GetDetailsEx expects an absolute pidl
  523. hr = _psdf->_psf2->GetDetailsEx(_pidl, &scid, pvRet);
  524. }
  525. }
  526. hr = FAILED(hr) ? S_FALSE : hr; // Java scripts barf on error values
  527. }
  528. return hr;
  529. }
  530. STDMETHODIMP CFolderItem::Verbs(FolderItemVerbs **ppfic)
  531. {
  532. HRESULT hr = _SecurityCheck();
  533. if (SUCCEEDED(hr))
  534. {
  535. hr = S_FALSE;
  536. IContextMenu *pcm;
  537. if (SUCCEEDED(_GetUIObjectOf(IID_PPV_ARG(IContextMenu, &pcm))))
  538. {
  539. hr = CFolderItemVerbs_Create(pcm, ppfic);
  540. if (SUCCEEDED(hr) && _dwSafetyOptions)
  541. {
  542. hr = MakeSafeForScripting((IUnknown**)ppfic);
  543. if (SUCCEEDED(hr))
  544. {
  545. // Set the folder's site to FolderItemVerbs
  546. IUnknown_SetSite(*ppfic, _psdf->_punkSite);
  547. }
  548. }
  549. pcm->Release();
  550. }
  551. }
  552. return hr;
  553. }
  554. STDMETHODIMP CFolderItem::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs)
  555. {
  556. // security check handled by _psdf
  557. return _psdf->InvokeVerbHelper(vVerb, vArgs, (LPCITEMIDLIST *)&_pidl, 1, _dwSafetyOptions);
  558. }
  559. STDMETHODIMP CFolderItem::InvokeVerb(VARIANT vVerb)
  560. {
  561. VARIANT vtEmpty = {VT_EMPTY};
  562. return InvokeVerbEx(vVerb, vtEmpty);
  563. }
  564. STDMETHODIMP CFolderItem::GetClassID(CLSID *pClassID)
  565. {
  566. *pClassID = CLSID_ShellFolderItem;
  567. return E_NOTIMPL;
  568. }
  569. // IPersistFolder
  570. // note, this duplicates some of CFolderItem::Init() functionality
  571. STDMETHODIMP CFolderItem::Initialize(LPCITEMIDLIST pidl)
  572. {
  573. LPITEMIDLIST pidlParent;
  574. HRESULT hr = SHILClone(pidl, &pidlParent);
  575. if (SUCCEEDED(hr))
  576. {
  577. ASSERT(_pidl == NULL);
  578. hr = SHILClone(ILFindLastID(pidlParent), &_pidl);
  579. if (SUCCEEDED(hr))
  580. {
  581. // Chop off the filename and get the folder that contains
  582. // this FolderItem.
  583. ILRemoveLastID(pidlParent);
  584. // BUGBUG: we should find some way to get a valid hwnd to
  585. // pass to CFolder_Create2 instead of NULL.
  586. ASSERT(_psdf == NULL);
  587. hr = CFolder_Create2(NULL, pidlParent, NULL, &_psdf);
  588. }
  589. ILFree(pidlParent);
  590. }
  591. return hr;
  592. }
  593. STDMETHODIMP CFolderItem::GetCurFolder(LPITEMIDLIST *ppidl)
  594. {
  595. LPITEMIDLIST pidlFolder;
  596. HRESULT hr = SHGetIDListFromUnk(_psdf->_psf, &pidlFolder);
  597. if (S_OK == hr)
  598. {
  599. hr = SHILCombine(pidlFolder, _pidl, ppidl);
  600. ILFree(pidlFolder);
  601. }
  602. else
  603. hr = E_FAIL;
  604. return hr;
  605. }
  606. // IParentAndItem
  607. STDMETHODIMP CFolderItem::SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidl)
  608. {
  609. return E_NOTIMPL;
  610. }
  611. STDMETHODIMP CFolderItem::GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidl)
  612. {
  613. if (ppidlParent)
  614. {
  615. *ppidlParent = _psdf->_pidl ? ILClone(_psdf->_pidl) : NULL;
  616. }
  617. if (ppsf)
  618. {
  619. *ppsf = NULL;
  620. if (_psdf && _psdf->_psf)
  621. _psdf->_psf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsf));
  622. }
  623. if (ppidl)
  624. *ppidl = ILClone(_pidl);
  625. if ((ppidlParent && !*ppidlParent)
  626. || (ppsf && !*ppsf)
  627. || (ppidl && !*ppidl))
  628. {
  629. // this is failure
  630. // but we dont know what failed
  631. if (ppsf && *ppsf)
  632. (*ppsf)->Release();
  633. if (ppidlParent)
  634. ILFree(*ppidlParent);
  635. if (ppidl)
  636. ILFree(*ppidl);
  637. return E_OUTOFMEMORY;
  638. }
  639. return S_OK;
  640. }
  641. HRESULT CFolderItemVerbs_Create(IContextMenu *pcm, FolderItemVerbs ** ppid)
  642. {
  643. *ppid = NULL;
  644. HRESULT hr = E_OUTOFMEMORY;
  645. CFolderItemVerbs* pfiv = new CFolderItemVerbs(pcm);
  646. if (pfiv)
  647. {
  648. if (pfiv->Init())
  649. hr = pfiv->QueryInterface(IID_PPV_ARG(FolderItemVerbs, ppid));
  650. pfiv->Release();
  651. }
  652. return hr;
  653. }
  654. CFolderItemVerbs::CFolderItemVerbs(IContextMenu *pcm) :
  655. _cRef(1), _hmenu(NULL),
  656. _pcm(pcm), CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItemVerbs)
  657. {
  658. DllAddRef();
  659. _pcm->AddRef();
  660. }
  661. CFolderItemVerbs::~CFolderItemVerbs(void)
  662. {
  663. DllRelease();
  664. if (_pcm)
  665. _pcm->Release();
  666. if (_hmenu)
  667. DestroyMenu(_hmenu);
  668. }
  669. BOOL CFolderItemVerbs::Init()
  670. {
  671. TraceMsg(TF_SHELLAUTO, "CFolderItemVerbs::Init called");
  672. // Start of only doing default verb...
  673. if (_pcm)
  674. {
  675. _hmenu = CreatePopupMenu();
  676. if (FAILED(_pcm->QueryContextMenu(_hmenu, 0, CONTEXTMENU_IDCMD_FIRST, CONTEXTMENU_IDCMD_LAST, CMF_CANRENAME|CMF_NORMAL)))
  677. return FALSE;
  678. }
  679. else
  680. return FALSE;
  681. // Just for the heck of it, remove junk like sepearators from the menu...
  682. for (int i = GetMenuItemCount(_hmenu) - 1; i >= 0; i--)
  683. {
  684. MENUITEMINFO mii;
  685. TCHAR szText[80]; // should be big enough for this
  686. mii.cbSize = sizeof(MENUITEMINFO);
  687. mii.dwTypeData = szText;
  688. mii.fMask = MIIM_TYPE | MIIM_ID;
  689. mii.cch = ARRAYSIZE(szText);
  690. mii.fType = MFT_SEPARATOR; // to avoid ramdom result.
  691. mii.dwItemData = 0;
  692. GetMenuItemInfo(_hmenu, i, TRUE, &mii);
  693. if (mii.fType & MFT_SEPARATOR)
  694. DeleteMenu(_hmenu, i, MF_BYPOSITION);
  695. }
  696. return TRUE;
  697. }
  698. STDMETHODIMP CFolderItemVerbs::QueryInterface(REFIID riid, void **ppv)
  699. {
  700. static const QITAB qit[] = {
  701. QITABENT(CFolderItemVerbs, FolderItemVerbs),
  702. QITABENT(CFolderItemVerbs, IObjectSafety),
  703. QITABENTMULTI(CFolderItemVerbs, IDispatch, FolderItemVerbs),
  704. QITABENT(CFolderItemVerbs, IObjectWithSite),
  705. { 0 },
  706. };
  707. return QISearch(this, qit, riid, ppv);
  708. }
  709. STDMETHODIMP_(ULONG) CFolderItemVerbs::AddRef(void)
  710. {
  711. return InterlockedIncrement(&_cRef);
  712. }
  713. STDMETHODIMP_(ULONG) CFolderItemVerbs::Release(void)
  714. {
  715. if (InterlockedDecrement(&_cRef))
  716. return _cRef;
  717. delete this;
  718. return 0;
  719. }
  720. STDMETHODIMP CFolderItemVerbs::get_Application(IDispatch **ppid)
  721. {
  722. *ppid = NULL;
  723. return E_NOTIMPL;
  724. }
  725. STDMETHODIMP CFolderItemVerbs::get_Parent(IDispatch **ppid)
  726. {
  727. *ppid = NULL;
  728. return E_NOTIMPL;
  729. }
  730. HRESULT CFolderItemVerbs::_SecurityCheck()
  731. {
  732. return (!_dwSafetyOptions || (IsSafePage(_punkSite) == S_OK)) ? S_OK : E_ACCESSDENIED;
  733. }
  734. STDMETHODIMP CFolderItemVerbs::get_Count(long *plCount)
  735. {
  736. *plCount = 0;
  737. HRESULT hr = _SecurityCheck();
  738. if (SUCCEEDED(hr))
  739. {
  740. *plCount = GetMenuItemCount(_hmenu);
  741. }
  742. return hr;
  743. }
  744. STDMETHODIMP CFolderItemVerbs::Item(VARIANT index, FolderItemVerb **ppid)
  745. {
  746. *ppid = NULL;
  747. HRESULT hr = _SecurityCheck();
  748. if (SUCCEEDED(hr))
  749. {
  750. // This is sortof gross, but if we are passed a pointer to another variant, simply
  751. // update our copy here...
  752. if (index.vt == (VT_BYREF | VT_VARIANT) && index.pvarVal)
  753. index = *index.pvarVal;
  754. switch (index.vt)
  755. {
  756. case VT_ERROR:
  757. QueryInterface(IID_PPV_ARG(FolderItemVerb, ppid));
  758. break;
  759. case VT_I2:
  760. index.lVal = (long)index.iVal;
  761. // And fall through...
  762. case VT_I4:
  763. if ((index.lVal >= 0) && (index.lVal <= GetMenuItemCount(_hmenu)))
  764. {
  765. CFolderItemVerb_Create(this, GetMenuItemID(_hmenu, index.lVal), ppid);
  766. }
  767. break;
  768. default:
  769. hr = E_NOTIMPL;
  770. }
  771. if (*ppid && _dwSafetyOptions)
  772. {
  773. hr = MakeSafeForScripting((IUnknown**)ppid);
  774. }
  775. else if (hr != E_NOTIMPL)
  776. {
  777. hr = S_OK;
  778. }
  779. }
  780. return hr;
  781. }
  782. STDMETHODIMP CFolderItemVerbs::_NewEnum(IUnknown **ppunk)
  783. {
  784. *ppunk = NULL;
  785. HRESULT hr = _SecurityCheck();
  786. if (SUCCEEDED(hr))
  787. {
  788. hr = E_OUTOFMEMORY;
  789. CEnumFolderItemVerbs *pNew = new CEnumFolderItemVerbs(SAFECAST(this, CFolderItemVerbs*));
  790. if (pNew)
  791. {
  792. if (pNew->Init())
  793. hr = pNew->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  794. pNew->Release();
  795. }
  796. if (SUCCEEDED(hr) && _dwSafetyOptions)
  797. hr = MakeSafeForScripting(ppunk);
  798. }
  799. return hr;
  800. }
  801. CEnumFolderItemVerbs::CEnumFolderItemVerbs(CFolderItemVerbs *pfiv) :
  802. _cRef(1), _iCur(0), _psdfiv(pfiv)
  803. {
  804. _psdfiv->AddRef();
  805. DllAddRef();
  806. }
  807. CEnumFolderItemVerbs::~CEnumFolderItemVerbs(void)
  808. {
  809. DllRelease();
  810. _psdfiv->Release();
  811. }
  812. BOOL CEnumFolderItemVerbs::Init()
  813. {
  814. return TRUE; // Currently no initialization needed
  815. }
  816. STDMETHODIMP CEnumFolderItemVerbs::QueryInterface(REFIID riid, void **ppv)
  817. {
  818. static const QITAB qit[] = {
  819. QITABENT(CEnumFolderItemVerbs, IEnumVARIANT),
  820. QITABENT(CEnumFolderItemVerbs, IObjectSafety),
  821. { 0 },
  822. };
  823. return QISearch(this, qit, riid, ppv);
  824. }
  825. STDMETHODIMP_(ULONG) CEnumFolderItemVerbs::AddRef(void)
  826. {
  827. return InterlockedIncrement(&_cRef);
  828. }
  829. STDMETHODIMP_(ULONG) CEnumFolderItemVerbs::Release(void)
  830. {
  831. if (InterlockedDecrement(&_cRef))
  832. return _cRef;
  833. delete this;
  834. return 0;
  835. }
  836. STDMETHODIMP CEnumFolderItemVerbs::Next(ULONG cVar, VARIANT *pVar, ULONG *pulVar)
  837. {
  838. ULONG cReturn = 0;
  839. HRESULT hr;
  840. if (!pulVar)
  841. {
  842. if (cVar != 1)
  843. return E_POINTER;
  844. }
  845. else
  846. *pulVar = 0;
  847. if (!pVar || _iCur >= GetMenuItemCount(_psdfiv->_hmenu))
  848. return S_FALSE;
  849. while (_iCur < GetMenuItemCount(_psdfiv->_hmenu) && cVar > 0)
  850. {
  851. FolderItemVerb *pidv;
  852. hr = CFolderItemVerb_Create(_psdfiv, GetMenuItemID(_psdfiv->_hmenu, _iCur), &pidv);
  853. if (SUCCEEDED(hr) && _dwSafetyOptions)
  854. hr = MakeSafeForScripting((IUnknown**)&pidv);
  855. _iCur++;
  856. if (SUCCEEDED(hr))
  857. {
  858. pVar->pdispVal = pidv;
  859. pVar->vt = VT_DISPATCH;
  860. pVar++;
  861. cReturn++;
  862. cVar--;
  863. }
  864. }
  865. if (pulVar)
  866. *pulVar = cReturn;
  867. return S_OK;
  868. }
  869. STDMETHODIMP CEnumFolderItemVerbs::Skip(ULONG cSkip)
  870. {
  871. if ((int)(_iCur + cSkip) >= GetMenuItemCount(_psdfiv->_hmenu))
  872. return S_FALSE;
  873. _iCur += cSkip;
  874. return S_OK;
  875. }
  876. STDMETHODIMP CEnumFolderItemVerbs::Reset(void)
  877. {
  878. _iCur = 0;
  879. return S_OK;
  880. }
  881. STDMETHODIMP CEnumFolderItemVerbs::Clone(IEnumVARIANT **ppEnum)
  882. {
  883. *ppEnum = NULL;
  884. HRESULT hr = E_OUTOFMEMORY;
  885. CEnumFolderItemVerbs *pNew = new CEnumFolderItemVerbs(_psdfiv);
  886. if (pNew)
  887. {
  888. if (pNew->Init())
  889. hr = pNew->QueryInterface(IID_PPV_ARG(IEnumVARIANT, ppEnum));
  890. pNew->Release();
  891. }
  892. if (SUCCEEDED(hr) && _dwSafetyOptions)
  893. hr = MakeSafeForScripting((IUnknown**)ppEnum);
  894. return hr;
  895. }
  896. HRESULT CFolderItemVerb_Create(CFolderItemVerbs *psdfivs, UINT id, FolderItemVerb **ppid)
  897. {
  898. *ppid = NULL;
  899. HRESULT hr = E_OUTOFMEMORY;
  900. CFolderItemVerb* psdfiv = new CFolderItemVerb(psdfivs, id);
  901. if (psdfiv)
  902. {
  903. hr = psdfiv->QueryInterface(IID_PPV_ARG(FolderItemVerb, ppid));
  904. psdfiv->Release();
  905. }
  906. return hr;
  907. }
  908. CFolderItemVerb::CFolderItemVerb(CFolderItemVerbs *psdfivs, UINT id) :
  909. _cRef(1), _psdfivs(psdfivs), _id(id),
  910. CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItemVerb)
  911. {
  912. _psdfivs->AddRef();
  913. DllAddRef();
  914. }
  915. CFolderItemVerb::~CFolderItemVerb(void)
  916. {
  917. DllRelease();
  918. _psdfivs->Release();
  919. }
  920. STDMETHODIMP CFolderItemVerb::QueryInterface(REFIID riid, void **ppv)
  921. {
  922. static const QITAB qit[] = {
  923. QITABENT(CFolderItemVerb, FolderItemVerb),
  924. QITABENT(CFolderItemVerb, IObjectSafety),
  925. QITABENTMULTI(CFolderItemVerb, IDispatch, FolderItemVerb),
  926. { 0 },
  927. };
  928. return QISearch(this, qit, riid, ppv);
  929. }
  930. STDMETHODIMP_(ULONG) CFolderItemVerb::AddRef(void)
  931. {
  932. return InterlockedIncrement(&_cRef);
  933. }
  934. STDMETHODIMP_(ULONG) CFolderItemVerb::Release(void)
  935. {
  936. if (InterlockedDecrement(&_cRef))
  937. return _cRef;
  938. delete this;
  939. return 0;
  940. }
  941. STDMETHODIMP CFolderItemVerb::get_Application(IDispatch **ppid)
  942. {
  943. // _psdfivs returns E_NOTIMPL
  944. return _psdfivs->get_Application(ppid);
  945. }
  946. STDMETHODIMP CFolderItemVerb::get_Parent(IDispatch **ppid)
  947. {
  948. *ppid = NULL;
  949. return E_NOTIMPL;
  950. }
  951. STDMETHODIMP CFolderItemVerb::get_Name(BSTR *pbs)
  952. {
  953. TCHAR szMenuText[MAX_PATH];
  954. // Warning: did not check security here as could not get here if unsafe...
  955. GetMenuString(_psdfivs->_hmenu, _id, szMenuText, ARRAYSIZE(szMenuText), MF_BYCOMMAND);
  956. *pbs = SysAllocStringT(szMenuText);
  957. return *pbs ? S_OK : E_OUTOFMEMORY;
  958. }
  959. STDMETHODIMP CFolderItemVerb::DoIt()
  960. {
  961. CMINVOKECOMMANDINFO ici = {
  962. sizeof(CMINVOKECOMMANDINFO),
  963. 0L,
  964. NULL,
  965. NULL,
  966. NULL, NULL,
  967. SW_SHOWNORMAL,
  968. };
  969. // Warning: did not check security here as could not get here if unsafe...
  970. ici.lpVerb = (LPSTR)MAKEINTRESOURCE(_id - CONTEXTMENU_IDCMD_FIRST);
  971. return _psdfivs->_pcm->InvokeCommand(&ici);
  972. }