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 /* TYPES *********************************************************************/
18 RTL_HANDLE_TABLE BaseHeapHandleTable
;
20 /* FUNCTIONS ***************************************************************/
27 HeapCreate(DWORD flOptions
,
34 /* Remove non-Win32 flags and tag this allocation */
35 Flags
= (flOptions
& (HEAP_GENERATE_EXCEPTIONS
| HEAP_NO_SERIALIZE
)) |
38 /* Check if heap is growable and ensure max size is correct */
39 if (dwMaximumSize
== 0)
40 Flags
|= HEAP_GROWABLE
;
41 else if (dwMaximumSize
< BaseStaticServerData
->SysInfo
.PageSize
&&
42 dwInitialSize
> dwMaximumSize
)
44 /* Max size is non-zero but less than page size which can't be correct.
45 Fix it up by bumping it to the initial size whatever it is. */
46 dwMaximumSize
= dwInitialSize
;
50 hRet
= RtlCreateHeap(Flags
,
57 /* Set the last error if we failed, and return the pointer */
58 if (!hRet
) SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
67 HeapDestroy(HANDLE hHeap
)
69 /* Return TRUE if the heap was destroyed */
70 if (!RtlDestroyHeap(hHeap
)) return TRUE
;
72 /* Otherwise, we got the handle back, so fail */
73 SetLastError(ERROR_INVALID_HANDLE
);
84 /* Call the RTL API */
85 return RtlGetProcessHeap();
93 GetProcessHeaps(DWORD NumberOfHeaps
,
96 /* Call the RTL API */
97 return RtlGetProcessHeaps(NumberOfHeaps
, ProcessHeaps
);
105 HeapLock(HANDLE hHeap
)
107 /* Call the RTL API */
108 return RtlLockHeap(hHeap
);
116 HeapUnlock(HANDLE hHeap
)
118 /* Call the RTL API */
119 return RtlUnlockHeap(hHeap
);
127 HeapCompact(HANDLE hHeap
, DWORD dwFlags
)
129 /* Call the RTL API */
130 return RtlCompactHeap(hHeap
, dwFlags
);
138 HeapValidate(HANDLE hHeap
,
142 /* Call the RTL API */
143 return RtlValidateHeap(hHeap
, dwFlags
, (PVOID
)lpMem
);
151 HeapCreateTagsW(HANDLE hHeap
,
156 /* Call the RTL API */
157 return RtlCreateTagHeap(hHeap
,
168 HeapExtend(HANDLE hHeap
,
175 /* Call the RTL API. Gone in Vista, so commented out. */
176 Status
= STATUS_NOT_IMPLEMENTED
; //RtlExtendHeap(hHeap, dwFlags, BaseAddress, dwBytes);
177 if (!NT_SUCCESS(Status
))
180 BaseSetLastNTError(Status
);
193 HeapQueryTagW(HANDLE hHeap
,
199 /* Call the RTL API */
200 return RtlQueryTagHeap(hHeap
,
203 (BOOLEAN
)bResetCounters
,
212 HeapSummary(HANDLE hHeap
,
217 RTL_HEAP_USAGE Usage
;
219 /* Fill in the length information */
220 Usage
.Length
= sizeof(Usage
);
222 /* Call RTL. Gone in Vista, so commented out */
223 Status
= STATUS_NOT_IMPLEMENTED
; //RtlUsageHeap(hHeap, dwFlags, &Usage);
224 if (!NT_SUCCESS(Status
))
227 BaseSetLastNTError(Status
);
231 /* FIXME: Summary == Usage?! */
232 RtlCopyMemory(Summary
, &Usage
, sizeof(Usage
));
241 HeapUsage(HANDLE hHeap
,
249 /* Call RTL. Gone in Vista, so commented out */
250 Status
= STATUS_NOT_IMPLEMENTED
; //RtlUsageHeap(hHeap, dwFlags, &Usage);
251 if (!NT_SUCCESS(Status
))
254 BaseSetLastNTError(Status
);
257 else if (Status
== STATUS_MORE_ENTRIES
)
259 /* There are still more entries to parse */
263 /* Otherwise, we're completely done, so we return FALSE, but NO_ERROR */
264 SetLastError(NO_ERROR
);
273 HeapWalk(HANDLE hHeap
,
274 LPPROCESS_HEAP_ENTRY lpEntry
)
278 Status
= RtlWalkHeap(hHeap
, lpEntry
);
280 if (!NT_SUCCESS(Status
))
282 SetLastError(RtlNtStatusToDosError(Status
));
294 HeapQueryInformation(HANDLE HeapHandle
,
295 HEAP_INFORMATION_CLASS HeapInformationClass
,
296 PVOID HeapInformation OPTIONAL
,
297 SIZE_T HeapInformationLength OPTIONAL
,
298 PSIZE_T ReturnLength OPTIONAL
)
302 Status
= RtlQueryHeapInformation(HeapHandle
,
303 HeapInformationClass
,
305 HeapInformationLength
,
308 if (!NT_SUCCESS(Status
))
310 BaseSetLastNTError(Status
);
322 HeapSetInformation(HANDLE HeapHandle
,
323 HEAP_INFORMATION_CLASS HeapInformationClass
,
324 PVOID HeapInformation OPTIONAL
,
325 SIZE_T HeapInformationLength OPTIONAL
)
329 Status
= RtlSetHeapInformation(HeapHandle
,
330 HeapInformationClass
,
332 HeapInformationLength
);
334 if (!NT_SUCCESS(Status
))
336 BaseSetLastNTError(Status
);
348 GlobalAlloc(UINT uFlags
,
354 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
355 BASE_TRACE_ALLOC(dwBytes
, uFlags
);
356 ASSERT(hProcessHeap
);
358 /* Make sure the flags are valid */
359 if (uFlags
& ~GMEM_VALID_FLAGS
)
361 /* They aren't, fail */
362 BASE_TRACE_FAILURE();
363 SetLastError(ERROR_INVALID_PARAMETER
);
367 /* Convert ZEROINIT */
368 if (uFlags
& GMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
370 /* Check if we're not movable, which means pointer-based heap */
371 if (!(uFlags
& GMEM_MOVEABLE
))
373 /* Check if this is DDESHARE (deprecated) */
374 if (uFlags
& GMEM_DDESHARE
) Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
376 /* Allocate heap for it */
377 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
378 BASE_TRACE_ALLOC2(Ptr
);
382 /* This is heap based, so lock it in first */
383 RtlLockHeap(hProcessHeap
);
386 * Disable locking, enable custom flags, and write the
387 * movable flag (deprecated)
389 Flags
|= HEAP_NO_SERIALIZE
|
390 HEAP_SETTABLE_USER_VALUE
|
391 BASE_HEAP_FLAG_MOVABLE
;
393 /* Allocate the handle */
394 HandleEntry
= BaseHeapAllocEntry();
399 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
400 BASE_TRACE_FAILURE();
404 /* Get the object and make sure we have size */
405 hMemory
= &HandleEntry
->Object
;
408 /* Allocate the actual memory for it */
409 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
410 BASE_TRACE_PTR(HandleEntry
, Ptr
);
413 /* We failed, manually set the allocate flag and free the handle */
414 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
415 BaseHeapFreeEntry(HandleEntry
);
417 /* For the cleanup case */
422 /* All worked well, save our heap entry */
423 RtlSetUserValueHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, Ptr
, hMemory
);
428 /* Cleanup! First unlock the heap */
429 RtlUnlockHeap(hProcessHeap
);
431 /* Check if a handle was allocated */
434 /* Set the pointer and allocated flag */
435 HandleEntry
->Object
= Ptr
;
436 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
439 /* We don't have a valid pointer, but so reuse this handle */
440 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
443 /* Check if the handle is discardable */
444 if (uFlags
& GMEM_DISCARDABLE
)
446 /* Save it in the handle entry */
447 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
450 /* Check if the handle is moveable */
451 if (uFlags
& GMEM_MOVEABLE
)
453 /* Save it in the handle entry */
454 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_MOVABLE
;
457 /* Check if the handle is DDE Shared */
458 if (uFlags
& GMEM_DDESHARE
)
460 /* Save it in the handle entry */
461 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
464 /* Set the pointer */
468 /* Return the pointer */
477 GlobalCompact(DWORD dwMinFree
)
479 /* Call the RTL Heap Manager */
480 return RtlCompactHeap(hProcessHeap
, 0);
488 GlobalFix(HGLOBAL hMem
)
490 /* Lock the memory if it the handle is valid */
491 if (INVALID_HANDLE_VALUE
!= hMem
) GlobalLock(hMem
);
499 GlobalFlags(HGLOBAL hMem
)
501 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
502 HANDLE Handle
= NULL
;
504 UINT uFlags
= GMEM_INVALID_HANDLE
;
506 /* Start by locking the heap */
507 RtlLockHeap(hProcessHeap
);
509 /* Check if this is a simple RTL Heap Managed block */
510 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
512 /* Then we'll query RTL Heap */
513 RtlGetUserInfoHeap(hProcessHeap
, Flags
, hMem
, &Handle
, &Flags
);
514 BASE_TRACE_PTR(Handle
, hMem
);
517 * Check if RTL Heap didn't find a handle associated with us or
518 * said that this heap isn't movable, which means something we're
519 * really not a handle-based heap.
521 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
523 /* Then set the flags to 0 */
528 /* Otherwise we're handle-based, so get the internal handle */
533 /* Check if the handle is actually an entry in our table */
534 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
536 /* Then get the entry */
537 HandleEntry
= BaseHeapGetEntry(hMem
);
538 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
540 /* Make sure it's a valid handle */
541 if (BaseHeapValidateEntry(HandleEntry
))
543 /* Get the lock count first */
544 uFlags
= HandleEntry
->LockCount
& GMEM_LOCKCOUNT
;
546 /* Now check if it's discardable */
547 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSABLE
)
549 /* Set the Win32 Flag */
550 uFlags
|= GMEM_DISCARDABLE
;
553 /* Check if it's DDE Shared */
554 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_DDESHARE
)
556 /* Set the Win32 Flag */
557 uFlags
|= GMEM_DDESHARE
;
560 /* Now check if it's discarded */
561 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
562 /* Set the Win32 Flag */
563 uFlags
|= GMEM_DISCARDED
;
567 /* Check if by now, we still haven't gotten any useful flags */
568 if (uFlags
== GMEM_INVALID_HANDLE
) SetLastError(ERROR_INVALID_HANDLE
);
570 /* All done! Unlock heap and return Win32 Flags */
571 RtlUnlockHeap(hProcessHeap
);
580 GlobalFree(HGLOBAL hMem
)
582 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
584 BASE_TRACE_DEALLOC(hMem
);
586 /* Check if this was a simple allocated heap entry */
587 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
589 /* Free it with the RTL Heap Manager */
590 if (RtlFreeHeap(hProcessHeap
, 0, hMem
))
592 /* Return NULL since there's no handle */
598 BASE_TRACE_FAILURE();
599 SetLastError(ERROR_INVALID_HANDLE
);
604 /* It's a handle probably, so lock the heap */
605 RtlLockHeap(hProcessHeap
);
607 /* Make sure that this is an entry in our handle database */
608 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
611 HandleEntry
= BaseHeapGetEntry(hMem
);
612 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
614 /* Make sure the handle is valid */
615 if (!BaseHeapValidateEntry(HandleEntry
))
618 SetLastError(ERROR_INVALID_HANDLE
);
623 /* It's valid, so get the pointer */
624 Ptr
= HandleEntry
->Object
;
626 /* Free this handle */
627 BaseHeapFreeEntry(HandleEntry
);
629 /* If the pointer is 0, then we don't have a handle either */
630 if (!Ptr
) hMem
= NULL
;
635 /* Otherwise, reuse the handle as a pointer */
636 BASE_TRACE_FAILURE();
640 /* Check if we got here with a valid heap pointer */
644 RtlFreeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, Ptr
);
648 /* We're done, so unlock the heap and return the handle */
649 RtlUnlockHeap(hProcessHeap
);
658 GlobalHandle(LPCVOID pMem
)
660 HANDLE Handle
= NULL
;
664 RtlLockHeap(hProcessHeap
);
667 RtlGetUserInfoHeap(hProcessHeap
,
672 BASE_TRACE_PTR(Handle
, pMem
);
675 * Check if RTL Heap didn't find a handle for us or said that
676 * this heap isn't movable.
678 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
680 /* We're actually handle-based, so the pointer is a handle */
681 Handle
= (HANDLE
)pMem
;
684 /* All done, unlock the heap and return the handle */
685 RtlUnlockHeap(hProcessHeap
);
694 GlobalLock(HGLOBAL hMem
)
696 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
699 /* Check if this was a simple allocated heap entry */
700 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
702 /* Verify and return the pointer */
703 return IsBadReadPtr(hMem
, 1) ? NULL
: hMem
;
706 /* Otherwise, lock the heap */
707 RtlLockHeap(hProcessHeap
);
711 /* Get the handle entry */
712 HandleEntry
= BaseHeapGetEntry(hMem
);
713 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
715 /* Make sure it's valid */
716 if (!BaseHeapValidateEntry(HandleEntry
))
719 BASE_TRACE_FAILURE();
720 SetLastError(ERROR_INVALID_HANDLE
);
725 /* Otherwise, get the pointer */
726 Ptr
= HandleEntry
->Object
;
729 /* Increase the lock count, unless we've went too far */
730 if (HandleEntry
->LockCount
++ == GMEM_LOCKCOUNT
)
732 /* In which case we simply unlock once */
733 HandleEntry
->LockCount
--;
738 /* The handle is still there but the memory was already freed */
739 SetLastError(ERROR_DISCARDED
);
743 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
745 SetLastError(ERROR_INVALID_HANDLE
);
750 /* All done. Unlock the heap and return the pointer */
751 RtlUnlockHeap(hProcessHeap
);
757 GlobalReAlloc(HGLOBAL hMem
,
761 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
766 /* Convert ZEROINIT */
767 if (uFlags
& GMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
769 /* If this wasn't a movable heap, then we MUST re-alloc in place */
770 if (!(uFlags
& GMEM_MOVEABLE
)) Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
772 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
773 RtlLockHeap(hProcessHeap
);
774 Flags
|= HEAP_NO_SERIALIZE
;
776 /* Check if this is a simple handle-based block */
777 if (((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
780 HandleEntry
= BaseHeapGetEntry(hMem
);
781 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
783 /* Make sure the handle is valid */
784 if (!BaseHeapValidateEntry(HandleEntry
))
787 BASE_TRACE_FAILURE();
788 SetLastError(ERROR_INVALID_HANDLE
);
791 else if (uFlags
& GMEM_MODIFY
)
793 /* User is changing flags... check if the memory was discardable */
794 if (uFlags
& GMEM_DISCARDABLE
)
796 /* Then set the flag */
797 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
801 /* Otherwise, remove the flag */
802 HandleEntry
->Flags
&= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
807 /* Otherwise, get the object and check if we have no size */
808 Ptr
= HandleEntry
->Object
;
811 /* Clear the handle and check for a pointer */
815 /* Make sure the handle isn't locked */
816 if ((uFlags
& GMEM_MOVEABLE
) && !(HandleEntry
->LockCount
))
818 /* Free the current heap */
819 RtlFreeHeap(hProcessHeap
, Flags
, Ptr
);
821 /* Free the handle */
822 HandleEntry
->Object
= NULL
;
823 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
825 /* Get the object pointer */
826 hMem
= &HandleEntry
->Object
;
831 /* Otherwise just return the object pointer */
832 hMem
= &HandleEntry
->Object
;
837 /* Otherwise, we're allocating, so set the new flags needed */
838 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
841 /* We don't have a base, so allocate one */
842 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
843 BASE_TRACE_ALLOC2(Ptr
);
846 /* Allocation succeeded, so save our entry */
847 RtlSetUserValueHeap(hProcessHeap
,
856 * If it's not movable or currently locked, we MUST allocate
859 if (!(uFlags
& GMEM_MOVEABLE
) && (HandleEntry
->LockCount
))
862 Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
866 /* Otherwise clear the flag if we set it previously */
867 Flags
&= ~HEAP_REALLOC_IN_PLACE_ONLY
;
870 /* And do the re-allocation */
871 Ptr
= RtlReAllocateHeap(hProcessHeap
, Flags
, Ptr
, dwBytes
);
875 /* Allocation succeeded, so save our entry */
876 RtlSetUserValueHeap(hProcessHeap
,
884 /* Make sure we have a pointer by now */
887 /* Write it in the handle entry and mark it in use */
888 HandleEntry
->Object
= Ptr
;
889 HandleEntry
->Flags
&= ~BASE_HEAP_ENTRY_FLAG_REUSE
;
893 /* Otherwise we failed */
895 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
900 else if (uFlags
& GMEM_MODIFY
)
902 /* This is not a handle-based heap and the caller wants it to be one */
903 if (uFlags
& GMEM_MOVEABLE
)
905 /* Get information on its current state */
907 DPRINT1("h h %lx %lx\n", Handle
, hMem
);
908 RtlGetUserInfoHeap(hProcessHeap
,
913 DPRINT1("h h %lx %lx\n", Handle
, hMem
);
916 * Check if the handle matches the pointer or if the moveable flag
917 * isn't there, which is what we expect since it currenly isn't.
919 if (Handle
== hMem
|| !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
921 /* Allocate a handle for it */
922 HandleEntry
= BaseHeapAllocEntry();
924 /* Calculate the size of the current heap */
925 dwBytes
= RtlSizeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
927 /* Set the movable flag */
928 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
930 /* Now allocate the actual heap for it */
931 HandleEntry
->Object
= RtlAllocateHeap(hProcessHeap
,
934 BASE_TRACE_PTR(HandleEntry
->Object
, HandleEntry
);
935 if (!HandleEntry
->Object
)
938 * We failed, manually set the allocate flag and
941 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
942 BaseHeapFreeEntry(HandleEntry
);
944 /* For the cleanup case */
945 BASE_TRACE_FAILURE();
947 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
951 /* Otherwise, copy the current heap and free the old one */
952 RtlMoveMemory(HandleEntry
->Object
, hMem
, dwBytes
);
953 RtlFreeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
955 /* Select the heap pointer */
956 hMem
= (HANDLE
)&HandleEntry
->Object
;
958 /* Initialize the count and default flags */
959 HandleEntry
->LockCount
= 0;
960 HandleEntry
->Flags
= RTL_HANDLE_VALID
|
961 BASE_HEAP_ENTRY_FLAG_MOVABLE
;
963 /* Check if it's also discardable */
964 if (uFlags
& GMEM_DISCARDABLE
)
966 /* Set the internal flag */
967 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
970 /* Check if it's also DDE Shared */
971 if (uFlags
& GMEM_DDESHARE
)
973 /* Set the internal flag */
974 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
977 /* Allocation succeeded, so save our entry */
978 RtlSetUserValueHeap(hProcessHeap
,
988 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
989 hMem
= RtlReAllocateHeap(hProcessHeap
,
990 Flags
| HEAP_NO_SERIALIZE
,
996 BASE_TRACE_FAILURE();
997 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1001 /* All done, unlock the heap and return the pointer */
1002 RtlUnlockHeap(hProcessHeap
);
1011 GlobalSize(HGLOBAL hMem
)
1013 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1014 PVOID Handle
= NULL
;
1016 SIZE_T dwSize
= MAXULONG_PTR
;
1019 RtlLockHeap(hProcessHeap
);
1023 /* Check if this is a simple RTL Heap Managed block */
1024 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
1026 /* Then we'll query RTL Heap */
1027 RtlGetUserInfoHeap(hProcessHeap
, Flags
, hMem
, &Handle
, &Flags
);
1028 BASE_TRACE_PTR(Handle
, hMem
);
1031 * Check if RTL Heap didn't give us a handle or said that this heap
1034 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
1036 /* This implies we're not a handle heap, so use the generic call */
1037 dwSize
= RtlSizeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
1041 /* Otherwise we're a handle heap, so get the internal handle */
1046 /* Make sure that this is an entry in our handle database */
1047 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
1050 HandleEntry
= BaseHeapGetEntry(hMem
);
1051 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1053 /* Make sure the handle is valid */
1054 if (!BaseHeapValidateEntry(HandleEntry
))
1057 BASE_TRACE_FAILURE();
1058 SetLastError(ERROR_INVALID_HANDLE
);
1060 else if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
1062 /* We've reused this block, but we've saved the size for you */
1063 dwSize
= HandleEntry
->OldSize
;
1067 /* Otherwise, query RTL about it */
1068 dwSize
= RtlSizeHeap(hProcessHeap
,
1070 HandleEntry
->Object
);
1074 /* Check if by now, we still haven't gotten any useful size */
1075 if (dwSize
== MAXULONG_PTR
)
1078 BASE_TRACE_FAILURE();
1079 SetLastError(ERROR_INVALID_HANDLE
);
1083 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1085 SetLastError(ERROR_INVALID_HANDLE
);
1090 /* All done! Unlock heap and return the size */
1091 RtlUnlockHeap(hProcessHeap
);
1100 GlobalUnfix(HGLOBAL hMem
)
1102 /* If the handle is valid, unlock it */
1103 if (hMem
!= INVALID_HANDLE_VALUE
) GlobalUnlock(hMem
);
1111 GlobalUnlock(HGLOBAL hMem
)
1113 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1116 /* Check if this was a simple allocated heap entry */
1117 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)) return RetVal
;
1119 /* Otherwise, lock the heap */
1120 RtlLockHeap(hProcessHeap
);
1122 /* Get the handle entry */
1123 HandleEntry
= BaseHeapGetEntry(hMem
);
1124 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1128 /* Make sure it's valid */
1129 if (!BaseHeapValidateEntry(HandleEntry
))
1131 /* It's not, fail */
1132 BASE_TRACE_FAILURE();
1133 SetLastError(ERROR_INVALID_HANDLE
);
1138 /* Otherwise, decrement lock count, unless we're already at 0*/
1139 if (!HandleEntry
->LockCount
--)
1141 /* In which case we simply lock it back and fail */
1142 HandleEntry
->LockCount
++;
1143 SetLastError(ERROR_NOT_LOCKED
);
1146 else if (!HandleEntry
->LockCount
)
1148 /* Nothing to unlock */
1149 SetLastError(NO_ERROR
);
1154 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1156 SetLastError(ERROR_INVALID_PARAMETER
);
1161 /* All done. Unlock the heap and return the pointer */
1162 RtlUnlockHeap(hProcessHeap
);
1171 GlobalUnWire(HGLOBAL hMem
)
1173 /* This is simply an unlock */
1174 return GlobalUnlock(hMem
);
1182 GlobalWire(HGLOBAL hMem
)
1184 /* This is just a lock */
1185 return GlobalLock(hMem
);
1193 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer
)
1195 SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo
;
1196 VM_COUNTERS VmCounters
;
1197 QUOTA_LIMITS QuotaLimits
;
1198 ULONGLONG PageFile
, PhysicalMemory
;
1200 /* Query performance information */
1201 NtQuerySystemInformation(SystemPerformanceInformation
,
1203 sizeof(PerformanceInfo
),
1206 /* Calculate memory load */
1207 lpBuffer
->dwMemoryLoad
= ((DWORD
)(BaseStaticServerData
->SysInfo
.NumberOfPhysicalPages
-
1208 PerformanceInfo
.AvailablePages
) * 100) /
1209 BaseStaticServerData
->SysInfo
.NumberOfPhysicalPages
;
1211 /* Save physical memory */
1212 PhysicalMemory
= BaseStaticServerData
->SysInfo
.NumberOfPhysicalPages
*
1213 BaseStaticServerData
->SysInfo
.PageSize
;
1214 lpBuffer
->ullTotalPhys
= PhysicalMemory
;
1216 /* Now save available physical memory */
1217 PhysicalMemory
= PerformanceInfo
.AvailablePages
*
1218 BaseStaticServerData
->SysInfo
.PageSize
;
1219 lpBuffer
->ullAvailPhys
= PhysicalMemory
;
1221 /* Query VM and Quota Limits */
1222 NtQueryInformationProcess(NtCurrentProcess(),
1225 sizeof(QUOTA_LIMITS
),
1227 NtQueryInformationProcess(NtCurrentProcess(),
1230 sizeof(VM_COUNTERS
),
1233 /* Save the commit limit */
1234 lpBuffer
->ullTotalPageFile
= min(QuotaLimits
.PagefileLimit
,
1235 PerformanceInfo
.CommitLimit
);
1237 /* Calculate how many pages are left */
1238 PageFile
= PerformanceInfo
.CommitLimit
- PerformanceInfo
.CommittedPages
;
1240 /* Save the total */
1241 lpBuffer
->ullAvailPageFile
= min(PageFile
,
1242 QuotaLimits
.PagefileLimit
-
1243 VmCounters
.PagefileUsage
);
1244 lpBuffer
->ullAvailPageFile
*= BaseStaticServerData
->SysInfo
.PageSize
;
1246 /* Now calculate the total virtual space */
1247 lpBuffer
->ullTotalVirtual
= (BaseStaticServerData
->SysInfo
.MaximumUserModeAddress
-
1248 BaseStaticServerData
->SysInfo
.MinimumUserModeAddress
) + 1;
1250 /* And finally the avilable virtual space */
1251 lpBuffer
->ullAvailVirtual
= lpBuffer
->ullTotalVirtual
-
1252 VmCounters
.VirtualSize
;
1253 lpBuffer
->ullAvailExtendedVirtual
= 0;
1262 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer
)
1264 MEMORYSTATUSEX lpBufferEx
;
1266 /* Call the extended function */
1267 lpBufferEx
.dwLength
= sizeof(MEMORYSTATUSEX
);
1268 if (GlobalMemoryStatusEx(&lpBufferEx
))
1270 /* Reset the right size and fill out the information */
1271 lpBuffer
->dwLength
= sizeof(MEMORYSTATUS
);
1272 lpBuffer
->dwMemoryLoad
= lpBufferEx
.dwMemoryLoad
;
1273 lpBuffer
->dwTotalPhys
= (SIZE_T
)lpBufferEx
.ullTotalPhys
;
1274 lpBuffer
->dwAvailPhys
= (SIZE_T
)lpBufferEx
.ullAvailPhys
;
1275 lpBuffer
->dwTotalPageFile
= (SIZE_T
)lpBufferEx
.ullTotalPageFile
;
1276 lpBuffer
->dwAvailPageFile
= (SIZE_T
)lpBufferEx
.ullAvailPageFile
;
1277 lpBuffer
->dwTotalVirtual
= (SIZE_T
)lpBufferEx
.ullTotalVirtual
;
1278 lpBuffer
->dwAvailVirtual
= (SIZE_T
)lpBufferEx
.ullAvailVirtual
;
1287 LocalAlloc(UINT uFlags
,
1293 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1294 BASE_TRACE_ALLOC(dwBytes
, uFlags
);
1295 ASSERT(hProcessHeap
);
1297 /* Make sure the flags are valid */
1298 if (uFlags
& ~LMEM_VALID_FLAGS
)
1300 /* They aren't, fail */
1301 BASE_TRACE_FAILURE();
1302 SetLastError(ERROR_INVALID_PARAMETER
);
1306 /* Convert ZEROINIT */
1307 if (uFlags
& LMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
1309 /* Check if we're not movable, which means pointer-based heap */
1310 if (!(uFlags
& LMEM_MOVEABLE
))
1312 /* Allocate heap for it */
1313 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
1314 BASE_TRACE_ALLOC2(Ptr
);
1318 /* This is heap based, so lock it in first */
1319 RtlLockHeap(hProcessHeap
);
1322 * Disable locking, enable custom flags, and write the
1323 * movable flag (deprecated)
1325 Flags
|= HEAP_NO_SERIALIZE
|
1326 HEAP_SETTABLE_USER_VALUE
|
1327 BASE_HEAP_FLAG_MOVABLE
;
1329 /* Allocate the handle */
1330 HandleEntry
= BaseHeapAllocEntry();
1335 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1336 BASE_TRACE_FAILURE();
1340 /* Get the object and make sure we have size */
1341 hMemory
= &HandleEntry
->Object
;
1344 /* Allocate the actual memory for it */
1345 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
1346 BASE_TRACE_PTR(HandleEntry
, Ptr
);
1349 /* We failed, manually set the allocate flag and free the handle */
1350 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
1351 BaseHeapFreeEntry(HandleEntry
);
1353 /* For the cleanup case */
1358 /* All worked well, save our heap entry */
1359 RtlSetUserValueHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, Ptr
, hMemory
);
1364 /* Cleanup! First unlock the heap */
1365 RtlUnlockHeap(hProcessHeap
);
1367 /* Check if a handle was allocated */
1370 /* Set the pointer and allocated flag */
1371 HandleEntry
->Object
= Ptr
;
1372 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
1375 /* We don't have a valid pointer, but so reuse this handle */
1376 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
1379 /* Check if the handle is discardable */
1380 if (uFlags
& GMEM_DISCARDABLE
)
1382 /* Save it in the handle entry */
1383 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
1386 /* Check if the handle is moveable */
1387 if (uFlags
& GMEM_MOVEABLE
)
1389 /* Save it in the handle entry */
1390 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_MOVABLE
;
1393 /* Set the pointer */
1397 /* Return the pointer */
1406 LocalCompact(UINT dwMinFree
)
1408 /* Call the RTL Heap Manager */
1409 return RtlCompactHeap(hProcessHeap
, 0);
1417 LocalFlags(HLOCAL hMem
)
1419 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1420 HANDLE Handle
= NULL
;
1422 UINT uFlags
= LMEM_INVALID_HANDLE
;
1424 /* Start by locking the heap */
1425 RtlLockHeap(hProcessHeap
);
1427 /* Check if this is a simple RTL Heap Managed block */
1428 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
1430 /* Then we'll query RTL Heap */
1431 RtlGetUserInfoHeap(hProcessHeap
, Flags
, hMem
, &Handle
, &Flags
);
1432 BASE_TRACE_PTR(Handle
, hMem
);
1435 * Check if RTL Heap didn't find a handle associated with us or
1436 * said that this heap isn't movable, which means something we're
1437 * really not a handle-based heap.
1439 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
1441 /* Then set the flags to 0 */
1446 /* Otherwise we're handle-based, so get the internal handle */
1451 /* Check if the handle is actually an entry in our table */
1452 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
1454 /* Then get the entry */
1455 HandleEntry
= BaseHeapGetEntry(hMem
);
1456 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1458 /* Make sure it's a valid handle */
1459 if (BaseHeapValidateEntry(HandleEntry
))
1461 /* Get the lock count first */
1462 uFlags
= HandleEntry
->LockCount
& LMEM_LOCKCOUNT
;
1464 /* Now check if it's discardable */
1465 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSABLE
)
1467 /* Set the Win32 Flag */
1468 uFlags
|= LMEM_DISCARDABLE
;
1471 /* Now check if it's discarded */
1472 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
1473 /* Set the Win32 Flag */
1474 uFlags
|= LMEM_DISCARDED
;
1478 /* Check if by now, we still haven't gotten any useful flags */
1479 if (uFlags
== LMEM_INVALID_HANDLE
) SetLastError(ERROR_INVALID_HANDLE
);
1481 /* All done! Unlock heap and return Win32 Flags */
1482 RtlUnlockHeap(hProcessHeap
);
1491 LocalFree(HLOCAL hMem
)
1493 /* This is identical to a Global Free */
1494 return GlobalFree(hMem
);
1502 LocalHandle(LPCVOID pMem
)
1504 /* This is identical to a Global Handle */
1505 return GlobalHandle(pMem
);
1513 LocalLock(HLOCAL hMem
)
1515 /* This is the same as a GlobalLock, assuming these never change */
1516 C_ASSERT(LMEM_LOCKCOUNT
== GMEM_LOCKCOUNT
);
1517 return GlobalLock(hMem
);
1522 LocalReAlloc(HLOCAL hMem
,
1526 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1530 /* Convert ZEROINIT */
1531 if (uFlags
& LMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
1533 /* If this wasn't a movable heap, then we MUST re-alloc in place */
1534 if (!(uFlags
& LMEM_MOVEABLE
)) Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
1536 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
1537 RtlLockHeap(hProcessHeap
);
1538 Flags
|= HEAP_NO_SERIALIZE
;
1540 /* Check if this is a simple handle-based block */
1541 if (((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
1544 HandleEntry
= BaseHeapGetEntry(hMem
);
1545 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1547 /* Make sure the handle is valid */
1548 if (!BaseHeapValidateEntry(HandleEntry
))
1551 BASE_TRACE_FAILURE();
1552 SetLastError(ERROR_INVALID_HANDLE
);
1555 else if (uFlags
& LMEM_MODIFY
)
1557 /* User is changing flags... check if the memory was discardable */
1558 if (uFlags
& LMEM_DISCARDABLE
)
1560 /* Then set the flag */
1561 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
1565 /* Otherwise, remove the flag */
1566 HandleEntry
->Flags
&= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
1571 /* Otherwise, get the object and check if we have no size */
1572 Ptr
= HandleEntry
->Object
;
1575 /* Clear the handle and check for a pointer */
1579 /* Make sure the handle isn't locked */
1580 if ((uFlags
& LMEM_MOVEABLE
) && !(HandleEntry
->LockCount
))
1582 /* Free the current heap */
1583 RtlFreeHeap(hProcessHeap
, Flags
, Ptr
);
1585 /* Free the handle */
1586 HandleEntry
->Object
= NULL
;
1587 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
1589 /* Get the object pointer */
1590 hMem
= &HandleEntry
->Object
;
1595 /* Otherwise just return the object pointer */
1596 hMem
= &HandleEntry
->Object
;
1601 /* Otherwise, we're allocating, so set the new flags needed */
1602 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
1605 /* We don't have a base, so allocate one */
1606 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
1607 BASE_TRACE_ALLOC2(Ptr
);
1610 /* Allocation succeeded, so save our entry */
1611 RtlSetUserValueHeap(hProcessHeap
,
1620 * If it's not movable or currently locked, we MUST allocate
1623 if (!(uFlags
& LMEM_MOVEABLE
) && (HandleEntry
->LockCount
))
1626 Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
1630 /* Otherwise clear the flag if we set it previously */
1631 Flags
&= ~HEAP_REALLOC_IN_PLACE_ONLY
;
1634 /* And do the re-allocation */
1635 Ptr
= RtlReAllocateHeap(hProcessHeap
, Flags
, Ptr
, dwBytes
);
1638 /* Make sure we have a pointer by now */
1641 /* Write it in the handle entry and mark it in use */
1642 HandleEntry
->Object
= Ptr
;
1643 HandleEntry
->Flags
&= ~BASE_HEAP_ENTRY_FLAG_REUSE
;
1647 /* Otherwise we failed */
1649 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1654 else if (!(uFlags
& LMEM_MODIFY
))
1656 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
1657 hMem
= RtlReAllocateHeap(hProcessHeap
,
1658 Flags
| HEAP_NO_SERIALIZE
,
1664 BASE_TRACE_FAILURE();
1665 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1669 /* All done, unlock the heap and return the pointer */
1670 RtlUnlockHeap(hProcessHeap
);
1679 LocalShrink(HLOCAL hMem
,
1683 return RtlCompactHeap(hProcessHeap
, 0);
1691 LocalSize(HLOCAL hMem
)
1693 /* This is the same as a Global Size */
1694 return GlobalSize(hMem
);
1702 LocalUnlock(HLOCAL hMem
)
1704 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
1707 /* Check if this was a simple allocated heap entry */
1708 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
1710 /* Fail, because LocalUnlock is not supported on LMEM_FIXED allocations */
1711 SetLastError(ERROR_NOT_LOCKED
);
1715 /* Otherwise, lock the heap */
1716 RtlLockHeap(hProcessHeap
);
1718 /* Get the handle entry */
1719 HandleEntry
= BaseHeapGetEntry(hMem
);
1720 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
1724 /* Make sure it's valid */
1725 if (!BaseHeapValidateEntry(HandleEntry
))
1727 /* It's not, fail */
1728 BASE_TRACE_FAILURE();
1729 SetLastError(ERROR_INVALID_HANDLE
);
1734 /* Otherwise, decrement lock count, unless we're already at 0*/
1735 if (!HandleEntry
->LockCount
--)
1737 /* In which case we simply lock it back and fail */
1738 HandleEntry
->LockCount
++;
1739 SetLastError(ERROR_NOT_LOCKED
);
1742 else if (!HandleEntry
->LockCount
)
1744 /* Nothing to unlock */
1745 SetLastError(NO_ERROR
);
1750 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1752 SetLastError(ERROR_INVALID_PARAMETER
);
1757 /* All done. Unlock the heap and return the pointer */
1758 RtlUnlockHeap(hProcessHeap
);