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 INIT_FUNCTION 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 && pentry->einfo.pobj->hHmgr == hobj); 530 531 return pentry; 532 } 533 534 static 535 HGDIOBJ 536 ENTRY_hInsertObject(PENTRY pentry, POBJ pobj, UCHAR objt, ULONG ulOwner) 537 { 538 ULONG ulIndex; 539 540 /* Calculate the handle index */ 541 ulIndex = pentry - gpentHmgr; 542 543 /* Update the fields in the ENTRY */ 544 pentry->einfo.pobj = pobj; 545 pentry->Objt = objt & 0x1f; 546 pentry->FullUnique = (pentry->FullUnique & 0xff00) | objt; 547 pentry->ObjectOwner.ulObj = ulOwner; 548 549 /* Make the handle valid with 1 reference */ 550 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_INUSE) == 0); 551 InterlockedOr((LONG*)&gpaulRefCount[ulIndex], REF_MASK_VALID | 1); 552 553 /* Return the handle */ 554 return (HGDIOBJ)(((ULONG_PTR)pentry->FullUnique << 16) | ulIndex); 555 } 556 557 POBJ 558 NTAPI 559 GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl) 560 { 561 POBJ pobj; 562 563 if (fl & BASEFLAG_LOOKASIDE) 564 { 565 /* Allocate the object from a lookaside list */ 566 pobj = ExAllocateFromPagedLookasideList(&gpaLookasideList[objt & 0x1f]); 567 } 568 else 569 { 570 /* Allocate the object from paged pool */ 571 pobj = ExAllocatePoolWithTag(PagedPool, cjSize, GDIOBJ_POOL_TAG(objt)); 572 } 573 574 if (!pobj) return NULL; 575 576 /* Initialize the object */ 577 RtlZeroMemory(pobj, cjSize); 578 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)objt << 16); 579 pobj->cExclusiveLock = 0; 580 pobj->ulShareCount = 1; 581 pobj->BaseFlags = fl & 0xffff; 582 DBG_INITLOG(&pobj->slhLog); 583 DBG_LOGEVENT(&pobj->slhLog, EVENT_ALLOCATE, 0); 584 #if DBG_ENABLE_GDIOBJ_BACKTRACES 585 DbgCaptureStackBackTace(pobj->apvBackTrace, 1, GDI_OBJECT_STACK_LEVELS); 586 #endif /* GDI_DEBUG */ 587 588 return pobj; 589 } 590 591 VOID 592 NTAPI 593 GDIOBJ_vFreeObject(POBJ pobj) 594 { 595 UCHAR objt; 596 597 DBG_CLEANUP_EVENT_LIST(&pobj->slhLog); 598 599 /* Get the object type */ 600 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0x1f; 601 602 /* Check if we have a delete procedure (for C++ based objects) */ 603 if (apfnDelete[objt] != NULL) 604 { 605 /* Invoke the delete procedure */ 606 apfnDelete[objt](pobj); 607 } 608 else 609 { 610 /* Call the cleanup procedure */ 611 NT_ASSERT(apfnCleanup[objt]); 612 apfnCleanup[objt](pobj); 613 614 /* Check if the object is allocated from a lookaside list */ 615 if (pobj->BaseFlags & BASEFLAG_LOOKASIDE) 616 { 617 ExFreeToPagedLookasideList(&gpaLookasideList[objt], pobj); 618 } 619 else 620 { 621 ExFreePoolWithTag(pobj, GDIOBJ_POOL_TAG(objt)); 622 } 623 } 624 } 625 626 VOID 627 NTAPI 628 GDIOBJ_vDereferenceObject(POBJ pobj) 629 { 630 ULONG cRefs, ulIndex; 631 632 /* Calculate the index */ 633 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 634 635 /* Check if the object has a handle */ 636 if (ulIndex) 637 { 638 /* Decrement reference count */ 639 if ((gpaulRefCount[ulIndex] & REF_MASK_COUNT) == 0) 640 { 641 DBG_DUMP_EVENT_LIST(&pobj->slhLog); 642 } 643 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); 644 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]); 645 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs); 646 647 /* Check if we reached 0 and handle bit is not set */ 648 if ((cRefs & REF_MASK_INUSE) == 0) 649 { 650 /* Make sure it's ok to delete the object */ 651 ASSERT(pobj->BaseFlags & BASEFLAG_READY_TO_DIE); 652 653 /* Check if the handle was process owned */ 654 if (gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_PUBLIC && 655 gpentHmgr[ulIndex].ObjectOwner.ulObj != GDI_OBJ_HMGR_NONE) 656 { 657 /* Decrement the process handle count */ 658 ASSERT(gpentHmgr[ulIndex].ObjectOwner.ulObj == 659 HandleToUlong(PsGetCurrentProcessId())); 660 DecrementCurrentProcessGdiHandleCount(); 661 } 662 663 /* Push entry to the free list */ 664 ENTRY_vPushFreeEntry(&gpentHmgr[ulIndex]); 665 666 /* Free the object */ 667 GDIOBJ_vFreeObject(pobj); 668 } 669 } 670 else 671 { 672 /* Decrement the objects reference count */ 673 ASSERT(pobj->ulShareCount > 0); 674 cRefs = InterlockedDecrement((LONG*)&pobj->ulShareCount); 675 DBG_LOGEVENT(&pobj->slhLog, EVENT_DEREFERENCE, cRefs); 676 677 /* Check if we reached 0 */ 678 if (cRefs == 0) 679 { 680 /* Free the object */ 681 GDIOBJ_vFreeObject(pobj); 682 } 683 } 684 } 685 686 POBJ 687 NTAPI 688 GDIOBJ_ReferenceObjectByHandle( 689 HGDIOBJ hobj, 690 UCHAR objt) 691 { 692 PENTRY pentry; 693 POBJ pobj; 694 695 /* Check if the handle type matches */ 696 ASSERT_SHARED_OBJECT_TYPE(objt); 697 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt) 698 { 699 DPRINT("GDIOBJ: Wrong type. handle=%p, type=%x\n", hobj, objt); 700 return NULL; 701 } 702 703 /* Reference the handle entry */ 704 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 705 if (!pentry) 706 { 707 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj); 708 return NULL; 709 } 710 711 /* Get the pointer to the BASEOBJECT */ 712 pobj = pentry->einfo.pobj; 713 714 /* Check if the object is exclusively locked */ 715 if (pobj->cExclusiveLock != 0) 716 { 717 DPRINT1("GDIOBJ: Cannot reference object %p with exclusive lock.\n", hobj); 718 GDIOBJ_vDereferenceObject(pobj); 719 DBG_DUMP_EVENT_LIST(&pobj->slhLog); 720 return NULL; 721 } 722 723 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, gpaulRefCount[pentry - gpentHmgr]); 724 725 /* All is well, return the object */ 726 return pobj; 727 } 728 729 VOID 730 NTAPI 731 GDIOBJ_vReferenceObjectByPointer(POBJ pobj) 732 { 733 ULONG cRefs; 734 735 /* Check if the object has a handle */ 736 if (GDI_HANDLE_GET_INDEX(pobj->hHmgr)) 737 { 738 /* Increase the handle's reference count */ 739 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 740 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); 741 cRefs = InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]); 742 } 743 else 744 { 745 /* Increase the object's reference count */ 746 cRefs = InterlockedIncrement((LONG*)&pobj->ulShareCount); 747 } 748 749 DBG_LOGEVENT(&pobj->slhLog, EVENT_REFERENCE, cRefs); 750 } 751 752 PGDIOBJ 753 NTAPI 754 GDIOBJ_TryLockObject( 755 HGDIOBJ hobj, 756 UCHAR objt) 757 { 758 PENTRY pentry; 759 POBJ pobj; 760 DWORD dwThreadId; 761 762 /* Check if the handle type matches */ 763 ASSERT_TRYLOCK_OBJECT_TYPE(objt); 764 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt) 765 { 766 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt); 767 return NULL; 768 } 769 770 /* Make sure lock order is correct */ 771 ASSERT_LOCK_ORDER(objt); 772 773 /* Reference the handle entry */ 774 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 775 if (!pentry) 776 { 777 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj); 778 return NULL; 779 } 780 781 /* Get the pointer to the BASEOBJECT */ 782 pobj = pentry->einfo.pobj; 783 784 /* Check if we already own the lock */ 785 dwThreadId = PtrToUlong(PsGetCurrentThreadId()); 786 if (pobj->dwThreadId != dwThreadId) 787 { 788 /* Disable APCs and try acquiring the push lock */ 789 KeEnterCriticalRegion(); 790 if(!ExTryAcquirePushLockExclusive(&pobj->pushlock)) 791 { 792 ULONG cRefs, ulIndex; 793 /* Already owned. Clean up and leave. */ 794 KeLeaveCriticalRegion(); 795 796 /* Calculate the index */ 797 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 798 799 /* Decrement reference count */ 800 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); 801 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]); 802 ASSERT(cRefs & REF_MASK_VALID); 803 804 return NULL; 805 } 806 807 /* Set us as lock owner */ 808 ASSERT(pobj->dwThreadId == 0); 809 pobj->dwThreadId = dwThreadId; 810 } 811 812 /* Increase lock count */ 813 pobj->cExclusiveLock++; 814 INCREASE_THREAD_LOCK_COUNT(hobj); 815 DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0); 816 817 /* Return the object */ 818 return pobj; 819 } 820 821 PGDIOBJ 822 NTAPI 823 GDIOBJ_LockObject( 824 HGDIOBJ hobj, 825 UCHAR objt) 826 { 827 PENTRY pentry; 828 POBJ pobj; 829 DWORD dwThreadId; 830 831 /* Check if the handle type matches */ 832 ASSERT_EXCLUSIVE_OBJECT_TYPE(objt); 833 if ((((ULONG_PTR)hobj >> 16) & 0x1f) != objt) 834 { 835 DPRINT("Wrong object type: hobj=0x%p, objt=0x%x\n", hobj, objt); 836 return NULL; 837 } 838 839 /* Make sure lock order is correct */ 840 ASSERT_LOCK_ORDER(objt); 841 842 /* Reference the handle entry */ 843 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 844 if (!pentry) 845 { 846 DPRINT("GDIOBJ: Requested handle 0x%p is not valid.\n", hobj); 847 return NULL; 848 } 849 850 /* Get the pointer to the BASEOBJECT */ 851 pobj = pentry->einfo.pobj; 852 853 /* Check if we already own the lock */ 854 dwThreadId = PtrToUlong(PsGetCurrentThreadId()); 855 if (pobj->dwThreadId != dwThreadId) 856 { 857 /* Disable APCs and acquire the push lock */ 858 KeEnterCriticalRegion(); 859 ExAcquirePushLockExclusive(&pobj->pushlock); 860 861 /* Set us as lock owner */ 862 ASSERT(pobj->dwThreadId == 0); 863 pobj->dwThreadId = dwThreadId; 864 } 865 866 /* Increase lock count */ 867 pobj->cExclusiveLock++; 868 INCREASE_THREAD_LOCK_COUNT(hobj); 869 DBG_LOGEVENT(&pobj->slhLog, EVENT_LOCK, 0); 870 871 /* Return the object */ 872 return pobj; 873 } 874 875 VOID 876 NTAPI 877 GDIOBJ_vUnlockObject(POBJ pobj) 878 { 879 ULONG cRefs, ulIndex; 880 ASSERT(pobj->cExclusiveLock > 0); 881 882 /* Decrease lock count */ 883 pobj->cExclusiveLock--; 884 DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr); 885 DBG_LOGEVENT(&pobj->slhLog, EVENT_UNLOCK, 0); 886 887 /* Check if this was the last lock */ 888 if (pobj->cExclusiveLock == 0) 889 { 890 /* Reset lock owner */ 891 pobj->dwThreadId = 0; 892 893 /* Release the pushlock and reenable APCs */ 894 ExReleasePushLockExclusive(&pobj->pushlock); 895 KeLeaveCriticalRegion(); 896 } 897 898 /* Calculate the index */ 899 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 900 901 /* Decrement reference count */ 902 ASSERT((gpaulRefCount[ulIndex] & REF_MASK_COUNT) > 0); 903 cRefs = InterlockedDecrement((LONG*)&gpaulRefCount[ulIndex]); 904 ASSERT(cRefs & REF_MASK_VALID); 905 } 906 907 HGDIOBJ 908 NTAPI 909 GDIOBJ_hInsertObject( 910 POBJ pobj, 911 ULONG ulOwner) 912 { 913 PENTRY pentry; 914 UCHAR objt; 915 916 /* Must have no handle and only one reference */ 917 ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr) == 0); 918 ASSERT(pobj->cExclusiveLock == 0); 919 ASSERT(pobj->ulShareCount == 1); 920 921 /* Get a free handle entry */ 922 pentry = ENTRY_pentPopFreeEntry(); 923 if (!pentry) 924 { 925 DPRINT1("GDIOBJ: Could not get a free entry.\n"); 926 return NULL; 927 } 928 929 /* Make the object exclusively locked */ 930 ExInitializePushLock(&pobj->pushlock); 931 KeEnterCriticalRegion(); 932 ExAcquirePushLockExclusive(&pobj->pushlock); 933 pobj->cExclusiveLock = 1; 934 pobj->dwThreadId = PtrToUlong(PsGetCurrentThreadId()); 935 INCREASE_THREAD_LOCK_COUNT(pobj->hHmgr); 936 937 /* Get object type from the hHmgr field */ 938 objt = ((ULONG_PTR)pobj->hHmgr >> 16) & 0xff; 939 ASSERT(objt != GDIObjType_DEF_TYPE); 940 941 /* Check if current process is requested owner */ 942 if (ulOwner == GDI_OBJ_HMGR_POWNED) 943 { 944 /* Increment the process handle count */ 945 IncrementCurrentProcessGdiHandleCount(); 946 947 /* Use Process id */ 948 ulOwner = HandleToUlong(PsGetCurrentProcessId()); 949 } 950 951 /* Insert the object into the handle table */ 952 pobj->hHmgr = ENTRY_hInsertObject(pentry, pobj, objt, ulOwner); 953 954 /* Return the handle */ 955 DPRINT("GDIOBJ: Created handle: %p\n", pobj->hHmgr); 956 DBG_LOGEVENT(&pobj->slhLog, EVENT_CREATE_HANDLE, 0); 957 return pobj->hHmgr; 958 } 959 960 VOID 961 NTAPI 962 GDIOBJ_vSetObjectOwner( 963 POBJ pobj, 964 ULONG ulNewOwner) 965 { 966 PENTRY pentry; 967 ULONG ulOldOwner; 968 969 /* This is a ugly HACK, needed to fix IntGdiSetDCOwnerEx */ 970 if (GDI_HANDLE_IS_STOCKOBJ(pobj->hHmgr)) 971 { 972 DPRINT("Trying to set ownership of stock object %p to %lx\n", pobj->hHmgr, ulNewOwner); 973 return; 974 } 975 976 /* Get the handle entry */ 977 NT_ASSERT(GDI_HANDLE_GET_INDEX(pobj->hHmgr)); 978 pentry = &gpentHmgr[GDI_HANDLE_GET_INDEX(pobj->hHmgr)]; 979 980 /* Check if the new owner is the same as the old one */ 981 ulOldOwner = pentry->ObjectOwner.ulObj; 982 if (ulOldOwner == ulNewOwner) 983 { 984 /* Nothing to do */ 985 return; 986 } 987 988 /* Is the current process requested? */ 989 if (ulNewOwner == GDI_OBJ_HMGR_POWNED) 990 { 991 /* Use process id */ 992 ulNewOwner = HandleToUlong(PsGetCurrentProcessId()); 993 } 994 995 // HACK 996 if (ulNewOwner == GDI_OBJ_HMGR_NONE) 997 ulNewOwner = GDI_OBJ_HMGR_PUBLIC; 998 999 /* Was the object process owned? */ 1000 if ((ulOldOwner != GDI_OBJ_HMGR_PUBLIC) && 1001 (ulOldOwner != GDI_OBJ_HMGR_NONE)) 1002 { 1003 /* Decrement the previous owners handle count */ 1004 DecrementGdiHandleCount(ulOldOwner); 1005 } 1006 1007 /* Is the new owner a process? */ 1008 if ((ulNewOwner != GDI_OBJ_HMGR_PUBLIC) && 1009 (ulNewOwner != GDI_OBJ_HMGR_NONE)) 1010 { 1011 /* Increment the new owners handle count */ 1012 IncrementGdiHandleCount(ulNewOwner); 1013 } 1014 else 1015 { 1016 /* Make sure we don't leak user mode memory */ 1017 NT_ASSERT(pentry->pUser == NULL); 1018 } 1019 1020 /* Set new owner */ 1021 pentry->ObjectOwner.ulObj = ulNewOwner; 1022 DBG_LOGEVENT(&pobj->slhLog, EVENT_SET_OWNER, 0); 1023 } 1024 1025 /* Locks 2 or 3 objects at a time */ 1026 BOOL 1027 NTAPI 1028 GDIOBJ_bLockMultipleObjects( 1029 IN ULONG ulCount, 1030 IN HGDIOBJ* ahObj, 1031 OUT PGDIOBJ* apObj, 1032 IN UCHAR objt) 1033 { 1034 UINT auiIndices[3] = {0, 1, 2}; 1035 UINT i, j, tmp; 1036 1037 ASSERT(ulCount <= 3); 1038 1039 /* Sort the handles */ 1040 for (i = 0; i < ulCount - 1; i++) 1041 { 1042 for (j = i + 1; j < ulCount; j++) 1043 { 1044 if ((ULONG_PTR)ahObj[auiIndices[i]] < 1045 (ULONG_PTR)ahObj[auiIndices[j]]) 1046 { 1047 tmp = auiIndices[i]; 1048 auiIndices[i] = auiIndices[j]; 1049 auiIndices[j] = tmp; 1050 } 1051 } 1052 } 1053 1054 /* Lock the objects in safe order */ 1055 for (i = 0; i < ulCount; i++) 1056 { 1057 /* Skip NULL handles */ 1058 if (ahObj[auiIndices[i]] == NULL) 1059 { 1060 apObj[auiIndices[i]] = NULL; 1061 continue; 1062 } 1063 1064 /* Lock the object */ 1065 apObj[auiIndices[i]] = GDIOBJ_LockObject(ahObj[auiIndices[i]], objt); 1066 1067 /* Check for failure */ 1068 if (apObj[auiIndices[i]] == NULL) 1069 { 1070 /* Cleanup */ 1071 while (i--) 1072 { 1073 if (apObj[auiIndices[i]]) 1074 GDIOBJ_vUnlockObject(apObj[auiIndices[i]]); 1075 } 1076 return FALSE; 1077 } 1078 } 1079 1080 return TRUE; 1081 } 1082 1083 PVOID 1084 NTAPI 1085 GDIOBJ_pvGetObjectAttr(POBJ pobj) 1086 { 1087 ULONG ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 1088 return gpentHmgr[ulIndex].pUser; 1089 } 1090 1091 VOID 1092 NTAPI 1093 GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr) 1094 { 1095 ULONG ulIndex; 1096 1097 ASSERT(pobj->hHmgr); 1098 1099 /* Get the handle index */ 1100 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 1101 1102 /* Set pointer to the usermode attribute */ 1103 gpentHmgr[ulIndex].pUser = pvObjAttr; 1104 } 1105 1106 VOID 1107 NTAPI 1108 GDIOBJ_vDeleteObject(POBJ pobj) 1109 { 1110 ULONG ulIndex; 1111 1112 /* Set the object's delete flag */ 1113 InterlockedOr16((SHORT*)&pobj->BaseFlags, BASEFLAG_READY_TO_DIE); 1114 DBG_LOGEVENT(&pobj->slhLog, EVENT_DELETE, 0); 1115 1116 /* Get the handle index */ 1117 ulIndex = GDI_HANDLE_GET_INDEX(pobj->hHmgr); 1118 if (ulIndex) 1119 { 1120 /* Reset the handle valid bit */ 1121 InterlockedAnd((LONG*)&gpaulRefCount[ulIndex], ~REF_MASK_VALID); 1122 1123 /* Check if the object is exclusively locked */ 1124 if (pobj->cExclusiveLock != 0) 1125 { 1126 /* Reset lock owner and lock count */ 1127 pobj->dwThreadId = 0; 1128 pobj->cExclusiveLock = 0; 1129 1130 /* Release the pushlock and reenable APCs */ 1131 ExReleasePushLockExclusive(&pobj->pushlock); 1132 KeLeaveCriticalRegion(); 1133 DECREASE_THREAD_LOCK_COUNT(pobj->hHmgr); 1134 } 1135 } 1136 1137 /* Dereference the object (will take care of deletion) */ 1138 GDIOBJ_vDereferenceObject(pobj); 1139 } 1140 1141 BOOL 1142 NTAPI 1143 GreIsHandleValid(HGDIOBJ hobj) 1144 { 1145 PENTRY pentry; 1146 1147 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 1148 if (!pentry) return FALSE; 1149 GDIOBJ_vDereferenceObject(pentry->einfo.pobj); 1150 return TRUE; 1151 } 1152 1153 BOOL 1154 NTAPI 1155 GreDeleteObject(HGDIOBJ hobj) 1156 { 1157 PENTRY pentry; 1158 1159 /* Check for stock objects */ 1160 if (GDI_HANDLE_IS_STOCKOBJ(hobj)) 1161 { 1162 DPRINT1("GreDeleteObject: Cannot delete stock object %p.\n", hobj); 1163 return FALSE; 1164 } 1165 1166 /* Reference the handle entry */ 1167 pentry = ENTRY_ReferenceEntryByHandle(hobj, 0); 1168 if (!pentry) 1169 { 1170 DPRINT1("GreDeleteObject: Trying to delete invalid object %p\n", hobj); 1171 return FALSE; 1172 } 1173 1174 /* Check for public owner */ 1175 if (pentry->ObjectOwner.ulObj == GDI_OBJ_HMGR_PUBLIC) 1176 { 1177 DPRINT1("GreDeleteObject: Trying to delete global object %p\n", hobj); 1178 GDIOBJ_vDereferenceObject(pentry->einfo.pobj); 1179 return FALSE; 1180 } 1181 1182 /* Delete the object */ 1183 GDIOBJ_vDeleteObject(pentry->einfo.pobj); 1184 return TRUE; 1185 } 1186 1187 ULONG 1188 NTAPI 1189 GreGetObjectOwner(HGDIOBJ hobj) 1190 { 1191 ULONG ulIndex, ulOwner; 1192 1193 /* Get the handle index */ 1194 ulIndex = GDI_HANDLE_GET_INDEX(hobj); 1195 1196 /* Check if the handle is valid */ 1197 if (ulIndex >= GDI_HANDLE_COUNT || 1198 gpentHmgr[ulIndex].Objt == GDIObjType_DEF_TYPE || 1199 ((ULONG_PTR)hobj >> 16) != gpentHmgr[ulIndex].FullUnique) 1200 { 1201 DPRINT1("GreGetObjectOwner: invalid handle 0x%p.\n", hobj); 1202 return GDI_OBJ_HMGR_RESTRICTED; 1203 } 1204 1205 /* Get the object owner */ 1206 ulOwner = gpentHmgr[ulIndex].ObjectOwner.ulObj; 1207 1208 if (ulOwner == HandleToUlong(PsGetCurrentProcessId())) 1209 return GDI_OBJ_HMGR_POWNED; 1210 1211 if (ulOwner == GDI_OBJ_HMGR_PUBLIC) 1212 return GDI_OBJ_HMGR_PUBLIC; 1213 1214 return GDI_OBJ_HMGR_RESTRICTED; 1215 } 1216 1217 BOOL 1218 NTAPI 1219 GreSetObjectOwnerEx( 1220 HGDIOBJ hobj, 1221 ULONG ulOwner, 1222 ULONG Flags) 1223 { 1224 PENTRY pentry; 1225 1226 /* Check for stock objects */ 1227 if (GDI_HANDLE_IS_STOCKOBJ(hobj)) 1228 { 1229 DPRINT("GreSetObjectOwner: Got stock object %p\n", hobj); 1230 return FALSE; 1231 } 1232 1233 /* Reference the handle entry */ 1234 pentry = ENTRY_ReferenceEntryByHandle(hobj, Flags); 1235 if (!pentry) 1236 { 1237 DPRINT("GreSetObjectOwner: Invalid handle 0x%p.\n", hobj); 1238 return FALSE; 1239 } 1240 1241 /* Call internal function */ 1242 GDIOBJ_vSetObjectOwner(pentry->einfo.pobj, ulOwner); 1243 1244 /* Dereference the object */ 1245 GDIOBJ_vDereferenceObject(pentry->einfo.pobj); 1246 1247 return TRUE; 1248 } 1249 1250 BOOL 1251 NTAPI 1252 GreSetObjectOwner( 1253 HGDIOBJ hobj, 1254 ULONG ulOwner) 1255 { 1256 return GreSetObjectOwnerEx(hobj, ulOwner, 0); 1257 } 1258 1259 INT 1260 NTAPI 1261 GreGetObject( 1262 IN HGDIOBJ hobj, 1263 IN INT cbCount, 1264 OUT PVOID pvBuffer) 1265 { 1266 PVOID pvObj; 1267 UCHAR objt; 1268 INT iResult = 0; 1269 1270 /* Verify object type */ 1271 objt = ((ULONG_PTR)hobj >> 16) & 0x1f; 1272 if (objt != GDIObjType_BRUSH_TYPE && 1273 objt != GDIObjType_SURF_TYPE && 1274 objt != GDIObjType_LFONT_TYPE && 1275 objt != GDIObjType_PAL_TYPE) 1276 { 1277 DPRINT1("GreGetObject: Invalid object type\n"); 1278 return 0; 1279 } 1280 1281 pvObj = GDIOBJ_ReferenceObjectByHandle(hobj, objt); 1282 if (!pvObj) 1283 { 1284 DPRINT("GreGetObject: Could not lock object\n"); 1285 return 0; 1286 } 1287 1288 switch (GDI_HANDLE_GET_TYPE(hobj)) 1289 { 1290 case GDILoObjType_LO_PEN_TYPE: 1291 case GDILoObjType_LO_EXTPEN_TYPE: 1292 iResult = PEN_GetObject(pvObj, cbCount, pvBuffer); 1293 break; 1294 1295 case GDILoObjType_LO_BRUSH_TYPE: 1296 iResult = BRUSH_GetObject(pvObj, cbCount, pvBuffer); 1297 break; 1298 1299 case GDILoObjType_LO_BITMAP_TYPE: 1300 iResult = BITMAP_GetObject(pvObj, cbCount, pvBuffer); 1301 break; 1302 1303 case GDILoObjType_LO_FONT_TYPE: 1304 iResult = FontGetObject(pvObj, cbCount, pvBuffer); 1305 break; 1306 1307 case GDILoObjType_LO_PALETTE_TYPE: 1308 iResult = PALETTE_GetObject(pvObj, cbCount, pvBuffer); 1309 break; 1310 1311 default: 1312 DPRINT1("GDI object type of 0x%p not implemented\n", hobj); 1313 break; 1314 } 1315 1316 GDIOBJ_vDereferenceObject(pvObj); 1317 return iResult; 1318 } 1319 1320 W32KAPI 1321 INT 1322 APIENTRY 1323 NtGdiExtGetObjectW( 1324 IN HANDLE hobj, 1325 IN INT cjBufferSize, 1326 OUT LPVOID lpBuffer) 1327 { 1328 UINT iResult, cjMaxSize; 1329 union 1330 { 1331 BITMAP bitmap; 1332 DIBSECTION dibsection; 1333 LOGPEN logpen; 1334 LOGBRUSH logbrush; 1335 LOGFONTW logfontw; 1336 EXTLOGFONTW extlogfontw; 1337 ENUMLOGFONTEXDVW enumlogfontexdvw; 1338 } object; 1339 1340 /* Normalize to the largest supported object size */ 1341 cjMaxSize = min((UINT)cjBufferSize, sizeof(object)); 1342 1343 /* Now do the actual call */ 1344 iResult = GreGetObject(hobj, cjMaxSize, lpBuffer ? &object : NULL); 1345 1346 /* Check if we have a buffer and data */ 1347 if ((lpBuffer != NULL) && (iResult != 0)) 1348 { 1349 /* Enter SEH for buffer transfer */ 1350 _SEH2_TRY 1351 { 1352 /* Probe the buffer and copy it */ 1353 cjMaxSize = min(cjMaxSize, iResult); 1354 ProbeForWrite(lpBuffer, cjMaxSize, sizeof(WORD)); 1355 RtlCopyMemory(lpBuffer, &object, cjMaxSize); 1356 } 1357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1358 { 1359 /* Clear the return value. 1360 * Do *NOT* set last error here! */ 1361 iResult = 0; 1362 } 1363 _SEH2_END; 1364 } 1365 1366 /* Return the count */ 1367 return iResult; 1368 } 1369 1370 W32KAPI 1371 HANDLE 1372 APIENTRY 1373 NtGdiCreateClientObj( 1374 IN ULONG ulType) 1375 { 1376 POBJ pObject; 1377 HANDLE handle; 1378 1379 /* Check if ulType is valid */ 1380 if ((ulType != GDILoObjType_LO_METAFILE16_TYPE) && 1381 (ulType != GDILoObjType_LO_METAFILE_TYPE) && 1382 (ulType != GDILoObjType_LO_METADC16_TYPE)) 1383 { 1384 DPRINT1("NtGdiCreateClientObj: Invalid object type 0x%lx.\n", ulType); 1385 return NULL; 1386 } 1387 1388 /* Allocate a new object */ 1389 pObject = GDIOBJ_AllocateObject(GDIObjType_CLIENTOBJ_TYPE, 1390 sizeof(CLIENTOBJ), 1391 BASEFLAG_LOOKASIDE); 1392 if (!pObject) 1393 { 1394 DPRINT1("NtGdiCreateClientObj: Could not allocate a clientobj.\n"); 1395 return NULL; 1396 } 1397 1398 /* Set the real object type */ 1399 pObject->hHmgr = UlongToHandle(ulType | GDILoObjType_LO_CLIENTOBJ_TYPE); 1400 1401 /* Create a handle */ 1402 handle = GDIOBJ_hInsertObject(pObject, GDI_OBJ_HMGR_POWNED); 1403 if (!handle) 1404 { 1405 DPRINT1("NtGdiCreateClientObj: Could not create a handle.\n"); 1406 GDIOBJ_vFreeObject(pObject); 1407 return NULL; 1408 } 1409 1410 /* Unlock it */ 1411 GDIOBJ_vUnlockObject(pObject); 1412 1413 return handle; 1414 } 1415 1416 W32KAPI 1417 BOOL 1418 APIENTRY 1419 NtGdiDeleteClientObj( 1420 IN HANDLE hobj) 1421 { 1422 /* We first need to get the real type from the handle */ 1423 ULONG ulType = GDI_HANDLE_GET_TYPE(hobj); 1424 1425 /* Check if it's really a CLIENTOBJ */ 1426 if ((ulType & GDI_HANDLE_BASETYPE_MASK) != GDILoObjType_LO_CLIENTOBJ_TYPE) 1427 { 1428 /* FIXME: SetLastError? */ 1429 return FALSE; 1430 } 1431 1432 return GreDeleteObject(hobj); 1433 } 1434 1435 1436 1437 PGDI_HANDLE_TABLE GdiHandleTable = NULL; 1438 1439 PGDIOBJ NTAPI 1440 GDIOBJ_ShareLockObj(HGDIOBJ hObj, DWORD ExpectedType) 1441 { 1442 if (ExpectedType == GDI_OBJECT_TYPE_DONTCARE) 1443 ExpectedType = GDI_HANDLE_GET_TYPE(hObj); 1444 return GDIOBJ_ReferenceObjectByHandle(hObj, (ExpectedType >> 16) & 0x1f); 1445 } 1446 1447 // This function is not safe to use with concurrent deleting attempts 1448 // That shouldn't be a problem, since we don't have any processes yet, 1449 // that could delete the handle 1450 BOOL 1451 NTAPI 1452 GDIOBJ_ConvertToStockObj(HGDIOBJ *phObj) 1453 { 1454 PENTRY pentry; 1455 POBJ pobj; 1456 1457 /* Reference the handle entry */ 1458 pentry = ENTRY_ReferenceEntryByHandle(*phObj, 0); 1459 if (!pentry) 1460 { 1461 DPRINT1("GDIOBJ: Requested handle 0x%p is not valid.\n", *phObj); 1462 return FALSE; 1463 } 1464 1465 /* Update the entry */ 1466 pentry->FullUnique |= GDI_ENTRY_STOCK_MASK; 1467 pentry->ObjectOwner.ulObj = 0; 1468 1469 /* Get the pointer to the BASEOBJECT */ 1470 pobj = pentry->einfo.pobj; 1471 1472 /* Calculate the new handle */ 1473 pobj->hHmgr = (HGDIOBJ)((ULONG_PTR)pobj->hHmgr | GDI_HANDLE_STOCK_MASK); 1474 1475 /* Return the new handle */ 1476 *phObj = pobj->hHmgr; 1477 1478 /* Dereference the handle */ 1479 GDIOBJ_vDereferenceObject(pobj); 1480 1481 return TRUE; 1482 } 1483 1484 POBJ NTAPI 1485 GDIOBJ_AllocObjWithHandle(ULONG ObjectType, ULONG cjSize) 1486 { 1487 POBJ pobj; 1488 FLONG fl = 0; 1489 UCHAR objt = (ObjectType >> 16) & 0xFF; 1490 1491 if ((objt == GDIObjType_DC_TYPE && cjSize == sizeof(DC)) || 1492 (objt == GDIObjType_PAL_TYPE && cjSize == sizeof(PALETTE)) || 1493 (objt == GDIObjType_RGN_TYPE && cjSize == sizeof(REGION)) || 1494 (objt == GDIObjType_SURF_TYPE && cjSize == sizeof(SURFACE)) || 1495 (objt == GDIObjType_PATH_TYPE && cjSize == sizeof(PATH))) 1496 { 1497 fl |= BASEFLAG_LOOKASIDE; 1498 } 1499 1500 pobj = GDIOBJ_AllocateObject(objt, cjSize, fl); 1501 if (!pobj) 1502 { 1503 return NULL; 1504 } 1505 1506 if (!GDIOBJ_hInsertObject(pobj, GDI_OBJ_HMGR_POWNED)) 1507 { 1508 GDIOBJ_vFreeObject(pobj); 1509 return NULL; 1510 } 1511 return pobj; 1512 } 1513 1514 PVOID NTAPI 1515 GDI_MapHandleTable(PEPROCESS pProcess) 1516 { 1517 PVOID pvMappedView = NULL; 1518 NTSTATUS Status; 1519 LARGE_INTEGER liOffset; 1520 SIZE_T cjViewSize = sizeof(GDI_HANDLE_TABLE); 1521 1522 liOffset.QuadPart = 0; 1523 1524 ASSERT(gpvGdiHdlTblSection != NULL); 1525 ASSERT(pProcess != NULL); 1526 1527 Status = MmMapViewOfSection(gpvGdiHdlTblSection, 1528 pProcess, 1529 &pvMappedView, 1530 0, 1531 0, 1532 &liOffset, 1533 &cjViewSize, 1534 ViewUnmap, 1535 SEC_NO_CHANGE, 1536 PAGE_READONLY); 1537 1538 if (!NT_SUCCESS(Status)) 1539 return NULL; 1540 1541 return pvMappedView; 1542 } 1543 1544 BOOL NTAPI 1545 GDI_CleanupForProcess(struct _EPROCESS *Process) 1546 { 1547 PENTRY pentry; 1548 ULONG ulIndex; 1549 DWORD dwProcessId; 1550 PPROCESSINFO ppi; 1551 1552 DPRINT("CleanupForProcess prochandle %p Pid %p\n", 1553 Process, Process->UniqueProcessId); 1554 1555 ASSERT(Process == PsGetCurrentProcess()); 1556 1557 /* Get the current process Id */ 1558 dwProcessId = PtrToUlong(PsGetCurrentProcessId()); 1559 1560 /* Loop all handles in the handle table */ 1561 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++) 1562 { 1563 pentry = &gpentHmgr[ulIndex]; 1564 1565 /* Check if the object is owned by the process */ 1566 if (pentry->ObjectOwner.ulObj == dwProcessId) 1567 { 1568 ASSERT(pentry->einfo.pobj->cExclusiveLock == 0); 1569 1570 /* Reference the object and delete it */ 1571 InterlockedIncrement((LONG*)&gpaulRefCount[ulIndex]); 1572 GDIOBJ_vDeleteObject(pentry->einfo.pobj); 1573 } 1574 } 1575 1576 #if DBG 1577 DbgGdiHTIntegrityCheck(); 1578 #endif 1579 1580 ppi = PsGetCurrentProcessWin32Process(); 1581 DPRINT("Completed cleanup for process %p\n", Process->UniqueProcessId); 1582 if (ppi->GDIHandleCount != 0) 1583 { 1584 DPRINT1("Leaking %d handles!\n", ppi->GDIHandleCount); 1585 ASSERT(FALSE); 1586 } 1587 1588 /* Loop all handles in the handle table */ 1589 for (ulIndex = RESERVE_ENTRIES_COUNT; ulIndex < gulFirstUnused; ulIndex++) 1590 { 1591 pentry = &gpentHmgr[ulIndex]; 1592 1593 /* Check if the object is owned by the process */ 1594 if (pentry->ObjectOwner.ulObj == dwProcessId) 1595 { 1596 DPRINT1("Leaking object. Index=%lx, type=0x%x, refcount=%lx\n", 1597 ulIndex, pentry->Objt, gpaulRefCount[ulIndex]); 1598 DBG_DUMP_EVENT_LIST(&pentry->einfo.pobj->slhLog); 1599 //DBG_CLEANUP_EVENT_LIST(&pentry->einfo.pobj->slhLog); 1600 ASSERT(FALSE); 1601 } 1602 } 1603 1604 return TRUE; 1605 } 1606 1607 /// HACK! 1608 PGDI_POOL 1609 GetBrushAttrPool(VOID) 1610 { 1611 PPROCESSINFO ppi; 1612 1613 ppi = PsGetCurrentProcessWin32Process(); 1614 NT_ASSERT(ppi != NULL); 1615 1616 return ppi->pPoolBrushAttr; 1617 } 1618 1619 /* EOF */ 1620