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