Reactos
at master 411 lines 15 kB view raw
1/* 2 * Trash virtual folder support. The trashing engine is implemented in trash.c 3 * 4 * Copyright (C) 2006 Mikolaj Zalewski 5 * Copyright (C) 2009 Andrew Hill 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22#include <precomp.h> 23 24WINE_DEFAULT_DEBUG_CHANNEL(CRecycleBin); 25 26typedef struct 27{ 28 ULARGE_INTEGER FreeBytesAvailable; 29 DWORD dwSerial; 30 DWORD dwMaxCapacity; 31 DWORD dwNukeOnDelete; 32} DRIVE_ITEM_CONTEXT, *PDRIVE_ITEM_CONTEXT; 33 34static void toggleNukeOnDeleteOption(HWND hwndDlg, BOOL bEnable) 35{ 36 if (bEnable) 37 { 38 SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_UNCHECKED, 0); 39 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE); 40 SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0); 41 } 42 else 43 { 44 SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_CHECKED, 0); 45 EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE); 46 SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_UNCHECKED, 0); 47 } 48 49 // FIXME: Max capacity not implemented yet, disable for now (CORE-13743) 50 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE); 51} 52 53static VOID 54InitializeRecycleBinDlg(HWND hwndDlg, WCHAR DefaultDrive) 55{ 56 WCHAR szDrive[] = L"A:\\"; 57 DWORD dwDrives; 58 WCHAR szName[100]; 59 WCHAR szVolume[100]; 60 DWORD MaxComponent, Flags; 61 DWORD dwSerial; 62 LVCOLUMNW lc; 63 HWND hDlgCtrl; 64 LVITEMW li; 65 INT itemCount; 66 ULARGE_INTEGER TotalNumberOfFreeBytes, TotalNumberOfBytes, FreeBytesAvailable; 67 RECT rect; 68 int columnSize; 69 int defIndex = 0; 70 DWORD dwSize; 71 PDRIVE_ITEM_CONTEXT pItem = NULL, pDefault = NULL, pFirst = NULL; 72 73 hDlgCtrl = GetDlgItem(hwndDlg, 14000); 74 75 if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_LOCATION, szVolume, _countof(szVolume))) 76 szVolume[0] = 0; 77 78 GetClientRect(hDlgCtrl, &rect); 79 80 ZeroMemory(&lc, sizeof(lc)); 81 lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT; 82 83 columnSize = 140; //FIXME 84 lc.iSubItem = 0; 85 lc.fmt = LVCFMT_FIXED_WIDTH; 86 lc.cx = columnSize; 87 lc.cchTextMax = wcslen(szVolume); 88 lc.pszText = szVolume; 89 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&lc); 90 91 if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_DISKSPACE, szVolume, _countof(szVolume))) 92 szVolume[0] = 0; 93 94 lc.iSubItem = 1; 95 lc.cx = rect.right - rect.left - columnSize; 96 lc.cchTextMax = wcslen(szVolume); 97 lc.pszText = szVolume; 98 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&lc); 99 100 dwDrives = GetLogicalDrives(); 101 itemCount = 0; 102 do 103 { 104 if (dwDrives & 0x1) 105 { 106 UINT Type = GetDriveTypeW(szDrive); 107 if (Type == DRIVE_FIXED) //FIXME 108 { 109 if (!GetVolumeInformationW(szDrive, szName, _countof(szName), &dwSerial, &MaxComponent, &Flags, NULL, 0)) 110 { 111 szName[0] = 0; 112 dwSerial = -1; 113 } 114 115 swprintf(szVolume, L"%s (%c:)", szName, szDrive[0]); 116 ZeroMemory(&li, sizeof(li)); 117 li.mask = LVIF_TEXT | LVIF_PARAM; 118 li.iSubItem = 0; 119 li.pszText = szVolume; 120 li.iItem = itemCount; 121 SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li); 122 if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable, &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) 123 { 124 if (StrFormatByteSizeW(TotalNumberOfFreeBytes.QuadPart, szVolume, _countof(szVolume))) 125 { 126 pItem = (DRIVE_ITEM_CONTEXT *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DRIVE_ITEM_CONTEXT)); 127 if (pItem) 128 { 129 pItem->FreeBytesAvailable = FreeBytesAvailable; 130 pItem->dwSerial = dwSerial; 131 132 swprintf(szName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\BitBucket\\Volume\\%04X-%04X", LOWORD(dwSerial), HIWORD(dwSerial)); 133 134 dwSize = sizeof(DWORD); 135 if (RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize)) 136 pItem->dwMaxCapacity = ~0; 137 138 /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */ 139 FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024)); 140 pItem->dwMaxCapacity = min(pItem->dwMaxCapacity, FreeBytesAvailable.LowPart); 141 142 dwSize = sizeof(DWORD); 143 RegGetValueW(HKEY_CURRENT_USER, szName, L"NukeOnDelete", RRF_RT_DWORD, NULL, &pItem->dwNukeOnDelete, &dwSize); 144 145 li.mask = LVIF_PARAM; 146 li.lParam = (LPARAM)pItem; 147 (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li); 148 if (szDrive[0] == DefaultDrive) 149 { 150 defIndex = itemCount; 151 pDefault = pItem; 152 } 153 } 154 if (!pFirst) 155 pFirst = pItem; 156 157 li.mask = LVIF_TEXT; 158 li.iSubItem = 1; 159 li.pszText = szVolume; 160 li.iItem = itemCount; 161 (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li); 162 } 163 } 164 itemCount++; 165 } 166 } 167 szDrive[0]++; 168 dwDrives = (dwDrives >> 1); 169 } while (dwDrives); 170 171 if (!pDefault) 172 pDefault = pFirst; 173 if (pDefault) 174 { 175 toggleNukeOnDeleteOption(hwndDlg, pDefault->dwNukeOnDelete); 176 SetDlgItemInt(hwndDlg, 14002, pDefault->dwMaxCapacity, FALSE); 177 } 178 ZeroMemory(&li, sizeof(li)); 179 li.mask = LVIF_STATE; 180 li.stateMask = (UINT)-1; 181 li.state = LVIS_FOCUSED | LVIS_SELECTED; 182 li.iItem = defIndex; 183 (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li); 184} 185 186static BOOL StoreDriveSettings(HWND hwndDlg) 187{ 188 int iCount, iIndex; 189 HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000); 190 LVITEMW li; 191 PDRIVE_ITEM_CONTEXT pItem; 192 HKEY hKey, hSubKey; 193 WCHAR szSerial[20]; 194 DWORD dwSize; 195 196 if (RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\BitBucket\\Volume", 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) 197 return FALSE; 198 199 iCount = ListView_GetItemCount(hDlgCtrl); 200 201 ZeroMemory(&li, sizeof(li)); 202 li.mask = LVIF_PARAM; 203 204 for (iIndex = 0; iIndex < iCount; iIndex++) 205 { 206 li.iItem = iIndex; 207 if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li)) 208 { 209 pItem = (PDRIVE_ITEM_CONTEXT)li.lParam; 210 swprintf(szSerial, L"%04X-%04X", LOWORD(pItem->dwSerial), HIWORD(pItem->dwSerial)); 211 if (RegCreateKeyExW(hKey, szSerial, 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS) 212 { 213 dwSize = sizeof(DWORD); 214 RegSetValueExW(hSubKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&pItem->dwMaxCapacity, dwSize); 215 dwSize = sizeof(DWORD); 216 RegSetValueExW(hSubKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&pItem->dwNukeOnDelete, dwSize); 217 RegCloseKey(hSubKey); 218 } 219 } 220 } 221 RegCloseKey(hKey); 222 return TRUE; 223} 224 225static VOID FreeDriveItemContext(HWND hwndDlg) 226{ 227 int iCount, iIndex; 228 HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000); 229 LVITEMW li; 230 231 iCount = ListView_GetItemCount(hDlgCtrl); 232 233 ZeroMemory(&li, sizeof(li)); 234 li.mask = LVIF_PARAM; 235 236 for (iIndex = 0; iIndex < iCount; iIndex++) 237 { 238 li.iItem = iIndex; 239 if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li)) 240 { 241 HeapFree(GetProcessHeap(), 0, (PVOID)li.lParam); 242 } 243 } 244} 245 246static INT 247GetSelectedDriveItem(HWND hwndDlg, LVITEMW* li) 248{ 249 HWND hDlgCtrl; 250 UINT iItemCount, iIndex; 251 252 hDlgCtrl = GetDlgItem(hwndDlg, 14000); 253 if (!hDlgCtrl) 254 return -1; 255 256 iItemCount = ListView_GetItemCount(hDlgCtrl); 257 if (!iItemCount) 258 return -1; 259 260 ZeroMemory(li, sizeof(LVITEMW)); 261 li->mask = LVIF_PARAM | LVIF_STATE; 262 li->stateMask = (UINT)-1; 263 for (iIndex = 0; iIndex < iItemCount; iIndex++) 264 { 265 li->iItem = iIndex; 266 if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)li)) 267 { 268 if (li->state & LVIS_SELECTED) 269 return iIndex; 270 } 271 } 272 return -1; 273} 274 275static INT_PTR CALLBACK 276RecycleBinDlg( 277 HWND hwndDlg, 278 UINT uMsg, 279 WPARAM wParam, 280 LPARAM lParam) 281{ 282 enum { WM_NEWDRIVESELECTED = WM_APP, WM_UPDATEDRIVESETTINGS }; 283 LPPSHNOTIFY lppsn; 284 LPNMLISTVIEW lppl; 285 LVITEMW li; 286 PDRIVE_ITEM_CONTEXT pItem; 287 BOOL bSuccess; 288 UINT uResult; 289 PROPSHEETPAGE * page; 290 DWORD dwStyle; 291 ULARGE_INTEGER FreeBytesAvailable; 292 293 switch(uMsg) 294 { 295 case WM_INITDIALOG: 296 page = (PROPSHEETPAGE*)lParam; 297 InitializeRecycleBinDlg(hwndDlg, (WCHAR)page->lParam); 298 SendDlgItemMessage(hwndDlg, 14004, BM_SETCHECK, !SHELL_GetSetting(SSF_NOCONFIRMRECYCLE, fNoConfirmRecycle), 0); 299 dwStyle = (DWORD) SendDlgItemMessage(hwndDlg, 14000, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 300 dwStyle = dwStyle | LVS_EX_FULLROWSELECT; 301 SendDlgItemMessage(hwndDlg, 14000, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle); 302 if (GetDlgCtrlID((HWND)wParam) != 14000) 303 { 304 SetFocus(GetDlgItem(hwndDlg, 14000)); 305 return FALSE; 306 } 307 return TRUE; 308 case WM_COMMAND: 309 switch(LOWORD(wParam)) 310 { 311 case 14001: 312 toggleNukeOnDeleteOption(hwndDlg, FALSE); 313 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 314 break; 315 case 14002: 316 if (HIWORD(wParam) == EN_CHANGE) 317 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 318 break; 319 case 14003: 320 toggleNukeOnDeleteOption(hwndDlg, TRUE); 321 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 322 break; 323 case 14004: 324 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 325 break; 326 } 327 break; 328 case WM_NOTIFY: 329 lppsn = (LPPSHNOTIFY) lParam; 330 lppl = (LPNMLISTVIEW) lParam; 331 if (lppsn->hdr.code == PSN_APPLY) 332 { 333 SHELLSTATE ss; 334 ss.fNoConfirmRecycle = SendDlgItemMessage(hwndDlg, 14004, BM_GETCHECK, 0, 0) == BST_UNCHECKED; 335 SHGetSetSettings(&ss, SSF_NOCONFIRMRECYCLE, TRUE); 336 337 if (GetSelectedDriveItem(hwndDlg, &li) > -1) 338 { 339 SendMessage(hwndDlg, WM_UPDATEDRIVESETTINGS, 0, li.lParam); 340 } 341 if (StoreDriveSettings(hwndDlg)) 342 { 343 SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR ); 344 return TRUE; 345 } 346 } 347 else if (lppl->hdr.code == LVN_ITEMCHANGING) 348 { 349 ZeroMemory(&li, sizeof(li)); 350 li.mask = LVIF_PARAM; 351 li.iItem = lppl->iItem; 352 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&li)) 353 return TRUE; 354 355 pItem = (PDRIVE_ITEM_CONTEXT)li.lParam; 356 if (!pItem) 357 return TRUE; 358 359 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED)) 360 { 361 // New focused item, delay handling until after kill focus has been processed 362 PostMessage(hwndDlg, WM_NEWDRIVESELECTED, 0, (LPARAM)pItem); 363 } 364 else if ((lppl->uOldState & LVIS_FOCUSED) && !(lppl->uNewState & LVIS_FOCUSED)) 365 { 366 // Kill focus 367 SendMessage(hwndDlg, WM_UPDATEDRIVESETTINGS, 0, (LPARAM)pItem); 368 } 369 return TRUE; 370 371 } 372 break; 373 case WM_NEWDRIVESELECTED: 374 if (lParam) 375 { 376 pItem = (PDRIVE_ITEM_CONTEXT)lParam; 377 toggleNukeOnDeleteOption(hwndDlg, pItem->dwNukeOnDelete); 378 SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE); 379 } 380 break; 381 case WM_UPDATEDRIVESETTINGS: 382 if (lParam) 383 { 384 pItem = (PDRIVE_ITEM_CONTEXT)lParam; 385 uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE); 386 if (bSuccess) 387 { 388 /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */ 389 FreeBytesAvailable = pItem->FreeBytesAvailable; 390 FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024)); 391 pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart); 392 SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE); 393 } 394 if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) 395 pItem->dwNukeOnDelete = TRUE; 396 else 397 pItem->dwNukeOnDelete = FALSE; 398 } 399 break; 400 case WM_DESTROY: 401 FreeDriveItemContext(hwndDlg); 402 break; 403 } 404 return FALSE; 405} 406 407HRESULT RecycleBin_AddPropSheetPages(LPFNSVADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) 408{ 409 HPROPSHEETPAGE hpsp = SH_CreatePropertySheetPage(IDD_RECYCLE_BIN_PROPERTIES, RecycleBinDlg, 0, NULL); 410 return AddPropSheetPage(hpsp, pfnAddPage, lParam); 411}