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
40 #include "shell32_main.h"
43 #include "shellfolder.h"
44 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
50 /***********************************************************************
51 * IShellFolder implementation
55 IUnknown IUnknown_inner
;
57 IShellFolder2 IShellFolder2_iface
;
58 IPersistFolder3 IPersistFolder3_iface
;
59 IPersistPropertyBag IPersistPropertyBag_iface
;
60 IDropTarget IDropTarget_iface
;
61 ISFHelper ISFHelper_iface
;
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
;
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 /**************************************************************************
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
);
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
);
133 IUnknown_AddRef((IUnknown
*)*ppvObj
);
134 TRACE ("-- Interface = %p\n", *ppvObj
);
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
);
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
);
159 TRACE("-- destroying IShellFolder(%p)\n", This
);
161 SHFree(This
->pidlRoot
);
162 SHFree(This
->sPathTarget
);
168 static const IUnknownVtbl unkvt
=
170 IUnknown_fnQueryInterface
,
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
,
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
;
231 TRACE("%p %s\n", pbc
, debugstr_w(path
));
236 /* see if the caller bound File System Bind Data */
237 r
= IBindCtx_GetObjectParam( pbc
, (WCHAR
*)L
"File System Bind Data", &unk
);
241 r
= IUnknown_QueryInterface( unk
, &IID_IFileSystemBindData
, (void**)&fsbd
);
244 WIN32_FIND_DATAW wfd
;
246 r
= IFileSystemBindData_GetFindData( fsbd
, &wfd
);
249 lstrcpynW( &wfd
.cFileName
[0], path
, MAX_PATH
);
250 pidl
= _ILCreateFromFindDataW( &wfd
);
252 IFileSystemBindData_Release( fsbd
);
254 IUnknown_Release( unk
);
259 /**************************************************************************
260 * IShellFolder_ParseDisplayName {SHELL32}
262 * Parse a display name.
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
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
281 * pdwAttributes is not set
282 * pchEaten is not set like in windows
284 static HRESULT WINAPI
285 IShellFolder_fnParseDisplayName (IShellFolder2
* iface
,
288 LPOLESTR lpszDisplayName
,
289 DWORD
* pchEaten
, LPITEMIDLIST
* ppidl
,
290 DWORD
* pdwAttributes
)
292 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
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
;
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
;
309 *pchEaten
= 0; /* strange but like the original */
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;
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 */
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 */
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
);
390 TRACE ("(%p)->(-- pidl=%p ret=0x%08lx)\n", This
, *ppidl
, hr
);
392 if (fsbd
) IFileSystemBindData_Release( fsbd
);
396 /**************************************************************************
397 * IShellFolder_fnEnumObjects
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
);
423 /**************************************************************************
424 * IShellFolder_fnBindToObject
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
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
);
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
);
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
);
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
),
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
);
511 hr
= IShellView_QueryInterface (pShellView
, riid
, ppvOut
);
512 IShellView_Release (pShellView
);
516 TRACE ("-- (%p)->(interface=%p)\n", This
, ppvOut
);
520 /**************************************************************************
521 * IShellFolder_fnGetAttributesOf
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
);
537 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08lx))\n", This
, cidl
, apidl
,
538 rgfInOut
, rgfInOut
? *rgfInOut
: 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
);
559 hr
= SHBindToParent(This
->pidlRoot
, &IID_IShellFolder2
, (void **)&parent
, &rpidl
);
561 SHELL32_GetItemAttributes(parent
, rpidl
, rgfInOut
);
562 IShellFolder2_Release(parent
);
567 while (cidl
> 0 && *apidl
) {
569 SHELL32_GetItemAttributes(&This
->IShellFolder2_iface
, *apidl
, rgfInOut
);
574 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
575 *rgfInOut
&= ~SFGAO_VALIDATE
;
577 TRACE ("-- result=0x%08lx\n", *rgfInOut
);
582 /**************************************************************************
583 * SHELL32_CreateExtensionUIObject (internal)
585 static HRESULT
SHELL32_CreateExtensionUIObject(IShellFolder2
*iface
,
586 LPCITEMIDLIST pidl
, REFIID riid
, LPVOID
*ppvOut
)
588 IPersistFile
*persist_file
;
590 WCHAR extensionW
[20], buf
[MAX_PATH
];
591 DWORD size
= MAX_PATH
;
599 if(!_ILGetExtension(pidl
, extensionA
, 20))
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
)
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
)
616 if(RegQueryValueExW(key
, buf
, 0, NULL
, NULL
, NULL
)
617 != ERROR_FILE_NOT_FOUND
)
618 return E_ACCESSDENIED
;
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
)
624 if(RegQueryValueExW(key
, buf
, 0, NULL
, NULL
, NULL
)
625 != ERROR_FILE_NOT_FOUND
)
626 return E_ACCESSDENIED
;
629 if(!GUIDFromStringW(buf
, &guid
))
632 hr
= CoCreateInstance(&guid
, NULL
, CLSCTX_INPROC_SERVER
,
633 &IID_IPersistFile
, (void**)&persist_file
);
637 hr
= IShellFolder2_GetDisplayNameOf(iface
, pidl
, SHGDN_FORPARSING
, &path
);
639 hr
= StrRetToStrW(&path
, NULL
, &file
);
641 IPersistFile_Release(persist_file
);
645 hr
= IPersistFile_Load(persist_file
, file
, STGM_READ
);
648 IPersistFile_Release(persist_file
);
652 hr
= IPersistFile_QueryInterface(persist_file
, riid
, ppvOut
);
653 IPersistFile_Release(persist_file
);
657 /**************************************************************************
658 * IShellFolder_fnGetUIObjectOf
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
669 * This function gets asked to return "view objects" for one or more (multiple
671 * The viewobject typically is an COM object with one of the following
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
,
683 UINT cidl
, LPCITEMIDLIST
* apidl
, REFIID riid
,
684 UINT
* prgfInOut
, LPVOID
* ppvOut
)
686 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
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
);
699 hr
= SHELL32_CreateExtensionUIObject(iface
, *apidl
, riid
, ppvOut
);
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
);
710 } else if (IsEqualIID (riid
, &IID_IExtractIconA
) && (cidl
== 1)) {
711 pidl
= ILCombine (This
->pidlRoot
, apidl
[0]);
712 pObj
= (LPUNKNOWN
) IExtractIconA_Constructor (pidl
);
715 } else if (IsEqualIID (riid
, &IID_IExtractIconW
) && (cidl
== 1)) {
716 pidl
= ILCombine (This
->pidlRoot
, apidl
[0]);
717 pObj
= (LPUNKNOWN
) IExtractIconW_Constructor (pidl
);
720 } else if (IsEqualIID (riid
, &IID_IDropTarget
) && (cidl
>= 1)) {
721 hr
= IShellFolder2_QueryInterface (iface
, &IID_IDropTarget
,
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
);
732 if (SUCCEEDED(hr
) && !pObj
)
737 TRACE ("(%p)->hr=0x%08lx\n", This
, hr
);
741 /******************************************************************************
742 * SHELL_FS_HideExtension [Internal]
744 * Query the registry if the filename extension of a given path should be
748 * szPath [I] Relative or absolute path of a file
751 * TRUE, if the filename's extension should be hidden
754 static BOOL
SHELL_FS_HideExtension(LPCWSTR szPath
)
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
))
769 LPWSTR ext
= PathFindExtensionW(szPath
);
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
))
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
)
802 lstrcpynW( dest
, path
, MAX_PATH
);
804 /* try to get a better path than the \\?\unix one */
805 if (!wcsnicmp( path
, L
"\\\\?\\unix\\", 9 ))
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
);
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
836 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
837 * DWORD dwFlags, //[in ] SHGNO formatting flags
838 * LPSTRRET lpName) //[out] Returned display name
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
);
853 TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This
, pidl
, dwFlags
, strRet
);
859 pszPath
= CoTaskMemAlloc((MAX_PATH
+1) * sizeof(WCHAR
));
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
));
871 /* pidl has to contain exactly one non null SHITEMID */
874 } else if (_ILIsPidlSimple(pidl
)) {
875 if ((GET_SHGDN_FOR(dwFlags
) & SHGDN_FORPARSING
) &&
876 (GET_SHGDN_RELATION(dwFlags
) != SHGDN_INFOLDER
) &&
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
);
885 hr
= SHELL32_GetDisplayNameOfChild(iface
, pidl
, dwFlags
, pszPath
, MAX_PATH
);
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
,
894 strRet
->cStr
[0] = '\0';
895 CoTaskMemFree(pszPath
);
897 strRet
->uType
= STRRET_WSTR
;
898 strRet
->pOleStr
= pszPath
;
901 CoTaskMemFree(pszPath
);
903 TRACE ("-- (%p)->(%s)\n", This
, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
907 /**************************************************************************
908 * IShellFolder_fnSetNameOf
909 * Changes the name of a file object or subfolder, possibly changing its item
910 * identifier in the process.
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
,
924 LPITEMIDLIST
* pPidlOut
)
926 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
927 WCHAR szSrc
[MAX_PATH
+ 1], szDest
[MAX_PATH
+ 1];
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
);
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
)) {
963 hr
= _ILCreateFromPathW(szDest
, pPidlOut
);
965 SHChangeNotify (bIsFolder
? SHCNE_RENAMEFOLDER
: SHCNE_RENAMEITEM
,
966 SHCNF_PATHW
, szSrc
, szDest
);
974 static HRESULT WINAPI
IShellFolder_fnGetDefaultSearchGUID(IShellFolder2
*iface
, GUID
*guid
)
976 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
977 TRACE("(%p)->(%p)\n", This
, guid
);
981 static HRESULT WINAPI
IShellFolder_fnEnumSearches (IShellFolder2
* iface
,
982 IEnumExtraSearch
** ppenum
)
984 IGenericSFImpl
*This
= impl_from_IShellFolder2(iface
);
985 FIXME ("(%p)\n", This
);
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
);
999 static HRESULT WINAPI
1000 IShellFolder_fnGetDefaultColumnState (IShellFolder2
* iface
, UINT iColumn
,
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
;
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
);
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
,
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
);
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)
1125 lstrcpynW (pwszName
, wszNewFolder
, uLen
);
1127 hr
= IShellFolder2_EnumObjects(&This
->IShellFolder2_iface
, 0,
1128 SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &penum
);
1135 IEnumIDList_Reset (penum
);
1136 while (S_OK
== IEnumIDList_Next (penum
, 1, &pidl
, &dwFetched
) &&
1138 _ILSimpleGetTextW (pidl
, wszText
, MAX_PATH
);
1139 if (0 == lstrcmpiW (wszText
, pwszName
)) {
1140 swprintf (pwszName
, uLen
, L
"%s %d", wszNewFolder
, i
++);
1149 IEnumIDList_Release (penum
);
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
];
1167 HRESULT hres
= E_FAIL
;
1169 TRACE ("(%p)(%s %p)\n", This
, debugstr_w(pwszName
), ppidlOut
);
1172 if (This
->sPathTarget
)
1173 lstrcpynW(wszNewDir
, This
->sPathTarget
, MAX_PATH
);
1174 PathAppendW(wszNewDir
, pwszName
);
1176 bRes
= CreateDirectoryW (wszNewDir
, NULL
);
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
);
1191 SHChangeNotify(SHCNE_MKDIR
, SHCNF_IDLIST
, fullPidl
, NULL
);
1195 *ppidlOut
= relPidl
;
1199 WARN("failed to combine %s into a full PIDL\n", wine_dbgstr_w(pwszName
));
1204 WARN("failed to parse %s into a PIDL\n", wine_dbgstr_w(pwszName
));
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
);
1221 /****************************************************************************
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
;
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
]))
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;
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
);
1262 WCHAR wszPath
[MAX_PATH
];
1263 WCHAR
*wszPathsList
;
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
);
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");
1290 /* we currently need to manually send the notifies */
1291 wszCurrentPath
= wszPathsList
;
1292 for (i
= 0; i
< cidl
; i
++)
1296 if (_ILIsFolder(apidl
[i
]))
1297 wEventId
= SHCNE_RMDIR
;
1298 else if (_ILIsValue(apidl
[i
]))
1299 wEventId
= SHCNE_DELETE
;
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
);
1311 wszCurrentPath
+= lstrlenW(wszCurrentPath
)+1;
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
)
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
,
1342 if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2
, &pidl
))) {
1343 SHGetPathFromIDListW (pidl
, wszSrcPathRoot
);
1344 if (This
->sPathTarget
)
1345 lstrcpynW(wszDstPath
, This
->sPathTarget
, MAX_PATH
);
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
;
1358 if(SHFileOperationW(&fop
))
1360 WARN("Copy failed\n");
1363 free(wszSrcPathsList
);
1366 IPersistFolder2_Release(ppf2
);
1371 static const ISFHelperVtbl shvt
=
1373 ISFHelper_fnQueryInterface
,
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
,
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
);
1428 *lpClassId
= *This
->pclsid
;
1433 /************************************************************************
1434 * IFSFldr_PersistFolder3_Initialize
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
];
1444 IGenericSFImpl
*This
= impl_from_IPersistFolder3(iface
);
1446 TRACE ("(%p)->(%p)\n", This
, pidl
);
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
;
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
));
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
);
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
);
1516 TRACE ("--%p %s %s 0x%08lx 0x%08x\n",
1517 ppfti
->pidlTargetFolder
, debugstr_w (ppfti
->szTargetParsingName
),
1518 debugstr_w (ppfti
->szNetworkProvider
), ppfti
->dwAttributes
,
1522 if (ppfti
&& ppfti
->pidlTargetFolder
)
1523 pdump (ppfti
->pidlTargetFolder
);
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
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
));
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
);
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
;
1643 TRACE("(%p)->(%p %p)\n", This
, pPropertyBag
, pErrorLog
);
1648 /* Get 'Target' property from the property bag. */
1649 V_VT(&var
) = VT_BSTR
;
1650 hr
= IPropertyBag_Read(pPropertyBag
, L
"Target", &var
, NULL
);
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
);
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
);
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
;
1746 static HRESULT WINAPI
1747 ISFDropTarget_DragOver (IDropTarget
* iface
, DWORD dwKeyState
, POINTL pt
,
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
);
1755 return E_INVALIDARG
;
1757 *pdwEffect
= KeyStateToDropEffect(dwKeyState
) & This
->drop_effects_mask
;
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
;
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
);
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
);
1789 if (medium
.tymed
== TYMED_HGLOBAL
) {
1790 IShellFolder
*psfSourceFolder
, *psfDesktopFolder
;
1791 LPIDA pidaShellIDList
= GlobalLock(medium
.hGlobal
);
1795 if (!pidaShellIDList
)
1796 return HRESULT_FROM_WIN32(GetLastError());
1798 hr
= SHGetDesktopFolder(&psfDesktopFolder
);
1800 GlobalUnlock(medium
.hGlobal
);
1804 hr
= IShellFolder_BindToObject(psfDesktopFolder
, HIDA_GetPIDLFolder(pidaShellIDList
), NULL
,
1805 &IID_IShellFolder
, (LPVOID
*)&psfSourceFolder
);
1806 IShellFolder_Release(psfDesktopFolder
);
1808 GlobalUnlock(medium
.hGlobal
);
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
);
1820 hr
= StrRetToBufW(&strret
, NULL
, wszSourcePath
, MAX_PATH
);
1824 switch (*pdwEffect
) {
1825 case DROPEFFECT_MOVE
:
1826 FIXME("Move %s to %s!\n", debugstr_w(wszSourcePath
), debugstr_w(This
->sPathTarget
));
1828 case DROPEFFECT_COPY
:
1829 FIXME("Copy %s to %s!\n", debugstr_w(wszSourcePath
), debugstr_w(This
->sPathTarget
));
1831 case DROPEFFECT_LINK
:
1832 FIXME("Link %s from %s!\n", debugstr_w(wszSourcePath
), debugstr_w(This
->sPathTarget
));
1837 IShellFolder_Release(psfSourceFolder
);
1838 GlobalUnlock(medium
.hGlobal
);
1845 static const IDropTargetVtbl dtvt
= {
1846 ISFDropTarget_QueryInterface
,
1847 ISFDropTarget_AddRef
,
1848 ISFDropTarget_Release
,
1849 ISFDropTarget_DragEnter
,
1850 ISFDropTarget_DragOver
,
1851 ISFDropTarget_DragLeave
,
1855 static HRESULT
create_fs( IUnknown
*outer_unk
, REFIID riid
, void **ppv
, const CLSID
*clsid
)
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
));
1867 return E_OUTOFMEMORY
;
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
;
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
);
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
);