shell32: Fix FOLDERID_Document definition.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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     const IUnknownVtbl        *lpVtbl;
64     LONG                ref;
65     const IShellFolder2Vtbl   *lpvtblShellFolder;
66     const IPersistFolder3Vtbl *lpvtblPersistFolder3;
67     const IDropTargetVtbl     *lpvtblDropTarget;
68     const ISFHelperVtbl       *lpvtblSFHelper;
69
70     IUnknown *pUnkOuter; /* used for aggregation */
71
72     CLSID *pclsid;
73
74     /* both paths are parsible from the desktop */
75     LPWSTR sPathTarget;     /* complete path to target used for enumeration and ChangeNotify */
76
77     LPITEMIDLIST pidlRoot; /* absolute pidl */
78
79     UINT cfShellIDList;    /* clipboardformat for IDropTarget */
80     BOOL fAcceptFmt;       /* flag for pending Drop */
81 } IGenericSFImpl;
82
83 static const IUnknownVtbl unkvt;
84 static const IShellFolder2Vtbl sfvt;
85 static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3; /* IPersistFolder3 for a FS_Folder */
86 static const IDropTargetVtbl dtvt;
87 static const ISFHelperVtbl shvt;
88
89 static inline IGenericSFImpl *impl_from_IShellFolder2( IShellFolder2 *iface )
90 {
91     return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblShellFolder));
92 }
93
94 static inline IGenericSFImpl *impl_from_IPersistFolder3( IPersistFolder3 *iface )
95 {
96     return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblPersistFolder3));
97 }
98
99 static inline IGenericSFImpl *impl_from_IDropTarget( IDropTarget *iface )
100 {
101     return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblDropTarget));
102 }
103
104 static inline IGenericSFImpl *impl_from_ISFHelper( ISFHelper *iface )
105 {
106     return (IGenericSFImpl *)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpvtblSFHelper));
107 }
108
109
110 /*
111   converts This to an interface pointer
112 */
113 #define _IUnknown_(This)        ((IUnknown*)&(This)->lpVtbl)
114 #define _IShellFolder_(This)    ((IShellFolder*)&(This)->lpvtblShellFolder)
115 #define _IShellFolder2_(This)   ((IShellFolder2*)&(This)->lpvtblShellFolder)
116 #define _IPersist_(This)        (&(This)->lpvtblPersistFolder3)
117 #define _IPersistFolder_(This)  (&(This)->lpvtblPersistFolder3)
118 #define _IPersistFolder2_(This) (&(This)->lpvtblPersistFolder3)
119 #define _IPersistFolder3_(This) (&(This)->lpvtblPersistFolder3)
120 #define _IDropTarget_(This)     (&(This)->lpvtblDropTarget)
121 #define _ISFHelper_(This)       (&(This)->lpvtblSFHelper)
122
123 /**************************************************************************
124 * registers clipboardformat once
125 */
126 static void SF_RegisterClipFmt (IGenericSFImpl * This)
127 {
128     TRACE ("(%p)\n", This);
129
130     if (!This->cfShellIDList) {
131         This->cfShellIDList = RegisterClipboardFormatW (CFSTR_SHELLIDLISTW);
132     }
133 }
134
135 /**************************************************************************
136 * we need a separate IUnknown to handle aggregation
137 * (inner IUnknown)
138 */
139 static HRESULT WINAPI IUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppvObj)
140 {
141     IGenericSFImpl *This = (IGenericSFImpl *)iface;
142
143     TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
144
145     *ppvObj = NULL;
146
147     if (IsEqualIID (riid, &IID_IUnknown))
148         *ppvObj = _IUnknown_ (This);
149     else if (IsEqualIID (riid, &IID_IShellFolder))
150         *ppvObj = _IShellFolder_ (This);
151     else if (IsEqualIID (riid, &IID_IShellFolder2))
152         *ppvObj = _IShellFolder_ (This);
153     else if (IsEqualIID (riid, &IID_IPersist))
154         *ppvObj = _IPersist_ (This);
155     else if (IsEqualIID (riid, &IID_IPersistFolder))
156         *ppvObj = _IPersistFolder_ (This);
157     else if (IsEqualIID (riid, &IID_IPersistFolder2))
158         *ppvObj = _IPersistFolder2_ (This);
159     else if (IsEqualIID (riid, &IID_IPersistFolder3))
160         *ppvObj = _IPersistFolder3_ (This);
161     else if (IsEqualIID (riid, &IID_ISFHelper))
162         *ppvObj = _ISFHelper_ (This);
163     else if (IsEqualIID (riid, &IID_IDropTarget)) {
164         *ppvObj = _IDropTarget_ (This);
165         SF_RegisterClipFmt (This);
166     }
167
168     if (*ppvObj) {
169         IUnknown_AddRef ((IUnknown *) (*ppvObj));
170         TRACE ("-- Interface = %p\n", *ppvObj);
171         return S_OK;
172     }
173     TRACE ("-- Interface: E_NOINTERFACE\n");
174     return E_NOINTERFACE;
175 }
176
177 static ULONG WINAPI IUnknown_fnAddRef (IUnknown * iface)
178 {
179     IGenericSFImpl *This = (IGenericSFImpl *)iface;
180     ULONG refCount = InterlockedIncrement(&This->ref);
181
182     TRACE ("(%p)->(count=%u)\n", This, refCount - 1);
183
184     return refCount;
185 }
186
187 static ULONG WINAPI IUnknown_fnRelease (IUnknown * iface)
188 {
189     IGenericSFImpl *This = (IGenericSFImpl *)iface;
190     ULONG refCount = InterlockedDecrement(&This->ref);
191
192     TRACE ("(%p)->(count=%u)\n", This, refCount + 1);
193
194     if (!refCount) {
195         TRACE ("-- destroying IShellFolder(%p)\n", This);
196
197         SHFree (This->pidlRoot);
198         SHFree (This->sPathTarget);
199         LocalFree (This);
200     }
201     return refCount;
202 }
203
204 static const IUnknownVtbl unkvt =
205 {
206       IUnknown_fnQueryInterface,
207       IUnknown_fnAddRef,
208       IUnknown_fnRelease,
209 };
210
211 static const shvheader GenericSFHeader[] = {
212     {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
213     {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
214     {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
215     {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
216     {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
217 };
218
219 #define GENERICSHELLVIEWCOLUMNS 5
220
221 /**************************************************************************
222 * IFSFolder_Constructor
223 *
224 * NOTES
225 *  creating undocumented ShellFS_Folder as part of an aggregation
226 *  {F3364BA0-65B9-11CE-A9BA-00AA004AE837}
227 *
228 */
229 HRESULT WINAPI
230 IFSFolder_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
231 {
232     IGenericSFImpl *sf;
233
234     TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
235
236     if (pUnkOuter && !IsEqualIID (riid, &IID_IUnknown))
237         return CLASS_E_NOAGGREGATION;
238     sf = LocalAlloc (LMEM_ZEROINIT, sizeof (IGenericSFImpl));
239     if (!sf)
240         return E_OUTOFMEMORY;
241
242     sf->ref = 0;
243     sf->lpVtbl = &unkvt;
244     sf->lpvtblShellFolder = &sfvt;
245     sf->lpvtblPersistFolder3 = &vt_FSFldr_PersistFolder3;
246     sf->lpvtblDropTarget = &dtvt;
247     sf->lpvtblSFHelper = &shvt;
248     sf->pclsid = (CLSID *) & CLSID_ShellFSFolder;
249     sf->pUnkOuter = pUnkOuter ? pUnkOuter : _IUnknown_ (sf);
250
251     if (FAILED (IUnknown_QueryInterface (_IUnknown_ (sf), riid, ppv))) {
252         IUnknown_Release (_IUnknown_ (sf));
253         return E_NOINTERFACE;
254     }
255
256     TRACE ("--%p\n", *ppv);
257     return S_OK;
258 }
259
260 /**************************************************************************
261  *  IShellFolder_fnQueryInterface
262  *
263  * PARAMETERS
264  *  REFIID riid       [in ] Requested InterfaceID
265  *  LPVOID* ppvObject [out] Interface* to hold the result
266  */
267 static HRESULT WINAPI
268 IShellFolder_fnQueryInterface (IShellFolder2 * iface, REFIID riid,
269                                LPVOID * ppvObj)
270 {
271     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
272
273     TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
274
275     return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
276 }
277
278 /**************************************************************************
279 *  IShellFolder_AddRef
280 */
281
282 static ULONG WINAPI IShellFolder_fnAddRef (IShellFolder2 * iface)
283 {
284     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
285
286     TRACE ("(%p)->(count=%u)\n", This, This->ref);
287
288     return IUnknown_AddRef (This->pUnkOuter);
289 }
290
291 /**************************************************************************
292  *  IShellFolder_fnRelease
293  */
294 static ULONG WINAPI IShellFolder_fnRelease (IShellFolder2 * iface)
295 {
296     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
297
298     TRACE ("(%p)->(count=%u)\n", This, This->ref);
299
300     return IUnknown_Release (This->pUnkOuter);
301 }
302
303 /**************************************************************************
304  *  SHELL32_CreatePidlFromBindCtx  [internal]
305  *
306  *  If the caller bound File System Bind Data, assume it is the 
307  *   find data for the path.
308  *  This allows binding of paths that don't exist.
309  */
310 LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
311 {
312     static WCHAR szfsbc[] = {
313         'F','i','l','e',' ','S','y','s','t','e','m',' ',
314         'B','i','n','d',' ','D','a','t','a',0 };
315     IFileSystemBindData *fsbd = NULL;
316     LPITEMIDLIST pidl = NULL;
317     IUnknown *unk = NULL;
318     HRESULT r;
319
320     TRACE("%p %s\n", pbc, debugstr_w(path));
321
322     if (!pbc)
323         return NULL;
324
325     /* see if the caller bound File System Bind Data */
326     r = IBindCtx_GetObjectParam( pbc, szfsbc, &unk );
327     if (FAILED(r))
328         return NULL;
329
330     r = IUnknown_QueryInterface( unk, &IID_IFileSystemBindData, (void**)&fsbd );
331     if (SUCCEEDED(r))
332     {
333         WIN32_FIND_DATAW wfd;
334
335         r = IFileSystemBindData_GetFindData( fsbd, &wfd );
336         if (SUCCEEDED(r))
337         {
338             lstrcpynW( &wfd.cFileName[0], path, MAX_PATH );
339             pidl = _ILCreateFromFindDataW( &wfd );
340         }
341         IFileSystemBindData_Release( fsbd );
342     }
343     IUnknown_Release( unk );
344     
345     return pidl;
346 }
347
348 /**************************************************************************
349 * IShellFolder_ParseDisplayName {SHELL32}
350 *
351 * Parse a display name.
352 *
353 * PARAMS
354 *  hwndOwner       [in]  Parent window for any message's
355 *  pbc             [in]  optional FileSystemBindData context
356 *  lpszDisplayName [in]  Unicode displayname.
357 *  pchEaten        [out] (unicode) characters processed
358 *  ppidl           [out] complex pidl to item
359 *  pdwAttributes   [out] items attributes
360 *
361 * NOTES
362 *  Every folder tries to parse only its own (the leftmost) pidl and creates a
363 *  subfolder to evaluate the remaining parts.
364 *  Now we can parse into namespaces implemented by shell extensions
365 *
366 *  Behaviour on win98: lpszDisplayName=NULL -> crash
367 *                      lpszDisplayName="" -> returns mycoputer-pidl
368 *
369 * FIXME
370 *    pdwAttributes is not set
371 *    pchEaten is not set like in windows
372 */
373 static HRESULT WINAPI
374 IShellFolder_fnParseDisplayName (IShellFolder2 * iface,
375                                  HWND hwndOwner,
376                                  LPBC pbc,
377                                  LPOLESTR lpszDisplayName,
378                                  DWORD * pchEaten, LPITEMIDLIST * ppidl,
379                                  DWORD * pdwAttributes)
380 {
381     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
382
383     HRESULT hr = E_INVALIDARG;
384     LPCWSTR szNext = NULL;
385     WCHAR szElement[MAX_PATH];
386     WCHAR szPath[MAX_PATH];
387     LPITEMIDLIST pidlTemp = NULL;
388     DWORD len;
389
390     TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
391      This, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
392      pchEaten, ppidl, pdwAttributes);
393
394     if (!lpszDisplayName || !ppidl)
395         return E_INVALIDARG;
396
397     if (pchEaten)
398         *pchEaten = 0; /* strange but like the original */
399
400     pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName);
401     if (!pidlTemp && *lpszDisplayName)
402     {
403         /* get the next element */
404         szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
405
406         /* build the full pathname to the element */
407         lstrcpynW(szPath, This->sPathTarget, MAX_PATH - 1);
408         PathAddBackslashW(szPath);
409         len = lstrlenW(szPath);
410         lstrcpynW(szPath + len, szElement, MAX_PATH - len);
411
412         /* get the pidl */
413         hr = _ILCreateFromPathW(szPath, &pidlTemp);
414
415         if (SUCCEEDED(hr)) {
416             if (szNext && *szNext) {
417                 /* try to analyse the next element */
418                 hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc,
419                  &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
420             } else {
421                 /* it's the last element */
422                 if (pdwAttributes && *pdwAttributes) {
423                     hr = SHELL32_GetItemAttributes (_IShellFolder_ (This),
424                      pidlTemp, pdwAttributes);
425                 }
426             }
427         }
428     }
429
430     if (SUCCEEDED(hr))
431         *ppidl = pidlTemp;
432     else
433         *ppidl = NULL;
434
435     TRACE ("(%p)->(-- pidl=%p ret=0x%08x)\n", This, *ppidl, hr);
436
437     return hr;
438 }
439
440 /**************************************************************************
441 * IShellFolder_fnEnumObjects
442 * PARAMETERS
443 *  HWND          hwndOwner,    //[in ] Parent Window
444 *  DWORD         grfFlags,     //[in ] SHCONTF enumeration mask
445 *  LPENUMIDLIST* ppenumIDList  //[out] IEnumIDList interface
446 */
447 static HRESULT WINAPI
448 IShellFolder_fnEnumObjects (IShellFolder2 * iface, HWND hwndOwner,
449                             DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
450 {
451     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
452
453     TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This, hwndOwner,
454      dwFlags, ppEnumIDList);
455
456     *ppEnumIDList = IEnumIDList_Constructor();
457     if (*ppEnumIDList)
458         CreateFolderEnumList(*ppEnumIDList, This->sPathTarget, dwFlags);
459
460     TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
461
462     return *ppEnumIDList ? S_OK : E_OUTOFMEMORY;
463 }
464
465 /**************************************************************************
466 * IShellFolder_fnBindToObject
467 * PARAMETERS
468 *  LPCITEMIDLIST pidl,       //[in ] relative pidl to open
469 *  LPBC          pbc,        //[in ] optional FileSystemBindData context
470 *  REFIID        riid,       //[in ] Initial Interface
471 *  LPVOID*       ppvObject   //[out] Interface*
472 */
473 static HRESULT WINAPI
474 IShellFolder_fnBindToObject (IShellFolder2 * iface, LPCITEMIDLIST pidl,
475                              LPBC pbc, REFIID riid, LPVOID * ppvOut)
476 {
477     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
478
479     TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", This, pidl, pbc,
480      shdebugstr_guid (riid), ppvOut);
481
482     return SHELL32_BindToChild (This->pidlRoot, This->sPathTarget, pidl, riid,
483      ppvOut);
484 }
485
486 /**************************************************************************
487 *  IShellFolder_fnBindToStorage
488 * PARAMETERS
489 *  LPCITEMIDLIST pidl,       //[in ] complex pidl to store
490 *  LPBC          pbc,        //[in ] reserved
491 *  REFIID        riid,       //[in ] Initial storage interface
492 *  LPVOID*       ppvObject   //[out] Interface* returned
493 */
494 static HRESULT WINAPI
495 IShellFolder_fnBindToStorage (IShellFolder2 * iface, LPCITEMIDLIST pidl,
496                               LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
497 {
498     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
499
500     FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", This, pidl, pbcReserved,
501      shdebugstr_guid (riid), ppvOut);
502
503     *ppvOut = NULL;
504     return E_NOTIMPL;
505 }
506
507 /**************************************************************************
508 *  IShellFolder_fnCompareIDs
509 */
510
511 static HRESULT WINAPI
512 IShellFolder_fnCompareIDs (IShellFolder2 * iface, LPARAM lParam,
513                            LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
514 {
515     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
516
517     int nReturn;
518
519     TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
520     nReturn = SHELL32_CompareIDs (_IShellFolder_ (This), lParam, pidl1, pidl2);
521     TRACE ("-- %i\n", nReturn);
522     return nReturn;
523 }
524
525 /**************************************************************************
526 * IShellFolder_fnCreateViewObject
527 */
528 static HRESULT WINAPI
529 IShellFolder_fnCreateViewObject (IShellFolder2 * iface, HWND hwndOwner,
530                                  REFIID riid, LPVOID * ppvOut)
531 {
532     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
533
534     LPSHELLVIEW pShellView;
535     HRESULT hr = E_INVALIDARG;
536
537     TRACE ("(%p)->(hwnd=%p,%s,%p)\n", This, hwndOwner, shdebugstr_guid (riid),
538      ppvOut);
539
540     if (ppvOut) {
541         *ppvOut = NULL;
542
543         if (IsEqualIID (riid, &IID_IDropTarget)) {
544             hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, ppvOut);
545         } else if (IsEqualIID (riid, &IID_IContextMenu)) {
546             FIXME ("IContextMenu not implemented\n");
547             hr = E_NOTIMPL;
548         } else if (IsEqualIID (riid, &IID_IShellView)) {
549             pShellView = IShellView_Constructor ((IShellFolder *) iface);
550             if (pShellView) {
551                 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
552                 IShellView_Release (pShellView);
553             }
554         }
555     }
556     TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
557     return hr;
558 }
559
560 /**************************************************************************
561 *  IShellFolder_fnGetAttributesOf
562 *
563 * PARAMETERS
564 *  UINT            cidl,     //[in ] num elements in pidl array
565 *  LPCITEMIDLIST*  apidl,    //[in ] simple pidl array
566 *  ULONG*          rgfInOut) //[out] result array
567 *
568 */
569 static HRESULT WINAPI
570 IShellFolder_fnGetAttributesOf (IShellFolder2 * iface, UINT cidl,
571                                 LPCITEMIDLIST * apidl, DWORD * rgfInOut)
572 {
573     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
574
575     HRESULT hr = S_OK;
576
577     TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", This, cidl, apidl,
578      rgfInOut, rgfInOut ? *rgfInOut : 0);
579
580     if (!rgfInOut)
581         return E_INVALIDARG;
582     if (cidl && !apidl)
583         return E_INVALIDARG;
584
585     if (*rgfInOut == 0)
586         *rgfInOut = ~0;
587
588     if(cidl == 0){
589         IShellFolder *psfParent = NULL;
590         LPCITEMIDLIST rpidl = NULL;
591
592         hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder, (LPVOID*)&psfParent, &rpidl);
593         if(SUCCEEDED(hr)) {
594             SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
595             IShellFolder_Release(psfParent);
596         }
597     }
598     else {
599         while (cidl > 0 && *apidl) {
600             pdump (*apidl);
601             SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
602             apidl++;
603             cidl--;
604         }
605     }
606     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
607     *rgfInOut &= ~SFGAO_VALIDATE;
608
609     TRACE ("-- result=0x%08x\n", *rgfInOut);
610
611     return hr;
612 }
613
614 /**************************************************************************
615  * SHELL32_CreateExtensionUIObject (internal)
616  */
617 HRESULT SHELL32_CreateExtensionUIObject(IShellFolder2 *iface,
618         LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut)
619 {
620     static const WCHAR reg_blockedW[] = {'S','o','f','t','w','a','r','e','\\',
621         'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
622         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
623         'S','h','e','l','l',' ','E','x','t','e','n','s','i','o','n','s','\\',
624         'B','l','o','c','k','e','d',0};
625     static const WCHAR formatW[] = {'.','%','s','\\','S','h','e','l','l','E','x','\\',
626         '{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
627         '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x',
628         '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
629
630     IPersistFile *persist_file;
631     char extensionA[20];
632     WCHAR extensionW[20], buf[MAX_PATH];
633     DWORD size = MAX_PATH;
634     STRRET path;
635     WCHAR *file;
636     GUID guid;
637     HKEY key;
638     HRESULT hr;
639
640
641     if(!_ILGetExtension(pidl, extensionA, 20))
642         return S_FALSE;
643
644     MultiByteToWideChar(CP_ACP, 0, extensionA, -1, extensionW, 20);
645
646     sprintfW(buf, formatW, extensionW, riid->Data1, riid->Data2, riid->Data3,
647             riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
648             riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
649
650     if(RegGetValueW(HKEY_CLASSES_ROOT, buf, NULL, RRF_RT_REG_SZ,
651                 NULL, buf, &size) != ERROR_SUCCESS)
652         return S_FALSE;
653
654     if(RegCreateKeyExW(HKEY_LOCAL_MACHINE, reg_blockedW, 0, 0, 0,
655                 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
656         return E_FAIL;
657     if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
658             != ERROR_FILE_NOT_FOUND)
659         return E_ACCESSDENIED;
660     RegCloseKey(key);
661
662     if(RegCreateKeyExW(HKEY_CURRENT_USER, reg_blockedW, 0, 0, 0,
663                 KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS)
664         return E_FAIL;
665     if(RegQueryValueExW(key, buf, 0, NULL, NULL, NULL)
666             != ERROR_FILE_NOT_FOUND)
667         return E_ACCESSDENIED;
668     RegCloseKey(key);
669
670     if(!GUIDFromStringW(buf, &guid))
671         return E_FAIL;
672
673     hr = CoCreateInstance(&guid, NULL, CLSCTX_INPROC_SERVER,
674             &IID_IPersistFile, (void**)&persist_file);
675     if(FAILED(hr))
676         return hr;
677
678     hr = IShellFolder_GetDisplayNameOf(iface, pidl, SHGDN_FORPARSING, &path);
679     if(SUCCEEDED(hr))
680         hr = StrRetToStrW(&path, NULL, &file);
681     if(FAILED(hr)) {
682         IPersistFile_Release(persist_file);
683         return hr;
684     }
685
686     hr = IPersistFile_Load(persist_file, file, STGM_READ);
687     CoTaskMemFree(file);
688     if(FAILED(hr)) {
689         IPersistFile_Release(persist_file);
690         return hr;
691     }
692
693     hr = IPersistFile_QueryInterface(persist_file, riid, ppvOut);
694     IPersistFile_Release(persist_file);
695     return hr;
696 }
697
698 /**************************************************************************
699 *  IShellFolder_fnGetUIObjectOf
700 *
701 * PARAMETERS
702 *  HWND           hwndOwner, //[in ] Parent window for any output
703 *  UINT           cidl,      //[in ] array size
704 *  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
705 *  REFIID         riid,      //[in ] Requested Interface
706 *  UINT*          prgfInOut, //[   ] reserved
707 *  LPVOID*        ppvObject) //[out] Resulting Interface
708 *
709 * NOTES
710 *  This function gets asked to return "view objects" for one or more (multiple
711 *  select) items:
712 *  The viewobject typically is an COM object with one of the following
713 *  interfaces:
714 *  IExtractIcon,IDataObject,IContextMenu
715 *  In order to support icon positions in the default Listview your DataObject
716 *  must implement the SetData method (in addition to GetData :) - the shell
717 *  passes a barely documented "Icon positions" structure to SetData when the
718 *  drag starts, and GetData's it if the drop is in another explorer window that
719 *  needs the positions.
720 */
721 static HRESULT WINAPI
722 IShellFolder_fnGetUIObjectOf (IShellFolder2 * iface,
723                               HWND hwndOwner,
724                               UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
725                               UINT * prgfInOut, LPVOID * ppvOut)
726 {
727     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
728
729     LPITEMIDLIST pidl;
730     IUnknown *pObj = NULL;
731     HRESULT hr = E_INVALIDARG;
732
733     TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
734      This, hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
735
736     if (ppvOut) {
737         *ppvOut = NULL;
738
739         if(cidl == 1) {
740             hr = SHELL32_CreateExtensionUIObject(iface, *apidl, riid, ppvOut);
741             if(hr != S_FALSE)
742                 return hr;
743         }
744
745         if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1)) {
746             pObj = (LPUNKNOWN) ISvItemCm_Constructor ((IShellFolder *) iface,
747              This->pidlRoot, apidl, cidl);
748             hr = S_OK;
749         } else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1)) {
750             pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
751              This->pidlRoot, apidl, cidl);
752             hr = S_OK;
753         } else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1)) {
754             pidl = ILCombine (This->pidlRoot, apidl[0]);
755             pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
756             SHFree (pidl);
757             hr = S_OK;
758         } else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1)) {
759             pidl = ILCombine (This->pidlRoot, apidl[0]);
760             pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
761             SHFree (pidl);
762             hr = S_OK;
763         } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) {
764             hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget,
765              (LPVOID *) & pObj);
766         } else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
767          IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1)) {
768             pidl = ILCombine (This->pidlRoot, apidl[0]);
769             hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
770             SHFree (pidl);
771         } else {
772             hr = E_NOINTERFACE;
773         }
774
775         if (SUCCEEDED(hr) && !pObj)
776             hr = E_OUTOFMEMORY;
777
778         *ppvOut = pObj;
779     }
780     TRACE ("(%p)->hr=0x%08x\n", This, hr);
781     return hr;
782 }
783
784 static const WCHAR AdvancedW[] = { 'S','O','F','T','W','A','R','E',
785  '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
786  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
787  'o','r','e','r','\\','A','d','v','a','n','c','e','d',0 };
788 static const WCHAR HideFileExtW[] = { 'H','i','d','e','F','i','l','e','E','x',
789  't',0 };
790 static const WCHAR NeverShowExtW[] = { 'N','e','v','e','r','S','h','o','w','E',
791  'x','t',0 };
792
793 /******************************************************************************
794  * SHELL_FS_HideExtension [Internal]
795  *
796  * Query the registry if the filename extension of a given path should be 
797  * hidden.
798  *
799  * PARAMS
800  *  szPath [I] Relative or absolute path of a file
801  *  
802  * RETURNS
803  *  TRUE, if the filename's extension should be hidden
804  *  FALSE, otherwise.
805  */
806 BOOL SHELL_FS_HideExtension(LPCWSTR szPath)
807 {
808     HKEY hKey;
809     DWORD dwData;
810     DWORD dwDataSize = sizeof (DWORD);
811     BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
812     
813     if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
814         if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
815             doHide = dwData;
816         RegCloseKey (hKey);
817     }
818
819     if (!doHide) {
820         LPWSTR ext = PathFindExtensionW(szPath);
821
822         if (*ext != '\0') {
823             WCHAR classname[MAX_PATH];
824             LONG classlen = sizeof(classname);
825
826             if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
827                 if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
828                     if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
829                         doHide = TRUE;
830                     RegCloseKey(hKey);
831                 }
832         }
833     }
834     return doHide;
835 }
836     
837 void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
838 {
839     /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
840     if (!(dwFlags & SHGDN_FORPARSING) &&
841         ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
842         if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
843             PathRemoveExtensionW(szPath);
844     }
845 }
846
847 /**************************************************************************
848 *  IShellFolder_fnGetDisplayNameOf
849 *  Retrieves the display name for the specified file object or subfolder
850 *
851 * PARAMETERS
852 *  LPCITEMIDLIST pidl,    //[in ] complex pidl to item
853 *  DWORD         dwFlags, //[in ] SHGNO formatting flags
854 *  LPSTRRET      lpName)  //[out] Returned display name
855 *
856 * FIXME
857 *  if the name is in the pidl the ret value should be a STRRET_OFFSET
858 */
859
860 static HRESULT WINAPI
861 IShellFolder_fnGetDisplayNameOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
862                                  DWORD dwFlags, LPSTRRET strRet)
863 {
864     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
865     LPWSTR pszPath;
866
867     HRESULT hr = S_OK;
868     int len = 0;
869
870     TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
871     pdump (pidl);
872
873     if (!pidl || !strRet)
874         return E_INVALIDARG;
875
876     pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
877     if (!pszPath)
878         return E_OUTOFMEMORY;
879
880     if (_ILIsDesktop(pidl)) { /* empty pidl */
881         if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
882             (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER)) 
883         {
884             if (This->sPathTarget)
885                 lstrcpynW(pszPath, This->sPathTarget, MAX_PATH);
886         } else {
887             /* pidl has to contain exactly one non null SHITEMID */
888             hr = E_INVALIDARG;
889         }
890     } else if (_ILIsPidlSimple(pidl)) {
891         if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
892             (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && 
893             This->sPathTarget) 
894         {
895             lstrcpynW(pszPath, This->sPathTarget, MAX_PATH);
896             PathAddBackslashW(pszPath);
897             len = lstrlenW(pszPath);
898         }
899         _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
900         if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
901     } else {
902         hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH);
903     }
904
905     if (SUCCEEDED(hr)) {
906         /* Win9x always returns ANSI strings, NT always returns Unicode strings */
907         if (GetVersion() & 0x80000000) {
908             strRet->uType = STRRET_CSTR;
909             if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
910                  NULL, NULL))
911                 strRet->u.cStr[0] = '\0';
912             CoTaskMemFree(pszPath);
913         } else {
914             strRet->uType = STRRET_WSTR;
915             strRet->u.pOleStr = pszPath;
916         }
917     } else
918         CoTaskMemFree(pszPath);
919
920     TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr));
921     return hr;
922 }
923
924 /**************************************************************************
925 *  IShellFolder_fnSetNameOf
926 *  Changes the name of a file object or subfolder, possibly changing its item
927 *  identifier in the process.
928 *
929 * PARAMETERS
930 *  HWND          hwndOwner,  //[in ] Owner window for output
931 *  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
932 *  LPCOLESTR     lpszName,   //[in ] the items new display name
933 *  DWORD         dwFlags,    //[in ] SHGNO formatting flags
934 *  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
935 */
936 static HRESULT WINAPI IShellFolder_fnSetNameOf (IShellFolder2 * iface,
937                                                 HWND hwndOwner,
938                                                 LPCITEMIDLIST pidl,
939                                                 LPCOLESTR lpName,
940                                                 DWORD dwFlags,
941                                                 LPITEMIDLIST * pPidlOut)
942 {
943     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
944     WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
945     LPWSTR ptr;
946     BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
947
948     TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This, hwndOwner, pidl,
949      debugstr_w (lpName), dwFlags, pPidlOut);
950
951     /* build source path */
952     lstrcpynW(szSrc, This->sPathTarget, MAX_PATH);
953     ptr = PathAddBackslashW (szSrc);
954     if (ptr)
955         _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
956
957     /* build destination path */
958     if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
959         lstrcpynW(szDest, This->sPathTarget, MAX_PATH);
960         ptr = PathAddBackslashW (szDest);
961         if (ptr)
962             lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
963     } else
964         lstrcpynW(szDest, lpName, MAX_PATH);
965
966     if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
967         WCHAR *ext = PathFindExtensionW(szSrc);
968         if(*ext != '\0') {
969             INT len = strlenW(szDest);
970             lstrcpynW(szDest + len, ext, MAX_PATH - len);
971         }
972     }
973     
974     TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
975
976     if (MoveFileW (szSrc, szDest)) {
977         HRESULT hr = S_OK;
978
979         if (pPidlOut)
980             hr = _ILCreateFromPathW(szDest, pPidlOut);
981
982         SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
983          SHCNF_PATHW, szSrc, szDest);
984
985         return hr;
986     }
987
988     return E_FAIL;
989 }
990
991 static HRESULT WINAPI IShellFolder_fnGetDefaultSearchGUID (IShellFolder2 *iface,
992                                                            GUID * pguid)
993 {
994     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
995     FIXME ("(%p)\n", This);
996     return E_NOTIMPL;
997 }
998 static HRESULT WINAPI IShellFolder_fnEnumSearches (IShellFolder2 * iface,
999                                                    IEnumExtraSearch ** ppenum)
1000 {
1001     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1002     FIXME ("(%p)\n", This);
1003     return E_NOTIMPL;
1004 }
1005
1006 static HRESULT WINAPI
1007 IShellFolder_fnGetDefaultColumn (IShellFolder2 * iface, DWORD dwRes,
1008                                  ULONG * pSort, ULONG * pDisplay)
1009 {
1010     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1011
1012     TRACE ("(%p)\n", This);
1013
1014     if (pSort)
1015         *pSort = 0;
1016     if (pDisplay)
1017         *pDisplay = 0;
1018
1019     return S_OK;
1020 }
1021
1022 static HRESULT WINAPI
1023 IShellFolder_fnGetDefaultColumnState (IShellFolder2 * iface, UINT iColumn,
1024                                       DWORD * pcsFlags)
1025 {
1026     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1027
1028     TRACE ("(%p)\n", This);
1029
1030     if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
1031         return E_INVALIDARG;
1032
1033     *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
1034
1035     return S_OK;
1036 }
1037
1038 static HRESULT WINAPI
1039 IShellFolder_fnGetDetailsEx (IShellFolder2 * iface, LPCITEMIDLIST pidl,
1040                              const SHCOLUMNID * pscid, VARIANT * pv)
1041 {
1042     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1043     FIXME ("(%p)\n", This);
1044
1045     return E_NOTIMPL;
1046 }
1047
1048 static HRESULT WINAPI
1049 IShellFolder_fnGetDetailsOf (IShellFolder2 * iface, LPCITEMIDLIST pidl,
1050                              UINT iColumn, SHELLDETAILS * psd)
1051 {
1052     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1053     HRESULT hr = E_FAIL;
1054
1055     TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
1056
1057     if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
1058         return E_INVALIDARG;
1059
1060     if (!pidl) {
1061         /* the header titles */
1062         psd->fmt = GenericSFHeader[iColumn].fmt;
1063         psd->cxChar = GenericSFHeader[iColumn].cxChar;
1064         psd->str.uType = STRRET_CSTR;
1065         LoadStringA (shell32_hInstance, GenericSFHeader[iColumn].colnameid,
1066          psd->str.u.cStr, MAX_PATH);
1067         return S_OK;
1068     } else {
1069         hr = S_OK;
1070         psd->str.uType = STRRET_CSTR;
1071         /* the data from the pidl */
1072         switch (iColumn) {
1073         case 0:                /* name */
1074             hr = IShellFolder_GetDisplayNameOf (iface, pidl,
1075              SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
1076             break;
1077         case 1:                /* size */
1078             _ILGetFileSize (pidl, psd->str.u.cStr, MAX_PATH);
1079             break;
1080         case 2:                /* type */
1081             _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
1082             break;
1083         case 3:                /* date */
1084             _ILGetFileDate (pidl, psd->str.u.cStr, MAX_PATH);
1085             break;
1086         case 4:                /* attributes */
1087             _ILGetFileAttributes (pidl, psd->str.u.cStr, MAX_PATH);
1088             break;
1089         }
1090     }
1091
1092     return hr;
1093 }
1094
1095 static HRESULT WINAPI
1096 IShellFolder_fnMapColumnToSCID (IShellFolder2 * iface, UINT column,
1097                                 SHCOLUMNID * pscid)
1098 {
1099     IGenericSFImpl *This = impl_from_IShellFolder2(iface);
1100     FIXME ("(%p)\n", This);
1101     return E_NOTIMPL;
1102 }
1103
1104 static const IShellFolder2Vtbl sfvt =
1105 {
1106     IShellFolder_fnQueryInterface,
1107     IShellFolder_fnAddRef,
1108     IShellFolder_fnRelease,
1109     IShellFolder_fnParseDisplayName,
1110     IShellFolder_fnEnumObjects,
1111     IShellFolder_fnBindToObject,
1112     IShellFolder_fnBindToStorage,
1113     IShellFolder_fnCompareIDs,
1114     IShellFolder_fnCreateViewObject,
1115     IShellFolder_fnGetAttributesOf,
1116     IShellFolder_fnGetUIObjectOf,
1117     IShellFolder_fnGetDisplayNameOf,
1118     IShellFolder_fnSetNameOf,
1119     /* ShellFolder2 */
1120     IShellFolder_fnGetDefaultSearchGUID,
1121     IShellFolder_fnEnumSearches,
1122     IShellFolder_fnGetDefaultColumn,
1123     IShellFolder_fnGetDefaultColumnState,
1124     IShellFolder_fnGetDetailsEx,
1125     IShellFolder_fnGetDetailsOf,
1126     IShellFolder_fnMapColumnToSCID
1127 };
1128
1129 /****************************************************************************
1130  * ISFHelper for IShellFolder implementation
1131  */
1132
1133 static HRESULT WINAPI
1134 ISFHelper_fnQueryInterface (ISFHelper * iface, REFIID riid, LPVOID * ppvObj)
1135 {
1136     IGenericSFImpl *This = impl_from_ISFHelper(iface);
1137
1138     TRACE ("(%p)->(count=%u)\n", This, This->ref);
1139
1140     return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
1141 }
1142
1143 static ULONG WINAPI ISFHelper_fnAddRef (ISFHelper * iface)
1144 {
1145     IGenericSFImpl *This = impl_from_ISFHelper(iface);
1146
1147     TRACE ("(%p)->(count=%u)\n", This, This->ref);
1148
1149     return IUnknown_AddRef (This->pUnkOuter);
1150 }
1151
1152 static ULONG WINAPI ISFHelper_fnRelease (ISFHelper * iface)
1153 {
1154     IGenericSFImpl *This = impl_from_ISFHelper(iface);
1155
1156     TRACE ("(%p)\n", This);
1157
1158     return IUnknown_Release (This->pUnkOuter);
1159 }
1160
1161 /****************************************************************************
1162  * ISFHelper_fnGetUniqueName
1163  *
1164  * creates a unique folder name
1165  */
1166
1167 static HRESULT WINAPI
1168 ISFHelper_fnGetUniqueName (ISFHelper * iface, LPWSTR pwszName, UINT uLen)
1169 {
1170     IGenericSFImpl *This = impl_from_ISFHelper(iface);
1171     IEnumIDList *penum;
1172     HRESULT hr;
1173     WCHAR wszText[MAX_PATH];
1174     WCHAR wszNewFolder[25];
1175     const WCHAR wszFormat[] = {'%','s',' ','%','d',0 };
1176
1177     TRACE ("(%p)(%p %u)\n", This, pwszName, uLen);
1178
1179     LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder,  sizeof(wszNewFolder)/sizeof(WCHAR));
1180     if (uLen < sizeof(wszNewFolder)/sizeof(WCHAR) + 3)
1181         return E_POINTER;
1182
1183     lstrcpynW (pwszName, wszNewFolder, uLen);
1184
1185     hr = IShellFolder_fnEnumObjects (_IShellFolder2_ (This), 0,
1186      SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
1187     if (penum) {
1188         LPITEMIDLIST pidl;
1189         DWORD dwFetched;
1190         int i = 1;
1191
1192 next:
1193         IEnumIDList_Reset (penum);
1194         while (S_OK == IEnumIDList_Next (penum, 1, &pidl, &dwFetched) &&
1195          dwFetched) {
1196             _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
1197             if (0 == lstrcmpiW (wszText, pwszName)) {
1198                 snprintfW (pwszName, uLen, wszFormat, wszNewFolder, i++);
1199                 if (i > 99) {
1200                     hr = E_FAIL;
1201                     break;
1202                 }
1203                 goto next;
1204             }
1205         }
1206
1207         IEnumIDList_Release (penum);
1208     }
1209     return hr;
1210 }
1211
1212 /****************************************************************************
1213  * ISFHelper_fnAddFolder
1214  *
1215  * adds a new folder.
1216  */
1217
1218 static HRESULT WINAPI
1219 ISFHelper_fnAddFolder (ISFHelper * iface, HWND hwnd, LPCWSTR pwszName,
1220                        LPITEMIDLIST * ppidlOut)
1221 {
1222     IGenericSFImpl *This = impl_from_ISFHelper(iface);
1223     WCHAR wszNewDir[MAX_PATH];
1224     DWORD bRes;
1225     HRESULT hres = E_FAIL;
1226
1227     TRACE ("(%p)(%s %p)\n", This, debugstr_w(pwszName), ppidlOut);
1228
1229     wszNewDir[0] = 0;
1230     if (This->sPathTarget)
1231         lstrcpynW(wszNewDir, This->sPathTarget, MAX_PATH);
1232     PathAppendW(wszNewDir, pwszName);
1233
1234     bRes = CreateDirectoryW (wszNewDir, NULL);
1235     if (bRes) {
1236         LPITEMIDLIST relPidl;
1237
1238         lstrcpyW(wszNewDir, pwszName);
1239
1240         hres = IShellFolder_ParseDisplayName((IShellFolder*)&This->lpvtblShellFolder,
1241                 hwnd, NULL, wszNewDir, NULL, &relPidl, NULL);
1242
1243         if (SUCCEEDED(hres)) {
1244             LPITEMIDLIST fullPidl;
1245
1246             fullPidl = ILCombine(This->pidlRoot, relPidl);
1247
1248             if (fullPidl) {
1249                 SHChangeNotify(SHCNE_MKDIR, SHCNF_IDLIST, fullPidl, NULL);
1250                 ILFree(fullPidl);
1251
1252                 if (ppidlOut)
1253                     *ppidlOut = relPidl;
1254                 else
1255                     ILFree(relPidl);
1256             } else {
1257                 WARN("failed to combine %s into a full PIDL\n", wine_dbgstr_w(pwszName));
1258                 ILFree(relPidl);
1259             }
1260
1261         } else
1262             WARN("failed to parse %s into a PIDL\n", wine_dbgstr_w(pwszName));
1263
1264     } else {
1265         WCHAR wszText[128 + MAX_PATH];
1266         WCHAR wszTempText[128];
1267         WCHAR wszCaption[256];
1268
1269         /* Cannot Create folder because of permissions */
1270         LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
1271          sizeof (wszTempText)/sizeof (wszTempText[0]));
1272         LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
1273          sizeof (wszCaption)/sizeof (wszCaption[0]));
1274         sprintfW (wszText, wszTempText, wszNewDir);
1275         MessageBoxW (hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
1276     }
1277
1278     return hres;
1279 }
1280
1281 /****************************************************************************
1282  * build_paths_list
1283  *
1284  * Builds a list of paths like the one used in SHFileOperation from a table of
1285  * PIDLs relative to the given base folder
1286  */
1287 static WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, const LPCITEMIDLIST *pidls)
1288 {
1289     WCHAR *wszPathsList;
1290     WCHAR *wszListPos;
1291     int iPathLen;
1292     int i;
1293     
1294     iPathLen = lstrlenW(wszBasePath);
1295     wszPathsList = HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR)*cidl+1);
1296     wszListPos = wszPathsList;
1297     
1298     for (i = 0; i < cidl; i++) {
1299         if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i]))
1300             continue;
1301
1302         lstrcpynW(wszListPos, wszBasePath, MAX_PATH);
1303         /* FIXME: abort if path too long */
1304         _ILSimpleGetTextW(pidls[i], wszListPos+iPathLen, MAX_PATH-iPathLen);
1305         wszListPos += lstrlenW(wszListPos)+1;
1306     }
1307     *wszListPos=0;
1308     return wszPathsList;
1309 }
1310
1311 /****************************************************************************
1312  * ISFHelper_fnDeleteItems
1313  *
1314  * deletes items in folder
1315  */
1316 static HRESULT WINAPI
1317 ISFHelper_fnDeleteItems (ISFHelper * iface, UINT cidl, LPCITEMIDLIST * apidl)
1318 {
1319     IGenericSFImpl *This = impl_from_ISFHelper(iface);
1320     UINT i;
1321     SHFILEOPSTRUCTW op;
1322     WCHAR wszPath[MAX_PATH];
1323     WCHAR *wszPathsList;
1324     HRESULT ret;
1325     WCHAR *wszCurrentPath;
1326
1327     TRACE ("(%p)(%u %p)\n", This, cidl, apidl);
1328     if (cidl==0) return S_OK;
1329
1330     if (This->sPathTarget)
1331         lstrcpynW(wszPath, This->sPathTarget, MAX_PATH);
1332     else
1333         wszPath[0] = '\0';
1334     PathAddBackslashW(wszPath);
1335     wszPathsList = build_paths_list(wszPath, cidl, apidl);
1336
1337     ZeroMemory(&op, sizeof(op));
1338     op.hwnd = GetActiveWindow();
1339     op.wFunc = FO_DELETE;
1340     op.pFrom = wszPathsList;
1341     op.fFlags = FOF_ALLOWUNDO;
1342     if (SHFileOperationW(&op))
1343     {
1344         WARN("SHFileOperation failed\n");
1345         ret = E_FAIL;
1346     }
1347     else
1348         ret = S_OK;
1349
1350     /* we currently need to manually send the notifies */
1351     wszCurrentPath = wszPathsList;
1352     for (i = 0; i < cidl; i++)
1353     {
1354         LONG wEventId;
1355
1356         if (_ILIsFolder(apidl[i]))
1357             wEventId = SHCNE_RMDIR;
1358         else if (_ILIsValue(apidl[i]))
1359             wEventId = SHCNE_DELETE;
1360         else
1361             continue;
1362
1363         /* check if file exists */
1364         if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
1365         {
1366             LPITEMIDLIST pidl = ILCombine(This->pidlRoot, apidl[i]);
1367             SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
1368             SHFree(pidl);
1369         }
1370
1371         wszCurrentPath += lstrlenW(wszCurrentPath)+1;
1372     }
1373     HeapFree(GetProcessHeap(), 0, wszPathsList);
1374     return ret;
1375 }
1376
1377 /****************************************************************************
1378  * ISFHelper_fnCopyItems
1379  *
1380  * copies items to this folder
1381  */
1382 static HRESULT WINAPI
1383 ISFHelper_fnCopyItems (ISFHelper * iface, IShellFolder * pSFFrom, UINT cidl,
1384                        LPCITEMIDLIST * apidl)
1385 {
1386     UINT i;
1387     IPersistFolder2 *ppf2 = NULL;
1388     char szSrcPath[MAX_PATH],
1389       szDstPath[MAX_PATH];
1390
1391     IGenericSFImpl *This = impl_from_ISFHelper(iface);
1392
1393     TRACE ("(%p)->(%p,%u,%p)\n", This, pSFFrom, cidl, apidl);
1394
1395     IShellFolder_QueryInterface (pSFFrom, &IID_IPersistFolder2,
1396      (LPVOID *) & ppf2);
1397     if (ppf2) {
1398         LPITEMIDLIST pidl;
1399
1400         if (SUCCEEDED (IPersistFolder2_GetCurFolder (ppf2, &pidl))) {
1401             for (i = 0; i < cidl; i++) {
1402                 SHGetPathFromIDListA (pidl, szSrcPath);
1403                 PathAddBackslashA (szSrcPath);
1404                 _ILSimpleGetText (apidl[i], szSrcPath + strlen (szSrcPath),
1405                  MAX_PATH);
1406
1407                 if (!WideCharToMultiByte(CP_ACP, 0, This->sPathTarget, -1, szDstPath, MAX_PATH, NULL, NULL))
1408                     szDstPath[0] = '\0';
1409                 PathAddBackslashA (szDstPath);
1410                 _ILSimpleGetText (apidl[i], szDstPath + strlen (szDstPath),
1411                  MAX_PATH);
1412                 MESSAGE ("would copy %s to %s\n", szSrcPath, szDstPath);
1413             }
1414             SHFree (pidl);
1415         }
1416         IPersistFolder2_Release (ppf2);
1417     }
1418     return S_OK;
1419 }
1420
1421 static const ISFHelperVtbl shvt =
1422 {
1423     ISFHelper_fnQueryInterface,
1424     ISFHelper_fnAddRef,
1425     ISFHelper_fnRelease,
1426     ISFHelper_fnGetUniqueName,
1427     ISFHelper_fnAddFolder,
1428     ISFHelper_fnDeleteItems,
1429     ISFHelper_fnCopyItems
1430 };
1431
1432 /************************************************************************
1433  * IFSFldr_PersistFolder3_QueryInterface
1434  *
1435  */
1436 static HRESULT WINAPI
1437 IFSFldr_PersistFolder3_QueryInterface (IPersistFolder3 * iface, REFIID iid,
1438                                        LPVOID * ppvObj)
1439 {
1440     IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1441
1442     TRACE ("(%p)\n", This);
1443
1444     return IUnknown_QueryInterface (This->pUnkOuter, iid, ppvObj);
1445 }
1446
1447 /************************************************************************
1448  * IFSFldr_PersistFolder3_AddRef
1449  *
1450  */
1451 static ULONG WINAPI
1452 IFSFldr_PersistFolder3_AddRef (IPersistFolder3 * iface)
1453 {
1454     IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1455
1456     TRACE ("(%p)->(count=%u)\n", This, This->ref);
1457
1458     return IUnknown_AddRef (This->pUnkOuter);
1459 }
1460
1461 /************************************************************************
1462  * IFSFldr_PersistFolder3_Release
1463  *
1464  */
1465 static ULONG WINAPI
1466 IFSFldr_PersistFolder3_Release (IPersistFolder3 * iface)
1467 {
1468     IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1469
1470     TRACE ("(%p)->(count=%u)\n", This, This->ref);
1471
1472     return IUnknown_Release (This->pUnkOuter);
1473 }
1474
1475 /************************************************************************
1476  * IFSFldr_PersistFolder3_GetClassID
1477  */
1478 static HRESULT WINAPI
1479 IFSFldr_PersistFolder3_GetClassID (IPersistFolder3 * iface, CLSID * lpClassId)
1480 {
1481     IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1482
1483     TRACE ("(%p)\n", This);
1484
1485     if (!lpClassId)
1486         return E_POINTER;
1487     *lpClassId = *This->pclsid;
1488
1489     return S_OK;
1490 }
1491
1492 /************************************************************************
1493  * IFSFldr_PersistFolder3_Initialize
1494  *
1495  * NOTES
1496  *  sPathTarget is not set. Don't know how to handle in a non rooted environment.
1497  */
1498 static HRESULT WINAPI
1499 IFSFldr_PersistFolder3_Initialize (IPersistFolder3 * iface, LPCITEMIDLIST pidl)
1500 {
1501     WCHAR wszTemp[MAX_PATH];
1502
1503     IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1504
1505     TRACE ("(%p)->(%p)\n", This, pidl);
1506
1507     SHFree (This->pidlRoot);     /* free the old pidl */
1508     This->pidlRoot = ILClone (pidl); /* set my pidl */
1509
1510     SHFree (This->sPathTarget);
1511     This->sPathTarget = NULL;
1512
1513     /* set my path */
1514     if (SHGetPathFromIDListW (pidl, wszTemp)) {
1515         int len = strlenW(wszTemp);
1516         This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1517         if (!This->sPathTarget)
1518             return E_OUTOFMEMORY;
1519         memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1520     }
1521
1522     TRACE ("--(%p)->(%s)\n", This, debugstr_w(This->sPathTarget));
1523     return S_OK;
1524 }
1525
1526 /**************************************************************************
1527  * IFSFldr_PersistFolder3_GetCurFolder
1528  */
1529 static HRESULT WINAPI
1530 IFSFldr_PersistFolder3_fnGetCurFolder (IPersistFolder3 * iface,
1531                                        LPITEMIDLIST * pidl)
1532 {
1533     IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1534
1535     TRACE ("(%p)->(%p)\n", This, pidl);
1536
1537     if (!pidl) return E_POINTER;
1538     *pidl = ILClone (This->pidlRoot);
1539     return S_OK;
1540 }
1541
1542 /**************************************************************************
1543  * IFSFldr_PersistFolder3_InitializeEx
1544  *
1545  * FIXME: error handling
1546  */
1547 static HRESULT WINAPI
1548 IFSFldr_PersistFolder3_InitializeEx (IPersistFolder3 * iface,
1549                                      IBindCtx * pbc, LPCITEMIDLIST pidlRoot,
1550                                      const PERSIST_FOLDER_TARGET_INFO * ppfti)
1551 {
1552     WCHAR wszTemp[MAX_PATH];
1553
1554     IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1555
1556     TRACE ("(%p)->(%p,%p,%p)\n", This, pbc, pidlRoot, ppfti);
1557     if (ppfti)
1558         TRACE ("--%p %s %s 0x%08x 0x%08x\n",
1559          ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
1560          debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
1561          ppfti->csidl);
1562
1563     pdump (pidlRoot);
1564     if (ppfti && ppfti->pidlTargetFolder)
1565         pdump (ppfti->pidlTargetFolder);
1566
1567     if (This->pidlRoot)
1568         __SHFreeAndNil (&This->pidlRoot);    /* free the old */
1569     if (This->sPathTarget)
1570         __SHFreeAndNil (&This->sPathTarget);
1571
1572     /*
1573      * Root path and pidl
1574      */
1575     This->pidlRoot = ILClone (pidlRoot);
1576
1577     /*
1578      *  the target folder is specified in csidl OR pidlTargetFolder OR
1579      *  szTargetParsingName
1580      */
1581     if (ppfti) {
1582         if (ppfti->csidl != -1) {
1583             if (SHGetSpecialFolderPathW (0, wszTemp, ppfti->csidl,
1584              ppfti->csidl & CSIDL_FLAG_CREATE)) {
1585                 int len = strlenW(wszTemp);
1586                 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1587                 if (!This->sPathTarget)
1588                     return E_OUTOFMEMORY;
1589                 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1590             }
1591         } else if (ppfti->szTargetParsingName[0]) {
1592             int len = strlenW(ppfti->szTargetParsingName);
1593             This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1594             if (!This->sPathTarget)
1595                 return E_OUTOFMEMORY;
1596             memcpy(This->sPathTarget, ppfti->szTargetParsingName,
1597                    (len + 1) * sizeof(WCHAR));
1598         } else if (ppfti->pidlTargetFolder) {
1599             if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) {
1600                 int len = strlenW(wszTemp);
1601                 This->sPathTarget = SHAlloc((len + 1) * sizeof(WCHAR));
1602                 if (!This->sPathTarget)
1603                     return E_OUTOFMEMORY;
1604                 memcpy(This->sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
1605             }
1606         }
1607     }
1608
1609     TRACE ("--(%p)->(target=%s)\n", This, debugstr_w(This->sPathTarget));
1610     pdump (This->pidlRoot);
1611     return (This->sPathTarget) ? S_OK : E_FAIL;
1612 }
1613
1614 static HRESULT WINAPI
1615 IFSFldr_PersistFolder3_GetFolderTargetInfo (IPersistFolder3 * iface,
1616                                             PERSIST_FOLDER_TARGET_INFO * ppfti)
1617 {
1618     IGenericSFImpl *This = impl_from_IPersistFolder3(iface);
1619     FIXME ("(%p)->(%p)\n", This, ppfti);
1620     ZeroMemory (ppfti, sizeof (*ppfti));
1621     return E_NOTIMPL;
1622 }
1623
1624 static const IPersistFolder3Vtbl vt_FSFldr_PersistFolder3 =
1625 {
1626     IFSFldr_PersistFolder3_QueryInterface,
1627     IFSFldr_PersistFolder3_AddRef,
1628     IFSFldr_PersistFolder3_Release,
1629     IFSFldr_PersistFolder3_GetClassID,
1630     IFSFldr_PersistFolder3_Initialize,
1631     IFSFldr_PersistFolder3_fnGetCurFolder,
1632     IFSFldr_PersistFolder3_InitializeEx,
1633     IFSFldr_PersistFolder3_GetFolderTargetInfo
1634 };
1635
1636 /****************************************************************************
1637  * ISFDropTarget implementation
1638  */
1639 static BOOL
1640 ISFDropTarget_QueryDrop (IDropTarget * iface, DWORD dwKeyState,
1641                          LPDWORD pdwEffect)
1642 {
1643     DWORD dwEffect = *pdwEffect;
1644
1645     IGenericSFImpl *This = impl_from_IDropTarget(iface);
1646
1647     *pdwEffect = DROPEFFECT_NONE;
1648
1649     if (This->fAcceptFmt) { /* Does our interpretation of the keystate ... */
1650         *pdwEffect = KeyStateToDropEffect (dwKeyState);
1651
1652         /* ... matches the desired effect ? */
1653         if (dwEffect & *pdwEffect) {
1654             return TRUE;
1655         }
1656     }
1657     return FALSE;
1658 }
1659
1660 static HRESULT WINAPI
1661 ISFDropTarget_QueryInterface (IDropTarget * iface, REFIID riid, LPVOID * ppvObj)
1662 {
1663     IGenericSFImpl *This = impl_from_IDropTarget(iface);
1664
1665     TRACE ("(%p)\n", This);
1666
1667     return IUnknown_QueryInterface (This->pUnkOuter, riid, ppvObj);
1668 }
1669
1670 static ULONG WINAPI ISFDropTarget_AddRef (IDropTarget * iface)
1671 {
1672     IGenericSFImpl *This = impl_from_IDropTarget(iface);
1673
1674     TRACE ("(%p)\n", This);
1675
1676     return IUnknown_AddRef (This->pUnkOuter);
1677 }
1678
1679 static ULONG WINAPI ISFDropTarget_Release (IDropTarget * iface)
1680 {
1681     IGenericSFImpl *This = impl_from_IDropTarget(iface);
1682
1683     TRACE ("(%p)\n", This);
1684
1685     return IUnknown_Release (This->pUnkOuter);
1686 }
1687
1688 static HRESULT WINAPI
1689 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
1690                          DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1691 {
1692     FORMATETC fmt;
1693
1694     IGenericSFImpl *This = impl_from_IDropTarget(iface);
1695
1696     TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject);
1697
1698     InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL);
1699
1700     This->fAcceptFmt = (S_OK == IDataObject_QueryGetData (pDataObject, &fmt)) ?
1701      TRUE : FALSE;
1702
1703     ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1704
1705     return S_OK;
1706 }
1707
1708 static HRESULT WINAPI
1709 ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
1710                         DWORD * pdwEffect)
1711 {
1712     IGenericSFImpl *This = impl_from_IDropTarget(iface);
1713
1714     TRACE ("(%p)\n", This);
1715
1716     if (!pdwEffect)
1717         return E_INVALIDARG;
1718
1719     ISFDropTarget_QueryDrop (iface, dwKeyState, pdwEffect);
1720
1721     return S_OK;
1722 }
1723
1724 static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
1725 {
1726     IGenericSFImpl *This = impl_from_IDropTarget(iface);
1727
1728     TRACE ("(%p)\n", This);
1729
1730     This->fAcceptFmt = FALSE;
1731
1732     return S_OK;
1733 }
1734
1735 static HRESULT WINAPI
1736 ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
1737                     DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
1738 {
1739     IGenericSFImpl *This = impl_from_IDropTarget(iface);
1740
1741     FIXME ("(%p) object dropped\n", This);
1742
1743     return E_NOTIMPL;
1744 }
1745
1746 static const IDropTargetVtbl dtvt = {
1747     ISFDropTarget_QueryInterface,
1748     ISFDropTarget_AddRef,
1749     ISFDropTarget_Release,
1750     ISFDropTarget_DragEnter,
1751     ISFDropTarget_DragOver,
1752     ISFDropTarget_DragLeave,
1753     ISFDropTarget_Drop
1754 };