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 NTSTATUS Status; 1279 1280 if (lpBuffer->dwLength != sizeof(*lpBuffer)) 1281 { 1282 SetLastError(ERROR_INVALID_PARAMETER); 1283 return FALSE; 1284 } 1285 1286 /* Query performance information */ 1287 Status = NtQuerySystemInformation(SystemPerformanceInformation, 1288 &PerformanceInfo, 1289 sizeof(PerformanceInfo), 1290 NULL); 1291 if (!NT_SUCCESS(Status)) 1292 { 1293 BaseSetLastNTError(Status); 1294 return FALSE; 1295 } 1296 1297 /* Calculate memory load */ 1298 lpBuffer->dwMemoryLoad = ((DWORD)(BaseStaticServerData->SysInfo.NumberOfPhysicalPages - 1299 PerformanceInfo.AvailablePages) * 100) / 1300 BaseStaticServerData->SysInfo.NumberOfPhysicalPages; 1301 1302 /* Save physical memory */ 1303 PhysicalMemory = BaseStaticServerData->SysInfo.NumberOfPhysicalPages * 1304 BaseStaticServerData->SysInfo.PageSize; 1305 lpBuffer->ullTotalPhys = PhysicalMemory; 1306 1307 /* Now save available physical memory */ 1308 PhysicalMemory = PerformanceInfo.AvailablePages * 1309 BaseStaticServerData->SysInfo.PageSize; 1310 lpBuffer->ullAvailPhys = PhysicalMemory; 1311 1312 /* Query VM and Quota Limits */ 1313 Status = NtQueryInformationProcess(NtCurrentProcess(), 1314 ProcessQuotaLimits, 1315 &QuotaLimits, 1316 sizeof(QUOTA_LIMITS), 1317 NULL); 1318 if (!NT_SUCCESS(Status)) 1319 { 1320 BaseSetLastNTError(Status); 1321 return FALSE; 1322 } 1323 1324 Status = NtQueryInformationProcess(NtCurrentProcess(), 1325 ProcessVmCounters, 1326 &VmCounters, 1327 sizeof(VM_COUNTERS), 1328 NULL); 1329 if (!NT_SUCCESS(Status)) 1330 { 1331 BaseSetLastNTError(Status); 1332 return FALSE; 1333 } 1334 1335 /* Save the commit limit */ 1336 lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit, 1337 PerformanceInfo.CommitLimit); 1338 lpBuffer->ullTotalPageFile *= BaseStaticServerData->SysInfo.PageSize; 1339 1340 /* Calculate how many pages are left */ 1341 PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages; 1342 1343 /* Save the total */ 1344 lpBuffer->ullAvailPageFile = min(PageFile, 1345 QuotaLimits.PagefileLimit - 1346 VmCounters.PagefileUsage); 1347 lpBuffer->ullAvailPageFile *= BaseStaticServerData->SysInfo.PageSize; 1348 1349 /* Now calculate the total virtual space */ 1350 lpBuffer->ullTotalVirtual = (BaseStaticServerData->SysInfo.MaximumUserModeAddress - 1351 BaseStaticServerData->SysInfo.MinimumUserModeAddress) + 1; 1352 1353 /* And finally the available virtual space */ 1354 lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual - VmCounters.VirtualSize; 1355 lpBuffer->ullAvailExtendedVirtual = 0; 1356 1357 return TRUE; 1358 } 1359 1360 /* 1361 * @implemented 1362 */ 1363 VOID 1364 NTAPI 1365 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer) 1366 { 1367 MEMORYSTATUSEX lpBufferEx; 1368 1369 /* Call the extended function */ 1370 lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX); 1371 if (GlobalMemoryStatusEx(&lpBufferEx)) 1372 { 1373 /* Reset the right size and fill out the information */ 1374 lpBuffer->dwLength = sizeof(MEMORYSTATUS); 1375 lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad; 1376 lpBuffer->dwTotalPhys = (SIZE_T)min(lpBufferEx.ullTotalPhys, MAXULONG_PTR); 1377 lpBuffer->dwAvailPhys = (SIZE_T)min(lpBufferEx.ullAvailPhys, MAXULONG_PTR); 1378 lpBuffer->dwTotalPageFile = (SIZE_T)min(lpBufferEx.ullTotalPageFile, MAXULONG_PTR); 1379 lpBuffer->dwAvailPageFile = (SIZE_T)min(lpBufferEx.ullAvailPageFile, MAXULONG_PTR); 1380 lpBuffer->dwTotalVirtual = (SIZE_T)min(lpBufferEx.ullTotalVirtual, MAXULONG_PTR); 1381 lpBuffer->dwAvailVirtual = (SIZE_T)min(lpBufferEx.ullAvailVirtual, MAXULONG_PTR); 1382 } 1383 } 1384 1385 /* 1386 * @implemented 1387 */ 1388 HLOCAL 1389 NTAPI 1390 LocalAlloc(UINT uFlags, 1391 SIZE_T dwBytes) 1392 { 1393 ULONG Flags = 0; 1394 PVOID Ptr = NULL; 1395 HANDLE hMemory; 1396 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1397 BASE_TRACE_ALLOC(dwBytes, uFlags); 1398 ASSERT(BaseHeap); 1399 1400 /* Make sure the flags are valid */ 1401 if (uFlags & ~LMEM_VALID_FLAGS) 1402 { 1403 /* They aren't, fail */ 1404 BASE_TRACE_FAILURE(); 1405 SetLastError(ERROR_INVALID_PARAMETER); 1406 return NULL; 1407 } 1408 1409 /* Convert ZEROINIT */ 1410 if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY; 1411 1412 /* Check if we're not movable, which means pointer-based heap */ 1413 if (!(uFlags & LMEM_MOVEABLE)) 1414 { 1415 /* Allocate heap for it */ 1416 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes); 1417 BASE_TRACE_ALLOC2(Ptr); 1418 return Ptr; 1419 } 1420 1421 /* This is heap based, so lock it in first */ 1422 RtlLockHeap(BaseHeap); 1423 1424 /* 1425 * Disable locking, enable custom flags, and write the 1426 * movable flag (deprecated) 1427 */ 1428 Flags |= HEAP_NO_SERIALIZE | 1429 HEAP_SETTABLE_USER_VALUE | 1430 BASE_HEAP_FLAG_MOVABLE; 1431 1432 /* Allocate the handle */ 1433 HandleEntry = BaseHeapAllocEntry(); 1434 if (!HandleEntry) 1435 { 1436 /* Fail */ 1437 hMemory = NULL; 1438 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1439 BASE_TRACE_FAILURE(); 1440 goto Quickie; 1441 } 1442 1443 /* Get the object and make sure we have size */ 1444 hMemory = &HandleEntry->Object; 1445 if (dwBytes) 1446 { 1447 /* Allocate the actual memory for it */ 1448 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes); 1449 BASE_TRACE_PTR(HandleEntry, Ptr); 1450 if (!Ptr) 1451 { 1452 /* We failed, manually set the allocate flag and free the handle */ 1453 HandleEntry->Flags = RTL_HANDLE_VALID; 1454 BaseHeapFreeEntry(HandleEntry); 1455 1456 /* For the cleanup case */ 1457 HandleEntry = NULL; 1458 } 1459 else 1460 { 1461 /* All worked well, save our heap entry */ 1462 RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory); 1463 } 1464 } 1465 1466 Quickie: 1467 /* Cleanup! First unlock the heap */ 1468 RtlUnlockHeap(BaseHeap); 1469 1470 /* Check if a handle was allocated */ 1471 if (HandleEntry) 1472 { 1473 /* Set the pointer and allocated flag */ 1474 HandleEntry->Object = Ptr; 1475 HandleEntry->Flags = RTL_HANDLE_VALID; 1476 if (!Ptr) 1477 { 1478 /* We don't have a valid pointer, but so reuse this handle */ 1479 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE; 1480 } 1481 1482 /* Check if the handle is discardable */ 1483 if (uFlags & GMEM_DISCARDABLE) 1484 { 1485 /* Save it in the handle entry */ 1486 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE; 1487 } 1488 1489 /* Check if the handle is moveable */ 1490 if (uFlags & GMEM_MOVEABLE) 1491 { 1492 /* Save it in the handle entry */ 1493 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE; 1494 } 1495 1496 /* Set the pointer */ 1497 Ptr = hMemory; 1498 } 1499 1500 /* Return the pointer */ 1501 return Ptr; 1502 } 1503 1504 /* 1505 * @implemented 1506 */ 1507 SIZE_T 1508 NTAPI 1509 LocalCompact(UINT dwMinFree) 1510 { 1511 /* Call the RTL Heap Manager */ 1512 return RtlCompactHeap(BaseHeap, 0); 1513 } 1514 1515 /* 1516 * @implemented 1517 */ 1518 UINT 1519 NTAPI 1520 LocalFlags(HLOCAL hMem) 1521 { 1522 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1523 HANDLE Handle = NULL; 1524 ULONG Flags = 0; 1525 UINT uFlags = LMEM_INVALID_HANDLE; 1526 1527 /* Start by locking the heap */ 1528 RtlLockHeap(BaseHeap); 1529 1530 /* Check if this is a simple RTL Heap Managed block */ 1531 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 1532 { 1533 /* Then we'll query RTL Heap */ 1534 RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags); 1535 BASE_TRACE_PTR(Handle, hMem); 1536 1537 /* 1538 * Check if RTL Heap didn't find a handle associated with us or 1539 * said that this heap isn't movable, which means something we're 1540 * really not a handle-based heap. 1541 */ 1542 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE)) 1543 { 1544 /* Then set the flags to 0 */ 1545 uFlags = 0; 1546 } 1547 else 1548 { 1549 /* Otherwise we're handle-based, so get the internal handle */ 1550 hMem = Handle; 1551 } 1552 } 1553 1554 /* Check if the handle is actually an entry in our table */ 1555 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY) 1556 { 1557 /* Then get the entry */ 1558 HandleEntry = BaseHeapGetEntry(hMem); 1559 BASE_TRACE_HANDLE(HandleEntry, hMem); 1560 1561 /* Make sure it's a valid handle */ 1562 if (BaseHeapValidateEntry(HandleEntry)) 1563 { 1564 /* Get the lock count first */ 1565 uFlags = HandleEntry->LockCount & LMEM_LOCKCOUNT; 1566 1567 /* Now check if it's discardable */ 1568 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE) 1569 { 1570 /* Set the Win32 Flag */ 1571 uFlags |= LMEM_DISCARDABLE; 1572 } 1573 1574 /* Now check if it's discarded */ 1575 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE) 1576 /* Set the Win32 Flag */ 1577 uFlags |= LMEM_DISCARDED; 1578 } 1579 } 1580 1581 /* Check if by now, we still haven't gotten any useful flags */ 1582 if (uFlags == LMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE); 1583 1584 /* All done! Unlock heap and return Win32 Flags */ 1585 RtlUnlockHeap(BaseHeap); 1586 return uFlags; 1587 } 1588 1589 /* 1590 * @implemented 1591 */ 1592 HLOCAL 1593 NTAPI 1594 LocalFree(HLOCAL hMem) 1595 { 1596 /* This is identical to a Global Free */ 1597 return GlobalFree(hMem); 1598 } 1599 1600 /* 1601 * @implemented 1602 */ 1603 HLOCAL 1604 NTAPI 1605 LocalHandle(LPCVOID pMem) 1606 { 1607 /* This is identical to a Global Handle */ 1608 return GlobalHandle(pMem); 1609 } 1610 1611 /* 1612 * @implemented 1613 */ 1614 LPVOID 1615 NTAPI 1616 LocalLock(HLOCAL hMem) 1617 { 1618 /* This is the same as a GlobalLock, assuming these never change */ 1619 C_ASSERT(LMEM_LOCKCOUNT == GMEM_LOCKCOUNT); 1620 return GlobalLock(hMem); 1621 } 1622 1623 HLOCAL 1624 NTAPI 1625 LocalReAlloc(HLOCAL hMem, 1626 SIZE_T dwBytes, 1627 UINT uFlags) 1628 { 1629 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1630 LPVOID Ptr; 1631 ULONG Flags = 0; 1632 1633 /* Convert ZEROINIT */ 1634 if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY; 1635 1636 /* If this wasn't a movable heap, then we MUST re-alloc in place */ 1637 if (!(uFlags & LMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY; 1638 1639 /* Lock the heap and disable built-in locking in the RTL Heap functions */ 1640 RtlLockHeap(BaseHeap); 1641 Flags |= HEAP_NO_SERIALIZE; 1642 1643 /* Check if this is a simple handle-based block */ 1644 if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 1645 { 1646 /* Get the entry */ 1647 HandleEntry = BaseHeapGetEntry(hMem); 1648 BASE_TRACE_HANDLE(HandleEntry, hMem); 1649 1650 /* Make sure the handle is valid */ 1651 if (!BaseHeapValidateEntry(HandleEntry)) 1652 { 1653 /* Fail */ 1654 BASE_TRACE_FAILURE(); 1655 SetLastError(ERROR_INVALID_HANDLE); 1656 hMem = NULL; 1657 } 1658 else if (uFlags & LMEM_MODIFY) 1659 { 1660 /* User is changing flags... check if the memory was discardable */ 1661 if (uFlags & LMEM_DISCARDABLE) 1662 { 1663 /* Then set the flag */ 1664 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE; 1665 } 1666 else 1667 { 1668 /* Otherwise, remove the flag */ 1669 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE; 1670 } 1671 } 1672 else 1673 { 1674 /* Otherwise, get the object and check if we have no size */ 1675 Ptr = HandleEntry->Object; 1676 if (!dwBytes) 1677 { 1678 /* Clear the handle and check for a pointer */ 1679 hMem = NULL; 1680 if (Ptr) 1681 { 1682 /* Make sure the handle isn't locked */ 1683 if ((uFlags & LMEM_MOVEABLE) && !(HandleEntry->LockCount)) 1684 { 1685 /* Free the current heap */ 1686 RtlFreeHeap(BaseHeap, Flags, Ptr); 1687 1688 /* Free the handle */ 1689 HandleEntry->Object = NULL; 1690 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE; 1691 1692 /* Get the object pointer */ 1693 hMem = &HandleEntry->Object; 1694 } 1695 } 1696 else 1697 { 1698 /* Otherwise just return the object pointer */ 1699 hMem = &HandleEntry->Object; 1700 } 1701 } 1702 else 1703 { 1704 /* Otherwise, we're allocating, so set the new flags needed */ 1705 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE; 1706 if (!Ptr) 1707 { 1708 /* We don't have a base, so allocate one */ 1709 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes); 1710 BASE_TRACE_ALLOC2(Ptr); 1711 if (Ptr) 1712 { 1713 /* Allocation succeeded, so save our entry */ 1714 RtlSetUserValueHeap(BaseHeap, 1715 HEAP_NO_SERIALIZE, 1716 Ptr, 1717 hMem); 1718 } 1719 } 1720 else 1721 { 1722 /* 1723 * If it's not movable or currently locked, we MUST allocate 1724 * in-place! 1725 */ 1726 if (!(uFlags & LMEM_MOVEABLE) && (HandleEntry->LockCount)) 1727 { 1728 /* Set the flag */ 1729 Flags |= HEAP_REALLOC_IN_PLACE_ONLY; 1730 } 1731 else 1732 { 1733 /* Otherwise clear the flag if we set it previously */ 1734 Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY; 1735 } 1736 1737 /* And do the re-allocation */ 1738 Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes); 1739 } 1740 1741 /* Make sure we have a pointer by now */ 1742 if (Ptr) 1743 { 1744 /* Write it in the handle entry and mark it in use */ 1745 HandleEntry->Object = Ptr; 1746 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE; 1747 } 1748 else 1749 { 1750 /* Otherwise we failed */ 1751 hMem = NULL; 1752 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1753 } 1754 } 1755 } 1756 } 1757 else if (!(uFlags & LMEM_MODIFY)) 1758 { 1759 /* Otherwise, this is a simple RTL Managed Heap, so just call it */ 1760 hMem = RtlReAllocateHeap(BaseHeap, 1761 Flags | HEAP_NO_SERIALIZE, 1762 hMem, 1763 dwBytes); 1764 if (!hMem) 1765 { 1766 /* Fail */ 1767 BASE_TRACE_FAILURE(); 1768 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1769 } 1770 } 1771 1772 /* All done, unlock the heap and return the pointer */ 1773 RtlUnlockHeap(BaseHeap); 1774 return hMem; 1775 } 1776 1777 /* 1778 * @implemented 1779 */ 1780 SIZE_T 1781 WINAPI 1782 LocalShrink(HLOCAL hMem, 1783 UINT cbNewSize) 1784 { 1785 /* Call RTL */ 1786 return RtlCompactHeap(BaseHeap, 0); 1787 } 1788 1789 /* 1790 * @implemented 1791 */ 1792 SIZE_T 1793 NTAPI 1794 LocalSize(HLOCAL hMem) 1795 { 1796 /* This is the same as a Global Size */ 1797 return GlobalSize(hMem); 1798 } 1799 1800 /* 1801 * @implemented 1802 */ 1803 BOOL 1804 NTAPI 1805 LocalUnlock(HLOCAL hMem) 1806 { 1807 PBASE_HEAP_HANDLE_ENTRY HandleEntry; 1808 BOOL RetVal = TRUE; 1809 1810 /* Check if this was a simple allocated heap entry */ 1811 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) 1812 { 1813 /* Fail, because LocalUnlock is not supported on LMEM_FIXED allocations */ 1814 SetLastError(ERROR_NOT_LOCKED); 1815 return FALSE; 1816 } 1817 1818 /* Otherwise, lock the heap */ 1819 RtlLockHeap(BaseHeap); 1820 1821 /* Get the handle entry */ 1822 HandleEntry = BaseHeapGetEntry(hMem); 1823 BASE_TRACE_HANDLE(HandleEntry, hMem); 1824 _SEH2_TRY 1825 { 1826 /* Make sure it's valid */ 1827 if (!BaseHeapValidateEntry(HandleEntry)) 1828 { 1829 /* It's not, fail */ 1830 BASE_TRACE_FAILURE(); 1831 SetLastError(ERROR_INVALID_HANDLE); 1832 RetVal = FALSE; 1833 } 1834 else 1835 { 1836 /* Otherwise, decrement lock count, unless we're already at 0*/ 1837 if (!HandleEntry->LockCount--) 1838 { 1839 /* In which case we simply lock it back and fail */ 1840 HandleEntry->LockCount++; 1841 SetLastError(ERROR_NOT_LOCKED); 1842 RetVal = FALSE; 1843 } 1844 else if (!HandleEntry->LockCount) 1845 { 1846 /* Nothing to unlock */ 1847 SetLastError(NO_ERROR); 1848 RetVal = FALSE; 1849 } 1850 } 1851 } 1852 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1853 { 1854 SetLastError(ERROR_INVALID_PARAMETER); 1855 RetVal = FALSE; 1856 } 1857 _SEH2_END; 1858 1859 /* All done. Unlock the heap and return the pointer */ 1860 RtlUnlockHeap(BaseHeap); 1861 return RetVal; 1862 } 1863 1864 /* EOF */ 1865