Added memicmpW.
[wine.git] / dlls / shell32 / enumidlist.c
blob57cc4023d7dbb8e46da577ca61220301bee5ca6f
1 /*
2 * IEnumIDList
4 * Copyright 1998 Juergen Schmied <juergen.schmied@metronet.de>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "wine/debug.h"
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "undocshell.h"
29 #include "shlwapi.h"
30 #include "winerror.h"
31 #include "objbase.h"
32 #include <cpl.h>
34 #include "pidl.h"
35 #include "shlguid.h"
36 #include "shell32_main.h"
37 #include "cpanel.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(shell);
41 typedef struct tagENUMLIST
43 struct tagENUMLIST *pNext;
44 LPITEMIDLIST pidl;
46 } ENUMLIST, *LPENUMLIST;
48 typedef struct
50 ICOM_VFIELD(IEnumIDList);
51 DWORD ref;
52 LPENUMLIST mpFirst;
53 LPENUMLIST mpLast;
54 LPENUMLIST mpCurrent;
56 } IEnumIDListImpl;
58 static struct ICOM_VTABLE(IEnumIDList) eidlvt;
60 /**************************************************************************
61 * AddToEnumList()
63 static BOOL AddToEnumList(
64 IEnumIDList * iface,
65 LPITEMIDLIST pidl)
67 ICOM_THIS(IEnumIDListImpl,iface);
69 LPENUMLIST pNew;
71 TRACE("(%p)->(pidl=%p)\n",This,pidl);
72 pNew = (LPENUMLIST)SHAlloc(sizeof(ENUMLIST));
73 if(pNew)
75 /*set the next pointer */
76 pNew->pNext = NULL;
77 pNew->pidl = pidl;
79 /*is This the first item in the list? */
80 if(!This->mpFirst)
82 This->mpFirst = pNew;
83 This->mpCurrent = pNew;
86 if(This->mpLast)
88 /*add the new item to the end of the list */
89 This->mpLast->pNext = pNew;
92 /*update the last item pointer */
93 This->mpLast = pNew;
94 TRACE("-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
95 return TRUE;
97 return FALSE;
100 /**************************************************************************
101 * CreateFolderEnumList()
103 static BOOL CreateFolderEnumList(
104 IEnumIDList * iface,
105 LPCSTR lpszPath,
106 DWORD dwFlags)
108 ICOM_THIS(IEnumIDListImpl,iface);
110 LPITEMIDLIST pidl=NULL;
111 WIN32_FIND_DATAA stffile;
112 HANDLE hFile;
113 CHAR szPath[MAX_PATH];
115 TRACE("(%p)->(path=%s flags=0x%08lx) \n",This,debugstr_a(lpszPath),dwFlags);
117 if(!lpszPath || !lpszPath[0]) return FALSE;
119 strcpy(szPath, lpszPath);
120 PathAddBackslashA(szPath);
121 strcat(szPath,"*.*");
123 /*enumerate the folders*/
124 if(dwFlags & SHCONTF_FOLDERS)
126 TRACE("-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",This,debugstr_a(szPath));
127 hFile = FindFirstFileA(szPath,&stffile);
128 if ( hFile != INVALID_HANDLE_VALUE )
132 if ( !(dwFlags & SHCONTF_INCLUDEHIDDEN) && (stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ) continue;
133 if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
135 pidl = _ILCreateFolder (&stffile);
136 if(pidl && AddToEnumList((IEnumIDList*)This, pidl))
138 continue;
140 return FALSE;
142 } while( FindNextFileA(hFile,&stffile));
143 FindClose (hFile);
147 /*enumerate the non-folder items (values) */
148 if(dwFlags & SHCONTF_NONFOLDERS)
150 TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",This,debugstr_a(szPath));
151 hFile = FindFirstFileA(szPath,&stffile);
152 if ( hFile != INVALID_HANDLE_VALUE )
156 if ( !(dwFlags & SHCONTF_INCLUDEHIDDEN) && (stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ) continue;
157 if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
159 pidl = _ILCreateValue(&stffile);
160 if(pidl && AddToEnumList((IEnumIDList*)This, pidl))
162 continue;
164 return FALSE;
166 } while( FindNextFileA(hFile,&stffile));
167 FindClose (hFile);
170 return TRUE;
173 BOOL SHELL_RegisterCPanelApp(IEnumIDList* list, LPCSTR path)
175 LPITEMIDLIST pidl;
176 CPlApplet* applet;
177 CPanel panel;
178 CPLINFO info;
179 unsigned i;
180 int iconIdx;
182 char displayName[MAX_PATH];
183 char comment[MAX_PATH];
185 WCHAR wpath[MAX_PATH];
187 MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH);
189 panel.first = NULL;
190 applet = Control_LoadApplet(0, wpath, &panel);
192 if (applet) {
193 for(i=0; i<applet->count; ++i) {
194 WideCharToMultiByte(CP_ACP, 0, applet->info[i].szName, -1, displayName, MAX_PATH, 0, 0);
195 WideCharToMultiByte(CP_ACP, 0, applet->info[i].szInfo, -1, comment, MAX_PATH, 0, 0);
197 applet->proc(0, CPL_INQUIRE, i, (LPARAM)&info);
199 if (info.idIcon > 0)
200 iconIdx = -info.idIcon; /* negative icon index instead of icon number */
201 else
202 iconIdx = 0;
204 pidl = _ILCreateCPanel(path, displayName, comment, iconIdx);
206 if (pidl)
207 AddToEnumList(list, pidl);
210 Control_UnloadApplet(applet);
213 return TRUE;
216 int SHELL_RegisterRegistryCPanelApps(IEnumIDList* list, HKEY hkey_root, LPCSTR szRepPath)
218 char name[MAX_PATH];
219 char value[MAX_PATH];
220 HKEY hkey;
222 int cnt = 0;
224 if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
226 int idx = 0;
227 for(;; ++idx)
229 DWORD nameLen = MAX_PATH;
230 DWORD valueLen = MAX_PATH;
232 if (RegEnumValueA(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS)
233 break;
235 if (SHELL_RegisterCPanelApp(list, value))
236 ++cnt;
239 RegCloseKey(hkey);
242 return cnt;
245 int SHELL_RegisterCPanelFolders(IEnumIDList* list, HKEY hkey_root, LPCSTR szRepPath)
247 char name[MAX_PATH];
248 HKEY hkey;
250 int cnt = 0;
252 if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
254 int idx = 0;
255 for(;; ++idx)
257 if (RegEnumKeyA(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
258 break;
260 if (*name == '{') {
261 LPITEMIDLIST pidl = _ILCreateSpecial(name);
263 if (pidl && AddToEnumList(list, pidl))
264 ++cnt;
268 RegCloseKey(hkey);
271 return cnt;
274 /**************************************************************************
275 * CreateCPanelEnumList()
277 static BOOL CreateCPanelEnumList(
278 IEnumIDList * iface,
279 DWORD dwFlags)
281 ICOM_THIS(IEnumIDListImpl,iface);
283 CHAR szPath[MAX_PATH];
284 WIN32_FIND_DATAA wfd;
285 HANDLE hFile;
287 TRACE("(%p)->(flags=0x%08lx) \n",This,dwFlags);
289 /* enumerate control panel folders folders */
290 if (dwFlags & SHCONTF_FOLDERS)
291 SHELL_RegisterCPanelFolders((IEnumIDList*)This, HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace");
293 /* enumerate the control panel applets */
294 if (dwFlags & SHCONTF_NONFOLDERS)
296 LPSTR p;
298 GetSystemDirectoryA(szPath, MAX_PATH);
299 p = PathAddBackslashA(szPath);
300 strcpy(p, "*.cpl");
302 TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",This,debugstr_a(szPath));
303 hFile = FindFirstFileA(szPath, &wfd);
305 if (hFile != INVALID_HANDLE_VALUE)
309 if (!(dwFlags & SHCONTF_INCLUDEHIDDEN) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
310 continue;
312 if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
313 strcpy(p, wfd.cFileName);
314 SHELL_RegisterCPanelApp((IEnumIDList*)This, szPath);
316 } while(FindNextFileA(hFile, &wfd));
318 FindClose(hFile);
321 SHELL_RegisterRegistryCPanelApps((IEnumIDList*)This, HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
322 SHELL_RegisterRegistryCPanelApps((IEnumIDList*)This, HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
325 return TRUE;
328 /**************************************************************************
329 * CreateDesktopEnumList()
331 static BOOL CreateDesktopEnumList(
332 IEnumIDList * iface,
333 DWORD dwFlags)
335 ICOM_THIS(IEnumIDListImpl,iface);
337 LPITEMIDLIST pidl=NULL;
338 HKEY hkey;
339 char szPath[MAX_PATH];
341 TRACE("(%p)->(flags=0x%08lx) \n",This,dwFlags);
343 /*enumerate the root folders */
344 if(dwFlags & SHCONTF_FOLDERS)
346 /*create the pidl for This item */
347 pidl = _ILCreateMyComputer();
348 if(pidl)
350 if(!AddToEnumList((IEnumIDList*)This, pidl))
351 return FALSE;
354 if (! RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\explorer\\desktop\\NameSpace", 0, KEY_READ, &hkey))
356 char iid[50];
357 int i=0;
359 while (1)
361 DWORD size = sizeof (iid);
363 if (ERROR_SUCCESS!=RegEnumKeyExA(hkey, i, iid, &size, 0, NULL, NULL, NULL))
364 break;
366 pidl = _ILCreateSpecial(iid);
368 if(pidl)
369 AddToEnumList((IEnumIDList*)This, pidl);
371 i++;
373 RegCloseKey(hkey);
377 /*enumerate the elements in %windir%\desktop */
378 SHGetSpecialFolderPathA(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
379 CreateFolderEnumList( (IEnumIDList*)This, szPath, dwFlags);
381 return TRUE;
384 /**************************************************************************
385 * CreateMyCompEnumList()
387 static BOOL CreateMyCompEnumList(
388 IEnumIDList * iface,
389 DWORD dwFlags)
391 ICOM_THIS(IEnumIDListImpl,iface);
393 LPITEMIDLIST pidl=NULL;
394 DWORD dwDrivemap;
395 CHAR szDriveName[4];
396 HKEY hkey;
398 TRACE("(%p)->(flags=0x%08lx) \n",This,dwFlags);
400 /*enumerate the folders*/
401 if(dwFlags & SHCONTF_FOLDERS)
403 dwDrivemap = GetLogicalDrives();
404 strcpy (szDriveName,"A:\\");
405 while (szDriveName[0]<='Z')
407 if(dwDrivemap & 0x00000001L)
409 pidl = _ILCreateDrive(szDriveName);
410 if(pidl)
412 if(!AddToEnumList((IEnumIDList*)This, pidl))
413 return FALSE;
416 szDriveName[0]++;
417 dwDrivemap = dwDrivemap >> 1;
420 TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n",This);
421 if (! RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\explorer\\mycomputer\\NameSpace", 0, KEY_READ, &hkey))
423 char iid[50];
424 int i=0;
426 while (1)
428 DWORD size = sizeof (iid);
430 if (ERROR_SUCCESS!=RegEnumKeyExA(hkey, i, iid, &size, 0, NULL, NULL, NULL))
431 break;
433 pidl = _ILCreateSpecial(iid);
435 if(pidl)
436 AddToEnumList((IEnumIDList*)This, pidl);
438 i++;
440 RegCloseKey(hkey);
443 return TRUE;
446 /**************************************************************************
447 * DeleteList()
449 static BOOL DeleteList(
450 IEnumIDList * iface)
452 ICOM_THIS(IEnumIDListImpl,iface);
454 LPENUMLIST pDelete;
456 TRACE("(%p)->()\n",This);
458 while(This->mpFirst)
459 { pDelete = This->mpFirst;
460 This->mpFirst = pDelete->pNext;
461 SHFree(pDelete->pidl);
462 SHFree(pDelete);
464 This->mpFirst = This->mpLast = This->mpCurrent = NULL;
465 return TRUE;
468 /**************************************************************************
469 * IEnumIDList_Folder_Constructor
473 IEnumIDList * IEnumIDList_Constructor(
474 LPCSTR lpszPath,
475 DWORD dwFlags,
476 DWORD dwKind)
478 IEnumIDListImpl* lpeidl;
479 BOOL ret = FALSE;
481 TRACE("()->(%s flags=0x%08lx kind=0x%08lx)\n",debugstr_a(lpszPath),dwFlags, dwKind);
483 lpeidl = (IEnumIDListImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumIDListImpl));
485 if (lpeidl)
487 lpeidl->ref = 1;
488 lpeidl->lpVtbl = &eidlvt;
490 switch (dwKind)
492 case EIDL_DESK:
493 ret = CreateDesktopEnumList((IEnumIDList*)lpeidl, dwFlags);
494 break;
496 case EIDL_MYCOMP:
497 ret = CreateMyCompEnumList((IEnumIDList*)lpeidl, dwFlags);
498 break;
500 case EIDL_FILE:
501 ret = CreateFolderEnumList((IEnumIDList*)lpeidl, lpszPath, dwFlags);
502 break;
504 case EIDL_CPANEL:
505 ret = CreateCPanelEnumList((IEnumIDList*)lpeidl, dwFlags);
506 break;
509 if(!ret) {
510 HeapFree(GetProcessHeap(),0,lpeidl);
511 lpeidl = NULL;
515 TRACE("-- (%p)->()\n",lpeidl);
517 return (IEnumIDList*)lpeidl;
520 /**************************************************************************
521 * EnumIDList_QueryInterface
523 static HRESULT WINAPI IEnumIDList_fnQueryInterface(
524 IEnumIDList * iface,
525 REFIID riid,
526 LPVOID *ppvObj)
528 ICOM_THIS(IEnumIDListImpl,iface);
530 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
532 *ppvObj = NULL;
534 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
535 { *ppvObj = This;
537 else if(IsEqualIID(riid, &IID_IEnumIDList)) /*IEnumIDList*/
538 { *ppvObj = (IEnumIDList*)This;
541 if(*ppvObj)
542 { IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
543 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
544 return S_OK;
547 TRACE("-- Interface: E_NOINTERFACE\n");
548 return E_NOINTERFACE;
551 /******************************************************************************
552 * IEnumIDList_fnAddRef
554 static ULONG WINAPI IEnumIDList_fnAddRef(
555 IEnumIDList * iface)
557 ICOM_THIS(IEnumIDListImpl,iface);
558 TRACE("(%p)->(%lu)\n",This,This->ref);
559 return ++(This->ref);
561 /******************************************************************************
562 * IEnumIDList_fnRelease
564 static ULONG WINAPI IEnumIDList_fnRelease(
565 IEnumIDList * iface)
567 ICOM_THIS(IEnumIDListImpl,iface);
569 TRACE("(%p)->(%lu)\n",This,This->ref);
571 if (!--(This->ref)) {
572 TRACE(" destroying IEnumIDList(%p)\n",This);
573 DeleteList((IEnumIDList*)This);
574 HeapFree(GetProcessHeap(),0,This);
575 return 0;
577 return This->ref;
580 /**************************************************************************
581 * IEnumIDList_fnNext
584 static HRESULT WINAPI IEnumIDList_fnNext(
585 IEnumIDList * iface,
586 ULONG celt,
587 LPITEMIDLIST * rgelt,
588 ULONG *pceltFetched)
590 ICOM_THIS(IEnumIDListImpl,iface);
592 ULONG i;
593 HRESULT hr = S_OK;
594 LPITEMIDLIST temp;
596 TRACE("(%p)->(%ld,%p, %p)\n",This,celt,rgelt,pceltFetched);
598 /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
599 * subsystems actually use it (and so may a third party browser)
601 if(pceltFetched)
602 *pceltFetched = 0;
604 *rgelt=0;
606 if(celt > 1 && !pceltFetched)
607 { return E_INVALIDARG;
610 if(celt > 0 && !This->mpCurrent)
611 { return S_FALSE;
614 for(i = 0; i < celt; i++)
615 { if(!(This->mpCurrent))
616 break;
618 temp = ILClone(This->mpCurrent->pidl);
619 rgelt[i] = temp;
620 This->mpCurrent = This->mpCurrent->pNext;
622 if(pceltFetched)
623 { *pceltFetched = i;
626 return hr;
629 /**************************************************************************
630 * IEnumIDList_fnSkip
632 static HRESULT WINAPI IEnumIDList_fnSkip(
633 IEnumIDList * iface,ULONG celt)
635 ICOM_THIS(IEnumIDListImpl,iface);
637 DWORD dwIndex;
638 HRESULT hr = S_OK;
640 TRACE("(%p)->(%lu)\n",This,celt);
642 for(dwIndex = 0; dwIndex < celt; dwIndex++)
643 { if(!This->mpCurrent)
644 { hr = S_FALSE;
645 break;
647 This->mpCurrent = This->mpCurrent->pNext;
649 return hr;
651 /**************************************************************************
652 * IEnumIDList_fnReset
654 static HRESULT WINAPI IEnumIDList_fnReset(
655 IEnumIDList * iface)
657 ICOM_THIS(IEnumIDListImpl,iface);
659 TRACE("(%p)\n",This);
660 This->mpCurrent = This->mpFirst;
661 return S_OK;
663 /**************************************************************************
664 * IEnumIDList_fnClone
666 static HRESULT WINAPI IEnumIDList_fnClone(
667 IEnumIDList * iface,LPENUMIDLIST * ppenum)
669 ICOM_THIS(IEnumIDListImpl,iface);
671 TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
672 return E_NOTIMPL;
675 /**************************************************************************
676 * IEnumIDList_fnVTable
678 static ICOM_VTABLE (IEnumIDList) eidlvt =
680 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
681 IEnumIDList_fnQueryInterface,
682 IEnumIDList_fnAddRef,
683 IEnumIDList_fnRelease,
684 IEnumIDList_fnNext,
685 IEnumIDList_fnSkip,
686 IEnumIDList_fnReset,
687 IEnumIDList_fnClone,