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