1 /*
2 * IShellItem and IShellItemArray implementations
3 *
4 * Copyright 2008 Vincent Povirk for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdio.h>
25 #include <stdarg.h>
26
27 #define COBJMACROS
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wine/debug.h"
34
35 #include "pidl.h"
36 #include "shell32_main.h"
37 #include "debughlp.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(shell);
40
41 typedef struct _ShellItem {
42 IShellItem2 IShellItem2_iface;
43 LONG ref;
44 LPITEMIDLIST pidl;
45 IPersistIDList IPersistIDList_iface;
46 } ShellItem;
47
48 static inline ShellItem *impl_from_IShellItem2(IShellItem2 *iface)
49 {
50 return CONTAINING_RECORD(iface, ShellItem, IShellItem2_iface);
51 }
52
53
54 static inline ShellItem *impl_from_IPersistIDList( IPersistIDList *iface )
55 {
56 return CONTAINING_RECORD(iface, ShellItem, IPersistIDList_iface);
57 }
58
59
60 static HRESULT WINAPI ShellItem_QueryInterface(IShellItem2 *iface, REFIID riid,
61 void **ppv)
62 {
63 ShellItem *This = impl_from_IShellItem2(iface);
64
65 TRACE("(%p,%p,%p)\n", iface, riid, ppv);
66
67 if (!ppv) return E_INVALIDARG;
68
69 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellItem, riid) ||
70 IsEqualIID(&IID_IShellItem2, riid))
71 {
72 *ppv = This;
73 }
74 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistIDList, riid))
75 {
76 *ppv = &This->IPersistIDList_iface;
77 }
78 else {
79 FIXME("not implemented for %s\n", shdebugstr_guid(riid));
80 *ppv = NULL;
81 return E_NOINTERFACE;
82 }
83
84 IUnknown_AddRef((IUnknown*)*ppv);
85 return S_OK;
86 }
87
88 static ULONG WINAPI ShellItem_AddRef(IShellItem2 *iface)
89 {
90 ShellItem *This = impl_from_IShellItem2(iface);
91 ULONG ref = InterlockedIncrement(&This->ref);
92
93 TRACE("(%p), new refcount=%i\n", iface, ref);
94
95 return ref;
96 }
97
98 static ULONG WINAPI ShellItem_Release(IShellItem2 *iface)
99 {
100 ShellItem *This = impl_from_IShellItem2(iface);
101 ULONG ref = InterlockedDecrement(&This->ref);
102
103 TRACE("(%p), new refcount=%i\n", iface, ref);
104
105 if (ref == 0)
106 {
107 ILFree(This->pidl);
108 HeapFree(GetProcessHeap(), 0, This);
109 }
110
111 return ref;
112 }
113
114 static HRESULT ShellItem_get_parent_pidl(ShellItem *This, LPITEMIDLIST *parent_pidl)
115 {
116 *parent_pidl = ILClone(This->pidl);
117 if (*parent_pidl)
118 {
119 if (ILRemoveLastID(*parent_pidl))
120 return S_OK;
121 else
122 {
123 ILFree(*parent_pidl);
124 *parent_pidl = NULL;
125 return E_INVALIDARG;
126 }
127 }
128 else
129 {
130 *parent_pidl = NULL;
131 return E_OUTOFMEMORY;
132 }
133 }
134
135 static HRESULT ShellItem_get_parent_shellfolder(ShellItem *This, IShellFolder **ppsf)
136 {
137 LPITEMIDLIST parent_pidl;
138 IShellFolder *desktop;
139 HRESULT ret;
140
141 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
142 if (SUCCEEDED(ret))
143 {
144 ret = SHGetDesktopFolder(&desktop);
145 if (SUCCEEDED(ret))
146 {
147 ret = IShellFolder_BindToObject(desktop, parent_pidl, NULL, &IID_IShellFolder, (void**)ppsf);
148 IShellFolder_Release(desktop);
149 }
150 ILFree(parent_pidl);
151 }
152
153 return ret;
154 }
155
156 static HRESULT ShellItem_get_shellfolder(ShellItem *This, IBindCtx *pbc, IShellFolder **ppsf)
157 {
158 IShellFolder *desktop;
159 HRESULT ret;
160
161 ret = SHGetDesktopFolder(&desktop);
162 if (SUCCEEDED(ret))
163 {
164 if (_ILIsDesktop(This->pidl))
165 {
166 *ppsf = desktop;
167 IShellFolder_AddRef(*ppsf);
168 }
169 else
170 {
171 ret = IShellFolder_BindToObject(desktop, This->pidl, pbc, &IID_IShellFolder, (void**)ppsf);
172 }
173
174 IShellFolder_Release(desktop);
175 }
176
177 return ret;
178 }
179
180 static HRESULT WINAPI ShellItem_BindToHandler(IShellItem2 *iface, IBindCtx *pbc,
181 REFGUID rbhid, REFIID riid, void **ppvOut)
182 {
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);
186
187 *ppvOut = NULL;
188 if (IsEqualGUID(rbhid, &BHID_SFObject))
189 {
190 IShellFolder *psf;
191 ret = ShellItem_get_shellfolder(This, pbc, &psf);
192 if (SUCCEEDED(ret))
193 {
194 ret = IShellFolder_QueryInterface(psf, riid, ppvOut);
195 IShellFolder_Release(psf);
196 }
197 return ret;
198 }
199 else if (IsEqualGUID(rbhid, &BHID_SFUIObject))
200 {
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);
206
207 if (SUCCEEDED(ret))
208 {
209 LPCITEMIDLIST pidl = ILFindLastID(This->pidl);
210 ret = IShellFolder_GetUIObjectOf(psf_parent, NULL, 1, &pidl, riid, NULL, ppvOut);
211 IShellFolder_Release(psf_parent);
212 }
213 return ret;
214 }
215 else if (IsEqualGUID(rbhid, &BHID_DataObject))
216 {
217 return ShellItem_BindToHandler(&This->IShellItem2_iface, pbc, &BHID_SFUIObject,
218 &IID_IDataObject, ppvOut);
219 }
220
221 FIXME("Unsupported BHID %s.\n", debugstr_guid(rbhid));
222
223 return MK_E_NOOBJECT;
224 }
225
226 static HRESULT WINAPI ShellItem_GetParent(IShellItem2 *iface, IShellItem **ppsi)
227 {
228 ShellItem *This = impl_from_IShellItem2(iface);
229 LPITEMIDLIST parent_pidl;
230 HRESULT ret;
231
232 TRACE("(%p,%p)\n", iface, ppsi);
233
234 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
235 if (SUCCEEDED(ret))
236 {
237 ret = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi);
238 ILFree(parent_pidl);
239 }
240
241 return ret;
242 }
243
244 static HRESULT WINAPI ShellItem_GetDisplayName(IShellItem2 *iface, SIGDN sigdnName,
245 LPWSTR *ppszName)
246 {
247 ShellItem *This = impl_from_IShellItem2(iface);
248 TRACE("(%p,%x,%p)\n", iface, sigdnName, ppszName);
249
250 return SHGetNameFromIDList(This->pidl, sigdnName, ppszName);
251 }
252
253 static HRESULT WINAPI ShellItem_GetAttributes(IShellItem2 *iface, SFGAOF sfgaoMask,
254 SFGAOF *psfgaoAttribs)
255 {
256 ShellItem *This = impl_from_IShellItem2(iface);
257 IShellFolder *parent_folder;
258 LPITEMIDLIST child_pidl;
259 HRESULT ret;
260
261 TRACE("(%p,%x,%p)\n", iface, sfgaoMask, psfgaoAttribs);
262
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))
268 {
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);
273 }
274
275 return ret;
276 }
277
278 static HRESULT WINAPI ShellItem_Compare(IShellItem2 *iface, IShellItem *oth,
279 SICHINTF hint, int *piOrder)
280 {
281 LPWSTR dispname, dispname_oth;
282 HRESULT ret;
283 TRACE("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder);
284
285 if(hint & (SICHINT_CANONICAL | SICHINT_ALLFIELDS))
286 FIXME("Unsupported flags 0x%08x\n", hint);
287
288 ret = IShellItem_GetDisplayName(iface, SIGDN_DESKTOPABSOLUTEEDITING, &dispname);
289 if(SUCCEEDED(ret))
290 {
291 ret = IShellItem_GetDisplayName(oth, SIGDN_DESKTOPABSOLUTEEDITING, &dispname_oth);
292 if(SUCCEEDED(ret))
293 {
294 *piOrder = lstrcmpiW(dispname, dispname_oth);
295 CoTaskMemFree(dispname_oth);
296 }
297 CoTaskMemFree(dispname);
298 }
299
300 if(SUCCEEDED(ret) && *piOrder &&
301 (hint & SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL))
302 {
303 LPWSTR dispname, dispname_oth;
304
305 TRACE("Testing filesystem path.\n");
306 ret = IShellItem_GetDisplayName(iface, SIGDN_FILESYSPATH, &dispname);
307 if(SUCCEEDED(ret))
308 {
309 ret = IShellItem_GetDisplayName(oth, SIGDN_FILESYSPATH, &dispname_oth);
310 if(SUCCEEDED(ret))
311 {
312 *piOrder = lstrcmpiW(dispname, dispname_oth);
313 CoTaskMemFree(dispname_oth);
314 }
315 CoTaskMemFree(dispname);
316 }
317 }
318
319 if(FAILED(ret))
320 return ret;
321
322 if(*piOrder)
323 return S_FALSE;
324 else
325 return S_OK;
326 }
327
328 static HRESULT WINAPI ShellItem2_GetPropertyStore(IShellItem2 *iface, GETPROPERTYSTOREFLAGS flags,
329 REFIID riid, void **ppv)
330 {
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;
334 }
335
336 static HRESULT WINAPI ShellItem2_GetPropertyStoreWithCreateObject(IShellItem2 *iface,
337 GETPROPERTYSTOREFLAGS flags, IUnknown *punkCreateObject, REFIID riid, void **ppv)
338 {
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;
343 }
344
345 static HRESULT WINAPI ShellItem2_GetPropertyStoreForKeys(IShellItem2 *iface, const PROPERTYKEY *rgKeys,
346 UINT cKeys, GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv)
347 {
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;
352 }
353
354 static HRESULT WINAPI ShellItem2_GetPropertyDescriptionList(IShellItem2 *iface,
355 REFPROPERTYKEY keyType, REFIID riid, void **ppv)
356 {
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;
360 }
361
362 static HRESULT WINAPI ShellItem2_Update(IShellItem2 *iface, IBindCtx *pbc)
363 {
364 ShellItem *This = impl_from_IShellItem2(iface);
365 FIXME("Stub: %p (%p)\n", This, pbc);
366 return E_NOTIMPL;
367 }
368
369 static HRESULT WINAPI ShellItem2_GetProperty(IShellItem2 *iface, REFPROPERTYKEY key, PROPVARIANT *ppropvar)
370 {
371 ShellItem *This = impl_from_IShellItem2(iface);
372 FIXME("Stub: %p (%p, %p)\n", This, key, ppropvar);
373 return E_NOTIMPL;
374 }
375
376 static HRESULT WINAPI ShellItem2_GetCLSID(IShellItem2 *iface, REFPROPERTYKEY key, CLSID *pclsid)
377 {
378 ShellItem *This = impl_from_IShellItem2(iface);
379 FIXME("Stub: %p (%p, %p)\n", This, key, pclsid);
380 return E_NOTIMPL;
381 }
382
383 static HRESULT WINAPI ShellItem2_GetFileTime(IShellItem2 *iface, REFPROPERTYKEY key, FILETIME *pft)
384 {
385 ShellItem *This = impl_from_IShellItem2(iface);
386 FIXME("Stub: %p (%p, %p)\n", This, key, pft);
387 return E_NOTIMPL;
388 }
389
390 static HRESULT WINAPI ShellItem2_GetInt32(IShellItem2 *iface, REFPROPERTYKEY key, int *pi)
391 {
392 ShellItem *This = impl_from_IShellItem2(iface);
393 FIXME("Stub: %p (%p, %p)\n", This, key, pi);
394 return E_NOTIMPL;
395 }
396
397 static HRESULT WINAPI ShellItem2_GetString(IShellItem2 *iface, REFPROPERTYKEY key, LPWSTR *ppsz)
398 {
399 ShellItem *This = impl_from_IShellItem2(iface);
400 FIXME("Stub: %p (%p, %p)\n", This, key, ppsz);
401 return E_NOTIMPL;
402 }
403
404 static HRESULT WINAPI ShellItem2_GetUInt32(IShellItem2 *iface, REFPROPERTYKEY key, ULONG *pui)
405 {
406 ShellItem *This = impl_from_IShellItem2(iface);
407 FIXME("Stub: %p (%p, %p)\n", This, key, pui);
408 return E_NOTIMPL;
409 }
410
411 static HRESULT WINAPI ShellItem2_GetUInt64(IShellItem2 *iface, REFPROPERTYKEY key, ULONGLONG *pull)
412 {
413 ShellItem *This = impl_from_IShellItem2(iface);
414 FIXME("Stub: %p (%p, %p)\n", This, key, pull);
415 return E_NOTIMPL;
416 }
417
418 static HRESULT WINAPI ShellItem2_GetBool(IShellItem2 *iface, REFPROPERTYKEY key, BOOL *pf)
419 {
420 ShellItem *This = impl_from_IShellItem2(iface);
421 FIXME("Stub: %p (%p, %p)\n", This, key, pf);
422 return E_NOTIMPL;
423 }
424
425
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
448 };
449
450
451 static HRESULT ShellItem_GetClassID(ShellItem* This, CLSID *pClassID)
452 {
453 TRACE("(%p,%p)\n", This, pClassID);
454
455 *pClassID = CLSID_ShellItem;
456 return S_OK;
457 }
458
459
460 static HRESULT WINAPI ShellItem_IPersistIDList_QueryInterface(IPersistIDList *iface,
461 REFIID riid, void **ppv)
462 {
463 ShellItem *This = impl_from_IPersistIDList(iface);
464 return ShellItem_QueryInterface(&This->IShellItem2_iface, riid, ppv);
465 }
466
467 static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface)
468 {
469 ShellItem *This = impl_from_IPersistIDList(iface);
470 return ShellItem_AddRef(&This->IShellItem2_iface);
471 }
472
473 static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface)
474 {
475 ShellItem *This = impl_from_IPersistIDList(iface);
476 return ShellItem_Release(&This->IShellItem2_iface);
477 }
478
479 static HRESULT WINAPI ShellItem_IPersistIDList_GetClassID(IPersistIDList* iface,
480 CLSID *pClassID)
481 {
482 ShellItem *This = impl_from_IPersistIDList(iface);
483
484 return ShellItem_GetClassID(This, pClassID);
485 }
486
487 static HRESULT WINAPI ShellItem_IPersistIDList_SetIDList(IPersistIDList* iface,
488 LPCITEMIDLIST pidl)
489 {
490 ShellItem *This = impl_from_IPersistIDList(iface);
491 LPITEMIDLIST new_pidl;
492
493 TRACE("(%p,%p)\n", This, pidl);
494
495 new_pidl = ILClone(pidl);
496
497 if (new_pidl)
498 {
499 ILFree(This->pidl);
500 This->pidl = new_pidl;
501 return S_OK;
502 }
503 else
504 return E_OUTOFMEMORY;
505 }
506
507 static HRESULT WINAPI ShellItem_IPersistIDList_GetIDList(IPersistIDList* iface,
508 LPITEMIDLIST *ppidl)
509 {
510 ShellItem *This = impl_from_IPersistIDList(iface);
511
512 TRACE("(%p,%p)\n", This, ppidl);
513
514 *ppidl = ILClone(This->pidl);
515 if (*ppidl)
516 return S_OK;
517 else
518 return E_OUTOFMEMORY;
519 }
520
521 static const IPersistIDListVtbl ShellItem_IPersistIDList_Vtbl = {
522 ShellItem_IPersistIDList_QueryInterface,
523 ShellItem_IPersistIDList_AddRef,
524 ShellItem_IPersistIDList_Release,
525 ShellItem_IPersistIDList_GetClassID,
526 ShellItem_IPersistIDList_SetIDList,
527 ShellItem_IPersistIDList_GetIDList
528 };
529
530
531 HRESULT WINAPI IShellItem_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
532 {
533 ShellItem *This;
534 HRESULT ret;
535
536 TRACE("(%p,%s)\n",pUnkOuter, debugstr_guid(riid));
537
538 *ppv = NULL;
539
540 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
541
542 This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem));
543 This->IShellItem2_iface.lpVtbl = &ShellItem2_Vtbl;
544 This->ref = 1;
545 This->pidl = NULL;
546 This->IPersistIDList_iface.lpVtbl = &ShellItem_IPersistIDList_Vtbl;
547
548 ret = ShellItem_QueryInterface(&This->IShellItem2_iface, riid, ppv);
549 ShellItem_Release(&This->IShellItem2_iface);
550
551 return ret;
552 }
553
554 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
555 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
556 {
557 ShellItem *This;
558 LPITEMIDLIST new_pidl;
559 HRESULT ret;
560
561 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
562
563 if (!pidl)
564 {
565 return E_INVALIDARG;
566 }
567 else if (pidlParent || psfParent)
568 {
569 LPITEMIDLIST temp_parent=NULL;
570 if (!pidlParent)
571 {
572 IPersistFolder2* ppf2Parent;
573
574 if (FAILED(IPersistFolder2_QueryInterface(psfParent, &IID_IPersistFolder2, (void**)&ppf2Parent)))
575 {
576 FIXME("couldn't get IPersistFolder2 interface of parent\n");
577 return E_NOINTERFACE;
578 }
579
580 if (FAILED(IPersistFolder2_GetCurFolder(ppf2Parent, &temp_parent)))
581 {
582 FIXME("couldn't get parent PIDL\n");
583 IPersistFolder2_Release(ppf2Parent);
584 return E_NOINTERFACE;
585 }
586
587 pidlParent = temp_parent;
588 IPersistFolder2_Release(ppf2Parent);
589 }
590
591 new_pidl = ILCombine(pidlParent, pidl);
592 ILFree(temp_parent);
593
594 if (!new_pidl)
595 return E_OUTOFMEMORY;
596 }
597 else
598 {
599 new_pidl = ILClone(pidl);
600 if (!new_pidl)
601 return E_OUTOFMEMORY;
602 }
603
604 ret = IShellItem_Constructor(NULL, &IID_IShellItem, (void**)&This);
605 if (This)
606 {
607 *ppsi = (IShellItem*)&This->IShellItem2_iface;
608 This->pidl = new_pidl;
609 }
610 else
611 {
612 *ppsi = NULL;
613 ILFree(new_pidl);
614 }
615 return ret;
616 }
617
618 HRESULT WINAPI SHCreateItemFromParsingName(PCWSTR pszPath,
619 IBindCtx *pbc, REFIID riid, void **ppv)
620 {
621 LPITEMIDLIST pidl;
622 HRESULT ret;
623
624 *ppv = NULL;
625
626 ret = SHParseDisplayName(pszPath, pbc, &pidl, 0, NULL);
627 if(SUCCEEDED(ret))
628 {
629 ShellItem *This;
630 ret = IShellItem_Constructor(NULL, riid, (void**)&This);
631
632 if(SUCCEEDED(ret))
633 {
634 This->pidl = pidl;
635 *ppv = (void*)This;
636 }
637 else
638 {
639 ILFree(pidl);
640 }
641 }
642 return ret;
643 }
644
645 HRESULT WINAPI SHCreateItemFromIDList(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv)
646 {
647 ShellItem *psiimpl;
648 HRESULT ret;
649
650 if(!pidl)
651 return E_INVALIDARG;
652
653 ret = IShellItem_Constructor(NULL, riid, ppv);
654 if(SUCCEEDED(ret))
655 {
656 psiimpl = (ShellItem*)*ppv;
657 psiimpl->pidl = ILClone(pidl);
658 }
659
660 return ret;
661 }
662
663 HRESULT WINAPI SHGetItemFromDataObject(IDataObject *pdtobj,
664 DATAOBJ_GET_ITEM_FLAGS dwFlags, REFIID riid, void **ppv)
665 {
666 FORMATETC fmt;
667 STGMEDIUM medium;
668 HRESULT ret;
669
670 TRACE("%p, %x, %s, %p\n", pdtobj, dwFlags, debugstr_guid(riid), ppv);
671
672 if(!pdtobj)
673 return E_INVALIDARG;
674
675 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
676 fmt.ptd = NULL;
677 fmt.dwAspect = DVASPECT_CONTENT;
678 fmt.lindex = -1;
679 fmt.tymed = TYMED_HGLOBAL;
680
681 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
682 if(SUCCEEDED(ret))
683 {
684 LPIDA pida = GlobalLock(medium.u.hGlobal);
685
686 if((pida->cidl > 1 && !(dwFlags & DOGIF_ONLY_IF_ONE)) ||
687 pida->cidl == 1)
688 {
689 LPITEMIDLIST pidl;
690
691 /* Get the first pidl (parent + child1) */
692 pidl = ILCombine((LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]),
693 (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]));
694
695 ret = SHCreateItemFromIDList(pidl, riid, ppv);
696 ILFree(pidl);
697 }
698 else
699 {
700 ret = E_FAIL;
701 }
702
703 GlobalUnlock(medium.u.hGlobal);
704 GlobalFree(medium.u.hGlobal);
705 }
706
707 if(FAILED(ret) && !(dwFlags & DOGIF_NO_HDROP))
708 {
709 TRACE("Attempting to fall back on CF_HDROP.\n");
710
711 fmt.cfFormat = CF_HDROP;
712 fmt.ptd = NULL;
713 fmt.dwAspect = DVASPECT_CONTENT;
714 fmt.lindex = -1;
715 fmt.tymed = TYMED_HGLOBAL;
716
717 ret = IDataObject_GetData(pdtobj, &fmt, &medium);
718 if(SUCCEEDED(ret))
719 {
720 DROPFILES *df = GlobalLock(medium.u.hGlobal);
721 LPBYTE files = (LPBYTE)df + df->pFiles;
722 BOOL multiple_files = FALSE;
723
724 ret = E_FAIL;
725 if(!df->fWide)
726 {
727 WCHAR filename[MAX_PATH];
728 PCSTR first_file = (PCSTR)files;
729 if(*(files + lstrlenA(first_file) + 1) != 0)
730 multiple_files = TRUE;
731
732 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
733 {
734 MultiByteToWideChar(CP_ACP, 0, first_file, -1, filename, MAX_PATH);
735 ret = SHCreateItemFromParsingName(filename, NULL, riid, ppv);
736 }
737 }
738 else
739 {
740 PCWSTR first_file = (PCWSTR)files;
741 if(*((PCWSTR)files + lstrlenW(first_file) + 1) != 0)
742 multiple_files = TRUE;
743
744 if( !(multiple_files && (dwFlags & DOGIF_ONLY_IF_ONE)) )
745 ret = SHCreateItemFromParsingName(first_file, NULL, riid, ppv);
746 }
747
748 GlobalUnlock(medium.u.hGlobal);
749 GlobalFree(medium.u.hGlobal);
750 }
751 }
752
753 if(FAILED(ret) && !(dwFlags & DOGIF_NO_URL))
754 {
755 FIXME("Failed to create item, should try CF_URL.\n");
756 }
757
758 return ret;
759 }
760
761 HRESULT WINAPI SHGetItemFromObject(IUnknown *punk, REFIID riid, void **ppv)
762 {
763 LPITEMIDLIST pidl;
764 HRESULT ret;
765
766 ret = SHGetIDListFromObject(punk, &pidl);
767 if(SUCCEEDED(ret))
768 {
769 ret = SHCreateItemFromIDList(pidl, riid, ppv);
770 ILFree(pidl);
771 }
772
773 return ret;
774 }
775
776 /*************************************************************************
777 * IShellItemArray implementation
778 */
779 typedef struct {
780 IShellItemArray IShellItemArray_iface;
781 LONG ref;
782
783 IShellItem **array;
784 DWORD item_count;
785 } IShellItemArrayImpl;
786
787 static inline IShellItemArrayImpl *impl_from_IShellItemArray(IShellItemArray *iface)
788 {
789 return CONTAINING_RECORD(iface, IShellItemArrayImpl, IShellItemArray_iface);
790 }
791
792 static HRESULT WINAPI IShellItemArray_fnQueryInterface(IShellItemArray *iface,
793 REFIID riid,
794 void **ppvObject)
795 {
796 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
797 TRACE("%p (%s, %p)\n", This, shdebugstr_guid(riid), ppvObject);
798
799 *ppvObject = NULL;
800 if(IsEqualIID(riid, &IID_IShellItemArray) ||
801 IsEqualIID(riid, &IID_IUnknown))
802 {
803 *ppvObject = This;
804 }
805
806 if(*ppvObject)
807 {
808 IUnknown_AddRef((IUnknown*)*ppvObject);
809 return S_OK;
810 }
811
812 return E_NOINTERFACE;
813 }
814
815 static ULONG WINAPI IShellItemArray_fnAddRef(IShellItemArray *iface)
816 {
817 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
818 LONG ref = InterlockedIncrement(&This->ref);
819 TRACE("%p - ref %d\n", This, ref);
820
821 return ref;
822 }
823
824 static ULONG WINAPI IShellItemArray_fnRelease(IShellItemArray *iface)
825 {
826 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
827 LONG ref = InterlockedDecrement(&This->ref);
828 TRACE("%p - ref %d\n", This, ref);
829
830 if(!ref)
831 {
832 UINT i;
833 TRACE("Freeing.\n");
834
835 for(i = 0; i < This->item_count; i++)
836 IShellItem_Release(This->array[i]);
837
838 HeapFree(GetProcessHeap(), 0, This->array);
839 HeapFree(GetProcessHeap(), 0, This);
840 return 0;
841 }
842
843 return ref;
844 }
845
846 static HRESULT WINAPI IShellItemArray_fnBindToHandler(IShellItemArray *iface,
847 IBindCtx *pbc,
848 REFGUID bhid,
849 REFIID riid,
850 void **ppvOut)
851 {
852 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
853 FIXME("Stub: %p (%p, %s, %s, %p)\n",
854 This, pbc, shdebugstr_guid(bhid), shdebugstr_guid(riid), ppvOut);
855
856 return E_NOTIMPL;
857 }
858
859 static HRESULT WINAPI IShellItemArray_fnGetPropertyStore(IShellItemArray *iface,
860 GETPROPERTYSTOREFLAGS flags,
861 REFIID riid,
862 void **ppv)
863 {
864 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
865 FIXME("Stub: %p (%x, %s, %p)\n", This, flags, shdebugstr_guid(riid), ppv);
866
867 return E_NOTIMPL;
868 }
869
870 static HRESULT WINAPI IShellItemArray_fnGetPropertyDescriptionList(IShellItemArray *iface,
871 REFPROPERTYKEY keyType,
872 REFIID riid,
873 void **ppv)
874 {
875 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
876 FIXME("Stub: %p (%p, %s, %p)\n",
877 This, keyType, shdebugstr_guid(riid), ppv);
878
879 return E_NOTIMPL;
880 }
881
882 static HRESULT WINAPI IShellItemArray_fnGetAttributes(IShellItemArray *iface,
883 SIATTRIBFLAGS AttribFlags,
884 SFGAOF sfgaoMask,
885 SFGAOF *psfgaoAttribs)
886 {
887 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
888 FIXME("Stub: %p (%x, %x, %p)\n", This, AttribFlags, sfgaoMask, psfgaoAttribs);
889
890 return E_NOTIMPL;
891 }
892
893 static HRESULT WINAPI IShellItemArray_fnGetCount(IShellItemArray *iface,
894 DWORD *pdwNumItems)
895 {
896 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
897 TRACE("%p (%p)\n", This, pdwNumItems);
898
899 *pdwNumItems = This->item_count;
900
901 return S_OK;
902 }
903
904 static HRESULT WINAPI IShellItemArray_fnGetItemAt(IShellItemArray *iface,
905 DWORD dwIndex,
906 IShellItem **ppsi)
907 {
908 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
909 TRACE("%p (%x, %p)\n", This, dwIndex, ppsi);
910
911 /* zero indexed */
912 if(dwIndex + 1 > This->item_count)
913 return E_FAIL;
914
915 *ppsi = This->array[dwIndex];
916 IShellItem_AddRef(*ppsi);
917
918 return S_OK;
919 }
920
921 static HRESULT WINAPI IShellItemArray_fnEnumItems(IShellItemArray *iface,
922 IEnumShellItems **ppenumShellItems)
923 {
924 IShellItemArrayImpl *This = impl_from_IShellItemArray(iface);
925 FIXME("Stub: %p (%p)\n", This, ppenumShellItems);
926
927 return E_NOTIMPL;
928 }
929
930 static const IShellItemArrayVtbl vt_IShellItemArray = {
931 IShellItemArray_fnQueryInterface,
932 IShellItemArray_fnAddRef,
933 IShellItemArray_fnRelease,
934 IShellItemArray_fnBindToHandler,
935 IShellItemArray_fnGetPropertyStore,
936 IShellItemArray_fnGetPropertyDescriptionList,
937 IShellItemArray_fnGetAttributes,
938 IShellItemArray_fnGetCount,
939 IShellItemArray_fnGetItemAt,
940 IShellItemArray_fnEnumItems
941 };
942
943 static HRESULT IShellItemArray_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
944 {
945 IShellItemArrayImpl *This;
946 HRESULT ret;
947
948 TRACE("(%p, %s, %p)\n",pUnkOuter, debugstr_guid(riid), ppv);
949
950 if(pUnkOuter)
951 return CLASS_E_NOAGGREGATION;
952
953 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItemArrayImpl));
954 if(!This)
955 return E_OUTOFMEMORY;
956
957 This->ref = 1;
958 This->IShellItemArray_iface.lpVtbl = &vt_IShellItemArray;
959 This->array = NULL;
960 This->item_count = 0;
961
962 ret = IShellItemArray_QueryInterface(&This->IShellItemArray_iface, riid, ppv);
963 IShellItemArray_Release(&This->IShellItemArray_iface);
964
965 return ret;
966 }
967
968 HRESULT WINAPI SHCreateShellItemArray(PCIDLIST_ABSOLUTE pidlParent,
969 IShellFolder *psf,
970 UINT cidl,
971 PCUITEMID_CHILD_ARRAY ppidl,
972 IShellItemArray **ppsiItemArray)
973 {
974 IShellItemArrayImpl *This;
975 IShellItem **array;
976 HRESULT ret = E_FAIL;
977 UINT i;
978
979 TRACE("%p, %p, %d, %p, %p\n", pidlParent, psf, cidl, ppidl, ppsiItemArray);
980
981 if(!pidlParent && !psf)
982 return E_POINTER;
983
984 if(!ppidl)
985 return E_INVALIDARG;
986
987 array = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cidl*sizeof(IShellItem*));
988 if(!array)
989 return E_OUTOFMEMORY;
990
991 for(i = 0; i < cidl; i++)
992 {
993 ret = SHCreateShellItem(pidlParent, psf, ppidl[i], &array[i]);
994 if(FAILED(ret)) break;
995 }
996
997 if(SUCCEEDED(ret))
998 {
999 ret = IShellItemArray_Constructor(NULL, &IID_IShellItemArray, (void**)&This);
1000 if(SUCCEEDED(ret))
1001 {
1002 This->array = array;
1003 This->item_count = cidl;
1004 *ppsiItemArray = &This->IShellItemArray_iface;
1005
1006 return ret;
1007 }
1008 }
1009
1010 /* Something failed, clean up. */
1011 for(i = 0; i < cidl; i++)
1012 if(array[i]) IShellItem_Release(array[i]);
1013 HeapFree(GetProcessHeap(), 0, array);
1014 *ppsiItemArray = NULL;
1015 return ret;
1016 }
1017
1018 HRESULT WINAPI SHCreateShellItemArrayFromShellItem(IShellItem *psi, REFIID riid, void **ppv)
1019 {
1020 IShellItemArrayImpl *This;
1021 IShellItem **array;
1022 HRESULT ret;
1023
1024 TRACE("%p, %s, %p\n", psi, shdebugstr_guid(riid), ppv);
1025
1026 array = HeapAlloc(GetProcessHeap(), 0, sizeof(IShellItem*));
1027 if(!array)
1028 return E_OUTOFMEMORY;
1029
1030 ret = IShellItemArray_Constructor(NULL, riid, (void**)&This);
1031 if(SUCCEEDED(ret))
1032 {
1033 array[0] = psi;
1034 IShellItem_AddRef(psi);
1035 This->array = array;
1036 This->item_count = 1;
1037 *ppv = This;
1038 }
1039 else
1040 {
1041 HeapFree(GetProcessHeap(), 0, array);
1042 *ppv = NULL;
1043 }
1044
1045 return ret;
1046 }
1047
1048 HRESULT WINAPI SHCreateShellItemArrayFromDataObject(IDataObject *pdo, REFIID riid, void **ppv)
1049 {
1050 IShellItemArray *psia;
1051 FORMATETC fmt;
1052 STGMEDIUM medium;
1053 HRESULT ret;
1054
1055 TRACE("%p, %s, %p\n", pdo, shdebugstr_guid(riid), ppv);
1056
1057 if(!pdo)
1058 return E_INVALIDARG;
1059
1060 *ppv = NULL;
1061
1062 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
1063 fmt.ptd = NULL;
1064 fmt.dwAspect = DVASPECT_CONTENT;
1065 fmt.lindex = -1;
1066 fmt.tymed = TYMED_HGLOBAL;
1067
1068 ret = IDataObject_GetData(pdo, &fmt, &medium);
1069 if(SUCCEEDED(ret))
1070 {
1071 LPIDA pida = GlobalLock(medium.u.hGlobal);
1072 LPCITEMIDLIST parent_pidl;
1073 LPCITEMIDLIST *children;
1074 UINT i;
1075 TRACE("Converting %d objects.\n", pida->cidl);
1076
1077 parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
1078
1079 children = HeapAlloc(GetProcessHeap(), 0, sizeof(LPCITEMIDLIST)*pida->cidl);
1080 for(i = 0; i < pida->cidl; i++)
1081 children[i] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i+1]);
1082
1083 ret = SHCreateShellItemArray(parent_pidl, NULL, pida->cidl, children, &psia);
1084
1085 HeapFree(GetProcessHeap(), 0, children);
1086
1087 GlobalUnlock(medium.u.hGlobal);
1088 GlobalFree(medium.u.hGlobal);
1089 }
1090
1091 if(SUCCEEDED(ret))
1092 {
1093 ret = IShellItemArray_QueryInterface(psia, riid, ppv);
1094 IShellItemArray_Release(psia);
1095 }
1096
1097 return ret;
1098 }
1099
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.