1 /* 2 * PROJECT: ReactOS win32 kernel mode subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/gdiobj.c 5 * PURPOSE: General GDI object manipulation routines 6 * PROGRAMMERS: Timo Kreuzer 7 */ 8 9 /* 10 * If you want to understand this code, you need to start thinking in portals. 11 * - gpaulRefCount is a global pointer to an allocated array of ULONG values, 12 * one for each handle. Bits 0 - 22 contain a reference count for the handle. 13 * It gets increased for each handle lock / reference. Bit 23 contains a valid 14 * bit. If this bit is 0, the handle got deleted and will be pushed to the free 15 * list, once all references are gone. Bits 24 - 31 contain the reuse value of 16 * the handle, which allows to check if the entry was changed before atomically 17 * exchanging the reference count. 18 * - Objects can exist with or without a handle 19 * - Objects with a handle can be locked either exclusively or shared. 20 * Both locks increase the handle reference count in gpaulRefCount. 21 * Exclusive locks also increase the BASEOBJECT's cExclusiveLock field 22 * and the first lock (can be acquired recursively) acquires a pushlock 23 * that is also stored in the BASEOBJECT. 24 * - Objects without a handle cannot have exclusive locks. Their reference 25 * count is tracked in the BASEOBJECT's ulShareCount field. 26 * - An object that is inserted in the handle table automatically has an 27 * exclusive lock. For objects that are "shared objects" (BRUSH, PALETTE, ...) 28 * this is the only way it can ever be exclusively locked. It prevents the 29 * object from being locked by another thread. A shared lock will simply fail, 30 * while an exclusive lock will succeed after the object was unlocked. 31 * 32 * Ownership: 33 * 34 * Owner: POWNED PUBLIC NONE spec 35 * --------------------------------------------------- 36 * LockForRead + + - PUBLIC 37 * LockForWrite + - - POWNED 38 * LockAny + + + NONE 39 * NtGdiDeleteObjectApp + - - PUBLIC 40 * GreDeleteObject + + + NONE 41 * GreSetOwner(POWNED) - - + - 42 * GreSetOwner(PUBLIC) + - + - 43 * GreSetOwner(NONE) + - - - 44 * 45 */ 46 47 /* INCLUDES ******************************************************************/ 48 49 #include <win32k.h> 50 #define NDEBUG 51 #include <debug.h> 52 53 FORCEINLINE 54 ULONG 55 InterlockedReadUlong( 56 _In_ _Interlocked_operand_ ULONG volatile *Source) 57 { 58 return *Source; 59 } 60 61 FORCEINLINE 62 void 63 INCREASE_THREAD_LOCK_COUNT( 64 _In_ HANDLE hobj) 65 { 66 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 67 DBG_UNREFERENCED_PARAMETER(hobj); 68 if (pti) 69 { 70 #if DBG 71 pti->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]++; 72 #endif 73 pti->cExclusiveLocks++; 74 } 75 } 76 77 FORCEINLINE 78 void 79 DECREASE_THREAD_LOCK_COUNT( 80 _In_ HANDLE hobj) 81 { 82 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 83 DBG_UNREFERENCED_PARAMETER(hobj); 84 if (pti) 85 { 86 #if DBG 87 pti->acExclusiveLockCount[((ULONG_PTR)hobj >> 16) & 0x1f]--; 88 #endif 89 pti->cExclusiveLocks--; 90 } 91 } 92 93 #if DBG 94 VOID 95 ASSERT_LOCK_ORDER( 96 _In_ UCHAR objt) 97 { 98 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 99 ULONG i; 100 101 if (pti) 102 { 103 /* Ensure correct locking order! */ 104 for (i = objt + 1; i < GDIObjTypeTotal; i++) 105 { 106 NT_ASSERT(pti->acExclusiveLockCount[i] == 0); 107 } 108 } 109 } 110 #define ASSERT_SHARED_OBJECT_TYPE(objt) \ 111 ASSERT((objt) == GDIObjType_SURF_TYPE || \ 112 (objt) == GDIObjType_PAL_TYPE || \ 113 (objt) == GDIObjType_LFONT_TYPE || \ 114 (objt) == GDIObjType_PATH_TYPE || \ 115 (objt) == GDIObjType_BRUSH_TYPE) 116 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) \ 117 ASSERT((objt) == GDIObjType_DC_TYPE || \ 118 (objt) == GDIObjType_RGN_TYPE || \ 119 (objt) == GDIObjType_UMPD_TYPE || \ 120 (objt) == GDIObjType_META_TYPE) 121 #define ASSERT_TRYLOCK_OBJECT_TYPE(objt) \ 122 ASSERT((objt) == GDIObjType_DRVOBJ_TYPE) 123 #else 124 #define ASSERT_LOCK_ORDER(hobj) 125 #define ASSERT_SHARED_OBJECT_TYPE(objt) 126 #define ASSERT_EXCLUSIVE_OBJECT_TYPE(objt) 127 #define ASSERT_TRYLOCK_OBJECT_TYPE(objt) 128 #endif 129 130 #if defined(_M_IX86) || defined(_M_AMD64) 131 #define InterlockedOr16 _InterlockedOr16 132 #endif 133 134 #define GDIOBJ_POOL_TAG(type) ('00hG' + (((type) & 0x1f) << 24)) 135 136 enum 137 { 138 REF_MASK_REUSE = 0xff000000, 139 REF_INC_REUSE = 0x01000000, 140 REF_MASK_VALID = 0x00800000, 141 REF_MASK_COUNT = 0x007fffff, 142 REF_MASK_INUSE = 0x00ffffff, 143 }; 144 145 /* GLOBALS *******************************************************************/ 146 147 /* Per session handle table globals */ 148 static PVOID gpvGdiHdlTblSection = NULL; 149 PENTRY gpentHmgr; 150 PULONG gpaulRefCount; 151 volatile ULONG gulFirstFree; 152 volatile ULONG gulFirstUnused; 153 static PPAGED_LOOKASIDE_LIST gpaLookasideList; 154 155 static VOID NTAPI GDIOBJ_vCleanup(PVOID ObjectBody); 156 157 static const 158 GDICLEANUPPROC 159 apfnCleanup[] = 160 { 161 NULL, /* 00 GDIObjType_DEF_TYPE */ 162 DC_vCleanup, /* 01 GDIObjType_DC_TYPE */ 163 NULL, /* 02 GDIObjType_UNUSED1_TYPE */ 164 NULL, /* 03 GDIObjType_UNUSED2_TYPE */ 165 REGION_vCleanup, /* 04 GDIObjType_RGN_TYPE */ 166 SURFACE_vCleanup, /* 05 GDIObjType_SURF_TYPE */ 167 GDIOBJ_vCleanup, /* 06 GDIObjType_CLIENTOBJ_TYPE */ 168 GDIOBJ_vCleanup, /* 07 GDIObjType_PATH_TYPE */ 169 PALETTE_vCleanup, /* 08 GDIObjType_PAL_TYPE */ 170 GDIOBJ_vCleanup, /* 09 GDIObjType_ICMLCS_TYPE */ 171 GDIOBJ_vCleanup, /* 0a GDIObjType_LFONT_TYPE */ 172 NULL, /* 0b GDIObjType_RFONT_TYPE, unused */ 173 NULL, /* 0c GDIObjType_PFE_TYPE, unused */ 174 NULL, /* 0d GDIObjType_PFT_TYPE, unused */ 175 GDIOBJ_vCleanup, /* 0e GDIObjType_ICMCXF_TYPE */ 176 NULL, /* 0f GDIObjType_SPRITE_TYPE, unused */ 177 NULL, /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */ 178 NULL, /* 11 GDIObjType_UMPD_TYPE, unused */ 179 NULL, /* 12 GDIObjType_UNUSED4_TYPE */ 180 NULL, /* 13 GDIObjType_SPACE_TYPE, unused */ 181 NULL, /* 14 GDIObjType_UNUSED5_TYPE */ 182 GDIOBJ_vCleanup, /* 15 GDIObjType_META_TYPE */ 183 NULL, /* 16 GDIObjType_EFSTATE_TYPE, unused */ 184 NULL, /* 17 GDIObjType_BMFD_TYPE, unused */ 185 NULL, /* 18 GDIObjType_VTFD_TYPE, unused */ 186 NULL, /* 19 GDIObjType_TTFD_TYPE, unused */ 187 NULL, /* 1a GDIObjType_RC_TYPE, unused */ 188 NULL, /* 1b GDIObjType_TEMP_TYPE, unused */ 189 DRIVEROBJ_vCleanup,/* 1c GDIObjType_DRVOBJ_TYPE */ 190 NULL, /* 1d GDIObjType_DCIOBJ_TYPE, unused */ 191 NULL, /* 1e GDIObjType_SPOOL_TYPE, unused */ 192 NULL, /* 1f reserved entry */ 193 }; 194 195 static const 196 GDIOBJDELETEPROC 197 apfnDelete[] = 198 { 199 NULL, /* 00 GDIObjType_DEF_TYPE */ 200 NULL, /* 01 GDIObjType_DC_TYPE */ 201 NULL, /* 02 GDIObjType_UNUSED1_TYPE */ 202 NULL, /* 03 GDIObjType_UNUSED2_TYPE */ 203 NULL, /* 04 GDIObjType_RGN_TYPE */ 204 NULL, /* 05 GDIObjType_SURF_TYPE */ 205 NULL, /* 06 GDIObjType_CLIENTOBJ_TYPE */ 206 NULL, /* 07 GDIObjType_PATH_TYPE */ 207 NULL, /* 08 GDIObjType_PAL_TYPE */ 208 NULL, /* 09 GDIObjType_ICMLCS_TYPE */ 209 NULL, /* 0a GDIObjType_LFONT_TYPE */ 210 NULL, /* 0b GDIObjType_RFONT_TYPE, unused */ 211 NULL, /* 0c GDIObjType_PFE_TYPE, unused */ 212 NULL, /* 0d GDIObjType_PFT_TYPE, unused */ 213 NULL, /* 0e GDIObjType_ICMCXF_TYPE */ 214 NULL, /* 0f GDIObjType_SPRITE_TYPE, unused */ 215 BRUSH_vDeleteObject, /* 10 GDIObjType_BRUSH_TYPE, BRUSH, PEN, EXTPEN */ 216 NULL, /* 11 GDIObjType_UMPD_TYPE, unused */ 217 NULL, /* 12 GDIObjType_UNUSED4_TYPE */ 218 NULL, /* 13 GDIObjType_SPACE_TYPE, unused */ 219 NULL, /* 14 GDIObjType_UNUSED5_TYPE */ 220 NULL, /* 15 GDIObjType_META_TYPE, unused */ 221 NULL, /* 16 GDIObjType_EFSTATE_TYPE, unused */ 222 NULL, /* 17 GDIObjType_BMFD_TYPE, unused */ 223 NULL, /* 18 GDIObjType_VTFD_TYPE, unused */ 224 NULL, /* 19 GDIObjType_TTFD_TYPE, unused */ 225 NULL, /* 1a GDIObjType_RC_TYPE, unused */ 226 NULL, /* 1b GDIObjType_TEMP_TYPE, unused */ 227 NULL, /* 1c GDIObjType_DRVOBJ_TYPE */ 228 NULL, /* 1d GDIObjType_DCIOBJ_TYPE, unused */ 229 NULL, /* 1e GDIObjType_SPOOL_TYPE, unused */ 230 NULL, /* 1f reserved entry */ 231 }; 232 233 /* INTERNAL FUNCTIONS ********************************************************/ 234 235 static 236 VOID 237 NTAPI 238 GDIOBJ_vCleanup(PVOID ObjectBody) 239 { 240 /* Nothing to do */ 241 } 242 243 static 244 VOID 245 InitLookasideList(UCHAR objt, ULONG cjSize) 246 { 247 ExInitializePagedLookasideList(&gpaLookasideList[objt], 248 NULL, 249 NULL, 250 0, 251 cjSize, 252 GDITAG_HMGR_LOOKASIDE_START + (objt << 24), 253 0); 254 } 255 256 CODE_SEG("INIT") 257 NTSTATUS 258 NTAPI 259 InitGdiHandleTable(void) 260 { 261 NTSTATUS status; 262 LARGE_INTEGER liSize; 263 PVOID pvSection; 264 SIZE_T cjViewSize = 0; 265 266 /* Create a section for the shared handle table */ 267 liSize.QuadPart = sizeof(GDI_HANDLE_TABLE); // GDI_HANDLE_COUNT * sizeof(ENTRY); 268 status = MmCreateSection(&gpvGdiHdlTblSection, 269 SECTION_ALL_ACCESS, 270 NULL, 271 &liSize, 272 PAGE_READWRITE, 273 SEC_COMMIT | 0x1, 274 NULL, 275 NULL); 276 if (!NT_SUCCESS(status)) 277 { 278 DPRINT1("INITGDI: Could not allocate a GDI handle table.\n"); 279 return status; 280 } 281 282 /* Map the section in session space */ 283 status = MmMapViewInSessionSpace(gpvGdiHdlTblSection, 284 (PVOID*)&gpentHmgr, 285 &cjViewSize); 286 if (!NT_SUCCESS(status)) 287 { 288 DPRINT1("INITGDI: Failed to map handle table section\n"); 289 ObDereferenceObject(gpvGdiHdlTblSection); 290 return status; 291 } 292 293 /* Allocate memory for the reference counter table */ 294 gpaulRefCount = EngAllocSectionMem(&pvSection, 295 FL_ZERO_MEMORY, 296 GDI_HANDLE_COUNT * sizeof(ULONG), 297 'frHG'); 298 if (!gpaulRefCount) 299 { 300 DPRINT1("INITGDI: Failed to allocate reference table.\n"); 301 ObDereferenceObject(gpvGdiHdlTblSection); 302 return STATUS_INSUFFICIENT_RESOURCES; 303 } 304 305 gulFirstFree = 0; 306 gulFirstUnused = RESERVE_ENTRIES_COUNT; 307 308 GdiHandleTable = (PVOID)gpentHmgr; 309 310 /* Initialize the lookaside lists */ 311 gpaLookasideList = ExAllocatePoolWithTag(NonPagedPool, 312 GDIObjTypeTotal * sizeof(PAGED_LOOKASIDE_LIST), 313 TAG_GDIHNDTBLE); 314 if(!gpaLookasideList) 315 return STATUS_NO_MEMORY; 316 317 InitLookasideList(GDIObjType_DC_TYPE, sizeof(DC)); 318 InitLookasideList(GDIObjType_RGN_TYPE, sizeof(REGION)); 319 InitLookasideList(GDIObjType_SURF_TYPE, sizeof(SURFACE)); 320 InitLookasideList(GDIObjType_CLIENTOBJ_TYPE, sizeof(CLIENTOBJ)); 321 InitLookasideList(GDIObjType_PATH_TYPE, sizeof(PATH)); 322 InitLookasideList(GDIObjType_PAL_TYPE, sizeof(PALETTE)); 323 InitLookasideList(GDIObjType_ICMLCS_TYPE, sizeof(COLORSPACE)); 324 InitLookasideList(GDIObjType_LFONT_TYPE, sizeof(TEXTOBJ)); 325 InitLookasideList(GDIObjType_BRUSH_TYPE, sizeof(BRUSH)); 326 327 return STATUS_SUCCESS; 328 } 329 330 FORCEINLINE 331 VOID 332 IncrementCurrentProcessGdiHandleCount(void) 333 { 334 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process(); 335 if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount); 336 } 337 338 FORCEINLINE 339 VOID 340 DecrementCurrentProcessGdiHandleCount(void) 341 { 342 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process(); 343 if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount); 344 } 345 346 static inline 347 VOID 348 IncrementGdiHandleCount(ULONG ulProcessId) 349 { 350 PEPROCESS pep; 351 PPROCESSINFO ppi; 352 NTSTATUS Status; 353 354 Status = PsLookupProcessByProcessId(ULongToHandle(ulProcessId), &pep); 355 NT_ASSERT(NT_SUCCESS(Status)); 356 __analysis_assume(NT_SUCCESS(Status)); 357 358 ppi = PsGetProcessWin32Process(pep); 359 if (ppi) InterlockedIncrement((LONG*)&ppi->GDIHandleCount); 360 if (NT_SUCCESS(Status)) ObDereferenceObject(pep); 361 } 362 363 static inline 364 VOID 365 DecrementGdiHandleCount(ULONG ulProcessId) 366 { 367 PEPROCESS pep; 368 PPROCESSINFO ppi; 369 NTSTATUS Status; 370 371 Status = PsLookupProcessByProcessId(ULongToHandle(ulProcessId), &pep); 372 NT_ASSERT(NT_SUCCESS(Status)); 373 __analysis_assume(NT_SUCCESS(Status)); 374 375 ppi = PsGetProcessWin32Process(pep); 376 if (ppi) InterlockedDecrement((LONG*)&ppi->GDIHandleCount); 377 if (NT_SUCCESS(Status)) ObDereferenceObject(pep); 378 } 379 380 static 381 PENTRY 382 ENTRY_pentPopFreeEntry(VOID) 383 { 384 ULONG iFirst, iNext, iPrev; 385 PENTRY pentFree; 386 387 DPRINT("Enter InterLockedPopFreeEntry\n"); 388 389 do 390 { 391 /* Get the index and sequence number of the first free entry */ 392 iFirst = InterlockedReadUlong(&gulFirstFree); 393 394 /* Check if we have a free entry */ 395 if (!(iFirst & GDI_HANDLE_INDEX_MASK)) 396 { 397 /* Increment FirstUnused and get the new index */ 398 iFirst = InterlockedIncrement((LONG*)&gulFirstUnused) - 1; 399 400 /* Check if we have unused entries left */ 401 if (iFirst >= GDI_HANDLE_COUNT) 402 { 403 DPRINT1("No more GDI handles left!\n"); 404 #if DBG_ENABLE_GDIOBJ_BACKTRACES 405 DbgDumpGdiHandleTableWithBT(); 406 #endif 407 InterlockedDecrement((LONG*)&gulFirstUnused); 408 return 0; 409 } 410 411 /* Return the old entry */ 412 return &gpentHmgr[iFirst]; 413 } 414 415 /* Get a pointer to the first free entry */ 416 pentFree = &gpentHmgr[iFirst & GDI_HANDLE_INDEX_MASK]; 417 418 /* Create a new value with an increased sequence number */ 419 iNext = GDI_HANDLE_GET_INDEX(pentFree->einfo.hFree); 420 iNext |= (iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000; 421 422 /* Try to exchange the FirstFree value */ 423 iPrev = InterlockedCompareExchange((LONG*)&gulFirstFree, 424 iNext, 425 iFirst); 426 } 427 while (iPrev != iFirst); 428 429 /* Sanity check: is entry really free? */ 430 ASSERT(((ULONG_PTR)pentFree->einfo.pobj & ~GDI_HANDLE_INDEX_MASK) == 0); 431 432 return pentFree; 433 } 434 435 /* Pushes an entry of the handle table to the free list, 436 The entry must not have any references left */ 437 static 438 VOID 439 ENTRY_vPushFreeEntry(PENTRY pentFree) 440 { 441 ULONG iToFree, iFirst, iPrev, idxToFree; 442 443 DPRINT("Enter ENTRY_vPushFreeEntry\n"); 444 445 idxToFree = pentFree - gpentHmgr; 446 ASSERT((gpaulRefCount[idxToFree] & REF_MASK_INUSE) == 0); 447 448 /* Initialize entry */ 449 pentFree->Objt = GDIObjType_DEF_TYPE; 450 pentFree->ObjectOwner.ulObj = 0; 451 pentFree->pUser = NULL; 452 453 /* Increase reuse counter in entry and reference counter */ 454 InterlockedExchangeAdd((LONG*)&gpaulRefCount[idxToFree], REF_INC_REUSE); 455 pentFree->FullUnique += 0x0100; 456 457 do 458 { 459 /* Get the current first free index and sequence number */ 460 iFirst = InterlockedReadUlong(&gulFirstFree); 461 462 /* Set the einfo.pobj member to the index of the first free entry */ 463 pentFree->einfo.pobj = UlongToPtr(iFirst & GDI_HANDLE_INDEX_MASK); 464 465 /* Combine new index and increased sequence number in iToFree */ 466 iToFree = idxToFree | ((iFirst & ~GDI_HANDLE_INDEX_MASK) + 0x10000); 467 468 /* Try to atomically update the first free entry */ 469 iPrev = InterlockedCompareExchange((LONG*)&gulFirstFree, 470 iToFree, 471 iFirst); 472 } 473 while (iPrev != iFirst); 474 } 475 476 static 477 PENTRY 478 ENTRY_ReferenceEntryByHandle(HGDIOBJ hobj, FLONG fl) 479 { 480 ULONG ulIndex, cNewRefs, cOldRefs; 481 PENTRY pentry; 482 483 /* Get the handle index and check if its too big */ 484 ulIndex = GDI_HANDLE_GET_INDEX(hobj); 485 486 /* Get pointer to the entry */ 487 pentry = &gpentHmgr[ulIndex]; 488 489 /* Get the current reference count */ 490 cOldRefs = gpaulRefCount[ulIndex]; 491 492 do 493 { 494 /* Check if the slot is deleted */ 495 if ((cOldRefs & REF_MASK_VALID) == 0) 496 { 497 DPRINT("GDIOBJ: Slot is not valid: 0x%lx, hobh=%p\n", cOldRefs, hobj); 498 return NULL; 499 } 500 501 /* Check if the unique value matches */ 502 if (pentry->FullUnique != (USHORT)((ULONG_PTR)hobj >> 16)) 503 { 504 DPRINT("GDIOBJ: Wrong unique value. Handle: 0x%4x, entry: 0x%4x\n", 505 (USHORT)((ULONG_PTR)hobj >> 16), pentry->FullUnique); 506 return NULL; 507 } 508 509 /* Check if the object owner is this process or public */ 510 if (!(fl & GDIOBJFLAG_IGNOREPID) && 511 pentry->ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC && 512 pentry->ObjectOwner.ulObj != PtrToUlong(PsGetCurrentProcessId())) 513 { 514 DPRINT("GDIOBJ: Cannot reference foreign handle %p, pentry=%p:%lx.\n", 515 hobj, pentry, pentry->ObjectOwner.ulObj); 516 return NULL; 517 } 518 519 /* Try to atomically increment the reference count */ 520 cNewRefs = cOldRefs + 1; 521 cOldRefs = InterlockedCompareExchange((PLONG)&gpaulRefCount[ulIndex], 522 cNewRefs, 523 cOldRefs); 524 } 525 while (cNewRefs != cOldRefs + 1); 526 527 /* Integrity checks */ 528 ASSERT((pentry->FullUnique & 0x1f) == pentry->Objt); 529 ASSERT(pentry->einfo.pobj != NULL); 530 531 /* Check if lower 32 bits match, the upper 32 bits are ignored */ 532 ASSERT(pentry->einfo.pobj->hHmgr == UlongToPtr(PtrToUlong(hobj))); 533 534 return pentry; 535 } 536 537 static 538 HGDIOBJ 539 ENTRY_hInsertObject(PENTRY pentry, POBJ pobj, UCHAR objt, ULONG ulOwner) 540 { 541 ULONG ulIndex; 542 543 /* Calculate the handle index */ 544 ulIndex = pentry - gpentHmgr; 545 546 /* Update the fields in the ENTRY */ 547 pentry->einfo.pobj = pobj; 548 pentry->Objt = objt & 0x1f; 549 pentry->FullUnique = (pentry->FullUnique & 0xff00) | objt; 550 pentry->ObjectOwner.ulObj = ulOwner; 551 552 /* Make the handle valid with 1 reference */ 553 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_INUSE) == 0); 554 InterlockedOr((LONG*)&gpaulRefCount[ulIndex], REF_MASK_VALID | 1); 555 556 /* Return the handle */ 557 return (HGDIOBJ)(((ULONG_PTR)pentry->FullUnique << 16) | ulIndex); 558 } 559 560 POBJ 561 NTAPI 562 GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl) 563 { 564 POBJ pobj; 565 566 if (fl & BASEFLAG_LOOKASIDE) 567 { 568 /* Allocate the object from a lookaside list */ 569 pobj = ExAllocateFromPagedLookasideList(&gpaLookasideList[objt & 0x1f]); 570 } 571 else 572 { 573 /* Allocate the object from paged pool */ 574 pobj = ExAllocatePoolWithTag(PagedPool, cjSize, GDIOBJ_POOL_TAG(objt)); 575 } 576 577 if (!pobj) return NULL; 578 579 /* Initialize the object */ 580 RtlZeroMemory(pobj, cjSize); 581 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)objt << 16); 582 pobj->cExclusiveLock = 0; 583 pobj->ulShareCount = 1; 584 pobj->BaseFlags = fl & 0xffff; 585 DBG_INITLOG(&pobj->slhLog); 586 DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0); 587 #if DBG_ENABLE_GDIOBJ_BACKTRACES 588 DbgCaptureStackBackTace(pobj->apvBackTrace, 1, GDI_OBJECT_STACK_LEVELS); 589 #endif /* GDI_DEBUG */ 590 591 return pobj; 592 } 593 594 VOID 595 NTAPI 596 GDIOBJ_vFreeObject(POBJ pobj) 597 { 598 UCHAR objt; 599 600 DBG_CLEANUP_EVENT_LIST(&pobj->slhLog); 601 602 /* Get the object type */ 603 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0x1f; 604 605 /* Check if we have a delete procedure (for C++ based objects) */ 606 if (apfnDelete[objt] != NULL) 607 { 608 /* Invoke the delete procedure */ 609 apfnDelete[objt](pobj); 610 } 611 else 612 { 613 /* Call the cleanup procedure */ 614 NT_ASSERT(apfnCleanup[objt]); 615 apfnCleanup[objt](pobj); 616 617 /* Check if the object is allocated from a lookaside list */ 618 if (pobj->BaseFlags & BASEFLAG_LOOKASIDE) 619 { 620 ExFreeToPagedLookasideList(&gpaLookasideList[objt], pobj); 621 } 622 else 623 { 624 ExFreePoolWithTag(pobj, GDIOBJ_POOL_TAG(objt)); 625 } 626 } 627 } 628 629 VOID 630 NTAPI 631 GDIOBJ_vDereferenceObject(POBJ pobj) 632 { 633 ULONG cRefs, ulIndex; 634 635 /* Calculate the index */ 636 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 637 638 /* Check if the object has a handle */ 639 if (ulIndex) 640 { 641 /* Decrement reference count */ 642 if ((gpaulRefCount[ulIndex] & REF_MASK_COUNT) == 0) 643 { 644 DBG_DUMP_EVENT_LIST(&pobj->slhLog); 645 } 646 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); 647 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]); 648 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs); 649 650 /* Check if we reached 0 and handle bit is not set */ 651 if ((cRefs & REF_MASK_INUSE) == 0) 652 { 653 /* Make sure it's ok to delete the object */ 654 ASSERT(pobj->BaseFlags & BASEFLAG_READY_TO_DIE); 655 656 /* Check if the handle was process owned */ 657 if (gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC && 658 gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE) 659 { 660 /* Decrement the process handle count */ 661 ASSERT(gpentHmgr[ulIndex].ObjectOwner.ulObj == 662 HandleToUlong(PsGetCurrentProcessId())); 663 DecrementCurrentProcessGdiHandleCount(); 664 } 665 666 /* Push entry to the free list */ 667 ENTRY_vPushFreeEntry(&gpentHmgr[ulIndex]); 668 669 /* Free the object */ 670 GDIOBJ_vFreeObject(pobj); 671 } 672 } 673 else 674 { 675 /* Decrement the objects reference count */ 676 ASSERT(pobj->ulShareCount > 0); 677 cRefs = InterlockedDecrement((LONG*)&pobj->ulShareCount); 678 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs); 679 680 /* Check if we reached 0 */ 681 if (cRefs == 0) 682 { 683 /* Free the object */ 684 GDIOBJ_vFreeObject(pobj); 685 } 686 } 687 } 688 689 POBJ 690 NTAPI 691 GDIOBJ_ReferenceObjectByHandle( 692 HGDIOBJ hobj, 693 UCHAR objt) 694 { 695 PENTRY pentry; 696 POBJ pobj; 697 698 /* Check if the handle type matches */ 699 ASSERT_SHARED_OBJECT_TYPE(objt); 700 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt) 701 { 702 DPRINT("GDIOBJ: Wrong type. handle=%p, type=%x\n", hobj, objt); 703 return NULL; 704 } 705 706 /* Reference the handle entry */ 707 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 708 if (!pentry) 709 { 710 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj); 711 return NULL; 712 } 713 714 /* Get the pointer to the BASEOBJECT */ 715 pobj = pentry->einfo.pobj; 716 717 /* Check if the object is exclusively locked */ 718 if (pobj->cExclusiveLock != 0) 719 { 720 DPRINT1("GDIOBJ: Cannot reference object %p with exclusive lock.\n", hobj); 721 GDIOBJ_vDereferenceObject(pobj); 722 DBG_DUMP_EVENT_LIST(&pobj->slhLog); 723 return NULL; 724 } 725 726 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, gpaulRefCount[pentry - gpentHmgr]); 727 728 /* All is well, return the object */ 729 return pobj; 730 } 731 732 VOID 733 NTAPI 734 GDIOBJ_vReferenceObjectByPointer(POBJ pobj) 735 { 736 ULONG cRefs; 737 738 /* Check if the object has a handle */ 739 if (GDI_HANDLE_GET_INDEX(pobj->hHmgr)) 740 { 741 /* Increase the handle's reference count */ 742 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 743 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); 744 cRefs = InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]); 745 } 746 else 747 { 748 /* Increase the object's reference count */ 749 cRefs = InterlockedIncrement((LONG*)&pobj->ulShareCount); 750 } 751 752 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs); 753 } 754 755 PGDIOBJ 756 NTAPI 757 GDIOBJ_TryLockObject( 758 HGDIOBJ hobj, 759 UCHAR objt) 760 { 761 PENTRY pentry; 762 POBJ pobj; 763 DWORD dwThreadId; 764 765 /* Check if the handle type matches */ 766 ASSERT_TRYLOCK_OBJECT_TYPE(objt); 767 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt) 768 { 769 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt); 770 return NULL; 771 } 772 773 /* Make sure lock order is correct */ 774 ASSERT_LOCK_ORDER(objt); 775 776 /* Reference the handle entry */ 777 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 778 if (!pentry) 779 { 780 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj); 781 return NULL; 782 } 783 784 /* Get the pointer to the BASEOBJECT */ 785 pobj = pentry->einfo.pobj; 786 787 /* Check if we already own the lock */ 788 dwThreadId = PtrToUlong(PsGetCurrentThreadId()); 789 if (pobj->dwThreadId != dwThreadId) 790 { 791 /* Disable APCs and try acquiring the push lock */ 792 KeEnterCriticalRegion(); 793 if(!ExTryAcquirePushLockExclusive(&pobj->pushlock)) 794 { 795 ULONG cRefs, ulIndex; 796 /* Already owned. Clean up and leave. */ 797 KeLeaveCriticalRegion(); 798 799 /* Calculate the index */ 800 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 801 802 /* Decrement reference count */ 803 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); 804 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]); 805 ASSERT(cRefs & REF_MASK_VALID); 806 807 return NULL; 808 } 809 810 /* Set us as lock owner */ 811 ASSERT(pobj->dwThreadId == 0); 812 pobj->dwThreadId = dwThreadId; 813 } 814 815 /* Increase lock count */ 816 pobj->cExclusiveLock++; 817 INCREASE_THREAD_LOCK_COUNT(hobj); 818 DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0); 819 820 /* Return the object */ 821 return pobj; 822 } 823 824 PGDIOBJ 825 NTAPI 826 GDIOBJ_LockObject( 827 HGDIOBJ hobj, 828 UCHAR objt) 829 { 830 PENTRY pentry; 831 POBJ pobj; 832 DWORD dwThreadId; 833 834 /* Check if the handle type matches */ 835 ASSERT_EXCLUSIVE_OBJECT_TYPE(objt); 836 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt) 837 { 838 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt); 839 return NULL; 840 } 841 842 /* Make sure lock order is correct */ 843 ASSERT_LOCK_ORDER(objt); 844 845 /* Reference the handle entry */ 846 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 847 if (!pentry) 848 { 849 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj); 850 return NULL; 851 } 852 853 /* Get the pointer to the BASEOBJECT */ 854 pobj = pentry->einfo.pobj; 855 856 /* Check if we already own the lock */ 857 dwThreadId = PtrToUlong(PsGetCurrentThreadId()); 858 if (pobj->dwThreadId != dwThreadId) 859 { 860 /* Disable APCs and acquire the push lock */ 861 KeEnterCriticalRegion(); 862 ExAcquirePushLockExclusive(&pobj->pushlock); 863 864 /* Set us as lock owner */ 865 ASSERT(pobj->dwThreadId == 0); 866 pobj->dwThreadId = dwThreadId; 867 } 868 869 /* Increase lock count */ 870 pobj->cExclusiveLock++; 871 INCREASE_THREAD_LOCK_COUNT(hobj); 872 DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0); 873 874 /* Return the object */ 875 return pobj; 876 } 877 878 VOID 879 NTAPI 880 GDIOBJ_vUnlockObject(POBJ pobj) 881 { 882 ULONG cRefs, ulIndex; 883 ASSERT(pobj->cExclusiveLock > 0); 884 885 /* Decrease lock count */ 886 pobj->cExclusiveLock--; 887 DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr); 888 DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0); 889 890 /* Check if this was the last lock */ 891 if (pobj->cExclusiveLock == 0) 892 { 893 /* Reset lock owner */ 894 pobj->dwThreadId = 0; 895 896 /* Release the pushlock and reenable APCs */ 897 ExReleasePushLockExclusive(&pobj->pushlock); 898 KeLeaveCriticalRegion(); 899 } 900 901 /* Calculate the index */ 902 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 903 904 /* Decrement reference count */ 905 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); 906 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]); 907 ASSERT(cRefs & REF_MASK_VALID); 908 } 909 910 HGDIOBJ 911 NTAPI 912 GDIOBJ_hInsertObject( 913 POBJ pobj, 914 ULONG ulOwner) 915 { 916 PENTRY pentry; 917 UCHAR objt; 918 919 /* Must have no handle and only one reference */ 920 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr) == 0); 921 ASSERT(pobj->cExclusiveLock == 0); 922 ASSERT(pobj->ulShareCount == 1); 923 924 /* Get a free handle entry */ 925 pentry = ENTRY_pentPopFreeEntry(); 926 if (!pentry) 927 { 928 DPRINT1("GDIOBJ: Could not get a free entry.\n"); 929 return NULL; 930 } 931 932 /* Make the object exclusively locked */ 933 ExInitializePushLock(&pobj->pushlock); 934 KeEnterCriticalRegion(); 935 ExAcquirePushLockExclusive(&pobj->pushlock); 936 pobj->cExclusiveLock = 1; 937 pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId()); 938 INCREASE_THREAD_LOCK_COUNT(pobj->hHmgr); 939 940 /* Get object type from the hHmgr field */ 941 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff; 942 ASSERT(objt != GDIObjType_DEF_TYPE); 943 944 /* Check if current process is requested owner */ 945 if (ulOwner == GDI_OBJ_HMGR_POWNED) 946 { 947 /* Increment the process handle count */ 948 IncrementCurrentProcessGdiHandleCount(); 949 950 /* Use Process id */ 951 ulOwner = HandleToUlong(PsGetCurrentProcessId()); 952 } 953 954 /* Insert the object into the handle table */ 955 pobj->hHmgr = ENTRY_hInsertObject(pentry, pobj, objt, ulOwner); 956 957 /* Return the handle */ 958 DPRINT("GDIOBJ: Created handle: %p\n", pobj->hHmgr); 959 DBG_LOGEVENT(&pobj->slhLog, EVENT_CREATE_HANDLE, 0); 960 return pobj->hHmgr; 961 } 962 963 VOID 964 NTAPI 965 GDIOBJ_vSetObjectOwner( 966 POBJ pobj, 967 ULONG ulNewOwner) 968 { 969 PENTRY pentry; 970 ULONG ulOldOwner; 971 972 /* This is a ugly HACK, needed to fix IntGdiSetDCOwnerEx */ 973 if (GDI_HANDLE_IS_STOCKOBJ(pobj->hHmgr)) 974 { 975 DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulNewOwner); 976 return; 977 } 978 979 /* Get the handle entry */ 980 NT_ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr)); 981 pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)]; 982 983 /* Check if the new owner is the same as the old one */ 984 ulOldOwner = pentry->ObjectOwner.ulObj; 985 if (ulOldOwner == ulNewOwner) 986 { 987 /* Nothing to do */ 988 return; 989 } 990 991 /* Is the current process requested? */ 992 if (ulNewOwner == GDI_OBJ_HMGR_POWNED) 993 { 994 /* Use process id */ 995 ulNewOwner = HandleToUlong(PsGetCurrentProcessId()); 996 } 997 998 // HACK 999 if (ulNewOwner == GDI_OBJ_HMGR_NONE) 1000 ulNewOwner = GDI_OBJ_HMGR_PUBLIC; 1001 1002 /* Was the object process owned? */ 1003 if ((ulOldOwner != GDI_OBJ_HMGR_PUBLIC) && 1004 (ulOldOwner != GDI_OBJ_HMGR_NONE)) 1005 { 1006 /* Decrement the previous owners handle count */ 1007 DecrementGdiHandleCount(ulOldOwner); 1008 } 1009 1010 /* Is the new owner a process? */ 1011 if ((ulNewOwner != GDI_OBJ_HMGR_PUBLIC) && 1012 (ulNewOwner != GDI_OBJ_HMGR_NONE)) 1013 { 1014 /* Increment the new owners handle count */ 1015 IncrementGdiHandleCount(ulNewOwner); 1016 } 1017 else 1018 { 1019 /* Make sure we don't leak user mode memory */ 1020 NT_ASSERT(pentry->pUser == NULL); 1021 } 1022 1023 /* Set new owner */ 1024 pentry->ObjectOwner.ulObj = ulNewOwner; 1025 DBG_LOGEVENT(&pobj->slhLog, EVENT_SET_OWNER, 0); 1026 } 1027 1028 /* Locks 2 or 3 objects at a time */ 1029 BOOL 1030 NTAPI 1031 GDIOBJ_bLockMultipleObjects( 1032 IN ULONG ulCount, 1033 IN HGDIOBJ* ahObj, 1034 OUT PGDIOBJ* apObj, 1035 IN UCHAR objt) 1036 { 1037 UINT auiIndices[3] = {0, 1, 2}; 1038 UINT i, j, tmp; 1039 1040 ASSERT(ulCount <= 3); 1041 1042 /* Sort the handles */ 1043 for (i = 0; i < ulCount - 1; i++) 1044 { 1045 for (j = i + 1; j < ulCount; j++) 1046 { 1047 if ((ULONG_PTR)ahObj[auiIndices[i]] < 1048 (ULONG_PTR)ahObj[auiIndices[j]]) 1049 { 1050 tmp = auiIndices[i]; 1051 auiIndices[i] = auiIndices[j]; 1052 auiIndices[j] = tmp; 1053 } 1054 } 1055 } 1056 1057 /* Lock the objects in safe order */ 1058 for (i = 0; i < ulCount; i++) 1059 { 1060 /* Skip NULL handles */ 1061 if (ahObj[auiIndices[i]] == NULL) 1062 { 1063 apObj[auiIndices[i]] = NULL; 1064 continue; 1065 } 1066 1067 /* Lock the object */ 1068 apObj[auiIndices[i]] = GDIOBJ_LockObject(ahObj[auiIndices[i]], objt); 1069 1070 /* Check for failure */ 1071 if (apObj[auiIndices[i]] == NULL) 1072 { 1073 /* Cleanup */ 1074 while (i--) 1075 { 1076 if (apObj[auiIndices[i]]) 1077 GDIOBJ_vUnlockObject(apObj[auiIndices[i]]); 1078 } 1079 return FALSE; 1080 } 1081 } 1082 1083 return TRUE; 1084 } 1085 1086 PVOID 1087 NTAPI 1088 GDIOBJ_pvGetObjectAttr(POBJ pobj) 1089 { 1090 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 1091 return gpentHmgr[ulIndex].pUser; 1092 } 1093 1094 VOID 1095 NTAPI 1096 GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr) 1097 { 1098 ULONG ulIndex; 1099 1100 ASSERT(pobj->hHmgr); 1101 1102 /* Get the handle index */ 1103 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 1104 1105 /* Set pointer to the usermode attribute */ 1106 gpentHmgr[ulIndex].pUser = pvObjAttr; 1107 } 1108 1109 VOID 1110 NTAPI 1111 GDIOBJ_vDeleteObject(POBJ pobj) 1112 { 1113 ULONG ulIndex; 1114 1115 /* Set the object's delete flag */ 1116 InterlockedOr16((SHORT*)&pobj->BaseFlags, BASEFLAG_READY_TO_DIE); 1117 DBG_LOGEVENT(&pobj->slhLog, EVENT_DELETE, 0); 1118 1119 /* Get the handle index */ 1120 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 1121 if (ulIndex) 1122 { 1123 /* Reset the handle valid bit */ 1124 InterlockedAnd((LONG*)&gpaulRefCount[ulIndex], ~REF_MASK_VALID); 1125 1126 /* Check if the object is exclusively locked */ 1127 if (pobj->cExclusiveLock != 0) 1128 { 1129 /* Reset lock owner and lock count */ 1130 pobj->dwThreadId = 0; 1131 pobj->cExclusiveLock = 0; 1132 1133 /* Release the pushlock and reenable APCs */ 1134 ExReleasePushLockExclusive(&pobj->pushlock); 1135 KeLeaveCriticalRegion(); 1136 DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr); 1137 } 1138 } 1139 1140 /* Dereference the object (will take care of deletion) */ 1141 GDIOBJ_vDereferenceObject(pobj); 1142 } 1143 1144 BOOL 1145 NTAPI 1146 GreIsHandleValid(HGDIOBJ hobj) 1147 { 1148 PENTRY pentry; 1149 1150 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 1151 if (!pentry) return FALSE; 1152 GDIOBJ_vDereferenceObject(pentry->einfo.pobj); 1153 return TRUE; 1154 } 1155 1156 BOOL 1157 NTAPI 1158 GreDeleteObject(HGDIOBJ hobj) 1159 { 1160 PENTRY pentry; 1161 1162 /* Check for stock objects */ 1163 if (GDI_HANDLE_IS_STOCKOBJ(hobj)) 1164 { 1165 DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj); 1166 return FALSE; 1167 } 1168 1169 /* Reference the handle entry */ 1170 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 1171 if (!pentry) 1172 { 1173 DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj); 1174 return FALSE; 1175 } 1176 1177 /* Check for public owner */ 1178 if (pentry->ObjectOwner.ulObj == GDI_OBJ_HMGR_PUBLIC) 1179 { 1180 DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj); 1181 GDIOBJ_vDereferenceObject(pentry->einfo.pobj); 1182 return FALSE; 1183 } 1184 1185 /* Delete the object */ 1186 GDIOBJ_vDeleteObject(pentry->einfo.pobj); 1187 return TRUE; 1188 } 1189 1190 ULONG 1191 NTAPI 1192 GreGetObjectOwner(HGDIOBJ hobj) 1193 { 1194 ULONG ulIndex, ulOwner; 1195 1196 /* Get the handle index */ 1197 ulIndex = GDI_HANDLE_GET_INDEX(hobj); 1198 1199 /* Check if the handle is valid */ 1200 if (ulIndex >= GDI_HANDLE_COUNT || 1201 gpentHmgr[ulIndex].Objt == GDIObjType_DEF_TYPE || 1202 ((ULONG_PTR)hobj >> 16) != gpentHmgr[ulIndex].FullUnique) 1203 { 1204 DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj); 1205 return GDI_OBJ_HMGR_RESTRICTED; 1206 } 1207 1208 /* Get the object owner */ 1209 ulOwner = gpentHmgr[ulIndex].ObjectOwner.ulObj; 1210 1211 if (ulOwner == HandleToUlong(PsGetCurrentProcessId())) 1212 return GDI_OBJ_HMGR_POWNED; 1213 1214 if (ulOwner == GDI_OBJ_HMGR_PUBLIC) 1215 return GDI_OBJ_HMGR_PUBLIC; 1216 1217 return GDI_OBJ_HMGR_RESTRICTED; 1218 } 1219 1220 BOOL 1221 NTAPI 1222 GreSetObjectOwnerEx( 1223 HGDIOBJ hobj, 1224 ULONG ulOwner, 1225 ULONG Flags) 1226 { 1227 PENTRY pentry; 1228 1229 /* Check for stock objects */ 1230 if (GDI_HANDLE_IS_STOCKOBJ(hobj)) 1231 { 1232 DPRINT("GreSetObjectOwner: Got stock object %p\n", hobj); 1233 return FALSE; 1234 } 1235 1236 /* Reference the handle entry */ 1237 pentry = ENTRY_ReferenceEntryByHandle(hobj, Flags); 1238 if (!pentry) 1239 { 1240 DPRINT("GreSetObjectOwner: Invalid handle 0x%p.\n", hobj); 1241 return FALSE; 1242 } 1243 1244 /* Call internal function */ 1245 GDIOBJ_vSetObjectOwner(pentry->einfo.pobj, ulOwner); 1246 1247 /* Dereference the object */ 1248 GDIOBJ_vDereferenceObject(pentry->einfo.pobj); 1249 1250 return TRUE; 1251 } 1252 1253 BOOL 1254 NTAPI 1255 GreSetObjectOwner( 1256 HGDIOBJ hobj, 1257 ULONG ulOwner) 1258 { 1259 return GreSetObjectOwnerEx(hobj, ulOwner, 0); 1260 } 1261 1262 INT 1263 NTAPI 1264 GreGetObject( 1265 IN HGDIOBJ hobj, 1266 IN INT cbCount, 1267 OUT PVOID pvBuffer) 1268 { 1269 PVOID pvObj; 1270 UCHAR objt; 1271 INT iResult = 0; 1272 1273 /* Verify object type */ 1274 objt = ((ULONG_PTR)hobj >> 16) & 0x1f; 1275 if (objt != GDIObjType_BRUSH_TYPE && 1276 objt != GDIObjType_SURF_TYPE && 1277 objt != GDIObjType_LFONT_TYPE && 1278 objt != GDIObjType_PAL_TYPE) 1279 { 1280 DPRINT1("GreGetObject: Invalid object type\n"); 1281 return 0; 1282 } 1283 1284 pvObj = GDIOBJ_ReferenceObjectByHandle(hobj, objt); 1285 if (!pvObj) 1286 { 1287 DPRINT("GreGetObject: Could not lock object\n"); 1288 return 0; 1289 } 1290 1291 switch (GDI_HANDLE_GET_TYPE(hobj)) 1292 { 1293 case GDILoObjType_LO_PEN_TYPE: 1294 case GDILoObjType_LO_EXTPEN_TYPE: 1295 iResult = PEN_GetObject(pvObj, cbCount, pvBuffer); 1296 break; 1297 1298 case GDILoObjType_LO_BRUSH_TYPE: 1299 iResult = BRUSH_GetObject(pvObj, cbCount, pvBuffer); 1300 break; 1301 1302 case GDILoObjType_LO_BITMAP_TYPE: 1303 iResult = BITMAP_GetObject(pvObj, cbCount, pvBuffer); 1304 break; 1305 1306 case GDILoObjType_LO_FONT_TYPE: 1307 iResult = FontGetObject(pvObj, cbCount, pvBuffer); 1308 break; 1309 1310 case GDILoObjType_LO_PALETTE_TYPE: 1311 iResult = PALETTE_GetObject(pvObj, cbCount, pvBuffer); 1312 break; 1313 1314 default: 1315 DPRINT1("GDI object type of 0x%p not implemented\n", hobj); 1316 break; 1317 } 1318 1319 GDIOBJ_vDereferenceObject(pvObj); 1320 return iResult; 1321 } 1322 1323 W32KAPI 1324 INT 1325 APIENTRY 1326 NtGdiExtGetObjectW( 1327 IN HANDLE hobj, 1328 IN INT cjBufferSize, 1329 OUT LPVOID lpBuffer) 1330 { 1331 UINT iResult, cjMaxSize; 1332 union 1333 { 1334 BITMAP bitmap; 1335 DIBSECTION dibsection; 1336 LOGPEN logpen; 1337 LOGBRUSH logbrush; 1338 LOGFONTW logfontw; 1339 EXTLOGFONTW extlogfontw; 1340 ENUMLOGFONTEXDVW enumlogfontexdvw; 1341 } object; 1342 1343 /* Normalize to the largest supported object size */ 1344 cjMaxSize = min((UINT)cjBufferSize, sizeof(object)); 1345 1346 /* Now do the actual call */ 1347 iResult = GreGetObject(hobj, cjMaxSize, lpBuffer ? &object : NULL); 1348 1349 /* Check if we have a buffer and data */ 1350 if ((lpBuffer != NULL) && (iResult != 0)) 1351 { 1352 /* Enter SEH for buffer transfer */ 1353 _SEH2_TRY 1354 { 1355 /* Probe the buffer and copy it */ 1356 cjMaxSize = min(cjMaxSize, iResult); 1357 ProbeForWrite(lpBuffer, cjMaxSize, sizeof(WORD)); 1358 RtlCopyMemory(lpBuffer, &object, cjMaxSize); 1359 } 1360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1361 { 1362 /* Clear the return value. 1363 * Do *NOT* set last error here! */ 1364 iResult = 0; 1365 } 1366 _SEH2_END; 1367 } 1368 1369 /* Return the count */ 1370 return iResult; 1371 } 1372 1373 W32KAPI 1374 HANDLE 1375 APIENTRY 1376 NtGdiCreateClientObj( 1377 IN ULONG ulType) 1378 { 1379 POBJ pObject; 1380 HANDLE handle; 1381 1382 /* Check if ulType is valid */ 1383 if ((ulType != GDILoObjType_LO_METAFILE16_TYPE) && 1384 (ulType != GDILoObjType_LO_METAFILE_TYPE) && 1385 (ulType != GDILoObjType_LO_METADC16_TYPE)) 1386 { 1387 DPRINT1("NtGdiCreateClientObj: Invalid object type 0x%lx.\n", ulType); 1388 return NULL; 1389 } 1390 1391 /* Allocate a new object */ 1392 pObject = GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE, 1393 sizeof(CLIENTOBJ), 1394 BASEFLAG_LOOKASIDE); 1395 if (!pObject) 1396 { 1397 DPRINT1("NtGdiCreateClientObj: Could not allocate a clientobj.\n"); 1398 return NULL; 1399 } 1400 1401 /* Set the real object type */ 1402 pObject->hHmgr = UlongToHandle(ulType | GDILoObjType_LO_CLIENTOBJ_TYPE); 1403 1404 /* Create a handle */ 1405 handle = GDIOBJ_hInsertObject(pObject, GDI_OBJ_HMGR_POWNED); 1406 if (!handle) 1407 { 1408 DPRINT1("NtGdiCreateClientObj: Could not create a handle.\n"); 1409 GDIOBJ_vFreeObject(pObject); 1410 return NULL; 1411 } 1412 1413 /* Unlock it */ 1414 GDIOBJ_vUnlockObject(pObject); 1415 1416 return handle; 1417 } 1418 1419 W32KAPI 1420 BOOL 1421 APIENTRY 1422 NtGdiDeleteClientObj( 1423 IN HANDLE hobj) 1424 { 1425 /* We first need to get the real type from the handle */ 1426 ULONG ulType = GDI_HANDLE_GET_TYPE(hobj); 1427 1428 /* Check if it's really a CLIENTOBJ */ 1429 if ((ulType & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE) 1430 { 1431 /* FIXME: SetLastError? */ 1432 return FALSE; 1433 } 1434 1435 return GreDeleteObject(hobj); 1436 } 1437 1438 1439 1440 PGDI_HANDLE_TABLE GdiHandleTable = NULL; 1441 1442 PGDIOBJ NTAPI 1443 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType) 1444 { 1445 if (ExpectedType == GDI_OBJECT_TYPE_DONTCARE) 1446 ExpectedType = GDI_HANDLE_GET_TYPE(hObj); 1447 return GDIOBJ_ReferenceObjectByHandle(hObj, (ExpectedType >> 16) & 0x1f); 1448 } 1449 1450 // This function is not safe to use with concurrent deleting attempts 1451 // That shouldn't be a problem, since we don't have any processes yet, 1452 // that could delete the handle 1453 BOOL 1454 NTAPI 1455 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj) 1456 { 1457 PENTRY pentry; 1458 POBJ pobj; 1459 1460 /* Reference the handle entry */ 1461 pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0); 1462 if (!pentry) 1463 { 1464 DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj); 1465 return FALSE; 1466 } 1467 1468 /* Update the entry */ 1469 pentry->FullUnique |= GDI_ENTRY_STOCK_MASK; 1470 pentry->ObjectOwner.ulObj = 0; 1471 1472 /* Get the pointer to the BASEOBJECT */ 1473 pobj = pentry->einfo.pobj; 1474 1475 /* Calculate the new handle */ 1476 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr | GDI_HANDLE_STOCK_MASK); 1477 1478 /* Return the new handle */ 1479 *phObj = pobj->hHmgr; 1480 1481 /* Dereference the handle */ 1482 GDIOBJ_vDereferenceObject(pobj); 1483 1484 return TRUE; 1485 } 1486 1487 BOOL 1488 NTAPI 1489 GDIOBJ_ConvertFromStockObj(HGDIOBJ *phObj) 1490 { 1491 PENTRY pentry; 1492 POBJ pobj; 1493 1494 /* Reference the handle entry */ 1495 pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0); 1496 if (!pentry) 1497 { 1498 DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj); 1499 return FALSE; 1500 } 1501 1502 /* Update the entry */ 1503 pentry->FullUnique &= ~GDI_ENTRY_STOCK_MASK; 1504 pentry->ObjectOwner.ulObj = PtrToUlong(PsGetCurrentProcessId()); 1505 1506 /* Get the pointer to the BASEOBJECT */ 1507 pobj = pentry->einfo.pobj; 1508 1509 /* Calculate the new handle */ 1510 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr & ~GDI_HANDLE_STOCK_MASK); 1511 1512 /* Return the new handle */ 1513 *phObj = pobj->hHmgr; 1514 1515 /* Dereference the handle */ 1516 GDIOBJ_vDereferenceObject(pobj); 1517 1518 return TRUE; 1519 } 1520 1521 POBJ NTAPI 1522 GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize) 1523 { 1524 POBJ pobj; 1525 FLONG fl = 0; 1526 UCHAR objt = (ObjectType >> 16) & 0xFF; 1527 1528 if ((objt == GDIObjType_DC_TYPE && cjSize == sizeof(DC)) || 1529 (objt == GDIObjType_PAL_TYPE && cjSize == sizeof(PALETTE)) || 1530 (objt == GDIObjType_RGN_TYPE && cjSize == sizeof(REGION)) || 1531 (objt == GDIObjType_SURF_TYPE && cjSize == sizeof(SURFACE)) || 1532 (objt == GDIObjType_PATH_TYPE && cjSize == sizeof(PATH))) 1533 { 1534 fl |= BASEFLAG_LOOKASIDE; 1535 } 1536 1537 pobj = GDIOBJ_AllocateObject(objt, cjSize, fl); 1538 if (!pobj) 1539 { 1540 return NULL; 1541 } 1542 1543 if (!GDIOBJ_hInsertObject(pobj, GDI_OBJ_HMGR_POWNED)) 1544 { 1545 GDIOBJ_vFreeObject(pobj); 1546 return NULL; 1547 } 1548 return pobj; 1549 } 1550 1551 PVOID NTAPI 1552 GDI_MapHandleTable(PEPROCESS pProcess) 1553 { 1554 PVOID pvMappedView = NULL; 1555 NTSTATUS Status; 1556 LARGE_INTEGER liOffset; 1557 SIZE_T cjViewSize = sizeof(GDI_HANDLE_TABLE); 1558 1559 liOffset.QuadPart = 0; 1560 1561 ASSERT(gpvGdiHdlTblSection != NULL); 1562 ASSERT(pProcess != NULL); 1563 1564 Status = MmMapViewOfSection(gpvGdiHdlTblSection, 1565 pProcess, 1566 &pvMappedView, 1567 0, 1568 0, 1569 &liOffset, 1570 &cjViewSize, 1571 ViewUnmap, 1572 SEC_NO_CHANGE, 1573 PAGE_READONLY); 1574 1575 if (!NT_SUCCESS(Status)) 1576 return NULL; 1577 1578 return pvMappedView; 1579 } 1580 1581 BOOL NTAPI 1582 GDI_CleanupForProcess(struct _EPROCESS *Process) 1583 { 1584 PENTRY pentry; 1585 ULONG ulIndex; 1586 DWORD dwProcessId; 1587 PPROCESSINFO ppi; 1588 1589 DPRINT("CleanupForProcess prochandle %p Pid %p\n", 1590 Process, Process->UniqueProcessId); 1591 1592 ASSERT(Process == PsGetCurrentProcess()); 1593 1594 /* Get the current process Id */ 1595 dwProcessId = PtrToUlong(PsGetCurrentProcessId()); 1596 1597 /* Loop all handles in the handle table */ 1598 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++) 1599 { 1600 pentry = &gpentHmgr[ulIndex]; 1601 1602 /* Check if the object is owned by the process */ 1603 if (pentry->ObjectOwner.ulObj == dwProcessId) 1604 { 1605 ASSERT(pentry->einfo.pobj->cExclusiveLock == 0); 1606 1607 /* Reference the object and delete it */ 1608 InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]); 1609 GDIOBJ_vDeleteObject(pentry->einfo.pobj); 1610 } 1611 } 1612 1613 #if DBG 1614 DbgGdiHTIntegrityCheck(); 1615 #endif 1616 1617 ppi = PsGetCurrentProcessWin32Process(); 1618 DPRINT("Completed cleanup for process %p\n", Process->UniqueProcessId); 1619 if (ppi->GDIHandleCount != 0) 1620 { 1621 DPRINT1("Leaking %d handles!\n", ppi->GDIHandleCount); 1622 ASSERT(FALSE); 1623 } 1624 1625 /* Loop all handles in the handle table */ 1626 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++) 1627 { 1628 pentry = &gpentHmgr[ulIndex]; 1629 1630 /* Check if the object is owned by the process */ 1631 if (pentry->ObjectOwner.ulObj == dwProcessId) 1632 { 1633 DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n", 1634 ulIndex, pentry->Objt, gpaulRefCount[ulIndex]); 1635 DBG_DUMP_EVENT_LIST(&pentry->einfo.pobj->slhLog); 1636 //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog); 1637 ASSERT(FALSE); 1638 } 1639 } 1640 1641 return TRUE; 1642 } 1643 1644 /// HACK! 1645 PGDI_POOL 1646 GetBrushAttrPool(VOID) 1647 { 1648 PPROCESSINFO ppi; 1649 1650 ppi = PsGetCurrentProcessWin32Process(); 1651 NT_ASSERT(ppi != NULL); 1652 1653 return ppi->pPoolBrushAttr; 1654 } 1655 1656 /* EOF */ 1657