1989 lines
59 KiB
C++
1989 lines
59 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
/* File: userprop.cpp
|
|
|
|
Description: Provides implementations for quota user property page.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
06/25/98 Replaced AddUserPropSheet with AddUserDialog. BrianAu
|
|
Now that we're getting user info from the DS
|
|
object picker, the prop sheet idea doesn't work
|
|
so well. A std dialog is better.
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.h" // PCH
|
|
#pragma hdrstop
|
|
|
|
#include <lm.h>
|
|
#include "undo.h"
|
|
#include "userprop.h"
|
|
#include "userbat.h"
|
|
#include "uihelp.h"
|
|
#include "progress.h"
|
|
#include "uiutils.h"
|
|
|
|
//
|
|
// Context help IDs.
|
|
//
|
|
#pragma data_seg(".text", "CODE")
|
|
const static DWORD rgUserPropSheetHelpIDs[] =
|
|
{
|
|
IDC_ICON_USER, DWORD(-1),
|
|
IDC_STATIC2, DWORD(-1),
|
|
IDC_TXT_USERNAME, IDH_TXT_USERNAME,
|
|
IDC_TXT_SPACEUSED, IDH_TXT_SPACEUSED,
|
|
IDC_TXT_SPACEREMAINING, IDH_TXT_SPACEREMAINING,
|
|
IDC_LBL_SPACEUSED, DWORD(-1),
|
|
IDC_LBL_SPACEREMAINING, DWORD(-1),
|
|
IDC_ICON_USERSTATUS, IDH_ICON_USERSTATUS,
|
|
IDC_RBN_USER_NOLIMIT, IDH_RBN_USER_NOLIMIT,
|
|
IDC_RBN_USER_LIMIT, IDH_RBN_USER_LIMIT,
|
|
IDC_TXT_WARN_LEVEL, DWORD(-1),
|
|
IDC_EDIT_USER_LIMIT, IDH_EDIT_USER_LIMIT,
|
|
IDC_EDIT_USER_THRESHOLD, IDH_EDIT_USER_THRESHOLD,
|
|
IDC_CMB_USER_LIMIT, IDH_CMB_USER_LIMIT,
|
|
IDC_CMB_USER_THRESHOLD, IDH_CMB_USER_THRESHOLD,
|
|
0,0
|
|
};
|
|
|
|
#pragma data_seg()
|
|
|
|
|
|
//
|
|
// Messages for querying property page for icon images.
|
|
//
|
|
#define DQM_QUERY_STATUS_ICON (WM_USER + 1)
|
|
#define DQM_QUERY_USER_ICON (WM_USER + 2)
|
|
#define DQM_ENABLE_APPLY_BUTTON (WM_USER + 3)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::UserPropSheet
|
|
|
|
Description: Constructor for a user property sheet object.
|
|
Initializes the members that hold user quota data.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Nothing.
|
|
|
|
Exceptions: OutOfMemory.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
UserPropSheet::UserPropSheet(
|
|
PDISKQUOTA_CONTROL pQuotaControl,
|
|
const CVolumeID& idVolume,
|
|
HWND hWndParent,
|
|
LVSelection& LVSel,
|
|
UndoList& UndoList
|
|
) : m_cVolumeMaxBytes(0),
|
|
m_pQuotaControl(pQuotaControl),
|
|
m_UndoList(UndoList),
|
|
m_LVSelection(LVSel),
|
|
m_hWndParent(hWndParent),
|
|
m_bIsDirty(FALSE),
|
|
m_bHomogeneousSelection(TRUE), // Assume selection is homogeneous.
|
|
m_pxbQuotaLimit(NULL),
|
|
m_pxbQuotaThreshold(NULL),
|
|
m_idVolume(idVolume),
|
|
m_strPageTitle(g_hInstDll, IDS_TITLE_GENERAL),
|
|
m_idCtlNextFocus(-1)
|
|
{
|
|
DBGASSERT((NULL != m_pQuotaControl));
|
|
DBGASSERT((NULL != m_hWndParent));
|
|
DBGTRACE((DM_UPROP, DL_HIGH, TEXT("UserPropSheet::UserPropSheet")));
|
|
|
|
m_llQuotaUsed = 0;
|
|
m_llQuotaLimit = 0;
|
|
m_llQuotaThreshold = 0;
|
|
|
|
DBGASSERT((0 == iICON_USER_SINGLE));
|
|
DBGASSERT((1 == iICON_USER_MULTIPLE));
|
|
m_hIconUser[0] = LoadIcon(g_hInstDll, MAKEINTRESOURCE(IDI_SINGLE_USER));
|
|
m_hIconUser[1] = LoadIcon(g_hInstDll, MAKEINTRESOURCE(IDI_MULTI_USER));
|
|
|
|
DBGASSERT((0 == iICON_STATUS_OK));
|
|
DBGASSERT((1 == iICON_STATUS_OVER_THRESHOLD));
|
|
DBGASSERT((2 == iICON_STATUS_OVER_LIMIT));
|
|
m_hIconStatus[0] = LoadIcon(g_hInstDll, MAKEINTRESOURCE(IDI_OKBUBBLE));
|
|
m_hIconStatus[1] = LoadIcon(NULL, IDI_WARNING);
|
|
m_hIconStatus[2] = LoadIcon(g_hInstDll, MAKEINTRESOURCE(IDI_WARNERR));
|
|
}
|
|
|
|
|
|
|
|
UserPropSheet::~UserPropSheet(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_UPROP, DL_HIGH, TEXT("UserPropSheet::~UserPropSheet")));
|
|
INT i = 0;
|
|
|
|
if (NULL != m_pQuotaControl)
|
|
m_pQuotaControl->Release();
|
|
|
|
if (NULL != m_pxbQuotaLimit)
|
|
delete m_pxbQuotaLimit;
|
|
if (NULL != m_pxbQuotaThreshold)
|
|
delete m_pxbQuotaThreshold;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::Run
|
|
|
|
Description: Creates and runs the property sheet dialog.
|
|
This is the only method a client needs to call once the object
|
|
is created.
|
|
|
|
Arguments: None.
|
|
|
|
Returns:
|
|
NO_ERROR
|
|
E_FAIL - Couldn't create property sheet.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
UserPropSheet::Run(
|
|
VOID
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR; // Assume success.
|
|
|
|
PROPSHEETHEADER psh;
|
|
PROPSHEETPAGE psp;
|
|
|
|
ZeroMemory(&psh, sizeof(psh));
|
|
ZeroMemory(&psp, sizeof(psp));
|
|
|
|
//
|
|
// Define page.
|
|
//
|
|
psp.dwSize = sizeof(PROPSHEETPAGE);
|
|
psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE;
|
|
psp.hInstance = g_hInstDll;
|
|
psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE_USERQUOTA);
|
|
psp.pszTitle = (LPCTSTR)m_strPageTitle;
|
|
psp.pfnDlgProc = DlgProc;
|
|
psp.lParam = (LPARAM)this;
|
|
psp.pcRefParent = (UINT *)& g_cRefThisDll;
|
|
|
|
//
|
|
// Define sheet.
|
|
//
|
|
psh.dwSize = sizeof(PROPSHEETHEADER);
|
|
psh.dwFlags = PSH_PROPSHEETPAGE;
|
|
psh.hwndParent = m_hWndParent;
|
|
psh.hInstance = g_hInstDll;
|
|
psh.pszIcon = NULL;
|
|
psh.pszCaption = NULL;
|
|
psh.nPages = 1;
|
|
psh.nStartPage = 0;
|
|
psh.ppsp = (LPCPROPSHEETPAGE)&psp;
|
|
|
|
if (0 <= PropertySheet(&psh))
|
|
hResult = E_FAIL;
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::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
|
|
UserPropSheet::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().
|
|
//
|
|
UserPropSheet *pThis = (UserPropSheet *)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
try
|
|
{
|
|
switch(message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_INITDIALOG")));
|
|
bResult = OnInitDialog(hDlg, 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")));
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
case WM_ENDSESSION:
|
|
DestroyWindow(hDlg);
|
|
break;
|
|
|
|
case DQM_ENABLE_APPLY_BUTTON:
|
|
pThis->m_bIsDirty = TRUE;
|
|
bResult = PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
break;
|
|
|
|
//
|
|
// These two icon query messages are for automated testing
|
|
// of the UI.
|
|
//
|
|
case DQM_QUERY_USER_ICON:
|
|
bResult = pThis->QueryUserIcon(hDlg);
|
|
break;
|
|
|
|
case DQM_QUERY_STATUS_ICON:
|
|
bResult = pThis->QueryUserStatusIcon(hDlg);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
DiskQuotaMsgBox(GetDesktopWindow(),
|
|
IDS_OUTOFMEMORY,
|
|
IDS_TITLE_DISK_QUOTA,
|
|
MB_ICONERROR | MB_OK);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::OnInitDialog
|
|
|
|
Description: Handler for WM_INITDIALOG. Retrieves the "this" pointer from
|
|
the PROPSHEETPAGE structure (pointed to by lParam) and saves it in
|
|
the window's USERDATA.
|
|
|
|
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
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
INT_PTR
|
|
UserPropSheet::OnInitDialog(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
PROPSHEETPAGE *pPage = (PROPSHEETPAGE *)lParam;
|
|
UserPropSheet *pThis = (UserPropSheet *)pPage->lParam;
|
|
DWORD dwSectorsPerCluster = 0;
|
|
DWORD dwBytesPerSector = 0;
|
|
DWORD dwFreeClusters = 0;
|
|
DWORD dwTotalClusters = 0;
|
|
|
|
DBGASSERT((NULL != pThis));
|
|
|
|
//
|
|
// Save "this" in the window's userdata.
|
|
//
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (INT_PTR)pThis);
|
|
|
|
//
|
|
// Read quota info from NTFS.
|
|
// For single selection, we cache the selected user's info.
|
|
// For multi selection, we cache the defaults for the volume.
|
|
// If adding a new user (count == 0), we also use the defaults for the
|
|
// volume.
|
|
//
|
|
pThis->RefreshCachedQuotaInfo();
|
|
|
|
//
|
|
// Calculate the volume's size.
|
|
// We'll use this to limit user threshold and quota limit entries.
|
|
//
|
|
if (GetDiskFreeSpace(pThis->m_idVolume.ForParsing(),
|
|
&dwSectorsPerCluster,
|
|
&dwBytesPerSector,
|
|
&dwFreeClusters,
|
|
&dwTotalClusters))
|
|
{
|
|
pThis->m_cVolumeMaxBytes = (LONGLONG)dwSectorsPerCluster *
|
|
(LONGLONG)dwBytesPerSector *
|
|
(LONGLONG)dwTotalClusters;
|
|
}
|
|
|
|
pThis->m_pxbQuotaLimit = new XBytes(hDlg,
|
|
IDC_EDIT_USER_LIMIT,
|
|
IDC_CMB_USER_LIMIT,
|
|
pThis->m_llQuotaLimit);
|
|
pThis->m_pxbQuotaThreshold = new XBytes(hDlg,
|
|
IDC_EDIT_USER_THRESHOLD,
|
|
IDC_CMB_USER_THRESHOLD,
|
|
pThis->m_llQuotaThreshold);
|
|
|
|
pThis->InitializeControls(hDlg);
|
|
|
|
return TRUE; // Set focus to default control.
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::RefreshCachedQuotaInfo
|
|
|
|
Description: Reads the quota limit, threshold and used values from the
|
|
property sheet's user object. If multiple users are selected,
|
|
only the first one is read.
|
|
|
|
Arguments: None.
|
|
|
|
Returns: Result of read operation.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
UserPropSheet::RefreshCachedQuotaInfo(
|
|
VOID
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
PDISKQUOTA_USER pUser = NULL;
|
|
INT cSelectedUsers = m_LVSelection.Count();
|
|
|
|
m_LVSelection.Retrieve(0, &pUser);
|
|
|
|
//
|
|
// Read quota threshold. Multi-user selections use the volume's default.
|
|
//
|
|
if (1 == cSelectedUsers)
|
|
{
|
|
hResult = pUser->GetQuotaThreshold(&m_llQuotaThreshold);
|
|
}
|
|
else
|
|
{
|
|
hResult = m_pQuotaControl->GetDefaultQuotaThreshold(&m_llQuotaThreshold);
|
|
}
|
|
if (FAILED(hResult))
|
|
goto refresh_quota_info_failed;
|
|
|
|
//
|
|
// Read quota limit. Multi-user selections use the volume's default.
|
|
//
|
|
if (1 == cSelectedUsers)
|
|
{
|
|
hResult = pUser->GetQuotaLimit(&m_llQuotaLimit);
|
|
}
|
|
else
|
|
{
|
|
hResult = m_pQuotaControl->GetDefaultQuotaLimit(&m_llQuotaLimit);
|
|
}
|
|
if (FAILED(hResult))
|
|
goto refresh_quota_info_failed;
|
|
|
|
|
|
//
|
|
// Read quota used.
|
|
//
|
|
if (1 == cSelectedUsers)
|
|
{
|
|
hResult = pUser->GetQuotaUsed(&m_llQuotaUsed);
|
|
}
|
|
else
|
|
{
|
|
m_llQuotaUsed = 0;
|
|
}
|
|
|
|
refresh_quota_info_failed:
|
|
return hResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::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
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
INT_PTR
|
|
UserPropSheet::OnCommand(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
DWORD dwCtlId = LOWORD(wParam);
|
|
HWND hWndCtl = (HWND)lParam;
|
|
DWORD dwNotifyCode = HIWORD(wParam);
|
|
INT_PTR bResult = FALSE;
|
|
|
|
switch(dwCtlId)
|
|
{
|
|
case IDC_TXT_USERNAME:
|
|
if (EN_SETFOCUS == dwNotifyCode && IDC_EDIT_USER_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.
|
|
//
|
|
SetFocus(GetDlgItem(hDlg, IDC_EDIT_USER_THRESHOLD));
|
|
SendDlgItemMessage(hDlg, IDC_EDIT_USER_THRESHOLD, EM_SETSEL, 0, -1);
|
|
m_idCtlNextFocus = -1;
|
|
}
|
|
break;
|
|
|
|
case IDC_RBN_USER_NOLIMIT:
|
|
if (m_pxbQuotaThreshold->IsEnabled())
|
|
{
|
|
//
|
|
// This is simple. Just set both the limit and threshold controls
|
|
// to "no limit".
|
|
//
|
|
m_pxbQuotaThreshold->SetBytes(NOLIMIT);
|
|
m_pxbQuotaLimit->SetBytes(NOLIMIT);
|
|
m_bIsDirty = TRUE;
|
|
}
|
|
break;
|
|
|
|
case IDC_RBN_USER_LIMIT:
|
|
{
|
|
LONGLONG llValue;
|
|
|
|
//
|
|
// This handler needs some logic. We have to handle several
|
|
// scenarios/rules with this one.
|
|
// 1. Single vs. Multiple selection.
|
|
// 2. Single selection for Administrator account.
|
|
// 3. Multi selection homogeneous/heterogenous with respect to
|
|
// quota limit and threshold values.
|
|
// 4. Can't display "No Limit" in edit controls when they're active.
|
|
// 5. Use volume defaults for new user and hetergenous multi-select.
|
|
//
|
|
if (!m_pxbQuotaThreshold->IsEnabled())
|
|
{
|
|
enum use_types { USE_CACHED, USE_VOLDEF, USE_NOLIMIT };
|
|
|
|
INT iUseAsValue = USE_CACHED;
|
|
INT cSelected = m_LVSelection.Count();
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// First set the quota limit controls.
|
|
///////////////////////////////////////////////////////////////
|
|
if (0 == cSelected) // Adding new user...
|
|
{
|
|
iUseAsValue = USE_VOLDEF;
|
|
}
|
|
else if (1 == cSelected) // One user selected...
|
|
{
|
|
PDISKQUOTA_USER pUser = NULL;
|
|
m_LVSelection.Retrieve(0, &pUser);
|
|
if (UserIsAdministrator(pUser))
|
|
{
|
|
//
|
|
// If user is administrator, the limit is always "No Limit".
|
|
// This will disable the "Limit" controls and prevent
|
|
// user from setting a limit on this account.
|
|
//
|
|
iUseAsValue = USE_NOLIMIT;
|
|
}
|
|
else if (NOLIMIT == m_llQuotaLimit)
|
|
{
|
|
//
|
|
// Account isn't Administrator AND the limit is NOLIMIT.
|
|
// Use the volume's default "new user" limit value.
|
|
//
|
|
iUseAsValue = USE_VOLDEF;
|
|
}
|
|
}
|
|
else if (!m_bHomogeneousSelection || NOLIMIT == m_llQuotaLimit) // Multiple user.
|
|
{
|
|
//
|
|
// Multiple non-homogeneous users get the volume's default limit.
|
|
// Multiple homogeneous users get their current cached setting unless
|
|
// the cached setting is NOLIMIT; in which case, they get the
|
|
// volume's defaults.
|
|
//
|
|
iUseAsValue = USE_VOLDEF;
|
|
}
|
|
|
|
//
|
|
// Set the proper quota limit value in the edit/combo box control.
|
|
//
|
|
llValue = 0;
|
|
switch(iUseAsValue)
|
|
{
|
|
case USE_VOLDEF:
|
|
m_pQuotaControl->GetDefaultQuotaLimit(&llValue);
|
|
//
|
|
// If default is NOLIMIT, display 0 MB. We can't display an
|
|
// "editable" No Limit in the edit control. Only numbers.
|
|
//
|
|
if (NOLIMIT == llValue)
|
|
llValue = 0;
|
|
break;
|
|
|
|
case USE_NOLIMIT:
|
|
llValue = NOLIMIT;
|
|
break;
|
|
|
|
case USE_CACHED:
|
|
llValue = m_llQuotaLimit;
|
|
break;
|
|
}
|
|
|
|
m_pxbQuotaLimit->SetBytes(llValue);
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Now the threshold controls...
|
|
///////////////////////////////////////////////////////////////
|
|
llValue = 0;
|
|
iUseAsValue = USE_CACHED;
|
|
if (0 == cSelected)
|
|
{
|
|
iUseAsValue = USE_VOLDEF;
|
|
}
|
|
else if (1 == cSelected)
|
|
{
|
|
if (NOLIMIT == m_llQuotaThreshold)
|
|
{
|
|
iUseAsValue = USE_VOLDEF;
|
|
}
|
|
}
|
|
else if (!m_bHomogeneousSelection || NOLIMIT == m_llQuotaThreshold)
|
|
{
|
|
iUseAsValue = USE_VOLDEF;
|
|
}
|
|
|
|
//
|
|
// Set the proper quota threshold value in the edit/combo box control.
|
|
//
|
|
switch(iUseAsValue)
|
|
{
|
|
case USE_VOLDEF:
|
|
m_pQuotaControl->GetDefaultQuotaThreshold(&llValue);
|
|
//
|
|
// If default is NOLIMIT, display 0 MB. We can't display an
|
|
// "editable" No Limit in the edit control. Only numbers.
|
|
//
|
|
if (NOLIMIT == llValue)
|
|
llValue = 0;
|
|
break;
|
|
|
|
case USE_NOLIMIT:
|
|
llValue = NOLIMIT;
|
|
break;
|
|
|
|
case USE_CACHED:
|
|
llValue = m_llQuotaThreshold;
|
|
break;
|
|
}
|
|
|
|
m_pxbQuotaThreshold->SetBytes(llValue);
|
|
|
|
m_bIsDirty = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_EDIT_USER_LIMIT:
|
|
case IDC_EDIT_USER_THRESHOLD:
|
|
switch(dwNotifyCode)
|
|
{
|
|
case EN_UPDATE:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("OnCommand, EN_CHANGE")));
|
|
bResult = OnEditNotifyUpdate(hDlg, wParam, lParam);
|
|
m_bIsDirty = TRUE;
|
|
break;
|
|
|
|
case EN_KILLFOCUS:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("OnCommand, EN_KILLFOCUS")));
|
|
bResult = OnEditNotifyKillFocus(hDlg, wParam, lParam);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDC_CMB_USER_LIMIT:
|
|
case IDC_CMB_USER_THRESHOLD:
|
|
switch(dwNotifyCode)
|
|
{
|
|
case CBN_SELCHANGE:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("OnCommand, CBN_CHANGE")));
|
|
bResult = OnComboNotifySelChange(hDlg, wParam, lParam);
|
|
m_bIsDirty = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
bResult = TRUE; // Didn't handle message.
|
|
break;
|
|
}
|
|
|
|
|
|
if (m_bIsDirty)
|
|
PropSheet_Changed(GetParent(hDlg), hDlg);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::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
|
|
UserPropSheet::OnNotify(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
INT_PTR bResult = FALSE;
|
|
|
|
switch(((NMHDR *)lParam)->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("OnNotify, PSN_SETACTIVE")));
|
|
bResult = OnSheetNotifySetActive(hDlg, wParam, lParam);
|
|
break;
|
|
|
|
case PSN_APPLY:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("OnNotify, PSN_APPLY")));
|
|
bResult = OnSheetNotifyApply(hDlg, wParam, lParam);
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("OnNotify, PSN_KILLACTIVE")));
|
|
bResult = OnSheetNotifyKillActive(hDlg, wParam, lParam);
|
|
break;
|
|
|
|
case PSN_RESET:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("OnNotify, PSN_RESET")));
|
|
//
|
|
// Fall through.
|
|
//
|
|
default:
|
|
break;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::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
|
|
UserPropSheet::OnSheetNotifySetActive(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::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
|
|
UserPropSheet::OnSheetNotifyApply(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
LONG dwPSNReturn = PSNRET_NOERROR;
|
|
|
|
//
|
|
// Only apply settings if the "Apply" button is enabled indicating
|
|
// that something has been changed. No need to apply unchanged
|
|
// settings when the OK button is pressed.
|
|
//
|
|
if (m_bIsDirty)
|
|
{
|
|
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_pxbQuotaThreshold->OnEditKillFocus((LPARAM)GetDlgItem(hDlg, IDC_EDIT_USER_THRESHOLD));
|
|
m_pxbQuotaLimit->OnEditKillFocus((LPARAM)GetDlgItem(hDlg, IDC_EDIT_USER_LIMIT));
|
|
|
|
//
|
|
// Ensure warning threshold is not above limit.
|
|
//
|
|
INT64 iThreshold = m_pxbQuotaThreshold->GetBytes();
|
|
INT64 iLimit = m_pxbQuotaLimit->GetBytes();
|
|
|
|
if (NOLIMIT != iLimit && 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_pxbQuotaThreshold->SetBytes(iLimit);
|
|
break;
|
|
|
|
case IDNO:
|
|
//
|
|
// This m_idCtlNextFocus hack stuff is here because I can't get
|
|
// the @#$%! prop sheet to return focus to the threshold control.
|
|
// The only way I've been able to get this to happen is to
|
|
// cache this ID value then on the EN_SETFOCUS generated when
|
|
// the page is activated, set focus to the control.
|
|
// Gross but it works without too much hassle. [brianau]
|
|
//
|
|
m_idCtlNextFocus = IDC_EDIT_USER_THRESHOLD;
|
|
dwPSNReturn = PSNRET_INVALID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (PSNRET_NOERROR == dwPSNReturn)
|
|
{
|
|
hResult = ApplySettings(hDlg);
|
|
if (FAILED(hResult))
|
|
{
|
|
INT idMsg = IDS_UNKNOWN_ERROR;
|
|
UINT uFlags = MB_OK;
|
|
switch(hResult)
|
|
{
|
|
case E_FAIL:
|
|
idMsg = IDS_WRITE_ERROR;
|
|
uFlags |= MB_ICONERROR;
|
|
break;
|
|
|
|
default:
|
|
switch(HRESULT_CODE(hResult))
|
|
{
|
|
|
|
// case ERROR_USER_EXISTS:
|
|
// idMsg = IDS_NOADD_EXISTING_USER;
|
|
// uFlags |= MB_ICONWARNING;
|
|
// break;
|
|
//
|
|
// FEATURE: Still valid? [brianau - 5/27/98]
|
|
//
|
|
case ERROR_NO_SUCH_USER:
|
|
idMsg = IDS_NOADD_UNKNOWN_USER;
|
|
uFlags |= MB_ICONWARNING;
|
|
break;
|
|
|
|
case ERROR_ACCESS_DENIED:
|
|
idMsg = IDS_NO_WRITE_ACCESS;
|
|
uFlags |= MB_ICONWARNING;
|
|
break;
|
|
|
|
default:
|
|
uFlags |= MB_ICONERROR;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
DiskQuotaMsgBox(GetDesktopWindow(),
|
|
idMsg,
|
|
IDS_TITLE_DISK_QUOTA,
|
|
uFlags);
|
|
|
|
dwPSNReturn = PSNRET_INVALID;
|
|
}
|
|
else
|
|
{
|
|
m_bIsDirty = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, dwPSNReturn);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::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
|
|
UserPropSheet::OnSheetNotifyKillActive(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
BOOL bAllDataIsValid = TRUE;
|
|
|
|
//
|
|
// No sheet-level validation performed at this time.
|
|
//
|
|
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, !bAllDataIsValid);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::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
|
|
UserPropSheet::OnHelp(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, STR_DSKQUOUI_HELPFILE,
|
|
HELP_WM_HELP, (DWORD_PTR)(LPTSTR) rgUserPropSheetHelpIDs);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
UserPropSheet::OnContextMenu(
|
|
HWND hwndItem,
|
|
int xPos,
|
|
int yPos
|
|
)
|
|
{
|
|
int idCtl = GetDlgCtrlID(hwndItem);
|
|
WinHelp(hwndItem,
|
|
UseWindowsHelp(idCtl) ? NULL : STR_DSKQUOUI_HELPFILE,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)((LPTSTR)rgUserPropSheetHelpIDs));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropPage::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
|
|
-------- --------------------------------------------------- ----------
|
|
09/03/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
INT_PTR
|
|
UserPropSheet::OnEditNotifyUpdate(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
XBytes *pxb = NULL;
|
|
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_EDIT_USER_LIMIT:
|
|
pxb = m_pxbQuotaLimit;
|
|
break;
|
|
|
|
case IDC_EDIT_USER_THRESHOLD:
|
|
pxb = m_pxbQuotaThreshold;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (NULL != pxb)
|
|
pxb->OnEditNotifyUpdate(lParam);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::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
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
INT_PTR
|
|
UserPropSheet::OnEditNotifyKillFocus(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
XBytes *pxb = NULL;
|
|
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_EDIT_USER_LIMIT:
|
|
pxb = m_pxbQuotaLimit;
|
|
break;
|
|
|
|
case IDC_EDIT_USER_THRESHOLD:
|
|
pxb = m_pxbQuotaThreshold;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (NULL != pxb)
|
|
pxb->OnEditKillFocus(lParam);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropPage::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
|
|
-------- --------------------------------------------------- ----------
|
|
09/03/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
INT_PTR
|
|
UserPropSheet::OnComboNotifySelChange(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
XBytes *pxb = NULL;
|
|
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_CMB_USER_LIMIT:
|
|
pxb = m_pxbQuotaLimit;
|
|
break;
|
|
|
|
case IDC_CMB_USER_THRESHOLD:
|
|
pxb = m_pxbQuotaThreshold;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
if (NULL != pxb)
|
|
pxb->OnComboNotifySelChange(lParam);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::ApplySettings
|
|
|
|
Description: Applies the current settings to the user's quota information
|
|
if they have not 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
|
|
01/24/98 Added bUndo argument. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
UserPropSheet::ApplySettings(
|
|
HWND hDlg,
|
|
bool bUndo // Default == true.
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
BOOL bTranslated = FALSE;
|
|
com_autoptr<DISKQUOTA_USER> ptrUser;
|
|
UINT cUsers = m_LVSelection.Count();
|
|
UINT i = 0;
|
|
LONGLONG llThreshold;
|
|
LONGLONG llLimit;
|
|
CAutoSetRedraw autoredraw(m_hWndParent);
|
|
|
|
if (bUndo)
|
|
m_UndoList.Clear(); // Clear current undo list.
|
|
|
|
//
|
|
// Determine what threshold and limit to apply.
|
|
//
|
|
if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RBN_USER_NOLIMIT))
|
|
{
|
|
llThreshold = NOLIMIT;
|
|
llLimit = NOLIMIT;
|
|
}
|
|
else
|
|
{
|
|
llThreshold = m_pxbQuotaThreshold->GetBytes();
|
|
llLimit = m_pxbQuotaLimit->GetBytes();
|
|
}
|
|
|
|
if (cUsers > 1)
|
|
{
|
|
//
|
|
// Create batch object and do batch update for multiple users.
|
|
//
|
|
com_autoptr<DISKQUOTA_USER_BATCH> ptrBatch;
|
|
|
|
hResult = m_pQuotaControl->CreateUserBatch(ptrBatch.getaddr());
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
for (i = 0; i < cUsers; i++)
|
|
{
|
|
m_LVSelection.Retrieve(i, ptrUser.getaddr());
|
|
if (bUndo)
|
|
{
|
|
//
|
|
// Add an entry to the undo list.
|
|
//
|
|
LONGLONG LimitUndo;
|
|
LONGLONG ThresholdUndo;
|
|
ptrUser->GetQuotaThreshold(&ThresholdUndo);
|
|
ptrUser->GetQuotaLimit(&LimitUndo);
|
|
//
|
|
// Use a local autoptr to ensure proper release of
|
|
// iface in case adding to the undo list throws an exception.
|
|
// On success, disown the real ptr so that the object
|
|
// stays with the undo list.
|
|
//
|
|
com_autoptr<DISKQUOTA_USER> ptrQuotaUser(ptrUser);
|
|
ptrUser->AddRef();
|
|
m_UndoList.Add(new UndoModify(ptrUser, ThresholdUndo, LimitUndo));
|
|
ptrQuotaUser.disown();
|
|
}
|
|
|
|
ptrUser->SetQuotaThreshold(llThreshold, FALSE);
|
|
|
|
if (UserIsAdministrator(ptrUser) && NOLIMIT != llLimit)
|
|
{
|
|
//
|
|
// User is the Administrator account AND
|
|
// We're trying to set the limit to something other than NOLIMIT.
|
|
// Can't set a limit on the administrator account.
|
|
//
|
|
DiskQuotaMsgBox(GetDesktopWindow(),
|
|
IDS_CANT_SET_ADMIN_LIMIT,
|
|
IDS_TITLE_DISK_QUOTA,
|
|
MB_ICONWARNING | MB_OK);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// OK to set quota limit.
|
|
//
|
|
ptrUser->SetQuotaLimit(llLimit, FALSE);
|
|
}
|
|
|
|
ptrBatch->Add(ptrUser);
|
|
}
|
|
|
|
hResult = ptrBatch->FlushToDisk();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do single user update or add new user.
|
|
//
|
|
m_LVSelection.Retrieve(0, ptrUser.getaddr());
|
|
DBGASSERT((NULL != ptrUser.get()));
|
|
|
|
if (bUndo)
|
|
{
|
|
//
|
|
// Add an entry to the undo list.
|
|
//
|
|
LONGLONG LimitUndo;
|
|
LONGLONG ThresholdUndo;
|
|
ptrUser->GetQuotaThreshold(&ThresholdUndo);
|
|
ptrUser->GetQuotaLimit(&LimitUndo);
|
|
//
|
|
// Use local autoptr to ensure proper release of iface ptr if
|
|
// an exception is thrown. Disown real ptr on success.
|
|
//
|
|
com_autoptr<DISKQUOTA_USER> ptrQuotaUser(ptrUser);
|
|
ptrUser->AddRef();
|
|
m_UndoList.Add(new UndoModify(ptrUser, ThresholdUndo, LimitUndo));
|
|
ptrQuotaUser.disown();
|
|
}
|
|
|
|
if (llThreshold != m_llQuotaThreshold)
|
|
{
|
|
hResult = ptrUser->SetQuotaThreshold(llThreshold, TRUE);
|
|
|
|
if (FAILED(hResult))
|
|
goto apply_failed;
|
|
|
|
m_llQuotaThreshold = llThreshold;
|
|
}
|
|
|
|
if (llLimit != m_llQuotaLimit)
|
|
{
|
|
hResult = ptrUser->SetQuotaLimit(llLimit, TRUE);
|
|
if (FAILED(hResult))
|
|
goto apply_failed;
|
|
|
|
m_llQuotaLimit = llLimit;
|
|
}
|
|
|
|
//
|
|
// Update the user's status icon and %used to reflect the new settings.
|
|
//
|
|
UpdateUserStatusIcon(hDlg,
|
|
m_llQuotaUsed,
|
|
m_llQuotaThreshold,
|
|
m_llQuotaLimit);
|
|
|
|
UpdateSpaceUsed(hDlg,
|
|
m_llQuotaUsed,
|
|
m_llQuotaLimit,
|
|
1);
|
|
}
|
|
|
|
//
|
|
// Update the listview item(s) so the user sees a visual response to
|
|
// pressing the "Apply" button.
|
|
//
|
|
autoredraw.Set(false);
|
|
for (i = 0; i < cUsers; i++)
|
|
{
|
|
INT iItem = 0;
|
|
m_LVSelection.Retrieve(i, &iItem);
|
|
ListView_Update(m_hWndParent, iItem);
|
|
}
|
|
autoredraw.Set(true);
|
|
InvalidateRect(m_hWndParent, NULL, FALSE);
|
|
|
|
apply_failed:
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::InitializeControls
|
|
|
|
Description: Initializes the page controls based on the user'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
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
UserPropSheet::InitializeControls(
|
|
HWND hDlg
|
|
)
|
|
{
|
|
PDISKQUOTA_USER pUser = NULL;
|
|
UINT cUsers = m_LVSelection.Count();
|
|
|
|
if (1 == cUsers)
|
|
{
|
|
//
|
|
// Initialize controls for a single user.
|
|
//
|
|
m_LVSelection.Retrieve(0, &pUser);
|
|
|
|
//
|
|
// Configure the Limit/NoLimit radio buttons.
|
|
// Must examine the current threshold rather than the limit because of the
|
|
// special-case for the Administrator account. That account can have a
|
|
// threshold value but quota limit must always be "No Limit".
|
|
//
|
|
CheckDlgButton(hDlg, IDC_RBN_USER_LIMIT, NOLIMIT != m_llQuotaThreshold);
|
|
CheckDlgButton(hDlg, IDC_RBN_USER_NOLIMIT, NOLIMIT == m_llQuotaThreshold);
|
|
if (UserIsAdministrator(pUser))
|
|
{
|
|
//
|
|
// Override initialization of Quota Limit control with "No Limit".
|
|
//
|
|
m_pxbQuotaLimit->SetBytes(NOLIMIT);
|
|
}
|
|
|
|
//
|
|
// Note that the XBytes controls have already been set for single-user.
|
|
// See OnInitDialog().
|
|
//
|
|
|
|
//
|
|
// Configure the remaining dialog controls.
|
|
//
|
|
UpdateUserName(hDlg, pUser);
|
|
UpdateSpaceUsed(hDlg, m_llQuotaUsed, m_llQuotaLimit, cUsers);
|
|
UpdateUserStatusIcon(hDlg,
|
|
m_llQuotaUsed,
|
|
m_llQuotaThreshold,
|
|
m_llQuotaLimit);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Initialize controls for multiple users.
|
|
//
|
|
LONGLONG llLimit = 0;
|
|
LONGLONG llLastLimit = 0;
|
|
LONGLONG llThreshold = 0;
|
|
LONGLONG llLastThreshold = 0;
|
|
LONGLONG llUsed = 0;
|
|
LONGLONG llTotalUsed = 0;
|
|
|
|
//
|
|
// Add up the total usage by all users.
|
|
//
|
|
for (UINT i = 0; i < cUsers; i++)
|
|
{
|
|
m_LVSelection.Retrieve(i, &pUser);
|
|
pUser->GetQuotaLimit(&llLimit);
|
|
pUser->GetQuotaThreshold(&llThreshold);
|
|
pUser->GetQuotaUsed(&llUsed);
|
|
|
|
llTotalUsed += llUsed;
|
|
if (m_bHomogeneousSelection)
|
|
{
|
|
//
|
|
// Determine if at least one user has a different
|
|
// threshold or limit. If all are the same, we can display
|
|
// the values in the edit controls. Otherwise, we default
|
|
// to "No Limit". Radio buttons don't provide an
|
|
// indeterminate state like checkboxes.
|
|
//
|
|
if (i > 0 &&
|
|
(llLimit != llLastLimit ||
|
|
llThreshold != llLastThreshold))
|
|
{
|
|
m_bHomogeneousSelection = FALSE;
|
|
}
|
|
else
|
|
{
|
|
llLastLimit = llLimit;
|
|
llLastThreshold = llThreshold;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If all selected objects have the same limit and threshold,
|
|
// set the cached data to represent multiple-selection.
|
|
// If any one is different, we stick with the volume's default
|
|
// values set in RefreshCachedQuotaInfo().
|
|
//
|
|
if (m_bHomogeneousSelection)
|
|
{
|
|
m_llQuotaThreshold = llLastThreshold;
|
|
m_llQuotaLimit = llLastLimit;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Since not all selected users have the same limit/thresold,
|
|
// the number we're displaying will be a change for at least
|
|
// one user. Activate the "Apply" button.
|
|
//
|
|
//
|
|
PostMessage(hDlg, DQM_ENABLE_APPLY_BUTTON, 0, 0);
|
|
}
|
|
|
|
m_pxbQuotaThreshold->SetBytes(m_llQuotaThreshold);
|
|
m_pxbQuotaLimit->SetBytes(m_llQuotaLimit);
|
|
|
|
//
|
|
// Configure the Limit/NoLimit radio buttons.
|
|
//
|
|
CheckDlgButton(hDlg,
|
|
IDC_RBN_USER_NOLIMIT,
|
|
NOLIMIT == m_llQuotaThreshold);
|
|
CheckDlgButton(hDlg,
|
|
IDC_RBN_USER_LIMIT,
|
|
NOLIMIT != m_llQuotaThreshold);
|
|
|
|
UpdateUserName(hDlg, cUsers);
|
|
UpdateSpaceUsed(hDlg, llTotalUsed, NOLIMIT, cUsers);
|
|
//
|
|
// Don't display any user status icon for multi-users.
|
|
//
|
|
}
|
|
|
|
|
|
//
|
|
// If "No Limit" radio button is checked, set limit and threshold controls
|
|
// to the "No Limit" state (disabled and displaying "No Limit" text).
|
|
// This may override any setting we made above.
|
|
//
|
|
if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RBN_USER_NOLIMIT))
|
|
{
|
|
m_pxbQuotaThreshold->SetBytes(NOLIMIT);
|
|
m_pxbQuotaLimit->SetBytes(NOLIMIT);
|
|
}
|
|
|
|
//
|
|
// Set user icon.
|
|
//
|
|
SendMessage(GetDlgItem(hDlg, IDC_ICON_USER),
|
|
STM_SETICON,
|
|
(WPARAM)m_hIconUser[1 == cUsers ? iICON_USER_SINGLE :
|
|
iICON_USER_MULTIPLE],
|
|
0);
|
|
|
|
//
|
|
// Force the property sheet to disable the "Apply" button.
|
|
// The way I have set up the "Apply" enabling logic through OnCommand(),
|
|
// merely initializing the edit controls on the page causes the Apply
|
|
// button to become enabled. Since the user hasn't changed anything
|
|
// yet, it should be disabled.
|
|
//
|
|
m_bIsDirty = FALSE;
|
|
PropSheet_UnChanged(GetParent(hDlg), hDlg);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::QueryUserStatusIcon
|
|
|
|
|
|
Description: This function is provided for automated testing of the UI.
|
|
It is used by test scripts to determine which user status icon is
|
|
currently displayed.
|
|
|
|
Arguments:
|
|
hDlg - Dialog handle.
|
|
|
|
|
|
Returns: -1 = No icon displayed.
|
|
0 = "Everything OK" icon.
|
|
1 = Threshold exceded icon.
|
|
2 = Limit exceded icon.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
INT
|
|
UserPropSheet::QueryUserStatusIcon(
|
|
HWND hDlg
|
|
) const
|
|
{
|
|
HICON hicon = (HICON)SendMessage(GetDlgItem(hDlg, IDC_ICON_USERSTATUS),
|
|
STM_GETICON,
|
|
0, 0);
|
|
|
|
for (UINT i = 0; i < cSTATUS_ICONS; i++)
|
|
{
|
|
if (hicon == m_hIconStatus[i])
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::QueryUserIcon
|
|
|
|
|
|
Description: This function is provided for automated testing of the UI.
|
|
It is used by test scripts to determine which user status icon is
|
|
currently displayed.
|
|
|
|
Arguments:
|
|
hDlg - Dialog handle.
|
|
|
|
|
|
Returns: -1 = No icon displayed.
|
|
0 = Single-user icon.
|
|
1 = Multi-user icon.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
INT
|
|
UserPropSheet::QueryUserIcon(
|
|
HWND hDlg
|
|
) const
|
|
{
|
|
HICON hicon = (HICON)SendMessage(GetDlgItem(hDlg, IDC_ICON_USER),
|
|
STM_GETICON,
|
|
0, 0);
|
|
|
|
for (UINT i = 0; i < cUSER_ICONS; i++)
|
|
{
|
|
if (hicon == m_hIconUser[i])
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::UpdateUserStatusIcon
|
|
|
|
Description: Updates the quota status icon in the dialog box. This icon
|
|
must match the icon displayed in the listview for the selected user.
|
|
|
|
Arguments:
|
|
hDlg - Dialog handle.
|
|
|
|
iUsed - Quota bytes charged to user.
|
|
|
|
iThreshold - Quota warning threshold (bytes).
|
|
|
|
iLimit - User's quota limit.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
UserPropSheet::UpdateUserStatusIcon(
|
|
HWND hDlg,
|
|
LONGLONG iUsed,
|
|
LONGLONG iThreshold,
|
|
LONGLONG iLimit
|
|
)
|
|
{
|
|
//
|
|
// Set the user status icon if user is exceding the
|
|
// quota threshold or the limit. This is the same icon that is
|
|
// displayed in the listview status column. This logic must
|
|
// mirror that used in DetailsView::GetDispInfo_Image().
|
|
//
|
|
INT iIcon = iICON_STATUS_OK;
|
|
if (NOLIMIT != iLimit && iUsed > iLimit)
|
|
{
|
|
iIcon = iICON_STATUS_OVER_LIMIT;
|
|
}
|
|
else if (NOLIMIT != iThreshold && iUsed > iThreshold)
|
|
{
|
|
iIcon = iICON_STATUS_OVER_THRESHOLD;
|
|
}
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_ICON_USERSTATUS),
|
|
STM_SETICON,
|
|
(WPARAM)m_hIconStatus[iIcon],
|
|
0);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::UpdateUserName
|
|
|
|
Description: Updates the Domain\Name text with the user's domain name
|
|
and account name strings. This method is called for a single-user
|
|
selection.
|
|
|
|
Also sets the property sheet title text.
|
|
|
|
Arguments:
|
|
hDlg - Dialog handle.
|
|
|
|
pUser - Address of user's IDiskQuotaUser interface.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
08/05/97 Added code to set prop sheet title text. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
UserPropSheet::UpdateUserName(
|
|
HWND hDlg,
|
|
PDISKQUOTA_USER pUser
|
|
)
|
|
{
|
|
DBGASSERT((NULL != pUser));
|
|
//
|
|
// Display the user name, or some status text
|
|
// if the name hasn't been resolved.
|
|
//
|
|
CString strLogonName;
|
|
DWORD dwAccountStatus = 0;
|
|
|
|
pUser->GetAccountStatus(&dwAccountStatus);
|
|
|
|
if (DISKQUOTA_USER_ACCOUNT_RESOLVED == dwAccountStatus)
|
|
{
|
|
//
|
|
// User account name has been resolved. Display it.
|
|
//
|
|
TCHAR szLogonName[MAX_USERNAME];
|
|
TCHAR szDisplayName[MAX_FULL_USERNAME];
|
|
|
|
pUser->GetName(NULL, 0,
|
|
szLogonName, ARRAYSIZE(szLogonName),
|
|
szDisplayName, ARRAYSIZE(szDisplayName));
|
|
|
|
if (TEXT('\0') != szLogonName[0])
|
|
{
|
|
if (TEXT('\0') != szDisplayName[0])
|
|
{
|
|
strLogonName.Format(g_hInstDll,
|
|
IDS_FMT_DISPLAY_LOGON,
|
|
szDisplayName,
|
|
szLogonName);
|
|
}
|
|
else
|
|
{
|
|
strLogonName = szLogonName;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// User account name has not been resolved or cannot
|
|
// be resolved for some reason. Display appropriate
|
|
// status text. This is the same text displayed in the
|
|
// listview when the user's name has not been resolved.
|
|
//
|
|
INT idText = IDS_USER_ACCOUNT_UNKNOWN;
|
|
|
|
switch(dwAccountStatus)
|
|
{
|
|
case DISKQUOTA_USER_ACCOUNT_UNAVAILABLE:
|
|
idText = IDS_USER_ACCOUNT_UNAVAILABLE;
|
|
break;
|
|
|
|
case DISKQUOTA_USER_ACCOUNT_DELETED:
|
|
idText = IDS_USER_ACCOUNT_DELETED;
|
|
break;
|
|
|
|
case DISKQUOTA_USER_ACCOUNT_INVALID:
|
|
idText = IDS_USER_ACCOUNT_INVALID;
|
|
break;
|
|
|
|
case DISKQUOTA_USER_ACCOUNT_UNRESOLVED:
|
|
idText = IDS_USER_ACCOUNT_UNRESOLVED;
|
|
break;
|
|
|
|
case DISKQUOTA_USER_ACCOUNT_UNKNOWN:
|
|
default:
|
|
break;
|
|
}
|
|
strLogonName.Format(g_hInstDll, idText);
|
|
}
|
|
SetDlgItemText(hDlg, IDC_TXT_USERNAME, strLogonName);
|
|
|
|
//
|
|
// Format and draw the prop sheet title string.
|
|
//
|
|
CString strSheetTitle(g_hInstDll,
|
|
IDS_TITLE_EDIT_USER,
|
|
(LPCTSTR)strLogonName);
|
|
|
|
PropSheet_SetTitle(GetParent(hDlg), 0, (LPCTSTR)strSheetTitle);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::UpdateUserName
|
|
|
|
Description: Replaces the user Domain\Name text with a message showing
|
|
how many users are selected. This is used for multi-user selections
|
|
where no single user name is applicable.
|
|
|
|
Also sets the property sheet title text.
|
|
|
|
Arguments:
|
|
hDlg - Dialog handle.
|
|
|
|
cUsers - Number of users represented in the property dialog.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
08/05/97 Added code to set prop sheet title text. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
UserPropSheet::UpdateUserName(
|
|
HWND hDlg,
|
|
INT cUsers
|
|
)
|
|
{
|
|
//
|
|
// Hide name edit control. Can't display names for all users.
|
|
// Display "Multiple Quota Users." instead.
|
|
//
|
|
CString strText(g_hInstDll, IDS_TITLE_MULTIUSER, cUsers);
|
|
SetDlgItemText(hDlg, IDC_TXT_USERNAME, strText);
|
|
|
|
//
|
|
// Set the title of the property sheet.
|
|
//
|
|
CString strSheetTitle(g_hInstDll, IDS_TITLE_EDIT_MULTIUSER);
|
|
PropSheet_SetTitle(GetParent(hDlg), 0, (LPCTSTR)strSheetTitle);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: UserPropSheet::UpdateSpaceUsed
|
|
|
|
Description: Updates the "space used" and "remaining" fields on the user
|
|
property sheet.
|
|
|
|
Arguments:
|
|
hDlg - Dialog handle.
|
|
|
|
iUsed - Quota bytes charged to user(s).
|
|
|
|
iLimit - User's quota limit.
|
|
|
|
cUsers - Number of users represented in the property dialog.
|
|
|
|
Returns: Nothing.
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
UserPropSheet::UpdateSpaceUsed(
|
|
HWND hDlg,
|
|
LONGLONG iUsed,
|
|
LONGLONG iLimit,
|
|
INT cUsers
|
|
)
|
|
{
|
|
TCHAR szText[80];
|
|
|
|
//
|
|
// Display - Used: 999XB (99%)
|
|
//
|
|
XBytes::FormatByteCountForDisplay(iUsed,
|
|
szText, ARRAYSIZE(szText));
|
|
CString strText(szText);
|
|
if (1 == cUsers)
|
|
{
|
|
//
|
|
// Only single-user page gets (99%) appended.
|
|
// Pct quota is meaningless for multiple users.
|
|
//
|
|
if (0 != iLimit && NOLIMIT != iLimit)
|
|
{
|
|
UINT iPct = (INT)((iUsed * 100) / iLimit);
|
|
|
|
strText.Format(g_hInstDll,
|
|
IDS_QUOTA_USED_SINGLEUSER,
|
|
szText,
|
|
iPct);
|
|
}
|
|
}
|
|
|
|
SetDlgItemText(hDlg,
|
|
IDC_TXT_SPACEUSED,
|
|
strText);
|
|
|
|
|
|
//
|
|
// Display - Remaining: 999XB
|
|
//
|
|
strText = szText;
|
|
if (NOLIMIT != iLimit)
|
|
{
|
|
LONGLONG iAmount = 0;
|
|
|
|
if (iUsed <= iLimit)
|
|
iAmount = iLimit - iUsed;
|
|
|
|
XBytes::FormatByteCountForDisplay(iAmount,
|
|
strText.GetBuffer(80), 80);
|
|
strText.ReleaseBuffer();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Display "N/A" if limit is NOLIMIT.
|
|
//
|
|
strText.Format(g_hInstDll, IDS_NOT_APPLICABLE);
|
|
}
|
|
|
|
SetDlgItemText(hDlg,
|
|
IDC_TXT_SPACEREMAINING,
|
|
strText);
|
|
}
|
|
|
|
|