Release 950901

Thu Aug 31 17:19:57 1995  Alexandre Julliard  <julliard@sunsite.unc.edu>

	* [Configure]
	Added compile-time option for IPC.

	* [configure.in]
	Added command-line options for language, IPC and malloc
	debugging.

	* [controls/menu.c]
	WM_MENUSELECT was sometimes sent to the wrong window.

	* [debugger/break.c]
	For the 'next' command, only step over instruction that require
	it. This allows 'next' to do the right thing with jmp and ret
	instructions.

	* [ipc/*.c] [memory/atom.c] [memory/global.c]
	IPC can now be configured out at compile-time.

	* [loader/task.c]
	Bug fix in TASK_Reschedule() that could cause a task to be deleted
	twice.

	* [miscemu/dosmem.c] (New file)
	Partial emulation of the BIOS data segment.

	* [miscemu/instr.c]
	Trap attempts to access selector 0x40 and remap the access to
	segment __0040H.

	* [tools/build.c]
	Fixed bug in CallTo32_LargeStack() that caused problems when
	compiling Wine with the -fomit-frame-pointer option.

	* [windows/message.c]
	Fixed bug in hardware event handling that could cause some events
	to get ignored.

Sat Aug 26 13:12:59 IST 1995 Michael Veksler <mveksler@vnet.ibm.com>

	* [ipc/README] [ipc/dde.tex]
	LaTeX documentation for the ipc and DDE stuff.

Wed Aug 23 22:01:23 GMT 1995 Michael Veksler <mveksler@vnet.ibm.com>

	* [ipc/Imakefile] [ipc/wine_test_stub.c]
	Fixed IPC testing. Now it can be compiled with "make tests"

Wed Aug 23 21:04:14 1995  Fons Botman  <botman@wab-tis.rabobank.nl>

	* [if1632/kernel.spec] [include/windows.h] [misc/main.c]
	Added GetWinDebugInfo/SetWinDebugInfo stub for player.exe

Sun Aug  20 13:49:42 1995  Marcus Meissner  <msmeissn@faui01.informatik.uni-erlangen.de>

	* [miscemu/int21.c]
	Misc fix to int21,ah=40 (write) to match _lwrite().
	AX=0x440A (check if handle is remote) added.

	* [multimedia/mmsystem.c]
	Moved mciSendString to mcistring.c.

	* [multimedia/mcistring.c]
	New file, string interface for MCI (not complete, not thoroughly
	tested).

	* [multimedia/audio.c]
	IOCTL prints errors; one paranoid check disabled.

	* [misc/file.c]
	Misc operator precedence fixes.

	* [if1632/gdi.spec] [objects/bitblt.c]
	Stub for FastWindowFrame (parameters not correct).

Sat Aug 19 01:31:23 1995  Graham Menhennitt <gfm@werple.mira.net.au>

	* [loader/ne_image.c]
	Preliminary support for iterated segments.

Sat Aug 19 00:43:04 1995  Andrew Taylor  (andrew@riscan.com)

	* [windows/mapping.c]
	In function MAPPING_FixIsotropic(), VportExt[XY] is multiplied by
 	the absolute value of (ydim / xdim) or (xdim / ydim).

Thu Aug 15 23:00:16  Gregory Trubetskoy  <grisha@mira.com>

	* [objects/oembitmap.c]
	Added some includes for Windows 95.

	* [include/sysmetrics.h]
	Added some sysmetrics for Windows 95.

	* [include/bitmaps/*95]
	New files: obm_close_95, obm_closed_95, obm_reduce_95, obm_reduced_95
	obm_zoom_95, obm_zoomd_95 - these are some pixmaps for Windows 95.

Thu Aug 10 12:00:00 1995  Jan Willamowius  (jan@janhh.shnet.org)

	* [misc/shell.c] [rc/sysres*.rc]
	The caption of the ShellAbout dialog box is language specific and
 	should be defined in the resources.
diff --git a/ANNOUNCE b/ANNOUNCE
index 137878f..8120304 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,14 +1,15 @@
-This is release 950817 of Wine the MS Windows emulator.  This is still a
+This is release 950901 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.
 
 Patches should be submitted to "wine-new@amscons.com".  Please don't forget
-to include a ChangeLog entry.  I'll make a new release every other Sunday.
+to include a ChangeLog entry.  I'll make a new release every other week.
 
-WHAT'S NEW with Wine-950817: (see ChangeLog for details)
-	- Built-in debugger improvements.
-	- Multimedia fixes.
-	- IPC can be disabled at run-time.
+WHAT'S NEW with Wine-950901: (see ChangeLog for details)
+	- Accesses to BIOS segment 0x40 are trapped and emulated.
+	- Multimedia improvements.
+	- IPC can now be disabled at compile-time.
+	- Documentation for the IPC code.
 	- Lots of bug fixes.
 
 See the README file in the distribution for installation instructions.
@@ -17,11 +18,11 @@
 the release is available at the ftp sites.  The sources will be available
 from the following locations:
 
-    sunsite.unc.edu:/pub/Linux/ALPHA/wine/Wine-950817.tar.gz
-    tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-950817.tar.gz
-    ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-950817.tar.gz
-    ftp.funet.fi:/pub/OS/Linux/ALPHA/Wine/Wine-950817.tar.gz
-    aris.com:/pub/linux/ALPHA/Wine/development/Wine-950817.tar.gz
+    sunsite.unc.edu:/pub/Linux/ALPHA/wine/Wine-950901.tar.gz
+    tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-950901.tar.gz
+    ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-950901.tar.gz
+    ftp.funet.fi:/pub/OS/Linux/ALPHA/Wine/Wine-950901.tar.gz
+    aris.com:/pub/linux/ALPHA/Wine/development/Wine-950901.tar.gz
 
 It should also be available from any site that mirrors tsx-11 or sunsite.
 
diff --git a/ChangeLog b/ChangeLog
index 29c8497..5a64227 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,108 @@
+Thu Aug 31 17:19:57 1995  Alexandre Julliard  <julliard@sunsite.unc.edu>
+
+	* [Configure]
+	Added compile-time option for IPC.
+
+	* [configure.in]
+	Added command-line options for language, IPC and malloc
+	debugging.
+
+	* [controls/menu.c]
+	WM_MENUSELECT was sometimes sent to the wrong window.
+
+	* [debugger/break.c]
+	For the 'next' command, only step over instruction that require
+	it. This allows 'next' to do the right thing with jmp and ret
+	instructions.
+
+	* [ipc/*.c] [memory/atom.c] [memory/global.c]
+	IPC can now be configured out at compile-time.
+
+	* [loader/task.c]
+	Bug fix in TASK_Reschedule() that could cause a task to be deleted
+	twice.
+
+	* [miscemu/dosmem.c] (New file)
+	Partial emulation of the BIOS data segment.
+
+	* [miscemu/instr.c]
+	Trap attempts to access selector 0x40 and remap the access to
+	segment __0040H.
+
+	* [tools/build.c]
+	Fixed bug in CallTo32_LargeStack() that caused problems when
+	compiling Wine with the -fomit-frame-pointer option.
+
+	* [windows/message.c]
+	Fixed bug in hardware event handling that could cause some events
+	to get ignored.
+
+Sat Aug 26 13:12:59 IST 1995 Michael Veksler <mveksler@vnet.ibm.com>
+
+	* [ipc/README] [ipc/dde.tex]
+	LaTeX documentation for the ipc and DDE stuff.
+
+Wed Aug 23 22:01:23 GMT 1995 Michael Veksler <mveksler@vnet.ibm.com>
+
+	* [ipc/Imakefile] [ipc/wine_test_stub.c]
+	Fixed IPC testing. Now it can be compiled with "make tests"
+
+Wed Aug 23 21:04:14 1995  Fons Botman  <botman@wab-tis.rabobank.nl>
+
+	* [if1632/kernel.spec] [include/windows.h] [misc/main.c]
+	Added GetWinDebugInfo/SetWinDebugInfo stub for player.exe
+
+Sun Aug  20 13:49:42 1995  Marcus Meissner  <msmeissn@faui01.informatik.uni-erlangen.de>
+
+	* [miscemu/int21.c]
+	Misc fix to int21,ah=40 (write) to match _lwrite().
+	AX=0x440A (check if handle is remote) added.
+
+	* [multimedia/mmsystem.c]
+	Moved mciSendString to mcistring.c.
+
+	* [multimedia/mcistring.c]
+	New file, string interface for MCI (not complete, not thoroughly
+	tested).
+
+	* [multimedia/audio.c]
+	IOCTL prints errors; one paranoid check disabled.
+
+	* [misc/file.c]
+	Misc operator precedence fixes.
+
+	* [if1632/gdi.spec] [objects/bitblt.c]
+	Stub for FastWindowFrame (parameters not correct).
+
+Sat Aug 19 01:31:23 1995  Graham Menhennitt <gfm@werple.mira.net.au>
+
+	* [loader/ne_image.c]
+	Preliminary support for iterated segments.
+
+Sat Aug 19 00:43:04 1995  Andrew Taylor  (andrew@riscan.com)
+
+	* [windows/mapping.c]
+	In function MAPPING_FixIsotropic(), VportExt[XY] is multiplied by
+ 	the absolute value of (ydim / xdim) or (xdim / ydim).
+
+Thu Aug 15 23:00:16  Gregory Trubetskoy  <grisha@mira.com>
+
+	* [objects/oembitmap.c]
+	Added some includes for Windows 95.
+
+	* [include/sysmetrics.h]
+	Added some sysmetrics for Windows 95.
+
+	* [include/bitmaps/*95]
+	New files: obm_close_95, obm_closed_95, obm_reduce_95, obm_reduced_95
+	obm_zoom_95, obm_zoomd_95 - these are some pixmaps for Windows 95.
+
+Thu Aug 10 12:00:00 1995  Jan Willamowius  (jan@janhh.shnet.org)
+
+	* [misc/shell.c] [rc/sysres*.rc]
+	The caption of the ShellAbout dialog box is language specific and
+ 	should be defined in the resources.
+
 ----------------------------------------------------------------------
 Thu Aug 17 19:30:14 1995  Alexandre Julliard  <julliard@sunsite.unc.edu>
 
diff --git a/Configure b/Configure
index 9a9435a..7e7f4a0 100644
--- a/Configure
+++ b/Configure
@@ -49,6 +49,12 @@
 done
 ALLDEFINES="$ALLDEFINES -ALANG\($LANGUAGE\)"
 
+prompt "Inter-process communication" CONFIG_IPC N
+if [ CONFIG_IPC = 'Y' -o $CONFIG_IPC = 'y' ]
+then
+       ALLDEFINES="$ALLDEFINES -DCONFIG_IPC"
+fi
+
 prompt "Malloc debugging" MALLOC_DEBUGGING N
 if [ MALLOC_DEBUGGING = 'Y' -o $MALLOC_DEBUGGING = 'y' ]
 then
diff --git a/Imakefile b/Imakefile
index 5488945..47ffac6 100644
--- a/Imakefile
+++ b/Imakefile
@@ -3,7 +3,6 @@
 
 #if defined(i386FreeBsd) || defined(FreeBSDArchitecture)
 MAKE = gmake
-CC = gcc -D__FreeBSD__
 #endif
 
 DEFINES = AutoDefines -DUSE_READLINE
diff --git a/Makefile.in b/Makefile.in
index 59cd6cb..fd71192 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -12,6 +12,7 @@
 
 CC 	= @CC@
 CFLAGS 	= @CFLAGS@
+DEFS    = @DEFS@
 XINCL 	= @x_includes@
 TOPSRC  = @top_srcdir@
 DIVINCL = -I$(TOPSRC)/include
@@ -22,7 +23,7 @@
 LD	= @LD@
 LANG	= @LANG@
 LDCOMBINEFLAGS = @LDCOMBINEFLAGS@
- 
+@SET_MAKE@
 
 COMMONSUBDIRS = controls rc ipc loader misc multimedia objects windows
 
@@ -53,7 +54,7 @@
 	$(CC) -o wine $(OBJS) $(LDOPTIONS) $(XDIR) $(XPM_LIB) $(XLIB) $(LDLIBS)
 
 $(SUBDIRS): dummy
-	@cd $@; $(MAKE) 'CC=$(CC)' 'CFLAGS=$(CFLAGS)' 'LD=$(LD)' 'LDCOMBINEFLAGS=$(LDCOMBINEFLAGS)' 'LANG=$(LANG)'
+	@cd $@; $(MAKE) 'CC=$(CC)' 'CFLAGS=$(CFLAGS)' 'DEFS=$(DEFS)' 'LD=$(LD)' 'LDCOMBINEFLAGS=$(LDCOMBINEFLAGS)' 'LANG=$(LANG)'
 
 depend:
 	for i in $(SUBDIRS); do (cd $$i; $(MAKE) depend); done
@@ -63,14 +64,14 @@
 
 clean:
 	for i in $(SUBDIRS); do (cd $$i; $(MAKE) clean); done
-	rm -f *.o \#*\# *~ wine wine.sym TAGS
+	rm -f *.o \#*\# *~ *.bak wine wine.sym TAGS
 
 distclean:
 	for i in $(SUBDIRS); do (cd $$i; $(MAKE) distclean); done
 	echo "/* autoconf.h generated automatically.  Run Configure */" >autoconf.h
 	echo "#error You must run Configure before you can build the makefiles." >>autoconf.h
-	rm -f *.o \#*\# *~ wine wine.sym
-	rm -f stamp-config config.* include/config.h Makefile
+	rm -f *.o \#*\# *~ *.bak wine wine.sym TAGS
+	rm -f config.* include/config.h Makefile
 
 countryclean:
 	for i in $(SUBDIRS); do (cd $$i; $(MAKE) countryclean); done
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 85028b1..ee927be 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -12,16 +12,19 @@
 sure to analyze the problem before you report it to the newsgroup.
 
 2. What are these questions in Configure?
-Emulator/Library: You need an emulator when you want to run MS-Win
-binaries. You need a library when you want to compile the source code
-of a Windows program.
-Language: Wine can present the system menu in multiple languages. Select
-one of English, German, or Norwegian here.
-Malloc debugging: When enabled, the mtrace and mcheck GNU libc functions
-are called. You might want to set the MALLOC_TRACE environment variable
-to a trace file name. If your system supports another way of malloc 
-debugging, feel free to add it.
-Config file: Sets the Wine environment. See README for details.
+- Emulator/Library: You need an emulator when you want to run MS-Win
+    binaries. You need a library when you want to compile the source code
+    of a Windows program.
+- Language: Wine can present the system menu in multiple languages. Select
+    one of English, German, or Norwegian here.
+- Inter-process communication: Allows setting up a DDE conversation
+    between different instances of Wine. Only really useful when
+    building Wine as a library.
+- Malloc debugging: When enabled, the mtrace and mcheck GNU libc functions
+    are called. You might want to set the MALLOC_TRACE environment variable
+    to a trace file name. If your system supports another way of malloc 
+    debugging, feel free to add it.
+- Config file: Sets the Wine environment. See README for details.
 
 3. BAR.EXE used to work, but does not work anymore
 Look at the ChangeLog to see what files have been changed. Try to undo
diff --git a/configure b/configure
index f495a92..3b8d7da 100755
--- a/configure
+++ b/configure
@@ -13,6 +13,12 @@
 ac_default_prefix=/usr/local
 # Any additions from configure.in:
 ac_help="$ac_help
+  --with-language=LANG    change the default language (LANG=En/De/No)"
+ac_help="$ac_help
+  --with-ipc              use inter-process communication for DDE"
+ac_help="$ac_help
+  --with-malloc-debug     enable malloc() debugging"
+ac_help="$ac_help
   --with-x                use the X Window System"
 
 # Initialize some variables set by options.
@@ -402,11 +408,38 @@
 
 		
 
-
 # We want these before the checks, so the checks can modify their values.
 test -z "$CFLAGS" && CFLAGS="-g -O2 -Wall" 
 test -z "$LDFLAGS" && LDFLAGS=-g 
 
+# Check whether --with-language or --without-language was given.
+withval="$with_language"
+if test -n "$withval"; then
+  LANG="-ALANG\($withval\)"
+else
+  LANG="-ALANG\(En\)"
+fi
+
+
+# Check whether --with-ipc or --without-ipc was given.
+withval="$with_ipc"
+if test -n "$withval"; then
+  cat >> confdefs.h <<\EOF
+#define CONFIG_IPC 1
+EOF
+
+fi
+
+# Check whether --with-malloc-debug or --without-malloc-debug was given.
+withval="$with_malloc_debug"
+if test -n "$withval"; then
+  cat >> confdefs.h <<\EOF
+#define MALLOC_DEBUGGING 1
+EOF
+
+fi
+
+
 echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
 set dummy ${MAKE-make}; ac_make=$2
 if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
@@ -521,7 +554,7 @@
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 525 "configure"
+#line 558 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
@@ -535,7 +568,7 @@
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 539 "configure"
+#line 572 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
@@ -621,7 +654,7 @@
 test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc
 test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h
 cat > conftest.$ac_ext <<EOF
-#line 625 "configure"
+#line 658 "configure"
 #include "confdefs.h"
 #include <$x_direct_test_include>
 EOF
@@ -684,7 +717,7 @@
 ac_save_LIBS="$LIBS"
 LIBS="-l$x_direct_test_library $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 688 "configure"
+#line 721 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -840,7 +873,7 @@
   ac_save_LIBS="$LIBS"
 LIBS="-l$ac_lib  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 844 "configure"
+#line 877 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -891,7 +924,7 @@
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 895 "configure"
+#line 928 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -943,7 +976,7 @@
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 947 "configure"
+#line 980 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
@@ -971,122 +1004,12 @@
 fi
 done
 
-ac_header_dirent=no
-for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
-do
-ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
-echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
-if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 984 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#include <$ac_hdr>
-int main() { return 0; }
-int t() {
-DIR *dirp = 0;
-; return 0; }
-EOF
-if eval $ac_compile; then
-  rm -rf conftest*
-  eval "ac_cv_header_dirent_$ac_safe=yes"
-else
-  rm -rf conftest*
-  eval "ac_cv_header_dirent_$ac_safe=no"
-fi
-rm -f conftest*
-
-fi
-if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
- ac_header_dirent=$ac_hdr; break
-else
-  echo "$ac_t""no" 1>&6
-fi
-done
-# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
-if test $ac_header_dirent = dirent.h; then
-echo $ac_n "checking for -ldir""... $ac_c" 1>&6
-if eval "test \"`echo '$''{'ac_cv_lib_dir'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-ldir  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1023 "configure"
-#include "confdefs.h"
-
-int main() { return 0; }
-int t() {
-opendir()
-; return 0; }
-EOF
-if eval $ac_link; then
-  rm -rf conftest*
-  eval "ac_cv_lib_dir=yes"
-else
-  rm -rf conftest*
-  eval "ac_cv_lib_dir=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'dir`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  LIBS="$LIBS -ldir"
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-else
-echo $ac_n "checking for -lx""... $ac_c" 1>&6
-if eval "test \"`echo '$''{'ac_cv_lib_x'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-lx  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1057 "configure"
-#include "confdefs.h"
-
-int main() { return 0; }
-int t() {
-opendir()
-; return 0; }
-EOF
-if eval $ac_link; then
-  rm -rf conftest*
-  eval "ac_cv_lib_x=yes"
-else
-  rm -rf conftest*
-  eval "ac_cv_lib_x=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'x`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  LIBS="$LIBS -lx"
-else
-  echo "$ac_t""no" 1>&6
-fi
-
-fi
-
 echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6
 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 1090 "configure"
+#line 1013 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -1140,7 +1063,7 @@
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1144 "configure"
+#line 1067 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1217,7 +1140,7 @@
   ac_cv_c_cross=yes
 else
 cat > conftest.$ac_ext <<EOF
-#line 1221 "configure"
+#line 1144 "configure"
 #include "confdefs.h"
 main(){return(0);}
 EOF
@@ -1238,7 +1161,7 @@
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1242 "configure"
+#line 1165 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1260,7 +1183,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 1264 "configure"
+#line 1187 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -1278,7 +1201,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 1282 "configure"
+#line 1205 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1299,7 +1222,7 @@
   ac_cv_header_stdc=no
 else
 cat > conftest.$ac_ext <<EOF
-#line 1303 "configure"
+#line 1226 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1333,7 +1256,7 @@
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1337 "configure"
+#line 1260 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -1365,82 +1288,6 @@
 else
 TOP_SRCDIR="${top_srcdir}"
 fi
-echo $ac_n "checking for language in autoconf.h""... $ac_c" 1>&6
-if test -f ${TOP_SRCDIR}/autoconf.h; then
-LANG=`tr ' ' '\n' < ${TOP_SRCDIR}/autoconf.h | grep '\-ALANG' | head -1`
-if test -n "${LANG}"; then
-echo "$ac_t""`echo "${LANG}" | cut -b9-10`" 1>&6
-fi
-fi
-if test -z "${LANG}"; then
-echo "$ac_t""no" 1>&6
-fi
-
-
-if test -z "${LANG}"; then
-echo $ac_n "checking for language through domainname""... $ac_c" 1>&6
-DNAME=`domainname`
-if test `echo "${DNAME}" | grep -c "\.no"` -ne 0; then
-LANG="-ALANG\(No\)"
-echo "$ac_t""No" 1>&6
-fi
-if test `echo "${DNAME}" | grep -c "\.de"` -ne 0; then
-LANG="-ALANG\(De\)"
-echo "$ac_t""De" 1>&6
-fi
-if test `echo "${DNAME}" | grep -c "\.uk"` -ne 0; then
-LANG="-ALANG\(En\)"
-echo "$ac_t""En" 1>&6
-fi
-if test `echo "${DNAME}" | grep -c "\.com"` -ne 0; then
-LANG="-ALANG\(En\)"
-echo "$ac_t""En" 1>&6
-fi
-if test `echo "${DNAME}" | grep -c "\.edu"` -ne 0; then
-LANG="-ALANG\(En\)"
-echo "$ac_t""En" 1>&6
-fi
-if test `echo "${DNAME}" | grep -c "\.gov"` -ne 0; then
-LANG="-ALANG\(En\)"
-echo "$ac_t""En" 1>&6
-fi
-if test -z "${LANG}"; then
-echo "$ac_t""no" 1>&6
-fi
-fi
-
-if test -z "${LANG}"; then
-echo $ac_n "checking for linux""... $ac_c" 1>&6
-cat > conftest.$ac_ext <<EOF
-#line 1416 "configure"
-#include "confdefs.h"
-#ifdef linux
-   yes
-#endif
-
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "yes" >/dev/null 2>&1; then
-  rm -rf conftest*
-  echo "$ac_t""yes" 1>&6
-echo $ac_n "checking for language by examining keymap""... $ac_c" 1>&6
-if test `dumpkeys | grep "keycode *26" | tr ' ' '\n' | grep -c udiaeresis` -ne 0; then
-echo "$ac_t""De" 1>&6
-LANG='-ALANG\(De\)'
-else
-echo "$ac_t""no" 1>&6
-LANG='-ALANG\(En\)'
-fi
-
-else
-  rm -rf conftest*
-  echo "$ac_t""no" 1>&6
-LANG='-ALANG\(En\)'
-
-fi
-rm -f conftest*
-
-fi
 
 echo $ac_n "checking for wine.ini in autoconf.h""... $ac_c" 1>&6
 if test -f ${TOP_SRCDIR}/autoconf.h; then
@@ -1518,7 +1365,19 @@
 
 trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
 
-DEFS=-DHAVE_CONFIG_H
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%-D\1=\2%g
+s%[ 	`~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
 
 # Without the "./", some shells look in PATH for config.status.
 : ${CONFIG_STATUS=./config.status}
@@ -1555,7 +1414,7 @@
 
 ac_given_srcdir=$srcdir
 
-trap 'rm -fr `echo "controls/Makefile ipc/Makefile loader/Makefile memory/Makefile misc/Makefile miscemu/Makefile multimedia/Makefile objects/Makefile windows/Makefile rc/Makefile debugger/Makefile debugger/readline/Makefile tools/Makefile if1632/Makefile Makefile autoconf.h include/config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+trap 'rm -fr `echo "controls/Makefile ipc/Makefile loader/Makefile memory/Makefile misc/Makefile miscemu/Makefile multimedia/Makefile objects/Makefile windows/Makefile rc/Makefile debugger/Makefile debugger/readline/Makefile tools/Makefile if1632/Makefile Makefile autoconf.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
 
 # Protect against being on the right side of a sed subst in config.status. 
 sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; 
@@ -1571,6 +1430,7 @@
 s%@exec_prefix@%$exec_prefix%g
 s%@prefix@%$prefix%g
 s%@program_transform_name@%$program_transform_name%g
+s%@LANG@%$LANG%g
 s%@SET_MAKE@%$SET_MAKE%g
 s%@CC@%$CC%g
 s%@CPP@%$CPP%g
@@ -1583,7 +1443,6 @@
 s%@LIBOBJS@%$LIBOBJS%g
 s%@LD@%$LD%g
 s%@LDCOMBINEFLAGS@%$LDCOMBINEFLAGS%g
-s%@LANG@%$LANG%g
 s%@WINE_INI_GLOBAL@%$WINE_INI_GLOBAL%g
 
 CEOF
@@ -1641,104 +1500,8 @@
 fi; done
 rm -f conftest.subs
 
-# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
-# NAME is the cpp macro being defined and VALUE is the value it is being given.
-#
-# ac_d sets the value in "#define NAME VALUE" lines.
-ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
-ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
-ac_dC='\3'
-ac_dD='%g'
-# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
-ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
-ac_uB='\([ 	]\)%\1#\2define\3'
-ac_uC=' '
-ac_uD='\4%g'
-# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
-ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
-ac_eB='$%\1#\2define\3'
-ac_eC=' '
-ac_eD='%g'
-
-CONFIG_HEADERS=${CONFIG_HEADERS-"include/config.h"}
-for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
-  # Support "outfile[:infile]", defaulting infile="outfile.in".
-  case "$ac_file" in
-  *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
-       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
-  *) ac_file_in="${ac_file}.in" ;;
-  esac
-
-  echo creating $ac_file
-
-  rm -f conftest.frag conftest.in conftest.out
-  cp $ac_given_srcdir/$ac_file_in conftest.in
-
-EOF
-
-# Transform confdefs.h into a sed script conftest.vals that substitutes
-# the proper values into config.h.in to produce config.h.  And first:
-# Protect against being on the right side of a sed subst in config.status. 
-# Protect against being in an unquoted here document in config.status.
-rm -f conftest.vals
-cat > conftest.hdr <<\EOF
-s/[\\&%]/\\&/g
-s%[\\$`]%\\&%g
-s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
-s%ac_d%ac_u%gp
-s%ac_u%ac_e%gp
-EOF
-sed -n -f conftest.hdr confdefs.h > conftest.vals
-rm -f conftest.hdr
-
-# This sed command replaces #undef with comments.  This is necessary, for
-# example, in the case of _POSIX_SOURCE, which is predefined and required
-# on some systems where configure will not decide to define it.
-cat >> conftest.vals <<\EOF
-s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
-EOF
-
-# Break up conftest.vals because some shells have a limit on
-# the size of here documents, and old seds have small limits too.
-# Maximum number of lines to put in a single here document.
-ac_max_here_lines=12
-
-rm -f conftest.tail
-while :
-do
-  ac_lines=`grep -c . conftest.vals`
-  # grep -c gives empty output for an empty file on some AIX systems.
-  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
-  # Write a limited-size here document to conftest.frag.
-  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
-  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
-  echo 'CEOF
-  sed -f conftest.frag conftest.in > conftest.out
-  rm -f conftest.in
-  mv conftest.out conftest.in
-' >> $CONFIG_STATUS
-  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
-  rm -f conftest.vals
-  mv conftest.tail conftest.vals
-done
-rm -f conftest.vals
-
-cat >> $CONFIG_STATUS <<\EOF
-  rm -f conftest.frag conftest.h
-  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
-  cat conftest.in >> conftest.h
-  rm -f conftest.in
-  if cmp -s $ac_file conftest.h 2>/dev/null; then
-    echo "$ac_file is unchanged"
-    rm -f conftest.h
-  else
-    rm -f $ac_file
-    mv conftest.h $ac_file
-  fi
-fi; done
 
 
-touch stamp-config
 exit 0
 EOF
 chmod +x $CONFIG_STATUS
diff --git a/configure.in b/configure.in
index eded50a..71aac5c 100644
--- a/configure.in
+++ b/configure.in
@@ -3,12 +3,23 @@
 dnl                         <patra@itp1.physik.tu-berlin.de>
 AC_REVISION([configure.in 1.00])
 AC_INIT(controls/edit.c)		
-AC_CONFIG_HEADER(include/config.h)
 
 # We want these before the checks, so the checks can modify their values.
 test -z "$CFLAGS" && CFLAGS="-g -O2 -Wall" AC_SUBST(CFLAGS)
 test -z "$LDFLAGS" && LDFLAGS=-g AC_SUBST(LDFLAGS)
 
+AC_ARG_WITH(language,
+[  --with-language=LANG    change the default language (LANG=En/De/No)],
+[LANG="-ALANG\($withval\)"],
+[LANG="-ALANG\(En\)"],)
+AC_SUBST(LANG)
+AC_ARG_WITH(ipc,
+[  --with-ipc              use inter-process communication for DDE],
+[AC_DEFINE(CONFIG_IPC)])
+AC_ARG_WITH(malloc-debug,
+[  --with-malloc-debug     enable malloc() debugging],
+[AC_DEFINE(MALLOC_DEBUGGING)])
+
 AC_PROG_MAKE_SET
 AC_PROG_CC
 AC_PATH_X
@@ -41,70 +52,6 @@
 else
 TOP_SRCDIR="${top_srcdir}"
 fi
-AC_MSG_CHECKING(for language in autoconf.h)
-if test -f ${TOP_SRCDIR}/autoconf.h; then
-LANG=`tr ' ' '\n' < ${TOP_SRCDIR}/autoconf.h | grep '\-ALANG' | head -1`
-if test -n "${LANG}"; then
-AC_MSG_RESULT(`echo "${LANG}" | cut -b9-10`)
-fi
-fi
-if test -z "${LANG}"; then
-AC_MSG_RESULT(no)
-fi
-AC_SUBST(LANG)
-
-if test -z "${LANG}"; then
-AC_MSG_CHECKING(for language through domainname)
-DNAME=`domainname`
-if test `echo "${DNAME}" | grep -c "\.no"` -ne 0; then
-LANG="-ALANG\(No\)"
-AC_MSG_RESULT(No)
-fi
-if test `echo "${DNAME}" | grep -c "\.de"` -ne 0; then
-LANG="-ALANG\(De\)"
-AC_MSG_RESULT(De)
-fi
-if test `echo "${DNAME}" | grep -c "\.uk"` -ne 0; then
-LANG="-ALANG\(En\)"
-AC_MSG_RESULT(En)
-fi
-if test `echo "${DNAME}" | grep -c "\.com"` -ne 0; then
-LANG="-ALANG\(En\)"
-AC_MSG_RESULT(En)
-fi
-if test `echo "${DNAME}" | grep -c "\.edu"` -ne 0; then
-LANG="-ALANG\(En\)"
-AC_MSG_RESULT(En)
-fi
-if test `echo "${DNAME}" | grep -c "\.gov"` -ne 0; then
-LANG="-ALANG\(En\)"
-AC_MSG_RESULT(En)
-fi
-if test -z "${LANG}"; then
-AC_MSG_RESULT(no)
-fi
-fi
-
-if test -z "${LANG}"; then
-AC_MSG_CHECKING(for linux)
-AC_EGREP_CPP(yes,
-[#ifdef linux
-   yes
-#endif
-], AC_MSG_RESULT(yes)
-AC_MSG_CHECKING(for language by examining keymap)
-if test `dumpkeys | grep "keycode *26" | tr ' ' '\n' | grep -c udiaeresis` -ne 0; then
-AC_MSG_RESULT(De)
-LANG='-ALANG\(De\)'
-else
-AC_MSG_RESULT(no)
-LANG='-ALANG\(En\)'
-fi
-,
-AC_MSG_RESULT(no)
-LANG='-ALANG\(En\)'
-)
-fi
 
 AC_MSG_CHECKING(for wine.ini in autoconf.h)
 if test -f ${TOP_SRCDIR}/autoconf.h; then
@@ -129,11 +76,7 @@
 fi
 AC_SUBST(WINE_INI_GLOBAL)
 
-
-test -z "$LDFLAGS" && LDFLAGS=-g AC_SUBST(LDFLAGS)
-
-
-AC_OUTPUT(controls/Makefile ipc/Makefile loader/Makefile memory/Makefile misc/Makefile miscemu/Makefile multimedia/Makefile objects/Makefile windows/Makefile rc/Makefile debugger/Makefile debugger/readline/Makefile tools/Makefile if1632/Makefile Makefile autoconf.h, [touch stamp-config])
+AC_OUTPUT(controls/Makefile ipc/Makefile loader/Makefile memory/Makefile misc/Makefile miscemu/Makefile multimedia/Makefile objects/Makefile windows/Makefile rc/Makefile debugger/Makefile debugger/readline/Makefile tools/Makefile if1632/Makefile Makefile autoconf.h)
 
 echo
 echo "Configure finished.  Do 'make depend; make' to compile Wine."
diff --git a/controls/Makefile.in b/controls/Makefile.in
index 9aa20c7..02cbb3b 100644
--- a/controls/Makefile.in
+++ b/controls/Makefile.in
@@ -27,7 +27,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/controls/button.c b/controls/button.c
index 9e29e54..b33900a 100644
--- a/controls/button.c
+++ b/controls/button.c
@@ -261,7 +261,6 @@
     HBRUSH hOldBrush;
     char *text;
     DWORD dwTextSize;
-    int delta;
     TEXTMETRIC tm;
     WND *wndPtr = WIN_FindWndPtr( hButton );
     BUTTONINFO *infoPtr = (BUTTONINFO *)wndPtr->wExtra;
diff --git a/controls/menu.c b/controls/menu.c
index 88c4c15..598de3a 100644
--- a/controls/menu.c
+++ b/controls/menu.c
@@ -697,7 +697,7 @@
 /***********************************************************************
  *           MENU_SelectItem
  */
-static void MENU_SelectItem( HMENU hmenu, WORD wIndex )
+static void MENU_SelectItem( HWND hwndOwner, HMENU hmenu, WORD wIndex )
 {
     MENUITEM *items;
     LPPOPUPMENU lppop;
@@ -739,8 +739,9 @@
 	    MENU_DrawMenuItem( lppop->hWnd, hdc, &items[lppop->FocusedItem], lppop->Height,
 			       !(lppop->wFlags & MF_POPUP) );
 	    dprintf_menu(stddeb,"Sending WM_MENUSELECT %04x %04x\n", items[lppop->FocusedItem].item_id,items[lppop->FocusedItem].item_flags);
-	    SendMessage(lppop->hWnd, WM_MENUSELECT, items[lppop->FocusedItem].item_id,
-		       MAKELONG( items[lppop->FocusedItem].item_flags | MF_MOUSESELECT, hmenu));
+	    SendMessage( hwndOwner, WM_MENUSELECT,
+                         items[lppop->FocusedItem].item_id,
+		         MAKELONG( items[lppop->FocusedItem].item_flags | MF_MOUSESELECT, hmenu));
 	}
     }
     ReleaseDC( lppop->hWnd, hdc );
@@ -750,7 +751,7 @@
 /***********************************************************************
  *           MENU_SelectNextItem
  */
-static void MENU_SelectNextItem( HMENU hmenu )
+static void MENU_SelectNextItem( HWND hwndOwner, HMENU hmenu )
 {
     int i;
     MENUITEM *items;
@@ -766,13 +767,13 @@
 	{
 	    if (!(items[i].item_flags & MF_SEPARATOR))
 	    {
-		MENU_SelectItem( hmenu, i );
+		MENU_SelectItem( hwndOwner, hmenu, i );
 		return;
 	    }
 	}
 	if (MENU_HasSysMenu( menu ))
 	{
-	    MENU_SelectItem( hmenu, SYSMENU_SELECTED );
+	    MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
 	    return;
 	}
     }
@@ -780,18 +781,19 @@
     {
 	if (!(items[i].item_flags & MF_SEPARATOR))
 	{
-	    MENU_SelectItem( hmenu, i );
+	    MENU_SelectItem( hwndOwner, hmenu, i );
 	    return;
 	}
     }
-    if (MENU_HasSysMenu( menu )) MENU_SelectItem( hmenu, SYSMENU_SELECTED );
+    if (MENU_HasSysMenu( menu ))
+        MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
 }
 
 
 /***********************************************************************
  *           MENU_SelectPrevItem
  */
-static void MENU_SelectPrevItem( HMENU hmenu )
+static void MENU_SelectPrevItem( HWND hwndOwner, HMENU hmenu )
 {
     int i;
     MENUITEM *items;
@@ -807,13 +809,13 @@
 	{
 	    if (!(items[i].item_flags & MF_SEPARATOR))
 	    {
-		MENU_SelectItem( hmenu, i );
+		MENU_SelectItem( hwndOwner, hmenu, i );
 		return;
 	    }
 	}
 	if (MENU_HasSysMenu( menu ))
 	{
-	    MENU_SelectItem( hmenu, SYSMENU_SELECTED );
+	    MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
 	    return;
 	}
     }
@@ -821,11 +823,12 @@
     {
 	if (!(items[i].item_flags & MF_SEPARATOR))
 	{
-	    MENU_SelectItem( hmenu, i );
+	    MENU_SelectItem( hwndOwner, hmenu, i );
 	    return;
 	}
     }
-    if (MENU_HasSysMenu( menu )) MENU_SelectItem( hmenu, SYSMENU_SELECTED );
+    if (MENU_HasSysMenu( menu ))
+        MENU_SelectItem( hwndOwner, hmenu, SYSMENU_SELECTED );
 }
 
 
@@ -856,7 +859,7 @@
  *
  * Hide the sub-popup menus of this menu.
  */
-static void MENU_HideSubPopups( HMENU hmenu )
+static void MENU_HideSubPopups( HWND hwndOwner, HMENU hmenu )
 {
     MENUITEM *item;
     POPUPMENU *menu, *submenu;
@@ -877,9 +880,9 @@
 	hsubmenu = item->item_id;
     }
     submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
-    MENU_HideSubPopups( hsubmenu );
+    MENU_HideSubPopups( hwndOwner, hsubmenu );
     if (submenu->hWnd) ShowWindow( submenu->hWnd, SW_HIDE );
-    MENU_SelectItem( hsubmenu, NO_SELECTED_ITEM );
+    MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM );
 }
 
 
@@ -902,7 +905,7 @@
     {
 	MENU_ShowPopup(hwndOwner, wndPtr->hSysMenu, 0, wndPtr->rectClient.left,
 		wndPtr->rectClient.top - menu->Height - 2*SYSMETRICS_CYBORDER);
-	if (selectFirst) MENU_SelectNextItem( wndPtr->hSysMenu );
+	if (selectFirst) MENU_SelectNextItem( hwndOwner, wndPtr->hSysMenu );
 	return wndPtr->hSysMenu;
     }
     item = ((MENUITEM *)USER_HEAP_LIN_ADDR(menu->hItems)) + menu->FocusedItem;
@@ -921,7 +924,7 @@
 		        wndPtr->rectWindow.left + item->rect.left,
 		        wndPtr->rectWindow.top + item->rect.bottom );
     }
-    if (selectFirst) MENU_SelectNextItem( (HMENU)item->item_id );
+    if (selectFirst) MENU_SelectNextItem( hwndOwner, (HMENU)item->item_id );
     return (HMENU)item->item_id;
 }
 
@@ -1027,7 +1030,7 @@
 	    {
 		if (menu->wFlags & MF_POPUP)
 		{
-		    MENU_HideSubPopups( hmenu );
+		    MENU_HideSubPopups( hwndOwner, hmenu );
 		    *hmenuCurrent = hmenu;
 		}
 		else return FALSE;
@@ -1037,8 +1040,8 @@
     }
     else
     {
-	MENU_HideSubPopups( hmenu );
-	MENU_SelectItem( hmenu, id );
+	MENU_HideSubPopups( hwndOwner, hmenu );
+	MENU_SelectItem( hwndOwner, hmenu, id );
 	*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
     }
     return TRUE;
@@ -1081,8 +1084,8 @@
 	hsubmenu = item->item_id;
     }
       /* Select first item of sub-popup */
-    MENU_SelectItem( hsubmenu, NO_SELECTED_ITEM );
-    MENU_SelectNextItem( hsubmenu );
+    MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM );
+    MENU_SelectNextItem( hwndOwner, hsubmenu );
     return TRUE;
 }
 
@@ -1113,12 +1116,12 @@
     }	
     if (id == NO_SELECTED_ITEM)
     {
-	MENU_SelectItem( *hmenuCurrent, NO_SELECTED_ITEM );
+	MENU_SelectItem( hwndOwner, *hmenuCurrent, NO_SELECTED_ITEM );
     }
     else if (menu->FocusedItem != id)
     {
-	MENU_HideSubPopups( hmenu );
-	MENU_SelectItem( hmenu, id );
+	MENU_HideSubPopups( hwndOwner, hmenu );
+	MENU_SelectItem( hwndOwner, hmenu, id );
 	*hmenuCurrent = MENU_ShowSubPopup( hwndOwner, hmenu, FALSE );
     }
     return TRUE;
@@ -1143,12 +1146,12 @@
 	hmenutmp = MENU_GetSubPopup( hmenuprev );
 	if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
     }
-    MENU_HideSubPopups( hmenuprev );
+    MENU_HideSubPopups( hwndOwner, hmenuprev );
 
     if ((hmenuprev == hmenu) && !(menu->wFlags & MF_POPUP))
     {
 	  /* Select previous item on the menu bar */
-	MENU_SelectPrevItem( hmenu );
+	MENU_SelectPrevItem( hwndOwner, hmenu );
 	if (*hmenuCurrent != hmenu)
 	{
 	      /* A popup menu was displayed -> display the next one */
@@ -1186,8 +1189,8 @@
       /* If on menu-bar, go to next item */
     if (!(menu->wFlags & MF_POPUP))
     {
-	MENU_HideSubPopups( hmenu );
-	MENU_SelectNextItem( hmenu );
+	MENU_HideSubPopups( hwndOwner, hmenu );
+	MENU_SelectNextItem( hwndOwner, hmenu );
 	if (*hmenuCurrent != hmenu)
 	{
 	      /* A popup menu was displayed -> display the next one */
@@ -1203,7 +1206,7 @@
 	    hmenutmp = MENU_GetSubPopup( hmenuprev );
 	    if (hmenutmp != *hmenuCurrent) hmenuprev = hmenutmp;
 	}
-	MENU_HideSubPopups( hmenuprev );
+	MENU_HideSubPopups( hwndOwner, hmenuprev );
 	*hmenuCurrent = hmenuprev;
     }
 }
@@ -1293,17 +1296,17 @@
 		switch(msg->wParam)
 		{
 		case VK_HOME:
-		    MENU_SelectItem( hmenuCurrent, NO_SELECTED_ITEM );
-		    MENU_SelectNextItem( hmenuCurrent );
+		    MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM );
+		    MENU_SelectNextItem( hwnd, hmenuCurrent );
 		    break;
 
 		case VK_END:
-		    MENU_SelectItem( hmenuCurrent, NO_SELECTED_ITEM );
-		    MENU_SelectPrevItem( hmenuCurrent );
+		    MENU_SelectItem( hwnd, hmenuCurrent, NO_SELECTED_ITEM );
+		    MENU_SelectPrevItem( hwnd, hmenuCurrent );
 		    break;
 
 		case VK_UP:
-		    MENU_SelectPrevItem( hmenuCurrent );
+		    MENU_SelectPrevItem( hwnd, hmenuCurrent );
 		    break;
 
 		case VK_DOWN:
@@ -1311,7 +1314,7 @@
 		    if (!(menu->wFlags & MF_POPUP) && (hmenuCurrent == hmenu))
 			hmenuCurrent = MENU_ShowSubPopup( hwnd, hmenu, TRUE );
 		    else
-			MENU_SelectNextItem( hmenuCurrent );
+			MENU_SelectNextItem( hwnd, hmenuCurrent );
 		    break;
 
 		case VK_LEFT:
@@ -1357,7 +1360,7 @@
 		    else if (pos == (WORD)-1) MessageBeep(0);
 		    else
 		    {
-			MENU_SelectItem( hmenuCurrent, pos );
+			MENU_SelectItem( hwnd, hmenuCurrent, pos );
 			fClosed = !MENU_ExecFocusedItem( hwnd, hmenuCurrent,
 							 &hmenuCurrent );
 			
@@ -1378,9 +1381,10 @@
     }
     USER_HEAP_FREE( hMsg );
     ReleaseCapture();
-    MENU_HideSubPopups( hmenu );
+    MENU_HideSubPopups( hwnd, hmenu );
     if (menu->wFlags & MF_POPUP) ShowWindow( menu->hWnd, SW_HIDE );
-    MENU_SelectItem( hmenu, NO_SELECTED_ITEM );
+    MENU_SelectItem( hwnd, hmenu, NO_SELECTED_ITEM );
+    SendMessage( hwnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
     fEndMenuCalled = FALSE;
     return TRUE;
 }
@@ -1412,8 +1416,8 @@
     if (!wndPtr->wIDmenu) return;
     SendMessage( hwnd, WM_ENTERMENULOOP, 0, 0 );
       /* Select first selectable item */
-    MENU_SelectItem( wndPtr->wIDmenu, NO_SELECTED_ITEM );
-    MENU_SelectNextItem( (HMENU)wndPtr->wIDmenu );
+    MENU_SelectItem( hwnd, wndPtr->wIDmenu, NO_SELECTED_ITEM );
+    MENU_SelectNextItem( hwnd, (HMENU)wndPtr->wIDmenu );
     MENU_TrackMenu( (HMENU)wndPtr->wIDmenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
 		    0, 0, hwnd, NULL );
     SendMessage( hwnd, WM_EXITMENULOOP, 0, 0 );
@@ -1595,8 +1599,8 @@
     if (!(lpitem = MENU_FindItem( &hMenu, &wItemID, wHilite ))) return FALSE;
     if (!(menu = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu))) return FALSE;
     if (menu->FocusedItem == wItemID) return TRUE;
-    MENU_HideSubPopups( hMenu );
-    MENU_SelectItem( hMenu, wItemID );
+    MENU_HideSubPopups( hWnd, hMenu );
+    MENU_SelectItem( hWnd, hMenu, wItemID );
     return TRUE;
 }
 
@@ -1957,16 +1961,13 @@
  */
 HMENU GetSystemMenu(HWND hWnd, BOOL bRevert)
 {
-	WND		*wndPtr;
-	wndPtr = WIN_FindWndPtr(hWnd);
-	if (!bRevert) {
-		return wndPtr->hSysMenu;
-		}
-	else {
-		DestroyMenu(wndPtr->hSysMenu);
-		wndPtr->hSysMenu = CopySysMenu();
-		}
-	return wndPtr->hSysMenu;
+    WND *wndPtr = WIN_FindWndPtr( hWnd );
+    if (!wndPtr) return 0;
+
+    if (!bRevert) return wndPtr->hSysMenu;
+    DestroyMenu(wndPtr->hSysMenu);
+    wndPtr->hSysMenu = CopySysMenu();
+    return wndPtr->hSysMenu;
 }
 
 /**********************************************************************
diff --git a/debugger/Makefile.in b/debugger/Makefile.in
index ed50f1b..75b0316 100644
--- a/debugger/Makefile.in
+++ b/debugger/Makefile.in
@@ -41,11 +41,12 @@
 
 clean:
 	(cd readline; $(MAKE) clean)
-	rm -f *.o \#*\# *~ dbg.tab.c dbg.tab.h lex.yy.c y.tab.c y.tab.h tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
+	rm -f dbg.tab.c dbg.tab.h lex.yy.c y.tab.c y.tab.h
 
 distclean:
 	(cd readline; $(MAKE) distclean)
-	rm -f *.o \#*\# *~ dbg.tab.c dbg.tab.h lex.yy.c y.tab.c y.tab.h tmp_make Makefile
+	rm -f *.o \#*\# *~ *.bak dbg.tab.c dbg.tab.h lex.yy.c y.tab.c y.tab.h tmp_make Makefile
 
 countryclean:
 
diff --git a/debugger/break.c b/debugger/break.c
index b237ce0..4406b2f 100644
--- a/debugger/break.c
+++ b/debugger/break.c
@@ -66,6 +66,71 @@
 
 
 /***********************************************************************
+ *           DEBUG_IsStepOverInstr
+ *
+ * Determine if the instruction at CS:EIP is an instruction that
+ * we need to step over (like a call or a repetitive string move).
+ */
+static BOOL DEBUG_IsStepOverInstr( struct sigcontext_struct *context )
+{
+    BYTE *instr = (BYTE *)PTR_SEG_OFF_TO_LIN(CS_reg(context),EIP_reg(context));
+
+    for (;;)
+    {
+        switch(*instr)
+        {
+          /* Skip all prefixes */
+
+        case 0x2e:  /* cs: */
+        case 0x36:  /* ss: */
+        case 0x3e:  /* ds: */
+        case 0x26:  /* es: */
+        case 0x64:  /* fs: */
+        case 0x65:  /* gs: */
+        case 0x66:  /* opcode size prefix */
+        case 0x67:  /* addr size prefix */
+        case 0xf0:  /* lock */
+        case 0xf2:  /* repne */
+        case 0xf3:  /* repe */
+            instr++;
+            continue;
+
+          /* Handle call instructions */
+
+        case 0xe8:  /* call <offset> */
+        case 0x9a:  /* lcall <seg>:<off> */
+            return TRUE;
+
+        case 0xff:  /* call <regmodrm> */
+            return (((instr[1] & 0x38) == 0x10) ||
+                    ((instr[1] & 0x38) == 0x18));
+
+          /* Handle string instructions */
+
+        case 0x6c:  /* insb */
+        case 0x6d:  /* insw */
+        case 0x6e:  /* outsb */
+        case 0x6f:  /* outsw */
+        case 0xa4:  /* movsb */
+        case 0xa5:  /* movsw */
+        case 0xa6:  /* cmpsb */
+        case 0xa7:  /* cmpsw */
+        case 0xaa:  /* stosb */
+        case 0xab:  /* stosw */
+        case 0xac:  /* lodsb */
+        case 0xad:  /* lodsw */
+        case 0xae:  /* scasb */
+        case 0xaf:  /* scasw */
+            return TRUE;
+
+        default:
+            return FALSE;
+        }
+    }
+}
+
+
+/***********************************************************************
  *           DEBUG_SetBreakpoints
  *
  * Set or remove all the breakpoints.
@@ -257,14 +322,18 @@
         break;
 
     case EXEC_STEP_OVER:  /* Stepping over a call */
-        EFL_reg(DEBUG_context) &= ~STEP_FLAG;
-        addr.off += instr_len;
-        breakpoints[0].addr    = addr;
-        breakpoints[0].enabled = TRUE;
-        breakpoints[0].in_use  = TRUE;
-        breakpoints[0].opcode  = *(BYTE *)DBG_ADDR_TO_LIN( &addr );
-        DEBUG_SetBreakpoints( TRUE );
-        break;
+        if (DEBUG_IsStepOverInstr(DEBUG_context))
+        {
+            EFL_reg(DEBUG_context) &= ~STEP_FLAG;
+            addr.off += instr_len;
+            breakpoints[0].addr    = addr;
+            breakpoints[0].enabled = TRUE;
+            breakpoints[0].in_use  = TRUE;
+            breakpoints[0].opcode  = *(BYTE *)DBG_ADDR_TO_LIN( &addr );
+            DEBUG_SetBreakpoints( TRUE );
+            break;
+        }
+        /* else fall through to single-stepping */
 
     case EXEC_STEP_INSTR: /* Single-stepping an instruction */
         EFL_reg(DEBUG_context) |= STEP_FLAG;
diff --git a/debugger/memory.c b/debugger/memory.c
index 80dfcd3..206e587 100644
--- a/debugger/memory.c
+++ b/debugger/memory.c
@@ -115,7 +115,7 @@
 		{
 			fprintf(stderr," %04x", *wdump++);
                         addr.off += 2;
-			if ((i % 10) == 7) {
+			if ((i % 8) == 7) {
 				fprintf(stderr,"\n");
 				DEBUG_PrintAddress( &addr, dbg_mode );
 				fprintf(stderr,":  ");
@@ -133,7 +133,7 @@
 			} else
 				fprintf(stderr," %c", *pnt++);
                         addr.off++;
-			if ((i % 32) == 7) {
+			if ((i % 32) == 31) {
 				fprintf(stderr,"\n");
 				DEBUG_PrintAddress( &addr, dbg_mode );
 				fprintf(stderr,":  ");
@@ -147,7 +147,7 @@
 		{
 			fprintf(stderr," %02x", (*pnt++) & 0xff);
                         addr.off++;
-			if ((i % 32) == 7) {
+			if ((i % 16) == 15) {
 				fprintf(stderr,"\n");
 				DEBUG_PrintAddress( &addr, dbg_mode );
 				fprintf(stderr,":  ");
diff --git a/debugger/readline/Makefile.in b/debugger/readline/Makefile.in
index 5f32753..873f3d2 100644
--- a/debugger/readline/Makefile.in
+++ b/debugger/readline/Makefile.in
@@ -1,11 +1,12 @@
 CC 	= @CC@
 CFLAGS 	= @CFLAGS@
+DEFS    = @DEFS@
 XINCL 	= @x_includes@
 TOPSRC  = @top_srcdir@
 DIVINCL = -I$(TOPSRC)/include
 LD	= @LD@
 LDCOMBINEFLAGS = @LDCOMBINEFLAGS@
-DIVDEFS	= @DEFS@ -DHIDE -DANSI_ARROWS
+DIVDEFS	= $(DEFS) -DHIDE -DANSI_ARROWS
 
 
 MODULE 	= readline
@@ -28,7 +29,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/debugger/readline/sysunix.c b/debugger/readline/sysunix.c
index fdc8d2d..010744e1 100644
--- a/debugger/readline/sysunix.c
+++ b/debugger/readline/sysunix.c
@@ -4,10 +4,6 @@
 */
 #include "editline.h"
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #if	defined(HAVE_TCGETATTR)
 #include <termios.h>
 
diff --git a/if1632/Makefile.in b/if1632/Makefile.in
index 225d5fb..4eab62c 100644
--- a/if1632/Makefile.in
+++ b/if1632/Makefile.in
@@ -24,7 +24,8 @@
 
 OBJS = $(SRCS:.c=.o) $(DLLS16:.spec=.o) $(DLLS32:.spec=.o) call16.o call32.o
 
-SFILES = $(DLLS16:.spec=.S)
+SPEC16_FILES = $(DLLS16:.spec=.S)
+SPEC32_FILES = $(DLLS32:.spec=.c)
 
 .SUFFIXES: .spec
 
@@ -42,16 +43,16 @@
 
 all: checkbuild $(MODULE).o
 
-$(SFILES): $(TOPSRC)/tools/build
+$(SPEC16_FILES) $(SPEC32_FILES): $(TOPSRC)/tools/build
 
 checkbuild:
 	cd $(TOPSRC)/tools; $(MAKE) 'CC=$(CC)' 'CFLAGS=$(CFLAGS)' 'LD=$(LD)' 'LDCOMBINEFLAGS=$(LDCOMBINEFLAGS)' build
 
-call16.S: $(TOPSRC)/include/callback.h
-	$(TOPSRC)/tools/build -call16 `cat $(TOPSRC)/include/callback.h | grep "extern.*CallTo16_" | sed 's/.*CallTo16_\(.*\)(.*/\1/' | sort | uniq` > call16.S
+call16.S: $(TOPSRC)/include/callback.h $(BUILD)
+	$(BUILD) -call16 `cat $(TOPSRC)/include/callback.h | grep "extern.*CallTo16_" | sed 's/.*CallTo16_\(.*\)(.*/\1/' | sort | uniq` > call16.S
 
-call32.S: $(SFILES)
-	$(BUILD) -call32 `cat $(SFILES) | grep CallTo32_ | sed 's/.*CallTo32_\(.*\)/\1/' | sort | uniq` > call32.S
+call32.S: $(SPEC16_FILES)
+	$(BUILD) -call32 `cat $(SPEC16_FILES) | grep CallTo32_ | sed 's/.*CallTo32_\(.*\)/\1/' | sort | uniq` > call32.S
 
 $(MODULE).o: $(OBJS)
 	$(LD) $(LDCOMBINEFLAGS) $(OBJS) -o $(MODULE).o
@@ -62,7 +63,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 	rm -f $(DLLS16:.spec=.S) $(DLLS32:.spec=.c) call32.S call16.S
 
 distclean: clean
diff --git a/if1632/gdi.spec b/if1632/gdi.spec
index 7b302ad..784ad66 100644
--- a/if1632/gdi.spec
+++ b/if1632/gdi.spec
@@ -245,7 +245,7 @@
 380 stub ENDPAGE
 381 stub SETABORTPROC
 382 stub ABORTDOC
-400 stub FASTWINDOWFRAME
+400 pascal16 FastWindowFrame(word long word word long) FastWindowFrame
 401 stub GDIMOVEBITMAP
 403 stub GDIINIT2
 405 stub FINALGDIINIT
diff --git a/if1632/kernel.spec b/if1632/kernel.spec
index a08132b..78815bf 100644
--- a/if1632/kernel.spec
+++ b/if1632/kernel.spec
@@ -232,7 +232,7 @@
 #351 BUNNY_351
 353 pascal lstrcpyn(segptr segptr word) lstrcpyn
 354 stub GetAppCompatFlags
-355 stub GetWinDebugInfo
-356 stub SetWinDebugInfo
+355 pascal16 GetWinDebugInfo(ptr word) GetWinDebugInfo
+356 pascal16 SetWinDebugInfo(ptr) SetWinDebugInfo
 403 pascal16 FarSetOwner(word word) FarSetOwner
 404 pascal16 FarGetOwner(word) FarGetOwner
diff --git a/if1632/pop.h b/if1632/pop.h
deleted file mode 100644
index 3694b33..0000000
--- a/if1632/pop.h
+++ /dev/null
@@ -1,18 +0,0 @@
-	add	$8,%esp
-	popw	%es
-	add	$2,%esp
-	popw	%ds
-	add	$2,%esp
-	popl	%edi
-	popl	%esi
-	popl	%ebp
-	add	$4,%esp
-	popl	%ebx
-	popl	%edx
-	popl	%ecx
-	popl	%eax
-	add	$16,%esp
-	popl	%gs:return_value
-	add	$20,%esp
-	pushl	%gs:return_value
-	popfl
diff --git a/include/atom.h b/include/atom.h
index 706b709..5988a5b 100644
--- a/include/atom.h
+++ b/include/atom.h
@@ -25,10 +25,4 @@
     HANDLE      entries[1];
 } ATOMTABLE;
 
-
-ATOM LocalAddAtom( SEGPTR str );
-ATOM LocalDeleteAtom( ATOM atom );
-ATOM LocalFindAtom( SEGPTR str );
-WORD LocalGetAtomName( ATOM atom, LPSTR buffer, short count );
-
 #endif  /* ATOM_H */
diff --git a/include/bitmaps/obm_close_95 b/include/bitmaps/obm_close_95
new file mode 100644
index 0000000..eeb1760
--- /dev/null
+++ b/include/bitmaps/obm_close_95
@@ -0,0 +1,23 @@
+/* XPM */
+static char * obm_close_95[] = {
+"16 14 6 1",
+" 	s button_highlight	c white",
+"+	s button_edge	c grey85",
+"X	s button_face	c grey75",
+"o	s button_shadow c grey50",
+".	s button_text	c black",
+"O	s window_frame	c black",
+"               O",
+" +++++++++++++oO",
+" +XXXXXXXXXXXXoO",
+" +XX..XXXX..XXoO",
+" +XXX..XX..XXXoO",
+" +XXXX....XXXXoO",
+" +XXXXX..XXXXXoO",
+" +XXXX....XXXXoO",
+" +XXX..XX..XXXoO",
+" +XX..XXXX..XXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" ooooooooooooooO",
+"OOOOOOOOOOOOOOOO"};
diff --git a/include/bitmaps/obm_closed_95 b/include/bitmaps/obm_closed_95
new file mode 100644
index 0000000..090e9d7
--- /dev/null
+++ b/include/bitmaps/obm_closed_95
@@ -0,0 +1,23 @@
+/* XPM */
+static char * obm_closed_95[] = {
+"16 14 6 1",
+" 	s button_highlight	c white",
+"+	s button_edge	c grey85",
+"X	s button_face	c grey75",
+"o	s button_shadow c grey50",
+".	s button_text	c black",
+"O	s window_frame	c black",
+"OOOOOOOOOOOOOOO ",
+"Oooooooooooooo+ ",
+"OoXXXXXXXXXXXX+ ",
+"OoXXXXXXXXXXXX+ ",
+"OoXXX..XXXX..X+ ",
+"OoXXXX..XX..XX+ ",
+"OoXXXXX....XXX+ ",
+"OoXXXXXX..XXXX+ ",
+"OoXXXXX....XXX+ ",
+"OoXXXX..XX..XX+ ",
+"OoXXX..XXXX..X+ ",
+"OoXXXXXXXXXXXX+ ",
+"O++++++++++++++ ",
+"                "};
diff --git a/include/bitmaps/obm_reduce_95 b/include/bitmaps/obm_reduce_95
new file mode 100644
index 0000000..b32531d
--- /dev/null
+++ b/include/bitmaps/obm_reduce_95
@@ -0,0 +1,23 @@
+/* XPM */
+static char * obm_reduce_95[] = {
+"16 14 6 1",
+" 	s button_highlight	c white",
+"+	s button_edge	c grey85",
+"X	s button_face	c grey75",
+"o	s button_shadow	c grey50",
+".	s button_text	c black",
+"O	s window_frame	c black",
+"               O",
+" +++++++++++++oO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XX......XXXXoO",
+" +XX......XXXXoO",
+" +XXXXXXXXXXXXoO",
+" ooooooooooooooO",
+"OOOOOOOOOOOOOOOO"};
diff --git a/include/bitmaps/obm_reduced_95 b/include/bitmaps/obm_reduced_95
new file mode 100644
index 0000000..4199248
--- /dev/null
+++ b/include/bitmaps/obm_reduced_95
@@ -0,0 +1,23 @@
+/* XPM */
+static char * obm_reduced_95[] = {
+"16 14 6 1",
+"O	s button_highlight	c white",
+"o	s button_edge	c grey85",
+"X	s button_face	c grey75",
+"+	s button_shadow	c grey50",
+".	s button_text	c black",
+" 	s window_frame	c black",
+"                ",
+" +++++++++++++oO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXXXXXXXXXXXoO",
+" +XXX......XXXoO",
+" +XXX......XXXoO",
+" ooooooooooooooO",
+"OOOOOOOOOOOOOOOO"};
diff --git a/include/bitmaps/obm_zoom_95 b/include/bitmaps/obm_zoom_95
new file mode 100644
index 0000000..81c937a
--- /dev/null
+++ b/include/bitmaps/obm_zoom_95
@@ -0,0 +1,23 @@
+/* XPM */
+static char * obm_zoom_95[] = {
+"16 14 6 1",
+" 	s button_highlight	c white",
+"+	s button_edge	c grey85",
+"X	s button_face	c grey75",
+"o	s button_shadow	c grey50",
+".	s button_text	c black",
+"O	s window_frame	c black",
+"               O",
+" +++++++++++++oO",
+" +X.........XXoO",
+" +X.........XXoO",
+" +X.XXXXXXX.XXoO",
+" +X.XXXXXXX.XXoO",
+" +X.XXXXXXX.XXoO",
+" +X.XXXXXXX.XXoO",
+" +X.XXXXXXX.XXoO",
+" +X.XXXXXXX.XXoO",
+" +X.........XXoO",
+" +XXXXXXXXXXXXoO",
+" ooooooooooooooO",
+"OOOOOOOOOOOOOOOO"};
diff --git a/include/bitmaps/obm_zoomd_95 b/include/bitmaps/obm_zoomd_95
new file mode 100644
index 0000000..6a15a8c
--- /dev/null
+++ b/include/bitmaps/obm_zoomd_95
@@ -0,0 +1,23 @@
+/* XPM */
+static char * obm_zoomd_95[] = {
+"16 14 6 1",
+"O	s button_highlight	c white",
+"o	s button_edge	c grey85",
+"X	s button_face	c grey75",
+"+	s button_shadow	c grey50",
+".	s button_text	c black",
+" 	s window_frame	c black",
+"                ",
+" +++++++++++++oO",
+" +XXXXXXXXXXXXoO",
+" +XX.........XoO",
+" +XX.........XoO",
+" +XX.XXXXXXX.XoO",
+" +XX.XXXXXXX.XoO",
+" +XX.XXXXXXX.XoO",
+" +XX.XXXXXXX.XoO",
+" +XX.XXXXXXX.XoO",
+" +XX.XXXXXXX.XoO",
+" +XX.........XoO",
+" ooooooooooooooO",
+"OOOOOOOOOOOOOOOO"};
diff --git a/include/dde_atom.h b/include/dde_atom.h
index 56df6b7..62b50ff 100644
--- a/include/dde_atom.h
+++ b/include/dde_atom.h
@@ -9,15 +9,20 @@
  */
 #ifndef __WINE_DDE_ATOM_H
 #define __WINE_DDE_ATOM_H
+
+#ifdef CONFIG_IPC
+
 #include "windows.h"
 
 #define DDE_ATOMS 157		   /* a prime number for hashing */
 
 void ATOM_GlobalInit(void);
-/*
-ATOM GlobalAddAtom( LPCSTR str );
-ATOM GlobalDeleteAtom( ATOM atom );
-ATOM GlobalFindAtom( LPCSTR str );
-WORD GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
-*/
+
+ATOM DDE_GlobalAddAtom( SEGPTR str );
+ATOM DDE_GlobalDeleteAtom( ATOM atom );
+ATOM DDE_GlobalFindAtom( SEGPTR str );
+WORD DDE_GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
+
+#endif  /* CONFIG_IPC */
+
 #endif __WINE_DDE_ATOM_H
diff --git a/include/dde_mem.h b/include/dde_mem.h
index 6a830e1..3bc8dfa 100644
--- a/include/dde_mem.h
+++ b/include/dde_mem.h
@@ -9,6 +9,9 @@
  */
 #ifndef __WINE_DDE_MEM_H
 #define __WINE_DDE_MEM_H
+
+#ifdef CONFIG_IPC
+
 #include "wintypes.h"
 #include "global.h"
 #include "shm_block.h"
@@ -31,4 +34,6 @@
 HANDLE DDE_GlobalHandle(WORD);
 HANDLE DDE_GlobalFlags(WORD);
 
+#endif  /* CONFIG_IPC */
+
 #endif /* __WINE_DDE_MEM_H */
diff --git a/include/dde_proc.h b/include/dde_proc.h
index 85e682a..011d389 100644
--- a/include/dde_proc.h
+++ b/include/dde_proc.h
@@ -9,6 +9,9 @@
  */
 #ifndef __WINE_DDE_PROC_H
 #define __WINE_DDE_PROC_H
+
+#ifdef CONFIG_IPC
+
 #include <setjmp.h>
 #include "wintypes.h"
 #include "windows.h"
@@ -54,4 +57,7 @@
 int DDE_GetRemoteMessage();
 void DDE_DestroyWindow(HWND hwnd); /* delete DDE info regarding hwnd */
 void DDE_TestDDE(HWND hwnd);	   /* do we have dde handling in the window ?*/
+
+#endif  /* CONFIG_IPC */
+
 #endif /* __WINE_DDE_PROC_H */
diff --git a/include/miscemu.h b/include/miscemu.h
index 2309274..bf2b007 100644
--- a/include/miscemu.h
+++ b/include/miscemu.h
@@ -1,20 +1,39 @@
+/*
+ * Misc. emulation definitions
+ *
+ * Copyright 1995 Alexandre Julliard
+ */
+
 #ifndef __WINE_MISCEMU_H
 #define __WINE_MISCEMU_H
 
 #include "wintypes.h"
 #include "registers.h"
 
+
+  /* miscemu/dosmem.c */
+extern BOOL DOSMEM_Init(void);
+extern void DOSMEM_FillBiosSegment(void);
+extern HANDLE DOSMEM_BiosSeg;
+
+  /* miscemu/instr.c */
 extern BOOL INSTR_EmulateInstruction( struct sigcontext_struct *context );
 
-extern DWORD inport( int port, int count );
-extern void outport( int port, int count, DWORD value );
-
+  /* miscemu/interrupts.c */
 extern BOOL INT_Init(void);
 extern SEGPTR INT_GetHandler( BYTE intnum );
 extern void INT_SetHandler( BYTE intnum, SEGPTR handler );
 
+  /* miscemu/int1a.c */
+extern DWORD INT1A_GetTicksSinceMidnight(void);
+
+  /* miscemu/int21.c */
 extern void INT21_Init(void);
 
+  /* miscemu/ioports.c */
+extern DWORD inport( int port, int count );
+extern void outport( int port, int count, DWORD value );
+
 
 #define INT_BARF(context,num) \
     fprintf( stderr, "int%x: unknown/not implemented parameters:\n" \
diff --git a/include/shm_block.h b/include/shm_block.h
index c19c84f..e8612d2 100644
--- a/include/shm_block.h
+++ b/include/shm_block.h
@@ -9,6 +9,9 @@
  */
 #ifndef __WINE_SHM_BLOCK_H
 #define __WINE_SHM_BLOCK_H
+
+#ifdef CONFIG_IPC
+
 #include <sys/shm.h>
 #include "wintypes.h"
 #define SEGSIZE                 0x10000 /* 64 */ 
@@ -83,4 +86,5 @@
 /* delete chain of shm blocks (pointing to each other */
 void shm_delete_chain(int *shmid);
 
-#endif /* __WINE_SHM_BLOCK_H */
+#endif  /* CONFIG_IPC */
+#endif  /* __WINE_SHM_BLOCK_H */
diff --git a/include/shm_fragment.h b/include/shm_fragment.h
index 81a4b66..893aee7 100644
--- a/include/shm_fragment.h
+++ b/include/shm_fragment.h
@@ -10,6 +10,8 @@
 #ifndef __WINE_SHM_FRAGMENT_H
 #define __WINE_SHM_FRAGMENT_H
 
+#ifdef CONFIG_IPC
+
 #include "shm_block.h"
 
 #define NIL ((int) 0)
@@ -44,4 +46,6 @@
 /* This is used for debugging only */
 void shm_print_free_list(struct shm_block *block);
 
+#endif  /* CONFIG_IPC */
+
 #endif /* __WINE_SHM_FRAGMENT_H */
diff --git a/include/shm_main_blk.h b/include/shm_main_blk.h
index e3f9e5b..4076bcf 100644
--- a/include/shm_main_blk.h
+++ b/include/shm_main_blk.h
@@ -9,6 +9,9 @@
  */
 #ifndef __WINE_SHM_MAIN_BLK_H
 #define __WINE_SHM_MAIN_BLK_H
+
+#ifdef CONFIG_IPC
+
 #include <sys/shm.h>
 #include "shm_block.h"
 #include "shm_semaph.h"
@@ -52,4 +55,6 @@
 int DDE_no_of_attached();
 #define DDE_IPC_init()  ( (main_block==NULL) ?  (DDE_mem_init()) : 0 )
 
+#endif  /* CONFIG_IPC */
+
 #endif /* __WINE_SHM_MAIN_BLK_H */
diff --git a/include/shm_semaph.h b/include/shm_semaph.h
index 5562446..62852f0 100644
--- a/include/shm_semaph.h
+++ b/include/shm_semaph.h
@@ -12,6 +12,8 @@
 #define __WINE_SHM_SEMAPH_H
 /* IMPORTANT: If possible, restrict usage of these functions. */
 
+#ifdef CONFIG_IPC
+
 typedef int shm_sem;
 
 void shm_read_wait(shm_sem semid);
@@ -21,4 +23,6 @@
 void shm_sem_init(shm_sem *semptr);
 void shm_sem_done(shm_sem *semptr);
 
+#endif  /* CONFIG_IPC */
+
 #endif /* __WINE_SHM_SEMAPH_H */
diff --git a/include/sysmetrics.h b/include/sysmetrics.h
index f9e73e7..11e08b4 100644
--- a/include/sysmetrics.h
+++ b/include/sysmetrics.h
@@ -11,30 +11,56 @@
 
 
   /* Constant system metrics */
+#ifdef WIN_95_LOOK
+#define SYSMETRICS_CXVSCROLL         14
+#define SYSMETRICS_CYHSCROLL         14
+#else
 #define SYSMETRICS_CXVSCROLL         16
 #define SYSMETRICS_CYHSCROLL         16
+#endif
 #define SYSMETRICS_CYCAPTION         20
 #define SYSMETRICS_CXBORDER           1
 #define SYSMETRICS_CYBORDER           1
+#ifdef WIN_95_LOOK
+#define SYSMETRICS_CXDLGFRAME         2
+#define SYSMETRICS_CYDLGFRAME         2
+#define SYSMETRICS_CYVTHUMB          13
+#define SYSMETRICS_CXHTHUMB          13
+#else
 #define SYSMETRICS_CXDLGFRAME         4
 #define SYSMETRICS_CYDLGFRAME         4
 #define SYSMETRICS_CYVTHUMB          16
 #define SYSMETRICS_CXHTHUMB          16
+#endif
 #define SYSMETRICS_CXICON            32
 #define SYSMETRICS_CYICON            32
 #define SYSMETRICS_CXCURSOR          32
 #define SYSMETRICS_CYCURSOR          32
 #define SYSMETRICS_CYMENU            18
+#ifdef WIN_95_LOOK
+#define SYSMETRICS_CYVSCROLL         14
+#define SYSMETRICS_CXHSCROLL         14
+#define SYSMETRICS_CXMIN            112
+#define SYSMETRICS_CYMIN             27
+#else
 #define SYSMETRICS_CYVSCROLL         16
 #define SYSMETRICS_CXHSCROLL         16
 #define SYSMETRICS_CXMIN            100
 #define SYSMETRICS_CYMIN             28
+#endif
 #define SYSMETRICS_CXSIZE            18
 #define SYSMETRICS_CYSIZE            18
+#ifdef WIN_95_LOOK
+#define SYSMETRICS_CXMINTRACK       112
+#define SYSMETRICS_CYMINTRACK        27
+#define SYSMETRICS_CXICONSPACING     75
+#define SYSMETRICS_CYICONSPACING     75
+#else
 #define SYSMETRICS_CXMINTRACK       100
 #define SYSMETRICS_CYMINTRACK        28
 #define SYSMETRICS_CXICONSPACING     20
 #define SYSMETRICS_CYICONSPACING     20
+#endif
 
   /* Some non-constant system metrics */
 #define SYSMETRICS_CXSCREEN            sysMetrics[SM_CXSCREEN]
diff --git a/include/windows.h b/include/windows.h
index 61a7618..105237f 100644
--- a/include/windows.h
+++ b/include/windows.h
@@ -2318,6 +2318,56 @@
 #define META_CREATEBITMAP            0x06FE
 #define META_CREATEREGION            0x06FF
 
+/* Debugging support (DEBUG SYSTEM ONLY) */
+typedef struct tagWINDEBUGINFO
+{
+    UINT    flags;
+    DWORD   dwOptions;
+    DWORD   dwFilter;
+    char    achAllocModule[8];
+    DWORD   dwAllocBreak;
+    DWORD   dwAllocCount;
+} WINDEBUGINFO;
+typedef WINDEBUGINFO FAR* LPWINDEBUGINFO;
+
+/* WINDEBUGINFO flags values */
+#define WDI_OPTIONS         0x0001
+#define WDI_FILTER          0x0002
+#define WDI_ALLOCBREAK      0x0004
+
+/* dwOptions values */
+#define DBO_CHECKHEAP       0x0001
+#define DBO_BUFFERFILL      0x0004
+#define DBO_DISABLEGPTRAPPING 0x0010
+#define DBO_CHECKFREE       0x0020
+
+#define DBO_SILENT          0x8000
+
+#define DBO_TRACEBREAK      0x2000
+#define DBO_WARNINGBREAK    0x1000
+#define DBO_NOERRORBREAK    0x0800
+#define DBO_NOFATALBREAK    0x0400
+#define DBO_INT3BREAK       0x0100
+
+/* DebugOutput flags values */
+#define DBF_TRACE           0x0000
+#define DBF_WARNING         0x4000
+#define DBF_ERROR           0x8000
+#define DBF_FATAL           0xc000
+
+/* dwFilter values */
+#define DBF_KERNEL          0x1000
+#define DBF_KRN_MEMMAN      0x0001
+#define DBF_KRN_LOADMODULE  0x0002
+#define DBF_KRN_SEGMENTLOAD 0x0004
+#define DBF_USER            0x0800
+#define DBF_GDI             0x0400
+#define DBF_MMSYSTEM        0x0040
+#define DBF_PENWIN          0x0020
+#define DBF_APPLICATION     0x0008
+#define DBF_DRIVER          0x0010
+
+
 #ifndef WINELIB
 #pragma pack(4)
 #endif
@@ -2439,6 +2489,7 @@
 Fa(BOOL,SetDeskWallPaper,LPSTR,a)
 Fa(BOOL,SetErrorMode,WORD,a)
 Fa(BOOL,SetMessageQueue,int,a)
+Fa(BOOL,SetWinDebugInfo,LPWINDEBUGINFO,a)
 Fa(BOOL,SwapMouseButton,BOOL,a)
 Fa(BOOL,TranslateMessage,LPMSG,a)
 Fa(BOOL,UnhookWindowsHookEx,HHOOK,a)
@@ -2623,6 +2674,7 @@
 Fb(BOOL,GetTextMetrics,HDC,a,LPTEXTMETRIC,b)
 Fb(BOOL,GetViewportExtEx,HDC,a,LPPOINT,b)
 Fb(BOOL,GetViewportOrgEx,HDC,a,LPPOINT,b)
+Fb(BOOL,GetWinDebugInfo,LPWINDEBUGINFO,a,UINT,b)
 Fb(BOOL,GetWindowExtEx,HDC,a,LPPOINT,b)
 Fb(BOOL,GetWindowOrgEx,HDC,a,LPPOINT,b)
 Fb(BOOL,GetWindowPlacement,HWND,a,LPWINDOWPLACEMENT,b)
diff --git a/include/winsock.h b/include/winsock.h
index a0450c2..63e92bb 100644
--- a/include/winsock.h
+++ b/include/winsock.h
@@ -174,7 +174,7 @@
  * compatibility purposes.
  */
 
-#define h_errno         WSAGetLastError()
+/* #define h_errno         WSAGetLastError() */
 
 /* Authoritative Answer: Host not found */
 #define WSAHOST_NOT_FOUND       (WSABASEERR+1001)
diff --git a/ipc/Imakefile b/ipc/Imakefile
index cf5d6df..e9e82a1 100644
--- a/ipc/Imakefile
+++ b/ipc/Imakefile
@@ -2,32 +2,36 @@
 
 MODULE = ipc
 
-TEST_SRCS =  \
-          shm_fragment_test.c \
-          bit_array_test.c\
-          dde_proc_test.c \
-          dde_atom_test.c \
-          shm_semaph_test.c \
-          wine_test_stub.c \
-          hash_test.c \
-          dde_mem_test.c 
-
 SRCS =    bit_array.c \
-	  dde_atom.c  \
-	  dde_mem.c \
           dde_proc.c  \
-          generic_hash.c \
-          shm_block.c \
-          shm_fragment.c \
           shm_main_blk.c \
-          shm_semaph.c
+	  dde_atom.c  \
+          shm_semaph.c \
+	  dde_mem.c \
+          shm_block.c \
+          shm_fragment.c
 
 OBJS = $(SRCS:.c=.o)
-TEST_OBJS = $(TEST_SRCS:.c=.o)
+
+SHM_OBJ=shm_block.o shm_semaph.o shm_main_blk.o dde_proc.o \
+               	   dde_mem.o bit_array.o shm_fragment.o wine_test_stub.o
+
 
 WineRelocatableTarget($(MODULE),,$(OBJS))
+
 DependTarget()
 
+tests:: dde_mem_test dde_proc_test dde_atom_test shm_fragment_test \
+        shm_semaph_test
+
+NormalProgramTarget(bit_array_test, bit_array.o bit_array_test.o,,,)
+NormalProgramTarget(shm_semaph_test, shm_semaph_test.o shm_semaph.o,,,)
+NormalProgramTarget(shm_fragment_test, shm_fragment_test.o shm_fragment.o,,,)
+NormalProgramTarget(dde_atom_test, dde_atom_test.o dde_atom.o $(SHM_OBJ),,,)
+NormalProgramTarget(dde_mem_test, dde_mem_test.o $(SHM_OBJ),,,)
+NormalProgramTarget(dde_proc_test, dde_proc_test.o $(SHM_OBJ) ,,,)
+
+
 includes::
 
 install::
diff --git a/ipc/Makefile.in b/ipc/Makefile.in
index fd2dfae..811f2b4 100644
--- a/ipc/Makefile.in
+++ b/ipc/Makefile.in
@@ -35,7 +35,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/ipc/README b/ipc/README
index 6903f53..c004de8 100644
--- a/ipc/README
+++ b/ipc/README
@@ -1,8 +1,34 @@
-This is a pre-alpha code, it does not work for 100%,
-but it does not break anything (I hope).
-Proper documentation (LaTeX) will be ready for the next release.
+               Technion- Israel Institute of Technology
+                 Electrical Engineering software lab.
 
-You can use "ipcl" perl script to remove junk IPC stuff.
-You can use "ipcs" system program to find junk IPC stuff.
 
-Michael
+		 
+	Author : Michael Veksler 11678223
+	
+	Tutor:   Avner Lottem
+
+	
+DDE support for Wine
+====================
+
+Wine emulator is able to run MS-Windows 3.1 applications under Linux
+(Linux is a UNIX clone) . Wine is also a toolkit allowing MS-Windows
+applications to compile under Linux. Wine is a world-wide Internet
+project with more than 20 developers. Wine is still under development
+so many vital MS-Windows features are still missing.
+
+DDE is Dynamic Data Exchange used for communication between MS-Windows
+applications. This project adds DDE capabilities into Wine. The new
+improved Wine will be able to send messages and share memory between
+two different Wine processes.
+
+This project uses System-V IPC mechanisms to implement DDE.
+
+Besides sharing memory handles and sending DDE messages, Wine processes 
+are synchronize to emulates MS-Windows non-preemptive task switching.
+(MS-Windows switches tasks only on given instructions). This is done
+without hurting the performance or stability of a single Wine process.
+
+The project adds DDE to Wine emulator and to the toolkit. This allows
+old MS-Windows applications to be compiled for UNIX, and have DDE
+working among them. 
diff --git a/ipc/bit_array.c b/ipc/bit_array.c
index 14d72e9..6873c82 100644
--- a/ipc/bit_array.c
+++ b/ipc/bit_array.c
@@ -14,13 +14,15 @@
  ***************************************************************************
  */
 
+#ifdef CONFIG_IPC
+
 /*
 ** uncoment the following line to disable assertions,
 ** this may boost performance by up to 50%
 */
 /* #define NDEBUG */
 
-#ifndef NO_ASM
+#if defined(linux) && !defined(NO_ASM)
 #define HAS_BITOPS
 #endif
 
@@ -275,3 +277,5 @@
 
   return bit_nr;
 }
+
+#endif  /* CONFIG_IPC */
diff --git a/ipc/dde.tex b/ipc/dde.tex
new file mode 100644
index 0000000..ef4e1ff
--- /dev/null
+++ b/ipc/dde.tex
@@ -0,0 +1,962 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Written by Michael Veksler.
+%% May be freely redistributed as long as this header is unchanged.
+%% The file be modified as long as there will be appropriate comment
+%% containing the Author and a description.
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\documentstyle{article}
+\renewcommand{\thepage}{}
+\newcommand{\Wine}{Wine}
+\newcommand{\WINE}{{\em WINdows Emulator}}
+\newcommand{\DDE}{{\em Dynamic Data Exchange}}
+\newcommand{\windoz}{MS-Win\-dows}
+\newcommand{\fname}[1]{{\tt #1}}
+\newcommand{\libwine}{\fname{libwine.a}}
+\title{DDE\footnote{DDE is \DDE\ mechanism provided by \windoz.
+    (Appendix~\protect\ref{sec:DDE}).
+    }
+  \ capability for \Wine\footnote{\Wine\ (\WINE) Runs \windoz\
+    programs under UNIX\@. (Appendix~\protect\ref{sec:Wine}).
+    }
+}
+\author{Michael Veksler 11678223}
+%%\date{Aug 6, 1995}
+\begin{document}
+\maketitle
+\vfill
+\abstract{\Wine{} provides an environment for running or compiling
+  \windoz{} applications for UNIX clones (such as Linux).
+  \Wine{} is not yet finished and lacks many basic important features.
+  One of the missing features is DDE\@. DDE implementation
+  (especially for \libwine) requires
+  UNIX IPC\footnote{IPC - Inter-Process Communication}. This Project
+  introduces the IPC mechanism into \Wine{}, thus allowing DDE to work
+  between different \Wine{} processes.}
+
+
+\vfill
+{\LARGE
+  \begin{itemize}
+    \item[Instructor:] Avner Lottem
+    \item[Done for:] Technion- Israel Institute of Technology,\\
+      Electrical Engineering software lab$^{\mbox{\small\copyright}}$.
+  \end{itemize}
+  }
+\vfill
+
+\newpage
+\renewcommand{\thepage}{\roman{page}}
+\setcounter{page}{1}
+\begin{center}
+    {\LARGE Table Of Contents}
+\end{center}
+\tableofcontents
+
+\newpage
+\renewcommand{\thepage}{\arabic{page}}
+\setcounter{page}{1}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% end of title
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section{Introduction}
+
+\subsection{The project}
+The purpose of the project is to add DDE capabilities into \Wine.
+The project enables \Wine{} DDE client-server applications communication.
+This involved messing around with:
+\begin{itemize}
+  \item \windoz\ message mechanism.
+  \item \windoz\ memory management.
+  \item \windoz\ task management.
+  \item UNIX messages among  \Wine\ processes.
+  \item Exchanging (sharing) UNIX memory.
+\end{itemize}
+
+\subsection{Problem description}
+DDE is essentially a communication protocol between \windoz\
+tasks. Implementing this protocol requires communication among
+\Wine{} processes and among tasks in one process (each \Wine{} process
+can contain several tasks). Since \Wine\ already provides
+communication among internal tasks, this project provides communication
+between \Wine\ processes. 
+
+Different \Wine\ processes should be able to send \windoz\ messages
+and to pass \windoz\ memory handles. There also has to be a
+synchronization mechanism between the processes (\windoz\ applications
+make assumptions about task switching - and don't use semaphores, or
+any \windoz\ equivalent).
+
+Passing messages is a bit tricky. \windoz\ gives a feedback about the
+success of a message (fails if the window does not exist).
+In case of SendMessage (see Appendix~\ref{sec:WindozMsg}), the process
+will have to halt until the message has been processed.
+In case of PostMessage, things are simpler - only the existence of the
+recipient has to be checked.
+
+\windoz\ switches tasks only when certain system calls are used (such
+as delivering or polling messages). \windoz\ applications rely on this
+behavior. The problem arises when two applications run on different
+\Wine\ processes. Since UNIX preempts processes there is no guaranty
+that the UNIX task will occur at the correct place (in respect of the
+application).
+One one hand is the need for compatibility (no UNIX ``current''
+execution), and on the other hand is performance and stability.
+
+Another problem is passing handles between \Wine\ processes. \windoz\
+applications pass atoms\footnote{See appendix~\ref{sec:WhatAreAtoms}},
+memory handles and window handles. These handles have to be allocated
+globally (in shared memory) or translated on the fly.
+
+
+If a process dies from ``unnatural causes'' (e.g.\ kill $-9$). It will
+leave garbage in memory and other IPC handles will start floating
+around. There should be some way to collect this garbage.
+
+\subsection{Solutions}
+\label{sec:ProjSolutions}
+\Wine\ uses Sys-V IPC mechanism (See
+Appendix~\ref{sec:SysV-IPC}). This allows sharing data and passing
+data between processes (The alternatives are not that good in that
+respect - see Appendix~\ref{DDE-Alternatives}).
+The shared data contains only essential information (performance or
+compatibility). The minimum is kept on shared memory in order to get
+maximum stability (\windoz\ is known as an unstable system, \Wine\
+should not imitate \windoz\ in this respect).
+
+Communications are done by Sys-V messages and UNIX signals (a signal
+wakes \Wine\ up and the message passes the data). Sys-V messages are
+used for carrying \windoz\ messages, as well as synchronization
+information. There are 3 types of messages: sent, posted and ack.
+Ack message is used for synchronization as well as for returning error
+codes (In case sending/posting messages fail). When a message is sent,
+the sending process will block until \Wine's {\em ack}{} message is
+received.
+
+Synchronization between \Wine\ processes is divided into 2 categories,
+in both cases the sender of a message waits for an ack message:
+\begin{enumerate}
+  \item Sent messages - Wait until the recipient delivers ack message.
+    (When the recipient finished message processing) 
+  \item Posted message - The recipient will send ack only during
+    task switching instructions (like PostMessage, GetMessage, Yield,
+    etc.). This way nothing will be done after PostMessage until it is
+    safe. 
+\end{enumerate}
+
+There is no real \Wine\ server. Every \Wine\ process has to handle
+it's end. This approach somehow resembles a distributed OS\@. This
+introduces some problems (Resources might not be freed in case of a
+crash). On the other hand this ``distributed OS'' approach simplifies
+installation and use, and improves performance.
+
+Atoms are stored on shared memory, so every two \Wine\ processes will
+be in sync in this respect (atom 5 will mean the same on both
+processes). Shared memory handles are stored on shared memory as
+well. Shared memory handles are not from the same range as local
+memory handles (\windoz\ requires an plication to declare about it's
+shared memory). Since local memory handles have different range they
+can be allocated locally (without any sync requirements - handle x may
+appear on 10 different \Wine\ processes and address different data).
+
+Window handles are allocated locally. This approach gives stability,
+but window handles are no longer unique (same handle may appear
+on different processes). This requires on the fly window handle
+translation. When an \windoz\ message is transfered, \Wine\ will
+translate any contained window handle. The sender translates the
+handle to a global (unique) handle, the receiver translates the global
+handle to the local window handle.
+
+Collecting the garbage of dead processes is done in two cases:
+\begin{enumerate}
+  \item When setting up a new \Wine\ process: If no \Wine\ process is
+    running and shared memory is floating around all the IPC stuff is
+    deleted. 
+  \item When sending a message: If the recipient is dead it's IPC
+    handles are deleted.
+\end{enumerate}
+
+
+
+\section{The software}
+
+\subsection{DDE project structure}
+Old \Wine\ functions call the new DDE functions whenever needed.
+(e.g.\ when sending a DDE message, the original SendMessage function calls
+DDE\_SendMessage). This approach minimizes changes to original \Wine{}
+code. The new code was written in C. The new capabilities where written
+as much as possible in OOP\footnote{OOP stands for Object Oriented
+Programming}{} style.
+
+Currently DDE uses Sys-V IPC mechanism, for it's operation.
+
+
+\paragraph{Major OOP objects and files:}
+
+\begin{table}[h]
+    \begin{center}
+        \leavevmode
+        \begin{tabular}{|l|p{20em}|} \hline
+            Object           & Description \\ \hline
+            shm\_block       & shared memory block operations. \\
+            shm\_main\_block & (derived from shm\_block.) Things all
+                               DDE applications need access to. \\
+            shm\_fragment    & Allocation of in-block fragments. \\
+            shm\_semaph      & Semaphore operations. \\
+            dde\_proc        & Process and DDE message handling. \\
+            dde\_mem         & Front end of DDE memory handling
+                               (Interface of DDE to outer world). \\
+            dde\_atom        & Handling global atoms. \\ 
+            bit\_array       & Array of bits. It has atomic
+                               operations, so bits can be used instead
+                               of semaphores. \\ \hline
+        \end{tabular}
+        \caption{Objects constructing the DDE extension.}
+        \label{tab:ObjList}
+    \end{center}
+\end{table}
+
+Table~\ref{tab:ObjList}{} lists the objects used in the DDE code.
+The following rules apply to objects:
+
+\begin{itemize} 
+  \item Object names that begin with {\em dde\_$\cdots$}{} are the front
+    end. These objects are working directly with the rest of
+    \Wine. Objects that start with {\em shm\_$\cdots$}{} are the back
+    end. These objects provide services for the rest of the
+    implementation. 
+  \item The objects are stored in file with the same name as the object.
+    (e.g.\ dde\_mem is stored in dde\_mem.c and dde\_mem.h).
+  \item For each object there is a test file (that partially tests it).
+    The name of this file is object's name with the word ``test''
+    (e.g.\ dde\_mem object has dde\_mem\_test.c).
+  \item dde.h file has declarations used by dde\_proc and external DDE
+    users.
+\end{itemize}
+    
+
+\subsection{Major algorithms}
+
+\paragraph{Delivering messages:}
+\label{sec:DeliveringMessages}
+\windoz\ messages are passed using Sys-V IPC messages. Processing
+starts with SendMessage() or PostMessage() \windoz\ system
+functions:
+\begin{enumerate}
+  \item SendMessage and PostMessage call the DDE functions (same names
+    prefixed with DDE\_). If the DDE functions pass, don't go any
+    further. If it fails try to process the message in the
+    conventional way. 
+  \item The DDE message functions call DDE\_DoMessage, which is
+    the main DDE message processing function. From now on there is no
+    difference between sending and posting messages (from initiator's
+    point of view).
+  \item If the message is not a DDE message or the recipient is not
+    remote, fail and return to original message functions.
+  \item Bring the message to a format suitable for IPC delivery. The
+    format includes:
+    \begin{itemize}
+      \item message type (sent or posted).
+      \item Sender window handle (translated to global window id.)
+      \item Other message ingredients (msg, lParam).
+    \end{itemize}
+  \item Deliver the message to every recipients using
+    DDE\_DoOneMessage. There might be many recipients in case of a
+    broadcast (when the ``recipient'' window is -1). 
+  \item DDE\_DoOneMessage delivers the message and waits for response.
+    Fail if timeout is reached.
+\end{enumerate}
+
+
+\paragraph{Receiving messages:}
+Messages from other \Wine\ processes are received. Processing start
+from DDE\_GetRemoteMessage():
+\begin{enumerate}
+  \item DDE\_GetRemoteMessage is called whenever wine is going to wait
+    or receive X-windows message. If wine is sleeping (waiting for X),
+    it will waken by a SIGUSR2 signal. In this case the handler will
+    siglongjmp() out of the select() function.
+  \item If no remote message is pending in the message queue - exit.
+    (Sys-V message queue holds the remote messages until they are
+    read).
+  \item If the message is broadcasted, goto stage~\ref{BroadcastAlgo}.
+  \item Translate the global window handle of the recipient to local
+    handle. 
+  \item Do this if the message was sent. Send the message to the
+    recipient window. Reply with ack to the sender. (Reply with the
+    return code of the SendMessage function). {\em \bf Return}\ with
+    positive return value.
+  \item Post the message.
+  \item If PostMessage fails - send failing ack message. 
+  \item If PostMessage passes, add the message data into a FIFO\@. This
+    FIFO contains all messages that have to be acknowledged (who's
+    sender is waiting for ack). Whenever internal task switch occurs,
+    a item from this FIFO is popped out and an ack message is sent.  
+  \item \label{BroadcastAlgo} Iterate through the local windows and
+    deliver the message to every one of them.
+  \item Send a positive ack message.
+\end{enumerate}
+
+\paragraph{Allocating memory:}
+Shared memory allocation is divided into two categories: internal wine
+and \windoz\ application. The memory used by \windoz\ applications is
+allocated in two phases - allocate internal wine, and then prepare all
+the stuff needed by \windoz.
+
+The internal allocation (DDE\_malloc):
+\begin{enumerate}
+  \item Try to allocate big enough memory fragment in allocated shared
+    memory. 
+  \item If fragment could not be allocated, allocate a new shared
+    memory block. Allocate the memory fragment.
+  \item Allocate a shared memory handle (call the dde\_alloc\_handle() 
+    function). The allocated handle is from a range used only by
+    shared memory handles. This allocation function is used only for
+    shared DDE memory.
+  \item Write the handle in the data structure. Also write the
+    relative location of this handle (Pointer location is useless since
+    it differs from one \Wine\ process to another).
+    This information is written in the main shared memory block.    
+\end{enumerate}
+When a fragment is allocated, it is removed from the list of free
+memory.
+
+Allocation for \windoz\ applications (this is done in GlobalAlloc):
+\begin{enumerate}
+  \item Do the internal allocation (instead of malloc in the local
+    allocation). 
+  \item Everything else is the same as with local memory. A segment is
+    allocated for the new memory, and it's data is kept in the data
+    structure. 
+\end{enumerate}
+
+
+\paragraph{Atoms:}
+Atoms have pretty simple algorithms operating on them. Since atoms are
+supposed to give a unique number for each string - atoms are
+implemented as hash tables. The id of the atom is the entry in the
+hash table. The disadvantage of this approach is that there is a limit
+on the number of atoms, the big advantages are simplicity and
+speed.
+
+Since implementing a hash tables is strait forward, I will not
+discuss it in depth. This hash table has two hash functions - primary
+and secondary. When searching for an item (for deletion, addition, or
+a seek) the following steps are taken:
+\begin{enumerate}
+  \item The primary hash function returns the first entry.
+  \item \label{AtomHashLoop}
+    If the entry is empty or no unchecked entries {\bf \em fail}.
+  \item If the entry is correct, {\bf \em success!!!}.
+  \item Add the result of secondary hash function to the item index.
+  \item Goto step~\ref{AtomHashLoop}.
+\end{enumerate}
+
+
+\subsection{Major data structures}
+There are two kinds of data structure, local and shared. The local
+data structures are strait forward and will not be discussed in
+detail.
+
+The shared data structures have four level hierarchy. Each level
+depend on the other and can not exist without it. Most structures have
+much less than four levels.
+
+\paragraph{Level one data structure - the main block:}
+This data structure is part of the shm\_main\_block object. It
+contains essential information needed by all \Wine\ processes. : 
+\begin{enumerate}
+  \item Semaphore identifier used for locking the data structure.
+  \item A table containing information about \Wine\ processes.
+  \item Relative pointers to atoms.
+  \item A table containing window information.
+  \item Tables with global memory handles.
+\end{enumerate}
+
+The first level is allocated and initialized when \Wine\ calls a DDE
+function the first time. DDE functions are: global memory allocation,
+global atoms or DDE messages. 
+
+The first level data structure contains the second level data
+structure. 
+
+
+\paragraph{Atom element (level two):}
+Each element is allocated dynamically (the size of the string is
+unknown). The allocation is gained from the shm\_fragment object (each
+atom is an instance of that object). Each atom contains:
+\begin{enumerate}
+  \item Count of links. Each allocation of the atom establishes a new
+    link and each deallocation deletes one link (until all links are
+    removed). 
+  \item The string of the atom. The string ends with a null character.
+\end{enumerate}
+
+\paragraph{Wine processes data (level two):}
+(part of the dde\_proc object) :
+\begin{enumerate}
+  \item pid (\Wine\ process id).
+  \item Message queue id.
+  \item Semaphore used for locking process's data structure.
+  \item Sys-V shared memory id of the first block in the chain of
+    process's blocks.
+\end{enumerate}
+
+
+\paragraph{Window information (level two):}
+This is part of the dde\_proc object. The index of array entry
+specifies the window handle. Each entry contains:
+\begin{enumerate}
+  \item The process index of the \Wine\ process running this window.
+  \item The local window handle of this window (remember that each DDE
+    window has different global and local handles).
+\end{enumerate}
+
+
+\paragraph{Global memory handles (Level two):}
+(part of bit\_array and dde\_mem objects):
+\begin{enumerate}
+  \item A bit array contains '1' in every entry that refers to
+    used global memory handle.
+  \item Array of handles contains handle data. Each entry refers
+    to a global memory handle (The index is a function of the
+    handle).  The data includes: 1) Sys-V shared memory handles 2)
+    offset into the memory block. 
+\end{enumerate}
+
+\paragraph{Block allocation data structure (Level three):}
+This data structure a part of the shm\_block object. It is local to
+each shared memory block, so every memory block has it's own data
+structure. The shared memory blocks are organized in chains grouped by
+processes (each DDE process has one and only one chain): 
+\begin{enumerate}
+  \item The id of the next shared memory block in the chain.
+  \item The size of the block.
+  \item Number of free bytes in the block.
+  \item The index of the owner process.
+  \item The first item in the free list (a linked list of free items).
+\end{enumerate}
+
+
+\paragraph{Fragment allocation (Level four):}
+This data is a part of the shm\_fragment object. It is a part of the shared
+memory allocation mechanism. Every fragment is a part of shared memory
+block. Each fragments contain:
+\begin{enumerate}
+  \item The size of the fragment (for allocating and freeing this
+    fragment). 
+  \item A union that contains one of:
+    \begin{itemize}
+      \item data - if it is allocated.
+      \item offset of the next free fragment (if it is a member of the
+        free list).
+    \end{itemize}
+\end{enumerate}
+
+
+\paragraph{Local reference to global memory:}
+Global memory blocks are referenced from local memory. This is used
+for storing pointers that refer to the memory block. It contains:
+\begin{enumerate}
+  \item next item in the list.
+  \item shared memory block id.
+  \item Owner process.
+  \item Pointer to the data.
+\end{enumerate}
+
+\paragraph{Local mirroring of global handles:}
+Global handles require local segments handles (when they are locked).
+These segments have to be deleted when the handle is freed.
+There is a minimal mirroring of handles in the original tables of
+wine, this information is stored the way local handles have always
+been stored.
+
+\subsection{Interface and IO}
+The DDE section of wine has several interfaces to different entities:
+\begin{enumerate}
+  \item User debug information.
+  \item Interface between several \Wine\ processes.
+  \item Interface to the `old' code of \Wine.
+\end{enumerate}
+
+
+\paragraph{User debug information:}
+The debug information is written according to \Wine's
+conventions. This means that dprintf\_$\cdots$ macros are used to
+print the debug information. (These macros allow runtime or compile time
+disabling of a any sort of debug information).
+
+In some cases the dprintf\_$\cdots$ macros are not powerful enough. In
+those cases the following construct is used instead:
+\begin{verbatim}
+    if (debugging_dde) {
+      /* print whatever is needed for dde debugging */
+    }
+\end{verbatim}
+
+
+\paragraph{Interface between \Wine\ processes:}
+The interface between processes includes:
+\begin{itemize}
+  \item Message delivery (see Section~\ref{sec:DeliveringMessages}).
+  \item Sharing \windoz\ constructs (atoms, memory, window
+    handles).
+  \item Synchronization among different \Wine\ processes so it will
+    appear to a \windoz\ as if there is only one process.
+\end{itemize}
+
+\paragraph{Interface to the rest of \Wine:}
+Most of the interface has been minimized to an additional few lines in
+the original functions. The hook for DDE are in the following
+locations:
+\begin{itemize}
+  \item Global atoms functions - these are called directly from
+    \windoz\ applications. 
+  \item Message delivery - a hook calls the DDE functions from the
+    original message delivery functions.
+  \item Initialization - Every PeekMessage() call a DDE function to
+    check if the current window has DDE management (by sending
+    a dummy WM\_DDE\_INITIATE message).
+  \item Waiting on messages - The original code for waiting on X
+    messages was enhanced to wait on DDE messages as well. This
+    includes aborting sleeps when SIGUSR2 signal is sent. The actual
+    test for DDE messages is done in the DDE code.
+\end{itemize}
+
+\subsection{Major functions and their role}
+\paragraph{Message delivery functions:}
+\begin{itemize}
+  \item DDE\_SendMessage and DDE\_PostMessage - hooks used by original
+    \Wine's SendMessage and PostMessage. They return true if the
+    message could be successfully sent to a remote \Wine\ process.
+    Only in this case SendMessage and PostMessage stop further
+    processing.
+  \item DDE\_DoMessage - Try to post or send a message to another
+    \Wine\ process. This function can do broadcasting as well as
+    sending. (A message is `broadcasted' if it is delivered to every
+    window on the system).
+  \item DDE\_DoOneMessage - Deliver a message to a given wine
+    {\bf process}.
+  \item dde\_proc\_send\_ack - Send ack message to \Wine\
+    process. The input window handle is used for detecting the
+    process.
+  \item get\_ack - wait for ack or timeout.
+\end{itemize}
+
+\paragraph{Memory allocation functions:}
+\begin{itemize}
+  \item DDE\_malloc - Allocate a shared memory fragment. This function
+    also allocates global memory handle.
+  \item DDE\_GlobalFree - Free a shared memory fragment according to
+    it's handle. And free the handle.
+  \item DDE\_SyncHandle - synchronize the global handles mirrored
+    locally. Delete any outdated handles, or remap reallocated
+    handles. 
+  \item DDE\_mem\_init - initialize or attach the main shared memory
+    block, and relevant local data structures.
+  \item shm\_delete\_all - delete all IPC stuff related to this
+    process. Kill the main memory block if appropriate.
+\end{itemize}
+
+
+\section{Software testing}
+The testing of this module was a substantial part of the
+development. Testing revealed bugs just as they where created.
+
+\subsection{Testing methods utilized}
+\label{sec:TestMethod}
+Two major testing methods where used:
+\begin{enumerate}
+  \item Running DDE \windoz\ applications. The applications used are
+    DDE demonstration applications. This applications seem to show 
+    precisely what DDE is all about. The applications used where:
+    ddepop1.exe (server), showpop1.exe (client). These
+    applications come with \windoz\ programming manual by Charles
+    Petzold \cite{bib:WinManual}. 
+  \item Running standalone DDE objects linked with a test
+    object. Every object was tested this way. Some objects had to be
+    linked with a stub that emulated \Wine's functions. The stub is
+    pretty poor with dde\_mem object since this object requires hard
+    to emulate functionalities (things like allocating a segment).
+
+    For some objects the coverage seems to be perfect (100\%). For
+    some object the coverage is poor. The objects with massive stub
+    usage suffer from this (especially dde\_mem).
+\end{enumerate}
+
+\subsection{input for testing}
+Most of the testing described in section~\ref{sec:TestMethod} has no
+input. Most of the testing knowledge is in the test objects
+themselves. There are two exceptions to this rule:
+\begin{enumerate}
+  \item The \windoz\ applications described in
+    section~\ref{sec:TestMethod} - which are essentially an input to
+    the software. These applications can't be distributed since it
+    will be a \copyright{} violation.
+  \item A trace file which is used for comparing test's output with
+    the expected trace result. This trace file is used for
+    shm\_fragment validation. This file is implementation Dependants
+    and should be updated whenever the object is rewritten. When
+    updating the trace, it should be inspected manually before it is
+    released. 
+\end{enumerate}
+
+\subsection{usage instructions}
+
+\paragraph{Running the DDE applications:}
+To test the DDE applications one must run:
+\begin{verbatim}
+   prompt> wine /full-path/ddepop1.exe > /dev/null &
+\end{verbatim}
+Wait for the server window to pop up (A tiny window should appear at
+the lower left corner of your screen). Then activate the client by
+typing: 
+\begin{verbatim}
+   prompt> wine /full-path/showpop1.exe > /dev/null 
+\end{verbatim}
+The server updates ``USA population'' data every 5 seconds. The client
+asks for a hot link (i.e.\ it sends a WM\_DDE\_ADVISE on every
+item). From that point on the server updates the client of any
+population change.
+
+
+\paragraph{Running the object tests:}
+The {\em run\_tests}{} script is provided to automate the object
+tests. Every object test is run and the script checks for results. At
+the end the script prints a nice summary table.
+
+Invoking tests outside the {\em run\_tests}{} script is not as simple
+as it may look. Every test has differently looking output.
+\begin{itemize}
+  \item dde\_atom\_test - The executable is run. It passes if no
+    errors are printed at the bottom. 
+  \item dde\_mem\_test - The same as for dde\_atom\_test.
+  \item shm\_semaph\_test - The same as for dde\_atom\_test.
+  \item bit\_array\_test -  The same as for dde\_atom\_test.
+  \item shm\_fragment\_test - After the executable is run,  the output
+    has to be compared with TEST\_FRAGMENT.std 
+  \item dde\_proc\_test - This actually runs as a client and as a
+    server. To activate the server one should write:
+\begin{verbatim}
+  prompt> dde_proc_test 1 > server.log
+\end{verbatim}
+    Then the client has to be activated within five seconds by
+    writing:
+\begin{verbatim}
+  prompt> dde_proc_test > client.log
+\end{verbatim}
+    The log files should contain:
+    \begin{description}
+      \item[server.log:] Should contain traces of received
+        WM\_DDE\_INITIATE message, and ack sent for it. (Pretty much
+        the same what  {\em run\_tests}{} does).  
+      \item[client.log:] Should contain traces of sending
+        WM\_DDE\_INITIATE and then receiving an ack message.
+    \end{description}
+    No `timeout' traces should be present in the log files.
+
+\end{itemize}
+
+
+\section{Summary}
+\subsection{Software limitations}
+\begin{itemize}
+  \item Only most fundamental memory management functions where
+    written. This means that the following functions will not work:
+    \begin{itemize}
+      \item GlobalReAlloc
+      \item GlobalSize - two line fix.
+      \item GlobalFlags - two line fix.
+      \item LockSegment - two line fix.
+      \item UnlockSegment - two line fix.
+      \item GlobalFreeAll - will not free DDE memory.
+      \item GlobalPageLock - two line fix.
+      \item GlobalPageUnlock - two line fix.
+      \item GlobalFix - two line fix.
+      \item GlobalUnfix - two line fix.
+    \end{itemize}
+  \item Non DDE messages to remote windows will not work. This is
+    currently only a sanity check, it may be removed in the future.
+  \item Message sending has a timeout limit. This is incompatible with
+    \windoz. This limit increases stability of a singe \Wine\ process.
+  \item Synchronization mechanism between wine processes is not
+    perfect. It was not proved theoretically. I never saw it fail.
+\end{itemize}
+
+\subsection{Concluding Remarks}
+This extension to \Wine{} enables further development of \windoz\ IPC
+support. Things like OLE can be extended using these features -
+although some modifications might be inevitable.
+
+The most important contribution of this project is the support for
+\libwine{}. Any \windoz\ application compiled under UNIX and linked to
+\libwine{} will need the IPC mechanism provided by this project.
+
+During the progress of the project it got a bit outdated. During that
+time \Wine{} started to handle tasks internally, so the external IPC
+was no longer needed for the emulator configuration of
+wine. Nevertheless the support of IPC for \libwine will never
+be obsolete.
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Appendixes
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\clearpage
+\appendix
+
+\section{\Wine}
+\label{sec:Wine}
+\Wine\ stand for {\em WINdows Emulator}. It is an X-windows - UNIX 
+application (Linux and FreeBSD). \Wine\ emulates \windoz\  environment
+for the \windoz\  applications. It has two uses:
+\begin{enumerate}
+  \item Run \windoz\  binary code (compiled under \windoz).
+  \item To be used as a toolkit for compiling \windoz\ applications
+    under UNIX. (The \libwine\ library is provided)
+\end{enumerate}
+For emulation, only  Intel-Architecture CPU (386, 486, Pentium) are
+supported. \libwine\ Toolkit should run on any platforms, but it was not
+tested. \Wine\ is still in alpha state, and does not support all \windoz\
+capabilities yet.
+
+
+\section{Messages under \windoz}
+\label{sec:WindozMsg}
+Messages are the means of communication to a user window (from another
+window or from \windoz\ itself).
+Messages can be delivered in two ways:
+\begin{itemize}
+  \item Messages can be sent. The sent message enters the window handler
+    asynchronously (The handler may be reentered many times).
+    A window sending the message waits for the recipient to process
+    the message and return an exit code.
+  \item Messages can be posted. The posted message enters a queue, and
+    it's up to the recipient to process it. If the recipient ignores
+    it, the message might be eventually sent to the recipient from
+    WinMain handler.
+\end{itemize}
+
+\section{DDE}
+\label{sec:DDE}
+DDE stands for \DDE\@. DDE is an \windoz\ 
+protocol used for data exchange between applications.
+It has synchronous and asynchronous operation modes.
+DDE mechanism is based on messages, atoms
+(Section~\ref{sec:WhatAreAtoms}) and shared memory.
+
+DDE applications are divided roughly into two classes: servers AND
+clients. Clients have the initiative, they try to connect to the
+server. Servers only maintain an existing DDE link.
+
+
+\subsection{DDE Messages}
+\paragraph{DDE message format}:
+
+\label{sec:DDEMessageFormat}
+
+DDE messages contain the following fields.
+\begin{description}
+  \item[wnd] The recipient of this message ($-1$ if every window
+    should receive).
+  \item[msg]    The ID of the message.
+  \item[wParam] Who sent this message.
+  \item[lParam] 32 bit parameter, divided into two 16 bit words.
+    Usually, the lower 16 bits contain a memory handle. The handle
+    points to some extra DATA about this message.
+    
+\end{description}
+
+\paragraph{Available messages:}
+\begin{description}
+  \item[WM\_DDE\_INITIATE]
+    This message is sent by the client to the whole ``world''.
+    {\em lParam}{} contains the two atoms used for passing the topic and
+    application information.
+
+    Every server application checks if this message refers to it
+    (According to the Application and the Topic atoms).
+
+
+  \item[WM\_DDE\_ACK]
+    This is a generic response to various events
+    (one of them is WM\_DDE\_INITIATE).
+    The low part of {\em lParam}{} passes extra information, such as
+    success/failure.
+
+  \item[WM\_DDE\_TERMINATE]
+    Kill the DDE link.
+
+
+  \item[WM\_DDE\_ADVISE]
+    Tell the server to inform the client of any updates.
+
+
+  \item[WM\_DDE\_UNADVISE]
+    Stop the WM\_DDE\_UNADVISE mode.
+
+
+  \item[WM\_DDE\_DATA]
+    Transfer data handle (note that the data handle must be globally allocated
+    with the GMEM\_DDESHARE flag).
+
+  \item[WM\_DDE\_REQUEST]
+    Request a data item from the server. This message is used in a
+    cold link. {\em lParam}{} contains an atom describing the desired
+    item, and a WORD describing the wanted data format.
+  \item[WM\_DDE\_POKE]
+    The client gives the server new data.
+  \item[WM\_DDE\_EXECUTE]
+    The client asks the server to execute a procedure (according to a
+    command string).
+
+\end{description}
+
+\subsection{Atoms}
+\label{sec:WhatAreAtoms}
+Atoms are represented by numbers. Every atom maps uniquely to a string
+(i.e.\ two atoms can't map to the same string).
+There are two types of atoms - local and global. The local are visible
+only to the application that created them. Global atoms are seen by all
+\windoz\  applications.
+
+Functions:
+\begin{description}
+  \item[AddAtom(str)]   create a local atom that maps to ``str''.
+    If it exists, increment the allocation-counter,
+    and return the atom.
+  \item[DeleteAtom(atom)] decrement the allocation-counter.  When it
+    reaches zero the atom, will be deleted.
+  \item[FindAtom(str)]  Find the atom that maps to this string (if exist).
+    
+  \item[GetAtomName(\ldots)] Find the string that this atom points to.
+\end{description}
+
+NOTE:
+\begin{description}
+  \item[Global atoms] Add ``Global'' before the listed names to get Global
+    atom functions.
+  \item[Case sensitivity] All atom operations ignore case.
+\end{description}
+
+
+\section{DDE under \Wine\ - Alternatives}
+\label{DDE-Alternatives}
+There where three possible approaches for this project. I have chosen
+System-V IPC, but it can be easily changed.
+
+\subsection{IPC - Inter-Process Communication}
+\label{sec:SysV-IPC}
+
+The IPC mechanism was originated from System-V UNIX\@. This mechanism
+allows complicate communication between two process (on the same machine). 
+IPC includes the following capabilities:
+\begin{enumerate}
+  \item Shared Memory (shm) - can be shared among few processes and users.
+  \item Semaphores (These semaphores allow grouped operations - i.e.\ 
+    operations gathered as an atomic operation).
+  \item Message Queues (allow few messages at a time).
+\end{enumerate}
+
+The advantages of IPC over the other variants are:
+\begin{itemize}
+  \item Memory access speed is good. (after the memory was attached).
+  \item Easy to block critical code (don't enter critical code from two
+    processes at the same time)
+\end{itemize}
+Disadvantages of IPC:
+\begin{itemize}
+  \item Impossible to communicate to other machine.
+  \item Requires complex mechanism to wait both for X and IPC messages.
+\end{itemize}
+
+\subsection{X-Windows Communication mechanisms}
+The advantages of X-Windows Communication over the other variants are:
+\begin{itemize}
+  \item Possible to communicate to other machines.
+  \item No need for additional mechanism that will wait both for X and DDE\@.
+  \item Many of the required capabilities are already there.
+\end{itemize}
+Disadvantages of X-windows communication:
+\begin{itemize}
+  \item {\em Slow}\ and complex memory access.
+  \item May be hard to avoid two applications from entering critical
+    code at the same time.
+\end{itemize}
+
+\subsection{BSD Sockets}
+The advantages of Sockets are:
+\begin{itemize}
+  \item Possible to communicate to other machines.
+  \item No need for complex mechanism that will wait both for X and
+    DDE\@. (can use one ``select'' on X-windows socket in concert with
+    the DDE socket).
+\end{itemize}
+Disadvantages of socket are:
+\begin{itemize}
+  \item {\em Slow}{} and complex memory access. (note that mmap on a
+    descriptor does not work for Linux 0.99).
+  \item May be hard to avoid two applications from entering critical
+    code at the same time.
+\end{itemize}
+
+\subsection{Why was it written in C? Pros and cons.}
+Advantages of C:
+
+\begin{itemize}
+  \item History- \Wine{} is already written in C.
+  \item Portability- not all systems have C++.
+  \item Speed- C++ sometimes makes it very difficult to write fast code.
+  \item Maintenance- More programmers know C than C++. 
+\end{itemize}
+
+Advantages of C++:
+
+\begin{itemize}
+  \item smaller code - Templates allow Smaller and more readable code.
+  \item Maintenance - It is easier to add and modify code in C++ (than in C).
+  \item Verification - Functionality can be verified and debugged for
+    individual objects.
+\end{itemize}
+
+I have decided to use C. Most of C++ advantages can be acquired
+by using OOP methodologies. OOP methods that require inline functions
+can't be used (without performance impact). GCC supports inline functions,
+but this solution is not compatible.
+
+
+
+\section{\Wine\ basics}
+\subsection{How it runs}
+\Wine\ works in the following order:
+\begin{enumerate}
+  \item \Wine\ loads the \windoz\  application into it's memory.
+    (in the process it, links
+    DLL's\footnote{DLL (Dynamically Linked Library) is linked on load-time.}
+    creates 16-bit segments).
+  \item \windoz\  code is executed.
+\end{enumerate}
+
+\section{bibliography}
+\begin{thebibliography}{99}
+  \bibitem{bib:WinManual} Charles Petzold {\em  Programming
+      Windows~3.1}{} - 1992. \\ 
+    On cover: {\em the Microsoft guide to writing applications for
+      windows~3.1}. \\
+    Published by {\em Microsoft press}. 
+\end{thebibliography}
+
+
+\newpage
+
+
+\end{document}
diff --git a/ipc/dde_atom.c b/ipc/dde_atom.c
index e07690c..5ca9b42 100644
--- a/ipc/dde_atom.c
+++ b/ipc/dde_atom.c
@@ -6,6 +6,7 @@
  * File:      dde_atom.c
  * Purpose :  atom functionality for DDE
  */
+#ifdef CONFIG_IPC
 
 #include <ctype.h>
 #include <string.h>
@@ -106,11 +107,11 @@
 }
 
 /***********************************************************************
- *           GlobalAddAtom   (USER.268)
+ *           DDE_GlobalAddAtom
  */
 
 /* important! don't forget to unlock semaphores before return */
-ATOM GlobalAddAtom( SEGPTR name )
+ATOM DDE_GlobalAddAtom( SEGPTR name )
 {
   int atom_idx;
   int atom_ofs;
@@ -164,10 +165,10 @@
 }
 
 /***********************************************************************
- *           GlobalDeleteAtom   (USER.269)
+ *           DDE_GlobalDeleteAtom
  */
 
-ATOM GlobalDeleteAtom( ATOM atom )
+ATOM DDE_GlobalDeleteAtom( ATOM atom )
 {
   int atom_idx;
   int atom_ofs;
@@ -203,9 +204,9 @@
 }
 
 /***********************************************************************
- *           GlobalFindAtom   (USER.270)
+ *           DDE_GlobalFindAtom
  */
-ATOM GlobalFindAtom( SEGPTR name )
+ATOM DDE_GlobalFindAtom( SEGPTR name )
 {
   int atom_idx;
   int atom_ofs;
@@ -242,9 +243,9 @@
 }
 
 /***********************************************************************
- *           GlobalGetAtomName   (USER.271)
+ *           DDE_GlobalGetAtomName
  */
-WORD GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
+WORD DDE_GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
 {
   int atom_idx, atom_ofs;
   int size;
@@ -283,3 +284,4 @@
   return size;
 }
 
+#endif  /* CONFIG_IPC */
diff --git a/ipc/dde_mem.c b/ipc/dde_mem.c
index f19b013..5e9c03d 100644
--- a/ipc/dde_mem.c
+++ b/ipc/dde_mem.c
@@ -7,6 +7,8 @@
  * Purpose :  shared DDE memory functionality for DDE
  ***************************************************************************
  */
+#ifdef CONFIG_IPC
+
 #include <stdio.h>
 #include <stddebug.h>
 #include <debug.h>
@@ -280,3 +282,5 @@
   nr_of_bits= BITS_PER_BYTE * sizeof(main_block->free_handles);
   AssembleArray( &free_handles, main_block->free_handles, nr_of_bits);
 }
+
+#endif  /* CONFIG_IPC */
diff --git a/ipc/dde_proc.c b/ipc/dde_proc.c
index 9f5f59e..df6e6a8 100644
--- a/ipc/dde_proc.c
+++ b/ipc/dde_proc.c
@@ -7,6 +7,12 @@
  * Purpose :  DDE signals and processes functionality for DDE
  ***************************************************************************
  */
+#ifdef CONFIG_IPC
+
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+#define msgbuf mymsg
+#endif
+
 #include <sys/time.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -716,3 +722,4 @@
   }
 }
 
+#endif  /* CONFIG_IPC */
diff --git a/ipc/generic_hash.c b/ipc/generic_hash.c
index f5e0f44..df0449b 100644
--- a/ipc/generic_hash.c
+++ b/ipc/generic_hash.c
@@ -5,6 +5,8 @@
  * Purpose :  dynamically growing hash, may use shared or local memory.
  ***************************************************************************
  */
+#ifdef CONFIG_IPC
+
 #include <sys/types.h>
 #include <stdlib.h>
 #include <assert.h>
@@ -677,3 +679,5 @@
 {
    return ptr.ptr;
 }
+
+#endif  /* CONFIG_IPC */
diff --git a/ipc/shm_block.c b/ipc/shm_block.c
index 77ff766..259378f 100644
--- a/ipc/shm_block.c
+++ b/ipc/shm_block.c
@@ -7,6 +7,7 @@
  * Purpose:   Treat a shared memory block.
  ***************************************************************************
  */
+#ifdef CONFIG_IPC
 
 #define inline __inline__
 #include <sys/types.h>
@@ -76,7 +77,7 @@
   shmctl(shm_id, IPC_STAT, &ds );
 
   block=(struct shm_block*)shmat(shm_id, NULL, 0);
-  if (block==NULL) return NULL;
+  if (block==NULL || block == (struct shm_block*) -1) return NULL;
 
   this=(struct local_shm_map *)malloc(sizeof(*this));
   this->next= shm_map;
@@ -190,3 +191,5 @@
   *shmid=-1;
   shmdt((char *)block);
 }
+
+#endif  /* CONFIG_IPC */
diff --git a/ipc/shm_fragment.c b/ipc/shm_fragment.c
index 098d6cc..15c51fe 100644
--- a/ipc/shm_fragment.c
+++ b/ipc/shm_fragment.c
@@ -7,6 +7,8 @@
  * Purpose:   Data fragments and free list items. Allocate and free blocks.
  ***************************************************************************
  */
+#ifdef CONFIG_IPC
+
 #include <stdio.h>		   /* for debugging only */
 #include <stddebug.h>
 #include <debug.h>		   /* for "stddeb" */
@@ -176,3 +178,5 @@
   fprintf(stddeb," [total free=%04x]\n",block->free);
   fflush(stddeb);
 }
+
+#endif  /* CONFIG_IPC */
diff --git a/ipc/shm_main_blk.c b/ipc/shm_main_blk.c
index 96b4681..fdc2307 100644
--- a/ipc/shm_main_blk.c
+++ b/ipc/shm_main_blk.c
@@ -7,6 +7,8 @@
  * Purpose:   Main Wine's shared memory block
  ***************************************************************************
  */
+#ifdef CONFIG_IPC
+
 #define inline __inline__
 #include <sys/types.h>
 #include <sys/sem.h>
@@ -265,3 +267,5 @@
   for (proc_idx= 0 ; proc_idx < DDE_PROCS ; proc_idx++)
      dde_proc_refresh( &main_block->proc[proc_idx] );
 }
+
+#endif  /* CONFIG_IPC */
diff --git a/ipc/shm_semaph.c b/ipc/shm_semaph.c
index c226808..f730154 100644
--- a/ipc/shm_semaph.c
+++ b/ipc/shm_semaph.c
@@ -7,6 +7,8 @@
  * Purpose:   Handle semaphores for shared memory operations.
  ***************************************************************************
  */
+#ifdef CONFIG_IPC
+
 #define inline __inline__
 #include <assert.h>
 #include <unistd.h>
@@ -134,3 +136,5 @@
 
   *semptr= -1;
 }
+
+#endif  /* CONFIG_IPC */
diff --git a/ipc/wine_test_stub.c b/ipc/wine_test_stub.c
index fb1747e..dd9499c 100644
--- a/ipc/wine_test_stub.c
+++ b/ipc/wine_test_stub.c
@@ -23,7 +23,7 @@
     return 0;
 }
 
-int LDT_SetEntry( int entry, ldt_entry *content )
+int LDT_SetEntry( int entry, ldt_entry const *content )
 {
     return 0;
 }
diff --git a/loader/Makefile.in b/loader/Makefile.in
index f250120..bf3e4cf 100644
--- a/loader/Makefile.in
+++ b/loader/Makefile.in
@@ -28,7 +28,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/loader/main.c b/loader/main.c
index 384e3f3..9bb0185 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -66,6 +66,9 @@
       /* Initialize interrupt vectors */
     if (!INT_Init()) return 0;
 
+      /* Initialize DOS memory */
+    if (!DOSMEM_Init()) return 0;
+
       /* Initialize signal handling */
     init_wine_signals();
 
diff --git a/loader/module.c b/loader/module.c
index 45891b3..f518e6c 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -39,7 +39,6 @@
     NE_MODULE *pModule;
     SEGTABLEENTRY *pSegTable;
     struct dll_table_s *table;
-    char *dosmem;
     int i;
 
       /* Create the built-in modules */
@@ -82,47 +81,10 @@
         hFirstModule = hModule;
     }
 
-      /* Initialize some KERNEL exported values */
+    /* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */
 
-    if (!(hModule = GetModuleHandle( "KERNEL" ))) return TRUE;
+    MODULE_SetEntryPoint( GetModuleHandle( "KERNEL" ), 178, GetWinFlags() );
 
-      /* KERNEL.178: __WINFLAGS */
-    MODULE_SetEntryPoint( hModule, 178, GetWinFlags() );
-
-    /* Allocate 7 64k segments for 0000, A000, B000, C000, D000, E000, F000. */
-
-    dosmem = malloc( 0x70000 );
-
-    MODULE_SetEntryPoint( hModule, 183,  /* KERNEL.183: __0000H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 193,  /* KERNEL.193: __0040H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x400,
-                                  0x100, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 174,  /* KERNEL.174: __A000H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x10000,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 181,  /* KERNEL.181: __B000H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x20000,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 182,  /* KERNEL.182: __B800H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x28000,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 195,  /* KERNEL.195: __C000H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x30000,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 179,  /* KERNEL.179: __D000H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x40000,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 190,  /* KERNEL.190: __E000H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x50000,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 173,  /* KERNEL.173: __ROMBIOS */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x60000,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
-    MODULE_SetEntryPoint( hModule, 194,  /* KERNEL.194: __F000H */
-                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x60000,
-                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
     return TRUE;
 }
 
diff --git a/loader/ne_image.c b/loader/ne_image.c
index 2a4e9ea..1450c0a 100644
--- a/loader/ne_image.c
+++ b/loader/ne_image.c
@@ -39,6 +39,8 @@
     int fd;
     struct relocation_entry_s *rep, *reloc_entries;
     BYTE *func_name;
+    int size;
+    char* mem;
 
     char buffer[100];
     int ordinal, additive;
@@ -51,23 +53,37 @@
 
     if (!pSeg->filepos) return TRUE;  /* No file image, just return */
 	
-	if (pSeg->flags & NE_SEGFLAGS_ITERATED)
-	{
-		fprintf(stderr, "Sorry, iterated segments are not supported\n"
-			"Please report that %*.*s, segment %d is such a segment\n",
-			*((BYTE*)pModule + pModule->name_table), 
-			*((BYTE*)pModule + pModule->name_table), 
-			(char *)pModule + pModule->name_table + 1,
-			segnum
-		);
-		exit(1);
-	}
-
     fd = MODULE_OpenFile( hModule );
     dprintf_module( stddeb, "Loading segment %d, selector=%04x\n",
                     segnum, pSeg->selector );
     lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
-    read( fd, GlobalLock( pSeg->selector ), pSeg->size ? pSeg->size : 0x10000);
+    size = pSeg->size ? pSeg->size : 0x10000;
+    mem = GlobalLock(pSeg->selector);
+    if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
+      read(fd, mem, size);
+    else {
+      /*
+	 The following bit of code for "iterated segments" was written without
+	 any documentation on the format of these segments. It seems to work,
+	 but may be missing something. If you have any doco please either send
+	 it to me or fix the code yourself. gfm@werple.mira.net.au
+      */
+      char* buff = malloc(size);
+      char* curr = buff;
+      read(fd, buff, size);
+      while(curr < buff + size) {
+	unsigned int rept = *((short*) curr)++;
+	unsigned int len = *((short*) curr)++;
+	for(; rept > 0; rept--) {
+	  char* bytes = curr;
+	  unsigned int byte;
+	  for(byte = 0; byte < len; byte++)
+	    *mem++ = *bytes++;
+	}
+	curr += len;
+      }
+      free(buff);
+    }
 
     if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
         return TRUE;  /* No relocation data, we are done */
diff --git a/loader/signal.c b/loader/signal.c
index 82d9651..d943bc5 100644
--- a/loader/signal.c
+++ b/loader/signal.c
@@ -80,19 +80,21 @@
 	   it aligned  */
 	segv_act.sa_restorer = 
 	    (void (*)()) (((unsigned int)(cstack) + sizeof(cstack) - 4) & ~3);
-	usr2_act.sa_restorer= segv_act.sa_restorer;
-	usr2_act.sa_handler = (__sighandler_t) stop_wait;
 	/* Point to the top of the stack, minus 4 just in case, and make
 	   it aligned  */
 	wine_sigaction(SIGSEGV, &segv_act, NULL);
 	wine_sigaction(SIGILL, &segv_act, NULL);
 	wine_sigaction(SIGFPE, &segv_act, NULL);
-	wine_sigaction(SIGUSR2, &usr2_act, NULL);
 #ifdef SIGBUS
 	wine_sigaction(SIGBUS, &segv_act, NULL);
 #endif
 	wine_sigaction(SIGTRAP, &segv_act, NULL); /* For breakpoints */
-#endif
+#ifdef CONFIG_IPC
+	usr2_act.sa_restorer= segv_act.sa_restorer;
+	usr2_act.sa_handler = (__sighandler_t) stop_wait;
+	wine_sigaction(SIGUSR2, &usr2_act, NULL);
+#endif  /* CONFIG_IPC */
+#endif  /* linux */
 #if defined(__NetBSD__) || defined(__FreeBSD__)
         sigset_t sig_mask;
         struct sigaltstack ss;
@@ -134,6 +136,7 @@
                 perror("sigaction: SIGTRAP");
                 exit(1);
         }
+#ifdef CONFIG_IPC
         usr2_act.sa_handler = (void (*)) stop_wait; /* For breakpoints */
 	usr2_act.sa_flags = SA_ONSTACK;
         usr2_act.sa_mask = sig_mask;
@@ -141,7 +144,8 @@
                 perror("sigaction: SIGUSR2");
                 exit(1);
         }
-#endif
+#endif  /* CONFIG_IPC */
+#endif  /* __FreeBSD__ || __NetBSD__ */
 }
 
 #endif /* ifndef WINELIB */
diff --git a/loader/task.c b/loader/task.c
index 7350965..b2180f4 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -528,7 +528,7 @@
 /***********************************************************************
  *           TASK_DeleteTask
  */
-void TASK_DeleteTask( HTASK hTask )
+static void TASK_DeleteTask( HTASK hTask )
 {
     TDB *pTask;
 
@@ -600,11 +600,16 @@
     TDB *pOldTask = NULL, *pNewTask;
     HTASK hTask = 0;
 
+#ifdef CONFIG_IPC
     dde_reschedule();
+#endif
       /* First check if there's a task to kill */
 
     if (hTaskToKill && (hTaskToKill != hCurrentTask))
+    {
         TASK_DeleteTask( hTaskToKill );
+        hTaskToKill = 0;
+    }
 
       /* If current task is locked, simply return */
 
diff --git a/loader/wine.c b/loader/wine.c
deleted file mode 100644
index b88f985..0000000
--- a/loader/wine.c
+++ /dev/null
@@ -1,756 +0,0 @@
-static char RCSId[] = "$Id: wine.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
-static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#ifdef linux
-#include <linux/unistd.h>
-#include <linux/head.h>
-#include <linux/ldt.h>
-#include <linux/segment.h>
-#endif
-#include <string.h>
-#include <errno.h>
-#include "neexe.h"
-#include "segmem.h"
-#include "prototypes.h"
-#include "dlls.h"
-#include "wine.h"
-#include "windows.h"
-#include "wineopts.h"
-#include "arch.h"
-#include "options.h"
-
-/* #define DEBUG_FIXUP */
-
-extern int CallToInit16(unsigned long csip, unsigned long sssp, 
-			unsigned short ds);
-extern void CallTo32();
-
-char * GetModuleName(struct w_files * wpnt, int index, char *buffer);
-extern unsigned char ran_out;
-extern char WindowsPath[256];
-char *WIN_ProgramName;
-
-unsigned short WIN_StackSize;
-unsigned short WIN_HeapSize;
-
-struct  w_files * wine_files = NULL;
-
-int WineForceFail = 0;
-
-char **Argv;
-int Argc;
-struct mz_header_s *CurrentMZHeader;
-struct ne_header_s *CurrentNEHeader;
-int CurrentNEFile;
-HINSTANCE hSysRes;
-
-static char *DLL_Extensions[] = { "dll", "exe", NULL };
-static char *EXE_Extensions[] = { "exe", NULL };
-static char *WinePath = NULL;
-
-FILE *SpyFp = NULL;
-
-/**********************************************************************
- *					myerror
- */
-void
-myerror(const char *s)
-{
-    if (s == NULL)
-	perror("wine");
-    else
-	fprintf(stderr, "wine: %s\n", s);
-
-    exit(1);
-}
-
-/**********************************************************************
- *					GetFilenameFromInstance
- */
-char *
-GetFilenameFromInstance(unsigned short instance)
-{
-    register struct w_files *w = wine_files;
-
-    while (w && w->hinstance != instance)
-	w = w->next;
-    
-    if (w)
-	return w->filename;
-    else
-	return NULL;
-}
-
-struct w_files *
-GetFileInfo(unsigned short instance)
-{
-    register struct w_files *w = wine_files;
-
-    while (w && w->hinstance != instance)
-	w = w->next;
-    
-    return w;
-}
-
-#ifndef WINELIB
-/**********************************************************************
- *
- * Load MZ Header
- */
-void load_mz_header(int fd, struct mz_header_s *mz_header)
-{
-    if (read(fd, mz_header, sizeof(struct mz_header_s)) !=
-	sizeof(struct mz_header_s))
-    {
-	myerror("Unable to read MZ header from file");
-    }
-}
-
-void load_ne_header (int fd, struct ne_header_s *ne_header)
-{
-    if (read(fd, ne_header, sizeof(struct ne_header_s)) 
-	!= sizeof(struct ne_header_s))
-    {
-	myerror("Unable to read NE header from file");
-    }
-}
-#endif
-
-/**********************************************************************
- *					LoadImage
- * Load one NE format executable into memory
- */
-HINSTANCE LoadImage(char *modulename, int filetype, int change_dir)
-{
-    unsigned int read_size;
-    int i;
-    struct w_files * wpnt, *wpnt1;
-    unsigned int status;
-    char buffer[256];
-    char *fullname;
-
-    /*
-     * search file
-     */
-    fullname = FindFile(buffer, sizeof(buffer), modulename, 
-			(filetype == EXE ? EXE_Extensions : DLL_Extensions), 
-			WindowsPath);
-    if (fullname == NULL)
-    {
-    	fprintf(stderr, "LoadImage: I can't find %s.dll | %s.exe !\n",
-		modulename, modulename);
-	return (HINSTANCE) NULL;
-    }
-
-    fullname = GetDosFileName(fullname);
-    WIN_ProgramName = strdup(fullname);
-    
-    fprintf(stderr,"LoadImage: loading %s (%s)\n           [%s]\n", 
-	    modulename, buffer, WIN_ProgramName);
-
-    if (change_dir && fullname)
-    {
-	char dirname[256];
-	char *p;
-
-	strcpy(dirname, fullname);
-	p = strrchr(dirname, '\\');
-	*p = '\0';
-
-	DOS_SetDefaultDrive(dirname[0] - 'A');
-	DOS_ChangeDir(dirname[0] - 'A', dirname + 2);
-    }
-
-    /* First allocate a spot to store the info we collect, and add it to
-     * our linked list.
-     */
-
-    wpnt = (struct w_files *) malloc(sizeof(struct w_files));
-    if(wine_files == NULL)
-      wine_files = wpnt;
-    else {
-      wpnt1 = wine_files;
-      while(wpnt1->next) wpnt1 =  wpnt1->next;
-      wpnt1->next  = wpnt;
-    };
-    wpnt->next = NULL;
-
-    /*
-     * Open file for reading.
-     */
-    wpnt->fd = open(buffer, O_RDONLY);
-    if (wpnt->fd < 0)
-    {
-	myerror(NULL);
-    }
-    /*
-     * Establish header pointers.
-     */
-    wpnt->filename = strdup(buffer);
-    wpnt->name = NULL;
-    if(modulename)  wpnt->name = strdup(modulename);
-
-    wpnt->mz_header = (struct mz_header_s *) malloc(sizeof(struct mz_header_s));;
-    status = lseek(wpnt->fd, 0, SEEK_SET);
-    load_mz_header (wpnt->fd, wpnt->mz_header);
-    if (wpnt->mz_header->must_be_0x40 != 0x40)
-	myerror("This is not a Windows program");
-    
-    wpnt->ne_header = (struct ne_header_s *) malloc(sizeof(struct ne_header_s));
-    status = lseek(wpnt->fd, wpnt->mz_header->ne_offset, SEEK_SET);
-    load_ne_header (wpnt->fd, wpnt->ne_header);
-    if (wpnt->ne_header->header_type[0] != 'N' || 
-	wpnt->ne_header->header_type[1] != 'E')
-      myerror("This is not a Windows program");
-
-    if(wine_files ==  wpnt){
-      CurrentMZHeader = wpnt->mz_header;
-      CurrentNEHeader = wpnt->ne_header;
-      CurrentNEFile   = wpnt->fd;
-      
-      WIN_StackSize = wpnt->ne_header->stack_length;
-      WIN_HeapSize = wpnt->ne_header->local_heap_length;
-    };
-
-    /*
-     * Create segment selectors.
-     */
-#ifndef WINELIB
-    status = lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
-		   wpnt->ne_header->segment_tab_offset,
-		   SEEK_SET);
-    read_size  = wpnt->ne_header->n_segment_tab *
-	         sizeof(struct ne_segment_table_entry_s);
-    wpnt->seg_table = (struct ne_segment_table_entry_s *) malloc(read_size);
-    if (read(wpnt->fd, wpnt->seg_table, read_size) != read_size)
-	myerror("Unable to read segment table header from file");
-    wpnt->selector_table = CreateSelectors(wpnt);
-    wpnt->hinstance 
-	= wpnt->
-	    selector_table[wpnt->ne_header->auto_data_seg-1].selector;
-
-    /* Get the lookup  table.  This is used for looking up the addresses
-       of functions that are exported */
-
-    read_size  = wpnt->ne_header->entry_tab_length;
-    wpnt->lookup_table = (char *) malloc(read_size);
-    lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
-	  wpnt->ne_header->entry_tab_offset, SEEK_SET);
-    if (read(wpnt->fd, wpnt->lookup_table, read_size) != read_size)
-	myerror("Unable to read lookup table header from file");
-
-    /* Get the iname table.  This is used for looking up the names
-       of functions that are exported */
-
-    status = lseek(wpnt->fd, wpnt->ne_header->nrname_tab_offset,  SEEK_SET);
-    read_size  = wpnt->ne_header->nrname_tab_length;
-    wpnt->nrname_table = (char *) malloc(read_size);
-    if (read(wpnt->fd, wpnt->nrname_table, read_size) != read_size)
-	myerror("Unable to read nrname table header from file");
-
-    status = lseek(wpnt->fd, wpnt->mz_header->ne_offset + 
-		   wpnt->ne_header->rname_tab_offset,  SEEK_SET);
-    read_size  = wpnt->ne_header->moduleref_tab_offset - 
-	    wpnt->ne_header->rname_tab_offset;
-    wpnt->rname_table = (char *) malloc(read_size);
-    if (read(wpnt->fd, wpnt->rname_table, read_size) != read_size)
-	myerror("Unable to read rname table header from file");
-
-    /* Now get the module name */
-
-    wpnt->name  = (char*) malloc(*wpnt->rname_table + 1);
-    memcpy(wpnt->name, wpnt->rname_table+1, *wpnt->rname_table);
-    wpnt->name[*wpnt->rname_table] =  0;
-#endif
-    /*
-     * Now load any DLLs that  this module refers to.
-     */
-    for(i=0; i<wpnt->ne_header->n_mod_ref_tab; i++){
-      char buff[14];
-      char buff2[256];
-      int  fd, j;
-      GetModuleName(wpnt, i + 1, buff);
-      
-#ifndef WINELIB
-      if(FindDLLTable(buff)) continue;  /* This module already loaded */
-#endif
-
-      LoadImage(buff, DLL, 0);
-/*
-      fprintf(stderr,"Unable to load:%s\n",  buff);
-*/
-    }
-return(wpnt->hinstance);
-}
-
-
-/**********************************************************************
- *					main
- */
-_WinMain(int argc, char **argv)
-{
-	int segment;
-	char *p;
-	char *sysresname;
-	char filename[100];
-	char syspath[256];
-	char exe_path[256];
-#ifdef WINESTAT
-	char * cp;
-#endif
-	struct w_files * wpnt;
-	int cs_reg, ds_reg, ss_reg, ip_reg, sp_reg;
-	int i;
-	int rv;
-
-	Argc = argc - 1;
-	Argv = argv + 1;
-	
-	WinePath = malloc(1024);
-	
-	getcwd(WinePath, 512);
-	
-	if ((p = getenv("WINEPATH")) != NULL) { 
-		strcat(WinePath, ";");
-		strcat(WinePath, p);
-	}
-	
-	if ((hInstMain = LoadImage(Argv[0], EXE, 1)) == (HINSTANCE) NULL ) {
-		fprintf(stderr, "wine: can't find %s!.\n", Argv[0]);
-		exit(1);
-	}
-
-	GetPrivateProfileString("wine", "SystemResources", "sysres.dll", 
-				filename, sizeof(filename), WINE_INI);
-
-	hSysRes = LoadImage(filename, DLL);
-	if (hSysRes == (HINSTANCE)NULL)
-		fprintf(stderr, "wine: can't find %s!\n", filename);
- 	else
- 	    printf("System Resources Loaded // hSysRes='%04X'\n", hSysRes);
-	
-    /*
-     * Fixup references.
-     */
-    wpnt = wine_files;
-    for(wpnt = wine_files; wpnt; wpnt = wpnt->next)
-    {
-	for (segment = 0; segment < wpnt->ne_header->n_segment_tab; segment++)
-	{
-	    if (FixupSegment(wpnt, segment) < 0)
-	    {
-		myerror("fixup failed.");
-	    }
-	}
-    }
-
-#ifdef WINESTAT
-    cp = strrchr(argv[0], '/');
-    if(!cp) cp = argv[0];
-	else cp++;
-    if(strcmp(cp,"winestat") == 0) {
-	    winestat();
-	    exit(0);
-    };
-#endif
-
-    /*
-     * Initialize signal handling.
-     */
-    init_wine_signals();
-
-    /*
-     * Fixup stack and jump to start.
-     */
-    ds_reg = (wine_files->
-	      selector_table[wine_files->ne_header->auto_data_seg-1].selector);
-    cs_reg = wine_files->selector_table[wine_files->ne_header->cs-1].selector;
-    ip_reg = wine_files->ne_header->ip;
-    ss_reg = wine_files->selector_table[wine_files->ne_header->ss-1].selector;
-    sp_reg = wine_files->ne_header->sp;
-
-    if (Options.debug) wine_debug(0, NULL);
-
-    rv = CallToInit16(cs_reg << 16 | ip_reg, ss_reg << 16 | sp_reg, ds_reg);
-    printf ("rv = %x\n", rv);
-}
-
-void InitializeLoadedDLLs()
-{
-    struct w_files * wpnt;
-    int cs_reg, ds_reg, ip_reg;
-    int rv;
-
-    fprintf(stderr, "Initializing DLLs\n");
-
-    /*
-     * Initialize libraries
-     */
-    wpnt = wine_files;
-    for(wpnt = wine_files; wpnt; wpnt = wpnt->next)
-    {
-	/* 
-	 * Is this a library? 
-	 */
-	if (wpnt->ne_header->format_flags & 0x8000)
-	{
-	    if (!(wpnt->ne_header->format_flags & 0x0001))
-	    {
-		/* Not SINGLEDATA */
-		fprintf(stderr, "Library is not marked SINGLEDATA\n");
-		exit(1);
-	    }
-
-	    ds_reg = wpnt->selector_table[wpnt->
-					  ne_header->auto_data_seg-1].selector;
-	    cs_reg = wpnt->selector_table[wpnt->ne_header->cs-1].selector;
-	    ip_reg = wpnt->ne_header->ip;
-
-	    fprintf(stderr, "Initializing %s, cs:ip %04x:%04x, ds %04x\n", 
-		    wpnt->name, cs_reg, ip_reg, ds_reg);
-
-	    rv = CallTo16(cs_reg << 16 | ip_reg, ds_reg);
-	    printf ("rv = %x\n", rv);
-	}
-    }
-}
-
-
-/**********************************************************************
- *					GetImportedName
- */
-char *
-GetImportedName(int fd, struct mz_header_s *mz_header, 
-		struct ne_header_s *ne_header, int name_offset, char *buffer)
-{
-    char *p;
-    int length;
-    int status;
-    int i;
-    
-    status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
-		   name_offset, SEEK_SET);
-    length = 0;
-    read(fd, &length, 1);  /* Get the length byte */
-    length = CONV_CHAR_TO_LONG (length);
-    read(fd, buffer, length);
-    buffer[length] = 0;
-    return buffer;
-}
-
-/**********************************************************************
- *					GetModuleName
- */
-char *
-GetModuleName(struct w_files * wpnt, int index, char *buffer)
-{
-    int fd = wpnt->fd;
-    struct mz_header_s *mz_header = wpnt->mz_header; 
-    struct ne_header_s *ne_header = wpnt->ne_header;
-    char *p;
-    int length;
-    WORD name_offset, status;
-    int i;
-    
-    status = lseek(fd, mz_header->ne_offset + ne_header->moduleref_tab_offset +
-		   2*(index - 1), SEEK_SET);
-    name_offset = 0;
-    read(fd, &name_offset, 2);
-    name_offset = CONV_SHORT (name_offset);
-    status = lseek(fd, mz_header->ne_offset + ne_header->iname_tab_offset +
-		   name_offset, SEEK_SET);
-    length = 0;
-    read(fd, &length, 1);  /* Get the length byte */
-    length = CONV_CHAR_TO_LONG (length);
-    read(fd, buffer, length);
-    buffer[length] = 0;
-
-    /* Module names  are always upper case */
-    for(i=0; i<length; i++)
-	    if(buffer[i] >= 'a' && buffer[i] <= 'z')  buffer[i] &= ~0x20;
-
-    return buffer;
-}
-
-
-#ifndef WINELIB
-/**********************************************************************
- *					FixupSegment
- */
-int
-FixupSegment(struct w_files * wpnt, int segment_num)
-{
-    int fd =  wpnt->fd;
-    struct mz_header_s * mz_header = wpnt->mz_header;
-    struct ne_header_s *ne_header =  wpnt->ne_header;
-    struct ne_segment_table_entry_s *seg_table = wpnt->seg_table;
-    struct segment_descriptor_s *selector_table = wpnt->selector_table;
-    struct relocation_entry_s *rep, *rep1;
-    struct ne_segment_table_entry_s *seg;
-    struct segment_descriptor_s *sel;
-    struct dll_table_entry_s *dll_table;
-    int status;
-    unsigned short *sp;
-    unsigned int selector, address;
-    unsigned int next_addr;
-    int ordinal;
-    char dll_name[257];
-    char func_name[257];
-    int i, n_entries;
-    int additive;
-
-    seg = &seg_table[segment_num];
-    sel = &selector_table[segment_num];
-
-#ifdef DEBUG_FIXUP
-    printf("Segment fixups for %s, segment %d, selector %x\n", 
-	   wpnt->name, segment_num, (int) sel->base_addr >> 16);
-#endif
-
-    if ((seg->seg_data_offset == 0) ||
-	!(seg->seg_flags & NE_SEGFLAGS_RELOC_DATA))
-	return 0;
-
-    /*
-     * Go through the relocation table on entry at a time.
-     */
-    i = seg->seg_data_length;
-    if (i == 0)
-	i = 0x10000;
-
-    status = lseek(fd, seg->seg_data_offset * 
-		       (1 << ne_header->align_shift_count) + i, SEEK_SET);
-    n_entries = 0;
-    read(fd, &n_entries, sizeof(short int));
-    rep = (struct relocation_entry_s *)
-	  malloc(n_entries * sizeof(struct relocation_entry_s));
-
-    if (read(fd,rep, n_entries * sizeof(struct relocation_entry_s)) !=
-        n_entries * sizeof(struct relocation_entry_s))
-    {
-	myerror("Unable to read relocation information");
-    }
-    
-    rep1 = rep;
-
-    for (i = 0; i < n_entries; i++, rep++)
-    {
-	/*
-	 * Get the target address corresponding to this entry.
-	 */
-	additive = 0;
-	
-	switch (rep->relocation_type)
-	{
-	  case NE_RELTYPE_ORDINALADD:
-	    additive = 1;
-	    
-	  case NE_RELTYPE_ORDINAL:
-	    if (GetModuleName(wpnt, rep->target1,
-			      dll_name) == NULL)
-	    {
-	      fprintf(stderr, "NE_RELTYPE_ORDINAL failed");
-		return -1;
-	    }
-	    
-	    ordinal = rep->target2;
-
-  	    status = GetEntryDLLOrdinal(dll_name, ordinal, &selector,
-					&address);
-	    if (status)
-	    {
-		char s[80];
-		
-		sprintf(s, "Bad DLL name '%s.%d'", dll_name, ordinal);
-		myerror(s);
-		return -1;
-	    }
-
-#ifdef DEBUG_FIXUP
-	    printf("%d: %s.%d: %04.4x:%04.4x\n", i + 1, dll_name, ordinal,
-		   selector, address);
-#endif
-	    break;
-	    
-	  case NE_RELTYPE_NAMEADD:
-	    additive = 1;
-	    
-	  case NE_RELTYPE_NAME:
-	    if (GetModuleName(wpnt, rep->target1, dll_name)
-		== NULL)
-	    {
-	      fprintf(stderr,"NE_RELTYPE_NAME failed");
-		return -1;
-	    }
-
-	    if (GetImportedName(fd, mz_header, ne_header, 
-				rep->target2, func_name) == NULL)
-	    {
-	      fprintf(stderr,"getimportedname failed");
-		return -1;
-	    }
-
-  	    status = GetEntryDLLName(dll_name, func_name, &selector, 
-					   &address);
-	    if (status)
-	    {
-		char s[80];
-		
-		sprintf(s, "Bad DLL name '%s (%s)'", dll_name,func_name);
-		myerror(s);
-		return -1;
-	    }
-
-#ifdef DEBUG_FIXUP
-	    printf("%d: %s %s.%d: %04.4x:%04.4x\n", i + 1, func_name,
-		   dll_name, ordinal, selector, address);
-#endif
-	    break;
-	    
-	  case NE_RELTYPE_INTERNAL:
-    	  case NE_RELTYPE_INT1:
-	    if (rep->target1 == 0x00ff)
-	    {
-		address  = GetEntryPointFromOrdinal(wpnt, rep->target2);
-		selector = (address >> 16) & 0xffff;
-		address &= 0xffff;
-	    }
-	    else
-	    {
-		selector = selector_table[rep->target1-1].selector;
-		address  = rep->target2;
-	    }
-	    
-#ifdef DEBUG_FIXUP
-	    printf("%d: %04.4x:%04.4x\n", i + 1, selector, address);
-#endif
-	    break;
-
-	  case 7:
-	    /* Relocation type 7:
-	     *
-	     *    These appear to be used as fixups for the Windows
-	     * floating point emulator.  Let's just ignore them and
-	     * try to use the hardware floating point.  Linux should
-	     * successfully emulate the coprocessor if it doesn't
-	     * exist.
-	     */
-#ifdef DEBUG_FIXUP
-	    printf("%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
-		   i + 1, rep->address_type, rep->relocation_type, 
-		   rep->offset);
-	    printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
-#endif
-	    continue;
-	    
-	  default:
-	    fprintf(stderr,"%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
-		   i + 1, rep->address_type, rep->relocation_type, 
-		   rep->offset);
-	    fprintf(stderr,"TARGET %04.4x %04.4x\n", 
-		    rep->target1, rep->target2);
-	    free(rep1);
-	    return -1;
-	}
-
-	/*
-	 * Stuff the right size result in.
-	 */
-	sp = (unsigned short *) ((char *) sel->base_addr + rep->offset);
-	if (additive)
-	{
-	    if (FindDLLTable(dll_name) == NULL)
-		additive = 2;
-
-	    fprintf(stderr,"%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
-		   i + 1, rep->address_type, rep->relocation_type, 
-		   rep->offset);
-	    fprintf(stderr,"TARGET %04.4x %04.4x\n", 
-		    rep->target1, rep->target2);
-	    fprintf(stderr, "    Additive = %d\n", additive);
-	}
-	
-	switch (rep->address_type)
-	{
-	  case NE_RADDR_OFFSET16:
-	    do {
-#ifdef DEBUG_FIXUP
-		printf("    %04.4x:%04.4x:%04.4x OFFSET16\n",
-		       (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
-#endif
-		next_addr = *sp;
-		*sp = (unsigned short) address;
-		if (additive == 2)
-		    *sp += next_addr;
-		sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
-	    } 
-	    while (next_addr != 0xffff && !additive);
-
-	    break;
-	    
-	  case NE_RADDR_POINTER32:
-	    do {
-#ifdef DEBUG_FIXUP
-		printf("    %04.4x:%04.4x:%04.4x POINTER32\n",
-		       (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
-#endif
-		next_addr = *sp;
-		*sp     = (unsigned short) address;
-		if (additive == 2)
-		    *sp += next_addr;
-		*(sp+1) = (unsigned short) selector;
-		sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
-	    } 
-	    while (next_addr != 0xffff && !additive);
-
-	    break;
-	    
-	  case NE_RADDR_SELECTOR:
-	    do {
-#ifdef DEBUG_FIXUP
-		printf("    %04.4x:%04.4x:%04.4x SELECTOR\n",
-		       (unsigned long) sp >> 16, (int) sp & 0xFFFF, *sp);
-#endif
-		next_addr = *sp;
-		*sp     = (unsigned short) selector;
-		sp = (unsigned short *) ((char *) sel->base_addr + next_addr);
-		if (rep->relocation_type == NE_RELTYPE_INT1) 
-		    break;
-	    } 
-	    while (next_addr != 0xffff && !additive);
-
-	    break;
-	    
-	  default:
-	    printf("%d: ADDR TYPE %d,  TYPE %d,  OFFSET %04.4x,  ",
-		   i + 1, rep->address_type, rep->relocation_type, 
-		   rep->offset);
-	    printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2);
-	    free(rep1);
-	    return -1;
-	}
-    }
-
-    free(rep1);
-    return 0;
-}
-
-/**********************************************************************
- *					GetProcAddress
- */
-FARPROC GetProcAddress(HINSTANCE hinstance, char *proc_name)
-{
-    if ((int) proc_name & 0xffff0000)
-	printf("GetProcAddress: %#04x, '%s'\n", hinstance, proc_name);
-    else
-	printf("GetProcAddress: %#04x, %d\n", hinstance, (int) proc_name);
-
-    return NULL;
-}
-#endif
diff --git a/memory/Makefile.in b/memory/Makefile.in
index e056dce..791bdae 100644
--- a/memory/Makefile.in
+++ b/memory/Makefile.in
@@ -32,7 +32,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/memory/atom.c b/memory/atom.c
index db76863..359158c 100644
--- a/memory/atom.c
+++ b/memory/atom.c
@@ -22,6 +22,11 @@
 #include "stackframe.h"
 #include "user.h"
 
+#ifdef CONFIG_IPC
+#include "dde_atom.h"
+#include "options.h"
+#endif
+
 #define DEFAULT_ATOMTABLE_SIZE    37
 #define MIN_STR_ATOM              0xc000
 
@@ -321,36 +326,48 @@
 
 
 /***********************************************************************
- *           LocalAddAtom   (USER.268)
+ *           GlobalAddAtom   (USER.268)
  */
-ATOM LocalAddAtom( SEGPTR str )
+ATOM GlobalAddAtom( SEGPTR str )
 {
+#ifdef CONFIG_IPC
+    if (Options.ipc) return DDE_GlobalAddAtom( str );
+#endif
     return ATOM_AddAtom( USER_HeapSel, str );
 }
 
 
 /***********************************************************************
- *           LocalDeleteAtom   (USER.269)
+ *           GlobalDeleteAtom   (USER.269)
  */
-ATOM LocalDeleteAtom( ATOM atom )
+ATOM GlobalDeleteAtom( ATOM atom )
 {
+#ifdef CONFIG_IPC
+    if (Options.ipc) return DDE_GlobalDeleteAtom( atom );
+#endif
     return ATOM_DeleteAtom( USER_HeapSel, atom );
 }
 
 
 /***********************************************************************
- *           LocalFindAtom   (USER.270)
+ *           GlobalFindAtom   (USER.270)
  */
-ATOM LocalFindAtom( SEGPTR str )
+ATOM GlobalFindAtom( SEGPTR str )
 {
+#ifdef CONFIG_IPC
+    if (Options.ipc) return DDE_GlobalFindAtom( str );
+#endif
     return ATOM_FindAtom( USER_HeapSel, str );
 }
 
 
 /***********************************************************************
- *           LocalGetAtomName   (USER.271)
+ *           GlobalGetAtomName   (USER.271)
  */
-WORD LocalGetAtomName( ATOM atom, LPSTR buffer, short count )
+WORD GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
 {
+#ifdef CONFIG_IPC
+    if (Options.ipc) return DDE_GlobalGetAtomName( atom, buffer, count );
+#endif
     return ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
 }
diff --git a/memory/global.c b/memory/global.c
index 704fe9d..83f0dda 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -81,21 +81,6 @@
     if (printed)
 	printf("\n");
 }
-/***********************************************************************
- *           GLOBAL_FindArena
- *
- * Find the arena  for a given handle
- * (when handle is not serial - e.g. DDE)
- */
-static GLOBALARENA *GLOBAL_FindArena( HGLOBAL handle)
-{
-    int i;
-    for (i = globalArenaSize-1 ; i>=0 ; i--) {
-	if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
-	    return ( &pGlobalArena[i] );
-    }
-    return NULL;
-}
 
 
 /***********************************************************************
@@ -196,9 +181,11 @@
 
       /* Allocate the linear memory */
 
+#ifdef CONFIG_IPC
     if ((flags & GMEM_DDESHARE) && Options.ipc)
-        ptr= DDE_malloc(flags, size, &shmdata);
+        ptr = DDE_malloc(flags, size, &shmdata);
     else 
+#endif  /* CONFIG_IPC */
 	ptr = malloc( size );
     if (!ptr) return 0;
 
@@ -216,6 +203,25 @@
     return handle;
 }
 
+
+#ifdef CONFIG_IPC
+/***********************************************************************
+ *           GLOBAL_FindArena
+ *
+ * Find the arena  for a given handle
+ * (when handle is not serial - e.g. DDE)
+ */
+static GLOBALARENA *GLOBAL_FindArena( HGLOBAL handle)
+{
+    int i;
+    for (i = globalArenaSize-1 ; i>=0 ; i--) {
+	if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
+	    return ( &pGlobalArena[i] );
+    }
+    return NULL;
+}
+
+
 /***********************************************************************
  *           DDE_GlobalHandleToSel
  */
@@ -238,6 +244,7 @@
 
     return SELECTOROF( segptr );
 }
+#endif  /* CONFIG_IPC */
 
 
 /***********************************************************************
@@ -268,11 +275,13 @@
                     handle, size, flags );
     if (!handle) return 0;
     
+#ifdef CONFIG_IPC
     if (Options.ipc && (flags & GMEM_DDESHARE || is_dde_handle(handle))) {
 	fprintf(stdnimp,
 		"GlobalReAlloc: shared memory reallocating unimplemented\n"); 
 	return 0;
     }
+#endif  /* CONFIG_IPC */
 
     pArena = GET_ARENA_PTR( handle );
 
@@ -366,7 +375,9 @@
 
     dprintf_global( stddeb, "GlobalFree: %04x\n", handle );
     if (!GLOBAL_FreeBlock( handle )) return handle;  /* failed */
+#ifdef CONFIG_IPC
     if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
+#endif  /* CONFIG_IPC */
     if (ptr) free( ptr );
     return 0;
 }
@@ -382,9 +393,13 @@
     dprintf_global( stddeb, "WIN16_GlobalLock(%04x) -> %08lx\n",
                     handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
     if (!handle) return 0;
-    if ( !is_dde_handle(handle) && !GET_ARENA_PTR(handle)->base)
-	return (SEGPTR)0;
 
+#ifdef CONFIG_IPC
+    if (is_dde_handle(handle))
+        return (SEGPTR)MAKELONG( 0, DDE_GlobalHandleToSel(handle) );
+#endif  /* CONFIG_IPC */
+
+    if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
     return (SEGPTR)MAKELONG( 0, GlobalHandleToSel(handle) );
 }
 
@@ -397,9 +412,9 @@
 LPSTR GlobalLock( HGLOBAL handle )
 {
     if (!handle) return 0;
-    if (is_dde_handle(handle)) {
-       return DDE_AttachHandle(handle, NULL);
-    }
+#ifdef CONFIG_IPC
+    if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
+#endif
     return (LPSTR)GET_ARENA_PTR(handle)->base;
 }
 
@@ -644,9 +659,9 @@
 {
     dprintf_toolhelp( stddeb, "GlobalHandleToSel: %04x\n", handle );
     if (!handle) return 0;
-    if (is_dde_handle(handle)) 
-	return DDE_GlobalHandleToSel(handle);
-
+#ifdef CONFIG_IPC
+    if (is_dde_handle(handle)) return DDE_GlobalHandleToSel(handle);
+#endif
     if (!(handle & 7))
     {
         fprintf( stderr, "Program attempted invalid selector conversion\n" );
diff --git a/misc/Makefile.in b/misc/Makefile.in
index c2bdaa7..f2b4a96 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -36,7 +36,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/misc/clipboard.c b/misc/clipboard.c
index e11c4a8..fef309d 100644
--- a/misc/clipboard.c
+++ b/misc/clipboard.c
@@ -143,6 +143,7 @@
 {
     LPCLIPFORMAT lpFormat = ClipFormats; 
     dprintf_clipboard(stddeb,"GetClipboardData(%04X) !\n", wFormat);
+    if (!hWndClipboardOwner) return 0;
     if(wFormat == CF_TEXT && !wineOwnsSelection)
     {	wait_for_selection=True;
         dprintf_clipboard(stddeb,"Requesting selection\n");
diff --git a/misc/file.c b/misc/file.c
index 895e180..c3dc3ed 100644
--- a/misc/file.c
+++ b/misc/file.c
@@ -75,7 +75,7 @@
   dprintf_file(stddeb, "_lread: handle %d, buffer = %p, length = %d\n",
 	  		hFile, lpBuffer, wBytes);
   
-  result = wBytes == 0 ? 0 : read (hFile, lpBuffer, wBytes);
+  result = (wBytes == 0) ? 0 : read (hFile, lpBuffer, wBytes);
 
   if (result == -1)
   	return HFILE_ERROR;
@@ -454,12 +454,12 @@
  ***************************************************************************/
 LONG _hread(INT hf, LPSTR hpvBuffer, LONG cbBuffer)
 {
-    return cbBuffer == 0 ? 0 : read(hf, hpvBuffer, cbBuffer);
+    return (cbBuffer == 0) ? 0 : read(hf, hpvBuffer, cbBuffer);
 }
 /***************************************************************************
  _hwrite
  ***************************************************************************/
 LONG _hwrite(INT hf, LPCSTR hpvBuffer, LONG cbBuffer)
 {
-    return cbBuffer == 0 ? 0 : write(hf, hpvBuffer, cbBuffer);
+    return (cbBuffer == 0) ? 0 : write(hf, hpvBuffer, cbBuffer);
 }
diff --git a/misc/main.c b/misc/main.c
index 1eb750c..ceb206d 100644
--- a/misc/main.c
+++ b/misc/main.c
@@ -846,3 +846,27 @@
 {
 	printf("FileCDR(%8x)\n", (int) x);
 }
+
+/***********************************************************************
+*	GetWinDebugInfo (KERNEL.355)
+*/
+BOOL GetWinDebugInfo(WINDEBUGINFO FAR* lpwdi, UINT flags)
+{
+	printf("GetWinDebugInfo(%8lx,%d) stub returning 0\n", (unsigned long)lpwdi, flags);
+	/* 0 means not in debugging mode/version */
+	/* Can this type of debugging be used in wine ? */
+	/* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
+	return 0;
+}
+
+/***********************************************************************
+*	GetWinDebugInfo (KERNEL.355)
+*/
+BOOL SetWinDebugInfo(WINDEBUGINFO FAR* lpwdi)
+{
+	printf("SetWinDebugInfo(%8lx) stub returning 0\n", (unsigned long)lpwdi);
+	/* 0 means not in debugging mode/version */
+	/* Can this type of debugging be used in wine ? */
+	/* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
+	return 0;
+}
diff --git a/misc/profile.c b/misc/profile.c
index 3a400d7..d9067b1 100644
--- a/misc/profile.c
+++ b/misc/profile.c
@@ -382,6 +382,8 @@
 BOOL WritePrivateProfileString (LPSTR AppName, LPSTR KeyName, LPSTR String,
 				LPSTR FileName)
 {
+    if (!AppName || !KeyName || !String)  /* Flush file to disk */
+        return TRUE;
     return GetSetProfile (1, AppName, KeyName, String, "", 0, FileName);
 }
 
diff --git a/misc/shell.c b/misc/shell.c
index 2157470..758feb2 100644
--- a/misc/shell.c
+++ b/misc/shell.c
@@ -450,10 +450,14 @@
  */
 INT AboutDlgProc(HWND hWnd, WORD msg, WORD wParam, LONG lParam)
 {
+  char Template[512], AppTitle[512];
+ 
   switch(msg) {
    case WM_INITDIALOG:
     SendDlgItemMessage(hWnd,stc1,STM_SETICON,LOWORD(lParam),0);
-    SetWindowText(hWnd, AppName);
+    GetWindowText(hWnd, Template, 511);
+    sprintf(AppTitle, Template, AppName);
+    SetWindowText(hWnd, AppTitle);
     SetWindowText(GetDlgItem(hWnd,100), AppMisc);
     return 1;
     
@@ -474,7 +478,7 @@
 INT ShellAbout(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon)
 {
   if (szApp) {
-    sprintf(AppName, "About %s", szApp);
+    strcpy(AppName, szApp);
   } else  {
     *AppName = 0;
   }
diff --git a/miscemu/Imakefile b/miscemu/Imakefile
index 74a89df..60adb1a 100644
--- a/miscemu/Imakefile
+++ b/miscemu/Imakefile
@@ -3,6 +3,7 @@
 MODULE = miscemu
 
 SRCS = \
+	dosmem.c \
 	dpmi.c \
 	emulate.c \
 	instr.c \
diff --git a/miscemu/Makefile.in b/miscemu/Makefile.in
index c9af5ea..426097d 100644
--- a/miscemu/Makefile.in
+++ b/miscemu/Makefile.in
@@ -9,9 +9,22 @@
 
 MODULE 	= miscemu
 
-SRCS 	= dpmi.c emulate.c instr.c int10.c int13.c \
-        int1a.c int21.c int25.c int26.c int2a.c int2f.c int5c.c interrupts.c \
-        ioports.c
+SRCS = \
+	dosmem.c \
+	dpmi.c \
+	emulate.c \
+	instr.c \
+	int10.c \
+	int13.c \
+	int1a.c \
+	int21.c \
+	int25.c \
+	int26.c \
+	int2a.c \
+	int2f.c \
+	int5c.c \
+	interrupts.c \
+	ioports.c
 
 OBJS = $(SRCS:.c=.o)
 
@@ -29,7 +42,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/miscemu/dosmem.c b/miscemu/dosmem.c
new file mode 100644
index 0000000..4ac0444
--- /dev/null
+++ b/miscemu/dosmem.c
@@ -0,0 +1,184 @@
+/*
+ * DOS memory emulation
+ *
+ * Copyright 1995 Alexandre Julliard
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "windows.h"
+#include "global.h"
+#include "ldt.h"
+#include "miscemu.h"
+#include "module.h"
+
+
+HANDLE DOSMEM_BiosSeg;  /* BIOS data segment at 0x40:0 */
+
+
+#pragma pack(1)
+
+typedef struct
+{
+    WORD  Com1Addr;                  /* 00: COM1 I/O address */
+    WORD  Com2Addr;                  /* 02: COM2 I/O address */
+    WORD  Com3Addr;                  /* 04: COM3 I/O address */
+    WORD  Com4Addr;                  /* 06: COM4 I/O address */
+    WORD  Lpt1Addr;                  /* 08: LPT1 I/O address */
+    WORD  Lpt2Addr;                  /* 0a: LPT2 I/O address */
+    WORD  Lpt3Addr;                  /* 0c: LPT3 I/O address */
+    WORD  Lpt4Addr;                  /* 0e: LPT4 I/O address */
+    WORD  InstalledHardware;         /* 10: Installed hardware flags */
+    BYTE  POSTstatus;                /* 12: Power-On Self Test status */
+    WORD  MemSize WINE_PACKED;       /* 13: Base memory size in Kb */
+    WORD  unused1 WINE_PACKED;       /* 15: Manufacturing test scratch pad */
+    BYTE  KbdFlags1;                 /* 17: Keyboard flags 1 */
+    BYTE  KbdFlags2;                 /* 18: Keyboard flags 2 */
+    BYTE  unused2;                   /* 19: Keyboard driver workspace */
+    WORD  NextKbdCharPtr;            /* 1a: Next character in kbd buffer */
+    WORD  FirstKbdCharPtr;           /* 1c: First character in kbd buffer */
+    WORD  KbdBuffer[16];             /* 1e: Keyboard buffer */
+    BYTE  DisketteStatus1;           /* 3e: Diskette recalibrate status */
+    BYTE  DisketteStatus2;           /* 3f: Diskette motor status */
+    BYTE  DisketteStatus3;           /* 40: Diskette motor timeout */
+    BYTE  DisketteStatus4;           /* 41: Diskette last operation status */
+    BYTE  DiskStatus[7];             /* 42: Disk status/command bytes */
+    BYTE  VideoMode;                 /* 49: Video mode */
+    WORD  VideoColumns;              /* 4a: Number of columns */
+    WORD  VideoPageSize;             /* 4c: Video page size in bytes */
+    WORD  VideoPageStartAddr;        /* 4e: Video page start address */
+    BYTE  VideoCursorPos[16];        /* 50: Cursor position for 8 pages */
+    WORD  VideoCursorType;           /* 60: Video cursor type */
+    BYTE  VideoCurPage;              /* 62: Video current page */
+    WORD  VideoCtrlAddr WINE_PACKED; /* 63: Video controller address */
+    BYTE  VideoReg1;                 /* 65: Video mode select register */
+    BYTE  VideoReg2;                 /* 66: Video CGA palette register */
+    DWORD ResetEntry WINE_PACKED;    /* 67: Warm reset entry point */
+    BYTE  LastIRQ;                   /* 6b: Last unexpected interrupt */
+    DWORD Ticks;                     /* 6c: Ticks since midnight */
+    BYTE  TicksOverflow;             /* 70: Timer overflow if past midnight */
+    BYTE  CtrlBreakFlag;             /* 71: Ctrl-Break flag */
+    WORD  ResetFlag;                 /* 72: POST Reset flag */
+    BYTE  DiskOpStatus;              /* 74: Last hard-disk operation status */
+    BYTE  NbHardDisks;               /* 75: Number of hard disks */
+    BYTE  DiskCtrlByte;              /* 76: Disk control byte */
+    BYTE  DiskIOPort;                /* 77: Disk I/O port offset */
+    BYTE  LptTimeout[4];             /* 78: Timeouts for parallel ports */
+    BYTE  ComTimeout[4];             /* 7c: Timeouts for serial ports */
+    WORD  KbdBufferStart;            /* 80: Keyboard buffer start */
+    WORD  KbdBufferEnd;              /* 82: Keyboard buffer end */
+} BIOSDATA;
+
+#pragma pack(4)
+
+
+static BIOSDATA *pBiosData = NULL;
+
+
+/***********************************************************************
+ *           DOSMEM_Init
+ *
+ * Create the dos memory segments, and store them into the KERNEL
+ * exported values. MODULE_Init() must already have been called.
+ */
+BOOL DOSMEM_Init(void)
+{
+    HMODULE hModule = GetModuleHandle( "KERNEL" );
+    char *dosmem;
+
+    /* Allocate 7 64k segments for 0000, A000, B000, C000, D000, E000, F000. */
+
+    dosmem = malloc( 0x70000 );
+
+    MODULE_SetEntryPoint( hModule, 183,  /* KERNEL.183: __0000H */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    DOSMEM_BiosSeg = GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x400, 0x100,
+                                         hModule, FALSE, FALSE, FALSE, NULL );
+
+    MODULE_SetEntryPoint( hModule, 193,  /* KERNEL.193: __0040H */
+                          DOSMEM_BiosSeg );
+    MODULE_SetEntryPoint( hModule, 174,  /* KERNEL.174: __A000H */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x10000,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    MODULE_SetEntryPoint( hModule, 181,  /* KERNEL.181: __B000H */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x20000,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    MODULE_SetEntryPoint( hModule, 182,  /* KERNEL.182: __B800H */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x28000,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    MODULE_SetEntryPoint( hModule, 195,  /* KERNEL.195: __C000H */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x30000,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    MODULE_SetEntryPoint( hModule, 179,  /* KERNEL.179: __D000H */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x40000,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    MODULE_SetEntryPoint( hModule, 190,  /* KERNEL.190: __E000H */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x50000,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    MODULE_SetEntryPoint( hModule, 173,  /* KERNEL.173: __ROMBIOS */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x60000,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    MODULE_SetEntryPoint( hModule, 194,  /* KERNEL.194: __F000H */
+                          GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x60000,
+                                0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
+    DOSMEM_FillBiosSegment();
+
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           DOSMEM_Alarm
+ *
+ * Increment the BIOS tick counter.
+ */
+static void DOSMEM_Alarm(void)
+{
+    pBiosData->Ticks = INT1A_GetTicksSinceMidnight();
+    printf( "Ticks = %d\n", pBiosData->Ticks );
+/*
+    signal( SIGALRM, DOSMEM_Alarm );
+    alarm( 1 );
+*/
+}
+
+
+/***********************************************************************
+ *           DOSMEM_FillBiosSegment
+ *
+ * Fill the BIOS data segment with dummy values.
+ */
+void DOSMEM_FillBiosSegment(void)
+{
+    pBiosData = (BIOSDATA *)GlobalLock( DOSMEM_BiosSeg );
+
+      /* Clear all unused values */
+    memset( pBiosData, 0, sizeof(*pBiosData) );
+
+    /* FIXME: should check the number of configured drives and ports */
+
+    pBiosData->Com1Addr             = 0x3e8;
+    pBiosData->Com2Addr             = 0x2e8;
+    pBiosData->Lpt1Addr             = 0x378;
+    pBiosData->Lpt2Addr             = 0x278;
+    pBiosData->InstalledHardware    = 0x8443;
+    pBiosData->MemSize              = 640;
+    pBiosData->NextKbdCharPtr       = 0x1e;
+    pBiosData->FirstKbdCharPtr      = 0x1e;
+    pBiosData->VideoMode            = 0;
+    pBiosData->VideoColumns         = 80;
+    pBiosData->VideoPageSize        = 80 * 25 * 2;
+    pBiosData->VideoPageStartAddr   = 0xb800;
+    pBiosData->VideoCtrlAddr        = 0x3d4;
+    pBiosData->Ticks                = INT1A_GetTicksSinceMidnight();
+    pBiosData->NbHardDisks          = 2;
+    pBiosData->KbdBufferStart       = 0x1e;
+    pBiosData->KbdBufferEnd         = 0x3e;
+
+/*
+    signal( SIGALRM, DOSMEM_Alarm );
+    alarm( 1 );
+*/
+}
diff --git a/miscemu/emulate.c b/miscemu/emulate.c
index a8b40f3..afa61e7 100644
--- a/miscemu/emulate.c
+++ b/miscemu/emulate.c
@@ -72,11 +72,12 @@
         /* IN: AX&0x0C00 rounding protocol */
         /* OUT: DX:AX variable popped */
         {
-            DWORD dw,junk;
+            DWORD dw;
             /* I don't know much about asm() programming. This could be 
              * wrong. 
              */
-            __asm__("fistp %1\nwait":"=m" (junk):"m" (dw):"memory");
+/* FIXME: could someone who really understands asm() fix this please? --AJ */
+/*            __asm__("fistp %0;wait" : "=m" (dw) : : "memory"); */
             dprintf_int(stddeb,"emulate.c:On top of stack was %ld\n",dw);
             AX_reg(&context) = LOWORD(dw);
             DX_reg(&context) = HIWORD(dw);
diff --git a/miscemu/instr.c b/miscemu/instr.c
index 55388da..e5d89d8 100644
--- a/miscemu/instr.c
+++ b/miscemu/instr.c
@@ -11,6 +11,258 @@
 #include "registers.h"
 
 
+#define STACK_PTR(context) \
+    (PTR_SEG_OFF_TO_LIN( SS_reg(context), \
+        ((GET_SEL_FLAGS(SS_reg(context)) & LDT_FLAGS_32BIT) ? \
+            ESP_reg(context) : SP_reg(context))))
+
+/***********************************************************************
+ *           INSTR_ReplaceSelector
+ *
+ * Try to replace an invalid selector by a valid one.
+ * For now, only selector 0x40 is handled here.
+ */
+static WORD INSTR_ReplaceSelector( struct sigcontext_struct *context, WORD sel)
+{
+    if (sel == 0x40)
+    {
+        fprintf( stderr, "Direct access to segment 0x40 (cs:ip=%04x:%04lx).\n",
+                 CS_reg(context), EIP_reg(context) );
+        return DOSMEM_BiosSeg;
+    }
+    return 0;  /* Can't replace selector */
+}
+
+
+/***********************************************************************
+ *           INSTR_GetOperandAddr
+ *
+ * Return the address of an instruction operand (from the mod/rm byte).
+ */
+static BYTE *INSTR_GetOperandAddr( struct sigcontext_struct *context,
+                                   BYTE *instr, int long_addr,
+                                   int segprefix, int *len )
+{
+    int mod, rm, base, index = 0, ss = 0, seg = 0, off;
+
+#define GET_VAL(val,type) \
+    { *val = *(type *)instr; instr += sizeof(type); *len += sizeof(type); }
+
+    *len = 0;
+    GET_VAL( &mod, BYTE );
+    rm = mod & 7;
+    mod >>= 6;
+
+    if (mod == 3)
+    {
+        switch(rm)
+        {
+        case 0: return (BYTE *)&EAX_reg(context);
+        case 1: return (BYTE *)&ECX_reg(context);
+        case 2: return (BYTE *)&EDX_reg(context);
+        case 3: return (BYTE *)&EBX_reg(context);
+        case 4: return (BYTE *)&ESP_reg(context);
+        case 5: return (BYTE *)&EBP_reg(context);
+        case 6: return (BYTE *)&ESI_reg(context);
+        case 7: return (BYTE *)&EDI_reg(context);
+        }
+    }
+
+    if (long_addr)
+    {
+        if (rm == 4)
+        {
+            BYTE sib;
+            GET_VAL( &sib, BYTE );
+            rm = sib & 7;
+            ss = sib >> 6;
+            switch(sib >> 3)
+            {
+            case 0: index = EAX_reg(context); break;
+            case 1: index = ECX_reg(context); break;
+            case 2: index = EDX_reg(context); break;
+            case 3: index = EBX_reg(context); break;
+            case 4: index = 0; break;
+            case 5: index = EBP_reg(context); break;
+            case 6: index = ESI_reg(context); break;
+            case 7: index = EDI_reg(context); break;
+            }
+        }
+
+        switch(rm)
+        {
+        case 0: base = EAX_reg(context); seg = DS_reg(context); break;
+        case 1: base = ECX_reg(context); seg = DS_reg(context); break;
+        case 2: base = EDX_reg(context); seg = DS_reg(context); break;
+        case 3: base = EBX_reg(context); seg = DS_reg(context); break;
+        case 4: base = ESP_reg(context); seg = SS_reg(context); break;
+        case 5: base = EBP_reg(context); seg = SS_reg(context); break;
+        case 6: base = ESI_reg(context); seg = DS_reg(context); break;
+        case 7: base = EDI_reg(context); seg = DS_reg(context); break;
+        }
+        switch (mod)
+        {
+        case 0:
+            if (rm == 5)  /* special case: ds:(disp32) */
+            {
+                GET_VAL( &base, DWORD );
+                seg = DS_reg(context);
+            }
+            break;
+
+        case 1:  /* 8-bit disp */
+            GET_VAL( &off, BYTE );
+            base += (signed char)off;
+            break;
+
+        case 2:  /* 32-bit disp */
+            GET_VAL( &off, DWORD );
+            base += (signed long)off;
+            break;
+        }
+    }
+    else  /* short address */
+    {
+        switch(rm)
+        {
+        case 0:  /* ds:(bx,si) */
+            base = BX_reg(context) + SI_reg(context);
+            seg  = DS_reg(context);
+            break;
+        case 1:  /* ds:(bx,di) */
+            base = BX_reg(context) + DI_reg(context);
+            seg  = DS_reg(context);
+            break;
+        case 2:  /* ss:(bp,si) */
+            base = BP_reg(context) + SI_reg(context);
+            seg  = SS_reg(context);
+            break;
+        case 3:  /* ss:(bp,di) */
+            base = BP_reg(context) + DI_reg(context);
+            seg  = SS_reg(context);
+            break;
+        case 4:  /* ds:(si) */
+            base = SI_reg(context);
+            seg  = DS_reg(context);
+            break;
+        case 5:  /* ds:(di) */
+            base = DI_reg(context);
+            seg  = DS_reg(context);
+            break;
+        case 6:  /* ss:(bp) */
+            base = BP_reg(context);
+            seg  = SS_reg(context);
+            break;
+        case 7:  /* ds:(bx) */
+            base = BX_reg(context);
+            seg  = DS_reg(context);
+            break;
+        }
+
+        switch(mod)
+        {
+        case 0:
+            if (rm == 6)  /* special case: ds:(disp16) */
+            {
+                GET_VAL( &base, WORD );
+                seg  = DS_reg(context);
+            }
+            break;
+
+        case 1:  /* 8-bit disp */
+            GET_VAL( &off, BYTE );
+            base += (signed char)off;
+            break;
+
+        case 2:  /* 16-bit disp */
+            GET_VAL( &off, WORD );
+            base += (signed short)off;
+            break;
+        }
+    }
+    if (segprefix != -1) seg = segprefix;
+
+    return (BYTE *)PTR_SEG_OFF_TO_LIN( seg, (base + (index << ss)) );
+}
+
+
+/***********************************************************************
+ *           INSTR_EmulateLDS
+ *
+ * Emulate the LDS (and LES,LFS,etc.) instruction.
+ */
+static BOOL INSTR_EmulateLDS( struct sigcontext_struct *context,
+                              BYTE *instr, int long_op, int long_addr,
+                              int segprefix, int *len )
+{
+    BYTE *regmodrm = instr + 1 + (*instr == 0x0f);
+    BYTE *addr = INSTR_GetOperandAddr( context, regmodrm,
+                                       long_addr, segprefix, len );
+    WORD seg = *(WORD *)(addr + (long_op ? 4 : 2));
+
+    if (!(seg = INSTR_ReplaceSelector( context, seg )))
+        return FALSE;  /* Unable to emulate it */
+
+    /* Now store the offset in the correct register */
+
+    switch((*regmodrm >> 3) & 7)
+    {
+    case 0:
+        if (long_op) EAX_reg(context) = *(DWORD *)addr;
+        else AX_reg(context) = *(WORD *)addr;
+        break;
+    case 1:
+        if (long_op) ECX_reg(context) = *(DWORD *)addr;
+        else CX_reg(context) = *(WORD *)addr;
+        break;
+    case 2:
+        if (long_op) EDX_reg(context) = *(DWORD *)addr;
+        else DX_reg(context) = *(WORD *)addr;
+        break;
+    case 3:
+        if (long_op) EBX_reg(context) = *(DWORD *)addr;
+        else BX_reg(context) = *(WORD *)addr;
+        break;
+    case 4:
+        if (long_op) ESP_reg(context) = *(DWORD *)addr;
+        else SP_reg(context) = *(WORD *)addr;
+        break;
+    case 5:
+        if (long_op) EBP_reg(context) = *(DWORD *)addr;
+        else BP_reg(context) = *(WORD *)addr;
+        break;
+    case 6:
+        if (long_op) ESI_reg(context) = *(DWORD *)addr;
+        else SI_reg(context) = *(WORD *)addr;
+        break;
+    case 7:
+        if (long_op) EDI_reg(context) = *(DWORD *)addr;
+        else DI_reg(context) = *(WORD *)addr;
+        break;
+    }
+
+    /* Store the correct segment in the segment register */
+
+    switch(*instr)
+    {
+    case 0xc4: ES_reg(context) = seg; break;  /* les */
+    case 0xc5: DS_reg(context) = seg; break;  /* lds */
+    case 0x0f: switch(instr[1])
+               {
+               case 0xb2: SS_reg(context) = seg; break;  /* lss */
+               case 0xb4: FS_reg(context) = seg; break;  /* lfs */
+               case 0xb5: GS_reg(context) = seg; break;  /* lgs */
+               }
+               break;
+    }
+
+    /* Add the opcode size to the total length */
+
+    *len += 1 + (*instr == 0x0f);
+    return TRUE;
+}
+
+
 /***********************************************************************
  *           INSTR_EmulateInstruction
  *
@@ -18,7 +270,7 @@
  */
 BOOL INSTR_EmulateInstruction( struct sigcontext_struct *context )
 {
-    int prefix, segprefix, repX, long_op, long_addr;
+    int prefix, segprefix, prefixlen, len, repX, long_op, long_addr;
     BYTE *instr;
 
     long_op = long_addr = (GET_SEL_FLAGS(CS_reg(context)) & LDT_FLAGS_32BIT) != 0;
@@ -29,6 +281,7 @@
     segprefix = -1;  /* no prefix */
     prefix = 1;
     repX = 0;
+    prefixlen = 0;
     while(prefix)
     {
         switch(*instr)
@@ -72,7 +325,7 @@
         if (prefix)
         {
             instr++;
-            EIP_reg(context)++;
+            prefixlen++;
         }
     }
 
@@ -80,103 +333,59 @@
 
     switch(*instr)
     {
-        case 0xcd: /* int <XX> */
-            if (long_op)
+        case 0x07: /* pop es */
+        case 0x17: /* pop ss */
+        case 0x1f: /* pop ds */
             {
-                fprintf(stderr, "int xx from 32-bit code is not supported.\n");
-                return FALSE;  /* Unable to emulate it */
+                WORD seg = *(WORD *)STACK_PTR( context );
+                if ((seg = INSTR_ReplaceSelector( context, seg )) != 0)
+                {
+                    switch(*instr)
+                    {
+                    case 0x07: ES_reg(context) = seg; break;
+                    case 0x17: SS_reg(context) = seg; break;
+                    case 0x1f: DS_reg(context) = seg; break;
+                    }
+                    SP_reg(context) += sizeof(WORD);
+                    EIP_reg(context) += prefixlen + 1;
+                    return TRUE;
+                }
             }
-            else
+            break;  /* Unable to emulate it */
+
+        case 0x0f: /* extended instruction */
+            switch(instr[1])
             {
-                SEGPTR addr = INT_GetHandler( instr[1] );
-                /* FIXME: should check the stack 'big' bit */
-                WORD *stack = (WORD *)PTR_SEG_OFF_TO_LIN( SS_reg(context),
-                                                          SP_reg(context) );
-                /* Push the flags and return address on the stack */
-                *(--stack) = FL_reg(context);
-                *(--stack) = CS_reg(context);
-                *(--stack) = IP_reg(context) + 2;
-                SP_reg(context) -= 3 * sizeof(WORD);
-                /* Jump to the interrupt handler */
-                CS_reg(context)  = HIWORD(addr);
-                EIP_reg(context) = LOWORD(addr);
+            case 0xa1: /* pop fs */
+            case 0xa9: /* pop gs */
+                {
+                    WORD seg = *(WORD *)STACK_PTR( context );
+                    if ((seg = INSTR_ReplaceSelector( context, seg )) != 0)
+                    {
+                        switch(instr[1])
+                        {
+                        case 0xa1: FS_reg(context) = seg; break;
+                        case 0xa9: GS_reg(context) = seg; break;
+                        }
+                        SP_reg(context) += sizeof(WORD);
+                        EIP_reg(context) += prefixlen + 2;
+                        return TRUE;
+                    }
+                }
+                break;
+
+            case 0xb2: /* lss addr,reg */
+            case 0xb4: /* lfs addr,reg */
+            case 0xb5: /* lgs addr,reg */
+                if (INSTR_EmulateLDS( context, instr, long_op,
+                                      long_addr, segprefix, &len ))
+                {
+                    EIP_reg(context) += prefixlen + len;
+                    return TRUE;
+                }
+                break;
             }
-            break;
-
-        case 0xcf: /* iret */
-            if (long_op)
-            {
-                /* FIXME: should check the stack 'big' bit */
-                DWORD *stack = (DWORD *)PTR_SEG_OFF_TO_LIN( SS_reg(context),
-                                                            SP_reg(context) );
-                EIP_reg(context) = *stack++;
-                CS_reg(context)  = *stack++;
-                EFL_reg(context) = *stack;
-                SP_reg(context) += 3*sizeof(DWORD);  /* Pop the return address and flags */
-            }
-            else
-            {
-                /* FIXME: should check the stack 'big' bit */
-                WORD *stack = (WORD *)PTR_SEG_OFF_TO_LIN( SS_reg(context),
-                                                          SP_reg(context) );
-                EIP_reg(context) = *stack++;
-                CS_reg(context)  = *stack++;
-                FL_reg(context)  = *stack;
-                SP_reg(context) += 3*sizeof(WORD);  /* Pop the return address and flags */
-            }
-            break;
-
-        case 0xe4: /* inb al,XX */
-            AL_reg(context) = inport( instr[1], 1 );
-	    EIP_reg(context) += 2;
-            break;
-
-        case 0xe5: /* in (e)ax,XX */
-            if (long_op) EAX_reg(context) = inport( instr[1], 4 );
-            else AX_reg(context) = inport( instr[1], 2 );
-	    EIP_reg(context) += 2;
-            break;
-
-        case 0xe6: /* outb XX,al */
-            outport( instr[1], 1, AL_reg(context) );
-	    EIP_reg(context) += 2;
-            break;
-
-        case 0xe7: /* out XX,(e)ax */
-            if (long_op) outport( instr[1], 4, EAX_reg(context) );
-            else outport( instr[1], 2, AX_reg(context) );
-  	    EIP_reg(context) += 2;
-            break;
-
-        case 0xec: /* inb al,dx */
-            AL_reg(context) = inport( DX_reg(context), 1 );
-	    EIP_reg(context)++;
-            break;
-
-        case 0xed: /* in (e)ax,dx */
-            if (long_op) EAX_reg(context) = inport( DX_reg(context), 4 );
-            else AX_reg(context) = inport( DX_reg(context), 2 );
-	    EIP_reg(context)++;  
-            break;
-
-        case 0xee: /* outb dx,al */
-            outport( DX_reg(context), 1, AL_reg(context) );
-	    EIP_reg(context)++;
-            break;
-      
-        case 0xef: /* out dx,(e)ax */
-            if (long_op) outport( DX_reg(context), 4, EAX_reg(context) );
-            else outport( DX_reg(context), 2, AX_reg(context) );
-	    EIP_reg(context)++;
-            break;
-
-        case 0xfa: /* cli, ignored */
-	    EIP_reg(context)++;
-            break;
-
-        case 0xfb: /* sti, ignored */
-	    EIP_reg(context)++;
-            break;
+            break;  /* Unable to emulate it */
 
         case 0x6c: /* insb     */
         case 0x6d: /* insw/d   */
@@ -190,7 +399,7 @@
 	      int opsize = (typ & 1) ? (long_op ? 4 : 2) : 1;
 	      int step = (EFL_reg(context) & 0x400) ? -opsize : +opsize;
 	      int seg = outp ? (segprefix >= 0 ? segprefix : DS_reg(context))
-                             : ES_reg(context);
+                             : ES_reg(context);  /* FIXME: is this right? */
 
 	      if (outp)
 		/* FIXME: Check segment readable.  */
@@ -245,14 +454,151 @@
 		      break;
 		    }
 		}
-	      EIP_reg(context)++;
-	      break;
+              EIP_reg(context) += prefixlen + 1;
 	    }
+            return TRUE;
 
-      default:
-            fprintf(stderr, "Unexpected Windows program segfault"
-                            " - opcode = %x\n", *instr);
-            return FALSE;  /* Unable to emulate it */
+        case 0x8e: /* mov reg,segment_reg */
+            {
+                WORD seg = *(WORD *)INSTR_GetOperandAddr( context, instr + 1,
+                                                  long_addr, segprefix, &len );
+                if (!(seg = INSTR_ReplaceSelector( context, seg )))
+                    break;  /* Unable to emulate it */
+
+                switch((instr[1] >> 3) & 7)
+                {
+                case 0:
+                    ES_reg(context) = seg;
+                    EIP_reg(context) += prefixlen + len + 1;
+                    return TRUE;
+                case 1:  /* cs */
+                    break;
+                case 2:
+                    SS_reg(context) = seg;
+                    EIP_reg(context) += prefixlen + len + 1;
+                    return TRUE;
+                case 3:
+                    DS_reg(context) = seg;
+                    EIP_reg(context) += prefixlen + len + 1;
+                    return TRUE;
+                case 4:
+                    FS_reg(context) = seg;
+                    EIP_reg(context) += prefixlen + len + 1;
+                    return TRUE;
+                case 5:
+                    GS_reg(context) = seg;
+                    EIP_reg(context) += prefixlen + len + 1;
+                    return TRUE;
+                case 6:  /* unused */
+                case 7:  /* unused */
+                    break;
+                }
+            }
+            break;  /* Unable to emulate it */
+
+        case 0xc4: /* les addr,reg */
+        case 0xc5: /* lds addr,reg */
+            if (INSTR_EmulateLDS( context, instr, long_op,
+                                  long_addr, segprefix, &len ))
+            {
+                EIP_reg(context) += prefixlen + len;
+                return TRUE;
+            }
+            break;  /* Unable to emulate it */
+            
+        case 0xcd: /* int <XX> */
+            if (long_op)
+            {
+                fprintf(stderr, "int xx from 32-bit code is not supported.\n");
+                break;  /* Unable to emulate it */
+            }
+            else
+            {
+                SEGPTR addr = INT_GetHandler( instr[1] );
+                WORD *stack = (WORD *)STACK_PTR( context );
+                /* Push the flags and return address on the stack */
+                *(--stack) = FL_reg(context);
+                *(--stack) = CS_reg(context);
+                *(--stack) = IP_reg(context) + prefixlen + 2;
+                SP_reg(context) -= 3 * sizeof(WORD);
+                /* Jump to the interrupt handler */
+                CS_reg(context)  = HIWORD(addr);
+                EIP_reg(context) = LOWORD(addr);
+            }
+            return TRUE;
+
+        case 0xcf: /* iret */
+            if (long_op)
+            {
+                DWORD *stack = (DWORD *)STACK_PTR( context );
+                EIP_reg(context) = *stack++;
+                CS_reg(context)  = *stack++;
+                EFL_reg(context) = *stack;
+                SP_reg(context) += 3*sizeof(DWORD);  /* Pop the return address and flags */
+            }
+            else
+            {
+                WORD *stack = (WORD *)STACK_PTR( context );
+                EIP_reg(context) = *stack++;
+                CS_reg(context)  = *stack++;
+                FL_reg(context)  = *stack;
+                SP_reg(context) += 3*sizeof(WORD);  /* Pop the return address and flags */
+            }
+            return TRUE;
+
+        case 0xe4: /* inb al,XX */
+            AL_reg(context) = inport( instr[1], 1 );
+	    EIP_reg(context) += prefixlen + 2;
+            return TRUE;
+
+        case 0xe5: /* in (e)ax,XX */
+            if (long_op) EAX_reg(context) = inport( instr[1], 4 );
+            else AX_reg(context) = inport( instr[1], 2 );
+	    EIP_reg(context) += prefixlen + 2;
+            return TRUE;
+
+        case 0xe6: /* outb XX,al */
+            outport( instr[1], 1, AL_reg(context) );
+	    EIP_reg(context) += prefixlen + 2;
+            return TRUE;
+
+        case 0xe7: /* out XX,(e)ax */
+            if (long_op) outport( instr[1], 4, EAX_reg(context) );
+            else outport( instr[1], 2, AX_reg(context) );
+  	    EIP_reg(context) += prefixlen + 2;
+            return TRUE;
+
+        case 0xec: /* inb al,dx */
+            AL_reg(context) = inport( DX_reg(context), 1 );
+  	    EIP_reg(context) += prefixlen + 1;
+            return TRUE;
+
+        case 0xed: /* in (e)ax,dx */
+            if (long_op) EAX_reg(context) = inport( DX_reg(context), 4 );
+            else AX_reg(context) = inport( DX_reg(context), 2 );
+  	    EIP_reg(context) += prefixlen + 1;
+            return TRUE;
+
+        case 0xee: /* outb dx,al */
+            outport( DX_reg(context), 1, AL_reg(context) );
+  	    EIP_reg(context) += prefixlen + 1;
+            return TRUE;
+      
+        case 0xef: /* out dx,(e)ax */
+            if (long_op) outport( DX_reg(context), 4, EAX_reg(context) );
+            else outport( DX_reg(context), 2, AX_reg(context) );
+  	    EIP_reg(context) += prefixlen + 1;
+            return TRUE;
+
+        case 0xfa: /* cli, ignored */
+  	    EIP_reg(context) += prefixlen + 1;
+            return TRUE;
+
+        case 0xfb: /* sti, ignored */
+  	    EIP_reg(context) += prefixlen + 1;
+            return TRUE;
     }
-    return TRUE;
+    fprintf(stderr, "Unexpected Windows program segfault"
+                    " - opcode = %x\n", *instr);
+    return FALSE;  /* Unable to emulate it */
 }
diff --git a/miscemu/int1a.c b/miscemu/int1a.c
index 7e17e42..69386c0 100644
--- a/miscemu/int1a.c
+++ b/miscemu/int1a.c
@@ -15,6 +15,27 @@
 
 
 /**********************************************************************
+ *	    INT1A_GetTicksSinceMidnight
+ *
+ * Return number of clock ticks since midnight.
+ */
+DWORD INT1A_GetTicksSinceMidnight(void)
+{
+    struct tm *bdtime;
+    struct timeval tvs;
+
+    /* This should give us the (approximately) correct
+     * 18.206 clock ticks per second since midnight.
+     */
+    gettimeofday( &tvs, NULL );
+    bdtime = localtime( &tvs.tv_sec );
+    return (((bdtime->tm_hour * 3600 + bdtime->tm_min * 60 +
+              bdtime->tm_sec) * 18206) / 1000) +
+                  (tvs.tv_usec / 54927);
+}
+
+
+/**********************************************************************
  *	    INT_Int1aHandler
  *
  * Handler for int 1ah (date and time).
@@ -24,25 +45,16 @@
     time_t ltime;
     DWORD ticks;
     struct tm *bdtime;
-    struct timeval tvs;
 
     switch(AH_reg(&context))
     {
 	case 0:
-                /* This should give us the (approximately) correct
-                 * 18.206 clock ticks per second since midnight
-                 * expected from this interrupt
-                 */
-                gettimeofday(&tvs, NULL);
-                bdtime = localtime(&tvs.tv_sec);
-                ticks = (((bdtime->tm_hour * 3600 + bdtime->tm_min * 60 +
-                        bdtime->tm_sec) * 18206) / 1000) +
-                        (tvs.tv_usec / 54927);
-		CX_reg(&context) = HIWORD(ticks);
-		DX_reg(&context) = LOWORD(ticks);
-		AX_reg(&context) = 0;  /* No midnight rollover */
-		dprintf_int(stddeb,"int1a_00 // ticks=%ld\n", ticks);
-		break;
+            ticks = INT1A_GetTicksSinceMidnight();
+            CX_reg(&context) = HIWORD(ticks);
+            DX_reg(&context) = LOWORD(ticks);
+            AX_reg(&context) = 0;  /* No midnight rollover */
+            dprintf_int(stddeb,"int1a_00 // ticks=%ld\n", ticks);
+            break;
 		
 	case 2: 
 		ltime = time(NULL);
diff --git a/miscemu/int21.c b/miscemu/int21.c
index b0a05e7..720806c 100644
--- a/miscemu/int21.c
+++ b/miscemu/int21.c
@@ -341,14 +341,9 @@
 		AX_reg(context) = CX_reg(context);
 		RESET_CFLAG(context);
 	} else {
-		size = write(BX_reg(context), ptr , CX_reg(context));
-		if (size == 0) {
-			Error (WriteFault, EC_Unknown, EL_Unknown);
-			AX_reg(context) = ExtendedError;
-			return;
-		}
-
-		if (size == -1) {
+		/* well, this function already handles everything we need */
+		size = _lwrite(BX_reg(context),ptr,CX_reg(context));
+		if (size == -1) { /* HFILE_ERROR == -1 */
 			errno_to_doserr();
 			AX_reg(context) = ExtendedError;
 			SET_CFLAG(context);
@@ -417,8 +412,12 @@
 			return;
 		    }
 	    
-		    /* This isn't the right answer, but should be close enough. */
 		    DX_reg(context) = 0x0943;
+		    /* bits 0-5 are current drive
+		     * bit 6 - file has NOT been written..FIXME: correct?
+		     * bit 8 - generate int24 if no diskspace on write/ read past end of file
+		     * bit 11 - media not removable
+		     */
 		}
 	}
 	RESET_CFLAG(context);
@@ -1526,7 +1525,13 @@
 		    RESET_CFLAG(&context);
                 }
 		break;
-
+	      case 0x0a: /* check if handle (BX) is remote */
+	      	/* returns DX, bit 15 set if remote, bit 14 set if date/time
+	      	 * not set on close
+	      	 */
+		DX_reg(&context) = 0;
+		RESET_CFLAG(&context);
+		break;
 	      case 0x0b:   /* SET SHARING RETRY COUNT */
 		if (!CX_reg(&context))
 		{ 
diff --git a/multimedia/Imakefile b/multimedia/Imakefile
index 582e384..51ea94f 100644
--- a/multimedia/Imakefile
+++ b/multimedia/Imakefile
@@ -7,6 +7,7 @@
 	joystick.c \
 	mcianim.c \
 	mcicda.c \
+	mcistring.c \
 	midi.c \
 	mmaux.c \
 	mmsystem.c \
diff --git a/multimedia/Makefile.in b/multimedia/Makefile.in
index 17ea1c7..bc034fc 100644
--- a/multimedia/Makefile.in
+++ b/multimedia/Makefile.in
@@ -9,9 +9,16 @@
 
 MODULE 	= multimedia
 
-SRCS 	= audio.c joystick.c mcianim.c mcicda.c midi.c mmaux.c \
-	  mmsystem.c time.c
-
+SRCS = \
+	audio.c \
+	joystick.c \
+	mcianim.c \
+	mcicda.c \
+	mcistring.c \
+	midi.c \
+	mmaux.c \
+	mmsystem.c \
+	time.c
 
 OBJS = $(SRCS:.c=.o)
 
@@ -29,7 +36,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/multimedia/audio.c b/multimedia/audio.c
index 5ce2271..5c46e07 100644
--- a/multimedia/audio.c
+++ b/multimedia/audio.c
@@ -35,7 +35,7 @@
 #define SOUND_DEV "/dev/dsp"
 
 #ifdef SOUND_VERSION
-#define IOCTL(a,b,c)		ioctl(a,b,&c)
+#define IOCTL(a,b,c)		((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
 #else
 #define IOCTL(a,b,c)		(c = ioctl(a,b,c) )
 #endif
@@ -863,10 +863,11 @@
 	close(WOutDev[wDevID].unixdev);
 	WOutDev[wDevID].unixdev = 0;
 	WOutDev[wDevID].bufsize = 0;
+	WOutDev[wDevID].lpQueueHdr = NULL;
 	if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
 		dprintf_mciwave(stddeb,"Linux 'wodClose' // can't notify client !\n");
 		return MMSYSERR_INVALPARAM;
-		}
+	}
 	return MMSYSERR_NOERROR;
 }
 
@@ -920,10 +921,13 @@
 		dprintf_mciwave(stddeb,"Linux 'wodPrepare' // can't prepare !\n");
 		return MMSYSERR_NOTENABLED;
 		}
+	/* the COOL waveeditor feels much better without this check... 
+	 * someone please have a look at available documentation
 	if (WOutDev[wDevID].lpQueueHdr != NULL) {
 		dprintf_mciwave(stddeb,"Linux 'wodPrepare' // already prepare !\n");
 		return MMSYSERR_NOTENABLED;
-		}
+	}
+	*/
 	WOutDev[wDevID].dwTotalPlayed = 0;
 	WOutDev[wDevID].lpQueueHdr = lpWaveHdr;
 	if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
diff --git a/multimedia/mcistring.c b/multimedia/mcistring.c
new file mode 100644
index 0000000..653a907
--- /dev/null
+++ b/multimedia/mcistring.c
@@ -0,0 +1,2177 @@
+/*
+ * MCI stringinterface
+ *
+ * Copyright 1995 Marcus Meissner
+ */
+/* FIXME: special commands of device drivers should be handled by those drivers
+ */
+
+#ifndef WINELIB
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "windows.h"
+#include "ldt.h"
+#include "callback.h"
+#include "user.h"
+#include "driver.h"
+#include "mmsystem.h"
+#include "stddebug.h"
+#include "debug.h"
+
+extern MCI_OPEN_DRIVER_PARMS	mciDrv[MAXMCIDRIVERS];
+
+/* FIXME: I need to remember the aliasname of a spec. driver. 
+ *        and this is the easiest way. *sigh*
+ */
+static MCI_OPEN_PARMS		mciOpenDrv[MAXMCIDRIVERS];
+
+LONG DrvDefDriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg, 
+		      DWORD dwParam1, DWORD dwParam2);
+
+LONG WAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg, 
+		     DWORD dwParam1, DWORD dwParam2);
+LONG MIDI_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg, 
+		     DWORD dwParam1, DWORD dwParam2);
+LONG CDAUDIO_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg, 
+			DWORD dwParam1, DWORD dwParam2);
+LONG ANIM_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg, 
+		     DWORD dwParam1, DWORD dwParam2);
+
+/* The reason why I just don't lowercase the keywords array in 
+ * mciSendString is left as an exercise to the reader.
+ */
+#define STRCMP(x,y) strcasecmp(x,y)
+
+/* standard functionparameters for all functions */
+#define _MCISTR_PROTO_ \
+	WORD wDevID,WORD uDevTyp,LPSTR lpstrReturnString,UINT uReturnLength,\
+	LPCSTR dev,LPSTR *keywords,UINT nrofkeywords,DWORD dwFlags
+
+/* copy string to return pointer including necessary checks 
+ * for use in mciSendString()
+ */
+#define _MCI_STR(s) do {\
+	int __l__;\
+	dprintf_mci(stddeb,"->returns \"%s\"",s);\
+	if (lpstrReturnString) {\
+		__l__=strlen(s);\
+		if(__l__>uReturnLength) {\
+			strncpy(lpstrReturnString,s,uReturnLength-1);\
+			lpstrReturnString[uReturnLength-1]='\0';\
+		} else\
+			strcpy(lpstrReturnString,s);\
+		dprintf_mci(stddeb,"-->\"%s\"\n",lpstrReturnString);\
+	}\
+} while(0)
+
+/* calling DriverProc. We need to pass the struct as SEGMENTED POINTER. */
+#define _MCI_CALL_DRIVER(cmd,params) {\
+	DWORD	xparams;\
+	xparams=MAKE_SEGPTR(&params);\
+	switch(uDevTyp) {\
+	case MCI_DEVTYPE_CD_AUDIO:\
+		res=CDAUDIO_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags, xparams);\
+		break;\
+	case MCI_DEVTYPE_WAVEFORM_AUDIO:\
+		res=WAVE_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
+		break;\
+	case MCI_DEVTYPE_SEQUENCER:\
+		res=MIDI_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
+		break;\
+	case MCI_DEVTYPE_ANIMATION:\
+		res=ANIM_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
+		break;\
+	case MCI_DEVTYPE_DIGITAL_VIDEO:\
+		dprintf_mci(stddeb,"_MCI_CALL_DRIVER //No DIGITAL_VIDEO yet !\n");\
+		res=MCIERR_DEVICE_NOT_INSTALLED;\
+		break;\
+	default:\
+		dprintf_mci(stddeb,"_MCI_CALL_DRIVER //Invalid Device Name '%s' !\n",dev);\
+		res=MCIERR_INVALID_DEVICE_NAME;\
+		break;\
+	}\
+}
+/* we need to have strings in 16 bit space for some things 
+ * FIXME: this is bad.
+ */
+#define	_MCI_STRDUP_TO_SEG(dest,source) {\
+	HANDLE	x;\
+	x=USER_HEAP_ALLOC(strlen(source));\
+	dest=(LPSTR)MAKELONG(x,USER_HeapSel);\
+	strcpy(PTR_SEG_TO_LIN(dest),source);\
+}
+
+/* print a DWORD in the specified timeformat */
+static void
+_MCISTR_printtf(char *buf,UINT uDevType,DWORD timef,DWORD val) {
+	*buf='\0';
+	switch (timef) {
+	case MCI_FORMAT_MILLISECONDS:
+	case MCI_FORMAT_FRAMES:
+	case MCI_FORMAT_BYTES:
+	case MCI_FORMAT_SAMPLES:
+	case MCI_VD_FORMAT_TRACK:
+	/*case MCI_SEQ_FORMAT_SONGPTR: sameas MCI_VD_FORMAT_TRACK */
+		sprintf(buf,"%ld",val);
+		break;
+	case MCI_FORMAT_HMS:
+		/* well, the macros have the same content*/
+		/*FALLTRHOUGH*/
+	case MCI_FORMAT_MSF:
+		sprintf(buf,"%d:%d:%d",
+			MCI_HMS_HOUR(val),
+			MCI_HMS_MINUTE(val),
+			MCI_HMS_SECOND(val)
+		);
+		break;
+	case MCI_FORMAT_TMSF:
+		sprintf(buf,"%d:%d:%d:%d",
+			MCI_TMSF_TRACK(val),
+			MCI_TMSF_MINUTE(val),
+			MCI_TMSF_SECOND(val),
+			MCI_TMSF_FRAME(val)
+		);
+		break;
+	default:
+		fprintf(stdnimp,__FILE__":MCISTR_Status:missing timeformat for %ld, report.\n",timef);
+		strcpy(buf,"0"); /* hmm */
+		break;
+	}
+	return;
+}
+/* possible different return types */
+#define _MCISTR_int	1
+#define _MCISTR_time	2
+#define _MCISTR_bool	3
+#define _MCISTR_tfname	4
+#define _MCISTR_mode	5
+#define _MCISTR_divtype	6
+#define _MCISTR_seqtype	7
+#define _MCISTR_vdmtype	8
+#define _MCISTR_devtype	9
+
+static void
+_MCISTR_convreturn(int type,DWORD dwReturn,LPSTR lpstrReturnString,
+	WORD uReturnLength,WORD uDevTyp,int timef
+) {
+	switch (type) {
+	case _MCISTR_vdmtype:
+		switch (dwReturn) {
+		case MCI_VD_MEDIA_CLV:_MCI_STR("CLV");break;
+		case MCI_VD_MEDIA_CAV:_MCI_STR("CAV");break;
+		default:
+		case MCI_VD_MEDIA_OTHER:_MCI_STR("other");break;
+		}
+		break;
+	case _MCISTR_seqtype:
+		switch (dwReturn) {
+		case MCI_SEQ_NONE:_MCI_STR("none");break;
+		case MCI_SEQ_SMPTE:_MCI_STR("smpte");break;
+		case MCI_SEQ_FILE:_MCI_STR("file");break;
+		case MCI_SEQ_MIDI:_MCI_STR("midi");break;
+		default:fprintf(stdnimp,__FILE__":MCISTR_Status:missing sequencer mode %ld\n",dwReturn);
+		}
+		break;
+	case _MCISTR_mode:
+		switch (dwReturn) {
+		case MCI_MODE_NOT_READY:_MCI_STR("not ready");break;
+		case MCI_MODE_STOP:_MCI_STR("stopped");break;
+		case MCI_MODE_PLAY:_MCI_STR("playing");break;
+		case MCI_MODE_RECORD:_MCI_STR("recording");break;
+		case MCI_MODE_SEEK:_MCI_STR("seeking");break;
+		case MCI_MODE_PAUSE:_MCI_STR("paused");break;
+		case MCI_MODE_OPEN:_MCI_STR("open");break;
+		default:break;
+		}
+		break;
+	case _MCISTR_bool:
+		if (dwReturn)
+			_MCI_STR("true");
+		else
+			_MCI_STR("false");
+		break;
+	case _MCISTR_int:{
+		char	buf[16];
+		sprintf(buf,"%ld",dwReturn);
+		_MCI_STR(buf);
+		break;
+	}
+	case _MCISTR_time: {	
+		char	buf[100];
+		_MCISTR_printtf(buf,uDevTyp,timef,dwReturn);
+		_MCI_STR(buf);
+		break;
+	}
+	case _MCISTR_tfname:
+		switch (timef) {
+		case MCI_FORMAT_MILLISECONDS:_MCI_STR("milliseconds");break;
+		case MCI_FORMAT_FRAMES:_MCI_STR("frames");break;
+		case MCI_FORMAT_BYTES:_MCI_STR("bytes");break;
+		case MCI_FORMAT_SAMPLES:_MCI_STR("samples");break;
+		case MCI_FORMAT_HMS:_MCI_STR("hms");break;
+		case MCI_FORMAT_MSF:_MCI_STR("msf");break;
+		case MCI_FORMAT_TMSF:_MCI_STR("tmsf");break;
+		default:
+			fprintf(stdnimp,__FILE__":MCISTR_Status:missing timeformat for %d, report.\n",timef);
+			break;
+		}
+		break;
+	case _MCISTR_divtype:
+		switch (dwReturn) {
+		case MCI_SEQ_DIV_PPQN:_MCI_STR("PPQN");break;
+		case MCI_SEQ_DIV_SMPTE_24:_MCI_STR("SMPTE 24 frame");break;
+		case MCI_SEQ_DIV_SMPTE_25:_MCI_STR("SMPTE 25 frame");break;
+		case MCI_SEQ_DIV_SMPTE_30:_MCI_STR("SMPTE 30 frame");break;
+		case MCI_SEQ_DIV_SMPTE_30DROP:_MCI_STR("SMPTE 30 frame drop");break;
+		}
+	case _MCISTR_devtype:
+		switch (dwReturn) {
+		case MCI_DEVTYPE_VCR:_MCI_STR("vcr");break;
+		case MCI_DEVTYPE_VIDEODISC:_MCI_STR("videodisc");break;
+		case MCI_DEVTYPE_CD_AUDIO:_MCI_STR("cd audio");break;
+		case MCI_DEVTYPE_OVERLAY:_MCI_STR("overlay");break;
+		case MCI_DEVTYPE_DAT:_MCI_STR("dat");break;
+		case MCI_DEVTYPE_SCANNER:_MCI_STR("scanner");break;
+		case MCI_DEVTYPE_ANIMATION:_MCI_STR("animation");break;
+		case MCI_DEVTYPE_DIGITAL_VIDEO:_MCI_STR("digital video");break;
+		case MCI_DEVTYPE_OTHER:_MCI_STR("other");break;
+		case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio");break;
+		case MCI_DEVTYPE_SEQUENCER:_MCI_STR("sequencer");break;
+		default:fprintf(stdnimp,__FILE__":_MCISTR_convreturn:unknown device type %ld, report.\n",dwReturn);break;
+		}
+		break;
+	default:
+		fprintf(stdnimp,__FILE__":_MCISTR_convreturn:unknown resulttype %d, report.\n",type);
+		break;
+	}
+}
+
+#define FLAG1(str,flag) \
+	if (!STRCMP(keywords[i],str)) {\
+		dwFlags |= flag;\
+		i++;\
+		continue;\
+	}
+#define FLAG2(str1,str2,flag) \
+	if (!STRCMP(keywords[i],str1) && (i+1<nrofkeywords) && !STRCMP(keywords[i+1],str2)) {\
+		dwFlags |= flag;\
+		i+=2;\
+		continue;\
+	}
+
+/* All known subcommands are implemented in single functions to avoid
+ * bloat and a xxxx lines long mciSendString(). All commands are of the
+ * format MCISTR_Cmd(_MCISTR_PROTO_) where _MCISTR_PROTO_ is the above
+ * defined line of arguments. (This is just for easy enhanceability.)
+ * All functions return the MCIERR_ errorvalue as DWORD. Returnvalues
+ * for the calls are in lpstrReturnString (If I mention return values
+ * in function headers, I mean returnvalues in lpstrReturnString.)
+ * Integers are sprintf("%d")ed integers. Boolean values are 
+ * "true" and "false". 
+ * timeformat depending values are "%d" "%d:%d" "%d:%d:%d" "%d:%d:%d:%d"
+ * FIXME: is above line correct?
+ *
+ * Preceding every function is a list of implemented/known arguments.
+ * Feel free to add missing arguments.
+ *
+ */
+
+/*
+ * Opens the specified MCI driver. 
+ * Arguments: <name> 
+ * Optional:
+ *	"shareable"
+ *	"alias <aliasname>"
+ * 	"element <elementname>"
+ * Additional:
+ * waveform audio:
+ *	"buffer <nrBytesPerSec>"
+ * Animation:
+ *	"nostatic"	increaste nr of nonstatic colours
+ *	"parent <windowhandle>"
+ *	"style <mask>"	bitmask of WS_xxxxx (see windows.h)
+ *	"style child"	WS_CHILD
+ *	"style overlap"	WS_OVERLAPPED
+ *	"style popup"	WS_POPUP
+ * Overlay:
+ *	"parent <windowhandle>"
+ *	"style <mask>"	bitmask of WS_xxxxx (see windows.h)
+ *	"style child"	WS_CHILD
+ *	"style overlap"	WS_OVERLAPPED
+ *	"style popup"	WS_POPUP
+ * Returns nothing.
+ */
+static DWORD
+MCISTR_Open(_MCISTR_PROTO_) {
+	int		res,i;
+	char		*s;
+	union {
+		MCI_OPEN_PARMS	openParams;
+		MCI_WAVE_OPEN_PARMS	waveopenParams;
+		MCI_ANIM_OPEN_PARMS	animopenParams;
+		MCI_OVLY_OPEN_PARMS	ovlyopenParams;
+	} U;
+
+	U.openParams.lpstrElementName = NULL;
+	s=strchr(dev,'!');
+	if (s!=NULL) {
+		*s++='\0';
+		_MCI_STRDUP_TO_SEG(U.openParams.lpstrElementName,s);
+	}
+	if (!STRCMP(dev,"cdaudio")) {
+		uDevTyp=MCI_DEVTYPE_CD_AUDIO;
+	} else if (!STRCMP(dev,"waveaudio")) {
+		uDevTyp=MCI_DEVTYPE_WAVEFORM_AUDIO;
+	} else if (!STRCMP(dev,"sequencer")) {
+		uDevTyp=MCI_DEVTYPE_SEQUENCER;
+	} else if (!STRCMP(dev,"animation1")) {
+		uDevTyp=MCI_DEVTYPE_ANIMATION;
+	} else if (!STRCMP(dev,"avivideo")) {
+		uDevTyp=MCI_DEVTYPE_DIGITAL_VIDEO;
+	} else {
+		return MCIERR_INVALID_DEVICE_NAME;
+	}
+	wDevID=0;
+	while(mciDrv[wDevID].wType) {
+		if (++wDevID>=MAXMCIDRIVERS) {
+			dprintf_mci(stddeb, __FILE__":MCISTR_Open:MAXMCIDRIVERS reached!\n");
+			return MCIERR_INTERNAL;
+		}
+	}
+	mciDrv[wDevID].wType		= uDevTyp;
+	mciDrv[wDevID].wDeviceID	= wDevID;
+	U.openParams.dwCallback		= 0;
+	U.openParams.wDeviceID		= wDevID;
+	U.ovlyopenParams.dwStyle	= 0; 
+	U.animopenParams.dwStyle	= 0; 
+
+	_MCI_STRDUP_TO_SEG(U.openParams.lpstrDeviceType,dev);
+	U.openParams.lpstrAlias		= NULL;
+	dwFlags |= MCI_OPEN_TYPE;
+	i=0;
+	while (i<nrofkeywords) {
+		FLAG1("shareable",MCI_OPEN_SHAREABLE);
+		if (!strcmp(keywords[i],"alias") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_OPEN_ALIAS;
+			_MCI_STRDUP_TO_SEG(U.openParams.lpstrAlias,keywords[i]);
+			i+=2;
+			continue;
+		}
+		if (!strcmp(keywords[i],"element") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_OPEN_ELEMENT;
+			_MCI_STRDUP_TO_SEG(U.openParams.lpstrElementName,keywords[i]);
+			i+=2;
+			continue;
+		}
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+		case MCI_DEVTYPE_DIGITAL_VIDEO:
+			FLAG1("nostatic",MCI_ANIM_OPEN_NOSTATIC);
+			if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_ANIM_OPEN_PARENT;
+				sscanf(keywords[i+1],"%u",&(U.animopenParams.hWndParent));
+				i+=2;
+				continue;
+			}
+			if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
+				DWORD	st;
+
+				dwFlags |= MCI_ANIM_OPEN_WS;
+				if (!STRCMP(keywords[i+1],"popup")) {
+					U.animopenParams.dwStyle |= WS_POPUP; 
+				} else if (!STRCMP(keywords[i+1],"overlap")) {
+					U.animopenParams.dwStyle |= WS_OVERLAPPED; 
+				} else if (!STRCMP(keywords[i+1],"child")) {
+					U.animopenParams.dwStyle |= WS_CHILD; 
+				} else if (sscanf(keywords[i+1],"%ld",&st)) {
+					U.animopenParams.dwStyle |= st; 
+				} else
+					fprintf(stdnimp,__FILE__":MCISTR_Open:unknown 'style' keyword %s, please report.\n",keywords[i+1]);
+				i+=2;
+				continue;
+			}
+			break;
+		case MCI_DEVTYPE_WAVEFORM_AUDIO:
+			if (!STRCMP(keywords[i],"buffer") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_WAVE_OPEN_BUFFER;
+				sscanf(keywords[i+1],"%ld",&(U.waveopenParams.dwBufferSeconds));
+			}
+			break;
+		case MCI_DEVTYPE_OVERLAY:
+			/* looks just like anim, but without NOSTATIC */
+			if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_OVLY_OPEN_PARENT;
+				sscanf(keywords[i+1],"%d",&(U.ovlyopenParams.hWndParent));
+				i+=2;
+				continue;
+			}
+			if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
+				DWORD	st;
+
+				dwFlags |= MCI_OVLY_OPEN_WS;
+				if (!STRCMP(keywords[i+1],"popup")) {
+					U.ovlyopenParams.dwStyle |= WS_POPUP; 
+				} else if (!STRCMP(keywords[i+1],"overlap")) {
+					U.ovlyopenParams.dwStyle |= WS_OVERLAPPED; 
+				} else if (!STRCMP(keywords[i+1],"child")) {
+					U.ovlyopenParams.dwStyle |= WS_CHILD; 
+				} else if (sscanf(keywords[i+1],"%ld",&st)) {
+					U.ovlyopenParams.dwStyle |= st; 
+				} else
+					fprintf(stdnimp,__FILE__":MCISTR_Open:unknown 'style' keyword %s, please report.\n",keywords[i+1]);
+				i+=2;
+				continue;
+			}
+			break;
+		}
+		fprintf(stdnimp,__FILE__":MCISTR_Open:unknown parameter passed %s, please report.\n",keywords[i]);
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_OPEN,U);
+	if (res==0)
+		memcpy(&mciOpenDrv[wDevID],&U.openParams,sizeof(MCI_OPEN_PARMS));
+	return res;
+}
+
+/* A help function for a lot of others ... 
+ * for instance status/play/record/seek etc.
+ */
+DWORD
+_MCISTR_determine_timeformat(LPCSTR dev,WORD wDevID,WORD uDevTyp,int *timef) {
+	MCI_STATUS_PARMS	statusParams;
+	DWORD			dwFlags;
+	int			res;
+
+	dwFlags	= MCI_STATUS_ITEM;
+	statusParams.dwItem	= MCI_STATUS_TIME_FORMAT;
+	statusParams.dwReturn	= 0;
+	_MCI_CALL_DRIVER(MCI_STATUS,statusParams);
+	if (res==0) *timef=statusParams.dwReturn;
+	return res;
+}
+
+/* query status of MCI drivers
+ * Arguments:
+ * Required: 
+ *	"mode"	- returns "not ready" "paused" "playing" "stopped" "open" 
+ *		  "parked" "recording" "seeking" ....
+ * Basics:
+ *	"current track"	- returns current track as integer
+ *	"length [track <nr>]"	- returns length [of track <nr>] in current 
+ *				timeformat
+ *	"number of tracks" - returns number of tracks as integer
+ *	"position [track <nr>]" - returns position [in track <nr>] in current 
+ *				timeformat
+ *	"ready"			- checks if device is ready to play, -> bool
+ *	"start position"	- returns start position in timeformat
+ *	"time format"		- returns timeformat (list of possible values:
+ * 				"ms" "msf" "milliseconds" "hmsf" "tmsf" "frames"
+ *				"bytes" "samples" "hms")
+ *	"media present"		- returns if media is present as bool
+ * Animation:
+ *	"forward"		- returns "true" if device is playing forwards
+ *	"speed"			- returns speed for device
+ *	"palette handle"	- returns palette handle
+ *	"window handle"		- returns window handle
+ * 	"stretch"		- returns stretch bool
+ * MIDI sequencer:
+ *	"division type"		- ? returns "PPQN" "SMPTE 24 frame" 
+ * 			"SMPTE 25 frame" "SMPTE 30 frame" "SMPTE 30 drop frame"
+ *	"tempo"			- current tempo in (PPQN? speed in frames, SMPTE*? speed in hsmf)
+ *	"offset"		- offset in dito.
+ *	"port"			- midi port as integer
+ * 	"slave"			- slave device ("midi","file","none","smpte")
+ *	"master"		- masterdevice (dito.)
+ * Overlay:
+ *	"window handle"		- see animation
+ *	"stretch"		- dito
+ * Video Disc:
+ *	"speed"			- speed as integer
+ *	"forward"		- returns bool (when playing forward)
+ *	"side"			- returns 1 or 2
+ *	"media type"		- returns "CAV" "CLV" "other"
+ *	"disc size"		- returns "8" or "12"
+ * WAVEFORM audio:
+ *	"input"			- base queries on input set
+ *	"output"		- base queries on output set
+ *	"format tag"		- return integer format tag
+ *	"channels"		- return integer nr of channels
+ *	"bytespersec"		- return average nr of bytes/sec
+ *	"samplespersec"		- return nr of samples per sec
+ *	"bitspersample"		- return bitspersample
+ *	"alignment"		- return block alignment
+ *	"level"			- return level?
+ */
+
+#define ITEM1(str,item,xtype) \
+	if (!STRCMP(keywords[i],str)) {\
+		statusParams.dwItem = item;\
+		type = xtype;\
+		i++;\
+		continue;\
+	}
+#define ITEM2(str1,str2,item,xtype) \
+	if (	!STRCMP(keywords[i],str1) &&\
+		(i+1<nrofkeywords) &&\
+		!STRCMP(keywords[i+1],str2)\
+	) {\
+		statusParams.dwItem = item;\
+		type = xtype;\
+		i+=2;\
+		continue;\
+	}
+#define ITEM3(str1,str2,str3,item,xtype) \
+	if (	!STRCMP(keywords[i],str1) &&\
+		(i+2<nrofkeywords) &&\
+		!STRCMP(keywords[i+1],str2) &&\
+		!STRCMP(keywords[i+2],str3)\
+	) {\
+		statusParams.dwItem = item;\
+		type = xtype;\
+		i+=3;\
+		continue;\
+	}
+static DWORD
+MCISTR_Status(_MCISTR_PROTO_) {
+	MCI_STATUS_PARMS	statusParams;
+	int			type,i,res,timef;
+
+	statusParams.dwCallback = 0;
+	dwFlags	|= MCI_STATUS_ITEM;
+	res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
+	if (res) return res;
+
+	statusParams.dwReturn	= 0;
+	statusParams.dwItem	= 0;
+	i = 0;
+
+	while (i<nrofkeywords) {
+		if (!STRCMP(keywords[i],"track") && (i+1<nrofkeywords)) {
+			sscanf(keywords[i+1],"%ld",&(statusParams.dwTrack));
+			dwFlags |= MCI_TRACK;
+			i+=2;
+			continue;
+		}
+		FLAG1("start",MCI_STATUS_START);
+		/* generic things */
+		ITEM2("current","track",MCI_STATUS_CURRENT_TRACK,_MCISTR_time);
+		ITEM2("time","format",MCI_STATUS_TIME_FORMAT,_MCISTR_tfname);
+		ITEM1("ready",MCI_STATUS_READY,_MCISTR_bool);
+		ITEM1("mode",MCI_STATUS_MODE,_MCISTR_mode);
+		ITEM3("number","of","tracks",MCI_STATUS_NUMBER_OF_TRACKS,_MCISTR_int);
+		ITEM1("length",MCI_STATUS_LENGTH,_MCISTR_time);
+		ITEM1("position",MCI_STATUS_POSITION,_MCISTR_time);
+		ITEM2("media","present",MCI_STATUS_MEDIA_PRESENT,_MCISTR_bool);
+
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+		case MCI_DEVTYPE_DIGITAL_VIDEO:
+			ITEM2("palette","handle",MCI_ANIM_STATUS_HPAL,_MCISTR_int);
+			ITEM2("window","handle",MCI_ANIM_STATUS_HWND,_MCISTR_int);
+			ITEM1("stretch",MCI_ANIM_STATUS_STRETCH,_MCISTR_bool);
+			ITEM1("speed",MCI_ANIM_STATUS_SPEED,_MCISTR_int);
+			ITEM1("forward",MCI_ANIM_STATUS_FORWARD,_MCISTR_bool);
+			break;
+		case MCI_DEVTYPE_SEQUENCER:
+			/* just completing the list, not working correctly */
+			ITEM2("division","type",MCI_SEQ_STATUS_DIVTYPE,_MCISTR_divtype);
+			/* tempo ... PPQN in frames/second, SMPTE in hmsf */
+			ITEM1("tempo",MCI_SEQ_STATUS_TEMPO,_MCISTR_int);
+			ITEM1("port",MCI_SEQ_STATUS_PORT,_MCISTR_int);
+			ITEM1("slave",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
+			ITEM1("master",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
+			/* offset ... PPQN in frames/second, SMPTE in hmsf */
+			ITEM1("offset",MCI_SEQ_STATUS_SLAVE,_MCISTR_time);
+			break;
+		case MCI_DEVTYPE_OVERLAY:
+			ITEM2("window","handle",MCI_OVLY_STATUS_HWND,_MCISTR_int);
+			ITEM1("stretch",MCI_OVLY_STATUS_STRETCH,_MCISTR_bool);
+			break;
+		case MCI_DEVTYPE_VIDEODISC:
+			ITEM1("speed",MCI_VD_STATUS_SPEED,_MCISTR_int);
+			ITEM1("forward",MCI_VD_STATUS_FORWARD,_MCISTR_bool);
+			ITEM1("side",MCI_VD_STATUS_SIDE,_MCISTR_int);
+			ITEM2("media","type",MCI_VD_STATUS_SIDE,_MCISTR_vdmtype);
+			/* returns 8 or 12 */
+			ITEM2("disc","size",MCI_VD_STATUS_DISC_SIZE,_MCISTR_int);
+			break;
+		case MCI_DEVTYPE_WAVEFORM_AUDIO:
+			/* I am not quite sure if foll. 2 lines are right. */
+			FLAG1("input",MCI_WAVE_INPUT);
+			FLAG1("output",MCI_WAVE_OUTPUT);
+
+			ITEM2("format","tag",MCI_WAVE_STATUS_FORMATTAG,_MCISTR_int);
+			ITEM1("channels",MCI_WAVE_STATUS_CHANNELS,_MCISTR_int);
+			ITEM1("bytespersec",MCI_WAVE_STATUS_AVGBYTESPERSEC,_MCISTR_int);
+			ITEM1("samplespersec",MCI_WAVE_STATUS_SAMPLESPERSEC,_MCISTR_int);
+			ITEM1("bitspersample",MCI_WAVE_STATUS_BITSPERSAMPLE,_MCISTR_int);
+			ITEM1("alignment",MCI_WAVE_STATUS_BLOCKALIGN,_MCISTR_int);
+			ITEM1("level",MCI_WAVE_STATUS_LEVEL,_MCISTR_int);
+			break;
+		}
+		fprintf(stdnimp,__FILE__":MCISTR_Status:unknown keyword '%s'\n",keywords[i]);
+		i++;
+	}
+	if (!statusParams.dwItem) 
+		return MCIERR_MISSING_STRING_ARGUMENT;
+
+	_MCI_CALL_DRIVER(MCI_STATUS,statusParams);
+	if (res==0)
+		_MCISTR_convreturn(type,statusParams.dwReturn,lpstrReturnString,uReturnLength,uDevTyp,timef);
+	return res;
+}
+#undef ITEM1
+#undef ITEM2
+#undef ITEM3
+
+/* set specified parameters in respective MCI drivers
+ * Arguments:
+ *	"door open"	eject media or somesuch
+ *	"door close"	load media
+ *	"time format <timeformatname>"	"ms" "milliseconds" "msf" "hmsf" 
+ *					"tmsf" "SMPTE 24" "SMPTE 25" "SMPTE 30"
+ *					"SMPTE drop 30"
+ *	"audio [all|left|right] [on|off]" sets specified audiochannel on or off
+ *	"video [on|off]"		sets video on/off
+ * Waveform audio:
+ *	"formattag pcm"		sets format to pcm
+ *	"formattag <nr>"	sets integer formattag value
+ *	"any input"		accept input from any known source
+ *	"any output"		output to any known destination
+ *	"input <nr>"		input from source <nr>
+ *	"output <nr>"		output to destination <nr>
+ *	"channels <nr>"		sets nr of channels 
+ *	"bytespersec <nr>"	sets average bytes per second
+ *	"samplespersec <nr>"	sets average samples per second (1 sample can
+ *				be 2 bytes!) 
+ *	"alignment <nr>"	sets the blockalignment to <nr>
+ *	"bitspersample <nr>"	sets the nr of bits per sample
+ * Sequencer:
+ *	"master [midi|file|smpte|none]" sets the midi master device
+ *	"slave [midi|file|smpte|none]" sets the midi master device
+ *	"port mapper"		midioutput to portmapper
+ *	"port <nr>"		midioutput to specified port
+ *	"tempo <nr>"		tempo of track (depends on timeformat/divtype)
+ *	"offset <nr>"		start offset?
+ */
+static DWORD
+MCISTR_Set(_MCISTR_PROTO_) {
+	union	{
+		MCI_SET_PARMS		setParams;
+		MCI_WAVE_SET_PARMS	wavesetParams;
+		MCI_SEQ_SET_PARMS	seqsetParams;
+	} U;
+	int	i,res;
+
+	U.setParams.dwCallback = 0;
+	i = 0;
+	while (i<nrofkeywords) {
+		FLAG2("door","open",MCI_SET_DOOR_OPEN);
+		FLAG2("door","closed",MCI_SET_DOOR_CLOSED);
+
+		if (	!STRCMP(keywords[i],"time") && 
+			(i+2<nrofkeywords) &&
+			!STRCMP(keywords[i+1],"format")
+		) {
+			dwFlags |= MCI_SET_TIME_FORMAT;
+
+			/* FIXME:is this a shortcut for milliseconds or
+			 *	 minutes:seconds? */
+			if (!STRCMP(keywords[i+2],"ms"))
+				U.setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
+
+			if (!STRCMP(keywords[i+2],"milliseconds"))
+				U.setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
+			if (!STRCMP(keywords[i+2],"msf"))
+				U.setParams.dwTimeFormat = MCI_FORMAT_MSF;
+			if (!STRCMP(keywords[i+2],"hms"))
+				U.setParams.dwTimeFormat = MCI_FORMAT_HMS;
+			if (!STRCMP(keywords[i+2],"frames"))
+				U.setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
+			if (!STRCMP(keywords[i+2],"track"))
+				U.setParams.dwTimeFormat = MCI_VD_FORMAT_TRACK;
+			if (!STRCMP(keywords[i+2],"bytes"))
+				U.setParams.dwTimeFormat = MCI_FORMAT_BYTES;
+			if (!STRCMP(keywords[i+2],"samples"))
+				U.setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
+			if (!STRCMP(keywords[i+2],"tmsf"))
+				U.setParams.dwTimeFormat = MCI_FORMAT_TMSF;
+			if (	!STRCMP(keywords[i+2],"song") && 
+				(i+3<nrofkeywords) &&
+				!STRCMP(keywords[i+3],"pointer")
+			)
+				U.setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR;
+			if (!STRCMP(keywords[i+2],"smpte") && (i+3<nrofkeywords)) {
+				if (!STRCMP(keywords[i+3],"24"))
+					U.setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
+				if (!STRCMP(keywords[i+3],"25"))
+					U.setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
+				if (!STRCMP(keywords[i+3],"30"))
+					U.setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
+				if (!STRCMP(keywords[i+3],"drop") && (i+4<nrofkeywords) && !STRCMP(keywords[i+4],"30")) {
+					U.setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
+					i++;
+				}
+				i++;
+				/*FALLTHROUGH*/
+			}
+			i+=3;
+			continue;
+		}
+		if (!STRCMP(keywords[i],"audio") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_SET_AUDIO;
+			if (!STRCMP(keywords[i+1],"all"))
+				U.setParams.dwAudio = MCI_SET_AUDIO_ALL;
+			if (!STRCMP(keywords[i+1],"left"))
+				U.setParams.dwAudio = MCI_SET_AUDIO_LEFT;
+			if (!STRCMP(keywords[i+1],"right"))
+				U.setParams.dwAudio = MCI_SET_AUDIO_RIGHT;
+			i+=2;
+			continue;
+		}
+		FLAG1("video",MCI_SET_VIDEO);
+		FLAG1("on",MCI_SET_ON);
+		FLAG1("off",MCI_SET_OFF);
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_WAVEFORM_AUDIO:
+			FLAG2("any","input",MCI_WAVE_SET_ANYINPUT);
+			FLAG2("any","output",MCI_WAVE_SET_ANYOUTPUT);
+
+			if (	!STRCMP(keywords[i],"formattag") && 
+				(i+1<nrofkeywords) &&
+				!STRCMP(keywords[i+1],"pcm")
+			) {
+				dwFlags |= MCI_WAVE_SET_FORMATTAG;
+				U.wavesetParams.wFormatTag = WAVE_FORMAT_PCM;
+				i+=2;
+				continue;
+			}
+
+			/* <keyword> <integer> */
+#define WII(str,flag,element) \
+			if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
+				sscanf(keywords[i+1],"%d",&(U.wavesetParams. element ));\
+				dwFlags |= flag;\
+				i+=2;\
+				continue;\
+			}
+			WII("formattag",MCI_WAVE_SET_FORMATTAG,wFormatTag);
+			WII("channels",MCI_WAVE_SET_CHANNELS,nChannels);
+			WII("bytespersec",MCI_WAVE_SET_AVGBYTESPERSEC,nAvgBytesPerSec);
+			WII("samplespersec",MCI_WAVE_SET_SAMPLESPERSEC,nSamplesPerSec);
+			WII("alignment",MCI_WAVE_SET_BLOCKALIGN,nBlockAlign);
+			WII("bitspersample",MCI_WAVE_SET_BITSPERSAMPLE,wBitsPerSample);
+			WII("input",MCI_WAVE_INPUT,wInput);
+			WII("output",MCI_WAVE_OUTPUT,wOutput);
+#undef WII
+			break;
+		case MCI_DEVTYPE_SEQUENCER:
+			if (!STRCMP(keywords[i],"master") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_SEQ_SET_MASTER;
+				if (!STRCMP(keywords[i+1],"midi"))
+					U.seqsetParams.dwMaster = MCI_SEQ_MIDI;
+				if (!STRCMP(keywords[i+1],"file"))
+					U.seqsetParams.dwMaster = MCI_SEQ_FILE;
+				if (!STRCMP(keywords[i+1],"smpte"))
+					U.seqsetParams.dwMaster = MCI_SEQ_SMPTE;
+				if (!STRCMP(keywords[i+1],"none"))
+					U.seqsetParams.dwMaster = MCI_SEQ_NONE;
+				i+=2;
+				continue;
+			}
+			if (!STRCMP(keywords[i],"slave") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_SEQ_SET_SLAVE;
+				if (!STRCMP(keywords[i+1],"midi"))
+					U.seqsetParams.dwMaster = MCI_SEQ_MIDI;
+				if (!STRCMP(keywords[i+1],"file"))
+					U.seqsetParams.dwMaster = MCI_SEQ_FILE;
+				if (!STRCMP(keywords[i+1],"smpte"))
+					U.seqsetParams.dwMaster = MCI_SEQ_SMPTE;
+				if (!STRCMP(keywords[i+1],"none"))
+					U.seqsetParams.dwMaster = MCI_SEQ_NONE;
+				i+=2;
+				continue;
+			}
+			if (	!STRCMP(keywords[i],"port") && 
+				(i+1<nrofkeywords) &&
+				!STRCMP(keywords[i+1],"mapper")
+			) {
+				U.seqsetParams.dwPort=-1;/* FIXME:not sure*/
+				dwFlags |= MCI_SEQ_SET_PORT;
+				i+=2;
+				continue;
+			}
+#define SII(str,flag,element) \
+			if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
+				sscanf(keywords[i+1],"%ld",&(U.seqsetParams. element ));\
+				dwFlags |= flag;\
+				i+=2;\
+				continue;\
+			}
+			SII("tempo",MCI_SEQ_SET_TEMPO,dwTempo);
+			SII("port",MCI_SEQ_SET_PORT,dwPort);
+			SII("offset",MCI_SEQ_SET_PORT,dwOffset);
+		}
+		i++;
+	}
+	if (!dwFlags)
+		return MCIERR_MISSING_STRING_ARGUMENT;
+	_MCI_CALL_DRIVER(MCI_SET,U);
+	return res;
+}
+
+/* specify break key
+ * Arguments: 
+ *	"off"		disable break
+ *	"on <keyid>"	enable break on key with keyid
+ * (I strongly suspect, that there is another parameter:
+ *	"window <handle>"	
+ * but I don't see it mentioned in my documentation.
+ * Returns nothing.
+ */
+static DWORD
+MCISTR_Break(_MCISTR_PROTO_) {
+	MCI_BREAK_PARMS	breakParams;
+	int	res,i;
+
+	/*breakParams.hwndBreak ? */
+	i=0;while (i<nrofkeywords) {
+		FLAG1("off",MCI_BREAK_OFF);
+		if (!strcmp(keywords[i],"on") && (nrofkeywords>i+1)) {
+			dwFlags&=~MCI_BREAK_OFF;
+			dwFlags|=MCI_BREAK_KEY;
+			sscanf(keywords[i+1],"%d",&(breakParams.nVirtKey));
+			i+=2;
+			continue;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_BREAK,breakParams);
+	return res;
+}
+
+#define ITEM1(str,item,xtype) \
+	if (!STRCMP(keywords[i],str)) {\
+		gdcParams.dwItem = item;\
+		type = xtype;\
+		i++;\
+		continue;\
+	}
+#define ITEM2(str1,str2,item,xtype) \
+	if (	!STRCMP(keywords[i],str1) &&\
+		(i+1<nrofkeywords) &&\
+		!STRCMP(keywords[i+1],str2)\
+	) {\
+		gdcParams.dwItem = item;\
+		type = xtype;\
+		i+=2;\
+		continue;\
+	}
+#define ITEM3(str1,str2,str3,item,xtype) \
+	if (	!STRCMP(keywords[i],str1) &&\
+		(i+2<nrofkeywords) &&\
+		!STRCMP(keywords[i+1],str2) &&\
+		!STRCMP(keywords[i+2],str3)\
+	) {\
+		gdcParams.dwItem = item;\
+		type = xtype;\
+		i+=3;\
+		continue;\
+	}
+/* get device capabilities of MCI drivers
+ * Arguments:
+ * Generic:
+ *	"device type"	returns device name as string
+ *	"has audio"	returns bool
+ *	"has video"	returns bool
+ *	"uses files"	returns bool
+ *	"compound device"	returns bool
+ *	"can record"	returns bool
+ *	"can play"	returns bool
+ *	"can eject"	returns bool
+ *	"can save"	returns bool
+ * Animation:
+ *	"palettes"	returns nr of available palette entries
+ *	"windows"	returns nr of available windows
+ *	"can reverse"	returns bool
+ *	"can stretch"	returns bool
+ *	"slow play rate"	returns the slow playrate
+ *	"fast play rate"	returns the fast playrate
+ *	"normal play rate"	returns the normal playrate
+ * Overlay:
+ *	"windows"	returns nr of available windows
+ *	"can stretch"	returns bool
+ *	"can freeze"	returns bool
+ * Videodisc:
+ *	"cav"		assume CAV discs (default if no disk inserted)
+ *	"clv"		assume CLV discs 
+ *	"can reverse"	returns bool
+ *	"slow play rate"	returns the slow playrate
+ *	"fast play rate"	returns the fast playrate
+ *	"normal play rate"	returns the normal playrate
+ * Waveform audio:
+ *	"inputs"	returns nr of inputdevices
+ *	"outputs"	returns nr of outputdevices
+ */
+static DWORD
+MCISTR_Capability(_MCISTR_PROTO_) {
+	MCI_GETDEVCAPS_PARMS	gdcParams;
+	int	type,i,res;
+
+	gdcParams.dwCallback = 0;
+	if (!nrofkeywords)
+		return MCIERR_MISSING_STRING_ARGUMENT;
+	/* well , thats default */
+	dwFlags |= MCI_GETDEVCAPS_ITEM;
+	gdcParams.dwItem = 0;
+	i=0;
+	while (i<nrofkeywords) {
+		ITEM2("device","type",MCI_GETDEVCAPS_DEVICE_TYPE,_MCISTR_devtype);
+		ITEM2("has","audio",MCI_GETDEVCAPS_HAS_AUDIO,_MCISTR_bool);
+		ITEM2("has","video",MCI_GETDEVCAPS_HAS_VIDEO,_MCISTR_bool);
+		ITEM2("uses","files",MCI_GETDEVCAPS_USES_FILES,_MCISTR_bool);
+		ITEM2("compound","device",MCI_GETDEVCAPS_COMPOUND_DEVICE,_MCISTR_bool);
+		ITEM2("can","record",MCI_GETDEVCAPS_CAN_RECORD,_MCISTR_bool);
+		ITEM2("can","play",MCI_GETDEVCAPS_CAN_PLAY,_MCISTR_bool);
+		ITEM2("can","eject",MCI_GETDEVCAPS_CAN_EJECT,_MCISTR_bool);
+		ITEM2("can","save",MCI_GETDEVCAPS_CAN_SAVE,_MCISTR_bool);
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+			ITEM1("palettes",MCI_ANIM_GETDEVCAPS_PALETTES,_MCISTR_int);
+			ITEM1("windows",MCI_ANIM_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
+			ITEM2("can","reverse",MCI_ANIM_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
+			ITEM2("can","stretch",MCI_ANIM_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
+			ITEM3("slow","play","rate",MCI_ANIM_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
+			ITEM3("fast","play","rate",MCI_ANIM_GETDEVCAPS_FAST_RATE,_MCISTR_int);
+			ITEM3("normal","play","rate",MCI_ANIM_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
+			break;
+		case MCI_DEVTYPE_OVERLAY:
+			ITEM1("windows",MCI_OVLY_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
+			ITEM2("can","freeze",MCI_OVLY_GETDEVCAPS_CAN_FREEZE,_MCISTR_bool);
+			ITEM2("can","stretch",MCI_OVLY_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
+			break;
+		case MCI_DEVTYPE_VIDEODISC:
+			FLAG1("cav",MCI_VD_GETDEVCAPS_CAV);
+			FLAG1("clv",MCI_VD_GETDEVCAPS_CLV);
+			ITEM2("can","reverse",MCI_VD_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
+			ITEM3("slow","play","rate",MCI_VD_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
+			ITEM3("fast","play","rate",MCI_VD_GETDEVCAPS_FAST_RATE,_MCISTR_int);
+			ITEM3("normal","play","rate",MCI_VD_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
+			break;
+		case MCI_DEVTYPE_WAVEFORM_AUDIO:
+			ITEM1("inputs",MCI_WAVE_GETDEVCAPS_INPUTS,_MCISTR_int);
+			ITEM1("outputs",MCI_WAVE_GETDEVCAPS_OUTPUTS,_MCISTR_int);
+			break;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_GETDEVCAPS,gdcParams);
+	/* no timeformat needed */
+	if (res==0)
+		_MCISTR_convreturn(type,gdcParams.dwReturn,lpstrReturnString,uReturnLength,uDevTyp,0);
+	return res;
+}
+#undef ITEM1
+#undef ITEM2
+#undef ITEM3
+/* resumes operation of device. no arguments, no return values */
+static DWORD
+MCISTR_Resume(_MCISTR_PROTO_) {
+	MCI_GENERIC_PARMS	genParams;
+	int	res;
+
+	genParams.dwCallback=0;
+	_MCI_CALL_DRIVER(MCI_RESUME,genParams);
+	return res;
+}
+
+/* pauses operation of device. no arguments, no return values */
+static DWORD
+MCISTR_Pause(_MCISTR_PROTO_) {
+	MCI_GENERIC_PARMS	genParams;
+	int			res;
+	genParams.dwCallback=0;
+	_MCI_CALL_DRIVER(MCI_PAUSE,genParams);
+	return res;
+}
+
+/* stops operation of device. no arguments, no return values */
+static DWORD
+MCISTR_Stop(_MCISTR_PROTO_) {
+	MCI_GENERIC_PARMS	genParams;
+	int			res;
+	genParams.dwCallback=0;
+	_MCI_CALL_DRIVER(MCI_STOP,genParams);
+	return res;
+}
+
+/* starts recording.
+ * Arguments:
+ *	"overwrite"	overwrite existing things
+ *	"insert"	insert at current position
+ *	"to <time>"	record up to <time> (specified in timeformat)
+ *	"from <time>"	record from <time> (specified in timeformat)
+ */
+static DWORD
+MCISTR_Record(_MCISTR_PROTO_) {
+	int			i,res,timef,nrargs,j,k,a[4];
+	char			*parsestr;
+	MCI_RECORD_PARMS	recordParams;
+
+	res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
+	if (res) return res;
+
+	switch (timef) {
+	case MCI_FORMAT_MILLISECONDS:
+	case MCI_FORMAT_FRAMES:
+	case MCI_FORMAT_BYTES:
+	case MCI_FORMAT_SAMPLES:
+		nrargs=1;
+		parsestr="%d";
+		break;
+	case MCI_FORMAT_HMS:
+	case MCI_FORMAT_MSF:
+		parsestr="%d:%d:%d";
+		nrargs=3;
+		break;
+	case MCI_FORMAT_TMSF:
+		parsestr="%d:%d:%d:%d";
+		nrargs=4;
+		break;
+	default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
+		parsestr="%d";
+		nrargs=1;
+		break;
+	}
+	recordParams.dwCallback = 0;
+	i = 0;
+	while (i<nrofkeywords) {
+		if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_TO;
+			a[0]=a[1]=a[2]=a[3]=0;
+			j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
+			/* add up all integers we got, if we have more 
+			 * shift them. (Well I should use the macros in 
+			 * mmsystem.h, right).
+			 */
+			recordParams.dwTo=0;
+			for (k=0;k<j;k++)
+				recordParams.dwTo+=a[k]<<(8*(nrargs-k));
+			i+=2;
+			continue;
+		}
+		if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_FROM;
+			a[0]=a[1]=a[2]=a[3]=0;
+			j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
+			/* dito. */
+			recordParams.dwFrom=0;
+			for (k=0;k<j;k++)
+				recordParams.dwFrom+=a[k]<<(8*(nrargs-k));
+			i+=2;
+			continue;
+		}
+		FLAG1("insert",MCI_RECORD_INSERT);
+		FLAG1("overwrite",MCI_RECORD_OVERWRITE);
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_RECORD,recordParams);
+	return res;
+}
+
+/* play media
+ * Arguments:
+ * 	"to <time>"	play up to <time> (specified in set timeformat)
+ * 	"from <time>"	play from <time> (specified in set timeformat)
+ * Animation:
+ *	"slow"		play slow
+ *	"fast"		play fast 
+ *	"scan"		play as fast as possible (with audio disabled perhaps)
+ *	"reverse"	play reverse
+ *	"speed <fps>"	play with specified frames per second
+ * Videodisc:
+ *	"slow"		play slow
+ *	"fast"		play fast 
+ *	"scan"		play as fast as possible (with audio disabled perhaps)
+ *	"reverse"	play reverse
+ *	"speed <fps>"	play with specified frames per second
+ */
+static DWORD
+MCISTR_Play(_MCISTR_PROTO_) {
+	int			i,res,timef,nrargs,j,k,a[4];
+	char			*parsestr;
+	union {
+		MCI_PLAY_PARMS		playParams;
+		MCI_VD_PLAY_PARMS	vdplayParams;
+		MCI_ANIM_PLAY_PARMS	animplayParams;
+	} U;
+
+	res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
+	if (res) return res;
+	switch (timef) {
+	case MCI_FORMAT_MILLISECONDS:
+	case MCI_FORMAT_FRAMES:
+	case MCI_FORMAT_BYTES:
+	case MCI_FORMAT_SAMPLES:
+		nrargs=1;
+		parsestr="%d";
+		break;
+	case MCI_FORMAT_HMS:
+	case MCI_FORMAT_MSF:
+		parsestr="%d:%d:%d";
+		nrargs=3;
+		break;
+	case MCI_FORMAT_TMSF:
+		parsestr="%d:%d:%d:%d";
+		nrargs=4;
+		break;
+	default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
+		parsestr="%d";
+		nrargs=1;
+		break;
+	}
+	U.playParams.dwCallback=0;
+	i=0;
+	while (i<nrofkeywords) {
+		if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_TO;
+			a[0]=a[1]=a[2]=a[3]=0;
+			j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
+			/* add up all integers we got, if we have more 
+			 * shift them. (Well I should use the macros in 
+			 * mmsystem.h, right).
+			 */
+			U.playParams.dwTo=0;
+			for (k=0;k<j;k++)
+				U.playParams.dwTo+=a[k]<<(8*(nrargs-k));
+			i+=2;
+			continue;
+		}
+		if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_FROM;
+			a[0]=a[1]=a[2]=a[3]=0;
+			j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
+			/* dito. */
+			U.playParams.dwFrom=0;
+			for (k=0;k<j;k++)
+				U.playParams.dwFrom+=a[k]<<(8*(nrargs-k));
+			i+=2;
+			continue;
+		}
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_VIDEODISC:
+			FLAG1("slow",MCI_VD_PLAY_SLOW);
+			FLAG1("fast",MCI_VD_PLAY_FAST);
+			FLAG1("scan",MCI_VD_PLAY_SCAN);
+			FLAG1("reverse",MCI_VD_PLAY_REVERSE);
+			if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_VD_PLAY_SPEED;
+				sscanf(keywords[i+1],"%ld",&(U.vdplayParams.dwSpeed));
+				i+=2;
+				continue;
+			}
+			break;
+		case MCI_DEVTYPE_ANIMATION:
+			FLAG1("slow",MCI_ANIM_PLAY_SLOW);
+			FLAG1("fast",MCI_ANIM_PLAY_FAST);
+			FLAG1("scan",MCI_ANIM_PLAY_SCAN);
+			FLAG1("reverse",MCI_ANIM_PLAY_REVERSE);
+			if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_ANIM_PLAY_SPEED;
+				sscanf(keywords[i+1],"%ld",&(U.animplayParams.dwSpeed));
+				i+=2;
+				continue;
+			}
+			break;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_PLAY,U);
+	return res;
+}
+
+/* seek to a specified position
+ * Arguments:
+ *	"to start"	seek to start of medium
+ *	"to end"	seek to end of medium
+ * 	"to <time>"	seek to <time> specified in current timeformat
+ */
+static DWORD
+MCISTR_Seek(_MCISTR_PROTO_) {
+	int		i,res,timef,nrargs,j,k,a[4];
+	char		*parsestr;
+	MCI_SEEK_PARMS	seekParams;
+
+	res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
+	if (res) return res;
+	switch (timef) {
+	case MCI_FORMAT_MILLISECONDS:
+	case MCI_FORMAT_FRAMES:
+	case MCI_FORMAT_BYTES:
+	case MCI_FORMAT_SAMPLES:
+		nrargs=1;
+		parsestr="%d";
+		break;
+	case MCI_FORMAT_HMS:
+	case MCI_FORMAT_MSF:
+		parsestr="%d:%d:%d";
+		nrargs=3;
+		break;
+	case MCI_FORMAT_TMSF:
+		parsestr="%d:%d:%d:%d";
+		nrargs=4;
+		break;
+	default:fprintf(stdnimp,"mciSendString:SEEK:unknown timeformat %d, please report.\n",timef);
+		parsestr="%d";
+		nrargs=1;
+		break;
+	}
+	seekParams.dwCallback=0;
+	i=0;
+	while (i<nrofkeywords) {
+		if (	!STRCMP(keywords[i],"to") && (i+1<nrofkeywords)) {
+			if (!STRCMP(keywords[i+1],"start")) {
+				dwFlags|=MCI_SEEK_TO_START;
+				seekParams.dwTo=0;
+				i+=2;
+				continue;
+			}
+			if (!STRCMP(keywords[i+1],"end")) {
+				dwFlags|=MCI_SEEK_TO_END;
+				seekParams.dwTo=0;
+				i+=2;
+				continue;
+			}
+			dwFlags|=MCI_TO;
+			i+=2;
+			a[0]=a[1]=a[2]=a[3]=0;
+			j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
+			seekParams.dwTo=0;
+			for (k=0;k<j;k++)
+				seekParams.dwTo+=a[k]<<(8*(nrargs-k));
+			continue;
+		}
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_VIDEODISC:
+			FLAG1("reverse",MCI_VD_SEEK_REVERSE);
+			break;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_SEEK,seekParams);
+	return res;
+}
+
+/* close media/driver */
+static DWORD
+MCISTR_Close(_MCISTR_PROTO_) {
+	MCI_GENERIC_PARMS	closeParams;
+	int			res;
+
+	_MCI_CALL_DRIVER(MCI_CLOSE,closeParams);
+	return res;
+}
+
+/* return information.
+ * Arguments:
+ *	"product"	return product name (human readable)
+ *	"file"		return filename
+ * Animation:
+ *	"text"		returns text?
+ * Overlay:
+ *	"text"		returns text?
+ */
+static DWORD
+MCISTR_Info(_MCISTR_PROTO_) {
+	MCI_INFO_PARMS	infoParams;
+	DWORD		sflags;
+	int		i,res;
+
+	sflags = dwFlags;
+	i=0;while (i<nrofkeywords) {
+		FLAG1("product",MCI_INFO_PRODUCT);
+		FLAG1("file",MCI_INFO_FILE);
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+			FLAG1("text",MCI_ANIM_INFO_TEXT);
+			break;
+		case MCI_DEVTYPE_OVERLAY:
+			FLAG1("text",MCI_OVLY_INFO_TEXT);
+			break;
+		}
+		i++;
+	}
+	if (dwFlags == sflags)
+		return MCIERR_MISSING_STRING_ARGUMENT;
+	/* MCI driver will fill in lpstrReturn, dwRetSize.
+	 * FIXME: I don't know if this is correct behaviour
+	 */
+	_MCI_CALL_DRIVER(MCI_INFO,infoParams);
+	if (res==0)
+		_MCI_STR(infoParams.lpstrReturn);
+	return res;
+}
+
+/* query MCI driver itself for information
+ * Arguments:
+ *	"installname"	return install name of <device> (system.ini)
+ *	"quantity"	return nr of installed drivers
+ *	"open"		open drivers only (additional flag)
+ *	"name <nr>"	return nr of devices with <devicetyp>
+ *	"name all"	return nr of all devices
+ *
+ * FIXME: mciSysInfo() is broken I think.
+ */
+static DWORD
+MCISTR_Sysinfo(_MCISTR_PROTO_) {
+	MCI_SYSINFO_PARMS	sysinfoParams;
+	int			i,res;
+
+	sysinfoParams.lpstrReturn	= lpstrReturnString;
+	sysinfoParams.dwRetSize		= uReturnLength;
+	sysinfoParams.wDeviceType	= uDevTyp;
+	i=0;
+	while (i<nrofkeywords) {
+		FLAG1("installname",MCI_SYSINFO_INSTALLNAME);
+		FLAG1("quantity",MCI_SYSINFO_INSTALLNAME);
+		FLAG1("open",MCI_SYSINFO_OPEN);
+		if (!strcmp(keywords[i],"name") && (i+1<nrofkeywords)) {
+			sscanf(keywords[i+1],"%ld",&(sysinfoParams.dwNumber));
+			dwFlags |= MCI_SYSINFO_NAME;
+			i+=2;
+			continue;
+		}
+		i++;
+	}
+	res=mciSysInfo(dwFlags,&sysinfoParams);
+	if (dwFlags & MCI_SYSINFO_QUANTITY) {
+		char	buf[100];
+
+		sprintf(buf,"%ld",*(long*)PTR_SEG_TO_LIN(lpstrReturnString));
+		_MCI_STR(buf);
+	}
+	/* no need to copy anything back, mciSysInfo did it for us */
+	return res;
+}
+
+/* load file
+ * Argument: "<filename>"
+ * Overlay: "at <left> <top> <right> <bottom>" additional
+ */
+static DWORD
+MCISTR_Load(_MCISTR_PROTO_) {
+	union {
+		MCI_LOAD_PARMS	loadParams;
+		MCI_OVLY_LOAD_PARMS	ovlyloadParams;
+	} U;
+	int		i,len,res;
+	char		*s;
+	HANDLE		x;
+
+	i=0;len=0;
+	while (i<nrofkeywords) {
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_OVERLAY:
+			if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
+				dwFlags |= MCI_OVLY_RECT;
+				sscanf(keywords[i+1],"%d",&(U.ovlyloadParams.rc.left));
+				sscanf(keywords[i+2],"%d",&(U.ovlyloadParams.rc.top));
+				sscanf(keywords[i+3],"%d",&(U.ovlyloadParams.rc.right));
+				sscanf(keywords[i+4],"%d",&(U.ovlyloadParams.rc.bottom));
+				memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
+				continue;
+			}
+			break;
+		}
+		len+=strlen(keywords[i])+1;
+		i++;
+	}
+	s=(char*)malloc(len);
+	*s='\0';
+	while (i<nrofkeywords) {
+		strcat(s,keywords[i]);
+		i++;
+		if (i<nrofkeywords) strcat(s," ");
+	}
+	/* FIXME: messy, but I strongly suspect we have to use a 
+	 * segmented pointer, so I am doing that
+	 */
+	x=USER_HEAP_ALLOC(len);
+	U.loadParams.lpfilename=(LPSTR)MAKELONG(x,USER_HeapSel);
+	strcpy(PTR_SEG_TO_LIN(U.loadParams.lpfilename),s);
+	free(s);
+	dwFlags |= MCI_LOAD_FILE;
+	_MCI_CALL_DRIVER(MCI_LOAD,U);
+	USER_HEAP_FREE(x);
+	return res;
+}
+
+/* save to file
+ * Argument: "<filename>"
+ * Overlay: "at <left> <top> <right> <bottom>" additional
+ */
+static DWORD
+MCISTR_Save(_MCISTR_PROTO_) {
+	union {
+		MCI_SAVE_PARMS	saveParams;
+		MCI_OVLY_SAVE_PARMS	ovlysaveParams;
+	} U;
+	int		i,len,res;
+	char		*s;
+	HANDLE		x;
+
+	i=0;len=0;
+	while (i<nrofkeywords) {
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_OVERLAY:
+			if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
+				dwFlags |= MCI_OVLY_RECT;
+				sscanf(keywords[i+1],"%d",&(U.ovlysaveParams.rc.left));
+				sscanf(keywords[i+2],"%d",&(U.ovlysaveParams.rc.top));
+				sscanf(keywords[i+3],"%d",&(U.ovlysaveParams.rc.right));
+				sscanf(keywords[i+4],"%d",&(U.ovlysaveParams.rc.bottom));
+				memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
+				continue;
+			}
+			break;
+		}
+		len+=strlen(keywords[i])+1;
+		i++;
+	}
+	s=(char*)malloc(len);
+	*s='\0';
+	while (i<nrofkeywords) {
+		strcat(s,keywords[i]);
+		i++;
+		if (i<nrofkeywords) strcat(s," ");
+	}
+	/* FIXME: messy, but I strongly suspect we have to use a 
+	 * segmented pointer, so I am doing that
+	 */
+	x=USER_HEAP_ALLOC(len);
+	U.saveParams.lpfilename=(LPSTR)MAKELONG(x,USER_HeapSel);
+	strcpy(PTR_SEG_TO_LIN(U.saveParams.lpfilename),s);
+	free(s);
+	dwFlags |= MCI_LOAD_FILE;
+	_MCI_CALL_DRIVER(MCI_SAVE,U);
+	USER_HEAP_FREE(x);
+	return res;
+}
+
+/* prepare device for input/output
+ * (only applyable to waveform audio)
+ */
+static DWORD
+MCISTR_Cue(_MCISTR_PROTO_) {
+	MCI_GENERIC_PARMS	cueParams;
+	int			i,res;
+
+	i=0;
+	while (i<nrofkeywords) {
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_WAVEFORM_AUDIO:
+			FLAG1("input",MCI_WAVE_INPUT);
+			FLAG1("output",MCI_WAVE_OUTPUT);
+			break;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_CUE,cueParams);
+	return res;
+}
+
+/* delete information */
+static DWORD
+MCISTR_Delete(_MCISTR_PROTO_) {
+	int	timef,nrargs,i,j,k,a[4],res;
+	char	*parsestr;
+	MCI_WAVE_DELETE_PARMS	deleteParams;
+
+	/* only implemented for waveform audio */
+	if (uDevTyp != MCI_DEVTYPE_WAVEFORM_AUDIO)
+		return MCIERR_UNSUPPORTED_FUNCTION; /* well it fits */
+	res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
+	if (res) return res;
+	switch (timef) {
+	case MCI_FORMAT_MILLISECONDS:
+	case MCI_FORMAT_FRAMES:
+	case MCI_FORMAT_BYTES:
+	case MCI_FORMAT_SAMPLES:
+		nrargs=1;
+		parsestr="%d";
+		break;
+	case MCI_FORMAT_HMS:
+	case MCI_FORMAT_MSF:
+		parsestr="%d:%d:%d";
+		nrargs=3;
+		break;
+	case MCI_FORMAT_TMSF:
+		parsestr="%d:%d:%d:%d";
+		nrargs=4;
+		break;
+	default:fprintf(stdnimp,"mciSendString:DELETE:unknown timeformat %d, please report.\n",timef);
+		parsestr="%d";
+		nrargs=1;
+		break;
+	}
+	i=0;
+	while (i<nrofkeywords) {
+		if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_TO;
+			a[0]=a[1]=a[2]=a[3]=0;
+			j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
+			/* add up all integers we got, if we have more 
+			 * shift them. (Well I should use the macros in 
+			 * mmsystem.h, right).
+			 */
+			deleteParams.dwTo=0;
+			for (k=0;k<j;k++)
+				deleteParams.dwTo+=a[k]<<(8*(nrargs-k));
+			i+=2;
+			continue;
+		}
+		if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_FROM;
+			a[0]=a[1]=a[2]=a[3]=0;
+			j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
+			/* dito. */
+			deleteParams.dwFrom=0;
+			for (k=0;k<j;k++)
+				deleteParams.dwFrom+=a[k]<<(8*(nrargs-k));
+			i+=2;
+			continue;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_DELETE,deleteParams);
+	return res;
+}
+
+/* send command to device. only applies to videodisc */
+static DWORD
+MCISTR_Escape(_MCISTR_PROTO_) {
+	MCI_VD_ESCAPE_PARMS	escapeParams;
+	int			i,len,res;
+	char		*s;
+	HANDLE		x;
+
+	if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
+		return MCIERR_UNSUPPORTED_FUNCTION;
+	i=0;len=0;
+	while (i<nrofkeywords) {
+		len+=strlen(keywords[i])+1;
+		i++;
+	}
+	s=(char*)malloc(len);
+	*s='\0';
+	while (i<nrofkeywords) {
+		strcat(s,keywords[i]);
+		i++;
+		if (i<nrofkeywords) strcat(s," ");
+	}
+	/* FIXME: messy, but I strongly suspect we have to use a 
+	 * segmented pointer, so I am doing that
+	 */
+	x=USER_HEAP_ALLOC(len);
+	escapeParams.lpstrCommand=(LPSTR)MAKELONG(x,USER_HeapSel);
+	strcpy(PTR_SEG_TO_LIN(escapeParams.lpstrCommand),s);
+	free(s);
+	dwFlags |= MCI_VD_ESCAPE_STRING;
+	_MCI_CALL_DRIVER(MCI_ESCAPE,escapeParams);
+	USER_HEAP_FREE(x);
+	return res;
+}
+
+/* unfreeze [part of] the overlayed video 
+ * only applyable to Overlay devices
+ */
+static DWORD
+MCISTR_Unfreeze(_MCISTR_PROTO_) {
+	MCI_OVLY_RECT_PARMS	unfreezeParams;
+	int			i,res;
+
+	if (uDevTyp != MCI_DEVTYPE_OVERLAY)
+		return MCIERR_UNSUPPORTED_FUNCTION;
+	i=0;while (i<nrofkeywords) {
+		if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
+			sscanf(keywords[i+1],"%ld",&(unfreezeParams.rc.left));
+			sscanf(keywords[i+2],"%ld",&(unfreezeParams.rc.top));
+			sscanf(keywords[i+3],"%ld",&(unfreezeParams.rc.right));
+			sscanf(keywords[i+4],"%ld",&(unfreezeParams.rc.bottom));
+			dwFlags |= MCI_OVLY_RECT;
+			i+=5;
+			continue;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_UNFREEZE,unfreezeParams);
+	return res;
+}
+/* freeze [part of] the overlayed video 
+ * only applyable to Overlay devices
+ */
+static DWORD
+MCISTR_Freeze(_MCISTR_PROTO_) {
+	MCI_OVLY_RECT_PARMS	freezeParams;
+	int			i,res;
+
+	if (uDevTyp != MCI_DEVTYPE_OVERLAY)
+		return MCIERR_UNSUPPORTED_FUNCTION;
+	i=0;while (i<nrofkeywords) {
+		if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
+			sscanf(keywords[i+1],"%ld",&(freezeParams.rc.left));
+			sscanf(keywords[i+2],"%ld",&(freezeParams.rc.top));
+			sscanf(keywords[i+3],"%ld",&(freezeParams.rc.right));
+			sscanf(keywords[i+4],"%ld",&(freezeParams.rc.bottom));
+			dwFlags |= MCI_OVLY_RECT;
+			i+=5;
+			continue;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_FREEZE,freezeParams);
+	return res;
+}
+
+/* copy parts of image to somewhere else 
+ * "source [at <left> <top> <right> <bottom>]"	source is framebuffer [or rect]
+ * "destination [at <left> <top> <right> <bottom>]"	destination is framebuffer [or rect]
+ * Overlay:
+ * "frame [at <left> <top> <right> <bottom>]"	frame is framebuffer [or rect]
+ * 						where the video input is placed
+ * "video [at <left> <top> <right> <bottom>]"	video is whole video [or rect]
+ *						(defining part of input to
+ *						be displayed)
+ *
+ * FIXME: This whole junk is passing multiple rectangles.
+ *	I don't know how to do that with the present interface.
+ *	(Means code below is broken)
+ */
+static DWORD
+MCISTR_Put(_MCISTR_PROTO_) {
+	union {
+		MCI_OVLY_RECT_PARMS	ovlyputParams;
+		MCI_ANIM_RECT_PARMS	animputParams;
+	} U;
+	int	i,res;
+	i=0;while (i<nrofkeywords) {
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+			FLAG1("source",MCI_ANIM_PUT_SOURCE);
+			FLAG1("destination",MCI_ANIM_PUT_DESTINATION);
+			if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
+				sscanf(keywords[i+1],"%ld",&(U.animputParams.rc.left));
+				sscanf(keywords[i+2],"%ld",&(U.animputParams.rc.top));
+				sscanf(keywords[i+3],"%ld",&(U.animputParams.rc.right));
+				sscanf(keywords[i+4],"%ld",&(U.animputParams.rc.bottom));
+				dwFlags |= MCI_ANIM_RECT;
+				i+=5;
+				continue;
+			}
+			break;
+		case MCI_DEVTYPE_OVERLAY:
+			FLAG1("source",MCI_OVLY_PUT_SOURCE);
+			FLAG1("destination",MCI_OVLY_PUT_DESTINATION);
+			FLAG1("video",MCI_OVLY_PUT_VIDEO);
+			FLAG1("frame",MCI_OVLY_PUT_FRAME);
+			if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
+				sscanf(keywords[i+1],"%ld",&(U.ovlyputParams.rc.left));
+				sscanf(keywords[i+2],"%ld",&(U.ovlyputParams.rc.top));
+				sscanf(keywords[i+3],"%ld",&(U.ovlyputParams.rc.right));
+				sscanf(keywords[i+4],"%ld",&(U.ovlyputParams.rc.bottom));
+				dwFlags |= MCI_OVLY_RECT;
+				i+=5;
+				continue;
+			}
+			break;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_PUT,U);
+	return res;
+}
+
+/* palette behaviour changing
+ * (Animation only)
+ * 	"normal"	realize the palette normally
+ * 	"background"	realize the palette as background palette
+ */
+static DWORD
+MCISTR_Realize(_MCISTR_PROTO_) {
+	MCI_GENERIC_PARMS	realizeParams;
+	int			i,res;
+
+	if (uDevTyp != MCI_DEVTYPE_ANIMATION)
+		return MCIERR_UNSUPPORTED_FUNCTION;
+	i=0;
+	while (i<nrofkeywords) {
+		FLAG1("background",MCI_ANIM_REALIZE_BKGD);
+		FLAG1("normal",MCI_ANIM_REALIZE_NORM);
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_REALIZE,realizeParams);
+	return res;
+}
+
+/* videodisc spinning
+ *	"up"
+ *	"down"
+ */
+static DWORD
+MCISTR_Spin(_MCISTR_PROTO_) {
+	MCI_GENERIC_PARMS	spinParams;
+	int			i,res;
+
+	if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
+		return MCIERR_UNSUPPORTED_FUNCTION;
+	i=0;
+	while (i<nrofkeywords) {
+		FLAG1("up",MCI_VD_SPIN_UP);
+		FLAG1("down",MCI_VD_SPIN_UP);
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_SPIN,spinParams);
+	return res;
+}
+
+/* step single frames
+ * 	"reverse"	optional flag
+ *	"by <nr>"	for <nr> frames
+ */
+static DWORD
+MCISTR_Step(_MCISTR_PROTO_) {
+	union	{
+		MCI_ANIM_STEP_PARMS	animstepParams;
+		MCI_VD_STEP_PARMS	vdstepParams;
+	} U;
+	int	i,res;
+
+	i=0;
+	while (i<nrofkeywords) {
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+			FLAG1("reverse",MCI_ANIM_STEP_REVERSE);
+			if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
+				sscanf(keywords[i+1],"%ld",&(U.animstepParams.dwFrames));
+				dwFlags |= MCI_ANIM_STEP_FRAMES;
+				i+=2;
+				continue;
+			}
+			break;
+		case MCI_DEVTYPE_VIDEODISC:
+			FLAG1("reverse",MCI_VD_STEP_REVERSE);
+			if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
+				sscanf(keywords[i+1],"%ld",&(U.vdstepParams.dwFrames));
+				dwFlags |= MCI_VD_STEP_FRAMES;
+				i+=2;
+				continue;
+			}
+			break;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_STEP,U);
+	return res;
+}
+
+/* update animation window
+ * Arguments:
+ *	"at <left> <top> <right> <bottom>" only in this rectangle
+ *	"hdc"		device context
+ */
+static DWORD
+MCISTR_Update(_MCISTR_PROTO_) {
+	int		i,res;
+	MCI_ANIM_UPDATE_PARMS	updateParams;
+
+	i=0;
+	while (i<nrofkeywords) {
+		if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
+			sscanf(keywords[i+1],"%ld",&(updateParams.rc.left));
+			sscanf(keywords[i+2],"%ld",&(updateParams.rc.top));
+			sscanf(keywords[i+3],"%ld",&(updateParams.rc.right));
+			sscanf(keywords[i+4],"%ld",&(updateParams.rc.bottom));
+			dwFlags |= MCI_ANIM_RECT;
+			i+=5;
+			continue;
+		}
+		if (!STRCMP(keywords[i],"hdc") && (i+1<nrofkeywords)) {
+			dwFlags |= MCI_ANIM_UPDATE_HDC;
+			sscanf(keywords[i+1],"%d",&(updateParams.hDC));
+			i+=2;
+			continue;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_UPDATE,updateParams);
+	return res;
+}
+
+/* where command for animation and overlay drivers.
+ * just returns the specified rectangle as a string
+ * Arguments:
+ *	"source"
+ *	"destination"
+ * Overlay special:
+ *	"video"
+ *	"frame"
+ */
+static DWORD
+MCISTR_Where(_MCISTR_PROTO_) {
+	union {
+		MCI_ANIM_RECT_PARMS	animwhereParams;
+		MCI_OVLY_RECT_PARMS	ovlywhereParams;
+	} U;
+	int	i,res;
+
+	i=0;
+	while (i<nrofkeywords) {
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+			FLAG1("source",MCI_ANIM_WHERE_SOURCE);
+			FLAG1("destination",MCI_ANIM_WHERE_DESTINATION);
+			break;
+		case MCI_DEVTYPE_OVERLAY:
+			FLAG1("source",MCI_OVLY_WHERE_SOURCE);
+			FLAG1("destination",MCI_OVLY_WHERE_DESTINATION);
+			FLAG1("video",MCI_OVLY_WHERE_VIDEO);
+			FLAG1("frame",MCI_OVLY_WHERE_FRAME);
+			break;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_WHERE,U);
+	if (res==0) {
+		char	buf[100];
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+			sprintf(buf,"%d %d %d %d",
+				U.animwhereParams.rc.left,
+				U.animwhereParams.rc.top,
+				U.animwhereParams.rc.right,
+				U.animwhereParams.rc.bottom
+			);
+			break;
+		case MCI_DEVTYPE_OVERLAY:
+			sprintf(buf,"%d %d %d %d",
+				U.ovlywhereParams.rc.left,
+				U.ovlywhereParams.rc.top,
+				U.ovlywhereParams.rc.right,
+				U.ovlywhereParams.rc.bottom
+			);
+			break;
+		default:strcpy(buf,"0 0 0 0");break;
+		}
+		_MCI_STR(buf);
+	}
+	return	res;
+}
+
+static DWORD
+MCISTR_Window(_MCISTR_PROTO_) {
+	int	i,res;
+	char	*s;
+	union 	{
+		MCI_ANIM_WINDOW_PARMS	animwindowParams;
+		MCI_OVLY_WINDOW_PARMS	ovlywindowParams;
+	} U;
+
+	s=NULL;
+	i=0;
+	while (i<nrofkeywords) {
+		switch (uDevTyp) {
+		case MCI_DEVTYPE_ANIMATION:
+			if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_ANIM_WINDOW_HWND;
+				if (!STRCMP(keywords[i+1],"default")) 
+					U.animwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
+				else
+					sscanf(keywords[i+1],"%d",&(U.animwindowParams.hWnd));
+				i+=2;
+				continue;
+			}
+			if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_ANIM_WINDOW_STATE;
+				if (!STRCMP(keywords[i+1],"hide"))
+					U.animwindowParams.nCmdShow = SW_HIDE;
+				if (!STRCMP(keywords[i+1],"iconic"))
+					U.animwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
+				if (!STRCMP(keywords[i+1],"minimized"))
+					U.animwindowParams.nCmdShow = SW_SHOWMINIMIZED;
+				if (!STRCMP(keywords[i+1],"maximized"))
+					U.animwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
+				if (!STRCMP(keywords[i+1],"minimize"))
+					U.animwindowParams.nCmdShow = SW_MINIMIZE;
+				if (!STRCMP(keywords[i+1],"normal"))
+					U.animwindowParams.nCmdShow = SW_NORMAL;
+				if (!STRCMP(keywords[i+1],"show"))
+					U.animwindowParams.nCmdShow = SW_SHOW;
+				if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
+					if (!STRCMP(keywords[i+2],"active"))
+						U.animwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
+					if (!STRCMP(keywords[i+2],"action"))
+						U.animwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
+					i++;
+				}
+				i+=2;
+				continue;
+			}
+			/* text is enclosed in " ... " as it seems */
+			if (!STRCMP(keywords[i],"text")) {
+				char	*t;
+				int	len,j,k;
+
+				if (keywords[i+1][0]!='"') {
+					i++;
+					continue;
+				}
+				dwFlags |= MCI_ANIM_WINDOW_TEXT;
+				len	= strlen(keywords[i+1])+1;
+				j	= i+2;
+				while (j<nrofkeywords) {
+					len += strlen(keywords[j])+1;
+					if (strchr(keywords[j],'"'))
+						break;
+					j++;
+				}
+				s=(char*)malloc(len);
+				strcpy(s,keywords[i+1]+1);
+				k=j;j=i+2;
+				while (j<=k) {
+					strcat(s," ");
+					strcat(s,keywords[j]);
+				}
+				if ((t=strchr(s,'"'))) *t='\0';
+				/* FIXME: segmented pointer? */
+				U.animwindowParams.lpstrText = s;
+				i=k+1;
+				continue;
+			}
+			FLAG1("stretch",MCI_ANIM_WINDOW_ENABLE_STRETCH);
+			break;
+		case MCI_DEVTYPE_OVERLAY:
+			if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_OVLY_WINDOW_HWND;
+				if (!STRCMP(keywords[i+1],"default")) 
+					U.ovlywindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
+				else
+					sscanf(keywords[i+1],"%d",&(U.ovlywindowParams.hWnd));
+				i+=2;
+				continue;
+			}
+			if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
+				dwFlags |= MCI_OVLY_WINDOW_STATE;
+				if (!STRCMP(keywords[i+1],"hide"))
+					U.ovlywindowParams.nCmdShow = SW_HIDE;
+				if (!STRCMP(keywords[i+1],"iconic"))
+					U.ovlywindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
+				if (!STRCMP(keywords[i+1],"minimized"))
+					U.ovlywindowParams.nCmdShow = SW_SHOWMINIMIZED;
+				if (!STRCMP(keywords[i+1],"maximized"))
+					U.ovlywindowParams.nCmdShow = SW_SHOWMAXIMIZED;
+				if (!STRCMP(keywords[i+1],"minimize"))
+					U.ovlywindowParams.nCmdShow = SW_MINIMIZE;
+				if (!STRCMP(keywords[i+1],"normal"))
+					U.ovlywindowParams.nCmdShow = SW_NORMAL;
+				if (!STRCMP(keywords[i+1],"show"))
+					U.ovlywindowParams.nCmdShow = SW_SHOW;
+				if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
+					if (!STRCMP(keywords[i+2],"active"))
+						U.ovlywindowParams.nCmdShow = SW_SHOWNOACTIVATE;
+					if (!STRCMP(keywords[i+2],"action"))
+						U.ovlywindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
+					i++;
+				}
+				i+=2;
+				continue;
+			}
+			/* text is enclosed in " ... " as it seems */
+			if (!STRCMP(keywords[i],"text")) {
+				char	*t;
+				int	len,j,k;
+
+				if (keywords[i+1][0]!='"') {
+					i++;
+					continue;
+				}
+				dwFlags |= MCI_OVLY_WINDOW_TEXT;
+				len	= strlen(keywords[i+1])+1;
+				j	= i+2;
+				while (j<nrofkeywords) {
+					len += strlen(keywords[j])+1;
+					if (strchr(keywords[j],'"'))
+						break;
+					j++;
+				}
+				s=(char*)malloc(len);
+				strcpy(s,keywords[i+1]+1);
+				k=j;j=i+2;
+				while (j<=k) {
+					strcat(s," ");
+					strcat(s,keywords[j]);
+				}
+				if ((t=strchr(s,'"'))) *t='\0';
+				/* FIXME: segmented pointer? */
+				U.ovlywindowParams.lpstrText = s;
+				i=k+1;
+				continue;
+			}
+			FLAG1("stretch",MCI_OVLY_WINDOW_ENABLE_STRETCH);
+			break;
+		}
+		i++;
+	}
+	_MCI_CALL_DRIVER(MCI_WINDOW,U);
+	if (s) free(s);
+	return res;
+}
+
+struct	_MCISTR_cmdtable {
+	char	*cmd;
+	DWORD	(*fun)(_MCISTR_PROTO_);
+} MCISTR_cmdtable[]={
+	{"break",	MCISTR_Break},
+	{"capability",	MCISTR_Capability},
+	{"close",	MCISTR_Close},
+	{"cue",		MCISTR_Cue},
+	{"delete",	MCISTR_Delete},
+	{"escape",	MCISTR_Escape},
+	{"freeze",	MCISTR_Freeze},
+	{"info",	MCISTR_Info},
+	{"load",	MCISTR_Load},
+	{"open",	MCISTR_Open},
+	{"pause",	MCISTR_Pause},
+	{"play",	MCISTR_Play},
+	{"put",		MCISTR_Put},
+	{"realize",	MCISTR_Realize},
+	{"record",	MCISTR_Record},
+	{"resume",	MCISTR_Resume},
+	{"save",	MCISTR_Save},
+	{"seek",	MCISTR_Seek},
+	{"set",		MCISTR_Set},
+	{"spin",	MCISTR_Spin},
+	{"status",	MCISTR_Status},
+	{"step",	MCISTR_Step},
+	{"stop",	MCISTR_Stop},
+	{"sysinfo",	MCISTR_Sysinfo},
+	{"unfreeze",	MCISTR_Unfreeze},
+	{"update",	MCISTR_Update},
+	{"where",	MCISTR_Where},
+	{"window",	MCISTR_Window},
+	{NULL,		NULL}
+};
+/**************************************************************************
+* 				mciSendString			[MMSYSTEM.702]
+*/
+/* The usercode sends a string with a command (and flags) expressed in 
+ * words in it... We do our best to call aprobiate drivers,
+ * and return a errorcode AND a readable string (if lpstrRS!=NULL)
+ * Info gathered by watching cool134.exe and from Borland's mcistrwh.hlp
+ */
+/* FIXME: "all" is a valid devicetype and we should access all devices if
+ * it is used. (imagine "close all"). Not implemented yet.
+ */
+DWORD mciSendString (LPCSTR lpstrCommand, LPSTR lpstrReturnString, 
+	UINT uReturnLength, HWND hwndCallback)
+{
+	char	*cmd,*dev,*args,**keywords;
+	WORD	uDevTyp,wDevID;
+	DWORD	dwFlags;
+	int	res,i,nrofkeywords;
+
+	dprintf_mci(stdnimp,"mciSendString('%s', %p, %d, %X)\n", lpstrCommand, 
+		lpstrReturnString, uReturnLength, hwndCallback
+	);
+	/* format is <command> <device> <optargs> */
+	cmd=strdup(lpstrCommand);
+	dev=strchr(cmd,' ');
+	if (dev==NULL) {
+		free(cmd);
+		return MCIERR_MISSING_DEVICE_NAME;
+	}
+	*dev++='\0';
+	args=strchr(dev,' ');
+	if (args!=NULL) *args++='\0';
+	AnsiUpper(dev);
+	if (args!=NULL) {
+		char	*s;
+		i=1;/* nrofkeywords = nrofspaces+1 */
+		s=args;
+		while ((s=strchr(s,' '))!=NULL) i++,s++;
+		keywords=(char**)malloc(sizeof(char*)*(i+2));
+		nrofkeywords=i;
+		s=args;i=0;
+		while (s && i<nrofkeywords) {
+			keywords[i++]=s;
+			s=strchr(s,' ');
+			if (s) *s++='\0';
+		}
+		keywords[i]=NULL;
+	} else {
+		nrofkeywords=0;
+		keywords=(char**)malloc(sizeof(char*));
+	}
+	dwFlags = 0; /* default flags */
+	for (i=0;i<nrofkeywords;) {
+		if (!STRCMP(keywords[i],"wait")) {
+			dwFlags |= MCI_WAIT;
+			memcpy(keywords+i,keywords+(i+1),nrofkeywords-i-1);
+			nrofkeywords--;
+			continue;
+		}
+		if (!STRCMP(keywords[i],"notify")) {
+			/* how should we callback?  I don't know. */
+			/*dwFlags |= MCI_NOTIFY;*/
+			memcpy(keywords+i,keywords+(i+1),nrofkeywords-i-1);
+			nrofkeywords--;
+			continue;
+		}
+		i++;
+	}
+
+ 	/* determine wDevID and uDevTyp for all commands except "open" */
+ 	if (STRCMP(cmd,"open")!=0) {
+		wDevID=0;
+		while (1) {
+			SEGPTR	dname;
+
+			dname=(SEGPTR)mciOpenDrv[wDevID].lpstrAlias;
+			if (dname==NULL) 
+				dname=(SEGPTR)mciOpenDrv[wDevID].lpstrDeviceType;
+			if (!STRCMP(PTR_SEG_TO_LIN(dname),dev))
+				break;
+			if (++wDevID >= MAXMCIDRIVERS) {
+				dprintf_mci(stddeb, __FILE__":mciSendString:MAXMCIDRIVERS reached!\n");
+				free(keywords);free(cmd);
+				return MCIERR_INTERNAL;
+			}
+		}
+		uDevTyp=mciDrv[wDevID].wType;
+	}
+
+ 	for (i=0;MCISTR_cmdtable[i].cmd!=NULL;i++) {
+ 		if (!STRCMP(MCISTR_cmdtable[i].cmd,cmd)) {
+ 			res=MCISTR_cmdtable[i].fun(
+ 				wDevID,uDevTyp,lpstrReturnString,
+ 				uReturnLength,dev,keywords,nrofkeywords,
+ 				dwFlags
+ 			);
+ 			break;
+ 		}
+ 	}
+ 	if (MCISTR_cmdtable[i].cmd!=NULL) {
+ 		free(keywords);free(cmd);
+ 		return	res;
+ 	}
+	fprintf(stdnimp,"mciSendString('%s', %p, %u, %X) // unimplemented, please report.\n", lpstrCommand, 
+		lpstrReturnString, uReturnLength, hwndCallback
+	);
+	free(keywords);free(cmd);
+	return MCIERR_MISSING_COMMAND_STRING;
+}
+#endif
diff --git a/multimedia/mmsystem.c b/multimedia/mmsystem.c
index 7827c1d..b2bc0e1 100644
--- a/multimedia/mmsystem.c
+++ b/multimedia/mmsystem.c
@@ -28,11 +28,7 @@
 static int	InstalledListLen;
 static LPSTR	lpInstallNames = NULL;
 
-static MCI_OPEN_DRIVER_PARMS	mciDrv[MAXMCIDRIVERS];
-/* FIXME: I need to remember the aliasname of a spec. driver. 
- *        and this is the easiest way. *sigh*
- */
-static MCI_OPEN_PARMS		mciOpenDrv[MAXMCIDRIVERS];
+MCI_OPEN_DRIVER_PARMS	mciDrv[MAXMCIDRIVERS];
 
 UINT midiGetErrorText(UINT uError, LPSTR lpText, UINT uSize);
 UINT waveGetErrorText(UINT uError, LPSTR lpText, UINT uSize);
@@ -798,777 +794,6 @@
 	return 0;
 }
 
-/* someone was just short of a crisis seeing me putting xxx lines of code
- * in a single define. Well. What does the code hope for if not for the
- * care of the optimizer? (Stolen by Terry Pratchett, ok ;)
- */
-#define _MCI_STR(s) do {\
-	int __l__;\
-	dprintf_mci(stddeb,"->returns \"%s\"",s);\
-	if (lpstrReturnString) {\
-		__l__=strlen(s);\
-		if(__l__>uReturnLength) {\
-			strncpy(lpstrReturnString,s,uReturnLength-1);\
-			lpstrReturnString[uReturnLength-1]='\0';\
-		} else\
-			strcpy(lpstrReturnString,s);\
-		dprintf_mci(stddeb,"-->\"%s\"\n",lpstrReturnString);\
-	}\
-} while(0)
-/* calling DriverProc. We need to pass the struct as SEGMENTED POINTER. */
-#define _MCI_CALL_DRIVER(cmd,params) {\
-	DWORD	xparams;\
-	xparams=MAKE_SEGPTR(&params);\
-	switch(uDevTyp) {\
-	case MCI_DEVTYPE_CD_AUDIO:\
-		res=CDAUDIO_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags, xparams);\
-		break;\
-	case MCI_DEVTYPE_WAVEFORM_AUDIO:\
-		res=WAVE_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
-		break;\
-	case MCI_DEVTYPE_SEQUENCER:\
-		res=MIDI_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
-		break;\
-	case MCI_DEVTYPE_ANIMATION:\
-		res=ANIM_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
-		break;\
-	case MCI_DEVTYPE_DIGITAL_VIDEO:\
-		dprintf_mci(stddeb,"_MCI_CALL_DRIVER //No DIGITAL_VIDEO yet !\n");\
-		res=MCIERR_DEVICE_NOT_INSTALLED;\
-		break;\
-	default:\
-		dprintf_mci(stddeb,"_MCI_CALL_DRIVER //Invalid Device Name '%s' !\n",dev);\
-		res=MCIERR_INVALID_DEVICE_NAME;\
-		break;\
-	}\
-}
-/* yeah, I know this is BAD. but we have to do that for MCI_OPEN_PARMS 
- * strings.
- */
-#define	_MCI_STRDUP_TO_SEG(dest,source) {\
-	HANDLE	x;\
-	x=USER_HEAP_ALLOC(strlen(source));\
-	dest=(LPSTR)MAKELONG(x,USER_HeapSel);\
-	strcpy(PTR_SEG_TO_LIN(dest),source);\
-}
-
-/**************************************************************************
-* 				mciSendString			[MMSYSTEM.702]
-*/
-/* Well, it's easy. The usercode sends a string with a command (and flags)
- * expressed in words in it... We do our best to call approbiate drivers,
- * and return a errorcode AND a readable string (if lpstrRS!=NULL)
- * Info taken by watching cool134.exe and from Borland's mcistrwh.hlp
- */
-DWORD mciSendString (LPCSTR lpstrCommand, LPSTR lpstrReturnString, 
-	UINT uReturnLength, HWND hwndCallback)
-{
-	char	*cmd,*dev,*args,**keywords;
-	WORD	uDevTyp,wDevID;
-	DWORD	dwFlags;
-	int	track,i,nrofkeywords,res,timef;
-
-	dprintf_mci(stdnimp,"mciSendString('%s', %p, %d, %X)\n", lpstrCommand, 
-		lpstrReturnString, uReturnLength, hwndCallback
-	);
-	/* format is <command> <device> <optargs> */
-	cmd=strdup(lpstrCommand);
-	dev=strchr(cmd,' ');
-	if (dev==NULL) {
-		free(cmd);
-		return MCIERR_MISSING_DEVICE_NAME;
-	}
-	*dev++='\0';
-	args=strchr(dev,' ');
-	if (args!=NULL) *args++='\0';
-	AnsiUpper(dev);
-	AnsiUpper(cmd);
-	if (args!=NULL) {
-		char	*s;
-		AnsiUpper(args);
-		i=1;/* nrofkeywords = nrofspaces+1 */
-		s=args;
-		while ((s=strchr(s,' '))!=NULL) i++,s++;
-		keywords=(char**)malloc(sizeof(char*)*(i+2));
-		nrofkeywords=i;
-		s=args;i=0;
-		while (s && i<nrofkeywords) {
-			keywords[i++]=s;
-			s=strchr(s,' ');
-			if (s) *s++='\0';
-		}
-		keywords[i]=NULL;
-	} else {
-		nrofkeywords=0;
-		keywords=(char**)malloc(sizeof(char*));
-	}
-	dwFlags = 0; /* default flags */
-	i=0;
-	while (i<nrofkeywords) {
-		if (!strcmp(keywords[i],"WAIT")) {
-			dwFlags |= MCI_WAIT;
-			i++;
-			continue;
-		}
-		if (!strcmp(keywords[i],"NOTIFY")) {
-			/* how should we callback?  I don't know. */
-			/*dwFlags |= MCI_NOTIFY;*/
-			i++;
-			continue;
-		}
-		if (!strcmp(keywords[i],"TRACK")) {
-			if (i+1<nrofkeywords) {
-				sscanf(keywords[i+1],"%d",&track);
-				dwFlags |= MCI_TRACK;
-				i++;
-				/*FALLTHROUGH*/
-			}
-			i++;
-			continue;
-		}
-		i++;
-	}
-	if (!strcmp(cmd,"OPEN")) {
-		char	*s;
-		MCI_OPEN_PARMS	openParams;
-
-		openParams.lpstrElementName = NULL;
-		s=strchr(dev,'!');
-		if (s!=NULL) {
-			*s++='\0';
-			_MCI_STRDUP_TO_SEG(openParams.lpstrElementName,s);
-		}
-		if (!strcmp(dev,"CDAUDIO")) {
-			uDevTyp=MCI_DEVTYPE_CD_AUDIO;
-		} else if (!strcmp(dev,"WAVEAUDIO")) {
-			uDevTyp=MCI_DEVTYPE_WAVEFORM_AUDIO;
-		} else if (!strcmp(dev,"SEQUENCER")) {
-			uDevTyp=MCI_DEVTYPE_SEQUENCER;
-		} else if (!strcmp(dev,"ANIMATION1")) {
-			uDevTyp=MCI_DEVTYPE_ANIMATION;
-		} else if (!strcmp(dev,"AVIVIDEO")) {
-			uDevTyp=MCI_DEVTYPE_DIGITAL_VIDEO;
-		} else {
-			free(keywords);free(cmd);
-			return MCIERR_INVALID_DEVICE_NAME;
-		}
-		wDevID=0;
-		while(mciDrv[wDevID].wType) {
-			if (++wDevID>=MAXMCIDRIVERS) {
-				dprintf_mci(stddeb, "MCI_OPEN // MAXMCIDRIVERS reached !\n");
-				free(keywords);free(cmd);
-				return MCIERR_INTERNAL;
-			}
-		}
-		mciDrv[wDevID].wType		= uDevTyp;
-		mciDrv[wDevID].wDeviceID	= wDevID;
-		openParams.dwCallback		= 0;
-		openParams.wDeviceID		= wDevID;
-		/* all strings must be copied */
-		_MCI_STRDUP_TO_SEG(openParams.lpstrDeviceType,dev);
-		openParams.lpstrAlias		= NULL;
-		dwFlags |= MCI_OPEN_TYPE;
-		i=0;
-		while (i<nrofkeywords) {
-			if (!strcmp(keywords[i],"SHAREABLE")) {
-				dwFlags|=MCI_OPEN_SHAREABLE;
-				i++;
-				continue;
-			}
-			if (!strcmp(keywords[i],"ALIAS") && (i+1<nrofkeywords)) {
-				dwFlags|=MCI_OPEN_ALIAS;
-				_MCI_STRDUP_TO_SEG(openParams.lpstrAlias,keywords[i]);
-				i+=2;
-				continue;
-			}
-			if (!strcmp(keywords[i],"ELEMENT") && (i+1<nrofkeywords)) {
-				dwFlags|=MCI_OPEN_ELEMENT;
-				_MCI_STRDUP_TO_SEG(openParams.lpstrElementName,keywords[i]);
-				i+=2;
-				continue;
-			}
-			i++;
-		}
-		_MCI_CALL_DRIVER(MCI_OPEN,openParams);
-		if (res==0)
-			memcpy(&mciOpenDrv[wDevID],&openParams,sizeof(MCI_OPEN_PARMS));
-		free(keywords);free(cmd);
-		return res;
-	}
-	/* all other commands use the alias set in MCI_OPEN or (if not set) 
-	 * the devicetype
-	 */
-	wDevID=0;
-	while(1) {
-		SEGPTR	dname;
-		dname=(SEGPTR)mciOpenDrv[wDevID].lpstrAlias;
-		if (dname==NULL) 
-			dname=(SEGPTR)mciOpenDrv[wDevID].lpstrDeviceType;
-		if (!strcasecmp(PTR_SEG_TO_LIN(dname),dev))
-			break;
-		if (++wDevID >= MAXMCIDRIVERS) {
-			dprintf_mci(stddeb, "mciSendString // MAXMCIDRIVERS reached !\n");
-			free(keywords);free(cmd);
-			return MCIERR_INTERNAL;
-		}
-	}
-	uDevTyp=mciDrv[wDevID].wType;
-
-	if (!strcmp(cmd,"STATUS")) {
-		MCI_STATUS_PARMS statusParams;
-
-		if (args==NULL) {
-			free(keywords);free(cmd);
-			return MCIERR_MISSING_STRING_ARGUMENT;
-		}
-		statusParams.dwCallback = 0;
-		if (dwFlags & MCI_TRACK)
-			statusParams.dwTrack = track;
-		dwFlags |= MCI_STATUS_ITEM;
-		/* we need that later for printing... */
-		statusParams.dwItem = MCI_STATUS_TIME_FORMAT;
-		_MCI_CALL_DRIVER(MCI_STATUS,statusParams);
-		timef=statusParams.dwReturn;
-		statusParams.dwReturn=0;
-		statusParams.dwItem=0;
-		i=0;
-		while (i<nrofkeywords) {
-			if (	!strcmp(keywords[i],"CURRENT") &&
-				(i+1<nrofkeywords) &&
-				!strcmp(keywords[i+1],"TRACK")
-			) {
-				statusParams.dwItem=MCI_STATUS_CURRENT_TRACK;
-				i+=2;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"TIME") &&
-				(i+1<nrofkeywords) &&
-				!strcmp(keywords[i+1],"FORMAT")
-			) {
-				statusParams.dwItem=MCI_STATUS_TIME_FORMAT;
-				i+=2;
-				continue;
-			}
-			if (!strcmp(keywords[i],"READY")) {
-				statusParams.dwItem=MCI_STATUS_READY;
-				i++;
-				continue;
-			}
-			if (!strcmp(keywords[i],"MODE")) {
-				statusParams.dwItem=MCI_STATUS_MODE;
-				i++;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"NUMBER") && 
-				(i+2<nrofkeywords) &&
-				!strcmp(keywords[i+1],"OF") &&
-				!strcmp(keywords[i+2],"TRACKS")
-			) {
-				statusParams.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
-				i+=3;
-				continue;
-			}
-			if (!strcmp(keywords[i],"LENGTH")) {
-				statusParams.dwItem = MCI_STATUS_LENGTH;
-				i++;
-				continue;
-			}
-			if (!strcmp(keywords[i],"POSITION")) {
-				statusParams.dwItem = MCI_STATUS_POSITION;
-				i++;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"MEDIA") && 
-				(i+1<nrofkeywords) &&
-				!strcmp(keywords[i+1],"PRESENT")
-			) {
-				statusParams.dwItem = MCI_STATUS_MEDIA_PRESENT;
-				i+=2;
-				continue;
-			}
-			i++;
-		}
-		_MCI_CALL_DRIVER(MCI_STATUS,statusParams);
-		if (res==0) {
-			switch (statusParams.dwItem) {
-			case MCI_STATUS_MODE:
-				switch (statusParams.dwReturn) {
-				case MCI_MODE_NOT_READY:_MCI_STR("not ready");break;
-				case MCI_MODE_STOP:_MCI_STR("stopped");break;
-				case MCI_MODE_PLAY:_MCI_STR("playing");break;
-				case MCI_MODE_RECORD:_MCI_STR("recording");break;
-				case MCI_MODE_SEEK:_MCI_STR("seeking");break;
-				case MCI_MODE_PAUSE:_MCI_STR("paused");break;
-				case MCI_MODE_OPEN:_MCI_STR("open");break;
-				default:break;
-				}
-				break;
-			case MCI_STATUS_MEDIA_PRESENT:
-				if (statusParams.dwReturn)
-					_MCI_STR("true");
-				else
-					_MCI_STR("false");
-				break;
-			case MCI_STATUS_NUMBER_OF_TRACKS:
-			case MCI_STATUS_CURRENT_TRACK:
-			{	char	buf[16];
-				sprintf(buf,"%ld",statusParams.dwReturn);
-				_MCI_STR(buf);
-				break;
-			}
-			case MCI_STATUS_POSITION:
-			case MCI_STATUS_LENGTH:
-			{	char	buf[100];
-				switch (timef) {
-				case MCI_FORMAT_MILLISECONDS:
-				case MCI_FORMAT_FRAMES:
-				case MCI_FORMAT_BYTES:
-				case MCI_FORMAT_SAMPLES:
-					sprintf(buf,"%ld",statusParams.dwReturn);
-					_MCI_STR(buf);
-					break;
-				case MCI_FORMAT_HMS:
-					/* well, the macros have the same content*/
-					/*FALLTRHOUGH*/
-				case MCI_FORMAT_MSF:
-					sprintf(buf,"%d:%d:%d",
-						MCI_HMS_HOUR(statusParams.dwReturn),
-						MCI_HMS_MINUTE(statusParams.dwReturn),
-						MCI_HMS_SECOND(statusParams.dwReturn)
-					);
-					_MCI_STR(buf);
-					break;
-				case MCI_FORMAT_TMSF:
-					sprintf(buf,"%d:%d:%d:%d",
-						MCI_TMSF_TRACK(statusParams.dwReturn),
-						MCI_TMSF_MINUTE(statusParams.dwReturn),
-						MCI_TMSF_SECOND(statusParams.dwReturn),
-						MCI_TMSF_FRAME(statusParams.dwReturn)
-					);
-					_MCI_STR(buf);
-					break;
-				default:
-					fprintf(stdnimp,"mciSendString:STATUS:missing timeformat for %d, report.\n",timef);
-					break;
-				}
-				break;
-			}
-			case MCI_STATUS_TIME_FORMAT:
-				switch (timef) {
-				case MCI_FORMAT_MILLISECONDS:_MCI_STR("milliseconds");break;
-				case MCI_FORMAT_FRAMES:_MCI_STR("frames");break;
-				case MCI_FORMAT_BYTES:_MCI_STR("bytes");break;
-				case MCI_FORMAT_SAMPLES:_MCI_STR("samples");break;
-				case MCI_FORMAT_HMS:_MCI_STR("hms");break;
-				case MCI_FORMAT_MSF:_MCI_STR("msf");break;
-				case MCI_FORMAT_TMSF:_MCI_STR("tmsf");break;
-				default:
-					fprintf(stdnimp,"mciSendString:STATUS:missing timeformat for %d, report.\n",timef);
-					break;
-				}
-				break;
-			default:
-				fprintf(stdnimp,"mciSendString:STATUS:missing result for %ld, report.\n",statusParams.dwItem);
-				break;
-			}
-		}
-		free(keywords);free(cmd);
-		return res;
-	}
-	if (!strcmp(cmd,"SET")) {
-		MCI_SET_PARMS	setParams;
-
-		if (args==NULL) {
-			free(keywords);free(cmd);
-			return MCIERR_MISSING_STRING_ARGUMENT;
-		}
-		setParams.dwCallback = 0;
-		i=0;
-		while (i<nrofkeywords) {
-			if (!strcmp(keywords[i],"DOOR") && i+1<nrofkeywords) {
-				if (!strcmp(keywords[i+1],"OPEN"))
-					dwFlags |= MCI_SET_DOOR_OPEN;
-				if (!strcmp(keywords[i+1],"CLOSED"))
-					dwFlags |= MCI_SET_DOOR_CLOSED;
-				i+=2;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"TIME") && 
-				(i+2<nrofkeywords) &&
-				!strcmp(keywords[i+1],"FORMAT")
-			) {
-				dwFlags |= MCI_SET_TIME_FORMAT;
-				if (!strcmp(keywords[i+2],"MS"))
-					setParams.dwTimeFormat = MCI_FORMAT_MSF;
-				if (!strcmp(keywords[i+2],"MILLISECONDS"))
-					setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
-				if (!strcmp(keywords[i+2],"MSF"))
-					setParams.dwTimeFormat = MCI_FORMAT_MSF;
-				if (!strcmp(keywords[i+2],"HMS")) /* untested */
-					setParams.dwTimeFormat = MCI_FORMAT_HMS;
-				if (!strcmp(keywords[i+2],"FRAMES")) /* untested */
-					setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
-				if (!strcmp(keywords[i+2],"BYTES")) /* untested */
-					setParams.dwTimeFormat = MCI_FORMAT_BYTES;
-				if (!strcmp(keywords[i+2],"SAMPLES")) /* untested */
-					setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
-				if (!strcmp(keywords[i+2],"TMSF")) /* untested */
-					setParams.dwTimeFormat = MCI_FORMAT_TMSF;
-				if (!strcmp(keywords[i+2],"SMPTE") && (i+3<nrofkeywords)) {
-					/* all untested */
-					if (!strcmp(keywords[i+3],"24"))
-						setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
-					if (!strcmp(keywords[i+3],"25"))
-						setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
-					if (!strcmp(keywords[i+3],"30"))
-						setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
-					if (!strcmp(keywords[i+3],"30DROP"))
-						setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
-					i++;
-					/*FALLTHROUGH*/
-				}
-				i+=3;
-				continue;
-			}
-			if (!strcmp(args,"AUDIO") && (i+1<nrofkeywords)) {
-				dwFlags |= MCI_SET_AUDIO;
-				/* I'm not sure if those belong to the flags...
-				 * they could belong to setParams.dwAudio
-				 */
-				if (!strcmp(args,"ALL"))
-					dwFlags |= MCI_SET_AUDIO_ALL;
-				if (!strcmp(args,"LEFT"))
-					dwFlags |= MCI_SET_AUDIO_LEFT;
-				if (!strcmp(args,"RIGHT"))
-					dwFlags |= MCI_SET_AUDIO_RIGHT;
-				i++;
-				continue;
-			}
-			if (!strcmp(args,"VIDEO")) {
-				/* how to handle those? */
-				i++;
-				continue;
-			}
-			if (!strcmp(args,"ON")) {
-				dwFlags |= MCI_SET_ON;
-				i++;
-				continue;
-			}
-			if (!strcmp(args,"OFF")) {
-				dwFlags |= MCI_SET_ON;
-				i++;
-				continue;
-			}
-			i++;
-		}
-		_MCI_CALL_DRIVER(MCI_SET,setParams);
-		if (res==0) { /* does set return data? */ }
-		free(keywords);free(cmd);
-		return res;
-	}
-	if (!strcmp(cmd,"CAPABILITY")) {
-		MCI_GETDEVCAPS_PARMS	gdcParams;
-
-		gdcParams.dwCallback = 0;
-		if (args==NULL) {
-			free(keywords);free(cmd);
-			return MCIERR_MISSING_STRING_ARGUMENT;
-		}
-		dwFlags |= MCI_GETDEVCAPS_ITEM;
-		gdcParams.dwItem = 0;
-		i=0;
-		while (i<nrofkeywords) {
-			if (	!strcmp(keywords[i],"DEVICE") && 
-				(i+1<nrofkeywords) &&
-				!strcmp(keywords[i+1],"TYPE")
-			) {
-				gdcParams.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;	
-				i+=2;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"HAS") &&
-				(i+1<nrofkeywords) &&
-				!strcmp(keywords[i+1],"AUDIO")
-			) {
-				gdcParams.dwItem = MCI_GETDEVCAPS_HAS_AUDIO;	
-				i+=2;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"HAS") &&
-				(i+1<nrofkeywords) &&
-				!strcmp(keywords[i+1],"VIDEO")
-			) {
-				gdcParams.dwItem = MCI_GETDEVCAPS_HAS_VIDEO;	
-				i+=2;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"USES") &&
-				(i+1<nrofkeywords) &&
-				!strcmp(keywords[i+1],"FILES")
-			) {
-				gdcParams.dwItem = MCI_GETDEVCAPS_HAS_VIDEO;	
-				i+=2;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"COMPOUND") &&
-				(i+1<nrofkeywords) &&
-				!strcmp(keywords[i+1],"DEVICE")
-			) {
-				gdcParams.dwItem = MCI_GETDEVCAPS_COMPOUND_DEVICE;	
-				i+=2;
-				continue;
-			}
-			if (!strcmp(keywords[i],"CAN") && (i+1<nrofkeywords)) {
-				if (!strcmp(keywords[i+1],"RECORD"))
-					gdcParams.dwItem = MCI_GETDEVCAPS_CAN_RECORD;	
-				if (!strcmp(keywords[i+1],"PLAY"))
-					gdcParams.dwItem = MCI_GETDEVCAPS_CAN_PLAY;	
-				if (!strcmp(keywords[i+1],"EJECT"))
-					gdcParams.dwItem = MCI_GETDEVCAPS_CAN_EJECT;	
-				if (!strcmp(keywords[i+1],"SAVE"))
-					gdcParams.dwItem = MCI_GETDEVCAPS_CAN_SAVE;	
-				i+=2;
-				continue;
-			}
-			i++;
-		}
-		res=-1;
-		_MCI_CALL_DRIVER(MCI_GETDEVCAPS,gdcParams);
-		fprintf(stderr,"GETDEVCAPS returned res=%d\n",res);
-		if (res==0) {
-			switch (gdcParams.dwItem) {
-			case MCI_GETDEVCAPS_DEVICE_TYPE:
-				switch (gdcParams.dwReturn) {
-				case MCI_DEVTYPE_VCR:_MCI_STR("vcr");break;
-				case MCI_DEVTYPE_VIDEODISC:_MCI_STR("videodisc");break;
-				case MCI_DEVTYPE_CD_AUDIO:_MCI_STR("cd audio");break;
-				case MCI_DEVTYPE_OVERLAY:_MCI_STR("overlay");break;
-				case MCI_DEVTYPE_DAT:_MCI_STR("dat");break;
-				case MCI_DEVTYPE_SCANNER:_MCI_STR("scanner");break;
-				case MCI_DEVTYPE_ANIMATION:_MCI_STR("animation");break;
-				case MCI_DEVTYPE_DIGITAL_VIDEO:_MCI_STR("digital video");break;
-				case MCI_DEVTYPE_OTHER:_MCI_STR("other");break;
-				case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio");break;
-				case MCI_DEVTYPE_SEQUENCER:_MCI_STR("sequencer");break;
-				default:fprintf(stdnimp,"mciSendString:GETCAPS_DEVTYPE:unknown type %ld, report.\n",gdcParams.dwReturn);break;
-				}
-				break;
-			case MCI_GETDEVCAPS_CAN_PLAY:
-			case MCI_GETDEVCAPS_CAN_EJECT:
-			case MCI_GETDEVCAPS_CAN_RECORD:
-			case MCI_GETDEVCAPS_CAN_SAVE:
-			case MCI_GETDEVCAPS_HAS_AUDIO:
-			case MCI_GETDEVCAPS_HAS_VIDEO:
-			case MCI_GETDEVCAPS_COMPOUND_DEVICE:
-			case MCI_GETDEVCAPS_USES_FILES:
-				/* well, is this right? no example here */
-				if (gdcParams.dwReturn)
-					_MCI_STR("true");
-				else
-					_MCI_STR("false");
-				break;
-			default:fprintf(stdnimp,"mciSendString:GETDEVCAPS:unknown type %ld, report.\n",gdcParams.dwItem);break;
-			}
-		}
-		free(keywords);free(cmd);
-		return res;
-	}
-	if (!strcmp(cmd,"PAUSE")) {
-		MCI_GENERIC_PARMS	genParams;
-		genParams.dwCallback=0;
-		_MCI_CALL_DRIVER(MCI_PAUSE,genParams);
-		free(keywords);free(cmd);
-		return res;
-	}
-	if (!strcmp(cmd,"PLAY")) {
-		int	nrargs,j,k,a[4];
-		char	*parsestr;
-		MCI_PLAY_PARMS		playParams;
-		MCI_STATUS_PARMS	statusParams;
-
-		statusParams.dwCallback=0;
-		statusParams.dwItem=MCI_STATUS_TIME_FORMAT;
-		dwFlags |= MCI_STATUS_ITEM;
-		_MCI_CALL_DRIVER(MCI_STATUS,statusParams);
-		dwFlags &= ~MCI_STATUS_ITEM;
-		timef=statusParams.dwReturn;
-		switch (timef) {
-		case MCI_FORMAT_MILLISECONDS:
-		case MCI_FORMAT_FRAMES:
-		case MCI_FORMAT_BYTES:
-		case MCI_FORMAT_SAMPLES:
-			nrargs=1;
-			parsestr="%d";
-			break;
-		case MCI_FORMAT_HMS:
-		case MCI_FORMAT_MSF:
-			parsestr="%d:%d:%d";
-			nrargs=3;
-			break;
-		case MCI_FORMAT_TMSF:
-			parsestr="%d:%d:%d:%d";
-			nrargs=4;
-			break;
-		default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
-			parsestr="%d";
-			nrargs=1;
-			break;
-		}
-		playParams.dwCallback=0;
-		i=0;
-		while (i<nrofkeywords) {
-			if (	!strcmp(keywords[i],"TO") &&
-				(i+1<nrofkeywords)
-			) {
-				dwFlags |= MCI_TO;
-				a[0]=a[1]=a[2]=a[3]=0;
-				j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
-				/* add up all integers we got, if we have more 
-				 * shift them. (Well I should use the macros in 
-				 * mmsystem.h, right).
-				 */
-				playParams.dwTo=0;
-				for (k=0;k<j;k++)
-					playParams.dwTo+=a[k]<<(8*(nrargs-k));
-				i+=2;
-				continue;
-			}
-			if (	!strcmp(keywords[i],"FROM") &&
-				(i+1<nrofkeywords)
-			) {
-				dwFlags |= MCI_FROM;
-				a[0]=a[1]=a[2]=a[3]=0;
-				j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
-				/* dito. */
-				playParams.dwFrom=0;
-				for (k=0;k<j;k++)
-					playParams.dwFrom+=a[k]<<(8*(nrargs-k));
-				i+=2;
-				continue;
-			}
-			i++;
-		}
-		_MCI_CALL_DRIVER(MCI_PLAY,playParams);
-		free(keywords);free(cmd);
-		return res;
-	}
-	if (!strcmp(cmd,"STOP")) {
-		MCI_GENERIC_PARMS	genParams;
-		genParams.dwCallback=0;
-		_MCI_CALL_DRIVER(MCI_STOP,genParams);
-		free(keywords);free(cmd);
-		return res;
-	}
-	if (!strcmp(cmd,"SEEK")) {
-		int	nrargs,j,k,a[4];
-		char	*parsestr;
-		MCI_STATUS_PARMS	statusParams;
-		MCI_SEEK_PARMS	seekParams;
-
-		statusParams.dwCallback=0;
-		statusParams.dwItem=MCI_STATUS_TIME_FORMAT;
-		dwFlags |= MCI_STATUS_ITEM;
-		_MCI_CALL_DRIVER(MCI_STATUS,statusParams);
-		dwFlags &= ~MCI_STATUS_ITEM;
-		timef=statusParams.dwReturn;
-		switch (timef) {
-		case MCI_FORMAT_MILLISECONDS:
-		case MCI_FORMAT_FRAMES:
-		case MCI_FORMAT_BYTES:
-		case MCI_FORMAT_SAMPLES:
-			nrargs=1;
-			parsestr="%d";
-			break;
-		case MCI_FORMAT_HMS:
-		case MCI_FORMAT_MSF:
-			parsestr="%d:%d:%d";
-			nrargs=3;
-			break;
-		case MCI_FORMAT_TMSF:
-			parsestr="%d:%d:%d:%d";
-			nrargs=4;
-			break;
-		default:fprintf(stdnimp,"mciSendString:SEEK:unknown timeformat %d, please report.\n",timef);
-			parsestr="%d";
-			nrargs=1;
-			break;
-		}
-		seekParams.dwCallback=0;
-		i=0;
-		while (i<nrofkeywords) {
-			if (	!strcmp(keywords[i],"TO") &&
-				(i+1<nrofkeywords)
-			) {
-				if (!strcmp(keywords[i+1],"START")) {
-					dwFlags=MCI_SEEK_TO_START;
-					seekParams.dwTo=0;
-					i+=2;
-					continue;
-				}
-				if (!strcmp(keywords[i+1],"END")) {
-					dwFlags=MCI_SEEK_TO_END;
-					seekParams.dwTo=0;
-					i+=2;
-					continue;
-				}
-				dwFlags=MCI_TO;
-				i+=2;
-				a[0]=a[1]=a[2]=a[3]=0;
-				j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
-				seekParams.dwTo=0;
-				for (k=0;k<j;k++)
-					seekParams.dwTo+=a[k]<<(8*(nrargs-k));
-				continue;
-			}
-			i++;
-		}
-		_MCI_CALL_DRIVER(MCI_SEEK,seekParams);
-		free(keywords);free(cmd);
-		return res;
-	}
-	if (!strcmp(cmd,"CLOSE")) {
-		MCI_GENERIC_PARMS	closeParams;
-
-		closeParams.dwCallback=0;
-		_MCI_CALL_DRIVER(MCI_CLOSE,closeParams);
-		free(keywords);free(cmd);
-		return res;
-	}
-	if (!strcmp(cmd,"INFO")) {
-		MCI_INFO_PARMS	infoParams;
-
-		dwFlags=-1;
-		while (i<nrofkeywords) {
-			if (!strcmp(keywords[i],"PRODUCT")) {
-				dwFlags=MCI_INFO_PRODUCT;
-				i++;
-				continue;
-			}
-			if (!strcmp(keywords[i],"FILE")) {
-				dwFlags=MCI_INFO_FILE;
-				i++;
-				continue;
-			}
-			i++;
-		}
-		if (dwFlags==-1) {
-			free(keywords);free(cmd);
-			return MCIERR_MISSING_STRING_ARGUMENT;
-		}
-		_MCI_CALL_DRIVER(MCI_INFO,infoParams);
-		if (res==0) {
-			_MCI_STR(infoParams.lpstrReturn);
-		}
-		free(cmd);free(keywords);
-		return res;
-	}
-	fprintf(stdnimp, "mciSendString('%s', %p, %u, %X) // unimplemented, please report.\n", lpstrCommand, 
-		lpstrReturnString, uReturnLength, hwndCallback
-	);
-	free(keywords);free(cmd);
-	return MCIERR_MISSING_COMMAND_STRING;
-}
-
 /**************************************************************************
 * 				mciSetYieldProc		[MMSYSTEM.714]
 */
diff --git a/objects/Makefile.in b/objects/Makefile.in
index 659c7ce..9a9a6af 100644
--- a/objects/Makefile.in
+++ b/objects/Makefile.in
@@ -29,7 +29,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm -f Makefile
diff --git a/objects/bitblt.c b/objects/bitblt.c
index 38074db..ab8daf9 100644
--- a/objects/bitblt.c
+++ b/objects/bitblt.c
@@ -1302,3 +1302,11 @@
                                 dcDst, xDst, yDst, widthDst, heightDst,
                                 dcSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
 }
+/***********************************************************************
+ *           FastWindowFrame    (GDI.400)
+ */
+WORD
+FastWindowFrame(WORD x1,DWORD x2,WORD x3,WORD x4,DWORD x5) {
+	dprintf_gdi(stdnimp,"FastWindowFrame (%04x, %08lx, %04x, %04x, %08lx) // unimplemented!\n",x1,x2,x3,x4,x5);
+	return 0xFFFF; /* failed? */
+}
diff --git a/objects/font.c b/objects/font.c
index 200b605..bbeb634 100644
--- a/objects/font.c
+++ b/objects/font.c
@@ -78,7 +78,7 @@
     FontNames[0].x11 = strdup( temp );
 
   } else {
-    FontNames[0].window = NULL; FontNames[0].x11 = "bitstream-courier";
+    FontNames[0].window = NULL; FontNames[0].x11 = "*-helvetica";
     FontNames[1].window = "ms sans serif"; FontNames[1].x11 = "*-helvetica";
     FontNames[2].window = "ms serif"; FontNames[2].x11 = "*-times";
     FontNames[3].window = "fixedsys"; FontNames[3].x11 = "*-fixed";
@@ -313,7 +313,8 @@
 {
     LOGFONT logfont = { height, width, esc, orient, weight, italic, underline,
 		    strikeout, charset, outpres, clippres, quality, pitch, };
-    strncpy( logfont.lfFaceName, name, LF_FACESIZE );
+    if (name) strncpy( logfont.lfFaceName, name, LF_FACESIZE );
+    else logfont.lfFaceName[0] = '\0';
     return CreateFontIndirect( &logfont );
 }
 
diff --git a/objects/oembitmap.c b/objects/oembitmap.c
index 6bb2581..ecd40b4 100644
--- a/objects/oembitmap.c
+++ b/objects/oembitmap.c
@@ -35,16 +35,11 @@
 #include "bitmaps/obm_dnarrowd"
 #include "bitmaps/obm_uparrowd"
 #include "bitmaps/obm_restored"
-#include "bitmaps/obm_zoomd"
-#include "bitmaps/obm_reduced"
 #include "bitmaps/obm_restore"
-#include "bitmaps/obm_zoom"
-#include "bitmaps/obm_reduce"
 #include "bitmaps/obm_lfarrow"
 #include "bitmaps/obm_rgarrow"
 #include "bitmaps/obm_dnarrow"
 #include "bitmaps/obm_uparrow"
-#include "bitmaps/obm_close"
 #include "bitmaps/obm_old_restore"
 #include "bitmaps/obm_old_zoom"
 #include "bitmaps/obm_old_reduce"
@@ -59,6 +54,21 @@
 #include "bitmaps/obm_size"
 #include "bitmaps/obm_old_close"
 
+#ifndef WIN_95_LOOK
+#include "bitmaps/obm_zoomd"
+#include "bitmaps/obm_reduced"
+#include "bitmaps/obm_zoom"
+#include "bitmaps/obm_reduce"
+#include "bitmaps/obm_close"
+#else
+#include "bitmaps/obm_zoomd_95"
+#include "bitmaps/obm_reduced_95"
+#include "bitmaps/obm_zoom_95"
+#include "bitmaps/obm_reduce_95"
+#include "bitmaps/obm_close_95"
+#include "bitmaps/obm_closed_95"
+#endif  /* WIN_95_LOOK */
+
 #define OBM_FIRST  OBM_CDROM      /* First OEM bitmap */
 #define OBM_LAST   OBM_OLD_CLOSE   /* Last OEM bitmap */
 
@@ -86,13 +96,22 @@
     { obm_zoomd, TRUE },        /* OBM_ZOOMD */
     { obm_reduced, TRUE },      /* OBM_REDUCED */
     { obm_restore, TRUE },      /* OBM_RESTORE */
+#ifdef WIN_95_LOOK
+    { obm_zoom_95, TRUE },      /* OBM_ZOOM */
+    { obm_reduce_95, TRUE },    /* OBM_REDUCE */
+#else
     { obm_zoom, TRUE },         /* OBM_ZOOM */
     { obm_reduce, TRUE },       /* OBM_REDUCE */
+#endif
     { obm_lfarrow, TRUE },      /* OBM_LFARROW */
     { obm_rgarrow, TRUE },      /* OBM_RGARROW */
     { obm_dnarrow, TRUE },      /* OBM_DNARROW */
     { obm_uparrow, TRUE },      /* OBM_UPARROW */
+#ifdef WIN_95_LOOK
+    { obm_close_95, TRUE },     /* OBM_CLOSE */
+#else
     { obm_close, TRUE },        /* OBM_CLOSE */
+#endif
     { obm_old_restore, FALSE }, /* OBM_OLD_RESTORE */
     { obm_old_zoom, FALSE },    /* OBM_OLD_ZOOM */
     { obm_old_reduce, FALSE },  /* OBM_OLD_REDUCE */
@@ -163,6 +182,7 @@
     { "button_face",      PALETTEINDEX(COLOR_BTNFACE) },
     { "button_shadow",    PALETTEINDEX(COLOR_BTNSHADOW) },
     { "button_highlight", PALETTEINDEX(COLOR_BTNHIGHLIGHT) },
+    { "button_edge",      PALETTEINDEX(COLOR_BTNHIGHLIGHT) },
     { "button_text",      PALETTEINDEX(COLOR_BTNTEXT) },
     { "window_frame",     PALETTEINDEX(COLOR_WINDOWFRAME) }
 };
diff --git a/rc/ChangeLog b/rc/ChangeLog
deleted file mode 100644
index c08835f..0000000
--- a/rc/ChangeLog
+++ /dev/null
@@ -1,5 +0,0 @@
-----------------------------------------------------------------------
-Sun Sep  25 12:00:00 PDT 1994	<martin@osiris.cs.csufresno.edu>
-
-	* [rc/rc.y] [rc/rc.h] [rc/rc.l] [rc/winerc.c]
-	Files created
diff --git a/rc/Makefile.in b/rc/Makefile.in
index 92bc5f8..63c42d0 100644
--- a/rc/Makefile.in
+++ b/rc/Makefile.in
@@ -34,8 +34,8 @@
 	$(COMPILE) -c -o $*.o $<
 
 clean:
-	rm -f *.o \#*\# *~ lex.yy.c sysres.tmp sysres.rct winerc y.tab.c \
-	y.tab.h sysres.c sysres.h tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
+	rm -f lex.yy.c sysres.tmp sysres.rct winerc y.tab.c y.tab.h sysres.c sysres.h
 
 distclean: clean
 	rm -f Makefile
diff --git a/rc/rc.h b/rc/rc.h
deleted file mode 100644
index 5064c60..0000000
--- a/rc/rc.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- *
- * Copyright  Martin von Loewis, 1994
- *
- */
-
-/* resource types */
-enum rt {acc,bmp,cur,dlg,fnt,ico,men,rdt,str};
-/* generic resource
-   Bytes can be inserted at arbitrary positions, the data field (res) 
-   grows as required. As the dialog header contains the number of 
-   controls, this number is generated in num_entries. If n_type if 0,
-   the resource name is i_name, and s_name otherwise. Top level
-   resources are linked via next. All gen_res objects are linked via
-   g_prev, g_next for debugging purposes. space is the length of res,
-   size is the used part of res.
-   As most bison rules are right recursive, new items are usually 
-   inserted at the beginning
-*/   
-typedef struct gen_res{
-	int size,space;
-	int num_entries;
-	enum rt type;
-	union{
-		int i_name;
-		char* s_name;
-	}n;
-	int n_type; /*0 - integer, 1 = string*/
-	struct gen_res *next;
-	struct gen_res *g_prev,*g_next;
-	unsigned char res[0];
-} gen_res;
-
-/* control/dialog style. or collects styles, and collects NOT styles */
-typedef struct rc_style{
-	int and, or;
-}rc_style;
-
-/* create a new resource */
-gen_res *new_res(void);
-/* double the space of the resource */
-gen_res* grow(gen_res*);
-/* insert byte array at the beginning, increase count */
-gen_res* insert_at_beginning(gen_res*,char*,int);
-/* insert byte array at offset */
-gen_res* insert_bytes(gen_res*,char*,int,int);
-/* delete bytes at offset */
-gen_res* delete_bytes(gen_res*,int,int);
-/* create a new style */
-rc_style* new_style(void);
-/* convert \t to tab etc. */
-char* parse_c_string(char*);
-/* get the resources type, convert dlg to "DIALOG" and so on */
-char* get_typename(gen_res*);
-
-gen_res* add_accelerator(int,int,int,gen_res*);
-gen_res* add_string_accelerator(char*,int,int,gen_res*);
-gen_res* add_ascii_accelerator(int,int,int,gen_res*);
-gen_res* add_vk_accelerator(int,int,int,gen_res*);
-
-gen_res* new_dialog(void);
-gen_res* dialog_style(rc_style*,gen_res*);
-int dialog_get_menu(gen_res*);
-int dialog_get_class(gen_res*);
-int dialog_get_caption(gen_res*);
-int dialog_get_fontsize(gen_res*);
-gen_res* dialog_caption(char*,gen_res*);
-gen_res* dialog_font(short,char*,gen_res*);
-gen_res* dialog_class(char*,gen_res*);
-gen_res* dialog_menu(char*,gen_res*);
-gen_res* create_control_desc(int,int,int,int,int,rc_style*);
-gen_res* label_control_desc(char*,gen_res*);
-gen_res* create_generic_control(char*,int,char*,rc_style*,int,int,int,int);
-gen_res* add_control(int,int,gen_res*,gen_res*);
-gen_res* add_icon(char*,int,int,int,gen_res*,gen_res*);
-gen_res* add_generic_control(gen_res*,gen_res*);
-gen_res* make_dialog(gen_res*,int,int,int,int,gen_res*);
-
-gen_res *hex_to_raw(char*,gen_res*);
-gen_res *make_bitmap(gen_res*);
-gen_res *make_icon(gen_res*);
-gen_res *make_cursor(gen_res*);
-gen_res *load_file(char*);
-
-gen_res *add_menuitem(char*,int,int,gen_res*);
-gen_res *add_popup(char*,short,gen_res*,gen_res*);
-gen_res *make_menu(gen_res*);
-
-gen_res *add_resource(gen_res*,gen_res*);
-
-void create_output(gen_res*);
-void set_out_file(char*);
-
-#define CT_BUTTON 	0x80
-#define CT_EDIT 	0x81
-#define CT_STATIC 	0x82
-#define CT_LISTBOX	0x83
-#define CT_SCROLLBAR 0x84
-#define CT_COMBOBOX	0x85
-
-extern int verbose;
-
-#ifdef __sun__
-#define strtoul strtol
-#endif
-
diff --git a/rc/rc.l b/rc/rc.l
deleted file mode 100644
index 2773820..0000000
--- a/rc/rc.l
+++ /dev/null
@@ -1,75 +0,0 @@
-%{
-/*
- *
- * Copyright  Martin von Loewis, 1994
- *
- */
-static char Copyright[] = "Copyright Martin von Loewis, 1994";
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "rc.h"
-#include "rc.tab.h"
-%}
-%%
-ACCELERATORS	return ACCELERATORS;
-ALT		return ALT;
-ASCII		return ASCII;
-BEGIN		return tBEGIN;
-BITMAP		return tBITMAP;
-CAPTION		return CAPTION;
-CHECKBOX	return CHECKBOX;
-CHECKED		return CHECKED;
-CLASS		return CLASS;
-COMBOBOX	return COMBOBOX;
-CONTROL		return CONTROL;
-CTEXT		return CTEXT;
-CURSOR		return CURSOR;
-DEFPUSHBUTTON	return DEFPUSHBUTTON;
-DIALOG		return DIALOG;
-DISCARDABLE	return DISCARDABLE;
-EDITTEXT	return EDITTEXT;
-END		return tEND;
-FIXED		return FIXED;
-FONT		return FONT;
-GRAYED		return GRAYED;
-GROUPBOX	return GROUPBOX;
-HELP		return HELP;
-ICON		return ICON;
-INACTIVE	return INACTIVE;
-LISTBOX		return LISTBOX;
-LTEXT		return LTEXT;
-MENU		return MENU;
-MENUBARBREAK	return MENUBARBREAK;
-MENUBREAK	return MENUBREAK;
-MENUITEM	return MENUITEM;
-MOVEABLE	return MOVEABLE;
-LOADONCALL	return LOADONCALL;
-NOINVERT	return NOINVERT;
-NOT			return NOT;
-NUMBER		return NUMBER;
-POPUP		return POPUP;
-PRELOAD		return PRELOAD;
-PUSHBUTTON	return PUSHBUTTON;
-PURE		return PURE;
-RADIOBUTTON	return RADIOBUTTON;
-RCDATA		return RCDATA;
-RTEXT		return RTEXT;
-SCROLLBAR	return SCROLLBAR;
-SHIFT		return SHIFT;
-SEPARATOR	return SEPARATOR;
-STRING		return STRING;
-STRINGTABLE	return STRINGTABLE;
-STYLE		return STYLE;
-VERSIONINFO	return VERSIONINFO;
-VIRTKEY		return VIRTKEY;
-\{			return tBEGIN;
-\}			return tEND;
-[+-]?[0-9]+	yylval.num=atoi(yytext);return NUMBER;
-0x[0-9A-Fa-f]+L?	yylval.num=strtoul(yytext,0,16);return NUMBER;
-[A-Za-z][A-Za-z_0-9]*	yylval.str=strdup(yytext);return IDENT;
-\"[^"]*\"	yylval.str=parse_c_string(yytext);return STRING;
-\'[^']*\'   yylval.str=strdup(yytext+1);return SINGLE_QUOTED;
-[ \t\n\r]		;
-.			return yytext[0];
diff --git a/rc/rc.y b/rc/rc.y
deleted file mode 100644
index 3844e39..0000000
--- a/rc/rc.y
+++ /dev/null
@@ -1,210 +0,0 @@
-%{
-/*
- *
- * Copyright  Martin von Loewis, 1994
- */
-
-static char Copyright[] = "Copyright Martin von Loewis, 1994";
-
-#include <stdio.h>
-#include "rc.h"
-#include "windows.h"
-%}
-%union{
-	gen_res *res;
-	char *str;
-	int num;
-	struct rc_style *style;
-}
-%token <num> NUMBER
-%token <str> STRING SINGLE_QUOTED IDENT
-%token ACCELERATORS ALT ASCII tBEGIN tBITMAP CAPTION CHECKBOX CHECKED 
-%token CLASS COMBOBOX CONTROL CTEXT CURSOR DEFPUSHBUTTON DIALOG 
-%token DISCARDABLE EDITTEXT tEND FIXED FONT GRAYED GROUPBOX HELP ICON 
-%token IDENT INACTIVE LISTBOX LTEXT MENU MENUBARBREAK MENUBREAK MENUITEM 
-%token MOVEABLE LOADONCALL NOINVERT NOT NOT_SUPPORTED POPUP PRELOAD 
-%token PURE PUSHBUTTON RADIOBUTTON RCDATA RTEXT SCROLLBAR SHIFT SEPARATOR 
-%token SINGLE_QUOTED STRING STRINGTABLE STYLE VERSIONINFO VIRTKEY
-%type <res> resource_file resource resources resource_definition accelerators
-%type <res> events bitmap cursor dialog dlg_attributes controls 
-%type <res> generic_control labeled_control control_desc font icon 
-%type <res> iconinfo menu menu_body item_definitions rcdata raw_data raw_elements 
-%type <res> stringtable strings versioninfo
-%type <num> acc_options item_options
-%type <style> style optional_style
-%%
-
-resource_file: resources {create_output($1);}
-
-/*resources are put into a linked list*/
-resources:	{$$=0;}
-		|resource resources {$$=add_resource($1,$2);}
-		;
-
-/* get the name for a single resource*/
-resource:	NUMBER resource_definition
-		{$$=$2;$$->n.i_name=$1;$$->n_type=0;
-			if(verbose)fprintf(stderr,"Got %s %d\n",get_typename($2),$1);
-		}
-		| IDENT resource_definition
-		{$$=$2;$$->n.s_name=$1;$$->n_type=1;
-			if(verbose)fprintf(stderr,"Got %s %s\n",get_typename($2),$1);
-		}
-
-/* get the value for a single resource*/
-resource_definition:	accelerators {$$=$1;}
-		| bitmap {$$=$1;}
-		| cursor {$$=$1;}
-		| dialog {$$=$1;}
-		| font {$$=$1;}
-		| icon {$$=$1;}
-		| menu {$$=$1;}
-		| rcdata {$$=$1;}
-		| stringtable {$$=$1;}
-		| versioninfo {$$=$1;}
-
-/* have to use tBEGIN because BEGIN is predefined */
-accelerators:	ACCELERATORS  tBEGIN  events tEND {$$=$3;$$->type=acc;}
-/* the events are collected in a gen_res, as the accelerator resource is just
-   an array of events */
-events:		{$$=new_res();}
-		| STRING ',' NUMBER acc_options  events 
-			{$$=add_string_accelerator($1,$3,$4,$5);}
-		| NUMBER ',' NUMBER ',' ASCII acc_options  events 
-			{$$=add_ascii_accelerator($1,$3,$6,$7);}
-		| NUMBER ',' NUMBER ',' VIRTKEY acc_options  events 
-			{$$=add_vk_accelerator($1,$3,$6,$7);}
-acc_options:	{$$=0;}
-		| ',' NOINVERT acc_options {$$=$3|2;}
-		| ',' ALT acc_options      {$$=$3|16;}
-		| ',' SHIFT acc_options	   {$$=$3|4;}
-		| ',' CONTROL acc_options  {$$=$3|8;}
-
-bitmap:		tBITMAP load_and_memoption STRING {$$=make_bitmap(load_file($3));}
-		| tBITMAP load_and_memoption raw_data {$$=make_bitmap($3);}
-
-/* load and memory options are ignored */
-load_and_memoption:	| lamo load_and_memoption
-lamo:	PRELOAD | LOADONCALL | FIXED | MOVEABLE | DISCARDABLE | PURE
-
-cursor:		CURSOR load_and_memoption STRING {$$=make_cursor(load_file($3));}
-		|CURSOR load_and_memoption raw_data {$$=make_cursor($3);}
-
-dialog:		DIALOG load_and_memoption NUMBER ',' NUMBER ',' NUMBER ',' NUMBER 
-		dlg_attributes
-		tBEGIN  controls tEND 
-		{$$=make_dialog($10,$3,$5,$7,$9,$12);}
-
-dlg_attributes:	{$$=new_dialog();}
-		| STYLE style dlg_attributes 
-		  {$$=dialog_style($2,$3);}
-		| CAPTION STRING dlg_attributes
-		  {$$=dialog_caption($2,$3);}
-		| FONT NUMBER ',' STRING dlg_attributes 
-		  {$$=dialog_font($2,$4,$5);}
-		| CLASS STRING dlg_attributes
-		  {$$=dialog_class($2,$3);}
-		| MENU STRING dlg_attributes
-		  {$$=dialog_menu($2,$3);}
-
-/* the controls are collected into a gen_res, and finally the dialog header 
-   is put at the beginning */
-controls:	{$$=new_res();}
-		| CHECKBOX  labeled_control controls 
-		  {$$=add_control(CT_BUTTON, BS_CHECKBOX, $2, $3);}
-		| COMBOBOX control_desc controls 
-		  {$$=add_control(CT_COMBOBOX, 0, $2, $3);}
-		| CONTROL generic_control controls
-		  {$$=add_generic_control($2, $3);}
-		| CTEXT labeled_control controls 
-		  {$$=add_control(CT_STATIC, SS_CENTER, $2, $3);}
-		| DEFPUSHBUTTON labeled_control controls 
-		  {$$=add_control(CT_BUTTON, BS_DEFPUSHBUTTON, $2, $3);}
-		| EDITTEXT control_desc controls 
-		  {$$=add_control(CT_EDIT, 0, $2, $3);}
-		| GROUPBOX labeled_control controls 
-		  {$$=add_control(CT_BUTTON, BS_GROUPBOX, $2, $3);}
-		/*special treatment for icons, as the extent is optional*/
-		| ICON STRING ',' NUMBER ',' NUMBER ',' NUMBER iconinfo controls
-		  {$$=add_icon($2, $4, $6, $8, $9, $10);}
-		| LISTBOX control_desc controls 
-		  {$$=add_control(CT_LISTBOX, 0, $2, $3);}
-		| LTEXT labeled_control controls 
-		  {$$=add_control(CT_STATIC, SS_LEFT, $2, $3);}
-		| PUSHBUTTON labeled_control controls 
-		  {$$=add_control(CT_BUTTON, BS_PUSHBUTTON, $2, $3);}
-		| RADIOBUTTON labeled_control controls 
-		  {$$=add_control(CT_BUTTON, BS_RADIOBUTTON, $2, $3);}
-		| RTEXT labeled_control controls 
-		  {$$=add_control(CT_STATIC, SS_RIGHT, $2, $3);}
-		| SCROLLBAR control_desc controls		
-		  {$$=add_control(CT_SCROLLBAR, 0, $2, $3);}
-
-
-labeled_control: STRING ',' control_desc {$$=label_control_desc($1,$3);}
-control_desc:	NUMBER ',' NUMBER ',' NUMBER ',' NUMBER ',' NUMBER optional_style 
-		{$$=create_control_desc($1,$3,$5,$7,$9,$10);}
-
-optional_style: {$$=0;}|
-		',' style {$$=$2;}
-
-iconinfo:	/*set extent and style to 0 if they are not provided */
-		{$$=create_control_desc(0,0,0,0,0,0);} 
-		/* x and y are overwritten later */
-		| ',' NUMBER ',' NUMBER optional_style
-        {$$=create_control_desc(0,0,0,$2,$4,$5);}
-
-generic_control:	STRING ',' NUMBER ',' STRING ',' style ',' NUMBER
-		',' NUMBER ',' NUMBER ',' NUMBER
-		{$$=create_generic_control($1,$3,$5,$7,$9,$11,$13,$15);}
-
-font:		FONT load_and_memoption STRING {$$=make_font(load_file($3));}
-
-icon:		ICON load_and_memoption STRING {$$=make_icon(load_file($3));}
-		| ICON load_and_memoption raw_data {$$=make_icon($3);}
-
-menu:		MENU load_and_memoption menu_body {$$=make_menu($3);}
-/* menu items are collected in a gen_res and prefixed with the menu header*/
-menu_body:	tBEGIN item_definitions tEND {$$=$2;}
-item_definitions:	{$$=new_res();}
-		| MENUITEM STRING ',' NUMBER item_options item_definitions
-		  {$$=add_menuitem($2,$4,$5,$6);}
-		| MENUITEM SEPARATOR item_definitions
-		  {$$=add_menuitem("",0,0,$3);}
-		| POPUP STRING item_options menu_body item_definitions
-		  {$$=add_popup($2,$3,$4,$5);}
-item_options:	{$$=0;}
-		| ',' CHECKED item_options {$$=$3|MF_CHECKED;}
-		| ',' GRAYED item_options {$$=$3|MF_GRAYED;}
-		| ',' HELP item_options {$$=$3|MF_HELP;}
-		| ',' INACTIVE item_options {$$=$3|MF_DISABLED;}
-		| ',' MENUBARBREAK item_options {$$=$3|MF_MENUBARBREAK;}
-		| ',' MENUBREAK item_options {$$=$3|MF_MENUBREAK;}
-
-rcdata:		RCDATA load_and_memoption raw_data {$$=make_raw($3);}
-
-raw_data:	tBEGIN raw_elements tEND {$$=$2;}
-raw_elements:	SINGLE_QUOTED {$$=hex_to_raw($1,new_res());}
-		| NUMBER {$$=int_to_raw($1,new_res());}
-		| SINGLE_QUOTED raw_elements {$$=hex_to_raw($1,$2);}
-		| NUMBER ',' raw_elements {$$=int_to_raw($1,$3);}
-
-stringtable:	STRINGTABLE load_and_memoption tBEGIN strings tEND
-			{$$=$4;}
-strings:	{$$=0;}|
-		NUMBER STRING strings {$$=0;}
-
-versioninfo:	VERSIONINFO NOT_SUPPORTED {$$=0;}
-
-/* NOT x | NOT y | a | b means (a|b)& ~x & ~y
-   NOT is used to disable default styles */
-style:		NUMBER {$$=new_style();$$->or=$1;}
-		| NOT NUMBER {$$=new_style();$$->and=~($2);}
-		| '(' style ')' {$$=$2;}
-		| style '|' style {$$=$1;$$->or|=$3->or;$$->and&=$3->and;}
-%%
-int yyerror(char *s)
-{
-	puts(s);
-}
-
diff --git a/rc/sysres.rc b/rc/sysres.rc
index bc15c8c..ecd7859 100644
--- a/rc/sysres.rc
+++ b/rc/sysres.rc
@@ -31,7 +31,7 @@
 
 SHELL_ABOUT_MSGBOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 50, 44, 213, 179
 STYLE DS_LOCALEDIT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-CAPTION "About X"
+CAPTION "About %s"
 FONT 10, "System"
 {
  DEFPUSHBUTTON "OK", 1, 86, 160, 40, 14
diff --git a/rc/sysres_De.rc b/rc/sysres_De.rc
index ee38aae..6201a65 100644
--- a/rc/sysres_De.rc
+++ b/rc/sysres_De.rc
@@ -29,7 +29,7 @@
 
 SHELL_ABOUT_MSGBOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 50, 44, 213, 179
 STYLE DS_LOCALEDIT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-CAPTION ""
+CAPTION "Info über %s"
 FONT 10, "System"
 {
  DEFPUSHBUTTON "OK", 1, 86, 160, 40, 14
diff --git a/rc/sysres_No.rc b/rc/sysres_No.rc
index ec29dd6..3387ef1 100644
--- a/rc/sysres_No.rc
+++ b/rc/sysres_No.rc
@@ -29,7 +29,7 @@
 
 SHELL_ABOUT_MSGBOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 50, 44, 213, 179
 STYLE DS_LOCALEDIT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-CAPTION "Om X"
+CAPTION "Om %s"
 FONT 10, "System"
 {
  DEFPUSHBUTTON "OK", 1, 86, 160, 40, 14
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 8935970..01c4b10 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -19,7 +19,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ build tmp_make
+	rm -f *.o \#*\# *~ *.bak build tmp_make
 
 distclean: clean
 	rm Makefile
diff --git a/tools/build.c b/tools/build.c
index 4fab002..ca9fac7 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -974,21 +974,19 @@
     printf( "\tpushl %%ebp\n" );
     printf( "\tmovl %%esp,%%ebp\n" );
 
-    /* Retrieve the original 32-bit stack pointer */
-
-    printf( "\tmovl " PREFIX "IF1632_Original32_esp, %%eax\n" );
-    printf( "\torl %%eax,%%eax\n" );
-    printf( "\tje 0f\n" );
-
     /* Save registers */
 
     printf( "\tpushl %%ecx\n" );
     printf( "\tpushl %%esi\n" );
     printf( "\tpushl %%edi\n" );
 
-    /* Switch to the new stack */
+    /* Retrieve the original 32-bit stack pointer and switch to it if any */
 
+    printf( "\tmovl " PREFIX "IF1632_Original32_esp, %%eax\n" );
+    printf( "\torl %%eax,%%eax\n" );
+    printf( "\tje 0f\n" );
     printf( "\tmovl %%eax,%%esp\n" );
+    printf( "0:\n" );
 
     /* Transfer the arguments */
 
@@ -1016,29 +1014,8 @@
     printf( "\tpopl %%edi\n" );
     printf( "\tpopl %%esi\n" );
     printf( "\tpopl %%ecx\n" );
-
     printf( "\tpopl %%ebp\n" );
     printf( "\tret\n" );
-
-    /* We get here if IF1632_Original32_esp is 0, i.e. we have not */
-    /* switched to another 32-bit stack yet. */
-
-    printf( "0:\n" );
-
-    /* Move the return address up the stack */
-
-    printf( "\tmovl 4(%%ebp),%%eax\n" );
-    printf( "\tmovl %%eax,12(%%ebp)\n" );
-
-    /* Restore ebp and remove old return address */
-
-    printf( "\tpopl %%ebp\n" );
-    printf( "\taddl $4,%%esp\n" );
-
-    /* Now jump to the routine, leaving the original return address and */
-    /* the arguments on the stack. */
-
-    printf( "\tret\n" );
 }
 
 
diff --git a/windows/Makefile.in b/windows/Makefile.in
index bc1ed67..7621b6f 100644
--- a/windows/Makefile.in
+++ b/windows/Makefile.in
@@ -32,7 +32,7 @@
 	mv tmp_make Makefile
 
 clean:
-	rm -f *.o \#*\# *~ tmp_make
+	rm -f *.o \#*\# *~ *.bak tmp_make
 
 distclean: clean
 	rm Makefile
diff --git a/windows/class.c b/windows/class.c
index 09071bd..4ce07ed 100644
--- a/windows/class.c
+++ b/windows/class.c
@@ -34,7 +34,7 @@
     HCLASS class;
     CLASS * classPtr;
 
-    if (!(atom = LocalFindAtom( name ))) return 0;
+    if (!(atom = GlobalFindAtom( name ))) return 0;
 
       /* First search task-specific classes */
 
@@ -128,7 +128,7 @@
     newClass->wc.cbWndExtra = (class->cbWndExtra < 0) ? 0 : class->cbWndExtra;
     newClass->wc.cbClsExtra = classExtra;
 
-    newClass->atomName = LocalAddAtom( class->lpszClassName );
+    newClass->atomName = GlobalAddAtom( class->lpszClassName );
     newClass->wc.lpszClassName = 0;
 
     if (newClass->wc.style & CS_CLASSDC)
@@ -189,8 +189,7 @@
       /* Delete the class */
     if (classPtr->hdce) DCE_FreeDCE( classPtr->hdce );
     if (classPtr->wc.hbrBackground) DeleteObject( classPtr->wc.hbrBackground );
-    /*if (classPtr->wc.style & CS_GLOBALCLASS)*/ LocalDeleteAtom( classPtr->atomName );
-    /*else DeleteAtom( classPtr->atomName );*/
+    GlobalDeleteAtom( classPtr->atomName );
     if (HIWORD(classPtr->wc.lpszMenuName))
 	USER_HEAP_FREE( LOWORD(classPtr->wc.lpszMenuName) );
     USER_HEAP_FREE( class );
@@ -270,7 +269,7 @@
     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
     if (!(classPtr = CLASS_FindClassPtr(wndPtr->hClass))) return 0;
     
-    return LocalGetAtomName(classPtr->atomName, lpClassName, maxCount);
+    return GlobalGetAtomName(classPtr->atomName, lpClassName, maxCount);
 }
 
 
@@ -315,7 +314,7 @@
 
     pClassEntry->hInst = classPtr->wc.hInstance;
     pClassEntry->wNext = classPtr->hNext;
-    LocalGetAtomName( classPtr->atomName, pClassEntry->szClassName,
+    GlobalGetAtomName( classPtr->atomName, pClassEntry->szClassName,
                        sizeof(pClassEntry->szClassName) );
     return TRUE;
 }
diff --git a/windows/mapping.c b/windows/mapping.c
index 93a6f37..74b91f3 100644
--- a/windows/mapping.c
+++ b/windows/mapping.c
@@ -4,6 +4,7 @@
  * Copyright 1993 Alexandre Julliard
  */
 
+#include <math.h>
 #include "gdi.h"
 #include "metafile.h"
 #include "stddebug.h"
@@ -24,12 +25,12 @@
 	          (dc->w.devCaps->vertRes * dc->w.WndExtY);
     if (xdim > ydim)
     {
-	dc->w.VportExtX = dc->w.VportExtX * ydim / xdim;
+	dc->w.VportExtX = dc->w.VportExtX * fabs( ydim / xdim );
 	if (!dc->w.VportExtX) dc->w.VportExtX = 1;
     }
     else
     {
-	dc->w.VportExtY = dc->w.VportExtY * xdim / ydim;
+	dc->w.VportExtY = dc->w.VportExtY * fabs( xdim / ydim );
 	if (!dc->w.VportExtY) dc->w.VportExtY = 1;
     }	
 }
diff --git a/windows/message.c b/windows/message.c
index 0457e36..72cb9ab 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -28,15 +28,6 @@
 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
 
 
-/* used for passing message information when sending message */ 
-typedef struct {
-    LONG lParam;
-    WORD wParam;
-    WORD wMsg;
-    WORD hWnd;
-} msgstruct;
-
-
 extern BOOL TIMER_CheckTimer( LONG *next, MSG *msg,
 			      HWND hwnd, BOOL remove );  /* timer.c */
 
@@ -146,8 +137,8 @@
 {
     int i, pos = msgQueue->nextMessage;
 
-    dprintf_msg(stddeb,"MSG_FindMsg: hwnd=0x%04x, proc=%d\n",
-		hwnd, curr_proc_idx);
+    dprintf_msg(stddeb,"MSG_FindMsg: hwnd=0x%04x\n\n", hwnd );
+
     if (!msgQueue->msgCount) return -1;
     if (!hwnd && !first && !last) return pos;
         
@@ -436,6 +427,7 @@
 
     for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
     {
+        if (pos >= sysMsgQueue->queueSize) pos = 0;
 	*msg = sysMsgQueue->messages[pos].msg;
 
           /* Translate message */
@@ -455,7 +447,8 @@
         if (hwnd && (msg->hwnd != hwnd)) continue;
         if ((first || last) && 
             ((msg->message < first) || (msg->message > last))) continue;
-        if (GetWindowTask(msg->hwnd) != GetCurrentTask())
+        if ((msg->hwnd != GetDesktopWindow()) && 
+            (GetWindowTask(msg->hwnd) != GetCurrentTask()))
             continue;  /* Not for this task */
         if (remove) MSG_RemoveMsg( sysMsgQueue, pos );
         return TRUE;
@@ -734,12 +727,16 @@
     XEvent event;
     int fd = ConnectionNumber(display);
 
-    if (!XPending(display))
+    if (!XPending(display) && (maxWait != -1))
     {
         FD_ZERO( &read_set );
         FD_SET( fd, &read_set );
+
+	timeout.tv_usec = (maxWait % 1000) * 1000;
+	timeout.tv_sec = maxWait / 1000;
+
+#ifdef CONFIG_IPC
 	sigsetjmp(env_wait_x, 1);
-	
 	stop_wait_op= CONT;
 	    
 	if (DDE_GetRemoteMessage()) {
@@ -747,10 +744,6 @@
 		;
 	    return TRUE;
 	}
-
-	timeout.tv_usec = (maxWait % 1000) * 1000;
-	timeout.tv_sec = maxWait / 1000;
-
 	stop_wait_op= STOP_WAIT_X;
 	/* The code up to the next "stop_wait_op= CONT" must be reentrant  */
 	if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
@@ -760,17 +753,25 @@
 	} else {
 	    stop_wait_op= CONT;
 	}
-	    
+#else  /* CONFIG_IPC */
+	if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
+            return FALSE;  /* Timeout or error */
+#endif  /* CONFIG_IPC */
+
     }
 
     /* Process the event (and possibly others that occurred in the meantime) */
     do
     {
-	if (DDE_GetRemoteMessage()) {
-	    while(DDE_GetRemoteMessage())
-		;
+
+#ifdef CONFIG_IPC
+	if (DDE_GetRemoteMessage())
+        {
+	    while(DDE_GetRemoteMessage()) ;
 	    return TRUE;
 	}
+#endif  /* CONFIG_IPC */
+
         XNextEvent( display, &event );
         EVENT_ProcessEvent( &event );
     }
@@ -789,8 +790,10 @@
     MESSAGEQUEUE *msgQueue;
     LONG nextExp;  /* Next timer expiration time */
 
+#ifdef CONFIG_IPC
     DDE_TestDDE(hwnd);	/* do we have dde handling in the window ?*/
     DDE_GetRemoteMessage();
+#endif  /* CONFIG_IPC */
     
     if (first || last)
     {
@@ -974,8 +977,10 @@
     msg.pt.x    = 0;
     msg.pt.y    = 0;
 
+#ifdef CONFIG_IPC
     if (DDE_PostMessage(&msg))
        return TRUE;
+#endif  /* CONFIG_IPC */
     
     if (hwnd == HWND_BROADCAST) {
       dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
@@ -1026,7 +1031,6 @@
 {
     WND * wndPtr;
     LONG ret;
-    MSG DDE_msg;
     struct
     {
 	LONG lParam;
@@ -1035,11 +1039,10 @@
 	WORD hWnd;
     } msgstruct = { lParam, wParam, msg, hwnd };
 
-    DDE_msg.hwnd    = hwnd;
-    DDE_msg.message = msg;
-    DDE_msg.wParam  = wParam;
-    DDE_msg.lParam  = lParam;
+#ifdef CONFIG_IPC
+    MSG DDE_msg = { hwnd, msg, wParam, lParam };
     if (DDE_SendMessage(&DDE_msg)) return TRUE;
+#endif  /* CONFIG_IPC */
 
     if (hwnd == HWND_BROADCAST)
     {
@@ -1080,7 +1083,9 @@
     MESSAGEQUEUE *queue;
     LONG nextExp = -1;  /* Next timer expiration time */
 
+#ifdef CONFIG_IPC
     DDE_GetRemoteMessage();
+#endif  /* CONFIG_IPC */
     
     if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return;
     if ((queue->wPostQMsg) || 
@@ -1197,7 +1202,7 @@
 WORD RegisterWindowMessage( SEGPTR str )
 {
     dprintf_msg(stddeb, "RegisterWindowMessage: '%08lx'\n", str );
-    return LocalAddAtom( str );
+    return GlobalAddAtom( str );
 }
 
 
diff --git a/windows/win.c b/windows/win.c
index 054df8c..5874ecb 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -189,8 +189,10 @@
     WND *wndPtr = WIN_FindWndPtr( hwnd );
     CLASS *classPtr = CLASS_FindClassPtr( wndPtr->hClass );
 
+#ifdef CONFIG_IPC
     if (main_block)
 	DDE_DestroyWindow(hwnd);
+#endif  /* CONFIG_IPC */
 	
     if (!wndPtr || !classPtr) return;
     WIN_UnlinkWindow( hwnd ); /* Remove the window from the linked list */
diff --git a/wine.ini b/wine.ini
index 6ad81d0..faa56fc 100644
--- a/wine.ini
+++ b/wine.ini
@@ -14,7 +14,7 @@
 SymbolTableFile=./wine.sym

 

 [fonts]

-system=bitstream-courier

+system=*-helvetica

 mssansserif=*-helvetica

 msserif=*-times

 fixedsys=*-fixed