2 * Provides default drive shell extension
4 * Copyright 2005 Johannes Anderwald
5 * Copyright 2012 Rafal Harabien
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
22 #define _USE_MATH_DEFINES
26 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
28 static const GUID GUID_DEVCLASS_DISKDRIVE
= {0x4d36e967L
, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
32 HWPD_STANDARDLIST
= 0,
34 HWPD_MAX
= HWPD_LARGELIST
35 } HWPAGE_DISPLAYMODE
, *PHWPAGE_DISPLAYMODE
;
38 DeviceCreateHardwarePageEx(HWND hWndParent
,
41 HWPAGE_DISPLAYMODE DisplayMode
);
42 UINT
SH_FormatByteSize(LONGLONG cbSize
, LPWSTR pwszResult
, UINT cchResultMax
);
45 GetDriveNameWithLetter(LPWSTR pwszText
, UINT cchTextMax
, LPCWSTR pwszDrive
)
47 DWORD dwMaxComp
, dwFileSys
;
50 if (GetVolumeInformationW(pwszDrive
, pwszText
, cchTextMax
, NULL
, &dwMaxComp
, &dwFileSys
, NULL
, 0))
52 cchText
= wcslen(pwszText
);
55 /* load default volume label */
56 cchText
= LoadStringW(shell32_hInstance
, IDS_DRIVE_FIXED
, pwszText
, cchTextMax
);
60 StringCchPrintfW(pwszText
+ cchText
, cchTextMax
- cchText
, L
" (%c)", pwszDrive
[0]);
64 InitializeChkDskDialog(HWND hwndDlg
, LPCWSTR pwszDrive
)
68 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (INT_PTR
)pwszDrive
);
70 Length
= GetWindowTextW(hwndDlg
, wszText
, sizeof(wszText
) / sizeof(WCHAR
));
71 wszText
[Length
] = L
' ';
72 GetDriveNameWithLetter(&wszText
[Length
+ 1], (sizeof(wszText
) / sizeof(WCHAR
)) - Length
- 1, pwszDrive
);
73 SetWindowText(hwndDlg
, wszText
);
76 static HWND hChkdskDrvDialog
= NULL
;
77 static BOOLEAN bChkdskSuccess
= FALSE
;
81 IN CALLBACKCOMMAND Command
,
90 Progress
= (PDWORD
)ActionInfo
;
91 SendDlgItemMessageW(hChkdskDrvDialog
, 14002, PBM_SETPOS
, (WPARAM
)*Progress
, 0);
94 pSuccess
= (PBOOLEAN
)ActionInfo
;
95 bChkdskSuccess
= (*pSuccess
);
99 case INSUFFICIENTRIGHTS
:
101 case CLUSTERSIZETOOSMALL
:
102 bChkdskSuccess
= FALSE
;
114 ChkDskNow(HWND hwndDlg
, LPCWSTR pwszDrive
)
116 //DWORD ClusterSize = 0;
118 ULARGE_INTEGER TotalNumberOfFreeBytes
, FreeBytesAvailableUser
;
119 BOOLEAN bCorrectErrors
= FALSE
, bScanDrive
= FALSE
;
121 if(!GetVolumeInformationW(pwszDrive
, NULL
, 0, NULL
, NULL
, NULL
, wszFs
, _countof(wszFs
)))
123 FIXME("failed to get drive fs type\n");
127 if (!GetDiskFreeSpaceExW(pwszDrive
, &FreeBytesAvailableUser
, &TotalNumberOfFreeBytes
, NULL
))
129 FIXME("failed to get drive space type\n");
133 /*if (!GetDefaultClusterSize(wszFs, &ClusterSize, &TotalNumberOfFreeBytes))
135 FIXME("invalid cluster size\n");
139 if (SendDlgItemMessageW(hwndDlg
, 14000, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
140 bCorrectErrors
= TRUE
;
142 if (SendDlgItemMessageW(hwndDlg
, 14001, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
145 hChkdskDrvDialog
= hwndDlg
;
146 bChkdskSuccess
= FALSE
;
147 SendDlgItemMessageW(hwndDlg
, 14002, PBM_SETRANGE
, 0, MAKELPARAM(0, 100));
148 Chkdsk((LPWSTR
)pwszDrive
, (LPWSTR
)wszFs
, bCorrectErrors
, TRUE
, FALSE
, bScanDrive
, NULL
, NULL
, ChkdskCallback
); // FIXME: casts
150 hChkdskDrvDialog
= NULL
;
151 bChkdskSuccess
= FALSE
;
154 static INT_PTR CALLBACK
164 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)lParam
);
165 InitializeChkDskDialog(hwndDlg
, (LPCWSTR
)lParam
);
168 switch(LOWORD(wParam
))
171 EndDialog(hwndDlg
, 0);
175 LPCWSTR pwszDrive
= (LPCWSTR
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
176 ChkDskNow(hwndDlg
, pwszDrive
);
187 CDrvDefExt::PaintStaticControls(HWND hwndDlg
, LPDRAWITEMSTRUCT pDrawItem
)
191 if (pDrawItem
->CtlID
== 14013)
193 hBrush
= CreateSolidBrush(RGB(0, 0, 255));
196 FillRect(pDrawItem
->hDC
, &pDrawItem
->rcItem
, hBrush
);
197 DeleteObject((HGDIOBJ
)hBrush
);
200 else if (pDrawItem
->CtlID
== 14014)
202 hBrush
= CreateSolidBrush(RGB(255, 0, 255));
205 FillRect(pDrawItem
->hDC
, &pDrawItem
->rcItem
, hBrush
);
206 DeleteObject((HGDIOBJ
)hBrush
);
209 else if (pDrawItem
->CtlID
== 14015)
211 HBRUSH hBlueBrush
= CreateSolidBrush(RGB(0, 0, 255));
212 HBRUSH hMagBrush
= CreateSolidBrush(RGB(255, 0, 255));
213 HPEN hDarkBluePen
= CreatePen(PS_SOLID
, 1, RGB(0, 0, 128));
214 HPEN hDarkMagPen
= CreatePen(PS_SOLID
, 1, RGB(128, 0, 128));
216 INT xCenter
= (pDrawItem
->rcItem
.left
+ pDrawItem
->rcItem
.right
)/2;
217 INT yCenter
= (pDrawItem
->rcItem
.top
+ pDrawItem
->rcItem
.bottom
- 10)/2;
218 INT cx
= pDrawItem
->rcItem
.right
- pDrawItem
->rcItem
.left
;
219 INT cy
= pDrawItem
->rcItem
.bottom
- pDrawItem
->rcItem
.top
- 10;
220 TRACE("FreeSpace %u a %f cx %d\n", m_FreeSpacePerc
, M_PI
+m_FreeSpacePerc
/100.0f
*M_PI
*2.0f
, cx
);
222 HBRUSH hbrOld
= (HBRUSH
)SelectObject(pDrawItem
->hDC
, hMagBrush
);
223 INT xRadial
= xCenter
+ (INT
)(cos(M_PI
+m_FreeSpacePerc
/100.0f
*M_PI
*2.0f
)*cx
/2);
224 INT yRadial
= yCenter
- (INT
)(sin(M_PI
+m_FreeSpacePerc
/100.0f
*M_PI
*2.0f
)*cy
/2);
226 pDrawItem
->rcItem
.left
, pDrawItem
->rcItem
.top
,
227 pDrawItem
->rcItem
.right
, pDrawItem
->rcItem
.bottom
- 10,
228 pDrawItem
->rcItem
.left
, yCenter
,
231 SelectObject(pDrawItem
->hDC
, hBlueBrush
);
233 pDrawItem
->rcItem
.left
, pDrawItem
->rcItem
.top
,
234 pDrawItem
->rcItem
.right
, pDrawItem
->rcItem
.bottom
- 10,
236 pDrawItem
->rcItem
.left
, yCenter
);
237 SelectObject(pDrawItem
->hDC
, hbrOld
);
239 HPEN hOldPen
= (HPEN
)SelectObject(pDrawItem
->hDC
, hDarkMagPen
);
240 for (INT x
= pDrawItem
->rcItem
.left
; x
< pDrawItem
->rcItem
.right
; ++x
)
242 if (m_FreeSpacePerc
< 50 && x
== xRadial
)
243 SelectObject(pDrawItem
->hDC
, hDarkBluePen
);
245 double cos_val
= (x
- xCenter
)*2.0f
/cx
;
246 INT y
= yCenter
+(INT
)(sin(acos(cos_val
))*cy
/2);
247 MoveToEx(pDrawItem
->hDC
, x
, y
, NULL
);
248 LineTo(pDrawItem
->hDC
, x
, y
+ 10);
250 SelectObject(pDrawItem
->hDC
, hOldPen
);
252 DeleteObject(hBlueBrush
);
253 DeleteObject(hMagBrush
);
254 DeleteObject(hDarkBluePen
);
255 DeleteObject(hDarkMagPen
);
260 CDrvDefExt::InitGeneralPage(HWND hwndDlg
)
262 WCHAR wszVolumeName
[MAX_PATH
+1] = {0};
263 WCHAR wszFileSystem
[MAX_PATH
+1] = {0};
267 bRet
= GetVolumeInformationW(m_wszDrive
, wszVolumeName
, _countof(wszVolumeName
), NULL
, NULL
, NULL
, wszFileSystem
, _countof(wszFileSystem
));
270 /* Set volume label and filesystem */
271 SetDlgItemTextW(hwndDlg
, 14000, wszVolumeName
);
272 SetDlgItemTextW(hwndDlg
, 14002, wszFileSystem
);
275 /* Set drive type and icon */
276 UINT DriveType
= GetDriveTypeW(m_wszDrive
);
277 UINT IconId
, TypeStrId
= 0;
280 case DRIVE_CDROM
: IconId
= IDI_SHELL_CDROM
; TypeStrId
= IDS_DRIVE_CDROM
; break;
281 case DRIVE_REMOVABLE
: IconId
= IDI_SHELL_FLOPPY
; break;
282 case DRIVE_RAMDISK
: IconId
= IDI_SHELL_RAMDISK
; break;
283 default: IconId
= IDI_SHELL_DRIVE
; TypeStrId
= IDS_DRIVE_FIXED
;
285 HICON hIcon
= (HICON
)LoadImage(shell32_hInstance
, MAKEINTRESOURCE(IconId
), IMAGE_ICON
, 32, 32, LR_SHARED
);
287 SendDlgItemMessageW(hwndDlg
, 14016, STM_SETICON
, (WPARAM
)hIcon
, 0);
288 if (TypeStrId
&& LoadStringW(shell32_hInstance
, TypeStrId
, wszBuf
, _countof(wszBuf
)))
289 SetDlgItemTextW(hwndDlg
, 14001, wszBuf
);
291 ULARGE_INTEGER FreeBytesAvailable
, TotalNumberOfBytes
;
292 if(GetDiskFreeSpaceExW(m_wszDrive
, &FreeBytesAvailable
, &TotalNumberOfBytes
, NULL
))
294 /* Init free space percentage used for drawing piechart */
295 m_FreeSpacePerc
= (UINT
)(FreeBytesAvailable
.QuadPart
* 100ull / TotalNumberOfBytes
.QuadPart
);
298 if (SH_FormatByteSize(TotalNumberOfBytes
.QuadPart
- FreeBytesAvailable
.QuadPart
, wszBuf
, _countof(wszBuf
)))
299 SetDlgItemTextW(hwndDlg
, 14003, wszBuf
);
301 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
- FreeBytesAvailable
.QuadPart
, wszBuf
, _countof(wszBuf
)))
302 SetDlgItemTextW(hwndDlg
, 14004, wszBuf
);
305 if (SH_FormatByteSize(FreeBytesAvailable
.QuadPart
, wszBuf
, _countof(wszBuf
)))
306 SetDlgItemTextW(hwndDlg
, 14005, wszBuf
);
308 if (StrFormatByteSizeW(FreeBytesAvailable
.QuadPart
, wszBuf
, _countof(wszBuf
)))
309 SetDlgItemTextW(hwndDlg
, 14006, wszBuf
);
312 if (SH_FormatByteSize(TotalNumberOfBytes
.QuadPart
, wszBuf
, _countof(wszBuf
)))
313 SetDlgItemTextW(hwndDlg
, 14007, wszBuf
);
315 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, wszBuf
, _countof(wszBuf
)))
316 SetDlgItemTextW(hwndDlg
, 14008, wszBuf
);
319 /* Set drive description */
321 GetDlgItemTextW(hwndDlg
, 14009, wszFormat
, _countof(wszFormat
));
322 swprintf(wszBuf
, wszFormat
, m_wszDrive
[0]);
323 SetDlgItemTextW(hwndDlg
, 14009, wszBuf
);
327 CDrvDefExt::GeneralPageProc(
337 LPPROPSHEETPAGEW ppsp
= (LPPROPSHEETPAGEW
)lParam
;
341 CDrvDefExt
*pDrvDefExt
= (CDrvDefExt
*)ppsp
->lParam
;
342 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)pDrvDefExt
);
343 pDrvDefExt
->InitGeneralPage(hwndDlg
);
348 LPDRAWITEMSTRUCT pDrawItem
= (LPDRAWITEMSTRUCT
)lParam
;
350 if (pDrawItem
->CtlID
>= 14013 && pDrawItem
->CtlID
<= 14015)
352 CDrvDefExt
*pDrvDefExt
= (CDrvDefExt
*)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
353 pDrvDefExt
->PaintStaticControls(hwndDlg
, pDrawItem
);
361 if (LOWORD(wParam
) == 14010) /* Disk Cleanup */
363 CDrvDefExt
*pDrvDefExt
= (CDrvDefExt
*)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
365 DWORD cbBuf
= sizeof(wszBuf
);
367 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
368 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\CleanupPath",
373 &cbBuf
) == ERROR_SUCCESS
)
375 WCHAR wszCmd
[MAX_PATH
];
377 StringCbPrintfW(wszCmd
, sizeof(wszCmd
), wszBuf
, pDrvDefExt
->m_wszDrive
[0]);
379 if (ShellExecuteW(hwndDlg
, NULL
, wszCmd
, NULL
, NULL
, SW_SHOW
) <= (HINSTANCE
)32)
380 ERR("Failed to create cleanup process %ls\n", wszCmd
);
383 else if (LOWORD(wParam
) == 14000) /* Label */
385 if (HIWORD(wParam
) == EN_CHANGE
)
386 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
390 if (((LPNMHDR
)lParam
)->hwndFrom
== GetParent(hwndDlg
))
393 LPPSHNOTIFY lppsn
= (LPPSHNOTIFY
)lParam
;
395 if (lppsn
->hdr
.code
== PSN_APPLY
)
397 CDrvDefExt
*pDrvDefExt
= (CDrvDefExt
*)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
400 if (GetDlgItemTextW(hwndDlg
, 14000, wszBuf
, _countof(wszBuf
)))
401 SetVolumeLabelW(pDrvDefExt
->m_wszDrive
, wszBuf
);
402 SetWindowLongPtr(hwndDlg
, DWL_MSGRESULT
, PSNRET_NOERROR
);
416 CDrvDefExt::ExtraPageProc(
426 LPPROPSHEETPAGEW ppsp
= (LPPROPSHEETPAGEW
)lParam
;
427 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)ppsp
->lParam
);
432 WCHAR wszBuf
[MAX_PATH
];
433 DWORD cbBuf
= sizeof(wszBuf
);
434 CDrvDefExt
*pDrvDefExt
= (CDrvDefExt
*)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
436 switch(LOWORD(wParam
))
439 DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_CHECK_DISK
), hwndDlg
, ChkDskDlg
, (LPARAM
)pDrvDefExt
->m_wszDrive
);
442 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
443 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath",
448 &cbBuf
) == ERROR_SUCCESS
)
450 WCHAR wszCmd
[MAX_PATH
];
452 StringCbPrintfW(wszCmd
, sizeof(wszCmd
), wszBuf
, pDrvDefExt
->m_wszDrive
[0]);
454 if (ShellExecuteW(hwndDlg
, NULL
, wszCmd
, NULL
, NULL
, SW_SHOW
) <= (HINSTANCE
)32)
455 ERR("Failed to create defrag process %ls\n", wszCmd
);
459 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
460 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath",
462 RRF_RT_REG_EXPAND_SZ
,
465 &cbBuf
) == ERROR_SUCCESS
)
467 if (ShellExecuteW(hwndDlg
, NULL
, wszBuf
, NULL
, NULL
, SW_SHOW
) <= (HINSTANCE
)32)
468 ERR("Failed to create backup process %ls\n", wszBuf
);
478 CDrvDefExt::HardwarePageProc(
484 UNREFERENCED_PARAMETER(lParam
);
485 UNREFERENCED_PARAMETER(wParam
);
491 GUID Guid
= GUID_DEVCLASS_DISKDRIVE
;
493 /* create the hardware page */
494 DeviceCreateHardwarePageEx(hwndDlg
, &Guid
, 1, HWPD_STANDARDLIST
);
502 CDrvDefExt::CDrvDefExt()
504 m_wszDrive
[0] = L
'\0';
507 CDrvDefExt::~CDrvDefExt()
513 CDrvDefExt::Initialize(LPCITEMIDLIST pidlFolder
, IDataObject
*pDataObj
, HKEY hkeyProgID
)
519 TRACE("%p %p %p %p\n", this, pidlFolder
, pDataObj
, hkeyProgID
);
524 format
.cfFormat
= CF_HDROP
;
526 format
.dwAspect
= DVASPECT_CONTENT
;
528 format
.tymed
= TYMED_HGLOBAL
;
530 hr
= pDataObj
->GetData(&format
, &stgm
);
534 if (!DragQueryFileW((HDROP
)stgm
.hGlobal
, 0, m_wszDrive
, _countof(m_wszDrive
)))
536 ERR("DragQueryFileW failed\n");
537 ReleaseStgMedium(&stgm
);
541 ReleaseStgMedium(&stgm
);
542 TRACE("Drive properties %ls\n", m_wszDrive
);
548 CDrvDefExt::QueryContextMenu(HMENU hmenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
555 CDrvDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
562 CDrvDefExt::GetCommandString(UINT_PTR idCmd
, UINT uType
, UINT
*pwReserved
, LPSTR pszName
, UINT cchMax
)
569 CDrvDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage
, LPARAM lParam
)
571 HPROPSHEETPAGE hPage
;
573 hPage
= SH_CreatePropertySheetPage(IDD_DRIVE_PROPERTIES
,
578 pfnAddPage(hPage
, lParam
);
580 if (GetDriveTypeW(m_wszDrive
) == DRIVE_FIXED
)
582 hPage
= SH_CreatePropertySheetPage(IDD_DRIVE_TOOLS
,
587 pfnAddPage(hPage
, lParam
);
590 hPage
= SH_CreatePropertySheetPage(IDD_DRIVE_HARDWARE
,
595 pfnAddPage(hPage
, lParam
);
601 CDrvDefExt::ReplacePage(UINT uPageID
, LPFNADDPROPSHEETPAGE pfnReplacePage
, LPARAM lParam
)
608 CDrvDefExt::SetSite(IUnknown
*punk
)
615 CDrvDefExt::GetSite(REFIID iid
, void **ppvSite
)