/////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 1996-1999 Microsoft Corporation
//
//  Module Name:
//      NetName.cpp
//
//  Abstract:
//      Implementation of the CNetworkNameParamsPage class.
//
//  Author:
//      David Potter (davidp)   June 28, 1996
//
//  Revision History:
//
//  Notes:
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CluAdmX.h"
#include "ExtObj.h"
#include "NetName.h"
#include "DDxDDv.h"
#include "ExcOper.h"
#include "ClusName.h"
#include "HelpData.h"   // for g_rghelpmap*

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CNetworkNameParamsPage property page
/////////////////////////////////////////////////////////////////////////////

IMPLEMENT_DYNCREATE(CNetworkNameParamsPage, CBasePropertyPage)

/////////////////////////////////////////////////////////////////////////////
// Message Maps

BEGIN_MESSAGE_MAP(CNetworkNameParamsPage, CBasePropertyPage)
    //{{AFX_MSG_MAP(CNetworkNameParamsPage)
    ON_EN_CHANGE(IDC_PP_NETNAME_PARAMS_NAME, OnChangeName)
    ON_BN_CLICKED(IDC_PP_NETNAME_PARAMS_RENAME, OnRename)
    ON_BN_CLICKED(IDC_PP_NETNAME_PARAMS_CHECKBOX_DNS, OnRequireDNS)
    ON_BN_CLICKED(IDC_PP_NETNAME_PARAMS_CHECKBOX_KERBEROS, CBasePropertyPage::OnChangeCtrl)
    //}}AFX_MSG_MAP
    // TODO: Modify the following lines to represent the data displayed on this page.
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::CNetworkNameParamsPage
//
//  Routine Description:
//      Default constructor.
//
//  Arguments:
//      None.
//
//  Return Value:
//      None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CNetworkNameParamsPage::CNetworkNameParamsPage(void)
    : CBasePropertyPage(g_aHelpIDs_IDD_PP_NETNAME_PARAMETERS, g_aHelpIDs_IDD_WIZ_NETNAME_PARAMETERS)
{
    // TODO: Modify the following lines to represent the data displayed on this page.
    //{{AFX_DATA_INIT(CNetworkNameParamsPage)
    m_strName = _T("");
    m_strPrevName = _T("");
    m_nRequireDNS = BST_UNCHECKED;
    m_nRequireKerberos = BST_UNCHECKED;
    m_dwNetBIOSStatus = 0;
    m_dwDNSStatus = 0;
    m_dwKerberosStatus = 0;
    //}}AFX_DATA_INIT

    // Setup the property array.
    {
        m_rgProps[epropName].Set(REGPARAM_NETNAME_NAME, m_strName, m_strPrevName);
        m_rgProps[epropRequireDNS].Set(REGPARAM_NETNAME_REQUIRE_DNS, m_nRequireDNS, m_nPrevRequireDNS);
        m_rgProps[epropRequireKerberos].Set(REGPARAM_NETNAME_REQUIRE_KERBEROS, m_nRequireKerberos, m_nPrevRequireKerberos);
        m_rgProps[epropStatusNetBIOS].Set(REGPARAM_NETNAME_STATUS_NETBIOS, m_dwNetBIOSStatus, m_dwPrevNetBIOSStatus);
        m_rgProps[epropStatusDNS].Set(REGPARAM_NETNAME_STATUS_DNS, m_dwDNSStatus, m_dwPrevDNSStatus);
        m_rgProps[epropStatusKerberos].Set(REGPARAM_NETNAME_STATUS_KERBEROS, m_dwKerberosStatus, m_dwPrevKerberosStatus);
    }  // Setup the property array

    m_dwFlags = 0;

    m_iddPropertyPage = IDD_PP_NETNAME_PARAMETERS;
    m_iddWizardPage = IDD_WIZ_NETNAME_PARAMETERS;

}  //*** CNetworkNameParamsPage::CNetworkNameParamsPage()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::HrInit
//
//  Routine Description:
//      Initialize the page.
//
//  Arguments:
//      peo         [IN OUT] Pointer to the extension object.
//
//  Return Value:
//      S_OK        Page initialized successfully.
//      hr          Page failed to initialize.
//
//--
/////////////////////////////////////////////////////////////////////////////
HRESULT CNetworkNameParamsPage::HrInit(IN OUT CExtObject * peo)
{
    HRESULT     hr;
    CWaitCursor wc;
    DWORD   sc;
    DWORD   cbReturned;

    // Call the base class method.
    // This populates the m_rgProps struct.
    hr = CBasePropertyPage::HrInit(peo);   

    if (!FAILED(hr))
    {
        m_strPrevName = m_strName;
        
        // Read the flags for this resource.
        sc = ClusterResourceControl(
                        Peo()->PrdResData()->m_hresource,
                        NULL,
                        CLUSCTL_RESOURCE_GET_FLAGS,
                        NULL,
                        NULL,
                        &m_dwFlags,
                        sizeof(m_dwFlags),
                        &cbReturned
                        );
        if (sc != ERROR_SUCCESS)
        {
            CNTException nte(sc, NULL, NULL, FALSE /*bAutoDelete*/);
            nte.ReportError();
            nte.Delete();
        }  // if:  error retrieving data
        else
        {
            ASSERT(cbReturned == sizeof(m_dwFlags));
        }  // else:  data retrieved successfully
    }  // if: base class init was successful

    return hr;

}  //*** CNetworkNameParamsPage::HrInit()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::DoDataExchange
//
//  Routine Description:
//      Do data exchange between the dialog and the class.
//
//  Arguments:
//      pDX     [IN OUT] Data exchange object 
//
//  Return Value:
//      None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CNetworkNameParamsPage::DoDataExchange(CDataExchange * pDX)
{
    DWORD       scError;
    BOOL        bError;

    if (!pDX->m_bSaveAndValidate || !BSaved())
    {
        AFX_MANAGE_STATE(AfxGetStaticModuleState());

        CWaitCursor wc;
        CString     strNetName;

        // TODO: Modify the following lines to represent the data displayed on this page.
        //{{AFX_DATA_MAP(CNetworkNameParamsPage)
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_NAME_LABEL, m_staticName);
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_RENAME, m_pbRename);
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_CORE_TEXT, m_staticCore);
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_NAME, m_editName);
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_CHECKBOX_DNS, m_cbRequireDNS);
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_CHECKBOX_KERBEROS, m_cbRequireKerberos);
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_STATUS_NETBIOS, m_editNetBIOSStatus);
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_STATUS_DNS, m_editDNSStatus);
        DDX_Control(pDX, IDC_PP_NETNAME_PARAMS_STATUS_KERBEROS, m_editKerberosStatus);

        //
        // Get the status of the checkboxes.
        //
        DDX_Check(pDX, IDC_PP_NETNAME_PARAMS_CHECKBOX_DNS, m_nRequireDNS);
        DDX_Check(pDX, IDC_PP_NETNAME_PARAMS_CHECKBOX_KERBEROS, m_nRequireKerberos);
        //}}AFX_DATA_MAP

        bError = FALSE;

        if (pDX->m_bSaveAndValidate && !BBackPressed())
        {
            CLRTL_NAME_STATUS cnStatus;
            CString     strMsg;
            UINT        idsError;

            //
            // Get the name from the control into a temp variable
            //
            DDX_Text(pDX, IDC_PP_NETNAME_PARAMS_NAME, strNetName);
            DDV_RequiredText(pDX, IDC_PP_NETNAME_PARAMS_NAME, IDC_PP_NETNAME_PARAMS_NAME_LABEL, strNetName);
            DDV_MaxChars(pDX, strNetName, MAX_CLUSTERNAME_LENGTH);

            if( m_nRequireDNS == BST_UNCHECKED )
            {
                m_nRequireKerberos = BST_UNCHECKED;
            }

            if ( (m_strName != strNetName ) &&
                 (! ClRtlIsNetNameValid(strNetName, &cnStatus, FALSE /*CheckIfExists*/)) )
            {
                switch (cnStatus)
                {
                    case NetNameTooLong:
                        idsError = IDS_INVALID_NETWORK_NAME_TOO_LONG;
                        break;
                    case NetNameInvalidChars:
                        idsError = IDS_INVALID_NETWORK_NAME_INVALID_CHARS;
                        break;
                    case NetNameInUse:
                        idsError = IDS_INVALID_NETWORK_NAME_IN_USE;
                        break;
                    case NetNameDNSNonRFCChars:
                        idsError = IDS_INVALID_NETWORK_NAME_INVALID_DNS_CHARS;
                        break;
                    case NetNameSystemError:
                    {
                        scError = GetLastError();
                        CNTException nte(scError, IDS_ERROR_VALIDATING_NETWORK_NAME, (LPCWSTR) strNetName);
                        nte.ReportError();
                        pDX->Fail();
                    }
                    default:
                        idsError = IDS_INVALID_NETWORK_NAME;
                        break;
                }  // switch:  cnStatus

                strMsg.LoadString(idsError);
                if ( idsError == IDS_INVALID_NETWORK_NAME_INVALID_DNS_CHARS )
                {
                    int id = AfxMessageBox(strMsg, MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION );

                    if ( id == IDNO )
                    {
                        strMsg.Empty();
                        pDX->Fail();
                        bError = TRUE;
                    }
                }
                else
                {
                    AfxMessageBox(strMsg, MB_ICONEXCLAMATION);
                    strMsg.Empty(); // exception prep
                    pDX->Fail();
                    bError = TRUE;
                }
            } // if: ((m_strName != strNetName) && (! ClRtlIsNetNameValid(strNetName, &cnStatus, FALSE)) )
            
            //
            // Everything was validated - apply all of the changes.
            //
            if( FALSE == bError )
            {
                m_strName = strNetName;
            }
            
        }// if:  (pDX->m_bSaveAndValidate && !BBackPressed())
        else  // if: populating controls
        {
            CString m_strStatus;

            //
            // Populate the controls with data from the member variables.
            //
            DDX_Text(pDX, IDC_PP_NETNAME_PARAMS_NAME, m_strName);

            m_strStatus.Format( _T("%d (0x%08x)"), m_dwNetBIOSStatus, m_dwNetBIOSStatus );
            DDX_Text( pDX, IDC_PP_NETNAME_PARAMS_STATUS_NETBIOS, m_strStatus );

            m_strStatus.Format( _T("%d (0x%08x)"), m_dwDNSStatus, m_dwDNSStatus );
            DDX_Text( pDX, IDC_PP_NETNAME_PARAMS_STATUS_DNS, m_strStatus );

            m_strStatus.Format( _T("%d (0x%08x)"), m_dwKerberosStatus, m_dwKerberosStatus );
            DDX_Text( pDX, IDC_PP_NETNAME_PARAMS_STATUS_KERBEROS, m_strStatus );
        }
    }  // if:  not saving or haven't saved yet

    CBasePropertyPage::DoDataExchange(pDX);

}  //*** CNetworkNameParamsPage::DoDataExchange()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::OnInitDialog
//
//  Routine Description:
//      Handler for the WM_INITDIALOG message.
//
//  Arguments:
//      None.
//
//  Return Value:
//      TRUE        We need the focus to be set for us.
//      FALSE       We already set the focus to the proper control.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CNetworkNameParamsPage::OnInitDialog(void)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    CBasePropertyPage::OnInitDialog();

    // Set limits on the edit controls.
    m_editName.SetLimitText(MAX_CLUSTERNAME_LENGTH);

    // Set up the checkboxes.
    m_cbRequireDNS.EnableWindow( TRUE );
    m_cbRequireKerberos.EnableWindow( m_nRequireDNS != 0 );

    // 
    // Make sure we're not dealing with a non-Whistler Cluster.  If we are then
    // disable both checkboxes (the props didn't exist back then - don't set them).
    //
    CheckForDownlevelCluster();
    
    // If this is a core resource, set the name control to be read-only
    // and enable the Core Resource static control.
    if (BCore())
    {
        WINDOWPLACEMENT wpLabel;
        WINDOWPLACEMENT wpName;
        WINDOWPLACEMENT wpButton;
        WINDOWPLACEMENT wpText;
        WINDOWPLACEMENT wpCheckDNS;
        WINDOWPLACEMENT wpCheckKerberos;
        CRect           rectName;
        CRect           rectText;
        RECT *          prect;
        LONG            nHeight;

        // Get the placement of the controls.
        m_editName.GetWindowPlacement(&wpName);
        m_staticCore.GetWindowPlacement(&wpText);
        m_staticName.GetWindowPlacement(&wpLabel);
        m_pbRename.GetWindowPlacement(&wpButton);
        m_cbRequireDNS.GetWindowPlacement(&wpCheckDNS);
        m_cbRequireKerberos.GetWindowPlacement(&wpCheckKerberos);
        
        // Get the positions of the edit control and text control.
        rectName = wpName.rcNormalPosition;
        rectText = wpText.rcNormalPosition;

        // Move the name control to where the text control is.
        prect = &wpName.rcNormalPosition;
        *prect = rectText;
        nHeight = rectName.bottom - rectName.top;
        prect->left = rectName.left;
        prect->right = rectName.right;
        prect->bottom = prect->top + nHeight;
        m_editName.SetWindowPlacement(&wpName);

        // Move the text control to where the name control was.
        prect = &wpText.rcNormalPosition;
        *prect = rectName;
        nHeight = rectText.bottom - rectText.top;
        prect->left = rectText.left;
        prect->right = rectText.right;
        prect->bottom = prect->top + nHeight;
        m_staticCore.SetWindowPlacement(&wpText);

        // Move the name label control to be next to the name edit control.
        prect = &wpLabel.rcNormalPosition;
        nHeight = prect->bottom - prect->top;
        prect->top = wpName.rcNormalPosition.top + 2;
        prect->bottom = prect->top + nHeight;
        m_staticName.SetWindowPlacement(&wpLabel);

        // Move the button control to be next to the name edit control.
        prect = &wpButton.rcNormalPosition;
        nHeight = prect->bottom - prect->top;
        prect->top = wpName.rcNormalPosition.top;
        prect->bottom = prect->top + nHeight;
        m_pbRename.SetWindowPlacement(&wpButton);

        // Move the Require DNS checkbox down.
        prect = &wpCheckDNS.rcNormalPosition;
        nHeight = prect->bottom - prect->top;

        // Move us down by the height of the now displayed static text.
        prect->top = prect->top + (wpText.rcNormalPosition.bottom - wpText.rcNormalPosition.top);
        prect->top = prect->top + rectText.top - rectName.bottom;
        prect->bottom = prect->top + nHeight;
        m_cbRequireDNS.SetWindowPlacement(&wpCheckDNS);
        
        // Move the Require Kerberos checkbox down.
        prect = &wpCheckKerberos.rcNormalPosition;
        nHeight = prect->bottom - prect->top;

        // Move us down by the height of the now displayed static text.
        prect->top = prect->top + (wpText.rcNormalPosition.bottom - wpText.rcNormalPosition.top);
        prect->top = prect->top + rectText.top - rectName.bottom;
        prect->bottom = prect->top + nHeight;
        m_cbRequireKerberos.SetWindowPlacement(&wpCheckKerberos);

        // Prevent the name edit control from being editable and
        // Show the text and the button.
        m_editName.SetReadOnly(TRUE);
        m_staticCore.ShowWindow(SW_SHOW);
        m_pbRename.ShowWindow(SW_SHOW);
        m_pbRename.EnableWindow( TRUE );       
    }
    else // if: core resource (show static text & move other controls down)
    {
        m_editName.SetReadOnly(FALSE);
        m_staticCore.ShowWindow(SW_HIDE);
        m_pbRename.ShowWindow(SW_HIDE);
        m_pbRename.EnableWindow( FALSE );
    }  // else:  not core resource

    return TRUE;    // return TRUE unless you set the focus to a control
                    // EXCEPTION: OCX Property Pages should return FALSE

}  //*** CNetworkNameParamsPage::OnInitDialog()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::OnSetActive
//
//  Routine Description:
//      Handler for the PSN_SETACTIVE message.
//
//  Arguments:
//      None.
//
//  Return Value:
//      TRUE    Page successfully initialized.
//      FALSE   Page not initialized.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CNetworkNameParamsPage::OnSetActive(void)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    // Enable/disable the Next/Finish button.
    if (BWizard())
    {
        if (m_strName.GetLength() == 0)
            EnableNext(FALSE);
        else
            EnableNext(TRUE);
    }  // if:  enable/disable the Next button

    return CBasePropertyPage::OnSetActive();

}  //*** CNetworkNameParamsPage::OnSetActive()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::BApplyChanges
//
//  Routine Description:
//      Apply changes made on the page.
//
//  Arguments:
//      None.
//
//  Return Value:
//      TRUE    Page successfully applied.
//      FALSE   Error applying page.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CNetworkNameParamsPage::BApplyChanges(void)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    CWaitCursor wc;
    BOOL        bSuccess = TRUE;

    // Save data.
    if (BCore())
    {
        DWORD       scStatus;

        //
        // If this is the core Network Name (Cluster Name) we should set the name via
        // the SetClusterName API. If that succeeds then we'll set the other properties.
        //
        if ( m_strName != m_strPrevName )
        {
            scStatus = SetClusterName(Hcluster(), m_strName);
            if (scStatus != ERROR_SUCCESS)
            {
                if (scStatus == ERROR_RESOURCE_PROPERTIES_STORED)
                {
                    TCHAR           szError[1024];
                    CNTException    nte(scStatus, NULL, m_strName, NULL, FALSE /*bAutoDelete*/);
                    nte.FormatErrorMessage(szError, sizeof(szError) / sizeof(TCHAR), NULL, FALSE /*bIncludeID*/);
                    nte.Delete();
                    AfxMessageBox(szError);
                }  // if:  properties stored
                else
                {
                    CNTException    nte(scStatus, IDS_ERROR_SETTING_CLUSTER_NAME, m_strName, NULL, FALSE /*bAutoDelete*/);
                    nte.ReportError();
                    nte.Delete();
                    bSuccess = FALSE;
                }  // else:  other error occurred
            }  // if:  error setting the cluster name
            else
            {
                //
                // By setting the prev value equal to the current value the BSetPrivateProps
                // function will skip this prop when constructing it's list of props to set.
                //
                m_strPrevName = m_strName;
            }
        } // if: name has changed

        //
        // Now set the other private properties.
        //
        if ( bSuccess == TRUE ) 
        {
            bSuccess = BSetPrivateProps();
        }
    }  // if:  core resource
    else
    {   
        bSuccess = BSetPrivateProps();
    }

    //
    // If we applied the changes then clear the require kerberos check if
    // the checkbox was disabled.  Don't make this dependent upon the require
    // DNS checkbox state as the dependency may change in the future.
    //
    if( ( bSuccess == TRUE ) &&
        ( m_cbRequireKerberos.IsWindowEnabled() == FALSE ) )
    {
        m_cbRequireKerberos.SetCheck( BST_UNCHECKED );
    }

    return bSuccess;

}  //*** CNetworkNameParamsPage::BApplyChanges()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::OnChangeName
//
//  Routine Description:
//      Handler for the EN_CHANGE message on the Name edit control.
//
//  Arguments:
//      None.
//
//  Return Value:
//      None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CNetworkNameParamsPage::OnChangeName(void)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    OnChangeCtrl();

    if (BWizard())
    {
        if (m_editName.GetWindowTextLength() == 0)
        {
            EnableNext(FALSE);
        }
        else
        {
            EnableNext(TRUE);
        }
    }  // if:  in a wizard

}  //*** CNetworkNameParamsPage::OnChangeName()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::OnRename
//
//  Routine Description:
//      Handler for the BN_CLICKED message on the Rename push button.
//
//  Arguments:
//      None.
//
//  Return Value:
//      None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CNetworkNameParamsPage::OnRename(void)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    CChangeClusterNameDlg   dlg(this);

    ASSERT(BCore());

    dlg.m_strClusName = m_strName;
    if (dlg.DoModal() == IDOK)
    {
        if (m_strName != dlg.m_strClusName)
        {
            OnChangeCtrl();
            m_strName = dlg.m_strClusName;
            UpdateData(FALSE /*bSaveAndValidate*/);
        }  // if:  the name changed
    }  // if:  user accepted change

}  //*** CNetworkNameParamsPage::OnRename()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::OnRequireDNS
//
//  Routine Description:
//      Handler for the BN_CLICKED message on the RequireDNS checkbox.
//
//  Arguments:
//      None.
//
//  Return Value:
//      None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CNetworkNameParamsPage::OnRequireDNS(void)
{
    int nChecked;
    
    nChecked = m_cbRequireDNS.GetCheck();

    m_cbRequireKerberos.EnableWindow( nChecked == BST_CHECKED );

    SetModified( TRUE );
}  //*** CNetworkNameParamsPage::OnRequireDNS()

/////////////////////////////////////////////////////////////////////////////
//++
//
//  CNetworkNameParamsPage::CheckForDownlevelCluster
//
//  Routine Description:
//      If determine whether the cluster we're connected to is pre-Whistler.
//      If it is then disable the buttons.  If an error occurs display a
//      message box.
//
//  Arguments:
//      None.
//
//  Return Value:
//      None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CNetworkNameParamsPage::CheckForDownlevelCluster(void)
{
    CLUSTERVERSIONINFO cvi;
    DWORD sc;
    DWORD scErr;
    DWORD cchName;

    //
    // Determine whether we're talking to a pre-Whistler cluster.
    // If so, disable the Require DNS & Kerberos checkboxes.
    //
    memset( &cvi, 0, sizeof( cvi ) );

    cvi.dwVersionInfoSize = sizeof( cvi );

    cchName = 0;
    sc = GetClusterInformation( Hcluster(), NULL, &cchName, &cvi );
    scErr = GetLastError();

    if( ERROR_SUCCESS != sc )
    {
        //
        // API failed.  Pop up a message box.
        //
        TCHAR           szError[1024];
        CNTException    nte(scErr, IDS_ERROR_GETTING_CLUSTER_INFORMATION, m_strName, NULL, FALSE /*bAutoDelete*/);
        nte.FormatErrorMessage(szError, sizeof(szError) / sizeof(TCHAR), NULL, FALSE /*bIncludeID*/);
        nte.ReportError();
        nte.Delete();

        //
        // We can't be sure that we're on a down-level cluster (chances are that we're not),
        // so leave the checkboxes enabled - the worst that will happen is that some extra props 
        // will be added that are ignored by the resource.
        //
    }
    else
    {
        if( CLUSTER_GET_MAJOR_VERSION( cvi.dwClusterHighestVersion ) < NT51_MAJOR_VERSION )
        {
            //
            // We're on a pre-Whistler Cluster where the DNS & Kerberos setting make no
            // sense.  So, disable the checkboxes to indicate that the settings
            // are unavailable.
            //
            m_cbRequireKerberos.EnableWindow( FALSE );
            m_cbRequireDNS.EnableWindow( FALSE );
        }
    }

}  //*** CNetworkNameParamsPage::CheckForDownlevelCluster()