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

707 lines
19 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: S T A B L E . C P P
//
// Contents: Implements operations that are valid on stack entries and
// stack tables.
//
// Notes:
//
// Author: shaunco 15 Jan 1999
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "nceh.h"
#include "netcfg.h"
#include "stable.h"
BOOL
CStackTable::FStackEntryInTable (
IN const CComponent* pUpper,
IN const CComponent* pLower) const
{
const CStackEntry* pStackEntry;
Assert (this);
Assert (pUpper);
Assert (pLower);
for (pStackEntry = begin(); pStackEntry != end(); pStackEntry++)
{
if ((pUpper == pStackEntry->pUpper) &&
(pLower == pStackEntry->pLower))
{
return TRUE;
}
}
return FALSE;
}
VOID
CStackTable::RemoveStackEntry(
IN const CComponent* pUpper,
IN const CComponent* pLower)
{
CStackEntry* pStackEntry;
Assert (this);
Assert (pUpper);
Assert (pLower);
for (pStackEntry = begin(); pStackEntry != end(); pStackEntry++)
{
if ((pUpper == pStackEntry->pUpper) &&
(pLower == pStackEntry->pLower))
{
erase(pStackEntry);
break;
}
}
}
HRESULT
CStackTable::HrCopyStackTable (
IN const CStackTable* pSourceTable)
{
HRESULT hr;
Assert (this);
Assert (pSourceTable);
NC_TRY
{
*this = *pSourceTable;
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CStackTable::HrCopyStackTable");
return hr;
}
HRESULT
CStackTable::HrInsertStackEntriesForComponent (
IN const CComponent* pComponent,
IN const CComponentList* pComponents,
IN DWORD dwFlags /* INS_FLAGS */)
{
HRESULT hr;
CStackEntry StackEntry;
CComponentList::const_iterator iter;
const CComponent* pScan;
Assert (this);
Assert (pComponent);
Assert (pComponents);
hr = S_OK;
// Insert the stack entries for other components which bind with this one.
//
for (iter = pComponents->begin();
iter != pComponents->end();
iter++)
{
pScan = *iter;
Assert (pScan);
if (pScan == pComponent)
{
continue;
}
if (pScan->FCanDirectlyBindTo (pComponent, NULL, NULL))
{
StackEntry.pUpper = pScan;
StackEntry.pLower = pComponent;
}
else if (pComponent->FCanDirectlyBindTo (pScan, NULL, NULL))
{
StackEntry.pUpper = pComponent;
StackEntry.pLower = pScan;
}
else
{
continue;
}
// Insert the stack entry. This should only fail if we are
// out of memory.
//
hr = HrInsertStackEntry (&StackEntry, dwFlags);
// If we fail to insert the entry, undo all of the previous
// insertions of this component and return.
//
if (S_OK != hr)
{
RemoveEntriesWithComponent (pComponent);
break;
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CStackTable::HrInsertStackEntriesForComponent");
return hr;
}
HRESULT
CStackTable::HrInsertStackEntry (
IN const CStackEntry* pStackEntry,
IN DWORD dwFlags)
{
HRESULT hr;
Assert (this);
Assert (pStackEntry);
Assert (dwFlags);
Assert ((INS_SORTED == dwFlags) || (INS_NON_SORTED == dwFlags));
const CComponent* pUpper = pStackEntry->pUpper;
const CComponent* pLower = pStackEntry->pLower;
Assert (pUpper && pLower && (pUpper != pLower));
Assert (!FStackEntryInTable (pUpper, pLower));
CStackEntry* pScan = end();
if (dwFlags & INS_SORTED)
{
CStackEntry* pFirstInClass = NULL;
CStackEntry* pFirstSameUpper = NULL;
// Find the beginning of the group of entries belonging to the
// same class or lower as the one we are inserting.
//
for (pScan = begin(); pScan != end(); pScan++)
{
if ((UINT)pUpper->Class() >= (UINT)pScan->pUpper->Class())
{
pFirstInClass = pScan;
break;
}
}
// Find the first entry with the same pUpper (if there is one).
//
for (; pScan != end(); pScan++)
{
if (pUpper == pScan->pUpper)
{
pFirstSameUpper = pScan;
break;
}
}
// If we found the first entry with a matching pUpper, find the
// specific entry to insert before.
//
if (pFirstSameUpper)
{
BOOL fLowerIsNetBt;
// This may seem ugly, but will save a lot of code in a
// notify object. If inserting pLower of netbt, make sure
// it comes after netbt_smb.
//
fLowerIsNetBt = (0 == wcscmp (pLower->m_pszInfId, L"ms_netbt"));
if (fLowerIsNetBt)
{
while ((pScan != end()) && (pUpper == pScan->pUpper))
{
pScan++;
}
}
else if (pLower->FIsWanAdapter() && !m_fWanAdaptersFirst)
{
// For WAN adapters, either insert them before or after
// all other adapters as determined by m_fWanAdaptersFirst.
// If they don't come first, they come last, so scan
// to the end of the group with the same upper.
//
while ((pScan != end()) && (pUpper == pScan->pUpper))
{
pScan++;
}
}
}
// Otherwise, (if we didn't find any entry with the same upper),
// but we did find the beginning of the class group, set pScan
// to the class marker because that is where we will insert.
//
else if (pFirstInClass)
{
pScan = pFirstInClass;
}
else
{
Assert (pScan == end());
}
}
// Now insert the entry before the element we found as appropriate.
//
NC_TRY
{
insert (pScan, *pStackEntry);
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CStackTable::HrInsertStackEntry");
return hr;
}
HRESULT
CStackTable::HrMoveStackEntries (
IN const CStackEntry* pSrc,
IN const CStackEntry* pDst,
IN MOVE_FLAG Flag,
IN CModifyContext* pModifyCtx)
{
CStackEntry* pScanSrc;
CStackEntry* pScanDst;
// Search for the matching source entry in the table. We need
// the pointer to the entry in the table so we can remove it before
// we re-insert it before or after pDst.
//
pScanSrc = find (begin(), end(), *pSrc);
// If we didn't find the entry, the caller has passed us an invalid
// argument.
//
if (pScanSrc == end())
{
return E_INVALIDARG;
}
if (pDst)
{
// pDst is optional, but if it is specified, it have the same upper
// but different lower than pSrc.
//
if ((pSrc->pUpper != pDst->pUpper) ||
(pSrc->pLower == pDst->pLower))
{
return E_INVALIDARG;
}
pScanDst = find (begin(), end(), *pDst);
// If we didn't find the entry, the caller has passed us an invalid
// argument.
//
if (pScanDst == end())
{
return E_INVALIDARG;
}
// Since we only have an insert operation, moving after is the
// same as inserting before the element following pScanDst.
//
if ((MOVE_AFTER == Flag) && (pScanDst != end()))
{
pScanDst++;
}
}
else
{
// Find the first or last in the group with the same upper
// as pScanSrc.
//
pScanDst = pScanSrc;
if (MOVE_AFTER == Flag)
{
// Find the last in the group and insert after that.
//
while (pScanDst->pUpper == pScanSrc->pUpper)
{
pScanDst++;
if (pScanDst == end())
{
break;
}
}
}
else
{
// Find the first in the group and insert before that.
//
while (1)
{
pScanDst--;
if (pScanDst == begin())
{
break;
}
// If we've stepped out of the group, we need to point
// back at the first element since we are inserting.
//
if (pScanDst->pUpper != pScanSrc->pUpper)
{
pScanDst++;
break;
}
}
}
}
// Remove pScanSrc and insert it pSrc before pScanDst.
//
Assert ((pScanSrc >= begin()) && pScanSrc < end());
erase (pScanSrc);
// Erasing pScanSrc will move everything that follows it up.
// If pScanDst comes after pScanSrc, we need to back it up by one.
//
Assert ((pScanDst >= begin()) && pScanSrc <= end());
if (pScanSrc < pScanDst)
{
pScanDst--;
}
Assert ((pScanDst >= begin()) && pScanSrc <= end());
insert (pScanDst, *pSrc);
// We now need to add pSrc->pUpper and all components above
// it to the modify context's dirty component list. This will
// allow us to rewrite the newly ordered bindings during ApplyChanges.
//
HRESULT hr = pModifyCtx->HrDirtyComponentAndComponentsAbove (pSrc->pUpper);
TraceHr (ttidError, FAL, hr, FALSE, "CStackTable::HrMoveStackEntries");
return hr;
}
HRESULT
CStackTable::HrReserveRoomForEntries (
IN UINT cEntries)
{
HRESULT hr;
NC_TRY
{
reserve (cEntries);
hr = S_OK;
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
TraceHr (ttidError, FAL, hr, FALSE, "CStackTable::HrReserveRoomForEntries");
return hr;
}
VOID
CStackTable::RemoveEntriesWithComponent (
IN const CComponent* pComponent)
{
CStackEntry* pStackEntry;
Assert (this);
Assert (pComponent);
pStackEntry = begin();
while (pStackEntry != end())
{
if ((pComponent == pStackEntry->pUpper) ||
(pComponent == pStackEntry->pLower))
{
erase (pStackEntry);
}
else
{
pStackEntry++;
}
}
}
HRESULT
CStackTable::HrUpdateEntriesForComponent (
IN const CComponent* pComponent,
IN const CComponentList* pComponents,
IN DWORD dwFlags)
{
HRESULT hr;
CStackEntry StackEntry;
CComponentList::const_iterator iter;
const CComponent* pScan;
CStackTable NewStackEntries;
CStackEntry* pStackEntry = NULL;
Assert (this);
Assert (pComponent);
Assert (pComponents);
hr = S_OK;
TraceTag(ttidBeDiag,
"UpdateBindingInterfaces for %S",
pComponent->PszGetPnpIdOrInfId());
// Save the stack entries for other components which bind with this one.
//
for (iter = pComponents->begin();
iter != pComponents->end();
iter++)
{
pScan = *iter;
Assert (pScan);
if (pScan == pComponent)
{
continue;
}
if (pScan->FCanDirectlyBindTo (pComponent, NULL, NULL))
{
StackEntry.pUpper = pScan;
StackEntry.pLower = pComponent;
}
else if (pComponent->FCanDirectlyBindTo (pScan, NULL, NULL))
{
StackEntry.pUpper = pComponent;
StackEntry.pLower = pScan;
}
else
{
continue;
}
// Save the stack entry for comparation later
NewStackEntries.push_back(StackEntry);
}
//Check whether the current stack entry table is consist with NewStackEntries
//if not, then update the current stack entry table
pStackEntry = begin();
while (pStackEntry != end())
{
if ((pComponent == pStackEntry->pUpper) ||
(pComponent == pStackEntry->pLower))
{
if (!NewStackEntries.FStackEntryInTable(pStackEntry->pUpper, pStackEntry->pLower))
{
//if the stack entry is not in the new component binding entry list, remove it
//from the current stack entry list
erase (pStackEntry);
TraceTag(ttidBeDiag,
"erasing binding interface Uppper %S - Lower %S",
pStackEntry->pUpper->PszGetPnpIdOrInfId(),
pStackEntry->pLower->PszGetPnpIdOrInfId());
//dont need to increase the iterator since we just removed the current one
continue;
}
else
{
//if the stack entry is also in NewStackEntries, just keep it untouched
//in current entry list. Remove that entry from NewStackEntries so that we don't add
// it again to the current entry list later
NewStackEntries.RemoveStackEntry(pStackEntry->pUpper, pStackEntry->pLower);
TraceTag(ttidBeDiag,
"Keep the binding interface untouched: Uppper %S - Lower %S",
pStackEntry->pUpper->PszGetPnpIdOrInfId(),
pStackEntry->pLower->PszGetPnpIdOrInfId());
}
}
pStackEntry++;
}
//At this step, the NewStackEntries only contains the stack entries that are in the new binding list
//but are NOT in the current entry list. So add them in.
pStackEntry = NewStackEntries.begin();
while (pStackEntry != NewStackEntries.end())
{
Assert(!FStackEntryInTable(pStackEntry->pUpper, pStackEntry->pLower));
TraceTag(ttidBeDiag,
"Adding the bind interface: Uppper %S - Lower %S",
pStackEntry->pUpper->PszGetPnpIdOrInfId(),
pStackEntry->pLower->PszGetPnpIdOrInfId());
hr = HrInsertStackEntry(pStackEntry, dwFlags);
if (S_OK != hr)
{
break;
}
pStackEntry++;
}
// If we fail to insert the entry, undo all of the previous
// insertions of this component and return.
//
if (S_OK != hr)
{
RemoveEntriesWithComponent (pComponent);
}
TraceError("UpdateEntriesWithComponent", hr);
return hr;
}
VOID
CStackTable::SetWanAdapterOrder (
IN BOOL fWanAdaptersFirst)
{
m_fWanAdaptersFirst = fWanAdaptersFirst;
// Note: TODO - reorder table
}
VOID
GetComponentsAboveComponent (
IN const CComponent* pComponent,
IN OUT GCCONTEXT* pCtx)
{
const CStackEntry* pStackEntry;
// For all rows in the stack table where the lower component
// is the one passed in...
//
for (pStackEntry = pCtx->pStackTable->begin();
pStackEntry != pCtx->pStackTable->end();
pStackEntry++)
{
if (pComponent != pStackEntry->pLower)
{
continue;
}
pCtx->hr = pCtx->pComponents->HrInsertComponent (
pStackEntry->pUpper, INS_IGNORE_IF_DUP | INS_SORTED);
// Special case: NCF_DONTEXPOSELOWER
// If the upper component has the NCF_DONTEXPOSELOWER characteristic,
// don't recurse.
//
if (!pCtx->fIgnoreDontExposeLower &&
(pStackEntry->pUpper->m_dwCharacter & NCF_DONTEXPOSELOWER))
{
continue;
}
// End Special case
// Recurse on the upper component...
//
GetComponentsAboveComponent (pStackEntry->pUpper, pCtx);
if (S_OK != pCtx->hr)
{
return;
}
}
}
VOID
GetBindingsBelowComponent (
IN const CComponent* pComponent,
IN OUT GBCONTEXT* pCtx)
{
BOOL fFoundOne = FALSE;
const CStackEntry* pStackEntry;
// Append this component to the end of the context's working bindpath.
//
pCtx->hr = pCtx->BindPath.HrAppendComponent (pComponent);
if (S_OK != pCtx->hr)
{
return;
}
// Special case: NCF_DONTEXPOSELOWER
// If this is not the original component we are asked to find the
// component for (i.e. not the top-level call) and if the component
// has the NCF_DONTEXPOSELOWER characteristic, stop recursion since
// this means we don't get to see components below it.
//
if ((pComponent != pCtx->pSourceComponent) &&
(pComponent->m_dwCharacter & NCF_DONTEXPOSELOWER))
{
;
}
// End Special case
else
{
// For all rows in the stack table where the upper component
// is the one passed in...
//
for (pStackEntry = pCtx->pCore->StackTable.begin();
pStackEntry != pCtx->pCore->StackTable.end();
pStackEntry++)
{
if (pComponent != pStackEntry->pUpper)
{
continue;
}
// Detect circular bindings. If the lower component of this
// stack entry is already on the bindpath we are building, we
// have a circular binding. Break it now, by not recursing any
// further.
//
if (pCtx->BindPath.FContainsComponent (pStackEntry->pLower))
{
g_pDiagCtx->Printf (ttidBeDiag, "Circular binding detected...\n");
continue;
}
fFoundOne = TRUE;
// Recurse on the lower component...
//
GetBindingsBelowComponent (pStackEntry->pLower, pCtx);
if (S_OK != pCtx->hr)
{
return;
}
}
}
// If we didn't find any rows with pComponent as an upper, it
// means we hit the depth of the bindpath. Time to add it to
// the binding set as a complete path unless this is the orignal
// component we were asked to find the bindpath for.
//
if (!fFoundOne && (pComponent != pCtx->pSourceComponent))
{
// Add the bindpath to the bindset if we're not pruning disabled
// bindings or the bindpath isn't disabled.
//
if (!pCtx->fPruneDisabledBindings ||
!pCtx->pCore->FIsBindPathDisabled (&pCtx->BindPath,
IBD_EXACT_MATCH_ONLY))
{
pCtx->hr = pCtx->pBindSet->HrAddBindPath (&pCtx->BindPath,
INS_APPEND | pCtx->dwAddBindPathFlags);
}
}
const CComponent* pRemoved;
pRemoved = pCtx->BindPath.RemoveLastComponent();
// This should be the component we appened above.
//
Assert (pRemoved == pComponent);
}