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