- sorted API by groups
[wine] / dlls / shell32 / enumidlist.c
1 /*
2  *      IEnumIDList
3  *
4  *      Copyright 1998  Juergen Schmied <juergen.schmied@metronet.de>
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include "debug.h"
10 #include "wine/obj_base.h"
11 #include "winerror.h"
12
13 #include "pidl.h"
14 #include "shlguid.h"
15 #include "shell32_main.h"
16
17 /* IEnumIDList Implementation */
18 static HRESULT WINAPI IEnumIDList_QueryInterface(LPENUMIDLIST,REFIID,LPVOID*);
19 static ULONG WINAPI IEnumIDList_AddRef(LPENUMIDLIST);
20 static ULONG WINAPI IEnumIDList_Release(LPENUMIDLIST);
21 static HRESULT WINAPI IEnumIDList_Next(LPENUMIDLIST,ULONG,LPITEMIDLIST*,ULONG*);
22 static HRESULT WINAPI IEnumIDList_Skip(LPENUMIDLIST,ULONG);
23 static HRESULT WINAPI IEnumIDList_Reset(LPENUMIDLIST);
24 static HRESULT WINAPI IEnumIDList_Clone(LPENUMIDLIST,LPENUMIDLIST*);
25 static BOOL WINAPI IEnumIDList_CreateEnumList(LPENUMIDLIST,LPCSTR, DWORD);
26 static BOOL WINAPI IEnumIDList_AddToEnumList(LPENUMIDLIST,LPITEMIDLIST);
27 static BOOL WINAPI IEnumIDList_DeleteList(LPENUMIDLIST);
28
29 /**************************************************************************
30  *  IEnumIDList_VTable
31  */
32 static IEnumIDList_VTable eidlvt = 
33 { IEnumIDList_QueryInterface,
34   IEnumIDList_AddRef,
35   IEnumIDList_Release,
36   IEnumIDList_Next,
37   IEnumIDList_Skip,
38   IEnumIDList_Reset,
39   IEnumIDList_Clone,
40   IEnumIDList_CreateEnumList,
41   IEnumIDList_AddToEnumList,
42   IEnumIDList_DeleteList
43 };
44
45 /**************************************************************************
46  *  IEnumIDList_Constructor
47  */
48
49 LPENUMIDLIST IEnumIDList_Constructor( LPCSTR lpszPath, DWORD dwFlags)
50 {       LPENUMIDLIST    lpeidl;
51
52         lpeidl = (LPENUMIDLIST)HeapAlloc(GetProcessHeap(),0,sizeof(IEnumIDList));
53         if (! lpeidl)
54           return NULL;
55
56         lpeidl->ref = 1;
57         lpeidl->lpvtbl = &eidlvt;
58         lpeidl->mpFirst=NULL;
59         lpeidl->mpLast=NULL;
60         lpeidl->mpCurrent=NULL;
61
62         TRACE(shell,"(%p)->(%s flags=0x%08lx)\n",lpeidl,debugstr_a(lpszPath),dwFlags);
63
64         if(!IEnumIDList_CreateEnumList(lpeidl, lpszPath, dwFlags))
65         { if (lpeidl)
66           { HeapFree(GetProcessHeap(),0,lpeidl);
67           }
68           return NULL;    
69         }
70
71         TRACE(shell,"-- (%p)->()\n",lpeidl);
72         shell32_ObjCount++;
73         return lpeidl;
74 }
75
76 /**************************************************************************
77  *  EnumIDList_QueryInterface
78  */
79 static HRESULT WINAPI IEnumIDList_QueryInterface(
80   LPENUMIDLIST this, REFIID riid, LPVOID *ppvObj)
81 {  char xriid[50];
82    WINE_StringFromCLSID((LPCLSID)riid,xriid);
83    TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",this,xriid,ppvObj);
84
85   *ppvObj = NULL;
86
87   if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
88   { *ppvObj = this; 
89   }
90   else if(IsEqualIID(riid, &IID_IEnumIDList))  /*IEnumIDList*/
91   {    *ppvObj = (IEnumIDList*)this;
92   }   
93
94   if(*ppvObj)
95   { (*(LPENUMIDLIST*)ppvObj)->lpvtbl->fnAddRef(this);   
96     TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
97     return S_OK;
98   }
99         TRACE(shell,"-- Interface: E_NOINTERFACE\n");
100         return E_NOINTERFACE;
101 }   
102
103 /******************************************************************************
104  * IEnumIDList_AddRef
105  */
106 static ULONG WINAPI IEnumIDList_AddRef(LPENUMIDLIST this)
107 {       TRACE(shell,"(%p)->(%lu)\n",this,this->ref);
108
109         shell32_ObjCount++;
110         return ++(this->ref);
111 }
112 /******************************************************************************
113  * IEnumIDList_Release
114  */
115 static ULONG WINAPI IEnumIDList_Release(LPENUMIDLIST this)
116 {       TRACE(shell,"(%p)->(%lu)\n",this,this->ref);
117
118         shell32_ObjCount--;
119
120         if (!--(this->ref)) 
121         { TRACE(shell," destroying IEnumIDList(%p)\n",this);
122           IEnumIDList_DeleteList(this);
123           HeapFree(GetProcessHeap(),0,this);
124           return 0;
125         }
126         return this->ref;
127 }
128    
129 /**************************************************************************
130  *  IEnumIDList_Next
131  */
132
133 static HRESULT WINAPI IEnumIDList_Next(
134         LPENUMIDLIST this,ULONG celt,LPITEMIDLIST * rgelt,ULONG *pceltFetched) 
135 {       ULONG    i;
136         HRESULT  hr = S_OK;
137         LPITEMIDLIST  temp;
138
139         TRACE(shell,"(%p)->(%ld,%p, %p)\n",this,celt,rgelt,pceltFetched);
140
141 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
142  * subsystems actually use it (and so may a third party browser)
143  */
144         if(pceltFetched)
145           *pceltFetched = 0;
146
147         *rgelt=0;
148         
149         if(celt > 1 && !pceltFetched)
150         { return E_INVALIDARG;
151         }
152
153         for(i = 0; i < celt; i++)
154         { if(!(this->mpCurrent))
155           { hr =  S_FALSE;
156             break;
157           }
158           temp = ILClone(this->mpCurrent->pidl);
159           rgelt[i] = temp;
160           this->mpCurrent = this->mpCurrent->pNext;
161         }
162         if(pceltFetched)
163         {  *pceltFetched = i;
164         }
165
166         return hr;
167 }
168
169 /**************************************************************************
170 *  IEnumIDList_Skip
171 */
172 static HRESULT WINAPI IEnumIDList_Skip(
173         LPENUMIDLIST this,ULONG celt)
174 { DWORD    dwIndex;
175   HRESULT  hr = S_OK;
176
177   TRACE(shell,"(%p)->(%lu)\n",this,celt);
178
179   for(dwIndex = 0; dwIndex < celt; dwIndex++)
180   { if(!this->mpCurrent)
181     { hr = S_FALSE;
182       break;
183     }
184     this->mpCurrent = this->mpCurrent->pNext;
185   }
186   return hr;
187 }
188 /**************************************************************************
189 *  IEnumIDList_Reset
190 */
191 static HRESULT WINAPI IEnumIDList_Reset(LPENUMIDLIST this)
192 { TRACE(shell,"(%p)\n",this);
193   this->mpCurrent = this->mpFirst;
194   return S_OK;
195 }
196 /**************************************************************************
197 *  IEnumIDList_Clone
198 */
199 static HRESULT WINAPI IEnumIDList_Clone(
200         LPENUMIDLIST this,LPENUMIDLIST * ppenum)
201 { TRACE(shell,"(%p)->() to (%p)->() E_NOTIMPL\n",this,ppenum);
202         return E_NOTIMPL;
203 }
204 /**************************************************************************
205  *  EnumIDList_CreateEnumList()
206  *  fixme: devices not handled
207  *  fixme: add wildcards to path
208  */
209 static BOOL WINAPI IEnumIDList_CreateEnumList(LPENUMIDLIST this, LPCSTR lpszPath, DWORD dwFlags)
210 {       LPITEMIDLIST    pidl=NULL;
211         LPPIDLDATA      pData=NULL;
212         WIN32_FIND_DATAA stffile;       
213         HANDLE hFile;
214         DWORD dwDrivemap;
215         CHAR  szDriveName[4];
216         CHAR  szPath[MAX_PATH];
217     
218         TRACE(shell,"(%p)->(path=%s flags=0x%08lx) \n",this,debugstr_a(lpszPath),dwFlags);
219
220         if (lpszPath && lpszPath[0]!='\0')
221         { strcpy(szPath, lpszPath);
222           PathAddBackslashA(szPath);
223           strcat(szPath,"*.*");
224         }
225
226         /*enumerate the folders*/
227         if(dwFlags & SHCONTF_FOLDERS)
228         { /* special case - we can't enumerate the Desktop level Objects (MyComputer,Nethood...
229           so we need to fake an enumeration of those.*/
230           if(!lpszPath)
231           { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (special) items\n",this);
232                 /*create the pidl for this item */
233             pidl = _ILCreateMyComputer();
234             if(pidl)
235             { if(!IEnumIDList_AddToEnumList(this, pidl))
236                 return FALSE;
237             }
238           }   
239           else if (lpszPath[0]=='\0') /* enumerate the drives*/
240           { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (drives)\n",this);
241             dwDrivemap = GetLogicalDrives();
242             strcpy (szDriveName,"A:\\");
243             while (szDriveName[0]<='Z')
244             { if(dwDrivemap & 0x00000001L)
245               { pidl = _ILCreateDrive(szDriveName);
246                 if(pidl)
247                 { if(!IEnumIDList_AddToEnumList(this, pidl))
248                   return FALSE;
249                 }
250               }
251               szDriveName[0]++;
252               dwDrivemap = dwDrivemap >> 1;
253             }   
254           }
255           else
256           { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",this,debugstr_a(szPath));
257             hFile = FindFirstFileA(szPath,&stffile);
258             if ( hFile != INVALID_HANDLE_VALUE )
259             { do
260               { if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
261                 { pidl = _ILCreateFolder( stffile.cAlternateFileName, stffile.cFileName);
262                   if(pidl)
263                   { pData = _ILGetDataPointer(pidl);
264                     FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.folder.uFileDate,&pData->u.folder.uFileTime);
265                     pData->u.folder.dwFileSize = stffile.nFileSizeLow;
266                     pData->u.folder.uFileAttribs=stffile.dwFileAttributes;
267                     if(!IEnumIDList_AddToEnumList(this, pidl))
268                     {  return FALSE;
269                     }
270                   }
271                   else
272                   { return FALSE;
273                   }   
274                 }
275               } while( FindNextFileA(hFile,&stffile));
276                         FindClose (hFile);
277             }
278           }   
279         }   
280         /*enumerate the non-folder items (values) */
281         if(dwFlags & SHCONTF_NONFOLDERS)
282         { if(lpszPath)
283           { TRACE (shell,"-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",this,debugstr_a(szPath));
284             hFile = FindFirstFileA(szPath,&stffile);
285             if ( hFile != INVALID_HANDLE_VALUE )
286             { do
287               { if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
288                 { pidl = _ILCreateValue( stffile.cAlternateFileName, stffile.cFileName);
289                   if(pidl)
290                   { pData = _ILGetDataPointer(pidl);
291                     FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.file.uFileDate,&pData->u.file.uFileTime);
292                     pData->u.file.dwFileSize = stffile.nFileSizeLow;
293                     pData->u.file.uFileAttribs=stffile.dwFileAttributes;
294                     if(!IEnumIDList_AddToEnumList(this, pidl))
295                     { return FALSE;
296                     }
297                   }
298                   else
299                   { return FALSE;
300                   }   
301                 }
302               } while( FindNextFileA(hFile,&stffile));
303               FindClose (hFile);
304             } 
305           }
306         } 
307         return TRUE;
308 }
309
310 /**************************************************************************
311  *  EnumIDList_AddToEnumList()
312  */
313 static BOOL WINAPI IEnumIDList_AddToEnumList(LPENUMIDLIST this,LPITEMIDLIST pidl)
314 { LPENUMLIST  pNew;
315
316   TRACE(shell,"(%p)->(pidl=%p)\n",this,pidl);
317   pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
318   if(pNew)
319   { /*set the next pointer */
320     pNew->pNext = NULL;
321     pNew->pidl = pidl;
322
323     /*is this the first item in the list? */
324     if(!this->mpFirst)
325     { this->mpFirst = pNew;
326       this->mpCurrent = pNew;
327     }
328    
329     if(this->mpLast)
330     { /*add the new item to the end of the list */
331       this->mpLast->pNext = pNew;
332     }
333    
334     /*update the last item pointer */
335     this->mpLast = pNew;
336     TRACE(shell,"-- (%p)->(first=%p, last=%p)\n",this,this->mpFirst,this->mpLast);
337     return TRUE;
338   }
339   return FALSE;
340 }
341 /**************************************************************************
342 *   EnumIDList_DeleteList()
343 */
344 static BOOL WINAPI IEnumIDList_DeleteList(LPENUMIDLIST this)
345 { LPENUMLIST  pDelete;
346
347   TRACE(shell,"(%p)->()\n",this);
348         
349   while(this->mpFirst)
350   { pDelete = this->mpFirst;
351     this->mpFirst = pDelete->pNext;
352     SHFree(pDelete->pidl);
353     SHFree(pDelete);
354   }
355   this->mpFirst = this->mpLast = this->mpCurrent = NULL;
356   return TRUE;
357 }