Sync with trunk r58687.
[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 {
32 m_pidl = NULL;
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 LPITEMIDLIST parent_pidl;
64 CComPtr<IShellFolder> desktop;
65 HRESULT hr;
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_IShellFolder, (void**)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 LPITEMIDLIST parent_pidl;
91 HRESULT hr;
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 CComPtr<IShellFolder> parent_folder;
108 HRESULT hr;
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 LPITEMIDLIST 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, (LPCITEMIDLIST*)&child_pidl, psfgaoAttribs);
165 }
166
167 return hr;
168 }
169
170 HRESULT WINAPI CShellItem::Compare(IShellItem *oth, SICHINTF hint, int *piOrder)
171 {
172 CComPtr<IShellFolder> parent_folder;
173 CComPtr<IPersistIDList> pIDList;
174 HRESULT hr;
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_IPersistIDList, (void **)&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 = (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 IShellItem *newShellItem;
243 LPITEMIDLIST new_pidl;
244 CComPtr<IPersistIDList> newPersistIDList;
245 HRESULT hr;
246
247 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
248
249 if (!pidl)
250 {
251 return E_INVALIDARG;
252 }
253 else if (pidlParent || psfParent)
254 {
255 LPITEMIDLIST temp_parent=NULL;
256 if (!pidlParent)
257 {
258 CComPtr<IPersistFolder2> ppf2Parent;
259
260 if (FAILED(psfParent->QueryInterface(IID_IPersistFolder2, (void**)&ppf2Parent)))
261 {
262 FIXME("couldn't get IPersistFolder2 interface of parent\n");
263 return E_NOINTERFACE;
264 }
265
266 if (FAILED(ppf2Parent->GetCurFolder(&temp_parent)))
267 {
268 FIXME("couldn't get parent PIDL\n");
269 return E_NOINTERFACE;
270 }
271
272 pidlParent = temp_parent;
273 }
274
275 new_pidl = ILCombine(pidlParent, pidl);
276 ILFree(temp_parent);
277
278 if (!new_pidl)
279 return E_OUTOFMEMORY;
280 }
281 else
282 {
283 new_pidl = ILClone(pidl);
284 if (!new_pidl)
285 return E_OUTOFMEMORY;
286 }
287
288 hr = CShellItem::_CreatorClass::CreateInstance(NULL, IID_IShellItem, (void**)&newShellItem);
289 if (FAILED(hr))
290 {
291 *ppsi = NULL;
292 ILFree(new_pidl);
293 return hr;
294 }
295 hr = newShellItem->QueryInterface(IID_IPersistIDList, (void **)&newPersistIDList);
296 if (FAILED(hr))
297 {
298 ILFree(new_pidl);
299 return hr;
300 }
301 hr = newPersistIDList->SetIDList(new_pidl);
302 if (FAILED(hr))
303 {
304 ILFree(new_pidl);
305 return hr;
306 }
307 ILFree(new_pidl);
308 *ppsi = newShellItem;
309 return hr;
310 }