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