Confirm file deletes. Make delete confirmation messages more
[wine] / dlls / shell32 / enumidlist.c
1 /*
2  *      IEnumIDList
3  *
4  *      Copyright 1998  Juergen Schmied <juergen.schmied@metronet.de>
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include "debugtools.h"
10 #include "winreg.h"
11 #include "wine/undocshell.h"
12 #include "shlwapi.h"
13 #include "winerror.h"
14 #include "wine/obj_base.h"
15 #include "wine/obj_enumidlist.h"
16
17 #include "pidl.h"
18 #include "shlguid.h"
19 #include "shell32_main.h"
20
21 DEFAULT_DEBUG_CHANNEL(shell);
22
23 typedef struct tagENUMLIST
24 {
25         struct tagENUMLIST      *pNext;
26         LPITEMIDLIST            pidl;
27
28 } ENUMLIST, *LPENUMLIST;
29
30 typedef struct
31 {
32         ICOM_VFIELD(IEnumIDList);
33         DWORD                           ref;
34         LPENUMLIST                      mpFirst;
35         LPENUMLIST                      mpLast;
36         LPENUMLIST                      mpCurrent;
37
38 } IEnumIDListImpl;
39
40 static struct ICOM_VTABLE(IEnumIDList) eidlvt;
41
42 /**************************************************************************
43  *  AddToEnumList()
44  */
45 static BOOL AddToEnumList(
46         IEnumIDList * iface,
47         LPITEMIDLIST pidl)
48 {
49         ICOM_THIS(IEnumIDListImpl,iface);
50
51         LPENUMLIST  pNew;
52
53         TRACE("(%p)->(pidl=%p)\n",This,pidl);
54         pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
55         if(pNew)
56         {
57           /*set the next pointer */
58           pNew->pNext = NULL;
59           pNew->pidl = pidl;
60
61           /*is This the first item in the list? */
62           if(!This->mpFirst)
63           {
64             This->mpFirst = pNew;
65             This->mpCurrent = pNew;
66           }
67
68           if(This->mpLast)
69           {
70             /*add the new item to the end of the list */
71             This->mpLast->pNext = pNew;
72           }
73          
74           /*update the last item pointer */
75           This->mpLast = pNew;
76           TRACE("-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
77           return TRUE;
78         }
79         return FALSE;
80 }
81
82 /**************************************************************************
83  *  CreateFolderEnumList()
84  */
85 static BOOL CreateFolderEnumList(
86         IEnumIDList * iface,
87         LPCSTR lpszPath,
88         DWORD dwFlags)
89 {
90         ICOM_THIS(IEnumIDListImpl,iface);
91
92         LPITEMIDLIST    pidl=NULL;
93         WIN32_FIND_DATAA stffile;       
94         HANDLE hFile;
95         CHAR  szPath[MAX_PATH];
96
97         TRACE("(%p)->(path=%s flags=0x%08lx) \n",This,debugstr_a(lpszPath),dwFlags);
98
99         if(!lpszPath || !lpszPath[0]) return FALSE;
100
101         strcpy(szPath, lpszPath);
102         PathAddBackslashA(szPath);
103         strcat(szPath,"*.*");
104
105         /*enumerate the folders*/
106         if(dwFlags & SHCONTF_FOLDERS)
107         { 
108           TRACE("-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",This,debugstr_a(szPath));
109           hFile = FindFirstFileA(szPath,&stffile);
110           if ( hFile != INVALID_HANDLE_VALUE )
111           {
112             do
113             {
114               if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
115               {
116                 pidl = _ILCreateFolder (&stffile);
117                 if(pidl && AddToEnumList((IEnumIDList*)This, pidl))
118                 {
119                   continue;
120                 }
121                 return FALSE;
122               }
123             } while( FindNextFileA(hFile,&stffile));
124             FindClose (hFile);
125           }
126         }
127
128         /*enumerate the non-folder items (values) */
129         if(dwFlags & SHCONTF_NONFOLDERS)
130         {
131           TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",This,debugstr_a(szPath));
132           hFile = FindFirstFileA(szPath,&stffile);
133           if ( hFile != INVALID_HANDLE_VALUE )
134           {
135             do
136             {
137               if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
138               {
139                 pidl = _ILCreateValue(&stffile);
140                 if(pidl && AddToEnumList((IEnumIDList*)This, pidl))
141                 {
142                   continue;
143                 }
144                 return FALSE;
145               }
146             } while( FindNextFileA(hFile,&stffile));
147             FindClose (hFile);
148           } 
149         }
150         return TRUE;
151 }
152
153 /**************************************************************************
154  *  CreateDesktopEnumList()
155  */
156 static BOOL CreateDesktopEnumList(
157         IEnumIDList * iface,
158         DWORD dwFlags)
159 {
160         ICOM_THIS(IEnumIDListImpl,iface);
161
162         LPITEMIDLIST    pidl=NULL;
163         HKEY hkey;
164         char    szPath[MAX_PATH];
165
166         TRACE("(%p)->(flags=0x%08lx) \n",This,dwFlags);
167
168         /*enumerate the root folders */
169         if(dwFlags & SHCONTF_FOLDERS)
170         { 
171           /*create the pidl for This item */
172           pidl = _ILCreateMyComputer();
173           if(pidl)
174           {
175             if(!AddToEnumList((IEnumIDList*)This, pidl))
176               return FALSE;
177           }
178
179           if (! RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\explorer\\desktop\\NameSpace", 0, KEY_READ, &hkey))
180           {
181             char iid[50];
182             int i=0;
183
184             while (1)
185             {
186               DWORD size = sizeof (iid);
187
188               if (ERROR_SUCCESS!=RegEnumKeyExA(hkey, i, iid, &size, 0, NULL, NULL, NULL))
189                 break;
190
191               pidl = _ILCreateSpecial(iid);
192
193               if(pidl)
194                 AddToEnumList((IEnumIDList*)This, pidl);
195
196               i++;
197             }
198             RegCloseKey(hkey);
199           }
200         }
201
202         /*enumerate the elements in %windir%\desktop */
203         SHGetSpecialFolderPathA(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
204         CreateFolderEnumList( (IEnumIDList*)This, szPath, dwFlags);
205         
206         return TRUE;
207 }
208
209 /**************************************************************************
210  *  CreateMyCompEnumList()
211  */
212 static BOOL CreateMyCompEnumList(
213         IEnumIDList * iface,
214         DWORD dwFlags)
215 {
216         ICOM_THIS(IEnumIDListImpl,iface);
217
218         LPITEMIDLIST    pidl=NULL;
219         DWORD           dwDrivemap;
220         CHAR            szDriveName[4];
221         HKEY            hkey;
222
223         TRACE("(%p)->(flags=0x%08lx) \n",This,dwFlags);
224
225         /*enumerate the folders*/
226         if(dwFlags & SHCONTF_FOLDERS)
227         {
228           dwDrivemap = GetLogicalDrives();
229           strcpy (szDriveName,"A:\\");
230           while (szDriveName[0]<='Z')
231           {
232             if(dwDrivemap & 0x00000001L)
233             {
234               pidl = _ILCreateDrive(szDriveName);
235               if(pidl)
236               {
237                 if(!AddToEnumList((IEnumIDList*)This, pidl))
238                   return FALSE;
239               }
240             }
241             szDriveName[0]++;
242             dwDrivemap = dwDrivemap >> 1;
243           }
244
245           TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n",This);
246           if (! RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\explorer\\mycomputer\\NameSpace", 0, KEY_READ, &hkey))
247           {
248             char iid[50];
249             int i=0;
250
251             while (1)
252             {
253               DWORD size = sizeof (iid);
254
255               if (ERROR_SUCCESS!=RegEnumKeyExA(hkey, i, iid, &size, 0, NULL, NULL, NULL))
256                 break;
257
258               pidl = _ILCreateSpecial(iid);
259
260               if(pidl)
261                 AddToEnumList((IEnumIDList*)This, pidl);
262
263               i++;
264             }
265             RegCloseKey(hkey);
266           }
267         }
268         return TRUE;
269 }
270
271 /**************************************************************************
272 *   DeleteList()
273 */
274 static BOOL DeleteList(
275         IEnumIDList * iface)
276 {
277         ICOM_THIS(IEnumIDListImpl,iface);
278
279         LPENUMLIST  pDelete;
280
281         TRACE("(%p)->()\n",This);
282         
283         while(This->mpFirst)
284         { pDelete = This->mpFirst;
285           This->mpFirst = pDelete->pNext;
286           SHFree(pDelete->pidl);
287           SHFree(pDelete);
288         }
289         This->mpFirst = This->mpLast = This->mpCurrent = NULL;
290         return TRUE;
291 }
292
293 /**************************************************************************
294  *  IEnumIDList_Folder_Constructor
295  *
296  */
297
298 IEnumIDList * IEnumIDList_Constructor(
299         LPCSTR lpszPath,
300         DWORD dwFlags,
301         DWORD dwKind)
302 {
303         IEnumIDListImpl*        lpeidl;
304         BOOL                    ret = FALSE;    
305
306         lpeidl = (IEnumIDListImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumIDListImpl));
307
308         TRACE("(%p)->(%s flags=0x%08lx kind=0x%08lx)\n",lpeidl,debugstr_a(lpszPath),dwFlags, dwKind);
309
310         if (lpeidl)
311         {
312           lpeidl->ref = 1;
313           ICOM_VTBL(lpeidl) = &eidlvt;
314
315           switch (dwKind)
316           {
317             case EIDL_DESK:
318               ret = CreateDesktopEnumList((IEnumIDList*)lpeidl, dwFlags);
319               break;
320
321             case EIDL_MYCOMP:
322               ret = CreateMyCompEnumList((IEnumIDList*)lpeidl, dwFlags);
323               break;
324
325             case EIDL_FILE:
326               ret = CreateFolderEnumList((IEnumIDList*)lpeidl, lpszPath, dwFlags);
327               break;
328           }
329
330           if(ret)
331           {
332             shell32_ObjCount++;
333           }
334           else
335           {
336             if (lpeidl)
337             {
338               HeapFree(GetProcessHeap(),0,lpeidl);
339             }
340           }
341         }
342
343         TRACE("-- (%p)->()\n",lpeidl);
344
345         return (IEnumIDList*)lpeidl;
346 }
347
348 /**************************************************************************
349  *  EnumIDList_QueryInterface
350  */
351 static HRESULT WINAPI IEnumIDList_fnQueryInterface(
352         IEnumIDList * iface,
353         REFIID riid,
354         LPVOID *ppvObj)
355 {
356         ICOM_THIS(IEnumIDListImpl,iface);
357
358         TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
359
360         *ppvObj = NULL;
361
362         if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
363         { *ppvObj = This; 
364         }
365         else if(IsEqualIID(riid, &IID_IEnumIDList))  /*IEnumIDList*/
366         {    *ppvObj = (IEnumIDList*)This;
367         }
368
369         if(*ppvObj)
370         { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
371           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
372           return S_OK;
373         }
374         
375         TRACE("-- Interface: E_NOINTERFACE\n");
376         return E_NOINTERFACE;
377 }
378
379 /******************************************************************************
380  * IEnumIDList_fnAddRef
381  */
382 static ULONG WINAPI IEnumIDList_fnAddRef(
383         IEnumIDList * iface)
384 {
385         ICOM_THIS(IEnumIDListImpl,iface);
386
387         TRACE("(%p)->(%lu)\n",This,This->ref);
388
389         shell32_ObjCount++;
390         return ++(This->ref);
391 }
392 /******************************************************************************
393  * IEnumIDList_fnRelease
394  */
395 static ULONG WINAPI IEnumIDList_fnRelease(
396         IEnumIDList * iface)
397 {
398         ICOM_THIS(IEnumIDListImpl,iface);
399
400         TRACE("(%p)->(%lu)\n",This,This->ref);
401
402         shell32_ObjCount--;
403
404         if (!--(This->ref)) 
405         { TRACE(" destroying IEnumIDList(%p)\n",This);
406           DeleteList((IEnumIDList*)This);
407           HeapFree(GetProcessHeap(),0,This);
408           return 0;
409         }
410         return This->ref;
411 }
412    
413 /**************************************************************************
414  *  IEnumIDList_fnNext
415  */
416
417 static HRESULT WINAPI IEnumIDList_fnNext(
418         IEnumIDList * iface,
419         ULONG celt,
420         LPITEMIDLIST * rgelt,
421         ULONG *pceltFetched) 
422 {
423         ICOM_THIS(IEnumIDListImpl,iface);
424
425         ULONG    i;
426         HRESULT  hr = S_OK;
427         LPITEMIDLIST  temp;
428
429         TRACE("(%p)->(%ld,%p, %p)\n",This,celt,rgelt,pceltFetched);
430
431 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
432  * subsystems actually use it (and so may a third party browser)
433  */
434         if(pceltFetched)
435           *pceltFetched = 0;
436
437         *rgelt=0;
438         
439         if(celt > 1 && !pceltFetched)
440         { return E_INVALIDARG;
441         }
442
443         for(i = 0; i < celt; i++)
444         { if(!(This->mpCurrent))
445           { hr =  S_FALSE;
446             break;
447           }
448           temp = ILClone(This->mpCurrent->pidl);
449           rgelt[i] = temp;
450           This->mpCurrent = This->mpCurrent->pNext;
451         }
452         if(pceltFetched)
453         {  *pceltFetched = i;
454         }
455
456         return hr;
457 }
458
459 /**************************************************************************
460 *  IEnumIDList_fnSkip
461 */
462 static HRESULT WINAPI IEnumIDList_fnSkip(
463         IEnumIDList * iface,ULONG celt)
464 {
465         ICOM_THIS(IEnumIDListImpl,iface);
466
467         DWORD    dwIndex;
468         HRESULT  hr = S_OK;
469
470         TRACE("(%p)->(%lu)\n",This,celt);
471
472         for(dwIndex = 0; dwIndex < celt; dwIndex++)
473         { if(!This->mpCurrent)
474           { hr = S_FALSE;
475             break;
476           }
477           This->mpCurrent = This->mpCurrent->pNext;
478         }
479         return hr;
480 }
481 /**************************************************************************
482 *  IEnumIDList_fnReset
483 */
484 static HRESULT WINAPI IEnumIDList_fnReset(
485         IEnumIDList * iface)
486 {
487         ICOM_THIS(IEnumIDListImpl,iface);
488
489         TRACE("(%p)\n",This);
490         This->mpCurrent = This->mpFirst;
491         return S_OK;
492 }
493 /**************************************************************************
494 *  IEnumIDList_fnClone
495 */
496 static HRESULT WINAPI IEnumIDList_fnClone(
497         IEnumIDList * iface,LPENUMIDLIST * ppenum)
498 {
499         ICOM_THIS(IEnumIDListImpl,iface);
500
501         TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
502         return E_NOTIMPL;
503 }
504
505 /**************************************************************************
506  *  IEnumIDList_fnVTable
507  */
508 static ICOM_VTABLE (IEnumIDList) eidlvt = 
509 {
510         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
511         IEnumIDList_fnQueryInterface,
512         IEnumIDList_fnAddRef,
513         IEnumIDList_fnRelease,
514         IEnumIDList_fnNext,
515         IEnumIDList_fnSkip,
516         IEnumIDList_fnReset,
517         IEnumIDList_fnClone,
518 };