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