windows-nt/Source/XPSP1/NT/net/config/netcfg/engine/ibind.cpp
2020-09-26 16:20:57 +08:00

807 lines
19 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: I B I N D . C P P
//
// Contents: Implements the INetCfgBindingInterface and INetCfgBindingPath
// COM interfaces.
//
// Notes:
//
// Author: shaunco 15 Jan 1999
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "ibind.h"
#include "ncvalid.h"
#include "netcfg.h"
#include "util.h"
//static
HRESULT
CImplINetCfgBindingInterface::HrCreateInstance (
IN CImplINetCfg* pINetCfg,
IN CImplINetCfgComponent* pUpper,
IN CImplINetCfgComponent* pLower,
OUT INetCfgBindingInterface** ppv)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr = E_OUTOFMEMORY;
CImplINetCfgBindingInterface* pObj;
pObj = new CComObject <CImplINetCfgBindingInterface>;
if (pObj)
{
// Initialize our members.
//
pObj->m_pUpper = pUpper;
pObj->m_pLower = pLower;
// Do the standard CComCreator::CreateInstance stuff.
//
pObj->SetVoid (NULL);
pObj->InternalFinalConstructAddRef ();
hr = pObj->FinalConstruct ();
pObj->InternalFinalConstructRelease ();
if (S_OK == hr)
{
hr = pObj->QueryInterface (IID_INetCfgBindingInterface,
(VOID**)ppv);
// The last thing we do is addref any interfaces we hold.
// We only do this if we are returning success.
//
if (S_OK == hr)
{
AddRefObj (pUpper->GetUnknown());
AddRefObj (pLower->GetUnknown());
pObj->HoldINetCfg (pINetCfg);
}
}
if (S_OK != hr)
{
delete pObj;
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingInterface::HrCreateInstance");
return hr;
}
HRESULT
CImplINetCfgBindingInterface::HrLockAndTestForValidInterface (
DWORD dwFlags)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
Lock();
hr = m_pUpper->HrIsValidInterface (dwFlags);
if (S_OK == hr)
{
hr = m_pLower->HrIsValidInterface (dwFlags);
}
if (S_OK != hr)
{
Unlock();
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingInterface::HrLockAndTestForValidInterface");
return hr;
}
//+---------------------------------------------------------------------------
// INetCfgBindingInterface
//
STDMETHODIMP
CImplINetCfgBindingInterface::GetName (
OUT PWSTR* ppszInterfaceName)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadOutPtr(ppszInterfaceName))
{
hr = E_POINTER;
}
else
{
*ppszInterfaceName = NULL;
hr = HrLockAndTestForValidInterface (IF_NEED_COMPONENT_DATA);
if (S_OK == hr)
{
CComponent* pUpper = m_pUpper->m_pComponent;
CComponent* pLower = m_pLower->m_pComponent;
const WCHAR* pch;
ULONG cch;
if (pUpper->FCanDirectlyBindTo (pLower, &pch, &cch))
{
hr = HrCoTaskMemAllocAndDupSzLen (
pch, cch, ppszInterfaceName);
}
else
{
AssertSz(0, "Why no match if we have a binding interface "
"created for these components?");
hr = E_UNEXPECTED;
}
Unlock();
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingInterface::GetName");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingInterface::GetUpperComponent (
OUT INetCfgComponent** ppComp)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadOutPtr(ppComp))
{
hr = E_POINTER;
}
else
{
*ppComp = NULL;
hr = HrLockAndTestForValidInterface (IF_DEFAULT);
if (S_OK == hr)
{
AddRefObj (m_pUpper->GetUnknown());
*ppComp = m_pUpper;
Unlock();
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingInterfaceGetName::GetUpperComponent");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingInterface::GetLowerComponent (
OUT INetCfgComponent** ppComp)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadOutPtr(ppComp))
{
hr = E_POINTER;
}
else
{
*ppComp = NULL;
hr = HrLockAndTestForValidInterface (IF_DEFAULT);
if (S_OK == hr)
{
AddRefObj (m_pLower->GetUnknown());
*ppComp = m_pLower;
Unlock();
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingInterfaceGetName::GetLowerComponent");
return hr;
}
//static
HRESULT
CImplINetCfgBindingPath::HrCreateInstance (
IN CImplINetCfg* pINetCfg,
IN const CBindPath* pBindPath,
OUT INetCfgBindingPath** ppIPath)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
ULONG ulDepth;
ULONG cbArray;
CComponent* pComponent;
CImplINetCfgBindingPath* pObj;
Assert (pINetCfg);
Assert (pBindPath);
Assert (ppIPath);
// Caller's are responsible for ensuring that if an interface is about
// to be handed out, and the external data has been loaded, that the
// data has been loaded successfully. If we handed out an interface
// and the data was NOT loaded successfully, it just means we are doomed
// to fail later when the client of the interface calls a method that
// requires that data.
//
Assert (pBindPath->FAllComponentsLoadedOkayIfLoadedAtAll());
hr = E_OUTOFMEMORY;
pObj = new CComObject <CImplINetCfgBindingPath>;
if (pObj)
{
// Initialize our members.
//
ulDepth = pBindPath->CountComponents();
cbArray = ulDepth * sizeof(INetCfgComponent*);
AssertSz (0 != ulDepth, "Why are we being asked to expose an empty bindpath?");
AssertSz (1 != ulDepth, "Why are we being asked to expose a bindpath with only one component?");
// If the bindpath has more components than our static
// array has room for, we'll have to use an allocated array.
//
if (cbArray > sizeof(pObj->m_apIComp))
{
// Ensure failure of MemAlloc causes us to return the correct
// error code. (Should be set above and not changed between.)
//
Assert (E_OUTOFMEMORY == hr);
pObj->m_papIComp = (INetCfgComponent**) MemAlloc (cbArray);
if (pObj->m_papIComp)
{
hr = S_OK;
}
}
else
{
pObj->m_papIComp = pObj->m_apIComp;
hr = S_OK;
}
// Now get each INetCfgComponent interface for the components in
// the bindpath.
//
if (S_OK == hr)
{
UINT iComp;
ZeroMemory (pObj->m_papIComp, cbArray);
for (iComp = 0; iComp < ulDepth; iComp++)
{
pComponent = pBindPath->PGetComponentAtIndex (iComp);
Assert (pComponent);
hr = pComponent->HrGetINetCfgComponentInterface (
pINetCfg, pObj->m_papIComp + iComp);
if (S_OK != hr)
{
ReleaseIUnknownArray (iComp+1, (IUnknown**)pObj->m_papIComp);
break;
}
}
}
if (S_OK == hr)
{
pObj->m_cpIComp = ulDepth;
// Do the standard CComCreator::CreateInstance stuff.
//
pObj->SetVoid (NULL);
pObj->InternalFinalConstructAddRef ();
hr = pObj->FinalConstruct ();
pObj->InternalFinalConstructRelease ();
if (S_OK == hr)
{
hr = pObj->QueryInterface (IID_INetCfgBindingPath,
(VOID**)ppIPath);
// The last thing we do is addref any interfaces we hold.
// We only do this if we are returning success.
//
if (S_OK == hr)
{
pObj->HoldINetCfg (pINetCfg);
}
}
}
if (S_OK != hr)
{
if (pObj->m_papIComp != pObj->m_apIComp)
{
MemFree (pObj->m_papIComp);
}
delete pObj;
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingPath::HrCreateInstance");
return hr;
}
HRESULT
CImplINetCfgBindingPath::HrIsValidInterface (
IN DWORD dwFlags,
OUT CBindPath* pBindPath)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
hr = m_pINetCfg->HrIsValidInterface (dwFlags);
if ((S_OK == hr) && pBindPath)
{
Assert (0 == pBindPath->CountComponents());
// When pBindPath is specified, it means the caller wants a
// CBindPath representation of the bindpath we represent.
// We have to build this using the array of INetCfgComponent
// pointer we maintain. Do this by verifying each one is valid
// and then adding its internal CComponent* to pBindPath.
//
hr = pBindPath->HrReserveRoomForComponents (m_cpIComp);
if (S_OK == hr)
{
CImplINetCfgComponent* pIComp;
CComponent* pComponent;
// For each INetCfgComponent* in our array...
//
for (UINT i = 0; i < m_cpIComp; i++)
{
pIComp = (CImplINetCfgComponent*)m_papIComp[i];
if (pIComp == NULL)
{
return(E_OUTOFMEMORY);
}
hr = pIComp->HrIsValidInterface (IF_DEFAULT);
if (S_OK != hr)
{
break;
}
pComponent = pIComp->m_pComponent;
Assert (pComponent);
hr = pBindPath->HrAppendComponent (pComponent);
if (S_OK != hr)
{
break;
}
}
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingPath::HrIsValidInterface");
return hr;
}
HRESULT
CImplINetCfgBindingPath::HrLockAndTestForValidInterface (
IN DWORD dwFlags,
OUT CBindPath* pBindPath)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
Lock();
hr = HrIsValidInterface (dwFlags, pBindPath);
if (S_OK != hr)
{
Unlock();
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgHolder::HrLockAndTestForValidInterface");
return hr;
}
//+---------------------------------------------------------------------------
// INetCfgBindingPath
//
STDMETHODIMP
CImplINetCfgBindingPath::IsSamePathAs (
IN INetCfgBindingPath* pIPath)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadInPtr(pIPath))
{
hr = E_POINTER;
}
else
{
hr = HrLockAndTestForValidInterface (IF_DEFAULT, NULL);
if (S_OK == hr)
{
CImplINetCfgBindingPath* pOther = (CImplINetCfgBindingPath*)pIPath;
Assert (m_cpIComp);
Assert (m_papIComp);
Assert (pOther->m_cpIComp);
Assert (pOther->m_papIComp);
// Can't be the same if our length is not the same.
//
if (m_cpIComp != pOther->m_cpIComp)
{
hr = S_FALSE;
}
else
{
UINT cb;
cb = m_cpIComp * sizeof(INetCfgComponent*);
hr = (0 == memcmp (
(BYTE*)(m_papIComp),
(BYTE*)(pOther->m_papIComp),
cb)) ? S_OK : S_FALSE;
}
Unlock();
}
}
TraceHr (ttidError, FAL, hr, (S_FALSE == hr),
"CImplINetCfgBindingPath::IsSamePathAs");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingPath::IsSubPathOf (
IN INetCfgBindingPath* pIPath)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadInPtr(pIPath))
{
hr = E_POINTER;
}
else
{
hr = HrLockAndTestForValidInterface (IF_DEFAULT, NULL);
if (S_OK == hr)
{
CImplINetCfgBindingPath* pOther = (CImplINetCfgBindingPath*)pIPath;
Assert (m_cpIComp);
Assert (m_papIComp);
Assert (pOther->m_cpIComp);
Assert (pOther->m_papIComp);
// Can't be a subpath if our length is greater or equal.
//
if (m_cpIComp >= pOther->m_cpIComp)
{
hr = S_FALSE;
}
else
{
UINT cb;
UINT unSkipComponents;
cb = m_cpIComp * sizeof(INetCfgComponent*);
Assert (pOther->m_cpIComp > m_cpIComp);
unSkipComponents = pOther->m_cpIComp - m_cpIComp;
hr = (0 == memcmp (
(BYTE*)(m_papIComp),
(BYTE*)(pOther->m_papIComp + unSkipComponents),
cb)) ? S_OK : S_FALSE;
}
// Special Case: NCF_DONTEXPOSELOWER
// If we're about to return false, let's check for a case like:
// is ms_ipx->adapter a subpath of ms_server->ms_ipx and return
// TRUE. For this case, it really is a subpath, but the binding
// has been broken because of NCF_DONTEXPOSELOWER.
//
// If the last component of pIPath, and the first component of
// this path both are NCF_DONTEXPOSELOWER, then consider this
// path a subpath of pIPath. This assumes that ms_nwipx and
// ms_nwnb are the only components with this characteristic.
//
if (S_FALSE == hr)
{
CImplINetCfgComponent* pIFirst;
CImplINetCfgComponent* pILast;
pIFirst = (CImplINetCfgComponent*)m_papIComp[0];
pILast = (CImplINetCfgComponent*)pOther->m_papIComp[pOther->m_cpIComp - 1];
if ((pIFirst == NULL) ||
(pILast == NULL))
{
return(E_OUTOFMEMORY);
}
if ((S_OK == pIFirst->HrIsValidInterface(IF_DEFAULT)) &&
(S_OK == pILast->HrIsValidInterface(IF_DEFAULT)))
{
Assert (pIFirst->m_pComponent);
Assert (pILast->m_pComponent);
if ((pIFirst->m_pComponent->m_dwCharacter & NCF_DONTEXPOSELOWER) &&
(pILast->m_pComponent->m_dwCharacter & NCF_DONTEXPOSELOWER))
{
if (0 == wcscmp(L"ms_nwipx", pIFirst->m_pComponent->m_pszInfId))
{
hr = S_OK;
}
else if (pIFirst->m_pComponent == pILast->m_pComponent)
{
hr = S_OK;
}
}
}
}
// End Special case
Unlock();
}
}
TraceHr (ttidError, FAL, hr, (S_FALSE == hr),
"CImplINetCfgBindingPath::IsSubPathOf");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingPath::IsEnabled ()
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
CBindPath BindPath;
hr = HrLockAndTestForValidInterface (IF_DEFAULT, &BindPath);
if (S_OK == hr)
{
Assert (m_pINetCfg);
if (m_pINetCfg->m_pNetConfig->Core.FIsBindPathDisabled (
&BindPath, IBD_MATCH_SUBPATHS_TOO))
{
hr = S_FALSE;
}
Unlock();
}
TraceHr (ttidError, FAL, hr, S_FALSE == hr,
"CImplINetCfgBindingPath::IsEnabled");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingPath::Enable (
IN BOOL fEnable)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
CBindPath BindPath;
hr = HrLockAndTestForValidInterface (IF_NEED_WRITE_LOCK, &BindPath);
if (S_OK == hr)
{
Assert (m_pINetCfg);
hr = m_pINetCfg->m_pNetConfig->ModifyCtx.HrEnableOrDisableBindPath (
(fEnable) ? NCN_ENABLE : NCN_DISABLE,
&BindPath,
this);
Unlock();
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingPath::Enable");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingPath::GetPathToken (
OUT PWSTR* ppszPathToken)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadOutPtr(ppszPathToken))
{
hr = E_POINTER;
}
else
{
CBindPath BindPath;
*ppszPathToken = NULL;
hr = HrLockAndTestForValidInterface (IF_DEFAULT, &BindPath);
if (S_OK == hr)
{
ULONG cch;
cch = 0;
BindPath.FGetPathToken (NULL, &cch);
if (cch)
{
hr = HrCoTaskMemAlloc (
((cch + 1) * sizeof(WCHAR)),
(VOID**)ppszPathToken);
if (S_OK == hr)
{
BindPath.FGetPathToken (*ppszPathToken, &cch);
}
}
Unlock();
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingPath::GetPathToken");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingPath::GetOwner (
OUT INetCfgComponent** ppIComp)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadOutPtr(ppIComp))
{
hr = E_POINTER;
}
else
{
*ppIComp = NULL;
hr = HrLockAndTestForValidInterface (IF_DEFAULT, NULL);
if (S_OK == hr)
{
Assert (m_cpIComp);
Assert (m_papIComp);
Assert (m_papIComp[0]);
AddRefObj (m_papIComp[0]);
*ppIComp = m_papIComp[0];
Unlock();
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingPath::GetOwner");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingPath::GetDepth (
OUT ULONG* pulDepth)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadOutPtr(pulDepth))
{
hr = E_POINTER;
}
else
{
*pulDepth = NULL;
hr = HrLockAndTestForValidInterface (IF_DEFAULT, NULL);
if (S_OK == hr)
{
Assert (m_cpIComp);
*pulDepth = m_cpIComp;
Unlock();
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingPath::GetDepth");
return hr;
}
STDMETHODIMP
CImplINetCfgBindingPath::EnumBindingInterfaces (
OUT IEnumNetCfgBindingInterface** ppIEnum)
{
TraceFileFunc(ttidNetCfgBind);
HRESULT hr;
// Validate parameters.
//
if (FBadOutPtr(ppIEnum))
{
hr = E_POINTER;
}
else
{
*ppIEnum = NULL;
hr = HrLockAndTestForValidInterface (IF_DEFAULT, NULL);
if (S_OK == hr)
{
hr = CImplIEnumNetCfgBindingInterface::HrCreateInstance (
m_pINetCfg,
this,
ppIEnum);
Unlock();
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CImplINetCfgBindingPath::EnumBindingInterfaces");
return hr;
}