1 /* $Id: global.c,v 1.15 2003/10/14 01:44:39 mtempel Exp $
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 <kernel32/kernel32.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)(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 DbgPrint("Magic: 0x%X\n", h
->Magic
);
50 DbgPrint("Pointer: 0x%X\n", h
->Pointer
);
51 DbgPrint("Flags: 0x%X\n", h
->Flags
);
52 DbgPrint("LockCount: 0x%X\n", h
->LockCount
);
57 /* FUNCTIONS ***************************************************************/
63 GlobalAlloc(UINT uFlags
,
67 PGLOBAL_HANDLE phandle
= 0;
70 /*Fixme: When we are sure all allocations are 8-byte aligned,
71 **we can remove this hack.
73 PGLOBAL_HANDLE hack_fix
= 0;
75 if (uFlags
& GMEM_ZEROINIT
)
77 heap_flags
= HEAP_ZERO_MEMORY
;
80 DPRINT("GlobalAlloc( 0x%X, 0x%lX )\n", uFlags
, dwBytes
);
82 //Changed hProcessHeap to GetProcessHeap()
83 if ((uFlags
& GMEM_MOVEABLE
)==0) /* POINTER */
85 return ((HGLOBAL
)RtlAllocateHeap(GetProcessHeap(), heap_flags
, dwBytes
));
89 HeapLock(hProcessHeap
);
91 phandle
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof(GLOBAL_HANDLE
));
92 /* This little hack is to make sure that we get a pointer with 8-byte
94 ** Fixme: When we are sure all allocations are 8-byte aligned,
95 ** we can remove this hack.
97 if (ISPOINTER(INTERN_TO_HANDLE(phandle
)))
99 hack_fix
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof(GLOBAL_HANDLE
));
100 RtlFreeHeap(GetProcessHeap(), 0, phandle
);
105 phandle
->Magic
= MAGIC_GLOBAL_USED
;
106 phandle
->Flags
= uFlags
>> 8;
107 phandle
->LockCount
= 0;
108 phandle
->Pointer
= 0;
112 palloc
= RtlAllocateHeap(GetProcessHeap(), heap_flags
, dwBytes
+ HANDLE_SIZE
);
115 *(PHANDLE
)palloc
= INTERN_TO_HANDLE(phandle
);
116 phandle
->Pointer
= palloc
+ HANDLE_SIZE
;
118 else /*failed to allocate the memory block*/
120 RtlFreeHeap(GetProcessHeap(), 0, phandle
);
126 DbgPrint("Allocated a 0 size movable block.\n");
127 DbgPrintStruct(phandle
);
128 DbgPrint("Address of the struct: 0x%X\n", phandle
);
129 DbgPrint("Address of pointer: 0x%X\n", &(phandle
->Pointer
));
132 HeapUnlock(hProcessHeap
);
135 return INTERN_TO_HANDLE(phandle
);
146 GlobalCompact(DWORD dwMinFree
)
148 return RtlCompactHeap(hProcessHeap
, 0);
156 GlobalFix(HGLOBAL hMem
)
158 if (INVALID_HANDLE_VALUE
!= hMem
)
166 GlobalFlags(HGLOBAL hMem
)
169 PGLOBAL_HANDLE phandle
;
171 DbgPrint("GlobalFlags( 0x%lX )\n", (ULONG
)hMem
);
175 DbgPrint("GlobalFlags: Fixed memory.\n");
180 HeapLock(GetProcessHeap());
182 phandle
= HANDLE_TO_INTERN(hMem
);
184 /*DbgPrintStruct(phandle);*/
186 if (MAGIC_GLOBAL_USED
== phandle
->Magic
)
188 /*DbgPrint("GlobalFlags: Magic number ok\n");
189 **DbgPrint("GlobalFlags: pointer is 0x%X\n", phandle->Pointer);
191 retval
= phandle
->LockCount
+ (phandle
->Flags
<< 8);
192 if (0 == phandle
->Pointer
)
194 retval
= retval
| GMEM_DISCARDED
;
199 DbgPrint("GlobalSize: invalid handle\n");
202 HeapUnlock(GetProcessHeap());
212 GlobalFree(HGLOBAL hMem
)
214 PGLOBAL_HANDLE phandle
;
216 DPRINT("GlobalFree( 0x%lX )\n", (ULONG
)hMem
);
218 if (ISPOINTER(hMem
)) /* POINTER */
220 RtlFreeHeap(GetProcessHeap(), 0, (PVOID
)hMem
);
225 HeapLock(GetProcessHeap());
227 phandle
= HANDLE_TO_INTERN(hMem
);
229 if(MAGIC_GLOBAL_USED
== phandle
->Magic
)
232 if(phandle
->LockCount
!=0)
234 DbgPrint("Warning! GlobalFree(0x%X) Freeing a handle to a locked object.\n", hMem
);
235 SetLastError(ERROR_INVALID_HANDLE
);
239 RtlFreeHeap(GetProcessHeap(), 0, phandle
->Pointer
- HANDLE_SIZE
);
241 RtlFreeHeap(GetProcessHeap(), 0, phandle
);
243 HeapUnlock(GetProcessHeap());
255 GlobalHandle(LPCVOID pMem
)
258 PGLOBAL_HANDLE test
= 0;
259 LPCVOID pointer_test
= 0;
261 DbgPrint("GlobalHandle( 0x%lX )\n", (ULONG
)pMem
);
262 if (0 == pMem
) /*Invalid argument */
264 SetLastError(ERROR_INVALID_PARAMETER
);
265 DbgPrint("Error: 0 handle.\n");
269 HeapLock(GetProcessHeap());
270 /* Now test to see if this pointer is associated with a handle.
271 * This is done by calling RtlValidateHeap() and seeing if it fails.
273 if (RtlValidateHeap(GetProcessHeap(), 0, (char *)pMem
)) /*FIXED*/
275 handle
= (HGLOBAL
)pMem
;
280 handle
= POINTER_TO_HANDLE(pMem
);
284 /* Test to see if this memory is valid*/
285 test
= HANDLE_TO_INTERN(handle
);
286 if (!IsBadReadPtr(test
, sizeof(GLOBAL_HANDLE
)))
288 if (MAGIC_GLOBAL_USED
== test
->Magic
)
290 pointer_test
= test
->Pointer
;
291 if (!RtlValidateHeap(GetProcessHeap(), 0, ((char *)pointer_test
) - HANDLE_SIZE
) ||
292 !RtlValidateHeap(GetProcessHeap(), 0, test
))
294 SetLastError(ERROR_INVALID_HANDLE
);
301 DbgPrint("GlobalHandle: Bad read pointer.\n");
302 SetLastError(ERROR_INVALID_HANDLE
);
306 HeapUnlock(GetProcessHeap());
316 GlobalLock(HGLOBAL hMem
)
318 PGLOBAL_HANDLE phandle
;
321 DPRINT("GlobalLock( 0x%lX )\n", (ULONG
)hMem
);
324 return (LPVOID
) hMem
;
326 HeapLock(GetProcessHeap());
328 phandle
= HANDLE_TO_INTERN(hMem
);
330 if(MAGIC_GLOBAL_USED
== phandle
->Magic
)
332 if(GLOBAL_LOCK_MAX
> phandle
->LockCount
)
334 phandle
->LockCount
++;
336 palloc
= phandle
->Pointer
;
340 DPRINT("GlobalLock: invalid handle\n");
341 palloc
= (LPVOID
) hMem
;
344 HeapUnlock(GetProcessHeap());
354 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer
)
357 SYSTEM_PERFORMANCE_INFORMATION Spi
;
360 PIMAGE_NT_HEADERS ImageNtHeader
;
362 RtlZeroMemory (lpBuffer
, sizeof (MEMORYSTATUS
));
363 lpBuffer
->dwLength
= sizeof (MEMORYSTATUS
);
364 Status
= NtQuerySystemInformation (
365 SystemPerformanceInformation
,
370 /* FIXME: perform computations and fill lpBuffer fields */
371 Status
= NtQueryInformationProcess (
378 /* FIXME: perform computations and fill lpBuffer fields */
379 Status
= NtQueryInformationProcess (
386 /* FIXME: perform computations and fill lpBuffer fields */
387 ImageNtHeader
= RtlImageNtHeader ((PVOID
)NtCurrentPeb()->ImageBaseAddress
);
388 /* FIXME: perform computations and fill lpBuffer fields */
393 GlobalReAlloc(HGLOBAL hMem
,
400 PGLOBAL_HANDLE phandle
= 0;
401 ULONG heap_flags
= 0;
403 DPRINT("GlobalReAlloc( 0x%lX, 0x%lX, 0x%X )\n", (ULONG
)hMem
, dwBytes
, uFlags
);
407 if (uFlags
& GMEM_ZEROINIT
)
409 heap_flags
= HEAP_ZERO_MEMORY
;
412 HeapLock(GetProcessHeap());
414 if(uFlags
& GMEM_MODIFY
) /* modify flags */
416 if( ISPOINTER(hMem
) && (uFlags
& GMEM_MOVEABLE
))
418 /* make a fixed block moveable
419 * actually only NT is able to do this. And it's soo simple
423 SetLastError( ERROR_NOACCESS
);
428 dwBytes
= RtlSizeHeap(GetProcessHeap(), 0, (LPVOID
) hMem
);
429 hnew
= GlobalAlloc( uFlags
, dwBytes
);
430 palloc
= GlobalLock(hnew
);
431 memcpy(palloc
, (LPVOID
) hMem
, dwBytes
);
433 RtlFreeHeap(GetProcessHeap(),0,hMem
);
436 else if(ISPOINTER(hMem
) && (uFlags
& GMEM_DISCARDABLE
))
438 /* change the flags to make our block "discardable" */
439 phandle
= HANDLE_TO_INTERN(hMem
);
440 phandle
->Flags
= phandle
->Flags
| (GMEM_DISCARDABLE
>> 8);
445 SetLastError(ERROR_INVALID_PARAMETER
);
453 /* reallocate fixed memory */
454 hnew
= (HANDLE
)RtlReAllocateHeap(GetProcessHeap(), heap_flags
, (LPVOID
) hMem
, dwBytes
);
458 /* reallocate a moveable block */
459 phandle
= HANDLE_TO_INTERN(hMem
);
461 if(phandle
->LockCount
!= 0)
463 SetLastError(ERROR_INVALID_HANDLE
);
472 palloc
= RtlReAllocateHeap(GetProcessHeap(), heap_flags
,
473 phandle
->Pointer
- HANDLE_SIZE
,
474 dwBytes
+ HANDLE_SIZE
);
481 *(PHANDLE
)palloc
= hMem
;
482 phandle
->Pointer
= palloc
+ HANDLE_SIZE
;
487 palloc
= RtlAllocateHeap(GetProcessHeap(), heap_flags
, dwBytes
+ HANDLE_SIZE
);
494 *(PHANDLE
)palloc
= hMem
;
495 phandle
->Pointer
= palloc
+ HANDLE_SIZE
;
504 RtlFreeHeap(GetProcessHeap(), 0, phandle
->Pointer
- HANDLE_SIZE
);
505 phandle
->Pointer
= 0;
510 HeapUnlock(GetProcessHeap());
517 GlobalSize(HGLOBAL hMem
)
520 PGLOBAL_HANDLE phandle
= 0;
522 DbgPrint("GlobalSize( 0x%lX )\n", (ULONG
)hMem
);
524 if(ISPOINTER(hMem
)) /*FIXED*/
526 retval
= RtlSizeHeap(GetProcessHeap(), 0, hMem
);
530 HeapLock(GetProcessHeap());
532 phandle
= HANDLE_TO_INTERN(hMem
);
534 if (MAGIC_GLOBAL_USED
== phandle
->Magic
)
536 if (0 != phandle
->Pointer
)/*NOT DISCARDED*/
538 retval
= RtlSizeHeap(GetProcessHeap(), 0, phandle
->Pointer
- HANDLE_SIZE
);
540 if (retval
== (SIZE_T
)-1) /*RtlSizeHeap failed*/
543 **TODO: RtlSizeHeap does not set last error.
544 ** We should choose an error value to set as
545 ** the last error. Which One?
547 DbgPrint("GlobalSize: RtlSizeHeap failed.\n");
550 else /*Everything is ok*/
552 retval
= retval
- HANDLE_SIZE
;
558 DPRINT("GlobalSize: invalid handle\n");
560 HeapUnlock(GetProcessHeap());
570 GlobalUnfix(HGLOBAL hMem
)
572 if (hMem
!= INVALID_HANDLE_VALUE
)
581 GlobalUnlock(HGLOBAL hMem
)
584 PGLOBAL_HANDLE phandle
;
587 DPRINT("GlobalUnlock( 0x%lX )\n", (ULONG
)hMem
);
593 HeapLock(GetProcessHeap());
595 phandle
= HANDLE_TO_INTERN(hMem
);
596 if(MAGIC_GLOBAL_USED
== phandle
->Magic
)
598 if((GLOBAL_LOCK_MAX
> phandle
->LockCount
) &&
599 (0 < phandle
->LockCount
) )
601 phandle
->LockCount
--;
603 locked
= (0 == phandle
->LockCount
) ? TRUE
: FALSE
;
607 DPRINT("GlobalUnlock: invalid handle\n");
610 HeapUnlock(GetProcessHeap());
619 GlobalUnWire(HGLOBAL hMem
)
621 return GlobalUnlock(hMem
);
629 GlobalWire(HGLOBAL hMem
)
631 return GlobalLock(hMem
);
638 //GlobalDiscard(HGLOBAL hMem)
640 // return GlobalReAlloc(hMem, 0, GMEM_MOVEABLE);