[SHELL32] CDrivesFolder: Implement the eject and disconnect menu items. CORE-13841
[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 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 switch (sigdnName)
126 {
127 case SIGDN_PARENTRELATIVEEDITING:
128 uFlags = SHGDN_FOREDITING | SHGDN_INFOLDER;
129 break;
130 case SIGDN_DESKTOPABSOLUTEEDITING:
131 uFlags = SHGDN_FOREDITING;
132 break;
133 case SIGDN_PARENTRELATIVEPARSING:
134 uFlags = SHGDN_FORPARSING | SHGDN_INFOLDER;
135 break;
136 case SIGDN_DESKTOPABSOLUTEPARSING:
137 uFlags = SHGDN_FORPARSING;
138 break;
139 default:
140 uFlags = SHGDN_NORMAL;
141 break;
142 }
143
144 hr = parent_folder->GetDisplayNameOf(m_pidl, uFlags, &name);
145 if (SUCCEEDED(hr))
146 {
147 StrRetToStrW(&name, m_pidl, ppszName);
148 return S_OK;
149 }
150 }
151
152 return hr;
153 }
154
155 HRESULT WINAPI CShellItem::GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs)
156 {
157 CComPtr<IShellFolder> parent_folder;
158 LPCITEMIDLIST child_pidl;
159 HRESULT hr;
160
161 TRACE("(%p,%x,%p)\n", this, sfgaoMask, psfgaoAttribs);
162
163 hr = get_parent_shellfolder(&parent_folder);
164 if (SUCCEEDED(hr))
165 {
166 child_pidl = ILFindLastID(m_pidl);
167 *psfgaoAttribs = sfgaoMask;
168 hr = parent_folder->GetAttributesOf(1, &child_pidl, psfgaoAttribs);
169 }
170
171 return hr;
172 }
173
174 HRESULT WINAPI CShellItem::Compare(IShellItem *oth, SICHINTF hint, int *piOrder)
175 {
176 HRESULT hr;
177 CComPtr<IPersistIDList> pIDList;
178 CComPtr<IShellFolder> parent_folder;
179 LPITEMIDLIST pidl;
180
181 TRACE("(%p,%p,%x,%p)\n", this, oth, hint, piOrder);
182
183 if (piOrder == NULL || oth == NULL)
184 return E_POINTER;
185
186 hr = oth->QueryInterface(IID_PPV_ARG(IPersistIDList, &pIDList));
187 if (SUCCEEDED(hr))
188 {
189 hr = pIDList->GetIDList(&pidl);
190 if (SUCCEEDED(hr))
191 {
192 hr = get_parent_shellfolder(&parent_folder);
193 if (SUCCEEDED(hr))
194 {
195 hr = parent_folder->CompareIDs(hint, m_pidl, pidl);
196 *piOrder = static_cast<int>(SCODE_CODE(hr));
197 }
198 ILFree(pidl);
199 }
200 }
201
202 if (SUCCEEDED(hr))
203 return S_OK;
204 return hr;
205 }
206
207 HRESULT WINAPI CShellItem::GetClassID(CLSID *pClassID)
208 {
209 TRACE("(%p,%p)\n", this, pClassID);
210
211 *pClassID = CLSID_ShellItem;
212 return S_OK;
213 }
214
215 HRESULT WINAPI CShellItem::SetIDList(LPCITEMIDLIST pidlx)
216 {
217 LPITEMIDLIST new_pidl;
218
219 TRACE("(%p,%p)\n", this, pidlx);
220
221 new_pidl = ILClone(pidlx);
222 if (new_pidl)
223 {
224 ILFree(m_pidl);
225 m_pidl = new_pidl;
226 return S_OK;
227 }
228 else
229 return E_OUTOFMEMORY;
230 }
231
232 HRESULT WINAPI CShellItem::GetIDList(LPITEMIDLIST *ppidl)
233 {
234 TRACE("(%p,%p)\n", this, ppidl);
235
236 *ppidl = ILClone(m_pidl);
237 if (*ppidl)
238 return S_OK;
239 else
240 return E_OUTOFMEMORY;
241 }
242
243 HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent,
244 IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi)
245 {
246 HRESULT hr;
247 CComPtr<IShellItem> newShellItem;
248 LPITEMIDLIST new_pidl;
249 CComPtr<IPersistIDList> newPersistIDList;
250
251 TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi);
252
253 if (!pidl)
254 return E_INVALIDARG;
255
256 if (pidlParent || psfParent)
257 {
258 LPITEMIDLIST temp_parent = NULL;
259 if (!pidlParent)
260 {
261 CComPtr<IPersistFolder2> ppf2Parent;
262
263 if (FAILED(psfParent->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2Parent))))
264 {
265 FIXME("couldn't get IPersistFolder2 interface of parent\n");
266 return E_NOINTERFACE;
267 }
268
269 if (FAILED(ppf2Parent->GetCurFolder(&temp_parent)))
270 {
271 FIXME("couldn't get parent PIDL\n");
272 return E_NOINTERFACE;
273 }
274
275 pidlParent = temp_parent;
276 }
277
278 new_pidl = ILCombine(pidlParent, pidl);
279 ILFree(temp_parent);
280
281 if (!new_pidl)
282 return E_OUTOFMEMORY;
283 }
284 else
285 {
286 new_pidl = ILClone(pidl);
287 if (!new_pidl)
288 return E_OUTOFMEMORY;
289 }
290
291 hr = CShellItem::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellItem, &newShellItem));
292 if (FAILED(hr))
293 {
294 *ppsi = NULL;
295 ILFree(new_pidl);
296 return hr;
297 }
298 hr = newShellItem->QueryInterface(IID_PPV_ARG(IPersistIDList, &newPersistIDList));
299 if (FAILED(hr))
300 {
301 ILFree(new_pidl);
302 return hr;
303 }
304 hr = newPersistIDList->SetIDList(new_pidl);
305 if (FAILED(hr))
306 {
307 ILFree(new_pidl);
308 return hr;
309 }
310 ILFree(new_pidl);
311
312 *ppsi = newShellItem.Detach();
313
314 return hr;
315 }