This really needs to go in a branch. It needs heavy testing and can't coincide with...
[reactos.git] / dll / win32 / shell32 / shellitem.c
1 /*
2 * IShellItem implementation
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 "precomp.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(shell);
24
25 typedef struct _ShellItem {
26 const IShellItemVtbl *lpIShellItemVtbl;
27 LONG ref;
28 LPITEMIDLIST pidl;
29 const IPersistIDListVtbl *lpIPersistIDListVtbl;
30 } ShellItem;
31
32 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
33 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi);
34
35
36 static inline ShellItem *impl_from_IPersistIDList( IPersistIDList *iface )
37 {
38 return (ShellItem*)((char*)iface - FIELD_OFFSET(ShellItem, lpIPersistIDListVtbl));
39 }
40
41
42 static HRESULT WINAPI ShellItem_QueryInterface(IShellItem *iface, REFIID riid,
43 void **ppv)
44 {
45 ShellItem *This = (ShellItem*)iface;
46
47 TRACE("(%p,%p,%p)\n", iface, riid, ppv);
48
49 if (!ppv) return E_INVALIDARG;
50
51 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IShellItem, riid))
52 {
53 *ppv = This;
54 }
55 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistIDList, riid))
56 {
57 *ppv = (IPersistIDListVtbl *)&(This->lpIPersistIDListVtbl);
58 }
59 else {
60 FIXME("not implemented for %s\n", shdebugstr_guid(riid));
61 *ppv = NULL;
62 return E_NOINTERFACE;
63 }
64
65 IUnknown_AddRef((IUnknown*)*ppv);
66 return S_OK;
67 }
68
69 static ULONG WINAPI ShellItem_AddRef(IShellItem *iface)
70 {
71 ShellItem *This = (ShellItem*)iface;
72 ULONG ref = InterlockedIncrement(&This->ref);
73
74 TRACE("(%p), new refcount=%i\n", iface, ref);
75
76 return ref;
77 }
78
79 static ULONG WINAPI ShellItem_Release(IShellItem *iface)
80 {
81 ShellItem *This = (ShellItem*)iface;
82 ULONG ref = InterlockedDecrement(&This->ref);
83
84 TRACE("(%p), new refcount=%i\n", iface, ref);
85
86 if (ref == 0)
87 {
88 ILFree(This->pidl);
89 HeapFree(GetProcessHeap(), 0, This);
90 }
91
92 return ref;
93 }
94
95 static HRESULT ShellItem_get_parent_pidl(ShellItem *This, LPITEMIDLIST *parent_pidl)
96 {
97 *parent_pidl = ILClone(This->pidl);
98 if (*parent_pidl)
99 {
100 if (ILRemoveLastID(*parent_pidl))
101 return S_OK;
102 else
103 {
104 ILFree(*parent_pidl);
105 *parent_pidl = NULL;
106 return E_INVALIDARG;
107 }
108 }
109 else
110 {
111 *parent_pidl = NULL;
112 return E_OUTOFMEMORY;
113 }
114 }
115
116 static HRESULT ShellItem_get_parent_shellfolder(ShellItem *This, IShellFolder **ppsf)
117 {
118 LPITEMIDLIST parent_pidl;
119 IShellFolder *desktop;
120 HRESULT ret;
121
122 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
123 if (SUCCEEDED(ret))
124 {
125 ret = SHGetDesktopFolder(&desktop);
126 if (SUCCEEDED(ret))
127 {
128 ret = IShellFolder_BindToObject(desktop, parent_pidl, NULL, &IID_IShellFolder, (void**)ppsf);
129 IShellFolder_Release(desktop);
130 }
131 ILFree(parent_pidl);
132 }
133
134 return ret;
135 }
136
137 static HRESULT WINAPI ShellItem_BindToHandler(IShellItem *iface, IBindCtx *pbc,
138 REFGUID rbhid, REFIID riid, void **ppvOut)
139 {
140 FIXME("(%p,%p,%s,%p,%p)\n", iface, pbc, shdebugstr_guid(rbhid), riid, ppvOut);
141
142 *ppvOut = NULL;
143
144 return E_NOTIMPL;
145 }
146
147 static HRESULT WINAPI ShellItem_GetParent(IShellItem *iface, IShellItem **ppsi)
148 {
149 ShellItem *This = (ShellItem*)iface;
150 LPITEMIDLIST parent_pidl;
151 HRESULT ret;
152
153 TRACE("(%p,%p)\n", iface, ppsi);
154
155 ret = ShellItem_get_parent_pidl(This, &parent_pidl);
156 if (SUCCEEDED(ret))
157 {
158 ret = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi);
159 ILFree(parent_pidl);
160 }
161
162 return ret;
163 }
164
165 static HRESULT WINAPI ShellItem_GetDisplayName(IShellItem *iface, SIGDN sigdnName,
166 LPWSTR *ppszName)
167 {
168 FIXME("(%p,%x,%p)\n", iface, sigdnName, ppszName);
169
170 *ppszName = NULL;
171
172 return E_NOTIMPL;
173 }
174
175 static HRESULT WINAPI ShellItem_GetAttributes(IShellItem *iface, SFGAOF sfgaoMask,
176 SFGAOF *psfgaoAttribs)
177 {
178 ShellItem *This = (ShellItem*)iface;
179 IShellFolder *parent_folder;
180 LPITEMIDLIST child_pidl;
181 HRESULT ret;
182
183 TRACE("(%p,%x,%p)\n", iface, sfgaoMask, psfgaoAttribs);
184
185 ret = ShellItem_get_parent_shellfolder(This, &parent_folder);
186 if (SUCCEEDED(ret))
187 {
188 child_pidl = ILFindLastID(This->pidl);
189 *psfgaoAttribs = sfgaoMask;
190 ret = IShellFolder_GetAttributesOf(parent_folder, 1, (LPCITEMIDLIST*)&child_pidl, psfgaoAttribs);
191 IShellFolder_Release(parent_folder);
192 }
193
194 return ret;
195 }
196
197 static HRESULT WINAPI ShellItem_Compare(IShellItem *iface, IShellItem *oth,
198 SICHINTF hint, int *piOrder)
199 {
200 FIXME("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder);
201
202 return E_NOTIMPL;
203 }
204
205 static const IShellItemVtbl ShellItem_Vtbl = {
206 ShellItem_QueryInterface,
207 ShellItem_AddRef,
208 ShellItem_Release,
209 ShellItem_BindToHandler,
210 ShellItem_GetParent,
211 ShellItem_GetDisplayName,
212 ShellItem_GetAttributes,
213 ShellItem_Compare
214 };
215
216
217 static HRESULT ShellItem_GetClassID(ShellItem* This, CLSID *pClassID)
218 {
219 TRACE("(%p,%p)\n", This, pClassID);
220
221 *pClassID = CLSID_ShellItem;
222 return S_OK;
223 }
224
225
226 static HRESULT WINAPI ShellItem_IPersistIDList_QueryInterface(IPersistIDList *iface,
227 REFIID riid, void **ppv)
228 {
229 ShellItem *This = impl_from_IPersistIDList(iface);
230 return ShellItem_QueryInterface((IShellItem*)This, riid, ppv);
231 }
232
233 static ULONG WINAPI ShellItem_IPersistIDList_AddRef(IPersistIDList *iface)
234 {
235 ShellItem *This = impl_from_IPersistIDList(iface);
236 return ShellItem_AddRef((IShellItem*)This);
237 }
238
239 static ULONG WINAPI ShellItem_IPersistIDList_Release(IPersistIDList *iface)
240 {
241 ShellItem *This = impl_from_IPersistIDList(iface);
242 return ShellItem_Release((IShellItem*)This);
243 }
244
245 static HRESULT WINAPI ShellItem_IPersistIDList_GetClassID(IPersistIDList* iface,
246 CLSID *pClassID)
247 {
248 ShellItem *This = impl_from_IPersistIDList(iface);
249
250 return ShellItem_GetClassID(This, pClassID);
251 }
252
253 static HRESULT WINAPI ShellItem_IPersistIDList_SetIDList(IPersistIDList* iface,
254 LPCITEMIDLIST pidl)
255 {
256 ShellItem *This = impl_from_IPersistIDList(iface);
257 LPITEMIDLIST new_pidl;
258
259 TRACE("(%p,%p)\n", This, pidl);
260
261 new_pidl = ILClone(pidl);
262
263 if (new_pidl)
264 {
265 ILFree(This->pidl);
266 This->pidl = new_pidl;
267 return S_OK;
268 }
269 else
270 return E_OUTOFMEMORY;
271 }
272
273 static HRESULT WINAPI ShellItem_IPersistIDList_GetIDList(IPersistIDList* iface,
274 LPITEMIDLIST *ppidl)
275 {
276 ShellItem *This = impl_from_IPersistIDList(iface);
277
278 TRACE("(%p,%p)\n", This, ppidl);
279
280 *ppidl = ILClone(This->pidl);
281 if (*ppidl)
282 return S_OK;
283 else
284 return E_OUTOFMEMORY;
285 }
286
287 static const IPersistIDListVtbl ShellItem_IPersistIDList_Vtbl = {
288 ShellItem_IPersistIDList_QueryInterface,
289 ShellItem_IPersistIDList_AddRef,
290 ShellItem_IPersistIDList_Release,
291 ShellItem_IPersistIDList_GetClassID,
292 ShellItem_IPersistIDList_SetIDList,
293 ShellItem_IPersistIDList_GetIDList
294 };
295
296
297 HRESULT WINAPI IShellItem_Constructor(IUnknown *pUnkOuter, REFIID riid, void **ppv)
298 {
299 ShellItem *This;
300 HRESULT ret;
301
302 TRACE("(%p,%s)\n",pUnkOuter, debugstr_guid(riid));
303
304 *ppv = NULL;
305
306 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
307
308 This = HeapAlloc(GetProcessHeap(), 0, sizeof(ShellItem));
309 This->lpIShellItemVtbl = &ShellItem_Vtbl;
310 This->ref = 1;
311 This->pidl = NULL;
312 This->lpIPersistIDListVtbl = &ShellItem_IPersistIDList_Vtbl;
313
314 ret = ShellItem_QueryInterface((IShellItem*)This, riid, ppv);
315 ShellItem_Release((IShellItem*)This);
316
317 return ret;
318 }
319
320 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
321 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
322 {
323 ShellItem *This;
324 LPITEMIDLIST new_pidl;
325 HRESULT ret;
326
327 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
328
329 if (!pidl)
330 {
331 return E_INVALIDARG;
332 }
333 else if (pidlParent || psfParent)
334 {
335 LPITEMIDLIST temp_parent=NULL;
336 if (!pidlParent)
337 {
338 IPersistFolder2* ppf2Parent;
339
340 if (FAILED(IPersistFolder2_QueryInterface(psfParent, &IID_IPersistFolder2, (void**)&ppf2Parent)))
341 {
342 FIXME("couldn't get IPersistFolder2 interface of parent\n");
343 return E_NOINTERFACE;
344 }
345
346 if (FAILED(IPersistFolder2_GetCurFolder(ppf2Parent, &temp_parent)))
347 {
348 FIXME("couldn't get parent PIDL\n");
349 IPersistFolder2_Release(ppf2Parent);
350 return E_NOINTERFACE;
351 }
352
353 pidlParent = temp_parent;
354 IPersistFolder2_Release(ppf2Parent);
355 }
356
357 new_pidl = ILCombine(pidlParent, pidl);
358 ILFree(temp_parent);
359
360 if (!new_pidl)
361 return E_OUTOFMEMORY;
362 }
363 else
364 {
365 new_pidl = ILClone(pidl);
366 if (!new_pidl)
367 return E_OUTOFMEMORY;
368 }
369
370 ret = IShellItem_Constructor(NULL, &IID_IShellItem, (void**)&This);
371 if (This)
372 {
373 *ppsi = (IShellItem*)This;
374 This->pidl = new_pidl;
375 }
376 else
377 {
378 *ppsi = NULL;
379 ILFree(new_pidl);
380 }
381 return ret;
382 }