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