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