[SHELLUTILS.H]
[reactos.git] / reactos / dll / win32 / shell32 / CEnumIDListBase.cpp
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 CEnumIDListBase::CEnumIDListBase()
26 {
27 mpFirst = NULL;
28 mpLast = NULL;
29 mpCurrent = NULL;
30 }
31
32 CEnumIDListBase::~CEnumIDListBase()
33 {
34 }
35
36 /**************************************************************************
37 * AddToEnumList()
38 */
39 BOOL CEnumIDListBase::AddToEnumList(LPITEMIDLIST pidl)
40 {
41 ENUMLIST *pNew;
42
43 TRACE("(%p)->(pidl=%p)\n", this, pidl);
44
45 if (!pidl)
46 return FALSE;
47
48 pNew = static_cast<ENUMLIST *>(SHAlloc(sizeof(ENUMLIST)));
49 if (pNew)
50 {
51 /*set the next pointer */
52 pNew->pNext = NULL;
53 pNew->pidl = pidl;
54
55 /*is This the first item in the list? */
56 if (!mpFirst)
57 {
58 mpFirst = pNew;
59 mpCurrent = pNew;
60 }
61
62 if (mpLast)
63 {
64 /*add the new item to the end of the list */
65 mpLast->pNext = pNew;
66 }
67
68 /*update the last item pointer */
69 mpLast = pNew;
70 TRACE("-- (%p)->(first=%p, last=%p)\n", this, mpFirst, mpLast);
71 return TRUE;
72 }
73 return FALSE;
74 }
75
76 /**************************************************************************
77 * DeleteList()
78 */
79 BOOL CEnumIDListBase::DeleteList()
80 {
81 ENUMLIST *pDelete;
82
83 TRACE("(%p)->()\n", this);
84
85 while (mpFirst)
86 {
87 pDelete = mpFirst;
88 mpFirst = pDelete->pNext;
89 SHFree(pDelete->pidl);
90 SHFree(pDelete);
91 }
92 mpFirst = NULL;
93 mpLast = NULL;
94 mpCurrent = NULL;
95 return TRUE;
96 }
97
98 /**************************************************************************
99 * HasItemWithCLSID()
100 */
101 BOOL CEnumIDListBase::HasItemWithCLSID(LPITEMIDLIST pidl)
102 {
103 ENUMLIST *pCur;
104 IID *ptr = _ILGetGUIDPointer(pidl);
105
106 if (ptr)
107 {
108 REFIID refid = *ptr;
109 pCur = mpFirst;
110
111 while(pCur)
112 {
113 LPGUID curid = _ILGetGUIDPointer(pCur->pidl);
114 if (curid && IsEqualGUID(*curid, refid))
115 {
116 return TRUE;
117 }
118 pCur = pCur->pNext;
119 }
120 }
121
122 return FALSE;
123 }
124
125
126 /**************************************************************************
127 * CreateFolderEnumList()
128 */
129 BOOL CEnumIDListBase::CreateFolderEnumList(
130 LPCWSTR lpszPath,
131 DWORD dwFlags)
132 {
133 WIN32_FIND_DATAW stffile;
134 HANDLE hFile;
135 WCHAR szPath[MAX_PATH];
136 BOOL succeeded = TRUE;
137 static const WCHAR stars[] = { '*','.','*',0 };
138 static const WCHAR dot[] = { '.',0 };
139 static const WCHAR dotdot[] = { '.','.',0 };
140
141 TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath), dwFlags);
142
143 if(!lpszPath || !lpszPath[0]) return FALSE;
144
145 wcscpy(szPath, lpszPath);
146 PathAddBackslashW(szPath);
147 wcscat(szPath,stars);
148
149 hFile = FindFirstFileW(szPath,&stffile);
150 if ( hFile != INVALID_HANDLE_VALUE )
151 {
152 BOOL findFinished = FALSE;
153
154 do
155 {
156 if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
157 || (dwFlags & SHCONTF_INCLUDEHIDDEN) )
158 {
159 LPITEMIDLIST pidl = NULL;
160
161 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
162 dwFlags & SHCONTF_FOLDERS &&
163 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
164 {
165 pidl = _ILCreateFromFindDataW(&stffile);
166 succeeded = succeeded && AddToEnumList(pidl);
167 }
168 else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
169 && dwFlags & SHCONTF_NONFOLDERS)
170 {
171 pidl = _ILCreateFromFindDataW(&stffile);
172 succeeded = succeeded && AddToEnumList(pidl);
173 }
174 }
175 if (succeeded)
176 {
177 if (!FindNextFileW(hFile, &stffile))
178 {
179 if (GetLastError() == ERROR_NO_MORE_FILES)
180 findFinished = TRUE;
181 else
182 succeeded = FALSE;
183 }
184 }
185 } while (succeeded && !findFinished);
186 FindClose(hFile);
187 }
188
189 return succeeded;
190 }
191
192 /**************************************************************************
193 * IEnumIDList_fnNext
194 */
195
196 HRESULT WINAPI CEnumIDListBase::Next(
197 ULONG celt,
198 LPITEMIDLIST * rgelt,
199 ULONG *pceltFetched)
200 {
201 ULONG i;
202 HRESULT hr = S_OK;
203 LPITEMIDLIST temp;
204
205 TRACE("(%p)->(%d,%p, %p)\n", this, celt, rgelt, pceltFetched);
206
207 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
208 * subsystems actually use it (and so may a third party browser)
209 */
210 if(pceltFetched)
211 *pceltFetched = 0;
212
213 *rgelt=0;
214
215 if(celt > 1 && !pceltFetched)
216 { return E_INVALIDARG;
217 }
218
219 if(celt > 0 && !mpCurrent)
220 { return S_FALSE;
221 }
222
223 for(i = 0; i < celt; i++)
224 { if(!mpCurrent)
225 break;
226
227 temp = ILClone(mpCurrent->pidl);
228 rgelt[i] = temp;
229 mpCurrent = mpCurrent->pNext;
230 }
231 if(pceltFetched)
232 { *pceltFetched = i;
233 }
234
235 return hr;
236 }
237
238 /**************************************************************************
239 * IEnumIDList_fnSkip
240 */
241 HRESULT WINAPI CEnumIDListBase::Skip(
242 ULONG celt)
243 {
244 DWORD dwIndex;
245 HRESULT hr = S_OK;
246
247 TRACE("(%p)->(%u)\n", this, celt);
248
249 for(dwIndex = 0; dwIndex < celt; dwIndex++)
250 { if(!mpCurrent)
251 { hr = S_FALSE;
252 break;
253 }
254 mpCurrent = mpCurrent->pNext;
255 }
256 return hr;
257 }
258
259 /**************************************************************************
260 * IEnumIDList_fnReset
261 */
262 HRESULT WINAPI CEnumIDListBase::Reset()
263 {
264 TRACE("(%p)\n", this);
265 mpCurrent = mpFirst;
266 return S_OK;
267 }
268
269 /**************************************************************************
270 * IEnumIDList_fnClone
271 */
272 HRESULT WINAPI CEnumIDListBase::Clone(LPENUMIDLIST *ppenum)
273 {
274 TRACE("(%p)->() to (%p)->() E_NOTIMPL\n", this, ppenum);
275 return E_NOTIMPL;
276 }
277
278 /**************************************************************************
279 * IEnumIDList_Folder_Constructor
280 *
281 */
282 HRESULT IEnumIDList_Constructor(IEnumIDList **enumerator)
283 {
284 return ShellObjectCreator<CEnumIDListBase>(IID_PPV_ARG(IEnumIDList, enumerator));
285 }