[SHELL32] RecycleBin5Enum: Make it C++ (#7173)

Modernize code.
JIRA issue: CORE-19595
Rewrite RecycleBin5Enum in C++.
This commit is contained in:
Katayama Hirofumi MZ 2024-07-29 08:14:02 +09:00 committed by GitHub
parent ec24b54731
commit 22b913928f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 500 additions and 540 deletions

View file

@ -9,9 +9,10 @@ list(APPEND SOURCE
recyclebin_generic.cpp
recyclebin_generic_enumerator.cpp
recyclebin_v5.c
recyclebin_v5_enumerator.c
recyclebin_v5_enumerator.cpp
recyclebin_private.h)
add_library(recyclebin ${SOURCE} guid.c)
add_pch(recyclebin recyclebin_private.h SOURCE)
add_dependencies(recyclebin psdk)
target_link_libraries(recyclebin PRIVATE atl_classes)

View file

@ -80,13 +80,14 @@ DECLARE_INTERFACE_(IRecycleBin5, IUnknown)
(This)->lpVtbl->OnClosing(This, prb5el)
#endif
EXTERN_C
HRESULT
RecycleBin5Enum_Constructor(
IN IRecycleBin5 *prb,
IN HANDLE hInfo,
IN HANDLE hInfoMapped,
IN LPCWSTR szPrefix,
OUT IUnknown **ppUnknown);
_In_ IRecycleBin5 *prb,
_In_ HANDLE hInfo,
_In_ HANDLE hInfoMapped,
_In_ LPCWSTR szPrefix,
_Out_ IUnknown **ppUnknown);
#ifdef __cplusplus
}

View file

@ -1,534 +0,0 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL v2 - See COPYING in the top level directory
* FILE: lib/recyclebin/recyclebin_v5_enumerator.c
* PURPOSE: Enumerates contents of a MS Windows 2000/XP/2003 recyclebin
* PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
*/
#include "recyclebin_private.h"
struct RecycleBin5File
{
ULONG ref;
IRecycleBin5 *recycleBin;
DELETED_FILE_RECORD deletedFile;
IRecycleBinFile recycleBinFileImpl;
WCHAR FullName[ANY_SIZE];
};
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetAttributes(
IN IRecycleBinFile *This,
OUT DWORD *pAttributes);
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_QueryInterface(
IN IRecycleBinFile *This,
IN REFIID riid,
OUT void **ppvObject)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
if (!ppvObject)
return E_POINTER;
if (IsEqualIID(riid, &IID_IUnknown))
*ppvObject = &s->recycleBinFileImpl;
else if (IsEqualIID(riid, &IID_IRecycleBinFile))
*ppvObject = &s->recycleBinFileImpl;
else if (IsEqualIID(riid, &IID_IExtractIconA) || IsEqualIID(riid, &IID_IExtractIconW))
{
DWORD dwAttributes;
if (RecycleBin5File_RecycleBinFile_GetAttributes(This, &dwAttributes) == S_OK)
return SHCreateFileExtractIconW(s->FullName, dwAttributes, riid, ppvObject);
else
return S_FALSE;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
IUnknown_AddRef(This);
return S_OK;
}
static ULONG STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_AddRef(
IN IRecycleBinFile *This)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
TRACE("(%p)\n", This);
return refCount;
}
static VOID
RecycleBin5File_Destructor(
struct RecycleBin5File *s)
{
TRACE("(%p)\n", s);
IRecycleBin5_Release(s->recycleBin);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_Release(
IN IRecycleBinFile *This)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
ULONG refCount;
TRACE("(%p)\n", This);
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
RecycleBin5File_Destructor(s);
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetLastModificationTime(
IN IRecycleBinFile *This,
OUT FILETIME *pLastModificationTime)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
HRESULT hr;
DWORD dwAttributes;
HANDLE hFile;
TRACE("(%p, %p)\n", This, pLastModificationTime);
dwAttributes = GetFileAttributesW(s->FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
else
hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
if (GetFileTime(hFile, NULL, NULL, pLastModificationTime))
hr = S_OK;
else
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hFile);
return hr;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetDeletionTime(
IN IRecycleBinFile *This,
OUT FILETIME *pDeletionTime)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
TRACE("(%p, %p)\n", This, pDeletionTime);
*pDeletionTime = s->deletedFile.DeletionTime;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetFileSize(
IN IRecycleBinFile *This,
OUT ULARGE_INTEGER *pFileSize)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
HRESULT hr;
DWORD dwAttributes;
HANDLE hFile;
TRACE("(%p, %p)\n", This, pFileSize);
dwAttributes = GetFileAttributesW(s->FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
pFileSize->QuadPart = 0;
return S_OK;
}
hFile = CreateFileW(s->FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
pFileSize->u.LowPart = GetFileSize(hFile, &pFileSize->u.HighPart);
if (pFileSize->u.LowPart != INVALID_FILE_SIZE)
hr = S_OK;
else
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hFile);
return hr;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetPhysicalFileSize(
IN IRecycleBinFile *This,
OUT ULARGE_INTEGER *pPhysicalFileSize)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
TRACE("(%p, %p)\n", This, pPhysicalFileSize);
pPhysicalFileSize->u.HighPart = 0;
pPhysicalFileSize->u.LowPart = s->deletedFile.dwPhysicalFileSize;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetAttributes(
IN IRecycleBinFile *This,
OUT DWORD *pAttributes)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
DWORD dwAttributes;
TRACE("(%p, %p)\n", This, pAttributes);
dwAttributes = GetFileAttributesW(s->FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
*pAttributes = dwAttributes;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetFileName(
IN IRecycleBinFile *This,
IN SIZE_T BufferSize,
IN OUT LPWSTR Buffer,
OUT SIZE_T *RequiredSize)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
DWORD dwRequired;
TRACE("(%p, %u, %p, %p)\n", This, BufferSize, Buffer, RequiredSize);
dwRequired = (DWORD)(wcslen(s->deletedFile.FileNameW) + 1) * sizeof(WCHAR);
if (RequiredSize)
*RequiredSize = dwRequired;
if (BufferSize == 0 && !Buffer)
return S_OK;
if (BufferSize < dwRequired)
return E_OUTOFMEMORY;
CopyMemory(Buffer, s->deletedFile.FileNameW, dwRequired);
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_GetTypeName(
IN IRecycleBinFile *This,
IN SIZE_T BufferSize,
IN OUT LPWSTR Buffer,
OUT SIZE_T *RequiredSize)
{
HRESULT hr;
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
DWORD dwRequired;
DWORD dwAttributes;
SHFILEINFOW shFileInfo;
TRACE("(%p, %u, %p, %p)\n", This, BufferSize, Buffer, RequiredSize);
hr = RecycleBin5File_RecycleBinFile_GetAttributes(This, &dwAttributes);
if (!SUCCEEDED(hr))
return hr;
hr = SHGetFileInfoW(s->FullName, dwAttributes, &shFileInfo, sizeof(shFileInfo), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
if (!SUCCEEDED(hr))
return hr;
dwRequired = (DWORD)(wcslen(shFileInfo.szTypeName) + 1) * sizeof(WCHAR);
if (RequiredSize)
*RequiredSize = dwRequired;
if (BufferSize == 0 && !Buffer)
return S_OK;
if (BufferSize < dwRequired)
return E_OUTOFMEMORY;
CopyMemory(Buffer, shFileInfo.szTypeName, dwRequired);
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_Delete(
IN IRecycleBinFile *This)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
TRACE("(%p)\n", This);
return IRecycleBin5_Delete(s->recycleBin, s->FullName, &s->deletedFile);
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5File_RecycleBinFile_Restore(
IN IRecycleBinFile *This)
{
struct RecycleBin5File *s = CONTAINING_RECORD(This, struct RecycleBin5File, recycleBinFileImpl);
TRACE("(%p)\n", This);
return IRecycleBin5_Restore(s->recycleBin, s->FullName, &s->deletedFile);
}
CONST_VTBL struct IRecycleBinFileVtbl RecycleBin5FileVtbl =
{
RecycleBin5File_RecycleBinFile_QueryInterface,
RecycleBin5File_RecycleBinFile_AddRef,
RecycleBin5File_RecycleBinFile_Release,
RecycleBin5File_RecycleBinFile_GetLastModificationTime,
RecycleBin5File_RecycleBinFile_GetDeletionTime,
RecycleBin5File_RecycleBinFile_GetFileSize,
RecycleBin5File_RecycleBinFile_GetPhysicalFileSize,
RecycleBin5File_RecycleBinFile_GetAttributes,
RecycleBin5File_RecycleBinFile_GetFileName,
RecycleBin5File_RecycleBinFile_GetTypeName,
RecycleBin5File_RecycleBinFile_Delete,
RecycleBin5File_RecycleBinFile_Restore,
};
static HRESULT
RecycleBin5File_Constructor(
IN IRecycleBin5 *prb,
IN LPCWSTR Folder,
IN PDELETED_FILE_RECORD pDeletedFile,
OUT IRecycleBinFile **ppFile)
{
struct RecycleBin5File *s = NULL;
LPCWSTR Extension;
SIZE_T Needed;
if (!ppFile)
return E_POINTER;
Extension = wcsrchr(pDeletedFile->FileNameW, '.');
if (Extension < wcsrchr(pDeletedFile->FileNameW, '\\'))
Extension = NULL;
Needed = wcslen(Folder) + 13;
if (Extension)
Needed += wcslen(Extension);
Needed *= sizeof(WCHAR);
s = CoTaskMemAlloc(sizeof(struct RecycleBin5File) + Needed);
if (!s)
return E_OUTOFMEMORY;
ZeroMemory(s, sizeof(struct RecycleBin5File) + Needed);
s->recycleBinFileImpl.lpVtbl = &RecycleBin5FileVtbl;
s->ref = 1;
s->deletedFile = *pDeletedFile;
s->recycleBin = prb;
IRecycleBin5_AddRef(s->recycleBin);
*ppFile = &s->recycleBinFileImpl;
wsprintfW(s->FullName, L"%s\\D%c%lu%s", Folder, pDeletedFile->dwDriveNumber + 'a', pDeletedFile->dwRecordUniqueId, Extension);
if (GetFileAttributesW(s->FullName) == INVALID_FILE_ATTRIBUTES)
{
RecycleBin5File_Destructor(s);
return E_FAIL;
}
return S_OK;
}
struct RecycleBin5Enum
{
ULONG ref;
IRecycleBin5 *recycleBin;
HANDLE hInfo;
INFO2_HEADER *pInfo;
DWORD dwCurrent;
IRecycleBinEnumList recycleBinEnumImpl;
WCHAR szPrefix[ANY_SIZE];
};
static HRESULT STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_QueryInterface(
IN IRecycleBinEnumList *This,
IN REFIID riid,
OUT void **ppvObject)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, 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
RecycleBin5Enum_RecycleBinEnumList_AddRef(
IN IRecycleBinEnumList *This)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
ULONG refCount = InterlockedIncrement((PLONG)&s->ref);
TRACE("(%p)\n", This);
return refCount;
}
static VOID
RecycleBin5Enum_Destructor(
struct RecycleBin5Enum *s)
{
TRACE("(%p)\n", s);
IRecycleBin5_OnClosing(s->recycleBin, &s->recycleBinEnumImpl);
UnmapViewOfFile(s->pInfo);
IRecycleBin5_Release(s->recycleBin);
CoTaskMemFree(s);
}
static ULONG STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Release(
IN IRecycleBinEnumList *This)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
ULONG refCount;
TRACE("(%p)\n", This);
refCount = InterlockedDecrement((PLONG)&s->ref);
if (refCount == 0)
RecycleBin5Enum_Destructor(s);
return refCount;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Next(
IRecycleBinEnumList *This,
IN DWORD celt,
IN OUT IRecycleBinFile **rgelt,
OUT DWORD *pceltFetched)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
ULARGE_INTEGER FileSize;
INFO2_HEADER *pHeader = s->pInfo;
DELETED_FILE_RECORD *pDeletedFile;
DWORD fetched = 0, i;
DWORD dwEntries;
HRESULT hr;
TRACE("(%p, %u, %p, %p)\n", This, celt, rgelt, pceltFetched);
if (!rgelt)
return E_POINTER;
if (!pceltFetched && celt > 1)
return E_INVALIDARG;
FileSize.u.LowPart = GetFileSize(s->hInfo, &FileSize.u.HighPart);
if (FileSize.u.LowPart == 0)
return HRESULT_FROM_WIN32(GetLastError());
dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
i = s->dwCurrent;
pDeletedFile = (DELETED_FILE_RECORD *)(pHeader + 1) + i;
for (; i < dwEntries && fetched < celt; i++)
{
hr = RecycleBin5File_Constructor(s->recycleBin, s->szPrefix, pDeletedFile, &rgelt[fetched]);
if (SUCCEEDED(hr))
fetched++;
pDeletedFile++;
}
s->dwCurrent = i;
if (pceltFetched)
*pceltFetched = fetched;
if (fetched == celt)
return S_OK;
else
return S_FALSE;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Skip(
IN IRecycleBinEnumList *This,
IN DWORD celt)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
TRACE("(%p, %u)\n", This, celt);
s->dwCurrent += celt;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
RecycleBin5Enum_RecycleBinEnumList_Reset(
IN IRecycleBinEnumList *This)
{
struct RecycleBin5Enum *s = CONTAINING_RECORD(This, struct RecycleBin5Enum, recycleBinEnumImpl);
TRACE("(%p)\n", This);
s->dwCurrent = 0;
return S_OK;
}
CONST_VTBL struct IRecycleBinEnumListVtbl RecycleBin5EnumVtbl =
{
RecycleBin5Enum_RecycleBinEnumList_QueryInterface,
RecycleBin5Enum_RecycleBinEnumList_AddRef,
RecycleBin5Enum_RecycleBinEnumList_Release,
RecycleBin5Enum_RecycleBinEnumList_Next,
RecycleBin5Enum_RecycleBinEnumList_Skip,
RecycleBin5Enum_RecycleBinEnumList_Reset,
};
HRESULT
RecycleBin5Enum_Constructor(
IN IRecycleBin5 *prb,
IN HANDLE hInfo,
IN HANDLE hInfoMapped,
IN LPCWSTR szPrefix,
OUT IUnknown **ppUnknown)
{
struct RecycleBin5Enum *s = NULL;
SIZE_T Needed;
if (!ppUnknown)
return E_POINTER;
Needed = (wcslen(szPrefix) + 1) * sizeof(WCHAR);
s = CoTaskMemAlloc(sizeof(struct RecycleBin5Enum) + Needed);
if (!s)
return E_OUTOFMEMORY;
ZeroMemory(s, sizeof(struct RecycleBin5Enum) + Needed);
s->recycleBinEnumImpl.lpVtbl = &RecycleBin5EnumVtbl;
s->ref = 1;
s->recycleBin = prb;
wcscpy(s->szPrefix, szPrefix);
s->hInfo = hInfo;
s->pInfo = MapViewOfFile(hInfoMapped, FILE_MAP_READ, 0, 0, 0);
if (!s->pInfo)
{
CoTaskMemFree(s);
return HRESULT_FROM_WIN32(GetLastError());
}
if (s->pInfo->dwVersion != 5 || s->pInfo->dwRecordSize != sizeof(DELETED_FILE_RECORD))
{
UnmapViewOfFile(s->pInfo);
CoTaskMemFree(s);
return E_FAIL;
}
IRecycleBin5_AddRef(s->recycleBin);
*ppUnknown = (IUnknown *)&s->recycleBinEnumImpl;
return S_OK;
}

View file

@ -0,0 +1,492 @@
/*
* PROJECT: Recycle bin management
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Enumerates contents of a MS Windows 2000/XP/2003 recyclebin
* COPYRIGHT: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org)
* Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
*/
#include "recyclebin_private.h"
#include <atlstr.h>
#include <shlwapi.h>
#include <strsafe.h>
class RecycleBin5File : public IRecycleBinFile
{
public:
RecycleBin5File();
virtual ~RecycleBin5File();
HRESULT Init(
_In_ IRecycleBin5 *prb,
_In_ LPCWSTR Folder,
_In_ PDELETED_FILE_RECORD pDeletedFile);
/* IUnknown methods */
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
/* IRecycleBinFile methods */
STDMETHODIMP GetLastModificationTime(FILETIME *pLastModificationTime) override;
STDMETHODIMP GetDeletionTime(FILETIME *pDeletionTime) override;
STDMETHODIMP GetFileSize(ULARGE_INTEGER *pFileSize) override;
STDMETHODIMP GetPhysicalFileSize(ULARGE_INTEGER *pPhysicalFileSize) override;
STDMETHODIMP GetAttributes(DWORD *pAttributes) override;
STDMETHODIMP GetFileName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) override;
STDMETHODIMP GetTypeName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) override;
STDMETHODIMP Delete() override;
STDMETHODIMP Restore() override;
protected:
LONG m_ref;
IRecycleBin5 *m_recycleBin;
DELETED_FILE_RECORD m_deletedFile;
LPWSTR m_FullName;
};
STDMETHODIMP RecycleBin5File::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_IRecycleBinFile))
*ppvObject = static_cast<IRecycleBinFile *>(this);
else if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW))
{
DWORD dwAttributes;
if (GetAttributes(&dwAttributes) == S_OK)
return SHCreateFileExtractIconW(m_FullName, dwAttributes, riid, ppvObject);
else
return S_FALSE;
}
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) RecycleBin5File::AddRef()
{
TRACE("(%p)\n", this);
return InterlockedIncrement(&m_ref);
}
RecycleBin5File::~RecycleBin5File()
{
TRACE("(%p)\n", this);
m_recycleBin->Release();
SHFree(m_FullName);
}
STDMETHODIMP_(ULONG) RecycleBin5File::Release()
{
TRACE("(%p)\n", this);
ULONG refCount = InterlockedDecrement(&m_ref);
if (refCount == 0)
delete this;
return refCount;
}
STDMETHODIMP RecycleBin5File::GetLastModificationTime(FILETIME *pLastModificationTime)
{
TRACE("(%p, %p)\n", this, pLastModificationTime);
DWORD dwAttributes = ::GetFileAttributesW(m_FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
HANDLE hFile;
hFile = CreateFileW(m_FullName,
GENERIC_READ,
FILE_SHARE_READ |
((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (FILE_SHARE_WRITE | FILE_SHARE_DELETE) : 0),
NULL,
OPEN_EXISTING,
(dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS : 0,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
HRESULT hr;
if (GetFileTime(hFile, NULL, NULL, pLastModificationTime))
hr = S_OK;
else
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hFile);
return hr;
}
STDMETHODIMP RecycleBin5File::GetDeletionTime(FILETIME *pDeletionTime)
{
TRACE("(%p, %p)\n", this, pDeletionTime);
*pDeletionTime = m_deletedFile.DeletionTime;
return S_OK;
}
STDMETHODIMP RecycleBin5File::GetFileSize(ULARGE_INTEGER *pFileSize)
{
TRACE("(%p, %p)\n", this, pFileSize);
DWORD dwAttributes = GetFileAttributesW(m_FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
pFileSize->QuadPart = 0;
return S_OK;
}
HANDLE hFile = CreateFileW(m_FullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return HRESULT_FROM_WIN32(GetLastError());
pFileSize->u.LowPart = ::GetFileSize(hFile, &pFileSize->u.HighPart);
HRESULT hr;
if (pFileSize->u.LowPart != INVALID_FILE_SIZE)
hr = S_OK;
else
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hFile);
return hr;
}
STDMETHODIMP RecycleBin5File::GetPhysicalFileSize(ULARGE_INTEGER *pPhysicalFileSize)
{
TRACE("(%p, %p)\n", this, pPhysicalFileSize);
pPhysicalFileSize->u.HighPart = 0;
pPhysicalFileSize->u.LowPart = m_deletedFile.dwPhysicalFileSize;
return S_OK;
}
STDMETHODIMP RecycleBin5File::GetAttributes(DWORD *pAttributes)
{
DWORD dwAttributes;
TRACE("(%p, %p)\n", this, pAttributes);
dwAttributes = GetFileAttributesW(m_FullName);
if (dwAttributes == INVALID_FILE_ATTRIBUTES)
return HRESULT_FROM_WIN32(GetLastError());
*pAttributes = dwAttributes;
return S_OK;
}
STDMETHODIMP RecycleBin5File::GetFileName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize)
{
DWORD dwRequired;
TRACE("(%p, %u, %p, %p)\n", this, BufferSize, Buffer, RequiredSize);
dwRequired = (DWORD)(wcslen(m_deletedFile.FileNameW) + 1) * sizeof(WCHAR);
if (RequiredSize)
*RequiredSize = dwRequired;
if (BufferSize == 0 && !Buffer)
return S_OK;
if (BufferSize < dwRequired)
return E_OUTOFMEMORY;
CopyMemory(Buffer, m_deletedFile.FileNameW, dwRequired);
return S_OK;
}
STDMETHODIMP RecycleBin5File::GetTypeName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize)
{
HRESULT hr;
DWORD dwRequired;
DWORD dwAttributes;
SHFILEINFOW shFileInfo;
TRACE("(%p, %u, %p, %p)\n", this, BufferSize, Buffer, RequiredSize);
hr = GetAttributes(&dwAttributes);
if (!SUCCEEDED(hr))
return hr;
hr = SHGetFileInfoW(m_FullName, dwAttributes, &shFileInfo, sizeof(shFileInfo), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
if (!SUCCEEDED(hr))
return hr;
dwRequired = (DWORD)(wcslen(shFileInfo.szTypeName) + 1) * sizeof(WCHAR);
if (RequiredSize)
*RequiredSize = dwRequired;
if (BufferSize == 0 && !Buffer)
return S_OK;
if (BufferSize < dwRequired)
return E_OUTOFMEMORY;
CopyMemory(Buffer, shFileInfo.szTypeName, dwRequired);
return S_OK;
}
STDMETHODIMP RecycleBin5File::Delete()
{
TRACE("(%p)\n", this);
return m_recycleBin->Delete(m_FullName, &m_deletedFile);
}
STDMETHODIMP RecycleBin5File::Restore()
{
TRACE("(%p)\n", this);
return m_recycleBin->Restore(m_FullName, &m_deletedFile);
}
RecycleBin5File::RecycleBin5File()
: m_ref(1)
, m_recycleBin(NULL)
, m_FullName(NULL)
{
ZeroMemory(&m_deletedFile, sizeof(m_deletedFile));
}
HRESULT
RecycleBin5File::Init(
_In_ IRecycleBin5 *prb,
_In_ LPCWSTR Folder,
_In_ PDELETED_FILE_RECORD pDeletedFile)
{
m_recycleBin = prb;
m_recycleBin->AddRef();
WCHAR szUniqueId[32];
StringCchPrintfW(szUniqueId, _countof(szUniqueId), L"%lu", pDeletedFile->dwRecordUniqueId);
CStringW strFullName(Folder);
strFullName += L"\\D";
strFullName += (WCHAR)(L'a' + pDeletedFile->dwDriveNumber);
strFullName += szUniqueId;
strFullName += PathFindExtensionW(pDeletedFile->FileNameW);
if (GetFileAttributesW(strFullName) == INVALID_FILE_ATTRIBUTES)
return E_FAIL;
return SHStrDup(strFullName, &m_FullName);
}
static HRESULT
RecycleBin5File_Constructor(
_In_ IRecycleBin5 *prb,
_In_ LPCWSTR Folder,
_In_ PDELETED_FILE_RECORD pDeletedFile,
_Out_ IRecycleBinFile **ppFile)
{
if (!ppFile)
return E_POINTER;
*ppFile = NULL;
RecycleBin5File *pThis = new RecycleBin5File();
if (!pThis)
return E_OUTOFMEMORY;
HRESULT hr = pThis->Init(prb, Folder, pDeletedFile);
if (FAILED(hr))
{
delete pThis;
return hr;
}
*ppFile = static_cast<IRecycleBinFile *>(pThis);
return S_OK;
}
class RecycleBin5Enum : public IRecycleBinEnumList
{
public:
RecycleBin5Enum();
virtual ~RecycleBin5Enum();
HRESULT Init(
_In_ IRecycleBin5 *prb,
_In_ HANDLE hInfo,
_In_ HANDLE hInfoMapped,
_In_ LPCWSTR pszPrefix);
/* 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;
IRecycleBin5 *m_recycleBin;
HANDLE m_hInfo;
INFO2_HEADER *m_pInfo;
DWORD m_dwCurrent;
LPWSTR m_pszPrefix;
};
STDMETHODIMP RecycleBin5Enum::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) RecycleBin5Enum::AddRef()
{
TRACE("(%p)\n", this);
return InterlockedIncrement(&m_ref);
}
RecycleBin5Enum::~RecycleBin5Enum()
{
TRACE("(%p)\n", this);
m_recycleBin->OnClosing(this);
UnmapViewOfFile(m_pInfo);
m_recycleBin->Release();
SHFree(m_pszPrefix);
}
STDMETHODIMP_(ULONG) RecycleBin5Enum::Release()
{
TRACE("(%p)\n", this);
ULONG refCount = InterlockedDecrement(&m_ref);
if (refCount == 0)
delete this;
return refCount;
}
STDMETHODIMP RecycleBin5Enum::Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *pceltFetched)
{
HRESULT hr;
TRACE("(%p, %u, %p, %p)\n", this, celt, rgelt, pceltFetched);
if (!rgelt)
return E_POINTER;
if (!pceltFetched && celt > 1)
return E_INVALIDARG;
ULARGE_INTEGER FileSize;
FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart);
if (FileSize.u.LowPart == 0)
return HRESULT_FROM_WIN32(GetLastError());
DWORD dwEntries =
(DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD));
DWORD iEntry = m_dwCurrent, fetched = 0;
PDELETED_FILE_RECORD pDeletedFile = (PDELETED_FILE_RECORD)(m_pInfo + 1) + iEntry;
for (; iEntry < dwEntries && fetched < celt; ++iEntry)
{
hr = RecycleBin5File_Constructor(m_recycleBin, m_pszPrefix, pDeletedFile, &rgelt[fetched]);
if (SUCCEEDED(hr))
fetched++;
pDeletedFile++;
}
m_dwCurrent = iEntry;
if (pceltFetched)
*pceltFetched = fetched;
if (fetched == celt)
return S_OK;
else
return S_FALSE;
}
STDMETHODIMP RecycleBin5Enum::Skip(DWORD celt)
{
TRACE("(%p, %u)\n", this, celt);
m_dwCurrent += celt;
return S_OK;
}
STDMETHODIMP RecycleBin5Enum::Reset()
{
TRACE("(%p)\n", this);
m_dwCurrent = 0;
return S_OK;
}
RecycleBin5Enum::RecycleBin5Enum()
: m_ref(1)
, m_recycleBin(NULL)
, m_hInfo(NULL)
, m_pInfo(NULL)
, m_dwCurrent(0)
, m_pszPrefix(NULL)
{
}
HRESULT
RecycleBin5Enum::Init(
_In_ IRecycleBin5 *prb,
_In_ HANDLE hInfo,
_In_ HANDLE hInfoMapped,
_In_ LPCWSTR pszPrefix)
{
m_recycleBin = prb;
m_recycleBin->AddRef();
HRESULT hr = SHStrDup(pszPrefix, &m_pszPrefix);
if (FAILED(hr))
return hr;
m_hInfo = hInfo;
m_pInfo = (PINFO2_HEADER)MapViewOfFile(hInfoMapped, FILE_MAP_READ, 0, 0, 0);
if (!m_pInfo)
return HRESULT_FROM_WIN32(GetLastError());
if (m_pInfo->dwVersion != 5 || m_pInfo->dwRecordSize != sizeof(DELETED_FILE_RECORD))
return E_FAIL;
return S_OK;
}
EXTERN_C
HRESULT
RecycleBin5Enum_Constructor(
_In_ IRecycleBin5 *prb,
_In_ HANDLE hInfo,
_In_ HANDLE hInfoMapped,
_In_ LPCWSTR szPrefix,
_Out_ IUnknown **ppUnknown)
{
if (!ppUnknown)
return E_POINTER;
*ppUnknown = NULL;
RecycleBin5Enum *pThis = new RecycleBin5Enum();
if (!pThis)
return E_OUTOFMEMORY;
HRESULT hr = pThis->Init(prb, hInfo, hInfoMapped, szPrefix);
if (FAILED(hr))
{
delete pThis;
return hr;
}
*ppUnknown = static_cast<IRecycleBinEnumList *>(pThis);
return S_OK;
}