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