winejoystick: Fix a crash on accessing a CFArray past its end due to an off-by-one...
[wine/multimedia.git] / dlls / shell32 / shellitem.c
blobb5d70dcf05d4314cb6d13b2f9f60f285ba884101
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 *psfgaoAttribs &= sfgaoMask;
273 IShellFolder_Release(parent_folder);
275 if(sfgaoMask == *psfgaoAttribs)
276 return S_OK;
277 else
278 return S_FALSE;
281 return ret;
284 static HRESULT WINAPI ShellItem_Compare(IShellItem2 *iface, IShellItem *oth,
285 SICHINTF hint, int *piOrder)
287 LPWSTR dispname, dispname_oth;
288 HRESULT ret;
289 TRACE("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder);
291 if(hint & (SICHINT_CANONICAL | SICHINT_ALLFIELDS))
292 FIXME("Unsupported flags 0x%08x\n", hint);
294 ret = IShellItem2_GetDisplayName(iface, SIGDN_DESKTOPABSOLUTEEDITING, &dispname);
295 if(SUCCEEDED(ret))
297 ret = IShellItem_GetDisplayName(oth, SIGDN_DESKTOPABSOLUTEEDITING, &dispname_oth);
298 if(SUCCEEDED(ret))
300 *piOrder = lstrcmpiW(dispname, dispname_oth);
301 CoTaskMemFree(dispname_oth);
303 CoTaskMemFree(dispname);
306 if(SUCCEEDED(ret) && *piOrder &&
307 (hint & SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL))
309 LPWSTR dispname, dispname_oth;
311 TRACE("Testing filesystem path.\n");
312 ret = IShellItem2_GetDisplayName(iface, SIGDN_FILESYSPATH, &dispname);
313 if(SUCCEEDED(ret))
315 ret = IShellItem_GetDisplayName(oth, SIGDN_FILESYSPATH, &dispname_oth);
316 if(SUCCEEDED(ret))
318 *piOrder = lstrcmpiW(dispname, dispname_oth);
319 CoTaskMemFree(dispname_oth);
321 CoTaskMemFree(dispname);
325 if(FAILED(ret))
326 return ret;
328 if(*piOrder)
329 return S_FALSE;
330 else
331 return S_OK;
334 static HRESULT WINAPI ShellItem2_GetPropertyStore(IShellItem2 *iface, GETPROPERTYSTOREFLAGS flags,
335 REFIID riid, void **ppv)
337 ShellItem *This = impl_from_IShellItem2(iface);
338 FIXME("Stub: %p (%d, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
339 return E_NOTIMPL;
342 static HRESULT WINAPI ShellItem2_GetPropertyStoreWithCreateObject(IShellItem2 *iface,
343 GETPROPERTYSTOREFLAGS flags, IUnknown *punkCreateObject, REFIID riid, void **ppv)
345 ShellItem *This = impl_from_IShellItem2(iface);
346 FIXME("Stub: %p (%08x, %p, %s, %p)\n",
347 This, flags, punkCreateObject, shdebugstr_guid(riid), ppv);
348 return E_NOTIMPL;
351 static HRESULT WINAPI ShellItem2_GetPropertyStoreForKeys(IShellItem2 *iface, const PROPERTYKEY *rgKeys,
352 UINT cKeys, GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv)
354 ShellItem *This = impl_from_IShellItem2(iface);
355 FIXME("Stub: %p (%p, %d, %08x, %s, %p)\n",
356 This, rgKeys, cKeys, flags, shdebugstr_guid(riid), ppv);
357 return E_NOTIMPL;
360 static HRESULT WINAPI ShellItem2_GetPropertyDescriptionList(IShellItem2 *iface,
361 REFPROPERTYKEY keyType, REFIID riid, void **ppv)
363 ShellItem *This = impl_from_IShellItem2(iface);
364 FIXME("Stub: %p (%p, %s, %p)\n", This, keyType, debugstr_guid(riid), ppv);
365 return E_NOTIMPL;
368 static HRESULT WINAPI ShellItem2_Update(IShellItem2 *iface, IBindCtx *pbc)
370 ShellItem *This = impl_from_IShellItem2(iface);
371 FIXME("Stub: %p (%p)\n", This, pbc);
372 return E_NOTIMPL;
375 static HRESULT WINAPI ShellItem2_GetProperty(IShellItem2 *iface, REFPROPERTYKEY key, PROPVARIANT *ppropvar)
377 ShellItem *This = impl_from_IShellItem2(iface);
378 FIXME("Stub: %p (%p, %p)\n", This, key, ppropvar);
379 return E_NOTIMPL;
382 static HRESULT WINAPI ShellItem2_GetCLSID(IShellItem2 *iface, REFPROPERTYKEY key, CLSID *pclsid)
384 ShellItem *This = impl_from_IShellItem2(iface);
385 FIXME("Stub: %p (%p, %p)\n", This, key, pclsid);
386 return E_NOTIMPL;
389 static HRESULT WINAPI ShellItem2_GetFileTime(IShellItem2 *iface, REFPROPERTYKEY key, FILETIME *pft)
391 ShellItem *This = impl_from_IShellItem2(iface);
392 FIXME("Stub: %p (%p, %p)\n", This, key, pft);
393 return E_NOTIMPL;
396 static HRESULT WINAPI ShellItem2_GetInt32(IShellItem2 *iface, REFPROPERTYKEY key, int *pi)
398 ShellItem *This = impl_from_IShellItem2(iface);
399 FIXME("Stub: %p (%p, %p)\n", This, key, pi);
400 return E_NOTIMPL;
403 static HRESULT WINAPI ShellItem2_GetString(IShellItem2 *iface, REFPROPERTYKEY key, LPWSTR *ppsz)
405 ShellItem *This = impl_from_IShellItem2(iface);
406 FIXME("Stub: %p (%p, %p)\n", This, key, ppsz);
407 return E_NOTIMPL;
410 static HRESULT WINAPI ShellItem2_GetUInt32(IShellItem2 *iface, REFPROPERTYKEY key, ULONG *pui)
412 ShellItem *This = impl_from_IShellItem2(iface);
413 FIXME("Stub: %p (%p, %p)\n", This, key, pui);
414 return E_NOTIMPL;
417 static HRESULT WINAPI ShellItem2_GetUInt64(IShellItem2 *iface, REFPROPERTYKEY key, ULONGLONG *pull)
419 ShellItem *This = impl_from_IShellItem2(iface);
420 FIXME("Stub: %p (%p, %p)\n", This, key, pull);
421 return E_NOTIMPL;
424 static HRESULT WINAPI ShellItem2_GetBool(IShellItem2 *iface, REFPROPERTYKEY key, BOOL *pf)
426 ShellItem *This = impl_from_IShellItem2(iface);
427 FIXME("Stub: %p (%p, %p)\n", This, key, pf);
428 return E_NOTIMPL;
432 static const IShellItem2Vtbl ShellItem2_Vtbl = {
433 ShellItem_QueryInterface,
434 ShellItem_AddRef,
435 ShellItem_Release,
436 ShellItem_BindToHandler,
437 ShellItem_GetParent,
438 ShellItem_GetDisplayName,
439 ShellItem_GetAttributes,
440 ShellItem_Compare,
441 ShellItem2_GetPropertyStore,
442 ShellItem2_GetPropertyStoreWithCreateObject,
443 ShellItem2_GetPropertyStoreForKeys,
444 ShellItem2_GetPropertyDescriptionList,
445 ShellItem2_Update,
446 ShellItem2_GetProperty,
447 ShellItem2_GetCLSID,
448 ShellItem2_GetFileTime,
449 ShellItem2_GetInt32,
450 ShellItem2_GetString,
451 ShellItem2_GetUInt32,
452 ShellItem2_GetUInt64,
453 ShellItem2_GetBool
456 static HRESULT WINAPI ShellItem_IPersistIDList_QueryInterface(IPersistIDList *iface,
457 REFIID riid, void **ppv)
459 ShellItem *This = impl_from_IPersistIDList(iface);
460 return IShellItem2_QueryInterface(&This->IShellItem2_iface, riid, ppv);
463 static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface)
465 ShellItem *This = impl_from_IPersistIDList(iface);
466 return IShellItem2_AddRef(&This->IShellItem2_iface);
469 static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface)
471 ShellItem *This = impl_from_IPersistIDList(iface);
472 return IShellItem2_Release(&This->IShellItem2_iface);
475 static HRESULT WINAPI ShellItem_IPersistIDList_GetClassID(IPersistIDList* iface,
476 CLSID *pClassID)
478 *pClassID = CLSID_ShellItem;
479 return S_OK;
482 static HRESULT WINAPI ShellItem_IPersistIDList_SetIDList(IPersistIDList* iface,
483 LPCITEMIDLIST pidl)
485 ShellItem *This = impl_from_IPersistIDList(iface);
486 LPITEMIDLIST new_pidl;
488 TRACE("(%p,%p)\n", This, pidl);
490 new_pidl = ILClone(pidl);
492 if (new_pidl)
494 ILFree(This->pidl);
495 This->pidl = new_pidl;
496 return S_OK;
498 else
499 return E_OUTOFMEMORY;
502 static HRESULT WINAPI ShellItem_IPersistIDList_GetIDList(IPersistIDList* iface,
503 LPITEMIDLIST *ppidl)
505 ShellItem *This = impl_from_IPersistIDList(iface);
507 TRACE("(%p,%p)\n", This, ppidl);
509 *ppidl = ILClone(This->pidl);
510 if (*ppidl)
511 return S_OK;
512 else
513 return E_OUTOFMEMORY;
516 static const IPersistIDListVtbl ShellItem_IPersistIDList_Vtbl = {
517 ShellItem_IPersistIDList_QueryInterface,
518 ShellItem_IPersistIDList_AddRef,
519 ShellItem_IPersistIDList_Release,
520 ShellItem_IPersistIDList_GetClassID,
521 ShellItem_IPersistIDList_SetIDList,
522 ShellItem_IPersistIDList_GetIDList
526 HRESULT WINAPI IShellItem_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
528 ShellItem *This;
529 HRESULT ret;
531 TRACE("(%p,%s)\n",pUnkOuter, debugstr_guid(riid));
533 *ppv = NULL;
535 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
537 This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem));
538 This->IShellItem2_iface.lpVtbl = &ShellItem2_Vtbl;
539 This->ref = 1;
540 This->pidl = NULL;
541 This->IPersistIDList_iface.lpVtbl = &ShellItem_IPersistIDList_Vtbl;
543 ret = IShellItem2_QueryInterface(&This->IShellItem2_iface, riid, ppv);
544 IShellItem2_Release(&This->IShellItem2_iface);
546 return ret;
549 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
550 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
552 ShellItem *This;
553 LPITEMIDLIST new_pidl;
554 HRESULT ret;
556 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
558 *ppsi = NULL;
560 if (!pidl)
562 return E_INVALIDARG;
564 else if (pidlParent || psfParent)
566 LPITEMIDLIST temp_parent=NULL;
567 if (!pidlParent)
569 IPersistFolder2* ppf2Parent;
571 if (FAILED(IShellFolder_QueryInterface(psfParent, &IID_IPersistFolder2, (void**)&ppf2Parent)))
573 FIXME("couldn't get IPersistFolder2 interface of parent\n");
574 return E_NOINTERFACE;
577 if (FAILED(IPersistFolder2_GetCurFolder(ppf2Parent, &temp_parent)))
579 FIXME("couldn't get parent PIDL\n");
580 IPersistFolder2_Release(ppf2Parent);
581 return E_NOINTERFACE;
584 pidlParent = temp_parent;
585 IPersistFolder2_Release(ppf2Parent);
588 new_pidl = ILCombine(pidlParent, pidl);
589 ILFree(temp_parent);
591 if (!new_pidl)
592 return E_OUTOFMEMORY;
594 else
596 new_pidl = ILClone(pidl);
597 if (!new_pidl)
598 return E_OUTOFMEMORY;
601 ret = IShellItem_Constructor(NULL, &IID_IShellItem, (void**)&This);
602 if (This)
604 *ppsi = (IShellItem*)&This->IShellItem2_iface;
605 This->pidl = new_pidl;
607 else
609 ILFree(new_pidl);
611 return ret;
614 HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath,
615 IBindCtx *pbc, REFIID riid, void **ppv)
617 LPITEMIDLIST pidl;
618 HRESULT ret;
620 *ppv = NULL;
622 ret = SHParseDisplayName(pszPath, pbc, &pidl, 0, NULL);
623 if(SUCCEEDED(ret))
625 ShellItem *This;
626 ret = IShellItem_Constructor(NULL, riid, (void**)&This);
628 if(SUCCEEDED(ret))
630 This->pidl = pidl;
631 *ppv = (void*)This;
633 else
635 ILFree(pidl);
638 return ret;
641 HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv)
643 ShellItem *psiimpl;
644 HRESULT ret;
646 if(!pidl)
647 return E_INVALIDARG;
649 ret = IShellItem_Constructor(NULL, riid, ppv);
650 if(SUCCEEDED(ret))
652 psiimpl = (ShellItem*)*ppv;
653 psiimpl->pidl = ILClone(pidl);
656 return ret;
659 HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj,
660 DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv)
662 FORMATETC fmt;
663 STGMEDIUM medium;
664 HRESULT ret;
666 TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(riid), ppv);
668 if(!pdtobj)
669 return E_INVALIDARG;
671 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
672 fmt.ptd = NULL;
673 fmt.dwAspect = DVASPECT_CONTENT;
674 fmt.lindex = -1;
675 fmt.tymed = TYMED_HGLOBAL;
677 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
678 if(SUCCEEDED(ret))
680 LPIDA pida = GlobalLock(medium.u.hGlobal);
682 if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) ||
683 pida->cidl == 1)
685 LPITEMIDLIST pidl;
687 /* Get the first pidl (parent + child1) */
688 pidl = ILCombine((LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]),
689 (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]));
691 ret = SHCreateItemFromIDList(pidl, riid, ppv);
692 ILFree(pidl);
694 else
696 ret = E_FAIL;
699 GlobalUnlock(medium.u.hGlobal);
700 GlobalFree(medium.u.hGlobal);
703 if(FAILED(ret) && !(dwFlags & DOGIF_NO_HDROP))
705 TRACE("Attempting to fall back on CF_HDROP.\n");
707 fmt.cfFormat = CF_HDROP;
708 fmt.ptd = NULL;
709 fmt.dwAspect = DVASPECT_CONTENT;
710 fmt.lindex = -1;
711 fmt.tymed = TYMED_HGLOBAL;
713 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
714 if(SUCCEEDED(ret))
716 DROPFILES *df = GlobalLock(medium.u.hGlobal);
717 LPBYTE files = (LPBYTE)df + df->pFiles;
718 BOOL multiple_files = FALSE;
720 ret = E_FAIL;
721 if(!df->fWide)
723 WCHAR filename[MAX_PATH];
724 PCSTR first_file = (PCSTR)files;
725 if(*(files + lstrlenA(first_file) + 1) != 0)
726 multiple_files = TRUE;
728 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
730 MultiByteToWideChar(CP_ACP, 0, first_file, -1, filename, MAX_PATH);
731 ret = SHCreateItemFromParsingName(filename, NULL, riid, ppv);
734 else
736 PCWSTR first_file = (PCWSTR)files;
737 if(*((PCWSTR)files + lstrlenW(first_file) + 1) != 0)
738 multiple_files = TRUE;
740 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
741 ret = SHCreateItemFromParsingName(first_file, NULL, riid, ppv);
744 GlobalUnlock(medium.u.hGlobal);
745 GlobalFree(medium.u.hGlobal);
749 if(FAILED(ret) && !(dwFlags & DOGIF_NO_URL))
751 FIXME("Failed to create item, should try CF_URL.\n");
754 return ret;
757 HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
759 LPITEMIDLIST pidl;
760 HRESULT ret;
762 ret = SHGetIDListFromObject(punk, &pidl);
763 if(SUCCEEDED(ret))
765 ret = SHCreateItemFromIDList(pidl, riid, ppv);
766 ILFree(pidl);
769 return ret;
772 /*************************************************************************
773 * IEnumShellItems implementation
775 typedef struct {
776 IEnumShellItems IEnumShellItems_iface;
777 LONG ref;
779 IShellItemArray *array;
780 DWORD count;
781 DWORD position;
782 } IEnumShellItemsImpl;
784 static inline IEnumShellItemsImpl *impl_from_IEnumShellItems(IEnumShellItems *iface)
786 return CONTAINING_RECORD(iface, IEnumShellItemsImpl, IEnumShellItems_iface);
789 static HRESULT WINAPI IEnumShellItems_fnQueryInterface(IEnumShellItems *iface,
790 REFIID riid,
791 void **ppvObject)
793 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
794 TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
796 *ppvObject = NULL;
797 if(IsEqualIID(riid, &IID_IEnumShellItems) ||
798 IsEqualIID(riid, &IID_IUnknown))
800 *ppvObject = &This->IEnumShellItems_iface;
803 if(*ppvObject)
805 IUnknown_AddRef((IUnknown*)*ppvObject);
806 return S_OK;
809 return E_NOINTERFACE;
812 static ULONG WINAPI IEnumShellItems_fnAddRef(IEnumShellItems *iface)
814 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
815 LONG ref = InterlockedIncrement(&This->ref);
816 TRACE("%p - ref %d\n", This, ref);
818 return ref;
821 static ULONG WINAPI IEnumShellItems_fnRelease(IEnumShellItems *iface)
823 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
824 LONG ref = InterlockedDecrement(&This->ref);
825 TRACE("%p - ref %d\n", This, ref);
827 if(!ref)
829 TRACE("Freeing.\n");
830 IShellItemArray_Release(This->array);
831 HeapFree(GetProcessHeap(), 0, This);
832 return 0;
835 return ref;
838 static HRESULT WINAPI IEnumShellItems_fnNext(IEnumShellItems* iface,
839 ULONG celt,
840 IShellItem **rgelt,
841 ULONG *pceltFetched)
843 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
844 HRESULT hr = S_FALSE;
845 UINT i;
846 ULONG fetched = 0;
847 TRACE("%p (%d %p %p)\n", This, celt, rgelt, pceltFetched);
849 if(pceltFetched == NULL && celt != 1)
850 return E_INVALIDARG;
852 for(i = This->position; fetched < celt && i < This->count; i++) {
853 hr = IShellItemArray_GetItemAt(This->array, i, &rgelt[fetched]);
854 if(FAILED(hr))
855 break;
856 fetched++;
857 This->position++;
860 if(SUCCEEDED(hr))
862 if(pceltFetched != NULL)
863 *pceltFetched = fetched;
865 if(fetched > 0)
866 return S_OK;
868 return S_FALSE;
871 return hr;
874 static HRESULT WINAPI IEnumShellItems_fnSkip(IEnumShellItems* iface, ULONG celt)
876 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
877 TRACE("%p (%d)\n", This, celt);
879 This->position = min(This->position + celt, This->count-1);
881 return S_OK;
884 static HRESULT WINAPI IEnumShellItems_fnReset(IEnumShellItems* iface)
886 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
887 TRACE("%p\n", This);
889 This->position = 0;
891 return S_OK;
894 static HRESULT WINAPI IEnumShellItems_fnClone(IEnumShellItems* iface, IEnumShellItems **ppenum)
896 IEnumShellItemsImpl *This = impl_from_IEnumShellItems(iface);
897 TRACE("%p (%p)\n", This, ppenum);
899 /* Not implemented anywhere */
900 *ppenum = NULL;
902 return E_NOTIMPL;
905 static const IEnumShellItemsVtbl vt_IEnumShellItems = {
906 IEnumShellItems_fnQueryInterface,
907 IEnumShellItems_fnAddRef,
908 IEnumShellItems_fnRelease,
909 IEnumShellItems_fnNext,
910 IEnumShellItems_fnSkip,
911 IEnumShellItems_fnReset,
912 IEnumShellItems_fnClone
915 static HRESULT IEnumShellItems_Constructor(IShellItemArray *array, IEnumShellItems **ppesi)
917 IEnumShellItemsImpl *This;
918 HRESULT ret;
920 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumShellItemsImpl));
921 if(!This)
922 return E_OUTOFMEMORY;
924 This->ref = 1;
925 This->IEnumShellItems_iface.lpVtbl = &vt_IEnumShellItems;
926 This->array = array;
927 This->position = 0;
929 IShellItemArray_AddRef(This->array);
930 IShellItemArray_GetCount(This->array, &This->count);
932 ret = IEnumShellItems_QueryInterface(&This->IEnumShellItems_iface, &IID_IEnumShellItems, (void**)ppesi);
933 IEnumShellItems_Release(&This->IEnumShellItems_iface);
935 return ret;
939 /*************************************************************************
940 * IShellItemArray implementation
942 typedef struct {
943 IShellItemArray IShellItemArray_iface;
944 LONG ref;
946 IShellItem **array;
947 DWORD item_count;
948 } IShellItemArrayImpl;
950 static inline IShellItemArrayImpl *impl_from_IShellItemArray(IShellItemArray *iface)
952 return CONTAINING_RECORD(iface, IShellItemArrayImpl, IShellItemArray_iface);
955 static HRESULT WINAPI IShellItemArray_fnQueryInterface(IShellItemArray *iface,
956 REFIID riid,
957 void **ppvObject)
959 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
960 TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
962 *ppvObject = NULL;
963 if(IsEqualIID(riid, &IID_IShellItemArray) ||
964 IsEqualIID(riid, &IID_IUnknown))
966 *ppvObject = &This->IShellItemArray_iface;
969 if(*ppvObject)
971 IUnknown_AddRef((IUnknown*)*ppvObject);
972 return S_OK;
975 return E_NOINTERFACE;
978 static ULONG WINAPI IShellItemArray_fnAddRef(IShellItemArray *iface)
980 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
981 LONG ref = InterlockedIncrement(&This->ref);
982 TRACE("%p - ref %d\n", This, ref);
984 return ref;
987 static ULONG WINAPI IShellItemArray_fnRelease(IShellItemArray *iface)
989 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
990 LONG ref = InterlockedDecrement(&This->ref);
991 TRACE("%p - ref %d\n", This, ref);
993 if(!ref)
995 UINT i;
996 TRACE("Freeing.\n");
998 for(i = 0; i < This->item_count; i++)
999 IShellItem_Release(This->array[i]);
1001 HeapFree(GetProcessHeap(), 0, This->array);
1002 HeapFree(GetProcessHeap(), 0, This);
1003 return 0;
1006 return ref;
1009 static HRESULT WINAPI IShellItemArray_fnBindToHandler(IShellItemArray *iface,
1010 IBindCtx *pbc,
1011 REFGUID bhid,
1012 REFIID riid,
1013 void **ppvOut)
1015 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1016 FIXME("Stub: %p (%p, %s, %s, %p)\n",
1017 This, pbc, shdebugstr_guid(bhid), shdebugstr_guid(riid), ppvOut);
1019 return E_NOTIMPL;
1022 static HRESULT WINAPI IShellItemArray_fnGetPropertyStore(IShellItemArray *iface,
1023 GETPROPERTYSTOREFLAGS flags,
1024 REFIID riid,
1025 void **ppv)
1027 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1028 FIXME("Stub: %p (%x, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
1030 return E_NOTIMPL;
1033 static HRESULT WINAPI IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray *iface,
1034 REFPROPERTYKEY keyType,
1035 REFIID riid,
1036 void **ppv)
1038 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1039 FIXME("Stub: %p (%p, %s, %p)\n",
1040 This, keyType, shdebugstr_guid(riid), ppv);
1042 return E_NOTIMPL;
1045 static HRESULT WINAPI IShellItemArray_fnGetAttributes(IShellItemArray *iface,
1046 SIATTRIBFLAGS AttribFlags,
1047 SFGAOF sfgaoMask,
1048 SFGAOF *psfgaoAttribs)
1050 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1051 HRESULT hr = S_OK;
1052 SFGAOF attr;
1053 UINT i;
1054 TRACE("%p (%x, %x, %p)\n", This, AttribFlags, sfgaoMask, psfgaoAttribs);
1056 if(AttribFlags & ~(SIATTRIBFLAGS_AND|SIATTRIBFLAGS_OR))
1057 FIXME("%08x contains unsupported attribution flags\n", AttribFlags);
1059 for(i = 0; i < This->item_count; i++)
1061 hr = IShellItem_GetAttributes(This->array[i], sfgaoMask, &attr);
1062 if(FAILED(hr))
1063 break;
1065 if(i == 0)
1067 *psfgaoAttribs = attr;
1068 continue;
1071 switch(AttribFlags & SIATTRIBFLAGS_MASK)
1073 case SIATTRIBFLAGS_AND:
1074 *psfgaoAttribs &= attr;
1075 break;
1076 case SIATTRIBFLAGS_OR:
1077 *psfgaoAttribs |= attr;
1078 break;
1082 if(SUCCEEDED(hr))
1084 if(*psfgaoAttribs == sfgaoMask)
1085 return S_OK;
1087 return S_FALSE;
1090 return hr;
1093 static HRESULT WINAPI IShellItemArray_fnGetCount(IShellItemArray *iface,
1094 DWORD *pdwNumItems)
1096 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1097 TRACE("%p (%p)\n", This, pdwNumItems);
1099 *pdwNumItems = This->item_count;
1101 return S_OK;
1104 static HRESULT WINAPI IShellItemArray_fnGetItemAt(IShellItemArray *iface,
1105 DWORD dwIndex,
1106 IShellItem **ppsi)
1108 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1109 TRACE("%p (%x, %p)\n", This, dwIndex, ppsi);
1111 /* zero indexed */
1112 if(dwIndex + 1 > This->item_count)
1113 return E_FAIL;
1115 *ppsi = This->array[dwIndex];
1116 IShellItem_AddRef(*ppsi);
1118 return S_OK;
1121 static HRESULT WINAPI IShellItemArray_fnEnumItems(IShellItemArray *iface,
1122 IEnumShellItems **ppenumShellItems)
1124 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
1125 HRESULT hr;
1126 TRACE("%p (%p)\n", This, ppenumShellItems);
1128 hr = IEnumShellItems_Constructor(iface, ppenumShellItems);
1130 return hr;
1133 static const IShellItemArrayVtbl vt_IShellItemArray = {
1134 IShellItemArray_fnQueryInterface,
1135 IShellItemArray_fnAddRef,
1136 IShellItemArray_fnRelease,
1137 IShellItemArray_fnBindToHandler,
1138 IShellItemArray_fnGetPropertyStore,
1139 IShellItemArray_fnGetPropertyDescriptionList,
1140 IShellItemArray_fnGetAttributes,
1141 IShellItemArray_fnGetCount,
1142 IShellItemArray_fnGetItemAt,
1143 IShellItemArray_fnEnumItems
1146 static HRESULT IShellItemArray_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
1148 IShellItemArrayImpl *This;
1149 HRESULT ret;
1151 TRACE("(%p, %s, %p)\n",pUnkOuter, debugstr_guid(riid), ppv);
1153 if(pUnkOuter)
1154 return CLASS_E_NOAGGREGATION;
1156 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl));
1157 if(!This)
1158 return E_OUTOFMEMORY;
1160 This->ref = 1;
1161 This->IShellItemArray_iface.lpVtbl = &vt_IShellItemArray;
1162 This->array = NULL;
1163 This->item_count = 0;
1165 ret = IShellItemArray_QueryInterface(&This->IShellItemArray_iface, riid, ppv);
1166 IShellItemArray_Release(&This->IShellItemArray_iface);
1168 return ret;
1171 HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent,
1172 IShellFolder *psf,
1173 UINT cidl,
1174 PCUITEMID_CHILD_ARRAY ppidl,
1175 IShellItemArray **ppsiItemArray)
1177 IShellItemArrayImpl *This;
1178 IShellItem **array;
1179 HRESULT ret = E_FAIL;
1180 UINT i;
1182 TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray);
1184 if(!pidlParent && !psf)
1185 return E_POINTER;
1187 if(!ppidl)
1188 return E_INVALIDARG;
1190 array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*));
1191 if(!array)
1192 return E_OUTOFMEMORY;
1194 for(i = 0; i < cidl; i++)
1196 ret = SHCreateShellItem(pidlParent, psf, ppidl[i], &array[i]);
1197 if(FAILED(ret)) break;
1200 if(SUCCEEDED(ret))
1202 ret = IShellItemArray_Constructor(NULL, &IID_IShellItemArray, (void**)&This);
1203 if(SUCCEEDED(ret))
1205 This->array = array;
1206 This->item_count = cidl;
1207 *ppsiItemArray = &This->IShellItemArray_iface;
1209 return ret;
1213 /* Something failed, clean up. */
1214 for(i = 0; i < cidl; i++)
1215 if(array[i]) IShellItem_Release(array[i]);
1216 HeapFree(GetProcessHeap(), 0, array);
1217 *ppsiItemArray = NULL;
1218 return ret;
1221 HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *psi, REFIID riid, void **ppv)
1223 IShellItemArrayImpl *This;
1224 IShellItem **array;
1225 HRESULT ret;
1227 TRACE("%p, %s, %p\n", psi, shdebugstr_guid(riid), ppv);
1229 array = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItem*));
1230 if(!array)
1231 return E_OUTOFMEMORY;
1233 ret = IShellItemArray_Constructor(NULL, riid, (void**)&This);
1234 if(SUCCEEDED(ret))
1236 array[0] = psi;
1237 IShellItem_AddRef(psi);
1238 This->array = array;
1239 This->item_count = 1;
1240 *ppv = This;
1242 else
1244 HeapFree(GetProcessHeap(), 0, array);
1245 *ppv = NULL;
1248 return ret;
1251 HRESULT WINAPI SHCreateShellItemArrayFromDataObject(IDataObject *pdo, REFIID riid, void **ppv)
1253 IShellItemArray *psia;
1254 FORMATETC fmt;
1255 STGMEDIUM medium;
1256 HRESULT ret;
1258 TRACE("%p, %s, %p\n", pdo, shdebugstr_guid(riid), ppv);
1260 if(!pdo)
1261 return E_INVALIDARG;
1263 *ppv = NULL;
1265 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
1266 fmt.ptd = NULL;
1267 fmt.dwAspect = DVASPECT_CONTENT;
1268 fmt.lindex = -1;
1269 fmt.tymed = TYMED_HGLOBAL;
1271 ret = IDataObject_GetData(pdo, &fmt, &medium);
1272 if(SUCCEEDED(ret))
1274 LPIDA pida = GlobalLock(medium.u.hGlobal);
1275 LPCITEMIDLIST parent_pidl;
1276 LPCITEMIDLIST *children;
1277 UINT i;
1278 TRACE("Converting %d objects.\n", pida->cidl);
1280 parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
1282 children = HeapAlloc(GetProcessHeap(), 0, sizeof(LPCITEMIDLIST)*pida->cidl);
1283 for(i = 0; i < pida->cidl; i++)
1284 children[i] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i+1]);
1286 ret = SHCreateShellItemArray(parent_pidl, NULL, pida->cidl, children, &psia);
1288 HeapFree(GetProcessHeap(), 0, children);
1290 GlobalUnlock(medium.u.hGlobal);
1291 GlobalFree(medium.u.hGlobal);
1294 if(SUCCEEDED(ret))
1296 ret = IShellItemArray_QueryInterface(psia, riid, ppv);
1297 IShellItemArray_Release(psia);
1300 return ret;
1303 HRESULT WINAPI SHCreateShellItemArrayFromIDLists(UINT cidl,
1304 PCIDLIST_ABSOLUTE_ARRAY pidl_array,
1305 IShellItemArray **psia)
1307 IShellItemArrayImpl *This;
1308 IShellItem **array;
1309 HRESULT ret;
1310 UINT i;
1311 TRACE("%d, %p, %p\n", cidl, pidl_array, psia);
1313 *psia = NULL;
1315 if(cidl == 0)
1316 return E_INVALIDARG;
1318 array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IShellItem*));
1319 if(!array)
1320 return E_OUTOFMEMORY;
1322 for(i = 0; i < cidl; i++)
1324 ret = SHCreateShellItem(NULL, NULL, pidl_array[i], &array[i]);
1325 if(FAILED(ret))
1326 break;
1329 if(SUCCEEDED(ret))
1331 ret = IShellItemArray_Constructor(NULL, &IID_IShellItemArray, (void**)psia);
1332 if(SUCCEEDED(ret))
1334 This = impl_from_IShellItemArray(*psia);
1335 This->array = array;
1336 This->item_count = cidl;
1337 return S_OK;
1341 for(i = 0; i < cidl; i++)
1342 if(array[i]) IShellItem_Release(array[i]);
1343 HeapFree(GetProcessHeap(), 0, array);
1344 *psia = NULL;
1345 return ret;