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