2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/mem/heap.c
5 * PURPOSE: Heap Memory APIs (wrappers for RtlHeap*)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *******************************************************************/
16 /* GLOBALS ********************************************************************/
18 RTL_HANDLE_TABLE BaseHeapHandleTable
;
20 ULONG_PTR SystemRangeStart
;
22 /* PRIVATE FUNCTIONS **********************************************************/
26 BaseDllInitializeMemoryManager(VOID
)
28 BaseHeap
= RtlGetProcessHeap();
29 RtlInitializeHandleTable(0xFFFF,
30 sizeof(BASE_HEAP_HANDLE_ENTRY
),
31 &BaseHeapHandleTable
);
32 NtQuerySystemInformation(SystemRangeStartInformation
,
34 sizeof(SystemRangeStart
),
38 /* PUBLIC FUNCTIONS ***********************************************************/
45 HeapCreate(DWORD flOptions
,
52 /* Remove non-Win32 flags and tag this allocation */
53 Flags
= (flOptions
& (HEAP_GENERATE_EXCEPTIONS
| HEAP_NO_SERIALIZE
)) |
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
)
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
;
68 hRet
= RtlCreateHeap(Flags
,
75 /* Set the last error if we failed, and return the pointer */
76 if (!hRet
) SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
85 HeapDestroy(HANDLE hHeap
)
87 /* Return TRUE if the heap was destroyed */
88 if (!RtlDestroyHeap(hHeap
)) return TRUE
;
90 /* Otherwise, we got the handle back, so fail */
91 SetLastError(ERROR_INVALID_HANDLE
);
102 /* Call the RTL API */
103 return RtlGetProcessHeap();
111 GetProcessHeaps(DWORD NumberOfHeaps
,
112 PHANDLE ProcessHeaps
)
114 /* Call the RTL API */
115 return RtlGetProcessHeaps(NumberOfHeaps
, ProcessHeaps
);
123 HeapLock(HANDLE hHeap
)
125 /* Call the RTL API */
126 return RtlLockHeap(hHeap
);
134 HeapUnlock(HANDLE hHeap
)
136 /* Call the RTL API */
137 return RtlUnlockHeap(hHeap
);
145 HeapCompact(HANDLE hHeap
, DWORD dwFlags
)
147 /* Call the RTL API */
148 return RtlCompactHeap(hHeap
, dwFlags
);
156 HeapValidate(HANDLE hHeap
,
160 /* Call the RTL API */
161 return RtlValidateHeap(hHeap
, dwFlags
, (PVOID
)lpMem
);
169 HeapCreateTagsW(HANDLE hHeap
,
174 /* Call the RTL API */
175 return RtlCreateTagHeap(hHeap
,
186 HeapExtend(HANDLE hHeap
,
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
))
198 BaseSetLastNTError(Status
);
211 HeapQueryTagW(HANDLE hHeap
,
217 /* Call the RTL API */
218 return RtlQueryTagHeap(hHeap
,
221 (BOOLEAN
)bResetCounters
,
230 HeapSummary(HANDLE hHeap
,
235 RTL_HEAP_USAGE Usage
;
237 /* Fill in the length information */
238 Usage
.Length
= sizeof(Usage
);
240 /* Call RTL. Gone in Vista, so commented out */
241 Status
= STATUS_NOT_IMPLEMENTED
; //RtlUsageHeap(hHeap, dwFlags, &Usage);
242 if (!NT_SUCCESS(Status
))
245 BaseSetLastNTError(Status
);
249 /* FIXME: Summary == Usage?! */
250 RtlCopyMemory(Summary
, &Usage
, sizeof(Usage
));
259 HeapUsage(HANDLE hHeap
,
267 /* Call RTL. Gone in Vista, so commented out */
268 Status
= STATUS_NOT_IMPLEMENTED
; //RtlUsageHeap(hHeap, dwFlags, &Usage);
269 if (!NT_SUCCESS(Status
))
272 BaseSetLastNTError(Status
);
275 else if (Status
== STATUS_MORE_ENTRIES
)
277 /* There are still more entries to parse */
281 /* Otherwise, we're completely done, so we return FALSE, but NO_ERROR */
282 SetLastError(NO_ERROR
);
291 HeapWalk(HANDLE hHeap
,
292 LPPROCESS_HEAP_ENTRY lpEntry
)
296 DPRINT1("Warning, HeapWalk is calling RtlWalkHeap with Win32 parameters\n");
298 Status
= RtlWalkHeap(hHeap
, lpEntry
);
300 if (!NT_SUCCESS(Status
))
302 SetLastError(RtlNtStatusToDosError(Status
));
314 HeapQueryInformation(HANDLE HeapHandle
,
315 HEAP_INFORMATION_CLASS HeapInformationClass
,
316 PVOID HeapInformation OPTIONAL
,
317 SIZE_T HeapInformationLength OPTIONAL
,
318 PSIZE_T ReturnLength OPTIONAL
)
322 Status
= RtlQueryHeapInformation(HeapHandle
,
323 HeapInformationClass
,
325 HeapInformationLength
,
328 if (!NT_SUCCESS(Status
))
330 BaseSetLastNTError(Status
);
342 HeapSetInformation(HANDLE HeapHandle
,
343 HEAP_INFORMATION_CLASS HeapInformationClass
,
344 PVOID HeapInformation OPTIONAL
,
345 SIZE_T HeapInformationLength OPTIONAL
)
349 Status
= RtlSetHeapInformation(HeapHandle
,
350 HeapInformationClass
,
352 HeapInformationLength
);
354 if (!NT_SUCCESS(Status
))
356 BaseSetLastNTError(Status
);
368 GlobalAlloc(UINT uFlags
,
374 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
375 BASE_TRACE_ALLOC(dwBytes
, uFlags
);
378 /* Make sure the flags are valid */
379 if (uFlags
& ~GMEM_VALID_FLAGS
)
381 /* They aren't, fail */
382 BASE_TRACE_FAILURE();
383 SetLastError(ERROR_INVALID_PARAMETER
);
387 /* Convert ZEROINIT */
388 if (uFlags
& GMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
390 /* Check if we're not movable, which means pointer-based heap */
391 if (!(uFlags
& GMEM_MOVEABLE
))
393 /* Check if this is DDESHARE (deprecated) */
394 if (uFlags
& GMEM_DDESHARE
) Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
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
);
403 /* This is heap based, so lock it in first */
404 RtlLockHeap(BaseHeap
);
407 * Disable locking, enable custom flags, and write the
408 * movable flag (deprecated)
410 Flags
|= HEAP_NO_SERIALIZE
|
411 HEAP_SETTABLE_USER_VALUE
|
412 BASE_HEAP_FLAG_MOVABLE
;
414 /* Allocate the handle */
415 HandleEntry
= BaseHeapAllocEntry();
420 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
421 BASE_TRACE_FAILURE();
425 /* Get the object and make sure we have size */
426 hMemory
= &HandleEntry
->Object
;
429 /* Allocate the actual memory for it */
430 Ptr
= RtlAllocateHeap(BaseHeap
, Flags
, dwBytes
);
431 BASE_TRACE_PTR(HandleEntry
, Ptr
);
434 /* We failed, manually set the allocate flag and free the handle */
435 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
436 BaseHeapFreeEntry(HandleEntry
);
438 /* For the cleanup case */
443 /* All worked well, save our heap entry */
444 RtlSetUserValueHeap(BaseHeap
, HEAP_NO_SERIALIZE
, Ptr
, hMemory
);
449 /* Cleanup! First unlock the heap */
450 RtlUnlockHeap(BaseHeap
);
452 /* Check if a handle was allocated */
455 /* Set the pointer and allocated flag */
456 HandleEntry
->Object
= Ptr
;
457 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
460 /* We don't have a valid pointer, but so reuse this handle */
461 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
464 /* Check if the handle is discardable */
465 if (uFlags
& GMEM_DISCARDABLE
)
467 /* Save it in the handle entry */
468 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
471 /* Check if the handle is moveable */
472 if (uFlags
& GMEM_MOVEABLE
)
474 /* Save it in the handle entry */
475 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_MOVABLE
;
478 /* Check if the handle is DDE Shared */
479 if (uFlags
& GMEM_DDESHARE
)
481 /* Save it in the handle entry */
482 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
485 /* Set the pointer */
489 /* Return the pointer */
498 GlobalCompact(DWORD dwMinFree
)
500 /* Call the RTL Heap Manager */
501 return RtlCompactHeap(BaseHeap
, 0);
509 GlobalFix(HGLOBAL hMem
)
511 /* Lock the memory if it the handle is valid */
512 if (INVALID_HANDLE_VALUE
!= hMem
) GlobalLock(hMem
);
520 GlobalFlags(HGLOBAL hMem
)
522 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
523 HANDLE Handle
= NULL
;
525 UINT uFlags
= GMEM_INVALID_HANDLE
;
527 /* Start by locking the heap */
528 RtlLockHeap(BaseHeap
);
531 /* Check if this is a simple RTL Heap Managed block */
532 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
534 /* Then we'll query RTL Heap */
535 RtlGetUserInfoHeap(BaseHeap
, Flags
, hMem
, &Handle
, &Flags
);
536 BASE_TRACE_PTR(Handle
, hMem
);
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.
543 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
545 /* Then set the flags to 0 */
550 /* Otherwise we're handle-based, so get the internal handle */
555 /* Check if the handle is actually an entry in our table */
556 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
558 /* Then get the entry */
559 HandleEntry
= BaseHeapGetEntry(hMem
);
560 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
562 /* Make sure it's a valid handle */
563 if (BaseHeapValidateEntry(HandleEntry
))
565 /* Get the lock count first */
566 uFlags
= HandleEntry
->LockCount
& GMEM_LOCKCOUNT
;
568 /* Now check if it's discardable */
569 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSABLE
)
571 /* Set the Win32 Flag */
572 uFlags
|= GMEM_DISCARDABLE
;
575 /* Check if it's DDE Shared */
576 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_DDESHARE
)
578 /* Set the Win32 Flag */
579 uFlags
|= GMEM_DDESHARE
;
582 /* Now check if it's discarded */
583 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
585 /* Set the Win32 Flag */
586 uFlags
|= GMEM_DISCARDED
;
591 /* Check if by now, we still haven't gotten any useful flags */
592 if (uFlags
== GMEM_INVALID_HANDLE
) SetLastError(ERROR_INVALID_HANDLE
);
594 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
596 /* Set the exception code */
597 BaseSetLastNTError(_SEH2_GetExceptionCode());
601 /* All done! Unlock heap and return Win32 Flags */
602 RtlUnlockHeap(BaseHeap
);
611 GlobalFree(HGLOBAL hMem
)
613 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
615 BASE_TRACE_DEALLOC(hMem
);
617 /* Check if this was a simple allocated heap entry */
618 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
620 /* Free it with the RTL Heap Manager */
621 if (RtlFreeHeap(BaseHeap
, 0, hMem
))
623 /* Return NULL since there's no handle */
629 BASE_TRACE_FAILURE();
630 SetLastError(ERROR_INVALID_HANDLE
);
635 /* It's a handle probably, so lock the heap */
636 RtlLockHeap(BaseHeap
);
639 /* Make sure that this is an entry in our handle database */
640 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
643 HandleEntry
= BaseHeapGetEntry(hMem
);
644 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
646 /* Make sure the handle is valid */
647 if (!BaseHeapValidateEntry(HandleEntry
))
650 SetLastError(ERROR_INVALID_HANDLE
);
655 /* It's valid, so get the pointer */
656 Ptr
= HandleEntry
->Object
;
658 /* Free this handle */
659 BaseHeapFreeEntry(HandleEntry
);
661 /* If the pointer is 0, then we don't have a handle either */
662 if (!Ptr
) hMem
= NULL
;
667 /* Otherwise, reuse the handle as a pointer */
668 BASE_TRACE_FAILURE();
672 /* Check if we got here with a valid heap pointer */
675 /* Free it with the RTL Heap Manager */
676 if (RtlFreeHeap(BaseHeap
, HEAP_NO_SERIALIZE
, Ptr
))
678 /* Everything worked */
683 /* This wasn't a real heap handle */
684 SetLastError(ERROR_INVALID_HANDLE
);
688 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
690 /* Set the exception code */
691 BaseSetLastNTError(_SEH2_GetExceptionCode());
695 /* We're done, so unlock the heap and return the handle */
696 RtlUnlockHeap(BaseHeap
);
705 GlobalHandle(LPCVOID pMem
)
707 HANDLE Handle
= NULL
;
711 RtlLockHeap(BaseHeap
);
715 if (!RtlGetUserInfoHeap(BaseHeap
,
721 /* RTL Heap Manager does not know about this heap */
722 SetLastError(ERROR_INVALID_HANDLE
);
727 * Check if RTL Heap didn't find a handle for us or said that
728 * this heap isn't movable.
730 BASE_TRACE_PTR(Handle
, pMem
);
731 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
733 /* We're actually handle-based, so the pointer is a handle */
734 Handle
= (HANDLE
)pMem
;
738 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
740 /* Set the exception code */
741 BaseSetLastNTError(_SEH2_GetExceptionCode());
745 /* All done, unlock the heap and return the handle */
746 RtlUnlockHeap(BaseHeap
);
755 GlobalLock(HGLOBAL hMem
)
757 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
760 /* Check if this was a simple allocated heap entry */
761 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
763 /* Make sure it's not a kernel or invalid address */
764 if ((hMem
>= (HGLOBAL
)SystemRangeStart
) || (IsBadReadPtr(hMem
, 1)))
766 /* Signal an error */
767 SetLastError(ERROR_INVALID_HANDLE
);
775 /* Otherwise, lock the heap */
776 RtlLockHeap(BaseHeap
);
779 /* Get the handle entry */
780 HandleEntry
= BaseHeapGetEntry(hMem
);
781 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
783 /* Make sure it's valid */
784 if (!BaseHeapValidateEntry(HandleEntry
))
787 BASE_TRACE_FAILURE();
788 SetLastError(ERROR_INVALID_HANDLE
);
793 /* Otherwise, get the pointer */
794 Ptr
= HandleEntry
->Object
;
797 /* Increase the lock count, unless we've went too far */
798 if (HandleEntry
->LockCount
++ == GMEM_LOCKCOUNT
)
800 /* In which case we simply unlock once */
801 HandleEntry
->LockCount
--;
806 /* The handle is still there but the memory was already freed */
807 SetLastError(ERROR_DISCARDED
);
811 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
813 SetLastError(ERROR_INVALID_HANDLE
);
818 /* All done. Unlock the heap and return the pointer */
819 RtlUnlockHeap(BaseHeap
);
825 GlobalReAlloc(HGLOBAL hMem
,
829 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
834 /* Throw out invalid flags */
835 if (uFlags
& ~(GMEM_VALID_FLAGS
| GMEM_MODIFY
))
837 SetLastError(ERROR_INVALID_PARAMETER
);
841 /* Throw out invalid combo */
842 if ((uFlags
& GMEM_DISCARDABLE
) && !(uFlags
& GMEM_MODIFY
))
844 SetLastError(ERROR_INVALID_PARAMETER
);
848 /* Convert ZEROINIT */
849 if (uFlags
& GMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
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
;
854 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
855 RtlLockHeap(BaseHeap
);
856 Flags
|= HEAP_NO_SERIALIZE
;
858 /* Check if this is a simple handle-based block */
859 if (((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
862 HandleEntry
= BaseHeapGetEntry(hMem
);
863 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
865 /* Make sure the handle is valid */
866 if (!BaseHeapValidateEntry(HandleEntry
))
869 BASE_TRACE_FAILURE();
870 SetLastError(ERROR_INVALID_HANDLE
);
873 else if (uFlags
& GMEM_MODIFY
)
875 /* User is changing flags... check if the memory was discardable */
876 if (uFlags
& GMEM_DISCARDABLE
)
878 /* Then set the flag */
879 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
883 /* Otherwise, remove the flag */
884 HandleEntry
->Flags
&= ~BASE_HEAP_ENTRY_FLAG_REUSABLE
;
889 /* Otherwise, get the object and check if we have no size */
890 Ptr
= HandleEntry
->Object
;
893 /* Clear the handle and check for a pointer */
897 /* Make sure the handle isn't locked */
898 if ((uFlags
& GMEM_MOVEABLE
) && !(HandleEntry
->LockCount
))
900 /* Free the current heap */
901 if (RtlFreeHeap(BaseHeap
, Flags
, Ptr
))
903 /* Free the handle */
904 HandleEntry
->Object
= NULL
;
905 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
907 /* Get the object pointer */
908 hMem
= &HandleEntry
->Object
;
914 /* Otherwise just return the object pointer */
915 hMem
= &HandleEntry
->Object
;
920 /* Otherwise, we're allocating, so set the new flags needed */
921 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
924 /* We don't have a base, so allocate one */
925 Ptr
= RtlAllocateHeap(BaseHeap
, Flags
, dwBytes
);
926 BASE_TRACE_ALLOC2(Ptr
);
929 /* Allocation succeeded, so save our entry */
930 RtlSetUserValueHeap(BaseHeap
,
939 * If it's not movable or currently locked, we MUST allocate
942 if (!(uFlags
& GMEM_MOVEABLE
) && (HandleEntry
->LockCount
))
945 Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
949 /* Otherwise clear the flag if we set it previously */
950 Flags
&= ~HEAP_REALLOC_IN_PLACE_ONLY
;
953 /* Do the re-allocation. No need to save the entry again */
954 Ptr
= RtlReAllocateHeap(BaseHeap
, Flags
, Ptr
, dwBytes
);
957 /* Make sure we have a pointer by now */
960 /* Write it in the handle entry and mark it in use */
961 HandleEntry
->Object
= Ptr
;
962 HandleEntry
->Flags
&= ~BASE_HEAP_ENTRY_FLAG_REUSE
;
966 /* Otherwise we failed */
968 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
973 else if (uFlags
& GMEM_MODIFY
)
975 /* This is not a handle-based heap and the caller wants it to be one */
976 if (uFlags
& GMEM_MOVEABLE
)
978 /* Get information on its current state */
980 if (RtlGetUserInfoHeap(BaseHeap
,
987 * Check if the handle matches the pointer or the moveable flag
988 * isn't there, which is what we expect since it currenly isn't.
990 if ((Handle
== hMem
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
992 /* Allocate a handle for it */
993 HandleEntry
= BaseHeapAllocEntry();
996 /* No entry could be allocated */
997 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
998 RtlUnlockHeap(BaseHeap
);
1002 /* Calculate the size of the current heap */
1003 dwBytes
= RtlSizeHeap(BaseHeap
, HEAP_NO_SERIALIZE
, hMem
);
1005 /* Set the movable flag */
1006 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
1008 /* Now allocate the actual heap for it */
1009 HandleEntry
->Object
= RtlAllocateHeap(BaseHeap
,
1012 BASE_TRACE_PTR(HandleEntry
->Object
, HandleEntry
);
1013 if (!HandleEntry
->Object
)
1016 * We failed, manually set the allocate flag and
1019 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
1020 BaseHeapFreeEntry(HandleEntry
);
1022 /* For the cleanup case */
1023 BASE_TRACE_FAILURE();
1025 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1029 /* Otherwise, copy the new heap and free the old one */
1030 RtlMoveMemory(HandleEntry
->Object
, hMem
, dwBytes
);
1031 RtlFreeHeap(BaseHeap
, HEAP_NO_SERIALIZE
, hMem
);
1033 /* Select the heap pointer */
1034 hMem
= (HANDLE
)&HandleEntry
->Object
;
1036 /* Initialize the count and default flags */
1037 HandleEntry
->LockCount
= 0;
1038 HandleEntry
->Flags
= RTL_HANDLE_VALID
|
1039 BASE_HEAP_ENTRY_FLAG_MOVABLE
;
1041 /* Check if it's also discardable */
1042 if (uFlags
& GMEM_DISCARDABLE
)
1044 /* Set the internal flag */
1045 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
1048 /* Check if it's also DDE Shared */
1049 if (uFlags
& GMEM_DDESHARE
)
1051 /* Set the internal flag */
1052 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
1055 /* Allocation succeeded, so save our entry */
1056 RtlSetUserValueHeap(BaseHeap
,
1058 HandleEntry
->Object
,
1067 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
1068 hMem
= RtlReAllocateHeap(BaseHeap
,
1069 Flags
| HEAP_NO_SERIALIZE
,
1075 BASE_TRACE_FAILURE();
1076 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1080 /* All done, unlock the heap and return the pointer */
1081 RtlUnlockHeap(BaseHeap
);
1090 GlobalSize(HGLOBAL hMem
)
1092 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1093 PVOID Handle
= NULL
;
1095 SIZE_T dwSize
= MAXULONG_PTR
;
1098 RtlLockHeap(BaseHeap
);
1101 /* Check if this is a simple RTL Heap Managed block */
1102 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
1104 /* Then we'll query RTL Heap */
1105 if (RtlGetUserInfoHeap(BaseHeap
, Flags
, hMem
, &Handle
, &Flags
))
1107 BASE_TRACE_PTR(Handle
, hMem
);
1109 * Check if RTL Heap didn't give us a handle or said that this
1110 * heap isn't movable.
1112 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
1114 /* We're not a handle heap, so use the generic call */
1115 dwSize
= RtlSizeHeap(BaseHeap
, HEAP_NO_SERIALIZE
, hMem
);
1119 /* We're a handle heap so get the internal handle */
1125 /* Make sure that this is an entry in our handle database */
1126 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
1129 HandleEntry
= BaseHeapGetEntry(hMem
);
1130 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1132 /* Make sure the handle is valid */
1133 if (!BaseHeapValidateEntry(HandleEntry
))
1136 BASE_TRACE_FAILURE();
1137 SetLastError(ERROR_INVALID_HANDLE
);
1139 else if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
1141 /* We've reused this block, but we've saved the size for you */
1142 dwSize
= HandleEntry
->OldSize
;
1146 /* Otherwise, query RTL about it */
1147 dwSize
= RtlSizeHeap(BaseHeap
,
1149 HandleEntry
->Object
);
1153 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1155 /* Set failure for later */
1156 dwSize
= MAXULONG_PTR
;
1160 /* Check if by now, we still haven't gotten any useful size */
1161 if (dwSize
== MAXULONG_PTR
)
1164 BASE_TRACE_FAILURE();
1165 SetLastError(ERROR_INVALID_HANDLE
);
1169 /* All done! Unlock heap and return the size */
1170 RtlUnlockHeap(BaseHeap
);
1179 GlobalUnfix(HGLOBAL hMem
)
1181 /* If the handle is valid, unlock it */
1182 if (hMem
!= INVALID_HANDLE_VALUE
) GlobalUnlock(hMem
);
1190 GlobalUnlock(HGLOBAL hMem
)
1192 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1195 /* Check if this was a simple allocated heap entry */
1196 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)) return RetVal
;
1198 /* Otherwise, lock the heap */
1199 RtlLockHeap(BaseHeap
);
1201 /* Get the handle entry */
1202 HandleEntry
= BaseHeapGetEntry(hMem
);
1203 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1207 /* Make sure it's valid */
1208 if (!BaseHeapValidateEntry(HandleEntry
))
1210 /* It's not, fail */
1211 BASE_TRACE_FAILURE();
1212 SetLastError(ERROR_INVALID_HANDLE
);
1217 /* Otherwise, decrement lock count, unless we're already at 0*/
1218 if (!HandleEntry
->LockCount
--)
1220 /* In which case we simply lock it back and fail */
1221 HandleEntry
->LockCount
++;
1222 SetLastError(ERROR_NOT_LOCKED
);
1225 else if (!HandleEntry
->LockCount
)
1227 /* Nothing to unlock */
1228 SetLastError(NO_ERROR
);
1233 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1235 SetLastError(ERROR_INVALID_PARAMETER
);
1240 /* All done. Unlock the heap and return the pointer */
1241 RtlUnlockHeap(BaseHeap
);
1250 GlobalUnWire(HGLOBAL hMem
)
1252 /* This is simply an unlock */
1253 return GlobalUnlock(hMem
);
1261 GlobalWire(HGLOBAL hMem
)
1263 /* This is just a lock */
1264 return GlobalLock(hMem
);
1272 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer
)
1274 SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo
;
1275 VM_COUNTERS VmCounters
;
1276 QUOTA_LIMITS QuotaLimits
;
1277 ULONGLONG PageFile
, PhysicalMemory
;
1279 if (lpBuffer
->dwLength
!= sizeof(*lpBuffer
))
1281 SetLastError(ERROR_INVALID_PARAMETER
);
1285 /* Query performance information */
1286 NtQuerySystemInformation(SystemPerformanceInformation
,
1288 sizeof(PerformanceInfo
),
1291 /* Calculate memory load */
1292 lpBuffer
->dwMemoryLoad
= ((DWORD
)(BaseStaticServerData
->SysInfo
.NumberOfPhysicalPages
-
1293 PerformanceInfo
.AvailablePages
) * 100) /
1294 BaseStaticServerData
->SysInfo
.NumberOfPhysicalPages
;
1296 /* Save physical memory */
1297 PhysicalMemory
= BaseStaticServerData
->SysInfo
.NumberOfPhysicalPages
*
1298 BaseStaticServerData
->SysInfo
.PageSize
;
1299 lpBuffer
->ullTotalPhys
= PhysicalMemory
;
1301 /* Now save available physical memory */
1302 PhysicalMemory
= PerformanceInfo
.AvailablePages
*
1303 BaseStaticServerData
->SysInfo
.PageSize
;
1304 lpBuffer
->ullAvailPhys
= PhysicalMemory
;
1306 /* Query VM and Quota Limits */
1307 NtQueryInformationProcess(NtCurrentProcess(),
1310 sizeof(QUOTA_LIMITS
),
1312 NtQueryInformationProcess(NtCurrentProcess(),
1315 sizeof(VM_COUNTERS
),
1318 /* Save the commit limit */
1319 lpBuffer
->ullTotalPageFile
= min(QuotaLimits
.PagefileLimit
,
1320 PerformanceInfo
.CommitLimit
);
1321 lpBuffer
->ullTotalPageFile
*= BaseStaticServerData
->SysInfo
.PageSize
;
1323 /* Calculate how many pages are left */
1324 PageFile
= PerformanceInfo
.CommitLimit
- PerformanceInfo
.CommittedPages
;
1326 /* Save the total */
1327 lpBuffer
->ullAvailPageFile
= min(PageFile
,
1328 QuotaLimits
.PagefileLimit
-
1329 VmCounters
.PagefileUsage
);
1330 lpBuffer
->ullAvailPageFile
*= BaseStaticServerData
->SysInfo
.PageSize
;
1332 /* Now calculate the total virtual space */
1333 lpBuffer
->ullTotalVirtual
= (BaseStaticServerData
->SysInfo
.MaximumUserModeAddress
-
1334 BaseStaticServerData
->SysInfo
.MinimumUserModeAddress
) + 1;
1336 /* And finally the avilable virtual space */
1337 lpBuffer
->ullAvailVirtual
= lpBuffer
->ullTotalVirtual
- VmCounters
.VirtualSize
;
1338 lpBuffer
->ullAvailExtendedVirtual
= 0;
1348 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer
)
1350 MEMORYSTATUSEX lpBufferEx
;
1352 /* Call the extended function */
1353 lpBufferEx
.dwLength
= sizeof(MEMORYSTATUSEX
);
1354 if (GlobalMemoryStatusEx(&lpBufferEx
))
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
);
1373 LocalAlloc(UINT uFlags
,
1379 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1380 BASE_TRACE_ALLOC(dwBytes
, uFlags
);
1383 /* Make sure the flags are valid */
1384 if (uFlags
& ~LMEM_VALID_FLAGS
)
1386 /* They aren't, fail */
1387 BASE_TRACE_FAILURE();
1388 SetLastError(ERROR_INVALID_PARAMETER
);
1392 /* Convert ZEROINIT */
1393 if (uFlags
& LMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
1395 /* Check if we're not movable, which means pointer-based heap */
1396 if (!(uFlags
& LMEM_MOVEABLE
))
1398 /* Allocate heap for it */
1399 Ptr
= RtlAllocateHeap(BaseHeap
, Flags
, dwBytes
);
1400 BASE_TRACE_ALLOC2(Ptr
);
1404 /* This is heap based, so lock it in first */
1405 RtlLockHeap(BaseHeap
);
1408 * Disable locking, enable custom flags, and write the
1409 * movable flag (deprecated)
1411 Flags
|= HEAP_NO_SERIALIZE
|
1412 HEAP_SETTABLE_USER_VALUE
|
1413 BASE_HEAP_FLAG_MOVABLE
;
1415 /* Allocate the handle */
1416 HandleEntry
= BaseHeapAllocEntry();
1421 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1422 BASE_TRACE_FAILURE();
1426 /* Get the object and make sure we have size */
1427 hMemory
= &HandleEntry
->Object
;
1430 /* Allocate the actual memory for it */
1431 Ptr
= RtlAllocateHeap(BaseHeap
, Flags
, dwBytes
);
1432 BASE_TRACE_PTR(HandleEntry
, Ptr
);
1435 /* We failed, manually set the allocate flag and free the handle */
1436 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
1437 BaseHeapFreeEntry(HandleEntry
);
1439 /* For the cleanup case */
1444 /* All worked well, save our heap entry */
1445 RtlSetUserValueHeap(BaseHeap
, HEAP_NO_SERIALIZE
, Ptr
, hMemory
);
1450 /* Cleanup! First unlock the heap */
1451 RtlUnlockHeap(BaseHeap
);
1453 /* Check if a handle was allocated */
1456 /* Set the pointer and allocated flag */
1457 HandleEntry
->Object
= Ptr
;
1458 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
1461 /* We don't have a valid pointer, but so reuse this handle */
1462 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
1465 /* Check if the handle is discardable */
1466 if (uFlags
& GMEM_DISCARDABLE
)
1468 /* Save it in the handle entry */
1469 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
1472 /* Check if the handle is moveable */
1473 if (uFlags
& GMEM_MOVEABLE
)
1475 /* Save it in the handle entry */
1476 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_MOVABLE
;
1479 /* Set the pointer */
1483 /* Return the pointer */
1492 LocalCompact(UINT dwMinFree
)
1494 /* Call the RTL Heap Manager */
1495 return RtlCompactHeap(BaseHeap
, 0);
1503 LocalFlags(HLOCAL hMem
)
1505 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1506 HANDLE Handle
= NULL
;
1508 UINT uFlags
= LMEM_INVALID_HANDLE
;
1510 /* Start by locking the heap */
1511 RtlLockHeap(BaseHeap
);
1513 /* Check if this is a simple RTL Heap Managed block */
1514 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
1516 /* Then we'll query RTL Heap */
1517 RtlGetUserInfoHeap(BaseHeap
, Flags
, hMem
, &Handle
, &Flags
);
1518 BASE_TRACE_PTR(Handle
, hMem
);
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.
1525 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
1527 /* Then set the flags to 0 */
1532 /* Otherwise we're handle-based, so get the internal handle */
1537 /* Check if the handle is actually an entry in our table */
1538 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
1540 /* Then get the entry */
1541 HandleEntry
= BaseHeapGetEntry(hMem
);
1542 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1544 /* Make sure it's a valid handle */
1545 if (BaseHeapValidateEntry(HandleEntry
))
1547 /* Get the lock count first */
1548 uFlags
= HandleEntry
->LockCount
& LMEM_LOCKCOUNT
;
1550 /* Now check if it's discardable */
1551 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSABLE
)
1553 /* Set the Win32 Flag */
1554 uFlags
|= LMEM_DISCARDABLE
;
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
;
1564 /* Check if by now, we still haven't gotten any useful flags */
1565 if (uFlags
== LMEM_INVALID_HANDLE
) SetLastError(ERROR_INVALID_HANDLE
);
1567 /* All done! Unlock heap and return Win32 Flags */
1568 RtlUnlockHeap(BaseHeap
);
1577 LocalFree(HLOCAL hMem
)
1579 /* This is identical to a Global Free */
1580 return GlobalFree(hMem
);
1588 LocalHandle(LPCVOID pMem
)
1590 /* This is identical to a Global Handle */
1591 return GlobalHandle(pMem
);
1599 LocalLock(HLOCAL hMem
)
1601 /* This is the same as a GlobalLock, assuming these never change */
1602 C_ASSERT(LMEM_LOCKCOUNT
== GMEM_LOCKCOUNT
);
1603 return GlobalLock(hMem
);
1608 LocalReAlloc(HLOCAL hMem
,
1612 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1616 /* Convert ZEROINIT */
1617 if (uFlags
& LMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
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
;
1622 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
1623 RtlLockHeap(BaseHeap
);
1624 Flags
|= HEAP_NO_SERIALIZE
;
1626 /* Check if this is a simple handle-based block */
1627 if (((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
1630 HandleEntry
= BaseHeapGetEntry(hMem
);
1631 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1633 /* Make sure the handle is valid */
1634 if (!BaseHeapValidateEntry(HandleEntry
))
1637 BASE_TRACE_FAILURE();
1638 SetLastError(ERROR_INVALID_HANDLE
);
1641 else if (uFlags
& LMEM_MODIFY
)
1643 /* User is changing flags... check if the memory was discardable */
1644 if (uFlags
& LMEM_DISCARDABLE
)
1646 /* Then set the flag */
1647 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
1651 /* Otherwise, remove the flag */
1652 HandleEntry
->Flags
&= ~BASE_HEAP_ENTRY_FLAG_REUSABLE
;
1657 /* Otherwise, get the object and check if we have no size */
1658 Ptr
= HandleEntry
->Object
;
1661 /* Clear the handle and check for a pointer */
1665 /* Make sure the handle isn't locked */
1666 if ((uFlags
& LMEM_MOVEABLE
) && !(HandleEntry
->LockCount
))
1668 /* Free the current heap */
1669 RtlFreeHeap(BaseHeap
, Flags
, Ptr
);
1671 /* Free the handle */
1672 HandleEntry
->Object
= NULL
;
1673 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
1675 /* Get the object pointer */
1676 hMem
= &HandleEntry
->Object
;
1681 /* Otherwise just return the object pointer */
1682 hMem
= &HandleEntry
->Object
;
1687 /* Otherwise, we're allocating, so set the new flags needed */
1688 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
1691 /* We don't have a base, so allocate one */
1692 Ptr
= RtlAllocateHeap(BaseHeap
, Flags
, dwBytes
);
1693 BASE_TRACE_ALLOC2(Ptr
);
1696 /* Allocation succeeded, so save our entry */
1697 RtlSetUserValueHeap(BaseHeap
,
1706 * If it's not movable or currently locked, we MUST allocate
1709 if (!(uFlags
& LMEM_MOVEABLE
) && (HandleEntry
->LockCount
))
1712 Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
1716 /* Otherwise clear the flag if we set it previously */
1717 Flags
&= ~HEAP_REALLOC_IN_PLACE_ONLY
;
1720 /* And do the re-allocation */
1721 Ptr
= RtlReAllocateHeap(BaseHeap
, Flags
, Ptr
, dwBytes
);
1724 /* Make sure we have a pointer by now */
1727 /* Write it in the handle entry and mark it in use */
1728 HandleEntry
->Object
= Ptr
;
1729 HandleEntry
->Flags
&= ~BASE_HEAP_ENTRY_FLAG_REUSE
;
1733 /* Otherwise we failed */
1735 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1740 else if (!(uFlags
& LMEM_MODIFY
))
1742 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
1743 hMem
= RtlReAllocateHeap(BaseHeap
,
1744 Flags
| HEAP_NO_SERIALIZE
,
1750 BASE_TRACE_FAILURE();
1751 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1755 /* All done, unlock the heap and return the pointer */
1756 RtlUnlockHeap(BaseHeap
);
1765 LocalShrink(HLOCAL hMem
,
1769 return RtlCompactHeap(BaseHeap
, 0);
1777 LocalSize(HLOCAL hMem
)
1779 /* This is the same as a Global Size */
1780 return GlobalSize(hMem
);
1788 LocalUnlock(HLOCAL hMem
)
1790 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1793 /* Check if this was a simple allocated heap entry */
1794 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
1796 /* Fail, because LocalUnlock is not supported on LMEM_FIXED allocations */
1797 SetLastError(ERROR_NOT_LOCKED
);
1801 /* Otherwise, lock the heap */
1802 RtlLockHeap(BaseHeap
);
1804 /* Get the handle entry */
1805 HandleEntry
= BaseHeapGetEntry(hMem
);
1806 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1809 /* Make sure it's valid */
1810 if (!BaseHeapValidateEntry(HandleEntry
))
1812 /* It's not, fail */
1813 BASE_TRACE_FAILURE();
1814 SetLastError(ERROR_INVALID_HANDLE
);
1819 /* Otherwise, decrement lock count, unless we're already at 0*/
1820 if (!HandleEntry
->LockCount
--)
1822 /* In which case we simply lock it back and fail */
1823 HandleEntry
->LockCount
++;
1824 SetLastError(ERROR_NOT_LOCKED
);
1827 else if (!HandleEntry
->LockCount
)
1829 /* Nothing to unlock */
1830 SetLastError(NO_ERROR
);
1835 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1837 SetLastError(ERROR_INVALID_PARAMETER
);
1842 /* All done. Unlock the heap and return the pointer */
1843 RtlUnlockHeap(BaseHeap
);