webservices: Add a stub implementation of WS_TYPE_ATTRIBUTE_FIELD_MAPPING in the...
[wine.git] / dlls / shell32 / shfldr_fs.c
blob2f49eb27064fb01e2d1f38d20e65dd03b98f8d9d
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 "config.h"
24 #include "wine/port.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <stdio.h>
31 #define COBJMACROS
32 #define NONAMELESSUNION
34 #include "winerror.h"
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winreg.h"
38 #include "wingdi.h"
39 #include "winuser.h"
41 #include "ole2.h"
42 #include "shlguid.h"
44 #include "pidl.h"
45 #include "undocshell.h"
46 #include "shell32_main.h"
47 #include "shresdef.h"
48 #include "shlwapi.h"
49 #include "shellfolder.h"
50 #include "wine/debug.h"
51 #include "debughlp.h"
52 #include "shfldr.h"
54 WINE_DEFAULT_DEBUG_CHANNEL (shell);
56 /***********************************************************************
57 * IShellFolder implementation
60 typedef struct {
61 IUnknown IUnknown_inner;
62 LONG ref;
63 IShellFolder2 IShellFolder2_iface;
64 IPersistFolder3 IPersistFolder3_iface;
65 IDropTarget IDropTarget_iface;
66 ISFHelper ISFHelper_iface;
67 IUnknown *outer_unk;
69 CLSID *pclsid;
71 /* both paths are parsible from the desktop */
72 LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
74 LPITEMIDLIST pidlRoot; /* absolute pidl */
76 UINT cfShellIDList; /* clipboardformat for IDropTarget */
77 BOOL fAcceptFmt; /* flag for pending Drop */
78 } IGenericSFImpl;
80 static inline IGenericSFImpl *impl_from_IUnknown(IUnknown *iface)
82 return CONTAINING_RECORD(iface, IGenericSFImpl, IUnknown_inner);
85 static inline IGenericSFImpl *impl_from_IShellFolder2(IShellFolder2 *iface)
87 return CONTAINING_RECORD(iface, IGenericSFImpl, IShellFolder2_iface);
90 static inline IGenericSFImpl *impl_from_IPersistFolder3(IPersistFolder3 *iface)
92 return CONTAINING_RECORD(iface, IGenericSFImpl, IPersistFolder3_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 * registers clipboardformat once
108 static void SF_RegisterClipFmt (IGenericSFImpl * This)
110 TRACE ("(%p)\n", This);
112 if (!This->cfShellIDList) {
113 This->cfShellIDList = RegisterClipboardFormatW (CFSTR_SHELLIDLISTW);
117 /**************************************************************************
118 * inner IUnknown
120 static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, void **ppvObj)
122 IGenericSFImpl *This = impl_from_IUnknown(iface);
124 TRACE("(%p)->(%s,%p)\n", This, shdebugstr_guid(riid), ppvObj);
126 *ppvObj = NULL;
128 if (IsEqualIID (riid, &IID_IUnknown))
129 *ppvObj = &This->IUnknown_inner;
130 else if (IsEqualIID(riid, &IID_IShellFolder) || IsEqualIID(riid, &IID_IShellFolder2))
131 *ppvObj = &This->IShellFolder2_iface;
132 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IPersistFolder) ||
133 IsEqualIID(riid, &IID_IPersistFolder2) || IsEqualIID(riid, &IID_IPersistFolder3))
134 *ppvObj = &This->IPersistFolder3_iface;
135 else if (IsEqualIID (riid, &IID_ISFHelper))
136 *ppvObj = &This->ISFHelper_iface;
137 else if (IsEqualIID (riid, &IID_IDropTarget)) {
138 *ppvObj = &This->IDropTarget_iface;
139 SF_RegisterClipFmt(This);
142 if (*ppvObj) {
143 IUnknown_AddRef((IUnknown *)*ppvObj);
144 TRACE ("-- Interface = %p\n", *ppvObj);
145 return S_OK;
147 TRACE ("-- Interface: E_NOINTERFACE\n");
148 return E_NOINTERFACE;
151 static ULONG WINAPI IUnknown_fnAddRef(IUnknown *iface)
153 IGenericSFImpl *This = impl_from_IUnknown(iface);
154 ULONG ref = InterlockedIncrement(&This->ref);
156 TRACE("(%p) ref=%d\n", This, ref);
158 return ref;
161 static ULONG WINAPI IUnknown_fnRelease(IUnknown *iface)
163 IGenericSFImpl *This = impl_from_IUnknown(iface);
164 ULONG ref = InterlockedDecrement(&This->ref);
166 TRACE("(%p) ref=%d\n", This, ref);
168 if (!ref) {
169 TRACE("-- destroying IShellFolder(%p)\n", This);
171 SHFree(This->pidlRoot);
172 SHFree(This->sPathTarget);
173 LocalFree(This);
175 return ref;
178 static const IUnknownVtbl unkvt =
180 IUnknown_fnQueryInterface,
181 IUnknown_fnAddRef,
182 IUnknown_fnRelease,
185 static const shvheader GenericSFHeader[] = {
186 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
187 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
188 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
189 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
190 {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
193 #define GENERICSHELLVIEWCOLUMNS 5
195 /**************************************************************************
196 * IShellFolder_fnQueryInterface
198 static HRESULT WINAPI IShellFolder_fnQueryInterface(IShellFolder2 *iface, REFIID riid,
199 void **ppvObj)
201 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
203 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
206 /**************************************************************************
207 * IShellFolder_AddRef
209 static ULONG WINAPI IShellFolder_fnAddRef(IShellFolder2 *iface)
211 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
213 return IUnknown_AddRef(This->outer_unk);
216 /**************************************************************************
217 * IShellFolder_fnRelease
219 static ULONG WINAPI IShellFolder_fnRelease(IShellFolder2 *iface)
221 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
223 return IUnknown_Release(This->outer_unk);
226 /**************************************************************************
227 * SHELL32_CreatePidlFromBindCtx [internal]
229 * If the caller bound File System Bind Data, assume it is the
230 * find data for the path.
231 * This allows binding of paths that don't exist.
233 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
235 static WCHAR szfsbc[] = {
236 'F','i','l','e',' ','S','y','s','t','e','m',' ',
237 'B','i','n','d',' ','D','a','t','a',0 };
238 IFileSystemBindData *fsbd = NULL;
239 LPITEMIDLIST pidl = NULL;
240 IUnknown *unk = NULL;
241 HRESULT r;
243 TRACE("%p %s\n", pbc, debugstr_w(path));
245 if (!pbc)
246 return NULL;
248 /* see if the caller bound File System Bind Data */
249 r = IBindCtx_GetObjectParam( pbc, szfsbc, &unk );
250 if (FAILED(r))
251 return NULL;
253 r = IUnknown_QueryInterface( unk, &IID_IFileSystemBindData, (void**)&fsbd );
254 if (SUCCEEDED(r))
256 WIN32_FIND_DATAW wfd;
258 r = IFileSystemBindData_GetFindData( fsbd, &wfd );
259 if (SUCCEEDED(r))
261 lstrcpynW( &wfd.cFileName[0], path, MAX_PATH );
262 pidl = _ILCreateFromFindDataW( &wfd );
264 IFileSystemBindData_Release( fsbd );
266 IUnknown_Release( unk );
268 return pidl;
271 /**************************************************************************
272 * IShellFolder_ParseDisplayName {SHELL32}
274 * Parse a display name.
276 * PARAMS
277 * hwndOwner [in] Parent window for any message's
278 * pbc [in] optional FileSystemBindData context
279 * lpszDisplayName [in] Unicode displayname.
280 * pchEaten [out] (unicode) characters processed
281 * ppidl [out] complex pidl to item
282 * pdwAttributes [out] items attributes
284 * NOTES
285 * Every folder tries to parse only its own (the leftmost) pidl and creates a
286 * subfolder to evaluate the remaining parts.
287 * Now we can parse into namespaces implemented by shell extensions
289 * Behaviour on win98: lpszDisplayName=NULL -> crash
290 * lpszDisplayName="" -> returns mycoputer-pidl
292 * FIXME
293 * pdwAttributes is not set
294 * pchEaten is not set like in windows
296 static HRESULT WINAPI
297 IShellFolder_fnParseDisplayName (IShellFolder2 * iface,
298 HWND hwndOwner,
299 LPBC pbc,
300 LPOLESTR lpszDisplayName,
301 DWORD * pchEaten, LPITEMIDLIST * ppidl,
302 DWORD * pdwAttributes)
304 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
306 HRESULT hr = E_INVALIDARG;
307 LPCWSTR szNext = NULL;
308 WCHAR szElement[MAX_PATH];
309 WCHAR szPath[MAX_PATH];
310 LPITEMIDLIST pidlTemp = NULL;
311 DWORD len;
313 TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
314 This, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
315 pchEaten, ppidl, pdwAttributes);
317 if (!lpszDisplayName || !ppidl)
318 return E_INVALIDARG;
320 if (pchEaten)
321 *pchEaten = 0; /* strange but like the original */
323 pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName);
324 if (!pidlTemp && *lpszDisplayName)
326 /* get the next element */
327 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
329 /* build the full pathname to the element */
330 lstrcpynW(szPath, This->sPathTarget, MAX_PATH - 1);
331 PathAddBackslashW(szPath);
332 len = lstrlenW(szPath);
333 lstrcpynW(szPath + len, szElement, MAX_PATH - len);
335 /* get the pidl */
336 hr = _ILCreateFromPathW(szPath, &pidlTemp);
338 if (SUCCEEDED(hr)) {
339 if (szNext && *szNext) {
340 /* try to analyse the next element */
341 hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc,
342 &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
343 } else {
344 /* it's the last element */
345 if (pdwAttributes && *pdwAttributes) {
346 hr = SHELL32_GetItemAttributes((IShellFolder *)&This->IShellFolder2_iface,
347 pidlTemp, pdwAttributes);
353 if (SUCCEEDED(hr))
354 *ppidl = pidlTemp;
355 else
356 *ppidl = NULL;
358 TRACE ("(%p)->(-- pidl=%p ret=0x%08x)\n", This, *ppidl, hr);
360 return hr;
363 /**************************************************************************
364 * IShellFolder_fnEnumObjects
365 * PARAMETERS
366 * HWND hwndOwner, //[in ] Parent Window
367 * DWORD grfFlags, //[in ] SHCONTF enumeration mask
368 * LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
370 static HRESULT WINAPI
371 IShellFolder_fnEnumObjects (IShellFolder2 * iface, HWND hwndOwner,
372 DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
374 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
375 IEnumIDListImpl *list;
377 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This, hwndOwner,
378 dwFlags, ppEnumIDList);
380 if (!(list = IEnumIDList_Constructor()))
381 return E_OUTOFMEMORY;
382 CreateFolderEnumList(list, This->sPathTarget, dwFlags);
383 *ppEnumIDList = &list->IEnumIDList_iface;
385 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
387 return S_OK;
390 /**************************************************************************
391 * IShellFolder_fnBindToObject
392 * PARAMETERS
393 * LPCITEMIDLIST pidl, //[in ] relative pidl to open
394 * LPBC pbc, //[in ] optional FileSystemBindData context
395 * REFIID riid, //[in ] Initial Interface
396 * LPVOID* ppvObject //[out] Interface*
398 static HRESULT WINAPI
399 IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl,
400 LPBC pbc, REFIID riid, LPVOID * ppvOut)
402 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
404 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbc,
405 shdebugstr_guid (riid), ppvOut);
407 return SHELL32_BindToChild (This->pidlRoot, This->sPathTarget, pidl, riid,
408 ppvOut);
411 /**************************************************************************
412 * IShellFolder_fnBindToStorage
413 * PARAMETERS
414 * LPCITEMIDLIST pidl, //[in ] complex pidl to store
415 * LPBC pbc, //[in ] reserved
416 * REFIID riid, //[in ] Initial storage interface
417 * LPVOID* ppvObject //[out] Interface* returned
419 static HRESULT WINAPI
420 IShellFolder_fnBindToStorage (IShellFolder2 * iface, LPCITEMIDLIST pidl,
421 LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
423 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
425 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved,
426 shdebugstr_guid (riid), ppvOut);
428 *ppvOut = NULL;
429 return E_NOTIMPL;
432 /**************************************************************************
433 * IShellFolder_fnCompareIDs
436 static HRESULT WINAPI
437 IShellFolder_fnCompareIDs (IShellFolder2 * iface, LPARAM lParam,
438 LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
440 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
442 int nReturn;
444 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
445 nReturn = SHELL32_CompareIDs(&This->IShellFolder2_iface, lParam, pidl1, pidl2);
446 TRACE ("-- %i\n", nReturn);
447 return nReturn;
450 /**************************************************************************
451 * IShellFolder_fnCreateViewObject
453 static HRESULT WINAPI
454 IShellFolder_fnCreateViewObject (IShellFolder2 * iface, HWND hwndOwner,
455 REFIID riid, LPVOID * ppvOut)
457 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
459 LPSHELLVIEW pShellView;
460 HRESULT hr = E_INVALIDARG;
462 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid (riid),
463 ppvOut);
465 if (ppvOut) {
466 *ppvOut = NULL;
468 if (IsEqualIID (riid, &IID_IDropTarget)) {
469 hr = IShellFolder2_QueryInterface (iface, &IID_IDropTarget, ppvOut);
470 } else if (IsEqualIID (riid, &IID_IContextMenu)) {
471 FIXME ("IContextMenu not implemented\n");
472 hr = E_NOTIMPL;
473 } else if (IsEqualIID (riid, &IID_IShellView)) {
474 pShellView = IShellView_Constructor ((IShellFolder *) iface);
475 if (pShellView) {
476 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
477 IShellView_Release (pShellView);
481 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
482 return hr;
485 /**************************************************************************
486 * IShellFolder_fnGetAttributesOf
488 * PARAMETERS
489 * UINT cidl, //[in ] num elements in pidl array
490 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
491 * ULONG* rgfInOut) //[out] result array
494 static HRESULT WINAPI
495 IShellFolder_fnGetAttributesOf (IShellFolder2 * iface, UINT cidl,
496 LPCITEMIDLIST * apidl, DWORD * rgfInOut)
498 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
500 HRESULT hr = S_OK;
502 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", This, cidl, apidl,
503 rgfInOut, rgfInOut ? *rgfInOut : 0);
505 if (!rgfInOut)
506 return E_INVALIDARG;
507 if (cidl && !apidl)
508 return E_INVALIDARG;
510 if (*rgfInOut == 0)
511 *rgfInOut = ~0;
513 if(cidl == 0){
514 IShellFolder *psfParent = NULL;
515 LPCITEMIDLIST rpidl = NULL;
517 hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, &rpidl);
518 if(SUCCEEDED(hr)) {
519 SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
520 IShellFolder_Release(psfParent);
523 else {
524 while (cidl > 0 && *apidl) {
525 pdump (*apidl);
526 SHELL32_GetItemAttributes((IShellFolder *)&This->IShellFolder2_iface, *apidl, rgfInOut);
527 apidl++;
528 cidl--;
531 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
532 *rgfInOut &= ~SFGAO_VALIDATE;
534 TRACE ("-- result=0x%08x\n", *rgfInOut);
536 return hr;
539 /**************************************************************************
540 * SHELL32_CreateExtensionUIObject (internal)
542 HRESULT SHELL32_CreateExtensionUIObject(IShellFolder2 *iface,
543 LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
545 static const WCHAR reg_blockedW[] = {'S','o','f','t','w','a','r','e','\\',
546 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
547 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
548 'S','h','e','l','l',' ','E','x','t','e','n','s','i','o','n','s','\\',
549 'B','l','o','c','k','e','d',0};
550 static const WCHAR formatW[] = {'.','%','s','\\','S','h','e','l','l','E','x','\\',
551 '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
552 '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x',
553 '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
555 IPersistFile *persist_file;
556 char extensionA[20];
557 WCHAR extensionW[20], buf[MAX_PATH];
558 DWORD size = MAX_PATH;
559 STRRET path;
560 WCHAR *file;
561 GUID guid;
562 HKEY key;
563 HRESULT hr;
566 if(!_ILGetExtension(pidl, extensionA, 20))
567 return S_FALSE;
569 MultiByteToWideChar(CP_ACP, 0, extensionA, -1, extensionW, 20);
571 sprintfW(buf, formatW, extensionW, riid->Data1, riid->Data2, riid->Data3,
572 riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
573 riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
575 if(RegGetValueW(HKEY_CLASSES_ROOT, buf, NULL, RRF_RT_REG_SZ,
576 NULL, buf, &size) != ERROR_SUCCESS)
577 return S_FALSE;
579 if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, reg_blockedW, 0, 0, 0,
580 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
581 return E_FAIL;
582 if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
583 != ERROR_FILE_NOT_FOUND)
584 return E_ACCESSDENIED;
585 RegCloseKey(key);
587 if(RegCreateKeyExW(HKEY_CURRENT_USER, reg_blockedW, 0, 0, 0,
588 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
589 return E_FAIL;
590 if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
591 != ERROR_FILE_NOT_FOUND)
592 return E_ACCESSDENIED;
593 RegCloseKey(key);
595 if(!GUIDFromStringW(buf, &guid))
596 return E_FAIL;
598 hr = CoCreateInstance(&guid, NULL, CLSCTX_INPROC_SERVER,
599 &IID_IPersistFile, (void**)&persist_file);
600 if(FAILED(hr))
601 return hr;
603 hr = IShellFolder2_GetDisplayNameOf(iface, pidl, SHGDN_FORPARSING, &path);
604 if(SUCCEEDED(hr))
605 hr = StrRetToStrW(&path, NULL, &file);
606 if(FAILED(hr)) {
607 IPersistFile_Release(persist_file);
608 return hr;
611 hr = IPersistFile_Load(persist_file, file, STGM_READ);
612 CoTaskMemFree(file);
613 if(FAILED(hr)) {
614 IPersistFile_Release(persist_file);
615 return hr;
618 hr = IPersistFile_QueryInterface(persist_file, riid, ppvOut);
619 IPersistFile_Release(persist_file);
620 return hr;
623 /**************************************************************************
624 * IShellFolder_fnGetUIObjectOf
626 * PARAMETERS
627 * HWND hwndOwner, //[in ] Parent window for any output
628 * UINT cidl, //[in ] array size
629 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
630 * REFIID riid, //[in ] Requested Interface
631 * UINT* prgfInOut, //[ ] reserved
632 * LPVOID* ppvObject) //[out] Resulting Interface
634 * NOTES
635 * This function gets asked to return "view objects" for one or more (multiple
636 * select) items:
637 * The viewobject typically is an COM object with one of the following
638 * interfaces:
639 * IExtractIcon,IDataObject,IContextMenu
640 * In order to support icon positions in the default Listview your DataObject
641 * must implement the SetData method (in addition to GetData :) - the shell
642 * passes a barely documented "Icon positions" structure to SetData when the
643 * drag starts, and GetData's it if the drop is in another explorer window that
644 * needs the positions.
646 static HRESULT WINAPI
647 IShellFolder_fnGetUIObjectOf (IShellFolder2 * iface,
648 HWND hwndOwner,
649 UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
650 UINT * prgfInOut, LPVOID * ppvOut)
652 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
654 LPITEMIDLIST pidl;
655 IUnknown *pObj = NULL;
656 HRESULT hr = E_INVALIDARG;
658 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
659 This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
661 if (ppvOut) {
662 *ppvOut = NULL;
664 if(cidl == 1) {
665 hr = SHELL32_CreateExtensionUIObject(iface, *apidl, riid, ppvOut);
666 if(hr != S_FALSE)
667 return hr;
670 if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1)) {
671 return ItemMenu_Constructor((IShellFolder*)iface, This->pidlRoot, apidl, cidl, riid, ppvOut);
672 } else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1)) {
673 pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
674 This->pidlRoot, apidl, cidl);
675 hr = S_OK;
676 } else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1)) {
677 pidl = ILCombine (This->pidlRoot, apidl[0]);
678 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
679 SHFree (pidl);
680 hr = S_OK;
681 } else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1)) {
682 pidl = ILCombine (This->pidlRoot, apidl[0]);
683 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
684 SHFree (pidl);
685 hr = S_OK;
686 } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) {
687 hr = IShellFolder2_QueryInterface (iface, &IID_IDropTarget,
688 (LPVOID *) & pObj);
689 } else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
690 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1)) {
691 pidl = ILCombine (This->pidlRoot, apidl[0]);
692 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, &pObj);
693 SHFree (pidl);
694 } else {
695 hr = E_NOINTERFACE;
698 if (SUCCEEDED(hr) && !pObj)
699 hr = E_OUTOFMEMORY;
701 *ppvOut = pObj;
703 TRACE ("(%p)->hr=0x%08x\n", This, hr);
704 return hr;
707 static const WCHAR AdvancedW[] = { 'S','O','F','T','W','A','R','E',
708 '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
709 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
710 'o','r','e','r','\\','A','d','v','a','n','c','e','d',0 };
711 static const WCHAR HideFileExtW[] = { 'H','i','d','e','F','i','l','e','E','x',
712 't',0 };
713 static const WCHAR NeverShowExtW[] = { 'N','e','v','e','r','S','h','o','w','E',
714 'x','t',0 };
716 /******************************************************************************
717 * SHELL_FS_HideExtension [Internal]
719 * Query the registry if the filename extension of a given path should be
720 * hidden.
722 * PARAMS
723 * szPath [I] Relative or absolute path of a file
725 * RETURNS
726 * TRUE, if the filename's extension should be hidden
727 * FALSE, otherwise.
729 BOOL SHELL_FS_HideExtension(LPCWSTR szPath)
731 HKEY hKey;
732 DWORD dwData;
733 DWORD dwDataSize = sizeof (DWORD);
734 BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
736 if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
737 if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
738 doHide = dwData;
739 RegCloseKey (hKey);
742 if (!doHide) {
743 LPWSTR ext = PathFindExtensionW(szPath);
745 if (*ext != '\0') {
746 WCHAR classname[MAX_PATH];
747 LONG classlen = sizeof(classname);
749 if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
750 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
751 if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
752 doHide = TRUE;
753 RegCloseKey(hKey);
757 return doHide;
760 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
762 /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
763 if (!(dwFlags & SHGDN_FORPARSING) &&
764 ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
765 if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
766 PathRemoveExtensionW(szPath);
770 /**************************************************************************
771 * IShellFolder_fnGetDisplayNameOf
772 * Retrieves the display name for the specified file object or subfolder
774 * PARAMETERS
775 * LPCITEMIDLIST pidl, //[in ] complex pidl to item
776 * DWORD dwFlags, //[in ] SHGNO formatting flags
777 * LPSTRRET lpName) //[out] Returned display name
779 * FIXME
780 * if the name is in the pidl the ret value should be a STRRET_OFFSET
783 static HRESULT WINAPI
784 IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
785 DWORD dwFlags, LPSTRRET strRet)
787 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
788 LPWSTR pszPath;
790 HRESULT hr = S_OK;
791 int len = 0;
793 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
794 pdump (pidl);
796 if (!pidl || !strRet)
797 return E_INVALIDARG;
799 pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
800 if (!pszPath)
801 return E_OUTOFMEMORY;
803 if (_ILIsDesktop(pidl)) { /* empty pidl */
804 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
805 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
807 if (This->sPathTarget)
808 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH);
809 } else {
810 /* pidl has to contain exactly one non null SHITEMID */
811 hr = E_INVALIDARG;
813 } else if (_ILIsPidlSimple(pidl)) {
814 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
815 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
816 This->sPathTarget)
818 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH);
819 PathAddBackslashW(pszPath);
820 len = lstrlenW(pszPath);
822 _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
823 if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
824 } else {
825 hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH);
828 if (SUCCEEDED(hr)) {
829 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
830 if (GetVersion() & 0x80000000) {
831 strRet->uType = STRRET_CSTR;
832 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
833 NULL, NULL))
834 strRet->u.cStr[0] = '\0';
835 CoTaskMemFree(pszPath);
836 } else {
837 strRet->uType = STRRET_WSTR;
838 strRet->u.pOleStr = pszPath;
840 } else
841 CoTaskMemFree(pszPath);
843 TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr));
844 return hr;
847 /**************************************************************************
848 * IShellFolder_fnSetNameOf
849 * Changes the name of a file object or subfolder, possibly changing its item
850 * identifier in the process.
852 * PARAMETERS
853 * HWND hwndOwner, //[in ] Owner window for output
854 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
855 * LPCOLESTR lpszName, //[in ] the items new display name
856 * DWORD dwFlags, //[in ] SHGNO formatting flags
857 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
859 static HRESULT WINAPI IShellFolder_fnSetNameOf (IShellFolder2 * iface,
860 HWND hwndOwner,
861 LPCITEMIDLIST pidl,
862 LPCOLESTR lpName,
863 DWORD dwFlags,
864 LPITEMIDLIST * pPidlOut)
866 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
867 WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
868 LPWSTR ptr;
869 BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
871 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl,
872 debugstr_w (lpName), dwFlags, pPidlOut);
874 /* build source path */
875 lstrcpynW(szSrc, This->sPathTarget, MAX_PATH);
876 ptr = PathAddBackslashW (szSrc);
877 if (ptr)
878 _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
880 /* build destination path */
881 if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
882 lstrcpynW(szDest, This->sPathTarget, MAX_PATH);
883 ptr = PathAddBackslashW (szDest);
884 if (ptr)
885 lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
886 } else
887 lstrcpynW(szDest, lpName, MAX_PATH);
889 if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
890 WCHAR *ext = PathFindExtensionW(szSrc);
891 if(*ext != '\0') {
892 INT len = strlenW(szDest);
893 lstrcpynW(szDest + len, ext, MAX_PATH - len);
897 TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
899 if (MoveFileW (szSrc, szDest)) {
900 HRESULT hr = S_OK;
902 if (pPidlOut)
903 hr = _ILCreateFromPathW(szDest, pPidlOut);
905 SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
906 SHCNF_PATHW, szSrc, szDest);
908 return hr;
911 return E_FAIL;
914 static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID (IShellFolder2 *iface,
915 GUID * pguid)
917 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
918 FIXME ("(%p)\n", This);
919 return E_NOTIMPL;
921 static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface,
922 IEnumExtraSearch ** ppenum)
924 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
925 FIXME ("(%p)\n", This);
926 return E_NOTIMPL;
929 static HRESULT WINAPI
930 IShellFolder_fnGetDefaultColumn (IShellFolder2 * iface, DWORD dwRes,
931 ULONG * pSort, ULONG * pDisplay)
933 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
935 TRACE ("(%p)\n", This);
937 if (pSort)
938 *pSort = 0;
939 if (pDisplay)
940 *pDisplay = 0;
942 return S_OK;
945 static HRESULT WINAPI
946 IShellFolder_fnGetDefaultColumnState (IShellFolder2 * iface, UINT iColumn,
947 DWORD * pcsFlags)
949 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
951 TRACE ("(%p)\n", This);
953 if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
954 return E_INVALIDARG;
956 *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
958 return S_OK;
961 static HRESULT WINAPI
962 IShellFolder_fnGetDetailsEx (IShellFolder2 * iface, LPCITEMIDLIST pidl,
963 const SHCOLUMNID * pscid, VARIANT * pv)
965 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
966 FIXME ("(%p)\n", This);
968 return E_NOTIMPL;
971 static HRESULT WINAPI
972 IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
973 UINT iColumn, SHELLDETAILS * psd)
975 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
976 HRESULT hr = E_FAIL;
978 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
980 if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
981 return E_INVALIDARG;
983 if (!pidl) {
984 /* the header titles */
985 psd->fmt = GenericSFHeader[iColumn].fmt;
986 psd->cxChar = GenericSFHeader[iColumn].cxChar;
987 psd->str.uType = STRRET_CSTR;
988 LoadStringA (shell32_hInstance, GenericSFHeader[iColumn].colnameid,
989 psd->str.u.cStr, MAX_PATH);
990 return S_OK;
991 } else {
992 hr = S_OK;
993 psd->str.uType = STRRET_CSTR;
994 /* the data from the pidl */
995 switch (iColumn) {
996 case 0: /* name */
997 hr = IShellFolder2_GetDisplayNameOf (iface, pidl,
998 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
999 break;
1000 case 1: /* size */
1001 _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH);
1002 break;
1003 case 2: /* type */
1004 _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
1005 break;
1006 case 3: /* date */
1007 _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH);
1008 break;
1009 case 4: /* attributes */
1010 _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
1011 break;
1015 return hr;
1018 static HRESULT WINAPI
1019 IShellFolder_fnMapColumnToSCID (IShellFolder2 * iface, UINT column,
1020 SHCOLUMNID * pscid)
1022 IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1023 FIXME ("(%p)\n", This);
1024 return E_NOTIMPL;
1027 static const IShellFolder2Vtbl sfvt =
1029 IShellFolder_fnQueryInterface,
1030 IShellFolder_fnAddRef,
1031 IShellFolder_fnRelease,
1032 IShellFolder_fnParseDisplayName,
1033 IShellFolder_fnEnumObjects,
1034 IShellFolder_fnBindToObject,
1035 IShellFolder_fnBindToStorage,
1036 IShellFolder_fnCompareIDs,
1037 IShellFolder_fnCreateViewObject,
1038 IShellFolder_fnGetAttributesOf,
1039 IShellFolder_fnGetUIObjectOf,
1040 IShellFolder_fnGetDisplayNameOf,
1041 IShellFolder_fnSetNameOf,
1042 /* ShellFolder2 */
1043 IShellFolder_fnGetDefaultSearchGUID,
1044 IShellFolder_fnEnumSearches,
1045 IShellFolder_fnGetDefaultColumn,
1046 IShellFolder_fnGetDefaultColumnState,
1047 IShellFolder_fnGetDetailsEx,
1048 IShellFolder_fnGetDetailsOf,
1049 IShellFolder_fnMapColumnToSCID
1052 /****************************************************************************
1053 * ISFHelper for IShellFolder implementation
1056 static HRESULT WINAPI ISFHelper_fnQueryInterface(ISFHelper *iface, REFIID riid, void **ppvObj)
1058 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1060 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
1063 static ULONG WINAPI ISFHelper_fnAddRef(ISFHelper *iface)
1065 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1067 return IUnknown_AddRef(This->outer_unk);
1070 static ULONG WINAPI ISFHelper_fnRelease(ISFHelper *iface)
1072 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1074 return IUnknown_Release(This->outer_unk);
1077 /****************************************************************************
1078 * ISFHelper_fnGetUniqueName
1080 * creates a unique folder name
1083 static HRESULT WINAPI
1084 ISFHelper_fnGetUniqueName (ISFHelper * iface, LPWSTR pwszName, UINT uLen)
1086 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1087 IEnumIDList *penum;
1088 HRESULT hr;
1089 WCHAR wszText[MAX_PATH];
1090 WCHAR wszNewFolder[25];
1091 const WCHAR wszFormat[] = {'%','s',' ','%','d',0 };
1093 TRACE ("(%p)(%p %u)\n", This, pwszName, uLen);
1095 LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, sizeof(wszNewFolder)/sizeof(WCHAR));
1096 if (uLen < sizeof(wszNewFolder)/sizeof(WCHAR) + 3)
1097 return E_POINTER;
1099 lstrcpynW (pwszName, wszNewFolder, uLen);
1101 hr = IShellFolder2_EnumObjects(&This->IShellFolder2_iface, 0,
1102 SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1103 if (penum) {
1104 LPITEMIDLIST pidl;
1105 DWORD dwFetched;
1106 int i = 1;
1108 next:
1109 IEnumIDList_Reset (penum);
1110 while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) &&
1111 dwFetched) {
1112 _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
1113 if (0 == lstrcmpiW (wszText, pwszName)) {
1114 snprintfW (pwszName, uLen, wszFormat, wszNewFolder, i++);
1115 if (i > 99) {
1116 hr = E_FAIL;
1117 break;
1119 goto next;
1123 IEnumIDList_Release (penum);
1125 return hr;
1128 /****************************************************************************
1129 * ISFHelper_fnAddFolder
1131 * adds a new folder.
1134 static HRESULT WINAPI
1135 ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCWSTR pwszName,
1136 LPITEMIDLIST * ppidlOut)
1138 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1139 WCHAR wszNewDir[MAX_PATH];
1140 BOOL bRes;
1141 HRESULT hres = E_FAIL;
1143 TRACE ("(%p)(%s %p)\n", This, debugstr_w(pwszName), ppidlOut);
1145 wszNewDir[0] = 0;
1146 if (This->sPathTarget)
1147 lstrcpynW(wszNewDir, This->sPathTarget, MAX_PATH);
1148 PathAppendW(wszNewDir, pwszName);
1150 bRes = CreateDirectoryW (wszNewDir, NULL);
1151 if (bRes) {
1152 LPITEMIDLIST relPidl;
1154 lstrcpyW(wszNewDir, pwszName);
1156 hres = IShellFolder2_ParseDisplayName(&This->IShellFolder2_iface, hwnd, NULL, wszNewDir,
1157 NULL, &relPidl, NULL);
1159 if (SUCCEEDED(hres)) {
1160 LPITEMIDLIST fullPidl;
1162 fullPidl = ILCombine(This->pidlRoot, relPidl);
1164 if (fullPidl) {
1165 SHChangeNotify(SHCNE_MKDIR, SHCNF_IDLIST, fullPidl, NULL);
1166 ILFree(fullPidl);
1168 if (ppidlOut)
1169 *ppidlOut = relPidl;
1170 else
1171 ILFree(relPidl);
1172 } else {
1173 WARN("failed to combine %s into a full PIDL\n", wine_dbgstr_w(pwszName));
1174 ILFree(relPidl);
1177 } else
1178 WARN("failed to parse %s into a PIDL\n", wine_dbgstr_w(pwszName));
1180 } else {
1181 WCHAR wszText[128 + MAX_PATH];
1182 WCHAR wszTempText[128];
1183 WCHAR wszCaption[256];
1185 /* Cannot Create folder because of permissions */
1186 LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
1187 sizeof (wszTempText)/sizeof (wszTempText[0]));
1188 LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
1189 sizeof (wszCaption)/sizeof (wszCaption[0]));
1190 sprintfW (wszText, wszTempText, wszNewDir);
1191 MessageBoxW (hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
1194 return hres;
1197 /****************************************************************************
1198 * build_paths_list
1200 * Builds a list of paths like the one used in SHFileOperation from a table of
1201 * PIDLs relative to the given base folder
1203 static WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, const LPCITEMIDLIST *pidls)
1205 WCHAR *wszPathsList;
1206 WCHAR *wszListPos;
1207 int iPathLen;
1208 int i;
1210 iPathLen = lstrlenW(wszBasePath);
1211 wszPathsList = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR)*cidl+1);
1212 wszListPos = wszPathsList;
1214 for (i = 0; i < cidl; i++) {
1215 if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i]))
1216 continue;
1218 lstrcpynW(wszListPos, wszBasePath, MAX_PATH);
1219 /* FIXME: abort if path too long */
1220 _ILSimpleGetTextW(pidls[i], wszListPos+iPathLen, MAX_PATH-iPathLen);
1221 wszListPos += lstrlenW(wszListPos)+1;
1223 *wszListPos=0;
1224 return wszPathsList;
1227 /****************************************************************************
1228 * ISFHelper_fnDeleteItems
1230 * deletes items in folder
1232 static HRESULT WINAPI
1233 ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl)
1235 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1236 UINT i;
1237 SHFILEOPSTRUCTW op;
1238 WCHAR wszPath[MAX_PATH];
1239 WCHAR *wszPathsList;
1240 HRESULT ret;
1241 WCHAR *wszCurrentPath;
1243 TRACE ("(%p)(%u %p)\n", This, cidl, apidl);
1244 if (cidl==0) return S_OK;
1246 if (This->sPathTarget)
1247 lstrcpynW(wszPath, This->sPathTarget, MAX_PATH);
1248 else
1249 wszPath[0] = '\0';
1250 PathAddBackslashW(wszPath);
1251 wszPathsList = build_paths_list(wszPath, cidl, apidl);
1253 ZeroMemory(&op, sizeof(op));
1254 op.hwnd = GetActiveWindow();
1255 op.wFunc = FO_DELETE;
1256 op.pFrom = wszPathsList;
1257 op.fFlags = FOF_ALLOWUNDO;
1258 if (SHFileOperationW(&op))
1260 WARN("SHFileOperation failed\n");
1261 ret = E_FAIL;
1263 else
1264 ret = S_OK;
1266 /* we currently need to manually send the notifies */
1267 wszCurrentPath = wszPathsList;
1268 for (i = 0; i < cidl; i++)
1270 LONG wEventId;
1272 if (_ILIsFolder(apidl[i]))
1273 wEventId = SHCNE_RMDIR;
1274 else if (_ILIsValue(apidl[i]))
1275 wEventId = SHCNE_DELETE;
1276 else
1277 continue;
1279 /* check if file exists */
1280 if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1282 LPITEMIDLIST pidl = ILCombine(This->pidlRoot, apidl[i]);
1283 SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1284 SHFree(pidl);
1287 wszCurrentPath += lstrlenW(wszCurrentPath)+1;
1289 HeapFree(GetProcessHeap(), 0, wszPathsList);
1290 return ret;
1293 /****************************************************************************
1294 * ISFHelper_fnCopyItems
1296 * copies items to this folder
1298 static HRESULT WINAPI
1299 ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl,
1300 LPCITEMIDLIST * apidl)
1302 HRESULT ret=E_FAIL;
1303 IPersistFolder2 *ppf2 = NULL;
1304 WCHAR wszSrcPathRoot[MAX_PATH],
1305 wszDstPath[MAX_PATH+1];
1306 WCHAR *wszSrcPathsList;
1307 IGenericSFImpl *This = impl_from_ISFHelper(iface);
1309 SHFILEOPSTRUCTW fop;
1311 TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl);
1313 IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2,
1314 (LPVOID *) & ppf2);
1315 if (ppf2) {
1316 LPITEMIDLIST pidl;
1318 if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) {
1319 SHGetPathFromIDListW (pidl, wszSrcPathRoot);
1320 ZeroMemory(wszDstPath, MAX_PATH+1);
1321 if (This->sPathTarget)
1322 lstrcpynW(wszDstPath, This->sPathTarget, MAX_PATH);
1323 PathAddBackslashW(wszSrcPathRoot);
1324 PathAddBackslashW(wszDstPath);
1325 wszSrcPathsList = build_paths_list(wszSrcPathRoot, cidl, apidl);
1326 ZeroMemory(&fop, sizeof(fop));
1327 fop.hwnd = GetActiveWindow();
1328 fop.wFunc = FO_COPY;
1329 fop.pFrom = wszSrcPathsList;
1330 fop.pTo = wszDstPath;
1331 fop.fFlags = FOF_ALLOWUNDO;
1332 ret = S_OK;
1333 if(SHFileOperationW(&fop))
1335 WARN("Copy failed\n");
1336 ret = E_FAIL;
1338 HeapFree(GetProcessHeap(), 0, wszSrcPathsList);
1341 SHFree(pidl);
1342 IPersistFolder2_Release(ppf2);
1344 return ret;
1347 static const ISFHelperVtbl shvt =
1349 ISFHelper_fnQueryInterface,
1350 ISFHelper_fnAddRef,
1351 ISFHelper_fnRelease,
1352 ISFHelper_fnGetUniqueName,
1353 ISFHelper_fnAddFolder,
1354 ISFHelper_fnDeleteItems,
1355 ISFHelper_fnCopyItems
1358 /************************************************************************
1359 * IFSFldr_PersistFolder3_QueryInterface
1362 static HRESULT WINAPI IFSFldr_PersistFolder3_QueryInterface(IPersistFolder3 *iface, REFIID iid,
1363 void **ppv)
1365 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1367 return IUnknown_QueryInterface(This->outer_unk, iid, ppv);
1370 /************************************************************************
1371 * IFSFldr_PersistFolder3_AddRef
1374 static ULONG WINAPI IFSFldr_PersistFolder3_AddRef(IPersistFolder3 *iface)
1376 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1378 return IUnknown_AddRef(This->outer_unk);
1381 /************************************************************************
1382 * IFSFldr_PersistFolder3_Release
1385 static ULONG WINAPI IFSFldr_PersistFolder3_Release(IPersistFolder3 *iface)
1387 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1389 return IUnknown_Release(This->outer_unk);
1392 /************************************************************************
1393 * IFSFldr_PersistFolder3_GetClassID
1395 static HRESULT WINAPI
1396 IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId)
1398 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1400 TRACE ("(%p)\n", This);
1402 if (!lpClassId)
1403 return E_POINTER;
1404 *lpClassId = *This->pclsid;
1406 return S_OK;
1409 /************************************************************************
1410 * IFSFldr_PersistFolder3_Initialize
1412 * NOTES
1413 * sPathTarget is not set. Don't know how to handle in a non rooted environment.
1415 static HRESULT WINAPI
1416 IFSFldr_PersistFolder3_Initialize (IPersistFolder3 * iface, LPCITEMIDLIST pidl)
1418 WCHAR wszTemp[MAX_PATH];
1420 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1422 TRACE ("(%p)->(%p)\n", This, pidl);
1424 SHFree (This->pidlRoot); /* free the old pidl */
1425 This->pidlRoot = ILClone (pidl); /* set my pidl */
1427 SHFree (This->sPathTarget);
1428 This->sPathTarget = NULL;
1430 /* set my path */
1431 if (SHGetPathFromIDListW (pidl, wszTemp)) {
1432 int len = strlenW(wszTemp);
1433 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1434 if (!This->sPathTarget)
1435 return E_OUTOFMEMORY;
1436 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1439 TRACE ("--(%p)->(%s)\n", This, debugstr_w(This->sPathTarget));
1440 return S_OK;
1443 /**************************************************************************
1444 * IFSFldr_PersistFolder3_GetCurFolder
1446 static HRESULT WINAPI
1447 IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface,
1448 LPITEMIDLIST * pidl)
1450 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1452 TRACE ("(%p)->(%p)\n", This, pidl);
1454 if (!pidl) return E_POINTER;
1455 *pidl = ILClone (This->pidlRoot);
1456 return S_OK;
1459 /**************************************************************************
1460 * IFSFldr_PersistFolder3_InitializeEx
1462 * FIXME: error handling
1464 static HRESULT WINAPI
1465 IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface,
1466 IBindCtx * pbc, LPCITEMIDLIST pidlRoot,
1467 const PERSIST_FOLDER_TARGET_INFO * ppfti)
1469 WCHAR wszTemp[MAX_PATH];
1471 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1473 TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti);
1474 if (ppfti)
1475 TRACE ("--%p %s %s 0x%08x 0x%08x\n",
1476 ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1477 debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1478 ppfti->csidl);
1480 pdump (pidlRoot);
1481 if (ppfti && ppfti->pidlTargetFolder)
1482 pdump (ppfti->pidlTargetFolder);
1484 if (This->pidlRoot)
1486 SHFree(This->pidlRoot);
1487 This->pidlRoot = NULL;
1489 if (This->sPathTarget)
1491 SHFree(This->sPathTarget);
1492 This->sPathTarget = NULL;
1496 * Root path and pidl
1498 This->pidlRoot = ILClone (pidlRoot);
1501 * the target folder is specified in csidl OR pidlTargetFolder OR
1502 * szTargetParsingName
1504 if (ppfti) {
1505 if (ppfti->csidl != -1) {
1506 if (SHGetSpecialFolderPathW (0, wszTemp, ppfti->csidl,
1507 ppfti->csidl & CSIDL_FLAG_CREATE)) {
1508 int len = strlenW(wszTemp);
1509 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1510 if (!This->sPathTarget)
1511 return E_OUTOFMEMORY;
1512 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1514 } else if (ppfti->szTargetParsingName[0]) {
1515 int len = strlenW(ppfti->szTargetParsingName);
1516 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1517 if (!This->sPathTarget)
1518 return E_OUTOFMEMORY;
1519 memcpy(This->sPathTarget, ppfti->szTargetParsingName,
1520 (len + 1) * sizeof(WCHAR));
1521 } else if (ppfti->pidlTargetFolder) {
1522 if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) {
1523 int len = strlenW(wszTemp);
1524 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1525 if (!This->sPathTarget)
1526 return E_OUTOFMEMORY;
1527 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1532 TRACE ("--(%p)->(target=%s)\n", This, debugstr_w(This->sPathTarget));
1533 pdump (This->pidlRoot);
1534 return (This->sPathTarget) ? S_OK : E_FAIL;
1537 static HRESULT WINAPI
1538 IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3 * iface,
1539 PERSIST_FOLDER_TARGET_INFO * ppfti)
1541 IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1542 FIXME ("(%p)->(%p)\n", This, ppfti);
1543 ZeroMemory (ppfti, sizeof (*ppfti));
1544 return E_NOTIMPL;
1547 static const IPersistFolder3Vtbl pfvt =
1549 IFSFldr_PersistFolder3_QueryInterface,
1550 IFSFldr_PersistFolder3_AddRef,
1551 IFSFldr_PersistFolder3_Release,
1552 IFSFldr_PersistFolder3_GetClassID,
1553 IFSFldr_PersistFolder3_Initialize,
1554 IFSFldr_PersistFolder3_fnGetCurFolder,
1555 IFSFldr_PersistFolder3_InitializeEx,
1556 IFSFldr_PersistFolder3_GetFolderTargetInfo
1559 /****************************************************************************
1560 * ISFDropTarget implementation
1562 static HRESULT WINAPI ISFDropTarget_QueryInterface(IDropTarget *iface, REFIID riid, void **ppv)
1564 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1566 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
1569 static ULONG WINAPI ISFDropTarget_AddRef(IDropTarget *iface)
1571 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1573 return IUnknown_AddRef(This->outer_unk);
1576 static ULONG WINAPI ISFDropTarget_Release(IDropTarget *iface)
1578 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1580 return IUnknown_Release(This->outer_unk);
1583 static HRESULT WINAPI
1584 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
1585 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1587 FORMATETC fmt;
1589 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1591 TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject);
1593 InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL);
1594 This->fAcceptFmt = IDataObject_QueryGetData (pDataObject, &fmt) == S_OK;
1595 if (This->fAcceptFmt)
1596 *pdwEffect = KeyStateToDropEffect(dwKeyState);
1597 else
1598 *pdwEffect = DROPEFFECT_NONE;
1600 return S_OK;
1603 static HRESULT WINAPI
1604 ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
1605 DWORD * pdwEffect)
1607 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1609 TRACE ("(%p)\n", This);
1611 if (!pdwEffect)
1612 return E_INVALIDARG;
1614 if (This->fAcceptFmt)
1615 *pdwEffect = KeyStateToDropEffect(dwKeyState);
1616 else
1617 *pdwEffect = DROPEFFECT_NONE;
1619 return S_OK;
1622 static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
1624 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1626 TRACE ("(%p)\n", This);
1628 This->fAcceptFmt = FALSE;
1630 return S_OK;
1633 static HRESULT WINAPI
1634 ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
1635 DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1637 IGenericSFImpl *This = impl_from_IDropTarget(iface);
1639 FIXME ("(%p) object dropped\n", This);
1641 return E_NOTIMPL;
1644 static const IDropTargetVtbl dtvt = {
1645 ISFDropTarget_QueryInterface,
1646 ISFDropTarget_AddRef,
1647 ISFDropTarget_Release,
1648 ISFDropTarget_DragEnter,
1649 ISFDropTarget_DragOver,
1650 ISFDropTarget_DragLeave,
1651 ISFDropTarget_Drop
1654 HRESULT WINAPI IFSFolder_Constructor(IUnknown *outer_unk, REFIID riid, void **ppv)
1656 IGenericSFImpl *sf;
1657 HRESULT hr;
1659 TRACE("outer_unk=%p %s\n", outer_unk, shdebugstr_guid(riid));
1661 if (outer_unk && !IsEqualIID(riid, &IID_IUnknown))
1662 return CLASS_E_NOAGGREGATION;
1664 sf = LocalAlloc(LMEM_ZEROINIT, sizeof(*sf));
1665 if (!sf)
1666 return E_OUTOFMEMORY;
1668 sf->ref = 1;
1669 sf->IUnknown_inner.lpVtbl = &unkvt;
1670 sf->IShellFolder2_iface.lpVtbl = &sfvt;
1671 sf->IPersistFolder3_iface.lpVtbl = &pfvt;
1672 sf->IDropTarget_iface.lpVtbl = &dtvt;
1673 sf->ISFHelper_iface.lpVtbl = &shvt;
1674 sf->pclsid = (CLSID *) & CLSID_ShellFSFolder;
1675 sf->outer_unk = outer_unk ? outer_unk : &sf->IUnknown_inner;
1677 hr = IUnknown_QueryInterface(&sf->IUnknown_inner, riid, ppv);
1678 IUnknown_Release(&sf->IUnknown_inner);
1680 TRACE ("--%p\n", *ppv);
1681 return hr;