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