[SHELL32] RecycleBinGenericEnum: Make it C++ (#7167)

Modernize code.
JIRA issue: CORE-19595
Rewrite RecycleBinGenericEnum
in C++.
This commit is contained in:
Katayama Hirofumi MZ 2024-07-24 11:24:56 +09:00 committed by GitHub
parent d5aca44042
commit 72116d0558
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 222 additions and 235 deletions

View file

@ -7,7 +7,7 @@ add_definitions(
list(APPEND SOURCE
recyclebin.c
recyclebin_generic.c
recyclebin_generic_enumerator.c
recyclebin_generic_enumerator.cpp
recyclebin_v5.c
recyclebin_v5_enumerator.c
recyclebin_private.h)

View file

@ -214,7 +214,7 @@ DECLARE_INTERFACE_(IRecycleBinEnumList, IUnknown)
STDMETHOD_(ULONG, Release)(THIS) PURE;
/* IRecycleBinEnumList methods */
STDMETHOD(Next)(THIS_ DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched);
STDMETHOD(Next)(THIS_ DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched) PURE;
STDMETHOD(Skip)(THIS_ DWORD celt) PURE;
STDMETHOD(Reset)(THIS) PURE;

View file

@ -1,233 +0,0 @@
/*
* 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);
}

View file

@ -0,0 +1,219 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Enumerates contents of all recycle bins
* COPYRIGHT: Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
* Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include "recyclebin_private.h"
class RecycleBinGenericEnum : public IRecycleBinEnumList
{
public:
RecycleBinGenericEnum();
virtual ~RecycleBinGenericEnum();
/* IUnknown methods */
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
/* IRecycleBinEnumList methods */
STDMETHODIMP Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched) override;
STDMETHODIMP Skip(DWORD celt) override;
STDMETHODIMP Reset() override;
protected:
LONG m_ref;
IRecycleBinEnumList *m_current;
DWORD m_dwLogicalDrives;
SIZE_T m_skip;
};
STDMETHODIMP
RecycleBinGenericEnum::QueryInterface(REFIID riid, void **ppvObject)
{
TRACE("(%p, %s, %p)\n", this, debugstr_guid(&riid), ppvObject);
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRecycleBinEnumList))
*ppvObject = static_cast<IRecycleBinEnumList *>(this);
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG)
RecycleBinGenericEnum::AddRef()
{
ULONG refCount = InterlockedIncrement(&m_ref);
TRACE("(%p)\n", this);
return refCount;
}
RecycleBinGenericEnum::~RecycleBinGenericEnum()
{
TRACE("(%p)\n", this);
if (m_current)
m_current->Release();
}
STDMETHODIMP_(ULONG)
RecycleBinGenericEnum::Release()
{
TRACE("(%p)\n", this);
ULONG refCount = InterlockedDecrement(&m_ref);
if (refCount == 0)
delete this;
return refCount;
}
STDMETHODIMP
RecycleBinGenericEnum::Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched)
{
TRACE("(%p, %u, %p, %p)\n", this, celt, rgelt, pceltFetched);
if (!rgelt)
return E_POINTER;
if (!pceltFetched && celt > 1)
return E_INVALIDARG;
HRESULT hr;
DWORD fetched = 0;
while (TRUE)
{
/* Get enumerator implementation */
if (!m_current && m_dwLogicalDrives)
{
for (DWORD i = 0; i < L'Z' - L'A' + 1; ++i)
{
if (m_dwLogicalDrives & (1 << i))
{
WCHAR szVolumeName[4];
szVolumeName[0] = (WCHAR)(L'A' + i);
szVolumeName[1] = L':';
szVolumeName[2] = L'\\';
szVolumeName[3] = UNICODE_NULL;
if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
{
m_dwLogicalDrives &= ~(1 << i);
continue;
}
IRecycleBin *prb;
hr = GetDefaultRecycleBin(szVolumeName, &prb);
if (!SUCCEEDED(hr))
return hr;
hr = prb->EnumObjects(&m_current);
prb->Release();
if (!SUCCEEDED(hr))
return hr;
m_dwLogicalDrives &= ~(1 << i);
break;
}
}
}
if (!m_current)
{
/* Nothing more to enumerate */
if (pceltFetched)
*pceltFetched = fetched;
return S_FALSE;
}
/* Skip some elements */
while (m_skip > 0)
{
IRecycleBinFile *rbf;
hr = m_current->Next(1, &rbf, NULL);
if (hr == S_OK)
rbf->Release();
else if (hr == S_FALSE)
break;
else if (!SUCCEEDED(hr))
return hr;
}
if (m_skip > 0)
continue;
/* Fill area */
DWORD newFetched;
hr = m_current->Next(celt - fetched, &rgelt[fetched], &newFetched);
if (SUCCEEDED(hr))
fetched += newFetched;
if (hr == S_FALSE || newFetched == 0)
{
m_current->Release();
m_current = NULL;
}
else if (!SUCCEEDED(hr))
return hr;
if (fetched == celt)
{
if (pceltFetched)
*pceltFetched = fetched;
return S_OK;
}
}
/* Never go here */
UNREACHABLE;
}
STDMETHODIMP RecycleBinGenericEnum::Skip(DWORD celt)
{
TRACE("(%p, %u)\n", this, celt);
m_skip += celt;
return S_OK;
}
STDMETHODIMP RecycleBinGenericEnum::Reset()
{
TRACE("(%p)\n", this);
if (m_current)
{
m_current->Release();
m_current = NULL;
}
m_skip = 0;
m_dwLogicalDrives = ::GetLogicalDrives();
return S_OK;
}
RecycleBinGenericEnum::RecycleBinGenericEnum()
: m_ref(1)
, m_current(NULL)
, m_dwLogicalDrives(0)
, m_skip(0)
{
}
EXTERN_C
HRESULT
RecycleBinGenericEnum_Constructor(
OUT IRecycleBinEnumList **pprbel)
{
RecycleBinGenericEnum *pThis = new RecycleBinGenericEnum();
if (!pThis)
return E_OUTOFMEMORY;
*pprbel = static_cast<IRecycleBinEnumList *>(pThis);
return (*pprbel)->Reset();
}

View file

@ -44,6 +44,7 @@ HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown);
/* recyclebin_generic_enumerator.c */
EXTERN_C
HRESULT RecycleBinGenericEnum_Constructor(OUT IRecycleBinEnumList **pprbel);
/* recyclebin_v5.c */