reactos/reactos/dll/win32/shell32/drive.cpp
Amine Khaldi 3bb734fcf3 [SHELL32]
* Reintegrate the c++ shell32 branch. Exemplary team-work.. kudos !
* Better code quality, more tests run with less failures... and more.
* Dedicated to everyone who helped ;)

svn path=/trunk/; revision=53653
2011-09-09 10:55:09 +00:00

1289 lines
38 KiB
C++

/*
* Shell Library Functions
*
* Copyright 2005 Johannes Anderwald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <precomp.h>
#define MAX_PROPERTY_SHEET_PAGE 32
WINE_DEFAULT_DEBUG_CHANNEL(shell);
typedef enum
{
HWPD_STANDARDLIST = 0,
HWPD_LARGELIST,
HWPD_MAX = HWPD_LARGELIST
} HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
typedef
BOOLEAN
(NTAPI *INITIALIZE_FMIFS)(
IN PVOID hinstDll,
IN DWORD dwReason,
IN PVOID reserved
);
typedef
BOOLEAN
(NTAPI *QUERY_AVAILABLEFSFORMAT)(
IN DWORD Index,
IN OUT PWCHAR FileSystem,
OUT UCHAR* Major,
OUT UCHAR* Minor,
OUT BOOLEAN* LastestVersion
);
typedef
BOOLEAN
(NTAPI *ENABLEVOLUMECOMPRESSION)(
IN PWCHAR DriveRoot,
IN USHORT Compression
);
typedef
VOID
(NTAPI *FORMAT_EX)(
IN PWCHAR DriveRoot,
IN FMIFS_MEDIA_FLAG MediaFlag,
IN PWCHAR Format,
IN PWCHAR Label,
IN BOOLEAN QuickFormat,
IN ULONG ClusterSize,
IN PFMIFSCALLBACK Callback
);
typedef
VOID
(NTAPI *CHKDSK)(
IN PWCHAR DriveRoot,
IN PWCHAR Format,
IN BOOLEAN CorrectErrors,
IN BOOLEAN Verbose,
IN BOOLEAN CheckOnlyIfDirty,
IN BOOLEAN ScanDrive,
IN PVOID Unused2,
IN PVOID Unused3,
IN PFMIFSCALLBACK Callback
);
typedef struct
{
WCHAR Drive;
UINT Options;
HMODULE hLibrary;
QUERY_AVAILABLEFSFORMAT QueryAvailableFileSystemFormat;
FORMAT_EX FormatEx;
ENABLEVOLUMECOMPRESSION EnableVolumeCompression;
CHKDSK Chkdsk;
UINT Result;
}FORMAT_DRIVE_CONTEXT, *PFORMAT_DRIVE_CONTEXT;
BOOL InitializeFmifsLibrary(PFORMAT_DRIVE_CONTEXT pContext);
BOOL GetDefaultClusterSize(LPWSTR szFs, PDWORD pClusterSize, PULARGE_INTEGER TotalNumberOfBytes);
EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
EXTERN_C HWND WINAPI
DeviceCreateHardwarePageEx(HWND hWndParent,
LPGUID lpGuids,
UINT uNumberOfGuids,
HWPAGE_DISPLAYMODE DisplayMode);
HPROPSHEETPAGE SH_CreatePropertySheetPage(LPCSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle);
#define DRIVE_PROPERTY_PAGES (3)
static const GUID GUID_DEVCLASS_DISKDRIVE = {0x4d36e967L, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
VOID
GetDriveNameWithLetter(LPWSTR szText, UINT Length, WCHAR Drive)
{
WCHAR szDrive[] = {'C',':','\\', 0};
DWORD dwMaxComp, dwFileSys, TempLength = 0;
szDrive[0] = Drive;
if (GetVolumeInformationW(szDrive, szText, Length, NULL, &dwMaxComp, &dwFileSys, NULL, 0))
{
szText[Length-1] = L'\0';
TempLength = wcslen(szText);
if (!TempLength)
{
/* load default volume label */
TempLength = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2);
}
}
if (TempLength + 4 < Length)
{
szText[TempLength] = L' ';
szText[TempLength+1] = L'(';
szText[TempLength+2] = szDrive[0];
szText[TempLength+3] = L')';
TempLength +=4;
}
if (TempLength < Length)
szText[TempLength] = L'\0';
else
szText[Length-1] = L'\0';
}
VOID
InitializeChkDskDialog(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
{
WCHAR szText[100];
UINT Length;
SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pContext);
Length = GetWindowTextW(hwndDlg, szText, sizeof(szText)/sizeof(WCHAR));
GetDriveNameWithLetter(&szText[Length +1], (sizeof(szText)/sizeof(WCHAR))-Length-1, pContext->Drive);
szText[Length] = L' ';
szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
SetWindowText(hwndDlg, szText);
}
HWND ChkdskDrvDialog = NULL;
BOOLEAN bChkdskSuccess = FALSE;
BOOLEAN
NTAPI
ChkdskCallback(
IN CALLBACKCOMMAND Command,
IN ULONG SubAction,
IN PVOID ActionInfo)
{
PDWORD Progress;
PBOOLEAN pSuccess;
switch(Command)
{
case PROGRESS:
Progress = (PDWORD)ActionInfo;
SendDlgItemMessageW(ChkdskDrvDialog, 14002, PBM_SETPOS, (WPARAM)*Progress, 0);
break;
case DONE:
pSuccess = (PBOOLEAN)ActionInfo;
bChkdskSuccess = (*pSuccess);
break;
case VOLUMEINUSE:
case INSUFFICIENTRIGHTS:
case FSNOTSUPPORTED:
case CLUSTERSIZETOOSMALL:
bChkdskSuccess = FALSE;
FIXME("\n");
break;
default:
break;
}
return TRUE;
}
VOID
ChkDskNow(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
{
DWORD ClusterSize = 0, dwMaxComponentLength, FileSystemFlags;
WCHAR szFs[30];
WCHAR szDrive[] = {'C',':','\\', 0};
WCHAR szVolumeLabel[40];
ULARGE_INTEGER TotalNumberOfFreeBytes, FreeBytesAvailableUser;
BOOLEAN bCorrectErrors = FALSE, bScanDrive = FALSE;
szDrive[0] = pContext->Drive;
if(!GetVolumeInformationW(szDrive, szVolumeLabel, sizeof(szVolumeLabel)/sizeof(WCHAR), NULL, &dwMaxComponentLength, &FileSystemFlags, szFs, sizeof(szFs)/sizeof(WCHAR)))
{
FIXME("failed to get drive fs type\n");
return;
}
if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfFreeBytes, NULL))
{
FIXME("failed to get drive space type\n");
return;
}
if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfFreeBytes))
{
FIXME("invalid cluster size\n");
return;
}
if (SendDlgItemMessageW(hwndDlg, 14000, BM_GETCHECK, 0, 0) == BST_CHECKED)
bCorrectErrors = TRUE;
if (SendDlgItemMessageW(hwndDlg, 14001, BM_GETCHECK, 0, 0) == BST_CHECKED)
bScanDrive = TRUE;
ChkdskDrvDialog = hwndDlg;
bChkdskSuccess = FALSE;
SendDlgItemMessageW(hwndDlg, 14002, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
pContext->Chkdsk(szDrive, szFs, bCorrectErrors, TRUE, FALSE, bScanDrive, NULL, NULL, ChkdskCallback);
ChkdskDrvDialog = NULL;
pContext->Result = bChkdskSuccess;
bChkdskSuccess = FALSE;
}
INT_PTR
CALLBACK
ChkDskDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
PFORMAT_DRIVE_CONTEXT pContext;
switch(uMsg)
{
case WM_INITDIALOG:
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
InitializeChkDskDialog(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, 0);
break;
case IDOK:
pContext = (PFORMAT_DRIVE_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER);
ChkDskNow(hwndDlg, pContext);
break;
}
break;
}
return FALSE;
}
static
ULONGLONG
GetFreeBytesShare(ULONGLONG TotalNumberOfFreeBytes, ULONGLONG TotalNumberOfBytes)
{
ULONGLONG Temp;
if (TotalNumberOfFreeBytes == 0LL)
{
return 0;
}
Temp = TotalNumberOfBytes / 100;
if (Temp >= TotalNumberOfFreeBytes)
{
return 1;
}
else
{
return TotalNumberOfFreeBytes / Temp;
}
}
static
void
PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT drawItem)
{
HBRUSH hBrush;
if (drawItem->CtlID == 14013)
{
hBrush = CreateSolidBrush(RGB(0, 0, 255));
if (hBrush)
{
FillRect(drawItem->hDC, &drawItem->rcItem, hBrush);
DeleteObject((HGDIOBJ)hBrush);
}
}
else if (drawItem->CtlID == 14014)
{
hBrush = CreateSolidBrush(RGB(255, 0, 255));
if (hBrush)
{
FillRect(drawItem->hDC, &drawItem->rcItem, hBrush);
DeleteObject((HGDIOBJ)hBrush);
}
}
else if (drawItem->CtlID == 14015)
{
HBRUSH hBlueBrush;
HBRUSH hMagBrush;
RECT rect;
LONG horzsize;
LONGLONG Result;
WCHAR szBuffer[20];
hBlueBrush = CreateSolidBrush(RGB(0, 0, 255));
hMagBrush = CreateSolidBrush(RGB(255, 0, 255));
SendDlgItemMessageW(hwndDlg, 14006, WM_GETTEXT, 20, (LPARAM)szBuffer);
Result = _wtoi(szBuffer);
CopyRect(&rect, &drawItem->rcItem);
horzsize = rect.right - rect.left;
Result = (Result * horzsize) / 100;
rect.right = drawItem->rcItem.right - Result;
FillRect(drawItem->hDC, &rect, hBlueBrush);
rect.left = rect.right;
rect.right = drawItem->rcItem.right;
FillRect(drawItem->hDC, &rect, hMagBrush);
DeleteObject(hBlueBrush);
DeleteObject(hMagBrush);
}
}
static
void
InitializeGeneralDriveDialog(HWND hwndDlg, WCHAR * szDrive)
{
WCHAR szVolumeName[MAX_PATH+1] = {0};
DWORD MaxComponentLength = 0;
DWORD FileSystemFlags = 0;
WCHAR FileSystemName[MAX_PATH+1] = {0};
WCHAR szFormat[50];
WCHAR szBuffer[128];
BOOL ret;
UINT DriveType;
ULARGE_INTEGER FreeBytesAvailable;
LARGE_INTEGER TotalNumberOfFreeBytes;
LARGE_INTEGER TotalNumberOfBytes;
ret = GetVolumeInformationW(szDrive, szVolumeName, MAX_PATH+1, NULL, &MaxComponentLength, &FileSystemFlags, FileSystemName, MAX_PATH+1);
if (ret)
{
/* set volume label */
SendDlgItemMessageW(hwndDlg, 14000, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szVolumeName);
/* set filesystem type */
SendDlgItemMessageW(hwndDlg, 14002, WM_SETTEXT, (WPARAM)NULL, (LPARAM)FileSystemName);
}
DriveType = GetDriveTypeW(szDrive);
if (DriveType == DRIVE_FIXED || DriveType == DRIVE_CDROM)
{
if(GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable, (PULARGE_INTEGER)&TotalNumberOfBytes, (PULARGE_INTEGER)&TotalNumberOfFreeBytes))
{
WCHAR szResult[128];
LONGLONG Result;
HANDLE hVolume;
DWORD BytesReturned = 0;
swprintf(szResult, L"\\\\.\\%c:", towupper(szDrive[0]));
hVolume = CreateFileW(szResult, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hVolume != INVALID_HANDLE_VALUE)
{
ret = DeviceIoControl(hVolume, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, (LPVOID)&TotalNumberOfBytes, sizeof(ULARGE_INTEGER), &BytesReturned, NULL);
if (ret && StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
SendDlgItemMessageW(hwndDlg, 14007, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
CloseHandle(hVolume);
}
TRACE("szResult %s hVOlume %p ret %d LengthInformation %ul Bytesreturned %d\n", debugstr_w(szResult), hVolume, ret, TotalNumberOfBytes.QuadPart, BytesReturned);
if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
SendDlgItemMessageW(hwndDlg, 14003, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR)))
SendDlgItemMessageW(hwndDlg, 14005, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult);
Result = GetFreeBytesShare(TotalNumberOfFreeBytes.QuadPart, TotalNumberOfBytes.QuadPart);
/* set free bytes percentage */
swprintf(szResult, L"%02d%%", Result);
SendDlgItemMessageW(hwndDlg, 14006, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult);
/* store used share amount */
Result = 100 - Result;
swprintf(szResult, L"%02d%%", Result);
SendDlgItemMessageW(hwndDlg, 14004, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult);
if (DriveType == DRIVE_FIXED)
{
if (LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer);
}
else /* DriveType == DRIVE_CDROM) */
{
if (LoadStringW(shell32_hInstance, IDS_DRIVE_CDROM, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer);
}
}
}
/* set drive description */
SendDlgItemMessageW(hwndDlg, 14009, WM_GETTEXT, (WPARAM)50, (LPARAM)szFormat);
swprintf(szBuffer, szFormat, szDrive);
SendDlgItemMessageW(hwndDlg, 14009, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szBuffer);
}
INT_PTR
CALLBACK
DriveGeneralDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
LPPROPSHEETPAGEW ppsp;
LPDRAWITEMSTRUCT drawItem;
STARTUPINFOW si;
PROCESS_INFORMATION pi;
WCHAR * lpstr;
WCHAR szPath[MAX_PATH];
UINT length;
LPPSHNOTIFY lppsn;
switch(uMsg)
{
case WM_INITDIALOG:
ppsp = (LPPROPSHEETPAGEW)lParam;
if (ppsp == NULL)
break;
lpstr = (WCHAR *)ppsp->lParam;
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lpstr);
InitializeGeneralDriveDialog(hwndDlg, lpstr);
return TRUE;
case WM_DRAWITEM:
drawItem = (LPDRAWITEMSTRUCT)lParam;
if (drawItem->CtlID >= 14013 && drawItem->CtlID <= 14015)
{
PaintStaticControls(hwndDlg, drawItem);
return TRUE;
}
break;
case WM_COMMAND:
if (LOWORD(wParam) == 14010) /* Disk Cleanup */
{
lpstr = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER);
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if (!GetSystemDirectoryW(szPath, MAX_PATH))
break;
wcscat(szPath, L"\\cleanmgr.exe /D ");
length = wcslen(szPath);
szPath[length] = lpstr[0];
szPath[length+1] = L'\0';
if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
break;
}
case WM_NOTIFY:
lppsn = (LPPSHNOTIFY) lParam;
if (LOWORD(wParam) == 14000)
{
if (HIWORD(wParam) == EN_CHANGE)
{
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
break;
}
if (lppsn->hdr.code == PSN_APPLY)
{
lpstr = (LPWSTR)GetWindowLongPtr(hwndDlg, DWLP_USER);
if (lpstr && SendDlgItemMessageW(hwndDlg, 14000, WM_GETTEXT, sizeof(szPath)/sizeof(WCHAR), (LPARAM)szPath))
{
szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0';
SetVolumeLabelW(lpstr, szPath);
}
SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
INT_PTR
CALLBACK
DriveExtraDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
STARTUPINFOW si;
PROCESS_INFORMATION pi;
WCHAR szPath[MAX_PATH + 10];
WCHAR szArg[MAX_PATH];
WCHAR * szDrive;
LPPROPSHEETPAGEW ppsp;
DWORD dwSize;
FORMAT_DRIVE_CONTEXT Context;
switch (uMsg)
{
case WM_INITDIALOG:
ppsp = (LPPROPSHEETPAGEW)lParam;
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam);
return TRUE;
case WM_COMMAND:
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
szDrive = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER);
switch(LOWORD(wParam))
{
case 14000:
if (InitializeFmifsLibrary(&Context))
{
Context.Drive = szDrive[0];
DialogBoxParamW(shell32_hInstance, L"CHKDSK_DLG", hwndDlg, ChkDskDlg, (LPARAM)&Context);
FreeLibrary(Context.hLibrary);
}
break;
case 14001:
dwSize = sizeof(szPath);
if (RegGetValueW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath",
NULL,
RRF_RT_REG_EXPAND_SZ,
NULL,
(PVOID)szPath,
&dwSize) == S_OK)
{
swprintf(szArg, szPath, szDrive[0]);
if (!GetSystemDirectoryW(szPath, MAX_PATH))
break;
szDrive = PathAddBackslashW(szPath);
if (!szDrive)
break;
wcscat(szDrive, L"mmc.exe");
if (CreateProcessW(szPath, szArg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
break;
case 14002:
dwSize = sizeof(szPath);
if (RegGetValueW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath",
NULL,
RRF_RT_REG_EXPAND_SZ,
NULL,
(PVOID)szPath,
&dwSize) == S_OK)
{
if (CreateProcessW(szPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
}
break;
}
return FALSE;
}
INT_PTR
CALLBACK
DriveHardwareDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
GUID Guids[1];
Guids[0] = GUID_DEVCLASS_DISKDRIVE;
UNREFERENCED_PARAMETER(lParam);
UNREFERENCED_PARAMETER(wParam);
switch(uMsg)
{
case WM_INITDIALOG:
/* create the hardware page */
DeviceCreateHardwarePageEx(hwndDlg,
Guids,
sizeof(Guids) / sizeof(Guids[0]),
HWPD_STANDARDLIST);
break;
}
return FALSE;
}
static
const
struct
{
LPCSTR resname;
DLGPROC dlgproc;
UINT DriveType;
} PropPages[] =
{
{ "DRIVE_GENERAL_DLG", DriveGeneralDlg, -1},
{ "DRIVE_EXTRA_DLG", DriveExtraDlg, DRIVE_FIXED},
{ "DRIVE_HARDWARE_DLG", DriveHardwareDlg, -1},
};
HRESULT
CALLBACK
AddPropSheetPageProc(HPROPSHEETPAGE hpage, LPARAM lParam)
{
PROPSHEETHEADER *ppsh = (PROPSHEETHEADER *)lParam;
if (ppsh != NULL && ppsh->nPages < MAX_PROPERTY_SHEET_PAGE)
{
ppsh->phpage[ppsh->nPages++] = hpage;
return TRUE;
}
return FALSE;
}
BOOL
SH_ShowDriveProperties(WCHAR * drive, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST * apidl)
{
HPSXA hpsx = NULL;
HPROPSHEETPAGE hpsp[MAX_PROPERTY_SHEET_PAGE];
PROPSHEETHEADERW psh;
BOOL ret;
UINT i;
WCHAR szName[MAX_PATH+6];
DWORD dwMaxComponent, dwFileSysFlags;
CComPtr<IDataObject> pDataObj;
UINT DriveType;
ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
psh.dwSize = sizeof(PROPSHEETHEADERW);
//psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE;
psh.hwndParent = NULL;
psh.nStartPage = 0;
psh.phpage = hpsp;
if (GetVolumeInformationW(drive, szName, sizeof(szName)/sizeof(WCHAR), NULL, &dwMaxComponent,
&dwFileSysFlags, NULL, 0))
{
psh.pszCaption = szName;
psh.dwFlags |= PSH_PROPTITLE;
if (!wcslen(szName))
{
/* FIXME
* check if disk is a really a local hdd
*/
i = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szName, sizeof(szName)/sizeof(WCHAR)-6);
if (i > 0 && i < (sizeof(szName)/sizeof(WCHAR)) - 6)
{
szName[i] = L' ';
szName[i+1] = L'(';
wcscpy(&szName[i+2], drive);
szName[i+4] = L')';
szName[i+5] = L'\0';
}
}
}
DriveType = GetDriveTypeW(drive);
for (i = 0; i < DRIVE_PROPERTY_PAGES; i++)
{
if (PropPages[i].DriveType == (UINT)-1 || (PropPages[i].DriveType != (UINT)-1 && PropPages[i].DriveType == DriveType))
{
HPROPSHEETPAGE hprop = SH_CreatePropertySheetPage(PropPages[i].resname, PropPages[i].dlgproc, (LPARAM)drive, NULL);
if (hprop)
{
hpsp[psh.nPages] = hprop;
psh.nPages++;
}
}
}
if (SHCreateDataObject(pidlFolder, 1, apidl, NULL, IID_IDataObject, (void **)&pDataObj) == S_OK)
{
hpsx = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, L"Drive", MAX_PROPERTY_SHEET_PAGE-DRIVE_PROPERTY_PAGES, pDataObj);
if (hpsx)
{
SHAddFromPropSheetExtArray(hpsx, (LPFNADDPROPSHEETPAGE)AddPropSheetPageProc, (LPARAM)&psh);
}
}
ret = PropertySheetW(&psh);
if (hpsx)
SHDestroyPropSheetExtArray(hpsx);
if (ret < 0)
return FALSE;
else
return TRUE;
}
BOOL
GetDefaultClusterSize(LPWSTR szFs, PDWORD pClusterSize, PULARGE_INTEGER TotalNumberOfBytes)
{
DWORD ClusterSize;
if (!wcsicmp(szFs, L"FAT16") ||
!wcsicmp(szFs, L"FAT")) //REACTOS HACK
{
if (TotalNumberOfBytes->QuadPart <= (16 * 1024 * 1024))
ClusterSize = 2048;
else if (TotalNumberOfBytes->QuadPart <= (32 * 1024 * 1024))
ClusterSize = 512;
else if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024))
ClusterSize = 1024;
else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
ClusterSize = 2048;
else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
ClusterSize = 4096;
else if (TotalNumberOfBytes->QuadPart <= (512 * 1024 * 1024))
ClusterSize = 8192;
else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024))
ClusterSize = 16384;
else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL))
ClusterSize = 32768;
else if (TotalNumberOfBytes->QuadPart <= (4096LL * 1024LL * 1024LL))
ClusterSize = 8192;
else
return FALSE;
}
else if (!wcsicmp(szFs, L"FAT32"))
{
if (TotalNumberOfBytes->QuadPart <=(64 * 1024 * 1024))
ClusterSize = 512;
else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024))
ClusterSize = 1024;
else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024))
ClusterSize = 2048;
else if (TotalNumberOfBytes->QuadPart <= (8192LL * 1024LL * 1024LL))
ClusterSize = 2048;
else if (TotalNumberOfBytes->QuadPart <= (16384LL * 1024LL * 1024LL))
ClusterSize = 8192;
else if (TotalNumberOfBytes->QuadPart <= (32768LL * 1024LL * 1024LL))
ClusterSize = 16384;
else
return FALSE;
}
else if (!wcsicmp(szFs, L"NTFS"))
{
if (TotalNumberOfBytes->QuadPart <=(512 * 1024 * 1024))
ClusterSize = 512;
else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024))
ClusterSize = 1024;
else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL))
ClusterSize = 2048;
else
ClusterSize = 2048;
}
else
return FALSE;
*pClusterSize = ClusterSize;
return TRUE;
}
VOID
InsertDefaultClusterSizeForFs(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
{
WCHAR szFs[100] = {0};
WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
INT iSelIndex;
ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
DWORD ClusterSize;
LRESULT lIndex;
HWND hDlgCtrl;
hDlgCtrl = GetDlgItem(hwndDlg, 28677);
iSelIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0);
if (iSelIndex == CB_ERR)
return;
if (SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFs) == CB_ERR)
return;
szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
szDrive[0] = pContext->Drive + 'A';
if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
return;
if (!wcsicmp(szFs, L"FAT16") ||
!wcsicmp(szFs, L"FAT")) //REACTOS HACK
{
if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes))
{
TRACE("FAT16 is not supported on hdd larger than 4G current %lu\n", TotalNumberOfBytes.QuadPart);
SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
return;
}
if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
{
hDlgCtrl = GetDlgItem(hwndDlg, 28680);
szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
if (lIndex != CB_ERR)
SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
}
}
else if (!wcsicmp(szFs, L"FAT32"))
{
if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes))
{
TRACE("FAT32 is not supported on hdd larger than 32G current %lu\n", TotalNumberOfBytes.QuadPart);
SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
return;
}
if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
{
hDlgCtrl = GetDlgItem(hwndDlg, 28680);
szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
if (lIndex != CB_ERR)
SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
}
}
else if (!wcsicmp(szFs, L"NTFS"))
{
if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes))
{
TRACE("NTFS is not supported on hdd larger than 2TB current %lu\n", TotalNumberOfBytes.QuadPart);
SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0);
return;
}
hDlgCtrl = GetDlgItem(hwndDlg, 28680);
if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR)))
{
szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0';
SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0);
lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
if (lIndex != CB_ERR)
SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0);
}
ClusterSize = 512;
for (lIndex = 0; lIndex < 4; lIndex++)
{
TotalNumberOfBytes.QuadPart = ClusterSize;
if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szFs, sizeof(szFs)/sizeof(WCHAR)))
{
lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs);
if (lIndex != CB_ERR)
SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize);
}
ClusterSize *= 2;
}
}
else
{
FIXME("unknown fs\n");
SendDlgItemMessageW(hwndDlg, 28680, CB_RESETCONTENT, iSelIndex, 0);
return;
}
}
VOID
InitializeFormatDriveDlg(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
{
WCHAR szText[120];
WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
WCHAR szFs[30] = {0};
INT Length, TempLength;
DWORD dwSerial, dwMaxComp, dwFileSys;
ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes;
DWORD dwIndex, dwDefault;
UCHAR uMinor, uMajor;
BOOLEAN Latest;
HWND hDlgCtrl;
Length = GetWindowTextW(hwndDlg, szText, sizeof(szText)/sizeof(WCHAR));
if (Length < 0)
Length = 0;
szDrive[0] = pContext->Drive + L'A';
if (GetVolumeInformationW(szDrive, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2, &dwSerial, &dwMaxComp, &dwFileSys, szFs, sizeof(szFs)/sizeof(WCHAR)))
{
szText[Length] = L' ';
szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
TempLength = wcslen(&szText[Length+1]);
if (!TempLength)
{
/* load default volume label */
TempLength = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2);
}
else
{
/* set volume label */
szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
SendDlgItemMessageW(hwndDlg, 28679, WM_SETTEXT, 0, (LPARAM)&szText[Length+1]);
}
Length += TempLength + 1;
}
if ((DWORD)Length + 4 < (sizeof(szText)/sizeof(WCHAR)))
{
szText[Length] = L' ';
szText[Length+1] = L'(';
szText[Length+2] = szDrive[0];
szText[Length+3] = L')';
Length +=4;
}
if ((DWORD)Length < (sizeof(szText)/sizeof(WCHAR)))
szText[Length] = L'\0';
else
szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
/* set window text */
SetWindowTextW(hwndDlg, szText);
if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL))
{
if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szText, sizeof(szText)/sizeof(WCHAR)))
{
/* add drive capacity */
szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
SendDlgItemMessageW(hwndDlg, 28673, CB_ADDSTRING, 0, (LPARAM)szText);
SendDlgItemMessageW(hwndDlg, 28673, CB_SETCURSEL, 0, (LPARAM)0);
}
}
if (pContext->Options & SHFMT_OPT_FULL)
{
/* check quick format button */
SendDlgItemMessageW(hwndDlg, 28674, BM_SETCHECK, BST_CHECKED, 0);
}
/* enumerate all available filesystems */
dwIndex = 0;
dwDefault = 0;
hDlgCtrl = GetDlgItem(hwndDlg, 28677);
while(pContext->QueryAvailableFileSystemFormat(dwIndex, szText, &uMajor, &uMinor, &Latest))
{
szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0';
if (!wcsicmp(szText, szFs))
dwDefault = dwIndex;
SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szText);
dwIndex++;
}
if (!dwIndex)
{
ERR("no filesystem providers\n");
return;
}
/* select default filesys */
SendMessageW(hDlgCtrl, CB_SETCURSEL, dwDefault, 0);
/* setup cluster combo */
InsertDefaultClusterSizeForFs(hwndDlg, pContext);
/* hide progress control */
ShowWindow(GetDlgItem(hwndDlg, 28678), SW_HIDE);
}
HWND FormatDrvDialog = NULL;
BOOLEAN bSuccess = FALSE;
BOOLEAN
NTAPI
FormatExCB(
IN CALLBACKCOMMAND Command,
IN ULONG SubAction,
IN PVOID ActionInfo)
{
PDWORD Progress;
PBOOLEAN pSuccess;
switch(Command)
{
case PROGRESS:
Progress = (PDWORD)ActionInfo;
SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, (WPARAM)*Progress, 0);
break;
case DONE:
pSuccess = (PBOOLEAN)ActionInfo;
bSuccess = (*pSuccess);
break;
case VOLUMEINUSE:
case INSUFFICIENTRIGHTS:
case FSNOTSUPPORTED:
case CLUSTERSIZETOOSMALL:
bSuccess = FALSE;
FIXME("\n");
break;
default:
break;
}
return TRUE;
}
VOID
FormatDrive(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext)
{
WCHAR szDrive[4] = { L'C', ':', '\\', 0 };
WCHAR szFileSys[40] = {0};
WCHAR szLabel[40] = {0};
INT iSelIndex;
UINT Length;
HWND hDlgCtrl;
BOOL QuickFormat;
DWORD ClusterSize;
/* set volume path */
szDrive[0] = pContext->Drive;
/* get filesystem */
hDlgCtrl = GetDlgItem(hwndDlg, 28677);
iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
if (iSelIndex == CB_ERR)
{
FIXME("\n");
return;
}
Length = SendMessageW(hDlgCtrl, CB_GETLBTEXTLEN, iSelIndex, 0);
if ((int)Length == CB_ERR || Length + 1> sizeof(szFileSys)/sizeof(WCHAR))
{
FIXME("\n");
return;
}
/* retrieve the file system */
SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFileSys);
szFileSys[(sizeof(szFileSys)/sizeof(WCHAR))-1] = L'\0';
/* retrieve the volume label */
hDlgCtrl = GetWindow(hwndDlg, 28679);
Length = SendMessageW(hDlgCtrl, WM_GETTEXTLENGTH, 0, 0);
if (Length + 1 > sizeof(szLabel)/sizeof(WCHAR))
{
FIXME("\n");
return;
}
SendMessageW(hDlgCtrl, WM_GETTEXT, sizeof(szLabel)/sizeof(WCHAR), (LPARAM)szLabel);
szLabel[(sizeof(szLabel)/sizeof(WCHAR))-1] = L'\0';
/* check for quickformat */
if (SendDlgItemMessageW(hwndDlg, 28674, BM_GETCHECK, 0, 0) == BST_CHECKED)
QuickFormat = TRUE;
else
QuickFormat = FALSE;
/* get the cluster size */
hDlgCtrl = GetDlgItem(hwndDlg, 28680);
iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0);
if (iSelIndex == CB_ERR)
{
FIXME("\n");
return;
}
ClusterSize = SendMessageW(hDlgCtrl, CB_GETITEMDATA, iSelIndex, 0);
if ((int)ClusterSize == CB_ERR)
{
FIXME("\n");
return;
}
hDlgCtrl = GetDlgItem(hwndDlg, 28680);
ShowWindow(hDlgCtrl, SW_SHOW);
SendMessageW(hDlgCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
bSuccess = FALSE;
/* FIXME
* will cause display problems
* when performing more than one format
*/
FormatDrvDialog = hwndDlg;
pContext->FormatEx(szDrive,
FMIFS_HARDDISK, /* FIXME */
szFileSys,
szLabel,
QuickFormat,
ClusterSize,
FormatExCB);
ShowWindow(hDlgCtrl, SW_HIDE);
FormatDrvDialog = NULL;
if (!bSuccess)
{
pContext->Result = SHFMT_ERROR;
}
else if (QuickFormat)
{
pContext->Result = SHFMT_OPT_FULL;
}
else
{
pContext->Result = FALSE;
}
}
BOOL
CALLBACK
FormatDriveDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PFORMAT_DRIVE_CONTEXT pContext;
switch(uMsg)
{
case WM_INITDIALOG:
InitializeFormatDriveDlg(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam);
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
FormatDrive(hwndDlg, pContext);
break;
case IDCANCEL:
pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
EndDialog(hwndDlg, pContext->Result);
break;
case 28677: // filesystem combo
if (HIWORD(wParam) == CBN_SELENDOK)
{
pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER);
InsertDefaultClusterSizeForFs(hwndDlg, pContext);
}
break;
}
}
return FALSE;
}
BOOL
InitializeFmifsLibrary(PFORMAT_DRIVE_CONTEXT pContext)
{
INITIALIZE_FMIFS InitFmifs;
BOOLEAN ret;
HMODULE hLibrary;
hLibrary = pContext->hLibrary = LoadLibraryW(L"fmifs.dll");
if(!hLibrary)
{
ERR("failed to load fmifs.dll\n");
return FALSE;
}
InitFmifs = (INITIALIZE_FMIFS)GetProcAddress(hLibrary, "InitializeFmIfs");
if (!InitFmifs)
{
ERR("InitializeFmIfs export is missing\n");
FreeLibrary(hLibrary);
return FALSE;
}
ret = (*InitFmifs)(NULL, DLL_PROCESS_ATTACH, NULL);
if (!ret)
{
ERR("fmifs failed to initialize\n");
FreeLibrary(hLibrary);
return FALSE;
}
pContext->QueryAvailableFileSystemFormat = (QUERY_AVAILABLEFSFORMAT)GetProcAddress(hLibrary, "QueryAvailableFileSystemFormat");
if (!pContext->QueryAvailableFileSystemFormat)
{
ERR("QueryAvailableFileSystemFormat export is missing\n");
FreeLibrary(hLibrary);
return FALSE;
}
pContext->FormatEx = (FORMAT_EX) GetProcAddress(hLibrary, "FormatEx");
if (!pContext->FormatEx)
{
ERR("FormatEx export is missing\n");
FreeLibrary(hLibrary);
return FALSE;
}
pContext->EnableVolumeCompression = (ENABLEVOLUMECOMPRESSION) GetProcAddress(hLibrary, "EnableVolumeCompression");
if (!pContext->FormatEx)
{
ERR("EnableVolumeCompression export is missing\n");
FreeLibrary(hLibrary);
return FALSE;
}
pContext->Chkdsk = (CHKDSK) GetProcAddress(hLibrary, "Chkdsk");
if (!pContext->Chkdsk)
{
ERR("Chkdsk export is missing\n");
FreeLibrary(hLibrary);
return FALSE;
}
return TRUE;
}
/*************************************************************************
* SHFormatDrive (SHELL32.@)
*/
DWORD
WINAPI
SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
{
FORMAT_DRIVE_CONTEXT Context;
int result;
TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options);
if (!InitializeFmifsLibrary(&Context))
{
ERR("failed to initialize fmifs\n");
return SHFMT_NOFORMAT;
}
Context.Drive = drive;
Context.Options = options;
result = DialogBoxParamW(shell32_hInstance, L"FORMAT_DLG", hwnd, FormatDriveDlg, (LPARAM)&Context);
FreeLibrary(Context.hLibrary);
return result;
}