[SHELL32] RecycleBinGeneric: Make it C++ (#7169)

Modernize code.
JIRA issue: CORE-19595
Rewrite RecycleBinGeneric in C++.
This commit is contained in:
Katayama Hirofumi MZ
2024-07-24 12:16:37 +09:00
committed by GitHub
parent 72116d0558
commit 6910fa624f
4 changed files with 179 additions and 215 deletions
@@ -6,7 +6,7 @@ add_definitions(
list(APPEND SOURCE
recyclebin.c
recyclebin_generic.c
recyclebin_generic.cpp
recyclebin_generic_enumerator.cpp
recyclebin_v5.c
recyclebin_v5_enumerator.c
@@ -1,214 +0,0 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/recyclebin_generic.c
* PURPOSE: Deals with a system-wide recycle bin
* PROGRAMMERS: Copyright 2007 Hervé Poussineau ([email protected])
*/
#include "recyclebin_private.h"
struct RecycleBinGeneric
{
ULONG ref;
IRecycleBin recycleBinImpl;
};
static HRESULT STDMETHODCALLTYPE
RecycleBinGeneric_RecycleBin_QueryInterface(
IRecycleBin *This,
REFIID riid,
void **ppvObject)
{
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, &IID_IUnknown))
*ppvObject = &s->recycleBinImpl;
else if (IsEqualIID(riid, &IID_IRecycleBin))
*ppvObject = &s->recycleBinImpl;
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef(This);
return S_OK;
}
static ULONG STDMETHODCALLTYPE
RecycleBinGeneric_RecycleBin_AddRef(
IRecycleBin *This)
{
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
TRACE("(%p)\n", This);
return refCount;
}
static VOID
RecycleBinGeneric_Destructor(
struct RecycleBinGeneric *s)
{
TRACE("(%p)\n", s);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBinGeneric_RecycleBin_Release(
IRecycleBin *This)
{
struct RecycleBinGeneric *s = CONTAINING_RECORD(This, struct RecycleBinGeneric, recycleBinImpl);
ULONG refCount;
TRACE("(%p)\n", This);
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
RecycleBinGeneric_Destructor(s);
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGeneric_RecycleBin_DeleteFile(
IN IRecycleBin *This,
IN LPCWSTR szFileName)
{
IRecycleBin *prb;
LPWSTR szFullName = NULL;
DWORD dwBufferLength = 0;
DWORD len;
WCHAR szVolume[MAX_PATH];
HRESULT hr;
TRACE("(%p, %s)\n", This, debugstr_w(szFileName));
/* Get full file name */
while (TRUE)
{
len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, NULL);
if (len == 0)
{
if (szFullName)
CoTaskMemFree(szFullName);
return HRESULT_FROM_WIN32(GetLastError());
}
else if (len < dwBufferLength)
break;
if (szFullName)
CoTaskMemFree(szFullName);
dwBufferLength = len;
szFullName = CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
if (!szFullName)
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
/* Get associated volume path */
#ifndef __REACTOS__
if (!GetVolumePathNameW(szFullName, szVolume, MAX_PATH))
{
CoTaskMemFree(szFullName);
return HRESULT_FROM_WIN32(GetLastError());
}
#else
swprintf(szVolume, L"%c:\\", szFullName[0]);
#endif
/* Skip namespace (if any) */
if (szVolume[0] == '\\'
&& szVolume[1] == '\\'
&& (szVolume[2] == '.' || szVolume[2] == '?')
&& szVolume[3] == '\\')
{
MoveMemory(szVolume, &szVolume[4], (MAX_PATH - 4) * sizeof(WCHAR));
}
hr = GetDefaultRecycleBin(szVolume, &prb);
if (!SUCCEEDED(hr))
{
CoTaskMemFree(szFullName);
return hr;
}
hr = IRecycleBin_DeleteFile(prb, szFullName);
CoTaskMemFree(szFullName);
IRecycleBin_Release(prb);
return hr;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGeneric_RecycleBin_EmptyRecycleBin(
IN IRecycleBin *This)
{
WCHAR szVolumeName[MAX_PATH];
DWORD dwLogicalDrives, i;
IRecycleBin *prb;
HRESULT hr;
TRACE("(%p)\n", This);
dwLogicalDrives = GetLogicalDrives();
if (dwLogicalDrives == 0)
return HRESULT_FROM_WIN32(GetLastError());
for (i = 0; i < 26; i++)
{
if (!(dwLogicalDrives & (1 << i)))
continue;
swprintf(szVolumeName, L"%c:\\", 'A' + i);
if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
continue;
hr = GetDefaultRecycleBin(szVolumeName, &prb);
if (!SUCCEEDED(hr))
return hr;
hr = IRecycleBin_EmptyRecycleBin(prb);
IRecycleBin_Release(prb);
}
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBinGeneric_RecycleBin_EnumObjects(
IN IRecycleBin *This,
OUT IRecycleBinEnumList **ppEnumList)
{
TRACE("(%p, %p)\n", This, ppEnumList);
return RecycleBinGenericEnum_Constructor(ppEnumList);
}
CONST_VTBL struct IRecycleBinVtbl RecycleBinGenericVtbl =
{
RecycleBinGeneric_RecycleBin_QueryInterface,
RecycleBinGeneric_RecycleBin_AddRef,
RecycleBinGeneric_RecycleBin_Release,
RecycleBinGeneric_RecycleBin_DeleteFile,
RecycleBinGeneric_RecycleBin_EmptyRecycleBin,
RecycleBinGeneric_RecycleBin_EnumObjects,
};
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown)
{
/* This RecycleBin implementation was introduced to be able to manage all
* drives at once, and instanciate the 'real' implementations when needed */
struct RecycleBinGeneric *s;
s = CoTaskMemAlloc(sizeof(struct RecycleBinGeneric));
if (!s)
return E_OUTOFMEMORY;
s->ref = 1;
s->recycleBinImpl.lpVtbl = &RecycleBinGenericVtbl;
*ppUnknown = (IUnknown *)&s->recycleBinImpl;
return S_OK;
}
@@ -0,0 +1,177 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Deals with a system-wide recycle bin
* COPYRIGHT: Copyright 2007 Hervé Poussineau ([email protected])
* Copyright 2024 Katayama Hirofumi MZ ([email protected])
*/
#include "recyclebin_private.h"
class RecycleBinGeneric : public IRecycleBin
{
public:
RecycleBinGeneric();
virtual ~RecycleBinGeneric();
/* IUnknown methods */
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
/* IRecycleBin methods */
STDMETHODIMP DeleteFile(LPCWSTR szFileName) override;
STDMETHODIMP EmptyRecycleBin() override;
STDMETHODIMP EnumObjects(IRecycleBinEnumList **ppEnumList) override;
protected:
LONG m_ref;
};
STDMETHODIMP RecycleBinGeneric::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_IRecycleBin))
*ppvObject = static_cast<IRecycleBin *>(this);
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) RecycleBinGeneric::AddRef()
{
ULONG refCount = InterlockedIncrement(&m_ref);
TRACE("(%p)\n", this);
return refCount;
}
RecycleBinGeneric::~RecycleBinGeneric()
{
TRACE("(%p)\n", this);
}
STDMETHODIMP_(ULONG) RecycleBinGeneric::Release()
{
TRACE("(%p)\n", this);
ULONG refCount = InterlockedDecrement(&m_ref);
if (refCount == 0)
delete this;
return refCount;
}
STDMETHODIMP RecycleBinGeneric::DeleteFile(LPCWSTR szFileName)
{
TRACE("(%p, %s)\n", this, debugstr_w(szFileName));
/* Get full file name */
LPWSTR szFullName = NULL;
DWORD dwBufferLength = 0;
while (TRUE)
{
DWORD len = GetFullPathNameW(szFileName, dwBufferLength, szFullName, NULL);
if (len == 0)
{
if (szFullName)
CoTaskMemFree(szFullName);
return HRESULT_FROM_WIN32(GetLastError());
}
else if (len < dwBufferLength)
break;
if (szFullName)
CoTaskMemFree(szFullName);
dwBufferLength = len;
szFullName = (LPWSTR)CoTaskMemAlloc(dwBufferLength * sizeof(WCHAR));
if (!szFullName)
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
/* Get associated volume path */
WCHAR szVolume[MAX_PATH];
swprintf(szVolume, L"%c:\\", szFullName[0]);
/* Skip namespace (if any): "\\.\" or "\\?\" */
if (szVolume[0] == '\\' &&
szVolume[1] == '\\' &&
(szVolume[2] == '.' || szVolume[2] == '?') &&
szVolume[3] == '\\')
{
MoveMemory(szVolume, &szVolume[4], (_countof(szVolume) - 4) * sizeof(WCHAR));
}
IRecycleBin *prb;
HRESULT hr = GetDefaultRecycleBin(szVolume, &prb);
if (!SUCCEEDED(hr))
{
CoTaskMemFree(szFullName);
return hr;
}
hr = prb->DeleteFile(szFullName);
CoTaskMemFree(szFullName);
prb->Release();
return hr;
}
STDMETHODIMP RecycleBinGeneric::EmptyRecycleBin()
{
TRACE("(%p)\n", this);
DWORD dwLogicalDrives = GetLogicalDrives();
if (dwLogicalDrives == 0)
return HRESULT_FROM_WIN32(GetLastError());
for (DWORD i = 0; i < L'Z' - L'A' + 1; i++)
{
if (!(dwLogicalDrives & (1 << i)))
continue;
WCHAR szVolumeName[MAX_PATH];
swprintf(szVolumeName, L"%c:\\", L'A' + i);
if (GetDriveTypeW(szVolumeName) != DRIVE_FIXED)
continue;
IRecycleBin *prb;
HRESULT hr = GetDefaultRecycleBin(szVolumeName, &prb);
if (!SUCCEEDED(hr))
return hr;
hr = prb->EmptyRecycleBin();
prb->Release();
}
return S_OK;
}
STDMETHODIMP RecycleBinGeneric::EnumObjects(IRecycleBinEnumList **ppEnumList)
{
TRACE("(%p, %p)\n", this, ppEnumList);
return RecycleBinGenericEnum_Constructor(ppEnumList);
}
RecycleBinGeneric::RecycleBinGeneric()
: m_ref(1)
{
}
EXTERN_C
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown)
{
/* This RecycleBin implementation was introduced to be able to manage all
* drives at once, and instanciate the 'real' implementations when needed */
RecycleBinGeneric *pThis = new RecycleBinGeneric();
if (!pThis)
return E_OUTOFMEMORY;
*ppUnknown = static_cast<IRecycleBin *>(pThis);
return S_OK;
}
@@ -40,6 +40,7 @@ typedef struct _INFO2_HEADER
/* recyclebin_generic.c */
EXTERN_C
HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown);
/* recyclebin_generic_enumerator.c */