Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1109 lines
34 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: adusrdlg.cpp
  3. Description: Provides implementations for the "Add User" dialog.
  4. Revision History:
  5. Date Description Programmer
  6. -------- --------------------------------------------------- ----------
  7. 08/15/96 Initial creation. BrianAu
  8. */
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "pch.h" // PCH
  11. #pragma hdrstop
  12. #include <lm.h>
  13. #include "undo.h"
  14. #include "adusrdlg.h"
  15. #include "uihelp.h"
  16. #include "progress.h"
  17. #include "uiutils.h"
  18. //
  19. // Context help IDs.
  20. //
  21. #pragma data_seg(".text", "CODE")
  22. const static DWORD rgAddUserDialogHelpIDs[] =
  23. {
  24. IDC_ICON_USER, DWORD(-1),
  25. IDC_STATIC2, DWORD(-1),
  26. IDC_TXT_DEFAULTS, DWORD(-1),
  27. IDC_TXT_USERNAME, IDH_TXT_USERNAME,
  28. IDC_TXT_SPACEUSED, IDH_TXT_SPACEUSED,
  29. IDC_TXT_SPACEREMAINING, IDH_TXT_SPACEREMAINING,
  30. IDC_ICON_USERSTATUS, IDH_ICON_USERSTATUS,
  31. IDC_RBN_USER_NOLIMIT, IDH_RBN_USER_NOLIMIT,
  32. IDC_RBN_USER_LIMIT, IDH_RBN_USER_LIMIT,
  33. IDC_TXT_WARN_LEVEL, DWORD(-1),
  34. IDC_EDIT_USER_LIMIT, IDH_EDIT_USER_LIMIT,
  35. IDC_EDIT_USER_THRESHOLD, IDH_EDIT_USER_THRESHOLD,
  36. IDC_CMB_USER_LIMIT, IDH_CMB_USER_LIMIT,
  37. IDC_CMB_USER_THRESHOLD, IDH_CMB_USER_THRESHOLD,
  38. 0,0
  39. };
  40. #pragma data_seg()
  41. ///////////////////////////////////////////////////////////////////////////////
  42. /* Function: AddUserDialog::AddUserDialog
  43. Description: Constructor for a user property sheet object.
  44. Initializes the members that hold user quota data.
  45. Arguments: None.
  46. Returns: Nothing.
  47. Exceptions: OutOfMemory.
  48. Revision History:
  49. Date Description Programmer
  50. -------- --------------------------------------------------- ----------
  51. 08/15/96 Initial creation. BrianAu
  52. */
  53. ///////////////////////////////////////////////////////////////////////////////
  54. AddUserDialog::AddUserDialog(
  55. PDISKQUOTA_CONTROL pQuotaControl,
  56. const CVolumeID& idVolume,
  57. HINSTANCE hInstance,
  58. HWND hwndParent,
  59. HWND hwndDetailsLV,
  60. UndoList& UndoList
  61. ) : m_cVolumeMaxBytes(0),
  62. m_pQuotaControl(pQuotaControl),
  63. m_idVolume(idVolume),
  64. m_UndoList(UndoList),
  65. m_hInstance(hInstance),
  66. m_hwndParent(hwndParent),
  67. m_hwndDetailsLV(hwndDetailsLV),
  68. m_pxbQuotaLimit(NULL),
  69. m_pxbQuotaThreshold(NULL),
  70. m_llQuotaLimit(0),
  71. m_llQuotaThreshold(0),
  72. m_pSelectionList(NULL), // Object instance doesn't own this memory.
  73. m_cfSelectionList((CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST))
  74. {
  75. DBGASSERT((NULL != m_pQuotaControl));
  76. DBGASSERT((NULL != m_hwndParent));
  77. DBGTRACE((DM_UPROP, DL_HIGH, TEXT("AddUserDialog::AddUserDialog")));
  78. DBGASSERT((0 == iICON_USER_SINGLE));
  79. DBGASSERT((1 == iICON_USER_MULTIPLE));
  80. m_hIconUser[0] = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_SINGLE_USER));
  81. m_hIconUser[1] = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_MULTI_USER));
  82. }
  83. AddUserDialog::~AddUserDialog(
  84. VOID
  85. )
  86. {
  87. DBGTRACE((DM_UPROP, DL_HIGH, TEXT("AddUserDialog::~AddUserDialog")));
  88. INT i = 0;
  89. if (NULL != m_pQuotaControl)
  90. m_pQuotaControl->Release();
  91. if (NULL != m_pxbQuotaLimit)
  92. delete m_pxbQuotaLimit;
  93. if (NULL != m_pxbQuotaThreshold)
  94. delete m_pxbQuotaThreshold;
  95. }
  96. ///////////////////////////////////////////////////////////////////////////////
  97. /* Function: AddUserDialog::Run
  98. Description: Creates and runs the property sheet dialog.
  99. This is the only method a client needs to call once the object
  100. is created.
  101. Arguments: None.
  102. Returns:
  103. NO_ERROR
  104. E_FAIL - Couldn't create property sheet.
  105. Revision History:
  106. Date Description Programmer
  107. -------- --------------------------------------------------- ----------
  108. 08/15/96 Initial creation. BrianAu
  109. */
  110. ///////////////////////////////////////////////////////////////////////////////
  111. HRESULT
  112. AddUserDialog::Run(
  113. VOID
  114. )
  115. {
  116. //
  117. // Invoke the standard object picker dialog.
  118. //
  119. IDataObject *pdtobj = NULL;
  120. HRESULT hr = BrowseForUsers(m_hwndParent, &pdtobj);
  121. if (S_OK == hr)
  122. {
  123. //
  124. // Retrieve the data object representing the selected user objects.
  125. //
  126. FORMATETC fe = { m_cfSelectionList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  127. STGMEDIUM stg;
  128. hr = pdtobj->GetData(&fe, &stg);
  129. {
  130. //
  131. // Cache the data obj ptr so the dialog can have access.
  132. //
  133. m_pSelectionList = (DS_SELECTION_LIST *)GlobalLock(stg.hGlobal);
  134. if (NULL != m_pSelectionList)
  135. {
  136. hr = (HRESULT) DialogBoxParam(m_hInstance,
  137. MAKEINTRESOURCE(IDD_ADDUSER),
  138. m_hwndParent,
  139. DlgProc,
  140. (LPARAM)this);
  141. GlobalUnlock(stg.hGlobal);
  142. m_pSelectionList = NULL;
  143. }
  144. ReleaseStgMedium(&stg);
  145. }
  146. pdtobj->Release();
  147. }
  148. return hr;
  149. }
  150. ///////////////////////////////////////////////////////////////////////////////
  151. /* Function: AddUserDialog::DlgProc
  152. Description: Static method called by windows to process messages for the
  153. property page dialog. Since it's static, we have to save the "this"
  154. pointer in the window's USERDATA.
  155. Arguments: Standard WndProc-type arguments.
  156. Returns: Standard WndProc-type return values.
  157. Revision History:
  158. Date Description Programmer
  159. -------- --------------------------------------------------- ----------
  160. 08/15/96 Initial creation. BrianAu
  161. */
  162. ///////////////////////////////////////////////////////////////////////////////
  163. INT_PTR CALLBACK
  164. AddUserDialog::DlgProc(
  165. HWND hDlg,
  166. UINT message,
  167. WPARAM wParam,
  168. LPARAM lParam
  169. )
  170. {
  171. INT_PTR bResult = FALSE;
  172. //
  173. // Retrieve the "this" pointer from the dialog's userdata.
  174. // It was placed there in OnInitDialog().
  175. //
  176. AddUserDialog *pThis = (AddUserDialog *)GetWindowLongPtr(hDlg, DWLP_USER);
  177. try
  178. {
  179. switch(message)
  180. {
  181. case WM_INITDIALOG:
  182. DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_INITDIALOG")));
  183. pThis = (AddUserDialog *)lParam;
  184. DBGASSERT((NULL != pThis));
  185. //
  186. // Save "this" in the window's userdata.
  187. //
  188. SetWindowLongPtr(hDlg, DWLP_USER, (INT_PTR)pThis);
  189. bResult = pThis->OnInitDialog(hDlg, wParam, lParam);
  190. break;
  191. case WM_COMMAND:
  192. DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_COMMAND")));
  193. bResult = pThis->OnCommand(hDlg, wParam, lParam);
  194. break;
  195. case WM_CONTEXTMENU:
  196. bResult = pThis->OnContextMenu((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  197. break;
  198. case WM_HELP:
  199. DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_HELP")));
  200. bResult = pThis->OnHelp(hDlg, wParam, lParam);
  201. break;
  202. case WM_DESTROY:
  203. DBGPRINT((DM_WND, DL_MID, TEXT("DlgProc: WM_DESTROY")));
  204. break;
  205. default:
  206. break;
  207. }
  208. }
  209. catch(CAllocException& e)
  210. {
  211. DiskQuotaMsgBox(GetDesktopWindow(),
  212. IDS_OUTOFMEMORY,
  213. IDS_TITLE_DISK_QUOTA,
  214. MB_ICONERROR | MB_OK);
  215. }
  216. return bResult;
  217. }
  218. INT_PTR
  219. AddUserDialog::OnInitDialog(
  220. HWND hDlg,
  221. WPARAM wParam,
  222. LPARAM lParam
  223. )
  224. {
  225. HRESULT hResult = NO_ERROR;
  226. DWORD dwSectorsPerCluster = 0;
  227. DWORD dwBytesPerSector = 0;
  228. DWORD dwFreeClusters = 0;
  229. DWORD dwTotalClusters = 0;
  230. //
  231. // The "new user" dialog is initialized with the volume's default quota
  232. // limit and threshold for new users.
  233. //
  234. m_pQuotaControl->GetDefaultQuotaLimit(&m_llQuotaLimit);
  235. m_pQuotaControl->GetDefaultQuotaThreshold(&m_llQuotaThreshold);
  236. //
  237. // Configure the Limit/NoLimit radio buttons.
  238. //
  239. if (NOLIMIT == m_llQuotaThreshold)
  240. {
  241. CheckDlgButton(hDlg, IDC_RBN_USER_LIMIT, FALSE);
  242. CheckDlgButton(hDlg, IDC_RBN_USER_NOLIMIT, TRUE);
  243. }
  244. else
  245. {
  246. CheckDlgButton(hDlg, IDC_RBN_USER_LIMIT, TRUE);
  247. CheckDlgButton(hDlg, IDC_RBN_USER_NOLIMIT, FALSE);
  248. }
  249. //
  250. // Calculate the volume's size.
  251. // We'll use this to limit user threshold and quota limit entries.
  252. //
  253. if (GetDiskFreeSpace(m_idVolume.ForParsing(),
  254. &dwSectorsPerCluster,
  255. &dwBytesPerSector,
  256. &dwFreeClusters,
  257. &dwTotalClusters))
  258. {
  259. m_cVolumeMaxBytes = (LONGLONG)dwSectorsPerCluster *
  260. (LONGLONG)dwBytesPerSector *
  261. (LONGLONG)dwTotalClusters;
  262. }
  263. m_pxbQuotaLimit = new XBytes(hDlg,
  264. IDC_EDIT_USER_LIMIT,
  265. IDC_CMB_USER_LIMIT,
  266. m_llQuotaLimit);
  267. m_pxbQuotaLimit->SetBytes(m_llQuotaLimit);
  268. m_pxbQuotaThreshold = new XBytes(hDlg,
  269. IDC_EDIT_USER_THRESHOLD,
  270. IDC_CMB_USER_THRESHOLD,
  271. m_llQuotaThreshold);
  272. m_pxbQuotaThreshold->SetBytes(m_llQuotaThreshold);
  273. DBGASSERT((0 < m_pSelectionList->cItems));
  274. if (1 == m_pSelectionList->cItems)
  275. {
  276. SetDlgItemText(hDlg,
  277. IDC_TXT_USERNAME,
  278. GetDsSelUserName(m_pSelectionList->aDsSelection[0]));
  279. }
  280. else
  281. {
  282. CString strMultiple(m_hInstance, IDS_MULTIPLE);
  283. SetDlgItemText(hDlg, IDC_TXT_USERNAME, strMultiple);
  284. }
  285. SendMessage(GetDlgItem(hDlg, IDC_ICON_USER),
  286. STM_SETICON,
  287. (WPARAM)m_hIconUser[1 == m_pSelectionList->cItems ? iICON_USER_SINGLE :
  288. iICON_USER_MULTIPLE],
  289. 0);
  290. return TRUE; // Set focus to default control.
  291. }
  292. //
  293. // The Object Picker scope definition structure looks like this
  294. // JeffreyS created these helper macros for working with the object picker
  295. // in the ACLEDIT security UI. Thanks Jeff!
  296. //
  297. #if 0
  298. { // DSOP_SCOPE_INIT_INFO
  299. cbSize,
  300. flType,
  301. flScope,
  302. { // DSOP_FILTER_FLAGS
  303. { // DSOP_UPLEVEL_FILTER_FLAGS
  304. flBothModes,
  305. flMixedModeOnly,
  306. flNativeModeOnly
  307. },
  308. flDownlevel
  309. },
  310. pwzDcName,
  311. pwzADsPath,
  312. hr // OUT
  313. }
  314. #endif
  315. //
  316. // macro for declaring one of the above
  317. //
  318. #define DECLARE_SCOPE(t,f,b,m,n,d) \
  319. { sizeof(DSOP_SCOPE_INIT_INFO), (t), (f), { { (b), (m), (n) }, (d) }, NULL, NULL, S_OK }
  320. #define COMMON_SCOPE_FLAGS (DSOP_SCOPE_FLAG_WANT_PROVIDER_LDAP | DSOP_SCOPE_FLAG_WANT_SID_PATH)
  321. #define TARGET_COMPUTER_SCOPE \
  322. DECLARE_SCOPE( \
  323. DSOP_SCOPE_TYPE_TARGET_COMPUTER, \
  324. COMMON_SCOPE_FLAGS, \
  325. DSOP_FILTER_USERS, \
  326. DSOP_FILTER_USERS, \
  327. DSOP_FILTER_USERS, \
  328. DSOP_DOWNLEVEL_FILTER_USERS)
  329. #define JOINED_UPLEVEL_DOMAIN_SCOPE \
  330. DECLARE_SCOPE( \
  331. DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN, \
  332. COMMON_SCOPE_FLAGS | DSOP_SCOPE_FLAG_STARTING_SCOPE, \
  333. DSOP_FILTER_USERS, \
  334. DSOP_FILTER_USERS, \
  335. DSOP_FILTER_USERS, \
  336. DSOP_DOWNLEVEL_FILTER_USERS)
  337. #define JOINED_DOWNLEVEL_DOMAIN_SCOPE \
  338. DECLARE_SCOPE( \
  339. DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN, \
  340. COMMON_SCOPE_FLAGS, \
  341. DSOP_FILTER_USERS, \
  342. DSOP_FILTER_USERS, \
  343. DSOP_FILTER_USERS, \
  344. DSOP_DOWNLEVEL_FILTER_USERS)
  345. #define ENTERPRISE_DOMAIN_SCOPE \
  346. DECLARE_SCOPE( \
  347. DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN, \
  348. COMMON_SCOPE_FLAGS, \
  349. DSOP_FILTER_USERS, \
  350. DSOP_FILTER_USERS, \
  351. DSOP_FILTER_USERS, \
  352. DSOP_DOWNLEVEL_FILTER_USERS)
  353. #define EXTERNAL_UPLEVEL_DOMAIN_SCOPE \
  354. DECLARE_SCOPE( \
  355. DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN, \
  356. COMMON_SCOPE_FLAGS, \
  357. DSOP_FILTER_USERS, \
  358. DSOP_FILTER_USERS, \
  359. DSOP_FILTER_USERS, \
  360. DSOP_DOWNLEVEL_FILTER_USERS)
  361. #define EXTERNAL_DOWNLEVEL_DOMAIN_SCOPE \
  362. DECLARE_SCOPE( \
  363. DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN, \
  364. COMMON_SCOPE_FLAGS, \
  365. DSOP_FILTER_USERS, \
  366. DSOP_FILTER_USERS, \
  367. DSOP_FILTER_USERS, \
  368. DSOP_DOWNLEVEL_FILTER_USERS)
  369. #define GLOBAL_CATALOG_SCOPE \
  370. DECLARE_SCOPE( \
  371. DSOP_SCOPE_TYPE_GLOBAL_CATALOG, \
  372. COMMON_SCOPE_FLAGS, \
  373. DSOP_FILTER_USERS, \
  374. DSOP_FILTER_USERS, \
  375. DSOP_FILTER_USERS, \
  376. DSOP_DOWNLEVEL_FILTER_USERS)
  377. #define WORKGROUP_SCOPE \
  378. DECLARE_SCOPE( \
  379. DSOP_SCOPE_TYPE_WORKGROUP, \
  380. COMMON_SCOPE_FLAGS, \
  381. DSOP_FILTER_USERS, \
  382. DSOP_FILTER_USERS, \
  383. DSOP_FILTER_USERS, \
  384. DSOP_DOWNLEVEL_FILTER_USERS)
  385. //
  386. // Invokes the standard DS object picker dialog.
  387. // Returns a list of DS_SELECTION structures in a data object
  388. // representing the selected user objects.
  389. //
  390. HRESULT
  391. AddUserDialog::BrowseForUsers(
  392. HWND hwndParent,
  393. IDataObject **ppdtobj
  394. )
  395. {
  396. DBGASSERT((NULL != hwndParent));
  397. DBGASSERT((NULL != ppdtobj));
  398. *ppdtobj = NULL;
  399. IDsObjectPicker *pop = NULL;
  400. HRESULT hr = CoCreateInstance(CLSID_DsObjectPicker,
  401. NULL,
  402. CLSCTX_INPROC_SERVER,
  403. IID_IDsObjectPicker,
  404. (void **)&pop);
  405. if (SUCCEEDED(hr))
  406. {
  407. //
  408. // This array initializes the scopes of the DS object picker.
  409. // The first entry is the "default" scope.
  410. //
  411. DSOP_SCOPE_INIT_INFO rgdsii[] = {
  412. JOINED_UPLEVEL_DOMAIN_SCOPE,
  413. JOINED_DOWNLEVEL_DOMAIN_SCOPE,
  414. ENTERPRISE_DOMAIN_SCOPE,
  415. EXTERNAL_UPLEVEL_DOMAIN_SCOPE,
  416. EXTERNAL_DOWNLEVEL_DOMAIN_SCOPE,
  417. GLOBAL_CATALOG_SCOPE,
  418. WORKGROUP_SCOPE,
  419. TARGET_COMPUTER_SCOPE
  420. };
  421. DSOP_INIT_INFO dii;
  422. dii.cbSize = sizeof(dii);
  423. dii.pwzTargetComputer = NULL;
  424. dii.cDsScopeInfos = ARRAYSIZE(rgdsii);
  425. dii.aDsScopeInfos = rgdsii;
  426. dii.flOptions = DSOP_FLAG_MULTISELECT;
  427. dii.cAttributesToFetch = 0;
  428. dii.apwzAttributeNames = NULL;
  429. //
  430. // Init and run the object picker dialog.
  431. //
  432. hr = pop->Initialize(&dii);
  433. if (SUCCEEDED(hr))
  434. {
  435. hr = pop->InvokeDialog(hwndParent, ppdtobj);
  436. }
  437. pop->Release();
  438. }
  439. return hr;
  440. }
  441. INT_PTR
  442. AddUserDialog::OnCommand(
  443. HWND hDlg,
  444. WPARAM wParam,
  445. LPARAM lParam
  446. )
  447. {
  448. DWORD dwCtlId = LOWORD(wParam);
  449. HWND hWndCtl = (HWND)lParam;
  450. DWORD dwNotifyCode = HIWORD(wParam);
  451. INT_PTR bResult = FALSE;
  452. switch(dwCtlId)
  453. {
  454. case IDC_RBN_USER_NOLIMIT:
  455. if (m_pxbQuotaThreshold->IsEnabled())
  456. {
  457. //
  458. // This is simple. Just set both the limit and threshold controls
  459. // to "no limit".
  460. //
  461. m_pxbQuotaThreshold->SetBytes(NOLIMIT);
  462. m_pxbQuotaLimit->SetBytes(NOLIMIT);
  463. }
  464. break;
  465. case IDC_RBN_USER_LIMIT:
  466. if (!m_pxbQuotaThreshold->IsEnabled())
  467. {
  468. LONGLONG llValue = 0;
  469. m_pQuotaControl->GetDefaultQuotaLimit(&llValue);
  470. m_pxbQuotaLimit->SetBytes(NOLIMIT == llValue ? 0 : llValue);
  471. llValue = 0;
  472. m_pQuotaControl->GetDefaultQuotaThreshold(&llValue);
  473. m_pxbQuotaThreshold->SetBytes(NOLIMIT == llValue ? 0 : llValue);
  474. }
  475. break;
  476. case IDC_EDIT_USER_LIMIT:
  477. case IDC_EDIT_USER_THRESHOLD:
  478. switch(dwNotifyCode)
  479. {
  480. case EN_UPDATE:
  481. bResult = OnEditNotifyUpdate(hDlg, wParam, lParam);
  482. break;
  483. default:
  484. break;
  485. }
  486. break;
  487. case IDC_CMB_USER_LIMIT:
  488. case IDC_CMB_USER_THRESHOLD:
  489. switch(dwNotifyCode)
  490. {
  491. case CBN_SELCHANGE:
  492. bResult = OnComboNotifySelChange(hDlg, wParam, lParam);
  493. break;
  494. default:
  495. break;
  496. }
  497. break;
  498. case IDOK:
  499. if (!OnOk(hDlg, wParam, lParam))
  500. return FALSE;
  501. //
  502. // Fall through...
  503. //
  504. case IDCANCEL:
  505. EndDialog(hDlg, 0);
  506. break;
  507. default:
  508. bResult = TRUE; // Didn't handle message.
  509. break;
  510. }
  511. return bResult;
  512. }
  513. INT_PTR
  514. AddUserDialog::OnOk(
  515. HWND hDlg,
  516. WPARAM wParam,
  517. LPARAM lParam
  518. )
  519. {
  520. HRESULT hResult = NO_ERROR;
  521. //
  522. // We need to do this because if you activate the OK button
  523. // with [Return] we receive the WM_COMMAND before EN_KILLFOCUS.
  524. //
  525. m_pxbQuotaThreshold->OnEditKillFocus((LPARAM)GetDlgItem(hDlg, IDC_EDIT_USER_THRESHOLD));
  526. m_pxbQuotaLimit->OnEditKillFocus((LPARAM)GetDlgItem(hDlg, IDC_EDIT_USER_LIMIT));
  527. //
  528. // Ensure warning threshold is not above limit.
  529. //
  530. INT64 iThreshold = m_pxbQuotaThreshold->GetBytes();
  531. INT64 iLimit = m_pxbQuotaLimit->GetBytes();
  532. if (NOLIMIT != iLimit && iThreshold > iLimit)
  533. {
  534. TCHAR szLimit[40], szThreshold[40];
  535. XBytes::FormatByteCountForDisplay(iLimit, szLimit, ARRAYSIZE(szLimit));
  536. XBytes::FormatByteCountForDisplay(iThreshold, szThreshold, ARRAYSIZE(szThreshold));
  537. CString s(m_hInstance, IDS_FMT_ERR_WARNOVERLIMIT, szThreshold, szLimit, szLimit);
  538. switch(DiskQuotaMsgBox(hDlg, s, IDS_TITLE_DISK_QUOTA, MB_ICONWARNING | MB_YESNO))
  539. {
  540. case IDYES:
  541. m_pxbQuotaThreshold->SetBytes(iLimit);
  542. break;
  543. case IDNO:
  544. //
  545. // Set focus to threshold edit box so user can correct
  546. // the entry. Return early with FALSE value.
  547. //
  548. SetFocus(GetDlgItem(hDlg, IDC_EDIT_USER_THRESHOLD));
  549. SendMessage(GetDlgItem(hDlg, IDC_EDIT_USER_THRESHOLD), EM_SETSEL, 0, -1);
  550. return FALSE;
  551. }
  552. }
  553. //
  554. // Only apply settings if the "Apply" button is enabled indicating
  555. // that something has been changed. No need to apply unchanged
  556. // settings when the OK button is pressed.
  557. //
  558. hResult = ApplySettings(hDlg);
  559. if (FAILED(hResult))
  560. {
  561. INT idMsg = IDS_UNKNOWN_ERROR;
  562. UINT uFlags = MB_OK;
  563. switch(hResult)
  564. {
  565. case E_FAIL:
  566. idMsg = IDS_WRITE_ERROR;
  567. uFlags |= MB_ICONERROR;
  568. break;
  569. default:
  570. switch(HRESULT_CODE(hResult))
  571. {
  572. // case ERROR_USER_EXISTS:
  573. // idMsg = IDS_NOADD_EXISTING_USER;
  574. // uFlags |= MB_ICONWARNING;
  575. // break;
  576. //
  577. // Still valid? [brianau - 5/27/98]
  578. //
  579. case ERROR_NO_SUCH_USER:
  580. idMsg = IDS_NOADD_UNKNOWN_USER;
  581. uFlags |= MB_ICONWARNING;
  582. break;
  583. case ERROR_ACCESS_DENIED:
  584. idMsg = IDS_NO_WRITE_ACCESS;
  585. uFlags |= MB_ICONWARNING;
  586. break;
  587. default:
  588. uFlags |= MB_ICONERROR;
  589. break;
  590. }
  591. break;
  592. }
  593. DiskQuotaMsgBox(GetDesktopWindow(),
  594. idMsg,
  595. IDS_TITLE_DISK_QUOTA,
  596. uFlags);
  597. }
  598. return TRUE;
  599. }
  600. INT_PTR
  601. AddUserDialog::OnHelp(
  602. HWND hDlg,
  603. WPARAM wParam,
  604. LPARAM lParam
  605. )
  606. {
  607. WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, STR_DSKQUOUI_HELPFILE,
  608. HELP_WM_HELP, (DWORD_PTR)(LPTSTR) rgAddUserDialogHelpIDs);
  609. return TRUE;
  610. }
  611. INT_PTR
  612. AddUserDialog::OnContextMenu(
  613. HWND hwndItem,
  614. int xPos,
  615. int yPos
  616. )
  617. {
  618. int idCtl = GetDlgCtrlID(hwndItem);
  619. WinHelp(hwndItem,
  620. UseWindowsHelp(idCtl) ? NULL : STR_DSKQUOUI_HELPFILE,
  621. HELP_CONTEXTMENU,
  622. (DWORD_PTR)((LPTSTR)rgAddUserDialogHelpIDs));
  623. return FALSE;
  624. }
  625. INT_PTR
  626. AddUserDialog::OnEditNotifyUpdate(
  627. HWND hDlg,
  628. WPARAM wParam,
  629. LPARAM lParam
  630. )
  631. {
  632. XBytes *pxb = NULL;
  633. switch(LOWORD(wParam))
  634. {
  635. case IDC_EDIT_USER_LIMIT:
  636. pxb = m_pxbQuotaLimit;
  637. break;
  638. case IDC_EDIT_USER_THRESHOLD:
  639. pxb = m_pxbQuotaThreshold;
  640. break;
  641. default:
  642. break;
  643. }
  644. if (NULL != pxb)
  645. pxb->OnEditNotifyUpdate(lParam);
  646. return FALSE;
  647. }
  648. INT_PTR
  649. AddUserDialog::OnComboNotifySelChange(
  650. HWND hDlg,
  651. WPARAM wParam,
  652. LPARAM lParam
  653. )
  654. {
  655. XBytes *pxb = NULL;
  656. switch(LOWORD(wParam))
  657. {
  658. case IDC_CMB_USER_LIMIT:
  659. pxb = m_pxbQuotaLimit;
  660. break;
  661. case IDC_CMB_USER_THRESHOLD:
  662. pxb = m_pxbQuotaThreshold;
  663. break;
  664. default:
  665. break;
  666. }
  667. if (NULL != pxb)
  668. pxb->OnComboNotifySelChange(lParam);
  669. return FALSE;
  670. }
  671. //
  672. // Retrieve from a DS_SELECTION structure the name to display for
  673. // a user object.
  674. //
  675. LPCWSTR
  676. AddUserDialog::GetDsSelUserName(
  677. const DS_SELECTION& sel
  678. )
  679. {
  680. return sel.pwzUPN && *sel.pwzUPN ? sel.pwzUPN : sel.pwzName;
  681. }
  682. //
  683. // Convert two hex chars into a single byte value.
  684. // Assumes input string is in upper case.
  685. //
  686. HRESULT
  687. AddUserDialog::HexCharsToByte(
  688. LPTSTR pszByteIn,
  689. LPBYTE pbOut
  690. )
  691. {
  692. static const int iShift[] = { 4, 0 };
  693. *pbOut = (BYTE)0;
  694. for (int i = 0; i < 2; i++)
  695. {
  696. TCHAR ch = *(pszByteIn + i);
  697. BYTE b = (BYTE)0;
  698. if (TEXT('0') <= ch && TEXT('9') >= ch)
  699. {
  700. b = ch - TEXT('0');
  701. }
  702. else if (TEXT('A') <= ch && TEXT('F') >= ch)
  703. {
  704. b = 10 + (ch - TEXT('A'));
  705. }
  706. else
  707. {
  708. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  709. }
  710. *pbOut |= (b << iShift[i]);
  711. }
  712. return NOERROR;
  713. }
  714. //
  715. // Returns:
  716. //
  717. // NOERROR
  718. // ERROR_INSUFFICIENT_BUFFER (as hresult)
  719. // ERROR_INVALID_DATA (as hresult)
  720. //
  721. HRESULT
  722. AddUserDialog::GetDsSelUserSid(
  723. const DS_SELECTION& sel,
  724. LPBYTE pbSid,
  725. int cbSid
  726. )
  727. {
  728. static const WCHAR szPrefix[] = L"LDAP://<SID=";
  729. static const WCHAR chTerm = L'>';
  730. HRESULT hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  731. LPWSTR pszLDAP = CharUpper(sel.pwzADsPath);
  732. if (NULL != pszLDAP)
  733. {
  734. int cb = 0;
  735. //
  736. // First check for the required prefix.
  737. //
  738. if (0 == StrCmpNW(pszLDAP, szPrefix, ARRAYSIZE(szPrefix) - 1))
  739. {
  740. hr = NOERROR;
  741. //
  742. // Advance ptr beyond prefix and convert the hex string
  743. // into a SID. Process chars until we hit a '>'.
  744. //
  745. pszLDAP += ARRAYSIZE(szPrefix) - 1;
  746. while(SUCCEEDED(hr) && *pszLDAP && chTerm != *pszLDAP)
  747. {
  748. if (0 < cbSid--)
  749. {
  750. hr = HexCharsToByte(pszLDAP, pbSid++);
  751. pszLDAP += 2;
  752. }
  753. else
  754. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  755. }
  756. if (SUCCEEDED(hr) && chTerm != *pszLDAP)
  757. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  758. }
  759. }
  760. if (FAILED(hr))
  761. {
  762. //
  763. // FEATURE: This can be removed once I'm comfortable that all
  764. // ADs paths returned from the object picker contain
  765. // a SID.
  766. //
  767. DBGERROR((TEXT("GetDsSelUserSid returning hr = 0x%08X for path \"%s\""),
  768. hr, sel.pwzADsPath));
  769. }
  770. return hr;
  771. }
  772. HRESULT
  773. AddUserDialog::ApplySettings(
  774. HWND hDlg,
  775. bool bUndo
  776. )
  777. {
  778. HRESULT hResult = E_FAIL;
  779. int cUsers = m_pSelectionList->cItems;
  780. CAutoWaitCursor wait_cursor;
  781. //
  782. // Retrieve limit and threshold values from dialog controls.
  783. //
  784. if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RBN_USER_NOLIMIT))
  785. {
  786. m_llQuotaThreshold = NOLIMIT;
  787. m_llQuotaLimit = NOLIMIT;
  788. }
  789. else
  790. {
  791. m_llQuotaThreshold = m_pxbQuotaThreshold->GetBytes();
  792. m_llQuotaLimit = m_pxbQuotaLimit->GetBytes();
  793. }
  794. if (bUndo)
  795. m_UndoList.Clear();
  796. ProgressDialog dlgProgress(IDD_PROGRESS,
  797. IDC_PROGRESS_BAR,
  798. IDC_TXT_PROGRESS_DESCRIPTION,
  799. IDC_TXT_PROGRESS_FILENAME);
  800. if (2 < cUsers)
  801. {
  802. //
  803. // Create and display a progress dialog if we're adding more than 2
  804. // users.
  805. //
  806. HWND hwndParent = IsWindowVisible(hDlg) ? hDlg : GetParent(hDlg);
  807. if (dlgProgress.Create(m_hInstance, hwndParent))
  808. {
  809. dlgProgress.ProgressBarInit(0, cUsers, 1);
  810. dlgProgress.SetDescription(MAKEINTRESOURCE(IDS_PROGRESS_ADDUSER));
  811. dlgProgress.Show();
  812. }
  813. }
  814. bool bCancelled = false;
  815. for (int i = 0; i < cUsers && !bCancelled; i++)
  816. {
  817. DS_SELECTION *pdss = &(m_pSelectionList->aDsSelection[i]);
  818. LPCWSTR pwzName = GetDsSelUserName(*pdss);
  819. //
  820. // Add a user to the quota file. This will add it using the defaults
  821. // for new users. We get back an interface to the new user object.
  822. // Also specify async name resolution.
  823. //
  824. if (NULL == pwzName)
  825. {
  826. dlgProgress.ProgressBarAdvance();
  827. continue;
  828. }
  829. dlgProgress.SetFileName(pwzName);
  830. com_autoptr<DISKQUOTA_USER> ptrUser;
  831. DiskQuotaControl *pDQC = static_cast<DiskQuotaControl *>(m_pQuotaControl);
  832. BYTE sid[MAX_SID_LEN];
  833. hResult = GetDsSelUserSid(*pdss, sid, ARRAYSIZE(sid));
  834. if (SUCCEEDED(hResult))
  835. {
  836. hResult = pDQC->AddUserSid(sid,
  837. DISKQUOTA_USERNAME_RESOLVE_ASYNC,
  838. ptrUser.getaddr());
  839. if (SUCCEEDED(hResult))
  840. {
  841. if (S_FALSE == hResult)
  842. {
  843. hResult = HRESULT_FROM_WIN32(ERROR_USER_EXISTS);
  844. }
  845. else
  846. {
  847. if (SUCCEEDED(hResult = ptrUser->SetQuotaLimit(m_llQuotaLimit, TRUE)) &&
  848. SUCCEEDED(hResult = ptrUser->SetQuotaThreshold(m_llQuotaThreshold, TRUE)))
  849. {
  850. if (bUndo)
  851. {
  852. //
  853. // Create local autoptrs to ensure iface release if an
  854. // exception is thrown.
  855. //
  856. com_autoptr<DISKQUOTA_CONTROL> ptrQuotaControl(m_pQuotaControl);
  857. com_autoptr<DISKQUOTA_USER> ptrQuotaUser(ptrUser);
  858. ptrQuotaUser->AddRef();
  859. ptrQuotaControl->AddRef();
  860. autoptr<UndoAdd> ptrUndoAdd = new UndoAdd(ptrUser, m_pQuotaControl);
  861. m_UndoList.Add(ptrUndoAdd);
  862. //
  863. // Undo list now owns the action object.
  864. //
  865. ptrUndoAdd.disown();
  866. //
  867. // Successfully added to undo list. Disown real ptrs so
  868. // ref count stays with undo list. If an exception was
  869. // thrown, the local com_autoptr objects will automatically
  870. // release the interfaces.
  871. //
  872. ptrQuotaUser.disown();
  873. ptrQuotaControl.disown();
  874. }
  875. //
  876. // Add the user to the listview.
  877. //
  878. SendMessage(m_hwndDetailsLV,
  879. WM_ADD_USER_TO_DETAILS_VIEW,
  880. 0,
  881. (LPARAM)ptrUser.get());
  882. //
  883. // iface pointer added to listview. autoptr disowns the real
  884. // pointer so the autoptr's dtor doesn't release it.
  885. //
  886. ptrUser.disown();
  887. }
  888. }
  889. }
  890. }
  891. if (FAILED(hResult))
  892. {
  893. INT idMsg = IDS_UNKNOWN_ERROR;
  894. UINT uFlags = MB_OKCANCEL;
  895. switch(hResult)
  896. {
  897. case E_FAIL:
  898. idMsg = IDS_WRITE_ERROR;
  899. uFlags |= MB_ICONERROR;
  900. break;
  901. default:
  902. switch(HRESULT_CODE(hResult))
  903. {
  904. case ERROR_USER_EXISTS:
  905. idMsg = IDS_NOADD_EXISTING_USER;
  906. uFlags |= MB_ICONWARNING;
  907. break;
  908. case ERROR_NO_SUCH_USER:
  909. idMsg = IDS_NOADD_UNKNOWN_USER;
  910. uFlags |= MB_ICONWARNING;
  911. break;
  912. case ERROR_ACCESS_DENIED:
  913. idMsg = IDS_NO_WRITE_ACCESS;
  914. uFlags |= MB_ICONWARNING;
  915. break;
  916. default:
  917. uFlags |= MB_ICONERROR;
  918. break;
  919. }
  920. break;
  921. }
  922. //
  923. // Display message box with msg formatted as:
  924. //
  925. // The user already exists and could not be added.
  926. //
  927. // User: brianau
  928. // In Folder: Domain/Folder: ntdev.microsoft.com/US SOS-...
  929. //
  930. CString strError(m_hInstance, idMsg);
  931. CString strMsg(m_hInstance, IDS_FMT_ERR_ADDUSER, strError.Cstr(), pwzName);
  932. HWND hwndMsgBoxParent = (NULL != dlgProgress.m_hWnd && IsWindowVisible(dlgProgress.m_hWnd)) ?
  933. dlgProgress.m_hWnd : hDlg;
  934. if (IDCANCEL == DiskQuotaMsgBox(hwndMsgBoxParent,
  935. strMsg.Cstr(),
  936. IDS_TITLE_DISK_QUOTA,
  937. uFlags))
  938. {
  939. bCancelled = true;
  940. }
  941. }
  942. dlgProgress.ProgressBarAdvance();
  943. bCancelled = bCancelled || dlgProgress.UserCancelled();
  944. }
  945. return NOERROR;
  946. }