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