Fixed a few prototypes in the USER driver.
[wine] / dlls / shell32 / shfldr_fs.c
1
2 /*
3  * file system folder
4  *
5  * Copyright 1997             Marcus Meissner
6  * Copyright 1998, 1999, 2002 Juergen Schmied
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30
31 #define COBJMACROS
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34
35 #include "winerror.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41
42 #include "ole2.h"
43 #include "shlguid.h"
44
45 #include "enumidlist.h"
46 #include "pidl.h"
47 #include "undocshell.h"
48 #include "shell32_main.h"
49 #include "shresdef.h"
50 #include "shlwapi.h"
51 #include "shellfolder.h"
52 #include "wine/debug.h"
53 #include "debughlp.h"
54 #include "shfldr.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL (shell);
57
58 /***********************************************************************
59 *   IShellFolder implementation
60 */
61
62 typedef struct {
63     const IUnknownVtbl        *lpVtbl;
64     LONG                ref;
65     const IShellFolder2Vtbl   *lpvtblShellFolder;
66     const IPersistFolder3Vtbl *lpvtblPersistFolder3;
67     const IDropTargetVtbl     *lpvtblDropTarget;
68     const ISFHelperVtbl       *lpvtblSFHelper;
69
70     IUnknown *pUnkOuter; /* used for aggregation */
71
72     CLSID *pclsid;
73
74     /* both paths are parsible from the desktop */
75     LPSTR sPathTarget;     /* complete path to target used for enumeration and ChangeNotify */
76
77     LPITEMIDLIST pidlRoot; /* absolute pidl */
78
79     UINT cfShellIDList;    /* clipboardformat for IDropTarget */
80     BOOL fAcceptFmt;       /* flag for pending Drop */
81 } IGenericSFImpl;
82
83 static const IUnknownVtbl unkvt;
84 static const IShellFolder2Vtbl sfvt;
85 static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3; /* IPersistFolder3 for a FS_Folder */
86 static const IDropTargetVtbl dtvt;
87 static const ISFHelperVtbl shvt;
88
89 #define _IShellFolder2_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblShellFolder)))
90 #define _ICOM_THIS_From_IShellFolder2(class, name) class* This = (class*)(((char*)name)-_IShellFolder2_Offset);
91
92 #define _IPersistFolder2_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblPersistFolder3)))
93 #define _ICOM_THIS_From_IPersistFolder2(class, name) class* This = (class*)(((char*)name)-_IPersistFolder2_Offset);
94
95 #define _IPersistFolder3_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblPersistFolder3)))
96 #define _ICOM_THIS_From_IPersistFolder3(class, name) class* This = (class*)(((char*)name)-_IPersistFolder3_Offset);
97
98 #define _IDropTarget_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblDropTarget)))
99 #define _ICOM_THIS_From_IDropTarget(class, name) class* This = (class*)(((char*)name)-_IDropTarget_Offset);
100
101 #define _ISFHelper_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblSFHelper)))
102 #define _ICOM_THIS_From_ISFHelper(class, name) class* This = (class*)(((char*)name)-_ISFHelper_Offset);
103
104 /*
105   converts This to an interface pointer
106 */
107 #define _IUnknown_(This)        (IUnknown*)&(This->lpVtbl)
108 #define _IShellFolder_(This)    (IShellFolder*)&(This->lpvtblShellFolder)
109 #define _IShellFolder2_(This)   (IShellFolder2*)&(This->lpvtblShellFolder)
110 #define _IPersist_(This)        (IPersist*)&(This->lpvtblPersistFolder3)
111 #define _IPersistFolder_(This)  (IPersistFolder*)&(This->lpvtblPersistFolder3)
112 #define _IPersistFolder2_(This) (IPersistFolder2*)&(This->lpvtblPersistFolder3)
113 #define _IPersistFolder3_(This) (IPersistFolder3*)&(This->lpvtblPersistFolder3)
114 #define _IDropTarget_(This)     (IDropTarget*)&(This->lpvtblDropTarget)
115 #define _ISFHelper_(This)       (ISFHelper*)&(This->lpvtblSFHelper)
116
117 /**************************************************************************
118 * registers clipboardformat once
119 */
120 static void SF_RegisterClipFmt (IGenericSFImpl * This)
121 {
122     TRACE ("(%p)\n", This);
123
124     if (!This->cfShellIDList) {
125         This->cfShellIDList = RegisterClipboardFormatA (CFSTR_SHELLIDLIST);
126     }
127 }
128
129 /**************************************************************************
130 * we need a separate IUnknown to handle aggregation
131 * (inner IUnknown)
132 */
133 static HRESULT WINAPI IUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppvObj)
134 {
135     IGenericSFImpl *This = (IGenericSFImpl *)iface;
136
137     TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
138
139     *ppvObj = NULL;
140
141     if (IsEqualIID (riid, &IID_IUnknown))
142         *ppvObj = _IUnknown_ (This);
143     else if (IsEqualIID (riid, &IID_IShellFolder))
144         *ppvObj = _IShellFolder_ (This);
145     else if (IsEqualIID (riid, &IID_IShellFolder2))
146         *ppvObj = _IShellFolder_ (This);
147     else if (IsEqualIID (riid, &IID_IPersist))
148         *ppvObj = _IPersist_ (This);
149     else if (IsEqualIID (riid, &IID_IPersistFolder))
150         *ppvObj = _IPersistFolder_ (This);
151     else if (IsEqualIID (riid, &IID_IPersistFolder2))
152         *ppvObj = _IPersistFolder2_ (This);
153     else if (IsEqualIID (riid, &IID_IPersistFolder3))
154         *ppvObj = _IPersistFolder3_ (This);
155     else if (IsEqualIID (riid, &IID_ISFHelper))
156         *ppvObj = _ISFHelper_ (This);
157     else if (IsEqualIID (riid, &IID_IDropTarget)) {
158         *ppvObj = _IDropTarget_ (This);
159         SF_RegisterClipFmt (This);
160     }
161
162     if (*ppvObj) {
163         IUnknown_AddRef ((IUnknown *) (*ppvObj));
164         TRACE ("-- Interface = %p\n", *ppvObj);
165         return S_OK;
166     }
167     TRACE ("-- Interface: E_NOINTERFACE\n");
168     return E_NOINTERFACE;
169 }
170
171 static ULONG WINAPI IUnknown_fnAddRef (IUnknown * iface)
172 {
173     IGenericSFImpl *This = (IGenericSFImpl *)iface;
174     ULONG refCount = InterlockedIncrement(&This->ref);
175
176     TRACE ("(%p)->(count=%lu)\n", This, refCount - 1);
177
178     return refCount;
179 }
180
181 static ULONG WINAPI IUnknown_fnRelease (IUnknown * iface)
182 {
183     IGenericSFImpl *This = (IGenericSFImpl *)iface;
184     ULONG refCount = InterlockedDecrement(&This->ref);
185
186     TRACE ("(%p)->(count=%lu)\n", This, refCount + 1);
187
188     if (!refCount) {
189         TRACE ("-- destroying IShellFolder(%p)\n", This);
190
191         if (This->pidlRoot)
192             SHFree (This->pidlRoot);
193         if (This->sPathTarget)
194             SHFree (This->sPathTarget);
195         LocalFree ((HLOCAL) This);
196     }
197     return refCount;
198 }
199
200 static const IUnknownVtbl unkvt =
201 {
202       IUnknown_fnQueryInterface,
203       IUnknown_fnAddRef,
204       IUnknown_fnRelease,
205 };
206
207 static shvheader GenericSFHeader[] = {
208     {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
209     {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
210     {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
211     {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
212     {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
213 };
214
215 #define GENERICSHELLVIEWCOLUMNS 5
216
217 /**************************************************************************
218 * IFSFolder_Constructor
219 *
220 * NOTES
221 *  creating undocumented ShellFS_Folder as part of an aggregation
222 *  {F3364BA0-65B9-11CE-A9BA-00AA004AE837}
223 *
224 */
225 HRESULT WINAPI
226 IFSFolder_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
227 {
228     IGenericSFImpl *sf;
229
230     TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
231
232     if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
233         return CLASS_E_NOAGGREGATION;
234     sf = (IGenericSFImpl *) LocalAlloc (LMEM_ZEROINIT, sizeof (IGenericSFImpl));
235     if (!sf)
236         return E_OUTOFMEMORY;
237
238     sf->ref = 0;
239     sf->lpVtbl = &unkvt;
240     sf->lpvtblShellFolder = &sfvt;
241     sf->lpvtblPersistFolder3 = &vt_FSFldr_PersistFolder3;
242     sf->lpvtblDropTarget = &dtvt;
243     sf->lpvtblSFHelper = &shvt;
244     sf->pclsid = (CLSID *) & CLSID_ShellFSFolder;
245     sf->pUnkOuter = pUnkOuter ? pUnkOuter : _IUnknown_ (sf);
246
247     if (!SUCCEEDED (IUnknown_QueryInterface (_IUnknown_ (sf), riid, ppv))) {
248         IUnknown_Release (_IUnknown_ (sf));
249         return E_NOINTERFACE;
250     }
251
252     TRACE ("--%p\n", *ppv);
253     return S_OK;
254 }
255
256 /**************************************************************************
257  *  IShellFolder_fnQueryInterface
258  *
259  * PARAMETERS
260  *  REFIID riid       [in ] Requested InterfaceID
261  *  LPVOID* ppvObject [out] Interface* to hold the result
262  */
263 static HRESULT WINAPI
264 IShellFolder_fnQueryInterface (IShellFolder2 * iface, REFIID riid,
265                                LPVOID * ppvObj)
266 {
267     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
268
269     TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
270
271     return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
272 }
273
274 /**************************************************************************
275 *  IShellFolder_AddRef
276 */
277
278 static ULONG WINAPI IShellFolder_fnAddRef (IShellFolder2 * iface)
279 {
280     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
281
282     TRACE ("(%p)->(count=%lu)\n", This, This->ref);
283
284     return IUnknown_AddRef (This->pUnkOuter);
285 }
286
287 /**************************************************************************
288  *  IShellFolder_fnRelease
289  */
290 static ULONG WINAPI IShellFolder_fnRelease (IShellFolder2 * iface)
291 {
292     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
293
294     TRACE ("(%p)->(count=%lu)\n", This, This->ref);
295
296     return IUnknown_Release (This->pUnkOuter);
297 }
298
299 /**************************************************************************
300  *  SHELL32_CreatePidlFromBindCtx  [internal]
301  *
302  *  If the caller bound File System Bind Data, assume it is the 
303  *   find data for the path.
304  *  This allows binding of paths that don't exist.
305  */
306 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
307 {
308     static const WCHAR szfsbc[] = {
309         'F','i','l','e',' ','S','y','s','t','e','m',' ',
310         'B','i','n','d',' ','D','a','t','a',0 };
311     IFileSystemBindData *fsbd = NULL;
312     LPITEMIDLIST pidl = NULL;
313     IUnknown *param = NULL;
314     WIN32_FIND_DATAW wfd;
315     HRESULT r;
316
317     TRACE("%p %s\n", pbc, debugstr_w(path));
318
319     if (!pbc)
320         return NULL;
321
322     /* see if the caller bound File System Bind Data */
323     r = IBindCtx_GetObjectParam( pbc, (LPOLESTR) szfsbc, &param );
324     if (FAILED(r))
325         return NULL;
326
327     r = IUnknown_QueryInterface( param, &IID_IFileSystemBindData,
328                                  (LPVOID*) &fsbd );
329     if (SUCCEEDED(r))
330     {
331         r = IFileSystemBindData_GetFindData( fsbd, &wfd );
332         if (SUCCEEDED(r))
333         {
334             lstrcpynW( &wfd.cFileName[0], path, MAX_PATH );
335             pidl = _ILCreateFromFindDataW( &wfd );
336         }
337         IFileSystemBindData_Release( fsbd );
338     }
339     
340     return pidl;
341 }
342
343 /**************************************************************************
344 * IShellFolder_ParseDisplayName {SHELL32}
345 *
346 * Parse a display name.
347 *
348 * PARAMS
349 *  hwndOwner       [in]  Parent window for any message's
350 *  pbc             [in]  optional FileSystemBindData context
351 *  lpszDisplayName [in]  Unicode displayname.
352 *  pchEaten        [out] (unicode) characters processed
353 *  ppidl           [out] complex pidl to item
354 *  pdwAttributes   [out] items attributes
355 *
356 * NOTES
357 *  Every folder tries to parse only its own (the leftmost) pidl and creates a
358 *  subfolder to evaluate the remaining parts.
359 *  Now we can parse into namespaces implemented by shell extensions
360 *
361 *  Behaviour on win98: lpszDisplayName=NULL -> crash
362 *                      lpszDisplayName="" -> returns mycoputer-pidl
363 *
364 * FIXME
365 *    pdwAttributes is not set
366 *    pchEaten is not set like in windows
367 */
368 static HRESULT WINAPI
369 IShellFolder_fnParseDisplayName (IShellFolder2 * iface,
370                                  HWND hwndOwner,
371                                  LPBC pbc,
372                                  LPOLESTR lpszDisplayName,
373                                  DWORD * pchEaten, LPITEMIDLIST * ppidl,
374                                  DWORD * pdwAttributes)
375 {
376     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
377
378     HRESULT hr = E_INVALIDARG;
379     LPCWSTR szNext = NULL;
380     WCHAR szElement[MAX_PATH];
381     WCHAR szPath[MAX_PATH];
382     LPITEMIDLIST pidlTemp = NULL;
383     DWORD len;
384
385     TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
386      This, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
387      pchEaten, ppidl, pdwAttributes);
388
389     if (!lpszDisplayName || !ppidl)
390         return E_INVALIDARG;
391
392     if (pchEaten)
393         *pchEaten = 0; /* strange but like the original */
394
395     pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName);
396     if (!pidlTemp && *lpszDisplayName)
397     {
398         /* get the next element */
399         szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
400
401         /* build the full pathname to the element */
402         /* lstrcpyW(szPath, This->sPathTarget); */
403         MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, szPath, MAX_PATH);
404         PathAddBackslashW(szPath);
405         len = lstrlenW(szPath);
406         lstrcpynW(szPath + len, szElement, MAX_PATH - len);
407
408         /* get the pidl */
409         hr = _ILCreateFromPathW(szPath, &pidlTemp);
410
411         if (SUCCEEDED(hr)) {
412             if (szNext && *szNext) {
413                 /* try to analyse the next element */
414                 hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc,
415                  &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
416             } else {
417                 /* it's the last element */
418                 if (pdwAttributes && *pdwAttributes) {
419                     hr = SHELL32_GetItemAttributes (_IShellFolder_ (This),
420                      pidlTemp, pdwAttributes);
421                 }
422             }
423         }
424     }
425
426     if (SUCCEEDED(hr))
427         *ppidl = pidlTemp;
428     else
429         *ppidl = NULL;
430
431     TRACE ("(%p)->(-- pidl=%p ret=0x%08lx)\n", This, ppidl ? *ppidl : 0, hr);
432
433     return hr;
434 }
435
436 /**************************************************************************
437 * IShellFolder_fnEnumObjects
438 * PARAMETERS
439 *  HWND          hwndOwner,    //[in ] Parent Window
440 *  DWORD         grfFlags,     //[in ] SHCONTF enumeration mask
441 *  LPENUMIDLIST* ppenumIDList  //[out] IEnumIDList interface
442 */
443 static HRESULT WINAPI
444 IShellFolder_fnEnumObjects (IShellFolder2 * iface, HWND hwndOwner,
445                             DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
446 {
447     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
448
449     TRACE ("(%p)->(HWND=%p flags=0x%08lx pplist=%p)\n", This, hwndOwner,
450      dwFlags, ppEnumIDList);
451
452     *ppEnumIDList = IEnumIDList_Constructor();
453     if (*ppEnumIDList)
454     {
455         WCHAR path[MAX_PATH];
456         MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, path, MAX_PATH);
457         CreateFolderEnumList(*ppEnumIDList, path, dwFlags);
458     }
459
460     TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
461
462     return *ppEnumIDList ? S_OK : E_OUTOFMEMORY;
463 }
464
465 /**************************************************************************
466 * IShellFolder_fnBindToObject
467 * PARAMETERS
468 *  LPCITEMIDLIST pidl,       //[in ] relative pidl to open
469 *  LPBC          pbc,        //[in ] optional FileSystemBindData context
470 *  REFIID        riid,       //[in ] Initial Interface
471 *  LPVOID*       ppvObject   //[out] Interface*
472 */
473 static HRESULT WINAPI
474 IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl,
475                              LPBC pbc, REFIID riid, LPVOID * ppvOut)
476 {
477     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
478
479     TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbc,
480      shdebugstr_guid (riid), ppvOut);
481
482     return SHELL32_BindToChild (This->pidlRoot, This->sPathTarget, pidl, riid,
483      ppvOut);
484 }
485
486 /**************************************************************************
487 *  IShellFolder_fnBindToStorage
488 * PARAMETERS
489 *  LPCITEMIDLIST pidl,       //[in ] complex pidl to store
490 *  LPBC          pbc,        //[in ] reserved
491 *  REFIID        riid,       //[in ] Initial storage interface
492 *  LPVOID*       ppvObject   //[out] Interface* returned
493 */
494 static HRESULT WINAPI
495 IShellFolder_fnBindToStorage (IShellFolder2 * iface, LPCITEMIDLIST pidl,
496                               LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
497 {
498     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
499
500     FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved,
501      shdebugstr_guid (riid), ppvOut);
502
503     *ppvOut = NULL;
504     return E_NOTIMPL;
505 }
506
507 /**************************************************************************
508 *  IShellFolder_fnCompareIDs
509 */
510
511 static HRESULT WINAPI
512 IShellFolder_fnCompareIDs (IShellFolder2 * iface, LPARAM lParam,
513                            LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
514 {
515     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
516
517     int nReturn;
518
519     TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
520     nReturn = SHELL32_CompareIDs (_IShellFolder_ (This), lParam, pidl1, pidl2);
521     TRACE ("-- %i\n", nReturn);
522     return nReturn;
523 }
524
525 /**************************************************************************
526 * IShellFolder_fnCreateViewObject
527 */
528 static HRESULT WINAPI
529 IShellFolder_fnCreateViewObject (IShellFolder2 * iface, HWND hwndOwner,
530                                  REFIID riid, LPVOID * ppvOut)
531 {
532     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
533
534     LPSHELLVIEW pShellView;
535     HRESULT hr = E_INVALIDARG;
536
537     TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid (riid),
538      ppvOut);
539
540     if (ppvOut) {
541         *ppvOut = NULL;
542
543         if (IsEqualIID (riid, &IID_IDropTarget)) {
544             hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, ppvOut);
545         } else if (IsEqualIID (riid, &IID_IContextMenu)) {
546             FIXME ("IContextMenu not implemented\n");
547             hr = E_NOTIMPL;
548         } else if (IsEqualIID (riid, &IID_IShellView)) {
549             pShellView = IShellView_Constructor ((IShellFolder *) iface);
550             if (pShellView) {
551                 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
552                 IShellView_Release (pShellView);
553             }
554         }
555     }
556     TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
557     return hr;
558 }
559
560 /**************************************************************************
561 *  IShellFolder_fnGetAttributesOf
562 *
563 * PARAMETERS
564 *  UINT            cidl,     //[in ] num elements in pidl array
565 *  LPCITEMIDLIST*  apidl,    //[in ] simple pidl array
566 *  ULONG*          rgfInOut) //[out] result array
567 *
568 */
569 static HRESULT WINAPI
570 IShellFolder_fnGetAttributesOf (IShellFolder2 * iface, UINT cidl,
571                                 LPCITEMIDLIST * apidl, DWORD * rgfInOut)
572 {
573     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
574
575     HRESULT hr = S_OK;
576
577     TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08lx))\n", This, cidl, apidl,
578      rgfInOut, rgfInOut ? *rgfInOut : 0);
579
580     if (!rgfInOut)
581         return E_INVALIDARG;
582     if (cidl && !apidl)
583         return E_INVALIDARG;
584
585     if (*rgfInOut == 0)
586         *rgfInOut = ~0;
587
588     if(cidl == 0){
589         IShellFolder *psfParent = NULL;
590         LPCITEMIDLIST rpidl = NULL;
591
592         hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, (LPCITEMIDLIST*)&rpidl);
593         if(SUCCEEDED(hr)) {
594             SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
595             IShellFolder_Release(psfParent);
596         }
597     }
598     else {
599         while (cidl > 0 && *apidl) {
600             pdump (*apidl);
601             SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
602             apidl++;
603             cidl--;
604         }
605     }
606     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
607     *rgfInOut &= ~SFGAO_VALIDATE;
608
609     TRACE ("-- result=0x%08lx\n", *rgfInOut);
610
611     return hr;
612 }
613
614 /**************************************************************************
615 *  IShellFolder_fnGetUIObjectOf
616 *
617 * PARAMETERS
618 *  HWND           hwndOwner, //[in ] Parent window for any output
619 *  UINT           cidl,      //[in ] array size
620 *  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
621 *  REFIID         riid,      //[in ] Requested Interface
622 *  UINT*          prgfInOut, //[   ] reserved
623 *  LPVOID*        ppvObject) //[out] Resulting Interface
624 *
625 * NOTES
626 *  This function gets asked to return "view objects" for one or more (multiple
627 *  select) items:
628 *  The viewobject typically is an COM object with one of the following
629 *  interfaces:
630 *  IExtractIcon,IDataObject,IContextMenu
631 *  In order to support icon positions in the default Listview your DataObject
632 *  must implement the SetData method (in addition to GetData :) - the shell
633 *  passes a barely documented "Icon positions" structure to SetData when the
634 *  drag starts, and GetData's it if the drop is in another explorer window that
635 *  needs the positions.
636 */
637 static HRESULT WINAPI
638 IShellFolder_fnGetUIObjectOf (IShellFolder2 * iface,
639                               HWND hwndOwner,
640                               UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
641                               UINT * prgfInOut, LPVOID * ppvOut)
642 {
643     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
644
645     LPITEMIDLIST pidl;
646     IUnknown *pObj = NULL;
647     HRESULT hr = E_INVALIDARG;
648
649     TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
650      This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
651
652     if (ppvOut) {
653         *ppvOut = NULL;
654
655         if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1)) {
656             pObj = (LPUNKNOWN) ISvItemCm_Constructor ((IShellFolder *) iface,
657              This->pidlRoot, apidl, cidl);
658             hr = S_OK;
659         } else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1)) {
660             pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
661              This->pidlRoot, apidl, cidl);
662             hr = S_OK;
663         } else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1)) {
664             pidl = ILCombine (This->pidlRoot, apidl[0]);
665             pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
666             SHFree (pidl);
667             hr = S_OK;
668         } else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1)) {
669             pidl = ILCombine (This->pidlRoot, apidl[0]);
670             pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
671             SHFree (pidl);
672             hr = S_OK;
673         } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) {
674             hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget,
675              (LPVOID *) & pObj);
676         } else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
677          IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1)) {
678             pidl = ILCombine (This->pidlRoot, apidl[0]);
679             hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
680             SHFree (pidl);
681         } else {
682             hr = E_NOINTERFACE;
683         }
684
685         if (SUCCEEDED(hr) && !pObj)
686             hr = E_OUTOFMEMORY;
687
688         *ppvOut = pObj;
689     }
690     TRACE ("(%p)->hr=0x%08lx\n", This, hr);
691     return hr;
692 }
693
694 static const WCHAR AdvancedW[] = { 'S','O','F','T','W','A','R','E',
695  '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
696  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
697  'o','r','e','r','\\','A','d','v','a','n','c','e','d',0 };
698 static const WCHAR HideFileExtW[] = { 'H','i','d','e','F','i','l','e','E','x',
699  't',0 };
700 static const WCHAR NeverShowExtW[] = { 'N','e','v','e','r','S','h','o','w','E',
701  'x','t',0 };
702
703 /******************************************************************************
704  * SHELL_FS_HideExtension [Internal]
705  *
706  * Query the registry if the filename extension of a given path should be 
707  * hidden.
708  *
709  * PARAMS
710  *  szPath [I] Relative or absolute path of a file
711  *  
712  * RETURNS
713  *  TRUE, if the filename's extension should be hidden
714  *  FALSE, otherwise.
715  */
716 BOOL SHELL_FS_HideExtension(LPWSTR szPath)
717 {
718     HKEY hKey;
719     DWORD dwData;
720     DWORD dwDataSize = sizeof (DWORD);
721     BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
722     
723     if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
724         if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
725             doHide = dwData;
726         RegCloseKey (hKey);
727     }
728
729     if (!doHide) {
730         LPWSTR ext = PathFindExtensionW(szPath);
731
732         if (*ext != '\0') {
733             WCHAR classname[MAX_PATH];
734             LONG classlen = sizeof(classname);
735
736             if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
737                 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
738                     if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
739                         doHide = TRUE;
740                     RegCloseKey(hKey);
741                 }
742         }
743     }
744     return doHide;
745 }
746     
747 void SHELL_FS_ProcessDisplayFilename(LPSTR szPath, DWORD dwFlags)
748 {
749     WCHAR pathW[MAX_PATH];
750
751     /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
752     if (!(dwFlags & SHGDN_FORPARSING) &&
753         ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
754         MultiByteToWideChar(CP_ACP, 0, szPath, -1, pathW, MAX_PATH);
755         if (SHELL_FS_HideExtension(pathW) && szPath[0] != '.')
756             PathRemoveExtensionA (szPath);
757     }
758 }
759
760 /**************************************************************************
761 *  IShellFolder_fnGetDisplayNameOf
762 *  Retrieves the display name for the specified file object or subfolder
763 *
764 * PARAMETERS
765 *  LPCITEMIDLIST pidl,    //[in ] complex pidl to item
766 *  DWORD         dwFlags, //[in ] SHGNO formatting flags
767 *  LPSTRRET      lpName)  //[out] Returned display name
768 *
769 * FIXME
770 *  if the name is in the pidl the ret value should be a STRRET_OFFSET
771 */
772
773 static HRESULT WINAPI
774 IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
775                                  DWORD dwFlags, LPSTRRET strRet)
776 {
777     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
778
779     HRESULT hr = S_OK;
780     int len = 0;
781
782     TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", This, pidl, dwFlags, strRet);
783     pdump (pidl);
784
785     if (!pidl || !strRet)
786         return E_INVALIDARG;
787     
788     strRet->uType = STRRET_CSTR;
789     if (_ILIsDesktop(pidl)) { /* empty pidl */
790         if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
791             (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER)) 
792         {
793             if (This->sPathTarget)
794                 lstrcpynA(strRet->u.cStr, This->sPathTarget, MAX_PATH);
795         } else {
796             /* pidl has to contain exactly one non null SHITEMID */
797             hr = E_INVALIDARG;
798         }
799     } else if (_ILIsPidlSimple(pidl)) {
800         if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
801             (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && 
802             This->sPathTarget) 
803         {
804             lstrcpynA(strRet->u.cStr, This->sPathTarget, MAX_PATH);
805             PathAddBackslashA(strRet->u.cStr);
806             len = lstrlenA(strRet->u.cStr);
807         }
808         _ILSimpleGetText(pidl, strRet->u.cStr + len, MAX_PATH - len);
809         if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(strRet->u.cStr, dwFlags);
810     } else {
811         hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, strRet->u.cStr, MAX_PATH);
812     }
813
814     TRACE ("-- (%p)->(%s)\n", This, strRet->u.cStr);
815     return hr;
816 }
817
818 /**************************************************************************
819 *  IShellFolder_fnSetNameOf
820 *  Changes the name of a file object or subfolder, possibly changing its item
821 *  identifier in the process.
822 *
823 * PARAMETERS
824 *  HWND          hwndOwner,  //[in ] Owner window for output
825 *  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
826 *  LPCOLESTR     lpszName,   //[in ] the items new display name
827 *  DWORD         dwFlags,    //[in ] SHGNO formatting flags
828 *  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
829 */
830 static HRESULT WINAPI IShellFolder_fnSetNameOf (IShellFolder2 * iface,
831                                                 HWND hwndOwner,
832                                                 LPCITEMIDLIST pidl,
833                                                 LPCOLESTR lpName,
834                                                 DWORD dwFlags,
835                                                 LPITEMIDLIST * pPidlOut)
836 {
837     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
838     WCHAR szSrc[MAX_PATH], szDest[MAX_PATH];
839     LPWSTR ptr;
840     BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
841
842     TRACE ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", This, hwndOwner, pidl,
843      debugstr_w (lpName), dwFlags, pPidlOut);
844
845     /* build source path */
846     MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, szSrc, MAX_PATH);
847     ptr = PathAddBackslashW (szSrc);
848     if (ptr)
849         _ILSimpleGetTextW (pidl, ptr, MAX_PATH - (ptr - szSrc));
850
851     /* build destination path */
852     if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
853         MultiByteToWideChar(CP_ACP, 0, This->sPathTarget, -1, szDest, MAX_PATH);
854         ptr = PathAddBackslashW (szDest);
855         if (ptr)
856             lstrcpynW(ptr, lpName, MAX_PATH - (ptr - szDest));
857     } else
858         lstrcpynW(szDest, lpName, MAX_PATH);
859
860     if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
861         WCHAR *ext = PathFindExtensionW(szSrc);
862         if(*ext != '\0') {
863             INT len = strlenW(szDest);
864             lstrcpynW(szDest + len, ext, MAX_PATH - len);
865         }
866     }
867     
868     TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
869
870     if (MoveFileW (szSrc, szDest)) {
871         HRESULT hr = S_OK;
872
873         if (pPidlOut)
874             hr = _ILCreateFromPathW(szDest, pPidlOut);
875
876         SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
877          SHCNF_PATHW, szSrc, szDest);
878
879         return hr;
880     }
881
882     return E_FAIL;
883 }
884
885 static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID (IShellFolder2 *iface,
886                                                            GUID * pguid)
887 {
888     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
889     FIXME ("(%p)\n", This);
890     return E_NOTIMPL;
891 }
892 static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface,
893                                                    IEnumExtraSearch ** ppenum)
894 {
895     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
896     FIXME ("(%p)\n", This);
897     return E_NOTIMPL;
898 }
899
900 static HRESULT WINAPI
901 IShellFolder_fnGetDefaultColumn (IShellFolder2 * iface, DWORD dwRes,
902                                  ULONG * pSort, ULONG * pDisplay)
903 {
904     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
905
906     TRACE ("(%p)\n", This);
907
908     if (pSort)
909         *pSort = 0;
910     if (pDisplay)
911         *pDisplay = 0;
912
913     return S_OK;
914 }
915
916 static HRESULT WINAPI
917 IShellFolder_fnGetDefaultColumnState (IShellFolder2 * iface, UINT iColumn,
918                                       DWORD * pcsFlags)
919 {
920     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
921
922     TRACE ("(%p)\n", This);
923
924     if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
925         return E_INVALIDARG;
926
927     *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
928
929     return S_OK;
930 }
931
932 static HRESULT WINAPI
933 IShellFolder_fnGetDetailsEx (IShellFolder2 * iface, LPCITEMIDLIST pidl,
934                              const SHCOLUMNID * pscid, VARIANT * pv)
935 {
936     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
937     FIXME ("(%p)\n", This);
938
939     return E_NOTIMPL;
940 }
941
942 static HRESULT WINAPI
943 IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
944                              UINT iColumn, SHELLDETAILS * psd)
945 {
946     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
947     HRESULT hr = E_FAIL;
948
949     TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
950
951     if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
952         return E_INVALIDARG;
953
954     if (!pidl) {
955         /* the header titles */
956         psd->fmt = GenericSFHeader[iColumn].fmt;
957         psd->cxChar = GenericSFHeader[iColumn].cxChar;
958         psd->str.uType = STRRET_CSTR;
959         LoadStringA (shell32_hInstance, GenericSFHeader[iColumn].colnameid,
960          psd->str.u.cStr, MAX_PATH);
961         return S_OK;
962     } else {
963         /* the data from the pidl */
964         switch (iColumn) {
965         case 0:                /* name */
966             hr = IShellFolder_GetDisplayNameOf (iface, pidl,
967              SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
968             break;
969         case 1:                /* size */
970             _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH);
971             break;
972         case 2:                /* type */
973             _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
974             break;
975         case 3:                /* date */
976             _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH);
977             break;
978         case 4:                /* attributes */
979             _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
980             break;
981         }
982         hr = S_OK;
983         psd->str.uType = STRRET_CSTR;
984     }
985
986     return hr;
987 }
988
989 static HRESULT WINAPI
990 IShellFolder_fnMapColumnToSCID (IShellFolder2 * iface, UINT column,
991                                 SHCOLUMNID * pscid)
992 {
993     _ICOM_THIS_From_IShellFolder2 (IGenericSFImpl, iface)
994     FIXME ("(%p)\n", This);
995     return E_NOTIMPL;
996 }
997
998 static const IShellFolder2Vtbl sfvt =
999 {
1000     IShellFolder_fnQueryInterface,
1001     IShellFolder_fnAddRef,
1002     IShellFolder_fnRelease,
1003     IShellFolder_fnParseDisplayName,
1004     IShellFolder_fnEnumObjects,
1005     IShellFolder_fnBindToObject,
1006     IShellFolder_fnBindToStorage,
1007     IShellFolder_fnCompareIDs,
1008     IShellFolder_fnCreateViewObject,
1009     IShellFolder_fnGetAttributesOf,
1010     IShellFolder_fnGetUIObjectOf,
1011     IShellFolder_fnGetDisplayNameOf,
1012     IShellFolder_fnSetNameOf,
1013     /* ShellFolder2 */
1014     IShellFolder_fnGetDefaultSearchGUID,
1015     IShellFolder_fnEnumSearches,
1016     IShellFolder_fnGetDefaultColumn,
1017     IShellFolder_fnGetDefaultColumnState,
1018     IShellFolder_fnGetDetailsEx,
1019     IShellFolder_fnGetDetailsOf,
1020     IShellFolder_fnMapColumnToSCID
1021 };
1022
1023 /****************************************************************************
1024  * ISFHelper for IShellFolder implementation
1025  */
1026
1027 static HRESULT WINAPI
1028 ISFHelper_fnQueryInterface (ISFHelper * iface, REFIID riid, LPVOID * ppvObj)
1029 {
1030     _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface);
1031
1032     TRACE ("(%p)->(count=%lu)\n", This, This->ref);
1033
1034     return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
1035 }
1036
1037 static ULONG WINAPI ISFHelper_fnAddRef (ISFHelper * iface)
1038 {
1039     _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface);
1040
1041     TRACE ("(%p)->(count=%lu)\n", This, This->ref);
1042
1043     return IUnknown_AddRef (This->pUnkOuter);
1044 }
1045
1046 static ULONG WINAPI ISFHelper_fnRelease (ISFHelper * iface)
1047 {
1048     _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface);
1049
1050     TRACE ("(%p)\n", This);
1051
1052     return IUnknown_Release (This->pUnkOuter);
1053 }
1054
1055 /****************************************************************************
1056  * ISFHelper_fnAddFolder
1057  *
1058  * creates a unique folder name
1059  */
1060
1061 static HRESULT WINAPI
1062 ISFHelper_fnGetUniqueName (ISFHelper * iface, LPSTR lpName, UINT uLen)
1063 {
1064     _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface)
1065     IEnumIDList *penum;
1066     HRESULT hr;
1067     char szText[MAX_PATH];
1068     const char *szNewFolder = "New Folder";
1069
1070     TRACE ("(%p)(%s %u)\n", This, lpName, uLen);
1071
1072     if (uLen < strlen (szNewFolder) + 4)
1073         return E_POINTER;
1074
1075     strcpy (lpName, szNewFolder);
1076
1077     hr = IShellFolder_fnEnumObjects (_IShellFolder2_ (This), 0,
1078      SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1079     if (penum) {
1080         LPITEMIDLIST pidl;
1081         DWORD dwFetched;
1082         int i = 1;
1083
1084 next:
1085         IEnumIDList_Reset (penum);
1086         while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) &&
1087          dwFetched) {
1088             _ILSimpleGetText (pidl, szText, MAX_PATH);
1089             if (0 == strcasecmp (szText, lpName)) {
1090                 sprintf (lpName, "%s %d", szNewFolder, i++);
1091                 if (i > 99) {
1092                     hr = E_FAIL;
1093                     break;
1094                 }
1095                 goto next;
1096             }
1097         }
1098
1099         IEnumIDList_Release (penum);
1100     }
1101     return hr;
1102 }
1103
1104 /****************************************************************************
1105  * ISFHelper_fnAddFolder
1106  *
1107  * adds a new folder.
1108  */
1109
1110 static HRESULT WINAPI
1111 ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCSTR lpName,
1112                        LPITEMIDLIST * ppidlOut)
1113 {
1114     _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface)
1115     char lpstrNewDir[MAX_PATH];
1116     DWORD bRes;
1117     HRESULT hres = E_FAIL;
1118
1119     TRACE ("(%p)(%s %p)\n", This, lpName, ppidlOut);
1120
1121     strcpy (lpstrNewDir, This->sPathTarget);
1122     PathAppendA(lpstrNewDir, lpName);
1123
1124     bRes = CreateDirectoryA (lpstrNewDir, NULL);
1125     if (bRes) {
1126         SHChangeNotify (SHCNE_MKDIR, SHCNF_PATHA, lpstrNewDir, NULL);
1127
1128         hres = S_OK;
1129
1130         if (ppidlOut)
1131                 hres = _ILCreateFromPathA(lpstrNewDir, ppidlOut);
1132     } else {
1133         char lpstrText[128 + MAX_PATH];
1134         char lpstrTempText[128];
1135         char lpstrCaption[256];
1136
1137         /* Cannot Create folder because of permissions */
1138         LoadStringA (shell32_hInstance, IDS_CREATEFOLDER_DENIED, lpstrTempText,
1139          sizeof (lpstrTempText));
1140         LoadStringA (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, lpstrCaption,
1141          sizeof (lpstrCaption));
1142         sprintf (lpstrText, lpstrTempText, lpstrNewDir);
1143         MessageBoxA (hwnd, lpstrText, lpstrCaption, MB_OK | MB_ICONEXCLAMATION);
1144     }
1145
1146     return hres;
1147 }
1148
1149 /****************************************************************************
1150  * ISFHelper_fnDeleteItems
1151  *
1152  * deletes items in folder
1153  */
1154 static HRESULT WINAPI
1155 ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl)
1156 {
1157     _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface)
1158     UINT i;
1159     char szPath[MAX_PATH];
1160     BOOL bConfirm = TRUE;
1161
1162     TRACE ("(%p)(%u %p)\n", This, cidl, apidl);
1163
1164     /* deleting multiple items so give a slightly different warning */
1165     if (cidl != 1) {
1166         char tmp[8];
1167
1168         snprintf (tmp, sizeof (tmp), "%d", cidl);
1169         if (!SHELL_ConfirmDialog(ASK_DELETE_MULTIPLE_ITEM, tmp))
1170             return E_FAIL;
1171         bConfirm = FALSE;
1172     }
1173
1174     for (i = 0; i < cidl; i++) {
1175         strcpy (szPath, This->sPathTarget);
1176         PathAddBackslashA (szPath);
1177         _ILSimpleGetText (apidl[i], szPath + strlen (szPath), MAX_PATH);
1178
1179         if (_ILIsFolder (apidl[i])) {
1180             LPITEMIDLIST pidl;
1181
1182             TRACE ("delete %s\n", szPath);
1183             if (!SHELL_DeleteDirectoryA (szPath, bConfirm)) {
1184                 TRACE ("delete %s failed, bConfirm=%d\n", szPath, bConfirm);
1185                 return E_FAIL;
1186             }
1187             pidl = ILCombine (This->pidlRoot, apidl[i]);
1188             SHChangeNotify (SHCNE_RMDIR, SHCNF_IDLIST, pidl, NULL);
1189             SHFree (pidl);
1190         } else if (_ILIsValue (apidl[i])) {
1191             LPITEMIDLIST pidl;
1192
1193             TRACE ("delete %s\n", szPath);
1194             if (!SHELL_DeleteFileA (szPath, bConfirm)) {
1195                 TRACE ("delete %s failed, bConfirm=%d\n", szPath, bConfirm);
1196                 return E_FAIL;
1197             }
1198             pidl = ILCombine (This->pidlRoot, apidl[i]);
1199             SHChangeNotify (SHCNE_DELETE, SHCNF_IDLIST, pidl, NULL);
1200             SHFree (pidl);
1201         }
1202
1203     }
1204     return S_OK;
1205 }
1206
1207 /****************************************************************************
1208  * ISFHelper_fnCopyItems
1209  *
1210  * copies items to this folder
1211  */
1212 static HRESULT WINAPI
1213 ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl,
1214                        LPCITEMIDLIST * apidl)
1215 {
1216     UINT i;
1217     IPersistFolder2 *ppf2 = NULL;
1218     char szSrcPath[MAX_PATH],
1219       szDstPath[MAX_PATH];
1220
1221     _ICOM_THIS_From_ISFHelper (IGenericSFImpl, iface);
1222
1223     TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl);
1224
1225     IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2,
1226      (LPVOID *) & ppf2);
1227     if (ppf2) {
1228         LPITEMIDLIST pidl;
1229
1230         if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) {
1231             for (i = 0; i < cidl; i++) {
1232                 SHGetPathFromIDListA (pidl, szSrcPath);
1233                 PathAddBackslashA (szSrcPath);
1234                 _ILSimpleGetText (apidl[i], szSrcPath + strlen (szSrcPath),
1235                  MAX_PATH);
1236
1237                 strcpy (szDstPath, This->sPathTarget);
1238                 PathAddBackslashA (szDstPath);
1239                 _ILSimpleGetText (apidl[i], szDstPath + strlen (szDstPath),
1240                  MAX_PATH);
1241                 MESSAGE ("would copy %s to %s\n", szSrcPath, szDstPath);
1242             }
1243             SHFree (pidl);
1244         }
1245         IPersistFolder2_Release (ppf2);
1246     }
1247     return S_OK;
1248 }
1249
1250 static const ISFHelperVtbl shvt =
1251 {
1252     ISFHelper_fnQueryInterface,
1253     ISFHelper_fnAddRef,
1254     ISFHelper_fnRelease,
1255     ISFHelper_fnGetUniqueName,
1256     ISFHelper_fnAddFolder,
1257     ISFHelper_fnDeleteItems,
1258     ISFHelper_fnCopyItems
1259 };
1260
1261 /************************************************************************
1262  * IFSFldr_PersistFolder3_QueryInterface
1263  *
1264  */
1265 static HRESULT WINAPI
1266 IFSFldr_PersistFolder3_QueryInterface (IPersistFolder3 * iface, REFIID iid,
1267                                        LPVOID * ppvObj)
1268 {
1269     _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface);
1270
1271     TRACE ("(%p)\n", This);
1272
1273     return IUnknown_QueryInterface (This->pUnkOuter, iid, ppvObj);
1274 }
1275
1276 /************************************************************************
1277  * IFSFldr_PersistFolder3_AddRef
1278  *
1279  */
1280 static ULONG WINAPI
1281 IFSFldr_PersistFolder3_AddRef (IPersistFolder3 * iface)
1282 {
1283     _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface);
1284
1285     TRACE ("(%p)->(count=%lu)\n", This, This->ref);
1286
1287     return IUnknown_AddRef (This->pUnkOuter);
1288 }
1289
1290 /************************************************************************
1291  * IFSFldr_PersistFolder3_Release
1292  *
1293  */
1294 static ULONG WINAPI
1295 IFSFldr_PersistFolder3_Release (IPersistFolder3 * iface)
1296 {
1297     _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface);
1298
1299     TRACE ("(%p)->(count=%lu)\n", This, This->ref);
1300
1301     return IUnknown_Release (This->pUnkOuter);
1302 }
1303
1304 /************************************************************************
1305  * IFSFldr_PersistFolder3_GetClassID
1306  */
1307 static HRESULT WINAPI
1308 IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId)
1309 {
1310     _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface);
1311
1312     TRACE ("(%p)\n", This);
1313
1314     if (!lpClassId)
1315         return E_POINTER;
1316     *lpClassId = *This->pclsid;
1317
1318     return S_OK;
1319 }
1320
1321 /************************************************************************
1322  * IFSFldr_PersistFolder3_Initialize
1323  *
1324  * NOTES
1325  *  sPathTarget is not set. Don't know how to handle in a non rooted environment.
1326  */
1327 static HRESULT WINAPI
1328 IFSFldr_PersistFolder3_Initialize (IPersistFolder3 * iface, LPCITEMIDLIST pidl)
1329 {
1330     char sTemp[MAX_PATH];
1331
1332     _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface);
1333
1334     TRACE ("(%p)->(%p)\n", This, pidl);
1335
1336     if (This->pidlRoot)
1337         SHFree (This->pidlRoot);     /* free the old pidl */
1338     This->pidlRoot = ILClone (pidl); /* set my pidl */
1339
1340     if (This->sPathTarget)
1341         SHFree (This->sPathTarget);
1342
1343     /* set my path */
1344     if (SHGetPathFromIDListA (pidl, sTemp)) {
1345         This->sPathTarget = SHAlloc (strlen (sTemp) + 1);
1346         strcpy (This->sPathTarget, sTemp);
1347     }
1348
1349     TRACE ("--(%p)->(%s)\n", This, This->sPathTarget);
1350     return S_OK;
1351 }
1352
1353 /**************************************************************************
1354  * IFSFldr_PersistFolder3_GetCurFolder
1355  */
1356 static HRESULT WINAPI
1357 IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface,
1358                                        LPITEMIDLIST * pidl)
1359 {
1360     _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface);
1361
1362     TRACE ("(%p)->(%p)\n", This, pidl);
1363
1364     if (!pidl) return E_POINTER;
1365     *pidl = ILClone (This->pidlRoot);
1366     return S_OK;
1367 }
1368
1369 /**************************************************************************
1370  * IFSFldr_PersistFolder3_InitializeEx
1371  *
1372  * FIXME: error handling
1373  */
1374 static HRESULT WINAPI
1375 IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface,
1376                                      IBindCtx * pbc, LPCITEMIDLIST pidlRoot,
1377                                      const PERSIST_FOLDER_TARGET_INFO * ppfti)
1378 {
1379     char sTemp[MAX_PATH];
1380
1381     _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface);
1382
1383     TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti);
1384     if (ppfti)
1385         TRACE ("--%p %s %s 0x%08lx 0x%08x\n",
1386          ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1387          debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1388          ppfti->csidl);
1389
1390     pdump (pidlRoot);
1391     if (ppfti && ppfti->pidlTargetFolder)
1392         pdump (ppfti->pidlTargetFolder);
1393
1394     if (This->pidlRoot)
1395         __SHFreeAndNil (&This->pidlRoot);    /* free the old */
1396     if (This->sPathTarget)
1397         __SHFreeAndNil (&This->sPathTarget);
1398
1399     /*
1400      * Root path and pidl
1401      */
1402     This->pidlRoot = ILClone (pidlRoot);
1403
1404     /*
1405      *  the target folder is spezified in csidl OR pidlTargetFolder OR
1406      *  szTargetParsingName
1407      */
1408     if (ppfti) {
1409         if (ppfti->csidl != -1) {
1410             if (SHGetSpecialFolderPathA (0, sTemp, ppfti->csidl,
1411              ppfti->csidl & CSIDL_FLAG_CREATE)) {
1412                 __SHCloneStrA (&This->sPathTarget, sTemp);
1413             }
1414         } else if (ppfti->szTargetParsingName[0]) {
1415             __SHCloneStrWtoA (&This->sPathTarget, ppfti->szTargetParsingName);
1416         } else if (ppfti->pidlTargetFolder) {
1417             if (SHGetPathFromIDListA (ppfti->pidlTargetFolder, sTemp)) {
1418                 __SHCloneStrA (&This->sPathTarget, sTemp);
1419             }
1420         }
1421     }
1422
1423     TRACE ("--(%p)->(target=%s)\n", This, debugstr_a (This->sPathTarget));
1424     pdump (This->pidlRoot);
1425     return (This->sPathTarget) ? S_OK : E_FAIL;
1426 }
1427
1428 static HRESULT WINAPI
1429 IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3 * iface,
1430                                             PERSIST_FOLDER_TARGET_INFO * ppfti)
1431 {
1432     _ICOM_THIS_From_IPersistFolder3 (IGenericSFImpl, iface);
1433     FIXME ("(%p)->(%p)\n", This, ppfti);
1434     ZeroMemory (ppfti, sizeof (ppfti));
1435     return E_NOTIMPL;
1436 }
1437
1438 static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3 =
1439 {
1440     IFSFldr_PersistFolder3_QueryInterface,
1441     IFSFldr_PersistFolder3_AddRef,
1442     IFSFldr_PersistFolder3_Release,
1443     IFSFldr_PersistFolder3_GetClassID,
1444     IFSFldr_PersistFolder3_Initialize,
1445     IFSFldr_PersistFolder3_fnGetCurFolder,
1446     IFSFldr_PersistFolder3_InitializeEx,
1447     IFSFldr_PersistFolder3_GetFolderTargetInfo
1448 };
1449
1450 /****************************************************************************
1451  * ISFDropTarget implementation
1452  */
1453 static BOOL
1454 ISFDropTarget_QueryDrop (IDropTarget * iface, DWORD dwKeyState,
1455                          LPDWORD pdwEffect)
1456 {
1457     DWORD dwEffect = *pdwEffect;
1458
1459     _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface);
1460
1461     *pdwEffect = DROPEFFECT_NONE;
1462
1463     if (This->fAcceptFmt) { /* Does our interpretation of the keystate ... */
1464         *pdwEffect = KeyStateToDropEffect (dwKeyState);
1465
1466         /* ... matches the desired effect ? */
1467         if (dwEffect & *pdwEffect) {
1468             return TRUE;
1469         }
1470     }
1471     return FALSE;
1472 }
1473
1474 static HRESULT WINAPI
1475 ISFDropTarget_QueryInterface (IDropTarget * iface, REFIID riid, LPVOID * ppvObj)
1476 {
1477     _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface);
1478
1479     TRACE ("(%p)\n", This);
1480
1481     return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
1482 }
1483
1484 static ULONG WINAPI ISFDropTarget_AddRef (IDropTarget * iface)
1485 {
1486     _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface);
1487
1488     TRACE ("(%p)\n", This);
1489
1490     return IUnknown_AddRef (This->pUnkOuter);
1491 }
1492
1493 static ULONG WINAPI ISFDropTarget_Release (IDropTarget * iface)
1494 {
1495     _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface);
1496
1497     TRACE ("(%p)\n", This);
1498
1499     return IUnknown_Release (This->pUnkOuter);
1500 }
1501
1502 static HRESULT WINAPI
1503 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
1504                          DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1505 {
1506     FORMATETC fmt;
1507
1508     _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface);
1509
1510     TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject);
1511
1512     InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL);
1513
1514     This->fAcceptFmt = (S_OK == IDataObject_QueryGetData (pDataObject, &fmt)) ?
1515      TRUE : FALSE;
1516
1517     ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1518
1519     return S_OK;
1520 }
1521
1522 static HRESULT WINAPI
1523 ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
1524                         DWORD * pdwEffect)
1525 {
1526     _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface);
1527
1528     TRACE ("(%p)\n", This);
1529
1530     if (!pdwEffect)
1531         return E_INVALIDARG;
1532
1533     ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1534
1535     return S_OK;
1536 }
1537
1538 static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
1539 {
1540     _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface);
1541
1542     TRACE ("(%p)\n", This);
1543
1544     This->fAcceptFmt = FALSE;
1545
1546     return S_OK;
1547 }
1548
1549 static HRESULT WINAPI
1550 ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
1551                     DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1552 {
1553     _ICOM_THIS_From_IDropTarget (IGenericSFImpl, iface);
1554
1555     FIXME ("(%p) object dropped\n", This);
1556
1557     return E_NOTIMPL;
1558 }
1559
1560 static const IDropTargetVtbl dtvt = {
1561     ISFDropTarget_QueryInterface,
1562     ISFDropTarget_AddRef,
1563     ISFDropTarget_Release,
1564     ISFDropTarget_DragEnter,
1565     ISFDropTarget_DragOver,
1566     ISFDropTarget_DragLeave,
1567     ISFDropTarget_Drop
1568 };