247 lines
7.5 KiB
C++
247 lines
7.5 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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;
|
||
|
}
|