1110 lines
33 KiB
C++
1110 lines
33 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
/* File: adusrdlg.cpp
|
|
|
|
Description: Provides implementations for the "Add User" dialog.
|
|
|
|
|
|
Revision History:
|
|
|
|
Date Description Programmer
|
|
-------- --------------------------------------------------- ----------
|
|
08/15/96 Initial creation. BrianAu
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.h" // PCH
|
|
#pragma hdrstop
|
|
|
|
#include <lm.h>
|
|
#include "undo.h"
|
|
#include "adusrdlg.h"
|
|
#include "uihelp.h"
|
|
#include "progress.h"
|
|
#include "uiutils.h"
|
|
|
|
|
|
//
|
|
// Context help IDs.
|
|
//
|
|
#pragma data_seg(".text", "CODE")
|
|
const static DWORD rgAddUserDialogHelpIDs[] =
|
|
{
|
|
IDC_ICON_USER, DWORD(-1),
|
|
IDC_STATIC2, DWORD(-1),
|
|
IDC_TXT_DEFAULTS, DWORD(-1),
|
|
IDC_TXT_USERNAME, IDH_TXT_USERNAME,
|
|
IDC_TXT_SPACEUSED, IDH_TXT_SPACEUSED,
|
|
IDC_TXT_SPACEREMAINING, IDH_TXT_SPACEREMAINING,
|
|
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()
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: AddUserDialog::AddUserDialog
|
|
|
|
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
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
AddUserDialog::AddUserDialog(
|
|
PDISKQUOTA_CONTROL pQuotaControl,
|
|
const CVolumeID& idVolume,
|
|
HINSTANCE hInstance,
|
|
HWND hwndParent,
|
|
HWND hwndDetailsLV,
|
|
UndoList& UndoList
|
|
) : m_cVolumeMaxBytes(0),
|
|
m_pQuotaControl(pQuotaControl),
|
|
m_idVolume(idVolume),
|
|
m_UndoList(UndoList),
|
|
m_hInstance(hInstance),
|
|
m_hwndParent(hwndParent),
|
|
m_hwndDetailsLV(hwndDetailsLV),
|
|
m_pxbQuotaLimit(NULL),
|
|
m_pxbQuotaThreshold(NULL),
|
|
m_llQuotaLimit(0),
|
|
m_llQuotaThreshold(0),
|
|
m_pSelectionList(NULL), // Object instance doesn't own this memory.
|
|
m_cfSelectionList((CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST))
|
|
{
|
|
DBGASSERT((NULL != m_pQuotaControl));
|
|
DBGASSERT((NULL != m_hwndParent));
|
|
DBGTRACE((DM_UPROP, DL_HIGH, TEXT("AddUserDialog::AddUserDialog")));
|
|
|
|
DBGASSERT((0 == iICON_USER_SINGLE));
|
|
DBGASSERT((1 == iICON_USER_MULTIPLE));
|
|
m_hIconUser[0] = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_SINGLE_USER));
|
|
m_hIconUser[1] = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MULTI_USER));
|
|
}
|
|
|
|
|
|
|
|
AddUserDialog::~AddUserDialog(
|
|
VOID
|
|
)
|
|
{
|
|
DBGTRACE((DM_UPROP, DL_HIGH, TEXT("AddUserDialog::~AddUserDialog")));
|
|
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: AddUserDialog::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
|
|
AddUserDialog::Run(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Invoke the standard object picker dialog.
|
|
//
|
|
IDataObject *pdtobj = NULL;
|
|
HRESULT hr = BrowseForUsers(m_hwndParent, &pdtobj);
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// Retrieve the data object representing the selected user objects.
|
|
//
|
|
FORMATETC fe = { m_cfSelectionList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
STGMEDIUM stg;
|
|
hr = pdtobj->GetData(&fe, &stg);
|
|
{
|
|
//
|
|
// Cache the data obj ptr so the dialog can have access.
|
|
//
|
|
m_pSelectionList = (DS_SELECTION_LIST *)GlobalLock(stg.hGlobal);
|
|
|
|
if (NULL != m_pSelectionList)
|
|
{
|
|
hr = (HRESULT) DialogBoxParam(m_hInstance,
|
|
MAKEINTRESOURCE(IDD_ADDUSER),
|
|
m_hwndParent,
|
|
DlgProc,
|
|
(LPARAM)this);
|
|
GlobalUnlock(stg.hGlobal);
|
|
m_pSelectionList = NULL;
|
|
}
|
|
ReleaseStgMedium(&stg);
|
|
}
|
|
pdtobj->Release();
|
|
}
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/* Function: AddUserDialog::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 CALLBACK
|
|
AddUserDialog::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().
|
|
//
|
|
AddUserDialog *pThis = (AddUserDialog *)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
try
|
|
{
|
|
switch(message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_INITDIALOG")));
|
|
pThis = (AddUserDialog *)lParam;
|
|
DBGASSERT((NULL != pThis));
|
|
//
|
|
// Save "this" in the window's userdata.
|
|
//
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (INT_PTR)pThis);
|
|
bResult = pThis->OnInitDialog(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_CONTEXTMENU:
|
|
bResult = pThis->OnContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
|
|
break;
|
|
|
|
case WM_HELP:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_HELP")));
|
|
bResult = pThis->OnHelp(hDlg, wParam, lParam);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_DESTROY")));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
catch(CAllocException& e)
|
|
{
|
|
DiskQuotaMsgBox(GetDesktopWindow(),
|
|
IDS_OUTOFMEMORY,
|
|
IDS_TITLE_DISK_QUOTA,
|
|
MB_ICONERROR | MB_OK);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
INT_PTR
|
|
AddUserDialog::OnInitDialog(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
DWORD dwSectorsPerCluster = 0;
|
|
DWORD dwBytesPerSector = 0;
|
|
DWORD dwFreeClusters = 0;
|
|
DWORD dwTotalClusters = 0;
|
|
|
|
//
|
|
// The "new user" dialog is initialized with the volume's default quota
|
|
// limit and threshold for new users.
|
|
//
|
|
m_pQuotaControl->GetDefaultQuotaLimit(&m_llQuotaLimit);
|
|
m_pQuotaControl->GetDefaultQuotaThreshold(&m_llQuotaThreshold);
|
|
|
|
//
|
|
// Configure the Limit/NoLimit radio buttons.
|
|
//
|
|
if (NOLIMIT == m_llQuotaThreshold)
|
|
{
|
|
CheckDlgButton(hDlg, IDC_RBN_USER_LIMIT, FALSE);
|
|
CheckDlgButton(hDlg, IDC_RBN_USER_NOLIMIT, TRUE);
|
|
}
|
|
else
|
|
{
|
|
CheckDlgButton(hDlg, IDC_RBN_USER_LIMIT, TRUE);
|
|
CheckDlgButton(hDlg, IDC_RBN_USER_NOLIMIT, FALSE);
|
|
}
|
|
|
|
//
|
|
// 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 = (LONGLONG)dwSectorsPerCluster *
|
|
(LONGLONG)dwBytesPerSector *
|
|
(LONGLONG)dwTotalClusters;
|
|
}
|
|
|
|
m_pxbQuotaLimit = new XBytes(hDlg,
|
|
IDC_EDIT_USER_LIMIT,
|
|
IDC_CMB_USER_LIMIT,
|
|
m_llQuotaLimit);
|
|
|
|
m_pxbQuotaLimit->SetBytes(m_llQuotaLimit);
|
|
|
|
m_pxbQuotaThreshold = new XBytes(hDlg,
|
|
IDC_EDIT_USER_THRESHOLD,
|
|
IDC_CMB_USER_THRESHOLD,
|
|
m_llQuotaThreshold);
|
|
|
|
m_pxbQuotaThreshold->SetBytes(m_llQuotaThreshold);
|
|
|
|
DBGASSERT((0 < m_pSelectionList->cItems));
|
|
if (1 == m_pSelectionList->cItems)
|
|
{
|
|
SetDlgItemText(hDlg,
|
|
IDC_TXT_USERNAME,
|
|
GetDsSelUserName(m_pSelectionList->aDsSelection[0]));
|
|
}
|
|
else
|
|
{
|
|
CString strMultiple(m_hInstance, IDS_MULTIPLE);
|
|
SetDlgItemText(hDlg, IDC_TXT_USERNAME, strMultiple);
|
|
}
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_ICON_USER),
|
|
STM_SETICON,
|
|
(WPARAM)m_hIconUser[1 == m_pSelectionList->cItems ? iICON_USER_SINGLE :
|
|
iICON_USER_MULTIPLE],
|
|
0);
|
|
|
|
|
|
return TRUE; // Set focus to default control.
|
|
}
|
|
|
|
//
|
|
// The Object Picker scope definition structure looks like this
|
|
// JeffreyS created these helper macros for working with the object picker
|
|
// in the ACLEDIT security UI. Thanks Jeff!
|
|
//
|
|
#if 0
|
|
{ // DSOP_SCOPE_INIT_INFO
|
|
cbSize,
|
|
flType,
|
|
flScope,
|
|
{ // DSOP_FILTER_FLAGS
|
|
{ // DSOP_UPLEVEL_FILTER_FLAGS
|
|
flBothModes,
|
|
flMixedModeOnly,
|
|
flNativeModeOnly
|
|
},
|
|
flDownlevel
|
|
},
|
|
pwzDcName,
|
|
pwzADsPath,
|
|
hr // OUT
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// macro for declaring one of the above
|
|
//
|
|
#define DECLARE_SCOPE(t,f,b,m,n,d) \
|
|
{ sizeof(DSOP_SCOPE_INIT_INFO), (t), (f), { { (b), (m), (n) }, (d) }, NULL, NULL, S_OK }
|
|
|
|
|
|
#define COMMON_SCOPE_FLAGS (DSOP_SCOPE_FLAG_WANT_PROVIDER_LDAP | DSOP_SCOPE_FLAG_WANT_SID_PATH)
|
|
|
|
#define TARGET_COMPUTER_SCOPE \
|
|
DECLARE_SCOPE( \
|
|
DSOP_SCOPE_TYPE_TARGET_COMPUTER, \
|
|
COMMON_SCOPE_FLAGS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_DOWNLEVEL_FILTER_USERS)
|
|
|
|
#define JOINED_UPLEVEL_DOMAIN_SCOPE \
|
|
DECLARE_SCOPE( \
|
|
DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN, \
|
|
COMMON_SCOPE_FLAGS | DSOP_SCOPE_FLAG_STARTING_SCOPE, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_DOWNLEVEL_FILTER_USERS)
|
|
|
|
#define JOINED_DOWNLEVEL_DOMAIN_SCOPE \
|
|
DECLARE_SCOPE( \
|
|
DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN, \
|
|
COMMON_SCOPE_FLAGS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_DOWNLEVEL_FILTER_USERS)
|
|
|
|
#define ENTERPRISE_DOMAIN_SCOPE \
|
|
DECLARE_SCOPE( \
|
|
DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN, \
|
|
COMMON_SCOPE_FLAGS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_DOWNLEVEL_FILTER_USERS)
|
|
|
|
#define EXTERNAL_UPLEVEL_DOMAIN_SCOPE \
|
|
DECLARE_SCOPE( \
|
|
DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN, \
|
|
COMMON_SCOPE_FLAGS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_DOWNLEVEL_FILTER_USERS)
|
|
|
|
#define EXTERNAL_DOWNLEVEL_DOMAIN_SCOPE \
|
|
DECLARE_SCOPE( \
|
|
DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN, \
|
|
COMMON_SCOPE_FLAGS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_DOWNLEVEL_FILTER_USERS)
|
|
|
|
#define GLOBAL_CATALOG_SCOPE \
|
|
DECLARE_SCOPE( \
|
|
DSOP_SCOPE_TYPE_GLOBAL_CATALOG, \
|
|
COMMON_SCOPE_FLAGS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_DOWNLEVEL_FILTER_USERS)
|
|
|
|
#define WORKGROUP_SCOPE \
|
|
DECLARE_SCOPE( \
|
|
DSOP_SCOPE_TYPE_WORKGROUP, \
|
|
COMMON_SCOPE_FLAGS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_FILTER_USERS, \
|
|
DSOP_DOWNLEVEL_FILTER_USERS)
|
|
|
|
//
|
|
// Invokes the standard DS object picker dialog.
|
|
// Returns a list of DS_SELECTION structures in a data object
|
|
// representing the selected user objects.
|
|
//
|
|
HRESULT
|
|
AddUserDialog::BrowseForUsers(
|
|
HWND hwndParent,
|
|
IDataObject **ppdtobj
|
|
)
|
|
{
|
|
DBGASSERT((NULL != hwndParent));
|
|
DBGASSERT((NULL != ppdtobj));
|
|
|
|
*ppdtobj = NULL;
|
|
|
|
IDsObjectPicker *pop = NULL;
|
|
HRESULT hr = CoCreateInstance(CLSID_DsObjectPicker,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDsObjectPicker,
|
|
(void **)&pop);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// This array initializes the scopes of the DS object picker.
|
|
// The first entry is the "default" scope.
|
|
//
|
|
DSOP_SCOPE_INIT_INFO rgdsii[] = {
|
|
JOINED_UPLEVEL_DOMAIN_SCOPE,
|
|
JOINED_DOWNLEVEL_DOMAIN_SCOPE,
|
|
ENTERPRISE_DOMAIN_SCOPE,
|
|
EXTERNAL_UPLEVEL_DOMAIN_SCOPE,
|
|
EXTERNAL_DOWNLEVEL_DOMAIN_SCOPE,
|
|
GLOBAL_CATALOG_SCOPE,
|
|
WORKGROUP_SCOPE,
|
|
TARGET_COMPUTER_SCOPE
|
|
};
|
|
|
|
DSOP_INIT_INFO dii;
|
|
dii.cbSize = sizeof(dii);
|
|
dii.pwzTargetComputer = NULL;
|
|
dii.cDsScopeInfos = ARRAYSIZE(rgdsii);
|
|
dii.aDsScopeInfos = rgdsii;
|
|
dii.flOptions = DSOP_FLAG_MULTISELECT;
|
|
dii.cAttributesToFetch = 0;
|
|
dii.apwzAttributeNames = NULL;
|
|
//
|
|
// Init and run the object picker dialog.
|
|
//
|
|
hr = pop->Initialize(&dii);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pop->InvokeDialog(hwndParent, ppdtobj);
|
|
}
|
|
pop->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
AddUserDialog::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_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);
|
|
}
|
|
break;
|
|
|
|
case IDC_RBN_USER_LIMIT:
|
|
if (!m_pxbQuotaThreshold->IsEnabled())
|
|
{
|
|
LONGLONG llValue = 0;
|
|
m_pQuotaControl->GetDefaultQuotaLimit(&llValue);
|
|
m_pxbQuotaLimit->SetBytes(NOLIMIT == llValue ? 0 : llValue);
|
|
|
|
llValue = 0;
|
|
m_pQuotaControl->GetDefaultQuotaThreshold(&llValue);
|
|
m_pxbQuotaThreshold->SetBytes(NOLIMIT == llValue ? 0 : llValue);
|
|
}
|
|
break;
|
|
|
|
case IDC_EDIT_USER_LIMIT:
|
|
case IDC_EDIT_USER_THRESHOLD:
|
|
switch(dwNotifyCode)
|
|
{
|
|
case EN_UPDATE:
|
|
bResult = OnEditNotifyUpdate(hDlg, wParam, lParam);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDC_CMB_USER_LIMIT:
|
|
case IDC_CMB_USER_THRESHOLD:
|
|
switch(dwNotifyCode)
|
|
{
|
|
case CBN_SELCHANGE:
|
|
bResult = OnComboNotifySelChange(hDlg, wParam, lParam);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
if (!OnOk(hDlg, wParam, lParam))
|
|
return FALSE;
|
|
//
|
|
// Fall through...
|
|
//
|
|
case IDCANCEL:
|
|
EndDialog(hDlg, 0);
|
|
break;
|
|
|
|
default:
|
|
bResult = TRUE; // Didn't handle message.
|
|
break;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
INT_PTR
|
|
AddUserDialog::OnOk(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
HRESULT hResult = NO_ERROR;
|
|
|
|
//
|
|
// We need to do this because if you activate the OK button
|
|
// with [Return] we receive the WM_COMMAND 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(m_hInstance, 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:
|
|
//
|
|
// Set focus to threshold edit box so user can correct
|
|
// the entry. Return early with FALSE value.
|
|
//
|
|
SetFocus(GetDlgItem(hDlg, IDC_EDIT_USER_THRESHOLD));
|
|
SendMessage(GetDlgItem(hDlg, IDC_EDIT_USER_THRESHOLD), EM_SETSEL, 0, -1);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
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;
|
|
//
|
|
// 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);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
INT_PTR
|
|
AddUserDialog::OnHelp(
|
|
HWND hDlg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, STR_DSKQUOUI_HELPFILE,
|
|
HELP_WM_HELP, (DWORD_PTR)(LPTSTR) rgAddUserDialogHelpIDs);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
AddUserDialog::OnContextMenu(
|
|
HWND hwndItem,
|
|
int xPos,
|
|
int yPos
|
|
)
|
|
{
|
|
int idCtl = GetDlgCtrlID(hwndItem);
|
|
WinHelp(hwndItem,
|
|
UseWindowsHelp(idCtl) ? NULL : STR_DSKQUOUI_HELPFILE,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)((LPTSTR)rgAddUserDialogHelpIDs));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
INT_PTR
|
|
AddUserDialog::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;
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
AddUserDialog::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;
|
|
}
|
|
|
|
|
|
//
|
|
// Retrieve from a DS_SELECTION structure the name to display for
|
|
// a user object.
|
|
//
|
|
LPCWSTR
|
|
AddUserDialog::GetDsSelUserName(
|
|
const DS_SELECTION& sel
|
|
)
|
|
{
|
|
return sel.pwzUPN && *sel.pwzUPN ? sel.pwzUPN : sel.pwzName;
|
|
}
|
|
|
|
|
|
//
|
|
// Convert two hex chars into a single byte value.
|
|
// Assumes input string is in upper case.
|
|
//
|
|
HRESULT
|
|
AddUserDialog::HexCharsToByte(
|
|
LPTSTR pszByteIn,
|
|
LPBYTE pbOut
|
|
)
|
|
{
|
|
static const int iShift[] = { 4, 0 };
|
|
|
|
*pbOut = (BYTE)0;
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
TCHAR ch = *(pszByteIn + i);
|
|
BYTE b = (BYTE)0;
|
|
if (TEXT('0') <= ch && TEXT('9') >= ch)
|
|
{
|
|
b = ch - TEXT('0');
|
|
}
|
|
else if (TEXT('A') <= ch && TEXT('F') >= ch)
|
|
{
|
|
b = 10 + (ch - TEXT('A'));
|
|
}
|
|
else
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
*pbOut |= (b << iShift[i]);
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
//
|
|
// Returns:
|
|
//
|
|
// NOERROR
|
|
// ERROR_INSUFFICIENT_BUFFER (as hresult)
|
|
// ERROR_INVALID_DATA (as hresult)
|
|
//
|
|
HRESULT
|
|
AddUserDialog::GetDsSelUserSid(
|
|
const DS_SELECTION& sel,
|
|
LPBYTE pbSid,
|
|
int cbSid
|
|
)
|
|
{
|
|
static const WCHAR szPrefix[] = L"LDAP://<SID=";
|
|
static const WCHAR chTerm = L'>';
|
|
|
|
HRESULT hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
LPWSTR pszLDAP = CharUpper(sel.pwzADsPath);
|
|
if (NULL != pszLDAP)
|
|
{
|
|
int cb = 0;
|
|
|
|
//
|
|
// First check for the required prefix.
|
|
//
|
|
if (0 == StrCmpNW(pszLDAP, szPrefix, ARRAYSIZE(szPrefix) - 1))
|
|
{
|
|
hr = NOERROR;
|
|
//
|
|
// Advance ptr beyond prefix and convert the hex string
|
|
// into a SID. Process chars until we hit a '>'.
|
|
//
|
|
pszLDAP += ARRAYSIZE(szPrefix) - 1;
|
|
|
|
while(SUCCEEDED(hr) && *pszLDAP && chTerm != *pszLDAP)
|
|
{
|
|
if (0 < cbSid--)
|
|
{
|
|
hr = HexCharsToByte(pszLDAP, pbSid++);
|
|
pszLDAP += 2;
|
|
}
|
|
else
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
if (SUCCEEDED(hr) && chTerm != *pszLDAP)
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// FEATURE: This can be removed once I'm comfortable that all
|
|
// ADs paths returned from the object picker contain
|
|
// a SID.
|
|
//
|
|
DBGERROR((TEXT("GetDsSelUserSid returning hr = 0x%08X for path \"%s\""),
|
|
hr, sel.pwzADsPath));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AddUserDialog::ApplySettings(
|
|
HWND hDlg,
|
|
bool bUndo
|
|
)
|
|
{
|
|
HRESULT hResult = E_FAIL;
|
|
int cUsers = m_pSelectionList->cItems;
|
|
CAutoWaitCursor wait_cursor;
|
|
|
|
//
|
|
// Retrieve limit and threshold values from dialog controls.
|
|
//
|
|
if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RBN_USER_NOLIMIT))
|
|
{
|
|
m_llQuotaThreshold = NOLIMIT;
|
|
m_llQuotaLimit = NOLIMIT;
|
|
}
|
|
else
|
|
{
|
|
m_llQuotaThreshold = m_pxbQuotaThreshold->GetBytes();
|
|
m_llQuotaLimit = m_pxbQuotaLimit->GetBytes();
|
|
}
|
|
|
|
|
|
if (bUndo)
|
|
m_UndoList.Clear();
|
|
|
|
ProgressDialog dlgProgress(IDD_PROGRESS,
|
|
IDC_PROGRESS_BAR,
|
|
IDC_TXT_PROGRESS_DESCRIPTION,
|
|
IDC_TXT_PROGRESS_FILENAME);
|
|
if (2 < cUsers)
|
|
{
|
|
//
|
|
// Create and display a progress dialog if we're adding more than 2
|
|
// users.
|
|
//
|
|
HWND hwndParent = IsWindowVisible(hDlg) ? hDlg : GetParent(hDlg);
|
|
if (dlgProgress.Create(m_hInstance, hwndParent))
|
|
{
|
|
dlgProgress.ProgressBarInit(0, cUsers, 1);
|
|
dlgProgress.SetDescription(MAKEINTRESOURCE(IDS_PROGRESS_ADDUSER));
|
|
dlgProgress.Show();
|
|
}
|
|
}
|
|
|
|
bool bCancelled = false;
|
|
for (int i = 0; i < cUsers && !bCancelled; i++)
|
|
{
|
|
DS_SELECTION *pdss = &(m_pSelectionList->aDsSelection[i]);
|
|
LPCWSTR pwzName = GetDsSelUserName(*pdss);
|
|
|
|
//
|
|
// Add a user to the quota file. This will add it using the defaults
|
|
// for new users. We get back an interface to the new user object.
|
|
// Also specify async name resolution.
|
|
//
|
|
if (NULL == pwzName)
|
|
{
|
|
dlgProgress.ProgressBarAdvance();
|
|
continue;
|
|
}
|
|
|
|
dlgProgress.SetFileName(pwzName);
|
|
|
|
com_autoptr<DISKQUOTA_USER> ptrUser;
|
|
DiskQuotaControl *pDQC = static_cast<DiskQuotaControl *>(m_pQuotaControl);
|
|
|
|
BYTE sid[MAX_SID_LEN];
|
|
hResult = GetDsSelUserSid(*pdss, sid, ARRAYSIZE(sid));
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
hResult = pDQC->AddUserSid(sid,
|
|
DISKQUOTA_USERNAME_RESOLVE_ASYNC,
|
|
ptrUser.getaddr());
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
if (S_FALSE == hResult)
|
|
{
|
|
hResult = HRESULT_FROM_WIN32(ERROR_USER_EXISTS);
|
|
}
|
|
else
|
|
{
|
|
if (SUCCEEDED(hResult = ptrUser->SetQuotaLimit(m_llQuotaLimit, TRUE)) &&
|
|
SUCCEEDED(hResult = ptrUser->SetQuotaThreshold(m_llQuotaThreshold, TRUE)))
|
|
{
|
|
if (bUndo)
|
|
{
|
|
//
|
|
// Create local autoptrs to ensure iface release if an
|
|
// exception is thrown.
|
|
//
|
|
com_autoptr<DISKQUOTA_CONTROL> ptrQuotaControl(m_pQuotaControl);
|
|
com_autoptr<DISKQUOTA_USER> ptrQuotaUser(ptrUser);
|
|
|
|
ptrQuotaUser->AddRef();
|
|
ptrQuotaControl->AddRef();
|
|
|
|
autoptr<UndoAdd> ptrUndoAdd = new UndoAdd(ptrUser, m_pQuotaControl);
|
|
|
|
m_UndoList.Add(ptrUndoAdd);
|
|
//
|
|
// Undo list now owns the action object.
|
|
//
|
|
ptrUndoAdd.disown();
|
|
|
|
//
|
|
// Successfully added to undo list. Disown real ptrs so
|
|
// ref count stays with undo list. If an exception was
|
|
// thrown, the local com_autoptr objects will automatically
|
|
// release the interfaces.
|
|
//
|
|
ptrQuotaUser.disown();
|
|
ptrQuotaControl.disown();
|
|
}
|
|
|
|
//
|
|
// Add the user to the listview.
|
|
//
|
|
SendMessage(m_hwndDetailsLV,
|
|
WM_ADD_USER_TO_DETAILS_VIEW,
|
|
0,
|
|
(LPARAM)ptrUser.get());
|
|
//
|
|
// iface pointer added to listview. autoptr disowns the real
|
|
// pointer so the autoptr's dtor doesn't release it.
|
|
//
|
|
ptrUser.disown();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (FAILED(hResult))
|
|
{
|
|
INT idMsg = IDS_UNKNOWN_ERROR;
|
|
UINT uFlags = MB_OKCANCEL;
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Display message box with msg formatted as:
|
|
//
|
|
// The user already exists and could not be added.
|
|
//
|
|
// User: brianau
|
|
// In Folder: Domain/Folder: ntdev.microsoft.com/US SOS-...
|
|
//
|
|
CString strError(m_hInstance, idMsg);
|
|
CString strMsg(m_hInstance, IDS_FMT_ERR_ADDUSER, strError.Cstr(), pwzName);
|
|
|
|
HWND hwndMsgBoxParent = (NULL != dlgProgress.m_hWnd && IsWindowVisible(dlgProgress.m_hWnd)) ?
|
|
dlgProgress.m_hWnd : hDlg;
|
|
|
|
if (IDCANCEL == DiskQuotaMsgBox(hwndMsgBoxParent,
|
|
strMsg.Cstr(),
|
|
IDS_TITLE_DISK_QUOTA,
|
|
uFlags))
|
|
{
|
|
bCancelled = true;
|
|
}
|
|
}
|
|
dlgProgress.ProgressBarAdvance();
|
|
bCancelled = bCancelled || dlgProgress.UserCancelled();
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|