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.

645 lines
19 KiB

  1. #include "mslocusr.h"
  2. #include "msluglob.h"
  3. #include "resource.h"
  4. #include "profiles.h"
  5. #include <npmsg.h>
  6. #include <shellapi.h>
  7. #include "contxids.h"
  8. HRESULT GetLBItemText(HWND hDlg, UINT idCtrl, int iItem, NLS_STR *pnls)
  9. {
  10. HWND hCtrl = GetDlgItem(hDlg, idCtrl);
  11. UINT cch = (UINT)SendMessage(hCtrl, LB_GETTEXTLEN, iItem, 0);
  12. if (pnls->realloc(cch + 1)) {
  13. SendMessage(hCtrl, LB_GETTEXT, iItem, (LPARAM)(LPSTR)pnls->Party());
  14. pnls->DonePartying();
  15. return NOERROR;
  16. }
  17. return E_OUTOFMEMORY;
  18. }
  19. void SetErrorFocus(HWND hDlg, UINT idCtrl, BOOL fClear /* = TRUE */)
  20. {
  21. HWND hCtrl = ::GetDlgItem(hDlg, idCtrl);
  22. ::SetFocus(hCtrl);
  23. if (fClear)
  24. ::SetWindowText(hCtrl, "");
  25. else
  26. ::SendMessage(hCtrl, EM_SETSEL, 0, -1);
  27. }
  28. INT_PTR CALLBACK PasswordDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  29. {
  30. static DWORD aIds[] = {
  31. IDC_STATIC1, IDH_RATINGS_SUPERVISOR_PASSWORD,
  32. IDC_STATIC2, IDH_RATINGS_SUPERVISOR_PASSWORD,
  33. IDC_PASSWORD, IDH_RATINGS_SUPERVISOR_PASSWORD,
  34. 0,0
  35. };
  36. CHAR pszPassword[MAX_PATH];
  37. HRESULT hRet;
  38. switch (uMsg) {
  39. case WM_INITDIALOG:
  40. {
  41. HWND hwndCheckbox = GetDlgItem(hDlg, IDC_CACHE_PASSWORD);
  42. IUserDatabase *pDB = (IUserDatabase *)lParam;
  43. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  44. IUser *pCurrentUser;
  45. HRESULT hres;
  46. hres = pDB->GetCurrentUser(&pCurrentUser);
  47. if (SUCCEEDED(hres)) {
  48. DWORD cbBuffer = sizeof(pszPassword);
  49. hres = pCurrentUser->GetName(pszPassword, &cbBuffer);
  50. if (SUCCEEDED(hres)) {
  51. NLS_STR nlsName(STR_OWNERALLOC, pszPassword);
  52. NLS_STR nlsTemp(MAX_RES_STR_LEN);
  53. const NLS_STR *apnls[] = { &nlsName, NULL };
  54. hres = HRESULT_FROM_WIN32(nlsTemp.LoadString(IDS_CACHE_PASSWORD, apnls));
  55. if (SUCCEEDED(hres))
  56. SetWindowText(hwndCheckbox, nlsTemp.QueryPch());
  57. }
  58. pCurrentUser->Release();
  59. }
  60. if (FAILED(hres)) {
  61. ShowWindow(hwndCheckbox, SW_HIDE);
  62. EnableWindow(hwndCheckbox, FALSE);
  63. }
  64. CheckDlgButton(hDlg, IDC_CACHE_PASSWORD, 0);
  65. }
  66. return TRUE; /* we did not set the focus */
  67. case WM_COMMAND:
  68. switch (LOWORD(wParam)) {
  69. case IDCANCEL:
  70. EndDialog(hDlg, FALSE);
  71. break;
  72. case IDOK:
  73. GetDlgItemText(hDlg, IDC_PASSWORD, pszPassword, sizeof(pszPassword));
  74. hRet = VerifySupervisorPassword(pszPassword);
  75. if (hRet == (NOERROR)) {
  76. IUserDatabase *pDB = (IUserDatabase *)GetWindowLongPtr(hDlg, DWLP_USER);
  77. IUser *pCurrentUser;
  78. if (SUCCEEDED(pDB->GetCurrentUser(&pCurrentUser))) {
  79. if (IsDlgButtonChecked(hDlg, IDC_CACHE_PASSWORD)) {
  80. pCurrentUser->SetSupervisorPrivilege(TRUE, pszPassword);
  81. }
  82. else {
  83. pCurrentUser->MakeTempSupervisor(TRUE, pszPassword);
  84. }
  85. pCurrentUser->Release();
  86. }
  87. EndDialog(hDlg, TRUE);
  88. }
  89. else
  90. {
  91. MsgBox(hDlg, IDS_BADPASSWORD, MB_OK | MB_ICONSTOP);
  92. SetErrorFocus(hDlg, IDC_PASSWORD);
  93. }
  94. break;
  95. default:
  96. return FALSE;
  97. }
  98. break;
  99. case WM_HELP:
  100. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, ::szRatingsHelpFile,
  101. HELP_WM_HELP, (DWORD_PTR)(LPSTR)aIds);
  102. break;
  103. case WM_CONTEXTMENU:
  104. WinHelp((HWND)wParam, ::szRatingsHelpFile, HELP_CONTEXTMENU,
  105. (DWORD_PTR)(LPVOID)aIds);
  106. break;
  107. default:
  108. return FALSE;
  109. }
  110. return TRUE;
  111. }
  112. INT_PTR CALLBACK ChangePasswordDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  113. {
  114. static DWORD aIds[] = {
  115. IDC_STATIC1, IDH_OLD_PASSWORD,
  116. IDC_OLD_PASSWORD, IDH_OLD_PASSWORD,
  117. IDC_STATIC2, IDH_NEW_PASSWORD,
  118. IDC_PASSWORD, IDH_NEW_PASSWORD,
  119. IDC_STATIC3, IDH_CONFIRM_PASSWORD,
  120. IDC_CONFIRM_PASSWORD, IDH_CONFIRM_PASSWORD,
  121. 0,0
  122. };
  123. CHAR pszPassword[MAX_PATH];
  124. CHAR pszTempPassword[MAX_PATH];
  125. CHAR *p = NULL;
  126. HRESULT hRet;
  127. HWND hwndPassword;
  128. switch (uMsg) {
  129. case WM_INITDIALOG:
  130. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  131. return TRUE; /* we didn't set the focus */
  132. case WM_COMMAND:
  133. switch (LOWORD(wParam)) {
  134. case IDCANCEL:
  135. EndDialog(hDlg, FALSE);
  136. break;
  137. case IDOK:
  138. {
  139. IUser *pUser = (IUser *)GetWindowLongPtr(hDlg, DWLP_USER);
  140. hwndPassword = ::GetDlgItem(hDlg, IDC_PASSWORD);
  141. GetWindowText(hwndPassword, pszPassword, sizeof(pszPassword));
  142. GetDlgItemText(hDlg, IDC_CONFIRM_PASSWORD, pszTempPassword, sizeof(pszTempPassword));
  143. /* if they've typed just the first password but not the
  144. * second, let Enter take them to the second field
  145. */
  146. if (*pszPassword && !*pszTempPassword && GetFocus() == hwndPassword) {
  147. SetErrorFocus(hDlg, IDC_CONFIRM_PASSWORD);
  148. break;
  149. }
  150. if (strcmpf(pszPassword, pszTempPassword))
  151. {
  152. MsgBox(hDlg, IDS_NO_MATCH, MB_OK | MB_ICONSTOP);
  153. SetErrorFocus(hDlg, IDC_CONFIRM_PASSWORD);
  154. break;
  155. }
  156. GetDlgItemText(hDlg, IDC_OLD_PASSWORD, pszTempPassword, sizeof(pszTempPassword));
  157. hRet = pUser->ChangePassword(pszTempPassword, pszPassword);
  158. if (SUCCEEDED(hRet))
  159. EndDialog(hDlg, TRUE);
  160. else
  161. {
  162. MsgBox(hDlg, IDS_BADPASSWORD, MB_OK | MB_ICONSTOP);
  163. SetErrorFocus(hDlg, IDC_OLD_PASSWORD);
  164. }
  165. break;
  166. }
  167. default:
  168. return FALSE;
  169. }
  170. break;
  171. case WM_HELP:
  172. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, ::szHelpFile,
  173. HELP_WM_HELP, (DWORD_PTR)(LPSTR)aIds);
  174. break;
  175. case WM_CONTEXTMENU:
  176. WinHelp((HWND)wParam, ::szHelpFile, HELP_CONTEXTMENU,
  177. (DWORD_PTR)(LPVOID)aIds);
  178. break;
  179. default:
  180. return FALSE;
  181. }
  182. return TRUE;
  183. }
  184. BOOL DoPasswordConfirm(HWND hwndParent, IUserDatabase *pDB)
  185. {
  186. return (BOOL)DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PASSWORD), hwndParent, PasswordDialogProc, (LPARAM)pDB);
  187. }
  188. const UINT MAX_PAGES = 1;
  189. class CCPLData
  190. {
  191. public:
  192. IUserDatabase *m_pDB;
  193. LPCSTR m_pszNameToDelete;
  194. };
  195. void CPLUserSelected(HWND hwndLB, int iItem)
  196. {
  197. HWND hDlg = GetParent(hwndLB);
  198. BOOL fEnableButtons = (iItem != LB_ERR);
  199. EnableWindow(GetDlgItem(hDlg, IDC_Delete), fEnableButtons);
  200. EnableWindow(GetDlgItem(hDlg, IDC_Clone), fEnableButtons);
  201. EnableWindow(GetDlgItem(hDlg, IDC_SetPassword), fEnableButtons);
  202. EnableWindow(GetDlgItem(hDlg, IDC_OpenProfileFolder), fEnableButtons);
  203. NLS_STR nlsTemp(MAX_RES_STR_LEN);
  204. if (fEnableButtons) {
  205. NLS_STR nlsName;
  206. if (SUCCEEDED(GetLBItemText(hDlg, IDC_USERNAME, iItem, &nlsName))) {
  207. const NLS_STR *apnls[] = { &nlsName, NULL };
  208. if (nlsTemp.LoadString(IDS_SETTINGS_FOR, apnls) != ERROR_SUCCESS)
  209. nlsTemp = szNULL;
  210. }
  211. }
  212. else {
  213. if (nlsTemp.LoadString(IDS_SELECTED_USER) != ERROR_SUCCESS)
  214. nlsTemp = szNULL;
  215. }
  216. if (nlsTemp.strlen())
  217. SetDlgItemText(hDlg, IDC_MAIN_CAPTION, nlsTemp.QueryPch());
  218. }
  219. void ReInitUserList(HWND hDlg, CCPLData *pcpld)
  220. {
  221. HWND hwndLB = GetDlgItem(hDlg, IDC_USERNAME);
  222. SendMessage(hwndLB, WM_SETREDRAW, FALSE, 0);
  223. DestroyUserList(hwndLB);
  224. SendMessage(hwndLB, LB_RESETCONTENT, 0, 0);
  225. FillUserList(hwndLB, pcpld->m_pDB, NULL, FALSE, CPLUserSelected);
  226. SendMessage(hwndLB, WM_SETREDRAW, TRUE, 0);
  227. InvalidateRect(hwndLB, NULL, TRUE);
  228. }
  229. void DoCloneUser(HWND hDlg, CCPLData *pcpld, IUser *pUserToClone)
  230. {
  231. DoAddUserWizard(hDlg, pcpld->m_pDB, FALSE, pUserToClone);
  232. ReInitUserList(hDlg, pcpld);
  233. }
  234. HRESULT DeleteProgressFunc(LPARAM lParam)
  235. {
  236. CCPLData *pcpld = (CCPLData *)lParam;
  237. return pcpld->m_pDB->DeleteUser(pcpld->m_pszNameToDelete);
  238. }
  239. void DoDeleteUser(HWND hDlg, CCPLData *pcpld, int iItem)
  240. {
  241. NLS_STR nlsName;
  242. if (FAILED(GetLBItemText(hDlg, IDC_USERNAME, iItem, &nlsName)))
  243. return;
  244. const NLS_STR *apnls[] = { &nlsName, NULL };
  245. if (MsgBox(hDlg, IDS_CONFIRM_DELETE_USER,
  246. MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2,
  247. apnls) == IDNO)
  248. return;
  249. pcpld->m_pszNameToDelete = nlsName.QueryPch();
  250. HRESULT hres = CallWithinProgressDialog(hDlg, IDD_DeleteProgress,
  251. DeleteProgressFunc, (LPARAM)pcpld);
  252. if (SUCCEEDED(hres)) {
  253. ReInitUserList(hDlg, pcpld);
  254. }
  255. else {
  256. ReportUserError(hDlg, hres);
  257. }
  258. }
  259. void DoSetPassword(HWND hDlg, CCPLData *pcpld, int iItem)
  260. {
  261. /* Note, getting pUser this way does not automatically AddRef it */
  262. IUser *pUser = (IUser *)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETITEMDATA, iItem, 0);
  263. if (pUser != NULL) {
  264. pUser->AddRef(); /* extra AddRef for life of dialog */
  265. if (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CHANGE_PASSWORD), hDlg, ChangePasswordDialogProc, (LPARAM)pUser))
  266. MsgBox(hDlg, IDS_PASSWORD_CHANGED, MB_OK | MB_ICONINFORMATION);
  267. pUser->Release(); /* undo above AddRef */
  268. }
  269. }
  270. INT_PTR CALLBACK FoldersDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  271. {
  272. static DWORD aIds[] = {
  273. IDC_CHECK_DESKTOP, IDH_DESKTOP_NETHOOD,
  274. IDC_CHECK_STARTMENU, IDH_START_MENU,
  275. IDC_CHECK_FAVORITES, IDH_FAVORITES,
  276. IDC_CHECK_CACHE, IDH_TEMP_FILES,
  277. IDC_CHECK_MYDOCS, IDH_MY_DOCS,
  278. IDC_RADIO_EMPTY, IDH_EMPTY_FOLDERS,
  279. IDC_RADIO_COPY, IDH_EXISTING_FILES,
  280. 0,0
  281. };
  282. switch(message)
  283. {
  284. case WM_COMMAND:
  285. switch (LOWORD(wParam)) {
  286. case IDCANCEL:
  287. EndDialog(hDlg, FALSE);
  288. break;
  289. case IDOK:
  290. {
  291. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  292. pwd->m_fdwCloneFromDefault = IsDlgButtonChecked(hDlg, IDC_RADIO_EMPTY) ? 0 : 0xffffffff;
  293. pwd->m_fdwNewPerUserFolders = 0;
  294. if (IsDlgButtonChecked(hDlg, IDC_CHECK_DESKTOP))
  295. pwd->m_fdwNewPerUserFolders |= FOLDER_DESKTOP | FOLDER_NETHOOD | FOLDER_RECENT;
  296. else
  297. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_DESKTOP | FOLDER_NETHOOD | FOLDER_RECENT);
  298. if (IsDlgButtonChecked(hDlg, IDC_CHECK_STARTMENU))
  299. pwd->m_fdwNewPerUserFolders |= FOLDER_STARTMENU | FOLDER_PROGRAMS | FOLDER_STARTUP;
  300. else
  301. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_STARTMENU | FOLDER_PROGRAMS | FOLDER_STARTUP);
  302. if (IsDlgButtonChecked(hDlg, IDC_CHECK_FAVORITES))
  303. pwd->m_fdwNewPerUserFolders |= FOLDER_FAVORITES;
  304. else
  305. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_FAVORITES);
  306. if (IsDlgButtonChecked(hDlg, IDC_CHECK_CACHE))
  307. pwd->m_fdwNewPerUserFolders |= FOLDER_CACHE;
  308. else
  309. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_CACHE);
  310. if (IsDlgButtonChecked(hDlg, IDC_CHECK_MYDOCS))
  311. pwd->m_fdwNewPerUserFolders |= FOLDER_MYDOCS;
  312. else
  313. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_MYDOCS);
  314. FinishChooseFolders(hDlg, pwd);
  315. }
  316. break;
  317. default:
  318. return FALSE;
  319. }
  320. break;
  321. case WM_INITDIALOG:
  322. {
  323. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  324. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  325. InitFolderCheckboxes(hDlg, pwd);
  326. CheckRadioButton(hDlg, IDC_RADIO_COPY, IDC_RADIO_EMPTY, IDC_RADIO_COPY);
  327. }
  328. break;
  329. case WM_HELP:
  330. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, ::szHelpFile,
  331. HELP_WM_HELP, (DWORD_PTR)(LPSTR)aIds);
  332. break;
  333. case WM_CONTEXTMENU:
  334. WinHelp((HWND)wParam, ::szHelpFile, HELP_CONTEXTMENU,
  335. (DWORD_PTR)(LPVOID)aIds);
  336. break;
  337. default:
  338. return FALSE;
  339. } // end of switch on message
  340. return TRUE;
  341. }
  342. void DoOpenProfileFolder(HWND hDlg, CCPLData *pcpld, int iItem)
  343. {
  344. /* Note, getting pUser this way does not automatically AddRef it */
  345. IUser *pUser = (IUser *)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETITEMDATA, iItem, 0);
  346. #if 0 /* old code to launch Explorer on the user's profile dir */
  347. if (pUser != NULL) {
  348. CHAR szHomeDir[MAX_PATH];
  349. DWORD cbBuffer = sizeof(szHomeDir);
  350. if (SUCCEEDED(pUser->GetProfileDirectory(szHomeDir, &cbBuffer)) &&
  351. cbBuffer > 0) {
  352. TCHAR szArgs[MAX_PATH+4];
  353. lstrcpy(szArgs, "/e,");
  354. lstrcat(szArgs, szHomeDir);
  355. SHELLEXECUTEINFO ei;
  356. ei.lpFile = "explorer.exe";
  357. ei.cbSize = sizeof(SHELLEXECUTEINFO);
  358. ei.hwnd = NULL;
  359. ei.lpVerb = NULL;
  360. ei.lpParameters = szArgs;
  361. ei.lpDirectory = szHomeDir;
  362. ei.nShow = SW_SHOWNORMAL;
  363. ei.fMask = SEE_MASK_NOCLOSEPROCESS;
  364. if (ShellExecuteEx(&ei))
  365. {
  366. CloseHandle(ei.hProcess);
  367. }
  368. }
  369. }
  370. #else
  371. if (pUser != NULL) {
  372. CWizData wd;
  373. wd.m_pDB = pcpld->m_pDB;
  374. wd.m_pUserToClone = pUser;
  375. pUser->AddRef();
  376. DialogBoxParam(::hInstance, MAKEINTRESOURCE(IDD_ChooseFolders), hDlg,
  377. FoldersDlgProc, (LPARAM)&wd);
  378. }
  379. #endif
  380. }
  381. INT_PTR CALLBACK UserCPLDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  382. {
  383. static DWORD aIds[] = {
  384. IDC_USERNAME, IDH_USERS_LIST,
  385. IDC_Add, IDH_NEW_USER,
  386. IDC_Delete, IDH_REMOVE_USER,
  387. IDC_Clone, IDH_COPY_USER,
  388. IDC_SetPassword, IDH_SET_PASSWORD,
  389. IDC_OpenProfileFolder, IDH_CHANGE_DESKTOP,
  390. 0,0
  391. };
  392. NMHDR FAR *lpnm;
  393. switch(message)
  394. {
  395. case WM_NOTIFY:
  396. lpnm = (NMHDR FAR *)lParam;
  397. switch(lpnm->code)
  398. {
  399. case PSN_SETACTIVE:
  400. {
  401. int iItem = (int)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  402. CPLUserSelected((HWND)lParam, iItem);
  403. }
  404. break;
  405. default:
  406. return FALSE;
  407. }
  408. break;
  409. case WM_INITDIALOG:
  410. {
  411. PropSheet_CancelToClose(GetParent(hDlg));
  412. InitWizDataPtr(hDlg, lParam);
  413. CCPLData *pcpld = (CCPLData *)(((LPPROPSHEETPAGE)lParam)->lParam);
  414. FillUserList(GetDlgItem(hDlg, IDC_USERNAME), pcpld->m_pDB, NULL,
  415. FALSE, CPLUserSelected);
  416. }
  417. break;
  418. case WM_DESTROY:
  419. DestroyUserList(GetDlgItem(hDlg, IDC_USERNAME));
  420. break;
  421. case WM_COMMAND:
  422. {
  423. CCPLData *pcpld = (CCPLData *)GetWindowLongPtr(hDlg, DWLP_USER);
  424. int iItem = (int)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  425. switch (LOWORD(wParam)) {
  426. case IDC_USERNAME:
  427. if (HIWORD(wParam) == LBN_SELCHANGE) {
  428. CPLUserSelected((HWND)lParam, iItem);
  429. }
  430. break;
  431. case IDC_Add:
  432. DoCloneUser(hDlg, pcpld, NULL);
  433. break;
  434. case IDC_Clone:
  435. {
  436. if (iItem != LB_ERR) {
  437. IUser *pUser = (IUser *)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETITEMDATA, iItem, 0);
  438. DoCloneUser(hDlg, pcpld, pUser);
  439. }
  440. }
  441. break;
  442. case IDC_Delete:
  443. DoDeleteUser(hDlg, pcpld, iItem);
  444. break;
  445. case IDC_SetPassword:
  446. DoSetPassword(hDlg, pcpld, iItem);
  447. break;
  448. case IDC_OpenProfileFolder:
  449. DoOpenProfileFolder(hDlg, pcpld, iItem);
  450. break;
  451. default:
  452. return FALSE;
  453. } /* switch */
  454. }
  455. break;
  456. case WM_HELP:
  457. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, ::szHelpFile,
  458. HELP_WM_HELP, (DWORD_PTR)(LPSTR)aIds);
  459. break;
  460. case WM_CONTEXTMENU:
  461. WinHelp((HWND)wParam, ::szHelpFile, HELP_CONTEXTMENU,
  462. (DWORD_PTR)(LPVOID)aIds);
  463. break;
  464. default:
  465. return FALSE;
  466. } // end of switch on message
  467. return TRUE;
  468. }
  469. STDMETHODIMP CLUDatabase::UserCPL(HWND hwndParent)
  470. {
  471. if (ProfileUIRestricted()) {
  472. ReportRestrictionError(hwndParent);
  473. return E_ACCESSDENIED;
  474. }
  475. CCPLData cpld;
  476. cpld.m_pDB = this;
  477. if (!UseUserProfiles() || FAILED(VerifySupervisorPassword(szNULL))) {
  478. return InstallWizard(hwndParent);
  479. }
  480. else {
  481. BOOL fContinue = TRUE;
  482. if (IsCurrentUserSupervisor(this) != S_OK) {
  483. fContinue = DoPasswordConfirm(hwndParent, this);
  484. }
  485. if (fContinue) {
  486. LPPROPSHEETHEADER ppsh;
  487. // Allocate the property sheet header
  488. //
  489. if ((ppsh = (LPPROPSHEETHEADER)LocalAlloc(LMEM_FIXED, sizeof(PROPSHEETHEADER)+
  490. (MAX_PAGES * sizeof(HPROPSHEETPAGE)))) != NULL)
  491. {
  492. ppsh->dwSize = sizeof(*ppsh);
  493. ppsh->dwFlags = PSH_NOAPPLYNOW;
  494. ppsh->hwndParent = hwndParent;
  495. ppsh->hInstance = ::hInstance;
  496. ppsh->pszCaption = (LPSTR)IDS_MSGTITLE;
  497. ppsh->nPages = 0;
  498. ppsh->nStartPage = 0;
  499. ppsh->phpage = (HPROPSHEETPAGE *)(ppsh+1);
  500. AddPage(ppsh, IDD_Users, UserCPLDlgProc, &cpld);
  501. PropertySheet(ppsh);
  502. LocalFree((HLOCAL)ppsh);
  503. }
  504. }
  505. }
  506. return NOERROR;
  507. }
  508. void DoUserCPL(HWND hwndParent)
  509. {
  510. IUserDatabase *pDB = NULL;
  511. if (FAILED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB)))
  512. return;
  513. pDB->UserCPL(hwndParent);
  514. pDB->Release();
  515. }
  516. extern "C" void UserCPL(HWND hwndParent, HINSTANCE hinstEXE, LPSTR pszCmdLine, int nCmdShow)
  517. {
  518. DoUserCPL(hwndParent);
  519. }