Reactos
1/*
2 * PROJECT: shell32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: CRecycleBinCleaner implementation
5 * COPYRIGHT: Copyright 2023-2025 Mark Jansen <mark.jansen@reactos.org>
6 */
7
8#include "precomp.h"
9
10WINE_DEFAULT_DEBUG_CHANNEL(shell);
11
12
13CLSID CLSID_RecycleBinCleaner = { 0x5ef4af3a, 0xf726, 0x11d0, { 0xb8, 0xa2, 0x00, 0xc0, 0x4f, 0xc3, 0x09, 0xa4 } };
14
15struct CRecycleBinCleaner :
16 public CComObjectRootEx<CComSingleThreadModel>,
17 public CComCoClass<CRecycleBinCleaner, &CLSID_RecycleBinCleaner>,
18 public IEmptyVolumeCache2
19{
20 WCHAR m_wszVolume[4];
21
22 void
23 OutputResourceString(DWORD dwResId, _Out_ LPWSTR *ppwszOutput)
24 {
25 CStringW Tmp(MAKEINTRESOURCEW(dwResId));
26 SHStrDupW(Tmp, ppwszOutput);
27 }
28
29public:
30
31 // +IEmptyVolumeCache
32 STDMETHODIMP Initialize(
33 _In_ HKEY hkRegKey,
34 _In_ LPCWSTR pcwszVolume,
35 _Out_ LPWSTR* ppwszDisplayName,
36 _Out_ LPWSTR* ppwszDescription,
37 _Out_ DWORD* pdwFlags)
38 {
39 if (!pdwFlags)
40 return E_POINTER;
41
42 *pdwFlags = EVCF_HASSETTINGS;
43
44 OutputResourceString(IDS_RECYCLE_CLEANER_DISPLAYNAME, ppwszDisplayName);
45 OutputResourceString(IDS_RECYCLE_CLEANER_DESCRIPTION, ppwszDescription);
46
47 return StringCchCopyW(m_wszVolume, _countof(m_wszVolume), pcwszVolume);
48 }
49
50 STDMETHODIMP GetSpaceUsed(
51 _Out_ DWORDLONG* pdwlSpaceUsed,
52 _In_opt_ IEmptyVolumeCacheCallBack* picb)
53 {
54 if (!pdwlSpaceUsed)
55 return E_POINTER;
56
57 SHQUERYRBINFO bin = { sizeof(bin) };
58 HRESULT hr = SHQueryRecycleBinW(m_wszVolume, &bin);
59 if (FAILED_UNEXPECTEDLY(hr))
60 {
61 bin.i64Size = 0;
62 }
63 *pdwlSpaceUsed = bin.i64Size;
64 if (picb)
65 {
66 picb->ScanProgress(bin.i64Size, EVCCBF_LASTNOTIFICATION, NULL);
67 }
68
69 return S_OK;
70 }
71
72 STDMETHODIMP Purge(
73 _In_ DWORDLONG dwlSpaceToFree,
74 _In_opt_ IEmptyVolumeCacheCallBack *picb)
75 {
76 DWORDLONG dwlPrevious = 0;
77 GetSpaceUsed(&dwlPrevious, NULL);
78
79 SHEmptyRecycleBinW(NULL, m_wszVolume, SHERB_NOCONFIRMATION | SHERB_NOPROGRESSUI | SHERB_NOSOUND);
80 if (picb)
81 {
82 picb->PurgeProgress(dwlPrevious, 0, EVCCBF_LASTNOTIFICATION, NULL);
83 }
84
85 return S_OK;
86 }
87
88 STDMETHODIMP ShowProperties(
89 _In_ HWND hwnd)
90 {
91 CComHeapPtr<ITEMIDLIST> pidl;
92 HRESULT hr;
93 if (FAILED_UNEXPECTEDLY(hr = SHGetSpecialFolderLocation(hwnd, CSIDL_BITBUCKET, &pidl)))
94 return hr;
95
96 SHELLEXECUTEINFOW seei = {sizeof(seei)};
97 seei.hwnd = hwnd;
98 seei.lpVerb = L"open";
99 seei.nShow = SW_SHOWNORMAL;
100 seei.fMask = SEE_MASK_IDLIST;
101 seei.lpIDList = pidl;
102 ShellExecuteExW(&seei);
103
104 return S_OK;
105 }
106
107 STDMETHODIMP Deactivate(
108 _Out_ DWORD* pdwFlags)
109 {
110 if (!pdwFlags)
111 return E_POINTER;
112
113 *pdwFlags = 0;
114
115 return S_OK;
116 }
117 // -IEmptyVolumeCache
118
119
120 // +IEmptyVolumeCache2
121 STDMETHODIMP InitializeEx(
122 _In_ HKEY hkRegKey,
123 _In_ LPCWSTR pcwszVolume,
124 _In_ LPCWSTR pcwszKeyName,
125 _Out_ LPWSTR* ppwszDisplayName,
126 _Out_ LPWSTR* ppwszDescription,
127 _Out_ LPWSTR* ppwszBtnText,
128 _Out_ DWORD* pdwFlags)
129 {
130 OutputResourceString(IDS_RECYCLE_CLEANER_BUTTON_TEXT, ppwszBtnText);
131
132 return Initialize(hkRegKey, pcwszVolume, ppwszDisplayName, ppwszDescription, pdwFlags);
133 }
134 // -IEmptyVolumeCache2
135
136
137 DECLARE_PROTECT_FINAL_CONSTRUCT();
138 DECLARE_REGISTRY_RESOURCEID(IDR_RECYCLEBINCLEANER)
139 DECLARE_NOT_AGGREGATABLE(CRecycleBinCleaner)
140
141 BEGIN_COM_MAP(CRecycleBinCleaner)
142 COM_INTERFACE_ENTRY_IID(IID_IEmptyVolumeCache2, IEmptyVolumeCache2)
143 COM_INTERFACE_ENTRY_IID(IID_IEmptyVolumeCache, IEmptyVolumeCache)
144 COM_INTERFACE_ENTRY_IID(IID_IUnknown, IUnknown)
145 END_COM_MAP()
146};
147
148
149OBJECT_ENTRY_AUTO(CLSID_RecycleBinCleaner, CRecycleBinCleaner)