// the way handles work, so it's more dynamic now
-HBITMAP hPseudoStockBitmap; /* 1x1 bitmap for memory DCs */
+HBITMAP hPseudoStockBitmap; /*! 1x1 bitmap for memory DCs */
static PGDI_HANDLE_TABLE HandleTable = 0;
static FAST_MUTEX HandleTableMutex;
static FAST_MUTEX RefCountHandling;
+/*! Size of the GDI handle table
+ * per http://www.wd-mag.com/articles/1999/9902/9902b/9902b.htm?topic=articles
+ * gdi handle table can hold 0x4000 handles
+*/
#define GDI_HANDLE_NUMBER 0x4000
+/*!
+ * Allocate GDI object table.
+ * \param Size - number of entries in the object table.
+*/
static PGDI_HANDLE_TABLE
GDIOBJ_iAllocHandleTable (WORD Size)
{
return handleTable;
}
+/*!
+ * Returns the entry into the handle table by index.
+*/
static PGDI_HANDLE_ENTRY
GDIOBJ_iGetHandleEntryForIndex (WORD TableIndex)
{
return ((PGDI_HANDLE_ENTRY)HandleTable->Handles+TableIndex);
}
+/*!
+ * Finds next free entry in the GDI handle table.
+ * \return index into the table is successful, zero otherwise.
+*/
static WORD
GDIOBJ_iGetNextOpenHandleIndex (void)
{
return (tableIndex < HandleTable->wTableSize) ? tableIndex : 0;
}
-/*-----------------7/12/2002 11:38AM----------------
- * Allocate memory for GDI object and return handle to it
- * Use GDIOBJ_Lock to obtain pointer to the new object.
- * --------------------------------------------------*/
+/*!
+ * Allocate memory for GDI object and return handle to it.
+ *
+ * \param Size - size of the GDI object. This shouldn't to include the size of GDIOBJHDR.
+ * The actual amount of allocated memory is sizeof(GDIOBJHDR)+Size
+ * \param Magic - object magic (see GDI Magic)
+ *
+ * \return Handle of the allocated object.
+ *
+ * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
+*/
HGDIOBJ GDIOBJ_AllocObj(WORD Size, WORD Magic)
{
PGDIOBJHDR newObject;
return (HGDIOBJ) newObject->wTableIndex;
}
+/*!
+ * Free memory allocated for the GDI object. For each object type this function calls the
+ * appropriate cleanup routine.
+ *
+ * \param hObj - handle of the object to be deleted.
+ * \param Magic - object magic or GO_MAGIC_DONTCARE.
+ * \param Flag - if set to GDIOBJFLAG_IGNOREPID then the routine doesn't check if the process that
+ * tries to delete the object is the same one that created it.
+ *
+ * \return Returns TRUE if succesful.
+ *
+ * \note You should only use GDIOBJFLAG_IGNOREPID if you are cleaning up after the process that terminated.
+ * \note This function deferres object deletion if it is still in use.
+*/
BOOL GDIOBJ_FreeObj(HGDIOBJ hObj, WORD Magic, DWORD Flag)
{
PGDIOBJHDR objectHeader;
handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)hObj & 0xffff);
DPRINT("GDIOBJ_FreeObj: hObj: %d, magic: %x, handleEntry: %x\n", (WORD)hObj & 0xffff, Magic, handleEntry );
+
if (handleEntry == 0 || (handleEntry->wMagic != Magic && Magic != GO_MAGIC_DONTCARE )
|| ((handleEntry->hProcessId != PsGetCurrentProcessId()) && !(Flag & GDIOBJFLAG_IGNOREPID))){
+
DPRINT("Can't Delete hObj: %d, magic: %x, pid:%d\n currpid:%d, flag:%d, hmm:%d\n",(WORD)hObj & 0xffff, handleEntry->wMagic, handleEntry->hProcessId, PsGetCurrentProcessId(), (Flag&GDIOBJFLAG_IGNOREPID), ((handleEntry->hProcessId != PsGetCurrentProcessId()) && !(Flag&GDIOBJFLAG_IGNOREPID)) );
return FALSE;
}
handleEntry->hProcessId = 0;
ExFreePool (handleEntry->pObject);
handleEntry->pObject = 0;
- // (RJJ) set wMagic last to avoid race condition
handleEntry->wMagic = 0;
-
return TRUE;
}
+/*!
+ * Return pointer to the object by handle.
+ *
+ * \param hObj Object handle
+ * \param Magic one of the magic numbers defined in \ref GDI Magic
+ * \return Pointer to the object.
+ *
+ * \note Process can only get pointer to the objects it created or global objects.
+ *
+ * \todo Don't allow to lock the objects twice! Synchronization!
+*/
PGDIOBJ GDIOBJ_LockObj( HGDIOBJ hObj, WORD Magic )
{
PGDI_HANDLE_ENTRY handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) hObj & 0xffff);
objectHeader = (PGDIOBJHDR) handleEntry->pObject;
ASSERT(objectHeader);
+ if( objectHeader->dwCount > 0 ){
+ DbgPrint("Caution! GDIOBJ_LockObj trying to lock object second time\n" );
+ DbgPrint("\t called from: %x\n", __builtin_return_address(0));
+ }
ExAcquireFastMutex(&RefCountHandling);
objectHeader->dwCount++;
ExReleaseFastMutex(&RefCountHandling);
-
- DPRINT("GDIOBJ_LockObj: PGDIOBJ %x\n", ((PCHAR)objectHeader + sizeof(GDIOBJHDR)) );
return (PGDIOBJ)((PCHAR)objectHeader + sizeof(GDIOBJHDR));
}
+/*!
+ * Lock multiple objects. Use this function when you need to lock multiple objects and some of them may be
+ * duplicates. You should use this function to avoid trying to lock the same object twice!
+ *
+ * \param pList pointer to the list that contains handles to the objects. You should set hObj and Magic fields.
+ * \param nObj number of objects to lock
+ * \return for each entry in pList this function sets pObj field to point to the object.
+ *
+ * \note this function uses an O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
+*/
+BOOL GDIOBJ_LockMultipleObj( PGDIMULTILOCK pList, INT nObj )
+{
+ INT i, j;
+ ASSERT( pList );
+ //go through the list checking for duplicate objects
+ for( i = 0; i < nObj; i++ ){
+ (pList+i)->pObj = NULL;
+ for( j = 0; j < i; j++ ){
+ if( ((pList+i)->hObj == (pList+j)->hObj)
+ && ((pList+i)->Magic == (pList+j)->Magic) ){
+ //already locked, so just copy the pointer to the object
+ (pList+i)->pObj = (pList+j)->pObj;
+ break;
+ }
+ }
+ if( (pList+i)->pObj == NULL ){
+ //object hasn't been locked, so lock it.
+ (pList+i)->pObj = GDIOBJ_LockObj( (pList+i)->hObj, (pList+i)->Magic );
+ }
+ }
+ return TRUE;
+}
+
+/*!
+ * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
+ * as soon as you don't need to have access to it's data.
+
+ * \param hObj Object handle
+ * \param Magic one of the magic numbers defined in \ref GDI Magic
+ *
+ * \note This function performs delayed cleanup. If the object is locked when GDI_FreeObj() is called
+ * then \em this function frees the object when reference count is zero.
+ *
+ * \todo Change synchronization algorithm.
+*/
BOOL GDIOBJ_UnlockObj( HGDIOBJ hObj, WORD Magic )
{
PGDI_HANDLE_ENTRY handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD) hObj & 0xffff);
return TRUE;
}
-/*
-PGDIOBJ GDIOBJ_AllocObject(WORD Size, WORD Magic)
-{
- PGDIOBJHDR newObject;
- PGDI_HANDLE_ENTRY handleEntry;
-
- newObject = ExAllocatePool (PagedPool, Size + sizeof (GDIOBJHDR));
- if (newObject == NULL)
- {
- return NULL;
- }
- RtlZeroMemory (newObject, Size + sizeof (GDIOBJHDR));
-
- newObject->wTableIndex = GDIOBJ_iGetNextOpenHandleIndex ();
- handleEntry = GDIOBJ_iGetHandleEntryForIndex (newObject->wTableIndex);
- handleEntry->wMagic = Magic;
- handleEntry->hProcessId = PsGetCurrentProcessId ();
- handleEntry->pObject = newObject;
-
- return (PGDIOBJ)(((PCHAR) newObject) + sizeof (GDIOBJHDR));
-}
-
-BOOL GDIOBJ_FreeObject (PGDIOBJ Obj, WORD Magic)
-{
- PGDIOBJHDR objectHeader;
- PGDI_HANDLE_ENTRY handleEntry;
- objectHeader = (PGDIOBJHDR)(((PCHAR)Obj) - sizeof (GDIOBJHDR));
- handleEntry = GDIOBJ_iGetHandleEntryForIndex (objectHeader->wTableIndex);
- if (handleEntry == 0 || handleEntry->wMagic != Magic)
- return FALSE;
- handleEntry->hProcessId = 0;
- handleEntry->pObject = 0;
- // (RJJ) set wMagic last to avoid race condition
- handleEntry->wMagic = 0;
- ExFreePool (objectHeader);
-
- return TRUE;
-}
-
-HGDIOBJ GDIOBJ_PtrToHandle (PGDIOBJ Obj, WORD Magic)
+/*!
+ * Unlock multiple objects. Use this function when you need to unlock multiple objects and some of them may be
+ * duplicates.
+ *
+ * \param pList pointer to the list that contains handles to the objects. You should set hObj and Magic fields.
+ * \param nObj number of objects to lock
+ *
+ * \note this function uses O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
+*/
+BOOL GDIOBJ_UnlockMultipleObj( PGDIMULTILOCK pList, INT nObj )
{
- PGDIOBJHDR objectHeader;
- PGDI_HANDLE_ENTRY handleEntry;
-
- if (Obj == NULL)
- return NULL;
- objectHeader = (PGDIOBJHDR) (((PCHAR)Obj) - sizeof (GDIOBJHDR));
- handleEntry = GDIOBJ_iGetHandleEntryForIndex (objectHeader->wTableIndex);
- if (handleEntry == 0 ||
- handleEntry->wMagic != Magic ||
- handleEntry->hProcessId != PsGetCurrentProcessId () )
- return NULL;
-
- return (HGDIOBJ) objectHeader->wTableIndex;
+ INT i, j;
+ ASSERT( pList );
+ //go through the list checking for duplicate objects
+ for( i = 0; i < nObj; i++ ){
+ if( (pList+i)->pObj != NULL ){
+ for( j = i+1; j < nObj; j++ ){
+ if( ((pList+i)->pObj == (pList+j)->pObj) ){
+ //set the pointer to zero for all duplicates
+ (pList+j)->pObj = NULL;
+ }
+ }
+ GDIOBJ_UnlockObj( (pList+i)->hObj, (pList+i)->Magic );
+ (pList+i)->pObj = NULL;
+ }
+ }
+ return TRUE;
}
-PGDIOBJ GDIOBJ_HandleToPtr (HGDIOBJ ObjectHandle, WORD Magic)
-{
- PGDI_HANDLE_ENTRY handleEntry;
-
- if (ObjectHandle == NULL)
- return NULL;
-
- handleEntry = GDIOBJ_iGetHandleEntryForIndex ((WORD)ObjectHandle & 0xffff);
- if (handleEntry == 0 ||
- (Magic != GO_MAGIC_DONTCARE && Magic != Magic) ||
- handleEntry->hProcessId != PsGetCurrentProcessId () )
- return NULL;
-
- return (PGDIOBJ) (((PCHAR)handleEntry->pObject) + sizeof (GDIOBJHDR));
-}
+/*!
+ * Marks the object as global. (Creator process ID is set to 0xFFFFFFFF). Global objects may be
+ * accessed by any process.
+ * \param ObjectHandle - handle of the object to make global.
+ *
+ * \note Only stock objects should be marked global.
*/
-
VOID GDIOBJ_MarkObjectGlobal(HGDIOBJ ObjectHandle)
{
PGDI_HANDLE_ENTRY handleEntry;
handleEntry->hProcessId = (HANDLE)0xFFFFFFFF;
}
+/*!
+ * Get the type (magic value) of the object.
+ * \param ObjectHandle - handle of the object.
+ * \return GDI Magic value.
+*/
WORD GDIOBJ_GetHandleMagic (HGDIOBJ ObjectHandle)
{
PGDI_HANDLE_ENTRY handleEntry;
return handleEntry->wMagic;
}
+/*!
+ * Initialization of the GDI object engine.
+*/
VOID
InitGdiObjectHandleTable (void)
{
DPRINT ("InitGdiObjectHandleTable\n");
ExInitializeFastMutex (&HandleTableMutex);
ExInitializeFastMutex (&RefCountHandling);
- //per http://www.wd-mag.com/articles/1999/9902/9902b/9902b.htm?topic=articles
- //gdi handle table can hold 0x4000 handles
+
HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_NUMBER);
DPRINT("HandleTable: %x\n", HandleTable );
InitEngHandleTable();
}
+/*!
+ * Creates a bunch of stock objects: brushes, pens, fonts.
+*/
VOID CreateStockObjects(void)
{
// Create GDI Stock Objects from the logical structures we've defined
StockObjects[DEFAULT_PALETTE] = (HGDIOBJ*)PALETTE_Init();
}
+/*!
+ * Return stock object.
+ * \param Object - stock object id.
+ * \return Handle to the object.
+*/
HGDIOBJ STDCALL W32kGetStockObject(INT Object)
{
- HGDIOBJ ret;
-
-/* if ((Object < 0) || (Object >= NB_STOCK_OBJECTS)) return 0;
- if (!StockObjects[Object]) return 0;
- ret = FIRST_STOCK_HANDLE + Object;
-
- return ret; */
-
- return StockObjects[Object]; // FIXME........
+ // check when adding new objects
+ if( (Object < 0) || (Object >= NB_STOCK_OBJECTS) )
+ return NULL;
+ return StockObjects[Object];
}
+/*!
+ * Delete GDI object
+ * \param hObject object handle
+ * \return if the function fails the returned value is NULL.
+*/
BOOL STDCALL W32kDeleteObject(HGDIOBJ hObject)
{
return GDIOBJ_FreeObj( hObject, GO_MAGIC_DONTCARE, GDIOBJFLAG_DEFAULT );
}
+/*!
+ * Internal function. Called when the process is destroyed to free the remaining GDI handles.
+ * \param Process - PID of the process that was destroyed.
+*/
BOOL STDCALL W32kCleanupForProcess( INT Process )
{
DWORD i;
return TRUE;
}
-// dump all the objects for process. if process == 0 dump all the objects
+/*!
+ * Internal function. Dumps all the objects for the given process.
+ * \param If process == 0 dump all the objects.
+ *
+*/
VOID STDCALL W32kDumpGdiObjects( INT Process )
{
DWORD i;