Release 980927

Sun Sep 27 14:25:38 1998  Petter Reinholdtsen <pere@td.org.uit.no>

	* [files/drive.c]
	Make sure GetDriveType32A() handles param NULL.  Added some
	doc on function.

Sun Sep 27 14:07:26 1998  Huw D M Davies <daviesh@abacus.physics.ox.ac.uk>

	* [controls/edit.c] [windows/win.c]
	Don't call SetWindowLong() in EDIT_WM_NCREATE.
	Fix SetWindowLong(GWL_[EX]STYLE) to work for 16bit windows. Remove
	UpdateWindow() call. 

Sun Sep 27 13:41:22 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [scheduler/*.c] [server/event.c] [server/mutex.c]
	  [server/semaphore.c]
	Implemented server-side synchronisation objects.

Sun Sep 27 01:13:35 1998  Alex Priem <alexp@sci.kun.nl>

	* [dlls/comctl32/treeview.c] [include/treeview.h] [include/comctl.h]
	Treeview implementation.

	* [dlls/comctl32/trackbar.c] [include/trackbar.h] 
	Trackbar implementation.

Sat Sep 26 20:49:13 1998  Ulrich Weigand <weigand@informatik.uni-erlangen.de>

	* [if1632/thunk.c] [tools/build.c] [win32/kernel32.c]
	Bugfix: several problems with flat thunks fixed.

	* [memory/selector.c]
	Bugfix: IsBad...Ptr16 didn't work for limit_in_pages segments.

	* [scheduler/thread.c]
	Bugfix: CreateThread: Allow id parameter == NULL.

	* [objects/gdiobj.c]
	Bugfix: IsGDIObject: Return correct object type for stock objects.

	* [msdos/dpmi.c]
	Bugfix: fixed typo in INT_DoRealModeInt.

	* [msdos/int21.c]
	Bugfix: int21 READ *must* use WIN16_hread, not _hread16.

	* [if1632/kernel.spec] [if1632/dummy.c] [if1632/thunk.c]
	  [loader/ne/module.c] [scheduler/event.c] [scheduler/synchro.c]
	  [scheduler/thread.c] [win32/kernel32.c] [win32/ordinals.c]
	Added names/stubs for all undocumented KERNEL routines (Win95).
	Added the following undoc. 16-bit equivalents to Win32 routines:
	KERNEL.441-443,449-453,456-462,471-476,479-486,488.
	Added stubs for some other KERNEL routines.

	* [memory/heap.c] [memory/global.c] [include/global.h]
	Implemented Local32... 32-bit local heap routines (KERNEL.208-215, 229).

	* [miscemu/instr.c] [loader/module.c] [include/module.h]
	Implemented __GP fault handling and HasGPHandler (KERNEL.338).

	* [misc/error.c]
	Implemented LogParamErrorRegs (KERNEL.327).

	* [loader/task.c] [include/windows.h]
	Implemented GetCodeInfo (KERNEL.104).

	* [loader/task.c] [scheduler/thread.c] [include/thread.h]
	Implemented [GS]etThreadQueue and [GS]etFastQueue (KERNEL.463/4, 624/5).

	* [if1632/gdi.spec] [objects/dc.c] [objects/dib.c]
	  [objects/bitmap.c] [include/windows.h]
	Bugfix: fixed wrong parameter for CreateDIBSection16.
	Added [GS]etDIBColorTable16, stub for GetBoundsRect16.
	Partially implemented BITMAP_GetObject16 for DIBs.

	* [if1632/gdi.spec] [relay32/gdi32.spec] [objects/palette.c]
	Added some GDI stubs.

	* [if1632/Makefile.in] [if1632/display.spec] [if1632/mouse.spec]
	  [if1632/keyboard.spec] [if1632/builtin.c] [windows/keyboard.c]
	Added some stubs for Win16 drivers: KEYBOARD, MOUSE, DISPLAY.

	* [if1632/wprocs.spec] [msdos/vxd.c]
	Added some stubs for VxDs: VMM, ConfigMG, TimerAPI.

	* [msdos/int2f.c]
	Added some stubs for real-mode network drivers.

Sat Sep 26 18:18:18 1998  Marcus Meissner <marcus@jet.franken.de>

	* [configure.in]
	Merged in some more of the FreeBSD ports/emulators/wine patches. 
	(Maintainer(s) of this port: You can just submit these
	patches to Alexandre directly.)

	 * [loader/pe_image.c]
	Check filesize of image against size derived from header
	to spot truncated executeables without crashing.

	* [files/directory.c]
	Set envvar "COMSPEC". One win32(!!) program crashes without it.

	* [multimedia/mmio.c]
	Added mmioSetInfo32.

	* [include/file.h]
	Return STD_ERROR_HANDLE for AUX and PRT dos handles.

	* [loader/module.c]
	Handle executeables with spaces in their names a bit better in
	CreateProcess.

	* [relay32/msvfw32.spec][if1632/msvideo.spec][multimedia/msvideo.c][include/vfw.h]
	Started on MS Video support (can load Win32 ICMs).

	* [tools/testrun]
	A bit smarter use of ps.

	* [memory/virtual.c]
	Report PAGE_GUARDed pages as PAGE_PROTECTED (AutoCAD LT R17 fails
	without that check (since Win95 doesn't know about PAGE_GUARD)).

Sat Sep 26 15:04:05 1998  Ove Kaaven <ovek@arcticnet.no>

	* [include/miscemu.h] [if1632/builtin.c] [loader/task.c]
	  [miscemu/instr.c] [msdos/dpmi.c] [msdos/int21.c]
	  [msdos/interrupts.c] [windows/user.c]
	INT_[S|G]etHandler was renamed to INT_[S|G]etPMHandler.
	Added handlers to deal with real-mode interrupts; DOS
	programs are now able to hook real-mode interrupts.

	* [loader/dos/module.c] [msdos/dosmem.c] [msdos/int21.c]
	Moved real-mode interrupt table initialization to
	msdos/dosmem.c, and made new V86 tasks get a full copy
	of the existing "system memory" instead of almost empty
	space. Misc fixes.

	* [include/dosexe.h] [loader/dos/module.c] [msdos/dpmi.c]
	  [msdos/int2f.c]
	First shot at letting DOS programs start up DPMI (but DPMI
	is still disabled for DOS programs, for pkunzip's sake).

	* [include/debugger.h] [debugger/break.c] [debugger/dbg.y]
	  [debugger/registers.c] [debugger/memory.c] [debugger/info.c]
	  [loader/dos/dosvm.c]
	First shot at making Wine's debugger work for DOS programs.
	The -debug flag works, as do "nexti" and "stepi".

Sat Sep 26 13:13:13 1998  Juergen Schmied <juergen.schmied@metronet.de>

	* [dlls/shell32/dataobject.c]
	New classes IEnumFORMATETC implemented, IDataObject stubs.
	
	* [dlls/shell32/*.*][relay32/shell32.spec]
	Bugfixes.
	New: ICM_InsertItem(), ILCreateFromPath().
	Implemented: ILCloneFirst().
	Stubs: ILIsEqual(), ILFindChild(), SHLogILFromFSIL(),
	  PathMatchSpec(), PathIsExe().
	Changed: ILGetSize(), _ILIsDesktop(), PathCombine().

	* [include/shlobj.h]
	New SHLGUID's
	New structures: DVTARGETDEVICE32, STGMEDIUM32, FORMATETC32,
	CLIPFORMAT32.
	New interfaces: IEnumFORMATETC, IDataObject, ICommDlgBrowser
	IDockingWindowFrame, IServiceProvider.

	* [dlls/shell32/folders.c]
	Stubs for IShellLink.

	* [loader/resource.c]
	Small fixes.

	* [misc/crtdll.c][relay32/crtdll.spec]
	New __dllonexit().

	* [windows/message.c]
	SendNotifyMessageA, SendMessageCallBack32A half implemented.

	* [controls/edit.c]
	EDIT_WM_SetText set EF_UPDATE flag not for ES_MULTILINE.

	* [files/file.c]
	Handling of fileposition fixed.

Fri Sep 25 18:13:30 1998  Patrik Stridvall <ps@leissner.se>

	* [include/windows.h] [include/wintypes.h]
	  [ole/ole2nls.h] [relay32/kernel32.spec]
	Implemented EnumDateFormats and EnumTimeFormats.
	Only adds US English support.

	* [Makefile.in] [configure.in] 
	  [dlls/Makefile.in] [dlls/psapi/Makefile.in] 
	  [dlls/psapi/psapi_main.c] 
	New files to implement stubs for PSAPI.DLL (NT only).

	* [relay32/Makefile.in] [relay32/builtin32.c] 
	  [relay32/psapi.spec]
	New spec file for PSAPI.DLL (NT only).

	* [scheduler/handle.c]
	HANDLE_GetObjPtr should only interpret the pseudo handles as the
	current thread or the current process if a thread or a process is
	requested.

	* [include/winversion.h] [misc/version.c]
	Adds the global function VERSION_GetVersion() so functions can
	have different behavior depending on the -winver flag.

	* [include/oledlg.h] [ole/oledlg.c]
	Minor fixes. 

	* [windows/winproc.c]
	Minor changes.

	* [include/imm.h] [misc/imm.c]
	Now returns correct values under both Windows 95 and NT 4.0.

Thu Sep 24 22:11:44 1998  Kristian Nielsen  <kristian.nielsen@risoe.dk>

	* [configure.in] [include/acconfig.h] [include/thread.h]
	  [scheduler/sysdeps.c]
	Autoconfig test for non-reentrant libc.

Wed Sep 23 19:52:12 1998  Matthew Becker <mbecker@glasscity.net>

	* [*/*.c]
	Miscellaneous documentation updates and debugging output 
	standardizations.

	* [objects/clipping.c]
	Added ExtSelectClipRgn.

Wed Sep 23 00:03:28 EDT 1998  Pete Ratzlaff <pratzlaff@cfa.harvard.edu>

	* [include/windows.h] [if1632/user.spec] [relay32/user32.spec]
	  [windows/keyboard.c]
	Added, marginally implemented, GetKeyboardLayoutName().
	Only returns US English keyboard name.

Tue Sep 22 16:32:41 1998  Marcel Baur <mbaur@iiic.ethz.ch>

	* [programs/control/*]
	New Winelib application.

Mon Sep 21 00:29:18 1998  Peter Hunnisett <hunnise@nortel.ca>

	* [include/dplay.h][multimedia/dplay.c][ole/compobj.c]
	Added all DirectPlayLobby interfaces and enhanced DirectPlay
	and DirectPlayLobby support. Still not all that much. Useful
	enough if you just need to start a program, don't try any
	real dplay/lobby stuff.

	* [documentation/status/directplay]
	Added a very little bit.

	* [graphics/ddraw.c]
	- Call to SetWindowLong32A wasn't working because there was no
	  memory set aside when the window class was registered.
	- Fixed some xlib reference counting and change the behaviour
	  of DirectDrawSurface3_SetPalette to mimic observed behaviour
	  (palette is associated will all backbuffers)
	- Also stored all palette colour fields and spit back our saved
	  colour fields rather than query X for them.
	- Added plenty of AddRef and Release traces.
	- Added Xlib support for using -desktop option.
	- Fixed Xlib message handling. Messages weren't being passed to
	  the application. Fixes mouse movements in some xlib DDraw games.
	- Added a few stubs.

	* [windows/win.c][include/winerror.h]
	Fixed up some error handling in WIN_SetWindowLong. SetLastError
	wasn't being used. Could cause problems with 0 return codes.
	Added new error in winerror (1400).

	* [AUTHORS] [include/authors.h]
	Added myself as a Wine author.

Sun Sep 20 21:22:44 1998  Alexander Larsson  <alla@lysator.liu.se>

	* [loader/module.c]
	Changed GetModuleFileName32A so that is returns the
	long version of the filename. Note that just the name
	is long, not the directories.

Sat Sep 19 20:05:30 1998 Per Ångström <pang@mind.nu> 

	* [controls/menu.c]
	Made a couple of fixes to make life easier for applications that alter
	their menus at runtime.

	* [windows/defdlg.c]
	Removed the cast of the return value from dialog procedures to a 16-bit
	bool. The return value needs to retain all its 32 bits, since it is not 
	always a bool, such as when responding to the WM_NCHITTEST message.

Fri Sep 18 11:30:38 1998  Sergey Turchanov <turchanov@usa.net>

	* [loader/resource.c]
	Fixed very funny bug (though gravely affecting further excecution)
	with FindResource[Ex]32 functions.

	* [include/multimon.h] [windows/multimon.c] [relay32/user32.spec]
	  [include/windows.h] [windows/sysmetrics.c]
	Default implementation for Multimonitor API.

	* [include/windows.h] [windows/winpos.c]
	Fixed incorrect declaration (and behaviour) of GetWindowRect32.

Wed Sep 16 10:21:15 1998  Gerard Patel <G.Patel@Wanadoo.fr>

	* [controls/edit.c]
	Fixed EDIT_EM_GetLine to use correctly length of lines.

Tue Sep 15 20:40:16 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [misc/tweak.c][include/tweak.h][controls/menu.c]
	Replaced the tweak graphic routines by calls to DrawEdge32().

	* [misc/tweak.c][include/tweak.h][documentation/win95look]
	  [wine.ini][*/*]
	Changed "look and feel" selection. Allows Win3.1, Win95 and
	Win98 (no GUI code implemented) look and feel.

	* [dlls/comctl32/header.c][include/header.h][include/commctrl.h]
	Started callback item support and did some minor improvements.

	* [dlls/comctl32/imagelist.c]
	Fixed bug in transparent image display.
	ImageList_GetIcon is still buggy :-(

	* [dlls/comctl32/toolbar.c]
	Fixed button drawing (partial hack).

	* [dlls/comctl32/commctrl.c]
	Fixed MenuHelp().

	* [controls/button.c]
	Added 3d effect for groupbox.

	* [windows/msgbox.c]
	Added font support for message boxes.

	* [windows/nonclient.c]
	Fixed window moving bug.

	* [dlls/comctl32/*.c]
	Various improvements.

	* [dlls/comctl32/listview.c][dlls/comctl32/rebar.c]
	  [include/commctrl.h]
	More messages.

	* [windows/syscolor.c][include/windows.h]
	Introduced new Win98 system colors.

Tue Sep 15 18:29:45 1998 Wesley Filardo <eightknots@aol.com>

	* [files/profile.c]
	Added support in PROFILE_LoadWineIni for -config option

	* [misc/main.c] [include/options.h]
	Added -config option.

Tue Sep 15 18:22:26 1998  Petter Reinholdtsen <pere@td.org.uit.no>

	* [documentation/Makefile.in]
	Make sure directory exists before installing into it.

Tue Sep 15 01:47:33 1998  Pablo Saratxaga <pablo.sarachaga@ping.be>

	* [ole/nls/*] [ole/ole2nls.c] [include/winnls.h]
	Fixed a few errors and completed some NLS files.

Mon Sep 14 01:23:45 1998  Joseph Pranevich <knight@baltimore.wwaves.com>

	* [include/miscemu.h] [msdos/interrupts.c]
	Removed a compilation warning, added INT 25 to the list of interrupts
	callable from DOS applications, added a debug message when unsupported
	interrupts are used.

Sun Sep 13 19:55:22 1998  Lawson Whitney <lawson_whitney@juno.com>

	* [if1632/relay.c]
	CallProcEx32W should not reverse arguments.

Sun Aug 17 21:18:12 1998  Eric Pouech  <eric.pouech@lemel.fr>

	* [multimedia/midi.c] [multimedia/init.c] [multimedia/mmsys.c] 
	  [include/multimedia.h] [include/mmsystem.h] 
	  [multimedia/Makefile.in] [multimedia/midipatch.c]
	  [if1632/multimedia.spec]
	Made MIDI input and output functional on OSS capable systems.

	* [multimedia/timer.c]
	Changes to trigger callbacks at the accurate pace even when
	fake timers are used.
diff --git a/memory/global.c b/memory/global.c
index fd8bb5b..799eb9f 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -3,6 +3,7 @@
  *
  * Copyright 1995 Alexandre Julliard
  */
+/* 0xffff sometimes seems to mean: CURRENT_DS */
 
 #include <sys/types.h>
 #include <stdlib.h>
@@ -173,6 +174,30 @@
     return TRUE;
 }
 
+/***********************************************************************
+ *           GLOBAL_MoveBlock
+ */
+BOOL16 GLOBAL_MoveBlock( HGLOBAL16 handle, const void *ptr, DWORD size )
+{
+    WORD sel;
+    GLOBALARENA *pArena;
+
+    if (!handle) return TRUE;
+    sel = GlobalHandleToSel( handle ); 
+    if (!VALID_HANDLE(sel))
+    	return FALSE;
+    pArena = GET_ARENA_PTR(sel);
+    if (pArena->selCount != 1)
+        return FALSE;
+
+    pArena->base = (DWORD)ptr;
+    pArena->size = size;
+
+    SELECTOR_MoveBlock( sel, ptr );
+    SetSelectorLimit( sel, size-1 );
+
+    return TRUE;
+}
 
 /***********************************************************************
  *           GLOBAL_Alloc
diff --git a/memory/heap.c b/memory/heap.c
index 3bcc396..05dc8fa 100644
--- a/memory/heap.c
+++ b/memory/heap.c
@@ -2,6 +2,7 @@
  * Win32 heap functions
  *
  * Copyright 1996 Alexandre Julliard
+ * Copyright 1998 Ulrich Weigand
  */
 
 #include <assert.h>
@@ -9,6 +10,7 @@
 #include <string.h>
 #include "windows.h"
 #include "selectors.h"
+#include "global.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "winnt.h"
@@ -426,17 +428,104 @@
     }
 }
 
+/***********************************************************************
+ *           HEAP_InitSubHeap
+ */
+static BOOL32 HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
+                                DWORD commitSize, DWORD totalSize )
+{
+    SUBHEAP *subheap = (SUBHEAP *)address;
+    WORD selector = 0;
+    FREE_LIST_ENTRY *pEntry;
+    int i;
+
+    /* Commit memory */
+
+    if (!VirtualAlloc(address, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
+    {
+        WARN(heap, "Could not commit %08lx bytes for sub-heap %08lx\n",
+                   commitSize, (DWORD)address );
+        return FALSE;
+    }
+
+    /* Allocate a selector if needed */
+
+    if (flags & HEAP_WINE_SEGPTR)
+    {
+        selector = SELECTOR_AllocBlock( address, totalSize,
+                     (flags & HEAP_WINE_CODESEG) ? SEGMENT_CODE : SEGMENT_DATA,
+                     (flags & HEAP_WINE_CODESEG) != 0, FALSE );
+        if (!selector)
+        {
+            WARN(heap, "Could not allocate selector\n" );
+            return FALSE;
+        }
+    }
+
+    /* Fill the sub-heap structure */
+
+    subheap->heap       = heap;
+    subheap->selector   = selector;
+    subheap->size       = totalSize;
+    subheap->commitSize = commitSize;
+    subheap->magic      = SUBHEAP_MAGIC;
+
+    if ( subheap != (SUBHEAP *)heap )
+    {
+        /* If this is a secondary subheap, insert it into list */
+
+        subheap->headerSize = sizeof(SUBHEAP);
+        subheap->next       = heap->subheap.next;
+        heap->subheap.next  = subheap;
+    }
+    else
+    {
+        /* If this is a primary subheap, initialize main heap */
+
+        subheap->headerSize = sizeof(HEAP);
+        subheap->next       = NULL;
+        heap->next          = NULL;
+        heap->flags         = flags;
+        heap->magic         = HEAP_MAGIC;
+
+        /* Build the free lists */
+
+        for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
+        {
+            pEntry->size           = HEAP_freeListSizes[i];
+            pEntry->arena.size     = 0 | ARENA_FLAG_FREE;
+            pEntry->arena.next     = i < HEAP_NB_FREE_LISTS-1 ?
+                         &heap->freeList[i+1].arena : &heap->freeList[0].arena;
+            pEntry->arena.prev     = i ? &heap->freeList[i-1].arena : 
+                                   &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
+            pEntry->arena.threadId = 0;
+            pEntry->arena.magic    = ARENA_FREE_MAGIC;
+        }
+
+        /* Initialize critical section */
+
+        InitializeCriticalSection( &heap->critSection );
+        if (!SystemHeap) HEAP_SystemLock = &heap->critSection;
+    }
+ 
+    /* Create the first free block */
+
+    HEAP_CreateFreeBlock( subheap, (LPBYTE)subheap + subheap->headerSize, 
+                          subheap->size - subheap->headerSize );
+
+    return TRUE;
+}
 
 /***********************************************************************
  *           HEAP_CreateSubHeap
  *
  * Create a sub-heap of the given size.
+ * If heap == NULL, creates a main heap.
  */
-static SUBHEAP *HEAP_CreateSubHeap( DWORD flags, DWORD commitSize,
-                                    DWORD totalSize )
+static SUBHEAP *HEAP_CreateSubHeap( HEAP *heap, DWORD flags, 
+                                    DWORD commitSize, DWORD totalSize )
 {
-    SUBHEAP *subheap;
-    WORD selector = 0;
+    LPVOID address;
 
     /* Round-up sizes on a 64K boundary */
 
@@ -454,46 +543,24 @@
 
     /* Allocate the memory block */
 
-    if (!(subheap = VirtualAlloc( NULL, totalSize,
+    if (!(address = VirtualAlloc( NULL, totalSize,
                                   MEM_RESERVE, PAGE_EXECUTE_READWRITE )))
     {
         WARN(heap, "Could not VirtualAlloc %08lx bytes\n",
                  totalSize );
         return NULL;
     }
-    if (!VirtualAlloc(subheap, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
+
+    /* Initialize subheap */
+
+    if (!HEAP_InitSubHeap( heap? heap : (HEAP *)address, 
+                           address, flags, commitSize, totalSize ))
     {
-        WARN(heap, "Could not commit %08lx bytes for sub-heap %08lx\n",
-                 commitSize, (DWORD)subheap );
-        VirtualFree( subheap, 0, MEM_RELEASE );
+        VirtualFree( address, 0, MEM_RELEASE );
         return NULL;
     }
 
-    /* Allocate a selector if needed */
-
-    if (flags & HEAP_WINE_SEGPTR)
-    {
-        selector = SELECTOR_AllocBlock( subheap, totalSize,
-                     (flags & HEAP_WINE_CODESEG) ? SEGMENT_CODE : SEGMENT_DATA,
-                     (flags & HEAP_WINE_CODESEG) != 0, FALSE );
-        if (!selector)
-        {
-            WARN(heap, "Could not allocate selector\n" );
-            VirtualFree( subheap, 0, MEM_RELEASE );
-            return NULL;
-        }
-    }
-
-    /* Fill the sub-heap structure */
-
-    subheap->size       = totalSize;
-    subheap->commitSize = commitSize;
-    subheap->headerSize = sizeof(*subheap);
-    subheap->next       = NULL;
-    subheap->heap       = NULL;
-    subheap->magic      = SUBHEAP_MAGIC;
-    subheap->selector   = selector;
-    return subheap;
+    return (SUBHEAP *)address;
 }
 
 
@@ -538,20 +605,13 @@
         return NULL;
     }
     size += sizeof(SUBHEAP) + sizeof(ARENA_FREE);
-    if (!(subheap = HEAP_CreateSubHeap( heap->flags, size,
+    if (!(subheap = HEAP_CreateSubHeap( heap, heap->flags, size,
                                         MAX( HEAP_DEF_SIZE, size ) )))
         return NULL;
 
-    /* Insert the new sub-heap in the list */
-
-    subheap->heap = heap;
-    subheap->next = heap->subheap.next;
-    heap->subheap.next = subheap;
-    size = subheap->size;
     TRACE(heap, "created new sub-heap %08lx of %08lx bytes for heap %08lx\n",
-                  (DWORD)subheap, size, (DWORD)heap );
+                (DWORD)subheap, size, (DWORD)heap );
 
-    HEAP_CreateFreeBlock( subheap, subheap + 1, size - sizeof(*subheap) );
     *ppSubHeap = subheap;
     return (ARENA_FREE *)(subheap + 1);
 }
@@ -809,10 +869,7 @@
                 DWORD initialSize, /* [in] Initial heap size */
                 DWORD maxSize      /* [in] Maximum heap size */
 ) {
-    int i;
-    HEAP *heap;
     SUBHEAP *subheap;
-    FREE_LIST_ENTRY *pEntry;
 
     /* Allocate the heap block */
 
@@ -821,50 +878,15 @@
         maxSize = HEAP_DEF_SIZE;
         flags |= HEAP_GROWABLE;
     }
-    if (!(subheap = HEAP_CreateSubHeap( flags, initialSize, maxSize )))
+    if (!(subheap = HEAP_CreateSubHeap( NULL, flags, initialSize, maxSize )))
     {
         SetLastError( ERROR_OUTOFMEMORY );
         return 0;
     }
 
-    /* Fill the heap structure */
-
-    heap = (HEAP *)subheap;
-    subheap->heap       = heap;
-    subheap->headerSize = sizeof(HEAP);
-    heap->next          = NULL;
-    heap->flags         = flags;
-    heap->magic         = HEAP_MAGIC;
-
-    /* Build the free lists */
-
-    for (i = 0, pEntry = heap->freeList; i < HEAP_NB_FREE_LISTS; i++, pEntry++)
-    {
-        pEntry->size           = HEAP_freeListSizes[i];
-        pEntry->arena.size     = 0 | ARENA_FLAG_FREE;
-        pEntry->arena.next     = i < HEAP_NB_FREE_LISTS-1 ?
-                         &heap->freeList[i+1].arena : &heap->freeList[0].arena;
-        pEntry->arena.prev     = i ? &heap->freeList[i-1].arena : 
-                                   &heap->freeList[HEAP_NB_FREE_LISTS-1].arena;
-        pEntry->arena.threadId = 0;
-        pEntry->arena.magic    = ARENA_FREE_MAGIC;
-    }
-
-    /* Create the first free block */
-
-    HEAP_CreateFreeBlock( subheap, heap + 1, subheap->size - sizeof(*heap) );
-
-    /* Initialize critical section */
-
-    InitializeCriticalSection( &heap->critSection );
-    if (!SystemHeap) HEAP_SystemLock = &heap->critSection;
-
-    /* We are done */
-
-    return (HANDLE32)heap;
+    return (HANDLE32)subheap;
 }
 
-
 /***********************************************************************
  *           HeapDestroy   (KERNEL32.337)
  * RETURNS
@@ -1354,3 +1376,453 @@
     lstrcpyWtoA( ret, str );
     return ret;
 }
+
+
+
+/***********************************************************************
+ * 32-bit local heap functions (Win95; undocumented)
+ */
+
+#define HTABLE_SIZE      0x10000
+#define HTABLE_PAGESIZE  0x1000
+#define HTABLE_NPAGES    (HTABLE_SIZE / HTABLE_PAGESIZE)
+
+#pragma pack(1)
+typedef struct _LOCAL32HEADER
+{
+    WORD     freeListFirst[HTABLE_NPAGES];
+    WORD     freeListSize[HTABLE_NPAGES];
+    WORD     freeListLast[HTABLE_NPAGES];
+
+    DWORD    selectorTableOffset;
+    WORD     selectorTableSize;
+    WORD     selectorDelta;
+
+    DWORD    segment;
+    LPBYTE   base;
+
+    DWORD    limit;
+    DWORD    flags;
+
+    DWORD    magic;
+    HANDLE32 heap;
+
+} LOCAL32HEADER;
+#pragma pack(4)
+
+#define LOCAL32_MAGIC    ((DWORD)('L' | ('H'<<8) | ('3'<<16) | ('2'<<24)))
+
+/***********************************************************************
+ *           Local32Init   (KERNEL.208)
+ */
+HANDLE32 WINAPI Local32Init( WORD segment, DWORD tableSize,
+                             DWORD heapSize, DWORD flags )
+{
+    DWORD totSize, segSize = 0;
+    LPBYTE base;
+    LOCAL32HEADER *header;
+    HEAP *heap;
+    WORD *selectorTable;
+    WORD selectorEven, selectorOdd;
+    int i, nrBlocks;
+
+    /* Determine new heap size */
+
+    if ( segment )
+        if ( (segSize = GetSelectorLimit( segment )) == 0 )
+            return 0;
+        else
+            segSize++;
+
+    if ( heapSize == -1L )
+        heapSize = 1024L*1024L;   /* FIXME */
+
+    heapSize = (heapSize + 0xffff) & 0xffff0000;
+    segSize  = (segSize  + 0x0fff) & 0xfffff000;
+    totSize  = segSize + HTABLE_SIZE + heapSize;
+
+
+    /* Allocate memory and initialize heap */
+
+    if ( !(base = VirtualAlloc( NULL, totSize, MEM_RESERVE, PAGE_READWRITE )) )
+        return 0;
+
+    if ( !VirtualAlloc( base, segSize + HTABLE_PAGESIZE, 
+                        MEM_COMMIT, PAGE_READWRITE ) )
+    {
+        VirtualFree( base, 0, MEM_RELEASE );
+        return 0;
+    }
+
+    heap = (HEAP *)(base + segSize + HTABLE_SIZE);
+    if ( !HEAP_InitSubHeap( heap, (LPVOID)heap, 0, 0x10000, heapSize ) )
+    {
+        VirtualFree( base, 0, MEM_RELEASE );
+        return 0;
+    }
+
+
+    /* Set up header and handle table */
+    
+    header = (LOCAL32HEADER *)(base + segSize);
+    header->base    = base;
+    header->limit   = HTABLE_PAGESIZE-1;
+    header->flags   = 0;
+    header->magic   = LOCAL32_MAGIC;
+    header->heap    = (HANDLE32)heap;
+
+    header->freeListFirst[0] = sizeof(LOCAL32HEADER);
+    header->freeListLast[0]  = HTABLE_PAGESIZE - 4;
+    header->freeListSize[0]  = (HTABLE_PAGESIZE - sizeof(LOCAL32HEADER)) / 4;
+
+    for (i = header->freeListFirst[0]; i < header->freeListLast[0]; i += 4)
+        *(DWORD *)((LPBYTE)header + i) = i+4;
+
+    header->freeListFirst[1] = 0xffff;
+
+
+    /* Set up selector table */
+  
+    nrBlocks      = (totSize + 0x7fff) >> 15; 
+    selectorTable = (LPWORD) HeapAlloc( header->heap,  0, nrBlocks * 2 );
+    selectorEven  = SELECTOR_AllocBlock( base, totSize, 
+                                         SEGMENT_DATA, FALSE, FALSE );
+    selectorOdd   = SELECTOR_AllocBlock( base + 0x8000, totSize - 0x8000, 
+                                         SEGMENT_DATA, FALSE, FALSE );
+    
+    if ( !selectorTable || !selectorEven || !selectorOdd )
+    {
+        if ( selectorTable ) HeapFree( header->heap, 0, selectorTable );
+        if ( selectorEven  ) SELECTOR_FreeBlock( selectorEven, totSize >> 16 );
+        if ( selectorOdd   ) SELECTOR_FreeBlock( selectorOdd, (totSize-0x8000) >> 16 );
+        HeapDestroy( header->heap );
+        VirtualFree( base, 0, MEM_RELEASE );
+        return 0;
+    }
+
+    header->selectorTableOffset = (LPBYTE)selectorTable - header->base;
+    header->selectorTableSize   = nrBlocks * 4;  /* ??? Win95 does it this way! */
+    header->selectorDelta       = selectorEven - selectorOdd;
+    header->segment             = segment? segment : selectorEven;
+
+    for (i = 0; i < nrBlocks; i++)
+        selectorTable[i] = (i & 1)? selectorOdd  + ((i >> 1) << __AHSHIFT)
+                                  : selectorEven + ((i >> 1) << __AHSHIFT);
+
+    /* Move old segment */
+
+    if ( segment )
+    {
+        /* FIXME: This is somewhat ugly and relies on implementation
+                  details about 16-bit global memory handles ... */
+
+        LPBYTE oldBase = (LPBYTE)GetSelectorBase( segment );
+        memcpy( base, oldBase, segSize );
+        GLOBAL_MoveBlock( segment, base, totSize );
+        HeapFree( SystemHeap, 0, oldBase );
+    }
+    
+    return (HANDLE32)header;
+}
+
+/***********************************************************************
+ *           Local32_SearchHandle
+ */
+static LPDWORD Local32_SearchHandle( LOCAL32HEADER *header, DWORD addr )
+{
+    LPDWORD handle;
+
+    for ( handle = (LPDWORD)((LPBYTE)header + sizeof(LOCAL32HEADER));
+          handle < (LPDWORD)((LPBYTE)header + header->limit);
+          handle++)
+    {
+        if (*handle == addr)
+            return handle;
+    }
+
+    return NULL;
+}
+
+/***********************************************************************
+ *           Local32_ToHandle
+ */
+static VOID Local32_ToHandle( LOCAL32HEADER *header, INT16 type, 
+                              DWORD addr, LPDWORD *handle, LPBYTE *ptr )
+{
+    *handle = NULL;
+    *ptr    = NULL;
+
+    switch (type)
+    {
+        case -2:    /* 16:16 pointer, no handles */
+            *ptr    = PTR_SEG_TO_LIN( addr );
+            *handle = (LPDWORD)*ptr;
+            break;
+
+        case -1:    /* 32-bit offset, no handles */
+            *ptr    = header->base + addr;
+            *handle = (LPDWORD)*ptr;
+            break;
+
+        case 0:     /* handle */
+            if (    addr >= sizeof(LOCAL32HEADER) 
+                 && addr <  header->limit && !(addr & 3) 
+                 && *(LPDWORD)((LPBYTE)header + addr) >= HTABLE_SIZE )
+            {
+                *handle = (LPDWORD)((LPBYTE)header + addr);
+                *ptr    = header->base + **handle;
+            }
+            break;
+
+        case 1:     /* 16:16 pointer */
+            *ptr    = PTR_SEG_TO_LIN( addr );
+            *handle = Local32_SearchHandle( header, *ptr - header->base );
+            break;
+
+        case 2:     /* 32-bit offset */
+            *ptr    = header->base + addr;
+            *handle = Local32_SearchHandle( header, *ptr - header->base );
+            break;
+    }
+}
+
+/***********************************************************************
+ *           Local32_FromHandle
+ */
+static VOID Local32_FromHandle( LOCAL32HEADER *header, INT16 type, 
+                                DWORD *addr, LPDWORD handle, LPBYTE ptr )
+{
+    switch (type)
+    {
+        case -2:    /* 16:16 pointer */
+        case  1:
+        {
+            WORD *selTable = (LPWORD)(header->base + header->selectorTableOffset);
+            DWORD offset   = (LPBYTE)ptr - header->base;
+            *addr = MAKELONG( offset & 0x7fff, selTable[offset >> 15] ); 
+        }
+        break;
+
+        case -1:    /* 32-bit offset */
+        case  2:
+            *addr = ptr - header->base;
+            break;
+
+        case  0:    /* handle */
+            *addr = (LPBYTE)handle - (LPBYTE)header;
+            break;
+    }
+}
+
+/***********************************************************************
+ *           Local32Alloc   (KERNEL.209)
+ */
+DWORD WINAPI Local32Alloc( HANDLE32 heap, DWORD size, INT16 type, DWORD flags )
+{
+    LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
+    LPDWORD handle;
+    LPBYTE ptr;
+    DWORD addr;
+
+    /* Allocate memory */
+    ptr = HeapAlloc( header->heap, 
+                     (flags & LMEM_MOVEABLE)? HEAP_ZERO_MEMORY : 0, size );
+    if (!ptr) return 0;
+
+
+    /* Allocate handle if requested */
+    if (type >= 0)
+    {
+        int page, i;
+
+        /* Find first page of handle table with free slots */
+        for (page = 0; page < HTABLE_NPAGES; page++)
+            if (header->freeListFirst[page] != 0)
+                break;
+        if (page == HTABLE_NPAGES)
+        {
+            WARN( heap, "Out of handles!\n" );
+            HeapFree( header->heap, 0, ptr );
+            return 0;
+        }
+
+        /* If virgin page, initialize it */
+        if (header->freeListFirst[page] == 0xffff)
+        {
+            if ( !VirtualAlloc( (LPBYTE)header + (page << 12), 
+                                0x1000, MEM_COMMIT, PAGE_READWRITE ) )
+            {
+                WARN( heap, "Cannot grow handle table!\n" );
+                HeapFree( header->heap, 0, ptr );
+                return 0;
+            }
+            
+            header->limit += HTABLE_PAGESIZE;
+
+            header->freeListFirst[page] = 0;
+            header->freeListLast[page]  = HTABLE_PAGESIZE - 4;
+            header->freeListSize[page]  = HTABLE_PAGESIZE / 4;
+           
+            for (i = 0; i < HTABLE_PAGESIZE; i += 4)
+                *(DWORD *)((LPBYTE)header + i) = i+4;
+
+            if (page < 31) 
+                header->freeListFirst[page+1] = 0xffff;
+        }
+
+        /* Allocate handle slot from page */
+        handle = (LPDWORD)((LPBYTE)header + header->freeListFirst[page]);
+        if (--header->freeListSize[page] == 0)
+            header->freeListFirst[page] = header->freeListLast[page] = 0;
+        else
+            header->freeListFirst[page] = *handle;
+
+        /* Store 32-bit offset in handle slot */
+        *handle = ptr - header->base;
+    }
+    else
+    {
+        handle = (LPDWORD)ptr;
+        header->flags |= 1;
+    }
+
+
+    /* Convert handle to requested output type */
+    Local32_FromHandle( header, type, &addr, handle, ptr );
+    return addr;
+}
+
+/***********************************************************************
+ *           Local32ReAlloc   (KERNEL.210)
+ */
+DWORD WINAPI Local32ReAlloc( HANDLE32 heap, DWORD addr, INT16 type,
+                             DWORD size, DWORD flags )
+{
+    LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
+    LPDWORD handle;
+    LPBYTE ptr;
+
+    if (!addr)
+        return Local32Alloc( heap, size, type, flags );
+
+    /* Retrieve handle and pointer */
+    Local32_ToHandle( header, type, addr, &handle, &ptr );
+    if (!handle) return FALSE;
+
+    /* Reallocate memory block */
+    ptr = HeapReAlloc( header->heap, 
+                       (flags & LMEM_MOVEABLE)? HEAP_ZERO_MEMORY : 0, 
+                       ptr, size );
+    if (!ptr) return 0;
+
+    /* Modify handle */
+    if (type >= 0)
+        *handle = ptr - header->base;
+    else
+        handle = (LPDWORD)ptr;
+
+    /* Convert handle to requested output type */
+    Local32_FromHandle( header, type, &addr, handle, ptr );
+    return addr;
+}
+
+/***********************************************************************
+ *           Local32Free   (KERNEL.211)
+ */
+BOOL32 WINAPI Local32Free( HANDLE32 heap, DWORD addr, INT16 type )
+{
+    LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
+    LPDWORD handle;
+    LPBYTE ptr;
+
+    /* Retrieve handle and pointer */
+    Local32_ToHandle( header, type, addr, &handle, &ptr );
+    if (!handle) return FALSE;
+
+    /* Free handle if necessary */
+    if (type >= 0)
+    {
+        int offset = (LPBYTE)handle - (LPBYTE)header;
+        int page   = offset >> 12;
+
+        /* Return handle slot to page free list */
+        if (header->freeListSize[page]++ == 0)
+            header->freeListFirst[page] = header->freeListLast[page]  = offset;
+        else
+            *(LPDWORD)((LPBYTE)header + header->freeListLast[page]) = offset,
+            header->freeListLast[page] = *handle;
+
+        *handle = 0;
+
+        /* Shrink handle table when possible */
+        while (page > 0 && header->freeListSize[page] == HTABLE_PAGESIZE / 4)
+        {
+            if ( VirtualFree( (LPBYTE)header + 
+                              (header->limit & ~(HTABLE_PAGESIZE-1)),
+                              HTABLE_PAGESIZE, MEM_DECOMMIT ) )
+                break;
+
+            header->limit -= HTABLE_PAGESIZE;
+            header->freeListFirst[page] = -1;
+            page--;
+        }
+    }
+
+    /* Free memory */
+    return HeapFree( header->heap, 0, ptr );
+}
+
+/***********************************************************************
+ *           Local32Translate   (KERNEL.213)
+ */
+DWORD WINAPI Local32Translate( HANDLE32 heap, DWORD addr, INT16 type1, INT16 type2 )
+{
+    LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
+    LPDWORD handle;
+    LPBYTE ptr;
+
+    Local32_ToHandle( header, type1, addr, &handle, &ptr );
+    if (!handle) return 0;
+
+    Local32_FromHandle( header, type2, &addr, handle, ptr );
+    return addr;
+}
+
+/***********************************************************************
+ *           Local32Size   (KERNEL.214)
+ */
+DWORD WINAPI Local32Size( HANDLE32 heap, DWORD addr, INT16 type )
+{
+    LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
+    LPDWORD handle;
+    LPBYTE ptr;
+
+    Local32_ToHandle( header, type, addr, &handle, &ptr );
+    if (!handle) return 0;
+
+    return HeapSize( header->heap, 0, ptr );
+}
+
+/***********************************************************************
+ *           Local32ValidHandle   (KERNEL.215)
+ */
+BOOL32 WINAPI Local32ValidHandle( HANDLE32 heap, WORD addr )
+{
+    LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
+    LPDWORD handle;
+    LPBYTE ptr;
+
+    Local32_ToHandle( header, 0, addr, &handle, &ptr );
+    return handle != NULL;
+}
+
+/***********************************************************************
+ *           Local32GetSegment   (KERNEL.229)
+ */
+WORD WINAPI Local32GetSegment( HANDLE32 heap )
+{
+    LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
+    return header->segment;
+}
+
+
diff --git a/memory/local.c b/memory/local.c
index 5e4192c..9d8fe87 100644
--- a/memory/local.c
+++ b/memory/local.c
@@ -345,7 +345,8 @@
 	if ((pModule = NE_GetPtr( selector )))
 	{
 	    SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
-	    if (pModule->dgroup && (pSeg->selector == selector)) {
+	    if (pModule->dgroup && (GlobalHandleToSel(pSeg->hSeg) == selector))
+	    {
 		/* We can't just use the simple method of using the value
                  * of minsize + stacksize, since there are programs that
                  * resize the data segment before calling InitTask(). So,
@@ -1602,7 +1603,8 @@
     WORD ds;
 
     if (!(pModule = NE_GetPtr( module ))) return 0;
-    ds = (NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->selector;
+    ds =
+    GlobalHandleToSel((NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->hSeg);
     return MAKELONG( LOCAL_CountFree( ds ), LOCAL_HeapSize( ds ) );
 }
 
diff --git a/memory/selector.c b/memory/selector.c
index 859cc6a..16bddc6 100644
--- a/memory/selector.c
+++ b/memory/selector.c
@@ -406,7 +406,7 @@
     if (IS_SELECTOR_FREE(sel)) return TRUE;
     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
     if (entry.type != SEGMENT_CODE) return TRUE;
-    if (OFFSETOF(lpfn) > entry.limit) return TRUE;
+    if (OFFSETOF(lpfn) > GET_SEL_LIMIT(sel)) return TRUE;
     return FALSE;
 }
 
@@ -425,7 +425,7 @@
     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
     if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
     if (strlen(PTR_SEG_TO_LIN(ptr)) < size) size = strlen(PTR_SEG_TO_LIN(ptr));
-    if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
+    if (OFFSETOF(ptr) + size - 1 > GET_SEL_LIMIT(sel)) return TRUE;
     return FALSE;
 }
 
@@ -443,7 +443,7 @@
     if (IS_SELECTOR_FREE(sel)) return TRUE;
     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
     if ((entry.type == SEGMENT_CODE) && entry.read_only) return TRUE;
-    if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
+    if (OFFSETOF(ptr) + size - 1 > GET_SEL_LIMIT(sel)) return TRUE;
     return FALSE;
 }
 
@@ -461,7 +461,7 @@
     if (IS_SELECTOR_FREE(sel)) return TRUE;
     LDT_GetEntry( SELECTOR_TO_ENTRY(sel), &entry );
     if ((entry.type == SEGMENT_CODE) || entry.read_only) return TRUE;
-    if (OFFSETOF(ptr) + size - 1 > entry.limit) return TRUE;
+    if (OFFSETOF(ptr) + size - 1 > GET_SEL_LIMIT(sel)) return TRUE;
     return FALSE;
 }
 
diff --git a/memory/virtual.c b/memory/virtual.c
index 3b4e94f..58aa32a 100644
--- a/memory/virtual.c
+++ b/memory/virtual.c
@@ -6,6 +6,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <sys/errno.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -310,8 +311,10 @@
 ) {
     if (protect) {
     	*protect = VIRTUAL_Win32Flags[vprot & 0x0f];
-    	if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;
+/*    	if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/
     	if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
+
+    	if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS;
     }
 
     if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;