2 * IShellItem and IShellItemArray implementations
4 * Copyright 2008 Vincent Povirk for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
33 #include "wine/debug.h"
36 #include "shell32_main.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(shell);
41 typedef struct _ShellItem {
42 const IShellItemVtbl *lpIShellItemVtbl;
45 const IPersistIDListVtbl *lpIPersistIDListVtbl;
49 static inline ShellItem *impl_from_IPersistIDList( IPersistIDList *iface )
51 return (ShellItem*)((char*)iface - FIELD_OFFSET(ShellItem, lpIPersistIDListVtbl));
55 static HRESULT WINAPI ShellItem_QueryInterface(IShellItem *iface, REFIID riid,
58 ShellItem *This = (ShellItem*)iface;
60 TRACE("(%p,%p,%p)\n", iface, riid, ppv);
62 if (!ppv) return E_INVALIDARG;
64 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellItem, riid))
68 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistIDList, riid))
70 *ppv = &(This->lpIPersistIDListVtbl);
73 FIXME("not implemented for %s\n", shdebugstr_guid(riid));
78 IUnknown_AddRef((IUnknown*)*ppv);
82 static ULONG WINAPI ShellItem_AddRef(IShellItem *iface)
84 ShellItem *This = (ShellItem*)iface;
85 ULONG ref = InterlockedIncrement(&This->ref);
87 TRACE("(%p), new refcount=%i\n", iface, ref);
92 static ULONG WINAPI ShellItem_Release(IShellItem *iface)
94 ShellItem *This = (ShellItem*)iface;
95 ULONG ref = InterlockedDecrement(&This->ref);
97 TRACE("(%p), new refcount=%i\n", iface, ref);
102 HeapFree(GetProcessHeap(), 0, This);
108 static HRESULT ShellItem_get_parent_pidl(ShellItem *This, LPITEMIDLIST *parent_pidl)
110 *parent_pidl = ILClone(This->pidl);
113 if (ILRemoveLastID(*parent_pidl))
117 ILFree(*parent_pidl);
125 return E_OUTOFMEMORY;
129 static HRESULT ShellItem_get_parent_shellfolder(ShellItem *This, IShellFolder **ppsf)
131 LPITEMIDLIST parent_pidl;
132 IShellFolder *desktop;
135 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
138 ret = SHGetDesktopFolder(&desktop);
141 ret = IShellFolder_BindToObject(desktop, parent_pidl, NULL, &IID_IShellFolder, (void**)ppsf);
142 IShellFolder_Release(desktop);
150 static HRESULT ShellItem_get_shellfolder(ShellItem *This, IBindCtx *pbc, IShellFolder **ppsf)
152 IShellFolder *desktop;
155 ret = SHGetDesktopFolder(&desktop);
158 if (_ILIsDesktop(This->pidl))
161 IShellFolder_AddRef(*ppsf);
165 ret = IShellFolder_BindToObject(desktop, This->pidl, pbc, &IID_IShellFolder, (void**)ppsf);
168 IShellFolder_Release(desktop);
174 static HRESULT WINAPI ShellItem_BindToHandler(IShellItem *iface, IBindCtx *pbc,
175 REFGUID rbhid, REFIID riid, void **ppvOut)
177 ShellItem *This = (ShellItem*)iface;
179 TRACE("(%p,%p,%s,%p,%p)\n", iface, pbc, shdebugstr_guid(rbhid), riid, ppvOut);
182 if (IsEqualGUID(rbhid, &BHID_SFObject))
185 ret = ShellItem_get_shellfolder(This, pbc, &psf);
188 ret = IShellFolder_QueryInterface(psf, riid, ppvOut);
189 IShellFolder_Release(psf);
194 FIXME("Unsupported BHID %s.\n", debugstr_guid(rbhid));
196 return MK_E_NOOBJECT;
199 static HRESULT WINAPI ShellItem_GetParent(IShellItem *iface, IShellItem **ppsi)
201 ShellItem *This = (ShellItem*)iface;
202 LPITEMIDLIST parent_pidl;
205 TRACE("(%p,%p)\n", iface, ppsi);
207 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
210 ret = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi);
217 static HRESULT WINAPI ShellItem_GetDisplayName(IShellItem *iface, SIGDN sigdnName,
220 ShellItem *This = (ShellItem*)iface;
221 TRACE("(%p,%x,%p)\n", iface, sigdnName, ppszName);
223 return SHGetNameFromIDList(This->pidl, sigdnName, ppszName);
226 static HRESULT WINAPI ShellItem_GetAttributes(IShellItem *iface, SFGAOF sfgaoMask,
227 SFGAOF *psfgaoAttribs)
229 ShellItem *This = (ShellItem*)iface;
230 IShellFolder *parent_folder;
231 LPITEMIDLIST child_pidl;
234 TRACE("(%p,%x,%p)\n", iface, sfgaoMask, psfgaoAttribs);
236 ret = ShellItem_get_parent_shellfolder(This, &parent_folder);
239 child_pidl = ILFindLastID(This->pidl);
240 *psfgaoAttribs = sfgaoMask;
241 ret = IShellFolder_GetAttributesOf(parent_folder, 1, (LPCITEMIDLIST*)&child_pidl, psfgaoAttribs);
242 IShellFolder_Release(parent_folder);
248 static HRESULT WINAPI ShellItem_Compare(IShellItem *iface, IShellItem *oth,
249 SICHINTF hint, int *piOrder)
251 LPWSTR dispname, dispname_oth;
253 TRACE("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder);
255 if(hint & (SICHINT_CANONICAL | SICHINT_ALLFIELDS))
256 FIXME("Unsupported flags 0x%08x\n", hint);
258 ret = IShellItem_GetDisplayName(iface, SIGDN_DESKTOPABSOLUTEEDITING, &dispname);
261 ret = IShellItem_GetDisplayName(oth, SIGDN_DESKTOPABSOLUTEEDITING, &dispname_oth);
264 *piOrder = lstrcmpiW(dispname, dispname_oth);
265 CoTaskMemFree(dispname_oth);
267 CoTaskMemFree(dispname);
270 if(SUCCEEDED(ret) && *piOrder &&
271 (hint & SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL))
273 LPWSTR dispname, dispname_oth;
275 TRACE("Testing filesystem path.\n");
276 ret = IShellItem_GetDisplayName(iface, SIGDN_FILESYSPATH, &dispname);
279 ret = IShellItem_GetDisplayName(oth, SIGDN_FILESYSPATH, &dispname_oth);
282 *piOrder = lstrcmpiW(dispname, dispname_oth);
283 CoTaskMemFree(dispname_oth);
285 CoTaskMemFree(dispname);
298 static const IShellItemVtbl ShellItem_Vtbl = {
299 ShellItem_QueryInterface,
302 ShellItem_BindToHandler,
304 ShellItem_GetDisplayName,
305 ShellItem_GetAttributes,
310 static HRESULT ShellItem_GetClassID(ShellItem* This, CLSID *pClassID)
312 TRACE("(%p,%p)\n", This, pClassID);
314 *pClassID = CLSID_ShellItem;
319 static HRESULT WINAPI ShellItem_IPersistIDList_QueryInterface(IPersistIDList *iface,
320 REFIID riid, void **ppv)
322 ShellItem *This = impl_from_IPersistIDList(iface);
323 return ShellItem_QueryInterface((IShellItem*)This, riid, ppv);
326 static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface)
328 ShellItem *This = impl_from_IPersistIDList(iface);
329 return ShellItem_AddRef((IShellItem*)This);
332 static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface)
334 ShellItem *This = impl_from_IPersistIDList(iface);
335 return ShellItem_Release((IShellItem*)This);
338 static HRESULT WINAPI ShellItem_IPersistIDList_GetClassID(IPersistIDList* iface,
341 ShellItem *This = impl_from_IPersistIDList(iface);
343 return ShellItem_GetClassID(This, pClassID);
346 static HRESULT WINAPI ShellItem_IPersistIDList_SetIDList(IPersistIDList* iface,
349 ShellItem *This = impl_from_IPersistIDList(iface);
350 LPITEMIDLIST new_pidl;
352 TRACE("(%p,%p)\n", This, pidl);
354 new_pidl = ILClone(pidl);
359 This->pidl = new_pidl;
363 return E_OUTOFMEMORY;
366 static HRESULT WINAPI ShellItem_IPersistIDList_GetIDList(IPersistIDList* iface,
369 ShellItem *This = impl_from_IPersistIDList(iface);
371 TRACE("(%p,%p)\n", This, ppidl);
373 *ppidl = ILClone(This->pidl);
377 return E_OUTOFMEMORY;
380 static const IPersistIDListVtbl ShellItem_IPersistIDList_Vtbl = {
381 ShellItem_IPersistIDList_QueryInterface,
382 ShellItem_IPersistIDList_AddRef,
383 ShellItem_IPersistIDList_Release,
384 ShellItem_IPersistIDList_GetClassID,
385 ShellItem_IPersistIDList_SetIDList,
386 ShellItem_IPersistIDList_GetIDList
390 HRESULT WINAPI IShellItem_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
395 TRACE("(%p,%s)\n",pUnkOuter, debugstr_guid(riid));
399 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
401 This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem));
402 This->lpIShellItemVtbl = &ShellItem_Vtbl;
405 This->lpIPersistIDListVtbl = &ShellItem_IPersistIDList_Vtbl;
407 ret = ShellItem_QueryInterface((IShellItem*)This, riid, ppv);
408 ShellItem_Release((IShellItem*)This);
413 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
414 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
417 LPITEMIDLIST new_pidl;
420 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
426 else if (pidlParent || psfParent)
428 LPITEMIDLIST temp_parent=NULL;
431 IPersistFolder2* ppf2Parent;
433 if (FAILED(IPersistFolder2_QueryInterface(psfParent, &IID_IPersistFolder2, (void**)&ppf2Parent)))
435 FIXME("couldn't get IPersistFolder2 interface of parent\n");
436 return E_NOINTERFACE;
439 if (FAILED(IPersistFolder2_GetCurFolder(ppf2Parent, &temp_parent)))
441 FIXME("couldn't get parent PIDL\n");
442 IPersistFolder2_Release(ppf2Parent);
443 return E_NOINTERFACE;
446 pidlParent = temp_parent;
447 IPersistFolder2_Release(ppf2Parent);
450 new_pidl = ILCombine(pidlParent, pidl);
454 return E_OUTOFMEMORY;
458 new_pidl = ILClone(pidl);
460 return E_OUTOFMEMORY;
463 ret = IShellItem_Constructor(NULL, &IID_IShellItem, (void**)&This);
466 *ppsi = (IShellItem*)This;
467 This->pidl = new_pidl;
477 HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath,
478 IBindCtx *pbc, REFIID riid, void **ppv)
485 ret = SHParseDisplayName(pszPath, pbc, &pidl, 0, NULL);
489 ret = IShellItem_Constructor(NULL, riid, (void**)&This);
504 HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv)
512 ret = IShellItem_Constructor(NULL, riid, ppv);
515 psiimpl = (ShellItem*)*ppv;
516 psiimpl->pidl = ILClone(pidl);
522 HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj,
523 DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv)
529 TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(riid), ppv);
534 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
536 fmt.dwAspect = DVASPECT_CONTENT;
538 fmt.tymed = TYMED_HGLOBAL;
540 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
543 LPIDA pida = GlobalLock(medium.u.hGlobal);
545 if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) ||
550 /* Get the first pidl (parent + child1) */
551 pidl = ILCombine((LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]),
552 (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]));
554 ret = SHCreateItemFromIDList(pidl, riid, ppv);
562 GlobalUnlock(medium.u.hGlobal);
563 GlobalFree(medium.u.hGlobal);
566 if(FAILED(ret) && !(dwFlags & DOGIF_NO_HDROP))
568 TRACE("Attempting to fall back on CF_HDROP.\n");
570 fmt.cfFormat = CF_HDROP;
572 fmt.dwAspect = DVASPECT_CONTENT;
574 fmt.tymed = TYMED_HGLOBAL;
576 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
579 DROPFILES *df = GlobalLock(medium.u.hGlobal);
580 LPBYTE files = (LPBYTE)df + df->pFiles;
581 BOOL multiple_files = FALSE;
586 WCHAR filename[MAX_PATH];
587 PCSTR first_file = (PCSTR)files;
588 if(*(files + lstrlenA(first_file) + 1) != 0)
589 multiple_files = TRUE;
591 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
593 MultiByteToWideChar(CP_ACP, 0, first_file, -1, filename, MAX_PATH);
594 ret = SHCreateItemFromParsingName(filename, NULL, riid, ppv);
599 PCWSTR first_file = (PCWSTR)files;
600 if(*((PCWSTR)files + lstrlenW(first_file) + 1) != 0)
601 multiple_files = TRUE;
603 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
604 ret = SHCreateItemFromParsingName(first_file, NULL, riid, ppv);
607 GlobalUnlock(medium.u.hGlobal);
608 GlobalFree(medium.u.hGlobal);
612 if(FAILED(ret) && !(dwFlags & DOGIF_NO_URL))
614 FIXME("Failed to create item, should try CF_URL.\n");
620 HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
625 ret = SHGetIDListFromObject(punk, &pidl);
628 ret = SHCreateItemFromIDList(pidl, riid, ppv);
635 /*************************************************************************
636 * IShellItemArray implementation
639 const IShellItemArrayVtbl *lpVtbl;
644 } IShellItemArrayImpl;
646 static HRESULT WINAPI IShellItemArray_fnQueryInterface(IShellItemArray *iface,
650 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
651 TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
654 if(IsEqualIID(riid, &IID_IShellItemArray) ||
655 IsEqualIID(riid, &IID_IUnknown))
662 IUnknown_AddRef((IUnknown*)*ppvObject);
666 return E_NOINTERFACE;
669 static ULONG WINAPI IShellItemArray_fnAddRef(IShellItemArray *iface)
671 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
672 LONG ref = InterlockedIncrement(&This->ref);
673 TRACE("%p - ref %d\n", This, ref);
678 static ULONG WINAPI IShellItemArray_fnRelease(IShellItemArray *iface)
680 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
681 LONG ref = InterlockedDecrement(&This->ref);
682 TRACE("%p - ref %d\n", This, ref);
689 for(i = 0; i < This->item_count; i++)
690 IShellItem_Release(This->array[i]);
692 HeapFree(GetProcessHeap(), 0, This->array);
693 HeapFree(GetProcessHeap(), 0, This);
700 static HRESULT WINAPI IShellItemArray_fnBindToHandler(IShellItemArray *iface,
706 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
707 FIXME("Stub: %p (%p, %s, %s, %p)\n",
708 This, pbc, shdebugstr_guid(bhid), shdebugstr_guid(riid), ppvOut);
713 static HRESULT WINAPI IShellItemArray_fnGetPropertyStore(IShellItemArray *iface,
714 GETPROPERTYSTOREFLAGS flags,
718 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
719 FIXME("Stub: %p (%x, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
724 static HRESULT WINAPI IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray *iface,
725 REFPROPERTYKEY keyType,
729 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
730 FIXME("Stub: %p (%p, %s, %p)\n",
731 This, keyType, shdebugstr_guid(riid), ppv);
736 static HRESULT WINAPI IShellItemArray_fnGetAttributes(IShellItemArray *iface,
737 SIATTRIBFLAGS AttribFlags,
739 SFGAOF *psfgaoAttribs)
741 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
742 FIXME("Stub: %p (%x, %x, %p)\n", This, AttribFlags, sfgaoMask, psfgaoAttribs);
747 static HRESULT WINAPI IShellItemArray_fnGetCount(IShellItemArray *iface,
750 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
751 TRACE("%p (%p)\n", This, pdwNumItems);
753 *pdwNumItems = This->item_count;
758 static HRESULT WINAPI IShellItemArray_fnGetItemAt(IShellItemArray *iface,
762 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
763 TRACE("%p (%x, %p)\n", This, dwIndex, ppsi);
766 if(dwIndex + 1 > This->item_count)
769 *ppsi = This->array[dwIndex];
770 IShellItem_AddRef(*ppsi);
775 static HRESULT WINAPI IShellItemArray_fnEnumItems(IShellItemArray *iface,
776 IEnumShellItems **ppenumShellItems)
778 IShellItemArrayImpl *This = (IShellItemArrayImpl *)iface;
779 FIXME("Stub: %p (%p)\n", This, ppenumShellItems);
784 static const IShellItemArrayVtbl vt_IShellItemArray = {
785 IShellItemArray_fnQueryInterface,
786 IShellItemArray_fnAddRef,
787 IShellItemArray_fnRelease,
788 IShellItemArray_fnBindToHandler,
789 IShellItemArray_fnGetPropertyStore,
790 IShellItemArray_fnGetPropertyDescriptionList,
791 IShellItemArray_fnGetAttributes,
792 IShellItemArray_fnGetCount,
793 IShellItemArray_fnGetItemAt,
794 IShellItemArray_fnEnumItems
797 static HRESULT IShellItemArray_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
799 IShellItemArrayImpl *This;
802 TRACE("(%p, %s, %p)\n",pUnkOuter, debugstr_guid(riid), ppv);
805 return CLASS_E_NOAGGREGATION;
807 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl));
809 return E_OUTOFMEMORY;
812 This->lpVtbl = &vt_IShellItemArray;
814 This->item_count = 0;
816 ret = IShellItemArray_QueryInterface((IShellItemArray*)This, riid, ppv);
817 IShellItemArray_Release((IShellItemArray*)This);
822 HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent,
825 PCUITEMID_CHILD_ARRAY ppidl,
826 IShellItemArray **ppsiItemArray)
828 IShellItemArrayImpl *This;
830 HRESULT ret = E_FAIL;
833 TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray);
835 if(!pidlParent && !psf)
841 array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*));
843 return E_OUTOFMEMORY;
845 for(i = 0; i < cidl; i++)
847 ret = SHCreateShellItem(pidlParent, psf, ppidl[i], &array[i]);
848 if(FAILED(ret)) break;
853 ret = IShellItemArray_Constructor(NULL, &IID_IShellItemArray, (void**)&This);
857 This->item_count = cidl;
858 *ppsiItemArray = (IShellItemArray*)This;
864 /* Something failed, clean up. */
865 for(i = 0; i < cidl; i++)
866 if(array[i]) IShellItem_Release(array[i]);
867 HeapFree(GetProcessHeap(), 0, array);
868 *ppsiItemArray = NULL;
872 HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *psi, REFIID riid, void **ppv)
874 IShellItemArrayImpl *This;
878 TRACE("%p, %s, %p\n", psi, shdebugstr_guid(riid), ppv);
880 array = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItem*));
882 return E_OUTOFMEMORY;
884 ret = IShellItemArray_Constructor(NULL, riid, (void**)&This);
888 IShellItem_AddRef(psi);
890 This->item_count = 1;
895 HeapFree(GetProcessHeap(), 0, array);
902 HRESULT WINAPI SHCreateShellItemArrayFromDataObject(IDataObject *pdo, REFIID riid, void **ppv)
904 IShellItemArray *psia;
909 TRACE("%p, %s, %p\n", pdo, shdebugstr_guid(riid), ppv);
916 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
918 fmt.dwAspect = DVASPECT_CONTENT;
920 fmt.tymed = TYMED_HGLOBAL;
922 ret = IDataObject_GetData(pdo, &fmt, &medium);
925 LPIDA pida = GlobalLock(medium.u.hGlobal);
926 LPCITEMIDLIST parent_pidl;
927 LPCITEMIDLIST *children;
929 TRACE("Converting %d objects.\n", pida->cidl);
931 parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
933 children = HeapAlloc(GetProcessHeap(), 0, sizeof(LPCITEMIDLIST)*pida->cidl);
934 for(i = 0; i < pida->cidl; i++)
935 children[i] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i+1]);
937 ret = SHCreateShellItemArray(parent_pidl, NULL, pida->cidl, children, (IShellItemArray**)&psia);
939 HeapFree(GetProcessHeap(), 0, children);
941 GlobalUnlock(medium.u.hGlobal);
942 GlobalFree(medium.u.hGlobal);
947 ret = IShellItemArray_QueryInterface(psia, riid, ppv);
948 IShellItemArray_Release(psia);