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