| /* |
| * 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 |
| #define NONAMELESSSTRUCT |
| |
| #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; |
| |
| 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 HRESULT WINAPI ShellItem_QueryInterface(IShellItem2 *iface, REFIID riid, |
| void **ppv) |
| { |
| ShellItem *This = impl_from_IShellItem2(iface); |
| |
| TRACE("(%p,%p,%p)\n", iface, riid, ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellItem, riid) || |
| IsEqualIID(&IID_IShellItem2, riid)) |
| { |
| *ppv = This; |
| } |
| 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)) |
| { |
| 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); |
| IShellFolder_Release(parent_folder); |
| } |
| |
| 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 = IShellItem_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 = IShellItem_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 ShellItem_GetClassID(ShellItem* This, CLSID *pClassID) |
| { |
| TRACE("(%p,%p)\n", This, pClassID); |
| |
| *pClassID = CLSID_ShellItem; |
| return S_OK; |
| } |
| |
| |
| static HRESULT WINAPI ShellItem_IPersistIDList_QueryInterface(IPersistIDList *iface, |
| REFIID riid, void **ppv) |
| { |
| ShellItem *This = impl_from_IPersistIDList(iface); |
| return ShellItem_QueryInterface(&This->IShellItem2_iface, riid, ppv); |
| } |
| |
| static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface) |
| { |
| ShellItem *This = impl_from_IPersistIDList(iface); |
| return ShellItem_AddRef(&This->IShellItem2_iface); |
| } |
| |
| static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface) |
| { |
| ShellItem *This = impl_from_IPersistIDList(iface); |
| return ShellItem_Release(&This->IShellItem2_iface); |
| } |
| |
| static HRESULT WINAPI ShellItem_IPersistIDList_GetClassID(IPersistIDList* iface, |
| CLSID *pClassID) |
| { |
| ShellItem *This = impl_from_IPersistIDList(iface); |
| |
| return ShellItem_GetClassID(This, pClassID); |
| } |
| |
| 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 = ShellItem_QueryInterface(&This->IShellItem2_iface, riid, ppv); |
| ShellItem_Release(&This->IShellItem2_iface); |
| |
| return ret; |
| } |
| |
| HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent, |
| IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi) |
| { |
| ShellItem *This; |
| LPITEMIDLIST new_pidl; |
| HRESULT ret; |
| |
| TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi); |
| |
| if (!pidl) |
| { |
| return E_INVALIDARG; |
| } |
| else if (pidlParent || psfParent) |
| { |
| LPITEMIDLIST temp_parent=NULL; |
| if (!pidlParent) |
| { |
| IPersistFolder2* ppf2Parent; |
| |
| if (FAILED(IPersistFolder2_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 = IShellItem_Constructor(NULL, &IID_IShellItem, (void**)&This); |
| if (This) |
| { |
| *ppsi = (IShellItem*)&This->IShellItem2_iface; |
| This->pidl = new_pidl; |
| } |
| else |
| { |
| *ppsi = NULL; |
| 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)) |
| { |
| ShellItem *This; |
| ret = IShellItem_Constructor(NULL, riid, (void**)&This); |
| |
| if(SUCCEEDED(ret)) |
| { |
| This->pidl = pidl; |
| *ppv = (void*)This; |
| } |
| else |
| { |
| ILFree(pidl); |
| } |
| } |
| return ret; |
| } |
| |
| HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv) |
| { |
| ShellItem *psiimpl; |
| HRESULT ret; |
| |
| if(!pidl) |
| return E_INVALIDARG; |
| |
| ret = IShellItem_Constructor(NULL, riid, ppv); |
| if(SUCCEEDED(ret)) |
| { |
| psiimpl = (ShellItem*)*ppv; |
| psiimpl->pidl = ILClone(pidl); |
| } |
| |
| return ret; |
| } |
| |
| 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; |
| } |
| |
| /************************************************************************* |
| * 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; |
| } |
| |
| 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); |
| FIXME("Stub: %p (%x, %x, %p)\n", This, AttribFlags, sfgaoMask, psfgaoAttribs); |
| |
| return E_NOTIMPL; |
| } |
| |
| 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); |
| FIXME("Stub: %p (%p)\n", This, ppenumShellItems); |
| |
| return E_NOTIMPL; |
| } |
| |
| 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 |
| }; |
| |
| static HRESULT IShellItemArray_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv) |
| { |
| IShellItemArrayImpl *This; |
| HRESULT ret; |
| |
| TRACE("(%p, %s, %p)\n",pUnkOuter, debugstr_guid(riid), ppv); |
| |
| if(pUnkOuter) |
| return CLASS_E_NOAGGREGATION; |
| |
| This = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl)); |
| if(!This) |
| return E_OUTOFMEMORY; |
| |
| This->ref = 1; |
| This->IShellItemArray_iface.lpVtbl = &vt_IShellItemArray; |
| This->array = NULL; |
| This->item_count = 0; |
| |
| ret = IShellItemArray_QueryInterface(&This->IShellItemArray_iface, riid, ppv); |
| IShellItemArray_Release(&This->IShellItemArray_iface); |
| |
| return ret; |
| } |
| |
| HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent, |
| IShellFolder *psf, |
| UINT cidl, |
| PCUITEMID_CHILD_ARRAY ppidl, |
| IShellItemArray **ppsiItemArray) |
| { |
| IShellItemArrayImpl *This; |
| IShellItem **array; |
| HRESULT ret = E_FAIL; |
| UINT i; |
| |
| TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray); |
| |
| 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 = IShellItemArray_Constructor(NULL, &IID_IShellItemArray, (void**)&This); |
| if(SUCCEEDED(ret)) |
| { |
| This->array = array; |
| This->item_count = cidl; |
| *ppsiItemArray = &This->IShellItemArray_iface; |
| |
| return ret; |
| } |
| } |
| |
| /* Something failed, clean up. */ |
| for(i = 0; i < cidl; i++) |
| if(array[i]) IShellItem_Release(array[i]); |
| HeapFree(GetProcessHeap(), 0, array); |
| *ppsiItemArray = NULL; |
| return ret; |
| } |
| |
| HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *psi, REFIID riid, void **ppv) |
| { |
| IShellItemArrayImpl *This; |
| IShellItem **array; |
| HRESULT ret; |
| |
| TRACE("%p, %s, %p\n", psi, shdebugstr_guid(riid), ppv); |
| |
| array = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItem*)); |
| if(!array) |
| return E_OUTOFMEMORY; |
| |
| ret = IShellItemArray_Constructor(NULL, riid, (void**)&This); |
| if(SUCCEEDED(ret)) |
| { |
| array[0] = psi; |
| IShellItem_AddRef(psi); |
| This->array = array; |
| This->item_count = 1; |
| *ppv = This; |
| } |
| else |
| { |
| HeapFree(GetProcessHeap(), 0, array); |
| *ppv = NULL; |
| } |
| |
| 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; |
| } |