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