|
|
// Copyright (c) 1997-1999 Microsoft Corporation
//
// confirmation page
//
// 12-22-97 sburns
#include "headers.hxx"
#include "ConfirmationPage.hpp"
#include "common.hpp"
#include "resource.h"
#include "ProgressDialog.hpp"
#include "ds.hpp"
#include "state.hpp"
#include "GetCredentialsDialog.hpp"
#include "postop.hpp"
#include <DiagnoseDcNotFound.hpp>
void PromoteThreadProc(ProgressDialog& progress);
ConfirmationPage::ConfirmationPage() : DCPromoWizardPage( IDD_CONFIRMATION, IDS_CONFIRMATION_PAGE_TITLE, IDS_CONFIRMATION_PAGE_SUBTITLE), needToKillSelection(false) { LOG_CTOR(ConfirmationPage); }
ConfirmationPage::~ConfirmationPage() { LOG_DTOR(ConfirmationPage); }
void ConfirmationPage::OnInit() { LOG_FUNCTION(ConfirmationPage::OnInit);
// Since the multi-line edit control has a bug that causes it to eat
// enter keypresses, we will subclass the control to make it forward
// those keypresses to the page as WM_COMMAND messages
// This workaround from phellyar.
// NTRAID#NTBUG9-232092-2000/11/22-sburns
multiLineEdit.Init(Win::GetDlgItem(hwnd, IDC_MESSAGE)); }
int ConfirmationPage::Validate() { LOG_FUNCTION(ConfirmationPage::Validate);
// this function should never be called, as we override OnWizNext.
ASSERT(false);
return 0; }
static String GetMessage() { LOG_FUNCTION(GetMessage);
String message; State& state = State::GetInstance();
String netbiosName; State::RunContext context = state.GetRunContext();
if ( context == State::BDC_UPGRADE || context == State::PDC_UPGRADE) { netbiosName = state.GetComputer().GetDomainNetbiosName(); } else { netbiosName = state.GetNewDomainNetbiosName(); }
switch (state.GetOperation()) { case State::REPLICA: { message = String::format( IDS_CONFIRM_MESSAGE_REPLICA, state.GetReplicaDomainDNSName().c_str());
if (state.ReplicateFromMedia()) { message += String::format( IDS_CONFIRM_MESSAGE_REPLICATE_FROM_MEDIA, state.GetReplicationSourcePath().c_str()); } break; } case State::FOREST: { message = String::format( IDS_CONFIRM_MESSAGE_FOREST, state.GetNewDomainDNSName().c_str(), netbiosName.c_str()); break; } case State::TREE: { message = String::format( IDS_CONFIRM_MESSAGE_TREE, state.GetNewDomainDNSName().c_str(), netbiosName.c_str(), state.GetParentDomainDnsName().c_str()); break; } case State::CHILD: { message = String::format( IDS_CONFIRM_MESSAGE_CHILD, state.GetNewDomainDNSName().c_str(), netbiosName.c_str(), state.GetParentDomainDnsName().c_str()); break; } case State::DEMOTE: { String domain = state.GetComputer().GetDomainDnsName(); if (state.IsLastDCInDomain()) { message = String::format( IDS_CONFIRM_MESSAGE_DEMOTE_LAST_DC, domain.c_str()); } else { if (state.IsForcedDemotion()) { message = String::load(IDS_CONFIRM_MESSAGE_FORCE_DEMOTE); } else { message = String::format(IDS_CONFIRM_MESSAGE_DEMOTE, domain.c_str()); } }
if (state.GetAppPartitionList().size()) { message += String::format(IDS_CONFIRM_MESSAGE_APP_PARTITION); } break; } case State::ABORT_BDC_UPGRADE: { message = String::format( IDS_CONFIRM_ABORT_BDC_UPGRADE, netbiosName.c_str()); break; } case State::NONE: default: { ASSERT(false); break; } }
return message; }
bool ConfirmationPage::OnSetActive() { LOG_FUNCTION(ConfirmationPage::OnSetActive); ASSERT(State::GetInstance().GetOperation() != State::NONE);
State& state = State::GetInstance(); String message = GetMessage();
State::Operation operation = state.GetOperation(); switch (operation) { case State::REPLICA: case State::FOREST: case State::TREE: case State::CHILD: { // write the path options into the text box
String pathText = String::format( IDS_CONFIRM_PATHS_MESSAGE, state.GetDatabasePath().c_str(), state.GetLogPath().c_str(), state.GetSYSVOLPath().c_str());
message += pathText;
if (state.ShouldInstallAndConfigureDns()) { // NTRAID#NTBUG9-446484-2001/10/11-sburns
if (state.ShouldConfigDnsClient()) { message += String::load(IDS_CONFIRM_INSTALL_DNS_AND_CLIENT); } else { message += String::load(IDS_CONFIRM_INSTALL_DNS); } }
if (operation != State::REPLICA) { if (state.ShouldAllowAnonymousAccess()) { // Only show the anon access message in forest, tree, child
// 394387
message += String::load(IDS_CONFIRM_DO_RAS_FIXUP); }
message += String::load(IDS_DOMAIN_ADMIN_PASSWORD); }
break; } case State::DEMOTE: case State::ABORT_BDC_UPGRADE: { // hide the path controls: do nothing
break; } case State::NONE: default: { ASSERT(false); break; } }
Win::SetDlgItemText(hwnd, IDC_MESSAGE, message); needToKillSelection = true;
Win::PropSheet_SetWizButtons( Win::GetParent(hwnd), PSWIZB_BACK | PSWIZB_NEXT);
if (state.RunHiddenUnattended()) { return ConfirmationPage::OnWizNext(); }
return true; }
void DoOperation( HWND parentDialog, ProgressDialog::ThreadProc threadProc, int animationResID) { LOG_FUNCTION(DoOperation); ASSERT(Win::IsWindow(parentDialog)); ASSERT(threadProc); ASSERT(animationResID > 0);
// the ProgressDialog::OnInit actually starts the thread.
ProgressDialog dialog(threadProc, animationResID); if ( dialog.ModalExecute(parentDialog) == static_cast<int>(ProgressDialog::THREAD_SUCCEEDED)) { LOG(L"OPERATION SUCCESSFUL"); } else { LOG(L"OPERATION FAILED"); } }
int DetermineAnimation() { LOG_FUNCTION(DetermineAnimation);
State& state = State::GetInstance(); int aviID = IDR_AVI_DOMAIN;
switch (state.GetOperation()) { case State::REPLICA: { aviID = IDR_AVI_REPLICA; break; } case State::DEMOTE: { aviID = IDR_AVI_DEMOTE; break; } case State::FOREST: case State::TREE: case State::CHILD: case State::ABORT_BDC_UPGRADE: case State::NONE: default: { // do nothing
break; } }
return aviID; }
bool ConfirmationPage::OnWizNext() { LOG_FUNCTION(ConfirmationPage::OnWizNext);
State& state = State::GetInstance(); DoOperation(hwnd, PromoteThreadProc, DetermineAnimation()); if (state.GetNeedsReboot()) { Win::PropSheet_RebootSystem(Win::GetParent(hwnd)); }
int nextPage = IDD_FAILURE; if (!state.IsOperationRetryAllowed()) { nextPage = IDD_FINISH; } GetWizard().SetNextPageID(hwnd, nextPage); return true; }
// noRoleMessageResId - resource ID of the string to use to format messages
// when no role change error message is available.
//
// roleMessageResId - resource ID of the string to use to format messages when
// a role change error message is available.
//
// "is available" => an operation results message has been set on the global
// state object.
String ComposeFailureMessageHelper( const Win::Error& error, unsigned noRoleMessageResId, unsigned roleMessageResId) { State& state = State::GetInstance(); String win32_message = error.GetMessage(); String opMessage = state.GetOperationResultsMessage(); String message;
if ( error.GetHresult() == Win32ToHresult(ERROR_DS_CANT_ON_NON_LEAF) && state.GetOperation() == State::DEMOTE) { // supercede the meaningless error text for this situation.
win32_message = String::load(IDS_DEMOTE_DOMAIN_HAS_DEPENDENTS); }
if (error.GetHresult() == Win32ToHresult(ERROR_CANCELLED)) { // this message may be a failure message from the operation that was
// taking place when the cancel request was received. In that case,
// since the cancel has occurred, we don't care about this message
opMessage.erase(); }
if (error.GetHresult() == Win32ToHresult(ERROR_BAD_NETPATH)) { // n27117
win32_message = String::load(IDS_RAS_BAD_NETPATH); }
if (opMessage.empty()) { message = String::format( noRoleMessageResId, win32_message.c_str()); } else { message = String::format( roleMessageResId, win32_message.c_str(), opMessage.c_str()); }
return message; }
void ComposeFailureMessage( const Win::Error& error, bool wasDisjoined, const String& originalDomainName)
{ LOG_FUNCTION(ComposeFailureMessage);
String message = ComposeFailureMessageHelper( error, IDS_OPERATION_FAILED_NO_RESULT_MESSAGE, IDS_OPERATION_FAILED);
if (wasDisjoined) { message += String::format(IDS_DISJOINED, originalDomainName.c_str()); }
State& state = State::GetInstance(); if ( state.GetOperationResultsFlags() & DSROLE_IFM_RESTORED_DATABASE_FILES_MOVED) { message += L"\r\n\r\n" + String::load(IDS_MUST_RESTORE_IFM_FILES_AGAIN); }
state.SetFailureMessage(message); }
String GetSbsLimitMessage() { LOG_FUNCTION(GetSbsLimitMessage);
static const String SBSLIMIT_DLL(L"sbslimit.dll");
String message;
HMODULE sbsDll = 0; HRESULT hr = Win::LoadLibraryEx(SBSLIMIT_DLL, LOAD_LIBRARY_AS_DATAFILE, sbsDll); if (FAILED(hr)) { LOG(L"Unable to load SBSLIMIT_DLL");
// fall back to a message of our own
message = String::load(IDS_SBS_LIMITATION_MESSAGE); } else { // string 3 is the dcpromo message
message = Win::LoadString(3, sbsDll);
HRESULT unused = Win::FreeLibrary(sbsDll);
ASSERT(SUCCEEDED(unused)); }
return message; }
// Check if this is a Small Business Server product; if so, present throw an
// error, as SBS should only allow new forest & demote. Rather brutal to do
// it in this fashion, but SBS users should not be using dcpromo directly.
// 353854, 353856
void CheckSmallBusinessServerLimitations(HWND hwnd) throw (DS::Error) { LOG_FUNCTION(CheckSmallBusinessServerLimitations); ASSERT(Win::IsWindow(hwnd));
State& state = State::GetInstance(); State::Operation op = state.GetOperation();
switch (op) { case State::TREE: case State::CHILD: case State::REPLICA: { // Tree and child operations are not allowed with the SBS product.
// Replica is allowed, if it is of a forest root domain.
OSVERSIONINFOEX info; HRESULT hr = Win::GetVersionEx(info); BREAK_ON_FAILED_HRESULT(hr);
if (info.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED) { if (op == State::REPLICA) { String domain = state.GetReplicaDomainDNSName();
// Since domain has been previously validated by calling
// DsGetDcName, we don't anticipate that GetForestName will
// have any difficulty.
hr = S_OK; String forest = GetForestName(domain, &hr); if (FAILED(hr)) { ShowDcNotFoundErrorDialog( hwnd, -1, domain, String::load(IDS_WIZARD_TITLE), String::format(IDS_DC_NOT_FOUND, domain.c_str()), false);
throw DS::Error( hr, String::format( IDS_UNABLE_TO_DETERMINE_FOREST, domain.c_str()), String::load(IDS_WIZARD_TITLE)); } DNS_RELATE_STATUS compare = Dns::CompareNames(domain, forest); if (compare == DnsNameCompareEqual) { LOG(L"replica is of forest root, allowing promote"); break; } }
// This machine is an SBS machine under restricted license.
// Extract an error message from an SBS dll.
LOG(L"Is SBS Restricted");
String message = GetSbsLimitMessage();
// do not call state.SetOperationResultsMessage with this
// message, rather, include it in the thrown error.
throw DS::Error( S_OK, // don't trigger cred retry
message, String::load(IDS_SMALL_BUSINESS_LIMIT)); }
break; } case State::DEMOTE: case State::FOREST: case State::ABORT_BDC_UPGRADE: case State::NONE: default: { // do nothing
break; } } }
// Picks the name of a domain controller suitable for the creation of a
// replica. Since a server must be a member of the domain before it can be
// made a replica of that domain, the server may also be joined to the domain
// before the replica operation is attempted.
//
// We need to ensure that the domain controller used to join the domain is the
// same domain controller used to replicate the domain. Also, since a machine
// account for the server may already exist on one or more -- but not
// necessarily all -- domain controllers, we need to pick a domain controller
// that has that machine account. 406462
//
// domainName - DNS domain name of domain for which a replica is to be found.
//
// resultDcName - receives the located name, or the empty string on failure.
HRESULT GetJoinAndReplicaDcName(const String& domainName, String& resultDcName) { LOG_FUNCTION(GetJoinAndReplicaDcName); ASSERT(!domainName.empty());
resultDcName.erase();
HRESULT hr = S_OK;
do { // determine the local computer's domain machine account name. This is the
// name of the local computer, plus a "$"
String netbiosName = Win::GetComputerNameEx(ComputerNameNetBIOS); String accountName = netbiosName + L"$";
LOG(accountName);
// look for a domain controller that has a machine account for the local
// computer. Not all domain controllers may have this account, due to
// replication latency.
DOMAIN_CONTROLLER_INFO* info = 0; hr = MyDsGetDcNameWithAccount( 0, accountName, UF_WORKSTATION_TRUST_ACCOUNT | UF_SERVER_TRUST_ACCOUNT, domainName, DS_DIRECTORY_SERVICE_REQUIRED | DS_FORCE_REDISCOVERY, info); BREAK_ON_FAILED_HRESULT(hr);
ASSERT(info->DomainControllerName);
if (info->DomainControllerName) { resultDcName = Computer::RemoveLeadingBackslashes(info->DomainControllerName);
LOG(resultDcName); }
::NetApiBufferFree(info);
if (!resultDcName.empty()) { return hr; } } while (0);
// either there is no domain controller reachable with the required
// account, or the account does not exist, or DsGetDcName returned an
// empty name
LOG(L"Falling back to non-account DsGetDcName");
return GetDcName(domainName, resultDcName); }
void EvaluateRoleChangeState() throw (DS::Error) { LOG_FUNCTION(EvaluateRoleChangeState);
int messageResId = 0;
DSROLE_OPERATION_STATE opState = ::DsRoleOperationIdle; DSROLE_OPERATION_STATE_INFO* info = 0; HRESULT hr = MyDsRoleGetPrimaryDomainInformation(0, info); if (SUCCEEDED(hr) && info) { opState = info->OperationState; ::DsRoleFreeMemory(info); } else { throw DS::Error( hr, String::load(IDS_UNABLE_TO_DETERMINE_OP_STATE), String::load(IDS_WIZARD_TITLE)); } switch (opState) { case ::DsRoleOperationIdle: { // do nothing
break; } case ::DsRoleOperationActive: { // a role change operation is underway
messageResId = IDS_ROLE_CHANGE_IN_PROGRESS; break; } case ::DsRoleOperationNeedReboot: { // a role change has already taken place, need to reboot before
// attempting another.
messageResId = IDS_ROLE_CHANGE_NEEDS_REBOOT; break; } default: { ASSERT(false); break; } }
if (messageResId) { throw DS::Error( S_OK, String::load(messageResId), String::load(IDS_WIZARD_TITLE)); } }
// Verify that the current role of the machine is correct for the type of
// operation we're about to attempt. Throw an exception if it is not.
void DoubleCheckRoleChangeState() throw (DS::Error) { LOG_FUNCTION(DoubleCheckRoleChangeState);
// Make sure that an operation is not in progress or pending reboot.
EvaluateRoleChangeState(); State& state = State::GetInstance(); Computer& computer = state.GetComputer();
HRESULT hr = computer.Refresh(); if (FAILED(hr)) { throw DS::Error( hr, String::load(IDS_UNABLE_TO_DETERMINE_COMPUTER_CONFIG), String::load(IDS_WIZARD_TITLE)); } switch (state.GetOperation()) { case State::TREE: case State::CHILD: case State::REPLICA: case State::FOREST: case State::ABORT_BDC_UPGRADE: { // Make sure the machine is not already a DC. If the machine is
// an NT4 DC finishing upgrade, then its role will be member
// server, not domain controller.
if (computer.IsDomainController()) { throw DS::Error( S_OK, String::load(IDS_MACHINE_IS_ALREADY_DC), String::load(IDS_WIZARD_TITLE)); }
break; } case State::DEMOTE: { // Make sure the machine is still a DC
if (!computer.IsDomainController()) { throw DS::Error( S_OK, String::load(IDS_MACHINE_IS_NOT_ALREADY_DC), String::load(IDS_WIZARD_TITLE)); }
break; } case State::NONE: default: { ASSERT(false); // do nothing
break; } } }
// thread launched by ProgressDialog::OnInit.
// CODEWORK: Man, this function has evolved into a real mess.
void PromoteThreadProc(ProgressDialog& progress) { LOG_FUNCTION(PromoteThreadProc);
//
// Access to members of ProgressDialog is not, by default, threadsafe.
// However, since the only members we access are atomic data types, this
// is not a problem. Note also that calls to ProgressDialog Update
// methods usually resolve to calls to SendMessage on UI elements of the
// dialog. This too is threadsafe, as SendMessage is always executed
// in the thread that created the window (tho it may block the calling
// thread).
//
UINT message = ProgressDialog::THREAD_SUCCEEDED; bool retry = false; bool wasDisjoined = false; State& state = State::GetInstance(); String originalDomainName;
// a reference, as we will refresh the object
Computer& computer = state.GetComputer(); State::RunContext context = state.GetRunContext();
do { LOG(L"top of retry loop");
DisableConsoleLocking();
// clear the state of the operation attempt
bool exceptionWasThrown = false; Win::Error errorThrown(0, 0); message = ProgressDialog::THREAD_SUCCEEDED; retry = false; state.SetOperationResultsMessage(String()); state.SetOperationResultsFlags(0);
progress.UpdateText(IDS_STARTING);
try { CheckSmallBusinessServerLimitations(progress.GetHWND());
// Double check that the role of the machine is still ok for the
// operation to proceed. This is mostly a paranoid check, but there
// have been cases during development where the promotion actually
// succeeded, but reported a failure, and attempting the operation
// again trashes the DS. Such problems indicate the presence of
// other serious bugs, but if we can cheaply avoid zorching a DC,
// then bully for us.
// NTRAID#NTBUG9-345115-2001/03/23-sburns
DoubleCheckRoleChangeState(); switch (state.GetOperation()) { case State::REPLICA: { // if we're using an answerfile, look for a replication partner
// there. 107143
String replDc; if (state.UsingAnswerFile()) { replDc = state.GetAnswerFileOption( AnswerFile::OPTION_REPLICATION_SOURCE); state.SetReplicationPartnerDC(replDc); }
if (context != State::BDC_UPGRADE) { String replicaDnsDomainName = state.GetReplicaDomainDNSName(); if (!computer.IsJoinedToDomain(replicaDnsDomainName) ) { // need to join the domain we will replicate. Determine
// the name of a domain controller to use for join and
// replication. 270233
if (replDc.empty()) { // answerfile did not specify a dc. So pick one
// ourselves.
HRESULT hr = GetJoinAndReplicaDcName( replicaDnsDomainName, replDc); if (FAILED(hr)) { throw DS::Error( hr, IDS_JOIN_DOMAIN_FAILED); } state.SetReplicationPartnerDC(replDc); }
if (computer.IsJoinedToDomain()) { originalDomainName = computer.GetDomainNetbiosName(); }
progress.UpdateText(IDS_CHANGING_DOMAIN);
// this will unjoin if necessary
DS::JoinDomain( replicaDnsDomainName, replDc, state.GetUsername(), state.GetPassword(), state.GetUserDomainName());
if (ComputerWasRenamedAndNeedsReboot()) { // If we make it to this point, the machine was joined
// to a domain, and the name changed as a side-effect,
// and will need to be rebooted even if the promote
// fails. Set a flag to note that fact.
// NTRAID#NTBUG9-346120-2001/04/04-sburns
state.SetNeedsReboot(); } HRESULT hr = computer.Refresh(); ASSERT(SUCCEEDED(hr));
if (!originalDomainName.empty()) { wasDisjoined = true; } } DS::CreateReplica(progress); } else { DS::UpgradeBDC(progress); } break; } case State::FOREST: case State::TREE: case State::CHILD: { if (context != State::PDC_UPGRADE) { if (computer.IsJoinedToDomain()) { // need to unjoin the domain we belong to
originalDomainName = computer.GetDomainNetbiosName(); ASSERT(!originalDomainName.empty());
progress.UpdateText( String::format(IDS_DISJOINING_PROGRESS, originalDomainName.c_str()));
if (!DS::DisjoinDomain()) { // the computer account was not removed.
if (!state.RunHiddenUnattended()) { popup.Info( progress.GetHWND(), String::load(IDS_COULDNT_REMOVE_COMPUTER_ACCOUNT_TEXT)); } }
if (ComputerWasRenamedAndNeedsReboot()) { // If we make it to this point, the machine was
// disjoined from a domain, and the name changed as a
// side-effect, and will need to be rebooted even if
// the promote fails. Set a flag to note that fact.
// NTRAID#NTBUG9-346120-2001/04/04-sburns
state.SetNeedsReboot(); } HRESULT hr = computer.Refresh(); ASSERT(SUCCEEDED(hr));
wasDisjoined = true; }
DS::CreateNewDomain(progress); } else { DS::UpgradePDC(progress); } break; } case State::ABORT_BDC_UPGRADE: { ASSERT(state.GetRunContext() == State::BDC_UPGRADE); DS::AbortBDCUpgrade(); break; } case State::DEMOTE: { DS::DemoteDC(progress); break; } case State::NONE: default: { ASSERT(false); message = ProgressDialog::THREAD_FAILED; } }
//
// At this point, the operation was successfully completed.
//
DoPostOperationStuff(progress); state.SetOperationResults(State::SUCCESS); state.SetNeedsReboot(); } catch (const Win::Error& err) { LOG(L"Exception caught");
exceptionWasThrown = true; errorThrown = err;
LOG(L"catch completed"); }
if (exceptionWasThrown) { LOG(L"handling exception");
// go interactive from now on
state.ClearHiddenWhileUnattended(); // 22935
if ( state.GetRunContext() != State::PDC_UPGRADE && state.GetRunContext() != State::BDC_UPGRADE) { // re-enable console locking if not a downlevel upgrade 28496
EnableConsoleLocking(); }
state.SetOperationResults(State::FAILURE); progress.UpdateText(String()); message = ProgressDialog::THREAD_FAILED;
HRESULT errorThrownHresult = errorThrown.GetHresult();
if (!state.IsOperationRetryAllowed()) { // The operation failure was such that the user should not be
// allowed to retry it. In this case, we skip our special-case
// handling of known failure codes (as expressed by the other else
// if clauses here), and just report the failure.
//
// NTRAID#NTBUG9-296872-2001/01/29-sburns
retry = false; } else if ( errorThrownHresult == Win32ToHresult(ERROR_ACCESS_DENIED) || errorThrownHresult == Win32ToHresult(ERROR_LOGON_FAILURE) || errorThrownHresult == Win32ToHresult(ERROR_NOT_AUTHENTICATED) || errorThrownHresult == Win32ToHresult(RPC_S_SEC_PKG_ERROR) || errorThrownHresult == Win32ToHresult(ERROR_DS_DRA_ACCESS_DENIED) || errorThrownHresult == Win32ToHresult(ERROR_INVALID_PASSWORD) || errorThrownHresult == Win32ToHresult(ERROR_PASSWORD_EXPIRED) || errorThrownHresult == Win32ToHresult(ERROR_ACCOUNT_DISABLED) || errorThrownHresult == Win32ToHresult(ERROR_ACCOUNT_LOCKED_OUT) ) { // bad credentials. ask for new ones
String failureMessage = ComposeFailureMessageHelper( errorThrown, IDS_OPERATION_FAILED_GET_CRED_NO_RESULT, IDS_OPERATION_FAILED_GET_CRED);
GetCredentialsDialog dlg(failureMessage); if (dlg.ModalExecute(progress) == IDOK) { retry = true;
// jump to top of operation loop
continue; }
LOG(L"credential retry canceled");
ComposeFailureMessage( errorThrown, wasDisjoined, originalDomainName); break; } else if (errorThrownHresult == Win32ToHresult(ERROR_DOMAIN_EXISTS)) { LOG(L"domain exists: prompting for re-install");
// ask if the user wishes to reinstall the domain.
if ( popup.MessageBox( progress.GetHWND(), String::format( IDS_REINSTALL_DOMAIN_MESSAGE, state.GetNewDomainDNSName().c_str()), MB_YESNO | MB_ICONWARNING) == IDYES) { state.SetDomainReinstallFlag(true); retry = true;
// jump to top of operation loop
continue; }
LOG(L"reinstall domain retry canceled"); } else if ( errorThrownHresult == Win32ToHresult(ERROR_DOMAIN_CONTROLLER_EXISTS)) { LOG(L"domain controller exists: prompting to force promote");
// ask if the user wants to re-install the domain controller
if ( popup.MessageBox( progress.GetHWND(), String::format( IDS_REINSTALL_DOMAIN_CONTROLLER_MESSAGE, state.GetComputer().GetNetbiosName().c_str()), MB_YESNO | MB_ICONWARNING) == IDYES) { state.SetDomainControllerReinstallFlag(true); retry = true;
// jump to the top of the operation loop
continue; }
LOG(L"reinstall domain controller retry canceled"); }
// if we're retrying, then we should have jumped to the top of
// the loop.
ASSERT(!retry); ComposeFailureMessage( errorThrown, wasDisjoined, originalDomainName);
// NTRAID#NTBUG9-416968-2001/06/14-sburns
#ifdef DBG
if (state.IsExitOnFailureMode()) { // Farewell.
LOG(L"exit-on-failure mode active: time to die.");
::ExitProcess(0); } #endif
Win::MessageBox( progress.GetHWND(), state.GetFailureMessage(), errorThrown.GetSummary(), // title the error was built with
MB_OK | MB_ICONERROR | MB_SYSTEMMODAL); } } while (retry);
#ifdef DBG
if (message == ProgressDialog::THREAD_FAILED) { ASSERT(state.GetOperationResultsCode() == State::FAILURE); } else { ASSERT(state.GetOperationResultsCode() == State::SUCCESS); } #endif
LOG(L"posting message to progress window");
HRESULT hr = Win::PostMessage(progress.GetHWND(), message, 0, 0);
ASSERT(SUCCEEDED(hr));
// do not call _endthread here, or stack will not be properly cleaned up
}
bool ConfirmationPage::OnCommand( HWND windowFrom, unsigned controlIdFrom, unsigned code) { bool result = false; switch (controlIdFrom) { case IDCANCEL: { // multi-line edit control eats escape keys. This is a workaround
// from ericb, to forward the message to the prop sheet.
Win::SendMessage( Win::GetParent(hwnd), WM_COMMAND, MAKEWPARAM(controlIdFrom, code), (LPARAM) windowFrom); break; } case IDC_MESSAGE: { switch (code) { case EN_SETFOCUS: { if (needToKillSelection) { // kill the text selection
Win::Edit_SetSel(windowFrom, -1, -1); needToKillSelection = false; result = true; } break; } case MultiLineEditBoxThatForwardsEnterKey::FORWARDED_ENTER: { // our subclasses mutli-line edit control will send us
// WM_COMMAND messages when the enter key is pressed. We
// reinterpret this message as a press on the default button of
// the prop sheet.
// This workaround from phellyar.
// NTRAID#NTBUG9-232092-2000/11/22-sburns
HWND propSheet = Win::GetParent(hwnd); int defaultButtonId = Win::Dialog_GetDefaultButtonId(propSheet); // we expect that there is always a default button on the prop sheet
ASSERT(defaultButtonId); Win::SendMessage( propSheet, WM_COMMAND, MAKELONG(defaultButtonId, BN_CLICKED), 0); result = true; break; } } break; } default: { // do nothing
break; } }
return result; }
|