1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: User handle manager 5 * FILE: win32ss/user/ntuser/object.c 6 * PROGRAMER: Copyright (C) 2001 Alexandre Julliard 7 */ 8 9 #include <win32k.h> 10 DBG_DEFAULT_CHANNEL(UserObj); 11 12 //int usedHandles=0; 13 PUSER_HANDLE_TABLE gHandleTable = NULL; 14 15 /* Forward declarations */ 16 _Success_(return!=NULL) 17 static PVOID AllocThreadObject( 18 _In_ PDESKTOP pDesk, 19 _In_ PTHREADINFO pti, 20 _In_ SIZE_T Size, 21 _Out_ PVOID* HandleOwner) 22 { 23 PTHROBJHEAD ObjHead; 24 25 UNREFERENCED_PARAMETER(pDesk); 26 27 ASSERT(Size > sizeof(*ObjHead)); 28 ASSERT(pti != NULL); 29 30 ObjHead = UserHeapAlloc(Size); 31 if (!ObjHead) 32 return NULL; 33 34 RtlZeroMemory(ObjHead, Size); 35 36 ObjHead->pti = pti; 37 IntReferenceThreadInfo(pti); 38 *HandleOwner = pti; 39 /* It's a thread object, but it still count as one for the process */ 40 pti->ppi->UserHandleCount++; 41 42 return ObjHead; 43 } 44 45 static void FreeThreadObject( 46 _In_ PVOID Object) 47 { 48 PTHROBJHEAD ObjHead = (PTHROBJHEAD)Object; 49 PTHREADINFO pti = ObjHead->pti; 50 51 UserHeapFree(ObjHead); 52 53 pti->ppi->UserHandleCount--; 54 IntDereferenceThreadInfo(pti); 55 } 56 57 _Success_(return!=NULL) 58 static PVOID AllocDeskThreadObject( 59 _In_ PDESKTOP pDesk, 60 _In_ PTHREADINFO pti, 61 _In_ SIZE_T Size, 62 _Out_ PVOID* HandleOwner) 63 { 64 PTHRDESKHEAD ObjHead; 65 66 ASSERT(Size > sizeof(*ObjHead)); 67 ASSERT(pti != NULL); 68 69 if (!pDesk) 70 pDesk = pti->rpdesk; 71 72 ObjHead = DesktopHeapAlloc(pDesk, Size); 73 if (!ObjHead) 74 return NULL; 75 76 RtlZeroMemory(ObjHead, Size); 77 78 ObjHead->pSelf = ObjHead; 79 ObjHead->rpdesk = pDesk; 80 ObjHead->pti = pti; 81 IntReferenceThreadInfo(pti); 82 *HandleOwner = pti; 83 /* It's a thread object, but it still count as one for the process */ 84 pti->ppi->UserHandleCount++; 85 86 return ObjHead; 87 } 88 89 static void FreeDeskThreadObject( 90 _In_ PVOID Object) 91 { 92 PTHRDESKHEAD ObjHead = (PTHRDESKHEAD)Object; 93 PDESKTOP pDesk = ObjHead->rpdesk; 94 PTHREADINFO pti = ObjHead->pti; 95 96 DesktopHeapFree(pDesk, Object); 97 98 pti->ppi->UserHandleCount--; 99 IntDereferenceThreadInfo(pti); 100 } 101 102 _Success_(return!=NULL) 103 static PVOID AllocDeskProcObject( 104 _In_ PDESKTOP pDesk, 105 _In_ PTHREADINFO pti, 106 _In_ SIZE_T Size, 107 _Out_ PVOID* HandleOwner) 108 { 109 PPROCDESKHEAD ObjHead; 110 PPROCESSINFO ppi; 111 112 ASSERT(Size > sizeof(*ObjHead)); 113 ASSERT(pDesk != NULL); 114 ASSERT(pti != NULL); 115 116 ObjHead = DesktopHeapAlloc(pDesk, Size); 117 if (!ObjHead) 118 return NULL; 119 120 RtlZeroMemory(ObjHead, Size); 121 122 ppi = pti->ppi; 123 124 ObjHead->pSelf = ObjHead; 125 ObjHead->rpdesk = pDesk; 126 ObjHead->hTaskWow = (DWORD_PTR)ppi; 127 ppi->UserHandleCount++; 128 IntReferenceProcessInfo(ppi); 129 *HandleOwner = ppi; 130 131 return ObjHead; 132 } 133 134 static void FreeDeskProcObject( 135 _In_ PVOID Object) 136 { 137 PPROCDESKHEAD ObjHead = (PPROCDESKHEAD)Object; 138 PDESKTOP pDesk = ObjHead->rpdesk; 139 PPROCESSINFO ppi = (PPROCESSINFO)ObjHead->hTaskWow; 140 141 ppi->UserHandleCount--; 142 IntDereferenceProcessInfo(ppi); 143 144 DesktopHeapFree(pDesk, Object); 145 } 146 147 _Success_(return!=NULL) 148 static PVOID AllocProcMarkObject( 149 _In_ PDESKTOP pDesk, 150 _In_ PTHREADINFO pti, 151 _In_ SIZE_T Size, 152 _Out_ PVOID* HandleOwner) 153 { 154 PPROCMARKHEAD ObjHead; 155 PPROCESSINFO ppi = pti->ppi; 156 157 UNREFERENCED_PARAMETER(pDesk); 158 159 ASSERT(Size > sizeof(*ObjHead)); 160 161 ObjHead = UserHeapAlloc(Size); 162 if (!ObjHead) 163 return NULL; 164 165 RtlZeroMemory(ObjHead, Size); 166 167 ObjHead->ppi = ppi; 168 IntReferenceProcessInfo(ppi); 169 *HandleOwner = ppi; 170 ppi->UserHandleCount++; 171 172 return ObjHead; 173 } 174 175 void FreeProcMarkObject( 176 _In_ PVOID Object) 177 { 178 PPROCESSINFO ppi = ((PPROCMARKHEAD)Object)->ppi; 179 180 UserHeapFree(Object); 181 182 ppi->UserHandleCount--; 183 IntDereferenceProcessInfo(ppi); 184 } 185 186 _Success_(return!=NULL) 187 static PVOID AllocSysObject( 188 _In_ PDESKTOP pDesk, 189 _In_ PTHREADINFO pti, 190 _In_ SIZE_T Size, 191 _Out_ PVOID* ObjectOwner) 192 { 193 PVOID Object; 194 195 UNREFERENCED_PARAMETER(pDesk); 196 UNREFERENCED_PARAMETER(pti); 197 198 ASSERT(Size > sizeof(HEAD)); 199 200 Object = UserHeapAlloc(Size); 201 if (!Object) 202 return NULL; 203 204 *ObjectOwner = NULL; 205 206 RtlZeroMemory(Object, Size); 207 return Object; 208 } 209 210 _Success_(return!=NULL) 211 static PVOID AllocSysObjectCB( 212 _In_ PDESKTOP pDesk, 213 _In_ PTHREADINFO pti, 214 _In_ SIZE_T Size, 215 _Out_ PVOID* ObjectOwner) 216 { 217 PVOID Object; 218 219 UNREFERENCED_PARAMETER(pDesk); 220 UNREFERENCED_PARAMETER(pti); 221 ASSERT(Size > sizeof(HEAD)); 222 223 /* Allocate the clipboard data */ 224 // FIXME: This allocation should be done on the current session pool; 225 // however ReactOS' MM doesn't support session pool yet. 226 Object = ExAllocatePoolZero(/* SESSION_POOL_MASK | */ PagedPool, Size, USERTAG_CLIPBOARD); 227 if (!Object) 228 { 229 ERR("ExAllocatePoolZero failed. No object created.\n"); 230 return NULL; 231 } 232 233 *ObjectOwner = NULL; 234 return Object; 235 } 236 237 static void FreeSysObject( 238 _In_ PVOID Object) 239 { 240 UserHeapFree(Object); 241 } 242 243 static void FreeSysObjectCB( 244 _In_ PVOID Object) 245 { 246 ExFreePoolWithTag(Object, USERTAG_CLIPBOARD); 247 } 248 249 static const struct 250 { 251 PVOID (*ObjectAlloc)(PDESKTOP, PTHREADINFO, SIZE_T, PVOID*); 252 BOOLEAN (*ObjectDestroy)(PVOID); 253 void (*ObjectFree)(PVOID); 254 } ObjectCallbacks[TYPE_CTYPES] = 255 { 256 { NULL, NULL, NULL }, /* TYPE_FREE */ 257 { AllocDeskThreadObject, co_UserDestroyWindow, FreeDeskThreadObject }, /* TYPE_WINDOW */ 258 { AllocDeskProcObject, UserDestroyMenuObject, FreeDeskProcObject }, /* TYPE_MENU */ 259 { AllocProcMarkObject, IntDestroyCurIconObject, FreeCurIconObject }, /* TYPE_CURSOR */ 260 { AllocSysObject, /*UserSetWindowPosCleanup*/NULL, FreeSysObject }, /* TYPE_SETWINDOWPOS */ 261 { AllocDeskThreadObject, IntRemoveHook, FreeDeskThreadObject }, /* TYPE_HOOK */ 262 { AllocSysObjectCB, /*UserClipDataCleanup*/NULL,FreeSysObjectCB }, /* TYPE_CLIPDATA */ 263 { AllocDeskProcObject, DestroyCallProc, FreeDeskProcObject }, /* TYPE_CALLPROC */ 264 { AllocProcMarkObject, UserDestroyAccelTable, FreeProcMarkObject }, /* TYPE_ACCELTABLE */ 265 { NULL, NULL, NULL }, /* TYPE_DDEACCESS */ 266 { NULL, NULL, NULL }, /* TYPE_DDECONV */ 267 { NULL, NULL, NULL }, /* TYPE_DDEXACT */ 268 { AllocSysObject, /*UserMonitorCleanup*/NULL, FreeSysObject }, /* TYPE_MONITOR */ 269 { AllocSysObject, /*UserKbdLayoutCleanup*/NULL,FreeSysObject }, /* TYPE_KBDLAYOUT */ 270 { AllocSysObject, /*UserKbdFileCleanup*/NULL, FreeSysObject }, /* TYPE_KBDFILE */ 271 { AllocThreadObject, IntRemoveEvent, FreeThreadObject }, /* TYPE_WINEVENTHOOK */ 272 { AllocSysObject, /*UserTimerCleanup*/NULL, FreeSysObject }, /* TYPE_TIMER */ 273 { AllocInputContextObject, UserDestroyInputContext, UserFreeInputContext }, /* TYPE_INPUTCONTEXT */ 274 { NULL, NULL, NULL }, /* TYPE_HIDDATA */ 275 { NULL, NULL, NULL }, /* TYPE_DEVICEINFO */ 276 { NULL, NULL, NULL }, /* TYPE_TOUCHINPUTINFO */ 277 { NULL, NULL, NULL }, /* TYPE_GESTUREINFOOBJ */ 278 }; 279 280 #if DBG 281 282 void DbgUserDumpHandleTable(VOID) 283 { 284 int HandleCounts[TYPE_CTYPES]; 285 PPROCESSINFO ppiList; 286 int i; 287 PWCHAR TypeNames[] = {L"Free",L"Window",L"Menu", L"CursorIcon", L"SMWP", L"Hook", L"ClipBoardData", L"CallProc", 288 L"Accel", L"DDEaccess", L"DDEconv", L"DDExact", L"Monitor", L"KBDlayout", L"KBDfile", 289 L"Event", L"Timer", L"InputContext", L"HidData", L"DeviceInfo", L"TouchInput",L"GestureInfo"}; 290 291 ERR("Total handles count: %lu\n", gpsi->cHandleEntries); 292 293 memset(HandleCounts, 0, sizeof(HandleCounts)); 294 295 /* First of all count the number of handles per type */ 296 ppiList = gppiList; 297 while (ppiList) 298 { 299 ERR("Process %s (%p) handles count: %d\n\t", ppiList->peProcess->ImageFileName, ppiList->peProcess->UniqueProcessId, ppiList->UserHandleCount); 300 301 for (i = 1 ;i < TYPE_CTYPES; i++) 302 { 303 HandleCounts[i] += ppiList->DbgHandleCount[i]; 304 305 DbgPrint("%S: %lu, ", TypeNames[i], ppiList->DbgHandleCount[i]); 306 if (i % 6 == 0) 307 DbgPrint("\n\t"); 308 } 309 DbgPrint("\n"); 310 311 ppiList = ppiList->ppiNext; 312 } 313 314 /* Print total type counts */ 315 ERR("Total handles of the running processes: \n\t"); 316 for (i = 1 ;i < TYPE_CTYPES; i++) 317 { 318 DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]); 319 if (i % 6 == 0) 320 DbgPrint("\n\t"); 321 } 322 DbgPrint("\n"); 323 324 /* Now count the handle counts that are allocated from the handle table */ 325 memset(HandleCounts, 0, sizeof(HandleCounts)); 326 for (i = 0; i < gHandleTable->nb_handles; i++) 327 HandleCounts[gHandleTable->handles[i].type]++; 328 329 ERR("Total handles count allocated: \n\t"); 330 for (i = 1 ;i < TYPE_CTYPES; i++) 331 { 332 DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]); 333 if (i % 6 == 0) 334 DbgPrint("\n\t"); 335 } 336 DbgPrint("\n"); 337 } 338 339 #endif 340 341 PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle ) 342 { 343 unsigned short generation; 344 int index = (LOWORD(handle) - FIRST_USER_HANDLE) >> 1; 345 if (index < 0 || index >= ht->nb_handles) 346 return NULL; 347 if (!ht->handles[index].type) 348 return NULL; 349 generation = HIWORD(handle); 350 if (generation == ht->handles[index].generation || !generation || generation == 0xffff) 351 return &ht->handles[index]; 352 return NULL; 353 } 354 355 __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr ) 356 { 357 int index = ptr - ht->handles; 358 return (HANDLE)((((INT_PTR)index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16)); 359 } 360 361 __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht) 362 { 363 PUSER_HANDLE_ENTRY entry; 364 TRACE("handles used %lu\n", gpsi->cHandleEntries); 365 366 if (ht->freelist) 367 { 368 entry = ht->freelist; 369 ht->freelist = entry->ptr; 370 371 gpsi->cHandleEntries++; 372 return entry; 373 } 374 375 if (ht->nb_handles >= ht->allocated_handles) /* Need to grow the array */ 376 { 377 ERR("Out of user handles! Used -> %lu, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles); 378 379 #if DBG 380 DbgUserDumpHandleTable(); 381 #endif 382 383 return NULL; 384 #if 0 385 PUSER_HANDLE_ENTRY new_handles; 386 /* Grow array by 50% (but at minimum 32 entries) */ 387 int growth = max( 32, ht->allocated_handles / 2 ); 388 int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 ); 389 if (new_size <= ht->allocated_handles) 390 return NULL; 391 if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) ))) 392 return NULL; 393 ht->handles = new_handles; 394 ht->allocated_handles = new_size; 395 #endif 396 } 397 398 entry = &ht->handles[ht->nb_handles++]; 399 400 entry->generation = 1; 401 402 gpsi->cHandleEntries++; 403 404 return entry; 405 } 406 407 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes) 408 { 409 ht->freelist = NULL; 410 ht->handles = mem; 411 412 ht->nb_handles = 0; 413 ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY); 414 } 415 416 417 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry) 418 { 419 void *ret; 420 421 #if DBG 422 { 423 PPROCESSINFO ppi; 424 switch (entry->type) 425 { 426 case TYPE_WINDOW: 427 case TYPE_HOOK: 428 case TYPE_WINEVENTHOOK: 429 ppi = ((PTHREADINFO)entry->pi)->ppi; 430 break; 431 case TYPE_MENU: 432 case TYPE_CURSOR: 433 case TYPE_CALLPROC: 434 case TYPE_ACCELTABLE: 435 ppi = entry->pi; 436 break; 437 default: 438 ppi = NULL; 439 } 440 if (ppi) 441 ppi->DbgHandleCount[entry->type]--; 442 } 443 #endif 444 445 ret = entry->ptr; 446 entry->ptr = ht->freelist; 447 entry->type = 0; 448 entry->flags = 0; 449 entry->pi = NULL; 450 ht->freelist = entry; 451 452 gpsi->cHandleEntries--; 453 454 return ret; 455 } 456 457 /* allocate a user handle for a given object */ 458 HANDLE UserAllocHandle( 459 _Inout_ PUSER_HANDLE_TABLE ht, 460 _In_ PVOID object, 461 _In_ HANDLE_TYPE type, 462 _In_ PVOID HandleOwner) 463 { 464 PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht); 465 if (!entry) 466 return 0; 467 entry->ptr = object; 468 entry->type = type; 469 entry->flags = 0; 470 entry->pi = HandleOwner; 471 if (++entry->generation >= 0xffff) 472 entry->generation = 1; 473 474 /* We have created a handle, which is a reference! */ 475 UserReferenceObject(object); 476 477 return entry_to_handle(ht, entry ); 478 } 479 480 /* return a pointer to a user object from its handle without setting an error */ 481 PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type ) 482 { 483 PUSER_HANDLE_ENTRY entry; 484 485 ASSERT(ht); 486 487 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type) 488 { 489 return NULL; 490 } 491 return entry->ptr; 492 } 493 494 /* return a pointer to a user object from its handle */ 495 PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type ) 496 { 497 PUSER_HANDLE_ENTRY entry; 498 499 ASSERT(ht); 500 501 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type) 502 { 503 EngSetLastError(ERROR_INVALID_HANDLE); 504 return NULL; 505 } 506 return entry->ptr; 507 } 508 509 510 /* Get the full handle (32bit) for a possibly truncated (16bit) handle */ 511 HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht, HANDLE handle ) 512 { 513 PUSER_HANDLE_ENTRY entry; 514 515 if ((ULONG_PTR)handle >> 16) 516 return handle; 517 if (!(entry = handle_to_entry(ht, handle ))) 518 return handle; 519 return entry_to_handle( ht, entry ); 520 } 521 522 523 /* Same as get_user_object plus set the handle to the full 32-bit value */ 524 void *get_user_object_handle(PUSER_HANDLE_TABLE ht, HANDLE* handle, HANDLE_TYPE type ) 525 { 526 PUSER_HANDLE_ENTRY entry; 527 528 if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type) 529 return NULL; 530 *handle = entry_to_handle( ht, entry ); 531 return entry->ptr; 532 } 533 534 535 536 BOOL FASTCALL UserCreateHandleTable(VOID) 537 { 538 PVOID mem; 539 INT HandleCount = 1024 * 4; 540 541 // FIXME: Don't alloc all at once! Must be mapped into umode also... 542 mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * HandleCount); 543 if (!mem) 544 { 545 ERR("Failed creating handle table\n"); 546 return FALSE; 547 } 548 549 gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE)); 550 if (gHandleTable == NULL) 551 { 552 UserHeapFree(mem); 553 ERR("Failed creating handle table\n"); 554 return FALSE; 555 } 556 557 // FIXME: Make auto growable 558 UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * HandleCount); 559 560 return TRUE; 561 } 562 563 // 564 // New 565 // 566 PVOID 567 FASTCALL 568 UserCreateObject( PUSER_HANDLE_TABLE ht, 569 PDESKTOP pDesktop, 570 PTHREADINFO pti, 571 HANDLE* h, 572 HANDLE_TYPE type, 573 ULONG size) 574 { 575 HANDLE hi; 576 PVOID Object; 577 PVOID ObjectOwner; 578 579 /* Some sanity checks. Other checks will be made in the allocator */ 580 ASSERT(type < TYPE_CTYPES); 581 ASSERT(type != TYPE_FREE); 582 ASSERT(ht != NULL); 583 584 /* Allocate the object */ 585 ASSERT(ObjectCallbacks[type].ObjectAlloc != NULL); 586 Object = ObjectCallbacks[type].ObjectAlloc(pDesktop, pti, size, &ObjectOwner); 587 if (!Object) 588 { 589 ERR("User object allocation failed. Out of memory!\n"); 590 return NULL; 591 } 592 593 hi = UserAllocHandle(ht, Object, type, ObjectOwner); 594 if (hi == NULL) 595 { 596 ERR("Out of user handles!\n"); 597 ObjectCallbacks[type].ObjectFree(Object); 598 return NULL; 599 } 600 601 #if DBG 602 if (pti) 603 pti->ppi->DbgHandleCount[type]++; 604 #endif 605 606 /* Give this object its identity. */ 607 ((PHEAD)Object)->h = hi; 608 609 /* The caller will get a locked object. 610 * Note: with the reference from the handle, that makes two */ 611 UserReferenceObject(Object); 612 613 if (h) 614 *h = hi; 615 return Object; 616 } 617 618 // Win: HMMarkObjectDestroy 619 BOOL 620 FASTCALL 621 UserMarkObjectDestroy(PVOID Object) 622 { 623 PUSER_HANDLE_ENTRY entry; 624 PHEAD ObjHead = Object; 625 626 entry = handle_to_entry(gHandleTable, ObjHead->h); 627 628 ASSERT(entry != NULL); 629 630 entry->flags |= HANDLEENTRY_DESTROY; 631 632 if (ObjHead->cLockObj > 1) 633 { 634 entry->flags &= ~HANDLEENTRY_INDESTROY; 635 TRACE("Count %d\n",ObjHead->cLockObj); 636 return FALSE; 637 } 638 639 return TRUE; 640 } 641 642 BOOL 643 FASTCALL 644 UserDereferenceObject(PVOID Object) 645 { 646 PHEAD ObjHead = Object; 647 648 ASSERT(ObjHead->cLockObj >= 1); 649 ASSERT(ObjHead->cLockObj < 0x10000); 650 651 if (--ObjHead->cLockObj == 0) 652 { 653 PUSER_HANDLE_ENTRY entry; 654 HANDLE_TYPE type; 655 656 entry = handle_to_entry(gHandleTable, ObjHead->h); 657 658 ASSERT(entry != NULL); 659 /* The entry should be marked as in deletion */ 660 ASSERT(entry->flags & HANDLEENTRY_INDESTROY); 661 662 type = entry->type; 663 ASSERT(type != TYPE_FREE); 664 ASSERT(type < TYPE_CTYPES); 665 666 /* We can now get rid of everything */ 667 free_user_entry(gHandleTable, entry ); 668 669 #if 0 670 /* Call the object destructor */ 671 ASSERT(ObjectCallbacks[type].ObjectCleanup != NULL); 672 ObjectCallbacks[type].ObjectCleanup(Object); 673 #endif 674 675 /* And free it */ 676 ASSERT(ObjectCallbacks[type].ObjectFree != NULL); 677 ObjectCallbacks[type].ObjectFree(Object); 678 679 return TRUE; 680 } 681 return FALSE; 682 } 683 684 BOOL 685 FASTCALL 686 UserFreeHandle(PUSER_HANDLE_TABLE ht, HANDLE handle ) 687 { 688 PUSER_HANDLE_ENTRY entry; 689 690 if (!(entry = handle_to_entry( ht, handle ))) 691 { 692 SetLastNtError( STATUS_INVALID_HANDLE ); 693 return FALSE; 694 } 695 696 entry->flags = HANDLEENTRY_INDESTROY; 697 698 return UserDereferenceObject(entry->ptr); 699 } 700 701 BOOL 702 FASTCALL 703 UserObjectInDestroy(HANDLE h) 704 { 705 PUSER_HANDLE_ENTRY entry; 706 707 if (!(entry = handle_to_entry( gHandleTable, h ))) 708 { 709 SetLastNtError( STATUS_INVALID_HANDLE ); 710 return TRUE; 711 } 712 return (entry->flags & HANDLEENTRY_INDESTROY); 713 } 714 715 BOOL 716 FASTCALL 717 UserDeleteObject(HANDLE h, HANDLE_TYPE type ) 718 { 719 PVOID body = UserGetObject(gHandleTable, h, type); 720 721 if (!body) return FALSE; 722 723 ASSERT( ((PHEAD)body)->cLockObj >= 1); 724 ASSERT( ((PHEAD)body)->cLockObj < 0x10000); 725 726 return UserFreeHandle(gHandleTable, h); 727 } 728 729 VOID 730 FASTCALL 731 UserReferenceObject(PVOID obj) 732 { 733 PHEAD ObjHead = obj; 734 ASSERT(ObjHead->cLockObj < 0x10000); 735 736 ObjHead->cLockObj++; 737 } 738 739 PVOID 740 FASTCALL 741 UserReferenceObjectByHandle(HANDLE handle, HANDLE_TYPE type) 742 { 743 PVOID object; 744 745 object = UserGetObject(gHandleTable, handle, type); 746 if (object) 747 { 748 UserReferenceObject(object); 749 } 750 return object; 751 } 752 753 BOOLEAN 754 UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner) 755 { 756 int i; 757 PUSER_HANDLE_ENTRY Entry; 758 BOOLEAN Ret = TRUE; 759 760 /* Sweep the whole handle table */ 761 for (i = 0; i < Table->allocated_handles; i++) 762 { 763 Entry = &Table->handles[i]; 764 765 if (Entry->pi != Owner) 766 continue; 767 768 /* Do not destroy if it's already been done */ 769 if (Entry->flags & HANDLEENTRY_INDESTROY) 770 continue; 771 772 /* Call destructor */ 773 if (!ObjectCallbacks[Entry->type].ObjectDestroy(Entry->ptr)) 774 { 775 ERR("Failed destructing object %p, type %u.\n", Entry->ptr, Entry->type); 776 /* Don't return immediately, we must continue destroying the other objects */ 777 Ret = FALSE; 778 } 779 } 780 781 return Ret; 782 } 783 784 /* 785 * 786 * Status 787 * @implemented 788 */ 789 790 BOOL 791 APIENTRY 792 NtUserValidateHandleSecure( 793 HANDLE handle) 794 { 795 UINT uType; 796 PPROCESSINFO ppi; 797 PUSER_HANDLE_ENTRY entry; 798 BOOL Ret = FALSE; 799 800 UserEnterExclusive(); 801 802 if (!(entry = handle_to_entry(gHandleTable, handle ))) 803 { 804 EngSetLastError(ERROR_INVALID_HANDLE); 805 goto Exit; // Return FALSE 806 } 807 uType = entry->type; 808 switch (uType) 809 { 810 case TYPE_WINDOW: 811 case TYPE_INPUTCONTEXT: 812 ppi = ((PTHREADINFO)entry->pi)->ppi; 813 break; 814 case TYPE_MENU: 815 case TYPE_ACCELTABLE: 816 case TYPE_CURSOR: 817 case TYPE_HOOK: 818 case TYPE_CALLPROC: 819 case TYPE_SETWINDOWPOS: 820 ppi = entry->pi; 821 break; 822 default: 823 ppi = NULL; 824 break; 825 } 826 827 if (!ppi) 828 goto Exit; // Return FALSE 829 830 // Same process job returns TRUE. 831 if (gptiCurrent->ppi->pW32Job == ppi->pW32Job) Ret = TRUE; 832 833 Exit: 834 UserLeave(); 835 return Ret; 836 } 837 838 // Win: HMAssignmentLock 839 PVOID FASTCALL UserAssignmentLock(PVOID *ppvObj, PVOID pvNew) 840 { 841 PVOID pvOld = *ppvObj; 842 *ppvObj = pvNew; 843 844 if (pvOld && pvOld == pvNew) 845 return pvOld; 846 847 if (pvNew) 848 UserReferenceObject(pvNew); 849 850 if (pvOld) 851 { 852 if (UserDereferenceObject(pvOld)) 853 pvOld = NULL; 854 } 855 856 return pvOld; 857 } 858 859 // Win: HMAssignmentUnlock 860 PVOID FASTCALL UserAssignmentUnlock(PVOID *ppvObj) 861 { 862 PVOID pvOld = *ppvObj; 863 *ppvObj = NULL; 864 865 if (pvOld) 866 { 867 if (UserDereferenceObject(pvOld)) 868 pvOld = NULL; 869 } 870 871 return pvOld; 872 } 873