//+--------------------------------------------------------------------------- // // 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 #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(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(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 (begin(), end(), greater()); } VOID CBindingSet::SortForPnpUnbind () { TraceFileFunc(ttidNetCfgBind); // Sort where bindpaths furthest from the adapters come first. // sort (begin(), end(), less()); }