1 /* 2 * PROJECT: ReactOS Win32 Base API 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/win32/kernel32/client/heapmem.c 5 * PURPOSE: Heap Memory APIs (wrappers for RtlHeap*) 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <k32.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS ********************************************************************/ 17 18 RTL_HANDLE_TABLE BaseHeapHandleTable; 19 HANDLE BaseHeap; 20 ULONG_PTR SystemRangeStart; 21 22 /* PRIVATE FUNCTIONS **********************************************************/ 23 24 VOID 25 NTAPI 26 BaseDllInitializeMemoryManager(VOID) 27 { 28 BaseHeap = RtlGetProcessHeap(); 29 RtlInitializeHandleTable(0xFFFF, 30 sizeof(BASE_HEAP_HANDLE_ENTRY), 31 &BaseHeapHandleTable); 32 NtQuerySystemInformation(SystemRangeStartInformation, 33 &SystemRangeStart, 34 sizeof(SystemRangeStart), 35 NULL); 36 } 37 38 /* PUBLIC FUNCTIONS ***********************************************************/ 39 40 /* 41 * @implemented 42 */ 43 HANDLE 44 WINAPI 45 HeapCreate(DWORD flOptions, 46 SIZE_T dwInitialSize, 47 SIZE_T dwMaximumSize) 48 { 49 HANDLE hRet; 50 ULONG Flags; 51 52 /* Remove non-Win32 flags and tag this allocation */ 53 Flags = (flOptions & (HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE)) | 54 HEAP_CLASS_1; 55 56 /* Check if heap is growable and ensure max size is correct */ 57 if (dwMaximumSize == 0) 58 Flags |= HEAP_GROWABLE; 59 else if (dwMaximumSize < BaseStaticServerData->SysInfo.PageSize && 60 dwInitialSize > dwMaximumSize) 61 { 62 /* Max size is non-zero but less than page size which can't be correct. 63 Fix it up by bumping it to the initial size whatever it is. */ 64 dwMaximumSize = dwInitialSize; 65 } 66 67 /* Call RTL Heap */ 68 hRet = RtlCreateHeap(Flags, 69 NULL, 70 dwMaximumSize, 71 dwInitialSize, 72 NULL, 73 NULL); 74 75 /* Set the last error if we failed, and return the pointer */ 76 if (!hRet) SetLastError(ERROR_NOT_ENOUGH_MEMORY); 77 return hRet; 78 } 79 80 /* 81 * @implemented 82 */ 83 BOOL 84 WINAPI 85 HeapDestroy(HANDLE hHeap) 86 { 87 /* Return TRUE if the heap was destroyed */ 88 if (!RtlDestroyHeap(hHeap)) return TRUE; 89 90 /* Otherwise, we got the handle back, so fail */ 91 SetLastError(ERROR_INVALID_HANDLE); 92 return FALSE; 93 } 94 95 /* 96 * @implemented 97 */ 98 HANDLE 99 WINAPI 100 GetProcessHeap(VOID) 101 { 102 /* Call the RTL API */ 103 return RtlGetProcessHeap(); 104 } 105 106 /* 107 * @implemented 108 */ 109 DWORD 110 WINAPI 111 GetProcessHeaps(DWORD NumberOfHeaps, 112 PHANDLE ProcessHeaps) 113 { 114 /* Call the RTL API */ 115 return RtlGetProcessHeaps(NumberOfHeaps, ProcessHeaps); 116 } 117 118 /* 119 * @implemented 120 */ 121 BOOL 122 WINAPI 123 HeapLock(HANDLE hHeap) 124 { 125 /* Call the RTL API */ 126 return RtlLockHeap(hHeap); 127 } 128 129 /* 130 * @implemented 131 */ 132 BOOL 133 WINAPI 134 HeapUnlock(HANDLE hHeap) 135 { 136 /* Call the RTL API */ 137 return RtlUnlockHeap(hHeap); 138 } 139 140 /* 141 * @implemented 142 */ 143 SIZE_T 144 WINAPI 145 HeapCompact(HANDLE hHeap, DWORD dwFlags) 146 { 147 /* Call the RTL API */ 148 return RtlCompactHeap(hHeap, dwFlags); 149 } 150 151 /* 152 * @implemented 153 */ 154 BOOL 155 WINAPI 156 HeapValidate(HANDLE hHeap, 157 DWORD dwFlags, 158 LPCVOID lpMem) 159 { 160 /* Call the RTL API */ 161 return RtlValidateHeap(hHeap, dwFlags, (PVOID)lpMem); 162 } 163 164 /* 165 * @implemented 166 */ 167 DWORD 168 WINAPI 169 HeapCreateTagsW(_In_ HANDLE hHeap, 170 _In_ DWORD dwFlags, 171 _In_opt_ PWSTR lpTagName, 172 _In_ PWSTR lpTagSubName) 173 { 174 /* Call the RTL API */ 175 return RtlCreateTagHeap(hHeap, 176 dwFlags, 177 lpTagName, 178 lpTagSubName); 179 } 180 181 /* 182 * @implemented 183 */ 184 DWORD 185 WINAPI 186 HeapExtend(HANDLE hHeap, 187 DWORD dwFlags, 188 PVOID BaseAddress, 189 DWORD dwBytes) 190 { 191 NTSTATUS Status; 192 193 /* Call the RTL API. Gone in Vista, so commented out. */ 194 Status = STATUS_NOT_IMPLEMENTED; //RtlExtendHeap(hHeap, dwFlags, BaseAddress, dwBytes); 195 if (!NT_SUCCESS(Status)) 196 { 197 /* We failed */ 198 BaseSetLastNTError(Status); 199 return FALSE; 200 } 201 202 /* Return success */ 203 return TRUE; 204 } 205 206 /* 207 * @implemented 208 */ 209 PWSTR 210 WINAPI 211 HeapQueryTagW(HANDLE hHeap, 212 DWORD dwFlags, 213 WORD wTagIndex, 214 BOOL bResetCounters, 215 PVOID lpTagInfo) 216 { 217 /* Call the RTL API */ 218 return RtlQueryTagHeap(hHeap, 219 dwFlags, 220 wTagIndex, 221 (BOOLEAN)bResetCounters, 222 lpTagInfo); 223 } 224 225 /* 226 * @implemented 227 */ 228 BOOL 229 WINAPI 230 HeapSummary(HANDLE hHeap, 231 DWORD dwFlags, 232 PVOID Summary) 233 { 234 NTSTATUS Status; 235 RTL_HEAP_USAGE Usage; 236 237 /* Fill in the length information */ 238 Usage.Length = sizeof(Usage); 239 240 /* Call RTL. Gone in Vista, so commented out */ 241 Status = STATUS_NOT_IMPLEMENTED; //RtlUsageHeap(hHeap, dwFlags, &Usage); 242 if (!NT_SUCCESS(Status)) 243 { 244 /* We failed */ 245 BaseSetLastNTError(Status); 246 return FALSE; 247 } 248 249 /* FIXME: Summary == Usage?! */ 250 RtlCopyMemory(Summary, &Usage, sizeof(Usage)); 251 return TRUE; 252 } 253 254 /* 255 * @implemented 256 */ 257 BOOL 258 WINAPI 259 HeapUsage(HANDLE hHeap, 260 DWORD dwFlags, 261 DWORD Unknown, 262 DWORD Unknown2, 263 IN PVOID Usage) 264 { 265 NTSTATUS Status; 266 267 /* Call RTL. Gone in Vista, so commented out */ 268 Status = STATUS_NOT_IMPLEMENTED; //RtlUsageHeap(hHeap, dwFlags, &Usage); 269 if (!NT_SUCCESS(Status)) 270 { 271 /* We failed */ 272 BaseSetLastNTError(Status); 273 return FALSE; 274 } 275 else if (Status == STATUS_MORE_ENTRIES) 276 { 277 /* There are still more entries to parse */ 278 return TRUE; 279 } 280 281 /* Otherwise, we're completely done, so we return FALSE, but NO_ERROR */ 282 SetLastError(NO_ERROR); 283 return FALSE; 284 } 285 286 /* 287 * @implemented 288 */ 289 BOOL 290 WINAPI 291 HeapWalk(HANDLE hHeap, 292 LPPROCESS_HEAP_ENTRY lpEntry) 293 { 294 NTSTATUS Status; 295 296 DPRINT1("Warning, HeapWalk is calling RtlWalkHeap with Win32 parameters\n"); 297 298 Status = RtlWalkHeap(hHeap, lpEntry); 299 300 if (!NT_SUCCESS(Status)) 301 { 302 SetLastError(RtlNtStatusToDosError(Status)); 303 return FALSE; 304 } 305 306 return TRUE; 307 } 308 309 /* 310 * @implemented 311 */ 312 BOOL 313 WINAPI 314 HeapQueryInformation(HANDLE HeapHandle, 315 HEAP_INFORMATION_CLASS HeapInformationClass, 316 PVOID HeapInformation OPTIONAL, 317 SIZE_T HeapInformationLength OPTIONAL, 318 PSIZE_T ReturnLength OPTIONAL) 319 { 320 NTSTATUS Status; 321 322 Status = RtlQueryHeapInformation(HeapHandle, 323 HeapInformationClass, 324 HeapInformation, 325 HeapInformationLength, 326 ReturnLength); 327 328 if (!NT_SUCCESS(Status)) 329 { 330 BaseSetLastNTError(Status); 331 return FALSE; 332 } 333 334 return TRUE; 335 } 336 337 /* 338 * @implemented 339 */ 340 BOOL 341 WINAPI 342 HeapSetInformation(HANDLE HeapHandle, 343 HEAP_INFORMATION_CLASS HeapInformationClass, 344 PVOID HeapInformation OPTIONAL, 345 SIZE_T HeapInformationLength OPTIONAL) 346 { 347 NTSTATUS Status; 348 349 Status = RtlSetHeapInformation(HeapHandle, 350 HeapInformationClass, 351 HeapInformation, 352 HeapInformationLength); 353 354 if (!NT_SUCCESS(Status)) 355 { 356 BaseSetLastNTError(Status); 357 return FALSE; 358 } 359 360 return TRUE; 361 } 362 363 /* 364 * @implemented 365 */ 366 HGLOBAL 367 NTAPI 368 GlobalAlloc(UINT uFlags, 369 SIZE_T dwBytes) 370 { 371 ULONG Flags = 0; 372 PVOID Ptr = NULL; 373 HANDLE hMemory; 374 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 375 BASE_TRACE_ALLOC(dwBytes, uFlags); 376 ASSERT(BaseHeap); 377 378 /* Make sure the flags are valid */ 379 if (uFlags & ~GMEM_VALID_FLAGS) 380 { 381 /* They aren't, fail */ 382 BASE_TRACE_FAILURE(); 383 SetLastError(ERROR_INVALID_PARAMETER); 384 return NULL; 385 } 386 387 /* Convert ZEROINIT */ 388 if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY; 389 390 /* Check if we're not movable, which means pointer-based heap */ 391 if (!(uFlags & GMEM_MOVEABLE)) 392 { 393 /* Check if this is DDESHARE (deprecated) */ 394 if (uFlags & GMEM_DDESHARE) Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE; 395 396 /* Allocate heap for it */ 397 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes ? dwBytes : 1); 398 if (!Ptr) SetLastError(ERROR_NOT_ENOUGH_MEMORY); 399 BASE_TRACE_ALLOC2(Ptr); 400 return Ptr; 401 } 402 403 /* This is heap based, so lock it in first */ 404 RtlLockHeap(BaseHeap); 405 406 /* 407 * Disable locking, enable custom flags, and write the 408 * movable flag (deprecated) 409 */ 410 Flags |= HEAP_NO_SERIALIZE | 411 HEAP_SETTABLE_USER_VALUE | 412 BASE_HEAP_FLAG_MOVABLE; 413 414 /* Allocate the handle */ 415 HandleEntry = BaseHeapAllocEntry(); 416 if (!HandleEntry) 417 { 418 /* Fail */ 419 hMemory = NULL; 420 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 421 BASE_TRACE_FAILURE(); 422 } 423 else 424 { 425 /* Get the object and make sure we have size */ 426 hMemory = &HandleEntry->Object; 427 if (dwBytes) 428 { 429 /* Allocate the actual memory for it */ 430 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes); 431 BASE_TRACE_PTR(HandleEntry, Ptr); 432 if (!Ptr) 433 { 434 /* We failed, manually set the allocate flag and free the handle */ 435 HandleEntry->Flags = RTL_HANDLE_VALID; 436 BaseHeapFreeEntry(HandleEntry); 437 438 /* For the cleanup case */ 439 HandleEntry = NULL; 440 } 441 else 442 { 443 /* All worked well, save our heap entry */ 444 RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory); 445 } 446 } 447 } 448 449 /* Cleanup! First unlock the heap */ 450 RtlUnlockHeap(BaseHeap); 451 452 /* Check if a handle was allocated */ 453 if (HandleEntry) 454 { 455 /* Set the pointer and allocated flag */ 456 HandleEntry->Object = Ptr; 457 HandleEntry->Flags = RTL_HANDLE_VALID; 458 if (!Ptr) 459 { 460 /* We don't have a valid pointer, but so reuse this handle */ 461 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE; 462 } 463 464 /* Check if the handle is discardable */ 465 if (uFlags & GMEM_DISCARDABLE) 466 { 467 /* Save it in the handle entry */ 468 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE; 469 } 470 471 /* Check if the handle is moveable */ 472 if (uFlags & GMEM_MOVEABLE) 473 { 474 /* Save it in the handle entry */ 475 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE; 476 } 477 478 /* Check if the handle is DDE Shared */ 479 if (uFlags & GMEM_DDESHARE) 480 { 481 /* Save it in the handle entry */ 482 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE; 483 } 484 485 /* Set the pointer */ 486 Ptr = hMemory; 487 } 488 489 /* Return the pointer */ 490 return Ptr; 491 } 492 493 /* 494 * @implemented 495 */ 496 SIZE_T 497 NTAPI 498 GlobalCompact(DWORD dwMinFree) 499 { 500 /* Call the RTL Heap Manager */ 501 return RtlCompactHeap(BaseHeap, 0); 502 } 503 504 /* 505 * @implemented 506 */ 507 VOID 508 NTAPI 509 GlobalFix(HGLOBAL hMem) 510 { 511 /* Lock the memory if it the handle is valid */ 512 if (INVALID_HANDLE_VALUE != hMem) GlobalLock(hMem); 513 } 514 515 /* 516 * @implemented 517 */ 518 UINT 519 NTAPI 520 GlobalFlags(HGLOBAL hMem) 521 { 522 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 523 HANDLE Handle = NULL; 524 ULONG Flags = 0; 525 UINT uFlags = GMEM_INVALID_HANDLE; 526 527 /* Start by locking the heap */ 528 RtlLockHeap(BaseHeap); 529 _SEH2_TRY 530 { 531 /* Check if this is a simple RTL Heap Managed block */ 532 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 533 { 534 /* Then we'll query RTL Heap */ 535 RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags); 536 BASE_TRACE_PTR(Handle, hMem); 537 538 /* 539 * Check if RTL Heap didn't find a handle associated with us or 540 * said that this heap isn't movable, which means something we're 541 * really not a handle-based heap. 542 */ 543 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE)) 544 { 545 /* Then set the flags to 0 */ 546 uFlags = 0; 547 } 548 else 549 { 550 /* Otherwise we're handle-based, so get the internal handle */ 551 hMem = Handle; 552 } 553 } 554 555 /* Check if the handle is actually an entry in our table */ 556 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY) 557 { 558 /* Then get the entry */ 559 HandleEntry = BaseHeapGetEntry(hMem); 560 BASE_TRACE_HANDLE(HandleEntry, hMem); 561 562 /* Make sure it's a valid handle */ 563 if (BaseHeapValidateEntry(HandleEntry)) 564 { 565 /* Get the lock count first */ 566 uFlags = HandleEntry->LockCount & GMEM_LOCKCOUNT; 567 568 /* Now check if it's discardable */ 569 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE) 570 { 571 /* Set the Win32 Flag */ 572 uFlags |= GMEM_DISCARDABLE; 573 } 574 575 /* Check if it's DDE Shared */ 576 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_DDESHARE) 577 { 578 /* Set the Win32 Flag */ 579 uFlags |= GMEM_DDESHARE; 580 } 581 582 /* Now check if it's discarded */ 583 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE) 584 { 585 /* Set the Win32 Flag */ 586 uFlags |= GMEM_DISCARDED; 587 } 588 } 589 } 590 591 /* Check if by now, we still haven't gotten any useful flags */ 592 if (uFlags == GMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE); 593 } 594 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 595 { 596 /* Set the exception code */ 597 BaseSetLastNTError(_SEH2_GetExceptionCode()); 598 } 599 _SEH2_END; 600 601 /* All done! Unlock heap and return Win32 Flags */ 602 RtlUnlockHeap(BaseHeap); 603 return uFlags; 604 } 605 606 /* 607 * @implemented 608 */ 609 HGLOBAL 610 NTAPI 611 GlobalFree(HGLOBAL hMem) 612 { 613 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 614 LPVOID Ptr; 615 BASE_TRACE_DEALLOC(hMem); 616 617 /* Check if this was a simple allocated heap entry */ 618 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 619 { 620 /* Free it with the RTL Heap Manager */ 621 if (RtlFreeHeap(BaseHeap, 0, hMem)) 622 { 623 /* Return NULL since there's no handle */ 624 return NULL; 625 } 626 else 627 { 628 /* Otherwise fail */ 629 BASE_TRACE_FAILURE(); 630 SetLastError(ERROR_INVALID_HANDLE); 631 return hMem; 632 } 633 } 634 635 /* It's a handle probably, so lock the heap */ 636 RtlLockHeap(BaseHeap); 637 _SEH2_TRY 638 { 639 /* Make sure that this is an entry in our handle database */ 640 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY) 641 { 642 /* Get the entry */ 643 HandleEntry = BaseHeapGetEntry(hMem); 644 BASE_TRACE_HANDLE(HandleEntry, hMem); 645 646 /* Make sure the handle is valid */ 647 if (!BaseHeapValidateEntry(HandleEntry)) 648 { 649 /* It's not, fail */ 650 SetLastError(ERROR_INVALID_HANDLE); 651 Ptr = NULL; 652 } 653 else 654 { 655 /* It's valid, so get the pointer */ 656 Ptr = HandleEntry->Object; 657 658 /* Free this handle */ 659 BaseHeapFreeEntry(HandleEntry); 660 661 /* If the pointer is 0, then we don't have a handle either */ 662 if (!Ptr) hMem = NULL; 663 } 664 } 665 else 666 { 667 /* Otherwise, reuse the handle as a pointer */ 668 BASE_TRACE_FAILURE(); 669 Ptr = hMem; 670 } 671 672 /* Check if we got here with a valid heap pointer */ 673 if (Ptr) 674 { 675 /* Free it with the RTL Heap Manager */ 676 if (RtlFreeHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr)) 677 { 678 /* Everything worked */ 679 hMem = NULL; 680 } 681 else 682 { 683 /* This wasn't a real heap handle */ 684 SetLastError(ERROR_INVALID_HANDLE); 685 } 686 } 687 } 688 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 689 { 690 /* Set the exception code */ 691 BaseSetLastNTError(_SEH2_GetExceptionCode()); 692 } 693 _SEH2_END; 694 695 /* We're done, so unlock the heap and return the handle */ 696 RtlUnlockHeap(BaseHeap); 697 return hMem; 698 } 699 700 /* 701 * @implemented 702 */ 703 HGLOBAL 704 NTAPI 705 GlobalHandle(LPCVOID pMem) 706 { 707 HANDLE Handle = NULL; 708 ULONG Flags; 709 710 /* Lock the heap */ 711 RtlLockHeap(BaseHeap); 712 _SEH2_TRY 713 { 714 /* Query RTL Heap */ 715 if (!RtlGetUserInfoHeap(BaseHeap, 716 HEAP_NO_SERIALIZE, 717 (PVOID)pMem, 718 &Handle, 719 &Flags)) 720 { 721 /* RTL Heap Manager does not know about this heap */ 722 SetLastError(ERROR_INVALID_HANDLE); 723 } 724 else 725 { 726 /* 727 * Check if RTL Heap didn't find a handle for us or said that 728 * this heap isn't movable. 729 */ 730 BASE_TRACE_PTR(Handle, pMem); 731 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE)) 732 { 733 /* We're actually handle-based, so the pointer is a handle */ 734 Handle = (HANDLE)pMem; 735 } 736 } 737 } 738 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 739 { 740 /* Set the exception code */ 741 BaseSetLastNTError(_SEH2_GetExceptionCode()); 742 } 743 _SEH2_END; 744 745 /* All done, unlock the heap and return the handle */ 746 RtlUnlockHeap(BaseHeap); 747 return Handle; 748 } 749 750 /* 751 * @implemented 752 */ 753 LPVOID 754 NTAPI 755 GlobalLock(HGLOBAL hMem) 756 { 757 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 758 LPVOID Ptr; 759 760 /* Check if this was a simple allocated heap entry */ 761 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 762 { 763 /* Make sure it's not a kernel or invalid address */ 764 if ((hMem >= (HGLOBAL)SystemRangeStart) || (IsBadReadPtr(hMem, 1))) 765 { 766 /* Signal an error */ 767 SetLastError(ERROR_INVALID_HANDLE); 768 return NULL; 769 } 770 771 /* It's all good */ 772 return hMem; 773 } 774 775 /* Otherwise, lock the heap */ 776 RtlLockHeap(BaseHeap); 777 _SEH2_TRY 778 { 779 /* Get the handle entry */ 780 HandleEntry = BaseHeapGetEntry(hMem); 781 BASE_TRACE_HANDLE(HandleEntry, hMem); 782 783 /* Make sure it's valid */ 784 if (!BaseHeapValidateEntry(HandleEntry)) 785 { 786 /* It's not, fail */ 787 BASE_TRACE_FAILURE(); 788 SetLastError(ERROR_INVALID_HANDLE); 789 Ptr = NULL; 790 } 791 else 792 { 793 /* Otherwise, get the pointer */ 794 Ptr = HandleEntry->Object; 795 if (Ptr) 796 { 797 /* Increase the lock count, unless we've went too far */ 798 if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT) 799 { 800 /* In which case we simply unlock once */ 801 HandleEntry->LockCount--; 802 } 803 } 804 else 805 { 806 /* The handle is still there but the memory was already freed */ 807 SetLastError(ERROR_DISCARDED); 808 } 809 } 810 } 811 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 812 { 813 SetLastError(ERROR_INVALID_HANDLE); 814 Ptr = NULL; 815 } 816 _SEH2_END; 817 818 /* All done. Unlock the heap and return the pointer */ 819 RtlUnlockHeap(BaseHeap); 820 return Ptr; 821 } 822 823 HGLOBAL 824 NTAPI 825 GlobalReAlloc(HGLOBAL hMem, 826 SIZE_T dwBytes, 827 UINT uFlags) 828 { 829 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 830 HANDLE Handle; 831 LPVOID Ptr; 832 ULONG Flags = 0; 833 834 /* Throw out invalid flags */ 835 if (uFlags & ~(GMEM_VALID_FLAGS | GMEM_MODIFY)) 836 { 837 SetLastError(ERROR_INVALID_PARAMETER); 838 return NULL; 839 } 840 841 /* Throw out invalid combo */ 842 if ((uFlags & GMEM_DISCARDABLE) && !(uFlags & GMEM_MODIFY)) 843 { 844 SetLastError(ERROR_INVALID_PARAMETER); 845 return NULL; 846 } 847 848 /* Convert ZEROINIT */ 849 if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY; 850 851 /* If this wasn't a movable heap, then we MUST re-alloc in place */ 852 if (!(uFlags & GMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY; 853 854 /* Lock the heap and disable built-in locking in the RTL Heap functions */ 855 RtlLockHeap(BaseHeap); 856 Flags |= HEAP_NO_SERIALIZE; 857 858 /* Check if this is a simple handle-based block */ 859 if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 860 { 861 /* Get the entry */ 862 HandleEntry = BaseHeapGetEntry(hMem); 863 BASE_TRACE_HANDLE(HandleEntry, hMem); 864 865 /* Make sure the handle is valid */ 866 if (!BaseHeapValidateEntry(HandleEntry)) 867 { 868 /* Fail */ 869 BASE_TRACE_FAILURE(); 870 SetLastError(ERROR_INVALID_HANDLE); 871 hMem = NULL; 872 } 873 else if (uFlags & GMEM_MODIFY) 874 { 875 /* User is changing flags... check if the memory was discardable */ 876 if (uFlags & GMEM_DISCARDABLE) 877 { 878 /* Then set the flag */ 879 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE; 880 } 881 else 882 { 883 /* Otherwise, remove the flag */ 884 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE; 885 } 886 } 887 else 888 { 889 /* Otherwise, get the object and check if we have no size */ 890 Ptr = HandleEntry->Object; 891 if (!dwBytes) 892 { 893 /* Clear the handle and check for a pointer */ 894 hMem = NULL; 895 if (Ptr) 896 { 897 /* Make sure the handle isn't locked */ 898 if ((uFlags & GMEM_MOVEABLE) && !(HandleEntry->LockCount)) 899 { 900 /* Free the current heap */ 901 if (RtlFreeHeap(BaseHeap, Flags, Ptr)) 902 { 903 /* Free the handle */ 904 HandleEntry->Object = NULL; 905 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE; 906 907 /* Get the object pointer */ 908 hMem = &HandleEntry->Object; 909 } 910 } 911 } 912 else 913 { 914 /* Otherwise just return the object pointer */ 915 hMem = &HandleEntry->Object; 916 } 917 } 918 else 919 { 920 /* Otherwise, we're allocating, so set the new flags needed */ 921 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE; 922 if (!Ptr) 923 { 924 /* We don't have a base, so allocate one */ 925 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes); 926 BASE_TRACE_ALLOC2(Ptr); 927 if (Ptr) 928 { 929 /* Allocation succeeded, so save our entry */ 930 RtlSetUserValueHeap(BaseHeap, 931 HEAP_NO_SERIALIZE, 932 Ptr, 933 hMem); 934 } 935 } 936 else 937 { 938 /* 939 * If it's not movable or currently locked, we MUST allocate 940 * in-place! 941 */ 942 if (!(uFlags & GMEM_MOVEABLE) && (HandleEntry->LockCount)) 943 { 944 /* Set the flag */ 945 Flags |= HEAP_REALLOC_IN_PLACE_ONLY; 946 } 947 else 948 { 949 /* Otherwise clear the flag if we set it previously */ 950 Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY; 951 } 952 953 /* Do the re-allocation. No need to save the entry again */ 954 Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes); 955 } 956 957 /* Make sure we have a pointer by now */ 958 if (Ptr) 959 { 960 /* Write it in the handle entry and mark it in use */ 961 HandleEntry->Object = Ptr; 962 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE; 963 } 964 else 965 { 966 /* Otherwise we failed */ 967 hMem = NULL; 968 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 969 } 970 } 971 } 972 } 973 else if (uFlags & GMEM_MODIFY) 974 { 975 /* This is not a handle-based heap and the caller wants it to be one */ 976 if (uFlags & GMEM_MOVEABLE) 977 { 978 /* Get information on its current state */ 979 Handle = hMem; 980 if (RtlGetUserInfoHeap(BaseHeap, 981 HEAP_NO_SERIALIZE, 982 hMem, 983 &Handle, 984 NULL)) 985 { 986 /* 987 * Check if the handle matches the pointer or the moveable flag 988 * isn't there, which is what we expect since it currently isn't. 989 */ 990 if ((Handle == hMem) || !(Flags & BASE_HEAP_FLAG_MOVABLE)) 991 { 992 /* Allocate a handle for it */ 993 HandleEntry = BaseHeapAllocEntry(); 994 if (!HandleEntry) 995 { 996 /* No entry could be allocated */ 997 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 998 RtlUnlockHeap(BaseHeap); 999 return NULL; 1000 } 1001 1002 /* Calculate the size of the current heap */ 1003 dwBytes = RtlSizeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem); 1004 1005 /* Set the movable flag */ 1006 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE; 1007 1008 /* Now allocate the actual heap for it */ 1009 HandleEntry->Object = RtlAllocateHeap(BaseHeap, 1010 Flags, 1011 dwBytes); 1012 BASE_TRACE_PTR(HandleEntry->Object, HandleEntry); 1013 if (!HandleEntry->Object) 1014 { 1015 /* 1016 * We failed, manually set the allocate flag and 1017 * free the handle 1018 */ 1019 HandleEntry->Flags = RTL_HANDLE_VALID; 1020 BaseHeapFreeEntry(HandleEntry); 1021 1022 /* For the cleanup case */ 1023 BASE_TRACE_FAILURE(); 1024 HandleEntry = NULL; 1025 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1026 } 1027 else 1028 { 1029 /* Otherwise, copy the new heap and free the old one */ 1030 RtlMoveMemory(HandleEntry->Object, hMem, dwBytes); 1031 RtlFreeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem); 1032 1033 /* Select the heap pointer */ 1034 hMem = (HANDLE)&HandleEntry->Object; 1035 1036 /* Initialize the count and default flags */ 1037 HandleEntry->LockCount = 0; 1038 HandleEntry->Flags = RTL_HANDLE_VALID | 1039 BASE_HEAP_ENTRY_FLAG_MOVABLE; 1040 1041 /* Check if it's also discardable */ 1042 if (uFlags & GMEM_DISCARDABLE) 1043 { 1044 /* Set the internal flag */ 1045 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE; 1046 } 1047 1048 /* Check if it's also DDE Shared */ 1049 if (uFlags & GMEM_DDESHARE) 1050 { 1051 /* Set the internal flag */ 1052 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE; 1053 } 1054 1055 /* Allocation succeeded, so save our entry */ 1056 RtlSetUserValueHeap(BaseHeap, 1057 HEAP_NO_SERIALIZE, 1058 HandleEntry->Object, 1059 hMem); 1060 } 1061 } 1062 } 1063 } 1064 } 1065 else 1066 { 1067 /* Otherwise, this is a simple RTL Managed Heap, so just call it */ 1068 hMem = RtlReAllocateHeap(BaseHeap, 1069 Flags | HEAP_NO_SERIALIZE, 1070 hMem, 1071 dwBytes); 1072 if (!hMem) 1073 { 1074 /* Fail */ 1075 BASE_TRACE_FAILURE(); 1076 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1077 } 1078 } 1079 1080 /* All done, unlock the heap and return the pointer */ 1081 RtlUnlockHeap(BaseHeap); 1082 return hMem; 1083 } 1084 1085 /* 1086 * @implemented 1087 */ 1088 SIZE_T 1089 NTAPI 1090 GlobalSize(HGLOBAL hMem) 1091 { 1092 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1093 PVOID Handle = NULL; 1094 ULONG Flags = 0; 1095 SIZE_T dwSize = MAXULONG_PTR; 1096 1097 /* Lock the heap */ 1098 RtlLockHeap(BaseHeap); 1099 _SEH2_TRY 1100 { 1101 /* Check if this is a simple RTL Heap Managed block */ 1102 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 1103 { 1104 /* Then we'll query RTL Heap */ 1105 if (RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags)) 1106 { 1107 BASE_TRACE_PTR(Handle, hMem); 1108 /* 1109 * Check if RTL Heap didn't give us a handle or said that this 1110 * heap isn't movable. 1111 */ 1112 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE)) 1113 { 1114 /* We're not a handle heap, so use the generic call */ 1115 dwSize = RtlSizeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem); 1116 } 1117 else 1118 { 1119 /* We're a handle heap so get the internal handle */ 1120 hMem = Handle; 1121 } 1122 } 1123 } 1124 1125 /* Make sure that this is an entry in our handle database */ 1126 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY) 1127 { 1128 /* Get the entry */ 1129 HandleEntry = BaseHeapGetEntry(hMem); 1130 BASE_TRACE_HANDLE(HandleEntry, hMem); 1131 1132 /* Make sure the handle is valid */ 1133 if (!BaseHeapValidateEntry(HandleEntry)) 1134 { 1135 /* Fail */ 1136 BASE_TRACE_FAILURE(); 1137 SetLastError(ERROR_INVALID_HANDLE); 1138 } 1139 else if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE) 1140 { 1141 /* We've reused this block, but we've saved the size for you */ 1142 dwSize = HandleEntry->OldSize; 1143 } 1144 else 1145 { 1146 /* Otherwise, query RTL about it */ 1147 dwSize = RtlSizeHeap(BaseHeap, 1148 HEAP_NO_SERIALIZE, 1149 HandleEntry->Object); 1150 } 1151 } 1152 } 1153 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1154 { 1155 /* Set failure for later */ 1156 dwSize = MAXULONG_PTR; 1157 } 1158 _SEH2_END; 1159 1160 /* Check if by now, we still haven't gotten any useful size */ 1161 if (dwSize == MAXULONG_PTR) 1162 { 1163 /* Fail */ 1164 BASE_TRACE_FAILURE(); 1165 SetLastError(ERROR_INVALID_HANDLE); 1166 dwSize = 0; 1167 } 1168 1169 /* All done! Unlock heap and return the size */ 1170 RtlUnlockHeap(BaseHeap); 1171 return dwSize; 1172 } 1173 1174 /* 1175 * @implemented 1176 */ 1177 VOID 1178 NTAPI 1179 GlobalUnfix(HGLOBAL hMem) 1180 { 1181 /* If the handle is valid, unlock it */ 1182 if (hMem != INVALID_HANDLE_VALUE) GlobalUnlock(hMem); 1183 } 1184 1185 /* 1186 * @implemented 1187 */ 1188 BOOL 1189 NTAPI 1190 GlobalUnlock(HGLOBAL hMem) 1191 { 1192 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1193 BOOL RetVal = TRUE; 1194 1195 /* Check if this was a simple allocated heap entry */ 1196 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) return RetVal; 1197 1198 /* Otherwise, lock the heap */ 1199 RtlLockHeap(BaseHeap); 1200 1201 /* Get the handle entry */ 1202 HandleEntry = BaseHeapGetEntry(hMem); 1203 BASE_TRACE_HANDLE(HandleEntry, hMem); 1204 1205 _SEH2_TRY 1206 { 1207 /* Make sure it's valid */ 1208 if (!BaseHeapValidateEntry(HandleEntry)) 1209 { 1210 /* It's not, fail */ 1211 BASE_TRACE_FAILURE(); 1212 SetLastError(ERROR_INVALID_HANDLE); 1213 RetVal = FALSE; 1214 } 1215 else 1216 { 1217 /* Otherwise, decrement lock count, unless we're already at 0*/ 1218 if (!HandleEntry->LockCount--) 1219 { 1220 /* In which case we simply lock it back and fail */ 1221 HandleEntry->LockCount++; 1222 SetLastError(ERROR_NOT_LOCKED); 1223 RetVal = FALSE; 1224 } 1225 else if (!HandleEntry->LockCount) 1226 { 1227 /* Nothing to unlock */ 1228 SetLastError(NO_ERROR); 1229 RetVal = FALSE; 1230 } 1231 } 1232 } 1233 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1234 { 1235 SetLastError(ERROR_INVALID_PARAMETER); 1236 RetVal = FALSE; 1237 } 1238 _SEH2_END; 1239 1240 /* All done. Unlock the heap and return the pointer */ 1241 RtlUnlockHeap(BaseHeap); 1242 return RetVal; 1243 } 1244 1245 /* 1246 * @implemented 1247 */ 1248 BOOL 1249 NTAPI 1250 GlobalUnWire(HGLOBAL hMem) 1251 { 1252 /* This is simply an unlock */ 1253 return GlobalUnlock(hMem); 1254 } 1255 1256 /* 1257 * @implemented 1258 */ 1259 LPVOID 1260 NTAPI 1261 GlobalWire(HGLOBAL hMem) 1262 { 1263 /* This is just a lock */ 1264 return GlobalLock(hMem); 1265 } 1266 1267 /* 1268 * @implemented 1269 */ 1270 BOOL 1271 NTAPI 1272 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer) 1273 { 1274 SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo; 1275 VM_COUNTERS VmCounters; 1276 QUOTA_LIMITS QuotaLimits; 1277 ULONGLONG PageFile, PhysicalMemory; 1278 1279 if (lpBuffer->dwLength != sizeof(*lpBuffer)) 1280 { 1281 SetLastError(ERROR_INVALID_PARAMETER); 1282 return FALSE; 1283 } 1284 1285 /* Query performance information */ 1286 NtQuerySystemInformation(SystemPerformanceInformation, 1287 &PerformanceInfo, 1288 sizeof(PerformanceInfo), 1289 NULL); 1290 1291 /* Calculate memory load */ 1292 lpBuffer->dwMemoryLoad = ((DWORD)(BaseStaticServerData->SysInfo.NumberOfPhysicalPages - 1293 PerformanceInfo.AvailablePages) * 100) / 1294 BaseStaticServerData->SysInfo.NumberOfPhysicalPages; 1295 1296 /* Save physical memory */ 1297 PhysicalMemory = BaseStaticServerData->SysInfo.NumberOfPhysicalPages * 1298 BaseStaticServerData->SysInfo.PageSize; 1299 lpBuffer->ullTotalPhys = PhysicalMemory; 1300 1301 /* Now save available physical memory */ 1302 PhysicalMemory = PerformanceInfo.AvailablePages * 1303 BaseStaticServerData->SysInfo.PageSize; 1304 lpBuffer->ullAvailPhys = PhysicalMemory; 1305 1306 /* Query VM and Quota Limits */ 1307 NtQueryInformationProcess(NtCurrentProcess(), 1308 ProcessQuotaLimits, 1309 &QuotaLimits, 1310 sizeof(QUOTA_LIMITS), 1311 NULL); 1312 NtQueryInformationProcess(NtCurrentProcess(), 1313 ProcessVmCounters, 1314 &VmCounters, 1315 sizeof(VM_COUNTERS), 1316 NULL); 1317 1318 /* Save the commit limit */ 1319 lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit, 1320 PerformanceInfo.CommitLimit); 1321 lpBuffer->ullTotalPageFile *= BaseStaticServerData->SysInfo.PageSize; 1322 1323 /* Calculate how many pages are left */ 1324 PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages; 1325 1326 /* Save the total */ 1327 lpBuffer->ullAvailPageFile = min(PageFile, 1328 QuotaLimits.PagefileLimit - 1329 VmCounters.PagefileUsage); 1330 lpBuffer->ullAvailPageFile *= BaseStaticServerData->SysInfo.PageSize; 1331 1332 /* Now calculate the total virtual space */ 1333 lpBuffer->ullTotalVirtual = (BaseStaticServerData->SysInfo.MaximumUserModeAddress - 1334 BaseStaticServerData->SysInfo.MinimumUserModeAddress) + 1; 1335 1336 /* And finally the available virtual space */ 1337 lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual - VmCounters.VirtualSize; 1338 lpBuffer->ullAvailExtendedVirtual = 0; 1339 1340 return TRUE; 1341 } 1342 1343 /* 1344 * @implemented 1345 */ 1346 VOID 1347 NTAPI 1348 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer) 1349 { 1350 MEMORYSTATUSEX lpBufferEx; 1351 1352 /* Call the extended function */ 1353 lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX); 1354 if (GlobalMemoryStatusEx(&lpBufferEx)) 1355 { 1356 /* Reset the right size and fill out the information */ 1357 lpBuffer->dwLength = sizeof(MEMORYSTATUS); 1358 lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad; 1359 lpBuffer->dwTotalPhys = (SIZE_T)min(lpBufferEx.ullTotalPhys, MAXULONG_PTR); 1360 lpBuffer->dwAvailPhys = (SIZE_T)min(lpBufferEx.ullAvailPhys, MAXULONG_PTR); 1361 lpBuffer->dwTotalPageFile = (SIZE_T)min(lpBufferEx.ullTotalPageFile, MAXULONG_PTR); 1362 lpBuffer->dwAvailPageFile = (SIZE_T)min(lpBufferEx.ullAvailPageFile, MAXULONG_PTR); 1363 lpBuffer->dwTotalVirtual = (SIZE_T)min(lpBufferEx.ullTotalVirtual, MAXULONG_PTR); 1364 lpBuffer->dwAvailVirtual = (SIZE_T)min(lpBufferEx.ullAvailVirtual, MAXULONG_PTR); 1365 } 1366 } 1367 1368 /* 1369 * @implemented 1370 */ 1371 HLOCAL 1372 NTAPI 1373 LocalAlloc(UINT uFlags, 1374 SIZE_T dwBytes) 1375 { 1376 ULONG Flags = 0; 1377 PVOID Ptr = NULL; 1378 HANDLE hMemory; 1379 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1380 BASE_TRACE_ALLOC(dwBytes, uFlags); 1381 ASSERT(BaseHeap); 1382 1383 /* Make sure the flags are valid */ 1384 if (uFlags & ~LMEM_VALID_FLAGS) 1385 { 1386 /* They aren't, fail */ 1387 BASE_TRACE_FAILURE(); 1388 SetLastError(ERROR_INVALID_PARAMETER); 1389 return NULL; 1390 } 1391 1392 /* Convert ZEROINIT */ 1393 if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY; 1394 1395 /* Check if we're not movable, which means pointer-based heap */ 1396 if (!(uFlags & LMEM_MOVEABLE)) 1397 { 1398 /* Allocate heap for it */ 1399 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes); 1400 BASE_TRACE_ALLOC2(Ptr); 1401 return Ptr; 1402 } 1403 1404 /* This is heap based, so lock it in first */ 1405 RtlLockHeap(BaseHeap); 1406 1407 /* 1408 * Disable locking, enable custom flags, and write the 1409 * movable flag (deprecated) 1410 */ 1411 Flags |= HEAP_NO_SERIALIZE | 1412 HEAP_SETTABLE_USER_VALUE | 1413 BASE_HEAP_FLAG_MOVABLE; 1414 1415 /* Allocate the handle */ 1416 HandleEntry = BaseHeapAllocEntry(); 1417 if (!HandleEntry) 1418 { 1419 /* Fail */ 1420 hMemory = NULL; 1421 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1422 BASE_TRACE_FAILURE(); 1423 goto Quickie; 1424 } 1425 1426 /* Get the object and make sure we have size */ 1427 hMemory = &HandleEntry->Object; 1428 if (dwBytes) 1429 { 1430 /* Allocate the actual memory for it */ 1431 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes); 1432 BASE_TRACE_PTR(HandleEntry, Ptr); 1433 if (!Ptr) 1434 { 1435 /* We failed, manually set the allocate flag and free the handle */ 1436 HandleEntry->Flags = RTL_HANDLE_VALID; 1437 BaseHeapFreeEntry(HandleEntry); 1438 1439 /* For the cleanup case */ 1440 HandleEntry = NULL; 1441 } 1442 else 1443 { 1444 /* All worked well, save our heap entry */ 1445 RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory); 1446 } 1447 } 1448 1449 Quickie: 1450 /* Cleanup! First unlock the heap */ 1451 RtlUnlockHeap(BaseHeap); 1452 1453 /* Check if a handle was allocated */ 1454 if (HandleEntry) 1455 { 1456 /* Set the pointer and allocated flag */ 1457 HandleEntry->Object = Ptr; 1458 HandleEntry->Flags = RTL_HANDLE_VALID; 1459 if (!Ptr) 1460 { 1461 /* We don't have a valid pointer, but so reuse this handle */ 1462 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE; 1463 } 1464 1465 /* Check if the handle is discardable */ 1466 if (uFlags & GMEM_DISCARDABLE) 1467 { 1468 /* Save it in the handle entry */ 1469 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE; 1470 } 1471 1472 /* Check if the handle is moveable */ 1473 if (uFlags & GMEM_MOVEABLE) 1474 { 1475 /* Save it in the handle entry */ 1476 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE; 1477 } 1478 1479 /* Set the pointer */ 1480 Ptr = hMemory; 1481 } 1482 1483 /* Return the pointer */ 1484 return Ptr; 1485 } 1486 1487 /* 1488 * @implemented 1489 */ 1490 SIZE_T 1491 NTAPI 1492 LocalCompact(UINT dwMinFree) 1493 { 1494 /* Call the RTL Heap Manager */ 1495 return RtlCompactHeap(BaseHeap, 0); 1496 } 1497 1498 /* 1499 * @implemented 1500 */ 1501 UINT 1502 NTAPI 1503 LocalFlags(HLOCAL hMem) 1504 { 1505 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1506 HANDLE Handle = NULL; 1507 ULONG Flags = 0; 1508 UINT uFlags = LMEM_INVALID_HANDLE; 1509 1510 /* Start by locking the heap */ 1511 RtlLockHeap(BaseHeap); 1512 1513 /* Check if this is a simple RTL Heap Managed block */ 1514 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 1515 { 1516 /* Then we'll query RTL Heap */ 1517 RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags); 1518 BASE_TRACE_PTR(Handle, hMem); 1519 1520 /* 1521 * Check if RTL Heap didn't find a handle associated with us or 1522 * said that this heap isn't movable, which means something we're 1523 * really not a handle-based heap. 1524 */ 1525 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE)) 1526 { 1527 /* Then set the flags to 0 */ 1528 uFlags = 0; 1529 } 1530 else 1531 { 1532 /* Otherwise we're handle-based, so get the internal handle */ 1533 hMem = Handle; 1534 } 1535 } 1536 1537 /* Check if the handle is actually an entry in our table */ 1538 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY) 1539 { 1540 /* Then get the entry */ 1541 HandleEntry = BaseHeapGetEntry(hMem); 1542 BASE_TRACE_HANDLE(HandleEntry, hMem); 1543 1544 /* Make sure it's a valid handle */ 1545 if (BaseHeapValidateEntry(HandleEntry)) 1546 { 1547 /* Get the lock count first */ 1548 uFlags = HandleEntry->LockCount & LMEM_LOCKCOUNT; 1549 1550 /* Now check if it's discardable */ 1551 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE) 1552 { 1553 /* Set the Win32 Flag */ 1554 uFlags |= LMEM_DISCARDABLE; 1555 } 1556 1557 /* Now check if it's discarded */ 1558 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE) 1559 /* Set the Win32 Flag */ 1560 uFlags |= LMEM_DISCARDED; 1561 } 1562 } 1563 1564 /* Check if by now, we still haven't gotten any useful flags */ 1565 if (uFlags == LMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE); 1566 1567 /* All done! Unlock heap and return Win32 Flags */ 1568 RtlUnlockHeap(BaseHeap); 1569 return uFlags; 1570 } 1571 1572 /* 1573 * @implemented 1574 */ 1575 HLOCAL 1576 NTAPI 1577 LocalFree(HLOCAL hMem) 1578 { 1579 /* This is identical to a Global Free */ 1580 return GlobalFree(hMem); 1581 } 1582 1583 /* 1584 * @implemented 1585 */ 1586 HLOCAL 1587 NTAPI 1588 LocalHandle(LPCVOID pMem) 1589 { 1590 /* This is identical to a Global Handle */ 1591 return GlobalHandle(pMem); 1592 } 1593 1594 /* 1595 * @implemented 1596 */ 1597 LPVOID 1598 NTAPI 1599 LocalLock(HLOCAL hMem) 1600 { 1601 /* This is the same as a GlobalLock, assuming these never change */ 1602 C_ASSERT(LMEM_LOCKCOUNT == GMEM_LOCKCOUNT); 1603 return GlobalLock(hMem); 1604 } 1605 1606 HLOCAL 1607 NTAPI 1608 LocalReAlloc(HLOCAL hMem, 1609 SIZE_T dwBytes, 1610 UINT uFlags) 1611 { 1612 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1613 LPVOID Ptr; 1614 ULONG Flags = 0; 1615 1616 /* Convert ZEROINIT */ 1617 if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY; 1618 1619 /* If this wasn't a movable heap, then we MUST re-alloc in place */ 1620 if (!(uFlags & LMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY; 1621 1622 /* Lock the heap and disable built-in locking in the RTL Heap functions */ 1623 RtlLockHeap(BaseHeap); 1624 Flags |= HEAP_NO_SERIALIZE; 1625 1626 /* Check if this is a simple handle-based block */ 1627 if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 1628 { 1629 /* Get the entry */ 1630 HandleEntry = BaseHeapGetEntry(hMem); 1631 BASE_TRACE_HANDLE(HandleEntry, hMem); 1632 1633 /* Make sure the handle is valid */ 1634 if (!BaseHeapValidateEntry(HandleEntry)) 1635 { 1636 /* Fail */ 1637 BASE_TRACE_FAILURE(); 1638 SetLastError(ERROR_INVALID_HANDLE); 1639 hMem = NULL; 1640 } 1641 else if (uFlags & LMEM_MODIFY) 1642 { 1643 /* User is changing flags... check if the memory was discardable */ 1644 if (uFlags & LMEM_DISCARDABLE) 1645 { 1646 /* Then set the flag */ 1647 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE; 1648 } 1649 else 1650 { 1651 /* Otherwise, remove the flag */ 1652 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE; 1653 } 1654 } 1655 else 1656 { 1657 /* Otherwise, get the object and check if we have no size */ 1658 Ptr = HandleEntry->Object; 1659 if (!dwBytes) 1660 { 1661 /* Clear the handle and check for a pointer */ 1662 hMem = NULL; 1663 if (Ptr) 1664 { 1665 /* Make sure the handle isn't locked */ 1666 if ((uFlags & LMEM_MOVEABLE) && !(HandleEntry->LockCount)) 1667 { 1668 /* Free the current heap */ 1669 RtlFreeHeap(BaseHeap, Flags, Ptr); 1670 1671 /* Free the handle */ 1672 HandleEntry->Object = NULL; 1673 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE; 1674 1675 /* Get the object pointer */ 1676 hMem = &HandleEntry->Object; 1677 } 1678 } 1679 else 1680 { 1681 /* Otherwise just return the object pointer */ 1682 hMem = &HandleEntry->Object; 1683 } 1684 } 1685 else 1686 { 1687 /* Otherwise, we're allocating, so set the new flags needed */ 1688 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE; 1689 if (!Ptr) 1690 { 1691 /* We don't have a base, so allocate one */ 1692 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes); 1693 BASE_TRACE_ALLOC2(Ptr); 1694 if (Ptr) 1695 { 1696 /* Allocation succeeded, so save our entry */ 1697 RtlSetUserValueHeap(BaseHeap, 1698 HEAP_NO_SERIALIZE, 1699 Ptr, 1700 hMem); 1701 } 1702 } 1703 else 1704 { 1705 /* 1706 * If it's not movable or currently locked, we MUST allocate 1707 * in-place! 1708 */ 1709 if (!(uFlags & LMEM_MOVEABLE) && (HandleEntry->LockCount)) 1710 { 1711 /* Set the flag */ 1712 Flags |= HEAP_REALLOC_IN_PLACE_ONLY; 1713 } 1714 else 1715 { 1716 /* Otherwise clear the flag if we set it previously */ 1717 Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY; 1718 } 1719 1720 /* And do the re-allocation */ 1721 Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes); 1722 } 1723 1724 /* Make sure we have a pointer by now */ 1725 if (Ptr) 1726 { 1727 /* Write it in the handle entry and mark it in use */ 1728 HandleEntry->Object = Ptr; 1729 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE; 1730 } 1731 else 1732 { 1733 /* Otherwise we failed */ 1734 hMem = NULL; 1735 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1736 } 1737 } 1738 } 1739 } 1740 else if (!(uFlags & LMEM_MODIFY)) 1741 { 1742 /* Otherwise, this is a simple RTL Managed Heap, so just call it */ 1743 hMem = RtlReAllocateHeap(BaseHeap, 1744 Flags | HEAP_NO_SERIALIZE, 1745 hMem, 1746 dwBytes); 1747 if (!hMem) 1748 { 1749 /* Fail */ 1750 BASE_TRACE_FAILURE(); 1751 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1752 } 1753 } 1754 1755 /* All done, unlock the heap and return the pointer */ 1756 RtlUnlockHeap(BaseHeap); 1757 return hMem; 1758 } 1759 1760 /* 1761 * @implemented 1762 */ 1763 SIZE_T 1764 WINAPI 1765 LocalShrink(HLOCAL hMem, 1766 UINT cbNewSize) 1767 { 1768 /* Call RTL */ 1769 return RtlCompactHeap(BaseHeap, 0); 1770 } 1771 1772 /* 1773 * @implemented 1774 */ 1775 SIZE_T 1776 NTAPI 1777 LocalSize(HLOCAL hMem) 1778 { 1779 /* This is the same as a Global Size */ 1780 return GlobalSize(hMem); 1781 } 1782 1783 /* 1784 * @implemented 1785 */ 1786 BOOL 1787 NTAPI 1788 LocalUnlock(HLOCAL hMem) 1789 { 1790 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1791 BOOL RetVal = TRUE; 1792 1793 /* Check if this was a simple allocated heap entry */ 1794 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 1795 { 1796 /* Fail, because LocalUnlock is not supported on LMEM_FIXED allocations */ 1797 SetLastError(ERROR_NOT_LOCKED); 1798 return FALSE; 1799 } 1800 1801 /* Otherwise, lock the heap */ 1802 RtlLockHeap(BaseHeap); 1803 1804 /* Get the handle entry */ 1805 HandleEntry = BaseHeapGetEntry(hMem); 1806 BASE_TRACE_HANDLE(HandleEntry, hMem); 1807 _SEH2_TRY 1808 { 1809 /* Make sure it's valid */ 1810 if (!BaseHeapValidateEntry(HandleEntry)) 1811 { 1812 /* It's not, fail */ 1813 BASE_TRACE_FAILURE(); 1814 SetLastError(ERROR_INVALID_HANDLE); 1815 RetVal = FALSE; 1816 } 1817 else 1818 { 1819 /* Otherwise, decrement lock count, unless we're already at 0*/ 1820 if (!HandleEntry->LockCount--) 1821 { 1822 /* In which case we simply lock it back and fail */ 1823 HandleEntry->LockCount++; 1824 SetLastError(ERROR_NOT_LOCKED); 1825 RetVal = FALSE; 1826 } 1827 else if (!HandleEntry->LockCount) 1828 { 1829 /* Nothing to unlock */ 1830 SetLastError(NO_ERROR); 1831 RetVal = FALSE; 1832 } 1833 } 1834 } 1835 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1836 { 1837 SetLastError(ERROR_INVALID_PARAMETER); 1838 RetVal = FALSE; 1839 } 1840 _SEH2_END; 1841 1842 /* All done. Unlock the heap and return the pointer */ 1843 RtlUnlockHeap(BaseHeap); 1844 return RetVal; 1845 } 1846 1847 /* EOF */ 1848