[SHELL] IPersistIDList/IShellLink use P(C)IDLIST_ABSOLUTE. CORE-16385
[reactos.git] / dll / win32 / shell32 / CShellItem.cpp
1 /*
2 * IShellItem implementation
3 *
4 * Copyright 2008 Vincent Povirk for CodeWeavers
5 * Copyright 2009 Andrew Hill
6 * Copyright 2013 Katayama Hirofumi MZ
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include "precomp.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(shell);
26
27 EXTERN_C HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
28 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi);
29
30 CShellItem::CShellItem() :
31 m_pidl(NULL)
32 {
33 }
34
35 CShellItem::~CShellItem()
36 {
37 ILFree(m_pidl);
38 }
39
40 HRESULT CShellItem::get_parent_pidl(LPITEMIDLIST *parent_pidl)
41 {
42 *parent_pidl = ILClone(m_pidl);
43 if (*parent_pidl)
44 {
45 if (ILRemoveLastID(*parent_pidl))
46 return S_OK;
47 else
48 {
49 ILFree(*parent_pidl);
50 *parent_pidl = NULL;
51 return E_INVALIDARG;
52 }
53 }
54 else
55 {
56 *parent_pidl = NULL;
57 return E_OUTOFMEMORY;
58 }
59 }
60
61 HRESULT CShellItem::get_parent_shellfolder(IShellFolder **ppsf)
62 {
63 HRESULT hr;
64 LPITEMIDLIST parent_pidl;
65 CComPtr<IShellFolder> desktop;
66
67 hr = get_parent_pidl(&parent_pidl);
68 if (SUCCEEDED(hr))
69 {
70 hr = SHGetDesktopFolder(&desktop);
71 if (SUCCEEDED(hr))
72 hr = desktop->BindToObject(parent_pidl, NULL, IID_PPV_ARG(IShellFolder, ppsf));
73 ILFree(parent_pidl);
74 }
75
76 return hr;
77 }
78
79 HRESULT CShellItem::get_shellfolder(IBindCtx *pbc, REFIID riid, void **ppvOut)
80 {
81 CComPtr<IShellFolder> psf;
82 CComPtr<IShellFolder> psfDesktop;
83 HRESULT ret;
84
85 ret = SHGetDesktopFolder(&psfDesktop);
86 if (FAILED_UNEXPECTEDLY(ret))
87 return ret;
88
89 if (_ILIsDesktop(m_pidl))
90 psf = psfDesktop;
91 else
92 {
93 ret = psfDesktop->BindToObject(m_pidl, pbc, IID_PPV_ARG(IShellFolder, &psf));
94 if (FAILED_UNEXPECTEDLY(ret))
95 return ret;
96 }
97
98 return psf->QueryInterface(riid, ppvOut);
99 }
100
101 HRESULT WINAPI CShellItem::BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut)
102 {
103 HRESULT ret;
104 TRACE("(%p, %p,%s,%p,%p)\n", this, pbc, shdebugstr_guid(&rbhid), riid, ppvOut);
105
106 *ppvOut = NULL;
107 if (IsEqualGUID(rbhid, BHID_SFObject))
108 {
109 return get_shellfolder(pbc, riid, ppvOut);
110 }
111 else if (IsEqualGUID(rbhid, BHID_SFUIObject))
112 {
113 CComPtr<IShellFolder> psf_parent;
114 if (_ILIsDesktop(m_pidl))
115 ret = SHGetDesktopFolder(&psf_parent);
116 else
117 ret = get_parent_shellfolder(&psf_parent);
118 if (FAILED_UNEXPECTEDLY(ret))
119 return ret;
120
121 LPCITEMIDLIST pidl = ILFindLastID(m_pidl);
122 return psf_parent->GetUIObjectOf(NULL, 1, &pidl, riid, NULL, ppvOut);
123 }
124 else if (IsEqualGUID(rbhid, BHID_DataObject))
125 {
126 return BindToHandler(pbc, BHID_SFUIObject, IID_IDataObject, ppvOut);
127 }
128 else if (IsEqualGUID(rbhid, BHID_SFViewObject))
129 {
130 CComPtr<IShellFolder> psf;
131 ret = get_shellfolder(NULL, IID_PPV_ARG(IShellFolder, &psf));
132 if (FAILED_UNEXPECTEDLY(ret))
133 return ret;
134
135 return psf->CreateViewObject(NULL, riid, ppvOut);
136 }
137
138 FIXME("Unsupported BHID %s.\n", debugstr_guid(&rbhid));
139
140 return MK_E_NOOBJECT;
141 }
142
143 HRESULT WINAPI CShellItem::GetParent(IShellItem **ppsi)
144 {
145 HRESULT hr;
146 LPITEMIDLIST parent_pidl;
147
148 TRACE("(%p,%p)\n", this, ppsi);
149
150 hr = get_parent_pidl(&parent_pidl);
151 if (SUCCEEDED(hr))
152 {
153 hr = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi);
154 ILFree(parent_pidl);
155 }
156
157 return hr;
158 }
159
160 HRESULT WINAPI CShellItem::GetDisplayName(SIGDN sigdnName, LPWSTR *ppszName)
161 {
162 return SHGetNameFromIDList(m_pidl, sigdnName, ppszName);
163 }
164
165 HRESULT WINAPI CShellItem::GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs)
166 {
167 CComPtr<IShellFolder> parent_folder;
168 LPCITEMIDLIST child_pidl;
169 HRESULT hr;
170
171 TRACE("(%p,%x,%p)\n", this, sfgaoMask, psfgaoAttribs);
172
173 if (_ILIsDesktop(m_pidl))
174 hr = SHGetDesktopFolder(&parent_folder);
175 else
176 hr = get_parent_shellfolder(&parent_folder);
177 if (FAILED_UNEXPECTEDLY(hr))
178 return hr;
179
180 child_pidl = ILFindLastID(m_pidl);
181 *psfgaoAttribs = sfgaoMask;
182 hr = parent_folder->GetAttributesOf(1, &child_pidl, psfgaoAttribs);
183 *psfgaoAttribs &= sfgaoMask;
184
185 if (FAILED_UNEXPECTEDLY(hr))
186 return hr;
187
188 return (sfgaoMask == *psfgaoAttribs) ? S_OK : S_FALSE;
189 }
190
191 HRESULT WINAPI CShellItem::Compare(IShellItem *oth, SICHINTF hint, int *piOrder)
192 {
193 HRESULT hr;
194 CComPtr<IPersistIDList> pIDList;
195 CComPtr<IShellFolder> psfDesktop;
196 LPITEMIDLIST pidl;
197
198 TRACE("(%p,%p,%x,%p)\n", this, oth, hint, piOrder);
199
200 if (piOrder == NULL || oth == NULL)
201 return E_POINTER;
202
203 hr = oth->QueryInterface(IID_PPV_ARG(IPersistIDList, &pIDList));
204 if (SUCCEEDED(hr))
205 {
206 hr = pIDList->GetIDList(&pidl);
207 if (SUCCEEDED(hr))
208 {
209 hr = SHGetDesktopFolder(&psfDesktop);
210 if (SUCCEEDED(hr))
211 {
212 hr = psfDesktop->CompareIDs(hint, m_pidl, pidl);
213 *piOrder = (int)(short)SCODE_CODE(hr);
214 }
215 ILFree(pidl);
216 }
217 }
218
219 if(FAILED(hr))
220 return hr;
221
222 if(*piOrder)
223 return S_FALSE;
224 else
225 return S_OK;
226 }
227
228 HRESULT WINAPI CShellItem::GetClassID(CLSID *pClassID)
229 {
230 TRACE("(%p,%p)\n", this, pClassID);
231
232 *pClassID = CLSID_ShellItem;
233 return S_OK;
234 }
235
236 HRESULT WINAPI CShellItem::SetIDList(PCIDLIST_ABSOLUTE pidlx)
237 {
238 LPITEMIDLIST new_pidl;
239
240 TRACE("(%p,%p)\n", this, pidlx);
241
242 new_pidl = ILClone(pidlx);
243 if (new_pidl)
244 {
245 ILFree(m_pidl);
246 m_pidl = new_pidl;
247 return S_OK;
248 }
249 else
250 return E_OUTOFMEMORY;
251 }
252
253 HRESULT WINAPI CShellItem::GetIDList(PIDLIST_ABSOLUTE *ppidl)
254 {
255 TRACE("(%p,%p)\n", this, ppidl);
256
257 *ppidl = ILClone(m_pidl);
258 if (*ppidl)
259 return S_OK;
260 else
261 return E_OUTOFMEMORY;
262 }
263
264 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
265 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
266 {
267 HRESULT hr;
268 CComPtr<IShellItem> newShellItem;
269 LPITEMIDLIST new_pidl;
270 CComPtr<IPersistIDList> newPersistIDList;
271
272 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
273
274 *ppsi = NULL;
275
276 if (!pidl)
277 return E_INVALIDARG;
278
279 if (pidlParent || psfParent)
280 {
281 LPITEMIDLIST temp_parent = NULL;
282 if (!pidlParent)
283 {
284 CComPtr<IPersistFolder2> ppf2Parent;
285
286 if (FAILED(psfParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2Parent))))
287 {
288 FIXME("couldn't get IPersistFolder2 interface of parent\n");
289 return E_NOINTERFACE;
290 }
291
292 if (FAILED(ppf2Parent->GetCurFolder(&temp_parent)))
293 {
294 FIXME("couldn't get parent PIDL\n");
295 return E_NOINTERFACE;
296 }
297
298 pidlParent = temp_parent;
299 }
300
301 new_pidl = ILCombine(pidlParent, pidl);
302 ILFree(temp_parent);
303
304 if (!new_pidl)
305 return E_OUTOFMEMORY;
306 }
307 else
308 {
309 new_pidl = ILClone(pidl);
310 if (!new_pidl)
311 return E_OUTOFMEMORY;
312 }
313
314 hr = CShellItem::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellItem, &newShellItem));
315 if (FAILED(hr))
316 {
317 ILFree(new_pidl);
318 return hr;
319 }
320 hr = newShellItem->QueryInterface(IID_PPV_ARG(IPersistIDList, &newPersistIDList));
321 if (FAILED(hr))
322 {
323 ILFree(new_pidl);
324 return hr;
325 }
326 hr = newPersistIDList->SetIDList(new_pidl);
327 if (FAILED(hr))
328 {
329 ILFree(new_pidl);
330 return hr;
331 }
332 ILFree(new_pidl);
333
334 *ppsi = newShellItem.Detach();
335
336 return hr;
337 }