Windows-Server-2003/net/config/netcfg/engine/notify.cpp

1408 lines
37 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: N O T I F Y . C P P
//
// Contents: Implements the interface to a component's optional notify
// object. The object defined here is meant to be a member
// of CComponent. This object encapsulates all of its internal
// data in a separate allocation made only if the component
// actually has a notify object.
//
// Notes:
//
// Author: shaunco 15 Jan 1999
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "diagctx.h"
#include "ibind.h"
#include "inetcfg.h"
#include "nceh.h"
#include "ncmisc.h"
#include "ncprsht.h"
#include "netcfg.h"
#include "notify.h"
//+---------------------------------------------------------------------------
// CNotifyObjectInterface -
//
HRESULT
CNotifyObjectInterface::HrEnsureNotifyObjectInitialized (
IN CImplINetCfg* pINetCfg,
IN BOOL fInstalling)
{
Assert (pINetCfg);
// If we've already been through initialization, return immediately.
//
if (m_fInitialized)
{
return S_OK;
}
// Only perform initialization once, regardless of whether it succeeds
// or not.
//
m_fInitialized = TRUE;
// Get our containing component pointer so we can ask it what the
// CLSID for the notify object is. (If it has one.)
//
CComponent* pThis;
pThis = CONTAINING_RECORD (this, CComponent, Notify);
// Don't bother if we can't have a notify object. Bailing here saves
// uneccesarily loading the external data for netclass components only
// to find that they won't have a notify object below.
//
if (FIsEnumerated (pThis->Class()))
{
return S_OK;
}
HRESULT hrRet;
// Since the notify object clsid is part of the components external data,
// we have to make sure we've loaded this data.
//
hrRet = pThis->Ext.HrEnsureExternalDataLoaded ();
if (S_OK != hrRet)
{
goto finished;
}
// Don't bother if we don't have a notify object.
//
if (!pThis->Ext.FHasNotifyObject())
{
return S_OK;
}
// The component claims to have a notify object. Let's CoCreate it
// and see what we get.
//
HRESULT hr;
INetCfgComponentControl* pCc;
hr = pINetCfg->HrCoCreateWrapper (
*(pThis->Ext.PNotifyObjectClsid()),
NULL, CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
IID_INetCfgComponentControl,
(PVOID*)&pCc);
if (S_OK == hr)
{
// So far so good. The notify object implements the required
// INetCfgComponentControl interface.
//
// We now must get the INetCfgComponent interface that we'll
// pass to the notify object during Initialize below.
//
INetCfgComponent* pIComp;
hrRet = pThis->HrGetINetCfgComponentInterface (pINetCfg, &pIComp);
if (S_OK == hrRet)
{
// Allocate space for the various notify interfaces and QI for
// them.
//
hrRet = E_OUTOFMEMORY;
m_pNod = (NOTIFY_OBJECT_DATA*) MemAlloc (sizeof(NOTIFY_OBJECT_DATA));
if (m_pNod)
{
hrRet = S_OK;
ZeroMemory (m_pNod, sizeof(NOTIFY_OBJECT_DATA));
AddRefObj (pCc);
m_pNod->pCc = pCc;
pCc->QueryInterface (IID_INetCfgComponentNotifyBinding,
(PVOID*)&m_pNod->pNb);
pCc->QueryInterface (IID_INetCfgComponentPropertyUi,
(PVOID*)&m_pNod->pCp);
pCc->QueryInterface (IID_INetCfgComponentSetup,
(PVOID*)&m_pNod->pCs);
pCc->QueryInterface (IID_INetCfgComponentUpperEdge,
(PVOID*)&m_pNod->pUe);
pCc->QueryInterface (IID_INetCfgComponentNotifyGlobal,
(PVOID*)&m_pNod->pNg);
if (m_pNod->pNg)
{
// Since it supports INetCfgComponentNotifyGlobal,
// get the mask that indicates which global notifications
// it is interested in.
//
hr = m_pNod->pNg->GetSupportedNotifications(
&m_pNod->dwNotifyGlobalFlags);
if (FAILED(hr))
{
m_pNod->dwNotifyGlobalFlags = 0;
}
}
// We now need to initialize the notify object and indicate
// if we are installing its component or not.
//
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
Assert (pIComp);
Assert (pINetCfg);
(VOID) pCc->Initialize (pIComp, pINetCfg, fInstalling);
}
NC_CATCH_ALL
{
; // ignored
}
pINetCfg->LowerRpl (RPL_DISALLOW);
}
ReleaseObj (pIComp);
}
ReleaseObj (pCc);
}
finished:
TraceHr (ttidError, FAL, hrRet, FALSE,
"CNotifyObjectInterface::HrEnsureNotifyObjectInitialized");
return hrRet;
}
VOID
CNotifyObjectInterface::ApplyPnpChanges (
IN CImplINetCfg* pINetCfg,
OUT BOOL* pfNeedReboot) const
{
HRESULT hr;
Assert (pINetCfg);
Assert (pfNeedReboot);
Assert (m_fInitialized);
*pfNeedReboot = FALSE;
if (!m_pNod)
{
return;
}
Assert (m_pNod->pCc);
CComponent* pThis;
pThis = CONTAINING_RECORD (this, CComponent, Notify);
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
g_pDiagCtx->Printf (ttidBeDiag,
" calling %S->ApplyPnpChanges\n",
pThis->m_pszInfId);
hr = m_pNod->pCc->ApplyPnpChanges (pINetCfg);
if (FAILED(hr) || (NETCFG_S_REBOOT == hr))
{
*pfNeedReboot = TRUE;
}
}
NC_CATCH_ALL
{
*pfNeedReboot = TRUE;
}
pINetCfg->LowerRpl (RPL_DISALLOW);
}
VOID
CNotifyObjectInterface::ApplyRegistryChanges (
IN CImplINetCfg* pINetCfg,
OUT BOOL* pfNeedReboot) const
{
HRESULT hr;
Assert (pINetCfg);
Assert (pfNeedReboot);
Assert (m_fInitialized);
*pfNeedReboot = FALSE;
if (!m_pNod)
{
return;
}
Assert (m_pNod->pCc);
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
hr = m_pNod->pCc->ApplyRegistryChanges ();
if (FAILED(hr) || (NETCFG_S_REBOOT == hr))
{
*pfNeedReboot = TRUE;
}
}
NC_CATCH_ALL
{
*pfNeedReboot = TRUE;
}
pINetCfg->LowerRpl (RPL_DISALLOW);
}
HRESULT
CNotifyObjectInterface::HrGetInterfaceIdsForAdapter (
IN CImplINetCfg* pINetCfg,
IN const CComponent* pAdapter,
OUT DWORD* pcInterfaces,
OUT GUID** ppguidInterfaceIds) const
{
HRESULT hr;
Assert (pAdapter);
Assert (pcInterfaces);
Assert (m_fInitialized);
*pcInterfaces = 0;
if (ppguidInterfaceIds)
{
*ppguidInterfaceIds = NULL;
}
if (!m_pNod || !m_pNod->pUe)
{
return S_FALSE;
}
Assert (pAdapter->GetINetCfgComponentInterface());
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
hr = m_pNod->pUe->GetInterfaceIdsForAdapter (
pAdapter->GetINetCfgComponentInterface(),
pcInterfaces, ppguidInterfaceIds);
if (S_FALSE == hr)
{
*pcInterfaces = 0;
if (ppguidInterfaceIds)
{
*ppguidInterfaceIds = NULL;
}
}
}
NC_CATCH_ALL
{
; // ignored
}
pINetCfg->LowerRpl (RPL_DISALLOW);
TraceHr (ttidError, FAL, hr, (S_FALSE == hr),
"CNotifyObjectInterface::HrGetInterfaceIdsForAdapter");
return hr;
}
HRESULT
CNotifyObjectInterface::HrQueryPropertyUi (
IN CImplINetCfg* pINetCfg,
IN IUnknown* punkContext OPTIONAL)
{
HRESULT hr;
CComponent* pThis;
Assert (this);
Assert (pINetCfg);
Assert (m_fInitialized);
if (!m_pNod || !m_pNod->pCp)
{
return S_FALSE;
}
pThis = CONTAINING_RECORD (this, CComponent, Notify);
Assert (pThis);
if (!(pThis->m_dwCharacter & NCF_HAS_UI))
{
return S_FALSE;
}
hr = S_OK;
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
Assert (m_pNod && m_pNod->pCp);
hr = m_pNod->pCp->QueryPropertyUi (punkContext);
}
NC_CATCH_ALL
{
hr = E_UNEXPECTED;
}
pINetCfg->LowerRpl (RPL_DISALLOW);
TraceHr (ttidError, FAL, hr, FALSE,
"CNotifyObjectInterface::HrQueryPropertyUi");
return hr;
}
HRESULT
CNotifyObjectInterface::HrShowPropertyUi (
IN CImplINetCfg* pINetCfg,
IN HWND hwndParent,
IN IUnknown* punkContext OPTIONAL)
{
HRESULT hr;
DWORD cDefPages;
UINT cPages;
HPROPSHEETPAGE* ahpsp;
PCWSTR pszStartPage;
Assert (this);
Assert (pINetCfg);
Assert (m_fInitialized);
if (!m_pNod || !m_pNod->pCp)
{
return E_NOINTERFACE;
}
Assert (m_pNod && m_pNod->pCp);
// If given a context, let the notify object know what it is.
//
if (punkContext)
{
SetUiContext (pINetCfg, punkContext);
}
hr = S_OK;
cDefPages = 0;
ahpsp = NULL;
cPages = 0;
pszStartPage = NULL;
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
hr = m_pNod->pCp->MergePropPages (
&cDefPages,
(BYTE**)&ahpsp,
&cPages,
hwndParent,
&pszStartPage);
}
NC_CATCH_ALL
{
hr = E_UNEXPECTED;
}
pINetCfg->LowerRpl (RPL_DISALLOW);
if ((S_OK == hr) && cPages)
{
PROPSHEETHEADER psh;
CAPAGES caPages;
CAINCP cai;
CComponent* pThis;
pThis = CONTAINING_RECORD (this, CComponent, Notify);
Assert (pThis);
ZeroMemory(&psh, sizeof(psh));
ZeroMemory(&caPages, sizeof(caPages));
ZeroMemory(&cai, sizeof(cai));
psh.dwSize = sizeof(psh);
psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
psh.hwndParent = hwndParent;
psh.hInstance = _Module.GetModuleInstance();
psh.pszCaption = pThis->Ext.PszDescription();
caPages.nCount = cPages;
caPages.ahpsp = ahpsp;
cai.nCount = 1;
cai.apncp = &m_pNod->pCp;
hr = HrNetCfgPropertySheet (&psh, caPages, pszStartPage, cai);
// S_FALSE is returned if no changes were made.
//
if (S_OK == hr)
{
if (pINetCfg->m_WriteLock.FIsOwnedByMe ())
{
pINetCfg->m_pNetConfig->ModifyCtx.HrBeginBatchOperation ();
}
BOOL bCommitNow = FALSE;
// Call ApplyProperties
//
pINetCfg->RaiseRpl (RPL_ALLOW_INSTALL_REMOVE);
NC_TRY
{
hr = m_pNod->pCp->ApplyProperties ();
if(NETCFG_S_COMMIT_NOW == hr)
{
bCommitNow = TRUE;
}
}
NC_CATCH_ALL
{
hr = E_UNEXPECTED;
}
pINetCfg->LowerRpl (RPL_ALLOW_INSTALL_REMOVE);
if (pINetCfg->m_WriteLock.FIsOwnedByMe ())
{
// Set this component as dirty so we call its Apply method
// if INetCfg is applied.
//
hr = pINetCfg->m_pNetConfig->ModifyCtx.HrDirtyComponent(
pThis);
// Notify other components that this component changed.
//
pINetCfg->m_pNetConfig->Notify.NgSysNotifyComponent (
NCN_PROPERTYCHANGE,
pThis);
hr = pINetCfg->m_pNetConfig->ModifyCtx.
HrEndBatchOperation (bCommitNow ? EBO_COMMIT_NOW : EBO_DEFER_COMMIT_UNTIL_APPLY);
}
}
else
{
// Don't overwrite hr. It is what we need to return.
//
// Call CancelProperties
//
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
(VOID) m_pNod->pCp->CancelProperties ();
}
NC_CATCH_ALL
{
hr = E_UNEXPECTED;
}
pINetCfg->LowerRpl (RPL_DISALLOW);
}
}
// This is outside the above if in case a notify object actually
// allocates it but returns zero pages.
//
CoTaskMemFree (ahpsp);
// If given a context, let the notify object know it is no longer valid.
//
if (punkContext)
{
SetUiContext (pINetCfg, NULL);
}
TraceHr (ttidError, FAL, hr,
(HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr),
"CNotifyObjectInterface::HrShowPropertyUi");
return hr;
}
VOID
CNotifyObjectInterface::SetUiContext (
IN CImplINetCfg* pINetCfg,
IN IUnknown* punkContext)
{
Assert (m_fInitialized);
Assert (m_pNod && m_pNod->pCp);
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
(VOID) m_pNod->pCp->SetContext (punkContext);
}
NC_CATCH_ALL
{
; // ignored
}
pINetCfg->LowerRpl (RPL_DISALLOW);
}
VOID
CNotifyObjectInterface::NbQueryOrNotifyBindingPath (
IN CImplINetCfg* pINetCfg,
IN QN_FLAG Flag,
IN DWORD dwChangeFlag,
IN INetCfgBindingPath* pIPath,
OUT BOOL* pfDisabled)
{
RPL_FLAGS RplFlag;
Assert (pINetCfg);
Assert ((QN_QUERY == Flag) || (QN_NOTIFY == Flag));
Assert (pIPath);
Assert (FImplies(QN_QUERY == Flag, pfDisabled));
Assert (m_fInitialized);
if (pfDisabled)
{
*pfDisabled = FALSE;
}
if (m_pNod && m_pNod->pNb)
{
RplFlag = (QN_NOTIFY == Flag) ? RPL_ALLOW_INSTALL_REMOVE
: RPL_DISALLOW;
pINetCfg->RaiseRpl (RplFlag);
NC_TRY
{
if (QN_QUERY == Flag)
{
HRESULT hr;
hr = m_pNod->pNb->QueryBindingPath (dwChangeFlag, pIPath);
if (NETCFG_S_DISABLE_QUERY == hr)
{
*pfDisabled = TRUE;
}
}
else
{
(VOID) m_pNod->pNb->NotifyBindingPath (dwChangeFlag, pIPath);
}
}
NC_CATCH_ALL
{
; // ignored
}
pINetCfg->LowerRpl (RplFlag);
}
}
HRESULT
CNotifyObjectInterface::QueryNotifyObject (
IN CImplINetCfg* pINetCfg,
IN REFIID riid,
OUT VOID** ppvObject)
{
HRESULT hr;
*ppvObject = NULL;
hr = HrEnsureNotifyObjectInitialized (pINetCfg, FALSE);
if (S_OK == hr)
{
if (m_pNod && m_pNod->pCc)
{
hr = m_pNod->pCc->QueryInterface (riid, ppvObject);
}
else
{
hr = E_NOINTERFACE;
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CNotifyObjectInterface::QueryNotifyObject");
return hr;
}
VOID
CNotifyObjectInterface::ReleaseNotifyObject (
IN CImplINetCfg* pINetCfg,
IN BOOL fCancel)
{
Assert (FIff(pINetCfg, fCancel));
if (m_pNod)
{
// Tell the notify object to cancel if requested.
//
if (fCancel)
{
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
(VOID) m_pNod->pCc->CancelChanges ();
}
NC_CATCH_ALL
{
; // ignored
}
pINetCfg->LowerRpl (RPL_DISALLOW);
}
// Release all of the interfaces we are holding.
//
ReleaseObj (m_pNod->pCc);
ReleaseObj (m_pNod->pNb);
ReleaseObj (m_pNod->pCp);
ReleaseObj (m_pNod->pCs);
ReleaseObj (m_pNod->pUe);
ReleaseObj (m_pNod->pNg);
MemFree (m_pNod);
m_pNod = NULL;
}
m_fInitialized = FALSE;
}
HRESULT
CNotifyObjectInterface::NewlyAdded (
IN CImplINetCfg* pINetCfg,
IN const NETWORK_INSTALL_PARAMS* pnip)
{
HRESULT hr;
//$REVIEW: Calling HrEnsureNotifyObjectInitialized is probably not needed
// because when we have the write lock and call notify objects, we always
// ensure they are loaded before we get here.
//
hr = HrEnsureNotifyObjectInitialized (pINetCfg, TRUE);
if ((S_OK == hr) && m_pNod && m_pNod->pCs)
{
// Inform the notify object that its component is being installed
// and tell it to read the answerfile if we are using one.
//
DWORD dwSetupFlags;
if (pnip)
{
dwSetupFlags = pnip->dwSetupFlags;
}
else
{
dwSetupFlags = FInSystemSetup() ? NSF_PRIMARYINSTALL
: NSF_POSTSYSINSTALL;
}
// Raise the reentrancy protection level to only allow
// install or remove before calling the notify object's Install
// method.
//
pINetCfg->RaiseRpl (RPL_ALLOW_INSTALL_REMOVE);
NC_TRY
{
hr = m_pNod->pCs->Install (dwSetupFlags);
if (SUCCEEDED(hr) && pnip &&
pnip->pszAnswerFile &&
pnip->pszAnswerSection)
{
// Raise the reentrancy protection level to disallow
// all reentrancy before calling the notify object's
// ReadAnswerFile method.
//
pINetCfg->RaiseRpl (RPL_DISALLOW);
NC_TRY
{
hr = m_pNod->pCs->ReadAnswerFile (
pnip->pszAnswerFile,
pnip->pszAnswerSection);
}
NC_CATCH_ALL
{
;
}
pINetCfg->LowerRpl (RPL_DISALLOW);
}
}
NC_CATCH_ALL
{
;
}
pINetCfg->LowerRpl (RPL_ALLOW_INSTALL_REMOVE);
hr = S_OK;
}
TraceHr (ttidError, FAL, hr, FALSE,
"CNotifyObjectInterface::NewlyAdded");
return hr;
}
VOID
CNotifyObjectInterface::Removed (
IN CImplINetCfg* pINetCfg)
{
Assert (m_fInitialized);
if (!m_pNod || !m_pNod->pCs)
{
return;
}
// Raise the reentrancy protection level to only allow
// install or remove before calling the notify object's Install
// method.
//
pINetCfg->RaiseRpl (RPL_ALLOW_INSTALL_REMOVE);
NC_TRY
{
// Inform the notify object that its component is being removed.
//
(VOID) m_pNod->pCs->Removing ();
}
NC_CATCH_ALL
{
;
}
pINetCfg->LowerRpl (RPL_ALLOW_INSTALL_REMOVE);
}
VOID
CNotifyObjectInterface::Updated (
IN CImplINetCfg* pINetCfg,
IN DWORD dwSetupFlags,
IN DWORD dwUpgradeFromBuildNo)
{
Assert (m_fInitialized);
if (!m_pNod || !m_pNod->pCs)
{
return;
}
// Raise the reentrancy protection level to only allow
// install or remove before calling the notify object's Install
// method.
//
pINetCfg->RaiseRpl (RPL_ALLOW_INSTALL_REMOVE);
NC_TRY
{
HRESULT hrNotify;
// Inform the notify object that its component is being updated.
//
hrNotify = m_pNod->pCs->Upgrade (dwSetupFlags,
dwUpgradeFromBuildNo);
// If Upgrade returns S_OK, it means they recognized and
// handled the event and are now dirty because of it.
//
if (S_OK == hrNotify)
{
CComponent* pThis;
pThis = CONTAINING_RECORD (this, CComponent, Notify);
Assert (pThis);
(VOID) pINetCfg->m_pNetConfig->ModifyCtx.
HrDirtyComponent (pThis);
}
}
NC_CATCH_ALL
{
;
}
pINetCfg->LowerRpl (RPL_ALLOW_INSTALL_REMOVE);
}
//+---------------------------------------------------------------------------
// CGlobalNotifyInterface -
//
VOID
CGlobalNotifyInterface::HoldINetCfg (
CImplINetCfg* pINetCfg)
{
AssertH (pINetCfg);
AssertH (!m_pINetCfg);
AddRefObj (pINetCfg->GetUnknown());
m_pINetCfg = pINetCfg;
}
VOID
CGlobalNotifyInterface::ReleaseAllNotifyObjects (
IN CComponentList& Components,
IN BOOL fCancel)
{
CComponentList::iterator iter;
CComponent* pComponent;
CImplINetCfg* pINetCfg;
// We need to pass a non-NULL pINetCfg if we are not cancelling.
//
pINetCfg = (fCancel) ? m_pINetCfg : NULL;
for (iter = Components.begin();
iter != Components.end();
iter++)
{
pComponent = *iter;
Assert (pComponent);
pComponent->Notify.ReleaseNotifyObject (pINetCfg, fCancel);
}
m_fInitialized = FALSE;
}
VOID
CGlobalNotifyInterface::ReleaseINetCfg ()
{
// If we have a cached INetCfg interface, we need to tell it
// that we no longer exist. Then we need to release the interface,
// of course.
//
if (m_pINetCfg)
{
// Get our containing CNetConfig pointer.
//
CNetConfig* pThis;
pThis = CONTAINING_RECORD(this, CNetConfig, Notify);
Assert (pThis == m_pINetCfg->m_pNetConfig);
m_pINetCfg->m_pNetConfig = NULL;
ReleaseObj (m_pINetCfg->GetUnknown());
m_pINetCfg = NULL;
}
}
HRESULT
CGlobalNotifyInterface::HrEnsureNotifyObjectsInitialized ()
{
// If we've already been through initialization, return immediately.
//
if (m_fInitialized)
{
return S_OK;
}
// Only perform initialization once, regardless of whether it succeeds
// or not.
//
m_fInitialized = TRUE;
// Get our containing CNetConfig pointer so we can enumerate all components.
//
CNetConfig* pThis;
pThis = CONTAINING_RECORD(this, CNetConfig, Notify);
HRESULT hr = S_OK;
// If we don't have an INetCfg interface pointer yet, it means we are
// creating one instead of it creating CNetConfig. If we had one, it
// would have been handed to us via HoldINetCfg which is called when
// CNetConfig is created by CImplINetCfg.
//
if (!m_pINetCfg)
{
hr = CImplINetCfg::HrCreateInstance (pThis, &m_pINetCfg);
Assert (!m_pINetCfg->m_fOwnNetConfig);
}
if (S_OK == hr)
{
Assert (m_pINetCfg);
CComponentList::iterator iter;
CComponent* pComponent;
for (iter = pThis->Core.Components.begin();
iter != pThis->Core.Components.end();
iter++)
{
pComponent = *iter;
Assert (pComponent);
hr = pComponent->Notify.HrEnsureNotifyObjectInitialized (m_pINetCfg, FALSE);
if (S_OK != hr)
{
break;
}
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CGlobalNotifyInterface::HrEnsureNotifyObjectsInitialized");
return hr;
}
VOID
CGlobalNotifyInterface::NgSysQueryOrNotifyBindingPath (
IN QN_FLAG Flag,
IN DWORD dwChangeFlag,
IN INetCfgBindingPath* pIPath,
IN BOOL* pfDisabled)
{
RPL_FLAGS RplFlag;
CNetConfig* pThis;
CComponentList::iterator iter;
CComponent* pComponent;
Assert (m_pINetCfg);
Assert ((QN_QUERY == Flag) || (QN_NOTIFY == Flag));
Assert (pIPath);
Assert (FImplies(QN_QUERY == Flag, pfDisabled));
Assert (m_fInitialized);
if (pfDisabled)
{
*pfDisabled = FALSE;
}
// Get our containing CNetConfig pointer so we can enumerate
// all components.
//
pThis = CONTAINING_RECORD(this, CNetConfig, Notify);
RplFlag = (QN_NOTIFY == Flag) ? RPL_ALLOW_INSTALL_REMOVE
: RPL_DISALLOW;
m_pINetCfg->RaiseRpl (RplFlag);
for (iter = pThis->Core.Components.begin();
iter != pThis->Core.Components.end();
iter++)
{
pComponent = *iter;
Assert (pComponent);
if (!pComponent->Notify.m_pNod ||
!pComponent->Notify.m_pNod->pNg ||
!(pComponent->Notify.m_pNod->dwNotifyGlobalFlags & NCN_BINDING_PATH))
{
continue;
}
// If the component has not registered for what we are changing,
// (NCN_ADD, NCN_REMOVE, NCN_ENABLE, NCN_DISABLE) then
// skip it.
//
if (!(pComponent->Notify.m_pNod->dwNotifyGlobalFlags & dwChangeFlag))
{
continue;
}
NC_TRY
{
HRESULT hr;
if (QN_QUERY == Flag)
{
hr = pComponent->Notify.m_pNod->pNg->
SysQueryBindingPath (dwChangeFlag, pIPath);
if (NETCFG_S_DISABLE_QUERY == hr)
{
*pfDisabled = TRUE;
break;
}
}
else
{
hr = pComponent->Notify.m_pNod->pNg->
SysNotifyBindingPath (dwChangeFlag, pIPath);
// If SysNotifyBindingPath returns S_OK, it means they
// recognized and handled the event and are now dirty
// because of it. Because some notify objects let
// success codes such as NETCFG_S_REBOOT slip through,
// consider them dirty if they don't return S_FALSE.
//
if (S_FALSE != hr)
{
hr = m_pINetCfg->m_pNetConfig->ModifyCtx.
HrDirtyComponent(pComponent);
}
}
}
NC_CATCH_ALL
{
;
}
}
m_pINetCfg->LowerRpl (RplFlag);
}
HRESULT
CGlobalNotifyInterface::NgSysNotifyComponent (
IN DWORD dwChangeFlag,
IN CComponent* pComponentOfInterest)
{
HRESULT hr;
INetCfgComponent* pICompOfInterest;
// We should have called HrEnsureNotifyObjectsInitialized by now.
//
Assert (m_fInitialized);
// If the component of interest has not had its data loaded successfully,
// we shouldn't bother sending the notification. The notify objects are
// just going to call back on the interface to the component and fail
// if they call a method that requires this data.
//
if (!pComponentOfInterest->Ext.FLoadedOkayIfLoadedAtAll())
{
return S_OK;
}
hr = pComponentOfInterest->HrGetINetCfgComponentInterface (
m_pINetCfg, &pICompOfInterest);
if (S_OK == hr)
{
DWORD dwMask = 0;
NETCLASS Class = pComponentOfInterest->Class();
CNetConfig* pThis;
CComponentList::iterator iter;
CComponent* pComponent;
if (FIsConsideredNetClass(Class))
{
dwMask = NCN_NET;
}
else if (NC_NETTRANS == Class)
{
dwMask = NCN_NETTRANS;
}
else if (NC_NETCLIENT == Class)
{
dwMask = NCN_NETCLIENT;
}
else if (NC_NETSERVICE == Class)
{
dwMask = NCN_NETSERVICE;
}
// Get our containing CNetConfig pointer so we can enumerate
// all components.
//
pThis = CONTAINING_RECORD(this, CNetConfig, Notify);
// Raise the reentrancy protection level to only allow
// install or remove before calling the notify object's
// SysNotifyComponent method.
//
m_pINetCfg->RaiseRpl (RPL_ALLOW_INSTALL_REMOVE);
for (iter = pThis->Core.Components.begin();
iter != pThis->Core.Components.end();
iter++)
{
pComponent = *iter;
Assert (pComponent);
if (!pComponent->Notify.m_pNod ||
!pComponent->Notify.m_pNod->pNg)
{
continue;
}
// If the component has not registered for one of NCN_NET,
// NCN_NETTRANS, etc. then skip it.
//
if (!(pComponent->Notify.m_pNod->dwNotifyGlobalFlags & dwMask))
{
continue;
}
// If the component has not registered for what we are changing,
// (NCN_ADD, NCN_REMOVE, NCN_UPDATE, NCN_PROPERTYCHANGE) then
// skip it.
//
if (!(pComponent->Notify.m_pNod->dwNotifyGlobalFlags & dwChangeFlag))
{
continue;
}
NC_TRY
{
HRESULT hrNotify;
hrNotify = pComponent->Notify.m_pNod->pNg->SysNotifyComponent (
dwMask | dwChangeFlag,
pICompOfInterest);
// If SysNotifyComponent returns S_OK, it means they
// recognized and handled the event and are now dirty
// because of it. Because some notify objects let
// success codes such as NETCFG_S_REBOOT slip through,
// consider them dirty if they don't return S_FALSE.
//
if (S_FALSE != hrNotify)
{
hr = m_pINetCfg->m_pNetConfig->ModifyCtx.
HrDirtyComponent(pComponent);
}
}
NC_CATCH_ALL
{
;
}
}
m_pINetCfg->LowerRpl (RPL_ALLOW_INSTALL_REMOVE);
ReleaseObj (pICompOfInterest);
}
TraceHr (ttidError, FAL, hr, FALSE,
"CGlobalNotifyInterface::NgSysNotifyComponent");
return hr;
}
HRESULT
CGlobalNotifyInterface::ComponentAdded (
IN CComponent* pComponent,
IN const NETWORK_INSTALL_PARAMS* pnip)
{
HRESULT hr;
Assert (pComponent);
// Initialize the notify object for the component and call
// its Install method followed by ReadAnswerFile if we are installing
// with one.
//
hr = pComponent->Notify.NewlyAdded (m_pINetCfg, pnip);
if (S_OK == hr)
{
// Notify all notify objects that are interested in component
// additions.
//
hr = NgSysNotifyComponent(NCN_ADD, pComponent);
}
TraceHr (ttidError, FAL, hr, FALSE,
"CGlobalNotifyInterface::ComponentAdded");
return hr;
}
HRESULT
CGlobalNotifyInterface::ComponentRemoved (
IN CComponent* pComponent)
{
HRESULT hr;
Assert (pComponent);
pComponent->Notify.Removed (m_pINetCfg);
hr = NgSysNotifyComponent(NCN_REMOVE, pComponent);
TraceHr (ttidError, FAL, hr, FALSE,
"CGlobalNotifyInterface::ComponentRemoved");
return hr;
}
HRESULT
CGlobalNotifyInterface::ComponentUpdated (
IN CComponent* pComponent,
IN DWORD dwSetupFlags,
IN DWORD dwUpgradeFromBuildNo)
{
HRESULT hr;
Assert (pComponent);
pComponent->Notify.Updated (m_pINetCfg,
dwSetupFlags, dwUpgradeFromBuildNo);
hr = NgSysNotifyComponent(NCN_UPDATE, pComponent);
TraceHr (ttidError, FAL, hr, FALSE,
"CGlobalNotifyInterface::ComponentUpdated");
return hr;
}
VOID
CGlobalNotifyInterface::NotifyBindPath (
IN DWORD dwChangeFlag,
IN CBindPath* pBindPath,
IN INetCfgBindingPath* pIPath OPTIONAL)
{
HRESULT hr;
CImplINetCfg* pINetCfg;
CComponent* pOwner;
BOOL fReleasePath;
Assert (m_fInitialized);
Assert ((dwChangeFlag & NCN_ADD) ||
(dwChangeFlag & NCN_REMOVE) ||
(dwChangeFlag & NCN_ENABLE) ||
(dwChangeFlag & NCN_DISABLE));
Assert (FImplies(dwChangeFlag & NCN_REMOVE, !(dwChangeFlag & NCN_DISABLE)));
Assert (FImplies(dwChangeFlag & NCN_ADD, !(dwChangeFlag & NCN_REMOVE)));
Assert (FImplies(dwChangeFlag & NCN_REMOVE, !(dwChangeFlag & NCN_ADD)));
Assert (pBindPath);
hr = S_OK;
pINetCfg = PINetCfg();
pOwner = pBindPath->POwner();
fReleasePath = FALSE;
// Create an INetCfgBindingPath representation of the path for
// the notify objects if we were not given one.
//
if (!pIPath)
{
// If the bindpath contains components that have had a problem
// loading, we shouldn't bother sending the notification.
// The notify objects are just going to call back on the interface
// to the component and fail if they call a method that requires
// this data.
//
if (!pBindPath->FAllComponentsLoadedOkayIfLoadedAtAll())
{
return;
}
hr = CImplINetCfgBindingPath::HrCreateInstance (
pINetCfg, pBindPath, &pIPath);
fReleasePath = TRUE;
}
if (S_OK == hr)
{
Assert (pIPath);
// If adding...
//
if (dwChangeFlag & NCN_ADD)
{
BOOL fDisabled;
fDisabled = FALSE;
// First, query the owner of the bindpath to see if he wants
// it disabled.
//
pOwner->Notify.NbQueryOrNotifyBindingPath (
pINetCfg,
QN_QUERY,
dwChangeFlag,
pIPath,
&fDisabled);
// If the owner doesn't want it disabled, see if any global
// notify objects do.
//
if (!fDisabled)
{
NgSysQueryOrNotifyBindingPath (
QN_QUERY,
dwChangeFlag,
pIPath,
&fDisabled);
}
// If someone wants it disabled, adjust the change flag
// for notify and add the bindpath to our disabled list.
//
if (fDisabled)
{
dwChangeFlag = NCN_ADD | NCN_DISABLE;
(VOID)pINetCfg->m_pNetConfig->Core.HrDisableBindPath (pBindPath);
}
}
//if (g_pDiagCtx->Flags() & DF_SHOW_CONSOLE_OUTPUT)
{
WCHAR pszBindPath [1024];
ULONG cch;
cch = celems(pszBindPath) - 1;
if (pBindPath->FGetPathToken (pszBindPath, &cch))
{
g_pDiagCtx->Printf (ttidBeDiag, " %S (%s)\n",
pszBindPath,
(dwChangeFlag & NCN_ENABLE)
? "enabled"
: (dwChangeFlag & NCN_DISABLE)
? "disabled"
: "removed");
}
}
pOwner->Notify.NbQueryOrNotifyBindingPath (
pINetCfg,
QN_NOTIFY,
dwChangeFlag,
pIPath,
NULL);
NgSysQueryOrNotifyBindingPath (
QN_NOTIFY,
dwChangeFlag,
pIPath,
NULL);
if (fReleasePath)
{
ReleaseObj (pIPath);
}
}
}
HRESULT
CGlobalNotifyInterface::QueryAndNotifyBindPaths (
IN DWORD dwBaseChangeFlag,
IN CBindingSet* pBindSet,
IN UINT cSkipFirstBindPaths)
{
CBindPath* pBindPath;
DWORD dwChangeFlag;
PCSTR pszDiagMsg;
// We should have called HrEnsureNotifyObjectsInitialized by now.
//
Assert (m_fInitialized);
Assert ((dwBaseChangeFlag & NCN_ADD) || (dwBaseChangeFlag & NCN_REMOVE));
if (dwBaseChangeFlag & NCN_ADD)
{
dwChangeFlag = NCN_ADD | NCN_ENABLE;
pszDiagMsg = "Query and notify the following bindings:\n";
}
else
{
dwChangeFlag = NCN_REMOVE;
pszDiagMsg = "Notify the following bindings are removed:\n";
}
g_pDiagCtx->Printf (ttidBeDiag, pszDiagMsg);
// Iterate the newly added bindpaths by picking up where the
// previous set ended and going to the end of the binding set.
// Note, because this may recurse, pBindSet may change during
// iteration, so a simple pointer increment through begin() to end()
// may fail if the bindset is reallocated or grown.
// Note too that we save off the current count of bindpaths in
// iStopAtBindPath. If we did not, when we come out of a recursion where
// the binding set grew, we'd re-notify the newly added bindpaths
// if we used a direct comparison of 'i < pBindSet->CountBindPaths()'.
//
UINT iStopAtBindPath = pBindSet->CountBindPaths();
for (UINT i = cSkipFirstBindPaths; i < iStopAtBindPath; i++)
{
pBindPath = pBindSet->PGetBindPathAtIndex(i);
NotifyBindPath (dwChangeFlag, pBindPath, NULL);
}
return S_OK;
}