Reverse the order for deleting the items in resetcontent to correctly
[wine] / dlls / shell32 / enumidlist.c
1 /*
2  *      IEnumIDList
3  *
4  *      Copyright 1998  Juergen Schmied <juergen.schmied@metronet.de>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #define COBJMACROS
26
27 #include "wine/debug.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "shlwapi.h"
32
33 #include "pidl.h"
34 #include "enumidlist.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(shell);
37
38 typedef struct tagENUMLIST
39 {
40         struct tagENUMLIST      *pNext;
41         LPITEMIDLIST            pidl;
42
43 } ENUMLIST, *LPENUMLIST;
44
45 typedef struct
46 {
47         IEnumIDListVtbl                *lpVtbl;
48         DWORD                           ref;
49         LPENUMLIST                      mpFirst;
50         LPENUMLIST                      mpLast;
51         LPENUMLIST                      mpCurrent;
52
53 } IEnumIDListImpl;
54
55 static struct IEnumIDListVtbl eidlvt;
56
57 /**************************************************************************
58  *  AddToEnumList()
59  */
60 BOOL AddToEnumList(
61         IEnumIDList * iface,
62         LPITEMIDLIST pidl)
63 {
64         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
65
66         LPENUMLIST  pNew;
67
68         TRACE("(%p)->(pidl=%p)\n",This,pidl);
69
70     if (!iface || !pidl)
71         return FALSE;
72
73         pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
74         if(pNew)
75         {
76           /*set the next pointer */
77           pNew->pNext = NULL;
78           pNew->pidl = pidl;
79
80           /*is This the first item in the list? */
81           if(!This->mpFirst)
82           {
83             This->mpFirst = pNew;
84             This->mpCurrent = pNew;
85           }
86
87           if(This->mpLast)
88           {
89             /*add the new item to the end of the list */
90             This->mpLast->pNext = pNew;
91           }
92
93           /*update the last item pointer */
94           This->mpLast = pNew;
95           TRACE("-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
96           return TRUE;
97         }
98         return FALSE;
99 }
100
101 /**************************************************************************
102  *  CreateFolderEnumList()
103  */
104 BOOL CreateFolderEnumList(
105         IEnumIDList *list,
106         LPCSTR lpszPath,
107         DWORD dwFlags)
108 {
109     LPITEMIDLIST pidl=NULL;
110     WIN32_FIND_DATAA stffile;
111     HANDLE hFile;
112     CHAR  szPath[MAX_PATH];
113     BOOL succeeded = TRUE;
114
115     TRACE("(%p)->(path=%s flags=0x%08lx) \n",list,debugstr_a(lpszPath),dwFlags);
116
117     if(!lpszPath || !lpszPath[0]) return FALSE;
118
119     strcpy(szPath, lpszPath);
120     PathAddBackslashA(szPath);
121     strcat(szPath,"*.*");
122
123     hFile = FindFirstFileA(szPath,&stffile);
124     if ( hFile != INVALID_HANDLE_VALUE )
125     {
126         BOOL findFinished = FALSE;
127
128         do
129         {
130             if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 
131              || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
132             {
133                 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
134                  dwFlags & SHCONTF_FOLDERS &&
135                  strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
136                 {
137                     pidl = _ILCreateFromFindDataA(&stffile);
138                     succeeded = succeeded && AddToEnumList(list, pidl);
139                 }
140                 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
141                  && dwFlags & SHCONTF_NONFOLDERS)
142                 {
143                     pidl = _ILCreateFromFindDataA(&stffile);
144                     succeeded = succeeded && AddToEnumList(list, pidl);
145                 }
146             }
147             if (succeeded)
148             {
149                 if (!FindNextFileA(hFile, &stffile))
150                 {
151                     if (GetLastError() == ERROR_NO_MORE_FILES)
152                         findFinished = TRUE;
153                     else
154                         succeeded = FALSE;
155                 }
156             }
157         } while (succeeded && !findFinished);
158         FindClose(hFile);
159     }
160     return succeeded;
161 }
162
163 /**************************************************************************
164 *   DeleteList()
165 */
166 static BOOL DeleteList(
167         IEnumIDList * iface)
168 {
169         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
170
171         LPENUMLIST  pDelete;
172
173         TRACE("(%p)->()\n",This);
174
175         while(This->mpFirst)
176         { pDelete = This->mpFirst;
177           This->mpFirst = pDelete->pNext;
178           SHFree(pDelete->pidl);
179           SHFree(pDelete);
180         }
181         This->mpFirst = This->mpLast = This->mpCurrent = NULL;
182         return TRUE;
183 }
184
185 /**************************************************************************
186  *  IEnumIDList_Folder_Constructor
187  *
188  */
189
190 IEnumIDList * IEnumIDList_Constructor(void)
191 {
192     IEnumIDListImpl *lpeidl = (IEnumIDListImpl*)HeapAlloc(GetProcessHeap(),
193      HEAP_ZERO_MEMORY, sizeof(IEnumIDListImpl));
194
195     if (lpeidl)
196     {
197         lpeidl->ref = 1;
198         lpeidl->lpVtbl = &eidlvt;
199     }
200     TRACE("-- (%p)->()\n",lpeidl);
201
202     return (IEnumIDList*)lpeidl;
203 }
204
205 /**************************************************************************
206  *  EnumIDList_QueryInterface
207  */
208 static HRESULT WINAPI IEnumIDList_fnQueryInterface(
209         IEnumIDList * iface,
210         REFIID riid,
211         LPVOID *ppvObj)
212 {
213         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
214
215         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
216
217         *ppvObj = NULL;
218
219         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
220         { *ppvObj = This;
221         }
222         else if(IsEqualIID(riid, &IID_IEnumIDList))  /*IEnumIDList*/
223         {    *ppvObj = (IEnumIDList*)This;
224         }
225
226         if(*ppvObj)
227         { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
228           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
229           return S_OK;
230         }
231
232         TRACE("-- Interface: E_NOINTERFACE\n");
233         return E_NOINTERFACE;
234 }
235
236 /******************************************************************************
237  * IEnumIDList_fnAddRef
238  */
239 static ULONG WINAPI IEnumIDList_fnAddRef(
240         IEnumIDList * iface)
241 {
242         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
243         ULONG refCount = InterlockedIncrement(&This->ref);
244
245         TRACE("(%p)->(%lu)\n", This, refCount - 1);
246
247         return refCount;
248 }
249 /******************************************************************************
250  * IEnumIDList_fnRelease
251  */
252 static ULONG WINAPI IEnumIDList_fnRelease(
253         IEnumIDList * iface)
254 {
255         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
256         ULONG refCount = InterlockedDecrement(&This->ref);
257
258         TRACE("(%p)->(%lu)\n", This, refCount + 1);
259
260         if (!refCount) {
261           TRACE(" destroying IEnumIDList(%p)\n",This);
262           DeleteList((IEnumIDList*)This);
263           HeapFree(GetProcessHeap(),0,This);
264         }
265         return refCount;
266 }
267
268 /**************************************************************************
269  *  IEnumIDList_fnNext
270  */
271
272 static HRESULT WINAPI IEnumIDList_fnNext(
273         IEnumIDList * iface,
274         ULONG celt,
275         LPITEMIDLIST * rgelt,
276         ULONG *pceltFetched)
277 {
278         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
279
280         ULONG    i;
281         HRESULT  hr = S_OK;
282         LPITEMIDLIST  temp;
283
284         TRACE("(%p)->(%ld,%p, %p)\n",This,celt,rgelt,pceltFetched);
285
286 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
287  * subsystems actually use it (and so may a third party browser)
288  */
289         if(pceltFetched)
290           *pceltFetched = 0;
291
292         *rgelt=0;
293
294         if(celt > 1 && !pceltFetched)
295         { return E_INVALIDARG;
296         }
297
298         if(celt > 0 && !This->mpCurrent)
299         { return S_FALSE;
300         }
301
302         for(i = 0; i < celt; i++)
303         { if(!(This->mpCurrent))
304             break;
305
306           temp = ILClone(This->mpCurrent->pidl);
307           rgelt[i] = temp;
308           This->mpCurrent = This->mpCurrent->pNext;
309         }
310         if(pceltFetched)
311         {  *pceltFetched = i;
312         }
313
314         return hr;
315 }
316
317 /**************************************************************************
318 *  IEnumIDList_fnSkip
319 */
320 static HRESULT WINAPI IEnumIDList_fnSkip(
321         IEnumIDList * iface,ULONG celt)
322 {
323         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
324
325         DWORD    dwIndex;
326         HRESULT  hr = S_OK;
327
328         TRACE("(%p)->(%lu)\n",This,celt);
329
330         for(dwIndex = 0; dwIndex < celt; dwIndex++)
331         { if(!This->mpCurrent)
332           { hr = S_FALSE;
333             break;
334           }
335           This->mpCurrent = This->mpCurrent->pNext;
336         }
337         return hr;
338 }
339 /**************************************************************************
340 *  IEnumIDList_fnReset
341 */
342 static HRESULT WINAPI IEnumIDList_fnReset(
343         IEnumIDList * iface)
344 {
345         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
346
347         TRACE("(%p)\n",This);
348         This->mpCurrent = This->mpFirst;
349         return S_OK;
350 }
351 /**************************************************************************
352 *  IEnumIDList_fnClone
353 */
354 static HRESULT WINAPI IEnumIDList_fnClone(
355         IEnumIDList * iface,LPENUMIDLIST * ppenum)
356 {
357         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
358
359         TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
360         return E_NOTIMPL;
361 }
362
363 /**************************************************************************
364  *  IEnumIDList_fnVTable
365  */
366 static IEnumIDListVtbl eidlvt =
367 {
368         IEnumIDList_fnQueryInterface,
369         IEnumIDList_fnAddRef,
370         IEnumIDList_fnRelease,
371         IEnumIDList_fnNext,
372         IEnumIDList_fnSkip,
373         IEnumIDList_fnReset,
374         IEnumIDList_fnClone,
375 };