ShellExecuteEx, ExtractIconEx, SHFileOperation, SHGetFileInfo,
[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         TRACE("(%p)->(%lu)\n",This,This->ref);
244         return ++(This->ref);
245 }
246 /******************************************************************************
247  * IEnumIDList_fnRelease
248  */
249 static ULONG WINAPI IEnumIDList_fnRelease(
250         IEnumIDList * iface)
251 {
252         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
253
254         TRACE("(%p)->(%lu)\n",This,This->ref);
255
256         if (!--(This->ref)) {
257           TRACE(" destroying IEnumIDList(%p)\n",This);
258           DeleteList((IEnumIDList*)This);
259           HeapFree(GetProcessHeap(),0,This);
260           return 0;
261         }
262         return This->ref;
263 }
264
265 /**************************************************************************
266  *  IEnumIDList_fnNext
267  */
268
269 static HRESULT WINAPI IEnumIDList_fnNext(
270         IEnumIDList * iface,
271         ULONG celt,
272         LPITEMIDLIST * rgelt,
273         ULONG *pceltFetched)
274 {
275         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
276
277         ULONG    i;
278         HRESULT  hr = S_OK;
279         LPITEMIDLIST  temp;
280
281         TRACE("(%p)->(%ld,%p, %p)\n",This,celt,rgelt,pceltFetched);
282
283 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
284  * subsystems actually use it (and so may a third party browser)
285  */
286         if(pceltFetched)
287           *pceltFetched = 0;
288
289         *rgelt=0;
290
291         if(celt > 1 && !pceltFetched)
292         { return E_INVALIDARG;
293         }
294
295         if(celt > 0 && !This->mpCurrent)
296         { return S_FALSE;
297         }
298
299         for(i = 0; i < celt; i++)
300         { if(!(This->mpCurrent))
301             break;
302
303           temp = ILClone(This->mpCurrent->pidl);
304           rgelt[i] = temp;
305           This->mpCurrent = This->mpCurrent->pNext;
306         }
307         if(pceltFetched)
308         {  *pceltFetched = i;
309         }
310
311         return hr;
312 }
313
314 /**************************************************************************
315 *  IEnumIDList_fnSkip
316 */
317 static HRESULT WINAPI IEnumIDList_fnSkip(
318         IEnumIDList * iface,ULONG celt)
319 {
320         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
321
322         DWORD    dwIndex;
323         HRESULT  hr = S_OK;
324
325         TRACE("(%p)->(%lu)\n",This,celt);
326
327         for(dwIndex = 0; dwIndex < celt; dwIndex++)
328         { if(!This->mpCurrent)
329           { hr = S_FALSE;
330             break;
331           }
332           This->mpCurrent = This->mpCurrent->pNext;
333         }
334         return hr;
335 }
336 /**************************************************************************
337 *  IEnumIDList_fnReset
338 */
339 static HRESULT WINAPI IEnumIDList_fnReset(
340         IEnumIDList * iface)
341 {
342         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
343
344         TRACE("(%p)\n",This);
345         This->mpCurrent = This->mpFirst;
346         return S_OK;
347 }
348 /**************************************************************************
349 *  IEnumIDList_fnClone
350 */
351 static HRESULT WINAPI IEnumIDList_fnClone(
352         IEnumIDList * iface,LPENUMIDLIST * ppenum)
353 {
354         IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
355
356         TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
357         return E_NOTIMPL;
358 }
359
360 /**************************************************************************
361  *  IEnumIDList_fnVTable
362  */
363 static IEnumIDListVtbl eidlvt =
364 {
365         IEnumIDList_fnQueryInterface,
366         IEnumIDList_fnAddRef,
367         IEnumIDList_fnRelease,
368         IEnumIDList_fnNext,
369         IEnumIDList_fnSkip,
370         IEnumIDList_fnReset,
371         IEnumIDList_fnClone,
372 };