windows-nt/Source/XPSP1/NT/com/ole32/cs/cstore/csacc.cxx
2020-09-26 16:20:57 +08:00

754 lines
18 KiB
C++

//
// Author: DebiM
// Date: September 1996
//
// File: csacc.cxx
//
// Class Store Manager implementation for a client desktop.
//
// This source file contains implementations for IClassAccess
// interface for CClassAccess object.
// It also contains the IEnumPackage implementation for the
// aggregate of all class containers seen by the caller.
//
//
//---------------------------------------------------------------------
#include "cstore.hxx"
/**
void
LogCsPathError(
WCHAR * pwszContainerPath,
HRESULT hr );
**/
#define MAXCLASSSTORES 10
IClassAccess *GetNextValidClassStore(PCLASSCONTAINER *pStoreList,
DWORD cStores,
DWORD *pcount);
extern HRESULT GetUserClassStores(
PCLASSCONTAINER **ppStoreList,
DWORD *pcStores);
//
// Link list pointer for Class Containers Seen
//
extern CLASSCONTAINER *gpContainerHead;
//
// Link list pointer for User Profiles Seen
//
extern USERPROFILE *gpUserHead;
//
// Global Class Factory for Class Container
//
extern CAppContainerCF *pCF;
//
// Critical Section used during operations on list of class stores
//
extern CRITICAL_SECTION ClassStoreBindList;
//
// CClassAccess implementation
//
CClassAccess::CClassAccess()
{
m_uRefs = 1;
m_cCalls = 0;
}
CClassAccess::~CClassAccess()
{
}
//----------------------------------------------------------------------
//
//
#ifdef DBG
void PrintClassSpec(
uCLSSPEC * pclsspec // Class Spec (GUID/Ext/MIME)
)
{
STRINGGUID szClsid;
if (pclsspec->tyspec == TYSPEC_CLSID)
{
StringFromGUID (pclsspec->tagged_union.clsid, szClsid);
CSDbgPrint((" ... GetClassSpecInfo by CLSID = %ws\n", szClsid));
}
if (pclsspec->tyspec == TYSPEC_PROGID)
{
CSDbgPrint((" ... GetClassSpecInfo by ProgID = %ws\n",
pclsspec->tagged_union.pProgId));
}
if (pclsspec->tyspec == TYSPEC_MIMETYPE)
{
CSDbgPrint((" ... GetClassSpecInfo by MimeType = %ws\n",
pclsspec->tagged_union.pMimeType));
}
if (pclsspec->tyspec == TYSPEC_FILEEXT)
{
CSDbgPrint((" ... GetClassSpecInfo by FileExt = %ws\n",
pclsspec->tagged_union.pFileExt));
}
if (pclsspec->tyspec == TYSPEC_IID)
{
StringFromGUID (pclsspec->tagged_union.iid, szClsid);
CSDbgPrint((" ... GetClassSpecInfo by IID = %ws\n", szClsid));
}
}
#endif
//----------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CClassAccess::GetAppInfo(
uCLSSPEC * pclsspec, // Class Spec (GUID/Ext/MIME)
QUERYCONTEXT * pQryContext, // Query Attributes
INSTALLINFO * pInstallInfo
)
//
// This is the most common method to access the Class Store.
// It queries the class store for implementations for a specific
// Class Id, or File Ext, or ProgID or MIME type.
//
// If a matching implementation is available for the object type,
// client architecture, locale and class context pointer to the
// binary is returned.
{
//
// Assume that this method is called in the security context
// of the user process. Hence there is no need to impersonate.
//
//
// Get the list of Class Stores for this user
//
PCLASSCONTAINER *pStoreList;
ULONG cStores=0;
HRESULT hr;
ULONG i;
ULONG chEaten;
IMoniker *pmk;
LPBC pbc;
IClassAccess *pICA = NULL;
#ifdef DBG
PrintClassSpec(pclsspec);
#endif
hr = GetUserClassStores(
&pStoreList,
&cStores);
if (!SUCCEEDED(hr))
{
return hr;
}
//RpcImpersonateClient( NULL );
for (i=0; i < cStores; i++)
{
if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i)))
continue;
//
// Call method on this store
//
pICA->AddRef();
hr = pICA->GetAppInfo(
pclsspec,
pQryContext,
pInstallInfo);
// Release it after use.
pICA->Release();
//
// Special case error return E_INVALIDARG
// Do not continue to look, return this.
//
if (hr == E_INVALIDARG)
{
//RevertToSelf();
return hr;
}
//
// maintain access counters
//
(pStoreList[i])->cAccess++;
if (SUCCEEDED(hr))
{
//RevertToSelf();
return hr;
}
else
{
(pStoreList[i])->cNotFound++;
CSDbgPrint(("CS: .. CClassAccess::GetClassSpecInfo() returned 0x%x\n", hr));
}
}
//RevertToSelf();
return CS_E_PACKAGE_NOTFOUND;
}
//
// GetNextValidClassStore
//
//
IClassAccess *GetNextValidClassStore(CLASSCONTAINER **pStoreList, DWORD cStores, DWORD *pcount)
{
HRESULT hr = S_OK;
IClassAccess *pretICA = NULL;
// BUGBUG:: Probably should move this inside the for loops so that the
// read accesses to gpClassStore do not get serialized. Debi?
EnterCriticalSection (&ClassStoreBindList);
for (pStoreList += (*pcount); (*pcount) < cStores; (*pcount)++, pStoreList++)
{
if ((*pStoreList)->gpClassStore != NULL)
{
hr = S_OK;
break;
}
if (FALSE) // ((*pStoreList)->cBindFailures >= MAX_BIND_ATTEMPTS)
{
// Number of continuous failures have reached MAX_BIND_ATTEMPTS
// for this container.
// Will temporarily disable lookups in this container.
// Report it in EventLog once
//
if ((*pStoreList)->cBindFailures == MAX_BIND_ATTEMPTS)
{
//LogCsPathError((*pStoreList)->pszClassStorePath, hr);
(*pStoreList)->cBindFailures++;
}
continue;
}
else
{
CSDbgPrint(("CS: .. Connecting to Store %d \n ... %ws..\n",
(*pcount),
(*pStoreList)->pszClassStorePath));
//
// Bind to this Class Store
//
if (wcsncmp ((*pStoreList)->pszClassStorePath, L"ADCS:", 5) == 0)
{
//
// If the Storename starts with ADCS
// it is NTDS based implementation. Call directly.
//
hr = pCF->CreateConnectedInstance(
((*pStoreList)->pszClassStorePath + 5),
(void **)&((*pStoreList)->gpClassStore));
}
else
{
//
// Support for Third Party Pluggable
// Class Stores is not in Beta1.
//
#if 1
hr = E_NOTIMPL;
#else
ULONG chEaten;
IMoniker *pmk;
LPBC pbc;
pbc = NULL;
hr = CreateBindCtx (0, &pbc);
if (!SUCCEEDED(hr))
{
continue;
}
pmk = NULL;
chEaten = 0;
hr = MkParseDisplayName (pbc,
(*pStoreList)->pszClassStorePath,
&chEaten,
&pmk);
if (SUCCEEDED(hr))
{
hr = pmk->BindToObject (pbc,
NULL,
IID_IClassAccess,
(void **)&((*pStoreList)->gpClassStore));
pmk->Release();
}
pbc->Release();
#endif
}
if (SUCCEEDED(hr))
{
(*pStoreList)->cBindFailures = 0;
hr = S_OK;
break;
}
if (!SUCCEEDED(hr))
{
CSDbgPrint(("CS: ... Failed to connect to this store\n"));
if ((*pStoreList)->cBindFailures == 0)
{
// First failue or First failure after successful
// binding.
// Report it in EventLog
//
//LogCsPathError((*pStoreList)->pszClassStorePath, hr);
}
((*pStoreList)->cBindFailures) ++;
continue;
}
}
}
if ((*pcount) != cStores)
pretICA = (*pStoreList)->gpClassStore;
LeaveCriticalSection (&ClassStoreBindList);
return pretICA;
}
/*
HRESULT STDMETHODCALLTYPE
CClassAccess::GetUpgrades (
ULONG cClasses,
CLSID *pClassList, // CLSIDs Installed
CSPLATFORM Platform,
LCID Locale,
PACKAGEINFOLIST *pPackageInfoList)
{
//
// Assume that this method is called in the security context
// of the user process. Hence there is no need to impersonate.
//
PCLASSCONTAINER *pStoreList;
DWORD cStores=0;
HRESULT hr;
ULONG i;
IClassRefresh *pIClassRefresh = NULL;
PACKAGEINFOLIST PackageInfoList;
IClassAccess *pICA = NULL;
pPackageInfoList->cPackInfo = NULL;
pPackageInfoList->pPackageInfo = NULL;
//
// Get the list of Class Stores for this user
//
hr = GetUserClassStores(
&pStoreList,
&cStores);
if (!SUCCEEDED(hr))
{
return hr;
}
RpcImpersonateClient( NULL );
for (i=0; i < cStores; i++)
{
if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i)))
continue;
//
// Call method on this store
//
if (FAILED(pICA->QueryInterface(IID_IClassRefresh,
(void **)&pIClassRefresh)))
continue;
hr = pIClassRefresh->GetUpgrades(
cClasses,
pClassList,
Platform,
Locale,
&PackageInfoList);
pIClassRefresh->Release();
pIClassRefresh = NULL;
if (hr == E_INVALIDARG)
{
RevertToSelf();
return hr;
}
if (SUCCEEDED(hr) && (PackageInfoList.cPackInfo > 0))
{
//
// Add to the existing list of upgrades
//
UINT cCount = pPackageInfoList->cPackInfo;
if (cCount)
{
PACKAGEINFO *pInfo = pPackageInfoList->pPackageInfo;
pPackageInfoList->pPackageInfo =
(PACKAGEINFO *) CoTaskMemAlloc
((cCount + PackageInfoList.cPackInfo) * sizeof(PACKAGEINFO));
memcpy (pPackageInfoList->pPackageInfo,
pInfo,
cCount * sizeof(PACKAGEINFO));
memcpy ((pPackageInfoList->pPackageInfo)+cCount,
PackageInfoList.pPackageInfo,
PackageInfoList.cPackInfo * sizeof(PACKAGEINFO));
CoTaskMemFree (pInfo);
pPackageInfoList->cPackInfo += PackageInfoList.cPackInfo;
}
else
{
pPackageInfoList->cPackInfo = PackageInfoList.cPackInfo;
pPackageInfoList->pPackageInfo = PackageInfoList.pPackageInfo;
}
}
}
RevertToSelf();
return S_OK;
}
HRESULT STDMETHODCALLTYPE
CClassAccess::CommitUpgrades ()
{
//
// Assume that this method is called in the security context
// of the user process. Hence there is no need to impersonate.
//
PCLASSCONTAINER *pStoreList;
DWORD cStores=0;
HRESULT hr;
ULONG i;
IClassRefresh *pIClassRefresh;
IClassAccess *pICA = NULL;
//
// Get the list of Class Stores for this user
//
hr = GetUserClassStores(
&pStoreList,
&cStores);
if (!SUCCEEDED(hr))
{
return hr;
}
RpcImpersonateClient( NULL );
for (i=0; i < cStores; i++)
{
if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i)))
continue;
//
// Call method on this store
//
if (FAILED(pICA->QueryInterface(IID_IClassRefresh,
(void **)&pIClassRefresh)))
continue;
hr = pIClassRefresh->CommitUpgrades();
pIClassRefresh->Release();
}
RevertToSelf();
return hr;
}
*/
HRESULT STDMETHODCALLTYPE CClassAccess::EnumPackages(
LPOLESTR pszPackageName,
GUID *pCategory,
ULONGLONG *pLastUsn,
DWORD dwAppFlags, // AppType options
IEnumPackage **ppIEnumPackage)
{
//
// Get the list of Class Stores for this user
//
PCLASSCONTAINER *pStoreList;
DWORD cStores=0;
HRESULT hr;
ULONG i;
IEnumPackage *Enum[MAXCLASSSTORES];
ULONG cEnum = 0;
CMergedEnumPackage *EnumMerged;
IClassAccess *pICA = NULL;
//
// Get the list of Class Stores for this user
//
hr = GetUserClassStores(
&pStoreList,
&cStores);
*ppIEnumPackage = NULL;
if (!SUCCEEDED(hr))
{
return hr;
}
if (cStores == 0)
{
return CS_E_NO_CLASSSTORE;
}
//RpcImpersonateClient( NULL );
for (i=0; i < cStores; i++)
{
if (!(pICA = GetNextValidClassStore(pStoreList, cStores, &i)))
continue;
//
// Call method on this store
//
hr = pICA->EnumPackages (pszPackageName,
pCategory,
pLastUsn,
dwAppFlags,
&(Enum[cEnum]));
if (hr == E_INVALIDARG)
{
//RevertToSelf();
return hr;
}
if (SUCCEEDED(hr))
cEnum++;
}
EnumMerged = new CMergedEnumPackage;
hr = EnumMerged->Initialize(Enum, cEnum);
if (FAILED(hr))
{
for (i = 0; i < cEnum; i++)
Enum[i]->Release();
delete EnumMerged;
}
else
{
hr = EnumMerged->QueryInterface(IID_IEnumPackage, (void **)ppIEnumPackage);
if (FAILED(hr))
delete EnumMerged;
}
//RevertToSelf();
return hr;
}
//--------------------------------------------------------------
CMergedEnumPackage::CMergedEnumPackage()
{
m_pcsEnum = NULL;
m_cEnum = 0;
m_csnum = 0;
m_dwRefCount = 0;
}
CMergedEnumPackage::~CMergedEnumPackage()
{
ULONG i;
for (i = 0; i < m_cEnum; i++)
m_pcsEnum[i]->Release();
CoTaskMemFree(m_pcsEnum);
}
HRESULT __stdcall CMergedEnumPackage::QueryInterface(REFIID riid,
void * * ppObject)
{
*ppObject = NULL; //gd
if ((riid==IID_IUnknown) || (riid==IID_IEnumPackage))
{
*ppObject=(IEnumPackage *) this;
}
else
{
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG __stdcall CMergedEnumPackage::AddRef()
{
InterlockedIncrement((long*) &m_dwRefCount);
return m_dwRefCount;
}
ULONG __stdcall CMergedEnumPackage::Release()
{
ULONG dwRefCount;
if ((dwRefCount = InterlockedDecrement((long*) &m_dwRefCount))==0)
{
delete this;
return 0;
}
return dwRefCount;
}
HRESULT __stdcall CMergedEnumPackage::Next(
ULONG celt,
PACKAGEDISPINFO *rgelt,
ULONG *pceltFetched)
{
ULONG count=0, total = 0;
HRESULT hr = S_OK;
//RpcImpersonateClient( NULL );
for (; m_csnum < m_cEnum; m_csnum++)
{
count = 0;
hr = m_pcsEnum[m_csnum]->Next(celt, rgelt+total, &count);
if (hr == E_INVALIDARG)
{
//RevertToSelf();
return hr;
}
total += count;
celt -= count;
if (!celt)
break;
}
if (pceltFetched)
*pceltFetched = total;
//RevertToSelf();
if (!celt)
return S_OK;
return S_FALSE;
}
HRESULT __stdcall CMergedEnumPackage::Skip(
ULONG celt)
{
PACKAGEDISPINFO *pPackageInfo = NULL;
HRESULT hr = S_OK;
ULONG cgot = 0, i;
pPackageInfo = (PACKAGEDISPINFO *)CoTaskMemAlloc(sizeof(PACKAGEDISPINFO)*celt);
hr = Next(celt, pPackageInfo, &cgot);
for (i = 0; i < cgot; i++)
ReleasePackageInfo(pPackageInfo+i);
CoTaskMemFree(pPackageInfo);
return hr;
}
HRESULT __stdcall CMergedEnumPackage::Reset()
{
ULONG i;
//RpcImpersonateClient( NULL );
for (i = 0; ((i <= m_csnum) && (i < m_cEnum)); i++)
m_pcsEnum[i]->Reset(); // ignoring all error values
m_csnum = 0;
//RevertToSelf();
return S_OK;
}
HRESULT __stdcall CMergedEnumPackage::Clone(IEnumPackage **ppIEnumPackage)
{
ULONG i;
CMergedEnumPackage *pClone;
IEnumPackage *pcsEnumCloned[MAXCLASSSTORES];
//RpcImpersonateClient( NULL );
pClone = new CMergedEnumPackage;
for ( i = 0; i < m_cEnum; i++)
m_pcsEnum[i]->Clone(&(pcsEnumCloned[i]));
pClone->m_csnum = m_csnum;
pClone->Initialize(pcsEnumCloned, m_cEnum);
*ppIEnumPackage = (IEnumPackage *)pClone;
pClone->AddRef();
//RevertToSelf();
return S_OK;
}
HRESULT CMergedEnumPackage::Initialize(IEnumPackage **pcsEnum, ULONG cEnum)
{
ULONG i;
m_csnum = 0;
m_pcsEnum = (IEnumPackage **)CoTaskMemAlloc(sizeof(IEnumPackage *) * cEnum);
if (!m_pcsEnum)
return E_OUTOFMEMORY;
for (i = 0; i < cEnum; i++)
m_pcsEnum[i] = pcsEnum[i];
m_cEnum = cEnum;
return S_OK;
}