Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

323 lines
8.3 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000.
//
// File: ShtOle.hxx
//
// Contents: 'Short' OLE -- Minimal persistent handler implementation
//
// Classes: CShtOle
//
// History: 01-Feb-96 KyleP Added header
// 31-Jan-96 KyleP Added support for embeddings
//
//----------------------------------------------------------------------------
#pragma once
//+---------------------------------------------------------------------------
//
// Class: CShtOle
//
// Purpose: 'Short-OLE' -- Minimal persistent handler implementation
//
// History: 01-Feb-96 KyleP Added header
// 31-Jan-96 KyleP Added support for embeddings
// 18-Dec-97 KLam Added ability to flush idle filters
//
//----------------------------------------------------------------------------
class CShtOle
{
public:
CShtOle()
: _pclassList( 0 ),
_pserverList( 0 ),
_ulFilterIdleTimeout( 0xffffffff ),
_mutex( FALSE ),
_fInit( FALSE )
{
}
void Init()
{
_mutex.Init();
_fInit = TRUE;
}
~CShtOle() { Shutdown(); }
void Shutdown();
void FlushIdle (); // Ask idle classes and servers to unload
SCODE Bind( WCHAR const * pwszPath,
REFIID riid,
IUnknown * pUnkOuter,
void ** ppvObject,
BOOL fFreeThreadedOnly = FALSE );
SCODE Bind( WCHAR const * pwszPath,
GUID const & classid,
REFIID riid,
IUnknown * pUnkOuter,
void ** ppvObject,
BOOL fFreeThreadedOnly = FALSE );
SCODE Bind( IStorage * pStg,
REFIID riid,
IUnknown * pUnkOuter,
void ** ppvObject,
BOOL fFreeThreadedOnly = FALSE );
SCODE Bind( IStream * pStm,
REFIID riid,
IUnknown * pUnkOuter,
void ** ppvObject,
BOOL fFreeThreadedOnly = FALSE );
SCODE NewInstance( GUID const & classid, REFIID riid, void ** ppvObject );
static void StringToGuid( WCHAR * pwcsGuid, GUID & guid );
static void GuidToString( GUID const & guid, WCHAR * pwcsGuid );
private:
//
// InProcServer node
//
class CServerNode
{
public:
CServerNode( GUID guid, CServerNode * pNext )
: _guid( guid ),
_pNext( pNext ),
_pCF( 0 ),
_hModule( 0 ),
_pfnCanUnloadNow ( 0 )
{
_cLastUsed = GetTickCount ();
}
~CServerNode()
{
if( _pCF )
_pCF->Release();
if ( 0 != _hModule )
FreeLibrary( _hModule );
}
SCODE CreateInstance( IUnknown * pUnkOuter,
REFIID riid,
void ** ppv );
//IClassFactory * GetCF() { return _pCF; }
BOOL IsMatch( GUID guid ) { return( guid == _guid ); }
BOOL IsSingleThreaded() { return _fSingleThreaded; }
void SetSingleThreaded( BOOL fSingleThreaded )
{
_fSingleThreaded = fSingleThreaded;
}
void SetCF( IClassFactory * pCF ) { _pCF = pCF; }
void SetModule( HMODULE hmod );
//
// Link traversal
//
CServerNode * Next() { return _pNext; }
void Link( CServerNode * pNext ) { _pNext = pNext; }
//
// Usage
//
void Touch () { _cLastUsed = GetTickCount (); }
BOOL CanUnloadNow (DWORD cMaxIdle);
private:
CServerNode * _pNext;
GUID _guid;
IClassFactory * _pCF;
HMODULE _hModule;
BOOL _fSingleThreaded;
DWORD _cLastUsed;
LPFNCANUNLOADNOW _pfnCanUnloadNow;
};
CServerNode * FindServer( GUID const & classid, REFIID riid );
CServerNode * FindServerFromPHandler( GUID const & classid, REFIID riid );
//
// File class node
//
class CClassNode
{
public:
CClassNode( WCHAR const * pwcExt, CClassNode * pNext )
: _pNext( pNext ),
_pserver( 0 )
{
memset( &_classid, 0, sizeof(_classid) );
wcscpy( _wcExt, pwcExt );
_cLastUsed = GetTickCount ();
}
CClassNode( GUID const & classid, CClassNode * pNext )
: _pNext( pNext ),
_pserver( 0 )
{
memcpy( &_classid, &classid, sizeof(_classid) );
_wcExt[0] = 0;
_cLastUsed = GetTickCount ();
}
void SetClassId( GUID const & classid )
{
memcpy( &_classid, &classid, sizeof(_classid) );
}
#if 0
IClassFactory * GetCF()
{
if( _pserver )
return _pserver->GetCF();
else
return 0;
}
#endif
BOOL IsSingleThreaded()
{
if( _pserver )
return _pserver->IsSingleThreaded();
else
return FALSE;
}
BOOL IsMatch( WCHAR const * pext ) { return( _wcsicmp(pext, _wcExt) == 0 ); }
BOOL IsMatch( GUID const & classid ) { return( memcmp( &classid, &_classid, sizeof(classid) ) == 0 ); }
void SetServer( CServerNode * pserver ) { _pserver = pserver; }
//
// Link traversal
//
CClassNode * Next() { return _pNext; }
void Link( CClassNode * pNext ) { _pNext = pNext; }
//
// Usage
//
SCODE CreateInstance( IUnknown * pUnkOuter,
REFIID riid,
void ** ppv )
{
Touch();
if ( _pserver )
return _pserver->CreateInstance( pUnkOuter, riid, ppv );
else
return E_FAIL;
}
void Touch ()
{
_cLastUsed = GetTickCount ();
// If we are touching the class then we are touching its server
if ( _pserver )
_pserver->Touch ();
}
BOOL CanUnloadNow (DWORD cMaxIdle)
{
return (GetTickCount() - _cLastUsed > cMaxIdle);
}
enum EExtLen
{
ccExtLen = 10
};
private:
CClassNode * _pNext;
WCHAR _wcExt[ccExtLen + 1];
GUID _classid;
CServerNode * _pserver;
DWORD _cLastUsed;
};
//
// Private methods
//
CClassNode * InsertByClass( GUID const & classid, CClassNode * pnode );
CServerNode * InsertByClass( GUID const & classid, CServerNode * pnode );
ULONG GetFilterIdleTimeout ();
template<class T> T FlushList ( T ptNodeList )
{
if ( 0xffffffff == _ulFilterIdleTimeout )
_ulFilterIdleTimeout = GetFilterIdleTimeout();
T ptnHead = ptNodeList;
T ptnCurrent = ptnHead;
T ptnPrev = 0;
while ( ptnCurrent )
{
if ( ptnCurrent->CanUnloadNow ( _ulFilterIdleTimeout ) )
{
if ( ptnPrev )
{
// Removing a node from the middle of the list
// or end of the list
ptnPrev->Link( ptnCurrent->Next() );
delete ptnCurrent;
ptnCurrent = ptnPrev->Next ();
}
else
{
// Removing a node from the head of the list
ptnHead = ptnCurrent->Next();
delete ptnCurrent;
ptnCurrent = ptnHead;
}
}
else
{
ptnPrev = ptnCurrent;
ptnCurrent = ptnCurrent->Next();
}
}
return ptnHead;
}
CClassNode * _pclassList;
CServerNode * _pserverList;
ULONG _ulFilterIdleTimeout;
BOOL _fInit;
CMutexSem _mutex;
};