shell32: Forward ShExtractIconsW to user32.PrivateExtractIconsW.
[wine/wine-gecko.git] / dlls / shell32 / shellitem.c
blobf58c5663df0bb18c99011ad0b5be128038b38549
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 IShellItem2 IShellItem2_iface;
43 LONG ref;
44 LPITEMIDLIST pidl;
45 IPersistIDList IPersistIDList_iface;
46 } ShellItem;
48 static inline ShellItem *impl_from_IShellItem2(IShellItem2 *iface)
50 return CONTAINING_RECORD(iface, ShellItem, IShellItem2_iface);
54 static inline ShellItem *impl_from_IPersistIDList( IPersistIDList *iface )
56 return CONTAINING_RECORD(iface, ShellItem, IPersistIDList_iface);
60 static HRESULT WINAPI ShellItem_QueryInterface(IShellItem2 *iface, REFIID riid,
61 void **ppv)
63 ShellItem *This = impl_from_IShellItem2(iface);
65 TRACE("(%p,%p,%p)\n", iface, riid, ppv);
67 if (!ppv) return E_INVALIDARG;
69 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellItem, riid) ||
70 IsEqualIID(&IID_IShellItem2, riid))
72 *ppv = &This->IShellItem2_iface;
74 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistIDList, riid))
76 *ppv = &This->IPersistIDList_iface;
78 else {
79 FIXME("not implemented for %s\n", shdebugstr_guid(riid));
80 *ppv = NULL;
81 return E_NOINTERFACE;
84 IUnknown_AddRef((IUnknown*)*ppv);
85 return S_OK;
88 static ULONG WINAPI ShellItem_AddRef(IShellItem2 *iface)
90 ShellItem *This = impl_from_IShellItem2(iface);
91 ULONG ref = InterlockedIncrement(&This->ref);
93 TRACE("(%p), new refcount=%i\n", iface, ref);
95 return ref;
98 static ULONG WINAPI ShellItem_Release(IShellItem2 *iface)
100 ShellItem *This = impl_from_IShellItem2(iface);
101 ULONG ref = InterlockedDecrement(&This->ref);
103 TRACE("(%p), new refcount=%i\n", iface, ref);
105 if (ref == 0)
107 ILFree(This->pidl);
108 HeapFree(GetProcessHeap(), 0, This);
111 return ref;
114 static HRESULT ShellItem_get_parent_pidl(ShellItem *This, LPITEMIDLIST *parent_pidl)
116 *parent_pidl = ILClone(This->pidl);
117 if (*parent_pidl)
119 if (ILRemoveLastID(*parent_pidl))
120 return S_OK;
121 else
123 ILFree(*parent_pidl);
124 *parent_pidl = NULL;
125 return E_INVALIDARG;
128 else
130 *parent_pidl = NULL;
131 return E_OUTOFMEMORY;
135 static HRESULT ShellItem_get_parent_shellfolder(ShellItem *This, IShellFolder **ppsf)
137 LPITEMIDLIST parent_pidl;
138 IShellFolder *desktop;
139 HRESULT ret;
141 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
142 if (SUCCEEDED(ret))
144 ret = SHGetDesktopFolder(&desktop);
145 if (SUCCEEDED(ret))
147 ret = IShellFolder_BindToObject(desktop, parent_pidl, NULL, &IID_IShellFolder, (void**)ppsf);
148 IShellFolder_Release(desktop);
150 ILFree(parent_pidl);
153 return ret;
156 static HRESULT ShellItem_get_shellfolder(ShellItem *This, IBindCtx *pbc, IShellFolder **ppsf)
158 IShellFolder *desktop;
159 HRESULT ret;
161 ret = SHGetDesktopFolder(&desktop);
162 if (SUCCEEDED(ret))
164 if (_ILIsDesktop(This->pidl))
166 *ppsf = desktop;
167 IShellFolder_AddRef(*ppsf);
169 else
171 ret = IShellFolder_BindToObject(desktop, This->pidl, pbc, &IID_IShellFolder, (void**)ppsf);
174 IShellFolder_Release(desktop);
177 return ret;
180 static HRESULT WINAPI ShellItem_BindToHandler(IShellItem2 *iface, IBindCtx *pbc,
181 REFGUID rbhid, REFIID riid, void **ppvOut)
183 ShellItem *This = impl_from_IShellItem2(iface);
184 HRESULT ret;
185 TRACE("(%p,%p,%s,%p,%p)\n", iface, pbc, shdebugstr_guid(rbhid), riid, ppvOut);
187 *ppvOut = NULL;
188 if (IsEqualGUID(rbhid, &BHID_SFObject))
190 IShellFolder *psf;
191 ret = ShellItem_get_shellfolder(This, pbc, &psf);
192 if (SUCCEEDED(ret))
194 ret = IShellFolder_QueryInterface(psf, riid, ppvOut);
195 IShellFolder_Release(psf);
197 return ret;
199 else if (IsEqualGUID(rbhid, &BHID_SFUIObject))
201 IShellFolder *psf_parent;
202 if (_ILIsDesktop(This->pidl))
203 ret = SHGetDesktopFolder(&psf_parent);
204 else
205 ret = ShellItem_get_parent_shellfolder(This, &psf_parent);
207 if (SUCCEEDED(ret))
209 LPCITEMIDLIST pidl = ILFindLastID(This->pidl);
210 ret = IShellFolder_GetUIObjectOf(psf_parent, NULL, 1, &pidl, riid, NULL, ppvOut);
211 IShellFolder_Release(psf_parent);
213 return ret;
215 else if (IsEqualGUID(rbhid, &BHID_DataObject))
217 return ShellItem_BindToHandler(&This->IShellItem2_iface, pbc, &BHID_SFUIObject,
218 &IID_IDataObject, ppvOut);
221 FIXME("Unsupported BHID %s.\n", debugstr_guid(rbhid));
223 return MK_E_NOOBJECT;
226 static HRESULT WINAPI ShellItem_GetParent(IShellItem2 *iface, IShellItem **ppsi)
228 ShellItem *This = impl_from_IShellItem2(iface);
229 LPITEMIDLIST parent_pidl;
230 HRESULT ret;
232 TRACE("(%p,%p)\n", iface, ppsi);
234 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
235 if (SUCCEEDED(ret))
237 ret = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi);
238 ILFree(parent_pidl);
241 return ret;
244 static HRESULT WINAPI ShellItem_GetDisplayName(IShellItem2 *iface, SIGDN sigdnName,
245 LPWSTR *ppszName)
247 ShellItem *This = impl_from_IShellItem2(iface);
248 TRACE("(%p,%x,%p)\n", iface, sigdnName, ppszName);
250 return SHGetNameFromIDList(This->pidl, sigdnName, ppszName);
253 static HRESULT WINAPI ShellItem_GetAttributes(IShellItem2 *iface, SFGAOF sfgaoMask,
254 SFGAOF *psfgaoAttribs)
256 ShellItem *This = impl_from_IShellItem2(iface);
257 IShellFolder *parent_folder;
258 LPITEMIDLIST child_pidl;
259 HRESULT ret;
261 TRACE("(%p,%x,%p)\n", iface, sfgaoMask, psfgaoAttribs);
263 if (_ILIsDesktop(This->pidl))
264 ret = SHGetDesktopFolder(&parent_folder);
265 else
266 ret = ShellItem_get_parent_shellfolder(This, &parent_folder);
267 if (SUCCEEDED(ret))
269 child_pidl = ILFindLastID(This->pidl);
270 *psfgaoAttribs = sfgaoMask;
271 ret = IShellFolder_GetAttributesOf(parent_folder, 1, (LPCITEMIDLIST*)&child_pidl, psfgaoAttribs);
272 IShellFolder_Release(parent_folder);
275 return ret;
278 static HRESULT WINAPI ShellItem_Compare(IShellItem2 *iface, IShellItem *oth,
279 SICHINTF hint, int *piOrder)
281 LPWSTR dispname, dispname_oth;
282 HRESULT ret;
283 TRACE("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder);
285 if(hint & (SICHINT_CANONICAL | SICHINT_ALLFIELDS))
286 FIXME("Unsupported flags 0x%08x\n", hint);
288 ret = IShellItem2_GetDisplayName(iface, SIGDN_DESKTOPABSOLUTEEDITING, &dispname);
289 if(SUCCEEDED(ret))
291 ret = IShellItem_GetDisplayName(oth, SIGDN_DESKTOPABSOLUTEEDITING, &dispname_oth);
292 if(SUCCEEDED(ret))
294 *piOrder = lstrcmpiW(dispname, dispname_oth);
295 CoTaskMemFree(dispname_oth);
297 CoTaskMemFree(dispname);
300 if(SUCCEEDED(ret) && *piOrder &&
301 (hint & SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL))
303 LPWSTR dispname, dispname_oth;
305 TRACE("Testing filesystem path.\n");
306 ret = IShellItem2_GetDisplayName(iface, SIGDN_FILESYSPATH, &dispname);
307 if(SUCCEEDED(ret))
309 ret = IShellItem_GetDisplayName(oth, SIGDN_FILESYSPATH, &dispname_oth);
310 if(SUCCEEDED(ret))
312 *piOrder = lstrcmpiW(dispname, dispname_oth);
313 CoTaskMemFree(dispname_oth);
315 CoTaskMemFree(dispname);
319 if(FAILED(ret))
320 return ret;
322 if(*piOrder)
323 return S_FALSE;
324 else
325 return S_OK;
328 static HRESULT WINAPI ShellItem2_GetPropertyStore(IShellItem2 *iface, GETPROPERTYSTOREFLAGS flags,
329 REFIID riid, void **ppv)
331 ShellItem *This = impl_from_IShellItem2(iface);
332 FIXME("Stub: %p (%d, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
333 return E_NOTIMPL;
336 static HRESULT WINAPI ShellItem2_GetPropertyStoreWithCreateObject(IShellItem2 *iface,
337 GETPROPERTYSTOREFLAGS flags, IUnknown *punkCreateObject, REFIID riid, void **ppv)
339 ShellItem *This = impl_from_IShellItem2(iface);
340 FIXME("Stub: %p (%08x, %p, %s, %p)\n",
341 This, flags, punkCreateObject, shdebugstr_guid(riid), ppv);
342 return E_NOTIMPL;
345 static HRESULT WINAPI ShellItem2_GetPropertyStoreForKeys(IShellItem2 *iface, const PROPERTYKEY *rgKeys,
346 UINT cKeys, GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv)
348 ShellItem *This = impl_from_IShellItem2(iface);
349 FIXME("Stub: %p (%p, %d, %08x, %s, %p)\n",
350 This, rgKeys, cKeys, flags, shdebugstr_guid(riid), ppv);
351 return E_NOTIMPL;
354 static HRESULT WINAPI ShellItem2_GetPropertyDescriptionList(IShellItem2 *iface,
355 REFPROPERTYKEY keyType, REFIID riid, void **ppv)
357 ShellItem *This = impl_from_IShellItem2(iface);
358 FIXME("Stub: %p (%p, %s, %p)\n", This, keyType, debugstr_guid(riid), ppv);
359 return E_NOTIMPL;
362 static HRESULT WINAPI ShellItem2_Update(IShellItem2 *iface, IBindCtx *pbc)
364 ShellItem *This = impl_from_IShellItem2(iface);
365 FIXME("Stub: %p (%p)\n", This, pbc);
366 return E_NOTIMPL;
369 static HRESULT WINAPI ShellItem2_GetProperty(IShellItem2 *iface, REFPROPERTYKEY key, PROPVARIANT *ppropvar)
371 ShellItem *This = impl_from_IShellItem2(iface);
372 FIXME("Stub: %p (%p, %p)\n", This, key, ppropvar);
373 return E_NOTIMPL;
376 static HRESULT WINAPI ShellItem2_GetCLSID(IShellItem2 *iface, REFPROPERTYKEY key, CLSID *pclsid)
378 ShellItem *This = impl_from_IShellItem2(iface);
379 FIXME("Stub: %p (%p, %p)\n", This, key, pclsid);
380 return E_NOTIMPL;
383 static HRESULT WINAPI ShellItem2_GetFileTime(IShellItem2 *iface, REFPROPERTYKEY key, FILETIME *pft)
385 ShellItem *This = impl_from_IShellItem2(iface);
386 FIXME("Stub: %p (%p, %p)\n", This, key, pft);
387 return E_NOTIMPL;
390 static HRESULT WINAPI ShellItem2_GetInt32(IShellItem2 *iface, REFPROPERTYKEY key, int *pi)
392 ShellItem *This = impl_from_IShellItem2(iface);
393 FIXME("Stub: %p (%p, %p)\n", This, key, pi);
394 return E_NOTIMPL;
397 static HRESULT WINAPI ShellItem2_GetString(IShellItem2 *iface, REFPROPERTYKEY key, LPWSTR *ppsz)
399 ShellItem *This = impl_from_IShellItem2(iface);
400 FIXME("Stub: %p (%p, %p)\n", This, key, ppsz);
401 return E_NOTIMPL;
404 static HRESULT WINAPI ShellItem2_GetUInt32(IShellItem2 *iface, REFPROPERTYKEY key, ULONG *pui)
406 ShellItem *This = impl_from_IShellItem2(iface);
407 FIXME("Stub: %p (%p, %p)\n", This, key, pui);
408 return E_NOTIMPL;
411 static HRESULT WINAPI ShellItem2_GetUInt64(IShellItem2 *iface, REFPROPERTYKEY key, ULONGLONG *pull)
413 ShellItem *This = impl_from_IShellItem2(iface);
414 FIXME("Stub: %p (%p, %p)\n", This, key, pull);
415 return E_NOTIMPL;
418 static HRESULT WINAPI ShellItem2_GetBool(IShellItem2 *iface, REFPROPERTYKEY key, BOOL *pf)
420 ShellItem *This = impl_from_IShellItem2(iface);
421 FIXME("Stub: %p (%p, %p)\n", This, key, pf);
422 return E_NOTIMPL;
426 static const IShellItem2Vtbl ShellItem2_Vtbl = {
427 ShellItem_QueryInterface,
428 ShellItem_AddRef,
429 ShellItem_Release,
430 ShellItem_BindToHandler,
431 ShellItem_GetParent,
432 ShellItem_GetDisplayName,
433 ShellItem_GetAttributes,
434 ShellItem_Compare,
435 ShellItem2_GetPropertyStore,
436 ShellItem2_GetPropertyStoreWithCreateObject,
437 ShellItem2_GetPropertyStoreForKeys,
438 ShellItem2_GetPropertyDescriptionList,
439 ShellItem2_Update,
440 ShellItem2_GetProperty,
441 ShellItem2_GetCLSID,
442 ShellItem2_GetFileTime,
443 ShellItem2_GetInt32,
444 ShellItem2_GetString,
445 ShellItem2_GetUInt32,
446 ShellItem2_GetUInt64,
447 ShellItem2_GetBool
450 static HRESULT WINAPI ShellItem_IPersistIDList_QueryInterface(IPersistIDList *iface,
451 REFIID riid, void **ppv)
453 ShellItem *This = impl_from_IPersistIDList(iface);
454 return IShellItem2_QueryInterface(&This->IShellItem2_iface, riid, ppv);
457 static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface)
459 ShellItem *This = impl_from_IPersistIDList(iface);
460 return IShellItem2_AddRef(&This->IShellItem2_iface);
463 static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface)
465 ShellItem *This = impl_from_IPersistIDList(iface);
466 return IShellItem2_Release(&This->IShellItem2_iface);
469 static HRESULT WINAPI ShellItem_IPersistIDList_GetClassID(IPersistIDList* iface,
470 CLSID *pClassID)
472 *pClassID = CLSID_ShellItem;
473 return S_OK;
476 static HRESULT WINAPI ShellItem_IPersistIDList_SetIDList(IPersistIDList* iface,
477 LPCITEMIDLIST pidl)
479 ShellItem *This = impl_from_IPersistIDList(iface);
480 LPITEMIDLIST new_pidl;
482 TRACE("(%p,%p)\n", This, pidl);
484 new_pidl = ILClone(pidl);
486 if (new_pidl)
488 ILFree(This->pidl);
489 This->pidl = new_pidl;
490 return S_OK;
492 else
493 return E_OUTOFMEMORY;
496 static HRESULT WINAPI ShellItem_IPersistIDList_GetIDList(IPersistIDList* iface,
497 LPITEMIDLIST *ppidl)
499 ShellItem *This = impl_from_IPersistIDList(iface);
501 TRACE("(%p,%p)\n", This, ppidl);
503 *ppidl = ILClone(This->pidl);
504 if (*ppidl)
505 return S_OK;
506 else
507 return E_OUTOFMEMORY;
510 static const IPersistIDListVtbl ShellItem_IPersistIDList_Vtbl = {
511 ShellItem_IPersistIDList_QueryInterface,
512 ShellItem_IPersistIDList_AddRef,
513 ShellItem_IPersistIDList_Release,
514 ShellItem_IPersistIDList_GetClassID,
515 ShellItem_IPersistIDList_SetIDList,
516 ShellItem_IPersistIDList_GetIDList
520 HRESULT WINAPI IShellItem_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
522 ShellItem *This;
523 HRESULT ret;
525 TRACE("(%p,%s)\n",pUnkOuter, debugstr_guid(riid));
527 *ppv = NULL;
529 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
531 This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem));
532 This->IShellItem2_iface.lpVtbl = &ShellItem2_Vtbl;
533 This->ref = 1;
534 This->pidl = NULL;
535 This->IPersistIDList_iface.lpVtbl = &ShellItem_IPersistIDList_Vtbl;
537 ret = IShellItem2_QueryInterface(&This->IShellItem2_iface, riid, ppv);
538 IShellItem2_Release(&This->IShellItem2_iface);
540 return ret;
543 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
544 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
546 ShellItem *This;
547 LPITEMIDLIST new_pidl;
548 HRESULT ret;
550 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
552 if (!pidl)
554 return E_INVALIDARG;
556 else if (pidlParent || psfParent)
558 LPITEMIDLIST temp_parent=NULL;
559 if (!pidlParent)
561 IPersistFolder2* ppf2Parent;
563 if (FAILED(IShellFolder_QueryInterface(psfParent, &IID_IPersistFolder2, (void**)&ppf2Parent)))
565 FIXME("couldn't get IPersistFolder2 interface of parent\n");
566 return E_NOINTERFACE;
569 if (FAILED(IPersistFolder2_GetCurFolder(ppf2Parent, &temp_parent)))
571 FIXME("couldn't get parent PIDL\n");
572 IPersistFolder2_Release(ppf2Parent);
573 return E_NOINTERFACE;
576 pidlParent = temp_parent;
577 IPersistFolder2_Release(ppf2Parent);
580 new_pidl = ILCombine(pidlParent, pidl);
581 ILFree(temp_parent);
583 if (!new_pidl)
584 return E_OUTOFMEMORY;
586 else
588 new_pidl = ILClone(pidl);
589 if (!new_pidl)
590 return E_OUTOFMEMORY;
593 ret = IShellItem_Constructor(NULL, &IID_IShellItem, (void**)&This);
594 if (This)
596 *ppsi = (IShellItem*)&This->IShellItem2_iface;
597 This->pidl = new_pidl;
599 else
601 *ppsi = NULL;
602 ILFree(new_pidl);
604 return ret;
607 HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath,
608 IBindCtx *pbc, REFIID riid, void **ppv)
610 LPITEMIDLIST pidl;
611 HRESULT ret;
613 *ppv = NULL;
615 ret = SHParseDisplayName(pszPath, pbc, &pidl, 0, NULL);
616 if(SUCCEEDED(ret))
618 ShellItem *This;
619 ret = IShellItem_Constructor(NULL, riid, (void**)&This);
621 if(SUCCEEDED(ret))
623 This->pidl = pidl;
624 *ppv = (void*)This;
626 else
628 ILFree(pidl);
631 return ret;
634 HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv)
636 ShellItem *psiimpl;
637 HRESULT ret;
639 if(!pidl)
640 return E_INVALIDARG;
642 ret = IShellItem_Constructor(NULL, riid, ppv);
643 if(SUCCEEDED(ret))
645 psiimpl = (ShellItem*)*ppv;
646 psiimpl->pidl = ILClone(pidl);
649 return ret;
652 HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj,
653 DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv)
655 FORMATETC fmt;
656 STGMEDIUM medium;
657 HRESULT ret;
659 TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(riid), ppv);
661 if(!pdtobj)
662 return E_INVALIDARG;
664 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
665 fmt.ptd = NULL;
666 fmt.dwAspect = DVASPECT_CONTENT;
667 fmt.lindex = -1;
668 fmt.tymed = TYMED_HGLOBAL;
670 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
671 if(SUCCEEDED(ret))
673 LPIDA pida = GlobalLock(medium.u.hGlobal);
675 if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) ||
676 pida->cidl == 1)
678 LPITEMIDLIST pidl;
680 /* Get the first pidl (parent + child1) */
681 pidl = ILCombine((LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]),
682 (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]));
684 ret = SHCreateItemFromIDList(pidl, riid, ppv);
685 ILFree(pidl);
687 else
689 ret = E_FAIL;
692 GlobalUnlock(medium.u.hGlobal);
693 GlobalFree(medium.u.hGlobal);
696 if(FAILED(ret) && !(dwFlags & DOGIF_NO_HDROP))
698 TRACE("Attempting to fall back on CF_HDROP.\n");
700 fmt.cfFormat = CF_HDROP;
701 fmt.ptd = NULL;
702 fmt.dwAspect = DVASPECT_CONTENT;
703 fmt.lindex = -1;
704 fmt.tymed = TYMED_HGLOBAL;
706 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
707 if(SUCCEEDED(ret))
709 DROPFILES *df = GlobalLock(medium.u.hGlobal);
710 LPBYTE files = (LPBYTE)df + df->pFiles;
711 BOOL multiple_files = FALSE;
713 ret = E_FAIL;
714 if(!df->fWide)
716 WCHAR filename[MAX_PATH];
717 PCSTR first_file = (PCSTR)files;
718 if(*(files + lstrlenA(first_file) + 1) != 0)
719 multiple_files = TRUE;
721 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
723 MultiByteToWideChar(CP_ACP, 0, first_file, -1, filename, MAX_PATH);
724 ret = SHCreateItemFromParsingName(filename, NULL, riid, ppv);
727 else
729 PCWSTR first_file = (PCWSTR)files;
730 if(*((PCWSTR)files + lstrlenW(first_file) + 1) != 0)
731 multiple_files = TRUE;
733 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
734 ret = SHCreateItemFromParsingName(first_file, NULL, riid, ppv);
737 GlobalUnlock(medium.u.hGlobal);
738 GlobalFree(medium.u.hGlobal);
742 if(FAILED(ret) && !(dwFlags & DOGIF_NO_URL))
744 FIXME("Failed to create item, should try CF_URL.\n");
747 return ret;
750 HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
752 LPITEMIDLIST pidl;
753 HRESULT ret;
755 ret = SHGetIDListFromObject(punk, &pidl);
756 if(SUCCEEDED(ret))
758 ret = SHCreateItemFromIDList(pidl, riid, ppv);
759 ILFree(pidl);
762 return ret;
765 /*************************************************************************
766 * IShellItemArray implementation
768 typedef struct {
769 IShellItemArray IShellItemArray_iface;
770 LONG ref;
772 IShellItem **array;
773 DWORD item_count;
774 } IShellItemArrayImpl;
776 static inline IShellItemArrayImpl *impl_from_IShellItemArray(IShellItemArray *iface)
778 return CONTAINING_RECORD(iface, IShellItemArrayImpl, IShellItemArray_iface);
781 static HRESULT WINAPI IShellItemArray_fnQueryInterface(IShellItemArray *iface,
782 REFIID riid,
783 void **ppvObject)
785 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
786 TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
788 *ppvObject = NULL;
789 if(IsEqualIID(riid, &IID_IShellItemArray) ||
790 IsEqualIID(riid, &IID_IUnknown))
792 *ppvObject = &This->IShellItemArray_iface;
795 if(*ppvObject)
797 IUnknown_AddRef((IUnknown*)*ppvObject);
798 return S_OK;
801 return E_NOINTERFACE;
804 static ULONG WINAPI IShellItemArray_fnAddRef(IShellItemArray *iface)
806 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
807 LONG ref = InterlockedIncrement(&This->ref);
808 TRACE("%p - ref %d\n", This, ref);
810 return ref;
813 static ULONG WINAPI IShellItemArray_fnRelease(IShellItemArray *iface)
815 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
816 LONG ref = InterlockedDecrement(&This->ref);
817 TRACE("%p - ref %d\n", This, ref);
819 if(!ref)
821 UINT i;
822 TRACE("Freeing.\n");
824 for(i = 0; i < This->item_count; i++)
825 IShellItem_Release(This->array[i]);
827 HeapFree(GetProcessHeap(), 0, This->array);
828 HeapFree(GetProcessHeap(), 0, This);
829 return 0;
832 return ref;
835 static HRESULT WINAPI IShellItemArray_fnBindToHandler(IShellItemArray *iface,
836 IBindCtx *pbc,
837 REFGUID bhid,
838 REFIID riid,
839 void **ppvOut)
841 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
842 FIXME("Stub: %p (%p, %s, %s, %p)\n",
843 This, pbc, shdebugstr_guid(bhid), shdebugstr_guid(riid), ppvOut);
845 return E_NOTIMPL;
848 static HRESULT WINAPI IShellItemArray_fnGetPropertyStore(IShellItemArray *iface,
849 GETPROPERTYSTOREFLAGS flags,
850 REFIID riid,
851 void **ppv)
853 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
854 FIXME("Stub: %p (%x, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
856 return E_NOTIMPL;
859 static HRESULT WINAPI IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray *iface,
860 REFPROPERTYKEY keyType,
861 REFIID riid,
862 void **ppv)
864 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
865 FIXME("Stub: %p (%p, %s, %p)\n",
866 This, keyType, shdebugstr_guid(riid), ppv);
868 return E_NOTIMPL;
871 static HRESULT WINAPI IShellItemArray_fnGetAttributes(IShellItemArray *iface,
872 SIATTRIBFLAGS AttribFlags,
873 SFGAOF sfgaoMask,
874 SFGAOF *psfgaoAttribs)
876 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
877 FIXME("Stub: %p (%x, %x, %p)\n", This, AttribFlags, sfgaoMask, psfgaoAttribs);
879 return E_NOTIMPL;
882 static HRESULT WINAPI IShellItemArray_fnGetCount(IShellItemArray *iface,
883 DWORD *pdwNumItems)
885 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
886 TRACE("%p (%p)\n", This, pdwNumItems);
888 *pdwNumItems = This->item_count;
890 return S_OK;
893 static HRESULT WINAPI IShellItemArray_fnGetItemAt(IShellItemArray *iface,
894 DWORD dwIndex,
895 IShellItem **ppsi)
897 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
898 TRACE("%p (%x, %p)\n", This, dwIndex, ppsi);
900 /* zero indexed */
901 if(dwIndex + 1 > This->item_count)
902 return E_FAIL;
904 *ppsi = This->array[dwIndex];
905 IShellItem_AddRef(*ppsi);
907 return S_OK;
910 static HRESULT WINAPI IShellItemArray_fnEnumItems(IShellItemArray *iface,
911 IEnumShellItems **ppenumShellItems)
913 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
914 FIXME("Stub: %p (%p)\n", This, ppenumShellItems);
916 return E_NOTIMPL;
919 static const IShellItemArrayVtbl vt_IShellItemArray = {
920 IShellItemArray_fnQueryInterface,
921 IShellItemArray_fnAddRef,
922 IShellItemArray_fnRelease,
923 IShellItemArray_fnBindToHandler,
924 IShellItemArray_fnGetPropertyStore,
925 IShellItemArray_fnGetPropertyDescriptionList,
926 IShellItemArray_fnGetAttributes,
927 IShellItemArray_fnGetCount,
928 IShellItemArray_fnGetItemAt,
929 IShellItemArray_fnEnumItems
932 static HRESULT IShellItemArray_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
934 IShellItemArrayImpl *This;
935 HRESULT ret;
937 TRACE("(%p, %s, %p)\n",pUnkOuter, debugstr_guid(riid), ppv);
939 if(pUnkOuter)
940 return CLASS_E_NOAGGREGATION;
942 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl));
943 if(!This)
944 return E_OUTOFMEMORY;
946 This->ref = 1;
947 This->IShellItemArray_iface.lpVtbl = &vt_IShellItemArray;
948 This->array = NULL;
949 This->item_count = 0;
951 ret = IShellItemArray_QueryInterface(&This->IShellItemArray_iface, riid, ppv);
952 IShellItemArray_Release(&This->IShellItemArray_iface);
954 return ret;
957 HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent,
958 IShellFolder *psf,
959 UINT cidl,
960 PCUITEMID_CHILD_ARRAY ppidl,
961 IShellItemArray **ppsiItemArray)
963 IShellItemArrayImpl *This;
964 IShellItem **array;
965 HRESULT ret = E_FAIL;
966 UINT i;
968 TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray);
970 if(!pidlParent && !psf)
971 return E_POINTER;
973 if(!ppidl)
974 return E_INVALIDARG;
976 array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*));
977 if(!array)
978 return E_OUTOFMEMORY;
980 for(i = 0; i < cidl; i++)
982 ret = SHCreateShellItem(pidlParent, psf, ppidl[i], &array[i]);
983 if(FAILED(ret)) break;
986 if(SUCCEEDED(ret))
988 ret = IShellItemArray_Constructor(NULL, &IID_IShellItemArray, (void**)&This);
989 if(SUCCEEDED(ret))
991 This->array = array;
992 This->item_count = cidl;
993 *ppsiItemArray = &This->IShellItemArray_iface;
995 return ret;
999 /* Something failed, clean up. */
1000 for(i = 0; i < cidl; i++)
1001 if(array[i]) IShellItem_Release(array[i]);
1002 HeapFree(GetProcessHeap(), 0, array);
1003 *ppsiItemArray = NULL;
1004 return ret;
1007 HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *psi, REFIID riid, void **ppv)
1009 IShellItemArrayImpl *This;
1010 IShellItem **array;
1011 HRESULT ret;
1013 TRACE("%p, %s, %p\n", psi, shdebugstr_guid(riid), ppv);
1015 array = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItem*));
1016 if(!array)
1017 return E_OUTOFMEMORY;
1019 ret = IShellItemArray_Constructor(NULL, riid, (void**)&This);
1020 if(SUCCEEDED(ret))
1022 array[0] = psi;
1023 IShellItem_AddRef(psi);
1024 This->array = array;
1025 This->item_count = 1;
1026 *ppv = This;
1028 else
1030 HeapFree(GetProcessHeap(), 0, array);
1031 *ppv = NULL;
1034 return ret;
1037 HRESULT WINAPI SHCreateShellItemArrayFromDataObject(IDataObject *pdo, REFIID riid, void **ppv)
1039 IShellItemArray *psia;
1040 FORMATETC fmt;
1041 STGMEDIUM medium;
1042 HRESULT ret;
1044 TRACE("%p, %s, %p\n", pdo, shdebugstr_guid(riid), ppv);
1046 if(!pdo)
1047 return E_INVALIDARG;
1049 *ppv = NULL;
1051 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
1052 fmt.ptd = NULL;
1053 fmt.dwAspect = DVASPECT_CONTENT;
1054 fmt.lindex = -1;
1055 fmt.tymed = TYMED_HGLOBAL;
1057 ret = IDataObject_GetData(pdo, &fmt, &medium);
1058 if(SUCCEEDED(ret))
1060 LPIDA pida = GlobalLock(medium.u.hGlobal);
1061 LPCITEMIDLIST parent_pidl;
1062 LPCITEMIDLIST *children;
1063 UINT i;
1064 TRACE("Converting %d objects.\n", pida->cidl);
1066 parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
1068 children = HeapAlloc(GetProcessHeap(), 0, sizeof(LPCITEMIDLIST)*pida->cidl);
1069 for(i = 0; i < pida->cidl; i++)
1070 children[i] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i+1]);
1072 ret = SHCreateShellItemArray(parent_pidl, NULL, pida->cidl, children, &psia);
1074 HeapFree(GetProcessHeap(), 0, children);
1076 GlobalUnlock(medium.u.hGlobal);
1077 GlobalFree(medium.u.hGlobal);
1080 if(SUCCEEDED(ret))
1082 ret = IShellItemArray_QueryInterface(psia, riid, ppv);
1083 IShellItemArray_Release(psia);
1086 return ret;