2 * Shell Library Functions
4 * Copyright 2005 Johannes Anderwald
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #define MAX_PROPERTY_SHEET_PAGE 32
25 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
32 } FORMAT_DRIVE_CONTEXT
, *PFORMAT_DRIVE_CONTEXT
;
34 EXTERN_C HPSXA WINAPI
SHCreatePropSheetExtArrayEx(HKEY hKey
, LPCWSTR pszSubKey
, UINT max_iface
, IDataObject
*pDataObj
);
35 HPROPSHEETPAGE
SH_CreatePropertySheetPage(LPCSTR resname
, DLGPROC dlgproc
, LPARAM lParam
, LPWSTR szTitle
);
38 GetDefaultClusterSize(LPWSTR szFs
, PDWORD pClusterSize
, PULARGE_INTEGER TotalNumberOfBytes
)
42 if (!wcsicmp(szFs
, L
"FAT16") ||
43 !wcsicmp(szFs
, L
"FAT")) //REACTOS HACK
45 if (TotalNumberOfBytes
->QuadPart
<= (16 * 1024 * 1024))
47 else if (TotalNumberOfBytes
->QuadPart
<= (32 * 1024 * 1024))
49 else if (TotalNumberOfBytes
->QuadPart
<= (64 * 1024 * 1024))
51 else if (TotalNumberOfBytes
->QuadPart
<= (128 * 1024 * 1024))
53 else if (TotalNumberOfBytes
->QuadPart
<= (256 * 1024 * 1024))
55 else if (TotalNumberOfBytes
->QuadPart
<= (512 * 1024 * 1024))
57 else if (TotalNumberOfBytes
->QuadPart
<= (1024 * 1024 * 1024))
59 else if (TotalNumberOfBytes
->QuadPart
<= (2048LL * 1024LL * 1024LL))
61 else if (TotalNumberOfBytes
->QuadPart
<= (4096LL * 1024LL * 1024LL))
66 else if (!wcsicmp(szFs
, L
"FAT32"))
68 if (TotalNumberOfBytes
->QuadPart
<= (64 * 1024 * 1024))
70 else if (TotalNumberOfBytes
->QuadPart
<= (128 * 1024 * 1024))
72 else if (TotalNumberOfBytes
->QuadPart
<= (256 * 1024 * 1024))
74 else if (TotalNumberOfBytes
->QuadPart
<= (8192LL * 1024LL * 1024LL))
76 else if (TotalNumberOfBytes
->QuadPart
<= (16384LL * 1024LL * 1024LL))
78 else if (TotalNumberOfBytes
->QuadPart
<= (32768LL * 1024LL * 1024LL))
83 else if (!wcsicmp(szFs
, L
"NTFS"))
85 if (TotalNumberOfBytes
->QuadPart
<= (512 * 1024 * 1024))
87 else if (TotalNumberOfBytes
->QuadPart
<= (1024 * 1024 * 1024))
89 else if (TotalNumberOfBytes
->QuadPart
<= (2048LL * 1024LL * 1024LL))
94 else if (!wcsicmp(szFs
, L
"EXT2"))
96 // auto block size calculation
99 else if (!wcsicmp(szFs
, L
"BtrFS"))
101 // auto block size calculation
107 *pClusterSize
= ClusterSize
;
112 AddPropSheetPageCallback(HPROPSHEETPAGE hPage
, LPARAM lParam
)
114 PROPSHEETHEADER
*ppsh
= (PROPSHEETHEADER
*)lParam
;
115 if (ppsh
->nPages
< MAX_PROPERTY_SHEET_PAGE
)
117 ppsh
->phpage
[ppsh
->nPages
++] = hPage
;
123 typedef struct _DRIVE_PROP_PAGE
131 SH_ShowDriveProperties(WCHAR
*pwszDrive
, LPCITEMIDLIST pidlFolder
, PCUITEMID_CHILD_ARRAY apidl
)
134 HPROPSHEETPAGE hpsp
[MAX_PROPERTY_SHEET_PAGE
];
135 PROPSHEETHEADERW psh
;
136 CComObject
<CDrvDefExt
> *pDrvDefExt
= NULL
;
139 ZeroMemory(&psh
, sizeof(PROPSHEETHEADERW
));
140 psh
.dwSize
= sizeof(PROPSHEETHEADERW
);
141 psh
.dwFlags
= 0; // FIXME: make it modeless
142 psh
.hwndParent
= NULL
;
146 LPITEMIDLIST completePidl
= ILCombine(pidlFolder
, apidl
[0]);
150 if (ILGetDisplayNameExW(NULL
, completePidl
, wszName
, ILGDN_NORMAL
))
152 psh
.pszCaption
= wszName
;
153 psh
.dwFlags
|= PSH_PROPTITLE
;
156 ILFree(completePidl
);
158 CComPtr
<IDataObject
> pDataObj
;
159 HRESULT hr
= SHCreateDataObject(pidlFolder
, 1, apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
));
163 hr
= CComObject
<CDrvDefExt
>::CreateInstance(&pDrvDefExt
);
166 pDrvDefExt
->AddRef(); // CreateInstance returns object with 0 ref count
167 hr
= pDrvDefExt
->Initialize(pidlFolder
, pDataObj
, NULL
);
170 hr
= pDrvDefExt
->AddPages(AddPropSheetPageCallback
, (LPARAM
)&psh
);
172 ERR("AddPages failed\n");
174 ERR("Initialize failed\n");
177 hpsx
= SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT
, L
"Drive", MAX_PROPERTY_SHEET_PAGE
, pDataObj
);
179 SHAddFromPropSheetExtArray(hpsx
, (LPFNADDPROPSHEETPAGE
)AddPropSheetPageCallback
, (LPARAM
)&psh
);
182 HWND hwnd
= (HWND
)PropertySheetW(&psh
);
185 SHDestroyPropSheetExtArray(hpsx
);
187 pDrvDefExt
->Release();
195 InsertDefaultClusterSizeForFs(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
197 WCHAR wszBuf
[100] = {0};
198 WCHAR szDrive
[] = L
"C:\\";
200 ULARGE_INTEGER FreeBytesAvailableUser
, TotalNumberOfBytes
;
205 hDlgCtrl
= GetDlgItem(hwndDlg
, 28677);
206 iSelIndex
= SendMessage(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
207 if (iSelIndex
== CB_ERR
)
210 if (SendMessageW(hDlgCtrl
, CB_GETLBTEXT
, iSelIndex
, (LPARAM
)wszBuf
) == CB_ERR
)
213 szDrive
[0] = pContext
->Drive
+ L
'A';
215 if (!GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailableUser
, &TotalNumberOfBytes
, NULL
))
218 if (!wcsicmp(wszBuf
, L
"FAT16") ||
219 !wcsicmp(wszBuf
, L
"FAT")) //REACTOS HACK
221 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
223 TRACE("FAT16 is not supported on hdd larger than 4G current %lu\n", TotalNumberOfBytes
.QuadPart
);
224 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
228 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
230 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
231 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
232 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
233 if (lIndex
!= CB_ERR
)
234 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
235 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
238 SendMessageW(GetDlgItem(hwndDlg
, 28675), BM_SETCHECK
, BST_UNCHECKED
, 0);
239 EnableWindow(GetDlgItem(hwndDlg
, 28675), FALSE
);
241 else if (!wcsicmp(wszBuf
, L
"FAT32"))
243 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
245 TRACE("FAT32 is not supported on hdd larger than 32G current %lu\n", TotalNumberOfBytes
.QuadPart
);
246 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
250 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
252 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
253 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
254 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
255 if (lIndex
!= CB_ERR
)
256 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
257 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
260 SendMessageW(GetDlgItem(hwndDlg
, 28675), BM_SETCHECK
, BST_UNCHECKED
, 0);
261 EnableWindow(GetDlgItem(hwndDlg
, 28675), FALSE
);
263 else if (!wcsicmp(wszBuf
, L
"NTFS"))
265 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
267 TRACE("NTFS is not supported on hdd larger than 2TB current %lu\n", TotalNumberOfBytes
.QuadPart
);
268 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
272 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
273 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
275 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
276 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
277 if (lIndex
!= CB_ERR
)
278 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
279 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
282 for (lIndex
= 0; lIndex
< 4; lIndex
++)
284 TotalNumberOfBytes
.QuadPart
= ClusterSize
;
285 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, wszBuf
, _countof(wszBuf
)))
287 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
288 if (lIndex
!= CB_ERR
)
289 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
294 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
296 else if (!wcsicmp(wszBuf
, L
"EXT2"))
298 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
300 TRACE("EXT2 is not supported on hdd larger than 32T current %lu\n", TotalNumberOfBytes
.QuadPart
);
301 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
305 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
307 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
308 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
309 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
310 if (lIndex
!= CB_ERR
)
311 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
312 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
315 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
317 else if (!wcsicmp(wszBuf
, L
"BtrFS"))
319 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
321 TRACE("BtrFS is not supported on hdd larger than 16E current %lu\n", TotalNumberOfBytes
.QuadPart
);
322 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
326 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, _countof(wszBuf
)))
328 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
329 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
330 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
331 if (lIndex
!= CB_ERR
)
332 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
333 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
336 EnableWindow(GetDlgItem(hwndDlg
, 28675), TRUE
);
340 FIXME("unknown fs\n");
341 SendDlgItemMessageW(hwndDlg
, 28680, CB_RESETCONTENT
, iSelIndex
, 0);
347 InitializeFormatDriveDlg(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
350 WCHAR szDrive
[] = L
"C:\\";
351 WCHAR szFs
[30] = L
"";
353 ULARGE_INTEGER FreeBytesAvailableUser
, TotalNumberOfBytes
;
354 DWORD dwIndex
, dwDefault
;
355 UCHAR uMinor
, uMajor
;
357 HWND hwndFileSystems
;
359 cchText
= GetWindowTextW(hwndDlg
, szText
, _countof(szText
) - 1);
362 szText
[cchText
++] = L
' ';
363 szDrive
[0] = pContext
->Drive
+ L
'A';
364 if (GetVolumeInformationW(szDrive
, &szText
[cchText
], _countof(szText
) - cchText
, NULL
, NULL
, NULL
, szFs
, _countof(szFs
)))
366 if (szText
[cchText
] == UNICODE_NULL
)
368 /* load default volume label */
369 cchText
+= LoadStringW(shell32_hInstance
, IDS_DRIVE_FIXED
, &szText
[cchText
], _countof(szText
) - cchText
);
373 /* set volume label */
374 SetDlgItemTextW(hwndDlg
, 28679, &szText
[cchText
]);
375 cchText
+= wcslen(&szText
[cchText
]);
379 StringCchPrintfW(szText
+ cchText
, _countof(szText
) - cchText
, L
" (%c:)", szDrive
[0]);
381 /* set window text */
382 SetWindowTextW(hwndDlg
, szText
);
384 if (GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailableUser
, &TotalNumberOfBytes
, NULL
))
386 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, szText
, _countof(szText
)))
388 /* add drive capacity */
389 SendDlgItemMessageW(hwndDlg
, 28673, CB_ADDSTRING
, 0, (LPARAM
)szText
);
390 SendDlgItemMessageW(hwndDlg
, 28673, CB_SETCURSEL
, 0, (LPARAM
)0);
394 if (pContext
->Options
& SHFMT_OPT_FULL
)
396 /* check quick format button */
397 SendDlgItemMessageW(hwndDlg
, 28674, BM_SETCHECK
, BST_CHECKED
, 0);
400 /* enumerate all available filesystems */
403 hwndFileSystems
= GetDlgItem(hwndDlg
, 28677);
405 while(QueryAvailableFileSystemFormat(dwIndex
, szText
, &uMajor
, &uMinor
, &Latest
))
407 if (!wcsicmp(szText
, szFs
))
410 SendMessageW(hwndFileSystems
, CB_ADDSTRING
, 0, (LPARAM
)szText
);
416 ERR("no filesystem providers\n");
420 /* select default filesys */
421 SendMessageW(hwndFileSystems
, CB_SETCURSEL
, dwDefault
, 0);
422 /* setup cluster combo */
423 InsertDefaultClusterSizeForFs(hwndDlg
, pContext
);
424 /* hide progress control */
425 ShowWindow(GetDlgItem(hwndDlg
, 28678), SW_HIDE
);
428 static HWND FormatDrvDialog
= NULL
;
429 static BOOLEAN bSuccess
= FALSE
;
433 IN CALLBACKCOMMAND Command
,
442 Progress
= (PDWORD
)ActionInfo
;
443 SendDlgItemMessageW(FormatDrvDialog
, 28678, PBM_SETPOS
, (WPARAM
)*Progress
, 0);
446 pSuccess
= (PBOOLEAN
)ActionInfo
;
447 bSuccess
= (*pSuccess
);
451 case INSUFFICIENTRIGHTS
:
453 case CLUSTERSIZETOOSMALL
:
466 FormatDrive(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
468 WCHAR szDrive
[4] = { L
'C', ':', '\\', 0 };
469 WCHAR szFileSys
[40] = {0};
470 WCHAR szLabel
[40] = {0};
477 FMIFS_MEDIA_FLAG MediaFlag
= FMIFS_HARDDISK
;
479 /* set volume path */
480 szDrive
[0] = pContext
->Drive
+ L
'A';
483 hDlgCtrl
= GetDlgItem(hwndDlg
, 28677);
484 iSelIndex
= SendMessageW(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
485 if (iSelIndex
== CB_ERR
)
490 Length
= SendMessageW(hDlgCtrl
, CB_GETLBTEXTLEN
, iSelIndex
, 0);
491 if ((int)Length
== CB_ERR
|| Length
+ 1 > _countof(szFileSys
))
497 /* retrieve the file system */
498 SendMessageW(hDlgCtrl
, CB_GETLBTEXT
, iSelIndex
, (LPARAM
)szFileSys
);
499 szFileSys
[_countof(szFileSys
)-1] = L
'\0';
501 /* retrieve the volume label */
502 hDlgCtrl
= GetWindow(hwndDlg
, 28679);
503 Length
= SendMessageW(hDlgCtrl
, WM_GETTEXTLENGTH
, 0, 0);
504 if (Length
+ 1 > _countof(szLabel
))
509 SendMessageW(hDlgCtrl
, WM_GETTEXT
, _countof(szLabel
), (LPARAM
)szLabel
);
510 szLabel
[(sizeof(szLabel
)/sizeof(WCHAR
))-1] = L
'\0';
512 /* check for quickformat */
513 if (SendDlgItemMessageW(hwndDlg
, 28674, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
518 /* get the cluster size */
519 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
520 iSelIndex
= SendMessageW(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
521 if (iSelIndex
== CB_ERR
)
526 ClusterSize
= SendMessageW(hDlgCtrl
, CB_GETITEMDATA
, iSelIndex
, 0);
527 if ((int)ClusterSize
== CB_ERR
)
533 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
534 ShowWindow(hDlgCtrl
, SW_SHOW
);
535 SendMessageW(hDlgCtrl
, PBM_SETRANGE
, 0, MAKELPARAM(0, 100));
539 * will cause display problems
540 * when performing more than one format
542 FormatDrvDialog
= hwndDlg
;
544 /* See if the drive is removable or not */
545 DriveType
= GetDriveTypeW(szDrive
);
551 case DRIVE_NO_ROOT_DIR
:
557 case DRIVE_REMOVABLE
:
558 MediaFlag
= FMIFS_FLOPPY
;
563 MediaFlag
= FMIFS_HARDDISK
;
567 /* Format the drive */
576 ShowWindow(hDlgCtrl
, SW_HIDE
);
577 FormatDrvDialog
= NULL
;
580 pContext
->Result
= SHFMT_ERROR
;
582 else if (QuickFormat
)
584 pContext
->Result
= SHFMT_OPT_FULL
;
588 pContext
->Result
= FALSE
;
592 static INT_PTR CALLBACK
593 FormatDriveDlg(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
595 PFORMAT_DRIVE_CONTEXT pContext
;
600 InitializeFormatDriveDlg(hwndDlg
, (PFORMAT_DRIVE_CONTEXT
)lParam
);
601 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)lParam
);
604 switch(LOWORD(wParam
))
607 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
608 FormatDrive(hwndDlg
, pContext
);
611 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
612 EndDialog(hwndDlg
, pContext
->Result
);
614 case 28677: // filesystem combo
615 if (HIWORD(wParam
) == CBN_SELENDOK
)
617 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
618 InsertDefaultClusterSizeForFs(hwndDlg
, pContext
);
626 /*************************************************************************
627 * SHFormatDrive (SHELL32.@)
632 SHFormatDrive(HWND hwnd
, UINT drive
, UINT fmtID
, UINT options
)
634 FORMAT_DRIVE_CONTEXT Context
;
637 TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd
, drive
, fmtID
, options
);
639 Context
.Drive
= drive
;
640 Context
.Options
= options
;
642 result
= DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_FORMAT_DRIVE
), hwnd
, FormatDriveDlg
, (LPARAM
)&Context
);