2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/mem/global.c
5 * PURPOSE: Global Memory APIs (sits on top of Heap*)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
16 /* TYPES *********************************************************************/
18 extern SYSTEM_BASIC_INFORMATION BaseCachedSysInfo
;
19 RTL_HANDLE_TABLE BaseHeapHandleTable
;
21 /* FUNCTIONS ***************************************************************/
28 GlobalAlloc(UINT uFlags
,
34 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
35 BASE_TRACE_ALLOC(dwBytes
, uFlags
);
38 /* Make sure the flags are valid */
39 if (uFlags
& ~GMEM_VALID_FLAGS
)
41 /* They aren't, fail */
43 SetLastError(ERROR_INVALID_PARAMETER
);
47 /* Convert ZEROINIT */
48 if (uFlags
& GMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
50 /* Check if we're not movable, which means pointer-based heap */
51 if (!(uFlags
& GMEM_MOVEABLE
))
53 /* Check if this is DDESHARE (deprecated) */
54 if (uFlags
& GMEM_DDESHARE
) Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
56 /* Allocate heap for it */
57 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
58 BASE_TRACE_ALLOC2(Ptr
);
62 /* This is heap based, so lock it in first */
63 RtlLockHeap(hProcessHeap
);
66 * Disable locking, enable custom flags, and write the
67 * movable flag (deprecated)
69 Flags
|= HEAP_NO_SERIALIZE
|
70 HEAP_SETTABLE_USER_VALUE
|
71 BASE_HEAP_FLAG_MOVABLE
;
73 /* Allocate the handle */
74 HandleEntry
= BaseHeapAllocEntry();
79 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
84 /* Get the object and make sure we have size */
85 hMemory
= &HandleEntry
->Object
;
88 /* Allocate the actual memory for it */
89 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
90 BASE_TRACE_PTR(HandleEntry
, Ptr
);
93 /* We failed, manually set the allocate flag and free the handle */
94 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
95 BaseHeapFreeEntry(HandleEntry
);
97 /* For the cleanup case */
102 /* All worked well, save our heap entry */
103 RtlSetUserValueHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, Ptr
, hMemory
);
104 RtlSetUserFlagsHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, Ptr
, Flags
);
109 /* Cleanup! First unlock the heap */
110 RtlUnlockHeap(hProcessHeap
);
112 /* Check if a handle was allocated */
115 /* Set the pointer and allocated flag */
116 HandleEntry
->Object
= Ptr
;
117 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
120 /* We don't have a valid pointer, but so reuse this handle */
121 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
124 /* Check if the handle is discardable */
125 if (uFlags
& GMEM_DISCARDABLE
)
127 /* Save it in the handle entry */
128 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
131 /* Check if the handle is moveable */
132 if (uFlags
& GMEM_MOVEABLE
)
134 /* Save it in the handle entry */
135 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_MOVABLE
;
138 /* Check if the handle is DDE Shared */
139 if (uFlags
& GMEM_DDESHARE
)
141 /* Save it in the handle entry */
142 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
145 /* Set the pointer */
149 /* Return the pointer */
158 GlobalCompact(DWORD dwMinFree
)
160 /* Call the RTL Heap Manager */
161 return RtlCompactHeap(hProcessHeap
, 0);
169 GlobalFix(HGLOBAL hMem
)
171 /* Lock the memory if it the handle is valid */
172 if (INVALID_HANDLE_VALUE
!= hMem
) GlobalLock(hMem
);
180 GlobalFlags(HGLOBAL hMem
)
182 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
183 HANDLE Handle
= NULL
;
185 UINT uFlags
= GMEM_INVALID_HANDLE
;
187 /* Start by locking the heap */
188 RtlLockHeap(hProcessHeap
);
190 /* Check if this is a simple RTL Heap Managed block */
191 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
193 /* Then we'll query RTL Heap */
194 RtlGetUserInfoHeap(hProcessHeap
, Flags
, hMem
, &Handle
, &Flags
);
195 BASE_TRACE_PTR(Handle
, hMem
);
198 * Check if RTL Heap didn't find a handle associated with us or
199 * said that this heap isn't movable, which means something we're
200 * really not a handle-based heap.
202 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
204 /* Then set the flags to 0 */
209 /* Otherwise we're handle-based, so get the internal handle */
214 /* Check if the handle is actually an entry in our table */
215 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
217 /* Then get the entry */
218 HandleEntry
= BaseHeapGetEntry(hMem
);
219 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
221 /* Make sure it's a valid handle */
222 if (BaseHeapValidateEntry(HandleEntry
))
224 /* Get the lock count first */
225 uFlags
= HandleEntry
->LockCount
& GMEM_LOCKCOUNT
;
227 /* Now check if it's discardable */
228 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSABLE
)
230 /* Set the Win32 Flag */
231 uFlags
|= GMEM_DISCARDABLE
;
234 /* Check if it's DDE Shared */
235 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_DDESHARE
)
237 /* Set the Win32 Flag */
238 uFlags
|= GMEM_DDESHARE
;
241 /* Now check if it's discarded */
242 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
243 /* Set the Win32 Flag */
244 uFlags
|= GMEM_DISCARDED
;
248 /* Check if by now, we still haven't gotten any useful flags */
249 if (uFlags
== GMEM_INVALID_HANDLE
) SetLastError(ERROR_INVALID_HANDLE
);
251 /* All done! Unlock heap and return Win32 Flags */
252 RtlUnlockHeap(hProcessHeap
);
261 GlobalFree(HGLOBAL hMem
)
263 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
265 BASE_TRACE_DEALLOC(hMem
);
267 /* Check if this was a simple allocated heap entry */
268 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
270 /* Free it with the RTL Heap Manager */
271 if (RtlFreeHeap(hProcessHeap
, 0, hMem
))
273 /* Return NULL since there's no handle */
279 BASE_TRACE_FAILURE();
280 SetLastError(ERROR_INVALID_HANDLE
);
285 /* It's a handle probably, so lock the heap */
286 RtlLockHeap(hProcessHeap
);
288 /* Make sure that this is an entry in our handle database */
289 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
292 HandleEntry
= BaseHeapGetEntry(hMem
);
293 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
295 /* Make sure the handle is valid */
296 if (!BaseHeapValidateEntry(HandleEntry
))
299 SetLastError(ERROR_INVALID_HANDLE
);
304 /* It's valid, so get the pointer */
305 Ptr
= HandleEntry
->Object
;
307 /* Free this handle */
308 BaseHeapFreeEntry(HandleEntry
);
310 /* If the pointer is 0, then we don't have a handle either */
311 if (!Ptr
) hMem
= NULL
;
316 /* Otherwise, reuse the handle as a pointer */
317 BASE_TRACE_FAILURE();
321 /* Check if we got here with a valid heap pointer */
325 RtlFreeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, Ptr
);
329 /* We're done, so unlock the heap and return the handle */
330 RtlUnlockHeap(hProcessHeap
);
339 GlobalHandle(LPCVOID pMem
)
341 HANDLE Handle
= NULL
;
345 RtlLockHeap(hProcessHeap
);
348 RtlGetUserInfoHeap(hProcessHeap
,
353 BASE_TRACE_PTR(Handle
, pMem
);
356 * Check if RTL Heap didn't find a handle for us or said that
357 * this heap isn't movable.
359 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
361 /* We're actually handle-based, so the pointer is a handle */
362 Handle
= (HANDLE
)pMem
;
365 /* All done, unlock the heap and return the handle */
366 RtlUnlockHeap(hProcessHeap
);
375 GlobalLock(HGLOBAL hMem
)
377 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
380 /* Check if this was a simple allocated heap entry */
381 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
383 /* Verify and return the pointer */
384 return IsBadReadPtr(hMem
, 1) ? NULL
: hMem
;
387 /* Otherwise, lock the heap */
388 RtlLockHeap(hProcessHeap
);
392 /* Get the handle entry */
393 HandleEntry
= BaseHeapGetEntry(hMem
);
394 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
396 /* Make sure it's valid */
397 if (!BaseHeapValidateEntry(HandleEntry
))
400 BASE_TRACE_FAILURE();
401 SetLastError(ERROR_INVALID_HANDLE
);
406 /* Otherwise, get the pointer */
407 Ptr
= HandleEntry
->Object
;
410 /* Increase the lock count, unless we've went too far */
411 if (HandleEntry
->LockCount
++ == GMEM_LOCKCOUNT
)
413 /* In which case we simply unlock once */
414 HandleEntry
->LockCount
--;
419 /* The handle is still there but the memory was already freed */
420 SetLastError(ERROR_DISCARDED
);
424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
426 SetLastError(ERROR_INVALID_HANDLE
);
431 /* All done. Unlock the heap and return the pointer */
432 RtlUnlockHeap(hProcessHeap
);
438 GlobalReAlloc(HGLOBAL hMem
,
442 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
447 /* Convert ZEROINIT */
448 if (uFlags
& GMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
450 /* If this wasn't a movable heap, then we MUST re-alloc in place */
451 if (!(uFlags
& GMEM_MOVEABLE
)) Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
453 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
454 RtlLockHeap(hProcessHeap
);
455 Flags
|= HEAP_NO_SERIALIZE
;
457 /* Check if this is a simple handle-based block */
458 if (((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
461 HandleEntry
= BaseHeapGetEntry(hMem
);
462 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
464 /* Make sure the handle is valid */
465 if (!BaseHeapValidateEntry(HandleEntry
))
468 BASE_TRACE_FAILURE();
469 SetLastError(ERROR_INVALID_HANDLE
);
472 else if (uFlags
& GMEM_MODIFY
)
474 /* User is changing flags... check if the memory was discardable */
475 if (uFlags
& GMEM_DISCARDABLE
)
477 /* Then set the flag */
478 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
482 /* Otherwise, remove the flag */
483 HandleEntry
->Flags
&= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
488 /* Otherwise, get the object and check if we have no size */
489 Ptr
= HandleEntry
->Object
;
492 /* Clear the handle and check for a pointer */
496 /* Make sure the handle isn't locked */
497 if ((uFlags
& GMEM_MOVEABLE
) && !(HandleEntry
->LockCount
))
499 /* Free the current heap */
500 RtlFreeHeap(hProcessHeap
, Flags
, Ptr
);
502 /* Free the handle */
503 HandleEntry
->Object
= NULL
;
504 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
506 /* Get the object pointer */
507 hMem
= &HandleEntry
->Object
;
512 /* Otherwise just return the object pointer */
513 hMem
= &HandleEntry
->Object
;
518 /* Otherwise, we're allocating, so set the new flags needed */
519 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
522 /* We don't have a base, so allocate one */
523 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
524 BASE_TRACE_ALLOC2(Ptr
);
527 /* Allocation succeeded, so save our entry */
528 RtlSetUserValueHeap(hProcessHeap
,
532 RtlSetUserFlagsHeap(hProcessHeap
,
541 * If it's not movable or currently locked, we MUST allocate
544 if (!(uFlags
& GMEM_MOVEABLE
) && (HandleEntry
->LockCount
))
547 Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
551 /* Otherwise clear the flag if we set it previously */
552 Flags
&= ~HEAP_REALLOC_IN_PLACE_ONLY
;
555 /* And do the re-allocation */
556 Ptr
= RtlReAllocateHeap(hProcessHeap
, Flags
, Ptr
, dwBytes
);
560 /* Allocation succeeded, so save our entry */
561 RtlSetUserValueHeap(hProcessHeap
,
565 RtlSetUserFlagsHeap(hProcessHeap
,
573 /* Make sure we have a pointer by now */
576 /* Write it in the handle entry and mark it in use */
577 HandleEntry
->Object
= Ptr
;
578 HandleEntry
->Flags
&= ~BASE_HEAP_ENTRY_FLAG_REUSE
;
582 /* Otherwise we failed */
584 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
589 else if (uFlags
& GMEM_MODIFY
)
591 /* This is not a handle-based heap and the caller wants it to be one */
592 if (uFlags
& GMEM_MOVEABLE
)
594 /* Get information on its current state */
596 DPRINT1("h h %lx %lx\n", Handle
, hMem
);
597 RtlGetUserInfoHeap(hProcessHeap
,
602 DPRINT1("h h %lx %lx\n", Handle
, hMem
);
605 * Check if the handle matches the pointer or if the moveable flag
606 * isn't there, which is what we expect since it currenly isn't.
608 if (Handle
== hMem
|| !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
610 /* Allocate a handle for it */
611 HandleEntry
= BaseHeapAllocEntry();
613 /* Calculate the size of the current heap */
614 dwBytes
= RtlSizeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
616 /* Set the movable flag */
617 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
619 /* Now allocate the actual heap for it */
620 HandleEntry
->Object
= RtlAllocateHeap(hProcessHeap
,
623 BASE_TRACE_PTR(HandleEntry
->Object
, HandleEntry
);
624 if (!HandleEntry
->Object
)
627 * We failed, manually set the allocate flag and
630 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
631 BaseHeapFreeEntry(HandleEntry
);
633 /* For the cleanup case */
634 BASE_TRACE_FAILURE();
636 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
640 /* Otherwise, copy the current heap and free the old one */
641 RtlMoveMemory(HandleEntry
->Object
, hMem
, dwBytes
);
642 RtlFreeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
644 /* Select the heap pointer */
645 hMem
= (HANDLE
)&HandleEntry
->Object
;
647 /* Initialize the count and default flags */
648 HandleEntry
->LockCount
= 0;
649 HandleEntry
->Flags
= RTL_HANDLE_VALID
|
650 BASE_HEAP_ENTRY_FLAG_MOVABLE
;
652 /* Check if it's also discardable */
653 if (uFlags
& GMEM_DISCARDABLE
)
655 /* Set the internal flag */
656 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
659 /* Check if it's also DDE Shared */
660 if (uFlags
& GMEM_DDESHARE
)
662 /* Set the internal flag */
663 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
666 /* Allocation succeeded, so save our entry */
667 RtlSetUserValueHeap(hProcessHeap
,
671 RtlSetUserFlagsHeap(hProcessHeap
,
681 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
682 hMem
= RtlReAllocateHeap(hProcessHeap
,
683 Flags
| HEAP_NO_SERIALIZE
,
689 BASE_TRACE_FAILURE();
690 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
694 /* All done, unlock the heap and return the pointer */
695 RtlUnlockHeap(hProcessHeap
);
704 GlobalSize(HGLOBAL hMem
)
706 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
709 SIZE_T dwSize
= MAXULONG_PTR
;
712 RtlLockHeap(hProcessHeap
);
716 /* Check if this is a simple RTL Heap Managed block */
717 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
719 /* Then we'll query RTL Heap */
720 RtlGetUserInfoHeap(hProcessHeap
, Flags
, hMem
, &Handle
, &Flags
);
721 BASE_TRACE_PTR(Handle
, hMem
);
724 * Check if RTL Heap didn't give us a handle or said that this heap
727 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
729 /* This implies we're not a handle heap, so use the generic call */
730 dwSize
= RtlSizeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
734 /* Otherwise we're a handle heap, so get the internal handle */
739 /* Make sure that this is an entry in our handle database */
740 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
743 HandleEntry
= BaseHeapGetEntry(hMem
);
744 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
746 /* Make sure the handle is valid */
747 if (!BaseHeapValidateEntry(HandleEntry
))
750 BASE_TRACE_FAILURE();
751 SetLastError(ERROR_INVALID_HANDLE
);
753 else if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
755 /* We've reused this block, but we've saved the size for you */
756 dwSize
= HandleEntry
->OldSize
;
760 /* Otherwise, query RTL about it */
761 dwSize
= RtlSizeHeap(hProcessHeap
,
763 HandleEntry
->Object
);
767 /* Check if by now, we still haven't gotten any useful size */
768 if (dwSize
== MAXULONG_PTR
)
771 BASE_TRACE_FAILURE();
772 SetLastError(ERROR_INVALID_HANDLE
);
776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
778 SetLastError(ERROR_INVALID_HANDLE
);
783 /* All done! Unlock heap and return the size */
784 RtlUnlockHeap(hProcessHeap
);
793 GlobalUnfix(HGLOBAL hMem
)
795 /* If the handle is valid, unlock it */
796 if (hMem
!= INVALID_HANDLE_VALUE
) GlobalUnlock(hMem
);
804 GlobalUnlock(HGLOBAL hMem
)
806 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
809 /* Check if this was a simple allocated heap entry */
810 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)) return RetVal
;
812 /* Otherwise, lock the heap */
813 RtlLockHeap(hProcessHeap
);
815 /* Get the handle entry */
816 HandleEntry
= BaseHeapGetEntry(hMem
);
817 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
821 /* Make sure it's valid */
822 if (!BaseHeapValidateEntry(HandleEntry
))
825 BASE_TRACE_FAILURE();
826 SetLastError(ERROR_INVALID_HANDLE
);
831 /* Otherwise, decrement lock count, unless we're already at 0*/
832 if (!HandleEntry
->LockCount
--)
834 /* In which case we simply lock it back and fail */
835 HandleEntry
->LockCount
++;
836 SetLastError(ERROR_NOT_LOCKED
);
839 else if (!HandleEntry
->LockCount
)
841 /* Nothing to unlock */
842 SetLastError(NO_ERROR
);
847 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
849 SetLastError(ERROR_INVALID_PARAMETER
);
854 /* All done. Unlock the heap and return the pointer */
855 RtlUnlockHeap(hProcessHeap
);
864 GlobalUnWire(HGLOBAL hMem
)
866 /* This is simply an unlock */
867 return GlobalUnlock(hMem
);
875 GlobalWire(HGLOBAL hMem
)
877 /* This is just a lock */
878 return GlobalLock(hMem
);
886 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer
)
888 SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo
;
889 VM_COUNTERS VmCounters
;
890 QUOTA_LIMITS QuotaLimits
;
891 ULONGLONG PageFile
, PhysicalMemory
;
893 /* Query performance information */
894 NtQuerySystemInformation(SystemPerformanceInformation
,
896 sizeof(PerformanceInfo
),
899 /* Calculate memory load */
900 lpBuffer
->dwMemoryLoad
= ((DWORD
)(BaseCachedSysInfo
.NumberOfPhysicalPages
-
901 PerformanceInfo
.AvailablePages
) * 100) /
902 BaseCachedSysInfo
.NumberOfPhysicalPages
;
904 /* Save physical memory */
905 PhysicalMemory
= BaseCachedSysInfo
.NumberOfPhysicalPages
*
906 BaseCachedSysInfo
.PageSize
;
907 lpBuffer
->ullTotalPhys
= PhysicalMemory
;
909 /* Now save available physical memory */
910 PhysicalMemory
= PerformanceInfo
.AvailablePages
*
911 BaseCachedSysInfo
.PageSize
;
912 lpBuffer
->ullAvailPhys
= PhysicalMemory
;
914 /* Query VM and Quota Limits */
915 NtQueryInformationProcess(NtCurrentProcess(),
918 sizeof(QUOTA_LIMITS
),
920 NtQueryInformationProcess(NtCurrentProcess(),
926 /* Save the commit limit */
927 lpBuffer
->ullTotalPageFile
= min(QuotaLimits
.PagefileLimit
,
928 PerformanceInfo
.CommitLimit
);
930 /* Calculate how many pages are left */
931 PageFile
= PerformanceInfo
.CommitLimit
- PerformanceInfo
.CommittedPages
;
934 lpBuffer
->ullAvailPageFile
= min(PageFile
,
935 QuotaLimits
.PagefileLimit
-
936 VmCounters
.PagefileUsage
);
937 lpBuffer
->ullAvailPageFile
*= BaseCachedSysInfo
.PageSize
;
939 /* Now calculate the total virtual space */
940 lpBuffer
->ullTotalVirtual
= (BaseCachedSysInfo
.MaximumUserModeAddress
-
941 BaseCachedSysInfo
.MinimumUserModeAddress
) + 1;
943 /* And finally the avilable virtual space */
944 lpBuffer
->ullAvailVirtual
= lpBuffer
->ullTotalVirtual
-
945 VmCounters
.VirtualSize
;
946 lpBuffer
->ullAvailExtendedVirtual
= 0;
955 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer
)
957 MEMORYSTATUSEX lpBufferEx
;
959 /* Call the extended function */
960 lpBufferEx
.dwLength
= sizeof(MEMORYSTATUSEX
);
961 if (GlobalMemoryStatusEx(&lpBufferEx
))
963 /* Reset the right size and fill out the information */
964 lpBuffer
->dwLength
= sizeof(MEMORYSTATUS
);
965 lpBuffer
->dwMemoryLoad
= lpBufferEx
.dwMemoryLoad
;
966 lpBuffer
->dwTotalPhys
= (SIZE_T
)lpBufferEx
.ullTotalPhys
;
967 lpBuffer
->dwAvailPhys
= (SIZE_T
)lpBufferEx
.ullAvailPhys
;
968 lpBuffer
->dwTotalPageFile
= (SIZE_T
)lpBufferEx
.ullTotalPageFile
;
969 lpBuffer
->dwAvailPageFile
= (SIZE_T
)lpBufferEx
.ullAvailPageFile
;
970 lpBuffer
->dwTotalVirtual
= (SIZE_T
)lpBufferEx
.ullTotalVirtual
;
971 lpBuffer
->dwAvailVirtual
= (SIZE_T
)lpBufferEx
.ullAvailVirtual
;