windows-nt/Source/XPSP1/NT/net/config/shell/netsetup/wjoin.cpp

2485 lines
73 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "pch.h"
#pragma hdrstop
#include <ntsam.h>
#include <lmerr.h>
#include <wincred.h>
#include "afilexp.h"
#include "dsgetdc.h"
#include "ncatlui.h"
#include "nccom.h"
#include "nceh.h"
#include "ncerror.h"
#include "ncident.h"
#include "ncmisc.h"
#include "ncreg.h"
#include "ncsetup.h"
#include "ncsvc.h"
#include "ncui.h"
#include "resource.h"
#include "wizard.h"
#include "nslog.h"
#include "windns.h"
// header filename clash between config\inc\netsetup.h and
// private\net\inc\netsetup.h where this prototype lives.
// fix later.
//
EXTERN_C
NET_API_STATUS
NET_API_FUNCTION
NetpUpgradePreNT5JoinInfo( VOID );
// Setup Wizard Global - Only used during setup.
extern CWizard * g_pSetupWizard;
//
// NOTE: Set breakpoints in JoinDomainWorkThrd if debugging join problems
//
static const UINT PWM_JOINFAILURE = WM_USER+1201;
static const UINT PWM_JOINSUCCESS = WM_USER+1202;
static const INT MAX_USERNAME_LENGTH = UNLEN;
// the number of bytes in a full DNS name to reserve for stuff
// netlogon pre-/appends to DNS names when registering them
static const INT SRV_RECORD_RESERVE = 100;
static const INT MAX_DOMAINNAME_LENGTH = DNS_MAX_NAME_LENGTH - SRV_RECORD_RESERVE;
static const INT MAX_WORKGROUPNAME_LENGTH = 15;
static const INT MAX_TITLEBASE = 128;
static const INT MAX_TITLENEW = 256;
static const INT MAX_NAME_LENGTH = max( max( max( SAM_MAX_PASSWORD_LENGTH,
MAX_USERNAME_LENGTH ),
MAX_COMPUTERNAME_LENGTH ),
MAX_DOMAINNAME_LENGTH) + 1;
const int nrgIdc[] = {EDT_WORKGROUPJOIN_NAME, EDT_DOMAINJOIN_NAME, BTN_JOIN_WORKGROUP, BTN_JOIN_DOMAIN, TXT_JOIN_WORKGROUP_LINE2};
const int nrgIdcWorkgroup[] = {EDT_WORKGROUPJOIN_NAME};
const int nrgIdcDomain[] = {EDT_DOMAINJOIN_NAME};
const c_dwDomainJoinWaitDelay = 10000;
static const WCHAR c_szNetMsg[] = L"netmsg.dll";
static const WCHAR c_szIpParameters[] = L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters";
static const WCHAR c_szSyncDomainWithMembership[] = L"SyncDomainWithMembership";
static const WCHAR c_szWinlogonPath[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon";
static const WCHAR c_szRunNetAccessWizard[] = L"RunNetAccessWizard";
static const WCHAR c_szAfSectionGuiUnattended[] = L"GuiUnattended";
static const WCHAR c_szAfAutoLogonAccountCreation[] = L"AutoLogonAccountCreation";
extern const WCHAR c_szAfSectionIdentification[]; // L"Identification";
extern const WCHAR c_szAfComputerName[]; // L"ComputerName";
extern const WCHAR c_szAfJoinWorkgroup[]; // L"JoinWorkgroup";
extern const WCHAR c_szAfJoinDomain[]; // L"JoinDomain";
extern const WCHAR c_szAfDomainAdmin[]; // L"DomainAdmin";
extern const WCHAR c_szAfDomainAdminPassword[]; // L"DomainAdminPassword";
extern const WCHAR c_szAfSectionNetworking[]; // L"Networking";
extern const WCHAR c_szAfUpgradeFromProduct[]; // L"UpgradeFromProduct";
extern const WCHAR c_szAfWin95[]; // L"Windows95";
extern const WCHAR c_szSvcWorkstation[]; // L"LanmanWorkstation";
extern const WCHAR c_szAfMachineObjectOU[]; // L"MachineObjectOU";
extern const WCHAR c_szAfUnsecureJoin[]; // L"DoOldStyleDomainJoin";
extern const WCHAR c_szAfBuildNumber[]; // L"BuildNumber";
// For Secure Domain Join Support, the computer account password
extern const WCHAR c_szAfComputerPassword[]; // L"ComputerPassword";
typedef struct _tagJoinData
{
BOOL fUpgraded;
BOOL fUnattendedFailed;
CNetCfgIdentification * pIdent;
HCURSOR hClassCursor;
HCURSOR hOldCursor;
// Used by join thread
//
HWND hwndDlg;
// Set from answer file or user input then supplied to the join thread
// as the join parameters
//
DWORD dwJoinFlag;
WCHAR szUserName[MAX_USERNAME_LENGTH + 1];
WCHAR szPassword[SAM_MAX_PASSWORD_LENGTH + 1];
WCHAR szDomain[MAX_DOMAINNAME_LENGTH + 1];
WCHAR szComputerPassword[SAM_MAX_PASSWORD_LENGTH + 1];
WCHAR * pszMachineObjectOU;
} JoinData;
typedef enum
{
PSW_JOINEDDOMAIN = 2,
PSW_JOINFAILED = 3
} POSTSETUP_STATE;
//
// Function: IsRunningOnPersonal
//
// Purpose: Determines whether running on Whistler Personal
//
// Returns: Returns true if running on Personal - FALSE otherwise
BOOL
IsRunningOnPersonal(
VOID
)
{
TraceFileFunc(ttidGuiModeSetup);
OSVERSIONINFOEXW OsVer = {0};
ULONGLONG ConditionMask = 0;
OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
OsVer.wSuiteMask = VER_SUITE_PERSONAL;
OsVer.wProductType = VER_NT_WORKSTATION;
VER_SET_CONDITION(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_AND);
return VerifyVersionInfo(&OsVer,
VER_PRODUCT_TYPE | VER_SUITENAME,
ConditionMask
);
}
//
// Function: IsValidDomainName
//
// Purpose: Determines whether the domain name is valid.
//
// Returns: See win32 documentation on DnsValidateName.
//
// Author: Alok Sinha
//
DNS_STATUS IsValidDomainName (HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
WCHAR szDomain[MAX_DOMAINNAME_LENGTH+1];
HWND hwndEdit;
hwndEdit = GetDlgItem(hwndDlg, EDT_DOMAINJOIN_NAME);
Assert(0 != GetWindowTextLength(hwndEdit));
GetWindowText(hwndEdit, szDomain, MAX_DOMAINNAME_LENGTH + 1);
return DnsValidateName( szDomain,
DnsNameDomain );
}
//
// Function: SetCursorToHourglass
//
// Purpose: Changes the cursor to hourglass.
//
// Returns: Nothing
//
// Author: asinha 3/28/2001
//
VOID SetCursorToHourglass (HWND hwndDlg, JoinData *pData)
{
TraceFileFunc(ttidGuiModeSetup);
Assert( pData != NULL);
if ( pData )
{
pData->hClassCursor = (HCURSOR)GetClassLongPtr( hwndDlg, GCLP_HCURSOR );
SetClassLongPtr( hwndDlg, GCLP_HCURSOR, (LONG_PTR)NULL );
pData->hOldCursor = SetCursor( LoadCursor(NULL,IDC_WAIT) );
SetCapture( hwndDlg );
}
return;
}
//
// Function: RestoreCursor
//
// Purpose: Changes the cursor back to its orginal state.
//
// Returns: Nothing
//
// Author: asinha 3/28/2001
//
VOID RestoreCursor (HWND hwndDlg, JoinData *pData)
{
TraceFileFunc(ttidGuiModeSetup);
Assert( pData != NULL);
if ( pData )
{
if ( pData->hClassCursor )
{
SetClassLongPtr( hwndDlg, GCLP_HCURSOR, (LONG_PTR)pData->hClassCursor );
pData->hClassCursor = NULL;
}
if ( pData->hOldCursor )
{
SetCursor( pData->hOldCursor );
pData->hOldCursor = NULL;
}
ReleaseCapture();
}
return;
}
//
// Function: NotifyPostSetupWizard
//
// Purpose: Subclass the edit control so we can enable/disable the
// Next button as the content of the name edit control changes
//
// Parameters: State - Final Join State
//
// Returns: nothing
//
VOID NotifyPostSetupWizard(POSTSETUP_STATE State, CWizard * pWizard)
{
TraceFileFunc(ttidGuiModeSetup);
HKEY hkey;
HRESULT hr = S_OK;
BOOL fRunNaWizard = TRUE;
CSetupInfFile csif;
// If this is an upgrade or an unattended install, or it's a server do nothing
//
if (IsUpgrade(pWizard) || IsUnattended(pWizard) || (PRODUCT_WORKSTATION != ProductType(pWizard)) )
{
fRunNaWizard = FALSE;
}
// Is there an unattended flag to override default behavior?
if (IsUnattended(pWizard))
{
hr = csif.HrOpen(pWizard->PSetupData()->UnattendFile,
NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
if (SUCCEEDED(hr))
{
BOOL fValue = FALSE;
hr = csif.HrGetStringAsBool(c_szAfSectionGuiUnattended,
c_szAfAutoLogonAccountCreation,
&fValue);
if (SUCCEEDED(hr) && fValue)
{
fRunNaWizard = fValue;
}
}
hr = S_OK;
}
if (fRunNaWizard)
{
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szWinlogonPath,
KEY_WRITE, &hkey);
if (SUCCEEDED(hr))
{
hr = HrRegSetDword (hkey, c_szRunNetAccessWizard, (DWORD)State);
TraceTag(ttidWizard, "NotifyPostSetupWizard - State = %d",(DWORD)State);
RegCloseKey(hkey);
}
}
TraceError("WJOIN.CPP - NotifyPostSetupWizard",hr);
}
//
// Function: JoinEditSubclassProc
//
// Purpose: Subclass the edit control so we can enable/disable the
// Next button as the content of the name edit control changes
//
// Parameters: std for a window proc
//
// Returns: std for a window proc
//
STDAPI JoinEditSubclassProc(HWND hwnd, UINT wMsg,
WPARAM wParam, LPARAM lParam)
{
TraceFileFunc(ttidGuiModeSetup);
LONG lReturn;
HWND hwndDlg = GetParent(hwnd);
lReturn = CallWindowProc((WNDPROC)::GetWindowLongPtr(hwnd, GWLP_USERDATA),
hwnd, wMsg, wParam, lParam);
// If we processing a character send the message through the regular proc
if (WM_CHAR == wMsg)
{
CWizard * pWizard =
reinterpret_cast<CWizard *> (::GetWindowLongPtr(hwndDlg, DWLP_USER));
Assert(NULL != pWizard);
if ( !pWizard )
{
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
return lReturn;
}
JoinData * pData = reinterpret_cast<JoinData *>
(pWizard->GetPageData(IDD_Join));
Assert(NULL != pData);
if ( !pData ) {
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
return lReturn;
}
if (!IsUnattended(pWizard) ||
(IsUnattended(pWizard) && pData->fUnattendedFailed))
{
if (0 == GetWindowTextLength(hwnd))
{
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
}
else
{
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
}
}
}
return lReturn;
}
HRESULT HrGetIdentInterface(CNetCfgIdentification ** ppIdent)
{
TraceFileFunc(ttidGuiModeSetup);
HRESULT hr = S_OK;
*ppIdent = new CNetCfgIdentification;
if (NULL == *ppIdent)
hr = E_OUTOFMEMORY;
TraceHr(ttidWizard, FAL, hr, FALSE, "HrGetIdentInterface");
return hr;
}
//
// Function: IdsFromIdentError
//
// Purpose: Map a error code into a display string.
//
// Parameters: hr [IN] - Error code to map
//
// Returns: INT, the string ID of the corresponding error message
//
INT IdsFromIdentError(HRESULT hr, BOOL fWorkgroup)
{
TraceFileFunc(ttidGuiModeSetup);
INT ids = -1;
switch (hr)
{
case HRESULT_FROM_WIN32(ERROR_NO_TRUST_SAM_ACCOUNT):
ids = IDS_DOMMGR_CANT_CONNECT_DC_PW;
break;
case HRESULT_FROM_WIN32(ERROR_BAD_NETPATH):
case HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN):
ids = IDS_DOMMGR_CANT_FIND_DC1;
break;
case HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD):
ids = IDS_DOMMGR_INVALID_PASSWORD;
break;
case HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE):
ids = IDS_DOMMGR_NETWORK_UNREACHABLE;
break;
case HRESULT_FROM_WIN32(ERROR_ACCOUNT_DISABLED):
case HRESULT_FROM_WIN32(ERROR_LOGON_FAILURE):
case HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED):
ids = IDS_DOMMGR_ACCESS_DENIED;
break;
case HRESULT_FROM_WIN32(ERROR_SESSION_CREDENTIAL_CONFLICT):
ids = IDS_DOMMGR_CREDENTIAL_CONFLICT;
break;
case NETCFG_E_ALREADY_JOINED:
ids = IDS_DOMMGR_ALREADY_JOINED;
break;
case NETCFG_E_NAME_IN_USE:
ids = IDS_DOMMGR_NAME_IN_USE;
break;
case NETCFG_E_NOT_JOINED:
ids = IDS_DOMMGR_NOT_JOINED;
break;
case NETCFG_E_INVALID_DOMAIN:
case HRESULT_FROM_WIN32(ERROR_INVALID_NAME):
if (fWorkgroup)
ids = IDS_DOMMGR_INVALID_WORKGROUP;
else
ids = IDS_DOMMGR_INVALID_DOMAIN;
break;
default:
ids = IDS_E_UNEXPECTED;
break;
}
return ids;
}
//
// Function: SzFromError
//
// Purpose: Convert an error code into a message displayable to the user.
// The error message could come from our resources, or from netmsg.dll
//
// Parameters: hr [IN] - The error to map
// fWorkgroup [IN] - Flag to provide "workgroup" flavored error
// messages for some cases.
//
// Returns: PCWSTR, Pointer to a static buffer containing the error message
//
PCWSTR SzFromError(HRESULT hr, BOOL fWorkgroup)
{
TraceFileFunc(ttidGuiModeSetup);
static WCHAR szErrorMsg[1024];
INT nIds = IdsFromIdentError(hr, fWorkgroup);
// If the error string returned is unexpected, it means we couldn't
// a local match for the string. Search netmsg.dll if the errors'
// range is correct
if (IDS_E_UNEXPECTED == nIds)
{
// Extract the error code from the HRESULT
DWORD dwErr = ((DWORD)hr & 0x0000FFFF);
if ((NERR_BASE <= dwErr) && (MAX_NERR >= dwErr))
{
// The error is within the range hosted by netmsg.dll
HMODULE hModule = LoadLibraryEx(c_szNetMsg, NULL,
LOAD_LIBRARY_AS_DATAFILE);
if (NULL != hModule)
{
// Try to locate the error string
DWORD dwRet = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_IGNORE_INSERTS,
(LPVOID)hModule,
dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
szErrorMsg, // Output buffer
1024, // szErrorMsg in characters.
NULL);
FreeLibrary(hModule);
if (dwRet)
{
// We successfully found an error message
// Remove the trailing newline that format message adds
// This string is concatenated with another and the newline
// messes up the appearance.
//
// Raid 146173 - scottbri
//
int nLen = wcslen(szErrorMsg);
if ((nLen>2) && (L'\r' == szErrorMsg[nLen-2]))
{
szErrorMsg[nLen-2] = 0;
}
return szErrorMsg;
}
}
}
else if ( (dwErr >= 9000) && (dwErr <= 9999) )
{
// The error code from 9000-9999 is dns error code in which
// case show the dns error message.
//
DWORD dwRet = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
(LPVOID)NULL,
dwErr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
szErrorMsg, // Output buffer
1024, // szErrorMsg in characters.
NULL);
if (dwRet)
{
// We successfully found an error message
// Remove the trailing newline that format message adds
int nLen = wcslen(szErrorMsg);
if ((nLen>2) && (L'\r' == szErrorMsg[nLen-2]))
{
szErrorMsg[nLen-2] = 0;
}
return szErrorMsg;
}
}
}
// Load the error found
wcscpy(szErrorMsg, SzLoadIds(nIds));
return szErrorMsg;
}
//
// Function: GetJoinNameIIDFromSelection
//
// Purpose: Get the edit box for the workgroup / domain dialog depending on the current user selection
//
// Parameters: hwndDlg - The join domain dialog
//
// Returns:
//
inline DWORD GetJoinNameIIDFromSelection(HWND hwndDlg)
{
if (IsDlgButtonChecked(hwndDlg, BTN_JOIN_WORKGROUP))
{
return EDT_WORKGROUPJOIN_NAME;
}
else
{
return EDT_DOMAINJOIN_NAME;
}
}
//
// Function: UpdateNextBackBttns
//
// Purpose:
//
// Parameters:
//
// Returns:
//
VOID UpdateNextBackBttns(HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
int b = PSWIZB_BACK;
if (0 != GetWindowTextLength(GetDlgItem(hwndDlg, GetJoinNameIIDFromSelection(hwndDlg))))
{
b |= PSWIZB_NEXT;
}
PropSheet_SetWizButtons(GetParent(hwndDlg), b);
}
//
// Function: EnableAndDisableWorkGroupDomainControls
//
// Purpose: Disable the domain/workgroup edit boxes depending on the current user selection
//
// Parameters: hwndDlg - The join domain dialog
//
// Returns:
//
VOID EnableAndDisableWorkGroupDomainControls(HWND hwndDlg)
{
if (IsDlgButtonChecked(hwndDlg, BTN_JOIN_WORKGROUP))
{
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdcWorkgroup), nrgIdcWorkgroup, TRUE);
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdcDomain), nrgIdcDomain, FALSE);
}
else
{
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdcDomain), nrgIdcDomain, TRUE);
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdcWorkgroup), nrgIdcWorkgroup, FALSE);
}
}
//
// Function: JoinUpdatePromptText
//
// Purpose: Update the prompt text
//
// Parameters: hwndDlg [IN] - Current dialog handle
//
// Returns: Nothing
//
VOID JoinUpdatePromptText(HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
HWND hwndDomain = NULL;
int idsNew = IDS_WORKGROUP;
int idsOld = IDS_DOMAIN;
WCHAR szDomain[MAX_DOMAINNAME_LENGTH + 1];
JoinData * pData=NULL;
CWizard * pWizard = NULL;
// Based on the button selected, update the Prompt text & dialog box
if (!IsDlgButtonChecked(hwndDlg, BTN_JOIN_WORKGROUP))
{
hwndDomain = GetDlgItem(hwndDlg, EDT_DOMAINJOIN_NAME);
idsNew = IDS_DOMAIN;
idsOld = IDS_WORKGROUP;
}
else
{
hwndDomain = GetDlgItem(hwndDlg, EDT_WORKGROUPJOIN_NAME);
}
Assert(NULL != hwndDomain);
EnableAndDisableWorkGroupDomainControls(hwndDlg);
// Update the domain/workgroup only if the current contents
// are the default workgroup/domain
GetWindowText(hwndDomain, szDomain, celems(szDomain));
if (0 == lstrcmpW(szDomain, SzLoadIds(idsOld)))
{
SetWindowText(hwndDomain, SzLoadIds(idsNew));
}
// Update the back/next buttons based on the selected button. See bug 355978
pWizard = (CWizard *) ::GetWindowLongPtr(hwndDlg, DWLP_USER);
Assert(NULL != pWizard);
if ( pWizard)
{
pData = (JoinData *) pWizard->GetPageData(IDD_Join);
Assert(NULL != pData);
}
if ( pWizard && pData )
{
if (!IsUnattended(pWizard) ||
(IsUnattended(pWizard) && pData->fUnattendedFailed))
{
if (0 == GetWindowTextLengthW(hwndDomain))
{
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
}
else
{
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
}
}
}
}
//
// Function: UpdateJoinUsingComputerRole
//
// Purpose:
//
// Parameters:
//
// Returns:
//
VOID UpdateJoinUsingComputerRole(HWND hwndDlg,
CWizard * pWizard)
{
TraceFileFunc(ttidGuiModeSetup);
HRESULT hr;
INetCfg * pNetCfg = pWizard->PNetCfg();
JoinData * pData = reinterpret_cast<JoinData *>
(pWizard->GetPageData(IDD_Join));
Assert(NULL != pNetCfg);
Assert(NULL != pData);
Assert(NULL != pData->pIdent);
PWSTR pszwText = NULL;
DWORD computer_role;
int nIdc;
Assert(NULL != pData->pIdent);
if(!pData || !pData->pIdent)
{
return;
}
hr = pData->pIdent->GetComputerRole(&computer_role);
if (SUCCEEDED(hr))
{
if (computer_role & GCR_STANDALONE)
{
// Get the workgroup name
hr = pData->pIdent->GetWorkgroupName(&pszwText);
Assert(NULL != pszwText);
Assert(lstrlenW(pszwText) <= MAX_WORKGROUPNAME_LENGTH);
nIdc = BTN_JOIN_WORKGROUP;
}
else
{
// Get the domain name
hr = pData->pIdent->GetDomainName(&pszwText);
Assert(NULL != pszwText);
Assert(lstrlenW(pszwText) <= MAX_DOMAINNAME_LENGTH);
nIdc = BTN_JOIN_DOMAIN;
}
}
if (SUCCEEDED(hr))
{
HWND hwndEdit = GetDlgItem(hwndDlg, nIdc == BTN_JOIN_DOMAIN ? EDT_DOMAINJOIN_NAME : EDT_WORKGROUPJOIN_NAME);
Assert(NULL != hwndEdit);
SetWindowText(hwndEdit, pszwText);
CoTaskMemFree(pszwText);
CheckRadioButton(hwndDlg, BTN_JOIN_WORKGROUP,
BTN_JOIN_DOMAIN, nIdc);
}
else
{
HWND hwndEdit = GetDlgItem(hwndDlg, EDT_WORKGROUPJOIN_NAME);
Assert(NULL != hwndEdit);
SetWindowText(hwndEdit, SzLoadIds(IDS_WORKGROUP));
CheckRadioButton(hwndDlg, BTN_JOIN_WORKGROUP,
BTN_JOIN_DOMAIN, BTN_JOIN_WORKGROUP);
TraceHr(ttidWizard, FAL, hr, FALSE,
"UpdateJoinUsingComputerRole - Unable to determine role, using default");
}
JoinUpdatePromptText(hwndDlg);
}
//
// Function: JoinDefaultWorkgroup
//
// Purpose: Join the machine to the workgroup "WORKGROUP"
//
// Parameters: pWizard [IN] - Ptr to a wizard instance, containing
// hopefully a INetCfg instance pointer
// hwndDlg [IN] - HWND to parent error dialogs against
//
// Returns: nothing
//
void JoinDefaultWorkgroup(CWizard *pWizard, HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
// Join default workgroup.
CNetCfgIdentification *pINetid = NULL;
HRESULT hr = S_OK;
hr = HrGetIdentInterface(&pINetid);
if (S_OK == hr)
{
if (IsRunningOnPersonal())
{
hr = pINetid->JoinWorkgroup(SzLoadIds(IDS_WORKGROUP_PERSONAL));
}
else
{
hr = pINetid->JoinWorkgroup(SzLoadIds(IDS_WORKGROUP));
}
if (SUCCEEDED(hr))
{
hr = pINetid->Validate();
if (SUCCEEDED(hr))
{
hr = pINetid->Apply();
}
}
if (FAILED(hr))
{
if (UM_FULLUNATTENDED == pWizard->GetUnattendedMode())
{
// Raid 380374: no UI allowed if in full unattended mode ..
NetSetupLogStatusV( LogSevError,
SzLoadIds (IDS_E_UNATTENDED_JOIN_DEFAULT_WROKGROUP));
}
else
{
MessageBox(GetParent(hwndDlg), SzFromError(hr, TRUE),
SzLoadIds(IDS_SETUP_CAPTION), MB_OK);
}
goto Done;
}
}
else
{
AssertSz(0,"Cannot find the INegCfgIdentification interface!");
}
Done:
delete pINetid;
TraceHr(ttidWizard, FAL, hr, FALSE, "JoinDefaultWorkgroup");
}
BOOL OnJoinSuccess(HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
CWizard * pWizard =
reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
Assert(NULL != pWizard);
if ( !pWizard ) {
return TRUE;
}
// Reset the Wait Cursor
JoinData * pData = reinterpret_cast<JoinData *>
(pWizard->GetPageData(IDD_Join));
Assert(NULL != pData);
if ( !pData ) {
return TRUE;
}
RestoreCursor( hwndDlg, pData );
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdc), nrgIdc, TRUE);
EnableAndDisableWorkGroupDomainControls(hwndDlg);
if (!(IsUnattended(pWizard) && pData->fUpgraded))
{
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
}
// Goto the Exit page
pWizard->SetPageDirection(IDD_Join, NWPD_BACKWARD);
HPROPSHEETPAGE hPage = pWizard->GetPageHandle(IDD_Exit);
PostMessage(GetParent(hwndDlg), PSM_SETCURSEL, 0,
(LPARAM)(HPROPSHEETPAGE)hPage);
return TRUE;
}
BOOL OnJoinFailure(HWND hwndDlg, LPARAM lParam)
{
TraceFileFunc(ttidGuiModeSetup);
JoinData * pData = NULL;
BOOL fWorkgroup;
tstring str;
HRESULT hr = (HRESULT)lParam;
CWizard * pWizard =
reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
Assert(NULL != pWizard);
if (pWizard)
{
pData = reinterpret_cast<JoinData *>(pWizard->GetPageData(IDD_Join));
Assert(NULL != pData);
}
fWorkgroup = !IsDlgButtonChecked(hwndDlg, BTN_JOIN_DOMAIN);
if (fWorkgroup)
{
str = SzLoadIds(IDS_JOIN_E_WORKGROUP_MSG);
}
else
{
if (pData && (pData->dwJoinFlag & JDF_WIN9x_UPGRADE))
{
str = SzLoadIds(IDS_JOIN_E_DOMAIN_WIN9X_MSG_1);
str += SzLoadIds(IDS_JOIN_E_DOMAIN_WIN9X_MSG_2);
}
else
{
// Raid 372087: removed additional text
str = SzLoadIds(IDS_JOIN_E_DOMAIN_MSG);
}
}
// If an error actually occurred, ask the user if they want to ignore
// the error and proceed. Note Unattended can succeed but require us
// to stay on the page so this function is envoked to do this.
if (FAILED(hr))
{
if (IDYES == NcMsgBox(GetParent(hwndDlg),
IDS_SETUP_CAPTION, IDS_JOIN_FAILURE,
MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
SzFromError(hr, fWorkgroup), str.c_str()))
{
// User choose to proceed in spite of the failure, go to the Exit page
if (!fWorkgroup)
{
NotifyPostSetupWizard(PSW_JOINFAILED, pWizard);
}
OnJoinSuccess(hwndDlg);
return TRUE;
}
}
if (pData)
{
// Reset the Wait Cursor
RestoreCursor( hwndDlg, pData );
}
// Make sure the page is visible.
if (g_pSetupWizard != NULL)
{
g_pSetupWizard->PSetupData()->ShowHideWizardPage(TRUE);
}
// The user wants to stay and correct whatever's wrong
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdc), nrgIdc, TRUE);
EnableAndDisableWorkGroupDomainControls(hwndDlg);
UpdateNextBackBttns(hwndDlg);
return TRUE;
}
// ONLY return failure if the workstation is installed and it doesn't start for 2 minutes
HRESULT HrWorkstationStart(HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
HRESULT hr = S_OK;
HRESULT hrTmp;
CServiceManager scm;
TraceTag(ttidWizard, "Entering HrWorkstationStart...Checking for LanmanWorkstation presence");
// Open the service control manager
//
hrTmp = scm.HrOpen();
if (SUCCEEDED(hrTmp))
{
// Find the workstation service
//
SC_HANDLE hSvc = OpenService (scm.Handle(),
c_szSvcWorkstation,
SERVICE_QUERY_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_START | SERVICE_STOP |
SERVICE_USER_DEFINED_CONTROL);
if (hSvc)
{
SERVICE_STATUS status;
const UINT cmsWait = 100;
const UINT cmsTotal = 120000; // 2 minutes
UINT cLoop = cmsTotal / cmsWait;
// Check it's status, exit test once it's running
//
for (UINT nLoop = 0; nLoop < cLoop; nLoop++, Sleep (cmsWait))
{
BOOL fr = QueryServiceStatus (hSvc, &status);
Assert(fr);
if (SERVICE_RUNNING == status.dwCurrentState)
{
break;
}
}
if (SERVICE_RUNNING != status.dwCurrentState)
{
hr = HRESULT_FROM_WIN32(ERROR_NETWORK_UNREACHABLE);
#if DBG
OutputDebugString (L"***ERROR*** NETCFG - Workstation service didn't start after more than 2 minutes!\n");
OutputDebugString (L"***ERROR*** NETCFG - Join Domain will fail!\n");
#endif
}
CloseServiceHandle(hSvc);
}
scm.Close();
}
else
{
TraceError("WJOIN.CPP - HrWorkstationStart - Unable to open the Service Manager",hrTmp);
}
TraceError("WJOIN.CPP - HrWorkstationStart",hr);
TraceTag(ttidWizard, "Leaving HrWorkstationStart");
return hr;
}
// Purpose: Secure Domain Join with the new ComputerPassword Answer-File key.
// Domain Join tries to join the domain with the random precreated machine password.
// (the username is not required in this case)
// note: code path is inspired from HrAttemptJoin(JoinData * pData)
// functions defined in ncident.cpp
extern HRESULT HrNetValidateName(IN PCWSTR lpMachine,
IN PCWSTR lpName,
IN PCWSTR lpAccount,
IN PCWSTR lpPassword,
IN NETSETUP_NAME_TYPE NameType);
extern HRESULT HrNetJoinDomain(IN PWSTR lpMachine,
IN PWSTR lpMachineObjectOU,
IN PWSTR lpDomain,
IN PWSTR lpAccount,
IN PWSTR lpPassword,
IN DWORD fJoinOptions);
EXTERN_C HRESULT HrAttemptSecureDomainJoin(JoinData * pData)
{
TraceFileFunc(ttidGuiModeSetup);
HRESULT hr;
Assert(pData);
// 1. wait for the start of LanmanWorkstation service
// 2. check for valid domain
// 3. secure join domain
hr = HrWorkstationStart(pData->hwndDlg);
if (SUCCEEDED(hr))
{
hr = HrNetValidateName(NULL, pData->szDomain , NULL, NULL, NetSetupDomain);
}
TraceHr(ttidWizard, FAL, hr, FALSE, "HrAttemptSecureDomainJoin - HrNetValidateName");
if (SUCCEEDED(hr))
{
// do the secure join domain
DWORD dwJoinOption = 0;
dwJoinOption |= (NETSETUP_JOIN_DOMAIN | NETSETUP_JOIN_UNSECURE | NETSETUP_MACHINE_PWD_PASSED);
if (FInSystemSetup())
{
// During system setup, need to pass special flag that tells join code
// to not do certain operations because SAM is not initialized yet.
dwJoinOption |= NETSETUP_INSTALL_INVOCATION;
}
hr = HrNetJoinDomain(NULL,pData->pszMachineObjectOU,
pData->szDomain, NULL, pData->szComputerPassword,
dwJoinOption);
TraceHr(ttidWizard, FAL, hr, FALSE, "HrAttemptSecureDomainJoin - HrNetJoinDomain");
}
TraceError("HrAttemptSecureDomainJoin", hr);
return hr;
}
EXTERN_C HRESULT HrAttemptJoin(JoinData * pData)
{
TraceFileFunc(ttidGuiModeSetup);
HRESULT hr;
if (IsDlgButtonChecked(pData->hwndDlg, BTN_JOIN_DOMAIN))
{
hr = HrWorkstationStart(pData->hwndDlg);
if (SUCCEEDED(hr))
{
hr = pData->pIdent->JoinDomain(pData->szDomain,
pData->pszMachineObjectOU,
pData->szUserName,
pData->szPassword, pData->dwJoinFlag);
}
TraceHr(ttidWizard, FAL, hr, FALSE, "HrAttemptJoin - JoinDomain");
}
else
{
// Join a workgroup
hr = pData->pIdent->JoinWorkgroup(pData->szDomain);
TraceHr(ttidWizard, FAL, hr, FALSE, "HrAttemptJoin - JoinWorkgroup");
}
if (SUCCEEDED(hr))
{
if (S_OK == pData->pIdent->Validate())
{
hr = pData->pIdent->Apply();
TraceHr(ttidWizard, FAL, hr, FALSE, "HrAttemptJoin - Apply");
}
}
if (FAILED(hr))
{
// Rollback any changes
pData->pIdent->Cancel();
}
TraceError("HrAttemptJoin",hr);
return hr;
}
HRESULT HrAttemptJoin(JoinData * pData, DWORD dwRetries, DWORD dwDelayPeriod)
{
HRESULT hr = E_FAIL;
DWORD dwCount = dwRetries;
do
{
hr = HrAttemptJoin(pData);
if (FAILED(hr))
{
dwCount--;
Sleep(dwDelayPeriod);
}
} while (FAILED(hr) && (dwCount));
return hr;
}
HRESULT HrAttemptSecureDomainJoin(JoinData * pData, DWORD dwRetries, DWORD dwDelayPeriod)
{
HRESULT hr = E_FAIL;
DWORD dwCount = dwRetries;
do
{
hr = HrAttemptSecureDomainJoin(pData);
if (FAILED(hr))
{
dwCount--;
Sleep(dwDelayPeriod);
}
} while (FAILED(hr) && (dwCount));
return hr;
}
EXTERN_C DWORD JoinDomainWorkThrd(JoinData * pData)
{
TraceFileFunc(ttidGuiModeSetup);
BOOL fUninitCOM = FALSE;
HRESULT hr;
Assert(NULL != pData);
CWizard * pWizard =
reinterpret_cast<CWizard *>(::GetWindowLongPtr(pData->hwndDlg, DWLP_USER));
Assert(NULL != pWizard);
// Initialize COM on this thread
//
hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
// $REVIEW - LogError ?
TraceTag(ttidWizard, "Failed to initialize COM join work thread");
goto Done;
}
else
{
// Remember to uninitialize COM on thread exit
fUninitCOM = TRUE;
}
DWORD dwNumTries = 1;
if (IsDlgButtonChecked(pData->hwndDlg, BTN_JOIN_DOMAIN))
{
Sleep(c_dwDomainJoinWaitDelay);
dwNumTries = 5;
}
if (pData->dwJoinFlag & JDF_MACHINE_PWD_PASSED)
{ // Unattended Answer-File specified with ComputerPassword key
// Try Secure Domain Join
TraceTag(ttidWizard, "Attempting join with precreated computer password.");
hr = HrAttemptSecureDomainJoin(pData, dwNumTries, c_dwDomainJoinWaitDelay);
if (FAILED(hr))
{
// clear the secure domain join flag and try the normal join
TraceTag(ttidWizard, "Failed in secure join domain.");
pData->dwJoinFlag &= ~JDF_MACHINE_PWD_PASSED;
}
else
goto Cleanup;
}
// Try the normal join
//
TraceTag(ttidWizard, "Attempting join WITHOUT trying to create an account.");
hr = HrAttemptJoin(pData, 3, 10000);
// If the join failed, and the Create Account flag has not been
// specified, try adding it and reattempt the join.
//
if (FAILED(hr) && !(pData->dwJoinFlag & JDF_CREATE_ACCOUNT))
{
// Clear the Unsecure join flag if set, creating an account is
// mutually exclusive. Set the create account flag to reattempt.
//
pData->dwJoinFlag &= ~JDF_JOIN_UNSECURE;
pData->dwJoinFlag |= JDF_CREATE_ACCOUNT;
TraceTag(ttidWizard, "Attempting join but trying to create an account.");
hr = HrAttemptJoin(pData, dwNumTries, c_dwDomainJoinWaitDelay);
}
Cleanup:
// Cleanup username/password and MachineObjectOU
//
pData->szUserName[0] = 0;
pData->szPassword[0] = 0;
pData->dwJoinFlag = 0;
MemFree(pData->pszMachineObjectOU);
pData->pszMachineObjectOU = NULL;
pData->szComputerPassword[0] = 0;
if (FAILED(hr))
{
// Raid 380374: no UI allowed if in full unattended mode ..
if (UM_FULLUNATTENDED == pWizard->GetUnattendedMode())
{
if (IsDlgButtonChecked(pData->hwndDlg, BTN_JOIN_DOMAIN))
{
NetSetupLogStatusV( LogSevError,
SzLoadIds (IDS_E_UNATTENDED_JOIN_DOMAIN),
pData->szDomain);
}
else
{
NetSetupLogStatusV( LogSevError,
SzLoadIds (IDS_E_UNATTENDED_JOIN_WORKGROUP),
pData->szDomain);
}
// proceed to the exit page
PostMessage(pData->hwndDlg, PWM_JOINSUCCESS, 0, 0L);
}
else
{
// If we're in unattended mode, consider it failed.
pData->fUnattendedFailed = TRUE;
PostMessage(pData->hwndDlg, PWM_JOINFAILURE, 0, (LPARAM)hr);
}
}
else
{
if (IsDlgButtonChecked(pData->hwndDlg, BTN_JOIN_DOMAIN))
NotifyPostSetupWizard(PSW_JOINEDDOMAIN, pWizard);
PostMessage(pData->hwndDlg, PWM_JOINSUCCESS, 0, 0L);
}
Done:
// Uninitialize COM for this thread
//
if (fUninitCOM)
{
CoUninitialize();
}
TraceTag(ttidWizard, "Leaving JoinDomainWorkThrd...");
return( 0 );
}
//
// Function: HrJoinProcessAnswerFile
//
// Purpose: Read the answer file and populate the in memory structures
// and UI with the data found
//
// Parameters:
//
// Returns: HRESULT, S_OK on success
// S_FALSE if required information is missing
// A failed error code on error
//
HRESULT HrJoinProcessAnswerFile(HWND hwndDlg, CWizard * pWizard,
JoinData * pData)
{
TraceFileFunc(ttidGuiModeSetup);
CSetupInfFile csif;
INFCONTEXT ctx;
BOOL fValue;
HRESULT hr;
int nId = BTN_JOIN_WORKGROUP;
tstring str;
pData->dwJoinFlag = 0;
pData->szDomain[0] = 0;
pData->szUserName[0] = 0;
pData->szPassword[0] = 0;
pData->pszMachineObjectOU = NULL;
pData->szComputerPassword[0] = 0;
if ((NULL == pWizard->PSetupData()) ||
(NULL == pWizard->PSetupData()->UnattendFile))
{
hr = NETSETUP_E_ANS_FILE_ERROR;
goto Error;
}
// Open the answerfile
//
hr = csif.HrOpen(pWizard->PSetupData()->UnattendFile,
NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
if (FAILED(hr))
{
hr = S_FALSE;
TraceTag(ttidWizard, "Unable to open answer file!!!");
goto Error;
}
// Check for existance of the identification section. If it is not
// present return S_FALSE to indicate identification info not supplied
//
hr = HrSetupFindFirstLine (csif.Hinf(), c_szAfSectionIdentification,
NULL, &ctx);
if (SPAPI_E_LINE_NOT_FOUND == hr)
{
hr = S_FALSE;
goto Error;
}
// Try to get the workgroup
//
hr = csif.HrGetString(c_szAfSectionIdentification,
c_szAfJoinWorkgroup, &str);
if (SUCCEEDED(hr) && str.length())
{
if (MAX_WORKGROUPNAME_LENGTH >= str.length())
{
wcscpy(pData->szDomain, str.c_str());
TraceTag(ttidWizard, "Joining workgroup: %S", pData->szDomain);
}
else
{
hr = NETSETUP_E_ANS_FILE_ERROR;
TraceTag(ttidWizard, "JOIN Workgroup - Invalid workgroup supplied.");
goto Error;
}
}
else
{
// Try to get the domain
//
hr = csif.HrGetString(c_szAfSectionIdentification,
c_szAfJoinDomain, &str);
if (SPAPI_E_LINE_NOT_FOUND == hr)
{
// No domain or workgroup entry, skip joining a domain
hr = S_FALSE;
goto Error;
}
else if (FAILED(hr) || (0 == str.length()) ||
(MAX_DOMAINNAME_LENGTH < str.length()))
{
hr = NETSETUP_E_ANS_FILE_ERROR;
TraceTag(ttidWizard, "JOIN Domain - Invalid domain supplied.");
goto Error;
}
// Joining a domain...
//
nId = BTN_JOIN_DOMAIN;
wcscpy(pData->szDomain, str.c_str());
TraceTag(ttidWizard, "Joining domain: %S", pData->szDomain);
// If we're upgrading from win9x add the special flag
//
hr = csif.HrGetString(c_szAfSectionNetworking,
c_szAfUpgradeFromProduct, &str);
if (SUCCEEDED(hr) &&
(0 == lstrcmpiW(str.c_str(), c_szAfWin95)))
{
pData->dwJoinFlag |= JDF_WIN9x_UPGRADE;
}
// Support unsecure joins
//
hr = csif.HrGetStringAsBool(c_szAfSectionIdentification,
c_szAfUnsecureJoin,
&fValue);
if (SUCCEEDED(hr) && fValue)
{
pData->dwJoinFlag |= JDF_JOIN_UNSECURE;
}
// Is a MachineObjectOU specified?
//
hr = csif.HrGetString(c_szAfSectionIdentification,
c_szAfMachineObjectOU, &str);
if (SUCCEEDED(hr) && str.length())
{
pData->pszMachineObjectOU = reinterpret_cast<WCHAR *>(MemAlloc(sizeof(WCHAR) * (str.length() + 1)));
if (pData->pszMachineObjectOU)
{
TraceTag(ttidWizard, "Machine Object OU: %S", pData->szDomain);
lstrcpyW(pData->pszMachineObjectOU, str.c_str());
}
}
// Bug# 204377 secure domain join shouldn't require both "ComputerPassword" and
// "DomainAdmin"/"DomainAdminPassword" options to be presence
// in Answer-File simultaneously.
//
// Bug# 204378 If the Answer-File specifies the "ComputerPassword" key
// in the "Indentification" section, the code should attempt
// a secure domain join, regardless of the presence of the
// "DoOldstyleDomainjoin" key
// check if this is a secure domain join by
// quering the random machine account password
hr = csif.HrGetString(c_szAfSectionIdentification,
c_szAfComputerPassword, &str);
if (SUCCEEDED(hr) && (str.length() <= SAM_MAX_PASSWORD_LENGTH) && str.length())
{
TraceTag(ttidWizard, "Got the value of ComputerPassword");
wcscpy(pData->szComputerPassword, str.c_str());
// signal that we need to try secure domain join by
// passing the random machine password
pData->dwJoinFlag |= JDF_MACHINE_PWD_PASSED;
// Bug# 204378, make sure we won't do the unsecure domain join
// and we'll try to read "DomainAdmin"/"DomainAdminPassword"
// in the following if block.
pData->dwJoinFlag &= ~JDF_JOIN_UNSECURE;
}
// If not a remote boot client, Query the username, unless this
// is an unsecure domain join which doesn't need username/password.
//
if (
#if defined(REMOTE_BOOT)
(S_FALSE == HrIsRemoteBootMachine()) ||
#endif // defined(REMOTE_BOOT)
((pData->dwJoinFlag & JDF_JOIN_UNSECURE) == 0))
{
hr = csif.HrGetString(c_szAfSectionIdentification,
c_szAfDomainAdmin, &str);
if (SUCCEEDED(hr) && (MAX_USERNAME_LENGTH > str.length()))
{
wcscpy(pData->szUserName, str.c_str());
// Query the password
//
hr = csif.HrGetString(c_szAfSectionIdentification,
c_szAfDomainAdminPassword, &str);
if (SUCCEEDED(hr) && (SAM_MAX_PASSWORD_LENGTH > str.length()))
{
wcscpy(pData->szPassword, str.c_str());
// Raid 195920 - If both username and password are
// present, treat this like a fresh install and DO NOT
// use the JDF_WIN9x_UPGRADE flag
pData->dwJoinFlag &= ~(JDF_WIN9x_UPGRADE | JDF_JOIN_UNSECURE);
}
}
// Bug# 204377
// ignore any error on reading of "DomainAdmin"/"DomainAdminPassword" keys
// if "ComputerPassword" has been specified.
if (! (pData->dwJoinFlag & JDF_MACHINE_PWD_PASSED) )
{
// If failed or either is longer than the maximum length return an error
//
if (FAILED(hr) || (MAX_USERNAME_LENGTH <= str.length()))
{
hr = NETSETUP_E_ANS_FILE_ERROR;
TraceTag(ttidWizard, "JOIN Domain - Invalid username/password supplied.");
goto Error;
}
}
}
}
// Normalize any optional errors
//
hr = S_OK;
Error:
// Update the UI and pData with the info we managed to read.
//
CheckRadioButton(hwndDlg, BTN_JOIN_WORKGROUP, BTN_JOIN_DOMAIN, nId);
SetWindowText(GetDlgItem(hwndDlg, nId == BTN_JOIN_DOMAIN ? EDT_DOMAINJOIN_NAME : EDT_WORKGROUPJOIN_NAME ), pData->szDomain);
JoinUpdatePromptText(hwndDlg);
TraceHr(ttidWizard, FAL, hr, FALSE, "HrJoinProcessAnswerFile");
return hr;
}
//
// Function: OnJoinDoUnattended
//
// Purpose:
//
// Parameters:
//
// Returns: BOOL
//
BOOL OnJoinDoUnattended(HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
DWORD dwThreadId = 0;
HRESULT hr = S_OK;
CWizard * pWizard =
reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
Assert(NULL != pWizard);
JoinData * pData = reinterpret_cast<JoinData *>
(pWizard->GetPageData(IDD_Join));
Assert(NULL != pData);
Assert(NULL != pData->pIdent);
Assert(NULL != pData->hwndDlg);
if(pData) {
// Create the unattended thread
//
HANDLE hthrd = CreateThread(NULL, STACK_SIZE_TINY,
(LPTHREAD_START_ROUTINE)JoinDomainWorkThrd,
(LPVOID)pData, 0, &dwThreadId);
if (NULL != hthrd)
{
// Set the wait cursor
//
SetCursorToHourglass( hwndDlg, pData );
// Disable all the controls
//
PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdc), nrgIdc, FALSE);
CloseHandle(hthrd);
}
else
{
hr = HrFromLastWin32Error();
}
}
TraceHr(ttidWizard, FAL, hr, FALSE, "OnJoinDoUnattended");
return (SUCCEEDED(hr));
}
// Determines whether the computer DNS domain name should be kept in sync with
// the DNS domain name of the domain to which it is joined. If no
// synchonization is required (unlikely, as sync is the default), do nothing.
//
// Otherwise, attempt to determine the DNS domain name of the domain and write
// this value into reg key. If the DNS domain name cannot be determined,
// write a flag to a separate reg key to indicate that whatever services that
// care about the computer DNS domain name (i.e. kerberos authentication)
// should try to fix up the name.
void
fixupComputerDNSDomainName()
{
TraceFileFunc(ttidGuiModeSetup);
TraceTag(ttidWizard, "Entering fixupComputerDNSDomainName");
// check a reg key for the sync flag.
bool fSetName = false;
HKEY hkeyParams = 0;
HRESULT hr =
HrRegOpenKeyEx(
HKEY_LOCAL_MACHINE,
c_szIpParameters,
// all access as we may need to write a value here if we fail.
KEY_READ_WRITE,
&hkeyParams);
if (SUCCEEDED(hr))
{
DWORD dwValue = 0;
hr = HrRegQueryDword(hkeyParams, c_szSyncDomainWithMembership, &dwValue);
if (SUCCEEDED(hr) && (1 == dwValue))
{
// the sync flag was present in the registry, and its value is true
fSetName = true;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
// the sync flag was not present in the registry, which means we
// assume the default value of true.
fSetName = true;
hr = S_OK;
}
}
if (SUCCEEDED(hr) && fSetName)
{
bool fixup_success = false;
// 293301 Here we attempt to determine the DNS domain name of the domain
// the machine is joined to. If we cannot determine that name (because
// a dc could not be located, for example), then we will set a flag in
// the registry so that kerberos authentication agents will come along
// and fixup the DNS domain name.
PDOMAIN_CONTROLLER_INFO pDCInfo = 0;
DWORD dw =
DsGetDcName(
0,
0,
0,
0,
// make sure to ask for the DNS domain name, otherwise we're
// likely to get the flatname
DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_DNS_NAME,
&pDCInfo);
if (NOERROR == dw)
{
Assert(pDCInfo->DomainName);
Assert(pDCInfo->Flags & DS_DNS_DOMAIN_FLAG);
TraceTag(ttidWizard, "DsGetDcName succeeded %s", pDCInfo->DomainName);
if (pDCInfo->Flags & DS_DNS_DOMAIN_FLAG)
{
// the domain name is indeed the DNS name
// chop off any trailing '.'
WCHAR* AbsoluteSignifier =
&pDCInfo->DomainName[ wcslen(pDCInfo->DomainName) - 1 ];
if (*AbsoluteSignifier == L'.')
{
*AbsoluteSignifier = 0;
}
// set the computer's DNS domain name.
if (
SetComputerNameEx(
ComputerNamePhysicalDnsDomain,
pDCInfo->DomainName) )
{
fixup_success = true;
}
#if DBG
else
{
// this just isn't our day.
TraceTag(ttidWizard, "SetComputerNameEx failed");
}
#endif
}
NetApiBufferFree(pDCInfo);
}
#if DBG
else
{
TraceTag(ttidWizard, "DsGetDcName returned %ld",dw);
}
#endif
// at this point, fixup_success will indicate whether we successfully
// set the computer's domain DNS name, or not. If not, then we need
// to write a flag into the registry so that kerberos auth will fix
// it up later.
if (!fixup_success)
{
// write a flag to have someone else do the fixup
HrRegSetDword(hkeyParams, L"DoDNSDomainFixup", 1);
}
}
RegCloseKey(hkeyParams);
}
//
// Function: JoinUpgradeNT351orNT4toNT5
//
// Purpose: If currently processing NT4 -> NT5 upgrade, set the
// computer name.
//
// Parameters:
//
// Returns: none
//
VOID JoinUpgradeNT351orNT4toNT5(CWizard * pWizard, JoinData * pData)
{
TraceFileFunc(ttidGuiModeSetup);
HRESULT hr = S_OK;
CSetupInfFile csif;
INFCONTEXT ctx;
TraceTag(ttidWizard, "Checking for the need to do NT4->NT5 Join conversions...");
// If unattended
//
if (IsUnattended(pWizard) && (NULL != pWizard->PSetupData()) &&
(NULL != pWizard->PSetupData()->UnattendFile))
{
hr = csif.HrOpen(pWizard->PSetupData()->UnattendFile,
NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
if (SUCCEEDED(hr))
{
DWORD dw;
hr = csif.HrGetDword(c_szAfSectionNetworking, c_szAfBuildNumber, &dw);
if (SUCCEEDED(hr) && ((wWinNT4BuildNumber == dw) ||
(wWinNT351BuildNumber == dw)))
{
hr = pData->pIdent->GetComputerRole(&dw);
if (SUCCEEDED(hr) && (dw == GCR_MEMBER))
{
//fixupComputerDNSDomainName();
NC_TRY
{
TraceTag (ttidWizard, "Calling NetpUpgradePreNT5JoinInfo...");
NetpUpgradePreNT5JoinInfo ();
}
NC_CATCH_ALL
{
TraceHr (
ttidWizard, FAL, E_FAIL, FALSE,
"NetpUpgradePreNT5JoinInfo failed. "
"Likely delay load problem with netapi32.dll");
}
}
}
}
}
TraceHr(ttidWizard, FAL, hr, FALSE, "JoinUpgradeNT351orNT4toNT5");
}
//
// Function: OnJoinPageActivate
//
// Purpose:
//
// Parameters:
//
// Returns:
//
BOOL OnJoinPageActivate(HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
// Retrieve the CWizard instance from the dialog
CWizard * pWizard =
reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
Assert(NULL != pWizard);
JoinData * pData = reinterpret_cast<JoinData *>
(pWizard->GetPageData(IDD_Join));
Assert(NULL != pData);
TraceTag(ttidWizard, "Entering Join page...");
if (ISDC(ProductType(pWizard)))
{
// 412142 : we are going to skip the Join page a little farther down, but
// even for a DC, we need to do this.
//
if (FALSE == pData->fUpgraded)
{
JoinUpgradeNT351orNT4toNT5(pWizard, pData);
pData->fUpgraded = TRUE;
}
}
// mbend 02/08/2000
//
// BUG 433915
// Domain/Workgroup page in setup: Check to by-pass for SBS case
// If this computer is a domain controller or there are no adapters or we don't
// want activation, then don't show the Join page.
//
if (IsSBS() || ISDC(ProductType(pWizard)) || !pWizard->PAdapterQueue()->FAdaptersInstalled() ||
(IsRunningOnPersonal() && !(IsUnattended(pWizard) && (FALSE == pData->fUpgraded))) )
{
PAGEDIRECTION PageDir = pWizard->GetPageDirection(IDD_Join);
if (NWPD_FORWARD == PageDir)
{
// if forward goto exit page
//
pWizard->SetPageDirection(IDD_Join, NWPD_BACKWARD);
::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_Exit);
}
else
{
// if backward goto upgrade page
//
pWizard->SetPageDirection(IDD_Join, NWPD_FORWARD);
::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_Upgrade);
}
}
else // !DC
{
// Accept focus
//
::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0);
PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
// If we're in unattended mode and haven't tried to join a
// domain/workgroup then give it a try
//
if (IsUnattended(pWizard) && (FALSE == pData->fUpgraded))
{
HRESULT hr;
pData->fUpgraded = TRUE;
// Raid 193450 - NT4 -> NT5 we need to SetComputerNameEx
//
JoinUpgradeNT351orNT4toNT5(pWizard, pData);
// Get the join parameters from the answer file and populate the UI
//
hr = HrJoinProcessAnswerFile(hwndDlg, pWizard, pData);
if (S_FALSE == hr)
{
// S_FALSE was returned, this means no answerfile section
// for identification is present or not all the required
// data is present. Advance without joining unless we're in
// defaulthide mode.
// Advance regardless if we're upgrading, or running on Personal.
//
Assert(S_FALSE == hr);
if (((UM_DEFAULTHIDE == pWizard->GetUnattendedMode()) ||
(UM_READONLY == pWizard->GetUnattendedMode()))
&& (!IsUpgrade(pWizard))
&& (!IsRunningOnPersonal()) )
{
// Pretend something failed so that pressing NEXT will
// do the join. Basically we just populated the UI from
// the answerfile.
//
pData->fUnattendedFailed = TRUE;
}
else
{
PostMessage(hwndDlg, PWM_JOINSUCCESS, 0, 0L);
}
}
else
{
if (FAILED(hr))
{
if (UM_FULLUNATTENDED == pWizard->GetUnattendedMode())
{
// Raid 380374: no UI allowed if in full unattended mode ..
NetSetupLogStatusV( LogSevError,
SzLoadIds (IDS_E_UNATTENDED_INVALID_ID_SECTION));
PostMessage(hwndDlg, PWM_JOINSUCCESS, 0, 0L);
}
else
{
// Stop on this page, something was wrong in the answerfile
//
pData->fUnattendedFailed = TRUE;
}
}
else
{
// If we're in UM_FULLUNATTENDED or in UM_DEFAULTHIDE mode
// launch the thread which will do the unattended join
//
Assert(S_OK == hr);
if ((UM_FULLUNATTENDED == pWizard->GetUnattendedMode()) ||
(UM_DEFAULTHIDE == pWizard->GetUnattendedMode()) ||
(UM_READONLY == pWizard->GetUnattendedMode()))
{
OnJoinDoUnattended(hwndDlg);
}
else
{
// Pretend something failed so that pressing NEXT will
// do the join. Basically we just populated the UI from
// the answerfile.
//
pData->fUnattendedFailed = TRUE;
}
}
}
}
// If something failed in the unattended case or
// If we are not unattended and we did not process this,
// make sure the page shows if called from GUI mode setup.
if ( pData->fUnattendedFailed ||
!IsUnattended(pWizard) )
{
// Make the page visible if it is not an upgrade, otherwise just continue to the next page.
if (!IsUpgrade(pWizard))
{
if (g_pSetupWizard != NULL)
{
g_pSetupWizard->PSetupData()->ShowHideWizardPage(TRUE);
}
UpdateNextBackBttns(hwndDlg);
}
else
{
PostMessage(hwndDlg, PWM_JOINSUCCESS, 0, 0L);
}
}
}
return TRUE;
}
//
// Function: OnJoinInitDialog
//
// Purpose:
//
// Parameters:
//
// Returns:
//
BOOL OnJoinInitDialog(HWND hwndDlg, LPARAM lParam)
{
TraceFileFunc(ttidGuiModeSetup);
HRESULT hr;
CWizard * pWizard;
JoinData * pData;
PROPSHEETPAGE* psp = (PROPSHEETPAGE*)lParam;
Assert(psp->lParam);
::SetWindowLongPtr(hwndDlg, DWLP_USER, psp->lParam);
pWizard = reinterpret_cast<CWizard *>(psp->lParam);
Assert(NULL != pWizard);
pData = reinterpret_cast<JoinData *>(pWizard->GetPageData(IDD_Join));
Assert(NULL != pData);
if(!pData)
{
return false;
}
// Set the descriptive text
tstring str = SzLoadIds(IDS_TXT_JOIN_DESC_1);
str += L"\n";
str += SzLoadIds(IDS_TXT_JOIN_DESC_2);
SetWindowText(GetDlgItem(hwndDlg, TXT_JOIN_DESC), str.c_str());
// Set the maximum length of text in the edit control, and
// subclass it so when the control has no text the next bttn
// is disabled.
HWND hwndEditDomain = GetDlgItem(hwndDlg, EDT_DOMAINJOIN_NAME);
SendMessage(hwndEditDomain, EM_LIMITTEXT, MAX_DOMAINNAME_LENGTH, 0L);
::SetWindowLongPtr(hwndEditDomain, GWLP_USERDATA, ::GetWindowLongPtr(hwndEditDomain, GWLP_WNDPROC));
::SetWindowLongPtr(hwndEditDomain, GWLP_WNDPROC, (LONG_PTR)JoinEditSubclassProc);
HWND hwndEditWorkgroup = GetDlgItem(hwndDlg, EDT_WORKGROUPJOIN_NAME);
SendMessage(hwndEditWorkgroup, EM_LIMITTEXT, MAX_WORKGROUPNAME_LENGTH, 0L);
::SetWindowLongPtr(hwndEditWorkgroup, GWLP_USERDATA, ::GetWindowLongPtr(hwndEditWorkgroup, GWLP_WNDPROC));
::SetWindowLongPtr(hwndEditWorkgroup, GWLP_WNDPROC, (LONG_PTR)JoinEditSubclassProc);
pData->hwndDlg = hwndDlg;
// Initialize to Workgroup default
CheckRadioButton(hwndDlg, BTN_JOIN_WORKGROUP,
BTN_JOIN_DOMAIN, BTN_JOIN_WORKGROUP);
// Get the identification interface
TraceTag(ttidWizard, "Querying computer role...");
hr = HrGetIdentInterface(&pData->pIdent);
if (FAILED(hr))
{
Assert(NULL == pData->pIdent);
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdc), nrgIdc, FALSE);
PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
}
else
{
// Update the UI based on the selection
UpdateJoinUsingComputerRole(hwndDlg, pWizard);
}
return FALSE;
}
//
// Function: OnJoinWizBack
//
// Purpose:
//
// Parameters:
//
// Returns:
//
BOOL OnJoinWizBack(HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
OnProcessPrevAdapterPagePrev(hwndDlg, IDD_Upgrade);
return TRUE;
}
//
// Function: GetCredentials
//
// Purpose: Prompt the user for username and password.
//
// Returns: TRUE on success, otherwise FALSE.
//
// Author: asinha 5/03/2001
//
BOOL GetCredentials (HWND hwndParent, JoinData *pData)
{
WCHAR szCaption[CREDUI_MAX_CAPTION_LENGTH+1];
CREDUI_INFOW uiInfo;
DWORD dwErr;
TraceFileFunc(ttidGuiModeSetup);
DwFormatString(SzLoadIds(IDS_JOIN_DOMAIN_CAPTION), szCaption,
celems(szCaption), pData->szDomain);
ZeroMemory( &uiInfo, sizeof(uiInfo) );
uiInfo.cbSize = sizeof(CREDUI_INFOW);
uiInfo.hwndParent = hwndParent;
uiInfo.pszMessageText = SzLoadIds(IDS_JOIN_DOMAIN_TEXT);
uiInfo.pszCaptionText = szCaption;
dwErr = CredUIPromptForCredentialsW(
&uiInfo,
NULL,
NULL,
NO_ERROR,
pData->szUserName,
MAX_USERNAME_LENGTH+1,
pData->szPassword,
SAM_MAX_PASSWORD_LENGTH+1,
NULL,
CREDUI_FLAGS_DO_NOT_PERSIST |
CREDUI_FLAGS_GENERIC_CREDENTIALS |
CREDUI_FLAGS_VALIDATE_USERNAME |
CREDUI_FLAGS_COMPLETE_USERNAME |
CREDUI_FLAGS_ALWAYS_SHOW_UI );
Assert(dwErr != ERROR_INVALID_PARAMETER);
Assert(dwErr != ERROR_INVALID_FLAGS);
if (dwErr == ERROR_CANCELLED)
{
pData->szUserName[0] = 0;
pData->szPassword[0] = 0;
}
return NO_ERROR == dwErr; // e.g. ERROR_CANCELLED
}
//
// Function: JoinWorkgroupDomain
//
// Purpose:
//
// Parameters:
//
// Returns: nothing
//
VOID JoinWorkgroupDomain(HWND hwndDlg, CWizard * pWizard,
JoinData * pData)
{
TraceFileFunc(ttidGuiModeSetup);
DWORD dwThreadId = 0;
HANDLE hthrd = NULL;
Assert(NULL != pData->pIdent);
Assert(NULL != pData->hwndDlg);
// Retain the domain/workgroup name. Note that the answerfile
// populates the UI before this routine is called so requerying
// from the UI covers both cases (answerfile or user input)
//
if (IsDlgButtonChecked(hwndDlg, BTN_JOIN_DOMAIN))
{
HWND hwndEdit = GetDlgItem(hwndDlg, EDT_DOMAINJOIN_NAME);
Assert(0 != GetWindowTextLength(hwndEdit));
GetWindowText(hwndEdit, pData->szDomain, MAX_DOMAINNAME_LENGTH + 1);
// If no information was seeded into the structure, prompt for it.
//
if (0 == pData->szUserName[0])
{
pData->szPassword[0] = 0;
// Preserve the only Win9x upgrade flag if it was present
//
pData->dwJoinFlag &= JDF_WIN9x_UPGRADE;
// Get the username/password when joining a domain
//
BOOL bRet;
bRet = GetCredentials(GetParent(hwndDlg), pData);
// Note: Must set return as -1 otherwise join page will advance
//
::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
if (bRet == FALSE)
{
return;
}
}
}
else
{
HWND hwndEdit = GetDlgItem(hwndDlg, EDT_WORKGROUPJOIN_NAME);
Assert(0 != GetWindowTextLength(hwndEdit));
GetWindowText(hwndEdit, pData->szDomain, MAX_WORKGROUPNAME_LENGTH + 1);
// Initialize the workstation settings for username/password
// and join flags
//
pData->szUserName[0] = 0;
pData->dwJoinFlag = 0;
pData->szPassword[0] = 0;
MemFree(pData->pszMachineObjectOU);
pData->pszMachineObjectOU = NULL;
pData->szComputerPassword[0] = 0;
}
// Create the thread to join the workgroup/domain
hthrd = CreateThread(NULL, STACK_SIZE_TINY,
(LPTHREAD_START_ROUTINE)JoinDomainWorkThrd,
(LPVOID)pData, 0, &dwThreadId);
if (NULL != hthrd)
{
SetCursorToHourglass( hwndDlg, pData );
PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
EnableOrDisableDialogControls(hwndDlg, celems(nrgIdc), nrgIdc, FALSE);
CloseHandle(hthrd);
}
else
{
// Failed to create the required netsetup thread
AssertSz(0,"Unable to create JoinWorkgroupDomain thread.");
TraceHr(ttidWizard, FAL, E_OUTOFMEMORY, FALSE, "JoinWorkgroupDomain - Create thread failed");
}
}
//
// Function: OnJoinWizNext
//
// Purpose:
//
// Parameters:
//
// Returns:
//
BOOL OnJoinWizNext(HWND hwndDlg)
{
TraceFileFunc(ttidGuiModeSetup);
// Retrieve the CWizard instance from the dialog
CWizard * pWizard =
reinterpret_cast<CWizard *>(::GetWindowLongPtr(hwndDlg, DWLP_USER));
Assert(NULL != pWizard);
JoinData * pData = reinterpret_cast<JoinData *>
(pWizard->GetPageData(IDD_Join));
Assert(NULL != pData);
if(!pData)
{
return false;
}
// Attempt to join the workgroup/domain if we have the Ident interface
//
if (pData->pIdent)
{
// Ensure the user supplied a workgroup/domain name
//
if (0 == GetWindowTextLength(GetDlgItem(hwndDlg, GetJoinNameIIDFromSelection(hwndDlg))))
{
::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
return TRUE;
}
// Join the workgroup/domain
//
if (!IsUnattended(pWizard) || pData->fUnattendedFailed)
{
DNS_STATUS dnsStatus;
if ( IsDlgButtonChecked(hwndDlg, BTN_JOIN_DOMAIN) )
{
dnsStatus = IsValidDomainName( hwndDlg );
}
else
{
dnsStatus = ERROR_SUCCESS;
}
if ( (dnsStatus == ERROR_SUCCESS) ||
(dnsStatus == DNS_ERROR_NON_RFC_NAME) )
{
JoinWorkgroupDomain(hwndDlg, pWizard, pData);
}
else
{
tstring str;
str = SzLoadIds(IDS_JOIN_E_DOMAIN_INVALID_NAME);
MessageBox(GetParent(hwndDlg), str.c_str(),
SzLoadIds(IDS_SETUP_CAPTION), MB_OK);
}
}
::SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, -1);
}
else
{
OnJoinSuccess(hwndDlg);
}
return TRUE;
}
//
// Function: dlgprocJoin
//
// Purpose: Dialog Procedure for the Join wizard page
//
// Parameters: standard dlgproc parameters
//
// Returns: INT_PTR
//
INT_PTR CALLBACK dlgprocJoin( HWND hwndDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
TraceFileFunc(ttidGuiModeSetup);
BOOL frt = FALSE;
switch (uMsg)
{
case PWM_JOINFAILURE:
frt = OnJoinFailure(hwndDlg, lParam);
break;
case PWM_JOINSUCCESS:
frt = OnJoinSuccess(hwndDlg);
break;
case WM_INITDIALOG:
frt = OnJoinInitDialog(hwndDlg, lParam);
break;
case WM_COMMAND:
{
if ((BN_CLICKED == HIWORD(wParam)) &&
((BTN_JOIN_DOMAIN == LOWORD(wParam)) ||
(BTN_JOIN_WORKGROUP == LOWORD(wParam))))
{
JoinUpdatePromptText(hwndDlg);
}
}
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
// propsheet notification
case PSN_HELP:
break;
case PSN_SETACTIVE:
frt = OnJoinPageActivate(hwndDlg);
break;
case PSN_APPLY:
break;
case PSN_KILLACTIVE:
break;
case PSN_RESET:
break;
case PSN_WIZBACK:
frt = OnJoinWizBack(hwndDlg);
break;
case PSN_WIZFINISH:
break;
case PSN_WIZNEXT:
frt = OnJoinWizNext(hwndDlg);
break;
default:
break;
}
}
break;
default:
break;
}
return( frt );
}
//
// Function: JoinPageCleanup
//
// Purpose: As a callback function to allow any page allocated memory
// to be cleaned up, after the page will no longer be accessed.
//
// Parameters: pWizard [IN] - The wizard against which the page called
// register page
// lParam [IN] - The lParam supplied in the RegisterPage call
//
// Returns: nothing
//
VOID JoinPageCleanup(CWizard *pWizard, LPARAM lParam)
{
TraceFileFunc(ttidGuiModeSetup);
JoinData * pData = reinterpret_cast<JoinData *>(lParam);
if (NULL != pData)
{
delete pData->pIdent;
}
MemFree(reinterpret_cast<void*>(lParam));
}
//
// Function: CreateJoinPage
//
// Purpose: To determine if the Join page needs to be shown, and to
// to create the page if requested. Note the Join page is
// responsible for initial installs also.
//
// Parameters: pWizard [IN] - Ptr to a Wizard instance
// pData [IN] - Context data to describe the world in
// which the Wizard will be run
// fCountOnly [IN] - If True, only the maximum number of
// pages this routine will create need
// be determined.
// pnPages [IN] - Increment by the number of pages
// to create/created
//
// Returns: HRESULT, S_OK on success
//
HRESULT HrCreateJoinPage(CWizard *pWizard, PINTERNAL_SETUP_DATA pData,
BOOL fCountOnly, UINT *pnPages)
{
TraceFileFunc(ttidGuiModeSetup);
HRESULT hr = S_OK;
// Batch Mode or for fresh install
if (!IsPostInstall(pWizard))
{
// If not only counting, create and register the page
if (!fCountOnly)
{
JoinData * pData = NULL;
HPROPSHEETPAGE hpsp;
PROPSHEETPAGE psp;
TraceTag(ttidWizard, "Creating Join Page");
hr = E_OUTOFMEMORY;
pData = reinterpret_cast<JoinData *>(MemAlloc(sizeof(JoinData)));
if (pData)
{
pData->fUnattendedFailed = FALSE;
pData->fUpgraded = FALSE;
pData->pIdent = NULL;
pData->hOldCursor = NULL;
pData->hwndDlg = NULL;
pData->dwJoinFlag = 0;
pData->szUserName[0] = 0;
pData->szPassword[0] = 0;
pData->szDomain[0] = 0;
pData->pszMachineObjectOU = NULL;
pData->szComputerPassword[0] = 0;
psp.dwSize = sizeof( PROPSHEETPAGE );
psp.dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
psp.hInstance = _Module.GetResourceInstance();
psp.pszTemplate = MAKEINTRESOURCE( IDD_Join );
psp.hIcon = NULL;
psp.pfnDlgProc = dlgprocJoin;
psp.lParam = reinterpret_cast<LPARAM>(pWizard);
psp.pszHeaderTitle = SzLoadIds(IDS_T_Join);
psp.pszHeaderSubTitle = SzLoadIds(IDS_ST_Join);
hpsp = CreatePropertySheetPage( &psp );
if (hpsp)
{
pWizard->RegisterPage(IDD_Join, hpsp,
JoinPageCleanup,
reinterpret_cast<LPARAM>(pData));
hr = S_OK;
}
else
{
MemFree(pData);
}
}
}
if (SUCCEEDED(hr))
{
(*pnPages)++;
}
}
TraceHr(ttidWizard, FAL, hr, FALSE, "HrCreateJoinPage");
return hr;
}
//
// Function: AppendJoinPage
//
// Purpose: Add the Join page, if it was created, to the set of pages
// that will be displayed.
//
// Parameters: pWizard [IN] - Ptr to Wizard Instance
// pahpsp [IN,OUT] - Array of pages to add our page to
// pcPages [IN,OUT] - Count of pages in pahpsp
//
// Returns: Nothing
//
VOID AppendJoinPage(CWizard *pWizard, HPROPSHEETPAGE* pahpsp, UINT *pcPages)
{
TraceFileFunc(ttidGuiModeSetup);
if (!IsPostInstall(pWizard))
{
HPROPSHEETPAGE hPage = pWizard->GetPageHandle(IDD_Join);
Assert(hPage);
pahpsp[*pcPages] = hPage;
(*pcPages)++;
}
}