/**********************************************************************/
/**			  Microsoft Windows/NT			     **/
/**		   Copyright(c) Microsoft Corp., 1991		     **/
/**********************************************************************/

/*
    NCPDMAIN.CXX:    Windows/NT Network Control Panel Applet;

	    Main dialog presentation module.

    FILE HISTORY:
	DavidHov    10/9/91	    Created
        DavidHov    07/24/92        Removed server service checkboxes;
                                    added support for Update button.

*/

#include "pchncpa.hxx"

#if !defined(_CFRONT_PASS_)
#pragma hdrstop            //  This file creates the PCH
#endif



  //  Input parameter used to just run bindings algorithm.

static const TCHAR * pszParamBindOnly = SZ("BINDONLY") ;


REG_LISTBOX :: REG_LISTBOX ( OWNER_WINDOW * powin, CID cid )
    : STRING_LISTBOX( powin, cid ),
    _pcdlList( NULL )
{
}

REG_LISTBOX :: ~ REG_LISTBOX ()
{
    delete _pcdlList ;
}

APIERR REG_LISTBOX :: Fill ( COMPONENT_DLIST * pcdlList )
{
    Drain();
    _pcdlList = pcdlList ;

    APIERR err = NERR_Success ;
    INT cItems = _pcdlList->QueryNumElem() ;
    NLS_STR nlsName,
	    nlsDesc ;

    for ( INT cItem = 0 ; cItem < cItems ; cItem++ )
    {
	err = _pcdlList->QueryInfo( cItem, & nlsName, & nlsDesc ) ;

	if ( err )
	    break ;

	AddItem( nlsDesc ) ;
    }
    return err ;
}


VOID REG_LISTBOX :: Drain ()
{
    DeleteAllItems() ;
    delete _pcdlList ;
    _pcdlList = NULL ;
}


    //	Return a pointer to the selected element in the REG_LISTBOX

REG_KEY * REG_LISTBOX :: QuerySelComponent ()
{
    INT iSel = QueryCurrentItem() ;
    return iSel >= 0 ? _pcdlList->QueryNthItem( iSel ) : NULL ;
}


DLG_REG_LIST_GROUP :: DLG_REG_LIST_GROUP
   ( NCPA_DIALOG * pdlgNCPA,
     REG_LISTBOX & rlb1,
     REG_LISTBOX & rlb2,
     SLE & sleDescription,
     SLT & sltDescStatic,
     PUSH_BUTTON & butnConfigure,
     PUSH_BUTTON & butnRemove,
     PUSH_BUTTON & butnUpdate,
     REGISTRY_MANAGER & regMgr )
    : _pdlgNCPA( pdlgNCPA ),
      _rlb1( rlb1 ),
      _rlb2( rlb2 ),
      _sleDescription( sleDescription ),
      _sltDescStatic( sltDescStatic ),
      _butnConfigure( butnConfigure ),
      _butnRemove( butnRemove ),
      _butnUpdate( butnUpdate ),
      _prnDescription( NULL ),
      _regMgr( regMgr ),
      _fFilled( FALSE )
{
    _rlb1.SetGroup( this ) ;
    _rlb2.SetGroup( this ) ;
    ResetDescription( NULL );
}

DLG_REG_LIST_GROUP :: ~ DLG_REG_LIST_GROUP ()
{
    ResetDescription( NULL ) ;
}

BOOL DLG_REG_LIST_GROUP :: QueryUserAdmin()
{
    return _pdlgNCPA->QueryUserAdmin();
}

APIERR DLG_REG_LIST_GROUP :: OnUserAction
   ( CONTROL_WINDOW * pcw, const CONTROL_EVENT & cEvent )
{

    if (    cEvent.QueryMessage() == WM_COMMAND
	&&  cEvent.QueryCode() == LBN_SELCHANGE )
    {
	REG_LISTBOX * prlbOther = pcw == & _rlb1 ? & _rlb2 : & _rlb1 ;

        //  Guarantee that only one listbox has a selection.
	prlbOther->RemoveSelection() ;

        //  Change the description SLE; handle alteration.
        ResetDescription( QuerySelComponent() ) ;
    }
    return NERR_Success ;
}

    //	Return a pointer to the selected element in either listbox.

REG_KEY * DLG_REG_LIST_GROUP :: QuerySelComponent ()
{
    REG_KEY * prnNode = _rlb1.QuerySelComponent() ;
    if ( prnNode == NULL )
       prnNode = _rlb2.QuerySelComponent() ;
    return prnNode ;
}

   //  Return TRUE if the Adapters list has the current selection

BOOL DLG_REG_LIST_GROUP :: QueryAdapterListSelected ()
{
     return _rlb2.QuerySelComponent() != NULL ;
}

    //  Drain the listboxes, erase the description.

APIERR DLG_REG_LIST_GROUP :: Drain ()
{
    ResetDescription( NULL ) ;

    _rlb1.SetRedraw( FALSE ) ;
    _rlb2.SetRedraw( FALSE ) ;

    _rlb1.Drain();
    _rlb2.Drain();

    _rlb1.SetRedraw( TRUE ) ;
    _rlb2.SetRedraw( TRUE ) ;

    _rlb1.Invalidate( TRUE ) ;
    _rlb2.Invalidate( TRUE ) ;

    _fFilled = FALSE ;

    return 0 ;
}

    //  Reconstruct the listboxes

APIERR DLG_REG_LIST_GROUP :: Refill ()
{
    APIERR err, err2 ;
    REG_KEY * prkSelection ;
    REG_LISTBOX * prlbSelected ;
    BOOL fIncludeHidden = FALSE ;

#if defined(DEBUG)
    if ( NCPA_DBG_FLAG_ON( _pdlgNCPA->QueryDebugFlags(), NCPA_DBGCTL_NO_HIDDEN ) )
    {
        fIncludeHidden = TRUE ;
    }
#endif

    ResetDescription( NULL ) ;

    _rlb1.SetRedraw( FALSE ) ;
    _rlb2.SetRedraw( FALSE ) ;

    _rlb1.Drain();
    _rlb2.Drain();

    err  = _rlb1.Fill( _regMgr.ListOfProducts( fIncludeHidden ) ) ;
    err2 = _rlb2.Fill( _regMgr.ListOfAdapters( fIncludeHidden ) ) ;

    if ( err == 0 )
        err = err2 ;

    //  Select the first adapter if there is one; if not,
    //    select the first software compoent.

    prlbSelected = & _rlb2 ;
    prkSelection = _rlb2.QueryComponentList()->QueryNthItem( 0 ) ;
    if ( prkSelection == NULL )
    {
        prlbSelected = & _rlb1 ;
        prkSelection = _rlb1.QueryComponentList()->QueryNthItem( 0 ) ;
    }
    if ( prkSelection )
    {
        ResetDescription( prkSelection ) ;
        prlbSelected->SelectItem( 0 ) ;
    }
    _rlb1.SetRedraw( TRUE ) ;
    _rlb2.SetRedraw( TRUE ) ;

    _rlb1.Invalidate( TRUE ) ;
    _rlb2.Invalidate( TRUE ) ;

    _fFilled = TRUE ;

    return err ;
}

   //  There's a new entry for the Description SLE.  See if
   //  the old entry has changed, and alter it if so.

APIERR DLG_REG_LIST_GROUP ::  ResetDescription ( REG_KEY * prnNewSel )
{
    APIERR err  = 0,            //  Error from setting prior string
           err2 = 0 ;           //  Error from getting next string

    if ( prnNewSel != _prnDescription )
    {
        TCHAR * pchDesc = NULL ;
        NLS_STR nlsDesc ;

        if ( err = nlsDesc.QueryError() )
            return err ;

        //  If we had a desription, check to see if it has changed.

        if ( _prnDescription )
        {
            err = _sleDescription.QueryText( & nlsDesc ) ;
            if ( err == 0 && nlsDesc != _nlsDescription )
            {
                err = _regMgr.SetValueString( _prnDescription,
                                               RGAS_COMPONENT_DESC,
                                               nlsDesc.QueryPch() ) ;
            }
        }

        _sleDescription.SetText( SZ("") ) ;

        if ( (_prnDescription = prnNewSel) != NULL )
        {
            _sleDescription.Enable( QueryUserAdmin() ) ;
            _sltDescStatic.Enable( QueryUserAdmin() ) ;

            err2 = _regMgr.QueryValueString( prnNewSel,
                                             RGAS_COMPONENT_DESC,
                                             & pchDesc ) ;
            if ( ! err2 )
            {
                _nlsDescription = pchDesc ;
                if ( _nlsDescription.QueryError() == 0 )
                {
                    _prnDescription = prnNewSel ;
                    _sleDescription.SetText( _nlsDescription ) ;
                }
            }
            else
            {
                _nlsDescription = SZ("") ;
            }
            delete pchDesc ;
        }
    }

    if ( _prnDescription == NULL )
    {
        _sleDescription.Enable( FALSE ) ;
        _sltDescStatic.Enable( FALSE ) ;
    }

    _butnConfigure.Enable( QueryUserAdmin() && _prnDescription != NULL ) ;
    _butnRemove.Enable( QueryUserAdmin() && _prnDescription != NULL ) ;
    _butnUpdate.Enable( QueryUserAdmin() && _prnDescription != NULL ) ;

    return err ? err : err2 ;
}


static void alterWindowStyle (
    HWND hwnd,
    LPARAM lStyle,
    BOOL fSet = TRUE )
{
    LPARAM lStyleSet = ::GetWindowLong( hwnd, GWL_STYLE ) ;

    if ( fSet )
       lStyleSet |= lStyle ;
    else
       lStyleSet &= ~ lStyle ;

    ::SetWindowLong( hwnd, GWL_STYLE, lStyleSet ) ;
}

static void alterWindowStyle (
    CONTROL_WINDOW * pwCtl,
    LPARAM lStyle,
    BOOL fSet = TRUE )
{
    alterWindowStyle( pwCtl->QueryHwnd(), lStyle, fSet ) ;
}


/*******************************************************************

    NAME:	NCPA_DIALOG :: NCPA_DIALOG

    SYNOPSIS:	Main dialog constructor

    ENTRY:	nothing

    EXIT:	normal for BASE object

    RETURNS:	nothing

    NOTES:

    HISTORY:

********************************************************************/

NCPA_DIALOG :: NCPA_DIALOG (
    HWND hwndOwner,
    BOOL fMainInstall,
    const TCHAR * pszInstallParms )
    : DIALOG_WINDOW( DLG_NM_NCPA, hwndOwner ),
    _timer( this, NCPA_POLLING_INTERVAL, FALSE ),
    _pszInstallParms( pszInstallParms ),
    _sltDomain(      this, IDC_MAIN_DOMAIN_NAME ),
    _sltDomainLabel( this, IDC_MAIN_SLT_DOMAIN ),
    _sltComputer(    this, IDC_MAIN_COMPUTER_NAME ),
    _sltOverlay(     this, IDC_MAIN_OVERLAY ),
    _rlbComponents(  this, IDC_MAIN_LIST_PROTOCOLS ),
    _rlbCards(       this, IDC_MAIN_LIST_CARDS ),
    _sltDescStatic(  this, IDC_MAIN_STATIC_DESC ),
    _sleDescription( this, IDC_MAIN_EDIT_DESCRIPTION, 256 ),
    _butnCancel(     this, IDCANCEL ),
    _butnBindings(   this, IDC_MAIN_BUTN_BINDINGS ),
    _butnDomain(     this, IDC_MAIN_BUTN_DOMAIN ),
    _butnComputer(   this, IDC_MAIN_BUTN_COMPUTERNAME ),
    _butnProviders(  this, IDC_MAIN_BUTN_PROVIDERS ),
    _butnConfigure(  this, IDC_MAIN_BUTN_CONFIGURE ),
    _butnAdd(        this, IDC_MAIN_BUTN_ADD ),
    _butnAddCard(    this, IDC_MAIN_BUTN_ADD_CARD ),
    _butnRemove(     this, IDC_MAIN_BUTN_REMOVE ),
    _butnUpdate(     this, IDC_MAIN_BUTN_UPDATE ),
    _bindery( fMainInstall, pszInstallParms ),
    _drlGrp( this, _rlbComponents, _rlbCards,
             _sleDescription, _sltDescStatic,
             _butnConfigure, _butnRemove, _butnUpdate,
             _bindery )
{
    // CODEWORK :: these items are init'ed here because C8 dies
    //   with "too many open parentheses" otherwise.

    _hControlPanel = hwndOwner;
    _pdmgrDomain = NULL ;
    _psvcManager = NULL ;
    _pnscControl = NULL ;
    _pnscCtrlSave = NULL ;
    _lastErr = 0 ;
    _lastApiErr = 0 ;
    _lastDeferredErr = 0 ;
    _ptddacl = NULL ;
    _pOffscreenDialog = NULL ;
    _fMainInstall = fMainInstall ;
    _fWinNt = TRUE ;
    _fAdmin = FALSE ;
    _fConfigLocked = FALSE ;
    _fRebootRecommended = FALSE ;
    _fRefill = FALSE ;
    _fAuto = FALSE ;
    _eiMode = NCPA_IMODE_NONE ;
    _dwDebugFlags = 0 ;

    if ( QueryError() )
	return ;		//  Construction failure

    if ( _bindery.QueryError() )
    {				//  BINDERY Construction failure
	ReportError( _bindery.QueryError() ) ;
	return ;
    }

#if defined(TRACE)
    //  Drag in the debugging flags, if any.

    if ( _bindery.GetNcpaValueNumber( NCPA_DEBUG_CONTROL, & _dwDebugFlags ) == 0 )
    {
        // Found the value; indicate that the flags are active.
        _dwDebugFlags |= NCPA_DBGCTL_ACTIVE ;
    }
#endif

    //  Enable the timer; tick...tick...tick...

    _timer.Enable( TRUE ) ;

    //  Set the current directory to %SystemRoot%\SYSTEM.
    SetDirectory() ;

    //  Determine whether the user can access the full scope or any
    //    information whatever
    if ( ! EstablishUserAccess() )
    {
        ReportError( _lastErr ) ;
        return ;
    }

    //  Since EstablishUserAccess() was successful, we now have a
    //  DOMAIN_MANAGER at our disposal.

    //  If this is main installation, alter the dialog face to
    //  overlay the help text on top of the domain and machine name.
    //  Otherwise, if the user is admin, obtain the additional
    //  data.

    BOOL fGetBasicFields = TRUE ;

    if ( _fMainInstall )
    {
        //  Get the installation mode.
        _eiMode = QueryInstallMode() ;

        RenameCancelToClose() ;

        //  Since we cannot rely on the size or position of the parent
        //  window, center this dialog in the physical screen.

        INT cx = ::GetSystemMetrics( SM_CXSCREEN ) / 2 ;
        INT cy = ::GetSystemMetrics( SM_CYSCREEN ) / 2 ;
        INT cWidth, cHeight ;

        QuerySize( & cWidth, & cHeight ) ;

        XYPOINT xyNew( cx - (cWidth/2), cy - (cHeight/2) ) ;

        //  Don't repaint, since DIALOG_WINDOW will do that immediately
        //  upon return.

        SetPos( xyNew, FALSE ) ;

        //
        //  Now we have to play with the controls.   There are two distinct
        //  "installation" states: normal and retry.  In normal installation,
        //  we hide the "change computername" and "change domain/workgroup"
        //  controls and cover them with a text control.   In retry mode,
        //  we allow access to the "change computername" control but
        //  not the "change domain/workgroup" controls.
        //
        if ( _eiMode == NCPA_IMODE_RETRY )
        {
            //  Disable all domain/workgroup related controls.
            _butnDomain.Enable( FALSE ) ;
            _sltDomainLabel.Enable( FALSE ) ;
            _sltDomain.Enable( FALSE ) ;
        }
        else
        {
            HWND hwnd ;
            NLS_STR nlsMsg ;

            //  If not "retry", hide the upper controls

            fGetBasicFields = FALSE ;

            alterWindowStyle( & _sltComputer,    WS_VISIBLE, FALSE ) ;
            alterWindowStyle( & _butnDomain,     WS_VISIBLE, FALSE ) ;
            alterWindowStyle( & _butnComputer,   WS_VISIBLE, FALSE ) ;
            alterWindowStyle( & _sltDomainLabel, WS_VISIBLE, FALSE ) ;
            alterWindowStyle( & _sltDomain,      WS_VISIBLE, FALSE ) ;

            if ( hwnd = ::GetDlgItem( QueryHwnd(), IDC_MAIN_SLT_COMPUTER ) )
                 alterWindowStyle( hwnd, WS_VISIBLE, FALSE ) ;

            //   Build and reveal the help text.

            if ( ::ConcatMsgs( & nlsMsg, IDS_NCPA_OVERLAY1 ) == 0 )
                _sltOverlay.SetText( nlsMsg ) ;

            alterWindowStyle( & _sltOverlay,  WS_VISIBLE ) ;
        }
    }

    if ( fGetBasicFields )
    {
        //  Read in the basic LANMan/NT information

        HandleBasicFields() ;
        _lastErr = 0 ;

    }

    //  Drag in the bindings information

    if ( _bindery.QueryBindState() == BND_NOT_LOADED )
    {
        if ( LoadBindings() )
        {
            _bindery.SetBindState( BND_CURRENT ) ;
        }
        else
        {
#if defined(DEBUG)
             DBGEOL( SZ("NCPA/MAIN: bind info load failure; error ")
                     <<  _lastErr ) ;
#endif
            _bindery.SetBindState( BND_OUT_OF_DATE ) ;
            _lastErr = 0 ;
            SetReboot() ;
        }
    }

    if ( _bindery.QueryCfgDirty() )
    {
        SetReboot() ;
    }

    //	Fill the two list boxes

    _drlGrp.Refill() ;

    //  Disable the Providers button if the number of providers is < 2.

    if ( _fMainInstall || ((QueryNumProviders() < 2) || (QueryNumPrintProviders() < 2)))
    {
        _butnProviders.Enable( FALSE ) ;
    }

    if ( !_fMainInstall && !QueryUserAdmin() )
    {
        //  Disable any modifications, installations, etc.

        _butnComputer.Enable( FALSE ) ;
        _butnDomain.Enable( FALSE ) ;
        _butnBindings.Enable( FALSE ) ;
        _butnProviders.Enable( FALSE ) ;
        _butnConfigure.Enable( FALSE ) ;
        _butnAdd.Enable( FALSE ) ;
        _butnAddCard.Enable( FALSE );
        _butnRemove.Enable( FALSE );
        _butnUpdate.Enable( FALSE );
        _sleDescription.Enable( FALSE );
    }

// End of code from OnExpand()

}

ULONG NCPA_DIALOG :: QueryHelpContext ()
{
    return HC_NCPA_MAIN_DIALOG ;
}


/*******************************************************************

    NAME:	NCPA_DIALOG :: SetReboot

    SYNOPSIS:	Set the reboot flag on if parameter is TRUE; has
                no effect if reboot is already on.  Once on,
                reboot flag cannot be reset.

    ENTRY:	BOOL fOn

    EXIT:	

    RETURNS:	BOOL  new value of reboot flag.

    NOTES:

    HISTORY:

********************************************************************/
BOOL NCPA_DIALOG :: SetReboot ( BOOL fOn )
{
    BOOL fWasOn = _fRebootRecommended ;

    _fRebootRecommended = fOn ;

    if ( fOn && ! fWasOn )
    {
        TRACEEOL(SZ("NCPA/MAIN: setting reboot"));
        RenameCancelToClose() ;
    }

    return _fRebootRecommended ;
}

/*******************************************************************

    NAME:	NCPA_DIALOG :: SetDirectory

    SYNOPSIS:	Establish proper directory for NCPA to function

    ENTRY:	nothing

    EXIT:	nothing

    RETURNS:	BOOL if successful

    NOTES:      The Control Panel appears to consider %Systemroot%
                to be its home location.  For SETUP to execute,
                we need %Systemroot\SYSTEM.

    HISTORY:

********************************************************************/
BOOL NCPA_DIALOG :: SetDirectory ()
{
    TCHAR achPath [MAX_PATH] ;

    DWORD cchPath = ::GetCurrentDirectory( sizeof achPath, achPath ) ;

    if ( cchPath > 0 && cchPath < sizeof achPath )
    {
        _nlsCurrentDirectory = achPath ;
    }

    cchPath = ::GetSystemDirectory( achPath, sizeof achPath ) ;

    if ( cchPath > 0 && cchPath < sizeof achPath )
    {
        TRACEEOL( SZ("NCPA/NCPA: Current directory set to: ")
                  << achPath );
        return ::SetCurrentDirectory( achPath ) ;
    }
    return FALSE ;
}

/*******************************************************************

    NAME:	NCPA_DIALOG :: ResetDirectory

    SYNOPSIS:	

    ENTRY:	nothing

    EXIT:	nothing

    RETURNS:	TRUE if successful

    NOTES:      returns the current directory to where it was
                when the dialog opened

    HISTORY:

********************************************************************/
BOOL NCPA_DIALOG :: ResetDirectory ()
{
    if ( _nlsCurrentDirectory.QueryTextLength() != 0 )
    {
        TRACEEOL( SZ("NCPA/NCPA: Reset current directory to: ")
                  << _nlsCurrentDirectory.QueryPch() );
        return ::SetCurrentDirectory( (TCHAR *)  _nlsCurrentDirectory.QueryPch() ) ;
    }
    return FALSE ;
}

/*******************************************************************

    NAME:	NCPA_DIALOG::MayRun

    SYNOPSIS:	Override of standard MayRun() member.
                If we're installing in "express" mode,

    ENTRY:	Nothing

    EXIT:       TRUE if NCPA dialog is to be presented in normal form.

    RETURNS:	APIERR

    NOTES:      If we're INSTALLING but we're not in CUSTOM mode,
                or if we've been explicity called for "run bindings only"
                then just flash the dialog, run the bindings algorithm,
                store the bindings and leave.  The user is not allowed
                to fiddle with the product ensemble in this mode.

                In addition, if we're not installing, find out if
                the LanmanWorkstation service is installed and install
                standard MS NT Networking if the user so desires.

    HISTORY:    DavidHov     4/20/92     Created

********************************************************************/
BOOL NCPA_DIALOG :: MayRun ()
{
    BOOL fResult = TRUE ;
    BOOL fBindOnly = CheckBoolSetupParameter( pszParamBindOnly ) ;

    if ( _fMainInstall || fBindOnly )
    {
        //  Set the "bindings out of date" flag to force reconfiguration
        if ( fBindOnly || _eiMode != NCPA_IMODE_RETRY )
            _bindery.SetBindState( BND_OUT_OF_DATE ) ;

        //  Set the "autopilot" flag if we're not supposed to interact
        //  with the user.
        _fAuto = fBindOnly || _eiMode == NCPA_IMODE_EXPRESS ;

        //  If we're just being called for rebind, clear any left-over
        //  reboot flag (due to existence of ConfigChanged key).
        if ( fBindOnly )
        {
           SetReboot( FALSE ) ;
        }

        //  If this is a RETRY, stop the network.

        if ( _eiMode == NCPA_IMODE_RETRY )
        {
            AUTO_CURSOR cursAuto ;   //  put up the eternal hourglass
            TRACEEOL( SZ("NCPA/MAIN: stopping the network") );
            _bindery.StopNetwork() ;
            TRACEEOL( SZ("NCPA/MAIN: network stop complete.") );
        }
    }

    if ( _fAuto )
    {
        //  Express Mode:
        //     Complete all necessary operations;
        //     compute bindings; do INF callouts, etc.

#ifdef GLOBAL_LOCK
        ConfigLock( TRUE ) ;
#endif // GLOBAL_LOCK

        Close( FALSE ) ;

        //  Suppress real dialog execution
        fResult = FALSE ;
        _lastDeferredErr = 0 ;
    }
    else
    if ( QueryUserAdmin() )
    {
        //  Check to see if LanmanWorkstation service exists.
        //      Only display the main dialog if we DON'T launch
        //      NT LANManager installation.

        if ( CheckForAndInstallLanManager() )
        {
            fResult = FALSE ;
            _lastDeferredErr = 0 ;
            SetReboot( FALSE ) ;
            Dismiss( _lastErr = IDS_NCPA_PROCESS_LAUNCH ) ;
        }
    }

    //  Display any minor construction error

    if ( _lastDeferredErr )
    {
        DoMsgPopup() ;
    }

    return fResult ;
}

/*******************************************************************

    NAME:       NCPA_DIALOG::Close

    SYNOPSIS:   Handle all exit paths out of this dialog.

    ENTRY:      BOOL            TRUE if Cancel/Close button was used

    EXIT:

    RETURNS:    BOOL to return to window handler

    NOTES:

    The state of the network bindings is checked.  If
    the ensemble of products has changed or the user has
    reviewed the bindings, the Cancel button is now
    titled Close.

    If the bindings have been reviewed, they have already
    been computed and can be stored straightaway; otherwise,
    they must be computed.

    Note that we don't check or obtain the configuration
    lock.  This should already have been done by the
    function which instigated the change.  The lock is
    released by the dialog's destructor.

    HOW BINDINGS REVIEW WORKS:

    When the product ensemble has changed, we must store
    the recomputed bindings into the Registry via
    StoreBindings().  This member function will also
    handle the process of automatic bindings review by calling
    RunBindingsReview().

    FinishBindings() is then called to snapshot the state of the
    bindings for quick review, and the request to close the dialog
    is finally honored.

    HISTORY:

********************************************************************/
BOOL NCPA_DIALOG :: Close ( BOOL fCancel )
{
    //  If we started the separate process to install the network,
    //  don't put up the "reboot now" popup.  Otherwise, if
    //  this is not main installation, prompt the user.

    if ( _lastErr == IDS_NCPA_PROCESS_LAUNCH )
    {
        _fRebootRecommended = FALSE;
    }
    else
    if ( ! (_fMainInstall || _fAuto) )
    {
        //  Set the "reboot recommended" flag on if things have changed;
        //  leave it on if it's already on.

        _fRebootRecommended |=  _bindery.QueryBindState() > BND_OUT_OF_DATE_NO_REBOOT ;
    }

    switch ( _bindery.QueryBindState() )
    {
    case BND_NOT_LOADED:
    case BND_LOADED:
    case BND_CURRENT:

        //  The dialog execution has NOT changed the overall state of
        //    the product ensemble.  Return "Cancelled" to the caller
        //    if this is the Cancel button.

        break ;

    case BND_OUT_OF_DATE_NO_REBOOT:
    case BND_OUT_OF_DATE:

        // Product ensemble has changed.  Recompute the bindings
        //   and fall thru to apply them to the Registry

        if ( !QueryUserAdmin())
        {
            break;
        }

        if ( ! ComputeBindings() )
        {
            //  Since the binding operation has failed, suppress
            //  the reboot prompting.

             DoMsgPopup() ;
             break ;
        }
        RepaintNow() ;

    case BND_RECOMPUTED:
    case BND_REVIEWED:
    case BND_UPDATED:

        //  Write the bindings to the Registry, call interested parties,
        //    write the bindings state value, etc.

        if ( !QueryUserAdmin())
        {
            break;
        }

        if ( ! StoreBindings() )
        {
            DoMsgPopup() ;
        }
        RepaintNow() ;

    case BND_AUTO_REVIEW_DONE:

        //  Generate and write our saved data structure into the Registry

        if ( !QueryUserAdmin())
        {
            break;
        }

        FinishBindings();
        break ;

    default:
        TRACEEOL( SZ("NCPA/DIALOG: Invalid bind state during close: ")
                  << (long) _bindery.QueryBindState() ) ;
        break ;
    }

    TRACEEOL( SZ("NCPA/DIALOG: Main NCPA dialog dismissed") ) ;
    Dismiss( _lastErr ) ;

    return TRUE ;
}

BOOL NCPA_DIALOG ::  OnOK ()
{
    return Close( FALSE ) ;
}

BOOL NCPA_DIALOG :: OnCancel ()
{
    return Close( TRUE ) ;
}

/*******************************************************************

    NAME:	NCPA_DIALOG::RenameCancelToClose

    SYNOPSIS:	The effects of this dialog are now irreversible.
                Change the name of the Cancel button to Close to
                indicate this.

    ENTRY:	nothing

    EXIT:	nothing

    RETURNS:	APIERR (hopefully not)

    NOTES:

    HISTORY:

********************************************************************/
APIERR NCPA_DIALOG :: RenameCancelToClose()
{
    NLS_STR nlsButton ;
    APIERR err ;

    if ( (err = nlsButton.QueryError()) == 0 )
    {
        if ( (err = nlsButton.Load( IDS_NCPA_NAME_CLOSE )) == 0 )
        {
            _butnCancel.SetText( nlsButton ) ;
            _butnCancel.Invalidate() ;
        }
    }
    return err ;
}

 //  BUGBUG:  this should be a member function

static void setFocusOnOk ( DIALOG_WINDOW * pDlg )
{
    ::SetFocus( ::GetDlgItem( pDlg->QueryHwnd(), IDOK ) ) ;
}

/*******************************************************************

    NAME:	NCPA_DIALOG::OnCommand

    SYNOPSIS:	Handle dialog-based events.

    ENTRY:	const CONTROL_EVENT & event
			 the event which has occurred

    EXIT:	TRUE if the event was handled

    RETURNS:

    NOTES:      The configuration lock is obtained only when
                needed, and kept until the dialog is dismissed.

    HISTORY:

********************************************************************/
BOOL NCPA_DIALOG::OnCommand ( const CONTROL_EVENT & event )
{
    BOOL fDefault = TRUE ;
    BOOL fResult = FALSE ;
    BOOL fOk = TRUE ;
    REG_KEY * prnComponent = NULL ;
    static BOOL fDescHasFocus = FALSE ;

    switch ( event.QueryCid() )
    {
    //   Rename Cancel to Close whenever the description is updated.
    //   Note that we only check when the control has focus;
    //   otherwise, we'd be reacting to programmatic changes in
    //   its contents.

    case IDC_MAIN_EDIT_DESCRIPTION:
        switch ( event.QueryCode() )
        {
        case EN_CHANGE:
            if ( fDescHasFocus )
            {
                RenameCancelToClose();
            }
            break ;

        case EN_SETFOCUS:
            fDescHasFocus = TRUE ;
            break ;

        case EN_KILLFOCUS:
            fDescHasFocus = FALSE ;
            break ;
        }
        break ;

    case IDC_MAIN_BUTN_DOMAIN:
        fResult = TRUE ;
        fDefault = FALSE ;
#ifdef GLOBAL_LOCK
        fOk = ConfigLock( TRUE ) && RunDomainDialog() ;
#endif // GLOBAL_LOCK
        fOk = RunDomainDialog() ;
        break ;

    case IDC_MAIN_BUTN_COMPUTERNAME:
        fResult = TRUE ;
        fDefault = FALSE ;
#ifdef GLOBAL_LOCK
        fOk = ConfigLock( TRUE ) && RunComputerNameDialog() ;
#endif // GLOBAL_LOCK
        fOk = RunComputerNameDialog() ;
        if ( _fRebootRecommended )
        {
            // Disable the Domain Change... button if the computername
            // has been changed.
            _butnDomain.Enable( FALSE );
        }
	break;

    case IDC_MAIN_BUTN_PROVIDERS:
        fResult = TRUE ;
        fDefault = FALSE ;
#ifdef GLOBAL_LOCK
        fOk = ConfigLock( TRUE ) && RunProvidersDialog() ;
#endif // GLOBAL_LOCK
        fOk = RunProvidersDialog() ;
        break ;

    case IDC_MAIN_BUTN_BINDINGS:
	fResult = TRUE ;
	fDefault = FALSE ;
#ifdef GLOBAL_LOCK
        if ( ! (fOk = ConfigLock( TRUE )) )
            break ;
#endif // GLOBAL_LOCK

        if (    _bindery.QueryCompAssoc() == NULL
             || _bindery.QueryBindState() == BND_OUT_OF_DATE
             || _bindery.QueryBindState() == BND_OUT_OF_DATE_NO_REBOOT )
        {
            //   Rerun the binding algorithm and update the Registry.

            if ( ! (fOk = ComputeBindings() && StoreBindings( FALSE )) )
            {
                break ;
            }
        }

        //  Bindings are marked as "changed" if either we have
        //  regenerated them or the user has altered them.

	if ( RunBindingsDialog() )
        {
            _bindery.SetBindState( BND_REVIEWED );
        }

	break ;

    case IDC_MAIN_BUTN_ADD_CARD:

#ifdef GLOBAL_LOCK
        if ( ! (fOk = ConfigLock( TRUE )) )
            break ;
#endif // GLOBAL_LOCK

        //
        // Make sure we can lock the service controller database before trying to install.  This ensures
        // that the srevice controller is not still autostarting.
        //
        if ( _lastErr = _psvcManager->Lock() )
        {
            fOk = FALSE;
            break ;
        }
        _psvcManager->Unlock();

        if ( _bindery.QueryBindState() == BND_REVIEWED )
        {
            DoWarning( IDS_NCPA_BINDINGS_REVIEW_LOST ) ;
        }

        setFocusOnOk( this ) ;
        fOk = RunAddCard() || _lastErr == IDS_NCPA_SETUP_CANCELLED ;
	fResult = TRUE ;
	fDefault = FALSE ;
	break ;

    case IDC_MAIN_BUTN_ADD:

#ifdef GLOBAL_LOCK
        if ( ! (fOk = ConfigLock( TRUE )) )
            break ;
#endif // GLOBAL_LOCK
        //
        // Make sure we can lock the service controller database before trying to install.  This ensures
        // that the srevice controller is not still autostarting.
        //
        if ( _lastErr = _psvcManager->Lock() )
        {
            fOk = FALSE;
            break ;
        }
        _psvcManager->Unlock();

        if ( _bindery.QueryBindState() == BND_REVIEWED )
        {
            DoWarning( IDS_NCPA_BINDINGS_REVIEW_LOST ) ;
        }

        setFocusOnOk( this ) ;
        fOk = RunAddComponent() || _lastErr == IDS_NCPA_SETUP_CANCELLED ;
	fResult = TRUE ;
	fDefault = FALSE ;
	break ;

    case IDC_MAIN_LIST_PROTOCOLS:
    case IDC_MAIN_LIST_CARDS:

        //  A double-click in one of the component listboxes is
        //  a request to reconfigure the component.

        if ( event.QueryCode() != LBN_DBLCLK || !QueryUserAdmin() )
            break ;

        //  Fall thru to get selection and reconfigure...

    case IDC_MAIN_BUTN_REMOVE:

        //  Re-check of CID required due to fall thru above

        if ( event.QueryCid() == IDC_MAIN_BUTN_REMOVE )
        {
            if ( ::MsgPopup( this,
                             IDS_NCPA_REMOVE_WARNING,
                             MPSEV_WARNING,
                             MP_YESNO,
                             MP_NO ) != IDYES )
                break ;
        }

    case IDC_MAIN_BUTN_UPDATE:
    case IDC_MAIN_BUTN_CONFIGURE:

        //  Lock the configuration and run the configurator...

#ifdef GLOBAL_LOCK
        if ( ! (fOk = ConfigLock( TRUE )) )
            break ;
#endif // GLOBAL_LOCK

        if ( _bindery.QueryBindState() == BND_REVIEWED )
        {
            DoWarning( IDS_NCPA_BINDINGS_REVIEW_LOST ) ;
        }

        if ( prnComponent = _drlGrp.QuerySelComponent() )
        {
            NCPA_CFG_FUNC ncfg = event.QueryCid() == IDC_MAIN_BUTN_UPDATE
                               ? NCFG_UPDATE
                               : (   event.QueryCid() == IDC_MAIN_BUTN_REMOVE
                                   ? NCFG_REMOVE
                                   : NCFG_CONFIGURE ) ;

            setFocusOnOk( this ) ;
	    fOk = RunConfigurator( prnComponent, ncfg ) ;
        }

        fResult = TRUE ;
        fDefault = FALSE ;
	break ;

    default:
	break ;
    }

    if ( ! fOk )
    {
        DoMsgPopup() ;
    }

    if ( fDefault )
    {
	fResult =  DIALOG_WINDOW::OnCommand( event ) ;
    }

    return fResult ;
}


/*******************************************************************

    NAME:	NCPA_DIALOG::Refill
           and  NCPA_DIALOG::Drain

    SYNOPSIS:	Refill the software and hardware components listboxes

    ENTRY:	Nothing

    EXIT:	Nothing

    RETURNS:	TRUE

    NOTES:	Note that although the methods associated with the
		"expanded" controls exist before Expand() is called,
		they are disabled and hidden.

    HISTORY:

********************************************************************/
VOID NCPA_DIALOG :: Refill ()
{
    TRACEEOL( SZ("NCPA/NCPA: Refill list box start...") );

    // Things have changed; refill the component listboxes.
    _drlGrp.Refill() ;

    TRACEEOL( SZ("NCPA/NCPA: Refill list box end.") );
}

VOID NCPA_DIALOG :: Drain ()
{
    TRACEEOL( SZ("NCPA/NCPA: Drain list boxes.") );
    _drlGrp.Drain() ;
}


/*******************************************************************

    NAME:       NCPA_DIALOG::DoWarning

    SYNOPSIS:   Display a message box containing the last
                error message generated. If no error, no
                popup.

    ENTRY:      MSGID msgId          IDS of message
                BOOL fYesNo          TRUE if user gets a choice
                                     (Yes/No) or not (Ok only).

    EXIT:       Nothing

    RETURNS:    Result button value of ::MsgPopup

    NOTES:

    HISTORY:

********************************************************************/
INT NCPA_DIALOG :: DoWarning ( MSGID msgId, BOOL fYesNo )
{
    UINT uButtons = fYesNo ? MP_YESNO : MP_OK,
         uDefButton = fYesNo ? MP_YES : MP_OK ;

    return ::MsgPopup( this,
                          msgId,
                          MPSEV_WARNING,
                          uButtons,
                          uDefButton ) ;
}

/*******************************************************************

    NAME:       NCPA_DIALOG::DoMsgPopup

    SYNOPSIS:   Display a message box containing the last
                error message generated. If no error, no
                popup.

    ENTRY:      BOOL fReset             TRUE if _lastErr should be
                                        reset to NERR_Success (0)

    EXIT:       Nothing

    RETURNS:    Result button value of ::MsgPopup

    NOTES:      This is a very special case routine.   The caller
                implicitly knows what behavior will occur based
                upon the error code involved: warning, error,
                number of buttons, default button, etc.

    HISTORY:    DavidHov 6/26/92   Changed to use parameterized "default
                                   popup" in all cases.

********************************************************************/
INT NCPA_DIALOG :: DoMsgPopup ( BOOL fReset )
{
    //  Prepare default values for the "default popup".

    INT iResult = 0 ;
    BOOL fDefaultPopup = TRUE ;
    BOOL fRegError = FALSE ;
    const TCHAR * pszString = NULL ;
    MSG_SEVERITY mpSev = MPSEV_ERROR ;
    UINT uButtons = MP_OK,
         uDefButton = MP_UNKNOWN ;

    if ( _lastErr == 0 )
    {
        _lastErr = _lastDeferredErr ;
        _lastDeferredErr = 0 ;
    }

    APIERR err = _lastErr ;

    switch ( _lastErr )
    {
    case NO_ERROR:
    case IDS_NCPA_SETUP_CANCELLED:
        fDefaultPopup = FALSE ;
        break ;

    case ERROR_FILE_NOT_FOUND:
    case ERROR_PATH_NOT_FOUND:

        if ( _nlsMissingFile.QueryTextLength() > 0 )
        {
            err = IDS_NCPA_FILE_NOT_FOUND_STR ;
            pszString = _nlsMissingFile.QueryPch() ;
        }
        else
        {
            err = IDS_NCPA_FILE_NOT_FOUND ;
        }
        break ;

    //  Registry errors

    case ERROR_BADDB:
        fRegError = TRUE ;
        err = IDS_WINREG_BADDB ;
        break ;
    case ERROR_BADKEY:
        fRegError = TRUE ;
        err = IDS_WINREG_BADKEY ;
        break ;
    case ERROR_CANTOPEN:
        fRegError = TRUE ;
        err = IDS_WINREG_CANTOPEN ;
        break ;
    case ERROR_CANTREAD:
        fRegError = TRUE ;
        err = IDS_WINREG_CANTREAD ;
        break ;
    case ERROR_CANTWRITE:
        fRegError = TRUE ;
        err = IDS_WINREG_CANTWRITE ;
        break ;

    case IDS_NCPA_USER_SHOULD_REBOOT:

        // User should reboot now.  Ask her.

        uButtons = MP_YESNO ;
        mpSev = MPSEV_WARNING ;
        uDefButton = MP_YES ;
        break ;

    default:
        break ;
    }

    if ( fDefaultPopup )
    {
        if ( fRegError )
        {
           pszString  =  _bindery.QueryLastName().QueryPch() ;
        }

        if ( pszString )
        {
            iResult = ::MsgPopup( this,
                                  err,
                                  mpSev,
                                  uButtons,
                                  pszString,
                                  uDefButton );
        }
        else
        {
            iResult = ::MsgPopup( this,
                                  err,
                                  mpSev,
                                  uButtons,
                                  uDefButton );
        }
    }

    if ( fReset )
    {
        _nlsMissingFile = SZ("");
        _lastErr = _lastApiErr = _lastDeferredErr = 0 ;
    }

    return iResult ;
}

/*******************************************************************

    NAME:       NCPA_DIALOG::LoadBindings

    SYNOPSIS:   Retrieve the last generation of binding information
                from its Registry-pointed location.  Handle
                errors.

    ENTRY:      Nothing

    EXIT:       BOOL FALSE if failure (check _lastErr)

    RETURNS:    BOOL

    NOTES:      Any older results of bindings are discarded

    HISTORY:
                DavidHov 2/5/92 Created
********************************************************************/
BOOL NCPA_DIALOG :: LoadBindings ()
{
    //  Discard any old results
    _bindery.Reset() ;

    //  Attempt to load bindings from the last cycle.
    _lastErr = _bindery.LoadCompAssoc() ;

    return _lastErr == 0 ;
}

/*******************************************************************

    NAME:       NCPA_DIALOG::StoreBindings

    SYNOPSIS:   Create a new version of the text file containing
                bindings information.

    ENTRY:      There must be an active ARRAY_COMP_ASSOC.

    EXIT:       Nothing

    RETURNS:    BOOL FALSE if operation fails (see _lastErr).

    NOTES:      Write the binding and dependency information to
                the Configuration Registry.

                When complete, start the bindings review process.
                See notes in NCPDINST.CXX and the NCPA_DIALOG::Close()
                member for details.

    HISTORY:    DavidHov 2/5/92   Created
                DavidHov 9/25/92  Added "fApplyBindings"

********************************************************************/
BOOL NCPA_DIALOG :: StoreBindings ( BOOL fApplyBindings )
{
    AUTO_CURSOR cursAuto ;   //  put up the eternal hourglass

    REQUIRE( _bindery.QueryCompAssoc() != NULL ) ;

    _lastErr = 0 ;

    //  Write the bindings to the Registry if necessary

    if ( _bindery.QueryBindState() < BND_UPDATED )
    {
        if ( (_lastErr = _bindery.ApplyBindings( _psvcManager )) == 0 )
        {
            _bindery.SetBindState( BND_UPDATED ) ;
        }
    }

    //  See if any error has occurred.  If not, and we're asked
    //  to "apply bindings", release the configuration lock and
    //  run the bindings review cycle.

    if ( _lastErr )
    {
        _lastApiErr = _lastErr ;
        _lastErr = IDS_NCPA_SERVICE_DEPEND_FAILED ;
    }
    else
    if ( fApplyBindings )
    {
        //  In order to allow INFs to start services, we
        //  must unlock the Service Controller database now.

        ConfigLock( FALSE ) ;

        //  Call out to the components which want to review their
        //    bindings, and to the final review INFs, if any.
        //    Note that RunBindingsRevuiew() sets the binding
        //    state to BND_AUTO_REVIEW_DONE.

        cursAuto.TurnOff() ;
        RunBindingsReview() ;
    }

    return _lastErr == 0 ;
}


/*******************************************************************

    NAME:       NCPA_DIALOG::FinishBindings

    SYNOPSIS:   Create a new version of the binding information
                text structure attached to the NCPA's node.

    ENTRY:      There must be an active ARRAY_COMP_ASSOC!

    EXIT:       Nothing

    RETURNS:    BOOL FALSE if operation fails (see _lastErr).

    NOTES:

    HISTORY:    DavidHov 2/5/92  Created

********************************************************************/
BOOL NCPA_DIALOG :: FinishBindings ()
{
    AUTO_CURSOR cursAuto ;   //  put up the eternal hourglass

    APIERR err = _bindery.RegenerateAllDependencies( _psvcManager ) ;

#if defined(TRACE)
    if ( err )
    {
        TRACEEOL( SZ("NCPA/MAIN: RegenerateAllDependencies FAILED; error = ")
                  << err ) ;
    }
#endif

    _lastErr = _bindery.StoreCompAssoc() ;

    _bindery.SetBindState( BND_CURRENT ) ;

    return _lastErr == 0 ;
}


/*******************************************************************

    NAME:       NCPA_DIALOG::ContinueEvenIfCfgDirty

    SYNOPSIS:   See if the configuration is "dirty" (in need of a
                reboot). If so, warn the user and allow him to cancel
                the operation.

    ENTRY:      Nothing

    EXIT:       Nothing

    RETURNS:    TRUE if operation should continue; i.e., configuration
                is clean or user doesn't care.

    NOTES:

    HISTORY:    DavidHov 3/5/93  Created

********************************************************************/
BOOL NCPA_DIALOG :: ContinueEvenIfCfgDirty ()
{
    if ( ! _bindery.QueryCfgDirty() )
    {
        return TRUE ;
    }

    INT iResult = ::MsgPopup( this,
                              IDS_NCPA_WARN_CONFIG_DIRTY,
                              MPSEV_WARNING,
                              MP_YESNO,
                              MP_NO );

    return iResult == IDYES ;
}


BOOL NCPA_DIALOG :: CheckBoolSetupParameter ( const TCHAR * pszParameter )
{
    NLS_STR nlsTrue ;
    BOOL fResult = FALSE ;

    if ( FindSetupParameter( _pszInstallParms, pszParameter, & nlsTrue ) )
    {
        fResult = ::stricmpf( SZ("TRUE"), nlsTrue.QueryPch() ) == 0 ;
    }
    return fResult ;
}

// End of NCPDMAIN.CXX