2 * IShellItem and IShellItemArray implementations
4 * Copyright 2008 Vincent Povirk for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
28 #define NONAMELESSUNION
32 #include "wine/debug.h"
35 #include "shell32_main.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
40 typedef struct _ShellItem
{
41 IShellItem2 IShellItem2_iface
;
44 IPersistIDList IPersistIDList_iface
;
47 static inline ShellItem
*impl_from_IShellItem2(IShellItem2
*iface
)
49 return CONTAINING_RECORD(iface
, ShellItem
, IShellItem2_iface
);
53 static inline ShellItem
*impl_from_IPersistIDList( IPersistIDList
*iface
)
55 return CONTAINING_RECORD(iface
, ShellItem
, IPersistIDList_iface
);
59 static HRESULT WINAPI
ShellItem_QueryInterface(IShellItem2
*iface
, REFIID riid
,
62 ShellItem
*This
= impl_from_IShellItem2(iface
);
64 TRACE("(%p,%p,%p)\n", iface
, riid
, ppv
);
66 if (!ppv
) return E_INVALIDARG
;
68 if (IsEqualIID(&IID_IUnknown
, riid
) || IsEqualIID(&IID_IShellItem
, riid
) ||
69 IsEqualIID(&IID_IShellItem2
, riid
))
71 *ppv
= &This
->IShellItem2_iface
;
73 else if (IsEqualIID(&IID_IPersist
, riid
) || IsEqualIID(&IID_IPersistIDList
, riid
))
75 *ppv
= &This
->IPersistIDList_iface
;
78 FIXME("not implemented for %s\n", shdebugstr_guid(riid
));
83 IUnknown_AddRef((IUnknown
*)*ppv
);
87 static ULONG WINAPI
ShellItem_AddRef(IShellItem2
*iface
)
89 ShellItem
*This
= impl_from_IShellItem2(iface
);
90 ULONG ref
= InterlockedIncrement(&This
->ref
);
92 TRACE("(%p), new refcount=%i\n", iface
, ref
);
97 static ULONG WINAPI
ShellItem_Release(IShellItem2
*iface
)
99 ShellItem
*This
= impl_from_IShellItem2(iface
);
100 ULONG ref
= InterlockedDecrement(&This
->ref
);
102 TRACE("(%p), new refcount=%i\n", iface
, ref
);
107 HeapFree(GetProcessHeap(), 0, This
);
113 static HRESULT
ShellItem_get_parent_pidl(ShellItem
*This
, LPITEMIDLIST
*parent_pidl
)
115 *parent_pidl
= ILClone(This
->pidl
);
118 if (ILRemoveLastID(*parent_pidl
))
122 ILFree(*parent_pidl
);
130 return E_OUTOFMEMORY
;
134 static HRESULT
ShellItem_get_parent_shellfolder(ShellItem
*This
, IShellFolder
**ppsf
)
136 LPITEMIDLIST parent_pidl
;
137 IShellFolder
*desktop
;
140 ret
= ShellItem_get_parent_pidl(This
, &parent_pidl
);
143 ret
= SHGetDesktopFolder(&desktop
);
146 if (_ILIsDesktop(parent_pidl
))
152 ret
= IShellFolder_BindToObject(desktop
, parent_pidl
, NULL
, &IID_IShellFolder
, (void**)ppsf
);
153 IShellFolder_Release(desktop
);
162 static HRESULT
ShellItem_get_shellfolder(ShellItem
*This
, IBindCtx
*pbc
, IShellFolder
**ppsf
)
164 IShellFolder
*desktop
;
167 ret
= SHGetDesktopFolder(&desktop
);
170 if (_ILIsDesktop(This
->pidl
))
173 IShellFolder_AddRef(*ppsf
);
177 ret
= IShellFolder_BindToObject(desktop
, This
->pidl
, pbc
, &IID_IShellFolder
, (void**)ppsf
);
180 IShellFolder_Release(desktop
);
186 static HRESULT WINAPI
ShellItem_BindToHandler(IShellItem2
*iface
, IBindCtx
*pbc
,
187 REFGUID rbhid
, REFIID riid
, void **ppvOut
)
189 ShellItem
*This
= impl_from_IShellItem2(iface
);
191 TRACE("(%p,%p,%s,%p,%p)\n", iface
, pbc
, shdebugstr_guid(rbhid
), riid
, ppvOut
);
194 if (IsEqualGUID(rbhid
, &BHID_SFObject
))
197 ret
= ShellItem_get_shellfolder(This
, pbc
, &psf
);
200 ret
= IShellFolder_QueryInterface(psf
, riid
, ppvOut
);
201 IShellFolder_Release(psf
);
205 else if (IsEqualGUID(rbhid
, &BHID_SFUIObject
))
207 IShellFolder
*psf_parent
;
208 if (_ILIsDesktop(This
->pidl
))
209 ret
= SHGetDesktopFolder(&psf_parent
);
211 ret
= ShellItem_get_parent_shellfolder(This
, &psf_parent
);
215 LPCITEMIDLIST pidl
= ILFindLastID(This
->pidl
);
216 ret
= IShellFolder_GetUIObjectOf(psf_parent
, NULL
, 1, &pidl
, riid
, NULL
, ppvOut
);
217 IShellFolder_Release(psf_parent
);
221 else if (IsEqualGUID(rbhid
, &BHID_DataObject
))
223 return ShellItem_BindToHandler(&This
->IShellItem2_iface
, pbc
, &BHID_SFUIObject
,
224 &IID_IDataObject
, ppvOut
);
227 FIXME("Unsupported BHID %s.\n", debugstr_guid(rbhid
));
229 return MK_E_NOOBJECT
;
232 static HRESULT WINAPI
ShellItem_GetParent(IShellItem2
*iface
, IShellItem
**ppsi
)
234 ShellItem
*This
= impl_from_IShellItem2(iface
);
235 LPITEMIDLIST parent_pidl
;
238 TRACE("(%p,%p)\n", iface
, ppsi
);
240 ret
= ShellItem_get_parent_pidl(This
, &parent_pidl
);
243 ret
= SHCreateShellItem(NULL
, NULL
, parent_pidl
, ppsi
);
250 static HRESULT WINAPI
ShellItem_GetDisplayName(IShellItem2
*iface
, SIGDN sigdnName
,
253 ShellItem
*This
= impl_from_IShellItem2(iface
);
254 TRACE("(%p,%x,%p)\n", iface
, sigdnName
, ppszName
);
256 return SHGetNameFromIDList(This
->pidl
, sigdnName
, ppszName
);
259 static HRESULT WINAPI
ShellItem_GetAttributes(IShellItem2
*iface
, SFGAOF sfgaoMask
,
260 SFGAOF
*psfgaoAttribs
)
262 ShellItem
*This
= impl_from_IShellItem2(iface
);
263 IShellFolder
*parent_folder
;
264 LPITEMIDLIST child_pidl
;
267 TRACE("(%p,%x,%p)\n", iface
, sfgaoMask
, psfgaoAttribs
);
269 if (_ILIsDesktop(This
->pidl
))
270 ret
= SHGetDesktopFolder(&parent_folder
);
272 ret
= ShellItem_get_parent_shellfolder(This
, &parent_folder
);
275 child_pidl
= ILFindLastID(This
->pidl
);
276 *psfgaoAttribs
= sfgaoMask
;
277 ret
= IShellFolder_GetAttributesOf(parent_folder
, 1, (LPCITEMIDLIST
*)&child_pidl
, psfgaoAttribs
);
278 *psfgaoAttribs
&= sfgaoMask
;
279 IShellFolder_Release(parent_folder
);
283 if(sfgaoMask
== *psfgaoAttribs
)
293 static HRESULT WINAPI
ShellItem_Compare(IShellItem2
*iface
, IShellItem
*oth
,
294 SICHINTF hint
, int *piOrder
)
296 LPWSTR dispname
, dispname_oth
;
298 TRACE("(%p,%p,%x,%p)\n", iface
, oth
, hint
, piOrder
);
300 if(hint
& (SICHINT_CANONICAL
| SICHINT_ALLFIELDS
))
301 FIXME("Unsupported flags 0x%08x\n", hint
);
303 ret
= IShellItem2_GetDisplayName(iface
, SIGDN_DESKTOPABSOLUTEEDITING
, &dispname
);
306 ret
= IShellItem_GetDisplayName(oth
, SIGDN_DESKTOPABSOLUTEEDITING
, &dispname_oth
);
309 *piOrder
= lstrcmpiW(dispname
, dispname_oth
);
310 CoTaskMemFree(dispname_oth
);
312 CoTaskMemFree(dispname
);
315 if(SUCCEEDED(ret
) && *piOrder
&&
316 (hint
& SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL
))
318 LPWSTR dispname
, dispname_oth
;
320 TRACE("Testing filesystem path.\n");
321 ret
= IShellItem2_GetDisplayName(iface
, SIGDN_FILESYSPATH
, &dispname
);
324 ret
= IShellItem_GetDisplayName(oth
, SIGDN_FILESYSPATH
, &dispname_oth
);
327 *piOrder
= lstrcmpiW(dispname
, dispname_oth
);
328 CoTaskMemFree(dispname_oth
);
330 CoTaskMemFree(dispname
);
343 static HRESULT WINAPI
ShellItem2_GetPropertyStore(IShellItem2
*iface
, GETPROPERTYSTOREFLAGS flags
,
344 REFIID riid
, void **ppv
)
346 ShellItem
*This
= impl_from_IShellItem2(iface
);
347 FIXME("Stub: %p (%d, %s, %p)\n", This
, flags
, shdebugstr_guid(riid
), ppv
);
351 static HRESULT WINAPI
ShellItem2_GetPropertyStoreWithCreateObject(IShellItem2
*iface
,
352 GETPROPERTYSTOREFLAGS flags
, IUnknown
*punkCreateObject
, REFIID riid
, void **ppv
)
354 ShellItem
*This
= impl_from_IShellItem2(iface
);
355 FIXME("Stub: %p (%08x, %p, %s, %p)\n",
356 This
, flags
, punkCreateObject
, shdebugstr_guid(riid
), ppv
);
360 static HRESULT WINAPI
ShellItem2_GetPropertyStoreForKeys(IShellItem2
*iface
, const PROPERTYKEY
*rgKeys
,
361 UINT cKeys
, GETPROPERTYSTOREFLAGS flags
, REFIID riid
, void **ppv
)
363 ShellItem
*This
= impl_from_IShellItem2(iface
);
364 FIXME("Stub: %p (%p, %d, %08x, %s, %p)\n",
365 This
, rgKeys
, cKeys
, flags
, shdebugstr_guid(riid
), ppv
);
369 static HRESULT WINAPI
ShellItem2_GetPropertyDescriptionList(IShellItem2
*iface
,
370 REFPROPERTYKEY keyType
, REFIID riid
, void **ppv
)
372 ShellItem
*This
= impl_from_IShellItem2(iface
);
373 FIXME("Stub: %p (%p, %s, %p)\n", This
, keyType
, debugstr_guid(riid
), ppv
);
377 static HRESULT WINAPI
ShellItem2_Update(IShellItem2
*iface
, IBindCtx
*pbc
)
379 ShellItem
*This
= impl_from_IShellItem2(iface
);
380 FIXME("Stub: %p (%p)\n", This
, pbc
);
384 static HRESULT WINAPI
ShellItem2_GetProperty(IShellItem2
*iface
, REFPROPERTYKEY key
, PROPVARIANT
*ppropvar
)
386 ShellItem
*This
= impl_from_IShellItem2(iface
);
387 FIXME("Stub: %p (%p, %p)\n", This
, key
, ppropvar
);
391 static HRESULT WINAPI
ShellItem2_GetCLSID(IShellItem2
*iface
, REFPROPERTYKEY key
, CLSID
*pclsid
)
393 ShellItem
*This
= impl_from_IShellItem2(iface
);
394 FIXME("Stub: %p (%p, %p)\n", This
, key
, pclsid
);
398 static HRESULT WINAPI
ShellItem2_GetFileTime(IShellItem2
*iface
, REFPROPERTYKEY key
, FILETIME
*pft
)
400 ShellItem
*This
= impl_from_IShellItem2(iface
);
401 FIXME("Stub: %p (%p, %p)\n", This
, key
, pft
);
405 static HRESULT WINAPI
ShellItem2_GetInt32(IShellItem2
*iface
, REFPROPERTYKEY key
, int *pi
)
407 ShellItem
*This
= impl_from_IShellItem2(iface
);
408 FIXME("Stub: %p (%p, %p)\n", This
, key
, pi
);
412 static HRESULT WINAPI
ShellItem2_GetString(IShellItem2
*iface
, REFPROPERTYKEY key
, LPWSTR
*ppsz
)
414 ShellItem
*This
= impl_from_IShellItem2(iface
);
415 FIXME("Stub: %p (%p, %p)\n", This
, key
, ppsz
);
419 static HRESULT WINAPI
ShellItem2_GetUInt32(IShellItem2
*iface
, REFPROPERTYKEY key
, ULONG
*pui
)
421 ShellItem
*This
= impl_from_IShellItem2(iface
);
422 FIXME("Stub: %p (%p, %p)\n", This
, key
, pui
);
426 static HRESULT WINAPI
ShellItem2_GetUInt64(IShellItem2
*iface
, REFPROPERTYKEY key
, ULONGLONG
*pull
)
428 ShellItem
*This
= impl_from_IShellItem2(iface
);
429 FIXME("Stub: %p (%p, %p)\n", This
, key
, pull
);
433 static HRESULT WINAPI
ShellItem2_GetBool(IShellItem2
*iface
, REFPROPERTYKEY key
, BOOL
*pf
)
435 ShellItem
*This
= impl_from_IShellItem2(iface
);
436 FIXME("Stub: %p (%p, %p)\n", This
, key
, pf
);
441 static const IShellItem2Vtbl ShellItem2_Vtbl
= {
442 ShellItem_QueryInterface
,
445 ShellItem_BindToHandler
,
447 ShellItem_GetDisplayName
,
448 ShellItem_GetAttributes
,
450 ShellItem2_GetPropertyStore
,
451 ShellItem2_GetPropertyStoreWithCreateObject
,
452 ShellItem2_GetPropertyStoreForKeys
,
453 ShellItem2_GetPropertyDescriptionList
,
455 ShellItem2_GetProperty
,
457 ShellItem2_GetFileTime
,
459 ShellItem2_GetString
,
460 ShellItem2_GetUInt32
,
461 ShellItem2_GetUInt64
,
465 static HRESULT WINAPI
ShellItem_IPersistIDList_QueryInterface(IPersistIDList
*iface
,
466 REFIID riid
, void **ppv
)
468 ShellItem
*This
= impl_from_IPersistIDList(iface
);
469 return IShellItem2_QueryInterface(&This
->IShellItem2_iface
, riid
, ppv
);
472 static ULONG WINAPI
ShellItem_IPersistIDList_AddRef(IPersistIDList
*iface
)
474 ShellItem
*This
= impl_from_IPersistIDList(iface
);
475 return IShellItem2_AddRef(&This
->IShellItem2_iface
);
478 static ULONG WINAPI
ShellItem_IPersistIDList_Release(IPersistIDList
*iface
)
480 ShellItem
*This
= impl_from_IPersistIDList(iface
);
481 return IShellItem2_Release(&This
->IShellItem2_iface
);
484 static HRESULT WINAPI
ShellItem_IPersistIDList_GetClassID(IPersistIDList
* iface
,
487 *pClassID
= CLSID_ShellItem
;
491 static HRESULT WINAPI
ShellItem_IPersistIDList_SetIDList(IPersistIDList
* iface
,
494 ShellItem
*This
= impl_from_IPersistIDList(iface
);
495 LPITEMIDLIST new_pidl
;
497 TRACE("(%p,%p)\n", This
, pidl
);
499 new_pidl
= ILClone(pidl
);
504 This
->pidl
= new_pidl
;
508 return E_OUTOFMEMORY
;
511 static HRESULT WINAPI
ShellItem_IPersistIDList_GetIDList(IPersistIDList
* iface
,
514 ShellItem
*This
= impl_from_IPersistIDList(iface
);
516 TRACE("(%p,%p)\n", This
, ppidl
);
518 *ppidl
= ILClone(This
->pidl
);
522 return E_OUTOFMEMORY
;
525 static const IPersistIDListVtbl ShellItem_IPersistIDList_Vtbl
= {
526 ShellItem_IPersistIDList_QueryInterface
,
527 ShellItem_IPersistIDList_AddRef
,
528 ShellItem_IPersistIDList_Release
,
529 ShellItem_IPersistIDList_GetClassID
,
530 ShellItem_IPersistIDList_SetIDList
,
531 ShellItem_IPersistIDList_GetIDList
535 HRESULT WINAPI
IShellItem_Constructor(IUnknown
*pUnkOuter
, REFIID riid
, void **ppv
)
540 TRACE("(%p,%s)\n",pUnkOuter
, debugstr_guid(riid
));
544 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
546 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem
));
547 This
->IShellItem2_iface
.lpVtbl
= &ShellItem2_Vtbl
;
550 This
->IPersistIDList_iface
.lpVtbl
= &ShellItem_IPersistIDList_Vtbl
;
552 ret
= IShellItem2_QueryInterface(&This
->IShellItem2_iface
, riid
, ppv
);
553 IShellItem2_Release(&This
->IShellItem2_iface
);
558 HRESULT WINAPI
SHCreateShellItem(LPCITEMIDLIST pidlParent
,
559 IShellFolder
*psfParent
, LPCITEMIDLIST pidl
, IShellItem
**ppsi
)
561 LPITEMIDLIST new_pidl
;
564 TRACE("(%p,%p,%p,%p)\n", pidlParent
, psfParent
, pidl
, ppsi
);
572 else if (pidlParent
|| psfParent
)
574 LPITEMIDLIST temp_parent
=NULL
;
577 IPersistFolder2
* ppf2Parent
;
579 if (FAILED(IShellFolder_QueryInterface(psfParent
, &IID_IPersistFolder2
, (void**)&ppf2Parent
)))
581 FIXME("couldn't get IPersistFolder2 interface of parent\n");
582 return E_NOINTERFACE
;
585 if (FAILED(IPersistFolder2_GetCurFolder(ppf2Parent
, &temp_parent
)))
587 FIXME("couldn't get parent PIDL\n");
588 IPersistFolder2_Release(ppf2Parent
);
589 return E_NOINTERFACE
;
592 pidlParent
= temp_parent
;
593 IPersistFolder2_Release(ppf2Parent
);
596 new_pidl
= ILCombine(pidlParent
, pidl
);
600 return E_OUTOFMEMORY
;
604 new_pidl
= ILClone(pidl
);
606 return E_OUTOFMEMORY
;
609 ret
= SHCreateItemFromIDList(new_pidl
, &IID_IShellItem
, (void**)ppsi
);
615 HRESULT WINAPI
SHCreateItemFromParsingName(PCWSTR pszPath
,
616 IBindCtx
*pbc
, REFIID riid
, void **ppv
)
623 ret
= SHParseDisplayName(pszPath
, pbc
, &pidl
, 0, NULL
);
626 ret
= SHCreateItemFromIDList(pidl
, riid
, ppv
);
632 HRESULT WINAPI
SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl
, REFIID riid
, void **ppv
)
634 IPersistIDList
*persist
;
641 ret
= IShellItem_Constructor(NULL
, &IID_IPersistIDList
, (void**)&persist
);
645 ret
= IPersistIDList_SetIDList(persist
, pidl
);
648 IPersistIDList_Release(persist
);
652 ret
= IPersistIDList_QueryInterface(persist
, riid
, ppv
);
653 IPersistIDList_Release(persist
);
657 HRESULT WINAPI
SHGetItemFromDataObject(IDataObject
*pdtobj
,
658 DATAOBJ_GET_ITEM_FLAGS dwFlags
, REFIID riid
, void **ppv
)
664 TRACE("%p, %x, %s, %p\n", pdtobj
, dwFlags
, debugstr_guid(riid
), ppv
);
669 fmt
.cfFormat
= RegisterClipboardFormatW(CFSTR_SHELLIDLISTW
);
671 fmt
.dwAspect
= DVASPECT_CONTENT
;
673 fmt
.tymed
= TYMED_HGLOBAL
;
675 ret
= IDataObject_GetData(pdtobj
, &fmt
, &medium
);
678 LPIDA pida
= GlobalLock(medium
.u
.hGlobal
);
680 if((pida
->cidl
> 1 && !(dwFlags
& DOGIF_ONLY_IF_ONE
)) ||
685 /* Get the first pidl (parent + child1) */
686 pidl
= ILCombine((LPCITEMIDLIST
) ((LPBYTE
)pida
+pida
->aoffset
[0]),
687 (LPCITEMIDLIST
) ((LPBYTE
)pida
+pida
->aoffset
[1]));
689 ret
= SHCreateItemFromIDList(pidl
, riid
, ppv
);
697 GlobalUnlock(medium
.u
.hGlobal
);
698 GlobalFree(medium
.u
.hGlobal
);
701 if(FAILED(ret
) && !(dwFlags
& DOGIF_NO_HDROP
))
703 TRACE("Attempting to fall back on CF_HDROP.\n");
705 fmt
.cfFormat
= CF_HDROP
;
707 fmt
.dwAspect
= DVASPECT_CONTENT
;
709 fmt
.tymed
= TYMED_HGLOBAL
;
711 ret
= IDataObject_GetData(pdtobj
, &fmt
, &medium
);
714 DROPFILES
*df
= GlobalLock(medium
.u
.hGlobal
);
715 LPBYTE files
= (LPBYTE
)df
+ df
->pFiles
;
716 BOOL multiple_files
= FALSE
;
721 WCHAR filename
[MAX_PATH
];
722 PCSTR first_file
= (PCSTR
)files
;
723 if(*(files
+ lstrlenA(first_file
) + 1) != 0)
724 multiple_files
= TRUE
;
726 if( !(multiple_files
&& (dwFlags
& DOGIF_ONLY_IF_ONE
)) )
728 MultiByteToWideChar(CP_ACP
, 0, first_file
, -1, filename
, MAX_PATH
);
729 ret
= SHCreateItemFromParsingName(filename
, NULL
, riid
, ppv
);
734 PCWSTR first_file
= (PCWSTR
)files
;
735 if(*((PCWSTR
)files
+ lstrlenW(first_file
) + 1) != 0)
736 multiple_files
= TRUE
;
738 if( !(multiple_files
&& (dwFlags
& DOGIF_ONLY_IF_ONE
)) )
739 ret
= SHCreateItemFromParsingName(first_file
, NULL
, riid
, ppv
);
742 GlobalUnlock(medium
.u
.hGlobal
);
743 GlobalFree(medium
.u
.hGlobal
);
747 if(FAILED(ret
) && !(dwFlags
& DOGIF_NO_URL
))
749 FIXME("Failed to create item, should try CF_URL.\n");
755 HRESULT WINAPI
SHGetItemFromObject(IUnknown
*punk
, REFIID riid
, void **ppv
)
760 ret
= SHGetIDListFromObject(punk
, &pidl
);
763 ret
= SHCreateItemFromIDList(pidl
, riid
, ppv
);
770 /*************************************************************************
771 * IEnumShellItems implementation
774 IEnumShellItems IEnumShellItems_iface
;
777 IShellItemArray
*array
;
780 } IEnumShellItemsImpl
;
782 static inline IEnumShellItemsImpl
*impl_from_IEnumShellItems(IEnumShellItems
*iface
)
784 return CONTAINING_RECORD(iface
, IEnumShellItemsImpl
, IEnumShellItems_iface
);
787 static HRESULT WINAPI
IEnumShellItems_fnQueryInterface(IEnumShellItems
*iface
,
791 IEnumShellItemsImpl
*This
= impl_from_IEnumShellItems(iface
);
792 TRACE("%p (%s, %p)\n", This
, shdebugstr_guid(riid
), ppvObject
);
795 if(IsEqualIID(riid
, &IID_IEnumShellItems
) ||
796 IsEqualIID(riid
, &IID_IUnknown
))
798 *ppvObject
= &This
->IEnumShellItems_iface
;
803 IUnknown_AddRef((IUnknown
*)*ppvObject
);
807 return E_NOINTERFACE
;
810 static ULONG WINAPI
IEnumShellItems_fnAddRef(IEnumShellItems
*iface
)
812 IEnumShellItemsImpl
*This
= impl_from_IEnumShellItems(iface
);
813 LONG ref
= InterlockedIncrement(&This
->ref
);
814 TRACE("%p - ref %d\n", This
, ref
);
819 static ULONG WINAPI
IEnumShellItems_fnRelease(IEnumShellItems
*iface
)
821 IEnumShellItemsImpl
*This
= impl_from_IEnumShellItems(iface
);
822 LONG ref
= InterlockedDecrement(&This
->ref
);
823 TRACE("%p - ref %d\n", This
, ref
);
828 IShellItemArray_Release(This
->array
);
829 HeapFree(GetProcessHeap(), 0, This
);
836 static HRESULT WINAPI
IEnumShellItems_fnNext(IEnumShellItems
* iface
,
841 IEnumShellItemsImpl
*This
= impl_from_IEnumShellItems(iface
);
842 HRESULT hr
= S_FALSE
;
845 TRACE("%p (%d %p %p)\n", This
, celt
, rgelt
, pceltFetched
);
847 if(pceltFetched
== NULL
&& celt
!= 1)
850 for(i
= This
->position
; fetched
< celt
&& i
< This
->count
; i
++) {
851 hr
= IShellItemArray_GetItemAt(This
->array
, i
, &rgelt
[fetched
]);
860 if(pceltFetched
!= NULL
)
861 *pceltFetched
= fetched
;
872 static HRESULT WINAPI
IEnumShellItems_fnSkip(IEnumShellItems
* iface
, ULONG celt
)
874 IEnumShellItemsImpl
*This
= impl_from_IEnumShellItems(iface
);
875 TRACE("%p (%d)\n", This
, celt
);
877 This
->position
= min(This
->position
+ celt
, This
->count
-1);
882 static HRESULT WINAPI
IEnumShellItems_fnReset(IEnumShellItems
* iface
)
884 IEnumShellItemsImpl
*This
= impl_from_IEnumShellItems(iface
);
892 static HRESULT WINAPI
IEnumShellItems_fnClone(IEnumShellItems
* iface
, IEnumShellItems
**ppenum
)
894 IEnumShellItemsImpl
*This
= impl_from_IEnumShellItems(iface
);
895 TRACE("%p (%p)\n", This
, ppenum
);
897 /* Not implemented anywhere */
903 static const IEnumShellItemsVtbl vt_IEnumShellItems
= {
904 IEnumShellItems_fnQueryInterface
,
905 IEnumShellItems_fnAddRef
,
906 IEnumShellItems_fnRelease
,
907 IEnumShellItems_fnNext
,
908 IEnumShellItems_fnSkip
,
909 IEnumShellItems_fnReset
,
910 IEnumShellItems_fnClone
913 static HRESULT
IEnumShellItems_Constructor(IShellItemArray
*array
, IEnumShellItems
**ppesi
)
915 IEnumShellItemsImpl
*This
;
918 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumShellItemsImpl
));
920 return E_OUTOFMEMORY
;
923 This
->IEnumShellItems_iface
.lpVtbl
= &vt_IEnumShellItems
;
927 IShellItemArray_AddRef(This
->array
);
928 IShellItemArray_GetCount(This
->array
, &This
->count
);
930 ret
= IEnumShellItems_QueryInterface(&This
->IEnumShellItems_iface
, &IID_IEnumShellItems
, (void**)ppesi
);
931 IEnumShellItems_Release(&This
->IEnumShellItems_iface
);
937 /*************************************************************************
938 * IShellItemArray implementation
941 IShellItemArray IShellItemArray_iface
;
946 } IShellItemArrayImpl
;
948 static inline IShellItemArrayImpl
*impl_from_IShellItemArray(IShellItemArray
*iface
)
950 return CONTAINING_RECORD(iface
, IShellItemArrayImpl
, IShellItemArray_iface
);
953 static HRESULT WINAPI
IShellItemArray_fnQueryInterface(IShellItemArray
*iface
,
957 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
958 TRACE("%p (%s, %p)\n", This
, shdebugstr_guid(riid
), ppvObject
);
961 if(IsEqualIID(riid
, &IID_IShellItemArray
) ||
962 IsEqualIID(riid
, &IID_IUnknown
))
964 *ppvObject
= &This
->IShellItemArray_iface
;
969 IUnknown_AddRef((IUnknown
*)*ppvObject
);
973 return E_NOINTERFACE
;
976 static ULONG WINAPI
IShellItemArray_fnAddRef(IShellItemArray
*iface
)
978 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
979 LONG ref
= InterlockedIncrement(&This
->ref
);
980 TRACE("%p - ref %d\n", This
, ref
);
985 static ULONG WINAPI
IShellItemArray_fnRelease(IShellItemArray
*iface
)
987 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
988 LONG ref
= InterlockedDecrement(&This
->ref
);
989 TRACE("%p - ref %d\n", This
, ref
);
996 for(i
= 0; i
< This
->item_count
; i
++)
997 IShellItem_Release(This
->array
[i
]);
999 HeapFree(GetProcessHeap(), 0, This
->array
);
1000 HeapFree(GetProcessHeap(), 0, This
);
1007 static HRESULT WINAPI
IShellItemArray_fnBindToHandler(IShellItemArray
*iface
,
1013 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
1014 FIXME("Stub: %p (%p, %s, %s, %p)\n",
1015 This
, pbc
, shdebugstr_guid(bhid
), shdebugstr_guid(riid
), ppvOut
);
1020 static HRESULT WINAPI
IShellItemArray_fnGetPropertyStore(IShellItemArray
*iface
,
1021 GETPROPERTYSTOREFLAGS flags
,
1025 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
1026 FIXME("Stub: %p (%x, %s, %p)\n", This
, flags
, shdebugstr_guid(riid
), ppv
);
1031 static HRESULT WINAPI
IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray
*iface
,
1032 REFPROPERTYKEY keyType
,
1036 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
1037 FIXME("Stub: %p (%p, %s, %p)\n",
1038 This
, keyType
, shdebugstr_guid(riid
), ppv
);
1043 static HRESULT WINAPI
IShellItemArray_fnGetAttributes(IShellItemArray
*iface
,
1044 SIATTRIBFLAGS AttribFlags
,
1046 SFGAOF
*psfgaoAttribs
)
1048 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
1052 TRACE("%p (%x, %x, %p)\n", This
, AttribFlags
, sfgaoMask
, psfgaoAttribs
);
1054 if(AttribFlags
& ~(SIATTRIBFLAGS_AND
|SIATTRIBFLAGS_OR
))
1055 FIXME("%08x contains unsupported attribution flags\n", AttribFlags
);
1057 for(i
= 0; i
< This
->item_count
; i
++)
1059 hr
= IShellItem_GetAttributes(This
->array
[i
], sfgaoMask
, &attr
);
1065 *psfgaoAttribs
= attr
;
1069 switch(AttribFlags
& SIATTRIBFLAGS_MASK
)
1071 case SIATTRIBFLAGS_AND
:
1072 *psfgaoAttribs
&= attr
;
1074 case SIATTRIBFLAGS_OR
:
1075 *psfgaoAttribs
|= attr
;
1082 if(*psfgaoAttribs
== sfgaoMask
)
1091 static HRESULT WINAPI
IShellItemArray_fnGetCount(IShellItemArray
*iface
,
1094 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
1095 TRACE("%p (%p)\n", This
, pdwNumItems
);
1097 *pdwNumItems
= This
->item_count
;
1102 static HRESULT WINAPI
IShellItemArray_fnGetItemAt(IShellItemArray
*iface
,
1106 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
1107 TRACE("%p (%x, %p)\n", This
, dwIndex
, ppsi
);
1110 if(dwIndex
+ 1 > This
->item_count
)
1113 *ppsi
= This
->array
[dwIndex
];
1114 IShellItem_AddRef(*ppsi
);
1119 static HRESULT WINAPI
IShellItemArray_fnEnumItems(IShellItemArray
*iface
,
1120 IEnumShellItems
**ppenumShellItems
)
1122 IShellItemArrayImpl
*This
= impl_from_IShellItemArray(iface
);
1123 TRACE("%p (%p)\n", This
, ppenumShellItems
);
1124 return IEnumShellItems_Constructor(iface
, ppenumShellItems
);
1127 static const IShellItemArrayVtbl vt_IShellItemArray
= {
1128 IShellItemArray_fnQueryInterface
,
1129 IShellItemArray_fnAddRef
,
1130 IShellItemArray_fnRelease
,
1131 IShellItemArray_fnBindToHandler
,
1132 IShellItemArray_fnGetPropertyStore
,
1133 IShellItemArray_fnGetPropertyDescriptionList
,
1134 IShellItemArray_fnGetAttributes
,
1135 IShellItemArray_fnGetCount
,
1136 IShellItemArray_fnGetItemAt
,
1137 IShellItemArray_fnEnumItems
1140 /* Caller is responsible to AddRef all items */
1141 static HRESULT
create_shellitemarray(IShellItem
**items
, DWORD count
, IShellItemArray
**ret
)
1143 IShellItemArrayImpl
*This
;
1145 TRACE("(%p, %d, %p)\n", items
, count
, ret
);
1147 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl
));
1149 return E_OUTOFMEMORY
;
1151 This
->IShellItemArray_iface
.lpVtbl
= &vt_IShellItemArray
;
1154 This
->array
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(IShellItem
*));
1157 HeapFree(GetProcessHeap(), 0, This
);
1158 return E_OUTOFMEMORY
;
1160 memcpy(This
->array
, items
, count
*sizeof(IShellItem
*));
1161 This
->item_count
= count
;
1163 *ret
= &This
->IShellItemArray_iface
;
1167 HRESULT WINAPI
SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent
,
1170 PCUITEMID_CHILD_ARRAY ppidl
,
1171 IShellItemArray
**ppsiItemArray
)
1174 HRESULT ret
= E_FAIL
;
1177 TRACE("%p, %p, %d, %p, %p\n", pidlParent
, psf
, cidl
, ppidl
, ppsiItemArray
);
1179 *ppsiItemArray
= NULL
;
1181 if(!pidlParent
&& !psf
)
1185 return E_INVALIDARG
;
1187 array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cidl
*sizeof(IShellItem
*));
1189 return E_OUTOFMEMORY
;
1191 for(i
= 0; i
< cidl
; i
++)
1193 ret
= SHCreateShellItem(pidlParent
, psf
, ppidl
[i
], &array
[i
]);
1194 if(FAILED(ret
)) break;
1199 ret
= create_shellitemarray(array
, cidl
, ppsiItemArray
);
1200 HeapFree(GetProcessHeap(), 0, array
);
1205 /* Something failed, clean up. */
1206 for(i
= 0; i
< cidl
; i
++)
1207 if(array
[i
]) IShellItem_Release(array
[i
]);
1208 HeapFree(GetProcessHeap(), 0, array
);
1212 HRESULT WINAPI
SHCreateShellItemArrayFromShellItem(IShellItem
*item
, REFIID riid
, void **ppv
)
1214 IShellItemArray
*array
;
1217 TRACE("%p, %s, %p\n", item
, shdebugstr_guid(riid
), ppv
);
1221 IShellItem_AddRef(item
);
1222 ret
= create_shellitemarray(&item
, 1, &array
);
1225 IShellItem_Release(item
);
1229 ret
= IShellItemArray_QueryInterface(array
, riid
, ppv
);
1230 IShellItemArray_Release(array
);
1234 HRESULT WINAPI
SHCreateShellItemArrayFromDataObject(IDataObject
*pdo
, REFIID riid
, void **ppv
)
1236 IShellItemArray
*psia
;
1241 TRACE("%p, %s, %p\n", pdo
, shdebugstr_guid(riid
), ppv
);
1244 return E_INVALIDARG
;
1248 fmt
.cfFormat
= RegisterClipboardFormatW(CFSTR_SHELLIDLISTW
);
1250 fmt
.dwAspect
= DVASPECT_CONTENT
;
1252 fmt
.tymed
= TYMED_HGLOBAL
;
1254 ret
= IDataObject_GetData(pdo
, &fmt
, &medium
);
1257 LPIDA pida
= GlobalLock(medium
.u
.hGlobal
);
1258 LPCITEMIDLIST parent_pidl
;
1259 LPCITEMIDLIST
*children
;
1261 TRACE("Converting %d objects.\n", pida
->cidl
);
1263 parent_pidl
= (LPCITEMIDLIST
) ((LPBYTE
)pida
+pida
->aoffset
[0]);
1265 children
= HeapAlloc(GetProcessHeap(), 0, sizeof(LPCITEMIDLIST
)*pida
->cidl
);
1266 for(i
= 0; i
< pida
->cidl
; i
++)
1267 children
[i
] = (LPCITEMIDLIST
) ((LPBYTE
)pida
+pida
->aoffset
[i
+1]);
1269 ret
= SHCreateShellItemArray(parent_pidl
, NULL
, pida
->cidl
, children
, &psia
);
1271 HeapFree(GetProcessHeap(), 0, children
);
1273 GlobalUnlock(medium
.u
.hGlobal
);
1274 GlobalFree(medium
.u
.hGlobal
);
1279 ret
= IShellItemArray_QueryInterface(psia
, riid
, ppv
);
1280 IShellItemArray_Release(psia
);
1286 HRESULT WINAPI
SHCreateShellItemArrayFromIDLists(UINT cidl
,
1287 PCIDLIST_ABSOLUTE_ARRAY pidl_array
,
1288 IShellItemArray
**psia
)
1293 TRACE("%d, %p, %p\n", cidl
, pidl_array
, psia
);
1298 return E_INVALIDARG
;
1300 array
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cidl
*sizeof(IShellItem
*));
1302 return E_OUTOFMEMORY
;
1304 for(i
= 0; i
< cidl
; i
++)
1306 ret
= SHCreateShellItem(NULL
, NULL
, pidl_array
[i
], &array
[i
]);
1313 ret
= create_shellitemarray(array
, cidl
, psia
);
1314 HeapFree(GetProcessHeap(), 0, array
);
1319 for(i
= 0; i
< cidl
; i
++)
1320 if(array
[i
]) IShellItem_Release(array
[i
]);
1321 HeapFree(GetProcessHeap(), 0, array
);