1 /* 2 * Virtual Desktop Folder 3 * 4 * Copyright 1997 Marcus Meissner 5 * Copyright 1998, 1999, 2002 Juergen Schmied 6 * Copyright 2009 Andrew Hill 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 /* 28 CDesktopFolder should create two file system folders internally, one representing the 29 user's desktop folder, and the other representing the common desktop folder. It should 30 also create a CRegFolder to represent the virtual items that exist only in the registry. 31 The CRegFolder is aggregated by the CDesktopFolder, and queries for the CLSID_IShellFolder, 32 CLSID_IShellFolder2, or CLSID_IShellIconOverlay interfaces prefer the CRegFolder 33 implementation. 34 The CDesktopFolderEnum class should create two enumerators, one for each of the file 35 system folders, and enumerate the contents of each folder. Since the CRegFolder 36 implementation of IShellFolder::EnumObjects enumerates the virtual items, the 37 CDesktopFolderEnum is only responsible for returning the physical items. 38 CDesktopFolderEnum is incorrect where it filters My Computer from the enumeration 39 if the new start menu is used. The CDesktopViewCallback is responsible for filtering 40 it from the view by handling the IncludeObject query to return S_FALSE. The enumerator 41 always shows My Computer. 42 */ 43 44 /* Undocumented functions from shdocvw */ 45 extern "C" HRESULT WINAPI IEParseDisplayNameWithBCW(DWORD codepage, LPCWSTR lpszDisplayName, LPBC pbc, LPITEMIDLIST *ppidl); 46 47 static const WCHAR ClassicStartMenuW[] = L"SOFTWARE\\Microsoft\\Windows\\" 48 L"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu"; 49 50 static INT 51 IsNamespaceExtensionHidden(const WCHAR *iid) 52 { 53 DWORD Result, dwResult; 54 dwResult = sizeof(DWORD); 55 56 if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */ 57 ClassicStartMenuW, 58 iid, 59 RRF_RT_DWORD, 60 NULL, 61 &Result, 62 &dwResult) != ERROR_SUCCESS) 63 { 64 return -1; 65 } 66 67 return Result; 68 } 69 70 static INT IsNamespaceExtensionHidden(LPCITEMIDLIST pidl) 71 { 72 GUID const *clsid = _ILGetGUIDPointer (pidl); 73 if (!clsid) 74 return -1; 75 76 WCHAR pwszGuid[CHARS_IN_GUID]; 77 SHELL32_GUIDToStringW(*clsid, pwszGuid); 78 return IsNamespaceExtensionHidden(pwszGuid); 79 } 80 81 class CDesktopFolderEnum : 82 public CEnumIDListBase 83 { 84 private: 85 // CComPtr fDesktopEnumerator; 86 // CComPtr fCommonDesktopEnumerator; 87 public: 88 89 void AddItemsFromClassicStartMenuKey(HKEY hKeyRoot) 90 { 91 DWORD dwResult; 92 HKEY hkey; 93 DWORD j = 0, dwVal, Val, dwType, dwIID; 94 LONG r; 95 WCHAR iid[50]; 96 LPITEMIDLIST pidl; 97 98 dwResult = RegOpenKeyExW(hKeyRoot, ClassicStartMenuW, 0, KEY_READ, &hkey); 99 if (dwResult != ERROR_SUCCESS) 100 return; 101 102 while(1) 103 { 104 dwVal = sizeof(Val); 105 dwIID = sizeof(iid) / sizeof(WCHAR); 106 107 r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal); 108 if (r != ERROR_SUCCESS) 109 break; 110 111 if (Val == 0 && dwType == REG_DWORD) 112 { 113 pidl = _ILCreateGuidFromStrW(iid); 114 if (pidl != NULL) 115 { 116 if (!HasItemWithCLSID(pidl)) 117 AddToEnumList(pidl); 118 else 119 SHFree(pidl); 120 } 121 } 122 } 123 RegCloseKey(hkey); 124 } 125 126 HRESULT WINAPI Initialize(DWORD dwFlags,IEnumIDList * pRegEnumerator, IEnumIDList *pDesktopEnumerator, IEnumIDList *pCommonDesktopEnumerator) 127 { 128 BOOL ret = TRUE; 129 LPITEMIDLIST pidl; 130 131 static const WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}"; 132 133 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags); 134 135 /* enumerate the root folders */ 136 if (dwFlags & SHCONTF_FOLDERS) 137 { 138 AddToEnumList(_ILCreateMyComputer()); 139 if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1) 140 AddToEnumList(_ILCreateMyDocuments()); 141 142 DWORD dwFetched; 143 while((S_OK == pRegEnumerator->Next(1, &pidl, &dwFetched)) && dwFetched) 144 { 145 if (IsNamespaceExtensionHidden(pidl) < 1) 146 { 147 if (!HasItemWithCLSID(pidl)) 148 AddToEnumList(pidl); 149 else 150 SHFree(pidl); 151 } 152 } 153 AddItemsFromClassicStartMenuKey(HKEY_LOCAL_MACHINE); 154 AddItemsFromClassicStartMenuKey(HKEY_CURRENT_USER); 155 } 156 157 /* Enumerate the items in the two fs folders */ 158 AppendItemsFromEnumerator(pDesktopEnumerator); 159 AppendItemsFromEnumerator(pCommonDesktopEnumerator); 160 161 return ret ? S_OK : E_FAIL; 162 } 163 164 165 BEGIN_COM_MAP(CDesktopFolderEnum) 166 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 167 END_COM_MAP() 168 }; 169 170 int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll); 171 172 static const shvheader DesktopSFHeader[] = { 173 {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15}, 174 {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 10}, 175 {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10}, 176 {IDS_SHV_COLUMN_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, 177 {IDS_SHV_COLUMN_MODIFIED, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 12}, 178 {IDS_SHV_COLUMN_ATTRIBUTES, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10} 179 }; 180 181 #define DESKTOPSHELLVIEWCOLUMNS 6 182 183 static const DWORD dwDesktopAttributes = 184 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | 185 SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE; 186 static const DWORD dwMyComputerAttributes = 187 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | 188 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK; 189 static DWORD dwMyNetPlacesAttributes = 190 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | 191 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK; 192 193 CDesktopFolder::CDesktopFolder() : 194 sPathTarget(NULL), 195 pidlRoot(NULL) 196 { 197 } 198 199 CDesktopFolder::~CDesktopFolder() 200 { 201 } 202 203 HRESULT WINAPI CDesktopFolder::FinalConstruct() 204 { 205 WCHAR szMyPath[MAX_PATH]; 206 HRESULT hr; 207 208 /* Create the root pidl */ 209 pidlRoot = _ILCreateDesktop(); 210 if (!pidlRoot) 211 return E_OUTOFMEMORY; 212 213 /* Create the inner fs folder */ 214 hr = SHELL32_CoCreateInitSF(pidlRoot, 215 &CLSID_ShellFSFolder, 216 CSIDL_DESKTOPDIRECTORY, 217 IID_PPV_ARG(IShellFolder2, &m_DesktopFSFolder)); 218 if (FAILED_UNEXPECTEDLY(hr)) 219 return hr; 220 221 /* Create the inner shared fs folder. Dont fail on failure. */ 222 hr = SHELL32_CoCreateInitSF(pidlRoot, 223 &CLSID_ShellFSFolder, 224 CSIDL_COMMON_DESKTOPDIRECTORY, 225 IID_PPV_ARG(IShellFolder2, &m_SharedDesktopFSFolder)); 226 if (FAILED_UNEXPECTEDLY(hr)) 227 return hr; 228 229 /* Create the inner reg folder */ 230 hr = CRegFolder_CreateInstance(&CLSID_ShellDesktop, 231 pidlRoot, 232 L"", 233 L"Desktop", 234 IID_PPV_ARG(IShellFolder2, &m_regFolder)); 235 if (FAILED_UNEXPECTEDLY(hr)) 236 return hr; 237 238 /* Cache the path to the user desktop directory */ 239 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE )) 240 return E_UNEXPECTED; 241 242 sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR)); 243 if (!sPathTarget) 244 return E_OUTOFMEMORY; 245 246 wcscpy(sPathTarget, szMyPath); 247 return S_OK; 248 } 249 250 HRESULT CDesktopFolder::_GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf) 251 { 252 WCHAR szFileName[MAX_PATH]; 253 254 if (_ILIsSpecialFolder(pidl)) 255 return m_regFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); 256 257 lstrcpynW(szFileName, sPathTarget, MAX_PATH - 1); 258 PathAddBackslashW(szFileName); 259 int cLen = wcslen(szFileName); 260 261 if (!_ILSimpleGetTextW(pidl, szFileName + cLen, MAX_PATH - cLen)) 262 return E_FAIL; 263 264 if (GetFileAttributes(szFileName) == INVALID_FILE_ATTRIBUTES) 265 return m_SharedDesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); 266 else 267 return m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); 268 } 269 270 /************************************************************************** 271 * CDesktopFolder::ParseDisplayName 272 * 273 * NOTES 274 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds 275 * to MyComputer 276 */ 277 HRESULT WINAPI CDesktopFolder::ParseDisplayName( 278 HWND hwndOwner, 279 LPBC pbc, 280 LPOLESTR lpszDisplayName, 281 DWORD *pchEaten, 282 PIDLIST_RELATIVE *ppidl, 283 DWORD *pdwAttributes) 284 { 285 LPCWSTR szNext = NULL; 286 LPITEMIDLIST pidlTemp = NULL; 287 PARSEDURLW urldata; 288 HRESULT hr = S_OK; 289 290 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", 291 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName), 292 pchEaten, ppidl, pdwAttributes); 293 294 if (!ppidl) 295 return E_INVALIDARG; 296 297 *ppidl = NULL; 298 299 if (!lpszDisplayName) 300 return E_INVALIDARG; 301 302 if (pchEaten) 303 *pchEaten = 0; /* strange but like the original */ 304 305 urldata.cbSize = sizeof(urldata); 306 307 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':') 308 { 309 return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes); 310 } 311 else if (PathGetDriveNumberW (lpszDisplayName) >= 0) 312 { 313 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */ 314 pidlTemp = _ILCreateMyComputer (); 315 szNext = lpszDisplayName; 316 } 317 else if (PathIsUNCW(lpszDisplayName)) 318 { 319 pidlTemp = _ILCreateNetwork(); 320 szNext = lpszDisplayName; 321 } 322 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) ) 323 { 324 *ppidl = pidlTemp; 325 return S_OK; 326 } 327 else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata))) 328 { 329 if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */ 330 { 331 TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix)); 332 pidlTemp = _ILCreateGuidFromStrW(urldata.pszSuffix + 2); 333 } 334 else 335 return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl); 336 } 337 else 338 { 339 if (*lpszDisplayName) 340 { 341 /* it's a filesystem path on the desktop. Let a FSFolder parse it */ 342 hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes); 343 if (SUCCEEDED(hr)) 344 return hr; 345 346 return m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes); 347 } 348 else 349 pidlTemp = _ILCreateMyComputer(); 350 351 szNext = NULL; 352 } 353 354 if (SUCCEEDED(hr) && pidlTemp) 355 { 356 if (szNext && *szNext) 357 { 358 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc, 359 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes); 360 } 361 else 362 { 363 if (pdwAttributes && *pdwAttributes) 364 { 365 GetAttributesOf(1, &pidlTemp, pdwAttributes); 366 } 367 } 368 } 369 370 if (SUCCEEDED(hr)) 371 *ppidl = pidlTemp; 372 else 373 *ppidl = NULL; 374 375 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr); 376 377 return hr; 378 } 379 380 /************************************************************************** 381 * CDesktopFolder::EnumObjects 382 */ 383 HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 384 { 385 CComPtr<IEnumIDList> pRegEnumerator; 386 CComPtr<IEnumIDList> pDesktopEnumerator; 387 CComPtr<IEnumIDList> pCommonDesktopEnumerator; 388 HRESULT hr; 389 390 hr = m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator); 391 if (FAILED(hr)) 392 ERR("EnumObjects for reg folder failed\n"); 393 394 hr = m_DesktopFSFolder->EnumObjects(hwndOwner, dwFlags, &pDesktopEnumerator); 395 if (FAILED(hr)) 396 ERR("EnumObjects for desktop fs folder failed\n"); 397 398 hr = m_SharedDesktopFSFolder->EnumObjects(hwndOwner, dwFlags, &pCommonDesktopEnumerator); 399 if (FAILED(hr)) 400 ERR("EnumObjects for shared desktop fs folder failed\n"); 401 402 return ShellObjectCreatorInit<CDesktopFolderEnum>(dwFlags,pRegEnumerator, pDesktopEnumerator, pCommonDesktopEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 403 } 404 405 /************************************************************************** 406 * CDesktopFolder::BindToObject 407 */ 408 HRESULT WINAPI CDesktopFolder::BindToObject( 409 PCUIDLIST_RELATIVE pidl, 410 LPBC pbcReserved, 411 REFIID riid, 412 LPVOID *ppvOut) 413 { 414 if (!pidl) 415 return E_INVALIDARG; 416 417 CComPtr<IShellFolder2> psf; 418 HRESULT hr = _GetSFFromPidl(pidl, &psf); 419 if (FAILED_UNEXPECTEDLY(hr)) 420 return hr; 421 422 return psf->BindToObject(pidl, pbcReserved, riid, ppvOut); 423 } 424 425 /************************************************************************** 426 * CDesktopFolder::BindToStorage 427 */ 428 HRESULT WINAPI CDesktopFolder::BindToStorage( 429 PCUIDLIST_RELATIVE pidl, 430 LPBC pbcReserved, 431 REFIID riid, 432 LPVOID *ppvOut) 433 { 434 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", 435 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut); 436 437 *ppvOut = NULL; 438 return E_NOTIMPL; 439 } 440 441 /************************************************************************** 442 * CDesktopFolder::CompareIDs 443 */ 444 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 445 { 446 bool bIsDesktopFolder1, bIsDesktopFolder2; 447 448 if (!pidl1 || !pidl2) 449 { 450 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2); 451 return E_INVALIDARG; 452 } 453 454 bIsDesktopFolder1 = _ILIsDesktop(pidl1); 455 bIsDesktopFolder2 = _ILIsDesktop(pidl2); 456 if (bIsDesktopFolder1 || bIsDesktopFolder2) 457 return MAKE_COMPARE_HRESULT(bIsDesktopFolder1 - bIsDesktopFolder2); 458 459 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2)) 460 return m_regFolder->CompareIDs(lParam, pidl1, pidl2); 461 462 return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2); 463 } 464 465 /************************************************************************** 466 * CDesktopFolder::CreateViewObject 467 */ 468 HRESULT WINAPI CDesktopFolder::CreateViewObject( 469 HWND hwndOwner, 470 REFIID riid, 471 LPVOID *ppvOut) 472 { 473 HRESULT hr = E_INVALIDARG; 474 475 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", 476 this, hwndOwner, shdebugstr_guid (&riid), ppvOut); 477 478 if (!ppvOut) 479 return hr; 480 481 *ppvOut = NULL; 482 483 if (IsEqualIID (riid, IID_IDropTarget)) 484 { 485 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut); 486 } 487 else if (IsEqualIID (riid, IID_IContextMenu)) 488 { 489 HKEY hKeys[16]; 490 UINT cKeys = 0; 491 AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys); 492 493 DEFCONTEXTMENU dcm; 494 dcm.hwnd = hwndOwner; 495 dcm.pcmcb = this; 496 dcm.pidlFolder = pidlRoot; 497 dcm.psf = this; 498 dcm.cidl = 0; 499 dcm.apidl = NULL; 500 dcm.cKeys = cKeys; 501 dcm.aKeys = hKeys; 502 dcm.punkAssociationInfo = NULL; 503 hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut); 504 } 505 else if (IsEqualIID (riid, IID_IShellView)) 506 { 507 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; 508 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 509 } 510 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut); 511 return hr; 512 } 513 514 /************************************************************************** 515 * CDesktopFolder::GetAttributesOf 516 */ 517 HRESULT WINAPI CDesktopFolder::GetAttributesOf( 518 UINT cidl, 519 PCUITEMID_CHILD_ARRAY apidl, 520 DWORD *rgfInOut) 521 { 522 HRESULT hr = S_OK; 523 524 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", 525 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0); 526 527 if (cidl && !apidl) 528 return E_INVALIDARG; 529 530 if (*rgfInOut == 0) 531 *rgfInOut = ~0; 532 533 if(cidl == 0) 534 *rgfInOut &= dwDesktopAttributes; 535 else 536 { 537 /* TODO: always add SFGAO_CANLINK */ 538 for (UINT i = 0; i < cidl; ++i) 539 { 540 pdump(*apidl); 541 if (_ILIsDesktop(*apidl)) 542 *rgfInOut &= dwDesktopAttributes; 543 else if (_ILIsMyComputer(apidl[i])) 544 *rgfInOut &= dwMyComputerAttributes; 545 else if (_ILIsNetHood(apidl[i])) 546 *rgfInOut &= dwMyNetPlacesAttributes; 547 else if (_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]) || _ILIsSpecialFolder(apidl[i])) 548 { 549 CComPtr<IShellFolder2> psf; 550 HRESULT hr = _GetSFFromPidl(apidl[i], &psf); 551 if (FAILED_UNEXPECTEDLY(hr)) 552 continue; 553 554 psf->GetAttributesOf(1, &apidl[i], rgfInOut); 555 } 556 else 557 ERR("Got an unknown pidl type!!!\n"); 558 } 559 } 560 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */ 561 *rgfInOut &= ~SFGAO_VALIDATE; 562 563 TRACE("-- result=0x%08x\n", *rgfInOut); 564 565 return hr; 566 } 567 568 /************************************************************************** 569 * CDesktopFolder::GetUIObjectOf 570 * 571 * PARAMETERS 572 * HWND hwndOwner, //[in ] Parent window for any output 573 * UINT cidl, //[in ] array size 574 * LPCITEMIDLIST* apidl, //[in ] simple pidl array 575 * REFIID riid, //[in ] Requested Interface 576 * UINT* prgfInOut, //[ ] reserved 577 * LPVOID* ppvObject) //[out] Resulting Interface 578 * 579 */ 580 HRESULT WINAPI CDesktopFolder::GetUIObjectOf( 581 HWND hwndOwner, 582 UINT cidl, 583 PCUITEMID_CHILD_ARRAY apidl, 584 REFIID riid, 585 UINT *prgfInOut, 586 LPVOID *ppvOut) 587 { 588 LPVOID pObj = NULL; 589 HRESULT hr = E_INVALIDARG; 590 591 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", 592 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut); 593 594 if (!ppvOut) 595 return hr; 596 597 *ppvOut = NULL; 598 599 if (cidl == 1 && !_ILIsSpecialFolder(apidl[0])) 600 { 601 CComPtr<IShellFolder2> psf; 602 HRESULT hr = _GetSFFromPidl(apidl[0], &psf); 603 if (FAILED_UNEXPECTEDLY(hr)) 604 return hr; 605 606 return psf->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut); 607 } 608 609 if (IsEqualIID (riid, IID_IContextMenu)) 610 { 611 if (_ILIsSpecialFolder(apidl[0])) 612 { 613 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 614 } 615 else 616 { 617 /* Do not use the context menu of the CFSFolder here. */ 618 /* We need to pass a pointer of the CDesktopFolder so as the data object that the context menu gets is rooted to the desktop */ 619 /* Otherwise operations like that involve items from both user and shared desktop will not work */ 620 HKEY hKeys[16]; 621 UINT cKeys = 0; 622 AddFSClassKeysToArray(apidl[0], hKeys, &cKeys); 623 624 DEFCONTEXTMENU dcm; 625 dcm.hwnd = hwndOwner; 626 dcm.pcmcb = this; 627 dcm.pidlFolder = pidlRoot; 628 dcm.psf = this; 629 dcm.cidl = cidl; 630 dcm.apidl = apidl; 631 dcm.cKeys = cKeys; 632 dcm.aKeys = hKeys; 633 dcm.punkAssociationInfo = NULL; 634 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj); 635 } 636 } 637 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) 638 { 639 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj); 640 } 641 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 642 { 643 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 644 } 645 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1)) 646 { 647 CComPtr<IShellFolder> psfChild; 648 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 649 if (FAILED_UNEXPECTEDLY(hr)) 650 return hr; 651 652 return psfChild->CreateViewObject(NULL, riid, ppvOut); 653 } 654 else 655 hr = E_NOINTERFACE; 656 657 if (SUCCEEDED(hr) && !pObj) 658 hr = E_OUTOFMEMORY; 659 660 *ppvOut = pObj; 661 TRACE ("(%p)->hr=0x%08x\n", this, hr); 662 return hr; 663 } 664 665 /************************************************************************** 666 * CDesktopFolder::GetDisplayNameOf 667 * 668 * NOTES 669 * special case: pidl = null gives desktop-name back 670 */ 671 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 672 { 673 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); 674 pdump (pidl); 675 676 if (!strRet) 677 return E_INVALIDARG; 678 679 if (!_ILIsPidlSimple (pidl)) 680 { 681 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet); 682 } 683 else if (_ILIsDesktop(pidl)) 684 { 685 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING)) 686 return SHSetStrRet(strRet, sPathTarget); 687 else 688 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet); 689 } 690 691 /* file system folder or file rooted at the desktop */ 692 CComPtr<IShellFolder2> psf; 693 HRESULT hr = _GetSFFromPidl(pidl, &psf); 694 if (FAILED_UNEXPECTEDLY(hr)) 695 return hr; 696 697 return psf->GetDisplayNameOf(pidl, dwFlags, strRet); 698 } 699 700 /************************************************************************** 701 * CDesktopFolder::SetNameOf 702 * Changes the name of a file object or subfolder, possibly changing its item 703 * identifier in the process. 704 * 705 * PARAMETERS 706 * HWND hwndOwner, //[in ] Owner window for output 707 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change 708 * LPCOLESTR lpszName, //[in ] the items new display name 709 * DWORD dwFlags, //[in ] SHGNO formatting flags 710 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned 711 */ 712 HRESULT WINAPI CDesktopFolder::SetNameOf( 713 HWND hwndOwner, 714 PCUITEMID_CHILD pidl, /* simple pidl */ 715 LPCOLESTR lpName, 716 DWORD dwFlags, 717 PITEMID_CHILD *pPidlOut) 718 { 719 CComPtr<IShellFolder2> psf; 720 HRESULT hr = _GetSFFromPidl(pidl, &psf); 721 if (FAILED_UNEXPECTEDLY(hr)) 722 return hr; 723 724 return psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut); 725 } 726 727 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid) 728 { 729 FIXME ("(%p)\n", this); 730 return E_NOTIMPL; 731 } 732 733 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum) 734 { 735 FIXME ("(%p)\n", this); 736 return E_NOTIMPL; 737 } 738 739 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 740 { 741 TRACE ("(%p)\n", this); 742 743 if (pSort) 744 *pSort = 0; 745 if (pDisplay) 746 *pDisplay = 0; 747 748 return S_OK; 749 } 750 751 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 752 { 753 TRACE ("(%p)\n", this); 754 755 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS) 756 return E_INVALIDARG; 757 758 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags; 759 760 return S_OK; 761 } 762 763 HRESULT WINAPI CDesktopFolder::GetDetailsEx( 764 PCUITEMID_CHILD pidl, 765 const SHCOLUMNID *pscid, 766 VARIANT *pv) 767 { 768 FIXME ("(%p)\n", this); 769 770 return E_NOTIMPL; 771 } 772 773 HRESULT WINAPI CDesktopFolder::GetDetailsOf( 774 PCUITEMID_CHILD pidl, 775 UINT iColumn, 776 SHELLDETAILS *psd) 777 { 778 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS) 779 return E_INVALIDARG; 780 781 if (!pidl) 782 { 783 psd->fmt = DesktopSFHeader[iColumn].fmt; 784 psd->cxChar = DesktopSFHeader[iColumn].cxChar; 785 return SHSetStrRet(&psd->str, DesktopSFHeader[iColumn].colnameid); 786 } 787 788 CComPtr<IShellFolder2> psf; 789 HRESULT hr = _GetSFFromPidl(pidl, &psf); 790 if (FAILED_UNEXPECTEDLY(hr)) 791 return hr; 792 793 hr = psf->GetDetailsOf(pidl, iColumn, psd); 794 if (FAILED_UNEXPECTEDLY(hr)) 795 return hr; 796 797 return hr; 798 } 799 800 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 801 { 802 FIXME ("(%p)\n", this); 803 return E_NOTIMPL; 804 } 805 806 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId) 807 { 808 TRACE ("(%p)\n", this); 809 810 if (!lpClassId) 811 return E_POINTER; 812 813 *lpClassId = CLSID_ShellDesktop; 814 815 return S_OK; 816 } 817 818 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl) 819 { 820 TRACE ("(%p)->(%p)\n", this, pidl); 821 822 if (!pidl) 823 return S_OK; 824 825 return E_INVALIDARG; 826 } 827 828 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl) 829 { 830 TRACE ("(%p)->(%p)\n", this, pidl); 831 832 if (!pidl) 833 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */ 834 *pidl = ILClone (pidlRoot); 835 return S_OK; 836 } 837 838 HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) 839 { 840 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND) 841 return S_OK; 842 843 /* no data object means no selection */ 844 if (!pdtobj) 845 { 846 if (uMsg == DFM_INVOKECOMMAND && wParam == 0) 847 { 848 if (32 >= (UINT)ShellExecuteW(hwndOwner, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL)) 849 return E_FAIL; 850 return S_OK; 851 } 852 else if (uMsg == DFM_MERGECONTEXTMENU) 853 { 854 QCMINFO *pqcminfo = (QCMINFO *)lParam; 855 HMENU hpopup = CreatePopupMenu(); 856 _InsertMenuItemW(hpopup, 0, TRUE, 0, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); 857 Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu++, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR); 858 DestroyMenu(hpopup); 859 } 860 861 return S_OK; 862 } 863 864 if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES) 865 return S_OK; 866 867 PIDLIST_ABSOLUTE pidlFolder; 868 PUITEMID_CHILD *apidl; 869 UINT cidl; 870 HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl); 871 if (FAILED_UNEXPECTEDLY(hr)) 872 return hr; 873 874 if (cidl > 1) 875 ERR("SHMultiFileProperties is not yet implemented\n"); 876 877 STRRET strFile; 878 hr = GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strFile); 879 if (SUCCEEDED(hr)) 880 { 881 hr = SH_ShowPropertiesDialog(strFile.pOleStr, pidlFolder, apidl); 882 if (FAILED(hr)) 883 ERR("SH_ShowPropertiesDialog failed\n"); 884 } 885 else 886 { 887 ERR("Failed to get display name\n"); 888 } 889 890 SHFree(pidlFolder); 891 _ILFreeaPidl(apidl, cidl); 892 893 return hr; 894 } 895 896 /************************************************************************* 897 * SHGetDesktopFolder [SHELL32.@] 898 */ 899 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf) 900 { 901 HRESULT hres = S_OK; 902 TRACE("\n"); 903 904 if(!psf) return E_INVALIDARG; 905 *psf = NULL; 906 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf)); 907 908 TRACE("-- %p->(%p)\n",psf, *psf); 909 return hres; 910 }