2 * Shell Library Functions
4 * Copyright 2005 Johannes Anderwald
5 * Copyright 2017 Katayama Hirofumi MZ
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #define MAX_PROPERTY_SHEET_PAGE 32
26 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
33 } FORMAT_DRIVE_CONTEXT
, *PFORMAT_DRIVE_CONTEXT
;
35 EXTERN_C HPSXA WINAPI
SHCreatePropSheetExtArrayEx(HKEY hKey
, LPCWSTR pszSubKey
, UINT max_iface
, IDataObject
*pDataObj
);
36 HPROPSHEETPAGE
SH_CreatePropertySheetPage(LPCSTR resname
, DLGPROC dlgproc
, LPARAM lParam
, LPWSTR szTitle
);
39 GetDefaultClusterSize(LPWSTR szFs
, PDWORD pClusterSize
, PULARGE_INTEGER TotalNumberOfBytes
)
43 if (!wcsicmp(szFs
, L
"FAT16") ||
44 !wcsicmp(szFs
, L
"FAT")) //REACTOS HACK
46 if (TotalNumberOfBytes
->QuadPart
<= (16 * 1024 * 1024))
48 else if (TotalNumberOfBytes
->QuadPart
<= (32 * 1024 * 1024))
50 else if (TotalNumberOfBytes
->QuadPart
<= (64 * 1024 * 1024))
52 else if (TotalNumberOfBytes
->QuadPart
<= (128 * 1024 * 1024))
54 else if (TotalNumberOfBytes
->QuadPart
<= (256 * 1024 * 1024))
56 else if (TotalNumberOfBytes
->QuadPart
<= (512 * 1024 * 1024))
58 else if (TotalNumberOfBytes
->QuadPart
<= (1024 * 1024 * 1024))
60 else if (TotalNumberOfBytes
->QuadPart
<= (2048LL * 1024LL * 1024LL))
62 else if (TotalNumberOfBytes
->QuadPart
<= (4096LL * 1024LL * 1024LL))
67 else if (!wcsicmp(szFs
, L
"FAT32"))
69 if (TotalNumberOfBytes
->QuadPart
<= (64 * 1024 * 1024))
71 else if (TotalNumberOfBytes
->QuadPart
<= (128 * 1024 * 1024))
73 else if (TotalNumberOfBytes
->QuadPart
<= (256 * 1024 * 1024))
75 else if (TotalNumberOfBytes
->QuadPart
<= (8192LL * 1024LL * 1024LL))
77 else if (TotalNumberOfBytes
->QuadPart
<= (16384LL * 1024LL * 1024LL))
79 else if (TotalNumberOfBytes
->QuadPart
<= (32768LL * 1024LL * 1024LL))
84 else if (!wcsicmp(szFs
, L
"NTFS"))
86 if (TotalNumberOfBytes
->QuadPart
<= (512 * 1024 * 1024))
88 else if (TotalNumberOfBytes
->QuadPart
<= (1024 * 1024 * 1024))
90 else if (TotalNumberOfBytes
->QuadPart
<= (2048LL * 1024LL * 1024LL))
95 else if (!wcsicmp(szFs
, L
"EXT2"))
97 // auto block size calculation
100 else if (!wcsicmp(szFs
, L
"BtrFS"))
102 // auto block size calculation
108 *pClusterSize
= ClusterSize
;
113 AddPropSheetPageCallback(HPROPSHEETPAGE hPage
, LPARAM lParam
)
115 PROPSHEETHEADER
*ppsh
= (PROPSHEETHEADER
*)lParam
;
116 if (ppsh
->nPages
< MAX_PROPERTY_SHEET_PAGE
)
118 ppsh
->phpage
[ppsh
->nPages
++] = hPage
;
124 typedef struct _DRIVE_PROP_PAGE
132 SH_ShowDriveProperties(WCHAR
*pwszDrive
, LPCITEMIDLIST pidlFolder
, PCUITEMID_CHILD_ARRAY apidl
)
135 HPROPSHEETPAGE hpsp
[MAX_PROPERTY_SHEET_PAGE
];
136 PROPSHEETHEADERW psh
;
137 CComObject
<CDrvDefExt
> *pDrvDefExt
= NULL
;
140 ZeroMemory(&psh
, sizeof(PROPSHEETHEADERW
));
141 psh
.dwSize
= sizeof(PROPSHEETHEADERW
);
142 psh
.dwFlags
= 0; // FIXME: make it modeless
143 psh
.hwndParent
= NULL
;
147 LPITEMIDLIST completePidl
= ILCombine(pidlFolder
, apidl
[0]);
149 return E_OUTOFMEMORY
;
151 if (ILGetDisplayNameExW(NULL
, completePidl
, wszName
, ILGDN_NORMAL
))
153 psh
.pszCaption
= wszName
;
154 psh
.dwFlags
|= PSH_PROPTITLE
;
157 ILFree(completePidl
);
159 CComPtr
<IDataObject
> pDataObj
;
160 HRESULT hr
= SHCreateDataObject(pidlFolder
, 1, apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
));
164 hr
= CComObject
<CDrvDefExt
>::CreateInstance(&pDrvDefExt
);
167 pDrvDefExt
->AddRef(); // CreateInstance returns object with 0 ref count
168 hr
= pDrvDefExt
->Initialize(pidlFolder
, pDataObj
, NULL
);
171 hr
= pDrvDefExt
->AddPages(AddPropSheetPageCallback
, (LPARAM
)&psh
);
173 ERR("AddPages failed\n");
175 ERR("Initialize failed\n");
178 hpsx
= SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT
, L
"Drive", MAX_PROPERTY_SHEET_PAGE
, pDataObj
);
180 SHAddFromPropSheetExtArray(hpsx
, (LPFNADDPROPSHEETPAGE
)AddPropSheetPageCallback
, (LPARAM
)&psh
);
183 // NOTE: Currently property sheet is modal. If we make it modeless, then it returns HWND.
184 INT_PTR ret
= PropertySheetW(&psh
);
187 SHDestroyPropSheetExtArray(hpsx
);
189 pDrvDefExt
->Release();
199 InsertDefaultClusterSizeForFs(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
201 WCHAR wszBuf
[100] = {0};
202 WCHAR szDrive
[] = L
"C:\\";
204 ULARGE_INTEGER FreeBytesAvailableUser
, TotalNumberOfBytes
;
209 hDlgCtrl
= GetDlgItem(hwndDlg
, 28677);
210 iSelIndex
= SendMessage(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
211 if (iSelIndex
== CB_ERR
)
214 if (SendMessageW(hDlgCtrl
, CB_GETLBTEXT
, iSelIndex
, (LPARAM
)wszBuf
) == CB_ERR
)
217 szDrive
[0] = pContext
->Drive
+ L
'A';
219 if (!GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailableUser
, &TotalNumberOfBytes
, NULL
))
222 if (!wcsicmp(wszBuf
, L
"FAT16") ||
223 !wcsicmp(wszBuf
, L
"FAT")) //REACTOS HACK
225 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
227 TRACE("FAT16 is not supported on hdd larger than 4G current %lu\n", TotalNumberOfBytes
.QuadPart
);
228 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
232 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
234 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
235 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
236 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
237 if (lIndex
!= CB_ERR
)
238 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
239 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
242 SendMessageW(GetDlgItem(hwndDlg
, 28675), BM_SETCHECK
, BST_UNCHECKED
, 0);
243 EnableWindow(GetDlgItem(hwndDlg
, 28675), FALSE
);
245 else if (!wcsicmp(wszBuf
, L
"FAT32"))
247 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
249 TRACE("FAT32 is not supported on hdd larger than 32G current %lu\n", TotalNumberOfBytes
.QuadPart
);
250 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
254 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
256 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
257 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
258 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
259 if (lIndex
!= CB_ERR
)
260 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
261 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
264 SendMessageW(GetDlgItem(hwndDlg
, 28675), BM_SETCHECK
, BST_UNCHECKED
, 0);
265 EnableWindow(GetDlgItem(hwndDlg
, 28675), FALSE
);
267 else if (!wcsicmp(wszBuf
, L
"NTFS"))
269 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
271 TRACE("NTFS is not supported on hdd larger than 2TB current %lu\n", TotalNumberOfBytes
.QuadPart
);
272 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
276 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
277 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
279 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
280 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
281 if (lIndex
!= CB_ERR
)
282 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
283 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
286 for (lIndex
= 0; lIndex
< 4; lIndex
++)
288 TotalNumberOfBytes
.QuadPart
= ClusterSize
;
289 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, wszBuf
, _countof(wszBuf
)))
291 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
292 if (lIndex
!= CB_ERR
)
293 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
298 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
300 else if (!wcsicmp(wszBuf
, L
"EXT2"))
302 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
304 TRACE("EXT2 is not supported on hdd larger than 32T current %lu\n", TotalNumberOfBytes
.QuadPart
);
305 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
309 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
311 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
312 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
313 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
314 if (lIndex
!= CB_ERR
)
315 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
316 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
319 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
321 else if (!wcsicmp(wszBuf
, L
"BtrFS"))
323 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
325 TRACE("BtrFS is not supported on hdd larger than 16E current %lu\n", TotalNumberOfBytes
.QuadPart
);
326 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
330 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
332 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
333 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
334 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
335 if (lIndex
!= CB_ERR
)
336 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
337 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
340 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
344 FIXME("unknown fs\n");
345 SendDlgItemMessageW(hwndDlg
, 28680, CB_RESETCONTENT
, iSelIndex
, 0);
351 InitializeFormatDriveDlg(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
354 WCHAR szDrive
[] = L
"C:\\";
355 WCHAR szFs
[30] = L
"";
357 ULARGE_INTEGER FreeBytesAvailableUser
, TotalNumberOfBytes
;
358 DWORD dwIndex
, dwDefault
;
359 UCHAR uMinor
, uMajor
;
361 HWND hwndFileSystems
;
363 cchText
= GetWindowTextW(hwndDlg
, szText
, _countof(szText
) - 1);
366 szText
[cchText
++] = L
' ';
367 szDrive
[0] = pContext
->Drive
+ L
'A';
368 if (GetVolumeInformationW(szDrive
, &szText
[cchText
], _countof(szText
) - cchText
, NULL
, NULL
, NULL
, szFs
, _countof(szFs
)))
370 if (szText
[cchText
] == UNICODE_NULL
)
372 /* load default volume label */
373 cchText
+= LoadStringW(shell32_hInstance
, IDS_DRIVE_FIXED
, &szText
[cchText
], _countof(szText
) - cchText
);
377 /* set volume label */
378 SetDlgItemTextW(hwndDlg
, 28679, &szText
[cchText
]);
379 cchText
+= wcslen(&szText
[cchText
]);
383 StringCchPrintfW(szText
+ cchText
, _countof(szText
) - cchText
, L
" (%c:)", szDrive
[0]);
385 /* set window text */
386 SetWindowTextW(hwndDlg
, szText
);
388 if (GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailableUser
, &TotalNumberOfBytes
, NULL
))
390 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, szText
, _countof(szText
)))
392 /* add drive capacity */
393 SendDlgItemMessageW(hwndDlg
, 28673, CB_ADDSTRING
, 0, (LPARAM
)szText
);
394 SendDlgItemMessageW(hwndDlg
, 28673, CB_SETCURSEL
, 0, (LPARAM
)0);
398 if (pContext
->Options
& SHFMT_OPT_FULL
)
400 /* check quick format button */
401 SendDlgItemMessageW(hwndDlg
, 28674, BM_SETCHECK
, BST_CHECKED
, 0);
404 /* enumerate all available filesystems */
407 hwndFileSystems
= GetDlgItem(hwndDlg
, 28677);
409 while(QueryAvailableFileSystemFormat(dwIndex
, szText
, &uMajor
, &uMinor
, &Latest
))
411 if (!wcsicmp(szText
, szFs
))
414 SendMessageW(hwndFileSystems
, CB_ADDSTRING
, 0, (LPARAM
)szText
);
420 ERR("no filesystem providers\n");
424 /* select default filesys */
425 SendMessageW(hwndFileSystems
, CB_SETCURSEL
, dwDefault
, 0);
426 /* setup cluster combo */
427 InsertDefaultClusterSizeForFs(hwndDlg
, pContext
);
428 /* hide progress control */
429 ShowWindow(GetDlgItem(hwndDlg
, 28678), SW_HIDE
);
432 static HWND FormatDrvDialog
= NULL
;
433 static BOOLEAN bSuccess
= FALSE
;
437 IN CALLBACKCOMMAND Command
,
446 Progress
= (PDWORD
)ActionInfo
;
447 SendDlgItemMessageW(FormatDrvDialog
, 28678, PBM_SETPOS
, (WPARAM
)*Progress
, 0);
450 pSuccess
= (PBOOLEAN
)ActionInfo
;
451 bSuccess
= (*pSuccess
);
455 case INSUFFICIENTRIGHTS
:
457 case CLUSTERSIZETOOSMALL
:
470 FormatDrive(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
472 WCHAR szDrive
[4] = { L
'C', ':', '\\', 0 };
473 WCHAR szFileSys
[40] = {0};
474 WCHAR szLabel
[40] = {0};
481 FMIFS_MEDIA_FLAG MediaFlag
= FMIFS_HARDDISK
;
483 /* set volume path */
484 szDrive
[0] = pContext
->Drive
+ L
'A';
487 hDlgCtrl
= GetDlgItem(hwndDlg
, 28677);
488 iSelIndex
= SendMessageW(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
489 if (iSelIndex
== CB_ERR
)
494 Length
= SendMessageW(hDlgCtrl
, CB_GETLBTEXTLEN
, iSelIndex
, 0);
495 if ((int)Length
== CB_ERR
|| Length
+ 1 > _countof(szFileSys
))
501 /* retrieve the file system */
502 SendMessageW(hDlgCtrl
, CB_GETLBTEXT
, iSelIndex
, (LPARAM
)szFileSys
);
503 szFileSys
[_countof(szFileSys
)-1] = L
'\0';
505 /* retrieve the volume label */
506 hDlgCtrl
= GetWindow(hwndDlg
, 28679);
507 Length
= SendMessageW(hDlgCtrl
, WM_GETTEXTLENGTH
, 0, 0);
508 if (Length
+ 1 > _countof(szLabel
))
513 SendMessageW(hDlgCtrl
, WM_GETTEXT
, _countof(szLabel
), (LPARAM
)szLabel
);
514 szLabel
[(sizeof(szLabel
)/sizeof(WCHAR
))-1] = L
'\0';
516 /* check for quickformat */
517 if (SendDlgItemMessageW(hwndDlg
, 28674, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
522 /* get the cluster size */
523 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
524 iSelIndex
= SendMessageW(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
525 if (iSelIndex
== CB_ERR
)
530 ClusterSize
= SendMessageW(hDlgCtrl
, CB_GETITEMDATA
, iSelIndex
, 0);
531 if ((int)ClusterSize
== CB_ERR
)
537 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
538 ShowWindow(hDlgCtrl
, SW_SHOW
);
539 SendMessageW(hDlgCtrl
, PBM_SETRANGE
, 0, MAKELPARAM(0, 100));
543 * will cause display problems
544 * when performing more than one format
546 FormatDrvDialog
= hwndDlg
;
548 /* See if the drive is removable or not */
549 DriveType
= GetDriveTypeW(szDrive
);
555 case DRIVE_NO_ROOT_DIR
:
561 case DRIVE_REMOVABLE
:
562 MediaFlag
= FMIFS_FLOPPY
;
567 MediaFlag
= FMIFS_HARDDISK
;
571 /* Format the drive */
580 ShowWindow(hDlgCtrl
, SW_HIDE
);
581 FormatDrvDialog
= NULL
;
584 pContext
->Result
= SHFMT_ERROR
;
586 else if (QuickFormat
)
588 pContext
->Result
= SHFMT_OPT_FULL
;
592 pContext
->Result
= FALSE
;
596 static INT_PTR CALLBACK
597 FormatDriveDlg(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
599 PFORMAT_DRIVE_CONTEXT pContext
;
604 InitializeFormatDriveDlg(hwndDlg
, (PFORMAT_DRIVE_CONTEXT
)lParam
);
605 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)lParam
);
608 switch(LOWORD(wParam
))
611 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
612 FormatDrive(hwndDlg
, pContext
);
615 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
616 EndDialog(hwndDlg
, pContext
->Result
);
618 case 28677: // filesystem combo
619 if (HIWORD(wParam
) == CBN_SELENDOK
)
621 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
622 InsertDefaultClusterSizeForFs(hwndDlg
, pContext
);
630 /*************************************************************************
631 * SHFormatDrive (SHELL32.@)
636 SHFormatDrive(HWND hwnd
, UINT drive
, UINT fmtID
, UINT options
)
638 FORMAT_DRIVE_CONTEXT Context
;
641 TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd
, drive
, fmtID
, options
);
643 Context
.Drive
= drive
;
644 Context
.Options
= options
;
646 result
= DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_FORMAT_DRIVE
), hwnd
, FormatDriveDlg
, (LPARAM
)&Context
);