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
);
108 /* Cleanup! First unlock the heap */
109 RtlUnlockHeap(hProcessHeap
);
111 /* Check if a handle was allocated */
114 /* Set the pointer and allocated flag */
115 HandleEntry
->Object
= Ptr
;
116 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
119 /* We don't have a valid pointer, but so reuse this handle */
120 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
123 /* Check if the handle is discardable */
124 if (uFlags
& GMEM_DISCARDABLE
)
126 /* Save it in the handle entry */
127 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
130 /* Check if the handle is moveable */
131 if (uFlags
& GMEM_MOVEABLE
)
133 /* Save it in the handle entry */
134 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_MOVABLE
;
137 /* Check if the handle is DDE Shared */
138 if (uFlags
& GMEM_DDESHARE
)
140 /* Save it in the handle entry */
141 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
144 /* Set the pointer */
148 /* Return the pointer */
157 GlobalCompact(DWORD dwMinFree
)
159 /* Call the RTL Heap Manager */
160 return RtlCompactHeap(hProcessHeap
, 0);
168 GlobalFix(HGLOBAL hMem
)
170 /* Lock the memory if it the handle is valid */
171 if (INVALID_HANDLE_VALUE
!= hMem
) GlobalLock(hMem
);
179 GlobalFlags(HGLOBAL hMem
)
181 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
182 HANDLE Handle
= NULL
;
184 UINT uFlags
= GMEM_INVALID_HANDLE
;
186 /* Start by locking the heap */
187 RtlLockHeap(hProcessHeap
);
189 /* Check if this is a simple RTL Heap Managed block */
190 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
192 /* Then we'll query RTL Heap */
193 RtlGetUserInfoHeap(hProcessHeap
, Flags
, hMem
, &Handle
, &Flags
);
194 BASE_TRACE_PTR(Handle
, hMem
);
197 * Check if RTL Heap didn't find a handle associated with us or
198 * said that this heap isn't movable, which means something we're
199 * really not a handle-based heap.
201 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
203 /* Then set the flags to 0 */
208 /* Otherwise we're handle-based, so get the internal handle */
213 /* Check if the handle is actually an entry in our table */
214 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
216 /* Then get the entry */
217 HandleEntry
= BaseHeapGetEntry(hMem
);
218 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
220 /* Make sure it's a valid handle */
221 if (BaseHeapValidateEntry(HandleEntry
))
223 /* Get the lock count first */
224 uFlags
= HandleEntry
->LockCount
& GMEM_LOCKCOUNT
;
226 /* Now check if it's discardable */
227 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSABLE
)
229 /* Set the Win32 Flag */
230 uFlags
|= GMEM_DISCARDABLE
;
233 /* Check if it's DDE Shared */
234 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_DDESHARE
)
236 /* Set the Win32 Flag */
237 uFlags
|= GMEM_DDESHARE
;
240 /* Now check if it's discarded */
241 if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
242 /* Set the Win32 Flag */
243 uFlags
|= GMEM_DISCARDED
;
247 /* Check if by now, we still haven't gotten any useful flags */
248 if (uFlags
== GMEM_INVALID_HANDLE
) SetLastError(ERROR_INVALID_HANDLE
);
250 /* All done! Unlock heap and return Win32 Flags */
251 RtlUnlockHeap(hProcessHeap
);
260 GlobalFree(HGLOBAL hMem
)
262 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
264 BASE_TRACE_DEALLOC(hMem
);
266 /* Check if this was a simple allocated heap entry */
267 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
269 /* Free it with the RTL Heap Manager */
270 if (RtlFreeHeap(hProcessHeap
, 0, hMem
))
272 /* Return NULL since there's no handle */
278 BASE_TRACE_FAILURE();
279 SetLastError(ERROR_INVALID_HANDLE
);
284 /* It's a handle probably, so lock the heap */
285 RtlLockHeap(hProcessHeap
);
287 /* Make sure that this is an entry in our handle database */
288 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
291 HandleEntry
= BaseHeapGetEntry(hMem
);
292 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
294 /* Make sure the handle is valid */
295 if (!BaseHeapValidateEntry(HandleEntry
))
298 SetLastError(ERROR_INVALID_HANDLE
);
303 /* It's valid, so get the pointer */
304 Ptr
= HandleEntry
->Object
;
306 /* Free this handle */
307 BaseHeapFreeEntry(HandleEntry
);
309 /* If the pointer is 0, then we don't have a handle either */
310 if (!Ptr
) hMem
= NULL
;
315 /* Otherwise, reuse the handle as a pointer */
316 BASE_TRACE_FAILURE();
320 /* Check if we got here with a valid heap pointer */
324 RtlFreeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, Ptr
);
328 /* We're done, so unlock the heap and return the handle */
329 RtlUnlockHeap(hProcessHeap
);
338 GlobalHandle(LPCVOID pMem
)
340 HANDLE Handle
= NULL
;
344 RtlLockHeap(hProcessHeap
);
347 RtlGetUserInfoHeap(hProcessHeap
,
352 BASE_TRACE_PTR(Handle
, pMem
);
355 * Check if RTL Heap didn't find a handle for us or said that
356 * this heap isn't movable.
358 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
360 /* We're actually handle-based, so the pointer is a handle */
361 Handle
= (HANDLE
)pMem
;
364 /* All done, unlock the heap and return the handle */
365 RtlUnlockHeap(hProcessHeap
);
374 GlobalLock(HGLOBAL hMem
)
376 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
379 /* Check if this was a simple allocated heap entry */
380 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
382 /* Verify and return the pointer */
383 return IsBadReadPtr(hMem
, 1) ? NULL
: hMem
;
386 /* Otherwise, lock the heap */
387 RtlLockHeap(hProcessHeap
);
391 /* Get the handle entry */
392 HandleEntry
= BaseHeapGetEntry(hMem
);
393 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
395 /* Make sure it's valid */
396 if (!BaseHeapValidateEntry(HandleEntry
))
399 BASE_TRACE_FAILURE();
400 SetLastError(ERROR_INVALID_HANDLE
);
405 /* Otherwise, get the pointer */
406 Ptr
= HandleEntry
->Object
;
409 /* Increase the lock count, unless we've went too far */
410 if (HandleEntry
->LockCount
++ == GMEM_LOCKCOUNT
)
412 /* In which case we simply unlock once */
413 HandleEntry
->LockCount
--;
418 /* The handle is still there but the memory was already freed */
419 SetLastError(ERROR_DISCARDED
);
423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
425 SetLastError(ERROR_INVALID_HANDLE
);
430 /* All done. Unlock the heap and return the pointer */
431 RtlUnlockHeap(hProcessHeap
);
437 GlobalReAlloc(HGLOBAL hMem
,
441 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
446 /* Convert ZEROINIT */
447 if (uFlags
& GMEM_ZEROINIT
) Flags
|= HEAP_ZERO_MEMORY
;
449 /* If this wasn't a movable heap, then we MUST re-alloc in place */
450 if (!(uFlags
& GMEM_MOVEABLE
)) Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
452 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
453 RtlLockHeap(hProcessHeap
);
454 Flags
|= HEAP_NO_SERIALIZE
;
456 /* Check if this is a simple handle-based block */
457 if (((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
460 HandleEntry
= BaseHeapGetEntry(hMem
);
461 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
463 /* Make sure the handle is valid */
464 if (!BaseHeapValidateEntry(HandleEntry
))
467 BASE_TRACE_FAILURE();
468 SetLastError(ERROR_INVALID_HANDLE
);
471 else if (uFlags
& GMEM_MODIFY
)
473 /* User is changing flags... check if the memory was discardable */
474 if (uFlags
& GMEM_DISCARDABLE
)
476 /* Then set the flag */
477 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
481 /* Otherwise, remove the flag */
482 HandleEntry
->Flags
&= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
487 /* Otherwise, get the object and check if we have no size */
488 Ptr
= HandleEntry
->Object
;
491 /* Clear the handle and check for a pointer */
495 /* Make sure the handle isn't locked */
496 if ((uFlags
& GMEM_MOVEABLE
) && !(HandleEntry
->LockCount
))
498 /* Free the current heap */
499 RtlFreeHeap(hProcessHeap
, Flags
, Ptr
);
501 /* Free the handle */
502 HandleEntry
->Object
= NULL
;
503 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSE
;
505 /* Get the object pointer */
506 hMem
= &HandleEntry
->Object
;
511 /* Otherwise just return the object pointer */
512 hMem
= &HandleEntry
->Object
;
517 /* Otherwise, we're allocating, so set the new flags needed */
518 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
521 /* We don't have a base, so allocate one */
522 Ptr
= RtlAllocateHeap(hProcessHeap
, Flags
, dwBytes
);
523 BASE_TRACE_ALLOC2(Ptr
);
526 /* Allocation succeeded, so save our entry */
527 RtlSetUserValueHeap(hProcessHeap
,
536 * If it's not movable or currently locked, we MUST allocate
539 if (!(uFlags
& GMEM_MOVEABLE
) && (HandleEntry
->LockCount
))
542 Flags
|= HEAP_REALLOC_IN_PLACE_ONLY
;
546 /* Otherwise clear the flag if we set it previously */
547 Flags
&= ~HEAP_REALLOC_IN_PLACE_ONLY
;
550 /* And do the re-allocation */
551 Ptr
= RtlReAllocateHeap(hProcessHeap
, Flags
, Ptr
, dwBytes
);
555 /* Allocation succeeded, so save our entry */
556 RtlSetUserValueHeap(hProcessHeap
,
564 /* Make sure we have a pointer by now */
567 /* Write it in the handle entry and mark it in use */
568 HandleEntry
->Object
= Ptr
;
569 HandleEntry
->Flags
&= ~BASE_HEAP_ENTRY_FLAG_REUSE
;
573 /* Otherwise we failed */
575 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
580 else if (uFlags
& GMEM_MODIFY
)
582 /* This is not a handle-based heap and the caller wants it to be one */
583 if (uFlags
& GMEM_MOVEABLE
)
585 /* Get information on its current state */
587 DPRINT1("h h %lx %lx\n", Handle
, hMem
);
588 RtlGetUserInfoHeap(hProcessHeap
,
593 DPRINT1("h h %lx %lx\n", Handle
, hMem
);
596 * Check if the handle matches the pointer or if the moveable flag
597 * isn't there, which is what we expect since it currenly isn't.
599 if (Handle
== hMem
|| !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
601 /* Allocate a handle for it */
602 HandleEntry
= BaseHeapAllocEntry();
604 /* Calculate the size of the current heap */
605 dwBytes
= RtlSizeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
607 /* Set the movable flag */
608 Flags
|= HEAP_SETTABLE_USER_VALUE
| BASE_HEAP_FLAG_MOVABLE
;
610 /* Now allocate the actual heap for it */
611 HandleEntry
->Object
= RtlAllocateHeap(hProcessHeap
,
614 BASE_TRACE_PTR(HandleEntry
->Object
, HandleEntry
);
615 if (!HandleEntry
->Object
)
618 * We failed, manually set the allocate flag and
621 HandleEntry
->Flags
= RTL_HANDLE_VALID
;
622 BaseHeapFreeEntry(HandleEntry
);
624 /* For the cleanup case */
625 BASE_TRACE_FAILURE();
627 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
631 /* Otherwise, copy the current heap and free the old one */
632 RtlMoveMemory(HandleEntry
->Object
, hMem
, dwBytes
);
633 RtlFreeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
635 /* Select the heap pointer */
636 hMem
= (HANDLE
)&HandleEntry
->Object
;
638 /* Initialize the count and default flags */
639 HandleEntry
->LockCount
= 0;
640 HandleEntry
->Flags
= RTL_HANDLE_VALID
|
641 BASE_HEAP_ENTRY_FLAG_MOVABLE
;
643 /* Check if it's also discardable */
644 if (uFlags
& GMEM_DISCARDABLE
)
646 /* Set the internal flag */
647 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_REUSABLE
;
650 /* Check if it's also DDE Shared */
651 if (uFlags
& GMEM_DDESHARE
)
653 /* Set the internal flag */
654 HandleEntry
->Flags
|= BASE_HEAP_ENTRY_FLAG_DDESHARE
;
657 /* Allocation succeeded, so save our entry */
658 RtlSetUserValueHeap(hProcessHeap
,
668 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
669 hMem
= RtlReAllocateHeap(hProcessHeap
,
670 Flags
| HEAP_NO_SERIALIZE
,
676 BASE_TRACE_FAILURE();
677 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
681 /* All done, unlock the heap and return the pointer */
682 RtlUnlockHeap(hProcessHeap
);
691 GlobalSize(HGLOBAL hMem
)
693 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
696 SIZE_T dwSize
= MAXULONG_PTR
;
699 RtlLockHeap(hProcessHeap
);
703 /* Check if this is a simple RTL Heap Managed block */
704 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
))
706 /* Then we'll query RTL Heap */
707 RtlGetUserInfoHeap(hProcessHeap
, Flags
, hMem
, &Handle
, &Flags
);
708 BASE_TRACE_PTR(Handle
, hMem
);
711 * Check if RTL Heap didn't give us a handle or said that this heap
714 if (!(Handle
) || !(Flags
& BASE_HEAP_FLAG_MOVABLE
))
716 /* This implies we're not a handle heap, so use the generic call */
717 dwSize
= RtlSizeHeap(hProcessHeap
, HEAP_NO_SERIALIZE
, hMem
);
721 /* Otherwise we're a handle heap, so get the internal handle */
726 /* Make sure that this is an entry in our handle database */
727 if ((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)
730 HandleEntry
= BaseHeapGetEntry(hMem
);
731 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
733 /* Make sure the handle is valid */
734 if (!BaseHeapValidateEntry(HandleEntry
))
737 BASE_TRACE_FAILURE();
738 SetLastError(ERROR_INVALID_HANDLE
);
740 else if (HandleEntry
->Flags
& BASE_HEAP_ENTRY_FLAG_REUSE
)
742 /* We've reused this block, but we've saved the size for you */
743 dwSize
= HandleEntry
->OldSize
;
747 /* Otherwise, query RTL about it */
748 dwSize
= RtlSizeHeap(hProcessHeap
,
750 HandleEntry
->Object
);
754 /* Check if by now, we still haven't gotten any useful size */
755 if (dwSize
== MAXULONG_PTR
)
758 BASE_TRACE_FAILURE();
759 SetLastError(ERROR_INVALID_HANDLE
);
763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
765 SetLastError(ERROR_INVALID_HANDLE
);
770 /* All done! Unlock heap and return the size */
771 RtlUnlockHeap(hProcessHeap
);
780 GlobalUnfix(HGLOBAL hMem
)
782 /* If the handle is valid, unlock it */
783 if (hMem
!= INVALID_HANDLE_VALUE
) GlobalUnlock(hMem
);
791 GlobalUnlock(HGLOBAL hMem
)
793 PBASE_HEAP_HANDLE_ENTRY HandleEntry
;
796 /* Check if this was a simple allocated heap entry */
797 if (!((ULONG_PTR
)hMem
& BASE_HEAP_IS_HANDLE_ENTRY
)) return RetVal
;
799 /* Otherwise, lock the heap */
800 RtlLockHeap(hProcessHeap
);
802 /* Get the handle entry */
803 HandleEntry
= BaseHeapGetEntry(hMem
);
804 BASE_TRACE_HANDLE(HandleEntry
, hMem
);
808 /* Make sure it's valid */
809 if (!BaseHeapValidateEntry(HandleEntry
))
812 BASE_TRACE_FAILURE();
813 SetLastError(ERROR_INVALID_HANDLE
);
818 /* Otherwise, decrement lock count, unless we're already at 0*/
819 if (!HandleEntry
->LockCount
--)
821 /* In which case we simply lock it back and fail */
822 HandleEntry
->LockCount
++;
823 SetLastError(ERROR_NOT_LOCKED
);
826 else if (!HandleEntry
->LockCount
)
828 /* Nothing to unlock */
829 SetLastError(NO_ERROR
);
834 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
836 SetLastError(ERROR_INVALID_PARAMETER
);
841 /* All done. Unlock the heap and return the pointer */
842 RtlUnlockHeap(hProcessHeap
);
851 GlobalUnWire(HGLOBAL hMem
)
853 /* This is simply an unlock */
854 return GlobalUnlock(hMem
);
862 GlobalWire(HGLOBAL hMem
)
864 /* This is just a lock */
865 return GlobalLock(hMem
);
873 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer
)
875 SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo
;
876 VM_COUNTERS VmCounters
;
877 QUOTA_LIMITS QuotaLimits
;
878 ULONGLONG PageFile
, PhysicalMemory
;
880 /* Query performance information */
881 NtQuerySystemInformation(SystemPerformanceInformation
,
883 sizeof(PerformanceInfo
),
886 /* Calculate memory load */
887 lpBuffer
->dwMemoryLoad
= ((DWORD
)(BaseCachedSysInfo
.NumberOfPhysicalPages
-
888 PerformanceInfo
.AvailablePages
) * 100) /
889 BaseCachedSysInfo
.NumberOfPhysicalPages
;
891 /* Save physical memory */
892 PhysicalMemory
= BaseCachedSysInfo
.NumberOfPhysicalPages
*
893 BaseCachedSysInfo
.PageSize
;
894 lpBuffer
->ullTotalPhys
= PhysicalMemory
;
896 /* Now save available physical memory */
897 PhysicalMemory
= PerformanceInfo
.AvailablePages
*
898 BaseCachedSysInfo
.PageSize
;
899 lpBuffer
->ullAvailPhys
= PhysicalMemory
;
901 /* Query VM and Quota Limits */
902 NtQueryInformationProcess(NtCurrentProcess(),
905 sizeof(QUOTA_LIMITS
),
907 NtQueryInformationProcess(NtCurrentProcess(),
913 /* Save the commit limit */
914 lpBuffer
->ullTotalPageFile
= min(QuotaLimits
.PagefileLimit
,
915 PerformanceInfo
.CommitLimit
);
917 /* Calculate how many pages are left */
918 PageFile
= PerformanceInfo
.CommitLimit
- PerformanceInfo
.CommittedPages
;
921 lpBuffer
->ullAvailPageFile
= min(PageFile
,
922 QuotaLimits
.PagefileLimit
-
923 VmCounters
.PagefileUsage
);
924 lpBuffer
->ullAvailPageFile
*= BaseCachedSysInfo
.PageSize
;
926 /* Now calculate the total virtual space */
927 lpBuffer
->ullTotalVirtual
= (BaseCachedSysInfo
.MaximumUserModeAddress
-
928 BaseCachedSysInfo
.MinimumUserModeAddress
) + 1;
930 /* And finally the avilable virtual space */
931 lpBuffer
->ullAvailVirtual
= lpBuffer
->ullTotalVirtual
-
932 VmCounters
.VirtualSize
;
933 lpBuffer
->ullAvailExtendedVirtual
= 0;
942 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer
)
944 MEMORYSTATUSEX lpBufferEx
;
946 /* Call the extended function */
947 lpBufferEx
.dwLength
= sizeof(MEMORYSTATUSEX
);
948 if (GlobalMemoryStatusEx(&lpBufferEx
))
950 /* Reset the right size and fill out the information */
951 lpBuffer
->dwLength
= sizeof(MEMORYSTATUS
);
952 lpBuffer
->dwMemoryLoad
= lpBufferEx
.dwMemoryLoad
;
953 lpBuffer
->dwTotalPhys
= (SIZE_T
)lpBufferEx
.ullTotalPhys
;
954 lpBuffer
->dwAvailPhys
= (SIZE_T
)lpBufferEx
.ullAvailPhys
;
955 lpBuffer
->dwTotalPageFile
= (SIZE_T
)lpBufferEx
.ullTotalPageFile
;
956 lpBuffer
->dwAvailPageFile
= (SIZE_T
)lpBufferEx
.ullAvailPageFile
;
957 lpBuffer
->dwTotalVirtual
= (SIZE_T
)lpBufferEx
.ullTotalVirtual
;
958 lpBuffer
->dwAvailVirtual
= (SIZE_T
)lpBufferEx
.ullAvailVirtual
;