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

414 lines
11 KiB
C++

//+------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1997
//
// File: cclsto.cxx
//
// Contents: Class Factory and IUnknown methods for CAppContainer
//
// Author: DebiM
//
//-------------------------------------------------------------------------
#include "cstore.hxx"
//
// Constructor for App Container Class factory
//
unsigned long gulcappcon = 0;
extern CRITICAL_SECTION ClassStoreBindList;
ClassStoreCacheType ClassStoreCache;
CAppContainerCF::CAppContainerCF()
{
m_uRefs = 1;
InterlockedIncrement((long *) &gulcappcon );
ClassStoreCache.sz = 0;
ClassStoreCache.start = 0;
ClassStoreCache.end = 0;
}
void ReleaseBindings(BindingsType *pbd)
{
CSDBGPrint((L"Cleaning up entry in Cache. %s", pbd->szStorePath));
if (pbd->pIClassAccess)
{
(pbd->pIClassAccess)->Release();
}
CoTaskMemFree(pbd->Sid);
CoTaskMemFree(pbd->szStorePath);
}
//
// Destructor
//
CAppContainerCF::~CAppContainerCF()
{
//
// Cleanup the cache
//
for (UINT i=ClassStoreCache.start; i != ClassStoreCache.end;
i = (i+1)%(MAXCLASSSTORES))
{
ReleaseBindings(ClassStoreCache.Bindings+i);
}
InterlockedDecrement((long *) &gulcappcon );
}
HRESULT __stdcall CAppContainerCF::QueryInterface(REFIID riid, void * * ppvObject)
{
IUnknown *pUnkTemp = NULL;
SCODE sc = S_OK;
if( IsEqualIID( IID_IUnknown, riid ) )
{
pUnkTemp = (IUnknown *)(ITypeLib *)this;
}
else if( IsEqualIID( IID_IClassFactory, riid ) )
{
pUnkTemp = (IUnknown *)(IClassFactory *)this;
}
else if( IsEqualIID( IID_IParseDisplayName, riid ) )
{
pUnkTemp = (IUnknown *)(IParseDisplayName *)this;
}
else
{
sc = (E_NOINTERFACE);
}
if((pUnkTemp != NULL) && (SUCCEEDED(sc)))
{
*ppvObject = (void * )pUnkTemp;
pUnkTemp->AddRef();
}
return(sc);
}
ULONG __stdcall CAppContainerCF::AddRef()
{
InterlockedIncrement(( long * )&m_uRefs );
return m_uRefs;
}
ULONG __stdcall CAppContainerCF::Release()
{
unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs);
unsigned long cRef = m_uRefs;
// 0 is the only valid value to check
if (uTmp == 0)
{
delete this;
}
return(cRef);
}
//
// IClassFactory Overide
//
HRESULT __stdcall CAppContainerCF::CreateInstance(IUnknown * pUnkOuter, REFIID riid,
void ** ppvObject)
{
CAppContainer * pIUnk = NULL;
SCODE sc = S_OK;
if( pUnkOuter == NULL )
{
if( (pIUnk = new CAppContainer()) != NULL)
{
sc = pIUnk->QueryInterface( riid , ppvObject );
if(FAILED(sc))
{
sc = E_UNEXPECTED;
}
pIUnk->Release();
}
else
sc = E_OUTOFMEMORY;
}
else
{
return E_INVALIDARG;
}
return (sc);
}
//---------------------------------------------------------------
//
// Function: CreateConnectedInstance
//
// Synopsis: Returns IClassAccess Pointer, given a class store
// path.
//
// Arguments:
// [in]
// pszPath Class Store Path without the leading ADCS:
//
// pUserSid
// Sid under which the calling thread is running.
// fCache
// Boolean that decides whether to use a cached pointer or
// not.
// [out]
// ppvObject
// IClassAccess Interface pointer
//
// Returns:
// S_OK, E_NOINTERFACE, E_OUTOFMEMORY, CS_E_XXX
//
// if (fCache)
// Looks in the cache to see if we have already tried to bind to the same
// ClassStore Path under the same SID. If it finds it, then we just QI for
// IClassAccess and return. o/w create a new class store pointer and caches it.
// else
// Just binds to a new ClassStore and returns.
//----------------------------------------------------------------
HRESULT __stdcall
CAppContainerCF::CreateConnectedInstance(LPOLESTR pszPath, PSID pUserSid,
BOOL fCache, void ** ppvObject)
{
CAppContainer * pIUnk = NULL;
SCODE sc = S_OK;
HRESULT hr = S_OK;
BOOL fFound = FALSE;
if (fCache)
{
//
// Look in cache
//
EnterCriticalSection (&ClassStoreBindList);
for (UINT i=ClassStoreCache.start; i != ClassStoreCache.end;
i = (i+1)%(MAXCLASSSTORES))
{
// compare cached sids and Class Store path
if ((wcscmp(pszPath, ClassStoreCache.Bindings[i].szStorePath) == 0) &&
(EqualSid(pUserSid, ClassStoreCache.Bindings[i].Sid)))
{
//
// Found in cache
//
CSDBGPrint((L"Found %s in Cache.", pszPath));
fFound = TRUE;
if (ClassStoreCache.Bindings[i].pIClassAccess)
{
sc = (ClassStoreCache.Bindings[i].pIClassAccess)->
QueryInterface( IID_IClassAccess, ppvObject );
}
else
{
sc = ClassStoreCache.Bindings[i].Hr;
// return the same error code.
}
break;
}
}
LeaveCriticalSection (&ClassStoreBindList);
if (fFound)
return sc;
}
if ((pIUnk = new CAppContainer(pszPath, &sc)) != NULL)
{
if (SUCCEEDED(sc))
{
sc = pIUnk->QueryInterface( IID_IClassAccess, ppvObject );
if(FAILED(sc))
{
sc = E_UNEXPECTED;
}
}
else
CSDBGPrint((L"Connect to Store Failed. hr = 0x%x", sc));
pIUnk->Release();
}
else
sc = E_OUTOFMEMORY;
//
// Store the result in the cache
//
if (fCache)
{
//
// Should not cache situations out of network failures
// BUGBUG: For now we are only caching successes OR CS does not exist cases
//
if ((sc == S_OK) || (sc == CS_E_OBJECT_NOTFOUND))
{
EnterCriticalSection (&ClassStoreBindList);
for (UINT i=ClassStoreCache.start; i != ClassStoreCache.end;
i = (i+1)%(MAXCLASSSTORES))
{
if ((wcscmp(pszPath, ClassStoreCache.Bindings[i].szStorePath) == 0) &&
(EqualSid(pUserSid, ClassStoreCache.Bindings[i].Sid)))
{
//
// Found in cache after bind attempt
//
CSDBGPrint((L"Found in Cache after binding !!!."));
//
// If we already got an existing object, release the one we grabbed
// above
//
if (*ppvObject) {
((IClassAccess *)(*ppvObject))->Release();
*ppvObject = NULL;
} else {
ASSERT(CS_E_OBJECT_NOTFOUND == sc);
}
//
// Now we can get the object from the cache to satisfy
// the caller's request
//
if (ClassStoreCache.Bindings[i].pIClassAccess)
{
sc = (ClassStoreCache.Bindings[i].pIClassAccess)->
QueryInterface( IID_IClassAccess, ppvObject );
}
else
{
sc = ClassStoreCache.Bindings[i].Hr;
// return the same error code.
}
}
}
if (i == ClassStoreCache.end)
{
if (ClassStoreCache.sz == (MAXCLASSSTORES-1))
{
ReleaseBindings(ClassStoreCache.Bindings+ClassStoreCache.start);
ClassStoreCache.start = (ClassStoreCache.start+1)%MAXCLASSSTORES;
ClassStoreCache.sz--;
}
// allocate space for the guid and the Class store path.
ClassStoreCache.Bindings[i].szStorePath =
(LPOLESTR) CoTaskMemAlloc (sizeof(WCHAR) * (wcslen (pszPath) + 1));
UINT dwBytesRequired = GetLengthSid(pUserSid);
ClassStoreCache.Bindings[i].Sid = CoTaskMemAlloc(dwBytesRequired);
// if memory was allocated.
if ((ClassStoreCache.Bindings[i].szStorePath) &&
(ClassStoreCache.Bindings[i].Sid))
{
// copy the class store path.
wcscpy (ClassStoreCache.Bindings[i].szStorePath, pszPath);
ClassStoreCache.Bindings[i].pIClassAccess = NULL;
// get the IClassAccess pointer and cache it.
if (sc == S_OK)
{
((IClassAccess *)(*ppvObject))->QueryInterface( IID_IClassAccess,
(void **)&ClassStoreCache.Bindings[i].pIClassAccess);
}
ClassStoreCache.Bindings[i].Hr = sc;
// copy the SIDs
CopySid(dwBytesRequired, ClassStoreCache.Bindings[i].Sid, pUserSid);
ClassStoreCache.sz++;
ClassStoreCache.end = (ClassStoreCache.end + 1)% MAXCLASSSTORES;
}
}
LeaveCriticalSection (&ClassStoreBindList);
}
}
return (sc);
}
HRESULT __stdcall CAppContainerCF::LockServer(BOOL fLock)
{
if(fLock)
{ InterlockedIncrement((long *) &gulcappcon ); }
else
{ InterlockedDecrement((long *) &gulcappcon ); }
return(S_OK);
}
//
// IUnknown methods for CAppContainer
//
//
HRESULT __stdcall CAppContainer::QueryInterface(REFIID riid, void * * ppvObject)
{
IUnknown *pUnkTemp = NULL;
SCODE sc = S_OK;
if( IsEqualIID( IID_IUnknown, riid ) )
{
pUnkTemp = (IUnknown *)(IClassAccess *)this;
}
else if( IsEqualIID( IID_IClassAccess, riid ) )
{
pUnkTemp = (IUnknown *)(IClassAccess *)this;
}
/*
else if( IsEqualIID( IID_IClassRefresh, riid ) )
{
pUnkTemp = (IUnknown *)(IClassRefresh *)this;
}
else if( IsEqualIID( IID_ICatInformation, riid ) )
{
pUnkTemp = (IUnknown *)(ICatInformation *)this;
}
*/
else
{
sc = (E_NOINTERFACE);
}
if((pUnkTemp != NULL) && (SUCCEEDED(sc)))
{
*ppvObject = (void * )pUnkTemp;
pUnkTemp->AddRef();
}
return(sc);
}
ULONG __stdcall CAppContainer::AddRef()
{
InterlockedIncrement(( long * )&m_uRefs );
return m_uRefs;
}
ULONG __stdcall CAppContainer::Release()
{
unsigned long uTmp = InterlockedDecrement((long *)&m_uRefs);
unsigned long cRef = m_uRefs;
if (uTmp == 0)
{
delete this;
}
return(cRef);
}