Release 950403

Sun Apr  2 18:31:12 1995  Alexandre Julliard  (julliard@sunsite.unc.edu)

	* [Configure] [if1632/Imakefile]
	Removed new build and short names options.

	* [if1632/*.c] [tools/build.c]
	Implemented compiled call-back functions for better performance;
	all the relay code is now done in assembly code generated by the
	build program.
	Relay code is no longer dependent on being loaded below 64K.

	* [loader/resource.c]
	Fixed memory leak in LoadString(). A fix will also be needed for
	other resources.

	* [memory/global.c]
	Implemented global heap arenas, so we can store informations about
	global blocks, like lock counts or owner handle.
	Implemented FarGetOwner() and FarSetOwner().
	Implemented global heap TOOLHELP functions.

	* [memory/selector.c]
	Bug fix: it was not possible to re-use a free selector.

Sun Apr 2 01:34:52 1995 Constantine Sapuntzakis  (csapuntz@mit.edu)

	*  [controls/listbox.c]
	Major work on listbox code
         - Many bugs fixed (still many bugs)
         - More messages supported
         - Code simplified

Fri Mar 31 03:27:16 EST 1995 William Magro (wmagro@tc.cornell.edu)

	* [controls/edit.c]
	Lots of bug fixes related to diappearing text, lost carets,
	highlighting, segmentation faults, occurance of random
	characters, insertion of characters over selection, misplaced
	caret location, display corruption, end of line behavior, etc.

	* [controls/widgets.c]
	EDIT class doesn't want to use CS_PARENTDC flag.

Thu Mar 30 20:58:25 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
        
	* [loader/selector.c]
	  FixupFunctionPrologs() should also handle multiple data modules.
	  (this bug only became visible because MakeProcInstance() was fixed
	  in 950319)
	
	* [misc/dosfs.c]
	  Simplified DOS_SimplifyPath.
	  Small fix to DOS_opendir to reuse an entry if an open directory
	  is opened again, to prevent "too many open directories" messages.

Thu Mar 30 12:05:05 1995 Martin von Loewis  <loewis@informatik.hu-berlin.de>

	* [if1632/compobj.spec][include/compobj.h][misc/compobj.c]
	CoDisconnectObject: new stub function

	* [include/msdos.h]
	fix DOSVERSION

	* [loader/ne_image.c]
	NE_FixupSegment: Be more generous on additive fixups

	* [if1632/user.spec][misc/network.c]
	Add more WNet* stubs

Wed Mar 29 11:47:22 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>

        * [controls/listbox.c]
	  DlgDirList(): send segptr instead of linear pointer 
	  in message to static control
	* [controls/menu.c]
	  Tried to implement ownerdrawn menuitems. Doesn't work.
	* [if1632/gdi.spec] [include/windows.h] [objects/font.c]
	  Provide a stub for GetRasterizerCaps()
	* [loader/selector.c]
	  Pass end address instead of length to LocalInit() in 
	  CreateSelectors()
	* [memory/local.c]
	  LocalInit(): If there's already a local heap in the segment, do
	  nothing and return TRUE
	* [objects/linedda.c]
	  Replaced buggy LineDDA() with a Bresenham algorithm. Should work
	  now.
	* [windows/cursor.c]
	  LoadCursor()/CreateCursor(): Cleaned up the mess. Needs some
	  more work still.

Tue Mar 21 17:54:43 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>

        * [if1632/relay.c] [if1632/callback.c] [include/dlls.h]
	  [if1632/winprocs.spec] [if1632/winprocs.c] [include/winprocs.h]
	  [controls/widgets.c] [misc/shell.c] [misc/commdlg.c]
	  [windows/nonclient.c] [misc/message.c]
	  Added a new builtin DLL that provides 16 bit entry points for all
	  the Def*Procs (DefDlgProc, ButtonProc etc.). OWL programs work
	  again.
	* [misc/shell.c]
	  RegOpenKey()/RegCreateKey() bugs fixed.
        * [loader/ne_image.c]
	  Skipping the initialization of a DLL when CS == 0 was broken.
diff --git a/memory/global.c b/memory/global.c
index f62f2fd..2067ad0 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -13,20 +13,62 @@
 #include "stddebug.h"
 #include "debug.h"
 
+  /* Global arena block */
+typedef struct
+{
+    DWORD    base;           /* Base address  */
+    DWORD    size;           /* Size in bytes */
+    HGLOBAL  handle;         /* Handle for this block */
+    HGLOBAL  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 */
+} GLOBALARENA;
+
+  /* Flags definitions */
+#define GA_DGROUP       0x04
+#define GA_DISCARDABLE  0x08
+
+  /* Arena array */
+static GLOBALARENA *pGlobalArena = NULL;
+static int globalArenaSize = 0;
+
 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000  /* Largest allocation is 16M - 64K */
 
-#define HGLOBAL_TO_SEL(handle) \
-     ((handle == (HGLOBAL)-1) ? CURRENT_DS : GlobalHandleToSel(handle))
+#define GET_ARENA_PTR(handle)  (pGlobalArena + ((handle) >> __AHSHIFT))
 
 /***********************************************************************
- *           GlobalAlloc   (KERNEL.15)
+ *           GLOBAL_GetArena
+ *
+ * Return the arena for a given selector, growing the arena array if needed.
  */
-HGLOBAL GlobalAlloc( WORD flags, DWORD size )
+static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
 {
-    WORD sel;
-    void *ptr;
+    if (((sel >> __AHSHIFT) + selcount) >= globalArenaSize)
+    {
+        GLOBALARENA *pNewArena = realloc( pGlobalArena,
+                               (globalArenaSize + 256) * sizeof(GLOBALARENA) );
+        if (!pNewArena) return 0;
+        pGlobalArena = pNewArena;
+        memset( pGlobalArena + globalArenaSize, 0, 256 * sizeof(GLOBALARENA) );
+        globalArenaSize += 256;
+    }
+    return pGlobalArena + (sel >> __AHSHIFT);
+}
 
-    dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
+
+/***********************************************************************
+ *           GLOBAL_Alloc
+ *
+ * Implementation of GlobalAlloc()
+ */
+HGLOBAL GLOBAL_Alloc( WORD flags, DWORD size, HGLOBAL hOwner,
+                      BOOL isCode, BOOL isReadOnly )
+{
+    WORD sel, selcount;
+    void *ptr;
+    GLOBALARENA *pArena;
 
       /* Fixup the size */
 
@@ -41,20 +83,50 @@
 
       /* Allocate the selector(s) */
 
-    sel = SELECTOR_AllocBlock( ptr, size, SEGMENT_DATA, 0, 0 );
+    sel = SELECTOR_AllocBlock( ptr, size, isCode ? SEGMENT_CODE : SEGMENT_DATA,
+                               0, isReadOnly );
     if (!sel)
     {
         free( ptr );
         return 0;
     }
+    selcount = (size + 0xffff) / 0x10000;
+
+    if (!(pArena = GLOBAL_GetArena( sel, selcount )))
+    {
+        free( ptr );
+        FreeSelector( sel );
+        return 0;
+    }
+
+      /* Fill the arena block */
+
+    pArena->base = (DWORD)ptr;
+    pArena->size = GET_SEL_LIMIT(sel) + 1;
+    pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
+    pArena->hOwner = hOwner;
+    pArena->lockCount = 0;
+    pArena->pageLockCount = 0;
+    pArena->flags = flags & 0xff;
+    if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
+    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) );
 
     if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
+    return pArena->handle;
+}
 
-      /* Return the handle */
-      /* If allocating a GMEM_FIXED block, the handle is the selector. */
-      /* Otherwise, the handle is the selector-1 (don't ask me why :-) */
-    if (flags & GMEM_MOVEABLE) return sel - 1;
-    else return sel;
+
+/***********************************************************************
+ *           GlobalAlloc   (KERNEL.15)
+ */
+HGLOBAL GlobalAlloc( WORD flags, DWORD size )
+{
+    dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
+
+    return GLOBAL_Alloc( flags, size, GetCurrentPDB(), 0, 0 );
 }
 
 
@@ -63,12 +135,18 @@
  */
 HGLOBAL GlobalReAlloc( HGLOBAL handle, DWORD size, WORD flags )
 {
-    WORD sel;
+    WORD sel, selcount;
     DWORD oldsize;
     void *ptr;
+    GLOBALARENA *pArena, *pNewArena;
 
     dprintf_global( stddeb, "GlobalReAlloc: %04x %ld flags=%04x\n",
                     handle, size, flags );
+    if (!handle)
+    {
+        printf( "GlobalReAlloc: handle is 0.\n" );
+        return 0;
+    }
 
       /* Fixup the size */
 
@@ -78,15 +156,17 @@
 
       /* Reallocate the linear memory */
 
+    pArena = GET_ARENA_PTR( handle );
     sel = GlobalHandleToSel( handle );
-    ptr = (void *)GET_SEL_BASE( sel );
-    oldsize = GlobalSize( handle );
+    ptr = (void *)pArena->base;
+    oldsize = pArena->size;
     if (size == oldsize) return handle;  /* Nothing to do */
 
     ptr = realloc( ptr, size );
     if (!ptr)
     {
         FreeSelector( sel );
+        memset( pArena, 0, sizeof(GLOBALARENA) );
         return 0;
     }
 
@@ -96,17 +176,39 @@
     if (!sel)
     {
         free( ptr );
+        memset( pArena, 0, sizeof(GLOBALARENA) );
+        return 0;
+    }
+    selcount = (size + 0xffff) / 0x10000;
+
+    if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
+    {
+        free( ptr );
+        FreeSelector( sel );
         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;
+    if (flags & GMEM_MODIFY)
+    {
+          /* Change the flags, leaving GA_DGROUP alone */
+        pNewArena->flags = (pNewArena->flags & GA_DGROUP) |
+                           (flags & ~GA_DGROUP);
+        if (flags & GMEM_DISCARDABLE) pNewArena->flags |= GA_DISCARDABLE;
+    }
+    pNewArena->handle = (pNewArena->flags & GMEM_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 );
-
-    if (sel == GlobalHandleToSel( handle ))
-        return handle;  /* Selector didn't change */
-
-    if (flags & GMEM_MOVEABLE) return sel - 1;
-    else return sel;
+    return pNewArena->handle;
 }
 
 
@@ -119,10 +221,12 @@
     void *ptr;
 
     dprintf_global( stddeb, "GlobalFree: %04x\n", handle );
+    if (!handle) return 0;
     sel = GlobalHandleToSel( handle );
     ptr = (void *)GET_SEL_BASE(sel);
     if (FreeSelector( sel )) return handle;  /* failed */
     free( ptr );
+    memset( GET_ARENA_PTR(handle), 0, sizeof(GLOBALARENA) );
     return 0;
 }
 
@@ -136,7 +240,7 @@
 {
     dprintf_global( stddeb, "WIN16_GlobalLock: %04x\n", handle );
     if (!handle) return 0;
-    return (SEGPTR)MAKELONG( 0, HGLOBAL_TO_SEL(handle) );
+    return (SEGPTR)MAKELONG( 0, GlobalHandleToSel(handle) );
 }
 
 
@@ -149,7 +253,7 @@
 {
     dprintf_global( stddeb, "GlobalLock: %04x\n", handle );
     if (!handle) return 0;
-    return (LPSTR)GET_SEL_BASE( HGLOBAL_TO_SEL(handle) );
+    return (LPSTR)GET_ARENA_PTR(handle)->base;
 }
 
 
@@ -170,7 +274,7 @@
 {
     dprintf_global( stddeb, "GlobalSize: %04x\n", handle );
     if (!handle) return 0;
-    return GET_SEL_LIMIT( HGLOBAL_TO_SEL(handle) ) + 1;
+    return GET_ARENA_PTR(handle)->size;
 }
 
 
@@ -179,11 +283,8 @@
  */
 DWORD GlobalHandle( WORD sel )
 {
-      /* FIXME: what about GMEM_FIXED blocks? */
-    WORD handle = sel & ~1;
-    dprintf_global( stddeb, "GlobalHandle(%04x): returning %08lx\n",
-                    sel, MAKELONG( handle, sel ) );
-    return MAKELONG( handle, sel );
+    dprintf_global( stddeb, "GlobalHandle: %04x\n", sel );
+    return MAKELONG( GET_ARENA_PTR(sel)->handle, sel );
 }
 
 
@@ -192,8 +293,12 @@
  */
 WORD GlobalFlags( HGLOBAL handle )
 {
+    GLOBALARENA *pArena;
+
     dprintf_global( stddeb, "GlobalFlags: %04x\n", handle );
-    return 0;  /* lock count is always 0 */
+    pArena = GET_ARENA_PTR(handle);
+    return pArena->lockCount |
+           ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0);
 }
 
 
@@ -204,6 +309,7 @@
 {
     dprintf_global( stddeb, "LockSegment: %04x\n", handle );
     if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
+    GET_ARENA_PTR(handle)->lockCount++;
     return handle;
 }
 
@@ -214,6 +320,8 @@
 void UnlockSegment( HGLOBAL handle )
 {
     dprintf_global( stddeb, "UnlockSegment: %04x\n", handle );
+    if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
+    GET_ARENA_PTR(handle)->lockCount--;
     /* FIXME: this ought to return the lock count in CX (go figure...) */
 }
 
@@ -230,9 +338,9 @@
 /***********************************************************************
  *           GlobalWire   (KERNEL.111)
  */
-LPSTR GlobalWire( HGLOBAL handle )
+SEGPTR GlobalWire( HGLOBAL handle )
 {
-    return GlobalLock( handle );
+    return WIN16_GlobalLock( handle );
 }
 
 
@@ -312,8 +420,7 @@
 WORD GlobalPageLock( HGLOBAL handle )
 {
     dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
-    /* Nothing to do, as we can't page-lock a block (and we don't want to) */
-    return 1;  /* lock count */
+    return ++(GET_ARENA_PTR(handle)->pageLockCount);
 }
 
 
@@ -323,7 +430,7 @@
 WORD GlobalPageUnlock( HGLOBAL handle )
 {
     dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
-    return 0;  /* lock count */
+    return --(GET_ARENA_PTR(handle)->pageLockCount);
 }
 
 
@@ -333,7 +440,7 @@
 void GlobalFix( HGLOBAL handle )
 {
     dprintf_global( stddeb, "GlobalFix: %04x\n", handle );
-    /* Nothing to do, as all the blocks are fixed in linear memory anyway */
+    GET_ARENA_PTR(handle)->lockCount++;
 }
 
 
@@ -343,7 +450,25 @@
 void GlobalUnfix( HGLOBAL handle )
 {
     dprintf_global( stddeb, "GlobalUnfix: %04x\n", handle );
-    /* This one is even more complicated that GlobalFix() :-) */
+    GET_ARENA_PTR(handle)->lockCount--;
+}
+
+
+/***********************************************************************
+ *           FarSetOwner   (KERNEL.403)
+ */
+void FarSetOwner( HANDLE handle, WORD hOwner )
+{
+    GET_ARENA_PTR(handle)->hOwner = hOwner;
+}
+
+
+/***********************************************************************
+ *           FarGetOwner   (KERNEL.404)
+ */
+WORD FarGetOwner( HANDLE handle )
+{
+    return GET_ARENA_PTR(handle)->hOwner;
 }
 
 
@@ -353,21 +478,98 @@
 WORD GlobalHandleToSel( HGLOBAL handle )
 {
     dprintf_toolhelp( stddeb, "GlobalHandleToSel: %04x\n", handle );
+    if (!handle) return 0;
     if (!(handle & 7))
     {
         fprintf( stderr, "Program attempted invalid selector conversion\n" );
         return handle - 1;
     }
-    return handle | 1;
+    return handle | 7;
 }
 
 
-/**********************************************************************
- *                      MemManInfo (toolhelp.72)
+/***********************************************************************
+ *           GlobalFirst   (TOOLHELP.51)
  */
-/*
-BOOL MemManInfo(LPMEMMANINFO lpmmi)
+BOOL GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
 {
-	return 1;
+    if (wFlags == GLOBAL_LRU) return FALSE;
+    pGlobal->dwNext = 0;
+    return GlobalNext( pGlobal, wFlags );
 }
-*/
+
+
+/***********************************************************************
+ *           GlobalNext   (TOOLHELP.52)
+ */
+BOOL GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
+{
+    GLOBALARENA *pArena;
+
+    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)
+ */
+BOOL 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)
+ */
+BOOL GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL hItem )
+{
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *           GlobalEntryModule   (TOOLHELP.55)
+ */
+BOOL GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE hModule, WORD wSeg )
+{
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *           MemManInfo   (TOOLHELP.72)
+ */
+BOOL MemManInfo( MEMMANINFO *pInfo )
+{
+    return TRUE;
+}