/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/ /* mscope.cpp This file contains the implementation for the multicast scope node. FILE HISTORY: 9/25/97 EricDav Created */ #include "stdafx.h" #include "server.h" // Server definition #include "nodes.h" // Result pane node definitions #include "mscope.h" // mscope definition #include "addexcl.h" #include "mscopepp.h" // properties of the mScope #include "dlgrecon.h" // reconcile dialog /*--------------------------------------------------------------------------- GetLangTag Sets the language tag based on the name Author: EricDav ---------------------------------------------------------------------------*/ void GetLangTag ( CString & strLangTag ) { char b1[32], b2[32]; static char buff[80]; GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT, LOCALE_SISO639LANGNAME, b1, sizeof(b1)); GetLocaleInfoA(LOCALE_SYSTEM_DEFAULT, LOCALE_SISO3166CTRYNAME, b2, sizeof(b2)); ZeroMemory(buff, sizeof(buff)); if (_stricmp(b1, b2)) sprintf(buff, "%s-%s", b1, b2); else strcpy(buff, b1); strLangTag = buff; } /*--------------------------------------------------------------------------- Class CDhcpMScope implementation ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpMScope::CDhcpMScope ( ITFSComponentData* pTFSComponentData ) : CMTDhcpHandler(pTFSComponentData) { } CDhcpMScope::~CDhcpMScope() { } /*!-------------------------------------------------------------------------- CDhcpMScope::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::InitializeNode ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CString strDisplayName; BuildDisplayName(&strDisplayName, m_SubnetInfo.SubnetName); SetDisplayName(strDisplayName); if (m_SubnetInfo.SubnetState == DhcpSubnetDisabled) { m_strState.LoadString(IDS_SCOPE_INACTIVE); } else { m_strState.LoadString(IDS_SCOPE_ACTIVE); } // Make the node immediately visible pNode->SetVisibilityState(TFS_VIS_SHOW); pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode); pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE)); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); pNode->SetData(TFS_DATA_USER, (LPARAM) this); pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_MSCOPE); SetColumnStringIDs(&aColumns[DHCPSNAP_MSCOPE][0]); SetColumnWidths(&aColumnWidths[DHCPSNAP_MSCOPE][0]); return hrOK; } /*--------------------------------------------------------------------------- CDhcpMScope::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strNode, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); // id string is server name, scope name and guid. strNode = GetServerObject()->GetName(); strNode += GetName() + strGuid; strId = strNode; return hrOK; } /*--------------------------------------------------------------------------- CDhcpMScope::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CDhcpMScope::GetImageIndex(BOOL bOpenImage) { int nIndex = -1; switch (m_nState) { // TODO: these need to be updated with new busy state icons case loading: if (bOpenImage) nIndex = (IsEnabled()) ? ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN_BUSY : ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN_BUSY; else nIndex = (IsEnabled()) ? ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED_BUSY : ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED_BUSY; return nIndex; case notLoaded: case loaded: if (bOpenImage) nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_OPEN : ICON_IDX_SCOPE_INACTIVE_FOLDER_OPEN; else nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_CLOSED : ICON_IDX_SCOPE_INACTIVE_FOLDER_CLOSED; break; case unableToLoad: if (bOpenImage) nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_OPEN_LOST_CONNECTION : ICON_IDX_SCOPE_INACTIVE_FOLDER_OPEN_LOST_CONNECTION; else nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_CLOSED_LOST_CONNECTION : ICON_IDX_SCOPE_INACTIVE_FOLDER_CLOSED_LOST_CONNECTION; return nIndex; default: ASSERT(FALSE); } if (m_spServerNode && IsEnabled()) { CDhcpServer * pServer = GetServerObject(); LPDHCP_MCAST_MIB_INFO pMibInfo = pServer->DuplicateMCastMibInfo(); if (!pMibInfo) return nIndex; LPMSCOPE_MIB_INFO pScopeMibInfo = pMibInfo->ScopeInfo; // walk the list of scopes and find our info for (UINT i = 0; i < pMibInfo->Scopes; i++) { // Find our scope stats if ( (m_SubnetInfo.SubnetName.CompareNoCase(pScopeMibInfo[i].MScopeName) == 0) && (m_SubnetInfo.SubnetAddress == pScopeMibInfo[i].MScopeId) ) { int nPercentInUse; if ((pScopeMibInfo[i].NumAddressesInuse + pScopeMibInfo[i].NumAddressesFree) == 0) nPercentInUse = 0; else nPercentInUse = (pScopeMibInfo[i].NumAddressesInuse * 100) / (pScopeMibInfo[i].NumAddressesInuse + pScopeMibInfo[i].NumAddressesFree); // look to see if this scope meets the warning or red flag case if (pScopeMibInfo[i].NumAddressesFree == 0) { // red flag case, no addresses free, this is the highest // level of warning, so break out of the loop if we set this. if (bOpenImage) nIndex = ICON_IDX_SCOPE_FOLDER_OPEN_ALERT; else nIndex = ICON_IDX_SCOPE_FOLDER_CLOSED_ALERT; break; } else if (nPercentInUse >= SCOPE_WARNING_LEVEL) { // warning condition if Num Addresses in use is greater than // some pre-defined threshold. if (bOpenImage) nIndex = ICON_IDX_SCOPE_FOLDER_OPEN_WARNING; else nIndex = ICON_IDX_SCOPE_FOLDER_CLOSED_WARNING; } break; } } pServer->FreeDupMCastMibInfo(pMibInfo); } return nIndex; } /*--------------------------------------------------------------------------- Overridden base handler functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpMScope::OnAddMenuItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpMScope::OnAddMenuItems ( ITFSNode * pNode, LPCONTEXTMENUCALLBACK pContextMenuCallback, LPDATAOBJECT lpDataObject, DATA_OBJECT_TYPES type, DWORD dwType, long * pInsertionAllowed ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); LONG fFlags = 0, fLoadingFlags = 0; HRESULT hr = S_OK; CString strMenuText; if ( m_nState != loaded ) { fFlags |= MF_GRAYED; } if ( m_nState == loading) { fLoadingFlags = MF_GRAYED; } if (type == CCT_SCOPE) { // // these menu items go in the new menu, // only visible from scope pane // if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) { strMenuText.LoadString(IDS_SCOPE_SHOW_STATISTICS); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_SCOPE_SHOW_STATISTICS, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); // separator hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, 0, CCM_INSERTIONPOINTID_PRIMARY_TOP, MF_SEPARATOR); ASSERT( SUCCEEDED(hr) ); // reconcile strMenuText.LoadString(IDS_SCOPE_RECONCILE); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_SCOPE_RECONCILE, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); // separator hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, 0, CCM_INSERTIONPOINTID_PRIMARY_TOP, MF_SEPARATOR); ASSERT( SUCCEEDED(hr) ); // activate/deactivate if (m_SubnetInfo.SubnetState == DhcpSubnetDisabled) { strMenuText.LoadString(IDS_SCOPE_ACTIVATE); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_SCOPE_ACTIVATE, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); } else { strMenuText.LoadString(IDS_SCOPE_DEACTIVATE); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_SCOPE_DEACTIVATE, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); } } } return hr; } /*--------------------------------------------------------------------------- CDhcpMScope::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpMScope::OnCommand ( ITFSNode * pNode, long nCommandId, DATA_OBJECT_TYPES type, LPDATAOBJECT pDataObject, DWORD dwType ) { HRESULT hr = S_OK; switch (nCommandId) { case IDS_ACTIVATE: case IDS_DEACTIVATE: case IDS_SCOPE_ACTIVATE: case IDS_SCOPE_DEACTIVATE: OnActivateScope(pNode); break; case IDS_REFRESH: OnRefresh(pNode, pDataObject, dwType, 0, 0); break; case IDS_SCOPE_SHOW_STATISTICS: OnShowScopeStats(pNode); break; case IDS_SCOPE_RECONCILE: OnReconcileScope(pNode); break; case IDS_DELETE: OnDelete(pNode); break; default: break; } return hr; } /*--------------------------------------------------------------------------- CDhcpMScope::CreatePropertyPages Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpMScope::CreatePropertyPages ( ITFSNode * pNode, LPPROPERTYSHEETCALLBACK lpProvider, LPDATAOBJECT pDataObject, LONG_PTR handle, DWORD dwType ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = hrOK; DWORD dwError; DWORD dwDynDnsFlags; SPIComponentData spComponentData; LARGE_INTEGER liVersion; CDhcpServer * pServer; DHCP_IP_RANGE dhcpIpRange; // // Create the property page // m_spNodeMgr->GetComponentData(&spComponentData); CMScopeProperties * pScopeProp = new CMScopeProperties(pNode, spComponentData, m_spTFSCompData, NULL); // Get the Server version and set it in the property sheet pServer = GetServerObject(); pServer->GetVersion(liVersion); pScopeProp->SetVersion(liVersion); // Set scope specific data in the prop sheet pScopeProp->m_pageGeneral.m_SubnetInfo = m_SubnetInfo; BEGIN_WAIT_CURSOR; ZeroMemory(&dhcpIpRange, sizeof(dhcpIpRange)); dwError = GetIpRange(&dhcpIpRange); if (dwError != ERROR_SUCCESS) { ::DhcpMessageBox(dwError); goto Cleanup; } pScopeProp->m_pageGeneral.m_ScopeCfg.m_dwStartAddress = dhcpIpRange.StartAddress; pScopeProp->m_pageGeneral.m_ScopeCfg.m_dwEndAddress = dhcpIpRange.EndAddress; pScopeProp->m_pageGeneral.m_uImage = GetImageIndex(FALSE); dwError = GetLeaseTime(&pScopeProp->m_pageGeneral.m_ScopeCfg.m_dwLeaseTime); END_WAIT_CURSOR; GetLifetime(&pScopeProp->m_pageLifetime.m_Expiry); // // Object gets deleted when the page is destroyed // Assert(lpProvider != NULL); return pScopeProp->CreateModelessSheet(lpProvider, handle); Cleanup: delete pScopeProp; return hrFalse; } /*--------------------------------------------------------------------------- CDhcpMScope::OnPropertyChange Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnPropertyChange ( ITFSNode * pNode, LPDATAOBJECT pDataobject, DWORD dwType, LPARAM arg, LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CMScopeProperties * pScopeProp = reinterpret_cast(lParam); LONG_PTR changeMask = 0; // tell the property page to do whatever now that we are back on the // main thread pScopeProp->OnPropertyChange(TRUE, &changeMask); pScopeProp->AcknowledgeNotify(); if (changeMask) pNode->ChangeNode(changeMask); return hrOK; } /*!-------------------------------------------------------------------------- CDhcpMScope::GetString Returns string information for display in the result pane columns Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(LPCTSTR) CDhcpMScope::GetString ( ITFSNode * pNode, int nCol ) { switch (nCol) { case 0: return GetDisplayName(); case 1: return m_strState; case 2: return m_SubnetInfo.SubnetComment; } return NULL; } STDMETHODIMP CDhcpMScope::DestroyHandler( ITFSNode *pNode ) { // Cleanup the stats dialog WaitForStatisticsWindow( &m_dlgStats ); return CMTDhcpHandler::DestroyHandler( pNode ); } // CDhcpMScope::DestoryHandler() /*--------------------------------------------------------------------------- CDhcpMScope::CompareItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(int) CDhcpMScope::CompareItems ( ITFSComponent * pComponent, MMC_COOKIE cookieA, MMC_COOKIE cookieB, int nCol ) { SPITFSNode spNode1, spNode2; m_spNodeMgr->FindNode(cookieA, &spNode1); m_spNodeMgr->FindNode(cookieB, &spNode2); int nCompare = 0; return nCompare; } /*!-------------------------------------------------------------------------- CDhcpServer::OnDelete The base handler calls this when MMC sends a MMCN_DELETE for a scope pane item. We just call our delete command handler. Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnDelete ( ITFSNode * pNode, LPARAM arg, LPARAM lParam ) { return OnDelete(pNode); } /*--------------------------------------------------------------------------- CDhcpMScope::OnResultDelete This function is called when we are supposed to delete result pane items. We build a list of selected items and then delete them. Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnResultDelete ( ITFSComponent * pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM param ) { HRESULT hr = hrOK; AFX_MANAGE_STATE(AfxGetStaticModuleState()); return hr; } /*!-------------------------------------------------------------------------- CDhcpMScope::OnGetResultViewType MMC calls this to get the result view information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnGetResultViewType ( ITFSComponent * pComponent, MMC_COOKIE cookie, LPOLESTR * ppViewType, long * pViewOptions ) { *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT; // we still want the default MMC result pane view, we just want // multiselect, so return S_FALSE return S_FALSE; } /*!-------------------------------------------------------------------------- CDhcpMScope::OnUpdateToolbarButtons We override this function to show/hide the correct activate/deactivate buttons Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnUpdateToolbarButtons ( ITFSNode * pNode, LPDHCPTOOLBARNOTIFY pToolbarNotify ) { HRESULT hr = hrOK; if (pToolbarNotify->bSelect) { UpdateToolbarStates(); } CMTDhcpHandler::OnUpdateToolbarButtons(pNode, pToolbarNotify); return hr; } /*!-------------------------------------------------------------------------- CDhcpMScope::UpdateToolbarStates Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpMScope::UpdateToolbarStates() { if (( m_SubnetInfo.SubnetState == DhcpSubnetDisabled) || ( m_SubnetInfo.SubnetState == DhcpSubnetDisabledSwitched )) { g_SnapinButtonStates[DHCPSNAP_MSCOPE][TOOLBAR_IDX_ACTIVATE] = ENABLED; g_SnapinButtonStates[DHCPSNAP_MSCOPE][TOOLBAR_IDX_DEACTIVATE] = HIDDEN; } else { g_SnapinButtonStates[DHCPSNAP_MSCOPE][TOOLBAR_IDX_ACTIVATE] = HIDDEN; g_SnapinButtonStates[DHCPSNAP_MSCOPE][TOOLBAR_IDX_DEACTIVATE] = ENABLED; } } /*--------------------------------------------------------------------------- Command Handlers ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpmScope::OnActivateScope Message handler for the scope activate/deactivate menu Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::OnActivateScope ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); DWORD err = 0; int nOpenImage, nClosedImage; DHCP_SUBNET_STATE dhcpOldState = m_SubnetInfo.SubnetState; if (m_SubnetInfo.SubnetState == DhcpSubnetEnabled) { // if they want to disable the scope, confirm if (AfxMessageBox(IDS_SCOPE_DISABLE_CONFIRM, MB_YESNO) != IDYES) { return err; } } m_SubnetInfo.SubnetState = (m_SubnetInfo.SubnetState == DhcpSubnetDisabled) ? DhcpSubnetEnabled : DhcpSubnetDisabled; // Tell the scope to update it's state err = SetInfo(); if (err != 0) { ::DhcpMessageBox(err); m_SubnetInfo.SubnetState = dhcpOldState; } else { // update the icon and the status text if (m_SubnetInfo.SubnetState == DhcpSubnetDisabled) { nOpenImage = ICON_IDX_SCOPE_INACTIVE_FOLDER_OPEN; nClosedImage = ICON_IDX_SCOPE_INACTIVE_FOLDER_CLOSED; m_strState.LoadString(IDS_SCOPE_INACTIVE); } else { nOpenImage = GetImageIndex(TRUE); nClosedImage = GetImageIndex(FALSE); m_strState.LoadString(IDS_SCOPE_ACTIVE); } pNode->SetData(TFS_DATA_IMAGEINDEX, nClosedImage); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, nOpenImage); VERIFY(SUCCEEDED(pNode->ChangeNode(SCOPE_PANE_CHANGE_ITEM))); // Update the toolbar button UpdateToolbarStates(); SendUpdateToolbar(pNode, TRUE); } return err; } /*--------------------------------------------------------------------------- CDhcpMScope::OnReconcileScope Reconciles the active leases database for this scope Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnReconcileScope ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CReconcileDlg dlgRecon(pNode); dlgRecon.m_bMulticast = TRUE; dlgRecon.DoModal(); return hrOK; } /*--------------------------------------------------------------------------- CDhcpMScope::OnShowScopeStats() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnShowScopeStats ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = S_OK; CString strScopeAddress; // Fill in some information in the stats object. // CreateNewStatisticsWindow handles the case if the window is // already visible. m_dlgStats.SetNode(pNode); m_dlgStats.SetServer(GetServerIpAddress()); m_dlgStats.SetScopeId(GetScopeId()); m_dlgStats.SetName(GetName()); CreateNewStatisticsWindow(&m_dlgStats, ::FindMMCMainWindow(), IDD_STATS_NARROW); return hr; } /*--------------------------------------------------------------------------- CDhcpMScope::OnDelete() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::OnDelete(ITFSNode * pNode) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = S_OK; SPITFSNode spParent; BOOL fAbortDelete = FALSE; BOOL fDeactivated = FALSE; LONG err = 0 ; CDhcpMScope *pMScope; // Any property sheets open? pMScope = GETHANDLER( CDhcpMScope, pNode ); if ( pMScope->HasPropSheetsOpen()) { AfxMessageBox( IDS_MSG_CLOSE_PROPSHEET ); return S_FALSE; } if (::DhcpMessageBox( IsEnabled() ? IDS_MSG_DELETE_ACTIVE : IDS_MSG_DELETE_SCOPE, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION) == IDYES) { pNode->GetParent(&spParent); CDhcpServer * pServer = GETHANDLER(CDhcpServer, spParent); err = pServer->DeleteMScope(pNode); // delete the statistics window WaitForStatisticsWindow( &m_dlgStats ); } // if return hr; } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpMScope:OnHaveData Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpMScope::OnHaveData ( ITFSNode * pParentNode, ITFSNode * pNewNode ) { LPARAM dwType = pNewNode->GetData(TFS_DATA_TYPE); UpdateToolbarStates(); switch (dwType) { case DHCPSNAP_MSCOPE_LEASES: pParentNode->AddChild(pNewNode); m_spActiveLeases.Set(pNewNode); break; case DHCPSNAP_ADDRESS_POOL: pParentNode->AddChild(pNewNode); m_spAddressPool.Set(pNewNode); break; } // now tell the view to update themselves ExpandNode(pParentNode, TRUE); } /*--------------------------------------------------------------------------- CDhcpMScope::OnHaveData Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpMScope::OnHaveData ( ITFSNode * pParentNode, LPARAM Data, LPARAM Type ) { // This is how we get non-node data back from the background thread. if (Type == DHCP_QDATA_SUBNET_INFO) { LONG_PTR changeMask = 0; LPDHCP_MSCOPE_INFO pdhcpSubnetInfo = reinterpret_cast(Data); // update the scope name and state based on the info if (pdhcpSubnetInfo->MScopeName && m_SubnetInfo.SubnetName.CompareNoCase(pdhcpSubnetInfo->MScopeName) != 0) { SetName(pdhcpSubnetInfo->MScopeName); changeMask = SCOPE_PANE_CHANGE_ITEM; } // update the comment if (m_SubnetInfo.SubnetComment.CompareNoCase(pdhcpSubnetInfo->MScopeComment) != 0) { SetComment(pdhcpSubnetInfo->MScopeComment); } if (m_SubnetInfo.SubnetState != pdhcpSubnetInfo->MScopeState) { DHCP_SUBNET_STATE dhcpOldState = m_SubnetInfo.SubnetState; m_SubnetInfo.SubnetState = pdhcpSubnetInfo->MScopeState; pParentNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE)); pParentNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); // Update the toolbar button UpdateToolbarStates(); SendUpdateToolbar(pParentNode, TRUE); changeMask = SCOPE_PANE_CHANGE_ITEM; } // Update our internal struct m_SubnetInfo.Set(pdhcpSubnetInfo); if (pdhcpSubnetInfo) ::DhcpRpcFreeMemory(pdhcpSubnetInfo); if (changeMask) VERIFY(SUCCEEDED(pParentNode->ChangeNode(changeMask))); } } /*--------------------------------------------------------------------------- CDhcpMScope::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CDhcpMScope::OnCreateQuery(ITFSNode * pNode) { CDhcpMScopeQueryObj* pQuery = new CDhcpMScopeQueryObj(m_spTFSCompData, m_spNodeMgr); if ( pQuery == NULL ) return pQuery; pQuery->m_strServer = GetServerObject(pNode)->GetIpAddress(); pQuery->m_strName = GetName(); return pQuery; } /*--------------------------------------------------------------------------- CDhcpMScopeQueryObj::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpMScopeQueryObj::Execute() { HRESULT hr = hrOK; DWORD dwReturn; LPDHCP_MSCOPE_INFO pMScopeInfo = NULL; dwReturn = ::DhcpGetMScopeInfo(((LPWSTR) (LPCTSTR)m_strServer), ((LPWSTR) (LPCTSTR)m_strName), &pMScopeInfo); if (dwReturn == ERROR_SUCCESS && pMScopeInfo) { AddToQueue((LPARAM) pMScopeInfo, DHCP_QDATA_SUBNET_INFO); } else { Trace1("CDhcpMScopeQueryObj::Execute - DhcpGetMScopeInfo failed! %d\n", dwReturn); PostError(dwReturn); return hrFalse; } CreateSubcontainers(); return hrFalse; } /*--------------------------------------------------------------------------- CDhcpMScope::CreateSubcontainers() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScopeQueryObj::CreateSubcontainers() { HRESULT hr = hrOK; SPITFSNode spNode; // // create the address pool Handler // CMScopeAddressPool *pAddressPool = new CMScopeAddressPool(m_spTFSCompData); CreateContainerTFSNode(&spNode, &GUID_DhcpMCastAddressPoolNodeType, pAddressPool, pAddressPool, m_spNodeMgr); // Tell the handler to initialize any specific data pAddressPool->InitializeNode((ITFSNode *) spNode); // Add the node as a child to this node AddToQueue(spNode); pAddressPool->Release(); spNode.Set(NULL); // // create the Active Leases Handler // CMScopeActiveLeases *pActiveLeases = new CMScopeActiveLeases(m_spTFSCompData); CreateContainerTFSNode(&spNode, &GUID_DhcpMCastActiveLeasesNodeType, pActiveLeases, pActiveLeases, m_spNodeMgr); // Tell the handler to initialize any specific data pActiveLeases->InitializeNode((ITFSNode *) spNode); // Add the node as a child to this node AddToQueue(spNode); pActiveLeases->Release(); return hr; } /*--------------------------------------------------------------------------- Helper functions ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::BuildDisplayName ( CString * pstrDisplayName, LPCTSTR pName ) { if (pstrDisplayName) { CString strStandard, strName; strName = pName; strStandard.LoadString(IDS_MSCOPE_FOLDER); *pstrDisplayName = strStandard + _T(" [") + strName + _T("] "); } return hrOK; } HRESULT CDhcpMScope::SetName ( LPCWSTR pName ) { if (pName != NULL) { m_SubnetInfo.SubnetName = pName; } CString strDisplayName; // // Create the display name for this scope // Convert DHCP_IP_ADDRES to a string and initialize this object // BuildDisplayName(&strDisplayName, pName); SetDisplayName(strDisplayName); return hrOK; } /*--------------------------------------------------------------------------- CDhcpMScope::GetServerIpAddress() Description Author: EricDav ---------------------------------------------------------------------------*/ LPCWSTR CDhcpMScope::GetServerIpAddress() { CDhcpServer * pServer = GetServerObject(); return pServer->GetIpAddress(); } /*--------------------------------------------------------------------------- CDhcpMScope::GetServerIpAddress Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpMScope::GetServerIpAddress(DHCP_IP_ADDRESS * pdhcpIpAddress) { CDhcpServer * pServer = GetServerObject(); pServer->GetIpAddress(pdhcpIpAddress); } /*--------------------------------------------------------------------------- CDhcpMScope::GetServerVersion Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpMScope::GetServerVersion ( LARGE_INTEGER& liVersion ) { CDhcpServer * pServer = GetServerObject(); pServer->GetVersion(liVersion); } /*--------------------------------------------------------------------------- CDhcpMScope::InitMScopeInfo() Updates the scope's information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::InitMScopeInfo ( LPDHCP_MSCOPE_INFO pMScopeInfo ) { HRESULT hr = hrOK; m_SubnetInfo.Set(pMScopeInfo); return hr; } /*--------------------------------------------------------------------------- CDhcpMScope::InitMScopeInfo() Updates the scope's information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpMScope::InitMScopeInfo ( CSubnetInfo & subnetInfo ) { HRESULT hr = hrOK; m_SubnetInfo = subnetInfo; return hr; } /*--------------------------------------------------------------------------- CDhcpMScope::SetInfo() Updates the scope's information Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::SetInfo ( LPCTSTR pNewName ) { DWORD err = ERROR_SUCCESS; DHCP_MSCOPE_INFO dhcpMScopeInfo = {0}; dhcpMScopeInfo.MScopeName = (pNewName) ? (LPWSTR) pNewName : (LPTSTR) ((LPCTSTR) m_SubnetInfo.SubnetName); dhcpMScopeInfo.MScopeComment = (LPTSTR) ((LPCTSTR) m_SubnetInfo.SubnetComment); dhcpMScopeInfo.MScopeId = m_SubnetInfo.SubnetAddress; dhcpMScopeInfo.MScopeAddressPolicy = m_SubnetInfo.MScopeAddressPolicy; dhcpMScopeInfo.MScopeState = m_SubnetInfo.SubnetState; dhcpMScopeInfo.MScopeFlags = 0; dhcpMScopeInfo.ExpiryTime = m_SubnetInfo.ExpiryTime; dhcpMScopeInfo.TTL = m_SubnetInfo.TTL; // gotta fill in the language ID based on the name GetLangTag(m_SubnetInfo.LangTag); dhcpMScopeInfo.LangTag = (LPWSTR) ((LPCTSTR) m_SubnetInfo.LangTag); GetServerIpAddress(&dhcpMScopeInfo.PrimaryHost.IpAddress); // Review : ericdav - do we need to fill these in? dhcpMScopeInfo.PrimaryHost.NetBiosName = NULL; dhcpMScopeInfo.PrimaryHost.HostName = NULL; err = ::DhcpSetMScopeInfo(GetServerIpAddress(), (LPWSTR) ((LPCTSTR) m_SubnetInfo.SubnetName), &dhcpMScopeInfo, FALSE); // update the scope name if we are changing the name if (err == ERROR_SUCCESS && pNewName) { m_SubnetInfo.SubnetName = pNewName; } return err; } /*--------------------------------------------------------------------------- CDhcpMScope::GetLeaseTime Gets the lease time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::GetLeaseTime ( LPDWORD pdwLeaseTime ) { // // Check option -- the lease duration // DWORD dwLeaseTime = 0; DWORD err = ERROR_SUCCESS; DHCP_OPTION_VALUE * poptValue = NULL; err = GetOptionValue(MADCAP_OPTION_LEASE_TIME, &poptValue); if (err != ERROR_SUCCESS) { Trace1("CDhcpScope::GetLeaseTime - couldn't get lease duration!! %d \n", err); dwLeaseTime = 0; } else { if (poptValue->Value.Elements != NULL) dwLeaseTime = poptValue->Value.Elements[0].Element.DWordOption; if (poptValue) ::DhcpRpcFreeMemory(poptValue); } *pdwLeaseTime = dwLeaseTime; return err; } /*--------------------------------------------------------------------------- CDhcpMScope::SetLeaseTime Sets the lease time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::SetLeaseTime ( DWORD dwLeaseTime ) { DWORD err = 0; // // Set lease duration // CDhcpOption dhcpOption (MADCAP_OPTION_LEASE_TIME, DhcpDWordOption , _T(""), _T("")); dhcpOption.QueryValue().SetNumber(dwLeaseTime); err = SetOptionValue(&dhcpOption); return err; } /*--------------------------------------------------------------------------- CDhcpMScope::GetLifetime Gets the madcap scope lifetime Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::GetLifetime ( DATE_TIME * pdtLifetime ) { DWORD err = ERROR_SUCCESS; if (pdtLifetime) { pdtLifetime->dwLowDateTime = m_SubnetInfo.ExpiryTime.dwLowDateTime; pdtLifetime->dwHighDateTime = m_SubnetInfo.ExpiryTime.dwHighDateTime; } return err; } /*--------------------------------------------------------------------------- CDhcpMScope::SetLifetime Sets the madcap scope lifetime Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::SetLifetime ( DATE_TIME * pdtLifetime ) { DWORD err = 0; if (pdtLifetime) { m_SubnetInfo.ExpiryTime.dwLowDateTime = pdtLifetime->dwLowDateTime; m_SubnetInfo.ExpiryTime.dwHighDateTime = pdtLifetime->dwHighDateTime; } return err; } /*--------------------------------------------------------------------------- CDhcpMScope::GetTTL Gets the TTL for this multicast scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::GetTTL ( LPBYTE pbTTL ) { DWORD err = 0; if (pbTTL) *pbTTL = m_SubnetInfo.TTL; return err; } /*--------------------------------------------------------------------------- CDhcpMScope::SetTTL Sets the least time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::SetTTL ( BYTE TTL ) { DWORD err = 0; m_SubnetInfo.TTL = TTL; return err; } /*--------------------------------------------------------------------------- CDhcpMScope::DeleteClient Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::DeleteClient ( DHCP_IP_ADDRESS dhcpClientIpAddress ) { DWORD dwErr = ERROR_SUCCESS; DHCP_SEARCH_INFO dhcpClientInfo; dhcpClientInfo.SearchType = DhcpClientIpAddress; dhcpClientInfo.SearchInfo.ClientIpAddress = dhcpClientIpAddress; dwErr = ::DhcpDeleteMClientInfo((LPWSTR) GetServerIpAddress(), &dhcpClientInfo); return dwErr; } /*--------------------------------------------------------------------------- CDhcpMScope::SetOptionValue Sets the least time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::SetOptionValue ( CDhcpOption * pdhcType ) { DWORD err = 0; DHCP_OPTION_DATA * pdhcOptionData; DHCP_OPTION_SCOPE_INFO dhcScopeInfo; CDhcpOptionValue * pcOptionValue = NULL; ZeroMemory( & dhcScopeInfo, sizeof(dhcScopeInfo) ); CATCH_MEM_EXCEPTION { pcOptionValue = new CDhcpOptionValue( & pdhcType->QueryValue() ) ; if ( pcOptionValue ) { dhcScopeInfo.ScopeType = DhcpMScopeOptions; dhcScopeInfo.ScopeInfo.MScopeInfo = (LPWSTR) ((LPCTSTR) m_SubnetInfo.SubnetName); pcOptionValue->CreateOptionDataStruct(&pdhcOptionData, TRUE); err = (DWORD) ::DhcpSetOptionValue(GetServerIpAddress(), pdhcType->QueryId(), &dhcScopeInfo, pdhcOptionData); } delete pcOptionValue ; } END_MEM_EXCEPTION(err) ; return err ; } /*--------------------------------------------------------------------------- CDhcpScope::GetOptionValue Gets an option value for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::GetOptionValue ( DHCP_OPTION_ID OptionID, DHCP_OPTION_VALUE ** ppdhcOptionValue ) { DWORD err = 0 ; DHCP_OPTION_SCOPE_INFO dhcScopeInfo ; ZeroMemory( &dhcScopeInfo, sizeof(dhcScopeInfo) ); CATCH_MEM_EXCEPTION { dhcScopeInfo.ScopeType = DhcpMScopeOptions; dhcScopeInfo.ScopeInfo.MScopeInfo = (LPWSTR) ((LPCTSTR) m_SubnetInfo.SubnetName); err = (DWORD) ::DhcpGetOptionValue(GetServerIpAddress(), OptionID, &dhcScopeInfo, ppdhcOptionValue ); } END_MEM_EXCEPTION(err) ; return err ; } /*--------------------------------------------------------------------------- CDhcpMScope::RemoveValue Removes an option Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::RemoveOptionValue ( DHCP_OPTION_ID dhcOptId ) { DWORD dwErr = ERROR_SUCCESS; DHCP_OPTION_SCOPE_INFO dhcScopeInfo; ZeroMemory( &dhcScopeInfo, sizeof(dhcScopeInfo) ); dhcScopeInfo.ScopeType = DhcpMScopeOptions; dhcScopeInfo.ScopeInfo.MScopeInfo = (LPWSTR) ((LPCTSTR) m_SubnetInfo.SubnetName); dwErr = ::DhcpRemoveOptionValue(GetServerIpAddress(), dhcOptId, &dhcScopeInfo); return dwErr; } /*--------------------------------------------------------------------------- CDhcpMScope::AddElement Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::AddElement ( LPDHCP_SUBNET_ELEMENT_DATA_V4 pdhcpSubnetElementData ) { DWORD dwErr = ERROR_SUCCESS; dwErr = ::DhcpAddMScopeElement((LPWSTR) GetServerIpAddress(), (LPWSTR) ((LPCTSTR) m_SubnetInfo.SubnetName), pdhcpSubnetElementData); return dwErr; } /*--------------------------------------------------------------------------- CDhcpMScope::RemoveElement Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::RemoveElement ( LPDHCP_SUBNET_ELEMENT_DATA_V4 pdhcpSubnetElementData, BOOL bForce ) { DWORD dwErr = ERROR_SUCCESS; dwErr = ::DhcpRemoveMScopeElement((LPWSTR) GetServerIpAddress(), (LPWSTR) ((LPCTSTR) m_SubnetInfo.SubnetName), pdhcpSubnetElementData, bForce ? DhcpFullForce : DhcpNoForce); return dwErr; } /*--------------------------------------------------------------------------- CDhcpMScope::GetIpRange() returns the scope's allocation range. Connects to the server to get the information Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::GetIpRange ( DHCP_IP_RANGE * pdhipr ) { BOOL bAlloced = FALSE; DWORD dwError = ERROR_SUCCESS; pdhipr->StartAddress = 0; pdhipr->EndAddress = 0; CMScopeAddressPool * pAddressPool = GetAddressPoolObject(); if (pAddressPool == NULL) { // the address pool folder isn't there yet... // Create a temporary one for now... pAddressPool = new CMScopeAddressPool(m_spTFSCompData); bAlloced = TRUE; } // Get a query object from the address pool handler CMScopeAddressPoolQueryObj * pQueryObject = reinterpret_cast(pAddressPool->OnCreateQuery(m_spAddressPool)); // if we created an address pool handler, then free it up now if (bAlloced) { pQueryObject->m_strServer = GetServerIpAddress(); pQueryObject->m_strName = GetName(); pAddressPool->Release(); } // tell the query object to get the ip ranges pQueryObject->EnumerateIpRanges(); // check to see if there was any problems getting the information dwError = pQueryObject->m_dwError; if (dwError != ERROR_SUCCESS) { return dwError; } LPQUEUEDATA pQD; while (pQD = pQueryObject->RemoveFromQueue()) { Assert (pQD->Type == QDATA_PNODE); SPITFSNode p; p = reinterpret_cast(pQD->Data); delete pQD; CDhcpAllocationRange * pAllocRange = GETHANDLER(CDhcpAllocationRange, p); pdhipr->StartAddress = pAllocRange->QueryAddr(TRUE); pdhipr->EndAddress = pAllocRange->QueryAddr(FALSE); p.Release(); } pQueryObject->Release(); return dwError; } /*--------------------------------------------------------------------------- CDhcpMScope::UpdateIpRange() This function updates the IP range on the server. We also need to remove any exclusion ranges that fall outside of the new allocation range. Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::UpdateIpRange ( DHCP_IP_RANGE * pdhipr ) { return SetIpRange(pdhipr, TRUE); } /*--------------------------------------------------------------------------- CDhcpMScope::QueryIpRange() Returns the scope's allocation range (doesn't talk to the server directly, only returns internally cached information). Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpMScope::QueryIpRange ( DHCP_IP_RANGE * pdhipr ) { pdhipr->StartAddress = 0; pdhipr->EndAddress = 0; SPITFSNodeEnum spNodeEnum; SPITFSNode spCurrentNode; ULONG nNumReturned = 0; m_spAddressPool->GetEnum(&spNodeEnum); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); while (nNumReturned) { if (spCurrentNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ALLOCATION_RANGE) { // found the address // CDhcpAllocationRange * pAllocRange = GETHANDLER(CDhcpAllocationRange, spCurrentNode); pdhipr->StartAddress = pAllocRange->QueryAddr(TRUE); pdhipr->EndAddress = pAllocRange->QueryAddr(FALSE); } spCurrentNode.Release(); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); } } /*--------------------------------------------------------------------------- CDhcpMScope::SetIpRange Set's the allocation range for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::SetIpRange ( DHCP_IP_RANGE * pdhcpIpRange, BOOL bUpdateOnServer ) { CDhcpIpRange dhcpIpRange = *pdhcpIpRange; return SetIpRange(dhcpIpRange, bUpdateOnServer); } /*--------------------------------------------------------------------------- CDhcpMScope::SetIpRange Set's the allocation range for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::SetIpRange ( const CDhcpIpRange & dhcpIpRange, BOOL bUpdateOnServer ) { DWORD err = 0; if (bUpdateOnServer) { DHCP_SUBNET_ELEMENT_DATA_V4 dhcSubElData; DHCP_IP_RANGE dhipOldRange; err = GetIpRange(&dhipOldRange); if (err != ERROR_SUCCESS) { return err; } dhcSubElData.ElementType = DhcpIpRanges; dhcSubElData.Element.IpRange = &dhipOldRange; // // First update the information on the server // // Remove the old IP range; allow "not found" error in new scope. // (void)RemoveElement(&dhcSubElData); //if ( err == 0 || err == ERROR_FILE_NOT_FOUND ) //{ DHCP_IP_RANGE dhcpNewIpRange = dhcpIpRange; dhcSubElData.Element.IpRange = &dhcpNewIpRange; if ( (err = AddElement( & dhcSubElData )) == 0 ) { //m_ip_range = dhipr ; } else { Trace1("SetIpRange - AddElement failed %lx\n", err); // something bad happened, try to put the old range back dhcSubElData.Element.IpRange = &dhipOldRange; if (AddElement(&dhcSubElData) != ERROR_SUCCESS) { Trace0("SetIpRange - cannot return ip range back to old state!!"); } } //} } // // Find the address pool folder and update the UI object // SPITFSNodeEnum spNodeEnum; SPITFSNode spCurrentNode; ULONG nNumReturned = 0; if (m_spAddressPool == NULL) return err; m_spAddressPool->GetEnum(&spNodeEnum); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); while (nNumReturned) { if (spCurrentNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ALLOCATION_RANGE) { // found the address // CDhcpAllocationRange * pAllocRange = GETHANDLER(CDhcpAllocationRange, spCurrentNode); // now set them // pAllocRange->SetAddr(dhcpIpRange.QueryAddr(TRUE), TRUE); pAllocRange->SetAddr(dhcpIpRange.QueryAddr(FALSE), FALSE); // tell the UI to update spCurrentNode->ChangeNode(RESULT_PANE_CHANGE_ITEM_DATA); } spCurrentNode.Release(); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); } return err ; } /*--------------------------------------------------------------------------- CDhcpMScope::IsOverlappingRange determines if the exclusion overlaps an existing range Author: EricDav ---------------------------------------------------------------------------*/ BOOL CDhcpMScope::IsOverlappingRange ( CDhcpIpRange & dhcpIpRange ) { SPITFSNodeEnum spNodeEnum; SPITFSNode spCurrentNode; ULONG nNumReturned = 0; BOOL bOverlap = FALSE; m_spActiveLeases->GetEnum(&spNodeEnum); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); while (nNumReturned) { if (spCurrentNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_EXCLUSION_RANGE) { // found the address // CDhcpExclusionRange * pExclusion = GETHANDLER(CDhcpExclusionRange, spCurrentNode); if ( bOverlap = pExclusion->IsOverlap( dhcpIpRange ) ) { spCurrentNode.Release(); break; } } spCurrentNode.Release(); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); } return bOverlap ; } /*--------------------------------------------------------------------------- CDhcpMScope::IsValidExclusion determines if the exclusion is valid for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::IsValidExclusion ( CDhcpIpRange & dhcpExclusionRange ) { DWORD err = 0; DHCP_IP_RANGE dhcpIpRange; err = GetIpRange (&dhcpIpRange); CDhcpIpRange dhcpScopeRange(dhcpIpRange); // // Get the data into a range object. // if ( IsOverlappingRange( dhcpExclusionRange ) ) { // // Walk the current list, determining if the new range is valid. // Then, if OK, verify that it's really a sub-range of the current range. // err = IDS_ERR_IP_RANGE_OVERLAP ; } else if ( ! dhcpExclusionRange.IsSubset( dhcpScopeRange ) ) { // // Guarantee that the new range is an (improper) subset of the scope's range // err = IDS_ERR_IP_RANGE_NOT_SUBSET ; } return err; } /*--------------------------------------------------------------------------- CDhcpMScope::StoreExceptionList Adds a bunch of exclusions to the scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::StoreExceptionList ( CExclusionList * plistExclusions ) { DHCP_SUBNET_ELEMENT_DATA dhcElement ; DHCP_IP_RANGE dhipr ; CDhcpIpRange * pobIpRange ; DWORD err = 0, err1 = 0; POSITION pos; pos = plistExclusions->GetHeadPosition(); while ( pos ) { pobIpRange = plistExclusions->GetNext(pos); err1 = AddExclusion( *pobIpRange ) ; if ( err1 != 0 ) { err = err1; Trace1("CDhcpScope::StoreExceptionList error adding range %d\n", err); } } return err ; } /*--------------------------------------------------------------------------- CDhcpMScope::AddExclusion Adds an individual exclusion to the server Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::AddExclusion ( CDhcpIpRange & dhcpIpRange, BOOL bAddToUI ) { DHCP_SUBNET_ELEMENT_DATA_V4 dhcElement ; DHCP_IP_RANGE dhipr ; DWORD err = 0; dhcElement.ElementType = DhcpExcludedIpRanges ; dhipr = dhcpIpRange ; dhcElement.Element.ExcludeIpRange = & dhipr ; Trace2("CDhcpMScope::AddExclusion add excluded range %lx %lx\n", dhipr.StartAddress, dhipr.EndAddress ); err = AddElement( & dhcElement ) ; //if ( err != 0 && err != ERROR_DHCP_INVALID_RANGE) if ( err != 0 ) { Trace1("CDhcpMScope::AddExclusion error removing range %d\n", err); } if (m_spAddressPool != NULL) { CMScopeAddressPool * pAddrPool = GETHANDLER(CMScopeAddressPool, m_spAddressPool); if (!err && bAddToUI && pAddrPool->m_bExpanded) { SPITFSNode spNewExclusion; CDhcpExclusionRange * pExclusion = new CDhcpExclusionRange(m_spTFSCompData, &((DHCP_IP_RANGE) dhcpIpRange)); CreateLeafTFSNode(&spNewExclusion, &GUID_DhcpExclusionNodeType, pExclusion, pExclusion, m_spNodeMgr); // Tell the handler to initialize any specific data pExclusion->InitializeNode((ITFSNode *) spNewExclusion); // Add the node as a child to this node m_spAddressPool->AddChild(spNewExclusion); pExclusion->Release(); } } return err; } /*--------------------------------------------------------------------------- CDhcpMScope::RemoveExclusion Removes and exclusion from the server Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpMScope::RemoveExclusion ( CDhcpIpRange & dhcpIpRange ) { DHCP_SUBNET_ELEMENT_DATA_V4 dhcElement ; DHCP_IP_RANGE dhipr ; DWORD err = 0; dhcElement.ElementType = DhcpExcludedIpRanges ; dhipr = dhcpIpRange ; dhcElement.Element.ExcludeIpRange = & dhipr ; Trace2("CDhcpMScope::RemoveExclusion remove excluded range %lx %lx\n", dhipr.StartAddress, dhipr.EndAddress); err = RemoveElement( & dhcElement ) ; //if ( err != 0 && err != ERROR_DHCP_INVALID_RANGE) if ( err != 0 ) { Trace1("CDhcpMScope::RemoveExclusion error removing range %d\n", err); } return err; } ///////////////////////////////////////////////////////////////////// // // CMScopeActiveLeases implementation // ///////////////////////////////////////////////////////////////////// /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ CMScopeActiveLeases::CMScopeActiveLeases ( ITFSComponentData * pComponentData ) : CMTDhcpHandler(pComponentData) { } CMScopeActiveLeases::~CMScopeActiveLeases() { } /*!-------------------------------------------------------------------------- CMScopeActiveLeases::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeActiveLeases::InitializeNode ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = hrOK; // // Create the display name for this scope // CString strTemp; strTemp.LoadString(IDS_ACTIVE_LEASES_FOLDER); SetDisplayName(strTemp); // Make the node immediately visible pNode->SetVisibilityState(TFS_VIS_SHOW); pNode->SetData(TFS_DATA_IMAGEINDEX, ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN); pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode); pNode->SetData(TFS_DATA_USER, (LPARAM) this); pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_MSCOPE_LEASES); pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE); SetColumnStringIDs(&aColumns[DHCPSNAP_MSCOPE_LEASES][0]); SetColumnWidths(&aColumnWidths[DHCPSNAP_MSCOPE_LEASES][0]); return hr; } /*--------------------------------------------------------------------------- CMScopeActiveLeases::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeActiveLeases::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strNode, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); // id string is server name, scope name and guid. strNode = GetServerName(pNode); strNode += GetScopeObject(pNode)->GetName() + strGuid; strId = strNode; return hrOK; } /*--------------------------------------------------------------------------- CMScopeActiveLeases::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CMScopeActiveLeases::GetImageIndex(BOOL bOpenImage) { int nIndex = -1; switch (m_nState) { case notLoaded: case loaded: if (bOpenImage) nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN; else nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED; break; case loading: if (bOpenImage) nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN_BUSY; else nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED_BUSY; break; case unableToLoad: if (bOpenImage) nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_OPEN_LOST_CONNECTION; else nIndex = ICON_IDX_ACTIVE_LEASES_FOLDER_CLOSED_LOST_CONNECTION; break; default: ASSERT(FALSE); } return nIndex; } /*--------------------------------------------------------------------------- Overridden base handler functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CMScopeActiveLeases::OnAddMenuItems Adds entries to the context sensitive menu Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CMScopeActiveLeases::OnAddMenuItems ( ITFSNode * pNode, LPCONTEXTMENUCALLBACK pContextMenuCallback, LPDATAOBJECT lpDataObject, DATA_OBJECT_TYPES type, DWORD dwType, long * pInsertionAllowed ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); LONG fFlags = 0; HRESULT hr = S_OK; CString strMenuText; if ( (m_nState != loaded) ) { fFlags |= MF_GRAYED; } if (type == CCT_SCOPE) { } return hr; } /*--------------------------------------------------------------------------- CMScopeActiveLeases::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CMScopeActiveLeases::OnCommand ( ITFSNode * pNode, long nCommandId, DATA_OBJECT_TYPES type, LPDATAOBJECT pDataObject, DWORD dwType ) { HRESULT hr = S_OK; switch (nCommandId) { case IDS_REFRESH: OnRefresh(pNode, pDataObject, dwType, 0, 0); break; default: break; } return hr; } /*--------------------------------------------------------------------------- CMScopeActiveLeases::OnResultDelete This function is called when we are supposed to delete result pane items. We build a list of selected items and then delete them. Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeActiveLeases::OnResultDelete ( ITFSComponent * pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM param ) { HRESULT hr = hrOK; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // translate the cookie into a node pointer SPITFSNode spActiveLeases, spSelectedNode; m_spNodeMgr->FindNode(cookie, &spActiveLeases); pComponent->GetSelectedNode(&spSelectedNode); Assert(spSelectedNode == spActiveLeases); if (spSelectedNode != spActiveLeases) return hr; // build the list of selected nodes CTFSNodeList listNodesToDelete; hr = BuildSelectedItemList(pComponent, &listNodesToDelete); // // Confirm with the user // CString strMessage, strTemp; int nNodes = (int)listNodesToDelete.GetCount(); if (nNodes > 1) { strTemp.Format(_T("%d"), nNodes); AfxFormatString1(strMessage, IDS_DELETE_ITEMS, (LPCTSTR) strTemp); } else { strMessage.LoadString(IDS_DELETE_ITEM); } if (AfxMessageBox(strMessage, MB_YESNO) == IDNO) { return NOERROR; } // // Loop through all items deleting // BEGIN_WAIT_CURSOR; while (listNodesToDelete.GetCount() > 0) { SPITFSNode spActiveLeaseNode; spActiveLeaseNode = listNodesToDelete.RemoveHead(); CDhcpMCastLease * pActiveLease = GETHANDLER(CDhcpMCastLease, spActiveLeaseNode); // // delete the node, check to see if it is a reservation // DWORD dwError = GetScopeObject(spActiveLeases)->DeleteClient(pActiveLease->GetIpAddress()); if (dwError == ERROR_SUCCESS) { // // Client gone, now remove from UI // spActiveLeases->RemoveChild(spActiveLeaseNode); } else { ::DhcpMessageBox(dwError); RESTORE_WAIT_CURSOR; Trace1("DeleteClient failed %lx\n", dwError); hr = E_FAIL; } spActiveLeaseNode.Release(); } END_WAIT_CURSOR; return hr; } /*!-------------------------------------------------------------------------- CMScopeActiveLeases::OnGetResultViewType MMC calls this to get the result view information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeActiveLeases::OnGetResultViewType ( ITFSComponent * pComponent, MMC_COOKIE cookie, LPOLESTR * ppViewType, long * pViewOptions ) { *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT; // we still want the default MMC result pane view, we just want // multiselect, so return S_FALSE return S_FALSE; } /*--------------------------------------------------------------------------- CMScopeActiveLeases::CompareItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(int) CMScopeActiveLeases::CompareItems ( ITFSComponent * pComponent, MMC_COOKIE cookieA, MMC_COOKIE cookieB, int nCol ) { SPITFSNode spNode1, spNode2; m_spNodeMgr->FindNode(cookieA, &spNode1); m_spNodeMgr->FindNode(cookieB, &spNode2); int nCompare = 0; CDhcpMCastLease *pDhcpAL1 = GETHANDLER(CDhcpMCastLease, spNode1); CDhcpMCastLease *pDhcpAL2 = GETHANDLER(CDhcpMCastLease, spNode2); switch (nCol) { case 0: { // IP address compare // nCompare = CompareIpAddresses(pDhcpAL1, pDhcpAL2); } break; case 1: { // Client Name compare // CString strAL1 = pDhcpAL1->GetString(pComponent, cookieA, nCol); CString strAL2 = pDhcpAL2->GetString(pComponent, cookieA, nCol); // Compare should not be case sensitive // nCompare = strAL1.CompareNoCase(strAL2); } break; case 2: { // Lease start compare // CTime timeAL1, timeAL2; pDhcpAL1->GetLeaseStartTime(timeAL1); pDhcpAL2->GetLeaseStartTime(timeAL2); if (timeAL1 < timeAL2) nCompare = -1; else if (timeAL1 > timeAL2) nCompare = 1; } break; case 3: { // Lease expiration compare // CTime timeAL1, timeAL2; pDhcpAL1->GetLeaseExpirationTime(timeAL1); pDhcpAL2->GetLeaseExpirationTime(timeAL2); if (timeAL1 < timeAL2) nCompare = -1; else if (timeAL1 > timeAL2) nCompare = 1; } break; case 4: { CString strClientId1 = pDhcpAL1->GetClientId(); nCompare = strClientId1.CompareNoCase(pDhcpAL2->GetClientId()); } break; } return nCompare; } /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ int CMScopeActiveLeases::CompareIpAddresses ( CDhcpMCastLease * pDhcpAL1, CDhcpMCastLease * pDhcpAL2 ) { int nCompare = 0; DHCP_IP_ADDRESS dhcpIp1 = pDhcpAL1->GetIpAddress(); DHCP_IP_ADDRESS dhcpIp2 = pDhcpAL2->GetIpAddress(); if (dhcpIp1 < dhcpIp2) nCompare = -1; else if (dhcpIp1 > dhcpIp2) nCompare = 1; return nCompare; } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CMScopeActiveLeases::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CMScopeActiveLeases::OnCreateQuery(ITFSNode * pNode) { CMScopeActiveLeasesQueryObj* pQuery = new CMScopeActiveLeasesQueryObj(m_spTFSCompData, m_spNodeMgr); if ( pQuery == NULL ) return pQuery; pQuery->m_strServer = GetServerIpAddress(pNode); pQuery->m_dhcpResumeHandle = NULL; pQuery->m_dwPreferredMax = 200; CDhcpMScope * pScope = GetScopeObject(pNode); if (pScope) pQuery->m_strName = pScope->GetName(); else Panic0("no scope in MScopeActiveLease::OnCreateQuery!"); GetServerVersion(pNode, pQuery->m_liDhcpVersion); return pQuery; } /*--------------------------------------------------------------------------- CMScopeActiveLeasesQueryObj::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CMScopeActiveLeasesQueryObj::Execute() { HRESULT hr = hrOK; hr = EnumerateLeases(); return hr; } /*--------------------------------------------------------------------------- CMScopeActiveLeasesQueryObj::EnumerateLeases() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeActiveLeasesQueryObj::EnumerateLeases() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_MCLIENT_INFO_ARRAY pdhcpClientArray = NULL; DWORD dwClientsRead = 0, dwClientsTotal = 0; DWORD dwEnumedClients = 0; while (dwError == ERROR_MORE_DATA) { if (m_strName.IsEmpty()) Panic0("CMScopeActiveLeasesQueryObj::EnumerateLeases() - m_strName is empty!!"); dwError = ::DhcpEnumMScopeClients(((LPWSTR) (LPCTSTR)m_strServer), (LPWSTR) ((LPCTSTR) m_strName), &m_dhcpResumeHandle, m_dwPreferredMax, &pdhcpClientArray, &dwClientsRead, &dwClientsTotal); if (dwClientsRead && pdhcpClientArray) { // // loop through all of the elements that were returned // for (DWORD i = 0; i < pdhcpClientArray->NumElements; i++) { CDhcpMCastLease * pDhcpMCastLease; // // Create the result pane item for this element // SPITFSNode spNode; pDhcpMCastLease = new CDhcpMCastLease(m_spTFSCompData); CreateLeafTFSNode(&spNode, &GUID_DhcpMCastLeaseNodeType, pDhcpMCastLease, pDhcpMCastLease, m_spNodeMgr); // Tell the handler to initialize any specific data pDhcpMCastLease->InitMCastInfo(pdhcpClientArray->Clients[i]); pDhcpMCastLease->InitializeNode(spNode); AddToQueue(spNode); pDhcpMCastLease->Release(); } ::DhcpRpcFreeMemory(pdhcpClientArray); dwEnumedClients += dwClientsRead; dwClientsRead = 0; dwClientsTotal = 0; pdhcpClientArray = NULL; } // Check the abort flag on the thread if (FCheckForAbort() == hrOK) break; // check to see if we have an error and post it to the main thread if we do.. if (dwError != ERROR_NO_MORE_ITEMS && dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA) { Trace1("DHCP snapin: EnumerateLeases error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } Trace1("DHCP snpain: Leases enumerated: %d\n", dwEnumedClients); return hrFalse; } /*--------------------------------------------------------------------------- Class CMScopeAddressPool implementation ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ CMScopeAddressPool::CMScopeAddressPool ( ITFSComponentData * pComponentData ) : CMTDhcpHandler(pComponentData) { } CMScopeAddressPool::~CMScopeAddressPool() { } /*!-------------------------------------------------------------------------- CMScopeAddressPool::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeAddressPool::InitializeNode ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = hrOK; // // Create the display name for this scope // CString strTemp; strTemp.LoadString(IDS_ADDRESS_POOL_FOLDER); SetDisplayName(strTemp); // Make the node immediately visible pNode->SetVisibilityState(TFS_VIS_SHOW); pNode->SetData(TFS_DATA_IMAGEINDEX, ICON_IDX_ADDR_POOL_FOLDER_CLOSED); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, ICON_IDX_ADDR_POOL_FOLDER_OPEN); pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode); pNode->SetData(TFS_DATA_USER, (LPARAM) this); pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_ADDRESS_POOL); pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE); SetColumnStringIDs(&aColumns[DHCPSNAP_ADDRESS_POOL][0]); SetColumnWidths(&aColumnWidths[DHCPSNAP_ADDRESS_POOL][0]); return hr; } /*--------------------------------------------------------------------------- CMScopeAddressPool::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeAddressPool::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strNode, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); // id string is server name, scope name and guid. strNode = GetServerName(pNode); strNode += GetScopeObject(pNode)->GetName() + strGuid; strId = strNode; return hrOK; } /*--------------------------------------------------------------------------- CMScopeAddressPool::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CMScopeAddressPool::GetImageIndex(BOOL bOpenImage) { int nIndex = -1; switch (m_nState) { case notLoaded: case loaded: if (bOpenImage) nIndex = ICON_IDX_ADDR_POOL_FOLDER_OPEN; else nIndex = ICON_IDX_ADDR_POOL_FOLDER_CLOSED; break; case loading: if (bOpenImage) nIndex = ICON_IDX_ADDR_POOL_FOLDER_OPEN_BUSY; else nIndex = ICON_IDX_ADDR_POOL_FOLDER_CLOSED_BUSY; break; case unableToLoad: if (bOpenImage) nIndex = ICON_IDX_ADDR_POOL_FOLDER_OPEN_LOST_CONNECTION; else nIndex = ICON_IDX_ADDR_POOL_FOLDER_CLOSED_LOST_CONNECTION; break; default: ASSERT(FALSE); } return nIndex; } /*--------------------------------------------------------------------------- Overridden base handler functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CMScopeAddressPool::OnAddMenuItems Adds entries to the context sensitive menu Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CMScopeAddressPool::OnAddMenuItems ( ITFSNode * pNode, LPCONTEXTMENUCALLBACK pContextMenuCallback, LPDATAOBJECT lpDataObject, DATA_OBJECT_TYPES type, DWORD dwType, long * pInsertionAllowed ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); LONG fFlags = 0; HRESULT hr = S_OK; CString strMenuText; if ( (m_nState != loaded) ) { fFlags |= MF_GRAYED; } if (type == CCT_SCOPE) { // these menu items go in the new menu, // only visible from scope pane if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) { strMenuText.LoadString(IDS_CREATE_NEW_EXCLUSION); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_CREATE_NEW_EXCLUSION, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); } } return hr; } /*--------------------------------------------------------------------------- CMScopeAddressPool::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CMScopeAddressPool::OnCommand ( ITFSNode * pNode, long nCommandId, DATA_OBJECT_TYPES type, LPDATAOBJECT pDataObject, DWORD dwType ) { HRESULT hr = S_OK; switch (nCommandId) { case IDS_CREATE_NEW_EXCLUSION: OnCreateNewExclusion(pNode); break; case IDS_REFRESH: OnRefresh(pNode, pDataObject, dwType, 0, 0); break; default: break; } return hr; } /*--------------------------------------------------------------------------- Message handlers ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CMScopeAddressPool::OnCreateNewExclusion Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CMScopeAddressPool::OnCreateNewExclusion ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); SPITFSNode spScopeNode; pNode->GetParent(&spScopeNode); CAddExclusion dlgAddExclusion(spScopeNode, TRUE /* multicast */); dlgAddExclusion.DoModal(); return 0; } /*--------------------------------------------------------------------------- CMScopeAddressPool::OnResultDelete This function is called when we are supposed to delete result pane items. We build a list of selected items and then delete them. Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeAddressPool::OnResultDelete ( ITFSComponent * pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam ) { HRESULT hr = NOERROR; BOOL bIsRes, bIsActive, bBadAddress; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // translate the cookie into a node pointer SPITFSNode spAddressPool, spSelectedNode; m_spNodeMgr->FindNode(cookie, &spAddressPool); pComponent->GetSelectedNode(&spSelectedNode); Assert(spSelectedNode == spAddressPool); if (spSelectedNode != spAddressPool) return hr; // build the list of selected nodes CTFSNodeList listNodesToDelete; hr = BuildSelectedItemList(pComponent, &listNodesToDelete); // // Confirm with the user // CString strMessage, strTemp; int nNodes = (int)listNodesToDelete.GetCount(); if (nNodes > 1) { strTemp.Format(_T("%d"), nNodes); AfxFormatString1(strMessage, IDS_DELETE_ITEMS, (LPCTSTR) strTemp); } else { strMessage.LoadString(IDS_DELETE_ITEM); } if (AfxMessageBox(strMessage, MB_YESNO) == IDNO) { return NOERROR; } // // Loop through all items deleting // BEGIN_WAIT_CURSOR; while (listNodesToDelete.GetCount() > 0) { SPITFSNode spExclusionRangeNode; spExclusionRangeNode = listNodesToDelete.RemoveHead(); CDhcpExclusionRange * pExclusion = GETHANDLER(CDhcpExclusionRange, spExclusionRangeNode); if (spExclusionRangeNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ALLOCATION_RANGE) { // // This is the allocation range, can't delete // AfxMessageBox(IDS_CANNOT_DELETE_ALLOCATION_RANGE); spExclusionRangeNode.Release(); continue; } // // Try to remove it from the server // CDhcpIpRange dhcpIpRange((DHCP_IP_RANGE) *pExclusion); DWORD dwError = GetScopeObject(spAddressPool)->RemoveExclusion(dhcpIpRange); if (dwError != 0) { ::DhcpMessageBox(dwError); RESTORE_WAIT_CURSOR; hr = E_FAIL; continue; } // // Remove from UI now // spAddressPool->RemoveChild(spExclusionRangeNode); spExclusionRangeNode.Release(); } END_WAIT_CURSOR; return hr; } /*!-------------------------------------------------------------------------- CMScopeAddressPool::OnGetResultViewType MMC calls this to get the result view information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeAddressPool::OnGetResultViewType ( ITFSComponent * pComponent, MMC_COOKIE cookie, LPOLESTR * ppViewType, long * pViewOptions ) { *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT; // we still want the default MMC result pane view, we just want // multiselect, so return S_FALSE return S_FALSE; } /*--------------------------------------------------------------------------- CMScopeAddressPool::CompareItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(int) CMScopeAddressPool::CompareItems ( ITFSComponent * pComponent, MMC_COOKIE cookieA, MMC_COOKIE cookieB, int nCol ) { SPITFSNode spNode1, spNode2; m_spNodeMgr->FindNode(cookieA, &spNode1); m_spNodeMgr->FindNode(cookieB, &spNode2); int nCompare = 0; CDhcpAllocationRange *pDhcpAR1 = GETHANDLER(CDhcpAllocationRange, spNode1); CDhcpAllocationRange *pDhcpAR2 = GETHANDLER(CDhcpAllocationRange, spNode2); switch (nCol) { case 0: { // Start IP address compare // DHCP_IP_ADDRESS dhcpIp1 = pDhcpAR1->QueryAddr(TRUE); DHCP_IP_ADDRESS dhcpIp2 = pDhcpAR2->QueryAddr(TRUE); if (dhcpIp1 < dhcpIp2) nCompare = -1; else if (dhcpIp1 > dhcpIp2) nCompare = 1; // default is that they are equal } break; case 1: { // End IP address compare // DHCP_IP_ADDRESS dhcpIp1 = pDhcpAR1->QueryAddr(FALSE); DHCP_IP_ADDRESS dhcpIp2 = pDhcpAR2->QueryAddr(FALSE); if (dhcpIp1 < dhcpIp2) nCompare = -1; else if (dhcpIp1 > dhcpIp2) nCompare = 1; // default is that they are equal } break; case 2: { // Description compare // CString strRange1 = pDhcpAR1->GetString(pComponent, cookieA, nCol); CString strRange2 = pDhcpAR2->GetString(pComponent, cookieA, nCol); // Compare should not be case sensitive // strRange1.MakeUpper(); strRange2.MakeUpper(); nCompare = strRange1.Compare(strRange2); } break; } return nCompare; } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CMScopeAddressPool::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CMScopeAddressPool::OnCreateQuery(ITFSNode * pNode) { CMScopeAddressPoolQueryObj* pQuery = new CMScopeAddressPoolQueryObj(m_spTFSCompData, m_spNodeMgr); if ( pQuery == NULL ) return pQuery; pQuery->m_strServer = GetServerIpAddress(pNode); CDhcpMScope * pScope = GetScopeObject(pNode); if (pScope) pQuery->m_strName = pScope->GetName(); pQuery->m_dhcpExclResumeHandle = NULL; pQuery->m_dwExclPreferredMax = 0xFFFFFFFF; pQuery->m_dhcpIpResumeHandle = NULL; pQuery->m_dwIpPreferredMax = 0xFFFFFFFF; return pQuery; } /*--------------------------------------------------------------------------- CMScopeAddressPoolQueryObj::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CMScopeAddressPoolQueryObj::Execute() { HRESULT hr1 = EnumerateIpRanges(); HRESULT hr2 = EnumerateExcludedIpRanges(); if (hr1 == hrOK || hr2 == hrOK) return hrOK; else return hrFalse; } /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeAddressPoolQueryObj::EnumerateExcludedIpRanges() { DWORD dwError = ERROR_MORE_DATA; DHCP_RESUME_HANDLE dhcpResumeHandle = 0; LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 pdhcpSubnetElementArray = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumMScopeElements((LPWSTR) ((LPCTSTR) m_strServer), (LPWSTR) ((LPCTSTR) m_strName), DhcpExcludedIpRanges, &m_dhcpExclResumeHandle, m_dwExclPreferredMax, &pdhcpSubnetElementArray, &dwElementsRead, &dwElementsTotal); Trace3("Scope %s Excluded Ip Ranges read %d, total %d\n", m_strName, dwElementsRead, dwElementsTotal); if (dwElementsRead && dwElementsTotal && pdhcpSubnetElementArray) { // // loop through all of the elements that were returned // for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++) { // // Create the result pane item for this element // SPITFSNode spNode; CDhcpExclusionRange * pDhcpExclusionRange = new CDhcpExclusionRange(m_spTFSCompData, pdhcpSubnetElementArray->Elements[i].Element.ExcludeIpRange); CreateLeafTFSNode(&spNode, &GUID_DhcpExclusionNodeType, pDhcpExclusionRange, pDhcpExclusionRange, m_spNodeMgr); // Tell the handler to initialize any specific data pDhcpExclusionRange->InitializeNode(spNode); AddToQueue(spNode); pDhcpExclusionRange->Release(); } // Free up the memory from the RPC call // ::DhcpRpcFreeMemory(pdhcpSubnetElementArray); } // Check the abort flag on the thread if (FCheckForAbort() == hrOK) break; // check to see if we have an error and post it to the main thread if we do.. if (dwError != ERROR_NO_MORE_ITEMS && dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA) { Trace1("DHCP snapin: EnumerateExcludedIpRanges error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } return hrFalse; } /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CMScopeAddressPoolQueryObj::EnumerateIpRanges() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 pdhcpSubnetElementArray = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumMScopeElements((LPWSTR) ((LPCTSTR) m_strServer), (LPWSTR) ((LPCTSTR) m_strName), DhcpIpRanges, &m_dhcpIpResumeHandle, m_dwIpPreferredMax, &pdhcpSubnetElementArray, &dwElementsRead, &dwElementsTotal); Trace4("Scope %s allocation ranges read %d, total %d, dwError = %lx\n", m_strName, dwElementsRead, dwElementsTotal, dwError); if ((dwError == ERROR_MORE_DATA) || ( (dwElementsRead) && (dwError == ERROR_SUCCESS) )) { // // Loop through the array that was returned // for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++) { // // Create the result pane item for this element // SPITFSNode spNode; CDhcpAllocationRange * pDhcpAllocRange = new CDhcpAllocationRange(m_spTFSCompData, pdhcpSubnetElementArray->Elements[i].Element.IpRange); CreateLeafTFSNode(&spNode, &GUID_DhcpAllocationNodeType, pDhcpAllocRange, pDhcpAllocRange, m_spNodeMgr); // Tell the handler to initialize any specific data pDhcpAllocRange->InitializeNode(spNode); AddToQueue(spNode); pDhcpAllocRange->Release(); } ::DhcpRpcFreeMemory(pdhcpSubnetElementArray); } else if (dwError != ERROR_SUCCESS && dwError != ERROR_NO_MORE_ITEMS) { // set the error variable so that it can be looked at later m_dwError = dwError; } // Check the abort flag on the thread if (FCheckForAbort() == hrOK) break; // check to see if we have an error and post it to the main thread if we do.. if (dwError != ERROR_NO_MORE_ITEMS && dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA) { Trace1("DHCP snapin: EnumerateAllocationRanges error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } return hrFalse; }