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.

1145 lines
30 KiB

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