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