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