/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/ /* scope.cpp This file contains all of the implementation for the DHCP scope object and all objects that it may contain. They include: CDhcpScope CDhcpReservations CDhcpReservationClient CDhcpActiveLeases CDhcpAddressPool CDhcpScopeOptions FILE HISTORY: */ #include "stdafx.h" #include "server.h" // server object #include "scope.h" // scope object #include "scopepp.h" // scope property page #include "addbootp.h" // add BOOTP entry dialog #include "addexcl.h" // add exclusion range dialog #include "addres.h" // add reservation dialog #include "rclntpp.h" // reserved client property page #include "nodes.h" // all node (result pane) definitions #include "optcfg.h" // option configuration sheet #include "dlgrecon.h" // reconcile database dialog #include "scopstat.h" // scope statistics #include "addtoss.h" // add scope to superscope dialog WORD gwUnicodeHeader = 0xFEFF; // scope options result pane message stuff #define SCOPE_OPTIONS_MESSAGE_MAX_STRING 5 typedef enum _SCOPE_OPTIONS_MESSAGES { SCOPE_OPTIONS_MESSAGE_NO_OPTIONS, SCOPE_OPTIONS_MESSAGE_MAX }; UINT g_uScopeOptionsMessages[SCOPE_OPTIONS_MESSAGE_MAX][SCOPE_OPTIONS_MESSAGE_MAX_STRING] = { {IDS_SCOPE_OPTIONS_MESSAGE_TITLE, Icon_Information, IDS_SCOPE_OPTIONS_MESSAGE_BODY, 0, 0} }; // reservation options result pane message stuff #define RES_OPTIONS_MESSAGE_MAX_STRING 5 typedef enum _RES_OPTIONS_MESSAGES { RES_OPTIONS_MESSAGE_NO_OPTIONS, RES_OPTIONS_MESSAGE_MAX }; UINT g_uResOptionsMessages[RES_OPTIONS_MESSAGE_MAX][RES_OPTIONS_MESSAGE_MAX_STRING] = { {IDS_RES_OPTIONS_MESSAGE_TITLE, Icon_Information, IDS_RES_OPTIONS_MESSAGE_BODY, 0, 0} }; // reservations result pane message stuff #define RESERVATIONS_MESSAGE_MAX_STRING 5 typedef enum _RESERVATIONS_MESSAGES { RESERVATIONS_MESSAGE_NO_RES, RESERVATIONS_MESSAGE_MAX }; UINT g_uReservationsMessages[RESERVATIONS_MESSAGE_MAX][RESERVATIONS_MESSAGE_MAX_STRING] = { {IDS_RESERVATIONS_MESSAGE_TITLE, Icon_Information, IDS_RESERVATIONS_MESSAGE_BODY, 0, 0} }; /*--------------------------------------------------------------------------- Class CDhcpScope implementation ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpScope::CDhcpScope Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpScope::CDhcpScope ( ITFSComponentData * pComponentData, DHCP_IP_ADDRESS dhcpScopeIp, DHCP_IP_MASK dhcpSubnetMask, LPCWSTR pName, LPCWSTR pComment, DHCP_SUBNET_STATE dhcpSubnetState ) : CMTDhcpHandler(pComponentData) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // save off some parameters // m_dhcpIpAddress = dhcpScopeIp; m_dhcpSubnetMask = dhcpSubnetMask; m_strName = pName; m_strComment = pComment; m_dhcpSubnetState = dhcpSubnetState; m_bInSuperscope = FALSE; } /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpScope::CDhcpScope ( ITFSComponentData * pComponentData, LPDHCP_SUBNET_INFO pdhcpSubnetInfo ) : CMTDhcpHandler(pComponentData) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // save off some parameters // m_dhcpIpAddress = pdhcpSubnetInfo->SubnetAddress; m_dhcpSubnetMask = pdhcpSubnetInfo->SubnetMask; m_strName = pdhcpSubnetInfo->SubnetName; m_strComment = pdhcpSubnetInfo->SubnetComment; m_dhcpSubnetState = pdhcpSubnetInfo->SubnetState; m_bInSuperscope = FALSE; } /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpScope::CDhcpScope ( ITFSComponentData * pComponentData, CSubnetInfo & subnetInfo ) : CMTDhcpHandler(pComponentData) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // save off some parameters // m_dhcpIpAddress = subnetInfo.SubnetAddress; m_dhcpSubnetMask = subnetInfo.SubnetMask; m_strName = subnetInfo.SubnetName; m_strComment = subnetInfo.SubnetComment; m_dhcpSubnetState = subnetInfo.SubnetState; m_bInSuperscope = FALSE; } CDhcpScope::~CDhcpScope() { } /*!-------------------------------------------------------------------------- CDhcpScope::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::InitializeNode ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = hrOK; int nImage; // // Create the display name for this scope // CString strDisplay, strIpAddress; UtilCvtIpAddrToWstr (m_dhcpIpAddress, &strIpAddress); BuildDisplayName(&strDisplay, strIpAddress, m_strName); SetDisplayName(strDisplay); // // Figure out the correct icon // if ( !IsEnabled() ) { 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_IMAGEINDEX, GetImageIndex(FALSE)); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode); pNode->SetData(TFS_DATA_USER, (LPARAM) this); pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_SCOPE); SetColumnStringIDs(&aColumns[DHCPSNAP_SCOPE][0]); SetColumnWidths(&aColumnWidths[DHCPSNAP_SCOPE][0]); return hr; } /*--------------------------------------------------------------------------- CDhcpScope::DestroyHandler We need to free up any resources we are holding Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScope::DestroyHandler(ITFSNode *pNode) { // cleanup the stats dialog WaitForStatisticsWindow(&m_dlgStats); return CMTDhcpHandler::DestroyHandler(pNode); } /*--------------------------------------------------------------------------- CDhcpScope::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strIpAddress, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); UtilCvtIpAddrToWstr (m_dhcpIpAddress, &strIpAddress); strId = GetServerObject()->GetName() + strIpAddress + strGuid; return hrOK; } /*--------------------------------------------------------------------------- CDhcpScope::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CDhcpScope::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_SCOPE_FOLDER_OPEN_BUSY : ICON_IDX_SCOPE_FOLDER_OPEN_BUSY; else nIndex = (IsEnabled()) ? ICON_IDX_SCOPE_FOLDER_CLOSED_BUSY : ICON_IDX_SCOPE_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); } // only calcualte alert/warnings if the scope is enabled. if (m_spServerNode && IsEnabled()) { CDhcpServer * pServer = GetServerObject(); LPDHCP_MIB_INFO pMibInfo = pServer->DuplicateMibInfo(); if (!pMibInfo) return nIndex; LPSCOPE_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 (pScopeMibInfo[i].Subnet == m_dhcpIpAddress) { 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->FreeDupMibInfo(pMibInfo); } return nIndex; } /*--------------------------------------------------------------------------- Overridden base handler functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpScope::OnAddMenuItems Adds entries to the context sensitive menu Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScope::OnAddMenuItems ( ITFSNode * pNode, LPCONTEXTMENUCALLBACK pContextMenuCallback, LPDATAOBJECT lpDataObject, DATA_OBJECT_TYPES type, DWORD dwType, long * pInsertionAllowed ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Get the version of the server LONG fFlags = 0; LARGE_INTEGER liDhcpVersion; CDhcpServer * pServer = GetServerObject(); pServer->GetVersion(liDhcpVersion); 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_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 is only supports for NT4 SP2 and greater. if (liDhcpVersion.QuadPart >= DHCP_SP2_VERSION) { strMenuText.LoadString(IDS_SCOPE_RECONCILE); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_SCOPE_RECONCILE, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); } // Superscope support only on NT4 SP2 and greater if (liDhcpVersion.QuadPart >= DHCP_SP2_VERSION) { int nID = 0; if (IsInSuperscope()) { nID = IDS_SCOPE_REMOVE_SUPERSCOPE; } else { // check to see if there are superscopes to add to SPITFSNode spNode; pNode->GetParent(&spNode); pServer = GETHANDLER(CDhcpServer, spNode); if (pServer->HasSuperscopes(spNode)) nID = IDS_SCOPE_ADD_SUPERSCOPE; } // load the menu item if we need to if (nID) { strMenuText.LoadString(nID); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, nID, 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 ( !IsEnabled() ) { 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; } /*--------------------------------------------------------------------------- CDhcpScope::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScope::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; case IDS_SCOPE_ADD_SUPERSCOPE: OnAddToSuperscope(pNode); break; case IDS_SCOPE_REMOVE_SUPERSCOPE: OnRemoveFromSuperscope(pNode); break; default: break; } return hr; } /*!-------------------------------------------------------------------------- CDhcpScope::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 CDhcpScope::OnDelete ( ITFSNode * pNode, LPARAM arg, LPARAM lParam ) { return OnDelete(pNode); } /*!-------------------------------------------------------------------------- CDhcpScope::HasPropertyPages Says whether or not this handler has property pages Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScope::HasPropertyPages ( ITFSNode * pNode, LPDATAOBJECT pDataObject, DATA_OBJECT_TYPES type, DWORD dwType ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = hrOK; if (dwType & TFS_COMPDATA_CREATE) { // This is the case where we are asked to bring up property // pages when the user is adding a new snapin. These calls // are forwarded to the root node to handle. // Should never get here!! Assert(FALSE); hr = S_FALSE; } else { // we have property pages in the normal case hr = hrOK; } return hr; } /*--------------------------------------------------------------------------- CDhcpScope::CreatePropertyPages Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScope::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; CDhcpIpRange dhcpIpRange; // // Create the property page // m_spNodeMgr->GetComponentData(&spComponentData); CScopeProperties * pScopeProp = new CScopeProperties(pNode, spComponentData, m_spTFSCompData, NULL); // Get the Server version and set it in the property sheet pServer = GetServerObject(); pServer->GetVersion(liVersion); pScopeProp->SetVersion(liVersion); pScopeProp->SetSupportsDynBootp(pServer->FSupportsDynBootp()); // Set scope specific data in the prop sheet pScopeProp->m_pageGeneral.m_strName = m_strName; pScopeProp->m_pageGeneral.m_strComment = m_strComment; BEGIN_WAIT_CURSOR; dwError = GetIpRange(&dhcpIpRange); if (dwError != ERROR_SUCCESS) { ::DhcpMessageBox(dwError); return hrFalse; } pScopeProp->m_pageGeneral.m_dwStartAddress = dhcpIpRange.QueryAddr(TRUE); pScopeProp->m_pageGeneral.m_dwEndAddress = dhcpIpRange.QueryAddr(FALSE); pScopeProp->m_pageGeneral.m_dwSubnetMask = m_dhcpSubnetMask; pScopeProp->m_pageGeneral.m_uImage = GetImageIndex(FALSE); pScopeProp->m_pageAdvanced.m_RangeType = dhcpIpRange.GetRangeType(); GetLeaseTime(&pScopeProp->m_pageGeneral.m_dwLeaseTime); if (dwError != ERROR_SUCCESS) { ::DhcpMessageBox(dwError); return hrFalse; } if (pServer->FSupportsDynBootp()) { GetDynBootpLeaseTime(&pScopeProp->m_pageAdvanced.m_dwLeaseTime); if (dwError != ERROR_SUCCESS) { ::DhcpMessageBox(dwError); return hrFalse; } } // set the DNS registration option dwError = GetDnsRegistration(&dwDynDnsFlags); if (dwError != ERROR_SUCCESS) { ::DhcpMessageBox(dwError); return hrFalse; } END_WAIT_CURSOR; pScopeProp->SetDnsRegistration(dwDynDnsFlags, DhcpSubnetOptions); // // Object gets deleted when the page is destroyed // Assert(lpProvider != NULL); return pScopeProp->CreateModelessSheet(lpProvider, handle); } /*!-------------------------------------------------------------------------- CDhcpScope::GetString Returns string information for display in the result pane columns Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(LPCTSTR) CDhcpScope::GetString ( ITFSNode * pNode, int nCol ) { switch (nCol) { case 0: return GetDisplayName(); case 1: return m_strState; case 2: return m_strComment; } return NULL; } /*--------------------------------------------------------------------------- CDhcpScope::OnPropertyChange Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::OnPropertyChange ( ITFSNode * pNode, LPDATAOBJECT pDataobject, DWORD dwType, LPARAM arg, LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CScopeProperties * 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; } /*!-------------------------------------------------------------------------- CDhcpScope::OnUpdateToolbarButtons We override this function to show/hide the correct activate/deactivate buttons Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::OnUpdateToolbarButtons ( ITFSNode * pNode, LPDHCPTOOLBARNOTIFY pToolbarNotify ) { HRESULT hr = hrOK; if (pToolbarNotify->bSelect) { UpdateToolbarStates(); } CMTDhcpHandler::OnUpdateToolbarButtons(pNode, pToolbarNotify); return hr; } /*!-------------------------------------------------------------------------- CDhcpScope::UpdateToolbarStates Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScope::UpdateToolbarStates() { if ( !IsEnabled() ) { g_SnapinButtonStates[DHCPSNAP_SCOPE][TOOLBAR_IDX_ACTIVATE] = ENABLED; g_SnapinButtonStates[DHCPSNAP_SCOPE][TOOLBAR_IDX_DEACTIVATE] = HIDDEN; } else { g_SnapinButtonStates[DHCPSNAP_SCOPE][TOOLBAR_IDX_ACTIVATE] = HIDDEN; g_SnapinButtonStates[DHCPSNAP_SCOPE][TOOLBAR_IDX_DEACTIVATE] = ENABLED; } } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpScope:OnHaveData Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScope::OnHaveData ( ITFSNode * pParentNode, ITFSNode * pNewNode ) { if (pNewNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ACTIVE_LEASES) { pParentNode->AddChild(pNewNode); m_spActiveLeases.Set(pNewNode); } else if (pNewNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_ADDRESS_POOL) { pParentNode->AddChild(pNewNode); m_spAddressPool.Set(pNewNode); } else if (pNewNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_RESERVATIONS) { pParentNode->AddChild(pNewNode); m_spReservations.Set(pNewNode); } else if (pNewNode->GetData(TFS_DATA_TYPE) == DHCPSNAP_SCOPE_OPTIONS) { pParentNode->AddChild(pNewNode); m_spOptions.Set(pNewNode); } // now tell the view to update themselves ExpandNode(pParentNode, TRUE); } /*--------------------------------------------------------------------------- CDhcpScope::OnHaveData Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScope::OnHaveData ( ITFSNode * pParentNode, LPARAM Data, LPARAM Type ) { // This is how we get non-node data back from the background thread. switch (Type) { case DHCP_QDATA_SUBNET_INFO: { LONG_PTR changeMask = 0; LPDHCP_SUBNET_INFO pdhcpSubnetInfo = reinterpret_cast(Data); // update the scope name and state based on the info if (m_strName.CompareNoCase(pdhcpSubnetInfo->SubnetName) != 0) { CString strDisplay, strIpAddress; m_strName = pdhcpSubnetInfo->SubnetName; UtilCvtIpAddrToWstr (m_dhcpIpAddress, &strIpAddress); BuildDisplayName(&strDisplay, strIpAddress, m_strName); SetDisplayName(strDisplay); changeMask = SCOPE_PANE_CHANGE_ITEM; } if (m_dhcpSubnetState != pdhcpSubnetInfo->SubnetState) { DHCP_SUBNET_STATE dhcpOldState = m_dhcpSubnetState; m_dhcpSubnetState = pdhcpSubnetInfo->SubnetState; // Tell the scope to update it's state DWORD err = SetInfo(); if (err != 0) { ::DhcpMessageBox(err); m_dhcpSubnetState = dhcpOldState; } else { pParentNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE)); pParentNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); // Update the toolbar button UpdateToolbarStates(); SendUpdateToolbar(pParentNode, TRUE); // need to notify the owning superscope to update it's state information // this is strictly for UI purposes only. if (IsInSuperscope()) { SPITFSNode spSuperscopeNode; pParentNode->GetParent(&spSuperscopeNode); CDhcpSuperscope * pSuperscope = GETHANDLER(CDhcpSuperscope, spSuperscopeNode); Assert(pSuperscope); pSuperscope->NotifyScopeStateChange(spSuperscopeNode, m_dhcpSubnetState); } changeMask = SCOPE_PANE_CHANGE_ITEM; } } if (pdhcpSubnetInfo) ::DhcpRpcFreeMemory(pdhcpSubnetInfo); if (changeMask) VERIFY(SUCCEEDED(pParentNode->ChangeNode(changeMask))); } break; case DHCP_QDATA_OPTION_VALUES: { COptionValueEnum * pOptionValueEnum = reinterpret_cast(Data); SetOptionValueEnum(pOptionValueEnum); pOptionValueEnum->RemoveAll(); delete pOptionValueEnum; break; } default: break; } } /*--------------------------------------------------------------------------- CDhcpScope::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CDhcpScope::OnCreateQuery(ITFSNode * pNode) { CDhcpScopeQueryObj* pQuery = new CDhcpScopeQueryObj(m_spTFSCompData, m_spNodeMgr); pQuery->m_strServer = GetServerIpAddress(); pQuery->m_dhcpScopeAddress = GetAddress(); GetServerVersion(pQuery->m_liVersion); return pQuery; } /*--------------------------------------------------------------------------- CDhcpScope::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScopeQueryObj::Execute() { HRESULT hr = hrOK; DWORD dwReturn; LPDHCP_SUBNET_INFO pdhcpSubnetInfo = NULL; DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo; COptionValueEnum * pOptionValueEnum = NULL; dwReturn = ::DhcpGetSubnetInfo(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, &pdhcpSubnetInfo); if (dwReturn == ERROR_SUCCESS && pdhcpSubnetInfo) { AddToQueue((LPARAM) pdhcpSubnetInfo, DHCP_QDATA_SUBNET_INFO); } else { Trace1("CDhcpScopeQueryObj::Execute - DhcpGetSubnetInfo failed! %d\n", dwReturn); PostError(dwReturn); return hrFalse; } // get the option info for this scope pOptionValueEnum = new COptionValueEnum(); dhcpOptionScopeInfo.ScopeType = DhcpSubnetOptions; dhcpOptionScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpScopeAddress; pOptionValueEnum->Init(m_strServer, m_liVersion, dhcpOptionScopeInfo); dwReturn = pOptionValueEnum->Enum(); if (dwReturn != ERROR_SUCCESS) { Trace1("CDhcpScopeQueryObj::Execute - EnumOptions Failed! %d\n", dwReturn); m_dwErr = dwReturn; PostError(dwReturn); delete pOptionValueEnum; } else { pOptionValueEnum->SortById(); AddToQueue((LPARAM) pOptionValueEnum, DHCP_QDATA_OPTION_VALUES); } // now create the scope subcontainers CreateSubcontainers(); return hrFalse; } /*--------------------------------------------------------------------------- CDhcpScope::CreateSubcontainers() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeQueryObj::CreateSubcontainers() { HRESULT hr = hrOK; SPITFSNode spNode; // // create the address pool Handler // CDhcpAddressPool *pAddressPool = new CDhcpAddressPool(m_spTFSCompData); CreateContainerTFSNode(&spNode, &GUID_DhcpAddressPoolNodeType, 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 // CDhcpActiveLeases *pActiveLeases = new CDhcpActiveLeases(m_spTFSCompData); CreateContainerTFSNode(&spNode, &GUID_DhcpActiveLeasesNodeType, 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(); spNode.Set(NULL); // // create the reservations Handler // CDhcpReservations *pReservations = new CDhcpReservations(m_spTFSCompData); CreateContainerTFSNode(&spNode, &GUID_DhcpReservationsNodeType, pReservations, pReservations, m_spNodeMgr); // Tell the handler to initialize any specific data pReservations->InitializeNode((ITFSNode *) spNode); // Add the node as a child to this node AddToQueue(spNode); pReservations->Release(); spNode.Set(NULL); // // create the Scope Options Handler // CDhcpScopeOptions *pScopeOptions = new CDhcpScopeOptions(m_spTFSCompData); CreateContainerTFSNode(&spNode, &GUID_DhcpScopeOptionsNodeType, pScopeOptions, pScopeOptions, m_spNodeMgr); // Tell the handler to initialize any specific data pScopeOptions->InitializeNode((ITFSNode *) spNode); // Add the node as a child to this node AddToQueue(spNode); pScopeOptions->Release(); return hr; } /*--------------------------------------------------------------------------- Command handlers ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpScope::OnActivateScope Message handler for the scope activate/deactivate menu Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::OnActivateScope ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); DWORD err = 0; int nOpenImage, nClosedImage; DHCP_SUBNET_STATE dhcpOldState = m_dhcpSubnetState; if ( IsEnabled() ) { // if they want to disable the scope, confirm if (AfxMessageBox(IDS_SCOPE_DISABLE_CONFIRM, MB_YESNO) != IDYES) { return err; } } SetState( IsEnabled()? DhcpSubnetDisabled : DhcpSubnetEnabled ); // Tell the scope to update it's state err = SetInfo(); if (err != 0) { ::DhcpMessageBox(err); m_dhcpSubnetState = dhcpOldState; } else { // update the icon and the status text if ( !IsEnabled() ) { 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); // need to notify the owning superscope to update it's state information // this is strictly for UI purposes only. if (IsInSuperscope()) { SPITFSNode spSuperscopeNode; pNode->GetParent(&spSuperscopeNode); CDhcpSuperscope * pSuperscope = GETHANDLER(CDhcpSuperscope, spSuperscopeNode); Assert(pSuperscope); pSuperscope->NotifyScopeStateChange(spSuperscopeNode, m_dhcpSubnetState); } } TriggerStatsRefresh(); return err; } /*--------------------------------------------------------------------------- CDhcpScope::OnRefreshScope Refreshes all of the subnodes of the scope Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::OnRefreshScope ( ITFSNode * pNode, LPDATAOBJECT pDataObject, DWORD dwType ) { HRESULT hr = hrOK; CDhcpReservations * pReservations = GetReservationsObject(); CDhcpActiveLeases * pActiveLeases = GetActiveLeasesObject(); CDhcpAddressPool * pAddressPool = GetAddressPoolObject(); CDhcpScopeOptions * pScopeOptions = GetScopeOptionsObject(); Assert(pReservations); Assert(pActiveLeases); Assert(pAddressPool); Assert(pScopeOptions); if (pReservations) pReservations->OnRefresh(m_spReservations, pDataObject, dwType, 0, 0); if (pActiveLeases) pActiveLeases->OnRefresh(m_spActiveLeases, pDataObject, dwType, 0, 0); if (pAddressPool) pAddressPool->OnRefresh(m_spAddressPool, pDataObject, dwType, 0, 0); if (pScopeOptions) pScopeOptions->OnRefresh(m_spOptions, pDataObject, dwType, 0, 0); return hr; } /*--------------------------------------------------------------------------- CDhcpScope::OnReconcileScope Reconciles the active leases database for this scope Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::OnReconcileScope ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CReconcileDlg dlgRecon(pNode); dlgRecon.DoModal(); return hrOK; } /*--------------------------------------------------------------------------- CDhcpScope::OnShowScopeStats() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::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.SetScope(m_dhcpIpAddress); CreateNewStatisticsWindow(&m_dlgStats, ::FindMMCMainWindow(), IDD_STATS_NARROW); return hr; } /*--------------------------------------------------------------------------- CDhcpScope::OnDelete() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::OnDelete(ITFSNode * pNode) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = S_OK; SPITFSNode spServer; SPITFSNode spSuperscopeNode; int nVisible = 0, nTotal = 0; int nResponse; LONG err = 0 ; if (IsInSuperscope()) { pNode->GetParent(&spSuperscopeNode); spSuperscopeNode->GetChildCount(&nVisible, &nTotal); } if (nTotal == 1) { // warn the user that this is the last scope in the superscope // and the superscope will be removed. nResponse = AfxMessageBox(IDS_DELETE_LAST_SCOPE_FROM_SS, MB_YESNO); } else { nResponse = ::DhcpMessageBox( IsEnabled() ? IDS_MSG_DELETE_ACTIVE : IDS_MSG_DELETE_SCOPE, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION); } if (nResponse == IDYES) { SPITFSNode spTemp; if (IsInSuperscope()) { // superscope spTemp.Set(spSuperscopeNode); } else { spTemp.Set(pNode); } spTemp->GetParent(&spServer); CDhcpServer * pServer = GETHANDLER(CDhcpServer, spServer); err = pServer->DeleteScope(pNode); if (err == ERROR_SUCCESS && nTotal == 1) { // gotta remove the superscope spServer->RemoveChild(spSuperscopeNode); } } // trigger the statistics to refresh only if we removed this scope if (spServer) { TriggerStatsRefresh(); } return hr; } /*--------------------------------------------------------------------------- CDhcpScope::OnAddToSuperscope() Adds this scope to a superscope Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::OnAddToSuperscope ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CString strTitle, strAddress; UtilCvtIpAddrToWstr(m_dhcpIpAddress, &strAddress); AfxFormatString1(strTitle, IDS_ADD_SCOPE_DLG_TITLE, strAddress); CAddScopeToSuperscope dlgAddScope(pNode, strTitle); dlgAddScope.DoModal(); return hrOK; } /*--------------------------------------------------------------------------- CDhcpScope::OnRemoveFromSuperscope() Removes this scope from a superscope Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::OnRemoveFromSuperscope ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); int nVisible, nTotal, nResponse; SPITFSNode spSuperscopeNode; pNode->GetParent(&spSuperscopeNode); spSuperscopeNode->GetChildCount(&nVisible, &nTotal); if (nTotal == 1) { // warn the user that this is the last scope in the superscope // and the superscope will be removed. nResponse = AfxMessageBox(IDS_REMOVE_LAST_SCOPE_FROM_SS, MB_YESNO); } else { nResponse = AfxMessageBox(IDS_REMOVE_SCOPE_FROM_SS, MB_YESNO); } if (nResponse == IDYES) { // set the superscope for this scope to be NULL // effectively removing it from the scope. DWORD dwError = SetSuperscope(NULL, TRUE); if (dwError != ERROR_SUCCESS) { ::DhcpMessageBox(dwError); return hrFalse; } // now move the scope out of the supersope in the UI spSuperscopeNode->ExtractChild(pNode); // now put the scope node back in at the server level. SPITFSNode spServerNode; spSuperscopeNode->GetParent(&spServerNode); CDhcpServer * pServer = GETHANDLER(CDhcpServer, spServerNode); pServer->AddScopeSorted(spServerNode, pNode); SetInSuperscope(FALSE); if (nTotal == 1) { // now delete the superscope. spServerNode->RemoveChild(spSuperscopeNode); } } return hrOK; } /*--------------------------------------------------------------------------- CDhcpScope::UpdateStatistics Notification that stats are now available. Update stats for the node and give all subnodes a chance to update. Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::UpdateStatistics ( ITFSNode * pNode ) { HRESULT hr = hrOK; SPITFSNodeEnum spNodeEnum; SPITFSNode spCurrentNode; ULONG nNumReturned; HWND hStatsWnd; BOOL bChangeIcon = FALSE; // Check to see if this node has a stats sheet up. hStatsWnd = m_dlgStats.GetSafeHwnd(); if (hStatsWnd != NULL) { PostMessage(hStatsWnd, WM_NEW_STATS_AVAILABLE, 0, 0); } if (!IsEnabled()) return hr; // check to see if the image index has changed and only // switch it if we have to--this avoids flickering. LONG_PTR nOldIndex = pNode->GetData(TFS_DATA_IMAGEINDEX); int nNewIndex = GetImageIndex(FALSE); if (nOldIndex != nNewIndex) { pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE)); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); pNode->ChangeNode(SCOPE_PANE_CHANGE_ITEM_ICON); } return hr; } /*--------------------------------------------------------------------------- Scope manipulation functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpScope::SetState Sets the state for this scope - updates cached information and display string Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScope::SetState ( DHCP_SUBNET_STATE dhcpSubnetState ) { BOOL fSwitched = FALSE; if( m_dhcpSubnetState != DhcpSubnetEnabled && m_dhcpSubnetState != DhcpSubnetDisabled ) { fSwitched = TRUE; } if( fSwitched ) { if( dhcpSubnetState == DhcpSubnetEnabled ) { dhcpSubnetState = DhcpSubnetEnabledSwitched; } else { dhcpSubnetState = DhcpSubnetDisabledSwitched; } } m_dhcpSubnetState = dhcpSubnetState; // update the status text if ( !IsEnabled() ) { m_strState.LoadString(IDS_SCOPE_INACTIVE); } else { m_strState.LoadString(IDS_SCOPE_ACTIVE); } } /*--------------------------------------------------------------------------- CDhcpScope::CreateReservation Creates a reservation for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::CreateReservation ( const CDhcpClient * pClient ) { SPITFSNode spResClientNode, spActiveLeaseNode; DWORD err = 0; // // Tell the DHCP server to create this client // err = CreateClient(pClient); if (err != 0) return err; // // Now that we have this reservation on the server, create the UI object // in both the reservation folder and the ActiveLeases folder // // create the Reservation client folder // CDhcpReservations * pRes = GETHANDLER(CDhcpReservations, m_spReservations); CDhcpActiveLeases * pActLeases = GETHANDLER(CDhcpActiveLeases, m_spActiveLeases); // only add to the UI if the node is expanded. MMC will fail the call if // we try to add a child to a node that hasn't been expanded. If we don't add // it now, it will be enumerated when the user selects the node. if (pRes->m_bExpanded) { CDhcpReservationClient * pNewResClient = new CDhcpReservationClient(m_spTFSCompData, (CDhcpClient&) *pClient); CreateContainerTFSNode(&spResClientNode, &GUID_DhcpReservationClientNodeType, pNewResClient, pNewResClient, m_spNodeMgr); // Tell the handler to initialize any specific data pNewResClient->InitializeNode((ITFSNode *) spResClientNode); // Add the node as a child to this node CDhcpReservations * pReservations = GETHANDLER(CDhcpReservations, m_spReservations); pReservations->AddReservationSorted(m_spReservations, spResClientNode); pNewResClient->Release(); } // // Active Lease record // if (pActLeases->m_bExpanded) { CDhcpActiveLease * pNewLease = new CDhcpActiveLease(m_spTFSCompData, (CDhcpClient&) *pClient); CreateLeafTFSNode(&spActiveLeaseNode, &GUID_DhcpActiveLeaseNodeType, pNewLease, pNewLease, m_spNodeMgr); // Tell the handler to initialize any specific data pNewLease->InitializeNode((ITFSNode *) spActiveLeaseNode); // Add the node as a child to the Active Leases container m_spActiveLeases->AddChild(spActiveLeaseNode); pNewLease->Release(); } return err; } /*--------------------------------------------------------------------------- CDhcpScope::UpdateReservation Creates a reservation for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::UpdateReservation ( const CDhcpClient * pClient, COptionValueEnum * pOptionValueEnum ) { DWORD err = 0; const CByteArray & baHardwareAddress = pClient->QueryHardwareAddress(); SPITFSNode spResClientNode, spActiveLeaseNode; // // To update a reservation we need to remove the old one and update it // with the new information. This is mostly for the client type field. // err = DeleteReservation((CByteArray&) baHardwareAddress, pClient->QueryIpAddress()); // now add the updated one err = AddReservation(pClient); if (err != ERROR_SUCCESS) return err; // restore the options for this reserved client err = RestoreReservationOptions(pClient, pOptionValueEnum); if (err != ERROR_SUCCESS) return err; // Now update the client info record associated with this. err = SetClientInfo(pClient); return err; } /*--------------------------------------------------------------------------- CDhcpScope::RestoreReservationOptions Restores options when updating a reservation becuase the only way to update the reservation is to remove it and re-add it. Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::RestoreReservationOptions ( const CDhcpClient * pClient, COptionValueEnum * pOptionValueEnum ) { DWORD dwErr = ERROR_SUCCESS; CDhcpOption * pCurOption; LARGE_INTEGER liVersion; GetServerVersion(liVersion); // start at the top of the list pOptionValueEnum->Reset(); // loop through all the options, re-adding them while (pCurOption = pOptionValueEnum->Next()) { CDhcpOptionValue optValue = pCurOption->QueryValue(); DHCP_OPTION_DATA * pOptData; dwErr = optValue.CreateOptionDataStruct(&pOptData); if (dwErr != ERROR_SUCCESS) break; if ( liVersion.QuadPart >= DHCP_NT5_VERSION ) { LPCTSTR pClassName = pCurOption->IsClassOption() ? pCurOption->GetClassName() : NULL; dwErr = ::DhcpSetOptionValueV5((LPTSTR) GetServerIpAddress(), pCurOption->IsVendor() ? DHCP_FLAGS_OPTION_IS_VENDOR : 0, pCurOption->QueryId(), (LPTSTR) pClassName, (LPTSTR) pCurOption->GetVendor(), &pOptionValueEnum->m_dhcpOptionScopeInfo, pOptData); } else { dwErr = ::DhcpSetOptionValue((LPTSTR) GetServerIpAddress(), pCurOption->QueryId(), &pOptionValueEnum->m_dhcpOptionScopeInfo, pOptData); } if (dwErr != ERROR_SUCCESS) break; } return dwErr; } /*--------------------------------------------------------------------------- CDhcpScope::AddReservation Deletes a reservation Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::AddReservation ( const CDhcpClient * pClient ) { DWORD err = 0 ; DHCP_SUBNET_ELEMENT_DATA_V4 dhcSubElData; DHCP_IP_RESERVATION_V4 dhcpIpReservation; DHCP_CLIENT_UID dhcpClientUID; const CByteArray& baHardwareAddress = pClient->QueryHardwareAddress(); dhcpClientUID.DataLength = (DWORD) baHardwareAddress.GetSize(); dhcpClientUID.Data = (BYTE *) baHardwareAddress.GetData(); dhcpIpReservation.ReservedIpAddress = pClient->QueryIpAddress(); dhcpIpReservation.ReservedForClient = &dhcpClientUID; dhcSubElData.ElementType = DhcpReservedIps; dhcSubElData.Element.ReservedIp = &dhcpIpReservation; dhcpIpReservation.bAllowedClientTypes = pClient->QueryClientType(); LARGE_INTEGER liVersion; GetServerVersion(liVersion); if (liVersion.QuadPart >= DHCP_SP2_VERSION) { err = AddElementV4( &dhcSubElData ); } else { err = AddElement( reinterpret_cast(&dhcSubElData) ); } return err; } /*--------------------------------------------------------------------------- CDhcpScope::DeleteReservation Deletes a reservation Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::DeleteReservation ( CByteArray& baHardwareAddress, DHCP_IP_ADDRESS dhcpReservedIpAddress ) { DHCP_SUBNET_ELEMENT_DATA dhcpSubnetElementData; DHCP_IP_RESERVATION dhcpIpReservation; DHCP_CLIENT_UID dhcpClientUID; dhcpClientUID.DataLength = (DWORD) baHardwareAddress.GetSize(); dhcpClientUID.Data = baHardwareAddress.GetData(); dhcpIpReservation.ReservedIpAddress = dhcpReservedIpAddress; dhcpIpReservation.ReservedForClient = &dhcpClientUID; dhcpSubnetElementData.ElementType = DhcpReservedIps; dhcpSubnetElementData.Element.ReservedIp = &dhcpIpReservation; return RemoveElement(&dhcpSubnetElementData, TRUE); } /*--------------------------------------------------------------------------- CDhcpScope::DeleteReservation Deletes a reservation Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::DeleteReservation ( DHCP_CLIENT_UID &dhcpClientUID, DHCP_IP_ADDRESS dhcpReservedIpAddress ) { DHCP_SUBNET_ELEMENT_DATA dhcpSubnetElementData; DHCP_IP_RESERVATION dhcpIpReservation; dhcpIpReservation.ReservedIpAddress = dhcpReservedIpAddress; dhcpIpReservation.ReservedForClient = &dhcpClientUID; dhcpSubnetElementData.ElementType = DhcpReservedIps; dhcpSubnetElementData.Element.ReservedIp = &dhcpIpReservation; return RemoveElement(&dhcpSubnetElementData, TRUE); } /*--------------------------------------------------------------------------- CDhcpScope::GetClientInfo Gets a clients detailed information Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::GetClientInfo ( DHCP_IP_ADDRESS dhcpClientIpAddress, LPDHCP_CLIENT_INFO *ppdhcpClientInfo ) { DHCP_SEARCH_INFO dhcpSearchInfo; dhcpSearchInfo.SearchType = DhcpClientIpAddress; dhcpSearchInfo.SearchInfo.ClientIpAddress = dhcpClientIpAddress; return ::DhcpGetClientInfo(GetServerIpAddress(), &dhcpSearchInfo, ppdhcpClientInfo); } /*--------------------------------------------------------------------------- CDhcpScope::CreateClient CreateClient() creates a reservation for a client. The act of adding a new reserved IP address causes the DHCP server to create a new client record; we then set the client info for this newly created client. Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::CreateClient ( const CDhcpClient * pClient ) { DWORD err = 0; do { err = AddReservation( pClient ); if (err != ERROR_SUCCESS) break; err = SetClientInfo( pClient ); } while (FALSE); return err; } /*--------------------------------------------------------------------------- CDhcpScope::SetClientInfo Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetClientInfo ( const CDhcpClient * pClient ) { DWORD err = 0 ; DHCP_CLIENT_INFO_V4 dhcpClientInfo; const CByteArray& baHardwareAddress = pClient->QueryHardwareAddress(); LARGE_INTEGER liVersion; GetServerVersion(liVersion); dhcpClientInfo.ClientIpAddress = pClient->QueryIpAddress(); dhcpClientInfo.SubnetMask = pClient->QuerySubnet(); dhcpClientInfo.ClientHardwareAddress.DataLength = (DWORD) baHardwareAddress.GetSize(); dhcpClientInfo.ClientHardwareAddress.Data = (BYTE *) baHardwareAddress.GetData(); dhcpClientInfo.ClientName = (LPTSTR) ((LPCTSTR) pClient->QueryName()); dhcpClientInfo.ClientComment = (LPTSTR) ((LPCTSTR) pClient->QueryComment()); dhcpClientInfo.ClientLeaseExpires = pClient->QueryExpiryDateTime(); dhcpClientInfo.OwnerHost.IpAddress = 0; dhcpClientInfo.OwnerHost.HostName = NULL; dhcpClientInfo.OwnerHost.NetBiosName = NULL; if (liVersion.QuadPart >= DHCP_SP2_VERSION) { dhcpClientInfo.bClientType = pClient->QueryClientType(); err = ::DhcpSetClientInfoV4(GetServerIpAddress(), &dhcpClientInfo); } else { err = ::DhcpSetClientInfo(GetServerIpAddress(), reinterpret_cast(&dhcpClientInfo)); } return err; } /*--------------------------------------------------------------------------- CDhcpScope::DeleteClient Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::DeleteClient ( DHCP_IP_ADDRESS dhcpClientIpAddress ) { DHCP_SEARCH_INFO dhcpClientInfo; dhcpClientInfo.SearchType = DhcpClientIpAddress; dhcpClientInfo.SearchInfo.ClientIpAddress = dhcpClientIpAddress; return ::DhcpDeleteClientInfo((LPWSTR) GetServerIpAddress(), &dhcpClientInfo); } /*--------------------------------------------------------------------------- CDhcpScope::SetInfo() Updates the scope's information Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetInfo() { DWORD err = 0 ; DHCP_SUBNET_INFO dhcpSubnetInfo; dhcpSubnetInfo.SubnetAddress = m_dhcpIpAddress; dhcpSubnetInfo.SubnetMask = m_dhcpSubnetMask; dhcpSubnetInfo.SubnetName = (LPTSTR) ((LPCTSTR) m_strName); dhcpSubnetInfo.SubnetComment = (LPTSTR) ((LPCTSTR) m_strComment); dhcpSubnetInfo.SubnetState = m_dhcpSubnetState; GetServerIpAddress(&dhcpSubnetInfo.PrimaryHost.IpAddress); // Review : ericdav - do we need to fill these in? dhcpSubnetInfo.PrimaryHost.NetBiosName = NULL; dhcpSubnetInfo.PrimaryHost.HostName = NULL; err = ::DhcpSetSubnetInfo(GetServerIpAddress(), m_dhcpIpAddress, &dhcpSubnetInfo); return err; } /*--------------------------------------------------------------------------- CDhcpScope::GetIpRange() returns the scope's allocation range. Connects to the server to get the information Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::GetIpRange ( CDhcpIpRange * pdhipr ) { BOOL bAlloced = FALSE; DWORD dwError = ERROR_SUCCESS; pdhipr->SetAddr(0, TRUE); pdhipr->SetAddr(0, FALSE); CDhcpAddressPool * pAddressPool = GetAddressPoolObject(); if (pAddressPool == NULL) { // the address pool folder isn't there yet... // Create a temporary one for now... pAddressPool = new CDhcpAddressPool(m_spTFSCompData); bAlloced = TRUE; } // Get a query object from the address pool handler CDhcpAddressPoolQueryObj * 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_dhcpScopeAddress = GetAddress(); pQueryObject->m_fSupportsDynBootp = GetServerObject()->FSupportsDynBootp(); 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 = *pAllocRange; pdhipr->SetRangeType(pAllocRange->GetRangeType()); p.Release(); } pQueryObject->Release(); return dwError; } /*--------------------------------------------------------------------------- CDhcpScope::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 CDhcpScope::UpdateIpRange ( DHCP_IP_RANGE * pdhipr ) { return SetIpRange(pdhipr, TRUE); } /*--------------------------------------------------------------------------- CDhcpScope::QueryIpRange() Returns the scope's allocation range (doesn't talk to the server directly, only returns internally cached information). Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScope::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); } } /*--------------------------------------------------------------------------- CDhcpScope::SetIpRange Set's the allocation range for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetIpRange ( DHCP_IP_RANGE * pdhcpIpRange, BOOL bUpdateOnServer ) { CDhcpIpRange dhcpIpRange = *pdhcpIpRange; return SetIpRange(dhcpIpRange, bUpdateOnServer); } /*--------------------------------------------------------------------------- CDhcpScope::SetIpRange Set's the allocation range for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetIpRange ( CDhcpIpRange & dhcpIpRange, BOOL bUpdateOnServer ) { DWORD err = 0; if (bUpdateOnServer) { DHCP_SUBNET_ELEMENT_DATA dhcSubElData; CDhcpIpRange dhipOldRange; DHCP_IP_RANGE dhcpTempIpRange; err = GetIpRange(&dhipOldRange); if (err != ERROR_SUCCESS) { return err; } dhcpTempIpRange.StartAddress = dhipOldRange.QueryAddr(TRUE); dhcpTempIpRange.EndAddress = dhipOldRange.QueryAddr(FALSE); dhcSubElData.ElementType = DhcpIpRanges; dhcSubElData.Element.IpRange = &dhcpTempIpRange; // // First update the information on the server // if (dhcpIpRange.GetRangeType() != 0) { // Dynamic BOOTP stuff... DHCP_SUBNET_ELEMENT_DATA_V5 dhcSubElDataV5; DHCP_BOOTP_IP_RANGE dhcpNewIpRange = {0}; dhcpNewIpRange.StartAddress = dhcpIpRange.QueryAddr(TRUE); dhcpNewIpRange.EndAddress = dhcpIpRange.QueryAddr(FALSE); dhcpNewIpRange.BootpAllocated = 0; // this field could be set to allow X number of dyn bootp clients from a scope. dhcpNewIpRange.MaxBootpAllowed = -1; dhcSubElDataV5.Element.IpRange = &dhcpNewIpRange; dhcSubElDataV5.ElementType = (DHCP_SUBNET_ELEMENT_TYPE) dhcpIpRange.GetRangeType(); err = AddElementV5(&dhcSubElDataV5); if (err != ERROR_SUCCESS) { DHCP_BOOTP_IP_RANGE dhcpOldIpRange = {0}; // something bad happened, try to put the old range back dhcpOldIpRange.StartAddress = dhipOldRange.QueryAddr(TRUE); dhcpOldIpRange.EndAddress = dhipOldRange.QueryAddr(FALSE); dhcSubElDataV5.Element.IpRange = &dhcpOldIpRange; dhcSubElDataV5.ElementType = (DHCP_SUBNET_ELEMENT_TYPE) dhipOldRange.GetRangeType(); if (AddElementV5(&dhcSubElDataV5) != ERROR_SUCCESS) { Trace0("SetIpRange - cannot return ip range back to old state!!"); } } } else { // Remove the old IP range; allow "not found" error in new scope. // (void)RemoveElement(&dhcSubElData); DHCP_IP_RANGE dhcpNewIpRange = {0}; dhcpNewIpRange.StartAddress = dhcpIpRange.QueryAddr(TRUE); dhcpNewIpRange.EndAddress = dhcpIpRange.QueryAddr(FALSE); dhcSubElData.Element.IpRange = &dhcpNewIpRange; err = AddElement( & dhcSubElData ); if (err != ERROR_SUCCESS) { // something bad happened, try to put the old range back dhcpTempIpRange.StartAddress = dhipOldRange.QueryAddr(TRUE); dhcpTempIpRange.EndAddress = dhipOldRange.QueryAddr(FALSE); dhcSubElData.Element.IpRange = &dhcpTempIpRange; 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 ; } /*--------------------------------------------------------------------------- CDhcpScope::IsOverlappingRange determines if the exclusion overlaps an existing range Author: EricDav ---------------------------------------------------------------------------*/ BOOL CDhcpScope::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 ; } /*--------------------------------------------------------------------------- CDhcpScope::IsValidExclusion determines if the exclusion is valid for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::IsValidExclusion ( CDhcpIpRange & dhcpExclusionRange ) { DWORD err = 0; CDhcpIpRange dhcpScopeRange; err = GetIpRange (&dhcpScopeRange); // // 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; } /*--------------------------------------------------------------------------- CDhcpScope::StoreExceptionList Adds a bunch of exclusions to the scope Author: EricDav ---------------------------------------------------------------------------*/ LONG CDhcpScope::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 ; } /*--------------------------------------------------------------------------- CDhcpScope::AddExclusion Adds an individual exclusion to the server Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::AddExclusion ( CDhcpIpRange & dhcpIpRange, BOOL bAddToUI ) { DHCP_SUBNET_ELEMENT_DATA dhcElement ; DHCP_IP_RANGE dhipr ; DWORD err = 0; dhcElement.ElementType = DhcpExcludedIpRanges ; dhipr = dhcpIpRange ; dhcElement.Element.ExcludeIpRange = & dhipr ; Trace2("CDhcpScope::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("CDhcpScope::AddExclusion error removing range %d\n", err); } if (m_spAddressPool != NULL) { CDhcpAddressPool * pAddrPool = GETHANDLER(CDhcpAddressPool, 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(); } } TriggerStatsRefresh(); return err; } /*--------------------------------------------------------------------------- CDhcpScope::RemoveExclusion Removes and exclusion from the server Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::RemoveExclusion ( CDhcpIpRange & dhcpIpRange ) { DHCP_SUBNET_ELEMENT_DATA dhcElement ; DHCP_IP_RANGE dhipr ; DWORD err = 0; dhcElement.ElementType = DhcpExcludedIpRanges ; dhipr = dhcpIpRange ; dhcElement.Element.ExcludeIpRange = & dhipr ; Trace2("CDhcpScope::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("CDhcpScope::RemoveExclusion error removing range %d\n", err); } return err; } /*--------------------------------------------------------------------------- CDhcpScope::GetLeaseTime Gets the least time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::GetLeaseTime ( LPDWORD pdwLeaseTime ) { // // Check option 51 -- the lease duration // DWORD dwLeaseTime = 0; DHCP_OPTION_VALUE * poptValue = NULL; DWORD err = GetOptionValue(OPTION_LEASE_DURATION, DhcpSubnetOptions, &poptValue); if (err != ERROR_SUCCESS) { Trace0("CDhcpScope::GetLeaseTime - couldn't get lease duration -- \ this scope may have been created by a pre-release version of the admin tool\n"); // // The scope doesn't have a lease duration, maybe there's // a global option that can come to the rescue here... // if ((err = GetOptionValue(OPTION_LEASE_DURATION, DhcpGlobalOptions, &poptValue)) != ERROR_SUCCESS) { Trace0("CDhcpScope::GetLeaseTime - No global lease duration either -- \ assuming permanent lease duration\n"); dwLeaseTime = 0; } } if (err == ERROR_SUCCESS) { if (poptValue->Value.Elements != NULL) dwLeaseTime = poptValue->Value.Elements[0].Element.DWordOption; } if (poptValue) ::DhcpRpcFreeMemory(poptValue); *pdwLeaseTime = dwLeaseTime; return err; } /*--------------------------------------------------------------------------- CDhcpScope::SetLeaseTime Sets the least time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetLeaseTime ( DWORD dwLeaseTime ) { DWORD err = 0; // // Set lease duration (option 51) // CDhcpOption dhcpOption (OPTION_LEASE_DURATION, DhcpDWordOption , _T(""), _T("")); dhcpOption.QueryValue().SetNumber(dwLeaseTime); err = SetOptionValue(&dhcpOption, DhcpSubnetOptions); return err; } /*--------------------------------------------------------------------------- CDhcpScope::GetDynBootpLeaseTime Gets the least time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::GetDynBootpLeaseTime ( LPDWORD pdwLeaseTime ) { // // Check option 51 -- the lease duration // DWORD dwLeaseTime = 0; DHCP_OPTION_VALUE * poptValue = NULL; CString strName; GetDynBootpClassName(strName); DWORD err = GetOptionValue(OPTION_LEASE_DURATION, DhcpSubnetOptions, &poptValue, 0, strName, NULL); if (err != ERROR_SUCCESS) { Trace0("CDhcpScope::GetDynBootpLeaseTime - couldn't get lease duration -- \ this scope may have been created by a pre-release version of the admin tool\n"); // // The scope doesn't have a lease duration, maybe there's // a global option that can come to the rescue here... // if ((err = GetOptionValue(OPTION_LEASE_DURATION, DhcpGlobalOptions, &poptValue, 0, strName, NULL)) != ERROR_SUCCESS) { Trace0("CDhcpScope::GetDynBootpLeaseTime - No global lease duration either -- \ assuming permanent lease duration\n"); dwLeaseTime = 0; } } if (err == ERROR_SUCCESS) { if (poptValue->Value.Elements != NULL) dwLeaseTime = poptValue->Value.Elements[0].Element.DWordOption; } else { // none specified, using default dwLeaseTime = UtilConvertLeaseTime(DYN_BOOTP_DFAULT_LEASE_DAYS, DYN_BOOTP_DFAULT_LEASE_HOURS, DYN_BOOTP_DFAULT_LEASE_MINUTES); } if (poptValue) ::DhcpRpcFreeMemory(poptValue); *pdwLeaseTime = dwLeaseTime; return err; } /*--------------------------------------------------------------------------- CDhcpScope::SetDynBootpLeaseTime Sets the least time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetDynBootpLeaseTime ( DWORD dwLeaseTime ) { DWORD err = 0; // // Set lease duration (option 51) // CDhcpOption dhcpOption (OPTION_LEASE_DURATION, DhcpDWordOption , _T(""), _T("")); dhcpOption.QueryValue().SetNumber(dwLeaseTime); CString strName; GetDynBootpClassName(strName); err = SetOptionValue(&dhcpOption, DhcpSubnetOptions, 0, strName, NULL); return err; } /*--------------------------------------------------------------------------- CDhcpScope::GetDynBootpClassName returns the user class name to be used to set the lease time Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScope::GetDynBootpClassName(CString & strName) { // use DHCP_BOOTP_CLASS_TXT as the class data to search for CClassInfoArray classInfoArray; GetServerObject()->GetClassInfoArray(classInfoArray); for (int i = 0; i < classInfoArray.GetSize(); i++) { // check to make sure same size if (classInfoArray[i].IsDynBootpClass()) { // found it! strName = classInfoArray[i].strName; break; } } } DWORD CDhcpScope::SetDynamicBootpInfo(UINT uRangeType, DWORD dwLeaseTime) { DWORD dwErr = 0; // set the range type CDhcpIpRange dhcpIpRange; GetIpRange(&dhcpIpRange); dhcpIpRange.SetRangeType(uRangeType); // this updates the type dwErr = SetIpRange(dhcpIpRange, TRUE); if (dwErr != ERROR_SUCCESS) return dwErr; // set the lease time dwErr = SetDynBootpLeaseTime(dwLeaseTime); return dwErr; } /*--------------------------------------------------------------------------- CDhcpScope::GetDnsRegistration Gets the DNS registration option value Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::GetDnsRegistration ( LPDWORD pDnsRegOption ) { // // Check option 81 -- the DNS registration option // DHCP_OPTION_VALUE * poptValue = NULL; DWORD err = GetOptionValue(OPTION_DNS_REGISTATION, DhcpSubnetOptions, &poptValue); // this is the default if (pDnsRegOption) *pDnsRegOption = DHCP_DYN_DNS_DEFAULT; if (err == ERROR_SUCCESS) { if ((poptValue->Value.Elements != NULL) && (pDnsRegOption)) { *pDnsRegOption = poptValue->Value.Elements[0].Element.DWordOption; } } else { Trace0("CDhcpScope::GetDnsRegistration - couldn't get DNS reg value, option may not be defined, Getting Server value.\n"); CDhcpServer * pServer = GETHANDLER(CDhcpServer, m_spServerNode); err = pServer->GetDnsRegistration(pDnsRegOption); } if (poptValue) ::DhcpRpcFreeMemory(poptValue); return err; } /*--------------------------------------------------------------------------- CDhcpScope::SetDnsRegistration Sets the DNS Registration option for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetDnsRegistration ( DWORD DnsRegOption ) { DWORD err = 0; // // Set DNS name registration (option 81) // CDhcpOption dhcpOption (OPTION_DNS_REGISTATION, DhcpDWordOption , _T(""), _T("")); dhcpOption.QueryValue().SetNumber(DnsRegOption); err = SetOptionValue(&dhcpOption, DhcpSubnetOptions); return err; } /*--------------------------------------------------------------------------- CDhcpScope::SetOptionValue Sets the least time for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetOptionValue ( CDhcpOption * pdhcType, DHCP_OPTION_SCOPE_TYPE dhcOptType, DHCP_IP_ADDRESS dhipaReservation, LPCTSTR pClassName, LPCTSTR pVendorName ) { 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 ( (err = pcOptionValue->QueryError()) == 0 ) if ( pcOptionValue ) { dhcScopeInfo.ScopeType = dhcOptType ; // // Provide the sub-net address if this is a scope-level operation // if ( dhcOptType == DhcpSubnetOptions ) { dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpIpAddress; } else if ( dhcOptType == DhcpReservedOptions ) { dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation; dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_dhcpIpAddress; } pcOptionValue->CreateOptionDataStruct(&pdhcOptionData, TRUE); if (pClassName || pVendorName) { err = (DWORD) ::DhcpSetOptionValueV5((LPTSTR) GetServerIpAddress(), 0, pdhcType->QueryId(), (LPTSTR) pClassName, (LPTSTR) pVendorName, &dhcScopeInfo, pdhcOptionData); } else { err = (DWORD) ::DhcpSetOptionValue(GetServerIpAddress(), pdhcType->QueryId(), &dhcScopeInfo, pdhcOptionData); } } } END_MEM_EXCEPTION(err) ; delete pcOptionValue ; return err ; } /*--------------------------------------------------------------------------- CDhcpScope::GetValue Gets an option value for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::GetOptionValue ( DHCP_OPTION_ID OptionID, DHCP_OPTION_SCOPE_TYPE dhcOptType, DHCP_OPTION_VALUE ** ppdhcOptionValue, DHCP_IP_ADDRESS dhipaReservation, LPCTSTR pClassName, LPCTSTR pVendorName ) { DWORD err = 0 ; DHCP_OPTION_SCOPE_INFO dhcScopeInfo ; ZeroMemory( &dhcScopeInfo, sizeof(dhcScopeInfo) ); CATCH_MEM_EXCEPTION { dhcScopeInfo.ScopeType = dhcOptType ; // // Provide the sub-net address if this is a scope-level operation // if ( dhcOptType == DhcpSubnetOptions ) { dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpIpAddress; } else if ( dhcOptType == DhcpReservedOptions ) { dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation; dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_dhcpIpAddress; } if (pClassName || pVendorName) { err = (DWORD) ::DhcpGetOptionValueV5((LPTSTR) GetServerIpAddress(), 0, OptionID, (LPTSTR) pClassName, (LPTSTR) pVendorName, &dhcScopeInfo, ppdhcOptionValue ); } else { err = (DWORD) ::DhcpGetOptionValue(GetServerIpAddress(), OptionID, &dhcScopeInfo, ppdhcOptionValue ); } } END_MEM_EXCEPTION(err) ; return err ; } /*--------------------------------------------------------------------------- CDhcpScope::RemoveValue Removes an option Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::RemoveOptionValue ( DHCP_OPTION_ID dhcOptId, DHCP_OPTION_SCOPE_TYPE dhcOptType, DHCP_IP_ADDRESS dhipaReservation ) { DHCP_OPTION_SCOPE_INFO dhcScopeInfo; ZeroMemory( &dhcScopeInfo, sizeof(dhcScopeInfo) ); dhcScopeInfo.ScopeType = dhcOptType; // // Provide the sub-net address if this is a scope-level operation // if ( dhcOptType == DhcpSubnetOptions ) { dhcScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpIpAddress; } else if ( dhcOptType == DhcpReservedOptions ) { dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = dhipaReservation; dhcScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_dhcpIpAddress; } return (DWORD) ::DhcpRemoveOptionValue(GetServerIpAddress(), dhcOptId, &dhcScopeInfo); } /*--------------------------------------------------------------------------- CDhcpScope::AddElement Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::AddElement ( DHCP_SUBNET_ELEMENT_DATA * pdhcpSubnetElementData ) { return ::DhcpAddSubnetElement(GetServerIpAddress(), m_dhcpIpAddress, pdhcpSubnetElementData); } /*--------------------------------------------------------------------------- CDhcpScope::RemoveElement Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::RemoveElement ( DHCP_SUBNET_ELEMENT_DATA * pdhcpSubnetElementData, BOOL bForce ) { return ::DhcpRemoveSubnetElement(GetServerIpAddress(), m_dhcpIpAddress, pdhcpSubnetElementData, bForce ? DhcpFullForce : DhcpNoForce); } /*--------------------------------------------------------------------------- CDhcpScope::AddElementV4 Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::AddElementV4 ( DHCP_SUBNET_ELEMENT_DATA_V4 * pdhcpSubnetElementData ) { return ::DhcpAddSubnetElementV4(GetServerIpAddress(), m_dhcpIpAddress, pdhcpSubnetElementData); } /*--------------------------------------------------------------------------- CDhcpScope::RemoveElementV4 Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::RemoveElementV4 ( DHCP_SUBNET_ELEMENT_DATA_V4 * pdhcpSubnetElementData, BOOL bForce ) { return ::DhcpRemoveSubnetElementV4(GetServerIpAddress(), m_dhcpIpAddress, pdhcpSubnetElementData, bForce ? DhcpFullForce : DhcpNoForce); } /*--------------------------------------------------------------------------- CDhcpScope::AddElementV5 Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::AddElementV5 ( DHCP_SUBNET_ELEMENT_DATA_V5 * pdhcpSubnetElementData ) { return ::DhcpAddSubnetElementV5(GetServerIpAddress(), m_dhcpIpAddress, pdhcpSubnetElementData); } /*--------------------------------------------------------------------------- CDhcpScope::RemoveElementV5 Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::RemoveElementV5 ( DHCP_SUBNET_ELEMENT_DATA_V5 * pdhcpSubnetElementData, BOOL bForce ) { return ::DhcpRemoveSubnetElementV5(GetServerIpAddress(), m_dhcpIpAddress, pdhcpSubnetElementData, bForce ? DhcpFullForce : DhcpNoForce); } /*--------------------------------------------------------------------------- CDhcpScope::GetServerIpAddress() Description Author: EricDav ---------------------------------------------------------------------------*/ LPCWSTR CDhcpScope::GetServerIpAddress() { CDhcpServer * pServer = GetServerObject(); return pServer->GetIpAddress(); } /*--------------------------------------------------------------------------- CDhcpScope::GetServerIpAddress Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScope::GetServerIpAddress(DHCP_IP_ADDRESS * pdhcpIpAddress) { CDhcpServer * pServer = GetServerObject(); pServer->GetIpAddress(pdhcpIpAddress); } /*--------------------------------------------------------------------------- CDhcpScope::GetServerVersion Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScope::GetServerVersion ( LARGE_INTEGER& liVersion ) { CDhcpServer * pServer = GetServerObject(); pServer->GetVersion(liVersion); } /*--------------------------------------------------------------------------- CDhcpScope::SetSuperscope Sets this scope as part of the given superscope name Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpScope::SetSuperscope ( LPCTSTR pSuperscopeName, BOOL bRemove ) { DWORD dwReturn = 0; dwReturn = ::DhcpSetSuperScopeV4(GetServerIpAddress(), GetAddress(), (LPWSTR) pSuperscopeName, bRemove); if (dwReturn != ERROR_SUCCESS) { Trace1("CDhcpScope::SetSuperscope - DhcpSetSuperScopeV4 failed!! %d\n", dwReturn); } return dwReturn; } /*--------------------------------------------------------------------------- Helper functions ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::BuildDisplayName ( CString * pstrDisplayName, LPCTSTR pIpAddress, LPCTSTR pName ) { if (pstrDisplayName) { CString strStandard, strIpAddress, strName; strIpAddress = pIpAddress; strName = pName; strStandard.LoadString(IDS_SCOPE_FOLDER); *pstrDisplayName = strStandard + L" [" + strIpAddress + L"] " + strName; } return hrOK; } HRESULT CDhcpScope::SetName ( LPCWSTR pName ) { if (pName != NULL) { m_strName = pName; } CString strIpAddress, strDisplayName; // // Create the display name for this scope // Convert DHCP_IP_ADDRES to a string and initialize this object // UtilCvtIpAddrToWstr (m_dhcpIpAddress, &strIpAddress); BuildDisplayName(&strDisplayName, strIpAddress, pName); SetDisplayName(strDisplayName); return hrOK; } /*--------------------------------------------------------------------------- CDhcpScope::GetAddressPoolObject() Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpAddressPool * CDhcpScope::GetAddressPoolObject() { if (m_spAddressPool) return GETHANDLER(CDhcpAddressPool, m_spAddressPool); else return NULL; } /*--------------------------------------------------------------------------- CDhcpScope::GetReservationsObject() Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpReservations * CDhcpScope::GetReservationsObject() { if ( m_spReservations ) return GETHANDLER(CDhcpReservations, m_spReservations); else return NULL; } /*--------------------------------------------------------------------------- CDhcpScope::GetReservationsObject() Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpActiveLeases * CDhcpScope::GetActiveLeasesObject() { if (m_spActiveLeases) return GETHANDLER(CDhcpActiveLeases, m_spActiveLeases); else return NULL; } /*--------------------------------------------------------------------------- CDhcpScope::GetScopeOptionsContainer() Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpScopeOptions * CDhcpScope::GetScopeOptionsObject() { if (m_spOptions) return GETHANDLER(CDhcpScopeOptions, m_spOptions); else return NULL; } /*--------------------------------------------------------------------------- CDhcpScope::TriggerStatsRefresh() Calls into the server object to update the stats Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScope::TriggerStatsRefresh() { GetServerObject()->TriggerStatsRefresh(m_spServerNode); return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservations Implementation ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpReservations::CDhcpReservations() Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpReservations::CDhcpReservations ( ITFSComponentData * pComponentData ) : CMTDhcpHandler(pComponentData) { } // // copy all the resrved ips to an array and qsort it // when matching an entry that is read from dhcp db // we can do a binary search on the qsorted array // a better algorithm for large n ( n number of active clients ) is to // go through the active clients once for each m ( reserved ip ) where m > // 100 but << n BOOL CDhcpReservationsQueryObj::AddReservedIPsToArray( ) { DHCP_RESUME_HANDLE dhcpResumeHandle = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0, dwTotalRead = 0; DWORD dwError = ERROR_MORE_DATA; DWORD dwResvThreshold = 100; m_resvMap.RemoveAll(); m_subnetElements = NULL; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetElementsV4(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, DhcpReservedIps, &dhcpResumeHandle, -1, &m_subnetElements, &dwElementsRead, &dwElementsTotal); Trace3("BuildReservationList: Scope %lx Reservations read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal ); // // If number of reservations is less than 100 handle it the old way // if ( dwElementsTotal <= dwResvThreshold ) { m_totalResvs = dwElementsTotal; return( FALSE ); } if (dwElementsRead && dwElementsTotal && m_subnetElements ) { // // Loop through the array that was returned // for (DWORD i = 0; i < m_subnetElements->NumElements; i++) { m_resvMap.SetAt( m_subnetElements->Elements[i].Element.ReservedIp->ReservedIpAddress, &m_subnetElements->Elements[ i ]); } dwTotalRead += dwElementsRead; if ( dwTotalRead <= dwElementsTotal ) { m_totalResvs = dwTotalRead; } else { m_totalResvs = dwElementsTotal; } } } // while return( TRUE ); } CDhcpReservations::~CDhcpReservations() { } /*!-------------------------------------------------------------------------- CDhcpReservations::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservations::InitializeNode ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = hrOK; // // Create the display name for this scope // CString strTemp; strTemp.LoadString(IDS_RESERVATIONS_FOLDER); SetDisplayName(strTemp); // Make the node immediately visible pNode->SetVisibilityState(TFS_VIS_SHOW); pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE)); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode); pNode->SetData(TFS_DATA_USER, (LPARAM) this); pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_RESERVATIONS); SetColumnStringIDs(&aColumns[DHCPSNAP_RESERVATIONS][0]); SetColumnWidths(&aColumnWidths[DHCPSNAP_RESERVATIONS][0]); return hr; } /*--------------------------------------------------------------------------- CDhcpReservations::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservations::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strIpAddress, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode)->GetAddress(); UtilCvtIpAddrToWstr (dhcpIpAddress, &strIpAddress); strId = GetServerName(pNode) + strIpAddress + strGuid; return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservations::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CDhcpReservations::GetImageIndex(BOOL bOpenImage) { int nIndex = -1; switch (m_nState) { case notLoaded: case loaded: if (bOpenImage) nIndex = ICON_IDX_RESERVATIONS_FOLDER_OPEN; else nIndex = ICON_IDX_RESERVATIONS_FOLDER_CLOSED; break; case loading: if (bOpenImage) nIndex = ICON_IDX_RESERVATIONS_FOLDER_OPEN_BUSY; else nIndex = ICON_IDX_RESERVATIONS_FOLDER_CLOSED_BUSY; break; case unableToLoad: if (bOpenImage) nIndex = ICON_IDX_RESERVATIONS_FOLDER_OPEN_LOST_CONNECTION; else nIndex = ICON_IDX_RESERVATIONS_FOLDER_CLOSED_LOST_CONNECTION; break; default: ASSERT(FALSE); } return nIndex; } /*!-------------------------------------------------------------------------- CDhcpReservations::RemoveReservationFromUI Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpReservations::RemoveReservationFromUI ( ITFSNode * pReservationsNode, DHCP_IP_ADDRESS dhcpReservationIp ) { DWORD dwError = E_UNEXPECTED; CDhcpReservationClient * pReservationClient = NULL; SPITFSNodeEnum spNodeEnum; SPITFSNode spCurrentNode; ULONG nNumReturned = 0; pReservationsNode->GetEnum(&spNodeEnum); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); while (nNumReturned) { pReservationClient = GETHANDLER(CDhcpReservationClient, spCurrentNode); if (dhcpReservationIp == pReservationClient->GetIpAddress()) { // // Tell this reservation to delete itself // pReservationsNode->RemoveChild(spCurrentNode); spCurrentNode.Release(); dwError = ERROR_SUCCESS; break; } spCurrentNode.Release(); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); } return dwError; } /*--------------------------------------------------------------------------- Overridden base handler functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpReservations::OnAddMenuItems Adds entries to the context sensitive menu Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservations::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) { if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) { // these menu items go in the new menu, // only visible from scope pane strMenuText.LoadString(IDS_CREATE_NEW_RESERVATION); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_CREATE_NEW_RESERVATION, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); } } return hr; } /*--------------------------------------------------------------------------- CDhcpReservations::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservations::OnCommand ( ITFSNode * pNode, long nCommandId, DATA_OBJECT_TYPES type, LPDATAOBJECT pDataObject, DWORD dwType ) { HRESULT hr = S_OK; switch (nCommandId) { case IDS_CREATE_NEW_RESERVATION: OnCreateNewReservation(pNode); break; case IDS_REFRESH: OnRefresh(pNode, pDataObject, dwType, 0, 0); break; default: break; } return hr; } /*--------------------------------------------------------------------------- CDhcpReservations::CompareItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(int) CDhcpReservations::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; CDhcpReservationClient *pDhcpRC1 = GETHANDLER(CDhcpReservationClient, spNode1); CDhcpReservationClient *pDhcpRC2 = GETHANDLER(CDhcpReservationClient, spNode2); switch (nCol) { case 0: { // IP address compare // DHCP_IP_ADDRESS dhcpIp1 = pDhcpRC1->GetIpAddress(); DHCP_IP_ADDRESS dhcpIp2 = pDhcpRC2->GetIpAddress(); if (dhcpIp1 < dhcpIp2) nCompare = -1; else if (dhcpIp1 > dhcpIp2) nCompare = 1; // default is that they are equal } break; } return nCompare; } /*!-------------------------------------------------------------------------- CDhcpReservations::OnGetResultViewType MMC calls this to get the result view information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservations::OnGetResultViewType ( ITFSComponent * pComponent, MMC_COOKIE cookie, LPOLESTR * ppViewType, long * pViewOptions ) { HRESULT hr = hrOK; // call the base class to see if it is handling this if (CMTDhcpHandler::OnGetResultViewType(pComponent, cookie, ppViewType, pViewOptions) != S_OK) { *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT; hr = S_FALSE; } return hr; } /*!-------------------------------------------------------------------------- CDhcpReservations::OnResultSelect Update the verbs and the result pane message Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservations::OnResultSelect(ITFSComponent *pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam) { HRESULT hr = hrOK; SPITFSNode spNode; CORg(CMTDhcpHandler::OnResultSelect(pComponent, pDataObject, cookie, arg, lParam)); CORg (pComponent->GetSelectedNode(&spNode)); if ( spNode != 0 ) { UpdateResultMessage(spNode); } Error: return hr; } /*!-------------------------------------------------------------------------- CDhcpReservations::UpdateResultMessage Figures out what message to put in the result pane, if any Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpReservations::UpdateResultMessage(ITFSNode * pNode) { HRESULT hr = hrOK; int nMessage = -1; // default int nVisible, nTotal; int i; CString strTitle, strBody, strTemp; if (!m_dwErr) { pNode->GetChildCount(&nVisible, &nTotal); // determine what message to display if ( (m_nState == notLoaded) || (m_nState == loading) ) { nMessage = -1; } else if (nTotal == 0) { nMessage = RESERVATIONS_MESSAGE_NO_RES; } // build the strings if (nMessage != -1) { // now build the text strings // first entry is the title strTitle.LoadString(g_uReservationsMessages[nMessage][0]); // second entry is the icon // third ... n entries are the body strings for (i = 2; g_uReservationsMessages[nMessage][i] != 0; i++) { strTemp.LoadString(g_uReservationsMessages[nMessage][i]); strBody += strTemp; } } } // show the message if (nMessage == -1) { ClearMessage(pNode); } else { ShowMessage(pNode, strTitle, strBody, (IconIdentifier) g_uReservationsMessages[nMessage][1]); } } /*--------------------------------------------------------------------------- Message handlers ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpReservations::OnCreateNewReservation Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpReservations::OnCreateNewReservation ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); SPITFSNode spScopeNode; pNode->GetParent(&spScopeNode); CDhcpScope * pScope = GETHANDLER(CDhcpScope, spScopeNode); LARGE_INTEGER liVersion; pScope->GetServerVersion(liVersion); CAddReservation dlgAddReservation(spScopeNode, liVersion); dlgAddReservation.DoModal(); GetScopeObject(pNode)->TriggerStatsRefresh(); UpdateResultMessage(pNode); return 0; } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpReservations::OnHaveData Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpReservations::OnHaveData ( ITFSNode * pParentNode, ITFSNode * pNewNode ) { AddReservationSorted(pParentNode, pNewNode); // update the view ExpandNode(pParentNode, TRUE); } /*--------------------------------------------------------------------------- CDhcpReservations::AddReservationSorted Adding reservation after sorting it by comparing against the resvname takes too much time. Adds a scope node to the UI sorted Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservations::AddReservationSorted ( ITFSNode * pReservationsNode, ITFSNode * pResClientNode ) { HRESULT hr = hrOK; SPITFSNodeEnum spNodeEnum; SPITFSNode spCurrentNode; SPITFSNode spPrevNode; ULONG nNumReturned = 0; CDhcpReservationClient * pResClient; // get our target address pResClient = GETHANDLER(CDhcpReservationClient, pResClientNode); // get the enumerator for this node CORg(pReservationsNode->GetEnum(&spNodeEnum)); CORg(spNodeEnum->Next(1, &spCurrentNode, &nNumReturned)); while (nNumReturned) { pResClient = GETHANDLER(CDhcpReservationClient, spCurrentNode); // get the next node in the list spPrevNode.Set(spCurrentNode); spCurrentNode.Release(); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); } // Add the node in based on the PrevNode pointer if (spPrevNode) { if (m_bExpanded) { pResClientNode->SetData(TFS_DATA_RELATIVE_FLAGS, SDI_PREVIOUS); pResClientNode->SetData(TFS_DATA_RELATIVE_SCOPEID, spPrevNode->GetData(TFS_DATA_SCOPEID)); } CORg(pReservationsNode->InsertChild(spPrevNode, pResClientNode)); } else { // add to the head if (m_bExpanded) { pResClientNode->SetData(TFS_DATA_RELATIVE_FLAGS, SDI_FIRST); } CORg(pReservationsNode->AddChild(pResClientNode)); } Error: return hr; } /*--------------------------------------------------------------------------- CDhcpReservations::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CDhcpReservations::OnCreateQuery(ITFSNode * pNode) { CDhcpReservationsQueryObj* pQuery = new CDhcpReservationsQueryObj(m_spTFSCompData, m_spNodeMgr); pQuery->m_strServer = GetServerIpAddress(pNode); pQuery->m_dhcpScopeAddress = GetScopeObject(pNode)->GetAddress(); pQuery->m_dhcpResumeHandle = NULL; pQuery->m_dwPreferredMax = 2000; pQuery->m_resvMap.RemoveAll(); pQuery->m_totalResvs = 0; pQuery->m_subnetElements = NULL; GetScopeObject(pNode)->GetServerVersion(pQuery->m_liVersion); return pQuery; } /*--------------------------------------------------------------------------- CDhcpReservationsQueryObj::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservationsQueryObj::Execute() { HRESULT hr = hrOK; if (m_liVersion.QuadPart >= DHCP_SP2_VERSION) { if ( AddReservedIPsToArray( ) ) { // // // this should handle the case where there are a large # of resvs. // // hr = EnumerateReservationsV4(); } else { // // a typical corporation doesnt have more than 100 resvs // handle it here // hr = EnumerateReservationsForLessResvsV4( ); } } else { hr = EnumerateReservations(); } return hr; } HRESULT CDhcpReservationsQueryObj::EnumerateReservationsForLessResvsV4( ) { DWORD dwError = ERROR_MORE_DATA; LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 pdhcpSubnetElementArray = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0; HRESULT hr = hrOK; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetElementsV4(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, DhcpReservedIps, &m_dhcpResumeHandle, m_dwPreferredMax, &pdhcpSubnetElementArray, &dwElementsRead, &dwElementsTotal); Trace3("Scope %lx Reservations read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal); if (dwElementsRead && dwElementsTotal && pdhcpSubnetElementArray) { // // Loop through the array that was returned // for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++) { // // For each reservation, we need to get the client info // DWORD dwReturn; LPDHCP_CLIENT_INFO_V4 pClientInfo = NULL; DHCP_SEARCH_INFO dhcpSearchInfo; dhcpSearchInfo.SearchType = DhcpClientIpAddress; dhcpSearchInfo.SearchInfo.ClientIpAddress = pdhcpSubnetElementArray->Elements[i].Element.ReservedIp->ReservedIpAddress; dwReturn = ::DhcpGetClientInfoV4(m_strServer, &dhcpSearchInfo, &pClientInfo); if (dwReturn == ERROR_SUCCESS) { // // Create the result pane item for this element // SPITFSNode spNode; CDhcpReservationClient * pDhcpReservationClient; COM_PROTECT_TRY { pDhcpReservationClient = new CDhcpReservationClient(m_spTFSCompData, pClientInfo); // Tell the reservation what the client type is pDhcpReservationClient->SetClientType(pdhcpSubnetElementArray->Elements[i].Element.ReservedIp->bAllowedClientTypes); CreateContainerTFSNode(&spNode, &GUID_DhcpReservationClientNodeType, pDhcpReservationClient, pDhcpReservationClient, m_spNodeMgr); // Tell the handler to initialize any specific data pDhcpReservationClient->InitializeNode(spNode); AddToQueue(spNode); pDhcpReservationClient->Release(); } COM_PROTECT_CATCH ::DhcpRpcFreeMemory(pClientInfo); } else { // REVIEW: ericdav - do we need to post the error back here? Trace1("EnumReservationsV4 - GetClientInfoV4 failed! %d\n", dwReturn); } } ::DhcpRpcFreeMemory(pdhcpSubnetElementArray); pdhcpSubnetElementArray = NULL; dwElementsRead = 0; dwElementsTotal = 0; } // 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: EnumerateReservationsV4 error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } return hrFalse; } /*--------------------------------------------------------------------------- CDhcpReservationsQueryObj::EnumerateReservationsV4() Enumerates leases for NT4 SP2 and newer servers Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationsQueryObj::EnumerateReservationsV4() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_CLIENT_INFO_ARRAY_V5 pdhcpClientArrayV5 = NULL; LPDHCP_SUBNET_ELEMENT_DATA_V4 pSubnetData = NULL; DWORD dwClientsRead = 0, dwClientsTotal = 0; DWORD dwResvsHandled = 0; DWORD dwEnumedClients = 0; DWORD dwResvThreshold = 1000; DWORD i = 0; DWORD k = 0; DWORD *j = NULL; HRESULT hr = hrOK; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetClientsV5(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, &m_dhcpResumeHandle, -1, &pdhcpClientArrayV5, &dwClientsRead, &dwClientsTotal); if ( dwClientsRead && dwClientsTotal && pdhcpClientArrayV5 ) { // // we do a binary search for a reservation // that is present in the table. // for( i = 0; i < dwClientsRead; i ++ ) { // // do binary search against each client that was read to see // if it is a reservation. // k = pdhcpClientArrayV5 -> Clients[i] -> ClientIpAddress; if ( m_resvMap.Lookup( k, pSubnetData )) { // // Create the result pane item for this element // SPITFSNode spNode; CDhcpReservationClient * pDhcpReservationClient; COM_PROTECT_TRY { pDhcpReservationClient = new CDhcpReservationClient( m_spTFSCompData, reinterpret_cast(pdhcpClientArrayV5 -> Clients[ i ] )); pDhcpReservationClient->SetClientType( pSubnetData->Element.ReservedIp->bAllowedClientTypes ); CreateContainerTFSNode(&spNode, &GUID_DhcpReservationClientNodeType, pDhcpReservationClient, pDhcpReservationClient, m_spNodeMgr); // // Tell the handler to initialize any specific data // pDhcpReservationClient->InitializeNode(spNode); AddToQueue(spNode); pDhcpReservationClient->Release(); } COM_PROTECT_CATCH } // end of if that adds a reservation } // end of for ::DhcpRpcFreeMemory(pdhcpClientArrayV5); pdhcpClientArrayV5 = NULL; dwEnumedClients += dwClientsRead; dwClientsRead = 0; dwClientsTotal = 0; } // end of main if that checks if read succeeded. // 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: EnumerateReservationsV4 error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } DhcpRpcFreeMemory( m_subnetElements ); m_subnetElements = NULL; m_totalResvs = 0; m_resvMap.RemoveAll(); return hrFalse; } /*--------------------------------------------------------------------------- CDhcpReservationsQueryObj::Execute() Enumerates reservations for pre NT4 SP2 servers Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationsQueryObj::EnumerateReservations() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_SUBNET_ELEMENT_INFO_ARRAY pdhcpSubnetElementArray = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetElements(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, DhcpReservedIps, &m_dhcpResumeHandle, m_dwPreferredMax, &pdhcpSubnetElementArray, &dwElementsRead, &dwElementsTotal); Trace3("Scope %lx Reservations read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal); if (dwElementsRead && dwElementsTotal && pdhcpSubnetElementArray) { // // Loop through the array that was returned // for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++) { // // For each reservation, we need to get the client info // DWORD dwReturn; LPDHCP_CLIENT_INFO pClientInfo = NULL; DHCP_SEARCH_INFO dhcpSearchInfo; dhcpSearchInfo.SearchType = DhcpClientIpAddress; dhcpSearchInfo.SearchInfo.ClientIpAddress = pdhcpSubnetElementArray->Elements[i].Element.ReservedIp->ReservedIpAddress; dwReturn = ::DhcpGetClientInfo(m_strServer, &dhcpSearchInfo, &pClientInfo); if (dwReturn == ERROR_SUCCESS) { // // Create the result pane item for this element // SPITFSNode spNode; CDhcpReservationClient * pDhcpReservationClient; pDhcpReservationClient = new CDhcpReservationClient(m_spTFSCompData, reinterpret_cast(pClientInfo)); CreateContainerTFSNode(&spNode, &GUID_DhcpReservationClientNodeType, pDhcpReservationClient, pDhcpReservationClient, m_spNodeMgr); // Tell the handler to initialize any specific data pDhcpReservationClient->InitializeNode(spNode); AddToQueue(spNode); pDhcpReservationClient->Release(); ::DhcpRpcFreeMemory(pClientInfo); } } ::DhcpRpcFreeMemory(pdhcpSubnetElementArray); pdhcpSubnetElementArray = NULL; dwElementsRead = 0; dwElementsTotal = 0; } // 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: EnumerateReservations error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } return hrFalse; } /*!-------------------------------------------------------------------------- CDhcpReservations::OnNotifyExiting CMTDhcpHandler overridden functionality allows us to know when the background thread is done Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservations::OnNotifyExiting ( LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); SPITFSNode spNode; spNode.Set(m_spNode); // save this off because OnNotifyExiting will release it HRESULT hr = CMTDhcpHandler::OnNotifyExiting(lParam); UpdateResultMessage(spNode); return hr; } /*--------------------------------------------------------------------------- CDhcpReservationClient implementation ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpReservationClient::CDhcpReservationClient ( ITFSComponentData * pComponentData, LPDHCP_CLIENT_INFO pDhcpClientInfo ) : CMTDhcpHandler(pComponentData) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); InitializeData(pDhcpClientInfo); // // Intialize our client type // m_bClientType = CLIENT_TYPE_UNSPECIFIED; m_fResProp = TRUE; } CDhcpReservationClient::CDhcpReservationClient ( ITFSComponentData * pComponentData, LPDHCP_CLIENT_INFO_V4 pDhcpClientInfo ) : CMTDhcpHandler(pComponentData) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); InitializeData(reinterpret_cast(pDhcpClientInfo)); // // Intialize our client type // m_bClientType = pDhcpClientInfo->bClientType; m_fResProp = TRUE; } CDhcpReservationClient::CDhcpReservationClient ( ITFSComponentData * pComponentData, CDhcpClient & dhcpClient ) : CMTDhcpHandler(pComponentData) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); m_dhcpClientIpAddress = dhcpClient.QueryIpAddress(); // // Copy data out if it's there // if (dhcpClient.QueryName().GetLength() > 0) { m_pstrClientName = new CString (dhcpClient.QueryName()); } else { m_pstrClientName = NULL; } if (dhcpClient.QueryComment().GetLength() > 0) { m_pstrClientComment = new CString(dhcpClient.QueryComment()); } else { m_pstrClientComment = NULL; } // // build the clients hardware address // if (dhcpClient.QueryHardwareAddress().GetSize() > 0) { m_baHardwareAddress.Copy(dhcpClient.QueryHardwareAddress()); } if ( (dhcpClient.QueryExpiryDateTime().dwLowDateTime == 0) && (dhcpClient.QueryExpiryDateTime().dwHighDateTime == 0) ) { // // This is an inactive reservation // m_strLeaseExpires.LoadString(IDS_DHCP_INFINITE_LEASE_INACTIVE); } else { m_strLeaseExpires.LoadString(IDS_DHCP_INFINITE_LEASE_ACTIVE); } // // Intialize our client type // m_bClientType = dhcpClient.QueryClientType(); m_fResProp = TRUE; } CDhcpReservationClient::~CDhcpReservationClient() { if (m_pstrClientName) { delete m_pstrClientName; } if (m_pstrClientComment) { delete m_pstrClientComment; } } void CDhcpReservationClient::InitializeData ( LPDHCP_CLIENT_INFO pDhcpClientInfo ) { Assert(pDhcpClientInfo); m_dhcpClientIpAddress = pDhcpClientInfo->ClientIpAddress; // // Copy data out if it's there // if (pDhcpClientInfo->ClientName) { m_pstrClientName = new CString (pDhcpClientInfo->ClientName); } else { m_pstrClientName = NULL; } if (pDhcpClientInfo->ClientComment) { m_pstrClientComment = new CString(pDhcpClientInfo->ClientComment); } else { m_pstrClientComment = NULL; } // build a copy of the hardware address if (pDhcpClientInfo->ClientHardwareAddress.DataLength) { for (DWORD i = 0; i < pDhcpClientInfo->ClientHardwareAddress.DataLength; i++) { m_baHardwareAddress.Add(pDhcpClientInfo->ClientHardwareAddress.Data[i]); } } if ( (pDhcpClientInfo->ClientLeaseExpires.dwLowDateTime == 0) && (pDhcpClientInfo->ClientLeaseExpires.dwHighDateTime == 0) ) { // // This is an inactive reservation // m_strLeaseExpires.LoadString(IDS_DHCP_INFINITE_LEASE_INACTIVE); } else { m_strLeaseExpires.LoadString(IDS_DHCP_INFINITE_LEASE_ACTIVE); } } /*!-------------------------------------------------------------------------- CDhcpReservationClient::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::InitializeNode ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = hrOK; CString strIpAddress, strDisplayName; // // Create the display name for this scope // Convert DHCP_IP_ADDRES to a string and initialize this object // UtilCvtIpAddrToWstr (m_dhcpClientIpAddress, &strIpAddress); BuildDisplayName(&strDisplayName, strIpAddress, *m_pstrClientName); SetDisplayName(strDisplayName); // Make the node immediately visible pNode->SetVisibilityState(TFS_VIS_SHOW); pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE)); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode); pNode->SetData(TFS_DATA_USER, (LPARAM) this); pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_RESERVATION_CLIENT); pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE); SetColumnStringIDs(&aColumns[DHCPSNAP_RESERVATION_CLIENT][0]); SetColumnWidths(&aColumnWidths[DHCPSNAP_RESERVATION_CLIENT][0]); return hr; } /*--------------------------------------------------------------------------- CDhcpReservationClient::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strScopeIpAddress, strResIpAddress, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode, TRUE)->GetAddress(); UtilCvtIpAddrToWstr (dhcpIpAddress, &strScopeIpAddress); UtilCvtIpAddrToWstr (m_dhcpClientIpAddress, &strResIpAddress); strId = GetServerName(pNode, TRUE) + strScopeIpAddress + strResIpAddress + strGuid; return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservationClient::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CDhcpReservationClient::GetImageIndex(BOOL bOpenImage) { int nIndex = -1; switch (m_nState) { case notLoaded: case loaded: if (bOpenImage) nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_OPEN; else nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED; break; case loading: if (bOpenImage) nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_OPEN_BUSY; else nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED_BUSY; break; case unableToLoad: if (bOpenImage) nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_OPEN_LOST_CONNECTION; else nIndex = ICON_IDX_CLIENT_OPTION_FOLDER_CLOSED_LOST_CONNECTION; break; default: ASSERT(FALSE); } return nIndex; } /*--------------------------------------------------------------------------- Overridden base handler functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpReservationClient::OnAddMenuItems Adds entries to the context sensitive menu Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservationClient::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) { if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) { strMenuText.LoadString(IDS_CREATE_OPTION_RESERVATION); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_CREATE_OPTION_RESERVATION, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); } } return hr; } /*--------------------------------------------------------------------------- CDhcpReservationClient::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservationClient::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; case IDS_DELETE: OnDelete(pNode); break; case IDS_CREATE_OPTION_RESERVATION: OnCreateNewOptions(pNode); break; default: break; } return hr; } /*--------------------------------------------------------------------------- CDhcpReservationClient::CompareItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(int) CDhcpReservationClient::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; CDhcpOptionItem *pOpt1 = GETHANDLER(CDhcpOptionItem, spNode1); CDhcpOptionItem *pOpt2 = GETHANDLER(CDhcpOptionItem, spNode2); switch (nCol) { case 0: { // // Name compare - use the option # // LONG_PTR uImage1 = spNode1->GetData(TFS_DATA_IMAGEINDEX); LONG_PTR uImage2 = spNode2->GetData(TFS_DATA_IMAGEINDEX); nCompare = UtilGetOptionPriority((int) uImage1, (int) uImage2); if (nCompare == 0) { DHCP_OPTION_ID id1 = pOpt1->GetOptionId(); DHCP_OPTION_ID id2 = pOpt2->GetOptionId(); if (id1 < id2) nCompare = -1; else if (id1 > id2) nCompare = 1; } } break; case 1: { // compare the vendor strings CString str1, str2; str1 = pOpt1->GetVendorDisplay(); str2 = pOpt2->GetVendorDisplay(); nCompare = str1.CompareNoCase(str2); } break; case 2: { // compare the printable values CString str1, str2; str1 = pOpt1->GetString( pComponent, cookieA, nCol ); str2 = pOpt2->GetString( pComponent, cookieB, nCol ); nCompare = str1.CompareNoCase( str2 ); break; } case 3: { CString str1, str2; str1 = pOpt1->GetClassName(); str2 = pOpt2->GetClassName(); nCompare = str1.CompareNoCase(str2); } break; } return nCompare; } /*!-------------------------------------------------------------------------- CDhcpReservationClient::OnResultSelect Update the verbs and the result pane message Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::OnResultSelect(ITFSComponent *pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam) { HRESULT hr = hrOK; SPITFSNode spNode; CORg(CMTDhcpHandler::OnResultSelect(pComponent, pDataObject, cookie, arg, lParam)); CORg (pComponent->GetSelectedNode(&spNode)); if ( spNode != 0 ) { UpdateResultMessage(spNode); } Error: return hr; } /*!-------------------------------------------------------------------------- CDhcpReservationClient::UpdateResultMessage Figures out what message to put in the result pane, if any Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpReservationClient::UpdateResultMessage(ITFSNode * pNode) { HRESULT hr = hrOK; int nMessage = -1; // default int nVisible, nTotal; int i; CString strTitle, strBody, strTemp; if (!m_dwErr) { pNode->GetChildCount(&nVisible, &nTotal); // determine what message to display if ( (m_nState == notLoaded) || (m_nState == loading) ) { nMessage = -1; } else if (nTotal == 0) { nMessage = RES_OPTIONS_MESSAGE_NO_OPTIONS; } // build the strings if (nMessage != -1) { // now build the text strings // first entry is the title strTitle.LoadString(g_uResOptionsMessages[nMessage][0]); // second entry is the icon // third ... n entries are the body strings for (i = 2; g_uResOptionsMessages[nMessage][i] != 0; i++) { strTemp.LoadString(g_uResOptionsMessages[nMessage][i]); strBody += strTemp; } } } // show the message if (nMessage == -1) { ClearMessage(pNode); } else { ShowMessage(pNode, strTitle, strBody, (IconIdentifier) g_uResOptionsMessages[nMessage][1]); } } /*!-------------------------------------------------------------------------- CDhcpReservationClient::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 CDhcpReservationClient::OnDelete ( ITFSNode * pNode, LPARAM arg, LPARAM lParam ) { return OnDelete(pNode); } /*--------------------------------------------------------------------------- Command handlers ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::OnCreateNewOptions ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CPropertyPageHolderBase * pPropSheet; CString strOptCfgTitle, strOptType; SPITFSNode spServerNode; SPIComponentData spComponentData; COptionsConfig * pOptCfg; DHCP_OPTION_SCOPE_INFO dhcpScopeInfo; HRESULT hr = hrOK; COM_PROTECT_TRY { CString strOptCfgTitle, strOptType; SPIComponentData spComponentData; BOOL fFound = FALSE; strOptType.LoadString(IDS_CONFIGURE_OPTIONS_CLIENT); AfxFormatString1(strOptCfgTitle, IDS_CONFIGURE_OPTIONS_TITLE, strOptType); // this gets kinda weird because we implemented the option config page // as a property page, so technically this node has two property pages. // // search the open prop pages to see if the option config is up // if it's up, set it active instead of creating a new one. for (int i = 0; i < HasPropSheetsOpen(); i++) { GetOpenPropSheet(i, &pPropSheet); HWND hwnd = pPropSheet->GetSheetWindow(); CString strTitle; ::GetWindowText(hwnd, strTitle.GetBuffer(256), 256); strTitle.ReleaseBuffer(); if (strTitle == strOptCfgTitle) { pPropSheet->SetActiveWindow(); fFound = TRUE; break; } } if (!fFound) { m_spNodeMgr->GetComponentData(&spComponentData); m_fResProp = FALSE; hr = DoPropertiesOurselvesSinceMMCSucks(pNode, spComponentData, strOptCfgTitle); m_fResProp = TRUE; } } COM_PROTECT_CATCH; return hr; } /*--------------------------------------------------------------------------- CDhcpReservationClient::OnDelete Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpReservationClient::OnDelete ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString strMessage, strTemp; DWORD dwError = 0; CDhcpReservations *pResrv; pResrv = GETHANDLER( CDhcpReservations, pNode ); // Check for any open property sheets if ( pResrv->HasPropSheetsOpen()) { AfxMessageBox( IDS_MSG_CLOSE_PROPSHEET ); return ERROR_INVALID_PARAMETER; } UtilCvtIpAddrToWstr (m_dhcpClientIpAddress, &strTemp); AfxFormatString1(strMessage, IDS_DELETE_RESERVATION, (LPCTSTR) strTemp); if (AfxMessageBox(strMessage, MB_YESNO) == IDYES) { BEGIN_WAIT_CURSOR; dwError = GetScopeObject(pNode, TRUE)->DeleteReservation(m_baHardwareAddress, m_dhcpClientIpAddress); if (dwError != 0) { // // OOOpss. Something happened, reservation not // deleted, so don't remove from UI and put up a message box // ::DhcpMessageBox(dwError); } else { CDhcpScope * pScope = NULL; SPITFSNode spActiveLeasesNode; pScope = GetScopeObject(pNode, TRUE); pScope->GetActiveLeasesNode(&spActiveLeasesNode); pScope->GetActiveLeasesObject()->DeleteClient(spActiveLeasesNode, m_dhcpClientIpAddress); SPITFSNode spReservationsNode; pNode->GetParent(&spReservationsNode); spReservationsNode->RemoveChild(pNode); // update stats pScope->TriggerStatsRefresh(); } // else END_WAIT_CURSOR; } // if return dwError; } // CDhcpReservationClient::OnDelete() /*--------------------------------------------------------------------------- CDhcpReservationClient::OnResultPropertyChange Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::OnResultPropertyChange ( ITFSComponent * pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM param ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); SPITFSNode spNode; m_spNodeMgr->FindNode(cookie, &spNode); COptionsConfig * pOptCfg = reinterpret_cast(param); LPARAM changeMask = 0; // tell the property page to do whatever now that we are back on the // main thread pOptCfg->OnPropertyChange(TRUE, &changeMask); pOptCfg->AcknowledgeNotify(); if (changeMask) spNode->ChangeNode(changeMask); return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservationClient::CreatePropertyPages Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservationClient::CreatePropertyPages ( ITFSNode * pNode, LPPROPERTYSHEETCALLBACK lpProvider, LPDATAOBJECT pDataObject, LONG_PTR handle, DWORD dwType ) { HRESULT hr = hrOK; if (m_fResProp) { hr = DoResPages(pNode, lpProvider, pDataObject, handle, dwType); } else { hr = DoOptCfgPages(pNode, lpProvider, pDataObject, handle, dwType); } return hr; } HRESULT CDhcpReservationClient::DoResPages ( ITFSNode * pNode, LPPROPERTYSHEETCALLBACK lpProvider, LPDATAOBJECT pDataObject, LONG_PTR handle, DWORD dwType ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // // Create the property page // SPIComponentData spComponentData; m_spNodeMgr->GetComponentData(&spComponentData); CReservedClientProperties * pResClientProp = new CReservedClientProperties(pNode, spComponentData, m_spTFSCompData, NULL); // Get the Server version and set it in the property sheet LARGE_INTEGER liVersion; CDhcpServer * pServer = GetScopeObject(pNode, TRUE)->GetServerObject(); pServer->GetVersion(liVersion); pResClientProp->SetVersion(liVersion); // fill in the data for the prop page pResClientProp->m_pageGeneral.m_dwClientAddress = m_dhcpClientIpAddress; if (m_pstrClientName) pResClientProp->m_pageGeneral.m_strName = *m_pstrClientName; if (m_pstrClientComment) pResClientProp->m_pageGeneral.m_strComment = *m_pstrClientComment; pResClientProp->SetClientType(m_bClientType); // fill in the UID string UtilCvtByteArrayToString(m_baHardwareAddress, pResClientProp->m_pageGeneral.m_strUID); // set the DNS registration option DWORD dwDynDnsFlags; DWORD dwError; BEGIN_WAIT_CURSOR; dwError = GetDnsRegistration(pNode, &dwDynDnsFlags); if (dwError != ERROR_SUCCESS) { ::DhcpMessageBox(dwError); return hrFalse; } END_WAIT_CURSOR; pResClientProp->SetDnsRegistration(dwDynDnsFlags, DhcpReservedOptions); // // Object gets deleted when the page is destroyed // Assert(lpProvider != NULL); return pResClientProp->CreateModelessSheet(lpProvider, handle); } HRESULT CDhcpReservationClient::DoOptCfgPages ( ITFSNode * pNode, LPPROPERTYSHEETCALLBACK lpProvider, LPDATAOBJECT pDataObject, LONG_PTR handle, DWORD dwType ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); DWORD dwError; DWORD dwDynDnsFlags; HRESULT hr = hrOK; COptionsConfig * pOptCfg; CString strOptCfgTitle, strOptType; SPITFSNode spServerNode; SPIComponentData spComponentData; COptionValueEnum * pOptionValueEnum; // // Create the property page // COM_PROTECT_TRY { m_spNodeMgr->GetComponentData(&spComponentData); BEGIN_WAIT_CURSOR; strOptType.LoadString(IDS_CONFIGURE_OPTIONS_CLIENT); AfxFormatString1(strOptCfgTitle, IDS_CONFIGURE_OPTIONS_TITLE, strOptType); GetScopeObject(pNode, TRUE)->GetServerNode(&spServerNode); pOptCfg = new COptionsConfig(pNode, spServerNode, spComponentData, m_spTFSCompData, GetOptionValueEnum(), strOptCfgTitle); END_WAIT_CURSOR; // // Object gets deleted when the page is destroyed // Assert(lpProvider != NULL); hr = pOptCfg->CreateModelessSheet(lpProvider, handle); } COM_PROTECT_CATCH return hr; } /*--------------------------------------------------------------------------- CDhcpReservationClient::OnPropertyChange Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::OnPropertyChange ( ITFSNode * pNode, LPDATAOBJECT pDataobject, DWORD dwType, LPARAM arg, LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CPropertyPageHolderBase * pProp = reinterpret_cast(lParam); LONG_PTR changeMask = 0; // tell the property page to do whatever now that we are back on the // main thread pProp->OnPropertyChange(TRUE, &changeMask); pProp->AcknowledgeNotify(); if (changeMask) pNode->ChangeNode(changeMask); return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservationClient::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 CDhcpReservationClient::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 spResClient, spSelectedNode; DWORD dwError; m_spNodeMgr->FindNode(cookie, &spResClient); pComponent->GetSelectedNode(&spSelectedNode); Assert(spSelectedNode == spResClient); if (spSelectedNode != spResClient) 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; } // check to make sure we are deleting just scope options POSITION pos = listNodesToDelete.GetHeadPosition(); while (pos) { ITFSNode * pNode = listNodesToDelete.GetNext(pos); if (pNode->GetData(TFS_DATA_IMAGEINDEX) != ICON_IDX_CLIENT_OPTION_LEAF) { // this option is not scope option. Put up a dialog telling the user what to do AfxMessageBox(IDS_CANNOT_DELETE_OPTION_RES); return NOERROR; } } CString strServer = GetServerIpAddress(spResClient, TRUE); DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo; dhcpOptionScopeInfo.ScopeType = DhcpReservedOptions; dhcpOptionScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = m_dhcpClientIpAddress; CDhcpScope * pScope = GetScopeObject(spResClient, TRUE); dhcpOptionScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = pScope->GetAddress(); // // Loop through all items deleting // BEGIN_WAIT_CURSOR; while (listNodesToDelete.GetCount() > 0) { SPITFSNode spOptionNode; spOptionNode = listNodesToDelete.RemoveHead(); CDhcpOptionItem * pOptItem = GETHANDLER(CDhcpOptionItem, spOptionNode); // // Try to remove it from the server // if (pOptItem->IsVendorOption() || pOptItem->IsClassOption()) { LPCTSTR pClassName = pOptItem->GetClassName(); if (lstrlen(pClassName) == 0) pClassName = NULL; dwError = ::DhcpRemoveOptionValueV5((LPTSTR) ((LPCTSTR) strServer), pOptItem->IsVendorOption() ? DHCP_FLAGS_OPTION_IS_VENDOR : 0, pOptItem->GetOptionId(), (LPTSTR) pClassName, (LPTSTR) pOptItem->GetVendor(), &dhcpOptionScopeInfo); } else { dwError = ::DhcpRemoveOptionValue(strServer, pOptItem->GetOptionId(), &dhcpOptionScopeInfo); } if (dwError != 0) { ::DhcpMessageBox(dwError); RESTORE_WAIT_CURSOR; hr = E_FAIL; continue; } GetOptionValueEnum()->Remove(pOptItem->GetOptionId(), pOptItem->GetVendor(), pOptItem->GetClassName()); // // Remove from UI now // spResClient->RemoveChild(spOptionNode); spOptionNode.Release(); } END_WAIT_CURSOR; UpdateResultMessage(spResClient); return hr; } /*!-------------------------------------------------------------------------- CDhcpReservationClient::OnGetResultViewType MMC calls this to get the result view information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::OnGetResultViewType ( ITFSComponent * pComponent, MMC_COOKIE cookie, LPOLESTR * ppViewType, long * pViewOptions ) { HRESULT hr = hrOK; // call the base class to see if it is handling this if (CMTDhcpHandler::OnGetResultViewType(pComponent, cookie, ppViewType, pViewOptions) != S_OK) { *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT; hr = S_FALSE; } return hr; } /*!-------------------------------------------------------------------------- CDhcpReservationClient::OnHaveData Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpReservationClient::OnHaveData ( ITFSNode * pParentNode, LPARAM Data, LPARAM Type ) { // This is how we get non-node data back from the background thread. switch (Type) { case DHCP_QDATA_OPTION_VALUES: { HRESULT hr = hrOK; SPIComponentData spCompData; SPIConsole spConsole; SPIDataObject spDataObject; IDataObject * pDataObject; COptionValueEnum * pOptionValueEnum = reinterpret_cast(Data); SetOptionValueEnum(pOptionValueEnum); pOptionValueEnum->RemoveAll(); delete pOptionValueEnum; // now tell the view to update themselves m_spNodeMgr->GetComponentData(&spCompData); CORg ( spCompData->QueryDataObject((MMC_COOKIE) pParentNode, CCT_SCOPE, &pDataObject) ); spDataObject = pDataObject; CORg ( m_spNodeMgr->GetConsole(&spConsole) ); CORg ( spConsole->UpdateAllViews(pDataObject, (LPARAM) pParentNode, DHCPSNAP_UPDATE_OPTIONS) ); break; } } Error: return; } /*!-------------------------------------------------------------------------- CDhcpReservationClient::OnNotifyExiting CMTDhcpHandler overridden functionality allows us to know when the background thread is done Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservationClient::OnNotifyExiting ( LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); SPITFSNode spNode; spNode.Set(m_spNode); // save this off because OnNotifyExiting will release it HRESULT hr = CMTDhcpHandler::OnNotifyExiting(lParam); UpdateResultMessage(spNode); return hr; } /*!-------------------------------------------------------------------------- CDhcpReservationClient::OnResultUpdateView Implementation of ITFSResultHandler::OnResultUpdateView Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::OnResultUpdateView ( ITFSComponent *pComponent, LPDATAOBJECT pDataObject, LPARAM data, LPARAM hint ) { HRESULT hr = hrOK; SPITFSNode spSelectedNode; pComponent->GetSelectedNode(&spSelectedNode); if (spSelectedNode == NULL) return S_OK; // no selection for our IComponentData if ( hint == DHCPSNAP_UPDATE_OPTIONS ) { SPINTERNAL spInternal = ExtractInternalFormat(pDataObject); ITFSNode * pNode = reinterpret_cast(spInternal->m_cookie); SPITFSNode spSelectedNode; pComponent->GetSelectedNode(&spSelectedNode); EnumerateResultPane(pComponent, (MMC_COOKIE) spSelectedNode.p, 0, 0); } else { // we don't handle this message, let the base class do it. return CMTDhcpHandler::OnResultUpdateView(pComponent, pDataObject, data, hint); } return hr; } /*!-------------------------------------------------------------------------- CDhcpReservationClient::EnumerateResultPane We override this function for the options nodes for one reason. Whenever an option class is deleted, then all options defined for that class will be removed as well. Since there are multiple places that these options may show up, it's easier to just not show any options that don't have a class defined for it. Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::EnumerateResultPane ( ITFSComponent * pComponent, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CClassInfoArray ClassInfoArray; SPITFSNode spContainer, spServerNode; CDhcpServer * pServer; COptionValueEnum * aEnum[3]; int aImages[3] = {ICON_IDX_CLIENT_OPTION_LEAF, ICON_IDX_SCOPE_OPTION_LEAF, ICON_IDX_SERVER_OPTION_LEAF}; m_spNodeMgr->FindNode(cookie, &spContainer); spServerNode = GetServerNode(spContainer, TRUE); pServer = GETHANDLER(CDhcpServer, spServerNode); pServer->GetClassInfoArray(ClassInfoArray); aEnum[0] = GetOptionValueEnum(); aEnum[1] = GetScopeObject(spContainer, TRUE)->GetOptionValueEnum(); aEnum[2] = pServer->GetOptionValueEnum(); aEnum[0]->Reset(); aEnum[1]->Reset(); aEnum[2]->Reset(); return OnResultUpdateOptions(pComponent, spContainer, &ClassInfoArray, aEnum, aImages, 3); } /*--------------------------------------------------------------------------- Helper functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpReservationClient::GetDnsRegistration Gets the DNS registration option value Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpReservationClient::GetDnsRegistration ( ITFSNode * pNode, LPDWORD pDnsRegOption ) { // // Check option 81 -- the DNS registration option // CDhcpScope * pScope = GetScopeObject(pNode, TRUE); DHCP_OPTION_VALUE * poptValue = NULL; DWORD err = pScope->GetOptionValue(OPTION_DNS_REGISTATION, DhcpReservedOptions, &poptValue, m_dhcpClientIpAddress); // this is the default if (pDnsRegOption) *pDnsRegOption = DHCP_DYN_DNS_DEFAULT; if (err == ERROR_SUCCESS) { if ((poptValue->Value.Elements != NULL) && (pDnsRegOption)) { *pDnsRegOption = poptValue->Value.Elements[0].Element.DWordOption; } } else { Trace0("CDhcpReservationClient::GetDnsRegistration - couldn't get DNS reg value -- \ option may not be defined, Getting Scope value.\n"); err = pScope->GetDnsRegistration(pDnsRegOption); } if (poptValue) ::DhcpRpcFreeMemory(poptValue); return err; } /*--------------------------------------------------------------------------- CDhcpReservationClient::SetDnsRegistration Sets the DNS Registration option for this scope Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpReservationClient::SetDnsRegistration ( ITFSNode * pNode, DWORD DnsRegOption ) { CDhcpScope * pScope = GetScopeObject(pNode, TRUE); DWORD err = 0; // // Set DNS name registration (option 81) // CDhcpOption dhcpOption (OPTION_DNS_REGISTATION, DhcpDWordOption , _T(""), _T("")); dhcpOption.QueryValue().SetNumber(DnsRegOption); err = pScope->SetOptionValue(&dhcpOption, DhcpReservedOptions, m_dhcpClientIpAddress); return err; } /*--------------------------------------------------------------------------- CDhcpReservationClient::BuildDisplayName Builds the display name string Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::BuildDisplayName ( CString * pstrDisplayName, LPCTSTR pIpAddress, LPCTSTR pName ) { if (pstrDisplayName) { CString strTemp = pIpAddress; strTemp = L"[" + strTemp + L"]"; if (pName) { CString strName = pName; strTemp += L" " + strName; } *pstrDisplayName = strTemp; } return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservationClient::BuildDisplayName Updates the cached name for this reservation and updates the UI Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::SetName ( LPCTSTR pName ) { if (pName != NULL) { if (m_pstrClientName) { *m_pstrClientName = pName; } else { m_pstrClientName = new CString(pName); } } else { if (m_pstrClientName) { delete m_pstrClientName; m_pstrClientName = NULL; } } CString strIpAddress, strDisplayName; // // Create the display name for this scope // Convert DHCP_IP_ADDRES to a string and initialize this object // UtilCvtIpAddrToWstr (m_dhcpClientIpAddress, &strIpAddress); BuildDisplayName(&strDisplayName, strIpAddress, pName); SetDisplayName(strDisplayName); return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservationClient::BuildDisplayName Updates the cached comment for this reservation Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::SetComment ( LPCTSTR pComment ) { if (pComment != NULL) { if (m_pstrClientComment) { *m_pstrClientComment = pComment; } else { m_pstrClientComment = new CString(pComment); } } else { if (m_pstrClientComment) { delete m_pstrClientComment; m_pstrClientComment = NULL; } } return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservationClient::SetUID Updates the cached unique ID for this reservation Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpReservationClient::SetUID ( const CByteArray & baClientUID ) { m_baHardwareAddress.Copy(baClientUID); return hrOK; } /*--------------------------------------------------------------------------- CDhcpReservationClient::SetClientType Updates the cached client type for this record Author: EricDav ---------------------------------------------------------------------------*/ BYTE CDhcpReservationClient::SetClientType ( BYTE bClientType ) { BYTE bRet = m_bClientType; m_bClientType = bClientType; return bRet; } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpReservationClient::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CDhcpReservationClient::OnCreateQuery(ITFSNode * pNode) { CDhcpReservationClientQueryObj* pQuery = new CDhcpReservationClientQueryObj(m_spTFSCompData, m_spNodeMgr); pQuery->m_strServer = GetServerIpAddress(pNode, TRUE); pQuery->m_dhcpScopeAddress = GetScopeObject(pNode, TRUE)->GetAddress(); pQuery->m_dhcpClientIpAddress = m_dhcpClientIpAddress; GetScopeObject(pNode, TRUE)->GetServerVersion(pQuery->m_liDhcpVersion); GetScopeObject(pNode, TRUE)->GetDynBootpClassName(pQuery->m_strDynBootpClassName); pQuery->m_dhcpResumeHandle = NULL; pQuery->m_dwPreferredMax = 0xFFFFFFFF; return pQuery; } /*--------------------------------------------------------------------------- CDhcpReservationClientQueryObj::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpReservationClientQueryObj::Execute() { DWORD dwErr; COptionNodeEnum OptionNodeEnum(m_spTFSCompData, m_spNodeMgr); DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo; COptionValueEnum * pOptionValueEnum = new COptionValueEnum; pOptionValueEnum->m_strDynBootpClassName = m_strDynBootpClassName; dhcpOptionScopeInfo.ScopeType = DhcpReservedOptions; dhcpOptionScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpAddress = m_dhcpClientIpAddress; dhcpOptionScopeInfo.ScopeInfo.ReservedScopeInfo.ReservedIpSubnetAddress = m_dhcpScopeAddress; pOptionValueEnum->Init(m_strServer, m_liDhcpVersion, dhcpOptionScopeInfo); dwErr = pOptionValueEnum->Enum(); // add all of the nodes if (dwErr != ERROR_SUCCESS) { Trace1("CDhcpReservationClientQueryObj::Execute - Enum Failed! %d\n", dwErr); m_dwErr = dwErr; PostError(dwErr); delete pOptionValueEnum; } else { pOptionValueEnum->SortById(); AddToQueue((LPARAM) pOptionValueEnum, DHCP_QDATA_OPTION_VALUES); } return hrFalse; } ///////////////////////////////////////////////////////////////////// // // CDhcpActiveLeases implementation // ///////////////////////////////////////////////////////////////////// /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpActiveLeases::CDhcpActiveLeases ( ITFSComponentData * pComponentData ) : CMTDhcpHandler(pComponentData) { } CDhcpActiveLeases::~CDhcpActiveLeases() { } /*!-------------------------------------------------------------------------- CDhcpActiveLeases::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpActiveLeases::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, GetImageIndex(FALSE)); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode); pNode->SetData(TFS_DATA_USER, (LPARAM) this); pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_ACTIVE_LEASES); pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE); SetColumnStringIDs(&aColumns[DHCPSNAP_ACTIVE_LEASES][0]); SetColumnWidths(&aColumnWidths[DHCPSNAP_ACTIVE_LEASES][0]); return hr; } /*--------------------------------------------------------------------------- CDhcpActiveLeases::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpActiveLeases::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strIpAddress, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode)->GetAddress(); UtilCvtIpAddrToWstr (dhcpIpAddress, &strIpAddress); strId = GetServerName(pNode) + strIpAddress + strGuid; return hrOK; } /*--------------------------------------------------------------------------- CDhcpActiveLeases::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CDhcpActiveLeases::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 ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpActiveLeases::OnAddMenuItems Adds entries to the context sensitive menu Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpActiveLeases::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) { if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) { /* removed, using new MMC save list functionality strMenuText.LoadString(IDS_EXPORT_LEASE_INFO); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_EXPORT_LEASE_INFO, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); */ } } return hr; } /*--------------------------------------------------------------------------- CDhcpActiveLeases::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpActiveLeases::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; case IDS_EXPORT_LEASE_INFO: OnExportLeases(pNode); break; default: break; } return hr; } /*--------------------------------------------------------------------------- CDhcpActiveLeases::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 CDhcpActiveLeases::OnResultDelete ( ITFSComponent * pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM param ) { HRESULT hr = hrOK; BOOL bIsRes, bIsActive, bBadAddress; 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(); CDhcpActiveLease * pActiveLease = GETHANDLER(CDhcpActiveLease, spActiveLeaseNode); // // delete the node, check to see if it is a reservation // bIsRes = pActiveLease->IsReservation(&bIsActive, &bBadAddress); if (bIsRes && !bBadAddress) { // // Delete the reservation // LPDHCP_CLIENT_INFO pdhcpClientInfo; DWORD dwError = GetScopeObject(spActiveLeases)->GetClientInfo(pActiveLease->GetIpAddress(), &pdhcpClientInfo); if (dwError == ERROR_SUCCESS) { dwError = GetScopeObject(spActiveLeases)->DeleteReservation(pdhcpClientInfo->ClientHardwareAddress, pdhcpClientInfo->ClientIpAddress); if (dwError == ERROR_SUCCESS) { // // Tell the reservations folder to remove this from it's list // SPITFSNode spReservationsNode; GetScopeObject(spActiveLeases)->GetReservationsNode(&spReservationsNode); GetScopeObject(spActiveLeases)->GetReservationsObject()-> RemoveReservationFromUI((ITFSNode *) spReservationsNode, pActiveLease->GetIpAddress()); spActiveLeases->RemoveChild(spActiveLeaseNode); } else { UtilCvtIpAddrToWstr(pActiveLease->GetIpAddress(), &strTemp); AfxFormatString1(strMessage, IDS_ERROR_DELETING_RECORD, (LPCTSTR) strTemp); if (::DhcpMessageBoxEx(dwError, strMessage, MB_OKCANCEL) == IDCANCEL) { break; } RESTORE_WAIT_CURSOR; Trace1("Delete reservation failed %lx\n", dwError); hr = E_FAIL; } ::DhcpRpcFreeMemory(pdhcpClientInfo); } else { UtilCvtIpAddrToWstr(pActiveLease->GetIpAddress(), &strTemp); AfxFormatString1(strMessage, IDS_ERROR_DELETING_RECORD, (LPCTSTR) strTemp); if (::DhcpMessageBoxEx(dwError, strMessage, MB_OKCANCEL) == IDCANCEL) { break; } RESTORE_WAIT_CURSOR; Trace1("GetClientInfo failed %lx\n", dwError); hr = E_FAIL; } } else { DWORD dwError = GetScopeObject(spActiveLeases)->DeleteClient(pActiveLease->GetIpAddress()); if (dwError == ERROR_SUCCESS) { // // Client gone, now remove from UI // spActiveLeases->RemoveChild(spActiveLeaseNode); // if we are deleting a lot of addresses, then we can hit the server hard.. // lets take a short time out to smooth out the process Sleep(5); } else { UtilCvtIpAddrToWstr(pActiveLease->GetIpAddress(), &strTemp); AfxFormatString1(strMessage, IDS_ERROR_DELETING_RECORD, (LPCTSTR) strTemp); if (::DhcpMessageBoxEx(dwError, strMessage, MB_OKCANCEL) == IDCANCEL) { break; } RESTORE_WAIT_CURSOR; Trace1("DhcpDeleteClientInfo failed %lx\n", dwError); hr = E_FAIL; } } spActiveLeaseNode.Release(); } // update stats GetScopeObject(spActiveLeases)->TriggerStatsRefresh(); END_WAIT_CURSOR; return hr; } /*--------------------------------------------------------------------------- CDhcpActiveLeases::DeleteClient The reservations object will call this when a reservation is deleted. Since a reservation also has an active lease record, we have to delete it as well. Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpActiveLeases::DeleteClient ( ITFSNode * pActiveLeasesNode, DHCP_IP_ADDRESS dhcpIpAddress ) { DWORD dwError = E_UNEXPECTED; CDhcpActiveLease * pActiveLease = NULL; SPITFSNodeEnum spNodeEnum; SPITFSNode spCurrentNode; ULONG nNumReturned = 0; pActiveLeasesNode->GetEnum(&spNodeEnum); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); while (nNumReturned) { pActiveLease = GETHANDLER(CDhcpActiveLease, spCurrentNode); if (dhcpIpAddress == pActiveLease->GetIpAddress()) { // // Tell this reservation to delete itself // pActiveLeasesNode->RemoveChild(spCurrentNode); spCurrentNode.Release(); dwError = ERROR_SUCCESS; break; } spCurrentNode.Release(); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); } return dwError; } /*!-------------------------------------------------------------------------- CDhcpActiveLeases::OnGetResultViewType MMC calls this to get the result view information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpActiveLeases::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; } /*--------------------------------------------------------------------------- CDhcpActiveLeases::CompareItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(int) CDhcpActiveLeases::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; CDhcpActiveLease *pDhcpAL1 = GETHANDLER(CDhcpActiveLease, spNode1); CDhcpActiveLease *pDhcpAL2 = GETHANDLER(CDhcpActiveLease, 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); nCompare = strAL1.CompareNoCase(strAL2); } break; case 2: { // Lease expiration compare // BOOL bIsActive1, bIsActive2; BOOL bIsBad1, bIsBad2; BOOL bIsRes1 = pDhcpAL1->IsReservation(&bIsActive1, &bIsBad1); BOOL bIsRes2 = pDhcpAL2->IsReservation(&bIsActive2, &bIsBad2); // // Check to see if these are reservations // if (bIsRes1 && bIsRes2) { // // Figure out if this is a bad address // They go first // if (bIsBad1 && bIsBad2) { // // Sort by IP Address // nCompare = CompareIpAddresses(pDhcpAL1, pDhcpAL2); } else if (bIsBad1) nCompare = -1; else if (bIsBad2) nCompare = 1; else if ((bIsActive1 && bIsActive2) || (!bIsActive1 && !bIsActive2)) { // // if both reservations are either active/inactive // sort by IP address // nCompare = CompareIpAddresses(pDhcpAL1, pDhcpAL2); } else if (bIsActive1) nCompare = -1; else nCompare = 1; } else if (bIsRes1) { nCompare = -1; } else if (bIsRes2) { nCompare = 1; } else { CTime timeAL1, timeAL2; pDhcpAL1->GetLeaseExpirationTime(timeAL1); pDhcpAL2->GetLeaseExpirationTime(timeAL2); if (timeAL1 < timeAL2) nCompare = -1; else if (timeAL1 > timeAL2) nCompare = 1; } // default is that they are equal } break; case 3: { // Client Type Compare CString strAL1 = pDhcpAL1->GetString(pComponent, cookieA, nCol); CString strAL2 = pDhcpAL2->GetString(pComponent, cookieA, nCol); nCompare = strAL1.Compare(strAL2); } break; case 4: { CString strUID1 = pDhcpAL1->GetUID(); nCompare = strUID1.CompareNoCase(pDhcpAL2->GetUID()); } break; case 5: { CString strComment1 = pDhcpAL1->GetComment(); nCompare = strComment1.CompareNoCase(pDhcpAL2->GetComment()); } break; } return nCompare; } /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ int CDhcpActiveLeases::CompareIpAddresses ( CDhcpActiveLease * pDhcpAL1, CDhcpActiveLease * 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; } /*--------------------------------------------------------------------------- CDhcpActiveLeases::OnExportLeases() - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpActiveLeases::OnExportLeases(ITFSNode * pNode) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = hrOK; // Bring up the Save Dialog SPITFSNodeEnum spNodeEnum; SPITFSNode spCurrentNode; ULONG nNumReturned = 0; CString strType; CString strDefFileName; CString strFilter; CString strTitle; CString strFileName; strType.LoadString(IDS_FILE_EXTENSION); strDefFileName.LoadString(IDS_FILE_DEFNAME); strFilter.LoadString(IDS_STR_EXPORTFILE_FILTER); CFileDialog cFileDlg(FALSE, strType, strDefFileName, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, strFilter);//_T("Comma Separated Files (*.csv)|*.csv||") ); strTitle.LoadString(IDS_EXPFILE_TITLE); cFileDlg.m_ofn.lpstrTitle = strTitle; // put up the file dialog if( cFileDlg.DoModal() != IDOK ) return hrFalse; strFileName = cFileDlg.GetPathName(); COM_PROTECT_TRY { CString strContent; CString strLine; CString strTemp; CString strDelim = _T(','); CString strNewLine = _T("\r\n"); int nCount = 0; // create a file named "WinsExp.txt" in the current directory CFile cFileExp(strFileName, CFile::modeCreate | CFile::modeRead | CFile::modeWrite); // this is a unicode file, write the unicde lead bytes (2) cFileExp.Write(&gwUnicodeHeader, sizeof(WORD)); // write the header for (int i = 0; i < MAX_COLUMNS; i++) { if (aColumns[DHCPSNAP_ACTIVE_LEASES][i]) { if (!strLine.IsEmpty()) strLine += strDelim; strTemp.LoadString(aColumns[DHCPSNAP_ACTIVE_LEASES][i]); strLine += strTemp; } } strLine += strNewLine; cFileExp.Write(strLine, strLine.GetLength()*sizeof(TCHAR)); cFileExp.SeekToEnd(); BEGIN_WAIT_CURSOR #ifdef DEBUG CTime timeStart, timeFinish; timeStart = CTime::GetCurrentTime(); #endif // enumerate all the leases and output pNode->GetEnum(&spNodeEnum); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); while (nNumReturned) { CDhcpActiveLease * pLease = GETHANDLER(CDhcpActiveLease, spCurrentNode); strLine.Empty(); // ipaddr, name, type, lease exp, UID, comment for (int j = 0; j < 6; j++) { if (!strLine.IsEmpty()) strLine += strDelim; strLine += pLease->GetString(NULL, NULL, j); } strLine += strNewLine; strContent += strLine; nCount++; //optimize // write to the file for every 1000 records converted if( nCount % 1000 == 0) { cFileExp.Write(strContent, strContent.GetLength() * (sizeof(TCHAR)) ); cFileExp.SeekToEnd(); // clear all the strings now strContent.Empty(); } spCurrentNode.Release(); spNodeEnum->Next(1, &spCurrentNode, &nNumReturned); } // write to the file cFileExp.Write(strContent, strContent.GetLength() * (sizeof(TCHAR)) ); cFileExp.Close(); #ifdef DEBUG timeFinish = CTime::GetCurrentTime(); CTimeSpan timeDelta = timeFinish - timeStart; Trace2("ActiveLeases - Export Entries: %d records written, total time %s\n", nCount, timeDelta.Format(_T("%H:%M:%S"))); #endif END_WAIT_CURSOR } COM_PROTECT_CATCH CString strDisp; AfxFormatString1(strDisp, IDS_EXPORT_SUCCESS, strFileName); AfxMessageBox(strDisp, MB_ICONINFORMATION ); return hr; } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpActiveLeases::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CDhcpActiveLeases::OnCreateQuery(ITFSNode * pNode) { CDhcpActiveLeasesQueryObj* pQuery = new CDhcpActiveLeasesQueryObj(m_spTFSCompData, m_spNodeMgr); pQuery->m_strServer = GetServerIpAddress(pNode); pQuery->m_dhcpScopeAddress = GetScopeObject(pNode)->GetAddress(); pQuery->m_dhcpResumeHandle = NULL; pQuery->m_dwPreferredMax = 2000; GetServerVersion(pNode, pQuery->m_liDhcpVersion); return pQuery; } /*--------------------------------------------------------------------------- CDhcpActiveLeasesQueryObj::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpActiveLeasesQueryObj::Execute() { HRESULT hr; BuildReservationList(); if (m_liDhcpVersion.QuadPart >= DHCP_NT5_VERSION) { hr = EnumerateLeasesV5(); } else if (m_liDhcpVersion.QuadPart >= DHCP_SP2_VERSION) { hr = EnumerateLeasesV4(); } else { hr = EnumerateLeases(); } return hr; } /*--------------------------------------------------------------------------- CDhcpActiveLeasesQueryObj::IsReservation() Description Author: EricDav ---------------------------------------------------------------------------*/ BOOL CDhcpActiveLeasesQueryObj::IsReservation(DWORD dwIp) { BOOL fIsRes = FALSE; for (int i = 0; i < m_ReservationArray.GetSize(); i++) { if (m_ReservationArray[i] == dwIp) { fIsRes = TRUE; break; } } return fIsRes; } /*--------------------------------------------------------------------------- CDhcpActiveLeasesQueryObj::BuildReservationList() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpActiveLeasesQueryObj::BuildReservationList() { LPDHCP_SUBNET_ELEMENT_INFO_ARRAY pdhcpSubnetElementArray = NULL; DHCP_RESUME_HANDLE dhcpResumeHandle = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0; DWORD dwError = ERROR_MORE_DATA; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetElements(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, DhcpReservedIps, &dhcpResumeHandle, -1, &pdhcpSubnetElementArray, &dwElementsRead, &dwElementsTotal); Trace3("BuildReservationList: Scope %lx Reservations read %d, total %d\n", m_dhcpScopeAddress, dwElementsRead, dwElementsTotal); if (dwElementsRead && dwElementsTotal && pdhcpSubnetElementArray) { // // Loop through the array that was returned // for (DWORD i = 0; i < pdhcpSubnetElementArray->NumElements; i++) { m_ReservationArray.Add(pdhcpSubnetElementArray->Elements[i].Element.ReservedIp->ReservedIpAddress); } } // 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: BuildReservationList error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } return hrFalse; } /*--------------------------------------------------------------------------- CDhcpActiveLeasesQueryObj::EnumerateLeasesV5() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpActiveLeasesQueryObj::EnumerateLeasesV5() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_CLIENT_INFO_ARRAY_V5 pdhcpClientArrayV5 = NULL; DWORD dwClientsRead = 0, dwClientsTotal = 0; DWORD dwEnumedClients = 0; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetClientsV5(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, &m_dhcpResumeHandle, m_dwPreferredMax, &pdhcpClientArrayV5, &dwClientsRead, &dwClientsTotal); if (dwClientsRead && dwClientsTotal && pdhcpClientArrayV5) { // // loop through all of the elements that were returned // for (DWORD i = 0; i < dwClientsRead; i++) { CDhcpActiveLease * pDhcpActiveLease; // // Create the result pane item for this element // SPITFSNode spNode; pDhcpActiveLease = new CDhcpActiveLease(m_spTFSCompData, pdhcpClientArrayV5->Clients[i]); // filter these types of records out if (pDhcpActiveLease->IsUnreg()) { delete pDhcpActiveLease; continue; } if (IsReservation(pdhcpClientArrayV5->Clients[i]->ClientIpAddress)) pDhcpActiveLease->SetReservation(TRUE); CreateLeafTFSNode(&spNode, &GUID_DhcpActiveLeaseNodeType, pDhcpActiveLease, pDhcpActiveLease, m_spNodeMgr); // Tell the handler to initialize any specific data pDhcpActiveLease->InitializeNode(spNode); AddToQueue(spNode); pDhcpActiveLease->Release(); } ::DhcpRpcFreeMemory(pdhcpClientArrayV5); dwEnumedClients += dwClientsRead; dwClientsRead = 0; dwClientsTotal = 0; pdhcpClientArrayV5 = 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: EnumerateLeasesV5 error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } Trace1("DHCP snapin: V5 Leases enumerated: %d\n", dwEnumedClients); return hrFalse; } /*--------------------------------------------------------------------------- CDhcpActiveLeasesQueryObj::EnumerateLeasesV4() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpActiveLeasesQueryObj::EnumerateLeasesV4() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_CLIENT_INFO_ARRAY_V4 pdhcpClientArrayV4 = NULL; DWORD dwClientsRead = 0, dwClientsTotal = 0; DWORD dwEnumedClients = 0; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetClientsV4(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, &m_dhcpResumeHandle, m_dwPreferredMax, &pdhcpClientArrayV4, &dwClientsRead, &dwClientsTotal); if (dwClientsRead && dwClientsTotal && pdhcpClientArrayV4) { // // loop through all of the elements that were returned // //for (DWORD i = 0; i < pdhcpClientArrayV4->NumElements; i++) for (DWORD i = 0; i < dwClientsRead; i++) { CDhcpActiveLease * pDhcpActiveLease; // // Create the result pane item for this element // SPITFSNode spNode; pDhcpActiveLease = new CDhcpActiveLease(m_spTFSCompData, pdhcpClientArrayV4->Clients[i]); // filter these types of records out if (pDhcpActiveLease->IsGhost() || pDhcpActiveLease->IsUnreg() || pDhcpActiveLease->IsDoomed() ) { delete pDhcpActiveLease; continue; } if (IsReservation(pdhcpClientArrayV4->Clients[i]->ClientIpAddress)) pDhcpActiveLease->SetReservation(TRUE); CreateLeafTFSNode(&spNode, &GUID_DhcpActiveLeaseNodeType, pDhcpActiveLease, pDhcpActiveLease, m_spNodeMgr); // Tell the handler to initialize any specific data pDhcpActiveLease->InitializeNode(spNode); AddToQueue(spNode); pDhcpActiveLease->Release(); } ::DhcpRpcFreeMemory(pdhcpClientArrayV4); dwEnumedClients += dwClientsRead; dwClientsRead = 0; dwClientsTotal = 0; pdhcpClientArrayV4 = 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: EnumerateLeasesV4 error: %d\n", dwError); m_dwErr = dwError; PostError(dwError); } } Trace1("DHCP snapin: V4 Leases enumerated: %d\n", dwEnumedClients); return hrFalse; } /*--------------------------------------------------------------------------- CDhcpActiveLeasesQueryObj::EnumerateLeases() Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpActiveLeasesQueryObj::EnumerateLeases() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_CLIENT_INFO_ARRAY pdhcpClientArray = NULL; DWORD dwClientsRead = 0, dwClientsTotal = 0; DWORD dwEnumedClients = 0; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetClients(((LPWSTR) (LPCTSTR)m_strServer), m_dhcpScopeAddress, &m_dhcpResumeHandle, m_dwPreferredMax, &pdhcpClientArray, &dwClientsRead, &dwClientsTotal); if (dwClientsRead && dwClientsTotal && pdhcpClientArray) { // // loop through all of the elements that were returned // for (DWORD i = 0; i < pdhcpClientArray->NumElements; i++) { CDhcpActiveLease * pDhcpActiveLease; // // Create the result pane item for this element // SPITFSNode spNode; pDhcpActiveLease = new CDhcpActiveLease(m_spTFSCompData,pdhcpClientArray->Clients[i]); // filter these types of records out if (pDhcpActiveLease->IsGhost() || pDhcpActiveLease->IsUnreg() || pDhcpActiveLease->IsDoomed() ) { delete pDhcpActiveLease; continue; } if (IsReservation(pdhcpClientArray->Clients[i]->ClientIpAddress)) pDhcpActiveLease->SetReservation(TRUE); CreateLeafTFSNode(&spNode, &GUID_DhcpActiveLeaseNodeType, pDhcpActiveLease, pDhcpActiveLease, m_spNodeMgr); // Tell the handler to initialize any specific data pDhcpActiveLease->InitializeNode(spNode); AddToQueue(spNode); pDhcpActiveLease->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 CDhcpAddressPool implementation ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ CDhcpAddressPool::CDhcpAddressPool ( ITFSComponentData * pComponentData ) : CMTDhcpHandler(pComponentData) { } CDhcpAddressPool::~CDhcpAddressPool() { } /*!-------------------------------------------------------------------------- CDhcpAddressPool::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpAddressPool::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, GetImageIndex(FALSE)); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); 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; } /*--------------------------------------------------------------------------- CDhcpAddressPool::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpAddressPool::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strIpAddress, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode)->GetAddress(); UtilCvtIpAddrToWstr (dhcpIpAddress, &strIpAddress); strId = GetServerName(pNode) + strIpAddress + strGuid; return hrOK; } /*--------------------------------------------------------------------------- CDhcpAddressPool::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CDhcpAddressPool::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 ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpAddressPool::OnAddMenuItems Adds entries to the context sensitive menu Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpAddressPool::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; } /*--------------------------------------------------------------------------- CDhcpAddressPool::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpAddressPool::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 ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpAddressPool::OnCreateNewExclusion Description Author: EricDav ---------------------------------------------------------------------------*/ DWORD CDhcpAddressPool::OnCreateNewExclusion ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); SPITFSNode spScopeNode; pNode->GetParent(&spScopeNode); CAddExclusion dlgAddExclusion(spScopeNode); dlgAddExclusion.DoModal(); return 0; } /*--------------------------------------------------------------------------- CDhcpAddressPool::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 CDhcpAddressPool::OnResultDelete ( ITFSComponent * pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM param ) { 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(); } // update stats GetScopeObject(spAddressPool)->TriggerStatsRefresh(); END_WAIT_CURSOR; return hr; } /*!-------------------------------------------------------------------------- CDhcpAddressPool::OnGetResultViewType MMC calls this to get the result view information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpAddressPool::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; } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpAddressPool::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CDhcpAddressPool::OnCreateQuery(ITFSNode * pNode) { CDhcpAddressPoolQueryObj* pQuery = new CDhcpAddressPoolQueryObj(m_spTFSCompData, m_spNodeMgr); pQuery->m_strServer = GetServerIpAddress(pNode); CDhcpScope * pScope = GetScopeObject(pNode); if (pScope) { pQuery->m_dhcpScopeAddress = pScope->GetAddress(); pQuery->m_fSupportsDynBootp = pScope->GetServerObject()->FSupportsDynBootp(); } pQuery->m_dhcpExclResumeHandle = NULL; pQuery->m_dwExclPreferredMax = 0xFFFFFFFF; pQuery->m_dhcpIpResumeHandle = NULL; pQuery->m_dwIpPreferredMax = 0xFFFFFFFF; return pQuery; } /*--------------------------------------------------------------------------- CDhcpAddressPoolQueryObj::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpAddressPoolQueryObj::Execute() { HRESULT hr1 = EnumerateIpRanges(); HRESULT hr2 = EnumerateExcludedIpRanges(); if (hr1 == hrOK || hr2 == hrOK) return hrOK; else return hrFalse; } /*--------------------------------------------------------------------------- Function Name Here Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpAddressPoolQueryObj::EnumerateExcludedIpRanges() { DWORD dwError = ERROR_MORE_DATA; DHCP_RESUME_HANDLE dhcpResumeHandle = 0; LPDHCP_SUBNET_ELEMENT_INFO_ARRAY pdhcpSubnetElementArray = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetElements((LPWSTR) ((LPCTSTR) m_strServer), m_dhcpScopeAddress, DhcpExcludedIpRanges, &m_dhcpExclResumeHandle, m_dwExclPreferredMax, &pdhcpSubnetElementArray, &dwElementsRead, &dwElementsTotal); Trace3("Scope %lx Excluded Ip Ranges read %d, total %d\n", m_dhcpScopeAddress, 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 CDhcpAddressPoolQueryObj::EnumerateIpRanges() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_SUBNET_ELEMENT_INFO_ARRAY pdhcpSubnetElementArray = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0; if (m_fSupportsDynBootp) { return EnumerateIpRangesV5(); } while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetElements((LPWSTR) ((LPCTSTR) m_strServer), m_dhcpScopeAddress, DhcpIpRanges, &m_dhcpIpResumeHandle, m_dwIpPreferredMax, &pdhcpSubnetElementArray, &dwElementsRead, &dwElementsTotal); Trace4("Scope %lx allocation ranges read %d, total %d, dwError = %lx\n", m_dhcpScopeAddress, 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; } HRESULT CDhcpAddressPoolQueryObj::EnumerateIpRangesV5() { DWORD dwError = ERROR_MORE_DATA; LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V5 pdhcpSubnetElementArray = NULL; DWORD dwElementsRead = 0, dwElementsTotal = 0; while (dwError == ERROR_MORE_DATA) { dwError = ::DhcpEnumSubnetElementsV5((LPWSTR) ((LPCTSTR) m_strServer), m_dhcpScopeAddress, DhcpIpRangesDhcpBootp, &m_dhcpIpResumeHandle, m_dwIpPreferredMax, &pdhcpSubnetElementArray, &dwElementsRead, &dwElementsTotal); Trace4("EnumerateIpRangesV5: Scope %lx allocation ranges read %d, total %d, dwError = %lx\n", m_dhcpScopeAddress, 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); pDhcpAllocRange->SetRangeType(pdhcpSubnetElementArray->Elements[i].ElementType); 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; } /*--------------------------------------------------------------------------- CDhcpAddressPool::CompareItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(int) CDhcpAddressPool::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; } /*--------------------------------------------------------------------------- CDhcpScopeOptions Implementation ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpScopeOptions Constructor and destructor Author: EricDav ---------------------------------------------------------------------------*/ CDhcpScopeOptions::CDhcpScopeOptions ( ITFSComponentData * pComponentData ) : CMTDhcpHandler(pComponentData) { } CDhcpScopeOptions::~CDhcpScopeOptions() { } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::InitializeNode Initializes node specific data Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::InitializeNode ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); HRESULT hr = hrOK; // // Create the display name for this scope // CString strTemp; strTemp.LoadString(IDS_SCOPE_OPTIONS_FOLDER); SetDisplayName(strTemp); // Make the node immediately visible pNode->SetVisibilityState(TFS_VIS_SHOW); pNode->SetData(TFS_DATA_IMAGEINDEX, GetImageIndex(FALSE)); pNode->SetData(TFS_DATA_OPENIMAGEINDEX, GetImageIndex(TRUE)); pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode); pNode->SetData(TFS_DATA_USER, (LPARAM) this); pNode->SetData(TFS_DATA_TYPE, DHCPSNAP_SCOPE_OPTIONS); pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE); SetColumnStringIDs(&aColumns[DHCPSNAP_SCOPE_OPTIONS][0]); SetColumnWidths(&aColumnWidths[DHCPSNAP_SCOPE_OPTIONS][0]); return hr; } /*--------------------------------------------------------------------------- CDhcpScopeOptions::OnCreateNodeId2 Returns a unique string for this node Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags) { const GUID * pGuid = pNode->GetNodeType(); CString strIpAddress, strGuid; StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256); strGuid.ReleaseBuffer(); DHCP_IP_ADDRESS dhcpIpAddress = GetScopeObject(pNode)->GetAddress(); UtilCvtIpAddrToWstr (dhcpIpAddress, &strIpAddress); strId = GetServerName(pNode) + strIpAddress + strGuid; return hrOK; } /*--------------------------------------------------------------------------- CDhcpScopeOptions::GetImageIndex Description Author: EricDav ---------------------------------------------------------------------------*/ int CDhcpScopeOptions::GetImageIndex(BOOL bOpenImage) { int nIndex = -1; switch (m_nState) { case notLoaded: case loaded: if (bOpenImage) nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_OPEN; else nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED; break; case loading: if (bOpenImage) nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_OPEN_BUSY; else nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED_BUSY; break; case unableToLoad: if (bOpenImage) nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_OPEN_LOST_CONNECTION; else nIndex = ICON_IDX_SCOPE_OPTION_FOLDER_CLOSED_LOST_CONNECTION; break; default: ASSERT(FALSE); } return nIndex; } /*--------------------------------------------------------------------------- Overridden base handler functions ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpScopeOptions::OnAddMenuItems Adds entries to the context sensitive menu Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScopeOptions::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) { if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) { // these menu items go in the new menu, // only visible from scope pane strMenuText.LoadString(IDS_CREATE_OPTION_SCOPE); hr = LoadAndAddMenuItem( pContextMenuCallback, strMenuText, IDS_CREATE_OPTION_SCOPE, CCM_INSERTIONPOINTID_PRIMARY_TOP, fFlags ); ASSERT( SUCCEEDED(hr) ); } } return hr; } /*--------------------------------------------------------------------------- CDhcpScopeOptions::OnCommand Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScopeOptions::OnCommand ( ITFSNode * pNode, long nCommandId, DATA_OBJECT_TYPES type, LPDATAOBJECT pDataObject, DWORD dwType ) { HRESULT hr = S_OK; switch (nCommandId) { case IDS_CREATE_OPTION_SCOPE: OnCreateNewOptions(pNode); break; case IDS_REFRESH: OnRefresh(pNode, pDataObject, dwType, 0, 0); break; default: break; } return hr; } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::HasPropertyPages Implementation of ITFSNodeHandler::HasPropertyPages NOTE: the root node handler has to over-ride this function to handle the snapin manager property page (wizard) case!!! Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScopeOptions::HasPropertyPages ( ITFSNode * pNode, LPDATAOBJECT pDataObject, DATA_OBJECT_TYPES type, DWORD dwType ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = hrOK; // we have property pages in the normal case, but don't put the // menu up if we are not loaded yet if ( m_nState != loaded ) { hr = hrFalse; } else { hr = hrOK; } return hr; } /*--------------------------------------------------------------------------- CDhcpScopeOptions::CreatePropertyPages Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScopeOptions::CreatePropertyPages ( ITFSNode * pNode, LPPROPERTYSHEETCALLBACK lpProvider, LPDATAOBJECT pDataObject, LONG_PTR handle, DWORD dwType ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); DWORD dwError; DWORD dwDynDnsFlags; HRESULT hr = hrOK; COptionsConfig * pOptCfg; CString strOptCfgTitle, strOptType; SPITFSNode spServerNode; SPIComponentData spComponentData; COptionValueEnum * pOptionValueEnum; // // Create the property page // COM_PROTECT_TRY { m_spNodeMgr->GetComponentData(&spComponentData); BEGIN_WAIT_CURSOR; strOptType.LoadString(IDS_CONFIGURE_OPTIONS_SCOPE); AfxFormatString1(strOptCfgTitle, IDS_CONFIGURE_OPTIONS_TITLE, strOptType); GetScopeObject(pNode)->GetServerNode(&spServerNode); pOptionValueEnum = GetScopeObject(pNode)->GetOptionValueEnum(); pOptCfg = new COptionsConfig(pNode, spServerNode, spComponentData, m_spTFSCompData, pOptionValueEnum, strOptCfgTitle); END_WAIT_CURSOR; // // Object gets deleted when the page is destroyed // Assert(lpProvider != NULL); hr = pOptCfg->CreateModelessSheet(lpProvider, handle); } COM_PROTECT_CATCH return hr; } /*--------------------------------------------------------------------------- CDhcpScopeOptions::OnPropertyChange Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::OnPropertyChange ( ITFSNode * pNode, LPDATAOBJECT pDataobject, DWORD dwType, LPARAM arg, LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); COptionsConfig * pOptCfg = reinterpret_cast(lParam); LPARAM changeMask = 0; // tell the property page to do whatever now that we are back on the // main thread pOptCfg->OnPropertyChange(TRUE, &changeMask); pOptCfg->AcknowledgeNotify(); if (changeMask) pNode->ChangeNode(changeMask); return hrOK; } /*--------------------------------------------------------------------------- CDhcpScopeOptions::OnPropertyChange Description Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::OnResultPropertyChange ( ITFSComponent * pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM param ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); SPITFSNode spNode; m_spNodeMgr->FindNode(cookie, &spNode); COptionsConfig * pOptCfg = reinterpret_cast(param); LPARAM changeMask = 0; // tell the property page to do whatever now that we are back on the // main thread pOptCfg->OnPropertyChange(TRUE, &changeMask); pOptCfg->AcknowledgeNotify(); if (changeMask) spNode->ChangeNode(changeMask); return hrOK; } /*--------------------------------------------------------------------------- CDhcpScopeOptions::CompareItems Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP_(int) CDhcpScopeOptions::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; CDhcpOptionItem *pOpt1 = GETHANDLER(CDhcpOptionItem, spNode1); CDhcpOptionItem *pOpt2 = GETHANDLER(CDhcpOptionItem, spNode2); switch (nCol) { case 0: { // // Name compare - use the option # // LONG_PTR uImage1 = spNode1->GetData(TFS_DATA_IMAGEINDEX); LONG_PTR uImage2 = spNode2->GetData(TFS_DATA_IMAGEINDEX); nCompare = UtilGetOptionPriority((int) uImage1, (int) uImage2); if (nCompare == 0) { DHCP_OPTION_ID id1 = pOpt1->GetOptionId(); DHCP_OPTION_ID id2 = pOpt2->GetOptionId(); if (id1 < id2) nCompare = -1; else if (id1 > id2) nCompare = 1; } } break; case 1: { // compare the vendor strings CString str1, str2; str1 = pOpt1->GetVendorDisplay(); str2 = pOpt2->GetVendorDisplay(); nCompare = str1.CompareNoCase(str2); } break; case 2: { // compare the printable values CString str1, str2; str1 = pOpt1->GetString( pComponent, cookieA, nCol ); str2 = pOpt2->GetString( pComponent, cookieB, nCol ); nCompare = str1.CompareNoCase( str2 ); break; } case 3: { CString str1, str2; str1 = pOpt1->GetClassName(); str2 = pOpt2->GetClassName(); nCompare = str1.CompareNoCase(str2); } break; } return nCompare; } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::OnResultSelect Update the verbs and the result pane message Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::OnResultSelect(ITFSComponent *pComponent, LPDATAOBJECT pDataObject, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam) { HRESULT hr = hrOK; SPITFSNode spNode; CORg(CMTDhcpHandler::OnResultSelect(pComponent, pDataObject, cookie, arg, lParam)); CORg (pComponent->GetSelectedNode(&spNode)); if ( spNode != 0 ) { UpdateResultMessage(spNode); } Error: return hr; } /*--------------------------------------------------------------------------- CDhcpScopeOptions::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 CDhcpScopeOptions::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 spScopeOpt, spSelectedNode; m_spNodeMgr->FindNode(cookie, &spScopeOpt); pComponent->GetSelectedNode(&spSelectedNode); Assert(spSelectedNode == spScopeOpt); if (spSelectedNode != spScopeOpt) 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; } // check to make sure we are deleting just scope options POSITION pos = listNodesToDelete.GetHeadPosition(); while (pos) { ITFSNode * pNode = listNodesToDelete.GetNext(pos); if (pNode->GetData(TFS_DATA_IMAGEINDEX) != ICON_IDX_SCOPE_OPTION_LEAF) { // this option is not scope option. Put up a dialog telling the user what to do AfxMessageBox(IDS_CANNOT_DELETE_OPTION_SCOPE); return NOERROR; } } CString strServer = GetServerIpAddress(spScopeOpt); DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo; dhcpOptionScopeInfo.ScopeType = DhcpSubnetOptions; dhcpOptionScopeInfo.ScopeInfo.SubnetScopeInfo = GetScopeObject(spScopeOpt)->GetAddress(); // // Loop through all items deleting // BEGIN_WAIT_CURSOR; while (listNodesToDelete.GetCount() > 0) { SPITFSNode spOptionNode; spOptionNode = listNodesToDelete.RemoveHead(); CDhcpOptionItem * pOptItem = GETHANDLER(CDhcpOptionItem, spOptionNode); // // Try to remove it from the server // DWORD dwError; if (pOptItem->IsVendorOption() || pOptItem->IsClassOption()) { LPCTSTR pClassName = pOptItem->GetClassName(); if (lstrlen(pClassName) == 0) pClassName = NULL; dwError = ::DhcpRemoveOptionValueV5((LPTSTR) ((LPCTSTR) strServer), pOptItem->IsVendorOption() ? DHCP_FLAGS_OPTION_IS_VENDOR : 0, pOptItem->GetOptionId(), (LPTSTR) pClassName, (LPTSTR) pOptItem->GetVendor(), &dhcpOptionScopeInfo); } else { dwError = ::DhcpRemoveOptionValue(strServer, pOptItem->GetOptionId(), &dhcpOptionScopeInfo); } if (dwError != 0) { ::DhcpMessageBox(dwError); RESTORE_WAIT_CURSOR; hr = E_FAIL; continue; } // // remove from our internal list // GetScopeObject(spScopeOpt)->GetOptionValueEnum()->Remove(pOptItem->GetOptionId(), pOptItem->GetVendor(), pOptItem->GetClassName()); // // Remove from UI now // spScopeOpt->RemoveChild(spOptionNode); spOptionNode.Release(); } END_WAIT_CURSOR; UpdateResultMessage(spScopeOpt); return hr; } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::OnHaveData Description Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScopeOptions::OnHaveData ( ITFSNode * pParentNode, LPARAM Data, LPARAM Type ) { // This is how we get non-node data back from the background thread. switch (Type) { case DHCP_QDATA_OPTION_VALUES: { HRESULT hr = hrOK; SPIComponentData spCompData; SPIConsole spConsole; SPIDataObject spDataObject; IDataObject * pDataObject; CDhcpScope * pScope = GetScopeObject(pParentNode); COptionValueEnum * pOptionValueEnum = reinterpret_cast(Data); pScope->SetOptionValueEnum(pOptionValueEnum); pOptionValueEnum->RemoveAll(); delete pOptionValueEnum; // now tell the view to update themselves m_spNodeMgr->GetComponentData(&spCompData); CORg ( spCompData->QueryDataObject((MMC_COOKIE) pParentNode, CCT_SCOPE, &pDataObject) ); spDataObject = pDataObject; CORg ( m_spNodeMgr->GetConsole(&spConsole) ); CORg ( spConsole->UpdateAllViews(pDataObject, (LPARAM) pParentNode, DHCPSNAP_UPDATE_OPTIONS) ); break; } } Error: return; } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::OnResultUpdateView Implementation of ITFSResultHandler::OnResultUpdateView Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::OnResultUpdateView ( ITFSComponent *pComponent, LPDATAOBJECT pDataObject, LPARAM data, LPARAM hint ) { HRESULT hr = hrOK; SPITFSNode spSelectedNode; pComponent->GetSelectedNode(&spSelectedNode); if (spSelectedNode == NULL) return S_OK; // no selection for our IComponentData if ( hint == DHCPSNAP_UPDATE_OPTIONS ) { SPINTERNAL spInternal = ExtractInternalFormat(pDataObject); ITFSNode * pNode = reinterpret_cast(spInternal->m_cookie); SPITFSNode spSelectedNode; pComponent->GetSelectedNode(&spSelectedNode); EnumerateResultPane(pComponent, (MMC_COOKIE) spSelectedNode.p, 0, 0); } else { // we don't handle this message, let the base class do it. return CMTDhcpHandler::OnResultUpdateView(pComponent, pDataObject, data, hint); } return hr; } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::OnGetResultViewType MMC calls this to get the result view information Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::OnGetResultViewType ( ITFSComponent * pComponent, MMC_COOKIE cookie, LPOLESTR * ppViewType, long * pViewOptions ) { HRESULT hr = hrOK; // call the base class to see if it is handling this if (CMTDhcpHandler::OnGetResultViewType(pComponent, cookie, ppViewType, pViewOptions) != S_OK) { *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT; hr = S_FALSE; } return hr; } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::UpdateResultMessage Figures out what message to put in the result pane, if any Author: EricDav ---------------------------------------------------------------------------*/ void CDhcpScopeOptions::UpdateResultMessage(ITFSNode * pNode) { HRESULT hr = hrOK; int nMessage = -1; // default int nVisible, nTotal; int i; CString strTitle, strBody, strTemp; if (!m_dwErr) { pNode->GetChildCount(&nVisible, &nTotal); // determine what message to display if ( (m_nState == notLoaded) || (m_nState == loading) ) { nMessage = -1; } else if (nTotal == 0) { nMessage = SCOPE_OPTIONS_MESSAGE_NO_OPTIONS; } // build the strings if (nMessage != -1) { // now build the text strings // first entry is the title strTitle.LoadString(g_uScopeOptionsMessages[nMessage][0]); // second entry is the icon // third ... n entries are the body strings for (i = 2; g_uScopeOptionsMessages[nMessage][i] != 0; i++) { strTemp.LoadString(g_uScopeOptionsMessages[nMessage][i]); strBody += strTemp; } } } // show the message if (nMessage == -1) { ClearMessage(pNode); } else { ShowMessage(pNode, strTitle, strBody, (IconIdentifier) g_uScopeOptionsMessages[nMessage][1]); } } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::EnumerateResultPane We override this function for the options nodes for one reason. Whenever an option class is deleted, then all options defined for that class will be removed as well. Since there are multiple places that these options may show up, it's easier to just not show any options that don't have a class defined for it. Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::EnumerateResultPane ( ITFSComponent * pComponent, MMC_COOKIE cookie, LPARAM arg, LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CClassInfoArray ClassInfoArray; SPITFSNode spContainer, spServerNode; CDhcpServer * pServer; COptionValueEnum * aEnum[2]; int aImages[2] = {ICON_IDX_SCOPE_OPTION_LEAF, ICON_IDX_SERVER_OPTION_LEAF}; m_spNodeMgr->FindNode(cookie, &spContainer); spServerNode = GetServerNode(spContainer); pServer = GETHANDLER(CDhcpServer, spServerNode); pServer->GetClassInfoArray(ClassInfoArray); aEnum[0] = GetScopeObject(spContainer)->GetOptionValueEnum(); aEnum[1] = pServer->GetOptionValueEnum(); aEnum[0]->Reset(); aEnum[1]->Reset(); return OnResultUpdateOptions(pComponent, spContainer, &ClassInfoArray, aEnum, aImages, 2); } /*--------------------------------------------------------------------------- Command handlers ---------------------------------------------------------------------------*/ HRESULT CDhcpScopeOptions::OnCreateNewOptions ( ITFSNode * pNode ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); CPropertyPageHolderBase * pPropSheet; HRESULT hr = hrOK; COM_PROTECT_TRY { if (HasPropSheetsOpen()) { GetOpenPropSheet(0, &pPropSheet); pPropSheet->SetActiveWindow(); } else { CString strOptCfgTitle, strOptType; SPIComponentData spComponentData; strOptType.LoadString(IDS_CONFIGURE_OPTIONS_SCOPE); AfxFormatString1(strOptCfgTitle, IDS_CONFIGURE_OPTIONS_TITLE, strOptType); m_spNodeMgr->GetComponentData(&spComponentData); hr = DoPropertiesOurselvesSinceMMCSucks(pNode, spComponentData, strOptCfgTitle); } } COM_PROTECT_CATCH return hr; } /*--------------------------------------------------------------------------- Background thread functionality ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- CDhcpScopeOptions::OnCreateQuery() Description Author: EricDav ---------------------------------------------------------------------------*/ ITFSQueryObject* CDhcpScopeOptions::OnCreateQuery(ITFSNode * pNode) { CDhcpScopeOptionsQueryObj* pQuery = new CDhcpScopeOptionsQueryObj(m_spTFSCompData, m_spNodeMgr); pQuery->m_strServer = GetServerIpAddress(pNode); pQuery->m_dhcpScopeAddress = GetScopeObject(pNode)->GetAddress(); pQuery->m_dhcpResumeHandle = NULL; pQuery->m_dwPreferredMax = 0xFFFFFFFF; GetScopeObject(pNode)->GetDynBootpClassName(pQuery->m_strDynBootpClassName); GetScopeObject(pNode)->GetServerVersion(pQuery->m_liDhcpVersion); return pQuery; } /*--------------------------------------------------------------------------- CDhcpScopeOptionsQueryObj::Execute() Description Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScopeOptionsQueryObj::Execute() { DWORD dwErr; DHCP_OPTION_SCOPE_INFO dhcpOptionScopeInfo; COptionValueEnum * pOptionValueEnum; pOptionValueEnum = new COptionValueEnum(); pOptionValueEnum->m_strDynBootpClassName = m_strDynBootpClassName; dhcpOptionScopeInfo.ScopeType = DhcpSubnetOptions; dhcpOptionScopeInfo.ScopeInfo.SubnetScopeInfo = m_dhcpScopeAddress; pOptionValueEnum->Init(m_strServer, m_liDhcpVersion, dhcpOptionScopeInfo); dwErr = pOptionValueEnum->Enum(); if (dwErr != ERROR_SUCCESS) { Trace1("CDhcpScopeOptionsQueryObj::Execute - Enum Failed! %d\n", dwErr); m_dwErr = dwErr; PostError(dwErr); delete pOptionValueEnum; } else { pOptionValueEnum->SortById(); AddToQueue((LPARAM) pOptionValueEnum, DHCP_QDATA_OPTION_VALUES); } return hrFalse; } /*!-------------------------------------------------------------------------- CDhcpScopeOptions::OnNotifyExiting CMTDhcpHandler overridden functionality allows us to know when the background thread is done Author: EricDav ---------------------------------------------------------------------------*/ STDMETHODIMP CDhcpScopeOptions::OnNotifyExiting ( LPARAM lParam ) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); SPITFSNode spNode; spNode.Set(m_spNode); // save this off because OnNotifyExiting will release it HRESULT hr = CMTDhcpHandler::OnNotifyExiting(lParam); UpdateResultMessage(spNode); return hr; } // // // qsort comparison routine to compare the ip addresses. // // int __cdecl QCompare( const void *ip1, const void *ip2 ) { DWORD *lip1, *lip2; if ( ip1 && ip2 ) { lip1 = (DWORD *)ip1; lip2 = (DWORD *)ip2; if ( *lip1 < *lip2 ) { return -1; } else if ( *lip1 > *lip2 ) { return 1; } else { return 0; } } return 0; }