Merge r68232 to get Windows' rpcrt4.dll to work under ReactOS.
[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 /***********************************************************************
48 * Desktopfolder implementation
49 */
50
51 class CDesktopFolder;
52
53 class CDesktopFolderEnum :
54 public CEnumIDListBase
55 {
56 private:
57 // CComPtr fDesktopEnumerator;
58 // CComPtr fCommonDesktopEnumerator;
59 public:
60 CDesktopFolderEnum();
61 ~CDesktopFolderEnum();
62 HRESULT WINAPI Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags);
63
64 BEGIN_COM_MAP(CDesktopFolderEnum)
65 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
66 END_COM_MAP()
67 };
68
69 int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll);
70
71 static const shvheader DesktopSFHeader[] = {
72 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
73 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
74 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
75 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
76 {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
77 };
78
79 #define DESKTOPSHELLVIEWCOLUMNS 5
80
81 CDesktopFolderEnum::CDesktopFolderEnum()
82 {
83 }
84
85 CDesktopFolderEnum::~CDesktopFolderEnum()
86 {
87 }
88
89 static const WCHAR ClassicStartMenuW[] = L"SOFTWARE\\Microsoft\\Windows\\"
90 L"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu";
91
92 static INT
93 IsNamespaceExtensionHidden(const WCHAR *iid)
94 {
95 DWORD Result, dwResult;
96 dwResult = sizeof(DWORD);
97
98 if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */
99 ClassicStartMenuW,
100 iid,
101 RRF_RT_DWORD,
102 NULL,
103 &Result,
104 &dwResult) != ERROR_SUCCESS)
105 {
106 return -1;
107 }
108
109 return Result;
110 }
111
112 static VOID
113 SetNamespaceExtensionVisibleStatus(const WCHAR * iid, DWORD dwStatus)
114 {
115 HKEY hKey;
116
117 if (RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
118 {
119 RegSetValueExW(hKey, iid, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(DWORD));
120 RegCloseKey(hKey);
121 }
122 }
123
124 /**************************************************************************
125 * CreateDesktopEnumList()
126 */
127
128 HRESULT WINAPI CDesktopFolderEnum::Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags)
129 {
130 BOOL ret = TRUE;
131 WCHAR szPath[MAX_PATH];
132
133 static const WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}";
134 static const WCHAR Desktop_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\Namespace";
135
136 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
137
138 /* enumerate the root folders */
139 if (dwFlags & SHCONTF_FOLDERS)
140 {
141 HKEY hkey;
142 UINT i;
143 DWORD dwResult;
144
145 /* create the pidl for This item */
146 if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1)
147 {
148 ret = AddToEnumList(_ILCreateMyDocuments());
149 }
150 ret = AddToEnumList(_ILCreateMyComputer());
151
152 for (i = 0; i < 2; i++)
153 {
154 if (i == 0)
155 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
156 else
157 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
158
159 if (dwResult == ERROR_SUCCESS)
160 {
161 WCHAR iid[50];
162 LPITEMIDLIST pidl;
163 int i = 0;
164
165 while (ret)
166 {
167 DWORD size;
168 LONG r;
169
170 size = sizeof (iid) / sizeof (iid[0]);
171 r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
172 if (ERROR_SUCCESS == r)
173 {
174 if (IsNamespaceExtensionHidden(iid) < 1)
175 {
176 pidl = _ILCreateGuidFromStrW(iid);
177 if (pidl != NULL)
178 {
179 if (!HasItemWithCLSID(pidl))
180 {
181 ret = AddToEnumList(pidl);
182 }
183 else
184 {
185 SHFree(pidl);
186 }
187 }
188 }
189 }
190 else if (ERROR_NO_MORE_ITEMS == r)
191 break;
192 else
193 ret = FALSE;
194 i++;
195 }
196 RegCloseKey(hkey);
197 }
198 }
199 for (i = 0; i < 2; i++)
200 {
201 if (i == 0)
202 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, ClassicStartMenuW, 0, KEY_READ, &hkey);
203 else
204 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_READ, &hkey);
205
206 if (dwResult == ERROR_SUCCESS)
207 {
208 DWORD j = 0, dwVal, Val, dwType, dwIID;
209 LONG r;
210 WCHAR iid[50];
211
212 while(ret)
213 {
214 dwVal = sizeof(Val);
215 dwIID = sizeof(iid) / sizeof(WCHAR);
216
217 r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal);
218 if (r == ERROR_SUCCESS)
219 {
220 if (Val == 0 && dwType == REG_DWORD)
221 {
222 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(iid);
223 if (pidl != NULL)
224 {
225 if (!HasItemWithCLSID(pidl))
226 {
227 AddToEnumList(pidl);
228 }
229 else
230 {
231 SHFree(pidl);
232 }
233 }
234 }
235 }
236 else if (ERROR_NO_MORE_ITEMS == r)
237 break;
238 else
239 ret = FALSE;
240 }
241 RegCloseKey(hkey);
242 }
243
244 }
245 }
246
247 /* enumerate the elements in %windir%\desktop */
248 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
249 ret = ret && CreateFolderEnumList(szPath, dwFlags);
250
251 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
252 ret = ret && CreateFolderEnumList(szPath, dwFlags);
253
254 return ret ? S_OK : E_FAIL;
255 }
256
257 void CDesktopFolder::SF_RegisterClipFmt()
258 {
259 TRACE ("(%p)\n", this);
260
261 if (!cfShellIDList)
262 cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
263 }
264
265 CDesktopFolder::CDesktopFolder()
266 {
267 pidlRoot = NULL;
268 sPathTarget = NULL;
269 cfShellIDList = 0;
270 SF_RegisterClipFmt();
271 fAcceptFmt = FALSE;
272 }
273
274 CDesktopFolder::~CDesktopFolder()
275 {
276 }
277
278 HRESULT WINAPI CDesktopFolder::FinalConstruct()
279 {
280 WCHAR szMyPath[MAX_PATH];
281
282 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
283 return E_UNEXPECTED;
284
285 pidlRoot = _ILCreateDesktop(); /* my qualified pidl */
286 sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
287 wcscpy(sPathTarget, szMyPath);
288 return S_OK;
289 }
290
291 /**************************************************************************
292 * CDesktopFolder::ParseDisplayName
293 *
294 * NOTES
295 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
296 * to MyComputer
297 */
298 HRESULT WINAPI CDesktopFolder::ParseDisplayName(
299 HWND hwndOwner,
300 LPBC pbc,
301 LPOLESTR lpszDisplayName,
302 DWORD *pchEaten,
303 PIDLIST_RELATIVE *ppidl,
304 DWORD *pdwAttributes)
305 {
306 WCHAR szElement[MAX_PATH];
307 LPCWSTR szNext = NULL;
308 LPITEMIDLIST pidlTemp = NULL;
309 PARSEDURLW urldata;
310 HRESULT hr = S_OK;
311 CLSID clsid;
312
313 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
314 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
315 pchEaten, ppidl, pdwAttributes);
316
317 if (!ppidl)
318 return E_INVALIDARG;
319
320 if (!lpszDisplayName)
321 {
322 *ppidl = NULL;
323 return E_INVALIDARG;
324 }
325
326 *ppidl = NULL;
327
328 if (pchEaten)
329 *pchEaten = 0; /* strange but like the original */
330
331 urldata.cbSize = sizeof(urldata);
332
333 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
334 {
335 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
336 TRACE ("-- element: %s\n", debugstr_w (szElement));
337 CLSIDFromString (szElement + 2, &clsid);
338 pidlTemp = _ILCreateGuid (PT_GUID, clsid);
339 }
340 else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
341 {
342 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
343 pidlTemp = _ILCreateMyComputer ();
344 szNext = lpszDisplayName;
345 }
346 else if (PathIsUNCW(lpszDisplayName))
347 {
348 pidlTemp = _ILCreateNetwork();
349 szNext = lpszDisplayName;
350 }
351 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
352 {
353 *ppidl = pidlTemp;
354 return S_OK;
355 }
356 else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
357 {
358 if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
359 {
360 TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
361 SHCLSIDFromStringW (urldata.pszSuffix + 2, &clsid);
362 pidlTemp = _ILCreateGuid (PT_GUID, clsid);
363 }
364 else
365 return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl);
366 }
367 else
368 {
369 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
370
371 if (*lpszDisplayName)
372 {
373 WCHAR szPath[MAX_PATH];
374 LPWSTR pathPtr;
375
376 /* build a complete path to create a simple pidl */
377 lstrcpynW(szPath, sPathTarget, MAX_PATH);
378 pathPtr = PathAddBackslashW(szPath);
379 if (pathPtr)
380 {
381 lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
382 hr = _ILCreateFromPathW(szPath, &pidlTemp);
383 }
384 else
385 {
386 /* should never reach here, but for completeness */
387 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
388 }
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 hr = SHELL32_GetItemAttributes((IShellFolder *)this,
407 pidlTemp, pdwAttributes);
408 }
409 }
410
411 if (SUCCEEDED(hr))
412 *ppidl = pidlTemp;
413 else
414 *ppidl = NULL;
415
416 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
417
418 return hr;
419 }
420
421 /**************************************************************************
422 * CDesktopFolder::EnumObjects
423 */
424 HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
425 {
426 return ShellObjectCreatorInit<CDesktopFolderEnum>(this, hwndOwner, dwFlags, IID_IEnumIDList, ppEnumIDList);
427 }
428
429 /**************************************************************************
430 * CDesktopFolder::BindToObject
431 */
432 HRESULT WINAPI CDesktopFolder::BindToObject(
433 PCUIDLIST_RELATIVE pidl,
434 LPBC pbcReserved,
435 REFIID riid,
436 LPVOID *ppvOut)
437 {
438 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
439 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
440
441 return SHELL32_BindToChild( pidlRoot, sPathTarget, pidl, riid, ppvOut );
442 }
443
444 /**************************************************************************
445 * CDesktopFolder::BindToStorage
446 */
447 HRESULT WINAPI CDesktopFolder::BindToStorage(
448 PCUIDLIST_RELATIVE pidl,
449 LPBC pbcReserved,
450 REFIID riid,
451 LPVOID *ppvOut)
452 {
453 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
454 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
455
456 *ppvOut = NULL;
457 return E_NOTIMPL;
458 }
459
460 /**************************************************************************
461 * CDesktopFolder::CompareIDs
462 */
463 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
464 {
465 int nReturn;
466
467 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
468 nReturn = SHELL32_CompareIDs ((IShellFolder *)this, lParam, pidl1, pidl2);
469 TRACE ("-- %i\n", nReturn);
470 return nReturn;
471 }
472
473 /**************************************************************************
474 * CDesktopFolder::CreateViewObject
475 */
476 HRESULT WINAPI CDesktopFolder::CreateViewObject(
477 HWND hwndOwner,
478 REFIID riid,
479 LPVOID *ppvOut)
480 {
481 CComPtr<IShellView> pShellView;
482 HRESULT hr = E_INVALIDARG;
483
484 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
485 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
486
487 if (!ppvOut)
488 return hr;
489
490 *ppvOut = NULL;
491
492 if (IsEqualIID (riid, IID_IDropTarget))
493 {
494 hr = this->QueryInterface (IID_IDropTarget, ppvOut);
495 }
496 else if (IsEqualIID (riid, IID_IContextMenu))
497 {
498 WARN ("IContextMenu not implemented\n");
499 hr = E_NOTIMPL;
500 }
501 else if (IsEqualIID (riid, IID_IShellView))
502 {
503 hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
504 if (pShellView)
505 hr = pShellView->QueryInterface(riid, ppvOut);
506 }
507 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
508 return hr;
509 }
510
511 /**************************************************************************
512 * CDesktopFolder::GetAttributesOf
513 */
514 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
515 UINT cidl,
516 PCUITEMID_CHILD_ARRAY apidl,
517 DWORD *rgfInOut)
518 {
519 HRESULT hr = S_OK;
520 static const DWORD dwDesktopAttributes =
521 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
522 SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE | SFGAO_CANLINK;
523 static const DWORD dwMyComputerAttributes =
524 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
525 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
526 static DWORD dwMyNetPlacesAttributes =
527 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
528 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
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_GetItemAttributes(this, apidl[i], rgfInOut);
555 else if(_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]))
556 SHELL32_GetItemAttributes(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 || FAILED(hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj)))
627 {
628 IDropTarget * pDt = NULL;
629 hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
630 pObj = pDt;
631 }
632 }
633 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
634 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
635 {
636 pidl = ILCombine (pidlRoot, apidl[0]);
637 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
638 SHFree (pidl);
639 }
640 else
641 hr = E_NOINTERFACE;
642
643 if (SUCCEEDED(hr) && !pObj)
644 hr = E_OUTOFMEMORY;
645
646 *ppvOut = pObj;
647 TRACE ("(%p)->hr=0x%08x\n", this, hr);
648 return hr;
649 }
650
651 /**************************************************************************
652 * CDesktopFolder::GetDisplayNameOf
653 *
654 * NOTES
655 * special case: pidl = null gives desktop-name back
656 */
657 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
658 {
659 HRESULT hr = S_OK;
660 LPWSTR pszPath;
661
662 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
663 pdump (pidl);
664
665 if (!strRet)
666 return E_INVALIDARG;
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 GUID const *clsid;
683
684 if ((clsid = _ILGetGUIDPointer (pidl)))
685 {
686 if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
687 {
688 int bWantsForParsing;
689
690 /*
691 * We can only get a filesystem path from a shellfolder if the
692 * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
693 *
694 * Exception: The MyComputer folder doesn't have this key,
695 * but any other filesystem backed folder it needs it.
696 */
697 if (IsEqualIID (*clsid, CLSID_MyComputer))
698 {
699 bWantsForParsing = TRUE;
700 }
701 else
702 {
703 /* get the "WantsFORPARSING" flag from the registry */
704 static const WCHAR clsidW[] =
705 { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
706 static const WCHAR shellfolderW[] =
707 { '\\', 's', 'h', 'e', 'l', 'l', 'f', 'o', 'l', 'd', 'e', 'r', 0 };
708 static const WCHAR wantsForParsingW[] =
709 { 'W', 'a', 'n', 't', 's', 'F', 'o', 'r', 'P', 'a', 'r', 's', 'i', 'n',
710 'g', 0
711 };
712 WCHAR szRegPath[100];
713 LONG r;
714
715 wcscpy (szRegPath, clsidW);
716 SHELL32_GUIDToStringW (*clsid, &szRegPath[6]);
717 wcscat (szRegPath, shellfolderW);
718 r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
719 wantsForParsingW, NULL, NULL, NULL);
720 if (r == ERROR_SUCCESS)
721 bWantsForParsing = TRUE;
722 else
723 bWantsForParsing = FALSE;
724 }
725
726 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
727 bWantsForParsing)
728 {
729 /*
730 * we need the filesystem path to the destination folder.
731 * Only the folder itself can know it
732 */
733 hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
734 pszPath,
735 MAX_PATH);
736 }
737 else
738 {
739 /* parsing name like ::{...} */
740 pszPath[0] = ':';
741 pszPath[1] = ':';
742 SHELL32_GUIDToStringW (*clsid, &pszPath[2]);
743 }
744 }
745 else
746 {
747 /* user friendly name */
748 HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
749 }
750 }
751 else
752 {
753 int cLen = 0;
754
755 /* file system folder or file rooted at the desktop */
756 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
757 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
758 {
759 lstrcpynW(pszPath, sPathTarget, MAX_PATH - 1);
760 PathAddBackslashW(pszPath);
761 cLen = wcslen(pszPath);
762 }
763
764 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
765 if (!_ILIsFolder(pidl))
766 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
767
768 if (GetFileAttributes(pszPath) == INVALID_FILE_ATTRIBUTES)
769 {
770 /* file system folder or file rooted at the AllUsers desktop */
771 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
772 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
773 {
774 SHGetSpecialFolderPathW(0, pszPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
775 PathAddBackslashW(pszPath);
776 cLen = wcslen(pszPath);
777 }
778
779 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
780 if (!_ILIsFolder(pidl))
781 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
782 }
783 }
784 }
785 else
786 {
787 /* a complex pidl, let the subfolder do the work */
788 hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
789 pszPath, MAX_PATH);
790 }
791
792 if (SUCCEEDED(hr))
793 {
794 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
795 if (GetVersion() & 0x80000000)
796 {
797 strRet->uType = STRRET_CSTR;
798 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
799 NULL, NULL))
800 strRet->cStr[0] = '\0';
801 CoTaskMemFree(pszPath);
802 }
803 else
804 {
805 strRet->uType = STRRET_WSTR;
806 strRet->pOleStr = pszPath;
807 }
808 }
809 else
810 CoTaskMemFree(pszPath);
811
812 TRACE ("-- (%p)->(%s,0x%08x)\n", this,
813 strRet->uType == STRRET_CSTR ? strRet->cStr :
814 debugstr_w(strRet->pOleStr), hr);
815 return hr;
816 }
817
818 /**************************************************************************
819 * CDesktopFolder::SetNameOf
820 * Changes the name of a file object or subfolder, possibly changing its item
821 * identifier in the process.
822 *
823 * PARAMETERS
824 * HWND hwndOwner, //[in ] Owner window for output
825 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
826 * LPCOLESTR lpszName, //[in ] the items new display name
827 * DWORD dwFlags, //[in ] SHGNO formatting flags
828 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
829 */
830 HRESULT WINAPI CDesktopFolder::SetNameOf(
831 HWND hwndOwner,
832 PCUITEMID_CHILD pidl, /* simple pidl */
833 LPCOLESTR lpName,
834 DWORD dwFlags,
835 PITEMID_CHILD *pPidlOut)
836 {
837 CComPtr<IShellFolder2> psf;
838 HRESULT hr;
839 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
840 LPWSTR ptr;
841 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
842
843 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
844 debugstr_w (lpName), dwFlags, pPidlOut);
845
846 if (_ILGetGUIDPointer(pidl))
847 {
848 if (SUCCEEDED(BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder2, &psf))))
849 {
850 hr = psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
851 return hr;
852 }
853 }
854
855 /* build source path */
856 lstrcpynW(szSrc, sPathTarget, MAX_PATH);
857 ptr = PathAddBackslashW (szSrc);
858 if (ptr)
859 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
860
861 /* build destination path */
862 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
863 lstrcpynW(szDest, sPathTarget, MAX_PATH);
864 ptr = PathAddBackslashW (szDest);
865 if (ptr)
866 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
867 } else
868 lstrcpynW(szDest, lpName, MAX_PATH);
869
870 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
871 WCHAR *ext = PathFindExtensionW(szSrc);
872 if(*ext != '\0') {
873 INT len = wcslen(szDest);
874 lstrcpynW(szDest + len, ext, MAX_PATH - len);
875 }
876 }
877
878 if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
879 {
880 /* src and destination is the same */
881 hr = S_OK;
882 if (pPidlOut)
883 hr = _ILCreateFromPathW(szDest, pPidlOut);
884
885 return hr;
886 }
887
888 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
889 if (MoveFileW (szSrc, szDest))
890 {
891 hr = S_OK;
892
893 if (pPidlOut)
894 hr = _ILCreateFromPathW(szDest, pPidlOut);
895
896 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
897 SHCNF_PATHW, szSrc, szDest);
898
899 return hr;
900 }
901 return E_FAIL;
902 }
903
904 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
905 {
906 FIXME ("(%p)\n", this);
907 return E_NOTIMPL;
908 }
909
910 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
911 {
912 FIXME ("(%p)\n", this);
913 return E_NOTIMPL;
914 }
915
916 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
917 {
918 TRACE ("(%p)\n", this);
919
920 if (pSort)
921 *pSort = 0;
922 if (pDisplay)
923 *pDisplay = 0;
924
925 return S_OK;
926 }
927
928 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
929 {
930 TRACE ("(%p)\n", this);
931
932 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
933 return E_INVALIDARG;
934
935 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
936
937 return S_OK;
938 }
939
940 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
941 PCUITEMID_CHILD pidl,
942 const SHCOLUMNID *pscid,
943 VARIANT *pv)
944 {
945 FIXME ("(%p)\n", this);
946
947 return E_NOTIMPL;
948 }
949
950 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
951 PCUITEMID_CHILD pidl,
952 UINT iColumn,
953 SHELLDETAILS *psd)
954 {
955 HRESULT hr = S_OK;
956
957 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
958
959 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
960 return E_INVALIDARG;
961
962 if (!pidl)
963 {
964 psd->fmt = DesktopSFHeader[iColumn].fmt;
965 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
966 psd->str.uType = STRRET_CSTR;
967 LoadStringA (shell32_hInstance, DesktopSFHeader[iColumn].colnameid,
968 psd->str.cStr, MAX_PATH);
969 return S_OK;
970 }
971
972 /* the data from the pidl */
973 psd->str.uType = STRRET_CSTR;
974 switch (iColumn)
975 {
976 case 0: /* name */
977 hr = GetDisplayNameOf(pidl,
978 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
979 break;
980 case 1: /* size */
981 _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
982 break;
983 case 2: /* type */
984 _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
985 break;
986 case 3: /* date */
987 _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
988 break;
989 case 4: /* attributes */
990 _ILGetFileAttributes (pidl, psd->str.cStr, MAX_PATH);
991 break;
992 }
993
994 return hr;
995 }
996
997 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
998 {
999 FIXME ("(%p)\n", this);
1000 return E_NOTIMPL;
1001 }
1002
1003 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
1004 {
1005 TRACE ("(%p)\n", this);
1006
1007 if (!lpClassId)
1008 return E_POINTER;
1009
1010 *lpClassId = CLSID_ShellDesktop;
1011
1012 return S_OK;
1013 }
1014
1015 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
1016 {
1017 TRACE ("(%p)->(%p)\n", this, pidl);
1018
1019 return E_NOTIMPL;
1020 }
1021
1022 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
1023 {
1024 TRACE ("(%p)->(%p)\n", this, pidl);
1025
1026 if (!pidl) return E_POINTER;
1027 *pidl = ILClone (pidlRoot);
1028 return S_OK;
1029 }
1030
1031 HRESULT WINAPI CDesktopFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
1032 {
1033 CComPtr<IEnumIDList> penum;
1034 HRESULT hr;
1035 WCHAR wszText[MAX_PATH];
1036 WCHAR wszNewFolder[25];
1037 const WCHAR wszFormat[] = {'%', 's', ' ', '%', 'd', 0 };
1038
1039 LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, sizeof(wszNewFolder) / sizeof(WCHAR));
1040
1041 TRACE ("(%p)(%p %u)\n", this, pwszName, uLen);
1042
1043 if (uLen < sizeof(wszNewFolder) / sizeof(WCHAR) + 3)
1044 return E_POINTER;
1045
1046 lstrcpynW (pwszName, wszNewFolder, uLen);
1047
1048 hr = EnumObjects(0,
1049 SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1050 if (penum) {
1051 LPITEMIDLIST pidl;
1052 DWORD dwFetched;
1053 int i = 1;
1054
1055 next:
1056 penum->Reset ();
1057 while (S_OK == penum->Next(1, &pidl, &dwFetched) &&
1058 dwFetched) {
1059 _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
1060 if (0 == lstrcmpiW (wszText, pwszName)) {
1061 _snwprintf (pwszName, uLen, wszFormat, wszNewFolder, i++);
1062 if (i > 99) {
1063 hr = E_FAIL;
1064 break;
1065 }
1066 goto next;
1067 }
1068 }
1069
1070 }
1071 return hr;
1072 }
1073
1074 HRESULT WINAPI CDesktopFolder::AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut)
1075 {
1076 WCHAR wszNewDir[MAX_PATH];
1077 DWORD bRes;
1078 HRESULT hres = E_FAIL;
1079
1080 TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName), ppidlOut);
1081
1082 wszNewDir[0] = 0;
1083 if (sPathTarget)
1084 lstrcpynW(wszNewDir, sPathTarget, MAX_PATH);
1085 PathAppendW(wszNewDir, pwszName);
1086 bRes = CreateDirectoryW (wszNewDir, NULL);
1087 if (bRes)
1088 {
1089 SHChangeNotify (SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL);
1090 hres = S_OK;
1091 if (ppidlOut)
1092 hres = _ILCreateFromPathW(wszNewDir, ppidlOut);
1093 }
1094
1095 return hres;
1096 }
1097
1098 HRESULT WINAPI CDesktopFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
1099 {
1100 UINT i;
1101 SHFILEOPSTRUCTW op;
1102 WCHAR wszPath[MAX_PATH];
1103 WCHAR wszCaption[50];
1104 WCHAR *wszPathsList;
1105 HRESULT ret;
1106 WCHAR *wszCurrentPath;
1107 UINT bRestoreWithDeskCpl = FALSE;
1108 int res;
1109
1110 TRACE ("(%p)(%u %p)\n", this, cidl, apidl);
1111 if (cidl == 0) return S_OK;
1112
1113 for(i = 0; i < cidl; i++)
1114 {
1115 if (_ILIsMyComputer(apidl[i]))
1116 bRestoreWithDeskCpl++;
1117 else if (_ILIsNetHood(apidl[i]))
1118 bRestoreWithDeskCpl++;
1119 else if (_ILIsMyDocuments(apidl[i]))
1120 bRestoreWithDeskCpl++;
1121 }
1122
1123 if (bRestoreWithDeskCpl)
1124 {
1125 /* FIXME use FormatMessage
1126 * use a similar message resource as in windows
1127 */
1128 LoadStringW(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, wszPath, sizeof(wszPath) / sizeof(WCHAR));
1129 wszPath[(sizeof(wszPath)/sizeof(WCHAR))-1] = 0;
1130
1131 LoadStringW(shell32_hInstance, IDS_DELETEITEM_CAPTION, wszCaption, sizeof(wszCaption) / sizeof(WCHAR));
1132 wszCaption[(sizeof(wszCaption)/sizeof(WCHAR))-1] = 0;
1133
1134 res = SHELL_ConfirmMsgBox(GetActiveWindow(), wszPath, wszCaption, NULL, cidl > 1);
1135 if (res == IDC_YESTOALL || res == IDYES)
1136 {
1137 for(i = 0; i < cidl; i++)
1138 {
1139 if (_ILIsMyComputer(apidl[i]))
1140 SetNamespaceExtensionVisibleStatus(L"{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0x1);
1141 else if (_ILIsNetHood(apidl[i]))
1142 SetNamespaceExtensionVisibleStatus(L"{208D2C60-3AEA-1069-A2D7-08002B30309D}", 0x1);
1143 else if (_ILIsMyDocuments(apidl[i]))
1144 SetNamespaceExtensionVisibleStatus(L"{450D8FBA-AD25-11D0-98A8-0800361B1103}", 0x1);
1145 }
1146 }
1147 }
1148 if (sPathTarget)
1149 lstrcpynW(wszPath, sPathTarget, MAX_PATH);
1150 else
1151 wszPath[0] = '\0';
1152
1153 PathAddBackslashW(wszPath);
1154 wszPathsList = BuildPathsList(wszPath, cidl, apidl);
1155
1156 ZeroMemory(&op, sizeof(op));
1157 op.hwnd = GetActiveWindow();
1158 op.wFunc = FO_DELETE;
1159 op.pFrom = wszPathsList;
1160 op.fFlags = FOF_ALLOWUNDO;
1161 if (SHFileOperationW(&op))
1162 {
1163 WARN("SHFileOperation failed\n");
1164 ret = E_FAIL;
1165 }
1166 else
1167 ret = S_OK;
1168
1169 /* we currently need to manually send the notifies */
1170 wszCurrentPath = wszPathsList;
1171 for (i = 0; i < cidl; i++)
1172 {
1173 LONG wEventId;
1174
1175 if (_ILIsFolder(apidl[i]))
1176 wEventId = SHCNE_RMDIR;
1177 else if (_ILIsValue(apidl[i]))
1178 wEventId = SHCNE_DELETE;
1179 else
1180 continue;
1181
1182 /* check if file exists */
1183 if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1184 {
1185 LPITEMIDLIST pidl = ILCombine(pidlRoot, apidl[i]);
1186 SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1187 SHFree(pidl);
1188 }
1189
1190 wszCurrentPath += wcslen(wszCurrentPath) + 1;
1191 }
1192 HeapFree(GetProcessHeap(), 0, wszPathsList);
1193 return ret;
1194 }
1195
1196 HRESULT WINAPI CDesktopFolder::CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy)
1197 {
1198 CComPtr<IPersistFolder2> ppf2;
1199 WCHAR szSrcPath[MAX_PATH];
1200 WCHAR szTargetPath[MAX_PATH];
1201 SHFILEOPSTRUCTW op;
1202 LPITEMIDLIST pidl;
1203 LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList, pszFileName;
1204 int res, length;
1205 STRRET strRet;
1206
1207 TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl);
1208
1209 pSFFrom->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
1210 if (ppf2)
1211 {
1212 if (FAILED(ppf2->GetCurFolder(&pidl)))
1213 return E_FAIL;
1214
1215 if (FAILED(pSFFrom->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet)))
1216 {
1217 SHFree (pidl);
1218 return E_FAIL;
1219 }
1220
1221 if (FAILED(StrRetToBufW(&strRet, pidl, szSrcPath, MAX_PATH)))
1222 {
1223 SHFree (pidl);
1224 return E_FAIL;
1225 }
1226 SHFree (pidl);
1227
1228 pszSrc = PathAddBackslashW (szSrcPath);
1229
1230 wcscpy(szTargetPath, sPathTarget);
1231 pszTarget = PathAddBackslashW (szTargetPath);
1232
1233 pszSrcList = BuildPathsList(szSrcPath, cidl, apidl);
1234 pszTargetList = BuildPathsList(szTargetPath, cidl, apidl);
1235
1236 if (!pszSrcList || !pszTargetList)
1237 {
1238 if (pszSrcList)
1239 HeapFree(GetProcessHeap(), 0, pszSrcList);
1240
1241 if (pszTargetList)
1242 HeapFree(GetProcessHeap(), 0, pszTargetList);
1243
1244 SHFree (pidl);
1245 return E_OUTOFMEMORY;
1246 }
1247 ZeroMemory(&op, sizeof(op));
1248 if (!pszSrcList[0])
1249 {
1250 /* remove trailing backslash */
1251 pszSrc--;
1252 pszSrc[0] = L'\0';
1253 op.pFrom = szSrcPath;
1254 }
1255 else
1256 {
1257 op.pFrom = pszSrcList;
1258 }
1259
1260 if (!pszTargetList[0])
1261 {
1262 /* remove trailing backslash */
1263 if (pszTarget - szTargetPath > 3)
1264 {
1265 pszTarget--;
1266 pszTarget[0] = L'\0';
1267 }
1268 else
1269 {
1270 pszTarget[1] = L'\0';
1271 }
1272
1273 op.pTo = szTargetPath;
1274 op.fFlags = 0;
1275 }
1276 else
1277 {
1278 op.pTo = pszTargetList;
1279 op.fFlags = FOF_MULTIDESTFILES;
1280 }
1281 op.hwnd = GetActiveWindow();
1282 op.wFunc = bCopy ? FO_COPY : FO_MOVE;
1283 op.fFlags |= FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
1284
1285 res = SHFileOperationW(&op);
1286
1287 if (res == DE_SAMEFILE)
1288 {
1289 length = wcslen(szTargetPath);
1290
1291
1292 pszFileName = wcsrchr(pszSrcList, '\\');
1293 pszFileName++;
1294
1295 if (LoadStringW(shell32_hInstance, IDS_COPY_OF, pszTarget, MAX_PATH - length))
1296 {
1297 wcscat(szTargetPath, L" ");
1298 }
1299
1300 wcscat(szTargetPath, pszFileName);
1301 op.pTo = szTargetPath;
1302
1303 res = SHFileOperationW(&op);
1304 }
1305
1306
1307 HeapFree(GetProcessHeap(), 0, pszSrcList);
1308 HeapFree(GetProcessHeap(), 0, pszTargetList);
1309
1310 if (res)
1311 return E_FAIL;
1312 else
1313 return S_OK;
1314 }
1315 return E_FAIL;
1316 }
1317
1318 /****************************************************************************
1319 * IDropTarget implementation
1320 *
1321 * This should allow two somewhat separate things, copying files to the users directory,
1322 * as well as allowing icons to be moved anywhere and updating the registry to save.
1323 *
1324 * The first thing I think is best done using fs.cpp to prevent WET code. So we'll simulate
1325 * a drop to the user's home directory. The second will look at the pointer location and
1326 * set sensible places for the icons to live.
1327 *
1328 */
1329 BOOL CDesktopFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
1330 {
1331 /* TODO Windows does different drop effects if dragging across drives.
1332 i.e., it will copy instead of move if the directories are on different disks. */
1333
1334 DWORD dwEffect = DROPEFFECT_MOVE;
1335
1336 *pdwEffect = DROPEFFECT_NONE;
1337
1338 if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
1339 *pdwEffect = KeyStateToDropEffect (dwKeyState);
1340
1341 if (*pdwEffect == DROPEFFECT_NONE)
1342 *pdwEffect = dwEffect;
1343
1344 /* ... matches the desired effect ? */
1345 if (dwEffect & *pdwEffect) {
1346 return TRUE;
1347 }
1348 }
1349 return FALSE;
1350 }
1351
1352 HRESULT WINAPI CDesktopFolder::DragEnter(IDataObject *pDataObject,
1353 DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
1354 {
1355 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
1356 FORMATETC fmt;
1357 FORMATETC fmt2;
1358 fAcceptFmt = FALSE;
1359
1360 InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
1361 InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
1362
1363 if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
1364 fAcceptFmt = TRUE;
1365 else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
1366 fAcceptFmt = TRUE;
1367
1368 QueryDrop(dwKeyState, pdwEffect);
1369 return S_OK;
1370 }
1371
1372 HRESULT WINAPI CDesktopFolder::DragOver(DWORD dwKeyState, POINTL pt,
1373 DWORD *pdwEffect)
1374 {
1375 TRACE("(%p)\n", this);
1376
1377 if (!pdwEffect)
1378 return E_INVALIDARG;
1379
1380 QueryDrop(dwKeyState, pdwEffect);
1381
1382 return S_OK;
1383 }
1384
1385 HRESULT WINAPI CDesktopFolder::DragLeave()
1386 {
1387 TRACE("(%p)\n", this);
1388 fAcceptFmt = FALSE;
1389 return S_OK;
1390 }
1391
1392 HRESULT WINAPI CDesktopFolder::Drop(IDataObject *pDataObject,
1393 DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
1394 {
1395 TRACE("(%p) object dropped desktop\n", this);
1396
1397 STGMEDIUM medium;
1398 bool passthroughtofs = FALSE;
1399 FORMATETC formatetc;
1400 InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
1401
1402 HRESULT hr = pDataObject->GetData(&formatetc, &medium);
1403 if (SUCCEEDED(hr))
1404 {
1405 /* lock the handle */
1406 LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
1407 if (!lpcida)
1408 {
1409 ReleaseStgMedium(&medium);
1410 return E_FAIL;
1411 }
1412
1413 /* convert the clipboard data into pidl (pointer to id list) */
1414 LPITEMIDLIST pidl;
1415 LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
1416 if (!apidl)
1417 {
1418 ReleaseStgMedium(&medium);
1419 return E_FAIL;
1420 }
1421 passthroughtofs = !_ILIsDesktop(pidl) || (dwKeyState & MK_CONTROL);
1422 SHFree(pidl);
1423 _ILFreeaPidl(apidl, lpcida->cidl);
1424 ReleaseStgMedium(&medium);
1425 }
1426 else
1427 {
1428 InitFormatEtc (formatetc, CF_HDROP, TYMED_HGLOBAL);
1429 if (SUCCEEDED(pDataObject->QueryGetData(&formatetc)))
1430 {
1431 passthroughtofs = TRUE;
1432 }
1433 }
1434 /* We only want to really move files around if they don't already
1435 come from the desktop, or we're linking or copying */
1436 if (passthroughtofs)
1437 {
1438 LPITEMIDLIST pidl = NULL;
1439
1440 WCHAR szPath[MAX_PATH];
1441 //LPWSTR pathPtr;
1442
1443 /* build a complete path to create a simple pidl */
1444 lstrcpynW(szPath, sPathTarget, MAX_PATH);
1445 /*pathPtr = */PathAddBackslashW(szPath);
1446 //hr = _ILCreateFromPathW(szPath, &pidl);
1447 hr = this->ParseDisplayName(NULL, NULL, szPath, NULL, &pidl, NULL);
1448
1449 if (SUCCEEDED(hr))
1450 {
1451 CComPtr<IDropTarget> pDT;
1452 hr = this->BindToObject(pidl, NULL, IID_PPV_ARG(IDropTarget, &pDT));
1453 CoTaskMemFree(pidl);
1454 if (SUCCEEDED(hr))
1455 SHSimulateDrop(pDT, pDataObject, dwKeyState, NULL, pdwEffect);
1456 else
1457 ERR("Error Binding");
1458 }
1459 else
1460 ERR("Error creating from %s\n", debugstr_w(szPath));
1461 }
1462
1463 /* Todo, rewrite the registry such that the icons are well placed.
1464 Blocked by no bags implementation. */
1465 return hr;
1466 }
1467
1468 HRESULT WINAPI CDesktopFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) {
1469 HRESULT hr;
1470
1471 TRACE("CFSFolder::_GetDropTarget entered\n");
1472
1473 if (_ILGetGUIDPointer (pidl) || _ILIsFolder (pidl))
1474 return this->BindToObject(pidl, NULL, IID_IDropTarget, ppvOut);
1475
1476 LPITEMIDLIST pidlNext = NULL;
1477
1478 STRRET strFile;
1479 hr = this->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strFile);
1480 if (SUCCEEDED(hr))
1481 {
1482 WCHAR wszPath[MAX_PATH];
1483 hr = StrRetToBufW(&strFile, pidl, wszPath, _countof(wszPath));
1484
1485 if (SUCCEEDED(hr))
1486 {
1487 PathRemoveFileSpecW (wszPath);
1488 hr = this->ParseDisplayName(NULL, NULL, wszPath, NULL, &pidlNext, NULL);
1489
1490 if (SUCCEEDED(hr))
1491 {
1492 CComPtr<IShellFolder> psf;
1493 hr = this->BindToObject(pidlNext, NULL, IID_PPV_ARG(IShellFolder, &psf));
1494 CoTaskMemFree(pidlNext);
1495 if (SUCCEEDED(hr))
1496 {
1497 hr = psf->GetUIObjectOf(NULL, 1, &pidl, IID_IDropTarget, NULL, ppvOut);
1498 if (FAILED(hr))
1499 ERR("FS GetUIObjectOf failed: %x\n", hr);
1500 }
1501 else
1502 ERR("BindToObject failed: %x\n", hr);
1503 }
1504 else
1505 ERR("ParseDisplayName failed: %x\n", hr);
1506 }
1507 else
1508 ERR("StrRetToBufW failed: %x\n", hr);
1509 }
1510 else
1511 ERR("GetDisplayNameOf failed: %x\n", hr);
1512
1513 return hr;
1514 }
1515
1516 /*************************************************************************
1517 * SHGetDesktopFolder [SHELL32.@]
1518 */
1519 HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
1520 {
1521 HRESULT hres = S_OK;
1522 TRACE("\n");
1523
1524 if(!psf) return E_INVALIDARG;
1525 *psf = NULL;
1526 hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellFolder, psf));
1527
1528 TRACE("-- %p->(%p)\n",psf, *psf);
1529 return hres;
1530 }