reactos/reactos/dll/win32/shell32/drvdefext.cpp
Rafal Harabien d55ddcd563 [SHELL32]
- Implement changing filename in file properties dialog
- Fix changing volume label in drive properties dialog
- Remove WS_TABSTOP style from some read-only controls

svn path=/trunk/; revision=54956
2012-01-14 13:20:38 +00:00

619 lines
19 KiB
C++

/*
* Provides default drive shell extension
*
* Copyright 2005 Johannes Anderwald
* Copyright 2012 Rafal Harabien
*
* 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 St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define _USE_MATH_DEFINES
#include <precomp.h>
#include <math.h>
WINE_DEFAULT_DEBUG_CHANNEL(shell);
static const GUID GUID_DEVCLASS_DISKDRIVE = {0x4d36e967L, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
typedef enum
{
HWPD_STANDARDLIST = 0,
HWPD_LARGELIST,
HWPD_MAX = HWPD_LARGELIST
} HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE;
EXTERN_C HWND WINAPI
DeviceCreateHardwarePageEx(HWND hWndParent,
LPGUID lpGuids,
UINT uNumberOfGuids,
HWPAGE_DISPLAYMODE DisplayMode);
UINT SH_FormatByteSize(LONGLONG cbSize, LPWSTR pwszResult, UINT cchResultMax);
static VOID
GetDriveNameWithLetter(LPWSTR pwszText, UINT cchTextMax, LPCWSTR pwszDrive)
{
DWORD dwMaxComp, dwFileSys, cchText = 0;
if (GetVolumeInformationW(pwszDrive, pwszText, cchTextMax, NULL, &dwMaxComp, &dwFileSys, NULL, 0))
{
cchText = wcslen(pwszText);
if (cchText == 0)
{
/* load default volume label */
cchText = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, pwszText, cchTextMax);
}
}
StringCchPrintfW(pwszText + cchText, cchTextMax - cchText, L" (%c)", pwszDrive[0]);
}
static VOID
InitializeChkDskDialog(HWND hwndDlg, LPCWSTR pwszDrive)
{
WCHAR wszText[100];
UINT Length;
SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pwszDrive);
Length = GetWindowTextW(hwndDlg, wszText, sizeof(wszText) / sizeof(WCHAR));
wszText[Length] = L' ';
GetDriveNameWithLetter(&wszText[Length + 1], (sizeof(wszText) / sizeof(WCHAR)) - Length - 1, pwszDrive);
SetWindowText(hwndDlg, wszText);
}
static HWND hChkdskDrvDialog = NULL;
static BOOLEAN bChkdskSuccess = FALSE;
static BOOLEAN NTAPI
ChkdskCallback(
IN CALLBACKCOMMAND Command,
IN ULONG SubAction,
IN PVOID ActionInfo)
{
PDWORD Progress;
PBOOLEAN pSuccess;
switch(Command)
{
case PROGRESS:
Progress = (PDWORD)ActionInfo;
SendDlgItemMessageW(hChkdskDrvDialog, 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;
}
static VOID
ChkDskNow(HWND hwndDlg, LPCWSTR pwszDrive)
{
//DWORD ClusterSize = 0;
WCHAR wszFs[30];
ULARGE_INTEGER TotalNumberOfFreeBytes, FreeBytesAvailableUser;
BOOLEAN bCorrectErrors = FALSE, bScanDrive = FALSE;
if(!GetVolumeInformationW(pwszDrive, NULL, 0, NULL, NULL, NULL, wszFs, _countof(wszFs)))
{
FIXME("failed to get drive fs type\n");
return;
}
if (!GetDiskFreeSpaceExW(pwszDrive, &FreeBytesAvailableUser, &TotalNumberOfFreeBytes, NULL))
{
FIXME("failed to get drive space type\n");
return;
}
/*if (!GetDefaultClusterSize(wszFs, &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;
hChkdskDrvDialog = hwndDlg;
bChkdskSuccess = FALSE;
SendDlgItemMessageW(hwndDlg, 14002, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
Chkdsk((LPWSTR)pwszDrive, (LPWSTR)wszFs, bCorrectErrors, TRUE, FALSE, bScanDrive, NULL, NULL, ChkdskCallback); // FIXME: casts
hChkdskDrvDialog = NULL;
bChkdskSuccess = FALSE;
}
static INT_PTR CALLBACK
ChkDskDlg(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
InitializeChkDskDialog(hwndDlg, (LPCWSTR)lParam);
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, 0);
break;
case IDOK:
{
LPCWSTR pwszDrive = (LPCWSTR)GetWindowLongPtr(hwndDlg, DWLP_USER);
ChkDskNow(hwndDlg, pwszDrive);
break;
}
}
break;
}
return FALSE;
}
VOID
CDrvDefExt::PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT pDrawItem)
{
HBRUSH hBrush;
if (pDrawItem->CtlID == 14013)
{
hBrush = CreateSolidBrush(RGB(0, 0, 255));
if (hBrush)
{
FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hBrush);
DeleteObject((HGDIOBJ)hBrush);
}
}
else if (pDrawItem->CtlID == 14014)
{
hBrush = CreateSolidBrush(RGB(255, 0, 255));
if (hBrush)
{
FillRect(pDrawItem->hDC, &pDrawItem->rcItem, hBrush);
DeleteObject((HGDIOBJ)hBrush);
}
}
else if (pDrawItem->CtlID == 14015)
{
HBRUSH hBlueBrush = CreateSolidBrush(RGB(0, 0, 255));
HBRUSH hMagBrush = CreateSolidBrush(RGB(255, 0, 255));
HPEN hDarkBluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 128));
HPEN hDarkMagPen = CreatePen(PS_SOLID, 1, RGB(128, 0, 128));
INT xCenter = (pDrawItem->rcItem.left + pDrawItem->rcItem.right)/2;
INT yCenter = (pDrawItem->rcItem.top + pDrawItem->rcItem.bottom - 10)/2;
INT cx = pDrawItem->rcItem.right - pDrawItem->rcItem.left;
INT cy = pDrawItem->rcItem.bottom - pDrawItem->rcItem.top - 10;
TRACE("FreeSpace %u a %f cx %d\n", m_FreeSpacePerc, M_PI+m_FreeSpacePerc/100.0f*M_PI*2.0f, cx);
HBRUSH hbrOld = (HBRUSH)SelectObject(pDrawItem->hDC, hMagBrush);
INT xRadial = xCenter + (INT)(cosf(M_PI+m_FreeSpacePerc/100.0f*M_PI*2.0f)*cx/2);
INT yRadial = yCenter - (INT)(sinf(M_PI+m_FreeSpacePerc/100.0f*M_PI*2.0f)*cy/2);
Pie(pDrawItem->hDC,
pDrawItem->rcItem.left, pDrawItem->rcItem.top,
pDrawItem->rcItem.right, pDrawItem->rcItem.bottom - 10,
pDrawItem->rcItem.left, yCenter,
xRadial, yRadial);
SelectObject(pDrawItem->hDC, hBlueBrush);
Pie(pDrawItem->hDC,
pDrawItem->rcItem.left, pDrawItem->rcItem.top,
pDrawItem->rcItem.right, pDrawItem->rcItem.bottom - 10,
xRadial, yRadial,
pDrawItem->rcItem.left, yCenter);
SelectObject(pDrawItem->hDC, hbrOld);
HPEN hOldPen = (HPEN)SelectObject(pDrawItem->hDC, hDarkBluePen);
for (INT x = pDrawItem->rcItem.left; x < pDrawItem->rcItem.right; ++x)
{
if (m_FreeSpacePerc < 50 && x == xRadial)
SelectObject(pDrawItem->hDC, hDarkMagPen);
float cos_val = (x - xCenter)*2.0f/cx;
INT y = yCenter+sinf(acosf(cos_val))*cy/2;
MoveToEx(pDrawItem->hDC, x, y, NULL);
LineTo(pDrawItem->hDC, x, y + 10);
}
SelectObject(pDrawItem->hDC, hOldPen);
DeleteObject(hBlueBrush);
DeleteObject(hMagBrush);
DeleteObject(hDarkBluePen);
DeleteObject(hDarkMagPen);
}
}
VOID
CDrvDefExt::InitGeneralPage(HWND hwndDlg)
{
WCHAR wszVolumeName[MAX_PATH+1] = {0};
WCHAR wszFileSystem[MAX_PATH+1] = {0};
WCHAR wszBuf[128];
BOOL bRet;
bRet = GetVolumeInformationW(m_wszDrive, wszVolumeName, _countof(wszVolumeName), NULL, NULL, NULL, wszFileSystem, _countof(wszFileSystem));
if (bRet)
{
/* Set volume label and filesystem */
SetDlgItemTextW(hwndDlg, 14000, wszVolumeName);
SetDlgItemTextW(hwndDlg, 14002, wszFileSystem);
}
/* Set drive type and icon */
UINT DriveType = GetDriveTypeW(m_wszDrive);
UINT IconId, TypeStrId = 0;
switch (DriveType)
{
case DRIVE_CDROM: IconId = IDI_SHELL_CDROM; TypeStrId = IDS_DRIVE_CDROM; break;
case DRIVE_REMOVABLE: IconId = IDI_SHELL_FLOPPY; break;
case DRIVE_RAMDISK: IconId = IDI_SHELL_RAMDISK; break;
default: IconId = IDI_SHELL_DRIVE; TypeStrId = IDS_DRIVE_FIXED;
}
HICON hIcon = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IconId), IMAGE_ICON, 32, 32, LR_SHARED);
if (hIcon)
SendDlgItemMessageW(hwndDlg, 14016, STM_SETICON, (WPARAM)hIcon, 0);
if (TypeStrId && LoadStringW(shell32_hInstance, TypeStrId, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14001, wszBuf);
ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes;
if(GetDiskFreeSpaceExW(m_wszDrive, &FreeBytesAvailable, &TotalNumberOfBytes, NULL))
{
/* Init free space percentage used for drawing piechart */
m_FreeSpacePerc = (UINT)(FreeBytesAvailable.QuadPart * 100ull / TotalNumberOfBytes.QuadPart);
/* Used space */
if (SH_FormatByteSize(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14003, wszBuf);
if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14004, wszBuf);
/* Free space */
if (SH_FormatByteSize(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14005, wszBuf);
if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14006, wszBuf);
/* Total space */
if (SH_FormatByteSize(FreeBytesAvailable.QuadPart, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14007, wszBuf);
if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14008, wszBuf);
}
/* Set drive description */
WCHAR wszFormat[50];
GetDlgItemTextW(hwndDlg, 14009, wszFormat, _countof(wszFormat));
swprintf(wszBuf, wszFormat, m_wszDrive[0]);
SetDlgItemTextW(hwndDlg, 14009, wszBuf);
}
INT_PTR CALLBACK
CDrvDefExt::GeneralPageProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam;
if (ppsp == NULL)
break;
CDrvDefExt *pDrvDefExt = (CDrvDefExt*)ppsp->lParam;
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pDrvDefExt);
pDrvDefExt->InitGeneralPage(hwndDlg);
return TRUE;
}
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT pDrawItem = (LPDRAWITEMSTRUCT)lParam;
if (pDrawItem->CtlID >= 14013 && pDrawItem->CtlID <= 14015)
{
CDrvDefExt *pDrvDefExt = (CDrvDefExt*)GetWindowLongPtr(hwndDlg, DWLP_USER);
pDrvDefExt->PaintStaticControls(hwndDlg, pDrawItem);
return TRUE;
}
break;
}
case WM_PAINT:
break;
case WM_COMMAND:
if (LOWORD(wParam) == 14010) /* Disk Cleanup */
{
CDrvDefExt *pDrvDefExt = (CDrvDefExt*)GetWindowLongPtr(hwndDlg, DWLP_USER);
WCHAR wszBuf[256];
DWORD cbBuf = sizeof(wszBuf);
if (RegGetValueW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\CleanupPath",
NULL,
RRF_RT_REG_SZ,
NULL,
(PVOID)wszBuf,
&cbBuf) == ERROR_SUCCESS)
{
WCHAR wszCmd[MAX_PATH];
StringCbPrintfW(wszCmd, sizeof(wszCmd), wszBuf, pDrvDefExt->m_wszDrive[0]);
if (ShellExecuteW(hwndDlg, NULL, wszCmd, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
ERR("Failed to create cleanup process %ls\n", wszCmd);
}
}
else if (LOWORD(wParam) == 14000) /* Label */
{
if (HIWORD(wParam) == EN_CHANGE)
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
break;
case WM_NOTIFY:
if (((LPNMHDR)lParam)->hwndFrom == GetParent(hwndDlg))
{
/* Property Sheet */
LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
if (lppsn->hdr.code == PSN_APPLY)
{
CDrvDefExt *pDrvDefExt = (CDrvDefExt*)GetWindowLongPtr(hwndDlg, DWLP_USER);
WCHAR wszBuf[256];
if (GetDlgItemTextW(hwndDlg, 14000, wszBuf, _countof(wszBuf)))
SetVolumeLabelW(pDrvDefExt->m_wszDrive, wszBuf);
SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR);
return TRUE;
}
}
break;
default:
break;
}
return FALSE;
}
INT_PTR CALLBACK
CDrvDefExt::ExtraPageProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam;
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam);
return TRUE;
}
case WM_COMMAND:
{
WCHAR wszBuf[MAX_PATH];
DWORD cbBuf = sizeof(wszBuf);
CDrvDefExt *pDrvDefExt = (CDrvDefExt*)GetWindowLongPtr(hwndDlg, DWLP_USER);
switch(LOWORD(wParam))
{
case 14000:
DialogBoxParamW(shell32_hInstance, L"CHKDSK_DLG", hwndDlg, ChkDskDlg, (LPARAM)pDrvDefExt->m_wszDrive);
break;
case 14001:
if (RegGetValueW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath",
NULL,
RRF_RT_REG_SZ,
NULL,
(PVOID)wszBuf,
&cbBuf) == ERROR_SUCCESS)
{
WCHAR wszCmd[MAX_PATH];
StringCbPrintfW(wszCmd, sizeof(wszCmd), wszBuf, pDrvDefExt->m_wszDrive[0]);
if (ShellExecuteW(hwndDlg, NULL, wszCmd, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
ERR("Failed to create defrag process %ls\n", wszCmd);
}
break;
case 14002:
if (RegGetValueW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath",
NULL,
RRF_RT_REG_EXPAND_SZ,
NULL,
(PVOID)wszBuf,
&cbBuf) == ERROR_SUCCESS)
{
if (ShellExecuteW(hwndDlg, NULL, wszBuf, NULL, NULL, SW_SHOW) <= (HINSTANCE)32)
ERR("Failed to create backup process %ls\n", wszBuf);
}
}
break;
}
}
return FALSE;
}
INT_PTR CALLBACK
CDrvDefExt::HardwarePageProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
UNREFERENCED_PARAMETER(wParam);
switch(uMsg)
{
case WM_INITDIALOG:
{
GUID Guid = GUID_DEVCLASS_DISKDRIVE;
/* create the hardware page */
DeviceCreateHardwarePageEx(hwndDlg, &Guid, 1, HWPD_STANDARDLIST);
break;
}
}
return FALSE;
}
CDrvDefExt::CDrvDefExt()
{
m_wszDrive[0] = L'\0';
}
CDrvDefExt::~CDrvDefExt()
{
}
HRESULT WINAPI
CDrvDefExt::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pDataObj, HKEY hkeyProgID)
{
FORMATETC format;
STGMEDIUM stgm;
HRESULT hr;
TRACE("%p %p %p %p\n", this, pidlFolder, pDataObj, hkeyProgID);
if (!pDataObj)
return E_FAIL;
format.cfFormat = CF_HDROP;
format.ptd = NULL;
format.dwAspect = DVASPECT_CONTENT;
format.lindex = -1;
format.tymed = TYMED_HGLOBAL;
hr = pDataObj->GetData(&format, &stgm);
if (FAILED(hr))
return hr;
if (!DragQueryFileW((HDROP)stgm.hGlobal, 0, m_wszDrive, _countof(m_wszDrive)))
{
ERR("DragQueryFileW failed\n");
ReleaseStgMedium(&stgm);
return E_FAIL;
}
ReleaseStgMedium(&stgm);
TRACE("Drive properties %ls\n", m_wszDrive);
return S_OK;
}
HRESULT WINAPI
CDrvDefExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CDrvDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CDrvDefExt::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CDrvDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
{
HPROPSHEETPAGE hPage;
hPage = SH_CreatePropertySheetPage("DRIVE_GENERAL_DLG",
GeneralPageProc,
(LPARAM)this,
NULL);
if (hPage)
pfnAddPage(hPage, lParam);
if (GetDriveTypeW(m_wszDrive) == DRIVE_FIXED)
{
hPage = SH_CreatePropertySheetPage("DRIVE_EXTRA_DLG",
ExtraPageProc,
(LPARAM)this,
NULL);
if (hPage)
pfnAddPage(hPage, lParam);
}
hPage = SH_CreatePropertySheetPage("DRIVE_HARDWARE_DLG",
HardwarePageProc,
(LPARAM)this,
NULL);
if (hPage)
pfnAddPage(hPage, lParam);
return S_OK;
}
HRESULT WINAPI
CDrvDefExt::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CDrvDefExt::SetSite(IUnknown *punk)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CDrvDefExt::GetSite(REFIID iid, void **ppvSite)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}