cmd: Introduce helpers to handle directory walk.
[wine.git] / dlls / shell32 / enumidlist.c
blobb07bce09bac2417061c80cdf101f92d8e21c056e
1 /*
2 * IEnumIDList
4 * Copyright 1998 Juergen Schmied <juergen.schmied@metronet.de>
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.
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.
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
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #define COBJMACROS
27 #include "wine/debug.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "shlwapi.h"
33 #include "pidl.h"
34 #include "shell32_main.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(shell);
38 /**************************************************************************
39 * AddToEnumList()
41 BOOL AddToEnumList(IEnumIDListImpl *list, LPITEMIDLIST pidl)
43 struct pidl_enum_entry *pidl_entry;
45 TRACE("(%p)->(pidl=%p)\n", list, pidl);
47 if (!list || !pidl)
48 return FALSE;
50 if (!(pidl_entry = SHAlloc(sizeof(*pidl_entry))))
51 return FALSE;
53 pidl_entry->pidl = pidl;
54 list_add_tail(&list->pidls, &pidl_entry->entry);
55 if (!list->current)
56 list->current = list_head(&list->pidls);
58 return TRUE;
61 /**************************************************************************
62 * CreateFolderEnumList()
64 BOOL CreateFolderEnumList(IEnumIDListImpl *list, LPCWSTR lpszPath, DWORD dwFlags)
66 LPITEMIDLIST pidl=NULL;
67 WIN32_FIND_DATAW stffile;
68 HANDLE hFile;
69 WCHAR szPath[MAX_PATH];
70 BOOL succeeded = TRUE;
72 TRACE("(%p)->(path=%s flags=0x%08lx)\n", list, debugstr_w(lpszPath), dwFlags);
74 if(!lpszPath || !lpszPath[0]) return FALSE;
76 lstrcpyW(szPath, lpszPath);
77 PathAddBackslashW(szPath);
78 lstrcatW(szPath,L"*");
80 hFile = FindFirstFileW(szPath,&stffile);
81 if ( hFile != INVALID_HANDLE_VALUE )
83 BOOL findFinished = FALSE;
87 if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
88 || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
90 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
91 dwFlags & SHCONTF_FOLDERS &&
92 wcscmp(stffile.cFileName, L".") && wcscmp(stffile.cFileName, L".."))
94 pidl = _ILCreateFromFindDataW(&stffile);
95 succeeded = succeeded && AddToEnumList(list, pidl);
97 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
98 && dwFlags & SHCONTF_NONFOLDERS)
100 pidl = _ILCreateFromFindDataW(&stffile);
101 succeeded = succeeded && AddToEnumList(list, pidl);
104 if (succeeded)
106 if (!FindNextFileW(hFile, &stffile))
108 if (GetLastError() == ERROR_NO_MORE_FILES)
109 findFinished = TRUE;
110 else
111 succeeded = FALSE;
114 } while (succeeded && !findFinished);
115 FindClose(hFile);
117 return succeeded;
120 static inline IEnumIDListImpl *impl_from_IEnumIDList(IEnumIDList *iface)
122 return CONTAINING_RECORD(iface, IEnumIDListImpl, IEnumIDList_iface);
125 /**************************************************************************
126 * IEnumIDList::QueryInterface
128 static HRESULT WINAPI IEnumIDList_fnQueryInterface(IEnumIDList *iface, REFIID riid, void **ppvObj)
130 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
132 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj);
134 *ppvObj = NULL;
136 if (IsEqualIID(riid, &IID_IUnknown) ||
137 IsEqualIID(riid, &IID_IEnumIDList))
139 *ppvObj = &This->IEnumIDList_iface;
142 if (*ppvObj)
144 IUnknown_AddRef((IUnknown*)*ppvObj);
145 return S_OK;
148 WARN("interface %s is not supported\n", debugstr_guid(riid));
149 return E_NOINTERFACE;
152 /******************************************************************************
153 * IEnumIDList::AddRef
155 static ULONG WINAPI IEnumIDList_fnAddRef(IEnumIDList *iface)
157 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
158 ULONG refCount = InterlockedIncrement(&This->ref);
160 TRACE("(%p)->(%lu)\n", This, refCount - 1);
162 return refCount;
165 /******************************************************************************
166 * IEnumIDList::Release
168 static ULONG WINAPI IEnumIDList_fnRelease(IEnumIDList *iface)
170 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
171 ULONG refCount = InterlockedDecrement(&This->ref);
173 TRACE("(%p)->(%lu)\n", This, refCount + 1);
175 if (!refCount)
177 struct pidl_enum_entry *cur, *cur2;
179 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &This->pidls, struct pidl_enum_entry, entry)
181 list_remove(&cur->entry);
182 SHFree(cur->pidl);
183 SHFree(cur);
185 free(This);
188 return refCount;
191 /**************************************************************************
192 * IEnumIDList::Next
195 static HRESULT WINAPI IEnumIDList_fnNext(IEnumIDList *iface, ULONG celt, LPITEMIDLIST *rgelt,
196 ULONG *fetched)
198 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
199 HRESULT hr = S_OK;
200 ULONG i;
202 TRACE("(%p)->(%ld, %p, %p)\n", This, celt, rgelt, fetched);
204 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
205 * subsystems actually use it (and so may a third party browser)
207 if (fetched)
208 *fetched = 0;
210 *rgelt = NULL;
212 if (celt > 1 && !fetched)
213 return E_INVALIDARG;
215 if (celt > 0 && !This->current)
216 return S_FALSE;
218 for (i = 0; i < celt; i++)
220 if (!This->current)
221 break;
223 rgelt[i] = ILClone(LIST_ENTRY(This->current, struct pidl_enum_entry, entry)->pidl);
224 This->current = list_next(&This->pidls, This->current);
227 if (fetched)
228 *fetched = i;
230 return hr;
233 /**************************************************************************
234 * IEnumIDList::Skip
236 static HRESULT WINAPI IEnumIDList_fnSkip(IEnumIDList *iface, ULONG celt)
238 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
239 HRESULT hr = S_OK;
240 ULONG i;
242 TRACE("(%p)->(%lu)\n", This, celt);
244 for (i = 0; i < celt; i++)
246 if (!This->current)
248 hr = S_FALSE;
249 break;
251 This->current = list_next(&This->pidls, This->current);
254 return hr;
257 /**************************************************************************
258 * IEnumIDList::Reset
260 static HRESULT WINAPI IEnumIDList_fnReset(IEnumIDList *iface)
262 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
264 TRACE("(%p)\n",This);
265 This->current = list_head(&This->pidls);
266 return S_OK;
269 /**************************************************************************
270 * IEnumIDList::Clone
272 static HRESULT WINAPI IEnumIDList_fnClone(IEnumIDList *iface, IEnumIDList **ppenum)
274 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
276 FIXME("(%p)->(%p): stub\n",This, ppenum);
278 return E_NOTIMPL;
281 static const IEnumIDListVtbl eidlvt =
283 IEnumIDList_fnQueryInterface,
284 IEnumIDList_fnAddRef,
285 IEnumIDList_fnRelease,
286 IEnumIDList_fnNext,
287 IEnumIDList_fnSkip,
288 IEnumIDList_fnReset,
289 IEnumIDList_fnClone,
292 IEnumIDListImpl *IEnumIDList_Constructor(void)
294 IEnumIDListImpl *lpeidl = malloc(sizeof(*lpeidl));
296 if (lpeidl)
298 lpeidl->IEnumIDList_iface.lpVtbl = &eidlvt;
299 lpeidl->ref = 1;
300 list_init(&lpeidl->pidls);
301 lpeidl->current = NULL;
304 TRACE("-- (%p)->()\n",lpeidl);
306 return lpeidl;