windows-nt/Source/XPSP1/NT/net/config/netcfg/engine/bindings.cpp
2020-09-26 16:20:57 +08:00

801 lines
17 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: B I N D I N G S . C P P
//
// Contents: The basic datatypes for binding objects. Bindpaths are
// ordered collections of component pointers. Bindsets
// are a collection of bindpaths. This module implements
// the operations that are valid on binpaths and bindsets.
//
// Notes:
//
// Author: shaunco 15 Jan 1999
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "bindings.h"
#include "complist.h"
#include "diagctx.h"
#include "nceh.h"
//+---------------------------------------------------------------------------
// CBindPath -
//
bool
CBindPath::operator< (
const CBindPath& OtherPath) const
{
TraceFileFunc(ttidNetCfgBind);
const_iterator iterThis;
const_iterator iterOther;
NETCLASS Class;
NETCLASS OtherClass;
for (iterThis = begin(), iterOther = OtherPath.begin();
(iterThis != end()) && (iterOther != OtherPath.end());
iterThis++, iterOther++)
{
Class = (*iterThis)->Class();
OtherClass = (*iterOther)->Class();
if (Class > OtherClass)
{
return TRUE;
}
else if (Class < OtherClass)
{
return FALSE;
}
}
return size() > OtherPath.size();
}
bool
CBindPath::operator> (
const CBindPath& OtherPath) const
{
TraceFileFunc(ttidNetCfgBind);
const_iterator iterThis;
const_iterator iterOther;
NETCLASS Class;
NETCLASS OtherClass;
for (iterThis = begin(), iterOther = OtherPath.begin();
(iterThis != end()) && (iterOther != OtherPath.end());
iterThis++, iterOther++)
{
Class = (*iterThis)->Class();
OtherClass = (*iterOther)->Class();
if (Class < OtherClass)
{
return TRUE;
}
else if (Class > OtherClass)
{
return FALSE;
}
}
return size() < OtherPath.size();
}
BOOL
CBindPath::FAllComponentsLoadedOkayIfLoadedAtAll () const
{
TraceFileFunc(ttidNetCfgBind);
CBindPath::const_iterator iter;
const CComponent* pComponent;
Assert (this);
for (iter = begin(); iter != end(); iter++)
{
pComponent = *iter;
Assert (pComponent);
if (!pComponent->Ext.FLoadedOkayIfLoadedAtAll())
{
return FALSE;
}
}
return TRUE;
}
BOOL
CBindPath::FGetPathToken (
OUT PWSTR pszToken,
IN OUT ULONG* pcchToken) const
{
TraceFileFunc(ttidNetCfgBind);
const_iterator iter;
const CComponent* pComponent;
ULONG cchIn;
ULONG cch;
BOOL fFirstTime;
Assert (this);
Assert (pcchToken);
if (pszToken)
{
*pszToken = 0;
}
cchIn = *pcchToken;
cch = 0;
for (iter = begin(), fFirstTime = TRUE; iter != end(); iter++)
{
if (!fFirstTime)
{
cch += 2;
if (pszToken && (cch <= cchIn))
{
wcscat (pszToken, L"->");
}
}
else
{
fFirstTime = FALSE;
}
pComponent = *iter;
Assert (pComponent);
cch += wcslen (pComponent->PszGetPnpIdOrInfId());
if (pszToken && (cch <= cchIn))
{
wcscat (pszToken, pComponent->PszGetPnpIdOrInfId());
}
}
*pcchToken = cch;
return cch <= cchIn;
}
BOOL
CBindPath::FIsSameBindPathAs (
IN const CBindPath* pOtherPath) const
{
TraceFileFunc(ttidNetCfgBind);
UINT unThisSize;
UINT unOtherSize;
UINT cb;
Assert (this);
Assert (pOtherPath);
unThisSize = this->size();
unOtherSize = pOtherPath->size();
if ((0 == unThisSize) || (0 == unOtherSize) || (unThisSize != unOtherSize))
{
return FALSE;
}
// Sizes are non-zero and equal. Compare the data.
//
cb = (UINT)((BYTE*)(end()) - (BYTE*)(begin()));
Assert (cb == unThisSize * sizeof(CComponent*));
return (0 == memcmp (
(BYTE*)(this->begin()),
(BYTE*)(pOtherPath->begin()),
cb));
}
BOOL
CBindPath::FIsSubPathOf (
IN const CBindPath* pOtherPath) const
{
TraceFileFunc(ttidNetCfgBind);
UINT unThisSize;
UINT unOtherSize;
UINT unSkipComponents;
UINT cb;
Assert (this);
Assert (pOtherPath);
unThisSize = this->size();
unOtherSize = pOtherPath->size();
if ((0 == unThisSize) || (0 == unOtherSize) || (unThisSize >= unOtherSize))
{
return FALSE;
}
// This size is less than other. Compare the data starting at the
// component pointer in the other path that will have the same depth
// as this path.
//
cb = (UINT)((BYTE*)(end()) - (BYTE*)(begin()));
// The component pointer in the other path that we start comparing at
// is at an offset equal to the difference in path sizes.
//
// e.g. other path: a->b->c->d->e size=5
// this path: c->d->e size=3
// start comparing after skipping 5-3=2 components of the other path
//
Assert (unOtherSize > unThisSize);
unSkipComponents = unOtherSize - unThisSize;
return (0 == memcmp (
(BYTE*)(this->begin()),
(BYTE*)(pOtherPath->begin() + unSkipComponents),
cb));
}
HRESULT
CBindPath::HrAppendBindPath (
IN const CBindPath* pBindPath)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
Assert (this);
Assert (pBindPath);
NC_TRY
{
insert (end(), pBindPath->begin(), pBindPath->end());
DbgVerifyBindpath ();
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CBindPath::HrAppendBindPath");
return hr;
}
HRESULT
CBindPath::HrAppendComponent (
IN const CComponent* pComponent)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
Assert (this);
Assert (pComponent);
Assert (!FContainsComponent (pComponent));
NC_TRY
{
push_back (const_cast<CComponent*>(pComponent));
DbgVerifyBindpath ();
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CBindPath::HrAppendComponent");
return hr;
}
HRESULT
CBindPath::HrGetComponentsInBindPath (
IN OUT CComponentList* pComponents) const
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
CBindPath::const_iterator iter;
const CComponent* pComponent;
Assert (this);
Assert (pComponents);
for (iter = begin(); iter != end(); iter++)
{
pComponent = *iter;
Assert (pComponent);
hr = pComponents->HrInsertComponent (pComponent,
INS_IGNORE_IF_DUP | INS_SORTED);
if (S_OK != hr)
{
TraceHr (ttidError, FAL, hr, FALSE,
"CBindPath::HrGetComponentsInBindPath");
return hr;
}
}
return S_OK;
}
HRESULT
CBindPath::HrInsertComponent (
IN const CComponent* pComponent)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
Assert (this);
Assert (pComponent);
Assert (!FContainsComponent (pComponent));
NC_TRY
{
insert (begin(), const_cast<CComponent*>(pComponent));
DbgVerifyBindpath ();
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CBindPath::HrInsertComponent");
return hr;
}
HRESULT
CBindPath::HrReserveRoomForComponents (
IN UINT cComponents)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
NC_TRY
{
reserve (cComponents);
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE,
"CBindPath::HrReserveRoomForComponents");
return hr;
}
#if DBG
VOID
CBindPath::DbgVerifyBindpath ()
{
TraceFileFunc(ttidNetCfgBind);
const_iterator iter;
const_iterator iterOther;
const CComponent* pComponent;
const CComponent* pOtherComponent;
Assert (this);
// Make sure the bindpath does not contain any duplicate component
// pointers.
//
for (iter = begin(); iter != end(); iter++)
{
pComponent = *iter;
Assert (pComponent);
for (iterOther = begin(); iterOther != end(); iterOther++)
{
pOtherComponent = *iterOther;
Assert (pOtherComponent);
if (iter == iterOther)
{
continue;
}
Assert (pComponent != pOtherComponent);
}
}
}
#endif
//+---------------------------------------------------------------------------
// CBindingSet -
//
VOID
CBindingSet::Printf (
TRACETAGID ttid,
PCSTR pszPrefixLine) const
{
TraceFileFunc(ttidNetCfgBind);
WCHAR pszBuf [1024];
WCHAR* pch;
ULONG cch;
Assert (this);
if (pszPrefixLine)
{
g_pDiagCtx->Printf (ttid, pszPrefixLine);
}
const CBindPath* pBindPath;
INT nIndex = 1;
for (pBindPath = begin(); pBindPath != end(); pBindPath++, nIndex++)
{
pch = pszBuf + wsprintfW (pszBuf, L"%2i: ", nIndex);
cch = celems(pszBuf) - wcslen(pszBuf) - 1;
if (pBindPath->FGetPathToken (pch, &cch))
{
g_pDiagCtx->Printf (ttid, "%S\n", pszBuf);
}
}
}
BOOL
CBindingSet::FContainsBindPath (
IN const CBindPath* pBindPathToCheckFor) const
{
TraceFileFunc(ttidNetCfgBind);
const CBindPath* pBindPath;
Assert (this);
Assert (pBindPathToCheckFor);
for (pBindPath = begin(); pBindPath != end(); pBindPath++)
{
if (pBindPath->FIsSameBindPathAs (pBindPathToCheckFor))
{
return TRUE;
}
}
return FALSE;
}
BOOL
CBindingSet::FContainsComponent (
IN const CComponent* pComponent) const
{
TraceFileFunc(ttidNetCfgBind);
const CBindPath* pBindPath;
Assert (this);
Assert (pComponent);
for (pBindPath = begin(); pBindPath != end(); pBindPath++)
{
if (pBindPath->FContainsComponent (pComponent))
{
return TRUE;
}
}
return FALSE;
}
HRESULT
CBindingSet::HrAppendBindingSet (
IN const CBindingSet* pBindSet)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
const CBindPath* pSrcPath;
Assert (this);
Assert (pBindSet);
hr = S_OK;
NC_TRY
{
for (pSrcPath = pBindSet->begin();
pSrcPath != pBindSet->end();
pSrcPath++)
{
if (!FContainsBindPath (pSrcPath))
{
insert (end(), *pSrcPath);
}
}
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CBindingSet::HrAppendBindingSet");
return hr;
}
HRESULT
CBindingSet::HrAddBindPath (
IN const CBindPath* pBindPath,
IN DWORD dwFlags)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
Assert (this);
Assert (pBindPath);
Assert (!pBindPath->FIsEmpty());
Assert ((dwFlags & INS_ASSERT_IF_DUP) || (dwFlags & INS_IGNORE_IF_DUP));
Assert ((dwFlags & INS_APPEND) || (dwFlags & INS_INSERT));
Assert (!(INS_SORTED & dwFlags) && !(INS_NON_SORTED & dwFlags));
if (FContainsBindPath (pBindPath))
{
// If the caller didn't tell us to ignore duplicates, we assert
// if there is one because it is bad, bad, bad to have duplicate
// bindpaths in the set.
//
// If we have a dup, we want the caller to be aware that it
// is possible, and pass us the flag telling us to ignore it.
// Otherwise, we assert to let them know. (And we still ignore
// it.)
Assert (dwFlags & INS_IGNORE_IF_DUP);
return S_OK;
}
NC_TRY
{
// Either insert the bindpath or append it.
//
iterator iter = begin();
if (dwFlags & INS_APPEND)
{
iter = end();
}
insert (iter, *pBindPath);
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CBindingSet::HrAddBindPath");
return hr;
}
HRESULT
CBindingSet::HrAddBindPathsInSet1ButNotInSet2 (
IN const CBindingSet* pSet1,
IN const CBindingSet* pSet2)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
const CBindPath* pBindPath;
Assert (this);
Assert (pSet1);
Assert (pSet2);
Assert ((this != pSet1) && (this != pSet2));
hr = S_OK;
for (pBindPath = pSet1->begin();
pBindPath != pSet1->end();
pBindPath++)
{
if (pSet2->FContainsBindPath (pBindPath))
{
continue;
}
hr = HrAddBindPath (pBindPath, INS_IGNORE_IF_DUP | INS_APPEND);
if (S_OK != hr)
{
break;
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CBindingSet::HrAddBindPathsInSet1ButNotInSet2");
return hr;
}
HRESULT
CBindingSet::HrCopyBindingSet (
IN const CBindingSet* pSourceSet)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
Assert (this);
Assert (pSourceSet);
NC_TRY
{
*this = *pSourceSet;
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CBindingSet::HrCopyBindingSet");
return hr;
}
HRESULT
CBindingSet::HrGetAffectedComponentsInBindingSet (
IN OUT CComponentList* pComponents) const
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
const CBindPath* pBindPath;
Assert (this);
Assert (pComponents);
hr = S_OK;
for (pBindPath = begin(); pBindPath != end(); pBindPath++)
{
hr = pComponents->HrInsertComponent (pBindPath->POwner(),
INS_IGNORE_IF_DUP | INS_SORTED);
if (S_OK != hr)
{
break;
}
// For bindpaths from a protocol to an adpater, we want to
// add the adapter to the component list because it will need
// to have its upper bind changed.
//
if (pBindPath->CountComponents() == 2)
{
const CComponent* pAdapter;
pAdapter = pBindPath->PLastComponent();
if (FIsEnumerated (pAdapter->Class()))
{
hr = pComponents->HrInsertComponent (pAdapter,
INS_IGNORE_IF_DUP | INS_SORTED);
if (S_OK != hr)
{
break;
}
}
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CBindingSet::HrGetAffectedComponentsInBindingSet");
return hr;
}
HRESULT
CBindingSet::HrReserveRoomForBindPaths (
IN UINT cBindPaths)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
NC_TRY
{
reserve (cBindPaths);
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE,
"CBindingSet::HrReserveRoomForBindPaths");
return hr;
}
VOID
CBindingSet::RemoveBindPath (
IN const CBindPath* pBindPath)
{
TraceFileFunc(ttidNetCfgBind);
CBindPath* pScan;
for (pScan = begin(); pScan != end(); pScan++)
{
if (pScan->FIsSameBindPathAs (pBindPath))
{
erase (pScan);
return;
}
}
}
VOID
CBindingSet::RemoveBindPathsWithComponent (
IN const CComponent* pComponent)
{
TraceFileFunc(ttidNetCfgBind);
CBindPath* pBindPath;
Assert (this);
Assert (pComponent);
pBindPath = begin();
while (pBindPath != end())
{
if (pBindPath->FContainsComponent(pComponent))
{
erase (pBindPath);
}
else
{
pBindPath++;
}
}
}
VOID
CBindingSet::RemoveSubpaths ()
{
TraceFileFunc(ttidNetCfgBind);
CBindPath* pCandidate;
CBindPath* pBindPath;
Assert (this);
for (pBindPath = begin(); pBindPath != end(); pBindPath++)
{
pCandidate = begin();
while (pCandidate != end())
{
if (pCandidate->FIsSubPathOf (pBindPath))
{
// FIsSubPathOf returns FALSE when asked if a bindpath
// is a subpath of itself. (Set-theorectially, this is
// incorrect, but having it return FALSE for this case
// prevents us from having to make another check.
//
Assert (pCandidate != pBindPath);
erase (pCandidate);
// If erasing a bindpath that occurs before the current
// outer loop enumerator, we need to back it up because
// the erase would move everything up by one, but we still
// want to finish the inner loop for this current outer
// bindpath.
//
if (pCandidate < pBindPath)
{
pBindPath--;
}
}
else
{
pCandidate++;
}
}
}
}
VOID
CBindingSet::SortForPnpBind ()
{
TraceFileFunc(ttidNetCfgBind);
// Sort where bindpaths closes to the adapters come first.
//
sort<iterator> (begin(), end(), greater<CBindPath>());
}
VOID
CBindingSet::SortForPnpUnbind ()
{
TraceFileFunc(ttidNetCfgBind);
// Sort where bindpaths furthest from the adapters come first.
//
sort<iterator> (begin(), end(), less<CBindPath>());
}