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