From f9bedd5ca5b35511bd45b6e59befd86a79006340 Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Wed, 12 Apr 2023 23:27:08 +0200 Subject: [PATCH] [CLEANMGR] Add basic cleanmgr implementation CORE-18941 --- base/applications/CMakeLists.txt | 1 + base/applications/cleanmgr/CMakeLists.txt | 9 + .../cleanmgr/cleanmgr/CCleanupHandler.cpp | 212 +++++++++++++ .../cleanmgr/cleanmgr/CCleanupHandler.hpp | 48 +++ .../cleanmgr/cleanmgr/CCleanupHandlerList.cpp | 163 ++++++++++ .../cleanmgr/cleanmgr/CCleanupHandlerList.hpp | 31 ++ .../cleanmgr/CEmptyVolumeCacheCallBack.hpp | 54 ++++ .../cleanmgr/cleanmgr/CMakeLists.txt | 19 ++ .../cleanmgr/cleanmgr/CProgressDlg.hpp | 50 +++ .../cleanmgr/cleanmgr/CSelectDriveDlg.cpp | 67 ++++ .../cleanmgr/cleanmgr/cleanmgr.cpp | 296 ++++++++++++++++++ .../applications/cleanmgr/cleanmgr/cleanmgr.h | 66 ++++ .../cleanmgr/cleanmgr/cleanmgr.rc | 64 ++++ .../applications/cleanmgr/cleanmgr/resource.h | 30 ++ .../cleanmgr/cleanmgr/resources/cleanmgr.ico | Bin 0 -> 59389 bytes 15 files changed, 1110 insertions(+) create mode 100644 base/applications/cleanmgr/CMakeLists.txt create mode 100644 base/applications/cleanmgr/cleanmgr/CCleanupHandler.cpp create mode 100644 base/applications/cleanmgr/cleanmgr/CCleanupHandler.hpp create mode 100644 base/applications/cleanmgr/cleanmgr/CCleanupHandlerList.cpp create mode 100644 base/applications/cleanmgr/cleanmgr/CCleanupHandlerList.hpp create mode 100644 base/applications/cleanmgr/cleanmgr/CEmptyVolumeCacheCallBack.hpp create mode 100644 base/applications/cleanmgr/cleanmgr/CMakeLists.txt create mode 100644 base/applications/cleanmgr/cleanmgr/CProgressDlg.hpp create mode 100644 base/applications/cleanmgr/cleanmgr/CSelectDriveDlg.cpp create mode 100644 base/applications/cleanmgr/cleanmgr/cleanmgr.cpp create mode 100644 base/applications/cleanmgr/cleanmgr/cleanmgr.h create mode 100644 base/applications/cleanmgr/cleanmgr/cleanmgr.rc create mode 100644 base/applications/cleanmgr/cleanmgr/resource.h create mode 100644 base/applications/cleanmgr/cleanmgr/resources/cleanmgr.ico diff --git a/base/applications/CMakeLists.txt b/base/applications/CMakeLists.txt index dccaaa80438..03679ac33f9 100644 --- a/base/applications/CMakeLists.txt +++ b/base/applications/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(atactl) add_subdirectory(cacls) add_subdirectory(calc) add_subdirectory(charmap) +add_subdirectory(cleanmgr) add_subdirectory(clipbrd) add_subdirectory(cmdutils) add_subdirectory(control) diff --git a/base/applications/cleanmgr/CMakeLists.txt b/base/applications/cleanmgr/CMakeLists.txt new file mode 100644 index 00000000000..e3e3c65f6f9 --- /dev/null +++ b/base/applications/cleanmgr/CMakeLists.txt @@ -0,0 +1,9 @@ + +project(cleanmgr) + +# The main application +add_subdirectory(cleanmgr) + +# Cleanup handlers +#add_subdirectory(dataclen) # Data Driven Cleaner + diff --git a/base/applications/cleanmgr/cleanmgr/CCleanupHandler.cpp b/base/applications/cleanmgr/cleanmgr/CCleanupHandler.cpp new file mode 100644 index 00000000000..f04e1346466 --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/CCleanupHandler.cpp @@ -0,0 +1,212 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CCleanupHandler implementation + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#include "cleanmgr.h" + + +CCleanupHandler::CCleanupHandler(CRegKey &subKey, const CStringW &keyName, const GUID &guid) + : hSubKey(subKey) + , KeyName(keyName) + , Guid(guid) + , dwFlags(0) + , Priority(0) + , StateFlags(0) + , SpaceUsed(0) + , ShowHandler(true) + , hIcon(NULL) +{ +} + +CCleanupHandler::~CCleanupHandler() +{ + Deactivate(); + ::DestroyIcon(hIcon); +} + +void +CCleanupHandler::Deactivate() +{ + if (Handler) + { + DWORD dwFlags = 0; + Handler->Deactivate(&dwFlags); + if (dwFlags & EVCF_REMOVEFROMLIST) + UNIMPLEMENTED_DBGBREAK(); + } +} + +bool +CCleanupHandler::Initialize(LPCWSTR pcwszVolume) +{ + if (FAILED_UNEXPECTEDLY( + ::CoCreateInstance(Guid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IEmptyVolumeCache, &Handler)))) + { + return false; + } + + DWORD dwSize = sizeof(Priority); + if (hSubKey.QueryBinaryValue(L"Priority", &Priority, &dwSize) != ERROR_SUCCESS) + { + if (hSubKey.QueryDWORDValue(L"Priority", Priority) != ERROR_SUCCESS) + Priority = 200; + } + + dwSize = sizeof(StateFlags); + if (hSubKey.QueryDWORDValue(L"StateFlags", StateFlags) != ERROR_SUCCESS) + StateFlags = 0; + + WCHAR PathBuffer[MAX_PATH] = {}; + ULONG nChars = _countof(PathBuffer); + if (hSubKey.QueryStringValue(L"IconPath", PathBuffer, &nChars) != ERROR_SUCCESS) + { + CStringW Tmp; + WCHAR GuidStr[50] = {}; + if (StringFromGUID2(Guid, GuidStr, _countof(GuidStr))) + { + Tmp.Format(L"CLSID\\%s\\DefaultIcon", GuidStr); + CRegKey clsid; + nChars = _countof(PathBuffer); + if (clsid.Open(HKEY_CLASSES_ROOT, Tmp, KEY_READ) != ERROR_SUCCESS || + clsid.QueryStringValue(NULL, PathBuffer, &nChars) != ERROR_SUCCESS) + { + PathBuffer[0] = UNICODE_NULL; + } + } + } + if (!PathBuffer[0]) + StringCchCopyW(PathBuffer, _countof(PathBuffer), L"%systemroot%\\system32\\shell32.dll"); + + int Index = 0; + WCHAR *ptr = wcschr(PathBuffer, L','); + if (ptr) + { + *ptr++ = UNICODE_NULL; + Index = wcstol(ptr, NULL, 10); + } + HICON Large, Small; + UINT Result = ExtractIconExW(PathBuffer, Index, &Large, &Small, 1); + if (Result < 1) + Result = ExtractIconExW(L"%systemroot%\\system32\\shell32.dll", 0, &Large, &Small, 1); + if (Result >= 1) + { + hIcon = Small; + if (!hIcon) + { + hIcon = Large; + } + else + { + ::DestroyIcon(Large); + } + } + + // These options should come from the command line + // dwFlags |= EVCF_SETTINGSMODE; + // dwFlags |= EVCF_OUTOFDISKSPACE; + + CComPtr spHandler2; + HRESULT hr = Handler->QueryInterface(IID_PPV_ARG(IEmptyVolumeCache2, &spHandler2)); + if (SUCCEEDED(hr)) + { + hr = spHandler2->InitializeEx( + hSubKey, pcwszVolume, KeyName, &wszDisplayName, &wszDescription, &wszBtnText, &dwFlags); + if (FAILED_UNEXPECTEDLY(hr)) + return false; + + // No files to clean will return S_FALSE; + if (hr != S_OK) + return false; + } + else + { + // Observed behavior: + // When Initialize is called, wszDescription is actually pointing to data + // wszDescription.AllocateBytes(0x400u); + hr = Handler->Initialize(hSubKey, pcwszVolume, &wszDisplayName, &wszDescription, &dwFlags); + if (FAILED_UNEXPECTEDLY(hr)) + return false; + + // No files to clean will return S_FALSE; + if (hr != S_OK) + return false; + + CComPtr spBag; + WCHAR GuidStr[50] = {}; + nChars = _countof(GuidStr); + if (hSubKey.QueryStringValue(L"PropertyBag", GuidStr, &nChars) == ERROR_SUCCESS) + { + GUID guid = {}; + if (!FAILED_UNEXPECTEDLY(CLSIDFromString(GuidStr, &guid))) + { + FAILED_UNEXPECTEDLY( + CoCreateInstance(guid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPropertyBag, &spBag))); + } + } + ReadProperty(L"Display", spBag, wszDisplayName); + ReadProperty(L"Description", spBag, wszDescription); + + if (dwFlags & EVCF_HASSETTINGS) + { + ReadProperty(L"AdvancedButtonText", spBag, wszBtnText); + } + } + + if ((dwFlags & EVCF_ENABLEBYDEFAULT) && !(StateFlags & HANDLER_STATE_SELECTED)) + { + StateFlags |= HANDLER_STATE_SELECTED; + } + + // For convenience + if (!wszDisplayName) + SHStrDupW(KeyName, &wszDisplayName); + + return true; +} + +void +CCleanupHandler::ReadProperty(LPCWSTR Name, IPropertyBag *pBag, CComHeapPtr &storage) +{ + if (storage) + return; + + if (pBag) + { + CComVariant tmp; + tmp.vt = VT_BSTR; + HRESULT hr = pBag->Read(Name, &tmp, NULL); + if (!FAILED_UNEXPECTEDLY(hr) && tmp.vt == VT_BSTR) + { + SHStrDupW(tmp.bstrVal, &storage); + } + } + + if (!storage) + { + WCHAR TmpStr[0x200] = {}; + DWORD dwSize = _countof(TmpStr); + + if (hSubKey.QueryStringValue(Name, TmpStr, &dwSize) == ERROR_SUCCESS) + { + WCHAR ResolvedStr[0x200] = {}; + SHLoadIndirectString(TmpStr, ResolvedStr, _countof(ResolvedStr), NULL); + SHStrDupW(ResolvedStr, &storage); + } + } +} + +BOOL +CCleanupHandler::HasSettings() const +{ + return !!(dwFlags & EVCF_HASSETTINGS); +} + +BOOL +CCleanupHandler::DontShowIfZero() const +{ + return !!(dwFlags & EVCF_DONTSHOWIFZERO); +} + diff --git a/base/applications/cleanmgr/cleanmgr/CCleanupHandler.hpp b/base/applications/cleanmgr/cleanmgr/CCleanupHandler.hpp new file mode 100644 index 00000000000..3b829a82c21 --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/CCleanupHandler.hpp @@ -0,0 +1,48 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CCleanupHandler definition + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#define HANDLER_STATE_SELECTED 1 + + +struct CCleanupHandler +{ + CCleanupHandler(CRegKey &subKey, const CStringW &keyName, const GUID &guid); + ~CCleanupHandler(); + + void Deactivate(); + + bool + Initialize(LPCWSTR pcwszVolume); + + void + ReadProperty(LPCWSTR Name, IPropertyBag *pBag, CComHeapPtr &storage); + + BOOL + HasSettings() const; + + BOOL + DontShowIfZero() const; + + CRegKey hSubKey; + CStringW KeyName; + GUID Guid; + + CComHeapPtr wszDisplayName; + CComHeapPtr wszDescription; + CComHeapPtr wszBtnText; + + CStringW IconPath; + DWORD dwFlags; + DWORD Priority; + DWORD StateFlags; + + CComPtr Handler; + DWORDLONG SpaceUsed; + bool ShowHandler; + HICON hIcon; +}; + diff --git a/base/applications/cleanmgr/cleanmgr/CCleanupHandlerList.cpp b/base/applications/cleanmgr/cleanmgr/CCleanupHandlerList.cpp new file mode 100644 index 00000000000..73af85d7974 --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/CCleanupHandlerList.cpp @@ -0,0 +1,163 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CCleanupHandlerList implementation + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#include "cleanmgr.h" + +void CCleanupHandlerList::LoadHandlers(WCHAR Drive) +{ + m_DriveStr.Format(L"%c:", Drive); + + CRegKey VolumeCaches; + if (VolumeCaches.Open(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VolumeCaches", KEY_READ) != ERROR_SUCCESS) + return; + + LONG ItemIndex = 0; + WCHAR szKeyName[MAX_PATH]; + + WCHAR wszVolume[] = { Drive, L':', L'\\', UNICODE_NULL }; + + while (TRUE) + { + DWORD dwSize = _countof(szKeyName); + if (VolumeCaches.EnumKey(ItemIndex++, szKeyName, &dwSize) != ERROR_SUCCESS) + { + break; + } + + + CRegKey hSubKey; + if (hSubKey.Open(VolumeCaches, szKeyName, KEY_READ) == ERROR_SUCCESS) + { + WCHAR GuidStr[50] = {}; + dwSize = _countof(GuidStr); + if (hSubKey.QueryStringValue(NULL, GuidStr, &dwSize) != ERROR_SUCCESS) + { + continue; + } + + GUID guid = {}; + if (FAILED_UNEXPECTEDLY(CLSIDFromString(GuidStr, &guid))) + continue; + + CCleanupHandler* handler = new CCleanupHandler(hSubKey, szKeyName, guid); + + if (!handler->Initialize(wszVolume)) + { + delete handler; + continue; + } + + m_Handlers.AddTail(handler); + } + } + + // Sort handlers + BOOL fChanged = m_Handlers.GetCount() > 0; + while (fChanged) + { + fChanged = FALSE; + + for (size_t n = 0; n < m_Handlers.GetCount() - 1; n++) + { + POSITION leftPos = m_Handlers.FindIndex(n); + POSITION rightPos = m_Handlers.FindIndex(n+1); + CCleanupHandler* left = m_Handlers.GetAt(leftPos); + CCleanupHandler* right = m_Handlers.GetAt(rightPos); + + if (right->Priority < left->Priority) + { + m_Handlers.SwapElements(leftPos, rightPos); + fChanged = TRUE; + } + else if (right->Priority == left->Priority) + { + CStringW leftStr(left->wszDisplayName); + if (leftStr.Compare(right->wszDisplayName) > 0) + { + m_Handlers.SwapElements(leftPos, rightPos); + fChanged = TRUE; + } + } + } + } +} + + +DWORDLONG +CCleanupHandlerList::ScanDrive(IEmptyVolumeCacheCallBack *picb) +{ + CProgressDlg progress; + CString Caption; + Caption.Format(IDS_CALCULATING, m_DriveStr.GetString()); + CStringW Title(MAKEINTRESOURCE(IDS_DISK_CLEANUP)); + progress.Start((DWORD)m_Handlers.GetCount(), Title, Caption); + int ItemIndex = 0; + DWORDLONG TotalSpaceUsed = 0; + ForEach( + [&](CCleanupHandler *current) + { + Caption.Format(IDS_SCANNING, current->wszDisplayName.m_pData); + progress.Step(++ItemIndex, Caption); + + HRESULT hr = current->Handler->GetSpaceUsed(¤t->SpaceUsed, picb); + + if (FAILED_UNEXPECTEDLY(hr)) + { + current->ShowHandler = false; + current->StateFlags &= ~HANDLER_STATE_SELECTED; + return; + } + + if (current->SpaceUsed == 0 && current->DontShowIfZero()) + { + current->ShowHandler = false; + current->StateFlags &= ~HANDLER_STATE_SELECTED; + } + TotalSpaceUsed += current->SpaceUsed; + }); + progress.Stop(); + + return TotalSpaceUsed; +} + +void +CCleanupHandlerList::ExecuteCleanup(IEmptyVolumeCacheCallBack *picb) +{ + CProgressDlg progress; + CString Caption; + Caption.Format(IDS_CLEANING_CAPTION, m_DriveStr.GetString()); + + DWORD TotalSelected = 0; + ForEach( + [&](CCleanupHandler *current) + { + if (current->StateFlags & HANDLER_STATE_SELECTED) + TotalSelected++; + }); + + CStringW Title(MAKEINTRESOURCE(IDS_DISK_CLEANUP)); + progress.Start(TotalSelected, Title, Caption); + int ItemIndex = 0; + ForEach( + [&](CCleanupHandler *current) + { + if (!(current->StateFlags & HANDLER_STATE_SELECTED)) + return; + + Caption.Format(IDS_CLEANING, current->wszDisplayName.m_pData); + progress.Step(++ItemIndex, Caption); + + // If there is nothing to clean, we might get STG_E_NOMOREFILES + if (current->SpaceUsed > 0) + { + HRESULT hr = current->Handler->Purge(-1, picb); + if (FAILED_UNEXPECTEDLY(hr)) + return; + } + }); + progress.Stop(); +} diff --git a/base/applications/cleanmgr/cleanmgr/CCleanupHandlerList.hpp b/base/applications/cleanmgr/cleanmgr/CCleanupHandlerList.hpp new file mode 100644 index 00000000000..55e38502c83 --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/CCleanupHandlerList.hpp @@ -0,0 +1,31 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CCleanupHandlerList definition + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + + +class CCleanupHandlerList +{ +private: + CAtlList m_Handlers; + CStringW m_DriveStr; + +public: + + void LoadHandlers(WCHAR Drive); + DWORDLONG ScanDrive(IEmptyVolumeCacheCallBack* picb); + void ExecuteCleanup(IEmptyVolumeCacheCallBack *picb); + + template + void ForEach(Fn callback) + { + for (POSITION it = m_Handlers.GetHeadPosition(); it; m_Handlers.GetNext(it)) + { + CCleanupHandler *current = m_Handlers.GetAt(it); + + callback(current); + } + } +}; diff --git a/base/applications/cleanmgr/cleanmgr/CEmptyVolumeCacheCallBack.hpp b/base/applications/cleanmgr/cleanmgr/CEmptyVolumeCacheCallBack.hpp new file mode 100644 index 00000000000..8811d522dcc --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/CEmptyVolumeCacheCallBack.hpp @@ -0,0 +1,54 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: CEmptyVolumeCacheCallBack definition / implementation + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + + +// We don't really use this, but some windows handlers crash without it +struct CEmptyVolumeCacheCallBack + : public IEmptyVolumeCacheCallBack +{ + + STDMETHOD_(ULONG, AddRef)() throw() + { + return 2; + } + STDMETHOD_(ULONG, Release)() throw() + { + return 1; + } + STDMETHOD(QueryInterface)( + REFIID riid, + _COM_Outptr_ void** ppvObject) throw() + { + if (riid == IID_IUnknown || riid == IID_IEmptyVolumeCacheCallBack) + { + *ppvObject = (IUnknown*)this; + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; + } + + + STDMETHODIMP ScanProgress( + _In_ DWORDLONG dwlSpaceUsed, + _In_ DWORD dwFlags, + _In_ LPCWSTR pcwszStatus) override + { + DPRINT("dwlSpaceUsed: %lld, dwFlags: %x\n", dwlSpaceUsed, dwFlags); + return S_OK; + } + + STDMETHODIMP PurgeProgress( + _In_ DWORDLONG dwlSpaceFreed, + _In_ DWORDLONG dwlSpaceToFree, + _In_ DWORD dwFlags, + _In_ LPCWSTR pcwszStatus) override + { + DPRINT("dwlSpaceFreed: %lld, dwlSpaceToFree: %lld, dwFlags: %x\n", dwlSpaceFreed, dwlSpaceToFree, dwFlags); + return S_OK; + } +}; diff --git a/base/applications/cleanmgr/cleanmgr/CMakeLists.txt b/base/applications/cleanmgr/cleanmgr/CMakeLists.txt new file mode 100644 index 00000000000..f692c04796c --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_executable(cleanmgr + cleanmgr.cpp + cleanmgr.h + cleanmgr.rc + resource.h + CEmptyVolumeCacheCallBack.hpp + CProgressDlg.hpp + CSelectDriveDlg.cpp + CCleanupHandler.cpp + CCleanupHandler.hpp + CCleanupHandlerList.cpp + CCleanupHandlerList.hpp +) +set_module_type(cleanmgr win32gui UNICODE) +target_link_libraries(cleanmgr uuid cpprt atl_classes) +add_importlibs(cleanmgr shlwapi oleaut32 ole32 shell32 comctl32 user32 advapi32 msvcrt kernel32 ntdll) +add_dependencies(cleanmgr psdk) +add_cd_file(TARGET cleanmgr DESTINATION reactos/system32 FOR all) diff --git a/base/applications/cleanmgr/cleanmgr/CProgressDlg.hpp b/base/applications/cleanmgr/cleanmgr/CProgressDlg.hpp new file mode 100644 index 00000000000..66604de01de --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/CProgressDlg.hpp @@ -0,0 +1,50 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Progress dialog implementation + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#pragma once + +class CProgressDlg +{ + CComPtr m_spProgress; + DWORD m_dwTotal = 0; +public: + + ~CProgressDlg() + { + Stop(); + } + + + void Start(DWORD dwTotalSteps, LPCWSTR Title, LPCWSTR Text) + { + HRESULT hr = CoCreateInstance(CLSID_ProgressDialog, NULL, CLSCTX_INPROC, IID_PPV_ARG(IProgressDialog, &m_spProgress)); + if (FAILED_UNEXPECTEDLY(hr)) + return; + + m_dwTotal = dwTotalSteps; + + m_spProgress->SetTitle(Title); + m_spProgress->SetLine(2, Text, TRUE, NULL); + m_spProgress->StartProgressDialog(NULL, NULL, PROGDLG_NOMINIMIZE, NULL); + m_spProgress->SetProgress(0, m_dwTotal); + } + + void Step(DWORD dwProgress, LPCWSTR Text) + { + m_spProgress->SetProgress(dwProgress, m_dwTotal); + m_spProgress->SetLine(1, Text, TRUE, NULL); + } + + void Stop() + { + if (m_spProgress) + { + m_spProgress->StopProgressDialog(); + m_spProgress.Release(); + } + } +}; diff --git a/base/applications/cleanmgr/cleanmgr/CSelectDriveDlg.cpp b/base/applications/cleanmgr/cleanmgr/CSelectDriveDlg.cpp new file mode 100644 index 00000000000..6387bcd87a3 --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/CSelectDriveDlg.cpp @@ -0,0 +1,67 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Drive selection dialog + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#include "cleanmgr.h" + +class CSelectDriveDlg : public CDialogImpl +{ +public: + enum { IDD = IDD_SELECTDRIVE }; + + BEGIN_MSG_MAP(CSelectDriveDlg) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_ID_HANDLER(IDOK, OnEndDialog) + COMMAND_ID_HANDLER(IDCANCEL, OnEndDialog) + END_MSG_MAP() + + CSelectDriveDlg() + :m_SelectedDrive(UNICODE_NULL) + { + } + + LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) + { + CWindow cbo = GetDlgItem(IDC_DRIVES); + WCHAR VolumeNameBuffer[MAX_PATH + 1]; + CStringW Tmp; + for (WCHAR Drive = 'A'; Drive <= 'Z'; ++Drive) + { + WCHAR RootPathName[] = { Drive,':','\\',0 }; + UINT Type = GetDriveTypeW(RootPathName); + if (Type == DRIVE_FIXED) + { + GetVolumeInformationW(RootPathName, VolumeNameBuffer, _countof(VolumeNameBuffer), 0, 0, 0, 0, 0); + Tmp.Format(L"%s (%.2s)", VolumeNameBuffer, RootPathName); + + int index = (int)cbo.SendMessage(CB_ADDSTRING, NULL, (LPARAM)Tmp.GetString()); + cbo.SendMessage(CB_SETITEMDATA, index, Drive); + } + } + cbo.SendMessage(CB_SETCURSEL, 0); + return 1; + } + LRESULT OnEndDialog(WORD, WORD wID, HWND, BOOL&) + { + CWindow cbo = GetDlgItem(IDC_DRIVES); + m_SelectedDrive = (WCHAR)cbo.SendMessage(CB_GETITEMDATA, cbo.SendMessage(CB_GETCURSEL)); + EndDialog(wID); + return 0; + } + + WCHAR m_SelectedDrive; +}; + + +void +SelectDrive(WCHAR &Drive) +{ + CSelectDriveDlg dlgSelectDrive; + if (dlgSelectDrive.DoModal() == IDOK) + { + Drive = dlgSelectDrive.m_SelectedDrive; + } +} diff --git a/base/applications/cleanmgr/cleanmgr/cleanmgr.cpp b/base/applications/cleanmgr/cleanmgr/cleanmgr.cpp new file mode 100644 index 00000000000..13505521208 --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/cleanmgr.cpp @@ -0,0 +1,296 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Disk cleanup entrypoint + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#include "cleanmgr.h" + +// for listview with extend style LVS_EX_CHECKBOXES, State image 1 is the unchecked box, and state image 2 is the +// checked box. see this: https://docs.microsoft.com/en-us/windows/win32/controls/extended-list-view-styles +#define STATEIMAGETOINDEX(x) (((x)&LVIS_STATEIMAGEMASK) >> 12) +#define STATEIMAGE_UNCHECKED 1 +#define STATEIMAGE_CHECKED 2 + + +struct CCleanMgrProperties : + public CPropertyPageImpl +{ + enum { IDD = IDD_PROPERTIES_MAIN }; + CWindow m_HandlerListControl; + WCHAR m_Drive; + DWORDLONG m_TotalSpaceUsed; + CCleanupHandlerList* m_HandlerList; + bool m_IgnoreChanges = true; + + + CCleanMgrProperties(WCHAR Drive, DWORDLONG TotalSpaceUsed, CCleanupHandlerList *handlerList) + : m_Drive(Drive) + , m_TotalSpaceUsed(TotalSpaceUsed) + , m_HandlerList(handlerList) + { + } + + int OnApply() + { + CStringW Title(MAKEINTRESOURCE(IDS_DISK_CLEANUP)); + CStringW Text(MAKEINTRESOURCE(IDS_CONFIRM_DELETE)); + + if (MessageBoxW(Text, Title, MB_YESNO | MB_ICONQUESTION) != IDYES) + return PSNRET_INVALID; + + return PSNRET_NOERROR; + } + + LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + HICON hIcon = (HICON)::LoadImageW( + _AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCEW(IDI_CLEANMGR), IMAGE_ICON, 0, 0, + LR_DEFAULTSIZE | LR_SHARED); + SendDlgItemMessage(IDC_DISKICON, STM_SETICON, (WPARAM)hIcon); + + m_HandlerListControl = GetDlgItem(IDC_HANDLERLIST); + RECT rc; + m_HandlerListControl.GetClientRect(&rc); + rc.right -= GetSystemMetrics(SM_CXVSCROLL); + + LV_COLUMN column = {}; + column.mask = LVCF_FMT | LVCF_WIDTH; + column.fmt = LVCFMT_LEFT; + column.cx = rc.right * 80 / 100; + ListView_InsertColumn(m_HandlerListControl, 0, &column); + column.fmt = LVCFMT_RIGHT; + column.cx = rc.right * 20 / 100; + + ListView_InsertColumn(m_HandlerListControl, 1, &column); + HIMAGELIST hImagelist = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 1, 1); + ListView_SetImageList(m_HandlerListControl, hImagelist, LVSIL_SMALL); + + ListView_SetExtendedListViewStyleEx(m_HandlerListControl, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT); + + m_HandlerList->ForEach( + [&](CCleanupHandler *current) + { + if (!current->ShowHandler) + return; + + LV_ITEM item = {}; + item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; + item.lParam = (LPARAM)current; + item.pszText = (LPWSTR)current->wszDisplayName; + item.iItem = ListView_GetItemCount(m_HandlerListControl); + item.iImage = ImageList_AddIcon(hImagelist, current->hIcon); + item.iItem = ListView_InsertItem(m_HandlerListControl, &item); + ListView_SetCheckState( + m_HandlerListControl, item.iItem, !!(current->StateFlags & HANDLER_STATE_SELECTED)); + + item.mask = LVIF_TEXT; + WCHAR ByteSize[100] = {}; + StrFormatByteSizeW(current->SpaceUsed, ByteSize, _countof(ByteSize)); + ListView_SetItemText(m_HandlerListControl, item.iItem, 1, ByteSize); + }); + + // Now we should start responding to changes + m_IgnoreChanges = false; + + // Select the first item + ListView_SetItemState(m_HandlerListControl, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); + + UpdateSpaceUsed(); + return TRUE; + } + + CCleanupHandler* GetHandler(int Index) + { + LVITEMW item = {}; + item.iItem = Index; + if (item.iItem >= 0) + { + item.mask = LVIF_PARAM; + ListView_GetItem(m_HandlerListControl, &item); + return (CCleanupHandler*)item.lParam; + } + return nullptr; + } + + + LRESULT OnDetails(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) + { + CCleanupHandler *handler = GetHandler(ListView_GetNextItem(m_HandlerListControl, -1, LVIS_FOCUSED)); + if (handler) + { + handler->Handler->ShowProperties(m_hWnd); + } + return 0L; + } + + LRESULT OnHandlerItemchanged(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) + { + if (idCtrl == IDC_HANDLERLIST) + { + // We are still initializing, don't respond to changes just yet! + if (m_IgnoreChanges) + return 0L; + + LPNMLISTVIEW pnic = (LPNMLISTVIEW)pnmh; + + // We only care about state changes + if (!(pnic->uChanged & LVIF_STATE)) + return 0L; + + + INT ItemIndex = pnic->iItem; + if (ItemIndex == -1 || ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom)) + { + return 0L; + } + + bool GotSelected = (pnic->uNewState & LVIS_SELECTED) && !(pnic->uOldState & LVIS_SELECTED); + if (GotSelected) + { + CWindow DetailsButton = GetDlgItem(IDC_DETAILS); + CCleanupHandler* handler = (CCleanupHandler*)pnic->lParam; + + SetDlgItemText(IDC_DESCRIPTION, handler->wszDescription ? handler->wszDescription : L""); + if (handler->HasSettings()) + { + DetailsButton.ShowWindow(SW_SHOW); + DetailsButton.SetWindowText(handler->wszBtnText); + } + else + { + DetailsButton.ShowWindow(SW_HIDE); + } + } + + int iOldState = STATEIMAGETOINDEX(pnic->uOldState); + int iNewState = STATEIMAGETOINDEX(pnic->uNewState); + + if ((iOldState ^ iNewState) == (STATEIMAGE_UNCHECKED ^ STATEIMAGE_CHECKED)) + { + CCleanupHandler* handler = (CCleanupHandler*)pnic->lParam; + if (iNewState == STATEIMAGE_CHECKED) + handler->StateFlags |= HANDLER_STATE_SELECTED; + else + handler->StateFlags &= ~HANDLER_STATE_SELECTED; + UpdateSpaceUsed(); + } + } + return 0L; + } + + void UpdateSpaceUsed() + { + CStringW tmp; + WCHAR ByteSize[100]; + StrFormatByteSizeW(m_TotalSpaceUsed, ByteSize, _countof(ByteSize)); + + tmp.Format(IDS_TOTAL_CLEANABLE_CAPTION, ByteSize, m_Drive); + SetDlgItemText(IDC_TOTAL_CLEANABLE, tmp); + + DWORDLONG SelectedGained = 0; + + m_HandlerList->ForEach( + [&](CCleanupHandler *current) + { + if (current->StateFlags & HANDLER_STATE_SELECTED) + { + SelectedGained += current->SpaceUsed; + } + }); + + StrFormatByteSizeW(SelectedGained, ByteSize, _countof(ByteSize)); + SetDlgItemText(IDC_SELECTED_GAINED, ByteSize); + } + + BEGIN_MSG_MAP(CCleanMgrProperties) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_ID_HANDLER(IDC_DETAILS, OnDetails) + NOTIFY_HANDLER(IDC_HANDLERLIST, LVN_ITEMCHANGED, OnHandlerItemchanged) + CHAIN_MSG_MAP(CPropertyPageImpl) // Allow the default handler to call 'OnApply' etc + END_MSG_MAP() +}; + + + +class CCleanMgrModule : public ATL::CAtlExeModuleT< CCleanMgrModule > +{ +public: + WCHAR m_Drive = UNICODE_NULL; + + bool ParseCommandLine( + _In_z_ LPCTSTR lpCmdLine, + _Out_ HRESULT* pnRetCode) throw() + { + int argc = 0; + CLocalPtr argv(CommandLineToArgvW(lpCmdLine, &argc)); + + for (int n = 1; n < argc; ++n) + { + if ((argv[n][0] == '/' || argv[n][0] == '-') && towlower(argv[n][1]) == 'd') + { + if (iswalpha(argv[n][2])) + { + m_Drive = towupper(argv[n][2]); + continue; + } + if ((n + 1) < argc) + { + m_Drive = towupper(argv[n + 1][0]); + ++n; + continue; + } + } + } + *pnRetCode = S_OK; + return true; + } + + HRESULT Run(_In_ int nShowCmd) throw() + { + if (m_Drive == UNICODE_NULL) + { + SelectDrive(m_Drive); + } + + if (m_Drive == UNICODE_NULL) + return E_FAIL; + + CCleanupHandlerList Handlers; + CEmptyVolumeCacheCallBack CacheCallBack; + + Handlers.LoadHandlers(m_Drive); + DWORDLONG TotalSpaceUsed = Handlers.ScanDrive(&CacheCallBack); + + CCleanMgrProperties cleanMgr(m_Drive, TotalSpaceUsed, &Handlers); + HPROPSHEETPAGE hpsp[1] = { cleanMgr.Create() }; + + PROPSHEETHEADERW psh = { }; + psh.dwSize = sizeof(psh); + psh.dwFlags = PSH_NOAPPLYNOW | PSH_USEICONID | PSH_NOCONTEXTHELP; + psh.hInstance = _AtlBaseModule.GetResourceInstance(); + psh.pszIcon = MAKEINTRESOURCEW(IDI_CLEANMGR); + CStringW Title; + Title.Format(IDS_PROPERTIES_MAIN_TITLE, m_Drive); + psh.pszCaption = Title; + psh.nPages = _countof(hpsp); + psh.phpage = hpsp; + + if (PropertySheetW(&psh) >= 1) + { + Handlers.ExecuteCleanup(&CacheCallBack); + } + return S_OK; + } +}; + +CCleanMgrModule _AtlModule; + + + +extern "C" int WINAPI wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, + LPWSTR /*lpCmdLine*/, int nShowCmd) +{ + return _AtlModule.WinMain(nShowCmd); +} diff --git a/base/applications/cleanmgr/cleanmgr/cleanmgr.h b/base/applications/cleanmgr/cleanmgr/cleanmgr.h new file mode 100644 index 00000000000..742a585ba25 --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/cleanmgr.h @@ -0,0 +1,66 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Main header file + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#pragma once + +#ifndef STRICT +#define STRICT +#endif + +#define _ATL_APARTMENT_THREADED +#define _ATL_NO_AUTOMATIC_NAMESPACE +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW + +#define _FORCENAMELESSUNION + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + + +using namespace ATL; + +#define NDEBUG +#include +#include +#include + + +template class CLocalPtr + : public CHeapPtr +{ +public: + CLocalPtr() throw() + { + } + + explicit CLocalPtr(_In_ T* pData) throw() : + CHeapPtr(pData) + { + } +}; + +#include "resource.h" +#include "CProgressDlg.hpp" +#include "CCleanupHandler.hpp" +#include "CCleanupHandlerList.hpp" +#include "CEmptyVolumeCacheCallBack.hpp" + +// CSelectDriveDlg.cpp +void +SelectDrive(WCHAR &Drive); diff --git a/base/applications/cleanmgr/cleanmgr/cleanmgr.rc b/base/applications/cleanmgr/cleanmgr/cleanmgr.rc new file mode 100644 index 00000000000..07edd4d0d8a --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/cleanmgr.rc @@ -0,0 +1,64 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Resources + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#include +#include +#include +#include "resource.h" + +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Disk Cleanup" +#define REACTOS_STR_INTERNAL_NAME "cleanmgr" +#define REACTOS_STR_ORIGINAL_FILENAME "cleanmgr.exe" +#include + +#include + +IDI_CLEANMGR ICON "resources/cleanmgr.ico" + +#pragma code_page(65001) + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +STRINGTABLE +BEGIN + IDS_PROPERTIES_MAIN_TITLE "Disk Cleanup for (%c:)" + IDS_TOTAL_CLEANABLE_CAPTION "You can use Disk Cleanup to free up to %s of disk space on (%c:)." + IDS_DISK_CLEANUP "Disk Cleanup" + IDS_CONFIRM_DELETE "Are you sure you want to delete these files permanently?" + IDS_CALCULATING "Disk Cleanup is calculating how much space can be gained on (%s)." + IDS_SCANNING "Scanning: %s" + IDS_CLEANING_CAPTION "Disk Cleanup is cleaning up files on %s." + IDS_CLEANING "Cleaning: %s" +END + +IDD_PROPERTIES_MAIN DIALOGEX 0, 0, 235, 215 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Disk Cleanup" +FONT 8, "MS Shell Dlg", 400, 0, 0x0 +BEGIN + CONTROL "",IDC_DISKICON,"Static",SS_ICON,6,6,20,20 + LTEXT "You can use Disk Cleanup to free up to 0.0MB of disk space on drive C.",IDC_TOTAL_CLEANABLE,36,6,192,18 + LTEXT "Files to delete:",IDC_STATIC,6,30,222,8 + CONTROL "",IDC_HANDLERLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,6,42,222,66 + LTEXT "Total amount of disk space gained:",IDC_STATIC,6,114,144,8 + RTEXT "",IDC_SELECTED_GAINED,156,114,73,8 + GROUPBOX "Description",IDC_STATIC,6,126,222,84 + LTEXT "",IDC_DESCRIPTION,12,138,210,54 + PUSHBUTTON "Details...",IDC_DETAILS,150,192,74,14 +END + +IDD_SELECTDRIVE DIALOGEX 0, 0, 177, 74 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Disk Cleanup - Select Drive" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,30,48,50,14 + PUSHBUTTON "E&xit",IDCANCEL,96,48,50,14 + LTEXT "Select the drive to clean up.",IDC_STATIC,12,6,150,8 + COMBOBOX IDC_DRIVES,12,24,150,90,CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP +END + diff --git a/base/applications/cleanmgr/cleanmgr/resource.h b/base/applications/cleanmgr/cleanmgr/resource.h new file mode 100644 index 00000000000..5edb10b5b22 --- /dev/null +++ b/base/applications/cleanmgr/cleanmgr/resource.h @@ -0,0 +1,30 @@ +/* + * PROJECT: ReactOS Disk Cleanup + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Resource definitions + * COPYRIGHT: Copyright 2023-2025 Mark Jansen + */ + +#define IDC_STATIC -1 + +#define IDI_CLEANMGR 100 + +#define IDD_PROPERTIES_MAIN 200 +#define IDC_DISKICON 201 +#define IDC_TOTAL_CLEANABLE 202 +#define IDC_HANDLERLIST 203 +#define IDC_SELECTED_GAINED 204 +#define IDC_DESCRIPTION 205 +#define IDC_DETAILS 206 + +#define IDD_SELECTDRIVE 220 +#define IDC_DRIVES 221 + +#define IDS_PROPERTIES_MAIN_TITLE 1000 +#define IDS_TOTAL_CLEANABLE_CAPTION 1001 +#define IDS_DISK_CLEANUP 1002 +#define IDS_CONFIRM_DELETE 1003 +#define IDS_CALCULATING 1004 +#define IDS_SCANNING 1005 +#define IDS_CLEANING_CAPTION 1006 +#define IDS_CLEANING 1007 diff --git a/base/applications/cleanmgr/cleanmgr/resources/cleanmgr.ico b/base/applications/cleanmgr/cleanmgr/resources/cleanmgr.ico new file mode 100644 index 0000000000000000000000000000000000000000..577b6294d14c0a3c77cc0f6a23ad3da592b8a2d4 GIT binary patch literal 59389 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 YJl1Mw0SLo84FGzqmHQ2sApeg42Qaq0zyJUM literal 0 HcmV?d00001