1014 lines
29 KiB
C++
1014 lines
29 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1999.
|
|
//
|
|
// File: N E T C F G . C P P
|
|
//
|
|
// Contents: The main set of routines for dealing with the network
|
|
// binding engine.
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: shaunco 15 Jan 1999
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.h>
|
|
#pragma hdrstop
|
|
#include "diagctx.h"
|
|
#include "inetcfg.h"
|
|
#include "persist.h"
|
|
#include "netcfg.h"
|
|
#include "util.h"
|
|
|
|
// Called after a component has been removed. In case this component
|
|
// is still listed in any other component's references, we remove those
|
|
// references. This can happen if a notify object installs something
|
|
// on behalf of its component, but forgets to remove it.
|
|
//
|
|
VOID
|
|
CNetConfigCore::EnsureComponentNotReferencedByOthers (
|
|
IN const CComponent* pComponent)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
|
|
CComponentList::iterator iter;
|
|
CComponent* pScan;
|
|
|
|
for (iter = Components.begin();
|
|
iter != Components.end();
|
|
iter++)
|
|
{
|
|
pScan = *iter;
|
|
Assert (pScan);
|
|
|
|
if (pScan->Refs.FIsReferencedByComponent (pComponent))
|
|
{
|
|
g_pDiagCtx->Printf (ttidBeDiag, " %S is still referenced by %S. "
|
|
"Removing the refernce.\n",
|
|
pScan->PszGetPnpIdOrInfId(),
|
|
pComponent->PszGetPnpIdOrInfId());
|
|
|
|
pScan->Refs.RemoveReferenceByComponent (pComponent);
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CNetConfigCore::HrCopyCore (
|
|
IN const CNetConfigCore* pSourceCore)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
|
|
HRESULT hr;
|
|
|
|
hr = Components.HrCopyComponentList (&pSourceCore->Components);
|
|
if (S_OK != hr)
|
|
{
|
|
goto finished;
|
|
}
|
|
|
|
hr = StackTable.HrCopyStackTable (&pSourceCore->StackTable);
|
|
if (S_OK != hr)
|
|
{
|
|
goto finished;
|
|
}
|
|
|
|
hr = DisabledBindings.HrCopyBindingSet (&pSourceCore->DisabledBindings);
|
|
if (S_OK != hr)
|
|
{
|
|
goto finished;
|
|
}
|
|
|
|
finished:
|
|
if (S_OK != hr)
|
|
{
|
|
Clear ();
|
|
}
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CNetConfigCore::HrCopyCore");
|
|
return hr;
|
|
}
|
|
|
|
VOID
|
|
CNetConfigCore::Clear ()
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
|
|
Assert (this);
|
|
|
|
DisabledBindings.Clear();
|
|
StackTable.Clear();
|
|
Components.Clear();
|
|
}
|
|
|
|
VOID
|
|
CNetConfigCore::Free ()
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
|
|
Assert (this);
|
|
|
|
FreeCollectionAndItem (Components);
|
|
}
|
|
|
|
BOOL
|
|
CNetConfigCore::FIsEmpty () const
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
|
|
return Components.FIsEmpty () &&
|
|
StackTable.FIsEmpty () &&
|
|
DisabledBindings.FIsEmpty ();
|
|
}
|
|
|
|
BOOL
|
|
CNetConfigCore::FContainsFilterComponent () const
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
|
|
CComponentList::const_iterator iter;
|
|
const CComponent* pComponent;
|
|
|
|
for (iter = Components.begin();
|
|
iter != Components.end();
|
|
iter++)
|
|
{
|
|
pComponent = *iter;
|
|
Assert (pComponent);
|
|
|
|
if (pComponent->FIsFilter())
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
CNetConfigCore::FIsBindPathDisabled (
|
|
IN const CBindPath* pBindPath,
|
|
IN DWORD dwFlags /* IBD_FLAGS */) const
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
const CBindPath* pScan;
|
|
|
|
Assert (this);
|
|
Assert (pBindPath);
|
|
Assert ((dwFlags & IBD_EXACT_MATCH_ONLY) ||
|
|
(dwFlags & IBD_MATCH_SUBPATHS_TOO));
|
|
|
|
DbgVerifyBindingSet (&DisabledBindings);
|
|
|
|
// The bindpath is disabled if it matches one of the bindpaths in
|
|
// the disabled set or if one of the bindpaths in the disabled set
|
|
// is a subpath of it.
|
|
//
|
|
// IBD_EXACT_MATCH_ONLY is used when writing bindings to the registry.
|
|
// We only neglect writing a disabled binding for the components
|
|
// which directly have the disabled binding. i.e. if
|
|
// netbt>-tcpip->adapter is disabled, we only negect to write the
|
|
// binding for netbt. We still write binding for components above
|
|
// netbt (server, client) as if they were bound. We do this because
|
|
// 1) it doesn't matter that the upper components have these written
|
|
// 2) it means we don't have to involve these upper components in
|
|
// PnP notifications when then binding is enabled/disabled.
|
|
//
|
|
// IBD_MATCH_SUBPATHS_TOO is used when reporting bindpaths as enabled
|
|
// or disabled through the INetCfg interface. To clients, a binding
|
|
// is disabled if any of its subpaths are disabled. It has to be
|
|
// because there is no way that connectivity along the entire path
|
|
// will happen if any of the subpaths are cut-off (disabled).
|
|
//
|
|
for (pScan = DisabledBindings.begin();
|
|
pScan != DisabledBindings.end();
|
|
pScan++)
|
|
{
|
|
if (pScan->FIsSameBindPathAs (pBindPath))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (dwFlags & IBD_MATCH_SUBPATHS_TOO)
|
|
{
|
|
if (pScan->FIsSubPathOf (pBindPath))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// An alternate way to check if a bindpath is disabled when you have
|
|
// just the two components in question and you know that they are expected
|
|
// to be bound to one another. Using this method as opposed to
|
|
// FIsBindPathDisabled is better when you don't have the binpath allocated
|
|
// and don't want to allocate one just to check it. Thus, this method
|
|
// allocates no memory and doesn't need to check subpaths because a bindpath
|
|
// of length 2 can have no subpaths. This method is used primarily when
|
|
// seeing if a filter is bound to an adapter.
|
|
//
|
|
BOOL
|
|
CNetConfigCore::FIsLength2BindPathDisabled (
|
|
IN const CComponent* pUpper,
|
|
IN const CComponent* pLower) const
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
const CBindPath* pScan;
|
|
|
|
Assert (this);
|
|
Assert (pUpper);
|
|
Assert (pLower);
|
|
|
|
DbgVerifyBindingSet (&DisabledBindings);
|
|
|
|
for (pScan = DisabledBindings.begin();
|
|
pScan != DisabledBindings.end();
|
|
pScan++)
|
|
{
|
|
if (pScan->CountComponents() != 2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ((pScan->POwner() == pUpper) &&
|
|
(pScan->PLastComponent() == pLower))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT
|
|
CNetConfigCore::HrDisableBindPath (
|
|
IN const CBindPath* pBindPath)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
|
|
HRESULT hr;
|
|
|
|
Assert (this);
|
|
Assert (pBindPath);
|
|
|
|
hr = DisabledBindings.HrAddBindPath (
|
|
pBindPath, INS_IGNORE_IF_DUP | INS_APPEND);
|
|
|
|
DbgVerifyBindingSet (&DisabledBindings);
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"CNetConfigCore::HrDisableBindPath");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CNetConfigCore::HrGetComponentBindings (
|
|
IN const CComponent* pComponent,
|
|
IN DWORD dwFlags /* GB_FLAGS */,
|
|
OUT CBindingSet* pBindSet)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
GBCONTEXT Ctx;
|
|
|
|
Assert (pComponent);
|
|
Assert (pBindSet);
|
|
|
|
DbgVerifyData();
|
|
|
|
// Initialize the output parameter.
|
|
//
|
|
if (!(dwFlags & GBF_ADD_TO_BINDSET))
|
|
{
|
|
pBindSet->Clear();
|
|
}
|
|
|
|
// Initialize the members of our context structure for recursion.
|
|
// We set the append bindpath flags to assert if a duplicate is inserted
|
|
// because we know that GetBindingsBelowComponent will not insert
|
|
// duplicates under normal conditions.
|
|
//
|
|
ZeroMemory (&Ctx, sizeof(Ctx));
|
|
Ctx.pCore = this;
|
|
Ctx.pBindSet = pBindSet;
|
|
Ctx.pSourceComponent = pComponent;
|
|
Ctx.fPruneDisabledBindings = (dwFlags & GBF_PRUNE_DISABLED_BINDINGS);
|
|
Ctx.dwAddBindPathFlags = (dwFlags & GBF_ADD_TO_BINDSET)
|
|
? INS_IGNORE_IF_DUP
|
|
: INS_ASSERT_IF_DUP;
|
|
|
|
GetBindingsBelowComponent (pComponent, &Ctx);
|
|
|
|
// Verify the bindset we are about to return is valid.
|
|
// (Checked builds only.)
|
|
//
|
|
if (S_OK == Ctx.hr)
|
|
{
|
|
DbgVerifyBindingSet (pBindSet);
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, Ctx.hr, FALSE,
|
|
"CNetConfigCore::HrGetComponentBindings");
|
|
return Ctx.hr;
|
|
}
|
|
|
|
HRESULT
|
|
CNetConfigCore::HrGetComponentUpperBindings (
|
|
IN const CComponent* pComponent,
|
|
IN DWORD dwFlags,
|
|
OUT CBindingSet* pBindSet)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
HRESULT hr = S_OK;
|
|
CBindPath BindPath;
|
|
const CStackEntry* pScan;
|
|
DWORD dwAddBindPathFlags;
|
|
|
|
Assert (pComponent);
|
|
Assert (FIsEnumerated(pComponent->Class()));
|
|
Assert ((GBF_DEFAULT == dwFlags) ||
|
|
(dwFlags & GBF_ADD_TO_BINDSET) ||
|
|
(dwFlags & GBF_PRUNE_DISABLED_BINDINGS));
|
|
Assert (pBindSet);
|
|
|
|
DbgVerifyData();
|
|
|
|
dwAddBindPathFlags = INS_APPEND | INS_IGNORE_IF_DUP;
|
|
|
|
// Initialize the output parameter.
|
|
//
|
|
if (!(dwFlags & GBF_ADD_TO_BINDSET))
|
|
{
|
|
pBindSet->Clear();
|
|
dwAddBindPathFlags = INS_APPEND | INS_ASSERT_IF_DUP;
|
|
}
|
|
|
|
hr = BindPath.HrReserveRoomForComponents (2);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// This won't fail because we've reserved enough room above.
|
|
//
|
|
hr = BindPath.HrInsertComponent (pComponent);
|
|
Assert (S_OK == hr);
|
|
Assert (1 == BindPath.CountComponents());
|
|
|
|
// For all rows in the stack table where the lower component
|
|
// is the one passed in...
|
|
//
|
|
for (pScan = StackTable.begin();
|
|
pScan != StackTable.end();
|
|
pScan++)
|
|
{
|
|
if (pComponent != pScan->pLower)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Continue if this length-2 bindpath is disabled.
|
|
//
|
|
if (dwFlags & GBF_PRUNE_DISABLED_BINDINGS)
|
|
{
|
|
if (FIsLength2BindPathDisabled (pScan->pUpper, pScan->pLower))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// This won't fail because we've reserved enough room above.
|
|
//
|
|
hr = BindPath.HrInsertComponent (pScan->pUpper);
|
|
Assert (S_OK == hr);
|
|
|
|
Assert (2 == BindPath.CountComponents());
|
|
hr = pBindSet->HrAddBindPath (&BindPath, dwAddBindPathFlags);
|
|
if (S_OK != hr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
BindPath.RemoveFirstComponent();
|
|
}
|
|
|
|
// Verify the bindset we are about to return is valid.
|
|
// (Checked builds only.)
|
|
//
|
|
DbgVerifyBindingSet (pBindSet);
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"CNetConfigCore::HrGetComponentUpperBindings");
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CNetConfigCore::HrGetBindingsInvolvingComponent (
|
|
IN const CComponent* pComponent,
|
|
IN DWORD dwFlags,
|
|
IN OUT CBindingSet* pBindSet)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
GCCONTEXT Ctx;
|
|
CComponentList ComponentsAbove;
|
|
UINT cExistingBindPaths;
|
|
|
|
Assert (pComponent);
|
|
Assert ((GBF_DEFAULT == dwFlags) ||
|
|
(dwFlags & GBF_ADD_TO_BINDSET) ||
|
|
(dwFlags & GBF_PRUNE_DISABLED_BINDINGS) ||
|
|
(dwFlags & GBF_ONLY_WHICH_CONTAIN_COMPONENT));
|
|
Assert (pBindSet);
|
|
DbgVerifyData();
|
|
|
|
// Initialize the output parameter.
|
|
//
|
|
if (!(dwFlags & GBF_ADD_TO_BINDSET))
|
|
{
|
|
pBindSet->Clear();
|
|
}
|
|
|
|
// Since we may be adding to the bindset, be sure to exclude the existing
|
|
// bindpaths from our scans below.
|
|
//
|
|
cExistingBindPaths = pBindSet->CountBindPaths();
|
|
|
|
// Initialize the members of our context structure for recursion.
|
|
//
|
|
ZeroMemory (&Ctx, sizeof(Ctx));
|
|
Ctx.pStackTable = &StackTable;
|
|
Ctx.pComponents = &ComponentsAbove;
|
|
Ctx.fIgnoreDontExposeLower = TRUE;
|
|
|
|
GetComponentsAboveComponent (pComponent, &Ctx);
|
|
|
|
if (S_OK == Ctx.hr)
|
|
{
|
|
// First get the bindings below the component.
|
|
//
|
|
Ctx.hr = HrGetComponentBindings (
|
|
pComponent,
|
|
dwFlags | GBF_ADD_TO_BINDSET,
|
|
pBindSet);
|
|
|
|
if (S_OK == Ctx.hr)
|
|
{
|
|
CComponentList::const_iterator iter;
|
|
const CComponent* pComponentAbove;
|
|
|
|
// Now get the bindings below each of the components
|
|
// above the component and add them to the bindset.
|
|
//
|
|
for (iter = ComponentsAbove.begin();
|
|
iter != ComponentsAbove.end();
|
|
iter++)
|
|
{
|
|
pComponentAbove = *iter;
|
|
Assert (pComponentAbove);
|
|
|
|
Ctx.hr = HrGetComponentBindings (
|
|
pComponentAbove,
|
|
dwFlags | GBF_ADD_TO_BINDSET,
|
|
pBindSet);
|
|
|
|
if (S_OK != Ctx.hr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Verify the bindset we are about to return is valid.
|
|
// (Checked builds only.)
|
|
//
|
|
DbgVerifyBindingSet (pBindSet);
|
|
}
|
|
}
|
|
|
|
// Now remove any bindings that don't involve the component.
|
|
// If the component is enumerated, leave bindings that end in
|
|
// NCF_DONTEXPOSELOWER components, because they are indirectly
|
|
// involved in the bindings associated with the adapter.
|
|
//
|
|
if (S_OK == Ctx.hr)
|
|
{
|
|
CBindPath* pScan;
|
|
BOOL fIsEnumerated;
|
|
|
|
fIsEnumerated = FIsEnumerated(pComponent->Class());
|
|
|
|
if (fIsEnumerated || !(dwFlags & GBF_ONLY_WHICH_CONTAIN_COMPONENT))
|
|
{
|
|
// fDelBoundToComponent means "is there a NCF_DONTEXPOSELOWER
|
|
// component bound to pComponent". If there is not, we will
|
|
// be setting GBF_ONLY_WHICH_CONTAIN_COMPONENT to force the
|
|
// removal of any NCF_DONTEXPOSELOWER components from
|
|
// the bind set below.
|
|
//
|
|
BOOL fDelBoundToComponent = FALSE;
|
|
|
|
for (pScan = pBindSet->PGetBindPathAtIndex (cExistingBindPaths);
|
|
pScan != pBindSet->end();
|
|
pScan++)
|
|
{
|
|
if ((pScan->PLastComponent() == pComponent) &&
|
|
(pScan->POwner()->m_dwCharacter & NCF_DONTEXPOSELOWER))
|
|
{
|
|
fDelBoundToComponent = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fDelBoundToComponent)
|
|
{
|
|
dwFlags |= GBF_ONLY_WHICH_CONTAIN_COMPONENT;
|
|
}
|
|
}
|
|
|
|
pScan = pBindSet->PGetBindPathAtIndex (cExistingBindPaths);
|
|
while (pScan != pBindSet->end())
|
|
{
|
|
if (pScan->FContainsComponent (pComponent))
|
|
{
|
|
pScan++;
|
|
continue;
|
|
}
|
|
|
|
// At this point, we know that the bindpath does not
|
|
// contain pComponent. See if we should erase it or keep it.
|
|
//
|
|
|
|
// If the component is not an adpater or if the caller wants
|
|
// only bindpaths which contain the adapter, erase it.
|
|
//
|
|
if (!fIsEnumerated ||
|
|
(dwFlags & GBF_ONLY_WHICH_CONTAIN_COMPONENT))
|
|
{
|
|
pBindSet->erase (pScan);
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, (pComponent is an adpater and the caller wants
|
|
// indirect bindings involved with that adpater) we'll
|
|
// erase the bindpath only if the last component is not an
|
|
// NCF_DONTEXPOSELOWER component. We need to keep these
|
|
// bindpaths so that the LAN UI (which shows components
|
|
// involved in bindpaths that involve an adapter) can
|
|
// display these NCF_DONTEXPOSELOWER components too.
|
|
//
|
|
else
|
|
{
|
|
CComponent* pLast = pScan->PLastComponent();
|
|
|
|
if (!(pLast->m_dwCharacter & NCF_DONTEXPOSELOWER))
|
|
{
|
|
pBindSet->erase (pScan);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pScan++;
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, Ctx.hr, FALSE,
|
|
"CNetConfigCore::HrGetBindingsInvolvingComponent");
|
|
return Ctx.hr;
|
|
}
|
|
|
|
HRESULT
|
|
CNetConfigCore::HrGetFiltersEnabledForAdapter (
|
|
IN const CComponent* pAdapter,
|
|
OUT CComponentList* pFilters)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
HRESULT hr;
|
|
const CStackEntry* pScan;
|
|
|
|
Assert (this);
|
|
Assert (pAdapter);
|
|
Assert (FIsEnumerated(pAdapter->Class()));
|
|
Assert (pFilters);
|
|
|
|
// Initialize the output parameter.
|
|
//
|
|
pFilters->Clear();
|
|
|
|
// Scan the stack table looking for lower component matches to pAdapter.
|
|
// When found, and if the upper component is a filter, and if the
|
|
// direct bindpath is not disabled, add the filter to the output list.
|
|
//
|
|
for (pScan = StackTable.begin(); pScan != StackTable.end(); pScan++)
|
|
{
|
|
// Looking for lower component matches to the adapter where
|
|
// the upper component is a filter. Ignore all others.
|
|
//
|
|
if ((pScan->pLower != pAdapter) || !pScan->pUpper->FIsFilter())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Assert (pScan->pUpper->FIsFilter());
|
|
Assert (pScan->pLower == pAdapter);
|
|
|
|
// If the bindpath is not disabled, add the filter to the list.
|
|
//
|
|
if (!FIsLength2BindPathDisabled (pScan->pUpper, pScan->pLower))
|
|
{
|
|
// Assert if a duplicate because the same filter can't be bound
|
|
// to the same adapter more than once.
|
|
// No need to sort when we insert because the class of all of
|
|
// the components in this list will be the same.
|
|
//
|
|
hr = pFilters->HrInsertComponent (pScan->pUpper,
|
|
INS_ASSERT_IF_DUP | INS_NON_SORTED);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// (Takes ownership of pComponent)
|
|
//
|
|
HRESULT
|
|
CNetConfigCore::HrAddComponentToCore (
|
|
IN CComponent* pComponent,
|
|
IN DWORD dwFlags /* INS_FLAGS */)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
HRESULT hr;
|
|
|
|
Assert (pComponent);
|
|
Assert ((INS_SORTED == dwFlags) || (INS_NON_SORTED == dwFlags));
|
|
|
|
DbgVerifyExternalDataLoadedForAllComponents ();
|
|
pComponent->Ext.DbgVerifyExternalDataLoaded ();
|
|
|
|
// Make sure we are not trying to insert a component with a PnpId that
|
|
// is the same as one already in the core. Note that we do not perform
|
|
// this check inside of CComponentList::HrInsertComponent because it is
|
|
// not appropriate for all component lists. Specifically, the dirty
|
|
// component list may end up having two different components with the
|
|
// same PnpId for the case when we are asked to install an adapter that
|
|
// is pending removal. In this case the new adapter will get the same
|
|
// PnpId as the one that was removed. We'll remove the old one from
|
|
// core to insert the new one so the dirty component list will have
|
|
// both components with the same PnpId.
|
|
//
|
|
if (FIsEnumerated(pComponent->Class()) &&
|
|
Components.PFindComponentByPnpId (pComponent->m_pszPnpId))
|
|
{
|
|
AssertSz (FALSE, "Asked to add a component with a duplicate PnpId!");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Insert the component into the list. This should only fail if we
|
|
// are out of memory.
|
|
//
|
|
hr = Components.HrInsertComponent (
|
|
pComponent, dwFlags | INS_ASSERT_IF_DUP);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
// Insert the appropriate stack entries for pComponent based on
|
|
// how it binds with the other components.
|
|
//
|
|
hr = StackTable.HrInsertStackEntriesForComponent (
|
|
pComponent, &Components, dwFlags);
|
|
|
|
// If we failed to insert the stack entries, undo the insertion
|
|
// into the component list.
|
|
//
|
|
if (S_OK != hr)
|
|
{
|
|
Components.RemoveComponent (pComponent);
|
|
}
|
|
}
|
|
|
|
// Error or not, we should still have a valid core.
|
|
//
|
|
DbgVerifyData();
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE,
|
|
"CNetConfigCore::HrAddComponentToCore");
|
|
return hr;
|
|
}
|
|
|
|
VOID
|
|
CNetConfigCore::RemoveComponentFromCore (
|
|
IN const CComponent* pComponent)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
Assert (this);
|
|
Assert (pComponent);
|
|
|
|
Components.RemoveComponent (pComponent);
|
|
StackTable.RemoveEntriesWithComponent (pComponent);
|
|
DisabledBindings.RemoveBindPathsWithComponent (pComponent);
|
|
|
|
#if DBG
|
|
// We set m_fRemovedAComponent so that when subsequent
|
|
// DbgVerifyBindingSet calls are made, we don't assert on components
|
|
// that are in the binding set but not in the core. This is a natural
|
|
// occurance for the m_DeletedBindings we build up during removal of
|
|
// components.
|
|
//
|
|
m_fRemovedAComponent = TRUE;
|
|
|
|
// Note: need to find a convenient time during Apply where
|
|
// we set this flag back to FALSE.
|
|
#endif
|
|
}
|
|
|
|
|
|
// static
|
|
HRESULT
|
|
CNetConfig::HrCreateInstance (
|
|
IN class CImplINetCfg* pINetCfg,
|
|
OUT CNetConfig** ppNetConfig)
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
Assert (pINetCfg);
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
CNetConfig* pObj;
|
|
pObj = new CNetConfig;
|
|
if (pObj)
|
|
{
|
|
// Load the configuration binary. If we have have the write lock,
|
|
// request write access, otherwise, request read access.
|
|
// Requesting write access means this will only succeed if the
|
|
// volatile key indicating we need a reboot does not exist.
|
|
//
|
|
hr = HrLoadNetworkConfigurationFromRegistry (
|
|
(pINetCfg->m_WriteLock.FIsOwnedByMe ())
|
|
? KEY_WRITE : KEY_READ,
|
|
pObj);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
pObj->Core.DbgVerifyData();
|
|
pObj->Notify.HoldINetCfg (pINetCfg);
|
|
*ppNetConfig = pObj;
|
|
}
|
|
else
|
|
{
|
|
delete pObj;
|
|
}
|
|
}
|
|
TraceHr (ttidError, FAL, hr, FALSE, "CNetConfig::HrCreateInstance");
|
|
return hr;
|
|
}
|
|
|
|
CNetConfig::~CNetConfig ()
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
Core.Free ();
|
|
}
|
|
|
|
HRESULT
|
|
CNetConfig::HrEnsureExternalDataLoadedForAllComponents ()
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
HRESULT hr;
|
|
HRESULT hrRet;
|
|
CComponentList::iterator iter;
|
|
CComponent* pComponent;
|
|
|
|
hrRet = S_OK;
|
|
|
|
// This is a while loop instead of a for loop because of the
|
|
// potential for conditional advancement of the iterator. If we
|
|
// remove a component from the core while looping, we don't increment
|
|
// the iterator for the next iteration.
|
|
//
|
|
iter = Core.Components.begin();
|
|
while (iter != Core.Components.end())
|
|
{
|
|
pComponent = *iter;
|
|
Assert (pComponent);
|
|
|
|
hr = pComponent->Ext.HrEnsureExternalDataLoaded ();
|
|
|
|
if ((SPAPI_E_NO_SUCH_DEVINST == hr) ||
|
|
(SPAPI_E_KEY_DOES_NOT_EXIST == hr))
|
|
{
|
|
g_pDiagCtx->Printf (ttidBeDiag,
|
|
"Removing %s from the core because its external data is missing\n",
|
|
pComponent->PszGetPnpIdOrInfId());
|
|
|
|
Core.RemoveComponentFromCore (pComponent);
|
|
delete pComponent;
|
|
hr = S_OK;
|
|
|
|
// Because we removed this component from the core, the
|
|
// list has been adjusted and the next component is now this
|
|
// iter. Therefore, just continue without incrementing iter.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
// Remember the first error as our return code, but keep going.
|
|
// Like the name says, we are to load data for all components so
|
|
// don't stop just because one fails.
|
|
//
|
|
if ((S_OK != hr) && (S_OK == hrRet))
|
|
{
|
|
hrRet = hr;
|
|
}
|
|
|
|
iter++;
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hrRet, FALSE,
|
|
"CNetConfig::HrEnsureExternalDataLoadedForAllComponents");
|
|
return hrRet;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
CNetConfigCore::DbgVerifyData () const
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
HRESULT hr;
|
|
|
|
CComponentList::const_iterator iter;
|
|
const CComponent* pComponent;
|
|
const CStackEntry* pStackEntry;
|
|
const CComponent* pUpper;
|
|
const CComponent* pLower;
|
|
CHAR szBuffer [512];
|
|
|
|
for (pStackEntry = StackTable.begin();
|
|
pStackEntry != StackTable.end();
|
|
pStackEntry++)
|
|
{
|
|
pUpper = pStackEntry->pUpper;
|
|
pLower = pStackEntry->pLower;
|
|
|
|
Assert (pUpper);
|
|
Assert (pLower);
|
|
Assert (pUpper != pLower);
|
|
|
|
// Can't access upper and lower range if the external data isn't
|
|
// loaded.
|
|
//
|
|
if (pUpper->Ext.DbgIsExternalDataLoaded() &&
|
|
pLower->Ext.DbgIsExternalDataLoaded())
|
|
{
|
|
if (!pUpper->FCanDirectlyBindTo (pLower, NULL, NULL))
|
|
{
|
|
wsprintfA (szBuffer, "%S should not bind to %S. They are in the "
|
|
"stack table as if they do. (Likely upgrade problem.)",
|
|
pUpper->PszGetPnpIdOrInfId(),
|
|
pLower->PszGetPnpIdOrInfId());
|
|
AssertSzFn (szBuffer, FAL);
|
|
}
|
|
}
|
|
|
|
if (!FIsEnumerated (pUpper->Class()))
|
|
{
|
|
if (pUpper != Components.PFindComponentByInfId (
|
|
pUpper->m_pszInfId, NULL))
|
|
{
|
|
wsprintfA (szBuffer, "%S is an upper component in the stack "
|
|
"table, but was not found in the component list.",
|
|
pUpper->m_pszInfId);
|
|
AssertSzFn (szBuffer, FAL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pUpper != Components.PFindComponentByPnpId (
|
|
pUpper->m_pszPnpId))
|
|
{
|
|
wsprintfA (szBuffer, "%S is an upper component in the stack "
|
|
"table, but was not found in the component list.",
|
|
pUpper->m_pszInfId);
|
|
AssertSzFn (szBuffer, FAL);
|
|
}
|
|
}
|
|
|
|
if (!FIsEnumerated (pLower->Class()))
|
|
{
|
|
if (pLower != Components.PFindComponentByInfId (
|
|
pLower->m_pszInfId, NULL))
|
|
{
|
|
wsprintfA (szBuffer, "%S is a lower component in the stack "
|
|
"table, but was not found in the component list.",
|
|
pLower->m_pszInfId);
|
|
AssertSzFn (szBuffer, FAL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pLower != Components.PFindComponentByPnpId (
|
|
pLower->m_pszPnpId))
|
|
{
|
|
wsprintfA (szBuffer, "%S is a lower component in the stack "
|
|
"table, but was not found in the component list.",
|
|
pLower->m_pszInfId);
|
|
AssertSzFn (szBuffer, FAL);
|
|
}
|
|
}
|
|
|
|
if (pUpper != Components.PFindComponentByInstanceGuid (&pUpper->m_InstanceGuid))
|
|
{
|
|
wsprintfA (szBuffer, "%S is an upper component in the stack "
|
|
"table, but was not found in the component list by GUID.",
|
|
pUpper->PszGetPnpIdOrInfId());
|
|
AssertSzFn (szBuffer, FAL);
|
|
}
|
|
|
|
if (pLower != Components.PFindComponentByInstanceGuid (&pLower->m_InstanceGuid))
|
|
{
|
|
wsprintfA (szBuffer, "%S is a lower component in the stack "
|
|
"table, but was not found in the component list by GUID.",
|
|
pLower->PszGetPnpIdOrInfId());
|
|
AssertSzFn (szBuffer, FAL);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CNetConfigCore::DbgVerifyExternalDataLoadedForAllComponents () const
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
CComponentList::const_iterator iter;
|
|
const CComponent* pComponent;
|
|
|
|
for (iter = Components.begin();
|
|
iter != Components.end();
|
|
iter++)
|
|
{
|
|
pComponent = *iter;
|
|
Assert (pComponent);
|
|
|
|
pComponent->Ext.DbgVerifyExternalDataLoaded();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CNetConfigCore::DbgVerifyBindingSet (
|
|
const CBindingSet* pBindSet) const
|
|
{
|
|
TraceFileFunc(ttidNetcfgBase);
|
|
const CBindPath* pPath;
|
|
const CBindPath* pOtherPath;
|
|
CBindPath::const_iterator iter;
|
|
const CComponent* pComponent;
|
|
|
|
Assert (pBindSet);
|
|
|
|
// First make sure every component in the set is in our component
|
|
// list. We only do this if we're not in the state where a component
|
|
// has been removed from the core. For this case, its okay if those
|
|
// components still exist in binding sets.
|
|
//
|
|
if (!m_fRemovedAComponent)
|
|
{
|
|
for (pPath = pBindSet->begin();
|
|
pPath != pBindSet->end();
|
|
pPath++)
|
|
{
|
|
for (iter = pPath->begin();
|
|
iter != pPath->end();
|
|
iter++)
|
|
{
|
|
pComponent = *iter;
|
|
|
|
Assert (Components.FComponentInList (pComponent));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make sure there are no duplicate bindpaths in the set.
|
|
//
|
|
for (pPath = pBindSet->begin();
|
|
pPath != pBindSet->end();
|
|
pPath++)
|
|
{
|
|
Assert (!pPath->FIsEmpty());
|
|
|
|
for (pOtherPath = pBindSet->begin();
|
|
pOtherPath != pBindSet->end();
|
|
pOtherPath++)
|
|
{
|
|
if (pPath == pOtherPath)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Assert (!pPath->FIsSameBindPathAs (pOtherPath));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|