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

1110 lines
33 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
///////////////////////////////////////////////////////////////////////////////
/* 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;
}