2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * GDIOBJ.C - GDI object manipulation routines
22 * $Id: gdiobj.c,v 1.73 2004/10/02 16:48:12 navaraf Exp $
27 /* count all gdi objects */
28 #define GDI_COUNT_OBJECTS 1
30 /*! Size of the GDI handle table
31 * http://www.windevnet.com/documents/s=7290/wdj9902b/9902b.htm
32 * gdi handle table can hold 0x4000 handles
34 #define GDI_HANDLE_COUNT 0x4000
36 #define GDI_GLOBAL_PROCESS ((HANDLE) 0xffffffff)
38 #define GDI_HANDLE_INDEX_MASK (GDI_HANDLE_COUNT - 1)
39 #define GDI_HANDLE_TYPE_MASK 0x007f0000
40 #define GDI_HANDLE_STOCK_MASK 0x00800000
42 #define GDI_HANDLE_CREATE(i, t) ((HANDLE)(((i) & GDI_HANDLE_INDEX_MASK) | ((t) & GDI_HANDLE_TYPE_MASK)))
43 #define GDI_HANDLE_GET_INDEX(h) (((DWORD)(h)) & GDI_HANDLE_INDEX_MASK)
44 #define GDI_HANDLE_GET_TYPE(h) (((DWORD)(h)) & GDI_HANDLE_TYPE_MASK)
45 #define GDI_HANDLE_IS_TYPE(h, t) ((t) == (((DWORD)(h)) & GDI_HANDLE_TYPE_MASK))
46 #define GDI_HANDLE_IS_STOCKOBJ(h) (0 != (((DWORD)(h)) & GDI_HANDLE_STOCK_MASK))
47 #define GDI_HANDLE_SET_STOCKOBJ(h) ((h) = (HANDLE)(((DWORD)(h)) | GDI_HANDLE_STOCK_MASK))
49 #define GDI_TYPE_TO_MAGIC(t) ((WORD) ((t) >> 16))
50 #define GDI_MAGIC_TO_TYPE(m) ((DWORD)(m) << 16)
52 /* FIXME Ownership of GDI objects by processes not properly implemented yet */
54 #define GDI_VALID_OBJECT(h, obj, t, f) \
56 && (GDI_MAGIC_TO_TYPE((obj)->Magic) == (t) || GDI_OBJECT_TYPE_DONTCARE == (t)) \
57 && (GDI_HANDLE_GET_TYPE((h)) == GDI_MAGIC_TO_TYPE((obj)->Magic)) \
58 && (((obj)->hProcessId == PsGetCurrentProcessId()) \
59 || (GDI_GLOBAL_PROCESS == (obj)->hProcessId) \
60 || ((f) & GDIOBJFLAG_IGNOREPID)))
62 #define GDI_VALID_OBJECT(h, obj, t, f) \
64 && (GDI_MAGIC_TO_TYPE((obj)->Magic) == (t) || GDI_OBJECT_TYPE_DONTCARE == (t)) \
65 && (GDI_HANDLE_GET_TYPE((h)) == GDI_MAGIC_TO_TYPE((obj)->Magic)))
68 typedef struct _GDI_HANDLE_TABLE
75 PPAGED_LOOKASIDE_LIST LookasideLists
;
76 PGDIOBJHDR Handles
[1];
77 } GDI_HANDLE_TABLE
, *PGDI_HANDLE_TABLE
;
86 GDI_OBJ_SIZE ObjSizes
[] =
88 /* Testing shows that regions are the most used GDIObj type,
89 so put that one first for performance */
90 {GDI_OBJECT_TYPE_REGION
, sizeof(ROSRGNDATA
)},
91 {GDI_OBJECT_TYPE_BITMAP
, sizeof(BITMAPOBJ
)},
92 {GDI_OBJECT_TYPE_DC
, sizeof(DC
)},
93 {GDI_OBJECT_TYPE_PALETTE
, sizeof(PALGDI
)},
94 {GDI_OBJECT_TYPE_BRUSH
, sizeof(GDIBRUSHOBJ
)},
95 {GDI_OBJECT_TYPE_PEN
, sizeof(GDIBRUSHOBJ
)},
96 {GDI_OBJECT_TYPE_FONT
, sizeof(TEXTOBJ
)},
97 {GDI_OBJECT_TYPE_DCE
, sizeof(DCE
)},
99 {GDI_OBJECT_TYPE_DIRECTDRAW, sizeof(DD_DIRECTDRAW)},
100 {GDI_OBJECT_TYPE_DD_SURFACE, sizeof(DD_SURFACE)},
102 {GDI_OBJECT_TYPE_EXTPEN
, 0},
103 {GDI_OBJECT_TYPE_METADC
, 0},
104 {GDI_OBJECT_TYPE_METAFILE
, 0},
105 {GDI_OBJECT_TYPE_ENHMETAFILE
, 0},
106 {GDI_OBJECT_TYPE_ENHMETADC
, 0},
107 {GDI_OBJECT_TYPE_MEMDC
, 0},
108 {GDI_OBJECT_TYPE_EMF
, 0}
111 #define OBJTYPE_COUNT (sizeof(ObjSizes) / sizeof(ObjSizes[0]))
113 /* GDI stock objects */
115 static LOGBRUSH WhiteBrush
=
116 { BS_SOLID
, RGB(255,255,255), 0 };
118 static LOGBRUSH LtGrayBrush
=
119 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
120 { BS_SOLID
, RGB(192,192,192), 0 };
122 static LOGBRUSH GrayBrush
=
123 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
124 { BS_SOLID
, RGB(128,128,128), 0 };
126 static LOGBRUSH DkGrayBrush
=
127 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
128 /* NB_HATCH_STYLES is an index into HatchBrushes */
129 { BS_HATCHED
, RGB(0,0,0), NB_HATCH_STYLES
};
131 static LOGBRUSH BlackBrush
=
132 { BS_SOLID
, RGB(0,0,0), 0 };
134 static LOGBRUSH NullBrush
=
137 static LOGPEN WhitePen
=
138 { PS_SOLID
, { 0, 0 }, RGB(255,255,255) };
140 static LOGPEN BlackPen
=
141 { PS_SOLID
, { 0, 0 }, RGB(0,0,0) };
143 static LOGPEN NullPen
=
144 { PS_NULL
, { 0, 0 }, 0 };
146 static LOGFONTW OEMFixedFont
=
147 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, OEM_CHARSET
,
148 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
, L
"Bitstream Vera Sans Mono" };
150 static LOGFONTW AnsiFixedFont
=
151 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
152 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
, L
"Bitstream Vera Sans Mono" };
154 /*static LOGFONTW AnsiVarFont =
155 *{ 10, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
156 * 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" }; */
158 static LOGFONTW SystemFont
=
159 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
160 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
, L
"Bitstream Vera Sans" };
162 static LOGFONTW DeviceDefaultFont
=
163 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
164 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
, L
"Bitstream Vera Sans" };
166 static LOGFONTW SystemFixedFont
=
167 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
168 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
, L
"Bitstream Vera Sans Mono" };
170 /* FIXME: Is this correct? */
171 static LOGFONTW DefaultGuiFont
=
172 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
173 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
, L
"Bitstream Vera Sans" };
175 #define NB_STOCK_OBJECTS (DEFAULT_GUI_FONT + 1)
177 static HGDIOBJ StockObjects
[NB_STOCK_OBJECTS
];
178 static PGDI_HANDLE_TABLE HandleTable
= 0;
179 static FAST_MUTEX HandleTableMutex
;
180 static FAST_MUTEX RefCountHandling
;
181 static LARGE_INTEGER ShortDelay
;
184 * Allocate GDI object table.
185 * \param Size - number of entries in the object table.
186 * Notes:: Must be called at IRQL < DISPATCH_LEVEL.
188 static PGDI_HANDLE_TABLE FASTCALL
189 GDIOBJ_iAllocHandleTable (WORD Size
)
191 PGDI_HANDLE_TABLE handleTable
;
195 MemSize
= sizeof(GDI_HANDLE_TABLE
) + sizeof(PGDIOBJ
) * Size
;
197 ExAcquireFastMutex(&HandleTableMutex
);
198 handleTable
= ExAllocatePoolWithTag(PagedPool
, MemSize
, TAG_GDIHNDTBLE
);
199 ASSERT( handleTable
);
200 memset (handleTable
, 0, MemSize
);
201 #if GDI_COUNT_OBJECTS
202 handleTable
->HandlesCount
= 0;
204 handleTable
->wTableSize
= Size
;
205 handleTable
->AllocationHint
= 1;
206 handleTable
->LookasideLists
= ExAllocatePoolWithTag(PagedPool
,
207 OBJTYPE_COUNT
* sizeof(PAGED_LOOKASIDE_LIST
),
209 if (NULL
== handleTable
->LookasideLists
)
211 ExFreePool(handleTable
);
212 ExReleaseFastMutex(&HandleTableMutex
);
215 for (ObjType
= 0; ObjType
< OBJTYPE_COUNT
; ObjType
++)
217 ExInitializePagedLookasideList(handleTable
->LookasideLists
+ ObjType
, NULL
, NULL
, 0,
218 ObjSizes
[ObjType
].Size
+ sizeof(GDIOBJHDR
), TAG_GDIOBJ
, 0);
220 ExReleaseFastMutex(&HandleTableMutex
);
226 * Returns the entry into the handle table by index.
228 static PGDIOBJHDR FASTCALL
229 GDIOBJ_iGetObjectForIndex(WORD TableIndex
)
231 if (0 == TableIndex
|| HandleTable
->wTableSize
< TableIndex
)
233 DPRINT1("Invalid TableIndex %u\n", (unsigned) TableIndex
);
237 return HandleTable
->Handles
[TableIndex
];
241 * Finds next free entry in the GDI handle table.
242 * \return index into the table is successful, zero otherwise.
245 GDIOBJ_iGetNextOpenHandleIndex (void)
249 for (tableIndex
= HandleTable
->AllocationHint
;
250 tableIndex
< HandleTable
->wTableSize
;
253 if (HandleTable
->Handles
[tableIndex
] == NULL
)
255 HandleTable
->AllocationHint
= tableIndex
+ 1;
261 tableIndex
< HandleTable
->AllocationHint
;
264 if (HandleTable
->Handles
[tableIndex
] == NULL
)
266 HandleTable
->AllocationHint
= tableIndex
+ 1;
274 static PPAGED_LOOKASIDE_LIST FASTCALL
275 FindLookasideList(DWORD ObjectType
)
279 for (Index
= 0; Index
< OBJTYPE_COUNT
; Index
++)
281 if (ObjSizes
[Index
].Type
== ObjectType
)
283 return HandleTable
->LookasideLists
+ Index
;
287 DPRINT1("Can't find lookaside list for object type 0x%08x\n", ObjectType
);
293 * Allocate memory for GDI object and return handle to it.
295 * \param Size - size of the GDI object. This shouldn't to include the size of GDIOBJHDR.
296 * The actual amount of allocated memory is sizeof(GDIOBJHDR)+Size
297 * \param ObjectType - type of object \ref GDI object types
298 * \param CleanupProcPtr - Routine to be called on destruction of object
300 * \return Handle of the allocated object.
302 * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
305 GDIOBJ_AllocObj(WORD Size
, DWORD ObjectType
, GDICLEANUPPROC CleanupProc
)
307 PW32PROCESS W32Process
;
308 PGDIOBJHDR newObject
;
310 PPAGED_LOOKASIDE_LIST LookasideList
;
312 ExAcquireFastMutex(&HandleTableMutex
);
313 Index
= GDIOBJ_iGetNextOpenHandleIndex ();
316 ExReleaseFastMutex(&HandleTableMutex
);
317 DPRINT1("Out of GDI handles\n");
321 LookasideList
= FindLookasideList(ObjectType
);
322 if (NULL
== LookasideList
)
324 ExReleaseFastMutex(&HandleTableMutex
);
327 newObject
= ExAllocateFromPagedLookasideList(LookasideList
);
328 if (NULL
== newObject
)
330 ExReleaseFastMutex(&HandleTableMutex
);
331 DPRINT1("Unable to allocate GDI object from lookaside list\n");
334 RtlZeroMemory (newObject
, Size
+ sizeof(GDIOBJHDR
));
336 newObject
->wTableIndex
= Index
;
338 newObject
->dwCount
= 0;
339 newObject
->hProcessId
= PsGetCurrentProcessId ();
340 newObject
->CleanupProc
= CleanupProc
;
341 newObject
->Magic
= GDI_TYPE_TO_MAGIC(ObjectType
);
342 newObject
->lockfile
= NULL
;
343 newObject
->lockline
= 0;
344 #ifdef GDIOBJ_USE_FASTMUTEX
345 ExInitializeFastMutex(&newObject
->Lock
);
346 newObject
->RecursiveLockCount
= 0;
348 newObject
->LockTid
= 0;
349 newObject
->LockCount
= 0;
351 HandleTable
->Handles
[Index
] = newObject
;
352 #if GDI_COUNT_OBJECTS
353 HandleTable
->HandlesCount
++;
355 ExReleaseFastMutex(&HandleTableMutex
);
357 W32Process
= PsGetCurrentProcess()->Win32Process
;
360 W32Process
->GDIObjects
++;
363 return GDI_HANDLE_CREATE(Index
, ObjectType
);
367 * Free memory allocated for the GDI object. For each object type this function calls the
368 * appropriate cleanup routine.
370 * \param hObj - handle of the object to be deleted.
371 * \param ObjectType - one of the \ref GDI object types
372 * or GDI_OBJECT_TYPE_DONTCARE.
373 * \param Flag - if set to GDIOBJFLAG_IGNOREPID then the routine doesn't check if the process that
374 * tries to delete the object is the same one that created it.
376 * \return Returns TRUE if succesful.
378 * \note You should only use GDIOBJFLAG_IGNOREPID if you are cleaning up after the process that terminated.
379 * \note This function deferres object deletion if it is still in use.
382 GDIOBJ_FreeObj(HGDIOBJ hObj
, DWORD ObjectType
, DWORD Flag
)
384 PW32PROCESS W32Process
;
385 PGDIOBJHDR objectHeader
;
387 PPAGED_LOOKASIDE_LIST LookasideList
;
390 objectHeader
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
391 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x, object: %x\n", hObj
, objectHeader
);
393 if (! GDI_VALID_OBJECT(hObj
, objectHeader
, ObjectType
, Flag
)
394 || GDI_GLOBAL_PROCESS
== objectHeader
->hProcessId
)
397 DPRINT1("Can't delete hObj:0x%08x, type:0x%08x, flag:%d\n", hObj
, ObjectType
, Flag
);
401 DPRINT("FreeObj: locks: %x\n", objectHeader
->dwCount
);
402 if (!(Flag
& GDIOBJFLAG_IGNORELOCK
))
404 /* check that the reference count is zero. if not then set flag
405 * and delete object when releaseobj is called */
406 ExAcquireFastMutex(&RefCountHandling
);
407 if ((objectHeader
->dwCount
& ~0x80000000) > 0 )
409 DPRINT("GDIOBJ_FreeObj: delayed object deletion: count %d\n", objectHeader
->dwCount
);
410 objectHeader
->dwCount
|= 0x80000000;
411 ExReleaseFastMutex(&RefCountHandling
);
414 ExReleaseFastMutex(&RefCountHandling
);
417 /* allow object to delete internal data */
418 if (NULL
!= objectHeader
->CleanupProc
)
420 Obj
= (PGDIOBJ
)((PCHAR
)objectHeader
+ sizeof(GDIOBJHDR
));
421 bRet
= (*(objectHeader
->CleanupProc
))(Obj
);
423 LookasideList
= FindLookasideList(GDI_MAGIC_TO_TYPE(objectHeader
->Magic
));
424 if (NULL
!= LookasideList
)
426 ExFreeToPagedLookasideList(LookasideList
, objectHeader
);
428 ExAcquireFastMutexUnsafe (&HandleTableMutex
);
429 HandleTable
->Handles
[GDI_HANDLE_GET_INDEX(hObj
)] = NULL
;
430 #if GDI_COUNT_OBJECTS
431 HandleTable
->HandlesCount
--;
433 ExReleaseFastMutexUnsafe (&HandleTableMutex
);
435 W32Process
= PsGetCurrentProcess()->Win32Process
;
438 W32Process
->GDIObjects
--;
445 * Lock multiple objects. Use this function when you need to lock multiple objects and some of them may be
446 * duplicates. You should use this function to avoid trying to lock the same object twice!
448 * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields.
449 * \param nObj number of objects to lock
450 * \return for each entry in pList this function sets pObj field to point to the object.
452 * \note this function uses an O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
455 GDIOBJ_LockMultipleObj(PGDIMULTILOCK pList
, INT nObj
)
459 /* FIXME - check for "invalid" handles */
460 /* go through the list checking for duplicate objects */
461 for (i
= 0; i
< nObj
; i
++)
463 pList
[i
].pObj
= NULL
;
464 for (j
= 0; j
< i
; j
++)
466 if (pList
[i
].hObj
== pList
[j
].hObj
)
468 /* already locked, so just copy the pointer to the object */
469 pList
[i
].pObj
= pList
[j
].pObj
;
474 if (NULL
== pList
[i
].pObj
)
476 /* object hasn't been locked, so lock it. */
477 if (NULL
!= pList
[i
].hObj
)
479 pList
[i
].pObj
= GDIOBJ_LockObj(pList
[i
].hObj
, pList
[i
].ObjectType
);
488 * Unlock multiple objects. Use this function when you need to unlock multiple objects and some of them may be
491 * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields.
492 * \param nObj number of objects to lock
494 * \note this function uses O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
497 GDIOBJ_UnlockMultipleObj(PGDIMULTILOCK pList
, INT nObj
)
502 /* go through the list checking for duplicate objects */
503 for (i
= 0; i
< nObj
; i
++)
505 if (NULL
!= pList
[i
].pObj
)
507 for (j
= i
+ 1; j
< nObj
; j
++)
509 if ((pList
[i
].pObj
== pList
[j
].pObj
))
511 /* set the pointer to zero for all duplicates */
512 pList
[j
].pObj
= NULL
;
515 GDIOBJ_UnlockObj(pList
[i
].hObj
, pList
[i
].ObjectType
);
516 pList
[i
].pObj
= NULL
;
524 * Get the type of the object.
525 * \param ObjectHandle - handle of the object.
526 * \return One of the \ref GDI object types
529 GDIOBJ_GetObjectType(HGDIOBJ ObjectHandle
)
533 ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle
));
535 || ! GDI_VALID_OBJECT(ObjectHandle
, ObjHdr
, GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
), 0))
537 DPRINT1("Invalid ObjectHandle 0x%08x\n", ObjectHandle
);
540 DPRINT("GDIOBJ_GetObjectType for handle 0x%08x returns 0x%08x\n", ObjectHandle
,
541 GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
));
543 return GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
);
547 * Initialization of the GDI object engine.
550 InitGdiObjectHandleTable (VOID
)
552 DPRINT("InitGdiObjectHandleTable\n");
553 ExInitializeFastMutex (&HandleTableMutex
);
554 ExInitializeFastMutex (&RefCountHandling
);
556 ShortDelay
.QuadPart
= -100;
558 HandleTable
= GDIOBJ_iAllocHandleTable (GDI_HANDLE_COUNT
);
559 DPRINT("HandleTable: %x\n", HandleTable
);
561 InitEngHandleTable();
565 * Creates a bunch of stock objects: brushes, pens, fonts.
568 CreateStockObjects(void)
572 DPRINT("Beginning creation of stock objects\n");
574 /* Create GDI Stock Objects from the logical structures we've defined */
576 StockObjects
[WHITE_BRUSH
] = IntGdiCreateBrushIndirect(&WhiteBrush
);
577 StockObjects
[LTGRAY_BRUSH
] = IntGdiCreateBrushIndirect(&LtGrayBrush
);
578 StockObjects
[GRAY_BRUSH
] = IntGdiCreateBrushIndirect(&GrayBrush
);
579 StockObjects
[DKGRAY_BRUSH
] = IntGdiCreateBrushIndirect(&DkGrayBrush
);
580 StockObjects
[BLACK_BRUSH
] = IntGdiCreateBrushIndirect(&BlackBrush
);
581 StockObjects
[NULL_BRUSH
] = IntGdiCreateBrushIndirect(&NullBrush
);
583 StockObjects
[WHITE_PEN
] = IntGdiCreatePenIndirect(&WhitePen
);
584 StockObjects
[BLACK_PEN
] = IntGdiCreatePenIndirect(&BlackPen
);
585 StockObjects
[NULL_PEN
] = IntGdiCreatePenIndirect(&NullPen
);
587 (void) TextIntCreateFontIndirect(&OEMFixedFont
, (HFONT
*)&StockObjects
[OEM_FIXED_FONT
]);
588 (void) TextIntCreateFontIndirect(&AnsiFixedFont
, (HFONT
*)&StockObjects
[ANSI_FIXED_FONT
]);
589 (void) TextIntCreateFontIndirect(&SystemFont
, (HFONT
*)&StockObjects
[SYSTEM_FONT
]);
590 (void) TextIntCreateFontIndirect(&DeviceDefaultFont
, (HFONT
*)&StockObjects
[DEVICE_DEFAULT_FONT
]);
591 (void) TextIntCreateFontIndirect(&SystemFixedFont
, (HFONT
*)&StockObjects
[SYSTEM_FIXED_FONT
]);
592 (void) TextIntCreateFontIndirect(&DefaultGuiFont
, (HFONT
*)&StockObjects
[DEFAULT_GUI_FONT
]);
594 StockObjects
[DEFAULT_PALETTE
] = (HGDIOBJ
*)PALETTE_Init();
596 for (Object
= 0; Object
< NB_STOCK_OBJECTS
; Object
++)
598 if (NULL
!= StockObjects
[Object
])
600 GDIOBJ_SetOwnership(StockObjects
[Object
], NULL
);
601 /* GDI_HANDLE_SET_STOCKOBJ(StockObjects[Object]);*/
605 DPRINT("Completed creation of stock objects\n");
609 * Return stock object.
610 * \param Object - stock object id.
611 * \return Handle to the object.
614 NtGdiGetStockObject(INT Object
)
616 DPRINT("NtGdiGetStockObject index %d\n", Object
);
618 return ((Object
< 0) || (NB_STOCK_OBJECTS
<= Object
)) ? NULL
: StockObjects
[Object
];
623 * \param hObject object handle
624 * \return if the function fails the returned value is FALSE.
627 NtGdiDeleteObject(HGDIOBJ hObject
)
629 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
631 return NULL
!= hObject
632 ? GDIOBJ_FreeObj(hObject
, GDI_OBJECT_TYPE_DONTCARE
, GDIOBJFLAG_DEFAULT
) : FALSE
;
636 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
637 * \param Process - PID of the process that will be destroyed.
640 CleanupForProcess (struct _EPROCESS
*Process
, INT Pid
)
643 PGDIOBJHDR objectHeader
;
644 PEPROCESS CurrentProcess
;
646 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Pid
);
647 CurrentProcess
= PsGetCurrentProcess();
648 if (CurrentProcess
!= Process
)
650 KeAttachProcess(Process
);
653 for(i
= 1; i
< HandleTable
->wTableSize
; i
++)
655 objectHeader
= GDIOBJ_iGetObjectForIndex(i
);
656 if (NULL
!= objectHeader
&&
657 (INT
) objectHeader
->hProcessId
== Pid
)
659 DPRINT("CleanupForProcess: %d, process: %d, locks: %d, magic: 0x%x", i
, objectHeader
->hProcessId
, objectHeader
->dwCount
, objectHeader
->Magic
);
660 GDIOBJ_FreeObj(GDI_HANDLE_CREATE(i
, GDI_MAGIC_TO_TYPE(objectHeader
->Magic
)),
661 GDI_MAGIC_TO_TYPE(objectHeader
->Magic
),
662 GDIOBJFLAG_IGNOREPID
| GDIOBJFLAG_IGNORELOCK
);
666 if (CurrentProcess
!= Process
)
671 DPRINT("Completed cleanup for process %d\n", Pid
);
676 #define GDIOBJ_TRACKLOCKS
678 #ifdef GDIOBJ_LockObj
679 #undef GDIOBJ_LockObj
681 GDIOBJ_LockObjDbg (const char* file
, int line
, HGDIOBJ hObj
, DWORD ObjectType
)
683 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
684 #ifndef GDIOBJ_USE_FASTMUTEX
685 DWORD CurrentTid
= (DWORD
)PsGetCurrentThreadId();
688 DPRINT("(%s:%i) GDIOBJ_LockObjDbg(0x%08x,0x%08x)\n", file
, line
, hObj
, ObjectType
);
689 if (! GDI_VALID_OBJECT(hObj
, ObjHdr
, ObjectType
, GDIOBJFLAG_DEFAULT
))
696 else if (GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
) != ObjectType
&& ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
)
700 else if (ObjHdr
->hProcessId
!= GDI_GLOBAL_PROCESS
701 && ObjHdr
->hProcessId
!= PsGetCurrentProcessId())
705 else if (GDI_HANDLE_GET_TYPE(hObj
) != ObjectType
&& ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
)
709 DPRINT1("GDIOBJ_LockObj failed for 0x%08x, reqtype 0x%08x reason %d\n",
710 hObj
, ObjectType
, reason
);
711 DPRINT1("\tcalled from: %s:%i\n", file
, line
);
715 #ifdef GDIOBJ_USE_FASTMUTEX
716 if (ObjHdr
->Lock
.Owner
== KeGetCurrentThread())
718 ObjHdr
->RecursiveLockCount
++;
723 ExAcquireFastMutex(&ObjHdr
->Lock
);
725 if (! ExTryToAcquireFastMutex(&ObjHdr
->Lock
))
727 DPRINT1("Caution! GDIOBJ_LockObj trying to lock object 0x%x second time\n", hObj
);
728 DPRINT1(" called from: %s:%i (thread %x)\n", file
, line
, KeGetCurrentThread());
729 if (NULL
!= ObjHdr
->lockfile
)
731 DPRINT1(" previously locked from: %s:%i (thread %x)\n", ObjHdr
->lockfile
, ObjHdr
->lockline
, ObjHdr
->Lock
.Owner
);
733 ExAcquireFastMutex(&ObjHdr
->Lock
);
734 DPRINT1(" Disregard previous message about object 0x%x, it's ok\n", hObj
);
737 ObjHdr
->RecursiveLockCount
++;
740 if (ObjHdr
->LockTid
== CurrentTid
)
742 InterlockedIncrement(&ObjHdr
->LockCount
);
748 if (InterlockedCompareExchange(&ObjHdr
->LockTid
, CurrentTid
, 0) == CurrentTid
)
750 InterlockedIncrement(&ObjHdr
->LockCount
);
753 /* FIXME: KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay); */
758 ExAcquireFastMutex(&RefCountHandling
);
760 ExReleaseFastMutex(&RefCountHandling
);
762 if (NULL
== ObjHdr
->lockfile
)
764 ObjHdr
->lockfile
= file
;
765 ObjHdr
->lockline
= line
;
768 return (PGDIOBJ
)((PCHAR
)ObjHdr
+ sizeof(GDIOBJHDR
));
770 #endif//GDIOBJ_LockObj
772 #ifdef GDIOBJ_UnlockObj
773 #undef GDIOBJ_UnlockObj
775 GDIOBJ_UnlockObjDbg (const char* file
, int line
, HGDIOBJ hObj
, DWORD ObjectType
)
777 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
779 if (! GDI_VALID_OBJECT(hObj
, ObjHdr
, ObjectType
, GDIOBJFLAG_DEFAULT
))
781 DPRINT1("GDIBOJ_UnlockObj failed for 0x%08x, reqtype 0x%08x\n",
783 DPRINT1("\tcalled from: %s:%i\n", file
, line
);
786 DPRINT("(%s:%i) GDIOBJ_UnlockObj(0x%08x,0x%08x)\n", file
, line
, hObj
, ObjectType
);
787 ObjHdr
->lockfile
= NULL
;
788 ObjHdr
->lockline
= 0;
790 return GDIOBJ_UnlockObj(hObj
, ObjectType
);
792 #endif//GDIOBJ_LockObj
795 * Return pointer to the object by handle.
797 * \param hObj Object handle
798 * \param ObjectType one of the object types defined in \ref GDI object types
799 * \return Pointer to the object.
801 * \note Process can only get pointer to the objects it created or global objects.
803 * \todo Don't allow to lock the objects twice! Synchronization!
806 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ObjectType
)
808 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
809 #ifndef GDIOBJ_USE_FASTMUTEX
810 DWORD CurrentTid
= (DWORD
)PsGetCurrentThreadId();
813 DPRINT("GDIOBJ_LockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj
, ObjectType
, ObjHdr
);
814 if (! GDI_VALID_OBJECT(hObj
, ObjHdr
, ObjectType
, GDIOBJFLAG_DEFAULT
))
816 DPRINT1("GDIBOJ_LockObj failed for 0x%08x, type 0x%08x\n",
821 #ifdef GDIOBJ_USE_FASTMUTEX
822 if (ObjHdr
->Lock
.Owner
== KeGetCurrentThread())
824 ObjHdr
->RecursiveLockCount
++;
828 ExAcquireFastMutex(&ObjHdr
->Lock
);
829 ObjHdr
->RecursiveLockCount
++;
832 if (ObjHdr
->LockTid
== CurrentTid
)
834 InterlockedIncrement(&ObjHdr
->LockCount
);
840 if (InterlockedCompareExchange(&ObjHdr
->LockTid
, CurrentTid
, 0) == CurrentTid
)
842 InterlockedIncrement(&ObjHdr
->LockCount
);
845 /* FIXME: KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay); */
850 ExAcquireFastMutex(&RefCountHandling
);
852 ExReleaseFastMutex(&RefCountHandling
);
853 return (PGDIOBJ
)((PCHAR
)ObjHdr
+ sizeof(GDIOBJHDR
));
857 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
858 * as soon as you don't need to have access to it's data.
860 * \param hObj Object handle
861 * \param ObjectType one of the object types defined in \ref GDI object types
863 * \note This function performs delayed cleanup. If the object is locked when GDI_FreeObj() is called
864 * then \em this function frees the object when reference count is zero.
866 * \todo Change synchronization algorithm.
868 #undef GDIOBJ_UnlockObj
870 GDIOBJ_UnlockObj(HGDIOBJ hObj
, DWORD ObjectType
)
872 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
874 DPRINT("GDIOBJ_UnlockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj
, ObjectType
, ObjHdr
);
875 if (! GDI_VALID_OBJECT(hObj
, ObjHdr
, ObjectType
, GDIOBJFLAG_DEFAULT
))
877 DPRINT1( "GDIOBJ_UnLockObj: failed\n");
881 #ifdef GDIOBJ_USE_FASTMUTEX
882 if (--ObjHdr
->RecursiveLockCount
== 0)
883 ExReleaseFastMutex(&ObjHdr
->Lock
);
885 if (InterlockedDecrement(&ObjHdr
->LockCount
) == 0)
887 InterlockedExchange(&ObjHdr
->LockTid
, 0);
891 ExAcquireFastMutex(&RefCountHandling
);
892 if (0 == (ObjHdr
->dwCount
& ~0x80000000))
894 ExReleaseFastMutex(&RefCountHandling
);
895 DPRINT1( "GDIOBJ_UnLockObj: unlock object (0x%x) that is not locked\n", hObj
);
901 if (ObjHdr
->dwCount
== 0x80000000)
903 //delayed object release
905 ExReleaseFastMutex(&RefCountHandling
);
906 DPRINT("GDIOBJ_UnlockObj: delayed delete\n");
907 return GDIOBJ_FreeObj(hObj
, ObjectType
, GDIOBJFLAG_DEFAULT
);
909 ExReleaseFastMutex(&RefCountHandling
);
915 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
917 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle
));
919 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
920 ASSERT(GDI_VALID_OBJECT(ObjectHandle
, ObjHdr
, GDI_OBJECT_TYPE_DONTCARE
, GDIOBJFLAG_IGNOREPID
));
922 return ObjHdr
->hProcessId
== PsGetCurrentProcessId();
926 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
928 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle
));
929 PEPROCESS OldProcess
;
930 PW32PROCESS W32Process
;
933 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
934 ASSERT(GDI_VALID_OBJECT(ObjectHandle
, ObjHdr
, GDI_OBJECT_TYPE_DONTCARE
, GDIOBJFLAG_IGNOREPID
));
936 if ((NULL
== NewOwner
&& GDI_GLOBAL_PROCESS
!= ObjHdr
->hProcessId
)
937 || (NULL
!= NewOwner
&& ObjHdr
->hProcessId
!= (HANDLE
) NewOwner
->UniqueProcessId
))
939 Status
= PsLookupProcessByProcessId((PVOID
)ObjHdr
->hProcessId
, &OldProcess
);
940 if (NT_SUCCESS(Status
))
942 W32Process
= OldProcess
->Win32Process
;
945 W32Process
->GDIObjects
--;
947 ObDereferenceObject(OldProcess
);
951 if (NULL
== NewOwner
)
953 ObjHdr
->hProcessId
= GDI_GLOBAL_PROCESS
;
955 else if (ObjHdr
->hProcessId
!= (HANDLE
) NewOwner
->UniqueProcessId
)
957 ObjHdr
->hProcessId
= (HANDLE
) NewOwner
->UniqueProcessId
;
958 W32Process
= NewOwner
->Win32Process
;
961 W32Process
->GDIObjects
++;
967 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
969 PGDIOBJHDR ObjHdrFrom
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(CopyFrom
));
970 PGDIOBJHDR ObjHdrTo
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(CopyTo
));
972 PEPROCESS ProcessFrom
;
973 PEPROCESS CurrentProcess
;
975 ASSERT(NULL
!= ObjHdrFrom
&& NULL
!= ObjHdrTo
);
976 if (NULL
!= ObjHdrFrom
&& NULL
!= ObjHdrTo
977 && ObjHdrTo
->hProcessId
!= ObjHdrFrom
->hProcessId
)
979 if (ObjHdrFrom
->hProcessId
== GDI_GLOBAL_PROCESS
)
981 GDIOBJ_SetOwnership(CopyTo
, NULL
);
985 /* Warning: ugly hack ahead
987 * During process cleanup, we can't call PsLookupProcessByProcessId
988 * for the current process, 'cause that function will try to
989 * reference the process, and since the process is closing down
990 * that will result in a bugcheck.
991 * So, instead, we call PsGetCurrentProcess, which doesn't reference
992 * the process. If the current process is indeed the one we're
993 * looking for, we use it, otherwise we can (safely) call
994 * PsLookupProcessByProcessId
996 CurrentProcess
= PsGetCurrentProcess();
997 if (ObjHdrFrom
->hProcessId
== (HANDLE
) CurrentProcess
->UniqueProcessId
)
999 GDIOBJ_SetOwnership(CopyTo
, CurrentProcess
);
1003 Status
= PsLookupProcessByProcessId((PVOID
) ObjHdrFrom
->hProcessId
, &ProcessFrom
);
1004 if (NT_SUCCESS(Status
))
1006 GDIOBJ_SetOwnership(CopyTo
, ProcessFrom
);
1007 ObDereferenceObject(ProcessFrom
);