// // connlist.c // // Handles a linked list which will keep track of all the TCLIENT2 handles. // // Why is this needed? // // I am using SetTimer() callbacks to keep track of idled scripts. // The problem is, there is no way for me to tell exactly which // handle executed which timer. The only way to do this is to keep // a list of all the handles, and their associated timer id. // // Copyright (C) 2001 Microsoft Corporation // // Author: a-devjen (Devin Jenson) // // 03-08-2001 - Fixed bug regarding last node on list not being cleaned. #include "connlist.h" // Linked handle list typedef struct _ConnList { struct _ConnList *Next; struct _ConnList *Prev; HANDLE Handle; UINT_PTR TimerId; DWORD msStartTime; } ConnList; // This is the global variable, representing the head of the list ConnList *Head = NULL; // This queue is used to prevent two threads from messing // with the list at the same time CRITICAL_SECTION ListQueue; // Indicates the number of items in the list DWORD ItemCount; DWORD AccessCount; // Internal function prototypes void T2ConnList_EnterQueue(void); void T2ConnList_LeaveQueue(void); // T2ConnList_EnterQueue // // A "safe" critical section - no critical section needed. // // No return value. void T2ConnList_EnterQueue(void) { if (ItemCount == 0 && AccessCount == 0) InitializeCriticalSection(&ListQueue); ++AccessCount; EnterCriticalSection(&ListQueue); } // T2ConnList_LeaveQueue // // A "safe" critical section - critical section automatically // deletes itself when no longer needed. // // No return value. void T2ConnList_LeaveQueue(void) { LeaveCriticalSection(&ListQueue); --AccessCount; if (ItemCount == 0 && AccessCount == 0) DeleteCriticalSection(&ListQueue); } // T2ConnList_AddHandle // // Adds a new handle to the connection list. Additionally // this will also set the TimerId and msStartTime properties // for the new entry. // // Returns TRUE if the handle was successfully added. // FALSE otherwise. BOOL T2ConnList_AddHandle(HANDLE Handle, UINT_PTR TimerId, DWORD msStartTime) { ConnList *Node; // Sanity check if (Handle == NULL || Handle == INVALID_HANDLE_VALUE) return FALSE; // Get access to the list T2ConnList_EnterQueue(); Node = Head; // Loop through each item, ensuring the item does not already exist for (; Node != NULL && Node->Handle != Handle; Node = Node->Next); // If we didn't reach the end of the list, it already exists if (Node != NULL) { // Simply modify the parameters instead of adding it Node->TimerId = TimerId; Node->msStartTime = msStartTime; // Release access from the list T2ConnList_LeaveQueue(); return TRUE; } // It doesn't exist, allocate a new node for the handle Node = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof (ConnList)); if (Node == NULL) { // Allocation failed, release access from the list T2ConnList_LeaveQueue(); return FALSE; } // Begin adding it to the list by setting the new node at the head if (Head != NULL) Head->Prev = Node; Node->Next = Head; Head = Node; // Record the parameters Node->Handle = Handle; Node->TimerId = TimerId; Node->msStartTime = msStartTime; // Increment the number of handles in the list ++ItemCount; // Release access from the list and return T2ConnList_LeaveQueue(); return TRUE; } // T2ConnList_RemoveHandle // // Removes a handle from the list if it exists. // // No return value. void T2ConnList_RemoveHandle(HANDLE Handle) { ConnList *Node; // Sanity check if (Handle == NULL || Handle == INVALID_HANDLE_VALUE) return; // Gain access to the list T2ConnList_EnterQueue(); Node = Head; // First find the handle in the list for (; Node != NULL && Node->Handle != Handle; Node = Node->Next); // If the Node pointer is NULL, then the handle didn't exist if (Node == NULL) { // Just release access from the list, and return T2ConnList_LeaveQueue(); return; } // Handle found, now unlink it from the list if (Node->Next != NULL) Node->Next->Prev = Node->Prev; if (Node->Prev != NULL) Node->Prev->Next = Node->Next; // Costin and Hammad's Fix!! Yay!! if (Node == Head) Head = Node->Next; // Free the handle itself HeapFree(GetProcessHeap(), 0, Node); // Decrement the handle count in the list --ItemCount; // Release access from the list T2ConnList_LeaveQueue(); } // T2ConnList_GetData // // Gets any non-null pointer parameters for the specified // handle from the list. // // Returns TRUE if the handle was found, FALSE otherwise. BOOL T2ConnList_GetData(HANDLE Handle, UINT_PTR *TimerId, DWORD *msStartTime) { ConnList *Node; // Gain access to the list T2ConnList_EnterQueue(); Node = Head; // First find the handle in the list for (; Node != NULL && Node->Handle != Handle; Node = Node->Next); // If the Node pointer is NULL, then the handle didn't exist if (Node == NULL) { // Just release access from the list, and return an error T2ConnList_LeaveQueue(); return FALSE; } // Simply enter in the parameters if (TimerId != NULL) *TimerId = Node->TimerId; if (msStartTime != NULL) *msStartTime = Node->msStartTime; // Release access from the list, and return success T2ConnList_LeaveQueue(); return TRUE; } // T2ConnList_SetData // // Sets/changes all of the handle's parameters. // // Returns TRUE if the handle was found, FALSE otherwise. BOOL T2ConnList_SetData(HANDLE Handle, UINT_PTR TimerId, DWORD msStartTime) { ConnList *Node; // Gain access to the list T2ConnList_EnterQueue(); Node = Head; // First find the handle in the list for (; Node != NULL && Node->Handle != Handle; Node = Node->Next); // If the Node pointer is NULL, then the handle didn't exist if (Node == NULL) { // Just release access from the list, and return an error T2ConnList_LeaveQueue(); return FALSE; } // Change the parameters Node->TimerId = TimerId; Node->msStartTime = msStartTime; // Release access from the list, and return success T2ConnList_LeaveQueue(); return TRUE; } // T2ConnList_SetTimerId // // Sets the timer id parameter of the specified handle. // // Returns TRUE on success and FALSE on failure. BOOL T2ConnList_SetTimerId(HANDLE Handle, UINT_PTR TimerId) { ConnList *Node; // Gain access to the list T2ConnList_EnterQueue(); Node = Head; // First find the handle in the list for (; Node != NULL && Node->Handle != Handle; Node = Node->Next); // If the Node pointer is NULL, then the handle didn't exist if (Node == NULL) { // Just release access from the list, and return an error T2ConnList_LeaveQueue(); return FALSE; } // Change it Node->TimerId = TimerId; // Release access from the list, and return success T2ConnList_LeaveQueue(); return TRUE; } // T2ConnList_SetStartTime // // Sets the start time parameter of the specified handle. // // Returns TRUE on success and FALSE on failure. BOOL T2ConnList_SetStartTime(HANDLE Handle, DWORD msStartTime) { ConnList *Node; // Gain access to the list T2ConnList_EnterQueue(); Node = Head; // First find the handle in the list for (; Node != NULL && Node->Handle != Handle; Node = Node->Next); // If the Node pointer is NULL, then the handle didn't exist if (Node == NULL) { // Just release access from the list, and return an error T2ConnList_LeaveQueue(); return FALSE; } // Change it Node->msStartTime = msStartTime; // Release access from the list, and return success T2ConnList_LeaveQueue(); return TRUE; } // T2ConnList_FindHandleByTimerId // // Finds the first handle with the specified matching timer id. // // Returns the handle on success, or NULL if a handle // with the specified timer id did not existed. HANDLE T2ConnList_FindHandleByTimerId(UINT_PTR TimerId) { HANDLE Handle; ConnList *Node; // Gain access to the list T2ConnList_EnterQueue(); Node = Head; // Find the first matching timer in the list for (; Node != NULL && Node->TimerId != TimerId; Node = Node->Next); // If the Node pointer is NULL, then a handle didn't exist if (Node == NULL) { // Just release access from the list, and return an error T2ConnList_LeaveQueue(); return NULL; } // Found a handle, record it Handle = Node->Handle; // Release access from the list and return our found handle T2ConnList_LeaveQueue(); return Handle; } // T2ConnList_FindHandleByStartTime // // Finds the first handle with the specified matching start time. // // Returns the handle on success, or NULL if a handle // with the specified start time did not exist. HANDLE T2ConnList_FindHandleByStartTime(DWORD msStartTime) { HANDLE Handle; ConnList *Node; // Gain access to the list T2ConnList_EnterQueue(); Node = Head; // Find the first matching start time in the list for (; Node != NULL && Node->msStartTime != msStartTime; Node = Node->Next); // If the Node pointer is NULL, then a handle didn't exist if (Node == NULL) { // Just release access from the list, and return an error T2ConnList_LeaveQueue(); return NULL; } // Found a handle, record it Handle = Node->Handle; // Release access from the list and return our found handle T2ConnList_LeaveQueue(); return Handle; }