cmd: DIR command outputs free space for the path.
[wine.git] / dlls / shell32 / shfldr_fs.c
blob54828f99acca34d9040fadb96edc1e57f63fa672
2 /*
3 * file system folder
5 * Copyright 1997 Marcus Meissner
6 * Copyright 1998, 1999, 2002 Juergen Schmied
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.
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.
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
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <stdio.h>
28 #define COBJMACROS
29 #include "winerror.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winuser.h"
36 #include "ole2.h"
37 #include "shlguid.h"
39 #include "pidl.h"
40 #include "shell32_main.h"
41 #include "shresdef.h"
42 #include "shlwapi.h"
43 #include "shellfolder.h"
44 #include "wine/debug.h"
45 #include "debughlp.h"
46 #include "shfldr.h"
48 WINE_DEFAULT_DEBUG_CHANNEL (shell);
50 /***********************************************************************
51 * IShellFolder implementation
54 typedef struct {
55 IUnknown IUnknown_inner;
56 LONG ref;
57 IShellFolder2 IShellFolder2_iface;
58 IPersistFolder3 IPersistFolder3_iface;
59 IPersistPropertyBag IPersistPropertyBag_iface;
60 IDropTarget IDropTarget_iface;
61 ISFHelper ISFHelper_iface;
62 IUnknown *outer_unk;
64 const CLSID *pclsid;
66 /* both paths are parsible from the desktop */
67 LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
69 LPITEMIDLIST pidlRoot; /* absolute pidl */
70 DWORD drop_effects_mask;
71 } IGenericSFImpl;
73 static UINT cfShellIDList;
75 static inline IGenericSFImpl *impl_from_IUnknown(IUnknown *iface)
77 return CONTAINING_RECORD(iface, IGenericSFImpl, IUnknown_inner);
80 static inline IGenericSFImpl *impl_from_IShellFolder2(IShellFolder2 *iface)
82 return CONTAINING_RECORD(iface, IGenericSFImpl, IShellFolder2_iface);
85 static inline IGenericSFImpl *impl_from_IPersistFolder3(IPersistFolder3 *iface)
87 return CONTAINING_RECORD(iface, IGenericSFImpl, IPersistFolder3_iface);
90 static inline IGenericSFImpl *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface)
92 return CONTAINING_RECORD(iface, IGenericSFImpl, IPersistPropertyBag_iface);
95 static inline IGenericSFImpl *impl_from_IDropTarget(IDropTarget *iface)
97 return CONTAINING_RECORD(iface, IGenericSFImpl, IDropTarget_iface);
100 static inline IGenericSFImpl *impl_from_ISFHelper(ISFHelper *iface)
102 return CONTAINING_RECORD(iface, IGenericSFImpl, ISFHelper_iface);
105 /**************************************************************************
106 * inner IUnknown
108 static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, void **ppvObj)
110 IGenericSFImpl *This = impl_from_IUnknown(iface);
112 TRACE("(%p)->(%s,%p)\n", This, shdebugstr_guid(riid), ppvObj);
114 *ppvObj = NULL;
116 if (IsEqualIID (riid, &IID_IUnknown))
117 *ppvObj = &This->IUnknown_inner;
118 else if (IsEqualIID(riid, &IID_IShellFolder) || IsEqualIID(riid, &IID_IShellFolder2))
119 *ppvObj = &This->IShellFolder2_iface;
120 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IPersistFolder) ||
121 IsEqualIID(riid, &IID_IPersistFolder2) || IsEqualIID(riid, &IID_IPersistFolder3))
122 *ppvObj = &This->IPersistFolder3_iface;
123 else if (IsEqualIID(&IID_IPersistPropertyBag, riid))
124 *ppvObj = &This->IPersistPropertyBag_iface;
125 else if (IsEqualIID (riid, &IID_ISFHelper))
126 *ppvObj = &This->ISFHelper_iface;
127 else if (IsEqualIID (riid, &IID_IDropTarget)) {
128 *ppvObj = &This->IDropTarget_iface;
129 if (!cfShellIDList) cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
132 if (*ppvObj) {
133 IUnknown_AddRef((IUnknown *)*ppvObj);
134 TRACE ("-- Interface = %p\n", *ppvObj);
135 return S_OK;
137 TRACE ("-- Interface: E_NOINTERFACE\n");
138 return E_NOINTERFACE;
141 static ULONG WINAPI IUnknown_fnAddRef(IUnknown *iface)
143 IGenericSFImpl *This = impl_from_IUnknown(iface);
144 ULONG ref = InterlockedIncrement(&This->ref);
146 TRACE("(%p) ref=%ld\n", This, ref);
148 return ref;
151 static ULONG WINAPI IUnknown_fnRelease(IUnknown *iface)
153 IGenericSFImpl *This = impl_from_IUnknown(iface);
154 ULONG ref = InterlockedDecrement(&This->ref);
156 TRACE("(%p) ref=%ld\n", This, ref);
158 if (!ref) {
159 TRACE("-- destroying IShellFolder(%p)\n", This);
161 SHFree(This->pidlRoot);
162 SHFree(This->sPathTarget);
163 LocalFree(This);
165 return ref;
168 static const IUnknownVtbl unkvt =
170 IUnknown_fnQueryInterface,
171 IUnknown_fnAddRef,
172 IUnknown_fnRelease,
175 static const shvheader GenericSFHeader[] =
177 { &FMTID_Storage, PID_STG_NAME, IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15 },
178 { &FMTID_Storage, PID_STG_SIZE, IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10 },
179 { &FMTID_Storage, PID_STG_STORAGETYPE, IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10 },
180 { &FMTID_Storage, PID_STG_WRITETIME, IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12 },
181 { &FMTID_Storage, PID_STG_ATTRIBUTES, IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5 },
184 #define GENERICSHELLVIEWCOLUMNS 5
186 /**************************************************************************
187 * IShellFolder_fnQueryInterface
189 static HRESULT WINAPI IShellFolder_fnQueryInterface(IShellFolder2 *iface, REFIID riid,
190 void **ppvObj)
192 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
194 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
197 /**************************************************************************
198 * IShellFolder_AddRef
200 static ULONG WINAPI IShellFolder_fnAddRef(IShellFolder2 *iface)
202 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
204 return IUnknown_AddRef(This->outer_unk);
207 /**************************************************************************
208 * IShellFolder_fnRelease
210 static ULONG WINAPI IShellFolder_fnRelease(IShellFolder2 *iface)
212 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
214 return IUnknown_Release(This->outer_unk);
217 /**************************************************************************
218 * SHELL32_CreatePidlFromBindCtx [internal]
220 * If the caller bound File System Bind Data, assume it is the
221 * find data for the path.
222 * This allows binding of paths that don't exist.
224 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
226 IFileSystemBindData *fsbd = NULL;
227 LPITEMIDLIST pidl = NULL;
228 IUnknown *unk = NULL;
229 HRESULT r;
231 TRACE("%p %s\n", pbc, debugstr_w(path));
233 if (!pbc)
234 return NULL;
236 /* see if the caller bound File System Bind Data */
237 r = IBindCtx_GetObjectParam( pbc, (WCHAR *)L"File System Bind Data", &unk );
238 if (FAILED(r))
239 return NULL;
241 r = IUnknown_QueryInterface( unk, &IID_IFileSystemBindData, (void**)&fsbd );
242 if (SUCCEEDED(r))
244 WIN32_FIND_DATAW wfd;
246 r = IFileSystemBindData_GetFindData( fsbd, &wfd );
247 if (SUCCEEDED(r))
249 lstrcpynW( &wfd.cFileName[0], path, MAX_PATH );
250 pidl = _ILCreateFromFindDataW( &wfd );
252 IFileSystemBindData_Release( fsbd );
254 IUnknown_Release( unk );
256 return pidl;
259 /**************************************************************************
260 * IShellFolder_ParseDisplayName {SHELL32}
262 * Parse a display name.
264 * PARAMS
265 * hwndOwner [in] Parent window for any message's
266 * pbc [in] optional FileSystemBindData context
267 * lpszDisplayName [in] Unicode displayname.
268 * pchEaten [out] (unicode) characters processed
269 * ppidl [out] complex pidl to item
270 * pdwAttributes [out] items attributes
272 * NOTES
273 * Every folder tries to parse only its own (the leftmost) pidl and creates a
274 * subfolder to evaluate the remaining parts.
275 * Now we can parse into namespaces implemented by shell extensions
277 * Behaviour on win98: lpszDisplayName=NULL -> crash
278 * lpszDisplayName="" -> returns mycomputer-pidl
280 * FIXME
281 * pdwAttributes is not set
282 * pchEaten is not set like in windows
284 static HRESULT WINAPI
285 IShellFolder_fnParseDisplayName (IShellFolder2 * iface,
286 HWND hwndOwner,
287 LPBC pbc,
288 LPOLESTR lpszDisplayName,
289 DWORD * pchEaten, LPITEMIDLIST * ppidl,
290 DWORD * pdwAttributes)
292 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
294 HRESULT hr = S_OK;
295 LPCWSTR szNext = NULL;
296 WCHAR *p, szPath[MAX_PATH];
297 WIN32_FIND_DATAW find_data = { 0 };
298 IFileSystemBindData *fsbd = NULL;
299 LPITEMIDLIST pidlTemp = NULL;
300 DWORD len;
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);
306 if (!lpszDisplayName || !lpszDisplayName[0] || !ppidl) return E_INVALIDARG;
308 if (pchEaten)
309 *pchEaten = 0; /* strange but like the original */
311 if (pbc)
313 IUnknown *unk;
315 /* see if the caller bound File System Bind Data */
316 if (SUCCEEDED( IBindCtx_GetObjectParam( pbc, (WCHAR *)L"File System Bind Data", &unk )))
318 IUnknown_QueryInterface( unk, &IID_IFileSystemBindData, (void**)&fsbd );
319 IUnknown_Release( unk );
323 if (*lpszDisplayName)
325 /* build the full pathname to the element */
326 lstrcpynW(szPath, This->sPathTarget, MAX_PATH - 1);
327 PathAddBackslashW(szPath);
328 len = lstrlenW(szPath);
329 /* get the next element */
330 szNext = GetNextElementW( lpszDisplayName, szPath + len, MAX_PATH - len );
332 if (IsEqualCLSID( This->pclsid, &CLSID_UnixFolder ) && lpszDisplayName[0] == '/')
334 lstrcpynW( szPath + len, lpszDisplayName + 1, MAX_PATH - len );
335 for (p = szPath + len; *p; p++) if (*p == '/') *p = '\\';
337 else if (!wcsnicmp( lpszDisplayName, L"\\\\?\\unix\\", 9 ))
339 lstrcpynW( szPath + len, lpszDisplayName + 9, MAX_PATH - len );
340 if ((p = wcschr( szPath + len, '\\' )))
341 while (*p == '\\') *p++ = 0;
342 szNext = p;
345 /* Special case for the root folder. */
346 if (!wcsicmp( szPath, L"\\\\?\\unix\\" ))
348 *ppidl = SHAlloc(sizeof(**ppidl));
349 if (!*ppidl) return E_FAIL;
350 (*ppidl)->mkid.cb = 0; /* Terminate the ITEMIDLIST */
351 return S_OK;
354 PathRemoveBackslashW( szPath );
356 if (szNext && *szNext)
358 hr = _ILCreateFromPathW( szPath, &pidlTemp );
359 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) && fsbd)
361 find_data.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
362 lstrcpyW( find_data.cFileName, szPath + len );
363 pidlTemp = _ILCreateFromFindDataW( &find_data );
365 if (pidlTemp) /* try to analyse the next element */
366 hr = SHELL32_ParseNextElement( iface, hwndOwner, pbc, &pidlTemp,
367 (WCHAR *)szNext, pchEaten, pdwAttributes );
369 else /* it's the last element */
371 if (fsbd)
373 if (FAILED( IFileSystemBindData_GetFindData( fsbd, &find_data )))
374 find_data.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
375 lstrcpyW( find_data.cFileName, szPath + len );
376 pidlTemp = _ILCreateFromFindDataW( &find_data );
378 else hr = _ILCreateFromPathW(szPath, &pidlTemp);
380 if (pidlTemp && pdwAttributes && *pdwAttributes)
381 hr = SHELL32_GetItemAttributes(&This->IShellFolder2_iface, pidlTemp, pdwAttributes);
385 if (SUCCEEDED(hr))
386 *ppidl = pidlTemp;
387 else
388 *ppidl = NULL;
390 TRACE ("(%p)->(-- pidl=%p ret=0x%08lx)\n", This, *ppidl, hr);
392 if (fsbd) IFileSystemBindData_Release( fsbd );
393 return hr;
396 /**************************************************************************
397 * IShellFolder_fnEnumObjects
398 * PARAMETERS
399 * HWND hwndOwner, //[in ] Parent Window
400 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
401 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
403 static HRESULT WINAPI
404 IShellFolder_fnEnumObjects (IShellFolder2 * iface, HWND hwndOwner,
405 DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
407 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
408 IEnumIDListImpl *list;
410 TRACE ("(%p)->(HWND=%p flags=0x%08lx pplist=%p)\n", This, hwndOwner,
411 dwFlags, ppEnumIDList);
413 if (!(list = IEnumIDList_Constructor()))
414 return E_OUTOFMEMORY;
415 CreateFolderEnumList(list, This->sPathTarget, dwFlags);
416 *ppEnumIDList = &list->IEnumIDList_iface;
418 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
420 return S_OK;
423 /**************************************************************************
424 * IShellFolder_fnBindToObject
425 * PARAMETERS
426 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
427 * LPBC pbc, //[in ] optional FileSystemBindData context
428 * REFIID riid, //[in ] Initial Interface
429 * LPVOID* ppvObject //[out] Interface*
431 static HRESULT WINAPI
432 IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl,
433 LPBC pbc, REFIID riid, LPVOID * ppvOut)
435 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
436 const CLSID *clsid = This->pclsid;
438 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbc,
439 shdebugstr_guid (riid), ppvOut);
441 if (!IsEqualCLSID( clsid, &CLSID_UnixFolder ) && !IsEqualCLSID( clsid, &CLSID_UnixDosFolder ))
442 clsid = &CLSID_ShellFSFolder;
444 return SHELL32_BindToChild (This->pidlRoot, clsid, This->sPathTarget, pidl, riid, ppvOut);
447 /**************************************************************************
448 * IShellFolder_fnBindToStorage
449 * PARAMETERS
450 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
451 * LPBC pbc, //[in ] reserved
452 * REFIID riid, //[in ] Initial storage interface
453 * LPVOID* ppvObject //[out] Interface* returned
455 static HRESULT WINAPI
456 IShellFolder_fnBindToStorage (IShellFolder2 * iface, LPCITEMIDLIST pidl,
457 LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
459 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
461 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved,
462 shdebugstr_guid (riid), ppvOut);
464 *ppvOut = NULL;
465 return E_NOTIMPL;
468 /**************************************************************************
469 * IShellFolder_fnCompareIDs
472 static HRESULT WINAPI
473 IShellFolder_fnCompareIDs (IShellFolder2 * iface, LPARAM lParam,
474 LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
476 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
478 int nReturn;
480 TRACE ("(%p)->(0x%08Ix,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
481 nReturn = SHELL32_CompareIDs(&This->IShellFolder2_iface, lParam, pidl1, pidl2);
482 TRACE ("-- %i\n", nReturn);
483 return nReturn;
486 /**************************************************************************
487 * IShellFolder_fnCreateViewObject
489 static HRESULT WINAPI
490 IShellFolder_fnCreateViewObject (IShellFolder2 * iface, HWND hwndOwner,
491 REFIID riid, LPVOID * ppvOut)
493 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
495 LPSHELLVIEW pShellView;
496 HRESULT hr = E_INVALIDARG;
498 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid (riid),
499 ppvOut);
501 if (ppvOut) {
502 *ppvOut = NULL;
504 if (IsEqualIID (riid, &IID_IDropTarget)) {
505 hr = IShellFolder2_QueryInterface (iface, &IID_IDropTarget, ppvOut);
506 } else if (IsEqualIID (riid, &IID_IContextMenu)) {
507 hr = BackgroundMenu_Constructor((IShellFolder*)iface, FALSE, riid, ppvOut);
508 } else if (IsEqualIID (riid, &IID_IShellView)) {
509 pShellView = IShellView_Constructor ((IShellFolder *) iface);
510 if (pShellView) {
511 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
512 IShellView_Release (pShellView);
516 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
517 return hr;
520 /**************************************************************************
521 * IShellFolder_fnGetAttributesOf
523 * PARAMETERS
524 * UINT cidl, //[in ] num elements in pidl array
525 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
526 * ULONG* rgfInOut) //[out] result array
529 static HRESULT WINAPI
530 IShellFolder_fnGetAttributesOf (IShellFolder2 * iface, UINT cidl,
531 LPCITEMIDLIST * apidl, DWORD * rgfInOut)
533 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
535 HRESULT hr = S_OK;
537 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08lx))\n", This, cidl, apidl,
538 rgfInOut, rgfInOut ? *rgfInOut : 0);
540 if (!rgfInOut)
541 return E_INVALIDARG;
542 if (cidl && !apidl)
543 return E_INVALIDARG;
545 if (*rgfInOut == 0)
546 *rgfInOut = ~0;
548 if(cidl == 0){
549 IShellFolder2 *parent = NULL;
550 LPCITEMIDLIST rpidl = NULL;
552 if (_ILIsSpecialFolder(This->pidlRoot))
554 *rgfInOut &= (SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
555 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME);
557 else
559 hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder2, (void **)&parent, &rpidl);
560 if(SUCCEEDED(hr)) {
561 SHELL32_GetItemAttributes(parent, rpidl, rgfInOut);
562 IShellFolder2_Release(parent);
566 else {
567 while (cidl > 0 && *apidl) {
568 pdump (*apidl);
569 SHELL32_GetItemAttributes(&This->IShellFolder2_iface, *apidl, rgfInOut);
570 apidl++;
571 cidl--;
574 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
575 *rgfInOut &= ~SFGAO_VALIDATE;
577 TRACE ("-- result=0x%08lx\n", *rgfInOut);
579 return hr;
582 /**************************************************************************
583 * SHELL32_CreateExtensionUIObject (internal)
585 static HRESULT SHELL32_CreateExtensionUIObject(IShellFolder2 *iface,
586 LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
588 IPersistFile *persist_file;
589 char extensionA[20];
590 WCHAR extensionW[20], buf[MAX_PATH];
591 DWORD size = MAX_PATH;
592 STRRET path;
593 WCHAR *file;
594 GUID guid;
595 HKEY key;
596 HRESULT hr;
599 if(!_ILGetExtension(pidl, extensionA, 20))
600 return S_FALSE;
602 MultiByteToWideChar(CP_ACP, 0, extensionA, -1, extensionW, 20);
604 swprintf(buf, ARRAY_SIZE(buf), L".%s\\ShellEx\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
605 extensionW, riid->Data1, riid->Data2, riid->Data3,
606 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
607 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
609 if(RegGetValueW(HKEY_CLASSES_ROOT, buf, NULL, RRF_RT_REG_SZ,
610 NULL, buf, &size) != ERROR_SUCCESS)
611 return S_FALSE;
613 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Blocked", 0, 0, 0,
614 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
615 return E_FAIL;
616 if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
617 != ERROR_FILE_NOT_FOUND)
618 return E_ACCESSDENIED;
619 RegCloseKey(key);
621 if(RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Blocked", 0, 0, 0,
622 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
623 return E_FAIL;
624 if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
625 != ERROR_FILE_NOT_FOUND)
626 return E_ACCESSDENIED;
627 RegCloseKey(key);
629 if(!GUIDFromStringW(buf, &guid))
630 return E_FAIL;
632 hr = CoCreateInstance(&guid, NULL, CLSCTX_INPROC_SERVER,
633 &IID_IPersistFile, (void**)&persist_file);
634 if(FAILED(hr))
635 return hr;
637 hr = IShellFolder2_GetDisplayNameOf(iface, pidl, SHGDN_FORPARSING, &path);
638 if(SUCCEEDED(hr))
639 hr = StrRetToStrW(&path, NULL, &file);
640 if(FAILED(hr)) {
641 IPersistFile_Release(persist_file);
642 return hr;
645 hr = IPersistFile_Load(persist_file, file, STGM_READ);
646 CoTaskMemFree(file);
647 if(FAILED(hr)) {
648 IPersistFile_Release(persist_file);
649 return hr;
652 hr = IPersistFile_QueryInterface(persist_file, riid, ppvOut);
653 IPersistFile_Release(persist_file);
654 return hr;
657 /**************************************************************************
658 * IShellFolder_fnGetUIObjectOf
660 * PARAMETERS
661 * HWND hwndOwner, //[in ] Parent window for any output
662 * UINT cidl, //[in ] array size
663 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
664 * REFIID riid, //[in ] Requested Interface
665 * UINT* prgfInOut, //[ ] reserved
666 * LPVOID* ppvObject) //[out] Resulting Interface
668 * NOTES
669 * This function gets asked to return "view objects" for one or more (multiple
670 * select) items:
671 * The viewobject typically is an COM object with one of the following
672 * interfaces:
673 * IExtractIcon,IDataObject,IContextMenu
674 * In order to support icon positions in the default Listview your DataObject
675 * must implement the SetData method (in addition to GetData :) - the shell
676 * passes a barely documented "Icon positions" structure to SetData when the
677 * drag starts, and GetData's it if the drop is in another explorer window that
678 * needs the positions.
680 static HRESULT WINAPI
681 IShellFolder_fnGetUIObjectOf (IShellFolder2 * iface,
682 HWND hwndOwner,
683 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
684 UINT * prgfInOut, LPVOID * ppvOut)
686 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
688 LPITEMIDLIST pidl;
689 IUnknown *pObj = NULL;
690 HRESULT hr = E_INVALIDARG;
692 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
693 This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
695 if (ppvOut) {
696 *ppvOut = NULL;
698 if(cidl == 1) {
699 hr = SHELL32_CreateExtensionUIObject(iface, *apidl, riid, ppvOut);
700 if(hr != S_FALSE)
701 return hr;
704 if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1)) {
705 return ItemMenu_Constructor((IShellFolder*)iface, This->pidlRoot, apidl, cidl, riid, ppvOut);
706 } else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1)) {
707 pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
708 This->pidlRoot, apidl, cidl);
709 hr = S_OK;
710 } else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1)) {
711 pidl = ILCombine (This->pidlRoot, apidl[0]);
712 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
713 ILFree(pidl);
714 hr = S_OK;
715 } else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1)) {
716 pidl = ILCombine (This->pidlRoot, apidl[0]);
717 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
718 ILFree(pidl);
719 hr = S_OK;
720 } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) {
721 hr = IShellFolder2_QueryInterface (iface, &IID_IDropTarget,
722 (LPVOID *) & pObj);
723 } else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
724 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1)) {
725 pidl = ILCombine (This->pidlRoot, apidl[0]);
726 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, &pObj);
727 ILFree(pidl);
728 } else {
729 hr = E_NOINTERFACE;
732 if (SUCCEEDED(hr) && !pObj)
733 hr = E_OUTOFMEMORY;
735 *ppvOut = pObj;
737 TRACE ("(%p)->hr=0x%08lx\n", This, hr);
738 return hr;
741 /******************************************************************************
742 * SHELL_FS_HideExtension [Internal]
744 * Query the registry if the filename extension of a given path should be
745 * hidden.
747 * PARAMS
748 * szPath [I] Relative or absolute path of a file
750 * RETURNS
751 * TRUE, if the filename's extension should be hidden
752 * FALSE, otherwise.
754 static BOOL SHELL_FS_HideExtension(LPCWSTR szPath)
756 HKEY hKey;
757 DWORD dwData;
758 DWORD dwDataSize = sizeof (DWORD);
759 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
761 if (!RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
762 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
763 if (!RegQueryValueExW(hKey, L"HideFileExt", 0, 0, (LPBYTE) &dwData, &dwDataSize))
764 doHide = dwData;
765 RegCloseKey (hKey);
768 if (!doHide) {
769 LPWSTR ext = PathFindExtensionW(szPath);
771 if (*ext != '\0') {
772 WCHAR classname[MAX_PATH];
773 LONG classlen = sizeof(classname);
775 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
776 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
777 if (!RegQueryValueExW(hKey, L"NeverShowExt", 0, NULL, NULL, NULL))
778 doHide = TRUE;
779 RegCloseKey(hKey);
783 return doHide;
786 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
788 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
789 if (!(dwFlags & SHGDN_FORPARSING) &&
790 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
791 if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
792 PathRemoveExtensionW(szPath);
796 static void get_display_name( WCHAR dest[MAX_PATH], const WCHAR *path, LPCITEMIDLIST pidl, BOOL is_unix )
798 char *buffer;
799 WCHAR *res;
800 DWORD i, len;
802 lstrcpynW( dest, path, MAX_PATH );
804 /* try to get a better path than the \\?\unix one */
805 if (!wcsnicmp( path, L"\\\\?\\unix\\", 9 ))
807 if (!is_unix)
809 len = WideCharToMultiByte( CP_UNIXCP, 0, path + 8, -1, NULL, 0, NULL, NULL );
810 buffer = malloc( len );
811 len = WideCharToMultiByte( CP_UNIXCP, 0, path + 8, -1, buffer, len, NULL, NULL );
812 for (i = 0; i < len; i++) if (buffer[i] == '\\') buffer[i] = '/';
813 if ((res = wine_get_dos_file_name( buffer )))
815 lstrcpynW( dest, res, MAX_PATH );
816 heap_free( res );
819 else lstrcpynW( dest, path + 8, MAX_PATH );
822 if (!_ILIsDesktop(pidl))
824 PathAddBackslashW( dest );
825 len = lstrlenW( dest );
826 _ILSimpleGetTextW( pidl, dest + len, MAX_PATH - len );
828 if (is_unix) for (i = 0; dest[i]; i++) if (dest[i] == '\\') dest[i] = '/';
831 /**************************************************************************
832 * IShellFolder_fnGetDisplayNameOf
833 * Retrieves the display name for the specified file object or subfolder
835 * PARAMETERS
836 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
837 * DWORD dwFlags, //[in ] SHGNO formatting flags
838 * LPSTRRET lpName) //[out] Returned display name
840 * FIXME
841 * if the name is in the pidl the ret value should be a STRRET_OFFSET
844 static HRESULT WINAPI
845 IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
846 DWORD dwFlags, LPSTRRET strRet)
848 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
849 LPWSTR pszPath;
851 HRESULT hr = S_OK;
853 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This, pidl, dwFlags, strRet);
854 pdump (pidl);
856 if (!strRet)
857 return E_INVALIDARG;
859 pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
860 if (!pszPath)
861 return E_OUTOFMEMORY;
863 if (_ILIsDesktop(pidl)) { /* empty pidl */
864 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
865 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
867 if (This->sPathTarget)
868 get_display_name( pszPath, This->sPathTarget, pidl,
869 IsEqualCLSID( This->pclsid, &CLSID_UnixFolder ));
870 } else {
871 /* pidl has to contain exactly one non null SHITEMID */
872 hr = E_INVALIDARG;
874 } else if (_ILIsPidlSimple(pidl)) {
875 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
876 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
877 This->sPathTarget)
879 get_display_name( pszPath, This->sPathTarget, pidl,
880 IsEqualCLSID( This->pclsid, &CLSID_UnixFolder ));
882 else _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);
883 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
884 } else {
885 hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH);
888 if (SUCCEEDED(hr)) {
889 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
890 if (GetVersion() & 0x80000000) {
891 strRet->uType = STRRET_CSTR;
892 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
893 NULL, NULL))
894 strRet->cStr[0] = '\0';
895 CoTaskMemFree(pszPath);
896 } else {
897 strRet->uType = STRRET_WSTR;
898 strRet->pOleStr = pszPath;
900 } else
901 CoTaskMemFree(pszPath);
903 TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
904 return hr;
907 /**************************************************************************
908 * IShellFolder_fnSetNameOf
909 * Changes the name of a file object or subfolder, possibly changing its item
910 * identifier in the process.
912 * PARAMETERS
913 * HWND hwndOwner, //[in ] Owner window for output
914 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
915 * LPCOLESTR lpszName, //[in ] the items new display name
916 * DWORD dwFlags, //[in ] SHGNO formatting flags
917 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
919 static HRESULT WINAPI IShellFolder_fnSetNameOf (IShellFolder2 * iface,
920 HWND hwndOwner,
921 LPCITEMIDLIST pidl,
922 LPCOLESTR lpName,
923 DWORD dwFlags,
924 LPITEMIDLIST * pPidlOut)
926 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
927 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
928 LPWSTR ptr;
929 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
931 TRACE ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", This, hwndOwner, pidl,
932 debugstr_w (lpName), dwFlags, pPidlOut);
934 /* pidl has to contain a single non-empty SHITEMID */
935 if (_ILIsDesktop(pidl) || !_ILIsPidlSimple(pidl) || !_ILGetTextPointer(pidl)) return E_INVALIDARG;
937 if (wcspbrk( lpName, L"\\/:*?\"<>|" )) return HRESULT_FROM_WIN32(ERROR_CANCELLED);
939 /* build source path */
940 lstrcpynW(szSrc, This->sPathTarget, MAX_PATH);
941 ptr = PathAddBackslashW (szSrc);
942 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
944 /* build destination path */
945 lstrcpynW(szDest, This->sPathTarget, MAX_PATH);
946 ptr = PathAddBackslashW (szDest);
947 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
949 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
950 WCHAR *ext = PathFindExtensionW(szSrc);
951 if(*ext != '\0') {
952 INT len = lstrlenW(szDest);
953 lstrcpynW(szDest + len, ext, MAX_PATH - len);
957 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
959 if (MoveFileW (szSrc, szDest)) {
960 HRESULT hr = S_OK;
962 if (pPidlOut)
963 hr = _ILCreateFromPathW(szDest, pPidlOut);
965 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
966 SHCNF_PATHW, szSrc, szDest);
968 return hr;
971 return E_FAIL;
974 static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID(IShellFolder2 *iface, GUID *guid)
976 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
977 TRACE("(%p)->(%p)\n", This, guid);
978 return E_NOTIMPL;
981 static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface,
982 IEnumExtraSearch ** ppenum)
984 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
985 FIXME ("(%p)\n", This);
986 return E_NOTIMPL;
989 static HRESULT WINAPI
990 IShellFolder_fnGetDefaultColumn(IShellFolder2 *iface, DWORD reserved, ULONG *sort, ULONG *display)
992 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
994 TRACE("(%p)->(%#lx, %p, %p)\n", This, reserved, sort, display);
996 return E_NOTIMPL;
999 static HRESULT WINAPI
1000 IShellFolder_fnGetDefaultColumnState (IShellFolder2 * iface, UINT iColumn,
1001 DWORD * pcsFlags)
1003 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1005 TRACE ("(%p)\n", This);
1007 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
1008 return E_INVALIDARG;
1010 *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
1012 return S_OK;
1015 static HRESULT WINAPI
1016 IShellFolder_fnGetDetailsEx (IShellFolder2 * iface, LPCITEMIDLIST pidl,
1017 const SHCOLUMNID * pscid, VARIANT * pv)
1019 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1020 FIXME ("(%p)\n", This);
1022 return E_NOTIMPL;
1025 static HRESULT WINAPI
1026 IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
1027 UINT iColumn, SHELLDETAILS * psd)
1029 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1031 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
1033 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
1034 return E_INVALIDARG;
1036 if (!pidl) return SHELL32_GetColumnDetails(GenericSFHeader, iColumn, psd);
1038 return shellfolder_get_file_details( iface, pidl, GenericSFHeader, iColumn, psd );
1041 static HRESULT WINAPI
1042 IShellFolder_fnMapColumnToSCID (IShellFolder2 *iface, UINT column, SHCOLUMNID *scid)
1044 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1046 TRACE("(%p)->(%u %p)\n", This, column, scid);
1048 if (column >= GENERICSHELLVIEWCOLUMNS)
1049 return E_INVALIDARG;
1051 return shellfolder_map_column_to_scid(GenericSFHeader, column, scid);
1054 static const IShellFolder2Vtbl sfvt =
1056 IShellFolder_fnQueryInterface,
1057 IShellFolder_fnAddRef,
1058 IShellFolder_fnRelease,
1059 IShellFolder_fnParseDisplayName,
1060 IShellFolder_fnEnumObjects,
1061 IShellFolder_fnBindToObject,
1062 IShellFolder_fnBindToStorage,
1063 IShellFolder_fnCompareIDs,
1064 IShellFolder_fnCreateViewObject,
1065 IShellFolder_fnGetAttributesOf,
1066 IShellFolder_fnGetUIObjectOf,
1067 IShellFolder_fnGetDisplayNameOf,
1068 IShellFolder_fnSetNameOf,
1069 /* ShellFolder2 */
1070 IShellFolder_fnGetDefaultSearchGUID,
1071 IShellFolder_fnEnumSearches,
1072 IShellFolder_fnGetDefaultColumn,
1073 IShellFolder_fnGetDefaultColumnState,
1074 IShellFolder_fnGetDetailsEx,
1075 IShellFolder_fnGetDetailsOf,
1076 IShellFolder_fnMapColumnToSCID
1079 /****************************************************************************
1080 * ISFHelper for IShellFolder implementation
1083 static HRESULT WINAPI ISFHelper_fnQueryInterface(ISFHelper *iface, REFIID riid, void **ppvObj)
1085 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1087 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
1090 static ULONG WINAPI ISFHelper_fnAddRef(ISFHelper *iface)
1092 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1094 return IUnknown_AddRef(This->outer_unk);
1097 static ULONG WINAPI ISFHelper_fnRelease(ISFHelper *iface)
1099 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1101 return IUnknown_Release(This->outer_unk);
1104 /****************************************************************************
1105 * ISFHelper_fnGetUniqueName
1107 * creates a unique folder name
1110 static HRESULT WINAPI
1111 ISFHelper_fnGetUniqueName (ISFHelper * iface, LPWSTR pwszName, UINT uLen)
1113 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1114 IEnumIDList *penum;
1115 HRESULT hr;
1116 WCHAR wszText[MAX_PATH];
1117 WCHAR wszNewFolder[25];
1119 TRACE ("(%p)(%p %u)\n", This, pwszName, uLen);
1121 LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, ARRAY_SIZE(wszNewFolder));
1122 if (uLen < ARRAY_SIZE(wszNewFolder) + 3)
1123 return E_POINTER;
1125 lstrcpynW (pwszName, wszNewFolder, uLen);
1127 hr = IShellFolder2_EnumObjects(&This->IShellFolder2_iface, 0,
1128 SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1129 if (penum) {
1130 LPITEMIDLIST pidl;
1131 DWORD dwFetched;
1132 int i = 1;
1134 next:
1135 IEnumIDList_Reset (penum);
1136 while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) &&
1137 dwFetched) {
1138 _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
1139 if (0 == lstrcmpiW (wszText, pwszName)) {
1140 swprintf (pwszName, uLen, L"%s %d", wszNewFolder, i++);
1141 if (i > 99) {
1142 hr = E_FAIL;
1143 break;
1145 goto next;
1149 IEnumIDList_Release (penum);
1151 return hr;
1154 /****************************************************************************
1155 * ISFHelper_fnAddFolder
1157 * adds a new folder.
1160 static HRESULT WINAPI
1161 ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCWSTR pwszName,
1162 LPITEMIDLIST * ppidlOut)
1164 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1165 WCHAR wszNewDir[MAX_PATH];
1166 BOOL bRes;
1167 HRESULT hres = E_FAIL;
1169 TRACE ("(%p)(%s %p)\n", This, debugstr_w(pwszName), ppidlOut);
1171 wszNewDir[0] = 0;
1172 if (This->sPathTarget)
1173 lstrcpynW(wszNewDir, This->sPathTarget, MAX_PATH);
1174 PathAppendW(wszNewDir, pwszName);
1176 bRes = CreateDirectoryW (wszNewDir, NULL);
1177 if (bRes) {
1178 LPITEMIDLIST relPidl;
1180 lstrcpyW(wszNewDir, pwszName);
1182 hres = IShellFolder2_ParseDisplayName(&This->IShellFolder2_iface, hwnd, NULL, wszNewDir,
1183 NULL, &relPidl, NULL);
1185 if (SUCCEEDED(hres)) {
1186 LPITEMIDLIST fullPidl;
1188 fullPidl = ILCombine(This->pidlRoot, relPidl);
1190 if (fullPidl) {
1191 SHChangeNotify(SHCNE_MKDIR, SHCNF_IDLIST, fullPidl, NULL);
1192 ILFree(fullPidl);
1194 if (ppidlOut)
1195 *ppidlOut = relPidl;
1196 else
1197 ILFree(relPidl);
1198 } else {
1199 WARN("failed to combine %s into a full PIDL\n", wine_dbgstr_w(pwszName));
1200 ILFree(relPidl);
1203 } else
1204 WARN("failed to parse %s into a PIDL\n", wine_dbgstr_w(pwszName));
1206 } else {
1207 WCHAR wszText[128 + MAX_PATH];
1208 WCHAR wszTempText[128];
1209 WCHAR wszCaption[256];
1211 /* Cannot Create folder because of permissions */
1212 LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText, ARRAY_SIZE(wszTempText));
1213 LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption, ARRAY_SIZE(wszCaption));
1214 swprintf (wszText, ARRAY_SIZE(wszText), wszTempText, wszNewDir);
1215 MessageBoxW (hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
1218 return hres;
1221 /****************************************************************************
1222 * build_paths_list
1224 * Builds a list of paths like the one used in SHFileOperation from a table of
1225 * PIDLs relative to the given base folder
1227 static WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, const LPCITEMIDLIST *pidls)
1229 WCHAR *wszPathsList;
1230 WCHAR *wszListPos;
1231 int iPathLen;
1232 int i;
1234 iPathLen = lstrlenW(wszBasePath);
1235 wszPathsList = malloc(MAX_PATH * sizeof(WCHAR) * cidl + 1);
1236 wszListPos = wszPathsList;
1238 for (i = 0; i < cidl; i++) {
1239 if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i]))
1240 continue;
1242 lstrcpynW(wszListPos, wszBasePath, MAX_PATH);
1243 /* FIXME: abort if path too long */
1244 _ILSimpleGetTextW(pidls[i], wszListPos+iPathLen, MAX_PATH-iPathLen);
1245 wszListPos += lstrlenW(wszListPos)+1;
1247 *wszListPos=0;
1248 return wszPathsList;
1251 /****************************************************************************
1252 * ISFHelper_fnDeleteItems
1254 * deletes items in folder
1256 static HRESULT WINAPI
1257 ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl)
1259 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1260 UINT i;
1261 SHFILEOPSTRUCTW op;
1262 WCHAR wszPath[MAX_PATH];
1263 WCHAR *wszPathsList;
1264 HRESULT ret;
1265 WCHAR *wszCurrentPath;
1267 TRACE ("(%p)(%u %p)\n", This, cidl, apidl);
1268 if (cidl==0) return S_OK;
1270 if (This->sPathTarget)
1271 lstrcpynW(wszPath, This->sPathTarget, MAX_PATH);
1272 else
1273 wszPath[0] = '\0';
1274 PathAddBackslashW(wszPath);
1275 wszPathsList = build_paths_list(wszPath, cidl, apidl);
1277 ZeroMemory(&op, sizeof(op));
1278 op.hwnd = GetActiveWindow();
1279 op.wFunc = FO_DELETE;
1280 op.pFrom = wszPathsList;
1281 op.fFlags = FOF_ALLOWUNDO;
1282 if (SHFileOperationW(&op))
1284 WARN("SHFileOperation failed\n");
1285 ret = E_FAIL;
1287 else
1288 ret = S_OK;
1290 /* we currently need to manually send the notifies */
1291 wszCurrentPath = wszPathsList;
1292 for (i = 0; i < cidl; i++)
1294 LONG wEventId;
1296 if (_ILIsFolder(apidl[i]))
1297 wEventId = SHCNE_RMDIR;
1298 else if (_ILIsValue(apidl[i]))
1299 wEventId = SHCNE_DELETE;
1300 else
1301 continue;
1303 /* check if file exists */
1304 if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1306 LPITEMIDLIST pidl = ILCombine(This->pidlRoot, apidl[i]);
1307 SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1308 ILFree(pidl);
1311 wszCurrentPath += lstrlenW(wszCurrentPath)+1;
1313 free(wszPathsList);
1314 return ret;
1317 /****************************************************************************
1318 * ISFHelper_fnCopyItems
1320 * copies items to this folder
1322 static HRESULT WINAPI
1323 ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl,
1324 LPCITEMIDLIST * apidl)
1326 HRESULT ret=E_FAIL;
1327 IPersistFolder2 *ppf2 = NULL;
1328 WCHAR wszSrcPathRoot[MAX_PATH],
1329 wszDstPath[MAX_PATH+1];
1330 WCHAR *wszSrcPathsList;
1331 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1333 SHFILEOPSTRUCTW fop;
1335 TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl);
1337 IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2,
1338 (LPVOID *) & ppf2);
1339 if (ppf2) {
1340 LPITEMIDLIST pidl;
1342 if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) {
1343 SHGetPathFromIDListW (pidl, wszSrcPathRoot);
1344 if (This->sPathTarget)
1345 lstrcpynW(wszDstPath, This->sPathTarget, MAX_PATH);
1346 else
1347 wszDstPath[0] = 0;
1348 PathAddBackslashW(wszSrcPathRoot);
1349 PathAddBackslashW(wszDstPath);
1350 wszSrcPathsList = build_paths_list(wszSrcPathRoot, cidl, apidl);
1351 ZeroMemory(&fop, sizeof(fop));
1352 fop.hwnd = GetActiveWindow();
1353 fop.wFunc = FO_COPY;
1354 fop.pFrom = wszSrcPathsList;
1355 fop.pTo = wszDstPath;
1356 fop.fFlags = FOF_ALLOWUNDO;
1357 ret = S_OK;
1358 if(SHFileOperationW(&fop))
1360 WARN("Copy failed\n");
1361 ret = E_FAIL;
1363 free(wszSrcPathsList);
1365 SHFree(pidl);
1366 IPersistFolder2_Release(ppf2);
1368 return ret;
1371 static const ISFHelperVtbl shvt =
1373 ISFHelper_fnQueryInterface,
1374 ISFHelper_fnAddRef,
1375 ISFHelper_fnRelease,
1376 ISFHelper_fnGetUniqueName,
1377 ISFHelper_fnAddFolder,
1378 ISFHelper_fnDeleteItems,
1379 ISFHelper_fnCopyItems
1382 /************************************************************************
1383 * IFSFldr_PersistFolder3_QueryInterface
1386 static HRESULT WINAPI IFSFldr_PersistFolder3_QueryInterface(IPersistFolder3 *iface, REFIID iid,
1387 void **ppv)
1389 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1391 return IUnknown_QueryInterface(This->outer_unk, iid, ppv);
1394 /************************************************************************
1395 * IFSFldr_PersistFolder3_AddRef
1398 static ULONG WINAPI IFSFldr_PersistFolder3_AddRef(IPersistFolder3 *iface)
1400 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1402 return IUnknown_AddRef(This->outer_unk);
1405 /************************************************************************
1406 * IFSFldr_PersistFolder3_Release
1409 static ULONG WINAPI IFSFldr_PersistFolder3_Release(IPersistFolder3 *iface)
1411 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1413 return IUnknown_Release(This->outer_unk);
1416 /************************************************************************
1417 * IFSFldr_PersistFolder3_GetClassID
1419 static HRESULT WINAPI
1420 IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId)
1422 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1424 TRACE ("(%p)\n", This);
1426 if (!lpClassId)
1427 return E_POINTER;
1428 *lpClassId = *This->pclsid;
1430 return S_OK;
1433 /************************************************************************
1434 * IFSFldr_PersistFolder3_Initialize
1436 * NOTES
1437 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1439 static HRESULT WINAPI
1440 IFSFldr_PersistFolder3_Initialize (IPersistFolder3 * iface, LPCITEMIDLIST pidl)
1442 WCHAR wszTemp[MAX_PATH];
1443 int len;
1444 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1446 TRACE ("(%p)->(%p)\n", This, pidl);
1448 wszTemp[0] = 0;
1450 SHFree (This->pidlRoot); /* free the old pidl */
1451 This->pidlRoot = ILClone (pidl); /* set my pidl */
1453 /* FolderShortcuts' Initialize method only sets the ITEMIDLIST, which
1454 * specifies the location in the shell namespace, but leaves the
1455 * target folder alone */
1456 if (IsEqualCLSID( This->pclsid, &CLSID_FolderShortcut )) return S_OK;
1458 SHFree (This->sPathTarget);
1459 This->sPathTarget = NULL;
1461 /* set my path */
1462 if (_ILIsSpecialFolder(pidl) && IsEqualCLSID( This->pclsid, _ILGetGUIDPointer(pidl) ))
1464 if (IsEqualCLSID( This->pclsid, &CLSID_MyDocuments ))
1466 if (!SHGetSpecialFolderPathW( 0, wszTemp, CSIDL_PERSONAL, FALSE )) return E_FAIL;
1467 PathAddBackslashW( wszTemp );
1469 else lstrcpyW( wszTemp, L"\\\\?\\unix\\" );
1471 else SHGetPathFromIDListW( pidl, wszTemp );
1473 if ((len = lstrlenW(wszTemp)))
1475 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1476 if (!This->sPathTarget) return E_OUTOFMEMORY;
1477 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1480 TRACE ("--(%p)->(%s)\n", This, debugstr_w(This->sPathTarget));
1481 return S_OK;
1484 /**************************************************************************
1485 * IFSFldr_PersistFolder3_GetCurFolder
1487 static HRESULT WINAPI
1488 IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface,
1489 LPITEMIDLIST * pidl)
1491 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1493 TRACE ("(%p)->(%p)\n", This, pidl);
1495 if (!pidl) return E_POINTER;
1496 *pidl = ILClone (This->pidlRoot);
1497 return S_OK;
1500 /**************************************************************************
1501 * IFSFldr_PersistFolder3_InitializeEx
1503 * FIXME: error handling
1505 static HRESULT WINAPI
1506 IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface,
1507 IBindCtx * pbc, LPCITEMIDLIST pidlRoot,
1508 const PERSIST_FOLDER_TARGET_INFO * ppfti)
1510 WCHAR wszTemp[MAX_PATH];
1512 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1514 TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti);
1515 if (ppfti)
1516 TRACE ("--%p %s %s 0x%08lx 0x%08x\n",
1517 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1518 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1519 ppfti->csidl);
1521 pdump (pidlRoot);
1522 if (ppfti && ppfti->pidlTargetFolder)
1523 pdump (ppfti->pidlTargetFolder);
1525 if (This->pidlRoot)
1527 SHFree(This->pidlRoot);
1528 This->pidlRoot = NULL;
1530 if (This->sPathTarget)
1532 SHFree(This->sPathTarget);
1533 This->sPathTarget = NULL;
1537 * Root path and pidl
1539 This->pidlRoot = ILClone (pidlRoot);
1542 * the target folder is specified in csidl OR pidlTargetFolder OR
1543 * szTargetParsingName
1545 if (ppfti) {
1546 if (ppfti->csidl != -1) {
1547 if (SHGetSpecialFolderPathW (0, wszTemp, ppfti->csidl,
1548 ppfti->csidl & CSIDL_FLAG_CREATE)) {
1549 int len = lstrlenW(wszTemp);
1550 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1551 if (!This->sPathTarget)
1552 return E_OUTOFMEMORY;
1553 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1555 } else if (ppfti->szTargetParsingName[0]) {
1556 int len = lstrlenW(ppfti->szTargetParsingName);
1557 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1558 if (!This->sPathTarget)
1559 return E_OUTOFMEMORY;
1560 memcpy(This->sPathTarget, ppfti->szTargetParsingName,
1561 (len + 1) * sizeof(WCHAR));
1562 } else if (ppfti->pidlTargetFolder) {
1563 if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) {
1564 int len = lstrlenW(wszTemp);
1565 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1566 if (!This->sPathTarget)
1567 return E_OUTOFMEMORY;
1568 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1573 TRACE ("--(%p)->(target=%s)\n", This, debugstr_w(This->sPathTarget));
1574 pdump (This->pidlRoot);
1575 return (This->sPathTarget) ? S_OK : E_FAIL;
1578 static HRESULT WINAPI
1579 IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3 * iface,
1580 PERSIST_FOLDER_TARGET_INFO * ppfti)
1582 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1583 FIXME ("(%p)->(%p)\n", This, ppfti);
1584 ZeroMemory (ppfti, sizeof (*ppfti));
1585 return E_NOTIMPL;
1588 static const IPersistFolder3Vtbl pfvt =
1590 IFSFldr_PersistFolder3_QueryInterface,
1591 IFSFldr_PersistFolder3_AddRef,
1592 IFSFldr_PersistFolder3_Release,
1593 IFSFldr_PersistFolder3_GetClassID,
1594 IFSFldr_PersistFolder3_Initialize,
1595 IFSFldr_PersistFolder3_fnGetCurFolder,
1596 IFSFldr_PersistFolder3_InitializeEx,
1597 IFSFldr_PersistFolder3_GetFolderTargetInfo
1600 /****************************************************************************
1601 * IPersistPropertyBag implementation
1603 static HRESULT WINAPI PersistPropertyBag_QueryInterface(IPersistPropertyBag* iface,
1604 REFIID riid, void** ppv)
1606 IGenericSFImpl *This = impl_from_IPersistPropertyBag(iface);
1607 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1610 static ULONG WINAPI PersistPropertyBag_AddRef(IPersistPropertyBag* iface)
1612 IGenericSFImpl *This = impl_from_IPersistPropertyBag(iface);
1613 return IUnknown_AddRef(This->outer_unk);
1616 static ULONG WINAPI PersistPropertyBag_Release(IPersistPropertyBag* iface)
1618 IGenericSFImpl *This = impl_from_IPersistPropertyBag(iface);
1619 return IUnknown_Release(This->outer_unk);
1622 static HRESULT WINAPI PersistPropertyBag_GetClassID(IPersistPropertyBag* iface, CLSID* pClassID)
1624 IGenericSFImpl *This = impl_from_IPersistPropertyBag(iface);
1625 return IPersistFolder3_GetClassID(&This->IPersistFolder3_iface, pClassID);
1628 static HRESULT WINAPI PersistPropertyBag_InitNew(IPersistPropertyBag* iface)
1630 IGenericSFImpl *This = impl_from_IPersistPropertyBag(iface);
1631 FIXME("(%p): stub\n", This);
1632 return E_NOTIMPL;
1635 static HRESULT WINAPI PersistPropertyBag_Load(IPersistPropertyBag *iface,
1636 IPropertyBag *pPropertyBag, IErrorLog *pErrorLog)
1638 IGenericSFImpl *This = impl_from_IPersistPropertyBag(iface);
1639 PERSIST_FOLDER_TARGET_INFO pftiTarget;
1640 VARIANT var;
1641 HRESULT hr;
1643 TRACE("(%p)->(%p %p)\n", This, pPropertyBag, pErrorLog);
1645 if (!pPropertyBag)
1646 return E_POINTER;
1648 /* Get 'Target' property from the property bag. */
1649 V_VT(&var) = VT_BSTR;
1650 hr = IPropertyBag_Read(pPropertyBag, L"Target", &var, NULL);
1651 if (FAILED(hr))
1652 return E_FAIL;
1653 lstrcpyW(pftiTarget.szTargetParsingName, V_BSTR(&var));
1654 SysFreeString(V_BSTR(&var));
1656 pftiTarget.pidlTargetFolder = NULL;
1657 pftiTarget.szNetworkProvider[0] = 0;
1658 pftiTarget.dwAttributes = -1;
1659 pftiTarget.csidl = -1;
1661 return IPersistFolder3_InitializeEx(&This->IPersistFolder3_iface, NULL, NULL, &pftiTarget);
1664 static HRESULT WINAPI PersistPropertyBag_Save(IPersistPropertyBag *iface,
1665 IPropertyBag *pPropertyBag, BOOL fClearDirty, BOOL fSaveAllProperties)
1667 IGenericSFImpl *This = impl_from_IPersistPropertyBag(iface);
1668 FIXME("(%p): stub\n", This);
1669 return E_NOTIMPL;
1672 static const IPersistPropertyBagVtbl ppbvt = {
1673 PersistPropertyBag_QueryInterface,
1674 PersistPropertyBag_AddRef,
1675 PersistPropertyBag_Release,
1676 PersistPropertyBag_GetClassID,
1677 PersistPropertyBag_InitNew,
1678 PersistPropertyBag_Load,
1679 PersistPropertyBag_Save
1682 /****************************************************************************
1683 * ISFDropTarget implementation
1685 static HRESULT WINAPI ISFDropTarget_QueryInterface(IDropTarget *iface, REFIID riid, void **ppv)
1687 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1689 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1692 static ULONG WINAPI ISFDropTarget_AddRef(IDropTarget *iface)
1694 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1696 return IUnknown_AddRef(This->outer_unk);
1699 static ULONG WINAPI ISFDropTarget_Release(IDropTarget *iface)
1701 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1703 return IUnknown_Release(This->outer_unk);
1706 #define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
1707 #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
1709 static HRESULT WINAPI
1710 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
1711 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1713 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1714 FORMATETC format;
1715 STGMEDIUM medium;
1717 TRACE("(%p)->(%p 0x%08lx {.x=%ld, .y=%ld} %p)\n", This, pDataObject, dwKeyState, pt.x, pt.y, pdwEffect);
1719 if (!pdwEffect || !pDataObject)
1720 return E_INVALIDARG;
1722 /* Compute a mask of supported drop-effects for this shellfolder object and the given data
1723 * object. Dropping is only supported on folders, which represent filesystem locations. One
1724 * can't drop on file objects. And the 'move' drop effect is only supported, if the source
1725 * folder is not identical to the target folder. */
1726 This->drop_effects_mask = DROPEFFECT_NONE;
1727 InitFormatEtc(format, cfShellIDList, TYMED_HGLOBAL);
1728 if (_ILIsFolder(ILFindLastID(This->pidlRoot)) && /* Only drop to folders, not to files */
1729 SUCCEEDED(IDataObject_GetData(pDataObject, &format, &medium))) /* Only ShellIDList format */
1731 LPIDA pidaShellIDList = GlobalLock(medium.hGlobal);
1732 This->drop_effects_mask |= DROPEFFECT_COPY|DROPEFFECT_LINK;
1734 if (pidaShellIDList) { /* Files can only be moved between two different folders */
1735 if (!ILIsEqual(HIDA_GetPIDLFolder(pidaShellIDList), This->pidlRoot))
1736 This->drop_effects_mask |= DROPEFFECT_MOVE;
1737 GlobalUnlock(medium.hGlobal);
1741 *pdwEffect = KeyStateToDropEffect(dwKeyState) & This->drop_effects_mask;
1743 return S_OK;
1746 static HRESULT WINAPI
1747 ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
1748 DWORD * pdwEffect)
1750 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1752 TRACE("(%p)->(0x%08lx {.x=%ld, .y=%ld} %p)\n", This, dwKeyState, pt.x, pt.y, pdwEffect);
1754 if (!pdwEffect)
1755 return E_INVALIDARG;
1757 *pdwEffect = KeyStateToDropEffect(dwKeyState) & This->drop_effects_mask;
1759 return S_OK;
1762 static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
1764 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1766 TRACE("(%p)\n", This);
1768 This->drop_effects_mask = DROPEFFECT_NONE;
1769 return S_OK;
1772 static HRESULT WINAPI
1773 ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
1774 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1776 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1777 FORMATETC format;
1778 STGMEDIUM medium;
1779 HRESULT hr;
1781 TRACE("(%p)->(%p %ld {.x=%ld, .y=%ld} %p) semi-stub\n",
1782 This, pDataObject, dwKeyState, pt.x, pt.y, pdwEffect);
1784 InitFormatEtc(format, cfShellIDList, TYMED_HGLOBAL);
1785 hr = IDataObject_GetData(pDataObject, &format, &medium);
1786 if (FAILED(hr))
1787 return hr;
1789 if (medium.tymed == TYMED_HGLOBAL) {
1790 IShellFolder *psfSourceFolder, *psfDesktopFolder;
1791 LPIDA pidaShellIDList = GlobalLock(medium.hGlobal);
1792 STRRET strret;
1793 UINT i;
1795 if (!pidaShellIDList)
1796 return HRESULT_FROM_WIN32(GetLastError());
1798 hr = SHGetDesktopFolder(&psfDesktopFolder);
1799 if (FAILED(hr)) {
1800 GlobalUnlock(medium.hGlobal);
1801 return hr;
1804 hr = IShellFolder_BindToObject(psfDesktopFolder, HIDA_GetPIDLFolder(pidaShellIDList), NULL,
1805 &IID_IShellFolder, (LPVOID*)&psfSourceFolder);
1806 IShellFolder_Release(psfDesktopFolder);
1807 if (FAILED(hr)) {
1808 GlobalUnlock(medium.hGlobal);
1809 return hr;
1812 for (i = 0; i < pidaShellIDList->cidl; i++) {
1813 WCHAR wszSourcePath[MAX_PATH];
1815 hr = IShellFolder_GetDisplayNameOf(psfSourceFolder, HIDA_GetPIDLItem(pidaShellIDList, i),
1816 SHGDN_FORPARSING, &strret);
1817 if (FAILED(hr))
1818 break;
1820 hr = StrRetToBufW(&strret, NULL, wszSourcePath, MAX_PATH);
1821 if (FAILED(hr))
1822 break;
1824 switch (*pdwEffect) {
1825 case DROPEFFECT_MOVE:
1826 FIXME("Move %s to %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
1827 break;
1828 case DROPEFFECT_COPY:
1829 FIXME("Copy %s to %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
1830 break;
1831 case DROPEFFECT_LINK:
1832 FIXME("Link %s from %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
1833 break;
1837 IShellFolder_Release(psfSourceFolder);
1838 GlobalUnlock(medium.hGlobal);
1839 return hr;
1842 return E_NOTIMPL;
1845 static const IDropTargetVtbl dtvt = {
1846 ISFDropTarget_QueryInterface,
1847 ISFDropTarget_AddRef,
1848 ISFDropTarget_Release,
1849 ISFDropTarget_DragEnter,
1850 ISFDropTarget_DragOver,
1851 ISFDropTarget_DragLeave,
1852 ISFDropTarget_Drop
1855 static HRESULT create_fs( IUnknown *outer_unk, REFIID riid, void **ppv, const CLSID *clsid)
1857 IGenericSFImpl *sf;
1858 HRESULT hr;
1860 TRACE("outer_unk=%p %s\n", outer_unk, shdebugstr_guid(riid));
1862 if (outer_unk && !IsEqualIID(riid, &IID_IUnknown))
1863 return CLASS_E_NOAGGREGATION;
1865 sf = LocalAlloc(LMEM_ZEROINIT, sizeof(*sf));
1866 if (!sf)
1867 return E_OUTOFMEMORY;
1869 sf->ref = 1;
1870 sf->IUnknown_inner.lpVtbl = &unkvt;
1871 sf->IShellFolder2_iface.lpVtbl = &sfvt;
1872 sf->IPersistFolder3_iface.lpVtbl = &pfvt;
1873 sf->IPersistPropertyBag_iface.lpVtbl = &ppbvt;
1874 sf->IDropTarget_iface.lpVtbl = &dtvt;
1875 sf->ISFHelper_iface.lpVtbl = &shvt;
1876 sf->pclsid = clsid;
1877 sf->outer_unk = outer_unk ? outer_unk : &sf->IUnknown_inner;
1879 hr = IUnknown_QueryInterface(&sf->IUnknown_inner, riid, ppv);
1880 IUnknown_Release(&sf->IUnknown_inner);
1882 TRACE ("--%p\n", *ppv);
1883 return hr;
1886 HRESULT WINAPI IFSFolder_Constructor(IUnknown *outer_unk, REFIID riid, void **ppv)
1888 return create_fs( outer_unk, riid, ppv, &CLSID_ShellFSFolder );
1891 HRESULT WINAPI UnixFolder_Constructor(IUnknown *outer_unk, REFIID riid, void **ppv)
1893 return create_fs( outer_unk, riid, ppv, &CLSID_UnixFolder );
1896 HRESULT WINAPI UnixDosFolder_Constructor(IUnknown *outer_unk, REFIID riid, void **ppv)
1898 return create_fs( outer_unk, riid, ppv, &CLSID_UnixDosFolder );
1901 HRESULT WINAPI FolderShortcut_Constructor(IUnknown *outer_unk, REFIID riid, void **ppv)
1903 return create_fs( outer_unk, riid, ppv, &CLSID_FolderShortcut );
1906 HRESULT WINAPI MyDocuments_Constructor(IUnknown *outer_unk, REFIID riid, void **ppv)
1908 return create_fs( outer_unk, riid, ppv, &CLSID_MyDocuments );