- Implement ProtocolResetComplete
[reactos.git] / dll / win32 / 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 "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 const IEnumIDListVtbl *lpVtbl;
49 LONG ref;
50 LPENUMLIST mpFirst;
51 LPENUMLIST mpLast;
52 LPENUMLIST mpCurrent;
53
54 } IEnumIDListImpl;
55
56 static const IEnumIDListVtbl eidlvt;
57
58 /**************************************************************************
59 * AddToEnumList()
60 */
61 BOOL AddToEnumList(
62 IEnumIDList * iface,
63 LPITEMIDLIST pidl)
64 {
65 IEnumIDListImpl *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 * HasItemWithCLSID()
103 */
104 BOOL HasItemWithCLSID(IEnumIDList *iface, LPITEMIDLIST pidl)
105 {
106 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
107 LPENUMLIST pCur;
108 REFIID refid = _ILGetGUIDPointer(pidl);
109
110 pCur = This->mpFirst;
111
112 while(pCur)
113 {
114 REFIID curid = _ILGetGUIDPointer(pCur->pidl);
115 if (IsEqualIID(curid, refid))
116 {
117 return TRUE;
118 }
119 pCur = pCur->pNext;
120 }
121 return FALSE;
122 }
123
124
125 /**************************************************************************
126 * CreateFolderEnumList()
127 */
128 BOOL CreateFolderEnumList(
129 IEnumIDList *list,
130 LPCWSTR lpszPath,
131 DWORD dwFlags)
132 {
133 LPITEMIDLIST pidl=NULL;
134 WIN32_FIND_DATAW stffile;
135 HANDLE hFile;
136 WCHAR szPath[MAX_PATH];
137 BOOL succeeded = TRUE;
138 static const WCHAR stars[] = { '*','.','*',0 };
139 static const WCHAR dot[] = { '.',0 };
140 static const WCHAR dotdot[] = { '.','.',0 };
141
142 TRACE("(%p)->(path=%s flags=0x%08x)\n", list, debugstr_w(lpszPath), dwFlags);
143
144 if(!lpszPath || !lpszPath[0]) return FALSE;
145
146 strcpyW(szPath, lpszPath);
147 PathAddBackslashW(szPath);
148 strcatW(szPath,stars);
149
150 hFile = FindFirstFileW(szPath,&stffile);
151 if ( hFile != INVALID_HANDLE_VALUE )
152 {
153 BOOL findFinished = FALSE;
154
155 do
156 {
157 if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
158 || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
159 {
160 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
161 dwFlags & SHCONTF_FOLDERS &&
162 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
163 {
164 pidl = _ILCreateFromFindDataW(&stffile);
165 succeeded = succeeded && AddToEnumList(list, pidl);
166 }
167 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
168 && dwFlags & SHCONTF_NONFOLDERS)
169 {
170 pidl = _ILCreateFromFindDataW(&stffile);
171 succeeded = succeeded && AddToEnumList(list, pidl);
172 }
173 }
174 if (succeeded)
175 {
176 if (!FindNextFileW(hFile, &stffile))
177 {
178 if (GetLastError() == ERROR_NO_MORE_FILES)
179 findFinished = TRUE;
180 else
181 succeeded = FALSE;
182 }
183 }
184 } while (succeeded && !findFinished);
185 FindClose(hFile);
186 }
187 return succeeded;
188 }
189
190 /**************************************************************************
191 * DeleteList()
192 */
193 static BOOL DeleteList(
194 IEnumIDList * iface)
195 {
196 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
197
198 LPENUMLIST pDelete;
199
200 TRACE("(%p)->()\n",This);
201
202 while(This->mpFirst)
203 { pDelete = This->mpFirst;
204 This->mpFirst = pDelete->pNext;
205 SHFree(pDelete->pidl);
206 SHFree(pDelete);
207 }
208 This->mpFirst = This->mpLast = This->mpCurrent = NULL;
209 return TRUE;
210 }
211
212 /**************************************************************************
213 * IEnumIDList_Folder_Constructor
214 *
215 */
216
217 IEnumIDList * IEnumIDList_Constructor(void)
218 {
219 IEnumIDListImpl *lpeidl = HeapAlloc(GetProcessHeap(),
220 HEAP_ZERO_MEMORY, sizeof(IEnumIDListImpl));
221
222 if (lpeidl)
223 {
224 lpeidl->ref = 1;
225 lpeidl->lpVtbl = &eidlvt;
226 }
227 TRACE("-- (%p)->()\n",lpeidl);
228
229 return (IEnumIDList*)lpeidl;
230 }
231
232 /**************************************************************************
233 * EnumIDList_QueryInterface
234 */
235 static HRESULT WINAPI IEnumIDList_fnQueryInterface(
236 IEnumIDList * iface,
237 REFIID riid,
238 LPVOID *ppvObj)
239 {
240 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
241
242 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
243
244 *ppvObj = NULL;
245
246 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
247 { *ppvObj = This;
248 }
249 else if(IsEqualIID(riid, &IID_IEnumIDList)) /*IEnumIDList*/
250 { *ppvObj = (IEnumIDList*)This;
251 }
252
253 if(*ppvObj)
254 { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
255 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
256 return S_OK;
257 }
258
259 TRACE("-- Interface: E_NOINTERFACE\n");
260 return E_NOINTERFACE;
261 }
262
263 /******************************************************************************
264 * IEnumIDList_fnAddRef
265 */
266 static ULONG WINAPI IEnumIDList_fnAddRef(
267 IEnumIDList * iface)
268 {
269 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
270 ULONG refCount = InterlockedIncrement(&This->ref);
271
272 TRACE("(%p)->(%u)\n", This, refCount - 1);
273
274 return refCount;
275 }
276 /******************************************************************************
277 * IEnumIDList_fnRelease
278 */
279 static ULONG WINAPI IEnumIDList_fnRelease(
280 IEnumIDList * iface)
281 {
282 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
283 ULONG refCount = InterlockedDecrement(&This->ref);
284
285 TRACE("(%p)->(%u)\n", This, refCount + 1);
286
287 if (!refCount) {
288 TRACE(" destroying IEnumIDList(%p)\n",This);
289 DeleteList((IEnumIDList*)This);
290 HeapFree(GetProcessHeap(),0,This);
291 }
292 return refCount;
293 }
294
295 /**************************************************************************
296 * IEnumIDList_fnNext
297 */
298
299 static HRESULT WINAPI IEnumIDList_fnNext(
300 IEnumIDList * iface,
301 ULONG celt,
302 LPITEMIDLIST * rgelt,
303 ULONG *pceltFetched)
304 {
305 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
306
307 ULONG i;
308 HRESULT hr = S_OK;
309 LPITEMIDLIST temp;
310
311 TRACE("(%p)->(%d,%p, %p)\n",This,celt,rgelt,pceltFetched);
312
313 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
314 * subsystems actually use it (and so may a third party browser)
315 */
316 if(pceltFetched)
317 *pceltFetched = 0;
318
319 *rgelt=0;
320
321 if(celt > 1 && !pceltFetched)
322 { return E_INVALIDARG;
323 }
324
325 if(celt > 0 && !This->mpCurrent)
326 { return S_FALSE;
327 }
328
329 for(i = 0; i < celt; i++)
330 { if(!(This->mpCurrent))
331 break;
332
333 temp = ILClone(This->mpCurrent->pidl);
334 rgelt[i] = temp;
335 This->mpCurrent = This->mpCurrent->pNext;
336 }
337 if(pceltFetched)
338 { *pceltFetched = i;
339 }
340
341 return hr;
342 }
343
344 /**************************************************************************
345 * IEnumIDList_fnSkip
346 */
347 static HRESULT WINAPI IEnumIDList_fnSkip(
348 IEnumIDList * iface,ULONG celt)
349 {
350 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
351
352 DWORD dwIndex;
353 HRESULT hr = S_OK;
354
355 TRACE("(%p)->(%u)\n",This,celt);
356
357 for(dwIndex = 0; dwIndex < celt; dwIndex++)
358 { if(!This->mpCurrent)
359 { hr = S_FALSE;
360 break;
361 }
362 This->mpCurrent = This->mpCurrent->pNext;
363 }
364 return hr;
365 }
366 /**************************************************************************
367 * IEnumIDList_fnReset
368 */
369 static HRESULT WINAPI IEnumIDList_fnReset(
370 IEnumIDList * iface)
371 {
372 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
373
374 TRACE("(%p)\n",This);
375 This->mpCurrent = This->mpFirst;
376 return S_OK;
377 }
378 /**************************************************************************
379 * IEnumIDList_fnClone
380 */
381 static HRESULT WINAPI IEnumIDList_fnClone(
382 IEnumIDList * iface,LPENUMIDLIST * ppenum)
383 {
384 IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
385
386 TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
387 return E_NOTIMPL;
388 }
389
390 /**************************************************************************
391 * IEnumIDList_fnVTable
392 */
393 static const IEnumIDListVtbl eidlvt =
394 {
395 IEnumIDList_fnQueryInterface,
396 IEnumIDList_fnAddRef,
397 IEnumIDList_fnRelease,
398 IEnumIDList_fnNext,
399 IEnumIDList_fnSkip,
400 IEnumIDList_fnReset,
401 IEnumIDList_fnClone,
402 };