//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1999. // // File: R E M O V E . C P P // // Contents: Implements actions related to removing components. // // Notes: // // Author: shaunco 15 Jan 1999 // //---------------------------------------------------------------------------- #include #pragma hdrstop #include "ncreg.h" #include "netcfg.h" VOID CModifyContext::NotifyAndRemoveComponent ( IN CComponent* pComponent) { CNetConfig* pNetConfig; UINT cPreviousDeletedBindPaths; Assert (this); Assert (S_OK == m_hr); Assert (pComponent); pNetConfig = PNetConfig(); // Note the number of bindpaths currently in m_DeletedBindPaths. // We need this so that when we add to the set, we only notify // for the ones we add. // cPreviousDeletedBindPaths = m_DeletedBindPaths.CountBindPaths (); // Get the bindpaths that involve the component we are removing. // Add these to the deleted bindpaths we are keeping track of. // m_hr = pNetConfig->Core.HrGetBindingsInvolvingComponent ( pComponent, GBF_ADD_TO_BINDSET | GBF_ONLY_WHICH_CONTAIN_COMPONENT, &m_DeletedBindPaths); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; } // Remove the component from the core. // pNetConfig->Core.RemoveComponentFromCore (pComponent); // Notify that these bindpaths are being removed. We only need to do // so if we added any new ones to the set. Existing ones in the set // have already been notified. // // THIS MAY CAUSE RECURSION // if (m_DeletedBindPaths.CountBindPaths() > cPreviousDeletedBindPaths) { m_hr = pNetConfig->Notify.NotifyRemovedBindPaths ( &m_DeletedBindPaths, cPreviousDeletedBindPaths); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; } } // Notify the component's notify object it is being removed. // This also sends global notifications to other notify objects // who may be interested. // // THIS MAY CAUSE RECURSION // m_hr = pNetConfig->Notify.ComponentRemoved (pComponent); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; } // If we have a cached INetCfgComponent interface, we need to tell it // that the component it represents is no longer valid. // pComponent->ReleaseINetCfgComponentInterface (); // Remove (if not referenced) any components that this component // required. // // THIS MAY CAUSE RECURSION // InstallOrRemoveRequiredComponents (pComponent, IOR_REMOVE); if (S_OK != m_hr) { Assert(FAILED(m_hr)); return; } // Now that we've given a chance to notify objects to remove references // to the component being removed, we need to ensure it is not // referenced by anyone else. // Check to see if the component we just removed is still // referencing other components. If it is, it means it forgot // to remove those components. We'll print what they are and // remove the bogus reference (but not the components themselves) // so that when we save the configuration binary we don't // barf trying to lookup the index of this component we just // removed.) // pNetConfig->Core.EnsureComponentNotReferencedByOthers (pComponent); } HRESULT CModifyContext::HrRemoveComponentIfNotReferenced ( IN CComponent* pComponent, IN OBO_TOKEN* pOboToken OPTIONAL, OUT PWSTR* ppmszwRefs OPTIONAL) { CNetConfig* pNetConfig; BOOL fStillReferenced; Assert (this); Assert (S_OK == m_hr); Assert (pComponent); // If the caller is requesting removal on behalf of an obo token, // (and its not obo the user) make sure the component is actually // referenced by that obo token. If it is not, consider it an // invalid argument. // // The reason we don't consider the obo user case is because the UI // will show anything that is installed and allow the user to try to // remove them. If the user hasn't actually installed it, we don't // want to treat this as an invalid argument, rather, we want to let // the code fall through to the case where we will return the multi-sz // of descriptions of components still referencing the component. // // However, if there are no references (which can happen if we delete // the configuration binary and then re-create it) we'll go ahead and // allow removals by anyone). This is a safety-net. // // The overall purpose of the following 'if' is to catch programatic // removals that are on behalf of other components or software that // have previously installed the component being removed. // if (pOboToken && (OBO_USER != pOboToken->Type) && !pComponent->Refs.FIsReferencedByOboToken (pOboToken) && (pComponent->Refs.CountTotalReferencedBy() > 0)) { return E_INVALIDARG; } pNetConfig = PNetConfig(); fStillReferenced = TRUE; // Now that we actually are going to modify something, push a new // recursion depth. // PushRecursionDepth (); Assert (S_OK == m_hr); // If the component is NOT in the list of components we started with, // it means someone had previously installed it during this modify // context and now wants to remove it. This is tricky and should // probably be implemented later. For now, return an error and throw // up an assert so we can see who needs to do this. // if (!m_CoreStartedWith.Components.FComponentInList (pComponent)) { AssertSz (FALSE, "Whoa. Someone is trying to remove a " "component that was previously installed during this same " "modify context. We need to decide if we can support this."); m_hr = E_UNEXPECTED; } if (pOboToken && (S_OK == m_hr)) { m_hr = pComponent->Refs.HrRemoveReferenceByOboToken (pOboToken); } // If no obo token, or we removed the reference from it, actually // remove it if it is not still referenced by anything else. // if (S_OK == m_hr) { if (0 == pComponent->Refs.CountTotalReferencedBy()) { fStillReferenced = FALSE; NotifyAndRemoveComponent (pComponent); } else if (ppmszwRefs) { ULONG cb; // Need to return the multi-sz of descriptions still referencing // the component the caller tried to remove. // // Size the data first. // cb = 0; pComponent->Refs.GetReferenceDescriptionsAsMultiSz ( NULL, &cb); Assert (cb); // Allocate room to return the multi-sz. // Assert (S_OK == m_hr); m_hr = HrCoTaskMemAlloc (cb, (VOID**)ppmszwRefs); if (S_OK == m_hr) { // Now get the multi-sz. // pComponent->Refs.GetReferenceDescriptionsAsMultiSz ( (BYTE*)(*ppmszwRefs), &cb); Assert (fStillReferenced); } } } HRESULT hr; hr = HrPopRecursionDepth (); if (fStillReferenced && SUCCEEDED(hr)) { // Still reference return code overrides other success codes like // need reboot. // hr = NETCFG_S_STILL_REFERENCED; } return hr; }