Moved various DLLs to dlls/
[wine] / dlls / shell32 / shlfolder.c
1 /*
2  *      Shell Folder stuff
3  *
4  *      Copyright 1997  Marcus Meissner
5  *      Copyright 1998  Juergen Schmied
6  *      
7  *      IShellFolder with IDropTarget, IPersistFolder
8  *
9  */
10
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "debugtools.h"
15 #include "winerror.h"
16
17 #include "oleidl.h"
18 #include "shlguid.h"
19
20 #include "pidl.h"
21 #include "wine/obj_base.h"
22 #include "wine/obj_dragdrop.h"
23 #include "wine/obj_shellfolder.h"
24 #include "wine/undocshell.h"
25 #include "shell32_main.h"
26
27 DEFAULT_DEBUG_CHANNEL(shell)
28
29 /***************************************************************************
30  * IDropTarget interface definition for the ShellFolder
31  */
32
33 typedef struct
34 {       ICOM_VTABLE(IDropTarget)* lpvtbl;
35         ULONG ref;
36 } ISFDropTarget;
37
38 static struct ICOM_VTABLE(IDropTarget) dtvt;
39
40
41 /****************************************************************************
42  * ISFDropTarget implementation
43  */
44
45 static IDropTarget * WINAPI ISFDropTarget_Constructor(void)
46 {
47         ISFDropTarget* sf;
48
49         sf = HeapAlloc(GetProcessHeap(), 0, sizeof(ISFDropTarget));
50
51         if (sf)
52         { sf->lpvtbl = &dtvt;
53           sf->ref    = 1;
54         }
55
56         return (IDropTarget *)sf;
57 }
58
59 static HRESULT WINAPI ISFDropTarget_QueryInterface(
60         IDropTarget *iface,
61         REFIID riid,
62         LPVOID *ppvObj)
63 {
64         ICOM_THIS(ISFDropTarget,iface);
65
66         char    xriid[50];
67         WINE_StringFromCLSID((LPCLSID)riid,xriid);
68
69         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
70
71         if ( !This || !ppvObj)
72           return E_INVALIDARG;
73
74         *ppvObj = NULL;
75
76         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
77         { *ppvObj = This; 
78         }
79         else if(IsEqualIID(riid, &IID_IDropTarget))  /*IShellFolder*/
80         {    *ppvObj = (ISFDropTarget*)This;
81         }   
82
83         if(*ppvObj)
84         { IDropTarget_AddRef((IDropTarget*)*ppvObj);
85           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
86           return S_OK;
87         }
88
89         TRACE("-- Interface: E_NOINTERFACE\n");
90
91         return E_NOINTERFACE;
92 }
93
94 static ULONG WINAPI ISFDropTarget_AddRef( IDropTarget *iface)
95 {
96         ICOM_THIS(ISFDropTarget,iface);
97
98         TRACE("(%p)->(count=%lu)\n",This,This->ref);
99
100         shell32_ObjCount++;
101
102         return ++(This->ref);
103 }
104
105 static ULONG WINAPI ISFDropTarget_Release( IDropTarget *iface)
106 {
107         ICOM_THIS(ISFDropTarget,iface);
108
109         shell32_ObjCount--;
110
111         if (!--(This->ref)) 
112         { TRACE("-- destroying ISFDropTarget (%p)\n",This);
113           HeapFree(GetProcessHeap(),0,This);
114           return 0;
115         }
116         return This->ref;
117 }
118
119 static HRESULT WINAPI ISFDropTarget_DragEnter(
120         IDropTarget     *iface,
121         IDataObject     *pDataObject,
122         DWORD           grfKeyState,
123         POINTL          pt,
124         DWORD           *pdwEffect)
125 {       
126
127         ICOM_THIS(ISFDropTarget,iface);
128
129         FIXME("Stub: This=%p, DataObject=%p\n",This,pDataObject);
130
131         return E_NOTIMPL;
132 }
133
134 static HRESULT WINAPI ISFDropTarget_DragOver(
135         IDropTarget     *iface,
136         DWORD           grfKeyState,
137         POINTL          pt,
138         DWORD           *pdwEffect)
139 {
140         ICOM_THIS(ISFDropTarget,iface);
141
142         FIXME("Stub: This=%p\n",This);
143
144         return E_NOTIMPL;
145 }
146
147 static HRESULT WINAPI ISFDropTarget_DragLeave(
148         IDropTarget     *iface)
149 {
150         ICOM_THIS(ISFDropTarget,iface);
151
152         FIXME("Stub: This=%p\n",This);
153
154         return E_NOTIMPL;
155 }
156
157 static HRESULT WINAPI ISFDropTarget_Drop(
158         IDropTarget     *iface,
159         IDataObject*    pDataObject,
160         DWORD           grfKeyState,
161         POINTL          pt,
162         DWORD           *pdwEffect)
163 {
164         ICOM_THIS(ISFDropTarget,iface);
165
166         FIXME("Stub: This=%p\n",This);
167
168         return E_NOTIMPL;
169 }
170
171 static struct ICOM_VTABLE(IDropTarget) dtvt = 
172 {
173         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
174         ISFDropTarget_QueryInterface,
175         ISFDropTarget_AddRef,
176         ISFDropTarget_Release,
177         ISFDropTarget_DragEnter,
178         ISFDropTarget_DragOver,
179         ISFDropTarget_DragLeave,
180         ISFDropTarget_Drop
181 };
182
183 /***************************************************************************
184  *  GetNextElement (internal function)
185  *
186  * gets a part of a string till the first backslash
187  *
188  * PARAMETERS
189  *  pszNext [IN] string to get the element from
190  *  pszOut  [IN] pointer to buffer whitch receives string
191  *  dwOut   [IN] length of pszOut
192  *
193  *  RETURNS
194  *    LPSTR pointer to first, not yet parsed char
195  */
196
197 static LPCWSTR GetNextElementW(LPCWSTR pszNext,LPWSTR pszOut,DWORD dwOut)
198 {       LPCWSTR   pszTail = pszNext;
199         DWORD dwCopy;
200         TRACE("(%s %p 0x%08lx)\n",debugstr_w(pszNext),pszOut,dwOut);
201
202         *pszOut=0x0000;
203         
204         if(!pszNext || !*pszNext)
205           return NULL;
206
207         while(*pszTail && (*pszTail != (WCHAR)'\\'))
208           pszTail++;
209
210         dwCopy = (WCHAR*)pszTail - (WCHAR*)pszNext + 1;
211         lstrcpynW(pszOut, pszNext, (dwOut<dwCopy)? dwOut : dwCopy);
212
213         if(*pszTail)
214            pszTail++;
215         else
216            pszTail = NULL;
217
218         TRACE("--(%s %s 0x%08lx %p)\n",debugstr_w(pszNext),debugstr_w(pszOut),dwOut,pszTail);
219         return pszTail;
220 }
221
222 static HRESULT SHELL32_ParseNextElement(
223         HWND hwndOwner,
224         IShellFolder * psf,
225         LPITEMIDLIST * pidlInOut,
226         LPOLESTR szNext,
227         DWORD *pEaten,
228         DWORD *pdwAttributes)
229 {
230         HRESULT         hr = E_OUTOFMEMORY;
231         LPITEMIDLIST    pidlOut, pidlTemp = NULL;
232         IShellFolder    *psfChild;
233         
234         TRACE("(%p %p %s)\n",psf, pidlInOut? *pidlInOut: NULL, debugstr_w(szNext));
235
236
237         /* get the shellfolder for the child pidl and let it analyse further */
238         hr = IShellFolder_BindToObject(psf, *pidlInOut, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
239
240         if (psfChild)
241         {
242           hr = IShellFolder_ParseDisplayName(psfChild, hwndOwner, NULL, szNext, pEaten, &pidlOut, pdwAttributes);
243           IShellFolder_Release(psfChild);
244
245           pidlTemp = ILCombine(*pidlInOut, pidlOut);
246
247           if (pidlOut) 
248             ILFree(pidlOut);
249         }
250
251         ILFree(*pidlInOut);
252         *pidlInOut = pidlTemp;
253
254         TRACE("-- pidl=%p ret=0x%08lx\n", pidlInOut? *pidlInOut: NULL, hr);
255         return hr;      
256 }
257
258 /***********************************************************************
259  *      SHELL32_CoCreateInitSF
260  *
261  *      creates a initialized shell folder
262  */
263 static HRESULT SHELL32_CoCreateInitSF (
264         LPITEMIDLIST pidlRoot,
265         LPITEMIDLIST pidlChild,
266         REFCLSID clsid,
267         REFIID iid,
268         LPVOID * ppvOut)
269 {
270         HRESULT hr;
271         LPITEMIDLIST    absPidl;
272         IShellFolder    *pShellFolder;
273         IPersistFolder  *pPersistFolder;
274
275         TRACE("%p %p\n", pidlRoot, pidlChild);
276
277         *ppvOut = NULL;
278         
279         hr = SHCoCreateInstance(NULL, clsid, NULL, iid, (LPVOID*)&pShellFolder);
280         if (SUCCEEDED(hr))
281         {
282           hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder, (LPVOID*)&pPersistFolder);
283           if (SUCCEEDED(hr))
284           {
285             absPidl = ILCombine (pidlRoot, pidlChild);
286             hr = IPersistFolder_Initialize(pPersistFolder, absPidl);
287             IPersistFolder_Release(pPersistFolder);
288             SHFree(absPidl);
289             *ppvOut = pShellFolder;
290           }
291         }
292
293         TRACE("-- ret=0x%08lx\n", hr);
294         return hr;
295 }
296
297 static HRESULT SHELL32_GetDisplayNameOfChild(
298         IShellFolder * psf,
299         LPCITEMIDLIST pidl,
300         DWORD dwFlags,
301         LPSTR szOut,
302         DWORD dwOutLen)
303 {
304         LPITEMIDLIST    pidlFirst, pidlNext;
305         IShellFolder *  psfChild;
306         HRESULT         hr = E_OUTOFMEMORY;
307         STRRET strTemp;
308         
309         TRACE("(%p)->(pidl=%p 0x%08lx %p 0x%08lx)\n",psf,pidl,dwFlags,szOut, dwOutLen);
310         pdump(pidl);
311         
312         if ((pidlFirst = ILCloneFirst(pidl)))
313         { 
314           hr = IShellFolder_BindToObject(psf, pidlFirst, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
315           if (SUCCEEDED(hr))
316           {
317             pidlNext = ILGetNext(pidl);
318
319             hr = IShellFolder_GetDisplayNameOf(psfChild, pidlNext, dwFlags | SHGDN_INFOLDER, &strTemp);
320             if (SUCCEEDED(hr))
321             {
322               if (strTemp.uType == STRRET_CSTRA)
323               {
324                 lstrcpynA(szOut , strTemp.u.cStr, dwOutLen);
325               }
326               else
327               {
328                 FIXME("wrong return type");
329               }
330             }
331
332             IShellFolder_Release(psfChild);
333           }
334           ILFree(pidlFirst);
335         }
336
337         TRACE("-- ret=0x%08lx %s\n", hr, szOut);
338
339         return hr;
340 }
341
342 /***********************************************************************
343 *   IShellFolder implementation
344 */
345
346 typedef struct 
347 {
348         ICOM_VTABLE(IShellFolder)*      lpvtbl;
349         DWORD                           ref;
350
351         ICOM_VTABLE(IPersistFolder)*    lpvtblPersistFolder;
352         CLSID*                          pclsid;
353
354         LPSTR                           sMyPath;
355         LPITEMIDLIST                    absPidl;        /* complete pidl */
356 } IGenericSFImpl;
357
358 static struct ICOM_VTABLE(IShellFolder) sfvt;
359
360 static struct ICOM_VTABLE(IPersistFolder) psfvt;
361
362 static IShellFolder * ISF_MyComputer_Constructor(void);
363
364 #define _IPersistFolder_Offset ((int)(&(((IGenericSFImpl*)0)->lpvtblPersistFolder))) 
365 #define _ICOM_THIS_From_IPersistFolder(class, name) class* This = (class*)(((char*)name)-_IPersistFolder_Offset); 
366
367 /**************************************************************************
368 *         IShellFolder_Constructor
369 *
370 */
371
372 static IShellFolder * IShellFolder_Constructor(
373         IShellFolder * psf,
374         LPITEMIDLIST pidl)
375 {
376         IGenericSFImpl *        sf;
377         IGenericSFImpl *        sfParent = (IGenericSFImpl*) psf;
378         DWORD                   dwSize=0;
379
380         sf=(IGenericSFImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IGenericSFImpl));
381         sf->ref=1;
382
383         sf->lpvtbl=&sfvt;
384         sf->lpvtblPersistFolder=&psfvt;
385         sf->pclsid = (CLSID*)&CLSID_SFFile;
386         
387         TRACE("(%p)->(parent=%p, pidl=%p)\n",sf,sfParent, pidl);
388         pdump(pidl);
389                 
390         if(pidl)                                                /* do we have a pidl? */
391         {
392           int len;
393
394           sf->absPidl = ILCombine(sfParent->absPidl, pidl);     /* build a absolute pidl */
395
396           if (!_ILIsSpecialFolder(pidl))                                /* only file system paths */
397           {
398             if(sfParent->sMyPath)                               /* get the size of the parents path */
399             {
400               dwSize += strlen(sfParent->sMyPath) ;
401               TRACE("-- (%p)->(parent's path=%s)\n",sf, debugstr_a(sfParent->sMyPath));
402             }   
403
404             dwSize += _ILSimpleGetText(pidl,NULL,0);            /* add the size of our name*/
405             sf->sMyPath = SHAlloc(dwSize + 2);                  /* '\0' and backslash */
406
407             if(!sf->sMyPath) return NULL;
408             *(sf->sMyPath)=0x00;
409
410             if(sfParent->sMyPath)                               /* if the parent has a path, get it*/
411             {
412               strcpy(sf->sMyPath, sfParent->sMyPath);
413               PathAddBackslashA (sf->sMyPath);
414             }
415
416             len = strlen(sf->sMyPath);
417             _ILSimpleGetText(pidl, sf->sMyPath + len, dwSize - len + 1);
418           }
419
420           TRACE("-- (%p)->(my pidl=%p, my path=%s)\n",sf, sf->absPidl,debugstr_a(sf->sMyPath));
421
422           pdump (sf->absPidl);
423         }
424
425         shell32_ObjCount++;
426         return (IShellFolder *)sf;
427 }
428 /**************************************************************************
429  *  IShellFolder_fnQueryInterface
430  *
431  * PARAMETERS
432  *  REFIID riid         [in ] Requested InterfaceID
433  *  LPVOID* ppvObject   [out] Interface* to hold the result
434  */
435 static HRESULT WINAPI IShellFolder_fnQueryInterface(
436         IShellFolder * iface,
437         REFIID riid,
438         LPVOID *ppvObj)
439 {
440         ICOM_THIS(IGenericSFImpl, iface);
441
442         char    xriid[50];      
443         WINE_StringFromCLSID((LPCLSID)riid,xriid);
444         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
445
446         *ppvObj = NULL;
447
448         if(IsEqualIID(riid, &IID_IUnknown))
449         { *ppvObj = This; 
450         }
451         else if(IsEqualIID(riid, &IID_IShellFolder))
452         {    *ppvObj = (IShellFolder*)This;
453         }   
454         else if(IsEqualIID(riid, &IID_IPersist))
455         {    *ppvObj = (IPersistFolder*)&(This->lpvtblPersistFolder);
456         }   
457         else if(IsEqualIID(riid, &IID_IPersistFolder))
458         {    *ppvObj = (IPersistFolder*)&(This->lpvtblPersistFolder);
459         }   
460
461         if(*ppvObj)
462         {
463           IUnknown_AddRef((IUnknown*)(*ppvObj));
464           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
465           return S_OK;
466         }
467         TRACE("-- Interface: E_NOINTERFACE\n");
468         return E_NOINTERFACE;
469 }
470
471 /**************************************************************************
472 *  IShellFolder_AddRef
473 */
474
475 static ULONG WINAPI IShellFolder_fnAddRef(IShellFolder * iface)
476 {
477         ICOM_THIS(IGenericSFImpl, iface);
478
479         TRACE("(%p)->(count=%lu)\n",This,This->ref);
480
481         shell32_ObjCount++;
482         return ++(This->ref);
483 }
484
485 /**************************************************************************
486  *  IShellFolder_fnRelease
487  */
488 static ULONG WINAPI IShellFolder_fnRelease(IShellFolder * iface) 
489 {
490         ICOM_THIS(IGenericSFImpl, iface);
491
492         TRACE("(%p)->(count=%lu)\n",This,This->ref);
493
494         shell32_ObjCount--;
495         if (!--(This->ref)) 
496         { TRACE("-- destroying IShellFolder(%p)\n",This);
497
498           if (pdesktopfolder == iface)
499           { pdesktopfolder=NULL;
500             TRACE("-- destroyed IShellFolder(%p) was Desktopfolder\n",This);
501           }
502           if(This->absPidl)
503           { SHFree(This->absPidl);
504           }
505           if(This->sMyPath)
506           { SHFree(This->sMyPath);
507           }
508
509           HeapFree(GetProcessHeap(),0,This);
510
511           return 0;
512         }
513         return This->ref;
514 }
515 /**************************************************************************
516 *               IShellFolder_fnParseDisplayName
517 * PARAMETERS
518 *  HWND          hwndOwner,      //[in ] Parent window for any message's
519 *  LPBC          pbc,            //[in ] reserved
520 *  LPOLESTR      lpszDisplayName,//[in ] "Unicode" displayname.
521 *  ULONG*        pchEaten,       //[out] (unicode) characters processed
522 *  LPITEMIDLIST* ppidl,          //[out] complex pidl to item
523 *  ULONG*        pdwAttributes   //[out] items attributes
524 *
525 * NOTES
526 *  every folder trys to parse only it's own (the leftmost) pidl and creates a 
527 *  subfolder to evaluate the remaining parts
528 *  now we can parse into namespaces implemented by shell extensions
529 *
530 *  behaviour on win98:  lpszDisplayName=NULL -> chrash
531 *                       lpszDisplayName="" -> returns mycoputer-pidl
532 *
533 * FIXME: 
534 *    pdwAttributes: not set
535 *    pchEaten: not set like in windows
536 */
537 static HRESULT WINAPI IShellFolder_fnParseDisplayName(
538         IShellFolder * iface,
539         HWND hwndOwner,
540         LPBC pbcReserved,
541         LPOLESTR lpszDisplayName,
542         DWORD *pchEaten,
543         LPITEMIDLIST *ppidl,
544         DWORD *pdwAttributes)
545 {
546         ICOM_THIS(IGenericSFImpl, iface);
547
548         HRESULT         hr = E_OUTOFMEMORY;
549         LPCWSTR         szNext=NULL;
550         WCHAR           szElement[MAX_PATH];
551         CHAR            szTempA[MAX_PATH], szPath[MAX_PATH];
552         LPITEMIDLIST    pidlTemp=NULL;
553         
554         TRACE("(%p)->(HWND=0x%08x,%p,%p=%s,%p,pidl=%p,%p)\n",
555         This,hwndOwner,pbcReserved,lpszDisplayName,
556         debugstr_w(lpszDisplayName),pchEaten,ppidl,pdwAttributes);
557
558         if (pchEaten) *pchEaten = 0;    /* strange but like the original */
559         
560         if (*lpszDisplayName)
561         {       
562           /* get the next element */
563           szNext = GetNextElementW(lpszDisplayName, szElement, MAX_PATH);
564
565           /* build the full pathname to the element */
566           WideCharToLocal(szTempA, szElement, lstrlenW(szElement) + 1);
567           strcpy(szPath, This->sMyPath);
568           PathAddBackslashA(szPath);
569           strcat(szPath, szTempA);
570
571           /* get the pidl */
572           pidlTemp = SHSimpleIDListFromPathA(szPath);
573
574           if (pidlTemp)
575           {
576             /* try to analyse the next element */
577             if (szNext && *szNext)
578             {
579               hr = SHELL32_ParseNextElement(hwndOwner, (IShellFolder*)This, &pidlTemp, (LPOLESTR)szNext, pchEaten, pdwAttributes);
580             }
581             else
582             {
583                hr = S_OK;
584             }
585           }
586         }
587
588         *ppidl = pidlTemp;
589
590         TRACE("(%p)->(-- pidl=%p ret=0x%08lx)\n", This, ppidl? *ppidl:0, hr);
591
592         return hr;      
593 }
594
595 /**************************************************************************
596 *               IShellFolder_fnEnumObjects
597 * PARAMETERS
598 *  HWND          hwndOwner,    //[in ] Parent Window
599 *  DWORD         grfFlags,     //[in ] SHCONTF enumeration mask
600 *  LPENUMIDLIST* ppenumIDList  //[out] IEnumIDList interface
601 */
602 static HRESULT WINAPI IShellFolder_fnEnumObjects(
603         IShellFolder * iface,
604         HWND hwndOwner,
605         DWORD dwFlags,
606         LPENUMIDLIST* ppEnumIDList)
607 {
608         ICOM_THIS(IGenericSFImpl, iface);
609
610         TRACE("(%p)->(HWND=0x%08x flags=0x%08lx pplist=%p)\n",This,hwndOwner,dwFlags,ppEnumIDList);
611
612         *ppEnumIDList = NULL;
613         *ppEnumIDList = IEnumIDList_Constructor (This->sMyPath, dwFlags, EIDL_FILE);
614
615         TRACE("-- (%p)->(new ID List: %p)\n",This,*ppEnumIDList);
616
617         if(!*ppEnumIDList) return E_OUTOFMEMORY;
618
619         return S_OK;            
620 }
621
622 /**************************************************************************
623 *               IShellFolder_fnBindToObject
624 * PARAMETERS
625 *  LPCITEMIDLIST pidl,       //[in ] relative pidl to open
626 *  LPBC          pbc,        //[in ] reserved
627 *  REFIID        riid,       //[in ] Initial Interface
628 *  LPVOID*       ppvObject   //[out] Interface*
629 */
630 static HRESULT WINAPI IShellFolder_fnBindToObject( IShellFolder * iface, LPCITEMIDLIST pidl,
631                         LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
632 {
633         ICOM_THIS(IGenericSFImpl, iface);
634         GUID            const * iid;
635         char            xriid[50];
636         IShellFolder    *pShellFolder, *pSubFolder;
637         IPersistFolder  *pPersistFolder;
638         LPITEMIDLIST    absPidl;
639         
640         WINE_StringFromCLSID(riid,xriid);
641
642         TRACE("(%p)->(pidl=%p,%p,\n\tIID:\t%s,%p)\n",This,pidl,pbcReserved,xriid,ppvOut);
643
644         *ppvOut = NULL;
645
646         if ((iid=_ILGetGUIDPointer(pidl)) && !IsEqualIID(iid, &IID_MyComputer))
647         {
648           /* we have to create a alien folder */
649           if (  SUCCEEDED(SHCoCreateInstance(NULL, iid, NULL, riid, (LPVOID*)&pShellFolder))
650              && SUCCEEDED(IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder, (LPVOID*)&pPersistFolder)))
651             {
652               absPidl = ILCombine (This->absPidl, pidl);
653               IPersistFolder_Initialize(pPersistFolder, absPidl);
654               IPersistFolder_Release(pPersistFolder);
655               SHFree(absPidl);
656             }
657             else
658             {
659               return E_FAIL;
660             }
661         }
662         else
663         {
664           LPITEMIDLIST pidltemp = ILCloneFirst(pidl);
665           pShellFolder = IShellFolder_Constructor((IShellFolder*)This, pidltemp);
666           ILFree(pidltemp);
667         }
668         
669         if (_ILIsPidlSimple(pidl))
670         {
671           *ppvOut = pShellFolder;
672         }
673         else
674         {
675           IShellFolder_BindToObject(pShellFolder, ILGetNext(pidl), NULL, &IID_IShellFolder, (LPVOID)&pSubFolder);
676           IShellFolder_Release(pShellFolder);
677           *ppvOut = pSubFolder;
678         }
679
680         TRACE("-- (%p) returning (%p)\n",This, *ppvOut);
681
682         return S_OK;
683 }
684
685 /**************************************************************************
686 *  IShellFolder_fnBindToStorage
687 * PARAMETERS
688 *  LPCITEMIDLIST pidl,       //[in ] complex pidl to store
689 *  LPBC          pbc,        //[in ] reserved
690 *  REFIID        riid,       //[in ] Initial storage interface 
691 *  LPVOID*       ppvObject   //[out] Interface* returned
692 */
693 static HRESULT WINAPI IShellFolder_fnBindToStorage(
694         IShellFolder * iface,
695         LPCITEMIDLIST pidl,
696         LPBC pbcReserved,
697         REFIID riid,
698         LPVOID *ppvOut)
699 {
700         ICOM_THIS(IGenericSFImpl, iface);
701
702         char xriid[50];
703         WINE_StringFromCLSID(riid,xriid);
704
705         FIXME("(%p)->(pidl=%p,%p,\n\tIID:%s,%p) stub\n",This,pidl,pbcReserved,xriid,ppvOut);
706
707         *ppvOut = NULL;
708         return E_NOTIMPL;
709 }
710
711 /**************************************************************************
712 *  IShellFolder_fnCompareIDs
713 *
714 * PARMETERS
715 *  LPARAM        lParam, //[in ] Column?
716 *  LPCITEMIDLIST pidl1,  //[in ] simple pidl
717 *  LPCITEMIDLIST pidl2)  //[in ] simple pidl
718 *
719 * NOTES
720 *   Special case - If one of the items is a Path and the other is a File,
721 *   always make the Path come before the File.
722 *
723 * NOTES 
724 *  use SCODE_CODE() on the return value to get the result
725 */
726
727 static HRESULT WINAPI  IShellFolder_fnCompareIDs(
728         IShellFolder * iface,
729         LPARAM lParam,
730         LPCITEMIDLIST pidl1,
731         LPCITEMIDLIST pidl2)
732 {
733         ICOM_THIS(IGenericSFImpl, iface);
734
735         CHAR szTemp1[MAX_PATH];
736         CHAR szTemp2[MAX_PATH];
737         int   nReturn;
738         IShellFolder * psf;
739         HRESULT hr = E_OUTOFMEMORY;
740         LPCITEMIDLIST  pidlTemp;
741         PIDLTYPE pt1, pt2;
742
743         TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n",This,lParam,pidl1,pidl2);
744         pdump (pidl1);
745         pdump (pidl2);
746         
747         if (!pidl1 && !pidl2)
748         {
749           hr = ResultFromShort(0);
750         }
751         else if (!pidl1)
752         {
753           hr = ResultFromShort(-1);
754         }
755         else if (!pidl2)
756         {
757           hr = ResultFromShort(1);
758         }
759         else
760         {
761           LPPIDLDATA pd1, pd2;
762           pd1 = _ILGetDataPointer(pidl1);
763           pd2 = _ILGetDataPointer(pidl2);
764         
765           /* compate the types. sort order is the PT_* constant */
766           pt1 = ( pd1 ? pd1->type: PT_DESKTOP);
767           pt2 = ( pd2 ? pd2->type: PT_DESKTOP);
768
769           if (pt1 != pt2)
770           {
771             hr = ResultFromShort(pt1-pt2);
772           }
773           else                                          /* same type of pidl */
774           {
775             _ILSimpleGetText(pidl1, szTemp1, MAX_PATH);
776             _ILSimpleGetText(pidl2, szTemp2, MAX_PATH);
777             nReturn = strcasecmp(szTemp1, szTemp2);
778         
779             if (nReturn == 0)                           /* first pidl different ? */
780             {
781               pidl1 = ILGetNext(pidl1);
782
783               if (pidl1 && pidl1->mkid.cb)              /* go deeper? */        
784               {
785                 pidlTemp = ILCloneFirst(pidl1);
786                 pidl2 = ILGetNext(pidl2);
787         
788                 hr = IShellFolder_BindToObject((IShellFolder*)This, pidlTemp, NULL, &IID_IShellFolder, (LPVOID*)&psf);
789                 if (SUCCEEDED(hr))
790                 { 
791                   nReturn = IShellFolder_CompareIDs(psf, 0, pidl1, pidl2);
792                   IShellFolder_Release(psf);
793                   hr = ResultFromShort(nReturn);
794                 }
795                 ILFree(pidlTemp);
796               }
797               else
798               {
799                 hr = ResultFromShort(nReturn);          /* two equal simple pidls */
800               }
801             }
802             else
803             {
804               hr = ResultFromShort(nReturn);            /* two different simple pidls */
805             }
806           }
807         }
808         
809         TRACE("-- res=0x%08lx\n", hr);
810         return hr;
811 }
812
813 /**************************************************************************
814 *         IShellFolder_fnCreateViewObject
815 * Creates an View Object representing the ShellFolder
816 *  IShellView / IShellBrowser / IContextMenu
817 *
818 * PARAMETERS
819 *  HWND    hwndOwner,  // Handle of owner window
820 *  REFIID  riid,       // Requested initial interface
821 *  LPVOID* ppvObject)  // Resultant interface*
822 *
823 * NOTES
824 *  the same as SHCreateShellFolderViewEx ???
825 */
826 static HRESULT WINAPI IShellFolder_fnCreateViewObject( IShellFolder * iface,
827                  HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
828 {
829         ICOM_THIS(IGenericSFImpl, iface);
830
831         LPSHELLVIEW pShellView;
832         char    xriid[50];
833         HRESULT       hr;
834
835         WINE_StringFromCLSID(riid,xriid);
836         TRACE("(%p)->(hwnd=0x%x,\n\tIID:\t%s,%p)\n",This,hwndOwner,xriid,ppvOut);
837         
838         *ppvOut = NULL;
839
840         pShellView = IShellView_Constructor((IShellFolder *) This);
841
842         if(!pShellView)
843           return E_OUTOFMEMORY;
844           
845         hr = pShellView->lpvtbl->fnQueryInterface(pShellView, riid, ppvOut);
846         pShellView->lpvtbl->fnRelease(pShellView);
847         TRACE("-- (%p)->(interface=%p)\n",This, ppvOut);
848         return hr; 
849 }
850
851 /**************************************************************************
852 *  IShellFolder_fnGetAttributesOf
853 *
854 * PARAMETERS
855 *  UINT            cidl,     //[in ] num elements in pidl array
856 *  LPCITEMIDLIST*  apidl,    //[in ] simple pidl array 
857 *  ULONG*          rgfInOut) //[out] result array  
858 *
859 */
860 static HRESULT WINAPI IShellFolder_fnGetAttributesOf(IShellFolder * iface,UINT cidl,LPCITEMIDLIST *apidl,DWORD *rgfInOut)
861 {
862         ICOM_THIS(IGenericSFImpl, iface);
863
864         HRESULT hr = S_OK;
865
866         TRACE("(%p)->(cidl=%d apidl=%p mask=0x%08lx)\n",This,cidl,apidl,*rgfInOut);
867
868         if ( (!cidl) || (!apidl) || (!rgfInOut))
869           return E_INVALIDARG;
870
871         while (cidl > 0 && *apidl)
872         {
873           pdump (*apidl);
874           if (_ILIsFolder( *apidl))
875           {
876             *rgfInOut &= 0xe0000177;
877             goto next;
878           }
879           else if (_ILIsValue( *apidl))
880           {
881             *rgfInOut &= 0x40000177;
882             goto next;
883           }
884           hr = E_INVALIDARG;
885
886 next:     apidl++;
887           cidl--;
888         } 
889
890         TRACE("-- result=0x%08lx\n",*rgfInOut);
891
892         return hr;
893 }
894 /**************************************************************************
895 *  IShellFolder_fnGetUIObjectOf
896 *
897 * PARAMETERS
898 *  HWND           hwndOwner, //[in ] Parent window for any output
899 *  UINT           cidl,      //[in ] array size
900 *  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
901 *  REFIID         riid,      //[in ] Requested Interface
902 *  UINT*          prgfInOut, //[   ] reserved 
903 *  LPVOID*        ppvObject) //[out] Resulting Interface
904 *
905 * NOTES
906 *  This function gets asked to return "view objects" for one or more (multiple select)
907 *  items:
908 *  The viewobject typically is an COM object with one of the following interfaces:
909 *  IExtractIcon,IDataObject,IContextMenu
910 *  In order to support icon positions in the default Listview your DataObject
911 *  must implement the SetData method (in addition to GetData :) - the shell passes
912 *  a barely documented "Icon positions" structure to SetData when the drag starts,
913 *  and GetData's it if the drop is in another explorer window that needs the positions.
914 */
915 static HRESULT WINAPI IShellFolder_fnGetUIObjectOf( 
916         IShellFolder *  iface,
917         HWND            hwndOwner,
918         UINT            cidl,
919         LPCITEMIDLIST * apidl, 
920         REFIID          riid, 
921         UINT *          prgfInOut,
922         LPVOID *        ppvOut)
923 {       
924         ICOM_THIS(IGenericSFImpl, iface);
925
926         char            xclsid[50];
927         LPITEMIDLIST    pidl;
928         LPUNKNOWN       pObj = NULL; 
929
930         WINE_StringFromCLSID(riid,xclsid);
931
932         TRACE("(%p)->(%u,%u,apidl=%p,\n\tIID:%s,%p,%p)\n",
933           This,hwndOwner,cidl,apidl,xclsid,prgfInOut,ppvOut);
934
935         if (!ppvOut)
936           return E_INVALIDARG;
937
938         *ppvOut = NULL;
939
940         if(IsEqualIID(riid, &IID_IContextMenu))
941         { 
942           if(cidl < 1)
943             return E_INVALIDARG;
944
945           pObj  = (LPUNKNOWN)IContextMenu_Constructor((IShellFolder *)This, This->absPidl, apidl, cidl);
946         }
947         else if (IsEqualIID(riid, &IID_IDataObject))
948         { 
949           if (cidl < 1)
950             return E_INVALIDARG;
951
952           pObj = (LPUNKNOWN)IDataObject_Constructor (hwndOwner, This->absPidl, apidl, cidl);
953         }
954         else if(IsEqualIID(riid, &IID_IExtractIconA))
955         { 
956           if (cidl != 1)
957             return E_INVALIDARG;
958
959           pidl = ILCombine(This->absPidl,apidl[0]);
960           pObj = (LPUNKNOWN)IExtractIconA_Constructor( pidl );
961           SHFree(pidl);
962         } 
963         else if (IsEqualIID(riid, &IID_IDropTarget))
964         { 
965           if (cidl < 1)
966             return E_INVALIDARG;
967
968           pObj = (LPUNKNOWN)ISFDropTarget_Constructor();
969         }
970         else
971         { 
972           ERR("(%p)->E_NOINTERFACE\n",This);
973           return E_NOINTERFACE;
974         }
975
976         if(!pObj)
977           return E_OUTOFMEMORY;
978
979         *ppvOut = pObj;
980         return S_OK;
981 }
982
983 /**************************************************************************
984 *  IShellFolder_fnGetDisplayNameOf
985 *  Retrieves the display name for the specified file object or subfolder
986 *
987 * PARAMETERS
988 *  LPCITEMIDLIST pidl,    //[in ] complex pidl to item
989 *  DWORD         dwFlags, //[in ] SHGNO formatting flags
990 *  LPSTRRET      lpName)  //[out] Returned display name
991 *
992 * FIXME
993 *  if the name is in the pidl the ret value should be a STRRET_OFFSET
994 */
995 #define GET_SHGDN_FOR(dwFlags)         ((DWORD)dwFlags & (DWORD)0x0000FF00)
996 #define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)
997
998 static HRESULT WINAPI IShellFolder_fnGetDisplayNameOf(
999         IShellFolder * iface,
1000         LPCITEMIDLIST pidl,
1001         DWORD dwFlags,
1002         LPSTRRET strRet)
1003 {
1004         ICOM_THIS(IGenericSFImpl, iface);
1005
1006         CHAR            szPath[MAX_PATH]= "";
1007         int             len = 0;
1008         BOOL            bSimplePidl;
1009                 
1010         TRACE("(%p)->(pidl=%p,0x%08lx,%p)\n",This,pidl,dwFlags,strRet);
1011         pdump(pidl);
1012         
1013         if(!pidl || !strRet) return E_INVALIDARG;
1014         
1015         bSimplePidl = _ILIsPidlSimple(pidl);
1016
1017         /* take names of special folders only if its only this folder */
1018         if (_ILIsSpecialFolder(pidl))
1019         {
1020           if ( bSimplePidl)
1021           {
1022             _ILSimpleGetText(pidl, szPath, MAX_PATH); /* append my own path */
1023           }
1024         }
1025         else
1026         {
1027           if (!(dwFlags & SHGDN_INFOLDER) && (dwFlags & SHGDN_FORPARSING) && This->sMyPath)
1028           {
1029             strcpy (szPath, This->sMyPath);                     /* get path to root*/
1030             PathAddBackslashA(szPath);
1031             len = strlen(szPath);
1032           }
1033           _ILSimpleGetText(pidl, szPath + len, MAX_PATH - len); /* append my own path */
1034         }
1035         
1036         if ( (dwFlags & SHGDN_FORPARSING) && !bSimplePidl)      /* go deeper if needed */
1037         {
1038           PathAddBackslashA(szPath);
1039           len = strlen(szPath);
1040
1041           if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild((IShellFolder*)This, pidl, dwFlags, szPath + len, MAX_PATH - len)))
1042             return E_OUTOFMEMORY;
1043         }
1044         strRet->uType = STRRET_CSTRA;
1045         lstrcpynA(strRet->u.cStr, szPath, MAX_PATH);
1046
1047         TRACE("-- (%p)->(%s)\n", This, szPath);
1048         return S_OK;
1049 }
1050
1051 /**************************************************************************
1052 *  IShellFolder_fnSetNameOf
1053 *  Changes the name of a file object or subfolder, possibly changing its item
1054 *  identifier in the process.
1055 *
1056 * PARAMETERS
1057 *  HWND          hwndOwner,  //[in ] Owner window for output
1058 *  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
1059 *  LPCOLESTR     lpszName,   //[in ] the items new display name
1060 *  DWORD         dwFlags,    //[in ] SHGNO formatting flags
1061 *  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
1062 */
1063 static HRESULT WINAPI IShellFolder_fnSetNameOf(
1064         IShellFolder * iface,
1065         HWND hwndOwner, 
1066         LPCITEMIDLIST pidl, /*simple pidl*/
1067         LPCOLESTR lpName, 
1068         DWORD dw, 
1069         LPITEMIDLIST *pPidlOut)
1070 {
1071         ICOM_THIS(IGenericSFImpl, iface);
1072
1073         FIXME("(%p)->(%u,pidl=%p,%s,%lu,%p),stub!\n",
1074         This,hwndOwner,pidl,debugstr_w(lpName),dw,pPidlOut);
1075
1076         return E_NOTIMPL;
1077 }
1078
1079 /**************************************************************************
1080 *  IShellFolder_fnGetFolderPath
1081 */
1082 static HRESULT WINAPI IShellFolder_fnGetFolderPath(IShellFolder * iface, LPSTR lpszOut, DWORD dwOutSize)
1083 {
1084         ICOM_THIS(IGenericSFImpl, iface);
1085         
1086         TRACE("(%p)->(%p %lu)\n",This, lpszOut, dwOutSize);
1087
1088         if (!lpszOut) return FALSE;
1089
1090         *lpszOut=0;
1091
1092         if (! This->sMyPath) return FALSE;
1093
1094         lstrcpynA(lpszOut, This->sMyPath, dwOutSize);
1095
1096         TRACE("-- (%p)->(return=%s)\n",This, lpszOut);
1097         return TRUE;
1098 }
1099
1100 static ICOM_VTABLE(IShellFolder) sfvt = 
1101 {       
1102         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1103         IShellFolder_fnQueryInterface,
1104         IShellFolder_fnAddRef,
1105         IShellFolder_fnRelease,
1106         IShellFolder_fnParseDisplayName,
1107         IShellFolder_fnEnumObjects,
1108         IShellFolder_fnBindToObject,
1109         IShellFolder_fnBindToStorage,
1110         IShellFolder_fnCompareIDs,
1111         IShellFolder_fnCreateViewObject,
1112         IShellFolder_fnGetAttributesOf,
1113         IShellFolder_fnGetUIObjectOf,
1114         IShellFolder_fnGetDisplayNameOf,
1115         IShellFolder_fnSetNameOf,
1116         IShellFolder_fnGetFolderPath
1117 };
1118
1119 /***********************************************************************
1120 *       [Desktopfolder] IShellFolder implementation
1121 */
1122 static struct ICOM_VTABLE(IShellFolder) sfdvt;
1123
1124 /**************************************************************************
1125 *       ISF_Desktop_Constructor
1126 *
1127 */
1128 IShellFolder * ISF_Desktop_Constructor()
1129 {
1130         IGenericSFImpl *        sf;
1131
1132         sf=(IGenericSFImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IGenericSFImpl));
1133         sf->ref=1;
1134         sf->lpvtbl=&sfdvt;
1135         sf->absPidl=_ILCreateDesktop(); /* my qualified pidl */
1136
1137         TRACE("(%p)\n",sf);
1138
1139         shell32_ObjCount++;
1140         return (IShellFolder *)sf;
1141 }
1142
1143 /**************************************************************************
1144  *      ISF_Desktop_fnQueryInterface
1145  *
1146  * NOTES supports not IPersist/IPersistFolder
1147  */
1148 static HRESULT WINAPI ISF_Desktop_fnQueryInterface(
1149         IShellFolder * iface,
1150         REFIID riid,
1151         LPVOID *ppvObj)
1152 {
1153         ICOM_THIS(IGenericSFImpl, iface);
1154
1155         char    xriid[50];      
1156         WINE_StringFromCLSID((LPCLSID)riid,xriid);
1157         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
1158
1159         *ppvObj = NULL;
1160
1161         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
1162         { *ppvObj = This; 
1163         }
1164         else if(IsEqualIID(riid, &IID_IShellFolder))  /*IShellFolder*/
1165         {    *ppvObj = (IShellFolder*)This;
1166         }   
1167
1168         if(*ppvObj)
1169         {
1170           IUnknown_AddRef((IUnknown*)(*ppvObj));
1171           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
1172           return S_OK;
1173         }
1174         TRACE("-- Interface: E_NOINTERFACE\n");
1175         return E_NOINTERFACE;
1176 }
1177
1178 /**************************************************************************
1179 *       ISF_Desktop_fnParseDisplayName
1180 *
1181 * NOTES
1182 *       "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
1183 *       to MyComputer
1184 */
1185 static HRESULT WINAPI ISF_Desktop_fnParseDisplayName(
1186         IShellFolder * iface,
1187         HWND hwndOwner,
1188         LPBC pbcReserved,
1189         LPOLESTR lpszDisplayName,
1190         DWORD *pchEaten,
1191         LPITEMIDLIST *ppidl,
1192         DWORD *pdwAttributes)
1193 {
1194         ICOM_THIS(IGenericSFImpl, iface);
1195
1196         LPCWSTR         szNext=NULL;
1197         LPITEMIDLIST    pidlTemp=NULL;
1198         HRESULT         hr=E_OUTOFMEMORY;
1199         
1200         TRACE("(%p)->(HWND=0x%08x,%p,%p=%s,%p,pidl=%p,%p)\n",
1201         This,hwndOwner,pbcReserved,lpszDisplayName,
1202         debugstr_w(lpszDisplayName),pchEaten,ppidl,pdwAttributes);
1203
1204         *ppidl = 0;
1205         if (pchEaten) *pchEaten = 0;    /* strange but like the original */
1206         
1207         /* fixme no real parsing implemented */
1208         pidlTemp = _ILCreateMyComputer();
1209         szNext = lpszDisplayName;
1210
1211         if (szNext && *szNext)
1212         {
1213           hr = SHELL32_ParseNextElement(hwndOwner, (IShellFolder*)This, &pidlTemp, (LPOLESTR)szNext, pchEaten, pdwAttributes);
1214         }
1215         else
1216         {
1217           hr = S_OK;
1218         }
1219
1220         *ppidl = pidlTemp;
1221
1222         TRACE("(%p)->(-- ret=0x%08lx)\n", This, hr);
1223
1224         return hr;      
1225 }
1226
1227 /**************************************************************************
1228 *               ISF_Desktop_fnEnumObjects
1229 */
1230 static HRESULT WINAPI ISF_Desktop_fnEnumObjects(
1231         IShellFolder * iface,
1232         HWND hwndOwner,
1233         DWORD dwFlags,
1234         LPENUMIDLIST* ppEnumIDList)
1235 {
1236         ICOM_THIS(IGenericSFImpl, iface);
1237
1238         TRACE("(%p)->(HWND=0x%08x flags=0x%08lx pplist=%p)\n",This,hwndOwner,dwFlags,ppEnumIDList);
1239
1240         *ppEnumIDList = NULL;
1241         *ppEnumIDList = IEnumIDList_Constructor (NULL, dwFlags, EIDL_DESK);
1242
1243         TRACE("-- (%p)->(new ID List: %p)\n",This,*ppEnumIDList);
1244
1245         if(!*ppEnumIDList) return E_OUTOFMEMORY;
1246
1247         return S_OK;            
1248 }
1249
1250 /**************************************************************************
1251 *               ISF_Desktop_fnBindToObject
1252 */
1253 static HRESULT WINAPI ISF_Desktop_fnBindToObject( IShellFolder * iface, LPCITEMIDLIST pidl,
1254                         LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
1255 {
1256         ICOM_THIS(IGenericSFImpl, iface);
1257         GUID            const * clsid;
1258         char            xriid[50];
1259         IShellFolder    *pShellFolder, *pSubFolder;
1260         
1261         WINE_StringFromCLSID(riid,xriid);
1262
1263         TRACE("(%p)->(pidl=%p,%p,\n\tIID:\t%s,%p)\n",This,pidl,pbcReserved,xriid,ppvOut);
1264
1265         *ppvOut = NULL;
1266
1267         if (!(clsid=_ILGetGUIDPointer(pidl))) return E_INVALIDARG;
1268
1269         if ( IsEqualIID(clsid, &IID_MyComputer))
1270         {
1271           pShellFolder = ISF_MyComputer_Constructor();
1272         }
1273         else
1274         {
1275            if (!SUCCEEDED(SHELL32_CoCreateInitSF (This->absPidl, pidl, clsid, riid, (LPVOID*)&pShellFolder)))
1276            {
1277              return E_INVALIDARG;
1278            }
1279         }
1280         
1281         if (_ILIsPidlSimple(pidl))      /* no sub folders */
1282         {
1283           *ppvOut = pShellFolder;
1284         }
1285         else                            /* go deeper */
1286         {
1287           IShellFolder_BindToObject(pShellFolder, ILGetNext(pidl), NULL, riid, (LPVOID)&pSubFolder);
1288           IShellFolder_Release(pShellFolder);
1289           *ppvOut = pSubFolder;
1290         }
1291
1292         TRACE("-- (%p) returning (%p)\n",This, *ppvOut);
1293
1294         return S_OK;
1295 }
1296
1297 /**************************************************************************
1298 *  ISF_Desktop_fnGetAttributesOf
1299 */
1300 static HRESULT WINAPI ISF_Desktop_fnGetAttributesOf(IShellFolder * iface,UINT cidl,LPCITEMIDLIST *apidl,DWORD *rgfInOut)
1301 {
1302         ICOM_THIS(IGenericSFImpl, iface);
1303
1304         GUID            const * clsid;
1305         DWORD           attributes;
1306         HRESULT         hr = S_OK;
1307
1308         TRACE("(%p)->(cidl=%d apidl=%p mask=0x%08lx)\n",This,cidl,apidl, *rgfInOut);
1309
1310         if ( (!cidl) || (!apidl) || (!rgfInOut))
1311           return E_INVALIDARG;
1312
1313         while (cidl > 0 && *apidl)
1314         {
1315           pdump (*apidl);
1316
1317           if ((clsid=_ILGetGUIDPointer(*apidl)))
1318           {
1319             if (IsEqualIID(clsid, &IID_MyComputer))
1320             {
1321               *rgfInOut &= 0xb0000154;
1322               goto next;
1323             }
1324             else if (HCR_GetFolderAttributes(clsid, &attributes))
1325             {
1326               *rgfInOut &= attributes;
1327               goto next;
1328             }
1329           }
1330           else if (_ILIsFolder( *apidl))
1331           {
1332             *rgfInOut &= 0xe0000177;
1333             goto next;
1334           }
1335           else if (_ILIsValue( *apidl))
1336           {
1337             *rgfInOut &= 0x40000177;
1338             goto next;
1339           }
1340           hr = E_INVALIDARG;
1341
1342 next:     apidl++;
1343           cidl--;
1344         }
1345
1346         TRACE("-- result=0x%08lx\n",*rgfInOut);
1347
1348         return hr;
1349 }
1350
1351 /**************************************************************************
1352 *       ISF_Desktop_fnGetDisplayNameOf
1353 *
1354 * NOTES
1355 *       special case: pidl = null gives desktop-name back
1356 */
1357 static HRESULT WINAPI ISF_Desktop_fnGetDisplayNameOf(
1358         IShellFolder * iface,
1359         LPCITEMIDLIST pidl,
1360         DWORD dwFlags,
1361         LPSTRRET strRet)
1362 {
1363         ICOM_THIS(IGenericSFImpl, iface);
1364
1365         CHAR            szPath[MAX_PATH]= "";
1366                 
1367         TRACE("(%p)->(pidl=%p,0x%08lx,%p)\n",This,pidl,dwFlags,strRet);
1368         pdump(pidl);
1369         
1370         if(!strRet) return E_INVALIDARG;
1371         
1372         if(!pidl)
1373         {
1374           HCR_GetClassName(&CLSID_ShellDesktop, szPath, MAX_PATH);
1375         }
1376         else if ( _ILIsPidlSimple(pidl) )
1377         {
1378           _ILSimpleGetText(pidl, szPath, MAX_PATH);
1379         }
1380         else
1381         { 
1382           if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild((IShellFolder*)This, pidl, dwFlags, szPath, MAX_PATH)))
1383             return E_OUTOFMEMORY;
1384         }
1385         strRet->uType = STRRET_CSTRA;
1386         lstrcpynA(strRet->u.cStr, szPath, MAX_PATH);
1387
1388
1389         TRACE("-- (%p)->(%s)\n", This, szPath);
1390         return S_OK;
1391 }
1392
1393 static ICOM_VTABLE(IShellFolder) sfdvt = 
1394 {       
1395         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1396         ISF_Desktop_fnQueryInterface,
1397         IShellFolder_fnAddRef,
1398         IShellFolder_fnRelease,
1399         ISF_Desktop_fnParseDisplayName,
1400         ISF_Desktop_fnEnumObjects,
1401         ISF_Desktop_fnBindToObject,
1402         IShellFolder_fnBindToStorage,
1403         IShellFolder_fnCompareIDs,
1404         IShellFolder_fnCreateViewObject,
1405         ISF_Desktop_fnGetAttributesOf,
1406         IShellFolder_fnGetUIObjectOf,
1407         ISF_Desktop_fnGetDisplayNameOf,
1408         IShellFolder_fnSetNameOf,
1409         IShellFolder_fnGetFolderPath
1410 };
1411
1412
1413 /***********************************************************************
1414 *   IShellFolder [MyComputer] implementation
1415 */
1416
1417 static struct ICOM_VTABLE(IShellFolder) sfmcvt;
1418
1419 /**************************************************************************
1420 *       ISF_MyComputer_Constructor
1421 */
1422 static IShellFolder * ISF_MyComputer_Constructor(void)
1423 {
1424         IGenericSFImpl *        sf;
1425
1426         sf=(IGenericSFImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IGenericSFImpl));
1427         sf->ref=1;
1428
1429         sf->lpvtbl = &sfmcvt;
1430         sf->lpvtblPersistFolder = &psfvt;
1431         sf->pclsid = (CLSID*)&CLSID_SFMyComp;
1432         sf->absPidl=_ILCreateMyComputer();      /* my qualified pidl */
1433
1434         TRACE("(%p)\n",sf);
1435
1436         shell32_ObjCount++;
1437         return (IShellFolder *)sf;
1438 }
1439
1440 /**************************************************************************
1441 *       ISF_MyComputer_fnParseDisplayName
1442 */
1443 static HRESULT WINAPI ISF_MyComputer_fnParseDisplayName(
1444         IShellFolder * iface,
1445         HWND hwndOwner,
1446         LPBC pbcReserved,
1447         LPOLESTR lpszDisplayName,
1448         DWORD *pchEaten,
1449         LPITEMIDLIST *ppidl,
1450         DWORD *pdwAttributes)
1451 {
1452         ICOM_THIS(IGenericSFImpl, iface);
1453
1454         HRESULT         hr = E_OUTOFMEMORY;
1455         LPCWSTR         szNext=NULL;
1456         WCHAR           szElement[MAX_PATH];
1457         CHAR            szTempA[MAX_PATH];
1458         LPITEMIDLIST    pidlTemp;
1459         
1460         TRACE("(%p)->(HWND=0x%08x,%p,%p=%s,%p,pidl=%p,%p)\n",
1461         This,hwndOwner,pbcReserved,lpszDisplayName,
1462         debugstr_w(lpszDisplayName),pchEaten,ppidl,pdwAttributes);
1463
1464         *ppidl = 0;
1465         if (pchEaten) *pchEaten = 0;    /* strange but like the original */
1466         
1467         if (PathIsRootW(lpszDisplayName))
1468         {
1469           szNext = GetNextElementW(lpszDisplayName, szElement, MAX_PATH);
1470           WideCharToLocal(szTempA, szElement, lstrlenW(szElement) + 1);
1471           pidlTemp = _ILCreateDrive(szTempA);
1472
1473           if (szNext && *szNext)
1474           {
1475             hr = SHELL32_ParseNextElement(hwndOwner, (IShellFolder*)This, &pidlTemp, (LPOLESTR)szNext, pchEaten, pdwAttributes);
1476           }
1477           else
1478           {
1479             hr = S_OK;
1480           }
1481           *ppidl = pidlTemp;
1482         }
1483
1484         TRACE("(%p)->(-- ret=0x%08lx)\n", This, hr);
1485
1486         return hr;      
1487 }
1488
1489 /**************************************************************************
1490 *               ISF_MyComputer_fnEnumObjects
1491 */
1492 static HRESULT WINAPI ISF_MyComputer_fnEnumObjects(
1493         IShellFolder * iface,
1494         HWND hwndOwner,
1495         DWORD dwFlags,
1496         LPENUMIDLIST* ppEnumIDList)
1497 {
1498         ICOM_THIS(IGenericSFImpl, iface);
1499
1500         TRACE("(%p)->(HWND=0x%08x flags=0x%08lx pplist=%p)\n",This,hwndOwner,dwFlags,ppEnumIDList);
1501
1502         *ppEnumIDList = NULL;
1503         *ppEnumIDList = IEnumIDList_Constructor (NULL, dwFlags, EIDL_MYCOMP);
1504
1505         TRACE("-- (%p)->(new ID List: %p)\n",This,*ppEnumIDList);
1506
1507         if(!*ppEnumIDList) return E_OUTOFMEMORY;
1508
1509         return S_OK;            
1510 }
1511
1512 /**************************************************************************
1513 *               ISF_MyComputer_fnBindToObject
1514 */
1515 static HRESULT WINAPI ISF_MyComputer_fnBindToObject( IShellFolder * iface, LPCITEMIDLIST pidl,
1516                         LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
1517 {
1518         ICOM_THIS(IGenericSFImpl, iface);
1519         GUID            const * clsid;
1520         char            xriid[50];
1521         IShellFolder    *pShellFolder, *pSubFolder;
1522         LPITEMIDLIST    pidltemp;
1523         
1524         WINE_StringFromCLSID(riid,xriid);
1525
1526         TRACE("(%p)->(pidl=%p,%p,\n\tIID:\t%s,%p)\n",This,pidl,pbcReserved,xriid,ppvOut);
1527
1528         *ppvOut = NULL;
1529
1530         if ((clsid=_ILGetGUIDPointer(pidl)) && !IsEqualIID(clsid, &IID_MyComputer))
1531         {
1532            if (!SUCCEEDED(SHELL32_CoCreateInitSF (This->absPidl, pidl, clsid, riid, (LPVOID*)&pShellFolder)))
1533            {
1534              return E_FAIL;
1535            }
1536         }
1537         else
1538         {
1539           if (!_ILIsDrive(pidl)) return E_INVALIDARG;
1540
1541           pidltemp = ILCloneFirst(pidl);
1542           pShellFolder = IShellFolder_Constructor((IShellFolder*)This, pidltemp);
1543           ILFree(pidltemp);
1544         }
1545
1546         if (_ILIsPidlSimple(pidl))      /* no sub folders */
1547         {
1548           *ppvOut = pShellFolder;
1549         }
1550         else                            /* go deeper */
1551         {
1552           IShellFolder_BindToObject(pShellFolder, ILGetNext(pidl), NULL, &IID_IShellFolder, (LPVOID)&pSubFolder);
1553           IShellFolder_Release(pShellFolder);
1554           *ppvOut = pSubFolder;
1555         }
1556
1557         TRACE("-- (%p) returning (%p)\n",This, *ppvOut);
1558
1559         return S_OK;
1560 }
1561
1562 /**************************************************************************
1563 *  ISF_MyComputer_fnGetAttributesOf
1564 */
1565 static HRESULT WINAPI ISF_MyComputer_fnGetAttributesOf(IShellFolder * iface,UINT cidl,LPCITEMIDLIST *apidl,DWORD *rgfInOut)
1566 {
1567         ICOM_THIS(IGenericSFImpl, iface);
1568
1569         GUID            const * clsid;
1570         DWORD           attributes;
1571         HRESULT         hr = S_OK;
1572
1573         TRACE("(%p)->(cidl=%d apidl=%p mask=0x%08lx)\n",This,cidl,apidl,*rgfInOut);
1574
1575         if ( (!cidl) || (!apidl) || (!rgfInOut))
1576           return E_INVALIDARG;
1577
1578         *rgfInOut = 0xffffffff;
1579
1580         while (cidl > 0 && *apidl)
1581         {
1582           pdump (*apidl);
1583
1584           if (_ILIsDrive(*apidl))
1585           {
1586             *rgfInOut &= 0xf0000144;
1587             goto next;
1588           }
1589           else if ((clsid=_ILGetGUIDPointer(*apidl)))
1590           {
1591             if (HCR_GetFolderAttributes(clsid, &attributes))
1592             {
1593               *rgfInOut &= attributes;
1594               goto next;
1595             }
1596           }
1597           hr = E_INVALIDARG;
1598
1599 next:     apidl++;
1600           cidl--;
1601         }
1602
1603         TRACE("-- result=0x%08lx\n",*rgfInOut);
1604         return hr;
1605 }
1606
1607 /**************************************************************************
1608 *       ISF_MyComputer_fnGetDisplayNameOf
1609 *
1610 * NOTES
1611 *       The desktopfolder creates only complete paths (SHGDN_FORPARSING).
1612 *       SHGDN_INFOLDER makes no sense.
1613 */
1614 static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf(
1615         IShellFolder * iface,
1616         LPCITEMIDLIST pidl,
1617         DWORD dwFlags,
1618         LPSTRRET strRet)
1619 {
1620         ICOM_THIS(IGenericSFImpl, iface);
1621
1622         char            szPath[MAX_PATH], szDrive[18];
1623         int             len = 0;
1624         BOOL            bSimplePidl;
1625                 
1626         TRACE("(%p)->(pidl=%p,0x%08lx,%p)\n",This,pidl,dwFlags,strRet);
1627         pdump(pidl);
1628         
1629         if(!strRet) return E_INVALIDARG;
1630         
1631         szPath[0]=0x00; szDrive[0]=0x00;
1632         
1633         
1634         bSimplePidl = _ILIsPidlSimple(pidl);
1635         
1636         if (_ILIsSpecialFolder(pidl))
1637         {
1638           /* take names of special folders only if its only this folder */
1639           if ( bSimplePidl )
1640           {
1641             _ILSimpleGetText(pidl, szPath, MAX_PATH); /* append my own path */
1642           }
1643         }
1644         else
1645         {
1646           if (!_ILIsDrive(pidl))
1647           {
1648             ERR("Wrong pidl type\n");
1649             return E_INVALIDARG;
1650           }
1651
1652           _ILSimpleGetText(pidl, szPath, MAX_PATH);     /* append my own path */
1653
1654           /* long view "lw_name (C:)" */
1655           if ( bSimplePidl && !(dwFlags & SHGDN_FORPARSING))
1656           {
1657             DWORD dwVolumeSerialNumber,dwMaximumComponetLength,dwFileSystemFlags;
1658
1659             GetVolumeInformationA(szPath,szDrive,12,&dwVolumeSerialNumber,&dwMaximumComponetLength,&dwFileSystemFlags,NULL,0);
1660             strcat (szDrive," (");
1661             strncat (szDrive, szPath, 2);
1662             strcat (szDrive,")");
1663             strcpy (szPath, szDrive);
1664           }
1665         }
1666         
1667         if (!bSimplePidl)       /* go deeper if needed */
1668         { 
1669           PathAddBackslashA(szPath);
1670           len = strlen(szPath);
1671
1672           if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild((IShellFolder*)This, pidl, dwFlags | SHGDN_FORPARSING, szPath + len, MAX_PATH - len)))
1673             return E_OUTOFMEMORY;
1674         }
1675         strRet->uType = STRRET_CSTRA;
1676         lstrcpynA(strRet->u.cStr, szPath, MAX_PATH);
1677
1678
1679         TRACE("-- (%p)->(%s)\n", This, szPath);
1680         return S_OK;
1681 }
1682
1683 static ICOM_VTABLE(IShellFolder) sfmcvt = 
1684 {       
1685         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1686         IShellFolder_fnQueryInterface,
1687         IShellFolder_fnAddRef,
1688         IShellFolder_fnRelease,
1689         ISF_MyComputer_fnParseDisplayName,
1690         ISF_MyComputer_fnEnumObjects,
1691         ISF_MyComputer_fnBindToObject,
1692         IShellFolder_fnBindToStorage,
1693         IShellFolder_fnCompareIDs,
1694         IShellFolder_fnCreateViewObject,
1695         ISF_MyComputer_fnGetAttributesOf,
1696         IShellFolder_fnGetUIObjectOf,
1697         ISF_MyComputer_fnGetDisplayNameOf,
1698         IShellFolder_fnSetNameOf,
1699         IShellFolder_fnGetFolderPath
1700 };
1701
1702
1703 /************************************************************************
1704  * ISFPersistFolder_QueryInterface (IUnknown)
1705  *
1706  */
1707 static HRESULT WINAPI ISFPersistFolder_QueryInterface(
1708         IPersistFolder *        iface,
1709         REFIID                  iid,
1710         LPVOID*                 ppvObj)
1711 {
1712         _ICOM_THIS_From_IPersistFolder(IGenericSFImpl, iface);
1713
1714         return IShellFolder_QueryInterface((IShellFolder*)This, iid, ppvObj);
1715 }
1716
1717 /************************************************************************
1718  * ISFPersistFolder_AddRef (IUnknown)
1719  *
1720  */
1721 static ULONG WINAPI ISFPersistFolder_AddRef(
1722         IPersistFolder *        iface)
1723 {
1724         _ICOM_THIS_From_IPersistFolder(IShellFolder, iface);
1725
1726         return IShellFolder_AddRef((IShellFolder*)This);
1727 }
1728
1729 /************************************************************************
1730  * ISFPersistFolder_Release (IUnknown)
1731  *
1732  */
1733 static ULONG WINAPI ISFPersistFolder_Release(
1734         IPersistFolder *        iface)
1735 {
1736         _ICOM_THIS_From_IPersistFolder(IGenericSFImpl, iface);
1737
1738         return IShellFolder_Release((IShellFolder*)This);
1739 }
1740
1741 /************************************************************************
1742  * ISFPersistFolder_GetClassID (IPersist)
1743  */
1744 static HRESULT WINAPI ISFPersistFolder_GetClassID(
1745         IPersistFolder *        iface,
1746         CLSID *                 lpClassId)
1747 {
1748         _ICOM_THIS_From_IPersistFolder(IGenericSFImpl, iface);
1749
1750         if (!lpClassId) return E_POINTER;
1751         *lpClassId = *This->pclsid;
1752
1753         return S_OK;
1754 }
1755
1756 /************************************************************************
1757  * ISFPersistFolder_Initialize (IPersistFolder)
1758  *
1759  * NOTES
1760  *  sMyPath is not set. Don't know how to handle in a non rooted environment.
1761  */
1762 static HRESULT WINAPI ISFPersistFolder_Initialize(
1763         IPersistFolder *        iface,
1764         LPCITEMIDLIST           pidl)
1765 {
1766         _ICOM_THIS_From_IPersistFolder(IGenericSFImpl, iface);
1767
1768         if(This->absPidl)
1769         {
1770           SHFree(This->absPidl);
1771           This->absPidl = NULL;
1772         }
1773         This->absPidl = ILClone(pidl);
1774         return S_OK;
1775 }
1776
1777 static ICOM_VTABLE(IPersistFolder) psfvt = 
1778 {
1779         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1780         ISFPersistFolder_QueryInterface,
1781         ISFPersistFolder_AddRef,
1782         ISFPersistFolder_Release,
1783         ISFPersistFolder_GetClassID,
1784         ISFPersistFolder_Initialize
1785 };
1786