reactos/dll/win32/shell32/dialogs/recycler_prop.cpp
Bișoc George 019e3ffe5f
[SHELL32] Recycle-Bin: Validate the MaxCapacity value with respect to the available disk space. (#1688)
CORE-12313

Co-authored-by: Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
2019-07-07 19:01:09 +02:00

426 lines
15 KiB
C++

/*
* Trash virtual folder support. The trashing engine is implemented in trash.c
*
* Copyright (C) 2006 Mikolaj Zalewski
* Copyright (C) 2009 Andrew Hill
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <precomp.h>
WINE_DEFAULT_DEBUG_CHANNEL(CRecycleBin);
typedef struct
{
ULARGE_INTEGER FreeBytesAvailable;
DWORD dwSerial;
DWORD dwMaxCapacity;
DWORD dwNukeOnDelete;
} DRIVE_ITEM_CONTEXT, *PDRIVE_ITEM_CONTEXT;
static void toggleNukeOnDeleteOption(HWND hwndDlg, BOOL bEnable)
{
if (bEnable)
{
SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_UNCHECKED, 0);
EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0);
}
else
{
SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_CHECKED, 0);
EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE);
SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_UNCHECKED, 0);
}
}
static VOID
InitializeRecycleBinDlg(HWND hwndDlg, WCHAR DefaultDrive)
{
WCHAR szDrive[] = L"A:\\";
DWORD dwDrives;
WCHAR szName[100];
WCHAR szVolume[100];
DWORD MaxComponent, Flags;
DWORD dwSerial;
LVCOLUMNW lc;
HWND hDlgCtrl;
LVITEMW li;
INT itemCount;
ULARGE_INTEGER TotalNumberOfFreeBytes, TotalNumberOfBytes, FreeBytesAvailable;
RECT rect;
int columnSize;
int defIndex = 0;
DWORD dwSize;
PDRIVE_ITEM_CONTEXT pItem = NULL, pDefault = NULL, pFirst = NULL;
hDlgCtrl = GetDlgItem(hwndDlg, 14000);
if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_LOCATION, szVolume, _countof(szVolume)))
szVolume[0] = 0;
GetClientRect(hDlgCtrl, &rect);
ZeroMemory(&lc, sizeof(lc));
lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
columnSize = 140; //FIXME
lc.iSubItem = 0;
lc.fmt = LVCFMT_FIXED_WIDTH;
lc.cx = columnSize;
lc.cchTextMax = wcslen(szVolume);
lc.pszText = szVolume;
(void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&lc);
if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_DISKSPACE, szVolume, _countof(szVolume)))
szVolume[0] = 0;
lc.iSubItem = 1;
lc.cx = rect.right - rect.left - columnSize;
lc.cchTextMax = wcslen(szVolume);
lc.pszText = szVolume;
(void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&lc);
dwDrives = GetLogicalDrives();
itemCount = 0;
do
{
if (dwDrives & 0x1)
{
UINT Type = GetDriveTypeW(szDrive);
if (Type == DRIVE_FIXED) //FIXME
{
if (!GetVolumeInformationW(szDrive, szName, _countof(szName), &dwSerial, &MaxComponent, &Flags, NULL, 0))
{
szName[0] = 0;
dwSerial = -1;
}
swprintf(szVolume, L"%s (%c:)", szName, szDrive[0]);
ZeroMemory(&li, sizeof(li));
li.mask = LVIF_TEXT | LVIF_PARAM;
li.iSubItem = 0;
li.pszText = szVolume;
li.iItem = itemCount;
SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes))
{
if (StrFormatByteSizeW(TotalNumberOfFreeBytes.QuadPart, szVolume, _countof(szVolume)))
{
pItem = (DRIVE_ITEM_CONTEXT *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DRIVE_ITEM_CONTEXT));
if (pItem)
{
pItem->FreeBytesAvailable = FreeBytesAvailable;
pItem->dwSerial = dwSerial;
swprintf(szName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\BitBucket\\Volume\\%04X-%04X", LOWORD(dwSerial), HIWORD(dwSerial));
dwSize = sizeof(DWORD);
RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize);
/* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024));
pItem->dwMaxCapacity = min(pItem->dwMaxCapacity, FreeBytesAvailable.LowPart);
dwSize = sizeof(DWORD);
RegGetValueW(HKEY_CURRENT_USER, szName, L"NukeOnDelete", RRF_RT_DWORD, NULL, &pItem->dwNukeOnDelete, &dwSize);
li.mask = LVIF_PARAM;
li.lParam = (LPARAM)pItem;
(void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
if (szDrive[0] == DefaultDrive)
{
defIndex = itemCount;
pDefault = pItem;
}
}
if (!pFirst)
pFirst = pItem;
li.mask = LVIF_TEXT;
li.iSubItem = 1;
li.pszText = szVolume;
li.iItem = itemCount;
(void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
}
}
itemCount++;
}
}
szDrive[0]++;
dwDrives = (dwDrives >> 1);
} while (dwDrives);
if (!pDefault)
pDefault = pFirst;
if (pDefault)
{
toggleNukeOnDeleteOption(hwndDlg, pDefault->dwNukeOnDelete);
SetDlgItemInt(hwndDlg, 14002, pDefault->dwMaxCapacity, FALSE);
}
ZeroMemory(&li, sizeof(li));
li.mask = LVIF_STATE;
li.stateMask = (UINT)-1;
li.state = LVIS_FOCUSED | LVIS_SELECTED;
li.iItem = defIndex;
(void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
}
static BOOL StoreDriveSettings(HWND hwndDlg)
{
int iCount, iIndex;
HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000);
LVITEMW li;
PDRIVE_ITEM_CONTEXT pItem;
HKEY hKey, hSubKey;
WCHAR szSerial[20];
DWORD dwSize;
if (RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\BitBucket\\Volume", 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
return FALSE;
iCount = ListView_GetItemCount(hDlgCtrl);
ZeroMemory(&li, sizeof(li));
li.mask = LVIF_PARAM;
for (iIndex = 0; iIndex < iCount; iIndex++)
{
li.iItem = iIndex;
if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li))
{
pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
swprintf(szSerial, L"%04X-%04X", LOWORD(pItem->dwSerial), HIWORD(pItem->dwSerial));
if (RegCreateKeyExW(hKey, szSerial, 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
{
dwSize = sizeof(DWORD);
RegSetValueExW(hSubKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&pItem->dwMaxCapacity, dwSize);
dwSize = sizeof(DWORD);
RegSetValueExW(hSubKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&pItem->dwNukeOnDelete, dwSize);
RegCloseKey(hSubKey);
}
}
}
RegCloseKey(hKey);
return TRUE;
}
static VOID FreeDriveItemContext(HWND hwndDlg)
{
int iCount, iIndex;
HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000);
LVITEMW li;
iCount = ListView_GetItemCount(hDlgCtrl);
ZeroMemory(&li, sizeof(li));
li.mask = LVIF_PARAM;
for (iIndex = 0; iIndex < iCount; iIndex++)
{
li.iItem = iIndex;
if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li))
{
HeapFree(GetProcessHeap(), 0, (PVOID)li.lParam);
}
}
}
static INT
GetDefaultItem(HWND hwndDlg, LVITEMW* li)
{
HWND hDlgCtrl;
UINT iItemCount, iIndex;
hDlgCtrl = GetDlgItem(hwndDlg, 14000);
if (!hDlgCtrl)
return -1;
iItemCount = ListView_GetItemCount(hDlgCtrl);
if (!iItemCount)
return -1;
ZeroMemory(li, sizeof(LVITEMW));
li->mask = LVIF_PARAM | LVIF_STATE;
li->stateMask = (UINT)-1;
for (iIndex = 0; iIndex < iItemCount; iIndex++)
{
li->iItem = iIndex;
if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)li))
{
if (li->state & LVIS_SELECTED)
return iIndex;
}
}
return -1;
}
static INT_PTR CALLBACK
RecycleBinDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
LPPSHNOTIFY lppsn;
LPNMLISTVIEW lppl;
LVITEMW li;
PDRIVE_ITEM_CONTEXT pItem;
BOOL bSuccess;
UINT uResult;
PROPSHEETPAGE * page;
DWORD dwStyle;
ULARGE_INTEGER FreeBytesAvailable;
switch(uMsg)
{
case WM_INITDIALOG:
page = (PROPSHEETPAGE*)lParam;
InitializeRecycleBinDlg(hwndDlg, (WCHAR)page->lParam);
dwStyle = (DWORD) SendDlgItemMessage(hwndDlg, 14000, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
SendDlgItemMessage(hwndDlg, 14000, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
if (GetDlgCtrlID((HWND)wParam) != 14000)
{
SetFocus(GetDlgItem(hwndDlg, 14000));
return FALSE;
}
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 14001:
toggleNukeOnDeleteOption(hwndDlg, FALSE);
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
break;
case 14002:
if (HIWORD(wParam) == EN_CHANGE)
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
break;
case 14003:
toggleNukeOnDeleteOption(hwndDlg, TRUE);
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
break;
case 14004:
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
break;
}
break;
case WM_NOTIFY:
lppsn = (LPPSHNOTIFY) lParam;
lppl = (LPNMLISTVIEW) lParam;
if (lppsn->hdr.code == PSN_APPLY)
{
if (GetDefaultItem(hwndDlg, &li) > -1)
{
pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
if (pItem)
{
uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
if (bSuccess)
{
/* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
FreeBytesAvailable = pItem->FreeBytesAvailable;
FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024));
pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart);
SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
}
if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
pItem->dwNukeOnDelete = TRUE;
else
pItem->dwNukeOnDelete = FALSE;
}
}
if (StoreDriveSettings(hwndDlg))
{
SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR );
return TRUE;
}
}
else if (lppl->hdr.code == LVN_ITEMCHANGING)
{
ZeroMemory(&li, sizeof(li));
li.mask = LVIF_PARAM;
li.iItem = lppl->iItem;
if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&li))
return TRUE;
pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
if (!pItem)
return TRUE;
if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
{
/* new focused item */
toggleNukeOnDeleteOption(lppl->hdr.hwndFrom, pItem->dwNukeOnDelete);
SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
}
else if ((lppl->uOldState & LVIS_FOCUSED) && !(lppl->uNewState & LVIS_FOCUSED))
{
/* kill focus */
uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
if (bSuccess)
{
/* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
FreeBytesAvailable = pItem->FreeBytesAvailable;
FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024));
pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart);
SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
}
if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
pItem->dwNukeOnDelete = TRUE;
else
pItem->dwNukeOnDelete = FALSE;
}
return TRUE;
}
break;
case WM_DESTROY:
FreeDriveItemContext(hwndDlg);
break;
}
return FALSE;
}
BOOL SH_ShowRecycleBinProperties(WCHAR sDrive)
{
HPROPSHEETPAGE hpsp[1];
PROPSHEETHEADERW psh;
HPROPSHEETPAGE hprop;
INT_PTR ret;
ZeroMemory(&psh, sizeof(psh));
psh.dwSize = sizeof(psh);
psh.dwFlags = PSP_DEFAULT | PSH_PROPTITLE;
psh.pszCaption = MAKEINTRESOURCEW(IDS_RECYCLEBIN_FOLDER_NAME);
psh.hwndParent = NULL;
psh.phpage = hpsp;
psh.hInstance = shell32_hInstance;
hprop = SH_CreatePropertySheetPage(IDD_RECYCLE_BIN_PROPERTIES, RecycleBinDlg, (LPARAM)sDrive, NULL);
if (!hprop)
{
ERR("Failed to create property sheet\n");
return FALSE;
}
hpsp[psh.nPages] = hprop;
psh.nPages++;
ret = PropertySheetW(&psh);
return (ret >= 0);
}