Sync with trunk r63647.
[reactos.git] / dll / win32 / shell32 / shellitem.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 WINAPI CShellItem::BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut)
80 {
81 FIXME("(%p,%p,%s,%p,%p)\n", this, pbc, shdebugstr_guid(&rbhid), riid, ppvOut);
82
83 *ppvOut = NULL;
84
85 return E_NOTIMPL;
86 }
87
88 HRESULT WINAPI CShellItem::GetParent(IShellItem **ppsi)
89 {
90 HRESULT hr;
91 LPITEMIDLIST parent_pidl;
92
93 TRACE("(%p,%p)\n", this, ppsi);
94
95 hr = get_parent_pidl(&parent_pidl);
96 if (SUCCEEDED(hr))
97 {
98 hr = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi);
99 ILFree(parent_pidl);
100 }
101
102 return hr;
103 }
104
105 HRESULT WINAPI CShellItem::GetDisplayName(SIGDN sigdnName, LPWSTR *ppszName)
106 {
107 HRESULT hr;
108 CComPtr<IShellFolder> parent_folder;
109 STRRET name;
110 DWORD uFlags;
111
112 TRACE("(%p,%x,%p)\n", this, sigdnName, ppszName);
113
114 if (sigdnName & SIGDN_URL)
115 return E_NOTIMPL;
116
117 if (ppszName == NULL)
118 return E_POINTER;
119
120 *ppszName = NULL;
121
122 hr = get_parent_shellfolder(&parent_folder);
123 if (SUCCEEDED(hr))
124 {
125 if (sigdnName == SIGDN_PARENTRELATIVEEDITING)
126 uFlags = SHGDN_FOREDITING | SHGDN_INFOLDER;
127 else if (sigdnName == SIGDN_DESKTOPABSOLUTEEDITING)
128 uFlags = SHGDN_FOREDITING;
129 else if (sigdnName == SIGDN_PARENTRELATIVEEDITING)
130 uFlags = SHGDN_FOREDITING | SHGDN_INFOLDER;
131 else if (sigdnName == SIGDN_DESKTOPABSOLUTEEDITING)
132 uFlags = SHGDN_FOREDITING;
133 else if (sigdnName == SIGDN_PARENTRELATIVEPARSING)
134 uFlags = SHGDN_FORPARSING | SHGDN_INFOLDER;
135 else if (sigdnName == SIGDN_DESKTOPABSOLUTEPARSING)
136 uFlags = SHGDN_FORPARSING;
137 else
138 uFlags = SHGDN_NORMAL;
139
140 hr = parent_folder->GetDisplayNameOf(m_pidl, uFlags, &name);
141 if (SUCCEEDED(hr))
142 {
143 StrRetToStrW(&name, m_pidl, ppszName);
144 return S_OK;
145 }
146 }
147
148 return hr;
149 }
150
151 HRESULT WINAPI CShellItem::GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs)
152 {
153 CComPtr<IShellFolder> parent_folder;
154 LPCITEMIDLIST child_pidl;
155 HRESULT hr;
156
157 TRACE("(%p,%x,%p)\n", this, sfgaoMask, psfgaoAttribs);
158
159 hr = get_parent_shellfolder(&parent_folder);
160 if (SUCCEEDED(hr))
161 {
162 child_pidl = ILFindLastID(m_pidl);
163 *psfgaoAttribs = sfgaoMask;
164 hr = parent_folder->GetAttributesOf(1, &child_pidl, psfgaoAttribs);
165 }
166
167 return hr;
168 }
169
170 HRESULT WINAPI CShellItem::Compare(IShellItem *oth, SICHINTF hint, int *piOrder)
171 {
172 HRESULT hr;
173 CComPtr<IPersistIDList> pIDList;
174 CComPtr<IShellFolder> parent_folder;
175 LPITEMIDLIST pidl;
176
177 TRACE("(%p,%p,%x,%p)\n", this, oth, hint, piOrder);
178
179 if (piOrder == NULL || oth == NULL)
180 return E_POINTER;
181
182 hr = oth->QueryInterface(IID_PPV_ARG(IPersistIDList, &pIDList));
183 if (SUCCEEDED(hr))
184 {
185 hr = pIDList->GetIDList(&pidl);
186 if (SUCCEEDED(hr))
187 {
188 hr = get_parent_shellfolder(&parent_folder);
189 if (SUCCEEDED(hr))
190 {
191 hr = parent_folder->CompareIDs(hint, m_pidl, pidl);
192 *piOrder = static_cast<int>(SCODE_CODE(hr));
193 }
194 ILFree(pidl);
195 }
196 }
197
198 if (SUCCEEDED(hr))
199 return S_OK;
200 return hr;
201 }
202
203 HRESULT WINAPI CShellItem::GetClassID(CLSID *pClassID)
204 {
205 TRACE("(%p,%p)\n", this, pClassID);
206
207 *pClassID = CLSID_ShellItem;
208 return S_OK;
209 }
210
211 HRESULT WINAPI CShellItem::SetIDList(LPCITEMIDLIST pidlx)
212 {
213 LPITEMIDLIST new_pidl;
214
215 TRACE("(%p,%p)\n", this, pidlx);
216
217 new_pidl = ILClone(pidlx);
218 if (new_pidl)
219 {
220 ILFree(m_pidl);
221 m_pidl = new_pidl;
222 return S_OK;
223 }
224 else
225 return E_OUTOFMEMORY;
226 }
227
228 HRESULT WINAPI CShellItem::GetIDList(LPITEMIDLIST *ppidl)
229 {
230 TRACE("(%p,%p)\n", this, ppidl);
231
232 *ppidl = ILClone(m_pidl);
233 if (*ppidl)
234 return S_OK;
235 else
236 return E_OUTOFMEMORY;
237 }
238
239 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
240 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
241 {
242 HRESULT hr;
243 IShellItem *newShellItem;
244 LPITEMIDLIST new_pidl;
245 CComPtr<IPersistIDList> newPersistIDList;
246
247 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
248
249 if (!pidl)
250 return E_INVALIDARG;
251
252 if (pidlParent || psfParent)
253 {
254 LPITEMIDLIST temp_parent = NULL;
255 if (!pidlParent)
256 {
257 CComPtr<IPersistFolder2> ppf2Parent;
258
259 if (FAILED(psfParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2Parent))))
260 {
261 FIXME("couldn't get IPersistFolder2 interface of parent\n");
262 return E_NOINTERFACE;
263 }
264
265 if (FAILED(ppf2Parent->GetCurFolder(&temp_parent)))
266 {
267 FIXME("couldn't get parent PIDL\n");
268 return E_NOINTERFACE;
269 }
270
271 pidlParent = temp_parent;
272 }
273
274 new_pidl = ILCombine(pidlParent, pidl);
275 ILFree(temp_parent);
276
277 if (!new_pidl)
278 return E_OUTOFMEMORY;
279 }
280 else
281 {
282 new_pidl = ILClone(pidl);
283 if (!new_pidl)
284 return E_OUTOFMEMORY;
285 }
286
287 hr = CShellItem::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellItem, &newShellItem));
288 if (FAILED(hr))
289 {
290 *ppsi = NULL;
291 ILFree(new_pidl);
292 return hr;
293 }
294 hr = newShellItem->QueryInterface(IID_PPV_ARG(IPersistIDList, &newPersistIDList));
295 if (FAILED(hr))
296 {
297 ILFree(new_pidl);
298 return hr;
299 }
300 hr = newPersistIDList->SetIDList(new_pidl);
301 if (FAILED(hr))
302 {
303 ILFree(new_pidl);
304 return hr;
305 }
306 ILFree(new_pidl);
307 *ppsi = newShellItem;
308 return hr;
309 }