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