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 (cidl > 0 && _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 if (cidl > 0) 623 { 624 AddFSClassKeysToArray(apidl[0], hKeys, &cKeys); 625 } 626 627 DEFCONTEXTMENU dcm; 628 dcm.hwnd = hwndOwner; 629 dcm.pcmcb = this; 630 dcm.pidlFolder = pidlRoot; 631 dcm.psf = this; 632 dcm.cidl = cidl; 633 dcm.apidl = apidl; 634 dcm.cKeys = cKeys; 635 dcm.aKeys = hKeys; 636 dcm.punkAssociationInfo = NULL; 637 hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj); 638 } 639 } 640 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1)) 641 { 642 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, TRUE, (IDataObject **)&pObj); 643 } 644 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1)) 645 { 646 hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); 647 } 648 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1)) 649 { 650 CComPtr<IShellFolder> psfChild; 651 hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild)); 652 if (FAILED_UNEXPECTEDLY(hr)) 653 return hr; 654 655 return psfChild->CreateViewObject(NULL, riid, ppvOut); 656 } 657 else 658 hr = E_NOINTERFACE; 659 660 if (SUCCEEDED(hr) && !pObj) 661 hr = E_OUTOFMEMORY; 662 663 *ppvOut = pObj; 664 TRACE ("(%p)->hr=0x%08x\n", this, hr); 665 return hr; 666 } 667 668 /************************************************************************** 669 * CDesktopFolder::GetDisplayNameOf 670 * 671 * NOTES 672 * special case: pidl = null gives desktop-name back 673 */ 674 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 675 { 676 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); 677 pdump (pidl); 678 679 if (!strRet) 680 return E_INVALIDARG; 681 682 if (!_ILIsPidlSimple (pidl)) 683 { 684 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet); 685 } 686 else if (_ILIsDesktop(pidl)) 687 { 688 if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING)) 689 return SHSetStrRet(strRet, sPathTarget); 690 else 691 return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet); 692 } 693 694 /* file system folder or file rooted at the desktop */ 695 CComPtr<IShellFolder2> psf; 696 HRESULT hr = _GetSFFromPidl(pidl, &psf); 697 if (FAILED_UNEXPECTEDLY(hr)) 698 return hr; 699 700 return psf->GetDisplayNameOf(pidl, dwFlags, strRet); 701 } 702 703 /************************************************************************** 704 * CDesktopFolder::SetNameOf 705 * Changes the name of a file object or subfolder, possibly changing its item 706 * identifier in the process. 707 * 708 * PARAMETERS 709 * HWND hwndOwner, //[in ] Owner window for output 710 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change 711 * LPCOLESTR lpszName, //[in ] the items new display name 712 * DWORD dwFlags, //[in ] SHGNO formatting flags 713 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned 714 */ 715 HRESULT WINAPI CDesktopFolder::SetNameOf( 716 HWND hwndOwner, 717 PCUITEMID_CHILD pidl, /* simple pidl */ 718 LPCOLESTR lpName, 719 DWORD dwFlags, 720 PITEMID_CHILD *pPidlOut) 721 { 722 CComPtr<IShellFolder2> psf; 723 HRESULT hr = _GetSFFromPidl(pidl, &psf); 724 if (FAILED_UNEXPECTEDLY(hr)) 725 return hr; 726 727 return psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut); 728 } 729 730 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid) 731 { 732 FIXME ("(%p)\n", this); 733 return E_NOTIMPL; 734 } 735 736 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum) 737 { 738 FIXME ("(%p)\n", this); 739 return E_NOTIMPL; 740 } 741 742 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 743 { 744 TRACE ("(%p)\n", this); 745 746 if (pSort) 747 *pSort = 0; 748 if (pDisplay) 749 *pDisplay = 0; 750 751 return S_OK; 752 } 753 754 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 755 { 756 TRACE ("(%p)\n", this); 757 758 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS) 759 return E_INVALIDARG; 760 761 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags; 762 763 return S_OK; 764 } 765 766 HRESULT WINAPI CDesktopFolder::GetDetailsEx( 767 PCUITEMID_CHILD pidl, 768 const SHCOLUMNID *pscid, 769 VARIANT *pv) 770 { 771 FIXME ("(%p)\n", this); 772 773 return E_NOTIMPL; 774 } 775 776 HRESULT WINAPI CDesktopFolder::GetDetailsOf( 777 PCUITEMID_CHILD pidl, 778 UINT iColumn, 779 SHELLDETAILS *psd) 780 { 781 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS) 782 return E_INVALIDARG; 783 784 if (!pidl) 785 { 786 psd->fmt = DesktopSFHeader[iColumn].fmt; 787 psd->cxChar = DesktopSFHeader[iColumn].cxChar; 788 return SHSetStrRet(&psd->str, DesktopSFHeader[iColumn].colnameid); 789 } 790 791 CComPtr<IShellFolder2> psf; 792 HRESULT hr = _GetSFFromPidl(pidl, &psf); 793 if (FAILED_UNEXPECTEDLY(hr)) 794 return hr; 795 796 hr = psf->GetDetailsOf(pidl, iColumn, psd); 797 if (FAILED_UNEXPECTEDLY(hr)) 798 return hr; 799 800 return hr; 801 } 802 803 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 804 { 805 FIXME ("(%p)\n", this); 806 return E_NOTIMPL; 807 } 808 809 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId) 810 { 811 TRACE ("(%p)\n", this); 812 813 if (!lpClassId) 814 return E_POINTER; 815 816 *lpClassId = CLSID_ShellDesktop; 817 818 return S_OK; 819 } 820 821 HRESULT WINAPI CDesktopFolder::Initialize(PCIDLIST_ABSOLUTE pidl) 822 { 823 TRACE ("(%p)->(%p)\n", this, pidl); 824 825 if (!pidl) 826 return S_OK; 827 828 return E_INVALIDARG; 829 } 830 831 HRESULT WINAPI CDesktopFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl) 832 { 833 TRACE ("(%p)->(%p)\n", this, pidl); 834 835 if (!pidl) 836 return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */ 837 *pidl = ILClone (pidlRoot); 838 return S_OK; 839 } 840 841 HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) 842 { 843 if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND) 844 return S_OK; 845 846 /* no data object means no selection */ 847 if (!pdtobj) 848 { 849 if (uMsg == DFM_INVOKECOMMAND && wParam == 0) 850 { 851 if (32 >= (UINT_PTR)ShellExecuteW(hwndOwner, L"open", L"rundll32.exe", 852 L"shell32.dll,Control_RunDLL desk.cpl", NULL, SW_SHOWNORMAL)) 853 { 854 return E_FAIL; 855 } 856 return S_OK; 857 } 858 else if (uMsg == DFM_MERGECONTEXTMENU) 859 { 860 QCMINFO *pqcminfo = (QCMINFO *)lParam; 861 HMENU hpopup = CreatePopupMenu(); 862 _InsertMenuItemW(hpopup, 0, TRUE, 0, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); 863 Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu++, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR); 864 DestroyMenu(hpopup); 865 } 866 867 return S_OK; 868 } 869 870 if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES) 871 return S_OK; 872 873 return Shell_DefaultContextMenuCallBack(this, pdtobj); 874 } 875 876 /************************************************************************* 877 * SHGetDesktopFolder [SHELL32.@] 878 */ 879 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf) 880 { 881 HRESULT hres = S_OK; 882 TRACE("\n"); 883 884 if(!psf) return E_INVALIDARG; 885 *psf = NULL; 886 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf)); 887 888 TRACE("-- %p->(%p)\n",psf, *psf); 889 return hres; 890 }