Windows-Server-2003/net/wlbs/nlbmgr/exe2/detailsview.cpp

798 lines
21 KiB
C++
Raw Permalink Normal View History

2024-08-04 01:28:15 +02:00
//***************************************************************************
//
// DETAILSVIEW.CPP
//
// Module: NLB Manager
//
// Purpose: Implements DetailsView, the right-hand details list view.
//
// Copyright (c)2001-2002 Microsoft Corporation, All Rights Reserved
//
// History:
//
// 07/30/01 JosephJ Created
//
//***************************************************************************
#include "precomp.h"
#pragma hdrstop
#include "private.h"
#include "PortsPage.h"
#include "detailsview.tmh"
IMPLEMENT_DYNCREATE( DetailsView, CFormView )
BEGIN_MESSAGE_MAP( DetailsView, CFormView )
ON_NOTIFY(HDN_ITEMCLICK, 0, OnColumnClick)
ON_NOTIFY(LVN_KEYDOWN, IDC_LIST_DETAILS, OnNotifyKeyDown)
ON_WM_SIZE()
END_MESSAGE_MAP()
DetailsView::DetailsView()
: CFormView(IDD_DIALOG_DETAILSVIEW),
m_initialized(FALSE),
m_fPrepareToDeinitialize(FALSE)
{
InitializeCriticalSection(&m_crit);
}
DetailsView::~DetailsView()
{
DeleteCriticalSection(&m_crit);
}
void DetailsView::DoDataExchange(CDataExchange* pDX)
{
// IDC_TEXT_DETAILS_CAPTION
// TRACE_CRIT(L"<-> %!FUNC!");
CFormView::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST_DETAILS, m_ListCtrl);
}
Document*
DetailsView::GetDocument()
{
return ( Document *) m_pDocument;
}
/*
* Method: OnSize
* Description: This method is called by the WM_NOTIFY handler whenever
* a re-sizing of the details view occurs as the result of
* a window re-size or moving one of the window splitters.
*/
void
DetailsView::OnSize( UINT nType, int cx, int cy )
{
/* Call the Parent class OnSize method first. */
CFormView::OnSize( nType, cx, cy );
/* Call Resize to re-size the list view to fit the window. */
Resize();
}
/*
* Method: Resize
* Description: This method is called in several places to specifically
* re-size the listview control to fit the window.
*/
void
DetailsView::Resize()
{
/* If the window has not yet been initialized, don't bother.
This member is set in OnInitialUpdate. */
if (m_initialized) {
LONG Bottom;
RECT Rect;
/* Get a pointer to the caption edit box. */
CWnd * ListCaption = GetDlgItem(IDC_TEXT_DETAILS_CAPTION);
/* Get a pointer to the listview control. */
CListCtrl & ListCtrl = GetListCtrl();
/* Get the client rectangle of the caption dialog, which
stretches across the top of the window. */
ListCaption->GetClientRect(&Rect);
/* Note the location of the bottom. */
Bottom = Rect.bottom;
/* Now, get the client rectangle of the entire frame. */
GetClientRect(&Rect);
/* Re-set the top to be the bottom of the caption, plus
a little bit of empty space. */
Rect.top = Bottom + 6;
/* Re-set the window location of the LISTVIEW (Note: not
the frame, just the listview). Basically, we're re-
sizing the listview to be the same as the frame, but
with its top equal to the bottom of the caption. */
ListCtrl.MoveWindow(&Rect, TRUE);
}
}
void
DetailsView::OnInitialUpdate()
{
this->UpdateData(FALSE);
//
// register
// with the document class,
//
GetDocument()->registerDetailsView(this);
// initially nothing has been clicked.
m_sort_column = -1;
/* Mark the frame as initialized. This is needed
by the Resize notification callback. */
m_initialized = TRUE;
/* Set the initial size of the listview. */
Resize();
}
void DetailsView::OnColumnClick(NMHDR* pNotifyStruct, LRESULT* pResult)
{
TRACE_CRIT(L"<->%!FUNC!");
PortListUtils::OnColumnClick(
(LPNMLISTVIEW) pNotifyStruct,
REF GetListCtrl(),
FALSE, // FALSE == is host level
REF m_sort_ascending,
REF m_sort_column
);
}
//
// Handle a selection change notification from the left (tree) view
//
void
DetailsView::HandleLeftViewSelChange(
IN IUICallbacks::ObjectType objtype,
IN ENGINEHANDLE ehId
)
{
mfn_Lock();
if (m_fPrepareToDeinitialize)
{
goto end;
}
if (ehId == NULL)
{
// Root view ...
mfn_InitializeRootDisplay();
goto end;
}
switch(objtype)
{
case IUICallbacks::OBJ_CLUSTER:
mfn_InitializeClusterDisplay(ehId);
break;
case IUICallbacks::OBJ_INTERFACE:
mfn_InitializeInterfaceDisplay(ehId);
break;
default: // other object type unexpected
ASSERT(FALSE);
break;
}
end:
mfn_Unlock();
return;
}
//
// Handle an event relating to a specific instance of a specific
// object type.
//
void
DetailsView::HandleEngineEvent(
IN IUICallbacks::ObjectType objtype,
IN ENGINEHANDLE ehClusterId, // could be NULL
IN ENGINEHANDLE ehObjId,
IN IUICallbacks::EventCode evt
)
{
if (m_fPrepareToDeinitialize)
{
goto end;
}
mfn_Lock();
// DummyAction(L"DetailsView::HandleEngineEvent");
//
// If the object and type matches our, we'll re-draw our display...
//
if ((m_objType == objtype) && (m_ehObj == ehObjId))
{
//
// It's us -- re-draw...
//
HandleLeftViewSelChange(objtype, ehObjId);
}
else if ((m_objType == IUICallbacks::OBJ_CLUSTER) && (m_ehObj == ehClusterId))
{
//
// We're showing a cluster and this event is for one of our
// interfaces -- for now we'll redraw ourselves. An optimization
// would be to just re-draw that list element that represents the
// interface.
//
HandleLeftViewSelChange(m_objType, m_ehObj);
}
else if ((m_objType == IUICallbacks::OBJ_INVALID) && (objtype == IUICallbacks::OBJ_CLUSTER))
{
//
// We're showing the root display (list of clusters and this
// event is a cluster update, so we need to refresh.
//
HandleLeftViewSelChange(objtype, NULL);
}
mfn_Unlock();
end:
return;
}
void
DetailsView::mfn_InitializeRootDisplay(VOID)
//
// Initialize the details-view display with the root is selected.
//
{
vector <ENGINEHANDLE> ClusterList;
vector <ENGINEHANDLE>::iterator iCluster;
CListCtrl& ctrl = GetListCtrl();
CLocalLogger logDescription;
NLBERROR nerr;
int i = 0;
enum
{
COL_CL_NAME,
COL_CL_IP_ADDR,
COL_CL_IP_MASK,
COL_CL_MODE,
COL_CL_RCT_ENABLED
};
mfn_Clear();
logDescription.Log(
IDS_DETAILS_ROOT_DESCRIPTION
);
mfn_UpdateCaption(logDescription.GetStringSafe());
ctrl.SetImageList( GetDocument()->m_images48x48, LVSIL_SMALL );
ctrl.InsertColumn( COL_CL_NAME,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_CLUSTER_NAME),
// L"Cluster name",
LVCFMT_LEFT,
175
);
ctrl.InsertColumn( COL_CL_IP_ADDR,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_CIP),
// L"Cluster IP address",
LVCFMT_LEFT,
140
);
ctrl.InsertColumn( COL_CL_IP_MASK,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_CIPMASK),
// L"Cluster IP subnet mask",
LVCFMT_LEFT,
140
);
ctrl.InsertColumn( COL_CL_MODE,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_CMODE),
// L"Cluster mode",
LVCFMT_LEFT,
100
);
ctrl.InsertColumn( COL_CL_RCT_ENABLED,
GETRESOURCEIDSTRING(IDS_DETAILS_RCT_STATUS),
// L"Remote control status",
LVCFMT_LEFT,
125
);
nerr = gEngine.EnumerateClusters(ClusterList);
if (FAILED(nerr)) goto end;
for (iCluster = ClusterList.begin();
iCluster != ClusterList.end();
iCluster++)
{
ENGINEHANDLE ehCluster = (ENGINEHANDLE)*iCluster;
CClusterSpec cSpec;
INT iIcon;
LPCWSTR szClusterIp = L"";
LPCWSTR szClusterMask = L"";
LPCWSTR szClusterName = L"";
LPCWSTR szClusterMode = L"";
LPCWSTR szClusterRctEnabled = L"";
const WLBS_REG_PARAMS * pParams;
nerr = gEngine.GetClusterSpec(ehCluster, REF cSpec);
if (FAILED(nerr)) goto end;
if (cSpec.m_ClusterNlbCfg.IsValidNlbConfig())
{
pParams = &cSpec.m_ClusterNlbCfg.NlbParams;
szClusterName = pParams->domain_name;
szClusterIp= pParams->cl_ip_addr;
szClusterMask= pParams->cl_net_mask;
szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_UNICAST); //"unicast";
if (pParams->mcast_support)
{
if (pParams->fIGMPSupport)
{
szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_IGMP); //"IGMP multicast";
}
else
{
szClusterMode = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_CM_MULTI); //"multicast";
}
}
if (pParams->rct_enabled)
{
szClusterRctEnabled = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_RCT_ENABLED); //"enabled";
}
else
{
szClusterRctEnabled = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_RCT_DISABLED); //"disabled";
}
if (cSpec.m_fMisconfigured)
{
iIcon = Document::ICON_CLUSTER_BROKEN;
}
else
{
iIcon = Document::ICON_CLUSTER_OK;
}
//
// Insert all the columns...
//
ctrl.InsertItem(
LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, // nMask
i,
szClusterName, // text
0, // nState
0, // nStateMask
iIcon,
(LPARAM) ehCluster // lParam
);
ctrl.SetItemText( i, COL_CL_IP_ADDR, szClusterIp);
ctrl.SetItemText( i, COL_CL_IP_MASK, szClusterMask);
ctrl.SetItemText( i, COL_CL_MODE, szClusterMode);
ctrl.SetItemText( i, COL_CL_RCT_ENABLED, szClusterRctEnabled);
i++;
}
}
end:
return;
}
void
DetailsView::mfn_InitializeClusterDisplay(ENGINEHANDLE ehCluster)
//
// Initialize the details-view display with a cluster is selected.
//
{
NLBERROR nerr;
CClusterSpec cSpec;
CListCtrl& ctrl = GetListCtrl();
CLocalLogger logDescription;
enum
{
COL_INTERFACE_NAME=0,
COL_STATUS,
COL_DED_IP_ADDR,
COL_DED_IP_MASK,
COL_HOST_PRIORITY,
COL_HOST_INITIAL_STATE
};
mfn_Clear();
nerr = gEngine.GetClusterSpec(
ehCluster,
REF cSpec
);
if (FAILED(nerr)) goto end;
if (cSpec.m_ClusterNlbCfg.IsValidNlbConfig())
{
logDescription.Log(
IDS_DETAILS_CLUSTER_DESCRIPTION,
cSpec.m_ClusterNlbCfg.NlbParams.domain_name,
cSpec.m_ClusterNlbCfg.NlbParams.cl_ip_addr
);
}
mfn_UpdateCaption(logDescription.GetStringSafe());
ctrl.SetImageList( GetDocument()->m_images48x48,
LVSIL_SMALL );
ctrl.InsertColumn( COL_INTERFACE_NAME,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_HOST),
// L"Host(Interface)",
LVCFMT_LEFT,
175
);
ctrl.InsertColumn( COL_STATUS,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_STATUS),
// L"Status",
LVCFMT_LEFT,
85
);
ctrl.InsertColumn( COL_DED_IP_ADDR,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_DIP),
// L"Dedicated IP address",
LVCFMT_LEFT,
140
);
ctrl.InsertColumn( COL_DED_IP_MASK,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_DIPMASK),
// L"Dedicated IP subnet mask",
LVCFMT_LEFT,
140
);
ctrl.InsertColumn( COL_HOST_PRIORITY,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_PRIORITY),
// L"Host priority",
LVCFMT_LEFT,
75
);
ctrl.InsertColumn( COL_HOST_INITIAL_STATE,
GETRESOURCEIDSTRING(IDS_DETAILS_COL_INIT_STATE),
// L"Initial host state",
LVCFMT_LEFT,
100
);
//
// Now we loop through the interfaces in the cluster, adding one line of
// information on each;
//
for( int i = 0; i < cSpec.m_ehInterfaceIdList.size(); ++i )
{
CInterfaceSpec iSpec;
CHostSpec hSpec;
_bstr_t bstrStatus;
_bstr_t bstrDisplayName;
ENGINEHANDLE ehIID = cSpec.m_ehInterfaceIdList[i];
INT iIcon = 0;
WBEMSTATUS wStat;
LPCWSTR szDisplayName = L"";
LPCWSTR szStatus = L"";
LPCWSTR szDedIp = L"";
LPCWSTR szDedMask = L"";
LPCWSTR szHostPriority = L"";
LPCWSTR szHostInitialState = L"";
WCHAR rgPriority[64];
WCHAR rgInitialState[64];
const WLBS_REG_PARAMS *pParams =
&iSpec.m_NlbCfg.NlbParams;
nerr = gEngine.GetInterfaceInformation(
ehIID,
REF hSpec,
REF iSpec,
REF bstrDisplayName,
REF iIcon,
REF bstrStatus
);
if (NLBFAILED(nerr))
{
continue;
}
else
{
szDisplayName = bstrDisplayName;
szStatus = bstrStatus;
}
if (iSpec.m_NlbCfg.IsValidNlbConfig())
{
szDedIp = pParams->ded_ip_addr;
szDedMask = pParams->ded_net_mask;
StringCbPrintf(rgPriority, sizeof(rgPriority), L"%lu", pParams->host_priority);
szHostPriority = rgPriority;
// szHostInitialState
switch(pParams->cluster_mode)
{
case CVY_HOST_STATE_STARTED:
szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_STARTED); // L"started";
break;
case CVY_HOST_STATE_STOPPED:
szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_STOPPED); // L"stopped";
break;
case CVY_HOST_STATE_SUSPENDED:
szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_SUSPENDED); // L"suspended";
break;
default:
szHostInitialState = GETRESOURCEIDSTRING(IDS_DETAILS_HOST_STATE_UNKNOWN); // L"unknown";
break;
}
if (pParams->persisted_states & CVY_PERSIST_STATE_SUSPENDED)
{
StringCbPrintf(
rgInitialState,
sizeof(rgInitialState),
(LPCWSTR) GETRESOURCEIDSTRING(IDS_DETAILS_PERSIST_SUSPEND), // L"%ws, persist suspend"
szHostInitialState);
szHostInitialState = rgInitialState;
}
}
//
// Insert all the columns...
//
ctrl.InsertItem(
LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM, // nMask
i,
szDisplayName, // text
0, // nState
0, // nStateMask
iIcon,
(LPARAM) ehIID // lParam
);
ctrl.SetItemText( i, COL_STATUS, szStatus);
ctrl.SetItemText( i, COL_DED_IP_ADDR, szDedIp);
ctrl.SetItemText( i, COL_DED_IP_MASK, szDedMask);
ctrl.SetItemText( i, COL_HOST_PRIORITY, szHostPriority);
ctrl.SetItemText( i, COL_HOST_INITIAL_STATE, szHostInitialState);
}
//
// Keep track of which object we're displaying...
//
m_ehObj = ehCluster;
m_objType = IUICallbacks::OBJ_CLUSTER;
end:
return;
}
void
DetailsView::mfn_InitializeInterfaceDisplay(ENGINEHANDLE ehInterface)
//
// Initialize the details-view display when an interface in a cluster is
// selected.
//
{
NLBERROR nerr;
CInterfaceSpec ISpec;
CListCtrl& ctrl = GetListCtrl();
mfn_Clear();
nerr = gEngine.GetInterfaceSpec(ehInterface, REF ISpec);
if (NLBFAILED(nerr))
{
goto end;
}
//
// Fill out the caption with host name and interface name...
//
{
WBEMSTATUS wStat;
LPWSTR szAdapter = L"";
LPCWSTR szHostName = L"";
CHostSpec hSpec;
CLocalLogger log;
nerr = gEngine.GetHostSpec(
ISpec.m_ehHostId,
REF hSpec
);
if (NLBOK(nerr))
{
szHostName = (LPCWSTR) hSpec.m_MachineName;
if (szHostName == NULL)
{
szHostName = L"";
}
}
wStat = ISpec.m_NlbCfg.GetFriendlyName(&szAdapter);
if (FAILED(wStat))
{
szAdapter = NULL;
}
if (szAdapter == NULL)
szAdapter = L"";
log.Log(
IDS_DETAILS_PORT_CAPTION,
szHostName,
szAdapter
);
delete szAdapter;
mfn_UpdateCaption(log.GetStringSafe());
}
PortListUtils::LoadFromNlbCfg(
&ISpec.m_NlbCfg,
ctrl,
FALSE, // FALSE == is host-level
TRUE // TRUE == displaying in the details view
);
//
// Keep track of which object we're displaying...
//
m_ehObj = ehInterface;
m_objType = IUICallbacks::OBJ_INTERFACE;
end:
return;
}
void
DetailsView::mfn_UpdateInterfaceInClusterDisplay(
ENGINEHANDLE ehInterface,
BOOL fDelete
)
//
// Update or delete the specified interface from the cluster view.
// Assumes that a cluster is selected in the left view.
//
{
}
void
DetailsView::mfn_Clear(void)
//
// Delete all items and all columns in the list
//
{
CListCtrl& ctrl = GetListCtrl();
ctrl.DeleteAllItems();
// Delete all of the previous columns.
LV_COLUMN colInfo;
ZeroMemory(&colInfo, sizeof(colInfo));
colInfo.mask = LVCF_SUBITEM;
while(ctrl.GetColumn(0, &colInfo))
{
ctrl.DeleteColumn(0);
}
ctrl.SetImageList( NULL, LVSIL_SMALL );
mfn_UpdateCaption(L"");
//
// Clear currently displayed object handle and it's type.
//
m_ehObj = NULL;
m_objType = IUICallbacks::OBJ_INVALID;
}
VOID
DetailsView::mfn_UpdateCaption(LPCWSTR szText)
{
SetDlgItemText(IDC_TEXT_DETAILS_CAPTION, szText);
}
void
DetailsView::mfn_Lock(void)
{
//
// See notes.txt entry
// 01/23/2002 JosephJ DEADLOCK in Leftview::mfn_Lock
// for the reason for this convoluted implementation of mfn_Lock
//
while (!TryEnterCriticalSection(&m_crit))
{
ProcessMsgQueue();
Sleep(100);
}
}
void
DetailsView::Deinitialize(void)
{
TRACE_INFO(L"-> %!FUNC!");
ASSERT(m_fPrepareToDeinitialize);
// DummyAction(L"Details::Deinitialize");
TRACE_INFO(L"<- %!FUNC!");
}
void DetailsView::OnNotifyKeyDown( NMHDR* pNMHDR, LRESULT* pResult )
{
TRACE_CRIT(L"<->%!FUNC!");
NMLVKEYDOWN *pkd = (NMLVKEYDOWN *) pNMHDR;
if (pkd->wVKey == VK_F6 || pkd->wVKey == VK_TAB)
{
*pResult = 0;
if (! (::GetAsyncKeyState(VK_SHIFT) & 0x8000))
{
GetDocument()->SetFocusNextView(this, (int) pkd->wVKey);
}
else
{
GetDocument()->SetFocusPrevView(this, (int) pkd->wVKey);
}
}
}
void
DetailsView::SetFocus(void)
{
//
// We override our SetFocus, because we really need to set the focus
// on our list control, and also select a listview item if there isn't
// one selected...
//
CListCtrl& ctrl = GetListCtrl();
POSITION pos = NULL;
pos = ctrl.GetFirstSelectedItemPosition();
//
// If no item is selected, select one...
//
if(pos == NULL)
{
ctrl.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
}
ctrl.SetFocus();
}