reactos/dll/win32/shell32/shellrecyclebin/recyclebin_generic_enumerator.c

234 lines
5.6 KiB
C

/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/recyclebin_generic_enumerator.c
* PURPOSE: Enumerates contents of all recycle bins
* PROGRAMMERS: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "recyclebin_private.h"
struct RecycleBinGenericEnum
{
ULONG ref;
IRecycleBinEnumList recycleBinEnumImpl;
IRecycleBinEnumList *current;
DWORD dwLogicalDrives;
SIZE_T skip;
};
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_QueryInterface(
IN IRecycleBinEnumList *This,
IN REFIID riid,
OUT void **ppvObject)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, &IID_IUnknown))
*ppvObject = &s->recycleBinEnumImpl;
else if (IsEqualIID(riid, &IID_IRecycleBinEnumList))
*ppvObject = &s->recycleBinEnumImpl;
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef(This);
return S_OK;
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_AddRef(
IN IRecycleBinEnumList *This)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
TRACE("(%p)\n", This);
return refCount;
}
static VOID
RecycleBinGenericEnum_Destructor(
struct RecycleBinGenericEnum *s)
{
TRACE("(%p)\n", s);
if (s->current)
IRecycleBinEnumList_Release(s->current);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Release(
IN IRecycleBinEnumList *This)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
ULONG refCount;
TRACE("(%p)\n", This);
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
RecycleBinGenericEnum_Destructor(s);
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Next(
IN IRecycleBinEnumList *This,
IN DWORD celt,
IN OUT IRecycleBinFile **rgelt,
OUT DWORD *pceltFetched)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
IRecycleBin *prb;
DWORD i;
DWORD fetched = 0, newFetched;
HRESULT hr;
TRACE("(%p, %u, %p, %p)\n", This, celt, rgelt, pceltFetched);
if (!rgelt)
return E_POINTER;
if (!pceltFetched && celt > 1)
return E_INVALIDARG;
while (TRUE)
{
/* Get enumerator implementation */
if (!s->current && s->dwLogicalDrives)
{
for (i = 0; i < 26; i++)
if (s->dwLogicalDrives & (1 << i))
{
WCHAR szVolumeName[4];
szVolumeName[0] = (WCHAR)('A' + i);
szVolumeName[1] = ':';
szVolumeName[2] = '\\';
szVolumeName[3] = UNICODE_NULL;
if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
{
s->dwLogicalDrives &= ~(1 << i);
continue;
}
hr = GetDefaultRecycleBin(szVolumeName, &prb);
if (!SUCCEEDED(hr))
return hr;
hr = IRecycleBin_EnumObjects(prb, &s->current);
IRecycleBin_Release(prb);
if (!SUCCEEDED(hr))
return hr;
s->dwLogicalDrives &= ~(1 << i);
break;
}
}
if (!s->current)
{
/* Nothing more to enumerate */
if (pceltFetched)
*pceltFetched = fetched;
return S_FALSE;
}
/* Skip some elements */
while (s->skip > 0)
{
IRecycleBinFile *rbf;
hr = IRecycleBinEnumList_Next(s->current, 1, &rbf, NULL);
if (hr == S_OK)
hr = IRecycleBinFile_Release(rbf);
else if (hr == S_FALSE)
break;
else if (!SUCCEEDED(hr))
return hr;
}
if (s->skip > 0)
continue;
/* Fill area */
hr = IRecycleBinEnumList_Next(s->current, celt - fetched, &rgelt[fetched], &newFetched);
if (SUCCEEDED(hr))
fetched += newFetched;
if (hr == S_FALSE || newFetched == 0)
{
hr = IRecycleBinEnumList_Release(s->current);
s->current = NULL;
}
else if (!SUCCEEDED(hr))
return hr;
if (fetched == celt)
{
if (pceltFetched)
*pceltFetched = fetched;
return S_OK;
}
}
/* Never go here */
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Skip(
IN IRecycleBinEnumList *This,
IN DWORD celt)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
TRACE("(%p, %u)\n", This, celt);
s->skip += celt;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGenericEnum_RecycleBinEnumList_Reset(
IN IRecycleBinEnumList *This)
{
struct RecycleBinGenericEnum *s = CONTAINING_RECORD(This, struct RecycleBinGenericEnum, recycleBinEnumImpl);
TRACE("(%p)\n", This);
if (s->current)
{
IRecycleBinEnumList_Release(s->current);
s->current = NULL;
s->skip = 0;
}
s->dwLogicalDrives = GetLogicalDrives();
return S_OK;
}
CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBinGenericEnumVtbl =
{
RecycleBinGenericEnum_RecycleBinEnumList_QueryInterface,
RecycleBinGenericEnum_RecycleBinEnumList_AddRef,
RecycleBinGenericEnum_RecycleBinEnumList_Release,
RecycleBinGenericEnum_RecycleBinEnumList_Next,
RecycleBinGenericEnum_RecycleBinEnumList_Skip,
RecycleBinGenericEnum_RecycleBinEnumList_Reset,
};
HRESULT
RecycleBinGenericEnum_Constructor(
OUT IRecycleBinEnumList **pprbel)
{
struct RecycleBinGenericEnum *s;
s = CoTaskMemAlloc(sizeof(struct RecycleBinGenericEnum));
if (!s)
return E_OUTOFMEMORY;
ZeroMemory(s, sizeof(struct RecycleBinGenericEnum));
s->ref = 1;
s->recycleBinEnumImpl.lpVtbl = &RecycleBinGenericEnumVtbl;
*pprbel = &s->recycleBinEnumImpl;
return IRecycleBinEnumList_Reset(*pprbel);
}