xref: /reactos/dll/win32/shell32/CShellItem.cpp (revision f986527d)
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 }
338