Leaked source code of windows server 2003
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.
 
 
 
 
 
 

890 lines
29 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: C H K L I S T . C P P
//
// Contents: Implements bindings checkbox related utility functions
// and classes.
//
// Notes:
//
// Created: tongl 20 Nov 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "ncnetcfg.h"
#include "ncui.h"
#include "ncstl.h"
#include "lanuiobj.h"
#include "lanui.h"
#include "util.h"
#include "chklist.h"
#include "ncperms.h"
//+---------------------------------------------------------------------------
//
// Member: HrRebuildBindingPathObjCollection
//
// Purpose: Build or rebuild a list of BindingPathObjects,
// establish the links between sub-paths and super-paths,
// as well as between ComponentObjects in the list view
// and elements of the BindingPathObject collection
//
// Arguments:
// [IN] pnccAdapter
// [IN] hList
// [INOUT] pListObj
//
// Returns: TRUE
//
// Author: tongl 20 Nov 1997
//
// Notes:
//
HRESULT HrRebuildBindingPathObjCollection(INetCfgComponent * pnccAdapter,
ListBPObj * pListBPObj)
{
HRESULT hr = S_OK;
// now, add new BindingPathObjects to our list
CIterNetCfgUpperBindingPath ncbpIter(pnccAdapter);
INetCfgBindingPath * pncbp;
TraceTag(ttidLanUi, "*** List of binding paths: begin ***");
// Go through all upper binding paths starting from the current LAN
// adapter, and add to our list of BindingPathObjects:
while(SUCCEEDED(hr) && (hr = ncbpIter.HrNext(&pncbp)) == S_OK)
{
PrintBindingPath(ttidLanUi, pncbp, NULL);
// create a new BindingPathObj
CBindingPathObj * pBPObj = new CBindingPathObj(pncbp);
// insert to our list, sorted by the length of the path
// and establish super/sub path lists with existing items in
// the list
hr = HrInsertBindingPathObj(pListBPObj, pBPObj);
ReleaseObj(pncbp);
}
TraceTag(ttidLanUi, "*** List of binding paths: end ***");
#if DBG
TraceTag(ttidLanUi, "%%% Begin dump the subpath list %%%");
for (ListBPObj_ITER iter = pListBPObj->begin(); iter != pListBPObj->end(); iter++)
{
(*iter)->DumpSubPathList();
}
TraceTag(ttidLanUi, "%%% End dump the subpath list %%%");
#endif
if (hr == S_FALSE) // We just got to the end of the loop
hr = S_OK;
TraceError("HrRebuildBindingPathObjCollection", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: HrInsertBindingPathObj
//
// Purpose: Insert a BindingPathObj to a list of BindingPathObj's,
// keep the list sorted by the length of paths.
// Also establishs super/sub path lists with existing items
// in the list.
//
// Arguments:
// [INOUT] pListBPObj
// [IN] pBPObj
//
// Returns: S_OK if succeeded,
// otherwise return a failure code
//
// Author: tongl 20 Nov 1997
//
// Notes:
//
HRESULT HrInsertBindingPathObj(ListBPObj * pListBPObj,
CBindingPathObj * pBPObj)
{
HRESULT hr = S_OK;
HRESULT hrTmp = S_OK;
ListBPObj_ITER iter;
// insert the new element
for (iter = pListBPObj->begin();iter != pListBPObj->end(); iter++)
{
if ((*iter)->GetDepth() > pBPObj->GetDepth())
break;
}
// insert at the current position
ListBPObj_ITER iterNewItem = pListBPObj->insert(iter, pBPObj);
// set subpaths and superpaths
// Because of the change in the new binding engine for paths for DONT_EXPOSE_LOWER
// components, we have to compare with every item in the list because the length
// no longer garantees which one is the subpath..
for (iter = pListBPObj->begin(); iter != pListBPObj->end(); iter++)
{
// Is this a sub-path ?
hrTmp = ((*iter)->m_pncbp)->IsSubPathOf((*iterNewItem)->m_pncbp);
if (S_OK == hrTmp)
{
hrTmp = (*iter)->HrInsertSuperPath(*iterNewItem);
if SUCCEEDED(hr)
hr = hrTmp;
hrTmp = (*iterNewItem)->HrInsertSubPath(*iter);
if SUCCEEDED(hr)
hr = hrTmp;
}
// Is this a super-path ?
hrTmp = ((*iterNewItem)->m_pncbp)->IsSubPathOf((*iter)->m_pncbp);
if (S_OK == hrTmp)
{
hrTmp = (*iter)->HrInsertSubPath(*iterNewItem);
if SUCCEEDED(hr)
hr = hrTmp;
hrTmp = (*iterNewItem)->HrInsertSuperPath(*iter);
if SUCCEEDED(hr)
hr = hrTmp;
}
}
TraceError("HrInsertBindingPathObj", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: HrRefreshBindingPathObjCollectionState
//
// Purpose: Refresh the binding state of all items in the collection
// of BindingPathObjects
//
// Arguments:
// [INOUT] pListBPObj
//
// Returns: S_OK if succeeded,
// otherwise return a failure code
//
// Author: tongl 20 Nov 1997
//
// Notes:
//
HRESULT HrRefreshBindingPathObjCollectionState(ListBPObj * plistBPObj)
{
HRESULT hr = S_OK;
ListBPObj_ITER iter;
// first, clearup any existing state
for (iter = plistBPObj->begin();iter != plistBPObj->end(); iter++)
{
(*iter)->SetBindingState(BPOBJ_UNSET);
}
// now set the new states
TraceTag(ttidLanUi, "*** List of binding paths: begin ***");
for (iter = plistBPObj->begin();iter != plistBPObj->end(); iter++)
{
Assert((*iter)->GetBindingState() != BPOBJ_ENABLED);
#if DBG
PrintBindingPath (ttidLanUi, (*iter)->m_pncbp, NULL);
#endif
if (BPOBJ_UNSET != (*iter)->GetBindingState())
{
continue;
}
// if it's not disabled yet, i.e. all of its sub paths
// are enabled.
hr = ((*iter)->m_pncbp)->IsEnabled();
if (S_OK == hr) // enabled
{
(*iter)->SetBindingState(BPOBJ_ENABLED);
continue;
}
else if (S_FALSE == hr) // disabled
{
// normal disabled case
(*iter)->SetBindingState(BPOBJ_DISABLED);
// special cases:
// if the check state of the corresponding component is intent_check or mixed or checked
if ((*iter)->m_pCompObj != NULL)
{
// if user is not intentionally unchecking this component
if ((*iter)->m_pCompObj->m_ExpCheckState != UNCHECKED)
{
// if the component should be checked or if it's hidden
if ((((*iter)->m_pCompObj)->m_CheckState == INTENT_CHECKED) ||
(((*iter)->m_pCompObj)->m_CheckState == MIXED) ||
(((*iter)->m_pCompObj)->m_CheckState == CHECKED))
{
// (#297772) We should only do this if one of the subpaths has just
// been re-enabled by user
BOOL fSubPathEnabled = FALSE;
ListBPObj_ITER iterSub;
for (iterSub = (*iter)->m_listSubPaths.begin();
iterSub != (*iter)->m_listSubPaths.end();
iterSub++)
{
// is the top component just enabled ?
INetCfgComponent * pncc;
hr = (*iterSub)->m_pncbp->GetOwner(&pncc);
if (SUCCEEDED(hr))
{
if (((*iterSub)->m_pCompObj != NULL) &&
(CHECKED == (*iterSub)->m_pCompObj->m_ExpCheckState))
{
fSubPathEnabled = TRUE;
}
ReleaseObj(pncc);
if (fSubPathEnabled)
break;
}
}
if (fSubPathEnabled)
{
// Special case: enable the following binding path because
// 1) it's check state is intent or mixed, and
// 2) one of it's sub-paths is newly enabled
#if DBG
TraceTag(ttidLanUi, "Special case, enable the following path:");
PrintBindingPath(ttidLanUi, (*iter)->m_pncbp, "\n");
#endif
hr = HrEnableBindingPath((*iter)->m_pncbp, TRUE);
if (S_OK == hr)
{
(*iter)->SetBindingState(BPOBJ_ENABLED);
continue;
}
}
}
}
}
}
}
TraceTag(ttidLanUi, "*** List of binding paths: end ***");
TraceError("HrRefreshBindingPathObjCollectionState", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: HrRefreshCheckListState
//
// Purpose: Refresh the check state of all components in the list view
//
// Arguments:
// hwndList[in]: Handle of the list view
// pChangedCompObj[in]: Component object which state has
// changed and has induced this refresh call.
// This is used to keep a corresponding "undo" flag
// for the changed component in case other components
// are dependend on this component and the user decides
// not to go through with the change.
// Set to NULL if not applicable.
//
// Returns: S_OK if succeeded,
// otherwise return a failure code
//
// Author: tongl 20 Nov 1997
//
// Notes:
//
HRESULT HrRefreshCheckListState(HWND hListView,
CComponentObj *pChangedCompObj)
{
HRESULT hr = S_OK;
TraceTag(ttidLanUi, "<<<<<Entering HrRefreshCheckListState");
// for each item in the list view
int nlvCount = ListView_GetItemCount(hListView);
LV_ITEM lvItem;
for (int i=0; i< nlvCount; i++)
{
lvItem.iItem = i;
lvItem.iSubItem = 0;
lvItem.mask = LVIF_PARAM;
if (ListView_GetItem(hListView, &lvItem))
{
NET_ITEM_DATA * pnid;
pnid = reinterpret_cast<NET_ITEM_DATA *>(lvItem.lParam);
if (pnid)
{
// get the component object associated with this item
CComponentObj * pCompObj = pnid->pCompObj;
// assume the current component is not dependend on the
// supplied changed component
BOOL fDependedOnChangedComponent = FALSE;
// get counts for enabled & disabled paths
int iEnabled = 0;
int iDisabled =0;
// for each ComponentObject on the list
ListBPObj_ITER iter;
for (iter = (pCompObj->m_listBPObj).begin();
iter != (pCompObj->m_listBPObj).end();
iter++)
{
// the state should not be unset
Assert((*iter)->m_BindingState != BPOBJ_UNSET);
// if enabled
switch ((*iter)->m_BindingState)
{
case BPOBJ_ENABLED:
PrintBindingPath(ttidLanUi, (*iter)->m_pncbp, "is enabled");
iEnabled++;
break;
case BPOBJ_DISABLED:
PrintBindingPath(ttidLanUi, (*iter)->m_pncbp, "is disabled");
// $REVIEW(tongl 1/19/98): According to SteveFal,
// for paths with length>1, we only count "disabled" if
// the sub paths are all enabled but the main path is disabled.
// Bug #304606, can't use length any more with IPX special case
{
// Is all the subpaths enabled ?
BOOL fAllSubPathsEnabled = TRUE;
ListBPObj_ITER iterSubPath;
for (iterSubPath = ((*iter)->m_listSubPaths).begin();
iterSubPath != ((*iter)->m_listSubPaths).end();
iterSubPath++)
{
if ((*iterSubPath)->m_BindingState == BPOBJ_DISABLED)
{
fAllSubPathsEnabled = FALSE;
// Is the changed component part of this
// component's sub paths?
if (pChangedCompObj)
{
ListBPObj_ITER changedIter;
for (changedIter = (pChangedCompObj->m_listBPObj).begin();
changedIter != (pChangedCompObj->m_listBPObj).end();
changedIter++)
{
// Don't need to compare sub path to itself
if (pCompObj != pChangedCompObj)
{
hr = (*changedIter)->m_pncbp->IsSubPathOf((*iterSubPath)->m_pncbp);
if (S_OK == hr)
{
fDependedOnChangedComponent = TRUE;
break;
}
}
}
}
break;
}
}
if (fAllSubPathsEnabled)
{
// Is the binding path itself enabled ?
hr = ((*iter)->m_pncbp)->IsEnabled();
if (S_FALSE == hr)
{
iDisabled++;
hr = S_OK;
}
}
}
break;
default:
PrintBindingPath(ttidLanUi, (*iter)->m_pncbp, "*** has an invalid binding state ***");
break;
}
}
UINT iChkIndex = 0;
BOOL fHasPermission = FHasPermission(NCPERM_ChangeBindState);
if (pnid->dwFlags & NCF_FIXED_BINDING)
{
// Don't change the checked state, we just want to prevent
// the user from changing it.
iChkIndex = SELS_FIXEDBINDING_ENABLED;
}
else if ((iEnabled >0) && (iDisabled == 0))
{
if (!fHasPermission)
{
iChkIndex = SELS_FIXEDBINDING_ENABLED;
}
else
{
// if we enabled the changed component,
// it should not have any dependable
// components anymore to "undo"
if (pCompObj == pChangedCompObj)
{
pCompObj->m_DepStateChanged = FALSE;
}
// current state is "checked"
pCompObj->m_CheckState = CHECKED;
iChkIndex = SELS_CHECKED;
}
}
else if ((iEnabled >0) && (iDisabled > 0))
{
if (!fHasPermission)
{
iChkIndex = SELS_FIXEDBINDING_ENABLED;
}
else
{
// current state is "mixed"
pCompObj->m_CheckState = MIXED;
iChkIndex = SELS_INTERMEDIATE;
}
}
else //iEnabled ==0
{
if (!fHasPermission)
{
iChkIndex = SELS_FIXEDBINDING_DISABLED;
}
else
{
if (pCompObj->m_ExpCheckState == CHECKED)
{
// mark the component who caused this state
// in order to be able to "undo" it later
if ((pChangedCompObj) &&
(fDependedOnChangedComponent))
{
pChangedCompObj->m_DepStateChanged = TRUE;
}
// change current state to "intent checked"
pCompObj->m_CheckState = INTENT_CHECKED;
// $REVIEW(tongl 1/19/98): SteveFal wants to show the
// intent state as checked in the display
// iChkIndex = SELS_INTENTCHECKED;
iChkIndex = SELS_CHECKED;
}
else if (pCompObj->m_ExpCheckState == UNSET)
{
// we are not changing this component
if ((pCompObj->m_CheckState == CHECKED) ||
(pCompObj->m_CheckState == MIXED) ||
(pCompObj->m_CheckState == INTENT_CHECKED))
{
// mark the component who caused this state
// in order to be able to "undo" it later
if ((pChangedCompObj) &&
(fDependedOnChangedComponent))
{
pChangedCompObj->m_DepStateChanged = TRUE;
}
// set current state to "intent checked"
pCompObj->m_CheckState = INTENT_CHECKED;
// $REVIEW(tongl 1/19/98): SteveFal wants to show the
// intent state as checked in the display
// iChkIndex = SELS_INTENTCHECKED;
iChkIndex = SELS_CHECKED;
}
else
{
// set current state to "unchecked"
pCompObj->m_CheckState = UNCHECKED;
iChkIndex = SELS_UNCHECKED;
}
}
else
{
// current state is "unchecked"
pCompObj->m_CheckState = UNCHECKED;
iChkIndex = SELS_UNCHECKED;
}
}
}
// clear up expected check state
pCompObj->m_ExpCheckState = UNSET;
// update the checkmark
AssertSz(iChkIndex, "What's the new check state ??");
lvItem.mask = LVIF_STATE;
lvItem.stateMask = LVIS_STATEIMAGEMASK;
lvItem.state = INDEXTOSTATEIMAGEMASK(iChkIndex);
BOOL ret = ListView_SetItem(hListView, &lvItem);
}
}
}
TraceError("HrRefreshCheckListState", hr);
TraceTag(ttidLanUi, ">>>>>Leaving HrRefreshCheckListState");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: HrEnableBindingPath
//
// Purpose: Wraps the INetCfgBindingPath->Enable method with the following
// flags: if enabling, it applies to all hidden super paths, if
// disabling, it applies to all super paths.
//
//
// Arguments:
// [IN] pncbp : the binding path to enable or disable
// [IN] fEnable : Enable = TRUE; disable = FALSE
//
// Returns: S_OK if succeeded,
// otherwise return a failure code
//
// Author: tongl 5 Dec 1997
//
// Notes:
//
HRESULT HrEnableBindingPath(INetCfgBindingPath * pncbpThis, BOOL fEnable)
{
HRESULT hr;
hr = pncbpThis->Enable(fEnable);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CBindingPathObj implementation
//
// Author: tongl 20 Nov 1997
//
// Notes:
//
CBindingPathObj::CBindingPathObj(INetCfgBindingPath * pncbp)
{
Assert(pncbp);
m_pncbp = pncbp;
m_pncbp->AddRef();
// Initialize other members
m_pCompObj = NULL;
m_BindingState = BPOBJ_UNSET;
HRESULT hr = pncbp->GetDepth(&m_ulPathLen);
TraceError("CBindingPathObj::CBindingPathObj failed on GetDepth", hr);
}
CBindingPathObj::~CBindingPathObj()
{
ReleaseObj(m_pncbp);
m_listSubPaths.erase (m_listSubPaths.begin(), m_listSubPaths.end());
m_listSuperPaths.erase (m_listSuperPaths.begin(), m_listSuperPaths.end());
}
HRESULT CBindingPathObj::HrInsertSuperPath(CBindingPathObj * pbpobjSuperPath)
{
HRESULT hr = S_OK;
ListBPObj_ITER iter;
// insert the new super path into the list, in increasing order of length
for (iter = m_listSuperPaths.begin();
iter != m_listSuperPaths.end();
iter++)
{
if ((*iter)->GetDepth() > pbpobjSuperPath->GetDepth())
break;
}
// insert at the current position
ListBPObj_ITER iterNewItem = m_listSuperPaths.insert(iter, pbpobjSuperPath);
TraceError("CBindingPathObj::HrInsertSuperPath", hr);
return hr;
}
HRESULT CBindingPathObj::HrInsertSubPath(CBindingPathObj * pbpobjSubPath)
{
HRESULT hr = S_OK;
ListBPObj_ITER iter;
// insert the new sub path into the list, in decreasing order of length
for (iter = m_listSubPaths.begin();
iter != m_listSubPaths.end();
iter++)
{
if ((*iter)->GetDepth() < pbpobjSubPath->GetDepth())
break;
}
// insert at the current position
ListBPObj_ITER iterNewItem = m_listSubPaths.insert(iter, pbpobjSubPath);
TraceError("CBindingPathObj::HrInsertSubPath", hr);
return hr;
}
HRESULT CBindingPathObj::HrEnable(ListBPObj * plistBPObj)
{
HRESULT hr = S_OK;
#if DBG
if (m_BindingState == BPOBJ_ENABLED)
{
TraceTag(ttidError, "Why trying to enable a path that is already enabled ?");
}
#endif
AssertSz(m_ulPathLen > 1, "binding path length must be > 1");
if (m_ulPathLen == 2)
{
// enable the current path
hr = HrEnableBindingPath(m_pncbp, TRUE);
}
else
{
if (m_listSubPaths.size() <= 0)
{
PrintBindingPath(ttidLanUi, m_pncbp, "m_ulPathLen > 1, but no subpaths");
AssertSz(FALSE, "if pathLen>1, there must be subpaths");
}
else
{
// check if the sub-path object is enabled, if not then we can't
// enable this path ..
if (m_listSubPaths.back()->m_BindingState == BPOBJ_ENABLED)
{
hr = HrEnableBindingPath(m_pncbp, TRUE);
}
}
}
// now refresh the BindingPathObjectList
::HrRefreshBindingPathObjCollectionState(plistBPObj);
TraceError("CBindingPathObj::HrEnable", hr);
return hr;
}
HRESULT CBindingPathObj::HrDisable(ListBPObj * plistBPObj)
{
HRESULT hr = S_OK;
// Disable the current path
hr = ::HrEnableBindingPath(m_pncbp, FALSE);
if (S_OK == hr)
{
hr = ::HrRefreshBindingPathObjCollectionState(plistBPObj);
}
TraceError("CBindingPathObj::HrDisable", hr);
return hr;
}
#if DBG
VOID CBindingPathObj::DumpSubPathList()
{
TraceTag(ttidLanUi, " +++ Path: +++");
PrintBindingPath(ttidLanUi, m_pncbp, NULL);
if (m_listSubPaths.size())
{
TraceTag(ttidLanUi, "=== Subpaths: ===");
for (ListBPObj_ITER iter = m_listSubPaths.begin();
iter != m_listSubPaths.end();
iter++)
{
(*iter)->DumpPath();
}
}
}
VOID CBindingPathObj::DumpPath()
{
PrintBindingPath(ttidLanUi, m_pncbp, NULL);
}
#endif
//+---------------------------------------------------------------------------
//
// Member: CComponentObj implementation
//
// Author: tongl 20 Nov 1997
//
// Notes:
//
CComponentObj::CComponentObj(INetCfgComponent * pncc)
{
Assert(pncc);
m_pncc = pncc;
m_pncc->AddRef();
// Initialize other members
m_CheckState = UNSET;
m_ExpCheckState = UNSET;
m_DepStateChanged = FALSE;
}
CComponentObj::~CComponentObj()
{
ReleaseObj(m_pncc);
m_listBPObj.erase (m_listBPObj.begin(), m_listBPObj.end());
}
HRESULT CComponentObj::HrInit(ListBPObj * plistBindingPaths)
{
PWSTR pszwThisId;
HRESULT hr = m_pncc->GetId(&pszwThisId);
if (SUCCEEDED(hr))
{
// builds the connection between a component object and a list of
// binding path objects
ListBPObj_ITER iter;
for (iter = plistBindingPaths->begin();
iter != plistBindingPaths->end();
iter ++)
{
INetCfgComponent * pncc;
hr = (*iter)->m_pncbp->GetOwner(&pncc);
if SUCCEEDED(hr)
{
// check if the top component of the binding path is the
// same component by comparing INF id
PWSTR pszwId;
hr = pncc->GetId (&pszwId);
if (SUCCEEDED(hr))
{
if (FEqualComponentId (pszwId, pszwThisId))
{
// Add the BindingPathObj to the end of m_listBPObj
m_listBPObj.push_back((*iter));
// Make m_pCompObj of the BindingPathObj point to this ComponentObj
Assert(NULL == (*iter)->m_pCompObj);
(*iter)->m_pCompObj = this;
}
CoTaskMemFree(pszwId);
}
ReleaseObj(pncc);
}
}
CoTaskMemFree(pszwThisId);
}
TraceError ("CComponentObj::HrInit", hr);
return hr;
}
HRESULT CComponentObj::HrCheck(ListBPObj * plistBPObj)
{
HRESULT hr = S_OK;
HRESULT hrTmp = S_OK;
Assert(m_CheckState == UNCHECKED);
// remember that user wanted to check (enable) this component
m_ExpCheckState = CHECKED;
ListBPObj_ITER iter;
for (iter = m_listBPObj.begin();iter != m_listBPObj.end(); iter++)
{
// enable each binding path with enabled subpath
hrTmp = (*iter)->HrEnable(plistBPObj);
if SUCCEEDED(hr)
hr = hrTmp;
}
TraceError("CComponentObj::HrCheck", hr);
return hr;
}
HRESULT CComponentObj::HrUncheck(ListBPObj * plistBPObj)
{
HRESULT hr = S_OK;
HRESULT hrTmp = S_OK;
Assert(m_CheckState != UNCHECKED);
// remember that user wanted to uncheck (disable) this component
m_ExpCheckState = UNCHECKED;
if (INTENT_CHECKED == m_CheckState)
{
m_CheckState = UNCHECKED;
}
else
{
ListBPObj_ITER iter;
for (iter = m_listBPObj.begin();iter != m_listBPObj.end(); iter++)
{
// disable each binding path with enabled subpath
hrTmp = (*iter)->HrDisable(plistBPObj);
if SUCCEEDED(hr)
hr = hrTmp;
}
}
TraceError("CComponentObj::HrUnCheck", hr);
return hr;
}