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