winex11: Use a standard export function to handle MULTIPLE requests.
[wine.git] / dlls / shell32 / shellitem.c
blobb0af6d61e5f1ca4b22b24858619e4215d2de5cd5
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
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wine/debug.h"
34 #include "pidl.h"
35 #include "shell32_main.h"
36 #include "debughlp.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shell);
40 typedef struct _ShellItem {
41 IShellItem2 IShellItem2_iface;
42 LONG ref;
43 LPITEMIDLIST pidl;
44 IPersistIDList IPersistIDList_iface;
45 } ShellItem;
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,
60 void **ppv)
62 ShellItem *This = impl_from_IShellItem2(iface);
64 TRACE("(%p, %s, %p)\n", iface, debugstr_guid(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;
77 else {
78 FIXME("not implemented for %s\n", shdebugstr_guid(riid));
79 *ppv = NULL;
80 return E_NOINTERFACE;
83 IUnknown_AddRef((IUnknown*)*ppv);
84 return S_OK;
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);
94 return 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);
104 if (ref == 0)
106 ILFree(This->pidl);
107 HeapFree(GetProcessHeap(), 0, This);
110 return ref;
113 static HRESULT ShellItem_get_parent_pidl(ShellItem *This, LPITEMIDLIST *parent_pidl)
115 *parent_pidl = ILClone(This->pidl);
116 if (*parent_pidl)
118 if (ILRemoveLastID(*parent_pidl))
119 return S_OK;
120 else
122 ILFree(*parent_pidl);
123 *parent_pidl = NULL;
124 return E_INVALIDARG;
127 else
129 *parent_pidl = NULL;
130 return E_OUTOFMEMORY;
134 static HRESULT ShellItem_get_parent_shellfolder(ShellItem *This, IShellFolder **ppsf)
136 LPITEMIDLIST parent_pidl;
137 IShellFolder *desktop;
138 HRESULT ret;
140 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
141 if (SUCCEEDED(ret))
143 ret = SHGetDesktopFolder(&desktop);
144 if (SUCCEEDED(ret))
146 if (_ILIsDesktop(parent_pidl))
148 *ppsf = desktop;
150 else
152 ret = IShellFolder_BindToObject(desktop, parent_pidl, NULL, &IID_IShellFolder, (void**)ppsf);
153 IShellFolder_Release(desktop);
156 ILFree(parent_pidl);
159 return ret;
162 static HRESULT ShellItem_get_shellfolder(ShellItem *This, IBindCtx *pbc, IShellFolder **ppsf)
164 IShellFolder *desktop;
165 HRESULT ret;
167 ret = SHGetDesktopFolder(&desktop);
168 if (SUCCEEDED(ret))
170 if (_ILIsDesktop(This->pidl))
172 *ppsf = desktop;
173 IShellFolder_AddRef(*ppsf);
175 else
177 ret = IShellFolder_BindToObject(desktop, This->pidl, pbc, &IID_IShellFolder, (void**)ppsf);
180 IShellFolder_Release(desktop);
183 return ret;
186 static HRESULT WINAPI ShellItem_BindToHandler(IShellItem2 *iface, IBindCtx *pbc,
187 REFGUID rbhid, REFIID riid, void **ppvOut)
189 ShellItem *This = impl_from_IShellItem2(iface);
190 HRESULT ret;
191 TRACE("(%p,%p,%s,%p,%p)\n", iface, pbc, shdebugstr_guid(rbhid), riid, ppvOut);
193 *ppvOut = NULL;
194 if (IsEqualGUID(rbhid, &BHID_SFObject))
196 IShellFolder *psf;
197 ret = ShellItem_get_shellfolder(This, pbc, &psf);
198 if (SUCCEEDED(ret))
200 ret = IShellFolder_QueryInterface(psf, riid, ppvOut);
201 IShellFolder_Release(psf);
203 return ret;
205 else if (IsEqualGUID(rbhid, &BHID_SFUIObject))
207 IShellFolder *psf_parent;
208 if (_ILIsDesktop(This->pidl))
209 ret = SHGetDesktopFolder(&psf_parent);
210 else
211 ret = ShellItem_get_parent_shellfolder(This, &psf_parent);
213 if (SUCCEEDED(ret))
215 LPCITEMIDLIST pidl = ILFindLastID(This->pidl);
216 ret = IShellFolder_GetUIObjectOf(psf_parent, NULL, 1, &pidl, riid, NULL, ppvOut);
217 IShellFolder_Release(psf_parent);
219 return ret;
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;
236 HRESULT ret;
238 TRACE("(%p,%p)\n", iface, ppsi);
240 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
241 if (SUCCEEDED(ret))
243 ret = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi);
244 ILFree(parent_pidl);
247 return ret;
250 static HRESULT WINAPI ShellItem_GetDisplayName(IShellItem2 *iface, SIGDN sigdnName,
251 LPWSTR *ppszName)
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;
265 HRESULT ret;
267 TRACE("(%p,%x,%p)\n", iface, sfgaoMask, psfgaoAttribs);
269 if (_ILIsDesktop(This->pidl))
270 ret = SHGetDesktopFolder(&parent_folder);
271 else
272 ret = ShellItem_get_parent_shellfolder(This, &parent_folder);
273 if (SUCCEEDED(ret))
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);
281 if (SUCCEEDED(ret))
283 if(sfgaoMask == *psfgaoAttribs)
284 return S_OK;
285 else
286 return S_FALSE;
290 return ret;
293 static HRESULT WINAPI ShellItem_Compare(IShellItem2 *iface, IShellItem *oth,
294 SICHINTF hint, int *piOrder)
296 LPWSTR dispname, dispname_oth;
297 HRESULT ret;
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);
304 if(SUCCEEDED(ret))
306 ret = IShellItem_GetDisplayName(oth, SIGDN_DESKTOPABSOLUTEEDITING, &dispname_oth);
307 if(SUCCEEDED(ret))
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);
322 if(SUCCEEDED(ret))
324 ret = IShellItem_GetDisplayName(oth, SIGDN_FILESYSPATH, &dispname_oth);
325 if(SUCCEEDED(ret))
327 *piOrder = lstrcmpiW(dispname, dispname_oth);
328 CoTaskMemFree(dispname_oth);
330 CoTaskMemFree(dispname);
334 if(FAILED(ret))
335 return ret;
337 if(*piOrder)
338 return S_FALSE;
339 else
340 return S_OK;
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);
348 return E_NOTIMPL;
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);
357 return E_NOTIMPL;
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);
366 return E_NOTIMPL;
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);
374 return E_NOTIMPL;
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);
381 return E_NOTIMPL;
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);
388 return E_NOTIMPL;
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);
395 return E_NOTIMPL;
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);
402 return E_NOTIMPL;
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);
409 return E_NOTIMPL;
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);
416 return E_NOTIMPL;
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);
423 return E_NOTIMPL;
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);
430 return E_NOTIMPL;
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);
437 return E_NOTIMPL;
441 static const IShellItem2Vtbl ShellItem2_Vtbl = {
442 ShellItem_QueryInterface,
443 ShellItem_AddRef,
444 ShellItem_Release,
445 ShellItem_BindToHandler,
446 ShellItem_GetParent,
447 ShellItem_GetDisplayName,
448 ShellItem_GetAttributes,
449 ShellItem_Compare,
450 ShellItem2_GetPropertyStore,
451 ShellItem2_GetPropertyStoreWithCreateObject,
452 ShellItem2_GetPropertyStoreForKeys,
453 ShellItem2_GetPropertyDescriptionList,
454 ShellItem2_Update,
455 ShellItem2_GetProperty,
456 ShellItem2_GetCLSID,
457 ShellItem2_GetFileTime,
458 ShellItem2_GetInt32,
459 ShellItem2_GetString,
460 ShellItem2_GetUInt32,
461 ShellItem2_GetUInt64,
462 ShellItem2_GetBool
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,
485 CLSID *pClassID)
487 *pClassID = CLSID_ShellItem;
488 return S_OK;
491 static HRESULT WINAPI ShellItem_IPersistIDList_SetIDList(IPersistIDList* iface,
492 LPCITEMIDLIST pidl)
494 ShellItem *This = impl_from_IPersistIDList(iface);
495 LPITEMIDLIST new_pidl;
497 TRACE("(%p,%p)\n", This, pidl);
499 new_pidl = ILClone(pidl);
501 if (new_pidl)
503 ILFree(This->pidl);
504 This->pidl = new_pidl;
505 return S_OK;
507 else
508 return E_OUTOFMEMORY;
511 static HRESULT WINAPI ShellItem_IPersistIDList_GetIDList(IPersistIDList* iface,
512 LPITEMIDLIST *ppidl)
514 ShellItem *This = impl_from_IPersistIDList(iface);
516 TRACE("(%p,%p)\n", This, ppidl);
518 *ppidl = ILClone(This->pidl);
519 if (*ppidl)
520 return S_OK;
521 else
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)
537 ShellItem *This;
538 HRESULT ret;
540 TRACE("(%p,%s)\n",pUnkOuter, debugstr_guid(riid));
542 *ppv = NULL;
544 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
546 This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem));
547 This->IShellItem2_iface.lpVtbl = &ShellItem2_Vtbl;
548 This->ref = 1;
549 This->pidl = NULL;
550 This->IPersistIDList_iface.lpVtbl = &ShellItem_IPersistIDList_Vtbl;
552 ret = IShellItem2_QueryInterface(&This->IShellItem2_iface, riid, ppv);
553 IShellItem2_Release(&This->IShellItem2_iface);
555 return ret;
558 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
559 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
561 LPITEMIDLIST new_pidl;
562 HRESULT ret;
564 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
566 *ppsi = NULL;
568 if (!pidl)
570 return E_INVALIDARG;
572 else if (pidlParent || psfParent)
574 LPITEMIDLIST temp_parent=NULL;
575 if (!pidlParent)
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);
597 ILFree(temp_parent);
599 if (!new_pidl)
600 return E_OUTOFMEMORY;
602 else
604 new_pidl = ILClone(pidl);
605 if (!new_pidl)
606 return E_OUTOFMEMORY;
609 ret = SHCreateItemFromIDList(new_pidl, &IID_IShellItem, (void**)ppsi);
610 ILFree(new_pidl);
612 return ret;
615 HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath,
616 IBindCtx *pbc, REFIID riid, void **ppv)
618 LPITEMIDLIST pidl;
619 HRESULT ret;
621 *ppv = NULL;
623 ret = SHParseDisplayName(pszPath, pbc, &pidl, 0, NULL);
624 if(SUCCEEDED(ret))
626 ret = SHCreateItemFromIDList(pidl, riid, ppv);
627 ILFree(pidl);
629 return ret;
632 HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv)
634 IPersistIDList *persist;
635 HRESULT ret;
637 if(!pidl)
638 return E_INVALIDARG;
640 *ppv = NULL;
641 ret = IShellItem_Constructor(NULL, &IID_IPersistIDList, (void**)&persist);
642 if(FAILED(ret))
643 return ret;
645 ret = IPersistIDList_SetIDList(persist, pidl);
646 if(FAILED(ret))
648 IPersistIDList_Release(persist);
649 return ret;
652 ret = IPersistIDList_QueryInterface(persist, riid, ppv);
653 IPersistIDList_Release(persist);
654 return ret;
657 HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj,
658 DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv)
660 FORMATETC fmt;
661 STGMEDIUM medium;
662 HRESULT ret;
664 TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(riid), ppv);
666 if(!pdtobj)
667 return E_INVALIDARG;
669 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
670 fmt.ptd = NULL;
671 fmt.dwAspect = DVASPECT_CONTENT;
672 fmt.lindex = -1;
673 fmt.tymed = TYMED_HGLOBAL;
675 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
676 if(SUCCEEDED(ret))
678 LPIDA pida = GlobalLock(medium.u.hGlobal);
680 if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) ||
681 pida->cidl == 1)
683 LPITEMIDLIST pidl;
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);
690 ILFree(pidl);
692 else
694 ret = E_FAIL;
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;
706 fmt.ptd = NULL;
707 fmt.dwAspect = DVASPECT_CONTENT;
708 fmt.lindex = -1;
709 fmt.tymed = TYMED_HGLOBAL;
711 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
712 if(SUCCEEDED(ret))
714 DROPFILES *df = GlobalLock(medium.u.hGlobal);
715 LPBYTE files = (LPBYTE)df + df->pFiles;
716 BOOL multiple_files = FALSE;
718 ret = E_FAIL;
719 if(!df->fWide)
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);
732 else
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");
752 return ret;
755 HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
757 LPITEMIDLIST pidl;
758 HRESULT ret;
760 ret = SHGetIDListFromObject(punk, &pidl);
761 if(SUCCEEDED(ret))
763 ret = SHCreateItemFromIDList(pidl, riid, ppv);
764 ILFree(pidl);
767 return ret;
770 /*************************************************************************
771 * IEnumShellItems implementation
773 typedef struct {
774 IEnumShellItems IEnumShellItems_iface;
775 LONG ref;
777 IShellItemArray *array;
778 DWORD count;
779 DWORD position;
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,
788 REFIID riid,
789 void **ppvObject)
791 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
792 TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
794 *ppvObject = NULL;
795 if(IsEqualIID(riid, &IID_IEnumShellItems) ||
796 IsEqualIID(riid, &IID_IUnknown))
798 *ppvObject = &This->IEnumShellItems_iface;
801 if(*ppvObject)
803 IUnknown_AddRef((IUnknown*)*ppvObject);
804 return S_OK;
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);
816 return 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);
825 if(!ref)
827 TRACE("Freeing.\n");
828 IShellItemArray_Release(This->array);
829 HeapFree(GetProcessHeap(), 0, This);
830 return 0;
833 return ref;
836 static HRESULT WINAPI IEnumShellItems_fnNext(IEnumShellItems* iface,
837 ULONG celt,
838 IShellItem **rgelt,
839 ULONG *pceltFetched)
841 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
842 HRESULT hr = S_FALSE;
843 UINT i;
844 ULONG fetched = 0;
845 TRACE("%p (%d %p %p)\n", This, celt, rgelt, pceltFetched);
847 if(pceltFetched == NULL && celt != 1)
848 return E_INVALIDARG;
850 for(i = This->position; fetched < celt && i < This->count; i++) {
851 hr = IShellItemArray_GetItemAt(This->array, i, &rgelt[fetched]);
852 if(FAILED(hr))
853 break;
854 fetched++;
855 This->position++;
858 if(SUCCEEDED(hr))
860 if(pceltFetched != NULL)
861 *pceltFetched = fetched;
863 if(fetched > 0)
864 return S_OK;
866 return S_FALSE;
869 return hr;
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);
879 return S_OK;
882 static HRESULT WINAPI IEnumShellItems_fnReset(IEnumShellItems* iface)
884 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
885 TRACE("%p\n", This);
887 This->position = 0;
889 return S_OK;
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 */
898 *ppenum = NULL;
900 return E_NOTIMPL;
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;
916 HRESULT ret;
918 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumShellItemsImpl));
919 if(!This)
920 return E_OUTOFMEMORY;
922 This->ref = 1;
923 This->IEnumShellItems_iface.lpVtbl = &vt_IEnumShellItems;
924 This->array = array;
925 This->position = 0;
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);
933 return ret;
937 /*************************************************************************
938 * IShellItemArray implementation
940 typedef struct {
941 IShellItemArray IShellItemArray_iface;
942 LONG ref;
944 IShellItem **array;
945 DWORD item_count;
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,
954 REFIID riid,
955 void **ppvObject)
957 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
958 TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
960 *ppvObject = NULL;
961 if(IsEqualIID(riid, &IID_IShellItemArray) ||
962 IsEqualIID(riid, &IID_IUnknown))
964 *ppvObject = &This->IShellItemArray_iface;
967 if(*ppvObject)
969 IUnknown_AddRef((IUnknown*)*ppvObject);
970 return S_OK;
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);
982 return 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);
991 if(!ref)
993 UINT i;
994 TRACE("Freeing.\n");
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);
1001 return 0;
1004 return ref;
1007 static HRESULT WINAPI IShellItemArray_fnBindToHandler(IShellItemArray *iface,
1008 IBindCtx *pbc,
1009 REFGUID bhid,
1010 REFIID riid,
1011 void **ppvOut)
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);
1017 return E_NOTIMPL;
1020 static HRESULT WINAPI IShellItemArray_fnGetPropertyStore(IShellItemArray *iface,
1021 GETPROPERTYSTOREFLAGS flags,
1022 REFIID riid,
1023 void **ppv)
1025 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1026 FIXME("Stub: %p (%x, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
1028 return E_NOTIMPL;
1031 static HRESULT WINAPI IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray *iface,
1032 REFPROPERTYKEY keyType,
1033 REFIID riid,
1034 void **ppv)
1036 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1037 FIXME("Stub: %p (%p, %s, %p)\n",
1038 This, keyType, shdebugstr_guid(riid), ppv);
1040 return E_NOTIMPL;
1043 static HRESULT WINAPI IShellItemArray_fnGetAttributes(IShellItemArray *iface,
1044 SIATTRIBFLAGS AttribFlags,
1045 SFGAOF sfgaoMask,
1046 SFGAOF *psfgaoAttribs)
1048 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1049 HRESULT hr = S_OK;
1050 SFGAOF attr;
1051 UINT i;
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);
1060 if(FAILED(hr))
1061 break;
1063 if(i == 0)
1065 *psfgaoAttribs = attr;
1066 continue;
1069 switch(AttribFlags & SIATTRIBFLAGS_MASK)
1071 case SIATTRIBFLAGS_AND:
1072 *psfgaoAttribs &= attr;
1073 break;
1074 case SIATTRIBFLAGS_OR:
1075 *psfgaoAttribs |= attr;
1076 break;
1080 if(SUCCEEDED(hr))
1082 if(*psfgaoAttribs == sfgaoMask)
1083 return S_OK;
1085 return S_FALSE;
1088 return hr;
1091 static HRESULT WINAPI IShellItemArray_fnGetCount(IShellItemArray *iface,
1092 DWORD *pdwNumItems)
1094 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1095 TRACE("%p (%p)\n", This, pdwNumItems);
1097 *pdwNumItems = This->item_count;
1099 return S_OK;
1102 static HRESULT WINAPI IShellItemArray_fnGetItemAt(IShellItemArray *iface,
1103 DWORD dwIndex,
1104 IShellItem **ppsi)
1106 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1107 TRACE("%p (%x, %p)\n", This, dwIndex, ppsi);
1109 /* zero indexed */
1110 if(dwIndex + 1 > This->item_count)
1111 return E_FAIL;
1113 *ppsi = This->array[dwIndex];
1114 IShellItem_AddRef(*ppsi);
1116 return S_OK;
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));
1148 if(!This)
1149 return E_OUTOFMEMORY;
1151 This->IShellItemArray_iface.lpVtbl = &vt_IShellItemArray;
1152 This->ref = 1;
1154 This->array = HeapAlloc(GetProcessHeap(), 0, count*sizeof(IShellItem*));
1155 if (!This->array)
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;
1164 return S_OK;
1167 HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent,
1168 IShellFolder *psf,
1169 UINT cidl,
1170 PCUITEMID_CHILD_ARRAY ppidl,
1171 IShellItemArray **ppsiItemArray)
1173 IShellItem **array;
1174 HRESULT ret = E_FAIL;
1175 UINT i;
1177 TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray);
1179 *ppsiItemArray = NULL;
1181 if(!pidlParent && !psf)
1182 return E_POINTER;
1184 if(!ppidl)
1185 return E_INVALIDARG;
1187 array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*));
1188 if(!array)
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;
1197 if(SUCCEEDED(ret))
1199 ret = create_shellitemarray(array, cidl, ppsiItemArray);
1200 HeapFree(GetProcessHeap(), 0, array);
1201 if(SUCCEEDED(ret))
1202 return ret;
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);
1209 return ret;
1212 HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *item, REFIID riid, void **ppv)
1214 IShellItemArray *array;
1215 HRESULT ret;
1217 TRACE("%p, %s, %p\n", item, shdebugstr_guid(riid), ppv);
1219 *ppv = NULL;
1221 IShellItem_AddRef(item);
1222 ret = create_shellitemarray(&item, 1, &array);
1223 if(FAILED(ret))
1225 IShellItem_Release(item);
1226 return ret;
1229 ret = IShellItemArray_QueryInterface(array, riid, ppv);
1230 IShellItemArray_Release(array);
1231 return ret;
1234 HRESULT WINAPI SHCreateShellItemArrayFromDataObject(IDataObject *pdo, REFIID riid, void **ppv)
1236 IShellItemArray *psia;
1237 FORMATETC fmt;
1238 STGMEDIUM medium;
1239 HRESULT ret;
1241 TRACE("%p, %s, %p\n", pdo, shdebugstr_guid(riid), ppv);
1243 if(!pdo)
1244 return E_INVALIDARG;
1246 *ppv = NULL;
1248 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
1249 fmt.ptd = NULL;
1250 fmt.dwAspect = DVASPECT_CONTENT;
1251 fmt.lindex = -1;
1252 fmt.tymed = TYMED_HGLOBAL;
1254 ret = IDataObject_GetData(pdo, &fmt, &medium);
1255 if(SUCCEEDED(ret))
1257 LPIDA pida = GlobalLock(medium.u.hGlobal);
1258 LPCITEMIDLIST parent_pidl;
1259 LPCITEMIDLIST *children;
1260 UINT i;
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);
1277 if(SUCCEEDED(ret))
1279 ret = IShellItemArray_QueryInterface(psia, riid, ppv);
1280 IShellItemArray_Release(psia);
1283 return ret;
1286 HRESULT WINAPI SHCreateShellItemArrayFromIDLists(UINT cidl,
1287 PCIDLIST_ABSOLUTE_ARRAY pidl_array,
1288 IShellItemArray **psia)
1290 IShellItem **array;
1291 HRESULT ret;
1292 UINT i;
1293 TRACE("%d, %p, %p\n", cidl, pidl_array, psia);
1295 *psia = NULL;
1297 if(cidl == 0)
1298 return E_INVALIDARG;
1300 array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*));
1301 if(!array)
1302 return E_OUTOFMEMORY;
1304 for(i = 0; i < cidl; i++)
1306 ret = SHCreateShellItem(NULL, NULL, pidl_array[i], &array[i]);
1307 if(FAILED(ret))
1308 break;
1311 if(SUCCEEDED(ret))
1313 ret = create_shellitemarray(array, cidl, psia);
1314 HeapFree(GetProcessHeap(), 0, array);
1315 if(SUCCEEDED(ret))
1316 return ret;
1319 for(i = 0; i < cidl; i++)
1320 if(array[i]) IShellItem_Release(array[i]);
1321 HeapFree(GetProcessHeap(), 0, array);
1322 *psia = NULL;
1323 return ret;