enumidlist.c 8.47 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 *	IEnumIDList
 *
 *	Copyright 1998	Juergen Schmied <juergen.schmied@metronet.de>
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
22 23
#include <stdlib.h>
#include <string.h>
24 25 26

#define COBJMACROS

27
#include "wine/debug.h"
28
#include "wine/unicode.h"
29 30
#include "windef.h"
#include "winbase.h"
31
#include "winreg.h"
32
#include "shlwapi.h"
33

Alexandre Julliard's avatar
Alexandre Julliard committed
34
#include "pidl.h"
35
#include "shell32_main.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36

37
WINE_DEFAULT_DEBUG_CHANNEL(shell);
38

Alexandre Julliard's avatar
Alexandre Julliard committed
39
/**************************************************************************
40
 *  AddToEnumList()
Alexandre Julliard's avatar
Alexandre Julliard committed
41
 */
42
BOOL AddToEnumList(IEnumIDListImpl *This, LPITEMIDLIST pidl)
43
{
44
        struct enumlist *pNew;
45 46

	TRACE("(%p)->(pidl=%p)\n",This,pidl);
47

48
    if (!This || !pidl)
49 50
        return FALSE;

51
        pNew = SHAlloc(sizeof(*pNew));
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	if(pNew)
	{
	  /*set the next pointer */
	  pNew->pNext = NULL;
	  pNew->pidl = pidl;

	  /*is This the first item in the list? */
	  if(!This->mpFirst)
	  {
	    This->mpFirst = pNew;
	    This->mpCurrent = pNew;
	  }

	  if(This->mpLast)
	  {
	    /*add the new item to the end of the list */
	    This->mpLast->pNext = pNew;
	  }
70

71 72 73 74 75 76 77 78 79 80 81
	  /*update the last item pointer */
	  This->mpLast = pNew;
	  TRACE("-- (%p)->(first=%p, last=%p)\n",This,This->mpFirst,This->mpLast);
	  return TRUE;
	}
	return FALSE;
}

/**************************************************************************
 *  CreateFolderEnumList()
 */
82
BOOL CreateFolderEnumList(IEnumIDListImpl *list, LPCWSTR lpszPath, DWORD dwFlags)
83
{
84
    LPITEMIDLIST pidl=NULL;
85
    WIN32_FIND_DATAW stffile;
86
    HANDLE hFile;
87
    WCHAR  szPath[MAX_PATH];
88
    BOOL succeeded = TRUE;
89 90 91
    static const WCHAR stars[] = { '*','.','*',0 };
    static const WCHAR dot[] = { '.',0 };
    static const WCHAR dotdot[] = { '.','.',0 };
92

93
    TRACE("(%p)->(path=%s flags=0x%08x)\n", list, debugstr_w(lpszPath), dwFlags);
94

95
    if(!lpszPath || !lpszPath[0]) return FALSE;
96

97 98 99
    strcpyW(szPath, lpszPath);
    PathAddBackslashW(szPath);
    strcatW(szPath,stars);
100

101
    hFile = FindFirstFileW(szPath,&stffile);
102 103 104 105 106 107 108 109 110 111 112
    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 &&
113
                 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
114
                {
115
                    pidl = _ILCreateFromFindDataW(&stffile);
116 117 118 119 120
                    succeeded = succeeded && AddToEnumList(list, pidl);
                }
                else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                 && dwFlags & SHCONTF_NONFOLDERS)
                {
121
                    pidl = _ILCreateFromFindDataW(&stffile);
122 123 124 125 126
                    succeeded = succeeded && AddToEnumList(list, pidl);
                }
            }
            if (succeeded)
            {
127
                if (!FindNextFileW(hFile, &stffile))
128 129 130 131 132 133 134 135 136 137 138
                {
                    if (GetLastError() == ERROR_NO_MORE_FILES)
                        findFinished = TRUE;
                    else
                        succeeded = FALSE;
                }
            }
        } while (succeeded && !findFinished);
        FindClose(hFile);
    }
    return succeeded;
139 140
}

141
static BOOL DeleteList(IEnumIDListImpl *This)
142
{
143
        struct enumlist *pDelete;
144 145

	TRACE("(%p)->()\n",This);
146

147 148 149 150 151 152 153 154 155 156
	while(This->mpFirst)
	{ pDelete = This->mpFirst;
	  This->mpFirst = pDelete->pNext;
	  SHFree(pDelete->pidl);
	  SHFree(pDelete);
	}
	This->mpFirst = This->mpLast = This->mpCurrent = NULL;
	return TRUE;
}

157 158 159 160 161
static inline IEnumIDListImpl *impl_from_IEnumIDList(IEnumIDList *iface)
{
    return CONTAINING_RECORD(iface, IEnumIDListImpl, IEnumIDList_iface);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
162
/**************************************************************************
163
 *  IEnumIDList::QueryInterface
Alexandre Julliard's avatar
Alexandre Julliard committed
164
 */
165
static HRESULT WINAPI IEnumIDList_fnQueryInterface(IEnumIDList *iface, REFIID riid, void **ppvObj)
166
{
167
        IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
168

169
	TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
Alexandre Julliard's avatar
Alexandre Julliard committed
170

171 172 173
	*ppvObj = NULL;

	if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
174
	{ *ppvObj = This;
175 176
	}
	else if(IsEqualIID(riid, &IID_IEnumIDList))  /*IEnumIDList*/
177
	{    *ppvObj = This;
178 179 180 181
	}

	if(*ppvObj)
	{ IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
182
	  TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
183 184
	  return S_OK;
	}
185

186
	TRACE("-- Interface: E_NOINTERFACE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
187
	return E_NOINTERFACE;
188
}
Alexandre Julliard's avatar
Alexandre Julliard committed
189 190

/******************************************************************************
191
 * IEnumIDList::AddRef
Alexandre Julliard's avatar
Alexandre Julliard committed
192
 */
193
static ULONG WINAPI IEnumIDList_fnAddRef(IEnumIDList *iface)
194
{
195
        IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
196 197
	ULONG refCount = InterlockedIncrement(&This->ref);

198
	TRACE("(%p)->(%u)\n", This, refCount - 1);
199 200

	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
201 202
}
/******************************************************************************
203
 * IEnumIDList::Release
Alexandre Julliard's avatar
Alexandre Julliard committed
204
 */
205
static ULONG WINAPI IEnumIDList_fnRelease(IEnumIDList *iface)
206
{
207
        IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
208
	ULONG refCount = InterlockedDecrement(&This->ref);
209

210
	TRACE("(%p)->(%u)\n", This, refCount + 1);
211

212
	if (!refCount) {
213
	  TRACE(" destroying IEnumIDList(%p)\n",This);
214
          DeleteList(This);
215
	  HeapFree(GetProcessHeap(),0,This);
Alexandre Julliard's avatar
Alexandre Julliard committed
216
	}
217
	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
218
}
219

Alexandre Julliard's avatar
Alexandre Julliard committed
220
/**************************************************************************
221
 *  IEnumIDList::Next
Alexandre Julliard's avatar
Alexandre Julliard committed
222 223
 */

224 225
static HRESULT WINAPI IEnumIDList_fnNext(IEnumIDList *iface, ULONG celt, LPITEMIDLIST *rgelt,
        ULONG *pceltFetched)
226
{
227
        IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
228 229

	ULONG    i;
Alexandre Julliard's avatar
Alexandre Julliard committed
230 231
	HRESULT  hr = S_OK;
	LPITEMIDLIST  temp;
Alexandre Julliard's avatar
Alexandre Julliard committed
232

233
	TRACE("(%p)->(%d,%p, %p)\n",This,celt,rgelt,pceltFetched);
Alexandre Julliard's avatar
Alexandre Julliard committed
234

Alexandre Julliard's avatar
Alexandre Julliard committed
235 236 237 238 239
/* 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(pceltFetched)
	  *pceltFetched = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
240 241

	*rgelt=0;
242

Alexandre Julliard's avatar
Alexandre Julliard committed
243 244
	if(celt > 1 && !pceltFetched)
	{ return E_INVALIDARG;
Alexandre Julliard's avatar
Alexandre Julliard committed
245 246
	}

247 248 249 250
	if(celt > 0 && !This->mpCurrent)
	{ return S_FALSE;
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
251
	for(i = 0; i < celt; i++)
252
	{ if(!(This->mpCurrent))
Alexandre Julliard's avatar
Alexandre Julliard committed
253
	    break;
254

255
	  temp = ILClone(This->mpCurrent->pidl);
Alexandre Julliard's avatar
Alexandre Julliard committed
256
	  rgelt[i] = temp;
257
	  This->mpCurrent = This->mpCurrent->pNext;
Alexandre Julliard's avatar
Alexandre Julliard committed
258 259 260
	}
	if(pceltFetched)
	{  *pceltFetched = i;
Alexandre Julliard's avatar
Alexandre Julliard committed
261 262
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
263
	return hr;
Alexandre Julliard's avatar
Alexandre Julliard committed
264 265 266
}

/**************************************************************************
267
*  IEnumIDList::Skip
Alexandre Julliard's avatar
Alexandre Julliard committed
268
*/
269
static HRESULT WINAPI IEnumIDList_fnSkip(IEnumIDList *iface, ULONG celt)
270
{
271
        IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
Alexandre Julliard's avatar
Alexandre Julliard committed
272

273 274
	DWORD    dwIndex;
	HRESULT  hr = S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
275

276
	TRACE("(%p)->(%u)\n",This,celt);
277 278 279 280 281 282 283 284 285

	for(dwIndex = 0; dwIndex < celt; dwIndex++)
	{ if(!This->mpCurrent)
	  { hr = S_FALSE;
	    break;
	  }
	  This->mpCurrent = This->mpCurrent->pNext;
	}
	return hr;
Alexandre Julliard's avatar
Alexandre Julliard committed
286 287
}
/**************************************************************************
288
*  IEnumIDList::Reset
Alexandre Julliard's avatar
Alexandre Julliard committed
289
*/
290
static HRESULT WINAPI IEnumIDList_fnReset(IEnumIDList *iface)
291
{
292
        IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
293

294
	TRACE("(%p)\n",This);
295 296
	This->mpCurrent = This->mpFirst;
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
297 298
}
/**************************************************************************
299
*  IEnumIDList::Clone
Alexandre Julliard's avatar
Alexandre Julliard committed
300
*/
301
static HRESULT WINAPI IEnumIDList_fnClone(IEnumIDList *iface, IEnumIDList **ppenum)
302
{
303
        IEnumIDListImpl *This = impl_from_IEnumIDList(iface);
304

305
	TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
Alexandre Julliard's avatar
Alexandre Julliard committed
306 307
	return E_NOTIMPL;
}
308

309
static const IEnumIDListVtbl eidlvt =
310 311
{
	IEnumIDList_fnQueryInterface,
312 313 314 315 316 317 318
	IEnumIDList_fnAddRef,
	IEnumIDList_fnRelease,
	IEnumIDList_fnNext,
	IEnumIDList_fnSkip,
	IEnumIDList_fnReset,
	IEnumIDList_fnClone,
};
319

320
IEnumIDListImpl *IEnumIDList_Constructor(void)
321 322 323 324 325 326 327 328 329 330 331
{
    IEnumIDListImpl *lpeidl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lpeidl));

    if (lpeidl)
    {
        lpeidl->ref = 1;
        lpeidl->IEnumIDList_iface.lpVtbl = &eidlvt;
    }

    TRACE("-- (%p)->()\n",lpeidl);

332
    return lpeidl;
333
}