Windows2000/private/shell/ext/netplwiz/netwiz.cpp
2020-09-30 17:12:32 +02:00

1062 lines
30 KiB
C++

#include "stdafx.h"
#include "shlobj.h"
#include "shlobjp.h"
#include "shsemip.h"
// Headers for the group list and group page base
#include "grpinfo.h"
#include "grppage.h"
#pragma hdrstop
// useful globals and macros used by everybody
DWORD g_dwWhichNet;
UINT g_uWizardIs = NAW_NETID;
BOOL g_fRebootOnExit = FALSE;
BOOL g_fShownLastPage = FALSE;
// Stuff for creating a default autologon user
#define ITEMDATA_DEFAULTLOCALUSER 0xDEADBEEF
const WCHAR c_szAdminAccount[] = L"Administrator";
// The wizard pages we are adding
#define WIZDLG(name, dlgproc, dwFlags) \
{ MAKEINTRESOURCE(IDD_PSW_##name##), dlgproc, MAKEINTRESOURCE(IDS_##name##), MAKEINTRESOURCE(IDS_##name##_SUB), dwFlags }
struct
{
LPCWSTR idPage;
DLGPROC pDlgProc;
LPCWSTR pHeading;
LPCWSTR pSubHeading;
DWORD dwFlags;
}
pages[] =
{
WIZDLG(WELCOME, _IntroDlgProc, PSP_HIDEHEADER),
WIZDLG(HOWUSE, _HowUseDlgProc, 0),
WIZDLG(WHICHNET, _WhichNetDlgProc, 0),
WIZDLG(DOMAININFO, _DomainInfoDlgProc, 0),
WIZDLG(USERINFO, _UserInfoDlgProc, 0),
WIZDLG(COMPINFO, _CompInfoDlgProc, 0),
WIZDLG(ADDUSER, _AddUserDlgProc, 0),
WIZDLG(PERMISSIONS, _PermissionsDlgProc, 0),
WIZDLG(WORKGROUP, _WorkgroupDlgProc, 0),
WIZDLG(AUTOLOGON, _AutoLogonDlgProc, 0),
WIZDLG(DONE, _DoneDlgProc, PSP_HIDEHEADER),
};
// Set the Wizard buttons for the dialog
void SetWizardButtons(HWND hwndPage, DWORD dwButtons)
{
HWND hwndParent = GetParent(hwndPage);
if ( g_uWizardIs != NAW_NETID )
{
#if 0
EnableWindow(GetDlgItem(hwndParent,IDCANCEL),FALSE);
ShowWindow(GetDlgItem(hwndParent,IDCANCEL),SW_HIDE);
#endif
EnableWindow(GetDlgItem(hwndParent,IDHELP),FALSE);
ShowWindow(GetDlgItem(hwndParent,IDHELP),SW_HIDE);
}
if ( g_fRebootOnExit )
{
TCHAR szBuffer[80];
LoadString(GLOBAL_HINSTANCE, IDS_CLOSE, szBuffer, ARRAYSIZE(szBuffer));
SetDlgItemText(hwndParent, IDCANCEL, szBuffer);
}
PropSheet_SetWizButtons(hwndParent, dwButtons);
}
// Utility fn's
// GetRegisteredOwner - retrieves the name of the registered owner of the machine
HRESULT GetRegisteredOwner(TCHAR* pszOwner, DWORD cchOwner)
{
// REGKEY for Registered Owner (HKLM)
static const TCHAR c_szRegOwnerKey[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion");
static const TCHAR c_szRegOwnerVal[] = TEXT("RegisteredOwner");
// Default to failure
HRESULT hr = E_FAIL;
LONG Err;
HKEY hkey;
Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegOwnerKey, 0, KEY_QUERY_VALUE, &hkey);
if (ERROR_SUCCESS == Err)
{
DWORD cbBuffer = cchOwner * sizeof(TCHAR);
DWORD dwType;
Err = RegQueryValueEx(hkey, c_szRegOwnerVal, 0, &dwType, (LPBYTE) pszOwner, &cbBuffer);
if (ERROR_SUCCESS == Err)
{
hr = S_OK;
}
RegCloseKey(hkey);
}
return hr;
}
inline BOOL IsLegalNameCharacter(WCHAR ch)
{
// We need to use illegal fat chars, says SBurns
return (NULL == StrChr(ILLEGAL_FAT_CHARS, ch));
}
// Create a username from a source string by removing all non-alphabetic chars
HRESULT MungeUserName(TCHAR* pszSource, TCHAR* pszUsername, DWORD cchUsername)
{
DWORD ichDest = 0;
// Examine each char in the source string as long as there is room left
// in the destination buffer for the next char and a null-terminator
for (DWORD ichSrc = 0; ((TEXT('\0') != pszSource[ichSrc]) && (ichDest < (cchUsername-1))); ichSrc++)
{
TCHAR ch = pszSource[ichSrc];
// Is character allowed?
if (IsLegalNameCharacter(ch))
{
// it is, add it to the string
pszUsername[ichDest ++] = ch;
}
}
// Null-terminate
if (cchUsername != 0)
{
pszUsername[ichDest] = TEXT('\0');
// If we have room on the string for one more character before the null
if (ichDest < (cchUsername-1))
{
// If the generated name matches the computer name
TCHAR szComputer[MAX_COMPUTERNAME + 1];
DWORD cchComputer = ARRAYSIZE(szComputer);
if (GetComputerName(szComputer, &cchComputer))
{
if (0 == lstrcmpi(szComputer, pszUsername))
{
// Yes, names are the same. Then we need to munge the name just a bit more so they are different
// Add a '1' to the end of the string
pszUsername[ichDest++] = TEXT('1');
pszUsername[ichDest] = TEXT('\0');
}
}
}
}
return (ichDest > 0) ? S_OK : E_FAIL;
}
HRESULT GetDefaultLocalUserName(TCHAR* szUser, DWORD cchUser)
{
HRESULT hr = E_UNEXPECTED;
// Name of the registered owner of this machine - we'll munge
// a username from this
TCHAR szRegisteredOwner[256];
hr = GetRegisteredOwner(szRegisteredOwner, ARRAYSIZE(szRegisteredOwner));
if (SUCCEEDED(hr))
{
// Allowing for only alphabetic characters, turn the registered
// owners name into a username of no more than MAX_USER chars
hr = MungeUserName(szRegisteredOwner, szUser, cchUser);
}
return hr;
}
BOOL GetAdministratorsGroupName(TCHAR* pszAdmins, DWORD cchAdmins)
{
PSID psid;
SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
BOOL fSuccess = AllocateAndInitializeSid(&auth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &psid);
if (fSuccess)
{
TCHAR szDomain[DNLEN + 1];
DWORD cchDomain = ARRAYSIZE(szDomain);
SID_NAME_USE sUse;
fSuccess = LookupAccountSid(NULL, psid, pszAdmins, &cchAdmins, szDomain, &cchDomain, &sUse);
FreeSid(psid);
}
return fSuccess;
}
// CreateLocalAdminUser - creates a local user account, puts this user into the administrators group.
HRESULT CreateLocalAdminUser(HWND hwnd, LPTSTR szUser, LPTSTR szPassword)
{
HRESULT hr;
// Create a user account
// **
#ifdef DONT_JOIN
hr = S_OK;
#else // !DONT_JOIN
// Assume failure
hr = E_FAIL;
// Try to add this user to the system and put them in the administrators group
USER_INFO_1 usri1;
usri1.usri1_name = szUser;
usri1.usri1_password = szPassword;
usri1.usri1_password_age = 0;
usri1.usri1_priv = USER_PRIV_USER;
usri1.usri1_home_dir = L"";
usri1.usri1_comment = L"";
usri1.usri1_flags = UF_DONT_EXPIRE_PASSWD | UF_NORMAL_ACCOUNT;
usri1.usri1_script_path = NULL;
NET_API_STATUS status = NetUserAdd(NULL, 1, (LPBYTE) &usri1, NULL);
if (NERR_Success == status)
{
// Set the user's full name (easier than using USER_INFO_2)
USER_INFO_1011 usri1011;
TCHAR szRegisteredOwner[256];
if (SUCCEEDED(GetRegisteredOwner(szRegisteredOwner, ARRAYSIZE(szRegisteredOwner))))
{
usri1011.usri1011_full_name = szRegisteredOwner;
NetUserSetInfo(NULL, szUser, 1011, (LPBYTE) &usri1011, NULL);
}
// Add to administrators group
TCHAR szAdmins[GNLEN + 1];
if (GetAdministratorsGroupName(szAdmins, ARRAYSIZE(szAdmins)))
{
LOCALGROUP_MEMBERS_INFO_3 lgrmi3;
lgrmi3.lgrmi3_domainandname = szUser;
status = NetLocalGroupAddMembers(NULL, szAdmins, 3,
(LPBYTE) &lgrmi3, 1);
if (NERR_Success != status)
{
// Failure - Roll-back
// Delete this user since we couldn't add
// them to administrators
NetUserDel(NULL, szUser);
}
}
}
// Did we succeed? If not, show an error
switch ( status )
{
// Success conditions
case NERR_Success:
case ERROR_MEMBER_IN_GROUP:
case ERROR_MEMBER_IN_ALIAS:
{
hr = S_OK;
break;
}
default:
{
// Unexpected error
TCHAR szMessage[512];
DWORD dwFormatResult = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD) status, 0, szMessage, ARRAYSIZE(szMessage), NULL);
if (0 == dwFormatResult)
{
LoadString(g_hInstance, IDS_ERR_UNEXPECTED, szMessage, ARRAYSIZE(szMessage));
}
::DisplayFormatMessage(hwnd, IDS_ERR_CAPTION, IDS_ERR_ADDUSER, MB_OK|MB_ICONERROR, szMessage);
hr = E_FAIL;
break;
}
}
#endif //DONT_JOIN
return hr;
}
/*
/ Intro page to the wizard.
/*/
INT_PTR CALLBACK _IntroDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch ( uMsg )
{
case WM_INITDIALOG:
{
SendDlgItemMessage(hwnd, IDC_TITLE, WM_SETFONT, (WPARAM)GetIntroFont(hwnd), 0);
return TRUE;
}
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_SETACTIVE:
SetWizardButtons(hwnd, PSWIZB_NEXT);
return TRUE;
case PSN_WIZNEXT:
{
switch ( g_uWizardIs )
{
case NAW_PSDOMAINJOINED:
WizardNext(hwnd, IDD_PSW_ADDUSER);
break;
case NAW_PSWORKGROUP:
WizardNext(hwnd, IDD_PSW_AUTOLOGON);
break;
default:
// Let the wizard go to the next page
break;
}
return TRUE;
}
}
break;
}
}
return FALSE;
}
/*
/ Get the usage of the computer: corp vs home
/*/
INT_PTR CALLBACK _HowUseDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch ( uMsg )
{
case WM_INITDIALOG:
CheckRadioButton(hwnd, IDC_NETWORKED, IDC_NOTNETWORKED, IDC_NETWORKED);
return TRUE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_SETACTIVE:
SetWizardButtons(hwnd, PSWIZB_NEXT|PSWIZB_BACK);
return TRUE;
case PSN_WIZBACK:
WizardNext(hwnd, IDD_PSW_WELCOME);
return TRUE;
case PSN_WIZNEXT:
{
if ( IsDlgButtonChecked(hwnd, IDC_NETWORKED) == BST_CHECKED )
{
WizardNext(hwnd, IDD_PSW_WHICHNET);
}
else
{
g_dwWhichNet = IDC_NONE;
if ( SUCCEEDED(JoinDomain(hwnd, FALSE, DEFAULT_WORKGROUP, NULL)) )
WizardNext(hwnd, IDD_PSW_AUTOLOGON);
else
WizardNext(hwnd, -1);
}
return TRUE;
}
}
break;
}
}
return FALSE;
}
/*
/ Determine what sort of networking the user wants to use (domain, workgroup
/ or none).
/
/*/
INT_PTR CALLBACK _WhichNetDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch ( uMsg )
{
case WM_INITDIALOG:
CheckRadioButton(hwnd, IDC_DOMAIN, IDC_WORKGROUP, IDC_DOMAIN);
return TRUE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_SETACTIVE:
SetWizardButtons(hwnd, PSWIZB_NEXT|PSWIZB_BACK);
return TRUE;
case PSN_WIZBACK:
WizardNext(hwnd, IDD_PSW_HOWUSE);
return TRUE;
case PSN_WIZNEXT:
{
if ( IsDlgButtonChecked(hwnd, IDC_DOMAIN) == BST_CHECKED )
{
g_dwWhichNet = IDC_DOMAIN;
WizardNext(hwnd, IDD_PSW_DOMAININFO);
}
else
{
g_dwWhichNet = IDC_WORKGROUP;
WizardNext(hwnd, IDD_PSW_WORKGROUP);
}
return TRUE;
}
}
break;
}
}
return FALSE;
}
/*
/ Allow the user to change the workgroup name.
/*/
BOOL _WorkgroupBtnState(HWND hwnd)
{
DWORD dwButtons = PSWIZB_NEXT|PSWIZB_BACK;
if ( !FetchTextLength(hwnd, IDC_WORKGROUP) )
dwButtons &= ~PSWIZB_NEXT;
SetWizardButtons(hwnd, dwButtons);
return TRUE;
}
INT_PTR CALLBACK _WorkgroupDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch ( uMsg )
{
case WM_INITDIALOG:
{
Edit_LimitText(GetDlgItem(hwnd, IDC_WORKGROUP), MAX_COMPUTERNAME);
SetDlgItemText(hwnd, IDC_WORKGROUP, DEFAULT_WORKGROUP);
return TRUE;
}
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_SETACTIVE:
return _WorkgroupBtnState(hwnd);
case PSN_WIZBACK:
WizardNext(hwnd, IDD_PSW_WHICHNET);
return TRUE;
case PSN_WIZNEXT:
{
WCHAR szWorkgroup[MAX_WORKGROUP+1];
FetchText(hwnd, IDC_WORKGROUP, szWorkgroup, ARRAYSIZE(szWorkgroup));
if ( SUCCEEDED(JoinDomain(hwnd, FALSE, szWorkgroup, NULL)) )
{
ClearAutoLogon();
WizardNext(hwnd, IDD_PSW_DONE);
}
else
{
WizardNext(hwnd, -1);
}
return TRUE;
}
}
break;
}
case WM_COMMAND:
{
if ( HIWORD(wParam) == EN_CHANGE )
return _WorkgroupBtnState(hwnd);
break;
}
}
return FALSE;
}
/*
/ Handle the auto logon page
/*/
VOID _SetAutoLogonCtrls(HWND hwnd)
{
BOOL fDisable = IsDlgButtonChecked(hwnd, IDC_NOAUTOLOGON) == BST_CHECKED;
EnableWindow(GetDlgItem(hwnd, IDC_USERS), !fDisable);
EnableWindow(GetDlgItem(hwnd, IDC_USERSLABEL), !fDisable);
EnableWindow(GetDlgItem(hwnd, IDC_PASSWORD), !fDisable);
EnableWindow(GetDlgItem(hwnd, IDC_PASSWORDLABEL), !fDisable);
EnableWindow(GetDlgItem(hwnd, IDC_CONFIRMPASSWORD), !fDisable);
EnableWindow(GetDlgItem(hwnd, IDC_CONFIRMPASSWORDLABEL), !fDisable);
}
BOOL _InitAutoLogonDlg(HWND hwnd)
{
HWND hwndUsers = GetDlgItem(hwnd, IDC_USERS);
NET_API_STATUS status;
USER_INFO_1 *pbuff;
DWORD dwResume = 0;
DWORD dwCount, dwEntries;
// set the auto logon state
CheckRadioButton(hwnd, IDC_NOAUTOLOGON, IDC_AUTOLOGON, (g_uWizardIs == NAW_PSWORKGROUP) ? IDC_AUTOLOGON : IDC_NOAUTOLOGON);
_SetAutoLogonCtrls(hwnd);
// enumerate the local users of this machine and add them to the
// combo box.
do
{
status = NetUserEnum(NULL, 1, FILTER_NORMAL_ACCOUNT, (LPBYTE *)&pbuff, 8192, &dwCount, &dwEntries, &dwResume);
if ((status == NERR_Success) || (status == ERROR_MORE_DATA))
{
DWORD i;
for ( i = 0 ; i < dwCount ; i++ )
{
if ( !(pbuff[i].usri1_flags & UF_ACCOUNTDISABLE) )
ComboBox_AddString(hwndUsers, pbuff[i].usri1_name);
}
NetApiBufferFree(pbuff);
}
}
while ( dwCount != dwEntries );
// Select the first item, although we may override this with the default local user in a sec.
ComboBox_SetCurSel(hwndUsers, 0);
// If required, add the special default local user entry
if (g_uWizardIs == NAW_PSWORKGROUP)
{
// Add a special default local user string - user isn't actually created
// until Next is clicked.
TCHAR szUser[MAX_USER + 1];
if (SUCCEEDED(GetDefaultLocalUserName(szUser, ARRAYSIZE(szUser))))
{
// Don't add this user if he already exists. This is a weird situation since
// we only expect to run at first boot, but handle it anyway.
int iItem = ComboBox_FindStringExact(hwndUsers, -1, szUser);
if (iItem == CB_ERR)
{
iItem = ComboBox_AddString(hwndUsers, szUser);
if (iItem != CB_ERR)
{
// Mark this item as the default local user guy.
ComboBox_SetItemData(hwndUsers, iItem, ITEMDATA_DEFAULTLOCALUSER);
}
}
if (iItem != CB_ERR)
{
// Select it, its the default!
ComboBox_SetCurSel(hwndUsers, iItem);
}
}
}
// limit the length of the password fields accordingly
Edit_LimitText(GetDlgItem(hwnd, IDC_PASSWORD), PWLEN);
Edit_LimitText(GetDlgItem(hwnd, IDC_CONFIRMPASSWORD), PWLEN);
// enable/disable buttons accordingly
_SetAutoLogonCtrls(hwnd);
return TRUE;
}
INT_PTR CALLBACK _AutoLogonDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch ( uMsg )
{
case WM_INITDIALOG:
return _InitAutoLogonDlg(hwnd);
case WM_COMMAND:
{
switch ( LOWORD(wParam) )
{
case IDC_AUTOLOGON:
case IDC_NOAUTOLOGON:
_SetAutoLogonCtrls(hwnd);
break;
}
break;
}
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_QUERYINITIALFOCUS:
// Set focus to the password control if we are going to try to do the autologon thing
SetWindowLongPtr(hwnd, DWLP_MSGRESULT,
(LONG_PTR) ((g_uWizardIs == NAW_PSWORKGROUP) ? GetDlgItem(hwnd, IDC_PASSWORD) : 0)
);
return TRUE;
case PSN_SETACTIVE:
SetWizardButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT);
return TRUE;
case PSN_WIZBACK:
{
switch ( g_dwWhichNet )
{
case IDC_WORKGROUP:
WizardNext(hwnd, IDD_PSW_WORKGROUP);
break;
case IDC_NONE:
WizardNext(hwnd, IDD_PSW_HOWUSE);
break;
}
return TRUE;
}
case PSN_WIZNEXT:
{
WCHAR szUser[MAX_USER + 1] = { 0 };
WCHAR szPassword[MAX_PASSWORD + 1] = { 0 };
WCHAR szConfirmPwd[MAX_PASSWORD + 1] = { 0 };
if ( IsDlgButtonChecked(hwnd, IDC_NOAUTOLOGON) == BST_CHECKED )
{
// clear the auto admin logon
ClearAutoLogon();
}
else
{
// read the two passwords, check they match, if then don't tell
// the user clear them and prompt again. if they do then
// we can continue.
HWND hwndUsers = GetDlgItem(hwnd, IDC_USERS);
ComboBox_GetText(hwndUsers, szUser, ARRAYSIZE(szUser));
FetchText(hwnd, IDC_PASSWORD, szPassword, ARRAYSIZE(szPassword));
FetchText(hwnd, IDC_CONFIRMPASSWORD, szConfirmPwd, ARRAYSIZE(szConfirmPwd));
if ( StrCmpW(szPassword, szConfirmPwd) )
{
ShellMessageBox(GLOBAL_HINSTANCE, hwnd,
MAKEINTRESOURCE(IDS_ERR_PWDNOMATCH),
MAKEINTRESOURCE(IDS_AUTOLOGON),
MB_OK|MB_ICONWARNING);
SetFocus(GetDlgItem(hwnd, IDC_PASSWORD));
SetDlgItemText(hwnd, IDC_PASSWORD, L"");
SetDlgItemText(hwnd, IDC_CONFIRMPASSWORD, L"");
WizardNext(hwnd, -1);
}
else
{
// The passwords match - create the default local user if appropriate
// Is this the default boy?
HRESULT hr = S_OK;
int iItem = ComboBox_GetCurSel(hwndUsers);
if (iItem != CB_ERR)
{
if (ITEMDATA_DEFAULTLOCALUSER == ComboBox_GetItemData(hwndUsers, iItem))
{
hr = CreateLocalAdminUser(hwnd, szUser, szPassword);
}
}
if (SUCCEEDED(hr))
{
SetAutoLogon(szUser, szPassword);
WizardNext(hwnd, IDD_PSW_DONE);
}
else
{
WizardNext(hwnd, -1);
}
}
}
return TRUE;
}
}
break;
}
}
return FALSE;
}
/*
/ The wizard is complete, so lets allow them to back up if they want,
/ otherwise "Next" becomes "Finish" and we exit.
/*/
INT_PTR CALLBACK _DoneDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch ( uMsg )
{
case WM_INITDIALOG:
SendDlgItemMessage(hwnd, IDC_TITLE, WM_SETFONT, (WPARAM)GetIntroFont(hwnd), 0);
return TRUE;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_SETACTIVE:
{
TCHAR szBuffer[MAX_PATH];
// change the closing prompt if we are supposed to be
LoadString(GLOBAL_HINSTANCE,
g_fRebootOnExit ? IDS_NETWIZFINISHREBOOT:IDS_NETWIZFINISH,
szBuffer, ARRAYSIZE(szBuffer));
SetDlgItemText(hwnd, IDC_FINISHSTATIC, szBuffer);
SetWizardButtons(hwnd, PSWIZB_BACK|PSWIZB_FINISH);
g_fShownLastPage = TRUE; // show the last page of the wizard
return TRUE;
}
case PSN_WIZBACK:
{
switch ( g_dwWhichNet )
{
case IDC_DOMAIN:
WizardNext(hwnd, IDD_PSW_ADDUSER);
break;
case IDC_WORKGROUP:
WizardNext(hwnd, IDD_PSW_WORKGROUP);
break;
case IDC_NONE:
WizardNext(hwnd, IDD_PSW_AUTOLOGON);
break;
}
return TRUE;
}
}
break;
}
}
return FALSE;
}
/*
/ Main entry point used to invoke the wizard.
/*/
static WNDPROC _oldDlgWndProc;
LRESULT CALLBACK _WizardSubWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// on WM_WINDOWPOSCHANGING and the window is moving then lets centre it onto the
// desktop window. unfortunately setting the DS_CENTER bit doesn't buy us anything
// as the wizard is resized after creation.
if ( uMsg == WM_WINDOWPOSCHANGING )
{
LPWINDOWPOS lpwp = (LPWINDOWPOS)lParam;
RECT rcDlg, rcDesktop;
GetWindowRect(hwnd, &rcDlg);
GetWindowRect(GetDesktopWindow(), &rcDesktop);
lpwp->x = ((rcDesktop.right-rcDesktop.left)-(rcDlg.right-rcDlg.left))/2;
lpwp->y = ((rcDesktop.bottom-rcDesktop.top)-(rcDlg.bottom-rcDlg.top))/2;
lpwp->flags &= ~SWP_NOMOVE;
}
return _oldDlgWndProc(hwnd, uMsg, wParam, lParam);
}
int CALLBACK _PropSheetCB(HWND hwnd, UINT uMsg, LPARAM lParam)
{
switch ( uMsg )
{
// in pre-create lets set the window styles accorindlgy
// - remove the context menu and system menu
case PSCB_PRECREATE:
{
DLGTEMPLATE *pdlgtmp = (DLGTEMPLATE*)lParam;
pdlgtmp->style &= ~(DS_CONTEXTHELP|WS_SYSMENU);
break;
}
// we now have a dialog, so lets sub class it so we can stop it being
// move around.
case PSCB_INITIALIZED:
{
if ( g_uWizardIs != NAW_NETID )
_oldDlgWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)_WizardSubWndProc);
break;
}
}
return FALSE;
}
// The global group page base object used by the domain wizard
// defined in domain.cpp
extern CGroupPageBase* g_pGroupPageBase;
STDAPI NetAccessWizard(HWND hwnd, UINT uType, BOOL *pfReboot)
{
PROPSHEETHEADER psh = { 0 };
HPROPSHEETPAGE rghpage[ARRAYSIZE(pages)];
INT cPages = 0;
INITCOMMONCONTROLSEX iccex = { 0 };
iccex.dwSize = sizeof (iccex);
iccex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&iccex);
// decode the type and set our state accordingly
switch ( uType )
{
case NAW_NETID:
break;
case NAW_PSWORKGROUP:
case NAW_PSDOMAINJOINFAILED:
g_dwWhichNet = IDC_NONE;
g_uWizardIs = uType;
break;
case NAW_PSDOMAINJOINED:
g_dwWhichNet = IDC_DOMAIN;
g_uWizardIs = uType;
break;
default:
return E_INVALIDARG;
}
// build the pages for the wizard.
for ( cPages = 0 ; cPages < ARRAYSIZE(pages) ; cPages++ )
{
PROPSHEETPAGE psp = { 0 };
WCHAR szBuffer[MAX_PATH] = { 0 };
psp.dwSize = SIZEOF(PROPSHEETPAGE);
psp.hInstance = GLOBAL_HINSTANCE;
psp.lParam = cPages;
psp.dwFlags = PSP_USETITLE | PSP_DEFAULT | PSP_USEHEADERTITLE |
PSP_USEHEADERSUBTITLE | pages[cPages].dwFlags;
psp.pszTemplate = pages[cPages].idPage;
psp.pfnDlgProc = pages[cPages].pDlgProc;
psp.pszTitle = MAKEINTRESOURCE(IDS_NETWIZCAPTION);
psp.pszHeaderTitle = pages[cPages].pHeading;
psp.pszHeaderSubTitle = pages[cPages].pSubHeading;
rghpage[cPages] = CreatePropertySheetPage(&psp);
}
// wizard pages are ready, so lets display the wizard.
psh.dwSize = SIZEOF(PROPSHEETHEADER);
psh.hwndParent = hwnd;
psh.hInstance = GLOBAL_HINSTANCE;
psh.dwFlags = PSH_WIZARD | PSH_WIZARD97 | PSH_WATERMARK |
PSH_STRETCHWATERMARK | PSH_HEADER | PSH_USECALLBACK;
psh.pszbmHeader = MAKEINTRESOURCE(IDB_PSW_BANNER);
psh.pszbmWatermark = MAKEINTRESOURCE(IDB_PSW_WATERMARK);
psh.nPages = cPages;
psh.phpage = rghpage;
psh.pfnCallback = _PropSheetCB;
// Create the global CGroupPageBase object if necessary
CGroupInfoList grouplist;
if (SUCCEEDED(grouplist.Initialize()))
{
g_pGroupPageBase = new CGroupPageBase(NULL, &grouplist);
if (NULL != g_pGroupPageBase)
{
PropertySheetIcon(&psh, MAKEINTRESOURCE(IDI_PSW));
delete g_pGroupPageBase;
}
}
// Hang up the all RAS connections if the wizard created one. It is assumed that no non-wizard connections will
// exist at this time. 90% of the time, they've just changed their domain membership anyway to they will
// be just about to reboot. Hanging up all connections MAY cause trouble if: There were existing connections
// before the pre-logon wizard started AND the user cancelled after making connections with the wizard but before
// changing their domain. There are no situations where this currently happens.
if (g_fWizardCreatedRASConnection)
{
RASCONN* prgrasconn = (RASCONN*) LocalAlloc(0, sizeof(RASCONN));
if (NULL != prgrasconn)
{
prgrasconn[0].dwSize = sizeof(RASCONN);
DWORD cb = sizeof(RASCONN);
DWORD nConn = 0;
DWORD dwSuccess = RasEnumConnections(prgrasconn, &cb, &nConn);
if (ERROR_BUFFER_TOO_SMALL == dwSuccess)
{
LocalFree(prgrasconn);
prgrasconn = (RASCONN*) LocalAlloc(0, cb);
if (NULL != prgrasconn)
{
prgrasconn[0].dwSize = sizeof(RASCONN);
dwSuccess = RasEnumConnections(prgrasconn, &cb, &nConn);
}
}
if (0 == dwSuccess)
{
// Make sure we have one and only one connection before hanging up
for (DWORD i = 0; i < nConn; i ++)
{
RasHangUp(prgrasconn[i].hrasconn);
}
}
LocalFree(prgrasconn);
}
}
// restart the machine if we need to, eg: the domain changed
if ( pfReboot )
*pfReboot = g_fRebootOnExit;
// if this is coming from setup, then lets display the message
if ( g_fRebootOnExit && !g_fShownLastPage && (g_uWizardIs != NAW_NETID) )
{
ShellMessageBox(GLOBAL_HINSTANCE,
hwnd,
MAKEINTRESOURCE(IDS_RESTARTREQUIRED), MAKEINTRESOURCE(IDS_NETWIZCAPTION),
MB_OK);
}
return S_OK;
}
void APIENTRY NetAccWizRunDll(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
{
UINT uType = 0;
if ( *pszCmdLine )
uType = StrToIntA(pszCmdLine);
NetAccessWizard(hwndStub, uType, NULL);
}