windows-nt/Source/XPSP1/NT/shell/osshell/dskquota/ui/volprop.cpp

2205 lines
66 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
///////////////////////////////////////////////////////////////////////////////
/* File: volprop.cpp
Description: Provides implementations for quota property pages.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
08/01/97 Removed IDC_CBX_WARN_THRESHOLD from UI. BrianAu
11/27/98 Added logging checkboxes back in. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
#include "pch.h"
#pragma hdrstop
#include "dskquota.h"
#include "volprop.h"
#include "uihelp.h"
#include "registry.h"
#include "guidsp.h"
#include "uiutils.h"
#ifdef POLICY_MMC_SNAPIN
# include "snapin.h"
#endif
//
// Context help IDs.
//
#pragma data_seg(".text", "CODE")
const static DWORD rgVolumePropPageHelpIDs[] =
{
IDC_TRAFFIC_LIGHT, IDH_TRAFFIC_LIGHT,
IDC_TXT_QUOTA_STATUS, IDH_TXT_QUOTA_STATUS,
IDC_TXT_QUOTA_STATUS_LABEL, DWORD(-1),
IDC_CBX_ENABLE_QUOTA, IDH_CBX_ENABLE_QUOTA,
IDC_CBX_DENY_LIMIT, IDH_CBX_DENY_LIMIT,
IDC_RBN_DEF_NOLIMIT, IDH_RBN_DEF_NO_LIMIT,
IDC_RBN_DEF_LIMIT, IDH_RBN_DEF_LIMIT,
IDC_EDIT_DEF_LIMIT, IDH_EDIT_DEF_LIMIT,
IDC_EDIT_DEF_THRESHOLD, IDH_EDIT_DEF_THRESHOLD,
IDC_CMB_DEF_LIMIT, IDH_CMB_DEF_LIMIT,
IDC_CMB_DEF_THRESHOLD, IDH_CMB_DEF_THRESHOLD,
IDC_BTN_DETAILS, IDH_BTN_DETAILS,
IDC_BTN_EVENTLOG, IDH_BTN_EVENTLOG,
IDC_CBX_LOG_OVERWARNING, IDH_CBX_LOG_OVERWARNING,
IDC_CBX_LOG_OVERLIMIT, IDH_CBX_LOG_OVERLIMIT,
IDC_TXT_DEFAULTS, IDH_GRP_DEFAULTS,
IDC_TXT_LOGGING, DWORD(-1),
IDC_TXT_WARN_LEVEL, DWORD(-1),
0,0
};
#pragma data_seg()
#ifdef POLICY_MMC_SNAPIN
const TCHAR c_szSnapInPrefs[] = TEXT("GPTEditorExtData");
#endif
extern TCHAR c_szWndClassDetailsView[]; // defined in details.cpp
/*
// NOTE: This code has been disabled.
// I've left in case we decide to launch the event viewer from
// the volume prop page again. [brianau - 3/23/98]
//
const TCHAR c_szVerbOpen[] = TEXT("Open");
const TCHAR c_szManagementConsole[] = TEXT("MMC.EXE");
const TCHAR c_szMMCInitFile[] = TEXT("%SystemRoot%\\System32\\EVENTVWR.MSC");
*/
#define VPPM_FOCUS_ON_THRESHOLDEDIT (WM_USER + 1)
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::VolumePropPage
Description: Constructor for a volume property page object.
Initializes the members that hold volume quota data.
Arguments: None.
Returns: Nothing.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VolumePropPage::VolumePropPage(VOID)
: m_dwQuotaState(0),
m_dwQuotaLogFlags(0),
m_idStatusUpdateTimer(0),
m_dwLastStatusMsgID(0),
m_cVolumeMaxBytes(NOLIMIT),
m_pxbDefaultLimit(NULL),
m_pxbDefaultThreshold(NULL),
m_llDefaultQuotaThreshold(0),
m_llDefaultQuotaLimit(0),
m_idCtlNextFocus(-1)
{
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::~VolumePropPage
Description: Destructor for a volume property page object.
Arguments: None.
Returns: Nothing.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VolumePropPage::~VolumePropPage(
VOID
)
{
delete m_pxbDefaultLimit;
delete m_pxbDefaultThreshold;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::DlgProc
Description: Static method called by windows to process messages for the
property page dialog. Since it's static, we have to save the "this"
pointer in the window's USERDATA.
Arguments: Standard WndProc-type arguments.
Returns: Standard WndProc-type return values.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR APIENTRY
VolumePropPage::DlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
INT_PTR bResult = FALSE;
//
// Retrieve the "this" pointer from the dialog's userdata.
// It was placed there in OnInitDialog().
//
VolumePropPage *pThis = (VolumePropPage *)GetWindowLongPtr(hDlg, DWLP_USER);
try
{
switch(message)
{
case WM_INITDIALOG:
{
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_INITDIALOG")));
PROPSHEETPAGE *pPage = (PROPSHEETPAGE *)lParam;
pThis = (VolumePropPage *)pPage->lParam;
DBGASSERT((NULL != pThis));
//
// pThis pointer AddRef'd in AddPages().
// Save it in the window's userdata.
//
SetWindowLongPtr(hDlg, DWLP_USER, (INT_PTR)pThis);
bResult = pThis->OnInitDialog(hDlg, wParam, lParam);
break;
}
case WM_SYSCOLORCHANGE:
bResult = pThis->m_TrafficLight.ForwardMessage(message, wParam, lParam);
break;
case WM_NOTIFY:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_NOTIFY")));
bResult = pThis->OnNotify(hDlg, wParam, lParam);
break;
case WM_COMMAND:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_COMMAND")));
bResult = pThis->OnCommand(hDlg, wParam, lParam);
break;
case WM_HELP:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_HELP")));
bResult = pThis->OnHelp(hDlg, wParam, lParam);
break;
case WM_CONTEXTMENU:
bResult = pThis->OnContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
break;
case WM_DESTROY:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_DESTROY")));
pThis->KillStatusUpdateTimer(hDlg);
//
// Nothing to do.
//
break;
case WM_TIMER:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_TIMER")));
bResult = pThis->OnTimer(hDlg, wParam, lParam);
break;
case VPPM_FOCUS_ON_THRESHOLDEDIT:
//
// This is sort of a hack because of the way the prop sheet
// code in comctl32 sets focus after a page has returned
// PSNRET_INVALID. It automatically activates the problem
// page and sets focus to the FIRST control in the tab order.
// Since the only failure we generate is from the threshold
// exceeding the limit, I want to return focus to the threshold
// edit control so that the user can directly change the offending
// value. Posting this custom message was the only way I
// could get this to work. [brianau].
//
SetFocus((HWND)lParam);
SendMessage((HWND)lParam, EM_SETSEL, 0, -1);
break;
default:
break;
}
}
catch(CAllocException& me)
{
//
// Announce any out-of-memory errors associated with running the
// volume Quota property page.
//
DiskQuotaMsgBox(GetDesktopWindow(),
IDS_OUTOFMEMORY,
IDS_TITLE_DISK_QUOTA,
MB_ICONERROR | MB_OK);
}
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnInitDialog
Description: Handler for WM_INITDIALOG.
Arguments:
hDlg - Dialog window handle.
wParam - Handle of control to receive focus if we return FALSE.
lParam - Pointer to PROPSHEETPAGE structure for the property page.
Returns:
TRUE = Tells windows to assign focus to the control in wParam.
Exceptions: OutOfMemory.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
02/10/98 Converted from static to a virtual function to BrianAu
support addition of SnapInVolPropPage class.
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnInitDialog(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
HRESULT hResult = NO_ERROR;
DWORD dwSectorsPerCluster = 0;
DWORD dwBytesPerSector = 0;
DWORD dwFreeClusters = 0;
DWORD dwTotalClusters = 0;
//
// Load the volume's quota information into member variables.
//
hResult = RefreshCachedVolumeQuotaInfo();
//
// Calculate the volume's size.
// We'll use this to limit user threshold and quota limit entries.
//
if (GetDiskFreeSpace(m_idVolume.ForParsing(),
&dwSectorsPerCluster,
&dwBytesPerSector,
&dwFreeClusters,
&dwTotalClusters))
{
m_cVolumeMaxBytes = (UINT64)dwSectorsPerCluster *
(UINT64)dwBytesPerSector *
(UINT64)dwTotalClusters;
}
//
// Create the XBytes objects to manage the relationship between the
// limit/threshold edit controls and their combo boxes.
//
m_pxbDefaultLimit = new XBytes(hDlg,
IDC_EDIT_DEF_LIMIT,
IDC_CMB_DEF_LIMIT,
m_llDefaultQuotaLimit);
m_pxbDefaultThreshold = new XBytes(hDlg,
IDC_EDIT_DEF_THRESHOLD,
IDC_CMB_DEF_THRESHOLD,
m_llDefaultQuotaThreshold);
m_TrafficLight.Initialize(GetDlgItem(hDlg, IDC_TRAFFIC_LIGHT), IDR_AVI_TRAFFIC);
InitializeControls(hDlg);
return TRUE; // Set focus to default control.
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnCommand
Description: Handler for WM_COMMAND.
Arguments:
hDlg - Dialog window handle.
wParam - ID of selected control and notification code.
lParam - HWND of selected control.
Returns:
TRUE = Message wasn't handled.
FALSE = Message was handled.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
08/01/97 Removed IDC_CBX_WARN_THRESHOLD from UI. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnCommand(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
INT_PTR bResult = TRUE;
DWORD dwCtlId = LOWORD(wParam);
HWND hWndCtl = (HWND)lParam;
DWORD dwNotifyCode = HIWORD(wParam);
BOOL bIsChecked = FALSE;
BOOL bEnableApplyBtn = FALSE;
switch(dwCtlId)
{
case IDC_CBX_ENABLE_QUOTA:
{
//
// This is executed when the user checks or unchecks the
// "Enable quota management checkbox.
//
bIsChecked = IsDlgButtonChecked(hDlg, IDC_CBX_ENABLE_QUOTA);
//
// Remember: Limit/Threshold Edit and combo boxes are enabled/disabled
// through XBytes::SetBytes().
//
m_pxbDefaultLimit->SetBytes(m_llDefaultQuotaLimit);
m_pxbDefaultThreshold->SetBytes(m_llDefaultQuotaThreshold);
CheckDlgButton(hDlg, IDC_RBN_DEF_NOLIMIT, NOLIMIT == m_pxbDefaultLimit->GetBytes());
CheckDlgButton(hDlg, IDC_RBN_DEF_LIMIT, BST_CHECKED != IsDlgButtonChecked(hDlg, IDC_RBN_DEF_NOLIMIT));
CheckDlgButton(hDlg, IDC_CBX_DENY_LIMIT, bIsChecked && DISKQUOTA_IS_ENFORCED(m_dwQuotaState));
CheckDlgButton(hDlg,
IDC_CBX_LOG_OVERWARNING,
bIsChecked &&
DISKQUOTA_IS_LOGGED_USER_THRESHOLD(m_dwQuotaLogFlags));
CheckDlgButton(hDlg,
IDC_CBX_LOG_OVERLIMIT,
bIsChecked &&
DISKQUOTA_IS_LOGGED_USER_LIMIT(m_dwQuotaLogFlags));
EnableControls(hDlg);
bEnableApplyBtn = TRUE;
bResult = FALSE;
break;
}
case IDC_CBX_DENY_LIMIT:
bResult = FALSE;
bEnableApplyBtn = TRUE;
break;
case IDC_RBN_DEF_NOLIMIT:
DBGASSERT((IsDlgButtonChecked(hDlg, IDC_CBX_ENABLE_QUOTA)));
if (m_pxbDefaultLimit->IsEnabled())
{
m_pxbDefaultThreshold->SetBytes(NOLIMIT);
m_pxbDefaultLimit->SetBytes(NOLIMIT);
bEnableApplyBtn = TRUE;
}
bResult = FALSE;
break;
case IDC_RBN_DEF_LIMIT:
//
// If the original threshold was -1 (no limit), set to 0.
// Otherwise, set to the original value.
//
DBGASSERT((IsDlgButtonChecked(hDlg, IDC_CBX_ENABLE_QUOTA)));
if (!m_pxbDefaultLimit->IsEnabled())
{
m_pxbDefaultLimit->SetBytes(NOLIMIT == m_llDefaultQuotaLimit ?
0 : m_llDefaultQuotaLimit);
m_pxbDefaultThreshold->SetBytes(NOLIMIT == m_llDefaultQuotaThreshold ?
0 : m_llDefaultQuotaThreshold);
EnableControls(hDlg);
bEnableApplyBtn = TRUE;
}
bResult = FALSE;
break;
case IDC_EDIT_DEF_LIMIT:
case IDC_EDIT_DEF_THRESHOLD:
switch(dwNotifyCode)
{
case EN_UPDATE:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc; WM_COMMAND, EN_CHANGE")));
bResult = OnEditNotifyUpdate(hDlg, wParam, lParam);
bEnableApplyBtn = TRUE;
break;
case EN_KILLFOCUS:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc; WM_COMMAND, EN_KILLFOCUS")));
bResult = OnEditNotifyKillFocus(hDlg, wParam, lParam);
break;
case EN_SETFOCUS:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc; WM_COMMAND, EN_SETFOCUS")));
bResult = OnEditNotifySetFocus(hDlg, wParam, lParam);
break;
default:
break;
}
break;
case IDC_CMB_DEF_LIMIT:
case IDC_CMB_DEF_THRESHOLD:
switch(dwNotifyCode)
{
case CBN_SELCHANGE:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_COMMAND, CBN_CHANGE")));
bResult = OnComboNotifySelChange(hDlg, wParam, lParam);
bEnableApplyBtn = TRUE;
break;
default:
break;
}
break;
case IDC_BTN_DETAILS:
bResult = OnButtonDetails(hDlg, wParam, lParam);
break;
case IDC_CBX_LOG_OVERLIMIT:
case IDC_CBX_LOG_OVERWARNING:
bEnableApplyBtn = TRUE;
break;
/*
//
// NOTE: This code disabled until we decide to launch the event viewer
// from the volume prop page. Probably won't happen because we
// can't define a quota-specific error type for NT events.
// If we can't filter an event viewer list on quota-only events,
// there's not much use in getting to the event viewer from here.
// [brianau - 3/23/98]
//
case IDC_BTN_EVENTLOG:
bResult = OnButtonEventLog(hDlg, wParam, lParam);
break;
*/
default:
break;
}
if (bEnableApplyBtn)
PropSheet_Changed(GetParent(hDlg), hDlg);
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnNotify
Description: Handler for WM_NOTIFY.
Arguments:
hDlg - Dialog window handle.
wParam - ID of selected control and notification code.
lParam - HWND of selected control.
Returns:
TRUE = Message wasn't handled.
FALSE = Message was handled.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnNotify(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
DBGTRACE((DM_VPROP, DL_MID, TEXT("VolumePropPage::OnNotify")));
INT_PTR bResult = TRUE;
switch(((NMHDR *)lParam)->code)
{
case PSN_SETACTIVE:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_NOTIFY, PSN_SETACTIVE")));
bResult = OnSheetNotifySetActive(hDlg, wParam, lParam);
break;
case PSN_APPLY:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_NOTIFY, PSN_APPLY")));
bResult = OnSheetNotifyApply(hDlg, wParam, lParam);
break;
case PSN_KILLACTIVE:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_NOTIFY, PSN_KILLACTIVE")));
bResult = OnSheetNotifyKillActive(hDlg, wParam, lParam);
break;
case PSN_RESET:
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_NOTIFY, PSN_RESET")));
bResult = OnSheetNotifyReset(hDlg, wParam, lParam);
break;
default:
break;
}
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnSheetNotifySetActive
Description: Handler for WM_NOTIFY - PSN_SETACTIVE.
Arguments:
hDlg - Dialog window handle.
wParam - ID of control.
lParam - Address of NMHDR structure.
Returns:
FALSE = Accept activation.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnSheetNotifySetActive(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("VolumePropPage::OnSheetNotifySetActive")));
//
// Update the status text and set the status update timer.
//
UpdateStatusIndicators(hDlg);
SetStatusUpdateTimer(hDlg);
if (IDC_EDIT_DEF_THRESHOLD == m_idCtlNextFocus)
{
//
// Focus is being set as a result of an invalid entry
// in the warning level field. Force input focus to the
// field and select the entire contents. User can then just
// enter a new value.
//
PostMessage(hDlg,
VPPM_FOCUS_ON_THRESHOLDEDIT,
0,
(LPARAM)GetDlgItem(hDlg, IDC_EDIT_DEF_THRESHOLD));
m_idCtlNextFocus = -1;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnSheetNotifyApply
Description: Handler for WM_NOTIFY - PSN_APPLY.
Arguments:
hDlg - Dialog window handle.
wParam - ID of control.
lParam - Address of NMHDR structure.
Returns:
TRUE = PSN return value set using SetWindowLong.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnSheetNotifyApply(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("VolumePropPage::OnSheetNotifyApply")));
HRESULT hResult = NO_ERROR;
LONG dwPSNReturn = PSNRET_NOERROR;
INT idMsg = -1;
if (!IsDlgButtonChecked(hDlg, IDC_CBX_ENABLE_QUOTA) &&
!DISKQUOTA_IS_DISABLED(m_dwQuotaState))
{
idMsg = IDS_DISABLE_QUOTA_WARNING;
}
else if (IsDlgButtonChecked(hDlg, IDC_CBX_ENABLE_QUOTA) &&
DISKQUOTA_IS_DISABLED(m_dwQuotaState))
{
idMsg = IDS_ENABLE_QUOTA_WARNING;
}
if (-1 != idMsg)
{
//
// User wants to disable or enable quotas.
// Warn about what this means and let them know that
// re-activation of quotas requires a quota file rebuild.
//
if (IDCANCEL == DiskQuotaMsgBox(hDlg,
idMsg,
IDS_TITLE_DISK_QUOTA,
MB_ICONWARNING | MB_OKCANCEL))
{
//
// User decided to not continue the action.
// Restore the checkbox to it's previous setting and abort the
// settings change.
// Sending the message to our DlgProc resets the dependent controls
// to their proper states.
//
CheckDlgButton(hDlg,
IDC_CBX_ENABLE_QUOTA,
!IsDlgButtonChecked(hDlg, IDC_CBX_ENABLE_QUOTA));
SendMessage(hDlg,
WM_COMMAND,
(WPARAM)MAKELONG((WORD)IDC_CBX_ENABLE_QUOTA, (WORD)0),
(LPARAM)GetDlgItem(hDlg, IDC_CBX_ENABLE_QUOTA));
dwPSNReturn = PSNRET_INVALID;
}
}
if (PSNRET_NOERROR == dwPSNReturn)
{
//
// We need to do this because if you activate the apply button
// with Alt-A we receive PSN_APPLY before EN_KILLFOCUS.
//
m_pxbDefaultThreshold->OnEditKillFocus((LPARAM)GetDlgItem(hDlg, IDC_EDIT_DEF_THRESHOLD));
m_pxbDefaultLimit->OnEditKillFocus((LPARAM)GetDlgItem(hDlg, IDC_EDIT_DEF_LIMIT));
//
// Ensure warning threshold is not above limit.
//
INT64 iThreshold = m_pxbDefaultThreshold->GetBytes();
INT64 iLimit = m_pxbDefaultLimit->GetBytes();
if (iThreshold > iLimit)
{
TCHAR szLimit[40], szThreshold[40];
XBytes::FormatByteCountForDisplay(iLimit, szLimit, ARRAYSIZE(szLimit));
XBytes::FormatByteCountForDisplay(iThreshold, szThreshold, ARRAYSIZE(szThreshold));
CString s(g_hInstDll, IDS_FMT_ERR_WARNOVERLIMIT, szThreshold, szLimit, szLimit);
switch(DiskQuotaMsgBox(hDlg, s, IDS_TITLE_DISK_QUOTA, MB_ICONWARNING | MB_YESNO))
{
case IDYES:
m_pxbDefaultThreshold->SetBytes(iLimit);
break;
case IDNO:
m_idCtlNextFocus = IDC_EDIT_DEF_THRESHOLD;
dwPSNReturn = PSNRET_INVALID;
break;
}
}
}
if (PSNRET_NOERROR == dwPSNReturn)
{
hResult = ApplySettings(hDlg);
if (FAILED(hResult))
{
DiskQuotaMsgBox(hDlg,
IDS_APPLY_SETTINGS_ERROR,
IDS_TITLE_DISK_QUOTA,
MB_ICONERROR | MB_OK);
dwPSNReturn = PSNRET_INVALID;
InitializeControls(hDlg);
}
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, dwPSNReturn);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnSheetNotifyKillActive
Description: Handler for WM_NOTIFY - PSN_KILLACTIVE.
Arguments:
hDlg - Dialog window handle.
wParam - ID of control.
lParam - Address of NMHDR structure.
Returns:
TRUE = Invalid data entered. Don't kill page.
FALSE = All data is valid. Ok to kill page.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnSheetNotifyKillActive(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("VolumePropPage::OnSheetNotifyKillActive")));
BOOL bAllDataIsValid = TRUE;
if (bAllDataIsValid)
{
KillStatusUpdateTimer(hDlg);
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, !bAllDataIsValid);
//
// Must release quota controller whenever the sheet is deactivated.
// Without this we were holding open a handle to the volume. This prevented
// the disk check utility ("Tools" page) from accessing the volume.
// Whenever we need an IDiskQuotaControl ptr we call GetQuotaController which
// will create a new controller if necessary.
//
if (NULL != m_pQuotaControl)
{
m_pQuotaControl->Release();
m_pQuotaControl = NULL;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnSheetNotifyReset
Description: Handler for WM_NOTIFY - PSN_RESET.
Arguments:
hDlg - Dialog window handle.
wParam - ID of control.
lParam - Address of NMHDR structure.
Returns:
No return value.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnSheetNotifyReset(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("VolumePropPage::OnSheetNotifyReset")));
HRESULT hResult = NO_ERROR;
//
// Nothing to do right now.
//
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnHelp
Description: Handler for WM_HELP. Displays context sensitive help.
Arguments:
lParam - Pointer to a HELPINFO structure.
Returns: TRUE;
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/17/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnHelp(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, STR_DSKQUOUI_HELPFILE,
HELP_WM_HELP, (DWORD_PTR)(LPTSTR) rgVolumePropPageHelpIDs);
return TRUE;
}
INT_PTR
VolumePropPage::OnContextMenu(
HWND hwndItem,
int xPos,
int yPos
)
{
int idCtl = GetDlgCtrlID(hwndItem);
WinHelp(hwndItem,
UseWindowsHelp(idCtl) ? NULL : STR_DSKQUOUI_HELPFILE,
HELP_CONTEXTMENU,
(DWORD_PTR)((LPTSTR)rgVolumePropPageHelpIDs));
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnTimer
Description: Handler for WM_TIMER. Updates the quota status text and
traffic light.
Arguments:
wParam - Timer ID.
Returns: FALSE (0);
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/17/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnTimer(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
if (wParam == m_idStatusUpdateTimer)
{
UpdateStatusIndicators(hDlg);
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnEditNotifyUpdate
Description: Handler for WM_COMMAND, EN_UPDATE.
Called whenever a character is entered in an edit control.
Arguments:
Returns: FALSE;
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/17/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnEditNotifyUpdate(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
XBytes *rgpxb[2] = { m_pxbDefaultLimit, m_pxbDefaultThreshold };
const int iLIMIT = 0;
const int iTHRESHOLD = 1;
int iCurrent = iLIMIT;
if (IDC_EDIT_DEF_THRESHOLD == LOWORD(wParam))
iCurrent = iTHRESHOLD;
if (NULL != rgpxb[iCurrent])
rgpxb[iCurrent]->OnEditNotifyUpdate(lParam);
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnEditNotifyKillFocus
Description: Handler for WM_COMMAND, EN_KILLFOCUS.
Called whenever focus leaves an edit control.
Validates the value in the edit control and adjusts it if necessary.
Arguments:
Returns: FALSE;
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/17/96 Initial creation. BrianAu
11/12/98 Added code to call XBytes::OnEditKillFocus. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnEditNotifyKillFocus(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
XBytes *rgpxb[2] = { m_pxbDefaultLimit, m_pxbDefaultThreshold };
const int iLIMIT = 0;
const int iTHRESHOLD = 1;
int iCurrent = iLIMIT;
if (IDC_EDIT_DEF_THRESHOLD == LOWORD(wParam))
iCurrent = iTHRESHOLD;
if (NULL != rgpxb[iCurrent])
rgpxb[iCurrent]->OnEditKillFocus(lParam);
return FALSE;
}
INT_PTR
VolumePropPage::OnEditNotifySetFocus(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
//
// Nothing to do.
// FEATURE: Delete this method?
//
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnComboNotifySelChange
Description: Handler for WM_COMMAND, CBN_SELCHANGE.
Called whenever the user selects the combo box.
Arguments: Std DlgProc args.
Returns: FALSE;
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/17/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnComboNotifySelChange(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
XBytes *rgpxb[2] = { m_pxbDefaultLimit, m_pxbDefaultThreshold };
const int iLIMIT = 0;
const int iTHRESHOLD = 1;
int iCurrent = iLIMIT;
if (IDC_CMB_DEF_THRESHOLD == LOWORD(wParam))
iCurrent = iTHRESHOLD;
if (NULL != rgpxb[iCurrent])
rgpxb[iCurrent]->OnComboNotifySelChange(lParam);
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnButtonDetails
Description: Called when the user selects the "Details" button.
If a details view is already active for this prop page, it is brought
to the foreground. If no details view is already active, a new one
is created.
Arguments: Standard DlgProc arguments.
Returns:
Exceptions: OutOfMemory.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT_PTR
VolumePropPage::OnButtonDetails(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
if (!ActivateExistingDetailsView())
{
//
// This property page doesn't have an active details view.
// Create one. Note: If something fails in the details view
// creation, it isn't displayed. The DetailsView code is
// responsible for reporting any errors to the user.
//
// NOTE: The VolumePropPage object never calls "delete"
// on the pDetailsView pointer. The details view
// object must live on it's own (modeless) after it is created.
// If the VolumePropPage object (this object) is still alive
// when the details view object is destroyed, it will receive a
// WM_DETAILS_VIEW_DESTROYED message from the view object. That's
// why we pass the hDlg in this constructor. When this message
// is received, we set m_pDetailsView to NULL so that OnButtonDetails
// will know to create a new view object.
//
DetailsView *pDetailsView = new DetailsView;
if (!pDetailsView->Initialize(m_idVolume))
{
//
// Something failed. Either out of memory or the view's thread
// couldn't start. Either way, the view won't run.
// Need to call delete to clean up any partially-completed initialization.
//
delete pDetailsView;
}
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::OnButtonEventLog
Description: Called when the user selects the "Event Log" button.
Invokes the NT Event Viewer application.
Arguments: Standard DlgProc arguments.
Returns:
Exceptions: OutOfMemory.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
10/14/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
#ifdef __NEVER__
//
// NOTE: This code has been disabled. I just left it in case we ever
// decide to launch the event viewer from the volume prop page again.
// [brianan - 3/23/98]
//
/*
INT_PTR
VolumePropPage::OnButtonEventLog(
HWND hDlg,
WPARAM wParam,
LPARAM lParam
)
{
//
// Expand the %SystemRoot% env var in the path to the MMC
// initialization file (Event viewer).
//
CString strMMCInitFile(c_szMMCInitFile);
strMMCInitFile.ExpandEnvironmentStrings();
HINSTANCE SEhInstance = ShellExecute(hDlg,
c_szVerbOpen,
c_szManagementConsole,
strMMCInitFile,
NULL,
SW_SHOWNORMAL);
if ((DWORD)SEhInstance <= 32)
{
//
// Something failed.
//
INT iMsg = 0;
switch((DWORD)SEhInstance)
{
case 0:
throw CAllocException();
break;
case ERROR_FILE_NOT_FOUND:
iMsg = IDS_ERROR_FILE_NOT_FOUND;
break;
case ERROR_BAD_FORMAT:
iMsg = IDS_ERROR_FILE_CORRUPT;
break;
case SE_ERR_DDEBUSY:
case SE_ERR_DDEFAIL:
case SE_ERR_DDETIMEOUT:
iMsg = IDS_ERROR_DDE_EXECUTE;
break;
default:
//
// The rest of the ShellExecute errors shouldn't happen
// in this situation.
//
break;
}
if (0 != iMsg)
{
//
// Display error message.
// Note that this assumes error string resources have a %1 embedded
// for displaying the filename. If they don't, the following
// logic will need to be changed.
//
CString strMsg(g_hInstDll, iMsg, c_szManagementConsole);
DiskQuotaMsgBox(GetDesktopWindow(),
strMsg,
IDS_TITLE_DISK_QUOTA,
MB_ICONERROR | MB_OK);
}
}
return 0;
}
*/
#endif // __NEVER__
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::ActivateExistingDetailsView
Description: Called by OnButtonDetails to see if there's already a details
view active for this volume. If there is, open it.
Arguments: None.
Returns:
TRUE = Existing details view was found and promoted to the foreground.
FALSE = Either no existing view was found or an existing one could
not be promoted to the foreground.
Exceptions: OutOfMemory.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
02/25/97 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
VolumePropPage::ActivateExistingDetailsView(
VOID
) const
{
BOOL bResult = FALSE;
CString strVolDisplayName;
DetailsView::CreateVolumeDisplayName(m_idVolume, &strVolDisplayName);
CString strDetailsViewTitle(g_hInstDll, IDS_TITLE_MAINWINDOW, (LPCTSTR)strVolDisplayName);
HWND hwndDetailsView = FindWindow(c_szWndClassDetailsView,
strDetailsViewTitle);
if (NULL != hwndDetailsView)
{
//
// Restore the details view and bring it to the front.
//
ShowWindow(hwndDetailsView, SW_RESTORE);
bResult = SetForegroundWindow(hwndDetailsView);
}
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::ApplySettings
Description: Applies the current settings to the volume if they have
changed from the original settings.
Arguments:
hDlg - Dialog window handle.
Returns:
NO_ERROR - Success.
E_INVALIDARG - One of the settings was invalid.
ERROR_ACCESS_DENIED (hr) - No WRITE access to quota device.
E_FAIL - Any other error.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
VolumePropPage::ApplySettings(
HWND hDlg
)
{
HRESULT hResult = NO_ERROR;
DWORD dwStateSetting = 0;
DWORD dwLogFlagSettings = m_dwQuotaLogFlags;
BOOL bTranslated = FALSE;
LONGLONG llThreshold;
LONGLONG llLimit;
IDiskQuotaControl *pqc;
hResult = GetQuotaController(&pqc);
if (SUCCEEDED(hResult))
{
//
// Set quota state if changed.
//
QuotaStateFromControls(hDlg, &dwStateSetting);
if (dwStateSetting != (m_dwQuotaState & DISKQUOTA_STATE_MASK))
{
hResult = pqc->SetQuotaState(dwStateSetting);
if (FAILED(hResult))
goto apply_failed;
m_dwQuotaState = dwStateSetting;
}
//
// Set quota log flags if changed.
//
LogFlagsFromControls(hDlg, &dwLogFlagSettings);
if (dwLogFlagSettings != m_dwQuotaLogFlags)
{
hResult = pqc->SetQuotaLogFlags(dwLogFlagSettings);
if (FAILED(hResult))
goto apply_failed;
m_dwQuotaLogFlags = dwLogFlagSettings;
}
//
// Get current default quota threshold and limit values.
//
if (IsDlgButtonChecked(hDlg, IDC_RBN_DEF_NOLIMIT))
{
llThreshold = NOLIMIT;
llLimit = NOLIMIT;
}
else
{
llThreshold = m_pxbDefaultThreshold->GetBytes();
llLimit = m_pxbDefaultLimit->GetBytes();
}
//
// Set default quota threshold if changed.
//
if (llThreshold != m_llDefaultQuotaThreshold)
{
hResult = pqc->SetDefaultQuotaThreshold(llThreshold);
if (FAILED(hResult))
goto apply_failed;
m_llDefaultQuotaThreshold = llThreshold;
}
//
// Set default quota limit if changed.
//
if (llLimit != m_llDefaultQuotaLimit)
{
hResult = pqc->SetDefaultQuotaLimit(llLimit);
if (FAILED(hResult))
goto apply_failed;
m_llDefaultQuotaLimit = llLimit;
}
apply_failed:
pqc->Release();
}
return hResult;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::RefreshCachedVolumeInfo
Description: Reads the volume's quota information and stores it in
member variables.
Arguments: None.
Returns:
NO_ERROR - Success.
ERROR_ACCESS_DENIED (hr) - No READ access to quota device.
E_FAIL - Any other error.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
VolumePropPage::RefreshCachedVolumeQuotaInfo(
VOID
)
{
HRESULT hResult = NO_ERROR;
IDiskQuotaControl *pqc;
hResult = GetQuotaController(&pqc);
if (SUCCEEDED(hResult))
{
//
// Read quota state.
//
hResult = pqc->GetQuotaState(&m_dwQuotaState);
if (FAILED(hResult))
goto refresh_vol_info_failed;
//
// Read quota log flags.
//
hResult = pqc->GetQuotaLogFlags(&m_dwQuotaLogFlags);
if (FAILED(hResult))
goto refresh_vol_info_failed;
//
// Read default quota threshold.
//
hResult = pqc->GetDefaultQuotaThreshold(&m_llDefaultQuotaThreshold);
if (FAILED(hResult))
goto refresh_vol_info_failed;
//
// Read default quota limit.
//
hResult = pqc->GetDefaultQuotaLimit(&m_llDefaultQuotaLimit);
refresh_vol_info_failed:
pqc->Release();
}
return hResult;
}
//
// Determine if a given disk quota policy value is set.
//
bool
VolumePropPage::SetByPolicy(
LPCTSTR pszPolicyValue
)
{
DWORD dwData;
DWORD dwType;
DWORD cbData = sizeof(dwData);
return (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE,
REGSTR_KEY_POLICYDATA,
pszPolicyValue,
&dwType,
&dwData,
&cbData));
}
HRESULT
VolumePropPage::EnableControls(
HWND hwndDlg
)
{
BOOL bQuotaEnabled = (BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CBX_ENABLE_QUOTA));
BOOL bEnable;
//
// "Enable quota management" checkbox.
//
// Policy Quota Enabled Ctl Enabled
// 0 0 1
// 0 1 1
// 1 0 0
// 1 1 0
//
EnableWindow(GetDlgItem(hwndDlg, IDC_CBX_ENABLE_QUOTA),
!SetByPolicy(REGSTR_VAL_POLICY_ENABLE));
//
// "Deny disk space..." checkbox.
//
// Policy Quota Enabled Ctl Enabled
// 0 0 0
// 0 1 1
// 1 0 0
// 1 1 0
//
EnableWindow(GetDlgItem(hwndDlg, IDC_CBX_DENY_LIMIT),
bQuotaEnabled && !SetByPolicy(REGSTR_VAL_POLICY_ENFORCE));
//
// Log event checkboxes
//
// Policy Quota Enabled Ctl Enabled
// 0 0 0
// 0 1 1
// 1 0 0
// 1 1 0
//
EnableWindow(GetDlgItem(hwndDlg, IDC_CBX_LOG_OVERLIMIT),
bQuotaEnabled && !SetByPolicy(REGSTR_VAL_POLICY_LOGLIMIT));
EnableWindow(GetDlgItem(hwndDlg, IDC_CBX_LOG_OVERWARNING),
bQuotaEnabled && !SetByPolicy(REGSTR_VAL_POLICY_LOGTHRESHOLD));
//
// "Do not limit disk usage" radio button
// "Limit disk space to" radio button
//
// Policy Quota Enabled No Limit Ctl Enabled
// 0 0 0 0
// 0 0 1 0
// 0 1 0 0
// 0 1 1 1
// 1 0 0 0
// 1 0 1 0
// 1 1 0 0
// 1 1 1 0
//
bEnable = bQuotaEnabled && !SetByPolicy(REGSTR_VAL_POLICY_LIMIT);
EnableWindow(GetDlgItem(hwndDlg, IDC_RBN_DEF_NOLIMIT), bEnable);
EnableWindow(GetDlgItem(hwndDlg, IDC_RBN_DEF_LIMIT), bEnable);
//
// "Limit disk space" edit and combo controls.
//
// Policy Quota Enabled No Limit Ctl Enabled
// 0 0 0 0
// 0 0 1 0
// 0 1 0 1
// 0 1 1 0
// 1 0 0 0
// 1 0 1 0
// 1 1 0 0
// 1 1 1 0
//
bEnable = bQuotaEnabled &&
!SetByPolicy(REGSTR_VAL_POLICY_LIMIT) &&
NOLIMIT != m_pxbDefaultLimit->GetBytes();
EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_DEF_LIMIT), bEnable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CMB_DEF_LIMIT), bEnable);
bEnable = bQuotaEnabled &&
!SetByPolicy(REGSTR_VAL_POLICY_THRESHOLD) &&
NOLIMIT != m_pxbDefaultThreshold->GetBytes();
EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_WARN_LEVEL), bEnable);
EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_DEF_THRESHOLD), bEnable);
EnableWindow(GetDlgItem(hwndDlg, IDC_CMB_DEF_THRESHOLD), bEnable);
//
// Miscellaneous text controls.
//
// Quota Enabled Ctl Enabled
// 0 0
// 1 1
//
EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_DEFAULTS), bQuotaEnabled);
EnableWindow(GetDlgItem(hwndDlg, IDC_TXT_LOGGING), bQuotaEnabled);
return NOERROR;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::InitializeControls
Description: Initializes the page controls based on the volume's
quota settings.
Arguments:
hDlg - Dialog window handle.
Returns:
NO_ERROR - Always returns NO_ERROR.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/15/96 Initial creation. BrianAu
08/01/97 Removed IDC_CBX_WARN_THRESHOLD from UI. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
VolumePropPage::InitializeControls(
HWND hDlg
)
{
BOOL bQuotaEnabled = !(DISKQUOTA_IS_DISABLED(m_dwQuotaState));
BOOL bUnlimited = (NOLIMIT == m_llDefaultQuotaLimit);
CheckDlgButton(hDlg,
IDC_CBX_ENABLE_QUOTA,
bQuotaEnabled);
CheckDlgButton(hDlg,
IDC_CBX_DENY_LIMIT,
DISKQUOTA_IS_ENFORCED(m_dwQuotaState));
CheckDlgButton(hDlg,
IDC_CBX_LOG_OVERWARNING,
!DISKQUOTA_IS_DISABLED(m_dwQuotaState) &&
DISKQUOTA_IS_LOGGED_USER_THRESHOLD(m_dwQuotaLogFlags));
CheckDlgButton(hDlg,
IDC_CBX_LOG_OVERLIMIT,
!DISKQUOTA_IS_DISABLED(m_dwQuotaState) &&
DISKQUOTA_IS_LOGGED_USER_LIMIT(m_dwQuotaLogFlags));
CheckDlgButton(hDlg, IDC_RBN_DEF_NOLIMIT, bUnlimited);
CheckDlgButton(hDlg, IDC_RBN_DEF_LIMIT, !bUnlimited);
EnableControls(hDlg);
return NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::UpdateStatusIndicators
Description: Updates the "Status" text message at the top of the property
page according to the actual quota system state. Also updates the
traffic light AVI clip.
Arguments:
hDlg - Dialog handle.
Returns:
Always returns NO_ERROR.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/18/96 Initial creation. BrianAu
08/28/96 Added stoplight icon. BrianAu
09/10/96 Converted stoplight from an icon to an AVI clip. BrianAu
Call it a traffic light now.
07/14/97 Removed distinct "enforce" and "tracking" messages BrianAu
and replaced with a single "active" message.
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
VolumePropPage::UpdateStatusIndicators(
HWND hDlg
)
{
HRESULT hResult = NO_ERROR;
DWORD dwMsgID = IDS_STATUS_UNKNOWN;
IDiskQuotaControl *pqc;
hResult = GetQuotaController(&pqc);
if (SUCCEEDED(hResult))
{
//
// Update cached state information.
//
hResult = pqc->GetQuotaState(&m_dwQuotaState);
pqc->Release();
pqc = NULL;
}
if (SUCCEEDED(hResult))
{
//
// Figure out what message to display.
// "Rebuilding" overrides any other state.
//
if (DISKQUOTA_FILE_REBUILDING(m_dwQuotaState))
{
dwMsgID = IDS_STATUS_REBUILDING;
}
else switch(m_dwQuotaState & DISKQUOTA_STATE_MASK)
{
case DISKQUOTA_STATE_DISABLED:
dwMsgID = IDS_STATUS_DISABLED;
break;
case DISKQUOTA_STATE_TRACK:
case DISKQUOTA_STATE_ENFORCE:
dwMsgID = IDS_STATUS_ACTIVE;
break;
default:
break;
}
}
if (dwMsgID != m_dwLastStatusMsgID)
{
//
// Format the status text and configure the traffic light.
//
// Traffic light states:
// RED = Quotas disabled.
// GREEN = Quotas enabled.
// Flashing YELLOW = Quota file is rebuilding.
//
INT iTrafficLightState = TrafficLight::GREEN;
if (DISKQUOTA_FILE_REBUILDING(m_dwQuotaState))
iTrafficLightState = TrafficLight::FLASHING_YELLOW;
else if (DISKQUOTA_IS_DISABLED(m_dwQuotaState))
iTrafficLightState = TrafficLight::RED;
m_TrafficLight.Show(iTrafficLightState);
CString strStatus(g_hInstDll, dwMsgID);
SetWindowText(GetDlgItem(hDlg, IDC_TXT_QUOTA_STATUS), strStatus);
m_dwLastStatusMsgID = dwMsgID;
//
// Re-initialize the controls based on the new state.
//
InitializeControls(hDlg);
}
return NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::QuotaStateFromControls
Description: Determines the quota state from the states of the individual
controls on the page.
Arguments:
hDlg - Dialog's window handle.
pdwState - Address of DWORD variable to receive state bits.
Returns:
Always returns NO_ERROR.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/19/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
VolumePropPage::QuotaStateFromControls(
HWND hDlg,
LPDWORD pdwState
) const
{
DBGASSERT((NULL != pdwState));
//
// Set quota state if changed.
//
if (IsDlgButtonChecked(hDlg, IDC_CBX_ENABLE_QUOTA))
{
if (IsDlgButtonChecked(hDlg, IDC_CBX_DENY_LIMIT))
{
*pdwState = DISKQUOTA_STATE_ENFORCE;
}
else
*pdwState = DISKQUOTA_STATE_TRACK;
}
else
*pdwState = DISKQUOTA_STATE_DISABLED;
return NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::LogFlagsFromControls
Description: Determines the log flags state from the states of the
individual controls on the page.
Arguments:
hDlg - Dialog's window handle.
pdwLogFlags - Address of DWORD variable to receive flag bits.
Returns:
Always returns NO_ERROR.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
08/19/96 Initial creation. BrianAu
08/01/97 Removed IDC_CBX_WARN_THRESHOLD from UI. BrianAu
11/20/98 Added "log over limit" and "log over warning" BrianAu
controls.
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT
VolumePropPage::LogFlagsFromControls(
HWND hDlg,
LPDWORD pdwLogFlags
) const
{
DBGASSERT((NULL != pdwLogFlags));
DISKQUOTA_SET_LOG_USER_LIMIT(*pdwLogFlags,
IsDlgButtonChecked(hDlg, IDC_CBX_LOG_OVERLIMIT));
DISKQUOTA_SET_LOG_USER_THRESHOLD(*pdwLogFlags,
IsDlgButtonChecked(hDlg, IDC_CBX_LOG_OVERWARNING));
return NO_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::TrafficLight::Initialize
Description: Initializes the traffic light by opening the AVI clip.
Arguments:
hwndAnimateCtl - Handle to the animation control in the dialog.
idAviClipRes - Resource ID of the AVI clip resource.
Returns: Nothing. If the thing doesn't load, it just won't play.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
09/10/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
VolumePropPage::TrafficLight::Initialize(
HWND hwndAnimateCtl,
INT idAviClipRes
)
{
DBGASSERT((NULL != hwndAnimateCtl));
m_hwndAnimateCtl = hwndAnimateCtl;
m_idAviClipRes = idAviClipRes;
Animate_Open(m_hwndAnimateCtl, MAKEINTRESOURCE(idAviClipRes));
//
// See note in TrafficLight::Show below.
//
// Animate_SetFrameTime(m_hwndAnimateCtl, GetCaretBlinkTime());
}
///////////////////////////////////////////////////////////////////////////////
/* Function: VolumePropPage::TrafficLight::Show
Description: Shows the traffic light in one of it's states.
Arguments:
eShow - One of the following enumerated constant values:
OFF, YELLOW, RED, GREEN, FLASHING_YELLOW.
NOTE: THIS IS VERY IMPORTANT!!!
The definitions of these constants MUST match as follows
with the frame numbers in the AVI clip TRAFFIC.AVI. If
you change either, it won't work.
Frame Constant Value
------ ---------------- ------
0 OFF 0
1 YELLOW 1
2 RED 2
3 GREEN 3
N/A FLASHING_YELLOW 4
Flashing yellow is created by playing frames 0 and 1
repeatedly.
Returns: Nothing.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
09/10/96 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
VolumePropPage::TrafficLight::Show(
INT eShow
)
{
switch(eShow)
{
case OFF:
case YELLOW:
case RED:
case GREEN:
Animate_Seek(m_hwndAnimateCtl, eShow);
break;
case FLASHING_YELLOW:
Animate_Seek(m_hwndAnimateCtl, YELLOW);
//
// NOTE:
//
// The common control guys didn't want me to add the ACM_SETFRAMETIME
// message so we can't vary the rate of the animation. Since we can't
// have a fixed-rate blinking control, I'm just fixing the traffic light
// at yellow rather than flashing. If we can ever add the frame time
// modification message to the animation control, we can activate
// this functionality. A flashing light isn't worth the trouble of
// a unique implementation. I really wanted this. It looks cool.
//
// FEATURE: If we have time. Make this work without the animation control.
// Note that I tried just setting the icon. But since the volume
// status checking is done on the same thread that processes the
// STM_SETICON messgae, flashing of the icon is erratic.
//
// Animate_Play(m_hwndAnimateCtl, YELLOW, OFF, (UINT)-1);
break;
default:
break;
}
}
INT_PTR
VolumePropPage::TrafficLight::ForwardMessage(
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
return SendMessage(m_hwndAnimateCtl, uMsg, wParam, lParam);
}
#ifdef POLICY_MMC_SNAPIN
SnapInVolPropPage::~SnapInVolPropPage(
void
)
{
if (NULL != m_pPolicy)
m_pPolicy->Release();
}
BOOL
SnapInVolPropPage::OnInitDialog(
HWND hDlg,
UINT wParam,
LONG lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("SnapInVolPropPage::OnInitDialog")));
HRESULT hr = NO_ERROR;
bool bRemovableMedia = false;
//
// Policy object should have already been created and initialized
// by the creator of the property sheet. See CSnapInCompData::PropPageThreadProc.
//
DBGASSERT((NULL != m_pPolicy));
//
// Retrieve and restore the previous dialog state from when the
// user last used the snapin. We use the GPTInfo structure for
// convenience since we're storing the same information that is
// used for setting policy.
//
DISKQUOTAPOLICYINFO dqpi;
RegKey keyPref(HKEY_CURRENT_USER, REGSTR_KEY_DISKQUOTA);
if (SUCCEEDED(keyPref.Open(KEY_READ)) &&
SUCCEEDED(keyPref.GetValue(c_szSnapInPrefs, (LPBYTE)&dqpi, sizeof(dqpi))) &&
sizeof(dqpi) == dqpi.cb)
{
m_llDefaultQuotaLimit = dqpi.llDefaultQuotaLimit;
m_llDefaultQuotaThreshold = dqpi.llDefaultQuotaThreshold;
m_dwQuotaState = dqpi.dwQuotaState;
m_dwQuotaLogFlags = dqpi.dwQuotaLogFlags;
bRemovableMedia = dqpi.bRemovableMedia;
}
else
DBGERROR((TEXT("Error loading policy dialog information")));
//
// Create the XBytes objects to manage the relationship between the
// limit/threshold edit controls and their combo boxes.
//
m_pxbDefaultLimit = new XBytes(hDlg,
IDC_EDIT_DEF_LIMIT,
IDC_CMB_DEF_LIMIT,
m_llDefaultQuotaLimit);
m_pxbDefaultThreshold = new XBytes(hDlg,
IDC_EDIT_DEF_THRESHOLD,
IDC_CMB_DEF_THRESHOLD,
m_llDefaultQuotaThreshold);
InitializeControls(hDlg);
return TRUE; // Set focus to default control.
}
BOOL
SnapInVolPropPage::OnSheetNotifySetActive(
HWND hDlg,
UINT wParam,
LONG lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("SnapInVolPropPage::OnSheetNotifySetActive")));
return FALSE;
}
BOOL
SnapInVolPropPage::OnSheetNotifyApply(
HWND hDlg,
UINT wParam,
LONG lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("SnapInVolPropPage::OnSheetNotifyApply")));
LONG dwPSNReturn = PSNRET_NOERROR;
HRESULT hr = NOERROR;
DWORD dwState, dwLogFlags;
LONGLONG llThreshold, llLimit;
//
// Policy object should have already been created and initialized
// by the creator of the property sheet. See CSnapInCompData::PropPageThreadProc.
//
DBGASSERT((NULL != m_pPolicy));
//
// Query the state of the dialog to get the quota settings.
//
QuotaStateFromControls(hDlg, &dwState);
LogFlagsFromControls(hDlg, &dwLogFlags);
if (IsDlgButtonChecked(hDlg, IDC_RBN_DEF_NOLIMIT))
{
llThreshold = NOLIMIT;
llLimit = NOLIMIT;
}
else
{
llThreshold = m_pxbDefaultThreshold->GetBytes();
llLimit = m_pxbDefaultLimit->GetBytes();
}
DISKQUOTAPOLICYINFO dqpi;
dqpi.cb = sizeof(dqpi);
dqpi.llDefaultQuotaThreshold = llThreshold;
dqpi.llDefaultQuotaLimit = llLimit;
dqpi.dwQuotaState = dwState;
dqpi.dwQuotaLogFlags = dwLogFlags;
dqpi.bRemovableMedia = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RBN_POLICY_REMOVABLE));
//
// Save the policy information to the registry.
//
hr = m_pPolicy->Save(&dqpi);
if (FAILED(hr))
{
DBGERROR((TEXT("Error 0x%08X saving policy information"), hr));
//
// Show some UI?
//
}
//
// Save current dialog state so that we can restore it next time the
// user opens the snapin. This way, if the user typically sets
// quotas to the same values, the UI will appear much more friendly.
//
RegKey keyPref(HKEY_CURRENT_USER, REGSTR_KEY_DISKQUOTA);
if (FAILED(keyPref.Open(KEY_WRITE)) ||
FAILED(keyPref.SetValue(c_szSnapInPrefs, (LPBYTE)&dqpi, sizeof(dqpi))))
{
DBGERROR((TEXT("Error saving policy dialog information")));
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, dwPSNReturn);
return TRUE;
}
BOOL
SnapInVolPropPage::OnSheetNotifyKillActive(
HWND hDlg,
UINT wParam,
LONG lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("SnapInVolPropPage::OnSheetNotifyKillActive")));
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
return TRUE;
}
BOOL
SnapInVolPropPage::OnSheetNotifyReset(
HWND hDlg,
UINT wParam,
LONG lParam
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("SnapInVolPropPage::OnSheetNotifyReset")));
return FALSE;
}
HRESULT
SnapInVolPropPage::CreateDiskQuotaPolicyObject(
IDiskQuotaPolicy **ppOut
)
{
DBGTRACE((DM_VPROP, DL_HIGH, TEXT("SnapInVolPropPage::CreateDiskQuotaPolicyObject")));
HRESULT hr = NOERROR;
try
{
CDiskQuotaPolicy *pPolicy = new CDiskQuotaPolicy;
hr = pPolicy->QueryInterface(IID_IDiskQuotaPolicy,
reinterpret_cast<void **>(&m_pPolicy));
if (SUCCEEDED(hr))
{
m_pPolicy->AddRef();
*ppOut = m_pPolicy;
}
}
catch(CAllocException& e)
{
hr = E_OUTOFMEMORY;
}
return hr;
}
#endif // POLICY_MMC_SNAPIN