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

581 lines
13 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999.
//
// File: C O M P R E F S . C P P
//
// Contents: Implements the interface to a component's references. A
// component can be referenced (installed by) other components,
// the user, or other software. This module manages the
// interface to that data.
//
// Notes:
//
// Author: shaunco 15 Jan 1999
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "comp.h"
#include "comprefs.h"
#include "icomp.h"
#include "nceh.h"
#include "ncreg.h"
#define REGSTR_KEY_REFNAMES \
L"SYSTEM\\CurrentControlSet\\Control\\Network\\RefNames"
// Cannot be inline because comprefs.h cannot include comp.h.
//
CComponentReferences::~CComponentReferences ()
{
Assert (this);
// Must use delete on m_pData to get destructors of its members
// to be called.
//
delete m_pData;
}
ULONG
CComponentReferences::CountComponentsReferencedBy () const
{
Assert (this);
if (!m_pData)
{
return 0;
}
return m_pData->RefByComponents.Count ();
}
ULONG
CComponentReferences::CountSoftwareReferencedBy () const
{
Assert (this);
if (!m_pData)
{
return 0;
}
return m_pData->RefBySoftware.size ();
}
ULONG
CComponentReferences::CountTotalReferencedBy () const
{
Assert (this);
if (!m_pData)
{
return 0;
}
return ((m_pData->fRefByUser) ? 1 : 0) +
m_pData->RefByComponents.Count () +
m_pData->RefBySoftware.size ();
}
HRESULT
HrGetSoftwareOboTokenKey (
IN const OBO_TOKEN* pOboToken,
BOOL fRegister,
OUT PWSTR* ppszKey)
{
HRESULT hr;
UINT cch;
Assert (pOboToken);
Assert (OBO_SOFTWARE == pOboToken->Type);
Assert (pOboToken->pszwManufacturer && *pOboToken->pszwManufacturer);
Assert (pOboToken->pszwProduct && *pOboToken->pszwProduct);
Assert (ppszKey);
cch = wcslen (pOboToken->pszwManufacturer) +
wcslen (pOboToken->pszwProduct);
hr = E_OUTOFMEMORY;
*ppszKey = (PWSTR)MemAlloc ((cch + 1) * sizeof(WCHAR));
if (*ppszKey)
{
hr = S_OK;
wcscpy (*ppszKey, pOboToken->pszwManufacturer);
wcscat (*ppszKey, pOboToken->pszwProduct);
if (fRegister)
{
HKEY hkeyRefNames;
hr = HrRegCreateKeyEx (
HKEY_LOCAL_MACHINE,
REGSTR_KEY_REFNAMES,
REG_OPTION_NON_VOLATILE,
KEY_WRITE, NULL, &hkeyRefNames, NULL);
if (SUCCEEDED(hr))
{
hr = HrRegSetSz (
hkeyRefNames,
*ppszKey,
pOboToken->pszwDisplayName);
RegCloseKey (hkeyRefNames);
}
}
}
TraceHr (ttidError, FAL, hr, FALSE, "HrGetSoftwareOboTokenKey");
return hr;
}
BOOL
CComponentReferences::FIsReferencedByComponent (
IN const CComponent* pComponent) const
{
Assert (pComponent);
if (!m_pData)
{
return FALSE;
}
return m_pData->RefByComponents.FComponentInList (pComponent);
}
BOOL
CComponentReferences::FIsReferencedByOboToken (
IN const OBO_TOKEN* pOboToken) const
{
HRESULT hr;
BOOL fIsReferenced;
PWSTR pszKey;
Assert (pOboToken);
if (!m_pData)
{
return FALSE;
}
fIsReferenced = FALSE;
CComponent* pComponent;
switch (pOboToken->Type)
{
case OBO_USER:
fIsReferenced = m_pData->fRefByUser;
break;
case OBO_COMPONENT:
// Can't be referenced if there are no references.
//
if (m_pData->RefByComponents.Count() > 0)
{
pComponent = PComponentFromComInterface (pOboToken->pncc);
fIsReferenced = m_pData->RefByComponents.FComponentInList (
pComponent);
}
break;
case OBO_SOFTWARE:
// Can't be referenced if there are no references.
//
if (m_pData->RefBySoftware.size() > 0)
{
// Get the key for the software token, but don't register
// the display name.
//
hr = HrGetSoftwareOboTokenKey (pOboToken, FALSE, &pszKey);
if (S_OK == hr)
{
fIsReferenced =
find (m_pData->RefBySoftware.begin(),
m_pData->RefBySoftware.end(), pszKey) !=
m_pData->RefBySoftware.end();
MemFree (pszKey);
}
}
break;
default:
AssertSz (FALSE, "Invalid obo token");
}
return fIsReferenced;
}
VOID
CComponentReferences::GetReferenceDescriptionsAsMultiSz (
IN BYTE* pbBuf OPTIONAL,
OUT ULONG* pcbBuf) const
{
ULONG cbBuf;
ULONG cbBufIn;
ULONG cb;
CComponentList::const_iterator iter;
const CComponent* pComponent;
vector<CWideString>::const_iterator pStr;
Assert (this);
Assert (m_pData);
Assert (pcbBuf);
cbBufIn = *pcbBuf;
cbBuf = 0;
// Get/Size the component descriptions.
//
for (iter = m_pData->RefByComponents.begin();
iter != m_pData->RefByComponents.end();
iter++)
{
pComponent = *iter;
Assert (pComponent);
cb = CbOfSzAndTermSafe(pComponent->Ext.PszDescription());
cbBuf += cb;
if (pbBuf && (cbBuf <= cbBufIn))
{
wcscpy ((PWSTR)pbBuf, pComponent->Ext.PszDescription());
pbBuf += cb;
}
}
// Get/Size the software descriptions.
//
if (!m_pData->RefBySoftware.empty())
{
HRESULT hr;
HKEY hkeyRefNames;
hr = HrRegOpenKeyEx (
HKEY_LOCAL_MACHINE,
REGSTR_KEY_REFNAMES,
KEY_READ,
&hkeyRefNames);
if (S_OK == hr)
{
for (pStr = m_pData->RefBySoftware.begin();
pStr != m_pData->RefBySoftware.end();
pStr++)
{
cb = cbBufIn - cbBuf;
hr = HrRegQuerySzBuffer (hkeyRefNames, pStr->c_str(),
(PWSTR)pbBuf, &cb);
if (S_OK == hr)
{
cbBuf += cb;
if (pbBuf)
{
pbBuf += cb;
}
}
}
RegCloseKey (hkeyRefNames);
}
}
// Terminate the multi-sz.
//
cbBuf += sizeof(WCHAR);
if (pbBuf && (cbBuf <= cbBufIn))
{
*(PWSTR)pbBuf = 0;
}
// Return the size of the buffer required.
//
*pcbBuf = cbBuf;
}
BOOL
CComponentReferences::FIsReferencedByOthers () const
{
Assert (this);
if (!m_pData)
{
return FALSE;
}
return m_pData->fRefByUser ||
!m_pData->RefByComponents.empty() ||
!m_pData->RefBySoftware.empty();
}
CComponent*
CComponentReferences::PComponentReferencedByAtIndex (
IN UINT unIndex) const
{
Assert (this);
if (!m_pData)
{
return NULL;
}
return m_pData->RefByComponents.PGetComponentAtIndex (unIndex);
}
const CWideString*
CComponentReferences::PSoftwareReferencedByAtIndex (
IN UINT unIndex) const
{
Assert (this);
if (!m_pData)
{
return NULL;
}
return &m_pData->RefBySoftware[unIndex];
}
HRESULT
CComponentReferences::HrEnsureAllocated ()
{
Assert (this);
if (m_pData)
{
return S_OK;
}
HRESULT hr;
hr = E_OUTOFMEMORY;
m_pData = new COMPONENT_REFERENCE_DATA;
if (m_pData)
{
ZeroMemory (m_pData, sizeof(COMPONENT_REFERENCE_DATA));
hr = S_OK;
}
TraceHr (ttidError, FAL, hr, FALSE,
"CComponentReferences::HrEnsureAllocated");
return hr;
}
HRESULT
CComponentReferences::HrAddReferenceByUser ()
{
HRESULT hr;
Assert (this);
hr = HrEnsureAllocated ();
if (S_OK == hr)
{
m_pData->fRefByUser = TRUE;
}
TraceHr (ttidError, FAL, hr, FALSE,
"CComponentReferences::AddReferenceByUser");
return hr;
}
HRESULT
CComponentReferences::HrAddReferenceByComponent (
IN const CComponent* pComponent)
{
HRESULT hr;
Assert (this);
Assert (pComponent);
hr = HrEnsureAllocated ();
if (S_OK == hr)
{
// If someone wants to add a reference by the same component
// multiple times, we'll allow it. The component only goes in the
// list once.
//
hr = m_pData->RefByComponents.HrInsertComponent (
pComponent, INS_IGNORE_IF_DUP | INS_NON_SORTED);
}
TraceHr (ttidError, FAL, hr, FALSE,
"CComponentReferences::HrAddReferenceByComponent");
return hr;
}
HRESULT
CComponentReferences::HrAddReferenceByOboToken (
IN const OBO_TOKEN* pOboToken)
{
Assert (pOboToken);
HRESULT hr;
CComponent* pComponent;
PWSTR pszKey;
switch (pOboToken->Type)
{
case OBO_USER:
hr = HrAddReferenceByUser ();
break;
case OBO_COMPONENT:
pComponent = PComponentFromComInterface (pOboToken->pncc);
hr = HrAddReferenceByComponent (pComponent);
break;
case OBO_SOFTWARE:
// Register the display name of the obo token.
//
hr = HrGetSoftwareOboTokenKey (pOboToken, TRUE, &pszKey);
if (S_OK == hr)
{
hr = HrAddReferenceBySoftware (pszKey);
MemFree (pszKey);
}
break;
default:
AssertSz (FALSE, "Invalid obo token");
}
TraceHr (ttidError, FAL, hr, FALSE,
"CComponentReferences::HrAddReferenceByOboToken");
return hr;
}
HRESULT
CComponentReferences::HrAddReferenceBySoftware (
IN PCWSTR pszKey)
{
HRESULT hr;
Assert (this);
Assert (pszKey && *pszKey);
hr = HrEnsureAllocated ();
if (S_OK == hr)
{
// If the key is not in the list, add it.
//
if (find (m_pData->RefBySoftware.begin(),
m_pData->RefBySoftware.end(), pszKey) ==
m_pData->RefBySoftware.end())
{
NC_TRY
{
m_pData->RefBySoftware.push_back (pszKey);
Assert (S_OK == hr);
}
NC_CATCH_ALL
{
hr = E_OUTOFMEMORY;
}
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"CComponentReferences::HrAddReferenceBySoftware");
return hr;
}
VOID
CComponentReferences::RemoveAllReferences()
{
Assert (this);
if (m_pData)
{
m_pData->fRefByUser = FALSE;
m_pData->RefByComponents.Clear();
m_pData->RefBySoftware.clear();
}
}
HRESULT
CComponentReferences::HrRemoveReferenceByOboToken (
IN const OBO_TOKEN* pOboToken)
{
Assert (pOboToken);
HRESULT hr;
CComponent* pComponent;
PWSTR pszKey;
if (!m_pData)
{
return S_OK;
}
hr = S_OK;
switch (pOboToken->Type)
{
case OBO_USER:
// Don't allow the user's reference to be removed until all
// other references are. This is to prevent the case where
// the user wants to remove IPX, but it is still referenced by
// SAP. If we remove the user's reference to IPX, then we will
// report that it was not removed. If the user then removes
// SAP, both SAP and IPX will be removed. While this will
// certainly work, to end users, they feel that if we tell them
// we can't remove IPX because it is still referenced, then they
// believe we have left IPX untouched and they should first remove
// SAP and then come back and remove IPX.
//
if (m_pData->RefByComponents.empty() &&
m_pData->RefBySoftware.empty())
{
m_pData->fRefByUser = FALSE;
}
break;
case OBO_COMPONENT:
pComponent = PComponentFromComInterface (pOboToken->pncc);
m_pData->RefByComponents.RemoveComponent(pComponent);
break;
case OBO_SOFTWARE:
// Register the display name of the obo token.
//
hr = HrGetSoftwareOboTokenKey (pOboToken, TRUE, &pszKey);
if (S_OK == hr)
{
vector<CWideString>::iterator iter;
iter = find (m_pData->RefBySoftware.begin(),
m_pData->RefBySoftware.end(), pszKey);
Assert (m_pData->RefBySoftware.end() != iter);
m_pData->RefBySoftware.erase (iter);
Assert (m_pData->RefBySoftware.end() ==
find (m_pData->RefBySoftware.begin(),
m_pData->RefBySoftware.end(), pszKey));
MemFree (pszKey);
}
break;
default:
AssertSz (FALSE, "Invalid obo token");
}
TraceHr (ttidError, FAL, hr, FALSE,
"CComponentReferences::HrRemoveReferenceByOboToken");
return hr;
}