[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / folders / CDesktopFolder.cpp
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 class CDesktopFolderEnum :
48 public CEnumIDListBase
49 {
50 private:
51 // CComPtr fDesktopEnumerator;
52 // CComPtr fCommonDesktopEnumerator;
53 public:
54 CDesktopFolderEnum();
55 ~CDesktopFolderEnum();
56 HRESULT WINAPI Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags);
57
58 BEGIN_COM_MAP(CDesktopFolderEnum)
59 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
60 END_COM_MAP()
61 };
62
63 int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll);
64
65 static const shvheader DesktopSFHeader[] = {
66 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
67 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
68 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
69 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
70 {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
71 };
72
73 #define DESKTOPSHELLVIEWCOLUMNS 5
74
75 CDesktopFolderEnum::CDesktopFolderEnum()
76 {
77 }
78
79 CDesktopFolderEnum::~CDesktopFolderEnum()
80 {
81 }
82
83 static const WCHAR ClassicStartMenuW[] = L"SOFTWARE\\Microsoft\\Windows\\"
84 L"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu";
85
86 static INT
87 IsNamespaceExtensionHidden(const WCHAR *iid)
88 {
89 DWORD Result, dwResult;
90 dwResult = sizeof(DWORD);
91
92 if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */
93 ClassicStartMenuW,
94 iid,
95 RRF_RT_DWORD,
96 NULL,
97 &Result,
98 &dwResult) != ERROR_SUCCESS)
99 {
100 return -1;
101 }
102
103 return Result;
104 }
105
106 /**************************************************************************
107 * CreateDesktopEnumList()
108 */
109
110 HRESULT WINAPI CDesktopFolderEnum::Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags)
111 {
112 BOOL ret = TRUE;
113 WCHAR szPath[MAX_PATH];
114
115 static const WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}";
116 static const WCHAR Desktop_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\Namespace";
117
118 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
119
120 /* enumerate the root folders */
121 if (dwFlags & SHCONTF_FOLDERS)
122 {
123 HKEY hkey;
124 UINT i;
125 DWORD dwResult;
126
127 /* create the pidl for This item */
128 if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1)
129 {
130 ret = AddToEnumList(_ILCreateMyDocuments());
131 }
132 ret = AddToEnumList(_ILCreateMyComputer());
133
134 for (i = 0; i < 2; i++)
135 {
136 if (i == 0)
137 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
138 else
139 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
140
141 if (dwResult == ERROR_SUCCESS)
142 {
143 WCHAR iid[50];
144 LPITEMIDLIST pidl;
145 int i = 0;
146
147 while (ret)
148 {
149 DWORD size;
150 LONG r;
151
152 size = sizeof (iid) / sizeof (iid[0]);
153 r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
154 if (ERROR_SUCCESS == r)
155 {
156 if (IsNamespaceExtensionHidden(iid) < 1)
157 {
158 pidl = _ILCreateGuidFromStrW(iid);
159 if (pidl != NULL)
160 {
161 if (!HasItemWithCLSID(pidl))
162 {
163 ret = AddToEnumList(pidl);
164 }
165 else
166 {
167 SHFree(pidl);
168 }
169 }
170 }
171 }
172 else if (ERROR_NO_MORE_ITEMS == r)
173 break;
174 else
175 ret = FALSE;
176 i++;
177 }
178 RegCloseKey(hkey);
179 }
180 }
181 for (i = 0; i < 2; i++)
182 {
183 if (i == 0)
184 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, ClassicStartMenuW, 0, KEY_READ, &hkey);
185 else
186 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_READ, &hkey);
187
188 if (dwResult == ERROR_SUCCESS)
189 {
190 DWORD j = 0, dwVal, Val, dwType, dwIID;
191 LONG r;
192 WCHAR iid[50];
193
194 while(ret)
195 {
196 dwVal = sizeof(Val);
197 dwIID = sizeof(iid) / sizeof(WCHAR);
198
199 r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal);
200 if (r == ERROR_SUCCESS)
201 {
202 if (Val == 0 && dwType == REG_DWORD)
203 {
204 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(iid);
205 if (pidl != NULL)
206 {
207 if (!HasItemWithCLSID(pidl))
208 {
209 AddToEnumList(pidl);
210 }
211 else
212 {
213 SHFree(pidl);
214 }
215 }
216 }
217 }
218 else if (ERROR_NO_MORE_ITEMS == r)
219 break;
220 else
221 ret = FALSE;
222 }
223 RegCloseKey(hkey);
224 }
225
226 }
227 }
228
229 /* enumerate the elements in %windir%\desktop */
230 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
231 ret = ret && CreateFolderEnumList(szPath, dwFlags);
232
233 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
234 ret = ret && CreateFolderEnumList(szPath, dwFlags);
235
236 return ret ? S_OK : E_FAIL;
237 }
238
239 CDesktopFolder::CDesktopFolder() :
240 sPathTarget(NULL),
241 pidlRoot(NULL)
242 {
243 }
244
245 CDesktopFolder::~CDesktopFolder()
246 {
247 }
248
249 HRESULT WINAPI CDesktopFolder::FinalConstruct()
250 {
251 WCHAR szMyPath[MAX_PATH];
252 HRESULT hr;
253 CComPtr<IPersistFolder3> ppf3;
254
255 /* Create the root pidl */
256 pidlRoot = _ILCreateDesktop();
257
258 /* Create the inner fs folder */
259 hr = SHCoCreateInstance(NULL, &CLSID_ShellFSFolder, NULL, IID_PPV_ARG(IShellFolder, &m_DesktopFSFolder));
260 if (FAILED(hr))
261 return hr;
262
263 hr = m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf3));
264 if (FAILED(hr))
265 return hr;
266
267 PERSIST_FOLDER_TARGET_INFO info;
268 ZeroMemory(&info, sizeof(PERSIST_FOLDER_TARGET_INFO));
269 info.csidl = CSIDL_DESKTOPDIRECTORY;
270 hr = ppf3->InitializeEx(NULL, pidlRoot, &info);
271
272 /* Create the inner shared fs folder */
273 hr = SHCoCreateInstance(NULL, &CLSID_ShellFSFolder, NULL, IID_PPV_ARG(IShellFolder, &m_SharedDesktopFSFolder));
274 if (FAILED(hr))
275 return hr;
276
277 hr = m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf3));
278 if (FAILED(hr))
279 return hr;
280
281 info.csidl = CSIDL_COMMON_DESKTOPDIRECTORY;
282 hr = ppf3->InitializeEx(NULL, pidlRoot, &info);
283
284 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
285 return E_UNEXPECTED;
286
287 sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
288 wcscpy(sPathTarget, szMyPath);
289 return S_OK;
290 }
291
292 /**************************************************************************
293 * CDesktopFolder::ParseDisplayName
294 *
295 * NOTES
296 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
297 * to MyComputer
298 */
299 HRESULT WINAPI CDesktopFolder::ParseDisplayName(
300 HWND hwndOwner,
301 LPBC pbc,
302 LPOLESTR lpszDisplayName,
303 DWORD *pchEaten,
304 PIDLIST_RELATIVE *ppidl,
305 DWORD *pdwAttributes)
306 {
307 WCHAR szElement[MAX_PATH];
308 LPCWSTR szNext = NULL;
309 LPITEMIDLIST pidlTemp = NULL;
310 PARSEDURLW urldata;
311 HRESULT hr = S_OK;
312 CLSID clsid;
313
314 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
315 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
316 pchEaten, ppidl, pdwAttributes);
317
318 if (!ppidl)
319 return E_INVALIDARG;
320
321 if (!lpszDisplayName)
322 {
323 *ppidl = NULL;
324 return E_INVALIDARG;
325 }
326
327 *ppidl = NULL;
328
329 if (pchEaten)
330 *pchEaten = 0; /* strange but like the original */
331
332 urldata.cbSize = sizeof(urldata);
333
334 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
335 {
336 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
337 TRACE ("-- element: %s\n", debugstr_w (szElement));
338 CLSIDFromString (szElement + 2, &clsid);
339 pidlTemp = _ILCreateGuid (PT_GUID, clsid);
340 }
341 else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
342 {
343 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
344 pidlTemp = _ILCreateMyComputer ();
345 szNext = lpszDisplayName;
346 }
347 else if (PathIsUNCW(lpszDisplayName))
348 {
349 pidlTemp = _ILCreateNetwork();
350 szNext = lpszDisplayName;
351 }
352 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
353 {
354 *ppidl = pidlTemp;
355 return S_OK;
356 }
357 else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
358 {
359 if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
360 {
361 TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
362 SHCLSIDFromStringW (urldata.pszSuffix + 2, &clsid);
363 pidlTemp = _ILCreateGuid (PT_GUID, clsid);
364 }
365 else
366 return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl);
367 }
368 else
369 {
370 if (*lpszDisplayName)
371 {
372 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
373 hr = m_DesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
374 if (SUCCEEDED(hr))
375 return hr;
376
377 return m_SharedDesktopFSFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
378 }
379 else
380 pidlTemp = _ILCreateMyComputer();
381
382 szNext = NULL;
383 }
384
385 if (SUCCEEDED(hr) && pidlTemp)
386 {
387 if (szNext && *szNext)
388 {
389 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
390 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
391 }
392 else
393 {
394 if (pdwAttributes && *pdwAttributes)
395 hr = SHELL32_GetItemAttributes((IShellFolder *)this,
396 pidlTemp, pdwAttributes);
397 }
398 }
399
400 if (SUCCEEDED(hr))
401 *ppidl = pidlTemp;
402 else
403 *ppidl = NULL;
404
405 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
406
407 return hr;
408 }
409
410 /**************************************************************************
411 * CDesktopFolder::EnumObjects
412 */
413 HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
414 {
415 return ShellObjectCreatorInit<CDesktopFolderEnum>(this, hwndOwner, dwFlags, IID_IEnumIDList, ppEnumIDList);
416 }
417
418 /**************************************************************************
419 * CDesktopFolder::BindToObject
420 */
421 HRESULT WINAPI CDesktopFolder::BindToObject(
422 PCUIDLIST_RELATIVE pidl,
423 LPBC pbcReserved,
424 REFIID riid,
425 LPVOID *ppvOut)
426 {
427 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
428 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
429
430 return SHELL32_BindToChild( pidlRoot, sPathTarget, pidl, riid, ppvOut );
431 }
432
433 /**************************************************************************
434 * CDesktopFolder::BindToStorage
435 */
436 HRESULT WINAPI CDesktopFolder::BindToStorage(
437 PCUIDLIST_RELATIVE pidl,
438 LPBC pbcReserved,
439 REFIID riid,
440 LPVOID *ppvOut)
441 {
442 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
443 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
444
445 *ppvOut = NULL;
446 return E_NOTIMPL;
447 }
448
449 /**************************************************************************
450 * CDesktopFolder::CompareIDs
451 */
452 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
453 {
454 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
455 return SHELL32_CompareIDs ((IShellFolder *)this, lParam, pidl1, pidl2);
456
457 return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2);
458 }
459
460 /**************************************************************************
461 * CDesktopFolder::CreateViewObject
462 */
463 HRESULT WINAPI CDesktopFolder::CreateViewObject(
464 HWND hwndOwner,
465 REFIID riid,
466 LPVOID *ppvOut)
467 {
468 CComPtr<IShellView> pShellView;
469 HRESULT hr = E_INVALIDARG;
470
471 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
472 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
473
474 if (!ppvOut)
475 return hr;
476
477 *ppvOut = NULL;
478
479 if (IsEqualIID (riid, IID_IDropTarget))
480 {
481 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut);
482 }
483 else if (IsEqualIID (riid, IID_IContextMenu))
484 {
485 WARN ("IContextMenu not implemented\n");
486 hr = E_NOTIMPL;
487 }
488 else if (IsEqualIID (riid, IID_IShellView))
489 {
490 hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
491 if (pShellView)
492 hr = pShellView->QueryInterface(riid, ppvOut);
493 }
494 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
495 return hr;
496 }
497
498 /**************************************************************************
499 * CDesktopFolder::GetAttributesOf
500 */
501 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
502 UINT cidl,
503 PCUITEMID_CHILD_ARRAY apidl,
504 DWORD *rgfInOut)
505 {
506 HRESULT hr = S_OK;
507 static const DWORD dwDesktopAttributes =
508 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
509 SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE | SFGAO_CANLINK;
510 static const DWORD dwMyComputerAttributes =
511 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
512 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
513 static DWORD dwMyNetPlacesAttributes =
514 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
515 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
516
517 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
518 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
519
520 if (cidl && !apidl)
521 return E_INVALIDARG;
522
523 if (*rgfInOut == 0)
524 *rgfInOut = ~0;
525
526 if(cidl == 0)
527 *rgfInOut &= dwDesktopAttributes;
528 else
529 {
530 /* TODO: always add SFGAO_CANLINK */
531 for (UINT i = 0; i < cidl; ++i)
532 {
533 pdump(*apidl);
534 if (_ILIsDesktop(*apidl))
535 *rgfInOut &= dwDesktopAttributes;
536 else if (_ILIsMyComputer(apidl[i]))
537 *rgfInOut &= dwMyComputerAttributes;
538 else if (_ILIsNetHood(apidl[i]))
539 *rgfInOut &= dwMyNetPlacesAttributes;
540 else if (_ILIsSpecialFolder(apidl[i]))
541 SHELL32_GetGuidItemAttributes(this, apidl[i], rgfInOut);
542 else if(_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]))
543 SHELL32_GetItemAttributes(this, apidl[i], rgfInOut);
544 else
545 ERR("Got an unknown pidl type!!!\n");
546 }
547 }
548 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
549 *rgfInOut &= ~SFGAO_VALIDATE;
550
551 TRACE("-- result=0x%08x\n", *rgfInOut);
552
553 return hr;
554 }
555
556 /**************************************************************************
557 * CDesktopFolder::GetUIObjectOf
558 *
559 * PARAMETERS
560 * HWND hwndOwner, //[in ] Parent window for any output
561 * UINT cidl, //[in ] array size
562 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
563 * REFIID riid, //[in ] Requested Interface
564 * UINT* prgfInOut, //[ ] reserved
565 * LPVOID* ppvObject) //[out] Resulting Interface
566 *
567 */
568 HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
569 HWND hwndOwner,
570 UINT cidl,
571 PCUITEMID_CHILD_ARRAY apidl,
572 REFIID riid,
573 UINT *prgfInOut,
574 LPVOID *ppvOut)
575 {
576 LPITEMIDLIST pidl;
577 IUnknown *pObj = NULL;
578 HRESULT hr = E_INVALIDARG;
579
580 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
581 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
582
583 if (!ppvOut)
584 return hr;
585
586 *ppvOut = NULL;
587
588 if (IsEqualIID (riid, IID_IContextMenu))
589 {
590 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder *)this, NULL, 0, NULL, (IContextMenu **)&pObj);
591 }
592 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
593 {
594 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
595 }
596 else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
597 {
598 pidl = ILCombine (pidlRoot, apidl[0]);
599 pObj = IExtractIconA_Constructor (pidl);
600 SHFree (pidl);
601 hr = S_OK;
602 }
603 else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
604 {
605 pidl = ILCombine (pidlRoot, apidl[0]);
606 pObj = IExtractIconW_Constructor (pidl);
607 SHFree (pidl);
608 hr = S_OK;
609 }
610 else if (IsEqualIID (riid, IID_IDropTarget))
611 {
612 /* only interested in attempting to bind to shell folders, not files, semicolon intentionate */
613 if (cidl > 1)
614 {
615 hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj);
616 }
617 }
618 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
619 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
620 {
621 pidl = ILCombine (pidlRoot, apidl[0]);
622 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
623 SHFree (pidl);
624 }
625 else
626 hr = E_NOINTERFACE;
627
628 if (SUCCEEDED(hr) && !pObj)
629 hr = E_OUTOFMEMORY;
630
631 *ppvOut = pObj;
632 TRACE ("(%p)->hr=0x%08x\n", this, hr);
633 return hr;
634 }
635
636 /**************************************************************************
637 * CDesktopFolder::GetDisplayNameOf
638 *
639 * NOTES
640 * special case: pidl = null gives desktop-name back
641 */
642 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
643 {
644 HRESULT hr = S_OK;
645 LPWSTR pszPath;
646
647 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
648 pdump (pidl);
649
650 if (!strRet)
651 return E_INVALIDARG;
652
653 if (!_ILIsDesktop(pidl) && _ILIsPidlSimple(pidl) && _ILIsSpecialFolder(pidl))
654 {
655 return SHELL32_GetDisplayNameOfGUIDItem(this, L"", pidl, dwFlags, strRet);
656 }
657
658 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
659 if (!pszPath)
660 return E_OUTOFMEMORY;
661
662 if (_ILIsDesktop (pidl))
663 {
664 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
665 (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
666 wcscpy(pszPath, sPathTarget);
667 else
668 HCR_GetClassNameW(CLSID_ShellDesktop, pszPath, MAX_PATH);
669 }
670 else if (_ILIsPidlSimple (pidl))
671 {
672 int cLen = 0;
673
674 /* file system folder or file rooted at the desktop */
675 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
676 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
677 {
678 lstrcpynW(pszPath, sPathTarget, MAX_PATH - 1);
679 PathAddBackslashW(pszPath);
680 cLen = wcslen(pszPath);
681 }
682
683 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
684 if (!_ILIsFolder(pidl))
685 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
686
687 if (GetFileAttributes(pszPath) == INVALID_FILE_ATTRIBUTES)
688 {
689 /* file system folder or file rooted at the AllUsers desktop */
690 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
691 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
692 {
693 SHGetSpecialFolderPathW(0, pszPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
694 PathAddBackslashW(pszPath);
695 cLen = wcslen(pszPath);
696 }
697
698 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
699 if (!_ILIsFolder(pidl))
700 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
701 }
702 }
703 else
704 {
705 /* a complex pidl, let the subfolder do the work */
706 hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
707 pszPath, MAX_PATH);
708 }
709
710 if (SUCCEEDED(hr))
711 {
712 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
713 if (GetVersion() & 0x80000000)
714 {
715 strRet->uType = STRRET_CSTR;
716 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
717 NULL, NULL))
718 strRet->cStr[0] = '\0';
719 CoTaskMemFree(pszPath);
720 }
721 else
722 {
723 strRet->uType = STRRET_WSTR;
724 strRet->pOleStr = pszPath;
725 }
726 }
727 else
728 CoTaskMemFree(pszPath);
729
730 TRACE ("-- (%p)->(%s,0x%08x)\n", this,
731 strRet->uType == STRRET_CSTR ? strRet->cStr :
732 debugstr_w(strRet->pOleStr), hr);
733 return hr;
734 }
735
736 /**************************************************************************
737 * CDesktopFolder::SetNameOf
738 * Changes the name of a file object or subfolder, possibly changing its item
739 * identifier in the process.
740 *
741 * PARAMETERS
742 * HWND hwndOwner, //[in ] Owner window for output
743 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
744 * LPCOLESTR lpszName, //[in ] the items new display name
745 * DWORD dwFlags, //[in ] SHGNO formatting flags
746 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
747 */
748 HRESULT WINAPI CDesktopFolder::SetNameOf(
749 HWND hwndOwner,
750 PCUITEMID_CHILD pidl, /* simple pidl */
751 LPCOLESTR lpName,
752 DWORD dwFlags,
753 PITEMID_CHILD *pPidlOut)
754 {
755 CComPtr<IShellFolder2> psf;
756 HRESULT hr;
757 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
758 LPWSTR ptr;
759 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
760
761 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
762 debugstr_w (lpName), dwFlags, pPidlOut);
763
764 if (_ILGetGUIDPointer(pidl))
765 {
766 if (SUCCEEDED(BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder2, &psf))))
767 {
768 hr = psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
769 return hr;
770 }
771 }
772
773 /* build source path */
774 lstrcpynW(szSrc, sPathTarget, MAX_PATH);
775 ptr = PathAddBackslashW (szSrc);
776 if (ptr)
777 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
778
779 /* build destination path */
780 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
781 lstrcpynW(szDest, sPathTarget, MAX_PATH);
782 ptr = PathAddBackslashW (szDest);
783 if (ptr)
784 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
785 } else
786 lstrcpynW(szDest, lpName, MAX_PATH);
787
788 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
789 WCHAR *ext = PathFindExtensionW(szSrc);
790 if(*ext != '\0') {
791 INT len = wcslen(szDest);
792 lstrcpynW(szDest + len, ext, MAX_PATH - len);
793 }
794 }
795
796 if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
797 {
798 /* src and destination is the same */
799 hr = S_OK;
800 if (pPidlOut)
801 hr = _ILCreateFromPathW(szDest, pPidlOut);
802
803 return hr;
804 }
805
806 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
807 if (MoveFileW (szSrc, szDest))
808 {
809 hr = S_OK;
810
811 if (pPidlOut)
812 hr = _ILCreateFromPathW(szDest, pPidlOut);
813
814 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
815 SHCNF_PATHW, szSrc, szDest);
816
817 return hr;
818 }
819 return E_FAIL;
820 }
821
822 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
823 {
824 FIXME ("(%p)\n", this);
825 return E_NOTIMPL;
826 }
827
828 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
829 {
830 FIXME ("(%p)\n", this);
831 return E_NOTIMPL;
832 }
833
834 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
835 {
836 TRACE ("(%p)\n", this);
837
838 if (pSort)
839 *pSort = 0;
840 if (pDisplay)
841 *pDisplay = 0;
842
843 return S_OK;
844 }
845
846 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
847 {
848 TRACE ("(%p)\n", this);
849
850 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
851 return E_INVALIDARG;
852
853 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
854
855 return S_OK;
856 }
857
858 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
859 PCUITEMID_CHILD pidl,
860 const SHCOLUMNID *pscid,
861 VARIANT *pv)
862 {
863 FIXME ("(%p)\n", this);
864
865 return E_NOTIMPL;
866 }
867
868 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
869 PCUITEMID_CHILD pidl,
870 UINT iColumn,
871 SHELLDETAILS *psd)
872 {
873 HRESULT hr = S_OK;
874
875 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
876
877 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
878 return E_INVALIDARG;
879
880 if (!pidl)
881 {
882 psd->fmt = DesktopSFHeader[iColumn].fmt;
883 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
884 psd->str.uType = STRRET_CSTR;
885 LoadStringA (shell32_hInstance, DesktopSFHeader[iColumn].colnameid,
886 psd->str.cStr, MAX_PATH);
887 return S_OK;
888 }
889
890 /* the data from the pidl */
891 psd->str.uType = STRRET_CSTR;
892 switch (iColumn)
893 {
894 case 0: /* name */
895 hr = GetDisplayNameOf(pidl,
896 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
897 break;
898 case 1: /* size */
899 _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
900 break;
901 case 2: /* type */
902 _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
903 break;
904 case 3: /* date */
905 _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
906 break;
907 case 4: /* attributes */
908 _ILGetFileAttributes (pidl, psd->str.cStr, MAX_PATH);
909 break;
910 }
911
912 return hr;
913 }
914
915 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
916 {
917 FIXME ("(%p)\n", this);
918 return E_NOTIMPL;
919 }
920
921 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
922 {
923 TRACE ("(%p)\n", this);
924
925 if (!lpClassId)
926 return E_POINTER;
927
928 *lpClassId = CLSID_ShellDesktop;
929
930 return S_OK;
931 }
932
933 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
934 {
935 TRACE ("(%p)->(%p)\n", this, pidl);
936
937 return E_NOTIMPL;
938 }
939
940 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
941 {
942 TRACE ("(%p)->(%p)\n", this, pidl);
943
944 if (!pidl) return E_POINTER;
945 *pidl = ILClone (pidlRoot);
946 return S_OK;
947 }
948
949 HRESULT WINAPI CDesktopFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
950 {
951 CComPtr<ISFHelper> psfHelper;
952 HRESULT hr = m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(ISFHelper, &psfHelper));
953 if (FAILED(hr))
954 return hr;
955
956 return psfHelper->GetUniqueName(pwszName, uLen);
957 }
958
959 HRESULT WINAPI CDesktopFolder::AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut)
960 {
961 CComPtr<ISFHelper> psfHelper;
962 HRESULT hr = m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(ISFHelper, &psfHelper));
963 if (FAILED(hr))
964 return hr;
965
966 return psfHelper->AddFolder(hwnd, pwszName, ppidlOut);
967 }
968
969 HRESULT WINAPI CDesktopFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
970 {
971 return E_NOTIMPL;
972 }
973
974 HRESULT WINAPI CDesktopFolder::CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy)
975 {
976 CComPtr<ISFHelper> psfHelper;
977 HRESULT hr = m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(ISFHelper, &psfHelper));
978 if (FAILED(hr))
979 return hr;
980
981 return psfHelper->CopyItems(pSFFrom, cidl, apidl, bCopy);
982 }
983
984 HRESULT WINAPI CDesktopFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) {
985 HRESULT hr;
986
987 TRACE("CFSFolder::_GetDropTarget entered\n");
988
989 if (_ILGetGUIDPointer (pidl) || _ILIsFolder (pidl))
990 return this->BindToObject(pidl, NULL, IID_IDropTarget, ppvOut);
991
992 LPITEMIDLIST pidlNext = NULL;
993
994 STRRET strFile;
995 hr = this->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strFile);
996 if (SUCCEEDED(hr))
997 {
998 WCHAR wszPath[MAX_PATH];
999 hr = StrRetToBufW(&strFile, pidl, wszPath, _countof(wszPath));
1000
1001 if (SUCCEEDED(hr))
1002 {
1003 PathRemoveFileSpecW (wszPath);
1004 hr = this->ParseDisplayName(NULL, NULL, wszPath, NULL, &pidlNext, NULL);
1005
1006 if (SUCCEEDED(hr))
1007 {
1008 CComPtr<IShellFolder> psf;
1009 hr = this->BindToObject(pidlNext, NULL, IID_PPV_ARG(IShellFolder, &psf));
1010 CoTaskMemFree(pidlNext);
1011 if (SUCCEEDED(hr))
1012 {
1013 hr = psf->GetUIObjectOf(NULL, 1, &pidl, IID_IDropTarget, NULL, ppvOut);
1014 if (FAILED(hr))
1015 ERR("FS GetUIObjectOf failed: %x\n", hr);
1016 }
1017 else
1018 ERR("BindToObject failed: %x\n", hr);
1019 }
1020 else
1021 ERR("ParseDisplayName failed: %x\n", hr);
1022 }
1023 else
1024 ERR("StrRetToBufW failed: %x\n", hr);
1025 }
1026 else
1027 ERR("GetDisplayNameOf failed: %x\n", hr);
1028
1029 return hr;
1030 }
1031
1032 /*************************************************************************
1033 * SHGetDesktopFolder [SHELL32.@]
1034 */
1035 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
1036 {
1037 HRESULT hres = S_OK;
1038 TRACE("\n");
1039
1040 if(!psf) return E_INVALIDARG;
1041 *psf = NULL;
1042 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf));
1043
1044 TRACE("-- %p->(%p)\n",psf, *psf);
1045 return hres;
1046 }