From 22b913928f4a1d13120b0ec7a1c6889d37ec0e3a Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Mon, 29 Jul 2024 08:14:02 +0900 Subject: [PATCH] [SHELL32] RecycleBin5Enum: Make it C++ (#7173) Modernize code. JIRA issue: CORE-19595 Rewrite RecycleBin5Enum in C++. --- .../shell32/shellrecyclebin/CMakeLists.txt | 3 +- .../shell32/shellrecyclebin/recyclebin_v5.h | 11 +- .../recyclebin_v5_enumerator.c | 534 ------------------ .../recyclebin_v5_enumerator.cpp | 492 ++++++++++++++++ 4 files changed, 500 insertions(+), 540 deletions(-) delete mode 100644 dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.c create mode 100644 dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp 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@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@reactos.org) + * Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include "recyclebin_private.h" +#include +#include +#include + +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(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(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(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(pThis); + return S_OK; +}