Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

913 lines
21 KiB

//
// sitesecu.cpp : implementation file
//
#include "stdafx.h"
#include "comprop.h"
#include "ipaddr.hpp"
#include "accessdl.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define THIS_PAGE_IS_COMMON FALSE
#define NULL_IP_ADDRESS (0x00000000)
#define NULL_IP_MASK (0xffffffff)
#define INFINITE_BANDWIDTH (0xffffffff)
#define KILOBYTE (1024L)
#define MEGABYTE (1024L * KILOBYTE)
#define DEF_BANDWIDTH (4096L)
enum
{
BMPID_GRANTED = 0,
BMPID_DENIED,
BMPID_SINGLE,
BMPID_MULTIPLE,
};
//
// CAccess class
//
CAccess::CAccess(
BOOL fGranted,
BOOL fSingle,
DWORD dwIpAddress,
DWORD dwSubnetMask,
BOOL fNetworkByteOrder
)
{
SetValues(fGranted, fSingle, dwIpAddress, dwSubnetMask, fNetworkByteOrder);
}
CAccess::CAccess()
: m_fGranted(TRUE),
m_fSingle(TRUE),
m_iaIpAddress(0L),
m_iaSubnetMask(0L)
{
}
//
// Copy constructor
//
CAccess::CAccess(
const CAccess & ac
)
: m_fGranted(ac.m_fGranted),
m_fSingle(ac.m_fSingle),
m_iaIpAddress(ac.m_iaIpAddress),
m_iaSubnetMask(ac.m_iaSubnetMask)
{
}
CAccess::CAccess(
CAccess * pAccess
)
: m_fGranted(pAccess->m_fGranted),
m_fSingle(pAccess->m_fSingle),
m_iaIpAddress(pAccess->m_iaIpAddress),
m_iaSubnetMask(pAccess->m_iaSubnetMask)
{
}
void
CAccess::SetValues(
BOOL fGranted,
BOOL fSingle,
DWORD dwIpAddress,
DWORD dwSubnetMask,
BOOL fNetworkByteOrder
)
{
m_fGranted = fGranted;
m_fSingle = fSingle;
m_iaIpAddress = CIpAddress((LONG)dwIpAddress, fNetworkByteOrder);
m_iaSubnetMask = CIpAddress((LONG)dwSubnetMask, fNetworkByteOrder);
}
//
// Sorting helper function. The CObjectPlus pointer
// really refers to another CAccess
//
int
CAccess::OrderIpAddress (
const CObjectPlus * pobAccess
) const
{
const CAccess * pob = (CAccess *) pobAccess;
//
// First sort by access/denied
//
int n1 = HasAccess() ? 1 : 0;
int n2 = pob->HasAccess() ? 1 : 0;
if (n2 != n1)
{
return n2 - n1;
}
//
// Ip address is the second key
//
return pob->QueryIpAddress().CompareItem(QueryIpAddress());
}
//
// CAccessListBox : a listbox of CAccess structures
//
IMPLEMENT_DYNAMIC(CAccessListBox, CListBoxEx);
const int CAccessListBox::nBitmaps = 4;
CAccessListBox::CAccessListBox(
int nTab1,
int nTab2
)
{
SetTabs(nTab1, nTab2);
m_strGranted.LoadString(IDS_GRANTED);
m_strDenied.LoadString(IDS_DENIED);
}
void
CAccessListBox::DrawItemEx(
CListBoxExDrawStruct& ds
)
{
CAccess * p = (CAccess *)ds.m_ItemData;
ASSERT(p != NULL);
CDC * pBmpDC = (CDC *)&ds.m_pResources->DcBitMap();
int bmh = ds.m_pResources->BitmapHeight();
int bmw = ds.m_pResources->BitmapWidth();
//
// Display Granted/Denied with appropriate bitmap
//
int nOffset = p->HasAccess() ? BMPID_GRANTED : BMPID_DENIED;
int bm_h = (ds.m_Sel) ? 0 : bmh;
int bm_w = bmw * nOffset;
ds.m_pDC->BitBlt( ds.m_Rect.left+1, ds.m_Rect.top, bmw,
bmh, pBmpDC, bm_w, bm_h, SRCCOPY );
ColumnText(ds.m_pDC, ds.m_Rect.left + bmw + 3, ds.m_Rect.top,
m_nTab1, ds.m_Rect.bottom, p->HasAccess() ? m_strGranted : m_strDenied);
//
// Display IP Address with multiple/single bitmap
//
nOffset = p->IsSingle() ? BMPID_SINGLE : BMPID_MULTIPLE;
bm_h = (ds.m_Sel) ? 0 : bmh;
bm_w = bmw * nOffset;
ds.m_pDC->BitBlt( ds.m_Rect.left + m_nTab1, ds.m_Rect.top,
bmw, bmh, pBmpDC, bm_w, bm_h, SRCCOPY );
ColumnText(ds.m_pDC, ds.m_Rect.left + m_nTab1 + bmw + 3, ds.m_Rect.top, m_nTab2,
ds.m_Rect.bottom, p->QueryIpAddress());
//
// Display subnet mask only for multiple/ip
// addresses
//
if (!p->IsSingle())
{
ColumnText(ds.m_pDC, ds.m_Rect.left + m_nTab2, ds.m_Rect.top,
ds.m_Rect.right, ds.m_Rect.bottom, p->QuerySubnetMask());
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Site Security property page
//
IMPLEMENT_DYNCREATE(SiteSecurityPage, INetPropertyPage)
SiteSecurityPage::SiteSecurityPage(
INetPropertySheet * pSheet
)
: INetPropertyPage(SiteSecurityPage::IDD, pSheet,
::GetModuleHandle(COMPROP_DLL_NAME)),
m_ListBoxRes(
IDB_ACCESS,
m_list_IpAddresses.nBitmaps
),
m_oblAccessList(),
m_list_IpAddresses(),
m_fDefaultGranted(TRUE) // By default, we grant access
{
#if 0 // Keep class wizard happy
//{{AFX_DATA_INIT(CCommonPage)
m_fLimitNetworkUse = FALSE;
m_nGrantedDenied = FALSE;
//}}AFX_DATA_INIT
m_nMaxNetworkUse = 0;
#endif
if ( SingleServerSelected() && QueryGlobalError() == NO_ERROR )
{
m_fLimitNetworkUse = (GetInetGlobalData()->BandwidthLevel
!= INFINITE_BANDWIDTH);
m_nMaxNetworkUse = m_fLimitNetworkUse
? (GetInetGlobalData()->BandwidthLevel / KILOBYTE)
: DEF_BANDWIDTH;
}
m_nGrantedDenied = m_fDefaultGranted ? DEFAULT_GRANTED : DEFAULT_DENIED;
m_list_IpAddresses.AttachResources( &m_ListBoxRes );
}
SiteSecurityPage::~SiteSecurityPage()
{
//
// The access list will clean itself up
//
}
void
SiteSecurityPage::DoDataExchange(
CDataExchange* pDX
)
{
INetPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(SiteSecurityPage)
DDX_Control(pDX, IDC_RADIO_GRANTED, m_radio_Granted);
DDX_Control(pDX, IDC_STATIC_EXCEPT, m_static_Except);
DDX_Control(pDX, IDC_STATIC_BY_DEFAULT, m_static_ByDefault);
DDX_Control(pDX, IDC_BUTTON_ADD, m_button_Add);
DDX_Control(pDX, IDC_STATIC_SUBNETMASK, m_static_SubnetMask);
DDX_Control(pDX, IDC_STATIC_IP_ADDRESS, m_static_IpAddress);
DDX_Control(pDX, IDC_STATIC_ACCESS, m_static_Access);
DDX_Control(pDX, IDC_BUTTON_REMOVE, m_button_Remove);
DDX_Control(pDX, IDC_BUTTON_EDIT, m_button_Edit);
DDX_Radio(pDX, IDC_RADIO_GRANTED, m_nGrantedDenied);
DDX_Control(pDX, IDC_EDIT_MAX_NETWORK_USE, m_edit_MaxNetworkUse);
DDX_Control(pDX, IDC_NETWORK_SPIN, m_spin_MaxNetworkUse);
DDX_Control(pDX, IDC_STATIC_MAX_NETWORK_USE, m_static_MaxNetworkUse);
DDX_Control(pDX, IDC_STATIC_KBS, m_static_KBS);
DDX_Control(pDX, IDC_CHECK_LIMIT_NETWORK_USE, m_check_LimitNetworkUse);
DDX_Check(pDX, IDC_CHECK_LIMIT_NETWORK_USE, m_fLimitNetworkUse);
//}}AFX_DATA_MAP
//
// Private DDX/DDV Routines
//
DDX_Control(pDX, IDC_RADIO_DENIED, m_radio_Denied);
DDX_Control(pDX, IDC_LIST_IP_ADDRESSES, m_list_IpAddresses);
DDV_MinMaxSpin(pDX, CONTROL_HWND(IDC_NETWORK_SPIN), 0, UD_MAXVAL);
DDX_Spin(pDX, IDC_NETWORK_SPIN, m_nMaxNetworkUse);
}
BEGIN_MESSAGE_MAP(SiteSecurityPage, INetPropertyPage)
//{{AFX_MSG_MAP(SiteSecurityPage)
ON_BN_CLICKED(IDC_BUTTON_ADD, OnButtonAdd)
ON_BN_CLICKED(IDC_BUTTON_EDIT, OnButtonEdit)
ON_BN_CLICKED(IDC_BUTTON_REMOVE, OnButtonRemove)
ON_LBN_DBLCLK(IDC_LIST_IP_ADDRESSES, OnDblclkListIpAddresses)
ON_LBN_ERRSPACE(IDC_LIST_IP_ADDRESSES, OnErrspaceListIpAddresses)
ON_LBN_SELCHANGE(IDC_LIST_IP_ADDRESSES, OnSelchangeListIpAddresses)
ON_BN_CLICKED(IDC_RADIO_GRANTED, OnRadioGranted)
ON_BN_CLICKED(IDC_RADIO_DENIED, OnRadioDenied)
ON_WM_VKEYTOITEM()
ON_BN_CLICKED(IDC_CHECK_LIMIT_NETWORK_USE, OnCheckLimitNetworkUse)
//}}AFX_MSG_MAP
ON_EN_CHANGE(IDC_EDIT_MAX_NETWORK_USE, OnItemChanged)
END_MESSAGE_MAP()
//
// Set button states depending on contents
// of the listbox and the controls
//
// Return whether or not "Limit network use" is on
//
BOOL
SiteSecurityPage::SetControlStates()
{
BOOL fSelection = m_list_IpAddresses.GetCurSel() != LB_ERR;
m_button_Edit.EnableWindow(fSelection);
m_button_Remove.EnableWindow(fSelection);
BOOL fLimitOn = m_check_LimitNetworkUse.GetCheck() > 0;
m_static_MaxNetworkUse.EnableWindow(fLimitOn);
m_edit_MaxNetworkUse.EnableWindow(fLimitOn);
m_spin_MaxNetworkUse.EnableWindow(fLimitOn);
m_static_KBS.EnableWindow(fLimitOn);
return fLimitOn;
}
//
// Populate the listbox with the access list
// entries
//
void
SiteSecurityPage::FillListBox()
{
CObListIter obli( m_oblAccessList ) ;
const CAccess * pAccess;
//
// Remember the selection.
//
int nCurSel = m_list_IpAddresses.GetCurSel();
m_list_IpAddresses.SetRedraw(FALSE);
m_list_IpAddresses.ResetContent();
int cItems = 0 ;
for ( /**/ ; pAccess = (CAccess *) obli.Next() ; cItems++ )
{
//
// We only list those not adhering to the default
//
if (pAccess->HasAccess() != m_fDefaultGranted)
{
m_list_IpAddresses.AddString( (LPCTSTR)pAccess );
}
}
m_list_IpAddresses.SetRedraw(TRUE);
m_list_IpAddresses.SetCurSel(nCurSel);
}
//
// Sorting the access list by grant denied and ip address
// FillListBox() should be called after this because
// the listbox will no longer reflect the true status
// of the list of directories.
//
LONG
SiteSecurityPage::SortAccessList()
{
if (m_oblAccessList.GetCount() < 2)
{
return 0;
}
BeginWaitCursor();
LONG l = m_oblAccessList.Sort( (CObjectPlus::PCOBJPLUS_ORDER_FUNC)
& CAccess::OrderIpAddress );
EndWaitCursor();
return l;
}
//
// Bring up the dialog used for add or edit.
// return the value returned by the dialog
//
int
SiteSecurityPage::ShowPropertiesDialog(
BOOL fAdd
)
{
//
// Bring up the dialog
//
CAccess * pAccess = NULL;
int nCurSel = LB_ERR;
if (!fAdd)
{
nCurSel = m_list_IpAddresses.GetCurSel();
ASSERT(nCurSel != LB_ERR);
pAccess = m_list_IpAddresses.GetItem(nCurSel);
ASSERT(pAccess != NULL);
}
CAccessDlg dlgAccess(m_fDefaultGranted, pAccess);
int nReturn = dlgAccess.DoModal();
if (nReturn == IDOK)
{
if (!fAdd)
{
//
// Delete and re-add if editing
//
m_oblAccessList.RemoveIndex(nCurSel);
}
m_oblAccessList.AddTail(new CAccess(dlgAccess.GetAccess()));
SortAccessList();
FillListBox();
}
return nReturn;
}
//
// SiteSecurityPage message handlers
//
BOOL
SiteSecurityPage::OnInitDialog()
{
INetPropertyPage::OnInitDialog();
#ifdef NO_LSA
m_list_IpAddresses.EnableWindow(FALSE);
m_button_Add.EnableWindow(FALSE);
m_button_Edit.EnableWindow(FALSE);
m_button_Remove.EnableWindow(FALSE);
m_static_Access.EnableWindow(FALSE);
m_static_IpAddress.EnableWindow(FALSE);
m_static_SubnetMask.EnableWindow(FALSE);
m_static_Except.EnableWindow(FALSE);
m_static_ByDefault.EnableWindow(FALSE);
m_radio_Granted.EnableWindow(FALSE);
m_radio_Denied.EnableWindow(FALSE);
#endif // NO_LSA
//
// Set tabs
//
RECT rc1, rc2, rc3;
m_static_Access.GetWindowRect(&rc1);
m_static_IpAddress.GetWindowRect(&rc2);
m_static_SubnetMask.GetWindowRect(&rc3);
m_list_IpAddresses.SetTabs(rc2.left - rc1.left - 1, rc3.
left - rc1.left - 1);
if (SingleServerSelected()
&& QueryConfigError() == ERROR_SUCCESS
&& QueryGlobalError() == ERROR_SUCCESS
)
{
#ifndef NO_LSA
//
// We really should have only a deny list or
// grant list, but not both. If we do have
// both, it must manually have been hacked in
// the registry, as we don't set it
//
ASSERT(GetInetConfigData()->GrantIPList == NULL
|| GetInetConfigData()->DenyIPList == NULL);
//
// set the information (both lists in any case).
//
AddIpList(GetInetConfigData()->DenyIPList, FALSE);
AddIpList(GetInetConfigData()->GrantIPList, TRUE);
//
// Deny by default is checked if
//
// There are no entries in the deny list, AND
// the grant list is not empty (even if only
// contained the dummy entry)
//
// Otherwise, granted by default is set
//
if ( GetInetConfigData()->DenyIPList == NULL
&& GetInetConfigData()->GrantIPList != NULL
)
{
TRACEEOLID(_T("By default everyone will be denied"));
m_fDefaultGranted = FALSE;
m_nGrantedDenied = DEFAULT_DENIED;
UpdateData(FALSE);
}
SortAccessList();
FillListBox();
#endif // NO_LSA
}
SetControlStates();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
//
// The "limit network use" checkbox has been clicked
// Enable/disable the "max network use" controls.
//
void
SiteSecurityPage::OnCheckLimitNetworkUse()
{
//
// This is a common change, ask for confirmation
// first
//
if (::AfxMessageBox(IDS_COMMON_CHANGE,
MB_YESNO | MB_DEFBUTTON2) != IDYES)
{
//
// Reverse this action
//
BOOL fLimitOn = m_check_LimitNetworkUse.GetCheck() > 0;
m_check_LimitNetworkUse.SetCheck(fLimitOn ? 0 : 1);
return;
}
if (SetControlStates())
{
m_edit_MaxNetworkUse.SetSel(0,-1);
m_edit_MaxNetworkUse.SetFocus();
}
OnItemChanged();
}
//
// Add and edit bring up the same dialog
//
void
SiteSecurityPage::OnButtonAdd()
{
if (ShowPropertiesDialog(TRUE) == IDOK)
{
SetControlStates();
OnItemChanged();
}
}
void
SiteSecurityPage::OnButtonEdit()
{
int nCurSel = m_list_IpAddresses.GetCurSel();
if (nCurSel != LB_ERR)
{
if (ShowPropertiesDialog(FALSE) == IDOK)
{
SetControlStates();
OnItemChanged();
}
}
}
//
// Remove currently selected item from the listbox
//
void
SiteSecurityPage::OnButtonRemove()
{
//
// Should we ask for validation???
//
int nCurSel = m_list_IpAddresses.GetCurSel();
if (nCurSel != LB_ERR)
{
m_oblAccessList.RemoveIndex(nCurSel);
m_list_IpAddresses.DeleteString(nCurSel);
if (nCurSel)
{
--nCurSel;
}
m_list_IpAddresses.SetCurSel(nCurSel);
SetControlStates();
OnItemChanged();
}
}
//
// Double-clicking on an entry is the same as
// pressing the edit button.
//
void
SiteSecurityPage::OnDblclkListIpAddresses()
{
OnButtonEdit();
}
void
SiteSecurityPage::OnErrspaceListIpAddresses()
{
SetControlStates();
}
void
SiteSecurityPage::OnSelchangeListIpAddresses()
{
SetControlStates();
}
//
// Add list of ip addresses to the access list. The
// return value is TRUE if any dummy entries (with
// ip 0.0.0.0 and mask of 255.255.255.255) were encountered.
//
BOOL
SiteSecurityPage::AddIpList(
LPINETA_IP_SEC_LIST lpList,
BOOL fGranted // TRUE for granted, FALSE for denied list
)
{
BOOL fFoundDummy = FALSE;
TRACEEOLID(_T("Building IP list from API. Granted = ") << fGranted);
if (lpList != NULL)
{
for ( DWORD nCount = 0; nCount < lpList->cEntries; nCount++ )
{
if (lpList->aIPSecEntry[nCount].dwNetwork == NULL_IP_ADDRESS
&& lpList->aIPSecEntry[nCount].dwMask == NULL_IP_MASK
)
{
TRACEEOLID(_T("Found dummy entry; Entry will be skipped"));
fFoundDummy = TRUE;
}
else
{
//
// Build CAccess structure with the ip address
// assumed to be in Network byte order
//
CAccess *pAccess = new CAccess( fGranted,
(( lpList->aIPSecEntry[nCount].dwMask ) == SINGLE_MASK )
? TRUE
: FALSE,
lpList->aIPSecEntry[nCount].dwNetwork,
lpList->aIPSecEntry[nCount].dwMask,
TRUE
);
m_oblAccessList.AddTail( pAccess );
}
}
}
return fFoundDummy;
}
//
// Count the number of granted and the number
// of denied entries in the access list.
//
void
SiteSecurityPage::CountGrantedAndDeniedItems(
int & cGrants,
int & cDenied
)
{
cGrants = 0;
cDenied = 0;
CObListIter obli( m_oblAccessList );
const CAccess * pAccess;
while ( pAccess = (CAccess *) obli.Next())
{
ASSERT(pAccess != NULL);
if (pAccess->HasAccess())
{
++cGrants;
}
else
{
++cDenied;
}
}
}
NET_API_STATUS
SiteSecurityPage::SaveInfo(
BOOL fUpdateData
)
{
if (!IsDirty() || (fUpdateData && !UpdateData(TRUE)))
{
return NO_ERROR;
}
TRACEEOLID(_T("Saving advanced page now..."));
NET_API_STATUS err = 0;
#ifndef NO_LSA
LPINETA_IP_SEC_LIST GrantList = NULL;
LPINETA_IP_SEC_LIST DenyList = NULL;
int cGrants = 0;
int cDenied = 0;
CountGrantedAndDeniedItems(cGrants, cDenied);
TRACEEOLID(_T("Granted = ") << cGrants << _T(" Denied = ") << cDenied);
if ( cGrants == 0
&& !m_fDefaultGranted
)
{
//
// Special case: both lists are empty, but
// we want by default everything to be
// denied. We have to add a dummy
// nil entry to the grant list to accomplish
// this.
//
TRACEEOLID(_T("Adding dummy entry to access list"));
CAccess *pAccess = new CAccess( TRUE /*GRANTED*/, TRUE /*SINGLE*/,
NULL_IP_ADDRESS, NULL_IP_MASK);
m_oblAccessList.AddTail( pAccess );
++cGrants;
}
if (m_fDefaultGranted)
{
//
// do deny list
//
DenyList = GetIpSecList( FALSE, cDenied );
}
else
{
//
// Do grant list
//
GrantList = GetIpSecList( TRUE, cGrants );
}
CInetAConfigInfo config(GetConfig());
config.SetValues(
GrantList,
DenyList
);
err = config.SetInfo(THIS_PAGE_IS_COMMON);
#endif // NO_LSA
if (err == ERROR_SUCCESS)
{
TRACEEOLID(_T("Saving bandwidth level now..."));
CInetAGlobalConfigInfo glob(GetGlobal());
glob.SetValues(
m_fLimitNetworkUse
? m_nMaxNetworkUse * KILOBYTE
: INFINITE_BANDWIDTH
);
//
// Save common info +-+
// |
err = glob.SetInfo( TRUE );
}
#ifndef NO_LSA
//
// Clean up
//
if (GrantList != NULL)
{
delete GrantList;
}
if(DenyList != NULL)
{
delete DenyList;
}
#endif // NO_LSA
SetModified(FALSE);
return err;
}
//
// All EN_CHANGE messages map to this function
//
void
SiteSecurityPage::OnItemChanged()
{
SetModified(TRUE);
}
//
// Generate a list granted or denied ip addresses from the
// oblist. If cItems is 0, the NULL pointer will be
// returned.
//
LPINETA_IP_SEC_LIST
SiteSecurityPage::GetIpSecList(
BOOL fGranted, // TRUE for granted, FALSE for denied
int cItems // Number of items in the list
)
{
if (cItems <= 0)
{
return NULL;
}
LPINETA_IP_SEC_LIST pItemList = (LPINETA_IP_SEC_LIST)new BYTE[
sizeof(INETA_IP_SEC_LIST)
+ (sizeof(INETA_IP_SEC_ENTRY)*cItems)];
ASSERT(pItemList);
pItemList->cEntries = cItems;
//
// Loop through the list to find the
// items of the requested type and
// add them to our little array.
//
int nItems = 0;
CObListIter obli( m_oblAccessList );
const CAccess * pAccess;
while ( pAccess = (CAccess *) obli.Next() )
{
ASSERT(pAccess != NULL);
if (pAccess->HasAccess() == fGranted)
{
pItemList->aIPSecEntry[nItems].dwNetwork =
(LONG)pAccess->QueryIpAddress(TRUE);
pItemList->aIPSecEntry[nItems].dwMask =
(LONG)pAccess->QuerySubnetMask(TRUE);
++nItems;
}
}
ASSERT(nItems == cItems);
return pItemList;
}
//
// Granted by default has been selected.
// Refill the listbox with items that have
// been explicitly denied. Although we can
// only have a deny list or a grant list,
// we keep both of them around until it comes
// time to saving the information.
//
void
SiteSecurityPage::OnRadioGranted()
{
if (!m_fDefaultGranted)
{
m_fDefaultGranted = TRUE;
FillListBox();
OnItemChanged();
}
}
//
// As above, but reverse granted and denied
//
void
SiteSecurityPage::OnRadioDenied()
{
if (m_fDefaultGranted)
{
m_fDefaultGranted = FALSE;
FillListBox();
OnItemChanged();
}
}
//
// Trap insert/delete key
//
int
SiteSecurityPage::OnVKeyToItem(
UINT nKey,
CListBox* pListBox,
UINT nIndex
)
{
switch(nKey)
{
case VK_DELETE:
OnButtonRemove();
break;
case VK_INSERT:
OnButtonAdd();
break;
default:
//
// Not completely handled by this function, let
// windows handle the remaining default action.
//
return -1;
}
//
// No further action is neccesary.
//
return -2;
}