source: trunk/src/shell32/enumidlist.c

Last change on this file was 21494, checked in by dmik, 15 years ago

Fixed broken build after r21492 by sorting out a huuuuge wagon of duplicates, wrong include order and other dirty mess.

File size: 16.5 KB
Line 
1/* $Id: enumidlist.c,v 1.7 2003-07-28 11:28:56 sandervl Exp $ */
2/*
3 * IEnumIDList
4 *
5 * Copyright 1998 Juergen Schmied <juergen.schmied@metronet.de>
6 */
7#ifdef __WIN32OS2__
8#define CINTERFACE
9#include <odin.h>
10#endif
11
12#include <stdlib.h>
13#include <string.h>
14#include "debugtools.h"
15#include "winreg.h"
16#include "wine/obj_base.h"
17#include "wine/obj_enumidlist.h"
18#include "undocshell.h"
19#include "winerror.h"
20#include "shlwapi.h"
21
22#include "pidl.h"
23#include "shlguid.h"
24#include "shell32_main.h"
25
26DEFAULT_DEBUG_CHANNEL(shell)
27
28typedef struct tagENUMLIST
29{
30 struct tagENUMLIST *pNext;
31 LPITEMIDLIST pidl;
32
33} ENUMLIST, *LPENUMLIST;
34
35typedef struct
36{
37 ICOM_VFIELD(IEnumIDList);
38 DWORD ref;
39 LPENUMLIST mpFirst;
40 LPENUMLIST mpLast;
41 LPENUMLIST mpCurrent;
42#ifdef __WIN32OS2__
43 LPENUMLIST mpFirst2;
44 LPENUMLIST mpLast2;
45 LPENUMLIST mpCurrent2;
46#endif
47} IEnumIDListImpl;
48
49static struct ICOM_VTABLE(IEnumIDList) eidlvt;
50
51/**************************************************************************
52 * AddToEnumList()
53 */
54static BOOL AddToEnumList(
55 IEnumIDList * iface,
56 LPITEMIDLIST pidl)
57{
58 ICOM_THIS(IEnumIDListImpl,iface);
59
60 LPENUMLIST pNew;
61
62 TRACE("(%p)->(pidl=%p)\n",This,pidl);
63 pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
64 if(pNew)
65 {
66 /*set the next pointer */
67 pNew->pNext = NULL;
68 pNew->pidl = pidl;
69
70 /*is This the first item in the list? */
71 if(!This->mpFirst)
72 {
73 This->mpFirst = pNew;
74 This->mpCurrent = pNew;
75 }
76
77 if(This->mpLast)
78 {
79 /*add the new item to the end of the list */
80 This->mpLast->pNext = pNew;
81 }
82
83 /*update the last item pointer */
84 This->mpLast = pNew;
85 TRACE("-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
86 return TRUE;
87 }
88 return FALSE;
89}
90
91/**************************************************************************
92 * CreateFolderEnumList()
93 */
94#define __WIN32OS2__TEST_TURNED_OFF
95
96#ifdef __WIN32OS2__TEST_TURNED_OFF
97//CB: Special version to speed up retrieving files in a directory
98//SvL: Works well and is twice as fast. Quite important when called way too
99// many times
100/**************************************************************************
101 * AddToEnumList()
102 */
103static BOOL AddToEnumList2(
104 IEnumIDList * iface,
105 LPITEMIDLIST pidl)
106{
107 ICOM_THIS(IEnumIDListImpl,iface);
108
109 LPENUMLIST pNew;
110
111 TRACE("(%p)->(pidl=%p)\n",This,pidl);
112 pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
113 if(pNew)
114 {
115 /*set the next pointer */
116 pNew->pNext = NULL;
117 pNew->pidl = pidl;
118
119 /*is This the first item in the list? */
120 if(!This->mpFirst2)
121 {
122 This->mpFirst2 = pNew;
123 This->mpCurrent2 = pNew;
124 }
125
126 if(This->mpLast2)
127 {
128 /*add the new item to the end of the list */
129 This->mpLast2->pNext = pNew;
130 }
131
132 /*update the last item pointer */
133 This->mpLast2 = pNew;
134 TRACE("-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst2,This->mpLast2);
135 return TRUE;
136 }
137 return FALSE;
138}
139
140static VOID UniteEnumLists(IEnumIDList * iface)
141{
142 ICOM_THIS(IEnumIDListImpl,iface);
143
144 if (This->mpFirst2)
145 {
146 /*is This the first item in the list? */
147 if(!This->mpFirst)
148 {
149 This->mpFirst = This->mpFirst2;
150 This->mpCurrent = This->mpFirst2;
151 }
152
153 if(This->mpLast)
154 {
155 /*add the new item to the end of the list */
156 This->mpLast->pNext = This->mpFirst2;
157 }
158
159 /*update the last item pointer */
160 This->mpLast = This->mpLast2;
161
162 This->mpFirst2 = NULL;
163 This->mpCurrent2 = NULL;
164 This->mpLast2 = NULL;
165 }
166}
167
168static BOOL CreateFolderEnumList(
169 IEnumIDList * iface,
170 LPCSTR lpszPath,
171 DWORD dwFlags)
172{
173 ICOM_THIS(IEnumIDListImpl,iface);
174
175 const MULTICOUNT = 64;
176 LPITEMIDLIST pidl=NULL;
177 WIN32_FIND_DATAA *stffile = NULL;
178 DWORD count;
179 HANDLE hFile;
180 CHAR szPath[MAX_PATH];
181 int x;
182
183 TRACE("(%p)->(path=%s flags=0x%08lx) \n",This,debugstr_a(lpszPath),dwFlags);
184
185 if(!lpszPath || !lpszPath[0]) return FALSE;
186
187 strcpy(szPath, lpszPath);
188 PathAddBackslashA(szPath);
189 strcat(szPath,"*.*");
190
191 /*enumerate the folders*/
192 if(dwFlags & SHCONTF_FOLDERS)
193 {
194 TRACE("-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",This,debugstr_a(szPath));
195 count = MULTICOUNT;
196 stffile = (WIN32_FIND_DATAA*)malloc(count*sizeof(WIN32_FIND_DATAA));
197 hFile = FindFirstFileMultiA(szPath,stffile,&count);
198 if (hFile != INVALID_HANDLE_VALUE)
199 {
200 do
201 {
202 for (x = 0;x < count;x++)
203 {
204 if ( !(dwFlags & SHCONTF_INCLUDEHIDDEN) && (stffile[x].dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ) continue;
205
206 if (stffile[x].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
207 { //directory
208 if (strcmp (stffile[x].cFileName, ".") && strcmp (stffile[x].cFileName, ".."))
209 {
210 pidl = _ILCreateFolder (&stffile[x]);
211 if (pidl && AddToEnumList((IEnumIDList*)This, pidl))
212 continue;
213 free(stffile);
214 FindClose(hFile);
215 return FALSE;
216 }
217 }
218 else
219 if (dwFlags & SHCONTF_NONFOLDERS)
220 { //file
221 pidl = _ILCreateValue(&stffile[x]);
222 if (pidl && AddToEnumList2((IEnumIDList*)This, pidl))
223 continue;
224 free(stffile);
225 FindClose(hFile);
226 return FALSE;
227 }
228 }
229 count = MULTICOUNT;
230 }
231 while(FindNextFileMultiA(hFile,stffile,&count));
232
233 FindClose(hFile);
234 UniteEnumLists((IEnumIDList*)This);
235 }
236 }
237
238 /*enumerate the non-folder items (values) */
239 if((dwFlags & SHCONTF_NONFOLDERS) && !(dwFlags & SHCONTF_FOLDERS))
240 {
241 TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",This,debugstr_a(szPath));
242 count = MULTICOUNT;
243 if (!stffile) stffile = (WIN32_FIND_DATAA*)malloc(count*sizeof(WIN32_FIND_DATAA));
244 hFile = FindFirstFileMultiA(szPath,stffile,&count);
245 if (hFile != INVALID_HANDLE_VALUE)
246 {
247 do
248 {
249 for (x = 0;x < count;x++)
250 {
251 if ( !(dwFlags & SHCONTF_INCLUDEHIDDEN) && (stffile[x].dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ) continue;
252
253 if (! (stffile[x].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
254 {
255 pidl = _ILCreateValue(&stffile[x]);
256 if (pidl && AddToEnumList((IEnumIDList*)This, pidl))
257 continue;
258 free(stffile);
259 FindClose(hFile);
260 return FALSE;
261 }
262 }
263 count = MULTICOUNT;
264 } while(FindNextFileMultiA(hFile,stffile,&count));
265 FindClose (hFile);
266 }
267 }
268 if (stffile) free(stffile);
269
270 return TRUE;
271}
272#else
273static BOOL CreateFolderEnumList(
274 IEnumIDList * iface,
275 LPCSTR lpszPath,
276 DWORD dwFlags)
277{
278 ICOM_THIS(IEnumIDListImpl,iface);
279
280 LPITEMIDLIST pidl=NULL;
281 WIN32_FIND_DATAA stffile;
282 HANDLE hFile;
283 CHAR szPath[MAX_PATH];
284
285 TRACE("(%p)->(path=%s flags=0x%08lx) \n",This,debugstr_a(lpszPath),dwFlags);
286
287 if(!lpszPath || !lpszPath[0]) return FALSE;
288
289 strcpy(szPath, lpszPath);
290 PathAddBackslashA(szPath);
291 strcat(szPath,"*.*");
292
293 /*enumerate the folders*/
294 if(dwFlags & SHCONTF_FOLDERS)
295 {
296 TRACE("-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",This,debugstr_a(szPath));
297 hFile = FindFirstFileA(szPath,&stffile);
298 if ( hFile != INVALID_HANDLE_VALUE )
299 {
300 do
301 {
302 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
303 {
304 pidl = _ILCreateFolder (&stffile);
305 if(pidl && AddToEnumList((IEnumIDList*)This, pidl))
306 {
307 continue;
308 }
309 return FALSE;
310 }
311 } while( FindNextFileA(hFile,&stffile));
312 FindClose (hFile);
313 }
314 }
315
316 /*enumerate the non-folder items (values) */
317 if(dwFlags & SHCONTF_NONFOLDERS)
318 {
319 TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",This,debugstr_a(szPath));
320 hFile = FindFirstFileA(szPath,&stffile);
321 if ( hFile != INVALID_HANDLE_VALUE )
322 {
323 do
324 {
325 if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
326 {
327 pidl = _ILCreateValue(&stffile);
328 if(pidl && AddToEnumList((IEnumIDList*)This, pidl))
329 {
330 continue;
331 }
332 return FALSE;
333 }
334 } while( FindNextFileA(hFile,&stffile));
335 FindClose (hFile);
336 }
337 }
338 return TRUE;
339}
340#endif
341/**************************************************************************
342 * CreateDesktopEnumList()
343 */
344static BOOL CreateDesktopEnumList(
345 IEnumIDList * iface,
346 DWORD dwFlags)
347{
348 ICOM_THIS(IEnumIDListImpl,iface);
349
350 LPITEMIDLIST pidl=NULL;
351 HKEY hkey;
352 char szPath[MAX_PATH];
353
354 TRACE("(%p)->(flags=0x%08lx) \n",This,dwFlags);
355
356 /*enumerate the root folders */
357 if(dwFlags & SHCONTF_FOLDERS)
358 {
359 /*create the pidl for This item */
360 pidl = _ILCreateMyComputer();
361 if(pidl)
362 {
363 if(!AddToEnumList((IEnumIDList*)This, pidl))
364 return FALSE;
365 }
366
367 if (! RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\explorer\\desktop\\NameSpace", 0, KEY_READ, &hkey))
368 {
369 char iid[50];
370 int i=0;
371
372 while (1)
373 {
374 DWORD size = sizeof (iid);
375
376 if (ERROR_SUCCESS!=RegEnumKeyExA(hkey, i, iid, &size, 0, NULL, NULL, NULL))
377 break;
378
379 pidl = _ILCreateSpecial(iid);
380
381 if(pidl)
382 AddToEnumList((IEnumIDList*)This, pidl);
383
384 i++;
385 }
386 RegCloseKey(hkey);
387 }
388 }
389
390 /*enumerate the elements in %windir%\desktop */
391 SHGetSpecialFolderPathA(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
392 CreateFolderEnumList( (IEnumIDList*)This, szPath, dwFlags);
393
394 return TRUE;
395}
396
397/**************************************************************************
398 * CreateMyCompEnumList()
399 */
400static BOOL CreateMyCompEnumList(
401 IEnumIDList * iface,
402 DWORD dwFlags)
403{
404 ICOM_THIS(IEnumIDListImpl,iface);
405
406 LPITEMIDLIST pidl=NULL;
407 DWORD dwDrivemap;
408 CHAR szDriveName[4];
409 HKEY hkey;
410
411 TRACE("(%p)->(flags=0x%08lx) \n",This,dwFlags);
412
413 /*enumerate the folders*/
414 if(dwFlags & SHCONTF_FOLDERS)
415 {
416 dwDrivemap = GetLogicalDrives();
417 strcpy (szDriveName,"A:\\");
418 while (szDriveName[0]<='Z')
419 {
420 if(dwDrivemap & 0x00000001L)
421 {
422 pidl = _ILCreateDrive(szDriveName);
423 if(pidl)
424 {
425 if(!AddToEnumList((IEnumIDList*)This, pidl))
426 return FALSE;
427 }
428 }
429 szDriveName[0]++;
430 dwDrivemap = dwDrivemap >> 1;
431 }
432
433 TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n",This);
434 if (! RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\explorer\\mycomputer\\NameSpace", 0, KEY_READ, &hkey))
435 {
436 char iid[50];
437 int i=0;
438
439 while (1)
440 {
441 DWORD size = sizeof (iid);
442
443 if (ERROR_SUCCESS!=RegEnumKeyExA(hkey, i, iid, &size, 0, NULL, NULL, NULL))
444 break;
445
446 pidl = _ILCreateSpecial(iid);
447
448 if(pidl)
449 AddToEnumList((IEnumIDList*)This, pidl);
450
451 i++;
452 }
453 RegCloseKey(hkey);
454 }
455 }
456 return TRUE;
457}
458
459/**************************************************************************
460* DeleteList()
461*/
462static BOOL DeleteList(
463 IEnumIDList * iface)
464{
465 ICOM_THIS(IEnumIDListImpl,iface);
466
467 LPENUMLIST pDelete;
468
469 TRACE("(%p)->()\n",This);
470
471 while(This->mpFirst)
472 { pDelete = This->mpFirst;
473 This->mpFirst = pDelete->pNext;
474 SHFree(pDelete->pidl);
475 SHFree(pDelete);
476 }
477 This->mpFirst = This->mpLast = This->mpCurrent = NULL;
478 return TRUE;
479}
480
481/**************************************************************************
482 * IEnumIDList_Folder_Constructor
483 *
484 */
485
486IEnumIDList * IEnumIDList_Constructor(
487 LPCSTR lpszPath,
488 DWORD dwFlags,
489 DWORD dwKind)
490{
491 IEnumIDListImpl* lpeidl;
492 BOOL ret = FALSE;
493
494 lpeidl = (IEnumIDListImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumIDListImpl));
495
496 TRACE("(%p)->(%s flags=0x%08lx kind=0x%08lx)\n",lpeidl,debugstr_a(lpszPath),dwFlags, dwKind);
497
498 if (lpeidl)
499 {
500 lpeidl->ref = 1;
501 ICOM_VTBL(lpeidl) = &eidlvt;
502
503 switch (dwKind)
504 {
505 case EIDL_DESK:
506 ret = CreateDesktopEnumList((IEnumIDList*)lpeidl, dwFlags);
507 break;
508
509 case EIDL_MYCOMP:
510 ret = CreateMyCompEnumList((IEnumIDList*)lpeidl, dwFlags);
511 break;
512
513 case EIDL_FILE:
514 ret = CreateFolderEnumList((IEnumIDList*)lpeidl, lpszPath, dwFlags);
515 break;
516 }
517
518 if(ret)
519 {
520 shell32_ObjCount++;
521 }
522 else
523 {
524 if (lpeidl)
525 {
526 HeapFree(GetProcessHeap(),0,lpeidl);
527 lpeidl = NULL;
528 }
529 }
530 }
531
532 TRACE("-- (%p)->()\n",lpeidl);
533
534 return (IEnumIDList*)lpeidl;
535}
536
537/**************************************************************************
538 * EnumIDList_QueryInterface
539 */
540static HRESULT WINAPI IEnumIDList_fnQueryInterface(
541 IEnumIDList * iface,
542 REFIID riid,
543 LPVOID *ppvObj)
544{
545 ICOM_THIS(IEnumIDListImpl,iface);
546
547 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
548
549 *ppvObj = NULL;
550
551 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
552 { *ppvObj = This;
553 }
554 else if(IsEqualIID(riid, &IID_IEnumIDList)) /*IEnumIDList*/
555 { *ppvObj = (IEnumIDList*)This;
556 }
557
558 if(*ppvObj)
559 { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
560 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
561 return S_OK;
562 }
563
564 TRACE("-- Interface: E_NOINTERFACE\n");
565 return E_NOINTERFACE;
566}
567
568/******************************************************************************
569 * IEnumIDList_fnAddRef
570 */
571static ULONG WINAPI IEnumIDList_fnAddRef(
572 IEnumIDList * iface)
573{
574 ICOM_THIS(IEnumIDListImpl,iface);
575
576 TRACE("(%p)->(%lu)\n",This,This->ref);
577
578 shell32_ObjCount++;
579 return ++(This->ref);
580}
581/******************************************************************************
582 * IEnumIDList_fnRelease
583 */
584static ULONG WINAPI IEnumIDList_fnRelease(
585 IEnumIDList * iface)
586{
587 ICOM_THIS(IEnumIDListImpl,iface);
588
589 TRACE("(%p)->(%lu)\n",This,This->ref);
590
591 shell32_ObjCount--;
592
593 if (!--(This->ref))
594 { TRACE(" destroying IEnumIDList(%p)\n",This);
595 DeleteList((IEnumIDList*)This);
596 HeapFree(GetProcessHeap(),0,This);
597 return 0;
598 }
599 return This->ref;
600}
601
602/**************************************************************************
603 * IEnumIDList_fnNext
604 */
605
606static HRESULT WINAPI IEnumIDList_fnNext(
607 IEnumIDList * iface,
608 ULONG celt,
609 LPITEMIDLIST * rgelt,
610 ULONG *pceltFetched)
611{
612 ICOM_THIS(IEnumIDListImpl,iface);
613
614 ULONG i;
615 HRESULT hr = S_OK;
616 LPITEMIDLIST temp;
617
618 TRACE("(%p)->(%ld,%p, %p)\n",This,celt,rgelt,pceltFetched);
619
620/* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
621 * subsystems actually use it (and so may a third party browser)
622 */
623 if(pceltFetched)
624 *pceltFetched = 0;
625
626 *rgelt=0;
627
628 if(celt > 1 && !pceltFetched)
629 { return E_INVALIDARG;
630 }
631
632 for(i = 0; i < celt; i++)
633 { if(!(This->mpCurrent))
634 { hr = S_FALSE;
635 break;
636 }
637 temp = ILClone(This->mpCurrent->pidl);
638 rgelt[i] = temp;
639 This->mpCurrent = This->mpCurrent->pNext;
640 }
641 if(pceltFetched)
642 { *pceltFetched = i;
643 }
644
645 return hr;
646}
647
648/**************************************************************************
649* IEnumIDList_fnSkip
650*/
651static HRESULT WINAPI IEnumIDList_fnSkip(
652 IEnumIDList * iface,ULONG celt)
653{
654 ICOM_THIS(IEnumIDListImpl,iface);
655
656 DWORD dwIndex;
657 HRESULT hr = S_OK;
658
659 TRACE("(%p)->(%lu)\n",This,celt);
660
661 for(dwIndex = 0; dwIndex < celt; dwIndex++)
662 { if(!This->mpCurrent)
663 { hr = S_FALSE;
664 break;
665 }
666 This->mpCurrent = This->mpCurrent->pNext;
667 }
668 return hr;
669}
670/**************************************************************************
671* IEnumIDList_fnReset
672*/
673static HRESULT WINAPI IEnumIDList_fnReset(
674 IEnumIDList * iface)
675{
676 ICOM_THIS(IEnumIDListImpl,iface);
677
678 TRACE("(%p)\n",This);
679 This->mpCurrent = This->mpFirst;
680 return S_OK;
681}
682/**************************************************************************
683* IEnumIDList_fnClone
684*/
685static HRESULT WINAPI IEnumIDList_fnClone(
686 IEnumIDList * iface,LPENUMIDLIST * ppenum)
687{
688 ICOM_THIS(IEnumIDListImpl,iface);
689
690 TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
691 return E_NOTIMPL;
692}
693
694/**************************************************************************
695 * IEnumIDList_fnVTable
696 */
697static ICOM_VTABLE (IEnumIDList) eidlvt =
698{
699 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
700 IEnumIDList_fnQueryInterface,
701 IEnumIDList_fnAddRef,
702 IEnumIDList_fnRelease,
703 IEnumIDList_fnNext,
704 IEnumIDList_fnSkip,
705 IEnumIDList_fnReset,
706 IEnumIDList_fnClone,
707};
Note: See TracBrowser for help on using the repository browser.