Moved more things to the X11 driver.
[wine/multimedia.git] / dlls / shell32 / enumidlist.c
blob10f430ec1ffb13f1191198ca9b65e3fdd2a21fb5
1 /*
2 * IEnumIDList
4 * Copyright 1998 Juergen Schmied <juergen.schmied@metronet.de>
5 */
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "ole.h"
11 #include "ole2.h"
12 #include "debug.h"
13 #include "compobj.h"
14 #include "interfaces.h"
15 #include "shlobj.h"
16 #include "shell.h"
17 #include "winerror.h"
18 #include "winnls.h"
19 #include "winproc.h"
20 #include "commctrl.h"
21 #include "pidl.h"
22 #include "shell32_main.h"
24 /* IEnumIDList Implementation */
25 static HRESULT WINAPI IEnumIDList_QueryInterface(LPENUMIDLIST,REFIID,LPVOID*);
26 static ULONG WINAPI IEnumIDList_AddRef(LPENUMIDLIST);
27 static ULONG WINAPI IEnumIDList_Release(LPENUMIDLIST);
28 static HRESULT WINAPI IEnumIDList_Next(LPENUMIDLIST,ULONG,LPITEMIDLIST*,ULONG*);
29 static HRESULT WINAPI IEnumIDList_Skip(LPENUMIDLIST,ULONG);
30 static HRESULT WINAPI IEnumIDList_Reset(LPENUMIDLIST);
31 static HRESULT WINAPI IEnumIDList_Clone(LPENUMIDLIST,LPENUMIDLIST*);
32 static BOOL32 WINAPI IEnumIDList_CreateEnumList(LPENUMIDLIST,LPCSTR, DWORD);
33 static BOOL32 WINAPI IEnumIDList_AddToEnumList(LPENUMIDLIST,LPITEMIDLIST);
34 static BOOL32 WINAPI IEnumIDList_DeleteList(LPENUMIDLIST);
36 /**************************************************************************
37 * IEnumIDList_VTable
39 static IEnumIDList_VTable eidlvt =
40 { IEnumIDList_QueryInterface,
41 IEnumIDList_AddRef,
42 IEnumIDList_Release,
43 IEnumIDList_Next,
44 IEnumIDList_Skip,
45 IEnumIDList_Reset,
46 IEnumIDList_Clone,
47 IEnumIDList_CreateEnumList,
48 IEnumIDList_AddToEnumList,
49 IEnumIDList_DeleteList
52 /**************************************************************************
53 * IEnumIDList_Constructor
56 LPENUMIDLIST IEnumIDList_Constructor( LPCSTR lpszPath, DWORD dwFlags)
57 { LPENUMIDLIST lpeidl;
59 lpeidl = (LPENUMIDLIST)HeapAlloc(GetProcessHeap(),0,sizeof(IEnumIDList));
60 if (! lpeidl)
61 return NULL;
63 lpeidl->ref = 1;
64 lpeidl->lpvtbl = &eidlvt;
65 lpeidl->mpFirst=NULL;
66 lpeidl->mpLast=NULL;
67 lpeidl->mpCurrent=NULL;
69 TRACE(shell,"(%p)->(%s flags=0x%08lx)\n",lpeidl,debugstr_a(lpszPath),dwFlags);
71 if(!IEnumIDList_CreateEnumList(lpeidl, lpszPath, dwFlags))
72 { if (lpeidl)
73 { HeapFree(GetProcessHeap(),0,lpeidl);
75 return NULL;
78 TRACE(shell,"-- (%p)->()\n",lpeidl);
79 return lpeidl;
82 /**************************************************************************
83 * EnumIDList::QueryInterface
85 static HRESULT WINAPI IEnumIDList_QueryInterface(
86 LPENUMIDLIST this, REFIID riid, LPVOID *ppvObj)
87 { char xriid[50];
88 WINE_StringFromCLSID((LPCLSID)riid,xriid);
89 TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",this,xriid,ppvObj);
91 *ppvObj = NULL;
93 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
94 { *ppvObj = this;
96 else if(IsEqualIID(riid, &IID_IEnumIDList)) /*IEnumIDList*/
97 { *ppvObj = (IEnumIDList*)this;
100 if(*ppvObj)
101 { (*(LPENUMIDLIST*)ppvObj)->lpvtbl->fnAddRef(this);
102 TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
103 return S_OK;
105 TRACE(shell,"-- Interface: E_NOINTERFACE\n");
106 return E_NOINTERFACE;
109 /******************************************************************************
110 * IEnumIDList_AddRef
112 static ULONG WINAPI IEnumIDList_AddRef(LPENUMIDLIST this)
113 { TRACE(shell,"(%p)->()\n",this);
114 return ++(this->ref);
116 /******************************************************************************
117 * IEnumIDList_Release
119 static ULONG WINAPI IEnumIDList_Release(LPENUMIDLIST this)
120 { TRACE(shell,"(%p)->()\n",this);
121 if (!--(this->ref))
122 { TRACE(shell," destroying IEnumIDList(%p)\n",this);
123 IEnumIDList_DeleteList(this);
124 HeapFree(GetProcessHeap(),0,this);
125 return 0;
127 return this->ref;
130 /**************************************************************************
131 * IEnumIDList_Next
134 static HRESULT WINAPI IEnumIDList_Next(
135 LPENUMIDLIST this,ULONG celt,LPITEMIDLIST * rgelt,ULONG *pceltFetched)
136 { ULONG i;
137 HRESULT hr = S_OK;
138 LPITEMIDLIST temp;
140 TRACE(shell,"(%p)->(%ld,%p, %p)\n",this,celt,rgelt,pceltFetched);
142 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
143 * subsystems actually use it (and so may a third party browser)
145 if(pceltFetched)
146 *pceltFetched = 0;
148 *rgelt=0;
150 if(celt > 1 && !pceltFetched)
151 { return E_INVALIDARG;
154 for(i = 0; i < celt; i++)
155 { if(!(this->mpCurrent))
156 { hr = S_FALSE;
157 break;
159 temp = ILClone(this->mpCurrent->pidl);
160 rgelt[i] = temp;
161 this->mpCurrent = this->mpCurrent->pNext;
163 if(pceltFetched)
164 { *pceltFetched = i;
167 return hr;
170 /**************************************************************************
171 * IEnumIDList_Skip
173 static HRESULT WINAPI IEnumIDList_Skip(
174 LPENUMIDLIST this,ULONG celt)
175 { DWORD dwIndex;
176 HRESULT hr = S_OK;
178 TRACE(shell,"(%p)->(%lu)\n",this,celt);
180 for(dwIndex = 0; dwIndex < celt; dwIndex++)
181 { if(!this->mpCurrent)
182 { hr = S_FALSE;
183 break;
185 this->mpCurrent = this->mpCurrent->pNext;
187 return hr;
189 /**************************************************************************
190 * IEnumIDList_Reset
192 static HRESULT WINAPI IEnumIDList_Reset(LPENUMIDLIST this)
193 { TRACE(shell,"(%p)\n",this);
194 this->mpCurrent = this->mpFirst;
195 return S_OK;
197 /**************************************************************************
198 * IEnumIDList_Clone
200 static HRESULT WINAPI IEnumIDList_Clone(
201 LPENUMIDLIST this,LPENUMIDLIST * ppenum)
202 { TRACE(shell,"(%p)->() to (%p)->() E_NOTIMPL\n",this,ppenum);
203 return E_NOTIMPL;
205 /**************************************************************************
206 * EnumIDList_CreateEnumList()
207 * fixme: devices not handled
208 * fixme: add wildcards to path
210 static BOOL32 WINAPI IEnumIDList_CreateEnumList(LPENUMIDLIST this, LPCSTR lpszPath, DWORD dwFlags)
211 { LPITEMIDLIST pidl=NULL;
212 LPPIDLDATA pData=NULL;
213 WIN32_FIND_DATA32A stffile;
214 HANDLE32 hFile;
215 DWORD dwDrivemap;
216 CHAR szDriveName[4];
217 CHAR szPath[MAX_PATH];
219 TRACE(shell,"(%p)->(path=%s flags=0x%08lx) \n",this,debugstr_a(lpszPath),dwFlags);
221 if (lpszPath && lpszPath[0]!='\0')
222 { strcpy(szPath, lpszPath);
223 PathAddBackslash32A(szPath);
224 strcat(szPath,"*.*");
227 /*enumerate the folders*/
228 if(dwFlags & SHCONTF_FOLDERS)
229 { /* special case - we can't enumerate the Desktop level Objects (MyComputer,Nethood...
230 so we need to fake an enumeration of those.*/
231 if(!lpszPath)
232 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (special) items\n",this);
233 //create the pidl for this item
234 pidl = _ILCreateMyComputer();
235 if(pidl)
236 { pData = _ILGetDataPointer(pidl);
237 pData->u.generic.dwSFGAO = SFGAO_HASPROPSHEET | SFGAO_READONLY | SFGAO_HASSUBFOLDER;
238 if(!IEnumIDList_AddToEnumList(this, pidl))
239 return FALSE;
242 else if (lpszPath[0]=='\0') /* enumerate the drives*/
243 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (drives)\n",this);
244 dwDrivemap = GetLogicalDrives();
245 strcpy (szDriveName,"A:\\");
246 while (szDriveName[0]<='Z')
247 { if(dwDrivemap & 0x00000001L)
248 { pidl = _ILCreateDrive(szDriveName);
249 pData = _ILGetDataPointer(pidl);
250 pData->u.drive.dwSFGAO = SFGAO_HASPROPSHEET | SFGAO_READONLY | SFGAO_CANLINK |
251 SFGAO_HASSUBFOLDER | SFGAO_DROPTARGET | SFGAO_FILESYSTEM;
252 if(pidl)
253 { if(!IEnumIDList_AddToEnumList(this, pidl))
254 return FALSE;
257 szDriveName[0]++;
258 dwDrivemap = dwDrivemap >> 1;
261 else
262 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",this,debugstr_a(szPath));
263 hFile = FindFirstFile32A(szPath,&stffile);
264 if ( hFile != INVALID_HANDLE_VALUE32 )
265 { do
266 { if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
267 { pidl = _ILCreateFolder( stffile.cFileName);
268 if(pidl)
269 { pData = _ILGetDataPointer(pidl);
270 pData->u.folder.dwSFGAO = SFGAO_CANCOPY | SFGAO_CANDELETE | SFGAO_CANLINK |
271 SFGAO_CANMOVE | SFGAO_CANRENAME | SFGAO_DROPTARGET |
272 SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
273 if ( stffile.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
274 { pData->u.folder.dwSFGAO |= SFGAO_READONLY;
276 FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.folder.uFileDate,&pData->u.folder.uFileTime);
277 pData->u.folder.dwFileSize = stffile.nFileSizeLow;
278 pData->u.folder.uFileAttribs=stffile.dwFileAttributes;
279 strncpy (pData->u.folder.szAlternateName, stffile.cAlternateFileName,14);
280 if(!IEnumIDList_AddToEnumList(this, pidl))
281 { return FALSE;
284 else
285 { return FALSE;
288 } while( FindNextFile32A(hFile,&stffile));
289 FindClose32 (hFile);
293 //enumerate the non-folder items (values)
294 if(dwFlags & SHCONTF_NONFOLDERS)
295 { if(lpszPath)
296 { TRACE (shell,"-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",this,debugstr_a(szPath));
297 hFile = FindFirstFile32A(szPath,&stffile);
298 if ( hFile != INVALID_HANDLE_VALUE32 )
299 { do
300 { if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
301 { pidl = _ILCreateValue( stffile.cFileName);
302 if(pidl)
303 { pData = _ILGetDataPointer(pidl);
304 pData->u.file.dwSFGAO = SFGAO_CANCOPY | SFGAO_CANDELETE | SFGAO_CANLINK |
305 SFGAO_CANMOVE | SFGAO_CANRENAME | SFGAO_DROPTARGET |
306 SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM;
307 if ( stffile.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
308 { pData->u.file.dwSFGAO |= SFGAO_READONLY;
310 FileTimeToDosDateTime(&stffile.ftLastWriteTime,&pData->u.file.uFileDate,&pData->u.file.uFileTime);
311 pData->u.file.dwFileSize = stffile.nFileSizeLow;
312 pData->u.file.uFileAttribs=stffile.dwFileAttributes;
313 strncpy (pData->u.file.szAlternateName, stffile.cAlternateFileName,14);
314 if(!IEnumIDList_AddToEnumList(this, pidl))
315 { return FALSE;
318 else
319 { return FALSE;
322 } while( FindNextFile32A(hFile,&stffile));
323 FindClose32 (hFile);
327 return TRUE;
330 /**************************************************************************
331 * EnumIDList_AddToEnumList()
333 static BOOL32 WINAPI IEnumIDList_AddToEnumList(LPENUMIDLIST this,LPITEMIDLIST pidl)
334 { LPENUMLIST pNew;
336 TRACE(shell,"(%p)->(pidl=%p)\n",this,pidl);
337 pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
338 if(pNew)
339 { //set the next pointer
340 pNew->pNext = NULL;
341 pNew->pidl = pidl;
343 //is this the first item in the list?
344 if(!this->mpFirst)
345 { this->mpFirst = pNew;
346 this->mpCurrent = pNew;
349 if(this->mpLast)
350 { //add the new item to the end of the list
351 this->mpLast->pNext = pNew;
354 //update the last item pointer
355 this->mpLast = pNew;
356 TRACE(shell,"-- (%p)->(first=%p, last=%p)\n",this,this->mpFirst,this->mpLast);
357 return TRUE;
359 return FALSE;
361 /**************************************************************************
362 * EnumIDList_DeleteList()
364 static BOOL32 WINAPI IEnumIDList_DeleteList(LPENUMIDLIST this)
365 { LPENUMLIST pDelete;
367 TRACE(shell,"(%p)->()\n",this);
369 while(this->mpFirst)
370 { pDelete = this->mpFirst;
371 this->mpFirst = pDelete->pNext;
372 SHFree(pDelete->pidl);
373 SHFree(pDelete);
375 this->mpFirst = this->mpLast = this->mpCurrent = NULL;
376 return TRUE;