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(PCIDLIST_ABSOLUTE pidlParent, 28 IShellFolder *psfParent, PCUITEMID_CHILD 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(PCIDLIST_ABSOLUTE pidlParent, 265 IShellFolder *psfParent, PCUITEMID_CHILD 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 339 class CShellItemArray : 340 public CComCoClass<CShellItemArray, &CLSID_NULL>, 341 public CComObjectRootEx<CComMultiThreadModelNoCS>, 342 public IShellItemArray 343 { 344 CIDA *m_pCIDA; 345 STGMEDIUM m_Medium; 346 347 public: 348 CShellItemArray() : m_pCIDA(NULL) 349 { 350 m_Medium.tymed = TYMED_NULL; 351 } 352 353 virtual ~CShellItemArray() 354 { 355 CDataObjectHIDA::DestroyCIDA(m_pCIDA, m_Medium); 356 } 357 358 HRESULT Initialize(IDataObject *pdo) 359 { 360 return CDataObjectHIDA::CreateCIDA(pdo, &m_pCIDA, m_Medium); 361 } 362 363 inline UINT GetCount() const { return m_pCIDA->cidl; } 364 365 // IShellItemArray 366 STDMETHODIMP BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv) override 367 { 368 UNIMPLEMENTED; 369 *ppv = NULL; 370 return E_NOTIMPL; 371 } 372 373 STDMETHODIMP GetPropertyStore(GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) override 374 { 375 UNIMPLEMENTED; 376 *ppv = NULL; 377 return E_NOTIMPL; 378 } 379 380 STDMETHODIMP GetPropertyDescriptionList(REFPROPERTYKEY keyType, REFIID riid, void **ppv) override 381 { 382 UNIMPLEMENTED; 383 *ppv = NULL; 384 return E_NOTIMPL; 385 } 386 387 STDMETHODIMP GetAttributes(SIATTRIBFLAGS dwAttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) override 388 { 389 UNIMPLEMENTED; 390 *psfgaoAttribs = 0; 391 return E_NOTIMPL; 392 } 393 394 STDMETHODIMP GetCount(DWORD*pCount) override 395 { 396 *pCount = m_pCIDA ? GetCount() : 0; 397 return S_OK; 398 } 399 400 STDMETHODIMP GetItemAt(DWORD nIndex, IShellItem **ppItem) override 401 { 402 if (!ppItem) 403 return E_INVALIDARG; 404 *ppItem = NULL; 405 if (!m_pCIDA) 406 return E_UNEXPECTED; 407 if (nIndex >= GetCount()) 408 return E_FAIL; 409 return SHCreateShellItem(HIDA_GetPIDLFolder(m_pCIDA), NULL, 410 HIDA_GetPIDLItem(m_pCIDA, nIndex), ppItem); 411 } 412 413 STDMETHODIMP EnumItems(IEnumShellItems **ppESI) override 414 { 415 UNIMPLEMENTED; 416 *ppESI = NULL; 417 return E_NOTIMPL; 418 } 419 420 DECLARE_NO_REGISTRY() 421 DECLARE_NOT_AGGREGATABLE(CShellItemArray) 422 423 BEGIN_COM_MAP(CShellItemArray) 424 COM_INTERFACE_ENTRY_IID(IID_IShellItemArray, IShellItemArray) 425 END_COM_MAP() 426 }; 427 428 EXTERN_C HRESULT WINAPI 429 SHCreateShellItemArrayFromDataObject(_In_ IDataObject *pdo, _In_ REFIID riid, _Out_ void **ppv) 430 { 431 return ShellObjectCreatorInit<CShellItemArray>(pdo, riid, ppv); 432 } 433