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 zcmZQzU}WHAP*4zHU}Runc)`TLFpYtMK|lb)*I;B|sAFbeFfahA<6v09$H1_Rg@Hjq z0m|oKVDJ+LsfX}0SQ!|;Ni%=}BZC6N^KJ%)I7OI#1%?%>3=FPoVfqyqRtPXKyuAd| zufUMO!oV=~F$04J0|SEs0|SEt1ISz!uz9$N1_p)(1_p+P1_;H_0AeyUG&C?AIB^r*6kwtdw+}*JqA;8|eWA^492m$up)w?@) z%r1bb;O^d8UA=pDH;i9B+j{qo**msxfC^Oap546Lx_Wmrl)u|z$L`ME)$JfZgM_+w z@1DJV^A4DDj@{keyREI^#&L9m1iE3W8Q6DsckkT31Edp#*#)b+yLZD?GceAa*xd~` zjDdmOurjh6AVyCU;yFz{|^}K{~utG|9^miA4=E%Z(#WUzk%`p{|4s&{}}lH|6`E< z|Bu1`{~w0>|9=?%|NqDM|NlSc|Ns9m|Ns9({{R0U_W%EXu>b%6K|K`z|Ns93)Lu|J z2L%==t%LF(y8BT1R88mGw?iVaySfu(3%B*=&7c&--95XygMop8d&lnGVDawV;P{!o z1Ds;GE2o20F>vfK1<5k7&j527xS_FN4OYy+Pz;uZ^Z)<pMMSm zyH+EEtW__AnsEn%y?rkO1H&o?28KNh92~nCL_~HlC@QXG(AC|;z#ct~!7_Lb16RT{ z2C?*+4C+Pm88o98GVtauXOPKVz`#|$jzO|$6$4-SP6nZh?F=^As~9xOS1_1VEoD%y z+039*yOBY;eg{KX*er(V=y?n=$%_~~D>gCI*KcNEWIW6uEq#zdSol1Hl++alRn-#= zhK7e3jEzq-C@WuJ(AB-mU~GJs!P@#UgSGWb2L74@3<5O=8JwKnG5Gj=U7|)hQWWz5{AHu3mBs3u3_-)-oOw) zbq7P@lm!f#GZrz_&tAxoGjAV*RO2BArdbCV^m>jn81DF*J9rx=8mA7>C>ev(0G)hPza)u$L3H=bwU+jO2mc*8jcnGNR{n6_MC z;NEr(A|2GL21_&2Ay4378JRR+_&HyC_ooL~r> zdx9Zx%3+4sMQ0d77hPg--E)<}d(TyduzfcfQkI=&C|`P*A$8?thPs`%7?=;kU9F0 zLFDvf2C36e7-TQKWKcNrkU{(SV+Q3@j~JBCyu)6Y^!RE#r2JPz~7}RcjV9>t(nZfwZX9k-)pBbzkd}AB4qRslIeMER?&Lj&jAM5g63^Uc$Uk$Rq3G0I2In&m8N5$DWbixtf+6V4 z1BR%x4;Y*;JZA8|^n}6X>Kg{H>n|DHZ@y>ny!D15=<-vB=xfgy!fw1|h`IHO!Sn8C zhUohr8B)$ZV#q!JkRjvzD~80&PZ+W;J!VL`_JSep<_m_LTQ3<(uRdicy7P*m=I$$o z!n+?C{2zQ~aDMum!ROg;2HzKd7y_PrX9#@uiy`*uPlkXOe;A@){$WUY`I{m8)o+HP zC!ZOrAAMvfdGnj0>dkM4=36fqdhWeuXnXjEq36LHhKY~fGR%DPj-l(pM~03UUm2R- z{$`l^?iWMPhd&IHKmK7@`1}LI-+%u=WjXc&VT6f>xwv_S#}e)7=)y0D_wR2{^$sCU zOV)$E1*aa|%G%%T7D$8+*ORwW$}b#EE5GygdWuT`Asx}p52}miT*xU}bm2no{7)S& z!T5E!+`5o4?Nn>t^o^G~GgjZZm!9K^PeV-WowlOsr_&ZLxpW~Nu|q$ zDu3F_w&Er0FSq8czK~foZPw=pxjr~G6nK5nJsSEcHrTF8} z5V3b-?ewK9i`T8YT3EVqUfQ&2t1q0cOuKc+9lHkio3l!nEUQ_%eaF$vWv9|grp>u< zG&BG7-M{_VHKgBNIDOf+s_ol%W-i)NQ8I1Dg#~HV7e0S#hE)9+mNZ>nvUJvpf&x@ULsx=qCkr)_M>n0e=0ea#@z#TFq5#*I$XSrst;eidUN%~%iTNHEtz$9Z#@=ea3Mw! z0}(Fvo}cgEyn4E4`?|GvTifAs*cgn$1_nlkoPtw7yn4KQ+xh#26R@d5h-tENh#Fg1 zo3cpVc=_z@&730$DQv8)mZKU>d=_>N_TtQX*P8M9l!1X^V&;N1YquPiV={HHw=&`8 z$7UjmSbEFZ^Uq$tpD4g%W@#?Qh9ZZRvoHPhhY#=Hf9PiCHssL9ssvTg&$;R0@1Gxj zewSnuLY2YJlU7np==|~L_dA@)7e$}6hLXIzW9qSA_xn-Aad2ccwG`!*q$lmm>D-4y z39@jUQnHGQiUz1BjXxDYHOX|vD=YgdMM1fQD21*h8(Z6Cknx0+g5)Fp`fP1%68%C! z93rs7lz1B(+ddg0l!BBfOiEO=u}SQb1#yVLGE<~OC2e}uh)@bvqR^}UFH~z1vCd(T znIfYuGevVUSThmCWQE@DNgl+yo`Hd3vW&Ds91#YSt_0G}g7s_h(V!kFNd5skXc*-G z{|Af^`T#>ccxzz^mhV6X?%Amt$apuRYW zJ^*R{fxQ9ZgS-Wz53v6St8akP4DTU)kn;Zw44}R`Nd6BaDC8IzKz())AJjJm(;#jC z85ltQRTMryRJ}Ze29Y3nP(Kyamxqj7;qRyN^EWXtF!nLX$h0xAuuNwVm72gHtvs1Q zTyFw{xp_Z>iauyqWif+@$N~lihV2Z3f_oWsboMidI8I`a51Ydvo;8=jG;Rq4PwoN+ z@w~+hdw z%%E1km7%I?0|O)D5e8Y=Qw;L*ml?FQjxm^-onWxHf5KpC`2ya*3<>$cz}CKnLAG%} zgT%~j41%+EFxWP(VlbGrg2AYDCxd1C4hG#>8yVE+?_|(ivX3FUYbrx-|8$1Dsq+{r zr_5$>YF^9WIB5xk$K)jpUbEIPL``16;Ly39!KZ5jgHz8=2Dk4049@-g7^2#DGk8wi z#}GYvJ45Ug5Z=L%G-D@&T+0y#z1|ZH){{>$Ft0w%z_I2u1LxW^3ILE-Y@jL_P#&Zk;8_qGXZo0t0yzLSL--Zhe+*>X&Fz>p;z_R-q z1KXZ!47|IqGcfJH!N9ZU27~C{YvBH*_`W*~Qu}T*D6c%uptk5PBo~sOI+b%K~@4UibxbHfH-HuBPw!5w}SnR*f zV88!5gZGq!430AoGI-57&)_%rJVWs86AaFajx$8BJ;e~P;u3??&T9;A`>!$h@4Lnj zxc4eUX}!ytV04uklyy9{y%ZZk+6xz8YX z@*acw!P^X~M{hIeAG*n)f9wu}(#d-any2nF7=rqv$L})O9Js+?bL<|2@yUA(wx{ni z2%UPwAa>>ngY1b13{t0_Fvy&G!XSC}DTB=U7Ywo&Uoxm3d&Ho0<`IM9>1PajXC5&a zoq51ue*O`I)wzcZs@L8z=v;cmpn3HjgZ}lm491t9GuT{u#$bHq9fR5R_Y8Ko-ZN<4 z{K%kx`!j>--LDKr4}UP2J^IOD`|t;Y)stTg4#)2>cpSUU;C1{ygY&8T457#GFa(~w z#}IPj4ny>by9~)kZZo7GyUkE`_C7G!-Yo-&X=ArcwKnJ z;CJ~cgX{Ho41t%QFa%$H#t?J;B}4eV_Y4s?Uok}7e#78)=M#hHy)O*u=N>R*oO{Sn ze&zu~;*IAFiPv8;WZ!wuP;mVjL+O<#3?+A7F;v`n#gKCU14G8m4-9qpKQXvG{>k9{ z+=Bez41EO99?eGs^MU*zMX1{PRVSRF1)JRjJ9Irq$MeQPW#%sIc{SUfqQZ(iWMA1!xKr5VmF*}h@t&h+&uy|bdv zelJIpWjJ|d-R>=~mhYH2e@e{RhoHeiR29dc?0RwY#?}qX7RIl=bqrMw#H;!6^7WgG z&o?aXUVG>SNB{*ZaWM%!{qp|Zp6v_HRiVg0I2=66ysU0t-|pRhtq>xDN;dGbsA{Tn zHhsL8k17G-h0WcR&CaKz!OedXB7jDg%)I*PvkRM=3NxAnjN2G;|JS!?0*o*|IxQ%s zTl({N1-dYdZ>T6LCfs%aHg5qFhS43yQW6SYFdil?>no`zjwuWik+0L%^0R^QFzEJr zDM=p_3}Lu{ldHE#tsI<-!SHbRl&QuLMG}y9c637GlEj3x7og;T&pY66r!X+AX0Wzi z%3v6=gMqJXErV3$W(LLl9Sjx;I~mL>_cN&L9AdDxJI5egcaTA`X&-}W>vjgK?!62a z^EWdTPMFRRJb5=m$mCrN!3#Gs1TWjh5VB%B1K;+`3>y2cGnnkT%3!k-H312X8URAGpCFbNDWUg+QH#iI`xl+HY3usZ*ULHY7)29=Ai8O$#|XE40>hQa#M3kLn09~sPUePVDpdYi%f z^nHe)<98UM58Y&lICYO9@Aw^t&{Gc>qR&5M2)O)$!SVJdhJy;lB`r?SDgt=>LHXmH!JF zX8fPXu=W2&hAaOs!u5;jGcYIxFfbStFfiCoU|{gsz`ziBo`E6#0|P_Fe?f+>|Aq{6 z{s%Iw`(Ma#;QvI1OaC`AJVDa0rq96O5Wv6?RlvYdGJ%1iZvz9v%JU2ihdwYcT>LM{ zaO1xr!@d8343Ga8GQ9jhk>UOSjSSzA^y{lJFa$Ux(cj1Sl~u6c{itOt52M*x<{+ za6X!W;X@_^!~aS_hW}lL4FBf_GW=g($ngK*M27#DHZuHwilm>Jfgyl}fuVqnfnfqC z1H%R`28Q!I3=ALm7#RL52r>M(Gi3N56Ugwts*vIT^ob1rw{2wje+5ZD10O>GgE&J0 zgCfHO25p873}y`H85|fsFnBWj7mQ-~Z&<+aKd_DAf8iX4{}VSc{NH$j;r~TM{OL0& zFa$7|F%&TPFic=bV%We?!Em0TkKqHu5{CbRn;HHa?qm2Lc%0#X;YEi36Yntm-}sc_ z|HTjR_|sv~XYghSV8~=BU}$HUz_65I1H%!9^9&CeJ}`U`{Lk>o@IS+s!2b;23jZ^F zpZK5Q=f?jGzmeJr(hT|xx(opf_6!9KK@1ZZk{LEIlrfxV=wSH3FjMe9!!pDF3|j*K zGaM@X&v1U?e}+37|1-Qs($B%54-NrQh5`m@h6xOc3>z5K7|t{3FnnOJ6a3E*Vfde+ zFz`P^PvL(u+bP1v5+a~kOjr@9t}3r)f*1o5l~vSJ5!050Nvmn-YRW5%TiHVe3=EC5 z

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

rF+L)<3gXZ<)Zqa7O5n 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