kernel32: Move global/local memory functions to kernelbase.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-09-08 21:20:21 +02:00
parent 67a9700267
commit d38a5ba4e6
4 changed files with 369 additions and 469 deletions

View File

@ -236,78 +236,6 @@ typedef struct __GLOBAL32_INTERN
#include "poppack.h"
/***********************************************************************
* GlobalAlloc (KERNEL32.@)
*
* Allocate a global memory object.
*
* RETURNS
* Handle: Success
* NULL: Failure
*/
HGLOBAL WINAPI GlobalAlloc(
UINT flags, /* [in] Object allocation attributes */
SIZE_T size /* [in] Number of bytes to allocate */
) {
PGLOBAL32_INTERN pintern;
DWORD hpflags;
LPVOID palloc;
if(flags&GMEM_ZEROINIT)
hpflags=HEAP_ZERO_MEMORY;
else
hpflags=0;
if((flags & GMEM_MOVEABLE)==0) /* POINTER */
{
palloc = HeapAlloc( GetProcessHeap(), hpflags, max( 1, size ));
TRACE( "(flags=%04x) returning %p\n", flags, palloc );
return palloc;
}
else /* HANDLE */
{
if (size > INT_MAX-HGLOBAL_STORAGE)
{
SetLastError(ERROR_OUTOFMEMORY);
return 0;
}
pintern = HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
if (pintern)
{
/* Mask out obsolete flags */
flags &= ~(GMEM_LOWER | GMEM_NOCOMPACT | GMEM_NOT_BANKED | GMEM_NOTIFY);
pintern->Magic = MAGIC_GLOBAL_USED;
pintern->Flags = flags >> 8;
pintern->LockCount = 0;
if (size)
{
palloc = HeapAlloc(GetProcessHeap(), hpflags, size+HGLOBAL_STORAGE);
if (!palloc)
{
HeapFree(GetProcessHeap(), 0, pintern);
pintern = NULL;
}
else
{
*(HGLOBAL *)palloc = INTERN_TO_HANDLE(pintern);
pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
}
}
else
pintern->Pointer = NULL;
}
if (!pintern) return 0;
TRACE( "(flags=%04x) returning handle %p pointer %p\n",
flags, INTERN_TO_HANDLE(pintern), pintern->Pointer );
return INTERN_TO_HANDLE(pintern);
}
}
/***********************************************************************
* GlobalLock (KERNEL32.@)
*
@ -326,40 +254,7 @@ HGLOBAL WINAPI GlobalAlloc(
*/
LPVOID WINAPI GlobalLock(HGLOBAL hmem)
{
PGLOBAL32_INTERN pintern;
LPVOID palloc;
if (ISPOINTER(hmem))
return IsBadReadPtr(hmem, 1) ? NULL : hmem;
RtlLockHeap(GetProcessHeap());
__TRY
{
pintern = HANDLE_TO_INTERN(hmem);
if (pintern->Magic == MAGIC_GLOBAL_USED)
{
palloc = pintern->Pointer;
if (!pintern->Pointer)
SetLastError(ERROR_DISCARDED);
else if (pintern->LockCount < GMEM_LOCKCOUNT)
pintern->LockCount++;
}
else
{
WARN("invalid handle %p (Magic: 0x%04x)\n", hmem, pintern->Magic);
palloc = NULL;
SetLastError(ERROR_INVALID_HANDLE);
}
}
__EXCEPT_PAGE_FAULT
{
WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem);
palloc = NULL;
SetLastError(ERROR_INVALID_HANDLE);
}
__ENDTRY
RtlUnlockHeap(GetProcessHeap());
return palloc;
return LocalLock( hmem );
}
@ -381,46 +276,8 @@ LPVOID WINAPI GlobalLock(HGLOBAL hmem)
*/
BOOL WINAPI GlobalUnlock(HGLOBAL hmem)
{
PGLOBAL32_INTERN pintern;
BOOL locked;
if (ISPOINTER(hmem)) return TRUE;
RtlLockHeap(GetProcessHeap());
__TRY
{
pintern=HANDLE_TO_INTERN(hmem);
if(pintern->Magic==MAGIC_GLOBAL_USED)
{
if(pintern->LockCount)
{
pintern->LockCount--;
locked = (pintern->LockCount != 0);
if (!locked) SetLastError(NO_ERROR);
}
else
{
WARN("%p not locked\n", hmem);
SetLastError(ERROR_NOT_LOCKED);
locked = FALSE;
}
}
else
{
WARN("invalid handle %p (Magic: 0x%04x)\n", hmem, pintern->Magic);
SetLastError(ERROR_INVALID_HANDLE);
locked=FALSE;
}
}
__EXCEPT_PAGE_FAULT
{
WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem);
SetLastError( ERROR_INVALID_PARAMETER );
locked=FALSE;
}
__ENDTRY
RtlUnlockHeap(GetProcessHeap());
return locked;
if (ISPOINTER( hmem )) return TRUE;
return LocalUnlock( hmem );
}
@ -495,200 +352,9 @@ HGLOBAL WINAPI GlobalHandle(
* Handle: Success
* NULL: Failure
*/
HGLOBAL WINAPI GlobalReAlloc(
HGLOBAL hmem, /* [in] Handle of global memory object */
SIZE_T size, /* [in] New size of block */
UINT flags /* [in] How to reallocate object */
) {
LPVOID palloc;
HGLOBAL hnew;
PGLOBAL32_INTERN pintern;
DWORD heap_flags = (flags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
hnew = 0;
RtlLockHeap(GetProcessHeap());
if(flags & GMEM_MODIFY) /* modify flags */
{
if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
{
/* make a fixed block moveable
* actually only NT is able to do this. But it's soo simple
*/
if (hmem == 0)
{
WARN("GlobalReAlloc with null handle!\n");
SetLastError( ERROR_NOACCESS );
hnew = 0;
}
else
{
size = HeapSize(GetProcessHeap(), 0, hmem);
hnew = GlobalAlloc(flags, size);
palloc = GlobalLock(hnew);
memcpy(palloc, hmem, size);
GlobalUnlock(hnew);
GlobalFree(hmem);
}
}
else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
{
/* change the flags to make our block "discardable" */
pintern=HANDLE_TO_INTERN(hmem);
pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
hnew=hmem;
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
hnew = 0;
}
}
else
{
if(ISPOINTER(hmem))
{
/* reallocate fixed memory */
if (!(flags & GMEM_MOVEABLE))
heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
hnew=HeapReAlloc(GetProcessHeap(), heap_flags, hmem, size);
}
else
{
/* reallocate a moveable block */
pintern=HANDLE_TO_INTERN(hmem);
#if 0
/* Apparently Windows doesn't care whether the handle is locked at this point */
/* See also the same comment in GlobalFree() */
if(pintern->LockCount>1) {
ERR("handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
SetLastError(ERROR_INVALID_HANDLE);
} else
#endif
if(size!=0)
{
hnew=hmem;
if(pintern->Pointer)
{
if(size > INT_MAX-HGLOBAL_STORAGE)
{
SetLastError(ERROR_OUTOFMEMORY);
hnew = 0;
}
else if((palloc = HeapReAlloc(GetProcessHeap(), heap_flags,
(char *) pintern->Pointer-HGLOBAL_STORAGE,
size+HGLOBAL_STORAGE)) == NULL)
hnew = 0; /* Block still valid */
else
pintern->Pointer = (char *)palloc+HGLOBAL_STORAGE;
}
else
{
if(size > INT_MAX-HGLOBAL_STORAGE)
{
SetLastError(ERROR_OUTOFMEMORY);
hnew = 0;
}
else if((palloc=HeapAlloc(GetProcessHeap(), heap_flags, size+HGLOBAL_STORAGE))
== NULL)
hnew = 0;
else
{
*(HGLOBAL *)palloc = hmem;
pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
}
}
}
else
{
if (pintern->LockCount == 0)
{
if(pintern->Pointer)
{
HeapFree(GetProcessHeap(), 0, (char *) pintern->Pointer-HGLOBAL_STORAGE);
pintern->Pointer = NULL;
}
hnew = hmem;
}
else
WARN("not freeing memory associated with locked handle\n");
}
}
}
RtlUnlockHeap(GetProcessHeap());
return hnew;
}
/***********************************************************************
* GlobalFree (KERNEL32.@)
*
* Free a global memory object.
*
* PARAMS
* hmem [I] Handle of the global memory object
*
* RETURNS
* Success: NULL
* Failure: The provided handle
*
* NOTES
* When the handle is invalid, last error is set to ERROR_INVALID_HANDLE
*
*/
HGLOBAL WINAPI GlobalFree(HGLOBAL hmem)
HGLOBAL WINAPI GlobalReAlloc( HGLOBAL hmem, SIZE_T size, UINT flags )
{
PGLOBAL32_INTERN pintern;
HGLOBAL hreturned;
RtlLockHeap(GetProcessHeap());
__TRY
{
hreturned = 0;
if(ISPOINTER(hmem)) /* POINTER */
{
if(!HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, hmem))
{
SetLastError(ERROR_INVALID_HANDLE);
hreturned = hmem;
}
}
else /* HANDLE */
{
pintern=HANDLE_TO_INTERN(hmem);
if(pintern->Magic==MAGIC_GLOBAL_USED)
{
pintern->Magic = 0xdead;
/* WIN98 does not make this test. That is you can free a */
/* block you have not unlocked. Go figure!! */
/* if(pintern->LockCount!=0) */
/* SetLastError(ERROR_INVALID_HANDLE); */
if(pintern->Pointer)
if(!HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, (char *)(pintern->Pointer)-HGLOBAL_STORAGE))
hreturned=hmem;
if(!HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, pintern))
hreturned=hmem;
}
else
{
WARN("invalid handle %p (Magic: 0x%04x)\n", hmem, pintern->Magic);
SetLastError(ERROR_INVALID_HANDLE);
hreturned = hmem;
}
}
}
__EXCEPT_PAGE_FAULT
{
ERR("invalid handle %p\n", hmem);
SetLastError(ERROR_INVALID_HANDLE);
hreturned = hmem;
}
__ENDTRY
RtlUnlockHeap(GetProcessHeap());
return hreturned;
return LocalReAlloc( hmem, size, flags );
}
@ -846,33 +512,6 @@ SIZE_T WINAPI GlobalCompact( DWORD minfree )
}
/***********************************************************************
* LocalAlloc (KERNEL32.@)
*
* Allocate a local memory object.
*
* RETURNS
* Handle: Success
* NULL: Failure
*
* NOTES
* Windows memory management does not provide a separate local heap
* and global heap.
*/
HLOCAL WINAPI LocalAlloc( UINT flags, SIZE_T size )
{
/* LocalAlloc allows a 0-size fixed block, but GlobalAlloc doesn't */
if (!(flags & LMEM_MOVEABLE))
{
DWORD heap_flags = (flags & LMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
void *ret = HeapAlloc( GetProcessHeap(), heap_flags, size );
TRACE( "(flags=%04x) returning %p\n", flags, ret );
return ret;
}
return GlobalAlloc( flags, size );
}
/***********************************************************************
* LocalCompact (KERNEL32.@)
*/
@ -902,26 +541,6 @@ UINT WINAPI LocalFlags(
}
/***********************************************************************
* LocalFree (KERNEL32.@)
*
* Free a local memory object.
*
* RETURNS
* NULL: Success
* Handle: Failure
*
* NOTES
* Windows memory management does not provide a separate local heap
* and global heap.
*/
HLOCAL WINAPI LocalFree(
HLOCAL handle /* [in] Handle of memory object */
) {
return GlobalFree( handle );
}
/***********************************************************************
* LocalHandle (KERNEL32.@)
*
@ -942,48 +561,6 @@ HLOCAL WINAPI LocalHandle(
}
/***********************************************************************
* LocalLock (KERNEL32.@)
* Locks a local memory object and returns pointer to the first byte
* of the memory block.
*
* RETURNS
* Pointer: Success
* NULL: Failure
*
* NOTES
* Windows memory management does not provide a separate local heap
* and global heap.
*/
LPVOID WINAPI LocalLock(
HLOCAL handle /* [in] Address of local memory object */
) {
return GlobalLock( handle );
}
/***********************************************************************
* LocalReAlloc (KERNEL32.@)
*
* Change the size or attributes of a local memory object.
*
* RETURNS
* Handle: Success
* NULL: Failure
*
* NOTES
* Windows memory management does not provide a separate local heap
* and global heap.
*/
HLOCAL WINAPI LocalReAlloc(
HLOCAL handle, /* [in] Handle of memory object */
SIZE_T size, /* [in] New size of block */
UINT flags /* [in] How to reallocate object */
) {
return GlobalReAlloc( handle, size, flags );
}
/***********************************************************************
* LocalShrink (KERNEL32.@)
*/
@ -1013,32 +590,6 @@ SIZE_T WINAPI LocalSize(
}
/***********************************************************************
* LocalUnlock (KERNEL32.@)
*
* Unlock a local memory object.
*
* RETURNS
* TRUE: Object is still locked
* FALSE: Object is unlocked
*
* NOTES
* Windows memory management does not provide a separate local heap
* and global heap.
*/
BOOL WINAPI LocalUnlock(
HLOCAL handle /* [in] Handle of memory object */
)
{
if (ISPOINTER( handle ))
{
SetLastError( ERROR_NOT_LOCKED );
return FALSE;
}
return GlobalUnlock( handle );
}
/***********************************************************************
* GlobalMemoryStatusEx (KERNEL32.@)

View File

@ -893,14 +893,14 @@
# @ stub GetXStateFeaturesMask
@ stdcall GlobalAddAtomA(str)
@ stdcall GlobalAddAtomW(wstr)
@ stdcall GlobalAlloc(long long)
@ stdcall -import GlobalAlloc(long long)
@ stdcall GlobalCompact(long)
@ stdcall GlobalDeleteAtom(long)
@ stdcall GlobalFindAtomA(str)
@ stdcall GlobalFindAtomW(wstr)
@ stdcall GlobalFix(long)
@ stdcall GlobalFlags(long)
@ stdcall GlobalFree(long)
@ stdcall -import GlobalFree(long)
@ stdcall GlobalGetAtomNameA(long ptr long)
@ stdcall GlobalGetAtomNameW(long ptr long)
@ stdcall GlobalHandle(ptr)
@ -1050,17 +1050,17 @@
@ stdcall -import LoadResource(long long)
# @ stub LoadStringBaseExW
# @ stub LoadStringBaseW
@ stdcall LocalAlloc(long long)
@ stdcall -import LocalAlloc(long long)
@ stdcall LocalCompact(long)
@ stdcall LocalFileTimeToFileTime(ptr ptr)
@ stdcall LocalFlags(long)
@ stdcall LocalFree(long)
@ stdcall -import LocalFree(long)
@ stdcall LocalHandle(ptr)
@ stdcall LocalLock(long)
@ stdcall LocalReAlloc(long long long)
@ stdcall -import LocalLock(long)
@ stdcall -import LocalReAlloc(long long long)
@ stdcall LocalShrink(long long)
@ stdcall LocalSize(long)
@ stdcall LocalUnlock(long)
@ stdcall -import LocalUnlock(long)
@ stdcall LocaleNameToLCID(wstr long)
# @ stub LocateXStateFeature
@ stdcall -import LockFile(long long long long long)

View File

@ -766,8 +766,8 @@
# @ stub GetWsChanges
# @ stub GetWsChangesEx
# @ stub GetXStateFeaturesMask
@ stdcall GlobalAlloc(long long) kernel32.GlobalAlloc
@ stdcall GlobalFree(long) kernel32.GlobalFree
@ stdcall GlobalAlloc(long long)
@ stdcall GlobalFree(long)
@ stdcall GlobalMemoryStatusEx(ptr) kernel32.GlobalMemoryStatusEx
# @ stub GuardCheckLongJumpTarget
# @ stub HasPolicyForegroundProcessingCompletedInternal
@ -933,12 +933,12 @@
@ stub LoadStringBaseExW
@ stub LoadStringByReference
@ stdcall LoadStringW(long long ptr long)
@ stdcall LocalAlloc(long long) kernel32.LocalAlloc
@ stdcall LocalAlloc(long long)
@ stdcall LocalFileTimeToFileTime(ptr ptr) kernel32.LocalFileTimeToFileTime
@ stdcall LocalFree(long) kernel32.LocalFree
@ stdcall LocalLock(long) kernel32.LocalLock
@ stdcall LocalReAlloc(long long long) kernel32.LocalReAlloc
@ stdcall LocalUnlock(long) kernel32.LocalUnlock
@ stdcall LocalFree(long)
@ stdcall LocalLock(long)
@ stdcall LocalReAlloc(long long long)
@ stdcall LocalUnlock(long)
@ stdcall LocaleNameToLCID(wstr long) kernel32.LocaleNameToLCID
# @ stub LocateXStateFeature
@ stdcall LockFile(long long long long long)

View File

@ -21,6 +21,7 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include "ntstatus.h"
@ -36,7 +37,7 @@
#include "wine/exception.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(virtual);
WINE_DEFAULT_DEBUG_CHANNEL(heap);
/***********************************************************************
@ -384,6 +385,354 @@ BOOL WINAPI DECLSPEC_HOTPATCH HeapWalk( HANDLE heap, PROCESS_HEAP_ENTRY *entry )
}
/***********************************************************************
* Global/local heap functions
***********************************************************************/
#include "pshpack1.h"
struct local_header
{
WORD magic;
void *ptr;
BYTE flags;
BYTE lock;
};
#include "poppack.h"
#define MAGIC_LOCAL_USED 0x5342
/* align the storage needed for the HLOCAL on an 8-byte boundary thus
* LocalAlloc/LocalReAlloc'ing with LMEM_MOVEABLE of memory with
* size = 8*k, where k=1,2,3,... allocs exactly the given size.
* The Minolta DiMAGE Image Viewer heavily relies on this, corrupting
* the output jpeg's > 1 MB if not */
#define HLOCAL_STORAGE (sizeof(HLOCAL) * 2)
static inline struct local_header *get_header( HLOCAL hmem )
{
return (struct local_header *)((char *)hmem - 2);
}
static inline HLOCAL get_handle( struct local_header *header )
{
return &header->ptr;
}
static inline BOOL is_pointer( HLOCAL hmem )
{
return !((ULONG_PTR)hmem & 2);
}
/***********************************************************************
* GlobalAlloc (kernelbase.@)
*/
HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalAlloc( UINT flags, SIZE_T size )
{
/* mask out obsolete flags */
flags &= ~(GMEM_NOCOMPACT | GMEM_NOT_BANKED | GMEM_NOTIFY);
/* LocalAlloc allows a 0-size fixed block, but GlobalAlloc doesn't */
if (!(flags & GMEM_MOVEABLE) && !size) size = 1;
return LocalAlloc( flags, size );
}
/***********************************************************************
* GlobalFree (kernelbase.@)
*/
HGLOBAL WINAPI DECLSPEC_HOTPATCH GlobalFree( HLOCAL hmem )
{
return LocalFree( hmem );
}
/***********************************************************************
* LocalAlloc (kernelbase.@)
*/
HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size )
{
struct local_header *header;
DWORD heap_flags = 0;
void *ptr;
if (flags & LMEM_ZEROINIT) heap_flags = HEAP_ZERO_MEMORY;
if (!(flags & LMEM_MOVEABLE)) /* pointer */
{
ptr = HeapAlloc( GetProcessHeap(), heap_flags, size );
TRACE( "(flags=%04x) returning %p\n", flags, ptr );
return ptr;
}
if (size > INT_MAX - HLOCAL_STORAGE)
{
SetLastError( ERROR_OUTOFMEMORY );
return 0;
}
if (!(header = HeapAlloc( GetProcessHeap(), 0, sizeof(*header) ))) return 0;
header->magic = MAGIC_LOCAL_USED;
header->flags = flags >> 8;
header->lock = 0;
if (size)
{
if (!(ptr = HeapAlloc(GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE )))
{
HeapFree( GetProcessHeap(), 0, header );
return 0;
}
*(HLOCAL *)ptr = get_handle( header );
header->ptr = (char *)ptr + HLOCAL_STORAGE;
}
else header->ptr = NULL;
TRACE( "(flags=%04x) returning handle %p pointer %p\n",
flags, get_handle( header ), header->ptr );
return get_handle( header );
}
/***********************************************************************
* LocalFree (kernelbase.@)
*/
HLOCAL WINAPI DECLSPEC_HOTPATCH LocalFree( HLOCAL hmem )
{
struct local_header *header;
HLOCAL ret;
RtlLockHeap( GetProcessHeap() );
__TRY
{
ret = 0;
if (is_pointer(hmem)) /* POINTER */
{
if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, hmem ))
{
SetLastError( ERROR_INVALID_HANDLE );
ret = hmem;
}
}
else /* HANDLE */
{
header = get_header( hmem );
if (header->magic == MAGIC_LOCAL_USED)
{
header->magic = 0xdead;
if (header->ptr)
{
if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE,
(char *)header->ptr - HLOCAL_STORAGE ))
ret = hmem;
}
if (!HeapFree( GetProcessHeap(), HEAP_NO_SERIALIZE, header )) ret = hmem;
}
else
{
WARN( "invalid handle %p (magic: 0x%04x)\n", hmem, header->magic );
SetLastError( ERROR_INVALID_HANDLE );
ret = hmem;
}
}
}
__EXCEPT_PAGE_FAULT
{
WARN( "invalid handle %p\n", hmem );
SetLastError( ERROR_INVALID_HANDLE );
ret = hmem;
}
__ENDTRY
RtlUnlockHeap( GetProcessHeap() );
return ret;
}
/***********************************************************************
* LocalLock (kernelbase.@)
*/
LPVOID WINAPI DECLSPEC_HOTPATCH LocalLock( HLOCAL hmem )
{
void *ret = NULL;
if (is_pointer( hmem )) return IsBadReadPtr( hmem, 1 ) ? NULL : hmem;
RtlLockHeap( GetProcessHeap() );
__TRY
{
struct local_header *header = get_header( hmem );
if (header->magic == MAGIC_LOCAL_USED)
{
ret = header->ptr;
if (!header->ptr) SetLastError( ERROR_DISCARDED );
else if (header->lock < LMEM_LOCKCOUNT) header->lock++;
}
else
{
WARN( "invalid handle %p (magic: 0x%04x)\n", hmem, header->magic );
SetLastError( ERROR_INVALID_HANDLE );
}
}
__EXCEPT_PAGE_FAULT
{
WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem);
SetLastError( ERROR_INVALID_HANDLE );
}
__ENDTRY
RtlUnlockHeap( GetProcessHeap() );
return ret;
}
/***********************************************************************
* LocalReAlloc (kernelbase.@)
*/
HLOCAL WINAPI DECLSPEC_HOTPATCH LocalReAlloc( HLOCAL hmem, SIZE_T size, UINT flags )
{
struct local_header *header;
void *ptr;
HLOCAL ret = 0;
DWORD heap_flags = (flags & LMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
RtlLockHeap( GetProcessHeap() );
if (flags & LMEM_MODIFY) /* modify flags */
{
if (is_pointer( hmem ) && (flags & LMEM_MOVEABLE))
{
/* make a fixed block moveable
* actually only NT is able to do this. But it's soo simple
*/
if (hmem == 0)
{
WARN( "null handle\n");
SetLastError( ERROR_NOACCESS );
}
else
{
size = RtlSizeHeap( GetProcessHeap(), 0, hmem );
ret = LocalAlloc( flags, size );
ptr = LocalLock( ret );
memcpy( ptr, hmem, size );
LocalUnlock( ret );
LocalFree( hmem );
}
}
else if (!is_pointer( hmem ) && (flags & LMEM_DISCARDABLE))
{
/* change the flags to make our block "discardable" */
header = get_header( hmem );
header->flags |= LMEM_DISCARDABLE >> 8;
ret = hmem;
}
else SetLastError( ERROR_INVALID_PARAMETER );
}
else
{
if (is_pointer( hmem ))
{
/* reallocate fixed memory */
if (!(flags & LMEM_MOVEABLE)) heap_flags |= HEAP_REALLOC_IN_PLACE_ONLY;
ret = HeapReAlloc( GetProcessHeap(), heap_flags, hmem, size );
}
else
{
/* reallocate a moveable block */
header = get_header( hmem );
if (size != 0)
{
if (size <= INT_MAX - HLOCAL_STORAGE)
{
if (header->ptr)
{
if ((ptr = HeapReAlloc( GetProcessHeap(), heap_flags,
(char *)header->ptr - HLOCAL_STORAGE,
size + HLOCAL_STORAGE )))
{
header->ptr = (char *)ptr + HLOCAL_STORAGE;
ret = hmem;
}
}
else
{
if ((ptr = HeapAlloc( GetProcessHeap(), heap_flags, size + HLOCAL_STORAGE )))
{
*(HLOCAL *)ptr = hmem;
header->ptr = (char *)ptr + HLOCAL_STORAGE;
ret = hmem;
}
}
}
else SetLastError( ERROR_OUTOFMEMORY );
}
else
{
if (header->lock == 0)
{
if (header->ptr)
{
HeapFree( GetProcessHeap(), 0, (char *)header->ptr - HLOCAL_STORAGE );
header->ptr = NULL;
}
ret = hmem;
}
else WARN( "not freeing memory associated with locked handle\n" );
}
}
}
RtlUnlockHeap( GetProcessHeap() );
return ret;
}
/***********************************************************************
* LocalUnlock (kernelbase.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH LocalUnlock( HLOCAL hmem )
{
BOOL ret = FALSE;
if (is_pointer( hmem ))
{
SetLastError( ERROR_NOT_LOCKED );
return FALSE;
}
RtlLockHeap( GetProcessHeap() );
__TRY
{
struct local_header *header = get_header( hmem );
if (header->magic == MAGIC_LOCAL_USED)
{
if (header->lock)
{
header->lock--;
ret = (header->lock != 0);
if (!ret) SetLastError( NO_ERROR );
}
else
{
WARN( "%p not locked\n", hmem );
SetLastError( ERROR_NOT_LOCKED );
}
}
else
{
WARN( "invalid handle %p (Magic: 0x%04x)\n", hmem, header->magic );
SetLastError( ERROR_INVALID_HANDLE );
}
}
__EXCEPT_PAGE_FAULT
{
WARN("(%p): Page fault occurred ! Caused by bug ?\n", hmem);
SetLastError( ERROR_INVALID_PARAMETER );
}
__ENDTRY
RtlUnlockHeap( GetProcessHeap() );
return ret;
}
/***********************************************************************
* Memory resource functions
***********************************************************************/