msvcrt: Added _splitpath_s implementation.
[wine.git] / dlls / shell32 / shellitem.c
blobd9e7e7b68773e82ba140219f8a1c2f9d35334794
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdio.h>
25 #include <stdarg.h>
27 #define COBJMACROS
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wine/debug.h"
35 #include "pidl.h"
36 #include "shell32_main.h"
37 #include "debughlp.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(shell);
41 typedef struct _ShellItem {
42 const IShellItemVtbl *lpIShellItemVtbl;
43 LONG ref;
44 LPITEMIDLIST pidl;
45 const IPersistIDListVtbl *lpIPersistIDListVtbl;
46 } ShellItem;
49 static inline ShellItem *impl_from_IPersistIDList( IPersistIDList *iface )
51 return (ShellItem*)((char*)iface - FIELD_OFFSET(ShellItem, lpIPersistIDListVtbl));
55 static HRESULT WINAPI ShellItem_QueryInterface(IShellItem *iface, REFIID riid,
56 void **ppv)
58 ShellItem *This = (ShellItem*)iface;
60 TRACE("(%p,%p,%p)\n", iface, riid, ppv);
62 if (!ppv) return E_INVALIDARG;
64 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellItem, riid))
66 *ppv = This;
68 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistIDList, riid))
70 *ppv = &(This->lpIPersistIDListVtbl);
72 else {
73 FIXME("not implemented for %s\n", shdebugstr_guid(riid));
74 *ppv = NULL;
75 return E_NOINTERFACE;
78 IUnknown_AddRef((IUnknown*)*ppv);
79 return S_OK;
82 static ULONG WINAPI ShellItem_AddRef(IShellItem *iface)
84 ShellItem *This = (ShellItem*)iface;
85 ULONG ref = InterlockedIncrement(&This->ref);
87 TRACE("(%p), new refcount=%i\n", iface, ref);
89 return ref;
92 static ULONG WINAPI ShellItem_Release(IShellItem *iface)
94 ShellItem *This = (ShellItem*)iface;
95 ULONG ref = InterlockedDecrement(&This->ref);
97 TRACE("(%p), new refcount=%i\n", iface, ref);
99 if (ref == 0)
101 ILFree(This->pidl);
102 HeapFree(GetProcessHeap(), 0, This);
105 return ref;
108 static HRESULT ShellItem_get_parent_pidl(ShellItem *This, LPITEMIDLIST *parent_pidl)
110 *parent_pidl = ILClone(This->pidl);
111 if (*parent_pidl)
113 if (ILRemoveLastID(*parent_pidl))
114 return S_OK;
115 else
117 ILFree(*parent_pidl);
118 *parent_pidl = NULL;
119 return E_INVALIDARG;
122 else
124 *parent_pidl = NULL;
125 return E_OUTOFMEMORY;
129 static HRESULT ShellItem_get_parent_shellfolder(ShellItem *This, IShellFolder **ppsf)
131 LPITEMIDLIST parent_pidl;
132 IShellFolder *desktop;
133 HRESULT ret;
135 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
136 if (SUCCEEDED(ret))
138 ret = SHGetDesktopFolder(&desktop);
139 if (SUCCEEDED(ret))
141 ret = IShellFolder_BindToObject(desktop, parent_pidl, NULL, &IID_IShellFolder, (void**)ppsf);
142 IShellFolder_Release(desktop);
144 ILFree(parent_pidl);
147 return ret;
150 static HRESULT ShellItem_get_shellfolder(ShellItem *This, IBindCtx *pbc, IShellFolder **ppsf)
152 IShellFolder *desktop;
153 HRESULT ret;
155 ret = SHGetDesktopFolder(&desktop);
156 if (SUCCEEDED(ret))
158 if (_ILIsDesktop(This->pidl))
160 *ppsf = desktop;
161 IShellFolder_AddRef(*ppsf);
163 else
165 ret = IShellFolder_BindToObject(desktop, This->pidl, pbc, &IID_IShellFolder, (void**)ppsf);
168 IShellFolder_Release(desktop);
171 return ret;
174 static HRESULT WINAPI ShellItem_BindToHandler(IShellItem *iface, IBindCtx *pbc,
175 REFGUID rbhid, REFIID riid, void **ppvOut)
177 ShellItem *This = (ShellItem*)iface;
178 HRESULT ret;
179 TRACE("(%p,%p,%s,%p,%p)\n", iface, pbc, shdebugstr_guid(rbhid), riid, ppvOut);
181 *ppvOut = NULL;
182 if (IsEqualGUID(rbhid, &BHID_SFObject))
184 IShellFolder *psf;
185 ret = ShellItem_get_shellfolder(This, pbc, &psf);
186 if (SUCCEEDED(ret))
188 ret = IShellFolder_QueryInterface(psf, riid, ppvOut);
189 IShellFolder_Release(psf);
191 return ret;
193 else if (IsEqualGUID(rbhid, &BHID_SFUIObject))
195 IShellFolder *psf_parent;
196 if (_ILIsDesktop(This->pidl))
197 ret = SHGetDesktopFolder(&psf_parent);
198 else
199 ret = ShellItem_get_parent_shellfolder(This, &psf_parent);
201 if (SUCCEEDED(ret))
203 LPCITEMIDLIST pidl = ILFindLastID(This->pidl);
204 ret = IShellFolder_GetUIObjectOf(psf_parent, NULL, 1, &pidl, riid, NULL, ppvOut);
205 IShellFolder_Release(psf_parent);
207 return ret;
209 else if (IsEqualGUID(rbhid, &BHID_DataObject))
211 return ShellItem_BindToHandler((IShellItem*)This, pbc, &BHID_SFUIObject, &IID_IDataObject, ppvOut);
214 FIXME("Unsupported BHID %s.\n", debugstr_guid(rbhid));
216 return MK_E_NOOBJECT;
219 static HRESULT WINAPI ShellItem_GetParent(IShellItem *iface, IShellItem **ppsi)
221 ShellItem *This = (ShellItem*)iface;
222 LPITEMIDLIST parent_pidl;
223 HRESULT ret;
225 TRACE("(%p,%p)\n", iface, ppsi);
227 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
228 if (SUCCEEDED(ret))
230 ret = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi);
231 ILFree(parent_pidl);
234 return ret;
237 static HRESULT WINAPI ShellItem_GetDisplayName(IShellItem *iface, SIGDN sigdnName,
238 LPWSTR *ppszName)
240 ShellItem *This = (ShellItem*)iface;
241 TRACE("(%p,%x,%p)\n", iface, sigdnName, ppszName);
243 return SHGetNameFromIDList(This->pidl, sigdnName, ppszName);
246 static HRESULT WINAPI ShellItem_GetAttributes(IShellItem *iface, SFGAOF sfgaoMask,
247 SFGAOF *psfgaoAttribs)
249 ShellItem *This = (ShellItem*)iface;
250 IShellFolder *parent_folder;
251 LPITEMIDLIST child_pidl;
252 HRESULT ret;
254 TRACE("(%p,%x,%p)\n", iface, sfgaoMask, psfgaoAttribs);
256 ret = ShellItem_get_parent_shellfolder(This, &parent_folder);
257 if (SUCCEEDED(ret))
259 child_pidl = ILFindLastID(This->pidl);
260 *psfgaoAttribs = sfgaoMask;
261 ret = IShellFolder_GetAttributesOf(parent_folder, 1, (LPCITEMIDLIST*)&child_pidl, psfgaoAttribs);
262 IShellFolder_Release(parent_folder);
265 return ret;
268 static HRESULT WINAPI ShellItem_Compare(IShellItem *iface, IShellItem *oth,
269 SICHINTF hint, int *piOrder)
271 LPWSTR dispname, dispname_oth;
272 HRESULT ret;
273 TRACE("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder);
275 if(hint & (SICHINT_CANONICAL | SICHINT_ALLFIELDS))
276 FIXME("Unsupported flags 0x%08x\n", hint);
278 ret = IShellItem_GetDisplayName(iface, SIGDN_DESKTOPABSOLUTEEDITING, &dispname);
279 if(SUCCEEDED(ret))
281 ret = IShellItem_GetDisplayName(oth, SIGDN_DESKTOPABSOLUTEEDITING, &dispname_oth);
282 if(SUCCEEDED(ret))
284 *piOrder = lstrcmpiW(dispname, dispname_oth);
285 CoTaskMemFree(dispname_oth);
287 CoTaskMemFree(dispname);
290 if(SUCCEEDED(ret) && *piOrder &&
291 (hint & SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL))
293 LPWSTR dispname, dispname_oth;
295 TRACE("Testing filesystem path.\n");
296 ret = IShellItem_GetDisplayName(iface, SIGDN_FILESYSPATH, &dispname);
297 if(SUCCEEDED(ret))
299 ret = IShellItem_GetDisplayName(oth, SIGDN_FILESYSPATH, &dispname_oth);
300 if(SUCCEEDED(ret))
302 *piOrder = lstrcmpiW(dispname, dispname_oth);
303 CoTaskMemFree(dispname_oth);
305 CoTaskMemFree(dispname);
309 if(FAILED(ret))
310 return ret;
312 if(*piOrder)
313 return S_FALSE;
314 else
315 return S_OK;
318 static const IShellItemVtbl ShellItem_Vtbl = {
319 ShellItem_QueryInterface,
320 ShellItem_AddRef,
321 ShellItem_Release,
322 ShellItem_BindToHandler,
323 ShellItem_GetParent,
324 ShellItem_GetDisplayName,
325 ShellItem_GetAttributes,
326 ShellItem_Compare
330 static HRESULT ShellItem_GetClassID(ShellItem* This, CLSID *pClassID)
332 TRACE("(%p,%p)\n", This, pClassID);
334 *pClassID = CLSID_ShellItem;
335 return S_OK;
339 static HRESULT WINAPI ShellItem_IPersistIDList_QueryInterface(IPersistIDList *iface,
340 REFIID riid, void **ppv)
342 ShellItem *This = impl_from_IPersistIDList(iface);
343 return ShellItem_QueryInterface((IShellItem*)This, riid, ppv);
346 static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface)
348 ShellItem *This = impl_from_IPersistIDList(iface);
349 return ShellItem_AddRef((IShellItem*)This);
352 static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface)
354 ShellItem *This = impl_from_IPersistIDList(iface);
355 return ShellItem_Release((IShellItem*)This);
358 static HRESULT WINAPI ShellItem_IPersistIDList_GetClassID(IPersistIDList* iface,
359 CLSID *pClassID)
361 ShellItem *This = impl_from_IPersistIDList(iface);
363 return ShellItem_GetClassID(This, pClassID);
366 static HRESULT WINAPI ShellItem_IPersistIDList_SetIDList(IPersistIDList* iface,
367 LPCITEMIDLIST pidl)
369 ShellItem *This = impl_from_IPersistIDList(iface);
370 LPITEMIDLIST new_pidl;
372 TRACE("(%p,%p)\n", This, pidl);
374 new_pidl = ILClone(pidl);
376 if (new_pidl)
378 ILFree(This->pidl);
379 This->pidl = new_pidl;
380 return S_OK;
382 else
383 return E_OUTOFMEMORY;
386 static HRESULT WINAPI ShellItem_IPersistIDList_GetIDList(IPersistIDList* iface,
387 LPITEMIDLIST *ppidl)
389 ShellItem *This = impl_from_IPersistIDList(iface);
391 TRACE("(%p,%p)\n", This, ppidl);
393 *ppidl = ILClone(This->pidl);
394 if (*ppidl)
395 return S_OK;
396 else
397 return E_OUTOFMEMORY;
400 static const IPersistIDListVtbl ShellItem_IPersistIDList_Vtbl = {
401 ShellItem_IPersistIDList_QueryInterface,
402 ShellItem_IPersistIDList_AddRef,
403 ShellItem_IPersistIDList_Release,
404 ShellItem_IPersistIDList_GetClassID,
405 ShellItem_IPersistIDList_SetIDList,
406 ShellItem_IPersistIDList_GetIDList
410 HRESULT WINAPI IShellItem_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
412 ShellItem *This;
413 HRESULT ret;
415 TRACE("(%p,%s)\n",pUnkOuter, debugstr_guid(riid));
417 *ppv = NULL;
419 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
421 This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem));
422 This->lpIShellItemVtbl = &ShellItem_Vtbl;
423 This->ref = 1;
424 This->pidl = NULL;
425 This->lpIPersistIDListVtbl = &ShellItem_IPersistIDList_Vtbl;
427 ret = ShellItem_QueryInterface((IShellItem*)This, riid, ppv);
428 ShellItem_Release((IShellItem*)This);
430 return ret;
433 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
434 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
436 ShellItem *This;
437 LPITEMIDLIST new_pidl;
438 HRESULT ret;
440 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
442 if (!pidl)
444 return E_INVALIDARG;
446 else if (pidlParent || psfParent)
448 LPITEMIDLIST temp_parent=NULL;
449 if (!pidlParent)
451 IPersistFolder2* ppf2Parent;
453 if (FAILED(IPersistFolder2_QueryInterface(psfParent, &IID_IPersistFolder2, (void**)&ppf2Parent)))
455 FIXME("couldn't get IPersistFolder2 interface of parent\n");
456 return E_NOINTERFACE;
459 if (FAILED(IPersistFolder2_GetCurFolder(ppf2Parent, &temp_parent)))
461 FIXME("couldn't get parent PIDL\n");
462 IPersistFolder2_Release(ppf2Parent);
463 return E_NOINTERFACE;
466 pidlParent = temp_parent;
467 IPersistFolder2_Release(ppf2Parent);
470 new_pidl = ILCombine(pidlParent, pidl);
471 ILFree(temp_parent);
473 if (!new_pidl)
474 return E_OUTOFMEMORY;
476 else
478 new_pidl = ILClone(pidl);
479 if (!new_pidl)
480 return E_OUTOFMEMORY;
483 ret = IShellItem_Constructor(NULL, &IID_IShellItem, (void**)&This);
484 if (This)
486 *ppsi = (IShellItem*)This;
487 This->pidl = new_pidl;
489 else
491 *ppsi = NULL;
492 ILFree(new_pidl);
494 return ret;
497 HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath,
498 IBindCtx *pbc, REFIID riid, void **ppv)
500 LPITEMIDLIST pidl;
501 HRESULT ret;
503 *ppv = NULL;
505 ret = SHParseDisplayName(pszPath, pbc, &pidl, 0, NULL);
506 if(SUCCEEDED(ret))
508 ShellItem *This;
509 ret = IShellItem_Constructor(NULL, riid, (void**)&This);
511 if(SUCCEEDED(ret))
513 This->pidl = pidl;
514 *ppv = (void*)This;
516 else
518 ILFree(pidl);
521 return ret;
524 HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv)
526 ShellItem *psiimpl;
527 HRESULT ret;
529 if(!pidl)
530 return E_INVALIDARG;
532 ret = IShellItem_Constructor(NULL, riid, ppv);
533 if(SUCCEEDED(ret))
535 psiimpl = (ShellItem*)*ppv;
536 psiimpl->pidl = ILClone(pidl);
539 return ret;
542 HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj,
543 DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv)
545 FORMATETC fmt;
546 STGMEDIUM medium;
547 HRESULT ret;
549 TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(riid), ppv);
551 if(!pdtobj)
552 return E_INVALIDARG;
554 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
555 fmt.ptd = NULL;
556 fmt.dwAspect = DVASPECT_CONTENT;
557 fmt.lindex = -1;
558 fmt.tymed = TYMED_HGLOBAL;
560 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
561 if(SUCCEEDED(ret))
563 LPIDA pida = GlobalLock(medium.u.hGlobal);
565 if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) ||
566 pida->cidl == 1)
568 LPITEMIDLIST pidl;
570 /* Get the first pidl (parent + child1) */
571 pidl = ILCombine((LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]),
572 (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]));
574 ret = SHCreateItemFromIDList(pidl, riid, ppv);
575 ILFree(pidl);
577 else
579 ret = E_FAIL;
582 GlobalUnlock(medium.u.hGlobal);
583 GlobalFree(medium.u.hGlobal);
586 if(FAILED(ret) && !(dwFlags & DOGIF_NO_HDROP))
588 TRACE("Attempting to fall back on CF_HDROP.\n");
590 fmt.cfFormat = CF_HDROP;
591 fmt.ptd = NULL;
592 fmt.dwAspect = DVASPECT_CONTENT;
593 fmt.lindex = -1;
594 fmt.tymed = TYMED_HGLOBAL;
596 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
597 if(SUCCEEDED(ret))
599 DROPFILES *df = GlobalLock(medium.u.hGlobal);
600 LPBYTE files = (LPBYTE)df + df->pFiles;
601 BOOL multiple_files = FALSE;
603 ret = E_FAIL;
604 if(!df->fWide)
606 WCHAR filename[MAX_PATH];
607 PCSTR first_file = (PCSTR)files;
608 if(*(files + lstrlenA(first_file) + 1) != 0)
609 multiple_files = TRUE;
611 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
613 MultiByteToWideChar(CP_ACP, 0, first_file, -1, filename, MAX_PATH);
614 ret = SHCreateItemFromParsingName(filename, NULL, riid, ppv);
617 else
619 PCWSTR first_file = (PCWSTR)files;
620 if(*((PCWSTR)files + lstrlenW(first_file) + 1) != 0)
621 multiple_files = TRUE;
623 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
624 ret = SHCreateItemFromParsingName(first_file, NULL, riid, ppv);
627 GlobalUnlock(medium.u.hGlobal);
628 GlobalFree(medium.u.hGlobal);
632 if(FAILED(ret) && !(dwFlags & DOGIF_NO_URL))
634 FIXME("Failed to create item, should try CF_URL.\n");
637 return ret;
640 HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
642 LPITEMIDLIST pidl;
643 HRESULT ret;
645 ret = SHGetIDListFromObject(punk, &pidl);
646 if(SUCCEEDED(ret))
648 ret = SHCreateItemFromIDList(pidl, riid, ppv);
649 ILFree(pidl);
652 return ret;
655 /*************************************************************************
656 * IShellItemArray implementation
658 typedef struct {
659 const IShellItemArrayVtbl *lpVtbl;
660 LONG ref;
662 IShellItem **array;
663 DWORD item_count;
664 } IShellItemArrayImpl;
666 static HRESULT WINAPI IShellItemArray_fnQueryInterface(IShellItemArray *iface,
667 REFIID riid,
668 void **ppvObject)
670 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
671 TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
673 *ppvObject = NULL;
674 if(IsEqualIID(riid, &IID_IShellItemArray) ||
675 IsEqualIID(riid, &IID_IUnknown))
677 *ppvObject = This;
680 if(*ppvObject)
682 IUnknown_AddRef((IUnknown*)*ppvObject);
683 return S_OK;
686 return E_NOINTERFACE;
689 static ULONG WINAPI IShellItemArray_fnAddRef(IShellItemArray *iface)
691 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
692 LONG ref = InterlockedIncrement(&This->ref);
693 TRACE("%p - ref %d\n", This, ref);
695 return ref;
698 static ULONG WINAPI IShellItemArray_fnRelease(IShellItemArray *iface)
700 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
701 LONG ref = InterlockedDecrement(&This->ref);
702 TRACE("%p - ref %d\n", This, ref);
704 if(!ref)
706 UINT i;
707 TRACE("Freeing.\n");
709 for(i = 0; i < This->item_count; i++)
710 IShellItem_Release(This->array[i]);
712 HeapFree(GetProcessHeap(), 0, This->array);
713 HeapFree(GetProcessHeap(), 0, This);
714 return 0;
717 return ref;
720 static HRESULT WINAPI IShellItemArray_fnBindToHandler(IShellItemArray *iface,
721 IBindCtx *pbc,
722 REFGUID bhid,
723 REFIID riid,
724 void **ppvOut)
726 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
727 FIXME("Stub: %p (%p, %s, %s, %p)\n",
728 This, pbc, shdebugstr_guid(bhid), shdebugstr_guid(riid), ppvOut);
730 return E_NOTIMPL;
733 static HRESULT WINAPI IShellItemArray_fnGetPropertyStore(IShellItemArray *iface,
734 GETPROPERTYSTOREFLAGS flags,
735 REFIID riid,
736 void **ppv)
738 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
739 FIXME("Stub: %p (%x, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
741 return E_NOTIMPL;
744 static HRESULT WINAPI IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray *iface,
745 REFPROPERTYKEY keyType,
746 REFIID riid,
747 void **ppv)
749 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
750 FIXME("Stub: %p (%p, %s, %p)\n",
751 This, keyType, shdebugstr_guid(riid), ppv);
753 return E_NOTIMPL;
756 static HRESULT WINAPI IShellItemArray_fnGetAttributes(IShellItemArray *iface,
757 SIATTRIBFLAGS AttribFlags,
758 SFGAOF sfgaoMask,
759 SFGAOF *psfgaoAttribs)
761 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
762 FIXME("Stub: %p (%x, %x, %p)\n", This, AttribFlags, sfgaoMask, psfgaoAttribs);
764 return E_NOTIMPL;
767 static HRESULT WINAPI IShellItemArray_fnGetCount(IShellItemArray *iface,
768 DWORD *pdwNumItems)
770 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
771 TRACE("%p (%p)\n", This, pdwNumItems);
773 *pdwNumItems = This->item_count;
775 return S_OK;
778 static HRESULT WINAPI IShellItemArray_fnGetItemAt(IShellItemArray *iface,
779 DWORD dwIndex,
780 IShellItem **ppsi)
782 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
783 TRACE("%p (%x, %p)\n", This, dwIndex, ppsi);
785 /* zero indexed */
786 if(dwIndex + 1 > This->item_count)
787 return E_FAIL;
789 *ppsi = This->array[dwIndex];
790 IShellItem_AddRef(*ppsi);
792 return S_OK;
795 static HRESULT WINAPI IShellItemArray_fnEnumItems(IShellItemArray *iface,
796 IEnumShellItems **ppenumShellItems)
798 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
799 FIXME("Stub: %p (%p)\n", This, ppenumShellItems);
801 return E_NOTIMPL;
804 static const IShellItemArrayVtbl vt_IShellItemArray = {
805 IShellItemArray_fnQueryInterface,
806 IShellItemArray_fnAddRef,
807 IShellItemArray_fnRelease,
808 IShellItemArray_fnBindToHandler,
809 IShellItemArray_fnGetPropertyStore,
810 IShellItemArray_fnGetPropertyDescriptionList,
811 IShellItemArray_fnGetAttributes,
812 IShellItemArray_fnGetCount,
813 IShellItemArray_fnGetItemAt,
814 IShellItemArray_fnEnumItems
817 static HRESULT IShellItemArray_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
819 IShellItemArrayImpl *This;
820 HRESULT ret;
822 TRACE("(%p, %s, %p)\n",pUnkOuter, debugstr_guid(riid), ppv);
824 if(pUnkOuter)
825 return CLASS_E_NOAGGREGATION;
827 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl));
828 if(!This)
829 return E_OUTOFMEMORY;
831 This->ref = 1;
832 This->lpVtbl = &vt_IShellItemArray;
833 This->array = NULL;
834 This->item_count = 0;
836 ret = IShellItemArray_QueryInterface((IShellItemArray*)This, riid, ppv);
837 IShellItemArray_Release((IShellItemArray*)This);
839 return ret;
842 HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent,
843 IShellFolder *psf,
844 UINT cidl,
845 PCUITEMID_CHILD_ARRAY ppidl,
846 IShellItemArray **ppsiItemArray)
848 IShellItemArrayImpl *This;
849 IShellItem **array;
850 HRESULT ret = E_FAIL;
851 UINT i;
853 TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray);
855 if(!pidlParent && !psf)
856 return E_POINTER;
858 if(!ppidl)
859 return E_INVALIDARG;
861 array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*));
862 if(!array)
863 return E_OUTOFMEMORY;
865 for(i = 0; i < cidl; i++)
867 ret = SHCreateShellItem(pidlParent, psf, ppidl[i], &array[i]);
868 if(FAILED(ret)) break;
871 if(SUCCEEDED(ret))
873 ret = IShellItemArray_Constructor(NULL, &IID_IShellItemArray, (void**)&This);
874 if(SUCCEEDED(ret))
876 This->array = array;
877 This->item_count = cidl;
878 *ppsiItemArray = (IShellItemArray*)This;
880 return ret;
884 /* Something failed, clean up. */
885 for(i = 0; i < cidl; i++)
886 if(array[i]) IShellItem_Release(array[i]);
887 HeapFree(GetProcessHeap(), 0, array);
888 *ppsiItemArray = NULL;
889 return ret;
892 HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *psi, REFIID riid, void **ppv)
894 IShellItemArrayImpl *This;
895 IShellItem **array;
896 HRESULT ret;
898 TRACE("%p, %s, %p\n", psi, shdebugstr_guid(riid), ppv);
900 array = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItem*));
901 if(!array)
902 return E_OUTOFMEMORY;
904 ret = IShellItemArray_Constructor(NULL, riid, (void**)&This);
905 if(SUCCEEDED(ret))
907 array[0] = psi;
908 IShellItem_AddRef(psi);
909 This->array = array;
910 This->item_count = 1;
911 *ppv = This;
913 else
915 HeapFree(GetProcessHeap(), 0, array);
916 *ppv = NULL;
919 return ret;
922 HRESULT WINAPI SHCreateShellItemArrayFromDataObject(IDataObject *pdo, REFIID riid, void **ppv)
924 IShellItemArray *psia;
925 FORMATETC fmt;
926 STGMEDIUM medium;
927 HRESULT ret;
929 TRACE("%p, %s, %p\n", pdo, shdebugstr_guid(riid), ppv);
931 if(!pdo)
932 return E_INVALIDARG;
934 *ppv = NULL;
936 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
937 fmt.ptd = NULL;
938 fmt.dwAspect = DVASPECT_CONTENT;
939 fmt.lindex = -1;
940 fmt.tymed = TYMED_HGLOBAL;
942 ret = IDataObject_GetData(pdo, &fmt, &medium);
943 if(SUCCEEDED(ret))
945 LPIDA pida = GlobalLock(medium.u.hGlobal);
946 LPCITEMIDLIST parent_pidl;
947 LPCITEMIDLIST *children;
948 UINT i;
949 TRACE("Converting %d objects.\n", pida->cidl);
951 parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
953 children = HeapAlloc(GetProcessHeap(), 0, sizeof(LPCITEMIDLIST)*pida->cidl);
954 for(i = 0; i < pida->cidl; i++)
955 children[i] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i+1]);
957 ret = SHCreateShellItemArray(parent_pidl, NULL, pida->cidl, children, (IShellItemArray**)&psia);
959 HeapFree(GetProcessHeap(), 0, children);
961 GlobalUnlock(medium.u.hGlobal);
962 GlobalFree(medium.u.hGlobal);
965 if(SUCCEEDED(ret))
967 ret = IShellItemArray_QueryInterface(psia, riid, ppv);
968 IShellItemArray_Release(psia);
971 return ret;