- IShellFolder and IEnumIDList are using the new COM headers
[wine/wine-kai.git] / dlls / shell32 / enumidlist.c
blobcb1ae179c6c86c4bf94ff9601ffb8ab9d7032dc6
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 typedef struct tagENUMLIST
20 struct tagENUMLIST *pNext;
21 LPITEMIDLIST pidl;
23 } ENUMLIST, *LPENUMLIST;
25 typedef struct
27 ICOM_VTABLE(IEnumIDList)* lpvtbl;
28 DWORD ref;
29 LPENUMLIST mpFirst;
30 LPENUMLIST mpLast;
31 LPENUMLIST mpCurrent;
33 } IEnumIDListImpl;
35 static struct ICOM_VTABLE(IEnumIDList) eidlvt;
37 /**************************************************************************
38 * IEnumIDList_fnConstructor
41 IEnumIDList * IEnumIDList_Constructor(
42 LPCSTR lpszPath,
43 DWORD dwFlags)
44 { IEnumIDListImpl* lpeidl;
46 lpeidl = (IEnumIDListImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IEnumIDListImpl));
47 if (! lpeidl)
48 return NULL;
50 lpeidl->ref = 1;
51 lpeidl->lpvtbl = &eidlvt;
52 lpeidl->mpFirst=NULL;
53 lpeidl->mpLast=NULL;
54 lpeidl->mpCurrent=NULL;
56 TRACE(shell,"(%p)->(%s flags=0x%08lx)\n",lpeidl,debugstr_a(lpszPath),dwFlags);
58 if(!IEnumIDList_CreateEnumList((IEnumIDList*)lpeidl, lpszPath, dwFlags))
59 { if (lpeidl)
60 { HeapFree(GetProcessHeap(),0,lpeidl);
62 return NULL;
65 TRACE(shell,"-- (%p)->()\n",lpeidl);
66 shell32_ObjCount++;
67 return (IEnumIDList*)lpeidl;
70 /**************************************************************************
71 * EnumIDList_QueryInterface
73 static HRESULT WINAPI IEnumIDList_fnQueryInterface(
74 IEnumIDList * iface,
75 REFIID riid,
76 LPVOID *ppvObj)
78 ICOM_THIS(IEnumIDListImpl,iface);
80 char xriid[50];
81 WINE_StringFromCLSID((LPCLSID)riid,xriid);
82 TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj);
84 *ppvObj = NULL;
86 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
87 { *ppvObj = This;
89 else if(IsEqualIID(riid, &IID_IEnumIDList)) /*IEnumIDList*/
90 { *ppvObj = (IEnumIDList*)This;
93 if(*ppvObj)
94 { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
95 TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
96 return S_OK;
99 TRACE(shell,"-- Interface: E_NOINTERFACE\n");
100 return E_NOINTERFACE;
103 /******************************************************************************
104 * IEnumIDList_fnAddRef
106 static ULONG WINAPI IEnumIDList_fnAddRef(
107 IEnumIDList * iface)
109 ICOM_THIS(IEnumIDListImpl,iface);
111 TRACE(shell,"(%p)->(%lu)\n",This,This->ref);
113 shell32_ObjCount++;
114 return ++(This->ref);
116 /******************************************************************************
117 * IEnumIDList_fnRelease
119 static ULONG WINAPI IEnumIDList_fnRelease(
120 IEnumIDList * iface)
122 ICOM_THIS(IEnumIDListImpl,iface);
124 TRACE(shell,"(%p)->(%lu)\n",This,This->ref);
126 shell32_ObjCount--;
128 if (!--(This->ref))
129 { TRACE(shell," destroying IEnumIDList(%p)\n",This);
130 IEnumIDList_DeleteList((IEnumIDList*)This);
131 HeapFree(GetProcessHeap(),0,This);
132 return 0;
134 return This->ref;
137 /**************************************************************************
138 * IEnumIDList_fnNext
141 static HRESULT WINAPI IEnumIDList_fnNext(
142 IEnumIDList * iface,
143 ULONG celt,
144 LPITEMIDLIST * rgelt,
145 ULONG *pceltFetched)
147 ICOM_THIS(IEnumIDListImpl,iface);
149 ULONG i;
150 HRESULT hr = S_OK;
151 LPITEMIDLIST temp;
153 TRACE(shell,"(%p)->(%ld,%p, %p)\n",This,celt,rgelt,pceltFetched);
155 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
156 * subsystems actually use it (and so may a third party browser)
158 if(pceltFetched)
159 *pceltFetched = 0;
161 *rgelt=0;
163 if(celt > 1 && !pceltFetched)
164 { return E_INVALIDARG;
167 for(i = 0; i < celt; i++)
168 { if(!(This->mpCurrent))
169 { hr = S_FALSE;
170 break;
172 temp = ILClone(This->mpCurrent->pidl);
173 rgelt[i] = temp;
174 This->mpCurrent = This->mpCurrent->pNext;
176 if(pceltFetched)
177 { *pceltFetched = i;
180 return hr;
183 /**************************************************************************
184 * IEnumIDList_fnSkip
186 static HRESULT WINAPI IEnumIDList_fnSkip(
187 IEnumIDList * iface,ULONG celt)
189 ICOM_THIS(IEnumIDListImpl,iface);
191 DWORD dwIndex;
192 HRESULT hr = S_OK;
194 TRACE(shell,"(%p)->(%lu)\n",This,celt);
196 for(dwIndex = 0; dwIndex < celt; dwIndex++)
197 { if(!This->mpCurrent)
198 { hr = S_FALSE;
199 break;
201 This->mpCurrent = This->mpCurrent->pNext;
203 return hr;
205 /**************************************************************************
206 * IEnumIDList_fnReset
208 static HRESULT WINAPI IEnumIDList_fnReset(
209 IEnumIDList * iface)
211 ICOM_THIS(IEnumIDListImpl,iface);
213 TRACE(shell,"(%p)\n",This);
214 This->mpCurrent = This->mpFirst;
215 return S_OK;
217 /**************************************************************************
218 * IEnumIDList_fnClone
220 static HRESULT WINAPI IEnumIDList_fnClone(
221 IEnumIDList * iface,LPENUMIDLIST * ppenum)
223 ICOM_THIS(IEnumIDListImpl,iface);
225 TRACE(shell,"(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
226 return E_NOTIMPL;
228 /**************************************************************************
229 * EnumIDList_CreateEnumList()
230 * fixme: devices not handled
231 * fixme: add wildcards to path
233 static BOOL WINAPI IEnumIDList_fnCreateEnumList(
234 IEnumIDList * iface,
235 LPCSTR lpszPath,
236 DWORD dwFlags)
238 ICOM_THIS(IEnumIDListImpl,iface);
240 LPITEMIDLIST pidl=NULL;
241 LPPIDLDATA pData=NULL;
242 WIN32_FIND_DATAA stffile;
243 HANDLE hFile;
244 DWORD dwDrivemap;
245 CHAR szDriveName[4];
246 CHAR szPath[MAX_PATH];
248 TRACE(shell,"(%p)->(path=%s flags=0x%08lx) \n",This,debugstr_a(lpszPath),dwFlags);
250 if (lpszPath && lpszPath[0]!='\0')
251 { strcpy(szPath, lpszPath);
252 PathAddBackslashA(szPath);
253 strcat(szPath,"*.*");
256 /*enumerate the folders*/
257 if(dwFlags & SHCONTF_FOLDERS)
258 { /* special case - we can't enumerate the Desktop level Objects (MyComputer,Nethood...
259 so we need to fake an enumeration of those.*/
260 if(!lpszPath)
261 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (special) items\n",This);
262 /*create the pidl for This item */
263 pidl = _ILCreateMyComputer();
264 if(pidl)
265 { if(!IEnumIDList_AddToEnumList((IEnumIDList*)This, pidl))
266 return FALSE;
269 else if (lpszPath[0]=='\0') /* enumerate the drives*/
270 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (drives)\n",This);
271 dwDrivemap = GetLogicalDrives();
272 strcpy (szDriveName,"A:\\");
273 while (szDriveName[0]<='Z')
274 { if(dwDrivemap & 0x00000001L)
275 { pidl = _ILCreateDrive(szDriveName);
276 if(pidl)
277 { if(!IEnumIDList_AddToEnumList((IEnumIDList*)This, pidl))
278 return FALSE;
281 szDriveName[0]++;
282 dwDrivemap = dwDrivemap >> 1;
285 else
286 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",This,debugstr_a(szPath));
287 hFile = FindFirstFileA(szPath,&stffile);
288 if ( hFile != INVALID_HANDLE_VALUE )
289 { do
290 { if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
291 { pidl = _ILCreateFolder( stffile.cAlternateFileName, stffile.cFileName);
292 if(pidl)
293 { pData = _ILGetDataPointer(pidl);
294 FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.folder.uFileDate,&pData->u.folder.uFileTime);
295 pData->u.folder.dwFileSize = stffile.nFileSizeLow;
296 pData->u.folder.uFileAttribs=stffile.dwFileAttributes;
297 if(!IEnumIDList_AddToEnumList((IEnumIDList*)This, pidl))
298 { return FALSE;
301 else
302 { return FALSE;
305 } while( FindNextFileA(hFile,&stffile));
306 FindClose (hFile);
310 /*enumerate the non-folder items (values) */
311 if(dwFlags & SHCONTF_NONFOLDERS)
312 { if(lpszPath)
313 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",This,debugstr_a(szPath));
314 hFile = FindFirstFileA(szPath,&stffile);
315 if ( hFile != INVALID_HANDLE_VALUE )
316 { do
317 { if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
318 { pidl = _ILCreateValue( stffile.cAlternateFileName, stffile.cFileName);
319 if(pidl)
320 { pData = _ILGetDataPointer(pidl);
321 FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.file.uFileDate,&pData->u.file.uFileTime);
322 pData->u.file.dwFileSize = stffile.nFileSizeLow;
323 pData->u.file.uFileAttribs=stffile.dwFileAttributes;
324 if(!IEnumIDList_AddToEnumList((IEnumIDList*)This, pidl))
325 { return FALSE;
328 else
329 { return FALSE;
332 } while( FindNextFileA(hFile,&stffile));
333 FindClose (hFile);
337 return TRUE;
340 /**************************************************************************
341 * EnumIDList_AddToEnumList()
343 static BOOL WINAPI IEnumIDList_fnAddToEnumList(
344 IEnumIDList * iface,
345 LPITEMIDLIST pidl)
347 ICOM_THIS(IEnumIDListImpl,iface);
349 LPENUMLIST pNew;
351 TRACE(shell,"(%p)->(pidl=%p)\n",This,pidl);
352 pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
353 if(pNew)
354 { /*set the next pointer */
355 pNew->pNext = NULL;
356 pNew->pidl = pidl;
358 /*is This the first item in the list? */
359 if(!This->mpFirst)
360 { This->mpFirst = pNew;
361 This->mpCurrent = pNew;
364 if(This->mpLast)
365 { /*add the new item to the end of the list */
366 This->mpLast->pNext = pNew;
369 /*update the last item pointer */
370 This->mpLast = pNew;
371 TRACE(shell,"-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
372 return TRUE;
374 return FALSE;
376 /**************************************************************************
377 * EnumIDList_DeleteList()
379 static BOOL WINAPI IEnumIDList_fnDeleteList(
380 IEnumIDList * iface)
382 ICOM_THIS(IEnumIDListImpl,iface);
384 LPENUMLIST pDelete;
386 TRACE(shell,"(%p)->()\n",This);
388 while(This->mpFirst)
389 { pDelete = This->mpFirst;
390 This->mpFirst = pDelete->pNext;
391 SHFree(pDelete->pidl);
392 SHFree(pDelete);
394 This->mpFirst = This->mpLast = This->mpCurrent = NULL;
395 return TRUE;
398 /**************************************************************************
399 * IEnumIDList_fnVTable
401 static ICOM_VTABLE (IEnumIDList) eidlvt =
402 { IEnumIDList_fnQueryInterface,
403 IEnumIDList_fnAddRef,
404 IEnumIDList_fnRelease,
405 IEnumIDList_fnNext,
406 IEnumIDList_fnSkip,
407 IEnumIDList_fnReset,
408 IEnumIDList_fnClone,
409 IEnumIDList_fnCreateEnumList,
410 IEnumIDList_fnAddToEnumList,
411 IEnumIDList_fnDeleteList