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.63 2004/03/14 12:16:50 weiden Exp $
26 #undef WIN32_LEAN_AND_MEAN
27 #define WIN32_NO_STATUS
29 #include <ddk/ntddk.h>
30 #include <include/dce.h>
31 #include <include/object.h>
32 #include <win32k/gdiobj.h>
33 #include <win32k/brush.h>
34 #include <win32k/pen.h>
35 #include <win32k/text.h>
36 #include <win32k/dc.h>
37 #include <win32k/bitmaps.h>
38 #include <win32k/region.h>
39 #include <win32k/cursoricon.h>
40 #include <include/palette.h>
41 #include <include/intgdi.h>
42 #include <include/tags.h>
44 #include <win32k/debug1.h>
47 /* enable/disable GDI object caching */
48 #define GDI_CACHE_OBJECTS 0
49 /* count all gdi objects */
50 #define GDI_COUNT_OBJECTS 1
52 /*! Size of the GDI handle table
53 * http://www.windevnet.com/documents/s=7290/wdj9902b/9902b.htm
54 * gdi handle table can hold 0x4000 handles
56 #define GDI_HANDLE_COUNT 0x4000
58 #define GDI_GLOBAL_PROCESS ((HANDLE) 0xffffffff)
60 #define GDI_HANDLE_INDEX_MASK (GDI_HANDLE_COUNT - 1)
61 #define GDI_HANDLE_TYPE_MASK 0x007f0000
62 #define GDI_HANDLE_STOCK_MASK 0x00800000
64 #define GDI_HANDLE_CREATE(i, t) ((HANDLE)(((i) & GDI_HANDLE_INDEX_MASK) | ((t) & GDI_HANDLE_TYPE_MASK)))
65 #define GDI_HANDLE_GET_INDEX(h) (((DWORD)(h)) & GDI_HANDLE_INDEX_MASK)
66 #define GDI_HANDLE_GET_TYPE(h) (((DWORD)(h)) & GDI_HANDLE_TYPE_MASK)
67 #define GDI_HANDLE_IS_TYPE(h, t) ((t) == (((DWORD)(h)) & GDI_HANDLE_TYPE_MASK))
68 #define GDI_HANDLE_IS_STOCKOBJ(h) (0 != (((DWORD)(h)) & GDI_HANDLE_STOCK_MASK))
69 #define GDI_HANDLE_SET_STOCKOBJ(h) ((h) = (HANDLE)(((DWORD)(h)) | GDI_HANDLE_STOCK_MASK))
71 #define GDI_TYPE_TO_MAGIC(t) ((WORD) ((t) >> 16))
72 #define GDI_MAGIC_TO_TYPE(m) ((DWORD)(m) << 16)
74 /* FIXME Ownership of GDI objects by processes not properly implemented yet */
76 #define GDI_VALID_OBJECT(h, obj, t, f) \
78 && (GDI_MAGIC_TO_TYPE((obj)->Magic) == (t) || GDI_OBJECT_TYPE_DONTCARE == (t)) \
79 && (GDI_HANDLE_GET_TYPE((h)) == GDI_MAGIC_TO_TYPE((obj)->Magic)) \
80 && (((obj)->hProcessId == PsGetCurrentProcessId()) \
81 || (GDI_GLOBAL_PROCESS == (obj)->hProcessId) \
82 || ((f) & GDIOBJFLAG_IGNOREPID)))
84 #define GDI_VALID_OBJECT(h, obj, t, f) \
86 && (GDI_MAGIC_TO_TYPE((obj)->Magic) == (t) || GDI_OBJECT_TYPE_DONTCARE == (t)) \
87 && (GDI_HANDLE_GET_TYPE((h)) == GDI_MAGIC_TO_TYPE((obj)->Magic)))
90 typedef struct _GDI_HANDLE_TABLE
99 PGDIOBJHDR
*CachedObjects
;
101 PGDIOBJHDR Handles
[1];
102 } GDI_HANDLE_TABLE
, *PGDI_HANDLE_TABLE
;
104 #if GDI_CACHE_OBJECTS
106 #define N_OBJ_TYPES 16
114 typedef struct _GDI_DONTCARE
117 } GDI_DONTCARE
, *PGDI_DONTCARE
;
120 GDI_OBJ_SIZE ObjSizes
[N_OBJ_TYPES
] =
122 {GDI_OBJECT_TYPE_DC
, sizeof(DC
)},
123 {GDI_OBJECT_TYPE_DCE
, sizeof(DCE
)},
124 {GDI_OBJECT_TYPE_PALETTE
, sizeof(PALGDI
)},
125 {GDI_OBJECT_TYPE_FONT
, sizeof(TEXTOBJ
)},
126 {GDI_OBJECT_TYPE_BRUSH
, sizeof(BRUSHOBJ
)},
127 {GDI_OBJECT_TYPE_PEN
, sizeof(PENOBJ
)},
128 {GDI_OBJECT_TYPE_REGION
, sizeof(ROSRGNDATA
)},
129 {GDI_OBJECT_TYPE_BITMAP
, sizeof(BITMAPOBJ
)},
131 {GDI_OBJECT_TYPE_DIRECTDRAW, sizeof(DD_DIRECTDRAW)},
132 {GDI_OBJECT_TYPE_DD_SURFACE, sizeof(DD_SURFACE)},
134 {GDI_OBJECT_TYPE_DONTCARE
, sizeof(GDI_DONTCARE
)},
135 {GDI_OBJECT_TYPE_EXTPEN
, 0},
136 {GDI_OBJECT_TYPE_METADC
, 0},
137 {GDI_OBJECT_TYPE_METAFILE
, 0},
138 {GDI_OBJECT_TYPE_ENHMETAFILE
, 0},
139 {GDI_OBJECT_TYPE_ENHMETADC
, 0},
140 {GDI_OBJECT_TYPE_MEMDC
, 0},
141 {GDI_OBJECT_TYPE_EMF
, 0}
145 GDI_MaxGdiObjHeaderSize(VOID
)
148 for(i
= 0, Size
= 0; i
< N_OBJ_TYPES
; i
++)
150 Size
= max(Size
, ObjSizes
[i
].Size
);
157 /* GDI stock objects */
159 static LOGBRUSH WhiteBrush
=
160 { BS_SOLID
, RGB(255,255,255), 0 };
162 static LOGBRUSH LtGrayBrush
=
163 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
164 { BS_SOLID
, RGB(192,192,192), 0 };
166 static LOGBRUSH GrayBrush
=
167 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
168 { BS_SOLID
, RGB(128,128,128), 0 };
170 static LOGBRUSH DkGrayBrush
=
171 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
172 /* NB_HATCH_STYLES is an index into HatchBrushes */
173 { BS_HATCHED
, RGB(0,0,0), NB_HATCH_STYLES
};
175 static LOGBRUSH BlackBrush
=
176 { BS_SOLID
, RGB(0,0,0), 0 };
178 static LOGBRUSH NullBrush
=
181 static LOGPEN WhitePen
=
182 { PS_SOLID
, { 0, 0 }, RGB(255,255,255) };
184 static LOGPEN BlackPen
=
185 { PS_SOLID
, { 0, 0 }, RGB(0,0,0) };
187 static LOGPEN NullPen
=
188 { PS_NULL
, { 0, 0 }, 0 };
190 static LOGFONTW OEMFixedFont
=
191 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, OEM_CHARSET
,
192 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
, L
"Bitstream Vera Sans Mono" };
194 static LOGFONTW AnsiFixedFont
=
195 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
196 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
, L
"Bitstream Vera Sans Mono" };
198 /*static LOGFONTW AnsiVarFont =
199 *{ 10, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
200 * 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" }; */
202 static LOGFONTW SystemFont
=
203 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
204 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
, L
"Bitstream Vera Sans" };
206 static LOGFONTW DeviceDefaultFont
=
207 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
208 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
, L
"Bitstream Vera Sans" };
210 static LOGFONTW SystemFixedFont
=
211 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
212 0, 0, DEFAULT_QUALITY
, FIXED_PITCH
| FF_MODERN
, L
"Bitstream Vera Sans Mono" };
214 /* FIXME: Is this correct? */
215 static LOGFONTW DefaultGuiFont
=
216 { 11, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, ANSI_CHARSET
,
217 0, 0, DEFAULT_QUALITY
, VARIABLE_PITCH
| FF_SWISS
, L
"Bitstream Vera Sans" };
219 #define NB_STOCK_OBJECTS (DEFAULT_GUI_FONT + 1)
221 static HGDIOBJ
*StockObjects
[NB_STOCK_OBJECTS
];
222 static PGDI_HANDLE_TABLE HandleTable
= 0;
223 static FAST_MUTEX HandleTableMutex
;
224 static FAST_MUTEX RefCountHandling
;
227 * Allocate GDI object table.
228 * \param Size - number of entries in the object table.
229 * Notes:: Must be called at IRQL < DISPATCH_LEVEL.
231 static PGDI_HANDLE_TABLE FASTCALL
232 GDIOBJ_iAllocHandleTable (WORD Size
)
234 PGDI_HANDLE_TABLE handleTable
;
237 #if GDI_CACHE_OBJECTS
238 MemSize
= sizeof(GDI_HANDLE_TABLE
) + sizeof(PGDIOBJ
) * (Size
<< 1);
240 MemSize
= sizeof(GDI_HANDLE_TABLE
) + sizeof(PGDIOBJ
) * Size
;
243 /* prevent APC delivery for the *FastMutexUnsafe calls */
244 const KIRQL PrevIrql
= KfRaiseIrql(APC_LEVEL
);
245 ExAcquireFastMutexUnsafe (&HandleTableMutex
);
246 handleTable
= ExAllocatePoolWithTag(PagedPool
, MemSize
, TAG_GDIHNDTBLE
);
247 ASSERT( handleTable
);
248 memset (handleTable
, 0, MemSize
);
249 #if GDI_COUNT_OBJECTS
250 handleTable
->HandlesCount
= 0;
252 #if GDI_CACHE_OBJECTS
253 handleTable
->CachedObjects
= &handleTable
->Handles
[Size
];
254 handleTable
->ObjHdrSize
= sizeof(GDIOBJHDR
) + GDI_MaxGdiObjHeaderSize();
256 handleTable
->wTableSize
= Size
;
257 handleTable
->AllocationHint
= 1;
258 ExReleaseFastMutexUnsafe (&HandleTableMutex
);
259 KfLowerIrql(PrevIrql
);
265 * Returns the entry into the handle table by index.
267 static PGDIOBJHDR FASTCALL
268 GDIOBJ_iGetObjectForIndex(WORD TableIndex
)
270 if (0 == TableIndex
|| HandleTable
->wTableSize
< TableIndex
)
272 DPRINT1("Invalid TableIndex %u\n", (unsigned) TableIndex
);
276 return HandleTable
->Handles
[TableIndex
];
280 * Finds next free entry in the GDI handle table.
281 * \return index into the table is successful, zero otherwise.
284 GDIOBJ_iGetNextOpenHandleIndex (void)
288 for (tableIndex
= HandleTable
->AllocationHint
;
289 tableIndex
< HandleTable
->wTableSize
;
292 if (HandleTable
->Handles
[tableIndex
] == NULL
)
294 HandleTable
->AllocationHint
= tableIndex
+ 1;
300 tableIndex
< HandleTable
->AllocationHint
;
303 if (HandleTable
->Handles
[tableIndex
] == NULL
)
305 HandleTable
->AllocationHint
= tableIndex
+ 1;
314 * Allocate memory for GDI object and return handle to it.
316 * \param Size - size of the GDI object. This shouldn't to include the size of GDIOBJHDR.
317 * The actual amount of allocated memory is sizeof(GDIOBJHDR)+Size
318 * \param ObjectType - type of object \ref GDI object types
319 * \param CleanupProcPtr - Routine to be called on destruction of object
321 * \return Handle of the allocated object.
323 * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
326 GDIOBJ_AllocObj(WORD Size
, DWORD ObjectType
, GDICLEANUPPROC CleanupProc
)
328 PW32PROCESS W32Process
;
329 PGDIOBJHDR newObject
;
331 #if GDI_CACHE_OBJECTS
332 PGDIOBJHDR
*CachedObject
;
335 ExAcquireFastMutex(&HandleTableMutex
);
336 Index
= GDIOBJ_iGetNextOpenHandleIndex ();
339 ExReleaseFastMutex(&HandleTableMutex
);
340 DPRINT1("Out of GDI handles\n");
344 #if GDI_CACHE_OBJECTS
345 CachedObject
= (PGDIOBJHDR
*)(HandleTable
->CachedObjects
+ Index
);
346 if(!(newObject
= *CachedObject
))
348 /* allocate new gdi object */
349 newObject
= ExAllocatePoolWithTag(PagedPool
, HandleTable
->ObjHdrSize
, TAG_GDIOBJ
);
352 ExReleaseFastMutex(&HandleTableMutex
);
353 DPRINT1("GDIOBJ_AllocObj: failed\n");
356 RtlZeroMemory(newObject
, HandleTable
->ObjHdrSize
);
357 *CachedObject
= newObject
;
359 /* Zero the memory when destroying the object */
360 if(ObjectType
== GDI_OBJECT_TYPE_DONTCARE
)
365 Data
= ExAllocatePoolWithTag(PagedPool
, sizeof(PVOID
) + Size
, TAG_GDIOBJ
);
368 ExReleaseFastMutex(&HandleTableMutex
);
369 DPRINT1("GDIOBJ_AllocObj failed: %d bytes for GDI_OBJECT_TYPE_DONTCARE\n", Size
+ sizeof(PVOID
));
372 dc
= (PGDI_DONTCARE
)((PCHAR
)newObject
+ sizeof(GDIOBJHDR
));
373 RtlZeroMemory((PVOID
)(Data
+ 1), Size
);
374 ((PGDI_DONTCARE
)((PCHAR
)newObject
+ sizeof(GDIOBJHDR
)))->Data
= Data
;
378 DPRINT("GDIOBJ_AllocObj: handle: %d, size: %d, type: 0x%08x\n", Index
, Size
, ObjectType
);
379 newObject
= ExAllocatePoolWithTag(PagedPool
, Size
+ sizeof (GDIOBJHDR
), TAG_GDIOBJ
);
380 if (newObject
== NULL
)
382 ExReleaseFastMutex(&HandleTableMutex
);
383 DPRINT1("GDIOBJ_AllocObj: failed\n");
386 RtlZeroMemory (newObject
, Size
+ sizeof(GDIOBJHDR
));
389 newObject
->wTableIndex
= Index
;
391 newObject
->dwCount
= 0;
392 newObject
->hProcessId
= PsGetCurrentProcessId ();
393 newObject
->CleanupProc
= CleanupProc
;
394 newObject
->Magic
= GDI_TYPE_TO_MAGIC(ObjectType
);
395 newObject
->lockfile
= NULL
;
396 newObject
->lockline
= 0;
397 ExInitializeFastMutex(&newObject
->Lock
);
398 HandleTable
->Handles
[Index
] = newObject
;
399 #if GDI_COUNT_OBJECTS
400 HandleTable
->HandlesCount
++;
402 ExReleaseFastMutex(&HandleTableMutex
);
404 W32Process
= PsGetCurrentProcess()->Win32Process
;
407 W32Process
->GDIObjects
++;
410 return GDI_HANDLE_CREATE(Index
, ObjectType
);
414 * Free memory allocated for the GDI object. For each object type this function calls the
415 * appropriate cleanup routine.
417 * \param hObj - handle of the object to be deleted.
418 * \param ObjectType - one of the \ref GDI object types
419 * or GDI_OBJECT_TYPE_DONTCARE.
420 * \param Flag - if set to GDIOBJFLAG_IGNOREPID then the routine doesn't check if the process that
421 * tries to delete the object is the same one that created it.
423 * \return Returns TRUE if succesful.
425 * \note You should only use GDIOBJFLAG_IGNOREPID if you are cleaning up after the process that terminated.
426 * \note This function deferres object deletion if it is still in use.
429 GDIOBJ_FreeObj(HGDIOBJ hObj
, DWORD ObjectType
, DWORD Flag
)
431 PW32PROCESS W32Process
;
432 PGDIOBJHDR objectHeader
;
436 objectHeader
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
437 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x, object: %x\n", hObj
, objectHeader
);
439 if (! GDI_VALID_OBJECT(hObj
, objectHeader
, ObjectType
, Flag
)
440 || GDI_GLOBAL_PROCESS
== objectHeader
->hProcessId
)
443 DPRINT1("Can't delete hObj:0x%08x, type:0x%08x, flag:%d\n", hObj
, ObjectType
, Flag
);
447 DPRINT("FreeObj: locks: %x\n", objectHeader
->dwCount
);
448 if (!(Flag
& GDIOBJFLAG_IGNORELOCK
))
450 /* check that the reference count is zero. if not then set flag
451 * and delete object when releaseobj is called */
452 ExAcquireFastMutex(&RefCountHandling
);
453 if ((objectHeader
->dwCount
& ~0x80000000) > 0 )
455 DPRINT("GDIOBJ_FreeObj: delayed object deletion: count %d\n", objectHeader
->dwCount
);
456 objectHeader
->dwCount
|= 0x80000000;
457 ExReleaseFastMutex(&RefCountHandling
);
460 ExReleaseFastMutex(&RefCountHandling
);
463 /* allow object to delete internal data */
464 if (NULL
!= objectHeader
->CleanupProc
)
466 Obj
= (PGDIOBJ
)((PCHAR
)objectHeader
+ sizeof(GDIOBJHDR
));
467 bRet
= (*(objectHeader
->CleanupProc
))(Obj
);
469 #if GDI_CACHE_OBJECTS
470 if(GDI_MAGIC_TO_TYPE(objectHeader
->Magic
) == GDI_OBJECT_TYPE_DONTCARE
)
472 PGDI_DONTCARE dc
= (PGDI_DONTCARE
)((PCHAR
)objectHeader
+ sizeof(GDIOBJHDR
));
475 ExFreePool(dc
->Data
);
477 RtlZeroMemory(objectHeader
, HandleTable
->ObjHdrSize
);
480 ExFreePool(objectHeader
);
482 ExAcquireFastMutexUnsafe (&HandleTableMutex
);
483 HandleTable
->Handles
[GDI_HANDLE_GET_INDEX(hObj
)] = NULL
;
484 #if GDI_COUNT_OBJECTS
485 HandleTable
->HandlesCount
--;
487 ExReleaseFastMutexUnsafe (&HandleTableMutex
);
489 W32Process
= PsGetCurrentProcess()->Win32Process
;
492 W32Process
->GDIObjects
--;
499 * Lock multiple objects. Use this function when you need to lock multiple objects and some of them may be
500 * duplicates. You should use this function to avoid trying to lock the same object twice!
502 * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields.
503 * \param nObj number of objects to lock
504 * \return for each entry in pList this function sets pObj field to point to the object.
506 * \note this function uses an O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
509 GDIOBJ_LockMultipleObj(PGDIMULTILOCK pList
, INT nObj
)
513 /* FIXME - check for "invalid" handles */
514 /* go through the list checking for duplicate objects */
515 for (i
= 0; i
< nObj
; i
++)
517 pList
[i
].pObj
= NULL
;
518 for (j
= 0; j
< i
; j
++)
520 if (pList
[i
].hObj
== pList
[j
].hObj
)
522 /* already locked, so just copy the pointer to the object */
523 pList
[i
].pObj
= pList
[j
].pObj
;
528 if (NULL
== pList
[i
].pObj
)
530 /* object hasn't been locked, so lock it. */
531 if (NULL
!= pList
[i
].hObj
)
533 pList
[i
].pObj
= GDIOBJ_LockObj(pList
[i
].hObj
, pList
[i
].ObjectType
);
542 * Unlock multiple objects. Use this function when you need to unlock multiple objects and some of them may be
545 * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields.
546 * \param nObj number of objects to lock
548 * \note this function uses O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
551 GDIOBJ_UnlockMultipleObj(PGDIMULTILOCK pList
, INT nObj
)
556 /* go through the list checking for duplicate objects */
557 for (i
= 0; i
< nObj
; i
++)
559 if (NULL
!= pList
[i
].pObj
)
561 for (j
= i
+ 1; j
< nObj
; j
++)
563 if ((pList
[i
].pObj
== pList
[j
].pObj
))
565 /* set the pointer to zero for all duplicates */
566 pList
[j
].pObj
= NULL
;
569 GDIOBJ_UnlockObj(pList
[i
].hObj
, pList
[i
].ObjectType
);
570 pList
[i
].pObj
= NULL
;
578 * Get the type of the object.
579 * \param ObjectHandle - handle of the object.
580 * \return One of the \ref GDI object types
583 GDIOBJ_GetObjectType(HGDIOBJ ObjectHandle
)
587 ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle
));
589 || ! GDI_VALID_OBJECT(ObjectHandle
, ObjHdr
, GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
), 0))
591 DPRINT1("Invalid ObjectHandle 0x%08x\n", ObjectHandle
);
594 DPRINT("GDIOBJ_GetObjectType for handle 0x%08x returns 0x%08x\n", ObjectHandle
,
595 GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
));
597 return GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
);
601 * Initialization of the GDI object engine.
604 InitGdiObjectHandleTable (VOID
)
606 DPRINT("InitGdiObjectHandleTable\n");
607 ExInitializeFastMutex (&HandleTableMutex
);
608 ExInitializeFastMutex (&RefCountHandling
);
610 HandleTable
= GDIOBJ_iAllocHandleTable (GDI_HANDLE_COUNT
);
611 DPRINT("HandleTable: %x\n", HandleTable
);
613 InitEngHandleTable();
617 * Creates a bunch of stock objects: brushes, pens, fonts.
620 CreateStockObjects(void)
624 DPRINT("Beginning creation of stock objects\n");
626 /* Create GDI Stock Objects from the logical structures we've defined */
628 StockObjects
[WHITE_BRUSH
] = IntGdiCreateBrushIndirect(&WhiteBrush
);
629 StockObjects
[LTGRAY_BRUSH
] = IntGdiCreateBrushIndirect(&LtGrayBrush
);
630 StockObjects
[GRAY_BRUSH
] = IntGdiCreateBrushIndirect(&GrayBrush
);
631 StockObjects
[DKGRAY_BRUSH
] = IntGdiCreateBrushIndirect(&DkGrayBrush
);
632 StockObjects
[BLACK_BRUSH
] = IntGdiCreateBrushIndirect(&BlackBrush
);
633 StockObjects
[NULL_BRUSH
] = IntGdiCreateBrushIndirect(&NullBrush
);
635 StockObjects
[WHITE_PEN
] = IntGdiCreatePenIndirect(&WhitePen
);
636 StockObjects
[BLACK_PEN
] = IntGdiCreatePenIndirect(&BlackPen
);
637 StockObjects
[NULL_PEN
] = IntGdiCreatePenIndirect(&NullPen
);
639 (void) TextIntCreateFontIndirect(&OEMFixedFont
, (HFONT
*)&StockObjects
[OEM_FIXED_FONT
]);
640 (void) TextIntCreateFontIndirect(&AnsiFixedFont
, (HFONT
*)&StockObjects
[ANSI_FIXED_FONT
]);
641 (void) TextIntCreateFontIndirect(&SystemFont
, (HFONT
*)&StockObjects
[SYSTEM_FONT
]);
642 (void) TextIntCreateFontIndirect(&DeviceDefaultFont
, (HFONT
*)&StockObjects
[DEVICE_DEFAULT_FONT
]);
643 (void) TextIntCreateFontIndirect(&SystemFixedFont
, (HFONT
*)&StockObjects
[SYSTEM_FIXED_FONT
]);
644 (void) TextIntCreateFontIndirect(&DefaultGuiFont
, (HFONT
*)&StockObjects
[DEFAULT_GUI_FONT
]);
646 StockObjects
[DEFAULT_PALETTE
] = (HGDIOBJ
*)PALETTE_Init();
648 for (Object
= 0; Object
< NB_STOCK_OBJECTS
; Object
++)
650 if (NULL
!= StockObjects
[Object
])
652 GDIOBJ_SetOwnership(StockObjects
[Object
], NULL
);
653 /* GDI_HANDLE_SET_STOCKOBJ(StockObjects[Object]);*/
657 DPRINT("Completed creation of stock objects\n");
661 * Return stock object.
662 * \param Object - stock object id.
663 * \return Handle to the object.
666 NtGdiGetStockObject(INT Object
)
668 DPRINT("NtGdiGetStockObject index %d\n", Object
);
670 return ((Object
< 0) || (NB_STOCK_OBJECTS
<= Object
)) ? NULL
: StockObjects
[Object
];
675 * \param hObject object handle
676 * \return if the function fails the returned value is FALSE.
679 NtGdiDeleteObject(HGDIOBJ hObject
)
681 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject
);
683 return NULL
!= hObject
684 ? GDIOBJ_FreeObj(hObject
, GDI_OBJECT_TYPE_DONTCARE
, GDIOBJFLAG_DEFAULT
) : FALSE
;
688 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
689 * \param Process - PID of the process that will be destroyed.
692 CleanupForProcess (struct _EPROCESS
*Process
, INT Pid
)
695 PGDIOBJHDR objectHeader
;
696 PEPROCESS CurrentProcess
;
698 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process
, Pid
);
699 CurrentProcess
= PsGetCurrentProcess();
700 if (CurrentProcess
!= Process
)
702 KeAttachProcess(Process
);
705 for(i
= 1; i
< HandleTable
->wTableSize
; i
++)
707 objectHeader
= GDIOBJ_iGetObjectForIndex(i
);
708 if (NULL
!= objectHeader
&&
709 (INT
) objectHeader
->hProcessId
== Pid
)
711 DPRINT("CleanupForProcess: %d, process: %d, locks: %d, magic: 0x%x", i
, objectHeader
->hProcessId
, objectHeader
->dwCount
, objectHeader
->Magic
);
712 GDIOBJ_FreeObj(GDI_HANDLE_CREATE(i
, GDI_MAGIC_TO_TYPE(objectHeader
->Magic
)),
713 GDI_MAGIC_TO_TYPE(objectHeader
->Magic
),
714 GDIOBJFLAG_IGNOREPID
| GDIOBJFLAG_IGNORELOCK
);
718 if (CurrentProcess
!= Process
)
723 DPRINT("Completed cleanup for process %d\n", Pid
);
728 #define GDIOBJ_TRACKLOCKS
730 #ifdef GDIOBJ_LockObj
731 #undef GDIOBJ_LockObj
733 GDIOBJ_LockObjDbg (const char* file
, int line
, HGDIOBJ hObj
, DWORD ObjectType
)
735 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
737 DPRINT("(%s:%i) GDIOBJ_LockObjDbg(0x%08x,0x%08x)\n", file
, line
, hObj
, ObjectType
);
738 if (! GDI_VALID_OBJECT(hObj
, ObjHdr
, ObjectType
, GDIOBJFLAG_DEFAULT
))
745 else if (GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
) != ObjectType
&& ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
)
749 else if (ObjHdr
->hProcessId
!= GDI_GLOBAL_PROCESS
750 && ObjHdr
->hProcessId
!= PsGetCurrentProcessId())
754 else if (GDI_HANDLE_GET_TYPE(hObj
) != ObjectType
&& ObjectType
!= GDI_OBJECT_TYPE_DONTCARE
)
758 DPRINT1("GDIOBJ_LockObj failed for 0x%08x, reqtype 0x%08x reason %d\n",
759 hObj
, ObjectType
, reason
);
760 DPRINT1("\tcalled from: %s:%i\n", file
, line
);
765 ExAcquireFastMutex(&ObjHdr
->Lock
);
767 if (! ExTryToAcquireFastMutex(&ObjHdr
->Lock
))
769 DPRINT1("Caution! GDIOBJ_LockObj trying to lock object 0x%x second time\n", hObj
);
770 DPRINT1(" called from: %s:%i\n", file
, line
);
771 if (NULL
!= ObjHdr
->lockfile
)
773 DPRINT1(" previously locked from: %s:%i\n", ObjHdr
->lockfile
, ObjHdr
->lockline
);
775 ExAcquireFastMutex(&ObjHdr
->Lock
);
776 DPRINT1(" Disregard previous message about object 0x%x, it's ok\n", hObj
);
780 ExAcquireFastMutex(&RefCountHandling
);
782 ExReleaseFastMutex(&RefCountHandling
);
784 if (NULL
== ObjHdr
->lockfile
)
786 ObjHdr
->lockfile
= file
;
787 ObjHdr
->lockline
= line
;
790 #if GDI_CACHE_OBJECTS
791 if(GDI_MAGIC_TO_TYPE(ObjHdr
->Magic
) != GDI_OBJECT_TYPE_DONTCARE
)
793 return (PGDIOBJ
)((PCHAR
)ObjHdr
+ sizeof(GDIOBJHDR
));
795 return (PGDIOBJ
)((PVOID
)(((PGDI_DONTCARE
)((PCHAR
)ObjHdr
+ sizeof(GDIOBJHDR
)))->Data
) + 1);
797 return (PGDIOBJ
)((PCHAR
)ObjHdr
+ sizeof(GDIOBJHDR
));
800 #endif//GDIOBJ_LockObj
802 #ifdef GDIOBJ_UnlockObj
803 #undef GDIOBJ_UnlockObj
805 GDIOBJ_UnlockObjDbg (const char* file
, int line
, HGDIOBJ hObj
, DWORD ObjectType
)
807 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
809 if (! GDI_VALID_OBJECT(hObj
, ObjHdr
, ObjectType
, GDIOBJFLAG_DEFAULT
))
811 DPRINT1("GDIBOJ_UnlockObj failed for 0x%08x, reqtype 0x%08x\n",
813 DPRINT1("\tcalled from: %s:%i\n", file
, line
);
816 DPRINT("(%s:%i) GDIOBJ_UnlockObj(0x%08x,0x%08x)\n", file
, line
, hObj
, ObjectType
);
817 ObjHdr
->lockfile
= NULL
;
818 ObjHdr
->lockline
= 0;
820 return GDIOBJ_UnlockObj(hObj
, ObjectType
);
822 #endif//GDIOBJ_LockObj
825 * Return pointer to the object by handle.
827 * \param hObj Object handle
828 * \param ObjectType one of the object types defined in \ref GDI object types
829 * \return Pointer to the object.
831 * \note Process can only get pointer to the objects it created or global objects.
833 * \todo Don't allow to lock the objects twice! Synchronization!
836 GDIOBJ_LockObj(HGDIOBJ hObj
, DWORD ObjectType
)
838 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj
));
840 DPRINT("GDIOBJ_LockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj
, ObjectType
, ObjHdr
);
841 if (! GDI_VALID_OBJECT(hObj
, ObjHdr
, ObjectType
, GDIOBJFLAG_DEFAULT
))
843 DPRINT1("GDIBOJ_LockObj failed for 0x%08x, type 0x%08x\n",
848 ExAcquireFastMutex(&ObjHdr
->Lock
);
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 ExReleaseFastMutex(&ObjHdr
->Lock
);
883 ExAcquireFastMutex(&RefCountHandling
);
884 if (0 == (ObjHdr
->dwCount
& ~0x80000000))
886 ExReleaseFastMutex(&RefCountHandling
);
887 DPRINT1( "GDIOBJ_UnLockObj: unlock object (0x%x) that is not locked\n", hObj
);
893 if (ObjHdr
->dwCount
== 0x80000000)
895 //delayed object release
897 ExReleaseFastMutex(&RefCountHandling
);
898 DPRINT("GDIOBJ_UnlockObj: delayed delete\n");
899 return GDIOBJ_FreeObj(hObj
, ObjectType
, GDIOBJFLAG_DEFAULT
);
901 ExReleaseFastMutex(&RefCountHandling
);
907 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle
)
909 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle
));
911 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
912 ASSERT(GDI_VALID_OBJECT(ObjectHandle
, ObjHdr
, GDI_OBJECT_TYPE_DONTCARE
, GDIOBJFLAG_IGNOREPID
));
914 return ObjHdr
->hProcessId
== PsGetCurrentProcessId();
918 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle
, PEPROCESS NewOwner
)
920 PGDIOBJHDR ObjHdr
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle
));
921 PEPROCESS OldProcess
;
922 PW32PROCESS W32Process
;
925 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle
);
926 ASSERT(GDI_VALID_OBJECT(ObjectHandle
, ObjHdr
, GDI_OBJECT_TYPE_DONTCARE
, GDIOBJFLAG_IGNOREPID
));
928 if ((NULL
== NewOwner
&& GDI_GLOBAL_PROCESS
!= ObjHdr
->hProcessId
)
929 || (NULL
!= NewOwner
&& ObjHdr
->hProcessId
!= (HANDLE
) NewOwner
->UniqueProcessId
))
931 Status
= PsLookupProcessByProcessId((PVOID
)ObjHdr
->hProcessId
, &OldProcess
);
932 if (NT_SUCCESS(Status
))
934 W32Process
= OldProcess
->Win32Process
;
937 W32Process
->GDIObjects
--;
939 ObDereferenceObject(OldProcess
);
943 if (NULL
== NewOwner
)
945 ObjHdr
->hProcessId
= GDI_GLOBAL_PROCESS
;
947 else if (ObjHdr
->hProcessId
!= (HANDLE
) NewOwner
->UniqueProcessId
)
949 ObjHdr
->hProcessId
= (HANDLE
) NewOwner
->UniqueProcessId
;
950 W32Process
= NewOwner
->Win32Process
;
953 W32Process
->GDIObjects
++;
959 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom
, HGDIOBJ CopyTo
)
961 PGDIOBJHDR ObjHdrFrom
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(CopyFrom
));
962 PGDIOBJHDR ObjHdrTo
= GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(CopyTo
));
964 PEPROCESS ProcessFrom
;
965 PEPROCESS CurrentProcess
;
967 ASSERT(NULL
!= ObjHdrFrom
&& NULL
!= ObjHdrTo
);
968 if (NULL
!= ObjHdrFrom
&& NULL
!= ObjHdrTo
969 && ObjHdrTo
->hProcessId
!= ObjHdrFrom
->hProcessId
)
971 if (ObjHdrFrom
->hProcessId
== GDI_GLOBAL_PROCESS
)
973 GDIOBJ_SetOwnership(CopyTo
, NULL
);
977 /* Warning: ugly hack ahead
979 * During process cleanup, we can't call PsLookupProcessByProcessId
980 * for the current process, 'cause that function will try to
981 * reference the process, and since the process is closing down
982 * that will result in a bugcheck.
983 * So, instead, we call PsGetCurrentProcess, which doesn't reference
984 * the process. If the current process is indeed the one we're
985 * looking for, we use it, otherwise we can (safely) call
986 * PsLookupProcessByProcessId
988 CurrentProcess
= PsGetCurrentProcess();
989 if (ObjHdrFrom
->hProcessId
== (HANDLE
) CurrentProcess
->UniqueProcessId
)
991 GDIOBJ_SetOwnership(CopyTo
, CurrentProcess
);
995 Status
= PsLookupProcessByProcessId((PVOID
) ObjHdrFrom
->hProcessId
, &ProcessFrom
);
996 if (NT_SUCCESS(Status
))
998 GDIOBJ_SetOwnership(CopyTo
, ProcessFrom
);
999 ObDereferenceObject(ProcessFrom
);