widl: Strip last separator in append_namespaces if suffix is NULL.
[wine.git] / dlls / shell32 / enumidlist.c
blob3c28426ce438ac38ff0eaed59e204598680d2765
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 "wine/unicode.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "shlwapi.h"
34 #include "pidl.h"
35 #include "shell32_main.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(shell);
39 /**************************************************************************
40 * AddToEnumList()
42 BOOL AddToEnumList(IEnumIDListImpl *list, LPITEMIDLIST pidl)
44 struct pidl_enum_entry *pidl_entry;
46 TRACE("(%p)->(pidl=%p)\n", list, pidl);
48 if (!list || !pidl)
49 return FALSE;
51 if (!(pidl_entry = SHAlloc(sizeof(*pidl_entry))))
52 return FALSE;
54 pidl_entry->pidl = pidl;
55 list_add_tail(&list->pidls, &pidl_entry->entry);
56 if (!list->current)
57 list->current = list_head(&list->pidls);
59 return TRUE;
62 /**************************************************************************
63 * CreateFolderEnumList()
65 BOOL CreateFolderEnumList(IEnumIDListImpl *list, LPCWSTR lpszPath, DWORD dwFlags)
67 LPITEMIDLIST pidl=NULL;
68 WIN32_FIND_DATAW stffile;
69 HANDLE hFile;
70 WCHAR szPath[MAX_PATH];
71 BOOL succeeded = TRUE;
72 static const WCHAR stars[] = { '*','.','*',0 };
73 static const WCHAR dot[] = { '.',0 };
74 static const WCHAR dotdot[] = { '.','.',0 };
76 TRACE("(%p)->(path=%s flags=0x%08x)\n", list, debugstr_w(lpszPath), dwFlags);
78 if(!lpszPath || !lpszPath[0]) return FALSE;
80 strcpyW(szPath, lpszPath);
81 PathAddBackslashW(szPath);
82 strcatW(szPath,stars);
84 hFile = FindFirstFileW(szPath,&stffile);
85 if ( hFile != INVALID_HANDLE_VALUE )
87 BOOL findFinished = FALSE;
91 if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
92 || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
94 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
95 dwFlags & SHCONTF_FOLDERS &&
96 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
98 pidl = _ILCreateFromFindDataW(&stffile);
99 succeeded = succeeded && AddToEnumList(list, pidl);
101 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
102 && dwFlags & SHCONTF_NONFOLDERS)
104 pidl = _ILCreateFromFindDataW(&stffile);
105 succeeded = succeeded && AddToEnumList(list, pidl);
108 if (succeeded)
110 if (!FindNextFileW(hFile, &stffile))
112 if (GetLastError() == ERROR_NO_MORE_FILES)
113 findFinished = TRUE;
114 else
115 succeeded = FALSE;
118 } while (succeeded && !findFinished);
119 FindClose(hFile);
121 return succeeded;
124 static inline IEnumIDListImpl *impl_from_IEnumIDList(IEnumIDList *iface)
126 return CONTAINING_RECORD(iface, IEnumIDListImpl, IEnumIDList_iface);
129 /**************************************************************************
130 * IEnumIDList::QueryInterface
132 static HRESULT WINAPI IEnumIDList_fnQueryInterface(IEnumIDList *iface, REFIID riid, void **ppvObj)
134 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
136 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj);
138 *ppvObj = NULL;
140 if (IsEqualIID(riid, &IID_IUnknown) ||
141 IsEqualIID(riid, &IID_IEnumIDList))
143 *ppvObj = &This->IEnumIDList_iface;
146 if (*ppvObj)
148 IUnknown_AddRef((IUnknown*)*ppvObj);
149 return S_OK;
152 WARN("interface %s is not supported\n", debugstr_guid(riid));
153 return E_NOINTERFACE;
156 /******************************************************************************
157 * IEnumIDList::AddRef
159 static ULONG WINAPI IEnumIDList_fnAddRef(IEnumIDList *iface)
161 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
162 ULONG refCount = InterlockedIncrement(&This->ref);
164 TRACE("(%p)->(%u)\n", This, refCount - 1);
166 return refCount;
169 /******************************************************************************
170 * IEnumIDList::Release
172 static ULONG WINAPI IEnumIDList_fnRelease(IEnumIDList *iface)
174 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
175 ULONG refCount = InterlockedDecrement(&This->ref);
177 TRACE("(%p)->(%u)\n", This, refCount + 1);
179 if (!refCount)
181 struct pidl_enum_entry *cur, *cur2;
183 LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &This->pidls, struct pidl_enum_entry, entry)
185 list_remove(&cur->entry);
186 SHFree(cur->pidl);
187 SHFree(cur);
189 heap_free(This);
192 return refCount;
195 /**************************************************************************
196 * IEnumIDList::Next
199 static HRESULT WINAPI IEnumIDList_fnNext(IEnumIDList *iface, ULONG celt, LPITEMIDLIST *rgelt,
200 ULONG *fetched)
202 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
203 HRESULT hr = S_OK;
204 ULONG i;
206 TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, fetched);
208 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
209 * subsystems actually use it (and so may a third party browser)
211 if (fetched)
212 *fetched = 0;
214 *rgelt = NULL;
216 if (celt > 1 && !fetched)
217 return E_INVALIDARG;
219 if (celt > 0 && !This->current)
220 return S_FALSE;
222 for (i = 0; i < celt; i++)
224 if (!This->current)
225 break;
227 rgelt[i] = ILClone(LIST_ENTRY(This->current, struct pidl_enum_entry, entry)->pidl);
228 This->current = list_next(&This->pidls, This->current);
231 if (fetched)
232 *fetched = i;
234 return hr;
237 /**************************************************************************
238 * IEnumIDList::Skip
240 static HRESULT WINAPI IEnumIDList_fnSkip(IEnumIDList *iface, ULONG celt)
242 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
243 HRESULT hr = S_OK;
244 ULONG i;
246 TRACE("(%p)->(%u)\n", This, celt);
248 for (i = 0; i < celt; i++)
250 if (!This->current)
252 hr = S_FALSE;
253 break;
255 This->current = list_next(&This->pidls, This->current);
258 return hr;
261 /**************************************************************************
262 * IEnumIDList::Reset
264 static HRESULT WINAPI IEnumIDList_fnReset(IEnumIDList *iface)
266 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
268 TRACE("(%p)\n",This);
269 This->current = list_head(&This->pidls);
270 return S_OK;
273 /**************************************************************************
274 * IEnumIDList::Clone
276 static HRESULT WINAPI IEnumIDList_fnClone(IEnumIDList *iface, IEnumIDList **ppenum)
278 IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
280 FIXME("(%p)->(%p): stub\n",This, ppenum);
282 return E_NOTIMPL;
285 static const IEnumIDListVtbl eidlvt =
287 IEnumIDList_fnQueryInterface,
288 IEnumIDList_fnAddRef,
289 IEnumIDList_fnRelease,
290 IEnumIDList_fnNext,
291 IEnumIDList_fnSkip,
292 IEnumIDList_fnReset,
293 IEnumIDList_fnClone,
296 IEnumIDListImpl *IEnumIDList_Constructor(void)
298 IEnumIDListImpl *lpeidl = heap_alloc(sizeof(*lpeidl));
300 if (lpeidl)
302 lpeidl->IEnumIDList_iface.lpVtbl = &eidlvt;
303 lpeidl->ref = 1;
304 list_init(&lpeidl->pidls);
305 lpeidl->current = NULL;
308 TRACE("-- (%p)->()\n",lpeidl);
310 return lpeidl;