- Implement ISFHelper_fnCopyItems for desktop shellfolder
[reactos.git] / reactos / dll / win32 / shell32 / shfldr_desktop.c
1
2 /*
3 * Virtual Desktop Folder
4 *
5 * Copyright 1997 Marcus Meissner
6 * Copyright 1998, 1999, 2002 Juergen Schmied
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 * Desktopfolder implementation
29 */
30
31 typedef struct {
32 const IShellFolder2Vtbl *lpVtbl;
33 const IPersistFolder2Vtbl *lpPF2;
34 const ISFHelperVtbl *lpvtblSFHelper;
35 LONG ref;
36
37 /* both paths are parsible from the desktop */
38 LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
39 LPITEMIDLIST pidlRoot; /* absolute pidl */
40
41 UINT cfShellIDList; /* clipboardformat for IDropTarget */
42 BOOL fAcceptFmt; /* flag for pending Drop */
43 } IGenericSFImpl, *LPIGenericSFImpl;
44
45 WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls);
46 int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll);
47
48 #define _IUnknown_(This) (IShellFolder*)&(This->lpVtbl)
49 #define _IShellFolder_(This) (IShellFolder*)&(This->lpVtbl)
50
51 static const shvheader DesktopSFHeader[] = {
52 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
53 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
54 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
55 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
56 {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
57 };
58
59 #define DESKTOPSHELLVIEWCOLUMNS 5
60
61 /**************************************************************************
62 * ISF_Desktop_fnQueryInterface
63 *
64 * NOTES supports not IPersist/IPersistFolder
65 */
66 static HRESULT WINAPI ISF_Desktop_fnQueryInterface(
67 IShellFolder2 * iface, REFIID riid, LPVOID * ppvObj)
68 {
69 IGenericSFImpl *This = (IGenericSFImpl *)iface;
70
71 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
72
73 *ppvObj = NULL;
74
75 if (IsEqualIID (riid, &IID_IUnknown) ||
76 IsEqualIID (riid, &IID_IShellFolder) ||
77 IsEqualIID (riid, &IID_IShellFolder2))
78 {
79 *ppvObj = This;
80 }
81 else if (IsEqualIID (riid, &IID_IPersistFolder) ||
82 IsEqualIID (riid, &IID_IPersistFolder2))
83 {
84 *ppvObj = &This->lpPF2;
85 }
86 else if (IsEqualIID(riid, &IID_ISFHelper))
87 {
88 *ppvObj = &This->lpvtblSFHelper;
89 }
90 if (*ppvObj)
91 {
92 IUnknown_AddRef ((IUnknown *) (*ppvObj));
93 TRACE ("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
94 return S_OK;
95 }
96 TRACE ("-- Interface: E_NOINTERFACE\n");
97 return E_NOINTERFACE;
98 }
99
100 static LPIGenericSFImpl __inline impl_from_ISFHelper( ISFHelper *iface )
101 {
102 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblSFHelper));
103 }
104
105 static ULONG WINAPI ISF_Desktop_fnAddRef (IShellFolder2 * iface)
106 {
107 return 2; /* non-heap based object */
108 }
109
110 static ULONG WINAPI ISF_Desktop_fnRelease (IShellFolder2 * iface)
111 {
112 return 1; /* non-heap based object */
113 }
114
115 /**************************************************************************
116 * ISF_Desktop_fnParseDisplayName
117 *
118 * NOTES
119 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
120 * to MyComputer
121 */
122 static HRESULT WINAPI ISF_Desktop_fnParseDisplayName (IShellFolder2 * iface,
123 HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
124 DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
125 {
126 IGenericSFImpl *This = (IGenericSFImpl *)iface;
127 WCHAR szElement[MAX_PATH];
128 LPCWSTR szNext = NULL;
129 LPITEMIDLIST pidlTemp = NULL;
130 HRESULT hr = S_OK;
131 CLSID clsid;
132
133 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
134 This, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
135 pchEaten, ppidl, pdwAttributes);
136
137 if (!lpszDisplayName || !ppidl)
138 return E_INVALIDARG;
139
140 *ppidl = 0;
141
142 if (pchEaten)
143 *pchEaten = 0; /* strange but like the original */
144
145 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
146 {
147 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
148 TRACE ("-- element: %s\n", debugstr_w (szElement));
149 CLSIDFromString (szElement + 2, &clsid);
150 pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
151 }
152 else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
153 {
154 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
155 #if 0
156 if (UNIXFS_is_rooted_at_desktop())
157 pidlTemp = _ILCreateGuid(PT_GUID, &CLSID_UnixDosFolder);
158 else
159 #endif
160 pidlTemp = _ILCreateMyComputer ();
161 szNext = lpszDisplayName;
162 }
163 else if (PathIsUNCW(lpszDisplayName))
164 {
165 pidlTemp = _ILCreateNetwork();
166 szNext = lpszDisplayName;
167 }
168 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
169 {
170 *ppidl = pidlTemp;
171 return S_OK;
172 }
173 else
174 {
175 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
176
177 if (*lpszDisplayName)
178 {
179 WCHAR szPath[MAX_PATH];
180 LPWSTR pathPtr;
181
182 /* build a complete path to create a simple pidl */
183 lstrcpynW(szPath, This->sPathTarget, MAX_PATH);
184 pathPtr = PathAddBackslashW(szPath);
185 if (pathPtr)
186 {
187 lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
188 hr = _ILCreateFromPathW(szPath, &pidlTemp);
189 }
190 else
191 {
192 /* should never reach here, but for completeness */
193 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
194 }
195 }
196 else
197 pidlTemp = _ILCreateMyComputer();
198
199 szNext = NULL;
200 }
201
202 if (SUCCEEDED(hr) && pidlTemp)
203 {
204 if (szNext && *szNext)
205 {
206 hr = SHELL32_ParseNextElement(iface, hwndOwner, pbc,
207 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
208 }
209 else
210 {
211 if (pdwAttributes && *pdwAttributes)
212 hr = SHELL32_GetItemAttributes(_IShellFolder_ (This),
213 pidlTemp, pdwAttributes);
214 }
215 }
216
217 *ppidl = pidlTemp;
218
219 TRACE ("(%p)->(-- ret=0x%08x)\n", This, hr);
220
221 return hr;
222 }
223
224 static const WCHAR ClassicStartMenuW[] = {'S','O','F','T','W','A','R','E','\\',
225 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
226 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r',
227 '\\','H','i','d','e','D','e','s','k','t','o','p','I','c','o','n','s','\\',
228 'C','l','a','s','s','i','c','S','t','a','r','t','M','e','n','u','\0' };
229
230 INT
231 IsNamespaceExtensionHidden(WCHAR *iid)
232 {
233 DWORD Result, dwResult;
234 dwResult = sizeof(DWORD);
235
236 if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */
237 ClassicStartMenuW,
238 iid,
239 RRF_RT_DWORD,
240 NULL,
241 &Result,
242 &dwResult) != ERROR_SUCCESS)
243 {
244 return -1;
245 }
246
247 return Result;
248 }
249
250 static
251 VOID
252 SetNamespaceExtensionVisibleStatus(WCHAR * iid, DWORD dwStatus)
253 {
254 HKEY hKey;
255
256 if (RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
257 {
258 RegSetValueExW(hKey, iid, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(DWORD));
259 RegCloseKey(hKey);
260 }
261 }
262
263
264
265 /**************************************************************************
266 * CreateDesktopEnumList()
267 */
268 static const WCHAR Desktop_NameSpaceW[] = { 'S','O','F','T','W','A','R','E',
269 '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
270 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
271 'o','r','e','r','\\','D','e','s','k','t','o','p','\\','N','a','m','e','s','p',
272 'a','c','e','\0' };
273
274 static BOOL CreateDesktopEnumList(IEnumIDList *list, DWORD dwFlags)
275 {
276 BOOL ret = TRUE;
277 WCHAR szPath[MAX_PATH];
278
279 static WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}";
280
281
282 TRACE("(%p)->(flags=0x%08x)\n", list, dwFlags);
283
284 /* enumerate the root folders */
285 if (dwFlags & SHCONTF_FOLDERS)
286 {
287 HKEY hkey;
288 UINT i;
289 DWORD dwResult;
290
291 /* create the pidl for This item */
292 if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1)
293 {
294 ret = AddToEnumList(list, _ILCreateMyDocuments());
295 }
296 ret = AddToEnumList(list, _ILCreateMyComputer());
297
298 for (i = 0; i < 2; i++)
299 {
300 if (i == 0)
301 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
302 else
303 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
304
305 if (dwResult == ERROR_SUCCESS)
306 {
307 WCHAR iid[50];
308 LPITEMIDLIST pidl;
309 int i=0;
310
311 while (ret)
312 {
313 DWORD size;
314 LONG r;
315
316 size = sizeof (iid) / sizeof (iid[0]);
317 r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
318 if (ERROR_SUCCESS == r)
319 {
320 if (IsNamespaceExtensionHidden(iid) < 1)
321 {
322 pidl = _ILCreateGuidFromStrW(iid);
323 if (!HasItemWithCLSID(list, pidl))
324 {
325 ret = AddToEnumList(list, pidl);
326 }
327 else
328 {
329 SHFree(pidl);
330 }
331 }
332 }
333 else if (ERROR_NO_MORE_ITEMS == r)
334 break;
335 else
336 ret = FALSE;
337 i++;
338 }
339 RegCloseKey(hkey);
340 }
341 }
342 for (i = 0; i < 2; i++)
343 {
344 if (i == 0)
345 dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, ClassicStartMenuW, 0, KEY_READ, &hkey);
346 else
347 dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_READ, &hkey);
348
349 if (dwResult == ERROR_SUCCESS)
350 {
351 DWORD j = 0, dwVal, Val, dwType, dwIID;
352 LONG r;
353 WCHAR iid[50];
354
355 while(ret)
356 {
357 dwVal = sizeof(Val);
358 dwIID = sizeof(iid) / sizeof(WCHAR);
359
360 r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal);
361 if (r == ERROR_SUCCESS)
362 {
363 if (Val == 0 && dwType == REG_DWORD)
364 {
365 LPITEMIDLIST pidl = _ILCreateGuidFromStrW(iid);
366 if (!HasItemWithCLSID(list, pidl))
367 {
368 AddToEnumList(list, pidl);
369 }
370 else
371 {
372 SHFree(pidl);
373 }
374 }
375 }
376 else if (ERROR_NO_MORE_ITEMS == r)
377 break;
378 else
379 ret = FALSE;
380 }
381 }
382
383 }
384 }
385
386 /* enumerate the elements in %windir%\desktop */
387 ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
388 ret = ret && CreateFolderEnumList(list, szPath, dwFlags);
389
390 return ret;
391 }
392
393 /**************************************************************************
394 * ISF_Desktop_fnEnumObjects
395 */
396 static HRESULT WINAPI ISF_Desktop_fnEnumObjects (IShellFolder2 * iface,
397 HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
398 {
399 IGenericSFImpl *This = (IGenericSFImpl *)iface;
400
401 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n",
402 This, hwndOwner, dwFlags, ppEnumIDList);
403
404 *ppEnumIDList = IEnumIDList_Constructor();
405 if (*ppEnumIDList)
406 CreateDesktopEnumList(*ppEnumIDList, dwFlags);
407
408 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
409
410 return *ppEnumIDList ? S_OK : E_OUTOFMEMORY;
411 }
412
413 /**************************************************************************
414 * ISF_Desktop_fnBindToObject
415 */
416 static HRESULT WINAPI ISF_Desktop_fnBindToObject (IShellFolder2 * iface,
417 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
418 {
419 IGenericSFImpl *This = (IGenericSFImpl *)iface;
420
421 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
422 This, pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
423
424 return SHELL32_BindToChild( This->pidlRoot, This->sPathTarget, pidl, riid, ppvOut );
425 }
426
427 /**************************************************************************
428 * ISF_Desktop_fnBindToStorage
429 */
430 static HRESULT WINAPI ISF_Desktop_fnBindToStorage (IShellFolder2 * iface,
431 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
432 {
433 IGenericSFImpl *This = (IGenericSFImpl *)iface;
434
435 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
436 This, pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
437
438 *ppvOut = NULL;
439 return E_NOTIMPL;
440 }
441
442 /**************************************************************************
443 * ISF_Desktop_fnCompareIDs
444 */
445 static HRESULT WINAPI ISF_Desktop_fnCompareIDs (IShellFolder2 * iface,
446 LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
447 {
448 IGenericSFImpl *This = (IGenericSFImpl *)iface;
449 int nReturn;
450
451 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
452 nReturn = SHELL32_CompareIDs (_IShellFolder_ (This), lParam, pidl1, pidl2);
453 TRACE ("-- %i\n", nReturn);
454 return nReturn;
455 }
456
457 /**************************************************************************
458 * ISF_Desktop_fnCreateViewObject
459 */
460 static HRESULT WINAPI ISF_Desktop_fnCreateViewObject (IShellFolder2 * iface,
461 HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
462 {
463 IGenericSFImpl *This = (IGenericSFImpl *)iface;
464 LPSHELLVIEW pShellView;
465 HRESULT hr = E_INVALIDARG;
466
467 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
468 This, hwndOwner, shdebugstr_guid (riid), ppvOut);
469
470 if (!ppvOut)
471 return hr;
472
473 *ppvOut = NULL;
474
475 if (IsEqualIID (riid, &IID_IDropTarget))
476 {
477 WARN ("IDropTarget not implemented\n");
478 hr = E_NOTIMPL;
479 }
480 else if (IsEqualIID (riid, &IID_IContextMenu))
481 {
482 WARN ("IContextMenu not implemented\n");
483 hr = E_NOTIMPL;
484 }
485 else if (IsEqualIID (riid, &IID_IShellView))
486 {
487 pShellView = IShellView_Constructor ((IShellFolder *) iface);
488 if (pShellView)
489 {
490 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
491 IShellView_Release (pShellView);
492 }
493 }
494 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
495 return hr;
496 }
497
498 /**************************************************************************
499 * ISF_Desktop_fnGetAttributesOf
500 */
501 static HRESULT WINAPI ISF_Desktop_fnGetAttributesOf (IShellFolder2 * iface,
502 UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
503 {
504 IGenericSFImpl *This = (IGenericSFImpl *)iface;
505 HRESULT hr = S_OK;
506 static const DWORD dwDesktopAttributes =
507 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
508 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
509 static const DWORD dwMyComputerAttributes =
510 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
511 SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
512
513 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
514 This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
515
516 if (!rgfInOut)
517 return E_INVALIDARG;
518 if (cidl && !apidl)
519 return E_INVALIDARG;
520
521 if (*rgfInOut == 0)
522 *rgfInOut = ~0;
523
524 if(cidl == 0) {
525 *rgfInOut &= dwDesktopAttributes;
526 } else {
527 while (cidl > 0 && *apidl) {
528 pdump (*apidl);
529 if (_ILIsDesktop(*apidl)) {
530 *rgfInOut &= dwDesktopAttributes;
531 } else if (_ILIsMyComputer(*apidl)) {
532 *rgfInOut &= dwMyComputerAttributes;
533 } else {
534 SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
535 }
536 apidl++;
537 cidl--;
538 }
539 }
540 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
541 *rgfInOut &= ~SFGAO_VALIDATE;
542
543 TRACE ("-- result=0x%08x\n", *rgfInOut);
544
545 return hr;
546 }
547
548 /**************************************************************************
549 * ISF_Desktop_fnGetUIObjectOf
550 *
551 * PARAMETERS
552 * HWND hwndOwner, //[in ] Parent window for any output
553 * UINT cidl, //[in ] array size
554 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
555 * REFIID riid, //[in ] Requested Interface
556 * UINT* prgfInOut, //[ ] reserved
557 * LPVOID* ppvObject) //[out] Resulting Interface
558 *
559 */
560 static HRESULT WINAPI ISF_Desktop_fnGetUIObjectOf (IShellFolder2 * iface,
561 HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
562 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
563 {
564 IGenericSFImpl *This = (IGenericSFImpl *)iface;
565
566 LPITEMIDLIST pidl;
567 IUnknown *pObj = NULL;
568 HRESULT hr = E_INVALIDARG;
569
570 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
571 This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
572
573 if (!ppvOut)
574 return hr;
575
576 *ppvOut = NULL;
577
578 if (IsEqualIID (riid, &IID_IContextMenu))
579 {
580 hr = CDefFolderMenu_Create2(This->pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)iface, NULL, 0, NULL, (IContextMenu**)&pObj);
581 }
582 else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1))
583 {
584 pObj = (LPUNKNOWN) IDataObject_Constructor( hwndOwner,
585 This->pidlRoot, apidl, cidl);
586 hr = S_OK;
587 }
588 else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1))
589 {
590 pidl = ILCombine (This->pidlRoot, apidl[0]);
591 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
592 SHFree (pidl);
593 hr = S_OK;
594 }
595 else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1))
596 {
597 pidl = ILCombine (This->pidlRoot, apidl[0]);
598 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
599 SHFree (pidl);
600 hr = S_OK;
601 }
602 else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1))
603 {
604 hr = IShellFolder_QueryInterface (iface,
605 &IID_IDropTarget, (LPVOID *) & pObj);
606 }
607 else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
608 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1))
609 {
610 pidl = ILCombine (This->pidlRoot, apidl[0]);
611 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
612 SHFree (pidl);
613 }
614 else
615 hr = E_NOINTERFACE;
616
617 if (SUCCEEDED(hr) && !pObj)
618 hr = E_OUTOFMEMORY;
619
620 *ppvOut = pObj;
621 TRACE ("(%p)->hr=0x%08x\n", This, hr);
622 return hr;
623 }
624
625 /**************************************************************************
626 * ISF_Desktop_fnGetDisplayNameOf
627 *
628 * NOTES
629 * special case: pidl = null gives desktop-name back
630 */
631 static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf (IShellFolder2 * iface,
632 LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
633 {
634 IGenericSFImpl *This = (IGenericSFImpl *)iface;
635 HRESULT hr = S_OK;
636 LPWSTR pszPath;
637
638 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
639 pdump (pidl);
640
641 if (!strRet)
642 return E_INVALIDARG;
643
644 pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
645 if (!pszPath)
646 return E_OUTOFMEMORY;
647
648 if (_ILIsDesktop (pidl))
649 {
650 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
651 (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
652 wcscpy(pszPath, This->sPathTarget);
653 else
654 HCR_GetClassNameW(&CLSID_ShellDesktop, pszPath, MAX_PATH);
655 }
656 else if (_ILIsPidlSimple (pidl))
657 {
658 GUID const *clsid;
659
660 if ((clsid = _ILGetGUIDPointer (pidl)))
661 {
662 if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
663 {
664 int bWantsForParsing;
665
666 /*
667 * We can only get a filesystem path from a shellfolder if the
668 * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
669 *
670 * Exception: The MyComputer folder doesn't have this key,
671 * but any other filesystem backed folder it needs it.
672 */
673 if (IsEqualIID (clsid, &CLSID_MyComputer))
674 {
675 bWantsForParsing = TRUE;
676 }
677 else
678 {
679 /* get the "WantsFORPARSING" flag from the registry */
680 static const WCHAR clsidW[] =
681 { 'C','L','S','I','D','\\',0 };
682 static const WCHAR shellfolderW[] =
683 { '\\','s','h','e','l','l','f','o','l','d','e','r',0 };
684 static const WCHAR wantsForParsingW[] =
685 { 'W','a','n','t','s','F','o','r','P','a','r','s','i','n',
686 'g',0 };
687 WCHAR szRegPath[100];
688 LONG r;
689
690 wcscpy (szRegPath, clsidW);
691 SHELL32_GUIDToStringW (clsid, &szRegPath[6]);
692 wcscat (szRegPath, shellfolderW);
693 r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
694 wantsForParsingW, NULL, NULL, NULL);
695 if (r == ERROR_SUCCESS)
696 bWantsForParsing = TRUE;
697 else
698 bWantsForParsing = FALSE;
699 }
700
701 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
702 bWantsForParsing)
703 {
704 /*
705 * we need the filesystem path to the destination folder.
706 * Only the folder itself can know it
707 */
708 hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
709 pszPath,
710 MAX_PATH);
711 }
712 else
713 {
714 /* parsing name like ::{...} */
715 pszPath[0] = ':';
716 pszPath[1] = ':';
717 SHELL32_GUIDToStringW (clsid, &pszPath[2]);
718 }
719 }
720 else
721 {
722 /* user friendly name */
723 HCR_GetClassNameW (clsid, pszPath, MAX_PATH);
724 }
725 }
726 else
727 {
728 int cLen = 0;
729
730 /* file system folder or file rooted at the desktop */
731 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
732 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
733 {
734 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH - 1);
735 PathAddBackslashW(pszPath);
736 cLen = wcslen(pszPath);
737 }
738
739 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
740 if (!_ILIsFolder(pidl))
741 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
742 }
743 }
744 else
745 {
746 /* a complex pidl, let the subfolder do the work */
747 hr = SHELL32_GetDisplayNameOfChild (iface, pidl, dwFlags,
748 pszPath, MAX_PATH);
749 }
750
751 if (SUCCEEDED(hr))
752 {
753 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
754 if (GetVersion() & 0x80000000)
755 {
756 strRet->uType = STRRET_CSTR;
757 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
758 NULL, NULL))
759 strRet->u.cStr[0] = '\0';
760 CoTaskMemFree(pszPath);
761 }
762 else
763 {
764 strRet->uType = STRRET_WSTR;
765 strRet->u.pOleStr = pszPath;
766 }
767 }
768 else
769 CoTaskMemFree(pszPath);
770
771 TRACE ("-- (%p)->(%s,0x%08x)\n", This,
772 strRet->uType == STRRET_CSTR ? strRet->u.cStr :
773 debugstr_w(strRet->u.pOleStr), hr);
774 return hr;
775 }
776
777 /**************************************************************************
778 * ISF_Desktop_fnSetNameOf
779 * Changes the name of a file object or subfolder, possibly changing its item
780 * identifier in the process.
781 *
782 * PARAMETERS
783 * HWND hwndOwner, //[in ] Owner window for output
784 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
785 * LPCOLESTR lpszName, //[in ] the items new display name
786 * DWORD dwFlags, //[in ] SHGNO formatting flags
787 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
788 */
789 static HRESULT WINAPI ISF_Desktop_fnSetNameOf (IShellFolder2 * iface,
790 HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */
791 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
792 {
793 IGenericSFImpl *This = (IGenericSFImpl *)iface;
794 IShellFolder2 * psf;
795 HRESULT hr;
796 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
797 LPWSTR ptr;
798 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
799
800 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl,
801 debugstr_w (lpName), dwFlags, pPidlOut);
802
803 if (_ILGetGUIDPointer(pidl))
804 {
805 if (SUCCEEDED(IShellFolder2_BindToObject(iface, pidl, NULL, &IID_IShellFolder2, (LPVOID*)&psf)))
806 {
807 hr = IShellFolder2_SetNameOf(psf, hwndOwner, pidl, lpName, dwFlags, pPidlOut);
808 IShellFolder2_Release(psf);
809 return hr;
810 }
811 }
812
813 /* build source path */
814 lstrcpynW(szSrc, This->sPathTarget, MAX_PATH);
815 ptr = PathAddBackslashW (szSrc);
816 if (ptr)
817 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
818
819 /* build destination path */
820 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
821 lstrcpynW(szDest, This->sPathTarget, MAX_PATH);
822 ptr = PathAddBackslashW (szDest);
823 if (ptr)
824 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
825 } else
826 lstrcpynW(szDest, lpName, MAX_PATH);
827
828 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
829 WCHAR *ext = PathFindExtensionW(szSrc);
830 if(*ext != '\0') {
831 INT len = wcslen(szDest);
832 lstrcpynW(szDest + len, ext, MAX_PATH - len);
833 }
834 }
835
836 if (!memcmp(szSrc, szDest, (wcslen(szDest)+1) * sizeof(WCHAR)))
837 {
838 /* src and destination is the same */
839 hr = S_OK;
840 if (pPidlOut)
841 hr = _ILCreateFromPathW(szDest, pPidlOut);
842
843 return hr;
844 }
845
846 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
847 if (MoveFileW (szSrc, szDest))
848 {
849 hr = S_OK;
850
851 if (pPidlOut)
852 hr = _ILCreateFromPathW(szDest, pPidlOut);
853
854 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
855 SHCNF_PATHW, szSrc, szDest);
856
857 return hr;
858 }
859 return E_FAIL;
860 }
861 static HRESULT WINAPI ISF_Desktop_fnGetDefaultSearchGUID(IShellFolder2 *iface,
862 GUID * pguid)
863 {
864 IGenericSFImpl *This = (IGenericSFImpl *)iface;
865
866 FIXME ("(%p)\n", This);
867 return E_NOTIMPL;
868 }
869
870 static HRESULT WINAPI ISF_Desktop_fnEnumSearches (IShellFolder2 *iface,
871 IEnumExtraSearch ** ppenum)
872 {
873 IGenericSFImpl *This = (IGenericSFImpl *)iface;
874 FIXME ("(%p)\n", This);
875 return E_NOTIMPL;
876 }
877
878 static HRESULT WINAPI ISF_Desktop_fnGetDefaultColumn (IShellFolder2 * iface,
879 DWORD dwRes, ULONG * pSort, ULONG * pDisplay)
880 {
881 IGenericSFImpl *This = (IGenericSFImpl *)iface;
882
883 TRACE ("(%p)\n", This);
884
885 if (pSort)
886 *pSort = 0;
887 if (pDisplay)
888 *pDisplay = 0;
889
890 return S_OK;
891 }
892 static HRESULT WINAPI ISF_Desktop_fnGetDefaultColumnState (
893 IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
894 {
895 IGenericSFImpl *This = (IGenericSFImpl *)iface;
896
897 TRACE ("(%p)\n", This);
898
899 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
900 return E_INVALIDARG;
901
902 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
903
904 return S_OK;
905 }
906
907 static HRESULT WINAPI ISF_Desktop_fnGetDetailsEx (IShellFolder2 * iface,
908 LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
909 {
910 IGenericSFImpl *This = (IGenericSFImpl *)iface;
911 FIXME ("(%p)\n", This);
912
913 return E_NOTIMPL;
914 }
915
916 static HRESULT WINAPI ISF_Desktop_fnGetDetailsOf (IShellFolder2 * iface,
917 LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd)
918 {
919 IGenericSFImpl *This = (IGenericSFImpl *)iface;
920
921 HRESULT hr = S_OK;
922
923 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
924
925 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
926 return E_INVALIDARG;
927
928 if (!pidl)
929 {
930 psd->fmt = DesktopSFHeader[iColumn].fmt;
931 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
932 psd->str.uType = STRRET_CSTR;
933 LoadStringA (shell32_hInstance, DesktopSFHeader[iColumn].colnameid,
934 psd->str.u.cStr, MAX_PATH);
935 return S_OK;
936 }
937
938 /* the data from the pidl */
939 psd->str.uType = STRRET_CSTR;
940 switch (iColumn)
941 {
942 case 0: /* name */
943 hr = IShellFolder_GetDisplayNameOf(iface, pidl,
944 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
945 break;
946 case 1: /* size */
947 _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH);
948 break;
949 case 2: /* type */
950 _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
951 break;
952 case 3: /* date */
953 _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH);
954 break;
955 case 4: /* attributes */
956 _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
957 break;
958 }
959
960 return hr;
961 }
962
963 static HRESULT WINAPI ISF_Desktop_fnMapColumnToSCID (
964 IShellFolder2 * iface, UINT column, SHCOLUMNID * pscid)
965 {
966 IGenericSFImpl *This = (IGenericSFImpl *)iface;
967 FIXME ("(%p)\n", This);
968 return E_NOTIMPL;
969 }
970
971 static const IShellFolder2Vtbl vt_MCFldr_ShellFolder2 =
972 {
973 ISF_Desktop_fnQueryInterface,
974 ISF_Desktop_fnAddRef,
975 ISF_Desktop_fnRelease,
976 ISF_Desktop_fnParseDisplayName,
977 ISF_Desktop_fnEnumObjects,
978 ISF_Desktop_fnBindToObject,
979 ISF_Desktop_fnBindToStorage,
980 ISF_Desktop_fnCompareIDs,
981 ISF_Desktop_fnCreateViewObject,
982 ISF_Desktop_fnGetAttributesOf,
983 ISF_Desktop_fnGetUIObjectOf,
984 ISF_Desktop_fnGetDisplayNameOf,
985 ISF_Desktop_fnSetNameOf,
986 /* ShellFolder2 */
987 ISF_Desktop_fnGetDefaultSearchGUID,
988 ISF_Desktop_fnEnumSearches,
989 ISF_Desktop_fnGetDefaultColumn,
990 ISF_Desktop_fnGetDefaultColumnState,
991 ISF_Desktop_fnGetDetailsEx,
992 ISF_Desktop_fnGetDetailsOf,
993 ISF_Desktop_fnMapColumnToSCID
994 };
995
996 static LPIGenericSFImpl __inline impl_from_IPersistFolder2( IPersistFolder2 *iface )
997 {
998 return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpPF2));
999 }
1000
1001 static HRESULT WINAPI
1002 ISF_Desktop_PersistFolder2_fnQueryInterface (IPersistFolder2 * iface, REFIID iid,
1003 LPVOID * ppvObj)
1004 {
1005 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
1006
1007 TRACE ("(%p)\n", This);
1008
1009 return ISF_Desktop_fnQueryInterface ((IShellFolder2*)This, iid, ppvObj);
1010 }
1011
1012 static ULONG WINAPI
1013 ISF_Desktop_PersistFolder2_fnAddRef (IPersistFolder2 * iface)
1014 {
1015 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
1016
1017 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1018
1019 return ISF_Desktop_fnAddRef((IShellFolder2*)This);
1020 }
1021
1022 static ULONG WINAPI
1023 ISF_Desktop_PersistFolder2_fnRelease (IPersistFolder2 * iface)
1024 {
1025 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
1026
1027 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1028
1029 return ISF_Desktop_fnRelease ((IShellFolder2*)This);
1030 }
1031
1032 static HRESULT WINAPI
1033 ISF_Desktop_PersistFolder2_fnGetClassID (IPersistFolder2 * iface, CLSID * lpClassId)
1034 {
1035 static GUID const CLSID_Desktop =
1036 { 0x00021400, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
1037
1038 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
1039
1040 TRACE ("(%p)\n", This);
1041
1042 if (!lpClassId)
1043 return E_POINTER;
1044
1045 memcpy(lpClassId, &CLSID_Desktop, sizeof(GUID));
1046
1047 return S_OK;
1048 }
1049 static HRESULT WINAPI
1050 ISF_Desktop_PersistFolder2_fnInitialize (IPersistFolder2 * iface, LPCITEMIDLIST pidl)
1051 {
1052 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
1053
1054 TRACE ("(%p)->(%p)\n", This, pidl);
1055
1056 return E_NOTIMPL;
1057 }
1058
1059 static HRESULT WINAPI
1060 ISF_Desktop_PersistFolder2_fnGetCurFolder (IPersistFolder2 * iface,
1061 LPITEMIDLIST * pidl)
1062 {
1063 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
1064
1065 TRACE ("(%p)->(%p)\n", This, pidl);
1066
1067 if (!pidl) return E_POINTER;
1068 *pidl = ILClone (This->pidlRoot);
1069 return S_OK;
1070 }
1071
1072 static const IPersistFolder2Vtbl vt_FSFldr_PersistFolder2 =
1073 {
1074 ISF_Desktop_PersistFolder2_fnQueryInterface,
1075 ISF_Desktop_PersistFolder2_fnAddRef,
1076 ISF_Desktop_PersistFolder2_fnRelease,
1077 ISF_Desktop_PersistFolder2_fnGetClassID,
1078 ISF_Desktop_PersistFolder2_fnInitialize,
1079 ISF_Desktop_PersistFolder2_fnGetCurFolder,
1080 };
1081
1082 static HRESULT WINAPI
1083 ISF_Desktop_ISFHelper_fnQueryInterface (ISFHelper * iface, REFIID riid, LPVOID * ppvObj)
1084 {
1085 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1086
1087 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1088
1089 return ISF_Desktop_fnQueryInterface ((IShellFolder2*)This, riid, ppvObj);
1090 }
1091
1092 static ULONG WINAPI
1093 ISF_Desktop_ISFHelper_fnAddRef (ISFHelper * iface)
1094 {
1095 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1096
1097 TRACE ("(%p)->(count=%u)\n", This, This->ref);
1098
1099 return ISF_Desktop_fnAddRef((IShellFolder2*)This);
1100 }
1101
1102 static ULONG WINAPI
1103 ISF_Desktop_ISFHelper_fnRelease (ISFHelper * iface)
1104 {
1105 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1106
1107 TRACE ("(%p)\n", This);
1108
1109 return ISF_Desktop_fnRelease ((IShellFolder2*)This);
1110 }
1111
1112 static HRESULT WINAPI
1113 ISF_Desktop_ISFHelper_fnGetUniqueName (ISFHelper * iface, LPWSTR pwszName, UINT uLen)
1114 {
1115 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1116 IEnumIDList *penum;
1117 HRESULT hr;
1118 WCHAR wszText[MAX_PATH];
1119 WCHAR wszNewFolder[25];
1120 const WCHAR wszFormat[] = {'%','s',' ','%','d',0 };
1121
1122 LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, sizeof(wszNewFolder)/sizeof(WCHAR));
1123
1124 TRACE ("(%p)(%p %u)\n", This, pwszName, uLen);
1125
1126 if (uLen < sizeof(wszNewFolder)/sizeof(WCHAR) + 3)
1127 return E_POINTER;
1128
1129 lstrcpynW (pwszName, wszNewFolder, uLen);
1130
1131 hr = IShellFolder_EnumObjects ((IShellFolder2*)This, 0,
1132 SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1133 if (penum) {
1134 LPITEMIDLIST pidl;
1135 DWORD dwFetched;
1136 int i = 1;
1137
1138 next:
1139 IEnumIDList_Reset (penum);
1140 while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) &&
1141 dwFetched) {
1142 _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
1143 if (0 == lstrcmpiW (wszText, pwszName)) {
1144 _snwprintf (pwszName, uLen, wszFormat, wszNewFolder, i++);
1145 if (i > 99) {
1146 hr = E_FAIL;
1147 break;
1148 }
1149 goto next;
1150 }
1151 }
1152
1153 IEnumIDList_Release (penum);
1154 }
1155 return hr;
1156 }
1157
1158 static HRESULT WINAPI
1159 ISF_Desktop_ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCWSTR pwszName,
1160 LPITEMIDLIST * ppidlOut)
1161 {
1162 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1163 WCHAR wszNewDir[MAX_PATH];
1164 DWORD bRes;
1165 HRESULT hres = E_FAIL;
1166
1167 TRACE ("(%p)(%s %p)\n", This, debugstr_w(pwszName), ppidlOut);
1168
1169 wszNewDir[0] = 0;
1170 if (This->sPathTarget)
1171 lstrcpynW(wszNewDir, This->sPathTarget, MAX_PATH);
1172 PathAppendW(wszNewDir, pwszName);
1173 bRes = CreateDirectoryW (wszNewDir, NULL);
1174 if (bRes)
1175 {
1176 SHChangeNotify (SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL);
1177 hres = S_OK;
1178 if (ppidlOut)
1179 hres = _ILCreateFromPathW(wszNewDir, ppidlOut);
1180 }
1181
1182 return hres;
1183 }
1184 static HRESULT WINAPI
1185 ISF_Desktop_ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl)
1186 {
1187 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1188 UINT i;
1189 SHFILEOPSTRUCTW op;
1190 WCHAR wszPath[MAX_PATH];
1191 WCHAR wszCaption[50];
1192 WCHAR *wszPathsList;
1193 HRESULT ret;
1194 WCHAR *wszCurrentPath;
1195 UINT bRestoreWithDeskCpl = FALSE;
1196 int res;
1197
1198 TRACE ("(%p)(%u %p)\n", This, cidl, apidl);
1199 if (cidl==0) return S_OK;
1200
1201 for(i = 0; i < cidl; i++)
1202 {
1203 if (_ILIsMyComputer(apidl[i]))
1204 bRestoreWithDeskCpl++;
1205 else if (_ILIsNetHood(apidl[i]))
1206 bRestoreWithDeskCpl++;
1207 else if (_ILIsMyDocuments(apidl[i]))
1208 bRestoreWithDeskCpl++;
1209 }
1210
1211 if (bRestoreWithDeskCpl)
1212 {
1213 /* FIXME use FormatMessage
1214 * use a similar message resource as in windows
1215 */
1216 LoadStringW(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, wszPath, sizeof(wszPath)/sizeof(WCHAR));
1217 wszPath[(sizeof(wszPath)/sizeof(WCHAR))-1] = 0;
1218
1219 LoadStringW(shell32_hInstance, IDS_DELETEITEM_CAPTION, wszCaption, sizeof(wszCaption)/sizeof(WCHAR));
1220 wszCaption[(sizeof(wszCaption)/sizeof(WCHAR))-1] = 0;
1221
1222 res = SHELL_ConfirmMsgBox(GetActiveWindow(), wszPath, wszCaption, NULL, cidl > 1);
1223 if (res == IDD_YESTOALL || res == IDYES)
1224 {
1225 for(i = 0; i < cidl; i++)
1226 {
1227 if (_ILIsMyComputer(apidl[i]))
1228 SetNamespaceExtensionVisibleStatus(L"{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0x1);
1229 else if (_ILIsNetHood(apidl[i]))
1230 SetNamespaceExtensionVisibleStatus(L"{208D2C60-3AEA-1069-A2D7-08002B30309D}", 0x1);
1231 else if (_ILIsMyDocuments(apidl[i]))
1232 SetNamespaceExtensionVisibleStatus(L"{450D8FBA-AD25-11D0-98A8-0800361B1103}", 0x1);
1233 }
1234 }
1235 }
1236 if (This->sPathTarget)
1237 lstrcpynW(wszPath, This->sPathTarget, MAX_PATH);
1238 else
1239 wszPath[0] = '\0';
1240
1241 PathAddBackslashW(wszPath);
1242 wszPathsList = build_paths_list(wszPath, cidl, apidl);
1243
1244 ZeroMemory(&op, sizeof(op));
1245 op.hwnd = GetActiveWindow();
1246 op.wFunc = FO_DELETE;
1247 op.pFrom = wszPathsList;
1248 op.fFlags = FOF_ALLOWUNDO;
1249 if (SHFileOperationW(&op))
1250 {
1251 WARN("SHFileOperation failed\n");
1252 ret = E_FAIL;
1253 }
1254 else
1255 ret = S_OK;
1256
1257 /* we currently need to manually send the notifies */
1258 wszCurrentPath = wszPathsList;
1259 for (i = 0; i < cidl; i++)
1260 {
1261 LONG wEventId;
1262
1263 if (_ILIsFolder(apidl[i]))
1264 wEventId = SHCNE_RMDIR;
1265 else if (_ILIsValue(apidl[i]))
1266 wEventId = SHCNE_DELETE;
1267 else
1268 continue;
1269
1270 /* check if file exists */
1271 if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1272 {
1273 LPITEMIDLIST pidl = ILCombine(This->pidlRoot, apidl[i]);
1274 SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1275 SHFree(pidl);
1276 }
1277
1278 wszCurrentPath += wcslen(wszCurrentPath)+1;
1279 }
1280 HeapFree(GetProcessHeap(), 0, wszPathsList);
1281 return ret;
1282 }
1283
1284 static HRESULT WINAPI
1285 ISF_Desktop_ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl, LPCITEMIDLIST * apidl)
1286 {
1287 IPersistFolder2 *ppf2 = NULL;
1288 WCHAR szSrcPath[MAX_PATH];
1289 WCHAR szTargetPath[MAX_PATH];
1290 SHFILEOPSTRUCTW op;
1291 LPITEMIDLIST pidl;
1292 LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList;
1293 int res;
1294 STRRET strRet;
1295 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1296
1297 TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl);
1298
1299 IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2, (LPVOID *) & ppf2);
1300 if (ppf2)
1301 {
1302 if (FAILED(IPersistFolder2_GetCurFolder (ppf2, &pidl)))
1303 {
1304 IPersistFolder2_Release(ppf2);
1305 return E_FAIL;
1306 }
1307 IPersistFolder2_Release(ppf2);
1308
1309 if (FAILED(IShellFolder_GetDisplayNameOf(pSFFrom, pidl, SHGDN_FORPARSING, &strRet)))
1310 {
1311 SHFree (pidl);
1312 return E_FAIL;
1313 }
1314
1315 if (FAILED(StrRetToBufW(&strRet, pidl, szSrcPath, MAX_PATH)))
1316 {
1317 SHFree (pidl);
1318 return E_FAIL;
1319 }
1320 SHFree (pidl);
1321
1322 pszSrc = PathAddBackslashW (szSrcPath);
1323
1324 wcscpy(szTargetPath, This->sPathTarget);
1325 pszTarget = PathAddBackslashW (szTargetPath);
1326
1327 pszSrcList = build_paths_list(szSrcPath, cidl, apidl);
1328 pszTargetList = build_paths_list(szTargetPath, cidl, apidl);
1329
1330 if (!pszSrcList || !pszTargetList)
1331 {
1332 if (pszSrcList)
1333 HeapFree(GetProcessHeap(), 0, pszSrcList);
1334
1335 if (pszTargetList)
1336 HeapFree(GetProcessHeap(), 0, pszTargetList);
1337
1338 SHFree (pidl);
1339 IPersistFolder2_Release (ppf2);
1340 return E_OUTOFMEMORY;
1341 }
1342 ZeroMemory(&op, sizeof(op));
1343 if (!pszSrcList[0])
1344 {
1345 /* remove trailing backslash */
1346 pszSrc--;
1347 pszSrc[0] = L'\0';
1348 op.pFrom = szSrcPath;
1349 }
1350 else
1351 {
1352 op.pFrom = pszSrcList;
1353 }
1354
1355 if (!pszTargetList[0])
1356 {
1357 /* remove trailing backslash */
1358 if (pszTarget - szTargetPath > 3)
1359 {
1360 pszTarget--;
1361 pszTarget[0] = L'\0';
1362 }
1363 else
1364 {
1365 pszTarget[1] = L'\0';
1366 }
1367
1368 op.pTo = szTargetPath;
1369 }
1370 else
1371 {
1372 op.pTo = pszTargetList;
1373 }
1374 op.hwnd = GetActiveWindow();
1375 op.wFunc = FO_COPY;
1376 op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
1377
1378 res = SHFileOperationW(&op);
1379
1380 HeapFree(GetProcessHeap(), 0, pszSrc);
1381 HeapFree(GetProcessHeap(), 0, pszTarget);
1382
1383 if (res)
1384 return E_FAIL;
1385 else
1386 return S_OK;
1387 }
1388 return E_FAIL;
1389 }
1390
1391 static const ISFHelperVtbl vt_FSFldr_ISFHelper =
1392 {
1393 ISF_Desktop_ISFHelper_fnQueryInterface,
1394 ISF_Desktop_ISFHelper_fnAddRef,
1395 ISF_Desktop_ISFHelper_fnRelease,
1396 ISF_Desktop_ISFHelper_fnGetUniqueName,
1397 ISF_Desktop_ISFHelper_fnAddFolder,
1398 ISF_Desktop_ISFHelper_fnDeleteItems,
1399 ISF_Desktop_ISFHelper_fnCopyItems
1400 };
1401
1402
1403 /**************************************************************************
1404 * ISF_Desktop_Constructor
1405 */
1406 HRESULT WINAPI ISF_Desktop_Constructor (
1407 IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
1408 {
1409 static IGenericSFImpl *cached_sf;
1410 WCHAR szMyPath[MAX_PATH];
1411
1412 TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
1413
1414 if (!ppv)
1415 return E_POINTER;
1416 if (pUnkOuter)
1417 return CLASS_E_NOAGGREGATION;
1418
1419 if (!cached_sf)
1420 {
1421 IGenericSFImpl *sf;
1422
1423 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
1424 return E_UNEXPECTED;
1425
1426 sf = LocalAlloc( LMEM_ZEROINIT, sizeof (IGenericSFImpl) );
1427 if (!sf)
1428 return E_OUTOFMEMORY;
1429
1430 sf->ref = 1;
1431 sf->lpVtbl = &vt_MCFldr_ShellFolder2;
1432 sf->lpPF2 = &vt_FSFldr_PersistFolder2;
1433 sf->lpvtblSFHelper = &vt_FSFldr_ISFHelper;
1434 sf->pidlRoot = _ILCreateDesktop(); /* my qualified pidl */
1435 sf->sPathTarget = SHAlloc( (wcslen(szMyPath) + 1)*sizeof(WCHAR) );
1436 wcscpy( sf->sPathTarget, szMyPath );
1437
1438 if (InterlockedCompareExchangePointer((void *)&cached_sf, sf, NULL) != NULL)
1439 {
1440 /* some other thread already been here */
1441 SHFree( sf->pidlRoot );
1442 SHFree( sf->sPathTarget );
1443 LocalFree( sf );
1444 }
1445 }
1446
1447 return IUnknown_QueryInterface( _IUnknown_(cached_sf), riid, ppv );
1448 }