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))
97 *pClusterSize
= ClusterSize
;
102 AddPropSheetPageCallback(HPROPSHEETPAGE hPage
, LPARAM lParam
)
104 PROPSHEETHEADER
*ppsh
= (PROPSHEETHEADER
*)lParam
;
105 if (ppsh
->nPages
< MAX_PROPERTY_SHEET_PAGE
)
107 ppsh
->phpage
[ppsh
->nPages
++] = hPage
;
113 typedef struct _DRIVE_PROP_PAGE
121 SH_ShowDriveProperties(WCHAR
*pwszDrive
, LPCITEMIDLIST pidlFolder
, LPCITEMIDLIST
*apidl
)
124 HPROPSHEETPAGE hpsp
[MAX_PROPERTY_SHEET_PAGE
];
125 PROPSHEETHEADERW psh
;
126 CComObject
<CDrvDefExt
> *pDrvDefExt
= NULL
;
128 ZeroMemory(&psh
, sizeof(PROPSHEETHEADERW
));
129 psh
.dwSize
= sizeof(PROPSHEETHEADERW
);
130 psh
.dwFlags
= 0; // FIXME: make it modeless
131 psh
.hwndParent
= NULL
;
136 if (GetVolumeInformationW(pwszDrive
, wszName
, sizeof(wszName
) / sizeof(WCHAR
), NULL
, NULL
, NULL
, NULL
, 0))
138 psh
.pszCaption
= wszName
;
139 psh
.dwFlags
|= PSH_PROPTITLE
;
140 if (wszName
[0] == UNICODE_NULL
)
142 /* FIXME: check if disk is a really a local hdd */
143 UINT i
= LoadStringW(shell32_hInstance
, IDS_DRIVE_FIXED
, wszName
, sizeof(wszName
) / sizeof(WCHAR
) - 6);
144 StringCchPrintf(wszName
+ i
, sizeof(wszName
) / sizeof(WCHAR
) - i
, L
" (%s)", pwszDrive
);
148 CComPtr
<IDataObject
> pDataObj
;
149 HRESULT hr
= SHCreateDataObject(pidlFolder
, 1, apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
));
153 hr
= CComObject
<CDrvDefExt
>::CreateInstance(&pDrvDefExt
);
156 pDrvDefExt
->AddRef(); // CreateInstance returns object with 0 ref count
157 hr
= pDrvDefExt
->Initialize(pidlFolder
, pDataObj
, NULL
);
160 hr
= pDrvDefExt
->AddPages(AddPropSheetPageCallback
, (LPARAM
)&psh
);
162 ERR("AddPages failed\n");
164 ERR("Initialize failed\n");
167 hpsx
= SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT
, L
"Drive", MAX_PROPERTY_SHEET_PAGE
, pDataObj
);
169 SHAddFromPropSheetExtArray(hpsx
, (LPFNADDPROPSHEETPAGE
)AddPropSheetPageCallback
, (LPARAM
)&psh
);
172 HWND hwnd
= (HWND
)PropertySheetW(&psh
);
175 SHDestroyPropSheetExtArray(hpsx
);
177 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
+ '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
, sizeof(wszBuf
) / sizeof(WCHAR
)))
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 else if (!wcsicmp(wszBuf
, L
"FAT32"))
230 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
232 TRACE("FAT32 is not supported on hdd larger than 32G current %lu\n", TotalNumberOfBytes
.QuadPart
);
233 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
237 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, sizeof(wszBuf
) / sizeof(WCHAR
)))
239 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
240 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
241 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
242 if (lIndex
!= CB_ERR
)
243 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
244 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
247 else if (!wcsicmp(wszBuf
, L
"NTFS"))
249 if (!GetDefaultClusterSize(wszBuf
, &ClusterSize
, &TotalNumberOfBytes
))
251 TRACE("NTFS is not supported on hdd larger than 2TB current %lu\n", TotalNumberOfBytes
.QuadPart
);
252 SendMessageW(hDlgCtrl
, CB_DELETESTRING
, iSelIndex
, 0);
256 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
257 if (LoadStringW(shell32_hInstance
, IDS_DEFAULT_CLUSTER_SIZE
, wszBuf
, sizeof(wszBuf
) / sizeof(WCHAR
)))
259 SendMessageW(hDlgCtrl
, CB_RESETCONTENT
, 0, 0);
260 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
261 if (lIndex
!= CB_ERR
)
262 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
263 SendMessageW(hDlgCtrl
, CB_SETCURSEL
, 0, 0);
266 for (lIndex
= 0; lIndex
< 4; lIndex
++)
268 TotalNumberOfBytes
.QuadPart
= ClusterSize
;
269 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, wszBuf
, sizeof(wszBuf
) / sizeof(WCHAR
)))
271 lIndex
= SendMessageW(hDlgCtrl
, CB_ADDSTRING
, 0, (LPARAM
)wszBuf
);
272 if (lIndex
!= CB_ERR
)
273 SendMessageW(hDlgCtrl
, CB_SETITEMDATA
, lIndex
, (LPARAM
)ClusterSize
);
280 FIXME("unknown fs\n");
281 SendDlgItemMessageW(hwndDlg
, 28680, CB_RESETCONTENT
, iSelIndex
, 0);
287 InitializeFormatDriveDlg(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
290 WCHAR szDrive
[] = L
"C:\\";
291 WCHAR szFs
[30] = L
"";
293 ULARGE_INTEGER FreeBytesAvailableUser
, TotalNumberOfBytes
;
294 DWORD dwIndex
, dwDefault
;
295 UCHAR uMinor
, uMajor
;
297 HWND hwndFileSystems
;
299 cchText
= GetWindowTextW(hwndDlg
, szText
, sizeof(szText
) / sizeof(WCHAR
) - 1);
302 szText
[cchText
++] = L
' ';
303 szDrive
[0] = pContext
->Drive
+ L
'A';
304 if (GetVolumeInformationW(szDrive
, &szText
[cchText
], (sizeof(szText
) / sizeof(WCHAR
)) - cchText
, NULL
, NULL
, NULL
, szFs
, sizeof(szFs
) / sizeof(WCHAR
)))
306 if (szText
[cchText
] == UNICODE_NULL
)
308 /* load default volume label */
309 cchText
+= LoadStringW(shell32_hInstance
, IDS_DRIVE_FIXED
, &szText
[cchText
], (sizeof(szText
) / sizeof(WCHAR
)) - cchText
);
313 /* set volume label */
314 SetDlgItemTextW(hwndDlg
, 28679, &szText
[cchText
]);
315 cchText
+= wcslen(&szText
[cchText
]);
319 StringCchPrintfW(szText
+ cchText
, _countof(szText
) - cchText
, L
" (%c)", szDrive
[0]);
321 /* set window text */
322 SetWindowTextW(hwndDlg
, szText
);
324 if (GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailableUser
, &TotalNumberOfBytes
, NULL
))
326 if (StrFormatByteSizeW(TotalNumberOfBytes
.QuadPart
, szText
, sizeof(szText
) / sizeof(WCHAR
)))
328 /* add drive capacity */
329 SendDlgItemMessageW(hwndDlg
, 28673, CB_ADDSTRING
, 0, (LPARAM
)szText
);
330 SendDlgItemMessageW(hwndDlg
, 28673, CB_SETCURSEL
, 0, (LPARAM
)0);
334 if (pContext
->Options
& SHFMT_OPT_FULL
)
336 /* check quick format button */
337 SendDlgItemMessageW(hwndDlg
, 28674, BM_SETCHECK
, BST_CHECKED
, 0);
340 /* enumerate all available filesystems */
343 hwndFileSystems
= GetDlgItem(hwndDlg
, 28677);
345 while(QueryAvailableFileSystemFormat(dwIndex
, szText
, &uMajor
, &uMinor
, &Latest
))
347 if (!wcsicmp(szText
, szFs
))
350 SendMessageW(hwndFileSystems
, CB_ADDSTRING
, 0, (LPARAM
)szText
);
356 ERR("no filesystem providers\n");
360 /* select default filesys */
361 SendMessageW(hwndFileSystems
, CB_SETCURSEL
, dwDefault
, 0);
362 /* setup cluster combo */
363 InsertDefaultClusterSizeForFs(hwndDlg
, pContext
);
364 /* hide progress control */
365 ShowWindow(GetDlgItem(hwndDlg
, 28678), SW_HIDE
);
368 static HWND FormatDrvDialog
= NULL
;
369 static BOOLEAN bSuccess
= FALSE
;
373 IN CALLBACKCOMMAND Command
,
382 Progress
= (PDWORD
)ActionInfo
;
383 SendDlgItemMessageW(FormatDrvDialog
, 28678, PBM_SETPOS
, (WPARAM
)*Progress
, 0);
386 pSuccess
= (PBOOLEAN
)ActionInfo
;
387 bSuccess
= (*pSuccess
);
391 case INSUFFICIENTRIGHTS
:
393 case CLUSTERSIZETOOSMALL
:
406 FormatDrive(HWND hwndDlg
, PFORMAT_DRIVE_CONTEXT pContext
)
408 WCHAR szDrive
[4] = { L
'C', ':', '\\', 0 };
409 WCHAR szFileSys
[40] = {0};
410 WCHAR szLabel
[40] = {0};
417 /* set volume path */
418 szDrive
[0] = pContext
->Drive
;
421 hDlgCtrl
= GetDlgItem(hwndDlg
, 28677);
422 iSelIndex
= SendMessageW(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
423 if (iSelIndex
== CB_ERR
)
428 Length
= SendMessageW(hDlgCtrl
, CB_GETLBTEXTLEN
, iSelIndex
, 0);
429 if ((int)Length
== CB_ERR
|| Length
+ 1 > sizeof(szFileSys
) / sizeof(WCHAR
))
435 /* retrieve the file system */
436 SendMessageW(hDlgCtrl
, CB_GETLBTEXT
, iSelIndex
, (LPARAM
)szFileSys
);
437 szFileSys
[(sizeof(szFileSys
)/sizeof(WCHAR
))-1] = L
'\0';
439 /* retrieve the volume label */
440 hDlgCtrl
= GetWindow(hwndDlg
, 28679);
441 Length
= SendMessageW(hDlgCtrl
, WM_GETTEXTLENGTH
, 0, 0);
442 if (Length
+ 1 > sizeof(szLabel
) / sizeof(WCHAR
))
447 SendMessageW(hDlgCtrl
, WM_GETTEXT
, sizeof(szLabel
) / sizeof(WCHAR
), (LPARAM
)szLabel
);
448 szLabel
[(sizeof(szLabel
)/sizeof(WCHAR
))-1] = L
'\0';
450 /* check for quickformat */
451 if (SendDlgItemMessageW(hwndDlg
, 28674, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
456 /* get the cluster size */
457 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
458 iSelIndex
= SendMessageW(hDlgCtrl
, CB_GETCURSEL
, 0, 0);
459 if (iSelIndex
== CB_ERR
)
464 ClusterSize
= SendMessageW(hDlgCtrl
, CB_GETITEMDATA
, iSelIndex
, 0);
465 if ((int)ClusterSize
== CB_ERR
)
471 hDlgCtrl
= GetDlgItem(hwndDlg
, 28680);
472 ShowWindow(hDlgCtrl
, SW_SHOW
);
473 SendMessageW(hDlgCtrl
, PBM_SETRANGE
, 0, MAKELPARAM(0, 100));
477 * will cause display problems
478 * when performing more than one format
480 FormatDrvDialog
= hwndDlg
;
483 FMIFS_HARDDISK
, /* FIXME */
490 ShowWindow(hDlgCtrl
, SW_HIDE
);
491 FormatDrvDialog
= NULL
;
494 pContext
->Result
= SHFMT_ERROR
;
496 else if (QuickFormat
)
498 pContext
->Result
= SHFMT_OPT_FULL
;
502 pContext
->Result
= FALSE
;
506 static INT_PTR CALLBACK
507 FormatDriveDlg(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
509 PFORMAT_DRIVE_CONTEXT pContext
;
514 InitializeFormatDriveDlg(hwndDlg
, (PFORMAT_DRIVE_CONTEXT
)lParam
);
515 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)lParam
);
518 switch(LOWORD(wParam
))
521 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
522 FormatDrive(hwndDlg
, pContext
);
525 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
526 EndDialog(hwndDlg
, pContext
->Result
);
528 case 28677: // filesystem combo
529 if (HIWORD(wParam
) == CBN_SELENDOK
)
531 pContext
= (PFORMAT_DRIVE_CONTEXT
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
532 InsertDefaultClusterSizeForFs(hwndDlg
, pContext
);
540 /*************************************************************************
541 * SHFormatDrive (SHELL32.@)
546 SHFormatDrive(HWND hwnd
, UINT drive
, UINT fmtID
, UINT options
)
548 FORMAT_DRIVE_CONTEXT Context
;
551 TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd
, drive
, fmtID
, options
);
553 Context
.Drive
= drive
;
554 Context
.Options
= options
;
556 result
= DialogBoxParamW(shell32_hInstance
, MAKEINTRESOURCEW(IDD_FORMAT_DRIVE
), hwnd
, FormatDriveDlg
, (LPARAM
)&Context
);