Return "file not found" error values instead of E_INVALIDARG if
[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 #include "wine/debug.h"
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "undocshell.h"
29 #include "shlwapi.h"
30 #include "winerror.h"
31 #include "objbase.h"
32
33 #include "pidl.h"
34 #include "shlguid.h"
35 #include "enumidlist.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(shell);
38
39 typedef struct tagENUMLIST
40 {
41         struct tagENUMLIST      *pNext;
42         LPITEMIDLIST            pidl;
43
44 } ENUMLIST, *LPENUMLIST;
45
46 typedef struct
47 {
48         ICOM_VFIELD(IEnumIDList);
49         DWORD                           ref;
50         LPENUMLIST                      mpFirst;
51         LPENUMLIST                      mpLast;
52         LPENUMLIST                      mpCurrent;
53
54 } IEnumIDListImpl;
55
56 static struct ICOM_VTABLE(IEnumIDList) eidlvt;
57
58 /**************************************************************************
59  *  AddToEnumList()
60  */
61 BOOL AddToEnumList(
62         IEnumIDList * iface,
63         LPITEMIDLIST pidl)
64 {
65         ICOM_THIS(IEnumIDListImpl,iface);
66
67         LPENUMLIST  pNew;
68
69         TRACE("(%p)->(pidl=%p)\n",This,pidl);
70
71     if (!iface || !pidl)
72         return FALSE;
73
74         pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
75         if(pNew)
76         {
77           /*set the next pointer */
78           pNew->pNext = NULL;
79           pNew->pidl = pidl;
80
81           /*is This the first item in the list? */
82           if(!This->mpFirst)
83           {
84             This->mpFirst = pNew;
85             This->mpCurrent = pNew;
86           }
87
88           if(This->mpLast)
89           {
90             /*add the new item to the end of the list */
91             This->mpLast->pNext = pNew;
92           }
93
94           /*update the last item pointer */
95           This->mpLast = pNew;
96           TRACE("-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
97           return TRUE;
98         }
99         return FALSE;
100 }
101
102 /**************************************************************************
103  *  CreateFolderEnumList()
104  */
105 BOOL CreateFolderEnumList(
106         IEnumIDList *list,
107         LPCSTR lpszPath,
108         DWORD dwFlags)
109 {
110     LPITEMIDLIST pidl=NULL;
111     WIN32_FIND_DATAA stffile;
112     HANDLE hFile;
113     CHAR  szPath[MAX_PATH];
114     BOOL succeeded = TRUE;
115
116     TRACE("(%p)->(path=%s flags=0x%08lx) \n",list,debugstr_a(lpszPath),dwFlags);
117
118     if(!lpszPath || !lpszPath[0]) return FALSE;
119
120     strcpy(szPath, lpszPath);
121     PathAddBackslashA(szPath);
122     strcat(szPath,"*.*");
123
124     hFile = FindFirstFileA(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                  strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
137                 {
138                     pidl = _ILCreateFromFindDataA(&stffile);
139                     succeeded = succeeded && AddToEnumList(list, pidl);
140                 }
141                 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
142                  && dwFlags & SHCONTF_NONFOLDERS)
143                 {
144                     pidl = _ILCreateFromFindDataA(&stffile);
145                     succeeded = succeeded && AddToEnumList(list, pidl);
146                 }
147             }
148             if (succeeded)
149             {
150                 if (!FindNextFileA(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 /**************************************************************************
165 *   DeleteList()
166 */
167 static BOOL DeleteList(
168         IEnumIDList * iface)
169 {
170         ICOM_THIS(IEnumIDListImpl,iface);
171
172         LPENUMLIST  pDelete;
173
174         TRACE("(%p)->()\n",This);
175
176         while(This->mpFirst)
177         { pDelete = This->mpFirst;
178           This->mpFirst = pDelete->pNext;
179           SHFree(pDelete->pidl);
180           SHFree(pDelete);
181         }
182         This->mpFirst = This->mpLast = This->mpCurrent = NULL;
183         return TRUE;
184 }
185
186 /**************************************************************************
187  *  IEnumIDList_Folder_Constructor
188  *
189  */
190
191 IEnumIDList * IEnumIDList_Constructor(void)
192 {
193     IEnumIDListImpl *lpeidl = (IEnumIDListImpl*)HeapAlloc(GetProcessHeap(),
194      HEAP_ZERO_MEMORY, sizeof(IEnumIDListImpl));
195
196     if (lpeidl)
197     {
198         lpeidl->ref = 1;
199         lpeidl->lpVtbl = &eidlvt;
200     }
201     TRACE("-- (%p)->()\n",lpeidl);
202
203     return (IEnumIDList*)lpeidl;
204 }
205
206 /**************************************************************************
207  *  EnumIDList_QueryInterface
208  */
209 static HRESULT WINAPI IEnumIDList_fnQueryInterface(
210         IEnumIDList * iface,
211         REFIID riid,
212         LPVOID *ppvObj)
213 {
214         ICOM_THIS(IEnumIDListImpl,iface);
215
216         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
217
218         *ppvObj = NULL;
219
220         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
221         { *ppvObj = This;
222         }
223         else if(IsEqualIID(riid, &IID_IEnumIDList))  /*IEnumIDList*/
224         {    *ppvObj = (IEnumIDList*)This;
225         }
226
227         if(*ppvObj)
228         { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
229           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
230           return S_OK;
231         }
232
233         TRACE("-- Interface: E_NOINTERFACE\n");
234         return E_NOINTERFACE;
235 }
236
237 /******************************************************************************
238  * IEnumIDList_fnAddRef
239  */
240 static ULONG WINAPI IEnumIDList_fnAddRef(
241         IEnumIDList * iface)
242 {
243         ICOM_THIS(IEnumIDListImpl,iface);
244         TRACE("(%p)->(%lu)\n",This,This->ref);
245         return ++(This->ref);
246 }
247 /******************************************************************************
248  * IEnumIDList_fnRelease
249  */
250 static ULONG WINAPI IEnumIDList_fnRelease(
251         IEnumIDList * iface)
252 {
253         ICOM_THIS(IEnumIDListImpl,iface);
254
255         TRACE("(%p)->(%lu)\n",This,This->ref);
256
257         if (!--(This->ref)) {
258           TRACE(" destroying IEnumIDList(%p)\n",This);
259           DeleteList((IEnumIDList*)This);
260           HeapFree(GetProcessHeap(),0,This);
261           return 0;
262         }
263         return This->ref;
264 }
265
266 /**************************************************************************
267  *  IEnumIDList_fnNext
268  */
269
270 static HRESULT WINAPI IEnumIDList_fnNext(
271         IEnumIDList * iface,
272         ULONG celt,
273         LPITEMIDLIST * rgelt,
274         ULONG *pceltFetched)
275 {
276         ICOM_THIS(IEnumIDListImpl,iface);
277
278         ULONG    i;
279         HRESULT  hr = S_OK;
280         LPITEMIDLIST  temp;
281
282         TRACE("(%p)->(%ld,%p, %p)\n",This,celt,rgelt,pceltFetched);
283
284 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
285  * subsystems actually use it (and so may a third party browser)
286  */
287         if(pceltFetched)
288           *pceltFetched = 0;
289
290         *rgelt=0;
291
292         if(celt > 1 && !pceltFetched)
293         { return E_INVALIDARG;
294         }
295
296         if(celt > 0 && !This->mpCurrent)
297         { return S_FALSE;
298         }
299
300         for(i = 0; i < celt; i++)
301         { if(!(This->mpCurrent))
302             break;
303
304           temp = ILClone(This->mpCurrent->pidl);
305           rgelt[i] = temp;
306           This->mpCurrent = This->mpCurrent->pNext;
307         }
308         if(pceltFetched)
309         {  *pceltFetched = i;
310         }
311
312         return hr;
313 }
314
315 /**************************************************************************
316 *  IEnumIDList_fnSkip
317 */
318 static HRESULT WINAPI IEnumIDList_fnSkip(
319         IEnumIDList * iface,ULONG celt)
320 {
321         ICOM_THIS(IEnumIDListImpl,iface);
322
323         DWORD    dwIndex;
324         HRESULT  hr = S_OK;
325
326         TRACE("(%p)->(%lu)\n",This,celt);
327
328         for(dwIndex = 0; dwIndex < celt; dwIndex++)
329         { if(!This->mpCurrent)
330           { hr = S_FALSE;
331             break;
332           }
333           This->mpCurrent = This->mpCurrent->pNext;
334         }
335         return hr;
336 }
337 /**************************************************************************
338 *  IEnumIDList_fnReset
339 */
340 static HRESULT WINAPI IEnumIDList_fnReset(
341         IEnumIDList * iface)
342 {
343         ICOM_THIS(IEnumIDListImpl,iface);
344
345         TRACE("(%p)\n",This);
346         This->mpCurrent = This->mpFirst;
347         return S_OK;
348 }
349 /**************************************************************************
350 *  IEnumIDList_fnClone
351 */
352 static HRESULT WINAPI IEnumIDList_fnClone(
353         IEnumIDList * iface,LPENUMIDLIST * ppenum)
354 {
355         ICOM_THIS(IEnumIDListImpl,iface);
356
357         TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
358         return E_NOTIMPL;
359 }
360
361 /**************************************************************************
362  *  IEnumIDList_fnVTable
363  */
364 static ICOM_VTABLE (IEnumIDList) eidlvt =
365 {
366         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
367         IEnumIDList_fnQueryInterface,
368         IEnumIDList_fnAddRef,
369         IEnumIDList_fnRelease,
370         IEnumIDList_fnNext,
371         IEnumIDList_fnSkip,
372         IEnumIDList_fnReset,
373         IEnumIDList_fnClone,
374 };