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