Source code of Windows XP (NT5)
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.

2136 lines
65 KiB

  1. #include "stdafx.h"
  2. #include "grpinfo.h"
  3. #include "unpage.h"
  4. #include "netpage.h"
  5. #include "password.h"
  6. #include "cryptui.h" // for certificate mgr
  7. #pragma hdrstop
  8. // Certificate Manager helper static functions and delay-load stuff
  9. class CCertificateAPI
  10. {
  11. public:
  12. static BOOL ManagePasswords(HWND hwnd);
  13. static BOOL Wizard(HWND hwnd);
  14. private:
  15. static BOOL m_fFailed;
  16. static HINSTANCE m_hInstCryptUI;
  17. };
  18. BOOL CCertificateAPI::m_fFailed = FALSE;
  19. HINSTANCE CCertificateAPI::m_hInstCryptUI = NULL;
  20. // CCertificateAPI::ManagePasswords - launch certificate manager
  21. typedef BOOL (WINAPI *PFNCRYPTUIDLGCERTMGR)(IN PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr);
  22. BOOL CCertificateAPI::ManagePasswords(HWND hwnd)
  23. {
  24. // Use shellexecuteex to open up the keyring control panel
  25. SHELLEXECUTEINFO shexinfo = {0};
  26. shexinfo.cbSize = sizeof (shexinfo);
  27. shexinfo.fMask = SEE_MASK_DOENVSUBST;
  28. shexinfo.nShow = SW_SHOWNORMAL;
  29. shexinfo.lpFile = L"%windir%\\system32\\rundll32.exe";
  30. shexinfo.lpParameters = L"shell32.dll,Control_RunDLL keymgr.dll";
  31. shexinfo.lpVerb = TEXT("open");
  32. return ShellExecuteEx(&shexinfo);
  33. }
  34. // CCertificateAPI::Wizard - launch the enrollment wizard
  35. typedef BOOL (WINAPI *PFNCRYPTUIWIZCERTREQUEST)(IN DWORD dwFlags,
  36. IN OPTIONAL HWND, IN OPTIONAL LPCWSTR pwszWizardTitle,
  37. IN PCCRYPTUI_WIZ_CERT_REQUEST_INFO pCertRequestInfo,
  38. OUT OPTIONAL PCCERT_CONTEXT *ppCertContext,
  39. OUT OPTIONAL DWORD *pCAdwStatus);
  40. BOOL CCertificateAPI::Wizard(HWND hwnd)
  41. {
  42. static PFNCRYPTUIWIZCERTREQUEST pCryptUIWizCertRequest = NULL;
  43. if ((m_hInstCryptUI == NULL) && (!m_fFailed))
  44. {
  45. m_hInstCryptUI = LoadLibrary(TEXT("cryptui.dll"));
  46. }
  47. if (m_hInstCryptUI != NULL)
  48. {
  49. pCryptUIWizCertRequest = (PFNCRYPTUIWIZCERTREQUEST)
  50. GetProcAddress(m_hInstCryptUI, "CryptUIWizCertRequest");
  51. }
  52. if (pCryptUIWizCertRequest)
  53. {
  54. CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW CertRequestPvkNew = {0};
  55. CertRequestPvkNew.dwSize=sizeof(CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW);
  56. CRYPTUI_WIZ_CERT_REQUEST_INFO CertRequestInfo = {0};
  57. CertRequestInfo.dwSize=sizeof(CRYPTUI_WIZ_CERT_REQUEST_INFO);
  58. CertRequestInfo.dwPurpose=CRYPTUI_WIZ_CERT_ENROLL;
  59. CertRequestInfo.dwPvkChoice=CRYPTUI_WIZ_CERT_REQUEST_PVK_CHOICE_NEW;
  60. CertRequestInfo.pPvkNew=&CertRequestPvkNew;
  61. // This can take a while!
  62. CWaitCursor cur;
  63. pCryptUIWizCertRequest(0, hwnd, NULL, &CertRequestInfo, NULL, NULL);
  64. }
  65. else
  66. {
  67. m_fFailed = TRUE;
  68. }
  69. return (!m_fFailed);
  70. }
  71. // handle auto logon of users
  72. class CAutologonUserDlg: public CDialog
  73. {
  74. public:
  75. CAutologonUserDlg(LPTSTR szInitialUser)
  76. {m_pszUsername = szInitialUser;}
  77. private:
  78. virtual INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  79. BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  80. BOOL OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  81. LPTSTR m_pszUsername;
  82. };
  83. INT_PTR CAutologonUserDlg::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  84. {
  85. switch(uMsg)
  86. {
  87. HANDLE_MSG(hwndDlg, WM_INITDIALOG, OnInitDialog);
  88. HANDLE_MSG(hwndDlg, WM_COMMAND, OnCommand);
  89. }
  90. return FALSE;
  91. }
  92. BOOL CAutologonUserDlg::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  93. {
  94. HWND hwndUsername = GetDlgItem(hwnd, IDC_USER);
  95. HWND hwndPassword = GetDlgItem(hwnd, IDC_PASSWORD);
  96. HWND hwndConfirm = GetDlgItem(hwnd, IDC_CONFIRMPASSWORD);
  97. // limit the text with of the controls
  98. Edit_LimitText(hwndUsername, MAX_USER);
  99. Edit_LimitText(hwndPassword, MAX_PASSWORD);
  100. Edit_LimitText(hwndConfirm, MAX_PASSWORD);
  101. // Populate the username field and set focus to password
  102. SetWindowText(hwndUsername, m_pszUsername);
  103. SetFocus(hwndPassword);
  104. BOOL fSetDefaultFocus = FALSE;
  105. return (fSetDefaultFocus);
  106. }
  107. BOOL CAutologonUserDlg::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  108. {
  109. switch (id)
  110. {
  111. case IDOK:
  112. {
  113. TCHAR szUsername[MAX_USER + 1];
  114. TCHAR szPassword[MAX_PASSWORD + 1];
  115. TCHAR szConfirm[MAX_PASSWORD + 1];
  116. FetchText(hwnd, IDC_USER, szUsername, ARRAYSIZE(szUsername));
  117. GetWindowText(GetDlgItem(hwnd, IDC_PASSWORD), szPassword, ARRAYSIZE(szPassword));
  118. GetWindowText(GetDlgItem(hwnd, IDC_CONFIRMPASSWORD), szConfirm, ARRAYSIZE(szConfirm));
  119. if (StrCmp(szConfirm, szPassword) != 0)
  120. {
  121. // Display a message saying the passwords don't match
  122. DisplayFormatMessage(hwnd, IDS_USR_APPLET_CAPTION, IDS_ERR_PWDNOMATCH, MB_OK | MB_ICONERROR);
  123. break;
  124. }
  125. else
  126. {
  127. // Actually apply the autologon
  128. SetAutoLogon(szUsername, szPassword);
  129. ZeroMemory(szPassword, ARRAYSIZE(szPassword));
  130. }
  131. }
  132. // Fall through
  133. case IDCANCEL:
  134. EndDialog(hwnd, id);
  135. }
  136. return (TRUE);
  137. }
  138. // user list page (the main page the user sees)
  139. class CUserlistPropertyPage: public CPropertyPage
  140. {
  141. public:
  142. CUserlistPropertyPage(CUserManagerData* pdata): m_pData(pdata)
  143. {m_himlLarge = NULL;}
  144. ~CUserlistPropertyPage();
  145. static HRESULT AddUserToListView(HWND hwndList, CUserInfo* pUserInfo, BOOL fSelectUser = FALSE);
  146. private:
  147. virtual INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  148. BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  149. BOOL OnNotify(HWND hwnd, int idCtrl, LPNMHDR pnmh);
  150. BOOL OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  151. BOOL OnGetInfoTip(HWND hwndList, LPNMLVGETINFOTIP pGetInfoTip);
  152. BOOL OnListViewItemChanged(HWND hwnd);
  153. BOOL OnListViewDeleteItem(HWND hwndList, int iItem);
  154. BOOL OnHelp(HWND hwnd, LPHELPINFO pHelpInfo);
  155. BOOL OnContextMenu(HWND hwnd);
  156. BOOL OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg);
  157. long OnApply(HWND hwnd);
  158. HRESULT InitializeListView(HWND hwndList, BOOL fShowDomain);
  159. HRESULT LaunchNewUserWizard(HWND hwndParent);
  160. HRESULT LaunchAddNetUserWizard(HWND hwndParent);
  161. HRESULT LaunchUserProperties(HWND hwndParent);
  162. HRESULT LaunchSetPasswordDialog(HWND hwndParent);
  163. CUserInfo* GetSelectedUserInfo(HWND hwndList);
  164. void OnRemove(HWND hwnd);
  165. int ConfirmRemove(HWND hwnd, CUserInfo* pUserInfo);
  166. void RemoveSelectedUserFromList(HWND hwndList, BOOL fFreeUserInfo);
  167. void SetPageState(HWND hwnd);
  168. HRESULT SetAutologonState(HWND hwnd, BOOL fAutologon);
  169. void SetupList(HWND hwnd);
  170. HPSXA AddExtraUserPropPages(ADDPROPSHEETDATA* ppsd, PSID psid);
  171. static int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2,
  172. LPARAM lParamSort);
  173. CUserManagerData* m_pData;
  174. HIMAGELIST m_himlLarge;
  175. // When a column header is clicked, the list is sorted based on that column
  176. // When this happens, we store the column number here so that if the same
  177. // column is clicked again, we sort it in reverse. A 0 is stored if no
  178. // column should be sorted in reverse when clicked.
  179. int m_iReverseColumnIfSelected;
  180. BOOL m_fAutologonCheckChanged;
  181. };
  182. // Help ID array
  183. static const DWORD rgUserListHelpIds[] =
  184. {
  185. IDC_AUTOLOGON_CHECK, IDH_AUTOLOGON_CHECK,
  186. IDC_LISTTITLE_STATIC, IDH_USER_LIST,
  187. IDC_USER_LIST, IDH_USER_LIST,
  188. IDC_ADDUSER_BUTTON, IDH_ADDUSER_BUTTON,
  189. IDC_REMOVEUSER_BUTTON, IDH_REMOVEUSER_BUTTON,
  190. IDC_USERPROPERTIES_BUTTON, IDH_USERPROPERTIES_BUTTON,
  191. IDC_PASSWORD_STATIC, IDH_PASSWORD_BUTTON,
  192. IDC_CURRENTUSER_ICON, IDH_PASSWORD_BUTTON,
  193. IDC_PASSWORD_BUTTON, IDH_PASSWORD_BUTTON,
  194. IDC_PWGROUP_STATIC, (DWORD) -1,
  195. IDC_ULISTPG_TEXT, (DWORD) -1,
  196. IDC_USERLISTPAGE_ICON, (DWORD) -1,
  197. 0, 0
  198. };
  199. // Control ID arrays for enabling/disabling/moving
  200. static const UINT rgidDisableOnAutologon[] =
  201. {
  202. IDC_USER_LIST,
  203. IDC_ADDUSER_BUTTON,
  204. IDC_REMOVEUSER_BUTTON,
  205. IDC_USERPROPERTIES_BUTTON,
  206. IDC_PASSWORD_BUTTON
  207. };
  208. static const UINT rgidDisableOnNoSelection[] =
  209. {
  210. IDC_REMOVEUSER_BUTTON,
  211. IDC_USERPROPERTIES_BUTTON,
  212. IDC_PASSWORD_BUTTON
  213. };
  214. static const UINT rgidMoveOnNoAutologonCheck[] =
  215. {
  216. IDC_LISTTITLE_STATIC,
  217. IDC_USER_LIST,
  218. // IDC_ADDUSER_BUTTON,
  219. // IDC_e_BUTTON,
  220. // IDC_USERPROPERTIES_BUTTON,
  221. // IDC_PWGROUP_STATIC,
  222. // IDC_CURRENTUSER_ICON,
  223. // IDC_PASSWORD_STATIC,
  224. // IDC_PASSWORD_BUTTON
  225. };
  226. CUserlistPropertyPage::~CUserlistPropertyPage()
  227. {
  228. if (m_himlLarge != NULL)
  229. ImageList_Destroy(m_himlLarge);
  230. }
  231. INT_PTR CUserlistPropertyPage::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  232. {
  233. switch (uMsg)
  234. {
  235. HANDLE_MSG(hwndDlg, WM_INITDIALOG, OnInitDialog);
  236. HANDLE_MSG(hwndDlg, WM_NOTIFY, OnNotify);
  237. HANDLE_MSG(hwndDlg, WM_COMMAND, OnCommand);
  238. HANDLE_MSG(hwndDlg, WM_SETCURSOR, OnSetCursor);
  239. case WM_HELP:
  240. return OnHelp(hwndDlg, (LPHELPINFO) lParam);
  241. case WM_CONTEXTMENU:
  242. return OnContextMenu((HWND) wParam);
  243. case WM_ADDUSERTOLIST:
  244. return SUCCEEDED(AddUserToListView(GetDlgItem(hwndDlg, IDC_USER_LIST), (CUserInfo*)lParam, (BOOL) wParam));
  245. }
  246. return FALSE;
  247. }
  248. BOOL CUserlistPropertyPage::OnHelp(HWND hwnd, LPHELPINFO pHelpInfo)
  249. {
  250. WinHelp((HWND) pHelpInfo->hItemHandle, m_pData->GetHelpfilePath(),
  251. HELP_WM_HELP, (ULONG_PTR) (LPTSTR)rgUserListHelpIds);
  252. return TRUE;
  253. }
  254. BOOL CUserlistPropertyPage::OnContextMenu(HWND hwnd)
  255. {
  256. WinHelp(hwnd, m_pData->GetHelpfilePath(),
  257. HELP_CONTEXTMENU, (ULONG_PTR) (LPTSTR)rgUserListHelpIds);
  258. return TRUE;
  259. }
  260. BOOL CUserlistPropertyPage::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  261. {
  262. HWND hwndList = GetDlgItem(hwnd, IDC_USER_LIST);
  263. InitializeListView(hwndList, m_pData->IsComputerInDomain());
  264. m_pData->Initialize(hwnd);
  265. SetupList(hwnd);
  266. m_fAutologonCheckChanged = FALSE;
  267. return TRUE;
  268. }
  269. BOOL CUserlistPropertyPage::OnListViewDeleteItem(HWND hwndList, int iItem)
  270. {
  271. LVITEM lvi = {0};
  272. lvi.iItem = iItem;
  273. lvi.mask = LVIF_PARAM;
  274. ListView_GetItem(hwndList, &lvi);
  275. CUserInfo* pUserInfo = (CUserInfo*)lvi.lParam;
  276. if (NULL != pUserInfo)
  277. {
  278. delete pUserInfo;
  279. }
  280. return TRUE;
  281. }
  282. BOOL CUserlistPropertyPage::OnNotify(HWND hwnd, int idCtrl, LPNMHDR pnmh)
  283. {
  284. switch (pnmh->code)
  285. {
  286. case PSN_APPLY:
  287. {
  288. long applyEffect = OnApply(hwnd);
  289. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, applyEffect);
  290. break;
  291. }
  292. case LVN_GETINFOTIP:
  293. return OnGetInfoTip(pnmh->hwndFrom, (LPNMLVGETINFOTIP) pnmh);
  294. break;
  295. case LVN_ITEMCHANGED:
  296. return OnListViewItemChanged(hwnd);
  297. break;
  298. case LVN_DELETEITEM:
  299. return OnListViewDeleteItem(GetDlgItem(hwnd, IDC_USER_LIST), ((LPNMLISTVIEW) pnmh)->iItem);
  300. case NM_DBLCLK:
  301. LaunchUserProperties(hwnd);
  302. return TRUE;
  303. case LVN_COLUMNCLICK:
  304. {
  305. int iColumn = ((LPNMLISTVIEW) pnmh)->iSubItem;
  306. // Want to work with 1-based columns so we can use zero as
  307. // a special value
  308. iColumn += 1;
  309. // If we aren't showing the domain column because we're in
  310. // non-domain mode, then map column 2 (group since we're not in
  311. // domain mode to column 3 since the callback always expects
  312. // the columns to be, "username", "domain", "group".
  313. if ((iColumn == 2) && (!m_pData->IsComputerInDomain()))
  314. {
  315. iColumn = 3;
  316. }
  317. if (m_iReverseColumnIfSelected == iColumn)
  318. {
  319. m_iReverseColumnIfSelected = 0;
  320. iColumn = -iColumn;
  321. }
  322. else
  323. {
  324. m_iReverseColumnIfSelected = iColumn;
  325. }
  326. ListView_SortItems(pnmh->hwndFrom, ListCompare, (LPARAM) iColumn);
  327. return TRUE;
  328. }
  329. default:
  330. return FALSE;
  331. }
  332. return TRUE;
  333. }
  334. BOOL CUserlistPropertyPage::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  335. {
  336. switch (id)
  337. {
  338. case IDC_ADDUSER_BUTTON:
  339. if (m_pData->IsComputerInDomain())
  340. {
  341. // Launch the wizard to add a network user to a local group
  342. LaunchAddNetUserWizard(hwnd);
  343. }
  344. else
  345. {
  346. // No domain; create a new local machine user
  347. LaunchNewUserWizard(hwnd);
  348. }
  349. return TRUE;
  350. case IDC_REMOVEUSER_BUTTON:
  351. OnRemove(hwnd);
  352. return TRUE;
  353. case IDC_AUTOLOGON_CHECK:
  354. {
  355. m_fAutologonCheckChanged = TRUE;
  356. BOOL fAutoLogon = (BST_UNCHECKED == SendMessage(GetDlgItem(hwnd, IDC_AUTOLOGON_CHECK), BM_GETCHECK, 0, 0));
  357. SetAutologonState(hwnd, fAutoLogon);
  358. SetPageState(hwnd);
  359. break;
  360. }
  361. case IDC_ADVANCED_BUTTON:
  362. {
  363. // Consider using env. vars and ExpandEnvironmentString here
  364. static const TCHAR szMMCCommandLineFormat[] = TEXT("mmc.exe /computer=%s %%systemroot%%\\system32\\lusrmgr.msc");
  365. TCHAR szMMCCommandLine[MAX_PATH];
  366. TCHAR szExpandedCommandLine[MAX_PATH];
  367. wnsprintf(szMMCCommandLine, ARRAYSIZE(szMMCCommandLine), szMMCCommandLineFormat, m_pData->GetComputerName());
  368. if (ExpandEnvironmentStrings(szMMCCommandLine, szExpandedCommandLine, ARRAYSIZE(szExpandedCommandLine)) > 0)
  369. {
  370. PROCESS_INFORMATION pi;
  371. STARTUPINFO si = {0};
  372. si.cb = sizeof (si);
  373. if (CreateProcess(NULL, szExpandedCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
  374. {
  375. CloseHandle(pi.hProcess);
  376. CloseHandle(pi.hThread);
  377. }
  378. }
  379. break;
  380. }
  381. case IDC_PASSWORD_BUTTON:
  382. LaunchSetPasswordDialog(hwnd);
  383. break;
  384. case IDC_USERPROPERTIES_BUTTON:
  385. LaunchUserProperties(hwnd);
  386. break;
  387. }
  388. return FALSE;
  389. }
  390. BOOL CUserlistPropertyPage::OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg)
  391. {
  392. BOOL fHandled = FALSE;
  393. if (m_pData->GetUserListLoader()->InitInProgress())
  394. {
  395. // If the thread is filling, handle by setting the appstarting cursor
  396. SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
  397. fHandled = TRUE;
  398. }
  399. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, fHandled);
  400. return TRUE;
  401. }
  402. BOOL CUserlistPropertyPage::OnGetInfoTip(HWND hwndList, LPNMLVGETINFOTIP pGetInfoTip)
  403. {
  404. // Get the UserInfo structure for the selected item
  405. LVITEM lvi;
  406. lvi.mask = LVIF_PARAM;
  407. lvi.iItem = pGetInfoTip->iItem;
  408. lvi.iSubItem = 0;
  409. if ((lvi.iItem >= 0) && (ListView_GetItem(hwndList, &lvi)))
  410. {
  411. // Ensure full name and comment are available
  412. CUserInfo* pUserInfo = (CUserInfo*)lvi.lParam;
  413. pUserInfo->GetExtraUserInfo();
  414. // Make a string containing our "Full Name: %s\nComment: %s" message
  415. if ((pUserInfo->m_szFullName[0] != TEXT('\0')) &&
  416. (pUserInfo->m_szComment[0] != TEXT('\0')))
  417. {
  418. // We have a full name and comment
  419. FormatMessageString(IDS_USR_TOOLTIPBOTH_FORMAT, pGetInfoTip->pszText, pGetInfoTip->cchTextMax, pUserInfo->m_szFullName, pUserInfo->m_szComment);
  420. }
  421. else if (pUserInfo->m_szFullName[0] != TEXT('\0'))
  422. {
  423. // We only have full name
  424. FormatMessageString(IDS_USR_TOOLTIPFULLNAME_FORMAT, pGetInfoTip->pszText, pGetInfoTip->cchTextMax, pUserInfo->m_szFullName);
  425. }
  426. else if (pUserInfo->m_szComment[0] != TEXT('\0'))
  427. {
  428. // We only have comment
  429. FormatMessageString(IDS_USR_TOOLTIPCOMMENT_FORMAT, pGetInfoTip->pszText, pGetInfoTip->cchTextMax, pUserInfo->m_szComment);
  430. }
  431. else
  432. {
  433. // We have no extra information - do nothing (show no tip)
  434. }
  435. }
  436. return TRUE;
  437. }
  438. struct MYCOLINFO
  439. {
  440. int percentWidth;
  441. UINT idString;
  442. };
  443. HRESULT CUserlistPropertyPage::InitializeListView(HWND hwndList, BOOL fShowDomain)
  444. {
  445. // Array of icon ids icons 0, 1, and 2 respectively
  446. static const UINT rgIcons[] =
  447. {
  448. IDI_USR_LOCALUSER_ICON,
  449. IDI_USR_DOMAINUSER_ICON,
  450. IDI_USR_GROUP_ICON
  451. };
  452. // Array of relative column widths, for columns 0, 1, and 2 respectively
  453. static const MYCOLINFO rgColWidthsWithDomain[] =
  454. {
  455. {40, IDS_USR_NAME_COLUMN},
  456. {30, IDS_USR_DOMAIN_COLUMN},
  457. {30, IDS_USR_GROUP_COLUMN}
  458. };
  459. static const MYCOLINFO rgColWidthsNoDomain[] =
  460. {
  461. {50, IDS_USR_NAME_COLUMN},
  462. {50, IDS_USR_GROUP_COLUMN}
  463. };
  464. // Create a listview with three columns
  465. RECT rect;
  466. GetClientRect(hwndList, &rect);
  467. // Width of our window minus width of a verticle scroll bar minus one for the
  468. // little bevel at the far right of the header.
  469. int cxListView = (rect.right - rect.left) - GetSystemMetrics(SM_CXVSCROLL) - 1;
  470. // Make our columns
  471. int i;
  472. int nColumns;
  473. const MYCOLINFO* pColInfo;
  474. if (fShowDomain)
  475. {
  476. nColumns = ARRAYSIZE(rgColWidthsWithDomain);
  477. pColInfo = rgColWidthsWithDomain;
  478. }
  479. else
  480. {
  481. nColumns = ARRAYSIZE(rgColWidthsNoDomain);
  482. pColInfo = rgColWidthsNoDomain;
  483. }
  484. LVCOLUMN lvc;
  485. lvc.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
  486. for (i = 0; i < nColumns; i++)
  487. {
  488. TCHAR szText[MAX_PATH];
  489. // Load this column's caption
  490. LoadString(g_hinst, pColInfo[i].idString, szText, ARRAYSIZE(szText));
  491. lvc.iSubItem = i;
  492. lvc.cx = (int) MulDiv(pColInfo[i].percentWidth, cxListView, 100);
  493. lvc.pszText = szText;
  494. ListView_InsertColumn(hwndList, i, &lvc);
  495. }
  496. UINT flags = ILC_MASK;
  497. if(IS_WINDOW_RTL_MIRRORED(hwndList))
  498. {
  499. flags |= ILC_MIRROR;
  500. }
  501. // Create an image list for the listview
  502. HIMAGELIST himlSmall = ImageList_Create(16, 16, flags, 0, ARRAYSIZE(rgIcons));
  503. // Large image lists for the "set password" group icon
  504. m_himlLarge = ImageList_Create(32, 32, flags, 0, ARRAYSIZE(rgIcons));
  505. if (himlSmall && m_himlLarge)
  506. {
  507. // Add our icons to the image list
  508. for(i = 0; i < ARRAYSIZE(rgIcons); i ++)
  509. {
  510. HICON hIconSmall = (HICON) LoadImage(g_hinst, MAKEINTRESOURCE(rgIcons[i]), IMAGE_ICON, 16, 16, 0);
  511. if (hIconSmall)
  512. {
  513. ImageList_AddIcon(himlSmall, hIconSmall);
  514. DestroyIcon(hIconSmall);
  515. }
  516. HICON hIconLarge = (HICON) LoadImage(g_hinst, MAKEINTRESOURCE(rgIcons[i]), IMAGE_ICON, 32, 32, 0);
  517. if (hIconLarge)
  518. {
  519. ImageList_AddIcon(m_himlLarge, hIconLarge);
  520. DestroyIcon(hIconLarge);
  521. }
  522. }
  523. }
  524. ListView_SetImageList(hwndList, himlSmall, LVSIL_SMALL);
  525. // Set extended styles for the listview
  526. ListView_SetExtendedListViewStyleEx(hwndList,
  527. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP,
  528. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
  529. // Set some settings for our tooltips - stolen from defview.cpp code
  530. HWND hwndInfoTip = ListView_GetToolTips(hwndList);
  531. if (hwndInfoTip != NULL)
  532. {
  533. //make the tooltip window to be topmost window
  534. SetWindowPos(hwndInfoTip, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  535. // increase the ShowTime (the delay before we show the tooltip) to 2 times the default value
  536. LRESULT uiShowTime = SendMessage(hwndInfoTip, TTM_GETDELAYTIME, TTDT_INITIAL, 0);
  537. SendMessage(hwndInfoTip, TTM_SETDELAYTIME, TTDT_INITIAL, uiShowTime * 2);
  538. }
  539. return S_OK;
  540. }
  541. HRESULT CUserlistPropertyPage::AddUserToListView(HWND hwndList,
  542. CUserInfo* pUserInfo,
  543. BOOL fSelectUser /* = FALSE */)
  544. {
  545. if (!pUserInfo->m_fAccountDisabled)
  546. {
  547. LVITEM lvi = { 0 };
  548. lvi.iItem = 0;
  549. lvi.iSubItem = 0;
  550. lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  551. lvi.pszText = pUserInfo->m_szUsername;
  552. lvi.iImage = pUserInfo->m_userType;
  553. lvi.lParam = (LPARAM) pUserInfo;
  554. // Always select the first loaded user
  555. if (ListView_GetItemCount(hwndList) == 0)
  556. fSelectUser = TRUE;
  557. if (fSelectUser)
  558. {
  559. lvi.mask |= LVIF_STATE;
  560. lvi.state = lvi.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
  561. }
  562. int iItem = ListView_InsertItem(hwndList, &lvi);
  563. if (iItem >= 0)
  564. {
  565. if (fSelectUser)
  566. ListView_EnsureVisible(hwndList, iItem, FALSE); // Make the item visible
  567. // Success! Now add the subitems (domain, groups)
  568. lvi.iItem = iItem;
  569. lvi.mask = LVIF_TEXT;
  570. // Only add the domain field if the user is in a domain
  571. if (::IsComputerInDomain())
  572. {
  573. lvi.iSubItem = 1;
  574. lvi.pszText = pUserInfo->m_szDomain;
  575. ListView_SetItem(hwndList, &lvi);
  576. // User is in a domain; group should be third column
  577. lvi.iSubItem = 2;
  578. }
  579. else
  580. {
  581. // User isn't in a domain, group should be second column
  582. lvi.iSubItem = 1;
  583. }
  584. // Add group regardless of whether user is in a domain
  585. lvi.pszText = pUserInfo->m_szGroups;
  586. ListView_SetItem(hwndList, &lvi);
  587. }
  588. }
  589. return S_OK;
  590. }
  591. HRESULT CUserlistPropertyPage::LaunchNewUserWizard(HWND hwndParent)
  592. {
  593. static const int nPages = 3;
  594. int cPages = 0;
  595. HPROPSHEETPAGE rghPages[nPages];
  596. // Create a new user record
  597. CUserInfo* pNewUser = new CUserInfo;
  598. if ( !pNewUser )
  599. {
  600. DisplayFormatMessage(hwndParent, IDS_USR_NEWUSERWIZARD_CAPTION, IDS_USR_CREATE_MISC_ERROR, MB_OK | MB_ICONERROR);
  601. return E_OUTOFMEMORY;
  602. }
  603. pNewUser->InitializeForNewUser();
  604. pNewUser->m_userType = CUserInfo::LOCALUSER;
  605. PROPSHEETPAGE psp = {0};
  606. // Common propsheetpage settings
  607. psp.dwSize = sizeof (psp);
  608. psp.hInstance = g_hinst;
  609. psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
  610. // Page 1: Username entry page
  611. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_USERNAME_WIZARD_PAGE);
  612. CUsernameWizardPage page1(pNewUser);
  613. page1.SetPropSheetPageMembers(&psp);
  614. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  615. // Page 2: Password page
  616. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_PASSWORD_WIZARD_PAGE);
  617. CPasswordWizardPage page2(pNewUser);
  618. page2.SetPropSheetPageMembers(&psp);
  619. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  620. // Page 3: Local group addition
  621. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_CHOOSEGROUP_WIZARD_PAGE);
  622. CGroupWizardPage page3(pNewUser, m_pData->GetGroupList());
  623. page3.SetPropSheetPageMembers(&psp);
  624. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  625. PROPSHEETHEADER psh = {0};
  626. psh.dwSize = sizeof (psh);
  627. psh.dwFlags = PSH_NOCONTEXTHELP | PSH_WIZARD | PSH_WIZARD_LITE;
  628. psh.hwndParent = hwndParent;
  629. psh.hInstance = g_hinst;
  630. psh.nPages = nPages;
  631. psh.phpage = rghPages;
  632. if (PropertySheet(&psh) == IDOK)
  633. {
  634. AddUserToListView(GetDlgItem(hwndParent, IDC_USER_LIST), pNewUser, TRUE);
  635. }
  636. else
  637. {
  638. // User clicked cancel
  639. delete pNewUser;
  640. pNewUser = NULL;
  641. }
  642. return S_OK;
  643. }
  644. HRESULT CUserlistPropertyPage::LaunchAddNetUserWizard(HWND hwndParent)
  645. {
  646. HRESULT hr = S_OK;
  647. static const int nPages = 2;
  648. int cPages = 0;
  649. HPROPSHEETPAGE rghPages[nPages];
  650. // Create a new user record
  651. CUserInfo* pNewUser = new CUserInfo;
  652. if ( !pNewUser )
  653. {
  654. DisplayFormatMessage(hwndParent, IDS_USR_NEWUSERWIZARD_CAPTION, IDS_USR_CREATE_MISC_ERROR, MB_OK | MB_ICONERROR);
  655. return E_OUTOFMEMORY;
  656. }
  657. pNewUser->InitializeForNewUser();
  658. pNewUser->m_userType = CUserInfo::DOMAINUSER;
  659. PROPSHEETPAGE psp = {0};
  660. // Common propsheetpage settings
  661. psp.dwSize = sizeof (psp);
  662. psp.hInstance = g_hinst;
  663. psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
  664. // Page 1: Find a network user page
  665. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_FINDNETUSER_WIZARD_PAGE);
  666. CNetworkUserWizardPage page1(pNewUser);
  667. page1.SetPropSheetPageMembers(&psp);
  668. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  669. // Page 2: Local group addition
  670. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_CHOOSEGROUP_WIZARD_PAGE);
  671. CGroupWizardPage page2(pNewUser, m_pData->GetGroupList());
  672. page2.SetPropSheetPageMembers(&psp);
  673. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  674. PROPSHEETHEADER psh = {0};
  675. psh.dwSize = sizeof (psh);
  676. psh.dwFlags = PSH_NOCONTEXTHELP | PSH_WIZARD | PSH_WIZARD_LITE;
  677. psh.hwndParent = hwndParent;
  678. psh.hInstance = g_hinst;
  679. psh.nPages = nPages;
  680. psh.phpage = rghPages;
  681. if (PropertySheet(&psh) == IDOK)
  682. {
  683. AddUserToListView(GetDlgItem(hwndParent, IDC_USER_LIST), pNewUser, TRUE);
  684. m_pData->UserInfoChanged(pNewUser->m_szUsername, pNewUser->m_szDomain);
  685. }
  686. else
  687. {
  688. // No errors, but the user clicked Cancel...
  689. delete pNewUser;
  690. pNewUser = NULL;
  691. }
  692. return S_OK;
  693. }
  694. HRESULT CUserlistPropertyPage::LaunchUserProperties(HWND hwndParent)
  695. {
  696. HRESULT hr = S_OK;
  697. // Create a new user record
  698. HWND hwndList = GetDlgItem(hwndParent, IDC_USER_LIST);
  699. CUserInfo* pUserInfo = GetSelectedUserInfo(hwndList);
  700. if (pUserInfo != NULL)
  701. {
  702. pUserInfo->GetExtraUserInfo();
  703. // page addition information
  704. ADDPROPSHEETDATA apsd;
  705. apsd.nPages = 0;
  706. // Common propsheetpage settings
  707. PROPSHEETPAGE psp = {0};
  708. psp.dwSize = sizeof (psp);
  709. psp.hInstance = g_hinst;
  710. psp.dwFlags = PSP_DEFAULT;
  711. // If we have a local user, show both the username and group page, ow
  712. // just the group page
  713. // Page 1: Username entry page
  714. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_USERNAME_PROP_PAGE);
  715. CUsernamePropertyPage page1(pUserInfo);
  716. page1.SetPropSheetPageMembers(&psp);
  717. // Only actually create the prop page if we have a local user
  718. if (pUserInfo->m_userType == CUserInfo::LOCALUSER)
  719. {
  720. apsd.rgPages[apsd.nPages++] = CreatePropertySheetPage(&psp);
  721. }
  722. // Always add the second page
  723. // Page 2: Local group addition
  724. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_CHOOSEGROUP_PROP_PAGE);
  725. CGroupPropertyPage page2(pUserInfo, m_pData->GetGroupList());
  726. page2.SetPropSheetPageMembers(&psp);
  727. apsd.rgPages[apsd.nPages++] = CreatePropertySheetPage(&psp);
  728. HPSXA hpsxa = AddExtraUserPropPages(&apsd, pUserInfo->m_psid);
  729. PROPSHEETHEADER psh = {0};
  730. psh.dwSize = sizeof (psh);
  731. psh.dwFlags = PSH_DEFAULT | PSH_PROPTITLE;
  732. TCHAR szDomainUser[MAX_USER + MAX_DOMAIN + 2];
  733. MakeDomainUserString(pUserInfo->m_szDomain, pUserInfo->m_szUsername, szDomainUser, ARRAYSIZE(szDomainUser));
  734. psh.pszCaption = szDomainUser;
  735. psh.hwndParent = hwndParent;
  736. psh.hInstance = g_hinst;
  737. psh.nPages = apsd.nPages;
  738. psh.phpage = apsd.rgPages;
  739. int iRetCode = (int)PropertySheet(&psh);
  740. if (hpsxa != NULL)
  741. SHDestroyPropSheetExtArray(hpsxa);
  742. if (iRetCode == IDOK)
  743. {
  744. // PropSheet_Changed(GetParent(hwndParent), hwndParent);
  745. // So that we don't delete this pUserInfo when we remove
  746. // this user from the list:
  747. m_pData->UserInfoChanged(pUserInfo->m_szUsername, (pUserInfo->m_szDomain[0] == 0) ? NULL : pUserInfo->m_szDomain);
  748. RemoveSelectedUserFromList(hwndList, FALSE);
  749. AddUserToListView(hwndList, pUserInfo, TRUE);
  750. }
  751. }
  752. return S_OK;
  753. }
  754. CUserInfo* CUserlistPropertyPage::GetSelectedUserInfo(HWND hwndList)
  755. {
  756. int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  757. if (iItem >= 0)
  758. {
  759. LVITEM lvi = {0};
  760. lvi.mask = LVIF_PARAM;
  761. lvi.iItem = iItem;
  762. if (ListView_GetItem(hwndList, &lvi))
  763. {
  764. return (CUserInfo*)lvi.lParam;
  765. }
  766. }
  767. return NULL;
  768. }
  769. void CUserlistPropertyPage::RemoveSelectedUserFromList(HWND hwndList, BOOL fFreeUserInfo)
  770. {
  771. int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  772. // If we don't want to delete this user info, better set it to NULL
  773. if (!fFreeUserInfo)
  774. {
  775. LVITEM lvi = {0};
  776. lvi.iItem = iItem;
  777. lvi.mask = LVIF_PARAM;
  778. lvi.lParam = (LPARAM) (CUserInfo*) NULL;
  779. ListView_SetItem(hwndList, &lvi);
  780. }
  781. ListView_DeleteItem(hwndList, iItem);
  782. int iSelect = iItem > 0 ? iItem - 1 : 0;
  783. ListView_SetItemState(hwndList, iSelect, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  784. SetFocus(hwndList);
  785. }
  786. void CUserlistPropertyPage::OnRemove(HWND hwnd)
  787. {
  788. HWND hwndList = GetDlgItem(hwnd, IDC_USER_LIST);
  789. CUserInfo* pUserInfo = GetSelectedUserInfo(hwndList);
  790. if (pUserInfo)
  791. {
  792. if (ConfirmRemove(hwnd, pUserInfo) == IDYES)
  793. {
  794. if (SUCCEEDED(pUserInfo->Remove()))
  795. {
  796. RemoveSelectedUserFromList(hwndList, TRUE);
  797. }
  798. else
  799. {
  800. TCHAR szDisplayName[MAX_USER + MAX_DOMAIN + 2];
  801. ::MakeDomainUserString(pUserInfo->m_szDomain, pUserInfo->m_szUsername,
  802. szDisplayName, ARRAYSIZE(szDisplayName));
  803. DisplayFormatMessage(hwnd, IDS_USR_APPLET_CAPTION,
  804. IDS_USR_REMOVE_MISC_ERROR, MB_ICONERROR | MB_OK, szDisplayName);
  805. }
  806. }
  807. }
  808. }
  809. int CUserlistPropertyPage::ConfirmRemove(HWND hwnd, CUserInfo* pUserInfo)
  810. {
  811. TCHAR szDomainUser[MAX_USER + MAX_DOMAIN + 2];
  812. MakeDomainUserString(pUserInfo->m_szDomain, pUserInfo->m_szUsername, szDomainUser, ARRAYSIZE(szDomainUser));
  813. return DisplayFormatMessage(hwnd, IDS_USR_APPLET_CAPTION, IDS_USR_REMOVEUSER_WARNING,
  814. MB_ICONEXCLAMATION | MB_YESNO, szDomainUser);
  815. }
  816. void CUserlistPropertyPage::SetPageState(HWND hwnd)
  817. {
  818. BOOL fAutologon = (BST_UNCHECKED ==
  819. SendMessage(GetDlgItem(hwnd, IDC_AUTOLOGON_CHECK), BM_GETCHECK, 0, 0));
  820. EnableControls(hwnd, rgidDisableOnAutologon, ARRAYSIZE(rgidDisableOnAutologon),
  821. !fAutologon);
  822. HWND hwndList = GetDlgItem(hwnd, IDC_USER_LIST);
  823. CUserInfo* pUserInfo = GetSelectedUserInfo(hwndList);
  824. if (pUserInfo)
  825. {
  826. TCHAR szPWGroup[128];
  827. FormatMessageString(IDS_USR_PWGROUP_FORMAT, szPWGroup, ARRAYSIZE(szPWGroup), pUserInfo->m_szUsername);
  828. SetWindowText(GetDlgItem(hwnd, IDC_PWGROUP_STATIC), szPWGroup);
  829. TCHAR szPWMessage[128];
  830. // If the logged on user is the selected user
  831. CUserInfo* pLoggedOnUser = m_pData->GetLoggedOnUserInfo();
  832. if ((StrCmpI(pUserInfo->m_szUsername, pLoggedOnUser->m_szUsername) == 0) &&
  833. (StrCmpI(pUserInfo->m_szDomain, pLoggedOnUser->m_szDomain) == 0))
  834. {
  835. LoadString(g_hinst, IDS_USR_YOURPWMESSAGE_FORMAT, szPWMessage, ARRAYSIZE(szPWMessage));
  836. EnableWindow(GetDlgItem(hwnd, IDC_PASSWORD_BUTTON), FALSE);
  837. }
  838. // If the user is a local user
  839. else if (pUserInfo->m_userType == CUserInfo::LOCALUSER)
  840. {
  841. // We can set this user's password
  842. FormatMessageString(IDS_USR_PWMESSAGE_FORMAT, szPWMessage, ARRAYSIZE(szPWMessage), pUserInfo->m_szUsername);
  843. }
  844. else
  845. {
  846. // Nothing can be done with this user's password
  847. // the selected user may be a domain user or a group or something
  848. // We can set this user's password
  849. FormatMessageString(IDS_USR_CANTCHANGEPW_FORMAT, szPWMessage, ARRAYSIZE(szPWMessage), pUserInfo->m_szUsername);
  850. EnableWindow(GetDlgItem(hwnd, IDC_PASSWORD_BUTTON), FALSE);
  851. }
  852. SetWindowText(GetDlgItem(hwnd, IDC_PASSWORD_STATIC), szPWMessage);
  853. // Set the icon for the user
  854. HICON hIcon = ImageList_GetIcon(m_himlLarge, pUserInfo->m_userType, ILD_NORMAL);
  855. Static_SetIcon(GetDlgItem(hwnd, IDC_CURRENTUSER_ICON), hIcon);
  856. }
  857. else
  858. {
  859. EnableControls(hwnd, rgidDisableOnNoSelection, ARRAYSIZE(rgidDisableOnNoSelection), FALSE);
  860. }
  861. }
  862. HRESULT CUserlistPropertyPage::SetAutologonState(HWND hwnd, BOOL fAutologon)
  863. {
  864. PropSheet_Changed(GetParent(hwnd), hwnd);
  865. return S_OK;
  866. }
  867. BOOL CUserlistPropertyPage::OnListViewItemChanged(HWND hwnd)
  868. {
  869. SetPageState(hwnd);
  870. return TRUE;
  871. }
  872. long CUserlistPropertyPage::OnApply(HWND hwnd)
  873. {
  874. long applyEffect = PSNRET_NOERROR;
  875. BOOL fAutologonSet = (BST_UNCHECKED == SendMessage(GetDlgItem(hwnd, IDC_AUTOLOGON_CHECK), BM_GETCHECK, 0, 0));
  876. if (!fAutologonSet)
  877. {
  878. ClearAutoLogon(); // Ensure autologon is cleared
  879. }
  880. else if (m_fAutologonCheckChanged)
  881. {
  882. CUserInfo* pSelectedUser = GetSelectedUserInfo(GetDlgItem(hwnd, IDC_USER_LIST));
  883. TCHAR szNullName[] = TEXT("");
  884. CAutologonUserDlg dlg((pSelectedUser != NULL) ? pSelectedUser->m_szUsername : szNullName);
  885. if (dlg.DoModal(g_hinst, MAKEINTRESOURCE(IDD_USR_AUTOLOGON_DLG), hwnd) == IDCANCEL)
  886. {
  887. applyEffect = PSNRET_INVALID_NOCHANGEPAGE;
  888. }
  889. }
  890. m_fAutologonCheckChanged = FALSE;
  891. if (applyEffect == PSNRET_INVALID_NOCHANGEPAGE)
  892. {
  893. m_pData->Initialize(hwnd); // Reload the data and list
  894. SetupList(hwnd);
  895. }
  896. return applyEffect;
  897. }
  898. void CUserlistPropertyPage::SetupList(HWND hwnd)
  899. {
  900. HWND hwndList = GetDlgItem(hwnd, IDC_USER_LIST);
  901. // Disable autologon check box in the domain case where autologon isn't // enabled
  902. HWND hwndCheck = GetDlgItem(hwnd, IDC_AUTOLOGON_CHECK);
  903. if (m_pData->IsComputerInDomain() && !m_pData->IsAutologonEnabled())
  904. {
  905. ShowWindow(hwndCheck, SW_HIDE);
  906. EnableWindow(hwndCheck, FALSE);
  907. // Move most controls up a bit if the autologon is not visible
  908. RECT rcBottom;
  909. GetWindowRect(GetDlgItem(hwnd, IDC_LISTTITLE_STATIC), &rcBottom);
  910. RECT rcTop;
  911. GetWindowRect(hwndCheck, &rcTop);
  912. int dy = rcTop.top - rcBottom.top;
  913. OffsetControls(hwnd, rgidMoveOnNoAutologonCheck,
  914. ARRAYSIZE(rgidMoveOnNoAutologonCheck), 0, dy);
  915. // Grow the list by this amount also
  916. RECT rcList;
  917. GetWindowRect(hwndList, &rcList);
  918. SetWindowPos(hwndList, NULL, 0, 0, rcList.right - rcList.left,
  919. rcList.bottom - rcList.top - dy, SWP_NOZORDER|SWP_NOMOVE);
  920. }
  921. SendMessage(hwndCheck, BM_SETCHECK,
  922. m_pData->IsAutologonEnabled() ? BST_UNCHECKED : BST_CHECKED, 0);
  923. // Set the text in the set password group.
  924. SetPageState(hwnd);
  925. }
  926. HRESULT CUserlistPropertyPage::LaunchSetPasswordDialog(HWND hwndParent)
  927. {
  928. CUserInfo* pUserInfo = GetSelectedUserInfo(GetDlgItem(hwndParent, IDC_USER_LIST));
  929. if ((pUserInfo != NULL) && (pUserInfo->m_userType == CUserInfo::LOCALUSER))
  930. {
  931. CChangePasswordDlg dlg(pUserInfo);
  932. dlg.DoModal(g_hinst, MAKEINTRESOURCE(IDD_USR_SETPASSWORD_DLG), hwndParent);
  933. return S_OK;
  934. }
  935. return E_FAIL;
  936. }
  937. #define MAX_EXTRA_PAGES 10
  938. HPSXA CUserlistPropertyPage::AddExtraUserPropPages(ADDPROPSHEETDATA* ppsd, PSID psid)
  939. {
  940. HPSXA hpsxa = NULL;
  941. IDataObject *pdo;
  942. HRESULT hr = CUserSidDataObject_CreateInstance(psid, &pdo);
  943. if (SUCCEEDED(hr))
  944. {
  945. hpsxa = SHCreatePropSheetExtArrayEx(HKEY_LOCAL_MACHINE, REGSTR_USERPROPERTIES_SHEET, MAX_EXTRA_PAGES, pdo);
  946. if (hpsxa)
  947. {
  948. SHAddFromPropSheetExtArray(hpsxa, AddPropSheetPageCallback, (LPARAM) ppsd);
  949. }
  950. pdo->Release();
  951. }
  952. return hpsxa;
  953. }
  954. // ListCompare
  955. // Compares list items in for sorting the listview by column
  956. // lParamSort gets the 1-based column index. If lParamSort is negative
  957. // it indicates that the given column should be sorted in reverse.
  958. int CUserlistPropertyPage::ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  959. {
  960. CUserInfo* pUserInfo1 = (CUserInfo*)lParam1;
  961. CUserInfo* pUserInfo2 = (CUserInfo*)lParam2;
  962. int iColumn = (int)lParamSort;
  963. BOOL fReverse = FALSE;
  964. if (iColumn < 0)
  965. {
  966. fReverse = TRUE;
  967. iColumn = -iColumn;
  968. }
  969. int iResult = 0; // they match...
  970. switch (iColumn)
  971. {
  972. case 1:
  973. iResult = lstrcmpi(pUserInfo1->m_szUsername, pUserInfo2->m_szUsername);
  974. break;
  975. case 2:
  976. iResult = lstrcmpi(pUserInfo1->m_szDomain, pUserInfo2->m_szDomain);
  977. break;
  978. case 3:
  979. iResult = lstrcmpi(pUserInfo1->m_szGroups, pUserInfo2->m_szGroups);
  980. break;
  981. }
  982. if (fReverse)
  983. iResult = -iResult;
  984. return iResult;
  985. }
  986. // The DoModal call for this dialog will return IDOK if the applet should be
  987. // shown or IDCANCEL if the users.cpl should exit without displaying the applet.
  988. class CSecurityCheckDlg: public CDialog
  989. {
  990. public:
  991. CSecurityCheckDlg(LPCTSTR pszDomainUser):
  992. m_pszDomainUser(pszDomainUser)
  993. {}
  994. private:
  995. virtual INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  996. BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  997. BOOL OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  998. BOOL OnNotify(HWND hwnd, int id, NMHDR* pnmhdr);
  999. HRESULT RelaunchAsUser(HWND hwnd);
  1000. LPCTSTR m_pszDomainUser;
  1001. };
  1002. // implementation
  1003. INT_PTR CSecurityCheckDlg::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1004. {
  1005. switch(uMsg)
  1006. {
  1007. HANDLE_MSG(hwndDlg, WM_INITDIALOG, OnInitDialog);
  1008. HANDLE_MSG(hwndDlg, WM_COMMAND, OnCommand);
  1009. HANDLE_MSG(hwndDlg, WM_NOTIFY, OnNotify);
  1010. }
  1011. return FALSE;
  1012. }
  1013. BOOL CSecurityCheckDlg::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  1014. {
  1015. // First we must check if the current user is a local administrator; if this is
  1016. // the case, our dialog doesn't even display
  1017. BOOL fIsLocalAdmin;
  1018. if (SUCCEEDED(IsUserLocalAdmin(NULL, &fIsLocalAdmin)))
  1019. {
  1020. if (fIsLocalAdmin)
  1021. {
  1022. EndDialog(hwnd, IDOK); // We want to continue and launch the applet (don't display the security check dlg)
  1023. }
  1024. }
  1025. else
  1026. {
  1027. EndDialog(hwnd, IDCANCEL);
  1028. }
  1029. // Set the "can't launch User Options" message
  1030. TCHAR szUsername[MAX_USER + 1];
  1031. DWORD cchUsername = ARRAYSIZE(szUsername);
  1032. TCHAR szDomain[MAX_DOMAIN + 1];
  1033. DWORD cchDomain = ARRAYSIZE(szDomain);
  1034. if (GetCurrentUserAndDomainName(szUsername, &cchUsername, szDomain, &cchDomain))
  1035. {
  1036. TCHAR szDomainAndUsername[MAX_DOMAIN + MAX_USER + 2];
  1037. MakeDomainUserString(szDomain, szUsername, szDomainAndUsername, ARRAYSIZE(szDomainAndUsername));
  1038. TCHAR szMessage[256];
  1039. if (FormatMessageString(IDS_USR_CANTRUNCPL_FORMAT, szMessage, ARRAYSIZE(szMessage), szDomainAndUsername))
  1040. {
  1041. SetWindowText(GetDlgItem(hwnd, IDC_CANTRUNCPL_STATIC), szMessage);
  1042. }
  1043. TCHAR szAdministrator[MAX_USER + 1];
  1044. LoadString(g_hinst, IDS_ADMINISTRATOR, szAdministrator, ARRAYSIZE(szAdministrator));
  1045. SetWindowText(GetDlgItem(hwnd, IDC_USER), szAdministrator);
  1046. TCHAR szMachine[MAX_COMPUTERNAME + 1];
  1047. DWORD dwSize = ARRAYSIZE(szMachine);
  1048. ::GetComputerName(szMachine, &dwSize);
  1049. SetWindowText(GetDlgItem(hwnd, IDC_DOMAIN), szMachine);
  1050. }
  1051. // Limit the text in the edit fields
  1052. HWND hwndUsername = GetDlgItem(hwnd, IDC_USER);
  1053. Edit_LimitText(hwndUsername, MAX_USER);
  1054. HWND hwndDomain = GetDlgItem(hwnd, IDC_DOMAIN);
  1055. Edit_LimitText(hwndDomain, MAX_DOMAIN);
  1056. HWND hwndPassword = GetDlgItem(hwnd, IDC_PASSWORD);
  1057. Edit_LimitText(hwndPassword, MAX_PASSWORD);
  1058. if (!IsComputerInDomain())
  1059. {
  1060. // Don't need domain box
  1061. EnableWindow(hwndDomain, FALSE);
  1062. ShowWindow(hwndDomain, SW_HIDE);
  1063. ShowWindow(GetDlgItem(hwnd, IDC_DOMAIN_STATIC), SW_HIDE);
  1064. // Move up the OK/Cancel buttons and text and shrink the dialog
  1065. RECT rcDomain;
  1066. GetWindowRect(hwndDomain, &rcDomain);
  1067. RECT rcPassword;
  1068. GetWindowRect(hwndPassword, &rcPassword);
  1069. int dy = (rcPassword.top - rcDomain.top);
  1070. // dy is negative
  1071. OffsetWindow(GetDlgItem(hwnd, IDOK), 0, dy);
  1072. OffsetWindow(GetDlgItem(hwnd, IDCANCEL), 0, dy);
  1073. OffsetWindow(GetDlgItem(hwnd, IDC_PASSWORD_STATIC), 0, dy);
  1074. OffsetWindow(GetDlgItem(hwnd, IDC_OTHEROPTIONS_LINK), 0, dy);
  1075. RECT rcDialog;
  1076. GetWindowRect(hwnd, &rcDialog);
  1077. rcDialog.bottom += dy;
  1078. MoveWindow(hwnd, rcDialog.left, rcDialog.top, rcDialog.right-rcDialog.left,
  1079. rcDialog.bottom-rcDialog.top, FALSE);
  1080. }
  1081. return TRUE;
  1082. }
  1083. BOOL CSecurityCheckDlg::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1084. {
  1085. switch (id)
  1086. {
  1087. case IDOK:
  1088. if (SUCCEEDED(RelaunchAsUser(hwnd)))
  1089. {
  1090. EndDialog(hwnd, IDCANCEL);
  1091. }
  1092. return TRUE;
  1093. case IDCANCEL:
  1094. EndDialog(hwnd, IDCANCEL);
  1095. return TRUE;
  1096. }
  1097. return FALSE;
  1098. }
  1099. BOOL CSecurityCheckDlg::OnNotify(HWND hwnd, int id, NMHDR *pnmhdr)
  1100. {
  1101. BOOL fHandled = FALSE;
  1102. switch (pnmhdr->code)
  1103. {
  1104. // Handle link window clicks
  1105. case NM_CLICK:
  1106. case NM_RETURN:
  1107. {
  1108. if (IDC_OTHEROPTIONS_LINK == id)
  1109. {
  1110. // First link in the control is "manage passwords", second is "passport wizard"
  1111. NMLINKWND* pnm = (NMLINKWND*) pnmhdr;
  1112. if (0 == pnm->item.iLink)
  1113. {
  1114. // Launch "manage passwords"
  1115. CCertificateAPI::ManagePasswords(hwnd);
  1116. }
  1117. else if (1 == pnm->item.iLink)
  1118. {
  1119. // Launch passport wizard
  1120. IPassportWizard *pPW;
  1121. if (SUCCEEDED(CoCreateInstance(CLSID_PassportWizard, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPassportWizard, &pPW))))
  1122. {
  1123. pPW->SetOptions(PPW_LAUNCHEDBYUSER);
  1124. pPW->Show(hwnd);
  1125. pPW->Release();
  1126. }
  1127. }
  1128. fHandled = TRUE;
  1129. }
  1130. }
  1131. break;
  1132. };
  1133. return fHandled;
  1134. }
  1135. HRESULT CSecurityCheckDlg::RelaunchAsUser(HWND hwnd)
  1136. {
  1137. USES_CONVERSION;
  1138. HRESULT hr = E_FAIL;
  1139. TCHAR szUsername[MAX_USER + 1];
  1140. FetchText(hwnd, IDC_USER, szUsername, ARRAYSIZE(szUsername));
  1141. TCHAR szDomain[MAX_DOMAIN + 1];
  1142. FetchText(hwnd, IDC_DOMAIN, szDomain, ARRAYSIZE(szDomain));
  1143. // If the user didn't type a domain
  1144. if (szDomain[0] == TEXT('\0'))
  1145. {
  1146. // Use this machine as the domain
  1147. DWORD cchComputername = ARRAYSIZE(szDomain);
  1148. ::GetComputerName(szDomain, &cchComputername);
  1149. }
  1150. TCHAR szPassword[MAX_PASSWORD + 1];
  1151. GetWindowText(GetDlgItem(hwnd, IDC_PASSWORD), szPassword, ARRAYSIZE(szPassword));
  1152. // Now relaunch ourselves with this information
  1153. STARTUPINFO startupinfo = {0};
  1154. startupinfo.cb = sizeof (startupinfo);
  1155. WCHAR c_szCommandLineFormat[] = L"rundll32.exe netplwiz.dll,UsersRunDll %s";
  1156. // Put the "real" user name in the command-line so that we know what user is
  1157. // actually logged on to the machine even though we are re-launching in a different
  1158. // user context
  1159. WCHAR szCommandLine[ARRAYSIZE(c_szCommandLineFormat) + MAX_DOMAIN + MAX_USER + 2];
  1160. wnsprintf(szCommandLine, ARRAYSIZE(szCommandLine), c_szCommandLineFormat, m_pszDomainUser);
  1161. PROCESS_INFORMATION process_information;
  1162. if (CreateProcessWithLogonW(szUsername, szDomain, szPassword, LOGON_WITH_PROFILE, NULL,
  1163. szCommandLine, 0, NULL, NULL, &startupinfo, &process_information))
  1164. {
  1165. CloseHandle(process_information.hProcess);
  1166. CloseHandle(process_information.hThread);
  1167. hr = S_OK;
  1168. }
  1169. else
  1170. {
  1171. DisplayFormatMessage(hwnd, IDS_USR_APPLET_CAPTION, IDS_USR_CANTOPENCPLASUSER_ERROR, MB_OK|MB_ICONERROR);
  1172. }
  1173. return hr;
  1174. }
  1175. // Advanced Property Page
  1176. class CAdvancedPropertyPage: public CPropertyPage
  1177. {
  1178. public:
  1179. CAdvancedPropertyPage(CUserManagerData* pdata):
  1180. m_pData(pdata),
  1181. m_fRebootRequired(FALSE) {}
  1182. private:
  1183. virtual INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1184. BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  1185. BOOL OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  1186. BOOL OnNotify(HWND hwnd, int idCtrl, LPNMHDR pnmh);
  1187. BOOL OnHelp(HWND hwnd, LPHELPINFO pHelpInfo);
  1188. BOOL OnContextMenu(HWND hwnd);
  1189. void ReadRequireCad(BOOL* pfRequireCad, BOOL* pfSetInPolicy);
  1190. void WriteRequireCad(BOOL fRequireCad);
  1191. CUserManagerData* m_pData;
  1192. BOOL m_fRebootRequired;
  1193. };
  1194. // Relevant regkeys/regvals
  1195. #define REGKEY_WINLOGON \
  1196. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
  1197. #define REGKEY_WINLOGON_POLICY \
  1198. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System")
  1199. #define REGVAL_DISABLE_CAD TEXT("DisableCAD")
  1200. void CAdvancedPropertyPage::ReadRequireCad(BOOL* pfRequireCad, BOOL* pfSetInPolicy)
  1201. {
  1202. HKEY hkey;
  1203. DWORD dwSize;
  1204. DWORD dwType;
  1205. BOOL fDisableCad;
  1206. NT_PRODUCT_TYPE nttype;
  1207. *pfRequireCad = TRUE;
  1208. *pfSetInPolicy = FALSE;
  1209. if (!RtlGetNtProductType(&nttype))
  1210. {
  1211. nttype = NtProductWinNt;
  1212. }
  1213. // By default, don't require CAD for workstations not
  1214. // on a domain only
  1215. if ((NtProductWinNt == nttype) && !IsComputerInDomain())
  1216. {
  1217. *pfRequireCad = FALSE;
  1218. }
  1219. // Read the setting from the machine preferences
  1220. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WINLOGON, 0,
  1221. KEY_READ, &hkey) == ERROR_SUCCESS)
  1222. {
  1223. dwSize = sizeof(fDisableCad);
  1224. if (ERROR_SUCCESS == RegQueryValueEx (hkey, REGVAL_DISABLE_CAD, NULL, &dwType,
  1225. (LPBYTE) &fDisableCad, &dwSize))
  1226. {
  1227. *pfRequireCad = !fDisableCad;
  1228. }
  1229. RegCloseKey (hkey);
  1230. }
  1231. // Check if C-A-D is disabled via policy
  1232. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WINLOGON_POLICY, 0, KEY_READ,
  1233. &hkey) == ERROR_SUCCESS)
  1234. {
  1235. dwSize = sizeof(fDisableCad);
  1236. if (ERROR_SUCCESS == RegQueryValueEx (hkey, REGVAL_DISABLE_CAD, NULL, &dwType,
  1237. (LPBYTE) &fDisableCad, &dwSize))
  1238. {
  1239. *pfRequireCad = !fDisableCad;
  1240. *pfSetInPolicy = TRUE;
  1241. }
  1242. RegCloseKey (hkey);
  1243. }
  1244. }
  1245. void CAdvancedPropertyPage::WriteRequireCad(BOOL fRequireCad)
  1246. {
  1247. HKEY hkey;
  1248. DWORD dwDisp;
  1249. BOOL fDisableCad = !fRequireCad;
  1250. if (ERROR_SUCCESS == RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WINLOGON, 0,
  1251. NULL, 0, KEY_WRITE, NULL, &hkey, &dwDisp))
  1252. {
  1253. RegSetValueEx(hkey, REGVAL_DISABLE_CAD, 0, REG_DWORD,
  1254. (LPBYTE) &fDisableCad, sizeof(fDisableCad));
  1255. RegCloseKey (hkey);
  1256. }
  1257. }
  1258. static const DWORD rgAdvHelpIds[] =
  1259. {
  1260. IDC_ADVANCED_BUTTON, IDH_ADVANCED_BUTTON,
  1261. IDC_BOOT_ICON, IDH_SECUREBOOT_CHECK,
  1262. IDC_BOOT_TEXT, IDH_SECUREBOOT_CHECK,
  1263. IDC_REQUIRECAD, IDH_SECUREBOOT_CHECK,
  1264. IDC_MANAGEPWD_BUTTON, IDH_MANAGEPWD_BUTTON,
  1265. IDC_PASSPORTWIZARD, IDH_PASSPORTWIZARD,
  1266. IDC_CERT_ICON, (DWORD) -1,
  1267. IDC_CERT_TEXT, (DWORD) -1,
  1268. 0, 0
  1269. };
  1270. INT_PTR CAdvancedPropertyPage::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1271. {
  1272. switch (uMsg)
  1273. {
  1274. HANDLE_MSG(hwndDlg, WM_INITDIALOG, OnInitDialog);
  1275. HANDLE_MSG(hwndDlg, WM_COMMAND, OnCommand);
  1276. HANDLE_MSG(hwndDlg, WM_NOTIFY, OnNotify);
  1277. case WM_HELP: return OnHelp(hwndDlg, (LPHELPINFO) lParam);
  1278. case WM_CONTEXTMENU: return OnContextMenu((HWND) wParam);
  1279. }
  1280. return FALSE;
  1281. }
  1282. BOOL CAdvancedPropertyPage::OnNotify(HWND hwnd, int idCtrl, LPNMHDR pnmh)
  1283. {
  1284. BOOL fReturn = FALSE;
  1285. switch (pnmh->code)
  1286. {
  1287. case PSN_APPLY:
  1288. {
  1289. HWND hwndCheck = GetDlgItem(hwnd, IDC_REQUIRECAD);
  1290. BOOL fRequireCad = (BST_CHECKED == Button_GetCheck(hwndCheck));
  1291. // See if a change is really necessary
  1292. BOOL fOldRequireCad;
  1293. BOOL fDummy;
  1294. ReadRequireCad(&fOldRequireCad, &fDummy);
  1295. if (fRequireCad != fOldRequireCad)
  1296. {
  1297. WriteRequireCad(fRequireCad);
  1298. // m_fRebootRequired = TRUE;
  1299. // Uncomment the line above if it ever becomes necessary to reboot the machine - it isn't now.
  1300. }
  1301. // xxx->lParam == 0 means Ok as opposed to Apply
  1302. if ((((PSHNOTIFY*) pnmh)->lParam) && m_fRebootRequired)
  1303. {
  1304. PropSheet_RebootSystem(GetParent(hwnd));
  1305. }
  1306. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
  1307. fReturn = TRUE;
  1308. }
  1309. break;
  1310. }
  1311. return fReturn;
  1312. }
  1313. BOOL CAdvancedPropertyPage::OnHelp(HWND hwnd, LPHELPINFO pHelpInfo)
  1314. {
  1315. WinHelp((HWND) pHelpInfo->hItemHandle, m_pData->GetHelpfilePath(),
  1316. HELP_WM_HELP, (ULONG_PTR) (LPTSTR)rgAdvHelpIds);
  1317. return TRUE;
  1318. }
  1319. BOOL CAdvancedPropertyPage::OnContextMenu(HWND hwnd)
  1320. {
  1321. WinHelp(hwnd, m_pData->GetHelpfilePath(), HELP_CONTEXTMENU, (ULONG_PTR) (LPTSTR)rgAdvHelpIds);
  1322. return TRUE;
  1323. }
  1324. BOOL CAdvancedPropertyPage::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  1325. {
  1326. // Do the required mucking for the Require C-A-D checkbox...
  1327. // Read the setting for the require CAD checkbox
  1328. BOOL fRequireCad;
  1329. BOOL fSetInPolicy;
  1330. ReadRequireCad(&fRequireCad, &fSetInPolicy);
  1331. HWND hwndCheck = GetDlgItem(hwnd, IDC_REQUIRECAD);
  1332. // Disable the check if set in policy
  1333. EnableWindow(hwndCheck, !fSetInPolicy);
  1334. // Set the check accordingly
  1335. Button_SetCheck(hwndCheck,
  1336. fRequireCad ? BST_CHECKED : BST_UNCHECKED);
  1337. return TRUE;
  1338. }
  1339. BOOL CAdvancedPropertyPage::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1340. {
  1341. switch (id)
  1342. {
  1343. case IDC_MANAGEPWD_BUTTON:
  1344. {
  1345. CCertificateAPI::ManagePasswords(hwnd);
  1346. }
  1347. break;
  1348. case IDC_PASSPORTWIZARD:
  1349. {
  1350. IPassportWizard *pPW;
  1351. if (SUCCEEDED(CoCreateInstance(CLSID_PassportWizard, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPassportWizard, &pPW))))
  1352. {
  1353. pPW->SetOptions(PPW_LAUNCHEDBYUSER);
  1354. pPW->Show(hwnd);
  1355. pPW->Release();
  1356. }
  1357. }
  1358. break;
  1359. case IDC_ADVANCED_BUTTON:
  1360. {
  1361. // Launch the MMC local user manager
  1362. STARTUPINFO startupinfo = {0};
  1363. startupinfo.cb = sizeof (startupinfo);
  1364. PROCESS_INFORMATION process_information;
  1365. static const TCHAR szMMCCommandLine[] =
  1366. TEXT("mmc.exe %systemroot%\\system32\\lusrmgr.msc computername=localmachine");
  1367. TCHAR szExpandedCommandLine[MAX_PATH];
  1368. if (ExpandEnvironmentStrings(szMMCCommandLine, szExpandedCommandLine,
  1369. ARRAYSIZE(szExpandedCommandLine)) > 0)
  1370. {
  1371. if (CreateProcess(NULL, szExpandedCommandLine, NULL, NULL, FALSE, 0, NULL, NULL,
  1372. &startupinfo, &process_information))
  1373. {
  1374. CloseHandle(process_information.hProcess);
  1375. CloseHandle(process_information.hThread);
  1376. }
  1377. }
  1378. }
  1379. break;
  1380. case IDC_REQUIRECAD:
  1381. PropSheet_Changed(GetParent(hwnd), hwnd);
  1382. break;
  1383. }
  1384. return FALSE;
  1385. }
  1386. // users control panel entry point
  1387. void APIENTRY UsersRunDll(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
  1388. {
  1389. HRESULT hr = S_OK;
  1390. TCHAR szDomainUser[MAX_USER + MAX_DOMAIN + 2];
  1391. *szDomainUser = 0;
  1392. // Get the "real" user of this machine - this may be passed in the cmdline
  1393. if (0 == *pszCmdLine)
  1394. {
  1395. // user wasn't passed, assume its the currently logged on user
  1396. TCHAR szUser[MAX_USER + 1];
  1397. DWORD cchUser = ARRAYSIZE(szUser);
  1398. TCHAR szDomain[MAX_DOMAIN + 1];
  1399. DWORD cchDomain = ARRAYSIZE(szDomain);
  1400. if (0 != GetCurrentUserAndDomainName(szUser, &cchUser, szDomain, &cchDomain))
  1401. {
  1402. MakeDomainUserString(szDomain, szUser, szDomainUser, ARRAYSIZE(szDomainUser));
  1403. }
  1404. }
  1405. else
  1406. {
  1407. // User name was passed in, just copy it
  1408. MultiByteToWideChar(GetACP(), 0, pszCmdLine, -1, szDomainUser, ARRAYSIZE(szDomainUser));
  1409. }
  1410. // Initialize COM, but continue even if this fails.
  1411. BOOL fComInited = SUCCEEDED(CoInitialize(NULL));
  1412. // See if we're already running
  1413. TCHAR szCaption[256];
  1414. LoadString(g_hinst, IDS_USR_APPLET_CAPTION, szCaption, ARRAYSIZE(szCaption));
  1415. CEnsureSingleInstance ESI(szCaption);
  1416. if (!ESI.ShouldExit())
  1417. {
  1418. LinkWindow_RegisterClass();
  1419. // Create the security check dialog to ensure the logged-on user
  1420. // is a local admin
  1421. CSecurityCheckDlg dlg(szDomainUser);
  1422. if (dlg.DoModal(g_hinst, MAKEINTRESOURCE(IDD_USR_SECURITYCHECK_DLG), NULL) == IDOK)
  1423. {
  1424. // Create the shared user mgr object
  1425. CUserManagerData data(szDomainUser);
  1426. // Create the property sheet and page template
  1427. // Maximum number of pages
  1428. ADDPROPSHEETDATA ppd;
  1429. ppd.nPages = 0;
  1430. // Settings common to all pages
  1431. PROPSHEETPAGE psp = {0};
  1432. psp.dwSize = sizeof (psp);
  1433. psp.hInstance = g_hinst;
  1434. // Create the userlist property sheet page and its managing object
  1435. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_USERLIST_PAGE);
  1436. CUserlistPropertyPage userListPage(&data);
  1437. userListPage.SetPropSheetPageMembers(&psp);
  1438. ppd.rgPages[ppd.nPages++] = CreatePropertySheetPage(&psp);
  1439. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_ADVANCED_PAGE);
  1440. CAdvancedPropertyPage advancedPage(&data);
  1441. advancedPage.SetPropSheetPageMembers(&psp);
  1442. ppd.rgPages[ppd.nPages++] = CreatePropertySheetPage(&psp);
  1443. HPSXA hpsxa = SHCreatePropSheetExtArrayEx(HKEY_LOCAL_MACHINE, REGSTR_USERSANDPASSWORDS_CPL, 10, NULL);
  1444. if (hpsxa != NULL)
  1445. SHAddFromPropSheetExtArray(hpsxa, AddPropSheetPageCallback, (LPARAM)&ppd);
  1446. // Create the prop sheet
  1447. PROPSHEETHEADER psh = {0};
  1448. psh.dwSize = sizeof (psh);
  1449. psh.dwFlags = PSH_DEFAULT;
  1450. psh.hwndParent = hwndStub;
  1451. psh.hInstance = g_hinst;
  1452. psh.pszCaption = szCaption;
  1453. psh.nPages = ppd.nPages;
  1454. psh.phpage = ppd.rgPages;
  1455. // Show the property sheet
  1456. int iRetCode = PropertySheetIcon(&psh, MAKEINTRESOURCE(IDI_USR_USERS));
  1457. if (hpsxa != NULL)
  1458. {
  1459. SHDestroyPropSheetExtArray(hpsxa);
  1460. }
  1461. if (iRetCode == -1)
  1462. {
  1463. hr = E_FAIL;
  1464. }
  1465. else
  1466. {
  1467. hr = S_OK;
  1468. // Special case when we must restart or reboot
  1469. if (iRetCode == ID_PSREBOOTSYSTEM)
  1470. {
  1471. RestartDialogEx(NULL, NULL, EWX_REBOOT, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG);
  1472. }
  1473. else if (iRetCode == ID_PSRESTARTWINDOWS)
  1474. {
  1475. RestartDialogEx(NULL, NULL, EWX_REBOOT, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG);
  1476. }
  1477. else if (data.LogoffRequired())
  1478. {
  1479. int iLogoff = DisplayFormatMessage(NULL, IDS_USERSANDPASSWORDS, IDS_LOGOFFREQUIRED, MB_YESNO | MB_ICONQUESTION);
  1480. if (iLogoff == IDYES)
  1481. {
  1482. // Tell explorer to log off the "real" logged on user. We need to do this
  1483. // since they may be running U&P as a different user.
  1484. HWND hwnd = FindWindow(TEXT("Shell_TrayWnd"), TEXT(""));
  1485. if ( hwnd )
  1486. {
  1487. UINT uMsg = RegisterWindowMessage(TEXT("Logoff User"));
  1488. PostMessage(hwnd, uMsg, 0,0);
  1489. }
  1490. }
  1491. }
  1492. }
  1493. }
  1494. else
  1495. {
  1496. // Security check told us to exit; either another instance of the CPL is starting
  1497. // with admin priviledges or the user cancelled on the sec. check. dlg.
  1498. hr = E_FAIL;
  1499. }
  1500. }
  1501. if (fComInited)
  1502. CoUninitialize();
  1503. }
  1504. // user property property page object
  1505. class CUserPropertyPages: public IShellExtInit, IShellPropSheetExt
  1506. {
  1507. public:
  1508. CUserPropertyPages();
  1509. ~CUserPropertyPages();
  1510. // IUnknown
  1511. STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv);
  1512. STDMETHODIMP_(ULONG) AddRef();
  1513. STDMETHODIMP_(ULONG) Release();
  1514. // IShellExtInit
  1515. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdo, HKEY hkeyProgID);
  1516. // IShellPropSheetExt
  1517. STDMETHODIMP AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam);
  1518. STDMETHODIMP ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
  1519. { return E_NOTIMPL; }
  1520. private:
  1521. LONG _cRef;
  1522. CUserInfo *_pUserInfo; // The user for the property sheet
  1523. CUsernamePropertyPage *_pUserNamePage; // Basic info page, only shown for local users
  1524. CGroupPropertyPage *_pGroupPage; // The group page, which is common to both local and domain users
  1525. CGroupInfoList _GroupList; // The group list, used by the group page
  1526. };
  1527. CUserPropertyPages::CUserPropertyPages() :
  1528. _cRef(1)
  1529. {
  1530. DllAddRef();
  1531. }
  1532. CUserPropertyPages::~CUserPropertyPages()
  1533. {
  1534. if (_pUserInfo)
  1535. delete _pUserInfo;
  1536. if (_pUserNamePage)
  1537. delete _pUserNamePage;
  1538. if (_pGroupPage)
  1539. delete _pGroupPage;
  1540. DllRelease();
  1541. }
  1542. ULONG CUserPropertyPages::AddRef()
  1543. {
  1544. return InterlockedIncrement(&_cRef);
  1545. }
  1546. ULONG CUserPropertyPages::Release()
  1547. {
  1548. if (InterlockedDecrement(&_cRef))
  1549. return _cRef;
  1550. delete this;
  1551. return 0;
  1552. }
  1553. HRESULT CUserPropertyPages::QueryInterface(REFIID riid, LPVOID* ppv)
  1554. {
  1555. static const QITAB qit[] =
  1556. {
  1557. QITABENT(CUserPropertyPages, IShellExtInit), // IID_IShellExtInit
  1558. QITABENT(CUserPropertyPages, IShellPropSheetExt), // IID_IShellPropSheetExt
  1559. {0, 0 },
  1560. };
  1561. return QISearch(this, qit, riid, ppv);
  1562. }
  1563. // IShellExtInit
  1564. HRESULT CUserPropertyPages::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdo, HKEY hkeyProgID)
  1565. {
  1566. // Request the user's SID from the data object
  1567. FORMATETC fmt = {0};
  1568. fmt.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_USERPROPPAGESSID);
  1569. fmt.dwAspect = DVASPECT_CONTENT;
  1570. fmt.lindex = -1;
  1571. fmt.tymed = TYMED_HGLOBAL;
  1572. STGMEDIUM medium = { 0 };
  1573. HRESULT hr = pdo->GetData(&fmt, &medium);
  1574. if (SUCCEEDED(hr))
  1575. {
  1576. // medium.hGlobal is the user's SID; make sure it isn't null and that
  1577. // we haven't already set our copy of the SID
  1578. if ((medium.hGlobal != NULL) && (_pUserInfo == NULL))
  1579. {
  1580. PSID psid = (PSID) GlobalLock(medium.hGlobal);
  1581. if (IsValidSid(psid))
  1582. {
  1583. // Create a user info structure to party on
  1584. _pUserInfo = new CUserInfo;
  1585. if (_pUserInfo)
  1586. {
  1587. hr = _pUserInfo->Load(psid, TRUE);
  1588. if (SUCCEEDED(hr))
  1589. {
  1590. hr = _GroupList.Initialize(); // Get the groups
  1591. }
  1592. }
  1593. else
  1594. {
  1595. hr = E_OUTOFMEMORY;
  1596. }
  1597. }
  1598. else
  1599. {
  1600. hr = E_INVALIDARG;
  1601. }
  1602. GlobalUnlock(medium.hGlobal);
  1603. }
  1604. else
  1605. {
  1606. hr = E_UNEXPECTED; // hGlobal was NULL or prop sheet was already init'ed
  1607. }
  1608. ReleaseStgMedium(&medium);
  1609. }
  1610. return hr;
  1611. }
  1612. // AddPages - handles adding the property pages
  1613. HRESULT CUserPropertyPages::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
  1614. {
  1615. PROPSHEETPAGE psp = {0};
  1616. psp.dwSize = sizeof (psp);
  1617. psp.hInstance = g_hinst;
  1618. if (_pUserInfo->m_userType == CUserInfo::LOCALUSER)
  1619. {
  1620. // Add the local user prop pages
  1621. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_USERNAME_PROP_PAGE);
  1622. _pUserNamePage = new CUsernamePropertyPage(_pUserInfo);
  1623. if (_pUserNamePage != NULL)
  1624. {
  1625. _pUserNamePage->SetPropSheetPageMembers(&psp);
  1626. lpfnAddPage(CreatePropertySheetPage(&psp), lParam);
  1627. }
  1628. }
  1629. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_CHOOSEGROUP_PROP_PAGE);
  1630. _pGroupPage = new CGroupPropertyPage(_pUserInfo, &_GroupList);
  1631. if (_pGroupPage != NULL)
  1632. {
  1633. _pGroupPage->SetPropSheetPageMembers(&psp);
  1634. lpfnAddPage(CreatePropertySheetPage(&psp), lParam);
  1635. }
  1636. return S_OK;
  1637. }
  1638. STDAPI CUserPropertyPages_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  1639. {
  1640. CUserPropertyPages *pupp = new CUserPropertyPages();
  1641. if (!pupp)
  1642. {
  1643. *ppunk = NULL; // incase of failure
  1644. return E_OUTOFMEMORY;
  1645. }
  1646. HRESULT hr = pupp->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  1647. pupp->Release();
  1648. return hr;
  1649. }
  1650. // expose the SID for a user via an IDataObject
  1651. class CUserSidDataObject: public IDataObject
  1652. {
  1653. public:
  1654. CUserSidDataObject();
  1655. ~CUserSidDataObject();
  1656. // IUnknown
  1657. STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv);
  1658. STDMETHODIMP_(ULONG) AddRef();
  1659. STDMETHODIMP_(ULONG) Release();
  1660. // IDataObject
  1661. STDMETHODIMP GetData(FORMATETC* pFormatEtc, STGMEDIUM* pMedium);
  1662. STDMETHODIMP GetDataHere(FORMATETC* pFormatEtc, STGMEDIUM* pMedium)
  1663. { return E_NOTIMPL; }
  1664. STDMETHODIMP QueryGetData(FORMATETC* pFormatEtc)
  1665. { return E_NOTIMPL; }
  1666. STDMETHODIMP GetCanonicalFormatEtc(FORMATETC* pFormatetcIn, FORMATETC* pFormatetcOut)
  1667. { return E_NOTIMPL; }
  1668. STDMETHODIMP SetData(FORMATETC* pFormatetc, STGMEDIUM* pmedium, BOOL fRelease)
  1669. { return E_NOTIMPL; }
  1670. STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC ** ppenumFormatetc)
  1671. { return E_NOTIMPL; }
  1672. STDMETHODIMP DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD * pdwConnection)
  1673. { return E_NOTIMPL; }
  1674. STDMETHODIMP DUnadvise(DWORD dwConnection)
  1675. { return E_NOTIMPL; }
  1676. STDMETHODIMP EnumDAdvise(IEnumSTATDATA ** ppenumAdvise)
  1677. { return E_NOTIMPL; }
  1678. HRESULT SetSid(PSID psid);
  1679. private:
  1680. LONG _cRef;
  1681. PSID _psid;
  1682. };
  1683. CUserSidDataObject::CUserSidDataObject() :
  1684. _cRef(1)
  1685. {
  1686. DllAddRef();
  1687. }
  1688. CUserSidDataObject::~CUserSidDataObject()
  1689. {
  1690. if (_psid)
  1691. LocalFree(_psid);
  1692. DllRelease();
  1693. }
  1694. ULONG CUserSidDataObject::AddRef()
  1695. {
  1696. return InterlockedIncrement(&_cRef);
  1697. }
  1698. ULONG CUserSidDataObject::Release()
  1699. {
  1700. if (InterlockedDecrement(&_cRef))
  1701. return _cRef;
  1702. delete this;
  1703. return 0;
  1704. }
  1705. HRESULT CUserSidDataObject::QueryInterface(REFIID riid, LPVOID* ppv)
  1706. {
  1707. static const QITAB qit[] =
  1708. {
  1709. QITABENT(CUserSidDataObject, IDataObject), // IID_IDataObject
  1710. {0, 0 },
  1711. };
  1712. return QISearch(this, qit, riid, ppv);
  1713. }
  1714. HRESULT CUserSidDataObject::GetData(FORMATETC* pFormatEtc, STGMEDIUM* pMedium)
  1715. {
  1716. HRESULT hr = QueryGetData(pFormatEtc);
  1717. if (SUCCEEDED(hr))
  1718. {
  1719. pMedium->pUnkForRelease = (IDataObject*)this;
  1720. AddRef(); // reference to ourself
  1721. pMedium->tymed = TYMED_HGLOBAL;
  1722. pMedium->hGlobal = (HGLOBAL)_psid;
  1723. }
  1724. return hr;
  1725. }
  1726. HRESULT CUserSidDataObject::SetSid(PSID psid)
  1727. {
  1728. if (!psid)
  1729. return E_INVALIDARG;
  1730. if (_psid == NULL)
  1731. {
  1732. DWORD cbSid = GetLengthSid(psid);
  1733. _psid = (PSID)LocalAlloc(0, cbSid);
  1734. if (!_psid)
  1735. return E_OUTOFMEMORY;
  1736. if (CopySid(cbSid, _psid, psid))
  1737. return S_OK;
  1738. }
  1739. return E_FAIL;
  1740. }
  1741. STDAPI CUserSidDataObject_CreateInstance(PSID psid, IDataObject **ppdo)
  1742. {
  1743. CUserSidDataObject *pusdo = new CUserSidDataObject();
  1744. if (!pusdo)
  1745. return E_OUTOFMEMORY;
  1746. HRESULT hr = pusdo->SetSid(psid);
  1747. if (SUCCEEDED(hr))
  1748. {
  1749. hr = pusdo->QueryInterface(IID_PPV_ARG(IDataObject, ppdo));
  1750. }
  1751. pusdo->Release();
  1752. return hr;
  1753. }