#ifndef __ObjectLock_h__ #define __ObjectLock_h__ ///////////////////////////////////////////////////////////////////////////// // ObjectLock.h | Declaration of the TCObjectLock template class. // #include "AutoHandle.h" #include "..\Inc\TCLib.h" #include ///////////////////////////////////////////////////////////////////////////// // Global Diagnostic Function #ifdef _DEBUG #ifdef _ENABLE_TRACE_LOCKS #pragma warning(disable: 4786) #include inline bool TCObjectLock_EnableTraceLocks(const char* pszClassName) { // This is not currenlty being used, due to the _ENABLE_TRACE_LOCKS // directive not being defined, but it really appears to be quite // thread *UNSAFE*, since this map object does not have any explicit // thread synchronization. typedef std::map CClassNameMap; static CClassNameMap mapClassNames; // First lookup the class name in the map CClassNameMap::iterator it = mapClassNames.find(pszClassName); if (mapClassNames.end() != it) return (*it).second; // Open the debugging subkey bool bEnable = false; const LPCTSTR pszKeyName = TEXT("Software\\Microsoft\\Microsoft Games\\Debug\\EnableTraceLocks"); TCRegKeyHandle hkey; LONG lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszKeyName, 0, KEY_READ, &hkey); if (ERROR_SUCCESS == lResult) { // Attempt to read the value with the specified class name DWORD dwTraceLocks = 0; DWORD dwType = REG_DWORD; DWORD dwDataSize = sizeof(dwTraceLocks); USES_CONVERSION; lResult = RegQueryValueEx(hkey, A2CT(pszClassName), NULL, &dwType, LPBYTE(&dwTraceLocks), &dwDataSize); if (ERROR_SUCCESS == lResult && REG_DWORD == dwType) bEnable = dwTraceLocks != 0; } // Add the class name and the enabled flag to the map mapClassNames.insert(CClassNameMap::value_type(pszClassName, bEnable)); return bEnable; } #else // _ENABLE_TRACE_LOCKS inline bool TCObjectLock_EnableTraceLocks(const char* pszClassName) { return false; } #endif // _ENABLE_TRACE_LOCKS #endif // _DEBUG ///////////////////////////////////////////////////////////////////////////// // TCObjectLock provides a convenient mechanism for the locking and unlocking // of protected resources. // // The TCObjectLock template class can be used for any object, /T/, that has // the public members, Lock and Unlock, each without a parameter list. // // This object is constructed with a pointer to the attached object, /T/, and // the Lock method of that object is called. When this object goes out of // scope, the Unlock method of the attached object is automatically called. // Alternately, the Unlock method of this object will unlock the attached // object prior to this object going out of scope. // // The following is an example usage of this class: // // DWORD CMyObject::GetValue() const // { // TCObjectLock lock(this); // return m_dwValue; // } // Unlock is called automatically when lock goes out of scope // // Note that this example assumes that the CMyObject class provides the // public member functions, Lock and Unlock. // // It is common for a lockable object to declare a typedef for TCObjectLock. // For example, if the CMyObject declaration provides the following typedef: // // typedef TCObjectLock XLock; // // then, the previous examples could be changed to the following, using the // more abbreviated notation: // // DWORD CMyObject::GetValue() const // { // XLock lock(this); // return m_dwValue; // } // Unlock is called automatically when lock goes out of scope // // Parameters: // T - Any type that publicly exposes both a Lock and an Unlock method, // both of which do not take any parameters. template class TCObjectLock { // Construction / Destruction public: TCObjectLock(T* pObject); ~TCObjectLock(); // Operations public: void Unlock(); // Data Members: protected: T* m_pObject; // A pointer to the lockable class, /T/ }; ///////////////////////////////////////////////////////////////////////////// // Group=Construction / Destruction ///////////////////////////////////////////////////////////////////////////// // Locks the object, /T/, by calling the Lock method of class /T/. template inline TCObjectLock::TCObjectLock(T* pObject) : m_pObject(pObject) { if (m_pObject) m_pObject->Lock(); #ifdef _ENABLE_TRACE_LOCKS #ifdef _DEBUG const char* pszClass = TCTypeName(T); if (TCObjectLock_EnableTraceLocks(pszClass)) { DWORD dwID = GetCurrentThreadId(); _TRACE3("TCObjectLock<%hs> on thread 0x%0X (%d): Locking\n", pszClass, dwID, dwID); } #endif // _DEBUG #endif // _ENABLE_TRACE_LOCKS } ///////////////////////////////////////////////////////////////////////////// // Unlocks the object, /T/, if Unlock has not already been called. template inline TCObjectLock::~TCObjectLock() { if (m_pObject) Unlock(); } ///////////////////////////////////////////////////////////////////////////// // Group=Operations ///////////////////////////////////////////////////////////////////////////// // Unlocks the object, /T/, by calling the Unlock method of class /T/. // // After unlocking the object, the m_pObject data member is set to NULL so // that the destructor does not attempt to unlock it. // // See Also: TCThread::destructor template inline void TCObjectLock::Unlock() { #ifdef _ENABLE_TRACE_LOCKS #ifdef _DEBUG const char* pszClass = TCTypeName(T); if (TCObjectLock_EnableTraceLocks(pszClass)) { DWORD dwID = GetCurrentThreadId(); _TRACE3("TCObjectLock<%hs> on thread 0x%0X (%d): Unlocking\n", pszClass, dwID, dwID); } #endif // _DEBUG #endif // _ENABLE_TRACE_LOCKS if (m_pObject) { m_pObject->Unlock(); m_pObject = NULL; } } ///////////////////////////////////////////////////////////////////////////// #endif // __ObjectLock_h__