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