[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 if (_ILIsSpecialFolder(pidl))
450 return SHELL32_BindToGuidItem(pidlRoot, pidl, pbcReserved, riid, ppvOut);
451
452 return SHELL32_BindToFS( pidlRoot, sPathTarget, pidl, riid, ppvOut );
453 }
454
455 /**************************************************************************
456 * CDesktopFolder::BindToStorage
457 */
458 HRESULT WINAPI CDesktopFolder::BindToStorage(
459 PCUIDLIST_RELATIVE pidl,
460 LPBC pbcReserved,
461 REFIID riid,
462 LPVOID *ppvOut)
463 {
464 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
465 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
466
467 *ppvOut = NULL;
468 return E_NOTIMPL;
469 }
470
471 /**************************************************************************
472 * CDesktopFolder::CompareIDs
473 */
474 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
475 {
476 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
477 return SHELL32_CompareIDs ((IShellFolder *)this, lParam, pidl1, pidl2);
478
479 return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2);
480 }
481
482 /**************************************************************************
483 * CDesktopFolder::CreateViewObject
484 */
485 HRESULT WINAPI CDesktopFolder::CreateViewObject(
486 HWND hwndOwner,
487 REFIID riid,
488 LPVOID *ppvOut)
489 {
490 CComPtr<IShellView> pShellView;
491 HRESULT hr = E_INVALIDARG;
492
493 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
494 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
495
496 if (!ppvOut)
497 return hr;
498
499 *ppvOut = NULL;
500
501 if (IsEqualIID (riid, IID_IDropTarget))
502 {
503 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut);
504 }
505 else if (IsEqualIID (riid, IID_IContextMenu))
506 {
507 WARN ("IContextMenu not implemented\n");
508 hr = E_NOTIMPL;
509 }
510 else if (IsEqualIID (riid, IID_IShellView))
511 {
512 hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
513 if (pShellView)
514 hr = pShellView->QueryInterface(riid, ppvOut);
515 }
516 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
517 return hr;
518 }
519
520 /**************************************************************************
521 * CDesktopFolder::GetAttributesOf
522 */
523 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
524 UINT cidl,
525 PCUITEMID_CHILD_ARRAY apidl,
526 DWORD *rgfInOut)
527 {
528 HRESULT hr = S_OK;
529
530 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
531 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
532
533 if (cidl && !apidl)
534 return E_INVALIDARG;
535
536 if (*rgfInOut == 0)
537 *rgfInOut = ~0;
538
539 if(cidl == 0)
540 *rgfInOut &= dwDesktopAttributes;
541 else
542 {
543 /* TODO: always add SFGAO_CANLINK */
544 for (UINT i = 0; i < cidl; ++i)
545 {
546 pdump(*apidl);
547 if (_ILIsDesktop(*apidl))
548 *rgfInOut &= dwDesktopAttributes;
549 else if (_ILIsMyComputer(apidl[i]))
550 *rgfInOut &= dwMyComputerAttributes;
551 else if (_ILIsNetHood(apidl[i]))
552 *rgfInOut &= dwMyNetPlacesAttributes;
553 else if (_ILIsSpecialFolder(apidl[i]))
554 SHELL32_GetGuidItemAttributes(this, apidl[i], rgfInOut);
555 else if(_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]))
556 SHELL32_GetFSItemAttributes(this, apidl[i], rgfInOut);
557 else
558 ERR("Got an unknown pidl type!!!\n");
559 }
560 }
561 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
562 *rgfInOut &= ~SFGAO_VALIDATE;
563
564 TRACE("-- result=0x%08x\n", *rgfInOut);
565
566 return hr;
567 }
568
569 /**************************************************************************
570 * CDesktopFolder::GetUIObjectOf
571 *
572 * PARAMETERS
573 * HWND hwndOwner, //[in ] Parent window for any output
574 * UINT cidl, //[in ] array size
575 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
576 * REFIID riid, //[in ] Requested Interface
577 * UINT* prgfInOut, //[ ] reserved
578 * LPVOID* ppvObject) //[out] Resulting Interface
579 *
580 */
581 HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
582 HWND hwndOwner,
583 UINT cidl,
584 PCUITEMID_CHILD_ARRAY apidl,
585 REFIID riid,
586 UINT *prgfInOut,
587 LPVOID *ppvOut)
588 {
589 LPITEMIDLIST pidl;
590 IUnknown *pObj = NULL;
591 HRESULT hr = E_INVALIDARG;
592
593 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
594 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
595
596 if (!ppvOut)
597 return hr;
598
599 *ppvOut = NULL;
600
601 if (IsEqualIID (riid, IID_IContextMenu))
602 {
603 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder *)this, NULL, 0, NULL, (IContextMenu **)&pObj);
604 }
605 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
606 {
607 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
608 }
609 else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
610 {
611 pidl = ILCombine (pidlRoot, apidl[0]);
612 pObj = IExtractIconA_Constructor (pidl);
613 SHFree (pidl);
614 hr = S_OK;
615 }
616 else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
617 {
618 pidl = ILCombine (pidlRoot, apidl[0]);
619 pObj = IExtractIconW_Constructor (pidl);
620 SHFree (pidl);
621 hr = S_OK;
622 }
623 else if (IsEqualIID (riid, IID_IDropTarget))
624 {
625 /* only interested in attempting to bind to shell folders, not files, semicolon intentionate */
626 if (cidl > 1)
627 {
628 hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj);
629 }
630 }
631 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
632 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
633 {
634 pidl = ILCombine (pidlRoot, apidl[0]);
635 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
636 SHFree (pidl);
637 }
638 else
639 hr = E_NOINTERFACE;
640
641 if (SUCCEEDED(hr) && !pObj)
642 hr = E_OUTOFMEMORY;
643
644 *ppvOut = pObj;
645 TRACE ("(%p)->hr=0x%08x\n", this, hr);
646 return hr;
647 }
648
649 /**************************************************************************
650 * CDesktopFolder::GetDisplayNameOf
651 *
652 * NOTES
653 * special case: pidl = null gives desktop-name back
654 */
655 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
656 {
657 HRESULT hr = S_OK;
658 LPWSTR pszPath;
659
660 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
661 pdump (pidl);
662
663 if (!strRet)
664 return E_INVALIDARG;
665
666 if (!_ILIsPidlSimple (pidl))
667 {
668 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
669 }
670 else if (!_ILIsDesktop(pidl) && _ILIsSpecialFolder(pidl))
671 {
672 return SHELL32_GetDisplayNameOfGUIDItem(this, L"", pidl, dwFlags, strRet);
673 }
674
675 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
676 if (!pszPath)
677 return E_OUTOFMEMORY;
678
679 if (_ILIsDesktop (pidl))
680 {
681 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
682 (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
683 wcscpy(pszPath, sPathTarget);
684 else
685 HCR_GetClassNameW(CLSID_ShellDesktop, pszPath, MAX_PATH);
686 }
687 else
688 {
689 int cLen = 0;
690
691 /* file system folder or file rooted at the desktop */
692 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
693 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
694 {
695 lstrcpynW(pszPath, sPathTarget, MAX_PATH - 1);
696 PathAddBackslashW(pszPath);
697 cLen = wcslen(pszPath);
698 }
699
700 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
701 if (!_ILIsFolder(pidl))
702 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
703
704 if (GetFileAttributes(pszPath) == INVALID_FILE_ATTRIBUTES)
705 {
706 /* file system folder or file rooted at the AllUsers desktop */
707 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
708 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
709 {
710 SHGetSpecialFolderPathW(0, pszPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
711 PathAddBackslashW(pszPath);
712 cLen = wcslen(pszPath);
713 }
714
715 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
716 if (!_ILIsFolder(pidl))
717 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
718 }
719 }
720
721 if (SUCCEEDED(hr))
722 {
723 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
724 if (GetVersion() & 0x80000000)
725 {
726 strRet->uType = STRRET_CSTR;
727 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
728 NULL, NULL))
729 strRet->cStr[0] = '\0';
730 CoTaskMemFree(pszPath);
731 }
732 else
733 {
734 strRet->uType = STRRET_WSTR;
735 strRet->pOleStr = pszPath;
736 }
737 }
738 else
739 CoTaskMemFree(pszPath);
740
741 TRACE ("-- (%p)->(%s,0x%08x)\n", this,
742 strRet->uType == STRRET_CSTR ? strRet->cStr :
743 debugstr_w(strRet->pOleStr), hr);
744 return hr;
745 }
746
747 /**************************************************************************
748 * CDesktopFolder::SetNameOf
749 * Changes the name of a file object or subfolder, possibly changing its item
750 * identifier in the process.
751 *
752 * PARAMETERS
753 * HWND hwndOwner, //[in ] Owner window for output
754 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
755 * LPCOLESTR lpszName, //[in ] the items new display name
756 * DWORD dwFlags, //[in ] SHGNO formatting flags
757 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
758 */
759 HRESULT WINAPI CDesktopFolder::SetNameOf(
760 HWND hwndOwner,
761 PCUITEMID_CHILD pidl, /* simple pidl */
762 LPCOLESTR lpName,
763 DWORD dwFlags,
764 PITEMID_CHILD *pPidlOut)
765 {
766 CComPtr<IShellFolder2> psf;
767 HRESULT hr;
768 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
769 LPWSTR ptr;
770 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
771
772 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
773 debugstr_w (lpName), dwFlags, pPidlOut);
774
775 if (_ILGetGUIDPointer(pidl))
776 {
777 if (SUCCEEDED(BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder2, &psf))))
778 {
779 hr = psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
780 return hr;
781 }
782 }
783
784 /* build source path */
785 lstrcpynW(szSrc, sPathTarget, MAX_PATH);
786 ptr = PathAddBackslashW (szSrc);
787 if (ptr)
788 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
789
790 /* build destination path */
791 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
792 lstrcpynW(szDest, sPathTarget, MAX_PATH);
793 ptr = PathAddBackslashW (szDest);
794 if (ptr)
795 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
796 } else
797 lstrcpynW(szDest, lpName, MAX_PATH);
798
799 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
800 WCHAR *ext = PathFindExtensionW(szSrc);
801 if(*ext != '\0') {
802 INT len = wcslen(szDest);
803 lstrcpynW(szDest + len, ext, MAX_PATH - len);
804 }
805 }
806
807 if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
808 {
809 /* src and destination is the same */
810 hr = S_OK;
811 if (pPidlOut)
812 hr = _ILCreateFromPathW(szDest, pPidlOut);
813
814 return hr;
815 }
816
817 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
818 if (MoveFileW (szSrc, szDest))
819 {
820 hr = S_OK;
821
822 if (pPidlOut)
823 hr = _ILCreateFromPathW(szDest, pPidlOut);
824
825 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
826 SHCNF_PATHW, szSrc, szDest);
827
828 return hr;
829 }
830 return E_FAIL;
831 }
832
833 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
834 {
835 FIXME ("(%p)\n", this);
836 return E_NOTIMPL;
837 }
838
839 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
840 {
841 FIXME ("(%p)\n", this);
842 return E_NOTIMPL;
843 }
844
845 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
846 {
847 TRACE ("(%p)\n", this);
848
849 if (pSort)
850 *pSort = 0;
851 if (pDisplay)
852 *pDisplay = 0;
853
854 return S_OK;
855 }
856
857 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
858 {
859 TRACE ("(%p)\n", this);
860
861 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
862 return E_INVALIDARG;
863
864 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
865
866 return S_OK;
867 }
868
869 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
870 PCUITEMID_CHILD pidl,
871 const SHCOLUMNID *pscid,
872 VARIANT *pv)
873 {
874 FIXME ("(%p)\n", this);
875
876 return E_NOTIMPL;
877 }
878
879 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
880 PCUITEMID_CHILD pidl,
881 UINT iColumn,
882 SHELLDETAILS *psd)
883 {
884 HRESULT hr = S_OK;
885
886 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
887
888 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
889 return E_INVALIDARG;
890
891 if (!pidl)
892 {
893 psd->fmt = DesktopSFHeader[iColumn].fmt;
894 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
895 psd->str.uType = STRRET_CSTR;
896 LoadStringA (shell32_hInstance, DesktopSFHeader[iColumn].colnameid,
897 psd->str.cStr, MAX_PATH);
898 return S_OK;
899 }
900
901 /* the data from the pidl */
902 psd->str.uType = STRRET_CSTR;
903 switch (iColumn)
904 {
905 case 0: /* name */
906 hr = GetDisplayNameOf(pidl,
907 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
908 break;
909 case 1: /* size */
910 _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
911 break;
912 case 2: /* type */
913 _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
914 break;
915 case 3: /* date */
916 _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
917 break;
918 case 4: /* attributes */
919 _ILGetFileAttributes (pidl, psd->str.cStr, MAX_PATH);
920 break;
921 }
922
923 return hr;
924 }
925
926 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
927 {
928 FIXME ("(%p)\n", this);
929 return E_NOTIMPL;
930 }
931
932 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
933 {
934 TRACE ("(%p)\n", this);
935
936 if (!lpClassId)
937 return E_POINTER;
938
939 *lpClassId = CLSID_ShellDesktop;
940
941 return S_OK;
942 }
943
944 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
945 {
946 TRACE ("(%p)->(%p)\n", this, pidl);
947
948 return E_NOTIMPL;
949 }
950
951 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
952 {
953 TRACE ("(%p)->(%p)\n", this, pidl);
954
955 if (!pidl) return E_POINTER;
956 *pidl = ILClone (pidlRoot);
957 return S_OK;
958 }
959
960 HRESULT WINAPI CDesktopFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
961 {
962 CComPtr<ISFHelper> psfHelper;
963 HRESULT hr = m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(ISFHelper, &psfHelper));
964 if (FAILED(hr))
965 return hr;
966
967 return psfHelper->GetUniqueName(pwszName, uLen);
968 }
969
970 HRESULT WINAPI CDesktopFolder::AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut)
971 {
972 CComPtr<ISFHelper> psfHelper;
973 HRESULT hr = m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(ISFHelper, &psfHelper));
974 if (FAILED(hr))
975 return hr;
976
977 return psfHelper->AddFolder(hwnd, pwszName, ppidlOut);
978 }
979
980 HRESULT WINAPI CDesktopFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
981 {
982 return E_NOTIMPL;
983 }
984
985 HRESULT WINAPI CDesktopFolder::CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy)
986 {
987 CComPtr<ISFHelper> psfHelper;
988 HRESULT hr = m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(ISFHelper, &psfHelper));
989 if (FAILED(hr))
990 return hr;
991
992 return psfHelper->CopyItems(pSFFrom, cidl, apidl, bCopy);
993 }
994
995 HRESULT WINAPI CDesktopFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) {
996 HRESULT hr;
997
998 TRACE("CFSFolder::_GetDropTarget entered\n");
999
1000 if (_ILGetGUIDPointer (pidl) || _ILIsFolder (pidl))
1001 return this->BindToObject(pidl, NULL, IID_IDropTarget, ppvOut);
1002
1003 LPITEMIDLIST pidlNext = NULL;
1004
1005 STRRET strFile;
1006 hr = this->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strFile);
1007 if (SUCCEEDED(hr))
1008 {
1009 WCHAR wszPath[MAX_PATH];
1010 hr = StrRetToBufW(&strFile, pidl, wszPath, _countof(wszPath));
1011
1012 if (SUCCEEDED(hr))
1013 {
1014 PathRemoveFileSpecW (wszPath);
1015 hr = this->ParseDisplayName(NULL, NULL, wszPath, NULL, &pidlNext, NULL);
1016
1017 if (SUCCEEDED(hr))
1018 {
1019 CComPtr<IShellFolder> psf;
1020 hr = this->BindToObject(pidlNext, NULL, IID_PPV_ARG(IShellFolder, &psf));
1021 CoTaskMemFree(pidlNext);
1022 if (SUCCEEDED(hr))
1023 {
1024 hr = psf->GetUIObjectOf(NULL, 1, &pidl, IID_IDropTarget, NULL, ppvOut);
1025 if (FAILED(hr))
1026 ERR("FS GetUIObjectOf failed: %x\n", hr);
1027 }
1028 else
1029 ERR("BindToObject failed: %x\n", hr);
1030 }
1031 else
1032 ERR("ParseDisplayName failed: %x\n", hr);
1033 }
1034 else
1035 ERR("StrRetToBufW failed: %x\n", hr);
1036 }
1037 else
1038 ERR("GetDisplayNameOf failed: %x\n", hr);
1039
1040 return hr;
1041 }
1042
1043 /*************************************************************************
1044 * SHGetDesktopFolder [SHELL32.@]
1045 */
1046 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
1047 {
1048 HRESULT hres = S_OK;
1049 TRACE("\n");
1050
1051 if(!psf) return E_INVALIDARG;
1052 *psf = NULL;
1053 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf));
1054
1055 TRACE("-- %p->(%p)\n",psf, *psf);
1056 return hres;
1057 }