- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[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 "objbase.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 BOOL32 WINAPI IEnumIDList_CreateEnumList(LPENUMIDLIST,LPCSTR, DWORD);
26 static BOOL32 WINAPI IEnumIDList_AddToEnumList(LPENUMIDLIST,LPITEMIDLIST);
27 static BOOL32 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 BOOL32 WINAPI IEnumIDList_CreateEnumList(LPENUMIDLIST this, LPCSTR lpszPath, DWORD dwFlags)
210 {       LPITEMIDLIST    pidl=NULL;
211         LPPIDLDATA      pData=NULL;
212         WIN32_FIND_DATA32A stffile;     
213         HANDLE32 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           PathAddBackslash32A(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             { pData = _ILGetDataPointer(pidl);
236               pData->u.generic.dwSFGAO = SFGAO_HASPROPSHEET | SFGAO_READONLY | SFGAO_HASSUBFOLDER;
237               if(!IEnumIDList_AddToEnumList(this, pidl))
238                 return FALSE;
239             }
240           }   
241           else if (lpszPath[0]=='\0') /* enumerate the drives*/
242           { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (drives)\n",this);
243             dwDrivemap = GetLogicalDrives();
244             strcpy (szDriveName,"A:\\");
245             while (szDriveName[0]<='Z')
246             { if(dwDrivemap & 0x00000001L)
247               { pidl = _ILCreateDrive(szDriveName);
248                 pData = _ILGetDataPointer(pidl);
249                 pData->u.drive.dwSFGAO = SFGAO_HASPROPSHEET | SFGAO_READONLY | SFGAO_CANLINK | 
250                                  SFGAO_HASSUBFOLDER | SFGAO_DROPTARGET | SFGAO_FILESYSTEM;
251                 if(pidl)
252                 { if(!IEnumIDList_AddToEnumList(this, pidl))
253                   return FALSE;
254                 }
255               }
256               szDriveName[0]++;
257               dwDrivemap = dwDrivemap >> 1;
258             }   
259           }
260           else
261           { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",this,debugstr_a(szPath));
262             hFile = FindFirstFile32A(szPath,&stffile);
263             if ( hFile != INVALID_HANDLE_VALUE32 )
264             { do
265               { if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
266                 { pidl = _ILCreateFolder( stffile.cFileName);
267                   if(pidl)
268                   { pData = _ILGetDataPointer(pidl);
269                     pData->u.folder.dwSFGAO = SFGAO_CANCOPY | SFGAO_CANDELETE | SFGAO_CANLINK  |
270                                      SFGAO_CANMOVE | SFGAO_CANRENAME | SFGAO_DROPTARGET |
271                                      SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
272                     if ( stffile.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
273                     { pData->u.folder.dwSFGAO |= SFGAO_READONLY;
274                     }
275                     FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.folder.uFileDate,&pData->u.folder.uFileTime);
276                     pData->u.folder.dwFileSize = stffile.nFileSizeLow;
277                     pData->u.folder.uFileAttribs=stffile.dwFileAttributes;
278                     strncpy (pData->u.folder.szAlternateName, stffile.cAlternateFileName,14);
279                     if(!IEnumIDList_AddToEnumList(this, pidl))
280                     {  return FALSE;
281                     }
282                   }
283                   else
284                   { return FALSE;
285                   }   
286                 }
287               } while( FindNextFile32A(hFile,&stffile));
288                         FindClose32 (hFile);
289             }
290           }   
291         }   
292         /*enumerate the non-folder items (values) */
293         if(dwFlags & SHCONTF_NONFOLDERS)
294         { if(lpszPath)
295           { TRACE (shell,"-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",this,debugstr_a(szPath));
296             hFile = FindFirstFile32A(szPath,&stffile);
297             if ( hFile != INVALID_HANDLE_VALUE32 )
298             { do
299               { if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
300                 { pidl = _ILCreateValue( stffile.cFileName);
301                   if(pidl)
302                   { pData = _ILGetDataPointer(pidl);
303                     pData->u.file.dwSFGAO = SFGAO_CANCOPY | SFGAO_CANDELETE | SFGAO_CANLINK  |
304                                      SFGAO_CANMOVE | SFGAO_CANRENAME | SFGAO_DROPTARGET |
305                                      SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM;
306                     if ( stffile.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
307                     { pData->u.file.dwSFGAO |= SFGAO_READONLY;
308                     }
309                     FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.file.uFileDate,&pData->u.file.uFileTime);
310                     pData->u.file.dwFileSize = stffile.nFileSizeLow;
311                     pData->u.file.uFileAttribs=stffile.dwFileAttributes;
312                     strncpy (pData->u.file.szAlternateName, stffile.cAlternateFileName,14);
313                     if(!IEnumIDList_AddToEnumList(this, pidl))
314                     { return FALSE;
315                     }
316                   }
317                   else
318                   { return FALSE;
319                   }   
320                 }
321               } while( FindNextFile32A(hFile,&stffile));
322               FindClose32 (hFile);
323             } 
324           }
325         } 
326         return TRUE;
327 }
328
329 /**************************************************************************
330  *  EnumIDList_AddToEnumList()
331  */
332 static BOOL32 WINAPI IEnumIDList_AddToEnumList(LPENUMIDLIST this,LPITEMIDLIST pidl)
333 { LPENUMLIST  pNew;
334
335   TRACE(shell,"(%p)->(pidl=%p)\n",this,pidl);
336   pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
337   if(pNew)
338   { /*set the next pointer */
339     pNew->pNext = NULL;
340     pNew->pidl = pidl;
341
342     /*is this the first item in the list? */
343     if(!this->mpFirst)
344     { this->mpFirst = pNew;
345       this->mpCurrent = pNew;
346     }
347    
348     if(this->mpLast)
349     { /*add the new item to the end of the list */
350       this->mpLast->pNext = pNew;
351     }
352    
353     /*update the last item pointer */
354     this->mpLast = pNew;
355     TRACE(shell,"-- (%p)->(first=%p, last=%p)\n",this,this->mpFirst,this->mpLast);
356     return TRUE;
357   }
358   return FALSE;
359 }
360 /**************************************************************************
361 *   EnumIDList_DeleteList()
362 */
363 static BOOL32 WINAPI IEnumIDList_DeleteList(LPENUMIDLIST this)
364 { LPENUMLIST  pDelete;
365
366   TRACE(shell,"(%p)->()\n",this);
367         
368   while(this->mpFirst)
369   { pDelete = this->mpFirst;
370     this->mpFirst = pDelete->pNext;
371     SHFree(pDelete->pidl);
372     SHFree(pDelete);
373   }
374   this->mpFirst = this->mpLast = this->mpCurrent = NULL;
375   return TRUE;
376 }