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 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
31 } FORMAT_DRIVE_CONTEXT
, *PFORMAT_DRIVE_CONTEXT
;
33 EXTERN_C HPSXA WINAPI
SHCreatePropSheetExtArrayEx(HKEY hKey
, LPCWSTR pszSubKey
, UINT max_iface
, IDataObject
*pDataObj
);
34 HPROPSHEETPAGE
SH_CreatePropertySheetPage(LPCSTR resname
, DLGPROC dlgproc
, LPARAM lParam
, LPWSTR szTitle
);
37 GetDefaultClusterSize(LPWSTR szFs
, PDWORD pClusterSize
, PULARGE_INTEGER TotalNumberOfBytes
)
41 if (!wcsicmp(szFs
, L
"FAT16") ||
42 !wcsicmp(szFs
, L
"FAT")) //REACTOS HACK
44 if (TotalNumberOfBytes
->QuadPart
<= (16 * 1024 * 1024))
46 else if (TotalNumberOfBytes
->QuadPart
<= (32 * 1024 * 1024))
48 else if (TotalNumberOfBytes
->QuadPart
<= (64 * 1024 * 1024))
50 else if (TotalNumberOfBytes
->QuadPart
<= (128 * 1024 * 1024))
52 else if (TotalNumberOfBytes
->QuadPart
<= (256 * 1024 * 1024))
54 else if (TotalNumberOfBytes
->QuadPart
<= (512 * 1024 * 1024))
56 else if (TotalNumberOfBytes
->QuadPart
<= (1024 * 1024 * 1024))
58 else if (TotalNumberOfBytes
->QuadPart
<= (2048LL * 1024LL * 1024LL))
60 else if (TotalNumberOfBytes
->QuadPart
<= (4096LL * 1024LL * 1024LL))
65 else if (!wcsicmp(szFs
, L
"FAT32"))
67 if (TotalNumberOfBytes
->QuadPart
<= (64 * 1024 * 1024))
69 else if (TotalNumberOfBytes
->QuadPart
<= (128 * 1024 * 1024))
71 else if (TotalNumberOfBytes
->QuadPart
<= (256 * 1024 * 1024))
73 else if (TotalNumberOfBytes
->QuadPart
<= (8192LL * 1024LL * 1024LL))
75 else if (TotalNumberOfBytes
->QuadPart
<= (16384LL * 1024LL * 1024LL))
77 else if (TotalNumberOfBytes
->QuadPart
<= (32768LL * 1024LL * 1024LL))
82 else if (!wcsicmp(szFs
, L
"NTFS"))
84 if (TotalNumberOfBytes
->QuadPart
<= (512 * 1024 * 1024))
86 else if (TotalNumberOfBytes
->QuadPart
<= (1024 * 1024 * 1024))
88 else if (TotalNumberOfBytes
->QuadPart
<= (2048LL * 1024LL * 1024LL))
93 else if (!wcsicmp(szFs
, L
"EXT2"))
95 // auto block size calculation
98 else if (!wcsicmp(szFs
, L
"BtrFS"))
100 // auto block size calculation
106 *pClusterSize
= ClusterSize
;
110 typedef struct _DRIVE_PROP_PAGE
118 SH_ShowDriveProperties(WCHAR
*pwszDrive
, LPCITEMIDLIST pidlFolder
, PCUITEMID_CHILD_ARRAY apidl
)
121 HPROPSHEETPAGE hpsp
[MAX_PROPERTY_SHEET_PAGE
];
122 PROPSHEETHEADERW psh
;
123 CComObject
<CDrvDefExt
> *pDrvDefExt
= NULL
;
126 ZeroMemory(&psh
, sizeof(PROPSHEETHEADERW
));
127 psh
.dwSize
= sizeof(PROPSHEETHEADERW
);
128 psh
.dwFlags
= 0; // FIXME: make it modeless
129 psh
.hwndParent
= NULL
;
133 LPITEMIDLIST completePidl
= ILCombine(pidlFolder
, apidl
[0]);
135 return E_OUTOFMEMORY
;
137 if (ILGetDisplayNameExW(NULL
, completePidl
, wszName
, ILGDN_NORMAL
))
139 psh
.pszCaption
= wszName
;
140 psh
.dwFlags
|= PSH_PROPTITLE
;
143 ILFree(completePidl
);
145 CComPtr
<IDataObject
> pDataObj
;
146 HRESULT hr
= SHCreateDataObject(pidlFolder
, 1, apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
));
150 hr
= CComObject
<CDrvDefExt
>::CreateInstance(&pDrvDefExt
);
153 pDrvDefExt
->AddRef(); // CreateInstance returns object with 0 ref count
154 hr
= pDrvDefExt
->Initialize(pidlFolder
, pDataObj
, NULL
);
157 hr
= pDrvDefExt
->AddPages(AddPropSheetPageCallback
, (LPARAM
)&psh
);
159 ERR("AddPages failed\n");
161 ERR("Initialize failed\n");
164 hpsx
= SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT
, L
"Drive", MAX_PROPERTY_SHEET_PAGE
, pDataObj
);
166 SHAddFromPropSheetExtArray(hpsx
, (LPFNADDPROPSHEETPAGE
)AddPropSheetPageCallback
, (LPARAM
)&psh
);
169 // NOTE: Currently property sheet is modal. If we make it modeless, then it returns HWND.
170 INT_PTR ret
= PropertySheetW(&psh
);
173 SHDestroyPropSheetExtArray(hpsx
);
175 pDrvDefExt
->Release();
185 InsertDefaultClusterSizeForFs(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
187 WCHAR wszBuf
[100] = {0};
188 WCHAR szDrive
[] = L
"C:\\";
190 ULARGE_INTEGER FreeBytesAvailableUser
, TotalNumberOfBytes
;
195 hDlgCtrl
= GetDlgItem(hwndDlg
, 28677);
196 iSelIndex
= SendMessage(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
197 if (iSelIndex
== CB_ERR
)
200 if (SendMessageW(hDlgCtrl
, CB_GETLBTEXT
, iSelIndex
, (LPARAM
)wszBuf
) == CB_ERR
)
203 szDrive
[0] = pContext
->Drive
+ L
'A';
205 if (!GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailableUser
, &TotalNumberOfBytes
, NULL
))
208 if (!wcsicmp(wszBuf
, L
"FAT16") ||
209 !wcsicmp(wszBuf
, L
"FAT")) //REACTOS HACK
211 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
213 TRACE("FAT16 is not supported on hdd larger than 4G current %lu\n", TotalNumberOfBytes
.QuadPart
);
214 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
218 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
220 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
221 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
222 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
223 if (lIndex
!= CB_ERR
)
224 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
225 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
228 SendMessageW(GetDlgItem(hwndDlg
, 28675), BM_SETCHECK
, BST_UNCHECKED
, 0);
229 EnableWindow(GetDlgItem(hwndDlg
, 28675), FALSE
);
231 else if (!wcsicmp(wszBuf
, L
"FAT32"))
233 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
235 TRACE("FAT32 is not supported on hdd larger than 32G current %lu\n", TotalNumberOfBytes
.QuadPart
);
236 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
240 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
242 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
243 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
244 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
245 if (lIndex
!= CB_ERR
)
246 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
247 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
250 SendMessageW(GetDlgItem(hwndDlg
, 28675), BM_SETCHECK
, BST_UNCHECKED
, 0);
251 EnableWindow(GetDlgItem(hwndDlg
, 28675), FALSE
);
253 else if (!wcsicmp(wszBuf
, L
"NTFS"))
255 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
257 TRACE("NTFS is not supported on hdd larger than 2TB current %lu\n", TotalNumberOfBytes
.QuadPart
);
258 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
262 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
263 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
265 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
266 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
267 if (lIndex
!= CB_ERR
)
268 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
269 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
272 for (lIndex
= 0; lIndex
< 4; lIndex
++)
274 TotalNumberOfBytes
.QuadPart
= ClusterSize
;
275 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, wszBuf
, _countof(wszBuf
)))
277 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
278 if (lIndex
!= CB_ERR
)
279 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
284 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
286 else if (!wcsicmp(wszBuf
, L
"EXT2"))
288 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
290 TRACE("EXT2 is not supported on hdd larger than 32T current %lu\n", TotalNumberOfBytes
.QuadPart
);
291 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
295 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
297 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
298 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
299 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
300 if (lIndex
!= CB_ERR
)
301 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
302 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
305 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
307 else if (!wcsicmp(wszBuf
, L
"BtrFS"))
309 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
311 TRACE("BtrFS is not supported on hdd larger than 16E current %lu\n", TotalNumberOfBytes
.QuadPart
);
312 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
316 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
318 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
319 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
320 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
321 if (lIndex
!= CB_ERR
)
322 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
323 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
326 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
330 FIXME("unknown fs\n");
331 SendDlgItemMessageW(hwndDlg
, 28680, CB_RESETCONTENT
, iSelIndex
, 0);
337 InitializeFormatDriveDlg(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
340 WCHAR szDrive
[] = L
"C:\\";
341 WCHAR szFs
[30] = L
"";
343 ULARGE_INTEGER FreeBytesAvailableUser
, TotalNumberOfBytes
;
344 DWORD dwIndex
, dwDefault
;
345 UCHAR uMinor
, uMajor
;
347 HWND hwndFileSystems
;
349 cchText
= GetWindowTextW(hwndDlg
, szText
, _countof(szText
) - 1);
352 szText
[cchText
++] = L
' ';
353 szDrive
[0] = pContext
->Drive
+ L
'A';
354 if (GetVolumeInformationW(szDrive
, &szText
[cchText
], _countof(szText
) - cchText
, NULL
, NULL
, NULL
, szFs
, _countof(szFs
)))
356 if (szText
[cchText
] == UNICODE_NULL
)
358 /* load default volume label */
359 cchText
+= LoadStringW(shell32_hInstance
, IDS_DRIVE_FIXED
, &szText
[cchText
], _countof(szText
) - cchText
);
363 /* set volume label */
364 SetDlgItemTextW(hwndDlg
, 28679, &szText
[cchText
]);
365 cchText
+= wcslen(&szText
[cchText
]);
369 StringCchPrintfW(szText
+ cchText
, _countof(szText
) - cchText
, L
" (%c:)", szDrive
[0]);
371 /* set window text */
372 SetWindowTextW(hwndDlg
, szText
);
374 if (GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailableUser
, &TotalNumberOfBytes
, NULL
))
376 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, szText
, _countof(szText
)))
378 /* add drive capacity */
379 SendDlgItemMessageW(hwndDlg
, 28673, CB_ADDSTRING
, 0, (LPARAM
)szText
);
380 SendDlgItemMessageW(hwndDlg
, 28673, CB_SETCURSEL
, 0, (LPARAM
)0);
384 if (pContext
->Options
& SHFMT_OPT_FULL
)
386 /* check quick format button */
387 SendDlgItemMessageW(hwndDlg
, 28674, BM_SETCHECK
, BST_CHECKED
, 0);
390 /* enumerate all available filesystems */
393 hwndFileSystems
= GetDlgItem(hwndDlg
, 28677);
395 while(QueryAvailableFileSystemFormat(dwIndex
, szText
, &uMajor
, &uMinor
, &Latest
))
397 if (!wcsicmp(szText
, szFs
))
400 SendMessageW(hwndFileSystems
, CB_ADDSTRING
, 0, (LPARAM
)szText
);
406 ERR("no filesystem providers\n");
410 /* select default filesys */
411 SendMessageW(hwndFileSystems
, CB_SETCURSEL
, dwDefault
, 0);
412 /* setup cluster combo */
413 InsertDefaultClusterSizeForFs(hwndDlg
, pContext
);
414 /* hide progress control */
415 ShowWindow(GetDlgItem(hwndDlg
, 28678), SW_HIDE
);
418 static HWND FormatDrvDialog
= NULL
;
419 static BOOLEAN bSuccess
= FALSE
;
423 IN CALLBACKCOMMAND Command
,
432 Progress
= (PDWORD
)ActionInfo
;
433 SendDlgItemMessageW(FormatDrvDialog
, 28678, PBM_SETPOS
, (WPARAM
)*Progress
, 0);
436 pSuccess
= (PBOOLEAN
)ActionInfo
;
437 bSuccess
= (*pSuccess
);
441 case INSUFFICIENTRIGHTS
:
443 case CLUSTERSIZETOOSMALL
:
456 FormatDrive(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
458 WCHAR szDrive
[4] = { L
'C', ':', '\\', 0 };
459 WCHAR szFileSys
[40] = {0};
460 WCHAR szLabel
[40] = {0};
467 FMIFS_MEDIA_FLAG MediaFlag
= FMIFS_HARDDISK
;
469 /* set volume path */
470 szDrive
[0] = pContext
->Drive
+ L
'A';
473 hDlgCtrl
= GetDlgItem(hwndDlg
, 28677);
474 iSelIndex
= SendMessageW(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
475 if (iSelIndex
== CB_ERR
)
480 Length
= SendMessageW(hDlgCtrl
, CB_GETLBTEXTLEN
, iSelIndex
, 0);
481 if ((int)Length
== CB_ERR
|| Length
+ 1 > _countof(szFileSys
))
487 /* retrieve the file system */
488 SendMessageW(hDlgCtrl
, CB_GETLBTEXT
, iSelIndex
, (LPARAM
)szFileSys
);
489 szFileSys
[_countof(szFileSys
)-1] = L
'\0';
491 /* retrieve the volume label */
492 hDlgCtrl
= GetWindow(hwndDlg
, 28679);
493 Length
= SendMessageW(hDlgCtrl
, WM_GETTEXTLENGTH
, 0, 0);
494 if (Length
+ 1 > _countof(szLabel
))
499 SendMessageW(hDlgCtrl
, WM_GETTEXT
, _countof(szLabel
), (LPARAM
)szLabel
);
500 szLabel
[(sizeof(szLabel
)/sizeof(WCHAR
))-1] = L
'\0';
502 /* check for quickformat */
503 if (SendDlgItemMessageW(hwndDlg
, 28674, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
508 /* get the cluster size */
509 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
510 iSelIndex
= SendMessageW(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
511 if (iSelIndex
== CB_ERR
)
516 ClusterSize
= SendMessageW(hDlgCtrl
, CB_GETITEMDATA
, iSelIndex
, 0);
517 if ((int)ClusterSize
== CB_ERR
)
523 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
524 ShowWindow(hDlgCtrl
, SW_SHOW
);
525 SendMessageW(hDlgCtrl
, PBM_SETRANGE
, 0, MAKELPARAM(0, 100));
529 * will cause display problems
530 * when performing more than one format
532 FormatDrvDialog
= hwndDlg
;
534 /* See if the drive is removable or not */
535 DriveType
= GetDriveTypeW(szDrive
);
541 case DRIVE_NO_ROOT_DIR
:
547 case DRIVE_REMOVABLE
:
548 MediaFlag
= FMIFS_FLOPPY
;
553 MediaFlag
= FMIFS_HARDDISK
;
557 /* Format the drive */
566 ShowWindow(hDlgCtrl
, SW_HIDE
);
567 FormatDrvDialog
= NULL
;
570 pContext
->Result
= SHFMT_ERROR
;
572 else if (QuickFormat
)
574 pContext
->Result
= SHFMT_OPT_FULL
;
578 pContext
->Result
= FALSE
;
582 static INT_PTR CALLBACK
583 FormatDriveDlg(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
585 PFORMAT_DRIVE_CONTEXT pContext
;
590 InitializeFormatDriveDlg(hwndDlg
, (PFORMAT_DRIVE_CONTEXT
)lParam
);
591 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)lParam
);
594 switch(LOWORD(wParam
))
597 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
598 FormatDrive(hwndDlg
, pContext
);
601 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
602 EndDialog(hwndDlg
, pContext
->Result
);
604 case 28677: // filesystem combo
605 if (HIWORD(wParam
) == CBN_SELENDOK
)
607 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
608 InsertDefaultClusterSizeForFs(hwndDlg
, pContext
);
616 /*************************************************************************
617 * SHFormatDrive (SHELL32.@)
622 SHFormatDrive(HWND hwnd
, UINT drive
, UINT fmtID
, UINT options
)
624 FORMAT_DRIVE_CONTEXT Context
;
627 TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd
, drive
, fmtID
, options
);
629 Context
.Drive
= drive
;
630 Context
.Options
= options
;
632 result
= DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_FORMAT_DRIVE
), hwnd
, FormatDriveDlg
, (LPARAM
)&Context
);