3 * Win32 Global/Local heap functions (GlobalXXX, LocalXXX).
4 * These functions included in Win32 for compatibility with 16 bit Windows
5 * Especially the moveable blocks and handles are oldish.
6 * But the ability to directly allocate memory with GPTR and LPTR is widely
9 * Updated to support movable memory with algorithms taken from wine.
15 #include "../include/debug.h"
18 #define STRUCT_PACK __attribute__((packed))
23 #define MAGIC_GLOBAL_USED 0x5342BEEF
24 #define GLOBAL_LOCK_MAX 0xFF
26 /*Wine found that some applications complain if memory isn't 8 byte aligned.
27 * We make use of that experience here.
29 #define HANDLE_SIZE 8 /*sizeof(HANDLE) *2 */
32 typedef struct __GLOBAL_LOCAL_HANDLE
35 LPVOID Pointer
; STRUCT_PACK
38 } GLOBAL_HANDLE
, LOCAL_HANDLE
, *PGLOBAL_HANDLE
, *PLOCAL_HANDLE
;
40 #define HANDLE_TO_INTERN(h) ((PGLOBAL_HANDLE)(((char *)(h))-4))
41 #define INTERN_TO_HANDLE(i) ((HGLOBAL) &((i)->Pointer))
42 #define POINTER_TO_HANDLE(p) (*(PHANDLE)((ULONG_PTR)p - HANDLE_SIZE))
43 #define ISHANDLE(h) ((((ULONG)(h)) & 0x4)!=0)
44 #define ISPOINTER(h) ((((ULONG)(h)) & 0x4)==0)
47 static void DbgPrintStruct(PGLOBAL_HANDLE h
)
49 DPRINT("Magic: 0x%X\n", h
->Magic
);
50 DPRINT("Pointer: 0x%X\n", h
->Pointer
);
51 DPRINT("Flags: 0x%X\n", h
->Flags
);
52 DPRINT("LockCount: 0x%X\n", h
->LockCount
);
57 /* FUNCTIONS ***************************************************************/
63 GlobalAlloc(UINT uFlags
,
67 PGLOBAL_HANDLE phandle
= 0;
71 if (uFlags
& GMEM_ZEROINIT
)
73 heap_flags
= HEAP_ZERO_MEMORY
;
76 DPRINT("GlobalAlloc( 0x%X, 0x%lX )\n", uFlags
, dwBytes
);
78 //Changed hProcessHeap to GetProcessHeap()
79 if ((uFlags
& GMEM_MOVEABLE
)==0) /* POINTER */
81 palloc
= RtlAllocateHeap(GetProcessHeap(), heap_flags
, dwBytes
);
82 if (! ISPOINTER(palloc
))
84 DPRINT1("GlobalAlloced pointer which is not 8-byte aligned\n");
85 RtlFreeHeap(GetProcessHeap(), 0, palloc
);
88 return (HGLOBAL
) palloc
;
92 HeapLock(hProcessHeap
);
94 phandle
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof(GLOBAL_HANDLE
));
97 phandle
->Magic
= MAGIC_GLOBAL_USED
;
98 phandle
->Flags
= uFlags
>> 8;
99 phandle
->LockCount
= 0;
100 phandle
->Pointer
= 0;
104 palloc
= RtlAllocateHeap(GetProcessHeap(), heap_flags
, dwBytes
+ HANDLE_SIZE
);
107 *(PHANDLE
)palloc
= INTERN_TO_HANDLE(phandle
);
108 phandle
->Pointer
= (PVOID
)((ULONG_PTR
)palloc
+ HANDLE_SIZE
);
110 else /*failed to allocate the memory block*/
112 RtlFreeHeap(GetProcessHeap(), 0, phandle
);
118 DPRINT("Allocated a 0 size movable block.\n");
119 DbgPrintStruct(phandle
);
120 DPRINT("Address of the struct: 0x%X\n", phandle
);
121 DPRINT("Address of pointer: 0x%X\n", &(phandle
->Pointer
));
124 HeapUnlock(hProcessHeap
);
128 if (ISPOINTER(INTERN_TO_HANDLE(phandle
)))
130 DPRINT1("GlobalAlloced handle which is 8-byte aligned but shouldn't be\n");
131 RtlFreeHeap(GetProcessHeap(), 0, palloc
);
132 RtlFreeHeap(GetProcessHeap(), 0, phandle
);
135 return INTERN_TO_HANDLE(phandle
);
147 GlobalCompact(DWORD dwMinFree
)
149 return RtlCompactHeap(hProcessHeap
, 0);
157 GlobalFix(HGLOBAL hMem
)
159 if (INVALID_HANDLE_VALUE
!= hMem
)
167 GlobalFlags(HGLOBAL hMem
)
170 PGLOBAL_HANDLE phandle
;
172 DPRINT("GlobalFlags( 0x%lX )\n", (ULONG
)hMem
);
176 DPRINT("GlobalFlags: Fixed memory.\n");
181 HeapLock(GetProcessHeap());
183 phandle
= HANDLE_TO_INTERN(hMem
);
185 /*DbgPrintStruct(phandle);*/
187 if (MAGIC_GLOBAL_USED
== phandle
->Magic
)
189 /*DbgPrint("GlobalFlags: Magic number ok\n");
190 **DbgPrint("GlobalFlags: pointer is 0x%X\n", phandle->Pointer);
192 retval
= phandle
->LockCount
+ (phandle
->Flags
<< 8);
193 if (0 == phandle
->Pointer
)
195 retval
= retval
| GMEM_DISCARDED
;
200 DPRINT1("GlobalSize: invalid handle\n");
203 HeapUnlock(GetProcessHeap());
213 GlobalFree(HGLOBAL hMem
)
215 PGLOBAL_HANDLE phandle
;
217 DPRINT("GlobalFree( 0x%lX )\n", (ULONG
)hMem
);
219 if (ISPOINTER(hMem
)) /* POINTER */
221 RtlFreeHeap(GetProcessHeap(), 0, (PVOID
)hMem
);
226 HeapLock(GetProcessHeap());
228 phandle
= HANDLE_TO_INTERN(hMem
);
230 if(MAGIC_GLOBAL_USED
== phandle
->Magic
)
233 if(phandle
->LockCount
!=0)
235 DPRINT1("Warning! GlobalFree(0x%X) Freeing a handle to a locked object.\n", hMem
);
236 SetLastError(ERROR_INVALID_HANDLE
);
240 RtlFreeHeap(GetProcessHeap(), 0, (PVOID
)((ULONG_PTR
)phandle
->Pointer
- HANDLE_SIZE
));
242 RtlFreeHeap(GetProcessHeap(), 0, phandle
);
244 HeapUnlock(GetProcessHeap());
256 GlobalHandle(LPCVOID pMem
)
259 PGLOBAL_HANDLE test
= 0;
260 LPCVOID pointer_test
= 0;
262 DPRINT("GlobalHandle( 0x%lX )\n", (ULONG
)pMem
);
263 if (0 == pMem
) /*Invalid argument */
265 SetLastError(ERROR_INVALID_PARAMETER
);
266 DPRINT1("Error: 0 handle.\n");
270 HeapLock(GetProcessHeap());
271 /* Now test to see if this pointer is associated with a handle.
272 * This is done by calling RtlValidateHeap() and seeing if it fails.
274 if (RtlValidateHeap(GetProcessHeap(), 0, (char *)pMem
)) /*FIXED*/
276 handle
= (HGLOBAL
)pMem
;
281 handle
= POINTER_TO_HANDLE(pMem
);
285 /* Test to see if this memory is valid*/
286 test
= HANDLE_TO_INTERN(handle
);
287 if (!IsBadReadPtr(test
, sizeof(GLOBAL_HANDLE
)))
289 if (MAGIC_GLOBAL_USED
== test
->Magic
)
291 pointer_test
= test
->Pointer
;
292 if (!RtlValidateHeap(GetProcessHeap(), 0, ((char *)pointer_test
) - HANDLE_SIZE
) ||
293 !RtlValidateHeap(GetProcessHeap(), 0, test
))
295 SetLastError(ERROR_INVALID_HANDLE
);
302 DPRINT1("GlobalHandle: Bad read pointer.\n");
303 SetLastError(ERROR_INVALID_HANDLE
);
307 HeapUnlock(GetProcessHeap());
317 GlobalLock(HGLOBAL hMem
)
319 PGLOBAL_HANDLE phandle
;
322 DPRINT("GlobalLock( 0x%lX )\n", (ULONG
)hMem
);
325 return (LPVOID
) hMem
;
327 HeapLock(GetProcessHeap());
329 phandle
= HANDLE_TO_INTERN(hMem
);
331 if(MAGIC_GLOBAL_USED
== phandle
->Magic
)
333 if(GLOBAL_LOCK_MAX
> phandle
->LockCount
)
335 phandle
->LockCount
++;
337 palloc
= phandle
->Pointer
;
341 DPRINT("GlobalLock: invalid handle\n");
342 palloc
= (LPVOID
) hMem
;
345 HeapUnlock(GetProcessHeap());
355 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer
)
357 SYSTEM_BASIC_INFORMATION SysBasicInfo
;
358 SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo
;
362 DPRINT("GlobalMemoryStatusEx\n");
364 if (lpBuffer
->dwLength
!= sizeof(MEMORYSTATUSEX
))
366 SetLastError(ERROR_INVALID_PARAMETER
);
370 Status
= ZwQuerySystemInformation(SystemBasicInformation
,
372 sizeof(SysBasicInfo
),
374 if (!NT_SUCCESS(Status
))
376 SetLastErrorByStatus(Status
);
380 Status
= ZwQuerySystemInformation(SystemPerformanceInformation
,
384 if (!NT_SUCCESS(Status
))
386 SetLastErrorByStatus(Status
);
390 Status
= ZwQuerySystemInformation(SystemFullMemoryInformation
,
394 if (!NT_SUCCESS(Status
))
396 SetLastErrorByStatus(Status
);
401 * Load percentage 0 thru 100. 0 is good and 100 is bad.
403 * Um = allocated memory / physical memory
404 * Um = 177 MB / 256 MB = 69.1%
406 * Mult allocated memory by 100 to move decimal point up.
408 lpBuffer
->dwMemoryLoad
= (SysBasicInfo
.NumberOfPhysicalPages
-
409 SysPerfInfo
.AvailablePages
) * 100 /
410 SysBasicInfo
.NumberOfPhysicalPages
;
412 DPRINT1("Memory Load: %d%%\n",lpBuffer
->dwMemoryLoad
);
414 lpBuffer
->ullTotalPhys
= SysBasicInfo
.NumberOfPhysicalPages
*
415 SysBasicInfo
.PageSize
;
416 lpBuffer
->ullAvailPhys
= SysPerfInfo
.AvailablePages
*
417 SysBasicInfo
.PageSize
;
419 DPRINT("%d\n",SysPerfInfo
.AvailablePages
);
420 DPRINT("%d\n",lpBuffer
->ullAvailPhys
);
422 lpBuffer
->ullTotalPageFile
= SysPerfInfo
.CommitLimit
*
423 SysBasicInfo
.PageSize
;
425 DPRINT("%d\n",lpBuffer
->ullTotalPageFile
);
427 lpBuffer
->ullAvailPageFile
= ((SysPerfInfo
.CommitLimit
-
428 SysPerfInfo
.CommittedPages
) *
429 SysBasicInfo
.PageSize
);
431 /* VM available to the calling processes, User Mem? */
432 lpBuffer
->ullTotalVirtual
= SysBasicInfo
.MaximumUserModeAddress
-
433 SysBasicInfo
.MinimumUserModeAddress
;
435 lpBuffer
->ullAvailVirtual
= (lpBuffer
->ullTotalVirtual
-
437 SysBasicInfo
.PageSize
));
439 DPRINT("%d\n",lpBuffer
->ullAvailVirtual
);
440 DPRINT("%d\n",UserMemory
);
441 DPRINT("%d\n",SysBasicInfo
.PageSize
);
443 /* lol! Memory from beyond! */
444 lpBuffer
->ullAvailExtendedVirtual
= 0;
452 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer
)
454 MEMORYSTATUSEX lpBufferEx
;
456 if (lpBuffer
->dwLength
!= sizeof(MEMORYSTATUS
))
458 SetLastError(ERROR_INVALID_PARAMETER
);
462 lpBufferEx
.dwLength
= sizeof(MEMORYSTATUSEX
);
464 if (GlobalMemoryStatusEx(&lpBufferEx
))
467 lpBuffer
->dwLength
= sizeof(MEMORYSTATUS
);
469 lpBuffer
->dwMemoryLoad
= lpBufferEx
.dwMemoryLoad
;
470 lpBuffer
->dwTotalPhys
= lpBufferEx
.ullTotalPhys
;
471 lpBuffer
->dwAvailPhys
= lpBufferEx
.ullAvailPhys
;
472 lpBuffer
->dwTotalPageFile
= lpBufferEx
.ullTotalPageFile
;
473 lpBuffer
->dwAvailPageFile
= lpBufferEx
.ullAvailPageFile
;
474 lpBuffer
->dwTotalVirtual
= lpBufferEx
.ullTotalVirtual
;
475 lpBuffer
->dwAvailVirtual
= lpBufferEx
.ullAvailVirtual
;
481 GlobalReAlloc(HGLOBAL hMem
,
488 PGLOBAL_HANDLE phandle
= 0;
489 ULONG heap_flags
= 0;
491 DPRINT("GlobalReAlloc( 0x%lX, 0x%lX, 0x%X )\n", (ULONG
)hMem
, dwBytes
, uFlags
);
493 if (uFlags
& GMEM_ZEROINIT
)
495 heap_flags
= HEAP_ZERO_MEMORY
;
498 HeapLock(GetProcessHeap());
500 if(uFlags
& GMEM_MODIFY
) /* modify flags */
502 if( ISPOINTER(hMem
) && (uFlags
& GMEM_MOVEABLE
))
504 /* make a fixed block moveable
505 * actually only NT is able to do this. And it's soo simple
509 SetLastError( ERROR_NOACCESS
);
514 dwBytes
= RtlSizeHeap(GetProcessHeap(), 0, (LPVOID
) hMem
);
515 hnew
= GlobalAlloc( uFlags
, dwBytes
);
516 palloc
= GlobalLock(hnew
);
517 memcpy(palloc
, (LPVOID
) hMem
, dwBytes
);
519 RtlFreeHeap(GetProcessHeap(),0,hMem
);
522 else if(ISPOINTER(hMem
) && (uFlags
& GMEM_DISCARDABLE
))
524 /* change the flags to make our block "discardable" */
525 phandle
= HANDLE_TO_INTERN(hMem
);
526 phandle
->Flags
= phandle
->Flags
| (GMEM_DISCARDABLE
>> 8);
531 SetLastError(ERROR_INVALID_PARAMETER
);
539 /* reallocate fixed memory */
540 hnew
= (HANDLE
)RtlReAllocateHeap(GetProcessHeap(), heap_flags
, (LPVOID
) hMem
, dwBytes
);
544 /* reallocate a moveable block */
545 phandle
= HANDLE_TO_INTERN(hMem
);
551 palloc
= RtlReAllocateHeap(GetProcessHeap(), heap_flags
,
552 (PVOID
)((ULONG_PTR
)phandle
->Pointer
- HANDLE_SIZE
),
553 dwBytes
+ HANDLE_SIZE
);
560 *(PHANDLE
)palloc
= hMem
;
561 phandle
->Pointer
= (PVOID
)((ULONG_PTR
)palloc
+ HANDLE_SIZE
);
566 palloc
= RtlAllocateHeap(GetProcessHeap(), heap_flags
, dwBytes
+ HANDLE_SIZE
);
573 *(PHANDLE
)palloc
= hMem
;
574 phandle
->Pointer
= (PVOID
)((ULONG_PTR
)palloc
+ HANDLE_SIZE
);
582 RtlFreeHeap(GetProcessHeap(), 0, (PVOID
)((ULONG_PTR
)phandle
->Pointer
- HANDLE_SIZE
));
583 phandle
->Pointer
= 0;
588 HeapUnlock(GetProcessHeap());
595 GlobalSize(HGLOBAL hMem
)
598 PGLOBAL_HANDLE phandle
= 0;
600 DPRINT("GlobalSize( 0x%lX )\n", (ULONG
)hMem
);
602 if(ISPOINTER(hMem
)) /*FIXED*/
604 retval
= RtlSizeHeap(GetProcessHeap(), 0, hMem
);
608 HeapLock(GetProcessHeap());
610 phandle
= HANDLE_TO_INTERN(hMem
);
612 if (MAGIC_GLOBAL_USED
== phandle
->Magic
)
614 if (0 != phandle
->Pointer
)/*NOT DISCARDED*/
616 retval
= RtlSizeHeap(GetProcessHeap(), 0, (PVOID
)((ULONG_PTR
)phandle
->Pointer
- HANDLE_SIZE
));
618 if (retval
== (SIZE_T
)-1) /*RtlSizeHeap failed*/
621 **TODO: RtlSizeHeap does not set last error.
622 ** We should choose an error value to set as
623 ** the last error. Which One?
625 DPRINT("GlobalSize: RtlSizeHeap failed.\n");
628 else /*Everything is ok*/
630 retval
= retval
- HANDLE_SIZE
;
636 DPRINT("GlobalSize: invalid handle\n");
638 HeapUnlock(GetProcessHeap());
648 GlobalUnfix(HGLOBAL hMem
)
650 if (hMem
!= INVALID_HANDLE_VALUE
)
659 GlobalUnlock(HGLOBAL hMem
)
662 PGLOBAL_HANDLE phandle
;
665 DPRINT("GlobalUnlock( 0x%lX )\n", (ULONG
)hMem
);
669 SetLastError(ERROR_NOT_LOCKED
);
673 HeapLock(GetProcessHeap());
675 phandle
= HANDLE_TO_INTERN(hMem
);
676 if(MAGIC_GLOBAL_USED
== phandle
->Magic
)
678 if (0 >= phandle
->LockCount
)
681 SetLastError(ERROR_NOT_LOCKED
);
683 else if (GLOBAL_LOCK_MAX
> phandle
->LockCount
)
685 phandle
->LockCount
--;
686 locked
= (0 != phandle
->LockCount
) ? TRUE
: FALSE
;
687 SetLastError(NO_ERROR
);
692 DPRINT("GlobalUnlock: invalid handle\n");
695 HeapUnlock(GetProcessHeap());
704 GlobalUnWire(HGLOBAL hMem
)
706 return GlobalUnlock(hMem
);
714 GlobalWire(HGLOBAL hMem
)
716 return GlobalLock(hMem
);