enumidlist.c 8.98 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 "enumidlist.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36

37
WINE_DEFAULT_DEBUG_CHANNEL(shell);
38

39 40 41 42
typedef struct tagENUMLIST
{
	struct tagENUMLIST	*pNext;
	LPITEMIDLIST		pidl;
Alexandre Julliard's avatar
Alexandre Julliard committed
43

44 45 46 47
} ENUMLIST, *LPENUMLIST;

typedef struct
{
48
	const IEnumIDListVtbl          *lpVtbl;
Mike McCormack's avatar
Mike McCormack committed
49
	LONG				ref;
50 51 52 53 54 55
	LPENUMLIST			mpFirst;
	LPENUMLIST			mpLast;
	LPENUMLIST			mpCurrent;

} IEnumIDListImpl;

56
static const IEnumIDListVtbl eidlvt;
Alexandre Julliard's avatar
Alexandre Julliard committed
57 58

/**************************************************************************
59
 *  AddToEnumList()
Alexandre Julliard's avatar
Alexandre Julliard committed
60
 */
61
BOOL AddToEnumList(
62 63 64
	IEnumIDList * iface,
	LPITEMIDLIST pidl)
{
65
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
Alexandre Julliard's avatar
Alexandre Julliard committed
66

67 68 69
	LPENUMLIST  pNew;

	TRACE("(%p)->(pidl=%p)\n",This,pidl);
70 71 72 73

    if (!iface || !pidl)
        return FALSE;

74
        pNew = SHAlloc(sizeof(ENUMLIST));
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
	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;
	  }
93

94 95 96 97 98 99 100 101 102 103 104
	  /*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()
 */
105 106
BOOL CreateFolderEnumList(
	IEnumIDList *list,
107
	LPCWSTR lpszPath,
108
	DWORD dwFlags)
109
{
110
    LPITEMIDLIST pidl=NULL;
111
    WIN32_FIND_DATAW stffile;
112
    HANDLE hFile;
113
    WCHAR  szPath[MAX_PATH];
114
    BOOL succeeded = TRUE;
115 116 117
    static const WCHAR stars[] = { '*','.','*',0 };
    static const WCHAR dot[] = { '.',0 };
    static const WCHAR dotdot[] = { '.','.',0 };
118

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

121
    if(!lpszPath || !lpszPath[0]) return FALSE;
122

123 124 125
    strcpyW(szPath, lpszPath);
    PathAddBackslashW(szPath);
    strcatW(szPath,stars);
126

127
    hFile = FindFirstFileW(szPath,&stffile);
128 129 130 131 132 133 134 135 136 137 138
    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 &&
139
                 strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot))
140
                {
141
                    pidl = _ILCreateFromFindDataW(&stffile);
142 143 144 145 146
                    succeeded = succeeded && AddToEnumList(list, pidl);
                }
                else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                 && dwFlags & SHCONTF_NONFOLDERS)
                {
147
                    pidl = _ILCreateFromFindDataW(&stffile);
148 149 150 151 152
                    succeeded = succeeded && AddToEnumList(list, pidl);
                }
            }
            if (succeeded)
            {
153
                if (!FindNextFileW(hFile, &stffile))
154 155 156 157 158 159 160 161 162 163 164
                {
                    if (GetLastError() == ERROR_NO_MORE_FILES)
                        findFinished = TRUE;
                    else
                        succeeded = FALSE;
                }
            }
        } while (succeeded && !findFinished);
        FindClose(hFile);
    }
    return succeeded;
165 166 167 168 169 170 171 172
}

/**************************************************************************
*   DeleteList()
*/
static BOOL DeleteList(
	IEnumIDList * iface)
{
173
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
174 175 176 177

	LPENUMLIST  pDelete;

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

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
	while(This->mpFirst)
	{ pDelete = This->mpFirst;
	  This->mpFirst = pDelete->pNext;
	  SHFree(pDelete->pidl);
	  SHFree(pDelete);
	}
	This->mpFirst = This->mpLast = This->mpCurrent = NULL;
	return TRUE;
}

/**************************************************************************
 *  IEnumIDList_Folder_Constructor
 *
 */

194 195
IEnumIDList * IEnumIDList_Constructor(void)
{
196
    IEnumIDListImpl *lpeidl = HeapAlloc(GetProcessHeap(),
197 198 199 200 201 202 203 204 205 206 207 208
     HEAP_ZERO_MEMORY, sizeof(IEnumIDListImpl));

    if (lpeidl)
    {
        lpeidl->ref = 1;
        lpeidl->lpVtbl = &eidlvt;
    }
    TRACE("-- (%p)->()\n",lpeidl);

    return (IEnumIDList*)lpeidl;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
209
/**************************************************************************
Francois Gouget's avatar
Francois Gouget committed
210
 *  EnumIDList_QueryInterface
Alexandre Julliard's avatar
Alexandre Julliard committed
211
 */
212 213 214 215 216
static HRESULT WINAPI IEnumIDList_fnQueryInterface(
	IEnumIDList * iface,
	REFIID riid,
	LPVOID *ppvObj)
{
217
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
Alexandre Julliard's avatar
Alexandre Julliard committed
218

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

221 222 223
	*ppvObj = NULL;

	if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
224
	{ *ppvObj = This;
225 226 227 228 229 230 231
	}
	else if(IsEqualIID(riid, &IID_IEnumIDList))  /*IEnumIDList*/
	{    *ppvObj = (IEnumIDList*)This;
	}

	if(*ppvObj)
	{ IEnumIDList_AddRef((IEnumIDList*)*ppvObj);
232
	  TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
233 234
	  return S_OK;
	}
235

236
	TRACE("-- Interface: E_NOINTERFACE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
237
	return E_NOINTERFACE;
238
}
Alexandre Julliard's avatar
Alexandre Julliard committed
239 240

/******************************************************************************
241
 * IEnumIDList_fnAddRef
Alexandre Julliard's avatar
Alexandre Julliard committed
242
 */
243 244 245
static ULONG WINAPI IEnumIDList_fnAddRef(
	IEnumIDList * iface)
{
246
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
247 248
	ULONG refCount = InterlockedIncrement(&This->ref);

249
	TRACE("(%p)->(%u)\n", This, refCount - 1);
250 251

	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
252 253
}
/******************************************************************************
254
 * IEnumIDList_fnRelease
Alexandre Julliard's avatar
Alexandre Julliard committed
255
 */
256 257 258
static ULONG WINAPI IEnumIDList_fnRelease(
	IEnumIDList * iface)
{
259
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
260
	ULONG refCount = InterlockedDecrement(&This->ref);
261

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

264
	if (!refCount) {
265
	  TRACE(" destroying IEnumIDList(%p)\n",This);
266
	  DeleteList((IEnumIDList*)This);
267
	  HeapFree(GetProcessHeap(),0,This);
Alexandre Julliard's avatar
Alexandre Julliard committed
268
	}
269
	return refCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
270
}
271

Alexandre Julliard's avatar
Alexandre Julliard committed
272
/**************************************************************************
273
 *  IEnumIDList_fnNext
Alexandre Julliard's avatar
Alexandre Julliard committed
274 275
 */

276 277 278 279
static HRESULT WINAPI IEnumIDList_fnNext(
	IEnumIDList * iface,
	ULONG celt,
	LPITEMIDLIST * rgelt,
280
	ULONG *pceltFetched)
281
{
282
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
283 284

	ULONG    i;
Alexandre Julliard's avatar
Alexandre Julliard committed
285 286
	HRESULT  hr = S_OK;
	LPITEMIDLIST  temp;
Alexandre Julliard's avatar
Alexandre Julliard committed
287

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

Alexandre Julliard's avatar
Alexandre Julliard committed
290 291 292 293 294
/* 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
295 296

	*rgelt=0;
297

Alexandre Julliard's avatar
Alexandre Julliard committed
298 299
	if(celt > 1 && !pceltFetched)
	{ return E_INVALIDARG;
Alexandre Julliard's avatar
Alexandre Julliard committed
300 301
	}

302 303 304 305
	if(celt > 0 && !This->mpCurrent)
	{ return S_FALSE;
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
306
	for(i = 0; i < celt; i++)
307
	{ if(!(This->mpCurrent))
Alexandre Julliard's avatar
Alexandre Julliard committed
308
	    break;
309

310
	  temp = ILClone(This->mpCurrent->pidl);
Alexandre Julliard's avatar
Alexandre Julliard committed
311
	  rgelt[i] = temp;
312
	  This->mpCurrent = This->mpCurrent->pNext;
Alexandre Julliard's avatar
Alexandre Julliard committed
313 314 315
	}
	if(pceltFetched)
	{  *pceltFetched = i;
Alexandre Julliard's avatar
Alexandre Julliard committed
316 317
	}

Alexandre Julliard's avatar
Alexandre Julliard committed
318
	return hr;
Alexandre Julliard's avatar
Alexandre Julliard committed
319 320 321
}

/**************************************************************************
322
*  IEnumIDList_fnSkip
Alexandre Julliard's avatar
Alexandre Julliard committed
323
*/
324 325 326
static HRESULT WINAPI IEnumIDList_fnSkip(
	IEnumIDList * iface,ULONG celt)
{
327
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
Alexandre Julliard's avatar
Alexandre Julliard committed
328

329 330
	DWORD    dwIndex;
	HRESULT  hr = S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
331

332
	TRACE("(%p)->(%u)\n",This,celt);
333 334 335 336 337 338 339 340 341

	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
342 343
}
/**************************************************************************
344
*  IEnumIDList_fnReset
Alexandre Julliard's avatar
Alexandre Julliard committed
345
*/
346 347 348
static HRESULT WINAPI IEnumIDList_fnReset(
	IEnumIDList * iface)
{
349
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
350

351
	TRACE("(%p)\n",This);
352 353
	This->mpCurrent = This->mpFirst;
	return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
354 355
}
/**************************************************************************
356
*  IEnumIDList_fnClone
Alexandre Julliard's avatar
Alexandre Julliard committed
357
*/
358 359 360
static HRESULT WINAPI IEnumIDList_fnClone(
	IEnumIDList * iface,LPENUMIDLIST * ppenum)
{
361
	IEnumIDListImpl *This = (IEnumIDListImpl *)iface;
362

363
	TRACE("(%p)->() to (%p)->() E_NOTIMPL\n",This,ppenum);
Alexandre Julliard's avatar
Alexandre Julliard committed
364 365
	return E_NOTIMPL;
}
366 367 368 369

/**************************************************************************
 *  IEnumIDList_fnVTable
 */
370
static const IEnumIDListVtbl eidlvt =
371 372
{
	IEnumIDList_fnQueryInterface,
373 374 375 376 377 378 379
	IEnumIDList_fnAddRef,
	IEnumIDList_fnRelease,
	IEnumIDList_fnNext,
	IEnumIDList_fnSkip,
	IEnumIDList_fnReset,
	IEnumIDList_fnClone,
};