#include "mslocusr.h" #include "msluglob.h" #include "resource.h" #include #include "profiles.h" #include extern "C" void SHFlushSFCache(void); void ReportUserError(HWND hwndParent, HRESULT hres) { if (SUCCEEDED(hres)) return; UINT idMsg; NLS_STR nlsSub(16); /* long enough for any 32-bit number, any format */ if ((((DWORD)hres) >> 16) == (FACILITY_WIN32 | 0x8000)) { UINT err = (hres & 0xffff); switch (err) { case ERROR_ACCESS_DENIED: idMsg = IDS_E_ACCESSDENIED; break; case ERROR_NOT_AUTHENTICATED: idMsg = IDS_ERROR_NOT_AUTHENTICATED; break; case ERROR_NO_SUCH_USER: idMsg = IDS_ERROR_NO_SUCH_USER; break; case ERROR_USER_EXISTS: idMsg = IDS_ERROR_USER_EXISTS; break; case ERROR_NOT_ENOUGH_MEMORY: idMsg = IDS_ERROR_OUT_OF_MEMORY; break; case ERROR_BUSY: idMsg = IDS_ERROR_BUSY; break; case ERROR_PATH_NOT_FOUND: idMsg = IDS_ERROR_PATH_NOT_FOUND; break; case ERROR_BUFFER_OVERFLOW: idMsg = IDS_ERROR_BUFFER_OVERFLOW; break; case IERR_CachingDisabled: idMsg = IDS_IERR_CachingDisabled; break; case IERR_BadSig: idMsg = IDS_IERR_BadSig; break; case IERR_CacheReadOnly : idMsg = IDS_IERR_CacheReadOnly; break; case IERR_IncorrectUsername: idMsg = IDS_IERR_IncorrectUsername; break; case IERR_CacheCorrupt: idMsg = IDS_IERR_CacheCorrupt; break; case IERR_UsernameNotFound: idMsg = IDS_IERR_UsernameNotFound; break; case IERR_CacheFull: idMsg = IDS_IERR_CacheFull; break; case IERR_CacheAlreadyOpen: idMsg = IDS_IERR_CacheAlreadyOpen; break; default: idMsg = IDS_UNKNOWN_ERROR; wsprintf(nlsSub.Party(), "%d", err); nlsSub.DonePartying(); break; } } else { switch(hres) { case E_OUTOFMEMORY: idMsg = IDS_ERROR_OUT_OF_MEMORY; break; // case E_ACCESSDENIED: idMsg = IDS_E_ACCESSDENIED; break; default: idMsg = IDS_UNKNOWN_ERROR; wsprintf(nlsSub.Party(), "0x%x", hres); nlsSub.DonePartying(); break; } } const NLS_STR *apnls[] = { &nlsSub, NULL }; MsgBox(hwndParent, idMsg, MB_OK | MB_ICONSTOP, apnls); } const UINT MAX_WIZ_PAGES = 8; #if 0 /* now in mslocusr.h */ class CWizData : public IUserProfileInit { public: HRESULT m_hresRatings; /* result of VerifySupervisorPassword("") */ BOOL m_fGoMultiWizard; /* TRUE if this is the big go-multiuser wizard */ NLS_STR m_nlsSupervisorPassword; NLS_STR m_nlsUsername; NLS_STR m_nlsUserPassword; IUserDatabase *m_pDB; IUser *m_pUserToClone; int m_idPrevPage; /* ID of page before Finish */ UINT m_cRef; DWORD m_fdwOriginalPerUserFolders; DWORD m_fdwNewPerUserFolders; DWORD m_fdwCloneFromDefault; BOOL m_fCreatingProfile; CWizData(); ~CWizData(); // *** IUnknown methods *** STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); STDMETHODIMP PreInitProfile(HKEY hkeyUser, LPCSTR pszProfileDir); STDMETHODIMP PostInitProfile(HKEY hkeyUser, LPCSTR pszProfileDir); }; #endif CWizData::CWizData() : m_nlsSupervisorPassword(), m_nlsUsername(), m_nlsUserPassword(), m_cRef(0), m_fdwOriginalPerUserFolders(0), m_fdwNewPerUserFolders(0), m_fdwCloneFromDefault(0), m_fCreatingProfile(FALSE) { } CWizData::~CWizData() { if (m_pUserToClone != NULL) m_pUserToClone->Release(); } STDMETHODIMP CWizData::QueryInterface(REFIID riid, LPVOID * ppvObj) { if (!IsEqualIID(riid, IID_IUnknown) && !IsEqualIID(riid, IID_IUserProfileInit)) { *ppvObj = NULL; return ResultFromScode(E_NOINTERFACE); } *ppvObj = this; AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CWizData::AddRef(void) { return ++m_cRef; } STDMETHODIMP_(ULONG) CWizData::Release(void) { ULONG cRef; cRef = --m_cRef; if (0L == m_cRef) { delete this; } return cRef; } void LimitCredentialLength(HWND hDlg, UINT idCtrl) { SendDlgItemMessage(hDlg, idCtrl, EM_LIMITTEXT, (WPARAM)cchMaxUsername, 0); } void AddPage(LPPROPSHEETHEADER ppsh, UINT id, DLGPROC pfn, LPVOID pwd) { if (ppsh->nPages < MAX_WIZ_PAGES) { PROPSHEETPAGE psp; psp.dwSize = sizeof(psp); psp.dwFlags = PSP_DEFAULT; psp.hInstance = ::hInstance; psp.pszTemplate = MAKEINTRESOURCE(id); psp.pfnDlgProc = pfn; psp.lParam = (LPARAM)pwd; ppsh->phpage[ppsh->nPages] = CreatePropertySheetPage(&psp); if (ppsh->phpage[ppsh->nPages]) ppsh->nPages++; } } // AddPage INT_PTR CALLBACK IntroDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm; switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_SETACTIVE: { PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT); break; } default: return FALSE; } break; default: return FALSE; } // end of switch on message return TRUE; } void GoToPage(HWND hDlg, int idPage) { SetWindowLongPtr(hDlg, DWLP_MSGRESULT, idPage); } inline void FailChangePage(HWND hDlg) { GoToPage(hDlg, -1); } void InitWizDataPtr(HWND hDlg, LPARAM lParam) { CWizData *pwd = (CWizData *)(((LPPROPSHEETPAGE)lParam)->lParam); SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)pwd); } void InsertControlText(HWND hDlg, UINT idCtrl, const NLS_STR *pnlsInsert) { int cchText = GetWindowTextLength(GetDlgItem(hDlg, IDC_MAIN_CAPTION)) + pnlsInsert->strlen() + 1; NLS_STR nlsTemp(MAX_RES_STR_LEN); if (nlsTemp.QueryError() == ERROR_SUCCESS) { GetDlgItemText(hDlg, idCtrl, nlsTemp.Party(), nlsTemp.QueryAllocSize()); nlsTemp.DonePartying(); const NLS_STR *apnls[] = { pnlsInsert, NULL }; nlsTemp.InsertParams(apnls); if (nlsTemp.QueryError() == ERROR_SUCCESS) SetDlgItemText(hDlg, idCtrl, nlsTemp.QueryPch()); } } HRESULT GetControlText(HWND hDlg, UINT idCtrl, NLS_STR *pnls) { HWND hCtrl = GetDlgItem(hDlg, idCtrl); if (pnls->realloc(GetWindowTextLength(hCtrl) + 1)) { GetWindowText(hCtrl, pnls->Party(), pnls->QueryAllocSize()); pnls->DonePartying(); return NOERROR; } return E_OUTOFMEMORY; } INT_PTR CALLBACK EnterCAPWDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm; switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT); break; case PSN_WIZNEXT: { CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); if (SUCCEEDED(GetControlText(hDlg, IDC_PASSWORD, &pwd->m_nlsSupervisorPassword))) { if (VerifySupervisorPassword(pwd->m_nlsSupervisorPassword.QueryPch()) == S_FALSE) { MsgBox(hDlg, IDS_BADPASSWORD, MB_OK | MB_ICONSTOP); SetErrorFocus(hDlg, IDC_PASSWORD); FailChangePage(hDlg); } } } break; default: return FALSE; } break; case WM_INITDIALOG: InitWizDataPtr(hDlg, lParam); break; default: return FALSE; } // end of switch on message return TRUE; } INT_PTR CALLBACK EnterUserPWDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm; switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_SETACTIVE: { PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT); } break; case PSN_WIZNEXT: { CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); if (SUCCEEDED(GetControlText(hDlg, IDC_PASSWORD, &pwd->m_nlsUserPassword))) { HANDLE hPWL = NULL; if (FAILED(::GetUserPasswordCache(pwd->m_nlsUsername.QueryPch(), pwd->m_nlsUserPassword.QueryPch(), &hPWL, TRUE))) { MsgBox(hDlg, IDS_BADPASSWORD, MB_OK | MB_ICONSTOP); SetErrorFocus(hDlg, IDC_PASSWORD); FailChangePage(hDlg); } else { if (FAILED(pwd->m_hresRatings)) pwd->m_nlsSupervisorPassword = pwd->m_nlsUserPassword; pwd->m_idPrevPage = IDD_EnterUserPassword; ::ClosePasswordCache(hPWL, TRUE); int idNextPage; if (pwd->m_fCreatingProfile) idNextPage = IDD_ChooseFoldersWiz; else idNextPage = (pwd->m_fGoMultiWizard) ? IDD_FinishGoMulti : IDD_FinishAddUser; GoToPage(hDlg, idNextPage); } } } break; case PSN_WIZBACK: GoToPage(hDlg, IDD_EnterUsername); break; default: return FALSE; } break; case WM_INITDIALOG: { InitWizDataPtr(hDlg, lParam); CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); InsertControlText(hDlg, IDC_MAIN_CAPTION, &pwd->m_nlsUsername); LimitCredentialLength(hDlg, IDC_PASSWORD); if (FAILED(pwd->m_hresRatings)) { NLS_STR nlsTemp(MAX_RES_STR_LEN); if (nlsTemp.QueryError() == ERROR_SUCCESS) { nlsTemp.LoadString(IDS_RATINGS_PW_COMMENT); if (nlsTemp.QueryError() == ERROR_SUCCESS) SetDlgItemText(hDlg, IDC_RATINGS_PW_COMMENT, nlsTemp.QueryPch()); } } } break; default: return FALSE; } // end of switch on message return TRUE; } INT_PTR CALLBACK EnterUsernameDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm; switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_SETACTIVE: { PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT); } break; case PSN_WIZNEXT: { int cchUsername = GetWindowTextLength(GetDlgItem(hDlg, IDC_USERNAME)); if (!cchUsername) { MsgBox(hDlg, IDS_BLANK_USERNAME, MB_OK | MB_ICONSTOP); SetErrorFocus(hDlg, IDC_USERNAME, FALSE); FailChangePage(hDlg); } else { CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); if (SUCCEEDED(GetControlText(hDlg, IDC_USERNAME, &pwd->m_nlsUsername))) { /* If we're in the add-user wizard, fail if the user * already exists. In the go-multiuser wizard, we * just use the info to determine whether to offer * the folder-personalization page. */ IUser *pUser = NULL; if (SUCCEEDED(pwd->m_pDB->GetUser(pwd->m_nlsUsername.QueryPch(), &pUser))) { pUser->Release(); if (!pwd->m_fGoMultiWizard) { const NLS_STR *apnls[] = { &pwd->m_nlsUsername, NULL }; if (MsgBox(hDlg, IDS_USER_EXISTS, MB_OKCANCEL | MB_ICONSTOP, apnls) == IDCANCEL) { PropSheet_PressButton(GetParent(hDlg), PSBTN_CANCEL); break; } SetErrorFocus(hDlg, IDC_USERNAME, FALSE); FailChangePage(hDlg); break; } else { pwd->m_fCreatingProfile = FALSE; } } else { pwd->m_fCreatingProfile = TRUE; } /* See if the user already has a PWL. If not, next * page is to enter and confirm a password. If there * is a PWL and its password is non-blank, next page * is simply to enter the password. If there's a PWL * and its password is blank, next page is Finish. */ int idNextPage; HANDLE hPWL = NULL; HRESULT hres = ::GetUserPasswordCache(pwd->m_nlsUsername.QueryPch(), szNULL, &hPWL, FALSE); if (SUCCEEDED(hres)) { ::ClosePasswordCache(hPWL, TRUE); pwd->m_idPrevPage = IDD_EnterUsername; if (pwd->m_fCreatingProfile) idNextPage = IDD_ChooseFoldersWiz; else idNextPage = (pwd->m_fGoMultiWizard) ? IDD_FinishGoMulti : IDD_FinishAddUser; } else if (hres == HRESULT_FROM_WIN32(IERR_IncorrectUsername)) { idNextPage = IDD_EnterUserPassword; } else { idNextPage = IDD_NewUserPassword; } GoToPage(hDlg, idNextPage); } } } break; default: return FALSE; } break; case WM_INITDIALOG: { InitWizDataPtr(hDlg, lParam); CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); LimitCredentialLength(hDlg, IDC_USERNAME); if (pwd->m_fGoMultiWizard) { NLS_STR nlsText(MAX_RES_STR_LEN); if (nlsText.QueryError() == ERROR_SUCCESS) { nlsText.LoadString(IDS_ENTER_FIRST_USERNAME); if (nlsText.QueryError() == ERROR_SUCCESS) SetDlgItemText(hDlg, IDC_MAIN_CAPTION, nlsText.QueryPch()); } } } break; default: return FALSE; } // end of switch on message return TRUE; } void PickUserSelected(HWND hwndLB, int iItem) { HWND hDlg = GetParent(hwndLB); if (iItem == LB_ERR) { PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK); } else { PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT); } } INT_PTR CALLBACK PickUserDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm; switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_SETACTIVE: { int iItem = (int)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0); PickUserSelected((HWND)lParam, iItem); } break; case PSN_WIZNEXT: { CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); int iItem = (int)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0); if (iItem != LB_ERR) { if (pwd->m_pUserToClone != NULL) pwd->m_pUserToClone->Release(); pwd->m_pUserToClone = (IUser *)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETITEMDATA, iItem, 0); if (pwd->m_pUserToClone != NULL) pwd->m_pUserToClone->AddRef(); } else { MsgBox(hDlg, IDS_PICK_USERNAME, MB_OK | MB_ICONSTOP); FailChangePage(hDlg); } } break; default: return FALSE; } break; case WM_INITDIALOG: { InitWizDataPtr(hDlg, lParam); CWizData *pwd = (CWizData *)(((LPPROPSHEETPAGE)lParam)->lParam); FillUserList(GetDlgItem(hDlg, IDC_USERNAME), pwd->m_pDB, NULL, TRUE, PickUserSelected); } break; case WM_DESTROY: DestroyUserList(GetDlgItem(hDlg, IDC_USERNAME)); break; case WM_COMMAND: if (LOWORD(wParam) == IDC_USERNAME && HIWORD(wParam) == LBN_SELCHANGE) { int iItem = (int)::SendDlgItemMessage(hDlg, IDC_USERNAME, LB_GETCURSEL, 0, 0); PickUserSelected((HWND)lParam, iItem); } break; default: return FALSE; } // end of switch on message return TRUE; } INT_PTR CALLBACK NewPasswordDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm; switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_SETACTIVE: { PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT); } break; case PSN_WIZNEXT: { int cchPassword = GetWindowTextLength(GetDlgItem(hDlg, IDC_PASSWORD)); CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); GetControlText(hDlg, IDC_PASSWORD, &pwd->m_nlsUserPassword); BOOL fConfirmedOK = FALSE; int cchConfirm = GetWindowTextLength(GetDlgItem(hDlg, IDC_CONFIRM_PASSWORD)); if (cchConfirm == cchPassword) { NLS_STR nlsConfirm(cchConfirm+1); if (SUCCEEDED(GetControlText(hDlg, IDC_CONFIRM_PASSWORD, &nlsConfirm))) { if (!nlsConfirm.strcmp(pwd->m_nlsUserPassword)) fConfirmedOK = TRUE; } } if (!fConfirmedOK) { MsgBox(hDlg, IDS_NO_MATCH, MB_OK | MB_ICONSTOP); SetDlgItemText(hDlg, IDC_PASSWORD, szNULL); SetDlgItemText(hDlg, IDC_CONFIRM_PASSWORD, szNULL); SetErrorFocus(hDlg, IDC_PASSWORD); FailChangePage(hDlg); } else { pwd->m_idPrevPage = IDD_NewUserPassword; UINT idNextPage; if (pwd->m_fCreatingProfile) idNextPage = IDD_ChooseFoldersWiz; else idNextPage = pwd->m_fGoMultiWizard ? IDD_FinishGoMulti : IDD_FinishAddUser; GoToPage(hDlg, idNextPage); } } break; case PSN_WIZBACK: GoToPage(hDlg, IDD_EnterUsername); break; default: return FALSE; } break; case WM_INITDIALOG: { InitWizDataPtr(hDlg, lParam); CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); LimitCredentialLength(hDlg, IDC_PASSWORD); LimitCredentialLength(hDlg, IDC_CONFIRM_PASSWORD); if (pwd->m_fGoMultiWizard) { NLS_STR nlsText(MAX_RES_STR_LEN); if (nlsText.QueryError() == ERROR_SUCCESS) { nlsText.LoadString(IDS_YOURNEWPASSWORD); if (nlsText.QueryError() == ERROR_SUCCESS) SetDlgItemText(hDlg, IDC_MAIN_CAPTION, nlsText.QueryPch()); if (FAILED(pwd->m_hresRatings)) { nlsText.LoadString(IDS_RATINGS_PW_COMMENT); if (nlsText.QueryError() == ERROR_SUCCESS) SetDlgItemText(hDlg, IDC_RATINGS_PW_COMMENT, nlsText.QueryPch()); } } } else { InsertControlText(hDlg, IDC_MAIN_CAPTION, &pwd->m_nlsUsername); } } break; default: return FALSE; } // end of switch on message return TRUE; } const TCHAR c_szExplorerUSFKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"); const TCHAR c_szExplorerSFKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); const struct FolderDescriptor { UINT idsDirName; /* Resource ID for directory name */ LPCTSTR pszRegValue; /* Name of reg value to set path in */ LPCTSTR pszStaticName; /* Static name for ProfileReconciliation subkey */ LPCTSTR pszFiles; /* Spec for which files should roam */ DWORD dwAttribs; /* Desired attributes */ BOOL fSecondary : 1; /* TRUE if subsidiary to the Start Menu */ BOOL fDefaultInRoot : 1;/* TRUE if default is root of drive, not windir */ } aFolders[] = { /* NOTE: Keep the entries in the following table in the same order as the * corresponding FOLDER_XXXXXX bitflags in mslocusr.h. */ { IDS_CSIDL_DESKTOP_L, "Desktop", "Desktop", "*.*", FILE_ATTRIBUTE_DIRECTORY, 0, 0 }, { IDS_CSIDL_NETHOOD_L, "NetHood", "NetHood", "*.*", FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN, 0, 0 }, { IDS_CSIDL_RECENT_L, "Recent", "Recent", "*.*", FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN, 0, 0 }, { IDS_CSIDL_STARTMENU_L,"Start Menu","Start Menu","*.lnk,*.pif,*.url", FILE_ATTRIBUTE_DIRECTORY, 0, 0 }, { IDS_CSIDL_PROGRAMS_L, "Programs", "Programs", "*.lnk,*.pif,*.url", FILE_ATTRIBUTE_DIRECTORY, 1, 0 }, { IDS_CSIDL_STARTUP_L, "Startup", "Startup", "*.lnk,*.pif,*.url", FILE_ATTRIBUTE_DIRECTORY, 1, 0 }, { IDS_CSIDL_FAVORITES_L,"Favorites", "Favorites", "*.*", FILE_ATTRIBUTE_DIRECTORY, 0, 0 }, { IDS_CSIDL_CACHE_L, "Cache", "Cache", "", FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM, 0, 0 }, { IDS_CSIDL_PERSONAL_L, "Personal", "Personal", "*.*", FILE_ATTRIBUTE_DIRECTORY, 0, 1 }, }; const struct FolderDescriptor fdChannels = { IDS_CSIDL_CHANNELS_L, NULL, "Channel Preservation Key", "*.*", FILE_ATTRIBUTE_DIRECTORY, 0, 0 }; void InitFolderCheckboxes(HWND hDlg, CWizData *pwd) { IUser *pUserToClone; pwd->m_fdwOriginalPerUserFolders = 0; if (pwd->m_pUserToClone != NULL) { pUserToClone = pwd->m_pUserToClone; pUserToClone->AddRef(); } else { pwd->m_pDB->GetSpecialUser(GSU_DEFAULT, &pUserToClone); } HKEY hkeyUser; if (pUserToClone != NULL && SUCCEEDED(pUserToClone->LoadProfile(&hkeyUser))) { HKEY hkeyProfRec, hkeyProfRec2; if (RegOpenKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\ProfileReconciliation", 0, KEY_READ, &hkeyProfRec) != ERROR_SUCCESS) hkeyProfRec = NULL; if (RegOpenKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\SecondaryProfileReconciliation", 0, KEY_READ, &hkeyProfRec2) != ERROR_SUCCESS) hkeyProfRec2 = NULL; for (UINT iFolder = 0; iFolder < ARRAYSIZE(aFolders); iFolder++) { HKEY hkeyTemp; HKEY hkeyParent = aFolders[iFolder].fSecondary ? hkeyProfRec2 : hkeyProfRec; if (hkeyParent != NULL && RegOpenKeyEx(hkeyParent, aFolders[iFolder].pszStaticName, 0, KEY_READ, &hkeyTemp) == ERROR_SUCCESS) { RegCloseKey(hkeyTemp); pwd->m_fdwOriginalPerUserFolders |= 1 << iFolder; } /* else bit is already clear */ } if (hkeyProfRec != NULL) RegCloseKey(hkeyProfRec); if (hkeyProfRec2 != NULL) RegCloseKey(hkeyProfRec2); pUserToClone->UnloadProfile(hkeyUser); } if (pUserToClone != NULL) pUserToClone->Release(); CheckDlgButton(hDlg, IDC_CHECK_DESKTOP, (pwd->m_fdwOriginalPerUserFolders & (FOLDER_DESKTOP | FOLDER_NETHOOD | FOLDER_RECENT)) ? 1 : 0); CheckDlgButton(hDlg, IDC_CHECK_STARTMENU, (pwd->m_fdwOriginalPerUserFolders & (FOLDER_STARTMENU | FOLDER_PROGRAMS | FOLDER_STARTUP)) ? 1 : 0); CheckDlgButton(hDlg, IDC_CHECK_FAVORITES, (pwd->m_fdwOriginalPerUserFolders & FOLDER_FAVORITES) ? 1 : 0); CheckDlgButton(hDlg, IDC_CHECK_CACHE, (pwd->m_fdwOriginalPerUserFolders & FOLDER_CACHE) ? 1 : 0); CheckDlgButton(hDlg, IDC_CHECK_MYDOCS, (pwd->m_fdwOriginalPerUserFolders & FOLDER_MYDOCS) ? 1 : 0); } INT_PTR CALLBACK ChooseFoldersDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm; switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_SETACTIVE: { PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT); CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); InitFolderCheckboxes(hDlg, pwd); } break; case PSN_WIZNEXT: { CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); pwd->m_fdwCloneFromDefault = IsDlgButtonChecked(hDlg, IDC_RADIO_EMPTY) ? 0 : 0xffffffff; pwd->m_fdwNewPerUserFolders = 0; if (IsDlgButtonChecked(hDlg, IDC_CHECK_DESKTOP)) pwd->m_fdwNewPerUserFolders |= FOLDER_DESKTOP | FOLDER_NETHOOD | FOLDER_RECENT; else pwd->m_fdwNewPerUserFolders &= ~(FOLDER_DESKTOP | FOLDER_NETHOOD | FOLDER_RECENT); if (IsDlgButtonChecked(hDlg, IDC_CHECK_STARTMENU)) pwd->m_fdwNewPerUserFolders |= FOLDER_STARTMENU | FOLDER_PROGRAMS | FOLDER_STARTUP; else pwd->m_fdwNewPerUserFolders &= ~(FOLDER_STARTMENU | FOLDER_PROGRAMS | FOLDER_STARTUP); if (IsDlgButtonChecked(hDlg, IDC_CHECK_FAVORITES)) pwd->m_fdwNewPerUserFolders |= FOLDER_FAVORITES; else pwd->m_fdwNewPerUserFolders &= ~(FOLDER_FAVORITES); if (IsDlgButtonChecked(hDlg, IDC_CHECK_CACHE)) pwd->m_fdwNewPerUserFolders |= FOLDER_CACHE; else pwd->m_fdwNewPerUserFolders &= ~(FOLDER_CACHE); if (IsDlgButtonChecked(hDlg, IDC_CHECK_MYDOCS)) pwd->m_fdwNewPerUserFolders |= FOLDER_MYDOCS; else pwd->m_fdwNewPerUserFolders &= ~(FOLDER_MYDOCS); pwd->m_idPrevPage = IDD_ChooseFoldersWiz; GoToPage(hDlg, pwd->m_fGoMultiWizard ? IDD_FinishGoMulti : IDD_FinishAddUser); } break; case PSN_WIZBACK: { CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); GoToPage(hDlg, pwd->m_idPrevPage); } break; default: return FALSE; } break; case WM_INITDIALOG: { InitWizDataPtr(hDlg, lParam); CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); CheckRadioButton(hDlg, IDC_RADIO_COPY, IDC_RADIO_EMPTY, IDC_RADIO_COPY); } break; default: return FALSE; } // end of switch on message return TRUE; } void GetWindowsRootPath(LPSTR pszBuffer, UINT cchBuffer) { GetWindowsDirectory(pszBuffer, cchBuffer); LPSTR pszEnd = NULL; if (*pszBuffer == '\\' && *(pszBuffer+1) == '\\') { pszEnd = ::strchrf(pszBuffer+2, '\\'); if (pszEnd != NULL) { pszEnd = ::strchrf(pszEnd+1, '\\'); if (pszEnd != NULL) pszEnd++; } } else { LPSTR pszNext = CharNext(pszBuffer); if (*pszNext == ':' && *(pszNext+1) == '\\') pszEnd = pszNext + 2; } if (pszEnd != NULL) *pszEnd = '\0'; else AddBackslash(pszBuffer); } void AddProfRecKey(HKEY hkeyUser, HKEY hkeyProfRec, const FolderDescriptor *pFolder, BOOL fCloneFromDefault, LPCSTR pszProfileDir) { TCHAR szDefaultPath[MAX_PATH]; if (pFolder->fDefaultInRoot) GetWindowsRootPath(szDefaultPath, ARRAYSIZE(szDefaultPath)); else ::strcpyf(szDefaultPath, TEXT("*windir\\")); LPTSTR pszEnd = szDefaultPath + ::strlenf(szDefaultPath); LoadString(::hInstance, pFolder->idsDirName, pszEnd, ARRAYSIZE(szDefaultPath) - (int)(pszEnd - szDefaultPath)); LPTSTR pszLastComponent = ::strrchrf(pszEnd, '\\'); if (pszLastComponent == NULL) pszLastComponent = pszEnd; else pszLastComponent++; HKEY hSubKey; LONG err = RegCreateKeyEx(hkeyProfRec, pFolder->pszStaticName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hSubKey, NULL); if (err == ERROR_SUCCESS) { err = RegSetValueEx(hSubKey, "CentralFile", 0, REG_SZ, (LPBYTE)pszLastComponent, ::strlenf(pszLastComponent)+1); if (err == ERROR_SUCCESS) err = RegSetValueEx(hSubKey, "LocalFile", 0, REG_SZ, (LPBYTE)pszEnd, ::strlenf(pszEnd)+1); if (err == ERROR_SUCCESS) err = RegSetValueEx(hSubKey, "Name", 0, REG_SZ, (LPBYTE)pFolder->pszFiles, ::strlenf(pFolder->pszFiles) + 1); if (fCloneFromDefault && err == ERROR_SUCCESS) err = RegSetValueEx(hSubKey, "DefaultDir", 0, REG_SZ, (LPBYTE)szDefaultPath, ::strlenf(szDefaultPath) + 1); DWORD dwOne = 1; if (err == ERROR_SUCCESS) err = RegSetValueEx(hSubKey, "MustBeRelative", 0, REG_DWORD, (LPBYTE)&dwOne, sizeof(dwOne)); if (fCloneFromDefault && err == ERROR_SUCCESS) err = RegSetValueEx(hSubKey, "Default", 0, REG_DWORD, (LPBYTE)&dwOne, sizeof(dwOne)); if (pFolder->pszRegValue != NULL) { if (err == ERROR_SUCCESS) err = RegSetValueEx(hSubKey, "RegKey", 0, REG_SZ, (LPBYTE)c_szExplorerUSFKey, ::strlenf(c_szExplorerUSFKey) + 1); if (err == ERROR_SUCCESS) err = RegSetValueEx(hSubKey, "RegValue", 0, REG_SZ, (LPBYTE)pFolder->pszRegValue, ::strlenf(pFolder->pszRegValue) + 1); } if (err == ERROR_SUCCESS && pFolder->fSecondary) { err = RegSetValueEx(hSubKey, "ParentKey", 0, REG_SZ, (LPBYTE)"Start Menu", 11); } RegCloseKey(hSubKey); } /* And if we're not adding a clone-from-default profrec key, we know that * no profile code is going to create the directory, so we'd better do it * ourselves, and set the path in the registry. */ if (!fCloneFromDefault) { NLS_STR nlsTemp(MAX_PATH); if (nlsTemp.QueryError() == ERROR_SUCCESS) { nlsTemp = pszProfileDir; AddBackslash(nlsTemp); nlsTemp.strcat(pszEnd); HKEY hkeyExplorer; if (RegOpenKeyEx(hkeyUser, c_szExplorerSFKey, 0, KEY_READ | KEY_WRITE, &hkeyExplorer) == ERROR_SUCCESS) { RegSetValueEx(hkeyExplorer, pFolder->pszRegValue, 0, REG_SZ, (LPBYTE)nlsTemp.QueryPch(), nlsTemp.strlen()+1); RegCloseKey(hkeyExplorer); } if (RegOpenKeyEx(hkeyUser, c_szExplorerUSFKey, 0, KEY_READ | KEY_WRITE, &hkeyExplorer) == ERROR_SUCCESS) { RegSetValueEx(hkeyExplorer, pFolder->pszRegValue, 0, REG_SZ, (LPBYTE)nlsTemp.QueryPch(), nlsTemp.strlen()+1); RegCloseKey(hkeyExplorer); } CreateDirectoryPath(nlsTemp.QueryPch()); } } } /* CWizData::PreInitProfile is called back by IUserDatabase::Install or * ::AddUser after the new user's profile has been created but before * directory reconciliation takes place. This is our chance to add * roaming keys for any folders that we want to be per-user and initialized * from the defaults, and remove roaming keys for other folders we know about. */ STDMETHODIMP CWizData::PreInitProfile(HKEY hkeyUser, LPCSTR pszProfileDir) { HKEY hkeyProfRec, hkeyProfRec2; DWORD dwDisp; if (RegCreateKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\ProfileReconciliation", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkeyProfRec, &dwDisp) != ERROR_SUCCESS) hkeyProfRec = NULL; if (RegCreateKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\SecondaryProfileReconciliation", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkeyProfRec2, &dwDisp) != ERROR_SUCCESS) hkeyProfRec2 = NULL; m_fChannelHack = FALSE; DWORD fdwFlag = 1; for (UINT iFolder = 0; iFolder < ARRAYSIZE(aFolders); iFolder++, fdwFlag <<= 1) { BOOL fWasPerUser = (m_fdwOriginalPerUserFolders & fdwFlag); BOOL fMakePerUser = (m_fdwNewPerUserFolders & fdwFlag); BOOL fCloneFromDefault = (m_fdwCloneFromDefault & fdwFlag); /* If the folder was shared and is staying that way, do nothing. */ if (!fWasPerUser && !fMakePerUser) continue; /* If the folder was per-user and is staying that way, do nothing, * UNLESS we're creating a new profile and the user chose the start- * out-empty option. In that case we want to make sure to kill the * profrec keys until PostInitProfile. */ if (fWasPerUser && fMakePerUser && (!m_fCreatingProfile || fCloneFromDefault)) continue; HKEY hkeyParent = aFolders[iFolder].fSecondary ? hkeyProfRec2 : hkeyProfRec; /* If the user is making a folder per-user when it wasn't, and they * want this folder cloned from the default, add a profrec key now. */ if (fMakePerUser && fCloneFromDefault) { AddProfRecKey(hkeyUser, hkeyParent, &aFolders[iFolder], TRUE, pszProfileDir); } /* If the user is making a folder shared, or they want this per-user * folder to start out empty, delete the profrec key now. In the * latter case, we will add it for roaming purposes during * PostInitProfile. */ if (!fMakePerUser || !fCloneFromDefault) { RegDeleteKey(hkeyParent, aFolders[iFolder].pszStaticName); /* If we're making a folder shared and we're not cloning the * default profile, then the profile has a per-user directory * path in it which we need to clear out. * * We know that we need to delete the value from User Shell Folders, * and set the default path under Shell Folders. */ if (!fMakePerUser && m_pUserToClone != NULL) { TCHAR szDefaultPath[MAX_PATH+1]; if (aFolders[iFolder].fDefaultInRoot) { GetWindowsRootPath(szDefaultPath, ARRAYSIZE(szDefaultPath)); } else { GetWindowsDirectory(szDefaultPath, ARRAYSIZE(szDefaultPath)); AddBackslash(szDefaultPath); } LPTSTR pszEnd = szDefaultPath + ::strlenf(szDefaultPath); LoadString(::hInstance, aFolders[iFolder].idsDirName, pszEnd, ARRAYSIZE(szDefaultPath) - (int)(pszEnd - szDefaultPath)); HKEY hkeyExplorer; if (RegOpenKeyEx(hkeyUser, c_szExplorerUSFKey, 0, KEY_READ | KEY_WRITE, &hkeyExplorer) == ERROR_SUCCESS) { if (aFolders[iFolder].fDefaultInRoot) { RegSetValueEx(hkeyExplorer, aFolders[iFolder].pszRegValue, 0, REG_SZ, (LPBYTE)szDefaultPath, ::strlenf(szDefaultPath)+1); } else { RegDeleteValue(hkeyExplorer, aFolders[iFolder].pszRegValue); } RegCloseKey(hkeyExplorer); } if (RegOpenKeyEx(hkeyUser, c_szExplorerSFKey, 0, KEY_READ | KEY_WRITE, &hkeyExplorer) == ERROR_SUCCESS) { RegSetValueEx(hkeyExplorer, aFolders[iFolder].pszRegValue, 0, REG_SZ, (LPBYTE)szDefaultPath, ::strlenf(szDefaultPath)+1); RegCloseKey(hkeyExplorer); } } } /* Special code for start-out-empty folders: Some of them need to * start out with certain crucial files, not totally empty. */ if (fMakePerUser && (!fWasPerUser || m_fCreatingProfile) && !fCloneFromDefault) { /* Special hack for channels: If the user wants Favorites to be per-user, * but chooses to start it out empty, they get no channels either, because * Channels is a subdirectory of Favorites. So, for that case only, * we force in a clone-from-default profrec key for Channels, which we'll * delete in PostInit. */ if (fdwFlag == FOLDER_FAVORITES) { AddProfRecKey(hkeyUser, hkeyProfRec, &fdChannels, TRUE, pszProfileDir); m_fChannelHack = TRUE; } } } if (hkeyProfRec != NULL) RegCloseKey(hkeyProfRec); if (hkeyProfRec2 != NULL) RegCloseKey(hkeyProfRec2); return S_OK; } /* CWizData::PostInitProfile is called by IUserDatabase::Install or ::AddUser * after the user's folders have all been created and initialized. Here we * add profrec keys for any folders which we want to be per-user but don't * want initialized from the default. */ STDMETHODIMP CWizData::PostInitProfile(HKEY hkeyUser, LPCSTR pszProfileDir) { HKEY hkeyProfRec, hkeyProfRec2; DWORD dwDisp; if (RegCreateKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\ProfileReconciliation", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkeyProfRec, &dwDisp) != ERROR_SUCCESS) hkeyProfRec = NULL; if (RegCreateKeyEx(hkeyUser, "Software\\Microsoft\\Windows\\CurrentVersion\\SecondaryProfileReconciliation", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hkeyProfRec2, &dwDisp) != ERROR_SUCCESS) hkeyProfRec2 = NULL; DWORD fdwFlag = 1; for (UINT iFolder = 0; iFolder < ARRAYSIZE(aFolders); iFolder++, fdwFlag <<= 1) { HKEY hkeyParent = aFolders[iFolder].fSecondary ? hkeyProfRec2 : hkeyProfRec; if (m_fdwNewPerUserFolders & fdwFlag) { /* If the user is making a folder per-user when it wasn't or making a * folder per-user in a new profile, and they want this folder to start * out empty, add a profrec key now. */ if ((!(m_fdwOriginalPerUserFolders & fdwFlag) || m_fCreatingProfile) && !(m_fdwCloneFromDefault & fdwFlag)) { AddProfRecKey(hkeyUser, hkeyParent, &aFolders[iFolder], FALSE, pszProfileDir); } /* If the folder is per-user and is supposed to have special * attributes, make sure it has them. */ if (aFolders[iFolder].dwAttribs != FILE_ATTRIBUTE_DIRECTORY) { RegEntry re(aFolders[iFolder].pszStaticName, hkeyParent); NLS_STR nlsTemp(MAX_PATH); if (re.GetError() == ERROR_SUCCESS && nlsTemp.QueryError() == ERROR_SUCCESS) { GetSetRegistryPath(hkeyUser, re, &nlsTemp, FALSE); if (nlsTemp.strlen()) { ::SetFileAttributes(nlsTemp.QueryPch(), aFolders[iFolder].dwAttribs); } } } } } /* If we added a hack for channels, undo that hack now that we're done * initializing the profile. */ if (m_fChannelHack) RegDeleteKey(hkeyProfRec, fdChannels.pszStaticName); if (hkeyProfRec != NULL) RegCloseKey(hkeyProfRec); if (hkeyProfRec2 != NULL) RegCloseKey(hkeyProfRec2); return S_OK; } /* Following is actually for the CPL version of the choose-folders dialog */ HRESULT ChooseFoldersProgressFunc(LPARAM lParam) { CWizData *pwd = (CWizData *)lParam; HKEY hkeyUser; if (pwd->m_pUserToClone != NULL && SUCCEEDED(pwd->m_pUserToClone->LoadProfile(&hkeyUser))) { TCHAR szProfileDir[MAX_PATH]; DWORD cbBuffer = sizeof(szProfileDir); pwd->m_pUserToClone->GetProfileDirectory(szProfileDir, &cbBuffer); pwd->PreInitProfile(hkeyUser, szProfileDir); NLS_STR nlsPath(szProfileDir); AddBackslash(nlsPath); DWORD fdwFlag = 1; for (UINT iFolder = 0; iFolder < ARRAYSIZE(aFolders); iFolder++, fdwFlag <<= 1) { /* Do reconciliation if we want to per-user-ize a folder that * wasn't per-user before and we want to clone it from default. */ if (!(pwd->m_fdwOriginalPerUserFolders & fdwFlag) && (pwd->m_fdwNewPerUserFolders & fdwFlag) && (pwd->m_fdwCloneFromDefault & fdwFlag)) { DefaultReconcileKey(hkeyUser, nlsPath, aFolders[iFolder].pszStaticName, aFolders[iFolder].fSecondary); } } /* Process the initialization hack for Channels, if it exists. */ if (pwd->m_fChannelHack) DefaultReconcileKey(hkeyUser, nlsPath, fdChannels.pszStaticName, fdChannels.fSecondary); pwd->PostInitProfile(hkeyUser, szProfileDir); pwd->m_pUserToClone->UnloadProfile(hkeyUser); SHFlushSFCache(); return S_OK; } return E_FAIL; } void FinishChooseFolders(HWND hDlg, CWizData *pwd) { if (SUCCEEDED(CallWithinProgressDialog(hDlg, IDD_CreateProgress, ChooseFoldersProgressFunc, (LPARAM)pwd))) EndDialog(hDlg, TRUE); } HRESULT InstallProgressFunc(LPARAM lParam) { CWizData *pwd = (CWizData *)lParam; return pwd->m_pDB->Install(pwd->m_nlsUsername.QueryPch(), pwd->m_nlsUserPassword.QueryPch(), pwd->m_nlsSupervisorPassword.QueryPch(), pwd); } BOOL FinishGoMulti(HWND hDlg, CWizData *pwd) { DWORD dwExitCode = 0xffffffff; /* not a valid EWX_ value */ /* If user profiles aren't enabled, enable them. Using them requires * logging off. */ if (!UseUserProfiles()) { dwExitCode = EWX_LOGOFF; EnableProfiles(); } /* If there is no primary logon provider, install our logon dialog as * the primary. Using this requires rebooting the system. */ if (InstallLogonDialog()) { dwExitCode = EWX_REBOOT; } pwd->m_nlsUserPassword.strupr(); HRESULT hres = CallWithinProgressDialog(hDlg, IDD_CreateProgress, InstallProgressFunc, (LPARAM)pwd); if (SUCCEEDED(hres)) { /* Set the new username as the default one to log on as. */ HKEY hkeyLogon; if (OpenLogonKey(&hkeyLogon) == ERROR_SUCCESS) { pwd->m_nlsUsername.ToOEM(); RegSetValueEx(hkeyLogon, ::szUsername, 0, REG_SZ, (LPBYTE)pwd->m_nlsUsername.QueryPch(), pwd->m_nlsUsername.strlen() + 1); pwd->m_nlsUsername.ToAnsi(); RegCloseKey(hkeyLogon); } if ((dwExitCode != 0xffffffff) && MsgBox(hDlg, IDS_GO_MULTI_RESTART, MB_YESNO | MB_ICONQUESTION) == IDYES) { ::ExitWindowsEx(dwExitCode, 0); ::ExitProcess(0); } return TRUE; } ReportUserError(hDlg, hres); return FALSE; } HRESULT AddUserProgressFunc(LPARAM lParam) { CWizData *pwd = (CWizData *)lParam; return pwd->m_pDB->AddUser(pwd->m_nlsUsername.QueryPch(), pwd->m_pUserToClone, pwd, &pwd->m_pNewUser); } BOOL FinishAddUser(HWND hDlg, CWizData *pwd) { pwd->m_nlsUserPassword.strupr(); pwd->m_pNewUser = NULL; HRESULT hres = CallWithinProgressDialog(hDlg, IDD_CreateProgress, AddUserProgressFunc, (LPARAM)pwd); if (SUCCEEDED(hres)) { hres = pwd->m_pNewUser->ChangePassword(szNULL, pwd->m_nlsUserPassword.QueryPch()); pwd->m_pNewUser->Release(); pwd->m_pNewUser = NULL; } else { ReportUserError(hDlg, hres); } return SUCCEEDED(hres); } INT_PTR CALLBACK FinishDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { NMHDR FAR *lpnm; switch(message) { case WM_NOTIFY: lpnm = (NMHDR FAR *)lParam; switch(lpnm->code) { case PSN_SETACTIVE: { PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH); } break; case PSN_WIZFINISH: { CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); BOOL fOK = pwd->m_fGoMultiWizard ? FinishGoMulti(hDlg, pwd) : FinishAddUser(hDlg, pwd); if (!fOK) FailChangePage(hDlg); else return FALSE; /* destroy wizard */ } break; case PSN_WIZBACK: { CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); GoToPage(hDlg, pwd->m_idPrevPage); } break; default: return FALSE; } break; case WM_INITDIALOG: { InitWizDataPtr(hDlg, lParam); CWizData *pwd = (CWizData *)GetWindowLongPtr(hDlg, DWLP_USER); if (!pwd->m_fGoMultiWizard) { InsertControlText(hDlg, IDC_MAIN_CAPTION, &pwd->m_nlsUsername); InsertControlText(hDlg, IDC_MAIN_CAPTION2, &pwd->m_nlsUsername); } } break; default: return FALSE; } // end of switch on message return TRUE; } STDMETHODIMP CLUDatabase::InstallWizard(HWND hwndParent) { #if 0 if (UseUserProfiles()) { MsgBox(hwndParent, IDS_PROFILES_ALREADY_ENABLED, MB_OK | MB_ICONINFORMATION); return E_FAIL; } #endif if (ProfileUIRestricted()) { ReportRestrictionError(hwndParent); return E_ACCESSDENIED; } CWizData wd; wd.m_hresRatings = VerifySupervisorPassword(szNULL); wd.m_fGoMultiWizard = TRUE; wd.m_pDB = this; AddRef(); /* just in case */ wd.m_pUserToClone = NULL; LPPROPSHEETHEADER ppsh; // Allocate the property sheet header // if ((ppsh = (LPPROPSHEETHEADER)LocalAlloc(LMEM_FIXED, sizeof(PROPSHEETHEADER)+ (MAX_WIZ_PAGES * sizeof(HPROPSHEETPAGE)))) != NULL) { ppsh->dwSize = sizeof(*ppsh); ppsh->dwFlags = PSH_WIZARD; ppsh->hwndParent = hwndParent; ppsh->hInstance = ::hInstance; ppsh->pszCaption = NULL; ppsh->nPages = 0; ppsh->nStartPage = 0; ppsh->phpage = (HPROPSHEETPAGE *)(ppsh+1); /* Add the pages for the wizard. Note that we have two pages to * prompt for the user's account password -- one to enter, the other * to enter and confirm. The code in EnterUsernameDlgProc jumps to * the right password page depending on whether the user has a PWL. * The code in NewPasswordDlgProc knows to jump ahead to the finish * page. * * If you add more pages here, be sure to update the code as necessary * so the sequence is correct. */ AddPage(ppsh, IDD_EnableProfilesIntro, IntroDlgProc, &wd); if (wd.m_hresRatings == S_FALSE) AddPage(ppsh, IDD_EnterCAPassword, EnterCAPWDlgProc, &wd); AddPage(ppsh, IDD_EnterUsername, EnterUsernameDlgProc, &wd); AddPage(ppsh, IDD_NewUserPassword, NewPasswordDlgProc, &wd); AddPage(ppsh, IDD_EnterUserPassword, EnterUserPWDlgProc, &wd); AddPage(ppsh, IDD_ChooseFoldersWiz, ChooseFoldersDlgProc, &wd); AddPage(ppsh, IDD_FinishGoMulti, FinishDlgProc, &wd); PropertySheet(ppsh); LocalFree((HLOCAL)ppsh); } Release(); /* undo above AddRef() */ return S_OK; } HRESULT DoAddUserWizard(HWND hwndParent, IUserDatabase *pDB, BOOL fPickUserPage, IUser *pUserToClone) { CWizData wd; wd.m_hresRatings = VerifySupervisorPassword(szNULL); wd.m_fGoMultiWizard = FALSE; wd.m_pDB = pDB; pDB->AddRef(); /* just in case */ wd.m_pUserToClone = pUserToClone; if (wd.m_pUserToClone != NULL) wd.m_pUserToClone->AddRef(); LPPROPSHEETHEADER ppsh; // Allocate the property sheet header // if ((ppsh = (LPPROPSHEETHEADER)LocalAlloc(LMEM_FIXED, sizeof(PROPSHEETHEADER)+ (MAX_WIZ_PAGES * sizeof(HPROPSHEETPAGE)))) != NULL) { ppsh->dwSize = sizeof(*ppsh); ppsh->dwFlags = PSH_WIZARD; ppsh->hwndParent = hwndParent; ppsh->hInstance = ::hInstance; ppsh->pszCaption = NULL; ppsh->nPages = 0; ppsh->nStartPage = 0; ppsh->phpage = (HPROPSHEETPAGE *)(ppsh+1); AddPage(ppsh, IDD_AddUserIntro, IntroDlgProc, &wd); if (IsCurrentUserSupervisor(pDB) != S_OK) { AddPage(ppsh, IDD_EnterCAPassword, EnterCAPWDlgProc, &wd); } if (fPickUserPage) AddPage(ppsh, IDD_PickUser, PickUserDlgProc, &wd); AddPage(ppsh, IDD_EnterUsername, EnterUsernameDlgProc, &wd); AddPage(ppsh, IDD_NewUserPassword, NewPasswordDlgProc, &wd); AddPage(ppsh, IDD_EnterUserPassword, EnterUserPWDlgProc, &wd); AddPage(ppsh, IDD_ChooseFoldersWiz, ChooseFoldersDlgProc, &wd); AddPage(ppsh, IDD_FinishAddUser, FinishDlgProc, &wd); PropertySheet(ppsh); LocalFree((HLOCAL)ppsh); } pDB->Release(); /* undo above AddRef() */ return S_OK; } STDMETHODIMP CLUDatabase::AddUserWizard(HWND hwndParent) { if (ProfileUIRestricted()) { ReportRestrictionError(hwndParent); return E_ACCESSDENIED; } return DoAddUserWizard(hwndParent, this, TRUE, NULL); } extern "C" void InstallWizard(HWND hwndParent, HINSTANCE hinstEXE, LPSTR pszCmdLine, int nCmdShow) { IUserDatabase *pDB; if (SUCCEEDED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) { pDB->InstallWizard(hwndParent); pDB->Release(); } } extern "C" void AddUserWizard(HWND hwndParent, HINSTANCE hinstEXE, LPSTR pszCmdLine, int nCmdShow) { IUserDatabase *pDB; if (SUCCEEDED(::CreateUserDatabase(IID_IUserDatabase, (void **)&pDB))) { pDB->AddUserWizard(hwndParent); pDB->Release(); } } struct ProgressDlgData { PFNPROGRESS pfn; LPARAM lParam; HRESULT hres; }; void CallProgressFunc(HWND hDlg) { ProgressDlgData *ppdd = (ProgressDlgData *)GetWindowLongPtr(hDlg, DWLP_USER); ppdd->hres = ppdd->pfn(ppdd->lParam); EndDialog(hDlg, FALSE); } const UINT WM_CALL_FUNC = WM_USER + 100; INT_PTR CALLBACK ProgressDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: { SetWindowLongPtr(hDlg, DWLP_USER, lParam); /* Defer function call to a posted message so the dialog manager * will show our dialog. * * If PostMessage fails, at least still call the function anyway. */ if (!PostMessage(hDlg, WM_CALL_FUNC, 0, 0)) { CallProgressFunc(hDlg); } } return TRUE; /* we didn't set the focus */ case WM_CALL_FUNC: CallProgressFunc(hDlg); break; default: return FALSE; } return TRUE; } HRESULT CallWithinProgressDialog(HWND hwndOwner, UINT idResource, PFNPROGRESS pfn, LPARAM lParam) { ProgressDlgData pdd = { pfn, lParam, E_FAIL }; DialogBoxParam(::hInstance, MAKEINTRESOURCE(idResource), hwndOwner, ProgressDlgProc, (LPARAM)&pdd); return pdd.hres; } BOOL ProfileUIRestricted(void) { RegEntry rePolicy("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"); if (rePolicy.GetError() == ERROR_SUCCESS) { if (rePolicy.GetNumber("NoProfilePage") != 0) return TRUE; } return FALSE; } void ReportRestrictionError(HWND hwndOwner) { MsgBox(hwndOwner, IDS_PROFILE_POLICY, MB_OK | MB_ICONSTOP); }