diff --git a/dll/shellext/cabview/cabview.h b/dll/shellext/cabview/cabview.h index bd31cfac64f..6f34b7a38a7 100644 --- a/dll/shellext/cabview/cabview.h +++ b/dll/shellext/cabview/cabview.h @@ -69,7 +69,7 @@ public: UINT count = GetCount(), fetched = 0; if (m_Pos < count && fetched < celt) { - if (SUCCEEDED(hr = SHILClone(DPA_FastGetPtr(m_Items, m_Pos), &rgelt[fetched]))) + if (SUCCEEDED(hr = SHILClone((LPITEMIDLIST)DPA_FastGetPtr(m_Items, m_Pos), &rgelt[fetched]))) fetched++; } if (pceltFetched) diff --git a/dll/win32/browseui/shellbrowser.cpp b/dll/win32/browseui/shellbrowser.cpp index 7303e25540b..629297f5bed 100644 --- a/dll/win32/browseui/shellbrowser.cpp +++ b/dll/win32/browseui/shellbrowser.cpp @@ -1049,7 +1049,7 @@ HRESULT CShellBrowser::BrowseToPath(IShellFolder *newShellFolder, if (FAILED_UNEXPECTEDLY(hResult)) return hResult; - if (FAILED_UNEXPECTEDLY(hResult = SHILClone(absolutePIDL, &absolutePIDL))) + if (FAILED_UNEXPECTEDLY(hResult = SHILClone(absolutePIDL, const_cast(&absolutePIDL)))) return hResult; CComHeapPtr pidlAbsoluteClone(const_cast(absolutePIDL)); diff --git a/dll/win32/shell32/CCopyMoveToMenu.cpp b/dll/win32/shell32/CCopyMoveToMenu.cpp index 48068eccc9e..cfc044e8514 100644 --- a/dll/win32/shell32/CCopyMoveToMenu.cpp +++ b/dll/win32/shell32/CCopyMoveToMenu.cpp @@ -366,14 +366,14 @@ CCopyMoveToMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, H HRESULT hr = E_FAIL; if (pidlFolder) { - hr = SHILClone(pidlFolder, &pidlFolder); + hr = SHILClone(pidlFolder, const_cast(&pidlFolder)); } else { pidlFolder = SHELL_DataObject_ILCloneFullItem(pdtobj, 0); if (pidlFolder) { - ILRemoveLastID((LPITEMIDLIST)pidlFolder); + ILRemoveLastID(const_cast(pidlFolder)); hr = S_OK; } } diff --git a/dll/win32/shell32/CEnumIDListBase.cpp b/dll/win32/shell32/CEnumIDListBase.cpp index d0a79b350d1..c88cff9ca08 100644 --- a/dll/win32/shell32/CEnumIDListBase.cpp +++ b/dll/win32/shell32/CEnumIDListBase.cpp @@ -107,7 +107,13 @@ HRESULT CEnumIDListBase::AppendItemsFromEnumerator(IEnumIDList* pEnum) pEnum->Reset(); while((S_OK == pEnum->Next(1, &pidl, &dwFetched)) && dwFetched) - AddToEnumList(pidl); + { + if (!AddToEnumList(pidl)) + { + ILFree(pidl); + return E_OUTOFMEMORY; + } + } return S_OK; } @@ -204,6 +210,41 @@ HRESULT WINAPI CEnumIDListBase::Clone(LPENUMIDLIST *ppenum) return E_NOTIMPL; } +/************************************************************************** +* CreateInstance +*/ +HRESULT CEnumIDListBase::CreateInstance(IEnumIDList &Source, CREATEINSTANCEFILTERFUNC Filter, void *CallerCookie, IEnumIDList **ppEnum) +{ + *ppEnum = NULL; + CComPtr pEnum; + HRESULT hr = ShellObjectCreator(pEnum); + if (FAILED(hr)) + return hr; + + for (;;) + { + CComHeapPtr pidl; + hr = Source.Next(1, &pidl, NULL); + if (hr == S_OK) + { + if (Filter) + hr = Filter(CallerCookie, pidl); + if (FAILED(hr)) + return hr; + if (hr != S_OK) + continue; + if (!pEnum->AddToEnumList(pidl)) + return E_OUTOFMEMORY; + pidl.Detach(); // AddToEnumList took ownership + continue; + } + if (FAILED(hr)) + return hr; + *ppEnum = pEnum.Detach(); + return S_OK; + } +} + /************************************************************************** * IEnumIDList_Folder_Constructor * diff --git a/dll/win32/shell32/CEnumIDListBase.h b/dll/win32/shell32/CEnumIDListBase.h index 68ce0966617..f166c2e1ce8 100644 --- a/dll/win32/shell32/CEnumIDListBase.h +++ b/dll/win32/shell32/CEnumIDListBase.h @@ -57,6 +57,9 @@ public: STDMETHOD(Reset)() override; STDMETHOD(Clone)(IEnumIDList **ppenum) override; + typedef HRESULT (CALLBACK* CREATEINSTANCEFILTERFUNC)(void *CallerCookie, LPCITEMIDLIST pidl); + static HRESULT CreateInstance(IEnumIDList &Source, CREATEINSTANCEFILTERFUNC Filter, void *CallerCookie, IEnumIDList **ppEnum); + BEGIN_COM_MAP(CEnumIDListBase) COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) END_COM_MAP() diff --git a/dll/win32/shell32/CFolder.cpp b/dll/win32/shell32/CFolder.cpp index 5a6a0e4f14e..df0c7c112e1 100644 --- a/dll/win32/shell32/CFolder.cpp +++ b/dll/win32/shell32/CFolder.cpp @@ -13,6 +13,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); EXTERN_C BOOL WINAPI Win32CreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec); +static inline HRESULT GetFolderItem(FolderItems *pItems, UINT Index, FolderItem **ppItem) +{ + VARIANT v; + V_VT(&v) = VT_I4; + V_I4(&v) = Index; + return pItems->Item(v, ppItem); +} + +static HRESULT GetFolderItem(FolderItems *pItems, UINT Index, IShellFolder **ppsf, PITEMID_CHILD *ppidlChild) +{ + CComPtr pFI; + HRESULT hr = GetFolderItem(pItems, Index, &pFI); + if (FAILED(hr)) + return hr; + CComPtr pPAI; + if (SUCCEEDED(hr = pFI->QueryInterface(IID_PPV_ARG(IParentAndItem, &pPAI)))) + return pPAI->GetParentAndItem(NULL, ppsf, ppidlChild); + return hr; +} + CFolder::CFolder() { } @@ -21,12 +41,10 @@ CFolder::~CFolder() { } -HRESULT CFolder::Initialize(LPCITEMIDLIST idlist) +HRESULT CFolder::Initialize(LPCITEMIDLIST idlist, IDispatch *pDispatch) { - m_idlist.Attach(ILClone(idlist)); - if (!m_idlist) - return E_OUTOFMEMORY; - return CShellDispatch_Constructor(IID_PPV_ARG(IShellDispatch, &m_Application)); + m_Application = pDispatch; + return SHILClone(idlist, &m_idlist); } HRESULT CFolder::GetShellFolder(CComPtr& psfCurrent) @@ -83,7 +101,7 @@ HRESULT STDMETHODCALLTYPE CFolder::get_ParentFolder(Folder **ppsf) CComHeapPtr pidlParent; if (FAILED(SHILCloneParent(pidlAbsSelf, &pidlParent))) return E_OUTOFMEMORY; - return ShellObjectCreatorInit(static_cast(pidlParent), IID_PPV_ARG(Folder, ppsf)); + return CFolder::CreateInstance(pidlParent, m_Application, IID_PPV_ARG(Folder, ppsf)); } HRESULT STDMETHODCALLTYPE CFolder::Items(FolderItems **ppid) @@ -117,7 +135,7 @@ HRESULT STDMETHODCALLTYPE CFolder::ParseName(BSTR bName, FolderItem **ppid) if (FAILED(hr = SHILCloneParent((LPCITEMIDLIST)combined, &parentPidl))) return hr; CComPtr pParent; // The parent Folder of the thing we just parsed - hr = ShellObjectCreatorInit(parentPidl, IID_PPV_ARG(Folder, &pParent)); + hr = CFolder::CreateInstance(parentPidl, m_Application, IID_PPV_ARG(Folder, &pParent)); if (FAILED(hr)) return hr; @@ -158,14 +176,40 @@ tryfs: // HACKFIX: Our CFSFolder does not yet support IStorage, try it directly return hr; } -static HRESULT GetUIObjectFromVariant(VARIANT &vItem, REFIID riid, void **ppv) +HRESULT CFolder::GetUIObjectFromVariant(VARIANT &vItem, REFIID riid, void **ppv) { + HWND hWnd = NULL; CComHeapPtr pidlOneItem; if (SUCCEEDED(VariantToIdlist(&vItem, &pidlOneItem))) - return SHELL_GetUIObjectOfAbsoluteItem(NULL, pidlOneItem, riid, ppv); + return SHELL_GetUIObjectOfAbsoluteItem(hWnd, pidlOneItem, riid, ppv); - // TODO: CFolderItems array - return E_NOTIMPL; + HRESULT hr = E_NOTIMPL; + CComPtr pItems; + if (SUCCEEDED(VariantQueryInterface(&vItem, IID_PPV_ARG(FolderItems, &pItems)))) + { + long count; + if (FAILED(hr = pItems->get_Count(&count))) + return hr; + if (count <= 0) + return HRESULT_FROM_WIN32(ERROR_NO_DATA); + + LPITEMIDLIST *ppidls = (LPITEMIDLIST*)SHAlloc(sizeof(*ppidls) * count); + if (!ppidls) + return E_OUTOFMEMORY; + CComPtr pFolder; + for (UINT i = 0; i < (UINT)count; ++i) + { + if (SUCCEEDED(hr = GetFolderItem(pItems, i, i == 0 ? &pFolder : NULL, &ppidls[i]))) + continue; + ppidls[i] = NULL; + count = i; // Don't free undefined items. Stop the loop. + } + + if (SUCCEEDED(hr)) + hr = pFolder->GetUIObjectOf(hWnd, count, const_cast(ppidls), riid, NULL, ppv); + _ILFreeaPidl(ppidls, count); + } + return hr; } HRESULT CFolder::CopyMoveOperation(VARIANT &vItem, VARIANT vOptions, BOOL bCopy) @@ -180,7 +224,10 @@ HRESULT CFolder::CopyMoveOperation(VARIANT &vItem, VARIANT vOptions, BOOL bCopy) return hr; CComPtr pDO; - if (FAILED_UNEXPECTEDLY(hr = GetUIObjectFromVariant(vItem, IID_PPV_ARG(IDataObject, &pDO)))) + hr = GetUIObjectFromVariant(vItem, IID_PPV_ARG(IDataObject, &pDO)); + if (hr == HRESULT_FROM_WIN32(ERROR_NO_DATA)) + return S_FALSE; + if (FAILED_UNEXPECTEDLY(hr)) return hr; if (SUCCEEDED(VariantChangeType(&vOptions, &vOptions, 0, VT_I4))) @@ -219,8 +266,8 @@ HRESULT STDMETHODCALLTYPE CFolder::GetDetailsOf(VARIANT vItem, int iColumn, BSTR if (FAILED(hr)) return hr; - PCUITEMID_CHILD pidlItem = CFolderItem::GetLeafPidlRef(&vItem); - if (pidlItem && iColumn == -1) + CComHeapPtr pidlItem(CFolderItem::CloneLeafPidl(&vItem)); + if (pidlItem && iColumn == INFOTIPCOLUMN) { PWSTR pszTip = NULL; if (SUCCEEDED(hr = SHELL_QueryInfoTipAlloc(psf, QITIPF_DEFAULT, pidlItem, &pszTip))) diff --git a/dll/win32/shell32/CFolder.h b/dll/win32/shell32/CFolder.h index cb11bac6828..debb49fede7 100644 --- a/dll/win32/shell32/CFolder.h +++ b/dll/win32/shell32/CFolder.h @@ -19,16 +19,19 @@ private: HRESULT CopyMoveOperation(VARIANT &vItem, VARIANT vOptions, BOOL bCopy); CComHeapPtr m_idlist; - CComPtr m_Application; + CComPtr m_Application; public: CFolder(); ~CFolder(); - HRESULT Initialize(LPCITEMIDLIST idlist); + enum { INFOTIPCOLUMN = -1 }; // learn.microsoft.com/en-us/windows/win32/shell/folder-getdetailsof + + HRESULT Initialize(LPCITEMIDLIST idlist, IDispatch *pDispatch); LPCITEMIDLIST GetAbsoluteIDList() { return m_idlist; } HWND GetHwnd() { return NULL; } IUnknown* GetSite() { return NULL; } + static HRESULT GetUIObjectFromVariant(VARIANT &vItem, REFIID riid, void **ppv); // *** Folder methods *** STDMETHOD(get_Title)(BSTR *pbs) override; @@ -49,6 +52,17 @@ public: STDMETHOD(get_HaveToShowWebViewBarricade)(VARIANT_BOOL *pbHaveToShowWebViewBarricade) override; STDMETHOD(DismissedWebViewBarricade)() override; + static HRESULT CreateInstance(LPCITEMIDLIST pidl, IDispatch *pDispatch, REFIID riid, void **ppv) + { + return ShellObjectCreatorInit(pidl, pDispatch, riid, ppv); + } + static HRESULT CreateInstance(LPCITEMIDLIST pidl, Folder &Instance, REFIID riid, void **ppv) + { + CComPtr pDisp; + HRESULT hr = Instance.get_Application(&pDisp); + return SUCCEEDED(hr) ? CreateInstance(pidl, pDisp, riid, ppv) : hr; + } + DECLARE_NOT_AGGREGATABLE(CFolder) DECLARE_PROTECT_FINAL_CONSTRUCT() diff --git a/dll/win32/shell32/CFolderItemVerbs.cpp b/dll/win32/shell32/CFolderItemVerbs.cpp index 09be5abb458..6389e9b8d29 100644 --- a/dll/win32/shell32/CFolderItemVerbs.cpp +++ b/dll/win32/shell32/CFolderItemVerbs.cpp @@ -89,21 +89,27 @@ CFolderItemVerbs::~CFolderItemVerbs() DestroyMenu(m_menu); } -HRESULT CFolderItemVerbs::Init(LPCITEMIDLIST idlist) +HRESULT CFolderItemVerbs::Init(IContextMenu &cm) { - HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, idlist, IID_PPV_ARG(IContextMenu, &m_contextmenu)); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - + m_contextmenu = &cm; m_menu = CreatePopupMenu(); - hr = m_contextmenu->QueryContextMenu(m_menu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL); - if (!SUCCEEDED(hr)) + HRESULT hr = m_contextmenu->QueryContextMenu(m_menu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL); + if (FAILED(hr)) return hr; m_count = GetMenuItemCount(m_menu); return hr; } +HRESULT CFolderItemVerbs::Init(LPCITEMIDLIST idlist) +{ + CComPtr pCM; + HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, idlist, IID_PPV_ARG(IContextMenu, &pCM)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + return Init(*static_cast(pCM)); +} + // *** FolderItemVerbs methods *** HRESULT STDMETHODCALLTYPE CFolderItemVerbs::get_Count(LONG *plCount) @@ -146,13 +152,11 @@ HRESULT STDMETHODCALLTYPE CFolderItemVerbs::Item(VARIANT indexVar, FolderItemVer return E_INVALIDARG; int index = V_I4(&var); - if (index > m_count) - return S_OK; + return S_FALSE; BSTR name = NULL; - - if(index == m_count) + if (index == m_count) { name = SysAllocStringLen(NULL, 0); } diff --git a/dll/win32/shell32/CFolderItemVerbs.h b/dll/win32/shell32/CFolderItemVerbs.h index ea96ba09827..20aab079775 100644 --- a/dll/win32/shell32/CFolderItemVerbs.h +++ b/dll/win32/shell32/CFolderItemVerbs.h @@ -67,6 +67,7 @@ public: CFolderItemVerbs(); virtual ~CFolderItemVerbs(); + HRESULT Init(IContextMenu &cm); HRESULT Init(LPCITEMIDLIST idlist); // *** FolderItemVerbs methods *** diff --git a/dll/win32/shell32/CFolderItems.cpp b/dll/win32/shell32/CFolderItems.cpp index e9a8a73390d..a75b81bd9a2 100644 --- a/dll/win32/shell32/CFolderItems.cpp +++ b/dll/win32/shell32/CFolderItems.cpp @@ -10,6 +10,72 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); +HRESULT SHELL_InvokeCommandOnContextMenu(_In_opt_ HWND hWnd, _In_ IContextMenu *pCM, _In_opt_ PCWSTR pszVerb, _In_ UINT cVerbs, + _In_opt_ PCWSTR pszArgs, _In_ UINT fCMIC, _In_ UINT fCMF, _In_opt_ IUnknown *pSite) +{ + // Note: We can't use SHLWAPI::SHInvokeCommandOnContextMenu because it does not have an arguments parameter + if (!pCM) + return E_INVALIDARG; + + HRESULT hr = S_OK; + int iDefItem = 0; + HMENU hMenu = NULL; + HCURSOR hOldCursor = SetCursor(LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_WAIT))); + CMINVOKECOMMANDINFOEX ici = { sizeof(ici), fCMIC, hWnd, NULL, NULL, NULL, SW_SHOWNORMAL }; + CHAR szVerb[MAX_PATH], szArgs[MAX_PATH * 3]; + + if (pSite) + IUnknown_SetSite(pCM, pSite); + + if (IS_INTRESOURCE(pszVerb)) + { + ici.lpVerb = MAKEINTRESOURCEA(pszVerb); + if (!cVerbs) + { + hMenu = CreatePopupMenu(); + if (hMenu) + { + hr = pCM->QueryContextMenu(hMenu, 0, 1, MAXSHORT, fCMF | CMF_DEFAULTONLY); + if ((iDefItem = GetMenuDefaultItem(hMenu, 0, 0)) != -1) + ici.lpVerb = MAKEINTRESOURCEA(iDefItem - 1); + } + } + ici.lpVerbW = MAKEINTRESOURCEW(ici.lpVerb); + } + else + { + ici.fMask |= CMIC_MASK_UNICODE; + ici.lpVerbW = pszVerb; + if (pszVerb && SHUnicodeToAnsi(pszVerb, szVerb, _countof(szVerb))) + ici.lpVerb = szVerb; + } + + if (pszArgs) + { + ici.fMask |= CMIC_MASK_UNICODE; + ici.lpParametersW = pszArgs; + if (pszArgs && SHUnicodeToAnsi(pszArgs, szArgs, _countof(szArgs))) + ici.lpParameters = szArgs; + } + + SetCursor(hOldCursor); + + if (!FAILED_UNEXPECTEDLY(hr) && (iDefItem != -1 || ici.lpVerbW)) + hr = pCM->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici); + if (pSite) + IUnknown_SetSite(pCM, NULL); + if (hMenu) + DestroyMenu(hMenu); + return hr; +} + +static inline HRESULT GetUIObjectOfFolderItems(FolderItems *pFI, REFIID riid, void **ppv) +{ + VARIANT v; + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = static_cast(pFI); + return CFolder::GetUIObjectFromVariant(v, riid, ppv); +} CFolderItem::CFolderItem() { @@ -21,11 +87,8 @@ CFolderItem::~CFolderItem() HRESULT CFolderItem::Initialize(Folder* folder, LPCITEMIDLIST idlist) { - m_idlist.Attach(ILClone(idlist)); - if (!m_idlist) - return E_OUTOFMEMORY; m_Folder = folder; - return S_OK; + return SHILClone(idlist, &m_idlist); } inline HRESULT CFolderItem::GetParentShellFolderAndItem(REFIID riid, void**ppv, PCUITEMID_CHILD &pidlLast) @@ -33,41 +96,32 @@ inline HRESULT CFolderItem::GetParentShellFolderAndItem(REFIID riid, void**ppv, return SHBindToParent(GetAbsoluteIDList(), riid, ppv, &pidlLast); } -LPCITEMIDLIST CFolderItem::GetInternalPidlRef(IUnknown *pUnk) -{ - LPCITEMIDLIST pidl = NULL; - FolderItem2 *pFI2; - if (pUnk && SUCCEEDED(pUnk->QueryInterface(IID_PPV_ARG(FolderItem2, &pFI2)))) - { - // This assumes we are the only implementer of CFolderItem (probably true) - // but when we get IParentAndItem we can do this in a safer way - pidl = static_cast(pFI2)->m_idlist; - pFI2->Release(); - } - return pidl; -} - -LPCITEMIDLIST CFolderItem::GetInternalPidlRef(const VARIANT *pV) +HRESULT CFolderItem::GetParentAndItem(const VARIANT *pV, IParentAndItem **ppPAI) { if (!pV) - return NULL; - - if (V_VT(pV) == (VT_VARIANT | VT_BYREF) && V_VARIANTREF(pV)) - pV = V_VARIANTREF(pV); + return E_POINTER; + pV = VariantDerefVariant(pV); + IUnknown *pUnk = NULL; switch (V_VT(pV)) { case VT_DISPATCH | VT_BYREF: - return V_DISPATCHREF(pV) ? GetInternalPidlRef(*V_DISPATCHREF(pV)) : NULL; + pUnk = V_DISPATCHREF(pV) ? *V_DISPATCHREF(pV) : NULL; + break; case VT_DISPATCH: - return GetInternalPidlRef(V_DISPATCH(pV)); + pUnk = V_DISPATCH(pV); + break; } - return NULL; + return pUnk ? pUnk->QueryInterface(IID_PPV_ARG(IParentAndItem, ppPAI)) : E_INVALIDARG; } -PCUITEMID_CHILD CFolderItem::GetLeafPidlRef(const VARIANT *pV) +PITEMID_CHILD CFolderItem::CloneLeafPidl(const VARIANT *pV) { - return (PCUITEMID_CHILD)ILFindLastID(GetInternalPidlRef(pV)); + CComPtr pPAI; + PITEMID_CHILD pidl; + if (SUCCEEDED(GetParentAndItem(pV, &pPAI)) && SUCCEEDED(pPAI->GetParentAndItem(NULL, NULL, &pidl))) + return pidl; + return NULL; } HRESULT CFolderItem::GetFindDataFromIDList(WIN32_FIND_DATA &wfd) @@ -164,7 +218,7 @@ HRESULT STDMETHODCALLTYPE CFolderItem::get_GetLink(IDispatch **ppid) HRESULT STDMETHODCALLTYPE CFolderItem::get_GetFolder(IDispatch **ppid) { - return ShellObjectCreatorInit(const_cast(GetAbsoluteIDList()), IID_PPV_ARG(IDispatch, ppid)); + return CFolder::CreateInstance(GetAbsoluteIDList(), *static_cast(m_Folder), IID_PPV_ARG(IDispatch, ppid)); } HRESULT CFolderItem::HasAttribute(DWORD sfgaof, VARIANT_BOOL *pB) @@ -280,18 +334,17 @@ HRESULT STDMETHODCALLTYPE CFolderItem::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs { TRACE("(%p, %s)\n", this, wine_dbgstr_variant(&vVerb)); - SHELLEXECUTEINFOW sei; - sei.cbSize = sizeof(sei); - sei.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI; - sei.hwnd = GetHwnd(); - sei.lpVerb = V_VT(&vVerb) == VT_BSTR ? V_BSTR(&vVerb) : NULL; - sei.lpFile = NULL; - sei.lpParameters = V_VT(&vArgs) == VT_BSTR ? V_BSTR(&vArgs) : NULL; - sei.lpDirectory = NULL; - sei.nShow = SW_SHOW; - sei.lpIDList = const_cast(GetAbsoluteIDList()); - ShellExecuteExW(&sei); - return S_OK; + HWND hWnd = GetHwnd(); + CComPtr psf; + PCUITEMID_CHILD pidlItem; + HRESULT hr = GetParentShellFolderAndItem(IID_PPV_ARG(IShellFolder, &psf), pidlItem); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + CComPtr pCM; + if (SUCCEEDED(hr = psf->GetUIObjectOf(hWnd, 1, &pidlItem, IID_NULL_PPV_ARG(IContextMenu, &pCM)))) + hr = CFolderItems::InvokeVerbHelper(hWnd, *pCM, vVerb, vArgs, GetSite()); + return hr; } HRESULT CFolderItem::GetExtendedProperty(REFPROPERTYKEY pkey, VARIANT *pv) @@ -307,6 +360,18 @@ HRESULT STDMETHODCALLTYPE CFolderItem::ExtendedProperty(BSTR bsPropName, VARIANT if (!pv) return E_INVALIDARG; + if (!lstrcmpiW(bsPropName, L"InfoTip")) + { + VARIANT v; + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = static_cast(this); + if (SUCCEEDED(m_Folder->GetDetailsOf(v, CFolder::INFOTIPCOLUMN, &V_BSTR(pv)))) + { + V_VT(pv) = VT_BSTR; + return S_OK; + } + } + PROPERTYKEY pkeybuf; const PROPERTYKEY *pPK = SHELL_GetPropertyKeyFromString(bsPropName, &pkeybuf); if (pPK && GetExtendedProperty(*pPK, pv) == S_OK) @@ -316,6 +381,40 @@ HRESULT STDMETHODCALLTYPE CFolderItem::ExtendedProperty(BSTR bsPropName, VARIANT return S_FALSE; } +HRESULT STDMETHODCALLTYPE CFolderItem::GetParentAndItem(PIDLIST_ABSOLUTE *ppidlParent, IShellFolder **ppsf, PITEMID_CHILD *ppidlChild) +{ + if (ppidlParent) + *ppidlParent = NULL; + if (ppsf) + *ppsf = NULL; + if (ppidlChild) + *ppidlChild = NULL; + + HRESULT hr = S_FALSE; + CComPtr psf; + PCUITEMID_CHILD pidlChild; + if (ppsf || ppidlChild) + { + if (FAILED(hr = GetParentShellFolderAndItem(IID_PPV_ARG(IShellFolder, &psf), pidlChild))) + return hr; + } + + if (ppidlParent && FAILED(hr = SHILCloneParent(GetAbsoluteIDList(), ppidlParent))) + return hr; + if (ppidlChild && FAILED(hr = SHILClone(pidlChild, ppidlChild))) + { + if (ppidlParent) + { + ILFree(*ppidlParent); + *ppidlParent = NULL; + } + return hr; + } + if (ppsf) + *ppsf = psf.Detach(); + return hr; +} + CFolderItems::CFolderItems() :m_Count(-1) @@ -324,39 +423,71 @@ CFolderItems::CFolderItems() CFolderItems::~CFolderItems() { + SysFreeString(m_bstrFilter); } HRESULT CFolderItems::Initialize(LPCITEMIDLIST idlist, Folder* parent) { - CComPtr psfDesktop, psfTarget; - - m_idlist.Attach(ILClone(idlist)); - if (!m_idlist) - return E_OUTOFMEMORY; - - HRESULT hr = SHGetDesktopFolder(&psfDesktop); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - hr = psfDesktop->BindToObject(m_idlist, NULL, IID_PPV_ARG(IShellFolder, &psfTarget)); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - hr = psfTarget->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &m_EnumIDList); - - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - m_Folder = parent; + return SHILClone(idlist, &m_idlist); +} + +void CFolderItems::ResetEnum() +{ + m_EnumIDList = NULL; + m_Count = -1; +} + +BOOL CFolderItems::IncludeItem(LPCITEMIDLIST pidl) +{ + if (!m_bstrFilter) + return TRUE; + + CComHeapPtr pidlFull; + if (FAILED(SHILCombine(m_idlist, pidl, &pidlFull))) + return FALSE; + CComHeapPtr pszPath; + if (FAILED(SHELL_DisplayNameOf(NULL, pidlFull, SHGDN_FORPARSING | SHGDN_INFOLDER, &pszPath))) + return FALSE; + return PathMatchSpecW(pszPath, m_bstrFilter); +} + +HRESULT CALLBACK CFolderItems::ItemsEnumFilter(void *Cookie, LPCITEMIDLIST pidl) +{ + return ((CFolderItems*)Cookie)->IncludeItem(pidl) ? S_OK : S_FALSE; +} + +HRESULT CFolderItems::EnumObjects() +{ + if (m_EnumIDList) + return S_OK; + + CComPtr psf; + HRESULT hr = SHBindToObject(NULL, m_idlist, NULL, IID_PPV_ARG(IShellFolder, &psf)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + CComPtr pEnum; + if (FAILED(hr = psf->EnumObjects(NULL, m_Contf, &pEnum))) + return hr; + hr = pEnum ? S_OK : E_UNEXPECTED; + if (SUCCEEDED(hr) && m_bstrFilter) + { + CComPtr pFilteredEnum; + hr = CEnumIDListBase::CreateInstance(*pEnum, ItemsEnumFilter, this, &pFilteredEnum); + if (SUCCEEDED(hr)) + pEnum = pFilteredEnum; + } + + if (FAILED(hr)) + return hr; + m_EnumIDList = pEnum; return S_OK; } // *** FolderItems methods *** HRESULT STDMETHODCALLTYPE CFolderItems::get_Count(long *plCount) { - if (!m_EnumIDList) - return E_FAIL; - if (!plCount) return E_POINTER; @@ -364,12 +495,14 @@ HRESULT STDMETHODCALLTYPE CFolderItems::get_Count(long *plCount) { long count = 0; + if (FAILED(EnumObjects())) + return E_FAIL; HRESULT hr = m_EnumIDList->Reset(); if (FAILED_UNEXPECTEDLY(hr)) return hr; CComHeapPtr Pidl; - while ((hr = m_EnumIDList->Next(1, &Pidl, 0)) != S_FALSE) + while ((hr = GetNext(&Pidl)) == S_OK) { count++; Pidl.Free(); @@ -402,9 +535,6 @@ HRESULT STDMETHODCALLTYPE CFolderItems::Item(VARIANT var, FolderItem **ppid) CComVariant index; HRESULT hr; - if (!m_EnumIDList) - return E_FAIL; - hr = VariantCopyInd(&index, &var); if (FAILED(hr)) return hr; @@ -414,6 +544,9 @@ HRESULT STDMETHODCALLTYPE CFolderItems::Item(VARIANT var, FolderItem **ppid) if (V_VT(&index) == VT_I4) { + if (FAILED(EnumObjects())) + return E_FAIL; + ULONG count = V_UI4(&index); hr = m_EnumIDList->Reset(); @@ -425,11 +558,17 @@ HRESULT STDMETHODCALLTYPE CFolderItems::Item(VARIANT var, FolderItem **ppid) if (FAILED_UNEXPECTEDLY(hr)) return hr; - CComHeapPtr spPidl; - hr = m_EnumIDList->Next(1, &spPidl, 0); + CComHeapPtr pidlChild; + hr = GetNext(&pidlChild); if (FAILED_UNEXPECTEDLY(hr)) return hr; - hr = ShellObjectCreatorInit(m_Folder, static_cast(spPidl), IID_PPV_ARG(FolderItem, ppid)); + if (hr != S_OK) + return E_INVALIDARG; + + CComHeapPtr pidlFull; + if (FAILED_UNEXPECTEDLY(hr = SHILCombine(m_idlist, pidlChild, &pidlFull))) + return hr; + hr = ShellObjectCreatorInit(m_Folder, pidlFull, IID_PPV_ARG(FolderItem, ppid)); if (FAILED_UNEXPECTEDLY(hr)) return hr; return hr; @@ -454,3 +593,55 @@ HRESULT STDMETHODCALLTYPE CFolderItems::_NewEnum(IUnknown **ppunk) return ShellObjectCreatorInit(static_cast(m_idlist), m_Folder, IID_FolderItems, reinterpret_cast(ppunk)); } +HRESULT STDMETHODCALLTYPE CFolderItems::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs) +{ + CComPtr pCM; + HRESULT hr = GetUIObjectOfFolderItems(this, IID_PPV_ARG(IContextMenu, &pCM)); + if (FAILED(hr)) + return hr == HRESULT_FROM_WIN32(ERROR_NO_DATA) ? S_FALSE : hr; + return InvokeVerbHelper(GetHwnd(), *pCM, vVerb, vArgs, GetSite()); +} + +HRESULT STDMETHODCALLTYPE CFolderItems::Filter(LONG grfFlags, BSTR bstrFilter) +{ + if (bstrFilter) + { + if (!*bstrFilter) + bstrFilter = NULL; + else if ((bstrFilter = SysAllocString(bstrFilter)) == NULL) + return E_OUTOFMEMORY; + } + ResetEnum(); + SysFreeString(m_bstrFilter); + m_bstrFilter = bstrFilter; + m_Contf = grfFlags; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CFolderItems::get_Verbs(FolderItemVerbs **ppfic) +{ + if (!ppfic) + return E_POINTER; + + CComPtr pVerbs; + HRESULT hr = CFolderItemVerbs::CreateInstance(pVerbs); + if (FAILED(hr)) + return hr; + long count; + if (SUCCEEDED(hr = get_Count(&count)) && count) + { + CComPtr pCM; + if (SUCCEEDED(hr = GetUIObjectOfFolderItems(this, IID_PPV_ARG(IContextMenu, &pCM)))) + hr = pVerbs->Init(*static_cast(pCM)); + } + *ppfic = pVerbs.Detach(); + return S_OK; +} + +HRESULT CFolderItems::InvokeVerbHelper(HWND hWnd, IContextMenu &cm, VARIANT &vVerb, VARIANT &vArgs, IUnknown *pSite) +{ + PCWSTR pszVerb = V_VT(&vVerb) == VT_BSTR && !StrIsNullOrEmpty(V_BSTR(&vVerb)) ? V_BSTR(&vVerb) : NULL; + PCWSTR pszArgs = V_VT(&vArgs) == VT_BSTR && !StrIsNullOrEmpty(V_BSTR(&vArgs)) ? V_BSTR(&vArgs) : NULL; + HRESULT hr = SHELL_InvokeCommandOnContextMenu(hWnd, &cm, pszVerb, !!pszVerb, pszArgs, 0, 0, pSite); + return SUCCEEDED(hr) ? hr : S_FALSE; +} diff --git a/dll/win32/shell32/CFolderItems.h b/dll/win32/shell32/CFolderItems.h index 05d5ac7a562..a654e91f029 100644 --- a/dll/win32/shell32/CFolderItems.h +++ b/dll/win32/shell32/CFolderItems.h @@ -12,7 +12,8 @@ class CFolderItem: public CComCoClass, public CComObjectRootEx, - public IDispatchImpl + public IDispatchImpl, + public IParentAndItem { private: CComHeapPtr m_idlist; @@ -20,9 +21,6 @@ private: inline HRESULT GetParentShellFolderAndItem(REFIID riid, void**ppv, PCUITEMID_CHILD &pidlLast); - static LPCITEMIDLIST GetInternalPidlRef(IUnknown *pUnk); - static LPCITEMIDLIST GetInternalPidlRef(const VARIANT *pV); - public: CFolderItem(); ~CFolderItem(); @@ -30,11 +28,13 @@ public: HRESULT Initialize(Folder* folder, LPCITEMIDLIST idlist); LPCITEMIDLIST GetAbsoluteIDList() { return m_idlist; } HWND GetHwnd() { return NULL; } + IUnknown* GetSite() { return NULL; } HRESULT GetFindDataFromIDList(WIN32_FIND_DATA &wfd); HRESULT HasAttribute(DWORD sfgaof, VARIANT_BOOL *pB); HRESULT GetExtendedProperty(REFPROPERTYKEY pkey, VARIANT *pv); - static PCUITEMID_CHILD GetLeafPidlRef(const VARIANT *pV); + static HRESULT GetParentAndItem(const VARIANT *pV, IParentAndItem **ppPAI); + static PITEMID_CHILD CloneLeafPidl(const VARIANT *pV); // *** FolderItem methods *** STDMETHOD(get_Application)(IDispatch **ppid) override; @@ -59,6 +59,10 @@ public: STDMETHOD(InvokeVerbEx)(VARIANT vVerb, VARIANT vArgs) override; STDMETHOD(ExtendedProperty)(BSTR bsPropName, VARIANT *pv) override; + // *** IParentAndItem *** + STDMETHOD(SetParentAndItem)(PCIDLIST_ABSOLUTE, IShellFolder*, PCUITEMID_CHILD) override { return E_NOTIMPL; } + STDMETHOD(GetParentAndItem)(PIDLIST_ABSOLUTE *ppidlParent, IShellFolder **ppsf, PITEMID_CHILD *ppidlChild) override; + DECLARE_NOT_AGGREGATABLE(CFolderItem) DECLARE_PROTECT_FINAL_CONSTRUCT() @@ -66,26 +70,37 @@ BEGIN_COM_MAP(CFolderItem) COM_INTERFACE_ENTRY_IID(IID_FolderItem, FolderItem) COM_INTERFACE_ENTRY_IID(IID_FolderItem2, FolderItem2) COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispatch) + COM_INTERFACE_ENTRY_IID(IID_IParentAndItem, IParentAndItem) END_COM_MAP() }; class CFolderItems: public CComCoClass, public CComObjectRootEx, - public IDispatchImpl + public IDispatchImpl { private: CComHeapPtr m_idlist; CComPtr m_EnumIDList; CComPtr m_Folder; long m_Count; + LONG m_Contf = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS; + BSTR m_bstrFilter = NULL; + + void ResetEnum(); + BOOL IncludeItem(LPCITEMIDLIST pidl); + static HRESULT CALLBACK ItemsEnumFilter(void *Cookie, LPCITEMIDLIST pidl); + HRESULT EnumObjects(); + HRESULT GetNext(LPITEMIDLIST *ppidl) { return m_EnumIDList->Next(1, ppidl, NULL); } public: CFolderItems(); ~CFolderItems(); - // Please note: CFolderItems takes ownership of idlist. HRESULT Initialize(LPCITEMIDLIST idlist, Folder* parent); + HWND GetHwnd() { return NULL; } + IUnknown* GetSite() { return NULL; } + static HRESULT InvokeVerbHelper(HWND hWnd, IContextMenu &cm, VARIANT &vVerb, VARIANT &vArgs, IUnknown *pSite); // *** FolderItems methods *** STDMETHOD(get_Count)(long *plCount) override; @@ -93,12 +108,19 @@ public: STDMETHOD(get_Parent)(IDispatch **ppid) override; STDMETHOD(Item)(VARIANT index, FolderItem **ppid) override; STDMETHOD(_NewEnum)(IUnknown **ppunk) override; + // *** FolderItems2 methods *** + STDMETHOD(InvokeVerbEx)(VARIANT vVerb, VARIANT vArgs) override; + // *** FolderItems3 methods *** + STDMETHOD(Filter)(LONG grfFlags, BSTR bstrFilter) override; + STDMETHOD(get_Verbs)(FolderItemVerbs **ppfic) override; DECLARE_NOT_AGGREGATABLE(CFolderItems) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CFolderItems) COM_INTERFACE_ENTRY_IID(IID_FolderItems, FolderItems) + COM_INTERFACE_ENTRY_IID(IID_FolderItems, FolderItems2) + COM_INTERFACE_ENTRY_IID(IID_FolderItems, FolderItems3) COM_INTERFACE_ENTRY_IID(IID_IDispatch, IDispatch) END_COM_MAP() }; diff --git a/dll/win32/shell32/CShellDispatch.cpp b/dll/win32/shell32/CShellDispatch.cpp index 0bc8539cdcb..81eef447893 100644 --- a/dll/win32/shell32/CShellDispatch.cpp +++ b/dll/win32/shell32/CShellDispatch.cpp @@ -82,7 +82,7 @@ HRESULT STDMETHODCALLTYPE CShellDispatch::NameSpace(VARIANT vDir, Folder **ppsdf if (!SUCCEEDED(hr)) return S_FALSE; - return ShellObjectCreatorInit(static_cast(idlist), IID_PPV_ARG(Folder, ppsdf)); + return CFolder::CreateInstance(idlist, this, IID_PPV_ARG(Folder, ppsdf)); } static BOOL is_optional_argument(const VARIANT *arg) @@ -110,7 +110,7 @@ HRESULT STDMETHODCALLTYPE CShellDispatch::BrowseForFolder(LONG Hwnd, BSTR Title, if (!selection) return S_FALSE; - return ShellObjectCreatorInit(static_cast(selection), IID_PPV_ARG(Folder, ppsdf)); + return CFolder::CreateInstance(selection, this, IID_PPV_ARG(Folder, ppsdf)); } HRESULT STDMETHODCALLTYPE CShellDispatch::Windows(IDispatch **ppid) diff --git a/dll/win32/shell32/prop.cpp b/dll/win32/shell32/prop.cpp index 68da3553fa5..b297062c758 100644 --- a/dll/win32/shell32/prop.cpp +++ b/dll/win32/shell32/prop.cpp @@ -78,3 +78,18 @@ VariantToIdlist(_In_ VARIANT *pV, _Out_ LPITEMIDLIST *ppidl) } return hr; } + +HRESULT +VariantQueryInterface(_In_ VARIANT *pV, _In_ REFIID riid, _Out_ void **ppv) +{ + pV = VariantDerefVariant(pV); + switch (V_VT(pV)) + { + case VT_DISPATCH | VT_BYREF: + return V_DISPATCHREF(pV) && *V_DISPATCHREF(pV) ? (*V_DISPATCHREF(pV))->QueryInterface(riid, ppv) : E_UNEXPECTED; + case VT_DISPATCH: + case VT_UNKNOWN: + return V_UNKNOWN(pV) ? V_UNKNOWN(pV)->QueryInterface(riid, ppv) : E_UNEXPECTED; + } + return E_FAIL; +} diff --git a/dll/win32/shell32/prop.h b/dll/win32/shell32/prop.h index d7921831bbb..ef0a02c2f52 100644 --- a/dll/win32/shell32/prop.h +++ b/dll/win32/shell32/prop.h @@ -32,5 +32,15 @@ DEFINE_SHELL32PROPERTYKEY(PKEYSHELL32_Comments, PSGUID_SUMMARYINFORMATION, PIDSI const PROPERTYKEY* SHELL_GetPropertyKeyFromString(_In_ PCWSTR pszString, _Out_ PROPERTYKEY *pkey); +static inline VARIANT* +VariantDerefVariant(_In_ const VARIANT *pV) +{ + if (V_VT(pV) == (VT_BYREF | VT_VARIANT) && V_VARIANTREF(pV)) + return V_VARIANTREF(pV); + return (VARIANT*)pV; +} + HRESULT VariantToIdlist(_In_ VARIANT *pV, _Out_ LPITEMIDLIST *ppidl); +HRESULT +VariantQueryInterface(_In_ VARIANT *pV, _In_ REFIID riid, _Out_ void **ppv); diff --git a/dll/win32/shell32/shlfolder.cpp b/dll/win32/shell32/shlfolder.cpp index 932bfae044d..dbe8d9a7383 100644 --- a/dll/win32/shell32/shlfolder.cpp +++ b/dll/win32/shell32/shlfolder.cpp @@ -597,7 +597,7 @@ SHOpenFolderAndSelectItems(PCIDLIST_ABSOLUTE pidlFolder, } else { - HRESULT hr = SHILCombine(pidlFolder, apidl[0], &pidlItem); + HRESULT hr = SHILCombine(pidlFolder, apidl[0], const_cast(&pidlItem)); if (FAILED_UNEXPECTEDLY(hr)) return hr; freeItem.Attach(const_cast(pidlItem)); diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp index cad6fa4e181..cf68e329ccf 100644 --- a/dll/win32/shell32/utils.cpp +++ b/dll/win32/shell32/utils.cpp @@ -211,20 +211,6 @@ CStubWindow32::CreateStub(UINT Type, LPCWSTR Path, const POINT *pPt) return S_OK; } -HRESULT -SHILClone( - _In_opt_ LPCITEMIDLIST pidl, - _Outptr_ LPITEMIDLIST *ppidl) -{ - if (!pidl) - { - *ppidl = NULL; - return S_OK; - } - *ppidl = ILClone(pidl); - return (*ppidl ? S_OK : E_OUTOFMEMORY); -} - BOOL PathIsDotOrDotDotW(_In_ LPCWSTR pszPath) { if (pszPath[0] != L'.') diff --git a/dll/win32/shlwapi/utils.cpp b/dll/win32/shlwapi/utils.cpp index a9a828e561d..33fe26c03ed 100644 --- a/dll/win32/shlwapi/utils.cpp +++ b/dll/win32/shlwapi/utils.cpp @@ -343,7 +343,7 @@ SHInvokeCommandOnContextMenuInternal( { if (GetVersionMajorMinor() >= _WIN32_WINNT_WIN7) { - info.fMask |= CMF_OPTIMIZEFORINVOKE; + fCMF |= CMF_OPTIMIZEFORINVOKE; } if (pszVerb && SHAnsiToUnicode(pszVerb, wideverb, _countof(wideverb))) { diff --git a/sdk/include/psdk/shobjidl.idl b/sdk/include/psdk/shobjidl.idl index bf9215463da..d9086b6b906 100644 --- a/sdk/include/psdk/shobjidl.idl +++ b/sdk/include/psdk/shobjidl.idl @@ -359,6 +359,20 @@ interface IShellFolder2 : IShellFolder HRESULT MapColumnToSCID( [in] UINT iColumn, [in] SHCOLUMNID *pscid ); } +/***************************************************************************** + * IParentAndItem interface + */ +[ + object, + uuid(b3a4b685-b685-4805-99d9-5dead2873236), + pointer_default(unique) +] +interface IParentAndItem : IUnknown +{ + HRESULT SetParentAndItem([in] PCIDLIST_ABSOLUTE pidlParent, [in] IShellFolder*psf, [in] PCUITEMID_CHILD pidlChild); + HRESULT GetParentAndItem([out, optional] PIDLIST_ABSOLUTE *ppidlParent, [out, optional] IShellFolder **ppsf, [out, optional] PITEMID_CHILD *ppidlChild); +} + /***************************************************************************** * IShellItem interface */ @@ -481,6 +495,23 @@ interface IShellItem2 : IShellItem [out] BOOL *pf); } +/***************************************************************************** + * IRelatedItem interface + */ +[ + object, + uuid(a73ce67a-8ab1-44f1-8d43-d2fcbf6b1cd0), + pointer_default(unique) +] +interface IRelatedItem : IUnknown +{ + HRESULT GetItemIDList([out] PIDLIST_ABSOLUTE *ppidl); + HRESULT GetItem([out] IShellItem **ppsi); +} + +/***************************************************************************** + * INewWindowManager interface + */ typedef enum tagNWMF { NWMF_UNLOADING = 0x0001, NWMF_USERINITED = 0x0002, diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h index cb8b24053ce..70075fa97ba 100644 --- a/sdk/include/reactos/shellutils.h +++ b/sdk/include/reactos/shellutils.h @@ -459,23 +459,23 @@ HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, T3 initArg3, T4 } #endif // DECLARE_CLASSFACTORY (ATL) -template static HRESULT SHILClone(P pidl, R *ppOut) +static inline HRESULT SHILClone(LPCITEMIDLIST pidl, LPITEMIDLIST *ppOut) { - R r = *ppOut = (R)ILClone((PIDLIST_RELATIVE)pidl); + LPITEMIDLIST r = *ppOut = ILClone((PIDLIST_RELATIVE)pidl); return r ? S_OK : E_OUTOFMEMORY; } -template static HRESULT SHILCloneParent(P pidl, R *ppOut) +static inline HRESULT SHILCloneParent(LPCITEMIDLIST pidl, LPITEMIDLIST *ppOut) { - R r = *ppOut = (R)ILClone((PIDLIST_RELATIVE)pidl); + LPITEMIDLIST r = *ppOut = ILClone((PIDLIST_RELATIVE)pidl); if (r) ILRemoveLastID(r); // "c:\folder\thisitem" => "c:\folder" return r ? S_OK : E_OUTOFMEMORY; } -template static HRESULT SHILCombine(B base, PCUIDLIST_RELATIVE sub, R *ppOut) +static inline HRESULT SHILCombine(LPCITEMIDLIST base, PCUIDLIST_RELATIVE sub, LPITEMIDLIST *ppOut) { - R r = *ppOut = (R)ILCombine((PCIDLIST_ABSOLUTE)base, sub); + LPITEMIDLIST r = *ppOut = ILCombine((PCIDLIST_ABSOLUTE)base, sub); return r ? S_OK : E_OUTOFMEMORY; } @@ -919,7 +919,7 @@ static inline void DumpIdListOneLine(LPCITEMIDLIST pidl) { if (!depth) { - wsprintfA(buf, "%p [] (%s)\n", pidl, pidl ? "Empty/Desktop" : "NULL"); + wsprintfA(buf, "%p [] (%s)", pidl, pidl ? "Empty/Desktop" : "NULL"); OutputDebugStringA(buf); } break;