#include "precomp.h" #pragma hdrstop // BUGBUG: from shell32\prop.cpp STDAPI_(BOOL) ParseSCIDString(LPCTSTR pszString, SHCOLUMNID *pscid, UINT *pidRes); #define TF_SHELLAUTO TF_CUSTOM1 #define DEFINE_FLOAT_STUFF // Do this because DATE is being used below class CFolderItemVerbs; class CEnumFolderItemVerbs; class CFolderItemVerb; class CFolderItemVerbs : public FolderItemVerbs, public CObjectSafety, protected CImpIDispatch, protected CObjectWithSite { friend class CEnumFolderItemVerbs; friend class CFolderItemVerb; public: CFolderItemVerbs(IContextMenu *pcm); BOOL Init(void); // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IDispatch STDMETHODIMP GetTypeInfoCount(UINT * pctinfo) { return CImpIDispatch::GetTypeInfoCount(pctinfo); } STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo) { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); } STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid) { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); } STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr) { return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); } // FolderItemVerbs STDMETHODIMP get_Application(IDispatch **ppid); STDMETHODIMP get_Parent(IDispatch **ppid); STDMETHODIMP get_Count(long *plCount); STDMETHODIMP Item(VARIANT, FolderItemVerb**); STDMETHODIMP _NewEnum(IUnknown **); private: ~CFolderItemVerbs(void); HRESULT _SecurityCheck(); LONG _cRef; HMENU _hmenu; IContextMenu *_pcm; }; class CEnumFolderItemVerbs : public IEnumVARIANT, public CObjectSafety { public: CEnumFolderItemVerbs(CFolderItemVerbs *psdfiv); BOOL Init(); // IUnknown STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IEnumFORMATETC STDMETHODIMP Next(ULONG, VARIANT *, ULONG *); STDMETHODIMP Skip(ULONG); STDMETHODIMP Reset(void); STDMETHODIMP Clone(IEnumVARIANT **); private: ~CEnumFolderItemVerbs(); LONG _cRef; int _iCur; CFolderItemVerbs *_psdfiv; }; HRESULT CFolderItemVerb_Create(CFolderItemVerbs *psdfivs, UINT id, FolderItemVerb **pfiv); class CFolderItemVerb : public FolderItemVerb, public CObjectSafety, protected CImpIDispatch { friend class CFolderItemVerbs; public: CFolderItemVerb(CFolderItemVerbs *psdfivs, UINT id); // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IDispatch STDMETHODIMP GetTypeInfoCount(UINT * pctinfo) { return CImpIDispatch::GetTypeInfoCount(pctinfo); } STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo) { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); } STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid) { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); } STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr) { return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); } // FolderItemVerbs STDMETHODIMP get_Application(IDispatch **ppid); STDMETHODIMP get_Parent(IDispatch **ppid); STDMETHODIMP get_Name(BSTR *pbs); STDMETHODIMP DoIt(); private: ~CFolderItemVerb(void); LONG _cRef; CFolderItemVerbs *_psdfivs; UINT _id; }; // in: // psdf folder that contains pidl // pidl pidl retlative to psdf (the item in this folder) HRESULT CFolderItem_Create(CFolder *psdf, LPCITEMIDLIST pidl, FolderItem **ppid) { *ppid = NULL; HRESULT hr = E_OUTOFMEMORY; CFolderItem* psdfi = new CFolderItem(); if (psdfi) { hr = psdfi->Init(psdf, pidl); if (SUCCEEDED(hr)) hr = psdfi->QueryInterface(IID_PPV_ARG(FolderItem, ppid)); psdfi->Release(); } return hr; } STDAPI CFolderItem_CreateInstance(IUnknown *punk, REFIID riid, void **ppv) { HRESULT hr = E_OUTOFMEMORY; *ppv = NULL; CFolderItem *pfi = new CFolderItem(); if (pfi) { hr = pfi->QueryInterface(riid, ppv); pfi->Release(); } return hr; } // in: // pidl fully qualified pidl // hwnd hacks HRESULT CFolderItem_CreateFromIDList(HWND hwnd, LPCITEMIDLIST pidl, FolderItem **ppfi) { LPITEMIDLIST pidlParent; HRESULT hr = SHILClone(pidl, &pidlParent); if (SUCCEEDED(hr)) { ILRemoveLastID(pidlParent); CFolder *psdf; hr = CFolder_Create2(hwnd, pidlParent, NULL, &psdf); if (SUCCEEDED(hr)) { hr = CFolderItem_Create(psdf, ILFindLastID(pidl), ppfi); psdf->Release(); } ILFree(pidlParent); } return hr; } CFolderItem::CFolderItem() : _cRef(1), _psdf(NULL), _pidl(NULL), CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItem2) { DllAddRef(); } CFolderItem::~CFolderItem(void) { if (_pidl) ILFree(_pidl); if (_psdf) _psdf->Release(); DllRelease(); } HRESULT GetItemFolder(CFolder *psdfRoot, LPCITEMIDLIST pidl, CFolder **ppsdf) { HRESULT hr = S_OK; ASSERT(psdfRoot); if (ILFindLastID(pidl) != pidl) { LPITEMIDLIST pidlIn = ILClone(pidl); hr = E_OUTOFMEMORY; if (pidlIn && ILRemoveLastID(pidlIn)) { LPITEMIDLIST pidlParent; LPITEMIDLIST pidlFolder = NULL; hr = psdfRoot->GetCurFolder(&pidlFolder); if (SUCCEEDED(hr)) { pidlParent = ILCombine(pidlFolder, pidlIn); if (pidlParent) { hr = CFolder_Create2(NULL, pidlParent, NULL, ppsdf); ILFree(pidlParent); } ILFree(pidlFolder); } } ILFree(pidlIn);// ilfree does null check } else { *ppsdf = psdfRoot; psdfRoot->AddRef(); } return hr; } HRESULT CFolderItem::Init(CFolder *psdf, LPCITEMIDLIST pidl) { HRESULT hr = GetItemFolder(psdf, pidl, &_psdf); if (SUCCEEDED(hr)) { hr = SHILClone(ILFindLastID(pidl), &_pidl); } return hr; } STDMETHODIMP CFolderItem::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CFolderItem, FolderItem2), QITABENTMULTI(CFolderItem, FolderItem, FolderItem2), QITABENTMULTI(CFolderItem, IDispatch, FolderItem2), QITABENTMULTI(CFolderItem, IPersist, IPersistFolder2), QITABENTMULTI(CFolderItem, IPersistFolder, IPersistFolder2), QITABENT(CFolderItem, IPersistFolder2), QITABENT(CFolderItem, IObjectSafety), QITABENT(CFolderItem, IParentAndItem), { 0 }, }; HRESULT hr = QISearch(this, qit, riid, ppv); if (FAILED(hr) && IsEqualGUID(CLSID_ShellFolderItem, riid)) { *ppv = (CFolderItem *)this; // unrefed hr = S_OK; } return hr; } STDMETHODIMP_(ULONG) CFolderItem::AddRef(void) { return InterlockedIncrement(&_cRef); } STDMETHODIMP_(ULONG) CFolderItem::Release(void) { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } //The FolderItem implementation STDMETHODIMP CFolderItem::get_Application(IDispatch **ppid) { // Let the folder object handle security and reference counting of site, etc return _psdf->get_Application(ppid); } STDMETHODIMP CFolderItem::get_Parent(IDispatch **ppid) { // Assume that the Folder object is the parent of this object... HRESULT hr = _psdf->QueryInterface(IID_PPV_ARG(IDispatch, ppid)); if (SUCCEEDED(hr) && _dwSafetyOptions) hr = MakeSafeForScripting((IUnknown**)ppid); return hr; } HRESULT CFolderItem::_ItemName(UINT dwFlags, BSTR *pbs) { HRESULT hr; STRRET strret; if (SUCCEEDED(_psdf->_psf->GetDisplayNameOf(_pidl, dwFlags, &strret))) { hr = StrRetToBSTR(&strret, _pidl, pbs); } else { *pbs = SysAllocString(L""); hr = (*pbs) ? S_FALSE : E_OUTOFMEMORY; } return hr; } STDMETHODIMP CFolderItem::get_Name(BSTR *pbs) { *pbs = NULL; HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = _ItemName(SHGDN_INFOLDER, pbs); } return hr; } STDMETHODIMP CFolderItem::put_Name(BSTR bs) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { LPITEMIDLIST pidlOut; hr = _psdf->_psf->SetNameOf(_psdf->_hwnd, _pidl, bs, SHGDN_INFOLDER, &pidlOut); if (SUCCEEDED(hr)) { ILFree(_pidl); _pidl = pidlOut; } } return hr; } // BUGBUG: this should validate that the path is a file system // object (SFGAO_FILESYSTEM) STDMETHODIMP CFolderItem::get_Path(BSTR *pbs) { *pbs = NULL; HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = _ItemName(SHGDN_FORPARSING, pbs); } return hr; } STDMETHODIMP CFolderItem::get_GetLink(IDispatch **ppid) { *ppid = NULL; HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = CShortcut_CreateIDispatch(_psdf->_hwnd, _psdf->_psf, _pidl, ppid); if (SUCCEEDED(hr) && _dwSafetyOptions) { hr = MakeSafeForScripting((IUnknown**)ppid); } } return hr; } // BUGBUG:: this should return Folder **... STDMETHODIMP CFolderItem::get_GetFolder(IDispatch **ppid /* Folder **ppf */) { *ppid = NULL; // If in Safe mode we fail this one... HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { LPITEMIDLIST pidl; hr = SHILCombine(_psdf->_pidl, _pidl, &pidl); if (SUCCEEDED(hr)) { hr = CFolder_Create(NULL, pidl, NULL, IID_PPV_ARG(IDispatch, ppid)); if (SUCCEEDED(hr)) { if (_dwSafetyOptions) { // note, this is created without a site so script safety checks will fail hr = MakeSafeForScripting((IUnknown**)ppid); } } ILFree(pidl); } } return hr; } HRESULT CFolderItem::_CheckAttribute(ULONG ulAttrIn, VARIANT_BOOL * pb) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { ULONG ulAttr = ulAttrIn; hr = _psdf->_psf->GetAttributesOf(1, (LPCITEMIDLIST*)&_pidl, &ulAttr); *pb = (SUCCEEDED(hr) && (ulAttr & ulAttrIn)) ? VARIANT_TRUE : VARIANT_FALSE; } return hr; } HRESULT CFolderItem::_GetUIObjectOf(REFIID riid, void **ppv) { return _psdf->_psf->GetUIObjectOf(_psdf->_hwnd, 1, (LPCITEMIDLIST*)&_pidl, riid, NULL, ppv); } HRESULT CFolderItem::_SecurityCheck() { if (!_dwSafetyOptions) return S_OK; return _psdf->_SecurityCheck(); } // allow friend classes to get the IDList for a CFolderItem automation object LPCITEMIDLIST CFolderItem::_GetIDListFromVariant(const VARIANT *pv) { LPCITEMIDLIST pidl = NULL; if (pv) { VARIANT v; if (pv->vt == (VT_BYREF | VT_VARIANT) && pv->pvarVal) v = *pv->pvarVal; else v = *pv; switch (v.vt) { case VT_DISPATCH | VT_BYREF: if (v.ppdispVal == NULL) break; v.pdispVal = *v.ppdispVal; // fall through... case VT_DISPATCH: CFolderItem *pfi; if (v.pdispVal && SUCCEEDED(v.pdispVal->QueryInterface(CLSID_ShellFolderItem, (void **)&pfi))) { pidl = pfi->_pidl; // alias } break; } } return pidl; } STDMETHODIMP CFolderItem::get_IsLink(VARIANT_BOOL * pb) { return _CheckAttribute(SFGAO_LINK, pb); } STDMETHODIMP CFolderItem::get_IsFolder(VARIANT_BOOL * pb) { return _CheckAttribute(SFGAO_FOLDER, pb); } STDMETHODIMP CFolderItem::get_IsFileSystem(VARIANT_BOOL * pb) { return _CheckAttribute(SFGAO_FILESYSTEM, pb); } STDMETHODIMP CFolderItem::get_IsBrowsable(VARIANT_BOOL * pb) { return _CheckAttribute(SFGAO_BROWSABLE, pb); } STDMETHODIMP CFolderItem::get_ModifyDate(DATE *pdt) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { WIN32_FIND_DATA finddata; if (SUCCEEDED(SHGetDataFromIDList(_psdf->_psf, _pidl, SHGDFIL_FINDDATA, &finddata, sizeof(finddata)))) { WORD wDosDate, wDosTime; FILETIME filetime; FileTimeToLocalFileTime(&finddata.ftLastWriteTime, &filetime); FileTimeToDosDateTime(&filetime, &wDosDate, &wDosTime); DosDateTimeToVariantTime(wDosDate, wDosTime, pdt); } hr = S_OK; } return hr; } STDMETHODIMP CFolderItem::put_ModifyDate(DATE dt) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = S_FALSE; SYSTEMTIME st; FILETIME ftLocal, ft; BSTR bstrPath; if (SUCCEEDED(VariantTimeToSystemTime(dt, &st)) && SystemTimeToFileTime(&st, &ftLocal) && LocalFileTimeToFileTime(&ftLocal, &ft) && SUCCEEDED(get_Path(&bstrPath))) { TCHAR szPath[MAX_PATH]; SHUnicodeToTChar(bstrPath, szPath, ARRAYSIZE(szPath)); SysFreeString(bstrPath); HANDLE hFile = CreateFile(szPath, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OPEN_NO_RECALL, NULL); if (hFile != INVALID_HANDLE_VALUE) { if (SetFileTime(hFile, NULL, NULL, &ft)) { hr = S_OK; } CloseHandle(hFile); } } } return hr; } // BUGBUG:: Should see about getting larger numbers through STDMETHODIMP CFolderItem::get_Size(LONG *pul) { HRESULT hr =_SecurityCheck(); if (SUCCEEDED(hr)) { WIN32_FIND_DATA finddata; if (SUCCEEDED(SHGetDataFromIDList(_psdf->_psf, _pidl, SHGDFIL_FINDDATA, &finddata, sizeof(finddata)))) { *pul = (LONG)finddata.nFileSizeLow; } else { *pul = 0L; } hr = S_OK; // Scripts don't like error return values } return hr; } STDMETHODIMP CFolderItem::get_Type(BSTR *pbs) { *pbs = NULL; HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { VARIANT var; var.vt = VT_EMPTY; if (SUCCEEDED(ExtendedProperty(L"Type", &var)) && (var.vt == VT_BSTR)) { *pbs = SysAllocString(var.bstrVal); } else { *pbs = SysAllocString(L""); } VariantClear(&var); hr = *pbs ? S_OK : E_OUTOFMEMORY; } return hr; } STDMETHODIMP CFolderItem::ExtendedProperty(BSTR bstrPropName, VARIANT *pvRet) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = E_FAIL; VariantInit(pvRet); // currently, MCNL is 80, guidstr is 39, and 6 is the width of an int if (StrCmpIW(bstrPropName, L"infotip") == 0) { // They want the info tip for the item. if (_pidl && _psdf) { TCHAR szInfo[INFOTIPSIZE]; GetInfoTipHelp(_psdf->_psf, _pidl, szInfo, ARRAYSIZE(szInfo)); hr = InitVariantFromStr(pvRet, szInfo); } } else if (_psdf->_psf2) { SHCOLUMNID scid; TCHAR szTemp[128]; SHUnicodeToTChar(bstrPropName, szTemp, ARRAYSIZE(szTemp)); if (ParseSCIDString(szTemp, &scid, NULL)) { // Note that GetDetailsEx expects an absolute pidl hr = _psdf->_psf2->GetDetailsEx(_pidl, &scid, pvRet); } } hr = FAILED(hr) ? S_FALSE : hr; // Java scripts barf on error values } return hr; } STDMETHODIMP CFolderItem::Verbs(FolderItemVerbs **ppfic) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = S_FALSE; IContextMenu *pcm; if (SUCCEEDED(_GetUIObjectOf(IID_PPV_ARG(IContextMenu, &pcm)))) { hr = CFolderItemVerbs_Create(pcm, ppfic); if (SUCCEEDED(hr) && _dwSafetyOptions) { hr = MakeSafeForScripting((IUnknown**)ppfic); if (SUCCEEDED(hr)) { // Set the folder's site to FolderItemVerbs IUnknown_SetSite(*ppfic, _psdf->_punkSite); } } pcm->Release(); } } return hr; } STDMETHODIMP CFolderItem::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs) { // security check handled by _psdf return _psdf->InvokeVerbHelper(vVerb, vArgs, (LPCITEMIDLIST *)&_pidl, 1, _dwSafetyOptions); } STDMETHODIMP CFolderItem::InvokeVerb(VARIANT vVerb) { VARIANT vtEmpty = {VT_EMPTY}; return InvokeVerbEx(vVerb, vtEmpty); } STDMETHODIMP CFolderItem::GetClassID(CLSID *pClassID) { *pClassID = CLSID_ShellFolderItem; return E_NOTIMPL; } // IPersistFolder // note, this duplicates some of CFolderItem::Init() functionality STDMETHODIMP CFolderItem::Initialize(LPCITEMIDLIST pidl) { LPITEMIDLIST pidlParent; HRESULT hr = SHILClone(pidl, &pidlParent); if (SUCCEEDED(hr)) { ASSERT(_pidl == NULL); hr = SHILClone(ILFindLastID(pidlParent), &_pidl); if (SUCCEEDED(hr)) { // Chop off the filename and get the folder that contains // this FolderItem. ILRemoveLastID(pidlParent); // BUGBUG: we should find some way to get a valid hwnd to // pass to CFolder_Create2 instead of NULL. ASSERT(_psdf == NULL); hr = CFolder_Create2(NULL, pidlParent, NULL, &_psdf); } ILFree(pidlParent); } return hr; } STDMETHODIMP CFolderItem::GetCurFolder(LPITEMIDLIST *ppidl) { LPITEMIDLIST pidlFolder; HRESULT hr = SHGetIDListFromUnk(_psdf->_psf, &pidlFolder); if (S_OK == hr) { hr = SHILCombine(pidlFolder, _pidl, ppidl); ILFree(pidlFolder); } else hr = E_FAIL; return hr; } // IParentAndItem STDMETHODIMP CFolderItem::SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidl) { return E_NOTIMPL; } STDMETHODIMP CFolderItem::GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidl) { if (ppidlParent) { *ppidlParent = _psdf->_pidl ? ILClone(_psdf->_pidl) : NULL; } if (ppsf) { *ppsf = NULL; if (_psdf && _psdf->_psf) _psdf->_psf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsf)); } if (ppidl) *ppidl = ILClone(_pidl); if ((ppidlParent && !*ppidlParent) || (ppsf && !*ppsf) || (ppidl && !*ppidl)) { // this is failure // but we dont know what failed if (ppsf && *ppsf) (*ppsf)->Release(); if (ppidlParent) ILFree(*ppidlParent); if (ppidl) ILFree(*ppidl); return E_OUTOFMEMORY; } return S_OK; } HRESULT CFolderItemVerbs_Create(IContextMenu *pcm, FolderItemVerbs ** ppid) { *ppid = NULL; HRESULT hr = E_OUTOFMEMORY; CFolderItemVerbs* pfiv = new CFolderItemVerbs(pcm); if (pfiv) { if (pfiv->Init()) hr = pfiv->QueryInterface(IID_PPV_ARG(FolderItemVerbs, ppid)); pfiv->Release(); } return hr; } CFolderItemVerbs::CFolderItemVerbs(IContextMenu *pcm) : _cRef(1), _hmenu(NULL), _pcm(pcm), CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItemVerbs) { DllAddRef(); _pcm->AddRef(); } CFolderItemVerbs::~CFolderItemVerbs(void) { DllRelease(); if (_pcm) _pcm->Release(); if (_hmenu) DestroyMenu(_hmenu); } BOOL CFolderItemVerbs::Init() { TraceMsg(TF_SHELLAUTO, "CFolderItemVerbs::Init called"); // Start of only doing default verb... if (_pcm) { _hmenu = CreatePopupMenu(); if (FAILED(_pcm->QueryContextMenu(_hmenu, 0, CONTEXTMENU_IDCMD_FIRST, CONTEXTMENU_IDCMD_LAST, CMF_CANRENAME|CMF_NORMAL))) return FALSE; } else return FALSE; // Just for the heck of it, remove junk like sepearators from the menu... for (int i = GetMenuItemCount(_hmenu) - 1; i >= 0; i--) { MENUITEMINFO mii; TCHAR szText[80]; // should be big enough for this mii.cbSize = sizeof(MENUITEMINFO); mii.dwTypeData = szText; mii.fMask = MIIM_TYPE | MIIM_ID; mii.cch = ARRAYSIZE(szText); mii.fType = MFT_SEPARATOR; // to avoid ramdom result. mii.dwItemData = 0; GetMenuItemInfo(_hmenu, i, TRUE, &mii); if (mii.fType & MFT_SEPARATOR) DeleteMenu(_hmenu, i, MF_BYPOSITION); } return TRUE; } STDMETHODIMP CFolderItemVerbs::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CFolderItemVerbs, FolderItemVerbs), QITABENT(CFolderItemVerbs, IObjectSafety), QITABENTMULTI(CFolderItemVerbs, IDispatch, FolderItemVerbs), QITABENT(CFolderItemVerbs, IObjectWithSite), { 0 }, }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_(ULONG) CFolderItemVerbs::AddRef(void) { return InterlockedIncrement(&_cRef); } STDMETHODIMP_(ULONG) CFolderItemVerbs::Release(void) { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } STDMETHODIMP CFolderItemVerbs::get_Application(IDispatch **ppid) { *ppid = NULL; return E_NOTIMPL; } STDMETHODIMP CFolderItemVerbs::get_Parent(IDispatch **ppid) { *ppid = NULL; return E_NOTIMPL; } HRESULT CFolderItemVerbs::_SecurityCheck() { return (!_dwSafetyOptions || (IsSafePage(_punkSite) == S_OK)) ? S_OK : E_ACCESSDENIED; } STDMETHODIMP CFolderItemVerbs::get_Count(long *plCount) { *plCount = 0; HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { *plCount = GetMenuItemCount(_hmenu); } return hr; } STDMETHODIMP CFolderItemVerbs::Item(VARIANT index, FolderItemVerb **ppid) { *ppid = NULL; HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { // This is sortof gross, but if we are passed a pointer to another variant, simply // update our copy here... if (index.vt == (VT_BYREF | VT_VARIANT) && index.pvarVal) index = *index.pvarVal; switch (index.vt) { case VT_ERROR: QueryInterface(IID_PPV_ARG(FolderItemVerb, ppid)); break; case VT_I2: index.lVal = (long)index.iVal; // And fall through... case VT_I4: if ((index.lVal >= 0) && (index.lVal <= GetMenuItemCount(_hmenu))) { CFolderItemVerb_Create(this, GetMenuItemID(_hmenu, index.lVal), ppid); } break; default: hr = E_NOTIMPL; } if (*ppid && _dwSafetyOptions) { hr = MakeSafeForScripting((IUnknown**)ppid); } else if (hr != E_NOTIMPL) { hr = S_OK; } } return hr; } STDMETHODIMP CFolderItemVerbs::_NewEnum(IUnknown **ppunk) { *ppunk = NULL; HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = E_OUTOFMEMORY; CEnumFolderItemVerbs *pNew = new CEnumFolderItemVerbs(SAFECAST(this, CFolderItemVerbs*)); if (pNew) { if (pNew->Init()) hr = pNew->QueryInterface(IID_PPV_ARG(IUnknown, ppunk)); pNew->Release(); } if (SUCCEEDED(hr) && _dwSafetyOptions) hr = MakeSafeForScripting(ppunk); } return hr; } CEnumFolderItemVerbs::CEnumFolderItemVerbs(CFolderItemVerbs *pfiv) : _cRef(1), _iCur(0), _psdfiv(pfiv) { _psdfiv->AddRef(); DllAddRef(); } CEnumFolderItemVerbs::~CEnumFolderItemVerbs(void) { DllRelease(); _psdfiv->Release(); } BOOL CEnumFolderItemVerbs::Init() { return TRUE; // Currently no initialization needed } STDMETHODIMP CEnumFolderItemVerbs::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CEnumFolderItemVerbs, IEnumVARIANT), QITABENT(CEnumFolderItemVerbs, IObjectSafety), { 0 }, }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_(ULONG) CEnumFolderItemVerbs::AddRef(void) { return InterlockedIncrement(&_cRef); } STDMETHODIMP_(ULONG) CEnumFolderItemVerbs::Release(void) { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } STDMETHODIMP CEnumFolderItemVerbs::Next(ULONG cVar, VARIANT *pVar, ULONG *pulVar) { ULONG cReturn = 0; HRESULT hr; if (!pulVar) { if (cVar != 1) return E_POINTER; } else *pulVar = 0; if (!pVar || _iCur >= GetMenuItemCount(_psdfiv->_hmenu)) return S_FALSE; while (_iCur < GetMenuItemCount(_psdfiv->_hmenu) && cVar > 0) { FolderItemVerb *pidv; hr = CFolderItemVerb_Create(_psdfiv, GetMenuItemID(_psdfiv->_hmenu, _iCur), &pidv); if (SUCCEEDED(hr) && _dwSafetyOptions) hr = MakeSafeForScripting((IUnknown**)&pidv); _iCur++; if (SUCCEEDED(hr)) { pVar->pdispVal = pidv; pVar->vt = VT_DISPATCH; pVar++; cReturn++; cVar--; } } if (pulVar) *pulVar = cReturn; return S_OK; } STDMETHODIMP CEnumFolderItemVerbs::Skip(ULONG cSkip) { if ((int)(_iCur + cSkip) >= GetMenuItemCount(_psdfiv->_hmenu)) return S_FALSE; _iCur += cSkip; return S_OK; } STDMETHODIMP CEnumFolderItemVerbs::Reset(void) { _iCur = 0; return S_OK; } STDMETHODIMP CEnumFolderItemVerbs::Clone(IEnumVARIANT **ppEnum) { *ppEnum = NULL; HRESULT hr = E_OUTOFMEMORY; CEnumFolderItemVerbs *pNew = new CEnumFolderItemVerbs(_psdfiv); if (pNew) { if (pNew->Init()) hr = pNew->QueryInterface(IID_PPV_ARG(IEnumVARIANT, ppEnum)); pNew->Release(); } if (SUCCEEDED(hr) && _dwSafetyOptions) hr = MakeSafeForScripting((IUnknown**)ppEnum); return hr; } HRESULT CFolderItemVerb_Create(CFolderItemVerbs *psdfivs, UINT id, FolderItemVerb **ppid) { *ppid = NULL; HRESULT hr = E_OUTOFMEMORY; CFolderItemVerb* psdfiv = new CFolderItemVerb(psdfivs, id); if (psdfiv) { hr = psdfiv->QueryInterface(IID_PPV_ARG(FolderItemVerb, ppid)); psdfiv->Release(); } return hr; } CFolderItemVerb::CFolderItemVerb(CFolderItemVerbs *psdfivs, UINT id) : _cRef(1), _psdfivs(psdfivs), _id(id), CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItemVerb) { _psdfivs->AddRef(); DllAddRef(); } CFolderItemVerb::~CFolderItemVerb(void) { DllRelease(); _psdfivs->Release(); } STDMETHODIMP CFolderItemVerb::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CFolderItemVerb, FolderItemVerb), QITABENT(CFolderItemVerb, IObjectSafety), QITABENTMULTI(CFolderItemVerb, IDispatch, FolderItemVerb), { 0 }, }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_(ULONG) CFolderItemVerb::AddRef(void) { return InterlockedIncrement(&_cRef); } STDMETHODIMP_(ULONG) CFolderItemVerb::Release(void) { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } STDMETHODIMP CFolderItemVerb::get_Application(IDispatch **ppid) { // _psdfivs returns E_NOTIMPL return _psdfivs->get_Application(ppid); } STDMETHODIMP CFolderItemVerb::get_Parent(IDispatch **ppid) { *ppid = NULL; return E_NOTIMPL; } STDMETHODIMP CFolderItemVerb::get_Name(BSTR *pbs) { TCHAR szMenuText[MAX_PATH]; // Warning: did not check security here as could not get here if unsafe... GetMenuString(_psdfivs->_hmenu, _id, szMenuText, ARRAYSIZE(szMenuText), MF_BYCOMMAND); *pbs = SysAllocStringT(szMenuText); return *pbs ? S_OK : E_OUTOFMEMORY; } STDMETHODIMP CFolderItemVerb::DoIt() { CMINVOKECOMMANDINFO ici = { sizeof(CMINVOKECOMMANDINFO), 0L, NULL, NULL, NULL, NULL, SW_SHOWNORMAL, }; // Warning: did not check security here as could not get here if unsafe... ici.lpVerb = (LPSTR)MAKEINTRESOURCE(_id - CONTEXTMENU_IDCMD_FIRST); return _psdfivs->_pcm->InvokeCommand(&ici); }