Release 960309

Fri Mar  8 19:07:18 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [configure.in]
	Quote '[' and ']' in the test program for the strength-reduce
	bug. This should work much better...

	* [files/file.c]
	Augmented DOS_FILE structure. Most internal functions now return a
	DOS_FILE* instead of a Unix handle.
	Added a local file array to replace the PDB list upon startup, to
	allow using file I/O functions before the first task is created.
	Added FILE_SetDateTime() and FILE_Sync() functions.
	
	* [loader/module.c]
	Use the DOS file I/O functions in MODULE_LoadExeHeader().

	* [objects/bitblt.c]
	Use visible region instead of GC clip region to clip source
	area. This fixes the card drawing bug in freecell.

	* [objects/region.c]
	Fixed CombineRgn() to allow src and dest regions to be the same.

Fri Mar  8 16:32:23 1996  Frans van Dorsselaer <dorssel@rulhm1.leidenuniv.nl>

	* [controls/EDIT.TODO]
	Updated so it reflects the current status.

	* [controls/edit.c]
	Implemented internal EDIT_WordBreakProc().
	Implemented ES_READONLY.
	Implemented WM_LBUTTONDBLCLK to select whole words.
	Fixed a lot of types in the function definitions.

Wed Mar  6 19:55:00 1996  Alex Korobka <alex@phm30.pharm.sunysb.edu>

	* [debugger/info.c]
	Added "walk window" command to walk window list. 

	* [windows/mdi.c]
	Added proper(?) WM_MDISETMENU message handling.

Wed Mar  6 09:27:12 1996  Martin von Loewis <loewis@informatik.hu-berlin.de>

	* [if1632/callback.c][if1632/relay32.c]
	RELAY32_CallWindowProcConvStruct: new function.

	* [win32/struct32.c][win32/Makefile.in][win32/param.c][win32/user32.c]
	struct32.c: new file. Moved all structure conversions into that file
	PARAM32_POINT32to16,MSG16to32,USER32_RECT32to16: 
	renamed to STRUCT32_POINT32to16, ...
	WIN32_POINT,WIN32_MSG,WIN32_RECT,WIN32_PAINTSTRUCT: renamed to
	POINT32, ...
	New conversion functions for NCCALCSIZE_PARAMS, WINDOWPOS,
 	CREATESTRUCT.

	* [include/windows.h][misc/exec.c]
	WINHELP, MULTIKEYHELP, HELPWININFO: new structures
	WinHelp: Reimplemented. Thanks to Peter Balch
 	(100710.2566@compuserve.com) for his valuable research.

	* [win32/winprocs.c]
	WIN32_CallWindowProcTo16: new function, call in
 	USER32_DefWindowProcA,...

Mon Mar  4 23:22:40 1996  Jim Peterson <jspeter@birch.ee.vt.edu>

	* [include/wintypes.h]
	Added "#define __export".

	* [objects/bitblt.c]
	Put in a few hacks to make bitblt-ing work when upside-down and/or
	mirrored.  BITBLT_StretchImage should really be checked over
	thoroughly.

	* [programs/progman/main.c]
	Added "#include <resource.h>" for definition of HAVE_WINE_CONSTRUCTOR.

	* [rc/parser.h] [rc/parser.l] [rc/parser.y] [rc/winerc.c]
	Eliminated shift/reduce conflict in style definition.
	Added crude error message support: "stdin:%d: parse error before '%s'".
	Implemented string table support to the best of my ability (it works
	with LoadString() calls).

	* [windows/nonclient.c]
	Fixed bug in NC_DoSizeMove() that made system menu pop up when title
	bar of non-iconized window was clicked (checked for iconization).

Mon Mar 04 20:55:19 1996  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [if1632/lzexpand.spec] [if1632/relay.c]
	  [include/lzexpand.h][misc/lzexpand.c]
	LZEXPAND.DLL added.

Sun Mar 03 18:10:22 1996  Albrecht Kleine  <kleine@ak.sax.de>

	* [windows/win.c]
	Prevent usage of invalid HWNDs in WIN_EnumChildWin(),
	this prevents too early termination of EnumChildWindows().
diff --git a/ANNOUNCE b/ANNOUNCE
index 662f7c4..db46d6a 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,15 +1,14 @@
-This is release 960302 of Wine the MS Windows emulator.  This is still a
+This is release 960309 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 "julliard@lrc.epfl.ch".  Please don't
 forget to include a ChangeLog entry.
 
-WHAT'S NEW with Wine-960302: (see ChangeLog for details)
-	- Program manager clone using Winelib.
-	- Support for Esperanto language.
-	- Some scrollbar fixes.
-	- Edit control improvements.
+WHAT'S NEW with Wine-960309: (see ChangeLog for details)
+	- More edit control improvements.
+	- Help begins to work.
+	- Internal LZEXPAND.DLL.
 	- Lots of bug fixes.
 
 See the README file in the distribution for installation instructions.
@@ -18,10 +17,10 @@
 the release is available at the ftp sites.  The sources will be available
 from the following locations:
 
-    sunsite.unc.edu:/pub/Linux/ALPHA/wine/development/Wine-960302.tar.gz
-    tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-960302.tar.gz
-    ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-960302.tar.gz
-    aris.com:/pub/linux/ALPHA/Wine/development/Wine-960302.tar.gz
+    sunsite.unc.edu:/pub/Linux/ALPHA/wine/development/Wine-960309.tar.gz
+    tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-960309.tar.gz
+    ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-960309.tar.gz
+    aris.com:/pub/linux/ALPHA/Wine/development/Wine-960309.tar.gz
 
 It should also be available from any site that mirrors tsx-11 or sunsite.
 
diff --git a/ChangeLog b/ChangeLog
index 3ab435b..3191e3e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,100 @@
 ----------------------------------------------------------------------
+Fri Mar  8 19:07:18 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>
+
+	* [configure.in]
+	Quote '[' and ']' in the test program for the strength-reduce
+	bug. This should work much better...
+
+	* [files/file.c]
+	Augmented DOS_FILE structure. Most internal functions now return a
+	DOS_FILE* instead of a Unix handle.
+	Added a local file array to replace the PDB list upon startup, to
+	allow using file I/O functions before the first task is created.
+	Added FILE_SetDateTime() and FILE_Sync() functions.
+	
+	* [loader/module.c]
+	Use the DOS file I/O functions in MODULE_LoadExeHeader().
+
+	* [objects/bitblt.c]
+	Use visible region instead of GC clip region to clip source
+	area. This fixes the card drawing bug in freecell.
+
+	* [objects/region.c]
+	Fixed CombineRgn() to allow src and dest regions to be the same.
+
+Fri Mar  8 16:32:23 1996  Frans van Dorsselaer <dorssel@rulhm1.leidenuniv.nl>
+
+	* [controls/EDIT.TODO]
+	Updated so it reflects the current status.
+
+	* [controls/edit.c]
+	Implemented internal EDIT_WordBreakProc().
+	Implemented ES_READONLY.
+	Implemented WM_LBUTTONDBLCLK to select whole words.
+	Fixed a lot of types in the function definitions.
+
+Wed Mar  6 19:55:00 1996  Alex Korobka <alex@phm30.pharm.sunysb.edu>
+
+	* [debugger/info.c]
+	Added "walk window" command to walk window list. 
+
+	* [windows/mdi.c]
+	Added proper(?) WM_MDISETMENU message handling.
+
+Wed Mar  6 09:27:12 1996  Martin von Loewis <loewis@informatik.hu-berlin.de>
+
+	* [if1632/callback.c][if1632/relay32.c]
+	RELAY32_CallWindowProcConvStruct: new function.
+
+	* [win32/struct32.c][win32/Makefile.in][win32/param.c][win32/user32.c]
+	struct32.c: new file. Moved all structure conversions into that file
+	PARAM32_POINT32to16,MSG16to32,USER32_RECT32to16: 
+	renamed to STRUCT32_POINT32to16, ...
+	WIN32_POINT,WIN32_MSG,WIN32_RECT,WIN32_PAINTSTRUCT: renamed to
+	POINT32, ...
+	New conversion functions for NCCALCSIZE_PARAMS, WINDOWPOS,
+ 	CREATESTRUCT.
+
+	* [include/windows.h][misc/exec.c]
+	WINHELP, MULTIKEYHELP, HELPWININFO: new structures
+	WinHelp: Reimplemented. Thanks to Peter Balch
+ 	(100710.2566@compuserve.com) for his valuable research.
+
+	* [win32/winprocs.c]
+	WIN32_CallWindowProcTo16: new function, call in
+ 	USER32_DefWindowProcA,...
+
+Mon Mar  4 23:22:40 1996  Jim Peterson <jspeter@birch.ee.vt.edu>
+
+	* [include/wintypes.h]
+	Added "#define __export".
+
+	* [programs/progman/main.c]
+	Added "#include <resource.h>" for definition of HAVE_WINE_CONSTRUCTOR.
+
+	* [rc/parser.h] [rc/parser.l] [rc/parser.y] [rc/winerc.c]
+	Eliminated shift/reduce conflict in style definition.
+	Added crude error message support: "stdin:%d: parse error before '%s'".
+	Implemented string table support to the best of my ability (it works
+	with LoadString() calls).
+
+	* [windows/nonclient.c]
+	Fixed bug in NC_DoSizeMove() that made system menu pop up when title
+	bar of non-iconized window was clicked (checked for iconization).
+
+Mon Mar 04 20:55:19 1996  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
+
+	* [if1632/lzexpand.spec] [if1632/relay.c]
+	  [include/lzexpand.h][misc/lzexpand.c]
+	LZEXPAND.DLL added.
+
+Sun Mar 03 18:10:22 1996  Albrecht Kleine  <kleine@ak.sax.de>
+
+	* [windows/win.c]
+	Prevent usage of invalid HWNDs in WIN_EnumChildWin(),
+	this prevents too early termination of EnumChildWindows().
+
+----------------------------------------------------------------------
 Sat Mar  2 18:19:06 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>
 
 	* [controls/scroll.c]
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index ee927be..a9acbd2 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -5,28 +5,7 @@
 primary source of information to developers is the ChangeLog (next to
 the source, of course).
 
-1. make: No rule to make target foo/foo.o. Stop.
-This frequently happens when a prior attempt to make foo.o failed.
-In the current setup, make does not terminate then, but continues and
-realises the problem later on. 'make' again and watch the output. Be
-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.
-- 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
+1. BAR.EXE used to work, but does not work anymore
 Look at the ChangeLog to see what files have been changed. Try to undo
 the particular patch and go partially back to the previous version. If
 you have any suspicions, report them to the author or to the newsgroup.
diff --git a/configure b/configure
index df78b45..2ad3415 100755
--- a/configure
+++ b/configure
@@ -1473,11 +1473,11 @@
 #include "confdefs.h"
 
 int main(void) {
-  static int Array3;
+  static int Array[3];
   unsigned int B = 3;
   int i;
-  for(i=0; i<B; i++) Arrayi = i - 3;
-  exit( Array1 != -2 );
+  for(i=0; i<B; i++) Array[i] = i - 3;
+  exit( Array[1] != -2 );
 }
 EOF
 eval $ac_link
diff --git a/configure.in b/configure.in
index ff6531b..ad74c73 100644
--- a/configure.in
+++ b/configure.in
@@ -52,11 +52,11 @@
   AC_CACHE_CHECK( "for gcc strength-reduce bug", ac_cv_c_gcc_strength_bug,
                   AC_TRY_RUN([
 int main(void) {
-  static int Array[3];
+  static int Array[[3]];
   unsigned int B = 3;
   int i;
-  for(i=0; i<B; i++) Array[i] = i - 3;
-  exit( Array[1] != -2 );
+  for(i=0; i<B; i++) Array[[i]] = i - 3;
+  exit( Array[[1]] != -2 );
 }],
     ac_cv_c_gcc_strength_bug="no",
     ac_cv_c_gcc_strength_bug="yes",
diff --git a/controls/EDIT.TODO b/controls/EDIT.TODO
index 3aa0ff9..f2d404f 100644
--- a/controls/EDIT.TODO
+++ b/controls/EDIT.TODO
@@ -8,12 +8,8 @@
 
 -  ES_LOWERCASE and ES_UPPERCASE.
 
--  ES_PASSWORD and EM_PASSWORDCHAR.
-
 -  ES_OEMCONVERT.  Probably won't do anything very much.
 
--  ES_READONLY.
-
 -  ES_WANTRETURN and Ctrl-Enter to move to next line when this
    functionality is enabled.
 
@@ -21,3 +17,17 @@
    entered text as well as deleted text.  You can also undo an undo.
 
 -  Add word wrap - this is a very big change!
+
+I'm doing a rewrite on edit.c.  Please e-mail me if you want
+to work on edit.c as well, so we can synchronize.
+
+Bugs in the current version, known to me:
+-  An empty document still contains "\r\n"
+-  UNDO is unstable (incomplete, and it can cause a segfault)
+-  WM_LBUTTONDBLCLK lets you select whole words, but doesn't set
+   the caret at the end of the selection
+-  Scrolling (left-right) works, but the scrollbar doesn't
+
+
+Frans van Dorsselaer
+dorssel@rulhm1.LeidenUniv.nl
diff --git a/controls/edit.c b/controls/edit.c
index e952589..04db65b 100644
--- a/controls/edit.c
+++ b/controls/edit.c
@@ -3,7 +3,14 @@
  *
  * Copyright  David W. Metcalfe, 1994
  * Copyright  William Magro, 1995, 1996
+ * Copyright  Frans van Dorsselaer, 1996
  *
+ * Note: I'm doing a rewrite in order to implement word wrap
+ *       Please e-mail me if you want to word on edit.c as well, so
+ *       we can synchronize.
+ *
+ *       Frans van Dorsselaer
+ *       dorssel@rulhm1.LeidenUniv.nl
  */
 
 #include <stdio.h>
@@ -72,7 +79,6 @@
     int ClientHeight;        /* ditto */
     char PasswordChar;       /* The password character */
     EDITWORDBREAKPROC WordBreakProc;
-    BOOL WeOwnCaret;         /* Do we own the caret ? */
     int CaretPrepareCount;   /* Did we already prepare the caret ? */
     BOOL CaretHidden;        /* Did we hide the caret during painting ? */
     int oldWndCol;           /* WndCol before we started painting */
@@ -96,6 +102,7 @@
 #define IsMultiLine(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & ES_MULTILINE)
 #define IsVScrollBar(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & WS_VSCROLL)
 #define IsHScrollBar(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & WS_HSCROLL)
+#define IsReadOnly(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & ES_READONLY)
 
 /* internal variables */
 static BOOL TextMarking;         /* TRUE if text marking in progress */
@@ -117,7 +124,7 @@
     
     ret = LOCAL_Alloc( WIN_GetWindowInstance(hwnd), flags, bytes );
     if (!ret)
-        printf("EDIT_HeapAlloc: Out of heap-memory\n");
+	fprintf(stderr, "EDIT_HeapAlloc: Out of heap-memory\n");
     return ret;
 }
 
@@ -235,7 +242,7 @@
     EDITSTATE *es = EDIT_GetEditState(hwnd);
 
     if (!es) return;
-    if (!es->WeOwnCaret) return;
+    if (!es->HaveFocus) return;
     if (!es->CaretPrepareCount) return;
     
     if (!es->CaretHidden)
@@ -260,7 +267,7 @@
     es->CaretPrepareCount--;
     
     if (es->CaretPrepareCount) return;
-    if (!es->WeOwnCaret) return;
+    if (!es->HaveFocus) return;
 
     if ((es->WndCol != es->oldWndCol) || (es->WndRow != es->oldWndRow))
 	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
@@ -276,15 +283,53 @@
  *  EDIT_WordBreakProc
  *
  *  Find the beginning of words.
+ *  Note: unlike the specs for a WordBreakProc, this function only
+ *        allows to be called without linebreaks between s[0] upto
+ *        s[count - 1].  Remember it is only called
+ *        internally, so we can decide this for ourselves.
  */
-static int CALLBACK EDIT_WordBreakProc(char * pch, int ichCurrent,
-					int cch, int code)
+static int EDIT_WordBreakProc(char *s, int index, int count, int action)
 {
-    dprintf_edit(stddeb, "EDIT_WordBreakProc: pch=%p, ichCurrent=%d"
-	", cch=%d, code=%d\n", pch, ichCurrent, cch, code);
+    int ret = 0;
 
-    dprintf_edit(stddeb, "string=%s\n", pch);
-    return 0;
+    dprintf_edit(stddeb, "EDIT_WordBreakProc: s=%p, index=%d"
+	", count=%d, action=%d\n", s, index, count, action);
+
+    switch (action) {
+    case WB_LEFT:
+	if (!count) break;
+	if (index) index--;
+	if (s[index] == ' ') {
+	    while (index && (s[index] == ' ')) index--;
+	    if (index) {
+		while (index && (s[index] != ' ')) index--;
+		if (s[index] == ' ') index++;
+	    }
+	} else {
+	    while (index && (s[index] != ' ')) index--;
+	    if (s[index] == ' ') index++;
+	}
+	ret = index;
+	break;
+    case WB_RIGHT:
+	if (!count) break;
+	if (index) index--;
+	if (s[index] == ' ')
+	    while ((index < count) && (s[index] == ' ')) index++;
+	else {
+	    while (s[index] && (s[index] != ' ') && (index < count)) index++;
+	    while ((s[index] == ' ') && (index < count)) index++;
+	}
+	ret = index;
+	break;
+    case WB_ISDELIMITER:
+	ret = (s[index] == ' ');
+	break;
+    default:
+	fprintf(stderr, "EDIT_WordBreakProc: unknown action code !\n");
+	break;
+    }
+    return ret;
 }
 
 /*********************************************************************
@@ -1912,7 +1957,7 @@
 /*********************************************************************
  *  EM_UNDO message function
  */
-static LONG EDIT_UndoMsg(HWND hwnd)
+static LRESULT EDIT_UndoMsg(HWND hwnd)
 {
     char *text;
     EDITSTATE *es = EDIT_GetEditState(hwnd);
@@ -1976,7 +2021,7 @@
 /*********************************************************************
  *  EM_SETTABSTOPS message function
  */
-static LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam)
+static LRESULT EDIT_SetTabStopsMsg(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
     EDITSTATE *es = EDIT_GetEditState(hwnd);
 
@@ -2000,7 +2045,7 @@
 /*********************************************************************
  *  EM_GETLINE message function
  */
-static LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam)
+static LRESULT EDIT_GetLineMsg(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
     char *cp;
     int len = 0;
@@ -2032,13 +2077,13 @@
     dprintf_edit( stddeb, "EDIT_GetLineMsg: %d %d, len %d\n", (int)(WORD)(*buffer), (int)(WORD)(*(char *)buffer), len);
     lstrcpyn(buffer, cp, len);
 
-    return (LONG)len;
+    return (LRESULT)len;
 }
 
 /*********************************************************************
  *  EM_GETSEL message function
  */
-static LONG EDIT_GetSelMsg(HWND hwnd)
+static LRESULT EDIT_GetSelMsg(HWND hwnd)
 {
     int so, eo;
     EDITSTATE *es = EDIT_GetEditState(hwnd);
@@ -2046,13 +2091,13 @@
     so = es->textptrs[es->SelBegLine] + es->SelBegCol;
     eo = es->textptrs[es->SelEndLine] + es->SelEndCol;
 
-    return MAKELONG(so, eo);
+    return (LRESULT)MAKELONG(so, eo);
 }
 
 /*********************************************************************
  *  EM_REPLACESEL message function
  */
-static void EDIT_ReplaceSel(HWND hwnd, LONG lParam)
+static void EDIT_ReplaceSel(HWND hwnd, LPARAM lParam)
 {
     EDIT_DeleteSel(hwnd);
     EDIT_InsertText(hwnd, (char *)PTR_SEG_TO_LIN(lParam),
@@ -2064,24 +2109,24 @@
 /*********************************************************************
  *  EM_LINEFROMCHAR message function
  */
-static LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam)
+static LRESULT EDIT_LineFromCharMsg(HWND hwnd, WPARAM wParam)
 {
     int row, col;
     EDITSTATE *es = EDIT_GetEditState(hwnd);
 
     if (wParam == (WORD)-1)
-	return (LONG)(es->SelBegLine);
+	return (LRESULT)(es->SelBegLine);
     else
 	EDIT_GetLineCol(hwnd, wParam, &row, &col);
 
-    return (LONG)row;
+    return (LRESULT)row;
 }
 
 
 /*********************************************************************
  *  EM_LINEINDEX message function
  */
-static LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam)
+static LRESULT EDIT_LineIndexMsg(HWND hwnd, WPARAM wParam)
 {
     EDITSTATE *es = EDIT_GetEditState(hwnd);
 
@@ -2093,7 +2138,7 @@
 /*********************************************************************
  *  EM_LINELENGTH message function
  */
-static LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam)
+static LRESULT EDIT_LineLengthMsg(HWND hwnd, WPARAM wParam)
 {
     int row, col, len;
     int sbl, sbc, sel, sec;
@@ -2142,7 +2187,7 @@
 /*********************************************************************
  *  EM_SETSEL message function
  */
-static void EDIT_SetSelMsg(HWND hwnd, WORD wParam, LONG lParam)
+static void EDIT_SetSelMsg(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
     INT so, eo;
     EDITSTATE *es = EDIT_GetEditState(hwnd);
@@ -2259,7 +2304,7 @@
     if (lParam) UpdateWindow(hwnd);
     EDIT_RecalcSize(hwnd,es);
 
-    if (es->WeOwnCaret)
+    if (es->HaveFocus)
     {
 	EDIT_CaretHide(hwnd);
 	DestroyCaret();
@@ -2336,7 +2381,7 @@
 /*********************************************************************
  *  WM_NCCREATE
  */
-static long EDIT_WM_NCCreate(HWND hwnd, LONG lParam)
+static long EDIT_WM_NCCreate(HWND hwnd, LPARAM lParam)
 {
     CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
     WND *wndPtr = WIN_FindWndPtr(hwnd);
@@ -2361,7 +2406,7 @@
     /* Caret stuff */
     es->CaretPrepareCount = 1;
     es->CaretHidden = FALSE;
-    es->WeOwnCaret = FALSE;
+    es->HaveFocus = FALSE;
     /*
      * Hack - If there is no local heap then hwnd should be a globalHeap block
      * and the local heap needs to be initilised to the same size(minus something)
@@ -2458,7 +2503,7 @@
 /*********************************************************************
  *  WM_CREATE
  */
-static long EDIT_WM_Create(HWND hwnd, LONG lParam)
+static LRESULT EDIT_WM_Create(HWND hwnd, LPARAM lParam)
 {
     HDC hdc;
     EDITSTATE *es = EDIT_GetEditState(hwnd);
@@ -2507,7 +2552,7 @@
 /*********************************************************************
  *  WM_VSCROLL
  */
-static void EDIT_WM_VScroll(HWND hwnd, WORD wParam, LONG lParam)
+static void EDIT_WM_VScroll(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
 /*
  *    EDITSTATE *es = EDIT_GetEditState(hwnd);
@@ -2532,7 +2577,7 @@
 /*********************************************************************
  *  WM_HSCROLL
  */
-static void EDIT_WM_HScroll(HWND hwnd, WORD wParam, LONG lParam)
+static void EDIT_WM_HScroll(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
 /*
  *    EDITSTATE *es = EDIT_GetEditState(hwnd);
@@ -2548,7 +2593,7 @@
 /*********************************************************************
  *  WM_SIZE
  */
-static void EDIT_WM_Size(HWND hwnd, WORD wParam, LONG lParam)
+static void EDIT_WM_Size(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
     EDITSTATE *es = EDIT_GetEditState(hwnd);
   
@@ -2562,7 +2607,7 @@
 /*********************************************************************
  *  WM_LBUTTONDOWN
  */
-static void EDIT_WM_LButtonDown(HWND hwnd, WORD wParam, LONG lParam)
+static void EDIT_WM_LButtonDown(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
     char *cp;
     int len;
@@ -2605,7 +2650,7 @@
 /*********************************************************************
  *  WM_MOUSEMOVE
  */
-static void EDIT_WM_MouseMove(HWND hwnd, WORD wParam, LONG lParam)
+static void EDIT_WM_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
 {
 /*
  *    EDITSTATE *es = EDIT_GetEditState(hwnd);
@@ -2625,7 +2670,7 @@
 /*********************************************************************
  *  WM_CHAR
  */
-static void EDIT_WM_Char(HWND hwnd, WORD wParam)
+static void EDIT_WM_Char(HWND hwnd, WPARAM wParam)
 {
     dprintf_edit(stddeb,"EDIT_WM_Char: wParam=%c\n", (char)wParam);
 
@@ -2635,17 +2680,25 @@
     case '\n':
 	if (!IsMultiLine(hwnd))
 	    break;
+	if (IsReadOnly(hwnd))
+	{
+	    EDIT_Home(hwnd);
+	    EDIT_Downward(hwnd);
+	    break;
+	}
 	wParam = '\n';
 	EDIT_KeyTyped(hwnd, wParam);
 	break;
 
     case VK_TAB:
+	if (IsReadOnly(hwnd)) break;
 	if (!IsMultiLine(hwnd))
 	    break;
 	EDIT_KeyTyped(hwnd, wParam);
 	break;
 
     default:
+	if (IsReadOnly(hwnd)) break;
 	if (wParam >= 20 && wParam <= 254 && wParam != 127 )
 	    EDIT_KeyTyped(hwnd, wParam);
 	break;
@@ -2655,7 +2708,7 @@
 /*********************************************************************
  *  WM_KEYDOWN
  */
-static void EDIT_WM_KeyDown(HWND hwnd, WORD wParam)
+static void EDIT_WM_KeyDown(HWND hwnd, WPARAM wParam)
 {
     EDITSTATE *es = EDIT_GetEditState(hwnd);
     BOOL motionKey = FALSE;
@@ -2717,6 +2770,7 @@
 	break;
 
     case VK_BACK:
+	if (IsReadOnly(hwnd)) break;
 	if (SelMarked(es))
 	    EDIT_DeleteSel(hwnd);
 	else
@@ -2729,6 +2783,7 @@
 	break;
 
     case VK_DELETE:
+	if (IsReadOnly(hwnd)) break;
 	if (SelMarked(es))
 	    EDIT_DeleteSel(hwnd);
 	else
@@ -2758,7 +2813,7 @@
 /*********************************************************************
  *  WM_SETTEXT
  */
-static LONG EDIT_WM_SetText(HWND hwnd, LONG lParam)
+static LRESULT EDIT_WM_SetText(HWND hwnd, LPARAM lParam)
 {
     int len;
     char *text,*settext;
@@ -2790,11 +2845,34 @@
 }
 
 /*********************************************************************
+ *  WM_LBUTTONDBLCLK
+ */
+static void EDIT_WM_LButtonDblClk(HWND hwnd)
+{
+    EDITSTATE *es = EDIT_GetEditState(hwnd);
+
+    dprintf_edit(stddeb, "WM_LBUTTONDBLCLK: hwnd=%d\n", hwnd);
+    if (SelMarked(es)) EDIT_ClearSel(hwnd);
+    es->SelBegLine = es->SelEndLine = es->CurrLine;
+    es->SelBegCol = EDIT_CallWordBreakProc(hwnd,
+			EDIT_TextLine(hwnd, es->CurrLine),
+			es->CurrCol, 
+			EDIT_LineLength(hwnd, es->CurrLine), 
+			WB_LEFT);
+    es->SelEndCol = EDIT_CallWordBreakProc(hwnd,
+			EDIT_TextLine(hwnd, es->CurrLine),
+			es->CurrCol, 
+			EDIT_LineLength(hwnd, es->CurrLine), 
+			WB_RIGHT);
+    EDIT_WriteTextLine(hwnd, NULL, es->CurrLine);
+}
+
+/*********************************************************************
  * EditWndProc()
  */
 LRESULT EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-    LONG lResult = 0;
+    LRESULT lResult = 0;
     char *textPtr;
     int len;
     EDITSTATE *es = EDIT_GetEditState(hwnd);
@@ -2803,7 +2881,7 @@
 
     switch (uMsg) {
     case EM_CANUNDO:
-	lResult = (LONG)es->hDeletedText;
+	lResult = (LRESULT)es->hDeletedText;
 	break;
 	
     case EM_EMPTYUNDOBUFFER:
@@ -2823,21 +2901,17 @@
 	break;
 
     case EM_GETHANDLE:
-	lResult = (LONG)es->hText;
+	lResult = (LRESULT)es->hText;
 	break;
 
     case EM_GETLINE:
 	if (IsMultiLine(hwnd))
 	    lResult = EDIT_GetLineMsg(hwnd, wParam, lParam);
-	else
-	    lResult = 0L;
 	break;
 
     case EM_GETLINECOUNT:
 	if (IsMultiLine(hwnd))
 	    lResult = es->wlines;
-	else
-	    lResult = 0L;
 	break;
 
     case EM_GETMODIFY:
@@ -2858,7 +2932,7 @@
 
     case EM_GETWORDBREAKPROC:
 	dprintf_edit(stddeb, "EM_GETWORDBREAKPROC\n");
-	lResult = (LONG)es->WordBreakProc;
+	lResult = (LRESULT)es->WordBreakProc;
 	break;
 
     case EM_LIMITTEXT:
@@ -2877,8 +2951,6 @@
     case EM_LINEINDEX:
 	if (IsMultiLine(hwnd))
 	    lResult = EDIT_LineIndexMsg(hwnd, wParam);
-	else
-	    lResult = 0L;
 	break;
 
     case EM_LINELENGTH:
@@ -2907,7 +2979,10 @@
 	break;
 
     case EM_SETREADONLY:
-	fprintf(stdnimp,"edit: cannot process EM_SETREADONLY message\n");
+	dprintf_edit(stddeb, "EM_SETREADONLY, wParam=%d\n", wParam);
+	SetWindowLong(hwnd, GWL_STYLE,
+	    (BOOL)wParam ? (GetWindowLong(hwnd, GWL_STYLE) | ES_READONLY)
+		: (GetWindowLong(hwnd, GWL_STYLE) & ~(DWORD)ES_READONLY));
 	break;
 
     case EM_SETRECT:
@@ -2973,16 +3048,14 @@
 	if ((int)wParam > len)
 	{
 	    strcpy((char *)PTR_SEG_TO_LIN(lParam), textPtr);
-	    lResult = (DWORD)len ;
+	    lResult = (LRESULT)len ;
 	}
-	else
-	    lResult = 0L;
 	EDIT_HeapUnlock(hwnd, es->hText);
 	break;
 
     case WM_GETTEXTLENGTH:
 	textPtr = EDIT_HeapLock(hwnd, es->hText);
-	lResult = (DWORD)strlen(textPtr);
+	lResult = (LRESULT)strlen(textPtr);
 	EDIT_HeapUnlock(hwnd, es->hText);
 	break;
 
@@ -2998,7 +3071,6 @@
 	dprintf_edit(stddeb, "WM_KILLFOCUS\n");
 	es->HaveFocus = FALSE;
 	DestroyCaret();
-	es->WeOwnCaret = FALSE;
 	if (SelMarked(es))
             if(GetWindowLong(hwnd,GWL_STYLE) & ES_NOHIDESEL)
 	        EDIT_UpdateSel(hwnd);
@@ -3026,7 +3098,6 @@
 	break;
 
     case WM_MOVE:
-	lResult = 0;
 	break;
 
     case WM_NCCREATE:
@@ -3046,7 +3117,6 @@
 	es->HaveFocus = TRUE;
 	if (SelMarked(es)) EDIT_UpdateSel(hwnd);
 	CreateCaret(hwnd, 0, 2, es->txtht);
-	es->WeOwnCaret = TRUE;
 	SetCaretPos(es->WndCol, es->WndRow * es->txtht);
 	es->CaretHidden = TRUE;
 	NOTIFY_PARENT(hwnd, EN_SETFOCUS);
@@ -3059,7 +3129,6 @@
     case WM_SETREDRAW:
 	dprintf_edit(stddeb, "WM_SETREDRAW: hwnd=%d, wParam=%x\n",
 		     hwnd, wParam);
-	lResult = 0;
 	break;
 #endif
     case WM_SETTEXT:
@@ -3069,7 +3138,6 @@
 
     case WM_SIZE:
 	EDIT_WM_Size(hwnd, wParam, lParam);
-	lResult = 0;
 	break;
 
     case WM_VSCROLL:
@@ -3077,9 +3145,7 @@
 	break;
 
     case WM_LBUTTONDBLCLK:
-	dprintf_edit(stddeb, "WM_LBUTTONDBLCLK: hwnd=%d, wParam=%x\n",
-		     hwnd, wParam);
-	lResult = 0;
+	EDIT_WM_LButtonDblClk(hwnd);
 	break;
 
     default:
diff --git a/controls/scroll.c b/controls/scroll.c
index e746ec5..8f67f09 100644
--- a/controls/scroll.c
+++ b/controls/scroll.c
@@ -435,7 +435,7 @@
     InflateRect( &r, -1, -1 );
     GRAPH_DrawReliefRect( hdc, &r, 1, 2, FALSE );
     if ((hwndTracking == hwnd) && (nBarTracking == nBar))
-        SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, uTrackingPos);
+        SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, uTrackingPos);
 }
 
 
diff --git a/debugger/dbg.y b/debugger/dbg.y
index d42eac7..1105e0a 100644
--- a/debugger/dbg.y
+++ b/debugger/dbg.y
@@ -34,7 +34,8 @@
 }
 
 %token CONT STEP LIST NEXT QUIT HELP BACKTRACE INFO STACK SEGMENTS REGS
-%token ENABLE DISABLE BREAK DELETE SET MODE PRINT EXAM DEFINE ABORT
+%token ENABLE DISABLE BREAK DELETE SET MODE PRINT EXAM DEFINE ABORT WALK
+%token WND QUEUE 
 %token NO_SYMBOL EOL
 %token SYMBOLFILE
 
@@ -93,6 +94,8 @@
 			       }
 	| DELETE BREAK NUM EOL { DEBUG_DelBreakpoint( $3 ); }
 	| BACKTRACE EOL	       { DEBUG_BackTrace(); }
+	| WALK WND EOL	       { DEBUG_InitWalk(); DEBUG_WndWalk( NULL ); }
+	| WALK WND NUM EOL     { DEBUG_InitWalk(); DEBUG_WndWalk( $3 ); }
 	| infocmd
 	| x_command
 	| print_command
@@ -180,6 +183,8 @@
 	| INFO BREAK EOL          { DEBUG_InfoBreakpoints(); }
 	| INFO SEGMENTS EOL	  { LDT_Print( 0, -1 ); }
 	| INFO SEGMENTS expr EOL  { LDT_Print( SELECTOR_TO_ENTRY($3), 1 ); }
+	| INFO WND expr EOL       { DEBUG_WndDump( $3 ); } 
+	| INFO QUEUE expr EOL     { DEBUG_QueueDump( $3 ); }
 
 
 %%
diff --git a/debugger/debug.l b/debugger/debug.l
index 50c66d7..cc46238 100644
--- a/debugger/debug.l
+++ b/debugger/debug.l
@@ -90,6 +90,9 @@
 disable|disabl|disab|disa|dis	{ return DISABLE; }
 delete|delet|dele|del		{ return DELETE; }
 quit|qui|qu|q			{ return QUIT; }
+walk|w				{ return WALK; }
+queue|queu|que			{ return QUEUE; }
+window|windo|wind|win|wnd	{ return WND; }
 x				{ return EXAM; }
 
 help|hel|he|"?"			{ return HELP; }
diff --git a/debugger/info.c b/debugger/info.c
index 54d5140..c17efaa 100644
--- a/debugger/info.c
+++ b/debugger/info.c
@@ -7,8 +7,190 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include "global.h"
+#include "user.h"
+#include "class.h"
+#include "win.h"
+#include "message.h"
+#include "spy.h"
 #include "debugger.h"
 
+int	  	iWndIndent = 0;
+
+extern 	char	lpstrSpyMessageIndent[]; /* from misc/spy.c */
+
+/***********************************************************************
+ *	    DEBUG_InitWalk
+ */
+void DEBUG_InitWalk(void)
+{
+  fprintf(stderr,"%-24.24s %-6.6s %-17.17s %-8.8s %s\n",
+                 "HWND / WNDPTR","hQueue","Class Name", "Style", "WndProc");
+  lpstrSpyMessageIndent[0]='\0';
+}
+
+/***********************************************************************
+ *           DEBUG_WndWalk
+ *
+ */
+void DEBUG_WndWalk(HWND hStart)
+{
+  WND*  	wndPtr;
+  CLASS*	classPtr;
+  char	 	className[0x10];
+  int		i;
+
+  if( !hStart )
+       hStart = GetDesktopHwnd();
+
+  wndPtr = WIN_FindWndPtr(hStart);
+
+  if( !wndPtr )
+    { fprintf(stderr, "Invalid window handle: %04x\n", hStart);
+      return; }
+
+  i = strlen(lpstrSpyMessageIndent);
+ 
+  /* 0x10 bytes are always reserved at the end of lpstrSpyMessageIndent */
+  sprintf(lpstrSpyMessageIndent + i,"%04x %08x",hStart, (unsigned) wndPtr);
+
+  classPtr = CLASS_FindClassPtr(wndPtr->hClass);
+  if(classPtr)
+     GlobalGetAtomName(classPtr->atomName ,className, 0x10);
+  else
+     strcpy(className,"<BAD>");
+
+  fprintf(stderr,"%-24.24s %-6.4x %-17.17s %08x %04x:%04x\n",
+		 lpstrSpyMessageIndent,
+		 wndPtr->hmemTaskQ, 
+		 className,
+		 (unsigned) wndPtr->dwStyle,
+		 HIWORD(wndPtr->lpfnWndProc),
+		 LOWORD(wndPtr->lpfnWndProc));
+
+  lpstrSpyMessageIndent[i] = '\0';
+
+  if( wndPtr->hwndChild )  
+    {
+      /* walk children */
+
+      hStart = wndPtr->hwndChild;
+      wndPtr = WIN_FindWndPtr(hStart);
+
+      iWndIndent ++;
+      if( iWndIndent < SPY_MAX_INDENTLEVEL - 0x10 )
+        { 
+          lpstrSpyMessageIndent[iWndIndent - 1] = ' ';
+	  lpstrSpyMessageIndent[iWndIndent] = '\0';
+        }
+ 
+      while( wndPtr )
+  	  { 
+             DEBUG_WndWalk(hStart);
+	     hStart = wndPtr->hwndNext; 
+	     wndPtr = WIN_FindWndPtr(hStart);
+  	  }
+
+      if( hStart )
+          fprintf(stderr, "%s%s"NPFMT"\n", lpstrSpyMessageIndent,
+					  "<BAD>", hStart);
+
+      if( iWndIndent )
+        {
+          iWndIndent--;
+          if( iWndIndent < SPY_MAX_INDENTLEVEL - 0x10 )
+              lpstrSpyMessageIndent[iWndIndent] = '\0';
+        }
+
+    }
+}
+
+/***********************************************************************
+ *	     DEBUG_WndDump
+ *
+ */ 
+void DEBUG_WndDump(HWND hWnd)
+{
+  WND*		wnd;
+  char*		lpWndText = NULL;
+
+  wnd = WIN_FindWndPtr(hWnd);
+
+  if( !wnd )
+    { fprintf(stderr, "Invalid window handle: %04x\n", hWnd);
+      return; }
+ 
+  if( wnd->hText ) 
+      lpWndText = (LPSTR) USER_HEAP_LIN_ADDR( wnd->hText );
+
+  fprintf( stderr, "next: %12.4x\n"
+                   "child:  %10.4x\n"
+                   "parent: %10.4x\n"
+                   "owner:  %10.4x\n"
+                   "hClass: %10.4x\n"
+                   "hInst:  %10.4x\n"
+                   "clientRect: %i,%i - %i,%i\n"
+                   "windowRect: %i,%i - %i,%i\n"
+                   "hRgnUpdate: %6.4x\n"
+                   "hLastPopup: %6.4x\n"
+                   "Style:  %10.8x\n"
+                   "StyleEx: %9.8x\n"
+                   "hDCE:   %10.4x\n"
+                   "hVscroll: %8.4x\n"
+                   "hHscroll: %8.4x\n"
+                   "menuID: %10.4x\n"
+                   "hText:  %10.4x (\"%s\")\n"
+                   "flags:  %10.4x\n",
+                   wnd->hwndNext, wnd->hwndChild,wnd->hwndParent,
+                   wnd->hwndOwner,wnd->hClass,wnd->hInstance,
+                   wnd->rectClient.left, wnd->rectClient.top, 
+                   wnd->rectClient.right, wnd->rectClient.bottom,
+                   wnd->rectWindow.left, wnd->rectWindow.top,
+                   wnd->rectWindow.right, wnd->rectWindow.bottom,
+                   wnd->hrgnUpdate, wnd->hwndLastActive,
+                   (unsigned) wnd->dwStyle, (unsigned) wnd->dwExStyle,
+                   wnd->hdce, wnd->hVScroll, wnd->hHScroll,
+                   wnd->wIDmenu, wnd->hText, (lpWndText)?lpWndText:"NULL",
+                   wnd->flags);
+}
+
+/***********************************************************************
+ *	     DEBUG_QueueDump
+ *
+ */
+void DEBUG_QueueDump(HQUEUE hQ)
+{
+ MESSAGEQUEUE*	pq; 
+
+ if( !hQ || IsBadReadPtr((SEGPTR)MAKELONG( 0, GlobalHandleToSel(hQ)),
+		    				sizeof(MESSAGEQUEUE)) )
+   {
+     fprintf(stderr, "Invalid queue handle: "NPFMT"\n", hQ);
+     return;
+   }
+
+ pq = (MESSAGEQUEUE*) GlobalLock( hQ );
+
+ fprintf(stderr,"next: %12.4x  Intertask SendMessage:\n"
+                "hTask: %11.4x  ----------------------\n"
+                "msgSize: %9.4x  hWnd: %10.4x\n"
+                "msgCount: %8.4x  msg: %11.4x\n"
+                "msgNext: %9.4x  wParam: %8.4x\n"
+                "msgFree: %9.4x  lParam: %8.8x\n"
+                "qSize: %11.4x  lRet: %10.8x\n"
+                "wWinVer: %9.4x  ISMH: %10.4x\n"
+                "paints: %10.4x  hSendTask: %5.4x\n"
+                "timers: %10.4x  hPrevSend: %5.4x\n"
+                "wakeBits: %8.4x\n"
+                "wakeMask: %8.4x\n"
+                "hCurHook: %8.4x\n",
+                pq->next, pq->hTask, pq->msgSize, pq->hWnd, 
+		pq->msgCount, pq->msg, pq->nextMessage, pq->wParam,
+		pq->nextFreeMessage, (unsigned)pq->lParam, pq->queueSize,
+		(unsigned)pq->SendMessageReturn, pq->wWinVersion, pq->InSendMessageHandle,
+		pq->wPaintCount, pq->hSendingTask, pq->wTimerCount,
+		pq->hPrevSendingTask, pq->status, pq->wakeMask, pq->hCurHook);
+}
 
 /***********************************************************************
  *           DEBUG_Print
@@ -108,8 +290,10 @@
 "  step                                 next",
 "  mode [16,32]                         print <expr>",
 "  set <reg> = <expr>                   set *<addr> = <expr>",
+"  walk [wnd] <expr>			 dump [wnd, queue] <expr>",
 "  info [reg,stack,break,segments]      bt",
 "  symbolfile <filename>                define <identifier> <addr>",
+"  list <addr> ",
 "",
 "The 'x' command accepts repeat counts and formats (including 'i') in the",
 "same way that gdb does.",
@@ -143,7 +327,7 @@
     {
         DEBUG_PrintAddress( addr, dbg_mode );
         fprintf( stderr, ":  " );
-        if (!DBG_CHECK_READ_PTR( addr, 1 )) break;
+        if (!DBG_CHECK_READ_PTR( addr, 1 )) return;
         DEBUG_Disasm( addr );
         fprintf (stderr, "\n");
     }
diff --git a/files/dos_fs.c b/files/dos_fs.c
index e0172f6..2b736ca 100644
--- a/files/dos_fs.c
+++ b/files/dos_fs.c
@@ -259,9 +259,9 @@
  *
  * Convert a Unix time in the DOS date/time format.
  */
-void DOSFS_ToDosDateTime( time_t *unixtime, WORD *pDate, WORD *pTime )
+void DOSFS_ToDosDateTime( time_t unixtime, WORD *pDate, WORD *pTime )
 {
-    struct tm *tm = localtime( unixtime );
+    struct tm *tm = localtime( &unixtime );
     if (pTime)
         *pTime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2);
     if (pDate)
@@ -652,12 +652,11 @@
     
     if ((attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL)
     {
-        time_t now = time(NULL);
         if (skip) return 0;
         strcpy( entry->name, DRIVE_GetLabel( drive ) );
         entry->attr = FA_LABEL;
         entry->size = 0;
-        DOSFS_ToDosDateTime( &now, &entry->date, &entry->time );
+        DOSFS_ToDosDateTime( time(NULL), &entry->date, &entry->time );
         return 1;
     }
 
diff --git a/files/file.c b/files/file.c
index 8ea3d1e..a16f929 100644
--- a/files/file.c
+++ b/files/file.c
@@ -8,11 +8,13 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/errno.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <unistd.h>
+#include <utime.h>
 
 #include "windows.h"
 #include "directory.h"
@@ -25,91 +27,115 @@
 #include "task.h"
 #include "stddebug.h"
 #include "debug.h"
+#include "xmalloc.h"
 
 #define MAX_OPEN_FILES 64  /* Max. open files for all tasks; must be <255 */
 
-typedef struct
+typedef struct tagDOS_FILE
 {
-    int unix_handle;
-    int mode;
+    struct tagDOS_FILE *next;
+    int                 count;        /* Usage count (0 if free) */
+    int                 unix_handle;
+    int                 mode;
+    char               *unix_name;
+    WORD                filedate;
+    WORD                filetime;
 } DOS_FILE;
 
 /* Global files array */
-static DOS_FILE DOSFiles[MAX_OPEN_FILES];
+static DOS_FILE DOSFiles[MAX_OPEN_FILES] = { { 0, }, };
 
+static DOS_FILE *FILE_First = DOSFiles;
+static DOS_FILE *FILE_LastUsed = DOSFiles;
+
+/* Small file handles array for boot-up, before the first PDB is created */
+#define MAX_BOOT_HANDLES  4
+static BYTE bootFileHandles[MAX_BOOT_HANDLES] = { 0xff, 0xff, 0xff, 0xff };
 
 /***********************************************************************
- *           FILE_AllocDOSFile
+ *           FILE_Alloc
  *
- * Allocate a file from the DOS files array.
+ * Allocate a DOS file.
  */
-static BYTE FILE_AllocDOSFile( int unix_handle )
+static DOS_FILE *FILE_Alloc(void)
 {
-    BYTE i;
-    for (i = 0; i < MAX_OPEN_FILES; i++) if (!DOSFiles[i].mode)
+    DOS_FILE *file = FILE_First;
+    if (file) FILE_First = file->next;
+    else if (FILE_LastUsed >= &DOSFiles[MAX_OPEN_FILES-1])
     {
-        DOSFiles[i].unix_handle = unix_handle;
-        DOSFiles[i].mode = 1;
-        return i;
+        DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
+        return NULL;
     }
-    return 0xff;
+    else file = ++FILE_LastUsed;
+    file->count = 1;
+    file->unix_handle = -1;
+    file->unix_name = NULL;
+    return file;
 }
 
 
 /***********************************************************************
- *           FILE_FreeDOSFile
+ *           FILE_Close
  *
- * Free a file from the DOS files array.
+ * Close a DOS file.
  */
-static BOOL FILE_FreeDOSFile( BYTE handle )
+static BOOL FILE_Close( DOS_FILE *file )
 {
-    if (handle >= MAX_OPEN_FILES) return FALSE;
-    if (!DOSFiles[handle].mode) return FALSE;
-    DOSFiles[handle].mode = 0;
+    if (!file->count) return FALSE;
+    if (--file->count > 0) return TRUE;
+    /* Now really close the file */
+    if (file->unix_handle != -1) close( file->unix_handle );
+    if (file->unix_name) free( file->unix_name );
+    file->next = FILE_First;
+    FILE_First = file;
     return TRUE;
 }
 
 
 /***********************************************************************
- *           FILE_GetUnixHandle
+ *           FILE_GetPDBFiles
  *
- * Return the Unix handle for a global DOS file handle.
+ * Return a pointer to the current PDB files array.
  */
-static int FILE_GetUnixHandle( BYTE handle )
+static void FILE_GetPDBFiles( BYTE **files, WORD *nbFiles )
 {
-    if (handle >= MAX_OPEN_FILES) return -1;
-    if (!DOSFiles[handle].mode) return -1;
-    return DOSFiles[handle].unix_handle;
+    PDB *pdb;
+
+    if ((pdb = (PDB *)GlobalLock( GetCurrentPDB() )) != NULL)
+    {
+        *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
+        *nbFiles = pdb->nbFiles;
+    }
+    else
+    {
+        *files = bootFileHandles;
+        *nbFiles = MAX_BOOT_HANDLES;
+    }
 }
 
 
 /***********************************************************************
  *           FILE_AllocTaskHandle
  *
- * Allocate a per-task file handle.
+ * Allocate a task file handle for a DOS file.
  */
-static HFILE FILE_AllocTaskHandle( int unix_handle )
+static HFILE FILE_AllocTaskHandle( DOS_FILE *dos_file )
 {
-    PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
     BYTE *files, *fp;
-    WORD i;
+    WORD i, nbFiles;
 
-    if (!pdb)
-    {
-        fprintf(stderr,"FILE_MakeTaskHandle: internal error, no current PDB.\n");
-        exit(1);
-    }
-    files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
+    FILE_GetPDBFiles( &files, &nbFiles );
     fp = files + 1;  /* Don't use handle 0, as some programs don't like it */
-    for (i = pdb->nbFiles - 1; (i > 0) && (*fp != 0xff); i--, fp++);
-    if (!i || (*fp = FILE_AllocDOSFile( unix_handle )) == 0xff)
+    for (i = nbFiles - 1; (i > 0) && (*fp != 0xff); i--, fp++);
+    if (!i)
     {  /* No more handles or files */
         DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
         return -1;
     }
+    *fp = dos_file ? (BYTE)(dos_file - DOSFiles) : 0;
     dprintf_file(stddeb, 
-       "FILE_AllocTaskHandle: returning task handle %d, file %d for unix handle %d file %d of %d \n", 
-             (fp - files), *fp, unix_handle, pdb->nbFiles - i, pdb->nbFiles  );
+       "FILE_AllocTaskHandle: returning task handle %d, dos_file %d, file %d of %d \n", 
+             (fp - files), *fp, nbFiles - i, nbFiles  );
     return (HFILE)(fp - files);
 }
 
@@ -121,19 +147,13 @@
  */
 static void FILE_FreeTaskHandle( HFILE handle )
 {
-    PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
     BYTE *files;
-    
-    if (!pdb)
-    {
-        fprintf(stderr,"FILE_FreeTaskHandle: internal error, no current PDB.\n");
-        exit(1);
-    }
-    files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
+    WORD nbFiles;
+
+    FILE_GetPDBFiles( &files, &nbFiles );
     dprintf_file( stddeb,"FILE_FreeTaskHandle: dos=%d file=%d\n",
                   handle, files[handle] );
-    if ((handle < 0) || (handle >= (INT)pdb->nbFiles) ||
-        !FILE_FreeDOSFile( files[handle] ))
+    if ((handle < 0) || (handle >= (INT)nbFiles))
     {
         fprintf( stderr, "FILE_FreeTaskHandle: invalid file handle %d\n",
                  handle );
@@ -144,29 +164,49 @@
 
 
 /***********************************************************************
- *           FILE_GetUnixTaskHandle
+ *           FILE_SetTaskHandle
  *
- * Return the Unix file handle associated to a task file handle.
+ * Set the value of a task handle (no error checking).
  */
-int FILE_GetUnixTaskHandle( HFILE handle )
+static void FILE_SetTaskHandle( HFILE handle, DOS_FILE *file )
 {
-    PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
     BYTE *files;
-    int unix_handle;
+    WORD nbFiles;
 
-    if (!pdb)
-    {
-        fprintf(stderr,"FILE_GetUnixHandle: internal error, no current PDB.\n");
-        exit(1);
-    }
-    files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
-    if ((handle < 0) || (handle >= (INT)pdb->nbFiles) ||
-        ((unix_handle = FILE_GetUnixHandle( files[handle] )) == -1))
+    FILE_GetPDBFiles( &files, &nbFiles );
+    files[handle] = (BYTE)(file - DOSFiles);
+}
+
+
+/***********************************************************************
+ *           FILE_GetFile
+ *
+ * Return the DOS file associated to a task file handle.
+ */
+static DOS_FILE *FILE_GetFile( HFILE handle )
+{
+    BYTE *files;
+    WORD nbFiles;
+    DOS_FILE *file;
+
+    FILE_GetPDBFiles( &files, &nbFiles );
+    if ((handle < 0) || (handle >= (INT)nbFiles) ||
+        (files[handle] >= MAX_OPEN_FILES) ||
+        !(file = &DOSFiles[files[handle]])->count)
     {
         DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
-        return -1;
+        return NULL;
     }
-    return unix_handle;
+    return file;
+}
+
+
+int FILE_GetUnixHandle( HFILE hFile )
+{
+    DOS_FILE *file;
+
+    if (!(file = FILE_GetFile( hFile ))) return -1;
+    return file->unix_handle;
 }
 
 
@@ -180,22 +220,14 @@
     BYTE *files;
     WORD count;
     PDB *pdb = (PDB *)GlobalLock( hPDB );
-    int unix_handle;
 
     if (!pdb) return;
     files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
     dprintf_file(stddeb,"FILE_CloseAllFiles: closing %d files\n",pdb->nbFiles);
     for (count = pdb->nbFiles; count > 0; count--, files++)
     {
-        if (*files != 0xff)
-        {
-            if ((unix_handle = FILE_GetUnixHandle( *files )) != -1)
-            {
-                close( unix_handle );
-                FILE_FreeDOSFile( *files );
-            }
-            *files = 0xff;
-        }
+        if (*files < MAX_OPEN_FILES) FILE_Close( &DOSFiles[*files] );
+        *files = 0xff;
     }
 }
 
@@ -251,42 +283,45 @@
 /***********************************************************************
  *           FILE_OpenUnixFile
  */
-static int FILE_OpenUnixFile( const char *name, int mode )
+static DOS_FILE *FILE_OpenUnixFile( const char *name, int mode )
 {
-    int handle;
+    DOS_FILE *file;
     struct stat st;
 
-    if ((handle = open( name, mode )) == -1)
+    if (!(file = FILE_Alloc())) return NULL;
+    if ((file->unix_handle = open( name, mode )) == -1)
     {
         if (Options.allowReadOnly && (mode == O_RDWR))
         {
-            if ((handle = open( name, O_RDONLY )) != -1)
+            if ((file->unix_handle = open( name, O_RDONLY )) != -1)
                 fprintf( stderr, "Warning: could not open %s for writing, opening read-only.\n", name );
         }
     }
-    if (handle != -1)  /* Make sure it's not a directory */
+    if ((file->unix_handle == -1) || (fstat( file->unix_handle, &st ) == -1))
     {
-        if ((fstat( handle, &st ) == -1))
-        {
-            FILE_SetDosError();
-            close( handle );
-            handle = -1;
-        }
-        else if (S_ISDIR(st.st_mode))
-        {
-            DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
-            close( handle );
-            handle = -1;
-        }
+        FILE_SetDosError();
+        FILE_Close( file );
+        return NULL;
     }
-    return handle;
+    if (S_ISDIR(st.st_mode))
+    {
+        DOS_ERROR( ER_AccessDenied, EC_AccessDenied, SA_Abort, EL_Disk );
+        FILE_Close( file );
+        return NULL;
+    }
+
+    /* File opened OK, now fill the DOS_FILE */
+
+    file->unix_name = xstrdup( name );
+    DOSFS_ToDosDateTime( st.st_mtime, &file->filedate, &file->filetime );
+    return file;
 }
 
 
 /***********************************************************************
  *           FILE_Open
  */
-int FILE_Open( LPCSTR path, int mode )
+static DOS_FILE *FILE_Open( LPCSTR path, int mode )
 {
     const char *unixName;
 
@@ -298,10 +333,10 @@
         {
             dprintf_file(stddeb, "FILE_Open: Non-existing device\n");
             DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
-            return -1;
+            return NULL;
         }
     }
-    else if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return -1;
+    else if (!(unixName = DOSFS_GetUnixFileName( path, TRUE ))) return NULL;
     return FILE_OpenUnixFile( unixName, mode );
 }
 
@@ -309,10 +344,10 @@
 /***********************************************************************
  *           FILE_Create
  */
-int FILE_Create( LPCSTR path, int mode, int unique )
+static DOS_FILE *FILE_Create( LPCSTR path, int mode, int unique )
 {
+    DOS_FILE *file;
     const char *unixName;
-    int handle;
 
     dprintf_file(stddeb, "FILE_Create: '%s' %04x %d\n", path, mode, unique );
 
@@ -320,15 +355,30 @@
     {
         dprintf_file(stddeb, "FILE_Create: creating device '%s'!\n", unixName);
         DOS_ERROR( ER_AccessDenied, EC_NotFound, SA_Abort, EL_Disk );
-        return -1;
+        return NULL;
     }
 
-    if (!(unixName = DOSFS_GetUnixFileName( path, FALSE ))) return -1;
-    if ((handle = open( unixName,
-                        O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
-                        mode )) == -1)
+    if (!(file = FILE_Alloc())) return NULL;
+
+    if (!(unixName = DOSFS_GetUnixFileName( path, FALSE )))
+    {
+        FILE_Close( file );
+        return NULL;
+    }
+    if ((file->unix_handle = open( unixName,
+                           O_CREAT | O_TRUNC | O_RDWR | (unique ? O_EXCL : 0),
+                           mode )) == -1)
+    {
         FILE_SetDosError();
-    return handle;
+        FILE_Close( file );
+        return NULL;
+    } 
+
+    /* File created OK, now fill the DOS_FILE */
+
+    file->unix_name = xstrdup( unixName );
+    DOSFS_ToDosDateTime( time(NULL), &file->filedate, &file->filetime );
+    return file;
 }
 
 
@@ -375,36 +425,78 @@
     }
     if (pattr) *pattr = FA_ARCHIVE | (S_ISDIR(st.st_mode) ? FA_DIRECTORY : 0);
     if (psize) *psize = S_ISDIR(st.st_mode) ? 0 : st.st_size;
-    DOSFS_ToDosDateTime( &st.st_mtime, pdate, ptime );
+    DOSFS_ToDosDateTime( st.st_mtime, pdate, ptime );
     return 1;
 }
 
 
 /***********************************************************************
- *           FILE_Fstat
+ *           FILE_GetDateTime
  *
- * Stat a DOS handle. Return 1 if OK.
+ * Get the date and time of a file.
  */
-int FILE_Fstat( HFILE hFile, BYTE *pattr, DWORD *psize,
-                WORD *pdate, WORD *ptime )
+int FILE_GetDateTime( HFILE hFile, WORD *pdate, WORD *ptime, BOOL refresh )
 {
-    struct stat st;
-    int handle;
+    DOS_FILE *file;
 
-    if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return 0;
-    if (fstat( handle, &st ) == -1)
+    if (!(file = FILE_GetFile( hFile ))) return 0;
+    if (refresh)
     {
-        FILE_SetDosError();
-        return 0;
+        struct stat st;
+        if (fstat( file->unix_handle, &st ) == -1)
+        {
+            FILE_SetDosError();
+            return 0;
+        }
+        DOSFS_ToDosDateTime( st.st_mtime, &file->filedate, &file->filetime );
     }
-    if (pattr) *pattr = FA_ARCHIVE | (S_ISDIR(st.st_mode) ? FA_DIRECTORY : 0);
-    if (psize) *psize = S_ISDIR(st.st_mode) ? 0 : st.st_size;
-    DOSFS_ToDosDateTime( &st.st_mtime, pdate, ptime );
+    *pdate = file->filedate;
+    *ptime = file->filetime;
     return 1;
 }
 
 
 /***********************************************************************
+ *           FILE_SetDateTime
+ *
+ * Set the date and time of a file.
+ */
+int FILE_SetDateTime( HFILE hFile, WORD date, WORD time )
+{
+    DOS_FILE *file;
+    struct tm newtm;
+    struct utimbuf filetime;
+
+    if (!(file = FILE_GetFile( hFile ))) return 0;
+    newtm.tm_sec  = (time & 0x1f) * 2;
+    newtm.tm_min  = (time >> 5) & 0x3f;
+    newtm.tm_hour = (time >> 11);
+    newtm.tm_mday = (date & 0x1f);
+    newtm.tm_mon  = ((date >> 5) & 0x0f) - 1;
+    newtm.tm_year = (date >> 9) + 80;
+
+    filetime.actime = filetime.modtime = mktime( &newtm );
+    if (utime( file->unix_name, &filetime ) != -1) return 1;
+    FILE_SetDosError();
+    return 0;
+}
+
+
+/***********************************************************************
+ *           FILE_Sync
+ */
+int FILE_Sync( HFILE hFile )
+{
+    DOS_FILE *file;
+
+    if (!(file = FILE_GetFile( hFile ))) return 0;
+    if (fsync( file->unix_handle ) != -1) return 1;
+    FILE_SetDosError();
+    return 0;
+}
+
+
+/***********************************************************************
  *           FILE_MakeDir
  */
 int FILE_MakeDir( LPCSTR path )
@@ -461,20 +553,14 @@
  */
 HFILE FILE_Dup( HFILE hFile )
 {
-    int handle, newhandle;
-    HFILE dosHandle;
+    DOS_FILE *file;
+    HFILE handle;
 
-    if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return HFILE_ERROR;
-    dprintf_file( stddeb, "FILE_Dup for handle %d\n",handle);
-    if ((newhandle = dup(handle)) == -1)
-    {
-        FILE_SetDosError();
-        return HFILE_ERROR;
-    }
-    if ((dosHandle = FILE_AllocTaskHandle( newhandle )) == HFILE_ERROR)
-        close( newhandle );
-    dprintf_file( stddeb, "FILE_Dup return handle %d\n",dosHandle);
-    return dosHandle;
+    dprintf_file( stddeb, "FILE_Dup for handle %d\n", hFile );
+    if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
+    if ((handle = FILE_AllocTaskHandle( file )) != HFILE_ERROR) file->count++;
+    dprintf_file( stddeb, "FILE_Dup return handle %d\n", handle );
+    return handle;
 }
 
 
@@ -485,73 +571,138 @@
  */
 HFILE FILE_Dup2( HFILE hFile1, HFILE hFile2 )
 {
+    DOS_FILE *file;
     PDB *pdb = (PDB *)GlobalLock( GetCurrentPDB() );
-    BYTE *files;
-    int handle, newhandle;
+    BYTE *files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
 
-    if ((handle = FILE_GetUnixTaskHandle( hFile1 )) == -1) return HFILE_ERROR;
-    dprintf_file( stddeb, "FILE_Dup2 for handle %d\n",handle);
+    dprintf_file( stddeb, "FILE_Dup2 for handle %d\n", hFile1 );
+    if (!(file = FILE_GetFile( hFile1 ))) return HFILE_ERROR;
+
     if ((hFile2 < 0) || (hFile2 >= (INT)pdb->nbFiles))
     {
         DOS_ERROR( ER_InvalidHandle, EC_ProgramError, SA_Abort, EL_Disk );
         return HFILE_ERROR;
     }
-
-    if ((newhandle = dup(handle)) == -1)
+    if (files[hFile2] < MAX_OPEN_FILES)
     {
-        FILE_SetDosError();
-        return HFILE_ERROR;
+        dprintf_file( stddeb, "FILE_Dup2 closing old handle2 %d\n",
+                      files[hFile2] );
+        FILE_Close( &DOSFiles[files[hFile2]] );
     }
-    if (newhandle >= 0xff)
-    {
-        DOS_ERROR( ER_TooManyOpenFiles, EC_ProgramError, SA_Abort, EL_Disk );
-        close( newhandle );
-        return HFILE_ERROR;
-    }
-    files = PTR_SEG_TO_LIN( pdb->fileHandlesPtr );
-    if (files[hFile2] != 0xff) 
-    {
-        dprintf_file( stddeb, "FILE_Dup2 closing old  handle2 %d\n",
-                      files[hFile2]);
-        close( files[hFile2] );
-    }
-    files[hFile2] = (BYTE)newhandle;
-    dprintf_file( stddeb, "FILE_Dup2 return handle2 %d\n",newhandle);
+    files[hFile2] = (BYTE)(file - DOSFiles);
+    file->count++;
+    dprintf_file( stddeb, "FILE_Dup2 return handle2 %d\n", hFile2 );
     return hFile2;
 }
 
 
 /***********************************************************************
- *           FILE_OpenFile
- *
- * Implementation of API function OpenFile(). Returns a Unix file handle.
+ *           FILE_Read
  */
-int FILE_OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
+LONG FILE_Read( HFILE hFile, void *buffer, LONG count )
 {
+    DOS_FILE *file;
+    LONG result;
+
+    dprintf_file( stddeb, "FILE_Read: %d %p %ld\n", hFile, buffer, count );
+    if (!(file = FILE_GetFile( hFile ))) return -1;
+    if (!count) return 0;
+    if ((result = read( file->unix_handle, buffer, count )) == -1)
+        FILE_SetDosError();
+    return result;
+}
+
+
+/***********************************************************************
+ *           GetTempFileName   (KERNEL.97)
+ */
+INT GetTempFileName( BYTE drive, LPCSTR prefix, UINT unique, LPSTR buffer )
+{
+    int i;
+    UINT num = unique ? (unique & 0xffff) : time(NULL) & 0xffff;
+    char *p;
+
+    if (drive & TF_FORCEDRIVE)
+    {
+        sprintf( buffer, "%c:", drive & ~TF_FORCEDRIVE );
+    }
+    else
+    {
+        DIR_GetTempDosDir( buffer, 132 );  /* buffer must be at least 144 */
+        strcat( buffer, "\\" );
+    }
+
+    p = buffer + strlen(buffer);
+    for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
+    sprintf( p, "%04x.tmp", num );
+
+    if (unique)
+    {
+        lstrcpyn( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
+        dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
+        return unique;
+    }
+
+    /* Now try to create it */
+
+    do
+    {
+        DOS_FILE *file;
+        if ((file = FILE_Create( buffer, 0666, TRUE )) != NULL)
+        {  /* We created it */
+            dprintf_file( stddeb, "GetTempFileName: created %s\n", buffer );
+            FILE_Close( file );
+            break;
+        }
+        if (DOS_ExtendedError != ER_FileExists) break;  /* No need to go on */
+        num++;
+        sprintf( p, "%04x.tmp", num );
+    } while (num != (unique & 0xffff));
+
+    lstrcpyn( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
+    dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
+    return num;
+}
+
+
+/***********************************************************************
+ *           OpenFile   (KERNEL.74)
+ */
+HFILE OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
+{
+    DOS_FILE *file;
+    HFILE hFileRet;
+    WORD filedatetime[2];
     const char *unixName, *dosName;
     char *p;
-    int handle, len, i, unixMode;
-    struct stat st;
+    int len, i, unixMode;
 
     ofs->cBytes = sizeof(OFSTRUCT);
     ofs->nErrCode = 0;
     if (mode & OF_REOPEN) name = ofs->szPathName;
-    dprintf_file( stddeb, "FILE_Openfile: %s %04x\n", name, mode );
+    dprintf_file( stddeb, "OpenFile: %s %04x\n", name, mode );
+
+    /* First allocate a task handle */
+
+    if ((hFileRet = FILE_AllocTaskHandle( NULL )) == HFILE_ERROR)
+    {
+        ofs->nErrCode = DOS_ExtendedError;
+        dprintf_file( stddeb, "OpenFile: no more task handles.\n" );
+        return HFILE_ERROR;
+    }
 
     /* OF_PARSE simply fills the structure */
 
     if (mode & OF_PARSE)
     {
-        if (!(dosName = DOSFS_GetDosTrueName( name, FALSE )))
-        {
-            ofs->nErrCode = DOS_ExtendedError;
-            dprintf_file( stddeb, "FILE_Openfile: %s  return = -1\n", name);
-            return -1;
-        }
+        if (!(dosName = DOSFS_GetDosTrueName( name, FALSE ))) goto error;
         lstrcpyn( ofs->szPathName, dosName, sizeof(ofs->szPathName) );
         ofs->fFixedDisk = (GetDriveType( dosName[0]-'A' ) != DRIVE_REMOVABLE);
-        dprintf_file( stddeb, "FILE_Openfile: %s  return = 0\n", name);
-        return 0;
+        dprintf_file( stddeb, "OpenFile(%s): OF_PARSE, res = '%s', %d\n",
+                      name, ofs->szPathName, hFileRet );
+        /* Return the handle, but close it first */
+        FILE_FreeTaskHandle( hFileRet );
+        return hFileRet;
     }
 
     /* OF_CREATE is completely different from all other options, so
@@ -559,25 +710,10 @@
 
     if (mode & OF_CREATE)
     {
-        if ((unixName = DOSFS_GetUnixFileName( name, FALSE )) == NULL)
-        {
-            ofs->nErrCode = DOS_ExtendedError;
-            dprintf_file( stddeb, "FILE_Openfile: %s  return = -1\n", name);
-            return -1;
-        }
-        dprintf_file( stddeb, "FILE_OpenFile: creating '%s'\n", unixName );
-        handle = open( unixName, O_TRUNC | O_RDWR | O_CREAT, 0666 );
-        if (handle == -1)
-        {
-            FILE_SetDosError();
-            ofs->nErrCode = DOS_ExtendedError;
-            dprintf_file( stddeb, "FILE_Openfile: %s  return = -1\n", name);
-            return -1;
-        }   
+        if (!(file = FILE_Create( name, 0666, FALSE ))) goto error;
         lstrcpyn( ofs->szPathName, DOSFS_GetDosTrueName( name, FALSE ),
                   sizeof(ofs->szPathName) );
-        dprintf_file( stddeb, "FILE_Openfile: %s  return = %d \n", name, handle);
-        return handle;
+        goto success;
     }
 
     /* Now look for the file */
@@ -638,30 +774,25 @@
 
     for (i = 0; ; i++)
     {
-        if (!DIR_GetDosPath( i, ofs->szPathName, len )) break;
+        if (!DIR_GetDosPath( i, ofs->szPathName, len )) goto not_found;
         strcat( ofs->szPathName, "\\" );
         strcat( ofs->szPathName, name );
         if ((unixName = DOSFS_GetUnixFileName( ofs->szPathName, TRUE)) != NULL)
-            goto found;
+            break;
     }
 
-not_found:
-    dprintf_file( stddeb, "FILE_OpenFile: '%s' not found\n", name );
-    DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
-    ofs->nErrCode = ER_FileNotFound;
-    dprintf_file( stddeb, "FILE_Openfile: %s  return =-1\n", name);
-    return -1;
-
 found:
-    dprintf_file( stddeb, "FILE_OpenFile: found '%s'\n", unixName );
+    dprintf_file( stddeb, "OpenFile: found '%s'\n", unixName );
     lstrcpyn( ofs->szPathName, DOSFS_GetDosTrueName( ofs->szPathName, FALSE ),
               sizeof(ofs->szPathName) );
 
     if (mode & OF_DELETE)
     {
         if (unlink( unixName ) == -1) goto not_found;
-        dprintf_file( stddeb, "FILE_Openfile: %s  return = 0\n", name);
-        return 0;
+        dprintf_file( stddeb, "OpenFile(%s): OF_DELETE return = OK\n", name);
+        /* Return the handle, but close it first */
+        FILE_FreeTaskHandle( hFileRet );
+        return hFileRet;
     }
 
     switch(mode & 3)
@@ -675,119 +806,45 @@
         unixMode = O_RDONLY; break;
     }
 
-    if ((handle = FILE_OpenUnixFile( unixName, unixMode )) == -1)
-        goto not_found;
-
-    if (fstat( handle, &st ) != -1)
+    if (!(file = FILE_OpenUnixFile( unixName, unixMode ))) goto not_found;
+    filedatetime[0] = file->filedate;
+    filedatetime[1] = file->filetime;
+    if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
     {
-        if ((mode & OF_VERIFY) && (mode & OF_REOPEN))
+        if (memcmp( ofs->reserved, filedatetime, sizeof(ofs->reserved) ))
         {
-            if (memcmp( ofs->reserved, &st.st_mtime, sizeof(ofs->reserved) ))
-            {
-                dprintf_file( stddeb, "FILE_Openfile: %s  return = -1\n", name);
-                close( handle );
-                return -1;
-            }
+            FILE_Close( file );
+            dprintf_file( stddeb, "OpenFile(%s): OF_VERIFY failed\n", name );
+            /* FIXME: what error here? */
+            DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
+            goto error;
         }
-        memcpy( ofs->reserved, &st.st_mtime, sizeof(ofs->reserved) );
     }
+    memcpy( ofs->reserved, filedatetime, sizeof(ofs->reserved) );
 
     if (mode & OF_EXIST)
     {
-        close( handle );
-        return 0;
-    }
-    dprintf_file( stddeb, "FILE_Openfile: %s  return = %d\n", name,handle);
-
-    return handle;
-}
-
-
-/***********************************************************************
- *           FILE_Read
- */
-LONG FILE_Read( HFILE hFile, LPSTR buffer, LONG count )
-{
-    int handle;
-    LONG result;
-
-    dprintf_file( stddeb, "FILE_Read: %d %p %ld\n", hFile, buffer, count );
-    if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return -1;
-    if (!count) return 0;
-    if ((result = read( handle, buffer, count )) == -1) FILE_SetDosError();
-    return result;
-}
-
-
-/***********************************************************************
- *           GetTempFileName   (KERNEL.97)
- */
-INT GetTempFileName( BYTE drive, LPCSTR prefix, UINT unique, LPSTR buffer )
-{
-    int i, handle;
-    UINT num = unique ? (unique & 0xffff) : time(NULL) & 0xffff;
-    char *p;
-
-    if (drive & TF_FORCEDRIVE)
-    {
-        sprintf( buffer, "%c:", drive & ~TF_FORCEDRIVE );
-    }
-    else
-    {
-        DIR_GetTempDosDir( buffer, 132 );  /* buffer must be at least 144 */
-        strcat( buffer, "\\" );
+        FILE_Close( file );
+        /* Return the handle, but close it first */
+        FILE_FreeTaskHandle( hFileRet );
+        return hFileRet;
     }
 
-    p = buffer + strlen(buffer);
-    for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
-    sprintf( p, "%04x.tmp", num );
+success:  /* We get here if the open was successful */
+    dprintf_file( stddeb, "OpenFile(%s): OK, return = %d\n", name, hFileRet );
+    FILE_SetTaskHandle( hFileRet, file );
+    return hFileRet;
 
-    if (unique)
-    {
-        lstrcpyn( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
-        dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
-        return unique;
-    }
+not_found:  /* We get here if the file does not exist */
+    dprintf_file( stddeb, "OpenFile: '%s' not found\n", name );
+    DOS_ERROR( ER_FileNotFound, EC_NotFound, SA_Abort, EL_Disk );
+    /* fall through */
 
-    /* Now try to create it */
-
-    do
-    {
-        if ((handle = FILE_Create( buffer, 0666, TRUE )) != -1)
-        {  /* We created it */
-            dprintf_file( stddeb, "GetTempFileName: created %s\n", buffer );
-            close( handle );
-            break;
-        }
-        if (DOS_ExtendedError != ER_FileExists) break;  /* No need to go on */
-        num++;
-        sprintf( p, "%04x.tmp", num );
-    } while (num != (unique & 0xffff));
-
-    lstrcpyn( buffer, DOSFS_GetDosTrueName( buffer, FALSE ), 144 );
-    dprintf_file( stddeb, "GetTempFileName: returning %s\n", buffer );
-    return num;
-}
-
-
-/***********************************************************************
- *           OpenFile   (KERNEL.74)
- */
-HFILE OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
-{
-    int unixHandle;
-    HFILE handle;
-
-    dprintf_file( stddeb, "OpenFile %s \n",name);
-    if ((unixHandle = FILE_OpenFile( name, ofs, mode )) == -1)
-        return HFILE_ERROR;
-    if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
-    {
-        ofs->nErrCode = DOS_ExtendedError;
-        if (unixHandle) close( unixHandle );
-    }
-    if (!unixHandle) FILE_FreeTaskHandle( handle );
-    return handle;
+error:  /* We get here if there was an error opening the file */
+    ofs->nErrCode = DOS_ExtendedError;
+    dprintf_file( stddeb, "OpenFile(%s): return = HFILE_ERROR\n", name );
+    FILE_FreeTaskHandle( hFileRet );
+    return HFILE_ERROR;
 }
 
 
@@ -796,18 +853,12 @@
  */
 HFILE _lclose( HFILE hFile )
 {
-    int handle;
+    DOS_FILE *file;
 
-    
-    if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return HFILE_ERROR;
-    dprintf_file( stddeb, "_lclose: doshandle %d unixhandle %d\n", hFile,handle );
-    if (handle <= 2)
-    {
-        fprintf( stderr, "_lclose: internal error: closing handle %d\n", handle );
-        exit(1);
-    }
+    dprintf_file( stddeb, "_lclose: handle %d\n", hFile );
+    if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
+    FILE_Close( file );
     FILE_FreeTaskHandle( hFile );
-    close( handle );
     return 0;
 }
 
@@ -826,15 +877,15 @@
  */
 INT _lcreat( LPCSTR path, INT attr )
 {
-    int unixHandle, mode;
+    DOS_FILE *file;
     HFILE handle;
+    int mode;
     
     dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
     mode = (attr & 1) ? 0444 : 0666;
-    if ((unixHandle = FILE_Create( path, mode, FALSE )) == -1)
-        return HFILE_ERROR;
-    if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
-        close( unixHandle );
+    if (!(file = FILE_Create( path, mode, FALSE ))) return HFILE_ERROR;
+    if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
+        FILE_Close( file );
     return handle;
 }
 
@@ -844,15 +895,15 @@
  */
 INT _lcreat_uniq( LPCSTR path, INT attr )
 {
-    int unixHandle, mode;
+    DOS_FILE *file;
     HFILE handle;
+    int mode;
     
     dprintf_file( stddeb, "_lcreat: %s %02x\n", path, attr );
     mode = (attr & 1) ? 0444 : 0666;
-    if ((unixHandle = FILE_Create( path, mode, TRUE )) == -1)
-        return HFILE_ERROR;
-    if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
-        close( unixHandle );
+    if (!(file = FILE_Create( path, mode, TRUE ))) return HFILE_ERROR;
+    if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
+        FILE_Close( file );
     return handle;
 }
 
@@ -862,12 +913,13 @@
  */
 LONG _llseek( HFILE hFile, LONG lOffset, INT nOrigin )
 {
-    int handle, origin, result;
+    DOS_FILE *file;
+    int origin, result;
 
     dprintf_file( stddeb, "_llseek: handle %d, offset %ld, origin %d\n", 
                   hFile, lOffset, nOrigin);
 
-    if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return HFILE_ERROR;
+    if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
     switch(nOrigin)
     {
         case 1:  origin = SEEK_CUR; break;
@@ -875,8 +927,9 @@
         default: origin = SEEK_SET; break;
     }
 
-    if ((result = lseek( handle, lOffset, origin )) == -1) FILE_SetDosError();
-    return (result == -1) ? HFILE_ERROR : result;
+    if ((result = lseek( file->unix_handle, lOffset, origin )) == -1)
+        FILE_SetDosError();
+    return result;
 }
 
 
@@ -885,7 +938,7 @@
  */
 HFILE _lopen( LPCSTR path, INT mode )
 {
-    int unixHandle;
+    DOS_FILE *file;
     int unixMode;
     HFILE handle;
 
@@ -904,9 +957,9 @@
         unixMode = O_RDONLY;
         break;
     }
-    if ((unixHandle = FILE_Open( path, unixMode )) == -1) return HFILE_ERROR;
-    if ((handle = FILE_AllocTaskHandle( unixHandle )) == HFILE_ERROR)
-        close( unixHandle );
+    if (!(file = FILE_Open( path, unixMode ))) return HFILE_ERROR;
+    if ((handle = FILE_AllocTaskHandle( file )) == HFILE_ERROR)
+        FILE_Close( file );
     return handle;
 }
 
@@ -944,20 +997,21 @@
  */
 LONG _hwrite( HFILE hFile, LPCSTR buffer, LONG count )
 {
-    int handle;
+    DOS_FILE *file;
     LONG result;
 
     dprintf_file( stddeb, "_hwrite: %d %p %ld\n", hFile, buffer, count );
 
-    if ((handle = FILE_GetUnixTaskHandle( hFile )) == -1) return HFILE_ERROR;
+    if (!(file = FILE_GetFile( hFile ))) return HFILE_ERROR;
     
     if (count == 0)  /* Expand or truncate at current position */
-        result = ftruncate( handle, lseek( handle, 0, SEEK_CUR ) );
+        result = ftruncate( file->unix_handle,
+                            lseek( file->unix_handle, 0, SEEK_CUR ) );
     else
-        result = write( handle, buffer, count );
+        result = write( file->unix_handle, buffer, count );
 
     if (result == -1) FILE_SetDosError();
-    return (result == -1) ? HFILE_ERROR : result;
+    return result;
 }
 
 
diff --git a/if1632/Makefile.in b/if1632/Makefile.in
index 1db5b31..7e94b98 100644
--- a/if1632/Makefile.in
+++ b/if1632/Makefile.in
@@ -2,11 +2,33 @@
 
 MODULE = if1632
 
-DLLS16	= commdlg.spec compobj.spec ddeml.spec gdi.spec kernel.spec \
-	keyboard.spec mmsystem.spec mouse.spec ole2.spec ole2conv.spec \
-	ole2disp.spec ole2nls.spec ole2prox.spec olecli.spec olesvr.spec \
-	shell.spec sound.spec storage.spec stress.spec system.spec \
-	toolhelp.spec user.spec win87em.spec winprocs.spec winsock.spec
+DLLS16	= \
+	commdlg.spec \
+	compobj.spec \
+	ddeml.spec \
+	gdi.spec \
+	kernel.spec \
+	keyboard.spec \
+	lzexpand.spec \
+	mmsystem.spec \
+	mouse.spec \
+	ole2.spec \
+	ole2conv.spec \
+	ole2disp.spec \
+	ole2nls.spec \
+	ole2prox.spec \
+	olecli.spec \
+	olesvr.spec \
+	shell.spec \
+	sound.spec \
+	storage.spec \
+	stress.spec \
+	system.spec \
+	toolhelp.spec \
+	user.spec \
+	win87em.spec \
+	winprocs.spec \
+	winsock.spec
 
 DLLS32	= advapi32.spec comctl32.spec comdlg32.spec gdi32.spec kernel32.spec \
 	ole32.spec shell32.spec user32.spec winprocs32.spec winspool.spec
diff --git a/if1632/callback.c b/if1632/callback.c
index 346289e..7d22b17 100644
--- a/if1632/callback.c
+++ b/if1632/callback.c
@@ -38,7 +38,7 @@
     if(!a->win32)
         fprintf(stderr,"Where is the Win32 callback?\n");
     if (UsesLParamPtr(message))
-	return RELAY32_CallWindowProc(a->win32,hwnd,message,wParam,lParam ? PTR_SEG_TO_LIN(lParam): 0);
+	return RELAY32_CallWindowProcConvStruct(a->win32,hwnd,message,wParam,lParam);
     else
 	return RELAY32_CallWindowProc(a->win32,hwnd,message,wParam,lParam);
 }
diff --git a/if1632/lzexpand.spec b/if1632/lzexpand.spec
new file mode 100644
index 0000000..9f2e38d
--- /dev/null
+++ b/if1632/lzexpand.spec
@@ -0,0 +1,15 @@
+name	lzexpand
+id	26
+
+1  pascal   LZCopy(word word) LZCopy
+2  pascal16 LZOpenFile(ptr ptr word) LZOpenFile
+3  pascal16 LZInit(word) LZInit
+4  pascal   LZSeek(word long word) LZSeek
+5  pascal16 LZRead(word segptr word) LZRead
+6  pascal16 LZClose(word) LZClose
+7  pascal16 LZStart() LZStart
+8  pascal   CopyLZFile(word word) CopyLZFile
+9  pascal16 LZDone() LZDone
+10 pascal16 GetExpandedName(ptr ptr) GetExpandedName
+#11 WEP
+#12 ___EXPORTEDSTUB 
diff --git a/if1632/relay.c b/if1632/relay.c
index b5f1a2b..b0f3d9b 100644
--- a/if1632/relay.c
+++ b/if1632/relay.c
@@ -52,7 +52,8 @@
     DLL_ENTRY_NOTUSED(COMPOBJ),
     DLL_ENTRY_NOTUSED(STORAGE),
     DLL_ENTRY(WINPROCS),
-    DLL_ENTRY_NOTUSED(DDEML)
+    DLL_ENTRY_NOTUSED(DDEML),
+    DLL_ENTRY(LZEXPAND)
 };
 
 /* don't forget to increase N_BUILTINS in dlls.h if you add a dll */
diff --git a/if1632/relay32.c b/if1632/relay32.c
index a104958..4ec1104 100644
--- a/if1632/relay32.c
+++ b/if1632/relay32.c
@@ -17,7 +17,10 @@
 #include "pe_image.h"
 #include "peexe.h"
 #include "relay32.h"
+#include "struct32.h"
+#include "stackframe.h"
 #include "xmalloc.h"
+#include "ldt.h"
 #include "stddebug.h"
 #include "debug.h"
 
@@ -124,7 +127,7 @@
              int wParam, int lParam )
 {
 	int ret;
-__asm__ (
+	__asm__ (
 		"push %1;"
 		"push %2;"
 		"push %3;"
@@ -136,6 +139,68 @@
 	return ret;
 }
 
+LONG RELAY32_CallWindowProcConvStruct( WNDPROC func, int hwnd, int message,
+	int wParam, LPARAM lParam16)
+{
+	WINDOWPOS32 wp;
+	union {
+		MINMAXINFO32 mmi;
+		NCCALCSIZE_PARAMS32 nccs;
+		CREATESTRUCT32 cs;
+	} st;
+	CREATESTRUCT *lpcs;
+	LONG result;
+	void *lParam;
+	if(!lParam16)
+		return RELAY32_CallWindowProc(func,hwnd,message,wParam,(int)lParam16);
+	lParam = PTR_SEG_TO_LIN(lParam16);
+	switch(message) {
+		case WM_GETMINMAXINFO:
+			STRUCT32_MINMAXINFO16to32(lParam,&st.mmi);
+			result=RELAY32_CallWindowProc(func,hwnd,message,wParam,(int)&st.mmi);
+			STRUCT32_MINMAXINFO32to16(&st.mmi,lParam);
+			return result;
+		case WM_WINDOWPOSCHANGING:
+		case WM_WINDOWPOSCHANGED:
+			STRUCT32_WINDOWPOS16to32(lParam,&wp);
+			result=RELAY32_CallWindowProc(func,hwnd,message,wParam,(int)&wp);
+			STRUCT32_WINDOWPOS32to16(&wp,lParam);
+			return result;
+		case WM_NCCALCSIZE:
+			STRUCT32_NCCALCSIZE16to32Flat(lParam,&st.nccs);
+			if(((NCCALCSIZE_PARAMS*)lParam)->lppos) {
+				STRUCT32_WINDOWPOS16to32(((NCCALCSIZE_PARAMS*)lParam)->lppos,&wp);
+				st.nccs.lppos=&wp;
+			} else
+				st.nccs.lppos= 0;
+			result=RELAY32_CallWindowProc(func,hwnd,message,wParam,(int)&st.nccs);
+			STRUCT32_NCCALCSIZE32to16Flat(&st.nccs,lParam);
+			if(((NCCALCSIZE_PARAMS*)lParam)->lppos)
+				STRUCT32_WINDOWPOS32to16(&wp,((NCCALCSIZE_PARAMS*)lParam)->lppos);
+			return result;
+		case WM_NCCREATE:
+			lpcs = (CREATESTRUCT*)lParam;
+			STRUCT32_CREATESTRUCT16to32(lParam,&st.cs);
+			st.cs.lpszName = HIWORD(lpcs->lpszName) ? 
+				PTR_SEG_TO_LIN(lpcs->lpszName) : (char*)lpcs->lpszName;
+			st.cs.lpszClass = HIWORD(lpcs->lpszClass) ? 
+				PTR_SEG_TO_LIN(lpcs->lpszClass) : (char*)lpcs->lpszClass;
+			result=RELAY32_CallWindowProc(func,hwnd,message,wParam,(int)&st.cs);
+			STRUCT32_CREATESTRUCT32to16(&st.cs,lParam);
+			lpcs->lpszName = HIWORD(st.cs.lpszName) ? 
+				MAKE_SEGPTR(st.cs.lpszName) : (SEGPTR)st.cs.lpszName;
+			lpcs->lpszClass = HIWORD(st.cs.lpszClass) ? 
+				MAKE_SEGPTR(st.cs.lpszClass) : (SEGPTR)st.cs.lpszClass;
+			return result;
+		case WM_GETTEXT:
+		case WM_SETTEXT:
+			return RELAY32_CallWindowProc(func,hwnd,message,wParam,(int)lParam);
+		default:
+			fprintf(stderr,"No conversion function for message %d\n",message);
+	}
+	return RELAY32_CallWindowProc(func,hwnd,message,wParam,(int)lParam);
+}
+
 void RELAY32_MakeFakeModule(WIN32_builtin*dll)
 {
 	NE_MODULE *pModule;
diff --git a/include/debugger.h b/include/debugger.h
index 42b4206..8cc7c48 100644
--- a/include/debugger.h
+++ b/include/debugger.h
@@ -89,6 +89,10 @@
 extern void DEBUG_PrintAddress( const DBG_ADDR *addr, int addrlen );
 extern void DEBUG_Help(void);
 extern void DEBUG_List( DBG_ADDR *addr, int count );
+extern void DEBUG_InitWalk(void);
+extern void DEBUG_WndWalk( HWND );
+extern void DEBUG_WndDump( HWND );
+extern void DEBUG_QueueDump( HQUEUE );
 
   /* debugger/memory.c */
 extern BOOL DEBUG_IsBadReadPtr( const DBG_ADDR *address, int size );
diff --git a/include/dlls.h b/include/dlls.h
index 89c434a..00b5980 100644
--- a/include/dlls.h
+++ b/include/dlls.h
@@ -54,8 +54,9 @@
 DECLARE_DLL(STORAGE)
 DECLARE_DLL(WINPROCS)
 DECLARE_DLL(DDEML)
+DECLARE_DLL(LZEXPAND)
 
-#define N_BUILTINS	25
+#define N_BUILTINS	26
 
 extern struct dll_table_s dll_builtin_table[];
 
diff --git a/include/dos_fs.h b/include/dos_fs.h
index 2bcca39..8a2631e 100644
--- a/include/dos_fs.h
+++ b/include/dos_fs.h
@@ -25,7 +25,7 @@
 
 #define IS_END_OF_NAME(ch)  (!(ch) || ((ch) == '/') || ((ch) == '\\'))
 
-extern void DOSFS_ToDosDateTime( time_t *unixtime, WORD *pDate, WORD *pTime );
+extern void DOSFS_ToDosDateTime( time_t unixtime, WORD *pDate, WORD *pTime );
 extern const char *DOSFS_ToDosFCBFormat( const char *name );
 extern const char *DOSFS_ToDosDTAFormat( const char *name );
 extern const char *DOSFS_IsDevice( const char *name );
diff --git a/include/file.h b/include/file.h
index 9a4e0e4..7893a96 100644
--- a/include/file.h
+++ b/include/file.h
@@ -10,21 +10,21 @@
 #include "windows.h"
 
 extern void FILE_SetDosError(void);
-extern int FILE_GetUnixTaskHandle( HFILE handle );
 extern void FILE_CloseAllFiles( HANDLE hPDB );
-extern int FILE_Open( LPCSTR path, int mode );
-extern int FILE_Create( LPCSTR path, int mode, int unique );
 extern int FILE_Stat( LPCSTR unixName, BYTE *pattr, DWORD *psize,
                       WORD *pdate, WORD *ptime );
+extern int FILE_GetDateTime( HFILE hFile, WORD *pdate, WORD *ptime,
+                             BOOL refresh );
+extern int FILE_SetDateTime( HFILE hFile, WORD date, WORD time );
 extern int FILE_Fstat( HFILE hFile, BYTE *pattr, DWORD *psize,
                        WORD *pdate, WORD *ptime );
+extern int FILE_Sync( HFILE hFile );
 extern int FILE_Unlink( LPCSTR path );
 extern int FILE_MakeDir( LPCSTR path );
 extern int FILE_RemoveDir( LPCSTR path );
 extern HFILE FILE_Dup( HFILE hFile );
 extern HFILE FILE_Dup2( HFILE hFile1, HFILE hFile2 );
-extern int FILE_OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode );
-extern LONG FILE_Read( HFILE hFile, LPSTR buffer, LONG count );
+extern LONG FILE_Read( HFILE hFile, void *buffer, LONG count );
 extern INT _lcreat_uniq( LPCSTR path, INT attr );
 
 #endif  /* __WINE_FILE_H */
diff --git a/include/lzexpand.h b/include/lzexpand.h
new file mode 100644
index 0000000..bf58839
--- /dev/null
+++ b/include/lzexpand.h
@@ -0,0 +1,25 @@
+/* Includefile for the decompression library, lzexpand
+ *
+ * Copyright 1996 Marcus Meissner
+ */
+
+LONG	LZCopy(HFILE,HFILE);
+HFILE	LZOpenFile(LPCSTR,LPOFSTRUCT,UINT);
+HFILE	LZInit(HFILE);
+LONG	LZSeek(HFILE,LONG,INT);
+INT	LZRead(HFILE,SEGPTR,WORD); 
+void	LZClose(HFILE);
+INT	LZStart(void);
+LONG	CopyLZFile(HFILE,HFILE);
+void	LZDone(void);
+INT	GetExpandedName(LPCSTR,LPSTR);
+
+
+#define LZERROR_BADINHANDLE	0xFFFF	/* -1 */
+#define LZERROR_BADOUTHANDLE	0xFFFE	/* -2 */
+#define LZERROR_READ		0xFFFD	/* -3 */
+#define LZERROR_WRITE		0xFFFC	/* -4 */
+#define LZERROR_GLOBALLOC	0xFFFB	/* -5 */
+#define LZERROR_GLOBLOCK	0xFFFA	/* -6 */
+#define LZERROR_BADVALUE	0xFFF9	/* -7 */
+#define LZERROR_UNKNOWNALG	0xFFF8	/* -8 */
diff --git a/include/relay32.h b/include/relay32.h
index 0fd7680..c0cf499 100644
--- a/include/relay32.h
+++ b/include/relay32.h
@@ -7,6 +7,7 @@
 #ifndef _RELAY32_H
 #define _RELAY32_H
 #include "pe_image.h"
+#include "struct32.h"
 
 void RELAY32_Unimplemented(char *dll, int item);
 WIN32_builtin *RELAY32_GetBuiltinDLL(char *name);
@@ -27,41 +28,10 @@
 	char*	lpszClassName;
 }WNDCLASSA;
 
-struct WIN32_POINT{
-	LONG x;
-	LONG y;
-};
-
-struct WIN32_MSG{
-	DWORD hwnd;
-	DWORD message;
-	DWORD wParam;
-	DWORD lParam;
-	DWORD time;
-	struct WIN32_POINT pt;
-};
-
-struct WIN32_RECT{
-	LONG left;
-	LONG top;
-	LONG right;
-	LONG bottom;
-};
-
-struct WIN32_PAINTSTRUCT{
-	DWORD hdc;
-	DWORD fErase;
-	struct WIN32_RECT rcPaint;
-	DWORD fRestore;
-	DWORD fIncUpdate;
-	BYTE rgbReserved[32];
-};
-
-
 ATOM USER32_RegisterClassA(WNDCLASSA *);
 LRESULT USER32_DefWindowProcA(DWORD hwnd,DWORD msg,DWORD wParam,DWORD lParam);
-BOOL USER32_GetMessageA(struct WIN32_MSG* lpmsg,DWORD hwnd,DWORD min,DWORD max);
-HDC USER32_BeginPaint(DWORD hwnd,struct WIN32_PAINTSTRUCT *lpps);
-BOOL USER32_EndPaint(DWORD hwnd,struct WIN32_PAINTSTRUCT *lpps);
+BOOL USER32_GetMessageA(MSG32* lpmsg,DWORD hwnd,DWORD min,DWORD max);
+HDC USER32_BeginPaint(DWORD hwnd,PAINTSTRUCT32 *lpps);
+BOOL USER32_EndPaint(DWORD hwnd,PAINTSTRUCT32 *lpps);
 #endif
 
diff --git a/include/spy.h b/include/spy.h
index 7fa75fb..d4d9c65 100644
--- a/include/spy.h
+++ b/include/spy.h
@@ -12,6 +12,9 @@
 #define SPY_RESULT_OK           0x0000
 #define SPY_RESULT_INVALIDHWND  0x0001
 
+#define SPY_MAX_MSGNUM          WM_USER
+#define SPY_MAX_INDENTLEVEL     64
+
 extern void EnterSpyMessage( int, HWND, WORD, WORD, LONG);
 extern void  ExitSpyMessage( int, HWND, WORD, LONG);
 extern void         SpyInit( void);
diff --git a/include/struct32.h b/include/struct32.h
index 37c1fd0..1e1de48 100644
--- a/include/struct32.h
+++ b/include/struct32.h
@@ -1,6 +1,7 @@
 /* Structure definitions for Win32 -- used only internally */
 #ifndef _STRUCT32_H
 #define _STRUCT32_H
+#include "handle32.h"
 
 typedef struct tagRECT32
 {
@@ -10,8 +11,8 @@
 	LONG bottom;
 } RECT32;
 
-void USER32_RECT32to16(const RECT32*,RECT*);
-void USER32_RECT16to32(const RECT*,RECT32*);
+void STRUCT32_RECT32to16(const RECT32*,RECT*);
+void STRUCT32_RECT16to32(const RECT*,RECT32*);
 
 typedef struct tagPOINT32
 {
@@ -25,9 +26,21 @@
         LONG cy;
 } SIZE32;
   
-void PARAM32_POINT32to16(const POINT32*,POINT*);
-void PARAM32_POINT16to32(const POINT*,POINT32*);
-void PARAM32_SIZE16to32(const SIZE* p16, SIZE32* p32);
+void STRUCT32_POINT32to16(const POINT32*,POINT*);
+void STRUCT32_POINT16to32(const POINT*,POINT32*);
+void STRUCT32_SIZE16to32(const SIZE* p16, SIZE32* p32);
+
+typedef struct tagMINMAXINFO32
+{
+	POINT32 ptReserved;
+	POINT32 ptMaxSize;
+	POINT32 ptMaxPosition;
+	POINT32 ptMinTrackSize;
+	POINT32 ptMaxTrackSize;
+} MINMAXINFO32;
+
+void STRUCT32_MINMAXINFO32to16(const MINMAXINFO32*,MINMAXINFO*);
+void STRUCT32_MINMAXINFO16to32(const MINMAXINFO*,MINMAXINFO32*);
 
 typedef struct {
 	DWORD style;
@@ -51,4 +64,72 @@
 
 #define CW_USEDEFAULT32	0x80000000
 
+typedef struct tagMSG32
+{
+	DWORD hwnd;
+	DWORD message;
+	DWORD wParam;
+	DWORD lParam;
+	DWORD time;
+	POINT32 pt;
+} MSG32;
+
+void STRUCT32_MSG16to32(MSG *msg16,MSG32 *msg32);
+void STRUCT32_MSG32to16(MSG32 *msg32,MSG *msg16);
+
+typedef struct tagPAINTSTRUCT32
+{
+	DWORD hdc;
+	DWORD fErase;
+	RECT32 rcPaint;
+	DWORD fRestore;
+	DWORD fIncUpdate;
+	BYTE rgbReserved[32];
+} PAINTSTRUCT32;
+
+typedef struct tagWINDOWPOS32
+{
+	DWORD	hwnd;
+	DWORD	hwndInsertAfter;
+	LONG	x;
+	LONG	y;
+	LONG	cx;
+	LONG	cy;
+	DWORD	flags;
+} WINDOWPOS32;
+
+void STRUCT32_WINDOWPOS32to16(const WINDOWPOS32*,WINDOWPOS*);
+void STRUCT32_WINDOWPOS16to32(const WINDOWPOS*,WINDOWPOS32*);
+
+typedef struct tagNCCALCSIZE_PARAMS32
+{
+	RECT32	rgrc[3];
+	WINDOWPOS32	*lppos;
+} NCCALCSIZE_PARAMS32;
+
+void STRUCT32_NCCALCSIZE32to16Flat(const NCCALCSIZE_PARAMS32*,
+	NCCALCSIZE_PARAMS*);
+void STRUCT32_NCCALCSIZE16to32Flat(const NCCALCSIZE_PARAMS* from,
+	NCCALCSIZE_PARAMS32* to);
+
+typedef struct tagCREATESTRUCT32
+{
+	DWORD	lpCreateParams;
+	DWORD	hInstance;
+	DWORD	hMenu;
+	DWORD	hwndParent;
+	LONG	cy;
+	LONG	cx;
+	LONG	y;
+	LONG	x;
+	LONG	style;
+	LPSTR	lpszName;
+	LPSTR	lpszClass;
+	DWORD	dwExStyle;
+} CREATESTRUCT32;
+typedef CREATESTRUCT32	CREATESTRUCTA;
+
+void STRUCT32_CREATESTRUCT32to16(const CREATESTRUCT32*,CREATESTRUCT*);
+void STRUCT32_CREATESTRUCT16to32(const CREATESTRUCT*,CREATESTRUCT32*);
+
 #endif
diff --git a/include/windows.h b/include/windows.h
index 3d7c7b0..3fd0086 100644
--- a/include/windows.h
+++ b/include/windows.h
@@ -2553,6 +2553,32 @@
         WORD wMilliseconds;
 } SYSTEMTIME, *LPSYSTEMTIME;
 
+/* WinHelp internal structure */
+typedef struct {
+	WORD size;
+	WORD command;
+	LONG data;
+	LONG reserved;
+	WORD ofsFilename;
+	WORD ofsData;
+} WINHELP,*LPWINHELP;
+
+typedef struct {
+	UINT mkSize;
+	BYTE mkKeyList;
+	BYTE szKeyPhrase[1];
+} MULTIKEYHELP, *LPMULTIKEYHELP;
+
+typedef struct {
+	WORD wStructSize;
+	WORD x;
+	WORD y;
+	WORD dx;
+	WORD dy;
+	WORD wMax;
+	char rgchMember[2];
+} HELPWININFO, *LPHELPWININFO;
+
 #define HELP_CONTEXT        0x0001
 #define HELP_QUIT           0x0002
 #define HELP_INDEX          0x0003
diff --git a/include/wintypes.h b/include/wintypes.h
index 3884f3b..01df224 100644
--- a/include/wintypes.h
+++ b/include/wintypes.h
@@ -143,6 +143,7 @@
 #define _near
 #define PASCAL
 #define _pascal
+#define __export
 #define VOID                void
 #define WINAPI              PASCAL
 #define CALLBACK            PASCAL
diff --git a/library/README.libres b/library/README.libres
deleted file mode 100644
index 880272f..0000000
--- a/library/README.libres
+++ /dev/null
@@ -1,37 +0,0 @@
-                        WINElib resources: a proposal
-
-One of the current issues with WINElib is the inadequate support for accessing
-resources by name.  I propose the following technique (which I have already
-begun to implement) to allow this:
-
-   An internal table of resource entries is provided along with a registering
-   function for adding a resource to this table.  'winerc' should construct
-   *.c files much the same way as it does now with the inclusion of a single
-   static 'constructor' function that registers the associated resources with
-   the internal mechanism like so:
-
-      static void DoIt() __attribute__ ((constructor));
-      static void DoIt()
-      {
-        LIBRES_RegisterResource(hello3_MENU_MAIN__bytes,
-                                sizeof(hello3_MENU_MAIN__bytes),
-                                "MAIN",
-                                RT_MENU);
-        LIBRES_RegisterResource(hello3_DIALOG_DIADEMO__bytes,
-                                sizeof(hello3_DIALOG_DIADEMO__bytes),
-                                "DIADEMO",
-                                RT_DIALOG);
-           ... etc. ...
-      }
-
-   The internal table can then be searched for the resource by name.
-
-The only potential drawback I've determined so far is this technique's
-reliance on gcc's 'constructor' attribute, which disallows compilation with
-some other compiler.  However, I'm guessing that WINE is already heavily
-dependent on gcc, so this is probably not too much of a factor.
-
-Any comments/suggestions/criticisms will be greatly appreciated.
-
-Thank you,
---Jim
diff --git a/loader/module.c b/loader/module.c
index f9dd6fe..a18f1da 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -411,7 +411,7 @@
 /***********************************************************************
  *           MODULE_LoadExeHeader
  */
-HMODULE MODULE_LoadExeHeader( int fd, OFSTRUCT *ofs )
+HMODULE MODULE_LoadExeHeader( HFILE hFile, OFSTRUCT *ofs )
 {
     struct mz_header_s mz_header;
     struct ne_header_s ne_header;
@@ -427,15 +427,15 @@
        ((fastload && ((offset) >= fastload_offset) && \
          ((offset)+(size) <= fastload_offset+fastload_length)) ? \
         (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
-        (lseek( fd, mz_header.ne_offset+(offset), SEEK_SET), \
-         read( fd, (buffer), (size) ) == (size)))
+        (_llseek( hFile, mz_header.ne_offset+(offset), SEEK_SET), \
+         FILE_Read( hFile, (buffer), (size) ) == (size)))
 
-    lseek( fd, 0, SEEK_SET );
-    if ((read( fd, &mz_header, sizeof(mz_header) ) != sizeof(mz_header)) ||
+    _llseek( hFile, 0, SEEK_SET );
+    if ((FILE_Read(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
         (mz_header.mz_magic != MZ_SIGNATURE)) return (HMODULE)11;  /* invalid exe */
 
-    lseek( fd, mz_header.ne_offset, SEEK_SET );
-    if (read( fd, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
+    _llseek( hFile, mz_header.ne_offset, SEEK_SET );
+    if (FILE_Read( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
         return (HMODULE)11;  /* invalid exe */
 
     if (ne_header.ne_magic == PE_SIGNATURE) return (HMODULE)21;  /* win32 exe */
@@ -477,8 +477,8 @@
                         fastload_offset, fastload_length );
         if ((fastload = (char *)malloc( fastload_length )) != NULL)
         {
-            lseek( fd, mz_header.ne_offset + fastload_offset, SEEK_SET );
-            if (read( fd, fastload, fastload_length ) != fastload_length)
+            _llseek( hFile, mz_header.ne_offset + fastload_offset, SEEK_SET );
+            if (FILE_Read( hFile, fastload, fastload_length ) != fastload_length)
             {
                 free( fastload );
                 fastload = NULL;
@@ -572,8 +572,8 @@
                                                hModule, FALSE, FALSE, FALSE );
         if (!pModule->nrname_handle) return (HMODULE)11;  /* invalid exe */
         buffer = GlobalLock( pModule->nrname_handle );
-        lseek( fd, ne_header.nrname_tab_offset, SEEK_SET );
-        if (read( fd, buffer, ne_header.nrname_tab_length )
+        _llseek( hFile, ne_header.nrname_tab_offset, SEEK_SET );
+        if (FILE_Read( hFile, buffer, ne_header.nrname_tab_length )
               != ne_header.nrname_tab_length) return (HMODULE)11;  /* invalid exe */
     }
     else pModule->nrname_handle = 0;
@@ -925,7 +925,8 @@
     LOADPARAMS *params = (LOADPARAMS *)paramBlock;
 #ifndef WINELIB
     WORD *pModRef, *pDLLs;
-    int i, fd;
+    HFILE hFile;
+    int i;
 
     hModule = MODULE_FindModule( name );
 
@@ -936,7 +937,7 @@
         /* Try to load the built-in first if not disabled */
         if ((hModule = MODULE_LoadBuiltin( name, FALSE ))) return hModule;
 
-        if ((fd = FILE_OpenFile( name, &ofs, OF_READ )) == -1)
+        if ((hFile = OpenFile( name, &ofs, OF_READ )) == HFILE_ERROR)
         {
             /* Now try the built-in even if disabled */
             if ((hModule = MODULE_LoadBuiltin( name, TRUE )))
@@ -949,17 +950,20 @@
 
           /* Create the module structure */
 
-        hModule = MODULE_LoadExeHeader( fd, &ofs );
+        hModule = MODULE_LoadExeHeader( hFile, &ofs );
         if (hModule < 32)
         {
+            /* FIXME: Hack because PE_LoadModule is recursive */
+            int fd = dup( FILE_GetUnixHandle(hFile) );
+            _lclose( hFile );
             if (hModule == 21) hModule = PE_LoadModule( fd, &ofs, paramBlock );
-            close(fd);
+            close( fd );
             if (hModule < 32)
                 fprintf( stderr, "LoadModule: can't load '%s', error=%d\n",
                          name, hModule );
             return hModule;
         }
-        close( fd );
+        _lclose( hFile );
         pModule = (NE_MODULE *)GlobalLock( hModule );
 
           /* Allocate the segments for this module */
@@ -1017,6 +1021,7 @@
 
 	if (pModule->flags & NE_FFLAGS_SELFLOAD)
 	{
+                int fd;
 		/* Handle self loading modules */
 		SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
 		SELFLOADHEADER *selfloadheader;
@@ -1069,6 +1074,8 @@
 		  IF1632_Stack32_base = WIN16_GlobalLock(hInitialStack32);
 
 		}
+                /* FIXME: we probably need a DOS handle here */
+                fd = MODULE_OpenFile( hModule );
 		CallTo16_word_ww (selfloadheader->BootApp,
 			pModule->self_loading_sel, hModule, fd);
 		/* some BootApp procs overwrite the selector of dgroup */
diff --git a/loader/ne_image.c b/loader/ne_image.c
index da9675d..a2785c6 100644
--- a/loader/ne_image.c
+++ b/loader/ne_image.c
@@ -74,6 +74,7 @@
  	oldselector = pSeg->selector;
  	IF1632_Saved16_ss = pModule->self_loading_sel;
  	IF1632_Saved16_sp = 0xFF00;
+        /* FIXME: we probably need to pass a DOS file handle here */
  	newselector =  CallTo16_word_www(selfloadheader->LoadAppSeg,
  		pModule->self_loading_sel, hModule, fd, segnum);
  	if (newselector != oldselector) {
diff --git a/misc/Makefile.in b/misc/Makefile.in
index b9939f3..4196c1c 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -11,6 +11,7 @@
 	escape.c \
 	keyboard.c \
 	lstr.c \
+	lzexpand.c \
 	main.c \
 	network.c \
 	ole2.c \
diff --git a/misc/exec.c b/misc/exec.c
index 6def5ad..fc0131b 100644
--- a/misc/exec.c
+++ b/misc/exec.c
@@ -116,27 +116,75 @@
  */
 BOOL WinHelp(HWND hWnd, LPSTR lpHelpFile, WORD wCommand, DWORD dwData)
 {
-	char	str[256];
-    	dprintf_exec(stddeb,"WinHelp(%s, %u, %lu)\n", 
-		lpHelpFile, wCommand, dwData);
-	switch(wCommand) {
-	case 0:
-	case HELP_HELPONHELP:
-		GetWindowsDirectory(str, sizeof(str));
-		strcat(str, "\\winhelp.exe winhelp.hlp");
-        dprintf_exec(stddeb,"'%s'\n", str);
-		break;
-	case HELP_INDEX:
-		GetWindowsDirectory(str, sizeof(str));
-		strcat(str, "\\winhelp.exe ");
-		strcat(str, lpHelpFile);
-        dprintf_exec(stddeb,"'%s'\n", str);
-		break;
-        case HELP_QUIT:
-            return TRUE;
-	default:
+	static WORD WM_WINHELP=0;
+	HWND hDest;
+	char szBuf[20];
+	LPWINHELP lpwh;
+	HANDLE hwh;
+	void *data=0;
+	int size,dsize,nlen;
+        if (wCommand != HELP_QUIT)  /* FIXME */
+            if(WinExec("winhelp.exe -x",SW_SHOWNORMAL)<=32)
 		return FALSE;
+	/* FIXME: Should be directed yield, to let winhelp open the window */
+	Yield();
+	if(!WM_WINHELP) {
+		strcpy(szBuf,"WM_WINHELP");
+		WM_WINHELP=RegisterWindowMessage(MAKE_SEGPTR(szBuf));
+		if(!WM_WINHELP)
+			return FALSE;
 	}
-	WinExec(str, SW_SHOWNORMAL);
-	return(TRUE);
+	strcpy(szBuf,"MS_WINHELP");
+	hDest = FindWindow(MAKE_SEGPTR(szBuf),0);
+	if(!hDest)
+		return FALSE;
+	switch(wCommand)
+	{
+		case HELP_CONTEXT:
+		case HELP_CONTENTS:
+		case HELP_SETCONTENTS:
+		case HELP_CONTEXTPOPUP:
+		case HELP_FORCEFILE:
+		case HELP_HELPONHELP:
+		case HELP_QUIT:
+			dsize=0;
+			break;
+		case HELP_KEY:
+		case HELP_PARTIALKEY:
+		case HELP_COMMAND:
+			data = PTR_SEG_TO_LIN(dwData);
+			dsize = strlen(data)+1;
+			break;
+		case HELP_MULTIKEY:
+			data = PTR_SEG_TO_LIN(dwData);
+			dsize = ((LPMULTIKEYHELP)data) -> mkSize;
+			break;
+		case HELP_SETWINPOS:
+			data = PTR_SEG_TO_LIN(dwData);
+			dsize = ((LPHELPWININFO)data) -> wStructSize;
+			break;
+		default:
+			fprintf(stderr,"Unknown help command %d\n",wCommand);
+			return FALSE;
+	}
+	if(lpHelpFile)
+		nlen =  strlen(lpHelpFile)+1;
+	else
+		nlen = 0;
+	size = sizeof(WINHELP) + nlen + dsize;
+	hwh = GlobalAlloc(0,size);
+	lpwh = GlobalLock(hwh);
+	lpwh->size = size;
+	lpwh->command = wCommand;
+	if(nlen) {
+		lpwh->ofsFilename = sizeof(WINHELP);
+		strcpy(((char*)lpwh) + sizeof(WINHELP),lpHelpFile);
+	}
+	if(dsize) {
+		memcpy(((char*)lpwh)+sizeof(WINHELP)+nlen,data,dsize);
+		lpwh->ofsData = sizeof(WINHELP)+nlen;
+	} else
+		lpwh->ofsData = 0;
+	GlobalUnlock(hwh);
+	return SendMessage(hDest,WM_WINHELP,hWnd,hwh);
 }
diff --git a/misc/lzexpand.c b/misc/lzexpand.c
new file mode 100644
index 0000000..57e5c8c
--- /dev/null
+++ b/misc/lzexpand.c
@@ -0,0 +1,492 @@
+/*
+ * LZ Decompression functions 
+ *
+ * Copyright 1996 Marcus Meissner
+ */
+/* 
+ * FIXME: return values might be wrong
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "windows.h"
+#include "file.h"
+#include "lzexpand.h"
+#include "stackframe.h"
+#include "stddebug.h"
+#include "debug.h"
+#include "xmalloc.h"
+
+/* The readahead length of the decompressor. Reading single bytes
+ * using _lread() would be SLOW.
+ */
+#define	GETLEN	2048
+
+/* Format of first 14 byte of LZ compressed file */
+struct lzfileheader {
+	BYTE	magic[8];
+	BYTE	compressiontype;
+	CHAR	lastchar;
+	DWORD	reallength;		
+};
+static BYTE LZMagic[8]={'S','Z','D','D',0x88,0xf0,0x27,0x33};
+
+static struct lzstate {
+	HFILE	lzfd;		/* the handle used by the program */
+	HFILE	realfd;		/* the real filedescriptor */
+	CHAR	lastchar;	/* the last char of the filename */
+
+	DWORD	reallength;	/* the decompressed length of the file */
+	DWORD	realcurrent;	/* the position the decompressor currently is */
+	DWORD	realwanted;	/* the position the user wants to read from */
+
+	BYTE	table[0x1000];	/* the rotating LZ table */
+	UINT	curtabent;	/* CURrent TABle ENTry */
+
+	BYTE	stringlen;	/* length and position of current string */ 
+	DWORD	stringpos;	/* from stringtable */
+
+
+	WORD	bytetype;	/* bitmask within blocks */
+
+	BYTE	*get;		/* GETLEN bytes */
+	DWORD	getcur;		/* current read */
+	DWORD	getlen;		/* length last got */
+} *lzstates=NULL;
+static int nroflzstates=0;
+
+/* reads one compressed byte, including buffering */
+#define GET(lzs,b)	_lzget(lzs,&b)
+#define GET_FLUSH(lzs)	lzs->getcur=lzs->getlen;
+
+int
+_lzget(struct lzstate *lzs,BYTE *b) {
+	if (lzs->getcur<lzs->getlen) {
+		*b		= lzs->get[lzs->getcur++];
+		return		1;
+	} else {
+		int ret = FILE_Read(lzs->realfd,lzs->get,GETLEN);
+		if (ret==HFILE_ERROR)
+			return HFILE_ERROR;
+		if (ret==0)
+			return 0;
+		lzs->getlen	= ret;
+		lzs->getcur	= 1;
+		*b		= *(lzs->get);
+		return 1;
+	}
+}
+/* internal function, reads lzheader
+ * returns BADINHANDLE for non filedescriptors
+ * return 0 for file not compressed using LZ 
+ * return UNKNOWNALG for unknown algorithm
+ * returns lzfileheader in *head
+ */
+static INT
+read_header(HFILE fd,struct lzfileheader *head) {
+	BYTE	buf[14];
+
+	if (_llseek(fd,0,SEEK_SET)==-1)
+		return LZERROR_BADINHANDLE;
+
+	/* We can't directly read the lzfileheader struct due to 
+	 * structure element alignment
+	 */
+	if (FILE_Read(fd,buf,14)<14)
+		return 0;
+	memcpy(head->magic,buf,8);
+	memcpy(&(head->compressiontype),buf+8,1);
+	memcpy(&(head->lastchar),buf+9,1);
+
+	/* FIXME: consider endianess on non-intel architectures */
+	memcpy(&(head->reallength),buf+10,4);
+
+	if (memcmp(head->magic,LZMagic,8))
+		return 0;
+	if (head->compressiontype!='A')
+		return LZERROR_UNKNOWNALG;
+	return 1;
+}
+/* 
+ * LZSTART							[LZEXPAND.7] 
+ */
+INT
+LZStart(void) {
+	dprintf_file(stddeb,"LZStart(void)\n");
+	return 1;
+}
+
+/*
+ * LZINIT							[LZEXPAND.3]
+ * 
+ * initializes internal decompression buffers, returns lzfiledescriptor.
+ * (return value the same as hfSrc, if hfSrc is not compressed)
+ * on failure, returns error code <0
+ * lzfiledescriptors range from 0x400 to 0x410 (only 16 open files per process)
+ * we use as much as we need, we just OR 0x400 to the passed HFILE.
+ *
+ * since _llseek uses the same types as libc.lseek, we just use the macros of 
+ *  libc
+ */
+HFILE
+LZInit(HFILE hfSrc) {
+	struct	lzfileheader	head;
+	struct	lzstate		*lzs;
+	DWORD	ret;
+
+	dprintf_file(stddeb,"LZInit(%d)\n",hfSrc);
+	ret=read_header(hfSrc,&head);
+	if (ret<=0) {
+		_llseek(hfSrc,0,SEEK_SET);
+		return ret?ret:hfSrc;
+	}
+	lzstates=xrealloc(lzstates,(++nroflzstates)*sizeof(struct lzstate));
+	lzs		= lzstates+(nroflzstates-1);
+
+	memset(lzs,'\0',sizeof(*lzs));
+	lzs->realfd	= hfSrc;
+	lzs->lzfd	= hfSrc | 0x400;
+	lzs->lastchar	= head.lastchar;
+	lzs->reallength = head.reallength;
+
+	lzs->get	= xmalloc(GETLEN);
+	lzs->getlen	= 0;
+	lzs->getcur	= 0;
+
+	/* Yes, preinitialize with spaces */
+	memset(lzs->table,' ',0x1000);
+	/* Yes, start 16 byte from the END of the table */
+	lzs->curtabent	= 0xff0; 
+	return lzs->lzfd;
+}
+
+/*
+ * LZDone					[LZEXPAND.9] 
+ */
+
+void
+LZDone(void) {
+	dprintf_file(stddeb,"LZDone()\n");
+}
+
+/*
+ * GetExpandedName				[LZEXPAND.10]
+ *
+ * gets the full filename of the compressed file 'in' by opening it
+ * and reading the header
+ *
+ * "file." is being translated to "file"
+ * "file.bl_" (with lastchar 'a') is being translated to "file.bla"
+ * "FILE.BL_" (with lastchar 'a') is being translated to "FILE.BLA"
+ */
+
+INT
+GetExpandedName(LPCSTR in,LPSTR out) {
+	struct lzfileheader	head;
+	HFILE		fd;
+	OFSTRUCT	ofs;
+	INT		fnislowercased,ret,len;
+	LPSTR		s,t;
+
+	dprintf_file(stddeb,"GetExpandedName(%s)\n",in);
+	fd=OpenFile(in,&ofs,OF_READ);
+	if (fd==HFILE_ERROR)
+		return LZERROR_BADINHANDLE;
+	ret=read_header(fd,&head);
+	if (ret<=0) {
+		_lclose(fd);
+		return LZERROR_BADINHANDLE;
+	}
+
+	/* This line will crash if the caller hasn't allocated enough memory
+	 * for us.
+	 */
+	strcpy(out,in);
+
+	/* look for directory prefix and skip it. */
+	s=out;
+	while (NULL!=(t=strpbrk(s,"/\\:")))
+		s=t+1;
+
+	/* now mangle the basename */
+	if (!*s) {
+		/* FIXME: hmm. shouldn't happen? */
+		fprintf(stddeb,__FILE__":GetExpandedFileName(), specified a directory or what? (%s)\n",in);
+		_lclose(fd);
+		return 1;
+	}
+	/* see if we should use lowercase or uppercase on the last char */
+	fnislowercased=1;
+	t=s+strlen(s)-1;
+	while (t>=out) {
+		if (!isalpha(*t)) {
+			t--;
+			continue;
+		}
+		fnislowercased=islower(*t);
+		break;
+	}
+	if (isalpha(head.lastchar)) {
+		if (fnislowercased)
+			head.lastchar=tolower(head.lastchar);
+		else
+			head.lastchar=toupper(head.lastchar);
+	}	
+
+	/* now look where to replace the last character */
+	if (NULL!=(t=strchr(s,'.'))) {
+		if (t[1]=='\0') {
+			t[0]='\0';
+		} else {
+			len=strlen(t)-1;
+			if (t[len]=='_')
+				t[len]=head.lastchar;
+		}
+	} /* else no modification necessary */
+	_lclose(fd);
+	return 1;
+}
+
+/*
+ * LZRead				[LZEXPAND.5]
+ * just as normal read, but reads from LZ special fd and uncompresses.
+ */
+INT
+LZRead(HFILE fd,SEGPTR segbuf,WORD toread) {
+	int	i,howmuch;
+	BYTE	b;
+	BYTE	*buf;
+	struct	lzstate	*lzs;
+
+	dprintf_file(stddeb,"LZRead(%d,%08lx,%d)\n",fd,segbuf,toread);
+	howmuch=toread;
+	for (i=0;i<nroflzstates;i++)
+		if (lzstates[i].lzfd==fd)
+			break;
+	if (i==nroflzstates)
+		return _lread(fd,segbuf,toread);
+	lzs=lzstates+i;
+
+
+/* The decompressor itself is in a define, cause we need it twice
+ * in this function. (the decompressed byte will be in b)
+ */
+#define DECOMPRESS_ONE_BYTE 						\
+		if (lzs->stringlen) {					\
+			b		= lzs->table[lzs->stringpos];	\
+			lzs->stringpos	= (lzs->stringpos+1)&0xFFF;	\
+			lzs->stringlen--;				\
+		} else {						\
+			if (!(lzs->bytetype&0x100)) {			\
+				if (1!=GET(lzs,b)) 			\
+					return toread-howmuch;		\
+				lzs->bytetype = b|0xFF00;		\
+			}						\
+			if (lzs->bytetype & 1) {			\
+				if (1!=GET(lzs,b))			\
+					return toread-howmuch;		\
+			} else {					\
+				BYTE	b1,b2;				\
+									\
+				if (1!=GET(lzs,b1))			\
+					return toread-howmuch;		\
+				if (1!=GET(lzs,b2))			\
+					return toread-howmuch;		\
+				/* Format:				\
+				 * b1 b2				\
+				 * AB CD 				\
+				 * where CAB is the stringoffset in the table\
+				 * and D+3 is the len of the string	\
+				 */					\
+				lzs->stringpos	= b1|((b2&0xf0)<<4);	\
+				lzs->stringlen	= (b2&0xf)+2; 		\
+				/* 3, but we use a  byte already below ... */\
+				b		= lzs->table[lzs->stringpos];\
+				lzs->stringpos	= (lzs->stringpos+1)&0xFFF;\
+			}						\
+			lzs->bytetype>>=1;				\
+		}							\
+		/* store b in table */					\
+		lzs->table[lzs->curtabent++]= b;			\
+		lzs->curtabent	&= 0xFFF;				\
+		lzs->realcurrent++;
+
+	/* if someone has seeked, we have to bring the decompressor 
+	 * to that position
+	 */
+	if (lzs->realcurrent!=lzs->realwanted) {
+		/* if the wanted position is before the current position 
+		 * I see no easy way to unroll ... We have to restart at
+		 * the beginning. *sigh*
+		 */
+		if (lzs->realcurrent>lzs->realwanted) {
+			/* flush decompressor state */
+			_llseek(lzs->realfd,14,SEEK_SET);
+			GET_FLUSH(lzs);
+			lzs->realcurrent= 0;
+			lzs->bytetype	= 0;
+			lzs->stringlen	= 0;
+			memset(lzs->table,' ',0x1000);
+			lzs->curtabent	= 0xFF0;
+		}
+		while (lzs->realcurrent<lzs->realwanted) {
+			DECOMPRESS_ONE_BYTE;
+		}
+	}
+
+	buf=PTR_SEG_TO_LIN(segbuf);
+	while (howmuch) {
+		DECOMPRESS_ONE_BYTE;
+		lzs->realwanted++;
+		*buf++		= b;
+		howmuch--;
+	}
+	return 	toread;
+#undef DECOMPRESS_ONE_BYTE
+}
+
+/* 
+ * LZSeek				[LZEXPAND.4]
+ *
+ * works as the usual _llseek
+ */
+
+LONG
+LZSeek(HFILE fd,LONG off,INT type) {
+	int	i;
+	struct	lzstate	*lzs;
+	LONG	lastwanted,newwanted;
+
+	dprintf_file(stddeb,"LZSeek(%d,%ld,%d)\n",fd,off,type);
+	for (i=0;i<nroflzstates;i++)
+		if (lzstates[i].lzfd==fd)
+			break;
+	/* not compressed? just use normal _llseek() */
+	if (i==nroflzstates)
+		return _llseek(fd,off,type);
+	lzs		= lzstates+i;
+	lastwanted	= lzs->realwanted;
+	newwanted	= lzs->realwanted;
+	switch (type) {
+	case 1:	/* SEEK_CUR */
+		newwanted      += off;
+		break;
+	case 2:	/* SEEK_END */
+		newwanted	= lzs->reallength-off;
+		break;
+	default:/* SEEK_SET */
+		newwanted	= off;
+		break;
+	}
+	if (newwanted>lzs->reallength)
+		return LZERROR_BADVALUE;
+	if (newwanted<0)
+		return LZERROR_BADVALUE;
+	lzs->realwanted	= newwanted;
+	return lastwanted;
+}
+
+/* 
+ * LZCopy				[LZEXPAND.1]
+ *
+ * Copies everything from src to dest
+ * if src is a LZ compressed file, it will be uncompressed.
+ * will return the number of bytes written to dest or errors.
+ */
+LONG
+LZCopy(HFILE src,HFILE dest) {
+	int	i,ret,wret;
+	LONG	len;
+#define BUFLEN	1000
+	BYTE	buf[BUFLEN];
+	INT	(*xread)(HFILE,SEGPTR,WORD);
+
+	dprintf_file(stddeb,"LZCopy(%d,%d)\n",src,dest);
+	for (i=0;i<nroflzstates;i++)
+		if (src==lzstates[i].lzfd)
+			break;
+
+	/* not compressed? just copy */
+	if (i==nroflzstates)
+		xread=_lread;
+	else
+		xread=LZRead;
+	len=0;
+	while (1) {
+		ret=xread(src,MAKE_SEGPTR(buf),BUFLEN);
+		if (ret<=0) {
+			if (ret==0)
+				break;
+			if (ret==-1)
+				return LZERROR_READ;
+			return ret;
+		}
+		len    += ret;
+		wret	= _lwrite(dest,buf,ret);
+		if (wret!=ret)
+			return LZERROR_WRITE;
+	}
+	return len;
+#undef BUFLEN
+}
+
+/*
+ * LZOpenFile				[LZEXPAND.2]
+ * Opens a file. If not compressed, open it as a normal file.
+ */
+HFILE
+LZOpenFile(LPCSTR fn,LPOFSTRUCT ofs,UINT mode) {
+	HFILE	fd,cfd;
+
+	dprintf_file(stddeb,"LZOpenFile(%s,%p,%d)\n",fn,ofs,mode);
+	/* 0x70 represents all OF_SHARE_* flags, ignore them for the check */
+	fd=OpenFile(fn,ofs,mode);
+	if ((mode&~0x70)!=OF_READ)
+		return fd;
+	if (fd==HFILE_ERROR)
+		return HFILE_ERROR;
+	cfd=LZInit(fd);
+	if (cfd<=0)
+		return fd;
+	return cfd;
+}
+
+/*
+ * LZClose				[LZEXPAND.6]
+ */
+void
+LZClose(HFILE fd) {
+	int	i;
+
+	dprintf_file(stddeb,"LZClose(%d)\n",fd);
+	for (i=0;i<nroflzstates;i++)
+		if (lzstates[i].lzfd==fd)
+			break;
+	if (i==nroflzstates) {
+		_lclose(fd);
+		return;
+	}
+	if (lzstates[i].get)
+		free(lzstates[i].get);
+	_lclose(lzstates[i].realfd);
+	memcpy(lzstates+i,lzstates+i+1,sizeof(struct lzstate)*(nroflzstates-i-1));
+	nroflzstates--;
+	lzstates=xrealloc(lzstates,sizeof(struct lzstate)*nroflzstates);
+}
+
+/*
+ * CopyLZFile					[LZEXPAND.8]
+ *
+ * Copy src to dest (including uncompressing src).
+ * NOTE: Yes. This is exactly the same function as LZCopy.
+ */
+LONG
+CopyLZFile(HFILE src,HFILE dest) {
+	dprintf_file(stddeb,"CopyLZFile(%d,%d)\n",src,dest);
+	return LZCopy(src,dest);
+}
diff --git a/misc/spy.c b/misc/spy.c
index 81f2852..326e0f6 100644
--- a/misc/spy.c
+++ b/misc/spy.c
@@ -15,9 +15,6 @@
 #include "debug.h"
 #include "spy.h"
 
-#define SPY_MAX_MSGNUM		WM_USER
-#define SPY_MAX_INDENTLEVEL     64
-
 const char *MessageTypeNames[SPY_MAX_MSGNUM + 1] =
 {
     "WM_NULL",			/* 0x00 */
@@ -130,7 +127,7 @@
     "WM_NCMBUTTONDBLCLK",	/* 0x00A9 */
     NULL, NULL, NULL, NULL, NULL, NULL,
 
-    /* 0x00B0 */
+    /* 0x00B0 - Win32 Edit controls */
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
@@ -142,11 +139,11 @@
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
-    /* 0x00E0 */
+    /* 0x00E0 - Win32 Scrollbars */
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
-    /* 0x00F0 */
+    /* 0x00F0 - Win32 Buttons */
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
@@ -186,7 +183,7 @@
     NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
-    /* 0x0140 */
+    /* 0x0140 - Win32 Comboboxes */
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
@@ -198,11 +195,11 @@
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
-    /* 0x0170 */
+    /* 0x0170 - Win32 Static controls */
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
-    /* 0x0180 */
+    /* 0x0180 - Win32 Listboxes */
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
@@ -398,7 +395,7 @@
 static BOOL 	SpyIncludes[SPY_MAX_MSGNUM+1];
 
 static int      iSpyMessageIndentLevel  = 0;
-static char     lpstrSpyMessageIndent[SPY_MAX_INDENTLEVEL];
+       char     lpstrSpyMessageIndent[SPY_MAX_INDENTLEVEL]; /* referenced in debugger/info.c */
 static char    *lpstrSpyMessageFromWine = "Wine";
 static char     lpstrSpyMessageFromTask[10]; 
 static char    *lpstrSpyMessageFromSelf = "self";
@@ -501,8 +498,11 @@
 
   if( !SpyIncludes[wCheckMsg] || SpyFilters[wCheckMsg]) return;
 
-  iSpyMessageIndentLevel--;
-  lpstrSpyMessageIndent[iSpyMessageIndentLevel]='\0';
+  if( iSpyMessageIndentLevel )
+    {
+      iSpyMessageIndentLevel--;
+      lpstrSpyMessageIndent[iSpyMessageIndentLevel]='\0';
+    }
 
   switch(iFlag)
     {
diff --git a/miscemu/int21.c b/miscemu/int21.c
index f406ef7..08f300e 100644
--- a/miscemu/int21.c
+++ b/miscemu/int21.c
@@ -519,7 +519,7 @@
     char *dirname = PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context));
 
     dprintf_int(stddeb,"int21: changedir %s\n", dirname);
-    if (dirname[1] == ':')
+    if (dirname[0] && (dirname[1] == ':'))
     {
         drive = toupper(dirname[0]) - 'A';
         dirname += 2;
@@ -599,28 +599,6 @@
 }
 
 
-static int INT21_SetFileDateTime(struct sigcontext_struct *context)
-{
-    fprintf( stderr, "INT21_SetFileDateTime: not implemented yet.\n" );
-    return 1;
-#if 0
-    char *filename;
-    struct utimbuf filetime;
-	
-    /* FIXME: Argument isn't the name of the file in DS:DX,
-       but the file handle in BX */
-    filename = DOSFS_GetUnixFileName( PTR_SEG_OFF_TO_LIN(DS_reg(context),
-                                                         DX_reg(context)),TRUE );
-
-    filetime.actime = 0L;
-    filetime.modtime = filetime.actime;
-    
-    utime(filename, &filetime);
-    RESET_CFLAG(context);
-#endif
-}
-
-
 static int INT21_CreateTempFile(struct sigcontext_struct *context)
 {
     static int counter = 0;
@@ -1429,16 +1407,18 @@
     case 0x57: /* FILE DATE AND TIME */
         switch (AL_reg(&context))
         {
-        case 0x00:
-            if (!FILE_Fstat( BX_reg(&context), NULL, NULL,
-                             &DX_reg(&context), &CX_reg(&context) ))
+        case 0x00:  /* Get */
+            if (!FILE_GetDateTime( BX_reg(&context), &DX_reg(&context),
+                                   &CX_reg(&context), TRUE ))
             {
                 AX_reg(&context) = DOS_ExtendedError;
                 SET_CFLAG(&context);
             }
             break;
-        case 0x01:
-            if (!INT21_SetFileDateTime(&context))
+
+        case 0x01:  /* Set */
+            if (!FILE_SetDateTime( BX_reg(&context), DX_reg(&context),
+                                   CX_reg(&context) ))
             {
                 AX_reg(&context) = DOS_ExtendedError;
                 SET_CFLAG(&context);
@@ -1566,9 +1546,8 @@
 
     case 0x68: /* "FFLUSH" - COMMIT FILE */
     case 0x6a: /* COMMIT FILE */
-        if (fsync( FILE_GetUnixTaskHandle( BX_reg(&context) )) == -1)
+        if (!FILE_Sync( BX_reg(&context) ))
         {
-            FILE_SetDosError();
             AX_reg(&context) = DOS_ExtendedError;
             SET_CFLAG(&context);
         }
diff --git a/miscemu/int2f.c b/miscemu/int2f.c
index 86ff140..cc40aac 100644
--- a/miscemu/int2f.c
+++ b/miscemu/int2f.c
@@ -54,6 +54,9 @@
             INT_BARF( &context, 0x2f );
         }
         break;
+    case 0xb7:  /* append */
+        AL_reg(&context) = 0; /* not installed */
+        break;
     default:
         INT_BARF( &context, 0x2f );
         break;
diff --git a/objects/bitblt.c b/objects/bitblt.c
index d6e182c..73159f3 100644
--- a/objects/bitblt.c
+++ b/objects/bitblt.c
@@ -667,13 +667,13 @@
     {
         yinc = ((int)heightSrc << 16) / heightDst;
         ydst = visRectDst->top;
-        ysrc = yinc * ydst;
+        ysrc = yinc * ydst + (vswap ? heightSrc<<16 : 0);
     }
     else
     {
         yinc = ((int)heightDst << 16) / heightSrc;
         ysrc = visRectSrc->top;
-        ydst = yinc * ysrc;
+        ydst = yinc * ysrc - (vswap ? (heightDst-1)<<16 : 0);
     }
 
     while(vstretch ? (ydst < visRectDst->bottom) : (ysrc < visRectSrc->bottom))
@@ -685,7 +685,8 @@
 
           /* Stretch or shrink it */
         if (hstretch)
-            BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
+            BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left +
+			       (hswap ? widthDst : 0),
                                visRectDst->right-visRectDst->left, xinc, mode);
         else BITBLT_ShrinkRow( rowSrc, rowDst, visRectSrc->left,
                                visRectSrc->right-visRectSrc->left, xinc, mode);
@@ -714,7 +715,7 @@
         
           /* Store the destination row */
 
-        pixel = rowDst + visRectDst->right - 1;
+        pixel = rowDst + visRectDst->right - 1 + (hswap ? widthDst : 0);
         if (vswap)
             y = visRectDst->bottom - (vstretch ? ydst : ydst >> 16);
         else
@@ -972,7 +973,8 @@
 
     if (!dcSrc) return TRUE;
     SetRect( &tmpRect, xSrc, ySrc, xSrc + widthSrc, ySrc + heightSrc );
-    GetRgnBox( dcSrc->w.hGCClipRgn, &clipRect );
+    /* Apparently the clip region is only for output, so use hVisRgn here */
+    GetRgnBox( dcSrc->w.hVisRgn, &clipRect );
     OffsetRect( &clipRect, dcSrc->w.DCOrgX, dcSrc->w.DCOrgY );
     if (!IntersectRect( visRectSrc, &tmpRect, &clipRect )) return FALSE;
 
diff --git a/objects/region.c b/objects/region.c
index 1874a91..7e7e290 100644
--- a/objects/region.c
+++ b/objects/region.c
@@ -361,9 +361,11 @@
  */
 static int REGION_CopyRegion( RGNOBJ *src, RGNOBJ *dest )
 {
+    Region tmprgn;
     if (src->xrgn)
     {
-        Region tmprgn = XCreateRegion();
+        if (src->xrgn == dest->xrgn) return COMPLEXREGION;
+        tmprgn = XCreateRegion();
         if (!dest->xrgn) dest->xrgn = XCreateRegion();
         XUnionRegion( tmprgn, src->xrgn, dest->xrgn );
         XDestroyRegion( tmprgn );
@@ -401,11 +403,14 @@
 
 /***********************************************************************
  *           CombineRgn    (GDI.451)
+ *
+ * The behavior is correct even if src and dest regions are the same.
  */
 INT CombineRgn( HRGN hDest, HRGN hSrc1, HRGN hSrc2, INT mode )
 {
     RGNOBJ *destObj, *src1Obj, *src2Obj;
-    
+    Region destrgn;
+
     dprintf_region(stddeb, "CombineRgn: "NPFMT","NPFMT" -> "NPFMT" mode=%x\n", 
 		   hSrc1, hSrc2, hDest, mode );
     
@@ -445,29 +450,32 @@
 
       /* Perform the operation with the two X regions */
 
-    if (!destObj->xrgn) destObj->xrgn = XCreateRegion();
+    if (!(destrgn = XCreateRegion())) return ERROR;
     switch(mode)
     {
     case RGN_AND:
-        XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
+        XIntersectRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
         break;
     case RGN_OR:
-        XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
+        XUnionRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
         break;
     case RGN_XOR:
-        XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
+        XXorRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
         break;
     case RGN_DIFF:
-        XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destObj->xrgn );
+        XSubtractRegion( src1Obj->xrgn, src2Obj->xrgn, destrgn );
         break;
     default:
+        XDestroyRegion( destrgn );
         return ERROR;
     }
+    if (destObj->xrgn) XDestroyRegion( destObj->xrgn );
+    destObj->xrgn = destrgn;
     if (XEmptyRegion(destObj->xrgn))
     {
         XDestroyRegion( destObj->xrgn );
         destObj->xrgn = 0;
         return NULLREGION;
     }
-    else return COMPLEXREGION;
+    return COMPLEXREGION;
 }
diff --git a/programs/progman/main.c b/programs/progman/main.c
index f6173e2..6775121 100644
--- a/programs/progman/main.c
+++ b/programs/progman/main.c
@@ -9,6 +9,7 @@
 #include "license.h"
 #include "progman.h"
 #ifdef WINELIB
+#include <resource.h>
 #include <options.h>
 #include <shell.h>
 #endif
diff --git a/rc/parser.h b/rc/parser.h
index dc667ba..38e5028 100644
--- a/rc/parser.h
+++ b/rc/parser.h
@@ -91,6 +91,8 @@
 
 gen_res *add_resource(gen_res*,gen_res*);
 
+void add_str_tbl_elm(int,char*);
+
 void create_output(gen_res*);
 void set_out_file(char*);
 
diff --git a/rc/parser.l b/rc/parser.l
index 945ff82..ed39e54 100644
--- a/rc/parser.l
+++ b/rc/parser.l
@@ -10,6 +10,8 @@
 #include <stdlib.h>
 #include "parser.h"
 #include "y.tab.h"
+
+int line_number=1;
 %}
 %%
 ACCELERATORS	return ACCELERATORS;
@@ -70,7 +72,8 @@
 [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]		;
+\n                      { line_number++; }
+[ \t\r]                 ;
 .			return yytext[0];
 %%
 
diff --git a/rc/parser.y b/rc/parser.y
index 121c508..3cbd039 100644
--- a/rc/parser.y
+++ b/rc/parser.y
@@ -5,6 +5,7 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include "parser.h"
 #include "windows.h"
 %}
@@ -29,7 +30,7 @@
 %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
+%type <style> style style_elm optional_style
 %%
 
 resource_file: resources {create_output($1);}
@@ -48,6 +49,11 @@
 		{$$=$2;$$->n.s_name=$1;$$->n_type=1;
 			if(verbose)fprintf(stderr,"Got %s %s\n",get_typename($2),$1);
 		}
+                | stringtable
+                {$$=$1; /* <-- should be NULL */
+			if(verbose)fprintf(stderr,"Got STRINGTABLE\n");
+                }
+                ;
 
 /* get the value for a single resource*/
 resource_definition:	accelerators {$$=$1;}
@@ -58,8 +64,8 @@
 		| 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;}
@@ -190,20 +196,27 @@
 stringtable:	STRINGTABLE load_and_memoption tBEGIN strings tEND
 			{$$=$4;}
 strings:	{$$=0;}|
-		NUMBER STRING strings {$$=0;}
+		NUMBER STRING strings {$$=0;add_str_tbl_elm($1,$2);}
 
 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;}
+style:	        {$$=new_style();}
+                | style_elm {$$=$1;}
+		| style_elm '|' style 
+                {$$=$1;$$->or|=$3->or;$$->and&=$3->and;free($3);}
+
+style_elm:      NUMBER {$$=new_style();$$->or=$1;}
 		| NOT NUMBER {$$=new_style();$$->and=~($2);}
 		| '(' style ')' {$$=$2;}
-		| style '|' style {$$=$1;$$->or|=$3->or;$$->and&=$3->and;}
 %%
+extern int line_number;
+extern char* yytext;
+
 int yyerror(char *s)
 {
-	puts(s);
+	fprintf(stderr,"stdin:%d: %s before '%s'\n",line_number,s,yytext);
 	return 0;
 }
 
diff --git a/rc/winerc.c b/rc/winerc.c
index 494ab10..32a4dd1 100644
--- a/rc/winerc.c
+++ b/rc/winerc.c
@@ -505,8 +505,70 @@
 /* link top-level resources */
 gen_res *add_resource(gen_res* first,gen_res *rest)
 {
+    if(first)
+    {
 	first->next=rest;
 	return first;
+    }
+    else
+        return rest;
+}
+
+typedef struct str_tbl_elm{
+	int group;
+	struct str_tbl_elm *next;
+	char* strings[16];
+} str_tbl_elm;
+
+str_tbl_elm* string_table=NULL; /* sorted by group */
+
+void add_str_tbl_elm(int id,char* str)
+{
+  int group=(id>>4)+1;
+  int idx=id & 0x000f;
+
+  str_tbl_elm** elm=&string_table;
+  while(*elm && (*elm)->group<group) elm=&(*elm)->next;
+  if(!*elm || (*elm)->group!=group)
+  {
+    str_tbl_elm* new=xmalloc(sizeof(str_tbl_elm));
+    new->group=group;
+    new->next=*elm;
+    *elm=new;
+  }
+  (*elm)->strings[idx]=str;
+}
+
+gen_res* add_string_table(gen_res* t)
+{
+  str_tbl_elm* ste;
+  int size,i;
+  gen_res* res;
+  unsigned char* p;
+  char* q;
+
+  if(!string_table) return t;
+  for(ste=string_table; ste; ste=ste->next)
+  {
+    for(size=0,i=0; i<16; i++)
+      size += ste->strings[i] ? strlen(ste->strings[i])+1 : 1;
+    res=new_res();
+    while(res->space<size)res=grow(res);
+    res->type=str;
+    res->n.i_name=ste->group;
+    res->n_type=0;
+    res->size=size;
+    for(p=res->res,i=0; i<16; i++)
+      if((q=ste->strings[i])==NULL)
+	*p++ = 0;
+      else
+      {
+	*p++ = strlen(q);
+	while(*q) *p++ = *q++;
+      }
+    t=add_resource(res,t);
+  }
+  return t;
 }
 
 char *get_typename(gen_res* t)
@@ -543,6 +605,7 @@
 {
     gen_res *it;
 
+    top=add_string_table(top);
 
     fprintf( header, "/* %s\n"
                      " * This file is automatically generated. Do not edit!\n"
@@ -563,6 +626,7 @@
                    " * This file is automatically generated. Do not edit!\n"
                    " */\n\n"
                    "#include \"%s\"\n", sname, hname );
+
     for(it=top;it;it=it->next)
     {
         int i;
diff --git a/win32/Makefile.in b/win32/Makefile.in
index b7ea362..a5e8e38 100644
--- a/win32/Makefile.in
+++ b/win32/Makefile.in
@@ -18,6 +18,7 @@
 	process.c \
 	resource.c \
 	string32.c \
+	struct32.c \
 	thread.c \
 	time.c \
 	user32.c \
diff --git a/win32/param32.c b/win32/param32.c
index 523c265..7d6f95a 100644
--- a/win32/param32.c
+++ b/win32/param32.c
@@ -13,19 +13,6 @@
 #include "stddebug.h"
 #include "debug.h"
 
-void PARAM32_POINT32to16(const POINT32* p32,POINT* p16)
-{
-	p16->x = p32->x;
-	p16->y = p32->y;
-}
-
-void PARAM32_SIZE16to32(const SIZE* p16, SIZE32* p32) 
-  
-{
-        p32->cx = p16->cx;
-        p32->cy = p16->cy;
-}
-
 /****************************************************************
  *           MoveToEx          (GDI32.254)
  */
@@ -35,7 +22,7 @@
 	if (p32 == NULL)
 		return MoveToEx(hdc,x,y,(POINT *)NULL);
 	else {
-		PARAM32_POINT32to16(p32,&p);
+		STRUCT32_POINT32to16(p32,&p);
 		return MoveToEx(hdc,x,y,&p);
 	}
 }
@@ -47,7 +34,7 @@
         BOOL retval;
 
         retval = GetTextExtentPoint(hdc, str, length, &s);
-        PARAM32_SIZE16to32(&s, lpsize);
+        STRUCT32_SIZE16to32(&s, lpsize);
 
         return retval;
 }
diff --git a/win32/struct32.c b/win32/struct32.c
new file mode 100644
index 0000000..4a70c17
--- /dev/null
+++ b/win32/struct32.c
@@ -0,0 +1,150 @@
+/*
+ * Win32 structure conversion functions
+ *
+ * Copyright 1996 Martin von Loewis
+ */
+
+#include <stdio.h>
+#include "windows.h"
+#include "winerror.h"
+#include "struct32.h"
+#include "stddebug.h"
+#include "debug.h"
+
+void STRUCT32_POINT32to16(const POINT32* p32,POINT* p16)
+{
+	p16->x = p32->x;
+	p16->y = p32->y;
+}
+
+void STRUCT32_POINT16to32(const POINT* p16,POINT32* p32)
+{
+	p32->x = p16->x;
+	p32->y = p16->y;
+}
+
+void STRUCT32_SIZE16to32(const SIZE* p16, SIZE32* p32) 
+  
+{
+        p32->cx = p16->cx;
+        p32->cy = p16->cy;
+}
+
+void STRUCT32_MSG16to32(MSG *msg16,MSG32 *msg32)
+{
+	msg32->hwnd=(DWORD)msg16->hwnd;
+	msg32->message=msg16->message;
+	msg32->wParam=msg16->wParam;
+	msg32->lParam=msg16->lParam;
+	msg32->time=msg16->time;
+	msg32->pt.x=msg16->pt.x;
+	msg32->pt.y=msg16->pt.y;
+}
+
+void STRUCT32_MSG32to16(MSG32 *msg32,MSG *msg16)
+{
+	msg16->hwnd=(HWND)msg32->hwnd;
+	msg16->message=msg32->message;
+	msg16->wParam=msg32->wParam;
+	msg16->lParam=msg32->lParam;
+	msg16->time=msg32->time;
+	msg16->pt.x=msg32->pt.x;
+	msg16->pt.y=msg32->pt.y;
+}
+
+void STRUCT32_RECT32to16(const RECT32* r32,RECT *r16)
+{
+	r16->left = r32->left;
+	r16->right = r32->right;
+	r16->top = r32->top;
+	r16->bottom = r32->bottom;
+}
+
+void STRUCT32_RECT16to32(const RECT* r16,RECT32 *r32)
+{
+	r32->left = r16->left;
+	r32->right = r16->right;
+	r32->top = r16->top;
+	r32->bottom = r16->bottom;
+}
+
+void STRUCT32_MINMAXINFO32to16(const MINMAXINFO32 *from,MINMAXINFO *to)
+{
+	STRUCT32_POINT32to16(&from->ptReserved,&to->ptReserved);
+	STRUCT32_POINT32to16(&from->ptMaxSize,&to->ptMaxSize);
+	STRUCT32_POINT32to16(&from->ptMaxPosition,&to->ptMaxPosition);
+	STRUCT32_POINT32to16(&from->ptMinTrackSize,&to->ptMinTrackSize);
+	STRUCT32_POINT32to16(&from->ptMaxTrackSize,&to->ptMaxTrackSize);
+}
+
+void STRUCT32_MINMAXINFO16to32(const MINMAXINFO *from,MINMAXINFO32 *to)
+{
+	STRUCT32_POINT16to32(&from->ptReserved,&to->ptReserved);
+	STRUCT32_POINT16to32(&from->ptMaxSize,&to->ptMaxSize);
+	STRUCT32_POINT16to32(&from->ptMaxPosition,&to->ptMaxPosition);
+	STRUCT32_POINT16to32(&from->ptMinTrackSize,&to->ptMinTrackSize);
+	STRUCT32_POINT16to32(&from->ptMaxTrackSize,&to->ptMaxTrackSize);
+}
+
+void STRUCT32_WINDOWPOS32to16(const WINDOWPOS32* from,WINDOWPOS* to)
+{
+	to->hwnd=from->hwnd;
+	to->hwndInsertAfter=from->hwndInsertAfter;
+	to->x=from->x;
+	to->y=from->y;
+	to->cx=from->cx;
+	to->flags=from->flags;
+}
+
+void STRUCT32_WINDOWPOS16to32(const WINDOWPOS* from,WINDOWPOS32* to)
+{
+	to->hwnd=from->hwnd;
+	to->hwndInsertAfter=from->hwndInsertAfter;
+	to->x=from->x;
+	to->y=from->y;
+	to->cx=from->cx;
+	to->flags=from->flags;
+}
+
+void STRUCT32_NCCALCSIZE32to16Flat(const NCCALCSIZE_PARAMS32* from,
+	NCCALCSIZE_PARAMS* to)
+{
+	STRUCT32_RECT32to16(from->rgrc,to->rgrc);
+	STRUCT32_RECT32to16(from->rgrc+1,to->rgrc+1);
+	STRUCT32_RECT32to16(from->rgrc+2,to->rgrc+2);
+}
+
+void STRUCT32_NCCALCSIZE16to32Flat(const NCCALCSIZE_PARAMS* from,
+	NCCALCSIZE_PARAMS32* to)
+{
+	STRUCT32_RECT16to32(from->rgrc,to->rgrc);
+	STRUCT32_RECT16to32(from->rgrc+1,to->rgrc+1);
+	STRUCT32_RECT16to32(from->rgrc+2,to->rgrc+2);
+}
+
+/* The strings are not copied */
+void STRUCT32_CREATESTRUCT32to16(const CREATESTRUCT32* from,CREATESTRUCT* to)
+{
+	to->lpCreateParams = (LPVOID)from->lpCreateParams;
+	to->hInstance = from->hInstance;
+	to->hMenu = from->hMenu;
+	to->hwndParent = from->hwndParent;
+	to->cy = from->cy;
+	to->cx = from->cx;
+	to->y = from->y;
+	to->style = from->style;
+	to->dwExStyle = from->dwExStyle;
+}
+
+void STRUCT32_CREATESTRUCT16to32(const CREATESTRUCT* from,CREATESTRUCT32 *to)
+{
+	to->lpCreateParams = (DWORD)from->lpCreateParams;
+	to->hInstance = from->hInstance;
+	to->hMenu = from->hMenu;
+	to->hwndParent = from->hwndParent;
+	to->cy = from->cy;
+	to->cx = from->cx;
+	to->y = from->y;
+	to->style = from->style;
+	to->dwExStyle = from->dwExStyle;
+}
diff --git a/win32/user32.c b/win32/user32.c
index c195056..3c94151 100644
--- a/win32/user32.c
+++ b/win32/user32.c
@@ -24,45 +24,6 @@
 #include "debug.h"
 #include "stddebug.h"
 
-/* Structure copy functions */
-static void MSG16to32(MSG *msg16,struct WIN32_MSG *msg32)
-{
-	msg32->hwnd=(DWORD)msg16->hwnd;
-	msg32->message=msg16->message;
-	msg32->wParam=msg16->wParam;
-	msg32->lParam=msg16->lParam;
-	msg32->time=msg16->time;
-	msg32->pt.x=msg16->pt.x;
-	msg32->pt.y=msg16->pt.y;
-}
-
-static void MSG32to16(struct WIN32_MSG *msg32,MSG *msg16)
-{
-	msg16->hwnd=(HWND)msg32->hwnd;
-	msg16->message=msg32->message;
-	msg16->wParam=msg32->wParam;
-	msg16->lParam=msg32->lParam;
-	msg16->time=msg32->time;
-	msg16->pt.x=msg32->pt.x;
-	msg16->pt.y=msg32->pt.y;
-}
-
-void USER32_RECT32to16(const RECT32* r32,RECT *r16)
-{
-	r16->left = r32->left;
-	r16->right = r32->right;
-	r16->top = r32->top;
-	r16->bottom = r32->bottom;
-}
-
-void USER32_RECT16to32(const RECT* r16,RECT32 *r32)
-{
-	r32->left = r16->left;
-	r32->right = r16->right;
-	r32->top = r16->top;
-	r32->bottom = r16->bottom;
-}
-
 /***********************************************************************
  *           RegisterClassA      (USER32.426)
  */
@@ -113,19 +74,19 @@
 /***********************************************************************
  *          GetMessageA          (USER32.269)
  */
-BOOL USER32_GetMessageA(struct WIN32_MSG* lpmsg,DWORD hwnd,DWORD min,DWORD max)
+BOOL USER32_GetMessageA(MSG32* lpmsg,DWORD hwnd,DWORD min,DWORD max)
 {
 	BOOL ret;
 	MSG msg;
 	ret=GetMessage(MAKE_SEGPTR(&msg),(HWND)hwnd,min,max);
-	MSG16to32(&msg,lpmsg);
+	STRUCT32_MSG16to32(&msg,lpmsg);
 	return ret;
 }
 
 /***********************************************************************
  *          BeginPaint           (USER32.9)
  */
-HDC USER32_BeginPaint(DWORD hwnd,struct WIN32_PAINTSTRUCT *lpps)
+HDC USER32_BeginPaint(DWORD hwnd,PAINTSTRUCT32 *lpps)
 {
 	PAINTSTRUCT ps;
 	HDC ret;
@@ -144,7 +105,7 @@
 /***********************************************************************
  *          EndPaint             (USER32.175)
  */
-BOOL USER32_EndPaint(DWORD hwnd,struct WIN32_PAINTSTRUCT *lpps)
+BOOL USER32_EndPaint(DWORD hwnd,PAINTSTRUCT32 *lpps)
 {
 	PAINTSTRUCT ps;
 	ps.hdc=(HDC)lpps->hdc;
@@ -162,23 +123,23 @@
 /***********************************************************************
  *         DispatchMessageA       (USER32.140)
  */
-LONG USER32_DispatchMessageA(struct WIN32_MSG* lpmsg)
+LONG USER32_DispatchMessageA(MSG32* lpmsg)
 {
 	MSG msg;
 	LONG ret;
-	MSG32to16(lpmsg,&msg);
+	STRUCT32_MSG32to16(lpmsg,&msg);
 	ret=DispatchMessage(&msg);
-	MSG16to32(&msg,lpmsg);
+	STRUCT32_MSG16to32(&msg,lpmsg);
 	return ret;
 }
 
 /***********************************************************************
  *         TranslateMessage       (USER32.555)
  */
-BOOL USER32_TranslateMessage(struct WIN32_MSG* lpmsg)
+BOOL USER32_TranslateMessage(MSG32* lpmsg)
 {
 	MSG msg;
-	MSG32to16(lpmsg,&msg);
+	STRUCT32_MSG32to16(lpmsg,&msg);
 	return TranslateMessage(&msg);
 }
 
@@ -256,7 +217,7 @@
 	if (lpRect == NULL)
 		InvalidateRect(hWnd, (RECT *)NULL, bErase);
 	else {
-		USER32_RECT32to16(lpRect,&r);
+		STRUCT32_RECT32to16(lpRect,&r);
 		InvalidateRect(hWnd,&r,bErase);
 	}
 	/* FIXME: Return meaningful value */
@@ -269,7 +230,7 @@
 int USER32_DrawTextA(HDC hdc,LPCSTR lpStr,int count,RECT32* r32,UINT uFormat)
 {
 	RECT r;
-	USER32_RECT32to16(r32,&r);
+	STRUCT32_RECT32to16(r32,&r);
 	return DrawText(hdc,lpStr,count,&r,uFormat);
 }
 
@@ -280,7 +241,7 @@
 {
 	RECT r;
 	GetClientRect(hwnd,&r);
-	USER32_RECT16to32(&r,r32);
+	STRUCT32_RECT16to32(&r,r32);
 	/* FIXME: return value */
 	return 0;
 }
diff --git a/win32/winprocs.c b/win32/winprocs.c
index 9b2d364..963451c 100644
--- a/win32/winprocs.c
+++ b/win32/winprocs.c
@@ -13,6 +13,8 @@
 
 #include "winerror.h"
 #include "kernel32.h"
+#include "wintypes.h"
+#include "struct32.h"
 #include "wincon.h"
 #include "stackframe.h"
 #include "stddebug.h"
@@ -35,6 +37,70 @@
     }
 }
 
+BOOL WIN32_CallWindowProcTo16(LRESULT(*func)(HWND,UINT,WPARAM,LPARAM),
+	HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+	WINDOWPOS wp;
+	union{
+		MINMAXINFO mmi;
+		NCCALCSIZE_PARAMS nccs;
+		CREATESTRUCT cs;
+	} st;
+	WINDOWPOS32 *pwp;
+	CREATESTRUCT32 *pcs;
+	LONG result;
+	if(!lParam || !UsesLParamPtr(msg))
+		return func(hwnd,msg,wParam,lParam);
+	switch(msg)
+	{
+		case WM_GETMINMAXINFO:
+			STRUCT32_MINMAXINFO32to16((void*)lParam,&st.mmi);
+			result=func(hwnd,msg,wParam,MAKE_SEGPTR(&st.mmi));
+			STRUCT32_MINMAXINFO16to32(&st.mmi,(void*)lParam);
+			return result;
+		case WM_WINDOWPOSCHANGING:
+		case WM_WINDOWPOSCHANGED:
+			STRUCT32_WINDOWPOS32to16((void*)lParam,&wp);
+			result=func(hwnd,msg,wParam,MAKE_SEGPTR(&wp));
+			STRUCT32_WINDOWPOS16to32(&wp,(void*)lParam);
+			return result;
+		 case WM_NCCALCSIZE:
+		 	pwp=((NCCALCSIZE_PARAMS32*)lParam)->lppos;
+		 	STRUCT32_NCCALCSIZE32to16Flat((void*)lParam,&st.nccs);
+			if(pwp) {
+				STRUCT32_WINDOWPOS32to16(pwp,&wp);
+				st.nccs.lppos = &wp;
+			}else
+				st.nccs.lppos = 0;
+			result=func(hwnd,msg,wParam,MAKE_SEGPTR(&st.nccs));
+			STRUCT32_NCCALCSIZE16to32Flat(&st.nccs,(void*)lParam);
+			if(pwp)
+				STRUCT32_WINDOWPOS16to32(&wp,pwp);
+			return result;
+		case WM_NCCREATE:
+			pcs = (CREATESTRUCT32*)lParam;
+			STRUCT32_CREATESTRUCT32to16((void*)lParam,&st.cs);
+			st.cs.lpszName = HIWORD(pcs->lpszName) ? 
+				MAKE_SEGPTR(pcs->lpszName) : pcs->lpszName;
+			st.cs.lpszClass = HIWORD(pcs->lpszClass) ? 
+				MAKE_SEGPTR(pcs->lpszClass) : pcs->lpszClass;
+			result=func(hwnd,msg,wParam,MAKE_SEGPTR(&st.cs));
+			STRUCT32_CREATESTRUCT16to32(&st.cs,(void*)lParam);
+			pcs->lpszName = HIWORD(pcs->lpszName) ? 
+				PTR_SEG_TO_LIN(st.cs.lpszName) : pcs->lpszName;
+			pcs->lpszClass = HIWORD(pcs-> lpszClass) ? 
+				PTR_SEG_TO_LIN(st.cs.lpszClass) : pcs-> lpszClass;
+			return result;
+		case WM_GETTEXT:
+		case WM_SETTEXT:
+			return func(hwnd,msg,wParam,MAKE_SEGPTR((void*)lParam));
+		default:
+			fprintf(stderr,"No support for 32-16 msg 0x%x\n",msg);
+	}
+	return func(hwnd,msg,wParam,MAKE_SEGPTR((void*)lParam));
+}
+
+
 extern LRESULT AboutDlgProc(HWND,UINT,WPARAM,LPARAM);
 extern LRESULT ButtonWndProc(HWND,UINT,WPARAM,LPARAM);
 extern LRESULT ColorDlgProc(HWND,UINT,WPARAM,LPARAM);
@@ -53,211 +119,143 @@
 extern LRESULT ScrollBarWndProc(HWND,UINT,WPARAM,LPARAM);
 extern LRESULT StaticWndProc(HWND,UINT,WPARAM,LPARAM);
 extern LRESULT SystemMessageBoxProc(HWND,UINT,WPARAM,LPARAM);
+extern LRESULT ComboLBoxWndProc(HWND,UINT,WPARAM,LPARAM);
 
 LRESULT USER32_DefWindowProcA(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return DefWindowProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return DefWindowProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(DefWindowProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT ButtonWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return ButtonWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return ButtonWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(ButtonWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT StaticWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return StaticWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return StaticWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(StaticWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT ScrollBarWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return ScrollBarWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return ScrollBarWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(ScrollBarWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT ListBoxWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return ListBoxWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return ListBoxWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(ListBoxWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT ComboBoxWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return ComboBoxWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return ComboBoxWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(ComboBoxWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT EditWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return EditWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return EditWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(EditWndProc,(HWND)hwnd, msg, wParam,lParam);
 }
 
 LRESULT PopupMenuWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return PopupMenuWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return PopupMenuWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(PopupMenuWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT DesktopWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return DesktopWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return DesktopWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(DesktopWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT DefDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return DefDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return DefDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(DefDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT MDIClientWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return MDIClientWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return MDIClientWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(MDIClientWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT DefWindowProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return DefWindowProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return DefWindowProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(DefWindowProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT DefMDIChildProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return DefMDIChildProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return DefMDIChildProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(DefMDIChildProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT SystemMessageBoxProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return SystemMessageBoxProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return SystemMessageBoxProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(SystemMessageBoxProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT FileOpenDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return FileOpenDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return FileOpenDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(FileOpenDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT FileSaveDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return FileSaveDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return FileSaveDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(FileSaveDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT ColorDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return ColorDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return ColorDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(ColorDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT FindTextDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return FindTextDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return FindTextDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(FindTextDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT ReplaceTextDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return ReplaceTextDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return ReplaceTextDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(ReplaceTextDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT PrintSetupDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return PrintSetupDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return PrintSetupDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(PrintSetupDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT PrintDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return PrintDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return PrintDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(PrintDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT AboutDlgProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return AboutDlgProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return AboutDlgProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(AboutDlgProc,(HWND)hwnd, msg, wParam, lParam);
 }
 
 LRESULT ComboLBoxWndProc32(DWORD hwnd, DWORD msg, DWORD wParam, DWORD lParam)
 
 {
-    if (UsesLParamPtr(msg))
-	return ComboLBoxWndProc((HWND)hwnd, msg, wParam, MAKE_SEGPTR((void *)lParam));
-    else
-	return ComboLBoxWndProc((HWND)hwnd, msg, wParam, lParam);
+	return WIN32_CallWindowProcTo16(ComboLBoxWndProc,(HWND)hwnd, msg, wParam, lParam);
 }
 #endif
diff --git a/windows/dce.c b/windows/dce.c
index 04d90ae..ed9c8b2 100644
--- a/windows/dce.c
+++ b/windows/dce.c
@@ -146,30 +146,28 @@
 static HRGN DCE_ClipWindows( HWND hwndStart, HWND hwndEnd,
                              HRGN hrgn, int xoffset, int yoffset )
 {
-    HRGN hrgnTmp = 0, hrgnNew = 0;
+    HRGN hrgnNew;
     WND *wndPtr;
 
     if (!hwndStart) return hrgn;
+    if (!(hrgnNew = CreateRectRgn( 0, 0, 0, 0 )))
+    {
+        if (hrgn) DeleteObject( hrgn );
+        return 0;
+    }
     for (; hwndStart != hwndEnd; hwndStart = wndPtr->hwndNext)
     {
-        hrgnTmp = hrgnNew = 0;
         wndPtr = WIN_FindWndPtr( hwndStart );
         if (!(wndPtr->dwStyle & WS_VISIBLE)) continue;
-        if (!(hrgnTmp = CreateRectRgn( 0, 0, 0, 0 ))) break;
-        if (!(hrgnNew = CreateRectRgn( wndPtr->rectWindow.left + xoffset,
-                                       wndPtr->rectWindow.top + yoffset,
-                                       wndPtr->rectWindow.right + xoffset,
-                                       wndPtr->rectWindow.bottom + yoffset )))
-            break;
-        if (!CombineRgn( hrgnTmp, hrgn, hrgnNew, RGN_DIFF )) break;
-        DeleteObject( hrgn );
-        DeleteObject( hrgnNew );
-        hrgn = hrgnTmp;
+        SetRectRgn( hrgnNew, wndPtr->rectWindow.left + xoffset,
+                    wndPtr->rectWindow.top + yoffset,
+                    wndPtr->rectWindow.right + xoffset,
+                    wndPtr->rectWindow.bottom + yoffset );
+        if (!CombineRgn( hrgn, hrgn, hrgnNew, RGN_DIFF )) break;
     }
     if (hwndStart != hwndEnd)  /* something went wrong */
     {
-        if (hrgnTmp) DeleteObject( hrgnTmp );
-        if (hrgnNew) DeleteObject( hrgnNew );
+        DeleteObject( hrgnNew );
         if (hrgn) DeleteObject( hrgn );
         return 0;
     }
@@ -380,14 +378,8 @@
 
     if ((flags & DCX_INTERSECTRGN) || (flags & DCX_EXCLUDERGN))
     {
-	HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
-	if (hrgn)
-	{
-            CombineRgn( hrgn, hrgnVisible, hrgnClip,
-                       (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
-	    DeleteObject( hrgnVisible );
-            hrgnVisible = hrgn;
-	}
+        CombineRgn( hrgnVisible, hrgnVisible, hrgnClip,
+                    (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
     }
     SelectVisRgn( hdc, hrgnVisible );
     DeleteObject( hrgnVisible );
diff --git a/windows/graphics.c b/windows/graphics.c
index 741b49f..ab5cdcc 100644
--- a/windows/graphics.c
+++ b/windows/graphics.c
@@ -659,6 +659,9 @@
     oldDrawMode = SetROP2(hdc, R2_XORPEN);
     oldBkMode = SetBkMode(hdc, TRANSPARENT);
 
+    /* Hack: make sure the XORPEN operation has an effect */
+    dc->u.x.pen.pixel = (1 << screenDepth) - 1;
+
     if (DC_SetupGCForPen( dc ))
 	XDrawRectangle( display, dc->u.x.drawable, dc->u.x.gc,
 		        dc->w.DCOrgX + left, dc->w.DCOrgY + top,
diff --git a/windows/mdi.c b/windows/mdi.c
index 7ed6727..37ba8f7 100644
--- a/windows/mdi.c
+++ b/windows/mdi.c
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <math.h>
+#include "xmalloc.h"
 #include "windows.h"
 #include "win.h"
 #include "nonclient.h"
@@ -117,7 +118,7 @@
  MDICLIENTINFO  *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
  WND    	*wndPtr     = WIN_FindWndPtr(hWndChild);
  LPSTR		 lpWndText;
- INT		 index      = 0,id,n;
+ UINT		 index      = 0,id,n;
 
  if( !clientInfo->nActiveChildren ||
      !clientInfo->hWindowMenu ) return 0;
@@ -198,17 +199,71 @@
 
 /**********************************************************************
  *					MDISetMenu
- * FIXME: This is not complete.
  */
 HMENU MDISetMenu(HWND hwnd, BOOL fRefresh, HMENU hmenuFrame, HMENU hmenuWindow)
 {
-    dprintf_mdi(stddeb, "WM_MDISETMENU: "NPFMT" %04x "NPFMT" "NPFMT"\n", hwnd, fRefresh, hmenuFrame, hmenuWindow);
-    if (!fRefresh) {
+    WND           *w         = WIN_FindWndPtr(hwnd);
+    MDICLIENTINFO *ci;
+
+    dprintf_mdi(stddeb, "WM_MDISETMENU: "NPFMT" %04x "NPFMT" "NPFMT"\n",
+                hwnd, fRefresh, hmenuFrame, hmenuWindow);
+
+    ci = (MDICLIENTINFO *) w->wExtra;
+
+    if (!fRefresh) 
+       {
 	HWND hwndFrame = GetParent(hwnd);
 	HMENU oldFrameMenu = GetMenu(hwndFrame);
-	SetMenu(hwndFrame, hmenuFrame);
-	return oldFrameMenu;
-    }
+        
+	if( ci->flagChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
+	    MDI_RestoreFrameMenu(w->hwndParent, ci->flagChildMaximized );
+
+	if( hmenuWindow && hmenuWindow!=ci->hWindowMenu )
+	  {
+	    /* delete menu items from ci->hWindowMenu 
+	     * and add them to hmenuWindow */
+
+            INT		i = GetMenuItemCount(ci->hWindowMenu) - 1;
+	    INT 	pos = GetMenuItemCount(hmenuWindow) + 1;
+
+            AppendMenu(hmenuWindow,MF_SEPARATOR,0,(SEGPTR)0);
+
+	    if( ci->nActiveChildren )
+	      {
+	        INT  j = i - ci->nActiveChildren + 1;
+		char buffer[100];
+		UINT id,state;
+
+		for( ; i >= j ; i-- )
+		   {
+		     id = GetMenuItemID(ci->hWindowMenu,i );
+		     state = GetMenuState(ci->hWindowMenu,i,MF_BYPOSITION); 
+
+		     GetMenuString(ci->hWindowMenu, i, buffer, 100, MF_BYPOSITION);
+
+		     DeleteMenu(ci->hWindowMenu, i , MF_BYPOSITION);
+		     InsertMenu(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
+					     id, MAKE_SEGPTR(buffer));
+		     CheckMenuItem(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
+		   }
+	      }
+
+	    /* remove separator */
+	    DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION); 
+
+	    ci->hWindowMenu = hmenuWindow;
+	  } 
+
+	if( hmenuFrame && hmenuFrame!=oldFrameMenu)
+	  {
+	    SetMenu(hwndFrame, hmenuFrame);
+	    if( ci->flagChildMaximized )
+	        MDI_AugmentFrameMenu(ci, 
+                    w->hwndParent, ci->flagChildMaximized );
+	    return oldFrameMenu;
+	  }
+
+       }
     return 0;
 }
 
@@ -236,11 +291,12 @@
     HWND hwnd;
     WORD	     wIDmenu = ci->idFirstChild + ci->nActiveChildren;
     int spacing;
-    char	     chDef = '\0';
+    char*	     lpstrDef="junk!";
 
     /*
      * Create child window
      */
+
     cs->style &= (WS_MINIMIZE | WS_MAXIMIZE | WS_HSCROLL | WS_VSCROLL);
 
 				/* The child windows should probably  */
@@ -250,8 +306,10 @@
     cs->y = ci->nActiveChildren * spacing;
 
     /* this menu is needed to set a check mark in MDI_ChildActivate */
-    AppendMenu(ci->hWindowMenu ,MF_STRING ,wIDmenu, MAKE_SEGPTR(&chDef) );
+    AppendMenu(ci->hWindowMenu ,MF_STRING ,wIDmenu, MAKE_SEGPTR(lpstrDef) );
 
+    ci->nActiveChildren++;
+ 
     hwnd = CreateWindow( cs->szClass, cs->szTitle,
 			  WS_CHILD | WS_BORDER | WS_CAPTION | WS_CLIPSIBLINGS |
 			  WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU |
@@ -262,12 +320,14 @@
 
     if (hwnd)
     {
-	ci->nActiveChildren++;
 	MDI_MenuModifyItem(w ,hwnd); 
-
+        dprintf_mdi(stddeb, "MDICreateChild: created child - "NPFMT"\n",hwnd);
     }
     else
+    {
+       ci->nActiveChildren--;
 	DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
+    }
 	
     return hwnd;
 }
@@ -373,7 +433,7 @@
 	
         ci->nActiveChildren--;
 
-	/* WM_MDISETMENU ? */
+        dprintf_mdi(stddeb,"MDIDestroyChild: child destroyed - "NPFMT"\n",child);
 
         if (flagDestroy)
 	   {
@@ -499,22 +559,8 @@
     childWnd  =  WIN_FindWndPtr( listTop->hChild );
     while( childWnd && childWnd->hwndNext )
     {
-	listNext = (MDIWCL*)malloc(sizeof(MDIWCL));
+	listNext = (MDIWCL*)xmalloc(sizeof(MDIWCL));
 	
-	if( !listNext )
-	{
-	    /* quit gracefully */
-	    listNext = listTop->prev;
-	    while( listTop )
-	    {
-                listNext = listTop->prev;
-                free(listTop);
-                listTop  = listNext;
-	    }
-	    dprintf_mdi(stddeb,"MDICascade: allocation failed\n");
-	    return NULL;
-	}
-    
 	if( (childWnd->dwStyle & WS_DISABLED) ||
 	    (childWnd->dwStyle & WS_MINIMIZE) ||
 	    !(childWnd->dwStyle & WS_VISIBLE)   )
@@ -921,6 +967,7 @@
 	ci->hWindowMenu         = ccs->hWindowMenu;
 	ci->idFirstChild        = ccs->idFirstChild;
 	ci->flagChildMaximized  = 0;
+	ci->nActiveChildren	= 0;
 	ci->hFrameTitle		= frameWnd->hText;
 	ci->sbStop		= 0;
 	ci->self		= hwnd;
@@ -937,6 +984,8 @@
 	NC_HandleNCCalcSize(hwnd, (NCCALCSIZE_PARAMS*) &rect);
 	w->rectClient = rect;
 
+	dprintf_mdi(stddeb,"MDI: Client created - hwnd = "NPFMT", idFirst = %u\n",hwnd,ci->idFirstChild);
+
 	return 0;
       
       case WM_DESTROY:
diff --git a/windows/nonclient.c b/windows/nonclient.c
index 15fbcf7..917de6c 100644
--- a/windows/nonclient.c
+++ b/windows/nonclient.c
@@ -1075,9 +1075,9 @@
     SendMessage( hwnd, WM_EXITSIZEMOVE, 0, 0 );
     SendMessage( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
 
-    /* Single click brings up the system menu */
+    /* Single click brings up the system menu when iconized */
 
-    if (!moved)
+    if (!moved && (wndPtr->dwStyle & WS_MINIMIZE))
     {
         NC_TrackSysMenu( hwnd, hdc, pt );
         return;
diff --git a/windows/painting.c b/windows/painting.c
index 2e4c2b4..1c2b06a 100644
--- a/windows/painting.c
+++ b/windows/painting.c
@@ -133,7 +133,7 @@
  */
 BOOL RedrawWindow( HWND hwnd, LPRECT rectUpdate, HRGN hrgnUpdate, UINT flags )
 {
-    HRGN tmpRgn, hrgn;
+    HRGN hrgn;
     RECT rectClient;
     WND * wndPtr;
 
@@ -159,13 +159,10 @@
     {
         if (wndPtr->hrgnUpdate)  /* Is there already an update region? */
         {
-            tmpRgn = CreateRectRgn( 0, 0, 0, 0 );
             if ((hrgn = hrgnUpdate) == 0)
                 hrgn = CreateRectRgnIndirect( rectUpdate ? rectUpdate :
                                               &rectClient );
-            CombineRgn( tmpRgn, wndPtr->hrgnUpdate, hrgn, RGN_OR );
-            DeleteObject( wndPtr->hrgnUpdate );
-            wndPtr->hrgnUpdate = tmpRgn;
+            CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hrgn, RGN_OR );
             if (!hrgnUpdate) DeleteObject( hrgn );
         }
         else  /* No update region yet */
@@ -197,17 +194,14 @@
             }
             else
             {
-                tmpRgn = CreateRectRgn( 0, 0, 0, 0 );
                 if ((hrgn = hrgnUpdate) == 0)
                     hrgn = CreateRectRgnIndirect( rectUpdate );
-                if (CombineRgn( tmpRgn, wndPtr->hrgnUpdate,
+                if (CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate,
                                 hrgn, RGN_DIFF ) == NULLREGION)
                 {
-                    DeleteObject( tmpRgn );
-                    tmpRgn = 0;
+                    DeleteObject( wndPtr->hrgnUpdate );
+                    wndPtr->hrgnUpdate = 0;
                 }
-                DeleteObject( wndPtr->hrgnUpdate );
-                wndPtr->hrgnUpdate = tmpRgn;
                 if (!hrgnUpdate) DeleteObject( hrgn );
             }
             if (!wndPtr->hrgnUpdate)  /* No more update region */
diff --git a/windows/scroll.c b/windows/scroll.c
index 4aa0fce..95a88e8 100644
--- a/windows/scroll.c
+++ b/windows/scroll.c
@@ -182,16 +182,10 @@
         HRGN hrgnInv = SCROLL_TraceChildren(hwnd,dx,dy,DCX_CLIPCHILDREN |
 						       DCX_CLIPSIBLINGS );
         if( hrgnInv )
- 	  {
-	    HRGN hrgnCombine = CreateRectRgn(0,0,0,0);
-
-	    CombineRgn(hrgnCombine,hrgnInv,hrgnUpdate,RGN_OR);
-	    dprintf_scroll(stddeb,"ScrollWindow: hrgnComb="NPFMT" hrgnInv="NPFMT" hrgnUpd="NPFMT"\n",
-	 					           hrgnCombine,hrgnInv,hrgnUpdate);
-
-	    DeleteObject(hrgnUpdate); DeleteObject(hrgnInv);
-	    hrgnUpdate = hrgnCombine;
-	  }
+        {
+	    CombineRgn(hrgnUpdate,hrgnInv,hrgnUpdate,RGN_OR);
+            DeleteObject(hrgnInv);
+        }
 
         RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW);
       }
diff --git a/windows/win.c b/windows/win.c
index 697bef1..a6609a8 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -306,7 +306,7 @@
 {
     HANDLE class, hwnd;
     CLASS *classPtr;
-    WND *wndPtr, *parentWndPtr;
+    WND *wndPtr;
     POINT maxSize, maxPos, minTrack, maxTrack;
     CREATESTRUCT createStruct;
     int wmcreate;
@@ -1207,13 +1207,17 @@
 static BOOL WIN_EnumChildWin(HWND hwnd, FARPROC wndenumprc, LPARAM lParam)
 {
     WND *wndPtr;
+    HWND hwndN,hwndCh;
 
     while (hwnd)
     {
         if (!(wndPtr=WIN_FindWndPtr(hwnd))) return 0;
+        hwndN=wndPtr->hwndNext;		/* storing hwnd is a way to avoid.. */
+        hwndCh=wndPtr->hwndChild;		/* ..side effects after wndenumprc  */
         if (!CallEnumWindowsProc( wndenumprc, hwnd, lParam )) return 0;
-        if (!WIN_EnumChildWin(wndPtr->hwndChild, wndenumprc, lParam)) return 0;
-        hwnd=wndPtr->hwndNext;
+        if (IsWindow(hwndCh))			/* to prevent too early termination */
+         if (!WIN_EnumChildWin(hwndCh, wndenumprc, lParam)) return 0;
+        hwnd=hwndN;
     } 
     return 1;
 }