Release 980118

Sun Jan 18 17:05:58 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [include/stackframe.h] [tools/build.c]
	Some cleanups in stack frame building.

	* [misc/port.c]
	Implemented clone() wrapper for libc5 users.

	* [scheduler/mutex.c] [scheduler/synchro.c]
	Implemented abandoned mutexes.

	* [scheduler/process.c] [scheduler/thread.c]
	We now create a process and a thread structure as soon as possible
	during initialization.

	* [scheduler/thread.c] [scheduler/sysdeps.c]
	Moved system-specific thread handling to sysdeps.c.

Fri Jan 16 10:45:15 1998  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [graphics/ddraw.c][include/ddraw.h]
	Surface handling enhanced. Some stuff already works ;)

	* [multimedia/dsound.c][include/dsound.h]
	Implemented using the Open Sound System.
	Slowly starts to work (sounds terrible for some programs).

	* [configure.in][multimedia/audio.c][include/config.h.in]
	Added check for OpenSoundSystem, fixed -lXxf86dga check.
	Replaced OS #ifdefs by #ifdef HAVE_OSS in mm/audio.c.

	* [if1632/relay.c][relay32/relay386.c]
	Do not print control characters for 'str' or 'wstr' args.

	* [misc/registry.c]
	"" seems to equals NULL in keynames. Replace where needed. Seems
	to help the win95 regedit.exe...

	* [win32/newfns.c]
	Implemented QueryPerformance* using gettimeofday(2)
	(should be done using the pentium timers probably).

	* [tools/ipcl]
	Removed useless open_pipe construct.

Sun Jan 11 17:10:02 1998  Huw D M Davies <h.davies1@physics.oxford.ac.uk>

	* [objects/region.c] [include/region.h] [graphics/x11drv/clipping.c]
	Regions are now internal to Wine. The basis of this code is taken
	from the X11 distribution. GetRegionData() is implemented as is 
	ExtCreateRegion() (without Xforms). CreatePolyPolygonRgn() should
	behave correctly now. 

	* [objects/metafile.c] [graphics/metafiledrv/graphics.c]
	  [graphics/metafiledrv/init.c] [include/metafile.h]
	  [include/metafiledrv.h]
	Playback of META_CREATEREGION should now work. Implemented recording
	of META_CREATEREGION and META_PAINTREGION.

	* [graphics/x11drv/graphics.c]
	FillRgn() (and therefore its friends) respect logical co-ords.

Wed Jan  7 01:21:45 1998  Steinar Hamre  <steinarh@stud.fim.ntnu.no>

	* [configure.in] [include/acconfig.h] [tools/build.c]
	Now checking whether to use .string or .ascii.

	* [configure.in] [include/acconfig.h] [scheduler/critsection.c]
	Defining union semun if this is not available from header files.

	* [misc/lstr.c]
	Moved wine's own header files below <wctype.h> to avoid
	parse error on Solaris.

Sun Jan  4 15:38:07 1998  Andrew Taylor <ataylor@cadvision.com>

	* [multimedia/mmsystem.c] [multimedia/mmio.c]
	Implemented mmioSendMessage and rearranged the mmio
	subsystem in terms of this function.

Wed Dec 24 00:51:29 1997  Charles Duffy <cduffy@bigfoot.com>

	* [windows/clipboard.c] [relay32/user32.spec]
	GetPriorityClipboardFormat32 now has something other than just
	a stub. I have no idea if it works (can't test until
	SetClipboardData is finished) but HEdit likes things a lot more
	this way.
diff --git a/ANNOUNCE b/ANNOUNCE
index aba47d4..e7555fe 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,13 +1,13 @@
-This is release 980104 of Wine, the MS Windows emulator.  This is still a
+This is release 980118 of Wine, the MS Windows emulator.  This is still a
 developer's only release.  There are many bugs and many unimplemented API
 features.  Most applications still do not work correctly.
 
 Patches should be submitted to "julliard@lrc.epfl.ch".  Please don't
 forget to include a ChangeLog entry.
 
-WHAT'S NEW with Wine-980104: (see ChangeLog for details)
-	- Beginnings of DirectDraw/DirectSound support.
-	- Preliminary threading support based on clone().
+WHAT'S NEW with Wine-980118: (see ChangeLog for details)
+	- New region implementation based on X11 code.
+	- Improvements to DirectDraw and DirectSound.
 	- Lots of bug fixes.
 
 See the README file in the distribution for installation instructions.
@@ -16,10 +16,10 @@
 the release is available at the ftp sites.  The sources will be available
 from the following locations:
 
-  ftp://sunsite.unc.edu/pub/Linux/ALPHA/wine/development/Wine-980104.tar.gz
-  ftp://tsx-11.mit.edu/pub/linux/ALPHA/Wine/development/Wine-980104.tar.gz
-  ftp://ftp.infomagic.com/pub/mirrors/linux/wine/development/Wine-980104.tar.gz
-  ftp://ftp.progsoc.uts.edu.au/pub/Wine/development/Wine-980104.tar.gz
+  ftp://sunsite.unc.edu/pub/Linux/ALPHA/wine/development/Wine-980118.tar.gz
+  ftp://tsx-11.mit.edu/pub/linux/ALPHA/Wine/development/Wine-980118.tar.gz
+  ftp://ftp.infomagic.com/pub/mirrors/linux/wine/development/Wine-980118.tar.gz
+  ftp://ftp.progsoc.uts.edu.au/pub/Wine/development/Wine-980118.tar.gz
 
 It should also be available from any site that mirrors tsx-11 or sunsite.
 
diff --git a/ChangeLog b/ChangeLog
index 57e6fb2..65a51a7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,93 @@
 ----------------------------------------------------------------------
+Sun Jan 18 17:05:58 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>
+
+	* [include/stackframe.h] [tools/build.c]
+	Some cleanups in stack frame building.
+
+	* [misc/port.c]
+	Implemented clone() wrapper for libc5 users.
+
+	* [scheduler/mutex.c] [scheduler/synchro.c]
+	Implemented abandoned mutexes.
+
+	* [scheduler/process.c] [scheduler/thread.c]
+	We now create a process and a thread structure as soon as possible
+	during initialization.
+
+	* [scheduler/thread.c] [scheduler/sysdeps.c]
+	Moved system-specific thread handling to sysdeps.c.
+
+Fri Jan 16 10:45:15 1998  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
+
+	* [graphics/ddraw.c][include/ddraw.h]
+	Surface handling enhanced. Some stuff already works ;)
+
+	* [multimedia/dsound.c][include/dsound.h]
+	Implemented using the Open Sound System.
+	Slowly starts to work (sounds terrible for some programs).
+
+	* [configure.in][multimedia/audio.c][include/config.h.in]
+	Added check for OpenSoundSystem, fixed -lXxf86dga check.
+	Replaced OS #ifdefs by #ifdef HAVE_OSS in mm/audio.c.
+
+	* [if1632/relay.c][relay32/relay386.c]
+	Do not print control characters for 'str' or 'wstr' args.
+
+	* [misc/registry.c]
+	"" seems to equals NULL in keynames. Replace where needed. Seems
+	to help the win95 regedit.exe...
+
+	* [win32/newfns.c]
+	Implemented QueryPerformance* using gettimeofday(2)
+	(should be done using the pentium timers probably).
+
+	* [tools/ipcl]
+	Removed useless open_pipe construct.
+
+Sun Jan 11 17:10:02 1998  Huw D M Davies <h.davies1@physics.oxford.ac.uk>
+
+	* [objects/region.c] [include/region.h] [graphics/x11drv/clipping.c]
+	Regions are now internal to Wine. The basis of this code is taken
+	from the X11 distribution. GetRegionData() is implemented as is 
+	ExtCreateRegion() (without Xforms). CreatePolyPolygonRgn() should
+	behave correctly now. 
+
+	* [objects/metafile.c] [graphics/metafiledrv/graphics.c]
+	  [graphics/metafiledrv/init.c] [include/metafile.h]
+	  [include/metafiledrv.h]
+	Playback of META_CREATEREGION should now work. Implemented recording
+	of META_CREATEREGION and META_PAINTREGION.
+
+	* [graphics/x11drv/graphics.c]
+	FillRgn() (and therefore its friends) respect logical co-ords.
+
+Wed Jan  7 01:21:45 1998  Steinar Hamre  <steinarh@stud.fim.ntnu.no>
+
+	* [configure.in] [include/acconfig.h] [tools/build.c]
+	Now checking whether to use .string or .ascii.
+
+	* [configure.in] [include/acconfig.h] [scheduler/critsection.c]
+	Defining union semun if this is not available from header files.
+
+	* [misc/lstr.c]
+	Moved wine's own header files below <wctype.h> to avoid
+	parse error on Solaris.
+
+Sun Jan  4 15:38:07 1998  Andrew Taylor <ataylor@cadvision.com>
+
+	* [multimedia/mmsystem.c] [multimedia/mmio.c]
+	Implemented mmioSendMessage and rearranged the mmio
+	subsystem in terms of this function.
+
+Wed Dec 24 00:51:29 1997  Charles Duffy <cduffy@bigfoot.com>
+
+	* [windows/clipboard.c] [relay32/user32.spec]
+	GetPriorityClipboardFormat32 now has something other than just
+	a stub. I have no idea if it works (can't test until
+	SetClipboardData is finished) but HEdit likes things a lot more
+	this way.
+
+----------------------------------------------------------------------
 Sat Jan  3 17:15:56 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>
 
 	* [debugger/db_disasm.c]
@@ -149,6 +238,13 @@
 	* [files/drive.c]
 	Return correct "CDFS" fsname so Diablo is a bit happier.
 
+Sun Dec 21 21:45:48 1997  Kevin Cozens <kcozens@interlog.com>
+
+	* [misc/registry.c]
+	Fixed bugs in the routines which read the Windows '95 registry
+	files. Added extra information regarding the format of the Windows
+	'95 registry files.
+
 ----------------------------------------------------------------------
 Fri Dec 19 10:50:46 1997  Douglas Ridgway  <ridgway@winehq.com>
 
@@ -1232,7 +1328,7 @@
  	Add error checks for SYSCOLOR_SetColor, SYSCOLOR_Init,
 	GetSysColor16, GetSysColor32.  Add support for above colors.
 
-Sun Aug 24 16:22:57 1997  Andrew Taylor <andrew@riscan.com>
+Sun Aug 24 16:22:57 1997  Andrew Taylor <ataylor@cadvision.com>
 
 	* [multimedia/mmsystem.c]
 	Changed mmioDescend to use mmio functions for file I/O, neccessary
@@ -1731,7 +1827,7 @@
 	* [windows/mdi.c] [windows/win.c]
 	Replaced WCL lists with WIN_BuildWinArray().
 
-Mon Jun  9 23:51:16 1997  Andrew Taylor <andrew@riscan.com>
+Mon Jun  9 23:51:16 1997  Andrew Taylor <ataylor@cadvision.com>
 
 	* [misc/error.c] [include/windows.h] [if1632/kernel.spec]
 	Implemented LogParamError, LogError functions.
@@ -1973,7 +2069,7 @@
 	Another ximage!=bitmap memory layout bug. 
 	All _XinitImageFuncPtrs except one removed.
 
-Sun Apr 20 17:12:30 1997  Andrew Taylor <andrew@riscan.com>
+Sun Apr 20 17:12:30 1997  Andrew Taylor <ataylor@cadvision.com>
 
 	* [multimedia/audio.c]
 	Fixed some regression bugs.
@@ -2309,7 +2405,7 @@
 	* [controls/edit.c]
 	Fix incorrect arg order in LOCAL_Alloc() call.
 
-Fri Feb 21 18:19:17 1997  Andrew Taylor  <andrew@riscan.com>
+Fri Feb 21 18:19:17 1997  Andrew Taylor  <ataylor@cadvision.com>
 
 	* [multimedia/mmsystem.c] [multimedia/mcistring.c]
 	Fixed bug related to device IDs returned by multimedia
@@ -2351,7 +2447,7 @@
 	* [msdos/dosmem.c] [memory/global.c]
 	Some changes in DOS memory allocation.
 
-Fri Feb  7 21:46:03 1997  Andrew Taylor  <andrew@riscan.com>
+Fri Feb  7 21:46:03 1997  Andrew Taylor  <ataylor@cadvision.com>
 
 	* [win32/security.c]
 	Added SID manipulation functions.
@@ -3020,7 +3116,7 @@
 	* [windows/win.c]
 	SetWindowWord(): call SetParent on GWW_HWNDPARENT.
 
-Wed Dec  4 22:03:05 1996  Andrew Taylor <andrew@riscan.com>
+Wed Dec  4 22:03:05 1996  Andrew Taylor <ataylor@cadvision.com>
 
 	* [files/dos_fs.c]
 	Check if buf is NULL before copying string in GetFullPathName32A().
@@ -6870,7 +6966,7 @@
 	* [controls/edit.c]
 	Almost rewrote EDIT_GetLineMsg.
 
-Sat Dec 16 13:51:48 MST 1995  Andrew Taylor <andrew@riscan.com>
+Sat Dec 16 13:51:48 MST 1995  Andrew Taylor <ataylor@cadvision.com>
 
 	* [windows/mdi.c]
 	Fixed MDITile() bug that occurs when 0 windows are present or all
@@ -7883,7 +7979,7 @@
 	* [loader/ne_image.c]
 	Preliminary support for iterated segments.
 
-Sat Aug 19 00:43:04 1995  Andrew Taylor  (andrew@riscan.com)
+Sat Aug 19 00:43:04 1995  Andrew Taylor  (ataylor@cadvision.com)
 
 	* [windows/mapping.c]
 	In function MAPPING_FixIsotropic(), VportExt[XY] is multiplied by
diff --git a/Make.rules.in b/Make.rules.in
index 5cc35b7..0006fce 100644
--- a/Make.rules.in
+++ b/Make.rules.in
@@ -18,7 +18,7 @@
 CC        = @CC@
 CPP       = @CPP@
 CFLAGS    = @CFLAGS@
-OPTIONS   = @OPTIONS@
+OPTIONS   = @OPTIONS@ -D_REENTRANT
 X_CFLAGS  = @X_CFLAGS@
 X_LIBS    = @X_LIBS@
 XPM_LIB   = -lXpm
diff --git a/configure b/configure
index 20417c6..84d8791 100755
--- a/configure
+++ b/configure
@@ -1990,7 +1990,7 @@
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_save_LIBS="$LIBS"
-LIBS="-lXxf86dga -lXext -lX11 $LIBS"
+LIBS="-lXxf86dga $X_LIBS -lXext -lX11 $LIBS"
 cat > conftest.$ac_ext <<EOF
 #line 1996 "configure"
 #include "confdefs.h"
@@ -2018,19 +2018,91 @@
 fi
 if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
   echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo Xxf86dga | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
+  cat >> confdefs.h <<\EOF
+#define HAVE_LIBXXF86DGA 1
 EOF
-
-  LIBS="-lXxf86dga $LIBS"
-
+ X_PRE_LIBS="$X_PRE_LIBS -lXxf86dga"
 else
   echo "$ac_t""no" 1>&6
 fi
 
 
+
+echo $ac_n "checking "for Open Sound System"""... $ac_c" 1>&6
+echo "configure:2033: checking "for Open Sound System"" >&5
+if eval "test \"`echo '$''{'ac_cv_c_opensoundsystem'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2038 "configure"
+#include "confdefs.h"
+#include <sys/soundcard.h>
+int main() {
+
+/* check for open sound system and one of the SNDCTL_ defines to be sure */
+#if !defined(OPEN_SOUND_SYSTEM) || !defined(SNDCTL_DSP_STEREO)
+#error No open sound system
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2050: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_opensoundsystem="yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_opensoundsystem="no"
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_opensoundsystem" 1>&6
+
+if test "$ac_cv_c_opensoundsystem" = "yes"
+then
+    cat >> confdefs.h <<\EOF
+#define HAVE_OSS 1
+EOF
+
+fi
+
+
+echo $ac_n "checking "for union semun"""... $ac_c" 1>&6
+echo "configure:2074: checking "for union semun"" >&5
+if eval "test \"`echo '$''{'ac_cv_c_union_semun'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2079 "configure"
+#include "confdefs.h"
+#include <sys/sem.h>
+int main() {
+union semun foo
+; return 0; }
+EOF
+if { (eval echo configure:2086: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_union_semun="yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_union_semun="no"
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_union_semun" 1>&6
+if test "$ac_cv_c_union_semun" = "yes"
+then
+    cat >> confdefs.h <<\EOF
+#define HAVE_UNION_SEMUN 1
+EOF
+
+fi
+
 if test "$ac_cv_prog_LN_S" = "ln -s"; then : ; else LN_S=cp ; fi
 
 
@@ -2038,7 +2110,7 @@
 then
   CFLAGS="$CFLAGS -Wall"
   echo $ac_n "checking "for gcc strength-reduce bug"""... $ac_c" 1>&6
-echo "configure:2042: checking "for gcc strength-reduce bug"" >&5
+echo "configure:2114: checking "for gcc strength-reduce bug"" >&5
 if eval "test \"`echo '$''{'ac_cv_c_gcc_strength_bug'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2046,7 +2118,7 @@
   ac_cv_c_gcc_strength_bug="yes"
 else
   cat > conftest.$ac_ext <<EOF
-#line 2050 "configure"
+#line 2122 "configure"
 #include "confdefs.h"
 
 int main(void) {
@@ -2057,7 +2129,7 @@
   exit( Array[1] != -2 );
 }
 EOF
-if { (eval echo configure:2061: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2133: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_gcc_strength_bug="no"
 else
@@ -2080,7 +2152,7 @@
 
 
 echo $ac_n "checking "whether external symbols need an underscore prefix"""... $ac_c" 1>&6
-echo "configure:2084: checking "whether external symbols need an underscore prefix"" >&5
+echo "configure:2156: checking "whether external symbols need an underscore prefix"" >&5
 if eval "test \"`echo '$''{'ac_cv_c_extern_prefix'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2092,14 +2164,14 @@
 	.long 0
 EOF
 cat > conftest.$ac_ext <<EOF
-#line 2096 "configure"
+#line 2168 "configure"
 #include "confdefs.h"
 extern int ac_test;
 int main() {
 if (ac_test) return 1
 ; return 0; }
 EOF
-if { (eval echo configure:2103: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2175: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   ac_cv_c_extern_prefix="yes"
 else
@@ -2122,25 +2194,66 @@
 fi
 
 
+echo $ac_n "checking "whether assembler accepts .string"""... $ac_c" 1>&6
+echo "configure:2199: checking "whether assembler accepts .string"" >&5
+if eval "test \"`echo '$''{'ac_cv_c_asm_string'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  saved_libs=$LIBS
+LIBS="conftest_asm.s $LIBS"
+cat > conftest_asm.s <<EOF
+	.string "test"
+EOF
+cat > conftest.$ac_ext <<EOF
+#line 2209 "configure"
+#include "confdefs.h"
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:2216: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ac_cv_c_asm_string="yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_asm_string="no"
+fi
+rm -f conftest*
+LIBS=$saved_libs
+fi
+
+echo "$ac_t""$ac_cv_c_asm_string" 1>&6
+if test "$ac_cv_c_asm_string" = "yes"
+then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ASM_STRING 1
+EOF
+
+fi
+
+
 DLLFLAGS=""
 if test "$LIB_TARGET" = "libwine.so.1.0"
 then
   echo $ac_n "checking "whether we can build a dll"""... $ac_c" 1>&6
-echo "configure:2130: checking "whether we can build a dll"" >&5
+echo "configure:2243: checking "whether we can build a dll"" >&5
 if eval "test \"`echo '$''{'ac_cv_c_dll'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   saved_cflags=$CFLAGS
   CFLAGS="$CFLAGS -fPIC -shared -Wl,-soname,conftest.so.1.0"
   cat > conftest.$ac_ext <<EOF
-#line 2137 "configure"
+#line 2250 "configure"
 #include "confdefs.h"
 
 int main() {
 return 1
 ; return 0; }
 EOF
-if { (eval echo configure:2144: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2257: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   ac_cv_c_dll="yes"
 else
@@ -2168,12 +2281,12 @@
 for ac_func in clone memmove strerror tcgetattr usleep wait4 waitpid
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2172: checking for $ac_func" >&5
+echo "configure:2285: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2177 "configure"
+#line 2290 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2196,7 +2309,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2200: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -2224,17 +2337,17 @@
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:2228: checking for $ac_hdr" >&5
+echo "configure:2341: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2233 "configure"
+#line 2346 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2238: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2351: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -2261,12 +2374,12 @@
 done
 
 echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6
-echo "configure:2265: checking whether stat file-mode macros are broken" >&5
+echo "configure:2378: checking whether stat file-mode macros are broken" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2270 "configure"
+#line 2383 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -2317,12 +2430,12 @@
 fi
 
 echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:2321: checking for working const" >&5
+echo "configure:2434: checking for working const" >&5
 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2326 "configure"
+#line 2439 "configure"
 #include "confdefs.h"
 
 int main() {
@@ -2371,7 +2484,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:2375: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2488: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_const=yes
 else
@@ -2392,12 +2505,12 @@
 fi
 
 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:2396: checking for ANSI C header files" >&5
+echo "configure:2509: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2401 "configure"
+#line 2514 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -2405,7 +2518,7 @@
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2409: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2522: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -2422,7 +2535,7 @@
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 2426 "configure"
+#line 2539 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -2440,7 +2553,7 @@
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 2444 "configure"
+#line 2557 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -2461,7 +2574,7 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 2465 "configure"
+#line 2578 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -2472,7 +2585,7 @@
 exit (0); }
 
 EOF
-if { (eval echo configure:2476: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2589: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -2496,12 +2609,12 @@
 fi
 
 echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:2500: checking for size_t" >&5
+echo "configure:2613: checking for size_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2505 "configure"
+#line 2618 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
diff --git a/configure.in b/configure.in
index abf9119..83da896 100644
--- a/configure.in
+++ b/configure.in
@@ -51,7 +51,33 @@
 dnl Check for -lw for Solaris
 AC_CHECK_LIB(w,iswalnum)
 dnl Check for XFree86 DGA extension
-AC_CHECK_LIB(Xxf86dga,XF86DGAQueryExtension,,,-lXext -lX11)
+AC_CHECK_LIB(Xxf86dga,XF86DGAQueryExtension,AC_DEFINE(HAVE_LIBXXF86DGA) X_PRE_LIBS="$X_PRE_LIBS -lXxf86dga",,$X_LIBS -lXext -lX11)
+
+dnl **** Check for Open Sound System ****
+
+AC_CACHE_CHECK("for Open Sound System",
+	ac_cv_c_opensoundsystem,
+	AC_TRY_COMPILE([#include <sys/soundcard.h>],[
+/* check for open sound system and one of the SNDCTL_ defines to be sure */
+#if !defined(OPEN_SOUND_SYSTEM) || !defined(SNDCTL_DSP_STEREO)
+#error No open sound system
+#endif
+],ac_cv_c_opensoundsystem="yes",ac_cv_c_opensoundsystem="no"))
+
+if test "$ac_cv_c_opensoundsystem" = "yes"
+then
+    AC_DEFINE(HAVE_OSS)
+fi
+
+dnl **** Check for union semun ****
+
+AC_CACHE_CHECK("for union semun", ac_cv_c_union_semun,
+ AC_TRY_COMPILE([#include <sys/sem.h>],[union semun foo],
+                ac_cv_c_union_semun="yes", ac_cv_c_union_semun="no"))
+if test "$ac_cv_c_union_semun" = "yes"
+then
+    AC_DEFINE(HAVE_UNION_SEMUN)
+fi
 
 dnl **** If ln -s doesn't work, use cp instead ****
 if test "$ac_cv_prog_LN_S" = "ln -s"; then : ; else LN_S=cp ; fi
@@ -98,6 +124,22 @@
   AC_DEFINE(NEED_UNDERSCORE_PREFIX)
 fi
 
+dnl **** Check for .string in assembler ****
+
+AC_CACHE_CHECK("whether assembler accepts .string",
+               ac_cv_c_asm_string,
+[saved_libs=$LIBS
+LIBS="conftest_asm.s $LIBS"
+cat > conftest_asm.s <<EOF
+	.string "test"
+EOF
+AC_TRY_LINK(,,ac_cv_c_asm_string="yes",ac_cv_c_asm_string="no")
+LIBS=$saved_libs])
+if test "$ac_cv_c_asm_string" = "yes"
+then
+  AC_DEFINE(HAVE_ASM_STRING)
+fi
+
 dnl **** Check for working dll ****
 
 DLLFLAGS=""
diff --git a/controls/menu.c b/controls/menu.c
index ee5a098..e70533d 100644
--- a/controls/menu.c
+++ b/controls/menu.c
@@ -1837,7 +1837,7 @@
 	{
 	    if( menu->wFlags & MF_SYSMENU )
 	    {
-		PostMessage16( pmt->hOwnerWnd, WM_SYSCOMMAND, item->hSubMenu,
+		PostMessage16( pmt->hOwnerWnd, WM_SYSCOMMAND, item->wID,
 			       MAKELPARAM((INT16)pmt->pt.x, (INT16)pmt->pt.y) );
 	    }
 	    else
diff --git a/debugger/break.c b/debugger/break.c
index d842f50..b332ade 100644
--- a/debugger/break.c
+++ b/debugger/break.c
@@ -347,9 +347,7 @@
 
         if (pModule->flags & NE_FFLAGS_WIN32)  /* PE module */
         {
-            PE_MODREF *pem;
-            if (!pCurrentProcess) continue;
-            pem = pCurrentProcess->modref_list;
+            PE_MODREF *pem = PROCESS_Current()->modref_list;
             while (pem)
             {
 		if (pem->module == pModule->module32) break;
diff --git a/debugger/hash.c b/debugger/hash.c
index acf281f..ba87473 100644
--- a/debugger/hash.c
+++ b/debugger/hash.c
@@ -803,7 +803,7 @@
     void **functions;
     const char **names;
 
-    PE_MODREF *pem = pCurrentProcess->modref_list;
+    PE_MODREF *pem = PROCESS_Current()->modref_list;
     while (pem && (pem->module != hModule)) pem = pem->next;
     if (!pem) return;
     exports = pem->pe_export;
diff --git a/files/drive.c b/files/drive.c
index d5a8a86..7aca8b6 100644
--- a/files/drive.c
+++ b/files/drive.c
@@ -949,7 +949,7 @@
     	if (DRIVE_GetType(drive)==TYPE_CDROM)
 	    lstrcpyn32A( fsname, "CDFS", fsname_len );
 	else
-	    lstrcpyn32A( fsname, "FAT16", fsname_len );
+	    lstrcpyn32A( fsname, "FAT", fsname_len );
     }
     return TRUE;
 }
diff --git a/graphics/ddraw.c b/graphics/ddraw.c
index 7248690..d2fd0bd 100644
--- a/graphics/ddraw.c
+++ b/graphics/ddraw.c
@@ -1,6 +1,38 @@
 /*		DirectDraw
  *
- * Copyright 1997 Marcus Meissner
+ * Copyright 1997,1998 Marcus Meissner
+ */
+/* When DirectVideo mode is enabled you can no longer use 'normal' X 
+ * applications nor can you switch to a virtual console. Also, enabling
+ * only works, if you have switched to the screen where the application
+ * is running.
+ * Some ways to debug this stuff are:
+ * - A terminal connected to the serial port. Can be bought used for cheap.
+ *   (This is the method I am using.)
+ * - Another machine connected over some kind of network.
+ */
+/* Progress on following programs:
+ *
+ * - Diablo:
+ *   The movies play. The game doesn't yet. No sound. (Needs clone())
+ *
+ * - WingCommander 4 (not 5!) / Win95 Patch:
+ *   The intromovie plays, in 8 bit mode (to reconfigure wc4, run wine
+ *   "wc4w.exe -I"). The 16bit mode looks broken, but I think this is due to
+ *   my Matrox Mystique which uses 565 (rgb) colorweight instead of the usual
+ *   555. Specifying it in DDPIXELFORMAT didn't help.
+ *   Requires to be run in 640x480xdepth mode (doesn't seem to heed
+ *   DDSURFACEDESC.lPitch).
+ *
+ * - Monkey Island 3:
+ *   Goes to the easy/hard selection screen, then hangs due to not MT safe
+ *   XLibs.
+ * 
+ * - Dark Angel Demo (Some shoot and run game):
+ *   The graphics stuff works fine, you can play it.
+ *
+ * - XvT:
+ *   Doesn't work, I am still unsure why not.
  */
 
 #include "config.h"
@@ -8,6 +40,7 @@
 #include <unistd.h>
 #include <assert.h>
 #include <X11/Xlib.h>
+#include <sys/signal.h>
 
 #include "windows.h"
 #include "winerror.h"
@@ -30,7 +63,7 @@
 static HRESULT WINAPI IDirectDrawSurface_QueryInterface(LPDIRECTDRAWSURFACE,REFIID,LPVOID*);
 static HRESULT WINAPI IDirectDraw_QueryInterface(LPDIRECTDRAW this,REFIID refiid,LPVOID *obj);
 static HRESULT WINAPI IDirectDraw2_CreateSurface( LPDIRECTDRAW2 this,LPDDSURFACEDESC lpddsd,LPDIRECTDRAWSURFACE *lpdsf,IUnknown *lpunk);
-static HRESULT WINAPI IDirectDraw_CreateSurface( LPDIRECTDRAW this,LPDDSURFACEDESC *lpddsd,LPDIRECTDRAWSURFACE *lpdsf,IUnknown *lpunk);
+static HRESULT WINAPI IDirectDraw_CreateSurface( LPDIRECTDRAW this,LPDDSURFACEDESC lpddsd,LPDIRECTDRAWSURFACE *lpdsf,IUnknown *lpunk);
 static struct IDirectDrawSurface2_VTable dds2vt;
 static struct IDirectDrawSurface_VTable ddsvt;
 
@@ -39,8 +72,8 @@
 DirectDrawEnumerate32A(LPDDENUMCALLBACK32A ddenumproc,LPVOID data) {
 	fprintf(stderr,"DirectDrawEnumerateA(%p,%p).\n",ddenumproc,data);
 	ddenumproc(0,"WINE Display","display",data);
-	ddenumproc(&IID_IDirectDraw,"WINE DirectDraw","directdraw",data);
-	ddenumproc(&IID_IDirectDrawPalette,"WINE DirectPalette","directpalette",data);
+	ddenumproc((void*)&IID_IDirectDraw,"WINE DirectDraw","directdraw",data);
+	ddenumproc((void*)&IID_IDirectDrawPalette,"WINE DirectPalette","directpalette",data);
 	return 0;
 }
 
@@ -52,10 +85,125 @@
 
 #ifdef HAVE_LIBXXF86DGA
 
+static void _dump_DDSCAPS(DWORD flagmask) {
+	int	i;
+	const struct {
+		DWORD	mask;
+		char	*name;
+	} flags[] = {
+#define FE(x) { x, #x},
+		FE(DDSCAPS_3D)
+		FE(DDSCAPS_ALPHA)
+		FE(DDSCAPS_BACKBUFFER)
+		FE(DDSCAPS_COMPLEX)
+		FE(DDSCAPS_FLIP)
+		FE(DDSCAPS_FRONTBUFFER)
+		FE(DDSCAPS_OFFSCREENPLAIN)
+		FE(DDSCAPS_OVERLAY)
+		FE(DDSCAPS_PALETTE)
+		FE(DDSCAPS_PRIMARYSURFACE)
+		FE(DDSCAPS_PRIMARYSURFACELEFT)
+		FE(DDSCAPS_SYSTEMMEMORY)
+		FE(DDSCAPS_TEXTURE)
+		FE(DDSCAPS_3DDEVICE)
+		FE(DDSCAPS_VIDEOMEMORY)
+		FE(DDSCAPS_VISIBLE)
+		FE(DDSCAPS_WRITEONLY)
+		FE(DDSCAPS_ZBUFFER)
+		FE(DDSCAPS_OWNDC)
+		FE(DDSCAPS_LIVEVIDEO)
+		FE(DDSCAPS_HWCODEC)
+		FE(DDSCAPS_MODEX)
+		FE(DDSCAPS_MIPMAP)
+		FE(DDSCAPS_ALLOCONLOAD)
+	};
+	for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
+		if (flags[i].mask & flagmask)
+			fprintf(stderr,"%s ",flags[i].name);
+}
+
+static void _dump_DDCAPS(DWORD flagmask) {
+	int	i;
+	const struct {
+		DWORD	mask;
+		char	*name;
+} flags[] = {
+#define FE(x) { x, #x},
+		FE(DDCAPS_3D)
+		FE(DDCAPS_ALIGNBOUNDARYDEST)
+		FE(DDCAPS_ALIGNSIZEDEST)
+		FE(DDCAPS_ALIGNBOUNDARYSRC)
+		FE(DDCAPS_ALIGNSIZESRC)
+		FE(DDCAPS_ALIGNSTRIDE)
+		FE(DDCAPS_BLT)
+		FE(DDCAPS_BLTQUEUE)
+		FE(DDCAPS_BLTFOURCC)
+		FE(DDCAPS_BLTSTRETCH)
+		FE(DDCAPS_GDI)
+		FE(DDCAPS_OVERLAY)
+		FE(DDCAPS_OVERLAYCANTCLIP)
+		FE(DDCAPS_OVERLAYFOURCC)
+		FE(DDCAPS_OVERLAYSTRETCH)
+		FE(DDCAPS_PALETTE)
+		FE(DDCAPS_PALETTEVSYNC)
+		FE(DDCAPS_READSCANLINE)
+		FE(DDCAPS_STEREOVIEW)
+		FE(DDCAPS_VBI)
+		FE(DDCAPS_ZBLTS)
+		FE(DDCAPS_ZOVERLAYS)
+		FE(DDCAPS_COLORKEY)
+		FE(DDCAPS_ALPHA)
+		FE(DDCAPS_COLORKEYHWASSIST)
+		FE(DDCAPS_NOHARDWARE)
+		FE(DDCAPS_BLTCOLORFILL)
+		FE(DDCAPS_BANKSWITCHED)
+		FE(DDCAPS_BLTDEPTHFILL)
+		FE(DDCAPS_CANCLIP)
+		FE(DDCAPS_CANCLIPSTRETCHED)
+		FE(DDCAPS_CANBLTSYSMEM)
+	};
+	for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
+		if (flags[i].mask & flagmask)
+			fprintf(stderr,"%s ",flags[i].name);
+}
+
+static void _dump_DDSD(DWORD flagmask) {
+	int	i;
+	const struct {
+		DWORD	mask;
+		char	*name;
+	} flags[] = {
+		FE(DDSD_CAPS)
+		FE(DDSD_HEIGHT)
+		FE(DDSD_WIDTH)
+		FE(DDSD_PITCH)
+		FE(DDSD_BACKBUFFERCOUNT)
+		FE(DDSD_ZBUFFERBITDEPTH)
+		FE(DDSD_ALPHABITDEPTH)
+		FE(DDSD_PIXELFORMAT)
+		FE(DDSD_CKDESTOVERLAY)
+		FE(DDSD_CKDESTBLT)
+		FE(DDSD_CKSRCOVERLAY)
+		FE(DDSD_CKSRCBLT)
+		FE(DDSD_MIPMAPCOUNT)
+		FE(DDSD_REFRESHRATE)
+	};
+	for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
+		if (flags[i].mask & flagmask)
+			fprintf(stderr,"%s ",flags[i].name);
+}
+
 static int _getpixelformat(LPDIRECTDRAW ddraw,LPDDPIXELFORMAT pf) {
+	static XVisualInfo	*vi;
+	XVisualInfo		vt;
+	int			nitems;
+
+	if (!vi)
+		vi = XGetVisualInfo(display,VisualNoMask,&vt,&nitems);
+
 	pf->dwFourCC = mmioFOURCC('R','G','B',' ');
 	if (ddraw->d.depth==8) {
-		pf->dwFlags 		= DDPF_RGB|DDPF_PALETTEINDEXEDTO8;
+		pf->dwFlags 		= DDPF_RGB|DDPF_PALETTEINDEXED8;
 		pf->x.dwRGBBitCount	= 8;
 		pf->y.dwRBitMask  	= 0;
 		pf->z.dwGBitMask  	= 0;
@@ -63,11 +211,11 @@
 		return 0;
 	}
 	if (ddraw->d.depth==16) {
-		pf->dwFlags       = DDPF_RGB;
-		pf->x.dwRGBBitCount  = 16;
-		pf->y.dwRBitMask  = 0x0000f800;
-		pf->z.dwGBitMask  = 0x000007e0;
-		pf->xx.dwBBitMask = 0x0000001f;
+		pf->dwFlags       	= DDPF_RGB;
+		pf->x.dwRGBBitCount	= 16;
+		pf->y.dwRBitMask	= vi[0].red_mask;
+		pf->z.dwGBitMask	= vi[0].green_mask;
+		pf->xx.dwBBitMask	= vi[0].blue_mask;
 		return 0;
 	}
 	fprintf(stderr,"_getpixelformat:oops?\n");
@@ -78,10 +226,12 @@
 static HRESULT WINAPI IDirectDrawSurface_Lock(
     LPDIRECTDRAWSURFACE this,LPRECT32 lprect,LPDDSURFACEDESC lpddsd,DWORD flags, HANDLE32 hnd
 ) {
-	dprintf_relay(stddeb,"IDirectDrawSurface(%p)->Lock(%p,%p,%08lx,%08lx)\n",
+	/*
+	fprintf(stderr,"IDirectDrawSurface(%p)->Lock(%p,%p,%08lx,%08lx)\n",
 		this,lprect,lpddsd,flags,(DWORD)hnd
 	);
 	fprintf(stderr,".");
+	*/
 	if (lprect) {
 		/*
 		fprintf(stderr,"	lprect: %dx%d-%dx%d\n",
@@ -103,10 +253,10 @@
 static HRESULT WINAPI IDirectDrawSurface2_Lock(
     LPDIRECTDRAWSURFACE2 this,LPRECT32 lprect,LPDDSURFACEDESC lpddsd,DWORD flags, HANDLE32 hnd
 ) {
-	dprintf_relay(stddeb,"IDirectDrawSurface2(%p)->Lock(%p,%p,%08lx,%08lx)\n",
+	fprintf(stderr,"IDirectDrawSurface2(%p)->Lock(%p,%p,%08lx,%08lx)\n",
 		this,lprect,lpddsd,flags,(DWORD)hnd
 	);
-	fprintf(stderr,".");
+	/*fprintf(stderr,".");*/
 	if (lprect) {
 		/*
 		fprintf(stderr,"	lprect: %dx%d-%dx%d\n",
@@ -128,30 +278,47 @@
 static HRESULT WINAPI IDirectDrawSurface_Unlock(
 	LPDIRECTDRAWSURFACE this,LPVOID surface
 ) {
-	dprintf_relay(stddeb,"IDirectDrawSurface(%p)->Unlock(%p)\n",this,surface);
+	dprintf_relay(stderr,"IDirectDrawSurface(%p)->Unlock(%p)\n",this,surface);
 	return 0;
 }
 
 static HRESULT WINAPI IDirectDrawSurface_Flip(
 	LPDIRECTDRAWSURFACE this,LPDIRECTDRAWSURFACE flipto,DWORD dwFlags
 ) {
-	fprintf(stderr,"IDirectDrawSurface(%p)->Flip(%p,%08lx),STUB\n",this,flipto,dwFlags);
-	if (flipto) {
-		XF86DGASetViewPort(display,DefaultScreen(display),0,flipto->fb_height);
-	} else {
-		/* FIXME: flip through attached surfaces */
-		XF86DGASetViewPort(display,DefaultScreen(display),0,this->fb_height);
+/*	fprintf(stderr,"IDirectDrawSurface(%p)->Flip(%p,%08lx),STUB\n",this,flipto,dwFlags);*/
+	if (!flipto) {
+		if (this->backbuffer)
+			flipto = this->backbuffer;
+		else
+			flipto = this;
 	}
-	while (!XF86DGAViewPortChanged(display,DefaultScreen(display),1)) {
-	} 
-	fprintf(stderr,"flipped to new height %ld\n",flipto->fb_height);
+/*	fprintf(stderr,"f>%ld",flipto->fb_height);*/
+	XF86DGASetViewPort(display,DefaultScreen(display),0,flipto->fb_height);
+	if (flipto->palette && flipto->palette->cm)
+		XF86DGAInstallColormap(display,DefaultScreen(display),flipto->palette->cm);
+	while (!XF86DGAViewPortChanged(display,DefaultScreen(display),2)) {
+		fprintf(stderr,"w");
+	}
+	/* is this a good idea ? */
+	if (flipto!=this) {
+		int	tmp;
+		LPVOID	ptmp;
+
+		tmp = this->fb_height;
+		this->fb_height = flipto->fb_height;
+		flipto->fb_height = tmp;
+
+		ptmp = this->surface;
+		this->surface = flipto->surface;
+		flipto->surface = ptmp;
+	}
 	return 0;
 }
 
 static HRESULT WINAPI IDirectDrawSurface2_Unlock(
 	LPDIRECTDRAWSURFACE2 this,LPVOID surface
 ) {
-	dprintf_relay(stddeb,"IDirectDrawSurface2(%p)->Unlock(%p)\n",this,surface);
+	dprintf_relay(stderr,"IDirectDrawSurface2(%p)->Unlock(%p)\n",this,surface);
 	return 0;
 }
 
@@ -213,38 +380,43 @@
 static HRESULT WINAPI IDirectDrawSurface_GetCaps(
 	LPDIRECTDRAWSURFACE this,LPDDSCAPS caps
 ) {
-	fprintf(stderr,"IDirectDrawSurface(%p)->GetCaps(%p),stub!\n",this,caps);
-	caps->dwCaps = 0; /* we cannot do anything */
+	fprintf(stderr,"IDirectDrawSurface(%p)->GetCaps(%p)\n",this,caps);
+	caps->dwCaps = DDCAPS_PALETTE; /* probably more */
 	return 0;
 }
 
 static HRESULT WINAPI IDirectDrawSurface_GetSurfaceDesc(
 	LPDIRECTDRAWSURFACE this,LPDDSURFACEDESC ddsd
-) {
+) { 
 	fprintf(stderr,"IDirectDrawSurface(%p)->GetSurfaceDesc(%p)\n",this,ddsd);
-	if (ddsd->dwFlags & DDSD_CAPS)
-		ddsd->ddsCaps.dwCaps = 0;
-	if (ddsd->dwFlags & DDSD_BACKBUFFERCOUNT)
-		ddsd->dwBackBufferCount = 1;
-	if (ddsd->dwFlags & DDSD_HEIGHT)
-		ddsd->dwHeight = this->height;
-	if (ddsd->dwFlags & DDSD_WIDTH)
-		ddsd->dwHeight = this->width;
-	ddsd->dwFlags &= ~(DDSD_CAPS|DDSD_BACKBUFFERCOUNT|DDSD_HEIGHT|DDSD_WIDTH);
-	if (ddsd->dwFlags)
-		fprintf(stderr,"	ddsd->flags is 0x%08lx\n",ddsd->dwFlags);
+	fprintf(stderr,"	flags: ");
+	_dump_DDSD(ddsd->dwFlags);
+	fprintf(stderr,"\n");
+
+	ddsd->dwFlags |= DDSD_PIXELFORMAT|DDSD_CAPS|DDSD_BACKBUFFERCOUNT|DDSD_HEIGHT|DDSD_WIDTH;
+	ddsd->ddsCaps.dwCaps	= DDSCAPS_PALETTE;
+	ddsd->dwBackBufferCount	= 1;
+	ddsd->dwHeight		= this->height;
+	ddsd->dwWidth		= this->width;
+	ddsd->lPitch		= this->lpitch;
+	if (this->backbuffer)
+		ddsd->ddsCaps.dwCaps |= DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP;
+	_getpixelformat(this->ddraw,&(ddsd->ddpfPixelFormat));
+	
 	return 0;
 }
 
 static ULONG WINAPI IDirectDrawSurface_AddRef(LPDIRECTDRAWSURFACE this) {
-	dprintf_relay(stddeb,"IDirectDrawSurface(%p)->AddRef()\n",this);
+	dprintf_relay(stderr,"IDirectDrawSurface(%p)->AddRef()\n",this);
 	return ++(this->ref);
 }
 
 static ULONG WINAPI IDirectDrawSurface_Release(LPDIRECTDRAWSURFACE this) {
-	dprintf_relay(stddeb,"IDirectDrawSurface(%p)->Release()\n",this);
+	dprintf_relay(stderr,"IDirectDrawSurface(%p)->Release()\n",this);
 	if (!--(this->ref)) {
 		this->ddraw->lpvtbl->fnRelease(this->ddraw);
+		/* clear out of surface list */
+		this->ddraw->d.vpmask &= ~(1<<(this->fb_height/this->ddraw->d.fb_height));
 		HeapFree(GetProcessHeap(),0,this);
 		return 0;
 	}
@@ -252,14 +424,15 @@
 }
 
 static ULONG WINAPI IDirectDrawSurface2_AddRef(LPDIRECTDRAWSURFACE2 this) {
-	dprintf_relay(stddeb,"IDirectDrawSurface2(%p)->AddRef()\n",this);
+	dprintf_relay(stderr,"IDirectDrawSurface2(%p)->AddRef()\n",this);
 	return ++(this->ref);
 }
 
 static ULONG WINAPI IDirectDrawSurface2_Release(LPDIRECTDRAWSURFACE2 this) {
-	dprintf_relay(stddeb,"IDirectDrawSurface2(%p)->Release()\n",this);
+	dprintf_relay(stderr,"IDirectDrawSurface2(%p)->Release()\n",this);
 	if (!--(this->ref)) {
 		this->ddraw->lpvtbl->fnRelease(this->ddraw);
+		this->ddraw->d.vpmask &= ~(1<<(this->fb_height/this->ddraw->d.fb_height));
 		HeapFree(GetProcessHeap(),0,this);
 		return 0;
 	}
@@ -269,30 +442,28 @@
 static HRESULT WINAPI IDirectDrawSurface2_GetAttachedSurface(
 	LPDIRECTDRAWSURFACE2 this,LPDDSCAPS lpddsd,LPDIRECTDRAWSURFACE2 *lpdsf
 ) {
-	DDSURFACEDESC	ddsfd;
-	IUnknown	unk;
-
-	/* DOES NOT CREATE THEM, but uses the ones already attached to this
-	 * surface 
-	 */
 	fprintf(stderr,"IDirectDrawSurface2(%p)->GetAttachedSurface(%p,%p)\n",this,lpddsd,lpdsf);
-	/* FIXME: not correct */
-	IDirectDraw2_CreateSurface((LPDIRECTDRAW2)this->ddraw,&ddsfd,(LPDIRECTDRAWSURFACE*)lpdsf,&unk);
-
-	lpddsd->dwCaps = 0;
+	fprintf(stderr,"	caps ");_dump_DDSCAPS(lpddsd->dwCaps);fprintf(stderr,"\n");
+	if (!(lpddsd->dwCaps & DDSCAPS_BACKBUFFER)) {
+		fprintf(stderr,"whoops, can only handle backbuffers for now\n");
+		return E_FAIL;
+	}
+	/* FIXME: should handle more than one backbuffer */
+	*lpdsf = this->backbuffer;
 	return 0;
 }
 
 static HRESULT WINAPI IDirectDrawSurface_GetAttachedSurface(
 	LPDIRECTDRAWSURFACE this,LPDDSCAPS lpddsd,LPDIRECTDRAWSURFACE *lpdsf
 ) {
-	LPDDSURFACEDESC	lpddsfd;
-	IUnknown	unk;
-
 	fprintf(stderr,"IDirectDrawSurface(%p)->GetAttachedSurface(%p,%p)\n",this,lpddsd,lpdsf);
-	/* FIXME: not correct */
-	IDirectDraw_CreateSurface(this->ddraw,&lpddsfd,lpdsf,&unk);
-	lpddsd->dwCaps = 0;
+	fprintf(stderr,"	caps ");_dump_DDSCAPS(lpddsd->dwCaps);fprintf(stderr,"\n");
+	if (!(lpddsd->dwCaps & DDSCAPS_BACKBUFFER)) {
+		fprintf(stderr,"whoops, can only handle backbuffers for now\n");
+		return E_FAIL;
+	}
+	/* FIXME: should handle more than one backbuffer */
+	*lpdsf = this->backbuffer;
 	return 0;
 }
 
@@ -302,8 +473,7 @@
 	fprintf(stderr,"IDirectDrawSurface(%p)->Initialize(%p,%p)\n",
 		this,ddraw,lpdsfd
 	);
-	fprintf(stderr,"	dwFlags is %08lx\n",lpdsfd->dwFlags);
-	return 0;
+	return DDERR_ALREADYINITIALIZED;
 }
 
 static HRESULT WINAPI IDirectDrawSurface_GetPixelFormat(
@@ -340,45 +510,45 @@
 }
 
 static struct IDirectDrawSurface2_VTable dds2vt = {
-	1/*IDirectDrawSurface2_QueryInterface*/,
+	(void*)1/*IDirectDrawSurface2_QueryInterface*/,
 	IDirectDrawSurface2_AddRef,
 	IDirectDrawSurface2_Release,
-	4,
-	5,
-	6/*IDirectDrawSurface_Blt*/,
-	7/*IDirectDrawSurface_BltBatch*/,
-	8,
-	9,
+	(void*)4,
+	(void*)5,
+	(void*)6/*IDirectDrawSurface_Blt*/,
+	(void*)7/*IDirectDrawSurface_BltBatch*/,
+	(void*)8,
+	(void*)9,
 	IDirectDrawSurface2_EnumAttachedSurfaces,
-	11,
-	12,
+	(void*)11,
+	(void*)12,
 	IDirectDrawSurface2_GetAttachedSurface,
-	14,
-	15/*IDirectDrawSurface_GetCaps*/,
-	16,
-	17,
-	18,
-	19,
-	20,
-	21,
-	22,
-	23/*IDirectDrawSurface_GetSurfaceDesc*/,
-	24,
-	25,
+	(void*)14,
+	(void*)15/*IDirectDrawSurface_GetCaps*/,
+	(void*)16,
+	(void*)17,
+	(void*)18,
+	(void*)19,
+	(void*)20,
+	(void*)21,
+	(void*)22,
+	(void*)23/*IDirectDrawSurface_GetSurfaceDesc*/,
+	(void*)24,
+	(void*)25,
 	IDirectDrawSurface2_Lock,
-	27,
-	28,
-	29,
-	30,
-	31,
+	(void*)27,
+	(void*)28,
+	(void*)29,
+	(void*)30,
+	(void*)31,
 	IDirectDrawSurface2_SetPalette,
 	IDirectDrawSurface2_Unlock,
-	34,
-	35,
-	36,
-	37,
-	38,
-	39,
+	(void*)34,
+	(void*)35,
+	(void*)36,
+	(void*)37,
+	(void*)38,
+	(void*)39,
 };
 
 
@@ -408,61 +578,96 @@
 	IDirectDrawSurface_QueryInterface,
 	IDirectDrawSurface_AddRef,
 	IDirectDrawSurface_Release,
-	4,
-	5,
+	(void*)4,
+	(void*)5,
 	IDirectDrawSurface_Blt,
 	IDirectDrawSurface_BltBatch,
 	IDirectDrawSurface_BltFast,
-	9,
-	10,
-	11,
+	(void*)9,
+	(void*)10,
+	(void*)11,
 	IDirectDrawSurface_Flip,
 	IDirectDrawSurface_GetAttachedSurface,
 	IDirectDrawSurface_GetBltStatus,
 	IDirectDrawSurface_GetCaps,
-	16,
-	17,
+	(void*)16,
+	(void*)17,
 	IDirectDrawSurface_GetDC,
-	19,
+	(void*)19,
 	IDirectDrawSurface_GetOverlayPosition,
-	21,
+	(void*)21,
 	IDirectDrawSurface_GetPixelFormat,
 	IDirectDrawSurface_GetSurfaceDesc,
 	IDirectDrawSurface_Initialize,
-	25,
+	(void*)25,
 	IDirectDrawSurface_Lock,
-	27,
-	28,
-	29,
-	30,
-	31,
+	(void*)27,
+	(void*)28,
+	(void*)29,
+	(void*)30,
+	(void*)31,
 	IDirectDrawSurface_SetPalette,
 	IDirectDrawSurface_Unlock,
-	34,
-	35,
-	36,
+	(void*)34,
+	(void*)35,
+	(void*)36,
 };
 
 static HRESULT WINAPI IDirectDraw_CreateSurface(
-	LPDIRECTDRAW this,LPDDSURFACEDESC *lpddsd,LPDIRECTDRAWSURFACE *lpdsf,IUnknown *lpunk
+	LPDIRECTDRAW this,LPDDSURFACEDESC lpddsd,LPDIRECTDRAWSURFACE *lpdsf,IUnknown *lpunk
 ) {
+	int	i;
+
 	fprintf(stderr,"IDirectDraw(%p)->CreateSurface(%p,%p,%p)\n",this,lpddsd,lpdsf,lpunk);
-	*lpdsf = (LPDIRECTDRAWSURFACE)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectDrawSurface));
+	fprintf(stderr," [w=%ld,h=%ld,flags ",lpddsd->dwWidth,lpddsd->dwHeight);
+	_dump_DDSD(lpddsd->dwFlags);
+	fprintf(stderr,"caps ");_dump_DDSCAPS(lpddsd->ddsCaps.dwCaps);
+	fprintf(stderr,"]\n");
+
+	*lpdsf = (LPDIRECTDRAWSURFACE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectDrawSurface));
 	this->lpvtbl->fnAddRef(this);
 	(*lpdsf)->ref = 1;
 	(*lpdsf)->lpvtbl = &ddsvt;
-	(*lpdsf)->surface = this->d.fb_addr+(this->d.current_height*this->d.fb_width*this->d.depth/8);
-	(*lpdsf)->fb_height = this->d.current_height; /* for setviewport */
-	this->d.current_height += this->d.fb_height;
+	for (i=0;i<32;i++)
+		if (!(this->d.vpmask & (1<<i)))
+			break;
+	fprintf(stderr,"using viewport %d for a primary surface\n",i);
+	/* if i == 32 or maximum ... return error */
+	this->d.vpmask|=(1<<i);
+	(*lpdsf)->surface = this->d.fb_addr+((i*this->d.vp_height)*this->d.fb_width*this->d.depth/8);
+	(*lpdsf)->fb_height = i*this->d.fb_height;
+
 	(*lpdsf)->width = this->d.width;
 	(*lpdsf)->height = this->d.height;
 	(*lpdsf)->ddraw = this;
 	(*lpdsf)->lpitch = this->d.fb_width*this->d.depth/8;
-	*lpddsd = (LPDDSURFACEDESC)HeapAlloc(GetProcessHeap(),0,sizeof(DDSURFACEDESC));
-	(*lpddsd)->dwWidth = this->d.width;
-	(*lpddsd)->dwHeight = this->d.height;
-	(*lpddsd)->lPitch = this->d.fb_width*this->d.depth/8;
-	(*lpddsd)->ddsCaps.dwCaps = 0;
+	(*lpdsf)->backbuffer = NULL;
+	if (lpddsd->dwFlags & DDSD_BACKBUFFERCOUNT) {
+		LPDIRECTDRAWSURFACE	back;
+
+		if (lpddsd->dwBackBufferCount>1)
+			fprintf(stderr,"urks, wants to have more than one backbuffer (%ld)!\n",lpddsd->dwBackBufferCount);
+
+		(*lpdsf)->backbuffer = back = (LPDIRECTDRAWSURFACE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectDrawSurface));
+		this->lpvtbl->fnAddRef(this);
+		back->ref = 1;
+		back->lpvtbl = &ddsvt;
+		for (i=0;i<32;i++)
+			if (!(this->d.vpmask & (1<<i)))
+				break;
+		fprintf(stderr,"using viewport %d for backbuffer\n",i);
+		/* if i == 32 or maximum ... return error */
+		this->d.vpmask|=(1<<i);
+		back->surface = this->d.fb_addr+((i*this->d.vp_height)*this->d.fb_width*this->d.depth/8);
+		back->fb_height = i*this->d.fb_height;
+
+		back->width = this->d.width;
+		back->height = this->d.height;
+		back->ddraw = this;
+		back->lpitch = this->d.fb_width*this->d.depth/8;
+		back->backbuffer = NULL; /* does not have a backbuffer, it is
+					  * one! */
+	}
 	return 0;
 }
 
@@ -477,35 +682,85 @@
 static HRESULT WINAPI IDirectDraw2_CreateSurface(
 	LPDIRECTDRAW2 this,LPDDSURFACEDESC lpddsd,LPDIRECTDRAWSURFACE *lpdsf,IUnknown *lpunk
 ) {
+	int	i;
+
 	fprintf(stderr,"IDirectDraw2(%p)->CreateSurface(%p,%p,%p)\n",this,lpddsd,lpdsf,lpunk);
-	*lpdsf = (LPDIRECTDRAWSURFACE)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectDrawSurface));
+	*lpdsf = (LPDIRECTDRAWSURFACE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectDrawSurface));
 	this->lpvtbl->fnAddRef(this);
 	(*lpdsf)->ref = 1;
 	(*lpdsf)->lpvtbl = &ddsvt;
-	(*lpdsf)->surface = this->d.fb_addr+(this->d.current_height*this->d.fb_width*this->d.depth/8);
+
+	for (i=0;i<32;i++)
+		if (!(this->d.vpmask & (1<<i)))
+			break;
+	fprintf(stderr,"using viewport %d for primary\n",i);
+	/* if i == 32 or maximum ... return error */
+	this->d.vpmask|=(1<<i);
+	(*lpdsf)->surface = this->d.fb_addr+((i*this->d.fb_height)*this->d.fb_width*this->d.depth/8);
 	(*lpdsf)->width = this->d.width;
 	(*lpdsf)->height = this->d.height;
 	(*lpdsf)->ddraw = (LPDIRECTDRAW)this;
-	(*lpdsf)->fb_height = this->d.current_height;
+	(*lpdsf)->fb_height = i*this->d.fb_height;
 	(*lpdsf)->lpitch = this->d.fb_width*this->d.depth/8;
-	this->d.current_height += this->d.fb_height;
-	lpddsd->dwWidth = this->d.width;
-	lpddsd->dwHeight = this->d.height;
-	lpddsd->lPitch = this->d.fb_width*this->d.depth/8;
-	lpddsd->ddsCaps.dwCaps = 0;
+	(*lpdsf)->backbuffer = NULL;
+	if (lpddsd->dwFlags & DDSD_BACKBUFFERCOUNT) {
+		LPDIRECTDRAWSURFACE	back;
+
+		if (lpddsd->dwBackBufferCount>1)
+			fprintf(stderr,"urks, wants to have more than one backbuffer (%ld)!\n",lpddsd->dwBackBufferCount);
+
+		(*lpdsf)->backbuffer = back = (LPDIRECTDRAWSURFACE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectDrawSurface2));
+		this->lpvtbl->fnAddRef(this);
+		back->ref = 1;
+		back->lpvtbl = &ddsvt;
+		for (i=0;i<32;i++)
+			if (!(this->d.vpmask & (1<<i)))
+				break;
+		fprintf(stderr,"using viewport %d for backbuffer\n",i);
+		/* if i == 32 or maximum ... return error */
+		this->d.vpmask|=(1<<i);
+		back->surface = this->d.fb_addr+((i*this->d.vp_height)*this->d.fb_width*this->d.depth/8);
+		back->fb_height = i*this->d.fb_height;
+
+		back->width = this->d.width;
+		back->height = this->d.height;
+		back->ddraw = (LPDIRECTDRAW)this;
+		back->lpitch = this->d.fb_width*this->d.depth/8;
+		back->backbuffer = NULL; /* does not have a backbuffer, it is
+					  * one! */
+	}
 	return 0;
 }
 
 static HRESULT WINAPI IDirectDraw_SetCooperativeLevel(
-	LPDIRECTDRAW this,HWND32 hwnd,DWORD x
+	LPDIRECTDRAW this,HWND32 hwnd,DWORD cooplevel
 ) {
+	int	i;
+	const struct {
+		int	mask;
+		char	*name;
+	} flagmap[] = {
+		FE(DDSCL_FULLSCREEN)
+		FE(DDSCL_ALLOWREBOOT)
+		FE(DDSCL_NOWINDOWCHANGES)
+		FE(DDSCL_NORMAL)
+		FE(DDSCL_ALLOWMODEX)
+		FE(DDSCL_EXCLUSIVE)
+	};
 	fprintf(stderr,"IDirectDraw(%p)->SetCooperativeLevel(%08lx,%08lx),stub!\n",
-		this,(DWORD)hwnd,x
+		this,(DWORD)hwnd,cooplevel
 	);
+	fprintf(stderr,"	cooperative level ");
+	for (i=0;i<sizeof(flagmap)/sizeof(flagmap[0]);i++)
+		if (flagmap[i].mask & cooplevel)
+			fprintf(stderr,"%s ",flagmap[i].name);
+	fprintf(stderr,"\n");
 	this->d.mainwindow = hwnd;
 	return 0;
 }
 
+extern BOOL32 SIGNAL_InitEmulator(void);
+
 static HRESULT WINAPI IDirectDraw_SetDisplayMode(
 	LPDIRECTDRAW this,DWORD width,DWORD height,DWORD depth
 ) {
@@ -535,9 +790,18 @@
 	if (this->d.fb_height < height)
 		this->d.fb_height = height;
 	this->d.depth	= depth;
+
+	/* FIXME: this function OVERWRITES several signal handlers. 
+	 * can we save them? and restore them later? In a way that
+	 * it works for the library too?
+	 */
 	XF86DGADirectVideo(display,DefaultScreen(display),XF86DGADirectGraphics);
+/* FIXME:  can't call this in winelib... so comment only in for debugging.
+	SIGNAL_InitEmulator();
+ */
 	return 0;
 }
+
 static HRESULT WINAPI IDirectDraw_GetCaps(
 	LPDIRECTDRAW this,LPDDCAPS caps1,LPDDCAPS caps2
 )  {
@@ -560,7 +824,10 @@
 
 
 static struct IDirectDrawClipper_VTable ddclipvt = {
-	1,2,3,4,5,6,0x10007,8,9
+	(void*)1,
+	(void*)2,(void*)3,(void*)4,(void*)5,
+	(void*)6,
+	(void*)7,(void*)8,(void*)9
 };
 
 static HRESULT WINAPI IDirectDraw_CreateClipper(
@@ -569,7 +836,7 @@
 	fprintf(stderr,"IDirectDraw(%p)->CreateClipper(%08lx,%p,%p),stub!\n",
 		this,x,lpddclip,lpunk
 	);
-	*lpddclip = (LPDIRECTDRAWCLIPPER)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectDrawClipper));
+	*lpddclip = (LPDIRECTDRAWCLIPPER)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectDrawClipper));
 	(*lpddclip)->ref = 1;
 	(*lpddclip)->lpvtbl = &ddclipvt;
 	return 0;
@@ -590,17 +857,24 @@
 	XColor		xc;
 	int		i;
 
+/*
 	fprintf(stderr,"IDirectDrawPalette(%p)->SetEntries(%08lx,%ld,%ld,%p)\n",
 		this,x,start,end,palent
 	);
+ */
 	if (!this->cm) /* should not happen */ {
 		fprintf(stderr,"no colormap in SetEntries???\n");
 		return DDERR_GENERIC;
 	}
+/* FIXME: free colorcells instead of freeing whole map */
 	XFreeColormap(display,this->cm);
 	this->cm = XCreateColormap(display,DefaultRootWindow(display),DefaultVisual(display,DefaultScreen(display)),AllocAll);
-	xc.red = xc.blue = xc.green = 0; xc.flags = DoRed|DoGreen|DoBlue; xc.pixel = 0; XStoreColor(display,this->cm,&xc);
-	xc.red = xc.blue = xc.green = 0xffff; xc.flags = DoRed|DoGreen|DoBlue; xc.pixel = 255; XStoreColor(display,this->cm,&xc);
+	if (start>0) {
+		xc.red = xc.blue = xc.green = 0; xc.flags = DoRed|DoGreen|DoBlue; xc.pixel = 0; XStoreColor(display,this->cm,&xc);
+	}
+	if (end<256) {
+		xc.red = xc.blue = xc.green = 0xffff; xc.flags = DoRed|DoGreen|DoBlue; xc.pixel = 255; XStoreColor(display,this->cm,&xc);
+	}
 	for (i=start;i<end;i++) {
 		xc.red = palent[i-start].peRed<<8;
 		xc.blue = palent[i-start].peBlue<<8;
@@ -632,13 +906,20 @@
 	return ++(this->ref);
 }
 
+static HRESULT WINAPI IDirectDrawPalette_Initialize(
+	LPDIRECTDRAWPALETTE this,LPDIRECTDRAW ddraw,DWORD x,LPPALETTEENTRY palent
+) {
+	fprintf(stderr,"IDirectDrawPalette(%p)->Initialize(%p,0x%08lx,%p)\n",this,ddraw,x,palent);
+	return DDERR_ALREADYINITIALIZED;
+}
+
 static struct IDirectDrawPalette_VTable ddpalvt = {
-	1,
+	(void*)1,
 	IDirectDrawPalette_AddRef,
 	IDirectDrawPalette_Release,
-	4,
+	(void*)4,
 	IDirectDrawPalette_GetEntries,
-	6,
+	IDirectDrawPalette_Initialize,
 	IDirectDrawPalette_SetEntries
 };
 
@@ -648,7 +929,7 @@
 	fprintf(stderr,"IDirectDraw(%p)->CreatePalette(%08lx,%p,%p,%p),stub!\n",
 		this,x,palent,lpddpal,lpunk
 	);
-	*lpddpal = (LPDIRECTDRAWPALETTE)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectDrawPalette));
+	*lpddpal = (LPDIRECTDRAWPALETTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectDrawPalette));
 	(*lpddpal)->ref = 1;
 	(*lpddpal)->lpvtbl = &ddpalvt;
 	(*lpddpal)->ddraw = this;
@@ -675,14 +956,15 @@
 }
 
 static ULONG WINAPI IDirectDraw_AddRef(LPDIRECTDRAW this) {
-	dprintf_relay(stddeb,"IDirectDraw(%p)->AddRef()\n",this);
+	dprintf_relay(stderr,"IDirectDraw(%p)->AddRef()\n",this);
 	return ++(this->ref);
 }
 
 static ULONG WINAPI IDirectDraw_Release(LPDIRECTDRAW this) {
-	dprintf_relay(stddeb,"IDirectDraw(%p)->Release()\n",this);
+	dprintf_relay(stderr,"IDirectDraw(%p)->Release()\n",this);
 	if (!--(this->ref)) {
 		fprintf(stderr,"IDirectDraw::Release:freeing IDirectDraw(%p)\n",this);
+		XF86DGADirectVideo(display,DefaultScreen(display),0);
 		HeapFree(GetProcessHeap(),0,this);
 		return 0;
 	}
@@ -744,27 +1026,27 @@
 	IDirectDraw2_QueryInterface,
 	IDirectDraw2_AddRef,
 	IDirectDraw2_Release,
-	4,
-	5/*IDirectDraw_CreateClipper*/,
+	(void*)4,
+	(void*)5/*IDirectDraw_CreateClipper*/,
 	IDirectDraw2_CreatePalette,
 	IDirectDraw2_CreateSurface,
-	8,
-	9,
+	(void*)8,
+	(void*)9,
 	IDirectDraw2_EnumSurfaces,
-	11,
+	(void*)11,
 	IDirectDraw2_GetCaps,
-	13,
-	14,
-	15,
-	16,
-	17,
-	18,
-	19,
+	(void*)13,
+	(void*)14,
+	(void*)15,
+	(void*)16,
+	(void*)17,
+	(void*)18,
+	(void*)19,
 	IDirectDraw2_RestoreDisplayMode,
 	IDirectDraw2_SetCooperativeLevel,
 	IDirectDraw2_SetDisplayMode,
-	23/*IDirectDraw_WaitForVerticalBlank*/,
-	24
+	(void*)23/*IDirectDraw_WaitForVerticalBlank*/,
+	(void*)24
 };
 
 static HRESULT WINAPI IDirectDraw_QueryInterface(
@@ -804,16 +1086,33 @@
 
 	fprintf(stderr,"IDirectDraw(%p)->EnumDisplayModes(0x%08lx,%p,%p,%p),stub!\n",this,dwFlags,lpddsfd,context,modescb);
 	ddsfd.dwSize = sizeof(ddsfd);
-	ddsfd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_CAPS|DDSD_BACKBUFFERCOUNT|DDSD_REFRESHRATE;
+	fprintf(stderr,"size is %d\n",sizeof(ddsfd));
+	ddsfd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_BACKBUFFERCOUNT|DDSD_PIXELFORMAT|DDSD_CAPS;
 	ddsfd.dwHeight = 480;
 	ddsfd.dwWidth = 640;
 	ddsfd.lPitch = 640;
-	ddsfd.ddsCaps.dwCaps = DDSCAPS_PALETTE|DDSCAPS_FRONTBUFFER|DDSCAPS_BACKBUFFER|DDSCAPS_FLIP|DDSCAPS_PRIMARYSURFACE|DDSCAPS_VIDEOMEMORY|DDSCAPS_ZBUFFER;
 	ddsfd.dwBackBufferCount = 1;
 	ddsfd.x.dwRefreshRate = 60;
+	ddsfd.ddsCaps.dwCaps = DDSCAPS_PALETTE;
+	this->d.depth = 8;
 	_getpixelformat(this,&(ddsfd.ddpfPixelFormat));
 	fprintf(stderr,"modescb returned: 0x%lx\n",(DWORD)modescb(&ddsfd,context));
-	return 0;
+	return DD_OK;
+}
+
+static HRESULT WINAPI IDirectDraw_GetDisplayMode(
+	LPDIRECTDRAW this,LPDDSURFACEDESC lpddsfd
+) {
+	fprintf(stderr,"IDirectDraw(%p)->GetDisplayMode(%p),stub!\n",this,lpddsfd);
+	lpddsfd->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_BACKBUFFERCOUNT|DDSD_PIXELFORMAT|DDSD_CAPS;
+	lpddsfd->dwHeight = this->d.vp_height;
+	lpddsfd->dwWidth = this->d.vp_width;
+	lpddsfd->lPitch = this->d.fb_width*this->d.depth/8;
+	lpddsfd->dwBackBufferCount = 1;
+	lpddsfd->x.dwRefreshRate = 60;
+	lpddsfd->ddsCaps.dwCaps = DDSCAPS_PALETTE;
+	_getpixelformat(this,&(lpddsfd->ddpfPixelFormat));
+	return DD_OK;
 }
 
 
@@ -821,22 +1120,22 @@
 	IDirectDraw_QueryInterface,
 	IDirectDraw_AddRef,
 	IDirectDraw_Release,
-	4,
+	(void*)4,
 	IDirectDraw_CreateClipper,
 	IDirectDraw_CreatePalette,
 	IDirectDraw_CreateSurface,
 	IDirectDraw_DuplicateSurface,
 	IDirectDraw_EnumDisplayModes,
-	10,
-	11,
+	(void*)10,
+	(void*)11,
 	IDirectDraw_GetCaps,
-	13,
-	14,
-	15,
-	16,
-	17,
+	IDirectDraw_GetDisplayMode,
+	(void*)14,
+	(void*)15,
+	(void*)16,
+	(void*)17,
 	IDirectDraw_GetVerticalBlankStatus,
-	19,
+	(void*)19,
 	IDirectDraw_RestoreDisplayMode,
 	IDirectDraw_SetCooperativeLevel,
 	IDirectDraw_SetDisplayMode,
@@ -861,7 +1160,7 @@
 		MessageBox32A(0,"Using the XF86DGA extensions requires the program to be run using UID 0.","WINE DirectDraw",MB_OK|MB_ICONSTOP);
 		return E_UNEXPECTED;
 	}
-	*lplpDD = (LPDIRECTDRAW)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectDraw));
+	*lplpDD = (LPDIRECTDRAW)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectDraw));
 	(*lplpDD)->lpvtbl = &ddvt;
 	(*lplpDD)->ref = 1;
 	if (!XF86DGAQueryExtension(display,&evbase,&evret)) {
@@ -883,16 +1182,11 @@
 	(*lplpDD)->d.fb_banksize = banksize;
 
 	XF86DGASetViewPort(display,DefaultScreen(display),0,0);
-	while (!XF86DGAViewPortChanged(display,DefaultScreen(display),1)) {
-		fprintf(stderr,".");
-	}
 	XF86DGAGetViewPortSize(display,DefaultScreen(display),&width,&height);
 	(*lplpDD)->d.vp_width = width;
 	(*lplpDD)->d.vp_height = height;
-	(*lplpDD)->d.fb_height = height; /* FIXME: can we find out the virtual
-	 				* size somehow else ?
-					*/
-	(*lplpDD)->d.current_height = 0;
+	(*lplpDD)->d.fb_height = height;
+	(*lplpDD)->d.vpmask = 0;
 	return 0;
 }
 #else
diff --git a/graphics/metafiledrv/graphics.c b/graphics/metafiledrv/graphics.c
index f0fbc02..1647a66 100644
--- a/graphics/metafiledrv/graphics.c
+++ b/graphics/metafiledrv/graphics.c
@@ -188,3 +188,18 @@
 {
     return MF_MetaParam4(dc,META_FLOODFILL,x,y,HIWORD(color),LOWORD(color)); 
 }
+
+
+/**********************************************************************
+ *          MFDRV_PaintRgn
+ */
+BOOL32
+MFDRV_PaintRgn( DC *dc, HRGN32 hrgn )
+{
+    INT16 index;
+    index = MF_CreateRegion( dc, hrgn );
+    if(index == -1)
+        return FALSE;
+    return MF_MetaParam1( dc, META_PAINTREGION, index );
+}
+
diff --git a/graphics/metafiledrv/init.c b/graphics/metafiledrv/init.c
index f60fe08..c55832a 100644
--- a/graphics/metafiledrv/init.c
+++ b/graphics/metafiledrv/init.c
@@ -38,7 +38,7 @@
     NULL,                            /* pOffsetClipRgn */
     MFDRV_OffsetViewportOrg,         /* pOffsetViewportOrg */
     MFDRV_OffsetWindowOrg,           /* pOffsetWindowOrg */
-    NULL,                            /* pPaintRgn */
+    MFDRV_PaintRgn,                  /* pPaintRgn */
     MFDRV_PatBlt,                    /* pPatBlt */
     MFDRV_Pie,                       /* pPie */
     MFDRV_PolyPolygon,               /* pPolyPolygon */
diff --git a/graphics/x11drv/clipping.c b/graphics/x11drv/clipping.c
index 7645e68..d6cbc08 100644
--- a/graphics/x11drv/clipping.c
+++ b/graphics/x11drv/clipping.c
@@ -1,7 +1,7 @@
 /*
- * DC clipping functions
+ * X11DRV clipping functions
  *
- * Copyright 1993 Alexandre Julliard
+ * Copyright 1998 Huw Davies
  */
 
 #include <stdio.h>
@@ -10,26 +10,55 @@
 #include "region.h"
 #include "stddebug.h"
 #include "debug.h"
+#include "heap.h"
 
 /***********************************************************************
  *           X11DRV_SetDeviceClipping
+ *           Copy RECT32s to a temporary buffer of XRectangles and call
+ *           XSetClipRectangles().
+ *
+ *           Could write using GetRegionData but this would be slower.
  */
 void X11DRV_SetDeviceClipping( DC * dc )
 {
+    XRectangle *pXrect;
     RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr(dc->w.hGCClipRgn, REGION_MAGIC);
     if (!obj)
     {
         fprintf( stderr, "X11DRV_SetDeviceClipping: Rgn is 0. Please report this.\n");
         exit(1);
     }
-    if (obj->xrgn)
+    
+    if (obj->rgn->numRects > 0)
     {
-        XSetRegion( display, dc->u.x.gc, obj->xrgn );
-        XSetClipOrigin( display, dc->u.x.gc, dc->w.DCOrgX, dc->w.DCOrgY );
+        XRectangle *pXr;
+        RECT32 *pRect = obj->rgn->rects;
+        RECT32 *pEndRect = obj->rgn->rects + obj->rgn->numRects;
+
+        pXrect = HeapAlloc( GetProcessHeap(), 0, 
+			    sizeof(*pXrect) * obj->rgn->numRects );
+	if(!pXrect)
+	{
+	    fprintf(stderr, "X11DRV_SetDeviceClipping() can't alloc buffer\n");
+	    return;
+	}
+
+        for(pXr = pXrect; pRect < pEndRect; pRect++, pXr++)
+        {
+            pXr->x = pRect->left;
+            pXr->y = pRect->top;
+            pXr->width = pRect->right - pRect->left;
+            pXr->height = pRect->bottom - pRect->top;
+        }
     }
-    else  /* Clip everything */
-    {
-        XSetClipRectangles( display, dc->u.x.gc, 0, 0, NULL, 0, 0 );
-    }
+    else
+        pXrect = NULL;
+
+    XSetClipRectangles( display, dc->u.x.gc, dc->w.DCOrgX, dc->w.DCOrgY, 
+                pXrect, obj->rgn->numRects, YXBanded );
+
+    if(pXrect)
+        HeapFree( GetProcessHeap(), 0, pXrect );
+
     GDI_HEAP_UNLOCK( dc->w.hGCClipRgn );
 }
diff --git a/graphics/x11drv/graphics.c b/graphics/x11drv/graphics.c
index d6e42e4..af3fd94 100644
--- a/graphics/x11drv/graphics.c
+++ b/graphics/x11drv/graphics.c
@@ -440,15 +440,20 @@
     HRGN32 tmpVisRgn, prevVisRgn;
     HDC32  hdc = dc->hSelf; /* FIXME: should not mix dc/hdc this way */
 
-      /* Modify visible region */
+    if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 ))) return FALSE;
 
-    if (!(prevVisRgn = SaveVisRgn( hdc ))) return FALSE;
-    if (!(tmpVisRgn = CreateRectRgn32( 0, 0, 0, 0 )))
-    {
-        RestoreVisRgn( hdc );
-        return FALSE;
+      /* Transform region into device co-ords */
+    if (!REGION_LPTODP( hdc, tmpVisRgn, hrgn )) {
+        DeleteObject32( tmpVisRgn );
+	return FALSE;
     }
-    CombineRgn32( tmpVisRgn, prevVisRgn, hrgn, RGN_AND );
+
+      /* Modify visible region */
+    if (!(prevVisRgn = SaveVisRgn( hdc ))) {
+        DeleteObject32( tmpVisRgn );
+	return FALSE;
+    }
+    CombineRgn32( tmpVisRgn, prevVisRgn, tmpVisRgn, RGN_AND );
     SelectVisRgn( hdc, tmpVisRgn );
     DeleteObject32( tmpVisRgn );
 
diff --git a/if1632/relay.c b/if1632/relay.c
index 8e247ff..6e188bb 100644
--- a/if1632/relay.c
+++ b/if1632/relay.c
@@ -112,8 +112,25 @@
         case 't':
             args16 -= 4;
 	    printf( "0x%08x", *(int *)args16 );
-            if (HIWORD(*(int *)args16))
-                printf( " \"%s\"", (char *)PTR_SEG_TO_LIN(*(int *)args16) );
+            if (HIWORD(*(int *)args16)) {
+	    	LPBYTE s = (LPBYTE)PTR_SEG_TO_LIN(*(int*)args16);
+
+		/* filter out non printable chars, which would destroy output */
+		fputs(" \"",stdout);
+		while (*s) {
+			if (*s < ' ') {
+				printf( "\\0x%02x",*s++);
+				continue;
+			}
+			if (*s=='\\') {
+				fputs( "\\\\",stdout);
+				s++;
+				continue;
+			}
+			fputc(*s++,stdout);
+		}
+		fputs("\"",stdout);
+	    }
             break;
         case 'p':
             args16 -= 4;
@@ -122,8 +139,25 @@
         case 'T':
             args16 -= 4;
             printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
-            if (HIWORD(*(int *)args16))
-                printf( " \"%s\"", (char *)PTR_SEG_TO_LIN(*(int *)args16) );
+            if (HIWORD(*(int *)args16)) {
+	    	LPBYTE s = (LPBYTE)PTR_SEG_TO_LIN(*(int*)args16);
+
+		/* filter out non printable chars, which would destroy output */
+		fputs(" \"",stdout);
+		while (*s) {
+			if (*s < ' ') {
+				printf( "\\0x%02x",*s++);
+				continue;
+			}
+			if (*s=='\\') {
+				fputs( "\\\\",stdout);
+				s++;
+				continue;
+			}
+			fputc(*s++,stdout);
+		}
+		fputs("\"",stdout);
+	    }
             break;
         }
         args++;
@@ -209,10 +243,10 @@
     if (nb_args == -1)  /* Register function */
     {
         CONTEXT *context = (CONTEXT *)stack[0];
-        WORD *stack16 = (WORD *)CURRENT_STACK16 - 2 /* for saved %%esp */;
+        WORD *stack16 = (WORD *)CURRENT_STACK16;
         printf( "CallTo16(func=%04lx:%04x,ds=%04lx",
                 CS_reg(context), IP_reg(context), DS_reg(context) );
-        nb_args = -stack[1] / sizeof(WORD);
+        nb_args = stack[1] / sizeof(WORD);
         while (nb_args--) printf( ",0x%04x", *(--stack16) );
         printf( ")\n" );
         printf( "     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x\n",
@@ -268,13 +302,13 @@
 
     lpbuf[0] = IP_reg(context);
     lpbuf[1] = CS_reg(context);
-    lpbuf[2] = LOWORD(pFrame->saved_ss_sp);
+    lpbuf[2] = LOWORD(pFrame->frame32);
     lpbuf[3] = BP_reg(context);
     lpbuf[4] = SI_reg(context);
     lpbuf[5] = DI_reg(context);
     lpbuf[6] = DS_reg(context);
     lpbuf[7] = OFFSETOF(IF1632_Saved16_ss_sp);
-    lpbuf[8] = HIWORD(pFrame->saved_ss_sp);
+    lpbuf[8] = HIWORD(pFrame->frame32);
     AX_reg(context) = 0;  /* Return 0 */
 }
 
@@ -301,7 +335,7 @@
     IF1632_Saved16_ss_sp = MAKELONG( lpbuf[7] - sizeof(WORD),
                                      HIWORD(IF1632_Saved16_ss_sp) );
     pFrame = CURRENT_STACK16;
-    pFrame->saved_ss_sp = MAKELONG( lpbuf[2], lpbuf[8] );
+    pFrame->frame32 = MAKELONG( lpbuf[2], lpbuf[8] );
     IP_reg(context) = lpbuf[0];
     CS_reg(context) = lpbuf[1];
     BP_reg(context) = lpbuf[3];
@@ -375,6 +409,14 @@
 		break;
 	case 7:	ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
 		break;
+	case 8:	ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
+		break;
+	case 9:	ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
+		break;
+	case 10:	ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
+		break;
+	case 11:	ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
+		break;
 	default:
 		/* FIXME: should go up to 32  arguments */
 		fprintf(stderr,"CallProc32W: unsupported number of arguments %ld, please report.\n",nrofargs);
diff --git a/if1632/thunk.c b/if1632/thunk.c
index 5bb6eba..88b0281 100644
--- a/if1632/thunk.c
+++ b/if1632/thunk.c
@@ -240,15 +240,14 @@
 	}
     }
 
-    args = (WORD *)CURRENT_STACK16 - 7;
+    args = (WORD *)CURRENT_STACK16 - 5;
     args[0] = LOWORD(lParam);
     args[1] = HIWORD(lParam);
     args[2] = wParam;
     args[3] = msg;
     args[4] = hwnd;
-    /* args[5] and args[6] are used by relay code to store the stack pointer */
 
-    ret = CallTo16_sreg_( &context, -(5 * sizeof(WORD)) );
+    ret = CallTo16_sreg_( &context, 5 * sizeof(WORD) );
     if (offset) STACK16_POP(offset);
     return ret;
 }
diff --git a/include/acconfig.h b/include/acconfig.h
index 00d85cd..e7ec75b 100644
--- a/include/acconfig.h
+++ b/include/acconfig.h
@@ -5,3 +5,15 @@
 
 /* Define if symbols declared in assembly code need an underscore prefix */
 #undef NEED_UNDERSCORE_PREFIX
+
+/* Define to use .string instead of .ascii */
+#undef HAVE_ASM_STRING
+
+/* Define if union semun is defined in sys/sem.h */
+#undef HAVE_UNION_SEMUN
+
+/* Define if you have the Xxf86dga library (-lXxf86dga).  */
+#undef HAVE_LIBXXF86DGA
+
+/* Define if you have the Open Sound system.  */
+#undef HAVE_OSS
diff --git a/include/config.h.in b/include/config.h.in
index 40d489b..0f335ec 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -18,6 +18,18 @@
 /* Define if symbols declared in assembly code need an underscore prefix */
 #undef NEED_UNDERSCORE_PREFIX
 
+/* Define to use .string instead of .ascii */
+#undef HAVE_ASM_STRING
+
+/* Define if union semun is defined in sys/sem.h */
+#undef HAVE_UNION_SEMUN
+
+/* Define if you have the Xxf86dga library (-lXxf86dga).  */
+#undef HAVE_LIBXXF86DGA
+
+/* Define if you have the Open Sound system.  */
+#undef HAVE_OSS
+
 /* Define if you have the clone function.  */
 #undef HAVE_CLONE
 
@@ -42,9 +54,6 @@
 /* Define if you have the <wctype.h> header file.  */
 #undef HAVE_WCTYPE_H
 
-/* Define if you have the Xxf86dga library (-lXxf86dga).  */
-#undef HAVE_LIBXXF86DGA
-
 /* Define if you have the i386 library (-li386).  */
 #undef HAVE_LIBI386
 
diff --git a/include/ddraw.h b/include/ddraw.h
index 3197b85..26f72ac 100644
--- a/include/ddraw.h
+++ b/include/ddraw.h
@@ -20,6 +20,12 @@
 typedef struct IDirectDrawSurface IDirectDrawSurface,*LPDIRECTDRAWSURFACE;
 typedef struct IDirectDrawSurface2 IDirectDrawSurface2,*LPDIRECTDRAWSURFACE2;
 
+#define DDENUMRET_CANCEL	0
+#define DDENUMRET_OK		1
+
+#define DD_OK			0
+
+
 #define _FACDD		0x876
 #define MAKE_DDHRESULT( code )  MAKE_HRESULT( 1, _FACDD, code )
 
@@ -681,7 +687,7 @@
     STDMETHOD(Compact)(THIS) PURE;
     STDMETHOD(CreateClipper)(THIS_ DWORD, LPDIRECTDRAWCLIPPER FAR*, IUnknown FAR * ) PURE;
     STDMETHOD(CreatePalette)(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE FAR*, IUnknown FAR * ) PURE;
-    STDMETHOD(CreateSurface)(THIS_  LPDDSURFACEDESC *lpddsd, LPDIRECTDRAWSURFACE FAR *,
+    STDMETHOD(CreateSurface)(THIS_  LPDDSURFACEDESC, LPDIRECTDRAWSURFACE FAR *,
 IUnknown FAR *) PURE;
     STDMETHOD(DuplicateSurface)( THIS_ LPDIRECTDRAWSURFACE, LPDIRECTDRAWSURFACE
 FAR * ) PURE;
@@ -706,9 +712,10 @@
     DWORD			depth;
     DWORD			vp_width,vp_height; /* viewport dimension */
     DWORD			height,width;	/* SetDisplayMode */
-    DWORD			current_height,fb_width,fb_height,fb_banksize,fb_memsize;
+    DWORD			fb_width,fb_height,fb_banksize,fb_memsize;
     HWND32			mainwindow;
     void			*fb_addr;
+    unsigned int		vpmask;
 };
 
 
@@ -830,6 +837,7 @@
     LPDIRECTDRAWPALETTE	palette;
     DWORD		fb_height,lpitch,width,height;
     LPDIRECTDRAW	ddraw;
+    LPDIRECTDRAWSURFACE	backbuffer;
 };
 #undef THIS
 #define THIS LPDIRECTDRAWSURFACE2 this
@@ -885,6 +893,7 @@
     LPDIRECTDRAWPALETTE	palette;
     DWORD		fb_height,lpitch,width,height;
     LPDIRECTDRAW	ddraw;
+    LPDIRECTDRAWSURFACE	backbuffer;
 };
 #undef THIS
 
diff --git a/include/dsound.h b/include/dsound.h
index 61d042b..f4d6801 100644
--- a/include/dsound.h
+++ b/include/dsound.h
@@ -14,6 +14,25 @@
 typedef struct IDirectSound IDirectSound,*LPDIRECTSOUND;
 typedef struct IDirectSoundBuffer IDirectSoundBuffer,*LPDIRECTSOUNDBUFFER,**LPLPDIRECTSOUNDBUFFER;
 
+#define	_FACDS		0x878
+#define	MAKE_DSHRESULT(code)		MAKE_HRESULT(1,_FACDS,code)
+
+#define DSERR_ALLOCATED			MAKE_DSHRESULT(10)
+#define DSERR_CONTROLUNAVAIL		MAKE_DSHRESULT(30)
+#define DSERR_INVALIDPARAM		E_INVALIDARG
+#define DSERR_INVALIDCALL		MAKE_DSHRESULT(50)
+#define DSERR_GENERIC			E_FAIL
+#define DSERR_PRIOLEVELNEEDED		MAKE_DSHRESULT(70)
+#define DSERR_OUTOFMEMORY		E_OUTOFMEMORY
+#define DSERR_BADFORMAT			MAKE_DSHRESULT(100)
+#define DSERR_UNSUPPORTED		E_NOTIMPL
+#define DSERR_NODRIVER			MAKE_DSHRESULT(120)
+#define DSERR_ALREADYINITIALIZED	MAKE_DSHRESULT(130)
+#define DSERR_NOAGGREGATION		CLASS_E_NOAGGREGATION
+#define DSERR_BUFFERLOST		MAKE_DSHRESULT(150)
+#define DSERR_OTHERAPPHASPRIO		MAKE_DSHRESULT(160)
+#define DSERR_UNINITIALIZED		MAKE_DSHRESULT(170)
+
 #define DSCAPS_PRIMARYMONO          0x00000001
 #define DSCAPS_PRIMARYSTEREO        0x00000002
 #define DSCAPS_PRIMARY8BIT          0x00000004
@@ -26,6 +45,11 @@
 #define DSCAPS_SECONDARY8BIT        0x00000400
 #define DSCAPS_SECONDARY16BIT       0x00000800
 
+#define	DSSCL_NORMAL		1
+#define	DSSCL_PRIORITY		2
+#define	DSSCL_EXCLUSIVE		3
+#define	DSSCL_WRITEPRIMARY	4
+
 typedef struct _DSCAPS
 {
     DWORD	dwSize;
@@ -145,6 +169,8 @@
 struct IDirectSound {
 	LPDIRECTSOUND_VTABLE	lpvtbl;
 	DWORD			ref;
+	int			nrofbuffers;
+	LPDIRECTSOUNDBUFFER	*buffers;
 };
 
 #undef THIS
@@ -181,7 +207,11 @@
 
 struct IDirectSoundBuffer {
 	LPDIRECTSOUNDBUFFER_VTABLE	lpvtbl;
+	WAVEFORMATEX			wfx;
 	DWORD				ref;
+	LPBYTE				buffer;
+	DWORD				playing,playpos,writepos,buflen;
+	LPDIRECTSOUND			dsound;
 };
 
 #endif
diff --git a/include/k32obj.h b/include/k32obj.h
index afe3c94..5ac2a5e 100644
--- a/include/k32obj.h
+++ b/include/k32obj.h
@@ -44,7 +44,7 @@
 typedef struct
 {
     BOOL32 (*signaled)(K32OBJ*,DWORD);    /* Is object signaled? */
-    void   (*satisfied)(K32OBJ*,DWORD);   /* Wait on object is satisfied */
+    BOOL32 (*satisfied)(K32OBJ*,DWORD);   /* Wait on object is satisfied */
     void   (*add_wait)(K32OBJ*,DWORD);    /* Add thread to wait queue */
     void   (*remove_wait)(K32OBJ*,DWORD); /* Remove thread from wait queue */
     void   (*destroy)(K32OBJ *);          /* Destroy object on refcount==0 */
diff --git a/include/metafile.h b/include/metafile.h
index b511fce..c674718 100644
--- a/include/metafile.h
+++ b/include/metafile.h
@@ -36,6 +36,6 @@
 BOOL32 MF_StretchBlt(DC *dcDest, short xDest, short yDest, short widthDest,
 		   short heightDest, DC *dcSrc, short xSrc, short ySrc, 
 		   short widthSrc, short heightSrc, DWORD rop);
-
+INT16 MF_CreateRegion(DC *dc, HRGN32 hrgn);
 #endif   /* __WINE_METAFILE_H */
 
diff --git a/include/metafiledrv.h b/include/metafiledrv.h
index a8e67a9..e89d091 100644
--- a/include/metafiledrv.h
+++ b/include/metafiledrv.h
@@ -72,5 +72,6 @@
 extern BOOL32 MFDRV_ExtTextOut( struct tagDC *dc, INT32 x, INT32 y,
 				UINT32 flags, const RECT32 *lprect, LPCSTR str,
 				UINT32 count, const INT32 *lpDx );
+extern BOOL32 MFDRV_PaintRgn( DC *dc, HRGN32 hrgn );
 
 #endif  /* __WINE_METAFILEDRV_H */
diff --git a/include/options.h b/include/options.h
index c68158e..784614c 100644
--- a/include/options.h
+++ b/include/options.h
@@ -59,7 +59,6 @@
 			       if write access is requested */
     WINE_MODE mode;         /* Start Wine in selected mode
 			       (standard/enhanced) */
-    int    ipc;             /* Use IPC mechanisms */
     WINE_LANGUAGE language; /* Current language */
     int    managed;	    /* Managed windows */
     int    perfectGraphics; /* Favor correctness over speed for graphics */
diff --git a/include/process.h b/include/process.h
index ca0014f..21893db 100644
--- a/include/process.h
+++ b/include/process.h
@@ -98,20 +98,12 @@
     LCID             locale;           /* c4 Locale to be queried by GetThreadLocale (NT) */
 } PDB32;
 
-/* PDB <-> Process id conversion macros */
-#define PROCESS_OBFUSCATOR     ((DWORD)0xdeadbeef)
-#define PROCESS_ID_TO_PDB(id)  ((PDB32 *)((id) ^ PROCESS_OBFUSCATOR))
-#define PDB_TO_PROCESS_ID(pdb) ((DWORD)(pdb) ^ PROCESS_OBFUSCATOR)
-
 /* scheduler/process.c */
+extern PDB32 *PROCESS_Current(void);
+extern PDB32 *PROCESS_IdToPDB( DWORD id );
 extern HANDLE32 PROCESS_AllocHandle( K32OBJ *ptr, DWORD flags);
 extern K32OBJ *PROCESS_GetObjPtr( HANDLE32 handle, K32OBJ_TYPE type );
 extern BOOL32 PROCESS_SetObjPtr( HANDLE32 handle, K32OBJ *ptr, DWORD flags );
 extern PDB32 *PROCESS_Create( TDB *pTask, LPCSTR cmd_line );
-extern PDB32 *pCurrentProcess;
-
-/* scheduler/event.c */
-extern void EVENT_Set( K32OBJ *obj );
-extern K32OBJ *EVENT_Create( BOOL32 manual_reset, BOOL32 initial_state );
 
 #endif  /* __WINE_PROCESS_H */
diff --git a/include/region.h b/include/region.h
index d53546a..263379b 100644
--- a/include/region.h
+++ b/include/region.h
@@ -1,25 +1,394 @@
 /*
  * GDI region definitions
- *
- * Copyright 1994 Alexandre Julliard
+ * Mainly taken from the X11 distribution.
+ * Modifications: Copyright 1998 Huw Davies
  */
 
+/************************************************************************
+
+Copyright (c) 1987  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
 #ifndef __WINE_REGION_H
 #define __WINE_REGION_H
 
+#include "windows.h"
 #include "gdi.h"
 
+
+typedef struct {
+    INT32 size;
+    INT32 numRects;
+    INT32 type; /* NULL, SIMPLE or COMPLEX */
+    RECT32 *rects;
+    RECT32 extents;
+} WINEREGION;
+
   /* GDI logical region object */
 typedef struct
 {
     GDIOBJHDR   header;
-    Region      xrgn;
+    WINEREGION  *rgn;
 } RGNOBJ;
 
+/*  1 if two RECTs overlap.
+ *  0 if two RECTs do not overlap.
+ */
+#define EXTENTCHECK(r1, r2) \
+	((r1)->right > (r2)->left && \
+	 (r1)->left < (r2)->right && \
+	 (r1)->bottom > (r2)->top && \
+	 (r1)->top < (r2)->bottom)
+
+/*
+ *   Check to see if there is enough memory in the present region.
+ */
+#define MEMCHECK(reg, rect, firstrect){\
+        if ((reg)->numRects >= ((reg)->size - 1)){\
+          (firstrect) = HeapReAlloc( SystemHeap, 0, \
+           (firstrect), (2 * (sizeof(RECT32)) * ((reg)->size)));\
+          if ((firstrect) == 0)\
+            return;\
+          (reg)->size *= 2;\
+          (rect) = &(firstrect)[(reg)->numRects];\
+         }\
+       }
+
+#define EMPTY_REGION(pReg) { \
+    (pReg)->numRects = 0; \
+    (pReg)->extents.left = (pReg)->extents.top = 0; \
+    (pReg)->extents.right = (pReg)->extents.bottom = 0; \
+    (pReg)->type = NULLREGION; \
+ }
+
+#define REGION_NOT_EMPTY(pReg) pReg->numRects
+
+#define INRECT(r, x, y) \
+      ( ( ((r).right >  x)) && \
+        ( ((r).left <= x)) && \
+        ( ((r).bottom >  y)) && \
+        ( ((r).top <= y)) )
+
+
+/*
+ * number of points to buffer before sending them off
+ * to scanlines() :  Must be an even number
+ */
+#define NUMPTSTOBUFFER 200
+
+/*
+ * used to allocate buffers for points and link
+ * the buffers together
+ */
+
+typedef struct _POINTBLOCK {
+    POINT32 pts[NUMPTSTOBUFFER];
+    struct _POINTBLOCK *next;
+} POINTBLOCK;
+
+
+
+/*
+ *     This file contains a few macros to help track
+ *     the edge of a filled object.  The object is assumed
+ *     to be filled in scanline order, and thus the
+ *     algorithm used is an extension of Bresenham's line
+ *     drawing algorithm which assumes that y is always the
+ *     major axis.
+ *     Since these pieces of code are the same for any filled shape,
+ *     it is more convenient to gather the library in one
+ *     place, but since these pieces of code are also in
+ *     the inner loops of output primitives, procedure call
+ *     overhead is out of the question.
+ *     See the author for a derivation if needed.
+ */
+
+
+/*
+ *  In scan converting polygons, we want to choose those pixels
+ *  which are inside the polygon.  Thus, we add .5 to the starting
+ *  x coordinate for both left and right edges.  Now we choose the
+ *  first pixel which is inside the pgon for the left edge and the
+ *  first pixel which is outside the pgon for the right edge.
+ *  Draw the left pixel, but not the right.
+ *
+ *  How to add .5 to the starting x coordinate:
+ *      If the edge is moving to the right, then subtract dy from the
+ *  error term from the general form of the algorithm.
+ *      If the edge is moving to the left, then add dy to the error term.
+ *
+ *  The reason for the difference between edges moving to the left
+ *  and edges moving to the right is simple:  If an edge is moving
+ *  to the right, then we want the algorithm to flip immediately.
+ *  If it is moving to the left, then we don't want it to flip until
+ *  we traverse an entire pixel.
+ */
+#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
+    int dx;      /* local storage */ \
+\
+    /* \
+     *  if the edge is horizontal, then it is ignored \
+     *  and assumed not to be processed.  Otherwise, do this stuff. \
+     */ \
+    if ((dy) != 0) { \
+        xStart = (x1); \
+        dx = (x2) - xStart; \
+        if (dx < 0) { \
+            m = dx / (dy); \
+            m1 = m - 1; \
+            incr1 = -2 * dx + 2 * (dy) * m1; \
+            incr2 = -2 * dx + 2 * (dy) * m; \
+            d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
+        } else { \
+            m = dx / (dy); \
+            m1 = m + 1; \
+            incr1 = 2 * dx - 2 * (dy) * m1; \
+            incr2 = 2 * dx - 2 * (dy) * m; \
+            d = -2 * m * (dy) + 2 * dx; \
+        } \
+    } \
+}
+
+#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
+    if (m1 > 0) { \
+        if (d > 0) { \
+            minval += m1; \
+            d += incr1; \
+        } \
+        else { \
+            minval += m; \
+            d += incr2; \
+        } \
+    } else {\
+        if (d >= 0) { \
+            minval += m1; \
+            d += incr1; \
+        } \
+        else { \
+            minval += m; \
+            d += incr2; \
+        } \
+    } \
+}
+
+/*
+ *     This structure contains all of the information needed
+ *     to run the bresenham algorithm.
+ *     The variables may be hardcoded into the declarations
+ *     instead of using this structure to make use of
+ *     register declarations.
+ */
+typedef struct {
+    INT32 minor_axis;	/* minor axis        */
+    INT32 d;		/* decision variable */
+    INT32 m, m1;       	/* slope and slope+1 */
+    INT32 incr1, incr2;	/* error increments */
+} BRESINFO;
+
+
+#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
+	BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
+                     bres.m, bres.m1, bres.incr1, bres.incr2)
+
+#define BRESINCRPGONSTRUCT(bres) \
+        BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
+
+
+
+/*
+ *     These are the data structures needed to scan
+ *     convert regions.  Two different scan conversion
+ *     methods are available -- the even-odd method, and
+ *     the winding number method.
+ *     The even-odd rule states that a point is inside
+ *     the polygon if a ray drawn from that point in any
+ *     direction will pass through an odd number of
+ *     path segments.
+ *     By the winding number rule, a point is decided
+ *     to be inside the polygon if a ray drawn from that
+ *     point in any direction passes through a different
+ *     number of clockwise and counter-clockwise path
+ *     segments.
+ *
+ *     These data structures are adapted somewhat from
+ *     the algorithm in (Foley/Van Dam) for scan converting
+ *     polygons.
+ *     The basic algorithm is to start at the top (smallest y)
+ *     of the polygon, stepping down to the bottom of
+ *     the polygon by incrementing the y coordinate.  We
+ *     keep a list of edges which the current scanline crosses,
+ *     sorted by x.  This list is called the Active Edge Table (AET)
+ *     As we change the y-coordinate, we update each entry in 
+ *     in the active edge table to reflect the edges new xcoord.
+ *     This list must be sorted at each scanline in case
+ *     two edges intersect.
+ *     We also keep a data structure known as the Edge Table (ET),
+ *     which keeps track of all the edges which the current
+ *     scanline has not yet reached.  The ET is basically a
+ *     list of ScanLineList structures containing a list of
+ *     edges which are entered at a given scanline.  There is one
+ *     ScanLineList per scanline at which an edge is entered.
+ *     When we enter a new edge, we move it from the ET to the AET.
+ *
+ *     From the AET, we can implement the even-odd rule as in
+ *     (Foley/Van Dam).
+ *     The winding number rule is a little trickier.  We also
+ *     keep the EdgeTableEntries in the AET linked by the
+ *     nextWETE (winding EdgeTableEntry) link.  This allows
+ *     the edges to be linked just as before for updating
+ *     purposes, but only uses the edges linked by the nextWETE
+ *     link as edges representing spans of the polygon to
+ *     drawn (as with the even-odd rule).
+ */
+
+/*
+ * for the winding number rule
+ */
+#define CLOCKWISE          1
+#define COUNTERCLOCKWISE  -1 
+
+typedef struct _EdgeTableEntry {
+     INT32 ymax;           /* ycoord at which we exit this edge. */
+     BRESINFO bres;        /* Bresenham info to run the edge     */
+     struct _EdgeTableEntry *next;       /* next in the list     */
+     struct _EdgeTableEntry *back;       /* for insertion sort   */
+     struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
+     int ClockWise;        /* flag for winding number rule       */
+} EdgeTableEntry;
+
+
+typedef struct _ScanLineList{
+     INT32 scanline;            /* the scanline represented */
+     EdgeTableEntry *edgelist;  /* header node              */
+     struct _ScanLineList *next;  /* next in the list       */
+} ScanLineList;
+
+
+typedef struct {
+     INT32 ymax;               /* ymax for the polygon     */
+     INT32 ymin;               /* ymin for the polygon     */
+     ScanLineList scanlines;   /* header node              */
+} EdgeTable;
+
+
+/*
+ * Here is a struct to help with storage allocation
+ * so we can allocate a big chunk at a time, and then take
+ * pieces from this heap when we need to.
+ */
+#define SLLSPERBLOCK 25
+
+typedef struct _ScanLineListBlock {
+     ScanLineList SLLs[SLLSPERBLOCK];
+     struct _ScanLineListBlock *next;
+} ScanLineListBlock;
+
+
+/*
+ *
+ *     a few macros for the inner loops of the fill code where
+ *     performance considerations don't allow a procedure call.
+ *
+ *     Evaluate the given edge at the given scanline.
+ *     If the edge has expired, then we leave it and fix up
+ *     the active edge table; otherwise, we increment the
+ *     x value to be ready for the next scanline.
+ *     The winding number rule is in effect, so we must notify
+ *     the caller when the edge has been removed so he
+ *     can reorder the Winding Active Edge Table.
+ */
+#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
+   if (pAET->ymax == y) {          /* leaving this edge */ \
+      pPrevAET->next = pAET->next; \
+      pAET = pPrevAET->next; \
+      fixWAET = 1; \
+      if (pAET) \
+         pAET->back = pPrevAET; \
+   } \
+   else { \
+      BRESINCRPGONSTRUCT(pAET->bres); \
+      pPrevAET = pAET; \
+      pAET = pAET->next; \
+   } \
+}
+
+
+/*
+ *     Evaluate the given edge at the given scanline.
+ *     If the edge has expired, then we leave it and fix up
+ *     the active edge table; otherwise, we increment the
+ *     x value to be ready for the next scanline.
+ *     The even-odd rule is in effect.
+ */
+#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
+   if (pAET->ymax == y) {          /* leaving this edge */ \
+      pPrevAET->next = pAET->next; \
+      pAET = pPrevAET->next; \
+      if (pAET) \
+         pAET->back = pPrevAET; \
+   } \
+   else { \
+      BRESINCRPGONSTRUCT(pAET->bres); \
+      pPrevAET = pAET; \
+      pAET = pAET->next; \
+   } \
+}
 
 extern BOOL32 REGION_DeleteObject( HRGN32 hrgn, RGNOBJ * obj );
 extern BOOL32 REGION_UnionRectWithRgn( HRGN32 hrgn, const RECT32 *lpRect );
 extern BOOL32 REGION_FrameRgn( HRGN32 dest, HRGN32 src, INT32 x, INT32 y );
-extern BOOL32 REGION_IsEmpty( HRGN32 rgn );
+extern BOOL32 REGION_LPTODP( HDC32 hdc, HRGN32 hDest, HRGN32 hSrc );
 
 #endif  /* __WINE_REGION_H */
+
+
+
+
+
+
+
+
+
+
diff --git a/include/stackframe.h b/include/stackframe.h
index e1cfa77..1435bbb 100644
--- a/include/stackframe.h
+++ b/include/stackframe.h
@@ -13,36 +13,37 @@
 
 #pragma pack(1)
 
+  /* 32-bit stack layout after CallTo16() */
+typedef struct _STACK32FRAME
+{
+    SEGPTR  frame16;        /* 00 16-bit frame from last CallFrom16() */
+    DWORD   edi;            /* 04 saved registers */
+    DWORD   esi;            /* 08 */
+    DWORD   edx;            /* 0c */
+    DWORD   ecx;            /* 10 */
+    DWORD   ebx;            /* 14 */
+    DWORD   restore_addr;   /* 18 return address for restoring code selector */
+    DWORD   codeselector;   /* 1c code selector to restore */
+    DWORD   ebp;            /* 20 saved 32-bit frame pointer */
+    DWORD   retaddr;        /* 24 actual return address */
+    DWORD   args[1];        /* 28 arguments to 16-bit function */
+} STACK32FRAME;
+
   /* 16-bit stack layout after CallFrom16() */
 typedef struct
 {
-    DWORD   saved_ss_sp;    /* 00 saved previous 16-bit stack */
-    DWORD   ebp;            /* 04 full 32-bit content of ebp */
-    WORD    entry_ip;       /* 08 ip of entry point */
-    WORD    ds;             /* 0a ds */
-    WORD    entry_cs;       /* 0c cs of entry point */
-    WORD    es;             /* 0e es */
-    DWORD   entry_point;    /* 10 32-bit entry point to call */
-    WORD    bp;             /* 14 16-bit bp */
-    WORD    ip;             /* 16 return address */
-    WORD    cs;             /* 18 */
+    STACK32FRAME *frame32;        /* 00 32-bit frame from last CallTo16() */
+    DWORD         ebp;            /* 04 full 32-bit content of ebp */
+    WORD          entry_ip;       /* 08 ip of entry point */
+    WORD          ds;             /* 0a ds */
+    WORD          entry_cs;       /* 0c cs of entry point */
+    WORD          es;             /* 0e es */
+    DWORD         entry_point;    /* 10 32-bit entry point to call */
+    WORD          bp;             /* 14 16-bit bp */
+    WORD          ip;             /* 16 return address */
+    WORD          cs;             /* 18 */
 } STACK16FRAME;
 
-  /* 32-bit stack layout after CallTo16() */
-typedef struct
-{
-    DWORD   edi;            /* 00 saved registers */
-    DWORD   esi;            /* 04 */
-    DWORD   edx;            /* 08 */
-    DWORD   ecx;            /* 0c */
-    DWORD   ebx;            /* 10 */
-    DWORD   restore_addr;   /* 14 return address for restoring code selector */
-    DWORD   codeselector;   /* 18 code selector to restore */
-    DWORD   ebp;            /* 1c saved 32-bit frame pointer */
-    DWORD   retaddr;        /* 20 actual return address */
-    DWORD   args[1];        /* 24 arguments to 16-bit function */
-} STACK32FRAME;
-
 #pragma pack(4)
 
   /* Saved 16-bit stack for current process (Win16 only) */
diff --git a/include/thread.h b/include/thread.h
index 4e9b61f..361d165 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -55,9 +55,9 @@
     DWORD          exit_code;      /*  48 Termination status */
     WORD           teb_sel;        /*  4c Selector to TEB */
     WORD           emu_sel;        /*  4e 80387 emulator selector */
-    DWORD          unknown1;       /*  50 Unknown */
+    int            thread_errno;   /*  50 Per-thread errno (was: unknown) */
     WAIT_STRUCT   *wait_list;      /*  54 Event waiting list */
-    DWORD          unknown2;       /*  58 Unknown */
+    int            thread_h_errno; /*  50 Per-thread h_errno (was: unknown) */
     void          *ring0_thread;   /*  5c Pointer to ring 0 thread */
     void          *ptdbx;          /*  60 Pointer to TDBX structure */
     void          *stack_base;     /*  64 Base of the stack */
@@ -86,7 +86,8 @@
     K32OBJ        *win16_mutex;    /* 1e8 Pointer to Win16 mutex */
     K32OBJ        *win32_mutex;    /* 1ec Pointer to KERNEL32 mutex */
     K32OBJ        *crit_section2;  /* 1f0 Another critical section */
-    DWORD          unknown6[3];    /* 1f4 Unknown */
+    K32OBJ        *mutex_list;     /* 1f4 List of owned mutex (was: unknown)*/
+    DWORD          unknown6[2];    /* 1f8 Unknown */
     /* The following are Wine-specific fields */
     CONTEXT        context;        /* 200 Thread context */
     WAIT_STRUCT    wait_struct;    /*     Event wait structure */
@@ -124,8 +125,20 @@
 extern void THREAD_AddQueue( THREAD_QUEUE *queue, THDB *thread );
 extern void THREAD_RemoveQueue( THREAD_QUEUE *queue, THDB *thread );
 
+/* scheduler/event.c */
+extern void EVENT_Set( K32OBJ *obj );
+extern K32OBJ *EVENT_Create( BOOL32 manual_reset, BOOL32 initial_state );
+
+/* scheduler/mutex.c */
+extern void MUTEX_Abandon( K32OBJ *obj );
+
 /* scheduler/synchro.c */
 extern void SYNC_WaitForCondition( WAIT_STRUCT *wait, DWORD timeout );
 extern void SYNC_WakeUp( THREAD_QUEUE *queue, DWORD max );
 
+/* scheduler/sysdeps.c */
+extern int SYSDEPS_SpawnThread( THDB *thread );
+extern void SYSDEPS_ExitThread(void);
+extern TEB * WINAPI NtCurrentTeb(void);
+
 #endif  /* __WINE_THREAD_H */
diff --git a/include/version.h b/include/version.h
index bb64ee6..686a913 100644
--- a/include/version.h
+++ b/include/version.h
@@ -1 +1 @@
-#define WINE_RELEASE_INFO "Wine release 980104"
+#define WINE_RELEASE_INFO "Wine release 980118"
diff --git a/include/windows.h b/include/windows.h
index d9fe47d..43a00b8 100644
--- a/include/windows.h
+++ b/include/windows.h
@@ -5689,6 +5689,7 @@
 DWORD       WINAPI ExpandEnvironmentStrings32A(LPCSTR,LPSTR,DWORD);
 DWORD       WINAPI ExpandEnvironmentStrings32W(LPCWSTR,LPWSTR,DWORD);
 #define     ExpandEnvironmentStrings WINELIB_NAME_AW(ExpandEnvironmentStrings)
+HRGN32      WINAPI ExtCreateRegion(LPXFORM,DWORD,LPRGNDATA);
 BOOL32      WINAPI FileTimeToDosDateTime(const FILETIME*,LPWORD,LPWORD);
 BOOL32      WINAPI FileTimeToLocalFileTime(const FILETIME*,LPFILETIME);
 BOOL32      WINAPI FileTimeToSystemTime(const FILETIME*,LPSYSTEMTIME);
@@ -5752,6 +5753,7 @@
 INT32       WINAPI GetPrivateProfileSection32W(LPCWSTR,LPWSTR,INT32,LPCWSTR);
 #define     GetPrivateProfileSection WINELIB_NAME_AW(GetPrivateProfileSection)
 HANDLE32    WINAPI GetProcessHeap(void);
+DWORD       WINAPI GetRegionData(HRGN32,DWORD,LPRGNDATA);
 DWORD       WINAPI GetShortPathName32A(LPCSTR,LPSTR,DWORD);
 DWORD       WINAPI GetShortPathName32W(LPCWSTR,LPWSTR,DWORD);
 #define     GetShortPathName WINELIB_NAME_AW(GetShortPathName)
diff --git a/loader/main.c b/loader/main.c
index b596be2..767eb10 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -48,6 +48,7 @@
 BOOL32 MAIN_KernelInit(void)
 {
     extern BOOL32 EVENT_Init(void);
+    extern BOOL32 PROCESS_Init(void);
     extern BOOL32 VIRTUAL_Init(void);
 
     /* Initialize virtual memory management */
@@ -57,15 +58,18 @@
     if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
     if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
 
+    /* Create the initial process */
+    if (!PROCESS_Init()) return FALSE;
+
+    /* Initialize signal handling */
+    if (!SIGNAL_Init()) return FALSE;
+
     /* Load the configuration file */
     if (!PROFILE_LoadWineIni()) return FALSE;
 
       /* Initialize DOS memory */
     if (!DOSMEM_Init()) return FALSE;
 
-      /* Initialize signal handling */
-    if (!SIGNAL_Init()) return FALSE;
-
     /* Initialise DOS drives */
     if (!DRIVE_Init()) return FALSE;
 
diff --git a/loader/module.c b/loader/module.c
index 6cea6c5..831a001 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -1437,7 +1437,7 @@
 	hmod = PE_LoadLibraryEx32A(buffer,hfile,flags);
     }
     /* initialize all DLLs, which haven't been initialized yet. */
-    PE_InitializeDLLs( pCurrentProcess, DLL_PROCESS_ATTACH, NULL);
+    PE_InitializeDLLs( PROCESS_Current(), DLL_PROCESS_ATTACH, NULL);
     return hmod;
 }
 
diff --git a/loader/ne_image.c b/loader/ne_image.c
index 98a8a9c..14278c8 100644
--- a/loader/ne_image.c
+++ b/loader/ne_image.c
@@ -78,7 +78,7 @@
  	IF1632_Saved16_ss_sp = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
                                                  0xff00 - sizeof(*stack16Top));
         stack16Top = CURRENT_STACK16;
-        stack16Top->saved_ss_sp = 0;
+        stack16Top->frame32 = 0;
         stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
         stack16Top->entry_point = 0;
         stack16Top->entry_ip = 0;
@@ -386,7 +386,7 @@
         IF1632_Saved16_ss_sp = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
                                                 0xff00 - sizeof(*stack16Top) );
         stack16Top = CURRENT_STACK16;
-        stack16Top->saved_ss_sp = 0;
+        stack16Top->frame32 = 0;
         stack16Top->ebp = 0;
         stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
         stack16Top->entry_point = 0;
diff --git a/loader/pe_image.c b/loader/pe_image.c
index 043404d..e3f31d4 100644
--- a/loader/pe_image.c
+++ b/loader/pe_image.c
@@ -97,7 +97,7 @@
 	u_long				* function;
 	u_char				** name, *ename;
 	int				i;
-	PDB32				*process=pCurrentProcess;
+	PDB32				*process=PROCESS_Current();
 	PE_MODREF			*pem;
 	u_long				rva_start, rva_end, addr;
 	char				* forward;
@@ -690,14 +690,14 @@
 		if (!HIWORD(hModule)) /* internal (or bad) */
 			return hModule;
 		/* check if this module is already mapped */
-		pem 	= pCurrentProcess->modref_list;
+		pem 	= PROCESS_Current()->modref_list;
 		while (pem) {
 			if (pem->module == hModule) return hModule;
 			pem = pem->next;
 		}
 		pModule = MODULE_GetPtr(hModule);
 		if (pModule->flags & NE_FFLAGS_BUILTIN) {
-			PDB32	*process = pCurrentProcess;
+			PDB32	*process = PROCESS_Current();
 			IMAGE_DOS_HEADER	*dh;
 			IMAGE_NT_HEADERS	*nh;
 			IMAGE_SECTION_HEADER	*sh;
@@ -743,7 +743,7 @@
 		if (pModule->module32 < 32) return 21;
 	}
 	/* recurse */
-	pModule->module32 = PE_MapImage( pModule->module32, pCurrentProcess,
+	pModule->module32 = PE_MapImage( pModule->module32, PROCESS_Current(),
                                          &ofs,flags);
 	return pModule->module32;
 }
@@ -776,7 +776,7 @@
                          (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
                          *((WORD*)PTR_SEG_TO_LIN(params->showCmd) + 1) );
     }
-    pModule->module32 = PE_MapImage( hModule32, pCurrentProcess, ofs, 0 );
+    pModule->module32 = PE_MapImage( hModule32, PROCESS_Current(), ofs, 0 );
     return hInstance;
 }
 
@@ -875,7 +875,7 @@
  */
 BOOL32 WINAPI DisableThreadLibraryCalls(HMODULE32 hModule)
 {
-	PDB32	*process = pCurrentProcess;
+	PDB32	*process = PROCESS_Current();
 	PE_MODREF	*pem = process->modref_list;
 
 	while (pem) {
diff --git a/loader/pe_resource.c b/loader/pe_resource.c
index 4e4098c..60fa5b8 100644
--- a/loader/pe_resource.c
+++ b/loader/pe_resource.c
@@ -33,7 +33,7 @@
 static PE_MODREF*
 HMODULE32toPE_MODREF(HMODULE32 hmod) {
 	NE_MODULE	*pModule;
-	PDB32		*pdb = pCurrentProcess;
+	PDB32		*pdb = PROCESS_Current();
 	PE_MODREF	*pem;
 
 	if (!hmod) hmod = GetTaskDS(); /* FIXME: correct? */
diff --git a/loader/task.c b/loader/task.c
index 110a799..7c31fae 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -56,7 +56,7 @@
 static HGLOBAL16 TASK_CreateDOSEnvironment(void);
 static void	 TASK_YieldToSystem(TDB*);
 
-static THDB TASK_SystemTHDB;
+
 /***********************************************************************
  *           TASK_Init
  */
@@ -64,8 +64,6 @@
 {
     if (!(hDOSEnvironment = TASK_CreateDOSEnvironment()))
         fprintf( stderr, "Not enough memory for DOS Environment\n" );
-    TASK_SystemTHDB.teb_sel = SELECTOR_AllocBlock( &TASK_SystemTHDB, 0x1000, SEGMENT_DATA, TRUE, FALSE );
-    SET_FS( TASK_SystemTHDB.teb_sel );
     return (hDOSEnvironment != 0);
 }
 
@@ -340,6 +338,8 @@
     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
 
     IF1632_Saved16_ss_sp = pTask->ss_sp;
+    /* Terminate the stack frame */
+    CURRENT_STACK16->frame32 = NULL;
     SET_CUR_THREAD( pTask->thdb );
     if (pModule->flags & NE_FFLAGS_WIN32)
     {
@@ -347,11 +347,11 @@
 
         extern void InitTask( CONTEXT *context );
 
-        FARPROC32 entry = (FARPROC32)RVA_PTR( pCurrentProcess->exe_modref->module, OptionalHeader.AddressOfEntryPoint );
+        FARPROC32 entry = (FARPROC32)RVA_PTR( PROCESS_Current()->exe_modref->module, OptionalHeader.AddressOfEntryPoint );
 
         InitTask( NULL );
         InitApp( pTask->hModule );
-        PE_InitializeDLLs( pCurrentProcess, DLL_PROCESS_ATTACH, (LPVOID)-1 );
+        PE_InitializeDLLs( PROCESS_Current(), DLL_PROCESS_ATTACH, (LPVOID)-1 );
         dprintf_relay( stddeb, "CallTo32(entryproc=%p)\n", entry );
         exit_code = entry();
         TASK_KillCurrentTask( exit_code );
@@ -514,7 +514,7 @@
 
     /* Create the Win32 part of the task */
 
-    pCurrentProcess = pdb32 = PROCESS_Create( pTask, cmdLine );
+    pdb32 = PROCESS_Create( pTask, cmdLine );
     /* FIXME: check for pdb32 == NULL.  */
     pdb32->task = hTask;
     if (pModule->flags & NE_FFLAGS_WIN32)
@@ -522,8 +522,8 @@
     /*
         LPTHREAD_START_ROUTINE start =
             (LPTHREAD_START_ROUTINE)(
-	    	pCurrentProcess->exe_modref->load_addr +
-		pCurrentProcess->exe_modref->pe_module->pe_header->OptionalHeader.AddressOfEntryPoint);
+	    	PROCESS_Current()->exe_modref->load_addr +
+		PROCESS_Current()->exe_modref->pe_module->pe_header->OptionalHeader.AddressOfEntryPoint);
      */
         pTask->thdb = THREAD_Create( pdb32,
           PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve,
@@ -541,11 +541,11 @@
 
     stack32Top = (char*)pTask->thdb->teb.stack_top;
     frame32 = (STACK32FRAME *)stack32Top - 1;
-    frame32->edi = 0;
-    frame32->esi = 0;
-    frame32->edx = 0;
-    frame32->ecx = 0;
-    frame32->ebx = 0;
+    frame32->edi     = 0;
+    frame32->esi     = 0;
+    frame32->edx     = 0;
+    frame32->ecx     = 0;
+    frame32->ebx     = 0;
     frame32->retaddr = (DWORD)TASK_CallToStart;
     /* The remaining fields will be initialized in TASK_Reschedule */
 
@@ -555,9 +555,9 @@
         sp = pSegTable[pModule->ss-1].minsize + pModule->stack_size;
     sp &= ~1;
     pTask->ss_sp = PTR_SEG_OFF_TO_SEGPTR( hInstance, sp );
-    pTask->ss_sp -= sizeof(STACK16FRAME) + sizeof(DWORD) /* for saved %esp */;
+    pTask->ss_sp -= sizeof(STACK16FRAME);
     frame16 = (STACK16FRAME *)PTR_SEG_TO_LIN( pTask->ss_sp );
-    frame16->saved_ss_sp = 0;
+    frame16->frame32 = frame32;
     frame16->ebp = sp + (int)&((STACK16FRAME *)0)->bp;
     frame16->bp = LOWORD(frame16->ebp);
     frame16->ds = frame16->es = pTask->hInstance;
@@ -565,8 +565,6 @@
     frame16->entry_cs = 0;
     /* The remaining fields will be initialized in TASK_Reschedule */
 
-    *(STACK32FRAME **)(frame16 + 1) = frame32; /* Store the 32-bit %esp */
-
       /* If there's no 16-bit stack yet, use a part of the new task stack */
       /* This is only needed to have a stack to switch from on the first  */
       /* call to DirectedYield(). */
@@ -775,8 +773,8 @@
     if (!newframe16->entry_cs)
     {
         STACK16FRAME *oldframe16 = CURRENT_STACK16;
-        STACK32FRAME *oldframe32 = *(STACK32FRAME **)(oldframe16 + 1);
-        STACK32FRAME *newframe32 = *(STACK32FRAME **)(newframe16 + 1);
+        STACK32FRAME *oldframe32 = oldframe16->frame32;
+        STACK32FRAME *newframe32 = newframe16->frame32;
         newframe16->entry_ip     = oldframe16->entry_ip;
         newframe16->entry_cs     = oldframe16->entry_cs;
         newframe16->ip           = oldframe16->ip;
@@ -790,7 +788,6 @@
 
     hCurrentTask = hTask;
     SET_CUR_THREAD( pNewTask->thdb );
-    pCurrentProcess = pNewTask->thdb->process;
     IF1632_Saved16_ss_sp = pNewTask->ss_sp;
 }
 
@@ -1197,7 +1194,7 @@
     /* Build a stack frame for the return */
 
     newFrame = CURRENT_STACK16;
-    newFrame->saved_ss_sp = oldFrame->saved_ss_sp;
+    newFrame->frame32 = oldFrame->frame32;
     if (debugging_relay)
     {
         newFrame->entry_ip = oldFrame->entry_ip;
diff --git a/memory/atom.c b/memory/atom.c
index 83d7a4c..dc82162 100644
--- a/memory/atom.c
+++ b/memory/atom.c
@@ -24,7 +24,6 @@
 
 #ifdef CONFIG_IPC
 #include "dde_atom.h"
-#include "options.h"
 #endif
 
 #define DEFAULT_ATOMTABLE_SIZE    37
@@ -399,9 +398,10 @@
 {
     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
 #ifdef CONFIG_IPC
-    if (Options.ipc) return DDE_GlobalAddAtom( str );
-#endif
+    return DDE_GlobalAddAtom( str );
+#else
     return ATOM_AddAtom( USER_HeapSel, (LPCSTR)PTR_SEG_TO_LIN(str) );
+#endif
 }
 
 
@@ -433,9 +433,10 @@
 ATOM WINAPI GlobalDeleteAtom( ATOM atom )
 {
 #ifdef CONFIG_IPC
-    if (Options.ipc) return DDE_GlobalDeleteAtom( atom );
-#endif
+    return DDE_GlobalDeleteAtom( atom );
+#else
     return ATOM_DeleteAtom( USER_HeapSel, atom );
+#endif
 }
 
 
@@ -446,9 +447,10 @@
 {
     if (!HIWORD(str)) return (ATOM)LOWORD(str);  /* Integer atom */
 #ifdef CONFIG_IPC
-    if (Options.ipc) return DDE_GlobalFindAtom( str );
-#endif
+    return DDE_GlobalFindAtom( str );
+#else
     return ATOM_FindAtom( USER_HeapSel, (LPCSTR)PTR_SEG_TO_LIN(str) );
+#endif
 }
 
 
@@ -480,9 +482,10 @@
 UINT16 WINAPI GlobalGetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
 {
 #ifdef CONFIG_IPC
-    if (Options.ipc) return DDE_GlobalGetAtomName( atom, buffer, count );
-#endif
+    return DDE_GlobalGetAtomName( atom, buffer, count );
+#else
     return (UINT16)ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
+#endif
 }
 
 
diff --git a/memory/global.c b/memory/global.c
index 0830c14..ecb6c95 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -18,7 +18,6 @@
 #include "dde_mem.h"
 #include "stackframe.h"
 #include "module.h"
-#include "options.h"
 #include "stddebug.h"
 #include "debug.h"
 #include "winerror.h"
@@ -124,7 +123,7 @@
     pArena->size = GET_SEL_LIMIT(sel) + 1;
 
 #ifdef CONFIG_IPC
-    if ((flags & GMEM_DDESHARE) && Options.ipc)
+    if (flags & GMEM_DDESHARE)
     {
 	pArena->handle = shmdata->handle;
 	pArena->shmid  = shmdata->shmid;
@@ -200,7 +199,7 @@
       /* Allocate the linear memory */
 
 #ifdef CONFIG_IPC
-    if ((flags & GMEM_DDESHARE) && Options.ipc)
+    if (flags & GMEM_DDESHARE)
         ptr = DDE_malloc(flags, size, &shmdata);
     else 
 #endif  /* CONFIG_IPC */
@@ -297,7 +296,8 @@
     if (!handle) return 0;
     
 #ifdef CONFIG_IPC
-    if (Options.ipc && (flags & GMEM_DDESHARE || is_dde_handle(handle))) {
+    if (flags & GMEM_DDESHARE || is_dde_handle(handle))
+    {
 	fprintf(stdnimp,
                "GlobalReAlloc16: shared memory reallocating unimplemented\n"); 
 	return 0;
diff --git a/memory/selector.c b/memory/selector.c
index 410c0d5..28c8a61 100644
--- a/memory/selector.c
+++ b/memory/selector.c
@@ -182,7 +182,8 @@
     {
         if ((frame->ds >= sel) && (frame->ds < nextsel)) frame->ds = 0;
         if ((frame->es >= sel) && (frame->es < nextsel)) frame->es = 0;
-	frame = PTR_SEG_TO_LIN( frame->saved_ss_sp );
+        if (!frame->frame32) break;
+        frame = PTR_SEG_TO_LIN( frame->frame32->frame16 );
     }
 }
 
diff --git a/memory/virtual.c b/memory/virtual.c
index 9ffde82..65f17d4 100644
--- a/memory/virtual.c
+++ b/memory/virtual.c
@@ -660,7 +660,7 @@
     PDB32 *pdb = (PDB32 *)PROCESS_GetObjPtr( handle, K32OBJ_PROCESS );
     if (pdb)
     {
-        if (pdb == pCurrentProcess)
+        if (pdb == PROCESS_Current())
             ret = VirtualProtect( addr, size, new_prot, old_prot );
         else
             fprintf(stderr,"Unsupported: VirtualProtectEx on other process\n");
@@ -743,7 +743,7 @@
     PDB32 *pdb = (PDB32 *)PROCESS_GetObjPtr( handle, K32OBJ_PROCESS );
     if (pdb)
     {
-        if (pdb == pCurrentProcess)
+        if (pdb == PROCESS_Current())
             ret = VirtualQuery( addr, info, len );
         else
             fprintf(stderr,"Unsupported: VirtualQueryEx on other process\n");
diff --git a/misc/lstr.c b/misc/lstr.c
index 234ec07..1e54527 100644
--- a/misc/lstr.c
+++ b/misc/lstr.c
@@ -10,16 +10,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
-
-#include "windows.h"
-#include "winnt.h"	/* HEAP_ macros */
-#include "task.h"
-#include "heap.h"
-#include "ldt.h"
-#include "stackframe.h"
-#include "module.h"
-#include "stddebug.h"
-#include "debug.h"
+#include "config.h"
 
 #ifdef HAVE_WCTYPE_H
 # include <wctype.h>
@@ -32,6 +23,17 @@
 # define iswlower(c) islower(c)
 #endif  /* HAVE_WCTYPE_H */
 
+
+#include "windows.h"
+#include "winnt.h"	/* HEAP_ macros */
+#include "task.h"
+#include "heap.h"
+#include "ldt.h"
+#include "stackframe.h"
+#include "module.h"
+#include "stddebug.h"
+#include "debug.h"
+
 /* Funny to divide them between user and kernel. */
 
 /* be careful: always use functions from wctype.h if character > 255 */
diff --git a/misc/main.c b/misc/main.c
index cbc551b..ca68de1 100644
--- a/misc/main.c
+++ b/misc/main.c
@@ -81,7 +81,6 @@
     FALSE,
     FALSE,          /* failReadOnly */
     MODE_ENHANCED,  /* Enhanced mode */
-    FALSE,          /* IPC enabled */
 #ifdef DEFAULT_LANG
     DEFAULT_LANG,   /* Default language */
 #else
@@ -99,7 +98,6 @@
     { "-depth",         ".depth",           XrmoptionSepArg, (caddr_t)NULL },
     { "-display",       ".display",         XrmoptionSepArg, (caddr_t)NULL },
     { "-iconic",        ".iconic",          XrmoptionNoArg,  (caddr_t)"on" },
-    { "-ipc",           ".ipc",             XrmoptionNoArg,  (caddr_t)"off"},
     { "-language",      ".language",        XrmoptionSepArg, (caddr_t)"En" },
     { "-name",          ".name",            XrmoptionSepArg, (caddr_t)NULL },
     { "-perfect",       ".perfect",         XrmoptionNoArg,  (caddr_t)"on" },
@@ -131,7 +129,6 @@
   "    -failreadonly   Read only files may not be opened in write mode\n" \
   "    -fixedmap       Use a \"standard\" color map\n" \
   "    -iconic         Start as an icon\n" \
-  "    -ipc            Enable IPC facilities\n" \
   "    -language xx    Set the language (one of En,Es,De,No,Fr,Fi,Da,Cz,Eo,It,Ko,\n                    Hu,Pl,Po)\n" \
   "    -managed        Allow the window manager to manage created windows\n" \
   "    -mode mode      Start Wine in a particular mode (standard or enhanced)\n" \
@@ -359,8 +356,6 @@
 	Options.debug = TRUE;
     if (MAIN_GetResource( db, ".failreadonly", &value ))
         Options.failReadOnly = TRUE;
-    if (MAIN_GetResource( db, ".ipc", &value ))
-        Options.ipc = TRUE;
     if (MAIN_GetResource( db, ".perfect", &value ))
 	Options.perfectGraphics = TRUE;
     if (MAIN_GetResource( db, ".depth", &value))
@@ -537,8 +532,6 @@
     int *depth_list;
     struct timeval tv;
 
-    extern int _WinMain(int argc, char **argv);
-
 #ifdef MALLOC_DEBUGGING
     char *trace;
 
diff --git a/misc/port.c b/misc/port.c
index f98a951..657450e 100644
--- a/misc/port.c
+++ b/misc/port.c
@@ -57,3 +57,36 @@
     return sys_errlist[err];
 }
 #endif  /* HAVE_STRERROR */
+
+#if !defined(HAVE_CLONE) && defined(__linux__)
+#include <assert.h>
+#include <errno.h>
+#include <syscall.h>
+int clone( int (*fn)(void *), void *stack, int flags, void *arg )
+{
+#ifdef __i386__
+    int ret;
+    void **stack_ptr = (void **)stack;
+    *--stack_ptr = arg;  /* Push argument on stack */
+    *--stack_ptr = fn;   /* Push function pointer (popped into ebx) */
+    __asm__ __volatile__( "pushl %%ebx\n\t"
+                          "movl %2,%%ebx\n\t"
+                          "int $0x80\n\t"
+                          "popl %%ebx\n\t"   /* Contains fn in the child */
+                          "testl %%eax,%%eax\n\t"
+                          "jnz 0f\n\t"
+                          "call *%%ebx\n\t"       /* Should never return */
+                          "xorl %%eax,%%eax\n\t"  /* Just in case it does*/
+                          "0:"
+                          : "=a" (ret)
+                          : "0" (SYS_clone), "g" (flags), "c" (stack_ptr) );
+    assert( ret );  /* If ret is 0, we returned from the child function */
+    if (ret > 0) return ret;
+    errno = -ret;
+    return -1;
+#else
+    errno = EINVAL;
+    return -1;
+#endif  /* __i386__ */
+}
+#endif  /* !HAVE_CLONE && __linux__ */
diff --git a/misc/registry.c b/misc/registry.c
index 90e233c..9aa04ce 100644
--- a/misc/registry.c
+++ b/misc/registry.c
@@ -18,6 +18,7 @@
 #include <sys/fcntl.h>
 #include <sys/stat.h>
 #include <pwd.h>
+#include <assert.h>
 #include <time.h>
 #include "windows.h"
 #include "win.h"
@@ -587,6 +588,11 @@
 	LPKEYVALUE	val=NULL;
 	int		i;
 
+	if (name && !*name) {/* empty string equals default (NULL) value */
+		free(name);
+		name = NULL;
+	}
+
 	for (i=0;i<lpkey->nrofvalues;i++) {
 		val=lpkey->values+i;
 		if (name==NULL) {
@@ -711,7 +717,10 @@
 	}
 	*ws	= 0;
 	ws	= *str;
-	*str	= strdupW(*str);
+	if (*ws)
+		*str	= strdupW(*str);
+	else
+		*str	= NULL;
 	free(ws);
 	return s;
 }
@@ -1038,7 +1047,10 @@
 			int	len;
 
 			name = strdupA2W(key->values[i].name);
-			if (!*name) name = NULL;
+			if (!*name) {
+				free(name);
+				name = NULL;
+			}
 			free(key->values[i].name);
 
 			len	= key->values[i].datalen;
@@ -2085,6 +2097,8 @@
 	lpkey	= lookup_hkey(hkey);
 	if (!lpkey)
 		return SHELL_ERROR_BADKEY;
+	if (lpszValueName && !*lpszValueName)
+		lpszValueName = NULL;
 	if (lpszValueName==NULL) {
 		for (i=0;i<lpkey->nrofvalues;i++)
 			if (lpkey->values[i].name==NULL)
@@ -2726,9 +2740,8 @@
 		memcpy(lpszValue,val->name,2*lstrlen32W(val->name)+2);
 		*lpcchValue=lstrlen32W(val->name)*2+2;
 	} else {
-		/* how to handle NULL value? */
 		*lpszValue	= 0;
-		*lpcchValue	= 2;
+		*lpcchValue	= 0;
 	}
 	if (lpdwType)
 		*lpdwType=val->type;
diff --git a/misc/ver.c b/misc/ver.c
index 40c3241..c19e5f3 100644
--- a/misc/ver.c
+++ b/misc/ver.c
@@ -168,7 +168,7 @@
 
 static int read_xx_header(HFILE32 lzfd) {
 	IMAGE_DOS_HEADER	mzh;
-	char			magic[2];
+	char			magic[3];
 
 	LZSeek32(lzfd,0,SEEK_SET);
 	if (sizeof(mzh)!=LZRead32(lzfd,&mzh,sizeof(mzh)))
@@ -183,7 +183,8 @@
 		return IMAGE_OS2_SIGNATURE;
 	if (magic[0] == 'P' && magic[1] == 'E')
 		return IMAGE_NT_SIGNATURE;
-	fprintf(stderr,"misc/ver.c:read_ne_header:can't handle %*s files.\n",2,magic);
+	magic[2]='\0';
+	fprintf(stderr,"misc/ver.c:read_ne_header:can't handle %s files.\n",magic);
 	return 0;
 }
 
@@ -727,7 +728,7 @@
     strcpy(curDir, "");
     strcpy(destDir, "");
 
-    if(flags & VFFF_ISSHAREDFILE && !getuid()) {
+    if(flags & VFFF_ISSHAREDFILE) {
 	GetSystemDirectory32A(destDir, 256);
 
 	/* Were we given a filename?  If so, try to find the file. */
diff --git a/misc/version.c b/misc/version.c
index dafa443..e62438e 100644
--- a/misc/version.c
+++ b/misc/version.c
@@ -114,17 +114,15 @@
 
     if (versionForced) /* user has overridden any sensible checks */
         return defaultVersion;
-    if (!pCurrentProcess) /* at startuptime probably */
-        return defaultVersion;
-    if (!pCurrentProcess->exe_modref)
+    if (!PROCESS_Current()->exe_modref)
     {
         /* HACK: if we have loaded a PE image into this address space,
          * we are probably using thunks, so Win95 is our best bet
          */
-        if (pCurrentProcess->modref_list) return WIN95;
+        if (PROCESS_Current()->modref_list) return WIN95;
         return WIN31; /* FIXME: hmm, look at DDB.version ? */
     }
-    peheader = PE_HEADER(pCurrentProcess->exe_modref->module);
+    peheader = PE_HEADER(PROCESS_Current()->exe_modref->module);
     if (peheader->OptionalHeader.MajorSubsystemVersion == 4)
         /* FIXME: NT4 has the same majorversion; add a check here for it. */
         return WIN95;
diff --git a/msdos/int2f.c b/msdos/int2f.c
index 755e05b..c8efcab 100644
--- a/msdos/int2f.c
+++ b/msdos/int2f.c
@@ -41,6 +41,25 @@
         do_int2f_16( context );
         break;
 
+    case 0x45:
+       switch (AL_reg(context)) 
+       {
+       case 0x00:
+       case 0x01:
+       case 0x02:
+       case 0x03:
+       case 0x04:
+       case 0x05:
+       case 0x06:
+       case 0x07:
+       case 0x08:
+           /* Microsoft Profiler - not installed */
+           break;
+       default:
+            INT_BARF( context, 0x2f );
+       }
+       break;
+
     case 0x4a:
         switch(AL_reg(context))
         {
diff --git a/multimedia/Makefile.in b/multimedia/Makefile.in
index f4a288f..cc7446d 100644
--- a/multimedia/Makefile.in
+++ b/multimedia/Makefile.in
@@ -15,6 +15,7 @@
 	midi.c \
 	mixer.c \
 	mmaux.c \
+	mmio.c \
 	mmsystem.c \
 	time.c
 
diff --git a/multimedia/audio.c b/multimedia/audio.c
index 58d8365..8abae8c 100644
--- a/multimedia/audio.c
+++ b/multimedia/audio.c
@@ -1,5 +1,5 @@
 /*				   
- * Sample Wine Driver for Linux
+ * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
  *
  * Copyright 1994 Martin Ayotte
  */
@@ -24,17 +24,12 @@
 #include "mmsystem.h"
 #include "heap.h"
 #include "ldt.h"
-
-#ifdef linux
-#include <linux/soundcard.h>
-#elif __FreeBSD__
-#include <machine/soundcard.h>
-#endif
-
 #include "stddebug.h"
 #include "debug.h"
 
-#if defined(linux) || defined(__FreeBSD__)
+#ifdef HAVE_OSS
+#include <sys/soundcard.h>
+
 #define SOUND_DEV "/dev/dsp"
 #define MIXER_DEV "/dev/mixer"
 
@@ -62,7 +57,7 @@
 typedef struct {
 	int		unixdev;
 	int		state;
-	DWORD		bufsize;	/* Linux '/dev/dsp' give us that size */
+	DWORD		bufsize;	/* OpenSound '/dev/dsp' give us that size */
 	WAVEOPENDESC	waveDesc;
 	WORD		wFlags;
 	PCMWAVEFORMAT	Format;
@@ -749,17 +744,17 @@
 	lpParms->lpstrReturn = NULL;
 	switch(dwFlags) {
 	case MCI_INFO_PRODUCT:
-		lpParms->lpstrReturn = "Linux Sound System 0.5";
+		lpParms->lpstrReturn = "Open Sound System 0.5";
 		break;
 	case MCI_INFO_FILE:
 		lpParms->lpstrReturn = 
 			(LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
 		break;
 	case MCI_WAVE_INPUT:
-		lpParms->lpstrReturn = "Linux Sound System 0.5";
+		lpParms->lpstrReturn = "Open Sound System 0.5";
 		break;
 	case MCI_WAVE_OUTPUT:
-		lpParms->lpstrReturn = "Linux Sound System 0.5";
+		lpParms->lpstrReturn = "Open Sound System 0.5";
 		break;
 	default:
 		return MCIERR_UNRECOGNIZED_COMMAND;
@@ -799,7 +794,7 @@
 #else
 	lpCaps->wMid = 0x00FF; 	/* Manufac ID */
 	lpCaps->wPid = 0x0001; 	/* Product ID */
-	strcpy(lpCaps->szPname, "Linux WAVOUT Driver");
+	strcpy(lpCaps->szPname, "OpenSoundSystem WAVOUT Driver");
 #endif
 	lpCaps->vDriverVersion = 0x0100;
 	lpCaps->dwFormats = 0x00000000;
@@ -1213,8 +1208,6 @@
 	return MMSYSERR_NOERROR;
 }
 
-#endif /* linux || __FreeBSD__*/
-
 /**************************************************************************
  * 				wodMessage			[sample driver]
  */
@@ -1223,7 +1216,6 @@
 {
 	dprintf_mciwave(stddeb,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
 			wDevID, wMsg, dwUser, dwParam1, dwParam2);
-#if defined(linux) || defined(__FreeBSD__)
         switch(wMsg) {
 	case WODM_OPEN:
 		return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
@@ -1267,16 +1259,11 @@
 		dprintf_mciwave(stddeb,"wodMessage // unknown message !\n");
 	}
 	return MMSYSERR_NOTSUPPORTED;
-#else
-	return MMSYSERR_NOTENABLED;
-#endif
 }
 
 
 /*-----------------------------------------------------------------------*/
 
-#if defined(linux) || defined(__FreeBSD__)
-
 /**************************************************************************
  * 			widGetDevCaps				[internal]
  */
@@ -1297,7 +1284,7 @@
 #else
 	lpCaps->wMid = 0x00FF; 	/* Manufac ID */
 	lpCaps->wPid = 0x0001; 	/* Product ID */
-	strcpy(lpCaps->szPname, "Linux WAVIN Driver");
+	strcpy(lpCaps->szPname, "OpenSoundSystem WAVIN Driver");
 #endif
 	lpCaps->dwFormats = 0x00000000;
 	lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
@@ -1688,8 +1675,6 @@
 	return MMSYSERR_NOERROR;
 }
 
-#endif /* linux || __FreeBSD__ */
-
 /**************************************************************************
  * 				widMessage			[sample driver]
  */
@@ -1698,7 +1683,6 @@
 {
 	dprintf_mciwave(stddeb,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
 			wDevID, wMsg, dwUser, dwParam1, dwParam2);
-#if defined(linux) || defined(__FreeBSD__)
 	switch(wMsg) {
 	case WIDM_OPEN:
 		return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
@@ -1728,9 +1712,6 @@
 		dprintf_mciwave(stddeb,"widMessage // unknown message !\n");
 	}
 	return MMSYSERR_NOTSUPPORTED;
-#else
-	return MMSYSERR_NOTENABLED;
-#endif
 }
 
 
@@ -1740,7 +1721,6 @@
 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
 		     DWORD dwParam1, DWORD dwParam2)
 {
-#if defined(linux) || defined(__FreeBSD__)
 	dprintf_mciwave(stddeb,"WAVE_DriverProc(%08lX, %04X, %04X, %08lX, %08lX)\n", 
 		dwDevID, hDriv, wMsg, dwParam1, dwParam2);
 	switch(wMsg) {
@@ -1831,7 +1811,39 @@
 	default:
 		return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
 	}
-#else
 	return MMSYSERR_NOTENABLED;
-#endif
 }
+
+#else /* !HAVE_OSS */
+
+/**************************************************************************
+ * 				wodMessage			[sample driver]
+ */
+DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+					DWORD dwParam1, DWORD dwParam2)
+{
+	fprintf(stderr,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
+			wDevID, wMsg, dwUser, dwParam1, dwParam2);
+	return MMSYSERR_NOTENABLED;
+}
+
+/**************************************************************************
+ * 				widMessage			[sample driver]
+ */
+DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+					DWORD dwParam1, DWORD dwParam2)
+{
+	fprintf(stderr,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
+			wDevID, wMsg, dwUser, dwParam1, dwParam2);
+	return MMSYSERR_NOTENABLED;
+}
+
+/**************************************************************************
+ * 				AUDIO_DriverProc		[sample driver]
+ */
+LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
+		     DWORD dwParam1, DWORD dwParam2)
+{
+	return MMSYSERR_NOTENABLED;
+}
+#endif /* HAVE_OSS */
diff --git a/multimedia/dsound.c b/multimedia/dsound.c
index 5b3983b..fafa959 100644
--- a/multimedia/dsound.c
+++ b/multimedia/dsound.c
@@ -1,20 +1,120 @@
-/*  			DS
+/*  			DirectSound
+ * 
+ * Copyright 1998 Marcus Meissner
+ */
+/*
+ * Note: This file requires multithread ability. It is not possible to
+ * implement the stuff in a single thread anyway. And most DirectX apps
+ * require threading themselves.
+ *
+ * FIXME: This file is full of race conditions and unlocked variable access
+ * from two threads. But we usually don't need to bother.
+ *
  */
 
 #include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <sys/signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
 #include "windows.h"
+#include "winerror.h"
 #include "interfaces.h"
 #include "mmsystem.h"
 #include "dsound.h"
 
+#ifdef HAVE_OSS
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+static int audiofd = 0;
+static LPDIRECTSOUND	dsound = NULL;
+#endif
+
 HRESULT WINAPI DirectSoundEnumerate32A(LPDSENUMCALLBACK32A enumcb,LPVOID context) {
 	return 0;
 }
 
+#ifdef HAVE_OSS
+static void _dump_DSBCAPS(DWORD xmask) {
+	struct {
+		DWORD	mask;
+		char	*name;
+	} flags[] = {
+#define FE(x) { x, #x },
+		FE(DSBCAPS_PRIMARYBUFFER)
+		FE(DSBCAPS_STATIC)
+		FE(DSBCAPS_LOCHARDWARE)
+		FE(DSBCAPS_LOCSOFTWARE)
+		FE(DSBCAPS_CTRLFREQUENCY)
+		FE(DSBCAPS_CTRLPAN)
+		FE(DSBCAPS_CTRLVOLUME)
+		FE(DSBCAPS_CTRLDEFAULT)
+		FE(DSBCAPS_CTRLALL)
+		FE(DSBCAPS_STICKYFOCUS)
+		FE(DSBCAPS_GETCURRENTPOSITION2)
+	};
+	int	i;
+
+	for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
+		if (flags[i].mask & xmask)
+			fprintf(stderr,"%s ",flags[i].name);
+}
+
 static HRESULT WINAPI IDirectSoundBuffer_SetFormat(
 	LPDIRECTSOUNDBUFFER this,LPWAVEFORMATEX wfex
 ) {
+	int	xx,channels,speed,format,nformat;
+
 	fprintf(stderr,"IDirectSoundBuffer(%p)->SetFormat(%p),stub!\n",this,wfex);
+	memcpy(&(this->wfx),wfex,sizeof(this->wfx));
+	fprintf(stderr,"	[formattag=0x%04x,",wfex->wFormatTag);
+	fprintf(stderr,"chans=%d,",wfex->nChannels);
+	fprintf(stderr,"samplerate=%ld,",wfex->nSamplesPerSec);
+	fprintf(stderr,"bytespersec=%ld,",wfex->nAvgBytesPerSec);
+	fprintf(stderr,"blockalign=%d,",wfex->nBlockAlign);
+	fprintf(stderr,"bitspersamp=%d,",wfex->wBitsPerSample);
+	fprintf(stderr,"cbSize=%d]\n",wfex->cbSize);
+
+	switch (wfex->wFormatTag) {
+	default:
+		fprintf(stderr,"unknown WAVE_FORMAT tag %d\n",wfex->wFormatTag);
+		return DSERR_BADFORMAT;
+	case WAVE_FORMAT_PCM:
+		format = AFMT_S16_LE;
+		break;
+	}
+	if (-1==ioctl(audiofd,SNDCTL_DSP_GETFMTS,&xx)) {
+		perror("ioctl SNDCTL_DSP_GETFMTS");
+		return DSERR_BADFORMAT;
+	}
+	if ((xx&format)!=format) {/* format unsupported */
+		fprintf(stderr,"SNDCTL_DSP_GETFMTS: format not supported\n"); 
+		return DSERR_BADFORMAT;
+	}
+	nformat = format;
+	if (-1==ioctl(audiofd,SNDCTL_DSP_SETFMT,&nformat)) {
+		perror("ioctl SNDCTL_DSP_SETFMT");
+		return DSERR_BADFORMAT;
+	}
+	if (nformat!=format) {/* didn't work */
+		fprintf(stderr,"SNDCTL_DSP_GETFMTS: format not set\n"); 
+		return DSERR_BADFORMAT;
+	}
+
+	channels = wfex->nChannels-1;
+	if (-1==ioctl(audiofd,SNDCTL_DSP_STEREO,&channels)) {
+		perror("ioctl SNDCTL_DSP_STEREO");
+		return DSERR_BADFORMAT;
+	}
+	speed = wfex->nSamplesPerSec;
+	if (-1==ioctl(audiofd,SNDCTL_DSP_SPEED,&speed)) {
+		perror("ioctl SNDCTL_DSP_SPEED");
+		return DSERR_BADFORMAT;
+	}
 	return 0;
 }
 
@@ -41,28 +141,44 @@
 }
 
 static HRESULT WINAPI IDirectSoundBuffer_Play(
-	LPDIRECTSOUNDBUFFER this,DWORD x,DWORD y,DWORD z
+	LPDIRECTSOUNDBUFFER this,DWORD reserved1,DWORD reserved2,DWORD flags
 ) {
+
 	fprintf(stderr,"IDirectSoundBuffer(%p)->Play(%08lx,%08lx,%08lx),stub!\n",
-		this,x,y,z
+		this,reserved1,reserved2,flags
 	);
+	this->playing = 1;
 	return 0;
 }
 
 static HRESULT WINAPI IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER this) {
-	fprintf(stderr,"IDirectSoundBuffer(%p)->Stop()\n",this);
+	/*fprintf(stderr,"IDirectSoundBuffer(%p)->Stop()\n",this);*/
+	this->playing = 0;
 	return 0;
 }
 
 static DWORD WINAPI IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER this) {
-	fprintf(stderr,"IDirectSoundBuffer(%p)->AddRef()\n",this);
 	return ++(this->ref);
 }
 static DWORD WINAPI IDirectSoundBuffer_Release(LPDIRECTSOUNDBUFFER this) {
-	fprintf(stderr,"IDirectSoundBuffer(%p)->Release(),stub!\n",this);
+	int	i;
+
 	if (--this->ref)
 		return this->ref;
 	fprintf(stderr,"	-> IDirectSoundBuffer(%p) freed.\n",this);
+	for (i=0;i<this->dsound->nrofbuffers;i++)
+		if (this->dsound->buffers[i] == this)
+			break;
+	if (i < this->dsound->nrofbuffers) {
+		memcpy(
+			this->dsound->buffers+i,
+			this->dsound->buffers+i+1,
+			sizeof(LPDIRECTSOUNDBUFFER)*(this->dsound->nrofbuffers-i-1)
+		);
+		this->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,this->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER)*this->dsound->nrofbuffers);
+		this->dsound->nrofbuffers--;
+		this->dsound->lpvtbl->fnRelease(this->dsound);
+	}
 	HeapFree(GetProcessHeap(),0,this);
 	return 0;
 }
@@ -70,7 +186,11 @@
 static HRESULT WINAPI IDirectSoundBuffer_GetCurrentPosition(
 	LPDIRECTSOUNDBUFFER this,LPDWORD playpos,LPDWORD writepos
 ) {
-	fprintf(stderr,"IDirectSoundBuffer(%p)->GetCurrentPosition(%p,%p),stub!\n",this,playpos,writepos);
+/*	fprintf(stderr,"IDirectSoundBuffer(%p)->GetCurrentPosition(%p,%p),stub!\n",this,playpos,writepos);*/
+
+	if (playpos) *playpos = this->playpos;
+	this->writepos = (this->playpos+512) % this->buflen;
+	if (writepos) *writepos = this->writepos; /* hmm */
 	return 0;
 }
 
@@ -78,17 +198,85 @@
 	LPDIRECTSOUNDBUFFER this,LPDWORD status
 ) {
 	fprintf(stderr,"IDirectSoundBuffer(%p)->GetStatus(%p),stub!\n",this,status);
-	*status = 0; /* hmm. set playing? or not ? */
+	if (this->playing)
+		*status = DSBSTATUS_PLAYING;
+	*status |= DSBSTATUS_LOOPING; /* FIXME */
+	return 0;
+}
+
+static HRESULT WINAPI IDirectSoundBuffer_GetFormat(
+	LPDIRECTSOUNDBUFFER this,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
+) {
+	fprintf(stderr,"IDirectSoundBuffer(%p)->GetFormat(%p,0x%08lx,%p),stub!\n",this,lpwf,wfsize,wfwritten);
+	if (wfsize>sizeof(this->wfx)) wfsize = sizeof(this->wfx);
+	memcpy(lpwf,&(this->wfx),wfsize);
+	if (wfwritten) *wfwritten = wfsize;
 	return 0;
 }
 
 static HRESULT WINAPI IDirectSoundBuffer_Lock(
-	LPDIRECTSOUNDBUFFER this,DWORD x1,DWORD x2,LPVOID p1,LPDWORD x3,LPVOID p2,LPDWORD x4,DWORD x5
+	LPDIRECTSOUNDBUFFER this,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
 ) {
-	fprintf(stderr,"IDirectSoundBuffer(%p)->Lock(0x%08lx,0x%08lx,%p,%p,%p,%p,0x%08lx,),stub!\n",this,x1,x2,p1,x3,p2,x4,x5);
-	return 0x80000000;
+
+/*
+	fprintf(stderr,"IDirectSoundBuffer(%p)->Lock(%ld,%ld,%p,%p,%p,%p,0x%08lx),stub!\n",
+		this,
+		writecursor,
+		writebytes,
+		lplpaudioptr1,
+		audiobytes1,
+		lplpaudioptr2,
+		audiobytes2,
+		flags
+	);
+*/
+	if (flags & DSBLOCK_FROMWRITECURSOR)
+		writecursor = this->writepos;
+
+	if (writecursor+writebytes < this->buflen) {
+		*(LPBYTE*)lplpaudioptr1 = this->buffer+writecursor;
+		*audiobytes1 = writebytes;
+		if (lplpaudioptr2)
+			*(LPBYTE*)lplpaudioptr2 = NULL;
+		if (audiobytes2)
+			*audiobytes2 = 0;
+	} else {
+		*(LPBYTE*)lplpaudioptr1 = this->buffer+writecursor;
+		*audiobytes1 = this->buflen-writecursor;
+		if (lplpaudioptr2)
+			*(LPBYTE*)lplpaudioptr2 = this->buffer;
+		if (audiobytes2)
+			*audiobytes2 = writebytes-(this->buflen-writecursor);
+	}
+	this->writepos=(writecursor+writebytes)%this->buflen;
+	return 0;
 }
 
+static HRESULT WINAPI IDirectSoundBuffer_SetCurrentPosition(
+	LPDIRECTSOUNDBUFFER this,DWORD newpos
+) {
+	fprintf(stderr,"IDirectSoundBuffer(%p)->SetCurrentPosition(%ld)\n",this,newpos);
+	this->playpos = newpos;
+	return 0;
+}
+
+static HRESULT WINAPI IDirectSoundBuffer_SetPan(
+	LPDIRECTSOUNDBUFFER this,LONG newpan
+) {
+	fprintf(stderr,"IDirectSoundBuffer(%p)->SetPan(%ld),stub!\n",this,newpan);
+	return 0;
+}
+
+static HRESULT WINAPI IDirectSoundBuffer_Unlock(
+	LPDIRECTSOUNDBUFFER this,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
+) {
+	struct count_info	ci;
+/*
+	fprintf(stderr,"IDirectSoundBuffer(%p)->Unlock(%p,%ld,%p,%ld),stub!\n",this,p1,x1,p2,x2);
+ */
+ 	fprintf(stderr,"u%ld.%ld,",x1,x2);
+	return 0;
+}
 
 static struct tagLPDIRECTSOUNDBUFFER_VTABLE dsbvt = {
 	(void *)1,
@@ -96,7 +284,7 @@
 	IDirectSoundBuffer_Release,
 	(void *)4,
 	IDirectSoundBuffer_GetCurrentPosition,
-	(void *)6,
+	IDirectSoundBuffer_GetFormat,
 	IDirectSoundBuffer_GetVolume,
 	(void *)8,
         (void *)9,
@@ -104,13 +292,13 @@
 	(void *)11,
 	IDirectSoundBuffer_Lock,
 	IDirectSoundBuffer_Play,
-	(void *)14,
+	IDirectSoundBuffer_SetCurrentPosition,
 	IDirectSoundBuffer_SetFormat,
 	IDirectSoundBuffer_SetVolume,
-	(void *)17,
+	IDirectSoundBuffer_SetPan,
 	IDirectSoundBuffer_SetFrequency,
 	IDirectSoundBuffer_Stop,
-	(void *)20
+	IDirectSoundBuffer_Unlock
 };
 
 
@@ -128,27 +316,70 @@
 static HRESULT WINAPI IDirectSound_CreateSoundBuffer(
 	LPDIRECTSOUND this,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
 ) {
-	fprintf(stderr,"IDirectSound(%p)->CreateBuffer(%p,%p,%p),stub!\n",this,dsbd,ppdsb,lpunk);
+	fprintf(stderr,"IDirectSound(%p)->CreateSoundBuffer(%p,%p,%p),stub!\n",this,dsbd,ppdsb,lpunk);
+	fprintf(stderr,"[size=%ld,",dsbd->dwSize);
+	fprintf(stderr,"flags = 0x%08lx,",dsbd->dwFlags);
+	_dump_DSBCAPS(dsbd->dwFlags);
+	fprintf(stderr,"bufferbytes = %ld,",dsbd->dwBufferBytes);
+	fprintf(stderr,"lpwfxFormat = %p]\n",dsbd->lpwfxFormat);
 	*ppdsb = (LPDIRECTSOUNDBUFFER)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBuffer));
 	(*ppdsb)->ref =1;
+	(*ppdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsbd->dwBufferBytes);
+	(*ppdsb)->buflen = dsbd->dwBufferBytes;
+	(*ppdsb)->playpos = 0;
+	(*ppdsb)->writepos = 0;
 	(*ppdsb)->lpvtbl = &dsbvt;
+	(*ppdsb)->dsound = this;
+	(*ppdsb)->playing = 0;
+
+	/* register buffer */
+	this->buffers = (LPDIRECTSOUNDBUFFER*)HeapReAlloc(GetProcessHeap(),0,this->buffers,sizeof(LPDIRECTSOUNDBUFFER)*(this->nrofbuffers+1));
+	this->buffers[this->nrofbuffers] = *ppdsb;
+	this->nrofbuffers++;
+	this->lpvtbl->fnAddRef(this);
+
+	if (dsbd->lpwfxFormat) dsbvt.fnSetFormat(*ppdsb,dsbd->lpwfxFormat);
 	return 0;
 }
 
+static HRESULT WINAPI IDirectSound_DuplicateSoundBuffer(
+	LPDIRECTSOUND this,LPDIRECTSOUNDBUFFER pdsb,LPLPDIRECTSOUNDBUFFER ppdsb
+) {
+	fprintf(stderr,"IDirectSound(%p)->DuplicateSoundBuffer(%p,%p),stub!\n",this,pdsb,ppdsb);
+
+	*ppdsb = (LPDIRECTSOUNDBUFFER)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBuffer));
+	(*ppdsb)->ref =1;
+	(*ppdsb)->buffer = (LPBYTE)HeapAlloc(GetProcessHeap(),0,pdsb->buflen);
+	(*ppdsb)->buflen = pdsb->buflen;
+	(*ppdsb)->playpos = 0;
+	(*ppdsb)->writepos = 0;
+	(*ppdsb)->lpvtbl = &dsbvt;
+	(*ppdsb)->dsound = this;
+	dsbvt.fnSetFormat(*ppdsb,&(pdsb->wfx));
+	/* register buffer */
+	this->buffers = (LPDIRECTSOUNDBUFFER*)HeapReAlloc(GetProcessHeap(),0,this->buffers,sizeof(LPDIRECTSOUNDBUFFER)*(this->nrofbuffers+1));
+	this->buffers[this->nrofbuffers] = *ppdsb;
+	this->nrofbuffers++;
+	this->lpvtbl->fnAddRef(this);
+	return 0;
+}
+
+
 static HRESULT WINAPI IDirectSound_GetCaps(LPDIRECTSOUND this,LPDSCAPS dscaps) {
 	fprintf(stderr,"IDirectSound(%p)->GetCaps(%p),stub!\n",this,dscaps);
+	fprintf(stderr,"	flags = 0x%08lx\n",dscaps->dwFlags);
 	return 0;
 }
 
 static ULONG WINAPI IDirectSound_AddRef(LPDIRECTSOUND this) {
-	fprintf(stderr,"IDirectSound(%p)->AddRef()\n",this);
 	return ++(this->ref);
 }
 
 static ULONG WINAPI IDirectSound_Release(LPDIRECTSOUND this) {
-	fprintf(stderr,"IDirectSound(%p)->Release()\n",this);
 	if (!--(this->ref)) {
 		HeapFree(GetProcessHeap(),0,this);
+		fprintf(stderr,"	IDIrectSound(%p) freed!\n",this);
+		dsound = NULL;
 		return 0;
 	}
 	return this->ref;
@@ -160,7 +391,7 @@
 	IDirectSound_Release,
 	IDirectSound_CreateSoundBuffer,
 	IDirectSound_GetCaps,
-	(void *)6,
+	IDirectSound_DuplicateSoundBuffer,
 	IDirectSound_SetCooperativeLevel,
 	(void *)8,
         (void *)9,
@@ -168,10 +399,98 @@
         (void *)11
 };
 
+void
+DSOUND_thread(void) {
+	int	res,i,j,curleft,playing;
+	short	buf[512];
+
+	while (1) {
+		if (!dsound) {
+			fprintf(stderr,"DSOUND thread killed\n");
+			kill(getpid(),SIGTERM);
+			return;
+		}
+		dsound->lpvtbl->fnAddRef(dsound);
+		memset(buf,0,sizeof(buf));
+		/* FIXME: assumes 16 bit and same format on all buffers
+		 * which must not be the case
+		 */
+		playing = 0;
+		for (i=dsound->nrofbuffers;i--;) {
+
+			dsound->buffers[i]->lpvtbl->fnAddRef(dsound->buffers[i]);
+			if (	dsound->buffers[i]->buflen &&
+				dsound->buffers[i]->playing
+			) {
+				int	playpos = dsound->buffers[i]->playpos/sizeof(short);
+				int	buflen = dsound->buffers[i]->buflen/sizeof(short);
+				short	*xbuf = (short*)(dsound->buffers[i]->buffer);
+
+				playing++;
+				dsound->buffers[i]->playpos = (sizeof(buf)+(playpos<<1))%(buflen<<1);
+				for (j=0;j<sizeof(buf)/sizeof(short);j++)
+					buf[j]+=xbuf[(j+playpos)%buflen];
+			}
+			dsound->buffers[i]->lpvtbl->fnRelease(dsound->buffers[i]);
+		}
+		dsound->lpvtbl->fnRelease(dsound);
+		/*fputc('0'+playing,stderr);*/
+		curleft = 0;
+		while (curleft < sizeof(buf)) {
+			res = write(audiofd,(LPBYTE)buf+curleft,sizeof(buf)-curleft);
+			if (res==-1) {
+				perror("write audiofd");
+				fprintf(stderr,"buf is %p, curleft is %d\n",buf,curleft);
+				kill(getpid(),SIGTERM);
+				break;
+			}
+			curleft+=res;
+		}
+	}
+}
+
+#endif /* HAVE_OSS */
+
 HRESULT WINAPI DirectSoundCreate(LPGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUnkOuter ) {
+#ifdef HAVE_OSS
+	int	xx;
+
 	fprintf(stderr,"DirectSoundCreate(%p,%p,%p)\n",lpGUID,ppDS,pUnkOuter);
+	if (audiofd)
+		return DSERR_ALLOCATED;
+	audiofd = open("/dev/audio",O_WRONLY);
+	if (audiofd==-1) {
+		perror("open /dev/audio");
+		audiofd=0;
+		return DSERR_NODRIVER;
+	}
+	/* make it nonblocking */
+	if (-1==ioctl(audiofd,SNDCTL_DSP_NONBLOCK,NULL)) {
+		perror("ioctl SNDCTL_DSP_NONBLOCK");
+		close(audiofd);
+		audiofd=0;
+		return DSERR_NODRIVER;
+	}
+	if (-1==ioctl(audiofd,SNDCTL_DSP_GETCAPS,&xx)) {
+		perror("ioctl SNDCTL_DSP_GETCAPS");
+		close(audiofd);
+		audiofd=0;
+		return DSERR_NODRIVER;
+	}
+	fprintf(stderr,"SNDCTL_DSP_GETCAPS returned %x\n",xx);
 	*ppDS = (LPDIRECTSOUND)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound));
-	(*ppDS)->ref = 1;
-	(*ppDS)->lpvtbl = &dsvt;
+	(*ppDS)->ref		= 1;
+	(*ppDS)->lpvtbl		= &dsvt;
+	(*ppDS)->buffers	= NULL;
+	(*ppDS)->nrofbuffers	= 0;
+
+	if (!dsound) {
+		dsound = (*ppDS);
+/*		THREAD_CreateSysThread(0,DSOUND_thread); FIXME */
+	}
 	return 0;
+#else
+	MessageBox32A(0,"DirectSound needs the Open Sound System Driver, which has not been found by ./configure.","WINE DirectSound",MB_OK|MB_ICONSTOP);
+	return DSERR_NODRIVER; /* check */
+#endif
 }
diff --git a/multimedia/mmio.c b/multimedia/mmio.c
new file mode 100644
index 0000000..d140fe1
--- /dev/null
+++ b/multimedia/mmio.c
@@ -0,0 +1,674 @@
+/*
+ * MMIO functions
+ *
+ * Copyright 1998 Andrew Taylor
+ *
+ * NOTES:  I/O is still unbuffered;  mmioSetBuffer must be implemented
+ * and mmio{Read,Write,Seek,others?} need buffer support.
+ * Buffering should almost give us memory files for free.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "windows.h"
+#include "win.h"
+#include "heap.h"
+#include "user.h"
+#include "file.h"
+#include "mmsystem.h"
+#include "stddebug.h"
+#include "debug.h"
+#include "xmalloc.h"
+
+/**************************************************************************
+*               mmioDosIOProc           [internal]
+*/
+static LRESULT mmioDosIOProc(LPMMIOINFO16 lpmmioinfo, UINT16 uMessage, LPARAM lParam1, LPARAM lParam2) {
+	dprintf_mmio(stddeb, "mmioDosIOProc(%p, %X, %ld, %ld);\n", lpmmioinfo, uMessage, lParam1, lParam2);
+
+	switch (uMessage) {
+
+		case MMIOM_OPEN: {
+			/* Parameters:
+			 * lParam1 = szFileName parameter from mmioOpen
+			 * lParam2 = unused
+			 * Returns: zero on success, error code on error
+			 * NOTE: lDiskOffset automatically set to zero
+			 */
+
+			OFSTRUCT ofs;
+			LPSTR szFileName = (LPSTR) lParam1;
+
+			if (lpmmioinfo->dwFlags & MMIO_GETTEMP) {
+				dprintf_mmio(stdnimp, "mmioDosIOProc // MMIO_GETTEMP not implemented\n");
+				return MMIOERR_CANNOTOPEN;
+			}
+
+			/* if filename NULL, assume open file handle in adwInfo[0] */
+			if (!szFileName)
+				return 0;
+
+			lpmmioinfo->adwInfo[0] =
+				(DWORD) OpenFile32(szFileName, &ofs, lpmmioinfo->dwFlags);
+			if (lpmmioinfo->adwInfo[0] == -1)
+				return MMIOERR_CANNOTOPEN;
+
+			return 0;
+		}
+
+		case MMIOM_CLOSE: {
+			/* Parameters:
+			 * lParam1 = wFlags parameter from mmioClose
+			 * lParam2 = unused
+			 * Returns: zero on success, error code on error
+			 */
+
+			UINT16 uFlags = (UINT16) lParam1;
+
+			if (uFlags & MMIO_FHOPEN)
+				return 0;
+
+			_lclose32((HFILE32)lpmmioinfo->adwInfo[0]);
+			return 0;
+
+		}
+
+		case MMIOM_READ: {
+			/* Parameters:
+			 * lParam1 = huge pointer to read buffer
+			 * lParam2 = number of bytes to read
+			 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
+			 *	   in wErrorRet)
+			 * NOTE: lDiskOffset should be updated
+			 */
+
+			HPSTR pch = (HPSTR) lParam1;
+			LONG cch = (LONG) lParam2;
+			LONG count;
+
+			count = _lread32((HFILE32)lpmmioinfo->adwInfo[0], pch, cch);
+			if (count != -1)
+				lpmmioinfo->lDiskOffset += count;
+
+			return count;
+		}
+
+		case MMIOM_WRITE:
+		case MMIOM_WRITEFLUSH: { 
+			/* no internal buffering, so WRITEFLUSH handled same as WRITE */
+
+			/* Parameters:
+			 * lParam1 = huge pointer to write buffer
+			 * lParam2 = number of bytes to write
+			 * Returns: number of bytes written, -1 for error (error code in
+			 *		wErrorRet)
+			 * NOTE: lDiskOffset should be updated
+			 */
+
+			HPSTR pch = (HPSTR) lParam1;
+			LONG cch = (LONG) lParam2;
+			LONG count;
+
+			count = _hwrite16((HFILE32)lpmmioinfo->adwInfo[0], pch, cch);
+			if (count != -1)
+				lpmmioinfo->lDiskOffset += count;
+
+			return count;
+		}
+
+		case MMIOM_SEEK: {
+            /* Parameters:
+             * lParam1 = new position
+             * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
+             * Returns: new file postion, -1 on error
+             * NOTE: lDiskOffset should be updated
+             */
+
+            LONG Offset = (LONG) lParam1; 
+            LONG Whence = (LONG) lParam2; 
+            LONG pos;
+
+            pos = _llseek32((HFILE32)lpmmioinfo->adwInfo[0], Offset, Whence);
+            if (pos != -1)
+                lpmmioinfo->lDiskOffset = pos;
+
+            return pos;
+		}
+		  
+		case MMIOM_RENAME: {
+            /* Parameters:
+             * lParam1 = old name
+             * lParam2 = new name
+             * Returns: zero on success, non-zero on failure
+             */
+
+            dprintf_mmio(stddeb, "mmioDosIOProc: MMIOM_RENAME unimplemented\n");
+            return MMIOERR_FILENOTFOUND;
+		}
+
+		default:
+			dprintf_mmio(stddeb, "mmioDosIOProc: unexpected message %u\n", uMessage);
+			return 0;
+	}
+	
+	return 0;
+}
+
+/**************************************************************************
+*               mmioDosIOProc           [internal]
+*/
+static LRESULT mmioMemIOProc(LPMMIOINFO16 lpmmioinfo, UINT16 uMessage, LPARAM lParam1, LPARAM lParam2) {
+	return 0;
+}
+
+/**************************************************************************
+ * 				mmioOpenW       		[WINMM.123]
+ */
+HMMIO32 WINAPI mmioOpen32W(LPWSTR szFileName, MMIOINFO32 * lpmmioinfo,
+                          DWORD dwOpenFlags)
+{
+	LPSTR	szFn = HEAP_strdupWtoA(GetProcessHeap(),0,szFileName);
+	HMMIO32 ret = mmioOpen16(szFn,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags);
+
+	HeapFree(GetProcessHeap(),0,szFn);
+	return ret;
+}
+
+/**************************************************************************
+ * 				mmioOpenA       		[WINMM.122]
+ */
+HMMIO32 WINAPI mmioOpen32A(LPSTR szFileName, MMIOINFO32 * lpmmioinfo,
+                          DWORD dwOpenFlags)
+{
+	return mmioOpen16(szFileName,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags);
+}
+
+/**************************************************************************
+ * 				mmioOpen       		[MMSYSTEM.1210]
+ */
+HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16 * lpmmioinfo,
+                          DWORD dwOpenFlags)
+{
+	LPMMIOINFO16 lpmminfo;
+	HMMIO16 hmmio;
+	UINT16 result;
+
+	dprintf_mmio(stddeb, "mmioOpen('%s', %p, %08lX);\n", szFileName, lpmmioinfo, dwOpenFlags);
+
+	hmmio = GlobalAlloc16(GHND, sizeof(MMIOINFO16));
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL)
+		return 0;
+	memset(lpmminfo, 0, sizeof(MMIOINFO16));
+
+	/* assume DOS file if not otherwise specified */
+	if (!lpmmioinfo ||
+		(lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL)) {
+
+		lpmminfo->fccIOProc = mmioFOURCC('D', 'O', 'S', ' ');
+		lpmminfo->pIOProc = (LPMMIOPROC16) mmioDosIOProc;
+	}
+	/* if just the four character code is present, look up IO proc */
+	else if (lpmmioinfo->pIOProc == NULL) {
+
+		lpmminfo->fccIOProc = lpmmioinfo->fccIOProc;
+		lpmminfo->pIOProc = mmioInstallIOProc16(lpmmioinfo->fccIOProc, NULL, MMIO_FINDPROC);
+
+	} 
+	/* if IO proc specified, use it and specified four character code */
+	else {
+
+		lpmminfo->fccIOProc = lpmmioinfo->fccIOProc;
+		lpmminfo->pIOProc = lpmmioinfo->pIOProc;
+	}
+
+	if (dwOpenFlags & MMIO_ALLOCBUF) {
+		if ((result = mmioSetBuffer(hmmio, NULL, MMIO_DEFAULTBUFFER, 0))) {
+			if (lpmmioinfo)
+				lpmmioinfo->wErrorRet = result;
+			return 0;
+		}
+	}
+
+	lpmminfo->hmmio = hmmio;
+
+	/* call IO proc to actually open file */
+	result = (UINT16) mmioSendMessage(hmmio, MMIOM_OPEN, (LPARAM) szFileName, (LPARAM) 0);
+
+	GlobalUnlock16(hmmio);
+
+	if (result != 0) {
+		GlobalFree16(hmmio);
+		return 0;
+	}
+
+	return hmmio;
+}
+
+    
+/**************************************************************************
+* 				mmioClose      		[MMSYSTEM.1211]
+*/
+UINT16 WINAPI mmioClose(HMMIO16 hmmio, UINT16 uFlags)
+{
+	LPMMIOINFO16 lpmminfo;
+	UINT16 result;
+
+	dprintf_mmio(stddeb, "mmioClose(%04X, %04X);\n", hmmio, uFlags);
+
+	lpmminfo = (LPMMIOINFO16) GlobalLock16(hmmio);
+	if (lpmminfo == NULL)
+		return 0;
+
+	/* flush the file - if error reported, ignore */
+	if (mmioFlush(hmmio, MMIO_EMPTYBUF) != 0)
+		lpmminfo->dwFlags &= ~MMIO_DIRTY;
+
+	result = (UINT16) mmioSendMessage(hmmio, MMIOM_CLOSE, (LPARAM) uFlags, (LPARAM) 0);
+
+	mmioSetBuffer(hmmio, NULL, 0, 0);
+
+	GlobalUnlock16(hmmio);
+	GlobalFree16(hmmio);
+
+	return result;
+}
+
+
+
+/**************************************************************************
+* 				mmioRead	       	[MMSYSTEM.1212]
+*/
+LONG WINAPI mmioRead(HMMIO16 hmmio, HPSTR pch, LONG cch)
+{
+	LONG count;
+	LPMMIOINFO16 lpmminfo;
+
+	dprintf_mmio(stddeb, "mmioRead(%04X, %p, %ld);\n", hmmio, pch, cch);
+
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL)
+		return -1;
+
+	count = mmioSendMessage(hmmio, MMIOM_READ, (LPARAM) pch, (LPARAM) cch);
+
+	GlobalUnlock16(hmmio);
+	dprintf_mmio(stddeb, "mmioRead // count=%ld\n", count);
+	return count;
+}
+
+
+
+/**************************************************************************
+* 				mmioWrite      		[MMSYSTEM.1213]
+*/
+LONG WINAPI mmioWrite(HMMIO16 hmmio, HPCSTR pch, LONG cch)
+{
+	LONG count;
+	LPMMIOINFO16 lpmminfo;
+
+	dprintf_mmio(stddeb, "mmioWrite(%04X, %p, %ld);\n", hmmio, pch, cch);
+
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL)
+		return -1;
+
+	count = mmioSendMessage(hmmio, MMIOM_WRITE, (LPARAM) pch, (LPARAM) cch);
+
+	GlobalUnlock16(hmmio);
+	dprintf_mmio(stddeb, "mmioWrite // count=%ld\n", count);
+	return count;
+}
+
+/**************************************************************************
+* 				mmioSeek       		[MMSYSTEM.1214]
+*/
+LONG WINAPI mmioSeek(HMMIO16 hmmio, LONG lOffset, int iOrigin)
+{
+	int offset;
+	LPMMIOINFO16 lpmminfo;
+
+	dprintf_mmio(stddeb, "mmioSeek(%04X, %08lX, %d);\n", hmmio, lOffset, iOrigin);
+
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL)
+		return 0;
+
+    offset = mmioSendMessage(hmmio, MMIOM_SEEK, (LPARAM) lOffset, (LPARAM) iOrigin);
+
+	GlobalUnlock16(hmmio);
+	return offset;
+}
+
+/**************************************************************************
+* 				mmioGetInfo	       	[MMSYSTEM.1215]
+*/
+UINT16 WINAPI mmioGetInfo(HMMIO16 hmmio, MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
+{
+	LPMMIOINFO16	lpmminfo;
+	dprintf_mmio(stddeb, "mmioGetInfo\n");
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL) return 0;
+	memcpy(lpmmioinfo, lpmminfo, sizeof(MMIOINFO16));
+	GlobalUnlock16(hmmio);
+	return 0;
+}
+
+/**************************************************************************
+* 				mmioSetInfo    		[MMSYSTEM.1216]
+*/
+UINT16 WINAPI mmioSetInfo(HMMIO16 hmmio, const MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
+{
+	LPMMIOINFO16	lpmminfo;
+	dprintf_mmio(stddeb, "mmioSetInfo\n");
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL) return 0;
+	GlobalUnlock16(hmmio);
+	return 0;
+}
+
+/**************************************************************************
+* 				mmioSetBuffer		[MMSYSTEM.1217]
+*/
+UINT16 WINAPI mmioSetBuffer(HMMIO16 hmmio, LPSTR pchBuffer, 
+                            LONG cchBuffer, UINT16 uFlags)
+{
+	dprintf_mmio(stddeb, "mmioSetBuffer // empty stub \n");
+	return 0;
+}
+
+/**************************************************************************
+* 				mmioFlush      		[MMSYSTEM.1218]
+*/
+UINT16 WINAPI mmioFlush(HMMIO16 hmmio, UINT16 uFlags)
+{
+	LPMMIOINFO16	lpmminfo;
+	dprintf_mmio(stddeb, "mmioFlush(%04X, %04X)\n", hmmio, uFlags);
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL) return 0;
+	GlobalUnlock16(hmmio);
+	return 0;
+}
+
+/**************************************************************************
+* 				mmioAdvance    		[MMSYSTEM.1219]
+*/
+UINT16 WINAPI mmioAdvance(HMMIO16 hmmio, MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
+{
+	int		count = 0;
+	LPMMIOINFO16	lpmminfo;
+	dprintf_mmio(stddeb, "mmioAdvance\n");
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL) return 0;
+	if (uFlags == MMIO_READ) {
+		count = _lread32(LOWORD(lpmminfo->adwInfo[0]), 
+			lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer);
+		}
+	if (uFlags == MMIO_WRITE) {
+		count = _lwrite32(LOWORD(lpmminfo->adwInfo[0]),
+			lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer);
+		}
+	lpmmioinfo->pchNext	+= count;
+	GlobalUnlock16(hmmio);
+	lpmminfo->lDiskOffset = _llseek32((HFILE32)lpmminfo->adwInfo[0], 0, SEEK_CUR);
+	return 0;
+}
+
+/**************************************************************************
+ * 				mmioStringToFOURCCA	[WINMM.131]
+ */
+FOURCC WINAPI mmioStringToFOURCC32A(LPCSTR sz, UINT32 uFlags)
+{
+	return mmioStringToFOURCC16(sz,uFlags);
+}
+
+/**************************************************************************
+ * 				mmioStringToFOURCCW	[WINMM.132]
+ */
+FOURCC WINAPI mmioStringToFOURCC32W(LPCWSTR sz, UINT32 uFlags)
+{
+	LPSTR	szA = HEAP_strdupWtoA(GetProcessHeap(),0,sz);
+	FOURCC	ret = mmioStringToFOURCC32A(szA,uFlags);
+
+	HeapFree(GetProcessHeap(),0,szA);
+	return ret;
+}
+
+/**************************************************************************
+ * 				mmioStringToFOURCC	[MMSYSTEM.1220]
+ */
+FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags)
+{
+	dprintf_mmio(stddeb, "mmioStringToFOURCC // empty stub \n");
+	return 0;
+}
+
+/**************************************************************************
+* 				mmioInstallIOProc16	[MMSYSTEM.1221]
+*/
+LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, 
+                                        LPMMIOPROC16 pIOProc, DWORD dwFlags)
+{
+	dprintf_mmio(stddeb, "mmioInstallIOProc(%ld, %p, %08lX)\n",
+				 fccIOProc, pIOProc, dwFlags);
+
+	if (dwFlags & MMIO_GLOBALPROC) {
+		fprintf(stdnimp, "mmioInstallIOProc: global procedures not "
+				"implemented\n");
+	}
+
+	/* just handle the known procedures for now */
+	switch(dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
+		case MMIO_INSTALLPROC:
+			return NULL;
+		case MMIO_REMOVEPROC:
+			return NULL;
+		case MMIO_FINDPROC:
+			if (fccIOProc == FOURCC_DOS)
+				return (LPMMIOPROC16) mmioDosIOProc;
+			else if (fccIOProc == FOURCC_MEM)
+				return (LPMMIOPROC16) mmioMemIOProc;
+			else
+				return NULL;
+		default:
+			return NULL;
+	}
+}
+
+/**************************************************************************
+ * 				mmioInstallIOProc32A   [WINMM.120]
+ */
+LPMMIOPROC32 WINAPI mmioInstallIOProc32A(FOURCC fccIOProc, 
+                                         LPMMIOPROC32 pIOProc, DWORD dwFlags)
+{
+	dprintf_mmio(stddeb, "mmioInstallIOProcA (%c%c%c%c,%p,0x%08lx)// empty stub \n",
+                     (char)((fccIOProc&0xff000000)>>24),
+                     (char)((fccIOProc&0x00ff0000)>>16),
+                     (char)((fccIOProc&0x0000ff00)>> 8),
+                     (char)(fccIOProc&0x000000ff),
+                     pIOProc, dwFlags );
+	return 0;
+}
+
+/**************************************************************************
+* 				mmioSendMessage		[MMSYSTEM.1222]
+*/
+LRESULT WINAPI mmioSendMessage(HMMIO16 hmmio, UINT16 uMessage,
+                               LPARAM lParam1, LPARAM lParam2)
+{
+	LPMMIOINFO16 lpmminfo;
+	LRESULT result;
+	const char *msg = NULL;
+
+#ifdef DEBUG_RUNTIME
+	switch (uMessage) {
+#define msgname(x) case x: msg = #x; break;
+		msgname(MMIOM_OPEN);
+		msgname(MMIOM_CLOSE);
+		msgname(MMIOM_READ);
+		msgname(MMIOM_WRITE);
+		msgname(MMIOM_WRITEFLUSH);
+		msgname(MMIOM_SEEK);
+		msgname(MMIOM_RENAME);
+#undef msgname
+	}
+#endif
+
+	if (msg)
+		dprintf_mmio(stddeb, "mmioSendMessage(%04X, %s, %ld, %ld)\n",
+					 hmmio, msg, lParam1, lParam2);
+	else
+		dprintf_mmio(stddeb, "mmioSendMessage(%04X, %u, %ld, %ld)\n",
+					 hmmio, uMessage, lParam1, lParam2);
+	
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+
+	if (lpmminfo && lpmminfo->pIOProc)
+		result = (*lpmminfo->pIOProc)((LPSTR)lpmminfo, uMessage, lParam1, lParam2);
+	else
+		result = MMSYSERR_INVALPARAM;
+
+	GlobalUnlock16(hmmio);
+
+	return result;
+}
+
+/**************************************************************************
+* 				mmioDescend	       	[MMSYSTEM.1223]
+*/
+UINT16 WINAPI mmioDescend(HMMIO16 hmmio, MMCKINFO * lpck,
+                          const MMCKINFO * lpckParent, UINT16 uFlags)
+{
+	DWORD	dwfcc, dwOldPos;
+
+	dprintf_mmio(stddeb, "mmioDescend(%04X, %p, %p, %04X);\n", 
+				hmmio, lpck, lpckParent, uFlags);
+
+	if (lpck == NULL)
+	    return 0;
+
+	dwfcc = lpck->ckid;
+	dprintf_mmio(stddeb, "mmioDescend // dwfcc=%08lX\n", dwfcc);
+
+	dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
+	dprintf_mmio(stddeb, "mmioDescend // dwOldPos=%ld\n", dwOldPos);
+
+	if (lpckParent != NULL) {
+		dprintf_mmio(stddeb, "mmioDescend // seek inside parent at %ld !\n", lpckParent->dwDataOffset);
+		dwOldPos = mmioSeek(hmmio, lpckParent->dwDataOffset, SEEK_SET);
+	}
+/*
+
+   It seems to be that FINDRIFF should not be treated the same as the 
+   other FINDxxx so I treat it as a MMIO_FINDxxx
+
+	if ((uFlags & MMIO_FINDCHUNK) || (uFlags & MMIO_FINDRIFF) || 
+		(uFlags & MMIO_FINDLIST)) {
+*/
+	if ((uFlags & MMIO_FINDCHUNK) || (uFlags & MMIO_FINDLIST)) {
+		dprintf_mmio(stddeb, "mmioDescend // MMIO_FINDxxxx dwfcc=%08lX !\n", dwfcc);
+		while (TRUE) {
+		        LONG ix;
+
+			ix = mmioRead(hmmio, (LPSTR)lpck, sizeof(MMCKINFO));
+			dprintf_mmio(stddeb, "mmioDescend // after _lread32 ix = %ld req = %d, errno = %d\n",ix,sizeof(MMCKINFO),errno);
+			if (ix < sizeof(MMCKINFO)) {
+
+				mmioSeek(hmmio, dwOldPos, SEEK_SET);
+				dprintf_mmio(stddeb, "mmioDescend // return ChunkNotFound\n");
+				return MMIOERR_CHUNKNOTFOUND;
+			}
+			dprintf_mmio(stddeb, "mmioDescend // dwfcc=%08lX ckid=%08lX cksize=%08lX !\n", 
+									dwfcc, lpck->ckid, lpck->cksize);
+			if (dwfcc == lpck->ckid)
+				break;
+
+			dwOldPos += lpck->cksize + 2 * sizeof(DWORD);
+			if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) 
+				dwOldPos += sizeof(DWORD);
+			mmioSeek(hmmio, dwOldPos, SEEK_SET);
+		}
+	}
+	else {
+		if (mmioRead(hmmio, (LPSTR)lpck, sizeof(MMCKINFO)) < sizeof(MMCKINFO)) {
+			mmioSeek(hmmio, dwOldPos, SEEK_SET);
+			dprintf_mmio(stddeb, "mmioDescend // return ChunkNotFound 2nd\n");
+			return MMIOERR_CHUNKNOTFOUND;
+		}
+	}
+	lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
+	if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) 
+		lpck->dwDataOffset += sizeof(DWORD);
+	mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET);
+
+	dprintf_mmio(stddeb, "mmioDescend // lpck->ckid=%08lX lpck->cksize=%ld !\n", 
+								lpck->ckid, lpck->cksize);
+	dprintf_mmio(stddeb, "mmioDescend // lpck->fccType=%08lX !\n", lpck->fccType);
+
+	return 0;
+}
+
+/**************************************************************************
+* 				mmioAscend     		[MMSYSTEM.1224]
+*/
+UINT16 WINAPI mmioAscend(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
+{
+	dprintf_mmio(stddeb, "mmioAscend // empty stub !\n");
+	return 0;
+}
+
+/**************************************************************************
+* 				mmioCreateChunk		[MMSYSTEM.1225]
+*/
+UINT16 WINAPI mmioCreateChunk(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
+{
+	dprintf_mmio(stddeb, "mmioCreateChunk // empty stub \n");
+	return 0;
+}
+
+
+/**************************************************************************
+* 				mmioRename     		[MMSYSTEM.1226]
+*/
+UINT16 WINAPI mmioRename(LPCSTR szFileName, LPCSTR szNewFileName,
+                         MMIOINFO16 * lpmmioinfo, DWORD dwRenameFlags)
+{
+	UINT16 result;
+	LPMMIOINFO16 lpmminfo;
+	HMMIO16 hmmio;
+
+	dprintf_mmio(stddeb, "mmioRename('%s', '%s', %p, %08lX);\n",
+				 szFileName, szNewFileName, lpmmioinfo, dwRenameFlags);
+
+	hmmio = GlobalAlloc16(GHND, sizeof(MMIOINFO16));
+	lpmminfo = (LPMMIOINFO16) GlobalLock16(hmmio);
+
+	if (lpmmioinfo)
+		memcpy(lpmminfo, lpmmioinfo, sizeof(MMIOINFO16));
+	
+	/* assume DOS file if not otherwise specified */
+	if (lpmminfo->fccIOProc == 0 && lpmminfo->pIOProc == NULL) {
+
+		lpmminfo->fccIOProc = mmioFOURCC('D', 'O', 'S', ' ');
+		lpmminfo->pIOProc = (LPMMIOPROC16) mmioDosIOProc;
+
+	}
+	/* if just the four character code is present, look up IO proc */
+	else if (lpmminfo->pIOProc == NULL) {
+
+		lpmminfo->pIOProc = mmioInstallIOProc16(lpmminfo->fccIOProc, NULL, MMIO_FINDPROC);
+
+	} 
+	/* (if IO proc specified, use it and specified four character code) */
+
+	result = (UINT16) mmioSendMessage(hmmio, MMIOM_RENAME, (LPARAM) szFileName, (LPARAM) szNewFileName);
+	
+	GlobalUnlock16(hmmio);
+	GlobalFree16(hmmio);
+
+	return result;
+}
+
diff --git a/multimedia/mmsystem.c b/multimedia/mmsystem.c
index ad9d211..4f1e47c 100644
--- a/multimedia/mmsystem.c
+++ b/multimedia/mmsystem.c
@@ -3647,370 +3647,6 @@
 }
 
 /**************************************************************************
- * 				mmioOpenW       		[WINMM.123]
- */
-HMMIO32 WINAPI mmioOpen32W(LPWSTR szFileName, MMIOINFO32 * lpmmioinfo,
-                          DWORD dwOpenFlags)
-{
-	LPSTR	szFn = HEAP_strdupWtoA(GetProcessHeap(),0,szFileName);
-	HMMIO32 ret = mmioOpen16(szFn,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags);
-
-	HeapFree(GetProcessHeap(),0,szFn);
-	return ret;
-}
-
-/**************************************************************************
- * 				mmioOpenA       		[WINMM.122]
- */
-HMMIO32 WINAPI mmioOpen32A(LPSTR szFileName, MMIOINFO32 * lpmmioinfo,
-                          DWORD dwOpenFlags)
-{
-	return mmioOpen16(szFileName,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags);
-}
-
-/**************************************************************************
- * 				mmioOpen       		[MMSYSTEM.1210]
- */
-HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16 * lpmmioinfo,
-                          DWORD dwOpenFlags)
-{
-        HFILE32 hFile;
-	HMMIO16		hmmio;
-	OFSTRUCT	ofs;
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioOpen('%s', %p, %08lX);\n", szFileName, lpmmioinfo, dwOpenFlags);
-        if (!szFileName)
-        {
-            /* FIXME: should load memory file if szFileName == NULL */
-            fprintf(stderr, "WARNING: mmioOpen(): szFileName == NULL (memory file ???)\n");
-            return 0;
- 	}
-	hFile = OpenFile32(szFileName, &ofs, dwOpenFlags);
-	if (hFile == -1) return 0;
-	hmmio = GlobalAlloc16(GMEM_MOVEABLE, sizeof(MMIOINFO16));
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) return 0;
-	memset(lpmminfo, 0, sizeof(MMIOINFO16));
-	lpmminfo->hmmio = hmmio;
-	lpmminfo->dwReserved2 = hFile;
-	GlobalUnlock16(hmmio);
-	dprintf_mmio(stddeb, "mmioOpen // return hmmio=%04X\n", hmmio);
-	return hmmio;
-}
-
-    
-/**************************************************************************
-* 				mmioClose      		[MMSYSTEM.1211]
-*/
-UINT16 WINAPI mmioClose(HMMIO16 hmmio, UINT16 uFlags)
-{
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioClose(%04X, %04X);\n", hmmio, uFlags);
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) return 0;
-	_lclose32((HFILE32)lpmminfo->dwReserved2);
-	GlobalUnlock16(hmmio);
-	GlobalFree16(hmmio);
-	return 0;
-}
-
-
-
-/**************************************************************************
-* 				mmioRead	       	[MMSYSTEM.1212]
-*/
-LONG WINAPI mmioRead(HMMIO16 hmmio, HPSTR pch, LONG cch)
-{
-	LONG		count;
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioRead(%04X, %p, %ld);\n", hmmio, pch, cch);
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) return 0;
-	count = _lread32(LOWORD(lpmminfo->dwReserved2), pch, cch);
-	GlobalUnlock16(hmmio);
-	dprintf_mmio(stddeb, "mmioRead // count=%ld\n", count);
-	return count;
-}
-
-
-
-/**************************************************************************
-* 				mmioWrite      		[MMSYSTEM.1213]
-*/
-LONG WINAPI mmioWrite(HMMIO16 hmmio, HPCSTR pch, LONG cch)
-{
-	LONG		count;
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioWrite(%04X, %p, %ld);\n", hmmio, pch, cch);
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) return 0;
-	count = _lwrite32(LOWORD(lpmminfo->dwReserved2), (LPSTR)pch, cch);
-	GlobalUnlock16(hmmio);
-	return count;
-}
-
-/**************************************************************************
-* 				mmioSeek       		[MMSYSTEM.1214]
-*/
-LONG WINAPI mmioSeek(HMMIO16 hmmio, LONG lOffset, int iOrigin)
-{
-	int		count;
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioSeek(%04X, %08lX, %d);\n", hmmio, lOffset, iOrigin);
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) {
-		dprintf_mmio(stddeb, "mmioSeek // can't lock hmmio=%04X !\n", hmmio);
-		return 0;
-		}
-	count = _llseek32((HFILE32)lpmminfo->dwReserved2, lOffset, iOrigin);
-	GlobalUnlock16(hmmio);
-	return count;
-}
-
-/**************************************************************************
-* 				mmioGetInfo	       	[MMSYSTEM.1215]
-*/
-UINT16 WINAPI mmioGetInfo(HMMIO16 hmmio, MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
-{
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioGetInfo\n");
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) return 0;
-	memcpy(lpmmioinfo, lpmminfo, sizeof(MMIOINFO16));
-	GlobalUnlock16(hmmio);
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioSetInfo    		[MMSYSTEM.1216]
-*/
-UINT16 WINAPI mmioSetInfo(HMMIO16 hmmio, const MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
-{
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioSetInfo\n");
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) return 0;
-	GlobalUnlock16(hmmio);
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioSetBuffer		[MMSYSTEM.1217]
-*/
-UINT16 WINAPI mmioSetBuffer(HMMIO16 hmmio, LPSTR pchBuffer, 
-                            LONG cchBuffer, UINT16 uFlags)
-{
-	dprintf_mmio(stddeb, "mmioSetBuffer // empty stub \n");
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioFlush      		[MMSYSTEM.1218]
-*/
-UINT16 WINAPI mmioFlush(HMMIO16 hmmio, UINT16 uFlags)
-{
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioFlush(%04X, %04X)\n", hmmio, uFlags);
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) return 0;
-	GlobalUnlock16(hmmio);
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioAdvance    		[MMSYSTEM.1219]
-*/
-UINT16 WINAPI mmioAdvance(HMMIO16 hmmio, MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
-{
-	int		count = 0;
-	LPMMIOINFO16	lpmminfo;
-	dprintf_mmio(stddeb, "mmioAdvance\n");
-	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
-	if (lpmminfo == NULL) return 0;
-	if (uFlags == MMIO_READ) {
-		count = _lread32(LOWORD(lpmminfo->dwReserved2), 
-			lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer);
-		}
-	if (uFlags == MMIO_WRITE) {
-		count = _lwrite32(LOWORD(lpmminfo->dwReserved2),
-			lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer);
-		}
-	lpmmioinfo->pchNext	+= count;
-	GlobalUnlock16(hmmio);
-	lpmminfo->lDiskOffset = _llseek32((HFILE32)lpmminfo->dwReserved2, 0, SEEK_CUR);
-	return 0;
-}
-
-/**************************************************************************
- * 				mmioStringToFOURCCW	[WINMM.131]
- */
-FOURCC WINAPI mmioStringToFOURCC32A(LPCSTR sz, UINT32 uFlags)
-{
-	return mmioStringToFOURCC16(sz,uFlags);
-}
-
-/**************************************************************************
- * 				mmioStringToFOURCCW	[WINMM.132]
- */
-FOURCC WINAPI mmioStringToFOURCC32W(LPCWSTR sz, UINT32 uFlags)
-{
-	LPSTR	szA = HEAP_strdupWtoA(GetProcessHeap(),0,sz);
-	FOURCC	ret = mmioStringToFOURCC32A(szA,uFlags);
-
-	HeapFree(GetProcessHeap(),0,szA);
-	return ret;
-}
-
-/**************************************************************************
- * 				mmioStringToFOURCC	[MMSYSTEM.1220]
- */
-FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags)
-{
-	dprintf_mmio(stddeb, "mmioStringToFOURCC // empty stub \n");
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioInstallIOProc16	[MMSYSTEM.1221]
-*/
-LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, 
-                                        LPMMIOPROC16 pIOProc, DWORD dwFlags)
-{
-	dprintf_mmio(stddeb, "mmioInstallIOProc // empty stub \n");
-	return 0;
-}
-
-/**************************************************************************
- * 				mmioInstallIOProc32A   [WINMM.120]
- */
-LPMMIOPROC32 WINAPI mmioInstallIOProc32A(FOURCC fccIOProc, 
-                                         LPMMIOPROC32 pIOProc, DWORD dwFlags)
-{
-	dprintf_mmio(stddeb, "mmioInstallIOProcA (%c%c%c%c,%p,0x%08lx)// empty stub \n",
-                     (char)((fccIOProc&0xff000000)>>24),
-                     (char)((fccIOProc&0x00ff0000)>>16),
-                     (char)((fccIOProc&0x0000ff00)>> 8),
-                     (char)(fccIOProc&0x000000ff),
-                     pIOProc, dwFlags );
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioSendMessage		[MMSYSTEM.1222]
-*/
-LRESULT WINAPI mmioSendMessage(HMMIO16 hmmio, UINT16 uMessage,
-                               LPARAM lParam1, LPARAM lParam2)
-{
-	dprintf_mmio(stddeb, "mmioSendMessage // empty stub \n");
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioDescend	       	[MMSYSTEM.1223]
-*/
-UINT16 WINAPI mmioDescend(HMMIO16 hmmio, MMCKINFO * lpck,
-                          const MMCKINFO * lpckParent, UINT16 uFlags)
-{
-	DWORD	dwfcc, dwOldPos;
-
-	dprintf_mmio(stddeb, "mmioDescend(%04X, %p, %p, %04X);\n", 
-				hmmio, lpck, lpckParent, uFlags);
-
-	if (lpck == NULL)
-	    return 0;
-
-	dwfcc = lpck->ckid;
-	dprintf_mmio(stddeb, "mmioDescend // dwfcc=%08lX\n", dwfcc);
-
-	dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
-	dprintf_mmio(stddeb, "mmioDescend // dwOldPos=%ld\n", dwOldPos);
-
-	if (lpckParent != NULL) {
-		dprintf_mmio(stddeb, "mmioDescend // seek inside parent at %ld !\n", lpckParent->dwDataOffset);
-		dwOldPos = mmioSeek(hmmio, lpckParent->dwDataOffset, SEEK_SET);
-	}
-/*
-
-   It seems to be that FINDRIFF should not be treated the same as the 
-   other FINDxxx so I treat it as a MMIO_FINDxxx
-
-	if ((uFlags & MMIO_FINDCHUNK) || (uFlags & MMIO_FINDRIFF) || 
-		(uFlags & MMIO_FINDLIST)) {
-*/
-	if ((uFlags & MMIO_FINDCHUNK) || (uFlags & MMIO_FINDLIST)) {
-		dprintf_mmio(stddeb, "mmioDescend // MMIO_FINDxxxx dwfcc=%08lX !\n", dwfcc);
-		while (TRUE) {
-		        LONG ix;
-
-			ix = mmioRead(hmmio, (LPSTR)lpck, sizeof(MMCKINFO));
-			dprintf_mmio(stddeb, "mmioDescend // after _lread32 ix = %ld req = %d, errno = %d\n",ix,sizeof(MMCKINFO),errno);
-			if (ix < sizeof(MMCKINFO)) {
-
-				mmioSeek(hmmio, dwOldPos, SEEK_SET);
-				dprintf_mmio(stddeb, "mmioDescend // return ChunkNotFound\n");
-				return MMIOERR_CHUNKNOTFOUND;
-			}
-			dprintf_mmio(stddeb, "mmioDescend // dwfcc=%08lX ckid=%08lX cksize=%08lX !\n", 
-									dwfcc, lpck->ckid, lpck->cksize);
-			if (dwfcc == lpck->ckid)
-				break;
-
-			dwOldPos += lpck->cksize + 2 * sizeof(DWORD);
-			if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) 
-				dwOldPos += sizeof(DWORD);
-			mmioSeek(hmmio, dwOldPos, SEEK_SET);
-		}
-	}
-	else {
-		if (mmioRead(hmmio, (LPSTR)lpck, sizeof(MMCKINFO)) < sizeof(MMCKINFO)) {
-			mmioSeek(hmmio, dwOldPos, SEEK_SET);
-			dprintf_mmio(stddeb, "mmioDescend // return ChunkNotFound 2nd\n");
-			return MMIOERR_CHUNKNOTFOUND;
-		}
-	}
-	lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
-	if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) 
-		lpck->dwDataOffset += sizeof(DWORD);
-	mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET);
-
-	dprintf_mmio(stddeb, "mmioDescend // lpck->ckid=%08lX lpck->cksize=%ld !\n", 
-								lpck->ckid, lpck->cksize);
-	dprintf_mmio(stddeb, "mmioDescend // lpck->fccType=%08lX !\n", lpck->fccType);
-
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioAscend     		[MMSYSTEM.1224]
-*/
-UINT16 WINAPI mmioAscend(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
-{
-	dprintf_mmio(stddeb, "mmioAscend // empty stub !\n");
-	return 0;
-}
-
-/**************************************************************************
-* 				mmioCreateChunk		[MMSYSTEM.1225]
-*/
-UINT16 WINAPI mmioCreateChunk(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
-{
-	dprintf_mmio(stddeb, "mmioCreateChunk // empty stub \n");
-	return 0;
-}
-
-
-/**************************************************************************
-* 				mmioRename     		[MMSYSTEM.1226]
-*/
-UINT16 WINAPI mmioRename(LPCSTR szFileName, LPCSTR szNewFileName,
-                         MMIOINFO16 * lpmmioinfo, DWORD dwRenameFlags)
-{
-	dprintf_mmio(stddeb, "mmioRename('%s', '%s', %p, %08lX); // empty stub \n",
-			szFileName, szNewFileName, lpmmioinfo, dwRenameFlags);
-	return 0;
-}
-
-/**************************************************************************
 * 				DrvOpen	       		[MMSYSTEM.1100]
 */
 HDRVR16 WINAPI DrvOpen(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam)
diff --git a/objects/bitmap.c b/objects/bitmap.c
index 4092719..3290ae7 100644
--- a/objects/bitmap.c
+++ b/objects/bitmap.c
@@ -26,9 +26,6 @@
   /* GCs used for B&W and color bitmap operations */
 GC BITMAP_monoGC = 0, BITMAP_colorGC = 0;
 
-extern void CLIPPING_UpdateGCRegion( DC * dc );  /* objects/clipping.c */
-
-
 /***********************************************************************
  *           XPutImage_wrapper
  *
diff --git a/objects/clipping.c b/objects/clipping.c
index d417c71..7f9acb2 100644
--- a/objects/clipping.c
+++ b/objects/clipping.c
@@ -505,6 +505,8 @@
     HRGN32 saved;
     RGNOBJ *obj, *savedObj;
     DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    INT16 ret;
+
     if (!dc) return ERROR;    
     if (!dc->w.hVisRgn)
     {
@@ -533,6 +535,7 @@
     dc->w.hVisRgn = saved;
     CLIPPING_UpdateGCRegion( dc );
     GDI_HEAP_UNLOCK( hdc );
+    ret = savedObj->rgn->type; /* FIXME */
     GDI_HEAP_UNLOCK( saved );
-    return savedObj->xrgn ? COMPLEXREGION : NULLREGION;
+    return ret;
 }
diff --git a/objects/cursoricon.c b/objects/cursoricon.c
index 2ec3b59..a7e77c4 100644
--- a/objects/cursoricon.c
+++ b/objects/cursoricon.c
@@ -42,6 +42,7 @@
 #include "debug.h"
 #include "task.h"
 #include "user.h"
+#include "keyboard.h"
 
 extern UINT16 COLOR_GetSystemPaletteSize();
 
@@ -1243,6 +1244,18 @@
     {
 	pt->x = childX;
 	pt->y = childY;
+        if (mousebut & Button1Mask)
+            AsyncMouseButtonsStates[0] = MouseButtonsStates[0] = TRUE;
+        else
+            MouseButtonsStates[0] = FALSE;
+        if (mousebut & Button2Mask)
+            AsyncMouseButtonsStates[1] = MouseButtonsStates[1] = TRUE;
+        else       
+            MouseButtonsStates[1] = FALSE;
+        if (mousebut & Button3Mask)
+            AsyncMouseButtonsStates[2] = MouseButtonsStates[2] = TRUE;
+        else
+            MouseButtonsStates[2] = FALSE;
     }
     dprintf_cursor(stddeb, "GetCursorPos: ret=%d,%d\n", pt->x, pt->y );
 }
diff --git a/objects/dib.c b/objects/dib.c
index 0f1ef17..8955624 100644
--- a/objects/dib.c
+++ b/objects/dib.c
@@ -1420,6 +1420,8 @@
 	  hdc,bmi->bmiHeader.biWidth,bmi->bmiHeader.biHeight,
 	  usage,bits,section,offset
 	);
+  if (bmi->bmiHeader.biHeight < 0 ) bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
+  if (bmi->bmiHeader.biWidth < 0 ) bmi->bmiHeader.biWidth = -bmi->bmiHeader.biWidth;
   /* FIXME.  The following line isn't quite right.  */
   res = CreateDIBitmap32 (hdc, &bmi->bmiHeader, 0, NULL, bmi, 0);
   if (res)
@@ -1429,6 +1431,9 @@
 	{
             /* FIXME: this is wrong! (bmBits is always NULL) */
             if (bits) *bits = bmp.bmBits;
+	    /* hmpf */
+	    fprintf(stderr,"allocating %d bytes of memory\n",bmi->bmiHeader.biWidth*bmi->bmiHeader.biHeight*4);
+	    if (bits) *bits = (LPBYTE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,bmi->bmiHeader.biWidth*bmi->bmiHeader.biHeight*4);
             return res;
 	}
     }
diff --git a/objects/metafile.c b/objects/metafile.c
index 373c851..9fabc7c 100644
--- a/objects/metafile.c
+++ b/objects/metafile.c
@@ -8,6 +8,7 @@
 
 #include <string.h>
 #include <fcntl.h>
+#include "windows.h"
 #include "gdi.h"
 #include "bitmap.h"
 #include "file.h"
@@ -233,16 +234,15 @@
 
 
 /******************************************************************
- *         PlayMetafile16   (GDI.123)
+ *         PlayMetaFile16   (GDI.123)
  */
 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
 {
     return PlayMetaFile32( hdc, hmf );
 }
 
-
 /******************************************************************
- *         PlayMetafile32   (GDI32.265)
+ *         PlayMetaFile32   (GDI32.265)
  */
 BOOL32 WINAPI PlayMetaFile32( HDC32 hdc, HMETAFILE32 hmf )
 {
@@ -256,9 +256,8 @@
     HBRUSH32 hBrush;
     HFONT32 hFont;
     DC *dc;
-
+    
     dprintf_metafile(stddeb,"PlayMetaFile(%04x %04x)\n",hdc,hmf);
-
     if (!mh) return FALSE;
     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
     hPen = dc->w.hPen;
@@ -270,13 +269,14 @@
 		      sizeof(HANDLETABLE16) * mh->mtNoObjects);
     ht = (HANDLETABLE16 *)GlobalLock16(hHT);
 
+    
     /* loop through metafile playing records */
     offset = mh->mtHeaderSize * 2;
     while (offset < mh->mtSize * 2)
     {
-	mr = (METARECORD *)((char *)mh + offset);
-	dprintf_metafile(stddeb,"offset = %04x size = %08lx function = %04x\n",
-			 offset,mr->rdSize,mr->rdFunction);
+        mr = (METARECORD *)((char *)mh + offset);
+	dprintf_metafile(stddeb,"offset = %04x size = %08lx\n",
+			 offset, mr->rdSize);
 	if (!mr->rdSize) {
 		fprintf(stderr,"METAFILE entry got size 0 at offset %d, total mf length is %ld\n",offset,mh->mtSize*2);
 		break; /* would loop endlessly otherwise */
@@ -368,6 +368,7 @@
     return TRUE;
 }
 
+static BOOL32 MF_Meta_CreateRegion( METARECORD *mr, HRGN32 hrgn );
 
 /******************************************************************
  *             PlayMetaFileRecord16   (GDI.176)
@@ -380,8 +381,9 @@
     char *ptr;
     BITMAPINFOHEADER *infohdr;
 
-    dprintf_metafile(stddeb,"PlayMetaFileRecord(%04x %08lx %08lx %04x)\n",
-		     hdc,(LONG)ht, (LONG)mr, nHandles);
+    dprintf_metafile(stddeb,
+"PlayMetaFileRecord(%04x %08lx %08lx %04x) function %04x\n",
+		     hdc,(LONG)ht, (LONG)mr, nHandles, mr->rdFunction);
     
     switch (mr->rdFunction)
     {
@@ -420,6 +422,7 @@
     case META_SETSTRETCHBLTMODE:
 	SetStretchBltMode16(hdc, *(mr->rdParam));
 	break;
+
     case META_SETTEXTCOLOR:
 	SetTextColor16(hdc, MAKELONG(*(mr->rdParam), *(mr->rdParam + 1)));
 	break;
@@ -732,23 +735,13 @@
 
        /* --- Begin of new metafile operations. April, 1997 (ak) ----*/
     case META_CREATEREGION:
-	 {
-	    int i;
-	    HRGN32 h2,hrgn=CreateRectRgn32(mr->rdParam[7],mr->rdParam[8],
-                                           mr->rdParam[9],mr->rdParam[10]);
-	    for (i = 0; i < mr->rdParam[5]; i++)
-	    {
-	     if (mr->rdParam[11+i*6]==2)
-	     { 
-	       h2=CreateRectRgn32(mr->rdParam[14+i*6],mr->rdParam[12+i*6],
-				  mr->rdParam[15+i*6],mr->rdParam[13+i*6]);
-	       CombineRgn32(hrgn,hrgn,h2,mr->rdParam[16+i*6]);	/* e.g. RGN_OR */
-               DeleteObject32( h2 );
-	     }
-	    }
-	    MF_AddHandle(ht, nHandles,hrgn);
-         }
-       break;
+      {
+	HRGN32 hrgn = CreateRectRgn32(0,0,0,0);
+ 
+	MF_Meta_CreateRegion(mr, hrgn);
+	MF_AddHandle(ht, nHandles, hrgn);
+      }
+      break;
 
      case META_FILLREGION:
         FillRgn16(hdc, *(ht->objectHandle + *(mr->rdParam)),
@@ -861,6 +854,79 @@
 }
 
 /******************************************************************
+ *         MF_Meta_CreateRegion
+ *
+ *  Handles META_CREATEREGION for PlayMetaFileRecord().
+ */
+
+/*
+ *	The layout of the record looks something like this:
+ *	 
+ *	 rdParam	meaning
+ *	 0		Always 0?
+ *	 1		Always 6?
+ *	 2		Looks like a handle? - not constant
+ *	 3		0 or 1 ??
+ *	 4		Total number of bytes
+ *	 5		No. of seperate bands = n [see below]
+ *	 6		Largest number of x co-ords in a band
+ *	 7-10		Bounding box x1 y1 x2 y2
+ *	 11-...		n bands
+ *
+ *	 Regions are divided into bands that are uniform in the
+ *	 y-direction. Each band consists of pairs of on/off x-coords and is
+ *	 written as
+ *		m y0 y1 x1 x2 x3 ... xm m
+ *	 into successive rdParam[]s.
+ *
+ *	 This is probably just a dump of the internal RGNOBJ?
+ *
+ *	 HDMD - 18/12/97
+ *
+ */
+
+static BOOL32 MF_Meta_CreateRegion( METARECORD *mr, HRGN32 hrgn )
+{
+    WORD band, pair;
+    WORD *start, *end;
+    INT16 y0, y1;
+    HRGN32 hrgn2 = CreateRectRgn32( 0, 0, 0, 0 );
+
+    for(band  = 0, start = &(mr->rdParam[11]); band < mr->rdParam[5];
+ 					        band++, start = end + 1) {
+        if(*start / 2 != (*start + 1) / 2) {
+ 	    fprintf(stderr, "META_CREATEREGION: delimiter not even.\n");
+	    DeleteObject32( hrgn2 );
+ 	    return FALSE;
+        }
+
+	end = start + *start + 3;
+	if(end > (WORD *)mr + mr->rdSize) {
+	    fprintf(stderr, "META_CREATEREGION: end points outside record.\n");
+	    DeleteObject32( hrgn2 );
+	    return FALSE;
+        }
+
+	if(*start != *end) {
+	    fprintf(stderr, "META_CREATEREGION: mismatched delimiters.\n");
+	    DeleteObject32( hrgn2 );
+	    return FALSE;
+	}
+
+	y0 = *(INT16 *)(start + 1);
+	y1 = *(INT16 *)(start + 2);
+	for(pair = 0; pair < *start / 2; pair++) {
+	    SetRectRgn32( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
+				 *(INT16 *)(start + 4 + 2*pair), y1 );
+	    CombineRgn32(hrgn, hrgn, hrgn2, RGN_OR);
+        }
+    }
+    DeleteObject32( hrgn2 );
+    return TRUE;
+ }
+ 
+
+/******************************************************************
  *         MF_WriteRecord
  *
  * Warning: this function can change the metafile handle.
@@ -1389,3 +1455,88 @@
 }
 
 
+/******************************************************************
+ *         MF_CreateRegion
+ */
+INT16 MF_CreateRegion(DC *dc, HRGN32 hrgn)
+{
+    DWORD len;
+    METARECORD *mr;
+    RGNDATA *rgndata;
+    RECT32 *pCurRect, *pEndRect;
+    WORD Bands = 0, MaxBands = 0;
+    WORD *Param, *StartBand;
+    BOOL32 ret;
+
+    len = GetRegionData( hrgn, 0, NULL );
+    if( !(rgndata = HeapAlloc( SystemHeap, 0, len )) ) {
+        fprintf(stderr, "MF_CreateRegion: can't alloc rgndata buffer\n");
+	return -1;
+    }
+    GetRegionData( hrgn, len, rgndata );
+
+    /* Overestimate of length:
+     * Assume every rect is a separate band -> 6 WORDs per rect
+     */
+    len = sizeof(METARECORD) + 20 + (rgndata->rdh.nCount * 12);
+    if( !(mr = HeapAlloc( SystemHeap, 0, len )) ) {
+        fprintf(stderr, "MF_CreateRegion: can't alloc METARECORD buffer\n");
+	HeapFree( SystemHeap, 0, rgndata );
+	return -1;
+    }
+
+    memset(mr, 0, len);
+        
+    Param = mr->rdParam + 11;
+    StartBand = NULL;
+
+    pEndRect = (RECT32 *)rgndata->Buffer + rgndata->rdh.nCount;
+    for(pCurRect = (RECT32 *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
+    {
+        if( StartBand && pCurRect->top == *(StartBand + 1) )
+        {
+	    *Param++ = pCurRect->left;
+	    *Param++ = pCurRect->right;
+	}
+	else
+	{
+	    if(StartBand)
+	    {
+	        *StartBand = Param - StartBand - 3;
+		*Param++ = *StartBand;
+		if(*StartBand > MaxBands)
+		    MaxBands = *StartBand;
+		Bands++;
+	    }
+	    StartBand = Param++;
+	    *Param++ = pCurRect->top;
+	    *Param++ = pCurRect->bottom;
+	    *Param++ = pCurRect->left;
+	    *Param++ = pCurRect->right;
+	}
+    }
+    len = Param - (WORD *)mr;
+    
+    mr->rdParam[0] = 0;
+    mr->rdParam[1] = 6;
+    mr->rdParam[2] = 0x1234;
+    mr->rdParam[3] = 0;
+    mr->rdParam[4] = len * 2;
+    mr->rdParam[5] = Bands;
+    mr->rdParam[6] = MaxBands;
+    mr->rdParam[7] = rgndata->rdh.rcBound.left;
+    mr->rdParam[8] = rgndata->rdh.rcBound.top;
+    mr->rdParam[9] = rgndata->rdh.rcBound.right;
+    mr->rdParam[10] = rgndata->rdh.rcBound.bottom;
+    mr->rdFunction = META_CREATEREGION;
+    mr->rdSize = len / 2;
+    ret = MF_WriteRecord( dc, mr, mr->rdSize * 2 );	
+    HeapFree( SystemHeap, 0, mr );
+    HeapFree( SystemHeap, 0, rgndata );
+    if(!ret) 
+    {
+        fprintf(stderr, "MF_CreateRegion: MF_WriteRecord failed\n");
+	return -1;
+    }
+    return MF_AddHandleDC( dc );
+}
diff --git a/objects/region.c b/objects/region.c
index c68686f..a26cb96 100644
--- a/objects/region.c
+++ b/objects/region.c
@@ -1,17 +1,170 @@
 /*
- * GDI region objects
+ * GDI region objects. Shamelessly ripped out from the X11 distribution
+ * Thanks for the nice licence.
  *
  * Copyright 1993, 1994, 1995 Alexandre Julliard
+ * Modifications and additions: Copyright 1998 Huw Davies
  *
- * RGNOBJ is documented in the Dr. Dobbs Journal March 1993.
  */
 
-#include <stdlib.h>
+/************************************************************************
+
+Copyright (c) 1987, 1988  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+			All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.  
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+************************************************************************/
+/*
+ * The functions in this file implement the Region abstraction, similar to one
+ * used in the X11 sample server. A Region is simply an area, as the name
+ * implies, and is implemented as a "y-x-banded" array of rectangles. To
+ * explain: Each Region is made up of a certain number of rectangles sorted
+ * by y coordinate first, and then by x coordinate.
+ *
+ * Furthermore, the rectangles are banded such that every rectangle with a
+ * given upper-left y coordinate (y1) will have the same lower-right y
+ * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
+ * will span the entire vertical distance of the band. This means that some
+ * areas that could be merged into a taller rectangle will be represented as
+ * several shorter rectangles to account for shorter rectangles to its left
+ * or right but within its "vertical scope".
+ *
+ * An added constraint on the rectangles is that they must cover as much
+ * horizontal area as possible. E.g. no two rectangles in a band are allowed
+ * to touch.
+ *
+ * Whenever possible, bands will be merged together to cover a greater vertical
+ * distance (and thus reduce the number of rectangles). Two bands can be merged
+ * only if the bottom of one touches the top of the other and they have
+ * rectangles in the same places (of the same width, of course). This maintains
+ * the y-x-banding that's so nice to have...
+ */
+
 #include <stdio.h>
 #include "region.h"
 #include "stddebug.h"
 #include "debug.h"
+#include "heap.h"
+#include "dc.h"
 
+typedef void (*voidProcp)();
+
+/* Note the parameter order is different from the X11 equivalents */
+
+static void REGION_CopyRegion(WINEREGION *d, WINEREGION *s);
+static void REGION_IntersectRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
+static void REGION_UnionRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
+static void REGION_SubtractRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
+static void REGION_XorRegion(WINEREGION *d, WINEREGION *s1, WINEREGION *s2);
+static void REGION_UnionRectWithRegion(const RECT32 *rect, WINEREGION *rgn);
+
+
+/***********************************************************************
+ *            REGION_DumpRegion
+ *            Outputs the contents of a WINEREGION
+ */
+static void REGION_DumpRegion(WINEREGION *pReg)
+{
+    RECT32 *pRect, *pRectEnd = pReg->rects + pReg->numRects;
+
+    dprintf_region(stddeb, "Region %p: %d,%d - %d,%d %d rects\n", pReg,
+	    pReg->extents.left, pReg->extents.top,
+	    pReg->extents.right, pReg->extents.bottom, pReg->numRects);
+    for(pRect = pReg->rects; pRect < pRectEnd; pRect++)
+        dprintf_region(stddeb, "\t%d,%d - %d,%d\n", pRect->left, pRect->top,
+		       pRect->right, pRect->bottom);
+    return;
+}
+
+/***********************************************************************
+ *            REGION_AllocWineRegion
+ *            Create a new empty WINEREGION.
+ */
+static WINEREGION *REGION_AllocWineRegion( void )    
+{
+    WINEREGION *pReg;
+
+    if (!(pReg = HeapAlloc(SystemHeap, 0, sizeof( WINEREGION ))))
+	return NULL;
+    if (!(pReg->rects = HeapAlloc(SystemHeap, 0, sizeof( RECT32 ))))
+    {
+	HeapFree(SystemHeap, 0, pReg);
+	return NULL;
+    }
+    pReg->size = 1;
+    EMPTY_REGION(pReg);
+    return pReg;
+}
+
+/***********************************************************************
+ *          REGION_CreateRegion
+ *          Create a new empty region.
+ */
+static HRGN32 REGION_CreateRegion(void)
+{
+    HRGN32 hrgn;
+    RGNOBJ *obj;
+    
+    if(!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
+	return 0;
+    obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
+    if(!(obj->rgn = REGION_AllocWineRegion())) {
+	GDI_FreeObject( hrgn );
+	return 0;
+    }
+    GDI_HEAP_UNLOCK( hrgn );
+    return hrgn;
+}
+
+/***********************************************************************
+ *           REGION_DestroyWineRegion
+ */
+static void REGION_DestroyWineRegion( WINEREGION* pReg )
+{
+    HeapFree( SystemHeap, 0, pReg->rects );
+    HeapFree( SystemHeap, 0, pReg );
+    return;
+}
 
 /***********************************************************************
  *           REGION_DeleteObject
@@ -19,11 +172,11 @@
 BOOL32 REGION_DeleteObject( HRGN32 hrgn, RGNOBJ * obj )
 {
     dprintf_region(stddeb, "DeleteRegion: %04x\n", hrgn );
-    if (obj->xrgn) XDestroyRegion( obj->xrgn );
+
+    REGION_DestroyWineRegion( obj->rgn );
     return GDI_FreeObject( hrgn );
 }
 
-
 /***********************************************************************
  *           OffsetRgn16    (GDI.101)
  */
@@ -32,7 +185,6 @@
     return OffsetRgn32( hrgn, x, y );
 }
 
-
 /***********************************************************************
  *           OffsetRgn32   (GDI32.256)
  */
@@ -43,14 +195,24 @@
     if (obj)
     {
 	INT32 ret;
+	int nbox = obj->rgn->numRects;
+	RECT32 *pbox = obj->rgn->rects;
+	
 	dprintf_region(stddeb, "OffsetRgn: %04x %d,%d\n", hrgn, x, y );
-	if (obj->xrgn) 
-	{
-	    XOffsetRegion( obj->xrgn, x, y );
-	    ret = COMPLEXREGION;
+	if(nbox && (x || y)) {
+	    while(nbox--) {
+	        pbox->left += x;
+		pbox->right += x;
+		pbox->top += y;
+		pbox->bottom += y;
+		pbox++;
+	    }
+	    obj->rgn->extents.left += x;
+	    obj->rgn->extents.right += x;
+	    obj->rgn->extents.top += y;
+	    obj->rgn->extents.bottom += y;
 	}
-	else
-	    ret = NULLREGION;
+	ret = obj->rgn->type;
 	GDI_HEAP_UNLOCK( hrgn );
 	return ret;
     }
@@ -63,40 +225,31 @@
  */
 INT16 WINAPI GetRgnBox16( HRGN16 hrgn, LPRECT16 rect )
 {
-    RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
-    if (obj)
-    {
-	INT16 ret;
-	dprintf_region(stddeb, "GetRgnBox: %04x\n", hrgn );
-	if (obj->xrgn)
-	{
-	    XRectangle xrect;
-	    XClipBox( obj->xrgn, &xrect );
-	    SetRect16( rect, xrect.x, xrect.y,
-		       xrect.x + xrect.width, xrect.y + xrect.height);
-	    ret = COMPLEXREGION;
-	}
-	else
-	{
-	    SetRectEmpty16( rect );
-	    ret = NULLREGION;
-	}
-	GDI_HEAP_UNLOCK(hrgn);
-        return ret;
-    }
-    return ERROR;
+    RECT32 r;
+    INT16 ret = (INT16)GetRgnBox32( hrgn, &r );
+    CONV_RECT32TO16( &r, rect );
+    return ret;
 }
 
-
 /***********************************************************************
  *           GetRgnBox32    (GDI32.219)
  */
 INT32 WINAPI GetRgnBox32( HRGN32 hrgn, LPRECT32 rect )
 {
-    RECT16 r;
-    INT16 ret = GetRgnBox16( hrgn, &r );
-    CONV_RECT16TO32( &r, rect );
-    return ret;
+    RGNOBJ * obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
+    if (obj)
+    {
+	INT32 ret;
+	dprintf_region(stddeb, "GetRgnBox: %04x\n", hrgn );
+	rect->left = obj->rgn->extents.left;
+	rect->top = obj->rgn->extents.top;
+	rect->right = obj->rgn->extents.right;
+	rect->bottom = obj->rgn->extents.bottom;
+	ret = obj->rgn->type;
+	GDI_HEAP_UNLOCK(hrgn);
+	return ret;
+    }
+    return ERROR;
 }
 
 
@@ -115,28 +268,14 @@
 HRGN32 WINAPI CreateRectRgn32(INT32 left, INT32 top, INT32 right, INT32 bottom)
 {
     HRGN32 hrgn;
-    RGNOBJ *obj;
 
-    if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
-    obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
-    if ((right > left) && (bottom > top))
-    {
-	XRectangle rect = { left, top, right - left, bottom - top };
-	if (!(obj->xrgn = XCreateRegion()))
-        {
-            GDI_FreeObject( hrgn );
-            return 0;
-        }
-        XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
-    }
-    else obj->xrgn = 0;
-    dprintf_region( stddeb, "CreateRectRgn(%d,%d-%d,%d): returning %04x\n",
-                    left, top, right, bottom, hrgn );
-    GDI_HEAP_UNLOCK( hrgn );
+    if (!(hrgn = REGION_CreateRegion()))
+	return 0;
+    dprintf_region(stddeb, "CreateRectRgn: ");
+    SetRectRgn32(hrgn, left, top, right, bottom);
     return hrgn;
 }
 
-
 /***********************************************************************
  *           CreateRectRgnIndirect16    (GDI.65)
  */
@@ -159,7 +298,7 @@
  *           SetRectRgn16    (GDI.172)
  */
 VOID WINAPI SetRectRgn16( HRGN16 hrgn, INT16 left, INT16 top,
-                          INT16 right, INT16 bottom )
+			  INT16 right, INT16 bottom )
 {
     SetRectRgn32( hrgn, left, top, right, bottom );
 }
@@ -169,7 +308,7 @@
  *           SetRectRgn32    (GDI32.332)
  */
 VOID WINAPI SetRectRgn32( HRGN32 hrgn, INT32 left, INT32 top,
-                          INT32 right, INT32 bottom )
+			  INT32 right, INT32 bottom )
 {
     RGNOBJ * obj;
 
@@ -177,14 +316,18 @@
 		   hrgn, left, top, right, bottom );
     
     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC ))) return;
-    if (obj->xrgn) XDestroyRegion( obj->xrgn );
     if ((right > left) && (bottom > top))
     {
-	XRectangle rect = { left, top, right - left, bottom - top };
-	if ((obj->xrgn = XCreateRegion()) != 0)
-            XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
+        obj->rgn->rects->left = obj->rgn->extents.left = left;
+        obj->rgn->rects->top = obj->rgn->extents.top = top;
+        obj->rgn->rects->right = obj->rgn->extents.right = right;
+        obj->rgn->rects->bottom = obj->rgn->extents.bottom = bottom;
+	obj->rgn->numRects = 1;
+	obj->rgn->type = SIMPLEREGION;
     }
-    else obj->xrgn = 0;
+    else
+	EMPTY_REGION(obj->rgn);
+
     GDI_HEAP_UNLOCK( hrgn );
 }
 
@@ -193,39 +336,37 @@
  *           CreateRoundRectRgn16    (GDI.444)
  */
 HRGN16 WINAPI CreateRoundRectRgn16( INT16 left, INT16 top,
-                                    INT16 right, INT16 bottom,
-                                    INT16 ellipse_width, INT16 ellipse_height )
+				    INT16 right, INT16 bottom,
+				    INT16 ellipse_width, INT16 ellipse_height )
 {
     return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
-                                         ellipse_width, ellipse_height );
+					 ellipse_width, ellipse_height );
 }
 
-
 /***********************************************************************
  *           CreateRoundRectRgn32    (GDI32.61)
  */
 HRGN32 WINAPI CreateRoundRectRgn32( INT32 left, INT32 top,
-                                    INT32 right, INT32 bottom,
-                                    INT32 ellipse_width, INT32 ellipse_height )
+				    INT32 right, INT32 bottom,
+				    INT32 ellipse_width, INT32 ellipse_height )
 {
     RGNOBJ * obj;
     HRGN32 hrgn;
-    XRectangle rect;
     int asq, bsq, d, xd, yd;
-
+    RECT32 rect;
+    
       /* Check if we can do a normal rectangle instead */
 
     if ((right <= left) || (bottom <= top) ||
-        (ellipse_width <= 0) || (ellipse_height <= 0))
-        return CreateRectRgn32( left, top, right, bottom );
+                   (ellipse_width <= 0) || (ellipse_height <= 0))
+	return CreateRectRgn32( left, top, right, bottom );
 
       /* Create region */
 
-    if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC ))) return 0;
+    if (!(hrgn = REGION_CreateRegion())) return 0;
     obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
-    obj->xrgn = XCreateRegion();
-    dprintf_region(stddeb,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): return=%04x\n",
-               left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
+    dprintf_region(stddeb,"CreateRoundRectRgn(%d,%d-%d,%d %dx%d): ret=%04x\n",
+	       left, top, right, bottom, ellipse_width, ellipse_height, hrgn );
 
       /* Check parameters */
 
@@ -241,28 +382,29 @@
     xd = 0;
     yd = asq * ellipse_height;                      /* 2a^2b */
 
-    rect.x      = left + ellipse_width / 2;
-    rect.width  = right - left - ellipse_width;
-    rect.height = 1;
+    rect.left   = left + ellipse_width / 2;
+    rect.right  = right - ellipse_width;
 
       /* Loop to draw first half of quadrant */
 
     while (xd < yd)
     {
-        if (d > 0)  /* if nearest pixel is toward the center */
-        {
-              /* move toward center */
-            rect.y = top++;
-            XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
-            rect.y = --bottom;
-            XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
-            yd -= 2*asq;
-            d  -= yd;
-        }
-        rect.x--;        /* next horiz point */
-        rect.width += 2;
-        xd += 2*bsq;
-        d  += bsq + xd;
+	if (d > 0)  /* if nearest pixel is toward the center */
+	{
+	      /* move toward center */
+	    rect.top = top++;
+	    rect.bottom = rect.top + 1;
+	    REGION_UnionRectWithRegion( &rect, obj->rgn );
+	    rect.top = --bottom;
+	    rect.bottom = rect.top + 1;
+	    REGION_UnionRectWithRegion( &rect, obj->rgn );
+	    yd -= 2*asq;
+	    d  -= yd;
+	}
+	rect.left--;        /* next horiz point */
+	rect.right++;
+	xd += 2*bsq;
+	d  += bsq + xd;
     }
 
       /* Loop to draw second half of quadrant */
@@ -270,30 +412,33 @@
     d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
     while (yd >= 0)
     {
-          /* next vertical point */
-        rect.y = top++;
-        XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
-        rect.y = --bottom;
-        XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
-        if (d < 0)   /* if nearest pixel is outside ellipse */
-        {
-            rect.x--;     /* move away from center */
-            rect.width += 2;
-            xd += 2*bsq;
-            d  += xd;
-        }
-        yd -= 2*asq;
-        d  += asq - yd;
+	  /* next vertical point */
+	rect.top = top++;
+	rect.bottom = rect.top + 1;
+	REGION_UnionRectWithRegion( &rect, obj->rgn );
+	rect.top = --bottom;
+	rect.bottom = rect.top + 1;
+	REGION_UnionRectWithRegion( &rect, obj->rgn );
+	if (d < 0)   /* if nearest pixel is outside ellipse */
+	{
+	    rect.left--;     /* move away from center */
+	    rect.right++;
+	    xd += 2*bsq;
+	    d  += xd;
+	}
+	yd -= 2*asq;
+	d  += asq - yd;
     }
 
       /* Add the inside rectangle */
 
     if (top <= bottom)
     {
-        rect.y = top;
-        rect.height = bottom - top + 1;
-        XUnionRectWithRegion( &rect, obj->xrgn, obj->xrgn );
+	rect.top = top;
+	rect.bottom = bottom;
+	REGION_UnionRectWithRegion( &rect, obj->rgn );
     }
+    obj->rgn->type = SIMPLEREGION; /* FIXME? */
     GDI_HEAP_UNLOCK( hrgn );
     return hrgn;
 }
@@ -303,10 +448,10 @@
  *           CreateEllipticRgn16    (GDI.54)
  */
 HRGN16 WINAPI CreateEllipticRgn16( INT16 left, INT16 top,
-                                   INT16 right, INT16 bottom )
+				   INT16 right, INT16 bottom )
 {
     return (HRGN16)CreateRoundRectRgn32( left, top, right, bottom,
-                                         right-left, bottom-top );
+					 right-left, bottom-top );
 }
 
 
@@ -314,10 +459,10 @@
  *           CreateEllipticRgn32    (GDI32.39)
  */
 HRGN32 WINAPI CreateEllipticRgn32( INT32 left, INT32 top,
-                                   INT32 right, INT32 bottom )
+				   INT32 right, INT32 bottom )
 {
     return CreateRoundRectRgn32( left, top, right, bottom,
-                                 right-left, bottom-top );
+				 right-left, bottom-top );
 }
 
 
@@ -327,8 +472,8 @@
 HRGN16 WINAPI CreateEllipticRgnIndirect16( const RECT16 *rect )
 {
     return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
-                                 rect->bottom, rect->right - rect->left,
-                                 rect->bottom - rect->top );
+				 rect->bottom, rect->right - rect->left,
+				 rect->bottom - rect->top );
 }
 
 
@@ -338,132 +483,82 @@
 HRGN32 WINAPI CreateEllipticRgnIndirect32( const RECT32 *rect )
 {
     return CreateRoundRectRgn32( rect->left, rect->top, rect->right,
-                                 rect->bottom, rect->right - rect->left,
-                                 rect->bottom - rect->top );
+				 rect->bottom, rect->right - rect->left,
+				 rect->bottom - rect->top );
 }
 
-
 /***********************************************************************
- *           CreatePolygonRgn16    (GDI.63)
+ *           GetRegionData   (GDI32.217)
+ * 
  */
-HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
-                                  INT16 mode )
+DWORD WINAPI GetRegionData(HRGN32 hrgn, DWORD count, LPRGNDATA rgndata)
 {
-    return CreatePolyPolygonRgn16( points, &count, 1, mode );
-}
+    DWORD size;
+    RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
+    
+    dprintf_region(stddeb, "GetRegionData: %04x count = %ld, rgndata = %p\n",
+		   hrgn, count, rgndata);
 
+    if(!obj) return 0;
 
-/***********************************************************************
- *           CreatePolyPolygonRgn16    (GDI.451)
- */
-HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 * points,
-                                      const INT16 * count,
-                                      INT16 nbpolygons, INT16 mode )
-{
-    int		i,nrofpts;
-    LPINT32	count32;
-    LPPOINT32	points32;
-    HRGN32	ret;
-
-    nrofpts=0;
-    for (i=nbpolygons;i--;)
-	nrofpts+=count[i];
-    points32 = (LPPOINT32)HeapAlloc( GetProcessHeap(), 0,
-                                     nrofpts*sizeof(POINT32) );
-    for (i=nrofpts;i--;)
-    	CONV_POINT16TO32( &(points[i]), &(points32[i]) );
-    count32 = (LPINT32)HeapAlloc( GetProcessHeap(), 0, 
-                                  sizeof(INT32)*nbpolygons );
-    for (i=nbpolygons;i--;)
-    	count32[i]=count[i];
-    ret = CreatePolyPolygonRgn32(points32,count32,nbpolygons,mode);
-    HeapFree( GetProcessHeap(), 0, count32 );
-    HeapFree( GetProcessHeap(), 0, points32 );
-    return ret;
-}
-
-
-/***********************************************************************
- *           CreatePolygonRgn32    (GDI32.58)
- */
-HRGN32 WINAPI CreatePolygonRgn32( const POINT32 *points, INT32 count,
-                                  INT32 mode )
-{
-    return CreatePolyPolygonRgn32( points, &count, 1, mode );
-}
-
-
-/***********************************************************************
- *           CreatePolyPolygonRgn32    (GDI32.57)
- */
-HRGN32 WINAPI CreatePolyPolygonRgn32( const POINT32 * points,
-                                      const INT32 * count,
-                                      INT32 nbpolygons, INT32 mode )
-{
-    RGNOBJ * obj;
-    HRGN32 hrgn;
-    int i, j, maxPoints;
-    XPoint *xpoints, *pt;
-    Region xrgn;
-
-      /* Allocate points array */
-
-    if (!nbpolygons) return 0;
-    for (i = maxPoints = 0; i < nbpolygons; i++)
-	if (maxPoints < count[i]) maxPoints = count[i];
-    if (!maxPoints) return 0;
-    if (!(xpoints = (XPoint *)HeapAlloc( GetProcessHeap(), 0,
-                                         sizeof(XPoint) * maxPoints )))
-        return 0;
-
-      /* Allocate region */
-
-    if (!(hrgn = GDI_AllocObject( sizeof(RGNOBJ), REGION_MAGIC )))
+    size = obj->rgn->numRects * sizeof(RECT32);
+    if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
     {
-	HeapFree( GetProcessHeap(), 0, xpoints );
+        GDI_HEAP_UNLOCK( hrgn );
+        return size;
+    }
+
+    rgndata->rdh.dwSize = sizeof(RGNDATAHEADER);
+    rgndata->rdh.iType = RDH_RECTANGLES;
+    rgndata->rdh.nCount = obj->rgn->numRects;
+    rgndata->rdh.nRgnSize = size;
+    rgndata->rdh.rcBound.left = obj->rgn->extents.left;
+    rgndata->rdh.rcBound.top = obj->rgn->extents.top;
+    rgndata->rdh.rcBound.right = obj->rgn->extents.right;
+    rgndata->rdh.rcBound.bottom = obj->rgn->extents.bottom;
+
+    memcpy( rgndata->Buffer, obj->rgn->rects, size );
+
+    GDI_HEAP_UNLOCK( hrgn );
+    return 1;
+}
+
+/***********************************************************************
+ *           ExtCreateRegion   (GDI32.94)
+ * 
+ */
+HRGN32 WINAPI ExtCreateRegion( XFORM *lpXform, DWORD dwCount, RGNDATA *rgndata)
+{
+    HRGN32 hrgn = CreateRectRgn32(0, 0, 0, 0);
+    RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
+    RECT32 *pCurRect, *pEndRect;
+
+    dprintf_region(stddeb, "ExtCreateRegion: %p %ld %p. Returning %04x\n",
+		   lpXform, dwCount, rgndata, hrgn);
+    if(!hrgn)
+    {
+        fprintf(stderr, "ExtCreateRegion can't create a region!\n");
 	return 0;
     }
-    obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
-    obj->xrgn = 0;
-    dprintf_region(stddeb, "CreatePolyPolygonRgn: %d polygons, returning %04x\n",
-                   nbpolygons, hrgn );
-
-      /* Create X region */
-
-    for (i = 0; i < nbpolygons; i++, count++)
+    if(lpXform)
+        fprintf(stderr, "ExtCreateRegion: Xform not implemented - ignoring\n");
+    
+    if(rgndata->rdh.iType != RDH_RECTANGLES)
     {
-        if (*count <= 1) continue;
-	for (j = *count, pt = xpoints; j > 0; j--, points++, pt++)
-	{
-	    pt->x = points->x;
-	    pt->y = points->y;
-	}
-	xrgn = XPolygonRegion( xpoints, *count,
-			       (mode == WINDING) ? WindingRule : EvenOddRule );
-	if (!xrgn)
-        {
-            if (obj->xrgn) XDestroyRegion( obj->xrgn );
-            HeapFree( GetProcessHeap(), 0, xpoints );
-            GDI_FreeObject( hrgn );
-            return 0;
-        }
-	if (obj->xrgn)
-	{
-	    Region tmprgn = XCreateRegion();
-	    if (mode == WINDING) XUnionRegion( xrgn, obj->xrgn, tmprgn );
-	    else XXorRegion( xrgn, obj->xrgn, tmprgn );
-	    XDestroyRegion( obj->xrgn );
-	    obj->xrgn = tmprgn;
-	}
-	else obj->xrgn = xrgn;
+        fprintf(stderr, "ExtCreateRegion: type not RDH_RECTANGLES\n");
+	GDI_HEAP_UNLOCK( hrgn );
+	DeleteObject32( hrgn );
+	return 0;
     }
 
-    HeapFree( GetProcessHeap(), 0, xpoints );
+    pEndRect = (RECT32 *)rgndata->Buffer + rgndata->rdh.nCount;
+    for(pCurRect = (RECT32 *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
+        REGION_UnionRectWithRegion( pCurRect, obj->rgn );
+
     GDI_HEAP_UNLOCK( hrgn );
     return hrgn;
 }
 
-
 /***********************************************************************
  *           PtInRegion16    (GDI.161)
  */
@@ -482,11 +577,13 @@
     
     if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
     {
-	BOOL32 ret;
-	if (obj->xrgn)
-	    ret = XPointInRegion( obj->xrgn, x, y );
-	else
-	    ret = FALSE;
+	BOOL32 ret = FALSE;
+	int i;
+
+	if (obj->rgn->numRects > 0 && INRECT(obj->rgn->extents, x, y))
+	    for (i = 0; i < obj->rgn->numRects; i++)
+		if (INRECT (obj->rgn->rects[i], x, y))
+		    ret = TRUE;
 	GDI_HEAP_UNLOCK( hrgn );
 	return ret;
     }
@@ -499,25 +596,17 @@
  */
 BOOL16 WINAPI RectInRegion16( HRGN16 hrgn, const RECT16 *rect )
 {
-    RGNOBJ * obj;
+    RECT32 r32;
 
-    if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
-    {
-	BOOL16 ret;
-	if (obj->xrgn)
-	    ret = (XRectInRegion( obj->xrgn, rect->left, rect->top,
-                   rect->right-rect->left, rect->bottom-rect->top ) != RectangleOut);
-	else
-	    ret = FALSE;
-	GDI_HEAP_UNLOCK( hrgn );
-	return ret;
-    }
-    return FALSE;
+    CONV_RECT16TO32(rect, &r32);
+    return (BOOL16)RectInRegion32(hrgn, &r32);
 }
 
 
 /***********************************************************************
  *           RectInRegion32    (GDI32.281)
+ *
+ * Returns TRUE if rect is at least partly inside hrgn
  */
 BOOL32 WINAPI RectInRegion32( HRGN32 hrgn, const RECT32 *rect )
 {
@@ -525,19 +614,42 @@
     
     if ((obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC )))
     {
-	BOOL32 ret;
-	if (obj->xrgn)
-	    ret = (XRectInRegion( obj->xrgn, rect->left, rect->top,
-                   rect->right-rect->left, rect->bottom-rect->top ) != RectangleOut);
-	else
-	    ret = FALSE;
-	GDI_HEAP_UNLOCK( hrgn );
+	RECT32 *pCurRect, *pRectEnd;
+	BOOL32 ret = FALSE;
+    
+    /* this is (just) a useful optimization */
+	if ((obj->rgn->numRects > 0) && EXTENTCHECK(&obj->rgn->extents,
+						      rect))
+	{
+	    for (pCurRect = obj->rgn->rects, pRectEnd = pCurRect +
+	     obj->rgn->numRects; pCurRect < pRectEnd; pCurRect++)
+	    {
+	        if (pCurRect->bottom <= rect->top)
+		    continue;             /* not far enough down yet */
+
+		if (pCurRect->top >= rect->bottom) {
+		    ret = FALSE;          /* too far down */
+		    break;
+		}
+
+		if (pCurRect->right <= rect->left)
+		    continue;              /* not far enough over yet */
+
+		if (pCurRect->left >= rect->right) {
+		    ret = FALSE;           /* too far over */
+		    break;
+		}
+
+		ret = TRUE;
+		break;
+	    }
+	}
+	GDI_HEAP_UNLOCK(hrgn);
 	return ret;
     }
     return FALSE;
 }
 
-
 /***********************************************************************
  *           EqualRgn16    (GDI.72)
  */
@@ -550,122 +662,97 @@
 /***********************************************************************
  *           EqualRgn32    (GDI32.90)
  */
-BOOL32 WINAPI EqualRgn32( HRGN32 rgn1, HRGN32 rgn2 )
+BOOL32 WINAPI EqualRgn32( HRGN32 hrgn1, HRGN32 hrgn2 )
 {
     RGNOBJ *obj1, *obj2;
     BOOL32 ret = FALSE;
 
-    if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( rgn1, REGION_MAGIC ))) 
+    if ((obj1 = (RGNOBJ *) GDI_GetObjPtr( hrgn1, REGION_MAGIC ))) 
     {
-	if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( rgn2, REGION_MAGIC ))) 
+	if ((obj2 = (RGNOBJ *) GDI_GetObjPtr( hrgn2, REGION_MAGIC ))) 
 	{
-	    if (!obj1->xrgn || !obj2->xrgn) 
-		ret = (!obj1->xrgn && !obj2->xrgn);
-	    else 
-		ret = XEqualRegion( obj1->xrgn, obj2->xrgn );
-	    GDI_HEAP_UNLOCK( rgn2 );
+	    int i;
+
+	    ret = TRUE;
+	    if ( obj1->rgn->numRects != obj2->rgn->numRects ) ret = FALSE;
+	    else if ( obj1->rgn->numRects == 0 ) ret = TRUE;
+	    else if ( !EqualRect32(&obj1->rgn->extents, &obj2->rgn->extents) )
+		ret = FALSE;
+	    else for( i = 0; i < obj1->rgn->numRects; i++ ) {
+		if (!EqualRect32(obj1->rgn->rects + i, obj2->rgn->rects + i)) {
+		    ret = FALSE;
+		    break;
+		}
+	    }
+	    GDI_HEAP_UNLOCK(hrgn2);
 	}
-	GDI_HEAP_UNLOCK( rgn1 );
+	GDI_HEAP_UNLOCK(hrgn1);
     }
     return ret;
 }
-
-
 /***********************************************************************
- *           REGION_CopyRegion
- *
- * Copy region src into dest.
+ *           REGION_UnionRectWithRegion
+ *           Adds a rectangle to a WINEREGION
+ *           See below for REGION_UnionRectWithRgn
  */
-static INT32 REGION_CopyRegion( RGNOBJ *src, RGNOBJ *dest )
+static void REGION_UnionRectWithRegion(const RECT32 *rect, WINEREGION *rgn)
 {
-    Region tmprgn;
-    if (src->xrgn)
-    {
-        if (src->xrgn == dest->xrgn) return COMPLEXREGION;
-        tmprgn = XCreateRegion();
-        if (!dest->xrgn) dest->xrgn = XCreateRegion();
-        XUnionRegion( tmprgn, src->xrgn, dest->xrgn );
-        XDestroyRegion( tmprgn );
-        return COMPLEXREGION;
-    }
-    else
-    {
-        if (dest->xrgn) XDestroyRegion( dest->xrgn );
-        dest->xrgn = 0;
-        return NULLREGION;
-    }
+    WINEREGION region;
+
+    region.rects = &region.extents;
+    region.numRects = 1;
+    region.size = 1;
+    region.type = SIMPLEREGION;
+    CopyRect32(&(region.extents), rect);
+    REGION_UnionRegion(rgn, rgn, &region);
+    return;
 }
 
-
-/***********************************************************************
- *           REGION_IsEmpty
- */
-BOOL32 REGION_IsEmpty( HRGN32 hRgn )
-{
-    RGNOBJ*     rgnObj = (RGNOBJ*) GDI_GetObjPtr( hRgn, REGION_MAGIC );
-    BOOL32	ret = TRUE;
-
-    if( rgnObj )
-    {
-	if( rgnObj->xrgn && !XEmptyRegion(rgnObj->xrgn) ) ret = FALSE;
-	GDI_HEAP_UNLOCK( hRgn );
-    }
-    return ret;
-}
-
-
 /***********************************************************************
  *           REGION_UnionRectWithRgn
- *
- * Add rc rectangle to the region.
+ *           Adds a rectangle to a HRGN32
+ *           A helper used by scroll.c
  */
-BOOL32 REGION_UnionRectWithRgn( HRGN32 hRgn, const RECT32 *rc )
+BOOL32 REGION_UnionRectWithRgn( HRGN32 hrgn, const RECT32 *lpRect )
 {
-    RGNOBJ*	rgnObj = (RGNOBJ*) GDI_GetObjPtr( hRgn, REGION_MAGIC );
-    XRectangle  rect = { rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top };
-    BOOL32 	ret = ERROR;
+    RGNOBJ *obj = (RGNOBJ *) GDI_HEAP_LOCK( hrgn );
 
-    if( rgnObj )
-    {
-	if( !rgnObj->xrgn )
-	{
-	    if ((rgnObj->xrgn = XCreateRegion()))
-		ret = SIMPLEREGION;
-	    else
-		goto done;
-	}
-	else
-	    ret = COMPLEXREGION;
-	XUnionRectWithRegion( &rect, rgnObj->xrgn, rgnObj->xrgn );
-done:
-	GDI_HEAP_UNLOCK( hRgn );
-    }
-    return ret;
+    if(!obj) return FALSE;
+    REGION_UnionRectWithRegion( lpRect, obj->rgn );
+    GDI_HEAP_UNLOCK(hrgn);
+    return TRUE;
 }
 
-
 /***********************************************************************
  *           REGION_CreateFrameRgn
  *
- * Create a region that is a frame around another region
+ * Create a region that is a frame around another region.
+ * Expand all rectangles by +/- x and y, then subtract original region.
  */
 BOOL32 REGION_FrameRgn( HRGN32 hDest, HRGN32 hSrc, INT32 x, INT32 y )
 {
     BOOL32 bRet;
     RGNOBJ *srcObj = (RGNOBJ*) GDI_GetObjPtr( hSrc, REGION_MAGIC );
 
-    if (srcObj->xrgn) 
+    if (srcObj->rgn->numRects != 0) 
     {
 	RGNOBJ* destObj = (RGNOBJ*) GDI_GetObjPtr( hDest, REGION_MAGIC );
-	Region  resRgn;
+	RECT32 *pRect, *pEndRect;
+	RECT32 tempRect;
 
-	REGION_CopyRegion( srcObj, destObj );
-	XShrinkRegion( destObj->xrgn, -x, -y );
-	resRgn = XCreateRegion();
-	XSubtractRegion( destObj->xrgn, srcObj->xrgn, resRgn );
-	XDestroyRegion( destObj->xrgn );
-	destObj->xrgn = resRgn;
-	GDI_HEAP_UNLOCK( hDest );
+	EMPTY_REGION( destObj->rgn );
+	
+	pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
+	for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++)
+	{
+	    tempRect.left = pRect->left - x;        
+	    tempRect.top = pRect->top - y;
+	    tempRect.right = pRect->right + x;
+	    tempRect.bottom = pRect->bottom + y;
+	    REGION_UnionRectWithRegion( &tempRect, destObj->rgn );
+	}
+	REGION_SubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn );
+	GDI_HEAP_UNLOCK ( hDest );
 	bRet = TRUE;
     }
     else
@@ -674,7 +761,55 @@
     return bRet;
 }
 
+/***********************************************************************
+ *           REGION_LPTODP
+ *
+ * Convert region to device co-ords for the supplied dc. 
+ * Used by X11DRV_PaintRgn.
+ */
+BOOL32 REGION_LPTODP( HDC32 hdc, HRGN32 hDest, HRGN32 hSrc )
+{
+    RECT32 *pCurRect, *pEndRect;
+    RGNOBJ *srcObj, *destObj;
+    DC * dc = DC_GetDCPtr( hdc );
+    RECT32 tmpRect;
 
+    dprintf_region( stddeb, "REGION_LPTODP: hdc=%04x dest=%04x src=%04x\n",
+		    hdc, hDest, hSrc) ;
+    
+    if (dc->w.MapMode == MM_TEXT) /* Requires only a translation */
+    {
+        if( CombineRgn32( hDest, hSrc, 0, RGN_COPY ) == ERROR ) return FALSE;
+	OffsetRgn32( hDest, dc->vportOrgX - dc->wndOrgX, 
+		     dc->vportOrgY - dc->wndOrgY );
+	return TRUE;
+    }
+
+    if(!( srcObj = (RGNOBJ *) GDI_GetObjPtr( hSrc, REGION_MAGIC) ))
+        return FALSE;
+    if(!( destObj = (RGNOBJ *) GDI_GetObjPtr( hDest, REGION_MAGIC) ))
+    {
+        GDI_HEAP_UNLOCK( hSrc );
+        return FALSE;
+    }
+    EMPTY_REGION( destObj->rgn );
+
+    pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects;
+    for(pCurRect = srcObj->rgn->rects; pCurRect < pEndRect; pCurRect++)
+    {
+        tmpRect = *pCurRect;
+	tmpRect.left = XLPTODP( dc, tmpRect.left );
+	tmpRect.top = YLPTODP( dc, tmpRect.top );
+	tmpRect.right = XLPTODP( dc, tmpRect.right );
+	tmpRect.bottom = YLPTODP( dc, tmpRect.bottom );
+	REGION_UnionRectWithRegion( &tmpRect, destObj->rgn );
+    }
+    
+    GDI_HEAP_UNLOCK( hDest );
+    GDI_HEAP_UNLOCK( hSrc );
+    return TRUE;
+}
+    
 /***********************************************************************
  *           CombineRgn16    (GDI.451)
  */
@@ -702,107 +837,1673 @@
 
 	if (src1Obj)
 	{
+	    dprintf_region(stddeb, "src1:\n");
+	    if(debugging_region) REGION_DumpRegion(src1Obj->rgn);
 	    if (mode == RGN_COPY)
-		result = REGION_CopyRegion( src1Obj, destObj );
+	    {
+		REGION_CopyRegion( destObj->rgn, src1Obj->rgn );
+		result = destObj->rgn->type;
+	    }
 	    else
 	    {
 		RGNOBJ *src2Obj = (RGNOBJ *) GDI_GetObjPtr( hSrc2, REGION_MAGIC);
 
 		if (src2Obj)
 		{
-		    if (!src1Obj->xrgn || !src2Obj->xrgn)
+		    dprintf_region(stddeb, "src2:\n");
+		    if(debugging_region) REGION_DumpRegion(src2Obj->rgn);
+		    switch (mode)
 		    {
-			/* Some optimizations for null regions */
-			switch( mode )
-			{
-			    case RGN_DIFF:
-				 if (src1Obj->xrgn)
-				 {
-				     result = REGION_CopyRegion( src1Obj, destObj );
-				     break;
-				 }
-				 /* else fall through */
-			    case RGN_AND:
-				 if (destObj->xrgn) 
-				 {
-				     XDestroyRegion( destObj->xrgn );
-				     destObj->xrgn = 0;
-				 }
-				 result = NULLREGION;
-				 break;
-
-			    case RGN_OR:
-			    case RGN_XOR:
-#define __SRC_RGN ((src1Obj->xrgn) ? src1Obj : src2Obj)
-				 result = REGION_CopyRegion( __SRC_RGN, destObj );
-#undef  __SRC_RGN
-				 break;
-
-			    case 0:
-			    default:
-				 /* makes gcc generate more efficient code */
-			}
+		    case RGN_AND:
+			REGION_IntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn);
+			break;
+		    case RGN_OR:
+			REGION_UnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
+			break;
+		    case RGN_XOR:
+			REGION_XorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
+			break;
+		    case RGN_DIFF:
+			REGION_SubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn );
+			break;
 		    }
-		    else /* both regions are present */
-		    {
-			Region  destRgn = XCreateRegion();
-
-			if (destRgn)
-			{
-			    switch (mode)
-			    {
-				case RGN_AND:
-				     XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destRgn );
-				     break;
-				case RGN_OR:
-				     XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destRgn );
-				     break;
-				case RGN_XOR:
-				     XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destRgn );
-				     break;
-				case RGN_DIFF:
-			             XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destRgn );
-				     break;
-
-				case 0: /* makes gcc generate more efficient code */
-				default:
-				     XDestroyRegion( destRgn );
-				     goto done;
-			    }
-
-			    if ( destObj->xrgn ) 
-				 XDestroyRegion( destObj->xrgn );
-			    if ( XEmptyRegion( destRgn ) )
-			    {
-				 XDestroyRegion( destRgn );
-				 destObj->xrgn = 0;
-				 result = NULLREGION;
-			    }
-			    else 
-			    {
-				 destObj->xrgn = destRgn;
-				 result = COMPLEXREGION;
-			    }
-			}
-		    }
-done:
+		    result = destObj->rgn->type;
 		    GDI_HEAP_UNLOCK( hSrc2 );
 		}
 	    }
 	    GDI_HEAP_UNLOCK( hSrc1 );
 	}
+	dprintf_region(stddeb, "dest:\n");
+	if(debugging_region) REGION_DumpRegion(destObj->rgn);
+
 	GDI_HEAP_UNLOCK( hDest );
     }
     return result;
 }
 
 /***********************************************************************
- *           GetRegionData   (GDI32.217)
- * 
- * This seems to be rather impossible with the current region implementation
- * for it seems you cannot query X regions.
+ *           REGION_SetExtents
+ *           Re-calculate the extents of a region
  */
-DWORD WINAPI GetRegionData(HRGN32 hrgn,DWORD x,LPRGNDATA rgndata) {
-	fprintf(stderr,"GetRegionData(%04x,%08lx,%p), STUB!\n",hrgn,x,rgndata);
+static void REGION_SetExtents (WINEREGION *pReg)
+{
+    RECT32 *pRect, *pRectEnd, *pExtents;
+
+    if (pReg->numRects == 0)
+    {
+	pReg->extents.left = 0;
+	pReg->extents.top = 0;
+	pReg->extents.right = 0;
+	pReg->extents.bottom = 0;
+	return;
+    }
+
+    pExtents = &pReg->extents;
+    pRect = pReg->rects;
+    pRectEnd = &pRect[pReg->numRects - 1];
+
+    /*
+     * Since pRect is the first rectangle in the region, it must have the
+     * smallest top and since pRectEnd is the last rectangle in the region,
+     * it must have the largest bottom, because of banding. Initialize left and
+     * right from pRect and pRectEnd, resp., as good things to initialize them
+     * to...
+     */
+    pExtents->left = pRect->left;
+    pExtents->top = pRect->top;
+    pExtents->right = pRectEnd->right;
+    pExtents->bottom = pRectEnd->bottom;
+
+    while (pRect <= pRectEnd)
+    {
+	if (pRect->left < pExtents->left)
+	    pExtents->left = pRect->left;
+	if (pRect->right > pExtents->right)
+	    pExtents->right = pRect->right;
+	pRect++;
+    }
+}
+
+/***********************************************************************
+ *           REGION_CopyRegion
+ */
+static void REGION_CopyRegion(WINEREGION *dst, WINEREGION *src)
+{
+    if (dst != src) /*  don't want to copy to itself */
+    {  
+	if (dst->size < src->numRects)
+	{
+	    if (! (dst->rects = HeapReAlloc( SystemHeap, 0, dst->rects,
+				src->numRects * sizeof(RECT32) )))
+		return;
+	    dst->size = src->numRects;
+	}
+	dst->numRects = src->numRects;
+	dst->extents.left = src->extents.left;
+	dst->extents.top = src->extents.top;
+	dst->extents.right = src->extents.right;
+	dst->extents.bottom = src->extents.bottom;
+	dst->type = src->type;
+
+	memcpy((char *) dst->rects, (char *) src->rects,
+	       (int) (src->numRects * sizeof(RECT32)));
+    }
+    return;
+}
+
+/***********************************************************************
+ *           REGION_Coalesce
+ *
+ *      Attempt to merge the rects in the current band with those in the
+ *      previous one. Used only by REGION_RegionOp.
+ *
+ * Results:
+ *      The new index for the previous band.
+ *
+ * Side Effects:
+ *      If coalescing takes place:
+ *          - rectangles in the previous band will have their bottom fields
+ *            altered.
+ *          - pReg->numRects will be decreased.
+ *
+ */
+static INT32 REGION_Coalesce (WINEREGION *pReg, INT32 prevStart,
+			      INT32 curStart)
+   /*   pReg - Region to coalesce */
+   /*   prevStart - Index of start of previous band */
+   /*   curStart - Index of start of current band */
+{
+    RECT32 *pPrevRect;          /* Current rect in previous band */
+    RECT32 *pCurRect;           /* Current rect in current band */
+    RECT32 *pRegEnd;            /* End of region */
+    INT32 curNumRects;          /* Number of rectangles in current band */
+    INT32 prevNumRects;         /* Number of rectangles in previous band */
+    INT32 bandtop;               /* top coordinate for current band */
+
+    pRegEnd = &pReg->rects[pReg->numRects];
+
+    pPrevRect = &pReg->rects[prevStart];
+    prevNumRects = curStart - prevStart;
+
+    /*
+     * Figure out how many rectangles are in the current band. Have to do
+     * this because multiple bands could have been added in REGION_RegionOp
+     * at the end when one region has been exhausted.
+     */
+    pCurRect = &pReg->rects[curStart];
+    bandtop = pCurRect->top;
+    for (curNumRects = 0;
+	 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
+	 curNumRects++)
+    {
+	pCurRect++;
+    }
+    
+    if (pCurRect != pRegEnd)
+    {
+	/*
+	 * If more than one band was added, we have to find the start
+	 * of the last band added so the next coalescing job can start
+	 * at the right place... (given when multiple bands are added,
+	 * this may be pointless -- see above).
+	 */
+	pRegEnd--;
+	while (pRegEnd[-1].top == pRegEnd->top)
+	{
+	    pRegEnd--;
+	}
+	curStart = pRegEnd - pReg->rects;
+	pRegEnd = pReg->rects + pReg->numRects;
+    }
+	
+    if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
+	pCurRect -= curNumRects;
+	/*
+	 * The bands may only be coalesced if the bottom of the previous
+	 * matches the top scanline of the current.
+	 */
+	if (pPrevRect->bottom == pCurRect->top)
+	{
+	    /*
+	     * Make sure the bands have rects in the same places. This
+	     * assumes that rects have been added in such a way that they
+	     * cover the most area possible. I.e. two rects in a band must
+	     * have some horizontal space between them.
+	     */
+	    do
+	    {
+		if ((pPrevRect->left != pCurRect->left) ||
+		    (pPrevRect->right != pCurRect->right))
+		{
+		    /*
+		     * The bands don't line up so they can't be coalesced.
+		     */
+		    return (curStart);
+		}
+		pPrevRect++;
+		pCurRect++;
+		prevNumRects -= 1;
+	    } while (prevNumRects != 0);
+
+	    pReg->numRects -= curNumRects;
+	    pCurRect -= curNumRects;
+	    pPrevRect -= curNumRects;
+
+	    /*
+	     * The bands may be merged, so set the bottom of each rect
+	     * in the previous band to that of the corresponding rect in
+	     * the current band.
+	     */
+	    do
+	    {
+		pPrevRect->bottom = pCurRect->bottom;
+		pPrevRect++;
+		pCurRect++;
+		curNumRects -= 1;
+	    } while (curNumRects != 0);
+
+	    /*
+	     * If only one band was added to the region, we have to backup
+	     * curStart to the start of the previous band.
+	     *
+	     * If more than one band was added to the region, copy the
+	     * other bands down. The assumption here is that the other bands
+	     * came from the same region as the current one and no further
+	     * coalescing can be done on them since it's all been done
+	     * already... curStart is already in the right place.
+	     */
+	    if (pCurRect == pRegEnd)
+	    {
+		curStart = prevStart;
+	    }
+	    else
+	    {
+		do
+		{
+		    *pPrevRect++ = *pCurRect++;
+		} while (pCurRect != pRegEnd);
+	    }
+	    
+	}
+    }
+    return (curStart);
+}
+
+/***********************************************************************
+ *           REGION_RegionOp
+ *
+ *      Apply an operation to two regions. Called by REGION_Union,
+ *      REGION_Inverse, REGION_Subtract, REGION_Intersect...
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      The new region is overwritten.
+ *
+ * Notes:
+ *      The idea behind this function is to view the two regions as sets.
+ *      Together they cover a rectangle of area that this function divides
+ *      into horizontal bands where points are covered only by one region
+ *      or by both. For the first case, the nonOverlapFunc is called with
+ *      each the band and the band's upper and lower extents. For the
+ *      second, the overlapFunc is called to process the entire band. It
+ *      is responsible for clipping the rectangles in the band, though
+ *      this function provides the boundaries.
+ *      At the end of each band, the new region is coalesced, if possible,
+ *      to reduce the number of rectangles in the region.
+ *
+ */
+static void REGION_RegionOp(WINEREGION *newReg, WINEREGION *reg1,
+	WINEREGION *reg2, void (*overlapFunc)(), void (*nonOverlap1Func)(),
+	void (*nonOverlap2Func)())
+
+	/* newReg - Place to store result */
+	/* reg1 -   First region in operation */
+	/* reg2 -   2nd region in operation */
+	/* overlapFunc -  Function to call for over-lapping bands */
+	/* nonOverlap1Func - Function to call for non-overlapping bands in
+					region 1 */
+	/* nonOverlap2Func - Function to call for non-overlapping bands in
+					region 2 */
+{
+    RECT32 *r1;                         /* Pointer into first region */
+    RECT32 *r2;                         /* Pointer into 2d region */
+    RECT32 *r1End;                      /* End of 1st region */
+    RECT32 *r2End;                      /* End of 2d region */
+    INT32 ybot;                         /* Bottom of intersection */
+    INT32 ytop;                         /* Top of intersection */
+    RECT32 *oldRects;                   /* Old rects for newReg */
+    INT32 prevBand;                     /* Index of start of
+						 * previous band in newReg */
+    INT32 curBand;                      /* Index of start of current
+						 * band in newReg */
+    RECT32 *r1BandEnd;                  /* End of current band in r1 */
+    RECT32 *r2BandEnd;                  /* End of current band in r2 */
+    INT32 top;                          /* Top of non-overlapping band */
+    INT32 bot;                          /* Bottom of non-overlapping band */
+    
+    /*
+     * Initialization:
+     *  set r1, r2, r1End and r2End appropriately, preserve the important
+     * parts of the destination region until the end in case it's one of
+     * the two source regions, then mark the "new" region empty, allocating
+     * another array of rectangles for it to use.
+     */
+    r1 = reg1->rects;
+    r2 = reg2->rects;
+    r1End = r1 + reg1->numRects;
+    r2End = r2 + reg2->numRects;
+    
+    oldRects = newReg->rects;
+    
+    EMPTY_REGION(newReg);
+
+    /*
+     * Allocate a reasonable number of rectangles for the new region. The idea
+     * is to allocate enough so the individual functions don't need to
+     * reallocate and copy the array, which is time consuming, yet we don't
+     * have to worry about using too much memory. I hope to be able to
+     * nuke the Xrealloc() at the end of this function eventually.
+     */
+    newReg->size = MAX(reg1->numRects,reg2->numRects) * 2;
+
+    if (! (newReg->rects = HeapAlloc( SystemHeap, 0, 
+			          sizeof(RECT32) * newReg->size )))
+    {
+	newReg->size = 0;
+	return;
+    }
+    
+    /*
+     * Initialize ybot and ytop.
+     * In the upcoming loop, ybot and ytop serve different functions depending
+     * on whether the band being handled is an overlapping or non-overlapping
+     * band.
+     *  In the case of a non-overlapping band (only one of the regions
+     * has points in the band), ybot is the bottom of the most recent
+     * intersection and thus clips the top of the rectangles in that band.
+     * ytop is the top of the next intersection between the two regions and
+     * serves to clip the bottom of the rectangles in the current band.
+     *  For an overlapping band (where the two regions intersect), ytop clips
+     * the top of the rectangles of both regions and ybot clips the bottoms.
+     */
+    if (reg1->extents.top < reg2->extents.top)
+	ybot = reg1->extents.top;
+    else
+	ybot = reg2->extents.top;
+    
+    /*
+     * prevBand serves to mark the start of the previous band so rectangles
+     * can be coalesced into larger rectangles. qv. miCoalesce, above.
+     * In the beginning, there is no previous band, so prevBand == curBand
+     * (curBand is set later on, of course, but the first band will always
+     * start at index 0). prevBand and curBand must be indices because of
+     * the possible expansion, and resultant moving, of the new region's
+     * array of rectangles.
+     */
+    prevBand = 0;
+    
+    do
+    {
+	curBand = newReg->numRects;
+
+	/*
+	 * This algorithm proceeds one source-band (as opposed to a
+	 * destination band, which is determined by where the two regions
+	 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
+	 * rectangle after the last one in the current band for their
+	 * respective regions.
+	 */
+	r1BandEnd = r1;
+	while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
+	{
+	    r1BandEnd++;
+	}
+	
+	r2BandEnd = r2;
+	while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
+	{
+	    r2BandEnd++;
+	}
+	
+	/*
+	 * First handle the band that doesn't intersect, if any.
+	 *
+	 * Note that attention is restricted to one band in the
+	 * non-intersecting region at once, so if a region has n
+	 * bands between the current position and the next place it overlaps
+	 * the other, this entire loop will be passed through n times.
+	 */
+	if (r1->top < r2->top)
+	{
+	    top = MAX(r1->top,ybot);
+	    bot = MIN(r1->bottom,r2->top);
+
+	    if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
+	    {
+		(* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
+	    }
+
+	    ytop = r2->top;
+	}
+	else if (r2->top < r1->top)
+	{
+	    top = MAX(r2->top,ybot);
+	    bot = MIN(r2->bottom,r1->top);
+
+	    if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
+	    {
+		(* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
+	    }
+
+	    ytop = r1->top;
+	}
+	else
+	{
+	    ytop = r1->top;
+	}
+
+	/*
+	 * If any rectangles got added to the region, try and coalesce them
+	 * with rectangles from the previous band. Note we could just do
+	 * this test in miCoalesce, but some machines incur a not
+	 * inconsiderable cost for function calls, so...
+	 */
+	if (newReg->numRects != curBand)
+	{
+	    prevBand = REGION_Coalesce (newReg, prevBand, curBand);
+	}
+
+	/*
+	 * Now see if we've hit an intersecting band. The two bands only
+	 * intersect if ybot > ytop
+	 */
+	ybot = MIN(r1->bottom, r2->bottom);
+	curBand = newReg->numRects;
+	if (ybot > ytop)
+	{
+	    (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
+
+	}
+	
+	if (newReg->numRects != curBand)
+	{
+	    prevBand = REGION_Coalesce (newReg, prevBand, curBand);
+	}
+
+	/*
+	 * If we've finished with a band (bottom == ybot) we skip forward
+	 * in the region to the next band.
+	 */
+	if (r1->bottom == ybot)
+	{
+	    r1 = r1BandEnd;
+	}
+	if (r2->bottom == ybot)
+	{
+	    r2 = r2BandEnd;
+	}
+    } while ((r1 != r1End) && (r2 != r2End));
+
+    /*
+     * Deal with whichever region still has rectangles left.
+     */
+    curBand = newReg->numRects;
+    if (r1 != r1End)
+    {
+	if (nonOverlap1Func != (void (*)())NULL)
+	{
+	    do
+	    {
+		r1BandEnd = r1;
+		while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
+		{
+		    r1BandEnd++;
+		}
+		(* nonOverlap1Func) (newReg, r1, r1BandEnd,
+				     MAX(r1->top,ybot), r1->bottom);
+		r1 = r1BandEnd;
+	    } while (r1 != r1End);
+	}
+    }
+    else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
+    {
+	do
+	{
+	    r2BandEnd = r2;
+	    while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
+	    {
+		 r2BandEnd++;
+	    }
+	    (* nonOverlap2Func) (newReg, r2, r2BandEnd,
+				MAX(r2->top,ybot), r2->bottom);
+	    r2 = r2BandEnd;
+	} while (r2 != r2End);
+    }
+
+    if (newReg->numRects != curBand)
+    {
+	(void) REGION_Coalesce (newReg, prevBand, curBand);
+    }
+
+    /*
+     * A bit of cleanup. To keep regions from growing without bound,
+     * we shrink the array of rectangles to match the new number of
+     * rectangles in the region. This never goes to 0, however...
+     *
+     * Only do this stuff if the number of rectangles allocated is more than
+     * twice the number of rectangles in the region (a simple optimization...).
+     */
+    if (newReg->numRects < (newReg->size >> 1))
+    {
+	if (REGION_NOT_EMPTY(newReg))
+	{
+	    RECT32 *prev_rects = newReg->rects;
+	    newReg->size = newReg->numRects;
+	    newReg->rects = HeapReAlloc( SystemHeap, 0, newReg->rects,
+				   sizeof(RECT32) * newReg->size );
+	    if (! newReg->rects)
+		newReg->rects = prev_rects;
+	}
+	else
+	{
+	    /*
+	     * No point in doing the extra work involved in an Xrealloc if
+	     * the region is empty
+	     */
+	    newReg->size = 1;
+	    HeapFree( SystemHeap, 0, newReg->rects );
+	    newReg->rects = HeapAlloc( SystemHeap, 0, sizeof(RECT32) );
+	}
+    }
+    HeapFree( SystemHeap, 0, oldRects );
+    return;
+}
+
+/***********************************************************************
+ *          Region Intersection
+ ***********************************************************************/
+
+
+/***********************************************************************
+ *	     REGION_IntersectO
+ *
+ * Handle an overlapping band for REGION_Intersect.
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      Rectangles may be added to the region.
+ *
+ */
+static void REGION_IntersectO(WINEREGION *pReg,  RECT32 *r1, RECT32 *r1End,
+		RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
+
+{
+    INT32       left, right;
+    RECT32      *pNextRect;
+
+    pNextRect = &pReg->rects[pReg->numRects];
+
+    while ((r1 != r1End) && (r2 != r2End))
+    {
+	left = MAX(r1->left, r2->left);
+	right =	MIN(r1->right, r2->right);
+
+	/*
+	 * If there's any overlap between the two rectangles, add that
+	 * overlap to the new region.
+	 * There's no need to check for subsumption because the only way
+	 * such a need could arise is if some region has two rectangles
+	 * right next to each other. Since that should never happen...
+	 */
+	if (left < right)
+	{
+	    MEMCHECK(pReg, pNextRect, pReg->rects);
+	    pNextRect->left = left;
+	    pNextRect->top = top;
+	    pNextRect->right = right;
+	    pNextRect->bottom = bottom;
+	    pReg->numRects += 1;
+	    pNextRect++;
+	}
+
+	/*
+	 * Need to advance the pointers. Shift the one that extends
+	 * to the right the least, since the other still has a chance to
+	 * overlap with that region's next rectangle, if you see what I mean.
+	 */
+	if (r1->right < r2->right)
+	{
+	    r1++;
+	}
+	else if (r2->right < r1->right)
+	{
+	    r2++;
+	}
+	else
+	{
+	    r1++;
+	    r2++;
+	}
+    }
+    return;
+}
+
+/***********************************************************************
+ *	     REGION_IntersectRegion
+ */
+static void REGION_IntersectRegion(WINEREGION *newReg, WINEREGION *reg1,
+				   WINEREGION *reg2)
+{
+   /* check for trivial reject */
+    if ( (!(reg1->numRects)) || (!(reg2->numRects))  ||
+	(!EXTENTCHECK(&reg1->extents, &reg2->extents)))
+	newReg->numRects = 0;
+    else
+	REGION_RegionOp (newReg, reg1, reg2, 
+	 (voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
+    
+    /*
+     * Can't alter newReg's extents before we call miRegionOp because
+     * it might be one of the source regions and miRegionOp depends
+     * on the extents of those regions being the same. Besides, this
+     * way there's no checking against rectangles that will be nuked
+     * due to coalescing, so we have to examine fewer rectangles.
+     */
+    REGION_SetExtents(newReg);
+    newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
+    return;
+}
+
+/***********************************************************************
+ *	     Region Union
+ ***********************************************************************/
+
+/***********************************************************************
+ *	     REGION_UnionNonO
+ *
+ *      Handle a non-overlapping band for the union operation. Just
+ *      Adds the rectangles into the region. Doesn't have to check for
+ *      subsumption or anything.
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      pReg->numRects is incremented and the final rectangles overwritten
+ *      with the rectangles we're passed.
+ *
+ */
+static void REGION_UnionNonO (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd,
+			      INT32 top, INT32 bottom)
+{
+    RECT32 *pNextRect;
+
+    pNextRect = &pReg->rects[pReg->numRects];
+
+    while (r != rEnd)
+    {
+	MEMCHECK(pReg, pNextRect, pReg->rects);
+	pNextRect->left = r->left;
+	pNextRect->top = top;
+	pNextRect->right = r->right;
+	pNextRect->bottom = bottom;
+	pReg->numRects += 1;
+	pNextRect++;
+	r++;
+    }
+    return;
+}
+
+/***********************************************************************
+ *	     REGION_UnionO
+ *
+ *      Handle an overlapping band for the union operation. Picks the
+ *      left-most rectangle each time and merges it into the region.
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      Rectangles are overwritten in pReg->rects and pReg->numRects will
+ *      be changed.
+ *
+ */
+static void REGION_UnionO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End,
+			   RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
+{
+    RECT32 *pNextRect;
+    
+    pNextRect = &pReg->rects[pReg->numRects];
+
+#define MERGERECT(r) \
+    if ((pReg->numRects != 0) &&  \
+	(pNextRect[-1].top == top) &&  \
+	(pNextRect[-1].bottom == bottom) &&  \
+	(pNextRect[-1].right >= r->left))  \
+    {  \
+	if (pNextRect[-1].right < r->right)  \
+	{  \
+	    pNextRect[-1].right = r->right;  \
+	}  \
+    }  \
+    else  \
+    {  \
+	MEMCHECK(pReg, pNextRect, pReg->rects);  \
+	pNextRect->top = top;  \
+	pNextRect->bottom = bottom;  \
+	pNextRect->left = r->left;  \
+	pNextRect->right = r->right;  \
+	pReg->numRects += 1;  \
+	pNextRect += 1;  \
+    }  \
+    r++;
+    
+    while ((r1 != r1End) && (r2 != r2End))
+    {
+	if (r1->left < r2->left)
+	{
+	    MERGERECT(r1);
+	}
+	else
+	{
+	    MERGERECT(r2);
+	}
+    }
+    
+    if (r1 != r1End)
+    {
+	do
+	{
+	    MERGERECT(r1);
+	} while (r1 != r1End);
+    }
+    else while (r2 != r2End)
+    {
+	MERGERECT(r2);
+    }
+    return;
+}
+
+/***********************************************************************
+ *	     REGION_UnionRegion
+ */
+static void REGION_UnionRegion(WINEREGION *newReg, WINEREGION *reg1,
+			       WINEREGION *reg2)
+{
+    /*  checks all the simple cases */
+
+    /*
+     * Region 1 and 2 are the same or region 1 is empty
+     */
+    if ( (reg1 == reg2) || (!(reg1->numRects)) )
+    {
+	if (newReg != reg2)
+	    REGION_CopyRegion(newReg, reg2);
+	return;
+    }
+
+    /*
+     * if nothing to union (region 2 empty)
+     */
+    if (!(reg2->numRects))
+    {
+	if (newReg != reg1)
+	    REGION_CopyRegion(newReg, reg1);
+	return;
+    }
+
+    /*
+     * Region 1 completely subsumes region 2
+     */
+    if ((reg1->numRects == 1) && 
+	(reg1->extents.left <= reg2->extents.left) &&
+	(reg1->extents.top <= reg2->extents.top) &&
+	(reg1->extents.right >= reg2->extents.right) &&
+	(reg1->extents.bottom >= reg2->extents.bottom))
+    {
+	if (newReg != reg1)
+	    REGION_CopyRegion(newReg, reg1);
+	return;
+    }
+
+    /*
+     * Region 2 completely subsumes region 1
+     */
+    if ((reg2->numRects == 1) && 
+	(reg2->extents.left <= reg1->extents.left) &&
+	(reg2->extents.top <= reg1->extents.top) &&
+	(reg2->extents.right >= reg1->extents.right) &&
+	(reg2->extents.bottom >= reg1->extents.bottom))
+    {
+	if (newReg != reg2)
+	    REGION_CopyRegion(newReg, reg2);
+	return;
+    }
+
+    REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO, 
+		(voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
+
+    newReg->extents.left = MIN(reg1->extents.left, reg2->extents.left);
+    newReg->extents.top = MIN(reg1->extents.top, reg2->extents.top);
+    newReg->extents.right = MAX(reg1->extents.right, reg2->extents.right);
+    newReg->extents.bottom = MAX(reg1->extents.bottom, reg2->extents.bottom);
+    newReg->type = (newReg->numRects) ? COMPLEXREGION : NULLREGION ;
+    return;
+}
+
+/***********************************************************************
+ *	     Region Subtraction
+ ***********************************************************************/
+
+/***********************************************************************
+ *	     REGION_SubtractNonO1
+ *
+ *      Deal with non-overlapping band for subtraction. Any parts from
+ *      region 2 we discard. Anything from region 1 we add to the region.
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      pReg may be affected.
+ *
+ */
+static void REGION_SubtractNonO1 (WINEREGION *pReg, RECT32 *r, RECT32 *rEnd, 
+		INT32 top, INT32 bottom)
+{
+    RECT32 *pNextRect;
+	
+    pNextRect = &pReg->rects[pReg->numRects];
+	
+    while (r != rEnd)
+    {
+	MEMCHECK(pReg, pNextRect, pReg->rects);
+	pNextRect->left = r->left;
+	pNextRect->top = top;
+	pNextRect->right = r->right;
+	pNextRect->bottom = bottom;
+	pReg->numRects += 1;
+	pNextRect++;
+	r++;
+    }
+    return;
+}
+
+
+/***********************************************************************
+ *	     REGION_SubtractO
+ *
+ *      Overlapping band subtraction. x1 is the left-most point not yet
+ *      checked.
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      pReg may have rectangles added to it.
+ *
+ */
+static void REGION_SubtractO (WINEREGION *pReg, RECT32 *r1, RECT32 *r1End, 
+		RECT32 *r2, RECT32 *r2End, INT32 top, INT32 bottom)
+{
+    RECT32 *pNextRect;
+    INT32 left;
+    
+    left = r1->left;
+    pNextRect = &pReg->rects[pReg->numRects];
+
+    while ((r1 != r1End) && (r2 != r2End))
+    {
+	if (r2->right <= left)
+	{
+	    /*
+	     * Subtrahend missed the boat: go to next subtrahend.
+	     */
+	    r2++;
+	}
+	else if (r2->left <= left)
+	{
+	    /*
+	     * Subtrahend preceeds minuend: nuke left edge of minuend.
+	     */
+	    left = r2->right;
+	    if (left >= r1->right)
+	    {
+		/*
+		 * Minuend completely covered: advance to next minuend and
+		 * reset left fence to edge of new minuend.
+		 */
+		r1++;
+		if (r1 != r1End)
+		    left = r1->left;
+	    }
+	    else
+	    {
+		/*
+		 * Subtrahend now used up since it doesn't extend beyond
+		 * minuend
+		 */
+		r2++;
+	    }
+	}
+	else if (r2->left < r1->right)
+	{
+	    /*
+	     * Left part of subtrahend covers part of minuend: add uncovered
+	     * part of minuend to region and skip to next subtrahend.
+	     */
+	    MEMCHECK(pReg, pNextRect, pReg->rects);
+	    pNextRect->left = left;
+	    pNextRect->top = top;
+	    pNextRect->right = r2->left;
+	    pNextRect->bottom = bottom;
+	    pReg->numRects += 1;
+	    pNextRect++;
+	    left = r2->right;
+	    if (left >= r1->right)
+	    {
+		/*
+		 * Minuend used up: advance to new...
+		 */
+		r1++;
+		if (r1 != r1End)
+		    left = r1->left;
+	    }
+	    else
+	    {
+		/*
+		 * Subtrahend used up
+		 */
+		r2++;
+	    }
+	}
+	else
+	{
+	    /*
+	     * Minuend used up: add any remaining piece before advancing.
+	     */
+	    if (r1->right > left)
+	    {
+		MEMCHECK(pReg, pNextRect, pReg->rects);
+		pNextRect->left = left;
+		pNextRect->top = top;
+		pNextRect->right = r1->right;
+		pNextRect->bottom = bottom;
+		pReg->numRects += 1;
+		pNextRect++;
+	    }
+	    r1++;
+	    left = r1->left;
+	}
+    }
+
+    /*
+     * Add remaining minuend rectangles to region.
+     */
+    while (r1 != r1End)
+    {
+	MEMCHECK(pReg, pNextRect, pReg->rects);
+	pNextRect->left = left;
+	pNextRect->top = top;
+	pNextRect->right = r1->right;
+	pNextRect->bottom = bottom;
+	pReg->numRects += 1;
+	pNextRect++;
+	r1++;
+	if (r1 != r1End)
+	{
+	    left = r1->left;
+	}
+    }
+    return;
+}
+	
+/***********************************************************************
+ *	     REGION_SubtractRegion
+ *
+ *      Subtract regS from regM and leave the result in regD.
+ *      S stands for subtrahend, M for minuend and D for difference.
+ *
+ * Results:
+ *      TRUE.
+ *
+ * Side Effects:
+ *      regD is overwritten.
+ *
+ */
+static void REGION_SubtractRegion(WINEREGION *regD, WINEREGION *regM,
+				                       WINEREGION *regS )
+{
+   /* check for trivial reject */
+    if ( (!(regM->numRects)) || (!(regS->numRects))  ||
+	(!EXTENTCHECK(&regM->extents, &regS->extents)) )
+    {
+	REGION_CopyRegion(regD, regM);
+	return;
+    }
+ 
+    REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO, 
+		(voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
+
+    /*
+     * Can't alter newReg's extents before we call miRegionOp because
+     * it might be one of the source regions and miRegionOp depends
+     * on the extents of those regions being the unaltered. Besides, this
+     * way there's no checking against rectangles that will be nuked
+     * due to coalescing, so we have to examine fewer rectangles.
+     */
+    REGION_SetExtents (regD);
+    regD->type = (regD->numRects) ? COMPLEXREGION : NULLREGION ;
+    return;
+}
+
+/***********************************************************************
+ *	     REGION_XorRegion
+ */
+static void REGION_XorRegion(WINEREGION *dr, WINEREGION *sra,
+							WINEREGION *srb)
+{
+    WINEREGION *tra, *trb;
+
+    if ((! (tra = REGION_AllocWineRegion())) || 
+	(! (trb = REGION_AllocWineRegion())))
+	return;
+    REGION_SubtractRegion(tra,sra,srb);
+    REGION_SubtractRegion(trb,srb,sra);
+    REGION_UnionRegion(dr,tra,trb);
+    REGION_DestroyWineRegion(tra);
+    REGION_DestroyWineRegion(trb);
+    return;
+}
+
+/**************************************************************************
+ *
+ *    Poly Regions
+ * 
+ *************************************************************************/
+
+#define LARGE_COORDINATE  0x7fffffff /* FIXME */
+#define SMALL_COORDINATE  0x80000000
+
+/***********************************************************************
+ *     REGION_InsertEdgeInET
+ *
+ *     Insert the given edge into the edge table.
+ *     First we must find the correct bucket in the
+ *     Edge table, then find the right slot in the
+ *     bucket.  Finally, we can insert it.
+ *
+ */
+static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
+                INT32 scanline, ScanLineListBlock **SLLBlock, INT32 *iSLLBlock)
+
+{
+    EdgeTableEntry *start, *prev;
+    ScanLineList *pSLL, *pPrevSLL;
+    ScanLineListBlock *tmpSLLBlock;
+
+    /*
+     * find the right bucket to put the edge into
+     */
+    pPrevSLL = &ET->scanlines;
+    pSLL = pPrevSLL->next;
+    while (pSLL && (pSLL->scanline < scanline)) 
+    {
+        pPrevSLL = pSLL;
+        pSLL = pSLL->next;
+    }
+
+    /*
+     * reassign pSLL (pointer to ScanLineList) if necessary
+     */
+    if ((!pSLL) || (pSLL->scanline > scanline)) 
+    {
+        if (*iSLLBlock > SLLSPERBLOCK-1) 
+        {
+            tmpSLLBlock = HeapAlloc( SystemHeap, 0, sizeof(ScanLineListBlock));
+	    if(!tmpSLLBlock)
+	    {
+	        fprintf(stderr, "REGION_InsertEdgeInET(): Can't alloc SLLB\n");
+		return;
+	    }
+            (*SLLBlock)->next = tmpSLLBlock;
+            tmpSLLBlock->next = (ScanLineListBlock *)NULL;
+            *SLLBlock = tmpSLLBlock;
+            *iSLLBlock = 0;
+        }
+        pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+        pSLL->next = pPrevSLL->next;
+        pSLL->edgelist = (EdgeTableEntry *)NULL;
+        pPrevSLL->next = pSLL;
+    }
+    pSLL->scanline = scanline;
+
+    /*
+     * now insert the edge in the right bucket
+     */
+    prev = (EdgeTableEntry *)NULL;
+    start = pSLL->edgelist;
+    while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) 
+    {
+        prev = start;
+        start = start->next;
+    }
+    ETE->next = start;
+
+    if (prev)
+        prev->next = ETE;
+    else
+        pSLL->edgelist = ETE;
+}
+
+/***********************************************************************
+ *     REGION_CreateEdgeTable
+ *
+ *     This routine creates the edge table for
+ *     scan converting polygons. 
+ *     The Edge Table (ET) looks like:
+ *
+ *    EdgeTable
+ *     --------
+ *    |  ymax  |        ScanLineLists
+ *    |scanline|-->------------>-------------->...
+ *     --------   |scanline|   |scanline|
+ *                |edgelist|   |edgelist|
+ *                ---------    ---------
+ *                    |             |
+ *                    |             |
+ *                    V             V
+ *              list of ETEs   list of ETEs
+ *
+ *     where ETE is an EdgeTableEntry data structure,
+ *     and there is one ScanLineList per scanline at
+ *     which an edge is initially entered.
+ *
+ */
+static void REGION_CreateETandAET(const INT32 *Count, INT32 nbpolygons, 
+            const POINT32 *pts, EdgeTable *ET, EdgeTableEntry *AET,
+            EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
+{
+    const POINT32 *top, *bottom;
+    const POINT32 *PrevPt, *CurrPt, *EndPt;
+    INT32 poly, count;
+    int iSLLBlock = 0;
+    int dy;
+
+    
+    /*
+     *  initialize the Active Edge Table
+     */
+    AET->next = (EdgeTableEntry *)NULL;
+    AET->back = (EdgeTableEntry *)NULL;
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    AET->bres.minor_axis = SMALL_COORDINATE;
+
+    /*
+     *  initialize the Edge Table.
+     */
+    ET->scanlines.next = (ScanLineList *)NULL;
+    ET->ymax = SMALL_COORDINATE;
+    ET->ymin = LARGE_COORDINATE;
+    pSLLBlock->next = (ScanLineListBlock *)NULL;
+
+    EndPt = pts - 1;
+    for(poly = 0; poly < nbpolygons; poly++)
+    {
+        count = Count[poly];
+        EndPt += count;
+        if(count < 2)
+	    continue;
+	
+	PrevPt = EndPt;
+
+    /*
+     *  for each vertex in the array of points.
+     *  In this loop we are dealing with two vertices at
+     *  a time -- these make up one edge of the polygon.
+     */
+	while (count--) 
+	{
+	    CurrPt = pts++;
+
+        /*
+         *  find out which point is above and which is below.
+         */
+	    if (PrevPt->y > CurrPt->y) 
+	    {
+	        bottom = PrevPt, top = CurrPt;
+		pETEs->ClockWise = 0;
+	    }
+	    else 
+	    {
+	        bottom = CurrPt, top = PrevPt;
+		pETEs->ClockWise = 1;
+	    }
+
+        /*
+         * don't add horizontal edges to the Edge table.
+         */
+	    if (bottom->y != top->y) 
+	    {
+	        pETEs->ymax = bottom->y-1;
+				/* -1 so we don't get last scanline */
+
+            /*
+             *  initialize integer edge algorithm
+             */
+		dy = bottom->y - top->y;
+		BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+
+		REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, 
+								&iSLLBlock);
+
+		if (PrevPt->y > ET->ymax)
+		  ET->ymax = PrevPt->y;
+		if (PrevPt->y < ET->ymin)
+		  ET->ymin = PrevPt->y;
+		pETEs++;
+	    }
+
+	    PrevPt = CurrPt;
+	}
+    }
+}
+
+/***********************************************************************
+ *     REGION_loadAET
+ *
+ *     This routine moves EdgeTableEntries from the
+ *     EdgeTable into the Active Edge Table,
+ *     leaving them sorted by smaller x coordinate.
+ *
+ */
+static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
+{
+    EdgeTableEntry *pPrevAET;
+    EdgeTableEntry *tmp;
+
+    pPrevAET = AET;
+    AET = AET->next;
+    while (ETEs) 
+    {
+        while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis)) 
+        {
+            pPrevAET = AET;
+            AET = AET->next;
+        }
+        tmp = ETEs->next;
+        ETEs->next = AET;
+        if (AET)
+            AET->back = ETEs;
+        ETEs->back = pPrevAET;
+        pPrevAET->next = ETEs;
+        pPrevAET = ETEs;
+
+        ETEs = tmp;
+    }
+}
+
+/***********************************************************************
+ *     REGION_computeWAET
+ *
+ *     This routine links the AET by the
+ *     nextWETE (winding EdgeTableEntry) link for
+ *     use by the winding number rule.  The final 
+ *     Active Edge Table (AET) might look something
+ *     like:
+ *
+ *     AET
+ *     ----------  ---------   ---------
+ *     |ymax    |  |ymax    |  |ymax    | 
+ *     | ...    |  |...     |  |...     |
+ *     |next    |->|next    |->|next    |->...
+ *     |nextWETE|  |nextWETE|  |nextWETE|
+ *     ---------   ---------   ^--------
+ *         |                   |       |
+ *         V------------------->       V---> ...
+ *
+ */
+static void REGION_computeWAET(EdgeTableEntry *AET)
+{
+    register EdgeTableEntry *pWETE;
+    register int inside = 1;
+    register int isInside = 0;
+
+    AET->nextWETE = (EdgeTableEntry *)NULL;
+    pWETE = AET;
+    AET = AET->next;
+    while (AET) 
+    {
+        if (AET->ClockWise)
+            isInside++;
+        else
+            isInside--;
+
+        if ((!inside && !isInside) ||
+            ( inside &&  isInside)) 
+        {
+            pWETE->nextWETE = AET;
+            pWETE = AET;
+            inside = !inside;
+        }
+        AET = AET->next;
+    }
+    pWETE->nextWETE = (EdgeTableEntry *)NULL;
+}
+
+/***********************************************************************
+ *     REGION_InsertionSort
+ *
+ *     Just a simple insertion sort using
+ *     pointers and back pointers to sort the Active
+ *     Edge Table.
+ *
+ */
+static BOOL32 REGION_InsertionSort(EdgeTableEntry *AET)
+{
+    EdgeTableEntry *pETEchase;
+    EdgeTableEntry *pETEinsert;
+    EdgeTableEntry *pETEchaseBackTMP;
+    BOOL32 changed = FALSE;
+
+    AET = AET->next;
+    while (AET) 
+    {
+        pETEinsert = AET;
+        pETEchase = AET;
+        while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
+            pETEchase = pETEchase->back;
+
+        AET = AET->next;
+        if (pETEchase != pETEinsert) 
+        {
+            pETEchaseBackTMP = pETEchase->back;
+            pETEinsert->back->next = AET;
+            if (AET)
+                AET->back = pETEinsert->back;
+            pETEinsert->next = pETEchase;
+            pETEchase->back->next = pETEinsert;
+            pETEchase->back = pETEinsert;
+            pETEinsert->back = pETEchaseBackTMP;
+            changed = TRUE;
+        }
+    }
+    return changed;
+}
+
+/***********************************************************************
+ *     REGION_FreeStorage
+ *
+ *     Clean up our act.
+ */
+static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
+{
+    ScanLineListBlock   *tmpSLLBlock;
+
+    while (pSLLBlock) 
+    {
+        tmpSLLBlock = pSLLBlock->next;
+        HeapFree( SystemHeap, 0, pSLLBlock );
+        pSLLBlock = tmpSLLBlock;
+    }
+}
+
+
+/***********************************************************************
+ *     REGION_PtsToRegion
+ *
+ *     Create an array of rectangles from a list of points.
+ */
+static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock, 
+		       POINTBLOCK *FirstPtBlock, WINEREGION *reg)
+{
+    RECT32 *rects;
+    POINT32 *pts;
+    POINTBLOCK *CurPtBlock;
+    int i;
+    RECT32 *extents;
+    INT32 numRects;
+ 
+    extents = &reg->extents;
+ 
+    numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
+ 
+    if (!(reg->rects = HeapReAlloc( SystemHeap, 0, reg->rects, 
+			   sizeof(RECT32) * numRects )))
+        return(0);
+ 
+    reg->size = numRects;
+    CurPtBlock = FirstPtBlock;
+    rects = reg->rects - 1;
+    numRects = 0;
+    extents->left = LARGE_COORDINATE,  extents->right = SMALL_COORDINATE;
+ 
+    for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
+	/* the loop uses 2 points per iteration */
+	i = NUMPTSTOBUFFER >> 1;
+	if (!numFullPtBlocks)
+	    i = iCurPtBlock >> 1;
+	for (pts = CurPtBlock->pts; i--; pts += 2) {
+	    if (pts->x == pts[1].x)
+		continue;
+	    if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
+		pts[1].x == rects->right &&
+		(numRects == 1 || rects[-1].top != rects->top) &&
+		(i && pts[2].y > pts[1].y)) {
+		rects->bottom = pts[1].y + 1;
+		continue;
+	    }
+	    numRects++;
+	    rects++;
+	    rects->left = pts->x;  rects->top = pts->y;
+	    rects->right = pts[1].x;  rects->bottom = pts[1].y + 1;
+	    if (rects->left < extents->left)
+		extents->left = rects->left;
+	    if (rects->right > extents->right)
+		extents->right = rects->right;
+        }
+	CurPtBlock = CurPtBlock->next;
+    }
+
+    if (numRects) {
+	extents->top = reg->rects->top;
+	extents->bottom = rects->bottom;
+    } else {
+	extents->left = 0;
+	extents->top = 0;
+	extents->right = 0;
+	extents->bottom = 0;
+    }
+    reg->numRects = numRects;
+ 
+    return(TRUE);
+}
+
+/***********************************************************************
+ *           CreatePolyPolygonRgn32    (GDI32.57)
+ */
+HRGN32 WINAPI CreatePolyPolygonRgn32(const POINT32 *Pts, const INT32 *Count, 
+		      INT32 nbpolygons, INT32 mode)
+{
+    HRGN32 hrgn;
+    RGNOBJ *obj;
+    WINEREGION *region;
+    register EdgeTableEntry *pAET;   /* Active Edge Table       */
+    register INT32 y;                /* current scanline        */
+    register int iPts = 0;           /* number of pts in buffer */
+    register EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
+    register ScanLineList *pSLL;     /* current scanLineList    */
+    register POINT32 *pts;           /* output buffer           */
+    EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
+    EdgeTable ET;                    /* header node for ET      */
+    EdgeTableEntry AET;              /* header node for AET     */
+    EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
+    ScanLineListBlock SLLBlock;      /* header for scanlinelist */
+    int fixWAET = FALSE;
+    POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
+    POINTBLOCK *tmpPtBlock;
+    int numFullPtBlocks = 0;
+    INT32 poly, total;
+
+    if(!(hrgn = REGION_CreateRegion()))
+        return 0;
+    obj = (RGNOBJ *) GDI_GetObjPtr( hrgn, REGION_MAGIC );
+    region = obj->rgn;
+
+    /* special case a rectangle */
+
+    if (((nbpolygons == 1) && ((*Count == 4) ||
+       ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
+	(((Pts[0].y == Pts[1].y) &&
+	  (Pts[1].x == Pts[2].x) &&
+	  (Pts[2].y == Pts[3].y) &&
+	  (Pts[3].x == Pts[0].x)) ||
+	 ((Pts[0].x == Pts[1].x) &&
+	  (Pts[1].y == Pts[2].y) &&
+	  (Pts[2].x == Pts[3].x) &&
+	  (Pts[3].y == Pts[0].y))))
+    {
+        SetRectRgn32( hrgn, MIN(Pts[0].x, Pts[2].x), MIN(Pts[0].y, Pts[2].y), 
+		            MAX(Pts[0].x, Pts[2].x), MAX(Pts[0].y, Pts[2].y) );
+	GDI_HEAP_UNLOCK( hrgn );
+	return hrgn;
+    }
+    
+    for(poly = total = 0; poly < nbpolygons; poly++)
+        total += Count[poly];
+    if (! (pETEs = HeapAlloc( SystemHeap, 0, sizeof(EdgeTableEntry) * total )))
+    {
+        REGION_DeleteObject( hrgn, obj );
 	return 0;
+    }
+    pts = FirstPtBlock.pts;
+    REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
+    pSLL = ET.scanlines.next;
+    curPtBlock = &FirstPtBlock;
+ 
+    if (mode != WINDING) {
+        /*
+         *  for each scanline
+         */
+        for (y = ET.ymin; y < ET.ymax; y++) {
+            /*
+             *  Add a new edge to the active edge table when we
+             *  get to the next edge.
+             */
+            if (pSLL != NULL && y == pSLL->scanline) {
+                REGION_loadAET(&AET, pSLL->edgelist);
+                pSLL = pSLL->next;
+            }
+            pPrevAET = &AET;
+            pAET = AET.next;
+ 
+            /*
+             *  for each active edge
+             */
+            while (pAET) {
+                pts->x = pAET->bres.minor_axis,  pts->y = y;
+                pts++, iPts++;
+ 
+                /*
+                 *  send out the buffer
+                 */
+                if (iPts == NUMPTSTOBUFFER) {
+                    tmpPtBlock = HeapAlloc( SystemHeap, 0, sizeof(POINTBLOCK));
+		    if(!tmpPtBlock) {
+		        fprintf(stderr, 
+				"CreatePolyPolygonRgn(): can't alloc tPB\n");
+			return 0;
+		    }
+                    curPtBlock->next = tmpPtBlock;
+                    curPtBlock = tmpPtBlock;
+                    pts = curPtBlock->pts;
+                    numFullPtBlocks++;
+                    iPts = 0;
+                }
+                EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
+            }
+            REGION_InsertionSort(&AET);
+        }
+    }
+    else {
+        /*
+         *  for each scanline
+         */
+        for (y = ET.ymin; y < ET.ymax; y++) {
+            /*
+             *  Add a new edge to the active edge table when we
+             *  get to the next edge.
+             */
+            if (pSLL != NULL && y == pSLL->scanline) {
+                REGION_loadAET(&AET, pSLL->edgelist);
+                REGION_computeWAET(&AET);
+                pSLL = pSLL->next;
+            }
+            pPrevAET = &AET;
+            pAET = AET.next;
+            pWETE = pAET;
+ 
+            /*
+             *  for each active edge
+             */
+            while (pAET) {
+                /*
+                 *  add to the buffer only those edges that
+                 *  are in the Winding active edge table.
+                 */
+                if (pWETE == pAET) {
+                    pts->x = pAET->bres.minor_axis,  pts->y = y;
+                    pts++, iPts++;
+ 
+                    /*
+                     *  send out the buffer
+                     */
+                    if (iPts == NUMPTSTOBUFFER) {
+                        tmpPtBlock = HeapAlloc( SystemHeap, 0,
+					       sizeof(POINTBLOCK) );
+			if(!tmpPtBlock) {
+			    fprintf(stderr, 
+				"CreatePolyPolygonRgn(): can't alloc tPB\n");
+			    return 0;
+			}
+                        curPtBlock->next = tmpPtBlock;
+                        curPtBlock = tmpPtBlock;
+                        pts = curPtBlock->pts;
+                        numFullPtBlocks++;    iPts = 0;
+                    }
+                    pWETE = pWETE->nextWETE;
+                }
+                EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
+            }
+ 
+            /*
+             *  recompute the winding active edge table if
+             *  we just resorted or have exited an edge.
+             */
+            if (REGION_InsertionSort(&AET) || fixWAET) {
+                REGION_computeWAET(&AET);
+                fixWAET = FALSE;
+            }
+        }
+    }
+    REGION_FreeStorage(SLLBlock.next);	
+    REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
+    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
+	tmpPtBlock = curPtBlock->next;
+	HeapFree( SystemHeap, 0, curPtBlock );
+	curPtBlock = tmpPtBlock;
+    }
+    HeapFree( SystemHeap, 0, pETEs );
+    GDI_HEAP_UNLOCK( hrgn );
+    return hrgn;
+}
+
+
+/***********************************************************************
+ *           CreatePolygonRgn16    (GDI.63)
+ */
+HRGN16 WINAPI CreatePolygonRgn16( const POINT16 * points, INT16 count,
+                                  INT16 mode )
+{
+    return CreatePolyPolygonRgn16( points, &count, 1, mode );
+}
+
+/***********************************************************************
+ *           CreatePolyPolygonRgn16    (GDI.451)
+ */
+HRGN16 WINAPI CreatePolyPolygonRgn16( const POINT16 *points,
+                const INT16 *count, INT16 nbpolygons, INT16 mode )
+{
+    HRGN32 hrgn;
+    int i, npts = 0;
+    INT32 *count32;
+    POINT32 *points32;
+
+    for (i = 0; i < nbpolygons; i++)
+	npts += count[i];
+    points32 = HeapAlloc( SystemHeap, 0, npts * sizeof(POINT32) );
+    for (i = 0; i < npts; i++)
+    	CONV_POINT16TO32( &(points[i]), &(points32[i]) );
+
+    count32 = HeapAlloc( SystemHeap, 0, nbpolygons * sizeof(INT32) );
+    for (i = 0; i < nbpolygons; i++)
+    	count32[i] = count[i];
+    hrgn = CreatePolyPolygonRgn32( points32, count32, nbpolygons, mode );
+    HeapFree( SystemHeap, 0, count32 );
+    HeapFree( SystemHeap, 0, points32 );
+    return hrgn;
+}
+
+/***********************************************************************
+ *           CreatePolygonRgn32    (GDI32.58)
+ */
+HRGN32 WINAPI CreatePolygonRgn32( const POINT32 *points, INT32 count,
+                                  INT32 mode )
+{
+    return CreatePolyPolygonRgn32( points, &count, 1, mode );
 }
diff --git a/programs/notepad/En.rc b/programs/notepad/En.rc
index e4ebc9e..01b24ae 100644
--- a/programs/notepad/En.rc
+++ b/programs/notepad/En.rc
@@ -2,7 +2,7 @@
  * Notepad (English resources)
  *
  * Copyright 1997 Marcel Baur <mbaur@g26.ethz.ch>
- * FIXME: See TODO about how to fix weak translations.
+ * Proofread 1998 by David Lee Lambert <lamber45@egr.msu.edu>
  */
 
 #define LANGUAGE_ID                  En
@@ -13,9 +13,9 @@
 
 #define MENU_FILE                    "&File"
 #define MENU_FILE_NEW                "&New..."
-#define MENU_FILE_OPEN               "O&pen"
+#define MENU_FILE_OPEN               "&Open"
 #define MENU_FILE_SAVE               "&Save"
-#define MENU_FILE_SAVEAS             "&Save as..."
+#define MENU_FILE_SAVEAS             "Save &as..."
 #define MENU_FILE_PRINT              "&Print"
 #define MENU_FILE_PAGESETUP          "Page Se&tup..."
 #define MENU_FILE_PRINTSETUP         "P&rinter Setup..."
@@ -23,7 +23,7 @@
 
 #define MENU_EDIT                    "&Edit"
 #define MENU_EDIT_UNDO               "&Undo\tCtrl+Z"
-#define MENU_EDIT_CUT                "Cu&t\Ctrl+X"
+#define MENU_EDIT_CUT                "Cu&t\tCtrl+X"
 #define MENU_EDIT_COPY               "&Copy\tCtrl+C"
 #define MENU_EDIT_PASTE              "&Paste\tCtrl+V"
 #define MENU_EDIT_DELETE             "&Delete\tDel"
@@ -57,7 +57,7 @@
 #define DIALOG_PAGESETUP_CAPTION     "Page Setup"
 #define DIALOG_PAGESETUP_HEAD        "&Header:"
 #define DIALOG_PAGESETUP_TAIL        "&Footer:"
-#define DIALOG_PAGESETUP_BORDER      "Borders:"
+#define DIALOG_PAGESETUP_BORDER      "&Margins:"
 #define DIALOG_PAGESETUP_LEFT        "&Left:"
 #define DIALOG_PAGESETUP_RIGHT       "&Right:"
 #define DIALOG_PAGESETUP_TOP         "&Top:"
@@ -75,7 +75,7 @@
 #define STRING_ALLFILES              "All files (*.*)"
 #define STRING_TEXTFILES             "Text files (*.txt)"
 
-#define STRING_TOOLARGE         "File '%s' ist too large for notepad.\n \
+#define STRING_TOOLARGE         "File '%s' is too large for notepad.\n \
 Please use a different editor."
 
 #define STRING_NOTEXT           "You didn't enter any text. \
@@ -89,3 +89,7 @@
 
 #include "notepad.rc"
 
+
+
+
+
diff --git a/programs/notepad/notepad.rc b/programs/notepad/notepad.rc
index c3d4748..5a438de 100644
--- a/programs/notepad/notepad.rc
+++ b/programs/notepad/notepad.rc
@@ -51,10 +51,12 @@
    MENUITEM MENU_HELP_HELP_ON_HELP,     NP_HELP_ON_HELP
    MENUITEM SEPARATOR
 
- POPUP MENU_INFO {
-   MENUITEM MENU_INFO_LICENSE,          NP_HELP_LICENSE
-   MENUITEM MENU_INFO_NO_WARRANTY,      NP_HELP_NO_WARRANTY
-   MENUITEM MENU_INFO_ABOUT_WINE,       NP_HELP_ABOUT_WINE
+    POPUP MENU_INFO {
+      MENUITEM MENU_INFO_LICENSE,          NP_HELP_LICENSE
+      MENUITEM MENU_INFO_NO_WARRANTY,      NP_HELP_NO_WARRANTY
+      MENUITEM MENU_INFO_ABOUT_WINE,       NP_HELP_ABOUT_WINE
+    }
  }
+ 
 }
 
diff --git a/relay32/builtin32.c b/relay32/builtin32.c
index 764acad..01f9a7d 100644
--- a/relay32/builtin32.c
+++ b/relay32/builtin32.c
@@ -120,6 +120,7 @@
     DEBUG_ENTRY_POINT *debug;
     REG_ENTRY_POINT *regs;
     PE_MODREF *pem;
+    PDB32 *pdb = PROCESS_Current();
     INT32 i, size;
     BYTE *addr;
 
@@ -278,8 +279,8 @@
                                   sizeof(*pem) );
     pem->module = (HMODULE32)addr;
     pem->pe_export = exp;
-    pem->next = pCurrentProcess->modref_list;
-    pCurrentProcess->modref_list = pem;
+    pem->next = pdb->modref_list;
+    pdb->modref_list = pem;
 
     /* Create a Win16 dummy module */
 
diff --git a/relay32/gdi32.spec b/relay32/gdi32.spec
index fad209f..b6c5bea 100644
--- a/relay32/gdi32.spec
+++ b/relay32/gdi32.spec
@@ -98,7 +98,7 @@
  91 stdcall Escape(long long long ptr ptr) Escape32
  92 stdcall ExcludeClipRect(long long long long long) ExcludeClipRect32
  93 stdcall ExtCreatePen(long long ptr long ptr) ExtCreatePen32
- 94 stub ExtCreateRegion
+ 94 stdcall ExtCreateRegion(ptr long ptr) ExtCreateRegion
  95 stdcall ExtEscape(long long long ptr long ptr) ExtEscape32
  96 stdcall ExtFloodFill(long long long long long) ExtFloodFill32
  97 stub ExtSelectClipRgn
diff --git a/relay32/relay386.c b/relay32/relay386.c
index 752a582..1b5f706 100644
--- a/relay32/relay386.c
+++ b/relay32/relay386.c
@@ -14,6 +14,22 @@
 #include "stddebug.h"
 #include "debug.h"
 
+static void _dumpstr(unsigned char *s) {
+	fputs("\"",stdout);
+	while (*s) {
+		if (*s<' ') {
+			printf("\\0x%02x",*s++);
+			continue;
+		}
+		if (*s=='\\') {
+			fputs("\\\\",stdout);
+			s++;
+			continue;
+		}
+		fputc(*s++,stdout);
+	}
+	fputs("\"",stdout);
+}
 
 /***********************************************************************
  *           RELAY_CallFrom32
@@ -52,9 +68,14 @@
             {
                 char buff[80];
                 lstrcpynWtoA( buff, (LPWSTR)args[i], sizeof(buff) );
-	    	printf( "%08x L\"%s\"", args[i], buff );
+		buff[sizeof(buff)-1]='\0';
+	    	printf( "%08x L", args[i] );
+		_dumpstr((unsigned char*)buff);
 	    }
-            else printf( "%08x \"%s\"", args[i], (char *)args[i] );
+            else {
+	    	printf( "%08x ", args[i] );
+		_dumpstr((unsigned char*)args[i]);
+	    }
 	}
         else printf( "%08x", args[i] );
     }
diff --git a/relay32/user32.spec b/relay32/user32.spec
index 06ce2b1..5fdddb2 100644
--- a/relay32/user32.spec
+++ b/relay32/user32.spec
@@ -281,7 +281,7 @@
 276 stdcall GetNextDlgTabItem(long long long) GetNextDlgTabItem32
 277 stdcall GetOpenClipboardWindow() GetOpenClipboardWindow32
 278 stdcall GetParent(long) GetParent32
-279 stub GetPriorityClipboardFormat
+279 stdcall GetPriorityClipboardFormat(ptr long) GetPriorityClipboardFormat32
 280 stub GetProcessWindowStation
 281 stdcall GetPropA(long ptr) GetProp32A
 282 stdcall GetPropW(long ptr) GetProp32W
diff --git a/relay32/wow32.spec b/relay32/wow32.spec
index 4a37728..c60e58d 100644
--- a/relay32/wow32.spec
+++ b/relay32/wow32.spec
@@ -1,13 +1,13 @@
 name	wow32
 type	win32
 
-  1 stub    WOW_1
-  2 stub    WOWCallback16
+  1 stdcall WOW_1(long long) WOW32_1
+  2 stdcall WOWCallback16(long long) WOWCallback16
   3 stub    WOWCallback16Ex
   4 stub    WOWDirectedYield16
-  5 stub    WOWGetVDMPointer
-  6 stub    WOWGetVDMPointerFix
-  7 stub    WOWGetVDMPointerUnfix
+  5 stdcall WOWGetVDMPointer(long long long) WOWGetVDMPointer
+  6 stdcall WOWGetVDMPointerFix(long long long) WOWGetVDMPointerFix
+  7 stdcall WOWGetVDMPointerUnfix(long) WOWGetVDMPointerUnfix
   8 stub    WOWGlobalAlloc16
   9 stub    WOWGlobalAllocLock16
  10 stub    WOWGlobalFree16
diff --git a/scheduler/Makefile.in b/scheduler/Makefile.in
index 632f046..178d43a 100644
--- a/scheduler/Makefile.in
+++ b/scheduler/Makefile.in
@@ -13,6 +13,7 @@
 	process.c \
 	semaphore.c \
 	synchro.c \
+	sysdeps.c \
 	thread.c
 
 all: $(MODULE).o
diff --git a/scheduler/critsection.c b/scheduler/critsection.c
index 7f5c5b9..dc91651 100644
--- a/scheduler/critsection.c
+++ b/scheduler/critsection.c
@@ -28,9 +28,17 @@
     BOOL32        signaled;
 } CRIT_SECTION;
 
+/* On some systems this is supposed to be defined in the program */
+#ifndef HAVE_UNION_SEMUN
+union semun {
+    int val;
+    struct semid_ds *buf;
+    ushort *array;
+};
+#endif
 
 static BOOL32 CRIT_SECTION_Signaled( K32OBJ *obj, DWORD thread_id );
-static void CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id );
+static BOOL32 CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id );
 static void CRIT_SECTION_AddWait( K32OBJ *obj, DWORD thread_id );
 static void CRIT_SECTION_RemoveWait( K32OBJ *obj, DWORD thread_id );
 static void CRIT_SECTION_Destroy( K32OBJ *obj );
@@ -237,12 +245,13 @@
  *
  * Wait on this object has been satisfied.
  */
-static void CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id )
+static BOOL32 CRIT_SECTION_Satisfied( K32OBJ *obj, DWORD thread_id )
 {
     CRIT_SECTION *crit = (CRIT_SECTION *)obj;
     assert( obj->type == K32OBJ_CRITICAL_SECTION );
     /* Only one thread is allowed to wake up */
     crit->signaled = FALSE;
+    return FALSE;  /* Not abandoned */
 }
 
 
diff --git a/scheduler/event.c b/scheduler/event.c
index 4eb5e0c..0b578ba 100644
--- a/scheduler/event.c
+++ b/scheduler/event.c
@@ -21,7 +21,7 @@
 } EVENT;
 
 static BOOL32 EVENT_Signaled( K32OBJ *obj, DWORD thread_id );
-static void EVENT_Satisfied( K32OBJ *obj, DWORD thread_id );
+static BOOL32 EVENT_Satisfied( K32OBJ *obj, DWORD thread_id );
 static void EVENT_AddWait( K32OBJ *obj, DWORD thread_id );
 static void EVENT_RemoveWait( K32OBJ *obj, DWORD thread_id );
 static void EVENT_Destroy( K32OBJ *obj );
@@ -219,12 +219,13 @@
  *
  * Wait on this object has been satisfied.
  */
-static void EVENT_Satisfied( K32OBJ *obj, DWORD thread_id )
+static BOOL32 EVENT_Satisfied( K32OBJ *obj, DWORD thread_id )
 {
     EVENT *event = (EVENT *)obj;
     assert( obj->type == K32OBJ_EVENT );
     /* Reset if it's an auto-reset event */
     if (!event->manual_reset) event->signaled = FALSE;
+    return FALSE;  /* Not abandoned */
 }
 
 
diff --git a/scheduler/mutex.c b/scheduler/mutex.c
index 737789a..aebf9a6 100644
--- a/scheduler/mutex.c
+++ b/scheduler/mutex.c
@@ -12,16 +12,19 @@
 #include "thread.h"
 #include "heap.h"
 
-typedef struct
+typedef struct _MUTEX
 {
-    K32OBJ        header;
-    THREAD_QUEUE  wait_queue;
-    DWORD         owner;
-    DWORD         count;
+    K32OBJ         header;
+    THREAD_QUEUE   wait_queue;
+    DWORD          owner;
+    DWORD          count;
+    BOOL32         abandoned;
+    struct _MUTEX *next;
+    struct _MUTEX *prev;
 } MUTEX;
 
 static BOOL32 MUTEX_Signaled( K32OBJ *obj, DWORD thread_id );
-static void MUTEX_Satisfied( K32OBJ *obj, DWORD thread_id );
+static BOOL32 MUTEX_Satisfied( K32OBJ *obj, DWORD thread_id );
 static void MUTEX_AddWait( K32OBJ *obj, DWORD thread_id );
 static void MUTEX_RemoveWait( K32OBJ *obj, DWORD thread_id );
 static void MUTEX_Destroy( K32OBJ *obj );
@@ -37,6 +40,40 @@
 
 
 /***********************************************************************
+ *           MUTEX_Release
+ *
+ * Release a mutex once the count is 0.
+ * Helper function for MUTEX_Abandon and ReleaseMutex.
+ */
+static void MUTEX_Release( MUTEX *mutex )
+{
+    /* Remove the mutex from the thread list of owned mutexes */
+    if (mutex->next) mutex->next->prev = mutex->prev;
+    if (mutex->prev) mutex->prev->next = mutex->next;
+    else THREAD_Current()->mutex_list = &mutex->next->header;
+    mutex->next = mutex->prev = NULL;
+    mutex->owner = 0;
+    SYNC_WakeUp( &mutex->wait_queue, INFINITE32 );
+}
+
+
+/***********************************************************************
+ *           MUTEX_Abandon
+ *
+ * Abandon a mutex.
+ */
+void MUTEX_Abandon( K32OBJ *obj )
+{
+    MUTEX *mutex = (MUTEX *)obj;
+    assert( obj->type == K32OBJ_MUTEX );
+    assert( mutex->count && (mutex->owner == GetCurrentThreadId()) );
+    mutex->count = 0;
+    mutex->abandoned = TRUE;
+    MUTEX_Release( mutex );
+}
+
+
+/***********************************************************************
  *           CreateMutex32A   (KERNEL32.166)
  */
 HANDLE32 WINAPI CreateMutex32A( SECURITY_ATTRIBUTES *sa, BOOL32 owner,
@@ -52,18 +89,27 @@
     {
         /* Finish initializing it */
         mutex->wait_queue = NULL;
+        mutex->abandoned  = FALSE;
+        mutex->prev       = NULL;
         if (owner)
         {
+            K32OBJ **list;
             mutex->owner = GetCurrentThreadId();
             mutex->count = 1;
+            /* Add the mutex in the thread list of owned mutexes */
+            list = &THREAD_Current()->mutex_list;
+            if ((mutex->next = (MUTEX *)*list)) mutex->next->prev = mutex;
+            *list = &mutex->header;
         }
         else
         {
             mutex->owner = 0;
             mutex->count = 0;
+            mutex->next  = NULL;
         }
         K32OBJ_DecCount( &mutex->header );
     }
+    SetLastError(0); /* FIXME */
     SYSTEM_UNLOCK();
     return handle;
 }
@@ -130,11 +176,7 @@
         SetLastError( ERROR_NOT_OWNER );
         return FALSE;
     }
-    if (!--mutex->count)
-    {
-        mutex->owner = 0;
-        SYNC_WakeUp( &mutex->wait_queue, INFINITE32 );
-    }
+    if (!--mutex->count) MUTEX_Release( mutex );
     K32OBJ_DecCount( &mutex->header );
     SYSTEM_UNLOCK();
     return TRUE;
@@ -157,13 +199,25 @@
  *
  * Wait on this object has been satisfied.
  */
-static void MUTEX_Satisfied( K32OBJ *obj, DWORD thread_id )
+static BOOL32 MUTEX_Satisfied( K32OBJ *obj, DWORD thread_id )
 {
+    BOOL32 ret;
     MUTEX *mutex = (MUTEX *)obj;
     assert( obj->type == K32OBJ_MUTEX );
     assert( !mutex->count || (mutex->owner == thread_id) );
     mutex->owner = thread_id;
-    mutex->count++;
+    if (!mutex->count++)
+    {
+        /* Add the mutex in the thread list of owned mutexes */
+        K32OBJ **list = &THREAD_ID_TO_THDB( thread_id )->mutex_list;
+        assert( !mutex->next );
+        if ((mutex->next = (MUTEX *)*list)) mutex->next->prev = mutex;
+        *list = &mutex->header;
+        mutex->prev = NULL;
+    }
+    ret = mutex->abandoned;
+    mutex->abandoned = FALSE;
+    return ret;
 }
 
 
diff --git a/scheduler/process.c b/scheduler/process.c
index 225dd14..d42f3f3 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -18,15 +18,16 @@
 #include "winerror.h"
 #include "pe_image.h"
 
-PDB32 *pCurrentProcess = NULL;
-
 #define HTABLE_SIZE  0x30  /* Handle table initial size */
 #define HTABLE_INC   0x10  /* Handle table increment */
 
-#define BOOT_HTABLE_SIZE  10
+/* PDB <-> Process id conversion macros */
+#define PROCESS_OBFUSCATOR     ((DWORD)0xdeadbeef)
+#define PROCESS_ID_TO_PDB(id)  ((PDB32 *)((id) ^ PROCESS_OBFUSCATOR))
+#define PDB_TO_PROCESS_ID(pdb) ((DWORD)(pdb) ^ PROCESS_OBFUSCATOR)
 
 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id );
-static void PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id );
+static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id );
 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id );
 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id );
 static void PROCESS_Destroy( K32OBJ *obj );
@@ -40,7 +41,6 @@
     PROCESS_Destroy      /* destroy */
 };
 
-static HANDLE_ENTRY boot_handles[BOOT_HTABLE_SIZE];
 
 /***********************************************************************
  *           PROCESS_AllocHandleTable
@@ -79,83 +79,31 @@
 
 
 /***********************************************************************
- *           PROCESS_AllocBootHandle
- *
- * Allocate a handle from the boot table.
+ *           PROCESS_Current
  */
-static HANDLE32 PROCESS_AllocBootHandle( K32OBJ *ptr, DWORD flags )
+PDB32 *PROCESS_Current(void)
 {
-    HANDLE32 h;
-    SYSTEM_LOCK();
-    for (h = 0; h < BOOT_HTABLE_SIZE; h++)
-        if (!boot_handles[h].ptr) break;
-    assert( h < BOOT_HTABLE_SIZE );
-    K32OBJ_IncCount( ptr );
-    boot_handles[h].flags = flags;
-    boot_handles[h].ptr   = ptr;
-    SYSTEM_UNLOCK();
-    return h + 1;  /* Avoid handle 0 */
+    return THREAD_Current()->process;
 }
 
 
 /***********************************************************************
- *           PROCESS_CloseBootHandle
+ *           PROCESS_IdToPDB
  *
- * Close a handle from the boot table.
+ * Convert a process id to a PDB, making sure it is valid.
  */
-static BOOL32 PROCESS_CloseBootHandle( HANDLE32 handle )
+PDB32 *PROCESS_IdToPDB( DWORD id )
 {
-    K32OBJ *ptr;
-    HANDLE_ENTRY *entry = &boot_handles[handle - 1];
-    assert( (handle > 0) && (handle <= BOOT_HTABLE_SIZE) );
-    SYSTEM_LOCK();
-    assert( entry->ptr );
-    ptr = entry->ptr;
-    entry->flags = 0;
-    entry->ptr   = NULL;
-    K32OBJ_DecCount( ptr );
-    SYSTEM_UNLOCK();
-    return TRUE;
-}
+    PDB32 *pdb;
 
-
-/***********************************************************************
- *           PROCESS_GetBootObjPtr
- *
- * Get a handle ptr from the boot table.
- */
-static K32OBJ *PROCESS_GetBootObjPtr( HANDLE32 handle, K32OBJ_TYPE type )
-{
-    K32OBJ *ptr;
-
-    assert( (handle > 0) && (handle <= BOOT_HTABLE_SIZE) );
-    SYSTEM_LOCK();
-    ptr = boot_handles[handle - 1].ptr;
-    assert (ptr && (ptr->type == type));
-    K32OBJ_IncCount( ptr );
-    SYSTEM_UNLOCK();
-    return ptr;
-}
-
-
-/***********************************************************************
- *           PROCESS_SetBootObjPtr
- *
- * Set a handle ptr from the boot table.
- */
-static BOOL32 PROCESS_SetBootObjPtr( HANDLE32 handle, K32OBJ *ptr, DWORD flags)
-{
-    K32OBJ *old_ptr;
-
-    assert( (handle > 0) && (handle <= BOOT_HTABLE_SIZE) );
-    SYSTEM_LOCK();
-    K32OBJ_IncCount( ptr );
-    old_ptr = boot_handles[handle - 1].ptr;
-    boot_handles[handle - 1].flags = flags;
-    boot_handles[handle - 1].ptr   = ptr;
-    if (old_ptr) K32OBJ_DecCount( old_ptr );
-    SYSTEM_UNLOCK();
-    return TRUE;
+    if (!id) return PROCESS_Current();
+    pdb = PROCESS_ID_TO_PDB( id );
+    if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return NULL;
+    }
+    return pdb;
 }
 
 
@@ -168,18 +116,17 @@
 {
     HANDLE32 h;
     HANDLE_ENTRY *entry;
+    PDB32 *pdb = PROCESS_Current();
 
     assert( ptr );
-    if (!pCurrentProcess) return PROCESS_AllocBootHandle( ptr, flags );
     SYSTEM_LOCK();
     K32OBJ_IncCount( ptr );
-    entry = pCurrentProcess->handle_table->entries;
-    for (h = 0; h < pCurrentProcess->handle_table->count; h++, entry++)
+    entry = pdb->handle_table->entries;
+    for (h = 0; h < pdb->handle_table->count; h++, entry++)
         if (!entry->ptr) break;
-    if ((h < pCurrentProcess->handle_table->count) ||
-        PROCESS_GrowHandleTable( pCurrentProcess ))
+    if ((h < pdb->handle_table->count) || PROCESS_GrowHandleTable( pdb ))
     {
-        entry = &pCurrentProcess->handle_table->entries[h];
+        entry = &pdb->handle_table->entries[h];
         entry->flags = flags;
         entry->ptr   = ptr;
         SYSTEM_UNLOCK();
@@ -201,12 +148,13 @@
 K32OBJ *PROCESS_GetObjPtr( HANDLE32 handle, K32OBJ_TYPE type )
 {
     K32OBJ *ptr = NULL;
-    if (!pCurrentProcess) return PROCESS_GetBootObjPtr( handle, type );
+    PDB32 *pdb = PROCESS_Current();
+
     SYSTEM_LOCK();
 
-    if ((handle > 0) && (handle <= pCurrentProcess->handle_table->count))
-        ptr = pCurrentProcess->handle_table->entries[handle - 1].ptr;
-    else if (handle == 0x7fffffff) ptr = &pCurrentProcess->header;
+    if ((handle > 0) && (handle <= pdb->handle_table->count))
+        ptr = pdb->handle_table->entries[handle - 1].ptr;
+    else if (handle == 0x7fffffff) ptr = &pdb->header;
 
     if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
         K32OBJ_IncCount( ptr );
@@ -228,12 +176,12 @@
 {
     BOOL32 ret = TRUE;
     K32OBJ *old_ptr = NULL;
+    PDB32 *pdb = PROCESS_Current();
 
-    if (!pCurrentProcess) return PROCESS_SetBootObjPtr( handle, ptr, flags );
     SYSTEM_LOCK();
-    if ((handle > 0) && (handle <= pCurrentProcess->handle_table->count))
+    if ((handle > 0) && (handle <= pdb->handle_table->count))
     {
-        HANDLE_ENTRY*entry = &pCurrentProcess->handle_table->entries[handle-1];
+        HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle-1];
         old_ptr = entry->ptr;
         K32OBJ_IncCount( ptr );
         entry->flags = flags;
@@ -257,12 +205,12 @@
 {
     BOOL32 ret = FALSE;
     K32OBJ *ptr = NULL;
+    PDB32 *pdb = PROCESS_Current();
 
-    if (!pCurrentProcess) return PROCESS_CloseBootHandle( handle );
     SYSTEM_LOCK();
-    if ((handle > 0) && (handle <= pCurrentProcess->handle_table->count))
+    if ((handle > 0) && (handle <= pdb->handle_table->count))
     {
-        HANDLE_ENTRY*entry = &pCurrentProcess->handle_table->entries[handle-1];
+        HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle-1];
         if ((ptr = entry->ptr))
         {
             entry->flags = 0;
@@ -334,17 +282,32 @@
 
 
 /***********************************************************************
- *           PROCESS_Create
+ *           PROCESS_FreePDB
+ *
+ * Free a PDB and all associated storage.
  */
-PDB32 *PROCESS_Create( TDB *pTask, LPCSTR cmd_line )
+static void PROCESS_FreePDB( PDB32 *pdb )
+{
+    pdb->header.type = K32OBJ_UNKNOWN;
+    if (pdb->heap) HeapDestroy( pdb->heap );
+    if (pdb->handle_table) HeapFree( pdb->system_heap, 0, pdb->handle_table );
+    if (pdb->load_done_evt) K32OBJ_DecCount( pdb->load_done_evt );
+    if (pdb->event) K32OBJ_DecCount( pdb->event );
+    DeleteCriticalSection( &pdb->crit_section );
+    HeapFree( SystemHeap, 0, pdb );
+}
+
+
+/***********************************************************************
+ *           PROCESS_CreatePDB
+ *
+ * Allocate and fill a PDB structure.
+ */
+static PDB32 *PROCESS_CreatePDB( PDB32 *parent )
 {
     PDB32 *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB32) );
-    DWORD size, commit;
-    NE_MODULE *pModule;
 
     if (!pdb) return NULL;
-    if (!(pModule = MODULE_GetPtr( pTask->hModule ))) return 0;
-
     pdb->header.type     = K32OBJ_PROCESS;
     pdb->header.refcount = 1;
     pdb->exit_code       = 0x103; /* STILL_ACTIVE */
@@ -352,7 +315,7 @@
     pdb->running_threads = 1;
     pdb->ring0_threads   = 1;
     pdb->system_heap     = SystemHeap;
-    pdb->parent          = pCurrentProcess;
+    pdb->parent          = parent;
     pdb->group           = pdb;
     pdb->priority        = 8;  /* Normal */
 
@@ -363,6 +326,46 @@
     if (!(pdb->event = EVENT_Create( TRUE, FALSE ))) goto error;
     if (!(pdb->load_done_evt = EVENT_Create( TRUE, FALSE ))) goto error;
 
+    /* Allocate the handle table */
+
+    if (!(pdb->handle_table = PROCESS_AllocHandleTable( pdb ))) goto error;
+    return pdb;
+
+error:
+    PROCESS_FreePDB( pdb );
+    return NULL;
+}
+
+
+/***********************************************************************
+ *           PROCESS_Init
+ */
+BOOL32 PROCESS_Init(void)
+{
+    PDB32 *pdb;
+    THDB *thdb;
+
+    if (!(pdb = PROCESS_CreatePDB( NULL ))) return FALSE;
+    if (!(thdb = THREAD_Create( pdb, 0, NULL, NULL ))) return FALSE;
+    SET_CUR_THREAD( thdb );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           PROCESS_Create
+ *
+ * Create a new process database and associated info.
+ */
+PDB32 *PROCESS_Create( TDB *pTask, LPCSTR cmd_line )
+{
+    DWORD size, commit;
+    NE_MODULE *pModule;
+    PDB32 *pdb = PROCESS_CreatePDB( PROCESS_Current() );
+
+    if (!pdb) return NULL;
+    if (!(pModule = MODULE_GetPtr( pTask->hModule ))) return 0;
+
     /* Create the heap */
 
     if (pModule->module32)
@@ -380,18 +383,11 @@
 
     if (!(pdb->env_db = HeapAlloc(pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB))))
         goto error;
-    if (!(pdb->handle_table = PROCESS_AllocHandleTable( pdb ))) goto error;
     if (!PROCESS_FillEnvDB( pdb, pTask, cmd_line )) goto error;
     return pdb;
 
 error:
-    if (pdb->env_db) HeapFree( pdb->heap, 0, pdb->env_db );
-    if (pdb->handle_table) HeapFree( pdb->system_heap, 0, pdb->handle_table );
-    if (pdb->heap) HeapDestroy( pdb->heap );
-    if (pdb->load_done_evt) K32OBJ_DecCount( pdb->load_done_evt );
-    if (pdb->event) K32OBJ_DecCount( pdb->event );
-    DeleteCriticalSection( &pdb->crit_section );
-    HeapFree( SystemHeap, 0, pdb );
+    PROCESS_FreePDB( pdb );
     return NULL;
 }
 
@@ -412,7 +408,7 @@
  *
  * Wait on this object has been satisfied.
  */
-static void PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id )
+static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id )
 {
     PDB32 *pdb = (PDB32 *)obj;
     assert( obj->type == K32OBJ_PROCESS );
@@ -462,13 +458,7 @@
     /* Free everything */
 
     ptr->type = K32OBJ_UNKNOWN;
-    HeapFree( pdb->heap, 0, pdb->env_db );
-    HeapFree( pdb->system_heap, 0, pdb->handle_table );
-    HeapDestroy( pdb->heap );
-    K32OBJ_DecCount( pdb->load_done_evt );
-    K32OBJ_DecCount( pdb->event );
-    DeleteCriticalSection( &pdb->crit_section );
-    HeapFree( SystemHeap, 0, pdb );
+    PROCESS_FreePDB( pdb );
 }
 
 
@@ -477,10 +467,15 @@
  */
 void WINAPI ExitProcess( DWORD status )
 {
-    __RESTORE_ES;  /* Necessary for Pietrek's showseh example program */
+    PDB32 *pdb = PROCESS_Current();
+
+    SYSTEM_LOCK();
     /* FIXME: should kill all running threads of this process */
-    pCurrentProcess->exit_code = status;
-    EVENT_Set( pCurrentProcess->event );
+    pdb->exit_code = status;
+    EVENT_Set( pdb->event );
+    SYSTEM_UNLOCK();
+
+    __RESTORE_ES;  /* Necessary for Pietrek's showseh example program */
     TASK_KillCurrentTask( status );
 }
 
@@ -514,7 +509,8 @@
  */
 DWORD WINAPI GetCurrentProcessId(void)
 {
-    return PDB_TO_PROCESS_ID(pCurrentProcess);
+    PDB32 *pdb = PROCESS_Current();
+    return PDB_TO_PROCESS_ID( pdb );
 }
 
 
@@ -523,8 +519,8 @@
  */
 LPSTR WINAPI GetEnvironmentStrings32A(void)
 {
-    assert( pCurrentProcess );
-    return pCurrentProcess->env_db->environ;
+    PDB32 *pdb = PROCESS_Current();
+    return pdb->env_db->environ;
 }
 
 
@@ -536,12 +532,12 @@
     INT32 size;
     LPWSTR ret, pW;
     LPSTR pA;
+    PDB32 *pdb = PROCESS_Current();
 
-    assert( pCurrentProcess );
-    size = HeapSize( GetProcessHeap(), 0, pCurrentProcess->env_db->environ );
+    size = HeapSize( GetProcessHeap(), 0, pdb->env_db->environ );
     if (!(ret = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) )))
         return NULL;
-    pA = pCurrentProcess->env_db->environ;
+    pA = pdb->env_db->environ;
     pW = ret;
     while (*pA)
     {
@@ -560,8 +556,8 @@
  */
 BOOL32 WINAPI FreeEnvironmentStrings32A( LPSTR ptr )
 {
-    assert( pCurrentProcess );
-    if (ptr != pCurrentProcess->env_db->environ)
+    PDB32 *pdb = PROCESS_Current();
+    if (ptr != pdb->env_db->environ)
     {
         SetLastError( ERROR_INVALID_PARAMETER );
         return FALSE;
@@ -575,7 +571,6 @@
  */
 BOOL32 WINAPI FreeEnvironmentStrings32W( LPWSTR ptr )
 {
-    assert( pCurrentProcess );
     return HeapFree( GetProcessHeap(), 0, ptr );
 }
 
@@ -588,8 +583,7 @@
     LPSTR p;
     INT32 len, res;
 
-    assert( pCurrentProcess );
-    p = pCurrentProcess->env_db->environ;
+    p = PROCESS_Current()->env_db->environ;
     if (!name || !*name)
     {
         SetLastError( ERROR_INVALID_PARAMETER );
@@ -639,9 +633,9 @@
 {
     INT32 size, len, res;
     LPSTR p, env, new_env;
+    PDB32 *pdb = PROCESS_Current();
 
-    assert( pCurrentProcess );
-    env = p = pCurrentProcess->env_db->environ;
+    env = p = pdb->env_db->environ;
 
     /* Find a place to insert the string */
 
@@ -662,18 +656,16 @@
 
     len = value ? strlen(name) + strlen(value) + 2 : 0;
     if (!res) len -= strlen(p) + 1;  /* The name already exists */
-    size = pCurrentProcess->env_db->env_size + len;
+    size = pdb->env_db->env_size + len;
     if (len < 0)
     {
         LPSTR next = p + strlen(p) + 1;
-        memmove( next + len, next,
-                 pCurrentProcess->env_db->env_size - (next - env) );
+        memmove( next + len, next, pdb->env_db->env_size - (next - env) );
     }
     if (!(new_env = HeapReAlloc( GetProcessHeap(), 0, env, size )))
         return FALSE;
     p = new_env + (p - env);
-    if (len > 0)
-        memmove( p + len, p, pCurrentProcess->env_db->env_size - (p-new_env) );
+    if (len > 0) memmove( p + len, p, pdb->env_db->env_size - (p-new_env) );
 
     /* Set the new string */
 
@@ -683,8 +675,8 @@
         strcat( p, "=" );
         strcat( p, value );
     }
-    pCurrentProcess->env_db->env_size = size;
-    pCurrentProcess->env_db->environ  = new_env;
+    pdb->env_db->env_size = size;
+    pdb->env_db->environ  = new_env;
     return TRUE;
 }
 
@@ -799,8 +791,8 @@
  */
 HANDLE32 WINAPI GetProcessHeap(void)
 {
-    if (!pCurrentProcess) return SystemHeap;  /* For the boot-up code */
-    return pCurrentProcess->heap;
+    PDB32 *pdb = PROCESS_Current();
+    return pdb->heap ? pdb->heap : SystemHeap;
 }
 
 
@@ -809,7 +801,7 @@
  */
 LCID WINAPI GetThreadLocale(void)
 {
-    return pCurrentProcess->locale;
+    return PROCESS_Current()->locale;
 }
 
 
@@ -890,23 +882,20 @@
 {
     HFILE32 hFile;
     int fd;
+    PDB32 *pdb = PROCESS_Current();
 
-    assert( pCurrentProcess );
     switch(std_handle)
     {
     case STD_INPUT_HANDLE:
-        if (pCurrentProcess->env_db->hStdin)
-            return pCurrentProcess->env_db->hStdin;
+        if (pdb->env_db->hStdin) return pdb->env_db->hStdin;
         fd = 0;
         break;
     case STD_OUTPUT_HANDLE:
-        if (pCurrentProcess->env_db->hStdout)
-            return pCurrentProcess->env_db->hStdout;
+        if (pdb->env_db->hStdout) return pdb->env_db->hStdout;
         fd = 1;
         break;
     case STD_ERROR_HANDLE:
-        if (pCurrentProcess->env_db->hStderr)
-            return pCurrentProcess->env_db->hStderr;
+        if (pdb->env_db->hStderr) return pdb->env_db->hStderr;
         fd = 2;
         break;
     default:
@@ -919,9 +908,9 @@
         FILE_SetFileType( hFile, FILE_TYPE_CHAR );
         switch(std_handle)
         {
-        case STD_INPUT_HANDLE: pCurrentProcess->env_db->hStdin=hFile; break;
-        case STD_OUTPUT_HANDLE: pCurrentProcess->env_db->hStdout=hFile; break;
-        case STD_ERROR_HANDLE: pCurrentProcess->env_db->hStderr=hFile; break;
+        case STD_INPUT_HANDLE:  pdb->env_db->hStdin  = hFile; break;
+        case STD_OUTPUT_HANDLE: pdb->env_db->hStdout = hFile; break;
+        case STD_ERROR_HANDLE:  pdb->env_db->hStderr = hFile; break;
         }
     }
     return hFile;
@@ -933,17 +922,17 @@
  */
 BOOL32 WINAPI SetStdHandle( DWORD std_handle, HANDLE32 handle )
 {
-    assert( pCurrentProcess );
+    PDB32 *pdb = PROCESS_Current();
     switch(std_handle)
     {
     case STD_INPUT_HANDLE:
-        pCurrentProcess->env_db->hStdin = handle;
+        pdb->env_db->hStdin = handle;
         return TRUE;
     case STD_OUTPUT_HANDLE:
-        pCurrentProcess->env_db->hStdout = handle;
+        pdb->env_db->hStdout = handle;
         return TRUE;
     case STD_ERROR_HANDLE:
-        pCurrentProcess->env_db->hStderr = handle;
+        pdb->env_db->hStderr = handle;
         return TRUE;
     }
     SetLastError( ERROR_INVALID_PARAMETER );
@@ -955,43 +944,22 @@
  */
 DWORD WINAPI GetProcessVersion( DWORD processid )
 {
-    PDB32 *process;
     TDB *pTask;
+    PDB32 *pdb = PROCESS_IdToPDB( processid );
 
-    if (!processid) process = pCurrentProcess;
-    else
-    {
-        process = PROCESS_ID_TO_PDB(processid);
-        if (!K32OBJ_IsValid( &process->header, K32OBJ_PROCESS ))
-        {
-            SetLastError( ERROR_INVALID_PARAMETER );
-            return 0;
-        }
-    }
-    pTask = (TDB*)GlobalLock16(process->task);
-    if (!pTask)
-        return 0;
+    if (!pdb) return 0;
+    if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
     return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
 }
 
 /***********************************************************************
  *           GetProcessFlags    (KERNEL32)
  */
-DWORD WINAPI GetProcessFlags(DWORD processid)
+DWORD WINAPI GetProcessFlags( DWORD processid )
 {
-    PDB32 *process;
-
-    if (!processid) process = pCurrentProcess;
-    else
-    {
-        process = PROCESS_ID_TO_PDB(processid);
-        if (!K32OBJ_IsValid( &process->header, K32OBJ_PROCESS ))
-        {
-            SetLastError( ERROR_INVALID_PARAMETER );
-            return 0;
-        }
-    }
-    return process->flags;
+    PDB32 *pdb = PROCESS_IdToPDB( processid );
+    if (!pdb) return 0;
+    return pdb->flags;
 }
 
 /***********************************************************************
diff --git a/scheduler/semaphore.c b/scheduler/semaphore.c
index d8c1535..d6cfd49 100644
--- a/scheduler/semaphore.c
+++ b/scheduler/semaphore.c
@@ -21,7 +21,7 @@
 } SEMAPHORE;
 
 static BOOL32 SEMAPHORE_Signaled( K32OBJ *obj, DWORD thread_id );
-static void SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id );
+static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id );
 static void SEMAPHORE_AddWait( K32OBJ *obj, DWORD thread_id );
 static void SEMAPHORE_RemoveWait( K32OBJ *obj, DWORD thread_id );
 static void SEMAPHORE_Destroy( K32OBJ *obj );
@@ -165,12 +165,13 @@
  *
  * Wait on this object has been satisfied.
  */
-static void SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id )
+static BOOL32 SEMAPHORE_Satisfied( K32OBJ *obj, DWORD thread_id )
 {
     SEMAPHORE *sem = (SEMAPHORE *)obj;
     assert( obj->type == K32OBJ_SEMAPHORE );
     assert( sem->count > 0 );
     sem->count--;
+    return FALSE;  /* Not abandoned */
 }
 
 
diff --git a/scheduler/synchro.c b/scheduler/synchro.c
index 2000217..8577992 100644
--- a/scheduler/synchro.c
+++ b/scheduler/synchro.c
@@ -88,7 +88,8 @@
         /* Wait satisfied: tell it to all objects */
         wait->signaled = WAIT_OBJECT_0;
         for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
-            K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id );
+            if (K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id ))
+                wait->signaled = WAIT_ABANDONED_0;
         SYSTEM_UNLOCK();
         return TRUE;
     }
@@ -100,7 +101,8 @@
             {
                 /* Wait satisfied: tell it to the object */
                 wait->signaled = WAIT_OBJECT_0 + i;
-                K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id );
+                if (K32OBJ_OPS( *ptr )->satisfied( *ptr, thread_id ))
+                    wait->signaled = WAIT_ABANDONED_0 + i;
                 SYSTEM_UNLOCK();
                 return TRUE;
             }
diff --git a/scheduler/sysdeps.c b/scheduler/sysdeps.c
new file mode 100644
index 0000000..08c4dc3
--- /dev/null
+++ b/scheduler/sysdeps.c
@@ -0,0 +1,121 @@
+/*
+ * System-dependent scheduler support
+ *
+ * Copyright 1998 Alexandre Julliard
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "thread.h"
+
+#ifdef __linux__
+# ifdef HAVE_SCHED_H
+#  include <sched.h>
+# endif
+# ifndef CLONE_VM
+#  define CLONE_VM      0x00000100
+#  define CLONE_FS      0x00000200
+#  define CLONE_FILES   0x00000400
+#  define CLONE_SIGHAND 0x00000800
+#  define CLONE_PID     0x00001000
+/* If we didn't get the flags, we probably didn't get the prototype either */
+extern int clone( int (*fn)(void *arg), void *stack, int flags, void *arg );
+# endif  /* CLONE_VM */
+#endif  /* __linux__ */
+
+
+#ifdef __linux__
+/***********************************************************************
+ *           __errno_location
+ *
+ * Get the per-thread errno location.
+ */
+int *__errno_location()
+{
+    static int static_errno;
+    THDB *thdb = THREAD_Current();
+    if (!thdb) return &static_errno;
+    return &thdb->thread_errno;
+}
+
+/***********************************************************************
+ *           __h_errno_location
+ *
+ * Get the per-thread h_errno location.
+ */
+int *__h_errno_location()
+{
+    static int static_h_errno;
+    THDB *thdb = THREAD_Current();
+    if (!thdb) return &static_h_errno;
+    return &thdb->thread_h_errno;
+}
+
+/***********************************************************************
+ *           SYSDEPS_StartThread
+ *
+ * Startup routine for a new thread.
+ */
+static void SYSDEPS_StartThread( THDB *thdb )
+{
+    LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
+    thdb->unix_pid = getpid();
+    SET_FS( thdb->teb_sel );
+    ExitThread( func( thdb->entry_arg ) );
+}
+#endif  /* __linux__ */
+
+
+/***********************************************************************
+ *           SYSDEPS_SpawnThread
+ *
+ * Start running a new thread.
+ * Return -1 on error, 0 if OK.
+ */
+int SYSDEPS_SpawnThread( THDB *thread )
+{
+#ifdef __linux__
+    if (clone( (int (*)(void *))SYSDEPS_StartThread, thread->teb.stack_top,
+               CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, thread ) < 0)
+        return -1;
+#else
+    fprintf( stderr, "CreateThread: stub\n" );
+#endif  /* __linux__ */
+    return 0;
+}
+
+
+/***********************************************************************
+ *           SYSDEPS_ExitThread
+ *
+ * Exit a running thread; must not return.
+ */
+void SYSDEPS_ExitThread(void)
+{
+    _exit( 0 );
+}
+
+
+/**********************************************************************
+ *           NtCurrentTeb   (NTDLL.89)
+ */
+TEB * WINAPI NtCurrentTeb(void)
+{
+#ifdef __i386__
+    TEB *teb;
+    WORD ds, fs;
+
+    /* Check if we have a current thread */
+    GET_DS( ds );
+    GET_FS( fs );
+    if (fs == ds) return NULL; /* FIXME: should be an assert */
+    /* Get the TEB self-pointer */
+    __asm__( ".byte 0x64\n\tmovl (%1),%0"
+             : "=r" (teb) : "r" (&((TEB *)0)->self) );
+    return teb;
+#else
+    if (!pCurrentThread) return NULL;
+    return &pCurrentThread->teb;
+#endif  /* __i386__ */
+}
diff --git a/scheduler/thread.c b/scheduler/thread.c
index 73959d0..984b89c 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -18,27 +18,12 @@
 #include "debug.h"
 #include "stddebug.h"
 
-#ifdef HAVE_CLONE
-# ifdef HAVE_SCHED_H
-#  include <sched.h>
-# endif
-# ifndef CLONE_VM
-#  define CLONE_VM      0x00000100
-#  define CLONE_FS      0x00000200
-#  define CLONE_FILES   0x00000400
-#  define CLONE_SIGHAND 0x00000800
-#  define CLONE_PID     0x00001000
-/* If we didn't get the flags, we probably didn't get the prototype either */
-extern int clone( int (*fn)(void *arg), void *stack, int flags, void *arg );
-# endif  /* CLONE_VM */
-#endif  /* HAVE_CLONE */
-
 #ifndef __i386__
 THDB *pCurrentThread;
 #endif
 
 static BOOL32 THREAD_Signaled( K32OBJ *obj, DWORD thread_id );
-static void THREAD_Satisfied( K32OBJ *obj, DWORD thread_id );
+static BOOL32 THREAD_Satisfied( K32OBJ *obj, DWORD thread_id );
 static void THREAD_AddWait( K32OBJ *obj, DWORD thread_id );
 static void THREAD_RemoveWait( K32OBJ *obj, DWORD thread_id );
 static void THREAD_Destroy( K32OBJ *obj );
@@ -73,28 +58,6 @@
 }
 
 
-/**********************************************************************
- *           NtCurrentTeb   (NTDLL.89)
- */
-TEB * WINAPI NtCurrentTeb(void)
-{
-#ifdef __i386__
-    TEB *teb;
-    WORD ds, fs;
-
-    /* Check if we have a current thread */
-    GET_DS( ds );
-    GET_FS( fs );
-    if (fs == ds) return NULL; /* FIXME: should be an assert */
-    __asm__( "movl %%fs:(24),%0" : "=r" (teb) );
-    return teb;
-#else
-    if (!pCurrentThread) return NULL;
-    return &pCurrentThread->teb;
-#endif  /* __i386__ */
-}
-
-
 /***********************************************************************
  *           THREAD_Current
  *
@@ -181,7 +144,6 @@
     thdb->teb.self        = &thdb->teb;
     thdb->teb.tls_ptr     = thdb->tls_array;
     thdb->wait_list       = &thdb->wait_struct;
-    thdb->process2        = pdb;
     thdb->exit_code       = 0x103; /* STILL_ACTIVE */
     thdb->entry_point     = start_addr;
     thdb->entry_arg       = param;
@@ -234,20 +196,6 @@
 
 
 /***********************************************************************
- *           THREAD_Start
- *
- * Startup routine for a new thread.
- */
-static void THREAD_Start( THDB *thdb )
-{
-    LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
-    thdb->unix_pid = getpid();
-    SET_FS( thdb->teb_sel );
-    ExitThread( func( thdb->entry_arg ) );
-}
-
-
-/***********************************************************************
  *           THREAD_Signaled
  */
 static BOOL32 THREAD_Signaled( K32OBJ *obj, DWORD thread_id )
@@ -263,7 +211,7 @@
  *
  * Wait on this object has been satisfied.
  */
-static void THREAD_Satisfied( K32OBJ *obj, DWORD thread_id )
+static BOOL32 THREAD_Satisfied( K32OBJ *obj, DWORD thread_id )
 {
     THDB *thdb = (THDB *)obj;
     assert( obj->type == K32OBJ_THREAD );
@@ -336,26 +284,17 @@
                               DWORD flags, LPDWORD id )
 {
     HANDLE32 handle;
-    THDB *thread = THREAD_Create( pCurrentProcess, stack, start, param );
+    THDB *thread = THREAD_Create( PROCESS_Current(), stack, start, param );
     if (!thread) return INVALID_HANDLE_VALUE32;
     handle = PROCESS_AllocHandle( &thread->header, 0 );
-    if (handle == INVALID_HANDLE_VALUE32)
-    {
-        K32OBJ_DecCount( &thread->header );
-        return INVALID_HANDLE_VALUE32;
-    }
-#ifdef HAVE_CLONE
-    if (clone( (int (*)(void *))THREAD_Start, thread->teb.stack_top,
-               CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, thread ) < 0)
-    {
-        K32OBJ_DecCount( &thread->header );
-        return INVALID_HANDLE_VALUE32;
-    }
-#else
-    fprintf( stderr, "CreateThread: stub\n" );
-#endif  /* __linux__ */
+    if (handle == INVALID_HANDLE_VALUE32) goto error;
+    if (SYSDEPS_SpawnThread( thread ) == -1) goto error;
     *id = THDB_TO_THREAD_ID( thread );
     return handle;
+
+error:
+    K32OBJ_DecCount( &thread->header );
+    return INVALID_HANDLE_VALUE32;
 }
 
 
@@ -370,12 +309,16 @@
     SYSTEM_LOCK();
     thdb->exit_code = code;
     EVENT_Set( thdb->event );
+
+    /* Abandon all owned mutexes */
+    while (thdb->mutex_list) MUTEX_Abandon( thdb->mutex_list );
+
     /* FIXME: should free the stack somehow */
     K32OBJ_DecCount( &thdb->header );
     /* Completely unlock the system lock just in case */
     count = SYSTEM_LOCK_COUNT();
     while (count--) SYSTEM_UNLOCK();
-    _exit( 0 );
+    SYSDEPS_ExitThread();
 }
 
 
diff --git a/tools/build.c b/tools/build.c
index ad4db74..1cc07e7 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -25,6 +25,12 @@
 # define PREFIX
 #endif
 
+#ifdef HAVE_ASM_STRING
+# define STRING ".string"
+#else
+# define STRING ".ascii"
+#endif
+
 #if defined(__GNUC__) && !defined(__svr4__)
 # define USE_STABS
 #else
@@ -1240,7 +1246,7 @@
     /* Output the DLL descriptor */
 
     fprintf( outfile, "\t.text\n" );
-    fprintf( outfile, "DLLName:\t.string \"%s\\0\"\n", DLLName );
+    fprintf( outfile, "DLLName:\t" STRING " \"%s\\0\"\n", DLLName );
     fprintf( outfile, "\t.align 4\n" );
     fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
     fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
@@ -1299,14 +1305,6 @@
 {
     int i, pos16, pos32;
 
-    /* Save ebx first */
-
-    fprintf( outfile, "\tpushl %%ebx\n" );
-
-    /* Get the 32-bit stack pointer */
-
-    fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebx\n" );
-
     /* Copy the arguments */
 
     pos16 = 6;  /* skip bp and return address */
@@ -1355,10 +1353,6 @@
         }
     }
 
-    /* Restore ebx */
-    
-    fprintf( outfile, "\tpopl %%ebx\n" );
-
     return pos16 - 6;  /* Return the size of the 16-bit args */
 }
 
@@ -1370,18 +1364,8 @@
  */
 static void BuildContext16( FILE *outfile )
 {
-    /* Save ebx first */
-
-    fprintf( outfile, "\tpushl %%ebx\n" );
-
-    /* Get the 32-bit stack pointer */
-
-    fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebx\n" );
-
     /* Store the registers */
 
-    fprintf( outfile, "\tpopl %d(%%ebx)\n", /* Get ebx from stack*/
-             CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
              CONTEXTOFFSET(Eax) - sizeof(CONTEXT) );
     fprintf( outfile, "\tmovl %%ecx,%d(%%ebx)\n",
@@ -1393,6 +1377,9 @@
     fprintf( outfile, "\tmovl %%edi,%d(%%ebx)\n",
              CONTEXTOFFSET(Edi) - sizeof(CONTEXT) );
 
+    fprintf( outfile, "\tmovl -20(%%ebp),%%eax\n" ); /* Get %ebx from stack*/
+    fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
+             CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
     fprintf( outfile, "\tmovzwl -10(%%ebp),%%eax\n" ); /* Get %ds from stack*/
     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
              CONTEXTOFFSET(SegDs) - sizeof(CONTEXT) );
@@ -1437,7 +1424,8 @@
 {
     /* Get the 32-bit stack pointer */
 
-    fprintf( outfile, "\tmovl %%edx,%%ebx\n" );
+    fprintf( outfile, "\tleal -%d(%%ebp),%%ebx\n",
+             STRUCTOFFSET(STACK32FRAME,ebp) );
 
     /* Remove everything up to the return address from the 16-bit stack */
 
@@ -1500,8 +1488,7 @@
  *
  * Added on the stack:
  * (sp-4)  long   ebp
- * (sp-6)  word   saved previous sp
- * (sp-8)  word   saved previous ss
+ * (sp-8)  long   saved previous stack
  */
 static void BuildCallFrom16Func( FILE *outfile, char *profile )
 {
@@ -1544,16 +1531,28 @@
     /* fprintf( outfile, "\tmovw %%es,-6(%%ebp)\n" ); */
     fprintf( outfile, "\t.byte 0x66,0x8c,0x45,0xfa\n" );
 
+    /* Save %ebx */
+
+    fprintf( outfile, "\tpushl %%ebx\n" );
+
     /* Restore 32-bit ds and es */
 
-    fprintf( outfile, "\tpushl $0x%04x%04x\n", Data_Selector, Data_Selector );
-    fprintf( outfile, "\t.byte 0x66\n\tpopl %%ds\n" );
-    fprintf( outfile, "\t.byte 0x66\n\tpopl %%es\n" );
+    fprintf( outfile, "\tmovw $0x%04x,%%bx\n", Data_Selector );
+#ifdef __svr4__
+    fprintf( outfile, "\tdata16\n");
+#endif
+    fprintf( outfile, "\tmovw %%bx,%%ds\n" );
+#ifdef __svr4__
+    fprintf( outfile, "\tdata16\n");
+#endif
+    fprintf( outfile, "\tmovw %%bx,%%es\n" );
 
+    /* Get the 32-bit stack pointer */
+
+    fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebx\n" );
 
     /* Save the 16-bit stack */
 
-    fprintf( outfile, "\tpushl " PREFIX "IF1632_Saved16_ss_sp\n" );
 #ifdef __svr4__
     fprintf( outfile,"\tdata16\n");
 #endif
@@ -1574,9 +1573,14 @@
     if (!reg_func && short_ret)
         fprintf( outfile, "\tmovl %%edx,-4(%%ebp)\n" );
 
+    /* Restore %ebx and store the 32-bit stack pointer instead */
+
+    fprintf( outfile, "\tmovl %%ebx,%%ebp\n" );
+    fprintf( outfile, "\tpopl %%ebx\n" );
+    fprintf( outfile, "\tpushl %%ebp\n" );
+
     /* Switch to the 32-bit stack */
 
-    fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebp\n" );
     fprintf( outfile, "\tpushl %%ds\n" );
     fprintf( outfile, "\tpopl %%ss\n" );
     fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
@@ -1624,12 +1628,6 @@
         fprintf( outfile, "\tpopl %%eax\n" );
     }
 
-    /* Restore the value of the saved 32-bit stack pointer */
-
-    fprintf( outfile, "\tleal -%d(%%ebp),%%edx\n",
-             STRUCTOFFSET(STACK32FRAME,ebp) );
-    fprintf( outfile, "movl %%edx," PREFIX "CALLTO16_Saved32_esp\n" );
-
     /* Restore the 16-bit stack */
 
 #ifdef __svr4__
@@ -1637,7 +1635,7 @@
 #endif
     fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
     fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp,%%sp\n" );
-    fprintf( outfile, "\tpopl " PREFIX "IF1632_Saved16_ss_sp\n" );
+    fprintf( outfile, "\tpopl " PREFIX "CALLTO16_Saved32_esp\n" );
 
     if (reg_func)
     {
@@ -1722,8 +1720,8 @@
  * Prototypes for the CallTo16 functions:
  *   extern WINAPI WORD CallTo16_word_xxx( FARPROC16 func, args... );
  *   extern WINAPI LONG CallTo16_long_xxx( FARPROC16 func, args... );
- *   extern WINAPI void CallTo16_sreg_( const CONTEXT *context );
- *   extern WINAPI void CallTo16_lreg_( const CONTEXT *context );
+ *   extern WINAPI void CallTo16_sreg_( const CONTEXT *context, int nb_args );
+ *   extern WINAPI void CallTo16_lreg_( const CONTEXT *context, int nb_args );
  */
 static void BuildCallTo16Func( FILE *outfile, char *profile )
 {
@@ -1782,11 +1780,6 @@
     fprintf( outfile, "\tpushl %%esi\n" );
     fprintf( outfile, "\tpushl %%edi\n" );
 
-    /* Save the 32-bit stack */
-
-    fprintf( outfile, "\tmovl %%esp," PREFIX "CALLTO16_Saved32_esp\n" );
-    fprintf( outfile, "\tmovl %%ebp,%%ebx\n" );
-
     /* Print debugging info */
 
     if (debugging)
@@ -1800,21 +1793,23 @@
         fprintf( outfile, "\tpopl %%eax\n" );
     }
 
+    /* Save the 32-bit stack */
+
+    fprintf( outfile, "\tpushl " PREFIX "IF1632_Saved16_ss_sp\n" );
+    fprintf( outfile, "\tmovl %%esp," PREFIX "CALLTO16_Saved32_esp\n" );
+    fprintf( outfile, "\tmovl %%ebp,%%ebx\n" );
+
     if (reg_func)
     {
         /* Switch to the 16-bit stack, saving the current %%esp, */
         /* and adding the specified offset to the new sp */
-        fprintf( outfile, "\tmovzwl " PREFIX "IF1632_Saved16_ss_sp,%%edx\n" );
-        fprintf( outfile, "\tleal -4(%%edx),%%edx\n" );
-        fprintf( outfile, "\tmovl 12(%%ebx),%%eax\n" ); /* Get the offset */
-        fprintf( outfile, "\taddl %%edx,%%eax\n" );
+        fprintf( outfile, "\tmovzwl " PREFIX "IF1632_Saved16_ss_sp,%%eax\n" );
+        fprintf( outfile, "\tsubl 12(%%ebx),%%eax\n" ); /* Get the offset */
 #ifdef __svr4__
         fprintf( outfile,"\tdata16\n");
 #endif
         fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
-        fprintf( outfile, "\txchgl %%esp,%%eax\n" );
-        fprintf( outfile, "\t.byte 0x36\n" /* %ss: */ );
-        fprintf( outfile, "\tmovl %%eax,0(%%edx)\n" );
+        fprintf( outfile, "\tmovl %%eax,%%esp\n" );
 
         /* Get the registers. ebx is handled later on. */
 
@@ -1858,19 +1853,17 @@
     {
         int pos = 12;  /* first argument position */
 
-        /* Switch to the 16-bit stack, saving the current %%esp */
-        fprintf( outfile, "\tmovl %%esp,%%eax\n" );
+        /* Switch to the 16-bit stack */
 #ifdef __svr4__
         fprintf( outfile,"\tdata16\n");
 #endif
         fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
         fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp,%%sp\n" );
-        fprintf( outfile, "\tpushl %%eax\n" );
 
         /* Make %bp point to the previous stackframe (built by CallFrom16) */
         fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
         fprintf( outfile, "\tleal %d(%%ebp),%%ebp\n",
-                 STRUCTOFFSET(STACK16FRAME,bp) + 4 /* for saved %%esp */ );
+                 STRUCTOFFSET(STACK16FRAME,bp) );
 
         /* Transfer the arguments */
 
@@ -1931,8 +1924,6 @@
     /* Remove the arguments just in case */
 
     fprintf( outfile, PREFIX "CALLTO16_Ret_long:\n" );
-    fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
-                 STRUCTOFFSET(STACK16FRAME,bp) + 4 /* for saved %%esp */ );
 
     /* Put return value into %eax */
 
@@ -1943,7 +1934,6 @@
 
     /* Restore 32-bit segment registers */
 
-    fprintf( outfile, "\tpopl %%ecx\n" );  /* Get the saved %%esp */
     fprintf( outfile, "\tmovw $0x%04x,%%bx\n", Data_Selector );
 #ifdef __svr4__
     fprintf( outfile, "\tdata16\n");
@@ -1960,7 +1950,8 @@
     fprintf( outfile, "\tdata16\n");
 #endif
     fprintf( outfile, "\tmovw %%bx,%%ss\n" );
-    fprintf( outfile, "\tmovl %%ecx,%%esp\n" );
+    fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%esp\n" );
+    fprintf( outfile, "\tpopl " PREFIX "IF1632_Saved16_ss_sp\n" );
 
     /* Restore the 32-bit registers */
 
@@ -2216,8 +2207,8 @@
         fprintf( outfile, "/* Argument strings */\n" );
         for (i = 2; i < argc; i++)
         {
-            fprintf( outfile, "Profile_%s:\n", argv[i] );
-            fprintf( outfile, "\t.string \"%s\\0\"\n", argv[i] + 5 );
+            fprintf( outfile, "Profile_%s:\t", argv[i] );
+            fprintf( outfile, STRING " \"%s\\0\"\n", argv[i] + 5 );
         }
     }
 
diff --git a/tools/ipcl b/tools/ipcl
index 7a066d5..8cb6901 100644
--- a/tools/ipcl
+++ b/tools/ipcl
@@ -7,7 +7,7 @@
 $IPC_RMID=0;
 $USER=$ENV{USER};
 
-do open_pipe(IPCS,"ipcs");
+open(IPCS,"ipcs|");
 
 #
 # The following part is OS dependant, it works under linux only.
@@ -60,33 +60,3 @@
 foreach (@msq) {
     msgctl($_, $IPC_RMID,0);
 }
-
-exit(0);
-
-
-
-
-
-sub open_pipe {
-    local($pid);
-    local($handle,@params)=@_;
-    pipe($handle,WRITE) || die "can't pipe";
-
-    $pid=fork();
-
-    die "can't fork" if ($pid<0);
-    if ($pid>0) {
-	# whe are in the parent
-	close(WRITE);
-	waitpid($pid,0) || print "$params[0] exits status=$? ",$? >> 8, "\n";
-    } else {
-	# we are in the son.
-	open(STDOUT,">&WRITE");
-	open(STDERR, ">&WRITE");
-	close($handle);
-	close(WRITE);
-	exec(@params);
-	exit(-1);
-    }
-    
-}
diff --git a/win32/environment.c b/win32/environment.c
index 65ad44d..0680d1e 100644
--- a/win32/environment.c
+++ b/win32/environment.c
@@ -13,7 +13,7 @@
 #include "task.h"
 #include "stddebug.h"
 #include "debug.h"
-#include "process.h"  /* for pCurrentProcess */
+#include "process.h"  /* for PROCESS_Current() */
 
 
 /***********************************************************************
@@ -21,7 +21,7 @@
  */
 LPCSTR WINAPI GetCommandLine32A(void)
 {
-    return pCurrentProcess->env_db->cmd_line;
+    return PROCESS_Current()->env_db->cmd_line;
 }
 
 /***********************************************************************
diff --git a/win32/except.c b/win32/except.c
index 149d32f..0feae88 100644
--- a/win32/except.c
+++ b/win32/except.c
@@ -188,12 +188,13 @@
 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
 {
     char message[80];
+    PDB32 *pdb = PROCESS_Current();
 
     /* FIXME: Should check if the process is being debugged */
 
-    if (pCurrentProcess && pCurrentProcess->top_filter)
+    if (pdb->top_filter)
     {
-        DWORD ret = pCurrentProcess->top_filter( epointers );
+        DWORD ret = pdb->top_filter( epointers );
         if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
     }
 
@@ -213,7 +214,8 @@
 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
                                           LPTOP_LEVEL_EXCEPTION_FILTER filter )
 {
-    LPTOP_LEVEL_EXCEPTION_FILTER old = pCurrentProcess->top_filter;
-    pCurrentProcess->top_filter = filter;
+    PDB32 *pdb = PROCESS_Current();
+    LPTOP_LEVEL_EXCEPTION_FILTER old = pdb->top_filter;
+    pdb->top_filter = filter;
     return old;
 }
diff --git a/win32/kernel32.c b/win32/kernel32.c
index 0a651c7..ea78c82 100644
--- a/win32/kernel32.c
+++ b/win32/kernel32.c
@@ -161,23 +161,22 @@
  */
 VOID WINAPI QT_Thunk(CONTEXT *context)
 {
-	CONTEXT	context16;
-	DWORD	argsize;
+    CONTEXT context16;
+    DWORD argsize;
 
-	memcpy(&context16,context,sizeof(context16));
+    memcpy(&context16,context,sizeof(context16));
 
-	CS_reg(&context16)	 = HIWORD(EDX_reg(context));
-	IP_reg(&context16)	 = LOWORD(EDX_reg(context));
+    CS_reg(&context16)  = HIWORD(EDX_reg(context));
+    IP_reg(&context16)  = LOWORD(EDX_reg(context));
+    EBP_reg(&context16) = OFFSETOF(IF1632_Saved16_ss_sp)
+                           + (WORD)&((STACK16FRAME*)0)->bp;
 
-	argsize = EBP_reg(context)-ESP_reg(context)-0x44;
+    argsize = EBP_reg(context)-ESP_reg(context)-0x44;
 
-	/* additional 4 bytes used by the relaycode for storing the stackptr */
-	memcpy(	((LPBYTE)CURRENT_STACK16)-argsize-4,
-		(LPBYTE)ESP_reg(context)+4,
-		argsize
-	);
-	EAX_reg(context) = Callbacks->CallRegisterShortProc(&context16,
-                                                            -argsize);
+    memcpy( ((LPBYTE)CURRENT_STACK16)-argsize,
+            (LPBYTE)ESP_reg(context)+4, argsize );
+
+    EAX_reg(context) = Callbacks->CallRegisterShortProc( &context16, argsize );
 }
 
 
@@ -569,7 +568,7 @@
 	*x++=0x66;*x++=0x52;				/* pushl edx */
 	*x++=0xea;*(DWORD*)x=callback;x+=4;		/* jmpf callback */
 
-	*(PDB32**)(thunk+18) = pCurrentProcess;
+	*(PDB32**)(thunk+18) = PROCESS_Current();
 
 	sel = SELECTOR_AllocBlock( thunk , 32, SEGMENT_CODE, FALSE, FALSE );
 	return (sel<<16)|0;
diff --git a/win32/newfns.c b/win32/newfns.c
index 1ef72e5..bc40e49 100644
--- a/win32/newfns.c
+++ b/win32/newfns.c
@@ -8,7 +8,10 @@
 at a later date. */
 
 #include <stdio.h>
+#include <sys/time.h>
+#include <unistd.h>
 #include "windows.h"
+#include "winnt.h"
 #include "winerror.h"
 #include "stddebug.h"
 #include "debug.h"
@@ -37,16 +40,18 @@
     return TRUE;
 }
 
+
 /****************************************************************************
  *		QueryPerformanceCounter (KERNEL32.564)
  */
 BOOL32 WINAPI QueryPerformanceCounter(LPLARGE_INTEGER counter)
 {
-	/* FIXME: don't know what are good values */
-	counter->LowPart	= 0;
-	counter->HighPart	= 0;
-	/* FIXME: Set appropriate error */
-	return FALSE;
+    struct timeval tv;
+
+    gettimeofday(&tv,NULL);
+    counter->LowPart = tv.tv_usec+tv.tv_sec*1000000;
+    counter->HighPart = 0;
+    return TRUE;
 }
 
 HANDLE32 WINAPI FindFirstChangeNotification32A(LPCSTR lpPathName,BOOL32 bWatchSubtree,DWORD dwNotifyFilter) {
@@ -66,11 +71,9 @@
  */
 BOOL32 WINAPI QueryPerformanceFrequency(LPLARGE_INTEGER frequency)
 {
-	/* FIXME: don't know what are good values */
-	frequency->LowPart	= 0;
+	frequency->LowPart	= 1000000;
 	frequency->HighPart	= 0;
-	/* FIXME: Set appropriate error */
-	return FALSE;
+	return TRUE;
 }
 
 /****************************************************************************
diff --git a/win32/ordinals.c b/win32/ordinals.c
index 56d2f9f..a27fdd5 100644
--- a/win32/ordinals.c
+++ b/win32/ordinals.c
@@ -52,11 +52,7 @@
 	fprintf(stderr,"KERNEL32_18(%ld,%ld+0x38)\n",processid,action);
 	if (action>56)
 		return 0;
-	if (!processid) {
-		process=pCurrentProcess;
-		/* check if valid process */
-	} else
-		process=(PDB32*)pCurrentProcess; /* decrypt too, if needed */
+        if (!(process = PROCESS_IdToPDB( processid ))) return 0;
 	switch (action) {
 	case 0:	/* return app compat flags */
 		pTask = (TDB*)GlobalLock16(process->task);
diff --git a/windows/clipboard.c b/windows/clipboard.c
index 7a262bd..a6a072e 100644
--- a/windows/clipboard.c
+++ b/windows/clipboard.c
@@ -871,13 +871,24 @@
 
 
 /**************************************************************************
- *             GetPriorityClipboardFormat32   (USER32
+ *             GetPriorityClipboardFormat32   (USER32.279)
  */
 INT32 WINAPI GetPriorityClipboardFormat32( UINT32 *lpPriorityList, INT32 nCount )
 {
-    fprintf( stderr, "GetPriorityClipboardFormat32(%p, %d): stub\n",
-             lpPriorityList, nCount );
-    return 0;
+    int Counter;
+
+    if(CountClipboardFormats32() == 0) 
+    { 
+        return 0;
+    }
+
+    for(Counter = 0; Counter <= nCount; Counter++)
+    {
+        if(IsClipboardFormatAvailable32(*(lpPriorityList+sizeof(INT32)*Counter)))
+            return *(lpPriorityList+sizeof(INT32)*Counter);
+    }
+
+    return -1;
 }
 
 
diff --git a/windows/painting.c b/windows/painting.c
index eeb1c78..fba790b 100644
--- a/windows/painting.c
+++ b/windows/painting.c
@@ -340,6 +340,15 @@
 	
         if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT;
 
+        /* restrict update region to client area (FIXME: correct?) */
+        if (wndPtr->hrgnUpdate)
+        {
+            HRGN32 clientRgn = CreateRectRgnIndirect32( &rectClient );
+            rgnNotEmpty = CombineRgn32( wndPtr->hrgnUpdate, clientRgn, 
+                                        wndPtr->hrgnUpdate, RGN_AND );
+            DeleteObject32( clientRgn );
+        }
+
 	/* check for bogus update region */ 
 	if ( rgnNotEmpty == NULLREGION )
 	   {
diff --git a/windows/win.c b/windows/win.c
index c8ac1c4..69f88b4 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -2128,7 +2128,7 @@
  */
 BOOL32 WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC32 func, LPARAM lParam )
 {
-    THDB	*tdb = (THDB*)id;
+    THDB	*tdb = THREAD_ID_TO_THDB(id);
 
     return (BOOL16)EnumTaskWindows16(tdb->teb.htask16, (WNDENUMPROC16)func, lParam);
 }