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
24 #define _USE_MATH_DEFINES
27 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
29 static const GUID GUID_DEVCLASS_DISKDRIVE
= {0x4d36e967L
, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
33 HWPD_STANDARDLIST
= 0,
35 HWPD_MAX
= HWPD_LARGELIST
36 } HWPAGE_DISPLAYMODE
, *PHWPAGE_DISPLAYMODE
;
39 DeviceCreateHardwarePageEx(HWND hWndParent
,
42 HWPAGE_DISPLAYMODE DisplayMode
);
43 UINT
SH_FormatByteSize(LONGLONG cbSize
, LPWSTR pwszResult
, UINT cchResultMax
);
46 GetDriveNameWithLetter(LPWSTR pwszText
, UINT cchTextMax
, LPCWSTR pwszDrive
)
48 DWORD dwMaxComp
, dwFileSys
;
51 if (GetVolumeInformationW(pwszDrive
, pwszText
, cchTextMax
, NULL
, &dwMaxComp
, &dwFileSys
, NULL
, 0))
53 cchText
= wcslen(pwszText
);
56 /* load default volume label */
57 cchText
= LoadStringW(shell32_hInstance
, IDS_DRIVE_FIXED
, pwszText
, cchTextMax
);
61 StringCchPrintfW(pwszText
+ cchText
, cchTextMax
- cchText
, L
" (%c)", pwszDrive
[0]);
65 InitializeChkDskDialog(HWND hwndDlg
, LPCWSTR pwszDrive
)
69 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (INT_PTR
)pwszDrive
);
71 Length
= GetWindowTextW(hwndDlg
, wszText
, sizeof(wszText
) / sizeof(WCHAR
));
72 wszText
[Length
] = L
' ';
73 GetDriveNameWithLetter(&wszText
[Length
+ 1], (sizeof(wszText
) / sizeof(WCHAR
)) - Length
- 1, pwszDrive
);
74 SetWindowText(hwndDlg
, wszText
);
77 static HWND hChkdskDrvDialog
= NULL
;
78 static BOOLEAN bChkdskSuccess
= FALSE
;
82 IN CALLBACKCOMMAND Command
,
91 Progress
= (PDWORD
)ActionInfo
;
92 SendDlgItemMessageW(hChkdskDrvDialog
, 14002, PBM_SETPOS
, (WPARAM
)*Progress
, 0);
95 pSuccess
= (PBOOLEAN
)ActionInfo
;
96 bChkdskSuccess
= (*pSuccess
);
100 case INSUFFICIENTRIGHTS
:
102 case CLUSTERSIZETOOSMALL
:
103 bChkdskSuccess
= FALSE
;
115 ChkDskNow(HWND hwndDlg
, LPCWSTR pwszDrive
)
117 //DWORD ClusterSize = 0;
119 ULARGE_INTEGER TotalNumberOfFreeBytes
, FreeBytesAvailableUser
;
120 BOOLEAN bCorrectErrors
= FALSE
, bScanDrive
= FALSE
;
122 if(!GetVolumeInformationW(pwszDrive
, NULL
, 0, NULL
, NULL
, NULL
, wszFs
, _countof(wszFs
)))
124 FIXME("failed to get drive fs type\n");
128 if (!GetDiskFreeSpaceExW(pwszDrive
, &FreeBytesAvailableUser
, &TotalNumberOfFreeBytes
, NULL
))
130 FIXME("failed to get drive space type\n");
134 /*if (!GetDefaultClusterSize(wszFs, &ClusterSize, &TotalNumberOfFreeBytes))
136 FIXME("invalid cluster size\n");
140 if (SendDlgItemMessageW(hwndDlg
, 14000, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
141 bCorrectErrors
= TRUE
;
143 if (SendDlgItemMessageW(hwndDlg
, 14001, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
146 hChkdskDrvDialog
= hwndDlg
;
147 bChkdskSuccess
= FALSE
;
148 SendDlgItemMessageW(hwndDlg
, 14002, PBM_SETRANGE
, 0, MAKELPARAM(0, 100));
149 Chkdsk((LPWSTR
)pwszDrive
, (LPWSTR
)wszFs
, bCorrectErrors
, TRUE
, FALSE
, bScanDrive
, NULL
, NULL
, ChkdskCallback
); // FIXME: casts
151 hChkdskDrvDialog
= NULL
;
152 bChkdskSuccess
= FALSE
;
155 static INT_PTR CALLBACK
165 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)lParam
);
166 InitializeChkDskDialog(hwndDlg
, (LPCWSTR
)lParam
);
169 switch(LOWORD(wParam
))
172 EndDialog(hwndDlg
, 0);
176 LPCWSTR pwszDrive
= (LPCWSTR
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
177 ChkDskNow(hwndDlg
, pwszDrive
);
188 CDrvDefExt::PaintStaticControls(HWND hwndDlg
, LPDRAWITEMSTRUCT pDrawItem
)
192 if (pDrawItem
->CtlID
== 14013)
194 hBrush
= CreateSolidBrush(RGB(0, 0, 255));
197 FillRect(pDrawItem
->hDC
, &pDrawItem
->rcItem
, hBrush
);
198 DeleteObject((HGDIOBJ
)hBrush
);
201 else if (pDrawItem
->CtlID
== 14014)
203 hBrush
= CreateSolidBrush(RGB(255, 0, 255));
206 FillRect(pDrawItem
->hDC
, &pDrawItem
->rcItem
, hBrush
);
207 DeleteObject((HGDIOBJ
)hBrush
);
210 else if (pDrawItem
->CtlID
== 14015)
212 HBRUSH hBlueBrush
= CreateSolidBrush(RGB(0, 0, 255));
213 HBRUSH hMagBrush
= CreateSolidBrush(RGB(255, 0, 255));
214 HPEN hDarkBluePen
= CreatePen(PS_SOLID
, 1, RGB(0, 0, 128));
215 HPEN hDarkMagPen
= CreatePen(PS_SOLID
, 1, RGB(128, 0, 128));
217 INT xCenter
= (pDrawItem
->rcItem
.left
+ pDrawItem
->rcItem
.right
)/2;
218 INT yCenter
= (pDrawItem
->rcItem
.top
+ pDrawItem
->rcItem
.bottom
- 10)/2;
219 INT cx
= pDrawItem
->rcItem
.right
- pDrawItem
->rcItem
.left
;
220 INT cy
= pDrawItem
->rcItem
.bottom
- pDrawItem
->rcItem
.top
- 10;
221 TRACE("FreeSpace %u a %f cx %d\n", m_FreeSpacePerc
, M_PI
+m_FreeSpacePerc
/100.0f
*M_PI
*2.0f
, cx
);
223 HBRUSH hbrOld
= (HBRUSH
)SelectObject(pDrawItem
->hDC
, hMagBrush
);
224 INT xRadial
= xCenter
+ (INT
)(cos(M_PI
+m_FreeSpacePerc
/100.0f
*M_PI
*2.0f
)*cx
/2);
225 INT yRadial
= yCenter
- (INT
)(sin(M_PI
+m_FreeSpacePerc
/100.0f
*M_PI
*2.0f
)*cy
/2);
227 pDrawItem
->rcItem
.left
, pDrawItem
->rcItem
.top
,
228 pDrawItem
->rcItem
.right
, pDrawItem
->rcItem
.bottom
- 10,
229 pDrawItem
->rcItem
.left
, yCenter
,
232 SelectObject(pDrawItem
->hDC
, hBlueBrush
);
234 pDrawItem
->rcItem
.left
, pDrawItem
->rcItem
.top
,
235 pDrawItem
->rcItem
.right
, pDrawItem
->rcItem
.bottom
- 10,
237 pDrawItem
->rcItem
.left
, yCenter
);
238 SelectObject(pDrawItem
->hDC
, hbrOld
);
240 HPEN hOldPen
= (HPEN
)SelectObject(pDrawItem
->hDC
, hDarkMagPen
);
241 for (INT x
= pDrawItem
->rcItem
.left
; x
< pDrawItem
->rcItem
.right
; ++x
)
243 if (m_FreeSpacePerc
< 50 && x
== xRadial
)
244 SelectObject(pDrawItem
->hDC
, hDarkBluePen
);
246 double cos_val
= (x
- xCenter
)*2.0f
/cx
;
247 INT y
= yCenter
+(INT
)(sin(acos(cos_val
))*cy
/2);
248 MoveToEx(pDrawItem
->hDC
, x
, y
, NULL
);
249 LineTo(pDrawItem
->hDC
, x
, y
+ 10);
251 SelectObject(pDrawItem
->hDC
, hOldPen
);
253 DeleteObject(hBlueBrush
);
254 DeleteObject(hMagBrush
);
255 DeleteObject(hDarkBluePen
);
256 DeleteObject(hDarkMagPen
);
261 CDrvDefExt::InitGeneralPage(HWND hwndDlg
)
263 WCHAR wszVolumeName
[MAX_PATH
+1] = {0};
264 WCHAR wszFileSystem
[MAX_PATH
+1] = {0};
268 bRet
= GetVolumeInformationW(m_wszDrive
, wszVolumeName
, _countof(wszVolumeName
), NULL
, NULL
, NULL
, wszFileSystem
, _countof(wszFileSystem
));
271 /* Set volume label and filesystem */
272 SetDlgItemTextW(hwndDlg
, 14000, wszVolumeName
);
273 SetDlgItemTextW(hwndDlg
, 14002, wszFileSystem
);
276 /* Set drive type and icon */
277 UINT DriveType
= GetDriveTypeW(m_wszDrive
);
278 UINT IconId
, TypeStrId
= 0;
281 case DRIVE_CDROM
: IconId
= IDI_SHELL_CDROM
; TypeStrId
= IDS_DRIVE_CDROM
; break;
282 case DRIVE_REMOVABLE
: IconId
= IDI_SHELL_FLOPPY
; break;
283 case DRIVE_RAMDISK
: IconId
= IDI_SHELL_RAMDISK
; break;
284 default: IconId
= IDI_SHELL_DRIVE
; TypeStrId
= IDS_DRIVE_FIXED
;
286 HICON hIcon
= (HICON
)LoadImage(shell32_hInstance
, MAKEINTRESOURCE(IconId
), IMAGE_ICON
, 32, 32, LR_SHARED
);
288 SendDlgItemMessageW(hwndDlg
, 14016, STM_SETICON
, (WPARAM
)hIcon
, 0);
289 if (TypeStrId
&& LoadStringW(shell32_hInstance
, TypeStrId
, wszBuf
, _countof(wszBuf
)))
290 SetDlgItemTextW(hwndDlg
, 14001, wszBuf
);
292 ULARGE_INTEGER FreeBytesAvailable
, TotalNumberOfBytes
;
293 if(GetDiskFreeSpaceExW(m_wszDrive
, &FreeBytesAvailable
, &TotalNumberOfBytes
, NULL
))
295 /* Init free space percentage used for drawing piechart */
296 m_FreeSpacePerc
= (UINT
)(FreeBytesAvailable
.QuadPart
* 100ull / TotalNumberOfBytes
.QuadPart
);
299 if (SH_FormatByteSize(TotalNumberOfBytes
.QuadPart
- FreeBytesAvailable
.QuadPart
, wszBuf
, _countof(wszBuf
)))
300 SetDlgItemTextW(hwndDlg
, 14003, wszBuf
);
302 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
- FreeBytesAvailable
.QuadPart
, wszBuf
, _countof(wszBuf
)))
303 SetDlgItemTextW(hwndDlg
, 14004, wszBuf
);
306 if (SH_FormatByteSize(FreeBytesAvailable
.QuadPart
, wszBuf
, _countof(wszBuf
)))
307 SetDlgItemTextW(hwndDlg
, 14005, wszBuf
);
309 if (StrFormatByteSizeW(FreeBytesAvailable
.QuadPart
, wszBuf
, _countof(wszBuf
)))
310 SetDlgItemTextW(hwndDlg
, 14006, wszBuf
);
313 if (SH_FormatByteSize(TotalNumberOfBytes
.QuadPart
, wszBuf
, _countof(wszBuf
)))
314 SetDlgItemTextW(hwndDlg
, 14007, wszBuf
);
316 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, wszBuf
, _countof(wszBuf
)))
317 SetDlgItemTextW(hwndDlg
, 14008, wszBuf
);
320 /* Set drive description */
322 GetDlgItemTextW(hwndDlg
, 14009, wszFormat
, _countof(wszFormat
));
323 swprintf(wszBuf
, wszFormat
, m_wszDrive
[0]);
324 SetDlgItemTextW(hwndDlg
, 14009, wszBuf
);
328 CDrvDefExt::GeneralPageProc(
338 LPPROPSHEETPAGEW ppsp
= (LPPROPSHEETPAGEW
)lParam
;
342 CDrvDefExt
*pDrvDefExt
= reinterpret_cast<CDrvDefExt
*>(ppsp
->lParam
);
343 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)pDrvDefExt
);
344 pDrvDefExt
->InitGeneralPage(hwndDlg
);
349 LPDRAWITEMSTRUCT pDrawItem
= (LPDRAWITEMSTRUCT
)lParam
;
351 if (pDrawItem
->CtlID
>= 14013 && pDrawItem
->CtlID
<= 14015)
353 CDrvDefExt
*pDrvDefExt
= reinterpret_cast<CDrvDefExt
*>(GetWindowLongPtr(hwndDlg
, DWLP_USER
));
354 pDrvDefExt
->PaintStaticControls(hwndDlg
, pDrawItem
);
362 if (LOWORD(wParam
) == 14010) /* Disk Cleanup */
364 CDrvDefExt
*pDrvDefExt
= reinterpret_cast<CDrvDefExt
*>(GetWindowLongPtr(hwndDlg
, DWLP_USER
));
366 DWORD cbBuf
= sizeof(wszBuf
);
368 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
369 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\CleanupPath",
374 &cbBuf
) == ERROR_SUCCESS
)
376 WCHAR wszCmd
[MAX_PATH
];
378 StringCbPrintfW(wszCmd
, sizeof(wszCmd
), wszBuf
, pDrvDefExt
->m_wszDrive
[0]);
380 if (ShellExecuteW(hwndDlg
, NULL
, wszCmd
, NULL
, NULL
, SW_SHOW
) <= (HINSTANCE
)32)
381 ERR("Failed to create cleanup process %ls\n", wszCmd
);
384 else if (LOWORD(wParam
) == 14000) /* Label */
386 if (HIWORD(wParam
) == EN_CHANGE
)
387 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
391 if (((LPNMHDR
)lParam
)->hwndFrom
== GetParent(hwndDlg
))
394 LPPSHNOTIFY lppsn
= (LPPSHNOTIFY
)lParam
;
396 if (lppsn
->hdr
.code
== PSN_APPLY
)
398 CDrvDefExt
*pDrvDefExt
= reinterpret_cast<CDrvDefExt
*>(GetWindowLongPtr(hwndDlg
, DWLP_USER
));
401 if (GetDlgItemTextW(hwndDlg
, 14000, wszBuf
, _countof(wszBuf
)))
402 SetVolumeLabelW(pDrvDefExt
->m_wszDrive
, wszBuf
);
403 SetWindowLongPtr(hwndDlg
, DWL_MSGRESULT
, PSNRET_NOERROR
);
417 CDrvDefExt::ExtraPageProc(
427 LPPROPSHEETPAGEW ppsp
= (LPPROPSHEETPAGEW
)lParam
;
428 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)ppsp
->lParam
);
433 WCHAR wszBuf
[MAX_PATH
];
434 DWORD cbBuf
= sizeof(wszBuf
);
435 CDrvDefExt
*pDrvDefExt
= reinterpret_cast<CDrvDefExt
*>(GetWindowLongPtr(hwndDlg
, DWLP_USER
));
437 switch(LOWORD(wParam
))
440 DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_CHECK_DISK
), hwndDlg
, ChkDskDlg
, (LPARAM
)pDrvDefExt
->m_wszDrive
);
443 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
444 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath",
449 &cbBuf
) == ERROR_SUCCESS
)
451 WCHAR wszCmd
[MAX_PATH
];
453 StringCbPrintfW(wszCmd
, sizeof(wszCmd
), wszBuf
, pDrvDefExt
->m_wszDrive
[0]);
455 if (ShellExecuteW(hwndDlg
, NULL
, wszCmd
, NULL
, NULL
, SW_SHOW
) <= (HINSTANCE
)32)
456 ERR("Failed to create defrag process %ls\n", wszCmd
);
460 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
461 L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath",
463 RRF_RT_REG_EXPAND_SZ
,
466 &cbBuf
) == ERROR_SUCCESS
)
468 if (ShellExecuteW(hwndDlg
, NULL
, wszBuf
, NULL
, NULL
, SW_SHOW
) <= (HINSTANCE
)32)
469 ERR("Failed to create backup process %ls\n", wszBuf
);
479 CDrvDefExt::HardwarePageProc(
485 UNREFERENCED_PARAMETER(lParam
);
486 UNREFERENCED_PARAMETER(wParam
);
492 GUID Guid
= GUID_DEVCLASS_DISKDRIVE
;
494 /* create the hardware page */
495 DeviceCreateHardwarePageEx(hwndDlg
, &Guid
, 1, HWPD_STANDARDLIST
);
503 CDrvDefExt::CDrvDefExt()
505 m_wszDrive
[0] = L
'\0';
508 CDrvDefExt::~CDrvDefExt()
514 CDrvDefExt::Initialize(LPCITEMIDLIST pidlFolder
, IDataObject
*pDataObj
, HKEY hkeyProgID
)
520 TRACE("%p %p %p %p\n", this, pidlFolder
, pDataObj
, hkeyProgID
);
525 format
.cfFormat
= CF_HDROP
;
527 format
.dwAspect
= DVASPECT_CONTENT
;
529 format
.tymed
= TYMED_HGLOBAL
;
531 hr
= pDataObj
->GetData(&format
, &stgm
);
535 if (!DragQueryFileW((HDROP
)stgm
.hGlobal
, 0, m_wszDrive
, _countof(m_wszDrive
)))
537 ERR("DragQueryFileW failed\n");
538 ReleaseStgMedium(&stgm
);
542 ReleaseStgMedium(&stgm
);
543 TRACE("Drive properties %ls\n", m_wszDrive
);
549 CDrvDefExt::QueryContextMenu(HMENU hmenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
556 CDrvDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
563 CDrvDefExt::GetCommandString(UINT_PTR idCmd
, UINT uType
, UINT
*pwReserved
, LPSTR pszName
, UINT cchMax
)
570 CDrvDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage
, LPARAM lParam
)
572 HPROPSHEETPAGE hPage
;
574 hPage
= SH_CreatePropertySheetPage(IDD_DRIVE_PROPERTIES
,
579 pfnAddPage(hPage
, lParam
);
581 if (GetDriveTypeW(m_wszDrive
) == DRIVE_FIXED
)
583 hPage
= SH_CreatePropertySheetPage(IDD_DRIVE_TOOLS
,
588 pfnAddPage(hPage
, lParam
);
591 hPage
= SH_CreatePropertySheetPage(IDD_DRIVE_HARDWARE
,
596 pfnAddPage(hPage
, lParam
);
602 CDrvDefExt::ReplacePage(UINT uPageID
, LPFNADDPROPSHEETPAGE pfnReplacePage
, LPARAM lParam
)
609 CDrvDefExt::SetSite(IUnknown
*punk
)
616 CDrvDefExt::GetSite(REFIID iid
, void **ppvSite
)