//*************************************************************************** // // CONNECT.CPP // // Module: NLB Manager // // Purpose: Implements ConnectDialog, which is a dialog for connecting // to a host, extracting and displaying its list of adapters. // // Copyright (c)2001 Microsoft Corporation, All Rights Reserved // // History: // // 07/30/01 JosephJ Created // //*************************************************************************** #include "precomp.h" #pragma hdrstop #include "private.h" #include "connect.h" #include "connect.tmh" // BEGIN_MESSAGE_MAP( ConnectDialog, CDialog ) BEGIN_MESSAGE_MAP( ConnectDialog, CPropertyPage ) ON_BN_CLICKED(IDC_BUTTON_CONNECT, OnButtonConnect) ON_WM_HELPINFO() ON_WM_CONTEXTMENU() ON_NOTIFY( LVN_ITEMCHANGED, IDC_LIST_INTERFACES, OnSelchanged ) ON_EN_UPDATE(IDC_EDIT_HOSTADDRESS,OnUpdateEditHostAddress) // // Other options... // // ON_EN_SETFOCUS(IDC_EDIT_HOSTADDRESS,OnSetFocusEditHostAddress) // ON_WM_ACTIVATE() // ON_NOTIFY( NM_DBLCLK, IDC_LIST_INTERFACES, OnDoubleClick ) // ON_NOTIFY( LVN_COLUMNCLICK, IDC_LIST_INTERFACES, OnColumnClick ) // END_MESSAGE_MAP() // // Static help-id maps // DWORD ConnectDialog::s_HelpIDs[] = { IDC_TEXT_HOSTADDRESS, IDC_EDIT_HOSTADDRESS, IDC_EDIT_HOSTADDRESS, IDC_EDIT_HOSTADDRESS, IDC_BUTTON_CONNECT, IDC_BUTTON_CONNECT, IDC_GROUP_CONNECTION_STATUS, IDC_GROUP_CONNECTION_STATUS, IDC_TEXT_CONNECTION_STATUS, IDC_TEXT_CONNECTION_STATUS, IDC_TEXT_INTERFACES, IDC_LIST_INTERFACES, IDC_LIST_INTERFACES, IDC_LIST_INTERFACES, 0, 0 }; DWORD ConnectDialog::s_ExistingClusterHelpIDs[] = { IDC_TEXT_HOSTADDRESS, IDC_EDIT_HOSTADDRESSEX, IDC_EDIT_HOSTADDRESS, IDC_EDIT_HOSTADDRESSEX, IDC_BUTTON_CONNECT, IDC_BUTTON_CONNECTEX, IDC_GROUP_CONNECTION_STATUS, IDC_GROUP_CONNECTION_STATUS, IDC_TEXT_CONNECTION_STATUS, IDC_TEXT_CONNECTION_STATUS, IDC_TEXT_INTERFACES, IDC_LIST_INTERFACESEX, IDC_LIST_INTERFACES, IDC_LIST_INTERFACESEX, 0, 0 }; VOID zap_slash(LPWSTR sz) // Look for a the first '/' and set it to zero. { sz = wcschr(sz, '/'); if (sz!=NULL) *sz=0; } ConnectDialog::ConnectDialog( CPropertySheet *psh, Document *pDocument, NLB_EXTENDED_CLUSTER_CONFIGURATION *pNlbCfg, ENGINEHANDLE *pehInterface, // IN OUT DlgType type, CWnd* parent ) : // CDialog( IDD, parent ) CPropertyPage(IDD), m_type(type), m_fOK(FALSE), m_pshOwner(psh), m_pDocument(pDocument), m_fInterfaceSelected(FALSE), m_iInterfaceListItem(0), m_pehSelectedInterfaceId(pehInterface), m_fSelectedInterfaceIsInCluster(FALSE), m_pNlbCfg(pNlbCfg), m_ehHostId(NULL) { *m_pehSelectedInterfaceId = NULL; } void ConnectDialog::DoDataExchange( CDataExchange* pDX ) { // CDialog::DoDataExchange(pDX); CPropertyPage::DoDataExchange(pDX); DDX_Control(pDX, IDC_LIST_INTERFACES, interfaceList); DDX_Control(pDX, IDC_TEXT_CONNECTION_STATUS, connectionStatus); DDX_Control(pDX, IDC_TEXT_INTERFACES, listHeading); DDX_Control(pDX, IDC_EDIT_HOSTADDRESS, hostAddress); // // Note: the buttons are handled by the ON_BN_CLICKED macro // above. // // DDX_Control(pDX, IDC_BUTTON_CONNECT, buttonConnect); // DDX_Control(pDX, IDC_BUTTON_CREDENTIALS, credentialsButton); } BOOL ConnectDialog::OnInitDialog() { // BOOL fRet = CDialog::OnInitDialog(); BOOL fRet = CPropertyPage::OnInitDialog(); _bstr_t bstrDescription; _bstr_t bstrListText; m_fOK = FALSE; switch(m_type) { case DLGTYPE_NEW_CLUSTER: bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_NEW_HINT); bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_NEW_LIST_TXT); break; case DLGTYPE_EXISTING_CLUSTER: bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_EXISTING_HINT); bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_EXISTING_LIST_TXT); break; case DLGTYPE_ADD_HOST: bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_ADD_HOST_HINT); bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_ADD_HOST_LIST_TXT); break; } // // Initialize the caption and discription based on the type of // dialog. // { CWnd *pItem = GetDlgItem(IDC_TEXT_CONNECT_DESCRIPTION); pItem->SetWindowText(bstrDescription); pItem = GetDlgItem(IDC_TEXT_INTERFACES); pItem->SetWindowText(bstrListText); } // Initialize the list control mfn_InitializeListView(); // interfaceList.SetCurSel( 0 ); // ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_HOSTADDRESS), TRUE ); // ::EnableWindow(::GetDlgItem(m_hWnd, IDC_LIST_INTERFACES), TRUE ); // // The "Connect" button starts out disabled. It is only enabled // when the uers types non-whitespace text in the host address // edit control. // ::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, FALSE); return fRet; } BOOL ConnectDialog::OnHelpInfo (HELPINFO* helpInfo ) { if( helpInfo->iContextType == HELPINFO_WINDOW ) { // // We choose the context-senstive map appropriate to the // type of dialog (m_type). // ULONG_PTR pHelpIds = (ULONG_PTR) s_HelpIDs; BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER); if (fExisting) { pHelpIds = (ULONG_PTR) s_ExistingClusterHelpIDs; } ::WinHelp( static_cast ( helpInfo->hItemHandle ), CVY_CTXT_HELP_FILE, HELP_WM_HELP, (ULONG_PTR ) pHelpIds); } return TRUE; } void ConnectDialog::OnContextMenu( CWnd* pWnd, CPoint point ) { ::WinHelp( m_hWnd, CVY_CTXT_HELP_FILE, HELP_CONTEXTMENU, (ULONG_PTR ) s_HelpIDs); } void ConnectDialog::mfn_InitializeListView(void) // // Set the columns on the list box based on the type of dialog // { BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER); RECT rect; INT colWidth; interfaceList.GetClientRect(&rect); colWidth = (rect.right - rect.left)/4; if (fExisting) { // // The interface list is that of interfaces already bound to NLB. // we display the cluster dnsname and ip first, then adapter name. // interfaceList.InsertColumn( 0, GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERNAME), LVCFMT_LEFT, colWidth); interfaceList.InsertColumn( 1, GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERIP), LVCFMT_LEFT, colWidth); interfaceList.InsertColumn( 2, GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFNAME), LVCFMT_LEFT, colWidth * 2); } else { // // The interface list is that of interfaces NOT bound to NLB. // We display the current IP address first, then adapter name. // interfaceList.InsertColumn( 0, GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFNAME), LVCFMT_LEFT, colWidth * 2); interfaceList.InsertColumn( 1, GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFIP), LVCFMT_LEFT, colWidth); interfaceList.InsertColumn( 2, GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERIP), LVCFMT_LEFT, colWidth); } // // Allow entire row to be selected. // interfaceList.SetExtendedStyle( interfaceList.GetExtendedStyle() | LVS_EX_FULLROWSELECT ); } void ConnectDialog::mfn_InsertBoundInterface( ENGINEHANDLE ehInterfaceId, LPCWSTR szClusterName, LPCWSTR szClusterIp, LPCWSTR szInterfaceName ) { if (szClusterName == NULL) { szClusterName = L""; } if (szClusterIp == NULL) { szClusterIp = L""; } if (szInterfaceName == NULL) { szInterfaceName = L""; // TODO: localize } int iRet = interfaceList.InsertItem( LVIF_TEXT | LVIF_PARAM, // nMask 0, // nItem, szClusterName, // lpszItem 0, // nState (unused) 0, // nStateMask (unused) 0, // nImage (unused) (LPARAM) ehInterfaceId // lParam ); // interfaceList.InsertItem(0, szClusterName); interfaceList.SetItem( 0, // nItem 1,// nSubItem LVIF_TEXT, // nMask szClusterIp, // lpszItem 0, // nImage 0, // nState 0, // nStateMask 0 // lParam ); interfaceList.SetItem( 0, // nItem 2,// nSubItem LVIF_TEXT, // nMask szInterfaceName, // lpszItem 0, // nImage 0, // nState 0, // nStateMask 0 // lParam ); } void ConnectDialog::mfn_InsertInterface( ENGINEHANDLE ehInterfaceId, LPCWSTR szInterfaceIp, LPCWSTR szInterfaceName, LPCWSTR szClusterIp ) { if (szInterfaceIp == NULL) { szInterfaceIp = L""; } if (szInterfaceName == NULL) { szInterfaceName = L""; // TODO: localize } if (szClusterIp == NULL) { szClusterIp = L""; } int iRet = interfaceList.InsertItem( LVIF_TEXT | LVIF_PARAM, // nMask 0, // nItem, szInterfaceName, // lpszItem 0, // nState (unused) 0, // nStateMask (unused) 0, // nImage (unused) (LPARAM) ehInterfaceId // lParam ); // interfaceList.InsertItem(0, szInterfaceIp); interfaceList.SetItem( 0, // nItem 1,// nSubItem LVIF_TEXT, // nMask szInterfaceIp, // lpszItem 0, // nImage 0, // nState 0, // nStateMask 0 // lParam ); // interfaceList.InsertItem(0, szInterfaceIp); interfaceList.SetItem( 0, // nItem 2,// nSubItem LVIF_TEXT, // nMask szClusterIp, // lpszItem 0, // nImage 0, // nState 0, // nStateMask 0 // lParam ); // interfaceList.SetCurSel( 0 ); } void ConnectDialog::OnOK() { // CDialog::OnOK(); CPropertyPage::OnOK(); } _bstr_t g_hostName; void ConnectDialog::OnButtonConnect() /* User has clicked the "Connect" button. 1. (For now) If empty string, do nothing. Later we'll disable/enable. 2. Switch cursor to hourglass, connect, switch back from hourglass. */ { BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER); BOOL fRet; #define MAX_HOST_ADDRESS_LENGTH 256 WCHAR szHostAddress[MAX_HOST_ADDRESS_LENGTH+1]; ENGINEHANDLE ehHostId; CHostSpec hSpec; BOOL fNicsAvailable = FALSE; NLBERROR err; _bstr_t bstrUserName; _bstr_t bstrPassword; _bstr_t bstrConnectionStatus; // // Get the connection string. If empty, we simply return. // { fRet = GetDlgItemText( IDC_EDIT_HOSTADDRESS, szHostAddress, MAX_HOST_ADDRESS_LENGTH ); if (!fRet) { goto end; } // // Clean out trailing whitespace.. // { LPWSTR sz = (szHostAddress+wcslen(szHostAddress))-1; while (sz >= szHostAddress) { WCHAR c = *sz; if (c == ' ' || c == '\t') { *sz = 0; } else { break; } sz--; } } if (szHostAddress[0] == 0) { goto end; } } // // Let's see if we have any record of this connection string -- if so // we use that record's username and password as the first guest. // err = gEngine.LookupConnectionInfo( szHostAddress, REF bstrUserName, REF bstrPassword ); if (NLBFAILED(err)) { // // Nope -- let's use default credentials... // m_pDocument->getDefaultCredentials(REF bstrUserName, REF bstrPassword); } // // Set status // { bstrConnectionStatus = GETRESOURCEIDSTRING(IDS_CONNECT_STATUS_CONNECTING); SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, (LPCWSTR) bstrConnectionStatus); } // // Clear the list of interfaces. // interfaceList.DeleteAllItems(); // // These two buffers must be defined outside the loop below because // ConnInfo points to them across multiple iterations. // We initialize them to the user-name and password we obtained above... // WCHAR rgUserName[CREDUI_MAX_USERNAME_LENGTH+1]; WCHAR rgPassword[MAX_ENCRYPTED_PASSWORD_LENGTH]; LPCWSTR szName = (LPCWSTR) bstrUserName; LPCWSTR szPassword = (LPCWSTR) bstrPassword; if (szName == NULL) { szName = L""; } if (szPassword == NULL) { szPassword = L""; } ARRAYSTRCPY(rgUserName, szName); ARRAYSTRCPY(rgPassword, szPassword); while (1) { WMI_CONNECTION_INFO ConnInfo; CLocalLogger logger; ZeroMemory(&ConnInfo, sizeof(ConnInfo)); ConnInfo.szMachine = szHostAddress; if (*rgUserName == 0) { // Use default creds ... ConnInfo.szUserName = NULL; ConnInfo.szPassword = NULL; } else { ConnInfo.szUserName = rgUserName; ConnInfo.szPassword = rgPassword; } // // ACTUALLY CONNECT TO THE HOST // BeginWaitCursor(); // TRUE 2nd param says overwrite the connection info for this host // if the connect succeeds. err = gEngine.ConnectToHost(&ConnInfo, TRUE, REF ehHostId, REF bstrConnectionStatus); EndWaitCursor(); if (err != NLBERR_ACCESS_DENIED) { break; } // // We got an access-denied -- // Bring ui UI prompting for new username and password. // _bstr_t bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_CONNECT); logger.Log(IDS_SPECIFY_MACHINE_CREDS, ConnInfo.szMachine); fRet = PromptForEncryptedCreds( m_hWnd, (LPCWSTR) bstrCaption, logger.GetStringSafe(), rgUserName, ASIZE(rgUserName), rgPassword, ASIZE(rgPassword) ); if (!fRet) { err = NLBERR_CANCELLED; break; } } // while (1) if (err == NLBERR_OK) { // // Set status // bstrConnectionStatus = GETRESOURCEIDSTRING(IDS_CONNECT_STATUS_CONNECTED); SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, (LPCWSTR) bstrConnectionStatus); // // Clear list of all items // interfaceList.DeleteAllItems(); err = gEngine.GetHostSpec(ehHostId, REF hSpec); if (NLBFAILED(err)) { goto end; } // // Extract list of interfaces // for( int i = 0; i < hSpec.m_ehInterfaceIdList.size(); ++i ) { ENGINEHANDLE ehIID = hSpec.m_ehInterfaceIdList[i]; CInterfaceSpec iSpec; err = gEngine.GetInterfaceSpec(ehIID, REF iSpec); if (err == NLBERR_OK) { // // Get interfaces. // // szFriendlyName // szClusterIp (NULL if nlb not bound) // szClusterName (NULL if nlb not bound) // szFirstIp (first ip bound to NLB) // WBEMSTATUS wStat; LPWSTR szFriendlyName = NULL; LPWSTR szClusterIp = NULL; LPWSTR szClusterName = NULL; LPWSTR *pszNetworkAddresses = NULL; BOOL fNlbBound = FALSE; UINT NumAddresses=0; LPWSTR szFirstNetworkAddress = NULL; wStat = iSpec.m_NlbCfg.GetFriendlyName(&szFriendlyName); if (FAILED(wStat)) szFriendlyName = NULL; wStat = iSpec.m_NlbCfg.GetNetworkAddresses( &pszNetworkAddresses, &NumAddresses ); if (FAILED(wStat)) { pszNetworkAddresses = NULL; NumAddresses = 0; } else if (NumAddresses != 0) { szFirstNetworkAddress = pszNetworkAddresses[0]; zap_slash(szFirstNetworkAddress); // zap the / } if (iSpec.m_NlbCfg.IsNlbBound()) { fNlbBound = TRUE; if (iSpec.m_NlbCfg.IsValidNlbConfig()) { wStat = iSpec.m_NlbCfg.GetClusterNetworkAddress( &szClusterIp ); if (FAILED(wStat)) { szClusterIp = NULL; } else if (szClusterIp!=NULL) { zap_slash(szClusterIp); } wStat = iSpec.m_NlbCfg.GetClusterName( &szClusterName ); if (FAILED(wStat)) { szClusterName = NULL; } } } if (fExisting && fNlbBound) { fNicsAvailable = TRUE; mfn_InsertBoundInterface( ehIID, szClusterName, szClusterIp, szFriendlyName ); } else if (!fExisting) { fNicsAvailable = TRUE; mfn_InsertInterface( ehIID, szFirstNetworkAddress, szFriendlyName, szClusterIp ); } delete szFriendlyName; delete szClusterIp; delete szClusterName; delete pszNetworkAddresses; } } if (!fNicsAvailable) { // // There are no NICs on this host on which NLB may be installed. // if (fExisting) { MessageBox( GETRESOURCEIDSTRING( IDS_CONNECT_NO_NICS_EXISTING_CLUSTER), GETRESOURCEIDSTRING( IDS_CONNECT_SELECT_NICS_ERROR ), MB_ICONSTOP | MB_OK ); } else { MessageBox( GETRESOURCEIDSTRING( IDS_CONNECT_NO_NICS_NEW_CLUSTER ), GETRESOURCEIDSTRING( IDS_CONNECT_SELECT_NICS_ERROR ), MB_ICONSTOP | MB_OK ); } } else { m_ehHostId = ehHostId; m_MachineName = hSpec.m_MachineName; // machine name. m_fInterfaceSelected = FALSE; m_iInterfaceListItem = 0; *m_pehSelectedInterfaceId = NULL; m_fSelectedInterfaceIsInCluster = FALSE; if (fExisting) { // // We're asked to pick an existing cluster. // Let's select the first interface bound to NLB // mfn_SelectInterfaceIfAlreadyInCluster( NULL ); } else { // // We're asked to add a host to a cluster. // // Now we check if an interfaces is already part of // the cluster. If so we select it and prevent the user from // subsequently changing this selection. Furthermore, we use // the host-specific settings that already exist on that // interface. // mfn_SelectInterfaceIfAlreadyInCluster( m_pNlbCfg->NlbParams.cl_ip_addr ); // // Let's apply the selected interface's information. // mfn_ApplySelectedInterfaceConfiguration(); } } } else { // // Error connecting. // LPCWSTR szErr = (LPCWSTR)bstrConnectionStatus; if (szErr == NULL) { szErr = L""; } SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, szErr); } end: return; } void ConnectDialog::OnSelchanged(NMHDR * pNotifyStruct, LRESULT * result ) /* A listbox item has been selected. */ { POSITION pos = interfaceList.GetFirstSelectedItemPosition(); UINT WizardFlags = 0; int index = -1; if( pos != NULL ) { index = interfaceList.GetNextSelectedItem( pos ); } if (m_type == DLGTYPE_NEW_CLUSTER) { // // We're not the first, so we enable the back button. // WizardFlags = PSWIZB_BACK; } if (m_fInterfaceSelected && index == m_iInterfaceListItem) { // // No change in selection; Nothing to do.. // In fact we do NOT want to change the settings because the user // may have made some host-specific changes like change the // dedicated IP. // goto end; } if (m_fSelectedInterfaceIsInCluster) { BOOL fRet = FALSE; // // we don't allow a change in selection -- move back to // selecting the cluster ip. fRet = interfaceList.SetItemState( m_iInterfaceListItem, LVIS_FOCUSED | LVIS_SELECTED, // nState LVIS_FOCUSED | LVIS_SELECTED // nMask ); if (fRet) { goto end; } } // // We are getting here ONLY if (a) there has been a change in the selection // and (b) the selected interface is NOT already in the cluster. // We'll set the dedicated ip and subnet mask to be the first // address/subnet bound to the adapter. // // If adapter is configured for DHCP, we leave the dedicated IP field // blank. // if (index != -1) { // // Update m_pNlbCfg appropriately... // ENGINEHANDLE ehIID = NULL; ehIID = (ENGINEHANDLE) interfaceList.GetItemData(index); if (ehIID == NULL) { TRACE_CRIT("%!FUNC! could not get ehIID for index %lu", index); goto end; } else { // // Update the saved-away "selected interface" ID. // ENGINEHANDLE ehOldId = *m_pehSelectedInterfaceId; *m_pehSelectedInterfaceId = ehIID; m_fInterfaceSelected = TRUE; m_iInterfaceListItem = index; // // TODO: duplicate code // CInterfaceSpec iSpec; WBEMSTATUS wStat; LPWSTR szFriendlyName = NULL; LPWSTR szClusterIp = NULL; LPWSTR szClusterName = NULL; LPWSTR *pszNetworkAddresses = NULL; UINT NumAddresses=0; LPWSTR szFirstNetworkAddress = NULL; NLBERROR err; err = gEngine.GetInterfaceSpec(ehIID, REF iSpec); if (!NLBOK(err)) { TRACE_CRIT("%!FUNC! could not get iSpec for ehSpec 0x%lx", ehIID); goto end; } wStat = iSpec.m_NlbCfg.GetFriendlyName(&szFriendlyName); if (FAILED(wStat)) szFriendlyName = NULL; wStat = iSpec.m_NlbCfg.GetNetworkAddresses( &pszNetworkAddresses, &NumAddresses ); if (FAILED(wStat)) { pszNetworkAddresses = NULL; NumAddresses = 0; } else if (NumAddresses != 0) { szFirstNetworkAddress = pszNetworkAddresses[0]; } m_pNlbCfg->SetFriendlyName(szFriendlyName); if (iSpec.m_NlbCfg.IsNlbBound()) { if (m_type != DLGTYPE_EXISTING_CLUSTER) { // // The user has selected an interface that is bound with // some other IP address -- we should put up a message box // here or maybe later, on kill-active. // } } // // Set defaults for dedicatedip -- the first network address on // the NIC, but ONLY if this address is not a cluster IP address. // if (szFirstNetworkAddress != NULL) { LPCWSTR szAddress = szFirstNetworkAddress; WCHAR rgIp[WLBS_MAX_CL_IP_ADDR+1]; LPCWSTR pSlash = wcsrchr(szAddress, (int) '/'); if (pSlash != NULL) { UINT len = (UINT) (pSlash - szAddress); if (len < WLBS_MAX_CL_IP_ADDR) { CopyMemory(rgIp, szAddress, len*sizeof(WCHAR)); rgIp[len] = 0; szAddress = rgIp; } } if (!_wcsicmp(m_pNlbCfg->NlbParams.cl_ip_addr, szAddress)) { szFirstNetworkAddress = NULL; } if (iSpec.m_NlbCfg.fDHCP) { // // The adapter is currently under DHCP control. We don't // want to suggest that we use the current IP address // as the static DIP! // szFirstNetworkAddress = NULL; } // // TODO -- check also if this address conflicts with the // additional VIPS. // } m_pNlbCfg->SetDedicatedNetworkAddress(szFirstNetworkAddress); // NULL ok delete szFriendlyName; delete szClusterIp; delete szClusterName; delete pszNetworkAddresses; } if (m_type == DLGTYPE_EXISTING_CLUSTER) { // we're last page, so enable finish. WizardFlags |= PSWIZB_FINISH; } else { // we're not the last page, so enable next. WizardFlags |= PSWIZB_NEXT; } } m_pshOwner->SetWizardButtons(WizardFlags); end: return; } BOOL ConnectDialog::OnSetActive() { BOOL fRet = CPropertyPage::OnSetActive(); if (fRet) { UINT WizardFlags = 0; if (m_type == DLGTYPE_NEW_CLUSTER) { WizardFlags |= PSWIZB_BACK; // we're not the first page. } if (m_fInterfaceSelected) { WizardFlags |= PSWIZB_NEXT; // Ok to continue. } m_pshOwner->SetWizardButtons(WizardFlags); } return fRet; } LRESULT ConnectDialog::OnWizardNext() { LRESULT lRet = 0; TRACE_INFO("%!FUNC! ->"); lRet = CPropertyPage::OnWizardNext(); if (lRet != 0) { goto end; } if (mfn_ValidateData()) { lRet = 0; } else { lRet = -1; // validation failed -- stay in current page. } end: TRACE_INFO("%!FUNC! <- returns %lu", lRet); return lRet; } void ConnectDialog::OnUpdateEditHostAddress() { // // This gets called when the user has made changes to the connect-to-host // edit control. // // // We get the latest text -- if null or just blanks, we // disable the connect window. // Else we enable the connect window. // #define BUF_SIZ 32 WCHAR rgBuf[BUF_SIZ+1]; int l = hostAddress.GetWindowText(rgBuf, BUF_SIZ); if (l == 0 || _wcsspnp(rgBuf, L" \t")==NULL) { // // Empty string or entirely whitespace. // ::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, FALSE); } else { // // Non-empty string -- enable button and make it the default. // ::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, TRUE); this->SetDefID(IDC_BUTTON_CONNECT); } } void ConnectDialog::mfn_SelectInterfaceIfAlreadyInCluster(LPCWSTR szClusterIp) /* Check the list of interfaces to see if there exists an interface which is is already part of the cluster -- i.e., it is bound and it's cluster ip matches the one in m_pNlbCfg. If so, we select it, and furthermore, prevent the user from selecting any other interface. */ { ENGINEHANDLE ehInterfaceId = NULL; NLBERROR nerr; UINT NumFound = 0; nerr = gEngine.FindInterfaceOnHostByClusterIp( m_ehHostId, //m_pNlbCfg->NlbParams.cl_ip_addr, szClusterIp, REF ehInterfaceId, REF NumFound ); if (!NLBOK(nerr)) { // not found or bad host id or some other err -- we don't care which. goto end; } // // Find the list item with this ehInterfaceId. // { LVFINDINFO Info; int nItem; ZeroMemory(&Info, sizeof(Info)); Info.flags = LVFI_PARAM; Info.lParam = ehInterfaceId; nItem = interfaceList.FindItem(&Info); if (nItem != -1) { BOOL fRet; UINT WizardFlags = 0; // // Found it! -- select it and use it's host-specific information // m_fInterfaceSelected = TRUE; m_iInterfaceListItem = nItem; *m_pehSelectedInterfaceId = ehInterfaceId; if (NumFound == 1) { m_fSelectedInterfaceIsInCluster = TRUE; } fRet = interfaceList.SetItemState( nItem, LVIS_FOCUSED | LVIS_SELECTED, // nState LVIS_FOCUSED | LVIS_SELECTED // nMask ); if (m_type == DLGTYPE_NEW_CLUSTER) { WizardFlags |= PSWIZB_BACK; // we're not the first page. } if (m_type == DLGTYPE_EXISTING_CLUSTER) { WizardFlags |= PSWIZB_FINISH; } else { WizardFlags |= PSWIZB_NEXT; } // TODO: consider adding finish in add-host case here. m_pshOwner->SetWizardButtons(WizardFlags); } } // // Go through and set all other list items to have a gray background. // end: return; } void ConnectDialog::mfn_ApplySelectedInterfaceConfiguration(void) { ENGINEHANDLE ehIID = *m_pehSelectedInterfaceId; CInterfaceSpec iSpec; WBEMSTATUS wStat; BOOL fNlbBound = FALSE; NLBERROR err; NLB_EXTENDED_CLUSTER_CONFIGURATION TmpConfig; if (!m_fSelectedInterfaceIsInCluster) goto end; err = gEngine.GetInterfaceSpec(ehIID, REF iSpec); if (!NLBOK(err)) { TRACE_CRIT("%!FUNC! could not get iSpec for ehSpec 0x%lx", ehIID); goto end; } if (!iSpec.m_NlbCfg.IsValidNlbConfig()) { // can't trust NLB config info on this interface. goto end; } // // We'll make a copy of the interface's config and apply the cluster // properties to it and then copy this copy over to the cluster properties. // wStat = TmpConfig.Update(&iSpec.m_NlbCfg); if (FAILED(wStat)) { TRACE_CRIT("%!FUNC! could not perform an internal copy!"); goto end; } err = gEngine.ApplyClusterWideConfiguration(REF *m_pNlbCfg, TmpConfig); if (!NLBOK(err)) { goto end; } wStat = m_pNlbCfg->Update(&TmpConfig); if (FAILED(wStat)) { goto end; } // Fall through. end: return; } BOOL ConnectDialog::mfn_ValidateData() /* Make sure the interface is not already part of a different cluster, or other problem (eg we're connnecting to this interface and it's DHCP) NewCluster: ExistingCluster: AddHost: In all cases, we fail if pISpec already has an ehCluster associated with it. Put up a message box with the associated ehCluster. */ { BOOL fRet = FALSE; NLBERROR nerr; ENGINEHANDLE ehHost = NULL; ENGINEHANDLE ehCluster = NULL; _bstr_t bstrFriendlyName; _bstr_t bstrDisplayName; _bstr_t bstrHostName; LPCWSTR szFriendlyName = NULL; BOOL fOkCancel=FALSE; CLocalLogger msgLog; _bstr_t bstrCaption; if (*m_pehSelectedInterfaceId == NULL) { // // We shouldn't get here because the "Next" button is only enabled // if there IS a selection; however we deal with this case anyway. // // bstrCaption = L"No interface selected"; bstrCaption = GETRESOURCEIDSTRING (IDS_CONNECT_NO_INTERFACE_SELECTED); msgLog.Log(IDS_CONNECT_SELECT_AN_INTERFACE); goto end; } nerr = gEngine.GetInterfaceIdentification( *m_pehSelectedInterfaceId, REF ehHost, REF ehCluster, REF bstrFriendlyName, REF bstrDisplayName, REF bstrHostName ); if (NLBFAILED(nerr)) { // // This indicates an internal error like a bad handle. // bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED); // szCaption = L"Unable to proceed"; msgLog.Log(IDS_CONNECT_UNABLE_TO_PROCEEED_INTERNAL); // szMessage = L"Unable to proceed due to an internal error."; goto end; } szFriendlyName = (LPCWSTR) bstrFriendlyName; if (szFriendlyName == NULL) { szFriendlyName = L""; } if (ehCluster == NULL) { // // Should be good to go. // TODO -- if interface already bound AND m_type is NOT // DLGTYPE_EXISTING_CLUSTER, we should ask if user wants to // clobber the existing interface. // if (m_type != DLGTYPE_EXISTING_CLUSTER) { CInterfaceSpec iSpec; nerr = gEngine.GetInterfaceSpec(*m_pehSelectedInterfaceId, REF iSpec); if (nerr == NLBERR_OK) { // // Check if we're connected to this NIC, and // the NIC is DHCP, so we're not going to be able to // keep the connected IP address. // // If so, we cannot proceed. // { ENGINEHANDLE ehConnectionIF = NULL; _bstr_t bstrConnectionString; UINT uConnectionIp = 0; nerr = gEngine.GetHostConnectionInformation( ehHost, REF ehConnectionIF, REF bstrConnectionString, REF uConnectionIp ); if (NLBFAILED(nerr)) { TRACE_CRIT(L"%!FUNC! gEngine.GetHostConnectionInformation fails!"); // // We'll plow on... // ehConnectionIF = NULL; uConnectionIp = 0; } if (ehConnectionIF == *m_pehSelectedInterfaceId) { // // The selected interface is also the interface that we // are connecting over... // if (iSpec.m_NlbCfg.fDHCP) { // // Ouch -- it's also DHCP. We can't allow this... // msgLog.Log(IDS_CANT_USE_DHCP_NIC_MSG); bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED); fRet = FALSE; goto end; } } } // // Check if nlb is bound and if so, if it's cluster ip address // is different. // if (iSpec.m_NlbCfg.IsValidNlbConfig()) { // // Hmm... interface is already bound to NLB. // Let's see if the cluster IP address is different... // LPCWSTR szClusterIp = m_pNlbCfg->NlbParams.cl_ip_addr; LPCWSTR szIfClusterIp = iSpec.m_NlbCfg.NlbParams.cl_ip_addr; if ( szIfClusterIp[0]!=0 && (_wcsspnp(szIfClusterIp, L".0")!=NULL)) { // non-blank cluster Ip address if (wcscmp(szClusterIp, szIfClusterIp)) { // // IPs don't match! Put up message box.. // msgLog.Log( IDS_CONNECT_MSG_IF_ALREADY_BOUND, szFriendlyName, iSpec.m_NlbCfg.NlbParams.domain_name, szIfClusterIp ); bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_CAP_IF_ALREADY_BOUND); // szCaption = L"Interface already configured for NLB"; fOkCancel=TRUE; fRet = FALSE; goto end; } } } } } fRet = TRUE; } else { _bstr_t bstrClusterDescription; _bstr_t bstrIpAddress; _bstr_t bstrDomainName; LPCWSTR szClusterDescription = NULL; nerr = gEngine.GetClusterIdentification( ehCluster, REF bstrIpAddress, REF bstrDomainName, REF bstrDisplayName ); if (FAILED(nerr)) { TRACE_CRIT(L"%!FUNC!: Error 0x%lx getting ehCluster 0x%lx identification\n", nerr, ehCluster); bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED); // szCaption = L"Unable to proceed"; msgLog.Log(IDS_CONNECT_UNABLE_TO_PROCEEED_INTERNAL); // szMessage = L"Unable to proceed due to an internal error."; goto end; } szClusterDescription = bstrDisplayName; if (szClusterDescription==NULL) { szClusterDescription = L""; } // // We won't allow proceeding in this case, because this indicates that // this interface is already part of a cluster managed by NLB Manger. // msgLog.Log( IDS_CONNECT_MSG_INTERFACE_ALREADY_MANAGED, szFriendlyName, szClusterDescription ); bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED); } end: if (!fRet) { LPCWSTR szCaption = (LPCWSTR) bstrCaption; LPCWSTR szMessage = msgLog.GetStringSafe(); if (fOkCancel) { int i = MessageBox( szMessage, szCaption, MB_OKCANCEL); if (i == IDOK) { fRet = TRUE; } } else { MessageBox( szMessage, szCaption, MB_ICONSTOP | MB_OK); } } return fRet; } BOOL g_Silent = FALSE;