Patch, as suggested by Mike Nordell, to verify IRQL before calling unsafe fast mutex...
[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.46 2003/10/15 03:09:23 vizzini 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 #define NDEBUG
42 #include <win32k/debug1.h>
43
44 /*! Size of the GDI handle table
45 * http://www.windevnet.com/documents/s=7290/wdj9902b/9902b.htm
46 * gdi handle table can hold 0x4000 handles
47 */
48 #define GDI_HANDLE_COUNT 0x4000
49
50 #define GDI_GLOBAL_PROCESS ((HANDLE) 0xffffffff)
51
52 #define GDI_HANDLE_INDEX_MASK (GDI_HANDLE_COUNT - 1)
53 #define GDI_HANDLE_TYPE_MASK 0x007f0000
54 #define GDI_HANDLE_STOCK_MASK 0x00800000
55
56 #define GDI_HANDLE_CREATE(i, t) ((HANDLE)(((i) & GDI_HANDLE_INDEX_MASK) | ((t) & GDI_HANDLE_TYPE_MASK)))
57 #define GDI_HANDLE_GET_INDEX(h) (((DWORD)(h)) & GDI_HANDLE_INDEX_MASK)
58 #define GDI_HANDLE_GET_TYPE(h) (((DWORD)(h)) & GDI_HANDLE_TYPE_MASK)
59 #define GDI_HANDLE_IS_TYPE(h, t) ((t) == (((DWORD)(h)) & GDI_HANDLE_TYPE_MASK))
60 #define GDI_HANDLE_IS_STOCKOBJ(h) (0 != (((DWORD)(h)) & GDI_HANDLE_STOCK_MASK))
61 #define GDI_HANDLE_SET_STOCKOBJ(h) ((h) = (HANDLE)(((DWORD)(h)) | GDI_HANDLE_STOCK_MASK))
62
63 #define GDI_TYPE_TO_MAGIC(t) ((WORD) ((t) >> 16))
64 #define GDI_MAGIC_TO_TYPE(m) ((DWORD)(m) << 16)
65
66 #define GDI_VALID_OBJECT(h, obj, t, f) \
67 (NULL != (obj) \
68 && (GDI_MAGIC_TO_TYPE((obj)->Magic) == (t) || GDI_OBJECT_TYPE_DONTCARE == (t)) \
69 && (GDI_HANDLE_GET_TYPE((h)) == GDI_MAGIC_TO_TYPE((obj)->Magic)) \
70 && (((obj)->hProcessId == PsGetCurrentProcessId()) \
71 || (GDI_GLOBAL_PROCESS == (obj)->hProcessId) \
72 || ((f) & GDIOBJFLAG_IGNOREPID)))
73
74 typedef struct _GDI_HANDLE_TABLE
75 {
76 WORD wTableSize;
77 PGDIOBJHDR Handles[1];
78 } GDI_HANDLE_TABLE, *PGDI_HANDLE_TABLE;
79
80 /* GDI stock objects */
81
82 static LOGBRUSH WhiteBrush =
83 { BS_SOLID, RGB(255,255,255), 0 };
84
85 static LOGBRUSH LtGrayBrush =
86 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
87 { BS_SOLID, RGB(192,192,192), 0 };
88
89 static LOGBRUSH GrayBrush =
90 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
91 { BS_SOLID, RGB(128,128,128), 0 };
92
93 static LOGBRUSH DkGrayBrush =
94 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
95 /* NB_HATCH_STYLES is an index into HatchBrushes */
96 { BS_HATCHED, RGB(0,0,0), NB_HATCH_STYLES };
97
98 static LOGBRUSH BlackBrush =
99 { BS_SOLID, RGB(0,0,0), 0 };
100
101 static LOGBRUSH NullBrush =
102 { BS_NULL, 0, 0 };
103
104 static LOGPEN WhitePen =
105 { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
106
107 static LOGPEN BlackPen =
108 { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
109
110 static LOGPEN NullPen =
111 { PS_NULL, { 0, 0 }, 0 };
112
113 static LOGFONTW OEMFixedFont =
114 { 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
115 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
116
117 static LOGFONTW AnsiFixedFont =
118 { 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
119 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
120
121 /*static LOGFONTW AnsiVarFont =
122 *{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
123 * 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" }; */
124
125 static LOGFONTW SystemFont =
126 { 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
127 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"System" };
128
129 static LOGFONTW DeviceDefaultFont =
130 { 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
131 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"" };
132
133 static LOGFONTW SystemFixedFont =
134 { 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
135 0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
136
137 /* FIXME: Is this correct? */
138 static LOGFONTW DefaultGuiFont =
139 { 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
140 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" };
141
142 #define NB_STOCK_OBJECTS (DEFAULT_GUI_FONT + 1)
143
144 static HGDIOBJ *StockObjects[NB_STOCK_OBJECTS];
145 static PGDI_HANDLE_TABLE HandleTable = 0;
146 static FAST_MUTEX HandleTableMutex;
147 static FAST_MUTEX RefCountHandling;
148
149 /*!
150 * Allocate GDI object table.
151 * \param Size - number of entries in the object table.
152 */
153 static PGDI_HANDLE_TABLE FASTCALL
154 GDIOBJ_iAllocHandleTable (WORD Size)
155 {
156 PGDI_HANDLE_TABLE handleTable;
157 KIRQL OldIrql;
158 BOOLEAN IrqlRaised = FALSE;
159
160 if(KeGetCurrentIrql() < APC_LEVEL)
161 {
162 KeRaiseIrql(APC_LEVEL, &OldIrql);
163 IrqlRaised = TRUE;
164 }
165
166 ExAcquireFastMutexUnsafe (&HandleTableMutex);
167 handleTable = ExAllocatePool(PagedPool,
168 sizeof(GDI_HANDLE_TABLE) +
169 sizeof(PGDIOBJ) * Size);
170 ASSERT( handleTable );
171 memset (handleTable,
172 0,
173 sizeof(GDI_HANDLE_TABLE) + sizeof(PGDIOBJ) * Size);
174 handleTable->wTableSize = Size;
175 ExReleaseFastMutexUnsafe (&HandleTableMutex);
176
177 if(IrqlRaised)
178 KeLowerIrql(OldIrql);
179
180 return handleTable;
181 }
182
183 /*!
184 * Returns the entry into the handle table by index.
185 */
186 static PGDIOBJHDR FASTCALL
187 GDIOBJ_iGetObjectForIndex(WORD TableIndex)
188 {
189 if (0 == TableIndex || HandleTable->wTableSize < TableIndex)
190 {
191 DPRINT1("Invalid TableIndex %u\n", (unsigned) TableIndex);
192 return NULL;
193 }
194
195 return HandleTable->Handles[TableIndex];
196 }
197
198 /*!
199 * Finds next free entry in the GDI handle table.
200 * \return index into the table is successful, zero otherwise.
201 */
202 static WORD FASTCALL
203 GDIOBJ_iGetNextOpenHandleIndex (void)
204 {
205 WORD tableIndex;
206 BOOLEAN IrqlRaised = FALSE;
207 KIRQL OldIrql;
208
209 if(KeGetCurrentIrql() < APC_LEVEL)
210 {
211 KeRaiseIrql(APC_LEVEL, &OldIrql);
212 IrqlRaised = TRUE;
213 }
214
215 ExAcquireFastMutexUnsafe (&HandleTableMutex);
216 for (tableIndex = 1; tableIndex < HandleTable->wTableSize; tableIndex++)
217 {
218 if (NULL == HandleTable->Handles[tableIndex])
219 {
220 HandleTable->Handles[tableIndex] = (PGDIOBJHDR) -1;
221 break;
222 }
223 }
224 ExReleaseFastMutexUnsafe (&HandleTableMutex);
225
226 if(IrqlRaised)
227 KeLowerIrql(OldIrql);
228
229 return (tableIndex < HandleTable->wTableSize) ? tableIndex : 0;
230 }
231
232 /*!
233 * Allocate memory for GDI object and return handle to it.
234 *
235 * \param Size - size of the GDI object. This shouldn't to include the size of GDIOBJHDR.
236 * The actual amount of allocated memory is sizeof(GDIOBJHDR)+Size
237 * \param ObjectType - type of object \ref GDI object types
238 * \param CleanupProcPtr - Routine to be called on destruction of object
239 *
240 * \return Handle of the allocated object.
241 *
242 * \note Use GDIOBJ_Lock() to obtain pointer to the new object.
243 */
244 HGDIOBJ FASTCALL
245 GDIOBJ_AllocObj(WORD Size, DWORD ObjectType, GDICLEANUPPROC CleanupProc)
246 {
247 PGDIOBJHDR newObject;
248 WORD Index;
249
250 Index = GDIOBJ_iGetNextOpenHandleIndex ();
251 if (0 == Index)
252 {
253 DPRINT1("Out of GDI handles\n");
254 return NULL;
255 }
256
257 DPRINT("GDIOBJ_AllocObj: handle: %d, size: %d, type: 0x%08x\n", Index, Size, ObjectType);
258 newObject = ExAllocatePool(PagedPool, Size + sizeof (GDIOBJHDR));
259 if (newObject == NULL)
260 {
261 DPRINT1("GDIOBJ_AllocObj: failed\n");
262 return NULL;
263 }
264 RtlZeroMemory (newObject, Size + sizeof(GDIOBJHDR));
265
266 newObject->wTableIndex = Index;
267
268 newObject->dwCount = 0;
269 newObject->hProcessId = PsGetCurrentProcessId ();
270 newObject->CleanupProc = CleanupProc;
271 newObject->Magic = GDI_TYPE_TO_MAGIC(ObjectType);
272 newObject->lockfile = NULL;
273 newObject->lockline = 0;
274 HandleTable->Handles[Index] = newObject;
275
276 return GDI_HANDLE_CREATE(Index, ObjectType);
277 }
278
279 /*!
280 * Free memory allocated for the GDI object. For each object type this function calls the
281 * appropriate cleanup routine.
282 *
283 * \param hObj - handle of the object to be deleted.
284 * \param ObjectType - one of the \ref GDI object types
285 * or GDI_OBJECT_TYPE_DONTCARE.
286 * \param Flag - if set to GDIOBJFLAG_IGNOREPID then the routine doesn't check if the process that
287 * tries to delete the object is the same one that created it.
288 *
289 * \return Returns TRUE if succesful.
290 *
291 * \note You should only use GDIOBJFLAG_IGNOREPID if you are cleaning up after the process that terminated.
292 * \note This function deferres object deletion if it is still in use.
293 */
294 BOOL STDCALL
295 GDIOBJ_FreeObj(HGDIOBJ hObj, DWORD ObjectType, DWORD Flag)
296 {
297 PGDIOBJHDR objectHeader;
298 PGDIOBJ Obj;
299 BOOL bRet = TRUE;
300
301 objectHeader = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
302 DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x, object: %x\n", hObj, objectHeader);
303
304 if (! GDI_VALID_OBJECT(hObj, objectHeader, ObjectType, Flag)
305 || GDI_GLOBAL_PROCESS == objectHeader->hProcessId)
306
307 {
308 DPRINT1("Can't delete hObj:0x%08x, type:0x%08x, flag:%d\n", hObj, ObjectType, Flag);
309 return FALSE;
310 }
311
312 DPRINT("FreeObj: locks: %x\n", objectHeader->dwCount );
313 if (!(Flag & GDIOBJFLAG_IGNORELOCK))
314 {
315 /* check that the reference count is zero. if not then set flag
316 * and delete object when releaseobj is called */
317 ExAcquireFastMutex(&RefCountHandling);
318 if ((objectHeader->dwCount & ~0x80000000) > 0 )
319 {
320 DPRINT("GDIOBJ_FreeObj: delayed object deletion: count %d\n", objectHeader->dwCount);
321 objectHeader->dwCount |= 0x80000000;
322 ExReleaseFastMutex(&RefCountHandling);
323 return TRUE;
324 }
325 ExReleaseFastMutex(&RefCountHandling);
326 }
327
328 /* allow object to delete internal data */
329 if (NULL != objectHeader->CleanupProc)
330 {
331 Obj = (PGDIOBJ)((PCHAR)objectHeader + sizeof(GDIOBJHDR));
332 bRet = (*(objectHeader->CleanupProc))(Obj);
333 }
334
335 ExFreePool(objectHeader);
336 HandleTable->Handles[GDI_HANDLE_GET_INDEX(hObj)] = NULL;
337
338 return bRet;
339 }
340
341 /*!
342 * Lock multiple objects. Use this function when you need to lock multiple objects and some of them may be
343 * duplicates. You should use this function to avoid trying to lock the same object twice!
344 *
345 * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields.
346 * \param nObj number of objects to lock
347 * \return for each entry in pList this function sets pObj field to point to the object.
348 *
349 * \note this function uses an O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
350 */
351 BOOL FASTCALL
352 GDIOBJ_LockMultipleObj(PGDIMULTILOCK pList, INT nObj)
353 {
354 INT i, j;
355 ASSERT( pList );
356 /* FIXME - check for "invalid" handles */
357 /* go through the list checking for duplicate objects */
358 for (i = 0; i < nObj; i++)
359 {
360 pList[i].pObj = NULL;
361 for (j = 0; j < i; j++)
362 {
363 if (pList[i].hObj == pList[j].hObj)
364 {
365 /* already locked, so just copy the pointer to the object */
366 pList[i].pObj = pList[j].pObj;
367 break;
368 }
369 }
370
371 if (NULL == pList[i].pObj)
372 {
373 /* object hasn't been locked, so lock it. */
374 if (NULL != pList[i].hObj)
375 {
376 pList[i].pObj = GDIOBJ_LockObj(pList[i].hObj, pList[i].ObjectType);
377 }
378 }
379 }
380
381 return TRUE;
382 }
383
384 /*!
385 * Unlock multiple objects. Use this function when you need to unlock multiple objects and some of them may be
386 * duplicates.
387 *
388 * \param pList pointer to the list that contains handles to the objects. You should set hObj and ObjectType fields.
389 * \param nObj number of objects to lock
390 *
391 * \note this function uses O(n^2) algoritm because we shouldn't need to call it with more than 3 or 4 objects.
392 */
393 BOOL FASTCALL
394 GDIOBJ_UnlockMultipleObj(PGDIMULTILOCK pList, INT nObj)
395 {
396 INT i, j;
397 ASSERT(pList);
398
399 /* go through the list checking for duplicate objects */
400 for (i = 0; i < nObj; i++)
401 {
402 if (NULL != pList[i].pObj)
403 {
404 for (j = i + 1; j < nObj; j++)
405 {
406 if ((pList[i].pObj == pList[j].pObj))
407 {
408 /* set the pointer to zero for all duplicates */
409 pList[j].pObj = NULL;
410 }
411 }
412 GDIOBJ_UnlockObj(pList[i].hObj, pList[i].ObjectType);
413 pList[i].pObj = NULL;
414 }
415 }
416
417 return TRUE;
418 }
419
420 /*!
421 * Marks the object as global. (Creator process ID is set to GDI_GLOBAL_PROCESS). Global objects may be
422 * accessed by any process.
423 * \param ObjectHandle - handle of the object to make global.
424 *
425 * \note Only stock objects should be marked global.
426 */
427 VOID FASTCALL
428 GDIOBJ_MarkObjectGlobal(HGDIOBJ ObjectHandle)
429 {
430 PGDIOBJHDR ObjHdr;
431
432 DPRINT("GDIOBJ_MarkObjectGlobal handle 0x%08x\n", ObjectHandle);
433 ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
434 if (NULL == ObjHdr)
435 {
436 return;
437 }
438
439 ObjHdr->hProcessId = GDI_GLOBAL_PROCESS;
440 }
441
442 /*!
443 * Removes the global mark from the object. Global objects may be
444 * accessed by any process.
445 * \param ObjectHandle - handle of the object to make local.
446 *
447 * \note Only stock objects should be marked global.
448 */
449 VOID FASTCALL
450 GDIOBJ_UnmarkObjectGlobal(HGDIOBJ ObjectHandle)
451 {
452 PGDIOBJHDR ObjHdr;
453
454 DPRINT("GDIOBJ_MarkObjectGlobal handle 0x%08x\n", ObjectHandle);
455 ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
456 if (NULL == ObjHdr || GDI_GLOBAL_PROCESS != ObjHdr->hProcessId)
457 {
458 return;
459 }
460
461 ObjHdr->hProcessId = PsGetCurrentProcessId();
462 }
463
464 /*!
465 * Get the type of the object.
466 * \param ObjectHandle - handle of the object.
467 * \return One of the \ref GDI object types
468 */
469 DWORD FASTCALL
470 GDIOBJ_GetObjectType(HGDIOBJ ObjectHandle)
471 {
472 PGDIOBJHDR ObjHdr;
473
474 ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(ObjectHandle));
475 if (NULL == ObjHdr
476 || ! GDI_VALID_OBJECT(ObjectHandle, ObjHdr, GDI_MAGIC_TO_TYPE(ObjHdr->Magic), 0))
477 {
478 DPRINT1("Invalid ObjectHandle 0x%08x\n", ObjectHandle);
479 return 0;
480 }
481 DPRINT("GDIOBJ_GetObjectType for handle 0x%08x returns 0x%08x\n", ObjectHandle,
482 GDI_MAGIC_TO_TYPE(ObjHdr->Magic));
483
484 return GDI_MAGIC_TO_TYPE(ObjHdr->Magic);
485 }
486
487 /*!
488 * Initialization of the GDI object engine.
489 */
490 VOID FASTCALL
491 InitGdiObjectHandleTable (VOID)
492 {
493 DPRINT("InitGdiObjectHandleTable\n");
494 ExInitializeFastMutex (&HandleTableMutex);
495 ExInitializeFastMutex (&RefCountHandling);
496
497 HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_COUNT);
498 DPRINT("HandleTable: %x\n", HandleTable );
499
500 InitEngHandleTable();
501 }
502
503 /*!
504 * Creates a bunch of stock objects: brushes, pens, fonts.
505 */
506 VOID FASTCALL
507 CreateStockObjects(void)
508 {
509 unsigned Object;
510
511 DPRINT("Beginning creation of stock objects\n");
512
513 /* Create GDI Stock Objects from the logical structures we've defined */
514
515 StockObjects[WHITE_BRUSH] = NtGdiCreateBrushIndirect(&WhiteBrush);
516 StockObjects[LTGRAY_BRUSH] = NtGdiCreateBrushIndirect(&LtGrayBrush);
517 StockObjects[GRAY_BRUSH] = NtGdiCreateBrushIndirect(&GrayBrush);
518 StockObjects[DKGRAY_BRUSH] = NtGdiCreateBrushIndirect(&DkGrayBrush);
519 StockObjects[BLACK_BRUSH] = NtGdiCreateBrushIndirect(&BlackBrush);
520 StockObjects[NULL_BRUSH] = NtGdiCreateBrushIndirect(&NullBrush);
521
522 StockObjects[WHITE_PEN] = NtGdiCreatePenIndirect(&WhitePen);
523 StockObjects[BLACK_PEN] = NtGdiCreatePenIndirect(&BlackPen);
524 StockObjects[NULL_PEN] = NtGdiCreatePenIndirect(&NullPen);
525
526 (void) TextIntCreateFontIndirect(&OEMFixedFont, (HFONT*)&StockObjects[OEM_FIXED_FONT]);
527 (void) TextIntCreateFontIndirect(&AnsiFixedFont, (HFONT*)&StockObjects[ANSI_FIXED_FONT]);
528 (void) TextIntCreateFontIndirect(&SystemFont, (HFONT*)&StockObjects[SYSTEM_FONT]);
529 (void) TextIntCreateFontIndirect(&DeviceDefaultFont, (HFONT*)&StockObjects[DEVICE_DEFAULT_FONT]);
530 (void) TextIntCreateFontIndirect(&SystemFixedFont, (HFONT*)&StockObjects[SYSTEM_FIXED_FONT]);
531 (void) TextIntCreateFontIndirect(&DefaultGuiFont, (HFONT*)&StockObjects[DEFAULT_GUI_FONT]);
532
533 StockObjects[DEFAULT_PALETTE] = (HGDIOBJ*)PALETTE_Init();
534
535 for (Object = 0; Object < NB_STOCK_OBJECTS; Object++)
536 {
537 if (NULL != StockObjects[Object])
538 {
539 GDIOBJ_MarkObjectGlobal(StockObjects[Object]);
540 /* GDI_HANDLE_SET_STOCKOBJ(StockObjects[Object]);*/
541 }
542 }
543
544 DPRINT("Completed creation of stock objects\n");
545 }
546
547 /*!
548 * Return stock object.
549 * \param Object - stock object id.
550 * \return Handle to the object.
551 */
552 HGDIOBJ STDCALL
553 NtGdiGetStockObject(INT Object)
554 {
555 DPRINT("NtGdiGetStockObject index %d\n", Object);
556
557 return ((Object < 0) || (NB_STOCK_OBJECTS <= Object)) ? NULL : StockObjects[Object];
558 }
559
560 /*!
561 * Delete GDI object
562 * \param hObject object handle
563 * \return if the function fails the returned value is FALSE.
564 */
565 BOOL STDCALL
566 NtGdiDeleteObject(HGDIOBJ hObject)
567 {
568 DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
569
570 return GDIOBJ_FreeObj(hObject, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_DEFAULT);
571 }
572
573 /*!
574 * Internal function. Called when the process is destroyed to free the remaining GDI handles.
575 * \param Process - PID of the process that will be destroyed.
576 */
577 BOOL FASTCALL
578 CleanupForProcess (struct _EPROCESS *Process, INT Pid)
579 {
580 DWORD i;
581 PGDIOBJHDR objectHeader;
582 PEPROCESS CurrentProcess;
583
584 DPRINT("Starting CleanupForProcess prochandle %x Pid %d\n", Process, Pid);
585 CurrentProcess = PsGetCurrentProcess();
586 if (CurrentProcess != Process)
587 {
588 KeAttachProcess(Process);
589 }
590
591 for(i = 1; i < HandleTable->wTableSize; i++)
592 {
593 objectHeader = GDIOBJ_iGetObjectForIndex(i);
594 if (NULL != objectHeader &&
595 (INT) objectHeader->hProcessId == Pid)
596 {
597 DPRINT("CleanupForProcess: %d, process: %d, locks: %d, magic: 0x%x", i, objectHeader->hProcessId, objectHeader->dwCount, objectHeader->Magic);
598 GDIOBJ_FreeObj(GDI_HANDLE_CREATE(i, GDI_MAGIC_TO_TYPE(objectHeader->Magic)),
599 GDI_MAGIC_TO_TYPE(objectHeader->Magic),
600 GDIOBJFLAG_IGNOREPID | GDIOBJFLAG_IGNORELOCK);
601 }
602 }
603
604 if (CurrentProcess != Process)
605 {
606 KeDetachProcess();
607 }
608
609 DPRINT("Completed cleanup for process %d\n", Pid);
610
611 return TRUE;
612 }
613
614 #define GDIOBJ_TRACKLOCKS
615
616 #ifdef GDIOBJ_LockObj
617 #undef GDIOBJ_LockObj
618 PGDIOBJ FASTCALL
619 GDIOBJ_LockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
620 {
621 PGDIOBJ rc;
622 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
623
624 if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
625 {
626 int reason = 0;
627 if (NULL == ObjHdr)
628 {
629 reason = 1;
630 }
631 else if (GDI_MAGIC_TO_TYPE(ObjHdr->Magic) != ObjectType && ObjectType != GDI_OBJECT_TYPE_DONTCARE)
632 {
633 reason = 2;
634 }
635 else if (ObjHdr->hProcessId != GDI_GLOBAL_PROCESS
636 && ObjHdr->hProcessId != PsGetCurrentProcessId())
637 {
638 reason = 3;
639 }
640 else if (GDI_HANDLE_GET_TYPE(hObj) != ObjectType && ObjectType != GDI_OBJECT_TYPE_DONTCARE)
641 {
642 reason = 4;
643 }
644 DPRINT1("GDIOBJ_LockObj failed for 0x%08x, reqtype 0x%08x reason %d\n",
645 hObj, ObjectType, reason );
646 DPRINT1("\tcalled from: %s:%i\n", file, line );
647 return NULL;
648 }
649 if (NULL != ObjHdr->lockfile)
650 {
651 DPRINT1("Caution! GDIOBJ_LockObj trying to lock object (0x%x) second time\n", hObj );
652 DPRINT1("\tcalled from: %s:%i\n", file, line );
653 DPRINT1("\tpreviously locked from: %s:%i\n", ObjHdr->lockfile, ObjHdr->lockline );
654 }
655 DPRINT("(%s:%i) GDIOBJ_LockObj(0x%08x,0x%08x)\n", file, line, hObj, ObjectType);
656 rc = GDIOBJ_LockObj(hObj, ObjectType);
657 if (rc && NULL == ObjHdr->lockfile)
658 {
659 ObjHdr->lockfile = file;
660 ObjHdr->lockline = line;
661 }
662
663 return rc;
664 }
665 #endif//GDIOBJ_LockObj
666
667 #ifdef GDIOBJ_UnlockObj
668 #undef GDIOBJ_UnlockObj
669 BOOL FASTCALL
670 GDIOBJ_UnlockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
671 {
672 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
673
674 if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
675 {
676 DPRINT1("GDIBOJ_UnlockObj failed for 0x%08x, reqtype 0x%08x\n",
677 hObj, ObjectType);
678 DPRINT1("\tcalled from: %s:%i\n", file, line);
679 return FALSE;
680 }
681 DPRINT("(%s:%i) GDIOBJ_UnlockObj(0x%08x,0x%08x)\n", file, line, hObj, ObjectType);
682 ObjHdr->lockfile = NULL;
683 ObjHdr->lockline = 0;
684
685 return GDIOBJ_UnlockObj(hObj, ObjectType);
686 }
687 #endif//GDIOBJ_LockObj
688
689 /*!
690 * Return pointer to the object by handle.
691 *
692 * \param hObj Object handle
693 * \param ObjectType one of the object types defined in \ref GDI object types
694 * \return Pointer to the object.
695 *
696 * \note Process can only get pointer to the objects it created or global objects.
697 *
698 * \todo Don't allow to lock the objects twice! Synchronization!
699 */
700 PGDIOBJ FASTCALL
701 GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ObjectType)
702 {
703 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
704
705 DPRINT("GDIOBJ_LockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj, ObjectType, ObjHdr);
706 if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
707 {
708 DPRINT1("GDIBOJ_LockObj failed for 0x%08x, type 0x%08x\n",
709 hObj, ObjectType);
710 return NULL;
711 }
712
713 if(0 < ObjHdr->dwCount)
714 {
715 DPRINT1("Caution! GDIOBJ_LockObj trying to lock object (0x%x) second time\n", hObj);
716 DPRINT1("\t called from: %x\n", __builtin_return_address(0));
717 }
718
719 ExAcquireFastMutex(&RefCountHandling);
720 ObjHdr->dwCount++;
721 ExReleaseFastMutex(&RefCountHandling);
722 return (PGDIOBJ)((PCHAR)ObjHdr + sizeof(GDIOBJHDR));
723 }
724
725 /*!
726 * Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
727 * as soon as you don't need to have access to it's data.
728
729 * \param hObj Object handle
730 * \param ObjectType one of the object types defined in \ref GDI object types
731 *
732 * \note This function performs delayed cleanup. If the object is locked when GDI_FreeObj() is called
733 * then \em this function frees the object when reference count is zero.
734 *
735 * \todo Change synchronization algorithm.
736 */
737 #undef GDIOBJ_UnlockObj
738 BOOL FASTCALL
739 GDIOBJ_UnlockObj(HGDIOBJ hObj, DWORD ObjectType)
740 {
741 PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
742
743 DPRINT("GDIOBJ_UnlockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj, ObjectType, ObjHdr);
744 if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
745 {
746 DPRINT1( "GDIOBJ_UnLockObj: failed\n");
747 return FALSE;
748 }
749
750 ExAcquireFastMutex(&RefCountHandling);
751 if (0 == (ObjHdr->dwCount & ~0x80000000))
752 {
753 ExReleaseFastMutex(&RefCountHandling);
754 DPRINT1( "GDIOBJ_UnLockObj: unlock object (0x%x) that is not locked\n", hObj );
755 return FALSE;
756 }
757
758 ObjHdr->dwCount--;
759
760 if (ObjHdr->dwCount == 0x80000000)
761 {
762 //delayed object release
763 ObjHdr->dwCount = 0;
764 ExReleaseFastMutex(&RefCountHandling);
765 DPRINT("GDIOBJ_UnlockObj: delayed delete\n");
766 return GDIOBJ_FreeObj(hObj, ObjectType, GDIOBJFLAG_DEFAULT);
767 }
768 ExReleaseFastMutex(&RefCountHandling);
769
770 return TRUE;
771 }
772
773 /* EOF */