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