Skip to content

Commit f9bedd5

Browse files
committed
[CLEANMGR] Add basic cleanmgr implementation
CORE-18941
1 parent 0cd7e2c commit f9bedd5

15 files changed

+1110
-0
lines changed

base/applications/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_subdirectory(atactl)
33
add_subdirectory(cacls)
44
add_subdirectory(calc)
55
add_subdirectory(charmap)
6+
add_subdirectory(cleanmgr)
67
add_subdirectory(clipbrd)
78
add_subdirectory(cmdutils)
89
add_subdirectory(control)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
project(cleanmgr)
3+
4+
# The main application
5+
add_subdirectory(cleanmgr)
6+
7+
# Cleanup handlers
8+
#add_subdirectory(dataclen) # Data Driven Cleaner
9+
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*
2+
* PROJECT: ReactOS Disk Cleanup
3+
* LICENSE: MIT (https://spdx.org/licenses/MIT)
4+
* PURPOSE: CCleanupHandler implementation
5+
* COPYRIGHT: Copyright 2023-2025 Mark Jansen <[email protected]>
6+
*/
7+
8+
#include "cleanmgr.h"
9+
10+
11+
CCleanupHandler::CCleanupHandler(CRegKey &subKey, const CStringW &keyName, const GUID &guid)
12+
: hSubKey(subKey)
13+
, KeyName(keyName)
14+
, Guid(guid)
15+
, dwFlags(0)
16+
, Priority(0)
17+
, StateFlags(0)
18+
, SpaceUsed(0)
19+
, ShowHandler(true)
20+
, hIcon(NULL)
21+
{
22+
}
23+
24+
CCleanupHandler::~CCleanupHandler()
25+
{
26+
Deactivate();
27+
::DestroyIcon(hIcon);
28+
}
29+
30+
void
31+
CCleanupHandler::Deactivate()
32+
{
33+
if (Handler)
34+
{
35+
DWORD dwFlags = 0;
36+
Handler->Deactivate(&dwFlags);
37+
if (dwFlags & EVCF_REMOVEFROMLIST)
38+
UNIMPLEMENTED_DBGBREAK();
39+
}
40+
}
41+
42+
bool
43+
CCleanupHandler::Initialize(LPCWSTR pcwszVolume)
44+
{
45+
if (FAILED_UNEXPECTEDLY(
46+
::CoCreateInstance(Guid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IEmptyVolumeCache, &Handler))))
47+
{
48+
return false;
49+
}
50+
51+
DWORD dwSize = sizeof(Priority);
52+
if (hSubKey.QueryBinaryValue(L"Priority", &Priority, &dwSize) != ERROR_SUCCESS)
53+
{
54+
if (hSubKey.QueryDWORDValue(L"Priority", Priority) != ERROR_SUCCESS)
55+
Priority = 200;
56+
}
57+
58+
dwSize = sizeof(StateFlags);
59+
if (hSubKey.QueryDWORDValue(L"StateFlags", StateFlags) != ERROR_SUCCESS)
60+
StateFlags = 0;
61+
62+
WCHAR PathBuffer[MAX_PATH] = {};
63+
ULONG nChars = _countof(PathBuffer);
64+
if (hSubKey.QueryStringValue(L"IconPath", PathBuffer, &nChars) != ERROR_SUCCESS)
65+
{
66+
CStringW Tmp;
67+
WCHAR GuidStr[50] = {};
68+
if (StringFromGUID2(Guid, GuidStr, _countof(GuidStr)))
69+
{
70+
Tmp.Format(L"CLSID\\%s\\DefaultIcon", GuidStr);
71+
CRegKey clsid;
72+
nChars = _countof(PathBuffer);
73+
if (clsid.Open(HKEY_CLASSES_ROOT, Tmp, KEY_READ) != ERROR_SUCCESS ||
74+
clsid.QueryStringValue(NULL, PathBuffer, &nChars) != ERROR_SUCCESS)
75+
{
76+
PathBuffer[0] = UNICODE_NULL;
77+
}
78+
}
79+
}
80+
if (!PathBuffer[0])
81+
StringCchCopyW(PathBuffer, _countof(PathBuffer), L"%systemroot%\\system32\\shell32.dll");
82+
83+
int Index = 0;
84+
WCHAR *ptr = wcschr(PathBuffer, L',');
85+
if (ptr)
86+
{
87+
*ptr++ = UNICODE_NULL;
88+
Index = wcstol(ptr, NULL, 10);
89+
}
90+
HICON Large, Small;
91+
UINT Result = ExtractIconExW(PathBuffer, Index, &Large, &Small, 1);
92+
if (Result < 1)
93+
Result = ExtractIconExW(L"%systemroot%\\system32\\shell32.dll", 0, &Large, &Small, 1);
94+
if (Result >= 1)
95+
{
96+
hIcon = Small;
97+
if (!hIcon)
98+
{
99+
hIcon = Large;
100+
}
101+
else
102+
{
103+
::DestroyIcon(Large);
104+
}
105+
}
106+
107+
// These options should come from the command line
108+
// dwFlags |= EVCF_SETTINGSMODE;
109+
// dwFlags |= EVCF_OUTOFDISKSPACE;
110+
111+
CComPtr<IEmptyVolumeCache2> spHandler2;
112+
HRESULT hr = Handler->QueryInterface(IID_PPV_ARG(IEmptyVolumeCache2, &spHandler2));
113+
if (SUCCEEDED(hr))
114+
{
115+
hr = spHandler2->InitializeEx(
116+
hSubKey, pcwszVolume, KeyName, &wszDisplayName, &wszDescription, &wszBtnText, &dwFlags);
117+
if (FAILED_UNEXPECTEDLY(hr))
118+
return false;
119+
120+
// No files to clean will return S_FALSE;
121+
if (hr != S_OK)
122+
return false;
123+
}
124+
else
125+
{
126+
// Observed behavior:
127+
// When Initialize is called, wszDescription is actually pointing to data
128+
// wszDescription.AllocateBytes(0x400u);
129+
hr = Handler->Initialize(hSubKey, pcwszVolume, &wszDisplayName, &wszDescription, &dwFlags);
130+
if (FAILED_UNEXPECTEDLY(hr))
131+
return false;
132+
133+
// No files to clean will return S_FALSE;
134+
if (hr != S_OK)
135+
return false;
136+
137+
CComPtr<IPropertyBag> spBag;
138+
WCHAR GuidStr[50] = {};
139+
nChars = _countof(GuidStr);
140+
if (hSubKey.QueryStringValue(L"PropertyBag", GuidStr, &nChars) == ERROR_SUCCESS)
141+
{
142+
GUID guid = {};
143+
if (!FAILED_UNEXPECTEDLY(CLSIDFromString(GuidStr, &guid)))
144+
{
145+
FAILED_UNEXPECTEDLY(
146+
CoCreateInstance(guid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPropertyBag, &spBag)));
147+
}
148+
}
149+
ReadProperty(L"Display", spBag, wszDisplayName);
150+
ReadProperty(L"Description", spBag, wszDescription);
151+
152+
if (dwFlags & EVCF_HASSETTINGS)
153+
{
154+
ReadProperty(L"AdvancedButtonText", spBag, wszBtnText);
155+
}
156+
}
157+
158+
if ((dwFlags & EVCF_ENABLEBYDEFAULT) && !(StateFlags & HANDLER_STATE_SELECTED))
159+
{
160+
StateFlags |= HANDLER_STATE_SELECTED;
161+
}
162+
163+
// For convenience
164+
if (!wszDisplayName)
165+
SHStrDupW(KeyName, &wszDisplayName);
166+
167+
return true;
168+
}
169+
170+
void
171+
CCleanupHandler::ReadProperty(LPCWSTR Name, IPropertyBag *pBag, CComHeapPtr<WCHAR> &storage)
172+
{
173+
if (storage)
174+
return;
175+
176+
if (pBag)
177+
{
178+
CComVariant tmp;
179+
tmp.vt = VT_BSTR;
180+
HRESULT hr = pBag->Read(Name, &tmp, NULL);
181+
if (!FAILED_UNEXPECTEDLY(hr) && tmp.vt == VT_BSTR)
182+
{
183+
SHStrDupW(tmp.bstrVal, &storage);
184+
}
185+
}
186+
187+
if (!storage)
188+
{
189+
WCHAR TmpStr[0x200] = {};
190+
DWORD dwSize = _countof(TmpStr);
191+
192+
if (hSubKey.QueryStringValue(Name, TmpStr, &dwSize) == ERROR_SUCCESS)
193+
{
194+
WCHAR ResolvedStr[0x200] = {};
195+
SHLoadIndirectString(TmpStr, ResolvedStr, _countof(ResolvedStr), NULL);
196+
SHStrDupW(ResolvedStr, &storage);
197+
}
198+
}
199+
}
200+
201+
BOOL
202+
CCleanupHandler::HasSettings() const
203+
{
204+
return !!(dwFlags & EVCF_HASSETTINGS);
205+
}
206+
207+
BOOL
208+
CCleanupHandler::DontShowIfZero() const
209+
{
210+
return !!(dwFlags & EVCF_DONTSHOWIFZERO);
211+
}
212+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* PROJECT: ReactOS Disk Cleanup
3+
* LICENSE: MIT (https://spdx.org/licenses/MIT)
4+
* PURPOSE: CCleanupHandler definition
5+
* COPYRIGHT: Copyright 2023-2025 Mark Jansen <[email protected]>
6+
*/
7+
8+
#define HANDLER_STATE_SELECTED 1
9+
10+
11+
struct CCleanupHandler
12+
{
13+
CCleanupHandler(CRegKey &subKey, const CStringW &keyName, const GUID &guid);
14+
~CCleanupHandler();
15+
16+
void Deactivate();
17+
18+
bool
19+
Initialize(LPCWSTR pcwszVolume);
20+
21+
void
22+
ReadProperty(LPCWSTR Name, IPropertyBag *pBag, CComHeapPtr<WCHAR> &storage);
23+
24+
BOOL
25+
HasSettings() const;
26+
27+
BOOL
28+
DontShowIfZero() const;
29+
30+
CRegKey hSubKey;
31+
CStringW KeyName;
32+
GUID Guid;
33+
34+
CComHeapPtr<WCHAR> wszDisplayName;
35+
CComHeapPtr<WCHAR> wszDescription;
36+
CComHeapPtr<WCHAR> wszBtnText;
37+
38+
CStringW IconPath;
39+
DWORD dwFlags;
40+
DWORD Priority;
41+
DWORD StateFlags;
42+
43+
CComPtr<IEmptyVolumeCache> Handler;
44+
DWORDLONG SpaceUsed;
45+
bool ShowHandler;
46+
HICON hIcon;
47+
};
48+

0 commit comments

Comments
 (0)