/*++ Copyright (c) 1998-2000 Microsoft Corporation Module Name: drobjmgr Abstract: DrObjectMgr manages a list of client-side RDP objects. Author: Joy Chik 11/30/99 Revision History: --*/ #ifndef __DROBJMGR_H__ #define __DROBJMGR_H__ #include #include "drobject.h" #include "drdev.h" #include "drfile.h" template class DrObjectMgr; class DrDevice; class DrFile; /////////////////////////////////////////////////////////////// // // DrObjectMgr // // Locking: Member functions will implicitly lock the state // of the list. External explicit locking is also // available and recommended when iterating through // devices. // // GetFirstObject/GetNextObject: // Used in conjunction to iterate through the list // of objects. Any changes to the contents of list // resets the current object pointer. // template class DrObjectMgr : public DrObject { private: /////////////////////////////////////////////////////////////// // // Typedefs // typedef struct _DROBJECTLIST_NODE { ULONG magicNo; T *object; _DROBJECTLIST_NODE *next; _DROBJECTLIST_NODE *prev; } DROBJECTLIST_NODE, *PDROBJECTLIST_NODE; // // Private Data // BOOL _initialized; // Linked list of object instances. PDROBJECTLIST_NODE _listHead; // Global (to an instance of this class) monotonically // increasing object identifer. ULONG _objectID; // Current object for GetFirst/GetNext routines. PDROBJECTLIST_NODE _currentNode; // The lock. CRITICAL_SECTION _cs; // // Monitor the lock count in checked builds. // #if DBG LONG _lockCount; #endif // Object Count ULONG _count; // Remember if we are in the middle of checking the integrity of an // instance of this class. #if DBG BOOL _integrityCheckInProgress; #endif // // Private Methods // VOID deleteNode(PDROBJECTLIST_NODE node); PDROBJECTLIST_NODE FindNode(DRSTRING name, ULONG objectType); PDROBJECTLIST_NODE FindNode(ULONG id); // // Periodically, check the integrity of the list in debug builds. // #if DBG VOID CheckListIntegrity(); #endif public: // // Public Methods // // Constructor/Destructor DrObjectMgr(); virtual ~DrObjectMgr(); // Initialize DWORD Initialize(); // Lock/unlock the list of objects for multithreaded access. // Member functions that require that the list of objects be locked // will do implicitly. VOID Lock(); VOID Unlock(); // Add/remove an object. DWORD AddObject(T *object); T *RemoveObject(const DRSTRING name, ULONG objectType); T *RemoveObject(ULONG id); // Test for existence of an object. BOOL ObjectExists(const DRSTRING name); BOOL ObjectExists(const DRSTRING name, ULONG deviceType); BOOL ObjectExists(ULONG id); // Return an object. T *GetObject(const DRSTRING name); T *GetObject(const DRSTRING name, ULONG objectType); T *GetObject(ULONG id); // // Iterate through objects, sequentially. // ULONG GetCount() { return _count; } T *GetObjectByOffset(ULONG ofs); T *GetFirstObject(); T *GetNextObject(); // Return whether this class instance is valid. #if DBG virtual BOOL IsValid() { CheckListIntegrity(); return DrObject::IsValid(); } #endif // Get a unique object ID ... assuming that this function is the // clearinghouse for all objects associated with an instance of this // class. ULONG GetUniqueObjectID(); // Return the class name. virtual DRSTRING ClassName() { return TEXT("DrObjectMgr"); } }; /////////////////////////////////////////////////////////////// // // DrObjectMgr Inline Functions // // // // lock // template inline VOID DrObjectMgr::Lock() { DC_BEGIN_FN("DrObjectMgr::Lock"); EnterCriticalSection(&_cs); #if DBG InterlockedIncrement(&_lockCount); #endif DC_END_FN(); } // // unlock // template inline VOID DrObjectMgr::Unlock() { DC_BEGIN_FN("DrObjectMgr::Unlock"); #if DBG if (InterlockedDecrement(&_lockCount) < 0) { ASSERT(FALSE); } #endif LeaveCriticalSection(&_cs); DC_END_FN(); } // // GetUniqueObjectID // template inline ULONG DrObjectMgr::GetUniqueObjectID() { ULONG tmp; Lock(); tmp = ++_objectID; Unlock(); return tmp; } // // deleteNode // template inline VOID DrObjectMgr::deleteNode(PDROBJECTLIST_NODE node) { if (node == _listHead) { _listHead = _listHead->next; } else { node->prev->next = node->next; if (node->next != NULL) { node->next->prev = node->prev; } } // // Delete the node. // delete node; } // // Constructor // template DrObjectMgr::DrObjectMgr() { // // Initialize the lock count for debug builds. // #if DBG _lockCount = 0; #endif // // Not valid until initialized. // _initialized = FALSE; SetValid(FALSE); // // Initialize the list head. // _listHead = NULL; // // Initialize the unique device ID counter. // _objectID = 0; // // Initialize the device count. // _count = 0; // // Initialize the GetFirst/GetNext device pointer. // _currentNode = NULL; } // // Destructor // template DrObjectMgr::~DrObjectMgr() { DC_BEGIN_FN("DrObjectMgr::~DrObjectMgr"); // // Can't do anything if we are not initialized. // if (!_initialized) { return; } Lock(); // // The lock count should be one if we are being cleaned up. // ASSERT(_lockCount == 1); // // Release the object list. // if (_listHead != NULL) { // // Assert that the device list is empty. All device instances // should have been removed by the time this function is called. // ASSERT(_listHead->next == NULL); delete _listHead; } Unlock(); // // Clean up the critical section object. // DeleteCriticalSection(&_cs); DC_END_FN(); } // // Initialize // template DWORD DrObjectMgr::Initialize() { DC_BEGIN_FN("DrObjectMgr::Initialize"); DWORD result = ERROR_SUCCESS; // // Initialize the critical section. // __try { InitializeCriticalSection(&_cs); _initialized = TRUE; SetValid(TRUE); } __except(EXCEPTION_EXECUTE_HANDLER) { result = GetExceptionCode(); } return result; } // // FindNode // template __TYPENAME DrObjectMgr::PDROBJECTLIST_NODE DrObjectMgr::FindNode(DRSTRING name, ULONG objectType) { PDROBJECTLIST_NODE cur; cur = _listHead; while (cur != NULL) { T *obj = cur->object; if (!STRICMP(name, obj->GetName()) && (obj->GetDeviceType() == objectType)) { break; } else { cur = cur->next; } } return cur; } // // FindNode // template __TYPENAME DrObjectMgr::PDROBJECTLIST_NODE DrObjectMgr::FindNode(ULONG id) { PDROBJECTLIST_NODE cur; DC_BEGIN_FN("DrObjectMgr::FindNode"); cur = _listHead; while (cur != NULL) { T *obj = cur->object; if (id == obj->GetID()) { break; } else { cur = cur->next; } } DC_END_FN(); return cur; } // // AddObject // template DWORD DrObjectMgr::AddObject(T *object) { DWORD ret = ERROR_SUCCESS; PDROBJECTLIST_NODE newNode; DC_BEGIN_FN("DrObjectMgr::AddObject"); ASSERT(IsValid()); // // Make sure that the object doesn't already exist in the // list. // ASSERT(FindNode(object->GetID()) == NULL); // // Allocate the node. // newNode = new DROBJECTLIST_NODE; if (newNode != NULL) { #if DBG newNode->magicNo = GOODMEMMAGICNUMBER; #endif newNode->object = object; // // Add the node to the list. // Lock(); _count++; if (_listHead == NULL) { _listHead = newNode; _listHead->next = NULL; _listHead->prev = NULL; } else { _listHead->prev = newNode; newNode->prev = NULL; newNode->next = _listHead; _listHead = newNode; } Unlock(); } else { TRC_ERR((TB, _T("Failed to alloc device."))); ret = ERROR_NOT_ENOUGH_MEMORY; } ASSERT(IsValid()); DC_END_FN(); return ret; } // // RemoveObject // template T *DrObjectMgr::RemoveObject( const DRSTRING name, ULONG objectType ) { PDROBJECTLIST_NODE node; T *object; DC_BEGIN_FN("DrObjectMgr::RemoveObject"); ASSERT(IsValid()); // // Find the object. // Lock(); if ((node = FindNode(name, deviceType)) != NULL) { object = node->object; deleteNode(node); // // Decrement the count. // _count--; } else { object = NULL; } Unlock(); ASSERT(IsValid()); DC_END_FN(); return object; } // // RemoveObject // template T *DrObjectMgr::RemoveObject(ULONG id) { PDROBJECTLIST_NODE node; T *object; DC_BEGIN_FN("DrObjectMgr::RemoveObject"); ASSERT(IsValid()); // // Find the object. // Lock(); if ((node = FindNode(id)) != NULL) { object = node->object; deleteNode(node); // // Decrement the count. // _count--; } else { object = NULL; } Unlock(); ASSERT(IsValid()); DC_END_FN(); return object; } // // ObjectExists // template BOOL DrObjectMgr::ObjectExists(const DRSTRING name, ULONG objectType) { PDROBJECTLIST_NODE node; DC_BEGIN_FN("DrObjectMgr::ObjectExists"); ASSERT(IsValid()); Lock(); node = FindNode(name, objectType); Unlock(); ASSERT(IsValid()); DC_END_FN(); return node != NULL; } // // ObjectExists // template BOOL DrObjectMgr::ObjectExists(ULONG id) { PDROBJECTLIST_NODE node; DC_BEGIN_FN("DrObjectMgr::ObjectExists"); ASSERT(IsValid()); Lock(); node = FindNode(id); Unlock(); ASSERT(IsValid()); DC_END_FN(); return node != NULL; } // // Return an object. // template T *DrObjectMgr::GetObject(const DRSTRING name, ULONG objectType) { PDROBJECTLIST_NODE node; T *object; DC_BEGIN_FN("DrObjectMgr::GetObject"); ASSERT(IsValid()); Lock(); if ((node = FindNode(name, objectType)) != NULL) { object = node->object; } else { object = NULL; } Unlock(); ASSERT(IsValid()); DC_END_FN(); return object; } // // Return an object. // template T *DrObjectMgr::GetObject(ULONG id) { PDROBJECTLIST_NODE node; T *object; DC_BEGIN_FN("DrObjectMgr::GetObject"); ASSERT(IsValid()); Lock(); if ((node = FindNode(id)) != NULL) { object = node->object; } else { object = NULL; } Unlock(); ASSERT(IsValid()); DC_END_FN(); return object; } // // Get object at the specified offset. // template T *DrObjectMgr::GetObjectByOffset(ULONG ofs) { PDROBJECTLIST_NODE cur; ULONG cnt = 0; DC_BEGIN_FN("DrObjectMgr::GetObjectByOffset"); ASSERT(IsValid()); Lock(); for (cur=_listHead, cnt=0; (cur!=NULL) && (cnt != ofs); cnt++) { ASSERT(cur->magicNo == GOODMEMMAGICNUMBER); cur = cur->next; } Unlock(); ASSERT(IsValid()); DC_END_FN(); return cur->object; } // // Return the first object and set the internal current object // pointer to the beginning of the list. Returns NULL at the end // of the list. // template T *DrObjectMgr::GetFirstObject() { T *object; DC_BEGIN_FN("DrObjectMgr::GetFirstObject"); ASSERT(IsValid()); Lock(); _currentNode = _listHead; if (_currentNode != NULL) { object = _currentNode->object; } else { object = NULL; } Unlock(); ASSERT(IsValid()); DC_END_FN(); return object; } // // Return the next object and update the internal current object // pointer. Returns NULL at the end of the list. // template T *DrObjectMgr::GetNextObject() { T *object; DC_BEGIN_FN("DrObjectMgr::GetNextObject"); ASSERT(IsValid()); Lock(); if (_currentNode != NULL) { _currentNode = _currentNode->next; } if (_currentNode != NULL) { object = _currentNode->object; ASSERT(_currentNode->magicNo == GOODMEMMAGICNUMBER); } else { object = NULL; } Unlock(); ASSERT(IsValid()); DC_END_FN(); return object; } // // Check the integrity of the list. // #if DBG template VOID DrObjectMgr::CheckListIntegrity() { ULONG cnt; ULONG i; DC_BEGIN_FN("DrObjectMgr::CheckListIntegrity"); Lock(); // // Make sure we don't re-enter ourselves. // if (!_integrityCheckInProgress) { _integrityCheckInProgress = TRUE; } else { Unlock(); DC_END_FN(); return; } // // Use offsets to iterate throught the list of objects. // cnt = GetCount(); for (i=0; i_magicNo == GOODMEMMAGICNUMBER); } _integrityCheckInProgress = FALSE; Unlock(); DC_END_FN(); } #endif typedef DrObjectMgr DrDeviceMgr; typedef DrObjectMgr DrFileMgr; #endif