shell32: Get rid of a local typedef for a struct.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "wine/unicode.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
33
34 #include "pidl.h"
35 #include "shell32_main.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(shell);
38
39 struct enumlist
40 {
41         struct enumlist         *pNext;
42         LPITEMIDLIST            pidl;
43 };
44
45 typedef struct
46 {
47         IEnumIDList                     IEnumIDList_iface;
48         LONG                            ref;
49         struct enumlist                 *mpFirst;
50         struct enumlist                 *mpLast;
51         struct enumlist                 *mpCurrent;
52
53 } IEnumIDListImpl;
54
55 /**************************************************************************
56  *  AddToEnumList()
57  */
58 BOOL AddToEnumList(
59         IEnumIDList * iface,
60         LPITEMIDLIST pidl)
61 {
62         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
63
64         struct enumlist *pNew;
65
66         TRACE("(%p)->(pidl=%p)\n",This,pidl);
67
68     if (!iface || !pidl)
69         return FALSE;
70
71         pNew = SHAlloc(sizeof(*pNew));
72         if(pNew)
73         {
74           /*set the next pointer */
75           pNew->pNext = NULL;
76           pNew->pidl = pidl;
77
78           /*is This the first item in the list? */
79           if(!This->mpFirst)
80           {
81             This->mpFirst = pNew;
82             This->mpCurrent = pNew;
83           }
84
85           if(This->mpLast)
86           {
87             /*add the new item to the end of the list */
88             This->mpLast->pNext = pNew;
89           }
90
91           /*update the last item pointer */
92           This->mpLast = pNew;
93           TRACE("-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
94           return TRUE;
95         }
96         return FALSE;
97 }
98
99 /**************************************************************************
100  *  CreateFolderEnumList()
101  */
102 BOOL CreateFolderEnumList(
103         IEnumIDList *list,
104         LPCWSTR lpszPath,
105         DWORD dwFlags)
106 {
107     LPITEMIDLIST pidl=NULL;
108     WIN32_FIND_DATAW stffile;
109     HANDLE hFile;
110     WCHAR  szPath[MAX_PATH];
111     BOOL succeeded = TRUE;
112     static const WCHAR stars[] = { '*','.','*',0 };
113     static const WCHAR dot[] = { '.',0 };
114     static const WCHAR dotdot[] = { '.','.',0 };
115
116     TRACE("(%p)->(path=%s flags=0x%08x)\n", list, debugstr_w(lpszPath), dwFlags);
117
118     if(!lpszPath || !lpszPath[0]) return FALSE;
119
120     strcpyW(szPath, lpszPath);
121     PathAddBackslashW(szPath);
122     strcatW(szPath,stars);
123
124     hFile = FindFirstFileW(szPath,&stffile);
125     if ( hFile != INVALID_HANDLE_VALUE )
126     {
127         BOOL findFinished = FALSE;
128
129         do
130         {
131             if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 
132              || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
133             {
134                 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
135                  dwFlags & SHCONTF_FOLDERS &&
136                  strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
137                 {
138                     pidl = _ILCreateFromFindDataW(&stffile);
139                     succeeded = succeeded && AddToEnumList(list, pidl);
140                 }
141                 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
142                  && dwFlags & SHCONTF_NONFOLDERS)
143                 {
144                     pidl = _ILCreateFromFindDataW(&stffile);
145                     succeeded = succeeded && AddToEnumList(list, pidl);
146                 }
147             }
148             if (succeeded)
149             {
150                 if (!FindNextFileW(hFile, &stffile))
151                 {
152                     if (GetLastError() == ERROR_NO_MORE_FILES)
153                         findFinished = TRUE;
154                     else
155                         succeeded = FALSE;
156                 }
157             }
158         } while (succeeded && !findFinished);
159         FindClose(hFile);
160     }
161     return succeeded;
162 }
163
164 static BOOL DeleteList(IEnumIDListImpl *This)
165 {
166         struct enumlist *pDelete;
167
168         TRACE("(%p)->()\n",This);
169
170         while(This->mpFirst)
171         { pDelete = This->mpFirst;
172           This->mpFirst = pDelete->pNext;
173           SHFree(pDelete->pidl);
174           SHFree(pDelete);
175         }
176         This->mpFirst = This->mpLast = This->mpCurrent = NULL;
177         return TRUE;
178 }
179
180 static inline IEnumIDListImpl *impl_from_IEnumIDList(IEnumIDList *iface)
181 {
182     return CONTAINING_RECORD(iface, IEnumIDListImpl, IEnumIDList_iface);
183 }
184
185 /**************************************************************************
186  *  IEnumIDList::QueryInterface
187  */
188 static HRESULT WINAPI IEnumIDList_fnQueryInterface(IEnumIDList *iface, REFIID riid, void **ppvObj)
189 {
190         IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
191
192         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
193
194         *ppvObj = NULL;
195
196         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
197         { *ppvObj = This;
198         }
199         else if(IsEqualIID(riid, &IID_IEnumIDList))  /*IEnumIDList*/
200         {    *ppvObj = This;
201         }
202
203         if(*ppvObj)
204         { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
205           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
206           return S_OK;
207         }
208
209         TRACE("-- Interface: E_NOINTERFACE\n");
210         return E_NOINTERFACE;
211 }
212
213 /******************************************************************************
214  * IEnumIDList::AddRef
215  */
216 static ULONG WINAPI IEnumIDList_fnAddRef(IEnumIDList *iface)
217 {
218         IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
219         ULONG refCount = InterlockedIncrement(&This->ref);
220
221         TRACE("(%p)->(%u)\n", This, refCount - 1);
222
223         return refCount;
224 }
225 /******************************************************************************
226  * IEnumIDList::Release
227  */
228 static ULONG WINAPI IEnumIDList_fnRelease(IEnumIDList *iface)
229 {
230         IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
231         ULONG refCount = InterlockedDecrement(&This->ref);
232
233         TRACE("(%p)->(%u)\n", This, refCount + 1);
234
235         if (!refCount) {
236           TRACE(" destroying IEnumIDList(%p)\n",This);
237           DeleteList(This);
238           HeapFree(GetProcessHeap(),0,This);
239         }
240         return refCount;
241 }
242
243 /**************************************************************************
244  *  IEnumIDList::Next
245  */
246
247 static HRESULT WINAPI IEnumIDList_fnNext(IEnumIDList *iface, ULONG celt, LPITEMIDLIST *rgelt,
248         ULONG *pceltFetched)
249 {
250         IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
251
252         ULONG    i;
253         HRESULT  hr = S_OK;
254         LPITEMIDLIST  temp;
255
256         TRACE("(%p)->(%d,%p, %p)\n",This,celt,rgelt,pceltFetched);
257
258 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
259  * subsystems actually use it (and so may a third party browser)
260  */
261         if(pceltFetched)
262           *pceltFetched = 0;
263
264         *rgelt=0;
265
266         if(celt > 1 && !pceltFetched)
267         { return E_INVALIDARG;
268         }
269
270         if(celt > 0 && !This->mpCurrent)
271         { return S_FALSE;
272         }
273
274         for(i = 0; i < celt; i++)
275         { if(!(This->mpCurrent))
276             break;
277
278           temp = ILClone(This->mpCurrent->pidl);
279           rgelt[i] = temp;
280           This->mpCurrent = This->mpCurrent->pNext;
281         }
282         if(pceltFetched)
283         {  *pceltFetched = i;
284         }
285
286         return hr;
287 }
288
289 /**************************************************************************
290 *  IEnumIDList::Skip
291 */
292 static HRESULT WINAPI IEnumIDList_fnSkip(IEnumIDList *iface, ULONG celt)
293 {
294         IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
295
296         DWORD    dwIndex;
297         HRESULT  hr = S_OK;
298
299         TRACE("(%p)->(%u)\n",This,celt);
300
301         for(dwIndex = 0; dwIndex < celt; dwIndex++)
302         { if(!This->mpCurrent)
303           { hr = S_FALSE;
304             break;
305           }
306           This->mpCurrent = This->mpCurrent->pNext;
307         }
308         return hr;
309 }
310 /**************************************************************************
311 *  IEnumIDList::Reset
312 */
313 static HRESULT WINAPI IEnumIDList_fnReset(IEnumIDList *iface)
314 {
315         IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
316
317         TRACE("(%p)\n",This);
318         This->mpCurrent = This->mpFirst;
319         return S_OK;
320 }
321 /**************************************************************************
322 *  IEnumIDList::Clone
323 */
324 static HRESULT WINAPI IEnumIDList_fnClone(IEnumIDList *iface, IEnumIDList **ppenum)
325 {
326         IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
327
328         TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
329         return E_NOTIMPL;
330 }
331
332 static const IEnumIDListVtbl eidlvt =
333 {
334         IEnumIDList_fnQueryInterface,
335         IEnumIDList_fnAddRef,
336         IEnumIDList_fnRelease,
337         IEnumIDList_fnNext,
338         IEnumIDList_fnSkip,
339         IEnumIDList_fnReset,
340         IEnumIDList_fnClone,
341 };
342
343 IEnumIDList *IEnumIDList_Constructor(void)
344 {
345     IEnumIDListImpl *lpeidl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lpeidl));
346
347     if (lpeidl)
348     {
349         lpeidl->ref = 1;
350         lpeidl->IEnumIDList_iface.lpVtbl = &eidlvt;
351     }
352     else
353         return NULL;
354
355     TRACE("-- (%p)->()\n",lpeidl);
356
357     return &lpeidl->IEnumIDList_iface;
358 }