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