https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bc8c7d185d059677c9fe1c112584e00181807d55
commit bc8c7d185d059677c9fe1c112584e00181807d55 Author: Whindmar Saksit <whinds...@proton.me> AuthorDate: Sun Sep 8 22:08:15 2024 +0200 Commit: GitHub <nore...@github.com> CommitDate: Sun Sep 8 22:08:15 2024 +0200 [SHELL32] Fix CRecycleBin crash caused by PR #7173 (#7330) PR #7173 (22b913928f4a1d13120b0ec7a1c6889d37ec0e3a) fails to initialize the DELETED_FILE_RECORD struct when constructing a RecycleBin5File instance. This causes _ILCreateRecycleItem to create PIDLs without filenames and the CRecycleBin IShellFolder does not expect this to happen. Also fixes incorrect usage of SHFileOperationW when restoring deleted files. The previous code might have worked by chance in the past if the string just happened to be double-null terminated as required by this API! --- .../shell32/shellrecyclebin/recyclebin_v5.cpp | 45 ++++++++++++++++++---- .../shellrecyclebin/recyclebin_v5_enumerator.cpp | 1 + 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_v5.cpp b/dll/win32/shell32/shellrecyclebin/recyclebin_v5.cpp index a98e56861bb..c7009f94d9d 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin_v5.cpp +++ b/dll/win32/shell32/shellrecyclebin/recyclebin_v5.cpp @@ -11,6 +11,40 @@ #include <shlwapi.h> #include "sddl.h" +EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void); + +class CZZWStr +{ + LPWSTR m_sz; + +public: + ~CZZWStr() { SHFree(m_sz); } + CZZWStr() : m_sz(NULL) {} + CZZWStr(const CZZWStr&) = delete; + CZZWStr& operator=(const CZZWStr&) = delete; + + bool Initialize(LPCWSTR Str) + { + SIZE_T cch = wcslen(Str) + 1; + m_sz = (LPWSTR)SHAlloc((cch + 1) * sizeof(*Str)); + if (!m_sz) + return false; + CopyMemory(m_sz, Str, cch * sizeof(*Str)); + m_sz[cch] = UNICODE_NULL; // Double-null terminate + return true; + } + inline LPWSTR c_str() { return m_sz; } +}; + +static int SHELL_SingleFileOperation(HWND hWnd, UINT Op, LPCWSTR pszFrom, LPCWSTR pszTo, FILEOP_FLAGS Flags) +{ + CZZWStr szzFrom, szzTo; + if (!szzFrom.Initialize(pszFrom) || !szzTo.Initialize(pszTo)) + return ERROR_OUTOFMEMORY; // Note: Not one of the DE errors but also not in the DE range + SHFILEOPSTRUCTW fos = { hWnd, Op, szzFrom.c_str(), szzTo.c_str(), Flags }; + return SHFileOperationW(&fos); +} + static BOOL IntDeleteRecursive( IN LPCWSTR FullName) @@ -465,7 +499,6 @@ STDMETHODIMP RecycleBin5::Restore( PINFO2_HEADER pHeader; DELETED_FILE_RECORD *pRecord, *pLast; DWORD dwEntries, i; - SHFILEOPSTRUCTW op; int res; TRACE("(%p, %s, %p)\n", this, debugstr_w(pDeletedFileName), pDeletedFile); @@ -490,13 +523,7 @@ STDMETHODIMP RecycleBin5::Restore( { if (pRecord->dwRecordUniqueId == pDeletedFile->dwRecordUniqueId) { - /* Restore file */ - ZeroMemory(&op, sizeof(op)); - op.wFunc = FO_MOVE; - op.pFrom = pDeletedFileName; - op.pTo = pDeletedFile->FileNameW; - - res = SHFileOperationW(&op); + res = SHELL_SingleFileOperation(NULL, FO_MOVE, pDeletedFileName, pDeletedFile->FileNameW, 0); if (res) { ERR("SHFileOperationW failed with 0x%x\n", res); @@ -517,6 +544,8 @@ STDMETHODIMP RecycleBin5::Restore( m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); if (!m_hInfoMapped) return HRESULT_FROM_WIN32(GetLastError()); + if (dwEntries == 1) + SHUpdateRecycleBinIcon(); // Full --> Empty return S_OK; } pRecord++; diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp b/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp index 1f7855415d8..ff2593fe84d 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp +++ b/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp @@ -257,6 +257,7 @@ RecycleBin5File::Init( { m_recycleBin = prb; m_recycleBin->AddRef(); + m_deletedFile = *pDeletedFile; WCHAR szUniqueId[32]; StringCchPrintfW(szUniqueId, _countof(szUniqueId), L"%lu", pDeletedFile->dwRecordUniqueId);