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.

1612 lines
53 KiB

  1. #include "mslocusr.h"
  2. #include "msluglob.h"
  3. #include "resource.h"
  4. #include <regentry.h>
  5. #include "profiles.h"
  6. #include <npmsg.h>
  7. extern "C" void SHFlushSFCache(void);
  8. void ReportUserError(HWND hwndParent, HRESULT hres)
  9. {
  10. if (SUCCEEDED(hres))
  11. return;
  12. UINT idMsg;
  13. NLS_STR nlsSub(16); /* long enough for any 32-bit number, any format */
  14. if ((((DWORD)hres) >> 16) == (FACILITY_WIN32 | 0x8000)) {
  15. UINT err = (hres & 0xffff);
  16. switch (err) {
  17. case ERROR_ACCESS_DENIED: idMsg = IDS_E_ACCESSDENIED; break;
  18. case ERROR_NOT_AUTHENTICATED: idMsg = IDS_ERROR_NOT_AUTHENTICATED; break;
  19. case ERROR_NO_SUCH_USER: idMsg = IDS_ERROR_NO_SUCH_USER; break;
  20. case ERROR_USER_EXISTS: idMsg = IDS_ERROR_USER_EXISTS; break;
  21. case ERROR_NOT_ENOUGH_MEMORY: idMsg = IDS_ERROR_OUT_OF_MEMORY; break;
  22. case ERROR_BUSY: idMsg = IDS_ERROR_BUSY; break;
  23. case ERROR_PATH_NOT_FOUND: idMsg = IDS_ERROR_PATH_NOT_FOUND; break;
  24. case ERROR_BUFFER_OVERFLOW: idMsg = IDS_ERROR_BUFFER_OVERFLOW; break;
  25. case IERR_CachingDisabled: idMsg = IDS_IERR_CachingDisabled; break;
  26. case IERR_BadSig: idMsg = IDS_IERR_BadSig; break;
  27. case IERR_CacheReadOnly : idMsg = IDS_IERR_CacheReadOnly; break;
  28. case IERR_IncorrectUsername: idMsg = IDS_IERR_IncorrectUsername; break;
  29. case IERR_CacheCorrupt: idMsg = IDS_IERR_CacheCorrupt; break;
  30. case IERR_UsernameNotFound: idMsg = IDS_IERR_UsernameNotFound; break;
  31. case IERR_CacheFull: idMsg = IDS_IERR_CacheFull; break;
  32. case IERR_CacheAlreadyOpen: idMsg = IDS_IERR_CacheAlreadyOpen; break;
  33. default:
  34. idMsg = IDS_UNKNOWN_ERROR;
  35. wsprintf(nlsSub.Party(), "%d", err);
  36. nlsSub.DonePartying();
  37. break;
  38. }
  39. }
  40. else {
  41. switch(hres) {
  42. case E_OUTOFMEMORY: idMsg = IDS_ERROR_OUT_OF_MEMORY; break;
  43. // case E_ACCESSDENIED: idMsg = IDS_E_ACCESSDENIED; break;
  44. default:
  45. idMsg = IDS_UNKNOWN_ERROR;
  46. wsprintf(nlsSub.Party(), "0x%x", hres);
  47. nlsSub.DonePartying();
  48. break;
  49. }
  50. }
  51. const NLS_STR *apnls[] = { &nlsSub, NULL };
  52. MsgBox(hwndParent, idMsg, MB_OK | MB_ICONSTOP, apnls);
  53. }
  54. const UINT MAX_WIZ_PAGES = 8;
  55. #if 0 /* now in mslocusr.h */
  56. class CWizData : public IUserProfileInit
  57. {
  58. public:
  59. HRESULT m_hresRatings; /* result of VerifySupervisorPassword("") */
  60. BOOL m_fGoMultiWizard; /* TRUE if this is the big go-multiuser wizard */
  61. NLS_STR m_nlsSupervisorPassword;
  62. NLS_STR m_nlsUsername;
  63. NLS_STR m_nlsUserPassword;
  64. IUserDatabase *m_pDB;
  65. IUser *m_pUserToClone;
  66. int m_idPrevPage; /* ID of page before Finish */
  67. UINT m_cRef;
  68. DWORD m_fdwOriginalPerUserFolders;
  69. DWORD m_fdwNewPerUserFolders;
  70. DWORD m_fdwCloneFromDefault;
  71. BOOL m_fCreatingProfile;
  72. CWizData();
  73. ~CWizData();
  74. // *** IUnknown methods ***
  75. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  76. STDMETHODIMP_(ULONG) AddRef(void);
  77. STDMETHODIMP_(ULONG) Release(void);
  78. STDMETHODIMP PreInitProfile(HKEY hkeyUser, LPCSTR pszProfileDir);
  79. STDMETHODIMP PostInitProfile(HKEY hkeyUser, LPCSTR pszProfileDir);
  80. };
  81. #endif
  82. CWizData::CWizData()
  83. : m_nlsSupervisorPassword(),
  84. m_nlsUsername(),
  85. m_nlsUserPassword(),
  86. m_cRef(0),
  87. m_fdwOriginalPerUserFolders(0),
  88. m_fdwNewPerUserFolders(0),
  89. m_fdwCloneFromDefault(0),
  90. m_fCreatingProfile(FALSE)
  91. {
  92. }
  93. CWizData::~CWizData()
  94. {
  95. if (m_pUserToClone != NULL)
  96. m_pUserToClone->Release();
  97. }
  98. STDMETHODIMP CWizData::QueryInterface(REFIID riid, LPVOID * ppvObj)
  99. {
  100. if (!IsEqualIID(riid, IID_IUnknown) &&
  101. !IsEqualIID(riid, IID_IUserProfileInit)) {
  102. *ppvObj = NULL;
  103. return ResultFromScode(E_NOINTERFACE);
  104. }
  105. *ppvObj = this;
  106. AddRef();
  107. return NOERROR;
  108. }
  109. STDMETHODIMP_(ULONG) CWizData::AddRef(void)
  110. {
  111. return ++m_cRef;
  112. }
  113. STDMETHODIMP_(ULONG) CWizData::Release(void)
  114. {
  115. ULONG cRef;
  116. cRef = --m_cRef;
  117. if (0L == m_cRef) {
  118. delete this;
  119. }
  120. return cRef;
  121. }
  122. void LimitCredentialLength(HWND hDlg, UINT idCtrl)
  123. {
  124. SendDlgItemMessage(hDlg, idCtrl, EM_LIMITTEXT, (WPARAM)cchMaxUsername, 0);
  125. }
  126. void AddPage(LPPROPSHEETHEADER ppsh, UINT id, DLGPROC pfn, LPVOID pwd)
  127. {
  128. if (ppsh->nPages < MAX_WIZ_PAGES)
  129. {
  130. PROPSHEETPAGE psp;
  131. psp.dwSize = sizeof(psp);
  132. psp.dwFlags = PSP_DEFAULT;
  133. psp.hInstance = ::hInstance;
  134. psp.pszTemplate = MAKEINTRESOURCE(id);
  135. psp.pfnDlgProc = pfn;
  136. psp.lParam = (LPARAM)pwd;
  137. ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp);
  138. if (ppsh->phpage[ppsh->nPages])
  139. ppsh->nPages++;
  140. }
  141. } // AddPage
  142. INT_PTR CALLBACK IntroDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  143. {
  144. NMHDR FAR *lpnm;
  145. switch(message)
  146. {
  147. case WM_NOTIFY:
  148. lpnm = (NMHDR FAR *)lParam;
  149. switch(lpnm->code)
  150. {
  151. case PSN_SETACTIVE:
  152. {
  153. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
  154. break;
  155. }
  156. default:
  157. return FALSE;
  158. }
  159. break;
  160. default:
  161. return FALSE;
  162. } // end of switch on message
  163. return TRUE;
  164. }
  165. void GoToPage(HWND hDlg, int idPage)
  166. {
  167. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, idPage);
  168. }
  169. inline void FailChangePage(HWND hDlg)
  170. {
  171. GoToPage(hDlg, -1);
  172. }
  173. void InitWizDataPtr(HWND hDlg, LPARAM lParam)
  174. {
  175. CWizData *pwd = (CWizData *)(((LPPROPSHEETPAGE)lParam)->lParam);
  176. SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)pwd);
  177. }
  178. void InsertControlText(HWND hDlg, UINT idCtrl, const NLS_STR *pnlsInsert)
  179. {
  180. int cchText = GetWindowTextLength(GetDlgItem(hDlg, IDC_MAIN_CAPTION)) + pnlsInsert->strlen() + 1;
  181. NLS_STR nlsTemp(MAX_RES_STR_LEN);
  182. if (nlsTemp.QueryError() == ERROR_SUCCESS) {
  183. GetDlgItemText(hDlg, idCtrl, nlsTemp.Party(), nlsTemp.QueryAllocSize());
  184. nlsTemp.DonePartying();
  185. const NLS_STR *apnls[] = { pnlsInsert, NULL };
  186. nlsTemp.InsertParams(apnls);
  187. if (nlsTemp.QueryError() == ERROR_SUCCESS)
  188. SetDlgItemText(hDlg, idCtrl, nlsTemp.QueryPch());
  189. }
  190. }
  191. HRESULT GetControlText(HWND hDlg, UINT idCtrl, NLS_STR *pnls)
  192. {
  193. HWND hCtrl = GetDlgItem(hDlg, idCtrl);
  194. if (pnls->realloc(GetWindowTextLength(hCtrl) + 1)) {
  195. GetWindowText(hCtrl, pnls->Party(), pnls->QueryAllocSize());
  196. pnls->DonePartying();
  197. return NOERROR;
  198. }
  199. return E_OUTOFMEMORY;
  200. }
  201. INT_PTR CALLBACK EnterCAPWDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  202. {
  203. NMHDR FAR *lpnm;
  204. switch(message)
  205. {
  206. case WM_NOTIFY:
  207. lpnm = (NMHDR FAR *)lParam;
  208. switch(lpnm->code)
  209. {
  210. case PSN_SETACTIVE:
  211. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  212. break;
  213. case PSN_WIZNEXT:
  214. {
  215. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  216. if (SUCCEEDED(GetControlText(hDlg, IDC_PASSWORD, &pwd->m_nlsSupervisorPassword))) {
  217. if (VerifySupervisorPassword(pwd->m_nlsSupervisorPassword.QueryPch()) == S_FALSE) {
  218. MsgBox(hDlg, IDS_BADPASSWORD, MB_OK | MB_ICONSTOP);
  219. SetErrorFocus(hDlg, IDC_PASSWORD);
  220. FailChangePage(hDlg);
  221. }
  222. }
  223. }
  224. break;
  225. default:
  226. return FALSE;
  227. }
  228. break;
  229. case WM_INITDIALOG:
  230. InitWizDataPtr(hDlg, lParam);
  231. break;
  232. default:
  233. return FALSE;
  234. } // end of switch on message
  235. return TRUE;
  236. }
  237. INT_PTR CALLBACK EnterUserPWDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  238. {
  239. NMHDR FAR *lpnm;
  240. switch(message)
  241. {
  242. case WM_NOTIFY:
  243. lpnm = (NMHDR FAR *)lParam;
  244. switch(lpnm->code)
  245. {
  246. case PSN_SETACTIVE:
  247. {
  248. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  249. }
  250. break;
  251. case PSN_WIZNEXT:
  252. {
  253. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  254. if (SUCCEEDED(GetControlText(hDlg, IDC_PASSWORD, &pwd->m_nlsUserPassword))) {
  255. HANDLE hPWL = NULL;
  256. if (FAILED(::GetUserPasswordCache(pwd->m_nlsUsername.QueryPch(),
  257. pwd->m_nlsUserPassword.QueryPch(),
  258. &hPWL, TRUE))) {
  259. MsgBox(hDlg, IDS_BADPASSWORD, MB_OK | MB_ICONSTOP);
  260. SetErrorFocus(hDlg, IDC_PASSWORD);
  261. FailChangePage(hDlg);
  262. }
  263. else {
  264. if (FAILED(pwd->m_hresRatings))
  265. pwd->m_nlsSupervisorPassword = pwd->m_nlsUserPassword;
  266. pwd->m_idPrevPage = IDD_EnterUserPassword;
  267. ::ClosePasswordCache(hPWL, TRUE);
  268. int idNextPage;
  269. if (pwd->m_fCreatingProfile)
  270. idNextPage = IDD_ChooseFoldersWiz;
  271. else
  272. idNextPage = (pwd->m_fGoMultiWizard) ? IDD_FinishGoMulti : IDD_FinishAddUser;
  273. GoToPage(hDlg, idNextPage);
  274. }
  275. }
  276. }
  277. break;
  278. case PSN_WIZBACK:
  279. GoToPage(hDlg, IDD_EnterUsername);
  280. break;
  281. default:
  282. return FALSE;
  283. }
  284. break;
  285. case WM_INITDIALOG:
  286. {
  287. InitWizDataPtr(hDlg, lParam);
  288. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  289. InsertControlText(hDlg, IDC_MAIN_CAPTION, &pwd->m_nlsUsername);
  290. LimitCredentialLength(hDlg, IDC_PASSWORD);
  291. if (FAILED(pwd->m_hresRatings)) {
  292. NLS_STR nlsTemp(MAX_RES_STR_LEN);
  293. if (nlsTemp.QueryError() == ERROR_SUCCESS) {
  294. nlsTemp.LoadString(IDS_RATINGS_PW_COMMENT);
  295. if (nlsTemp.QueryError() == ERROR_SUCCESS)
  296. SetDlgItemText(hDlg, IDC_RATINGS_PW_COMMENT, nlsTemp.QueryPch());
  297. }
  298. }
  299. }
  300. break;
  301. default:
  302. return FALSE;
  303. } // end of switch on message
  304. return TRUE;
  305. }
  306. INT_PTR CALLBACK EnterUsernameDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  307. {
  308. NMHDR FAR *lpnm;
  309. switch(message)
  310. {
  311. case WM_NOTIFY:
  312. lpnm = (NMHDR FAR *)lParam;
  313. switch(lpnm->code)
  314. {
  315. case PSN_SETACTIVE:
  316. {
  317. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  318. }
  319. break;
  320. case PSN_WIZNEXT:
  321. {
  322. int cchUsername = GetWindowTextLength(GetDlgItem(hDlg, IDC_USERNAME));
  323. if (!cchUsername) {
  324. MsgBox(hDlg, IDS_BLANK_USERNAME, MB_OK | MB_ICONSTOP);
  325. SetErrorFocus(hDlg, IDC_USERNAME, FALSE);
  326. FailChangePage(hDlg);
  327. }
  328. else {
  329. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  330. if (SUCCEEDED(GetControlText(hDlg, IDC_USERNAME, &pwd->m_nlsUsername))) {
  331. /* If we're in the add-user wizard, fail if the user
  332. * already exists. In the go-multiuser wizard, we
  333. * just use the info to determine whether to offer
  334. * the folder-personalization page.
  335. */
  336. IUser *pUser = NULL;
  337. if (SUCCEEDED(pwd->m_pDB->GetUser(pwd->m_nlsUsername.QueryPch(), &pUser))) {
  338. pUser->Release();
  339. if (!pwd->m_fGoMultiWizard) {
  340. const NLS_STR *apnls[] = { &pwd->m_nlsUsername, NULL };
  341. if (MsgBox(hDlg, IDS_USER_EXISTS, MB_OKCANCEL | MB_ICONSTOP, apnls) == IDCANCEL) {
  342. PropSheet_PressButton(GetParent(hDlg), PSBTN_CANCEL);
  343. break;
  344. }
  345. SetErrorFocus(hDlg, IDC_USERNAME, FALSE);
  346. FailChangePage(hDlg);
  347. break;
  348. }
  349. else {
  350. pwd->m_fCreatingProfile = FALSE;
  351. }
  352. }
  353. else {
  354. pwd->m_fCreatingProfile = TRUE;
  355. }
  356. /* See if the user already has a PWL. If not, next
  357. * page is to enter and confirm a password. If there
  358. * is a PWL and its password is non-blank, next page
  359. * is simply to enter the password. If there's a PWL
  360. * and its password is blank, next page is Finish.
  361. */
  362. int idNextPage;
  363. HANDLE hPWL = NULL;
  364. HRESULT hres = ::GetUserPasswordCache(pwd->m_nlsUsername.QueryPch(),
  365. szNULL, &hPWL, FALSE);
  366. if (SUCCEEDED(hres)) {
  367. ::ClosePasswordCache(hPWL, TRUE);
  368. pwd->m_idPrevPage = IDD_EnterUsername;
  369. if (pwd->m_fCreatingProfile)
  370. idNextPage = IDD_ChooseFoldersWiz;
  371. else
  372. idNextPage = (pwd->m_fGoMultiWizard) ? IDD_FinishGoMulti : IDD_FinishAddUser;
  373. }
  374. else if (hres == HRESULT_FROM_WIN32(IERR_IncorrectUsername)) {
  375. idNextPage = IDD_EnterUserPassword;
  376. }
  377. else {
  378. idNextPage = IDD_NewUserPassword;
  379. }
  380. GoToPage(hDlg, idNextPage);
  381. }
  382. }
  383. }
  384. break;
  385. default:
  386. return FALSE;
  387. }
  388. break;
  389. case WM_INITDIALOG:
  390. {
  391. InitWizDataPtr(hDlg, lParam);
  392. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  393. LimitCredentialLength(hDlg, IDC_USERNAME);
  394. if (pwd->m_fGoMultiWizard) {
  395. NLS_STR nlsText(MAX_RES_STR_LEN);
  396. if (nlsText.QueryError() == ERROR_SUCCESS) {
  397. nlsText.LoadString(IDS_ENTER_FIRST_USERNAME);
  398. if (nlsText.QueryError() == ERROR_SUCCESS)
  399. SetDlgItemText(hDlg, IDC_MAIN_CAPTION, nlsText.QueryPch());
  400. }
  401. }
  402. }
  403. break;
  404. default:
  405. return FALSE;
  406. } // end of switch on message
  407. return TRUE;
  408. }
  409. void PickUserSelected(HWND hwndLB, int iItem)
  410. {
  411. HWND hDlg = GetParent(hwndLB);
  412. if (iItem == LB_ERR) {
  413. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK);
  414. }
  415. else {
  416. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  417. }
  418. }
  419. INT_PTR CALLBACK PickUserDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  420. {
  421. NMHDR FAR *lpnm;
  422. switch(message)
  423. {
  424. case WM_NOTIFY:
  425. lpnm = (NMHDR FAR *)lParam;
  426. switch(lpnm->code)
  427. {
  428. case PSN_SETACTIVE:
  429. {
  430. int iItem = (int)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  431. PickUserSelected((HWND)lParam, iItem);
  432. }
  433. break;
  434. case PSN_WIZNEXT:
  435. {
  436. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  437. int iItem = (int)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  438. if (iItem != LB_ERR) {
  439. if (pwd->m_pUserToClone != NULL)
  440. pwd->m_pUserToClone->Release();
  441. pwd->m_pUserToClone = (IUser *)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETITEMDATA, iItem, 0);
  442. if (pwd->m_pUserToClone != NULL)
  443. pwd->m_pUserToClone->AddRef();
  444. }
  445. else {
  446. MsgBox(hDlg, IDS_PICK_USERNAME, MB_OK | MB_ICONSTOP);
  447. FailChangePage(hDlg);
  448. }
  449. }
  450. break;
  451. default:
  452. return FALSE;
  453. }
  454. break;
  455. case WM_INITDIALOG:
  456. {
  457. InitWizDataPtr(hDlg, lParam);
  458. CWizData *pwd = (CWizData *)(((LPPROPSHEETPAGE)lParam)->lParam);
  459. FillUserList(GetDlgItem(hDlg, IDC_USERNAME), pwd->m_pDB, NULL,
  460. TRUE, PickUserSelected);
  461. }
  462. break;
  463. case WM_DESTROY:
  464. DestroyUserList(GetDlgItem(hDlg, IDC_USERNAME));
  465. break;
  466. case WM_COMMAND:
  467. if (LOWORD(wParam) == IDC_USERNAME && HIWORD(wParam) == LBN_SELCHANGE) {
  468. int iItem = (int)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0);
  469. PickUserSelected((HWND)lParam, iItem);
  470. }
  471. break;
  472. default:
  473. return FALSE;
  474. } // end of switch on message
  475. return TRUE;
  476. }
  477. INT_PTR CALLBACK NewPasswordDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  478. {
  479. NMHDR FAR *lpnm;
  480. switch(message)
  481. {
  482. case WM_NOTIFY:
  483. lpnm = (NMHDR FAR *)lParam;
  484. switch(lpnm->code)
  485. {
  486. case PSN_SETACTIVE:
  487. {
  488. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  489. }
  490. break;
  491. case PSN_WIZNEXT:
  492. {
  493. int cchPassword = GetWindowTextLength(GetDlgItem(hDlg, IDC_PASSWORD));
  494. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  495. GetControlText(hDlg, IDC_PASSWORD, &pwd->m_nlsUserPassword);
  496. BOOL fConfirmedOK = FALSE;
  497. int cchConfirm = GetWindowTextLength(GetDlgItem(hDlg, IDC_CONFIRM_PASSWORD));
  498. if (cchConfirm == cchPassword) {
  499. NLS_STR nlsConfirm(cchConfirm+1);
  500. if (SUCCEEDED(GetControlText(hDlg, IDC_CONFIRM_PASSWORD, &nlsConfirm))) {
  501. if (!nlsConfirm.strcmp(pwd->m_nlsUserPassword))
  502. fConfirmedOK = TRUE;
  503. }
  504. }
  505. if (!fConfirmedOK) {
  506. MsgBox(hDlg, IDS_NO_MATCH, MB_OK | MB_ICONSTOP);
  507. SetDlgItemText(hDlg, IDC_PASSWORD, szNULL);
  508. SetDlgItemText(hDlg, IDC_CONFIRM_PASSWORD, szNULL);
  509. SetErrorFocus(hDlg, IDC_PASSWORD);
  510. FailChangePage(hDlg);
  511. }
  512. else {
  513. pwd->m_idPrevPage = IDD_NewUserPassword;
  514. UINT idNextPage;
  515. if (pwd->m_fCreatingProfile)
  516. idNextPage = IDD_ChooseFoldersWiz;
  517. else
  518. idNextPage = pwd->m_fGoMultiWizard ? IDD_FinishGoMulti : IDD_FinishAddUser;
  519. GoToPage(hDlg, idNextPage);
  520. }
  521. }
  522. break;
  523. case PSN_WIZBACK:
  524. GoToPage(hDlg, IDD_EnterUsername);
  525. break;
  526. default:
  527. return FALSE;
  528. }
  529. break;
  530. case WM_INITDIALOG:
  531. {
  532. InitWizDataPtr(hDlg, lParam);
  533. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  534. LimitCredentialLength(hDlg, IDC_PASSWORD);
  535. LimitCredentialLength(hDlg, IDC_CONFIRM_PASSWORD);
  536. if (pwd->m_fGoMultiWizard) {
  537. NLS_STR nlsText(MAX_RES_STR_LEN);
  538. if (nlsText.QueryError() == ERROR_SUCCESS) {
  539. nlsText.LoadString(IDS_YOURNEWPASSWORD);
  540. if (nlsText.QueryError() == ERROR_SUCCESS)
  541. SetDlgItemText(hDlg, IDC_MAIN_CAPTION, nlsText.QueryPch());
  542. if (FAILED(pwd->m_hresRatings)) {
  543. nlsText.LoadString(IDS_RATINGS_PW_COMMENT);
  544. if (nlsText.QueryError() == ERROR_SUCCESS)
  545. SetDlgItemText(hDlg, IDC_RATINGS_PW_COMMENT, nlsText.QueryPch());
  546. }
  547. }
  548. }
  549. else {
  550. InsertControlText(hDlg, IDC_MAIN_CAPTION, &pwd->m_nlsUsername);
  551. }
  552. }
  553. break;
  554. default:
  555. return FALSE;
  556. } // end of switch on message
  557. return TRUE;
  558. }
  559. const TCHAR c_szExplorerUSFKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders");
  560. const TCHAR c_szExplorerSFKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
  561. const struct FolderDescriptor {
  562. UINT idsDirName; /* Resource ID for directory name */
  563. LPCTSTR pszRegValue; /* Name of reg value to set path in */
  564. LPCTSTR pszStaticName; /* Static name for ProfileReconciliation subkey */
  565. LPCTSTR pszFiles; /* Spec for which files should roam */
  566. DWORD dwAttribs; /* Desired attributes */
  567. BOOL fSecondary : 1; /* TRUE if subsidiary to the Start Menu */
  568. BOOL fDefaultInRoot : 1;/* TRUE if default is root of drive, not windir */
  569. } aFolders[] = {
  570. /* NOTE: Keep the entries in the following table in the same order as the
  571. * corresponding FOLDER_XXXXXX bitflags in mslocusr.h.
  572. */
  573. { IDS_CSIDL_DESKTOP_L, "Desktop", "Desktop", "*.*", FILE_ATTRIBUTE_DIRECTORY, 0, 0 },
  574. { IDS_CSIDL_NETHOOD_L, "NetHood", "NetHood", "*.*", FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN, 0, 0 },
  575. { IDS_CSIDL_RECENT_L, "Recent", "Recent", "*.*", FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN, 0, 0 },
  576. { IDS_CSIDL_STARTMENU_L,"Start Menu","Start Menu","*.lnk,*.pif,*.url", FILE_ATTRIBUTE_DIRECTORY, 0, 0 },
  577. { IDS_CSIDL_PROGRAMS_L, "Programs", "Programs", "*.lnk,*.pif,*.url", FILE_ATTRIBUTE_DIRECTORY, 1, 0 },
  578. { IDS_CSIDL_STARTUP_L, "Startup", "Startup", "*.lnk,*.pif,*.url", FILE_ATTRIBUTE_DIRECTORY, 1, 0 },
  579. { IDS_CSIDL_FAVORITES_L,"Favorites", "Favorites", "*.*", FILE_ATTRIBUTE_DIRECTORY, 0, 0 },
  580. { IDS_CSIDL_CACHE_L, "Cache", "Cache", "", FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM, 0, 0 },
  581. { IDS_CSIDL_PERSONAL_L, "Personal", "Personal", "*.*", FILE_ATTRIBUTE_DIRECTORY, 0, 1 },
  582. };
  583. const struct FolderDescriptor fdChannels =
  584. { IDS_CSIDL_CHANNELS_L, NULL, "Channel Preservation Key", "*.*", FILE_ATTRIBUTE_DIRECTORY, 0, 0 };
  585. void InitFolderCheckboxes(HWND hDlg, CWizData *pwd)
  586. {
  587. IUser *pUserToClone;
  588. pwd->m_fdwOriginalPerUserFolders = 0;
  589. if (pwd->m_pUserToClone != NULL) {
  590. pUserToClone = pwd->m_pUserToClone;
  591. pUserToClone->AddRef();
  592. }
  593. else {
  594. pwd->m_pDB->GetSpecialUser(GSU_DEFAULT, &pUserToClone);
  595. }
  596. HKEY hkeyUser;
  597. if (pUserToClone != NULL && SUCCEEDED(pUserToClone->LoadProfile(&hkeyUser))) {
  598. HKEY hkeyProfRec, hkeyProfRec2;
  599. if (RegOpenKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\ProfileReconciliation",
  600. 0, KEY_READ, &hkeyProfRec) != ERROR_SUCCESS)
  601. hkeyProfRec = NULL;
  602. if (RegOpenKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\SecondaryProfileReconciliation",
  603. 0, KEY_READ, &hkeyProfRec2) != ERROR_SUCCESS)
  604. hkeyProfRec2 = NULL;
  605. for (UINT iFolder = 0; iFolder < ARRAYSIZE(aFolders); iFolder++) {
  606. HKEY hkeyTemp;
  607. HKEY hkeyParent = aFolders[iFolder].fSecondary ? hkeyProfRec2 : hkeyProfRec;
  608. if (hkeyParent != NULL &&
  609. RegOpenKeyEx(hkeyParent,
  610. aFolders[iFolder].pszStaticName,
  611. 0, KEY_READ, &hkeyTemp) == ERROR_SUCCESS) {
  612. RegCloseKey(hkeyTemp);
  613. pwd->m_fdwOriginalPerUserFolders |= 1 << iFolder;
  614. }
  615. /* else bit is already clear */
  616. }
  617. if (hkeyProfRec != NULL)
  618. RegCloseKey(hkeyProfRec);
  619. if (hkeyProfRec2 != NULL)
  620. RegCloseKey(hkeyProfRec2);
  621. pUserToClone->UnloadProfile(hkeyUser);
  622. }
  623. if (pUserToClone != NULL)
  624. pUserToClone->Release();
  625. CheckDlgButton(hDlg, IDC_CHECK_DESKTOP,
  626. (pwd->m_fdwOriginalPerUserFolders &
  627. (FOLDER_DESKTOP | FOLDER_NETHOOD | FOLDER_RECENT)) ? 1 : 0);
  628. CheckDlgButton(hDlg, IDC_CHECK_STARTMENU,
  629. (pwd->m_fdwOriginalPerUserFolders &
  630. (FOLDER_STARTMENU | FOLDER_PROGRAMS | FOLDER_STARTUP)) ? 1 : 0);
  631. CheckDlgButton(hDlg, IDC_CHECK_FAVORITES,
  632. (pwd->m_fdwOriginalPerUserFolders & FOLDER_FAVORITES) ? 1 : 0);
  633. CheckDlgButton(hDlg, IDC_CHECK_CACHE,
  634. (pwd->m_fdwOriginalPerUserFolders & FOLDER_CACHE) ? 1 : 0);
  635. CheckDlgButton(hDlg, IDC_CHECK_MYDOCS,
  636. (pwd->m_fdwOriginalPerUserFolders & FOLDER_MYDOCS) ? 1 : 0);
  637. }
  638. INT_PTR CALLBACK ChooseFoldersDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  639. {
  640. NMHDR FAR *lpnm;
  641. switch(message)
  642. {
  643. case WM_NOTIFY:
  644. lpnm = (NMHDR FAR *)lParam;
  645. switch(lpnm->code)
  646. {
  647. case PSN_SETACTIVE:
  648. {
  649. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
  650. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  651. InitFolderCheckboxes(hDlg, pwd);
  652. }
  653. break;
  654. case PSN_WIZNEXT:
  655. {
  656. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  657. pwd->m_fdwCloneFromDefault = IsDlgButtonChecked(hDlg, IDC_RADIO_EMPTY) ? 0 : 0xffffffff;
  658. pwd->m_fdwNewPerUserFolders = 0;
  659. if (IsDlgButtonChecked(hDlg, IDC_CHECK_DESKTOP))
  660. pwd->m_fdwNewPerUserFolders |= FOLDER_DESKTOP | FOLDER_NETHOOD | FOLDER_RECENT;
  661. else
  662. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_DESKTOP | FOLDER_NETHOOD | FOLDER_RECENT);
  663. if (IsDlgButtonChecked(hDlg, IDC_CHECK_STARTMENU))
  664. pwd->m_fdwNewPerUserFolders |= FOLDER_STARTMENU | FOLDER_PROGRAMS | FOLDER_STARTUP;
  665. else
  666. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_STARTMENU | FOLDER_PROGRAMS | FOLDER_STARTUP);
  667. if (IsDlgButtonChecked(hDlg, IDC_CHECK_FAVORITES))
  668. pwd->m_fdwNewPerUserFolders |= FOLDER_FAVORITES;
  669. else
  670. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_FAVORITES);
  671. if (IsDlgButtonChecked(hDlg, IDC_CHECK_CACHE))
  672. pwd->m_fdwNewPerUserFolders |= FOLDER_CACHE;
  673. else
  674. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_CACHE);
  675. if (IsDlgButtonChecked(hDlg, IDC_CHECK_MYDOCS))
  676. pwd->m_fdwNewPerUserFolders |= FOLDER_MYDOCS;
  677. else
  678. pwd->m_fdwNewPerUserFolders &= ~(FOLDER_MYDOCS);
  679. pwd->m_idPrevPage = IDD_ChooseFoldersWiz;
  680. GoToPage(hDlg, pwd->m_fGoMultiWizard ? IDD_FinishGoMulti : IDD_FinishAddUser);
  681. }
  682. break;
  683. case PSN_WIZBACK:
  684. {
  685. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  686. GoToPage(hDlg, pwd->m_idPrevPage);
  687. }
  688. break;
  689. default:
  690. return FALSE;
  691. }
  692. break;
  693. case WM_INITDIALOG:
  694. {
  695. InitWizDataPtr(hDlg, lParam);
  696. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  697. CheckRadioButton(hDlg, IDC_RADIO_COPY, IDC_RADIO_EMPTY, IDC_RADIO_COPY);
  698. }
  699. break;
  700. default:
  701. return FALSE;
  702. } // end of switch on message
  703. return TRUE;
  704. }
  705. void GetWindowsRootPath(LPSTR pszBuffer, UINT cchBuffer)
  706. {
  707. GetWindowsDirectory(pszBuffer, cchBuffer);
  708. LPSTR pszEnd = NULL;
  709. if (*pszBuffer == '\\' && *(pszBuffer+1) == '\\') {
  710. pszEnd = ::strchrf(pszBuffer+2, '\\');
  711. if (pszEnd != NULL) {
  712. pszEnd = ::strchrf(pszEnd+1, '\\');
  713. if (pszEnd != NULL)
  714. pszEnd++;
  715. }
  716. }
  717. else {
  718. LPSTR pszNext = CharNext(pszBuffer);
  719. if (*pszNext == ':' && *(pszNext+1) == '\\')
  720. pszEnd = pszNext + 2;
  721. }
  722. if (pszEnd != NULL)
  723. *pszEnd = '\0';
  724. else
  725. AddBackslash(pszBuffer);
  726. }
  727. void AddProfRecKey(HKEY hkeyUser, HKEY hkeyProfRec, const FolderDescriptor *pFolder,
  728. BOOL fCloneFromDefault, LPCSTR pszProfileDir)
  729. {
  730. TCHAR szDefaultPath[MAX_PATH];
  731. if (pFolder->fDefaultInRoot)
  732. GetWindowsRootPath(szDefaultPath, ARRAYSIZE(szDefaultPath));
  733. else
  734. ::strcpyf(szDefaultPath, TEXT("*windir\\"));
  735. LPTSTR pszEnd = szDefaultPath + ::strlenf(szDefaultPath);
  736. LoadString(::hInstance, pFolder->idsDirName,
  737. pszEnd, ARRAYSIZE(szDefaultPath) - (int)(pszEnd - szDefaultPath));
  738. LPTSTR pszLastComponent = ::strrchrf(pszEnd, '\\');
  739. if (pszLastComponent == NULL)
  740. pszLastComponent = pszEnd;
  741. else
  742. pszLastComponent++;
  743. HKEY hSubKey;
  744. LONG err = RegCreateKeyEx(hkeyProfRec, pFolder->pszStaticName, 0, NULL, REG_OPTION_NON_VOLATILE,
  745. KEY_WRITE, NULL, &hSubKey, NULL);
  746. if (err == ERROR_SUCCESS) {
  747. err = RegSetValueEx(hSubKey, "CentralFile", 0, REG_SZ,
  748. (LPBYTE)pszLastComponent, ::strlenf(pszLastComponent)+1);
  749. if (err == ERROR_SUCCESS)
  750. err = RegSetValueEx(hSubKey, "LocalFile", 0, REG_SZ, (LPBYTE)pszEnd,
  751. ::strlenf(pszEnd)+1);
  752. if (err == ERROR_SUCCESS)
  753. err = RegSetValueEx(hSubKey, "Name", 0, REG_SZ, (LPBYTE)pFolder->pszFiles,
  754. ::strlenf(pFolder->pszFiles) + 1);
  755. if (fCloneFromDefault && err == ERROR_SUCCESS)
  756. err = RegSetValueEx(hSubKey, "DefaultDir", 0, REG_SZ, (LPBYTE)szDefaultPath,
  757. ::strlenf(szDefaultPath) + 1);
  758. DWORD dwOne = 1;
  759. if (err == ERROR_SUCCESS)
  760. err = RegSetValueEx(hSubKey, "MustBeRelative", 0, REG_DWORD, (LPBYTE)&dwOne,
  761. sizeof(dwOne));
  762. if (fCloneFromDefault && err == ERROR_SUCCESS)
  763. err = RegSetValueEx(hSubKey, "Default", 0, REG_DWORD, (LPBYTE)&dwOne,
  764. sizeof(dwOne));
  765. if (pFolder->pszRegValue != NULL) {
  766. if (err == ERROR_SUCCESS)
  767. err = RegSetValueEx(hSubKey, "RegKey", 0, REG_SZ, (LPBYTE)c_szExplorerUSFKey,
  768. ::strlenf(c_szExplorerUSFKey) + 1);
  769. if (err == ERROR_SUCCESS)
  770. err = RegSetValueEx(hSubKey, "RegValue", 0, REG_SZ, (LPBYTE)pFolder->pszRegValue,
  771. ::strlenf(pFolder->pszRegValue) + 1);
  772. }
  773. if (err == ERROR_SUCCESS && pFolder->fSecondary) {
  774. err = RegSetValueEx(hSubKey, "ParentKey", 0, REG_SZ, (LPBYTE)"Start Menu", 11);
  775. }
  776. RegCloseKey(hSubKey);
  777. }
  778. /* And if we're not adding a clone-from-default profrec key, we know that
  779. * no profile code is going to create the directory, so we'd better do it
  780. * ourselves, and set the path in the registry.
  781. */
  782. if (!fCloneFromDefault) {
  783. NLS_STR nlsTemp(MAX_PATH);
  784. if (nlsTemp.QueryError() == ERROR_SUCCESS) {
  785. nlsTemp = pszProfileDir;
  786. AddBackslash(nlsTemp);
  787. nlsTemp.strcat(pszEnd);
  788. HKEY hkeyExplorer;
  789. if (RegOpenKeyEx(hkeyUser, c_szExplorerSFKey, 0,
  790. KEY_READ | KEY_WRITE, &hkeyExplorer) == ERROR_SUCCESS) {
  791. RegSetValueEx(hkeyExplorer, pFolder->pszRegValue,
  792. 0, REG_SZ, (LPBYTE)nlsTemp.QueryPch(),
  793. nlsTemp.strlen()+1);
  794. RegCloseKey(hkeyExplorer);
  795. }
  796. if (RegOpenKeyEx(hkeyUser, c_szExplorerUSFKey, 0,
  797. KEY_READ | KEY_WRITE, &hkeyExplorer) == ERROR_SUCCESS) {
  798. RegSetValueEx(hkeyExplorer, pFolder->pszRegValue,
  799. 0, REG_SZ, (LPBYTE)nlsTemp.QueryPch(),
  800. nlsTemp.strlen()+1);
  801. RegCloseKey(hkeyExplorer);
  802. }
  803. CreateDirectoryPath(nlsTemp.QueryPch());
  804. }
  805. }
  806. }
  807. /* CWizData::PreInitProfile is called back by IUserDatabase::Install or
  808. * ::AddUser after the new user's profile has been created but before
  809. * directory reconciliation takes place. This is our chance to add
  810. * roaming keys for any folders that we want to be per-user and initialized
  811. * from the defaults, and remove roaming keys for other folders we know about.
  812. */
  813. STDMETHODIMP CWizData::PreInitProfile(HKEY hkeyUser, LPCSTR pszProfileDir)
  814. {
  815. HKEY hkeyProfRec, hkeyProfRec2;
  816. DWORD dwDisp;
  817. if (RegCreateKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\ProfileReconciliation",
  818. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  819. NULL, &hkeyProfRec, &dwDisp) != ERROR_SUCCESS)
  820. hkeyProfRec = NULL;
  821. if (RegCreateKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\SecondaryProfileReconciliation",
  822. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  823. NULL, &hkeyProfRec2, &dwDisp) != ERROR_SUCCESS)
  824. hkeyProfRec2 = NULL;
  825. m_fChannelHack = FALSE;
  826. DWORD fdwFlag = 1;
  827. for (UINT iFolder = 0;
  828. iFolder < ARRAYSIZE(aFolders);
  829. iFolder++, fdwFlag <<= 1) {
  830. BOOL fWasPerUser = (m_fdwOriginalPerUserFolders & fdwFlag);
  831. BOOL fMakePerUser = (m_fdwNewPerUserFolders & fdwFlag);
  832. BOOL fCloneFromDefault = (m_fdwCloneFromDefault & fdwFlag);
  833. /* If the folder was shared and is staying that way, do nothing. */
  834. if (!fWasPerUser && !fMakePerUser)
  835. continue;
  836. /* If the folder was per-user and is staying that way, do nothing,
  837. * UNLESS we're creating a new profile and the user chose the start-
  838. * out-empty option. In that case we want to make sure to kill the
  839. * profrec keys until PostInitProfile.
  840. */
  841. if (fWasPerUser && fMakePerUser && (!m_fCreatingProfile || fCloneFromDefault))
  842. continue;
  843. HKEY hkeyParent = aFolders[iFolder].fSecondary ? hkeyProfRec2 : hkeyProfRec;
  844. /* If the user is making a folder per-user when it wasn't, and they
  845. * want this folder cloned from the default, add a profrec key now.
  846. */
  847. if (fMakePerUser && fCloneFromDefault) {
  848. AddProfRecKey(hkeyUser, hkeyParent, &aFolders[iFolder], TRUE, pszProfileDir);
  849. }
  850. /* If the user is making a folder shared, or they want this per-user
  851. * folder to start out empty, delete the profrec key now. In the
  852. * latter case, we will add it for roaming purposes during
  853. * PostInitProfile.
  854. */
  855. if (!fMakePerUser || !fCloneFromDefault) {
  856. RegDeleteKey(hkeyParent, aFolders[iFolder].pszStaticName);
  857. /* If we're making a folder shared and we're not cloning the
  858. * default profile, then the profile has a per-user directory
  859. * path in it which we need to clear out.
  860. *
  861. * We know that we need to delete the value from User Shell Folders,
  862. * and set the default path under Shell Folders.
  863. */
  864. if (!fMakePerUser && m_pUserToClone != NULL) {
  865. TCHAR szDefaultPath[MAX_PATH+1];
  866. if (aFolders[iFolder].fDefaultInRoot) {
  867. GetWindowsRootPath(szDefaultPath, ARRAYSIZE(szDefaultPath));
  868. }
  869. else {
  870. GetWindowsDirectory(szDefaultPath, ARRAYSIZE(szDefaultPath));
  871. AddBackslash(szDefaultPath);
  872. }
  873. LPTSTR pszEnd = szDefaultPath + ::strlenf(szDefaultPath);
  874. LoadString(::hInstance, aFolders[iFolder].idsDirName,
  875. pszEnd, ARRAYSIZE(szDefaultPath) - (int)(pszEnd - szDefaultPath));
  876. HKEY hkeyExplorer;
  877. if (RegOpenKeyEx(hkeyUser, c_szExplorerUSFKey, 0,
  878. KEY_READ | KEY_WRITE, &hkeyExplorer) == ERROR_SUCCESS) {
  879. if (aFolders[iFolder].fDefaultInRoot) {
  880. RegSetValueEx(hkeyExplorer, aFolders[iFolder].pszRegValue,
  881. 0, REG_SZ, (LPBYTE)szDefaultPath,
  882. ::strlenf(szDefaultPath)+1);
  883. }
  884. else {
  885. RegDeleteValue(hkeyExplorer, aFolders[iFolder].pszRegValue);
  886. }
  887. RegCloseKey(hkeyExplorer);
  888. }
  889. if (RegOpenKeyEx(hkeyUser, c_szExplorerSFKey, 0,
  890. KEY_READ | KEY_WRITE, &hkeyExplorer) == ERROR_SUCCESS) {
  891. RegSetValueEx(hkeyExplorer, aFolders[iFolder].pszRegValue,
  892. 0, REG_SZ, (LPBYTE)szDefaultPath,
  893. ::strlenf(szDefaultPath)+1);
  894. RegCloseKey(hkeyExplorer);
  895. }
  896. }
  897. }
  898. /* Special code for start-out-empty folders: Some of them need to
  899. * start out with certain crucial files, not totally empty.
  900. */
  901. if (fMakePerUser &&
  902. (!fWasPerUser || m_fCreatingProfile) &&
  903. !fCloneFromDefault) {
  904. /* Special hack for channels: If the user wants Favorites to be per-user,
  905. * but chooses to start it out empty, they get no channels either, because
  906. * Channels is a subdirectory of Favorites. So, for that case only,
  907. * we force in a clone-from-default profrec key for Channels, which we'll
  908. * delete in PostInit.
  909. */
  910. if (fdwFlag == FOLDER_FAVORITES) {
  911. AddProfRecKey(hkeyUser, hkeyProfRec, &fdChannels, TRUE, pszProfileDir);
  912. m_fChannelHack = TRUE;
  913. }
  914. }
  915. }
  916. if (hkeyProfRec != NULL)
  917. RegCloseKey(hkeyProfRec);
  918. if (hkeyProfRec2 != NULL)
  919. RegCloseKey(hkeyProfRec2);
  920. return S_OK;
  921. }
  922. /* CWizData::PostInitProfile is called by IUserDatabase::Install or ::AddUser
  923. * after the user's folders have all been created and initialized. Here we
  924. * add profrec keys for any folders which we want to be per-user but don't
  925. * want initialized from the default.
  926. */
  927. STDMETHODIMP CWizData::PostInitProfile(HKEY hkeyUser, LPCSTR pszProfileDir)
  928. {
  929. HKEY hkeyProfRec, hkeyProfRec2;
  930. DWORD dwDisp;
  931. if (RegCreateKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\ProfileReconciliation",
  932. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  933. NULL, &hkeyProfRec, &dwDisp) != ERROR_SUCCESS)
  934. hkeyProfRec = NULL;
  935. if (RegCreateKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\SecondaryProfileReconciliation",
  936. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  937. NULL, &hkeyProfRec2, &dwDisp) != ERROR_SUCCESS)
  938. hkeyProfRec2 = NULL;
  939. DWORD fdwFlag = 1;
  940. for (UINT iFolder = 0;
  941. iFolder < ARRAYSIZE(aFolders);
  942. iFolder++, fdwFlag <<= 1) {
  943. HKEY hkeyParent = aFolders[iFolder].fSecondary ? hkeyProfRec2 : hkeyProfRec;
  944. if (m_fdwNewPerUserFolders & fdwFlag) {
  945. /* If the user is making a folder per-user when it wasn't or making a
  946. * folder per-user in a new profile, and they want this folder to start
  947. * out empty, add a profrec key now.
  948. */
  949. if ((!(m_fdwOriginalPerUserFolders & fdwFlag) || m_fCreatingProfile) &&
  950. !(m_fdwCloneFromDefault & fdwFlag)) {
  951. AddProfRecKey(hkeyUser, hkeyParent, &aFolders[iFolder], FALSE, pszProfileDir);
  952. }
  953. /* If the folder is per-user and is supposed to have special
  954. * attributes, make sure it has them.
  955. */
  956. if (aFolders[iFolder].dwAttribs != FILE_ATTRIBUTE_DIRECTORY) {
  957. RegEntry re(aFolders[iFolder].pszStaticName, hkeyParent);
  958. NLS_STR nlsTemp(MAX_PATH);
  959. if (re.GetError() == ERROR_SUCCESS && nlsTemp.QueryError() == ERROR_SUCCESS) {
  960. GetSetRegistryPath(hkeyUser, re, &nlsTemp, FALSE);
  961. if (nlsTemp.strlen()) {
  962. ::SetFileAttributes(nlsTemp.QueryPch(), aFolders[iFolder].dwAttribs);
  963. }
  964. }
  965. }
  966. }
  967. }
  968. /* If we added a hack for channels, undo that hack now that we're done
  969. * initializing the profile.
  970. */
  971. if (m_fChannelHack)
  972. RegDeleteKey(hkeyProfRec, fdChannels.pszStaticName);
  973. if (hkeyProfRec != NULL)
  974. RegCloseKey(hkeyProfRec);
  975. if (hkeyProfRec2 != NULL)
  976. RegCloseKey(hkeyProfRec2);
  977. return S_OK;
  978. }
  979. /* Following is actually for the CPL version of the choose-folders dialog */
  980. HRESULT ChooseFoldersProgressFunc(LPARAM lParam)
  981. {
  982. CWizData *pwd = (CWizData *)lParam;
  983. HKEY hkeyUser;
  984. if (pwd->m_pUserToClone != NULL &&
  985. SUCCEEDED(pwd->m_pUserToClone->LoadProfile(&hkeyUser))) {
  986. TCHAR szProfileDir[MAX_PATH];
  987. DWORD cbBuffer = sizeof(szProfileDir);
  988. pwd->m_pUserToClone->GetProfileDirectory(szProfileDir, &cbBuffer);
  989. pwd->PreInitProfile(hkeyUser, szProfileDir);
  990. NLS_STR nlsPath(szProfileDir);
  991. AddBackslash(nlsPath);
  992. DWORD fdwFlag = 1;
  993. for (UINT iFolder = 0;
  994. iFolder < ARRAYSIZE(aFolders);
  995. iFolder++, fdwFlag <<= 1) {
  996. /* Do reconciliation if we want to per-user-ize a folder that
  997. * wasn't per-user before and we want to clone it from default.
  998. */
  999. if (!(pwd->m_fdwOriginalPerUserFolders & fdwFlag) &&
  1000. (pwd->m_fdwNewPerUserFolders & fdwFlag) &&
  1001. (pwd->m_fdwCloneFromDefault & fdwFlag)) {
  1002. DefaultReconcileKey(hkeyUser, nlsPath,
  1003. aFolders[iFolder].pszStaticName,
  1004. aFolders[iFolder].fSecondary);
  1005. }
  1006. }
  1007. /* Process the initialization hack for Channels, if it exists. */
  1008. if (pwd->m_fChannelHack)
  1009. DefaultReconcileKey(hkeyUser, nlsPath, fdChannels.pszStaticName,
  1010. fdChannels.fSecondary);
  1011. pwd->PostInitProfile(hkeyUser, szProfileDir);
  1012. pwd->m_pUserToClone->UnloadProfile(hkeyUser);
  1013. SHFlushSFCache();
  1014. return S_OK;
  1015. }
  1016. return E_FAIL;
  1017. }
  1018. void FinishChooseFolders(HWND hDlg, CWizData *pwd)
  1019. {
  1020. if (SUCCEEDED(CallWithinProgressDialog(hDlg, IDD_CreateProgress,
  1021. ChooseFoldersProgressFunc, (LPARAM)pwd)))
  1022. EndDialog(hDlg, TRUE);
  1023. }
  1024. HRESULT InstallProgressFunc(LPARAM lParam)
  1025. {
  1026. CWizData *pwd = (CWizData *)lParam;
  1027. return pwd->m_pDB->Install(pwd->m_nlsUsername.QueryPch(),
  1028. pwd->m_nlsUserPassword.QueryPch(),
  1029. pwd->m_nlsSupervisorPassword.QueryPch(),
  1030. pwd);
  1031. }
  1032. BOOL FinishGoMulti(HWND hDlg, CWizData *pwd)
  1033. {
  1034. DWORD dwExitCode = 0xffffffff; /* not a valid EWX_ value */
  1035. /* If user profiles aren't enabled, enable them. Using them requires
  1036. * logging off.
  1037. */
  1038. if (!UseUserProfiles()) {
  1039. dwExitCode = EWX_LOGOFF;
  1040. EnableProfiles();
  1041. }
  1042. /* If there is no primary logon provider, install our logon dialog as
  1043. * the primary. Using this requires rebooting the system.
  1044. */
  1045. if (InstallLogonDialog()) {
  1046. dwExitCode = EWX_REBOOT;
  1047. }
  1048. pwd->m_nlsUserPassword.strupr();
  1049. HRESULT hres = CallWithinProgressDialog(hDlg, IDD_CreateProgress,
  1050. InstallProgressFunc, (LPARAM)pwd);
  1051. if (SUCCEEDED(hres)) {
  1052. /* Set the new username as the default one to log on as. */
  1053. HKEY hkeyLogon;
  1054. if (OpenLogonKey(&hkeyLogon) == ERROR_SUCCESS) {
  1055. pwd->m_nlsUsername.ToOEM();
  1056. RegSetValueEx(hkeyLogon, ::szUsername, 0, REG_SZ,
  1057. (LPBYTE)pwd->m_nlsUsername.QueryPch(),
  1058. pwd->m_nlsUsername.strlen() + 1);
  1059. pwd->m_nlsUsername.ToAnsi();
  1060. RegCloseKey(hkeyLogon);
  1061. }
  1062. if ((dwExitCode != 0xffffffff) &&
  1063. MsgBox(hDlg, IDS_GO_MULTI_RESTART, MB_YESNO | MB_ICONQUESTION) == IDYES) {
  1064. ::ExitWindowsEx(dwExitCode, 0);
  1065. ::ExitProcess(0);
  1066. }
  1067. return TRUE;
  1068. }
  1069. ReportUserError(hDlg, hres);
  1070. return FALSE;
  1071. }
  1072. HRESULT AddUserProgressFunc(LPARAM lParam)
  1073. {
  1074. CWizData *pwd = (CWizData *)lParam;
  1075. return pwd->m_pDB->AddUser(pwd->m_nlsUsername.QueryPch(),
  1076. pwd->m_pUserToClone, pwd, &pwd->m_pNewUser);
  1077. }
  1078. BOOL FinishAddUser(HWND hDlg, CWizData *pwd)
  1079. {
  1080. pwd->m_nlsUserPassword.strupr();
  1081. pwd->m_pNewUser = NULL;
  1082. HRESULT hres = CallWithinProgressDialog(hDlg, IDD_CreateProgress,
  1083. AddUserProgressFunc, (LPARAM)pwd);
  1084. if (SUCCEEDED(hres)) {
  1085. hres = pwd->m_pNewUser->ChangePassword(szNULL, pwd->m_nlsUserPassword.QueryPch());
  1086. pwd->m_pNewUser->Release();
  1087. pwd->m_pNewUser = NULL;
  1088. }
  1089. else {
  1090. ReportUserError(hDlg, hres);
  1091. }
  1092. return SUCCEEDED(hres);
  1093. }
  1094. INT_PTR CALLBACK FinishDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1095. {
  1096. NMHDR FAR *lpnm;
  1097. switch(message)
  1098. {
  1099. case WM_NOTIFY:
  1100. lpnm = (NMHDR FAR *)lParam;
  1101. switch(lpnm->code)
  1102. {
  1103. case PSN_SETACTIVE:
  1104. {
  1105. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
  1106. }
  1107. break;
  1108. case PSN_WIZFINISH:
  1109. {
  1110. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  1111. BOOL fOK = pwd->m_fGoMultiWizard ? FinishGoMulti(hDlg, pwd) : FinishAddUser(hDlg, pwd);
  1112. if (!fOK)
  1113. FailChangePage(hDlg);
  1114. else
  1115. return FALSE; /* destroy wizard */
  1116. }
  1117. break;
  1118. case PSN_WIZBACK:
  1119. {
  1120. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  1121. GoToPage(hDlg, pwd->m_idPrevPage);
  1122. }
  1123. break;
  1124. default:
  1125. return FALSE;
  1126. }
  1127. break;
  1128. case WM_INITDIALOG:
  1129. {
  1130. InitWizDataPtr(hDlg, lParam);
  1131. CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER);
  1132. if (!pwd->m_fGoMultiWizard) {
  1133. InsertControlText(hDlg, IDC_MAIN_CAPTION, &pwd->m_nlsUsername);
  1134. InsertControlText(hDlg, IDC_MAIN_CAPTION2, &pwd->m_nlsUsername);
  1135. }
  1136. }
  1137. break;
  1138. default:
  1139. return FALSE;
  1140. } // end of switch on message
  1141. return TRUE;
  1142. }
  1143. STDMETHODIMP CLUDatabase::InstallWizard(HWND hwndParent)
  1144. {
  1145. #if 0
  1146. if (UseUserProfiles()) {
  1147. MsgBox(hwndParent, IDS_PROFILES_ALREADY_ENABLED, MB_OK | MB_ICONINFORMATION);
  1148. return E_FAIL;
  1149. }
  1150. #endif
  1151. if (ProfileUIRestricted()) {
  1152. ReportRestrictionError(hwndParent);
  1153. return E_ACCESSDENIED;
  1154. }
  1155. CWizData wd;
  1156. wd.m_hresRatings = VerifySupervisorPassword(szNULL);
  1157. wd.m_fGoMultiWizard = TRUE;
  1158. wd.m_pDB = this;
  1159. AddRef(); /* just in case */
  1160. wd.m_pUserToClone = NULL;
  1161. LPPROPSHEETHEADER ppsh;
  1162. // Allocate the property sheet header
  1163. //
  1164. if ((ppsh = (LPPROPSHEETHEADER)LocalAlloc(LMEM_FIXED, sizeof(PROPSHEETHEADER)+
  1165. (MAX_WIZ_PAGES * sizeof(HPROPSHEETPAGE)))) != NULL)
  1166. {
  1167. ppsh->dwSize = sizeof(*ppsh);
  1168. ppsh->dwFlags = PSH_WIZARD;
  1169. ppsh->hwndParent = hwndParent;
  1170. ppsh->hInstance = ::hInstance;
  1171. ppsh->pszCaption = NULL;
  1172. ppsh->nPages = 0;
  1173. ppsh->nStartPage = 0;
  1174. ppsh->phpage = (HPROPSHEETPAGE *)(ppsh+1);
  1175. /* Add the pages for the wizard. Note that we have two pages to
  1176. * prompt for the user's account password -- one to enter, the other
  1177. * to enter and confirm. The code in EnterUsernameDlgProc jumps to
  1178. * the right password page depending on whether the user has a PWL.
  1179. * The code in NewPasswordDlgProc knows to jump ahead to the finish
  1180. * page.
  1181. *
  1182. * If you add more pages here, be sure to update the code as necessary
  1183. * so the sequence is correct.
  1184. */
  1185. AddPage(ppsh, IDD_EnableProfilesIntro, IntroDlgProc, &wd);
  1186. if (wd.m_hresRatings == S_FALSE)
  1187. AddPage(ppsh, IDD_EnterCAPassword, EnterCAPWDlgProc, &wd);
  1188. AddPage(ppsh, IDD_EnterUsername, EnterUsernameDlgProc, &wd);
  1189. AddPage(ppsh, IDD_NewUserPassword, NewPasswordDlgProc, &wd);
  1190. AddPage(ppsh, IDD_EnterUserPassword, EnterUserPWDlgProc, &wd);
  1191. AddPage(ppsh, IDD_ChooseFoldersWiz, ChooseFoldersDlgProc, &wd);
  1192. AddPage(ppsh, IDD_FinishGoMulti, FinishDlgProc, &wd);
  1193. PropertySheet(ppsh);
  1194. LocalFree((HLOCAL)ppsh);
  1195. }
  1196. Release(); /* undo above AddRef() */
  1197. return S_OK;
  1198. }
  1199. HRESULT DoAddUserWizard(HWND hwndParent, IUserDatabase *pDB,
  1200. BOOL fPickUserPage, IUser *pUserToClone)
  1201. {
  1202. CWizData wd;
  1203. wd.m_hresRatings = VerifySupervisorPassword(szNULL);
  1204. wd.m_fGoMultiWizard = FALSE;
  1205. wd.m_pDB = pDB;
  1206. pDB->AddRef(); /* just in case */
  1207. wd.m_pUserToClone = pUserToClone;
  1208. if (wd.m_pUserToClone != NULL)
  1209. wd.m_pUserToClone->AddRef();
  1210. LPPROPSHEETHEADER ppsh;
  1211. // Allocate the property sheet header
  1212. //
  1213. if ((ppsh = (LPPROPSHEETHEADER)LocalAlloc(LMEM_FIXED, sizeof(PROPSHEETHEADER)+
  1214. (MAX_WIZ_PAGES * sizeof(HPROPSHEETPAGE)))) != NULL)
  1215. {
  1216. ppsh->dwSize = sizeof(*ppsh);
  1217. ppsh->dwFlags = PSH_WIZARD;
  1218. ppsh->hwndParent = hwndParent;
  1219. ppsh->hInstance = ::hInstance;
  1220. ppsh->pszCaption = NULL;
  1221. ppsh->nPages = 0;
  1222. ppsh->nStartPage = 0;
  1223. ppsh->phpage = (HPROPSHEETPAGE *)(ppsh+1);
  1224. AddPage(ppsh, IDD_AddUserIntro, IntroDlgProc, &wd);
  1225. if (IsCurrentUserSupervisor(pDB) != S_OK)
  1226. {
  1227. AddPage(ppsh, IDD_EnterCAPassword, EnterCAPWDlgProc, &wd);
  1228. }
  1229. if (fPickUserPage)
  1230. AddPage(ppsh, IDD_PickUser, PickUserDlgProc, &wd);
  1231. AddPage(ppsh, IDD_EnterUsername, EnterUsernameDlgProc, &wd);
  1232. AddPage(ppsh, IDD_NewUserPassword, NewPasswordDlgProc, &wd);
  1233. AddPage(ppsh, IDD_EnterUserPassword, EnterUserPWDlgProc, &wd);
  1234. AddPage(ppsh, IDD_ChooseFoldersWiz, ChooseFoldersDlgProc, &wd);
  1235. AddPage(ppsh, IDD_FinishAddUser, FinishDlgProc, &wd);
  1236. PropertySheet(ppsh);
  1237. LocalFree((HLOCAL)ppsh);
  1238. }
  1239. pDB->Release(); /* undo above AddRef() */
  1240. return S_OK;
  1241. }
  1242. STDMETHODIMP CLUDatabase::AddUserWizard(HWND hwndParent)
  1243. {
  1244. if (ProfileUIRestricted()) {
  1245. ReportRestrictionError(hwndParent);
  1246. return E_ACCESSDENIED;
  1247. }
  1248. return DoAddUserWizard(hwndParent, this, TRUE, NULL);
  1249. }
  1250. extern "C" void InstallWizard(HWND hwndParent, HINSTANCE hinstEXE, LPSTR pszCmdLine, int nCmdShow)
  1251. {
  1252. IUserDatabase *pDB;
  1253. if (SUCCEEDED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) {
  1254. pDB->InstallWizard(hwndParent);
  1255. pDB->Release();
  1256. }
  1257. }
  1258. extern "C" void AddUserWizard(HWND hwndParent, HINSTANCE hinstEXE, LPSTR pszCmdLine, int nCmdShow)
  1259. {
  1260. IUserDatabase *pDB;
  1261. if (SUCCEEDED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) {
  1262. pDB->AddUserWizard(hwndParent);
  1263. pDB->Release();
  1264. }
  1265. }
  1266. struct ProgressDlgData
  1267. {
  1268. PFNPROGRESS pfn;
  1269. LPARAM lParam;
  1270. HRESULT hres;
  1271. };
  1272. void CallProgressFunc(HWND hDlg)
  1273. {
  1274. ProgressDlgData *ppdd = (ProgressDlgData *)GetWindowLongPtr(hDlg, DWLP_USER);
  1275. ppdd->hres = ppdd->pfn(ppdd->lParam);
  1276. EndDialog(hDlg, FALSE);
  1277. }
  1278. const UINT WM_CALL_FUNC = WM_USER + 100;
  1279. INT_PTR CALLBACK ProgressDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1280. {
  1281. switch(message)
  1282. {
  1283. case WM_INITDIALOG:
  1284. {
  1285. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1286. /* Defer function call to a posted message so the dialog manager
  1287. * will show our dialog.
  1288. *
  1289. * If PostMessage fails, at least still call the function anyway.
  1290. */
  1291. if (!PostMessage(hDlg, WM_CALL_FUNC, 0, 0)) {
  1292. CallProgressFunc(hDlg);
  1293. }
  1294. }
  1295. return TRUE; /* we didn't set the focus */
  1296. case WM_CALL_FUNC:
  1297. CallProgressFunc(hDlg);
  1298. break;
  1299. default:
  1300. return FALSE;
  1301. }
  1302. return TRUE;
  1303. }
  1304. HRESULT CallWithinProgressDialog(HWND hwndOwner, UINT idResource, PFNPROGRESS pfn,
  1305. LPARAM lParam)
  1306. {
  1307. ProgressDlgData pdd = { pfn, lParam, E_FAIL };
  1308. DialogBoxParam(::hInstance, MAKEINTRESOURCE(idResource), hwndOwner,
  1309. ProgressDlgProc, (LPARAM)&pdd);
  1310. return pdd.hres;
  1311. }
  1312. BOOL ProfileUIRestricted(void)
  1313. {
  1314. RegEntry rePolicy("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System");
  1315. if (rePolicy.GetError() == ERROR_SUCCESS) {
  1316. if (rePolicy.GetNumber("NoProfilePage") != 0)
  1317. return TRUE;
  1318. }
  1319. return FALSE;
  1320. }
  1321. void ReportRestrictionError(HWND hwndOwner)
  1322. {
  1323. MsgBox(hwndOwner, IDS_PROFILE_POLICY, MB_OK | MB_ICONSTOP);
  1324. }