Ignore trailing dots on file names.
[wine/testsucceed.git] / dlls / shell32 / enumidlist.c
blob2d8d8d3983d2d3fc48eded252a027481cb80d436
1 /*
2 * IEnumIDList
4 * Copyright 1998 Juergen Schmied <juergen.schmied@metronet.de>
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include "debug.h"
10 #include "wine/obj_base.h"
11 #include "wine/obj_enumidlist.h"
12 #include "winerror.h"
14 #include "pidl.h"
15 #include "shlguid.h"
16 #include "shell32_main.h"
18 DEFAULT_DEBUG_CHANNEL(shell)
20 typedef struct tagENUMLIST
22 struct tagENUMLIST *pNext;
23 LPITEMIDLIST pidl;
25 } ENUMLIST, *LPENUMLIST;
27 typedef struct
29 ICOM_VTABLE(IEnumIDList)* lpvtbl;
30 DWORD ref;
31 LPENUMLIST mpFirst;
32 LPENUMLIST mpLast;
33 LPENUMLIST mpCurrent;
35 } IEnumIDListImpl;
37 static struct ICOM_VTABLE(IEnumIDList) eidlvt;
39 /**************************************************************************
40 * IEnumIDList_fnConstructor
43 IEnumIDList * IEnumIDList_Constructor(
44 LPCSTR lpszPath,
45 DWORD dwFlags)
46 { IEnumIDListImpl* lpeidl;
48 lpeidl = (IEnumIDListImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IEnumIDListImpl));
49 if (! lpeidl)
50 return NULL;
52 lpeidl->ref = 1;
53 lpeidl->lpvtbl = &eidlvt;
54 lpeidl->mpFirst=NULL;
55 lpeidl->mpLast=NULL;
56 lpeidl->mpCurrent=NULL;
58 TRACE(shell,"(%p)->(%s flags=0x%08lx)\n",lpeidl,debugstr_a(lpszPath),dwFlags);
60 if(!IEnumIDList_CreateEnumList((IEnumIDList*)lpeidl, lpszPath, dwFlags))
61 { if (lpeidl)
62 { HeapFree(GetProcessHeap(),0,lpeidl);
64 return NULL;
67 TRACE(shell,"-- (%p)->()\n",lpeidl);
68 shell32_ObjCount++;
69 return (IEnumIDList*)lpeidl;
72 /**************************************************************************
73 * EnumIDList_QueryInterface
75 static HRESULT WINAPI IEnumIDList_fnQueryInterface(
76 IEnumIDList * iface,
77 REFIID riid,
78 LPVOID *ppvObj)
80 ICOM_THIS(IEnumIDListImpl,iface);
82 char xriid[50];
83 WINE_StringFromCLSID((LPCLSID)riid,xriid);
84 TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
86 *ppvObj = NULL;
88 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
89 { *ppvObj = This;
91 else if(IsEqualIID(riid, &IID_IEnumIDList)) /*IEnumIDList*/
92 { *ppvObj = (IEnumIDList*)This;
95 if(*ppvObj)
96 { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
97 TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
98 return S_OK;
101 TRACE(shell,"-- Interface: E_NOINTERFACE\n");
102 return E_NOINTERFACE;
105 /******************************************************************************
106 * IEnumIDList_fnAddRef
108 static ULONG WINAPI IEnumIDList_fnAddRef(
109 IEnumIDList * iface)
111 ICOM_THIS(IEnumIDListImpl,iface);
113 TRACE(shell,"(%p)->(%lu)\n",This,This->ref);
115 shell32_ObjCount++;
116 return ++(This->ref);
118 /******************************************************************************
119 * IEnumIDList_fnRelease
121 static ULONG WINAPI IEnumIDList_fnRelease(
122 IEnumIDList * iface)
124 ICOM_THIS(IEnumIDListImpl,iface);
126 TRACE(shell,"(%p)->(%lu)\n",This,This->ref);
128 shell32_ObjCount--;
130 if (!--(This->ref))
131 { TRACE(shell," destroying IEnumIDList(%p)\n",This);
132 IEnumIDList_DeleteList((IEnumIDList*)This);
133 HeapFree(GetProcessHeap(),0,This);
134 return 0;
136 return This->ref;
139 /**************************************************************************
140 * IEnumIDList_fnNext
143 static HRESULT WINAPI IEnumIDList_fnNext(
144 IEnumIDList * iface,
145 ULONG celt,
146 LPITEMIDLIST * rgelt,
147 ULONG *pceltFetched)
149 ICOM_THIS(IEnumIDListImpl,iface);
151 ULONG i;
152 HRESULT hr = S_OK;
153 LPITEMIDLIST temp;
155 TRACE(shell,"(%p)->(%ld,%p, %p)\n",This,celt,rgelt,pceltFetched);
157 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
158 * subsystems actually use it (and so may a third party browser)
160 if(pceltFetched)
161 *pceltFetched = 0;
163 *rgelt=0;
165 if(celt > 1 && !pceltFetched)
166 { return E_INVALIDARG;
169 for(i = 0; i < celt; i++)
170 { if(!(This->mpCurrent))
171 { hr = S_FALSE;
172 break;
174 temp = ILClone(This->mpCurrent->pidl);
175 rgelt[i] = temp;
176 This->mpCurrent = This->mpCurrent->pNext;
178 if(pceltFetched)
179 { *pceltFetched = i;
182 return hr;
185 /**************************************************************************
186 * IEnumIDList_fnSkip
188 static HRESULT WINAPI IEnumIDList_fnSkip(
189 IEnumIDList * iface,ULONG celt)
191 ICOM_THIS(IEnumIDListImpl,iface);
193 DWORD dwIndex;
194 HRESULT hr = S_OK;
196 TRACE(shell,"(%p)->(%lu)\n",This,celt);
198 for(dwIndex = 0; dwIndex < celt; dwIndex++)
199 { if(!This->mpCurrent)
200 { hr = S_FALSE;
201 break;
203 This->mpCurrent = This->mpCurrent->pNext;
205 return hr;
207 /**************************************************************************
208 * IEnumIDList_fnReset
210 static HRESULT WINAPI IEnumIDList_fnReset(
211 IEnumIDList * iface)
213 ICOM_THIS(IEnumIDListImpl,iface);
215 TRACE(shell,"(%p)\n",This);
216 This->mpCurrent = This->mpFirst;
217 return S_OK;
219 /**************************************************************************
220 * IEnumIDList_fnClone
222 static HRESULT WINAPI IEnumIDList_fnClone(
223 IEnumIDList * iface,LPENUMIDLIST * ppenum)
225 ICOM_THIS(IEnumIDListImpl,iface);
227 TRACE(shell,"(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
228 return E_NOTIMPL;
230 /**************************************************************************
231 * EnumIDList_CreateEnumList()
232 * fixme: devices not handled
233 * fixme: add wildcards to path
235 static BOOL WINAPI IEnumIDList_fnCreateEnumList(
236 IEnumIDList * iface,
237 LPCSTR lpszPath,
238 DWORD dwFlags)
240 ICOM_THIS(IEnumIDListImpl,iface);
242 LPITEMIDLIST pidl=NULL;
243 LPPIDLDATA pData=NULL;
244 WIN32_FIND_DATAA stffile;
245 HANDLE hFile;
246 DWORD dwDrivemap;
247 CHAR szDriveName[4];
248 CHAR szPath[MAX_PATH];
250 TRACE(shell,"(%p)->(path=%s flags=0x%08lx) \n",This,debugstr_a(lpszPath),dwFlags);
252 if (lpszPath && lpszPath[0]!='\0')
253 { strcpy(szPath, lpszPath);
254 PathAddBackslashA(szPath);
255 strcat(szPath,"*.*");
258 /*enumerate the folders*/
259 if(dwFlags & SHCONTF_FOLDERS)
260 { /* special case - we can't enumerate the Desktop level Objects (MyComputer,Nethood...
261 so we need to fake an enumeration of those.*/
262 if(!lpszPath)
263 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (special) items\n",This);
264 /*create the pidl for This item */
265 pidl = _ILCreateMyComputer();
266 if(pidl)
267 { if(!IEnumIDList_AddToEnumList((IEnumIDList*)This, pidl))
268 return FALSE;
271 else if (lpszPath[0]=='\0') /* enumerate the drives*/
272 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (drives)\n",This);
273 dwDrivemap = GetLogicalDrives();
274 strcpy (szDriveName,"A:\\");
275 while (szDriveName[0]<='Z')
276 { if(dwDrivemap & 0x00000001L)
277 { pidl = _ILCreateDrive(szDriveName);
278 if(pidl)
279 { if(!IEnumIDList_AddToEnumList((IEnumIDList*)This, pidl))
280 return FALSE;
283 szDriveName[0]++;
284 dwDrivemap = dwDrivemap >> 1;
287 else
288 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",This,debugstr_a(szPath));
289 hFile = FindFirstFileA(szPath,&stffile);
290 if ( hFile != INVALID_HANDLE_VALUE )
291 { do
292 { if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
293 { pidl = _ILCreateFolder( stffile.cAlternateFileName, stffile.cFileName);
294 if(pidl)
295 { pData = _ILGetDataPointer(pidl);
296 FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.folder.uFileDate,&pData->u.folder.uFileTime);
297 pData->u.folder.dwFileSize = stffile.nFileSizeLow;
298 pData->u.folder.uFileAttribs=stffile.dwFileAttributes;
299 if(!IEnumIDList_AddToEnumList((IEnumIDList*)This, pidl))
300 { return FALSE;
303 else
304 { return FALSE;
307 } while( FindNextFileA(hFile,&stffile));
308 FindClose (hFile);
312 /*enumerate the non-folder items (values) */
313 if(dwFlags & SHCONTF_NONFOLDERS)
314 { if(lpszPath)
315 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",This,debugstr_a(szPath));
316 hFile = FindFirstFileA(szPath,&stffile);
317 if ( hFile != INVALID_HANDLE_VALUE )
318 { do
319 { if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
320 { pidl = _ILCreateValue( stffile.cAlternateFileName, stffile.cFileName);
321 if(pidl)
322 { pData = _ILGetDataPointer(pidl);
323 FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.file.uFileDate,&pData->u.file.uFileTime);
324 pData->u.file.dwFileSize = stffile.nFileSizeLow;
325 pData->u.file.uFileAttribs=stffile.dwFileAttributes;
326 if(!IEnumIDList_AddToEnumList((IEnumIDList*)This, pidl))
327 { return FALSE;
330 else
331 { return FALSE;
334 } while( FindNextFileA(hFile,&stffile));
335 FindClose (hFile);
339 return TRUE;
342 /**************************************************************************
343 * EnumIDList_AddToEnumList()
345 static BOOL WINAPI IEnumIDList_fnAddToEnumList(
346 IEnumIDList * iface,
347 LPITEMIDLIST pidl)
349 ICOM_THIS(IEnumIDListImpl,iface);
351 LPENUMLIST pNew;
353 TRACE(shell,"(%p)->(pidl=%p)\n",This,pidl);
354 pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
355 if(pNew)
356 { /*set the next pointer */
357 pNew->pNext = NULL;
358 pNew->pidl = pidl;
360 /*is This the first item in the list? */
361 if(!This->mpFirst)
362 { This->mpFirst = pNew;
363 This->mpCurrent = pNew;
366 if(This->mpLast)
367 { /*add the new item to the end of the list */
368 This->mpLast->pNext = pNew;
371 /*update the last item pointer */
372 This->mpLast = pNew;
373 TRACE(shell,"-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
374 return TRUE;
376 return FALSE;
378 /**************************************************************************
379 * EnumIDList_DeleteList()
381 static BOOL WINAPI IEnumIDList_fnDeleteList(
382 IEnumIDList * iface)
384 ICOM_THIS(IEnumIDListImpl,iface);
386 LPENUMLIST pDelete;
388 TRACE(shell,"(%p)->()\n",This);
390 while(This->mpFirst)
391 { pDelete = This->mpFirst;
392 This->mpFirst = pDelete->pNext;
393 SHFree(pDelete->pidl);
394 SHFree(pDelete);
396 This->mpFirst = This->mpLast = This->mpCurrent = NULL;
397 return TRUE;
400 /**************************************************************************
401 * IEnumIDList_fnVTable
403 static ICOM_VTABLE (IEnumIDList) eidlvt =
404 { IEnumIDList_fnQueryInterface,
405 IEnumIDList_fnAddRef,
406 IEnumIDList_fnRelease,
407 IEnumIDList_fnNext,
408 IEnumIDList_fnSkip,
409 IEnumIDList_fnReset,
410 IEnumIDList_fnClone,
411 IEnumIDList_fnCreateEnumList,
412 IEnumIDList_fnAddToEnumList,
413 IEnumIDList_fnDeleteList