581 lines
13 KiB
C++
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;
|
||
|
}
|
||
|
|