| /* |
| * IShellItem implementation |
| * |
| * 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 { |
| const IShellItemVtbl *lpIShellItemVtbl; |
| LONG ref; |
| LPITEMIDLIST pidl; |
| const IPersistIDListVtbl *lpIPersistIDListVtbl; |
| } ShellItem; |
| |
| |
| static inline ShellItem *impl_from_IPersistIDList( IPersistIDList *iface ) |
| { |
| return (ShellItem*)((char*)iface - FIELD_OFFSET(ShellItem, lpIPersistIDListVtbl)); |
| } |
| |
| |
| static HRESULT WINAPI ShellItem_QueryInterface(IShellItem *iface, REFIID riid, |
| void **ppv) |
| { |
| ShellItem *This = (ShellItem*)iface; |
| |
| TRACE("(%p,%p,%p)\n", iface, riid, ppv); |
| |
| if (!ppv) return E_INVALIDARG; |
| |
| if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellItem, riid)) |
| { |
| *ppv = This; |
| } |
| else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistIDList, riid)) |
| { |
| *ppv = &(This->lpIPersistIDListVtbl); |
| } |
| 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(IShellItem *iface) |
| { |
| ShellItem *This = (ShellItem*)iface; |
| ULONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p), new refcount=%i\n", iface, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI ShellItem_Release(IShellItem *iface) |
| { |
| ShellItem *This = (ShellItem*)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 WINAPI ShellItem_BindToHandler(IShellItem *iface, IBindCtx *pbc, |
| REFGUID rbhid, REFIID riid, void **ppvOut) |
| { |
| FIXME("(%p,%p,%s,%p,%p)\n", iface, pbc, shdebugstr_guid(rbhid), riid, ppvOut); |
| |
| *ppvOut = NULL; |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellItem_GetParent(IShellItem *iface, IShellItem **ppsi) |
| { |
| ShellItem *This = (ShellItem*)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(IShellItem *iface, SIGDN sigdnName, |
| LPWSTR *ppszName) |
| { |
| FIXME("(%p,%x,%p)\n", iface, sigdnName, ppszName); |
| |
| *ppszName = NULL; |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI ShellItem_GetAttributes(IShellItem *iface, SFGAOF sfgaoMask, |
| SFGAOF *psfgaoAttribs) |
| { |
| ShellItem *This = (ShellItem*)iface; |
| IShellFolder *parent_folder; |
| LPITEMIDLIST child_pidl; |
| HRESULT ret; |
| |
| TRACE("(%p,%x,%p)\n", iface, sfgaoMask, psfgaoAttribs); |
| |
| 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(IShellItem *iface, IShellItem *oth, |
| SICHINTF hint, int *piOrder) |
| { |
| FIXME("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder); |
| |
| return E_NOTIMPL; |
| } |
| |
| static const IShellItemVtbl ShellItem_Vtbl = { |
| ShellItem_QueryInterface, |
| ShellItem_AddRef, |
| ShellItem_Release, |
| ShellItem_BindToHandler, |
| ShellItem_GetParent, |
| ShellItem_GetDisplayName, |
| ShellItem_GetAttributes, |
| ShellItem_Compare |
| }; |
| |
| |
| 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((IShellItem*)This, riid, ppv); |
| } |
| |
| static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface) |
| { |
| ShellItem *This = impl_from_IPersistIDList(iface); |
| return ShellItem_AddRef((IShellItem*)This); |
| } |
| |
| static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface) |
| { |
| ShellItem *This = impl_from_IPersistIDList(iface); |
| return ShellItem_Release((IShellItem*)This); |
| } |
| |
| 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->lpIShellItemVtbl = &ShellItem_Vtbl; |
| This->ref = 1; |
| This->pidl = NULL; |
| This->lpIPersistIDListVtbl = &ShellItem_IPersistIDList_Vtbl; |
| |
| ret = ShellItem_QueryInterface((IShellItem*)This, riid, ppv); |
| ShellItem_Release((IShellItem*)This); |
| |
| 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; |
| This->pidl = new_pidl; |
| } |
| else |
| { |
| *ppsi = NULL; |
| ILFree(new_pidl); |
| } |
| return ret; |
| } |