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