[Sorry for too many changes in one patch, but it's nearly impossible to separate...
[reactos.git] / reactos / subsys / win32k / objects / gdiobj.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * GDIOBJ.C - GDI object manipulation routines
21 *
22 * $Id: gdiobj.c,v 1.69 2004/07/03 13:55:36 navaraf Exp $
23 *
24 */
25 #include <w32k.h>
26
27 /* count all gdi objects */
28 #define GDI_COUNT_OBJECTS 1
29
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
33 */
34 #define GDI_HANDLE_COUNT 0x4000
35
36 #define GDI_GLOBAL_PROCESS ((HANDLE) 0xffffffff)
37
38 #define GDI_HANDLE_INDEX_MASK (GDI_HANDLE_COUNT - 1)
39 #define GDI_HANDLE_TYPE_MASK 0x007f0000
40 #define GDI_HANDLE_STOCK_MASK 0x00800000
41
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))
48
49 #define GDI_TYPE_TO_MAGIC(t) ((WORD) ((t) >> 16))
50 #define GDI_MAGIC_TO_TYPE(m) ((DWORD)(m) << 16)
51
52 /* FIXME Ownership of GDI objects by processes not properly implemented yet */
53 #if 0
54 #define GDI_VALID_OBJECT(h, obj, t, f) \
55 (NULL != (obj) \
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)))
61 #else
62 #define GDI_VALID_OBJECT(h, obj, t, f) \
63 (NULL != (obj) \
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)))
66 #endif
67
68 typedef struct _GDI_HANDLE_TABLE
69 {
70 WORD wTableSize;
71 WORD AllocationHint;
72 #if GDI_COUNT_OBJECTS
73 ULONG HandlesCount;
74 #endif
75 PPAGED_LOOKASIDE_LIST LookasideLists;
76 PGDIOBJHDR Handles[1];
77 } GDI_HANDLE_TABLE, *PGDI_HANDLE_TABLE;
78
79 typedef struct
80 {
81 ULONG Type;
82 ULONG Size;
83 } GDI_OBJ_SIZE;
84
85 const
86 GDI_OBJ_SIZE ObjSizes[] =
87 {
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)},
98 /*
99 {GDI_OBJECT_TYPE_DIRECTDRAW, sizeof(DD_DIRECTDRAW)},
100 {GDI_OBJECT_TYPE_DD_SURFACE, sizeof(DD_SURFACE)},
101 */
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}
109 };
110
111 #define OBJTYPE_COUNT (sizeof(ObjSizes) / sizeof(ObjSizes[0]))
112
113 /* GDI stock objects */
114
115 static LOGBRUSH WhiteBrush =
116 { BS_SOLID, RGB(255,255,255), 0 };
117
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 };
121
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 };
125
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 };
130
131 static LOGBRUSH BlackBrush =
132 { BS_SOLID, RGB(0,0,0), 0 };
133
134 static LOGBRUSH NullBrush =
135 { BS_NULL, 0, 0 };
136
137 static LOGPEN WhitePen =
138 { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
139
140 static LOGPEN BlackPen =
141 { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
142
143 static LOGPEN NullPen =
144 { PS_NULL, { 0, 0 }, 0 };
145
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" };
149
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" };
153
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" }; */
157
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" };
161
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" };
165
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" };
169
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" };
174
175 #define NB_STOCK_OBJECTS (DEFAULT_GUI_FONT + 1)
176
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
182 /*!
183 * Allocate GDI object table.
184 * \param Size - number of entries in the object table.
185 * Notes:: Must be called at IRQL < DISPATCH_LEVEL.
186 */
187 static PGDI_HANDLE_TABLE FASTCALL
188 GDIOBJ_iAllocHandleTable (WORD Size)
189 {
190 PGDI_HANDLE_TABLE handleTable;
191 ULONG MemSize;
192 UINT ObjType;
193
194 MemSize = sizeof(GDI_HANDLE_TABLE) + sizeof(PGDIOBJ) * Size;
195
196 /* prevent APC delivery for the *FastMutexUnsafe calls */
197 const KIRQL PrevIrql = KfRaiseIrql(APC_LEVEL);
198 ExAcquireFastMutexUnsafe (&HandleTableMutex);
199 handleTable = ExAllocatePoolWithTag(PagedPool, MemSize, TAG_GDIHNDTBLE);
200 ASSERT( handleTable );
201 memset (handleTable, 0, MemSize);
202 #if GDI_COUNT_OBJECTS
203 handleTable->HandlesCount = 0;
204 #endif
205 handleTable->wTableSize = Size;
206 handleTable->AllocationHint = 1;
207 handleTable->LookasideLists = ExAllocatePoolWithTag(PagedPool,
208 OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
209 TAG_GDIHNDTBLE);
210 if (NULL == handleTable->LookasideLists)
211 {
212 ExFreePool(handleTable);
213 ExReleaseFastMutexUnsafe (&HandleTableMutex);
214 KfLowerIrql(PrevIrql);
215 return NULL;
216 }
217 for (ObjType = 0; ObjType < OBJTYPE_COUNT; ObjType++)
218 {
219 ExInitializePagedLookasideList(handleTable->LookasideLists + ObjType, NULL, NULL, 0,
220 ObjSizes[ObjType].Size + sizeof(GDIOBJHDR), TAG_GDIOBJ, 0);
221 }
222 ExReleaseFastMutexUnsafe (&HandleTableMutex);
223 KfLowerIrql(PrevIrql);
224
225 return handleTable;
226 }
227
228 /*!
229 * Returns the entry into the handle table by index.
230 */
231 static PGDIOBJHDR FASTCALL
232 GDIOBJ_iGetObjectForIndex(WORD TableIndex)
233 {
234 if (0 == TableIndex || HandleTable->wTableSize < TableIndex)
235 {
236 DPRINT1("Invalid TableIndex %u\n", (unsigned) TableIndex);
237 return NULL;
238 }
239
240 return HandleTable->Handles[TableIndex];
241 }
242
243 /*!
244 * Finds next free entry in the GDI handle table.
245 * \return index into the table is successful, zero otherwise.
246 */
247 static WORD FASTCALL
248 GDIOBJ_iGetNextOpenHandleIndex (void)
249 {
250 WORD tableIndex;
251
252 for (tableIndex = HandleTable->AllocationHint;
253 tableIndex < HandleTable->wTableSize;
254 tableIndex++)
255 {
256 if (HandleTable->Handles[tableIndex] == NULL)
257 {
258 HandleTable->AllocationHint = tableIndex + 1;
259 return tableIndex;
260 }
261 }
262
263 for (tableIndex = 1;
264 tableIndex < HandleTable->AllocationHint;
265 tableIndex++)
266 {
267 if (HandleTable->Handles[tableIndex] == NULL)
268 {
269 HandleTable->AllocationHint = tableIndex + 1;
270 return tableIndex;
271 }
272 }
273
274 return 0;
275 }
276
277 static PPAGED_LOOKASIDE_LIST FASTCALL
278 FindLookasideList(DWORD ObjectType)
279 {
280 int Index;
281
282 for (Index = 0; Index < OBJTYPE_COUNT; Index++)
283 {
284 if (ObjSizes[Index].Type == ObjectType)
285 {
286 return HandleTable->LookasideLists + Index;
287 }
288 }
289
290 DPRINT1("Can't find lookaside list for object type 0x%08x\n", ObjectType);
291
292 return NULL;
293 }
294
295 /*!
296 * Allocate memory for GDI object and return handle to it.
297 *
298 * \param Size - size of the GDI object. This shouldn't to include the size of GDIOBJHDR.
299 * The actual amount of allocated memory is sizeof(GDIOBJHDR)+Size
300 * \param ObjectType - type of object \ref GDI object types
301 * \param CleanupProcPtr - Routine to be called on destruction of object
302 *
303 * \return Handle of the allocated object.
304 *
305 * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
306 */
307 HGDIOBJ FASTCALL
308 GDIOBJ_AllocObj(WORD Size, DWORD ObjectType, GDICLEANUPPROC CleanupProc)
309 {
310 PW32PROCESS W32Process;
311 PGDIOBJHDR newObject;
312 WORD Index;
313 PPAGED_LOOKASIDE_LIST LookasideList;
314
315 ExAcquireFastMutex(&HandleTableMutex);
316 Index = GDIOBJ_iGetNextOpenHandleIndex ();
317 if (0 == Index)
318 {
319 ExReleaseFastMutex(&HandleTableMutex);
320 DPRINT1("Out of GDI handles\n");
321 return NULL;
322 }
323
324 LookasideList = FindLookasideList(ObjectType);
325 if (NULL == LookasideList)
326 {
327 ExReleaseFastMutex(&HandleTableMutex);
328 return NULL;
329 }
330 newObject = ExAllocateFromPagedLookasideList(LookasideList);
331 if (NULL == newObject)
332 {
333 ExReleaseFastMutex(&HandleTableMutex);
334 DPRINT1("Unable to allocate GDI object from lookaside list\n");
335 return NULL;
336 }
337 RtlZeroMemory (newObject, Size + sizeof(GDIOBJHDR));
338
339 newObject->wTableIndex = Index;
340
341 newObject->dwCount = 0;
342 newObject->hProcessId = PsGetCurrentProcessId ();
343 newObject->CleanupProc = CleanupProc;
344 newObject->Magic = GDI_TYPE_TO_MAGIC(ObjectType);
345 newObject->lockfile = NULL;
346 newObject->lockline = 0;
347 ExInitializeFastMutex(&newObject->Lock);
348 HandleTable->Handles[Index] = newObject;
349 #if GDI_COUNT_OBJECTS
350 HandleTable->HandlesCount++;
351 #endif
352 ExReleaseFastMutex(&HandleTableMutex);
353
354 W32Process = PsGetCurrentProcess()->Win32Process;
355 if(W32Process)
356 {
357 W32Process->GDIObjects++;
358 }
359
360 return GDI_HANDLE_CREATE(Index, ObjectType);
361 }
362
363 /*!
364 * Free memory allocated for the GDI object. For each object type this function calls the
365 * appropriate cleanup routine.
366 *
367 * \param hObj - handle of the object to be deleted.
368 * \param ObjectType - one of the \ref GDI object types
369 * or GDI_OBJECT_TYPE_DONTCARE.
370 * \param Flag - if set to GDIOBJFLAG_IGNOREPID then the routine doesn't check if the process that
371 * tries to delete the object is the same one that created it.
372 *
373 * \return Returns TRUE if succesful.
374 *
375 * \note You should only use GDIOBJFLAG_IGNOREPID if you are cleaning up after the process that terminated.
376 * \note This function deferres object deletion if it is still in use.
377 */
378 BOOL STDCALL
379 GDIOBJ_FreeObj(HGDIOBJ hObj, DWORD ObjectType, DWORD Flag)
380 {
381 PW32PROCESS W32Process;
382 PGDIOBJHDR objectHeader;
383 PGDIOBJ Obj;
384 PPAGED_LOOKASIDE_LIST LookasideList;
385 BOOL bRet = TRUE;
386
387 objectHeader = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
388 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x, object: %x\n", hObj, objectHeader);
389
390 if (! GDI_VALID_OBJECT(hObj, objectHeader, ObjectType, Flag)
391 || GDI_GLOBAL_PROCESS == objectHeader->hProcessId)
392
393 {
394 DPRINT1("Can't delete hObj:0x%08x, type:0x%08x, flag:%d\n", hObj, ObjectType, Flag);
395 return FALSE;
396 }
397
398 DPRINT("FreeObj: locks: %x\n", objectHeader->dwCount );
399 if (!(Flag & GDIOBJFLAG_IGNORELOCK))
400 {
401 /* check that the reference count is zero. if not then set flag
402 * and delete object when releaseobj is called */
403 ExAcquireFastMutex(&RefCountHandling);
404 if ((objectHeader->dwCount & ~0x80000000) > 0 )
405 {
406 DPRINT("GDIOBJ_FreeObj: delayed object deletion: count %d\n", objectHeader->dwCount);
407 objectHeader->dwCount |= 0x80000000;
408 ExReleaseFastMutex(&RefCountHandling);
409 return TRUE;
410 }
411 ExReleaseFastMutex(&RefCountHandling);
412 }
413
414 /* allow object to delete internal data */
415 if (NULL != objectHeader->CleanupProc)
416 {
417 Obj = (PGDIOBJ)((PCHAR)objectHeader + sizeof(GDIOBJHDR));
418 bRet = (*(objectHeader->CleanupProc))(Obj);
419 }
420 LookasideList = FindLookasideList(GDI_MAGIC_TO_TYPE(objectHeader->Magic));
421 if (NULL != LookasideList)
422 {
423 ExFreeToPagedLookasideList(LookasideList, objectHeader);
424 }
425 ExAcquireFastMutexUnsafe (&HandleTableMutex);
426 HandleTable->Handles[GDI_HANDLE_GET_INDEX(hObj)] = NULL;
427 #if GDI_COUNT_OBJECTS
428 HandleTable->HandlesCount--;
429 #endif
430 ExReleaseFastMutexUnsafe (&HandleTableMutex);
431
432 W32Process = PsGetCurrentProcess()->Win32Process;
433 if(W32Process)
434 {
435 W32Process->GDIObjects--;
436 }
437
438 return bRet;
439 }
440
441 /*!
442 * Lock multiple objects. Use this function when you need to lock multiple objects and some of them may be
443 * duplicates. You should use this function to avoid trying to lock the same object twice!
444 *
445 * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields.
446 * \param nObj number of objects to lock
447 * \return for each entry in pList this function sets pObj field to point to the object.
448 *
449 * \note this function uses an O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
450 */
451 BOOL FASTCALL
452 GDIOBJ_LockMultipleObj(PGDIMULTILOCK pList, INT nObj)
453 {
454 INT i, j;
455 ASSERT( pList );
456 /* FIXME - check for "invalid" handles */
457 /* go through the list checking for duplicate objects */
458 for (i = 0; i < nObj; i++)
459 {
460 pList[i].pObj = NULL;
461 for (j = 0; j < i; j++)
462 {
463 if (pList[i].hObj == pList[j].hObj)
464 {
465 /* already locked, so just copy the pointer to the object */
466 pList[i].pObj = pList[j].pObj;
467 break;
468 }
469 }
470
471 if (NULL == pList[i].pObj)
472 {
473 /* object hasn't been locked, so lock it. */
474 if (NULL != pList[i].hObj)
475 {
476 pList[i].pObj = GDIOBJ_LockObj(pList[i].hObj, pList[i].ObjectType);
477 }
478 }
479 }
480
481 return TRUE;
482 }
483
484 /*!
485 * Unlock multiple objects. Use this function when you need to unlock multiple objects and some of them may be
486 * duplicates.
487 *
488 * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields.
489 * \param nObj number of objects to lock
490 *
491 * \note this function uses O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
492 */
493 BOOL FASTCALL
494 GDIOBJ_UnlockMultipleObj(PGDIMULTILOCK pList, INT nObj)
495 {
496 INT i, j;
497 ASSERT(pList);
498
499 /* go through the list checking for duplicate objects */
500 for (i = 0; i < nObj; i++)
501 {
502 if (NULL != pList[i].pObj)
503 {
504 for (j = i + 1; j < nObj; j++)
505 {
506 if ((pList[i].pObj == pList[j].pObj))
507 {
508 /* set the pointer to zero for all duplicates */
509 pList[j].pObj = NULL;
510 }
511 }
512 GDIOBJ_UnlockObj(pList[i].hObj, pList[i].ObjectType);
513 pList[i].pObj = NULL;
514 }
515 }
516
517 return TRUE;
518 }
519
520 /*!
521 * Get the type of the object.
522 * \param ObjectHandle - handle of the object.
523 * \return One of the \ref GDI object types
524 */
525 DWORD FASTCALL
526 GDIOBJ_GetObjectType(HGDIOBJ ObjectHandle)
527 {
528 PGDIOBJHDR ObjHdr;
529
530 ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
531 if (NULL == ObjHdr
532 || ! GDI_VALID_OBJECT(ObjectHandle, ObjHdr, GDI_MAGIC_TO_TYPE(ObjHdr->Magic), 0))
533 {
534 DPRINT1("Invalid ObjectHandle 0x%08x\n", ObjectHandle);
535 return 0;
536 }
537 DPRINT("GDIOBJ_GetObjectType for handle 0x%08x returns 0x%08x\n", ObjectHandle,
538 GDI_MAGIC_TO_TYPE(ObjHdr->Magic));
539
540 return GDI_MAGIC_TO_TYPE(ObjHdr->Magic);
541 }
542
543 /*!
544 * Initialization of the GDI object engine.
545 */
546 VOID FASTCALL
547 InitGdiObjectHandleTable (VOID)
548 {
549 DPRINT("InitGdiObjectHandleTable\n");
550 ExInitializeFastMutex (&HandleTableMutex);
551 ExInitializeFastMutex (&RefCountHandling);
552
553 HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_COUNT);
554 DPRINT("HandleTable: %x\n", HandleTable );
555
556 InitEngHandleTable();
557 }
558
559 /*!
560 * Creates a bunch of stock objects: brushes, pens, fonts.
561 */
562 VOID FASTCALL
563 CreateStockObjects(void)
564 {
565 unsigned Object;
566
567 DPRINT("Beginning creation of stock objects\n");
568
569 /* Create GDI Stock Objects from the logical structures we've defined */
570
571 StockObjects[WHITE_BRUSH] = IntGdiCreateBrushIndirect(&WhiteBrush);
572 StockObjects[LTGRAY_BRUSH] = IntGdiCreateBrushIndirect(&LtGrayBrush);
573 StockObjects[GRAY_BRUSH] = IntGdiCreateBrushIndirect(&GrayBrush);
574 StockObjects[DKGRAY_BRUSH] = IntGdiCreateBrushIndirect(&DkGrayBrush);
575 StockObjects[BLACK_BRUSH] = IntGdiCreateBrushIndirect(&BlackBrush);
576 StockObjects[NULL_BRUSH] = IntGdiCreateBrushIndirect(&NullBrush);
577
578 StockObjects[WHITE_PEN] = IntGdiCreatePenIndirect(&WhitePen);
579 StockObjects[BLACK_PEN] = IntGdiCreatePenIndirect(&BlackPen);
580 StockObjects[NULL_PEN] = IntGdiCreatePenIndirect(&NullPen);
581
582 (void) TextIntCreateFontIndirect(&OEMFixedFont, (HFONT*)&StockObjects[OEM_FIXED_FONT]);
583 (void) TextIntCreateFontIndirect(&AnsiFixedFont, (HFONT*)&StockObjects[ANSI_FIXED_FONT]);
584 (void) TextIntCreateFontIndirect(&SystemFont, (HFONT*)&StockObjects[SYSTEM_FONT]);
585 (void) TextIntCreateFontIndirect(&DeviceDefaultFont, (HFONT*)&StockObjects[DEVICE_DEFAULT_FONT]);
586 (void) TextIntCreateFontIndirect(&SystemFixedFont, (HFONT*)&StockObjects[SYSTEM_FIXED_FONT]);
587 (void) TextIntCreateFontIndirect(&DefaultGuiFont, (HFONT*)&StockObjects[DEFAULT_GUI_FONT]);
588
589 StockObjects[DEFAULT_PALETTE] = (HGDIOBJ*)PALETTE_Init();
590
591 for (Object = 0; Object < NB_STOCK_OBJECTS; Object++)
592 {
593 if (NULL != StockObjects[Object])
594 {
595 GDIOBJ_SetOwnership(StockObjects[Object], NULL);
596 /* GDI_HANDLE_SET_STOCKOBJ(StockObjects[Object]);*/
597 }
598 }
599
600 DPRINT("Completed creation of stock objects\n");
601 }
602
603 /*!
604 * Return stock object.
605 * \param Object - stock object id.
606 * \return Handle to the object.
607 */
608 HGDIOBJ STDCALL
609 NtGdiGetStockObject(INT Object)
610 {
611 DPRINT("NtGdiGetStockObject index %d\n", Object);
612
613 return ((Object < 0) || (NB_STOCK_OBJECTS <= Object)) ? NULL : StockObjects[Object];
614 }
615
616 /*!
617 * Delete GDI object
618 * \param hObject object handle
619 * \return if the function fails the returned value is FALSE.
620 */
621 BOOL STDCALL
622 NtGdiDeleteObject(HGDIOBJ hObject)
623 {
624 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
625
626 return NULL != hObject
627 ? GDIOBJ_FreeObj(hObject, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_DEFAULT) : FALSE;
628 }
629
630 /*!
631 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
632 * \param Process - PID of the process that will be destroyed.
633 */
634 BOOL FASTCALL
635 CleanupForProcess (struct _EPROCESS *Process, INT Pid)
636 {
637 DWORD i;
638 PGDIOBJHDR objectHeader;
639 PEPROCESS CurrentProcess;
640
641 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Pid);
642 CurrentProcess = PsGetCurrentProcess();
643 if (CurrentProcess != Process)
644 {
645 KeAttachProcess(Process);
646 }
647
648 for(i = 1; i < HandleTable->wTableSize; i++)
649 {
650 objectHeader = GDIOBJ_iGetObjectForIndex(i);
651 if (NULL != objectHeader &&
652 (INT) objectHeader->hProcessId == Pid)
653 {
654 DPRINT("CleanupForProcess: %d, process: %d, locks: %d, magic: 0x%x", i, objectHeader->hProcessId, objectHeader->dwCount, objectHeader->Magic);
655 GDIOBJ_FreeObj(GDI_HANDLE_CREATE(i, GDI_MAGIC_TO_TYPE(objectHeader->Magic)),
656 GDI_MAGIC_TO_TYPE(objectHeader->Magic),
657 GDIOBJFLAG_IGNOREPID | GDIOBJFLAG_IGNORELOCK);
658 }
659 }
660
661 if (CurrentProcess != Process)
662 {
663 KeDetachProcess();
664 }
665
666 DPRINT("Completed cleanup for process %d\n", Pid);
667
668 return TRUE;
669 }
670
671 #define GDIOBJ_TRACKLOCKS
672
673 #ifdef GDIOBJ_LockObj
674 #undef GDIOBJ_LockObj
675 PGDIOBJ FASTCALL
676 GDIOBJ_LockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
677 {
678 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
679
680 DPRINT("(%s:%i) GDIOBJ_LockObjDbg(0x%08x,0x%08x)\n", file, line, hObj, ObjectType);
681 if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
682 {
683 int reason = 0;
684 if (NULL == ObjHdr)
685 {
686 reason = 1;
687 }
688 else if (GDI_MAGIC_TO_TYPE(ObjHdr->Magic) != ObjectType && ObjectType != GDI_OBJECT_TYPE_DONTCARE)
689 {
690 reason = 2;
691 }
692 else if (ObjHdr->hProcessId != GDI_GLOBAL_PROCESS
693 && ObjHdr->hProcessId != PsGetCurrentProcessId())
694 {
695 reason = 3;
696 }
697 else if (GDI_HANDLE_GET_TYPE(hObj) != ObjectType && ObjectType != GDI_OBJECT_TYPE_DONTCARE)
698 {
699 reason = 4;
700 }
701 DPRINT1("GDIOBJ_LockObj failed for 0x%08x, reqtype 0x%08x reason %d\n",
702 hObj, ObjectType, reason );
703 DPRINT1("\tcalled from: %s:%i\n", file, line );
704 return NULL;
705 }
706
707 #ifdef NDEBUG
708 ExAcquireFastMutex(&ObjHdr->Lock);
709 #else /* NDEBUG */
710 if (! ExTryToAcquireFastMutex(&ObjHdr->Lock))
711 {
712 DPRINT1("Caution! GDIOBJ_LockObj trying to lock object 0x%x second time\n", hObj);
713 DPRINT1(" called from: %s:%i (thread %x)\n", file, line, KeGetCurrentThread());
714 if (NULL != ObjHdr->lockfile)
715 {
716 DPRINT1(" previously locked from: %s:%i (thread %x)\n", ObjHdr->lockfile, ObjHdr->lockline, ObjHdr->Lock.Owner);
717 }
718 ExAcquireFastMutex(&ObjHdr->Lock);
719 DPRINT1(" Disregard previous message about object 0x%x, it's ok\n", hObj);
720 }
721 #endif /* NDEBUG */
722
723 ExAcquireFastMutex(&RefCountHandling);
724 ObjHdr->dwCount++;
725 ExReleaseFastMutex(&RefCountHandling);
726
727 if (NULL == ObjHdr->lockfile)
728 {
729 ObjHdr->lockfile = file;
730 ObjHdr->lockline = line;
731 }
732
733 return (PGDIOBJ)((PCHAR)ObjHdr + sizeof(GDIOBJHDR));
734 }
735 #endif//GDIOBJ_LockObj
736
737 #ifdef GDIOBJ_UnlockObj
738 #undef GDIOBJ_UnlockObj
739 BOOL FASTCALL
740 GDIOBJ_UnlockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
741 {
742 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
743
744 if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
745 {
746 DPRINT1("GDIBOJ_UnlockObj failed for 0x%08x, reqtype 0x%08x\n",
747 hObj, ObjectType);
748 DPRINT1("\tcalled from: %s:%i\n", file, line);
749 return FALSE;
750 }
751 DPRINT("(%s:%i) GDIOBJ_UnlockObj(0x%08x,0x%08x)\n", file, line, hObj, ObjectType);
752 ObjHdr->lockfile = NULL;
753 ObjHdr->lockline = 0;
754
755 return GDIOBJ_UnlockObj(hObj, ObjectType);
756 }
757 #endif//GDIOBJ_LockObj
758
759 /*!
760 * Return pointer to the object by handle.
761 *
762 * \param hObj Object handle
763 * \param ObjectType one of the object types defined in \ref GDI object types
764 * \return Pointer to the object.
765 *
766 * \note Process can only get pointer to the objects it created or global objects.
767 *
768 * \todo Don't allow to lock the objects twice! Synchronization!
769 */
770 PGDIOBJ FASTCALL
771 GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ObjectType)
772 {
773 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
774
775 DPRINT("GDIOBJ_LockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj, ObjectType, ObjHdr);
776 if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
777 {
778 DPRINT1("GDIBOJ_LockObj failed for 0x%08x, type 0x%08x\n",
779 hObj, ObjectType);
780 return NULL;
781 }
782
783 ExAcquireFastMutex(&ObjHdr->Lock);
784
785 ExAcquireFastMutex(&RefCountHandling);
786 ObjHdr->dwCount++;
787 ExReleaseFastMutex(&RefCountHandling);
788 return (PGDIOBJ)((PCHAR)ObjHdr + sizeof(GDIOBJHDR));
789 }
790
791 /*!
792 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
793 * as soon as you don't need to have access to it's data.
794
795 * \param hObj Object handle
796 * \param ObjectType one of the object types defined in \ref GDI object types
797 *
798 * \note This function performs delayed cleanup. If the object is locked when GDI_FreeObj() is called
799 * then \em this function frees the object when reference count is zero.
800 *
801 * \todo Change synchronization algorithm.
802 */
803 #undef GDIOBJ_UnlockObj
804 BOOL FASTCALL
805 GDIOBJ_UnlockObj(HGDIOBJ hObj, DWORD ObjectType)
806 {
807 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
808
809 DPRINT("GDIOBJ_UnlockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj, ObjectType, ObjHdr);
810 if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
811 {
812 DPRINT1( "GDIOBJ_UnLockObj: failed\n");
813 return FALSE;
814 }
815
816 ExReleaseFastMutex(&ObjHdr->Lock);
817
818 ExAcquireFastMutex(&RefCountHandling);
819 if (0 == (ObjHdr->dwCount & ~0x80000000))
820 {
821 ExReleaseFastMutex(&RefCountHandling);
822 DPRINT1( "GDIOBJ_UnLockObj: unlock object (0x%x) that is not locked\n", hObj );
823 return FALSE;
824 }
825
826 ObjHdr->dwCount--;
827
828 if (ObjHdr->dwCount == 0x80000000)
829 {
830 //delayed object release
831 ObjHdr->dwCount = 0;
832 ExReleaseFastMutex(&RefCountHandling);
833 DPRINT("GDIOBJ_UnlockObj: delayed delete\n");
834 return GDIOBJ_FreeObj(hObj, ObjectType, GDIOBJFLAG_DEFAULT);
835 }
836 ExReleaseFastMutex(&RefCountHandling);
837
838 return TRUE;
839 }
840
841 BOOL FASTCALL
842 GDIOBJ_OwnedByCurrentProcess(HGDIOBJ ObjectHandle)
843 {
844 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
845
846 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
847 ASSERT(GDI_VALID_OBJECT(ObjectHandle, ObjHdr, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_IGNOREPID));
848
849 return ObjHdr->hProcessId == PsGetCurrentProcessId();
850 }
851
852 void FASTCALL
853 GDIOBJ_SetOwnership(HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
854 {
855 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
856 PEPROCESS OldProcess;
857 PW32PROCESS W32Process;
858 NTSTATUS Status;
859
860 DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
861 ASSERT(GDI_VALID_OBJECT(ObjectHandle, ObjHdr, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_IGNOREPID));
862
863 if ((NULL == NewOwner && GDI_GLOBAL_PROCESS != ObjHdr->hProcessId)
864 || (NULL != NewOwner && ObjHdr->hProcessId != (HANDLE) NewOwner->UniqueProcessId))
865 {
866 Status = PsLookupProcessByProcessId((PVOID)ObjHdr->hProcessId, &OldProcess);
867 if (NT_SUCCESS(Status))
868 {
869 W32Process = OldProcess->Win32Process;
870 if (W32Process)
871 {
872 W32Process->GDIObjects--;
873 }
874 ObDereferenceObject(OldProcess);
875 }
876 }
877
878 if (NULL == NewOwner)
879 {
880 ObjHdr->hProcessId = GDI_GLOBAL_PROCESS;
881 }
882 else if (ObjHdr->hProcessId != (HANDLE) NewOwner->UniqueProcessId)
883 {
884 ObjHdr->hProcessId = (HANDLE) NewOwner->UniqueProcessId;
885 W32Process = NewOwner->Win32Process;
886 if (W32Process)
887 {
888 W32Process->GDIObjects++;
889 }
890 }
891 }
892
893 void FASTCALL
894 GDIOBJ_CopyOwnership(HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
895 {
896 PGDIOBJHDR ObjHdrFrom = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(CopyFrom));
897 PGDIOBJHDR ObjHdrTo = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(CopyTo));
898 NTSTATUS Status;
899 PEPROCESS ProcessFrom;
900 PEPROCESS CurrentProcess;
901
902 ASSERT(NULL != ObjHdrFrom && NULL != ObjHdrTo);
903 if (NULL != ObjHdrFrom && NULL != ObjHdrTo
904 && ObjHdrTo->hProcessId != ObjHdrFrom->hProcessId)
905 {
906 if (ObjHdrFrom->hProcessId == GDI_GLOBAL_PROCESS)
907 {
908 GDIOBJ_SetOwnership(CopyTo, NULL);
909 }
910 else
911 {
912 /* Warning: ugly hack ahead
913 *
914 * During process cleanup, we can't call PsLookupProcessByProcessId
915 * for the current process, 'cause that function will try to
916 * reference the process, and since the process is closing down
917 * that will result in a bugcheck.
918 * So, instead, we call PsGetCurrentProcess, which doesn't reference
919 * the process. If the current process is indeed the one we're
920 * looking for, we use it, otherwise we can (safely) call
921 * PsLookupProcessByProcessId
922 */
923 CurrentProcess = PsGetCurrentProcess();
924 if (ObjHdrFrom->hProcessId == (HANDLE) CurrentProcess->UniqueProcessId)
925 {
926 GDIOBJ_SetOwnership(CopyTo, CurrentProcess);
927 }
928 else
929 {
930 Status = PsLookupProcessByProcessId((PVOID) ObjHdrFrom->hProcessId, &ProcessFrom);
931 if (NT_SUCCESS(Status))
932 {
933 GDIOBJ_SetOwnership(CopyTo, ProcessFrom);
934 ObDereferenceObject(ProcessFrom);
935 }
936 }
937 }
938 }
939 }
940
941 /* EOF */