From 42d1255857cec3f679782ad8c9dba863daab2047 Mon Sep 17 00:00:00 2001 From: "Sylvain St.Germain" Date: Sat, 13 Feb 1999 08:59:48 +0000 Subject: [PATCH] Implementation of a simple linked list (static) that stores and counts references to COM objects. --- ole/compobj.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 279 insertions(+), 3 deletions(-) diff --git a/ole/compobj.c b/ole/compobj.c index c6d329bfd02..97e6f466743 100644 --- a/ole/compobj.c +++ b/ole/compobj.c @@ -4,6 +4,7 @@ * Copyright 1995 Martin von Loewis * Copyright 1998 Justin Bradford * Copyright 1999 Francis Beaudet + * Copyright 1999 Sylvain St-Germain */ #include "config.h" @@ -44,6 +45,70 @@ #include "objbase.h" +/**************************************************************************** + * COM External Lock structures and methods declaration + * + * This api provides a linked list to managed external references to + * COM objects. + * + * The public interface consists of three calls: + * COM_ExternalLockAddRef + * COM_ExternalLockRelease + * COM_ExternalLockFreeList + */ + +#define EL_END_OF_LIST 0 +#define EL_NOT_FOUND 0 + +/* + * Declaration of the static structure that manage the + * external lock to COM objects. + */ +typedef struct COM_ExternalLock COM_ExternalLock; +typedef struct COM_ExternalLockList COM_ExternalLockList; + +struct COM_ExternalLock +{ + IUnknown *pUnk; /* IUnknown referenced */ + ULONG uRefCount; /* external lock counter to IUnknown object*/ + COM_ExternalLock *next; /* Pointer to next element in list */ +}; + +struct COM_ExternalLockList +{ + COM_ExternalLock *head; /* head of list */ +}; + +/* + * Declaration and initialization of the static structure that manages + * the external lock to COM objects. + */ +static COM_ExternalLockList elList = { EL_END_OF_LIST }; + +/* + * Public Interface to the external lock list + */ +static void COM_ExternalLockFreeList(); +static void COM_ExternalLockAddRef(IUnknown *pUnk); +static void COM_ExternalLockRelease(IUnknown *pUnk, BOOL32 bRelAll); +void COM_ExternalLockDump(); /* testing purposes, not static to avoid warning */ + +/* + * Private methods used to managed the linked list + */ +static BOOL32 COM_ExternalLockInsert( + IUnknown *pUnk); + +static void COM_ExternalLockDelete( + COM_ExternalLock *element); + +static COM_ExternalLock* COM_ExternalLockFind( + IUnknown *pUnk); + +static COM_ExternalLock* COM_ExternalLockLocate( + COM_ExternalLock *element, + IUnknown *pUnk); + /**************************************************************************** * This section defines variables internal to the COM module. * @@ -260,6 +325,11 @@ void WINAPI CoUninitialize32(void) * This will free the loaded COM Dlls. */ CoFreeAllLibraries(); + + /* + * This will free list of external references to COM objects. + */ + COM_ExternalLockFreeList(); } } @@ -1420,9 +1490,26 @@ HRESULT WINAPI CoLockObjectExternal16( HRESULT WINAPI CoLockObjectExternal32( LPUNKNOWN pUnk, /* [in] object to be locked */ BOOL32 fLock, /* [in] do lock */ - BOOL32 fLastUnlockReleases /* [in] ? */ -) { - FIXME(ole,"(%p,%d,%d),stub!\n",pUnk,fLock,fLastUnlockReleases); + BOOL32 fLastUnlockReleases) /* [in] unlock all */ +{ + + if (fLock) + { + /* + * Increment the external lock coutner, COM_ExternalLockAddRef also + * increment the object's internal lock counter. + */ + COM_ExternalLockAddRef( pUnk); + } + else + { + /* + * Decrement the external lock coutner, COM_ExternalLockRelease also + * decrement the object's internal lock counter. + */ + COM_ExternalLockRelease( pUnk, fLastUnlockReleases); + } + return S_OK; } @@ -1460,3 +1547,192 @@ static void COM_RevokeAllClasses() } } +/**************************************************************************** + * COM External Lock methods implementation + */ + +/**************************************************************************** + * Public - Method that increments the count for a IUnknown* in the linked + * list. The item is inserted if not already in the list. + */ +static void COM_ExternalLockAddRef( + IUnknown *pUnk) +{ + COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk); + + if ( externalLock == EL_NOT_FOUND ) + COM_ExternalLockInsert(pUnk); + else + { + externalLock->uRefCount++; /* add an external lock */ + IUnknown_AddRef(pUnk); /* add a local lock as well */ + } +} + +/**************************************************************************** + * Public - Method that decrements the count for a IUnknown* in the linked + * list. The item is removed from the list if its count end up at zero or if + * bRelAll is TRUE. + */ +static void COM_ExternalLockRelease( + IUnknown *pUnk, + BOOL32 bRelAll) +{ + COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk); + + if ( externalLock != EL_NOT_FOUND ) + { + do + { + externalLock->uRefCount--; /* release external locks */ + IUnknown_Release(pUnk); /* release local locks as well */ + + if ( bRelAll == FALSE ) + break; /* perform single release */ + + } while ( externalLock->uRefCount > 0 ); + + if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */ + COM_ExternalLockDelete(externalLock); + } +} +/**************************************************************************** + * Public - Method that frees the content of the list. + */ +static void COM_ExternalLockFreeList() +{ + COM_ExternalLock *head; + + do + { + head = elList.head; /* grab it be the head */ + COM_ExternalLockDelete(head); /* get rid of the head stuff */ + + head = elList.head; /* get the new head... */ + + } while ( head != EL_END_OF_LIST ); /* repeat as long as we have heads */ +} + +/**************************************************************************** + * Public - Method that dump the content of the list. + */ +void COM_ExternalLockDump() +{ + COM_ExternalLock *current = elList.head; + + printf("\nExternal lock list contains:\n"); + + while ( current != EL_END_OF_LIST ) + { + printf( "\t%p with %lu references count.\n", + current->pUnk, + current->uRefCount); + + /* Skip to the next item */ + current = current->next; + } + +} + +/**************************************************************************** + * Internal - Find a IUnknown* in the linked list + */ +static COM_ExternalLock* COM_ExternalLockFind( + IUnknown *pUnk) +{ + return COM_ExternalLockLocate(elList.head, pUnk); +} + +/**************************************************************************** + * Internal - Recursivity agent for IUnknownExternalLockList_Find + */ +static COM_ExternalLock* COM_ExternalLockLocate( + COM_ExternalLock *element, + IUnknown *pUnk) +{ + if ( element == EL_END_OF_LIST ) + return EL_NOT_FOUND; + + else if ( element->pUnk == pUnk ) /* We found it */ + return element; + + else /* Not the right guy, keep on looking */ + return COM_ExternalLockLocate( element->next, pUnk); +} + +/**************************************************************************** + * Internal - Insert a new IUnknown* to the linked list + */ +static BOOL32 COM_ExternalLockInsert( + IUnknown *pUnk) +{ + COM_ExternalLock *newLock = NULL; + COM_ExternalLock *previousHead = NULL; + + /* + * Allocate space for the new storage object + */ + newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock)); + + if (newLock!=NULL) + { + if ( elList.head == EL_END_OF_LIST ) + { + elList.head = newLock; /* The list is empty */ + } + else + { + /* + * insert does it at the head + */ + previousHead = elList.head; + elList.head = newLock; + } + + /* + * Set new list item data member + */ + newLock->pUnk = pUnk; + newLock->uRefCount = 1; + newLock->next = previousHead; + + return TRUE; + } + else + return FALSE; +} + +/**************************************************************************** + * Internal - Method that removes an item from the linked list. + */ +static void COM_ExternalLockDelete( + COM_ExternalLock *itemList) +{ + COM_ExternalLock *current = elList.head; + + if ( current == itemList ) + { + /* + * this section handles the deletion of the first node + */ + elList.head = itemList->next; + HeapFree( GetProcessHeap(), 0, itemList); + } + else + { + do + { + if ( current->next == itemList ) /* We found the item to free */ + { + current->next = itemList->next; /* readjust the list pointers */ + + HeapFree( GetProcessHeap(), 0, itemList); + break; + } + + /* Skip to the next item */ + current = current->next; + + } while ( current != EL_END_OF_LIST ); + } +}