[shell32]
[reactos.git] / reactos / dll / win32 / shell32 / folders / fs.cpp
1
2 /*
3 * file system 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 CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is
29 returned by Next. When the enumerator is created, it can do numerous additional operations
30 including formatting a drive, reconnecting a network share drive, and requesting a disk
31 be inserted in a removable drive.
32 */
33
34 /***********************************************************************
35 * IShellFolder implementation
36 */
37
38 class CFileSysEnum :
39 public IEnumIDListImpl
40 {
41 private:
42 public:
43 CFileSysEnum();
44 ~CFileSysEnum();
45 HRESULT WINAPI Initialize(LPWSTR sPathTarget, DWORD dwFlags);
46
47 BEGIN_COM_MAP(CFileSysEnum)
48 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
49 END_COM_MAP()
50 };
51
52 CFileSysEnum::CFileSysEnum()
53 {
54 }
55
56 CFileSysEnum::~CFileSysEnum()
57 {
58 }
59
60 HRESULT WINAPI CFileSysEnum::Initialize(LPWSTR sPathTarget, DWORD dwFlags)
61 {
62 return CreateFolderEnumList(sPathTarget, dwFlags);
63 }
64
65 /**************************************************************************
66 * registers clipboardformat once
67 */
68 void CFSFolder::SF_RegisterClipFmt()
69 {
70 TRACE ("(%p)\n", this);
71
72 if (!cfShellIDList)
73 cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
74 }
75
76 CFSFolder::CFSFolder()
77 {
78 pclsid = (CLSID *)&CLSID_ShellFSFolder;
79 sPathTarget = NULL;
80 pidlRoot = NULL;
81 cfShellIDList = 0;
82 fAcceptFmt = FALSE;
83 }
84
85 CFSFolder::~CFSFolder()
86 {
87 TRACE("-- destroying IShellFolder(%p)\n", this);
88
89 SHFree(pidlRoot);
90 SHFree(sPathTarget);
91 }
92
93
94 static const shvheader GenericSFHeader[] = {
95 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
96 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
97 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
98 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
99 {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
100 };
101
102 #define GENERICSHELLVIEWCOLUMNS 5
103
104 /**************************************************************************
105 * SHELL32_CreatePidlFromBindCtx [internal]
106 *
107 * If the caller bound File System Bind Data, assume it is the
108 * find data for the path.
109 * This allows binding of paths that don't exist.
110 */
111 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
112 {
113 IFileSystemBindData *fsbd = NULL;
114 LPITEMIDLIST pidl = NULL;
115 IUnknown *param = NULL;
116 WIN32_FIND_DATAW wfd;
117 HRESULT r;
118
119 TRACE("%p %s\n", pbc, debugstr_w(path));
120
121 if (!pbc)
122 return NULL;
123
124 /* see if the caller bound File System Bind Data */
125 r = pbc->GetObjectParam((LPOLESTR)STR_FILE_SYS_BIND_DATA, &param);
126 if (FAILED(r))
127 return NULL;
128
129 r = param->QueryInterface(IID_PPV_ARG(IFileSystemBindData,&fsbd));
130 if (SUCCEEDED(r))
131 {
132 r = fsbd->GetFindData(&wfd);
133 if (SUCCEEDED(r))
134 {
135 lstrcpynW(&wfd.cFileName[0], path, MAX_PATH);
136 pidl = _ILCreateFromFindDataW(&wfd);
137 }
138 fsbd->Release();
139 }
140
141 return pidl;
142 }
143
144 /**************************************************************************
145 * CFSFolder::ParseDisplayName {SHELL32}
146 *
147 * Parse a display name.
148 *
149 * PARAMS
150 * hwndOwner [in] Parent window for any message's
151 * pbc [in] optional FileSystemBindData context
152 * lpszDisplayName [in] Unicode displayname.
153 * pchEaten [out] (unicode) characters processed
154 * ppidl [out] complex pidl to item
155 * pdwAttributes [out] items attributes
156 *
157 * NOTES
158 * Every folder tries to parse only its own (the leftmost) pidl and creates a
159 * subfolder to evaluate the remaining parts.
160 * Now we can parse into namespaces implemented by shell extensions
161 *
162 * Behaviour on win98: lpszDisplayName=NULL -> crash
163 * lpszDisplayName="" -> returns mycoputer-pidl
164 *
165 * FIXME
166 * pdwAttributes is not set
167 * pchEaten is not set like in windows
168 */
169 HRESULT WINAPI CFSFolder::ParseDisplayName(HWND hwndOwner,
170 LPBC pbc,
171 LPOLESTR lpszDisplayName,
172 DWORD *pchEaten, LPITEMIDLIST *ppidl,
173 DWORD *pdwAttributes)
174 {
175 HRESULT hr = E_INVALIDARG;
176 LPCWSTR szNext = NULL;
177 WCHAR szElement[MAX_PATH];
178 WCHAR szPath[MAX_PATH];
179 LPITEMIDLIST pidlTemp = NULL;
180 DWORD len;
181
182 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
183 this, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
184 pchEaten, ppidl, pdwAttributes);
185
186 if (!ppidl)
187 return E_INVALIDARG;
188
189 if (!lpszDisplayName)
190 {
191 *ppidl = NULL;
192 return E_INVALIDARG;
193 }
194
195 *ppidl = NULL;
196
197 if (pchEaten)
198 *pchEaten = 0; /* strange but like the original */
199
200 if (*lpszDisplayName)
201 {
202 /* get the next element */
203 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
204
205 pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, szElement);
206 if (pidlTemp != NULL)
207 {
208 hr = S_OK;
209 }
210 else
211 {
212 /* build the full pathname to the element */
213 lstrcpynW(szPath, sPathTarget, MAX_PATH - 1);
214 PathAddBackslashW(szPath);
215 len = wcslen(szPath);
216 lstrcpynW(szPath + len, szElement, MAX_PATH - len);
217
218 /* get the pidl */
219 hr = _ILCreateFromPathW(szPath, &pidlTemp);
220 }
221
222 if (SUCCEEDED(hr))
223 {
224 if (szNext && *szNext)
225 {
226 /* try to analyse the next element */
227 hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
228 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
229 }
230 else
231 {
232 /* it's the last element */
233 if (pdwAttributes && *pdwAttributes)
234 hr = SHELL32_GetItemAttributes(this, pidlTemp, pdwAttributes);
235 }
236 }
237 }
238
239 if (SUCCEEDED(hr))
240 *ppidl = pidlTemp;
241 else
242 *ppidl = NULL;
243
244 TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl ? *ppidl : 0, hr);
245
246 return hr;
247 }
248
249 /**************************************************************************
250 * CFSFolder::EnumObjects
251 * PARAMETERS
252 * HWND hwndOwner, //[in ] Parent Window
253 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
254 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
255 */
256 HRESULT WINAPI CFSFolder::EnumObjects(
257 HWND hwndOwner,
258 DWORD dwFlags,
259 LPENUMIDLIST *ppEnumIDList)
260 {
261 CComObject<CFileSysEnum> *theEnumerator;
262 CComPtr<IEnumIDList> result;
263 HRESULT hResult;
264
265 TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
266
267 if (ppEnumIDList == NULL)
268 return E_POINTER;
269 *ppEnumIDList = NULL;
270 ATLTRY (theEnumerator = new CComObject<CFileSysEnum>);
271 if (theEnumerator == NULL)
272 return E_OUTOFMEMORY;
273 hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
274 if (FAILED(hResult))
275 {
276 delete theEnumerator;
277 return hResult;
278 }
279 hResult = theEnumerator->Initialize (sPathTarget, dwFlags);
280 if (FAILED (hResult))
281 return hResult;
282 *ppEnumIDList = result.Detach();
283
284 TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
285
286 return S_OK;
287 }
288
289 /**************************************************************************
290 * CFSFolder::BindToObject
291 * PARAMETERS
292 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
293 * LPBC pbc, //[in ] optional FileSystemBindData context
294 * REFIID riid, //[in ] Initial Interface
295 * LPVOID* ppvObject //[out] Interface*
296 */
297 HRESULT WINAPI CFSFolder::BindToObject(
298 LPCITEMIDLIST pidl,
299 LPBC pbc,
300 REFIID riid,
301 LPVOID * ppvOut)
302 {
303 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbc,
304 shdebugstr_guid(&riid), ppvOut);
305
306 return SHELL32_BindToChild(pidlRoot, sPathTarget, pidl, riid, ppvOut);
307 }
308
309 /**************************************************************************
310 * CFSFolder::BindToStorage
311 * PARAMETERS
312 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
313 * LPBC pbc, //[in ] reserved
314 * REFIID riid, //[in ] Initial storage interface
315 * LPVOID* ppvObject //[out] Interface* returned
316 */
317 HRESULT WINAPI CFSFolder::BindToStorage(
318 LPCITEMIDLIST pidl,
319 LPBC pbcReserved,
320 REFIID riid,
321 LPVOID *ppvOut)
322 {
323 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved,
324 shdebugstr_guid (&riid), ppvOut);
325
326 *ppvOut = NULL;
327 return E_NOTIMPL;
328 }
329
330 /**************************************************************************
331 * CFSFolder::CompareIDs
332 */
333
334 HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam,
335 LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
336 {
337 int nReturn;
338
339 TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
340 nReturn = SHELL32_CompareIDs(this, lParam, pidl1, pidl2);
341 TRACE("-- %i\n", nReturn);
342 return nReturn;
343 }
344
345 /**************************************************************************
346 * CFSFolder::CreateViewObject
347 */
348 HRESULT WINAPI CFSFolder::CreateViewObject(HWND hwndOwner,
349 REFIID riid, LPVOID * ppvOut)
350 {
351 LPSHELLVIEW pShellView;
352 HRESULT hr = E_INVALIDARG;
353
354 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid (&riid),
355 ppvOut);
356
357 if (ppvOut)
358 {
359 *ppvOut = NULL;
360
361 if (IsEqualIID (riid, IID_IDropTarget))
362 hr = this->QueryInterface (IID_IDropTarget, ppvOut);
363 else if (IsEqualIID (riid, IID_IContextMenu))
364 {
365 FIXME ("IContextMenu not implemented\n");
366 hr = E_NOTIMPL;
367 }
368 else if (IsEqualIID (riid, IID_IShellView))
369 {
370 hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
371 if (pShellView)
372 {
373 hr = pShellView->QueryInterface(riid, ppvOut);
374 pShellView->Release();
375 }
376 }
377 }
378 TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
379 return hr;
380 }
381
382 /**************************************************************************
383 * CFSFolder::GetAttributesOf
384 *
385 * PARAMETERS
386 * UINT cidl, //[in ] num elements in pidl array
387 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
388 * ULONG* rgfInOut) //[out] result array
389 *
390 */
391 HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl,
392 LPCITEMIDLIST * apidl, DWORD * rgfInOut)
393 {
394 HRESULT hr = S_OK;
395
396 TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this, cidl, apidl,
397 rgfInOut, rgfInOut ? *rgfInOut : 0);
398
399 if (!rgfInOut)
400 return E_INVALIDARG;
401 if (cidl && !apidl)
402 return E_INVALIDARG;
403
404 if (*rgfInOut == 0)
405 *rgfInOut = ~0;
406
407 if(cidl == 0)
408 {
409 IShellFolder *psfParent = NULL;
410 LPCITEMIDLIST rpidl = NULL;
411
412 hr = SHBindToParent(pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), &rpidl);
413 if(SUCCEEDED(hr))
414 {
415 SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
416 psfParent->Release();
417 }
418 }
419 else
420 {
421 while (cidl > 0 && *apidl)
422 {
423 pdump(*apidl);
424 SHELL32_GetItemAttributes(this, *apidl, rgfInOut);
425 apidl++;
426 cidl--;
427 }
428 }
429 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
430 *rgfInOut &= ~SFGAO_VALIDATE;
431
432 TRACE("-- result=0x%08x\n", *rgfInOut);
433
434 return hr;
435 }
436
437 /**************************************************************************
438 * CFSFolder::GetUIObjectOf
439 *
440 * PARAMETERS
441 * HWND hwndOwner, //[in ] Parent window for any output
442 * UINT cidl, //[in ] array size
443 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
444 * REFIID riid, //[in ] Requested Interface
445 * UINT* prgfInOut, //[ ] reserved
446 * LPVOID* ppvObject) //[out] Resulting Interface
447 *
448 * NOTES
449 * This function gets asked to return "view objects" for one or more (multiple
450 * select) items:
451 * The viewobject typically is an COM object with one of the following
452 * interfaces:
453 * IExtractIcon,IDataObject,IContextMenu
454 * In order to support icon positions in the default Listview your DataObject
455 * must implement the SetData method (in addition to GetData :) - the shell
456 * passes a barely documented "Icon positions" structure to SetData when the
457 * drag starts, and GetData's it if the drop is in another explorer window that
458 * needs the positions.
459 */
460 HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner,
461 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
462 UINT * prgfInOut, LPVOID * ppvOut)
463 {
464 LPITEMIDLIST pidl;
465 IUnknown *pObj = NULL;
466 HRESULT hr = E_INVALIDARG;
467
468 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
469 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
470
471 if (ppvOut)
472 {
473 *ppvOut = NULL;
474
475 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
476 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
477 else if (IsEqualIID (riid, IID_IDataObject))
478 {
479 if (cidl >= 1) {
480 hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
481 }
482 else
483 {
484 hr = IDataObject_Constructor (hwndOwner, pidlRoot, (LPCITEMIDLIST*)&pidlRoot, 1, (IDataObject **)&pObj);
485 }
486 }
487 else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
488 {
489 pidl = ILCombine (pidlRoot, apidl[0]);
490 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
491 SHFree (pidl);
492 hr = S_OK;
493 }
494 else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
495 {
496 pidl = ILCombine (pidlRoot, apidl[0]);
497 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
498 SHFree (pidl);
499 hr = S_OK;
500 }
501 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
502 hr = this->QueryInterface(IID_IDropTarget, (LPVOID*)&pObj);
503 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
504 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
505 {
506 pidl = ILCombine (pidlRoot, apidl[0]);
507 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
508 SHFree (pidl);
509 }
510 else
511 hr = E_NOINTERFACE;
512
513 if (SUCCEEDED(hr) && !pObj)
514 hr = E_OUTOFMEMORY;
515
516 *ppvOut = pObj;
517 }
518 TRACE("(%p)->hr=0x%08x\n", this, hr);
519 return hr;
520 }
521
522 static const WCHAR AdvancedW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
523 static const WCHAR HideFileExtW[] = L"HideFileExt";
524 static const WCHAR NeverShowExtW[] = L"NeverShowExt";
525
526 /******************************************************************************
527 * SHELL_FS_HideExtension [Internal]
528 *
529 * Query the registry if the filename extension of a given path should be
530 * hidden.
531 *
532 * PARAMS
533 * szPath [I] Relative or absolute path of a file
534 *
535 * RETURNS
536 * TRUE, if the filename's extension should be hidden
537 * FALSE, otherwise.
538 */
539 BOOL SHELL_FS_HideExtension(LPWSTR szPath)
540 {
541 HKEY hKey;
542 DWORD dwData;
543 DWORD dwDataSize = sizeof (DWORD);
544 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
545
546 if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
547 if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
548 doHide = dwData;
549 RegCloseKey (hKey);
550 }
551
552 if (!doHide) {
553 LPWSTR ext = PathFindExtensionW(szPath);
554
555 if (*ext != '\0') {
556 WCHAR classname[MAX_PATH];
557 LONG classlen = sizeof(classname);
558
559 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
560 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
561 if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
562 doHide = TRUE;
563 RegCloseKey(hKey);
564 }
565 }
566 }
567 return doHide;
568 }
569
570 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
571 {
572 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
573 if (!(dwFlags & SHGDN_FORPARSING) &&
574 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
575 if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
576 PathRemoveExtensionW(szPath);
577 }
578 }
579
580 /**************************************************************************
581 * CFSFolder::GetDisplayNameOf
582 * Retrieves the display name for the specified file object or subfolder
583 *
584 * PARAMETERS
585 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
586 * DWORD dwFlags, //[in ] SHGNO formatting flags
587 * LPSTRRET lpName) //[out] Returned display name
588 *
589 * FIXME
590 * if the name is in the pidl the ret value should be a STRRET_OFFSET
591 */
592
593 HRESULT WINAPI CFSFolder::GetDisplayNameOf(LPCITEMIDLIST pidl,
594 DWORD dwFlags, LPSTRRET strRet)
595 {
596 LPWSTR pszPath;
597
598 HRESULT hr = S_OK;
599 int len = 0;
600
601 TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
602 pdump(pidl);
603
604 if (!pidl || !strRet)
605 return E_INVALIDARG;
606
607 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
608 if (!pszPath)
609 return E_OUTOFMEMORY;
610
611 if (_ILIsDesktop(pidl)) /* empty pidl */
612 {
613 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
614 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
615 {
616 if (sPathTarget)
617 lstrcpynW(pszPath, sPathTarget, MAX_PATH);
618 }
619 else
620 hr = E_INVALIDARG; /* pidl has to contain exactly one non null SHITEMID */
621 }
622 else if (_ILIsPidlSimple(pidl))
623 {
624 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
625 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
626 sPathTarget)
627 {
628 lstrcpynW(pszPath, sPathTarget, MAX_PATH);
629 PathAddBackslashW(pszPath);
630 len = wcslen(pszPath);
631 }
632 _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
633 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
634 } else
635 hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
636
637 if (SUCCEEDED(hr)) {
638 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
639 if (GetVersion() & 0x80000000)
640 {
641 strRet->uType = STRRET_CSTR;
642 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
643 NULL, NULL))
644 strRet->cStr[0] = '\0';
645 CoTaskMemFree(pszPath);
646 }
647 else
648 {
649 strRet->uType = STRRET_WSTR;
650 strRet->pOleStr = pszPath;
651 }
652 } else
653 CoTaskMemFree(pszPath);
654
655 TRACE ("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
656 return hr;
657 }
658
659 /**************************************************************************
660 * CFSFolder::SetNameOf
661 * Changes the name of a file object or subfolder, possibly changing its item
662 * identifier in the process.
663 *
664 * PARAMETERS
665 * HWND hwndOwner, //[in ] Owner window for output
666 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
667 * LPCOLESTR lpszName, //[in ] the items new display name
668 * DWORD dwFlags, //[in ] SHGNO formatting flags
669 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
670 */
671 HRESULT WINAPI CFSFolder::SetNameOf(
672 HWND hwndOwner,
673 LPCITEMIDLIST pidl,
674 LPCOLESTR lpName,
675 DWORD dwFlags,
676 LPITEMIDLIST * pPidlOut)
677 {
678 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
679 LPWSTR ptr;
680 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
681
682 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
683 debugstr_w (lpName), dwFlags, pPidlOut);
684
685 /* build source path */
686 lstrcpynW(szSrc, sPathTarget, MAX_PATH);
687 ptr = PathAddBackslashW (szSrc);
688 if (ptr)
689 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
690
691 /* build destination path */
692 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
693 lstrcpynW(szDest, sPathTarget, MAX_PATH);
694 ptr = PathAddBackslashW (szDest);
695 if (ptr)
696 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
697 } else
698 lstrcpynW(szDest, lpName, MAX_PATH);
699
700 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
701 WCHAR *ext = PathFindExtensionW(szSrc);
702 if(*ext != '\0') {
703 INT len = wcslen(szDest);
704 lstrcpynW(szDest + len, ext, MAX_PATH - len);
705 }
706 }
707
708 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
709 if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
710 {
711 /* src and destination is the same */
712 HRESULT hr = S_OK;
713 if (pPidlOut)
714 hr = _ILCreateFromPathW(szDest, pPidlOut);
715
716 return hr;
717 }
718
719
720 if (MoveFileW (szSrc, szDest))
721 {
722 HRESULT hr = S_OK;
723
724 if (pPidlOut)
725 hr = _ILCreateFromPathW(szDest, pPidlOut);
726
727 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
728 SHCNF_PATHW, szSrc, szDest);
729
730 return hr;
731 }
732
733 return E_FAIL;
734 }
735
736 HRESULT WINAPI CFSFolder::GetDefaultSearchGUID(GUID * pguid)
737 {
738 FIXME ("(%p)\n", this);
739 return E_NOTIMPL;
740 }
741
742 HRESULT WINAPI CFSFolder::EnumSearches(IEnumExtraSearch ** ppenum)
743 {
744 FIXME ("(%p)\n", this);
745 return E_NOTIMPL;
746 }
747
748 HRESULT WINAPI CFSFolder::GetDefaultColumn(DWORD dwRes,
749 ULONG * pSort, ULONG * pDisplay)
750 {
751 TRACE ("(%p)\n", this);
752
753 if (pSort)
754 *pSort = 0;
755 if (pDisplay)
756 *pDisplay = 0;
757
758 return S_OK;
759 }
760
761 HRESULT WINAPI CFSFolder::GetDefaultColumnState(UINT iColumn,
762 DWORD * pcsFlags)
763 {
764 TRACE ("(%p)\n", this);
765
766 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
767 return E_INVALIDARG;
768
769 *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
770
771 return S_OK;
772 }
773
774 HRESULT WINAPI CFSFolder::GetDetailsEx(LPCITEMIDLIST pidl,
775 const SHCOLUMNID * pscid, VARIANT * pv)
776 {
777 FIXME ("(%p)\n", this);
778
779 return E_NOTIMPL;
780 }
781
782 HRESULT WINAPI CFSFolder::GetDetailsOf(LPCITEMIDLIST pidl,
783 UINT iColumn, SHELLDETAILS * psd)
784 {
785 HRESULT hr = E_FAIL;
786
787 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
788
789 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
790 return E_INVALIDARG;
791
792 if (!pidl)
793 {
794 /* the header titles */
795 psd->fmt = GenericSFHeader[iColumn].fmt;
796 psd->cxChar = GenericSFHeader[iColumn].cxChar;
797 psd->str.uType = STRRET_CSTR;
798 LoadStringA(shell32_hInstance, GenericSFHeader[iColumn].colnameid,
799 psd->str.cStr, MAX_PATH);
800 return S_OK;
801 }
802 else
803 {
804 hr = S_OK;
805 psd->str.uType = STRRET_CSTR;
806 /* the data from the pidl */
807 switch (iColumn)
808 {
809 case 0: /* name */
810 hr = GetDisplayNameOf (pidl,
811 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
812 break;
813 case 1: /* size */
814 _ILGetFileSize(pidl, psd->str.cStr, MAX_PATH);
815 break;
816 case 2: /* type */
817 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
818 break;
819 case 3: /* date */
820 _ILGetFileDate(pidl, psd->str.cStr, MAX_PATH);
821 break;
822 case 4: /* attributes */
823 _ILGetFileAttributes(pidl, psd->str.cStr, MAX_PATH);
824 break;
825 }
826 }
827
828 return hr;
829 }
830
831 HRESULT WINAPI CFSFolder::MapColumnToSCID (UINT column,
832 SHCOLUMNID * pscid)
833 {
834 FIXME ("(%p)\n", this);
835 return E_NOTIMPL;
836 }
837
838 /****************************************************************************
839 * ISFHelper for IShellFolder implementation
840 */
841
842 /****************************************************************************
843 * CFSFolder::GetUniqueName
844 *
845 * creates a unique folder name
846 */
847
848 HRESULT WINAPI CFSFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
849 {
850 IEnumIDList *penum;
851 HRESULT hr;
852 WCHAR wszText[MAX_PATH];
853 WCHAR wszNewFolder[25];
854 const WCHAR wszFormat[] = L"%s %d";
855
856 LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder));
857
858 TRACE ("(%p)(%p %u)\n", this, pwszName, uLen);
859
860 if (uLen < _countof(wszNewFolder) + 3)
861 return E_POINTER;
862
863 lstrcpynW (pwszName, wszNewFolder, uLen);
864
865 hr = EnumObjects(0, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
866 if (penum)
867 {
868 LPITEMIDLIST pidl;
869 DWORD dwFetched;
870 int i = 1;
871
872 next:
873 penum->Reset ();
874 while (S_OK == penum->Next(1, &pidl, &dwFetched) && dwFetched)
875 {
876 _ILSimpleGetTextW(pidl, wszText, MAX_PATH);
877 if (0 == lstrcmpiW(wszText, pwszName))
878 {
879 _snwprintf(pwszName, uLen, wszFormat, wszNewFolder, i++);
880 if (i > 99)
881 {
882 hr = E_FAIL;
883 break;
884 }
885 goto next;
886 }
887 }
888
889 penum->Release();
890 }
891 return hr;
892 }
893
894 /****************************************************************************
895 * CFSFolder::AddFolder
896 *
897 * adds a new folder.
898 */
899
900 HRESULT WINAPI CFSFolder::AddFolder(HWND hwnd, LPCWSTR pwszName,
901 LPITEMIDLIST * ppidlOut)
902 {
903 WCHAR wszNewDir[MAX_PATH];
904 DWORD bRes;
905 HRESULT hres = E_FAIL;
906
907 TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName), ppidlOut);
908
909 wszNewDir[0] = 0;
910 if (sPathTarget)
911 lstrcpynW(wszNewDir, sPathTarget, MAX_PATH);
912 PathAppendW(wszNewDir, pwszName);
913
914 bRes = CreateDirectoryW(wszNewDir, NULL);
915 if (bRes)
916 {
917 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL);
918
919 hres = S_OK;
920
921 if (ppidlOut)
922 hres = _ILCreateFromPathW(wszNewDir, ppidlOut);
923 }
924 else
925 {
926 WCHAR wszText[128 + MAX_PATH];
927 WCHAR wszTempText[128];
928 WCHAR wszCaption[256];
929
930 /* Cannot Create folder because of permissions */
931 LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
932 _countof(wszTempText));
933 LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
934 _countof(wszCaption));
935 swprintf(wszText, wszTempText, wszNewDir);
936 MessageBoxW(hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
937 }
938
939 return hres;
940 }
941
942 /****************************************************************************
943 * BuildPathsList
944 *
945 * Builds a list of paths like the one used in SHFileOperation from a table of
946 * PIDLs relative to the given base folder
947 */
948 WCHAR *
949 BuildPathsList(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls)
950 {
951 WCHAR *pwszPathsList;
952 WCHAR *pwszListPos;
953 int iPathLen, i;
954
955 iPathLen = wcslen(wszBasePath);
956 pwszPathsList = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) * cidl + 1);
957 pwszListPos = pwszPathsList;
958
959 for (i = 0; i < cidl; i++)
960 {
961 if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i]))
962 continue;
963
964 wcscpy(pwszListPos, wszBasePath);
965 pwszListPos += iPathLen;
966 /* FIXME: abort if path too long */
967 _ILSimpleGetTextW(pidls[i], pwszListPos, MAX_PATH - iPathLen);
968 pwszListPos += wcslen(pwszListPos) + 1;
969 }
970 *pwszListPos = 0;
971 return pwszPathsList;
972 }
973
974 /****************************************************************************
975 * CFSFolder::DeleteItems
976 *
977 * deletes items in folder
978 */
979 HRESULT WINAPI CFSFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
980 {
981 UINT i;
982 SHFILEOPSTRUCTW op;
983 WCHAR wszPath[MAX_PATH];
984 WCHAR *wszPathsList;
985 HRESULT ret;
986 WCHAR *wszCurrentPath;
987
988 TRACE ("(%p)(%u %p)\n", this, cidl, apidl);
989 if (cidl == 0) return S_OK;
990
991 if (sPathTarget)
992 lstrcpynW(wszPath, sPathTarget, MAX_PATH);
993 else
994 wszPath[0] = '\0';
995 PathAddBackslashW(wszPath);
996 wszPathsList = BuildPathsList(wszPath, cidl, apidl);
997
998 ZeroMemory(&op, sizeof(op));
999 op.hwnd = GetActiveWindow();
1000 op.wFunc = FO_DELETE;
1001 op.pFrom = wszPathsList;
1002 op.fFlags = FOF_ALLOWUNDO;
1003 if (SHFileOperationW(&op))
1004 {
1005 WARN("SHFileOperation failed\n");
1006 ret = E_FAIL;
1007 }
1008 else
1009 ret = S_OK;
1010
1011 /* we currently need to manually send the notifies */
1012 wszCurrentPath = wszPathsList;
1013 for (i = 0; i < cidl; i++)
1014 {
1015 LONG wEventId;
1016
1017 if (_ILIsFolder(apidl[i]))
1018 wEventId = SHCNE_RMDIR;
1019 else if (_ILIsValue(apidl[i]))
1020 wEventId = SHCNE_DELETE;
1021 else
1022 continue;
1023
1024 /* check if file exists */
1025 if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1026 {
1027 LPITEMIDLIST pidl = ILCombine(pidlRoot, apidl[i]);
1028 SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1029 SHFree(pidl);
1030 }
1031
1032 wszCurrentPath += wcslen(wszCurrentPath) + 1;
1033 }
1034 HeapFree(GetProcessHeap(), 0, wszPathsList);
1035 return ret;
1036 }
1037
1038 /****************************************************************************
1039 * CFSFolder::CopyItems
1040 *
1041 * copies items to this folder
1042 */
1043 HRESULT WINAPI CFSFolder::CopyItems(IShellFolder * pSFFrom, UINT cidl,
1044 LPCITEMIDLIST * apidl, bool bCopy)
1045 {
1046 IPersistFolder2 *ppf2 = NULL;
1047 WCHAR szSrcPath[MAX_PATH];
1048 WCHAR szTargetPath[MAX_PATH];
1049 SHFILEOPSTRUCTW op;
1050 LPITEMIDLIST pidl;
1051 LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList, pszFileName;
1052 int res, length;
1053 HRESULT hr;
1054 STRRET strRet;
1055
1056 TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl);
1057
1058 hr = pSFFrom->QueryInterface (IID_PPV_ARG(IPersistFolder2, &ppf2));
1059 if (SUCCEEDED(hr))
1060 {
1061 hr = ppf2->GetCurFolder(&pidl);
1062 if (FAILED(hr))
1063 {
1064 ppf2->Release();
1065 return hr;
1066 }
1067 ppf2->Release();
1068
1069 hr = pSFFrom->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet);
1070 if (FAILED(hr))
1071 {
1072 SHFree(pidl);
1073 return hr;
1074 }
1075
1076 hr = StrRetToBufW(&strRet, pidl, szSrcPath, MAX_PATH);
1077 if (FAILED(hr))
1078 {
1079 SHFree(pidl);
1080 return hr;
1081 }
1082 SHFree(pidl);
1083
1084 pszSrc = PathAddBackslashW(szSrcPath);
1085
1086 wcscpy(szTargetPath, sPathTarget);
1087 pszTarget = PathAddBackslashW(szTargetPath);
1088
1089 pszSrcList = BuildPathsList(szSrcPath, cidl, apidl);
1090 pszTargetList = BuildPathsList(szTargetPath, cidl, apidl);
1091
1092 if (!pszSrcList || !pszTargetList)
1093 {
1094 if (pszSrcList)
1095 HeapFree(GetProcessHeap(), 0, pszSrcList);
1096
1097 if (pszTargetList)
1098 HeapFree(GetProcessHeap(), 0, pszTargetList);
1099
1100 SHFree(pidl);
1101 ppf2->Release();
1102 return E_OUTOFMEMORY;
1103 }
1104
1105 ZeroMemory(&op, sizeof(op));
1106 if (!pszSrcList[0])
1107 {
1108 /* remove trailing backslash */
1109 pszSrc--;
1110 pszSrc[0] = L'\0';
1111 op.pFrom = szSrcPath;
1112 }
1113 else
1114 {
1115 op.pFrom = pszSrcList;
1116 }
1117
1118 if (!pszTargetList[0])
1119 {
1120 /* remove trailing backslash */
1121 if (pszTarget - szTargetPath > 3)
1122 {
1123 pszTarget--;
1124 pszTarget[0] = L'\0';
1125 }
1126 else
1127 {
1128 pszTarget[1] = L'\0';
1129 }
1130
1131 op.pTo = szTargetPath;
1132 op.fFlags = 0;
1133 }
1134 else
1135 {
1136 op.pTo = pszTargetList;
1137 op.fFlags = FOF_MULTIDESTFILES;
1138 }
1139 op.hwnd = GetActiveWindow();
1140 op.wFunc = bCopy ? FO_COPY : FO_MOVE;
1141 op.fFlags |= FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
1142
1143 res = SHFileOperationW(&op);
1144
1145 if (res == DE_SAMEFILE)
1146 {
1147 length = wcslen(szTargetPath);
1148
1149 pszFileName = wcsrchr(pszSrcList, '\\');
1150 pszFileName++;
1151
1152 if (LoadStringW(shell32_hInstance, IDS_COPY_OF, pszTarget, MAX_PATH - length))
1153 {
1154 wcscat(szTargetPath, L" ");
1155 }
1156
1157 wcscat(szTargetPath, pszFileName);
1158 op.pTo = szTargetPath;
1159
1160 res = SHFileOperationW(&op);
1161 }
1162
1163 HeapFree(GetProcessHeap(), 0, pszSrcList);
1164 HeapFree(GetProcessHeap(), 0, pszTargetList);
1165
1166 if (res)
1167 return E_FAIL;
1168 else
1169 return S_OK;
1170 }
1171 return E_FAIL;
1172 }
1173
1174 /************************************************************************
1175 * CFSFolder::GetClassID
1176 */
1177 HRESULT WINAPI CFSFolder::GetClassID(CLSID * lpClassId)
1178 {
1179 TRACE ("(%p)\n", this);
1180
1181 if (!lpClassId)
1182 return E_POINTER;
1183
1184 *lpClassId = *pclsid;
1185
1186 return S_OK;
1187 }
1188
1189 /************************************************************************
1190 * CFSFolder::Initialize
1191 *
1192 * NOTES
1193 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1194 */
1195 HRESULT WINAPI CFSFolder::Initialize(LPCITEMIDLIST pidl)
1196 {
1197 WCHAR wszTemp[MAX_PATH];
1198
1199 TRACE ("(%p)->(%p)\n", this, pidl);
1200
1201 SHFree (pidlRoot); /* free the old pidl */
1202 pidlRoot = ILClone (pidl); /* set my pidl */
1203
1204 SHFree (sPathTarget);
1205 sPathTarget = NULL;
1206
1207 /* set my path */
1208 if (SHGetPathFromIDListW (pidl, wszTemp))
1209 {
1210 int len = wcslen(wszTemp);
1211 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
1212 if (!sPathTarget)
1213 return E_OUTOFMEMORY;
1214 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1215 }
1216
1217 TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget));
1218 return S_OK;
1219 }
1220
1221 /**************************************************************************
1222 * CFSFolder::GetCurFolder
1223 */
1224 HRESULT WINAPI CFSFolder::GetCurFolder(LPITEMIDLIST * pidl)
1225 {
1226 TRACE ("(%p)->(%p)\n", this, pidl);
1227
1228 if (!pidl)
1229 return E_POINTER;
1230
1231 *pidl = ILClone(pidlRoot);
1232 return S_OK;
1233 }
1234
1235 /**************************************************************************
1236 * CFSFolder::InitializeEx
1237 *
1238 * FIXME: error handling
1239 */
1240 HRESULT WINAPI CFSFolder::InitializeEx(IBindCtx * pbc, LPCITEMIDLIST pidlRootx,
1241 const PERSIST_FOLDER_TARGET_INFO * ppfti)
1242 {
1243 WCHAR wszTemp[MAX_PATH];
1244
1245 TRACE("(%p)->(%p,%p,%p)\n", this, pbc, pidlRootx, ppfti);
1246 if (ppfti)
1247 TRACE("--%p %s %s 0x%08x 0x%08x\n",
1248 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1249 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1250 ppfti->csidl);
1251
1252 pdump (pidlRootx);
1253 if (ppfti && ppfti->pidlTargetFolder)
1254 pdump(ppfti->pidlTargetFolder);
1255
1256 if (pidlRoot)
1257 __SHFreeAndNil(&pidlRoot); /* free the old */
1258 if (sPathTarget)
1259 __SHFreeAndNil(&sPathTarget);
1260
1261 /*
1262 * Root path and pidl
1263 */
1264 pidlRoot = ILClone(pidlRootx);
1265
1266 /*
1267 * the target folder is spezified in csidl OR pidlTargetFolder OR
1268 * szTargetParsingName
1269 */
1270 if (ppfti)
1271 {
1272 if (ppfti->csidl != -1)
1273 {
1274 if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl,
1275 ppfti->csidl & CSIDL_FLAG_CREATE)) {
1276 int len = wcslen(wszTemp);
1277 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
1278 if (!sPathTarget)
1279 return E_OUTOFMEMORY;
1280 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1281 }
1282 }
1283 else if (ppfti->szTargetParsingName[0])
1284 {
1285 int len = wcslen(ppfti->szTargetParsingName);
1286 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
1287 if (!sPathTarget)
1288 return E_OUTOFMEMORY;
1289 memcpy(sPathTarget, ppfti->szTargetParsingName,
1290 (len + 1) * sizeof(WCHAR));
1291 }
1292 else if (ppfti->pidlTargetFolder)
1293 {
1294 if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp))
1295 {
1296 int len = wcslen(wszTemp);
1297 sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
1298 if (!sPathTarget)
1299 return E_OUTOFMEMORY;
1300 memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1301 }
1302 }
1303 }
1304
1305 TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget));
1306 pdump(pidlRoot);
1307 return (sPathTarget) ? S_OK : E_FAIL;
1308 }
1309
1310 HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti)
1311 {
1312 FIXME("(%p)->(%p)\n", this, ppfti);
1313 ZeroMemory(ppfti, sizeof (*ppfti));
1314 return E_NOTIMPL;
1315 }
1316
1317 /****************************************************************************
1318 * ISFDropTarget implementation
1319 */
1320 BOOL CFSFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
1321 {
1322 DWORD dwEffect = *pdwEffect;
1323
1324 *pdwEffect = DROPEFFECT_NONE;
1325
1326 if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
1327 *pdwEffect = KeyStateToDropEffect (dwKeyState);
1328
1329 /* ... matches the desired effect ? */
1330 if (dwEffect & *pdwEffect) {
1331 return TRUE;
1332 }
1333 }
1334 return FALSE;
1335 }
1336
1337 HRESULT WINAPI CFSFolder::DragEnter(IDataObject *pDataObject,
1338 DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
1339 {
1340 FORMATETC fmt;
1341
1342 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
1343
1344 InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
1345
1346 fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ?
1347 TRUE : FALSE;
1348
1349 QueryDrop(dwKeyState, pdwEffect);
1350
1351 return S_OK;
1352 }
1353
1354 HRESULT WINAPI CFSFolder::DragOver(DWORD dwKeyState, POINTL pt,
1355 DWORD *pdwEffect)
1356 {
1357 TRACE("(%p)\n", this);
1358
1359 if (!pdwEffect)
1360 return E_INVALIDARG;
1361
1362 QueryDrop(dwKeyState, pdwEffect);
1363
1364 return S_OK;
1365 }
1366
1367 HRESULT WINAPI CFSFolder::DragLeave()
1368 {
1369 TRACE("(%p)\n", this);
1370
1371 fAcceptFmt = FALSE;
1372
1373 return S_OK;
1374 }
1375
1376 HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
1377 DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
1378 {
1379 FIXME("(%p) object dropped\n", this);
1380
1381 return E_NOTIMPL;
1382 }