/*++ Copyright (c) 1994 Microsoft Corporation All rights reserved. Module Name: spcompat.hxx Abstract: porting the spool library code into printui Author: Lazar Ivanov (LazarI) Jul-05-2000 Revision History: --*/ #ifndef _SPLLIB_HXX #define _SPLLIB_HXX #if DBG #define _INLINE #else #define _INLINE inline #endif /////////////////////////////////////////////////// // @@file@@ debug.hxx /////////////////////////////////////////////////// /******************************************************************** C++ specific debug functionality. ********************************************************************/ #ifdef __cplusplus #if DBG /******************************************************************** Automatic status logging. Use TStatus instead of DWORD: DWORD dwStatus; -> TStatus Status; dwStatus = ERROR_SUCCESS -> Status DBGNOCHK = ERROR_SUCCESS; dwStatus = xxx; -> Status DBGCHK = xxx; if( dwStatus ){ -> if( Status != 0 ){ Anytime Status is set, the DBGCHK macro must be added before the '=.' If the variable must be set to a failure value at compilte time and logging is therefore not needed, then the DBGNOCHK macro should be used. There are different parameters to instantiation. Alternate debug level can be specified, and also 3 "benign" errors that can be ignored. TStatus Status( DBG_ERROR, ERROR_ACCESS_DENIED, ERROR_FOO ); ********************************************************************/ #define DBGCHK .pSetInfo( MODULE_DEBUG, __LINE__, __FILE__, MODULE ) #define DBGNOCHK .pNoChk() class TStatusBase { protected: DWORD _dwStatus; DWORD _dwStatusSafe1; DWORD _dwStatusSafe2; DWORD _dwStatusSafe3; UINT _uDbgLevel; UINT _uDbg; UINT _uLine; LPCSTR _pszFileA; LPCSTR _pszModuleA; public: TStatusBase( UINT uDbgLevel, DWORD dwStatusSafe1, DWORD dwStatusSafe2, DWORD dwStatusSafe3 ) : _dwStatus( 0xdeacface ), _uDbgLevel( uDbgLevel ), _dwStatusSafe1( dwStatusSafe1 ), _dwStatusSafe2( dwStatusSafe2 ), _dwStatusSafe3( dwStatusSafe3 ) { } TStatusBase& pSetInfo( UINT uDbg, UINT uLine, LPCSTR pszFileA, LPCSTR pszModuleA ); TStatusBase& pNoChk( VOID ); DWORD operator=( DWORD dwStatus ); }; class TStatus : public TStatusBase { private: // // Don't let clients use operator= without going through the // base class (i.e., using DBGCHK ). // // If you get an error trying to access private member function '=,' // you are trying to set the status without using the DBGCHK macro. // // This is needed to update the line and file, which must be done // at the macro level (not inline C++ function) since __LINE__ and // __FILE__ are handled by the preprocessor. // DWORD operator=( DWORD dwStatus ); public: TStatus( UINT uDbgLevel = DBG_WARN, DWORD dwStatusSafe1 = (DWORD)-1, DWORD dwStatusSafe2 = (DWORD)-1, DWORD dwStatusSafe3 = (DWORD)-1 ) : TStatusBase( uDbgLevel, dwStatusSafe1, dwStatusSafe2, dwStatusSafe3 ) { } DWORD dwGetStatus( VOID ); operator DWORD() { return dwGetStatus(); } }; /******************************************************************** Same thing, but for HRESULT status. ********************************************************************/ class TStatusHBase { protected: HRESULT _hrStatus; HRESULT _hrStatusSafe1; HRESULT _hrStatusSafe2; HRESULT _hrStatusSafe3; UINT _uDbgLevel; UINT _uDbg; UINT _uLine; LPCSTR _pszFileA; LPCSTR _pszModuleA; public: TStatusHBase( UINT uDbgLevel = DBG_WARN, HRESULT hrStatusSafe1 = S_FALSE, HRESULT hrStatusSafe2 = S_FALSE, HRESULT hrStatusSafe3 = S_FALSE ) : _hrStatus( 0xdeacface ), _uDbgLevel( uDbgLevel ), _hrStatusSafe1( hrStatusSafe1 ), _hrStatusSafe2( hrStatusSafe2 ), _hrStatusSafe3( hrStatusSafe3 ) { } TStatusHBase& pSetInfo( UINT uDbg, UINT uLine, LPCSTR pszFileA, LPCSTR pszModuleA ); TStatusHBase& pNoChk( VOID ); HRESULT operator=( HRESULT hrStatus ); }; class TStatusH : public TStatusHBase { private: // // Don't let clients use operator= without going through the // base class (i.e., using DBGCHK ). // // If you get an error trying to access private member function '=,' // you are trying to set the status without using the DBGCHK macro. // // This is needed to update the line and file, which must be done // at the macro level (not inline C++ function) since __LINE__ and // __FILE__ are handled by the preprocessor. // HRESULT operator=( HRESULT hrStatus ); public: TStatusH( UINT uDbgLevel = DBG_WARN, HRESULT hrStatusSafe1 = S_FALSE, HRESULT hrStatusSafe2 = S_FALSE, HRESULT hrStatusSafe3 = S_FALSE ) : TStatusHBase( uDbgLevel, hrStatusSafe1, hrStatusSafe2, hrStatusSafe3 ) { } HRESULT hrGetStatus( VOID ); operator HRESULT() { return hrGetStatus(); } }; /******************************************************************** Same thing, but for BOOL status. ********************************************************************/ class TStatusBBase { protected: BOOL _bStatus; DWORD _dwStatusSafe1; DWORD _dwStatusSafe2; DWORD _dwStatusSafe3; UINT _uDbgLevel; UINT _uDbg; UINT _uLine; LPCSTR _pszFileA; LPCSTR _pszModuleA; public: TStatusBBase( UINT uDbgLevel, DWORD dwStatusSafe1, DWORD dwStatusSafe2, DWORD dwStatusSafe3 ) : _bStatus( 0xabababab ), _uDbgLevel( uDbgLevel ), _dwStatusSafe1( dwStatusSafe1 ), _dwStatusSafe2( dwStatusSafe2 ), _dwStatusSafe3( dwStatusSafe3 ) { } TStatusBBase& pSetInfo( UINT uDbg, UINT uLine, LPCSTR pszFileA, LPCSTR pszModuleA ); TStatusBBase& pNoChk( VOID ); BOOL operator=( BOOL bStatus ); }; class TStatusB : public TStatusBBase { private: // // Don't let clients use operator= without going through the // base class (i.e., using DBGCHK ). // // If you get an error trying to access private member function '=,' // you are trying to set the status without using the DBGCHK macro. // // This is needed to update the line and file, which must be done // at the macro level (not inline C++ function) since __LINE__ and // __FILE__ are handled by the preprocessor. // BOOL operator=( BOOL bStatus ); public: TStatusB( UINT uDbgLevel = DBG_WARN, DWORD dwStatusSafe1 = (DWORD)-1, DWORD dwStatusSafe2 = (DWORD)-1, DWORD dwStatusSafe3 = (DWORD)-1 ) : TStatusBBase( uDbgLevel, dwStatusSafe1, dwStatusSafe2, dwStatusSafe3 ) { } BOOL bGetStatus( VOID ); operator BOOL() { return bGetStatus(); } }; #else #define DBGCHK #define DBGNOCHK class TStatus { private: DWORD _dwStatus; public: TStatus( UINT uDbgLevel = 0, DWORD dwStatusSafe1 = 0, DWORD dwStatusSafe2 = 0, DWORD dwStatusSafe3 = 0 ) { } DWORD operator=( DWORD dwStatus ) { return _dwStatus = dwStatus; } operator DWORD() { return _dwStatus; } }; class TStatusB { private: BOOL _bStatus; public: TStatusB( UINT uDbgLevel = 0, DWORD dwStatusSafe1 = 0, DWORD dwStatusSafe2 = 0, DWORD dwStatusSafe3 = 0 ) { } BOOL operator=( BOOL bStatus ) { return _bStatus = bStatus; } operator BOOL() { return _bStatus; } }; class TStatusH { private: HRESULT _hrStatus; public: TStatusH( UINT uDbgLevel = 0, HRESULT hrStatusSafe1 = 0, HRESULT hrStatusSafe2 = 0, HRESULT hrStatusSafe3 = 0 ) { } HRESULT operator=( HRESULT hrStatus ) { return _hrStatus = hrStatus; } operator HRESULT() { return _hrStatus; } }; #endif // #if DBG #endif // #ifdef __cplusplus /////////////////////////////////////////////////// // @@file@@ common.hxx /////////////////////////////////////////////////// // // This reverses a DWORD so that the bytes can be easily read // as characters ('prnt' can be read from debugger forward). // #define BYTE_SWAP_DWORD( val ) \ ( (val & 0xff) << 24 | \ (val & 0xff00) << 8 | \ (val & 0xff0000) >> 8 | \ (val & 0xff000000) >> 24 ) #define COUNTOF(x) (sizeof(x)/sizeof(*x)) #define BITCOUNTOF(x) (sizeof(x)*8) #define COUNT2BYTES(x) ((x)*sizeof(TCHAR)) #define OFFSETOF(type, id) ((DWORD)(ULONG_PTR)(&(((type*)0)->id))) #define OFFSETOF_BASE(type, baseclass) ((DWORD)(ULONG_PTR)((baseclass*)((type*)0x10))-0x10) #define ERRORP(Status) (Status != ERROR_SUCCESS) #define SUCCESSP(Status) (Status == ERROR_SUCCESS) // // COUNT and COUNT BYTES // typedef UINT COUNT, *PCOUNT; typedef UINT COUNTB, *PCOUNTB; typedef DWORD STATUS; // // Conversion between PPM (Page per minute), LPM (Line per minute) // and CPS (Character per second) // #define CPS2PPM(x) ((x)/48) #define LPM2PPM(x) ((x)/48) // // C++ specific functionality. // #ifdef __cplusplus const DWORD kStrMax = MAX_PATH; #define SAFE_NEW #define DBG_SAFE_NEW #define SIGNATURE( sig ) \ public: \ class TSignature { \ public: \ DWORD _Signature; \ TSignature() : _Signature( BYTE_SWAP_DWORD( sig )) { } \ }; \ TSignature _Signature; \ \ BOOL bSigCheck() const \ { return _Signature._Signature == BYTE_SWAP_DWORD( sig ); } \ private: #define ALWAYS_VALID \ public: \ BOOL bValid() const \ { return TRUE; } \ private: #define VAR(type,var) \ inline type& var() \ { return _##var; } \ inline type const & var() const \ { return _##var; } \ type _##var #define SVAR(type,var) \ static inline type& var() \ { return _##var; } \ static type _##var inline DWORD DWordAlign( DWORD dw ) { return ((dw)+3)&~3; } inline PVOID DWordAlignDown( PVOID pv ) { return (PVOID)((ULONG_PTR)pv&~3); } inline PVOID WordAlignDown( PVOID pv ) { return (PVOID)((ULONG_PTR)pv&~1); } inline DWORD Align( DWORD dw ) { return (dw+7)&~7; } #endif // __cplusplus /////////////////////////////////////////////////// // @@file@@ string.hxx /////////////////////////////////////////////////// class TString { SIGNATURE( 'strg' ) SAFE_NEW public: // // For the default constructor, we initialize _pszString to a // global gszState[kValid] string. This allows them to work correctly, // but prevents the extra memory allocation. // // Note: if this class is extended (with reference counting // or "smart" reallocations), this strategy may break. // TString( VOID ); TString( IN LPCTSTR psz ); ~TString( VOID ); TString( IN const TString &String ); BOOL bEmpty( VOID ) const; BOOL bValid( VOID ) const; BOOL bUpdate( IN LPCTSTR pszNew ); BOOL bLoadString( IN HINSTANCE hInst, IN UINT uID ); UINT TString:: uLen( VOID ) const; BOOL TString:: bCat( IN LPCTSTR psz ); BOOL TString:: bLimitBuffer( IN UINT nMaxLength ); BOOL TString:: bDeleteChar( IN UINT nPos ); BOOL TString:: bReplaceAll( IN TCHAR chFrom, IN TCHAR chTo ); VOID TString:: vToUpper( VOID ); VOID TString:: vToLower( VOID ); // // Caution: See function header for usage and side effects. // BOOL TString:: bFormat( IN LPCTSTR pszFmt, IN ... ); // // Caution: See function header for usage and side effects. // BOOL TString:: bvFormat( IN LPCTSTR pszFmt, IN va_list avlist ); // // Operator overloads. // operator LPCTSTR( VOID ) const { return _pszString; } friend INT operator==(const TString& String, LPCTSTR& psz) { return !lstrcmp(String._pszString, psz); } friend INT operator==(LPCTSTR& psz, const TString& String) { return !lstrcmp(psz, String._pszString); } friend INT operator==(const TString& String1, const TString& String2) { return !lstrcmp(String1._pszString, String2._pszString); } friend INT operator!=(const TString& String, LPCTSTR& psz) { return lstrcmp(String._pszString, psz) != 0; } friend INT operator!=(LPCTSTR& psz, const TString& String) { return lstrcmp(psz, String._pszString) != 0; } friend INT operator!=(const TString& String1, const TString& String2) { return lstrcmp(String1._pszString, String2._pszString) != 0; } protected: // // Not defined; used bUpdate since this forces clients to // check whether the assignment succeeded (it may fail due // to lack of memory, etc.). // TString& operator=( LPCTSTR psz ); TString& operator=(const TString& String); private: enum StringStatus { kValid = 0, kInValid = 1, }; enum { kStrIncrement = 256, kStrMaxFormatSize = 1024 * 100, }; LPTSTR _pszString; static TCHAR gszNullState[2]; LPTSTR TString:: vsntprintf( IN LPCTSTR szFmt, IN va_list pArgs ); VOID TString:: vFree( IN LPTSTR pszString ); }; /////////////////////////////////////////////////// // @@file@@ state.hxx /////////////////////////////////////////////////// typedef DWORD STATEVAR; /******************************************************************** State object (DWORD) for bitfields. ********************************************************************/ class TState { SIGNATURE( 'stat' ) ALWAYS_VALID SAFE_NEW public: #if DBG TState( VOID ); TState( STATEVAR StateVar ); ~TState( VOID ); STATEVAR operator|=( STATEVAR StateVarOn ); STATEVAR operator&=( STATEVAR StateVarMask ); STATEVAR operator|=( INT iStateVarOn ) { return operator|=( (STATEVAR)iStateVarOn ); } STATEVAR operator&=( INT iStateVarMask ) { return operator&=( (STATEVAR)iStateVarMask ); } #else TState(VOID) : _StateVar(0) { } TState(STATEVAR StateVar) : _StateVar( StateVar ) { } ~TState(VOID) { } STATEVAR operator|=( STATEVAR StateVarOn ) { return _StateVar |= StateVarOn; } STATEVAR operator&=( STATEVAR StateVarMask ) { return _StateVar &= StateVarMask; } STATEVAR operator|=( INT iStateVarOn ) { return operator|=( (STATEVAR)iStateVarOn ); } STATEVAR operator&=( INT iStateVarMask ) { return operator&=( (STATEVAR)iStateVarMask ); } #endif BOOL bBit( STATEVAR StateVarBit ) { return _StateVar & StateVarBit ? TRUE : FALSE; } STATEVAR operator&( TState& State ) { return _StateVar & State._StateVar; } STATEVAR operator=( STATEVAR StateVarNew ) { return _StateVar = StateVarNew; } TState& operator=( const TState& StateNew ) { _StateVar = StateNew._StateVar; return *this; } operator STATEVAR() const { return _StateVar; } private: STATEVAR _StateVar; #if DBG virtual BOOL bValidateState() const { return TRUE; } virtual BOOL bValidateSet(STATEVAR StateVarOn) const { UNREFERENCED_PARAMETER( StateVarOn ); return TRUE; } virtual BOOL bValidateMask(STATEVAR StateVarMask) const { UNREFERENCED_PARAMETER( StateVarMask ); return TRUE; } #endif }; class VRef { SAFE_NEW public: virtual ~VRef() { } // // Virtuals that must be overwritten by the reference classes. // virtual VOID vIncRef() = 0; virtual LONG cDecRef() = 0; virtual VOID vDecRefDelete() = 0; protected: // // Clients of the reference class should override this class // to perform cleanup. Generally clients will implement vRefZeroed // to delete themselves. // virtual VOID vRefZeroed() = 0; }; /************************************************************ MRefQuick: quick ref counter, no sync done. ************************************************************/ class MRefQuick : public VRef { SIGNATURE( 'refq' ) ALWAYS_VALID protected: VAR( LONG, cRef ); public: #if DBG MRefQuick( VOID ) : _cRef( 0 ) { } ~MRefQuick( VOID ) { SPLASSERT( !_cRef ); } #else MRefQuick( VOID ) : _cRef( 0 ) { } #endif VOID vIncRef(); LONG cDecRef(); VOID vDecRefDelete(); }; /************************************************************ MRefCom: Refcount with interlocks ************************************************************/ class MRefCom : public VRef { SIGNATURE( 'refc' ) ALWAYS_VALID public: #if DBG MRefCom( VOID ) : _cRef( 0 ) { } ~MRefCom( VOID ) { SPLASSERT( !_cRef ); } #else MRefCom( VOID ) : _cRef( 0 ) { } #endif VOID vIncRef(); LONG cDecRef(); VOID vDecRefDelete(); protected: // // Must be LONG, not REFCOUNT for Interlocked* apis. // VAR( LONG, cRef ); virtual VOID vRefZeroed(); }; /************************************************************ TRefLock: used to lock a VRef. ************************************************************/ template class TRefLock { SIGNATURE( 'refl' ) ALWAYS_VALID SAFE_NEW public: TRefLock( VOID ) : _pRef( NULL ) { } TRefLock( T* pRef ) { _pRef = pRef; _pRef->vIncRef( ); } ~TRefLock( ) { if( _pRef ) _pRef->cDecRef( ); } VOID vAcquire( T* pRef ) { SPLASSERT( !_pRef ); _pRef = pRef; _pRef->vIncRef( ); } VOID vRelease( VOID ) { SPLASSERT( _pRef ); _pRef->cDecRef( ); _pRef = NULL; } T* pGet( VOID ) const { return _pRef; } T* operator->( VOID ) const { return _pRef; } private: // // Copying and assignement not defined. // TRefLock( const TRefLock & ); TRefLock & operator =(const TRefLock &); T *_pRef; }; /////////////////////////////////////////////////// // @@file@@ splutil.hxx /////////////////////////////////////////////////// // // Double linked list. DLINK must be the same as DLINKBASE, except // with differnt constructors. // typedef struct DLINK { DLINK() { FLink = NULL; } DLINK* FLink; DLINK* BLink; } *PDLINK; typedef struct DLINKBASE { DLINKBASE() { FLink = BLink = (PDLINK)this; } DLINK* FLink; DLINK* BLink; } *PDLINKBASE; class TIter { public: PDLINK _pdlink; PDLINK _pdlBase; BOOL bValid() { return _pdlink != _pdlBase; } VOID vNext() { _pdlink = _pdlink->FLink; } VOID vPrev() { _pdlink = _pdlink->BLink; } operator PDLINK() { return _pdlink; } }; /******************************************************************** // Forward reference. class TLink; TBase has two linked lists of TLink. class TBase { DLINK_BASE( TLink, Link, Link ); DLINK_BASE( TLink, Link2, Link2 ); }; class TLink { DLINK( TLink, Link ); DLINK( TLink, Link2 ); }; // // Append pLink to the end of the Link2 list. // pBase->Link2_vAppend( pLink ); // // Insert pLinkInsert right after pLinkMiddle. // pBase->Link_vInsert( pLinkMiddle, pLinkInsert ); // // Get to the head. // pLinkHead = pBase->Link_pHead(); // // To get to the next element in the list. // pLink = pLinkHead->Link_pNext(); // // Remove an element from the list. // pLink->pLink_vDelinkSelf(); // // Using the iter class. // TIter Iter; for( Link_vIterInit( Iter ), Iter.vNext(); Iter.bValid(); Iter.vNext( )){ // // Use pLink. // vLinkOperation( pLink ); } ********************************************************************/ #define DLINK_BASE( type, name, linkname ) \ VOID name##_vReset() \ { pdl##name()->FLink = pdl##name()->BLink = pdl##name(); } \ \ PDLINK name##_pdlHead() const \ { return pdl##name()->FLink; } \ \ PDLINK name##_pdlBase() const \ { return pdl##name(); } \ \ type* name##_pHead( VOID ) const \ { \ return name##_bValid( name##_pdlHead() ) ? \ (type*)((PBYTE)name##_pdlHead() - OFFSETOF( type, \ _dl##linkname )) : \ NULL; \ } \ \ BOOL name##_bValid( PDLINK pdlink ) const \ { return pdlink != pdl##name(); } \ \ VOID name##_vAdd( type* pType ) \ { name##_vInsert( pdl##name(), pType->pdl##linkname( )); } \ \ VOID name##_vAppend( type* pType ) \ { name##_vInsert( pdl##name()->BLink, pType->pdl##linkname( )); } \ \ VOID name##_vInsert( PDLINK pdlink1, type* pType2 ) \ { name##_vInsert( pdlink1, pType2->pdl##linkname() ); } \ \ VOID name##_vInsert( PDLINK pdlink1, PDLINK pdlink2 ) \ { \ SPLASSERT( !pdlink2->FLink ); \ pdlink1->FLink->BLink = pdlink2; \ \ pdlink2->BLink = pdlink1; \ pdlink2->FLink = pdlink1->FLink; \ \ pdlink1->FLink = pdlink2; \ } \ \ VOID name##_vInsertBefore( PDLINK pdlink1, type* pType2 ) \ { name##_vInsertBefore( pdlink1, pType2->pdl##linkname() ); } \ \ VOID name##_vInsertBefore( PDLINK pdlink1, PDLINK pdlink2 ) \ { \ SPLASSERT( !pdlink2->FLink ); \ pdlink1->BLink->FLink = pdlink2; \ \ pdlink2->FLink = pdlink1; \ pdlink2->BLink = pdlink1->BLink; \ \ pdlink1->BLink = pdlink2; \ } \ \ VOID name##_vDelink( type* pType ) \ { name##_vDelink( pType->pdl##linkname( )); } \ \ VOID name##_vDelink( PDLINK pdlink ) \ { \ pdlink->FLink->BLink = pdlink->BLink; \ pdlink->BLink->FLink = pdlink->FLink; \ pdlink->FLink = NULL; \ } \ \ type* name##_pFind( type* pType ) const \ { \ PDLINK pdlinkT; \ PDLINK pdlink = pType->pdl##linkname(); \ \ for( pdlinkT = name##_pdlHead(); \ name##_bValid( pdlinkT ); \ pdlinkT = pdlinkT->FLink ){ \ \ if( pType->pdl##linkname() == pdlinkT ) \ return (type*)((PBYTE)pdlink - OFFSETOF( type, \ _dl##linkname )); \ } \ return NULL; \ } \ \ PDLINK name##_pdlFind( PDLINK pdlink ) const \ { \ PDLINK pdlinkT; \ for( pdlinkT = name##_pdlHead(); \ name##_bValid( pdlinkT ); \ pdlinkT = pdlinkT->FLink ){ \ \ if( pdlink == pdlinkT ) \ return pdlink; \ } \ return NULL; \ } \ \ PDLINK name##_pdlGetByIndex( UINT uIndex ) const \ { \ PDLINK pdlink; \ for( pdlink = name##_pdlHead(); \ uIndex; \ uIndex--, pdlink = pdlink->FLink ){ \ \ SPLASSERT( name##_bValid( pdlink )); \ } \ return pdlink; \ } \ \ type* name##_pGetByIndex( UINT uIndex ) const \ { \ PDLINK pdlink; \ for( pdlink = name##_pdlHead(); \ uIndex; \ uIndex--, pdlink = pdlink->FLink ){ \ \ SPLASSERT( name##_bValid( pdlink )); \ } \ return name##_pConvert( pdlink ); \ } \ \ static PDLINK name##_pdlNext( PDLINK pdlink ) \ { return pdlink->FLink; } \ \ static type* name##_pConvert( PDLINK pdlink ) \ { return (type*)( (PBYTE)pdlink - OFFSETOF( type, _dl##linkname )); } \ \ PDLINK pdl##name( VOID ) const \ { return (PDLINK)&_dlb##name; } \ \ BOOL name##_bEmpty() const \ { return pdl##name()->FLink == pdl##name(); } \ \ VOID name##_vIterInit( TIter& Iter ) const \ { Iter._pdlBase = Iter._pdlink = (PDLINK)&_dlb##name; } \ \ DLINKBASE _dlb##name; \ #define DLINK( type, name ) \ PDLINK pdl##name() \ { return &_dl##name; } \ \ VOID name##_vDelinkSelf( VOID ) \ { \ _dl##name.FLink->BLink = _dl##name.BLink; \ _dl##name.BLink->FLink = _dl##name.FLink; \ _dl##name.FLink = NULL; \ } \ \ BOOL name##_bLinked() const \ { return _dl##name.FLink != NULL; } \ \ PDLINK name##_pdlNext( VOID ) const \ { return _dl##name.FLink; } \ \ PDLINK name##_pdlPrev( VOID ) const \ { return _dl##name.BLink; } \ \ type* name##_pNext( VOID ) const \ { return name##_pConvert( _dl##name.FLink ); } \ \ type* name##_pPrev( VOID ) const \ { return name##_pConvert( _dl##name.BLink ); } \ \ static type* name##_pConvert( PDLINK pdlink ) \ { return (type*)( (PBYTE)pdlink - OFFSETOF( type, _dl##name )); } \ \ DLINK _dl##name // // Generic MEntry class that allows objects to be stored on a list // and searched by name. // class MEntry { SIGNATURE( 'entr' ) public: DLINK( MEntry, Entry ); TString _strName; BOOL bValid() { return _strName.bValid(); } static MEntry* pFindEntry( PDLINK pdlink, LPCTSTR pszName ); }; #define ENTRY_BASE( type, name ) \ friend MEntry; \ type* name##_pFindByName( LPCTSTR pszName ) const \ { \ MEntry* pEntry = MEntry::pFindEntry( name##_pdlBase(), pszName ); \ return pEntry ? (type*)pEntry : NULL; \ } \ static type* name##_pConvertEntry( PDLINK pdlink ) \ { \ return (type*)name##_pConvert( pdlink ); \ } \ DLINK_BASE( MEntry, name, Entry ) #define DELETE_ENTRY_LIST( type, name ) \ { \ PDLINK pdlink; \ type* pType; \ \ for( pdlink = name##_pdlHead(); name##_bValid( pdlink ); ){ \ \ pType = name##_pConvertEntry( pdlink ); \ pdlink = name##_pdlNext( pdlink ); \ \ pType->vDelete(); \ } \ } /////////////////////////////////////////////////// // @@file@@ threadm.hxx /////////////////////////////////////////////////// typedef PVOID PJOB; class CCSLock; class TThreadM { SIGNATURE( 'thdm' ) SAFE_NEW private: enum _States { kDestroyReq = 1, kDestroyed = 2, kPrivateCritSec = 4 } States; /******************************************************************** Valid TMSTATUS states: NULL -- Normal processing DESTROY_REQ -- No new jobs, jobs possibly running DESTROY_REQ, DESTROYED -- No new jobs, all jobs completed ********************************************************************/ TState _State; UINT _uIdleLife; UINT _uMaxThreads; UINT _uActiveThreads; UINT _uRunNowThreads; INT _iIdleThreads; HANDLE _hTrigger; CCSLock *_pCritSec; LONG _lLocks; DWORD dwThreadProc( VOID ); static DWORD xdwThreadProc( PVOID pVoid ); virtual PJOB pThreadMJobNext( VOID ) = 0; virtual VOID vThreadMJobProcess( PJOB pJob ) = 0; protected: TThreadM( UINT uMaxThreads, UINT uIdleLife, CCSLock* pCritSec ); virtual ~TThreadM( VOID ); BOOL bValid( VOID ) const { return _hTrigger != NULL; } BOOL bJobAdded( BOOL bRunNow ); VOID vDelete( VOID ); LONG Lock( VOID ) { return InterlockedIncrement(&_lLocks); } LONG Unlock( VOID ) { LONG lLocks = InterlockedDecrement(&_lLocks); if (0 == lLocks) delete this; return lLocks; } }; /////////////////////////////////////////////////// // @@file@@ exec.hxx /////////////////////////////////////////////////// /******************************************************************** This module implements an asynchronous, pooled threads to processes worker jobs. class TJobUnit : public MExecWork { ... } gpExec->bJobAdd( pJobUnit, USER_SPECIFIED_BITFIELD ); // // When thread is available to process job, // pJobUnit->svExecute( USER_SPECIFIED_BITFIELD, ... ) // will be called. // Declare a class Work derived from the mix-in MExecWork. When work needs to be done on an instantiation of Work, it is queued and immediately returned. A DWORD bitfield--4 high bits are predefined--indicates the type of work needed. This DWORD should be a bitfield, so if there are multiple bJobAdd requests and all threads are busy, these DWORDs are OR'd together. That is, bJobAdd( pJobUnit, 0x1 ); bJobAdd( pJobUnit, 0x2 ); bJobAdd( pJobUnit, 0x4 ); bJobAdd( pJobUnit, 0x8 ); We will call svExecute with 0xf. Two threads will never operate on one job simultaneously. This is guarenteed by this library. The worker routine is defined by the virtual function stExecute(). ********************************************************************/ typedef enum _STATE_EXEC { kExecUser = 0x08000000, // Here and below user may specify. kExecRunNow = 0x10000000, // Ignore thread limit. kExecExit = 0x20000000, // User requests the TExec exits. kExecActive = 0x40000000, // Private: job is actively running. kExecActiveReq = 0x80000000, // Private: job is queued. kExecPrivate = kExecActive | kExecActiveReq, kExecNoOutput = kExecPrivate | kExecRunNow } STATE_EXEC; class TExec; class MExecWork { friend TExec; SIGNATURE( 'exwk' ); ALWAYS_VALID SAFE_NEW private: DLINK( MExecWork, Work ); // // Accessed by worker thread. // VAR( TState, State ); // // StatePending is work that is pending (accumulated while the // job is executing in a thread). The job at this stage is // not in the queue. // VAR( TState, StatePending ); virtual STATEVAR svExecute( STATEVAR StateVar ) = 0; virtual VOID vExecFailedAddJob( VOID ) = 0; /******************************************************************** vExecExitComplete is called when a job completes and it is pending deletion. This allows a client to allow all pending work to complete before it deletes the object. User adds job. Job starts executing.., User decides job should be deleted so adds EXEC_EXIT. ... job finally completes. Library calls vExecExitComplete on job Client can now delete work object in vExecExitComplete call. Note that only jobs that are currently executing are allowed to complete. Jobs that are queued to work will exit immediately. ********************************************************************/ virtual VOID vExecExitComplete( VOID ) = 0; }; class TExec : public TThreadM { SIGNATURE( 'exec' ); SAFE_NEW public: TExec( CCSLock* pCritSec ); // // Clients should use vDelete, _not_ ~TExec. // ~TExec( VOID ) { } VOID vDelete( VOID ) { TThreadM::vDelete(); } BOOL bValid( VOID ) const { return TThreadM::bValid(); } BOOL bJobAdd( MExecWork* pExecWork, STATEVAR StateVar ); VOID vJobDone( MExecWork* pExecWork, STATEVAR StateVar ); STATEVAR svClearPendingWork( MExecWork* pExecWork ); private: DLINK_BASE( MExecWork, Work, Work ); CCSLock* _pCritSec; // // Virtual definitions for TThreadM. // PJOB pThreadMJobNext( VOID ); VOID vThreadMJobProcess( PJOB pJob ); BOOL bJobAddWorker( MExecWork* pExecWork ); }; /////////////////////////////////////////////////// // @@file@@ mem.hxx /////////////////////////////////////////////////// #define AllocMem(cb) malloc(cb) #define FreeMem(ptr) free(ptr) /////////////////////////////////////////////////// // @@file@@ bitarray.hxx /////////////////////////////////////////////////// class TBitArray { public: typedef UINT Type; enum { kBitsInType = sizeof( Type ) * 8, kBitsInTypeMask = 0xFFFFFFFF, }; TBitArray( IN UINT uBits = kBitsInType, IN UINT uGrowSize = kBitsInType ); TBitArray( IN const TBitArray &rhs ); const TBitArray & operator=( IN const TBitArray &rhs ); ~TBitArray( VOID ); BOOL bValid( VOID ) const; BOOL bToString( // Return string representation of bit array IN TString &strBits ) const; BOOL bRead( IN UINT uBit // Range 0 to nBit - 1 ) const; BOOL bSet( IN UINT uBit // Range 0 to nBit - 1 ); BOOL bReset( IN UINT uBit // Range 0 to nBit - 1 ); BOOL bToggle( IN UINT uBit // Range 0 to nBit - 1 ); BOOL bAdd( VOID // Add one bit to the array ); UINT uNumBits( // Return the total number of bits in the array VOID ) const; VOID vSetAll( // Set all the bits in the array VOID ); VOID vResetAll( // Reset all the bits in the array VOID ); BOOL bFindNextResetBit( // Locate first cleared bit in the array IN UINT *puNextFreeBit ); private: BOOL bClone( // Make a copy of the bit array IN const TBitArray &rhs ); BOOL bGrow( // Expand the bit array by x number of bits IN UINT uGrowSize ); UINT nBitsToType( IN UINT uBits // Range 1 to nBit ) const; Type BitToMask( IN UINT uBit // Range 0 to nBit - 1 ) const; UINT BitToIndex( IN UINT uBit // Range 0 to nBit - 1 ) const; BOOL bIsValidBit( IN UINT uBit // Range 0 to nBit - 1 ) const; UINT _nBits; // Number of currently allocated bits, Range 1 to n Type *_pBits; // Pointer to array which contains the bits UINT _uGrowSize; // Default number of bits to grow by }; /////////////////////////////////////////////////// // @@file@@ loadlib.hxx /////////////////////////////////////////////////// /******************************************************************** Helper class to load and release a DLL. Use the bValid for library load validation. ********************************************************************/ class TLibrary { public: TLibrary:: TLibrary( IN LPCTSTR pszLibName ); TLibrary:: ~TLibrary( ); BOOL TLibrary:: bValid( VOID ) const; FARPROC TLibrary:: pfnGetProc( IN LPCSTR pszProc ) const; FARPROC TLibrary:: pfnGetProc( IN UINT uOrdinal ) const; HINSTANCE TLibrary:: hInst( VOID ) const; private: HINSTANCE _hInst; }; /////////////////////////////////////////////////// // @@file@@ stack.hxx /////////////////////////////////////////////////// template class TStack { public: TStack( UINT uSize ); ~TStack( VOID ); BOOL bValid( VOID ) const; BOOL bPush( IN T Object ); BOOL bPop( IN OUT T *Object ); UINT uSize( VOID ) const; BOOL bEmpty( VOID ) const; private: BOOL bGrow( IN UINT uSize ); UINT _uSize; T *_pStack; T *_pStackPtr; }; /******************************************************************** Stack template class. ********************************************************************/ // // Note the _stackPtr points to the next available location. // template _INLINE TStack:: TStack( UINT uSize ) : _uSize( uSize ), _pStack( NULL ), _pStackPtr( NULL ) { _pStack = new T[_uSize+1]; if( _pStack ) { _pStackPtr = _pStack; } } template _INLINE TStack:: ~TStack( VOID ) { delete [] _pStack; } template _INLINE BOOL TStack:: bValid( VOID ) const { return _pStack != NULL; } template _INLINE BOOL TStack:: bPush( IN T Object ) { SPLASSERT( _pStack ); BOOL bReturn = TRUE; if( _pStackPtr >= _pStack + _uSize ) { bReturn = bGrow( _uSize ); if( !bReturn ) { DBGMSG( DBG_ERROR, ( "TStack::bPush - failed to grow\n" ) ); } } if( bReturn ) { *_pStackPtr++ = Object; bReturn = TRUE; } return bReturn; } template _INLINE BOOL TStack:: bPop( OUT T *pObject ) { SPLASSERT( _pStack ); BOOL bReturn; if( _pStackPtr <= _pStack ) { bReturn = FALSE; } else { *pObject = *--_pStackPtr; bReturn = TRUE; } return bReturn; } template _INLINE UINT TStack:: uSize( VOID ) const { if( _pStackPtr < _pStack || _pStackPtr > _pStack + _uSize ) { SPLASSERT( FALSE ); } return _pStackPtr - _pStack; } template _INLINE BOOL TStack:: bEmpty( VOID ) const { SPLASSERT( _pStack ); return _pStackPtr <= _pStack; } template _INLINE BOOL TStack:: bGrow( IN UINT uSize ) { BOOL bReturn = FALSE; // // Calculate the new stack size. // UINT uNewSize = _uSize + uSize; // // Allocate a new stack. // T* pNewStack = new T[uNewSize]; if( pNewStack ) { // // Copy the old stack contents to the new stack; // for( UINT i = 0; i < _uSize; i++ ) { pNewStack[i] = _pStack[i]; } // // Set the stack pointer in the new stack // T *pNewStackPtr = _pStackPtr - _pStack + pNewStack; // // Release the old stack; // delete [] _pStack; // // Set the stack pointer. // _pStack = pNewStack; _uSize = uNewSize; _pStackPtr = pNewStackPtr; // // Indicate the stack has grown. // bReturn = TRUE; } else { DBGMSG( DBG_TRACE, ( "TStack::bGrow failed.\n" ) ); } return bReturn; } /////////////////////////////////////////////////// // @@file@@ autoptr.hxx /////////////////////////////////////////////////// template class auto_ptr { public: // Constructor auto_ptr( T *p = 0 ); // Destructor ~auto_ptr( VOID ); // Dereference T& operator*( VOID ) const; // Dereference T* operator->( VOID ) const; // Return value of current dumb pointer T* get( VOID ) const; // Relinquish ownership of current dumb pointer T* release( VOID ); // Delete owned dumb pointer VOID reset( T *p ); // Copying an auto pointer auto_ptr( const auto_ptr& rhs ); // Assign one auto pointer to another const auto_ptr& operator=( const auto_ptr& rhs ); private: // Actual dumb pointer. T *pointee; }; // Constructor template< class T > _INLINE auto_ptr:: auto_ptr( T *p ) : pointee(p) { }; // Destructor template< class T > _INLINE auto_ptr:: ~auto_ptr( VOID ) { delete pointee; }; // Dereference template< class T > _INLINE T& auto_ptr:: operator*( VOID ) const { return *pointee; } // Dereference template< class T > _INLINE T* auto_ptr:: operator->( VOID ) const { return pointee; } // Return value of current dumb pointer template< class T > _INLINE T* auto_ptr:: get( VOID ) const { return pointee; } // Relinquish ownership of current dumb pointer template< class T > _INLINE T * auto_ptr:: release( VOID ) { T *oldPointee = pointee; pointee = 0; return oldPointee; } // Delete owned dumb pointer template< class T > _INLINE VOID auto_ptr:: reset( T *p ) { delete pointee; pointee = p; } // Copying an auto pointer template< class T > _INLINE auto_ptr:: auto_ptr( const auto_ptr& rhs ) : pointee( rhs.release() ) { } // Assign one auto pointer to another template< class T > _INLINE const auto_ptr& auto_ptr:: operator=( const auto_ptr& rhs ) { if( this != &rhs ) { reset( rhs.release() ); } return *this; } #endif // _SPLLIB_HXX