More include optimisations and fixes.
[wine] / dlls / shell32 / shlfolder.c
1 /*
2  *      Shell Folder stuff
3  *
4  *      Copyright 1997  Marcus Meissner
5  *      Copyright 1998  Juergen Schmied
6  *
7  */
8
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "debug.h"
13 #include "winerror.h"
14
15 #include "wine/obj_base.h"
16 #include "wine/obj_dragdrop.h"
17 #include "shlguid.h"
18
19 #include "pidl.h"
20 #include "shlobj.h"
21 #include "shell32_main.h"
22
23 static HRESULT WINAPI IShellFolder_QueryInterface(LPSHELLFOLDER,REFIID,LPVOID*);
24 static ULONG WINAPI IShellFolder_AddRef(LPSHELLFOLDER);
25 static ULONG WINAPI IShellFolder_Release(LPSHELLFOLDER);
26 static HRESULT WINAPI IShellFolder_Initialize(LPSHELLFOLDER,LPCITEMIDLIST);
27 static HRESULT WINAPI IShellFolder_ParseDisplayName(LPSHELLFOLDER,HWND,LPBC,LPOLESTR,DWORD*,LPITEMIDLIST*,DWORD*);
28 static HRESULT WINAPI IShellFolder_EnumObjects(LPSHELLFOLDER,HWND,DWORD,LPENUMIDLIST*);
29 static HRESULT WINAPI IShellFolder_BindToObject(LPSHELLFOLDER,LPCITEMIDLIST,LPBC,REFIID,LPVOID*);
30 static HRESULT WINAPI IShellFolder_BindToStorage(LPSHELLFOLDER,LPCITEMIDLIST,LPBC,REFIID,LPVOID*);
31 static HRESULT WINAPI IShellFolder_CompareIDs(LPSHELLFOLDER,LPARAM,LPCITEMIDLIST,LPCITEMIDLIST);
32 static HRESULT WINAPI IShellFolder_CreateViewObject(LPSHELLFOLDER,HWND,REFIID,LPVOID*);
33 static HRESULT WINAPI IShellFolder_GetAttributesOf(LPSHELLFOLDER,UINT,LPCITEMIDLIST*,DWORD*);
34 static HRESULT WINAPI IShellFolder_GetUIObjectOf(LPSHELLFOLDER,HWND,UINT,LPCITEMIDLIST*,REFIID,UINT*,LPVOID*);
35 static HRESULT WINAPI IShellFolder_GetDisplayNameOf(LPSHELLFOLDER,LPCITEMIDLIST,DWORD,LPSTRRET);
36 static HRESULT WINAPI IShellFolder_SetNameOf(LPSHELLFOLDER,HWND,LPCITEMIDLIST,LPCOLESTR,DWORD,LPITEMIDLIST*);
37 static BOOL WINAPI IShellFolder_GetFolderPath(LPSHELLFOLDER,LPSTR,DWORD);
38
39 /***************************************************************************
40  * IDropTarget interface definition for the ShellFolder
41  */
42
43 typedef struct
44 {       ICOM_VTABLE(IDropTarget)* lpvtbl;
45         ULONG ref;
46 } ISFDropTarget;
47
48 static struct ICOM_VTABLE(IDropTarget) dtvt;
49
50
51 /****************************************************************************
52  * ISFDropTarget implementation
53  */
54
55 static IDropTarget * WINAPI ISFDropTarget_Constructor(void)
56 {
57         ISFDropTarget* sf;
58
59         sf = HeapAlloc(GetProcessHeap(), 0, sizeof(ISFDropTarget));
60
61         if (sf)
62         { sf->lpvtbl = &dtvt;
63           sf->ref    = 1;
64         }
65
66         return (IDropTarget *)sf;
67 }
68
69 static HRESULT WINAPI ISFDropTarget_QueryInterface(
70         IDropTarget *iface,
71         REFIID riid,
72         LPVOID *ppvObj)
73 {
74         ICOM_THIS(ISFDropTarget,iface);
75
76         char    xriid[50];
77         WINE_StringFromCLSID((LPCLSID)riid,xriid);
78
79         TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
80
81         if ( !This || !ppvObj)
82           return E_INVALIDARG;
83
84         *ppvObj = NULL;
85
86         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
87         { *ppvObj = This; 
88         }
89         else if(IsEqualIID(riid, &IID_IDropTarget))  /*IShellFolder*/
90         {    *ppvObj = (ISFDropTarget*)This;
91         }   
92
93         if(*ppvObj)
94         { IDropTarget_AddRef((ISFDropTarget*)*ppvObj);
95           TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
96           return S_OK;
97         }
98
99         TRACE(shell,"-- Interface: E_NOINTERFACE\n");
100
101         return E_NOINTERFACE;
102 }
103
104 static ULONG WINAPI ISFDropTarget_AddRef( IDropTarget *iface)
105 {
106         ICOM_THIS(ISFDropTarget,iface);
107
108         TRACE(shell,"(%p)->(count=%lu)\n",This,This->ref);
109
110         shell32_ObjCount++;
111
112         return ++(This->ref);
113 }
114
115 static ULONG WINAPI ISFDropTarget_Release( IDropTarget *iface)
116 {
117         ICOM_THIS(ISFDropTarget,iface);
118
119         shell32_ObjCount--;
120
121         if (!--(This->ref)) 
122         { TRACE(shell,"-- destroying ISFDropTarget (%p)\n",This);
123           HeapFree(GetProcessHeap(),0,This);
124           return 0;
125         }
126         return This->ref;
127 }
128
129 static HRESULT WINAPI ISFDropTarget_DragEnter(
130         IDropTarget     *iface,
131         IDataObject     *pDataObject,
132         DWORD           grfKeyState,
133         POINTL          pt,
134         DWORD           *pdwEffect)
135 {       
136
137         ICOM_THIS(ISFDropTarget,iface);
138
139         FIXME(shell, "Stub: This=%p, DataObject=%p\n",This,pDataObject);
140
141         return E_NOTIMPL;
142 }
143
144 static HRESULT WINAPI ISFDropTarget_DragOver(
145         IDropTarget     *iface,
146         DWORD           grfKeyState,
147         POINTL          pt,
148         DWORD           *pdwEffect)
149 {
150         ICOM_THIS(ISFDropTarget,iface);
151
152         FIXME(shell, "Stub: This=%p\n",This);
153
154         return E_NOTIMPL;
155 }
156
157 static HRESULT WINAPI ISFDropTarget_DragLeave(
158         IDropTarget     *iface)
159 {
160         ICOM_THIS(ISFDropTarget,iface);
161
162         FIXME(shell, "Stub: This=%p\n",This);
163
164         return E_NOTIMPL;
165 }
166
167 static HRESULT WINAPI ISFDropTarget_Drop(
168         IDropTarget     *iface,
169         IDataObject*    pDataObject,
170         DWORD           grfKeyState,
171         POINTL          pt,
172         DWORD           *pdwEffect)
173 {
174         ICOM_THIS(ISFDropTarget,iface);
175
176         FIXME(shell, "Stub: This=%p\n",This);
177
178         return E_NOTIMPL;
179 }
180
181 static struct ICOM_VTABLE(IDropTarget) dtvt = 
182 {
183         ISFDropTarget_QueryInterface,
184         ISFDropTarget_AddRef,
185         ISFDropTarget_Release,
186         ISFDropTarget_DragEnter,
187         ISFDropTarget_DragOver,
188         ISFDropTarget_DragLeave,
189         ISFDropTarget_Drop
190 };
191
192 /***************************************************************************
193  *  GetNextElement (internal function)
194  *
195  * gets a part of a string till the first backslash
196  *
197  * PARAMETERS
198  *  pszNext [IN] string to get the element from
199  *  pszOut  [IN] pointer to buffer whitch receives string
200  *  dwOut   [IN] length of pszOut
201  *
202  *  RETURNS
203  *    LPSTR pointer to first, not yet parsed char
204  */
205 LPSTR GetNextElement(LPSTR pszNext,LPSTR pszOut,DWORD dwOut)
206 {       LPSTR   pszTail = pszNext;
207         DWORD dwCopy;
208         TRACE(shell,"(%s %p 0x%08lx)\n",debugstr_a(pszNext),pszOut,dwOut);
209
210         if(!pszNext || !*pszNext)
211           return NULL;
212
213         while(*pszTail && (*pszTail != '\\'))
214         { pszTail++;
215         }
216         dwCopy=((LPBYTE)pszTail-(LPBYTE)pszNext)/sizeof(CHAR)+1;
217         lstrcpynA(pszOut, pszNext, (dwOut<dwCopy)? dwOut : dwCopy);
218
219         if(*pszTail)
220         {  pszTail++;
221         }
222
223         TRACE(shell,"--(%s %s 0x%08lx)\n",debugstr_a(pszNext),debugstr_a(pszOut),dwOut);
224         return pszTail;
225 }
226
227 /***********************************************************************
228 *   IShellFolder implementation
229 */
230 static struct IShellFolder_VTable sfvt = 
231 { IShellFolder_QueryInterface,
232   IShellFolder_AddRef,
233   IShellFolder_Release,
234   IShellFolder_ParseDisplayName,
235   IShellFolder_EnumObjects,
236   IShellFolder_BindToObject,
237   IShellFolder_BindToStorage,
238   IShellFolder_CompareIDs,
239   IShellFolder_CreateViewObject,
240   IShellFolder_GetAttributesOf,
241   IShellFolder_GetUIObjectOf,
242   IShellFolder_GetDisplayNameOf,
243   IShellFolder_SetNameOf,
244   IShellFolder_GetFolderPath
245 };
246 /**************************************************************************
247 *         IShellFolder_Constructor
248 */
249
250 LPSHELLFOLDER IShellFolder_Constructor(LPSHELLFOLDER pParent,LPITEMIDLIST pidl) 
251 {       LPSHELLFOLDER    sf;
252         DWORD dwSize=0;
253         sf=(LPSHELLFOLDER)HeapAlloc(GetProcessHeap(),0,sizeof(IShellFolder));
254         sf->ref=1;
255         sf->lpvtbl=&sfvt;
256         sf->sMyPath=NULL;       /* path of the folder */
257         sf->pMyPidl=NULL;       /* my qualified pidl */
258
259         TRACE(shell,"(%p)->(parent=%p, pidl=%p)\n",sf,pParent, pidl);
260         pdump(pidl);
261                 
262         /* keep a copy of the pidl in the instance*/
263         sf->mpidl = ILClone(pidl);              /* my short pidl */
264         
265         if(sf->mpidl)                           /* do we have a pidl? */
266         { dwSize = 0;
267           if(pParent->sMyPath)                  /* get the size of the parents path */
268           { dwSize += strlen(pParent->sMyPath) ;
269             TRACE(shell,"-- (%p)->(parent's path=%s)\n",sf, debugstr_a(pParent->sMyPath));
270           }   
271           dwSize += _ILGetFolderText(sf->mpidl,NULL,0); /* add the size of the foldername*/
272           sf->sMyPath = SHAlloc(dwSize+2);              /* '\0' and backslash */
273           if(sf->sMyPath)
274           { int len;
275             *(sf->sMyPath)=0x00;
276             if(pParent->sMyPath)                        /* if the parent has a path, get it*/
277             {  strcpy(sf->sMyPath, pParent->sMyPath);
278                PathAddBackslashA (sf->sMyPath);
279             }
280             sf->pMyPidl = ILCombine(pParent->pMyPidl, pidl);
281             len = strlen(sf->sMyPath);
282             _ILGetFolderText(sf->mpidl, sf->sMyPath+len, dwSize-len);
283             TRACE(shell,"-- (%p)->(my pidl=%p, my path=%s)\n",sf, sf->pMyPidl,debugstr_a(sf->sMyPath));
284             pdump (sf->pMyPidl);
285           }
286         }
287         shell32_ObjCount++;
288         return sf;
289 }
290 /**************************************************************************
291 *  IShellFolder::QueryInterface
292 * PARAMETERS
293 *  REFIID riid,        //[in ] Requested InterfaceID
294 *  LPVOID* ppvObject)  //[out] Interface* to hold the result
295 */
296 static HRESULT WINAPI IShellFolder_QueryInterface(
297   LPSHELLFOLDER this, REFIID riid, LPVOID *ppvObj)
298 {       char    xriid[50];
299         WINE_StringFromCLSID((LPCLSID)riid,xriid);
300         TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",this,xriid,ppvObj);
301
302         *ppvObj = NULL;
303
304         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
305         { *ppvObj = this; 
306         }
307         else if(IsEqualIID(riid, &IID_IShellFolder))  /*IShellFolder*/
308         {    *ppvObj = (IShellFolder*)this;
309         }   
310
311         if(*ppvObj)
312         { (*(LPSHELLFOLDER*)ppvObj)->lpvtbl->fnAddRef(this);    
313           TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
314           return S_OK;
315         }
316         TRACE(shell,"-- Interface: E_NOINTERFACE\n");
317         return E_NOINTERFACE;
318 }
319
320 /**************************************************************************
321 *  IShellFolder::AddRef
322 */
323
324 static ULONG WINAPI IShellFolder_AddRef(LPSHELLFOLDER this)
325 {       TRACE(shell,"(%p)->(count=%lu)\n",this,this->ref);
326         shell32_ObjCount++;
327         return ++(this->ref);
328 }
329
330 /**************************************************************************
331  *  IShellFolder_Release
332  */
333 static ULONG WINAPI IShellFolder_Release(LPSHELLFOLDER this) 
334 {       TRACE(shell,"(%p)->(count=%lu)\n",this,this->ref);
335
336         shell32_ObjCount--;
337         if (!--(this->ref)) 
338         { TRACE(shell,"-- destroying IShellFolder(%p)\n",this);
339
340           if (pdesktopfolder==this)
341           { pdesktopfolder=NULL;
342             TRACE(shell,"-- destroyed IShellFolder(%p) was Desktopfolder\n",this);
343           }
344           if(this->pMyPidl)
345           { SHFree(this->pMyPidl);
346           }
347           if(this->mpidl)
348           { SHFree(this->mpidl);
349           }
350           if(this->sMyPath)
351           { SHFree(this->sMyPath);
352           }
353
354           HeapFree(GetProcessHeap(),0,this);
355
356           return 0;
357         }
358         return this->ref;
359 }
360 /**************************************************************************
361 *               IShellFolder_ParseDisplayName
362 * PARAMETERS
363 *  HWND          hwndOwner,      //[in ] Parent window for any message's
364 *  LPBC          pbc,            //[in ] reserved
365 *  LPOLESTR      lpszDisplayName,//[in ] "Unicode" displayname.
366 *  ULONG*        pchEaten,       //[out] (unicode) characters processed
367 *  LPITEMIDLIST* ppidl,          //[out] complex pidl to item
368 *  ULONG*        pdwAttributes   //[out] items attributes
369 *
370 * FIXME: 
371 *    pdwAttributes: not used
372 */
373 static HRESULT WINAPI IShellFolder_ParseDisplayName(
374         LPSHELLFOLDER this,
375         HWND hwndOwner,
376         LPBC pbcReserved,
377         LPOLESTR lpszDisplayName,
378         DWORD *pchEaten,
379         LPITEMIDLIST *ppidl,
380         DWORD *pdwAttributes)
381 {       HRESULT        hr=E_OUTOFMEMORY;
382         LPITEMIDLIST   pidlFull=NULL, pidlTemp = NULL, pidlOld = NULL;
383         LPSTR          pszNext=NULL;
384         CHAR           szTemp[MAX_PATH],szElement[MAX_PATH];
385         BOOL         bIsFile;
386        
387         TRACE(shell,"(%p)->(HWND=0x%08x,%p,%p=%s,%p,pidl=%p,%p)\n",
388                 this,hwndOwner,pbcReserved,lpszDisplayName,
389                 debugstr_w(lpszDisplayName),pchEaten,ppidl,pdwAttributes);
390
391         { hr = E_FAIL;
392           WideCharToLocal(szTemp, lpszDisplayName, lstrlenW(lpszDisplayName) + 1);
393           if(szTemp[0])
394           { if (strcmp(szTemp,"Desktop")==0)
395             { pidlFull = _ILCreateDesktop();
396             }
397             else if (strcmp(szTemp,"My Computer")==0)
398             { pidlFull = _ILCreateMyComputer();
399             }
400             else
401             { if (!PathIsRootA(szTemp))
402               { if (this->sMyPath && strlen (this->sMyPath))
403                 { if (strcmp(this->sMyPath,"My Computer"))
404                   { strcpy (szElement,this->sMyPath);
405                     PathAddBackslashA (szElement);
406                     strcat (szElement, szTemp);
407                     strcpy (szTemp, szElement);
408                   }
409                 }
410               }
411               
412               /* check if the lpszDisplayName is Folder or File*/
413               bIsFile = ! (GetFileAttributesA(szTemp) & FILE_ATTRIBUTE_DIRECTORY);
414               pszNext = GetNextElement(szTemp, szElement, MAX_PATH);
415
416               pidlFull = _ILCreateMyComputer();
417               pidlTemp = _ILCreateDrive(szElement);                     
418               pidlOld = pidlFull;
419               pidlFull = ILCombine(pidlFull,pidlTemp);
420               SHFree(pidlOld);
421   
422               if(pidlFull)
423               { while((pszNext=GetNextElement(pszNext, szElement, MAX_PATH)))
424                 { if(!*pszNext && bIsFile)
425                   { pidlTemp = _ILCreateValue(NULL, szElement);         /* FIXME: shortname */
426                   }
427                   else                          
428                   { pidlTemp = _ILCreateFolder(NULL, szElement);        /* FIXME: shortname */
429                   }
430                   pidlOld = pidlFull;
431                   pidlFull = ILCombine(pidlFull,pidlTemp);
432                   SHFree(pidlOld);
433                 }
434                 hr = S_OK;
435               }
436             }
437           }
438         }
439         *ppidl = pidlFull;
440         return hr;
441 }
442
443 /**************************************************************************
444 *               IShellFolder_EnumObjects
445 * PARAMETERS
446 *  HWND          hwndOwner,    //[in ] Parent Window
447 *  DWORD         grfFlags,     //[in ] SHCONTF enumeration mask
448 *  LPENUMIDLIST* ppenumIDList  //[out] IEnumIDList interface
449 */
450 static HRESULT WINAPI IShellFolder_EnumObjects(
451         LPSHELLFOLDER this,
452         HWND hwndOwner,
453         DWORD dwFlags,
454         LPENUMIDLIST* ppEnumIDList)
455 {       TRACE(shell,"(%p)->(HWND=0x%08x flags=0x%08lx pplist=%p)\n",this,hwndOwner,dwFlags,ppEnumIDList);
456
457         *ppEnumIDList = NULL;
458         *ppEnumIDList = IEnumIDList_Constructor (this->sMyPath, dwFlags);
459         TRACE(shell,"-- (%p)->(new ID List: %p)\n",this,*ppEnumIDList);
460         if(!*ppEnumIDList)
461         { return E_OUTOFMEMORY;
462         }
463         return S_OK;            
464 }
465 /**************************************************************************
466  *  IShellFolder_Initialize()
467  *  IPersistFolder Method
468  */
469 static HRESULT WINAPI IShellFolder_Initialize( LPSHELLFOLDER this,LPCITEMIDLIST pidl)
470 {       TRACE(shell,"(%p)->(pidl=%p)\n",this,pidl);
471
472         if(this->pMyPidl)
473         { SHFree(this->pMyPidl);
474           this->pMyPidl = NULL;
475         }
476         this->pMyPidl = ILClone(pidl);
477         return S_OK;
478 }
479
480 /**************************************************************************
481 *               IShellFolder_BindToObject
482 * PARAMETERS
483 *  LPCITEMIDLIST pidl,       //[in ] complex pidl to open
484 *  LPBC          pbc,        //[in ] reserved
485 *  REFIID        riid,       //[in ] Initial Interface
486 *  LPVOID*       ppvObject   //[out] Interface*
487 */
488 static HRESULT WINAPI IShellFolder_BindToObject( LPSHELLFOLDER this, LPCITEMIDLIST pidl,
489                         LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
490 {       char            xriid[50];
491         HRESULT       hr;
492         LPSHELLFOLDER pShellFolder;
493         
494         WINE_StringFromCLSID(riid,xriid);
495
496         TRACE(shell,"(%p)->(pidl=%p,%p,\n\tIID:%s,%p)\n",this,pidl,pbcReserved,xriid,ppvOut);
497
498         *ppvOut = NULL;
499
500         pShellFolder = IShellFolder_Constructor(this, pidl);
501
502         if(!pShellFolder)
503           return E_OUTOFMEMORY;
504
505         hr = pShellFolder->lpvtbl->fnQueryInterface(pShellFolder, riid, ppvOut);
506         pShellFolder->lpvtbl->fnRelease(pShellFolder);
507         TRACE(shell,"-- (%p)->(interface=%p)\n",this, ppvOut);
508         return hr;
509 }
510
511 /**************************************************************************
512 *  IShellFolder_BindToStorage
513 * PARAMETERS
514 *  LPCITEMIDLIST pidl,       //[in ] complex pidl to store
515 *  LPBC          pbc,        //[in ] reserved
516 *  REFIID        riid,       //[in ] Initial storage interface 
517 *  LPVOID*       ppvObject   //[out] Interface* returned
518 */
519 static HRESULT WINAPI IShellFolder_BindToStorage(LPSHELLFOLDER this,
520             LPCITEMIDLIST pidl,LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
521 {       char xriid[50];
522         WINE_StringFromCLSID(riid,xriid);
523
524         FIXME(shell,"(%p)->(pidl=%p,%p,\n\tIID:%s,%p) stub\n",this,pidl,pbcReserved,xriid,ppvOut);
525
526         *ppvOut = NULL;
527         return E_NOTIMPL;
528 }
529
530 /**************************************************************************
531 *  IShellFolder_CompareIDs
532 *
533 * PARMETERS
534 *  LPARAM        lParam, //[in ] Column?
535 *  LPCITEMIDLIST pidl1,  //[in ] simple pidl
536 *  LPCITEMIDLIST pidl2)  //[in ] simple pidl
537 *
538 * NOTES
539 *   Special case - If one of the items is a Path and the other is a File,
540 *   always make the Path come before the File.
541 *
542 * FIXME
543 *  we have to handle simple pidl's only (?)
544 */
545 static HRESULT WINAPI  IShellFolder_CompareIDs(LPSHELLFOLDER this,
546                  LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) 
547 { CHAR szString1[MAX_PATH] = "";
548   CHAR szString2[MAX_PATH] = "";
549   int   nReturn;
550   LPCITEMIDLIST  pidlTemp1 = pidl1, pidlTemp2 = pidl2;
551
552   TRACE(shell,"(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n",this,lParam,pidl1,pidl2);
553   pdump (pidl1);
554   pdump (pidl2);
555
556   if (!pidl1 && !pidl2)
557     return 0;
558   if (!pidl1)   /* Desktop < anything */
559     return -1;
560   if (!pidl2)
561     return 1;
562   
563   /* get the last item in each list */
564   while((ILGetNext(pidlTemp1))->mkid.cb)
565     pidlTemp1 = ILGetNext(pidlTemp1);
566   while((ILGetNext(pidlTemp2))->mkid.cb)
567     pidlTemp2 = ILGetNext(pidlTemp2);
568
569   /* at this point, both pidlTemp1 and pidlTemp2 point to the last item in the list */
570   if(_ILIsValue(pidlTemp1) != _ILIsValue(pidlTemp2))
571   { if(_ILIsValue(pidlTemp1))
572       return 1;
573    return -1;
574   }
575
576   _ILGetDrive( pidl1,szString1,sizeof(szString1));
577   _ILGetDrive( pidl2,szString1,sizeof(szString2));
578   nReturn = strcasecmp(szString1, szString2);
579
580   if(nReturn)
581     return nReturn;
582
583   _ILGetFolderText( pidl1,szString1,sizeof(szString1));
584   _ILGetFolderText( pidl2,szString2,sizeof(szString2));
585   nReturn = strcasecmp(szString1, szString2);
586
587   if(nReturn)
588     return nReturn;
589
590   _ILGetValueText(pidl1,szString1,sizeof(szString1));
591   _ILGetValueText(pidl2,szString2,sizeof(szString2));
592   return strcasecmp(szString1, szString2);
593 }
594
595 /**************************************************************************
596 *         IShellFolder_CreateViewObject
597 * Creates an View Object representing the ShellFolder
598 *  IShellView / IShellBrowser / IContextMenu
599 *
600 * PARAMETERS
601 *  HWND    hwndOwner,  // Handle of owner window
602 *  REFIID  riid,       // Requested initial interface
603 *  LPVOID* ppvObject)  // Resultant interface*
604 *
605 * NOTES
606 *  the same as SHCreateShellFolderViewEx ???
607 */
608 static HRESULT WINAPI IShellFolder_CreateViewObject( LPSHELLFOLDER this,
609                  HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
610 {       LPSHELLVIEW pShellView;
611         char    xriid[50];
612         HRESULT       hr;
613
614         WINE_StringFromCLSID(riid,xriid);
615         TRACE(shell,"(%p)->(hwnd=0x%x,\n\tIID:\t%s,%p)\n",this,hwndOwner,xriid,ppvOut);
616         
617         *ppvOut = NULL;
618
619         pShellView = IShellView_Constructor(this, this->mpidl);
620
621         if(!pShellView)
622           return E_OUTOFMEMORY;
623           
624         hr = pShellView->lpvtbl->fnQueryInterface(pShellView, riid, ppvOut);
625         pShellView->lpvtbl->fnRelease(pShellView);
626         TRACE(shell,"-- (%p)->(interface=%p)\n",this, ppvOut);
627         return hr; 
628 }
629
630 /**************************************************************************
631 *  IShellFolder_GetAttributesOf
632 *
633 * PARAMETERS
634 *  UINT            cidl,     //[in ] num elements in pidl array
635 +  LPCITEMIDLIST*  apidl,    //[in ] simple pidl array 
636 *  ULONG*          rgfInOut) //[out] result array  
637 *
638 * FIXME: quick hack
639 *  Note: rgfInOut is documented as being an array of ULONGS.
640 *  This does not seem to be the case. Testing this function using the shell to 
641 *  call it with cidl > 1 (by deleting multiple items) reveals that the shell
642 *  passes ONE element in the array and writing to further elements will
643 *  cause the shell to fail later.
644 */
645 static HRESULT WINAPI IShellFolder_GetAttributesOf(LPSHELLFOLDER this,UINT cidl,LPCITEMIDLIST *apidl,DWORD *rgfInOut)
646 { LPCITEMIDLIST * pidltemp;
647   DWORD i;
648
649   TRACE(shell,"(%p)->(%d,%p,%p)\n",this,cidl,apidl,rgfInOut);
650
651   if ((! cidl )| (!apidl) | (!rgfInOut))
652     return E_INVALIDARG;
653
654   pidltemp=apidl;
655   *rgfInOut = 0x00;
656   i=cidl;
657
658   TRACE(shell,"-- mask=0x%08lx\n",*rgfInOut);
659   
660   do
661   { if (*pidltemp)
662     { pdump (*pidltemp);
663       if (_ILIsDesktop( *pidltemp))
664       { *rgfInOut |= ( SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANLINK );
665       }
666       else if (_ILIsMyComputer( *pidltemp))
667       { *rgfInOut |= ( SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR
668                         | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK );
669       }
670       else if (_ILIsDrive( *pidltemp))
671       { *rgfInOut |= ( SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM  | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR  | 
672                         SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANLINK );
673       }
674       else if (_ILIsFolder( *pidltemp))
675       { *rgfInOut |= ( SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_CAPABILITYMASK );
676       }
677       else if (_ILIsValue( *pidltemp))
678       { *rgfInOut |= (SFGAO_FILESYSTEM | SFGAO_CAPABILITYMASK );
679       }
680     }
681     pidltemp++;
682     cidl--;
683   } while (cidl > 0 && *pidltemp);
684
685   return S_OK;
686 }
687 /**************************************************************************
688 *  IShellFolder_GetUIObjectOf
689 *
690 * PARAMETERS
691 *  HWND           hwndOwner, //[in ] Parent window for any output
692 *  UINT           cidl,      //[in ] array size
693 *  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
694 *  REFIID         riid,      //[in ] Requested Interface
695 *  UINT*          prgfInOut, //[   ] reserved 
696 *  LPVOID*        ppvObject) //[out] Resulting Interface
697 *
698 * NOTES
699 *  This function gets asked to return "view objects" for one or more (multiple select)
700 *  items:
701 *  The viewobject typically is an COM object with one of the following interfaces:
702 *  IExtractIcon,IDataObject,IContextMenu
703 *  In order to support icon positions in the default Listview your DataObject
704 *  must implement the SetData method (in addition to GetData :) - the shell passes
705 *  a barely documented "Icon positions" structure to SetData when the drag starts,
706 *  and GetData's it if the drop is in another explorer window that needs the positions.
707 */
708 static HRESULT WINAPI IShellFolder_GetUIObjectOf( 
709   LPSHELLFOLDER this,
710   HWND        hwndOwner,
711   UINT        cidl,
712   LPCITEMIDLIST * apidl, 
713   REFIID        riid, 
714   UINT        *  prgfInOut,
715   LPVOID        * ppvOut)
716 {       
717         char            xclsid[50];
718         LPITEMIDLIST    pidl;
719         LPUNKNOWN       pObj = NULL; 
720
721         WINE_StringFromCLSID(riid,xclsid);
722
723         TRACE(shell,"(%p)->(%u,%u,apidl=%p,\n\tIID:%s,%p,%p)\n",
724           this,hwndOwner,cidl,apidl,xclsid,prgfInOut,ppvOut);
725
726         *ppvOut = NULL;
727
728         if(IsEqualIID(riid, &IID_IContextMenu))
729         { 
730           if(cidl < 1)
731             return E_INVALIDARG;
732
733           pObj  = (LPUNKNOWN)IContextMenu_Constructor(this, apidl, cidl);
734         }
735         else if (IsEqualIID(riid, &IID_IDataObject))
736         { 
737           if (cidl < 1)
738             return(E_INVALIDARG);
739
740           pObj = (LPUNKNOWN)IDataObject_Constructor (hwndOwner, this, apidl, cidl);
741         }
742         else if(IsEqualIID(riid, &IID_IExtractIcon))
743         { 
744           if (cidl != 1)
745             return(E_INVALIDARG);
746
747           pidl = ILCombine(this->pMyPidl,apidl[0]);
748           pObj = (LPUNKNOWN)IExtractIcon_Constructor( pidl );
749           SHFree(pidl);
750         } 
751         else if (IsEqualIID(riid, &IID_IDropTarget))
752         { 
753           if (cidl < 1)
754             return(E_INVALIDARG);
755
756           pObj = (LPUNKNOWN)ISFDropTarget_Constructor();
757         }
758         else
759         { 
760           ERR(shell,"(%p)->E_NOINTERFACE\n",this);
761           return E_NOINTERFACE;
762         }
763
764         if(!pObj)
765           return E_OUTOFMEMORY;
766
767         *ppvOut = pObj;
768         return S_OK;
769 }
770 /**************************************************************************
771 *  IShellFolder_GetDisplayNameOf
772 *  Retrieves the display name for the specified file object or subfolder
773 *
774 * PARAMETERS
775 *  LPCITEMIDLIST pidl,    //[in ] complex pidl to item
776 *  DWORD         dwFlags, //[in ] SHGNO formatting flags
777 *  LPSTRRET      lpName)  //[out] Returned display name
778 *
779 * FIXME
780 *  if the name is in the pidl the ret value should be a STRRET_OFFSET
781 */
782 #define GET_SHGDN_FOR(dwFlags)         ((DWORD)dwFlags & (DWORD)0x0000FF00)
783 #define GET_SHGDN_RELATION(dwFlags)    ((DWORD)dwFlags & (DWORD)0x000000FF)
784
785 static HRESULT WINAPI IShellFolder_GetDisplayNameOf( LPSHELLFOLDER this, LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET lpName)
786 {       CHAR    szText[MAX_PATH];
787         CHAR    szTemp[MAX_PATH];
788         CHAR    szSpecial[MAX_PATH];
789         CHAR    szDrive[MAX_PATH];
790         DWORD   dwVolumeSerialNumber,dwMaximumComponetLength,dwFileSystemFlags;
791         LPITEMIDLIST    pidlTemp=NULL;
792         BOOL    bSimplePidl=FALSE;
793                 
794         TRACE(shell,"(%p)->(pidl=%p,0x%08lx,%p)\n",this,pidl,dwFlags,lpName);
795         pdump(pidl);
796         
797         szSpecial[0]=0x00; 
798         szDrive[0]=0x00;
799         szText[0]=0x00;
800         szTemp[0]=0x00;
801         
802         /* test if simple(relative) or complex(absolute) pidl */
803         pidlTemp = ILGetNext(pidl);
804         if (pidlTemp && pidlTemp->mkid.cb==0x00)
805         { bSimplePidl = TRUE;
806           TRACE(shell,"-- simple pidl\n");
807         }
808
809         if (_ILIsDesktop( pidl))
810         { strcpy (szText,"Desktop");
811         }       
812         else
813         { if (_ILIsMyComputer(pidl))
814           { _ILGetItemText(pidl, szSpecial, MAX_PATH);
815             pidl = ILGetNext(pidl);
816           }
817
818           if (_ILIsDrive(pidl))
819           { _ILGetDrive( pidl, szTemp, MAX_PATH);
820
821             if ( dwFlags==SHGDN_NORMAL || dwFlags==SHGDN_INFOLDER)      /* like "A1-dos (C:)" */
822             { GetVolumeInformationA(szTemp,szDrive,MAX_PATH,&dwVolumeSerialNumber,&dwMaximumComponetLength,&dwFileSystemFlags,NULL,0);
823               szTemp[2]=0x00;                                           /* overwrite '\' */
824               strcat (szDrive," (");
825               strcat (szDrive,szTemp);
826               strcat (szDrive,")"); 
827             }
828             else                                                        /* like "C:\" */
829             {  PathAddBackslashA (szTemp);
830                strcpy(szDrive,szTemp);
831             }
832           }
833
834                 
835           switch(dwFlags)
836           { case SHGDN_NORMAL:                          /* 0x0000 */
837               _ILGetPidlPath( pidl, szText, MAX_PATH);
838               break;
839
840             case SHGDN_INFOLDER | SHGDN_FORPARSING:     /* 0x8001 */
841             case SHGDN_INFOLDER:                        /* 0x0001 */
842               pidlTemp = ILFindLastID(pidl);
843               if (pidlTemp)
844               { _ILGetItemText( pidlTemp, szText, MAX_PATH);
845               }
846               break;                            
847
848             case SHGDN_FORPARSING:                      /* 0x8000 */
849               if (bSimplePidl)
850               { /* if the IShellFolder has parents, get the path from the
851                 parent and add the ItemName*/
852                 szText[0]=0x00;
853                 if (this->sMyPath && strlen (this->sMyPath))
854                 { if (strcmp(this->sMyPath,"My Computer"))
855                   { strcpy (szText,this->sMyPath);
856                     PathAddBackslashA (szText);
857                   }
858                 }
859                 pidlTemp = ILFindLastID(pidl);
860                 if (pidlTemp)
861                 { _ILGetItemText( pidlTemp, szTemp, MAX_PATH );
862                 } 
863                 strcat(szText,szTemp);
864               }
865               else      /* if the pidl is absolute, get everything from the pidl*/                                      
866               { _ILGetPidlPath( pidl, szText, MAX_PATH);
867               }
868               break;
869             default:
870               TRACE(shell,"--- wrong flags=%lx\n", dwFlags);
871               return E_INVALIDARG;
872           }
873           if ((szText[0]==0x00 && szDrive[0]!=0x00)|| (bSimplePidl && szDrive[0]!=0x00))
874           { strcpy(szText,szDrive);
875           }
876           if (szText[0]==0x00 && szSpecial[0]!=0x00)
877           { strcpy(szText,szSpecial);
878           }
879         }
880
881         TRACE(shell,"-- (%p)->(%s)\n",this,szText);
882
883         if(!(lpName))
884         {  return E_OUTOFMEMORY;
885         }
886         lpName->uType = STRRET_CSTRA;   
887         strcpy(lpName->u.cStr,szText);
888         return S_OK;
889 }
890
891 /**************************************************************************
892 *  IShellFolder_SetNameOf
893 *  Changes the name of a file object or subfolder, possibly changing its item
894 *  identifier in the process.
895 *
896 * PARAMETERS
897 *  HWND          hwndOwner,  //[in ] Owner window for output
898 *  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
899 *  LPCOLESTR     lpszName,   //[in ] the items new display name
900 *  DWORD         dwFlags,    //[in ] SHGNO formatting flags
901 *  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
902 */
903 static HRESULT WINAPI IShellFolder_SetNameOf(
904         LPSHELLFOLDER this,
905                 HWND hwndOwner, 
906     LPCITEMIDLIST pidl, /*simple pidl*/
907     LPCOLESTR lpName, 
908     DWORD dw, 
909     LPITEMIDLIST *pPidlOut)
910 {  FIXME(shell,"(%p)->(%u,pidl=%p,%s,%lu,%p),stub!\n",
911           this,hwndOwner,pidl,debugstr_w(lpName),dw,pPidlOut);
912          return E_NOTIMPL;
913 }
914 /**************************************************************************
915 *  IShellFolder_GetFolderPath
916 *  FIXME: drive not included
917 */
918 static BOOL WINAPI IShellFolder_GetFolderPath(LPSHELLFOLDER this, LPSTR lpszOut, DWORD dwOutSize)
919 {       DWORD   dwSize;
920
921         TRACE(shell,"(%p)->(%p %lu)\n",this, lpszOut, dwOutSize);
922         if (!lpszOut)
923         { return FALSE;
924         }
925     
926         *lpszOut=0;
927
928         if (! this->sMyPath)
929           return FALSE;
930           
931         dwSize = strlen (this->sMyPath) +1;
932         if ( dwSize > dwOutSize)
933           return FALSE;
934         strcpy(lpszOut, this->sMyPath);
935
936         TRACE(shell,"-- (%p)->(return=%s)\n",this, lpszOut);
937         return TRUE;
938 }
939
940