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