[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_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 bool bIsDesktopFolder1, bIsDesktopFolder2;
467
468 if (!pidl1 || !pidl2)
469 {
470 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
471 return E_INVALIDARG;
472 }
473
474 bIsDesktopFolder1 = _ILIsDesktop(pidl1);
475 bIsDesktopFolder2 = _ILIsDesktop(pidl2);
476 if (bIsDesktopFolder1 || bIsDesktopFolder2)
477 return MAKE_COMPARE_HRESULT(bIsDesktopFolder1 - bIsDesktopFolder2);
478
479 if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
480 return SHELL32_CompareGuidItems(this, lParam, pidl1, pidl2);
481
482 return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2);
483 }
484
485 /**************************************************************************
486 * CDesktopFolder::CreateViewObject
487 */
488 HRESULT WINAPI CDesktopFolder::CreateViewObject(
489 HWND hwndOwner,
490 REFIID riid,
491 LPVOID *ppvOut)
492 {
493 CComPtr<IShellView> pShellView;
494 HRESULT hr = E_INVALIDARG;
495
496 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
497 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
498
499 if (!ppvOut)
500 return hr;
501
502 *ppvOut = NULL;
503
504 if (IsEqualIID (riid, IID_IDropTarget))
505 {
506 hr = m_DesktopFSFolder->CreateViewObject(hwndOwner, riid, ppvOut);
507 }
508 else if (IsEqualIID (riid, IID_IContextMenu))
509 {
510 WARN ("IContextMenu not implemented\n");
511 hr = E_NOTIMPL;
512 }
513 else if (IsEqualIID (riid, IID_IShellView))
514 {
515 hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
516 if (pShellView)
517 hr = pShellView->QueryInterface(riid, ppvOut);
518 }
519 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
520 return hr;
521 }
522
523 /**************************************************************************
524 * CDesktopFolder::GetAttributesOf
525 */
526 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
527 UINT cidl,
528 PCUITEMID_CHILD_ARRAY apidl,
529 DWORD *rgfInOut)
530 {
531 HRESULT hr = S_OK;
532
533 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
534 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
535
536 if (cidl && !apidl)
537 return E_INVALIDARG;
538
539 if (*rgfInOut == 0)
540 *rgfInOut = ~0;
541
542 if(cidl == 0)
543 *rgfInOut &= dwDesktopAttributes;
544 else
545 {
546 /* TODO: always add SFGAO_CANLINK */
547 for (UINT i = 0; i < cidl; ++i)
548 {
549 pdump(*apidl);
550 if (_ILIsDesktop(*apidl))
551 *rgfInOut &= dwDesktopAttributes;
552 else if (_ILIsMyComputer(apidl[i]))
553 *rgfInOut &= dwMyComputerAttributes;
554 else if (_ILIsNetHood(apidl[i]))
555 *rgfInOut &= dwMyNetPlacesAttributes;
556 else if (_ILIsSpecialFolder(apidl[i]))
557 SHELL32_GetGuidItemAttributes(this, apidl[i], rgfInOut);
558 else if(_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]))
559 SHELL32_GetFSItemAttributes(this, apidl[i], rgfInOut);
560 else
561 ERR("Got an unknown pidl type!!!\n");
562 }
563 }
564 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
565 *rgfInOut &= ~SFGAO_VALIDATE;
566
567 TRACE("-- result=0x%08x\n", *rgfInOut);
568
569 return hr;
570 }
571
572 /**************************************************************************
573 * CDesktopFolder::GetUIObjectOf
574 *
575 * PARAMETERS
576 * HWND hwndOwner, //[in ] Parent window for any output
577 * UINT cidl, //[in ] array size
578 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
579 * REFIID riid, //[in ] Requested Interface
580 * UINT* prgfInOut, //[ ] reserved
581 * LPVOID* ppvObject) //[out] Resulting Interface
582 *
583 */
584 HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
585 HWND hwndOwner,
586 UINT cidl,
587 PCUITEMID_CHILD_ARRAY apidl,
588 REFIID riid,
589 UINT *prgfInOut,
590 LPVOID *ppvOut)
591 {
592 LPITEMIDLIST pidl;
593 LPVOID pObj = NULL;
594 HRESULT hr = E_INVALIDARG;
595
596 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
597 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
598
599 if (!ppvOut)
600 return hr;
601
602 *ppvOut = NULL;
603
604 if (IsEqualIID (riid, IID_IContextMenu))
605 {
606 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder *)this, NULL, 0, NULL, (IContextMenu **)&pObj);
607 }
608 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
609 {
610 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
611 }
612 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
613 {
614 hr = GenericExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
615 }
616 else if (IsEqualIID (riid, IID_IDropTarget))
617 {
618 /* only interested in attempting to bind to shell folders, not files, semicolon intentionate */
619 if (cidl > 1)
620 {
621 hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj);
622 }
623 }
624 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
625 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
626 {
627 pidl = ILCombine (pidlRoot, apidl[0]);
628 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
629 SHFree (pidl);
630 }
631 else
632 hr = E_NOINTERFACE;
633
634 if (SUCCEEDED(hr) && !pObj)
635 hr = E_OUTOFMEMORY;
636
637 *ppvOut = pObj;
638 TRACE ("(%p)->hr=0x%08x\n", this, hr);
639 return hr;
640 }
641
642 /**************************************************************************
643 * CDesktopFolder::GetDisplayNameOf
644 *
645 * NOTES
646 * special case: pidl = null gives desktop-name back
647 */
648 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
649 {
650 HRESULT hr = S_OK;
651 LPWSTR pszPath;
652
653 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
654 pdump (pidl);
655
656 if (!strRet)
657 return E_INVALIDARG;
658
659 if (!_ILIsPidlSimple (pidl))
660 {
661 return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
662 }
663 else if (!_ILIsDesktop(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
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
714 if (SUCCEEDED(hr))
715 {
716 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
717 if (GetVersion() & 0x80000000)
718 {
719 strRet->uType = STRRET_CSTR;
720 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
721 NULL, NULL))
722 strRet->cStr[0] = '\0';
723 CoTaskMemFree(pszPath);
724 }
725 else
726 {
727 strRet->uType = STRRET_WSTR;
728 strRet->pOleStr = pszPath;
729 }
730 }
731 else
732 CoTaskMemFree(pszPath);
733
734 TRACE ("-- (%p)->(%s,0x%08x)\n", this,
735 strRet->uType == STRRET_CSTR ? strRet->cStr :
736 debugstr_w(strRet->pOleStr), hr);
737 return hr;
738 }
739
740 /**************************************************************************
741 * CDesktopFolder::SetNameOf
742 * Changes the name of a file object or subfolder, possibly changing its item
743 * identifier in the process.
744 *
745 * PARAMETERS
746 * HWND hwndOwner, //[in ] Owner window for output
747 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
748 * LPCOLESTR lpszName, //[in ] the items new display name
749 * DWORD dwFlags, //[in ] SHGNO formatting flags
750 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
751 */
752 HRESULT WINAPI CDesktopFolder::SetNameOf(
753 HWND hwndOwner,
754 PCUITEMID_CHILD pidl, /* simple pidl */
755 LPCOLESTR lpName,
756 DWORD dwFlags,
757 PITEMID_CHILD *pPidlOut)
758 {
759 CComPtr<IShellFolder2> psf;
760 HRESULT hr;
761 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
762 LPWSTR ptr;
763 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
764
765 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
766 debugstr_w (lpName), dwFlags, pPidlOut);
767
768 if (_ILGetGUIDPointer(pidl))
769 return SHELL32_SetNameOfGuidItem(pidl, lpName, dwFlags, pPidlOut);
770
771 /* build source path */
772 lstrcpynW(szSrc, sPathTarget, MAX_PATH);
773 ptr = PathAddBackslashW (szSrc);
774 if (ptr)
775 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
776
777 /* build destination path */
778 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
779 lstrcpynW(szDest, sPathTarget, MAX_PATH);
780 ptr = PathAddBackslashW (szDest);
781 if (ptr)
782 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
783 } else
784 lstrcpynW(szDest, lpName, MAX_PATH);
785
786 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
787 WCHAR *ext = PathFindExtensionW(szSrc);
788 if(*ext != '\0') {
789 INT len = wcslen(szDest);
790 lstrcpynW(szDest + len, ext, MAX_PATH - len);
791 }
792 }
793
794 if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
795 {
796 /* src and destination is the same */
797 hr = S_OK;
798 if (pPidlOut)
799 hr = _ILCreateFromPathW(szDest, pPidlOut);
800
801 return hr;
802 }
803
804 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
805 if (MoveFileW (szSrc, szDest))
806 {
807 hr = S_OK;
808
809 if (pPidlOut)
810 hr = _ILCreateFromPathW(szDest, pPidlOut);
811
812 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
813 SHCNF_PATHW, szSrc, szDest);
814
815 return hr;
816 }
817 return E_FAIL;
818 }
819
820 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
821 {
822 FIXME ("(%p)\n", this);
823 return E_NOTIMPL;
824 }
825
826 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
827 {
828 FIXME ("(%p)\n", this);
829 return E_NOTIMPL;
830 }
831
832 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
833 {
834 TRACE ("(%p)\n", this);
835
836 if (pSort)
837 *pSort = 0;
838 if (pDisplay)
839 *pDisplay = 0;
840
841 return S_OK;
842 }
843
844 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
845 {
846 TRACE ("(%p)\n", this);
847
848 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
849 return E_INVALIDARG;
850
851 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
852
853 return S_OK;
854 }
855
856 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
857 PCUITEMID_CHILD pidl,
858 const SHCOLUMNID *pscid,
859 VARIANT *pv)
860 {
861 FIXME ("(%p)\n", this);
862
863 return E_NOTIMPL;
864 }
865
866 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
867 PCUITEMID_CHILD pidl,
868 UINT iColumn,
869 SHELLDETAILS *psd)
870 {
871 HRESULT hr = S_OK;
872
873 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
874
875 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
876 return E_INVALIDARG;
877
878 if (!pidl)
879 {
880 psd->fmt = DesktopSFHeader[iColumn].fmt;
881 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
882 return SHSetStrRet(&psd->str, DesktopSFHeader[iColumn].colnameid);
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 }