| /* | |
| * IShellItem and IShellItemArray implementations | |
| * | |
| * Copyright 2008 Vincent Povirk for CodeWeavers | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <stdio.h> | |
| #include <stdarg.h> | |
| #define COBJMACROS | |
| #define NONAMELESSUNION | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wine/debug.h" | |
| #include "pidl.h" | |
| #include "shell32_main.h" | |
| #include "debughlp.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(shell); | |
| typedef struct _ShellItem { | |
| IShellItem2 IShellItem2_iface; | |
| LONG ref; | |
| LPITEMIDLIST pidl; | |
| IPersistIDList IPersistIDList_iface; | |
| } ShellItem; | |
| typedef struct _CustomDestinationList { | |
| ICustomDestinationList ICustomDestinationList_iface; | |
| LONG ref; | |
| } CustomDestinationList; | |
| static inline ShellItem *impl_from_IShellItem2(IShellItem2 *iface) | |
| { | |
| return CONTAINING_RECORD(iface, ShellItem, IShellItem2_iface); | |
| } | |
| static inline ShellItem *impl_from_IPersistIDList( IPersistIDList *iface ) | |
| { | |
| return CONTAINING_RECORD(iface, ShellItem, IPersistIDList_iface); | |
| } | |
| static inline CustomDestinationList *impl_from_ICustomDestinationList( ICustomDestinationList *iface ) | |
| { | |
| return CONTAINING_RECORD(iface, CustomDestinationList, ICustomDestinationList_iface); | |
| } | |
| static HRESULT WINAPI ShellItem_QueryInterface(IShellItem2 *iface, REFIID riid, | |
| void **ppv) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), ppv); | |
| if (!ppv) return E_INVALIDARG; | |
| if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellItem, riid) || | |
| IsEqualIID(&IID_IShellItem2, riid)) | |
| { | |
| *ppv = &This->IShellItem2_iface; | |
| } | |
| else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistIDList, riid)) | |
| { | |
| *ppv = &This->IPersistIDList_iface; | |
| } | |
| else { | |
| FIXME("not implemented for %s\n", shdebugstr_guid(riid)); | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI ShellItem_AddRef(IShellItem2 *iface) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p), new refcount=%i\n", iface, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI ShellItem_Release(IShellItem2 *iface) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p), new refcount=%i\n", iface, ref); | |
| if (ref == 0) | |
| { | |
| ILFree(This->pidl); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| static HRESULT ShellItem_get_parent_pidl(ShellItem *This, LPITEMIDLIST *parent_pidl) | |
| { | |
| *parent_pidl = ILClone(This->pidl); | |
| if (*parent_pidl) | |
| { | |
| if (ILRemoveLastID(*parent_pidl)) | |
| return S_OK; | |
| else | |
| { | |
| ILFree(*parent_pidl); | |
| *parent_pidl = NULL; | |
| return E_INVALIDARG; | |
| } | |
| } | |
| else | |
| { | |
| *parent_pidl = NULL; | |
| return E_OUTOFMEMORY; | |
| } | |
| } | |
| static HRESULT ShellItem_get_parent_shellfolder(ShellItem *This, IShellFolder **ppsf) | |
| { | |
| LPITEMIDLIST parent_pidl; | |
| IShellFolder *desktop; | |
| HRESULT ret; | |
| ret = ShellItem_get_parent_pidl(This, &parent_pidl); | |
| if (SUCCEEDED(ret)) | |
| { | |
| ret = SHGetDesktopFolder(&desktop); | |
| if (SUCCEEDED(ret)) | |
| { | |
| if (_ILIsDesktop(parent_pidl)) | |
| { | |
| *ppsf = desktop; | |
| } | |
| else | |
| { | |
| ret = IShellFolder_BindToObject(desktop, parent_pidl, NULL, &IID_IShellFolder, (void**)ppsf); | |
| IShellFolder_Release(desktop); | |
| } | |
| } | |
| ILFree(parent_pidl); | |
| } | |
| return ret; | |
| } | |
| static HRESULT ShellItem_get_shellfolder(ShellItem *This, IBindCtx *pbc, IShellFolder **ppsf) | |
| { | |
| IShellFolder *desktop; | |
| HRESULT ret; | |
| ret = SHGetDesktopFolder(&desktop); | |
| if (SUCCEEDED(ret)) | |
| { | |
| if (_ILIsDesktop(This->pidl)) | |
| { | |
| *ppsf = desktop; | |
| IShellFolder_AddRef(*ppsf); | |
| } | |
| else | |
| { | |
| ret = IShellFolder_BindToObject(desktop, This->pidl, pbc, &IID_IShellFolder, (void**)ppsf); | |
| } | |
| IShellFolder_Release(desktop); | |
| } | |
| return ret; | |
| } | |
| static HRESULT WINAPI ShellItem_BindToHandler(IShellItem2 *iface, IBindCtx *pbc, | |
| REFGUID rbhid, REFIID riid, void **ppvOut) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| HRESULT ret; | |
| TRACE("(%p,%p,%s,%p,%p)\n", iface, pbc, shdebugstr_guid(rbhid), riid, ppvOut); | |
| *ppvOut = NULL; | |
| if (IsEqualGUID(rbhid, &BHID_SFObject)) | |
| { | |
| IShellFolder *psf; | |
| ret = ShellItem_get_shellfolder(This, pbc, &psf); | |
| if (SUCCEEDED(ret)) | |
| { | |
| ret = IShellFolder_QueryInterface(psf, riid, ppvOut); | |
| IShellFolder_Release(psf); | |
| } | |
| return ret; | |
| } | |
| else if (IsEqualGUID(rbhid, &BHID_SFUIObject)) | |
| { | |
| IShellFolder *psf_parent; | |
| if (_ILIsDesktop(This->pidl)) | |
| ret = SHGetDesktopFolder(&psf_parent); | |
| else | |
| ret = ShellItem_get_parent_shellfolder(This, &psf_parent); | |
| if (SUCCEEDED(ret)) | |
| { | |
| LPCITEMIDLIST pidl = ILFindLastID(This->pidl); | |
| ret = IShellFolder_GetUIObjectOf(psf_parent, NULL, 1, &pidl, riid, NULL, ppvOut); | |
| IShellFolder_Release(psf_parent); | |
| } | |
| return ret; | |
| } | |
| else if (IsEqualGUID(rbhid, &BHID_DataObject)) | |
| { | |
| return ShellItem_BindToHandler(&This->IShellItem2_iface, pbc, &BHID_SFUIObject, | |
| &IID_IDataObject, ppvOut); | |
| } | |
| FIXME("Unsupported BHID %s.\n", debugstr_guid(rbhid)); | |
| return MK_E_NOOBJECT; | |
| } | |
| static HRESULT WINAPI ShellItem_GetParent(IShellItem2 *iface, IShellItem **ppsi) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| LPITEMIDLIST parent_pidl; | |
| HRESULT ret; | |
| TRACE("(%p,%p)\n", iface, ppsi); | |
| ret = ShellItem_get_parent_pidl(This, &parent_pidl); | |
| if (SUCCEEDED(ret)) | |
| { | |
| ret = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi); | |
| ILFree(parent_pidl); | |
| } | |
| return ret; | |
| } | |
| static HRESULT WINAPI ShellItem_GetDisplayName(IShellItem2 *iface, SIGDN sigdnName, | |
| LPWSTR *ppszName) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| TRACE("(%p,%x,%p)\n", iface, sigdnName, ppszName); | |
| return SHGetNameFromIDList(This->pidl, sigdnName, ppszName); | |
| } | |
| static HRESULT WINAPI ShellItem_GetAttributes(IShellItem2 *iface, SFGAOF sfgaoMask, | |
| SFGAOF *psfgaoAttribs) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| IShellFolder *parent_folder; | |
| LPITEMIDLIST child_pidl; | |
| HRESULT ret; | |
| TRACE("(%p,%x,%p)\n", iface, sfgaoMask, psfgaoAttribs); | |
| if (_ILIsDesktop(This->pidl)) | |
| ret = SHGetDesktopFolder(&parent_folder); | |
| else | |
| ret = ShellItem_get_parent_shellfolder(This, &parent_folder); | |
| if (SUCCEEDED(ret)) | |
| { | |
| child_pidl = ILFindLastID(This->pidl); | |
| *psfgaoAttribs = sfgaoMask; | |
| ret = IShellFolder_GetAttributesOf(parent_folder, 1, (LPCITEMIDLIST*)&child_pidl, psfgaoAttribs); | |
| *psfgaoAttribs &= sfgaoMask; | |
| IShellFolder_Release(parent_folder); | |
| if (SUCCEEDED(ret)) | |
| { | |
| if(sfgaoMask == *psfgaoAttribs) | |
| return S_OK; | |
| else | |
| return S_FALSE; | |
| } | |
| } | |
| return ret; | |
| } | |
| static HRESULT WINAPI ShellItem_Compare(IShellItem2 *iface, IShellItem *oth, | |
| SICHINTF hint, int *piOrder) | |
| { | |
| LPWSTR dispname, dispname_oth; | |
| HRESULT ret; | |
| TRACE("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder); | |
| if(hint & (SICHINT_CANONICAL | SICHINT_ALLFIELDS)) | |
| FIXME("Unsupported flags 0x%08x\n", hint); | |
| ret = IShellItem2_GetDisplayName(iface, SIGDN_DESKTOPABSOLUTEEDITING, &dispname); | |
| if(SUCCEEDED(ret)) | |
| { | |
| ret = IShellItem_GetDisplayName(oth, SIGDN_DESKTOPABSOLUTEEDITING, &dispname_oth); | |
| if(SUCCEEDED(ret)) | |
| { | |
| *piOrder = lstrcmpiW(dispname, dispname_oth); | |
| CoTaskMemFree(dispname_oth); | |
| } | |
| CoTaskMemFree(dispname); | |
| } | |
| if(SUCCEEDED(ret) && *piOrder && | |
| (hint & SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL)) | |
| { | |
| LPWSTR dispname, dispname_oth; | |
| TRACE("Testing filesystem path.\n"); | |
| ret = IShellItem2_GetDisplayName(iface, SIGDN_FILESYSPATH, &dispname); | |
| if(SUCCEEDED(ret)) | |
| { | |
| ret = IShellItem_GetDisplayName(oth, SIGDN_FILESYSPATH, &dispname_oth); | |
| if(SUCCEEDED(ret)) | |
| { | |
| *piOrder = lstrcmpiW(dispname, dispname_oth); | |
| CoTaskMemFree(dispname_oth); | |
| } | |
| CoTaskMemFree(dispname); | |
| } | |
| } | |
| if(FAILED(ret)) | |
| return ret; | |
| if(*piOrder) | |
| return S_FALSE; | |
| else | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetPropertyStore(IShellItem2 *iface, GETPROPERTYSTOREFLAGS flags, | |
| REFIID riid, void **ppv) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%d, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetPropertyStoreWithCreateObject(IShellItem2 *iface, | |
| GETPROPERTYSTOREFLAGS flags, IUnknown *punkCreateObject, REFIID riid, void **ppv) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%08x, %p, %s, %p)\n", | |
| This, flags, punkCreateObject, shdebugstr_guid(riid), ppv); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetPropertyStoreForKeys(IShellItem2 *iface, const PROPERTYKEY *rgKeys, | |
| UINT cKeys, GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %d, %08x, %s, %p)\n", | |
| This, rgKeys, cKeys, flags, shdebugstr_guid(riid), ppv); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetPropertyDescriptionList(IShellItem2 *iface, | |
| REFPROPERTYKEY keyType, REFIID riid, void **ppv) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %s, %p)\n", This, keyType, debugstr_guid(riid), ppv); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_Update(IShellItem2 *iface, IBindCtx *pbc) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p)\n", This, pbc); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetProperty(IShellItem2 *iface, REFPROPERTYKEY key, PROPVARIANT *ppropvar) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %p)\n", This, key, ppropvar); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetCLSID(IShellItem2 *iface, REFPROPERTYKEY key, CLSID *pclsid) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %p)\n", This, key, pclsid); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetFileTime(IShellItem2 *iface, REFPROPERTYKEY key, FILETIME *pft) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %p)\n", This, key, pft); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetInt32(IShellItem2 *iface, REFPROPERTYKEY key, int *pi) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %p)\n", This, key, pi); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetString(IShellItem2 *iface, REFPROPERTYKEY key, LPWSTR *ppsz) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %p)\n", This, key, ppsz); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetUInt32(IShellItem2 *iface, REFPROPERTYKEY key, ULONG *pui) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %p)\n", This, key, pui); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetUInt64(IShellItem2 *iface, REFPROPERTYKEY key, ULONGLONG *pull) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %p)\n", This, key, pull); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI ShellItem2_GetBool(IShellItem2 *iface, REFPROPERTYKEY key, BOOL *pf) | |
| { | |
| ShellItem *This = impl_from_IShellItem2(iface); | |
| FIXME("Stub: %p (%p, %p)\n", This, key, pf); | |
| return E_NOTIMPL; | |
| } | |
| static const IShellItem2Vtbl ShellItem2_Vtbl = { | |
| ShellItem_QueryInterface, | |
| ShellItem_AddRef, | |
| ShellItem_Release, | |
| ShellItem_BindToHandler, | |
| ShellItem_GetParent, | |
| ShellItem_GetDisplayName, | |
| ShellItem_GetAttributes, | |
| ShellItem_Compare, | |
| ShellItem2_GetPropertyStore, | |
| ShellItem2_GetPropertyStoreWithCreateObject, | |
| ShellItem2_GetPropertyStoreForKeys, | |
| ShellItem2_GetPropertyDescriptionList, | |
| ShellItem2_Update, | |
| ShellItem2_GetProperty, | |
| ShellItem2_GetCLSID, | |
| ShellItem2_GetFileTime, | |
| ShellItem2_GetInt32, | |
| ShellItem2_GetString, | |
| ShellItem2_GetUInt32, | |
| ShellItem2_GetUInt64, | |
| ShellItem2_GetBool | |
| }; | |
| static HRESULT WINAPI ShellItem_IPersistIDList_QueryInterface(IPersistIDList *iface, | |
| REFIID riid, void **ppv) | |
| { | |
| ShellItem *This = impl_from_IPersistIDList(iface); | |
| return IShellItem2_QueryInterface(&This->IShellItem2_iface, riid, ppv); | |
| } | |
| static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface) | |
| { | |
| ShellItem *This = impl_from_IPersistIDList(iface); | |
| return IShellItem2_AddRef(&This->IShellItem2_iface); | |
| } | |
| static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface) | |
| { | |
| ShellItem *This = impl_from_IPersistIDList(iface); | |
| return IShellItem2_Release(&This->IShellItem2_iface); | |
| } | |
| static HRESULT WINAPI ShellItem_IPersistIDList_GetClassID(IPersistIDList* iface, | |
| CLSID *pClassID) | |
| { | |
| *pClassID = CLSID_ShellItem; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI ShellItem_IPersistIDList_SetIDList(IPersistIDList* iface, | |
| LPCITEMIDLIST pidl) | |
| { | |
| ShellItem *This = impl_from_IPersistIDList(iface); | |
| LPITEMIDLIST new_pidl; | |
| TRACE("(%p,%p)\n", This, pidl); | |
| new_pidl = ILClone(pidl); | |
| if (new_pidl) | |
| { | |
| ILFree(This->pidl); | |
| This->pidl = new_pidl; | |
| return S_OK; | |
| } | |
| else | |
| return E_OUTOFMEMORY; | |
| } | |
| static HRESULT WINAPI ShellItem_IPersistIDList_GetIDList(IPersistIDList* iface, | |
| LPITEMIDLIST *ppidl) | |
| { | |
| ShellItem *This = impl_from_IPersistIDList(iface); | |
| TRACE("(%p,%p)\n", This, ppidl); | |
| *ppidl = ILClone(This->pidl); | |
| if (*ppidl) | |
| return S_OK; | |
| else | |
| return E_OUTOFMEMORY; | |
| } | |
| static const IPersistIDListVtbl ShellItem_IPersistIDList_Vtbl = { | |
| ShellItem_IPersistIDList_QueryInterface, | |
| ShellItem_IPersistIDList_AddRef, | |
| ShellItem_IPersistIDList_Release, | |
| ShellItem_IPersistIDList_GetClassID, | |
| ShellItem_IPersistIDList_SetIDList, | |
| ShellItem_IPersistIDList_GetIDList | |
| }; | |
| HRESULT WINAPI IShellItem_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) | |
| { | |
| ShellItem *This; | |
| HRESULT ret; | |
| TRACE("(%p,%s)\n",pUnkOuter, debugstr_guid(riid)); | |
| *ppv = NULL; | |
| if (pUnkOuter) return CLASS_E_NOAGGREGATION; | |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem)); | |
| This->IShellItem2_iface.lpVtbl = &ShellItem2_Vtbl; | |
| This->ref = 1; | |
| This->pidl = NULL; | |
| This->IPersistIDList_iface.lpVtbl = &ShellItem_IPersistIDList_Vtbl; | |
| ret = IShellItem2_QueryInterface(&This->IShellItem2_iface, riid, ppv); | |
| IShellItem2_Release(&This->IShellItem2_iface); | |
| return ret; | |
| } | |
| HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent, | |
| IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi) | |
| { | |
| LPITEMIDLIST new_pidl; | |
| HRESULT ret; | |
| TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi); | |
| *ppsi = NULL; | |
| if (!pidl) | |
| { | |
| return E_INVALIDARG; | |
| } | |
| else if (pidlParent || psfParent) | |
| { | |
| LPITEMIDLIST temp_parent=NULL; | |
| if (!pidlParent) | |
| { | |
| IPersistFolder2* ppf2Parent; | |
| if (FAILED(IShellFolder_QueryInterface(psfParent, &IID_IPersistFolder2, (void**)&ppf2Parent))) | |
| { | |
| FIXME("couldn't get IPersistFolder2 interface of parent\n"); | |
| return E_NOINTERFACE; | |
| } | |
| if (FAILED(IPersistFolder2_GetCurFolder(ppf2Parent, &temp_parent))) | |
| { | |
| FIXME("couldn't get parent PIDL\n"); | |
| IPersistFolder2_Release(ppf2Parent); | |
| return E_NOINTERFACE; | |
| } | |
| pidlParent = temp_parent; | |
| IPersistFolder2_Release(ppf2Parent); | |
| } | |
| new_pidl = ILCombine(pidlParent, pidl); | |
| ILFree(temp_parent); | |
| if (!new_pidl) | |
| return E_OUTOFMEMORY; | |
| } | |
| else | |
| { | |
| new_pidl = ILClone(pidl); | |
| if (!new_pidl) | |
| return E_OUTOFMEMORY; | |
| } | |
| ret = SHCreateItemFromIDList(new_pidl, &IID_IShellItem, (void**)ppsi); | |
| ILFree(new_pidl); | |
| return ret; | |
| } | |
| HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath, | |
| IBindCtx *pbc, REFIID riid, void **ppv) | |
| { | |
| LPITEMIDLIST pidl; | |
| HRESULT ret; | |
| *ppv = NULL; | |
| ret = SHParseDisplayName(pszPath, pbc, &pidl, 0, NULL); | |
| if(SUCCEEDED(ret)) | |
| { | |
| ret = SHCreateItemFromIDList(pidl, riid, ppv); | |
| ILFree(pidl); | |
| } | |
| return ret; | |
| } | |
| HRESULT WINAPI SHCreateItemFromRelativeName(IShellItem *parent, PCWSTR name, IBindCtx *pbc, | |
| REFIID riid, void **ppv) | |
| { | |
| LPITEMIDLIST pidl_folder = NULL, pidl = NULL; | |
| IShellFolder *desktop = NULL, *folder = NULL; | |
| HRESULT hr; | |
| TRACE("(%p, %s, %p, %s, %p)\n", parent, wine_dbgstr_w(name), pbc, debugstr_guid(riid), ppv); | |
| if(!ppv) | |
| return E_INVALIDARG; | |
| *ppv = NULL; | |
| if(!name) | |
| return E_INVALIDARG; | |
| hr = SHGetIDListFromObject((IUnknown*)parent, &pidl_folder); | |
| if(hr != S_OK) | |
| return hr; | |
| hr = SHGetDesktopFolder(&desktop); | |
| if(hr != S_OK) | |
| goto cleanup; | |
| if(!_ILIsDesktop(pidl_folder)) | |
| { | |
| hr = IShellFolder_BindToObject(desktop, pidl_folder, NULL, &IID_IShellFolder, | |
| (void**)&folder); | |
| if(hr != S_OK) | |
| goto cleanup; | |
| } | |
| hr = IShellFolder_ParseDisplayName(folder ? folder : desktop, NULL, pbc, (LPWSTR)name, | |
| NULL, &pidl, NULL); | |
| if(hr != S_OK) | |
| goto cleanup; | |
| hr = SHCreateItemFromIDList(pidl, riid, ppv); | |
| cleanup: | |
| if(pidl_folder) | |
| ILFree(pidl_folder); | |
| if(pidl) | |
| ILFree(pidl); | |
| if(desktop) | |
| IShellFolder_Release(desktop); | |
| if(folder) | |
| IShellFolder_Release(folder); | |
| return hr; | |
| } | |
| HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv) | |
| { | |
| IPersistIDList *persist; | |
| HRESULT ret; | |
| if(!pidl) | |
| return E_INVALIDARG; | |
| *ppv = NULL; | |
| ret = IShellItem_Constructor(NULL, &IID_IPersistIDList, (void**)&persist); | |
| if(FAILED(ret)) | |
| return ret; | |
| ret = IPersistIDList_SetIDList(persist, pidl); | |
| if(FAILED(ret)) | |
| { | |
| IPersistIDList_Release(persist); | |
| return ret; | |
| } | |
| ret = IPersistIDList_QueryInterface(persist, riid, ppv); | |
| IPersistIDList_Release(persist); | |
| return ret; | |
| } | |
| HRESULT WINAPI SHCreateItemInKnownFolder(REFKNOWNFOLDERID rfid, DWORD flags, | |
| PCWSTR filename, REFIID riid, void **ppv) | |
| { | |
| HRESULT hr; | |
| IShellItem *parent = NULL; | |
| LPITEMIDLIST pidl = NULL; | |
| TRACE("(%p, %x, %s, %s, %p)\n", rfid, flags, wine_dbgstr_w(filename), | |
| debugstr_guid(riid), ppv); | |
| if(!rfid || !ppv) | |
| return E_INVALIDARG; | |
| *ppv = NULL; | |
| hr = SHGetKnownFolderIDList(rfid, flags, NULL, &pidl); | |
| if(hr != S_OK) | |
| return hr; | |
| hr = SHCreateItemFromIDList(pidl, &IID_IShellItem, (void**)&parent); | |
| if(hr != S_OK) | |
| { | |
| ILFree(pidl); | |
| return hr; | |
| } | |
| if(filename) | |
| hr = SHCreateItemFromRelativeName(parent, filename, NULL, riid, ppv); | |
| else | |
| hr = IShellItem_QueryInterface(parent, riid, ppv); | |
| ILFree(pidl); | |
| IShellItem_Release(parent); | |
| return hr; | |
| } | |
| HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj, | |
| DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv) | |
| { | |
| FORMATETC fmt; | |
| STGMEDIUM medium; | |
| HRESULT ret; | |
| TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(riid), ppv); | |
| if(!pdtobj) | |
| return E_INVALIDARG; | |
| fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); | |
| fmt.ptd = NULL; | |
| fmt.dwAspect = DVASPECT_CONTENT; | |
| fmt.lindex = -1; | |
| fmt.tymed = TYMED_HGLOBAL; | |
| ret = IDataObject_GetData(pdtobj, &fmt, &medium); | |
| if(SUCCEEDED(ret)) | |
| { | |
| LPIDA pida = GlobalLock(medium.u.hGlobal); | |
| if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) || | |
| pida->cidl == 1) | |
| { | |
| LPITEMIDLIST pidl; | |
| /* Get the first pidl (parent + child1) */ | |
| pidl = ILCombine((LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]), | |
| (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1])); | |
| ret = SHCreateItemFromIDList(pidl, riid, ppv); | |
| ILFree(pidl); | |
| } | |
| else | |
| { | |
| ret = E_FAIL; | |
| } | |
| GlobalUnlock(medium.u.hGlobal); | |
| GlobalFree(medium.u.hGlobal); | |
| } | |
| if(FAILED(ret) && !(dwFlags & DOGIF_NO_HDROP)) | |
| { | |
| TRACE("Attempting to fall back on CF_HDROP.\n"); | |
| fmt.cfFormat = CF_HDROP; | |
| fmt.ptd = NULL; | |
| fmt.dwAspect = DVASPECT_CONTENT; | |
| fmt.lindex = -1; | |
| fmt.tymed = TYMED_HGLOBAL; | |
| ret = IDataObject_GetData(pdtobj, &fmt, &medium); | |
| if(SUCCEEDED(ret)) | |
| { | |
| DROPFILES *df = GlobalLock(medium.u.hGlobal); | |
| LPBYTE files = (LPBYTE)df + df->pFiles; | |
| BOOL multiple_files = FALSE; | |
| ret = E_FAIL; | |
| if(!df->fWide) | |
| { | |
| WCHAR filename[MAX_PATH]; | |
| PCSTR first_file = (PCSTR)files; | |
| if(*(files + lstrlenA(first_file) + 1) != 0) | |
| multiple_files = TRUE; | |
| if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) ) | |
| { | |
| MultiByteToWideChar(CP_ACP, 0, first_file, -1, filename, MAX_PATH); | |
| ret = SHCreateItemFromParsingName(filename, NULL, riid, ppv); | |
| } | |
| } | |
| else | |
| { | |
| PCWSTR first_file = (PCWSTR)files; | |
| if(*((PCWSTR)files + lstrlenW(first_file) + 1) != 0) | |
| multiple_files = TRUE; | |
| if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) ) | |
| ret = SHCreateItemFromParsingName(first_file, NULL, riid, ppv); | |
| } | |
| GlobalUnlock(medium.u.hGlobal); | |
| GlobalFree(medium.u.hGlobal); | |
| } | |
| } | |
| if(FAILED(ret) && !(dwFlags & DOGIF_NO_URL)) | |
| { | |
| FIXME("Failed to create item, should try CF_URL.\n"); | |
| } | |
| return ret; | |
| } | |
| HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv) | |
| { | |
| LPITEMIDLIST pidl; | |
| HRESULT ret; | |
| ret = SHGetIDListFromObject(punk, &pidl); | |
| if(SUCCEEDED(ret)) | |
| { | |
| ret = SHCreateItemFromIDList(pidl, riid, ppv); | |
| ILFree(pidl); | |
| } | |
| return ret; | |
| } | |
| /************************************************************************* | |
| * IEnumShellItems implementation | |
| */ | |
| typedef struct { | |
| IEnumShellItems IEnumShellItems_iface; | |
| LONG ref; | |
| IShellItemArray *array; | |
| DWORD count; | |
| DWORD position; | |
| } IEnumShellItemsImpl; | |
| static inline IEnumShellItemsImpl *impl_from_IEnumShellItems(IEnumShellItems *iface) | |
| { | |
| return CONTAINING_RECORD(iface, IEnumShellItemsImpl, IEnumShellItems_iface); | |
| } | |
| static HRESULT WINAPI IEnumShellItems_fnQueryInterface(IEnumShellItems *iface, | |
| REFIID riid, | |
| void **ppvObject) | |
| { | |
| IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface); | |
| TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject); | |
| *ppvObject = NULL; | |
| if(IsEqualIID(riid, &IID_IEnumShellItems) || | |
| IsEqualIID(riid, &IID_IUnknown)) | |
| { | |
| *ppvObject = &This->IEnumShellItems_iface; | |
| } | |
| if(*ppvObject) | |
| { | |
| IUnknown_AddRef((IUnknown*)*ppvObject); | |
| return S_OK; | |
| } | |
| return E_NOINTERFACE; | |
| } | |
| static ULONG WINAPI IEnumShellItems_fnAddRef(IEnumShellItems *iface) | |
| { | |
| IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface); | |
| LONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("%p - ref %d\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI IEnumShellItems_fnRelease(IEnumShellItems *iface) | |
| { | |
| IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface); | |
| LONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("%p - ref %d\n", This, ref); | |
| if(!ref) | |
| { | |
| TRACE("Freeing.\n"); | |
| IShellItemArray_Release(This->array); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| return 0; | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI IEnumShellItems_fnNext(IEnumShellItems* iface, | |
| ULONG celt, | |
| IShellItem **rgelt, | |
| ULONG *pceltFetched) | |
| { | |
| IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface); | |
| HRESULT hr = S_FALSE; | |
| UINT i; | |
| ULONG fetched = 0; | |
| TRACE("%p (%d %p %p)\n", This, celt, rgelt, pceltFetched); | |
| if(pceltFetched == NULL && celt != 1) | |
| return E_INVALIDARG; | |
| for(i = This->position; fetched < celt && i < This->count; i++) { | |
| hr = IShellItemArray_GetItemAt(This->array, i, &rgelt[fetched]); | |
| if(FAILED(hr)) | |
| break; | |
| fetched++; | |
| This->position++; | |
| } | |
| if(SUCCEEDED(hr)) | |
| { | |
| if(pceltFetched != NULL) | |
| *pceltFetched = fetched; | |
| if(fetched > 0) | |
| return S_OK; | |
| return S_FALSE; | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI IEnumShellItems_fnSkip(IEnumShellItems* iface, ULONG celt) | |
| { | |
| IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface); | |
| TRACE("%p (%d)\n", This, celt); | |
| This->position = min(This->position + celt, This->count-1); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IEnumShellItems_fnReset(IEnumShellItems* iface) | |
| { | |
| IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface); | |
| TRACE("%p\n", This); | |
| This->position = 0; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IEnumShellItems_fnClone(IEnumShellItems* iface, IEnumShellItems **ppenum) | |
| { | |
| IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface); | |
| TRACE("%p (%p)\n", This, ppenum); | |
| /* Not implemented anywhere */ | |
| *ppenum = NULL; | |
| return E_NOTIMPL; | |
| } | |
| static const IEnumShellItemsVtbl vt_IEnumShellItems = { | |
| IEnumShellItems_fnQueryInterface, | |
| IEnumShellItems_fnAddRef, | |
| IEnumShellItems_fnRelease, | |
| IEnumShellItems_fnNext, | |
| IEnumShellItems_fnSkip, | |
| IEnumShellItems_fnReset, | |
| IEnumShellItems_fnClone | |
| }; | |
| static HRESULT IEnumShellItems_Constructor(IShellItemArray *array, IEnumShellItems **ppesi) | |
| { | |
| IEnumShellItemsImpl *This; | |
| HRESULT ret; | |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumShellItemsImpl)); | |
| if(!This) | |
| return E_OUTOFMEMORY; | |
| This->ref = 1; | |
| This->IEnumShellItems_iface.lpVtbl = &vt_IEnumShellItems; | |
| This->array = array; | |
| This->position = 0; | |
| IShellItemArray_AddRef(This->array); | |
| IShellItemArray_GetCount(This->array, &This->count); | |
| ret = IEnumShellItems_QueryInterface(&This->IEnumShellItems_iface, &IID_IEnumShellItems, (void**)ppesi); | |
| IEnumShellItems_Release(&This->IEnumShellItems_iface); | |
| return ret; | |
| } | |
| /************************************************************************* | |
| * IShellItemArray implementation | |
| */ | |
| typedef struct { | |
| IShellItemArray IShellItemArray_iface; | |
| LONG ref; | |
| IShellItem **array; | |
| DWORD item_count; | |
| } IShellItemArrayImpl; | |
| static inline IShellItemArrayImpl *impl_from_IShellItemArray(IShellItemArray *iface) | |
| { | |
| return CONTAINING_RECORD(iface, IShellItemArrayImpl, IShellItemArray_iface); | |
| } | |
| static HRESULT WINAPI IShellItemArray_fnQueryInterface(IShellItemArray *iface, | |
| REFIID riid, | |
| void **ppvObject) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject); | |
| *ppvObject = NULL; | |
| if(IsEqualIID(riid, &IID_IShellItemArray) || | |
| IsEqualIID(riid, &IID_IUnknown)) | |
| { | |
| *ppvObject = &This->IShellItemArray_iface; | |
| } | |
| if(*ppvObject) | |
| { | |
| IUnknown_AddRef((IUnknown*)*ppvObject); | |
| return S_OK; | |
| } | |
| return E_NOINTERFACE; | |
| } | |
| static ULONG WINAPI IShellItemArray_fnAddRef(IShellItemArray *iface) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| LONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("%p - ref %d\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI IShellItemArray_fnRelease(IShellItemArray *iface) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| LONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("%p - ref %d\n", This, ref); | |
| if(!ref) | |
| { | |
| UINT i; | |
| TRACE("Freeing.\n"); | |
| for(i = 0; i < This->item_count; i++) | |
| IShellItem_Release(This->array[i]); | |
| HeapFree(GetProcessHeap(), 0, This->array); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| return 0; | |
| } | |
| return ref; | |
| } | |
| static HRESULT WINAPI IShellItemArray_fnBindToHandler(IShellItemArray *iface, | |
| IBindCtx *pbc, | |
| REFGUID bhid, | |
| REFIID riid, | |
| void **ppvOut) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| FIXME("Stub: %p (%p, %s, %s, %p)\n", | |
| This, pbc, shdebugstr_guid(bhid), shdebugstr_guid(riid), ppvOut); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IShellItemArray_fnGetPropertyStore(IShellItemArray *iface, | |
| GETPROPERTYSTOREFLAGS flags, | |
| REFIID riid, | |
| void **ppv) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| FIXME("Stub: %p (%x, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray *iface, | |
| REFPROPERTYKEY keyType, | |
| REFIID riid, | |
| void **ppv) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| FIXME("Stub: %p (%p, %s, %p)\n", | |
| This, keyType, shdebugstr_guid(riid), ppv); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI IShellItemArray_fnGetAttributes(IShellItemArray *iface, | |
| SIATTRIBFLAGS AttribFlags, | |
| SFGAOF sfgaoMask, | |
| SFGAOF *psfgaoAttribs) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| HRESULT hr = S_OK; | |
| SFGAOF attr; | |
| UINT i; | |
| TRACE("%p (%x, %x, %p)\n", This, AttribFlags, sfgaoMask, psfgaoAttribs); | |
| if(AttribFlags & ~(SIATTRIBFLAGS_AND|SIATTRIBFLAGS_OR)) | |
| FIXME("%08x contains unsupported attribution flags\n", AttribFlags); | |
| for(i = 0; i < This->item_count; i++) | |
| { | |
| hr = IShellItem_GetAttributes(This->array[i], sfgaoMask, &attr); | |
| if(FAILED(hr)) | |
| break; | |
| if(i == 0) | |
| { | |
| *psfgaoAttribs = attr; | |
| continue; | |
| } | |
| switch(AttribFlags & SIATTRIBFLAGS_MASK) | |
| { | |
| case SIATTRIBFLAGS_AND: | |
| *psfgaoAttribs &= attr; | |
| break; | |
| case SIATTRIBFLAGS_OR: | |
| *psfgaoAttribs |= attr; | |
| break; | |
| } | |
| } | |
| if(SUCCEEDED(hr)) | |
| { | |
| if(*psfgaoAttribs == sfgaoMask) | |
| return S_OK; | |
| return S_FALSE; | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI IShellItemArray_fnGetCount(IShellItemArray *iface, | |
| DWORD *pdwNumItems) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| TRACE("%p (%p)\n", This, pdwNumItems); | |
| *pdwNumItems = This->item_count; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IShellItemArray_fnGetItemAt(IShellItemArray *iface, | |
| DWORD dwIndex, | |
| IShellItem **ppsi) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| TRACE("%p (%x, %p)\n", This, dwIndex, ppsi); | |
| /* zero indexed */ | |
| if(dwIndex + 1 > This->item_count) | |
| return E_FAIL; | |
| *ppsi = This->array[dwIndex]; | |
| IShellItem_AddRef(*ppsi); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI IShellItemArray_fnEnumItems(IShellItemArray *iface, | |
| IEnumShellItems **ppenumShellItems) | |
| { | |
| IShellItemArrayImpl *This = impl_from_IShellItemArray(iface); | |
| TRACE("%p (%p)\n", This, ppenumShellItems); | |
| return IEnumShellItems_Constructor(iface, ppenumShellItems); | |
| } | |
| static const IShellItemArrayVtbl vt_IShellItemArray = { | |
| IShellItemArray_fnQueryInterface, | |
| IShellItemArray_fnAddRef, | |
| IShellItemArray_fnRelease, | |
| IShellItemArray_fnBindToHandler, | |
| IShellItemArray_fnGetPropertyStore, | |
| IShellItemArray_fnGetPropertyDescriptionList, | |
| IShellItemArray_fnGetAttributes, | |
| IShellItemArray_fnGetCount, | |
| IShellItemArray_fnGetItemAt, | |
| IShellItemArray_fnEnumItems | |
| }; | |
| /* Caller is responsible to AddRef all items */ | |
| static HRESULT create_shellitemarray(IShellItem **items, DWORD count, IShellItemArray **ret) | |
| { | |
| IShellItemArrayImpl *This; | |
| TRACE("(%p, %d, %p)\n", items, count, ret); | |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl)); | |
| if(!This) | |
| return E_OUTOFMEMORY; | |
| This->IShellItemArray_iface.lpVtbl = &vt_IShellItemArray; | |
| This->ref = 1; | |
| This->array = HeapAlloc(GetProcessHeap(), 0, count*sizeof(IShellItem*)); | |
| if (!This->array) | |
| { | |
| HeapFree(GetProcessHeap(), 0, This); | |
| return E_OUTOFMEMORY; | |
| } | |
| memcpy(This->array, items, count*sizeof(IShellItem*)); | |
| This->item_count = count; | |
| *ret = &This->IShellItemArray_iface; | |
| return S_OK; | |
| } | |
| HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent, | |
| IShellFolder *psf, | |
| UINT cidl, | |
| PCUITEMID_CHILD_ARRAY ppidl, | |
| IShellItemArray **ppsiItemArray) | |
| { | |
| IShellItem **array; | |
| HRESULT ret = E_FAIL; | |
| UINT i; | |
| TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray); | |
| *ppsiItemArray = NULL; | |
| if(!pidlParent && !psf) | |
| return E_POINTER; | |
| if(!ppidl) | |
| return E_INVALIDARG; | |
| array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*)); | |
| if(!array) | |
| return E_OUTOFMEMORY; | |
| for(i = 0; i < cidl; i++) | |
| { | |
| ret = SHCreateShellItem(pidlParent, psf, ppidl[i], &array[i]); | |
| if(FAILED(ret)) break; | |
| } | |
| if(SUCCEEDED(ret)) | |
| { | |
| ret = create_shellitemarray(array, cidl, ppsiItemArray); | |
| HeapFree(GetProcessHeap(), 0, array); | |
| if(SUCCEEDED(ret)) | |
| return ret; | |
| } | |
| /* Something failed, clean up. */ | |
| for(i = 0; i < cidl; i++) | |
| if(array[i]) IShellItem_Release(array[i]); | |
| HeapFree(GetProcessHeap(), 0, array); | |
| return ret; | |
| } | |
| HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *item, REFIID riid, void **ppv) | |
| { | |
| IShellItemArray *array; | |
| HRESULT ret; | |
| TRACE("%p, %s, %p\n", item, shdebugstr_guid(riid), ppv); | |
| *ppv = NULL; | |
| IShellItem_AddRef(item); | |
| ret = create_shellitemarray(&item, 1, &array); | |
| if(FAILED(ret)) | |
| { | |
| IShellItem_Release(item); | |
| return ret; | |
| } | |
| ret = IShellItemArray_QueryInterface(array, riid, ppv); | |
| IShellItemArray_Release(array); | |
| return ret; | |
| } | |
| HRESULT WINAPI SHCreateShellItemArrayFromDataObject(IDataObject *pdo, REFIID riid, void **ppv) | |
| { | |
| IShellItemArray *psia; | |
| FORMATETC fmt; | |
| STGMEDIUM medium; | |
| HRESULT ret; | |
| TRACE("%p, %s, %p\n", pdo, shdebugstr_guid(riid), ppv); | |
| if(!pdo) | |
| return E_INVALIDARG; | |
| *ppv = NULL; | |
| fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); | |
| fmt.ptd = NULL; | |
| fmt.dwAspect = DVASPECT_CONTENT; | |
| fmt.lindex = -1; | |
| fmt.tymed = TYMED_HGLOBAL; | |
| ret = IDataObject_GetData(pdo, &fmt, &medium); | |
| if(SUCCEEDED(ret)) | |
| { | |
| LPIDA pida = GlobalLock(medium.u.hGlobal); | |
| LPCITEMIDLIST parent_pidl; | |
| LPCITEMIDLIST *children; | |
| UINT i; | |
| TRACE("Converting %d objects.\n", pida->cidl); | |
| parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]); | |
| children = HeapAlloc(GetProcessHeap(), 0, sizeof(LPCITEMIDLIST)*pida->cidl); | |
| for(i = 0; i < pida->cidl; i++) | |
| children[i] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i+1]); | |
| ret = SHCreateShellItemArray(parent_pidl, NULL, pida->cidl, children, &psia); | |
| HeapFree(GetProcessHeap(), 0, children); | |
| GlobalUnlock(medium.u.hGlobal); | |
| GlobalFree(medium.u.hGlobal); | |
| } | |
| if(SUCCEEDED(ret)) | |
| { | |
| ret = IShellItemArray_QueryInterface(psia, riid, ppv); | |
| IShellItemArray_Release(psia); | |
| } | |
| return ret; | |
| } | |
| HRESULT WINAPI SHCreateShellItemArrayFromIDLists(UINT cidl, | |
| PCIDLIST_ABSOLUTE_ARRAY pidl_array, | |
| IShellItemArray **psia) | |
| { | |
| IShellItem **array; | |
| HRESULT ret; | |
| UINT i; | |
| TRACE("%d, %p, %p\n", cidl, pidl_array, psia); | |
| *psia = NULL; | |
| if(cidl == 0) | |
| return E_INVALIDARG; | |
| array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*)); | |
| if(!array) | |
| return E_OUTOFMEMORY; | |
| for(i = 0; i < cidl; i++) | |
| { | |
| ret = SHCreateShellItem(NULL, NULL, pidl_array[i], &array[i]); | |
| if(FAILED(ret)) | |
| break; | |
| } | |
| if(SUCCEEDED(ret)) | |
| { | |
| ret = create_shellitemarray(array, cidl, psia); | |
| HeapFree(GetProcessHeap(), 0, array); | |
| if(SUCCEEDED(ret)) | |
| return ret; | |
| } | |
| for(i = 0; i < cidl; i++) | |
| if(array[i]) IShellItem_Release(array[i]); | |
| HeapFree(GetProcessHeap(), 0, array); | |
| *psia = NULL; | |
| return ret; | |
| } | |
| HRESULT WINAPI SHGetPropertyStoreFromParsingName(const WCHAR *path, IBindCtx *pbc, GETPROPERTYSTOREFLAGS flags, | |
| REFIID riid, void **ppv) | |
| { | |
| IShellItem2 *item; | |
| HRESULT hr; | |
| TRACE("(%s %p %#x %p %p)\n", debugstr_w(path), pbc, flags, riid, ppv); | |
| hr = SHCreateItemFromParsingName(path, pbc, &IID_IShellItem2, (void **)&item); | |
| if(SUCCEEDED(hr)) | |
| { | |
| hr = IShellItem2_GetPropertyStore(item, flags, riid, ppv); | |
| IShellItem2_Release(item); | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_QueryInterface(ICustomDestinationList *iface, REFIID riid, void **obj) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), obj); | |
| if (IsEqualIID(&IID_ICustomDestinationList, riid) || IsEqualIID(&IID_IUnknown, riid)) | |
| { | |
| *obj = &This->ICustomDestinationList_iface; | |
| } | |
| else { | |
| FIXME("not implemented for %s\n", shdebugstr_guid(riid)); | |
| *obj = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IUnknown_AddRef((IUnknown*)*obj); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI CustomDestinationList_AddRef(ICustomDestinationList *iface) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p), new refcount=%i\n", This, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI CustomDestinationList_Release(ICustomDestinationList *iface) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p), new refcount=%i\n", This, ref); | |
| if (ref == 0) | |
| HeapFree(GetProcessHeap(), 0, This); | |
| return ref; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_SetAppID(ICustomDestinationList *iface, const WCHAR *appid) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p (%s): stub\n", This, debugstr_w(appid)); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_BeginList(ICustomDestinationList *iface, UINT *min_slots, REFIID riid, void **obj) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p (%p %s %p): stub\n", This, min_slots, debugstr_guid(riid), obj); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_AppendCategory(ICustomDestinationList *iface, const WCHAR *category, IObjectArray *array) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p (%s %p): stub\n", This, debugstr_w(category), array); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_AppendKnownCategory(ICustomDestinationList *iface, KNOWNDESTCATEGORY category) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p (%d): stub\n", This, category); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_AddUserTasks(ICustomDestinationList *iface, IObjectArray *tasks) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p (%p): stub\n", This, tasks); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_CommitList(ICustomDestinationList *iface) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p: stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_GetRemovedDestinations(ICustomDestinationList *iface, REFIID riid, void **obj) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p (%s %p): stub\n", This, debugstr_guid(riid), obj); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_DeleteList(ICustomDestinationList *iface, const WCHAR *appid) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p (%s): stub\n", This, debugstr_w(appid)); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI CustomDestinationList_AbortList(ICustomDestinationList *iface) | |
| { | |
| CustomDestinationList *This = impl_from_ICustomDestinationList(iface); | |
| FIXME("%p: stub\n", This); | |
| return E_NOTIMPL; | |
| } | |
| static const ICustomDestinationListVtbl CustomDestinationListVtbl = | |
| { | |
| CustomDestinationList_QueryInterface, | |
| CustomDestinationList_AddRef, | |
| CustomDestinationList_Release, | |
| CustomDestinationList_SetAppID, | |
| CustomDestinationList_BeginList, | |
| CustomDestinationList_AppendCategory, | |
| CustomDestinationList_AppendKnownCategory, | |
| CustomDestinationList_AddUserTasks, | |
| CustomDestinationList_CommitList, | |
| CustomDestinationList_GetRemovedDestinations, | |
| CustomDestinationList_DeleteList, | |
| CustomDestinationList_AbortList | |
| }; | |
| HRESULT WINAPI CustomDestinationList_Constructor(IUnknown *outer, REFIID riid, void **obj) | |
| { | |
| CustomDestinationList *list; | |
| HRESULT hr; | |
| TRACE("%p %s %p\n", outer, debugstr_guid(riid), obj); | |
| if (outer) | |
| return CLASS_E_NOAGGREGATION; | |
| if(!(list = HeapAlloc(GetProcessHeap(), 0, sizeof(*list)))) | |
| return E_OUTOFMEMORY; | |
| list->ICustomDestinationList_iface.lpVtbl = &CustomDestinationListVtbl; | |
| list->ref = 1; | |
| hr = ICustomDestinationList_QueryInterface(&list->ICustomDestinationList_iface, riid, obj); | |
| ICustomDestinationList_Release(&list->ICustomDestinationList_iface); | |
| return hr; | |
| } |