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

#include "mslocusr.h"
#include "msluglob.h"
#include "resource.h"
#include <regentry.h>
#include "profiles.h"
#include <npmsg.h>
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);
}