wine/memory/global.c
Alexandre Julliard 767e6f6f9d Release 980809
Sat Aug  8 19:11:46 1998  Marcus Meissner <marcus@jet.franken.de>

 	* [*/*]
	Added some missing WINAPI and some missing prototypes for
	functions.

	* [controls/static.c]
	Got rid of the MODULE32_LookupHMODULE error showing up for every
	message box.

	* [windows/winproc.c]
	WM_NOTIFY 16->32 mapping (AOL Instant Messenger or however it is called).

	* [misc/winsock.c]
	hostent/servent/protoent should not use the same static buffers.
	(has broken nt3.15 finger.exe which does hp=gethostbyname(), then
	getservbyname("finger","tcp") and the references hp->h_addr_list[0]).

Sat Aug  8 13:21:24 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [include/server.h] [tools/make_requests] [server/request.c]
	  [server/trace.c]
	Automated part of the client/server request code generation.
	Added tracing of client/server communication.

	* [scheduler/*.c] [server/process.c]
	Added support for server-side handles.

	* [scheduler/thread.c]
	Added DLL_THREAD_ATTACH/DETACH notifications.

	* [configure.in]
	Added check for -lsocket.

	* [windows/winproc.c]
	Return the thunk address in WINPROC_GetProc if the function types
	don't match.

Sat Aug  8 02:44:04 1998  Douglas Ridgway  <ridgway@winehq.com>

	* [windows/winproc.c][windows/win.c][windows/message.c]  
	Documentation for CallWindowProc, SetWindowLong, DispatchMessage,
	WaitMessage, GetMessage, and PeekMessage.

Sat Aug  8 01:00:00 1998  Juergen Schmied <juergen.schmied@metronet.de>

	* [controls/commctrl.c][controls/widgets.c][include/builtin32.h]
	  [include/commctrl.h][relay32/builtin32.c][relay32/comctl32.spec]
	  [tools/build.c] [relay32/shell32.spec]
	Added the functionality of the LibMain function. The common 
	controls are properly initialized now.

	* [controls/treeview.c][memory/atom.c][scheduler/thread.c][windows/class.c]
	  [windows/msgbox.c][windows/win.c]
	Put TRACE in, put SetLastError() in.

	* [include/interfaces.h]
	Added IClassFactory::LockServer.

	* [include/ole2.h]
	Added struct for LPOLEMENUGROUPWIDTHS32, HOLEMENU32.

	* [include/shell.h][include/shlobj.h][misc/shell.c][ole/folders.c]
	Reorganized and many structs and classes (IShellBrowser,IShellView)
	added. shell32.dll should work in many cases now.
	Started SHGetFileInfoA implementeation, rewrote SHGetPathFromIDList32A.
	New Shell32LibMain started ShellIconCache Implementation.

	* [misc/shellord.c]
	Rewrote ILCombine, ILGetSize
	New stubs SHFind_InitMenuPopup, FileMenu_Create, ShellExecuteEx,
	SHSetInstanceExplorer, SHGetInstanceExplorer, SHFreeUnusedLibraries.

	* [include/winerror.h]
	Class and window related error codes added.

	* [memory/heap.c]
	Changed lstrlen32A to strlen to get rid of milions of TRACE lines.

	* [misc/ddeml.c]
	First lines for DdeCreateStringHandle32A / DdeFreeStringHandle32.

	* [misc/network.c][relay32/mpr.spec]
	Fixed some bugs, changed ordinals.

	* [windows/class.c]
	Workarounds for incorrect hInstance handling. Fixes parts of
	MSWord95/Excel95 and Money95.

Thu Aug  6 21:05:35 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [windows/nonclient.c][misc/tweak.c][include/tweak.h]
	  [documentation/win95look]
	Removed some tweak variables. They are no longer needed.

	* [files/dos_fs.c]
	Added check for null pointer in DOSFS_GetDevice().

	* [controls/tooltips.c][include/commctrl.h]
	Improved tooltips.

	* [controls/status.c][include/commctrl.h]
	Cleaned up code and added tooltip support.

	* [controls/toolbar.c][include/commctrl.h]
	Added tooltip support.

	* [documentation/common_controls]
	Updated.

Thu Aug  6 00:05:22 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [include/ver.h] [misc/ver.c]
	Write VIF_BUFFTOOSMALL, not VIF_BUFTOSMALL.

	* [debugger/hash.c] [debugger/stabs.c]
	Make debug output more friendly for posting.

	* [files/file.c]
	Partial implementation of OF_SHARE_EXCLUSIVE.
	Needed for Quicklogic/QuickChip (InstallShield).

	* [files/profile.c]
	When a cached-only entry is found, return it.

	* [graphics/x11drv/xfont.c]
	Accept a space as delimiter for a fontname and inhibit overrun
	(Make xplasim.ex from the Phillips Coolrunner CPLD suite proceed).

	* [miscemu/main.c]
	Delay setting IF1632_CallLargeStack after loading the executables.
	Stops fpgaexp.exe from the Viewlogic FPGA suite from crashing when
 	showing the Blinker error Message Box.

	* [misc/network.c]
	Make WNetGetConnection16 recognise a CDROM as a local drive.

	* [multimedia/mmsystem.c]
	Preliminary check for MCI_ALL_DEVICE_ID in MCI_Close by a FIXME.


Tue Aug 4 21:15:23 1998  James Juran <jrj120@psu.edu>

	* [ole/ole2nls.c]
	Fixed bug in CompareString32A.  strcmp() doesn't necessarily
	return -1, 0, or 1, which the previous code depended on.
	Changed name of is_punctuation to OLE2NLS_isPunctuation.
	Made NORM_IGNOREWIDTH not print a FIXME message in 
	LCMapString32A.
	Other debugging messages, documentation, and code cleanups.

	* [objects/font.c] [relay32/gdi32.spec] [include/winerror.h]
	Added stub for GetFontData32, and added GDI_ERROR constant 
	to winerror.h.

Tue Aug  4 07:44:43 1998  Ove Kaaven <ovek@arcticnet.no>

	* [multimedia/mmio.c]
	Implemented mmioSetBuffer, mmioAdvance, mmioAscend, and
	mmioCreateChunk to the best of my knowledge. But watch out,
	there's bound to be bugs in there...

	* [include/mmsystem.h] [multimedia/mmsystem.c]
	Hacked in support for 32-bit multimedia function callbacks.

	* [AUTHORS] [misc/shell.c]
	Selfishly credited my authorship. Hopefully I'm excused.

	* [include/dosexe.h] [include/module.h] [loader/dos/*]
	  [loader/module.c] [loader/task.c] [Makefile.in]
	  [configure.in] [Makefile.in]
	Added DOS EXE (MZ) loader and virtual machine. Task
	structure integration thanks to Ulrich Weigand.

	* [files/dos_fs.c]
	Work around a null pointer dereference if ioctlGetDeviceInfo-ing
	a FILE_DupUnixHandle'd file (i.e. GetStdHandle'd).

	* [include/miscemu.h] [include/winnt.h] [loader/main.c]
	  [memory/global.c] [msdos/dpmi.c] [msdos/dosmem.c]
	Added support for DOS memory images, and added
	DOSMEM_ResizeBlock() and DOSMEM_Available().

	* [msdos/int21.c]
	Added support for the DOS virtual machine, tweaked handle
	assignment to avoid stdio clashes, forced INT21_FindNext to exit
	wildcardless searches after finding one entry, added AH=7, 8, 9,
	C, 48, 49, 4A, and 7160 CL=1 (Get Short Filename), and made the
	long filename calls only respond if running with with -winver
	win95.

	* [objects/cursoricon.c]
	DestroyCursor32 and DestroyIcon32 should now free the objects
	(hopefully) correctly.

Sun Aug  2 21:42:09 1998  Huw D M Davies <daviesh@abacus.physics.ox.ac.uk>

	* [graphics/psdrv/*] [include/psdrv.h]
	Added PPD file parsing - at the moment it reads a file called
	default.ppd from the directory in which you start Wine. Page sizes
	other than A4 should now work (landscape may not). All fonts that are
	present on your printer (according to the PPD) should be available,
	providing you have the AFM files. Fonts should now be the correct size.
	Graphics is still basically lines only. See graphics/psdrv/README .

	* [misc/printdrv.c]
	Yet more Drv[Get/Set]PrinterData fixes.

Fri Jul 31 21:33:22 1998  Per Lindström <pelinstr@algonet.se>

	* [relay32/crtdll.spec] [misc/crtdll.c]
	Added stub for freopen, _findfirst, _findnext, _fstat and _read.

	* [files/directory.c]
	Modified warning message.

Wed Jul 29 11:25:28 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>

	* [objects/font.c]
	Added stub for GetFontData.

	* [multimedia/msvideo.c]
	Created this file to hold the msvideo.dll calls (and maybe also
	msvfw32.dll). 

	* [objects/cursoricon.c]
	Added search in Global Heap for cursor when trying to destroy it
	with DestroyCursor16. This test should be done in many (all?)
	other functions that use FreeResource.

	* [controls/treeview.c] [include/commctrl.h]
	Minor correction in name and addition of many placeholders for TVM
	messages in TREEVIEW_WindowProc.

	* [msdos/dpmi.c]
	Fixed a bug in DPMI_xrealloc where in a copy of a memory region
	"A" of size "a" to a region "B" of size "b", "b" bytes were being
	copied, instead of "a", as the new version does. This both
	increases speed, as well as avoids segfaults.
1998-08-09 12:47:43 +00:00

1509 lines
41 KiB
C

/*
* Global heap functions
*
* Copyright 1995 Alexandre Julliard
*/
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "windows.h"
#include "global.h"
#include "heap.h"
#include "toolhelp.h"
#include "selectors.h"
#include "miscemu.h"
#include "dde_mem.h"
#include "stackframe.h"
#include "module.h"
#include "debug.h"
#include "winerror.h"
/* Global arena block */
typedef struct
{
DWORD base; /* Base address (0 if discarded) */
DWORD size; /* Size in bytes (0 indicates a free block) */
HGLOBAL16 handle; /* Handle for this block */
HGLOBAL16 hOwner; /* Owner of this block */
BYTE lockCount; /* Count of GlobalFix() calls */
BYTE pageLockCount; /* Count of GlobalPageLock() calls */
BYTE flags; /* Allocation flags */
BYTE selCount; /* Number of selectors allocated for this block */
#ifdef CONFIG_IPC
int shmid;
#endif
} GLOBALARENA;
/* Flags definitions */
#define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
#define GA_DGROUP 0x04
#define GA_DISCARDABLE 0x08
#define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
/* Arena array */
static GLOBALARENA *pGlobalArena = NULL;
static int globalArenaSize = 0;
#define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
#define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
#define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
/***********************************************************************
* GLOBAL_GetArena
*
* Return the arena for a given selector, growing the arena array if needed.
*/
static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
{
if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
{
int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
GLOBALARENA *pNewArena = realloc( pGlobalArena,
newsize * sizeof(GLOBALARENA) );
if (!pNewArena) return 0;
pGlobalArena = pNewArena;
memset( pGlobalArena + globalArenaSize, 0,
(newsize - globalArenaSize) * sizeof(GLOBALARENA) );
globalArenaSize = newsize;
}
return pGlobalArena + (sel >> __AHSHIFT);
}
void debug_handles()
{
int printed=0;
int i;
for (i = globalArenaSize-1 ; i>=0 ; i--) {
if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
printed=1;
DUMP("0x%08x, ",pGlobalArena[i].handle);
}
}
if (printed)
DUMP("\n");
}
/***********************************************************************
* GLOBAL_CreateBlock
*
* Create a global heap block for a fixed range of linear memory.
*/
HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
HGLOBAL16 hOwner, BOOL16 isCode,
BOOL16 is32Bit, BOOL16 isReadOnly,
SHMDATA *shmdata )
{
WORD sel, selcount;
GLOBALARENA *pArena;
/* Allocate the selector(s) */
sel = SELECTOR_AllocBlock( ptr, size,
isCode ? SEGMENT_CODE : SEGMENT_DATA,
is32Bit, isReadOnly );
if (!sel) return 0;
selcount = (size + 0xffff) / 0x10000;
if (!(pArena = GLOBAL_GetArena( sel, selcount )))
{
SELECTOR_FreeBlock( sel, selcount );
return 0;
}
/* Fill the arena block */
pArena->base = (DWORD)ptr;
pArena->size = GET_SEL_LIMIT(sel) + 1;
#ifdef CONFIG_IPC
if (flags & GMEM_DDESHARE)
{
pArena->handle = shmdata->handle;
pArena->shmid = shmdata->shmid;
shmdata->sel = sel;
}
else
{
pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
pArena->shmid = 0;
}
#else
pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
#endif
pArena->hOwner = hOwner;
pArena->lockCount = 0;
pArena->pageLockCount = 0;
pArena->flags = flags & GA_MOVEABLE;
if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
if (!isCode) pArena->flags |= GA_DGROUP;
pArena->selCount = selcount;
if (selcount > 1) /* clear the next arena blocks */
memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
return pArena->handle;
}
/***********************************************************************
* GLOBAL_FreeBlock
*
* Free a block allocated by GLOBAL_CreateBlock, without touching
* the associated linear memory range.
*/
BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
{
WORD sel;
GLOBALARENA *pArena;
if (!handle) return TRUE;
sel = GlobalHandleToSel( handle );
if (!VALID_HANDLE(sel))
return FALSE;
pArena = GET_ARENA_PTR(sel);
SELECTOR_FreeBlock( sel, (pArena->size + 0xffff) / 0x10000 );
memset( pArena, 0, sizeof(GLOBALARENA) );
return TRUE;
}
/***********************************************************************
* GLOBAL_Alloc
*
* Implementation of GlobalAlloc16()
*/
HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
BOOL16 isCode, BOOL16 is32Bit, BOOL16 isReadOnly )
{
void *ptr;
HGLOBAL16 handle;
SHMDATA shmdata;
TRACE(global, "%ld flags=%04x\n", size, flags );
/* If size is 0, create a discarded block */
if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, isCode,
is32Bit, isReadOnly, NULL );
/* Fixup the size */
if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
size = (size + 0x1f) & ~0x1f;
/* Allocate the linear memory */
#ifdef CONFIG_IPC
if (flags & GMEM_DDESHARE)
ptr = DDE_malloc(flags, size, &shmdata);
else
#endif /* CONFIG_IPC */
{
ptr = HeapAlloc( SystemHeap, 0, size );
}
/* FIXME: free discardable blocks and try again? */
if (!ptr) return 0;
/* Allocate the selector(s) */
handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
isCode, is32Bit, isReadOnly, &shmdata);
if (!handle)
{
HeapFree( SystemHeap, 0, ptr );
return 0;
}
if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
return handle;
}
#ifdef CONFIG_IPC
/***********************************************************************
* GLOBAL_FindArena
*
* Find the arena for a given handle
* (when handle is not serial - e.g. DDE)
*/
static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
{
int i;
for (i = globalArenaSize-1 ; i>=0 ; i--) {
if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
return ( &pGlobalArena[i] );
}
return NULL;
}
/***********************************************************************
* DDE_GlobalHandleToSel
*/
WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
{
GLOBALARENA *pArena;
SEGPTR segptr;
pArena= GLOBAL_FindArena(handle);
if (pArena) {
int ArenaIdx = pArena - pGlobalArena;
/* See if synchronized to the shared memory */
return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
}
/* attach the block */
DDE_AttachHandle(handle, &segptr);
return SELECTOROF( segptr );
}
#endif /* CONFIG_IPC */
/***********************************************************************
* GlobalAlloc16 (KERNEL.15)
* RETURNS
* Handle: Success
* NULL: Failure
*/
HGLOBAL16 WINAPI GlobalAlloc16(
UINT16 flags, /* [in] Object allocation attributes */
DWORD size /* [in] Number of bytes to allocate */
) {
HANDLE16 owner = GetCurrentPDB();
if (flags & GMEM_DDESHARE)
owner = GetExePtr(owner); /* Make it a module handle */
return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
}
/***********************************************************************
* GlobalReAlloc16 (KERNEL.16)
* RETURNS
* Handle: Success
* NULL: Failure
*/
HGLOBAL16 WINAPI GlobalReAlloc16(
HGLOBAL16 handle, /* [in] Handle of global memory object */
DWORD size, /* [in] New size of block */
UINT16 flags /* [in] How to reallocate object */
) {
WORD selcount;
DWORD oldsize;
void *ptr;
GLOBALARENA *pArena, *pNewArena;
WORD sel = GlobalHandleToSel( handle );
TRACE(global, "%04x %ld flags=%04x\n",
handle, size, flags );
if (!handle) return 0;
#ifdef CONFIG_IPC
if (flags & GMEM_DDESHARE || is_dde_handle(handle))
{
FIXME(global, "shared memory reallocating unimplemented\n");
return 0;
}
#endif /* CONFIG_IPC */
if (!VALID_HANDLE(handle)) {
WARN(global, "Invalid handle 0x%04x!\n", handle);
return 0;
}
pArena = GET_ARENA_PTR( handle );
/* Discard the block if requested */
if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
{
if (!(pArena->flags & GA_MOVEABLE) ||
!(pArena->flags & GA_DISCARDABLE) ||
(pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
HeapFree( SystemHeap, 0, (void *)pArena->base );
pArena->base = 0;
/* Note: we rely on the fact that SELECTOR_ReallocBlock won't
* change the selector if we are shrinking the block.
* FIXME: shouldn't we keep selectors until the block is deleted?
*/
SELECTOR_ReallocBlock( sel, 0, 1, SEGMENT_DATA, 0, 0 );
return handle;
}
/* Fixup the size */
if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
if (size == 0) size = 0x20;
else size = (size + 0x1f) & ~0x1f;
/* Change the flags */
if (flags & GMEM_MODIFY)
{
/* Change the flags, leaving GA_DGROUP alone */
pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
return handle;
}
/* Reallocate the linear memory */
ptr = (void *)pArena->base;
oldsize = pArena->size;
TRACE(global,"oldsize %08lx\n",oldsize);
if (ptr && (size == oldsize)) return handle; /* Nothing to do */
ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
if (!ptr)
{
SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
memset( pArena, 0, sizeof(GLOBALARENA) );
return 0;
}
/* Reallocate the selector(s) */
sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
if (!sel)
{
HeapFree( SystemHeap, 0, ptr );
memset( pArena, 0, sizeof(GLOBALARENA) );
return 0;
}
selcount = (size + 0xffff) / 0x10000;
if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
{
HeapFree( SystemHeap, 0, ptr );
SELECTOR_FreeBlock( sel, selcount );
return 0;
}
/* Fill the new arena block */
if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
pNewArena->base = (DWORD)ptr;
pNewArena->size = GET_SEL_LIMIT(sel) + 1;
pNewArena->selCount = selcount;
pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
if (selcount > 1) /* clear the next arena blocks */
memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
if ((oldsize < size) && (flags & GMEM_ZEROINIT))
memset( (char *)ptr + oldsize, 0, size - oldsize );
return pNewArena->handle;
}
/***********************************************************************
* GlobalFree16 (KERNEL.17)
* RETURNS
* NULL: Success
* Handle: Failure
*/
HGLOBAL16 WINAPI GlobalFree16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
void *ptr;
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalFree16!\n",handle);
return 0;
}
ptr = (void *)GET_ARENA_PTR(handle)->base;
TRACE(global, "%04x\n", handle );
if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
#ifdef CONFIG_IPC
if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
#endif /* CONFIG_IPC */
if (ptr) HeapFree( SystemHeap, 0, ptr );
return 0;
}
/***********************************************************************
* WIN16_GlobalLock16 (KERNEL.18)
*
* This is the GlobalLock16() function used by 16-bit code.
*/
SEGPTR WINAPI WIN16_GlobalLock16( HGLOBAL16 handle )
{
TRACE(global, "(%04x) -> %08lx\n",
handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
if (handle)
{
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
#ifdef CONFIG_IPC
if (is_dde_handle(handle))
return PTR_SEG_OFF_TO_SEGPTR( DDE_GlobalHandleToSel(handle), 0 );
#endif /* CONFIG_IPC */
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to WIN16_GlobalLock16!\n",handle);
return (SEGPTR)0;
}
if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
GET_ARENA_PTR(handle)->lockCount++;
return PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(handle), 0 );
/* FIXME: put segment value in CX as well */
}
return (SEGPTR)0;
}
/***********************************************************************
* GlobalLock16 (KERNEL.18)
*
* This is the GlobalLock16() function used by 32-bit code.
*
* RETURNS
* Pointer to first byte of memory block
* NULL: Failure
*/
LPVOID WINAPI GlobalLock16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
if (!handle) return 0;
if (!VALID_HANDLE(handle))
return (LPVOID)0;
GET_ARENA_PTR(handle)->lockCount++;
#ifdef CONFIG_IPC
if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
#endif
return (LPVOID)GET_ARENA_PTR(handle)->base;
}
/***********************************************************************
* GlobalUnlock16 (KERNEL.19)
* NOTES
* Should the return values be cast to booleans?
*
* RETURNS
* TRUE: Object is still locked
* FALSE: Object is unlocked
*/
BOOL16 WINAPI GlobalUnlock16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
GLOBALARENA *pArena = GET_ARENA_PTR(handle);
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalUnlock16!\n",handle);
return 0;
}
TRACE(global, "%04x\n", handle );
if (pArena->lockCount) pArena->lockCount--;
return pArena->lockCount;
}
/***********************************************************************
* GlobalSize16 (KERNEL.20)
* RETURNS
* Size in bytes of object
* 0: Failure
*/
DWORD WINAPI GlobalSize16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
TRACE(global, "%04x\n", handle );
if (!handle) return 0;
if (!VALID_HANDLE(handle))
return 0;
return GET_ARENA_PTR(handle)->size;
}
/***********************************************************************
* GlobalHandle16 (KERNEL.21)
* NOTES
* Why is GlobalHandleToSel used here with the sel as input?
*
* RETURNS
* Handle: Success
* NULL: Failure
*/
DWORD WINAPI GlobalHandle16(
WORD sel /* [in] Address of global memory block */
) {
TRACE(global, "%04x\n", sel );
if (!VALID_HANDLE(sel)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalHandle16!\n",sel);
return 0;
}
return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
}
/***********************************************************************
* GlobalHandleNoRIP (KERNEL.159)
*/
DWORD WINAPI GlobalHandleNoRIP( WORD sel )
{
int i;
for (i = globalArenaSize-1 ; i>=0 ; i--) {
if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == sel)
return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
}
return 0;
}
/***********************************************************************
* GlobalFlags16 (KERNEL.22)
* NOTES
* Should this return GMEM_INVALID_HANDLE instead of 0 on invalid
* handle?
*
* RETURNS
* Value specifying flags and lock count
* GMEM_INVALID_HANDLE: Invalid handle
*/
UINT16 WINAPI GlobalFlags16(
HGLOBAL16 handle /* [in] Handle of global memory object */
) {
GLOBALARENA *pArena;
TRACE(global, "%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalFlags16!\n",handle);
return 0;
}
pArena = GET_ARENA_PTR(handle);
return pArena->lockCount |
((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
((pArena->base == 0) ? GMEM_DISCARDED : 0);
}
/***********************************************************************
* LockSegment16 (KERNEL.23)
*/
HGLOBAL16 WINAPI LockSegment16( HGLOBAL16 handle )
{
TRACE(global, "%04x\n", handle );
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to LockSegment16!\n",handle);
return 0;
}
GET_ARENA_PTR(handle)->lockCount++;
return handle;
}
/***********************************************************************
* UnlockSegment16 (KERNEL.24)
*/
void WINAPI UnlockSegment16( HGLOBAL16 handle )
{
TRACE(global, "%04x\n", handle );
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to UnlockSegment16!\n",handle);
return;
}
GET_ARENA_PTR(handle)->lockCount--;
/* FIXME: this ought to return the lock count in CX (go figure...) */
}
/***********************************************************************
* GlobalCompact16 (KERNEL.25)
*/
DWORD WINAPI GlobalCompact16( DWORD desired )
{
return GLOBAL_MAX_ALLOC_SIZE;
}
/***********************************************************************
* GlobalFreeAll (KERNEL.26)
*/
void WINAPI GlobalFreeAll( HGLOBAL16 owner )
{
DWORD i;
GLOBALARENA *pArena;
pArena = pGlobalArena;
for (i = 0; i < globalArenaSize; i++, pArena++)
{
if ((pArena->size != 0) && (pArena->hOwner == owner))
GlobalFree16( pArena->handle );
}
}
/***********************************************************************
* GlobalWire16 (KERNEL.111)
*/
SEGPTR WINAPI GlobalWire16( HGLOBAL16 handle )
{
return WIN16_GlobalLock16( handle );
}
/***********************************************************************
* GlobalUnWire16 (KERNEL.112)
*/
BOOL16 WINAPI GlobalUnWire16( HGLOBAL16 handle )
{
return !GlobalUnlock16( handle );
}
/***********************************************************************
* SetSwapAreaSize16 (KERNEL.106)
*/
LONG WINAPI SetSwapAreaSize16( WORD size )
{
FIXME(global, "(%d) - stub!\n", size );
return MAKELONG( size, 0xffff );
}
/***********************************************************************
* GlobalLRUOldest (KERNEL.163)
*/
HGLOBAL16 WINAPI GlobalLRUOldest( HGLOBAL16 handle )
{
TRACE(global, "%04x\n", handle );
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
return handle;
}
/***********************************************************************
* GlobalLRUNewest (KERNEL.164)
*/
HGLOBAL16 WINAPI GlobalLRUNewest( HGLOBAL16 handle )
{
TRACE(global, "%04x\n", handle );
if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
return handle;
}
/***********************************************************************
* GetFreeSpace16 (KERNEL.169)
*/
DWORD WINAPI GetFreeSpace16( UINT16 wFlags )
{
MEMORYSTATUS ms;
GlobalMemoryStatus( &ms );
return ms.dwAvailVirtual;
}
/***********************************************************************
* GlobalDOSAlloc (KERNEL.184)
* RETURNS
* Address (HW=Paragraph segment; LW=Selector)
*/
DWORD WINAPI GlobalDOSAlloc(
DWORD size /* [in] Number of bytes to be allocated */
) {
UINT16 uParagraph;
LPVOID lpBlock = DOSMEM_GetBlock( 0, size, &uParagraph );
if( lpBlock )
{
HMODULE16 hModule = GetModuleHandle16("KERNEL");
WORD wSelector;
wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size,
hModule, 0, 0, 0, NULL );
return MAKELONG(wSelector,uParagraph);
}
return 0;
}
/***********************************************************************
* GlobalDOSFree (KERNEL.185)
* RETURNS
* NULL: Success
* sel: Failure
*/
WORD WINAPI GlobalDOSFree(
WORD sel /* [in] Selector */
) {
DWORD block = GetSelectorBase(sel);
if( block && block < 0x100000 )
{
LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
if( DOSMEM_FreeBlock( 0, lpBlock ) )
GLOBAL_FreeBlock( sel );
sel = 0;
}
return sel;
}
/***********************************************************************
* GlobalPageLock (KERNEL.191)
*/
WORD WINAPI GlobalPageLock( HGLOBAL16 handle )
{
TRACE(global, "%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalPageLock!\n",handle);
return 0;
}
return ++(GET_ARENA_PTR(handle)->pageLockCount);
}
/***********************************************************************
* GlobalPageUnlock (KERNEL.192)
*/
WORD WINAPI GlobalPageUnlock( HGLOBAL16 handle )
{
TRACE(global, "%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalPageUnlock!\n",handle);
return 0;
}
return --(GET_ARENA_PTR(handle)->pageLockCount);
}
/***********************************************************************
* GlobalFix16 (KERNEL.197)
*/
void WINAPI GlobalFix16( HGLOBAL16 handle )
{
TRACE(global, "%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalFix16!\n",handle);
return;
}
GET_ARENA_PTR(handle)->lockCount++;
}
/***********************************************************************
* GlobalUnfix16 (KERNEL.198)
*/
void WINAPI GlobalUnfix16( HGLOBAL16 handle )
{
TRACE(global, "%04x\n", handle );
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalUnfix16!\n",handle);
return;
}
GET_ARENA_PTR(handle)->lockCount--;
}
/***********************************************************************
* FarSetOwner (KERNEL.403)
*/
void WINAPI FarSetOwner( HGLOBAL16 handle, HANDLE16 hOwner )
{
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to FarSetOwner!\n",handle);
return;
}
GET_ARENA_PTR(handle)->hOwner = hOwner;
}
/***********************************************************************
* FarGetOwner (KERNEL.404)
*/
HANDLE16 WINAPI FarGetOwner( HGLOBAL16 handle )
{
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to FarGetOwner!\n",handle);
return 0;
}
return GET_ARENA_PTR(handle)->hOwner;
}
/***********************************************************************
* GlobalHandleToSel (TOOLHELP.50)
*/
WORD WINAPI GlobalHandleToSel( HGLOBAL16 handle )
{
TRACE(toolhelp, "%04x\n", handle );
if (!handle) return 0;
#ifdef CONFIG_IPC
if (is_dde_handle(handle)) return DDE_GlobalHandleToSel(handle);
#endif
if (!VALID_HANDLE(handle)) {
WARN(global,"Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle);
return 0;
}
if (!(handle & 7))
{
WARN(global, "Program attempted invalid selector conversion\n" );
return handle - 1;
}
return handle | 7;
}
/***********************************************************************
* GlobalFirst (TOOLHELP.51)
*/
BOOL16 WINAPI GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
{
if (wFlags == GLOBAL_LRU) return FALSE;
pGlobal->dwNext = 0;
return GlobalNext( pGlobal, wFlags );
}
/***********************************************************************
* GlobalNext (TOOLHELP.52)
*/
BOOL16 WINAPI GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
{
GLOBALARENA *pArena;
if (pGlobal->dwNext >= globalArenaSize) return FALSE;
pArena = pGlobalArena + pGlobal->dwNext;
if (wFlags == GLOBAL_FREE) /* only free blocks */
{
int i;
for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
if (pArena->size == 0) break; /* block is free */
if (i >= globalArenaSize) return FALSE;
pGlobal->dwNext = i;
}
pGlobal->dwAddress = pArena->base;
pGlobal->dwBlockSize = pArena->size;
pGlobal->hBlock = pArena->handle;
pGlobal->wcLock = pArena->lockCount;
pGlobal->wcPageLock = pArena->pageLockCount;
pGlobal->wFlags = (GetCurrentPDB() == pArena->hOwner);
pGlobal->wHeapPresent = FALSE;
pGlobal->hOwner = pArena->hOwner;
pGlobal->wType = GT_UNKNOWN;
pGlobal->wData = 0;
pGlobal->dwNext++;
return TRUE;
}
/***********************************************************************
* GlobalInfo (TOOLHELP.53)
*/
BOOL16 WINAPI GlobalInfo( GLOBALINFO *pInfo )
{
int i;
GLOBALARENA *pArena;
pInfo->wcItems = globalArenaSize;
pInfo->wcItemsFree = 0;
pInfo->wcItemsLRU = 0;
for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
if (pArena->size == 0) pInfo->wcItemsFree++;
return TRUE;
}
/***********************************************************************
* GlobalEntryHandle (TOOLHELP.54)
*/
BOOL16 WINAPI GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
{
GLOBALARENA *pArena = GET_ARENA_PTR(hItem);
pGlobal->dwAddress = pArena->base;
pGlobal->dwBlockSize = pArena->size;
pGlobal->hBlock = pArena->handle;
pGlobal->wcLock = pArena->lockCount;
pGlobal->wcPageLock = pArena->pageLockCount;
pGlobal->wFlags = (GetCurrentPDB() == pArena->hOwner);
pGlobal->wHeapPresent = FALSE;
pGlobal->hOwner = pArena->hOwner;
pGlobal->wType = GT_UNKNOWN;
pGlobal->wData = 0;
pGlobal->dwNext++;
return TRUE;
}
/***********************************************************************
* GlobalEntryModule (TOOLHELP.55)
*/
BOOL16 WINAPI GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE16 hModule,
WORD wSeg )
{
return FALSE;
}
/***********************************************************************
* MemManInfo (TOOLHELP.72)
*/
BOOL16 WINAPI MemManInfo( MEMMANINFO *info )
{
MEMORYSTATUS status;
/*
* Not unsurprisingly although the documention says you
* _must_ provide the size in the dwSize field, this function
* (under Windows) always fills the structure and returns true.
*/
GlobalMemoryStatus( &status );
info->wPageSize = VIRTUAL_GetPageSize();
info->dwLargestFreeBlock = status.dwAvailVirtual;
info->dwMaxPagesAvailable = info->dwLargestFreeBlock / info->wPageSize;
info->dwMaxPagesLockable = info->dwMaxPagesAvailable;
info->dwTotalLinearSpace = status.dwTotalVirtual / info->wPageSize;
info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
info->dwFreePages = info->dwMaxPagesAvailable;
info->dwTotalPages = info->dwTotalLinearSpace;
info->dwFreeLinearSpace = info->dwMaxPagesAvailable;
info->dwSwapFilePages = status.dwTotalPageFile / info->wPageSize;
return TRUE;
}
/***********************************************************************
* GetFreeMemInfo (KERNEL.316)
*/
DWORD WINAPI GetFreeMemInfo(void)
{
MEMMANINFO info;
MemManInfo( &info );
return MAKELONG( info.dwTotalLinearSpace, info.dwMaxPagesAvailable );
}
/*
* Win32 Global heap functions (GlobalXXX).
* 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.
*
* The handle stuff looks horrible, but it's implemented almost like Win95
* does it.
*
*/
#define MAGIC_GLOBAL_USED 0x5342
#define GLOBAL_LOCK_MAX 0xFF
#define HANDLE_TO_INTERN(h) ((PGLOBAL32_INTERN)(((char *)(h))-2))
#define INTERN_TO_HANDLE(i) ((HGLOBAL32) &((i)->Pointer))
#define POINTER_TO_HANDLE(p) (*(((HGLOBAL32 *)(p))-1))
#define ISHANDLE(h) (((DWORD)(h)&2)!=0)
#define ISPOINTER(h) (((DWORD)(h)&2)==0)
typedef struct __GLOBAL32_INTERN
{
WORD Magic;
LPVOID Pointer WINE_PACKED;
BYTE Flags;
BYTE LockCount;
} GLOBAL32_INTERN, *PGLOBAL32_INTERN;
/***********************************************************************
* GlobalAlloc32 (KERNEL32.315)
* RETURNS
* Handle: Success
* NULL: Failure
*/
HGLOBAL32 WINAPI GlobalAlloc32(
UINT32 flags, /* [in] Object allocation attributes */
DWORD 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, size);
return (HGLOBAL32) palloc;
}
else /* HANDLE */
{
/* HeapLock(GetProcessHeap()); */
pintern=HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
if(size)
{
palloc=HeapAlloc(GetProcessHeap(), hpflags, size+sizeof(HGLOBAL32));
*(HGLOBAL32 *)palloc=INTERN_TO_HANDLE(pintern);
pintern->Pointer=palloc+sizeof(HGLOBAL32);
}
else
pintern->Pointer=NULL;
pintern->Magic=MAGIC_GLOBAL_USED;
pintern->Flags=flags>>8;
pintern->LockCount=0;
/* HeapUnlock(GetProcessHeap()); */
return INTERN_TO_HANDLE(pintern);
}
}
/***********************************************************************
* GlobalLock32 (KERNEL32.326)
* RETURNS
* Pointer to first byte of block
* NULL: Failure
*/
LPVOID WINAPI GlobalLock32(
HGLOBAL32 hmem /* [in] Handle of global memory object */
) {
PGLOBAL32_INTERN pintern;
LPVOID palloc;
if(ISPOINTER(hmem))
return (LPVOID) hmem;
/* HeapLock(GetProcessHeap()); */
pintern=HANDLE_TO_INTERN(hmem);
if(pintern->Magic==MAGIC_GLOBAL_USED)
{
if(pintern->LockCount<GLOBAL_LOCK_MAX)
pintern->LockCount++;
palloc=pintern->Pointer;
}
else
{
WARN(global, "invalid handle\n");
palloc=(LPVOID) NULL;
}
/* HeapUnlock(GetProcessHeap()); */;
return palloc;
}
/***********************************************************************
* GlobalUnlock32 (KERNEL32.332)
* RETURNS
* TRUE: Object is still locked
* FALSE: Object is unlocked
*/
BOOL32 WINAPI GlobalUnlock32(
HGLOBAL32 hmem /* [in] Handle of global memory object */
) {
PGLOBAL32_INTERN pintern;
BOOL32 locked;
if(ISPOINTER(hmem))
return FALSE;
/* HeapLock(GetProcessHeap()); */
pintern=HANDLE_TO_INTERN(hmem);
if(pintern->Magic==MAGIC_GLOBAL_USED)
{
if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
pintern->LockCount--;
locked=(pintern->LockCount==0) ? FALSE : TRUE;
}
else
{
WARN(global, "invalid handle\n");
locked=FALSE;
}
/* HeapUnlock(GetProcessHeap()); */
return locked;
}
/***********************************************************************
* GlobalHandle32 (KERNEL32.325)
* Returns the handle associated with the specified pointer.
*
* NOTES
* Since there in only one goto, can it be removed and the return
* be put 'inline'?
*
* RETURNS
* Handle: Success
* NULL: Failure
*/
HGLOBAL32 WINAPI GlobalHandle32(
LPCVOID pmem /* [in] Pointer to global memory block */
) {
HGLOBAL32 handle;
if (!HEAP_IsInsideHeap( GetProcessHeap(), 0, pmem )) goto error;
handle = POINTER_TO_HANDLE(pmem);
if (HEAP_IsInsideHeap( GetProcessHeap(), 0, (LPCVOID)handle ))
{
if (HANDLE_TO_INTERN(handle)->Magic == MAGIC_GLOBAL_USED)
return handle; /* valid moveable block */
}
/* maybe FIXED block */
if (HeapValidate( GetProcessHeap(), 0, pmem ))
return (HGLOBAL32)pmem; /* valid fixed block */
error:
SetLastError( ERROR_INVALID_HANDLE );
return 0;
}
/***********************************************************************
* GlobalReAlloc32 (KERNEL32.328)
* RETURNS
* Handle: Success
* NULL: Failure
*/
HGLOBAL32 WINAPI GlobalReAlloc32(
HGLOBAL32 hmem, /* [in] Handle of global memory object */
DWORD size, /* [in] New size of block */
UINT32 flags /* [in] How to reallocate object */
) {
LPVOID palloc;
HGLOBAL32 hnew;
PGLOBAL32_INTERN pintern;
hnew = 0;
/* HeapLock(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
*/
size=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
hnew=GlobalAlloc32( flags, size);
palloc=GlobalLock32(hnew);
memcpy(palloc, (LPVOID) hmem, size);
GlobalUnlock32(hnew);
GlobalFree32(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 */
hnew=(HGLOBAL32)HeapReAlloc(GetProcessHeap(), 0, (LPVOID) hmem, size);
}
else
{
/* reallocate a moveable block */
pintern=HANDLE_TO_INTERN(hmem);
if(pintern->LockCount>1) {
ERR(global,"handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
SetLastError(ERROR_INVALID_HANDLE);
} else if(size!=0)
{
hnew=hmem;
if(pintern->Pointer)
{
palloc=HeapReAlloc(GetProcessHeap(), 0,
pintern->Pointer-sizeof(HGLOBAL32),
size+sizeof(HGLOBAL32) );
pintern->Pointer=palloc+sizeof(HGLOBAL32);
}
else
{
palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
*(HGLOBAL32 *)palloc=hmem;
pintern->Pointer=palloc+sizeof(HGLOBAL32);
}
}
else
{
if(pintern->Pointer)
{
HeapFree(GetProcessHeap(), 0, pintern->Pointer-sizeof(HGLOBAL32));
pintern->Pointer=NULL;
}
}
}
}
/* HeapUnlock(GetProcessHeap()); */
return hnew;
}
/***********************************************************************
* GlobalFree32 (KERNEL32.322)
* RETURNS
* NULL: Success
* Handle: Failure
*/
HGLOBAL32 WINAPI GlobalFree32(
HGLOBAL32 hmem /* [in] Handle of global memory object */
) {
PGLOBAL32_INTERN pintern;
HGLOBAL32 hreturned = 0;
if(ISPOINTER(hmem)) /* POINTER */
{
if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0;
}
else /* HANDLE */
{
/* HeapLock(GetProcessHeap()); */
pintern=HANDLE_TO_INTERN(hmem);
if(pintern->Magic==MAGIC_GLOBAL_USED)
{
if(pintern->LockCount!=0)
SetLastError(ERROR_INVALID_HANDLE);
if(pintern->Pointer)
if(!HeapFree(GetProcessHeap(), 0,
(char *)(pintern->Pointer)-sizeof(HGLOBAL32)))
hreturned=hmem;
if(!HeapFree(GetProcessHeap(), 0, pintern))
hreturned=hmem;
}
/* HeapUnlock(GetProcessHeap()); */
}
return hreturned;
}
/***********************************************************************
* GlobalSize32 (KERNEL32.329)
* RETURNS
* Size in bytes of the global memory object
* 0: Failure
*/
DWORD WINAPI GlobalSize32(
HGLOBAL32 hmem /* [in] Handle of global memory object */
) {
DWORD retval;
PGLOBAL32_INTERN pintern;
if(ISPOINTER(hmem))
{
retval=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
}
else
{
/* HeapLock(GetProcessHeap()); */
pintern=HANDLE_TO_INTERN(hmem);
if(pintern->Magic==MAGIC_GLOBAL_USED)
{
retval=HeapSize(GetProcessHeap(), 0,
(char *)(pintern->Pointer)-sizeof(HGLOBAL32))-4;
}
else
{
WARN(global, "invalid handle\n");
retval=0;
}
/* HeapUnlock(GetProcessHeap()); */
}
return retval;
}
/***********************************************************************
* GlobalWire32 (KERNEL32.333)
*/
LPVOID WINAPI GlobalWire32(HGLOBAL32 hmem)
{
return GlobalLock32( hmem );
}
/***********************************************************************
* GlobalUnWire32 (KERNEL32.330)
*/
BOOL32 WINAPI GlobalUnWire32(HGLOBAL32 hmem)
{
return GlobalUnlock32( hmem);
}
/***********************************************************************
* GlobalFix32 (KERNEL32.320)
*/
VOID WINAPI GlobalFix32(HGLOBAL32 hmem)
{
GlobalLock32( hmem );
}
/***********************************************************************
* GlobalUnfix32 (KERNEL32.331)
*/
VOID WINAPI GlobalUnfix32(HGLOBAL32 hmem)
{
GlobalUnlock32( hmem);
}
/***********************************************************************
* GlobalFlags32 (KERNEL32.321)
* Returns information about the specified global memory object
*
* NOTES
* Should this return GMEM_INVALID_HANDLE on invalid handle?
*
* RETURNS
* Value specifying allocation flags and lock count
* GMEM_INVALID_HANDLE: Failure
*/
UINT32 WINAPI GlobalFlags32(
HGLOBAL32 hmem /* [in] Handle to global memory object */
) {
DWORD retval;
PGLOBAL32_INTERN pintern;
if(ISPOINTER(hmem))
{
retval=0;
}
else
{
/* HeapLock(GetProcessHeap()); */
pintern=HANDLE_TO_INTERN(hmem);
if(pintern->Magic==MAGIC_GLOBAL_USED)
{
retval=pintern->LockCount + (pintern->Flags<<8);
if(pintern->Pointer==0)
retval|= GMEM_DISCARDED;
}
else
{
WARN(global,"Invalid handle: %04x", hmem);
retval=0;
}
/* HeapUnlock(GetProcessHeap()); */
}
return retval;
}
/***********************************************************************
* GlobalCompact32 (KERNEL32.316)
*/
DWORD WINAPI GlobalCompact32( DWORD minfree )
{
return 0; /* GlobalCompact does nothing in Win32 */
}
/***********************************************************************
* GlobalMemoryStatus (KERNEL32.327)
* RETURNS
* None
*/
VOID WINAPI GlobalMemoryStatus(
LPMEMORYSTATUS lpmem
) {
#ifdef linux
FILE *f = fopen( "/proc/meminfo", "r" );
if (f)
{
char buffer[256];
int total, used, free;
lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
while (fgets( buffer, sizeof(buffer), f ))
{
/* old style /proc/meminfo ... */
if (sscanf( buffer, "Mem: %d %d %d", &total, &used, &free ))
{
lpmem->dwTotalPhys += total;
lpmem->dwAvailPhys += free;
}
if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
{
lpmem->dwTotalPageFile += total;
lpmem->dwAvailPageFile += free;
}
/* new style /proc/meminfo ... */
if (sscanf(buffer, "MemTotal: %d", &total))
lpmem->dwTotalPhys = total*1024;
if (sscanf(buffer, "MemFree: %d", &free))
lpmem->dwAvailPhys = free*1024;
if (sscanf(buffer, "SwapTotal: %d", &total))
lpmem->dwTotalPageFile = total*1024;
if (sscanf(buffer, "SwapFree: %d", &free))
lpmem->dwAvailPageFile = free*1024;
}
fclose( f );
if (lpmem->dwTotalPhys)
{
lpmem->dwTotalVirtual = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
lpmem->dwAvailVirtual = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
lpmem->dwMemoryLoad = (lpmem->dwTotalVirtual-lpmem->dwAvailVirtual)
/ (lpmem->dwTotalVirtual / 100);
return;
}
}
#endif
/* FIXME: should do something for other systems */
lpmem->dwMemoryLoad = 0;
lpmem->dwTotalPhys = 16*1024*1024;
lpmem->dwAvailPhys = 16*1024*1024;
lpmem->dwTotalPageFile = 16*1024*1024;
lpmem->dwAvailPageFile = 16*1024*1024;
lpmem->dwTotalVirtual = 32*1024*1024;
lpmem->dwAvailVirtual = 32*1024*1024;
}
/**********************************************************************
* WOWGlobalAllocLock (KERNEL32.62)
*
* Combined GlobalAlloc and GlobalLock.
*/
SEGPTR WINAPI WOWGlobalAllocLock16(DWORD flags,DWORD cb,HGLOBAL16 *hmem)
{
HGLOBAL16 xhmem;
xhmem = GlobalAlloc16(flags,cb);
if (hmem) *hmem = xhmem;
return WIN16_GlobalLock16(xhmem);
}
/**********************************************************************
* WOWGlobalUnlockFree (KERNEL32.64)
*
* Combined GlobalUnlock and GlobalFree.
*/
WORD WOWGlobalUnlockFree16(DWORD vpmem) {
if (!GlobalUnlock16(HIWORD(vpmem)))
return 0;
return GlobalFree16(HIWORD(vpmem));
}