[CLT2012]
[reactos.git] / dll / win32 / shell32 / folders / desktop.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 IEnumIDListImpl
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 CDesktopFolder::CDesktopFolder()
258 {
259 pidlRoot = NULL;
260 sPathTarget = NULL;
261 }
262
263 CDesktopFolder::~CDesktopFolder()
264 {
265 }
266
267 HRESULT WINAPI CDesktopFolder::FinalConstruct()
268 {
269 WCHAR szMyPath[MAX_PATH];
270
271 if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
272 return E_UNEXPECTED;
273
274 pidlRoot = _ILCreateDesktop(); /* my qualified pidl */
275 sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
276 wcscpy(sPathTarget, szMyPath);
277 return S_OK;
278 }
279
280 /**************************************************************************
281 * CDesktopFolder::ParseDisplayName
282 *
283 * NOTES
284 * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
285 * to MyComputer
286 */
287 HRESULT WINAPI CDesktopFolder::ParseDisplayName(
288 HWND hwndOwner,
289 LPBC pbc,
290 LPOLESTR lpszDisplayName,
291 DWORD *pchEaten,
292 LPITEMIDLIST *ppidl,
293 DWORD *pdwAttributes)
294 {
295 WCHAR szElement[MAX_PATH];
296 LPCWSTR szNext = NULL;
297 LPITEMIDLIST pidlTemp = NULL;
298 PARSEDURLW urldata;
299 HRESULT hr = S_OK;
300 CLSID clsid;
301
302 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
303 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
304 pchEaten, ppidl, pdwAttributes);
305
306 if (!ppidl)
307 return E_INVALIDARG;
308
309 if (!lpszDisplayName)
310 {
311 *ppidl = NULL;
312 return E_INVALIDARG;
313 }
314
315 *ppidl = NULL;
316
317 if (pchEaten)
318 *pchEaten = 0; /* strange but like the original */
319
320 urldata.cbSize = sizeof(urldata);
321
322 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
323 {
324 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
325 TRACE ("-- element: %s\n", debugstr_w (szElement));
326 CLSIDFromString (szElement + 2, &clsid);
327 pidlTemp = _ILCreateGuid (PT_GUID, clsid);
328 }
329 else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
330 {
331 /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
332 pidlTemp = _ILCreateMyComputer ();
333 szNext = lpszDisplayName;
334 }
335 else if (PathIsUNCW(lpszDisplayName))
336 {
337 pidlTemp = _ILCreateNetwork();
338 szNext = lpszDisplayName;
339 }
340 else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
341 {
342 *ppidl = pidlTemp;
343 return S_OK;
344 }
345 else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
346 {
347 if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
348 {
349 TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
350 SHCLSIDFromStringW (urldata.pszSuffix + 2, &clsid);
351 pidlTemp = _ILCreateGuid (PT_GUID, clsid);
352 }
353 else
354 return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl);
355 }
356 else
357 {
358 /* it's a filesystem path on the desktop. Let a FSFolder parse it */
359
360 if (*lpszDisplayName)
361 {
362 WCHAR szPath[MAX_PATH];
363 LPWSTR pathPtr;
364
365 /* build a complete path to create a simple pidl */
366 lstrcpynW(szPath, sPathTarget, MAX_PATH);
367 pathPtr = PathAddBackslashW(szPath);
368 if (pathPtr)
369 {
370 lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
371 hr = _ILCreateFromPathW(szPath, &pidlTemp);
372 }
373 else
374 {
375 /* should never reach here, but for completeness */
376 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
377 }
378 }
379 else
380 pidlTemp = _ILCreateMyComputer();
381
382 szNext = NULL;
383 }
384
385 if (SUCCEEDED(hr) && pidlTemp)
386 {
387 if (szNext && *szNext)
388 {
389 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
390 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
391 }
392 else
393 {
394 if (pdwAttributes && *pdwAttributes)
395 hr = SHELL32_GetItemAttributes((IShellFolder *)this,
396 pidlTemp, pdwAttributes);
397 }
398 }
399
400 if (SUCCEEDED(hr))
401 *ppidl = pidlTemp;
402 else
403 *ppidl = NULL;
404
405 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
406
407 return hr;
408 }
409
410 /**************************************************************************
411 * CDesktopFolder::EnumObjects
412 */
413 HRESULT WINAPI CDesktopFolder::EnumObjects(
414 HWND hwndOwner,
415 DWORD dwFlags,
416 LPENUMIDLIST *ppEnumIDList)
417 {
418 CComObject<CDesktopFolderEnum> *theEnumerator;
419 CComPtr<IEnumIDList> result;
420 HRESULT hResult;
421
422 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
423
424 if (ppEnumIDList == NULL)
425 return E_POINTER;
426 *ppEnumIDList = NULL;
427
428 ATLTRY (theEnumerator = new CComObject<CDesktopFolderEnum>);
429
430 if (theEnumerator == NULL)
431 return E_OUTOFMEMORY;
432
433 hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result);
434 if (FAILED (hResult))
435 {
436 delete theEnumerator;
437 return hResult;
438 }
439
440 hResult = theEnumerator->Initialize (this, hwndOwner, dwFlags);
441 if (FAILED (hResult))
442 return hResult;
443 *ppEnumIDList = result.Detach ();
444
445 TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
446
447 return S_OK;
448 }
449
450 /**************************************************************************
451 * CDesktopFolder::BindToObject
452 */
453 HRESULT WINAPI CDesktopFolder::BindToObject(
454 LPCITEMIDLIST pidl,
455 LPBC pbcReserved,
456 REFIID riid,
457 LPVOID *ppvOut)
458 {
459 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
460 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
461
462 return SHELL32_BindToChild( pidlRoot, sPathTarget, pidl, riid, ppvOut );
463 }
464
465 /**************************************************************************
466 * CDesktopFolder::BindToStorage
467 */
468 HRESULT WINAPI CDesktopFolder::BindToStorage(
469 LPCITEMIDLIST pidl,
470 LPBC pbcReserved,
471 REFIID riid,
472 LPVOID *ppvOut)
473 {
474 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
475 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
476
477 *ppvOut = NULL;
478 return E_NOTIMPL;
479 }
480
481 /**************************************************************************
482 * CDesktopFolder::CompareIDs
483 */
484 HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
485 {
486 int nReturn;
487
488 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
489 nReturn = SHELL32_CompareIDs ((IShellFolder *)this, lParam, pidl1, pidl2);
490 TRACE ("-- %i\n", nReturn);
491 return nReturn;
492 }
493
494 /**************************************************************************
495 * CDesktopFolder::CreateViewObject
496 */
497 HRESULT WINAPI CDesktopFolder::CreateViewObject(
498 HWND hwndOwner,
499 REFIID riid,
500 LPVOID *ppvOut)
501 {
502 CComPtr<IShellView> pShellView;
503 HRESULT hr = E_INVALIDARG;
504
505 TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
506 this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
507
508 if (!ppvOut)
509 return hr;
510
511 *ppvOut = NULL;
512
513 if (IsEqualIID (riid, IID_IDropTarget))
514 {
515 WARN ("IDropTarget not implemented\n");
516 hr = E_NOTIMPL;
517 }
518 else if (IsEqualIID (riid, IID_IContextMenu))
519 {
520 WARN ("IContextMenu not implemented\n");
521 hr = E_NOTIMPL;
522 }
523 else if (IsEqualIID (riid, IID_IShellView))
524 {
525 hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
526 if (pShellView)
527 hr = pShellView->QueryInterface(riid, ppvOut);
528 }
529 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
530 return hr;
531 }
532
533 /**************************************************************************
534 * CDesktopFolder::GetAttributesOf
535 */
536 HRESULT WINAPI CDesktopFolder::GetAttributesOf(
537 UINT cidl,
538 LPCITEMIDLIST *apidl,
539 DWORD *rgfInOut)
540 {
541 HRESULT hr = S_OK;
542 static const DWORD dwDesktopAttributes =
543 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
544 SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE | SFGAO_CANLINK;
545 static const DWORD dwMyComputerAttributes =
546 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
547 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
548 static DWORD dwMyNetPlacesAttributes =
549 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
550 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
551
552 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
553 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
554
555 if (cidl && !apidl)
556 return E_INVALIDARG;
557
558 if (*rgfInOut == 0)
559 *rgfInOut = ~0;
560
561 if(cidl == 0)
562 *rgfInOut &= dwDesktopAttributes;
563 else
564 {
565 /* TODO: always add SFGAO_CANLINK */
566 for (UINT i = 0; i < cidl; ++i)
567 {
568 pdump(*apidl);
569 if (_ILIsDesktop(*apidl))
570 *rgfInOut &= dwDesktopAttributes;
571 else if (_ILIsMyComputer(apidl[i]))
572 *rgfInOut &= dwMyComputerAttributes;
573 else if (_ILIsNetHood(apidl[i]))
574 *rgfInOut &= dwMyNetPlacesAttributes;
575 else
576 SHELL32_GetItemAttributes((IShellFolder *)this, apidl[i], rgfInOut);
577 }
578 }
579 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
580 *rgfInOut &= ~SFGAO_VALIDATE;
581
582 TRACE("-- result=0x%08x\n", *rgfInOut);
583
584 return hr;
585 }
586
587 /**************************************************************************
588 * CDesktopFolder::GetUIObjectOf
589 *
590 * PARAMETERS
591 * HWND hwndOwner, //[in ] Parent window for any output
592 * UINT cidl, //[in ] array size
593 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
594 * REFIID riid, //[in ] Requested Interface
595 * UINT* prgfInOut, //[ ] reserved
596 * LPVOID* ppvObject) //[out] Resulting Interface
597 *
598 */
599 HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
600 HWND hwndOwner,
601 UINT cidl,
602 LPCITEMIDLIST *apidl,
603 REFIID riid,
604 UINT *prgfInOut,
605 LPVOID *ppvOut)
606 {
607 LPITEMIDLIST pidl;
608 IUnknown *pObj = NULL;
609 HRESULT hr = E_INVALIDARG;
610
611 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
612 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
613
614 if (!ppvOut)
615 return hr;
616
617 *ppvOut = NULL;
618
619 if (IsEqualIID (riid, IID_IContextMenu))
620 {
621 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder *)this, NULL, 0, NULL, (IContextMenu **)&pObj);
622 }
623 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
624 {
625 hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
626 }
627 else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
628 {
629 pidl = ILCombine (pidlRoot, apidl[0]);
630 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
631 SHFree (pidl);
632 hr = S_OK;
633 }
634 else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
635 {
636 pidl = ILCombine (pidlRoot, apidl[0]);
637 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
638 SHFree (pidl);
639 hr = S_OK;
640 }
641 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
642 {
643 hr = this->QueryInterface (IID_IDropTarget, (LPVOID *)&pObj);
644 }
645 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
646 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
647 {
648 pidl = ILCombine (pidlRoot, apidl[0]);
649 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
650 SHFree (pidl);
651 }
652 else
653 hr = E_NOINTERFACE;
654
655 if (SUCCEEDED(hr) && !pObj)
656 hr = E_OUTOFMEMORY;
657
658 *ppvOut = pObj;
659 TRACE ("(%p)->hr=0x%08x\n", this, hr);
660 return hr;
661 }
662
663 /**************************************************************************
664 * CDesktopFolder::GetDisplayNameOf
665 *
666 * NOTES
667 * special case: pidl = null gives desktop-name back
668 */
669 HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
670 {
671 HRESULT hr = S_OK;
672 LPWSTR pszPath;
673
674 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
675 pdump (pidl);
676
677 if (!strRet)
678 return E_INVALIDARG;
679
680 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
681 if (!pszPath)
682 return E_OUTOFMEMORY;
683
684 if (_ILIsDesktop (pidl))
685 {
686 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
687 (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
688 wcscpy(pszPath, sPathTarget);
689 else
690 HCR_GetClassNameW(CLSID_ShellDesktop, pszPath, MAX_PATH);
691 }
692 else if (_ILIsPidlSimple (pidl))
693 {
694 GUID const *clsid;
695
696 if ((clsid = _ILGetGUIDPointer (pidl)))
697 {
698 if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
699 {
700 int bWantsForParsing;
701
702 /*
703 * We can only get a filesystem path from a shellfolder if the
704 * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
705 *
706 * Exception: The MyComputer folder doesn't have this key,
707 * but any other filesystem backed folder it needs it.
708 */
709 if (IsEqualIID (*clsid, CLSID_MyComputer))
710 {
711 bWantsForParsing = TRUE;
712 }
713 else
714 {
715 /* get the "WantsFORPARSING" flag from the registry */
716 static const WCHAR clsidW[] =
717 { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
718 static const WCHAR shellfolderW[] =
719 { '\\', 's', 'h', 'e', 'l', 'l', 'f', 'o', 'l', 'd', 'e', 'r', 0 };
720 static const WCHAR wantsForParsingW[] =
721 { 'W', 'a', 'n', 't', 's', 'F', 'o', 'r', 'P', 'a', 'r', 's', 'i', 'n',
722 'g', 0
723 };
724 WCHAR szRegPath[100];
725 LONG r;
726
727 wcscpy (szRegPath, clsidW);
728 SHELL32_GUIDToStringW (*clsid, &szRegPath[6]);
729 wcscat (szRegPath, shellfolderW);
730 r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
731 wantsForParsingW, NULL, NULL, NULL);
732 if (r == ERROR_SUCCESS)
733 bWantsForParsing = TRUE;
734 else
735 bWantsForParsing = FALSE;
736 }
737
738 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
739 bWantsForParsing)
740 {
741 /*
742 * we need the filesystem path to the destination folder.
743 * Only the folder itself can know it
744 */
745 hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
746 pszPath,
747 MAX_PATH);
748 }
749 else
750 {
751 /* parsing name like ::{...} */
752 pszPath[0] = ':';
753 pszPath[1] = ':';
754 SHELL32_GUIDToStringW (*clsid, &pszPath[2]);
755 }
756 }
757 else
758 {
759 /* user friendly name */
760 HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
761 }
762 }
763 else
764 {
765 int cLen = 0;
766
767 /* file system folder or file rooted at the desktop */
768 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
769 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
770 {
771 lstrcpynW(pszPath, sPathTarget, MAX_PATH - 1);
772 PathAddBackslashW(pszPath);
773 cLen = wcslen(pszPath);
774 }
775
776 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
777 if (!_ILIsFolder(pidl))
778 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
779
780 if (GetFileAttributes(pszPath) == INVALID_FILE_ATTRIBUTES)
781 {
782 /* file system folder or file rooted at the AllUsers desktop */
783 if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
784 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
785 {
786 SHGetSpecialFolderPathW(0, pszPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
787 PathAddBackslashW(pszPath);
788 cLen = wcslen(pszPath);
789 }
790
791 _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
792 if (!_ILIsFolder(pidl))
793 SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
794 }
795 }
796 }
797 else
798 {
799 /* a complex pidl, let the subfolder do the work */
800 hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
801 pszPath, MAX_PATH);
802 }
803
804 if (SUCCEEDED(hr))
805 {
806 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
807 if (GetVersion() & 0x80000000)
808 {
809 strRet->uType = STRRET_CSTR;
810 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
811 NULL, NULL))
812 strRet->cStr[0] = '\0';
813 CoTaskMemFree(pszPath);
814 }
815 else
816 {
817 strRet->uType = STRRET_WSTR;
818 strRet->pOleStr = pszPath;
819 }
820 }
821 else
822 CoTaskMemFree(pszPath);
823
824 TRACE ("-- (%p)->(%s,0x%08x)\n", this,
825 strRet->uType == STRRET_CSTR ? strRet->cStr :
826 debugstr_w(strRet->pOleStr), hr);
827 return hr;
828 }
829
830 /**************************************************************************
831 * CDesktopFolder::SetNameOf
832 * Changes the name of a file object or subfolder, possibly changing its item
833 * identifier in the process.
834 *
835 * PARAMETERS
836 * HWND hwndOwner, //[in ] Owner window for output
837 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
838 * LPCOLESTR lpszName, //[in ] the items new display name
839 * DWORD dwFlags, //[in ] SHGNO formatting flags
840 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
841 */
842 HRESULT WINAPI CDesktopFolder::SetNameOf(
843 HWND hwndOwner,
844 LPCITEMIDLIST pidl, /* simple pidl */
845 LPCOLESTR lpName,
846 DWORD dwFlags,
847 LPITEMIDLIST *pPidlOut)
848 {
849 CComPtr<IShellFolder2> psf;
850 HRESULT hr;
851 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
852 LPWSTR ptr;
853 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
854
855 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
856 debugstr_w (lpName), dwFlags, pPidlOut);
857
858 if (_ILGetGUIDPointer(pidl))
859 {
860 if (SUCCEEDED(BindToObject(pidl, NULL, IID_IShellFolder2, (LPVOID *)&psf)))
861 {
862 hr = psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
863 return hr;
864 }
865 }
866
867 /* build source path */
868 lstrcpynW(szSrc, sPathTarget, MAX_PATH);
869 ptr = PathAddBackslashW (szSrc);
870 if (ptr)
871 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
872
873 /* build destination path */
874 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
875 lstrcpynW(szDest, sPathTarget, MAX_PATH);
876 ptr = PathAddBackslashW (szDest);
877 if (ptr)
878 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
879 } else
880 lstrcpynW(szDest, lpName, MAX_PATH);
881
882 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
883 WCHAR *ext = PathFindExtensionW(szSrc);
884 if(*ext != '\0') {
885 INT len = wcslen(szDest);
886 lstrcpynW(szDest + len, ext, MAX_PATH - len);
887 }
888 }
889
890 if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
891 {
892 /* src and destination is the same */
893 hr = S_OK;
894 if (pPidlOut)
895 hr = _ILCreateFromPathW(szDest, pPidlOut);
896
897 return hr;
898 }
899
900 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
901 if (MoveFileW (szSrc, szDest))
902 {
903 hr = S_OK;
904
905 if (pPidlOut)
906 hr = _ILCreateFromPathW(szDest, pPidlOut);
907
908 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
909 SHCNF_PATHW, szSrc, szDest);
910
911 return hr;
912 }
913 return E_FAIL;
914 }
915
916 HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
917 {
918 FIXME ("(%p)\n", this);
919 return E_NOTIMPL;
920 }
921
922 HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
923 {
924 FIXME ("(%p)\n", this);
925 return E_NOTIMPL;
926 }
927
928 HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
929 {
930 TRACE ("(%p)\n", this);
931
932 if (pSort)
933 *pSort = 0;
934 if (pDisplay)
935 *pDisplay = 0;
936
937 return S_OK;
938 }
939
940 HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
941 {
942 TRACE ("(%p)\n", this);
943
944 if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
945 return E_INVALIDARG;
946
947 *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
948
949 return S_OK;
950 }
951
952 HRESULT WINAPI CDesktopFolder::GetDetailsEx(
953 LPCITEMIDLIST pidl,
954 const SHCOLUMNID *pscid,
955 VARIANT *pv)
956 {
957 FIXME ("(%p)\n", this);
958
959 return E_NOTIMPL;
960 }
961
962 HRESULT WINAPI CDesktopFolder::GetDetailsOf(
963 LPCITEMIDLIST pidl,
964 UINT iColumn,
965 SHELLDETAILS *psd)
966 {
967 HRESULT hr = S_OK;
968
969 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
970
971 if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
972 return E_INVALIDARG;
973
974 if (!pidl)
975 {
976 psd->fmt = DesktopSFHeader[iColumn].fmt;
977 psd->cxChar = DesktopSFHeader[iColumn].cxChar;
978 psd->str.uType = STRRET_CSTR;
979 LoadStringA (shell32_hInstance, DesktopSFHeader[iColumn].colnameid,
980 psd->str.cStr, MAX_PATH);
981 return S_OK;
982 }
983
984 /* the data from the pidl */
985 psd->str.uType = STRRET_CSTR;
986 switch (iColumn)
987 {
988 case 0: /* name */
989 hr = GetDisplayNameOf(pidl,
990 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
991 break;
992 case 1: /* size */
993 _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
994 break;
995 case 2: /* type */
996 _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
997 break;
998 case 3: /* date */
999 _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
1000 break;
1001 case 4: /* attributes */
1002 _ILGetFileAttributes (pidl, psd->str.cStr, MAX_PATH);
1003 break;
1004 }
1005
1006 return hr;
1007 }
1008
1009 HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
1010 {
1011 FIXME ("(%p)\n", this);
1012 return E_NOTIMPL;
1013 }
1014
1015 HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
1016 {
1017 TRACE ("(%p)\n", this);
1018
1019 if (!lpClassId)
1020 return E_POINTER;
1021
1022 *lpClassId = CLSID_ShellDesktop;
1023
1024 return S_OK;
1025 }
1026
1027 HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
1028 {
1029 TRACE ("(%p)->(%p)\n", this, pidl);
1030
1031 return E_NOTIMPL;
1032 }
1033
1034 HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
1035 {
1036 TRACE ("(%p)->(%p)\n", this, pidl);
1037
1038 if (!pidl) return E_POINTER;
1039 *pidl = ILClone (pidlRoot);
1040 return S_OK;
1041 }
1042
1043 HRESULT WINAPI CDesktopFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
1044 {
1045 CComPtr<IEnumIDList> penum;
1046 HRESULT hr;
1047 WCHAR wszText[MAX_PATH];
1048 WCHAR wszNewFolder[25];
1049 const WCHAR wszFormat[] = {'%', 's', ' ', '%', 'd', 0 };
1050
1051 LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, sizeof(wszNewFolder) / sizeof(WCHAR));
1052
1053 TRACE ("(%p)(%p %u)\n", this, pwszName, uLen);
1054
1055 if (uLen < sizeof(wszNewFolder) / sizeof(WCHAR) + 3)
1056 return E_POINTER;
1057
1058 lstrcpynW (pwszName, wszNewFolder, uLen);
1059
1060 hr = EnumObjects(0,
1061 SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1062 if (penum) {
1063 LPITEMIDLIST pidl;
1064 DWORD dwFetched;
1065 int i = 1;
1066
1067 next:
1068 penum->Reset ();
1069 while (S_OK == penum->Next(1, &pidl, &dwFetched) &&
1070 dwFetched) {
1071 _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
1072 if (0 == lstrcmpiW (wszText, pwszName)) {
1073 _snwprintf (pwszName, uLen, wszFormat, wszNewFolder, i++);
1074 if (i > 99) {
1075 hr = E_FAIL;
1076 break;
1077 }
1078 goto next;
1079 }
1080 }
1081
1082 }
1083 return hr;
1084 }
1085
1086 HRESULT WINAPI CDesktopFolder::AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut)
1087 {
1088 WCHAR wszNewDir[MAX_PATH];
1089 DWORD bRes;
1090 HRESULT hres = E_FAIL;
1091
1092 TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName), ppidlOut);
1093
1094 wszNewDir[0] = 0;
1095 if (sPathTarget)
1096 lstrcpynW(wszNewDir, sPathTarget, MAX_PATH);
1097 PathAppendW(wszNewDir, pwszName);
1098 bRes = CreateDirectoryW (wszNewDir, NULL);
1099 if (bRes)
1100 {
1101 SHChangeNotify (SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL);
1102 hres = S_OK;
1103 if (ppidlOut)
1104 hres = _ILCreateFromPathW(wszNewDir, ppidlOut);
1105 }
1106
1107 return hres;
1108 }
1109
1110 HRESULT WINAPI CDesktopFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
1111 {
1112 UINT i;
1113 SHFILEOPSTRUCTW op;
1114 WCHAR wszPath[MAX_PATH];
1115 WCHAR wszCaption[50];
1116 WCHAR *wszPathsList;
1117 HRESULT ret;
1118 WCHAR *wszCurrentPath;
1119 UINT bRestoreWithDeskCpl = FALSE;
1120 int res;
1121
1122 TRACE ("(%p)(%u %p)\n", this, cidl, apidl);
1123 if (cidl == 0) return S_OK;
1124
1125 for(i = 0; i < cidl; i++)
1126 {
1127 if (_ILIsMyComputer(apidl[i]))
1128 bRestoreWithDeskCpl++;
1129 else if (_ILIsNetHood(apidl[i]))
1130 bRestoreWithDeskCpl++;
1131 else if (_ILIsMyDocuments(apidl[i]))
1132 bRestoreWithDeskCpl++;
1133 }
1134
1135 if (bRestoreWithDeskCpl)
1136 {
1137 /* FIXME use FormatMessage
1138 * use a similar message resource as in windows
1139 */
1140 LoadStringW(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, wszPath, sizeof(wszPath) / sizeof(WCHAR));
1141 wszPath[(sizeof(wszPath)/sizeof(WCHAR))-1] = 0;
1142
1143 LoadStringW(shell32_hInstance, IDS_DELETEITEM_CAPTION, wszCaption, sizeof(wszCaption) / sizeof(WCHAR));
1144 wszCaption[(sizeof(wszCaption)/sizeof(WCHAR))-1] = 0;
1145
1146 res = SHELL_ConfirmMsgBox(GetActiveWindow(), wszPath, wszCaption, NULL, cidl > 1);
1147 if (res == IDC_YESTOALL || res == IDYES)
1148 {
1149 for(i = 0; i < cidl; i++)
1150 {
1151 if (_ILIsMyComputer(apidl[i]))
1152 SetNamespaceExtensionVisibleStatus(L"{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0x1);
1153 else if (_ILIsNetHood(apidl[i]))
1154 SetNamespaceExtensionVisibleStatus(L"{208D2C60-3AEA-1069-A2D7-08002B30309D}", 0x1);
1155 else if (_ILIsMyDocuments(apidl[i]))
1156 SetNamespaceExtensionVisibleStatus(L"{450D8FBA-AD25-11D0-98A8-0800361B1103}", 0x1);
1157 }
1158 }
1159 }
1160 if (sPathTarget)
1161 lstrcpynW(wszPath, sPathTarget, MAX_PATH);
1162 else
1163 wszPath[0] = '\0';
1164
1165 PathAddBackslashW(wszPath);
1166 wszPathsList = BuildPathsList(wszPath, cidl, apidl);
1167
1168 ZeroMemory(&op, sizeof(op));
1169 op.hwnd = GetActiveWindow();
1170 op.wFunc = FO_DELETE;
1171 op.pFrom = wszPathsList;
1172 op.fFlags = FOF_ALLOWUNDO;
1173 if (SHFileOperationW(&op))
1174 {
1175 WARN("SHFileOperation failed\n");
1176 ret = E_FAIL;
1177 }
1178 else
1179 ret = S_OK;
1180
1181 /* we currently need to manually send the notifies */
1182 wszCurrentPath = wszPathsList;
1183 for (i = 0; i < cidl; i++)
1184 {
1185 LONG wEventId;
1186
1187 if (_ILIsFolder(apidl[i]))
1188 wEventId = SHCNE_RMDIR;
1189 else if (_ILIsValue(apidl[i]))
1190 wEventId = SHCNE_DELETE;
1191 else
1192 continue;
1193
1194 /* check if file exists */
1195 if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1196 {
1197 LPITEMIDLIST pidl = ILCombine(pidlRoot, apidl[i]);
1198 SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1199 SHFree(pidl);
1200 }
1201
1202 wszCurrentPath += wcslen(wszCurrentPath) + 1;
1203 }
1204 HeapFree(GetProcessHeap(), 0, wszPathsList);
1205 return ret;
1206 }
1207
1208 HRESULT WINAPI CDesktopFolder::CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl)
1209 {
1210 CComPtr<IPersistFolder2> ppf2;
1211 WCHAR szSrcPath[MAX_PATH];
1212 WCHAR szTargetPath[MAX_PATH];
1213 SHFILEOPSTRUCTW op;
1214 LPITEMIDLIST pidl;
1215 LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList, pszFileName;
1216 int res, length;
1217 STRRET strRet;
1218
1219 TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl);
1220
1221 pSFFrom->QueryInterface(IID_IPersistFolder2, (LPVOID *)&ppf2);
1222 if (ppf2)
1223 {
1224 if (FAILED(ppf2->GetCurFolder(&pidl)))
1225 return E_FAIL;
1226
1227 if (FAILED(pSFFrom->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet)))
1228 {
1229 SHFree (pidl);
1230 return E_FAIL;
1231 }
1232
1233 if (FAILED(StrRetToBufW(&strRet, pidl, szSrcPath, MAX_PATH)))
1234 {
1235 SHFree (pidl);
1236 return E_FAIL;
1237 }
1238 SHFree (pidl);
1239
1240 pszSrc = PathAddBackslashW (szSrcPath);
1241
1242 wcscpy(szTargetPath, sPathTarget);
1243 pszTarget = PathAddBackslashW (szTargetPath);
1244
1245 pszSrcList = BuildPathsList(szSrcPath, cidl, apidl);
1246 pszTargetList = BuildPathsList(szTargetPath, cidl, apidl);
1247
1248 if (!pszSrcList || !pszTargetList)
1249 {
1250 if (pszSrcList)
1251 HeapFree(GetProcessHeap(), 0, pszSrcList);
1252
1253 if (pszTargetList)
1254 HeapFree(GetProcessHeap(), 0, pszTargetList);
1255
1256 SHFree (pidl);
1257 return E_OUTOFMEMORY;
1258 }
1259 ZeroMemory(&op, sizeof(op));
1260 if (!pszSrcList[0])
1261 {
1262 /* remove trailing backslash */
1263 pszSrc--;
1264 pszSrc[0] = L'\0';
1265 op.pFrom = szSrcPath;
1266 }
1267 else
1268 {
1269 op.pFrom = pszSrcList;
1270 }
1271
1272 if (!pszTargetList[0])
1273 {
1274 /* remove trailing backslash */
1275 if (pszTarget - szTargetPath > 3)
1276 {
1277 pszTarget--;
1278 pszTarget[0] = L'\0';
1279 }
1280 else
1281 {
1282 pszTarget[1] = L'\0';
1283 }
1284
1285 op.pTo = szTargetPath;
1286 }
1287 else
1288 {
1289 op.pTo = pszTargetList;
1290 }
1291 op.hwnd = GetActiveWindow();
1292 op.wFunc = FO_COPY;
1293 op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
1294
1295 res = SHFileOperationW(&op);
1296
1297 if (res == DE_SAMEFILE)
1298 {
1299 length = wcslen(szTargetPath);
1300
1301
1302 pszFileName = wcsrchr(pszSrcList, '\\');
1303 pszFileName++;
1304
1305 if (LoadStringW(shell32_hInstance, IDS_COPY_OF, pszTarget, MAX_PATH - length))
1306 {
1307 wcscat(szTargetPath, L" ");
1308 }
1309
1310 wcscat(szTargetPath, pszFileName);
1311 op.pTo = szTargetPath;
1312
1313 res = SHFileOperationW(&op);
1314 }
1315
1316
1317 HeapFree(GetProcessHeap(), 0, pszSrcList);
1318 HeapFree(GetProcessHeap(), 0, pszTargetList);
1319
1320 if (res)
1321 return E_FAIL;
1322 else
1323 return S_OK;
1324 }
1325 return E_FAIL;
1326 }