mirror of
https://github.com/reactos/reactos.git
synced 2025-07-01 04:11:21 +00:00

- Fixed some packing issues in DDK headers (more to come). svn path=/trunk/; revision=9664
738 lines
18 KiB
C
738 lines
18 KiB
C
/* $Id: global.c,v 1.25 2004/06/13 20:04:55 navaraf Exp $
|
|
*
|
|
* Win32 Global/Local heap functions (GlobalXXX, LocalXXX).
|
|
* These functions included in Win32 for compatibility with 16 bit Windows
|
|
* Especially the moveable blocks and handles are oldish.
|
|
* But the ability to directly allocate memory with GPTR and LPTR is widely
|
|
* used.
|
|
*
|
|
* Updated to support movable memory with algorithms taken from wine.
|
|
*/
|
|
|
|
#include <k32.h>
|
|
#include <time.h>
|
|
|
|
#define NDEBUG
|
|
#include "../include/debug.h"
|
|
|
|
#ifdef _GNUC_
|
|
#define STRUCT_PACK __attribute__((packed))
|
|
#else
|
|
#define STRUCT_PACK
|
|
#endif
|
|
|
|
#define MAGIC_GLOBAL_USED 0x5342BEEF
|
|
#define GLOBAL_LOCK_MAX 0xFF
|
|
|
|
/*Wine found that some applications complain if memory isn't 8 byte aligned.
|
|
* We make use of that experience here.
|
|
*/
|
|
#define HANDLE_SIZE 8 /*sizeof(HANDLE) *2 */
|
|
|
|
|
|
typedef struct __GLOBAL_LOCAL_HANDLE
|
|
{
|
|
DWORD Magic;
|
|
LPVOID Pointer; STRUCT_PACK
|
|
BYTE Flags;
|
|
BYTE LockCount;
|
|
} GLOBAL_HANDLE, LOCAL_HANDLE, *PGLOBAL_HANDLE, *PLOCAL_HANDLE;
|
|
|
|
#define HANDLE_TO_INTERN(h) ((PGLOBAL_HANDLE)(((char *)(h))-4))
|
|
#define INTERN_TO_HANDLE(i) ((HGLOBAL) &((i)->Pointer))
|
|
#define POINTER_TO_HANDLE(p) (*(PHANDLE)(p - HANDLE_SIZE))
|
|
#define ISHANDLE(h) ((((ULONG)(h)) & 0x4)!=0)
|
|
#define ISPOINTER(h) ((((ULONG)(h)) & 0x4)==0)
|
|
|
|
|
|
static void DbgPrintStruct(PGLOBAL_HANDLE h)
|
|
{
|
|
DPRINT("Magic: 0x%X\n", h->Magic);
|
|
DPRINT("Pointer: 0x%X\n", h->Pointer);
|
|
DPRINT("Flags: 0x%X\n", h->Flags);
|
|
DPRINT("LockCount: 0x%X\n", h->LockCount);
|
|
}
|
|
|
|
|
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HGLOBAL STDCALL
|
|
GlobalAlloc(UINT uFlags,
|
|
DWORD dwBytes)
|
|
{
|
|
|
|
PGLOBAL_HANDLE phandle = 0;
|
|
PVOID palloc = 0;
|
|
UINT heap_flags = 0;
|
|
|
|
if (uFlags & GMEM_ZEROINIT)
|
|
{
|
|
heap_flags = HEAP_ZERO_MEMORY;
|
|
}
|
|
|
|
DPRINT("GlobalAlloc( 0x%X, 0x%lX )\n", uFlags, dwBytes);
|
|
|
|
//Changed hProcessHeap to GetProcessHeap()
|
|
if ((uFlags & GMEM_MOVEABLE)==0) /* POINTER */
|
|
{
|
|
palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes);
|
|
if (! ISPOINTER(palloc))
|
|
{
|
|
DPRINT1("GlobalAlloced pointer which is not 8-byte aligned\n");
|
|
RtlFreeHeap(GetProcessHeap(), 0, palloc);
|
|
return NULL;
|
|
}
|
|
return (HGLOBAL) palloc;
|
|
}
|
|
else /* HANDLE */
|
|
{
|
|
HeapLock(hProcessHeap);
|
|
|
|
phandle = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(GLOBAL_HANDLE));
|
|
if (phandle)
|
|
{
|
|
phandle->Magic = MAGIC_GLOBAL_USED;
|
|
phandle->Flags = uFlags >> 8;
|
|
phandle->LockCount = 0;
|
|
phandle->Pointer = 0;
|
|
|
|
if (dwBytes)
|
|
{
|
|
palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes + HANDLE_SIZE);
|
|
if (palloc)
|
|
{
|
|
*(PHANDLE)palloc = INTERN_TO_HANDLE(phandle);
|
|
phandle->Pointer = palloc + HANDLE_SIZE;
|
|
}
|
|
else /*failed to allocate the memory block*/
|
|
{
|
|
RtlFreeHeap(GetProcessHeap(), 0, phandle);
|
|
phandle = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Allocated a 0 size movable block.\n");
|
|
DbgPrintStruct(phandle);
|
|
DPRINT("Address of the struct: 0x%X\n", phandle);
|
|
DPRINT("Address of pointer: 0x%X\n", &(phandle->Pointer));
|
|
}
|
|
}
|
|
HeapUnlock(hProcessHeap);
|
|
|
|
if (phandle)
|
|
{
|
|
if (ISPOINTER(INTERN_TO_HANDLE(phandle)))
|
|
{
|
|
DPRINT1("GlobalAlloced handle which is 8-byte aligned but shouldn't be\n");
|
|
RtlFreeHeap(GetProcessHeap(), 0, palloc);
|
|
RtlFreeHeap(GetProcessHeap(), 0, phandle);
|
|
return NULL;
|
|
}
|
|
return INTERN_TO_HANDLE(phandle);
|
|
}
|
|
else
|
|
return (HGLOBAL)0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
SIZE_T STDCALL
|
|
GlobalCompact(DWORD dwMinFree)
|
|
{
|
|
return RtlCompactHeap(hProcessHeap, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID STDCALL
|
|
GlobalFix(HGLOBAL hMem)
|
|
{
|
|
if (INVALID_HANDLE_VALUE != hMem)
|
|
GlobalLock(hMem);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT STDCALL
|
|
GlobalFlags(HGLOBAL hMem)
|
|
{
|
|
DWORD retval;
|
|
PGLOBAL_HANDLE phandle;
|
|
|
|
DPRINT("GlobalFlags( 0x%lX )\n", (ULONG)hMem);
|
|
|
|
if(!ISHANDLE(hMem))
|
|
{
|
|
DPRINT("GlobalFlags: Fixed memory.\n");
|
|
retval = 0;
|
|
}
|
|
else
|
|
{
|
|
HeapLock(GetProcessHeap());
|
|
|
|
phandle = HANDLE_TO_INTERN(hMem);
|
|
|
|
/*DbgPrintStruct(phandle);*/
|
|
|
|
if (MAGIC_GLOBAL_USED == phandle->Magic)
|
|
{
|
|
/*DbgPrint("GlobalFlags: Magic number ok\n");
|
|
**DbgPrint("GlobalFlags: pointer is 0x%X\n", phandle->Pointer);
|
|
*/
|
|
retval = phandle->LockCount + (phandle->Flags << 8);
|
|
if (0 == phandle->Pointer)
|
|
{
|
|
retval = retval | GMEM_DISCARDED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("GlobalSize: invalid handle\n");
|
|
retval = 0;
|
|
}
|
|
HeapUnlock(GetProcessHeap());
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HGLOBAL STDCALL
|
|
GlobalFree(HGLOBAL hMem)
|
|
{
|
|
PGLOBAL_HANDLE phandle;
|
|
|
|
DPRINT("GlobalFree( 0x%lX )\n", (ULONG)hMem);
|
|
|
|
if (ISPOINTER(hMem)) /* POINTER */
|
|
{
|
|
RtlFreeHeap(GetProcessHeap(), 0, (PVOID)hMem);
|
|
hMem = 0;
|
|
}
|
|
else /* HANDLE */
|
|
{
|
|
HeapLock(GetProcessHeap());
|
|
|
|
phandle = HANDLE_TO_INTERN(hMem);
|
|
|
|
if(MAGIC_GLOBAL_USED == phandle->Magic)
|
|
{
|
|
|
|
if(phandle->LockCount!=0)
|
|
{
|
|
DPRINT1("Warning! GlobalFree(0x%X) Freeing a handle to a locked object.\n", hMem);
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
if(phandle->Pointer)
|
|
RtlFreeHeap(GetProcessHeap(), 0, phandle->Pointer - HANDLE_SIZE);
|
|
|
|
RtlFreeHeap(GetProcessHeap(), 0, phandle);
|
|
}
|
|
HeapUnlock(GetProcessHeap());
|
|
|
|
hMem = 0;
|
|
}
|
|
return hMem;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HGLOBAL STDCALL
|
|
GlobalHandle(LPCVOID pMem)
|
|
{
|
|
HGLOBAL handle = 0;
|
|
PGLOBAL_HANDLE test = 0;
|
|
LPCVOID pointer_test = 0;
|
|
|
|
DPRINT("GlobalHandle( 0x%lX )\n", (ULONG)pMem);
|
|
if (0 == pMem) /*Invalid argument */
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
DPRINT1("Error: 0 handle.\n");
|
|
return 0;
|
|
}
|
|
|
|
HeapLock(GetProcessHeap());
|
|
/* Now test to see if this pointer is associated with a handle.
|
|
* This is done by calling RtlValidateHeap() and seeing if it fails.
|
|
*/
|
|
if (RtlValidateHeap(GetProcessHeap(), 0, (char *)pMem)) /*FIXED*/
|
|
{
|
|
handle = (HGLOBAL)pMem;
|
|
return handle;
|
|
}
|
|
else /*MOVABLE*/
|
|
{
|
|
handle = POINTER_TO_HANDLE(pMem);
|
|
}
|
|
|
|
|
|
/* Test to see if this memory is valid*/
|
|
test = HANDLE_TO_INTERN(handle);
|
|
if (!IsBadReadPtr(test, sizeof(GLOBAL_HANDLE)))
|
|
{
|
|
if (MAGIC_GLOBAL_USED == test->Magic)
|
|
{
|
|
pointer_test = test->Pointer;
|
|
if (!RtlValidateHeap(GetProcessHeap(), 0, ((char *)pointer_test) - HANDLE_SIZE) ||
|
|
!RtlValidateHeap(GetProcessHeap(), 0, test))
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
handle = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("GlobalHandle: Bad read pointer.\n");
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
handle = 0;
|
|
}
|
|
|
|
HeapUnlock(GetProcessHeap());
|
|
|
|
return handle;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
LPVOID STDCALL
|
|
GlobalLock(HGLOBAL hMem)
|
|
{
|
|
PGLOBAL_HANDLE phandle;
|
|
LPVOID palloc;
|
|
|
|
DPRINT("GlobalLock( 0x%lX )\n", (ULONG)hMem);
|
|
|
|
if (ISPOINTER(hMem))
|
|
return (LPVOID) hMem;
|
|
|
|
HeapLock(GetProcessHeap());
|
|
|
|
phandle = HANDLE_TO_INTERN(hMem);
|
|
|
|
if(MAGIC_GLOBAL_USED == phandle->Magic)
|
|
{
|
|
if(GLOBAL_LOCK_MAX > phandle->LockCount)
|
|
{
|
|
phandle->LockCount++;
|
|
}
|
|
palloc = phandle->Pointer;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("GlobalLock: invalid handle\n");
|
|
palloc = (LPVOID) hMem;
|
|
}
|
|
|
|
HeapUnlock(GetProcessHeap());
|
|
|
|
return palloc;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
STDCALL
|
|
GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
|
|
{
|
|
SYSTEM_BASIC_INFORMATION SysBasicInfo;
|
|
SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
|
|
ULONG UserMemory;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("GlobalMemoryStatusEx\n");
|
|
|
|
if (lpBuffer->dwLength != sizeof(MEMORYSTATUSEX))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = ZwQuerySystemInformation(SystemBasicInformation,
|
|
&SysBasicInfo,
|
|
sizeof(SysBasicInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastErrorByStatus(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = ZwQuerySystemInformation(SystemPerformanceInformation,
|
|
&SysPerfInfo,
|
|
sizeof(SysPerfInfo),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastErrorByStatus(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = ZwQuerySystemInformation(SystemFullMemoryInformation,
|
|
&UserMemory,
|
|
sizeof(ULONG),
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastErrorByStatus(Status);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Load percentage 0 thru 100. 0 is good and 100 is bad.
|
|
*
|
|
* Um = allocated memory / physical memory
|
|
* Um = 177 MB / 256 MB = 69.1%
|
|
*
|
|
* Mult allocated memory by 100 to move decimal point up.
|
|
*/
|
|
lpBuffer->dwMemoryLoad = (SysBasicInfo.NumberOfPhysicalPages -
|
|
SysPerfInfo.AvailablePages) * 100 /
|
|
SysBasicInfo.NumberOfPhysicalPages;
|
|
|
|
DPRINT1("Memory Load: %d\n",lpBuffer->dwMemoryLoad );
|
|
|
|
lpBuffer->ullTotalPhys = SysBasicInfo.NumberOfPhysicalPages *
|
|
SysBasicInfo.PhysicalPageSize;
|
|
lpBuffer->ullAvailPhys = SysPerfInfo.AvailablePages *
|
|
SysBasicInfo.PhysicalPageSize;
|
|
|
|
DPRINT("%d\n",SysPerfInfo.AvailablePages );
|
|
DPRINT("%d\n",lpBuffer->ullAvailPhys );
|
|
|
|
lpBuffer->ullTotalPageFile = SysPerfInfo.TotalCommitLimit *
|
|
SysBasicInfo.PhysicalPageSize;
|
|
|
|
DPRINT("%d\n",lpBuffer->ullTotalPageFile );
|
|
|
|
lpBuffer->ullAvailPageFile = ((SysPerfInfo.TotalCommitLimit -
|
|
SysPerfInfo.TotalCommittedPages) *
|
|
SysBasicInfo.PhysicalPageSize);
|
|
|
|
/* VM available to the calling processes, User Mem? */
|
|
lpBuffer->ullTotalVirtual = SysBasicInfo.HighestUserAddress -
|
|
SysBasicInfo.LowestUserAddress;
|
|
|
|
lpBuffer->ullAvailVirtual = (lpBuffer->ullTotalVirtual -
|
|
(UserMemory *
|
|
SysBasicInfo.PhysicalPageSize));
|
|
|
|
DPRINT("%d\n",lpBuffer->ullAvailVirtual );
|
|
DPRINT("%d\n",UserMemory);
|
|
DPRINT("%d\n",SysBasicInfo.PhysicalPageSize);
|
|
|
|
/* lol! Memory from beyond! */
|
|
lpBuffer->ullAvailExtendedVirtual = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID STDCALL
|
|
GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
|
|
{
|
|
MEMORYSTATUSEX lpBufferEx;
|
|
#if 0
|
|
if (lpBuffer->dwLength != sizeof(MEMORYSTATUS))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return;
|
|
}
|
|
#endif
|
|
lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
|
|
|
|
if (GlobalMemoryStatusEx(&lpBufferEx))
|
|
{
|
|
|
|
lpBuffer->dwLength = sizeof(MEMORYSTATUS);
|
|
|
|
lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
|
|
lpBuffer->dwTotalPhys = lpBufferEx.ullTotalPhys;
|
|
lpBuffer->dwAvailPhys = lpBufferEx.ullAvailPhys;
|
|
lpBuffer->dwTotalPageFile = lpBufferEx.ullTotalPageFile;
|
|
lpBuffer->dwAvailPageFile = lpBufferEx.ullAvailPageFile;
|
|
lpBuffer->dwTotalVirtual = lpBufferEx.ullTotalVirtual;
|
|
lpBuffer->dwAvailVirtual = lpBufferEx.ullAvailVirtual;
|
|
}
|
|
}
|
|
|
|
|
|
HGLOBAL STDCALL
|
|
GlobalReAlloc(HGLOBAL hMem,
|
|
DWORD dwBytes,
|
|
UINT uFlags)
|
|
{
|
|
|
|
LPVOID palloc = 0;
|
|
HGLOBAL hnew = 0;
|
|
PGLOBAL_HANDLE phandle = 0;
|
|
ULONG heap_flags = 0;
|
|
|
|
DPRINT("GlobalReAlloc( 0x%lX, 0x%lX, 0x%X )\n", (ULONG)hMem, dwBytes, uFlags);
|
|
|
|
hnew = 0;
|
|
|
|
if (uFlags & GMEM_ZEROINIT)
|
|
{
|
|
heap_flags = HEAP_ZERO_MEMORY;
|
|
}
|
|
|
|
HeapLock(GetProcessHeap());
|
|
|
|
if(uFlags & GMEM_MODIFY) /* modify flags */
|
|
{
|
|
if( ISPOINTER(hMem) && (uFlags & GMEM_MOVEABLE))
|
|
{
|
|
/* make a fixed block moveable
|
|
* actually only NT is able to do this. And it's soo simple
|
|
*/
|
|
if (0 == hMem)
|
|
{
|
|
SetLastError( ERROR_NOACCESS );
|
|
hnew = 0;
|
|
}
|
|
else
|
|
{
|
|
dwBytes = RtlSizeHeap(GetProcessHeap(), 0, (LPVOID) hMem);
|
|
hnew = GlobalAlloc( uFlags, dwBytes);
|
|
palloc = GlobalLock(hnew);
|
|
memcpy(palloc, (LPVOID) hMem, dwBytes);
|
|
GlobalUnlock(hnew);
|
|
RtlFreeHeap(GetProcessHeap(),0,hMem);
|
|
}
|
|
}
|
|
else if(ISPOINTER(hMem) && (uFlags & GMEM_DISCARDABLE))
|
|
{
|
|
/* change the flags to make our block "discardable" */
|
|
phandle = HANDLE_TO_INTERN(hMem);
|
|
phandle->Flags = phandle->Flags | (GMEM_DISCARDABLE >> 8);
|
|
hnew = hMem;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
hnew = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(ISPOINTER(hMem))
|
|
{
|
|
/* reallocate fixed memory */
|
|
hnew = (HANDLE)RtlReAllocateHeap(GetProcessHeap(), heap_flags, (LPVOID) hMem, dwBytes);
|
|
}
|
|
else
|
|
{
|
|
/* reallocate a moveable block */
|
|
phandle= HANDLE_TO_INTERN(hMem);
|
|
#if 0
|
|
if(phandle->LockCount != 0)
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
else
|
|
#endif
|
|
if (0 != dwBytes)
|
|
{
|
|
hnew = hMem;
|
|
if(phandle->Pointer)
|
|
{
|
|
palloc = RtlReAllocateHeap(GetProcessHeap(), heap_flags,
|
|
phandle->Pointer - HANDLE_SIZE,
|
|
dwBytes + HANDLE_SIZE);
|
|
if (0 == palloc)
|
|
{
|
|
hnew = 0;
|
|
}
|
|
else
|
|
{
|
|
*(PHANDLE)palloc = hMem;
|
|
phandle->Pointer = palloc + HANDLE_SIZE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
palloc = RtlAllocateHeap(GetProcessHeap(), heap_flags, dwBytes + HANDLE_SIZE);
|
|
if (0 == palloc)
|
|
{
|
|
hnew = 0;
|
|
}
|
|
else
|
|
{
|
|
*(PHANDLE)palloc = hMem;
|
|
phandle->Pointer = palloc + HANDLE_SIZE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hnew = hMem;
|
|
if(phandle->Pointer)
|
|
{
|
|
RtlFreeHeap(GetProcessHeap(), 0, phandle->Pointer - HANDLE_SIZE);
|
|
phandle->Pointer = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
HeapUnlock(GetProcessHeap());
|
|
|
|
return hnew;
|
|
}
|
|
|
|
|
|
DWORD STDCALL
|
|
GlobalSize(HGLOBAL hMem)
|
|
{
|
|
SIZE_T retval = 0;
|
|
PGLOBAL_HANDLE phandle = 0;
|
|
|
|
DPRINT("GlobalSize( 0x%lX )\n", (ULONG)hMem);
|
|
|
|
if(ISPOINTER(hMem)) /*FIXED*/
|
|
{
|
|
retval = RtlSizeHeap(GetProcessHeap(), 0, hMem);
|
|
}
|
|
else /*MOVEABLE*/
|
|
{
|
|
HeapLock(GetProcessHeap());
|
|
|
|
phandle = HANDLE_TO_INTERN(hMem);
|
|
|
|
if (MAGIC_GLOBAL_USED == phandle->Magic)
|
|
{
|
|
if (0 != phandle->Pointer)/*NOT DISCARDED*/
|
|
{
|
|
retval = RtlSizeHeap(GetProcessHeap(), 0, phandle->Pointer - HANDLE_SIZE);
|
|
|
|
if (retval == (SIZE_T)-1) /*RtlSizeHeap failed*/
|
|
{
|
|
/*
|
|
**TODO: RtlSizeHeap does not set last error.
|
|
** We should choose an error value to set as
|
|
** the last error. Which One?
|
|
*/
|
|
DPRINT("GlobalSize: RtlSizeHeap failed.\n");
|
|
retval = 0;
|
|
}
|
|
else /*Everything is ok*/
|
|
{
|
|
retval = retval - HANDLE_SIZE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINT("GlobalSize: invalid handle\n");
|
|
}
|
|
HeapUnlock(GetProcessHeap());
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID STDCALL
|
|
GlobalUnfix(HGLOBAL hMem)
|
|
{
|
|
if (hMem != INVALID_HANDLE_VALUE)
|
|
GlobalUnlock(hMem);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL STDCALL
|
|
GlobalUnlock(HGLOBAL hMem)
|
|
{
|
|
|
|
PGLOBAL_HANDLE phandle;
|
|
BOOL locked;
|
|
|
|
DPRINT("GlobalUnlock( 0x%lX )\n", (ULONG)hMem);
|
|
|
|
if(ISPOINTER(hMem))
|
|
{
|
|
SetLastError(ERROR_NOT_LOCKED);
|
|
return FALSE;
|
|
}
|
|
|
|
HeapLock(GetProcessHeap());
|
|
|
|
phandle = HANDLE_TO_INTERN(hMem);
|
|
if(MAGIC_GLOBAL_USED == phandle->Magic)
|
|
{
|
|
if (0 >= phandle->LockCount)
|
|
{
|
|
locked = FALSE;
|
|
SetLastError(ERROR_NOT_LOCKED);
|
|
}
|
|
else if (GLOBAL_LOCK_MAX > phandle->LockCount)
|
|
{
|
|
phandle->LockCount--;
|
|
locked = (0 == phandle->LockCount) ? TRUE : FALSE;
|
|
SetLastError(NO_ERROR);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPRINT("GlobalUnlock: invalid handle\n");
|
|
locked = FALSE;
|
|
}
|
|
HeapUnlock(GetProcessHeap());
|
|
return locked;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL STDCALL
|
|
GlobalUnWire(HGLOBAL hMem)
|
|
{
|
|
return GlobalUnlock(hMem);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
LPVOID STDCALL
|
|
GlobalWire(HGLOBAL hMem)
|
|
{
|
|
return GlobalLock(hMem);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
//HGLOBAL STDCALL
|
|
//GlobalDiscard(HGLOBAL hMem)
|
|
//{
|
|
// return GlobalReAlloc(hMem, 0, GMEM_MOVEABLE);
|
|
//}
|
|
/* EOF */
|