//+--------------------------------------------------------------------------- // // 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 #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 ; 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 ; 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; }