windows-nt/Source/XPSP1/NT/net/config/netcfg/engine/remove.cpp

247 lines
7.5 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// 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 <pch.h>
#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;
}