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