https://git.reactos.org/?p=reactos.git;a=commitdiff;h=22b913928f4a1d13120b0ec7a1c6889d37ec0e3a

commit 22b913928f4a1d13120b0ec7a1c6889d37ec0e3a
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Mon Jul 29 08:14:02 2024 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Mon Jul 29 08:14:02 2024 +0900

    [SHELL32] RecycleBin5Enum: Make it C++ (#7173)
    
    Modernize code.
    JIRA issue: CORE-19595
    Rewrite RecycleBin5Enum in C++.
---
 dll/win32/shell32/shellrecyclebin/CMakeLists.txt   |   3 +-
 dll/win32/shell32/shellrecyclebin/recyclebin_v5.h  |  11 +-
 .../shellrecyclebin/recyclebin_v5_enumerator.c     | 534 ---------------------
 .../shellrecyclebin/recyclebin_v5_enumerator.cpp   | 492 +++++++++++++++++++
 4 files changed, 500 insertions(+), 540 deletions(-)

diff --git a/dll/win32/shell32/shellrecyclebin/CMakeLists.txt 
b/dll/win32/shell32/shellrecyclebin/CMakeLists.txt
index 5ff948c8a95..ef5bf3da1c8 100644
--- a/dll/win32/shell32/shellrecyclebin/CMakeLists.txt
+++ b/dll/win32/shell32/shellrecyclebin/CMakeLists.txt
@@ -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)
diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_v5.h 
b/dll/win32/shell32/shellrecyclebin/recyclebin_v5.h
index 52681b584f9..f33b3adbe54 100644
--- a/dll/win32/shell32/shellrecyclebin/recyclebin_v5.h
+++ b/dll/win32/shell32/shellrecyclebin/recyclebin_v5.h
@@ -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
 }
diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.c 
b/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.c
deleted file mode 100644
index 411c623b3a2..00000000000
--- a/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.c
+++ /dev/null
@@ -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 (hpous...@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;
-}
diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp 
b/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp
new file mode 100644
index 00000000000..1f7855415d8
--- /dev/null
+++ b/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp
@@ -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 (hpous...@reactos.org)
+ *              Copyright 2024 Katayama Hirofumi MZ 
(katayama.hirofumi...@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;
+}

Reply via email to