windows-nt/Source/XPSP1/NT/net/mmc/rtrfiltr/ipxfltr.cpp
2020-09-26 16:20:57 +08:00

679 lines
20 KiB
C++

//============================================================================
// Copyright(c) 1996, Microsoft Corporation
//
// File: ipxfltr.cpp
//
// History:
// 08/30/96 Ram Cherala Created
//
// Implementation of IPX Filter dialog code
//============================================================================
#include "stdafx.h"
#include "rtrfiltr.h"
#include "ipxfltr.h"
#include "datafmt.h"
#include "ipxadd.h"
#include <ipxrtdef.h>
#include <ipxtfflt.h>
extern "C" {
#include <winsock.h>
}
#include "rtradmin.hm"
#include "listctrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#if 1
static UINT uStringIdTable[] = { IDS_COL_SOURCENETWORK,
IDS_COL_SOURCEMASK,
IDS_COL_SOURCENODE,
IDS_COL_SOURCESOCKET,
IDS_COL_DESTNETWORK,
IDS_COL_DESTMASK,
IDS_COL_DESTNODE,
IDS_COL_DESTSOCKET,
IDS_COL_PACKETTYPE
} ;
#else
static UINT uStringIdTable[] = { IDS_COL_SOURCEADDRESS,
IDS_COL_DESTADDRESS,
IDS_COL_PACKETTYPE
} ;
#endif
/////////////////////////////////////////////////////////////////////////////
// CIpxFilter dialog
CIpxFilter::CIpxFilter(CWnd* pParent /*=NULL*/,
IInfoBase * pInfoBase,
DWORD dwFilterType)
: CBaseDialog( (dwFilterType == FILTER_INBOUND ? CIpxFilter::IDD_INBOUND : CIpxFilter::IDD_OUTBOUND), pParent),
m_pParent(pParent),
m_dwFilterType(dwFilterType)
{
//{{AFX_DATA_INIT(CIpxFilter)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_spInfoBase.Set(pInfoBase);
// SetHelpMap(m_dwHelpMap);
}
CIpxFilter::~CIpxFilter()
{
while (!m_filterList.IsEmpty()) {
delete (FilterListEntry*)m_filterList.RemoveHead();
}
}
void CIpxFilter::DoDataExchange(CDataExchange* pDX)
{
CBaseDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CIpxFilter)
DDX_Control(pDX, IDC_IPX_FILTER_LIST, m_listCtrl);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CIpxFilter, CBaseDialog)
//{{AFX_MSG_MAP(CIpxFilter)
ON_NOTIFY(NM_DBLCLK, IDC_IPX_FILTER_LIST, OnDblclkIpxFilterList)
ON_BN_CLICKED(IDC_IPX_FILTER_ADD, OnIpxFilterAdd)
ON_BN_CLICKED(IDC_IPX_FILTER_EDIT, OnIpxFilterEdit)
ON_BN_CLICKED(IDC_IPX_FILTER_DELETE, OnIpxFilterDelete)
ON_NOTIFY(LVN_GETDISPINFO, IDC_IPX_FILTER_LIST, OnGetdispinfoIpxFilterList)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_IPX_FILTER_LIST, OnNotifyListItemChanged)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
DWORD CIpxFilter::m_dwHelpMap[] =
{
// IDC_IPX_PERMIT, HIDC_IPX_PERMIT,
// IDC_IPX_DENY, HIDC_IPX_DENY,
// IDC_IPX_FILTER_LIST, HIDC_IPX_FILTER_LIST,
// IDC_IPX_FILTER_ADD, HIDC_IPX_FILTER_ADD,
// IDC_IPX_FILTER_EDIT, HIDC_IPX_FILTER_EDIT,
// IDC_IPX_FILTER_DELETE, HIDC_IPX_FILTER_DELETE,
0,0
};
/////////////////////////////////////////////////////////////////////////////
// CIpxFilter message handlers
//------------------------------------------------------------------------------
// Function: CIpxFilter::OnInitDialog
//
// Handles 'WM_INITDIALOG' notification from the dialog
//------------------------------------------------------------------------------
BOOL CIpxFilter::OnInitDialog()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CBaseDialog::OnInitDialog();
ASSERT( m_dwFilterType == FILTER_INBOUND || m_dwFilterType == FILTER_OUTBOUND );
InfoBlock * pBlock;
IPX_TRAFFIC_FILTER_GLOBAL_INFO * pIpxGlobal;
IPX_TRAFFIC_FILTER_INFO * pIpxInfo;
CRect rcDlg, rc;
CString sCol;
DWORD dwErr = NO_ERROR;
HRESULT hr = hrOK;
m_stAny.LoadString(IDS_ANY);
// initialize rectangle for list control display
GetClientRect(rcDlg);
// insert columns
m_listCtrl.GetClientRect(&rc);
UINT i;
for ( i = 0; i < IPX_NUM_COLUMNS; i++ ) {
sCol.LoadString(uStringIdTable[i]);
m_listCtrl.InsertColumn(i, sCol);
AdjustColumnWidth(m_listCtrl, i, sCol);
}
// set extended attributes
ListView_SetExtendedListViewStyle( m_listCtrl.m_hWnd, LVS_EX_FULLROWSELECT );
hr = m_spInfoBase->GetBlock((m_dwFilterType == FILTER_INBOUND) ?
IPX_IN_TRAFFIC_FILTER_GLOBAL_INFO_TYPE :
IPX_OUT_TRAFFIC_FILTER_GLOBAL_INFO_TYPE,
&pBlock, 0);
// The filter was previously defined
// Windows NT Bug : 267091
// We may get a NULL block (one that has 0 data), so we need
// to check for that case also.
if (FHrSucceeded(hr) && (pBlock->pData != NULL))
{
pIpxGlobal = ( IPX_TRAFFIC_FILTER_GLOBAL_INFO * ) pBlock->pData;
SetFilterActionButtonsAndText(m_dwFilterType, pIpxGlobal->FilterAction);
}
else
{
SetFilterActionButtonsAndText(m_dwFilterType, IPX_TRAFFIC_FILTER_ACTION_DENY);
}
DWORD dwCount;
hr = m_spInfoBase->GetBlock( (m_dwFilterType == FILTER_INBOUND) ?
IPX_IN_TRAFFIC_FILTER_INFO_TYPE :
IPX_OUT_TRAFFIC_FILTER_INFO_TYPE, &pBlock,
0);
if (FHrSucceeded(hr))
{
dwCount = pBlock->dwCount;
pIpxInfo = ( PIPX_TRAFFIC_FILTER_INFO ) pBlock->pData;
if (pIpxInfo)
{
for ( i = 0; i < dwCount; i++, pIpxInfo++ ) {
FilterListEntry* pfle = new FilterListEntry;
if (!pfle) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; }
CopyMemory(pfle, pIpxInfo, sizeof(IPX_TRAFFIC_FILTER_INFO));
pfle->pos = m_filterList.AddTail(pfle);
INT item = m_listCtrl.InsertItem( LVIF_TEXT|LVIF_PARAM, i, LPSTR_TEXTCALLBACK,
0,0,0, (LPARAM)pfle);
if(item != -1) {m_listCtrl.SetItemData( item, (DWORD_PTR)pfle); }
}
}
}
// select the first item in the list if list is not empty, else
// disable the radio controls and set sate to Allow
if( m_listCtrl.GetItemCount())
{
m_listCtrl.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);
m_listCtrl.SetFocus();
GetDlgItem(IDC_IPX_FILTER_DELETE)->EnableWindow(TRUE);
GetDlgItem(IDC_IPX_FILTER_EDIT)->EnableWindow(TRUE);
}
else
{
SetFilterActionButtonsAndText(m_dwFilterType, IPX_TRAFFIC_FILTER_ACTION_DENY, FALSE);
GetDlgItem(IDC_IPX_FILTER_DELETE)->EnableWindow(FALSE);
GetDlgItem(IDC_IPX_FILTER_EDIT)->EnableWindow(FALSE);
}
#if 0
if ( dwErr != NO_ERROR ) {
// report construction error and return
::AfxMessageBox(IDS_CONSTRUCTION_ERROR);
}
#endif
return FALSE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
//------------------------------------------------------------------------------
// Function: CIpxFilter::OnDblclkIpxFilterList
// `
// Handles 'NM_DBLCLK' notification from the Filter list control
//------------------------------------------------------------------------------
void CIpxFilter::OnDblclkIpxFilterList(NMHDR* pNMHDR, LRESULT* pResult)
{
OnIpxFilterEdit();
*pResult = 0;
}
//------------------------------------------------------------------------------
// Function: CIpxFilter::OnIpxFilterAdd
// `
// Handles 'NM_DBLCLK' notification from the Filter list control
//------------------------------------------------------------------------------
void CIpxFilter::OnIpxFilterAdd()
{
// Display the IP filter Add/Edit dialog
//
FilterListEntry* pfle = NULL;
CIpxAddEdit dlg( this, (FilterListEntry**)&pfle);
if ( dlg.DoModal() != IDOK ) { return; }
// Add the newly configured filter to our list and update list control
pfle->pos = m_filterList.AddTail( pfle );
int item = m_listCtrl.InsertItem( LVIF_TEXT|LVIF_PARAM, 0, LPSTR_TEXTCALLBACK,
0,0,0, (LPARAM)pfle);
if(item != -1) {m_listCtrl.SetItemData( item, (DWORD_PTR)pfle); }
// enable radio controls when the first item is added to list
m_listCtrl.SetItemState(item, LVIS_SELECTED, LVIS_SELECTED);
m_listCtrl.SetFocus();
}
//------------------------------------------------------------------------------
// Function: CIpxFilter::OnIpxFilterEdit
// `
// Handles 'NM_DBLCLK' notification from the Filter list control
//------------------------------------------------------------------------------
void CIpxFilter::OnIpxFilterEdit()
{
// Get the current list selection
// get the corresponding itemdata
// pass it down to the CIpFltrAddEdit dialog
//
// Get the selected item
//
int i = m_listCtrl.GetNextItem(-1, LVNI_SELECTED);
if (i == -1) { return ; }
//
// Get the interface for the selected item
//
FilterListEntry* pfle = (FilterListEntry*)m_listCtrl.GetItemData(i);
CIpxAddEdit dlg( this, (FilterListEntry**)&pfle );
if ( dlg.DoModal() != IDOK ) { return; }
m_listCtrl.Update(i);
m_listCtrl.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
m_listCtrl.SetFocus();
}
//------------------------------------------------------------------------------
// Function: CIpxFilter::OnIpxFilterDelete
// `
// Handles 'NM_DBLCLK' notification from the Filter list control
//------------------------------------------------------------------------------
void CIpxFilter::OnIpxFilterDelete()
{
// Get the current list selection
// delete it from our private list
// delete the item from the list or just refresh the list view
//
// Get the selected item
//
int i = m_listCtrl.GetNextItem(-1, LVNI_SELECTED);
if (i == -1) { return ; }
//
// Get the interface for the selected item
//
FilterListEntry* pfle = (FilterListEntry*)m_listCtrl.GetItemData(i);
//
// delete it
m_listCtrl.DeleteItem(i);
m_filterList.RemoveAt(pfle->pos);
delete pfle;
//
// select the next available list item
//
// disable radio controls if all items in list are deleted
// they will be reenabled when the first filter is added to list
if( !m_listCtrl.GetItemCount())
{
SetFilterActionButtonsAndText(m_dwFilterType, IPX_TRAFFIC_FILTER_ACTION_DENY, FALSE);
}
else if (m_listCtrl.GetItemCount() == i)
m_listCtrl.SetItemState((i == 0? i: i-1), LVIS_SELECTED, LVIS_SELECTED);
else
m_listCtrl.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
m_listCtrl.SetFocus();
}
//------------------------------------------------------------------------------
// Function: CIpxFilter::OnOK
// `
// Handles 'NM_DBLCLK' notification from the Filter list control
//------------------------------------------------------------------------------
void CIpxFilter::OnOK()
{
// If the filters information changed, write this to registry
// and return
DWORD dwSize, dwCount, dwErr;
HRESULT hr = hrOK;
dwCount = (DWORD) m_filterList.GetCount();
if (!dwCount && IsDlgButtonChecked(IDC_IPX_DENY) )
{
if (m_dwFilterType == FILTER_INBOUND)
AfxMessageBox(IDS_RECEIVE_NO_FILTER, MB_OK);
else
AfxMessageBox(IDS_TRANSMIT_NO_FILTER, MB_OK);
return;
}
if(dwCount)
{
InfoBlock * pBlock = new InfoBlock;
// First Set the global information
if (!pBlock) { // display an error message for no memory
AfxMessageBox(IDS_ERROR_NO_MEMORY);
return;
};
dwSize = pBlock->dwSize = sizeof( IPX_TRAFFIC_FILTER_GLOBAL_INFO );
pBlock->dwType = (m_dwFilterType == FILTER_INBOUND) ?
IPX_IN_TRAFFIC_FILTER_GLOBAL_INFO_TYPE :
IPX_OUT_TRAFFIC_FILTER_GLOBAL_INFO_TYPE,
pBlock->dwCount = 1;
pBlock->pData = new BYTE[dwSize];
if(!pBlock->pData) { // display an error message for no memory
delete pBlock;
AfxMessageBox(IDS_ERROR_NO_MEMORY);
return;
}
IPX_TRAFFIC_FILTER_GLOBAL_INFO * pIpxGlobal = (IPX_TRAFFIC_FILTER_GLOBAL_INFO*)pBlock->pData;
pIpxGlobal->FilterAction = IsDlgButtonChecked(IDC_IPX_PERMIT) ? IPX_TRAFFIC_FILTER_ACTION_DENY : IPX_TRAFFIC_FILTER_ACTION_PERMIT;
if( FHrOK(m_spInfoBase->BlockExists(
(m_dwFilterType == FILTER_INBOUND)?
IPX_IN_TRAFFIC_FILTER_GLOBAL_INFO_TYPE :
IPX_OUT_TRAFFIC_FILTER_GLOBAL_INFO_TYPE )))
{
hr = m_spInfoBase->SetBlock(
(m_dwFilterType == FILTER_INBOUND)?
IPX_IN_TRAFFIC_FILTER_GLOBAL_INFO_TYPE :
IPX_OUT_TRAFFIC_FILTER_GLOBAL_INFO_TYPE ,
pBlock, 0);
}
else
{
hr = m_spInfoBase->AddBlock(
(m_dwFilterType == FILTER_INBOUND)?
IPX_IN_TRAFFIC_FILTER_GLOBAL_INFO_TYPE :
IPX_OUT_TRAFFIC_FILTER_GLOBAL_INFO_TYPE,
dwSize,
pBlock->pData,
1, FALSE);
}
delete[] pBlock->pData;
// now set the filter information
pBlock->dwType = (m_dwFilterType == FILTER_INBOUND) ? IPX_IN_TRAFFIC_FILTER_INFO_TYPE : IPX_OUT_TRAFFIC_FILTER_INFO_TYPE ;
// dwCount -1 because FILTER_DESCRIPTOR already has room for one FILTER_INFO structure
pBlock->dwSize = sizeof(IPX_TRAFFIC_FILTER_INFO);
dwSize = sizeof (IPX_TRAFFIC_FILTER_INFO) * dwCount;
pBlock->dwCount = dwCount;
pBlock->pData = new BYTE[dwSize];
if(!pBlock->pData) { // display an error message for no memory
delete pBlock;
AfxMessageBox(IDS_ERROR_NO_MEMORY);
return;
}
IPX_TRAFFIC_FILTER_INFO * pIPXfInfo;
pIPXfInfo = (IPX_TRAFFIC_FILTER_INFO*)pBlock->pData;
POSITION pos;
pos = m_filterList.GetHeadPosition();
while(pos) {
FilterListEntry* pfle = (FilterListEntry*)m_filterList.GetNext(pos);
CopyMemory(pIPXfInfo, pfle, sizeof(IPX_TRAFFIC_FILTER_INFO));
pIPXfInfo++;
}
if( FHrOK(m_spInfoBase->BlockExists(m_dwFilterType == FILTER_INBOUND?IPX_IN_TRAFFIC_FILTER_INFO_TYPE:IPX_OUT_TRAFFIC_FILTER_INFO_TYPE)))
{
hr = m_spInfoBase->SetBlock(
(m_dwFilterType == FILTER_INBOUND) ? IPX_IN_TRAFFIC_FILTER_INFO_TYPE : IPX_OUT_TRAFFIC_FILTER_INFO_TYPE,
pBlock, 0);
}
else
{
hr = m_spInfoBase->AddBlock(
(m_dwFilterType == FILTER_INBOUND) ? IPX_IN_TRAFFIC_FILTER_INFO_TYPE : IPX_OUT_TRAFFIC_FILTER_INFO_TYPE,
pBlock->dwSize,
pBlock->pData,
pBlock->dwCount,
FALSE);
}
if (!FHrSucceeded(hr))
{
AfxMessageBox(IDS_ERROR_SETTING_BLOCK);
}
delete[] pBlock->pData;
delete pBlock;
}
else
{
// remove any previously defined filters
hr = m_spInfoBase->AddBlock((m_dwFilterType == FILTER_INBOUND) ?
IPX_IN_TRAFFIC_FILTER_GLOBAL_INFO_TYPE :
IPX_OUT_TRAFFIC_FILTER_GLOBAL_INFO_TYPE,
0, NULL, 0, TRUE);
hr = m_spInfoBase->AddBlock((m_dwFilterType == FILTER_INBOUND) ?
IPX_IN_TRAFFIC_FILTER_INFO_TYPE :
IPX_OUT_TRAFFIC_FILTER_INFO_TYPE,
0, NULL, 0, TRUE);
}
CBaseDialog::OnOK();
}
//------------------------------------------------------------------------------
// Function: CIpxFilter::OnCancel
// `
// Handles 'NM_DBLCLK' notification from the Filter list control
//------------------------------------------------------------------------------
void CIpxFilter::OnCancel()
{
// TODO: Add extra cleanup here
CBaseDialog::OnCancel();
}
//------------------------------------------------------------------------------
// Function: CIpxFilter::SetFilterActionButtonsAndText
//
// Called to set the 'Filter Action' radio-buttons and corresponding text
// Enables/Disables controls based on 'bEnable' value - defaults to enable
//------------------------------------------------------------------------------
VOID
CIpxFilter::SetFilterActionButtonsAndText(
DWORD dwFilterType,
DWORD dwAction,
BOOL bEnable
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CheckDlgButton( IDC_IPX_PERMIT, dwAction == IPX_TRAFFIC_FILTER_ACTION_DENY );
CheckDlgButton( IDC_IPX_DENY, dwAction == IPX_TRAFFIC_FILTER_ACTION_PERMIT );
CString sItem;
// GetDlgItem(IDC_IPX_PERMIT)->EnableWindow(bEnable);
// GetDlgItem(IDC_IPX_DENY)->EnableWindow(bEnable);
// sItem.LoadString( dwFilterType == FILTER_INBOUND? IDS_RECEIVE : IDS_TRANSMIT );
// SetDlgItemText( IDC_IPX_PERMIT, sItem );
// sItem.LoadString( IDS_DROP );
// SetDlgItemText( IDC_IPX_DENY, sItem );
}
#if 1
enum {
SRC_NETWORK=0,
SRC_MASK,
SRC_NODE,
SRC_SOCKET,
DEST_NETWORK,
DEST_MASK,
DEST_NODE,
DEST_SOCKET,
PACKET_TYPE
};
#else
enum {
SRC_ADDRESS=0,
DEST_ADDRESS,
PACKET_TYPE
};
#endif
//------------------------------------------------------------------------------
// Function: CIpxFilter::OnGetdispinfoIpxFilterList
//
// Handles 'LVN_GETDISPINFO' notification from the list control
//------------------------------------------------------------------------------
void CIpxFilter::OnGetdispinfoIpxFilterList(NMHDR* pNMHDR, LRESULT* pResult)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
WCHAR buffer[32];
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
CString cStr;
BOOL bFilter;
FilterListEntry * pfle = (FilterListEntry*)pDispInfo->item.lParam;
// Setup some default
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) m_stAny;
switch( pDispInfo->hdr.code )
{
case LVN_GETDISPINFO:
switch( pDispInfo->item.iSubItem )
{
case SRC_NETWORK:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_SRCNET)
pfle->stSourceNetwork << CIPX_NETWORK(pfle->SourceNetwork);
else
pfle->stSourceNetwork = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stSourceNetwork;
break;
case SRC_MASK:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_SRCNET)
pfle->stSourceNetworkMask << CIPX_NETWORK(pfle->SourceNetworkMask);
else
pfle->stSourceNetworkMask = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stSourceNetworkMask;
break;
case SRC_NODE:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_SRCNODE)
pfle->stSourceNode << CIPX_NODE(pfle->SourceNode);
else
pfle->stSourceNode = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stSourceNode;
break;
case SRC_SOCKET:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_SRCSOCKET)
pfle->stSourceSocket << CIPX_SOCKET(pfle->SourceSocket);
else
pfle->stSourceSocket = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stSourceSocket;
break;
case DEST_NETWORK:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_DSTNET)
pfle->stDestinationNetwork << CIPX_NETWORK(pfle->DestinationNetwork);
else
pfle->stDestinationNetwork = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stDestinationNetwork;
break;
case DEST_MASK:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_DSTNET)
pfle->stDestinationNetworkMask << CIPX_NETWORK(pfle->DestinationNetworkMask);
else
pfle->stDestinationNetworkMask = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stDestinationNetworkMask;
break;
case DEST_NODE:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_DSTNODE)
pfle->stDestinationNode << CIPX_NODE(pfle->DestinationNode);
else
pfle->stDestinationNode = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stDestinationNode;
break;
case DEST_SOCKET:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_DSTSOCKET)
pfle->stDestinationSocket << CIPX_SOCKET(pfle->DestinationSocket);
else
pfle->stDestinationSocket = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stDestinationSocket;
break;
case PACKET_TYPE:
if (pfle->FilterDefinition & IPX_TRAFFIC_FILTER_ON_PKTTYPE)
pfle->stPacketType << CIPX_PACKET_TYPE(pfle->PacketType);
else
pfle->stPacketType = m_stAny;
pDispInfo->item.pszText = (LPTSTR) (LPCTSTR) pfle->stPacketType;
break;
default:
break;
}
}
*pResult = 0;
}
void CIpxFilter::OnNotifyListItemChanged(NMHDR *pNmHdr, LRESULT *pResult)
{
BOOL fSelected;
fSelected = (m_listCtrl.GetNextItem(-1, LVNI_SELECTED) != -1);
GetDlgItem(IDC_IPX_FILTER_DELETE)->EnableWindow(fSelected);
GetDlgItem(IDC_IPX_FILTER_EDIT)->EnableWindow(fSelected);
}