https://git.reactos.org/?p=reactos.git;a=commitdiff;h=22b913928f4a1d13120b0…
commit 22b913928f4a1d13120b0ec7a1c6889d37ec0e3a
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Mon Jul 29 08:14:02 2024 +0900
Commit: GitHub <noreply(a)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 (hpoussin(a)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 (hpoussin(a)reactos.org)
+ * Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)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;
+}