|
|
//+---------------------------------------------------------------------------
//
// 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); }
|