| /* | |
| * IEnumIDList | |
| * | |
| * Copyright 1998 Juergen Schmied <juergen.schmied@metronet.de> | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include <stdarg.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #define COBJMACROS | |
| #include "wine/debug.h" | |
| #include "wine/unicode.h" | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winreg.h" | |
| #include "shlwapi.h" | |
| #include "pidl.h" | |
| #include "shell32_main.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(shell); | |
| /************************************************************************** | |
| * AddToEnumList() | |
| */ | |
| BOOL AddToEnumList(IEnumIDListImpl *list, LPITEMIDLIST pidl) | |
| { | |
| struct pidl_enum_entry *pidl_entry; | |
| TRACE("(%p)->(pidl=%p)\n", list, pidl); | |
| if (!list || !pidl) | |
| return FALSE; | |
| if (!(pidl_entry = SHAlloc(sizeof(*pidl_entry)))) | |
| return FALSE; | |
| pidl_entry->pidl = pidl; | |
| list_add_tail(&list->pidls, &pidl_entry->entry); | |
| if (!list->current) | |
| list->current = list_head(&list->pidls); | |
| return TRUE; | |
| } | |
| /************************************************************************** | |
| * CreateFolderEnumList() | |
| */ | |
| BOOL CreateFolderEnumList(IEnumIDListImpl *list, LPCWSTR lpszPath, DWORD dwFlags) | |
| { | |
| LPITEMIDLIST pidl=NULL; | |
| WIN32_FIND_DATAW stffile; | |
| HANDLE hFile; | |
| WCHAR szPath[MAX_PATH]; | |
| BOOL succeeded = TRUE; | |
| static const WCHAR stars[] = { '*','.','*',0 }; | |
| static const WCHAR dot[] = { '.',0 }; | |
| static const WCHAR dotdot[] = { '.','.',0 }; | |
| TRACE("(%p)->(path=%s flags=0x%08x)\n", list, debugstr_w(lpszPath), dwFlags); | |
| if(!lpszPath || !lpszPath[0]) return FALSE; | |
| strcpyW(szPath, lpszPath); | |
| PathAddBackslashW(szPath); | |
| strcatW(szPath,stars); | |
| hFile = FindFirstFileW(szPath,&stffile); | |
| if ( hFile != INVALID_HANDLE_VALUE ) | |
| { | |
| BOOL findFinished = FALSE; | |
| do | |
| { | |
| if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) | |
| || (dwFlags & SHCONTF_INCLUDEHIDDEN) ) | |
| { | |
| if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && | |
| dwFlags & SHCONTF_FOLDERS && | |
| strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot)) | |
| { | |
| pidl = _ILCreateFromFindDataW(&stffile); | |
| succeeded = succeeded && AddToEnumList(list, pidl); | |
| } | |
| else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
| && dwFlags & SHCONTF_NONFOLDERS) | |
| { | |
| pidl = _ILCreateFromFindDataW(&stffile); | |
| succeeded = succeeded && AddToEnumList(list, pidl); | |
| } | |
| } | |
| if (succeeded) | |
| { | |
| if (!FindNextFileW(hFile, &stffile)) | |
| { | |
| if (GetLastError() == ERROR_NO_MORE_FILES) | |
| findFinished = TRUE; | |
| else | |
| succeeded = FALSE; | |
| } | |
| } | |
| } while (succeeded && !findFinished); | |
| FindClose(hFile); | |
| } | |
| return succeeded; | |
| } | |
| static inline IEnumIDListImpl *impl_from_IEnumIDList(IEnumIDList *iface) | |
| { | |
| return CONTAINING_RECORD(iface, IEnumIDListImpl, IEnumIDList_iface); | |
| } | |
| /************************************************************************** | |
| * IEnumIDList::QueryInterface | |
| */ | |
| static HRESULT WINAPI IEnumIDList_fnQueryInterface(IEnumIDList *iface, REFIID riid, void **ppvObj) | |
| { | |
| IEnumIDListImpl *This = impl_from_IEnumIDList(iface); | |
| TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj); | |
| *ppvObj = NULL; | |
| if (IsEqualIID(riid, &IID_IUnknown) || | |
| IsEqualIID(riid, &IID_IEnumIDList)) | |
| { | |
| *ppvObj = &This->IEnumIDList_iface; | |
| } | |
| if (*ppvObj) | |
| { | |
| IUnknown_AddRef((IUnknown*)*ppvObj); | |
| return S_OK; | |
| } | |
| WARN("interface %s is not supported\n", debugstr_guid(riid)); | |
| return E_NOINTERFACE; | |
| } | |
| /****************************************************************************** | |
| * IEnumIDList::AddRef | |
| */ | |
| static ULONG WINAPI IEnumIDList_fnAddRef(IEnumIDList *iface) | |
| { | |
| IEnumIDListImpl *This = impl_from_IEnumIDList(iface); | |
| ULONG refCount = InterlockedIncrement(&This->ref); | |
| TRACE("(%p)->(%u)\n", This, refCount - 1); | |
| return refCount; | |
| } | |
| /****************************************************************************** | |
| * IEnumIDList::Release | |
| */ | |
| static ULONG WINAPI IEnumIDList_fnRelease(IEnumIDList *iface) | |
| { | |
| IEnumIDListImpl *This = impl_from_IEnumIDList(iface); | |
| ULONG refCount = InterlockedDecrement(&This->ref); | |
| TRACE("(%p)->(%u)\n", This, refCount + 1); | |
| if (!refCount) | |
| { | |
| struct pidl_enum_entry *cur, *cur2; | |
| LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &This->pidls, struct pidl_enum_entry, entry) | |
| { | |
| list_remove(&cur->entry); | |
| SHFree(cur->pidl); | |
| SHFree(cur); | |
| } | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return refCount; | |
| } | |
| /************************************************************************** | |
| * IEnumIDList::Next | |
| */ | |
| static HRESULT WINAPI IEnumIDList_fnNext(IEnumIDList *iface, ULONG celt, LPITEMIDLIST *rgelt, | |
| ULONG *fetched) | |
| { | |
| IEnumIDListImpl *This = impl_from_IEnumIDList(iface); | |
| HRESULT hr = S_OK; | |
| ULONG i; | |
| TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, fetched); | |
| /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's | |
| * subsystems actually use it (and so may a third party browser) | |
| */ | |
| if (fetched) | |
| *fetched = 0; | |
| *rgelt = NULL; | |
| if (celt > 1 && !fetched) | |
| return E_INVALIDARG; | |
| if (celt > 0 && !This->current) | |
| return S_FALSE; | |
| for (i = 0; i < celt; i++) | |
| { | |
| if (!This->current) | |
| break; | |
| rgelt[i] = ILClone(LIST_ENTRY(This->current, struct pidl_enum_entry, entry)->pidl); | |
| This->current = list_next(&This->pidls, This->current); | |
| } | |
| if (fetched) | |
| *fetched = i; | |
| return hr; | |
| } | |
| /************************************************************************** | |
| * IEnumIDList::Skip | |
| */ | |
| static HRESULT WINAPI IEnumIDList_fnSkip(IEnumIDList *iface, ULONG celt) | |
| { | |
| IEnumIDListImpl *This = impl_from_IEnumIDList(iface); | |
| HRESULT hr = S_OK; | |
| ULONG i; | |
| TRACE("(%p)->(%u)\n", This, celt); | |
| for (i = 0; i < celt; i++) | |
| { | |
| if (!This->current) | |
| { | |
| hr = S_FALSE; | |
| break; | |
| } | |
| This->current = list_next(&This->pidls, This->current); | |
| } | |
| return hr; | |
| } | |
| /************************************************************************** | |
| * IEnumIDList::Reset | |
| */ | |
| static HRESULT WINAPI IEnumIDList_fnReset(IEnumIDList *iface) | |
| { | |
| IEnumIDListImpl *This = impl_from_IEnumIDList(iface); | |
| TRACE("(%p)\n",This); | |
| This->current = list_head(&This->pidls); | |
| return S_OK; | |
| } | |
| /************************************************************************** | |
| * IEnumIDList::Clone | |
| */ | |
| static HRESULT WINAPI IEnumIDList_fnClone(IEnumIDList *iface, IEnumIDList **ppenum) | |
| { | |
| IEnumIDListImpl *This = impl_from_IEnumIDList(iface); | |
| FIXME("(%p)->(%p): stub\n",This, ppenum); | |
| return E_NOTIMPL; | |
| } | |
| static const IEnumIDListVtbl eidlvt = | |
| { | |
| IEnumIDList_fnQueryInterface, | |
| IEnumIDList_fnAddRef, | |
| IEnumIDList_fnRelease, | |
| IEnumIDList_fnNext, | |
| IEnumIDList_fnSkip, | |
| IEnumIDList_fnReset, | |
| IEnumIDList_fnClone, | |
| }; | |
| IEnumIDListImpl *IEnumIDList_Constructor(void) | |
| { | |
| IEnumIDListImpl *lpeidl = HeapAlloc(GetProcessHeap(), 0, sizeof(*lpeidl)); | |
| if (lpeidl) | |
| { | |
| lpeidl->IEnumIDList_iface.lpVtbl = &eidlvt; | |
| lpeidl->ref = 1; | |
| list_init(&lpeidl->pidls); | |
| lpeidl->current = NULL; | |
| } | |
| TRACE("-- (%p)->()\n",lpeidl); | |
| return lpeidl; | |
| } |