2 * Trash virtual folder support. The trashing engine is implemented in trash.c
4 * Copyright (C) 2006 Mikolaj Zalewski
5 * Copyright (C) 2009 Andrew Hill
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.
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.
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
24 WINE_DEFAULT_DEBUG_CHANNEL(CRecycleBin
);
28 ULARGE_INTEGER FreeBytesAvailable
;
32 } DRIVE_ITEM_CONTEXT
, *PDRIVE_ITEM_CONTEXT
;
34 static void toggleNukeOnDeleteOption(HWND hwndDlg
, BOOL bEnable
)
38 SendDlgItemMessage(hwndDlg
, 14001, BM_SETCHECK
, BST_UNCHECKED
, 0);
39 EnableWindow(GetDlgItem(hwndDlg
, 14002), FALSE
);
40 SendDlgItemMessage(hwndDlg
, 14003, BM_SETCHECK
, BST_CHECKED
, 0);
44 SendDlgItemMessage(hwndDlg
, 14001, BM_SETCHECK
, BST_CHECKED
, 0);
45 EnableWindow(GetDlgItem(hwndDlg
, 14002), TRUE
);
46 SendDlgItemMessage(hwndDlg
, 14003, BM_SETCHECK
, BST_UNCHECKED
, 0);
51 InitializeRecycleBinDlg(HWND hwndDlg
, WCHAR DefaultDrive
)
53 WCHAR szDrive
[] = L
"A:\\";
57 DWORD MaxComponent
, Flags
;
63 ULARGE_INTEGER TotalNumberOfFreeBytes
, TotalNumberOfBytes
, FreeBytesAvailable
;
68 PDRIVE_ITEM_CONTEXT pItem
= NULL
, pDefault
= NULL
, pFirst
= NULL
;
70 hDlgCtrl
= GetDlgItem(hwndDlg
, 14000);
72 if (!LoadStringW(shell32_hInstance
, IDS_RECYCLEBIN_LOCATION
, szVolume
, _countof(szVolume
)))
75 GetClientRect(hDlgCtrl
, &rect
);
77 ZeroMemory(&lc
, sizeof(lc
));
78 lc
.mask
= LVCF_WIDTH
| LVCF_TEXT
| LVCF_SUBITEM
| LVCF_FMT
;
80 columnSize
= 140; //FIXME
82 lc
.fmt
= LVCFMT_FIXED_WIDTH
;
84 lc
.cchTextMax
= wcslen(szVolume
);
85 lc
.pszText
= szVolume
;
86 (void)SendMessageW(hDlgCtrl
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&lc
);
88 if (!LoadStringW(shell32_hInstance
, IDS_RECYCLEBIN_DISKSPACE
, szVolume
, _countof(szVolume
)))
92 lc
.cx
= rect
.right
- rect
.left
- columnSize
;
93 lc
.cchTextMax
= wcslen(szVolume
);
94 lc
.pszText
= szVolume
;
95 (void)SendMessageW(hDlgCtrl
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&lc
);
97 dwDrives
= GetLogicalDrives();
103 UINT Type
= GetDriveTypeW(szDrive
);
104 if (Type
== DRIVE_FIXED
) //FIXME
106 if (!GetVolumeInformationW(szDrive
, szName
, _countof(szName
), &dwSerial
, &MaxComponent
, &Flags
, NULL
, 0))
112 swprintf(szVolume
, L
"%s (%c:)", szName
, szDrive
[0]);
113 ZeroMemory(&li
, sizeof(li
));
114 li
.mask
= LVIF_TEXT
| LVIF_PARAM
;
116 li
.pszText
= szVolume
;
117 li
.iItem
= itemCount
;
118 SendMessageW(hDlgCtrl
, LVM_INSERTITEMW
, 0, (LPARAM
)&li
);
119 if (GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailable
, &TotalNumberOfBytes
, &TotalNumberOfFreeBytes
))
121 if (StrFormatByteSizeW(TotalNumberOfFreeBytes
.QuadPart
, szVolume
, _countof(szVolume
)))
123 pItem
= (DRIVE_ITEM_CONTEXT
*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(DRIVE_ITEM_CONTEXT
));
126 pItem
->FreeBytesAvailable
= FreeBytesAvailable
;
127 pItem
->dwSerial
= dwSerial
;
129 swprintf(szName
, L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\BitBucket\\Volume\\%04X-%04X", LOWORD(dwSerial
), HIWORD(dwSerial
));
131 dwSize
= sizeof(DWORD
);
132 RegGetValueW(HKEY_CURRENT_USER
, szName
, L
"MaxCapacity", RRF_RT_DWORD
, NULL
, &pItem
->dwMaxCapacity
, &dwSize
);
134 /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
135 FreeBytesAvailable
.QuadPart
= (FreeBytesAvailable
.QuadPart
/ (1024 * 1024));
136 pItem
->dwMaxCapacity
= min(pItem
->dwMaxCapacity
, FreeBytesAvailable
.LowPart
);
138 dwSize
= sizeof(DWORD
);
139 RegGetValueW(HKEY_CURRENT_USER
, szName
, L
"NukeOnDelete", RRF_RT_DWORD
, NULL
, &pItem
->dwNukeOnDelete
, &dwSize
);
141 li
.mask
= LVIF_PARAM
;
142 li
.lParam
= (LPARAM
)pItem
;
143 (void)SendMessageW(hDlgCtrl
, LVM_SETITEMW
, 0, (LPARAM
)&li
);
144 if (szDrive
[0] == DefaultDrive
)
146 defIndex
= itemCount
;
155 li
.pszText
= szVolume
;
156 li
.iItem
= itemCount
;
157 (void)SendMessageW(hDlgCtrl
, LVM_SETITEMW
, 0, (LPARAM
)&li
);
164 dwDrives
= (dwDrives
>> 1);
171 toggleNukeOnDeleteOption(hwndDlg
, pDefault
->dwNukeOnDelete
);
172 SetDlgItemInt(hwndDlg
, 14002, pDefault
->dwMaxCapacity
, FALSE
);
174 ZeroMemory(&li
, sizeof(li
));
175 li
.mask
= LVIF_STATE
;
176 li
.stateMask
= (UINT
)-1;
177 li
.state
= LVIS_FOCUSED
| LVIS_SELECTED
;
179 (void)SendMessageW(hDlgCtrl
, LVM_SETITEMW
, 0, (LPARAM
)&li
);
182 static BOOL
StoreDriveSettings(HWND hwndDlg
)
185 HWND hDlgCtrl
= GetDlgItem(hwndDlg
, 14000);
187 PDRIVE_ITEM_CONTEXT pItem
;
192 if (RegCreateKeyExW(HKEY_CURRENT_USER
, L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\BitBucket\\Volume", 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, NULL
) != ERROR_SUCCESS
)
195 iCount
= ListView_GetItemCount(hDlgCtrl
);
197 ZeroMemory(&li
, sizeof(li
));
198 li
.mask
= LVIF_PARAM
;
200 for (iIndex
= 0; iIndex
< iCount
; iIndex
++)
203 if (SendMessageW(hDlgCtrl
, LVM_GETITEMW
, 0, (LPARAM
)&li
))
205 pItem
= (PDRIVE_ITEM_CONTEXT
)li
.lParam
;
206 swprintf(szSerial
, L
"%04X-%04X", LOWORD(pItem
->dwSerial
), HIWORD(pItem
->dwSerial
));
207 if (RegCreateKeyExW(hKey
, szSerial
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hSubKey
, NULL
) == ERROR_SUCCESS
)
209 dwSize
= sizeof(DWORD
);
210 RegSetValueExW(hSubKey
, L
"MaxCapacity", 0, REG_DWORD
, (LPBYTE
)&pItem
->dwMaxCapacity
, dwSize
);
211 dwSize
= sizeof(DWORD
);
212 RegSetValueExW(hSubKey
, L
"NukeOnDelete", 0, REG_DWORD
, (LPBYTE
)&pItem
->dwNukeOnDelete
, dwSize
);
213 RegCloseKey(hSubKey
);
221 static VOID
FreeDriveItemContext(HWND hwndDlg
)
224 HWND hDlgCtrl
= GetDlgItem(hwndDlg
, 14000);
227 iCount
= ListView_GetItemCount(hDlgCtrl
);
229 ZeroMemory(&li
, sizeof(li
));
230 li
.mask
= LVIF_PARAM
;
232 for (iIndex
= 0; iIndex
< iCount
; iIndex
++)
235 if (SendMessageW(hDlgCtrl
, LVM_GETITEMW
, 0, (LPARAM
)&li
))
237 HeapFree(GetProcessHeap(), 0, (PVOID
)li
.lParam
);
243 GetDefaultItem(HWND hwndDlg
, LVITEMW
* li
)
246 UINT iItemCount
, iIndex
;
248 hDlgCtrl
= GetDlgItem(hwndDlg
, 14000);
252 iItemCount
= ListView_GetItemCount(hDlgCtrl
);
256 ZeroMemory(li
, sizeof(LVITEMW
));
257 li
->mask
= LVIF_PARAM
| LVIF_STATE
;
258 li
->stateMask
= (UINT
)-1;
259 for (iIndex
= 0; iIndex
< iItemCount
; iIndex
++)
262 if (SendMessageW(hDlgCtrl
, LVM_GETITEMW
, 0, (LPARAM
)li
))
264 if (li
->state
& LVIS_SELECTED
)
271 static INT_PTR CALLBACK
281 PDRIVE_ITEM_CONTEXT pItem
;
284 PROPSHEETPAGE
* page
;
286 ULARGE_INTEGER FreeBytesAvailable
;
291 page
= (PROPSHEETPAGE
*)lParam
;
292 InitializeRecycleBinDlg(hwndDlg
, (WCHAR
)page
->lParam
);
293 dwStyle
= (DWORD
) SendDlgItemMessage(hwndDlg
, 14000, LVM_GETEXTENDEDLISTVIEWSTYLE
, 0, 0);
294 dwStyle
= dwStyle
| LVS_EX_FULLROWSELECT
;
295 SendDlgItemMessage(hwndDlg
, 14000, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, dwStyle
);
296 if (GetDlgCtrlID((HWND
)wParam
) != 14000)
298 SetFocus(GetDlgItem(hwndDlg
, 14000));
303 switch(LOWORD(wParam
))
306 toggleNukeOnDeleteOption(hwndDlg
, FALSE
);
307 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
310 if (HIWORD(wParam
) == EN_CHANGE
)
311 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
314 toggleNukeOnDeleteOption(hwndDlg
, TRUE
);
315 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
318 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
323 lppsn
= (LPPSHNOTIFY
) lParam
;
324 lppl
= (LPNMLISTVIEW
) lParam
;
325 if (lppsn
->hdr
.code
== PSN_APPLY
)
327 if (GetDefaultItem(hwndDlg
, &li
) > -1)
329 pItem
= (PDRIVE_ITEM_CONTEXT
)li
.lParam
;
332 uResult
= GetDlgItemInt(hwndDlg
, 14002, &bSuccess
, FALSE
);
335 /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
336 FreeBytesAvailable
= pItem
->FreeBytesAvailable
;
337 FreeBytesAvailable
.QuadPart
= (FreeBytesAvailable
.QuadPart
/ (1024 * 1024));
338 pItem
->dwMaxCapacity
= min(uResult
, FreeBytesAvailable
.LowPart
);
339 SetDlgItemInt(hwndDlg
, 14002, pItem
->dwMaxCapacity
, FALSE
);
341 if (SendDlgItemMessageW(hwndDlg
, 14003, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
342 pItem
->dwNukeOnDelete
= TRUE
;
344 pItem
->dwNukeOnDelete
= FALSE
;
347 if (StoreDriveSettings(hwndDlg
))
349 SetWindowLongPtr( hwndDlg
, DWLP_MSGRESULT
, PSNRET_NOERROR
);
353 else if (lppl
->hdr
.code
== LVN_ITEMCHANGING
)
355 ZeroMemory(&li
, sizeof(li
));
356 li
.mask
= LVIF_PARAM
;
357 li
.iItem
= lppl
->iItem
;
358 if (!SendMessageW(lppl
->hdr
.hwndFrom
, LVM_GETITEMW
, 0, (LPARAM
)&li
))
361 pItem
= (PDRIVE_ITEM_CONTEXT
)li
.lParam
;
365 if (!(lppl
->uOldState
& LVIS_FOCUSED
) && (lppl
->uNewState
& LVIS_FOCUSED
))
367 /* new focused item */
368 toggleNukeOnDeleteOption(lppl
->hdr
.hwndFrom
, pItem
->dwNukeOnDelete
);
369 SetDlgItemInt(hwndDlg
, 14002, pItem
->dwMaxCapacity
, FALSE
);
371 else if ((lppl
->uOldState
& LVIS_FOCUSED
) && !(lppl
->uNewState
& LVIS_FOCUSED
))
374 uResult
= GetDlgItemInt(hwndDlg
, 14002, &bSuccess
, FALSE
);
377 /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */
378 FreeBytesAvailable
= pItem
->FreeBytesAvailable
;
379 FreeBytesAvailable
.QuadPart
= (FreeBytesAvailable
.QuadPart
/ (1024 * 1024));
380 pItem
->dwMaxCapacity
= min(uResult
, FreeBytesAvailable
.LowPart
);
381 SetDlgItemInt(hwndDlg
, 14002, pItem
->dwMaxCapacity
, FALSE
);
383 if (SendDlgItemMessageW(hwndDlg
, 14003, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
384 pItem
->dwNukeOnDelete
= TRUE
;
386 pItem
->dwNukeOnDelete
= FALSE
;
393 FreeDriveItemContext(hwndDlg
);
399 BOOL
SH_ShowRecycleBinProperties(WCHAR sDrive
)
401 HPROPSHEETPAGE hpsp
[1];
402 PROPSHEETHEADERW psh
;
403 HPROPSHEETPAGE hprop
;
406 ZeroMemory(&psh
, sizeof(psh
));
407 psh
.dwSize
= sizeof(psh
);
408 psh
.dwFlags
= PSP_DEFAULT
| PSH_PROPTITLE
;
409 psh
.pszCaption
= MAKEINTRESOURCEW(IDS_RECYCLEBIN_FOLDER_NAME
);
410 psh
.hwndParent
= NULL
;
412 psh
.hInstance
= shell32_hInstance
;
414 hprop
= SH_CreatePropertySheetPage(IDD_RECYCLE_BIN_PROPERTIES
, RecycleBinDlg
, (LPARAM
)sDrive
, NULL
);
417 ERR("Failed to create property sheet\n");
420 hpsp
[psh
.nPages
] = hprop
;
423 ret
= PropertySheetW(&psh
);