Release 980809

Sat Aug  8 19:11:46 1998  Marcus Meissner <marcus@jet.franken.de>

 	* [*/*]
	Added some missing WINAPI and some missing prototypes for
	functions.

	* [controls/static.c]
	Got rid of the MODULE32_LookupHMODULE error showing up for every
	message box.

	* [windows/winproc.c]
	WM_NOTIFY 16->32 mapping (AOL Instant Messenger or however it is called).

	* [misc/winsock.c]
	hostent/servent/protoent should not use the same static buffers.
	(has broken nt3.15 finger.exe which does hp=gethostbyname(), then
	getservbyname("finger","tcp") and the references hp->h_addr_list[0]).

Sat Aug  8 13:21:24 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [include/server.h] [tools/make_requests] [server/request.c]
	  [server/trace.c]
	Automated part of the client/server request code generation.
	Added tracing of client/server communication.

	* [scheduler/*.c] [server/process.c]
	Added support for server-side handles.

	* [scheduler/thread.c]
	Added DLL_THREAD_ATTACH/DETACH notifications.

	* [configure.in]
	Added check for -lsocket.

	* [windows/winproc.c]
	Return the thunk address in WINPROC_GetProc if the function types
	don't match.

Sat Aug  8 02:44:04 1998  Douglas Ridgway  <ridgway@winehq.com>

	* [windows/winproc.c][windows/win.c][windows/message.c]  
	Documentation for CallWindowProc, SetWindowLong, DispatchMessage,
	WaitMessage, GetMessage, and PeekMessage.

Sat Aug  8 01:00:00 1998  Juergen Schmied <juergen.schmied@metronet.de>

	* [controls/commctrl.c][controls/widgets.c][include/builtin32.h]
	  [include/commctrl.h][relay32/builtin32.c][relay32/comctl32.spec]
	  [tools/build.c] [relay32/shell32.spec]
	Added the functionality of the LibMain function. The common 
	controls are properly initialized now.

	* [controls/treeview.c][memory/atom.c][scheduler/thread.c][windows/class.c]
	  [windows/msgbox.c][windows/win.c]
	Put TRACE in, put SetLastError() in.

	* [include/interfaces.h]
	Added IClassFactory::LockServer.

	* [include/ole2.h]
	Added struct for LPOLEMENUGROUPWIDTHS32, HOLEMENU32.

	* [include/shell.h][include/shlobj.h][misc/shell.c][ole/folders.c]
	Reorganized and many structs and classes (IShellBrowser,IShellView)
	added. shell32.dll should work in many cases now.
	Started SHGetFileInfoA implementeation, rewrote SHGetPathFromIDList32A.
	New Shell32LibMain started ShellIconCache Implementation.

	* [misc/shellord.c]
	Rewrote ILCombine, ILGetSize
	New stubs SHFind_InitMenuPopup, FileMenu_Create, ShellExecuteEx,
	SHSetInstanceExplorer, SHGetInstanceExplorer, SHFreeUnusedLibraries.

	* [include/winerror.h]
	Class and window related error codes added.

	* [memory/heap.c]
	Changed lstrlen32A to strlen to get rid of milions of TRACE lines.

	* [misc/ddeml.c]
	First lines for DdeCreateStringHandle32A / DdeFreeStringHandle32.

	* [misc/network.c][relay32/mpr.spec]
	Fixed some bugs, changed ordinals.

	* [windows/class.c]
	Workarounds for incorrect hInstance handling. Fixes parts of
	MSWord95/Excel95 and Money95.

Thu Aug  6 21:05:35 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [windows/nonclient.c][misc/tweak.c][include/tweak.h]
	  [documentation/win95look]
	Removed some tweak variables. They are no longer needed.

	* [files/dos_fs.c]
	Added check for null pointer in DOSFS_GetDevice().

	* [controls/tooltips.c][include/commctrl.h]
	Improved tooltips.

	* [controls/status.c][include/commctrl.h]
	Cleaned up code and added tooltip support.

	* [controls/toolbar.c][include/commctrl.h]
	Added tooltip support.

	* [documentation/common_controls]
	Updated.

Thu Aug  6 00:05:22 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [include/ver.h] [misc/ver.c]
	Write VIF_BUFFTOOSMALL, not VIF_BUFTOSMALL.

	* [debugger/hash.c] [debugger/stabs.c]
	Make debug output more friendly for posting.

	* [files/file.c]
	Partial implementation of OF_SHARE_EXCLUSIVE.
	Needed for Quicklogic/QuickChip (InstallShield).

	* [files/profile.c]
	When a cached-only entry is found, return it.

	* [graphics/x11drv/xfont.c]
	Accept a space as delimiter for a fontname and inhibit overrun
	(Make xplasim.ex from the Phillips Coolrunner CPLD suite proceed).

	* [miscemu/main.c]
	Delay setting IF1632_CallLargeStack after loading the executables.
	Stops fpgaexp.exe from the Viewlogic FPGA suite from crashing when
 	showing the Blinker error Message Box.

	* [misc/network.c]
	Make WNetGetConnection16 recognise a CDROM as a local drive.

	* [multimedia/mmsystem.c]
	Preliminary check for MCI_ALL_DEVICE_ID in MCI_Close by a FIXME.


Tue Aug 4 21:15:23 1998  James Juran <jrj120@psu.edu>

	* [ole/ole2nls.c]
	Fixed bug in CompareString32A.  strcmp() doesn't necessarily
	return -1, 0, or 1, which the previous code depended on.
	Changed name of is_punctuation to OLE2NLS_isPunctuation.
	Made NORM_IGNOREWIDTH not print a FIXME message in 
	LCMapString32A.
	Other debugging messages, documentation, and code cleanups.

	* [objects/font.c] [relay32/gdi32.spec] [include/winerror.h]
	Added stub for GetFontData32, and added GDI_ERROR constant 
	to winerror.h.

Tue Aug  4 07:44:43 1998  Ove Kaaven <ovek@arcticnet.no>

	* [multimedia/mmio.c]
	Implemented mmioSetBuffer, mmioAdvance, mmioAscend, and
	mmioCreateChunk to the best of my knowledge. But watch out,
	there's bound to be bugs in there...

	* [include/mmsystem.h] [multimedia/mmsystem.c]
	Hacked in support for 32-bit multimedia function callbacks.

	* [AUTHORS] [misc/shell.c]
	Selfishly credited my authorship. Hopefully I'm excused.

	* [include/dosexe.h] [include/module.h] [loader/dos/*]
	  [loader/module.c] [loader/task.c] [Makefile.in]
	  [configure.in] [Makefile.in]
	Added DOS EXE (MZ) loader and virtual machine. Task
	structure integration thanks to Ulrich Weigand.

	* [files/dos_fs.c]
	Work around a null pointer dereference if ioctlGetDeviceInfo-ing
	a FILE_DupUnixHandle'd file (i.e. GetStdHandle'd).

	* [include/miscemu.h] [include/winnt.h] [loader/main.c]
	  [memory/global.c] [msdos/dpmi.c] [msdos/dosmem.c]
	Added support for DOS memory images, and added
	DOSMEM_ResizeBlock() and DOSMEM_Available().

	* [msdos/int21.c]
	Added support for the DOS virtual machine, tweaked handle
	assignment to avoid stdio clashes, forced INT21_FindNext to exit
	wildcardless searches after finding one entry, added AH=7, 8, 9,
	C, 48, 49, 4A, and 7160 CL=1 (Get Short Filename), and made the
	long filename calls only respond if running with with -winver
	win95.

	* [objects/cursoricon.c]
	DestroyCursor32 and DestroyIcon32 should now free the objects
	(hopefully) correctly.

Sun Aug  2 21:42:09 1998  Huw D M Davies <daviesh@abacus.physics.ox.ac.uk>

	* [graphics/psdrv/*] [include/psdrv.h]
	Added PPD file parsing - at the moment it reads a file called
	default.ppd from the directory in which you start Wine. Page sizes
	other than A4 should now work (landscape may not). All fonts that are
	present on your printer (according to the PPD) should be available,
	providing you have the AFM files. Fonts should now be the correct size.
	Graphics is still basically lines only. See graphics/psdrv/README .

	* [misc/printdrv.c]
	Yet more Drv[Get/Set]PrinterData fixes.

Fri Jul 31 21:33:22 1998  Per Lindström <pelinstr@algonet.se>

	* [relay32/crtdll.spec] [misc/crtdll.c]
	Added stub for freopen, _findfirst, _findnext, _fstat and _read.

	* [files/directory.c]
	Modified warning message.

Wed Jul 29 11:25:28 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>

	* [objects/font.c]
	Added stub for GetFontData.

	* [multimedia/msvideo.c]
	Created this file to hold the msvideo.dll calls (and maybe also
	msvfw32.dll). 

	* [objects/cursoricon.c]
	Added search in Global Heap for cursor when trying to destroy it
	with DestroyCursor16. This test should be done in many (all?)
	other functions that use FreeResource.

	* [controls/treeview.c] [include/commctrl.h]
	Minor correction in name and addition of many placeholders for TVM
	messages in TREEVIEW_WindowProc.

	* [msdos/dpmi.c]
	Fixed a bug in DPMI_xrealloc where in a copy of a memory region
	"A" of size "a" to a region "B" of size "b", "b" bytes were being
	copied, instead of "a", as the new version does. This both
	increases speed, as well as avoids segfaults.
diff --git a/ANNOUNCE b/ANNOUNCE
index d5b81f6..303c5bd 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,14 +1,16 @@
-This is release 980726 of Wine, the MS Windows emulator.  This is still a
+This is release 980809 of Wine, the MS Windows emulator.  This is still a
 developer's only release.  There are many bugs and many unimplemented API
 features.  Most applications still do not work correctly.
 
 Patches should be submitted to "julliard@lrc.epfl.ch".  Please don't
 forget to include a ChangeLog entry.
 
-WHAT'S NEW with Wine-980726: (see ChangeLog for details)
-	- Still more common controls stuff.
-	- More DirectDraw support.
-	- Compilation problems should be gone.
+WHAT'S NEW with Wine-980809: (see ChangeLog for details)
+	- Preliminary DOS executables support.
+	- Postscript driver improvements.
+	- More client/server stuff.
+	- Better shell32.dll builtin support.
+	- Proper Win16 mutex locking.
 	- Lots of bug fixes.
 
 See the README file in the distribution for installation instructions.
@@ -17,10 +19,10 @@
 the release is available at the ftp sites.  The sources will be available
 from the following locations:
 
-  ftp://sunsite.unc.edu/pub/Linux/ALPHA/wine/development/Wine-980726.tar.gz
-  ftp://tsx-11.mit.edu/pub/linux/ALPHA/Wine/development/Wine-980726.tar.gz
-  ftp://ftp.infomagic.com/pub/mirrors/linux/sunsite/ALPHA/wine/development/Wine-980726.tar.gz
-  ftp://ftp.progsoc.uts.edu.au/pub/Wine/development/Wine-980726.tar.gz
+  ftp://sunsite.unc.edu/pub/Linux/ALPHA/wine/development/Wine-980809.tar.gz
+  ftp://tsx-11.mit.edu/pub/linux/ALPHA/Wine/development/Wine-980809.tar.gz
+  ftp://ftp.infomagic.com/pub/mirrors/linux/sunsite/ALPHA/wine/development/Wine-980809.tar.gz
+  ftp://ftp.progsoc.uts.edu.au/pub/Wine/development/Wine-980809.tar.gz
 
 It should also be available from any site that mirrors tsx-11 or sunsite.
 
diff --git a/AUTHORS b/AUTHORS
index 04c6de34..87e0804 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -64,6 +64,7 @@
 Alex Korobka,
 Greg Kreider,
 Anand Kumria,
+Ove Kåven,
 Scott A. Laird,
 David Lee Lambert,
 Andrew Lewycky,
diff --git a/BUGS b/BUGS
index 9f08c48..e7113ad 100644
--- a/BUGS
+++ b/BUGS
@@ -73,6 +73,10 @@
 
  * AllocCSToDSAlias() shouldn't alloc alias for the same segment multiple
    times.
+ 
+ * Some programs expect that menu window handles stay the same all the time.
+   (chemdraw). This implies that the menu popupwindows are just hidden, not
+   destroyed in real Windows.
 
 Where to look in source files:
 
diff --git a/ChangeLog b/ChangeLog
index 955ee95..bd9cb45 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,261 @@
 ----------------------------------------------------------------------
+Sun Aug  9 13:21:35 1998  Andreas Mohr <100.30936@germany.net>
+
+	* [loader/ne/module.c] [if1632/kernel.spec]
+	Added the undocumented HIWORD of GetModuleHandle (hFirstModule).
+
+	* [loader/ne/segment.c]
+	Wine forgot to set some NE_SEGFLAGS_*.
+	Combined with another loader change, this fixed the
+	"BLINKER -- error in loading module" or ghost MessageBox problem
+	that about 1% of all Windows programs have.
+	Some BLINKER programs still don't work, though.
+	But I'm working on it, with great help from Blinkinc.
+
+	* [loader/task.c]
+	InitTask needs to decrement the SP register by two as Win95 does.
+
+Sat Aug  8 19:11:46 1998  Marcus Meissner <marcus@jet.franken.de>
+
+ 	* [*/*]
+	Added some missing WINAPI and some missing prototypes for
+	functions.
+
+	* [controls/static.c]
+	Got rid of the MODULE32_LookupHMODULE error showing up for every
+	message box.
+
+	* [windows/winproc.c]
+	WM_NOTIFY 16->32 mapping (AOL Instant Messenger or however it is called).
+
+	* [misc/winsock.c]
+	hostent/servent/protoent should not use the same static buffers.
+	(has broken nt3.15 finger.exe which does hp=gethostbyname(), then
+	getservbyname("finger","tcp") and the references hp->h_addr_list[0]).
+
+Sat Aug  8 13:21:24 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>
+
+	* [include/server.h] [tools/make_requests] [server/request.c]
+	  [server/trace.c]
+	Automated part of the client/server request code generation.
+	Added tracing of client/server communication.
+
+	* [scheduler/*.c] [server/process.c]
+	Added support for server-side handles.
+
+	* [scheduler/thread.c]
+	Added DLL_THREAD_ATTACH/DETACH notifications.
+
+	* [configure.in]
+	Added check for -lsocket.
+
+	* [windows/winproc.c]
+	Return the thunk address in WINPROC_GetProc if the function types
+	don't match.
+
+Sat Aug  8 02:44:04 1998  Douglas Ridgway  <ridgway@winehq.com>
+
+	* [windows/winproc.c][windows/win.c][windows/message.c]  
+	Documentation for CallWindowProc, SetWindowLong, DispatchMessage,
+	WaitMessage, GetMessage, and PeekMessage.
+
+Sat Aug  8 01:00:00 1998  Juergen Schmied <juergen.schmied@metronet.de>
+
+	* [controls/commctrl.c][controls/widgets.c][include/builtin32.h]
+	  [include/commctrl.h][relay32/builtin32.c][relay32/comctl32.spec]
+	  [tools/build.c] [relay32/shell32.spec]
+	Added the functionality of the LibMain function. The common 
+	controls are properly initialized now.
+
+	* [controls/treeview.c][memory/atom.c][scheduler/thread.c][windows/class.c]
+	  [windows/msgbox.c][windows/win.c]
+	Put TRACE in, put SetLastError() in.
+
+	* [include/interfaces.h]
+	Added IClassFactory::LockServer.
+
+	* [include/ole2.h]
+	Added struct for LPOLEMENUGROUPWIDTHS32, HOLEMENU32.
+
+	* [include/shell.h][include/shlobj.h][misc/shell.c][ole/folders.c]
+	Reorganized and many structs and classes (IShellBrowser,IShellView)
+	added. shell32.dll should work in many cases now.
+	Started SHGetFileInfoA implementeation, rewrote SHGetPathFromIDList32A.
+	New Shell32LibMain started ShellIconCache Implementation.
+
+	* [misc/shellord.c]
+	Rewrote ILCombine, ILGetSize
+	New stubs SHFind_InitMenuPopup, FileMenu_Create, ShellExecuteEx,
+	SHSetInstanceExplorer, SHGetInstanceExplorer, SHFreeUnusedLibraries.
+
+	* [include/winerror.h]
+	Class and window related error codes added.
+
+	* [memory/heap.c]
+	Changed lstrlen32A to strlen to get rid of milions of TRACE lines.
+
+	* [misc/ddeml.c]
+	First lines for DdeCreateStringHandle32A / DdeFreeStringHandle32.
+
+	* [misc/network.c][relay32/mpr.spec]
+	Fixed some bugs, changed ordinals.
+
+	* [windows/class.c]
+	Workarounds for incorrect hInstance handling. Fixes parts of
+	MSWord95/Excel95 and Money95.
+
+Thu Aug  6 21:05:35 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>
+
+	* [windows/nonclient.c][misc/tweak.c][include/tweak.h]
+	  [documentation/win95look]
+	Removed some tweak variables. They are no longer needed.
+
+	* [files/dos_fs.c]
+	Added check for null pointer in DOSFS_GetDevice().
+
+	* [controls/tooltips.c][include/commctrl.h]
+	Improved tooltips.
+
+	* [controls/status.c][include/commctrl.h]
+	Cleaned up code and added tooltip support.
+
+	* [controls/toolbar.c][include/commctrl.h]
+	Added tooltip support.
+
+	* [documentation/common_controls]
+	Updated.
+
+Thu Aug  6 00:05:22 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>
+
+	* [include/ver.h] [misc/ver.c]
+	Write VIF_BUFFTOOSMALL, not VIF_BUFTOSMALL.
+
+	* [debugger/hash.c] [debugger/stabs.c]
+	Make debug output more friendly for posting.
+
+	* [files/file.c]
+	Partial implementation of OF_SHARE_EXCLUSIVE.
+	Needed for Quicklogic/QuickChip (InstallShield).
+
+	* [files/profile.c]
+	When a cached-only entry is found, return it.
+
+	* [graphics/x11drv/xfont.c]
+	Accept a space as delimiter for a fontname and inhibit overrun
+	(Make xplasim.ex from the Phillips Coolrunner CPLD suite proceed).
+
+	* [miscemu/main.c]
+	Delay setting IF1632_CallLargeStack after loading the executables.
+	Stops fpgaexp.exe from the Viewlogic FPGA suite from crashing when
+ 	showing the Blinker error Message Box.
+
+	* [misc/network.c]
+	Make WNetGetConnection16 recognise a CDROM as a local drive.
+
+	* [multimedia/mmsystem.c]
+	Preliminary check for MCI_ALL_DEVICE_ID in MCI_Close by a FIXME.
+
+
+Tue Aug 4 21:15:23 1998  James Juran <jrj120@psu.edu>
+
+	* [ole/ole2nls.c]
+	Fixed bug in CompareString32A.  strcmp() doesn't necessarily
+	return -1, 0, or 1, which the previous code depended on.
+	Changed name of is_punctuation to OLE2NLS_isPunctuation.
+	Made NORM_IGNOREWIDTH not print a FIXME message in 
+	LCMapString32A.
+	Other debugging messages, documentation, and code cleanups.
+
+	* [objects/font.c] [relay32/gdi32.spec] [include/winerror.h]
+	Added stub for GetFontData32, and added GDI_ERROR constant 
+	to winerror.h.
+
+Tue Aug  4 07:44:43 1998  Ove Kaaven <ovek@arcticnet.no>
+
+	* [multimedia/mmio.c]
+	Implemented mmioSetBuffer, mmioAdvance, mmioAscend, and
+	mmioCreateChunk to the best of my knowledge. But watch out,
+	there's bound to be bugs in there...
+
+	* [include/mmsystem.h] [multimedia/mmsystem.c]
+	Hacked in support for 32-bit multimedia function callbacks.
+
+	* [AUTHORS] [misc/shell.c]
+	Selfishly credited my authorship. Hopefully I'm excused.
+
+	* [include/dosexe.h] [include/module.h] [loader/dos/*]
+	  [loader/module.c] [loader/task.c] [Makefile.in]
+	  [configure.in] [Makefile.in]
+	Added DOS EXE (MZ) loader and virtual machine. Task
+	structure integration thanks to Ulrich Weigand.
+
+	* [files/dos_fs.c]
+	Work around a null pointer dereference if ioctlGetDeviceInfo-ing
+	a FILE_DupUnixHandle'd file (i.e. GetStdHandle'd).
+
+	* [include/miscemu.h] [include/winnt.h] [loader/main.c]
+	  [memory/global.c] [msdos/dpmi.c] [msdos/dosmem.c]
+	Added support for DOS memory images, and added
+	DOSMEM_ResizeBlock() and DOSMEM_Available().
+
+	* [msdos/int21.c]
+	Added support for the DOS virtual machine, tweaked handle
+	assignment to avoid stdio clashes, forced INT21_FindNext to exit
+	wildcardless searches after finding one entry, added AH=7, 8, 9,
+	C, 48, 49, 4A, and 7160 CL=1 (Get Short Filename), and made the
+	long filename calls only respond if running with with -winver
+	win95.
+
+	* [objects/cursoricon.c]
+	DestroyCursor32 and DestroyIcon32 should now free the objects
+	(hopefully) correctly.
+
+Sun Aug  2 21:42:09 1998  Huw D M Davies <daviesh@abacus.physics.ox.ac.uk>
+
+	* [graphics/psdrv/*] [include/psdrv.h]
+	Added PPD file parsing - at the moment it reads a file called
+	default.ppd from the directory in which you start Wine. Page sizes
+	other than A4 should now work (landscape may not). All fonts that are
+	present on your printer (according to the PPD) should be available,
+	providing you have the AFM files. Fonts should now be the correct size.
+	Graphics is still basically lines only. See graphics/psdrv/README .
+
+	* [misc/printdrv.c]
+	Yet more Drv[Get/Set]PrinterData fixes.
+
+Fri Jul 31 21:33:22 1998  Per Lindström <pelinstr@algonet.se>
+
+	* [relay32/crtdll.spec] [misc/crtdll.c]
+	Added stub for freopen, _findfirst, _findnext, _fstat and _read.
+
+	* [files/directory.c]
+	Modified warning message.
+
+Wed Jul 29 11:25:28 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>
+
+	* [objects/font.c]
+	Added stub for GetFontData.
+
+	* [multimedia/msvideo.c]
+	Created this file to hold the msvideo.dll calls (and maybe also
+	msvfw32.dll). 
+
+	* [objects/cursoricon.c]
+	Added search in Global Heap for cursor when trying to destroy it
+	with DestroyCursor16. This test should be done in many (all?)
+	other functions that use FreeResource.
+
+	* [controls/treeview.c] [include/commctrl.h]
+	Minor correction in name and addition of many placeholders for TVM
+	messages in TREEVIEW_WindowProc.
+
+	* [msdos/dpmi.c]
+	Fixed a bug in DPMI_xrealloc where in a copy of a memory region
+	"A" of size "a" to a region "B" of size "b", "b" bytes were being
+	copied, instead of "a", as the new version does. This both
+	increases speed, as well as avoids segfaults.
+
+----------------------------------------------------------------------
 Sat Jul 25 19:45:45 1998  Juergen Schmied <juergen.schmied@metronet.de>
 
 	* [include/shlobj.h][misc/shell.c][misc/shellord.c][ole/folders.c]
diff --git a/Makefile.in b/Makefile.in
index e79008c..52a3b6a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34,6 +34,7 @@
 	library \
 	loader \
 	loader/ne \
+	loader/dos \
 	memory \
 	misc \
 	msdos \
@@ -81,6 +82,7 @@
 	ipc/ipc.o \
 	loader/loader.o \
 	loader/ne/ne.o \
+	loader/dos/dos.o \
 	memory/memory.o \
 	misc/misc.o \
 	msdos/msdos.o \
@@ -131,6 +133,7 @@
 	-mkdirhier $(libdir)
 	$(INSTALL_PROGRAM) wine $(bindir)/wine
 	$(INSTALL_DATA) wine.sym $(libdir)/wine.sym
+	$(INSTALL_PROGRAM) loader/dos/dosmod $(bindir)/dosmod
 
 install_lib: install_includes
 	$(INSTALL_DATA) $(LIB_TARGET) $(libdir)
diff --git a/README b/README
index 25be8f4..f267de1 100644
--- a/README
+++ b/README
@@ -15,7 +15,7 @@
 
 	Linux version 0.99.13 or above
 	NetBSD-current
-	FreeBSD-current or FreeBSD 1.1
+	FreeBSD-current or FreeBSD 1.1 or later
 	OpenBSD/i386 2.1 or later
 	Solaris x86 2.5 or later
 
diff --git a/configure b/configure
index 04695b2..840938e 100755
--- a/configure
+++ b/configure
@@ -2457,7 +2457,7 @@
 fi
 
 
-for ac_func in clone getpagesize memmove sigaltstack strerror stricmp tcgetattr timegm usleep wait4 waitpid vfscanf
+for ac_func in clone getpagesize memmove sendmsg sigaltstack strerror stricmp tcgetattr timegm usleep wait4 waitpid vfscanf
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
 echo "configure:2464: checking for $ac_func" >&5
@@ -2861,15 +2861,66 @@
 
 
 
+if test $ac_cv_func_sendmsg = no; then
+    echo $ac_n "checking for sendmsg in -lsocket""... $ac_c" 1>&6
+echo "configure:2867: checking for sendmsg in -lsocket" >&5
+ac_lib_var=`echo socket'_'sendmsg | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2875 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char sendmsg();
+
+int main() {
+sendmsg()
+; return 0; }
+EOF
+if { (eval echo configure:2886: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
 if test "$ac_cv_header_sys_vfs_h" = "yes"
 then
     echo $ac_n "checking "whether sys/vfs.h defines statfs"""... $ac_c" 1>&6
-echo "configure:2868: checking "whether sys/vfs.h defines statfs"" >&5
+echo "configure:2919: checking "whether sys/vfs.h defines statfs"" >&5
 if eval "test \"`echo '$''{'wine_cv_sys_vfs_has_statfs'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2873 "configure"
+#line 2924 "configure"
 #include "confdefs.h"
 
 	#include <sys/types.h>
@@ -2886,7 +2937,7 @@
 	
 ; return 0; }
 EOF
-if { (eval echo configure:2890: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2941: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   wine_cv_sys_vfs_has_statfs=yes
 else
@@ -2913,12 +2964,12 @@
 if test "$ac_cv_header_sys_statfs_h" = "yes"
 then
     echo $ac_n "checking "whether sys/statfs.h defines statfs"""... $ac_c" 1>&6
-echo "configure:2917: checking "whether sys/statfs.h defines statfs"" >&5
+echo "configure:2968: checking "whether sys/statfs.h defines statfs"" >&5
 if eval "test \"`echo '$''{'wine_cv_sys_statfs_has_statfs'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2922 "configure"
+#line 2973 "configure"
 #include "confdefs.h"
 
 	#include <sys/types.h>
@@ -2933,7 +2984,7 @@
 	
 ; return 0; }
 EOF
-if { (eval echo configure:2937: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2988: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   wine_cv_sys_statfs_has_statfs=yes
 else
@@ -2960,12 +3011,12 @@
 if test "$ac_cv_header_sys_mount_h" = "yes"
 then
     echo $ac_n "checking "whether sys/mount.h defines statfs"""... $ac_c" 1>&6
-echo "configure:2964: checking "whether sys/mount.h defines statfs"" >&5
+echo "configure:3015: checking "whether sys/mount.h defines statfs"" >&5
 if eval "test \"`echo '$''{'wine_cv_sys_mount_has_statfs'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2969 "configure"
+#line 3020 "configure"
 #include "confdefs.h"
 
 	#include <sys/types.h>
@@ -2980,7 +3031,7 @@
 	
 ; return 0; }
 EOF
-if { (eval echo configure:2984: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3035: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   wine_cv_sys_mount_has_statfs=yes
 else
@@ -3006,7 +3057,7 @@
 
 
 echo $ac_n "checking "for statfs.f_bfree"""... $ac_c" 1>&6
-echo "configure:3010: checking "for statfs.f_bfree"" >&5
+echo "configure:3061: checking "for statfs.f_bfree"" >&5
 if eval "test \"`echo '$''{'wine_cv_statfs_bfree'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3015,7 +3066,7 @@
         wine_cv_statfs_bfree=no
     else
     	cat > conftest.$ac_ext <<EOF
-#line 3019 "configure"
+#line 3070 "configure"
 #include "confdefs.h"
 
 	#include <sys/types.h>
@@ -3042,7 +3093,7 @@
 	
 ; return 0; }
 EOF
-if { (eval echo configure:3046: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3097: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   wine_cv_statfs_bfree=yes
 else
@@ -3066,7 +3117,7 @@
 fi
 
 echo $ac_n "checking "for statfs.f_bavail"""... $ac_c" 1>&6
-echo "configure:3070: checking "for statfs.f_bavail"" >&5
+echo "configure:3121: checking "for statfs.f_bavail"" >&5
 if eval "test \"`echo '$''{'wine_cv_statfs_bavail'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3075,7 +3126,7 @@
         wine_cv_statfs_bavail=no
     else
     	cat > conftest.$ac_ext <<EOF
-#line 3079 "configure"
+#line 3130 "configure"
 #include "confdefs.h"
 
 	#include <sys/types.h>
@@ -3102,7 +3153,7 @@
 	
 ; return 0; }
 EOF
-if { (eval echo configure:3106: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3157: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   wine_cv_statfs_bavail=yes
 else
@@ -3127,7 +3178,7 @@
 
 
 echo $ac_n "checking "for working sigaltstack"""... $ac_c" 1>&6
-echo "configure:3131: checking "for working sigaltstack"" >&5
+echo "configure:3182: checking "for working sigaltstack"" >&5
 if eval "test \"`echo '$''{'ac_cv_c_working_sigaltstack'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3136,7 +3187,7 @@
 
 else
   cat > conftest.$ac_ext <<EOF
-#line 3140 "configure"
+#line 3191 "configure"
 #include "confdefs.h"
 
 	#include <stdio.h>
@@ -3174,7 +3225,7 @@
 	}
 	
 EOF
-if { (eval echo configure:3178: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:3229: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_working_sigaltstack="yes"
 else
@@ -3201,12 +3252,12 @@
 
 
 echo $ac_n "checking "for msg_accrights in struct msghdr"""... $ac_c" 1>&6
-echo "configure:3205: checking "for msg_accrights in struct msghdr"" >&5
+echo "configure:3256: checking "for msg_accrights in struct msghdr"" >&5
 if eval "test \"`echo '$''{'ac_cv_c_msg_accrights'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 3210 "configure"
+#line 3261 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -3214,7 +3265,7 @@
 struct msghdr hdr; hdr.msg_accrights=0
 ; return 0; }
 EOF
-if { (eval echo configure:3218: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:3269: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_msg_accrights="yes"
 else
@@ -3358,6 +3409,7 @@
 libtest/Makefile
 loader/Makefile
 loader/ne/Makefile
+loader/dos/Makefile
 memory/Makefile
 misc/Makefile
 miscemu/Makefile
@@ -3492,6 +3544,7 @@
 libtest/Makefile
 loader/Makefile
 loader/ne/Makefile
+loader/dos/Makefile
 memory/Makefile
 misc/Makefile
 miscemu/Makefile
diff --git a/configure.in b/configure.in
index 5256e25..19731df 100644
--- a/configure.in
+++ b/configure.in
@@ -240,13 +240,19 @@
 
 dnl **** Check for functions and header files ****
 
-AC_CHECK_FUNCS(clone getpagesize memmove sigaltstack strerror stricmp tcgetattr timegm usleep wait4 waitpid vfscanf)
+AC_CHECK_FUNCS(clone getpagesize memmove sendmsg sigaltstack strerror stricmp tcgetattr timegm usleep wait4 waitpid vfscanf)
 AC_CHECK_HEADERS(wctype.h sys/syscall.h syscall.h sys/param.h sys/vfs.h sys/mount.h sys/statfs.h float.h linux/cdrom.h linux/ucdrom.h sys/cdio.h sys/filio.h sys/modem.h strings.h sys/strtio.h)
 AC_HEADER_STAT()
 AC_C_CONST()
 AC_TYPE_SIZE_T()
 AC_CHECK_SIZEOF(long long,0)
 
+dnl **** Check for sendmsg in -lsocket if not found above ****
+
+if test $ac_cv_func_sendmsg = no; then
+    AC_CHECK_LIB(socket,sendmsg)
+fi
+
 dnl **** statfs checks ****
 
 if test "$ac_cv_header_sys_vfs_h" = "yes"
@@ -467,6 +473,7 @@
 libtest/Makefile
 loader/Makefile
 loader/ne/Makefile
+loader/dos/Makefile
 memory/Makefile
 misc/Makefile
 miscemu/Makefile
diff --git a/controls/comctl32undoc.c b/controls/comctl32undoc.c
index 7cc24aa..7027960 100644
--- a/controls/comctl32undoc.c
+++ b/controls/comctl32undoc.c
@@ -42,9 +42,6 @@
 } DPA_DATA, *LPDPA_DATA;
 
 
-DWORD WINAPI DSA_Create (DWORD, DWORD);
-
-
 DWORD WINAPI DPA_Create (DWORD);
 DWORD WINAPI DPA_GetPtr (DWORD, DWORD);
 DWORD WINAPI DPA_InsertPtr (DWORD, DWORD, DWORD);
@@ -255,24 +252,24 @@
 
 
 DWORD WINAPI
-DSA_InsertItem (DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
+DSA_InsertItem (DWORD dwParam1, DWORD dwParam2, LPSTR lpString)
 {
     LPDSA_DATA dsaPtr = (LPDSA_DATA)dwParam1;
     DWORD dwIndex;
     INT32 len;
 
     TRACE (commctrl, "(0x%08lx 0x%08lx \"%s\"):semi-stub!\n",
-	   dwParam1, dwParam2, (LPSTR)dwParam3);
+	   dwParam1, dwParam2, lpString);
 
     if (dsaPtr->ptrs == NULL) {
 	dsaPtr->ptrs = (LPSTR*)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
 					  dsaPtr->dwInitial * sizeof(LPVOID));
 	dsaPtr->dwMaxCount = dsaPtr->dwInitial;
         dwIndex = 0;
-	len = lstrlen32A ((LPSTR)dwParam3);
+	len = lstrlen32A (lpString);
 	dsaPtr->ptrs[dwIndex] =
 	    (LPSTR)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len+1);
-	lstrcpy32A (dsaPtr->ptrs[dwIndex], (LPSTR)dwParam3);
+	lstrcpy32A (dsaPtr->ptrs[dwIndex], lpString);
     }
     else {
 	TRACE (commctrl, "(0x%08lx 0x%08lx)\n",
@@ -280,10 +277,10 @@
 	if (dwParam2 >= dsaPtr->dwEntryCount) {
 	    if (dsaPtr->dwEntryCount < dsaPtr->dwMaxCount) {
 		dwIndex = dsaPtr->dwEntryCount;
-		len = lstrlen32A ((LPSTR)dwParam3);
+		len = lstrlen32A (lpString);
 		dsaPtr->ptrs[dwIndex] =
 		    (LPSTR)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len+1);
-		lstrcpy32A (dsaPtr->ptrs[dwIndex], (LPSTR)dwParam3);
+		lstrcpy32A (dsaPtr->ptrs[dwIndex], lpString);
 	    }
 	    else {
 		/* allocate new pointer list and copy all pointers */
@@ -298,10 +295,10 @@
 
 		/* add new string */
 		dwIndex = dsaPtr->dwEntryCount;
-		len = lstrlen32A ((LPSTR)dwParam3);
+		len = lstrlen32A (lpString);
 		dsaPtr->ptrs[dwIndex] =
 		    (LPSTR)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len+1);
-		lstrcpy32A (dsaPtr->ptrs[dwIndex], (LPSTR)dwParam3);
+		lstrcpy32A (dsaPtr->ptrs[dwIndex], lpString);
 	    }
 	}
 	else {
diff --git a/controls/commctrl.c b/controls/commctrl.c
index 728f123..4be6540 100644
--- a/controls/commctrl.c
+++ b/controls/commctrl.c
@@ -22,7 +22,18 @@
 #include "updown.h"
 #include "debug.h"
 
+/***********************************************************************
+ * ComCtl32LibMain
+ */
 
+BOOL32 WINAPI ComCtl32LibMain (HINSTANCE32 hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{ TRACE(commctrl,"%x,%lx,%p\n",hinstDLL,fdwReason,lpvReserved);
+  if ( fdwReason == DLL_PROCESS_ATTACH)
+  { InitCommonControls();
+  }
+  return TRUE;
+
+}
 /***********************************************************************
  * DrawStatusText32A [COMCTL32.5][COMCTL32.27]
  *
@@ -157,6 +168,8 @@
   INT32 cCount;
   DWORD dwMask;
 
+  TRACE(commctrl,"\n");
+  
   if (lpInitCtrls == NULL) return FALSE;
   if (lpInitCtrls->dwSize < sizeof(INITCOMMONCONTROLSEX)) return FALSE;
 
@@ -544,4 +557,3 @@
 
     return FALSE;
 }
-
diff --git a/controls/static.c b/controls/static.c
index 255f01f..ac53bbd 100644
--- a/controls/static.c
+++ b/controls/static.c
@@ -115,18 +115,22 @@
 
     if (wndPtr->flags & WIN_ISWIN32)
     {
-        hicon = LoadIcon32A( wndPtr->hInstance, name );
-        if (!hicon)  /* Try OEM icon (FIXME: is this right?) */
-            hicon = LoadIcon32A( 0, name );
-    }
-    else
-    {
+	if (!HIWORD(wndPtr->hInstance)) {
+	    LPSTR segname = SEGPTR_STRDUP(name);
+	    hicon = LoadIcon16( wndPtr->hInstance, SEGPTR_GET(segname) );
+	    SEGPTR_FREE(segname);
+	} else
+	    hicon = LoadIcon32A( wndPtr->hInstance, name );
+    } else {
         LPSTR segname = SEGPTR_STRDUP(name);
+
+	if (HIWORD(wndPtr->hInstance))
+		FIXME(static,"win16 window class, but win32 hinstance??\n");
         hicon = LoadIcon16( wndPtr->hInstance, SEGPTR_GET(segname) );
-        if (!hicon)  /* Try OEM icon (FIXME: is this right?) */
-            hicon = LoadIcon32A( 0, segname );
         SEGPTR_FREE(segname);
     }
+    if (!hicon)
+	hicon = LoadIcon32A( 0, name );
     return hicon;
 }
 
diff --git a/controls/status.c b/controls/status.c
index f0bcd28..6536fa9 100644
--- a/controls/status.c
+++ b/controls/status.c
@@ -10,6 +10,7 @@
 #include "commctrl.h"
 #include "heap.h"
 #include "win.h"
+#include "debug.h"
 
 /*
  * Run tests using Waite Group Windows95 API Bible Vol. 1&2
@@ -20,7 +21,7 @@
 /*
  * Fixme/Todo
  * 1) Don't hard code bar to bottom of window, allow CCS_TOP also.
- + 2) Tooltip support.
+ + 2) Tooltip support (almost done).
  */
 
 #define _MAX(a,b) (((a)>(b))?(a):(b))
@@ -30,18 +31,11 @@
 #define VERT_BORDER 2
 #define HORZ_GAP    2
 
-
-static STATUSWINDOWINFO *GetStatusInfo(HWND32 hwnd)
-{
-    WND *wndPtr;
-
-    wndPtr = WIN_FindWndPtr(hwnd);
-    return ((STATUSWINDOWINFO *) wndPtr->wExtra[0]);
-}
+#define STATUSBAR_GetInfoPtr(wndPtr) ((STATUSWINDOWINFO *)wndPtr->wExtra[0])
 
 
 static void
-STATUS_DrawSizeGrip (HDC32 hdc, LPRECT32 lpRect)
+STATUSBAR_DrawSizeGrip (HDC32 hdc, LPRECT32 lpRect)
 {
     HPEN32 hOldPen;
     POINT32 pt;
@@ -78,32 +72,31 @@
 
 
 static void 
-SB_DrawPart( HDC32 hdc, LPRECT32 lprc, HICON32 hIcon,
-             LPCSTR text, UINT32 style )
+STATUSBAR_DrawPart (HDC32 hdc, STATUSWINDOWPART *part)
 {
-    RECT32 r = *lprc;
+    RECT32 r = part->bound;
     UINT32 border = BDR_SUNKENOUTER;
 
-    if (style==SBT_POPOUT)
+    if (part->style==SBT_POPOUT)
       border = BDR_RAISEDOUTER;
-    else if (style==SBT_NOBORDERS)
+    else if (part->style==SBT_NOBORDERS)
       border = 0;
 
     DrawEdge32(hdc, &r, border, BF_RECT|BF_ADJUST);
 
     /* draw the icon */
-    if (hIcon) {
+    if (part->hIcon) {
 	INT32 cy = r.bottom - r.top;
 
 	r.left += 2;
-	DrawIconEx32 (hdc, r.left, r.top, hIcon, cy, cy, 0, 0, DI_NORMAL);
+	DrawIconEx32 (hdc, r.left, r.top, part->hIcon, cy, cy, 0, 0, DI_NORMAL);
 	r.left += cy;
     }
 
     /* now draw text */
-    if (text) {
+    if (part->text) {
       int oldbkmode = SetBkMode32(hdc, TRANSPARENT);
-      LPSTR p = (LPSTR)text;
+      LPSTR p = (LPSTR)part->text;
       UINT32 align = DT_LEFT;
       if (*p == '\t') {
 	p++;
@@ -122,22 +115,66 @@
 }
 
 
-static BOOL32
-SW_Refresh( HWND32 hwnd, HDC32 hdc, STATUSWINDOWINFO *self )
+static VOID
+STATUSBAR_RefreshPart (WND *wndPtr, STATUSWINDOWPART *part, HDC32 hdc)
 {
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+    HBRUSH32 hbrBk;
+    HFONT32  hOldFont;
+
+    if (!IsWindowVisible32(wndPtr->hwndSelf))
+        return;
+
+    if (self->clrBk != CLR_DEFAULT)
+	hbrBk = CreateSolidBrush32 (self->clrBk);
+    else
+	hbrBk = GetSysColorBrush32 (COLOR_3DFACE);
+    FillRect32(hdc, &part->bound, hbrBk);
+
+    hOldFont = SelectObject32 (hdc, self->hFont ? self->hFont : self->hDefaultFont);
+
+    if (part->style == SBT_OWNERDRAW) {
+	DRAWITEMSTRUCT32 dis;
+
+	dis.CtlID = wndPtr->wIDmenu;
+	dis.itemID = -1;
+	dis.hwndItem = wndPtr->hwndSelf;
+	dis.hDC = hdc;
+	dis.rcItem = part->bound;
+	dis.itemData = (INT32)part->text;
+	SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_DRAWITEM,
+			(WPARAM32)wndPtr->wIDmenu, (LPARAM)&dis);
+    }
+    else
+	STATUSBAR_DrawPart (hdc, part);
+
+    SelectObject32 (hdc, hOldFont);
+
+    if (self->clrBk != CLR_DEFAULT)
+	DeleteObject32 (hbrBk);
+
+    if (wndPtr->dwStyle & SBARS_SIZEGRIP) {
+	RECT32 rect;
+
+	GetClientRect32 (wndPtr->hwndSelf, &rect);
+	STATUSBAR_DrawSizeGrip (hdc, &rect);
+    }
+}
+
+
+static BOOL32
+STATUSBAR_Refresh (WND *wndPtr, HDC32 hdc)
+{
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     int      i;
     RECT32   rect;
     HBRUSH32 hbrBk;
-    HFONT32 hOldFont;
-    WND *wndPtr;
+    HFONT32  hOldFont;
 
-    wndPtr = WIN_FindWndPtr(hwnd);
-
-    if (!IsWindowVisible32(hwnd)) {
+    if (!IsWindowVisible32(wndPtr->hwndSelf))
         return (TRUE);
-    }
 
-    GetClientRect32 (hwnd, &rect);
+    GetClientRect32 (wndPtr->hwndSelf, &rect);
 
     if (self->clrBk != CLR_DEFAULT)
 	hbrBk = CreateSolidBrush32 (self->clrBk);
@@ -148,33 +185,24 @@
     hOldFont = SelectObject32 (hdc, self->hFont ? self->hFont : self->hDefaultFont);
 
     if (self->simple) {
-	SB_DrawPart (hdc,
-		     &self->part0.bound,
-		     self->part0.hIcon,
-		     self->part0.text,
-		     self->part0.style);
+	STATUSBAR_DrawPart (hdc, &self->part0);
     }
     else {
 	for (i = 0; i < self->numParts; i++) {
 	    if (self->parts[i].style == SBT_OWNERDRAW) {
 		DRAWITEMSTRUCT32 dis;
-		WND *wndPtr = WIN_FindWndPtr(hwnd);
 
 		dis.CtlID = wndPtr->wIDmenu;
 		dis.itemID = -1;
-		dis.hwndItem = hwnd;
+		dis.hwndItem = wndPtr->hwndSelf;
 		dis.hDC = hdc;
-		dis.rcItem = self->part0.bound;
-		dis.itemData = (INT32)self->part0.text;
-		SendMessage32A (GetParent32 (hwnd), WM_DRAWITEM, 
+		dis.rcItem = self->parts[i].bound;
+		dis.itemData = (INT32)self->parts[i].text;
+		SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_DRAWITEM,
 				(WPARAM32)wndPtr->wIDmenu, (LPARAM)&dis);
 	    }
 	    else
-		SB_DrawPart (hdc,
-			     &self->parts[i].bound,
-			     self->parts[i].hIcon,
-			     self->parts[i].text,
-			     self->parts[i].style);
+		STATUSBAR_DrawPart (hdc, &self->parts[i]);
 	}
     }
 
@@ -184,33 +212,22 @@
 	DeleteObject32 (hbrBk);
 
     if (wndPtr->dwStyle & SBARS_SIZEGRIP)
-	STATUS_DrawSizeGrip (hdc, &rect);
+	STATUSBAR_DrawSizeGrip (hdc, &rect);
 
     return TRUE;
 }
 
 
-__inline__ static LRESULT
-SW_GetBorders (LPARAM lParam)
-{
-    LPINT32 out = (LPINT32) lParam;
-
-    out[0] = HORZ_BORDER; /* horizontal border width */
-    out[1] = VERT_BORDER; /* vertical border width */
-    out[2] = HORZ_GAP; /* width of border between rectangles */
-
-    return TRUE;
-}
-
 static void
-SW_SetPartBounds(HWND32 hwnd, STATUSWINDOWINFO *self)
+STATUSBAR_SetPartBounds (WND *wndPtr)
 {
-    int	i;
-    RECT32	rect, *r;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     STATUSWINDOWPART *part;
+    RECT32 rect, *r;
+    int	i;
 
     /* get our window size */
-    GetClientRect32(hwnd, &rect);
+    GetClientRect32 (wndPtr->hwndSelf, &rect);
 
     rect.top += VERT_BORDER;
 
@@ -231,97 +248,76 @@
 	    r->right = rect.right;
 	else
 	    r->right = part->x;
+
+	if (self->hwndToolTip) {
+	    TTTOOLINFO32A ti;
+
+	    ti.cbSize = sizeof(TTTOOLINFO32A);
+	    ti.hwnd = wndPtr->hwndSelf;
+	    ti.uId = i;
+	    ti.rect = *r;
+	    SendMessage32A (self->hwndToolTip, TTM_NEWTOOLRECT32A,
+			    0, (LPARAM)&ti);
+	}
     }
 }
 
-static LRESULT
-SW_SetText(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+
+static VOID
+STATUSBAR_RelayEvent (HWND32 hwndTip, HWND32 hwndMsg, UINT32 uMsg,
+		      WPARAM32 wParam, LPARAM lParam)
 {
-    int	part_num;
-    int	style;
-    LPSTR	text;
-    int	len;
-    STATUSWINDOWPART *part;
+    MSG32 msg;
 
-    text = (LPSTR) lParam;
-    part_num = ((INT32) wParam) & 0x00ff;
-    style = ((INT32) wParam) & 0xff00;
+    msg.hwnd = hwndMsg;
+    msg.message = uMsg;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    msg.time = GetMessageTime ();
+    msg.pt.x = LOWORD(GetMessagePos ());
+    msg.pt.y = HIWORD(GetMessagePos ());
 
-    if ((self->simple) || (self->parts==NULL) || (part_num==255))
-	part = &self->part0;
+    SendMessage32A (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
+}
+
+
+__inline__ static LRESULT
+STATUSBAR_GetBorders (LPARAM lParam)
+{
+    LPINT32 out = (LPINT32) lParam;
+
+    out[0] = HORZ_BORDER; /* horizontal border width */
+    out[1] = VERT_BORDER; /* vertical border width */
+    out[2] = HORZ_GAP; /* width of border between rectangles */
+
+    return TRUE;
+}
+
+
+static LRESULT
+STATUSBAR_GetIcon (WND *wndPtr, WPARAM32 wParam)
+{
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+    INT32 nPart;
+
+    nPart = (INT32)wParam & 0x00ff;
+    if ((nPart < -1) || (nPart >= self->numParts)) return 0;
+
+    if (nPart == -1)
+        return (self->part0.hIcon);
     else
-	part = &self->parts[part_num];
-    if (!part) return FALSE;
-    part->style = style;
-    if (style == SBT_OWNERDRAW) {
-	part->text = text;
-    }
-    else {
-	/* duplicate string */
-	if (part->text)
-	    HeapFree(SystemHeap, 0, part->text);
-	part->text = 0;
-	if (text && (len = lstrlen32A(text))) {
-	    part->text = HeapAlloc(SystemHeap, 0, len+1);
-	    lstrcpy32A(part->text, text);
-	}
-    }
-    InvalidateRect32(hwnd, &part->bound, FALSE);
-//    SW_RefreshPart (hdc, part);
-    return TRUE;
+        return (self->parts[nPart].hIcon);
 }
 
-static LRESULT
-SW_SetParts(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
-{
-    HDC32	hdc;
-    LPINT32 parts;
-    STATUSWINDOWPART *	tmp;
-    int	i;
-    int	oldNumParts;
-
-    if (self->simple) {
-	self->simple = FALSE;
-    }
-    oldNumParts = self->numParts;
-    self->numParts = (INT32) wParam;
-    parts = (LPINT32) lParam;
-    if (oldNumParts > self->numParts) {
-	for (i = self->numParts ; i < oldNumParts; i++) {
-	    if (self->parts[i].text && (self->parts[i].style != SBT_OWNERDRAW))
-		HeapFree(SystemHeap, 0, self->parts[i].text);
-	}
-    }
-    else if (oldNumParts < self->numParts) {
-	tmp = HeapAlloc(SystemHeap, HEAP_ZERO_MEMORY,
-			sizeof(STATUSWINDOWPART) * self->numParts);
-	for (i = 0; i < oldNumParts; i++) {
-	    tmp[i] = self->parts[i];
-	}
-	if (self->parts)
-	    HeapFree(SystemHeap, 0, self->parts);
-	self->parts = tmp;
-    }
-    
-    for (i = 0; i < self->numParts; i++) {
-	self->parts[i].x = parts[i];
-    }
-    SW_SetPartBounds(hwnd, self);
-
-    hdc = GetDC32(hwnd);
-    SW_Refresh(hwnd, hdc, self);
-    ReleaseDC32(hwnd, hdc);
-    return TRUE;
-}
 
 static LRESULT
-SW_GetParts(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_GetParts (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     LPINT32 parts;
-    INT32	num_parts;
-    int	i;
+    INT32   num_parts;
+    int	    i;
 
-    self = GetStatusInfo(hwnd);
     num_parts = (INT32) wParam;
     parts = (LPINT32) lParam;
     if (parts) {
@@ -333,78 +329,11 @@
     return (self->numParts);
 }
 
-static LRESULT
-SW_Create(HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
-{
-    LPCREATESTRUCT32A lpCreate = (LPCREATESTRUCT32A) lParam;
-    NONCLIENTMETRICS32A nclm;
-    RECT32	rect;
-    int	        width, len;
-    HDC32	hdc;
-    HWND32	parent;
-    WND *wndPtr;
-    STATUSWINDOWINFO *self;
-
-    wndPtr = WIN_FindWndPtr(hwnd);
-    self = (STATUSWINDOWINFO*)HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
-					 sizeof(STATUSWINDOWINFO));
-    wndPtr->wExtra[0] = (DWORD)self;
-
-    self->numParts = 1;
-    self->parts = 0;
-    self->simple = FALSE;
-    self->clrBk = CLR_DEFAULT;
-    self->hFont = 0;
-    GetClientRect32(hwnd, &rect);
-
-    nclm.cbSize = sizeof(NONCLIENTMETRICS32A);
-    SystemParametersInfo32A (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
-    self->hDefaultFont = CreateFontIndirect32A (&nclm.lfStatusFont);
-
-    /* initialize simple case */
-    self->part0.bound = rect;
-    self->part0.text = 0;
-    self->part0.x = 0;
-    self->part0.style = 0;
-    self->part0.hIcon = 0;
-
-    /* initialize first part */
-    self->parts = HeapAlloc (SystemHeap, HEAP_ZERO_MEMORY,
-			     sizeof(STATUSWINDOWPART));
-    self->parts[0].bound = rect;
-    self->parts[0].text = 0;
-    self->parts[0].x = -1;
-    self->parts[0].style = 0;
-    self->parts[0].hIcon = 0;
-
-    if ((len = lstrlen32A (lpCreate->lpszName))) {
-        self->parts[0].text = HeapAlloc (SystemHeap, 0, len + 1);
-        lstrcpy32A (self->parts[0].text, lpCreate->lpszName);
-    }
-
-    if ((hdc = GetDC32 (0))) {
-	TEXTMETRIC32A tm;
-	HFONT32 hOldFont;
-
-	hOldFont = SelectObject32 (hdc,self->hDefaultFont);
-	GetTextMetrics32A(hdc, &tm);
-	self->textHeight = tm.tmHeight;
-	SelectObject32 (hdc, hOldFont);
-	ReleaseDC32(0, hdc);
-    }
-
-    parent = GetParent32 (hwnd);
-    GetClientRect32 (parent, &rect);
-    width = rect.right - rect.left;
-    self->height = self->textHeight + 4 + VERT_BORDER;
-    MoveWindow32 (hwnd, lpCreate->x, lpCreate->y-1, width, self->height, FALSE);
-    SW_SetPartBounds (hwnd, self);
-    return 0;
-}
 
 static LRESULT
-SW_GetRect(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_GetRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     int	part_num;
     LPRECT32  rect;
 
@@ -417,13 +346,15 @@
     return TRUE;
 }
 
+
 static LRESULT
-SW_GetText(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_GetText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    int	part_num;
-    LRESULT	result;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     STATUSWINDOWPART *part;
-    LPSTR	out_text;
+    int	part_num;
+    LRESULT result;
+    LPSTR   out_text;
 
     part_num = ((INT32) wParam) & 0x00ff;
     out_text = (LPSTR) lParam;
@@ -444,11 +375,16 @@
     return result;
 }
 
+
+//  << STATUSBAR_GetText32W >>
+
+
 static LRESULT
-SW_GetTextLength(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_GetTextLength32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    int	part_num;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     STATUSWINDOWPART *part;
+    int	part_num;
     DWORD	result;
 
     part_num = ((INT32) wParam) & 0x00ff;
@@ -467,129 +403,417 @@
     return result;
 }
 
-static LRESULT
-SW_SetMinHeight(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
-{
-    INT32	width, x, y;
-    RECT32	parent_rect;
-    HWND32	parent;
 
-    if (IsWindowVisible32 (hwnd)) {
-	parent = GetParent32(hwnd);
-	GetClientRect32(parent, &parent_rect);
-	self->height = (INT32)wParam + VERT_BORDER;
-	width = parent_rect.right - parent_rect.left;
-	x = parent_rect.left;
-	y = parent_rect.bottom - self->height;
-	MoveWindow32(hwnd, parent_rect.left, parent_rect.bottom - self->height,
-		     width, self->height, TRUE);
-	SW_SetPartBounds(hwnd, self);
+//  << STATUSBAR_GetTextLength32W >>
+
+
+static LRESULT
+STATUSBAR_GetTipText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
+
+    if (infoPtr->hwndToolTip) {
+	TTTOOLINFO32A ti;
+
+	ti.cbSize = sizeof(TTTOOLINFO32A);
+	ti.hwnd = wndPtr->hwndSelf;
+	ti.uId = LOWORD(wParam);
+	SendMessage32A (infoPtr->hwndToolTip, TTM_GETTEXT32A, 0, (LPARAM)&ti);
+
+	if (ti.lpszText)
+	    lstrcpyn32A ((LPSTR)lParam, ti.lpszText, HIWORD(wParam));
     }
 
-    return TRUE;
+    return 0;
 }
 
-static LRESULT
-SW_SetBkColor(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+
+//  << STATUSBAR_GetTipText32W >>
+//  << STATUSBAR_GetUnicodeFormat >>
+
+
+__inline__ static LRESULT
+STATUSBAR_IsSimple (WND *wndPtr)
 {
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+
+    return self->simple;
+}
+
+
+static LRESULT
+STATUSBAR_SetBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     COLORREF oldBkColor;
     HDC32    hdc;
 
     oldBkColor = self->clrBk;
     self->clrBk = (COLORREF)lParam;
-    hdc = GetDC32(hwnd);
-    SW_Refresh(hwnd, hdc, self);
-    ReleaseDC32(hwnd, hdc);
+    hdc = GetDC32 (wndPtr->hwndSelf);
+    STATUSBAR_Refresh (wndPtr, hdc);
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
+
     return oldBkColor;
 }
 
 
 static LRESULT
-SW_SetIcon (STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_SetIcon (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    INT32  nPart = (INT32)wParam & 0x00ff;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+    INT32 nPart = (INT32)wParam & 0x00ff;
+    HDC32 hdc; 
 
     if ((nPart < -1) || (nPart >= self->numParts)) return FALSE;
 
+    hdc = GetDC32 (wndPtr->hwndSelf);
     if (nPart == -1) {
-        self->part0.hIcon = (HICON32)lParam;
-        if (self->simple) 
-            InvalidateRect32(hwnd, &self->part0.bound, FALSE);
+	self->part0.hIcon = (HICON32)lParam;
+	if (self->simple)
+	    STATUSBAR_RefreshPart (wndPtr, &self->part0, hdc);
     }
     else {
-        self->parts[nPart].hIcon = (HICON32)lParam;
-        if (!(self->simple))
-            InvalidateRect32(hwnd, &self->parts[nPart].bound, FALSE);
+	self->parts[nPart].hIcon = (HICON32)lParam;
+	if (!(self->simple))
+	    STATUSBAR_RefreshPart (wndPtr, &self->parts[nPart], hdc);
     }
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
+
     return TRUE;
 }
 
+
 static LRESULT
-SW_GetIcon(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_SetMinHeight (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    INT32    nPart;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
 
-    nPart = (INT32)wParam & 0x00ff;
-    if ((nPart < -1) || (nPart >= self->numParts)) return 0;
+    if (IsWindowVisible32 (wndPtr->hwndSelf)) {
+	HWND32 parent = GetParent32 (wndPtr->hwndSelf);
+	INT32  width, x, y;
+	RECT32 parent_rect;
 
-    if (nPart == -1)
-        return (self->part0.hIcon);
-    else
-        return (self->parts[nPart].hIcon);
+	GetClientRect32 (parent, &parent_rect);
+	self->height = (INT32)wParam + VERT_BORDER;
+	width = parent_rect.right - parent_rect.left;
+	x = parent_rect.left;
+	y = parent_rect.bottom - self->height;
+	MoveWindow32 (wndPtr->hwndSelf, parent_rect.left,
+		      parent_rect.bottom - self->height,
+		      width, self->height, TRUE);
+	STATUSBAR_SetPartBounds (wndPtr);
+    }
+
+    return TRUE;
 }
 
+
 static LRESULT
-SW_Simple(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_SetParts (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    WND *wndPtr;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+    HDC32	hdc;
+    LPINT32 parts;
+    STATUSWINDOWPART *	tmp;
+    int	i;
+    int	oldNumParts;
+
+    if (self->simple)
+	self->simple = FALSE;
+
+    oldNumParts = self->numParts;
+    self->numParts = (INT32) wParam;
+    parts = (LPINT32) lParam;
+    if (oldNumParts > self->numParts) {
+	for (i = self->numParts ; i < oldNumParts; i++) {
+	    if (self->parts[i].text && (self->parts[i].style != SBT_OWNERDRAW))
+		HeapFree(GetProcessHeap (), 0, self->parts[i].text);
+	}
+    }
+    else if (oldNumParts < self->numParts) {
+	tmp = HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY,
+			sizeof(STATUSWINDOWPART) * self->numParts);
+	for (i = 0; i < oldNumParts; i++) {
+	    tmp[i] = self->parts[i];
+	}
+	if (self->parts)
+	    HeapFree(GetProcessHeap (), 0, self->parts);
+	self->parts = tmp;
+    }
+    
+    for (i = 0; i < self->numParts; i++) {
+	self->parts[i].x = parts[i];
+    }
+
+    if (self->hwndToolTip) {
+	INT32 nTipCount =
+	    SendMessage32A (self->hwndToolTip, TTM_GETTOOLCOUNT, 0, 0);
+
+	if (nTipCount < self->numParts) {
+	    /* add tools */
+	    TTTOOLINFO32A ti;
+	    INT32 i;
+
+	    ZeroMemory (&ti, sizeof(TTTOOLINFO32A));
+	    ti.cbSize = sizeof(TTTOOLINFO32A);
+	    ti.hwnd = wndPtr->hwndSelf;
+	    for (i = nTipCount; i < self->numParts; i++) {
+		TRACE (statusbar, "add tool %d\n", i);
+		ti.uId = i;
+		SendMessage32A (self->hwndToolTip, TTM_ADDTOOL32A,
+				0, (LPARAM)&ti);
+	    }
+	}
+	else if (nTipCount > self->numParts) {
+	    /* delete tools */
+	    INT32 i;
+
+	    for (i = nTipCount - 1; i >= self->numParts; i--) {
+
+		TRACE (statusbar, "delete tool %d\n", i);
+
+	    }
+	}
+    }
+
+    STATUSBAR_SetPartBounds (wndPtr);
+
+    hdc = GetDC32 (wndPtr->hwndSelf);
+    STATUSBAR_Refresh (wndPtr, hdc);
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
+
+    return TRUE;
+}
+
+
+static LRESULT
+STATUSBAR_SetText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+    STATUSWINDOWPART *part;
+    int	part_num;
+    int	style;
+    LPSTR text;
+    int	len;
+    HDC32 hdc;
+
+    text = (LPSTR) lParam;
+    part_num = ((INT32) wParam) & 0x00ff;
+    style = ((INT32) wParam) & 0xff00;
+
+    if ((self->simple) || (self->parts==NULL) || (part_num==255))
+	part = &self->part0;
+    else
+	part = &self->parts[part_num];
+    if (!part) return FALSE;
+    part->style = style;
+    if (style == SBT_OWNERDRAW) {
+	part->text = text;
+    }
+    else {
+	/* duplicate string */
+	if (part->text)
+	    HeapFree (GetProcessHeap (), 0, part->text);
+	part->text = 0;
+	if (text && (len = lstrlen32A(text))) {
+	    part->text = HeapAlloc (GetProcessHeap (), 0, len+1);
+	    lstrcpy32A(part->text, text);
+	}
+    }
+
+    hdc = GetDC32 (wndPtr->hwndSelf);
+    STATUSBAR_RefreshPart (wndPtr, part, hdc);
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
+
+    return TRUE;
+}
+
+
+//  << STATUSBAR_SetText32W >>
+
+
+static LRESULT
+STATUSBAR_SetTipText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+    TTTOOLINFO32A ti;
+
+    TRACE (statusbar, "part %d: \"%s\"\n", (INT32)wParam, (LPSTR)lParam);
+    if (self->hwndToolTip) {
+	ti.cbSize = sizeof(TTTOOLINFO32A);
+	ti.hwnd = wndPtr->hwndSelf;
+	ti.uId = (INT32)wParam;
+	ti.hinst = 0;
+	ti.lpszText = (LPSTR)lParam;
+	SendMessage32A (self->hwndToolTip, TTM_UPDATETIPTEXT32A,
+			0, (LPARAM)&ti);
+    }
+
+    return 0;
+}
+
+
+//  << STATUSBAR_SetTipText32W >>
+//  << STATUSBAR_SetUnicodeFormat >>
+
+
+static LRESULT
+STATUSBAR_Simple (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     BOOL32 simple;
     HDC32  hdc;
     NMHDR  nmhdr;
 
-    wndPtr = WIN_FindWndPtr(hwnd);
-
     simple = (BOOL32) wParam;
     self->simple = simple;
 
     /* send notification */
-    nmhdr.hwndFrom = hwnd;
+    nmhdr.hwndFrom = wndPtr->hwndSelf;
     nmhdr.idFrom = wndPtr->wIDmenu;
     nmhdr.code = SBN_SIMPLEMODECHANGE;
-    SendMessage32A (GetParent32 (hwnd), WM_NOTIFY, 0, (LPARAM)&nmhdr);
+    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
+		    0, (LPARAM)&nmhdr);
 
-    hdc = GetDC32(hwnd);
-    SW_Refresh(hwnd, hdc, self);
-    ReleaseDC32(hwnd, hdc);
+    hdc = GetDC32 (wndPtr->hwndSelf);
+    STATUSBAR_Refresh (wndPtr, hdc);
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
 
     return TRUE;
 }
 
 
 static LRESULT
-SW_Destroy(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_WMCreate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    int	i;
+    LPCREATESTRUCT32A lpCreate = (LPCREATESTRUCT32A) lParam;
+    NONCLIENTMETRICS32A nclm;
+    RECT32	rect;
+    int	        width, len;
+    HDC32	hdc;
+    STATUSWINDOWINFO *self;
 
-    for (i = 0; i < self->numParts; i++) {
-	if (self->parts[i].text && (self->parts[i].style != SBT_OWNERDRAW))
-	    HeapFree(SystemHeap, 0, self->parts[i].text);
+    self = (STATUSWINDOWINFO*)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
+					 sizeof(STATUSWINDOWINFO));
+    wndPtr->wExtra[0] = (DWORD)self;
+
+    self->numParts = 1;
+    self->parts = 0;
+    self->simple = FALSE;
+    self->clrBk = CLR_DEFAULT;
+    self->hFont = 0;
+    GetClientRect32 (wndPtr->hwndSelf, &rect);
+
+    nclm.cbSize = sizeof(NONCLIENTMETRICS32A);
+    SystemParametersInfo32A (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
+    self->hDefaultFont = CreateFontIndirect32A (&nclm.lfStatusFont);
+
+    /* initialize simple case */
+    self->part0.bound = rect;
+    self->part0.text = 0;
+    self->part0.x = 0;
+    self->part0.style = 0;
+    self->part0.hIcon = 0;
+
+    /* initialize first part */
+    self->parts = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
+			     sizeof(STATUSWINDOWPART));
+    self->parts[0].bound = rect;
+    self->parts[0].text = 0;
+    self->parts[0].x = -1;
+    self->parts[0].style = 0;
+    self->parts[0].hIcon = 0;
+
+    if ((len = lstrlen32A (lpCreate->lpszName))) {
+        self->parts[0].text = HeapAlloc (GetProcessHeap (), 0, len + 1);
+        lstrcpy32A (self->parts[0].text, lpCreate->lpszName);
     }
-    if (self->part0.text && (self->part0.style != SBT_OWNERDRAW))
-	HeapFree(SystemHeap, 0, self->part0.text);
-    HeapFree(SystemHeap, 0, self->parts);
 
-    /* delete default font */
-    if (self->hDefaultFont)
-	DeleteObject32 (self->hDefaultFont);
+    if ((hdc = GetDC32 (0))) {
+	TEXTMETRIC32A tm;
+	HFONT32 hOldFont;
 
-    HeapFree(SystemHeap, 0, self);
+	hOldFont = SelectObject32 (hdc,self->hDefaultFont);
+	GetTextMetrics32A(hdc, &tm);
+	self->textHeight = tm.tmHeight;
+	SelectObject32 (hdc, hOldFont);
+	ReleaseDC32(0, hdc);
+    }
+
+    if (wndPtr->dwStyle & SBT_TOOLTIPS) {
+	self->hwndToolTip =
+	    CreateWindowEx32A (0, TOOLTIPS_CLASS32A, NULL, 0,
+			       CW_USEDEFAULT32, CW_USEDEFAULT32,
+			       CW_USEDEFAULT32, CW_USEDEFAULT32,
+			       wndPtr->hwndSelf, 0,
+			       wndPtr->hInstance, NULL);
+
+	if (self->hwndToolTip) {
+	    NMTOOLTIPSCREATED nmttc;
+
+	    nmttc.hdr.hwndFrom = wndPtr->hwndSelf;
+	    nmttc.hdr.idFrom = wndPtr->wIDmenu;
+	    nmttc.hdr.code = NM_TOOLTIPSCREATED;
+	    nmttc.hwndToolTips = self->hwndToolTip;
+
+	    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
+			    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmttc);
+	}
+    }
+
+    GetClientRect32 (GetParent32 (wndPtr->hwndSelf), &rect);
+    width = rect.right - rect.left;
+    self->height = self->textHeight + 4 + VERT_BORDER;
+    MoveWindow32 (wndPtr->hwndSelf, lpCreate->x, lpCreate->y-1,
+		  width, self->height, FALSE);
+    STATUSBAR_SetPartBounds (wndPtr);
+
     return 0;
 }
 
 
 static LRESULT
-SW_WMGetText (STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_WMDestroy (WND *wndPtr)
 {
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+    int	i;
+
+    for (i = 0; i < self->numParts; i++) {
+	if (self->parts[i].text && (self->parts[i].style != SBT_OWNERDRAW))
+	    HeapFree(GetProcessHeap (), 0, self->parts[i].text);
+    }
+    if (self->part0.text && (self->part0.style != SBT_OWNERDRAW))
+	HeapFree(GetProcessHeap (), 0, self->part0.text);
+    HeapFree(GetProcessHeap (), 0, self->parts);
+
+    /* delete default font */
+    if (self->hDefaultFont)
+	DeleteObject32 (self->hDefaultFont);
+
+    /* delete tool tip control */
+    if (self->hwndToolTip)
+	DestroyWindow32 (self->hwndToolTip);
+
+    HeapFree(GetProcessHeap (), 0, self);
+
+    return 0;
+}
+
+
+static __inline__ LRESULT
+STATUSBAR_WMGetFont (WND *wndPtr)
+{
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+
+    return self->hFont;
+}
+
+
+static LRESULT
+STATUSBAR_WMGetText (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     INT32 len;
 
     if (!(self->parts[0].text))
@@ -605,21 +829,36 @@
 
 
 static LRESULT
-SW_WMGetTextLength (STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_WMGetTextLength (WND *wndPtr)
 {
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+
     if (!(self->parts[0].text))
         return 0;
+
     return (lstrlen32A (self->parts[0].text));
 }
 
 
-static LRESULT
-SW_NcHitTest (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+__inline__ static LRESULT
+STATUSBAR_WMMouseMove (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    RECT32  rect;
-    POINT32 pt;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
 
+    if (self->hwndToolTip)
+	STATUSBAR_RelayEvent (self->hwndToolTip, wndPtr->hwndSelf,
+			      WM_MOUSEMOVE, wParam, lParam);
+    return 0;
+}
+
+
+static LRESULT
+STATUSBAR_WMNCHitTest (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
     if (wndPtr->dwStyle & SBARS_SIZEGRIP) {
+	RECT32  rect;
+	POINT32 pt;
+
 	GetClientRect32 (wndPtr->hwndSelf, &rect);
 
 	pt.x = (INT32)LOWORD(lParam);
@@ -637,86 +876,93 @@
 }
 
 
-static LRESULT
-SW_NcLButtonDown (HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+static __inline__ LRESULT
+STATUSBAR_WMNCLButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    PostMessage32A (GetParent32 (hwnd), WM_NCLBUTTONDOWN,
+    PostMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NCLBUTTONDOWN,
+		    wParam, lParam);
+    return 0;
+}
+
+
+static __inline__ LRESULT
+STATUSBAR_WMNCLButtonUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    PostMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NCLBUTTONUP,
 		    wParam, lParam);
     return 0;
 }
 
 
 static LRESULT
-SW_NcLButtonUp (HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_WMPaint (WND *wndPtr, WPARAM32 wParam)
 {
-    PostMessage32A (GetParent32 (hwnd), WM_NCLBUTTONUP,
-		    wParam, lParam);
+    HDC32 hdc;
+    PAINTSTRUCT32 ps;
+
+    hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
+    STATUSBAR_Refresh (wndPtr, hdc);
+    if (!wParam)
+	EndPaint32 (wndPtr->hwndSelf, &ps);
+
     return 0;
 }
 
 
 static LRESULT
-SW_Paint(STATUSWINDOWINFO *self, HWND32 hwnd)
+STATUSBAR_WMSetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    HDC32 hdc;
-    PAINTSTRUCT32	ps;
-
-    hdc = BeginPaint32(hwnd, &ps);
-    SW_Refresh(hwnd, hdc, self);
-    EndPaint32(hwnd, &ps);
-    return 0;
-}
-
-
-static LRESULT
-SW_WMSetFont (STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
-{
-    HDC32 hdc;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
 
     self->hFont = (HFONT32)wParam;
     if (LOWORD(lParam) == TRUE) {
-        hdc = GetDC32(hwnd);
-        SW_Refresh(hwnd, hdc, self);
-        ReleaseDC32(hwnd, hdc);
+	HDC32 hdc = GetDC32 (wndPtr->hwndSelf);
+        STATUSBAR_Refresh (wndPtr, hdc);
+        ReleaseDC32 (wndPtr->hwndSelf, hdc);
     }
+
     return 0;
 }
 
 
 static LRESULT
-SW_WMSetText (STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_WMSetText (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    int len;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
     STATUSWINDOWPART *part;
+    int len;
+    HDC32 hdc;
 
-    if (self->numParts == 0) return FALSE;
+    if (self->numParts == 0)
+	return FALSE;
 
     part = &self->parts[0];
     /* duplicate string */
     if (part->text)
-        HeapFree(SystemHeap, 0, part->text);
+        HeapFree(GetProcessHeap (), 0, part->text);
     part->text = 0;
     if (lParam && (len = lstrlen32A((LPCSTR)lParam))) {
-        part->text = HeapAlloc (SystemHeap, 0, len+1);
+        part->text = HeapAlloc (GetProcessHeap (), 0, len+1);
         lstrcpy32A (part->text, (LPCSTR)lParam);
     }
-    InvalidateRect32(hwnd, &part->bound, FALSE);
-//    SW_RefreshPart (hdc, part);
+
+    hdc = GetDC32 (wndPtr->hwndSelf);
+    STATUSBAR_RefreshPart (wndPtr, part, hdc);
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
 
     return TRUE;
 }
 
 
 static LRESULT
-SW_Size(STATUSWINDOWINFO *self, HWND32 hwnd, WPARAM32 wParam, LPARAM lParam)
+STATUSBAR_WMSize (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
-    /* Need to resize width to match parent */
-    INT32	width, x, y;
+    STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
+    INT32	width, x, y, flags;
     RECT32	parent_rect;
     HWND32	parent;
 
-    INT32  	flags;
-
+    /* Need to resize width to match parent */
     flags = (INT32) wParam;
 
     /* FIXME for flags =
@@ -725,31 +971,30 @@
 
     if (flags == SIZE_RESTORED) {
 	/* width and height don't apply */
-	parent = GetParent32(hwnd);
-	GetClientRect32(parent, &parent_rect);
+	parent = GetParent32 (wndPtr->hwndSelf);
+	GetClientRect32 (parent, &parent_rect);
 	width = parent_rect.right - parent_rect.left;
 	x = parent_rect.left;
 	y = parent_rect.bottom - self->height;
-	MoveWindow32(hwnd, parent_rect.left, parent_rect.bottom - self->height,
-		     width, self->height, TRUE);
-	SW_SetPartBounds(hwnd, self);
+	MoveWindow32 (wndPtr->hwndSelf, parent_rect.left, 
+		      parent_rect.bottom - self->height,
+		      width, self->height, TRUE);
+	STATUSBAR_SetPartBounds (wndPtr);
     }
     return 0;
 }
 
 
 static LRESULT
-SW_SendNotify (HWND32 hwnd, UINT32 code)
+STATUSBAR_SendNotify (WND *wndPtr, UINT32 code)
 {
-    WND    *wndPtr;
     NMHDR  nmhdr;
 
-    wndPtr = WIN_FindWndPtr(hwnd);
-    nmhdr.hwndFrom = hwnd;
+    nmhdr.hwndFrom = wndPtr->hwndSelf;
     nmhdr.idFrom = wndPtr->wIDmenu;
     nmhdr.code = code;
-    SendMessage32A (GetParent32 (hwnd), WM_NOTIFY, 0, (LPARAM)&nmhdr);
-
+    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
+		    0, (LPARAM)&nmhdr);
     return 0;
 }
 
@@ -758,80 +1003,123 @@
 LRESULT WINAPI
 StatusWindowProc (HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
 {
-    STATUSWINDOWINFO *self;
-    WND *wndPtr;
-
-    wndPtr = WIN_FindWndPtr(hwnd);
-    self = GetStatusInfo(hwnd);
+    WND *wndPtr = WIN_FindWndPtr (hwnd);
 
     switch (msg) {
-    case SB_GETBORDERS:
-	return SW_GetBorders (lParam);
-    case SB_GETICON:
-        return SW_GetIcon(self, hwnd, wParam, lParam);
-    case SB_GETPARTS:
-	return SW_GetParts(self, hwnd, wParam, lParam);
-    case SB_GETRECT:
-	return SW_GetRect(self, hwnd, wParam, lParam);
-    case SB_GETTEXT32A:
-	return SW_GetText(self, hwnd, wParam, lParam);
-    case SB_GETTEXTLENGTH32A:
-	return SW_GetTextLength(self, hwnd, wParam, lParam);
-    case SB_ISSIMPLE:
-        return self->simple;
-    case SB_SETBKCOLOR:
-        return SW_SetBkColor(self, hwnd, wParam, lParam);
-    case SB_SETICON:
-        return SW_SetIcon(self, hwnd, wParam, lParam);
-    case SB_SETMINHEIGHT:
-	return SW_SetMinHeight(self, hwnd, wParam, lParam);
-    case SB_SETPARTS:	
-	return SW_SetParts(self, hwnd, wParam, lParam);
-    case SB_SETTEXT32A:
-	return SW_SetText(self, hwnd, wParam, lParam);
-    case SB_SIMPLE:
-	return SW_Simple(self, hwnd, wParam, lParam);
+	case SB_GETBORDERS:
+	    return STATUSBAR_GetBorders (lParam);
 
-    case WM_CREATE:
-	return SW_Create(hwnd, wParam, lParam);
-    case WM_DESTROY:
-	return SW_Destroy(self, hwnd, wParam, lParam);
-    case WM_GETFONT:
-        return self->hFont;
-    case WM_GETTEXT:
-        return SW_WMGetText(self, hwnd, wParam, lParam);
-    case WM_GETTEXTLENGTH:
-        return SW_WMGetTextLength(self, hwnd, wParam, lParam);
+	case SB_GETICON:
+	    return STATUSBAR_GetIcon (wndPtr, wParam);
 
-    case WM_LBUTTONDBLCLK:
-        return SW_SendNotify (hwnd, NM_DBLCLK);
+	case SB_GETPARTS:
+	    return STATUSBAR_GetParts (wndPtr, wParam, lParam);
 
-    case WM_LBUTTONUP:
-	return SW_SendNotify (hwnd, NM_CLICK);
+	case SB_GETRECT:
+	    return STATUSBAR_GetRect (wndPtr, wParam, lParam);
 
-    case WM_NCHITTEST:
-        return SW_NcHitTest (wndPtr, wParam, lParam);
+	case SB_GETTEXT32A:
+	    return STATUSBAR_GetText32A (wndPtr, wParam, lParam);
 
-    case WM_NCLBUTTONDOWN:
-	return SW_NcLButtonDown (hwnd, wParam, lParam);
+//	case SB_GETTEXT32W:
 
-    case WM_NCLBUTTONUP:
-	return SW_NcLButtonUp (hwnd, wParam, lParam);
+	case SB_GETTEXTLENGTH32A:
+	    return STATUSBAR_GetTextLength32A (wndPtr, wParam, lParam);
 
-    case WM_PAINT:
-	return SW_Paint(self, hwnd);
-    case WM_RBUTTONDBLCLK:
-        return SW_SendNotify (hwnd, NM_RDBLCLK);
-    case WM_RBUTTONUP:
-        return SW_SendNotify (hwnd, NM_RCLICK);
-    case WM_SETFONT:
-        return SW_WMSetFont(self, hwnd, wParam, lParam);
-    case WM_SETTEXT:
-        return SW_WMSetText(self, hwnd, wParam, lParam);
-    case WM_SIZE:
-	return SW_Size(self, hwnd, wParam, lParam);
-    default:
-	return DefWindowProc32A (hwnd, msg, wParam, lParam);
+//	case SB_GETTEXTLENGHT32W:
+
+	case SB_GETTIPTEXT32A:
+	    return STATUSBAR_GetTipText32A (wndPtr, wParam, lParam);
+
+//	case SB_GETTIPTEXT32W:
+//	case SB_GETUNICODEFORMAT:
+
+	case SB_ISSIMPLE:
+	    return STATUSBAR_IsSimple (wndPtr);
+
+	case SB_SETBKCOLOR:
+	    return STATUSBAR_SetBkColor (wndPtr, wParam, lParam);
+
+	case SB_SETICON:
+	    return STATUSBAR_SetIcon (wndPtr, wParam, lParam);
+
+	case SB_SETMINHEIGHT:
+	    return STATUSBAR_SetMinHeight (wndPtr, wParam, lParam);
+
+	case SB_SETPARTS:	
+	    return STATUSBAR_SetParts (wndPtr, wParam, lParam);
+
+	case SB_SETTEXT32A:
+	    return STATUSBAR_SetText32A (wndPtr, wParam, lParam);
+
+//	case SB_SETTEXT32W:
+
+	case SB_SETTIPTEXT32A:
+	    return STATUSBAR_SetTipText32A (wndPtr, wParam, lParam);
+
+//	case SB_SETTIPTEXT32W:
+//	case SB_SETUNICODEFORMAT:
+
+	case SB_SIMPLE:
+	    return STATUSBAR_Simple (wndPtr, wParam, lParam);
+
+
+	case WM_CREATE:
+	    return STATUSBAR_WMCreate (wndPtr, wParam, lParam);
+
+	case WM_DESTROY:
+	    return STATUSBAR_WMDestroy (wndPtr);
+
+	case WM_GETFONT:
+            return STATUSBAR_WMGetFont (wndPtr);
+
+	case WM_GETTEXT:
+            return STATUSBAR_WMGetText (wndPtr, wParam, lParam);
+
+	case WM_GETTEXTLENGTH:
+            return STATUSBAR_WMGetTextLength (wndPtr);
+
+	case WM_LBUTTONDBLCLK:
+            return STATUSBAR_SendNotify (wndPtr, NM_DBLCLK);
+
+	case WM_LBUTTONUP:
+	    return STATUSBAR_SendNotify (wndPtr, NM_CLICK);
+
+	case WM_MOUSEMOVE:
+            return STATUSBAR_WMMouseMove (wndPtr, wParam, lParam);
+
+	case WM_NCHITTEST:
+            return STATUSBAR_WMNCHitTest (wndPtr, wParam, lParam);
+
+	case WM_NCLBUTTONDOWN:
+	    return STATUSBAR_WMNCLButtonDown (wndPtr, wParam, lParam);
+
+	case WM_NCLBUTTONUP:
+	    return STATUSBAR_WMNCLButtonUp (wndPtr, wParam, lParam);
+
+	case WM_PAINT:
+	    return STATUSBAR_WMPaint (wndPtr, wParam);
+
+	case WM_RBUTTONDBLCLK:
+	    return STATUSBAR_SendNotify (wndPtr, NM_RDBLCLK);
+
+	case WM_RBUTTONUP:
+	    return STATUSBAR_SendNotify (wndPtr, NM_RCLICK);
+
+	case WM_SETFONT:
+	    return STATUSBAR_WMSetFont (wndPtr, wParam, lParam);
+
+	case WM_SETTEXT:
+	    return STATUSBAR_WMSetText (wndPtr, wParam, lParam);
+
+	case WM_SIZE:
+	    return STATUSBAR_WMSize (wndPtr, wParam, lParam);
+
+	default:
+	    if (msg >= WM_USER)
+		ERR (statusbar, "unknown msg %04x wp=%04x lp=%08lx\n",
+		     msg, wParam, lParam);
+	    return DefWindowProc32A (hwnd, msg, wParam, lParam);
     }
     return 0;
 }
diff --git a/controls/toolbar.c b/controls/toolbar.c
index c604954..6a883d5 100644
--- a/controls/toolbar.c
+++ b/controls/toolbar.c
@@ -10,7 +10,7 @@
  *   - Notifications.
  *   - Fix TB_GETBITMAPFLAGS.
  *   - Fix TB_GETROWS and TB_SETROWS.
- *   - Tooltip support (partially).
+ *   - Tooltip support (under contruction).
  *   - Unicode suppport.
  *   - Internal COMMCTL32 bitmaps.
  *   - Fix TOOLBAR_Customize. (Customize dialog.)
@@ -249,8 +249,6 @@
     BOOL32 bVertical;
     SIZE32  sizeString;
 
-
-    /* test */
     TOOLBAR_CalcStrings (wndPtr, &sizeString);
 
     if (sizeString.cy > 0)
@@ -301,6 +299,18 @@
 	btnPtr->rect.right  = x + cx;
 	btnPtr->rect.bottom = y + cy;
 
+	if (infoPtr->hwndToolTip) {
+	    TTTOOLINFO32A ti;
+
+	    ZeroMemory (&ti, sizeof(TTTOOLINFO32A));
+	    ti.cbSize = sizeof(TTTOOLINFO32A);
+	    ti.hwnd = wndPtr->hwndSelf;
+	    ti.uId = btnPtr->idCommand;
+	    ti.rect = btnPtr->rect;
+	    SendMessage32A (infoPtr->hwndToolTip, TTM_NEWTOOLRECT32A,
+			    0, (LPARAM)&ti);
+	}
+
 	if (bVertical) {
 	    x = 0;
 	    y += cy;
@@ -411,6 +421,24 @@
 }
 
 
+static VOID
+TOOLBAR_RelayEvent (HWND32 hwndTip, HWND32 hwndMsg, UINT32 uMsg,
+		    WPARAM32 wParam, LPARAM lParam)
+{
+    MSG32 msg;
+
+    msg.hwnd = hwndMsg;
+    msg.message = uMsg;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    msg.time = GetMessageTime ();
+    msg.pt.x = LOWORD(GetMessagePos ());
+    msg.pt.y = HIWORD(GetMessagePos ());
+
+    SendMessage32A (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
+}
+
+
 static LRESULT
 TOOLBAR_AddBitmap (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
@@ -512,6 +540,20 @@
 	infoPtr->buttons[nOldButtons+nCount].fsStyle   = lpTbb[nCount].fsStyle;
 	infoPtr->buttons[nOldButtons+nCount].dwData    = lpTbb[nCount].dwData;
 	infoPtr->buttons[nOldButtons+nCount].iString   = lpTbb[nCount].iString;
+
+	if (infoPtr->hwndToolTip) {
+	    TTTOOLINFO32A ti;
+
+	    ZeroMemory (&ti, sizeof(TTTOOLINFO32A));
+	    ti.cbSize   = sizeof (TTTOOLINFO32A);
+	    ti.hwnd     = wndPtr->hwndSelf;
+	    ti.uId      = (LPSTR)lpTbb[nCount].idCommand;
+	    ti.hinst    = 0;
+	    ti.lpszText = LPSTR_TEXTCALLBACK32A;
+
+	    SendMessage32A (infoPtr->hwndToolTip, TTM_ADDTOOL32A,
+			    0, (LPARAM)&ti);
+	}
     }
 
     TOOLBAR_CalcToolbar (wndPtr);
@@ -636,8 +678,8 @@
 	cy += 2;
 
     infoPtr->bAutoSize = TRUE;
-    SetWindowPos32 (wndPtr->hwndSelf, 0, parent_rect.left, parent_rect.top,
-		    cx, cy, uPosFlags | SWP_NOZORDER);
+    SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, parent_rect.left, parent_rect.top,
+		    cx, cy, uPosFlags);
 
     return 0;
 }
@@ -763,6 +805,17 @@
     if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
 	return FALSE;
 
+    if (infoPtr->hwndToolTip) {
+	TTTOOLINFO32A ti;
+
+	ZeroMemory (&ti, sizeof(TTTOOLINFO32A));
+	ti.cbSize   = sizeof (TTTOOLINFO32A);
+	ti.hwnd     = wndPtr->hwndSelf;
+	ti.uId      = infoPtr->buttons[nIndex].idCommand;
+
+	SendMessage32A (infoPtr->hwndToolTip, TTM_DELTOOL32A, 0, (LPARAM)&ti);
+    }
+
     if (infoPtr->nNumButtons == 1) {
 	TRACE (toolbar, " simple delete!\n");
 	HeapFree (GetProcessHeap (), 0, infoPtr->buttons);
@@ -875,7 +928,55 @@
 }
 
 
-// << TOOLBAR_GetButtonInfo >>
+static LRESULT
+TOOLBAR_GetButtonInfo32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    LPTBBUTTONINFO32A lpTbInfo = (LPTBBUTTONINFO32A)lParam;
+    TBUTTON_INFO *btnPtr;
+    INT32 nIndex;
+
+    if (infoPtr == NULL) return -1;
+    if (lpTbInfo == NULL) return -1;
+    if (lpTbInfo->cbSize < sizeof(LPTBBUTTONINFO32A)) return -1;
+
+    nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT32)wParam);
+
+    if (nIndex == -1)
+	return -1;
+
+    btnPtr = &infoPtr->buttons[nIndex];
+
+    if (lpTbInfo->dwMask & TBIF_COMMAND)
+	lpTbInfo->idCommand = btnPtr->idCommand;
+
+    if (lpTbInfo->dwMask & TBIF_IMAGE)
+	lpTbInfo->iImage = btnPtr->iBitmap;
+
+    if (lpTbInfo->dwMask & TBIF_LPARAM)
+	lpTbInfo->lParam = btnPtr->dwData;
+
+    if (lpTbInfo->dwMask & TBIF_SIZE)
+	lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
+
+    if (lpTbInfo->dwMask & TBIF_STATE)
+	lpTbInfo->fsState = btnPtr->fsState;
+
+    if (lpTbInfo->dwMask & TBIF_STYLE)
+	lpTbInfo->fsStyle = btnPtr->fsStyle;
+
+    if (lpTbInfo->dwMask & TBIF_TEXT) {
+	if ((btnPtr->iString >= 0) || (btnPtr->iString < infoPtr->nNumStrings))
+	    lstrcpyn32A (lpTbInfo->pszText, 
+			 (LPSTR)infoPtr->strings[btnPtr->iString],
+			 lpTbInfo->cchText);
+    }
+
+    return nIndex;
+}
+
+
+// << TOOLBAR_GetButtonInfo32W >>
 
 
 static LRESULT
@@ -929,7 +1030,13 @@
 }
 
 
-// << TOOLBAR_GetExtendedStyle >>
+__inline__ static LRESULT
+TOOLBAR_GetExtendedStyle (WND *wndPtr)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+
+    return infoPtr->dwExStyle;
+}
 
 
 static LRESULT
@@ -995,7 +1102,7 @@
     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
     LPSIZE32 lpSize = (LPSIZE32)lParam;
 
-
+    FIXME (toolbar, "empty stub!\n");
 
     return TRUE;
 }
@@ -1155,6 +1262,20 @@
     infoPtr->buttons[nIndex].dwData    = lpTbb->dwData;
     infoPtr->buttons[nIndex].iString   = lpTbb->iString;
 
+    if (infoPtr->hwndToolTip) {
+	TTTOOLINFO32A ti;
+
+	ZeroMemory (&ti, sizeof(TTTOOLINFO32A));
+	ti.cbSize   = sizeof (TTTOOLINFO32A);
+	ti.hwnd     = wndPtr->hwndSelf;
+	ti.uId      = lpTbb->idCommand;
+	ti.hinst    = 0;
+	ti.lpszText = LPSTR_TEXTCALLBACK32A;
+
+	SendMessage32A (infoPtr->hwndToolTip, TTM_ADDTOOL32A,
+			0, (LPARAM)&ti);
+    }
+
     /* post insert copy */
     if (nIndex < infoPtr->nNumButtons - 1) {
 	memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
@@ -1612,10 +1733,25 @@
 
     if (wndPtr->dwStyle & TBSTYLE_TOOLTIPS) {
 	/* Create tooltip control */
-//	infoPtr->hwndToolTip = CreateWindowEx32A (....);
+	infoPtr->hwndToolTip =
+	    CreateWindowEx32A (0, TOOLTIPS_CLASS32A, NULL, TTS_ALWAYSTIP,
+			       CW_USEDEFAULT32, CW_USEDEFAULT32,
+			       CW_USEDEFAULT32, CW_USEDEFAULT32,
+			       wndPtr->hwndSelf, 0,
+			       wndPtr->hInstance, 0);
 
 	/* Send NM_TOOLTIPSCREATED notification */
+	if (infoPtr->hwndToolTip) {
+	    NMTOOLTIPSCREATED nmttc;
 
+	    nmttc.hdr.hwndFrom = wndPtr->hwndSelf;
+	    nmttc.hdr.idFrom = wndPtr->wIDmenu;
+	    nmttc.hdr.code = NM_TOOLTIPSCREATED;
+	    nmttc.hwndToolTips = infoPtr->hwndToolTip;
+
+	    SendMessage32A (infoPtr->hwndNotify, WM_NOTIFY,
+			    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmttc);
+	}
     }
 
     return 0;
@@ -1724,6 +1860,10 @@
     INT32   nHit;
     HDC32   hdc;
 
+    if (infoPtr->hwndToolTip)
+	TOOLBAR_RelayEvent (infoPtr->hwndToolTip, wndPtr->hwndSelf,
+			    WM_LBUTTONDOWN, wParam, lParam);
+
     pt.x = (INT32)LOWORD(lParam);
     pt.y = (INT32)HIWORD(lParam);
     nHit = TOOLBAR_InternalHitTest (wndPtr, &pt);
@@ -1761,6 +1901,10 @@
     HDC32   hdc;
     BOOL32  bSendMessage = TRUE;
 
+    if (infoPtr->hwndToolTip)
+	TOOLBAR_RelayEvent (infoPtr->hwndToolTip, wndPtr->hwndSelf,
+			    WM_LBUTTONUP, wParam, lParam);
+
     pt.x = (INT32)LOWORD(lParam);
     pt.y = (INT32)HIWORD(lParam);
     nHit = TOOLBAR_InternalHitTest (wndPtr, &pt);
@@ -1822,6 +1966,10 @@
     INT32   nHit;
     HDC32   hdc;
 
+    if (infoPtr->hwndToolTip)
+	TOOLBAR_RelayEvent (infoPtr->hwndToolTip, wndPtr->hwndSelf,
+			    WM_MOUSEMOVE, wParam, lParam);
+
     pt.x = (INT32)LOWORD(lParam);
     pt.y = (INT32)HIWORD(lParam);
     nHit = TOOLBAR_InternalHitTest (wndPtr, &pt);
@@ -1885,9 +2033,13 @@
 	return 0;
     }
 
-    /* this is just for security (reliable??)*/
+    /* paranoid!! */
     infoPtr->dwStructSize = sizeof(TBBUTTON);
 
+    /* fix instance handle, if the toolbar was created by CreateToolbarEx() */
+    if (!wndPtr->hInstance)
+	wndPtr->hInstance = wndPtr->parent->hInstance;
+
     return DefWindowProc32A (wndPtr->hwndSelf, WM_NCCREATE, wParam, lParam);
 }
 
@@ -1910,8 +2062,7 @@
 		        wndPtr->rectClient.top-wndPtr->rectWindow.top,
 		        wndPtr->rectClient.right-wndPtr->rectWindow.left,
 		        wndPtr->rectClient.bottom-wndPtr->rectWindow.top )
-	== NULLREGION)
-    {
+	== NULLREGION){
 	ReleaseDC32( hwnd, hdc );
 	return 0;
     }
@@ -1939,6 +2090,23 @@
 }
 
 
+__inline__ static LRESULT
+TOOLBAR_Notify (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(wndPtr);
+    LPNMHDR lpnmh = (LPNMHDR)lParam;
+
+    if ((infoPtr->hwndToolTip) && ((lpnmh->code == TTN_GETDISPINFO32A) ||
+	(lpnmh->code == TTN_GETDISPINFO32W))) {
+
+	SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
+			wParam, lParam);
+    }
+
+    return 0;
+}
+
+
 static LRESULT
 TOOLBAR_Paint (WND *wndPtr, WPARAM32 wParam)
 {
@@ -2079,7 +2247,10 @@
 	case TB_GETBUTTON:
 	    return TOOLBAR_GetButton (wndPtr, wParam, lParam);
 
-//	case TB_GETBUTTONINFO:			/* 4.71 */
+	case TB_GETBUTTONINFO32A:
+	    return TOOLBAR_GetButtonInfo32A (wndPtr, wParam, lParam);
+
+//	case TB_GETBUTTONINFO32W:		/* 4.71 */
 
 	case TB_GETBUTTONSIZE:
 	    return TOOLBAR_GetButtonSize (wndPtr);
@@ -2093,7 +2264,8 @@
 	case TB_GETDISABLEDIMAGELIST:
 	    return TOOLBAR_GetDisabledImageList (wndPtr, wParam, lParam);
 
-//	case TB_GETEXTENDEDSTYLE:		/* 4.71 */
+	case TB_GETEXTENDEDSTYLE:
+	    return TOOLBAR_GetExtendedStyle (wndPtr);
 
 	case TB_GETHOTIMAGELIST:
 	    return TOOLBAR_GetHotImageList (wndPtr, wParam, lParam);
@@ -2185,7 +2357,8 @@
 	case TB_SETBITMAPSIZE:
 	    return TOOLBAR_SetBitmapSize (wndPtr, wParam, lParam);
 
-//	case TB_SETBUTTONINFO:			/* 4.71 */
+//	case TB_SETBUTTONINFO32A:		/* 4.71 */
+//	case TB_SETBUTTONINFO32W:		/* 4.71 */
 
 	case TB_SETBUTTONSIZE:
 	    return TOOLBAR_SetButtonSize (wndPtr, wParam, lParam);
@@ -2243,15 +2416,23 @@
 	    return TOOLBAR_SetUnicodeFormat (wndPtr, wParam, lParam);
 
 
+//	case WM_CHAR:
+
 	case WM_CREATE:
 	    return TOOLBAR_Create (wndPtr, wParam, lParam);
 
+//	case WM_COMMAND:
+
 	case WM_DESTROY:
 	    return TOOLBAR_Destroy (wndPtr, wParam, lParam);
 
 	case WM_ERASEBKGND:
 	    return TOOLBAR_EraseBackground (wndPtr, wParam, lParam);
 
+//	case WM_GETFONT:
+//	case WM_KEYDOWN:
+//	case WM_KILLFOCUS:
+
 	case WM_LBUTTONDBLCLK:
 	    return TOOLBAR_LButtonDblClk (wndPtr, wParam, lParam);
 
@@ -2276,8 +2457,10 @@
 	case WM_NCPAINT:
 	    return TOOLBAR_NCPaint (wndPtr, wParam, lParam);
 
-//	case WM_NOTIFY:
-//	    SendMessage32A (GetParent32 (hwnd), uMsg, wParam, lParam);
+	case WM_NOTIFY:
+	    return TOOLBAR_Notify (wndPtr, wParam, lParam);
+
+//	case WM_NOTIFYFORMAT:
 
 	case WM_PAINT:
 	    return TOOLBAR_Paint (wndPtr, wParam);
@@ -2306,8 +2489,7 @@
 }
 
 
-void
-TOOLBAR_Register (void)
+void TOOLBAR_Register (void)
 {
     WNDCLASS32A wndClass;
 
@@ -2324,4 +2506,3 @@
  
     RegisterClass32A (&wndClass);
 }
-
diff --git a/controls/tooltips.c b/controls/tooltips.c
index 69a00ef..e0e8477 100644
--- a/controls/tooltips.c
+++ b/controls/tooltips.c
@@ -4,17 +4,24 @@
  * Copyright 1998 Eric Kohl
  *
  * TODO:
- *   - Some messages.
- *   - All notifications.
+ *   - Subclassing.
+ *   - Tracking tooltips (under construction).
+ *   - TTS_ALWAYSTIP (undefined).
+ *   - Unicode support.
+ *   - Custom draw support.
  *
  * Testing:
  *   - Run tests using Waite Group Windows95 API Bible Volume 2.
- *     The second cdrom contains executables enumtools.exe ...
- *   - additional features.
+ *     The second cdrom (chapter 3) contains executables activate.exe,
+ *     curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe,
+ *     hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe.
  *
- * FIXME:
- *   - Display code.
- *   - Missing Unicode support.
+ *   - Activate.exe, deltool.exe, enumtool.exe, getinfo.exe and getiptxt.exe
+ *     are the only working examples, since subclassing is not implemented.
+ *
+ * Fixme:
+ *   - The "lParam" variable from NMTTDISPINFO32A is not handled
+ *     in TOOLTIPS_GetTipText.
  */
 
 #include "windows.h"
@@ -25,8 +32,9 @@
 #include "debug.h"
 
 
-#define ID_TIMER1  1
-#define ID_TIMER2  2
+#define ID_TIMER1  1    /* show delay timer */
+#define ID_TIMER2  2    /* auto pop timer */
+#define ID_TIMER3  3    /* tool leave timer */
 
 #define TOOLTIPS_GetInfoPtr(wndPtr) ((TOOLTIPS_INFO *)wndPtr->wExtra[0])
 
@@ -38,12 +46,21 @@
     RECT32 rc;
     INT32 oldBkMode;
     HFONT32 hOldFont;
+    UINT32 uFlags = DT_EXTERNALLEADING;
 
+    if (infoPtr->nMaxTipWidth > -1)
+	uFlags |= DT_WORDBREAK;
+    if (wndPtr->dwStyle & TTS_NOPREFIX)
+	uFlags |= DT_NOPREFIX;
     GetClientRect32 (wndPtr->hwndSelf, &rc);
+    rc.left   += (2 + infoPtr->rcMargin.left);
+    rc.top    += (2 + infoPtr->rcMargin.top);
+    rc.right  -= (2 + infoPtr->rcMargin.right);
+    rc.bottom -= (2 + infoPtr->rcMargin.bottom);
     oldBkMode = SetBkMode32 (hdc, TRANSPARENT);
     SetTextColor32 (hdc, infoPtr->clrText);
     hOldFont = SelectObject32 (hdc, infoPtr->hFont);
-    DrawText32A (hdc, infoPtr->szTipText, -1, &rc, DT_EXTERNALLEADING);
+    DrawText32A (hdc, infoPtr->szTipText, -1, &rc, uFlags);
     SelectObject32 (hdc, hOldFont);
     if (oldBkMode != TRANSPARENT)
 	SetBkMode32 (hdc, oldBkMode);
@@ -56,28 +73,72 @@
     TTTOOL_INFO *toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
 
     if (toolPtr->hinst) {
+	TRACE (tooltips, "get res string %x %x\n",
+	       toolPtr->hinst, (int)toolPtr->lpszText);
 	LoadString32A (toolPtr->hinst, (UINT32)toolPtr->lpszText,
 		       infoPtr->szTipText, INFOTIPSIZE);
     }
     else if (toolPtr->lpszText) {
 	if (toolPtr->lpszText == LPSTR_TEXTCALLBACK32A) {
-	    NMTTDISPINFOA ttnmdi;
+	    NMTTDISPINFO32A ttnmdi;
 
 	    /* fill NMHDR struct */
+	    ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFO32A));
 	    ttnmdi.hdr.hwndFrom = wndPtr->hwndSelf;
-	    ttnmdi.hdr.idFrom = infoPtr->nCurrentTool;
-	    ttnmdi.hdr.code = TTN_GETDISPINFOA;
+	    ttnmdi.hdr.idFrom = toolPtr->uId;
+	    ttnmdi.hdr.code = TTN_GETDISPINFO32A;
+	    ttnmdi.uFlags = toolPtr->uFlags;
+	    ttnmdi.lpszText = infoPtr->szTipText;
 
+	    TRACE (tooltips, "hdr.idFrom = %x\n", ttnmdi.hdr.idFrom);
 	    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
 			    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&ttnmdi);
 
-	    /* FIXME: partial */
-	    lstrcpyn32A (infoPtr->szTipText, ttnmdi.szText, INFOTIPSIZE);
-
+	    if (ttnmdi.hinst) {
+		LoadString32A (ttnmdi.hinst, (UINT32)ttnmdi.szText,
+			       infoPtr->szTipText, INFOTIPSIZE);
+		if (ttnmdi.uFlags & TTF_DI_SETITEM) {
+		    toolPtr->hinst = ttnmdi.hinst;
+		    toolPtr->lpszText = ttnmdi.szText;
+		}
+	    }
+	    else if (ttnmdi.szText[0]) {
+		lstrcpyn32A (infoPtr->szTipText, ttnmdi.szText, 80);
+		if (ttnmdi.uFlags & TTF_DI_SETITEM) {
+		    INT32 len = lstrlen32A (ttnmdi.szText) + 1;
+		    toolPtr->hinst = 0;
+		    toolPtr->lpszText =	
+			HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len);
+		    lstrcpy32A (toolPtr->lpszText, ttnmdi.szText);
+		}
+	    }
+	    else if (ttnmdi.lpszText == 0) {
+		/* no text available */
+		infoPtr->szTipText[0] = '\0';
+	    }
+	    else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACK32A) {
+		if (ttnmdi.lpszText != infoPtr->szTipText)
+		    lstrcpyn32A (infoPtr->szTipText, ttnmdi.lpszText,
+				 INFOTIPSIZE);
+		if (ttnmdi.uFlags & TTF_DI_SETITEM) {
+		    INT32 len = lstrlen32A (ttnmdi.lpszText) + 1;
+		    toolPtr->hinst = 0;
+		    toolPtr->lpszText =	
+			HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len);
+		    lstrcpy32A (toolPtr->lpszText, ttnmdi.lpszText);
+		}
+	    }
+	    else
+		ERR (tooltips, "recursive text callback!\n");
 	}
 	else
 	    lstrcpyn32A (infoPtr->szTipText, toolPtr->lpszText, INFOTIPSIZE);
     }
+    else
+	/* no text available */
+	infoPtr->szTipText[0] = '\0';
+
+    TRACE (tooltips, "\"%s\"\n", infoPtr->szTipText);
 }
 
 
@@ -86,36 +147,94 @@
 {
     HDC32 hdc;
     HFONT32 hOldFont;
-    RECT32 rc;
+    UINT32 uFlags = DT_EXTERNALLEADING | DT_CALCRECT;
+    RECT32 rc = {0, 0, 0, 0};
+
+    if (infoPtr->nMaxTipWidth > -1) {
+	rc.right = infoPtr->nMaxTipWidth;
+	uFlags |= DT_WORDBREAK;
+    }
+    if (wndPtr->dwStyle & TTS_NOPREFIX)
+	uFlags |= DT_NOPREFIX;
+    TRACE (tooltips, "\"%s\"\n", infoPtr->szTipText);
 
     hdc = GetDC32 (wndPtr->hwndSelf);
     hOldFont = SelectObject32 (hdc, infoPtr->hFont);
-    DrawText32A (hdc, infoPtr->szTipText, -1, &rc, DT_EXTERNALLEADING | DT_CALCRECT);
+    DrawText32A (hdc, infoPtr->szTipText, -1, &rc, uFlags);
     SelectObject32 (hdc, hOldFont);
-    ReleaseDC32 (hdc, wndPtr->hwndSelf);
+    ReleaseDC32 (wndPtr->hwndSelf, hdc);
 
-    lpSize->cx = rc.right - rc.left + 4;
-    lpSize->cy = rc.bottom - rc.top + 4;
+    lpSize->cx = rc.right - rc.left + 4 + 
+		 infoPtr->rcMargin.left + infoPtr->rcMargin.right;
+    lpSize->cy = rc.bottom - rc.top + 4 +
+		 infoPtr->rcMargin.bottom + infoPtr->rcMargin.top;
 }
 
 
 static VOID
 TOOLTIPS_Show (WND *wndPtr, TOOLTIPS_INFO *infoPtr)
 {
+    TTTOOL_INFO *toolPtr;
     POINT32 pt;
     SIZE32 size;
+    NMHDR hdr;
+
+    if (infoPtr->nTool == -1) {
+	TRACE (tooltips, "invalid tool (-1)!\n");
+	return;
+    }
 
     infoPtr->nCurrentTool = infoPtr->nTool;
-    FIXME (tooltips, "Show tooltip %d!\n", infoPtr->nCurrentTool);
 
-    GetCursorPos32 (&pt);
+    TRACE (tooltips, "Show tooltip pre %d!\n", infoPtr->nTool);
 
     TOOLTIPS_GetTipText (wndPtr, infoPtr);
+
+    if (infoPtr->szTipText[0] == '\0') {
+	infoPtr->nCurrentTool = -1;
+	return;
+    }
+
+    TRACE (tooltips, "Show tooltip %d!\n", infoPtr->nTool);
+
+    hdr.hwndFrom = wndPtr->hwndSelf;
+    hdr.idFrom = infoPtr->nTool;
+    hdr.code = TTN_SHOW;
+    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
+		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&hdr);
+
     TRACE (tooltips, "\"%s\"\n", infoPtr->szTipText);
 
+    toolPtr = &infoPtr->tools[infoPtr->nTool];
     TOOLTIPS_CalcTipSize (wndPtr, infoPtr, &size);
+    TRACE (tooltips, "size %d - %d\n", size.cx, size.cy);
 
-    SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, pt.x, pt.y + 20,
+    if ((toolPtr->uFlags & TTF_TRACK) && (toolPtr->uFlags & TTF_ABSOLUTE)) {
+	pt.x = infoPtr->xTrackPos;
+	pt.y = infoPtr->yTrackPos;
+    }
+    else if (toolPtr->uFlags & TTF_CENTERTIP) {
+	RECT32 rect;
+
+	if (toolPtr->uFlags & TTF_IDISHWND)
+	    GetWindowRect32 ((HWND32)toolPtr->uId, &rect);
+	else {
+	    rect = toolPtr->rect;
+	    MapWindowPoints32 (toolPtr->hwnd, (HWND32)0, (LPPOINT32)&rect, 2);
+	}
+	pt.x = (rect.left + rect.right - size.cx) / 2;
+	pt.y = rect.bottom + 2;
+    }
+    else {
+	GetCursorPos32 (&pt);
+	pt.y += 20;
+    }
+
+    TRACE (tooltips, "pos %d - %d\n", pt.x, pt.y);
+
+//    SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, pt.x, pt.y,
+//		    size.cx, size.cy, SWP_SHOWWINDOW);
+    SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, 1, 1,
 		    size.cx, size.cy, SWP_SHOWWINDOW);
 
     SetTimer32 (wndPtr->hwndSelf, ID_TIMER2, infoPtr->nAutoPopTime, 0);
@@ -125,28 +244,63 @@
 static VOID
 TOOLTIPS_Hide (WND *wndPtr, TOOLTIPS_INFO *infoPtr)
 {
+    NMHDR hdr;
+
     if (infoPtr->nCurrentTool == -1)
 	return;
 
-    FIXME (tooltips, "Hide tooltip %d!\n", infoPtr->nCurrentTool);
+    TRACE (tooltips, "Hide tooltip %d!\n", infoPtr->nCurrentTool);
     KillTimer32 (wndPtr->hwndSelf, ID_TIMER2);
+
+    hdr.hwndFrom = wndPtr->hwndSelf;
+    hdr.idFrom = infoPtr->nCurrentTool;
+    hdr.code = TTN_POP;
+    SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
+		    (WPARAM32)wndPtr->wIDmenu, (LPARAM)&hdr);
+
     infoPtr->nCurrentTool = -1;
+
     SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0, SWP_HIDEWINDOW);
 }
 
 
 static INT32
-TOOLTIPS_GetIndexFromInfoA (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOA lpToolInfo)
+TOOLTIPS_GetToolFromInfoA (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFO32A lpToolInfo)
 {
     TTTOOL_INFO *toolPtr;
-    INT32 nIndex;
+    INT32 nTool;
 
-    for (nIndex = 0; nIndex < infoPtr->uNumTools; nIndex++) {
-	toolPtr = &infoPtr->tools[nIndex];
+#if 0
+    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
+	toolPtr = &infoPtr->tools[nTool];
 
-	if ((lpToolInfo->hwnd == toolPtr->hwnd) &&
+	if (toolPtr->uFlags & TTF_IDISHWND) {
+	    if (lpToolInfo->uId == toolPtr->uId)
+		return nTool;
+	}
+	else {
+	    if ((lpToolInfo->hwnd == toolPtr->hwnd) &&
+		(lpToolInfo->uId == toolPtr->uId))
+		return nTool;
+	}
+    }
+#endif
+
+    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
+	toolPtr = &infoPtr->tools[nTool];
+
+	if (!(toolPtr->uFlags & TTF_IDISHWND) && 
+	    (lpToolInfo->hwnd == toolPtr->hwnd) &&
 	    (lpToolInfo->uId == toolPtr->uId))
-	    return nIndex;
+	    return nTool;
+    }
+
+    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
+	toolPtr = &infoPtr->tools[nTool];
+
+	if ((toolPtr->uFlags & TTF_IDISHWND) &&
+	    (lpToolInfo->uId == toolPtr->uId))
+	    return nTool;
     }
 
     return -1;
@@ -154,24 +308,24 @@
 
 
 static INT32
-TOOLTIPS_GetIndexFromPoint (TOOLTIPS_INFO *infoPtr, HWND32 hwnd, LPPOINT32 lpPt)
+TOOLTIPS_GetToolFromPoint (TOOLTIPS_INFO *infoPtr, HWND32 hwnd, LPPOINT32 lpPt)
 {
     TTTOOL_INFO *toolPtr;
-    INT32  nIndex;
+    INT32  nTool;
 
-    for (nIndex = 0; nIndex < infoPtr->uNumTools; nIndex++) {
-	toolPtr = &infoPtr->tools[nIndex];
+    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
+	toolPtr = &infoPtr->tools[nTool];
 
 	if (toolPtr->uFlags & TTF_IDISHWND) {
 	    if ((HWND32)toolPtr->uId == hwnd)
-		return nIndex;
+		return nTool;
 	}
 	else {
 	    if (hwnd != toolPtr->hwnd)
 		continue;
 	    if (!PtInRect32 (&toolPtr->rect, *lpPt))
 		continue;
-	    return nIndex;
+	    return nTool;
 	}
     }
 
@@ -179,6 +333,28 @@
 }
 
 
+static BOOL32
+TOOLTIPS_CheckTool (WND *wndPtr)
+{
+    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
+    POINT32 pt;
+    HWND32 hwndTool;
+    INT32 nTool;
+
+    GetCursorPos32 (&pt);
+    hwndTool =
+	SendMessage32A (wndPtr->hwndSelf, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt);
+    if (hwndTool == 0)
+	return FALSE;
+
+    ScreenToClient32 (hwndTool, &pt);
+    nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt);
+    TRACE (tooltips, "tool %d\n", nTool);
+
+    return (nTool != -1);
+}
+
+
 static LRESULT
 TOOLTIPS_Activate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
@@ -186,12 +362,11 @@
 
     infoPtr->bActive = (BOOL32)wParam;
 
-    if (infoPtr->bActive) {
-	FIXME (tooltips, "activated!\n");
-    }
-    else {
-	FIXME (tooltips, "deactivated!\n");
-    }
+    if (infoPtr->bActive)
+	TRACE (tooltips, "activate!\n");
+
+    if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1)) 
+	    TOOLTIPS_Hide (wndPtr, infoPtr);
 
     return 0;
 }
@@ -201,11 +376,18 @@
 TOOLTIPS_AddTool32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
-    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
+    LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
     TTTOOL_INFO *toolPtr;
 
     if (lpToolInfo == NULL) return FALSE;
 
+    if (lpToolInfo->uFlags & TTF_SUBCLASS)
+	FIXME (tooltips, "subclassing not supported!\n");
+
+    TRACE (tooltips, "add tool (%x) %x %d%s!\n",
+	   wndPtr->hwndSelf, lpToolInfo->hwnd, lpToolInfo->uId,
+	   (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");
+
     if (infoPtr->uNumTools == 0) {
 	infoPtr->tools =
 	    HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
@@ -233,20 +415,24 @@
     toolPtr->hinst  = lpToolInfo->hinst;
 
     if (lpToolInfo->hinst) {
+	TRACE (tooltips, "add string id %x!\n", (int)lpToolInfo->lpszText);
 	toolPtr->lpszText = lpToolInfo->lpszText;
     }
     else if (lpToolInfo->lpszText) {
-	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACK32A)
+	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACK32A) {
+	    TRACE (tooltips, "add CALLBACK!\n");
 	    toolPtr->lpszText = lpToolInfo->lpszText;
+	}
 	else {
 	    INT32 len = lstrlen32A (lpToolInfo->lpszText);
+	    TRACE (tooltips, "add text \"%s\"!\n", lpToolInfo->lpszText);
 	    toolPtr->lpszText =
 		HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len + 1);
 	    lstrcpy32A (toolPtr->lpszText, lpToolInfo->lpszText);
 	}
     }
 
-    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
+    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
 	toolPtr->lParam = lpToolInfo->lParam;
 
     return TRUE;
@@ -260,20 +446,20 @@
 TOOLTIPS_DelTool32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
-    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
+    LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
     TTTOOL_INFO *toolPtr;
-    INT32 nIndex;
+    INT32 nTool;
 
     if (lpToolInfo == NULL) return 0;
     if (infoPtr->uNumTools == 0) return 0;
 
-    nIndex = TOOLTIPS_GetIndexFromInfoA (infoPtr, lpToolInfo);
-    if (nIndex == -1) return 0;
+    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
+    if (nTool == -1) return 0;
 
-    TRACE (tooltips, "index=%d\n", nIndex);
+    TRACE (tooltips, "tool %d\n", nTool);
 
     /* delete text string */
-    toolPtr = &infoPtr->tools[nIndex]; 
+    toolPtr = &infoPtr->tools[nTool]; 
     if ((toolPtr->hinst) && (toolPtr->lpszText)) {
 	if (toolPtr->lpszText != LPSTR_TEXTCALLBACK32A)
 	    HeapFree (GetProcessHeap (), 0, toolPtr->lpszText);
@@ -290,13 +476,13 @@
 	    HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
 		       sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
 
-	if (nIndex > 0)
+	if (nTool > 0)
 	    memcpy (&infoPtr->tools[0], &oldTools[0],
-		    nIndex * sizeof(TTTOOL_INFO));
+		    nTool * sizeof(TTTOOL_INFO));
 
-	if (nIndex < infoPtr->uNumTools - 1)
-	    memcpy (&infoPtr->tools[nIndex], &oldTools[nIndex + 1],
-		    (infoPtr->uNumTools - nIndex - 1) * sizeof(TTTOOL_INFO));
+	if (nTool < infoPtr->uNumTools - 1)
+	    memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1],
+		    (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO));
 
 	HeapFree (GetProcessHeap (), 0, oldTools);
     }
@@ -315,7 +501,7 @@
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
     UINT32 uIndex = (UINT32)wParam;
-    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
+    LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
     TTTOOL_INFO *toolPtr;
 
     if (uIndex >= infoPtr->uNumTools) return FALSE;
@@ -333,7 +519,7 @@
     lpToolInfo->hinst    = toolPtr->hinst;
     lpToolInfo->lpszText = toolPtr->lpszText;
 
-    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
+    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
 	lpToolInfo->lParam = toolPtr->lParam;
 
     return TRUE;
@@ -347,7 +533,7 @@
 TOOLTIPS_GetCurrentTool32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
-    LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam;
+    LPTTTOOLINFO32A lpti = (LPTTTOOLINFO32A)lParam;
     TTTOOL_INFO *toolPtr;
 
     if (lpti) {
@@ -360,7 +546,7 @@
 	    lpti->hinst    = toolPtr->hinst;
 	    lpti->lpszText = toolPtr->lpszText;
 
-	    if (lpti->cbSize >= sizeof(TTTOOLINFOA))
+	    if (lpti->cbSize >= sizeof(TTTOOLINFO32A))
 		lpti->lParam = toolPtr->lParam;
 
 	    return TRUE;
@@ -429,16 +615,16 @@
 TOOLTIPS_GetText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
-    LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam;
-    INT32 nIndex;
+    LPTTTOOLINFO32A lpti = (LPTTTOOLINFO32A)lParam;
+    INT32 nTool;
 
     if (!(lpti)) return 0;
-    if (lpti->cbSize < sizeof(TTTOOLINFOA)) return 0;
+    if (lpti->cbSize < sizeof(TTTOOLINFO32A)) return 0;
 
-    nIndex = TOOLTIPS_GetIndexFromInfoA (infoPtr, lpti);
-    if (nIndex == -1) return 0;
+    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti);
+    if (nTool == -1) return 0;
 
-    lstrcpy32A (lpti->lpszText, infoPtr->tools[nIndex].lpszText);
+    lstrcpy32A (lpti->lpszText, infoPtr->tools[nTool].lpszText);
 
     return 0;
 }
@@ -475,19 +661,19 @@
 TOOLTIPS_GetToolInfo32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
-    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
+    LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
     TTTOOL_INFO *toolPtr;
-    INT32 nIndex;
+    INT32 nTool;
 
     if (lpToolInfo == NULL) return FALSE;
     if (infoPtr->uNumTools == 0) return FALSE;
 
-    nIndex = TOOLTIPS_GetIndexFromInfoA (infoPtr, lpToolInfo);
-    if (nIndex == -1) return FALSE;
+    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
+    if (nTool == -1) return FALSE;
 
-    TRACE (tooltips, "index=%d\n", nIndex);
+    TRACE (tooltips, "tool %d\n", nTool);
 
-    toolPtr = &infoPtr->tools[nIndex];
+    toolPtr = &infoPtr->tools[nTool];
 
     /* copy tool data */
     lpToolInfo->uFlags   = toolPtr->uFlags;
@@ -495,7 +681,7 @@
     lpToolInfo->hinst    = toolPtr->hinst;
     lpToolInfo->lpszText = toolPtr->lpszText;
 
-    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
+    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
 	lpToolInfo->lParam = toolPtr->lParam;
 
     return TRUE;
@@ -509,22 +695,22 @@
 TOOLTIPS_HitTest32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
-    LPTTHITTESTINFOA lptthit = (LPTTHITTESTINFOA)lParam;
+    LPTTHITTESTINFO32A lptthit = (LPTTHITTESTINFO32A)lParam;
     TTTOOL_INFO *toolPtr;
     INT32 nTool;
 
     if (lptthit == 0)
 	return FALSE;
 
-    nTool = TOOLTIPS_GetIndexFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
+    nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
     if (nTool == -1)
 	return FALSE;
 
-    TRACE (tooltips, "nTool = %d!\n", nTool);
+    TRACE (tooltips, "tool %d!\n", nTool);
 
     /* copy tool data */
     toolPtr = &infoPtr->tools[nTool];
-    lptthit->ti.cbSize   = sizeof(TTTOOLINFOA);
+    lptthit->ti.cbSize   = sizeof(TTTOOLINFO32A);
     lptthit->ti.uFlags   = toolPtr->uFlags;
     lptthit->ti.hwnd     = toolPtr->hwnd;
     lptthit->ti.uId      = toolPtr->uId;
@@ -544,16 +730,16 @@
 TOOLTIPS_NewToolRect32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
-    LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam;
-    INT32 nIndex;
+    LPTTTOOLINFO32A lpti = (LPTTTOOLINFO32A)lParam;
+    INT32 nTool;
 
     if (!(lpti)) return 0;
-    if (lpti->cbSize < sizeof(TTTOOLINFOA)) return 0;
+    if (lpti->cbSize < sizeof(TTTOOLINFO32A)) return 0;
 
-    nIndex = TOOLTIPS_GetIndexFromInfoA (infoPtr, lpti);
-    if (nIndex == -1) return 0;
+    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti);
+    if (nTool == -1) return 0;
 
-    infoPtr->tools[nIndex].rect = lpti->rect;
+    infoPtr->tools[nTool].rect = lpti->rect;
 
     return 0;
 }
@@ -581,15 +767,15 @@
     POINT32 pt;
 
     if (lpMsg == NULL) {
-	WARN (tooltips, "lpMsg == NULL!\n");
+	ERR (tooltips, "lpMsg == NULL!\n");
 	return 0;
     }
 
     pt = lpMsg->pt;
     ScreenToClient32 (lpMsg->hwnd, &pt);
     infoPtr->nOldTool = infoPtr->nTool;
-    infoPtr->nTool = TOOLTIPS_GetIndexFromPoint (infoPtr, lpMsg->hwnd, &pt);
-    TRACE (tooltips, "nTool = %d\n", infoPtr->nTool);
+    infoPtr->nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lpMsg->hwnd, &pt);
+    TRACE (tooltips, "tool (%x) %d %d\n", wndPtr->hwndSelf, infoPtr->nOldTool, infoPtr->nTool);
 
     switch (lpMsg->message) {
 	case WM_LBUTTONDOWN:
@@ -602,13 +788,24 @@
 	    break;
 
 	case WM_MOUSEMOVE:
-	    TRACE (tooltips, "WM_MOUSEMOVE (%d %d)\n", pt.x, pt.y);
-	    if (infoPtr->nTool != infoPtr->nOldTool) {
-		if (infoPtr->nOldTool == -1)
-		    SetTimer32 (wndPtr->hwndSelf, ID_TIMER1, infoPtr->nInitialTime, 0);
-		else
+	    TRACE (tooltips, "WM_MOUSEMOVE (%04x %d %d)\n",
+		   wndPtr->hwndSelf, pt.x, pt.y);
+	    if ((infoPtr->bActive) && (infoPtr->nTool != infoPtr->nOldTool)) {
+		if (infoPtr->nOldTool == -1) {
+		    SetTimer32 (wndPtr->hwndSelf, ID_TIMER1,
+				infoPtr->nInitialTime, 0);
+		    TRACE (tooltips, "timer 1 started!\n");
+		}
+		else {
 		    TOOLTIPS_Hide (wndPtr, infoPtr);
-		    SetTimer32 (wndPtr->hwndSelf, ID_TIMER1, infoPtr->nReshowTime, 0);
+		    SetTimer32 (wndPtr->hwndSelf, ID_TIMER1,
+				infoPtr->nReshowTime, 0);
+		    TRACE (tooltips, "timer 2 started!\n");
+		}
+	    }
+	    if (infoPtr->nCurrentTool != -1) {
+		SetTimer32 (wndPtr->hwndSelf, ID_TIMER3, 100, 0);
+		TRACE (tooltips, "timer 3 started!\n");
 	    }
 	    break;
     }
@@ -709,18 +906,18 @@
 TOOLTIPS_SetToolInfo32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
-    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
+    LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
     TTTOOL_INFO *toolPtr;
-    INT32 nIndex;
+    INT32 nTool;
 
     if (lpToolInfo == NULL) return 0;
 
-    nIndex = TOOLTIPS_GetIndexFromInfoA (infoPtr, lpToolInfo);
-    if (nIndex == -1) return 0;
+    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
+    if (nTool == -1) return 0;
 
-    TRACE (tooltips, "nIndex=%d\n", nIndex);
+    TRACE (tooltips, "tool %d\n", nTool);
 
-    toolPtr = &infoPtr->tools[nIndex];
+    toolPtr = &infoPtr->tools[nTool];
 
     /* copy tool data */
     toolPtr->uFlags = lpToolInfo->uFlags;
@@ -744,7 +941,7 @@
 	}
     }
 
-    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
+    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
 	toolPtr->lParam = lpToolInfo->lParam;
 
     return 0;
@@ -752,12 +949,112 @@
 
 
 // << TOOLTIPS_SetToolInfo32W >>
-// << TOOLTIPS_TrackActive >>
-// << TOOLTIPS_TrackPosition >>
-// << TOOLTIPS_Update >>
-// << TOOLTIPS_UpdateTipText32A >>
+
+
+static LRESULT
+TOOLTIPS_TrackActivate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
+    LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
+
+    if ((BOOL32)wParam) {
+	/* activate */
+	infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
+	if (infoPtr->nTrackTool != -1) {
+	    infoPtr->bTrackActive = TRUE;
+
+	    /* FIXME : show tool tip */
+	}
+    }
+    else {
+	/* deactivate */
+	/* FIXME : hide tool tip */
+
+	infoPtr->bTrackActive = FALSE;
+	infoPtr->nTrackTool = -1;
+    }
+
+    return 0;
+}
+
+
+static LRESULT
+TOOLTIPS_TrackPosition (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
+
+    infoPtr->xTrackPos = (INT32)LOWORD(lParam);
+    infoPtr->yTrackPos = (INT32)HIWORD(lParam);
+
+    if (infoPtr->bTrackActive) {
+
+	FIXME (tooltips, "set position!\n");
+    }
+
+    return 0;
+}
+
+
+static LRESULT
+TOOLTIPS_Update (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
+
+    if (infoPtr->nCurrentTool != -1)
+	UpdateWindow32 (wndPtr->hwndSelf);
+
+    return 0;
+}
+
+
+static LRESULT
+TOOLTIPS_UpdateTipText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
+    LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
+    TTTOOL_INFO *toolPtr;
+    INT32 nTool;
+
+    if (lpToolInfo == NULL) return 0;
+
+    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
+    if (nTool == -1) return 0;
+
+    TRACE (tooltips, "tool %d\n", nTool);
+
+    toolPtr = &infoPtr->tools[nTool];
+
+    /* copy tool text */
+    toolPtr->hinst  = lpToolInfo->hinst;
+
+    if (lpToolInfo->hinst) {
+	toolPtr->lpszText = lpToolInfo->lpszText;
+    }
+    else if (lpToolInfo->lpszText) {
+	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACK32A)
+	    toolPtr->lpszText = lpToolInfo->lpszText;
+	else {
+	    INT32 len = lstrlen32A (lpToolInfo->lpszText);
+	    HeapFree (GetProcessHeap (), 0, toolPtr->lpszText);
+	    toolPtr->lpszText =
+		HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len + 1);
+	    lstrcpy32A (toolPtr->lpszText, lpToolInfo->lpszText);
+	}
+    }
+
+    return 0;
+}
+
+
 // << TOOLTIPS_UpdateTipText32W >>
-// << TOOLTIPS_WindowFromPoint >>
+
+
+static LRESULT
+TOOLTIPS_WindowFromPoint (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    return WindowFromPoint32 (*((LPPOINT32)lParam));
+}
+
 
 
 static LRESULT
@@ -778,6 +1075,7 @@
 
     /* initialize info structure */
     infoPtr->bActive = TRUE;
+    infoPtr->bTrackActive = FALSE;
     infoPtr->clrBk   = GetSysColor32 (COLOR_INFOBK);
     infoPtr->clrText = GetSysColor32 (COLOR_INFOTEXT);
 
@@ -788,12 +1086,15 @@
     infoPtr->nTool = -1;
     infoPtr->nOldTool = -1;
     infoPtr->nCurrentTool = -1;
+    infoPtr->nTrackTool = -1;
 
     infoPtr->nAutomaticTime = 500;
     infoPtr->nReshowTime    = 100;
     infoPtr->nAutoPopTime   = 5000;
     infoPtr->nInitialTime   = 500;
 
+    SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0, SWP_HIDEWINDOW);
+
     return 0;
 }
 
@@ -803,7 +1104,6 @@
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
 
-
     /* free tools */
     if (infoPtr->tools) {
 	INT32 i;
@@ -816,6 +1116,9 @@
 	HeapFree (GetProcessHeap (), 0, infoPtr->tools);
     }
 
+    /* delete font */
+    DeleteObject32 (infoPtr->hFont);
+
     /* free tool tips info data */
     HeapFree (GetProcessHeap (), 0, infoPtr);
 
@@ -890,9 +1193,8 @@
 
     infoPtr->hFont = (HFONT32)wParam;
 
-    if (LOWORD(lParam)) {
-	/* redraw */
-
+    if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) {
+	FIXME (tooltips, "full redraw needed!\n");
     }
 
     return 0;
@@ -904,6 +1206,8 @@
 {
     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
 
+    TRACE (tooltips, "timer %d (%x) expired!\n", wParam, wndPtr->hwndSelf);
+
     switch (wParam)
     {
 	case ID_TIMER1:
@@ -914,12 +1218,35 @@
 	case ID_TIMER2:
 	    TOOLTIPS_Hide (wndPtr, infoPtr);
 	    break;
+
+	case ID_TIMER3:
+	    KillTimer32 (wndPtr->hwndSelf, ID_TIMER3);
+	    if (TOOLTIPS_CheckTool (wndPtr) == FALSE) {
+		infoPtr->nTool = -1;
+		infoPtr->nOldTool = -1;
+		TOOLTIPS_Hide (wndPtr, infoPtr);
+	    }
+	    break;
     }
     return 0;
 }
 
 
-// << TOOLTIPS_WinIniChange >>
+static LRESULT
+TOOLTIPS_WinIniChange (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
+{
+    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
+    LOGFONT32A logFont;
+
+    infoPtr->clrBk   = GetSysColor32 (COLOR_INFOBK);
+    infoPtr->clrText = GetSysColor32 (COLOR_INFOTEXT);
+
+    DeleteObject32 (infoPtr->hFont);
+    SystemParametersInfo32A( SPI_GETICONTITLELOGFONT, 0, &logFont, 0 );
+    infoPtr->hFont = CreateFontIndirect32A( &logFont );
+
+    return 0;
+}
 
 
 LRESULT WINAPI
@@ -1015,12 +1342,23 @@
 	    return TOOLTIPS_SetToolInfo32A (wndPtr, wParam, lParam);
 
 //	case TTM_SETTOOLINFO32W:
-//	case TTM_TRACKACTIVE:			/* 4.70 */
-//	case TTM_TRACKPOSITION:			/* 4.70 */
-//	case TTM_UPDATE:			/* 4.71 */
-//	case TTM_UPDATETIPTEXT32A:
+
+	case TTM_TRACKACTIVATE:
+	    return TOOLTIPS_TrackActivate (wndPtr, wParam, lParam);
+
+	case TTM_TRACKPOSITION:
+	    return TOOLTIPS_TrackPosition (wndPtr, wParam, lParam);
+
+	case TTM_UPDATE:
+	    return TOOLTIPS_Update (wndPtr, wParam, lParam);
+
+	case TTM_UPDATETIPTEXT32A:
+	    return TOOLTIPS_UpdateTipText32A (wndPtr, wParam, lParam);
+
 //	case TTM_UPDATETIPTEXT32W:
-//	case TTM_WINDOWFROMPOINT:
+
+	case TTM_WINDOWFROMPOINT:
+	    return TOOLTIPS_WindowFromPoint (wndPtr, wParam, lParam);
 
 
 	case WM_CREATE:
@@ -1035,22 +1373,36 @@
 	case WM_GETFONT:
 	    return TOOLTIPS_GetFont (wndPtr, wParam, lParam);
 
+//	case WM_GETTEXT:
+//	case WM_GETTEXTLENGTH:
+//	case WM_LBUTTONDOWN:
+//	case WM_MBUTTONDOWN:
+
 	case WM_MOUSEMOVE:
 	    return TOOLTIPS_MouseMove (wndPtr, wParam, lParam);
 
 	case WM_NCCREATE:
 	    return TOOLTIPS_NcCreate (wndPtr, wParam, lParam);
 
+//	case WM_NCHITTEST:
+//	case WM_NOTIFYFORMAT:
+
 	case WM_PAINT:
 	    return TOOLTIPS_Paint (wndPtr, wParam, lParam);
 
+//	case WM_PRINTCLIENT:
+//	case WM_RBUTTONDOWN:
+
 	case WM_SETFONT:
 	    return TOOLTIPS_SetFont (wndPtr, wParam, lParam);
 
+//	case WM_STYLECHANGED:
+
 	case WM_TIMER:
 	    return TOOLTIPS_Timer (wndPtr, wParam, lParam);
 
-//	case WM_WININICHANGE:
+	case WM_WININICHANGE:
+	    return TOOLTIPS_WinIniChange (wndPtr, wParam, lParam);
 
 	default:
 	    if (uMsg >= WM_USER)
@@ -1080,4 +1432,3 @@
  
     RegisterClass32A (&wndClass);
 }
-
diff --git a/controls/treeview.c b/controls/treeview.c
index f04f40e..992b5d8 100644
--- a/controls/treeview.c
+++ b/controls/treeview.c
@@ -40,7 +40,7 @@
 	infoPtr->himlState = (HIMAGELIST)lParam;
     }
     else
-	return NULL;
+	return 0;
 
     return (LRESULT)himlTemp;
 }
@@ -109,23 +109,132 @@
 
 
 LRESULT WINAPI
-TreeviewWindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
+TREEVIEW_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
 {
     WND *wndPtr = WIN_FindWndPtr(hwnd);
 
     switch (uMsg)
     {
 
+    case TVM_INSERTITEMA:
+      FIXME (treeview, "Unimplemented msg TVM_INSERTITEMA\n");
+      return 0;
 
-//	case TVM_GETIMAGELIST:
-//	    return TREEVIEW_GetImageList (wndPtr, wParam, lParam);
+    case TVM_INSERTITEMW:
+      FIXME (treeview, "Unimplemented msg TVM_INSERTITEMW\n");
+      return 0;
 
+    case TVM_DELETEITEM:
+      FIXME (treeview, "Unimplemented msg TVM_DELETEITEM\n");
+      return 0;
 
+    case TVM_EXPAND:
+      FIXME (treeview, "Unimplemented msg TVM_EXPAND\n");
+      return 0;
+
+    case TVM_GETITEMRECT:
+      FIXME (treeview, "Unimplemented msg TVM_GETITEMRECT\n");
+      return 0;
+
+    case TVM_GETCOUNT:
+      FIXME (treeview, "Unimplemented msg TVM_GETCOUNT\n");
+      return 0;
+
+    case TVM_GETINDENT:
+      FIXME (treeview, "Unimplemented msg TVM_GETINDENT\n");
+      return 0;
+
+    case TVM_SETINDENT:
+      FIXME (treeview, "Unimplemented msg TVM_SETINDENT\n");
+      return 0;
+
+    case TVM_GETIMAGELIST:
+      FIXME (treeview, "Unimplemented msg TVM_GETIMAGELIST\n");
+      return 0;
+      //return TREEVIEW_GetImageList (wndPtr, wParam, lParam);
 
 	case TVM_SETIMAGELIST:
 	    return TREEVIEW_SetImageList (wndPtr, wParam, lParam);
 
+    case TVM_GETNEXTITEM:
+      FIXME (treeview, "Unimplemented msg TVM_GETNEXTITEM\n");
+      return 0;
 
+    case TVM_SELECTITEM:
+      FIXME (treeview, "Unimplemented msg TVM_SELECTITEM \n");
+      return 0;
+
+    case TVM_GETITEMA:
+      FIXME (treeview, "Unimplemented msg TVM_GETITEMA\n");
+      return 0;
+
+    case TVM_GETITEMW:
+      FIXME (treeview, "Unimplemented msg TVM_GETITEMW\n");
+      return 0;
+
+    case TVM_SETITEMA:
+      FIXME (treeview, "Unimplemented msg TVM_SETITEMA\n");
+      return 0;
+
+    case TVM_SETITEMW:
+      FIXME (treeview, "Unimplemented msg TVM_SETITEMW\n");
+      return 0;
+
+    case TVM_EDITLABELA:
+      FIXME (treeview, "Unimplemented msg TVM_EDITLABELA \n");
+      return 0;
+
+    case TVM_EDITLABELW:
+      FIXME (treeview, "Unimplemented msg TVM_EDITLABELW \n");
+      return 0;
+
+    case TVM_GETEDITCONTROL:
+      FIXME (treeview, "Unimplemented msg TVM_GETEDITCONTROL\n");
+      return 0;
+
+    case TVM_GETVISIBLECOUNT:
+      FIXME (treeview, "Unimplemented msg TVM_GETVISIBLECOUNT\n");
+      return 0;
+
+    case TVM_HITTEST:
+      FIXME (treeview, "Unimplemented msg TVM_HITTEST\n");
+      return 0;
+
+    case TVM_CREATEDRAGIMAGE:
+      FIXME (treeview, "Unimplemented msg TVM_CREATEDRAGIMAGE\n");
+      return 0;
+
+    case TVM_SORTCHILDREN:
+      FIXME (treeview, "Unimplemented msg TVM_SORTCHILDREN\n");
+      return 0;
+
+    case TVM_ENSUREVISIBLE:
+      FIXME (treeview, "Unimplemented msg TVM_ENSUREVISIBLE\n");
+      return 0;
+
+    case TVM_SORTCHILDRENCB:
+      FIXME (treeview, "Unimplemented msg TVM_SORTCHILDRENCB\n");
+      return 0;
+
+    case TVM_ENDEDITLABELNOW:
+      FIXME (treeview, "Unimplemented msg TVM_ENDEDITLABELNOW\n");
+      return 0;
+
+    case TVM_GETISEARCHSTRINGA:
+      FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRINGA\n");
+      return 0;
+
+    case TVM_GETISEARCHSTRINGW:
+      FIXME (treeview, "Unimplemented msg TVM_GETISEARCHSTRINGW\n");
+      return 0;
+
+    case TVM_SETTOOLTIPS:
+      FIXME (treeview, "Unimplemented msg TVM_SETTOOLTIPS\n");
+      return 0;
+
+    case TVM_GETTOOLTIPS:
+      FIXME (treeview, "Unimplemented msg TVM_GETTOOLTIPS\n");
+      return 0;
 
 	case WM_CREATE:
 	    return TREEVIEW_Create (wndPtr, wParam, lParam);
@@ -141,7 +250,6 @@
 	case WM_GETDLGCODE:
 	    return DLGC_WANTARROWS | DLGC_WANTCHARS;
 
-
 //	case WM_PAINT:
 //	    return TREEVIEW_Paint (wndPtr, wParam);
 
@@ -153,7 +261,7 @@
 
 	default:
 	    if (uMsg >= WM_USER)
-		ERR (treeview, "unknown msg %04x wp=%08x lp=%08lx\n",
+	FIXME (treeview, "Unknown msg %04x wp=%08x lp=%08lx\n",
 		     uMsg, wParam, lParam);
 	    return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
     }
@@ -166,11 +274,13 @@
 {
     WNDCLASS32A wndClass;
 
+    TRACE (treeview,"\n");
+
     if (GlobalFindAtom32A (WC_TREEVIEW32A)) return;
 
     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
-    wndClass.lpfnWndProc   = (WNDPROC32)TreeviewWindowProc;
+    wndClass.lpfnWndProc   = (WNDPROC32)TREEVIEW_WindowProc;
     wndClass.cbClsExtra    = 0;
     wndClass.cbWndExtra    = sizeof(TREEVIEW_INFO *);
     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
diff --git a/controls/widgets.c b/controls/widgets.c
index daa89d9..20ca347 100644
--- a/controls/widgets.c
+++ b/controls/widgets.c
@@ -103,8 +103,6 @@
         if (!(bicAtomTable[i] = RegisterClass32A( cls ))) return FALSE;
     }
 
-    /* FIXME: hack to enable using built-in controls with Windows COMCTL32 */
-    InitCommonControls();
     return TRUE;
 }
 
diff --git a/debugger/dbg.y b/debugger/dbg.y
index 4066824..9aa95f2 100644
--- a/debugger/dbg.y
+++ b/debugger/dbg.y
@@ -19,6 +19,7 @@
 #include "winnt.h"
 #include "debugger.h"
 #include "neexe.h"
+#include "process.h"
 
 #include "expr.h"
 
@@ -436,7 +437,6 @@
 	 * don't grok that yet, and in this case we fall back to using
 	 * the wine.sym file.
 	 */
-	fprintf(stderr,"Loading symbols: ");
 	if( DEBUG_ReadExecutableDbgInfo() == FALSE )
         {
 	    char *symfilename = "wine.sym";
@@ -451,7 +451,6 @@
 
         DEBUG_LoadEntryPoints();
 	DEBUG_ProcessDeferredDebug();
-	fprintf(stderr,"\n");
     }
 
 #if 0
@@ -481,6 +480,8 @@
         if (newmode != dbg_mode)
             fprintf(stderr,"In %d bit mode.\n", dbg_mode = newmode);
 
+        PROCESS_SuspendOtherThreads();
+
 	DEBUG_DoDisplay();
 
         if (signal != SIGTRAP)  /* This is a real crash, dump some info */
@@ -542,6 +543,7 @@
     if( dbg_exec_mode == EXEC_CONT )
       {
 	dbg_exec_count = 0;
+        PROCESS_ResumeOtherThreads();
       }
 
     in_debugger = FALSE;
diff --git a/debugger/hash.c b/debugger/hash.c
index 4befa47..ffb4d6f 100644
--- a/debugger/hash.c
+++ b/debugger/hash.c
@@ -874,19 +874,35 @@
     NE_MODULE *pModule;
     BOOL32 ok;
     WINE_MODREF	*wm;
+    int rowcount = 3;
 
+    fprintf( stderr, "   " );
     for (ok = ModuleFirst(&entry); ok; ok = ModuleNext(&entry))
     {
         if (!(pModule = NE_GetPtr( entry.hModule ))) continue;
+	if ((rowcount + strlen(entry.szModule)) > 76)
+        {
+	    fprintf( stderr,"\n   ");
+	    rowcount = 3;
+        }
         fprintf( stderr, " %s", entry.szModule );
+        rowcount += strlen(entry.szModule) + 1;
 
         if (!(pModule->flags & NE_FFLAGS_WIN32))  /* NE module */
             DEBUG_LoadEntryPoints16( entry.hModule, pModule, entry.szModule );
     }
-    for (wm=PROCESS_Current()->modref_list;wm;wm=wm->next) {
+    for (wm=PROCESS_Current()->modref_list;wm;wm=wm->next)
+    {
+        if ((rowcount + strlen(wm->modname)) > 76)
+        {
+            fprintf( stderr,"\n   ");
+            rowcount = 3;
+        }
         fprintf( stderr, " %s", wm->modname );
+        rowcount += strlen(wm->modname) + 1;
 	DEBUG_LoadEntryPoints32( wm->module, wm->modname );
     }
+    fprintf( stderr, "\n" );
 }
 
 
diff --git a/debugger/memory.c b/debugger/memory.c
index 0b26748..fbd5047 100644
--- a/debugger/memory.c
+++ b/debugger/memory.c
@@ -19,7 +19,7 @@
  *     write (rwflag == 0)
  ************************************************************/
 
-#ifdef linux
+#if defined(linux) || defined(__FreeBSD__)
 BOOL32 DEBUG_checkmap_bad( const char *addr, size_t size, int rwflag)
 {
   FILE *fp;
@@ -28,6 +28,7 @@
   char *start, *end;
   int ret = TRUE;
 
+#ifdef linux
   /* 
      The entries in /proc/self/maps are of the form:
      08000000-08002000 r-xp 00000000 03:41 2361
@@ -41,12 +42,34 @@
 
      Only permissions start and end are used here
      */
+#else
+/*
+    % cat /proc/curproc/map
+    start      end         resident   private perm    type
+    0x1000     0xe000            12         0 r-x COW vnode
+    0xe000     0x10000            2         2 rwx COW vnode
+    0x10000    0x27000            4         4 rwx     default
+    0x800e000  0x800f000          1         1 rw-     default
+    0xefbde000 0xefbfe000         1         1 rwx     default
+    
+    COW = "copy on write"
+*/
+#endif
+
   
+#ifdef linux
   if (!(fp = fopen("/proc/self/maps", "r")))
+#else
+  if (!(fp = fopen("/proc/curproc/map", "r")))
+#endif
     return FALSE; 
 
   while (fgets( buf, 79, fp)) {
+#ifdef linux
     sscanf(buf, "%x-%x %3s", (int *) &start, (int *) &end, prot);
+#else
+    sscanf(buf, "%x %x %*d %*d %3s", (int *) &start, (int *) &end, prot);
+#endif
     if ( end <= addr)
       continue;
     if (start <= addr && addr+size < end) {
@@ -60,13 +83,13 @@
   fclose( fp);
   return ret;
 }
-#else  /* linux */
+#else  /* linux || FreeBSD */
 /* FIXME: code needed for BSD et al. */
 BOOL32 DEBUG_checkmap_bad(char *addr, size_t size, int rwflag)
 {
     return FALSE;
 }
-#endif  /* linux */
+#endif  /* linux || FreeBSD */
 
 
 /***********************************************************************
diff --git a/debugger/stabs.c b/debugger/stabs.c
index 10ada5d..f3d080b 100644
--- a/debugger/stabs.c
+++ b/debugger/stabs.c
@@ -1077,8 +1077,7 @@
 	free(fn);
 	if (t) s = t+1;
       }
-      if (!s || !*s)
-      	fprintf(stderr," %s not found",filename);
+      if (!s || !*s) fprintf(stderr," not found");
       free(paths);
       goto leave;
     }
@@ -1100,12 +1099,6 @@
       goto leave;
 
   /*
-   * Give a nice status message here...
-   * Well not, just print the name.
-   */
-  fprintf(stderr, " %s", filename);
-
-  /*
    * Next, we need to find a few of the internal ELF headers within
    * this thing.  We need the main executable header, and the section
    * table.
@@ -1182,6 +1175,7 @@
   struct link_map     * lpnt = NULL;
   extern Elf32_Dyn      _DYNAMIC[];
   int			rtn = FALSE;
+  int                   rowcount;
 
   exe_name = DEBUG_argv0;
 
@@ -1191,6 +1185,8 @@
   if( exe_name == NULL )
       goto leave;
 
+  fprintf( stderr, "Loading symbols: %s", exe_name );
+  rowcount = 17 + strlen(exe_name);
   DEBUG_ProcessElfObject(exe_name, 0);
 
   /*
@@ -1238,13 +1234,22 @@
 	  continue;
 
       if( lpnt->l_name != NULL )
+      {
+          if (rowcount + strlen(lpnt->l_name) > 76)
+          {
+              fprintf( stderr, "\n   " );
+              rowcount = 3;
+          }
+          fprintf( stderr, " %s", lpnt->l_name );
+          rowcount += strlen(lpnt->l_name) + 1;
 	  DEBUG_ProcessElfObject(lpnt->l_name, lpnt->l_addr);
+      }
     }
 
   rtn = TRUE;
 
 leave:
-
+  fprintf( stderr, "\n" );
   return (rtn);
 
 }
@@ -1309,7 +1314,7 @@
   /*
    * Give a nice status message here...
    */
-  fprintf(stderr, " %s", exe_name);
+  fprintf( stderr, "Loading symbols: %s", exe_name );
 
   rtn = TRUE;
 
diff --git a/documentation/common_controls b/documentation/common_controls
index 722edec..6f854a2 100644
--- a/documentation/common_controls
+++ b/documentation/common_controls
@@ -175,10 +175,8 @@
       - Almost finished.
 
   Notes:
-      - Tool tips need to be added, but since they are not done yet...
-
-  Notes:
-      Have a look at controls/status.c for a list of bugs and missing features.
+      - Unicode support is still missing.
+      - Tooltip integration is almost complete.
 
 
 3.17 Tab Control
@@ -200,7 +198,7 @@
       - Development in progress.
       - Basic functionality is almost done. (dll version 4.0)
 
-  Notes
+  Notes:
       Bitmaps are not correctly displayed.
 
 
@@ -210,10 +208,11 @@
       Eric Kohl <ekohl@abo.rhein-zeitung.de>
 
   Status:
-      - Development in progress. Almost done.
+      - Almost finished.
 
-  Notes
-      The control does not behave very well. This will be fixed
+  Notes:
+      - Unicode support is still missing.
+      - No subclassing.
 
 
 3.20 Trackbar Control
@@ -232,6 +231,7 @@
 ----------------------
   Author:
       Dummy written by Eric Kohl.
+      Alex Priem (alexp@sci.kun.nl)
 
   Status:
       - Dummy control. No functionality.
diff --git a/documentation/win95look b/documentation/win95look
index bd04bf9..ddab05a 100644
--- a/documentation/win95look
+++ b/documentation/win95look
@@ -21,7 +21,6 @@
 
 [Tweak.Layout]
 Win95Look=[true|false]        # Enables/disables the Win95 look and feel
-MenuHeight=<pixels>           # Sets the height of the menu bar
 MenuBarItemTopNudge=<pixels>  # Nudges the menu bar items down/up
 MenuBarItemLeftNudge=<pixels> # Nudges the menu bar items left/right
 MenuItemTopNudge=<pixels>     # Nudges the menu items down/up
@@ -30,18 +29,4 @@
 MenuHighlightLeftNudge=<pixels> # Nudges the left side of the highlight bar
 MenuHighlightRightNudge=<pixels> # Nudges the right side of the highlight bar
 MenuHighlightBottomNudge=<pixels> # Nudges the bottom of the highlight bar
-CaptionAlignment=[left|right|center] # Sets the alignment of caption text
-SysControlNudge=<pixels>      # Nudges the system menu left/right
-MaxControlNudge=<pixels>      # Nudges the maximize control left/right
-MinControlNudge=<pixels>      # Nudges the minimize control left/right
-ScrollBarWidth=<pixels>       # Sets scroll bar sizes
-DialogFrameWidth=<pixels>     # Sets the frame width of dialog boxes
 
-[Tweak.Colors]
-PenFF95.Red=<0-255>           # Sets the red value of the Win95 white pen
-PenFF95.Grn=<0-255>           # Sets the green value of the Win95 white pen
-PenFF95.Blu=<0-255>           # Sets the blue value of the Win95 white pen
-PenE095.xxx                   # Sets the RGB values of the Win95 grey-88 pen
-PenC095.xxx                   # Sets the RGB values of the Win95 grey-75 pen
-Pen8095.xxx                   # Sets the RGB values of the Win95 grey-50 pen
-Pen0095.xxx                   # Sets the RGB values of the Win95 black pen
diff --git a/files/Makefile.in b/files/Makefile.in
index 55b76a9..eb37b89 100644
--- a/files/Makefile.in
+++ b/files/Makefile.in
@@ -8,6 +8,7 @@
 MODULE     = files
 
 C_SRCS = \
+	change.c \
 	directory.c \
 	dos_fs.c \
 	drive.c \
diff --git a/files/change.c b/files/change.c
new file mode 100644
index 0000000..7a09e5c
--- /dev/null
+++ b/files/change.c
@@ -0,0 +1,188 @@
+/*
+ * Win32 file change notification functions
+ *
+ * Copyright 1998 Ulrich Weigand
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include "windows.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "process.h"
+#include "thread.h"
+#include "heap.h"
+#include "debug.h"
+
+static BOOL32 CHANGE_Signaled( K32OBJ *obj, DWORD thread_id );
+static BOOL32 CHANGE_Satisfied( K32OBJ *obj, DWORD thread_id );
+static void CHANGE_AddWait( K32OBJ *obj, DWORD thread_id );
+static void CHANGE_RemoveWait( K32OBJ *obj, DWORD thread_id );
+static void CHANGE_Destroy( K32OBJ *obj );
+
+const K32OBJ_OPS CHANGE_Ops =
+{
+    CHANGE_Signaled,    /* signaled */
+    CHANGE_Satisfied,   /* satisfied */
+    CHANGE_AddWait,     /* add_wait */
+    CHANGE_RemoveWait,  /* remove_wait */
+    NULL,               /* read */
+    NULL,               /* write */
+    CHANGE_Destroy      /* destroy */
+};
+
+/* The change notification object */
+typedef struct
+{
+    K32OBJ       header;
+
+    LPSTR        lpPathName;
+    BOOL32       bWatchSubtree;
+    DWORD        dwNotifyFilter;
+
+    THREAD_QUEUE wait_queue;    
+    BOOL32       notify;
+
+} CHANGE_OBJECT;
+
+/***********************************************************************
+ *           CHANGE_Signaled
+ */
+static BOOL32 CHANGE_Signaled( K32OBJ *obj, DWORD thread_id )
+{
+    CHANGE_OBJECT *change = (CHANGE_OBJECT *)obj;
+    assert( obj->type == K32OBJ_CHANGE );
+    return change->notify;
+}
+
+/***********************************************************************
+ *           CHANGE_Satisfied
+ *
+ * Wait on this object has been satisfied.
+ */
+static BOOL32 CHANGE_Satisfied( K32OBJ *obj, DWORD thread_id )
+{
+    assert( obj->type == K32OBJ_CHANGE );
+    return FALSE;  /* Not abandoned */
+}
+
+/***********************************************************************
+ *           CHANGE_AddWait
+ *
+ * Add thread to object wait queue.
+ */
+static void CHANGE_AddWait( K32OBJ *obj, DWORD thread_id )
+{
+    CHANGE_OBJECT *change = (CHANGE_OBJECT *)obj;
+    assert( obj->type == K32OBJ_CHANGE );
+    THREAD_AddQueue( &change->wait_queue, THREAD_ID_TO_THDB(thread_id) );
+}
+
+/***********************************************************************
+ *           CHANGE_RemoveWait
+ *
+ * Remove thread from object wait queue.
+ */
+static void CHANGE_RemoveWait( K32OBJ *obj, DWORD thread_id )
+{
+    CHANGE_OBJECT *change = (CHANGE_OBJECT *)obj;
+    assert( obj->type == K32OBJ_CHANGE );
+    THREAD_RemoveQueue( &change->wait_queue, THREAD_ID_TO_THDB(thread_id) );
+}
+
+/****************************************************************************
+ *		CHANGE_Destroy
+ */
+static void CHANGE_Destroy( K32OBJ *obj )
+{
+    CHANGE_OBJECT *change = (CHANGE_OBJECT *)obj;
+    assert( obj->type == K32OBJ_CHANGE );
+
+    if ( change->lpPathName )
+    {
+        HeapFree( SystemHeap, 0, change->lpPathName );
+        change->lpPathName = NULL;
+    }
+
+    obj->type = K32OBJ_UNKNOWN;
+    HeapFree( SystemHeap, 0, change );
+}
+
+/****************************************************************************
+ *		FindFirstChangeNotification32A (KERNEL32.248)
+ */
+HANDLE32 WINAPI FindFirstChangeNotification32A( LPCSTR lpPathName,
+                                                BOOL32 bWatchSubtree,
+                                                DWORD dwNotifyFilter ) 
+{
+    HANDLE32 handle;
+    CHANGE_OBJECT *change;
+
+    change = HeapAlloc( SystemHeap, 0, sizeof(CHANGE_OBJECT) );
+    if (!change) return INVALID_HANDLE_VALUE32;
+
+    change->header.type = K32OBJ_CHANGE;
+    change->header.refcount = 1;
+
+    change->lpPathName = HEAP_strdupA( SystemHeap, 0, lpPathName );
+    change->bWatchSubtree = bWatchSubtree;
+    change->dwNotifyFilter = dwNotifyFilter;
+
+    change->wait_queue = NULL;
+    change->notify = FALSE;
+
+    handle = HANDLE_Alloc( PROCESS_Current(), &change->header, 
+                           FILE_ALL_ACCESS /*FIXME*/, TRUE, -1 );
+    /* If the allocation failed, the object is already destroyed */
+    if (handle == INVALID_HANDLE_VALUE32) change = NULL;
+    return handle;
+}
+
+/****************************************************************************
+ *		FindFirstChangeNotification32W (KERNEL32.249)
+ */
+HANDLE32 WINAPI FindFirstChangeNotification32W( LPCWSTR lpPathName,
+                                                BOOL32 bWatchSubtree,
+                                                DWORD dwNotifyFilter) 
+{
+    LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpPathName );
+    HANDLE32 ret = FindFirstChangeNotification32A( nameA, bWatchSubtree, 
+                                                          dwNotifyFilter );
+    if (nameA) HeapFree( GetProcessHeap(), 0, nameA );
+    return ret;
+}
+
+/****************************************************************************
+ *		FindNextChangeNotification (KERNEL32.252)
+ */
+BOOL32 WINAPI FindNextChangeNotification( HANDLE32 handle ) 
+{
+    CHANGE_OBJECT *change;
+
+    SYSTEM_LOCK();
+    if (!(change = (CHANGE_OBJECT *)HANDLE_GetObjPtr( PROCESS_Current(),
+                                                      handle, K32OBJ_CHANGE, 
+                                                      0 /*FIXME*/, NULL )) )
+    {
+        SYSTEM_UNLOCK();
+        return FALSE;
+    }
+
+    change->notify = FALSE;
+    K32OBJ_DecCount( &change->header );
+    SYSTEM_UNLOCK();
+    return TRUE;
+}
+
+/****************************************************************************
+ *		FindCloseChangeNotification (KERNEL32.247)
+ */
+BOOL32 WINAPI FindCloseChangeNotification( HANDLE32 handle) 
+{
+    return CloseHandle( handle );
+}
+
diff --git a/files/directory.c b/files/directory.c
index 9835a7d..cdcba08 100644
--- a/files/directory.c
+++ b/files/directory.c
@@ -85,7 +85,7 @@
     if (-1 == access( tmp_dir.long_name, W_OK ))
     {
     	if (errno==EACCES)
-		MSG("Warning: The Temporary Directory (as specified in wine.conf) is NOT writeable. Please check your configuration.\n");
+		MSG("Warning: The Temporary Directory (as specified in wine.conf or ~/.winerc) is NOT writeable. Please check your configuration.\n");
 	else
 		MSG("Warning: Access to Temporary Directory failed (%s).\n",
 		    strerror(errno));
diff --git a/files/dos_fs.c b/files/dos_fs.c
index 1204d09..e61e8e7 100644
--- a/files/dos_fs.c
+++ b/files/dos_fs.c
@@ -577,6 +577,7 @@
     int	i;
     const char *p;
 
+    if (!name) return NULL; /* if FILE_DupUnixHandle was used */
     if (name[0] && (name[1] == ':')) name += 2;
     if ((p = strrchr( name, '/' ))) name = p + 1;
     if ((p = strrchr( name, '\\' ))) name = p + 1;
@@ -604,6 +605,7 @@
     FILE_OBJECT *file;
     HFILE32 handle;
 
+    if (!name) return NULL; /* if FILE_DupUnixHandle was used */
     if (name[0] && (name[1] == ':')) name += 2;
     if ((p = strrchr( name, '/' ))) name = p + 1;
     if ((p = strrchr( name, '\\' ))) name = p + 1;
diff --git a/files/drive.c b/files/drive.c
index 8dcf69e..fa813af 100644
--- a/files/drive.c
+++ b/files/drive.c
@@ -998,7 +998,12 @@
     /* Set the filesystem information */
     /* Note: we only emulate a FAT fs at the present */
 
-    if (filename_len) *filename_len = 12;
+    if (filename_len) {
+    	if (DOSDrives[drive].flags & DRIVE_SHORT_NAMES)
+	    *filename_len = 12;
+	else
+	    *filename_len = 255;
+    }
     if (flags) *flags = 0;
     if (fsname) {
     	/* Diablo checks that return code ... */
diff --git a/files/file.c b/files/file.c
index d9ac977..6ae8d60 100644
--- a/files/file.c
+++ b/files/file.c
@@ -90,7 +90,7 @@
 
     handle = HANDLE_Alloc( PROCESS_Current(), &(*file)->header,
                            FILE_ALL_ACCESS | GENERIC_READ |
-                           GENERIC_WRITE | GENERIC_EXECUTE /*FIXME*/, TRUE );
+                           GENERIC_WRITE | GENERIC_EXECUTE /*FIXME*/, TRUE, -1 );
     /* If the allocation failed, the object is already destroyed */
     if (handle == INVALID_HANDLE_VALUE32) *file = NULL;
     return handle;
@@ -188,7 +188,7 @@
 FILE_OBJECT *FILE_GetFile( HFILE32 handle )
 {
     return (FILE_OBJECT *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
-                                            K32OBJ_FILE, 0 /*FIXME*/ );
+                                            K32OBJ_FILE, 0 /*FIXME*/, NULL );
 }
 
 
@@ -508,7 +508,7 @@
     DOS_FULL_NAME full_name;
     BY_HANDLE_FILE_INFORMATION info;
 
-    if (name == NULL) return -1;
+    if (name == NULL || *name=='\0') return -1;
 
     if (!DOSFS_GetFullName( name, TRUE, &full_name )) return -1;
     if (!FILE_Stat( full_name.long_name, &info )) return -1;
@@ -796,6 +796,22 @@
     lstrcpyn32A( ofs->szPathName, full_name.short_name,
                  sizeof(ofs->szPathName) );
 
+    if (mode & OF_SHARE_EXCLUSIVE)
+      {
+	char *last = strrchr(full_name.long_name,'/');
+	if (!last)
+	  last = full_name.long_name - 1;
+	/* Some InstallShield version uses OF_SHARE_EXCLUSIVE 
+	 on the file <tempdir>/_ins0432._mp to determine how
+	 far installation has proceeded*/
+	if (GetModuleHandle16(last+1))
+	  {
+	    TRACE(file,"Denying shared open for %s\n",full_name.long_name);
+	    return HFILE_ERROR32;
+	  }
+	FIXME(file,"OF_SHARE_EXCLUSIVE only partial implemented\n");
+      }
+
     if (mode & OF_DELETE)
     {
         if (unlink( full_name.long_name ) == -1) goto not_found;
@@ -925,7 +941,7 @@
 
     TRACE( file, "%d %p %d\n", handle, buffer, count);
     if (!(ptr = HANDLE_GetObjPtr( PROCESS_Current(), handle,
-                                  K32OBJ_UNKNOWN, 0))) return -1;
+                                  K32OBJ_UNKNOWN, 0, NULL))) return -1;
     if (K32OBJ_OPS(ptr)->read)
         result = K32OBJ_OPS(ptr)->read(ptr, buffer, count, &numWritten, NULL);
     K32OBJ_DecCount( ptr );
@@ -1147,7 +1163,7 @@
 	}
 	
 	if (!(ioptr = HANDLE_GetObjPtr( PROCESS_Current(), handle,
-                                        K32OBJ_UNKNOWN, 0 )))
+                                        K32OBJ_UNKNOWN, 0, NULL )))
             return HFILE_ERROR32;
         if (K32OBJ_OPS(ioptr)->write)
             status = K32OBJ_OPS(ioptr)->write(ioptr, buffer, count, &result, NULL);
diff --git a/files/profile.c b/files/profile.c
index c1f0daf..ecdd09c 100644
--- a/files/profile.c
+++ b/files/profile.c
@@ -452,13 +452,12 @@
              CurProfile=tempProfile;
             }
           if(!stat(CurProfile->unix_name,&buf) && CurProfile->mtime==buf.st_mtime)
-            {
              TRACE(profile, "(%s): already opened (mru=%d)\n",
                               filename, i );
-             return TRUE;
-            }
-          TRACE(profile, "(%s): already opened, needs refreshing (mru=%d)\n",
-                           filename, i );
+          else
+              TRACE(profile, "(%s): already opened, needs refreshing (mru=%d)\n",
+                             filename, i );
+	  return TRUE;
          }
       }
 
diff --git a/graphics/driver.c b/graphics/driver.c
index c4a28d6..08df15e 100644
--- a/graphics/driver.c
+++ b/graphics/driver.c
@@ -53,7 +53,8 @@
 const DC_FUNCTIONS *DRIVER_FindDriver( LPCSTR name )
 {
     GRAPHICS_DRIVER *driver = firstDriver;
-    while (driver)
+
+    while (driver && name)
     {
         if (!strcasecmp( driver->name, name )) return driver->funcs;
         driver = driver->next;
diff --git a/graphics/psdrv/Makefile.in b/graphics/psdrv/Makefile.in
index 169f06f..c829559 100644
--- a/graphics/psdrv/Makefile.in
+++ b/graphics/psdrv/Makefile.in
@@ -13,6 +13,7 @@
 	graphics.c \
 	init.c \
 	objects.c \
+	ppd.c \
 	ps.c \
 	text.c
 
diff --git a/graphics/psdrv/README b/graphics/psdrv/README
index 85fcd88..33a0a1b 100644
--- a/graphics/psdrv/README
+++ b/graphics/psdrv/README
@@ -39,6 +39,13 @@
 
 for each AFM file that you wish to use. [This might change in the future]
 
+You also require a ppd file for your printer. This describes certain
+characteristics of the printer such as which fonts are installed, how to select
+manual feed etc. Adobe also has many of these on its website, have a look in
+ftp://ftp.adobe.com/pub/adobe/printerdrivers/win/all/
+Put the ppd in the directory from which you start wine and call it default.ppd
+[this will definitely change soon].
+
 Note that you need not set printer=on in the [wine] section of wine.conf, this
 enables printing via external printer drivers and does not affect wineps.
 
@@ -51,9 +58,12 @@
 TODO / Bugs
 -----------
 
-Driver doesn't read PPD files - it should.
+Driver does read PPD files, but ignores all constraints and doesn't let you
+specify whether you have optional extras such as envelope feeders. You will
+therefore find a larger than normal selection of input bins in the print setup
+dialog box. I've only really tested ppd parsing on the hp4m6_v1.ppd file.
 
-A4 portrait mode is hard coded in at the moment.
+Landscape mode probably doesn't quite work yet (this is easy to fix).
 
 Graphics are basically non-existent. Only MoveTo/LineTo/Rectangle with a thin
 black pen.
@@ -64,12 +74,13 @@
 
 No TrueType download.
 
-Many partial-implemented functions.
+Many partially implemented functions.
+
+ps.c is becoming messy.
 
 Probably many more...
 
-
-Since the driver is very very alpha, things are likely to change quickly.
+Since the driver is very alpha, things are likely to change quickly.
 Please contact me if you want to help so that we can avoid duplication.
 
 Huw Davies <h.davies1@physics.ox.ac.uk>
diff --git a/graphics/psdrv/afm.c b/graphics/psdrv/afm.c
index f97ee9f..4477c27 100644
--- a/graphics/psdrv/afm.c
+++ b/graphics/psdrv/afm.c
@@ -16,7 +16,7 @@
 #include <ctype.h>
 
 /* ptr to fonts for which we have afm files */
-FontFamily *PSDRV_AFMFontList = NULL;
+FONTFAMILY *PSDRV_AFMFontList = NULL;
 
 
 /***********************************************************
@@ -35,6 +35,8 @@
     int i, charno;
 
     for(i = 0; i < afm->NumofMetrics; i++) {
+        char *name = NULL;
+
         if(!fgets(buf, sizeof(buf), fp)) {
 	   ERR(psdrv, "Unexpected EOF\n");
 	   return;
@@ -71,6 +73,22 @@
 	    }
 	    /* would carry on here to scan in BBox, name and ligs */
 
+	    /* Carry on to find BBox (or actually just ascent) of Aring. This
+	       will provide something like the lfHeight value */
+
+	    else if(!strncmp("N ", item, 2)) {
+	        name = value; /* may end in space */
+	    }
+
+	    else if(!strncmp("B ", item, 2)) {
+	        if(name && !strncmp("Aring", name, 5)) {
+		    float llx, lly, urx, ury;
+		    llx = lly = urx = ury = 0.0;
+		    sscanf(value, "%f%f%f%f", &llx, &lly, &urx, &ury);
+		    afm->FullAscender = ury;
+		}
+	    }
+
 	}
     }
 
@@ -100,7 +118,7 @@
         return NULL;
     }
 
-    afm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AFM));
+    afm = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(AFM));
     if(!afm) {
         fclose(fp);
         return NULL;
@@ -118,17 +136,17 @@
 	    value++;
 
 	if(!strncmp("FontName", buf, 8)) {
-	    afm->FontName = HEAP_strdupA(GetProcessHeap(), 0, value);
+	    afm->FontName = HEAP_strdupA(PSDRV_Heap, 0, value);
 	    continue;
 	}
 
 	if(!strncmp("FullName", buf, 8)) {
-	    afm->FullName = HEAP_strdupA(GetProcessHeap(), 0, value);
+	    afm->FullName = HEAP_strdupA(PSDRV_Heap, 0, value);
 	    continue;
 	}
 
 	if(!strncmp("FamilyName", buf, 10)) {
-	    afm->FamilyName = HEAP_strdupA(GetProcessHeap(), 0, value);
+	    afm->FamilyName = HEAP_strdupA(PSDRV_Heap, 0, value);
 	    continue;
 	}
 	
@@ -205,24 +223,81 @@
 	    continue;
 	}
 
-    }
 
+
+
+    }
     fclose(fp);
-    if(afm->Ascender == 0.0) afm->Ascender = 1000.0;
+
+    if(afm->Ascender == 0.0)
+        afm->Ascender = afm->FontBBox.ury;
+    if(afm->Descender == 0.0)
+        afm->Descender = afm->FontBBox.lly;
+    if(afm->FullAscender == 0.0)
+        afm->FullAscender = afm->Ascender;
+
     return afm;
 }
 
 /***********************************************************
  *
+ *	PSDRV_FreeAFMList
+ *
+ * Frees the family and afmlistentry structures in list head
+ */
+void PSDRV_FreeAFMList( FONTFAMILY *head )
+{
+    AFMLISTENTRY *afmle, *nexta;
+    FONTFAMILY *family, *nextf;
+
+    for(nextf = family = head; nextf; family = nextf) {
+        for(nexta = afmle = family->afmlist; nexta; afmle = nexta) {
+	    nexta = afmle->next;
+	    HeapFree( PSDRV_Heap, 0, afmle );
+	}
+        nextf = family->next;
+	HeapFree( PSDRV_Heap, 0, family );
+    }
+    return;
+}
+
+
+/***********************************************************
+ *
+ *	PSDRV_FindAFMinList
+ * Returns ptr to an AFM if name (which is a PS font name) exists in list
+ * headed by head.
+ */
+AFM *PSDRV_FindAFMinList(FONTFAMILY *head, char *name)
+{
+    FONTFAMILY *family;
+    AFMLISTENTRY *afmle;
+
+    for(family = head; family; family = family->next) {
+        for(afmle = family->afmlist; afmle; afmle = afmle->next) {
+	    if(!strcmp(afmle->afm->FontName, name))
+	        return afmle->afm;
+	}
+    }
+    return NULL;
+}
+
+/***********************************************************
+ *
  *	PSDRV_AddAFMtoList
  *
- * Adds an afm to the current font list. Creates new family node if necessary.
+ * Adds an afm to the list whose head is pointed to by head. Creates new
+ * family node if necessary and always creates a new AFMLISTENTRY.
  */
-static void PSDRV_AddAFMtoList(AFM *afm)
+void PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm)
 {
-    FontFamily *family = PSDRV_AFMFontList;
-    FontFamily **insert = &PSDRV_AFMFontList;
-    AFM *tmpafm;
+    FONTFAMILY *family = *head;
+    FONTFAMILY **insert = head;
+    AFMLISTENTRY *tmpafmle, *newafmle;
+
+    newafmle = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY,
+			   sizeof(*newafmle));
+    newafmle->afm = afm;
 
     while(family) {
         if(!strcmp(family->FamilyName, afm->FamilyName))
@@ -230,22 +305,22 @@
 	insert = &(family->next);
 	family = family->next;
     }
-    
+ 
     if(!family) {
-        family = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+        family = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY,
 			   sizeof(*family));
 	*insert = family;
-	family->FamilyName = HEAP_strdupA(GetProcessHeap(), 0,
+	family->FamilyName = HEAP_strdupA(PSDRV_Heap, 0,
 					  afm->FamilyName);
-	family->afm = afm;
+	family->afmlist = newafmle;
 	return;
     }
     
-    tmpafm = family->afm;
-    while(tmpafm->next)
-        tmpafm = tmpafm->next;
+    tmpafmle = family->afmlist;
+    while(tmpafmle->next)
+        tmpafmle = tmpafmle->next;
 
-    tmpafm->next = afm;
+    tmpafmle->next = newafmle;
 
     return;
 }
@@ -263,7 +338,7 @@
 
     afm = PSDRV_AFMParse(value);
     if(afm)
-        PSDRV_AddAFMtoList(afm);
+        PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm);
     return;
 }
 
@@ -275,13 +350,13 @@
  */
 static void PSDRV_DumpFontList(void)
 {
-    FontFamily *family;
-    AFM *afm;
+    FONTFAMILY *family;
+    AFMLISTENTRY *afmle;
 
     for(family = PSDRV_AFMFontList; family; family = family->next) {
         TRACE(psdrv, "Family '%s'\n", family->FamilyName);
-	for(afm = family->afm; afm; afm = afm->next) {
-	    TRACE(psdrv, "\tFontName '%s'\n", afm->FontName);
+	for(afmle = family->afmlist; afmle; afmle = afmle->next) {
+	    TRACE(psdrv, "\tFontName '%s'\n", afmle->afm->FontName);
 	}
     }
     return;
diff --git a/graphics/psdrv/driver.c b/graphics/psdrv/driver.c
index d217e99..ead31bb 100644
--- a/graphics/psdrv/driver.c
+++ b/graphics/psdrv/driver.c
@@ -1,7 +1,7 @@
 /*
- * Exported functions from the Postscript driver.
+ * Exported functions from the PostScript driver.
  *
- * [Ext]DeviceMode, DeviceCapabilities. 
+ * [Ext]DeviceMode, DeviceCapabilities, AdvancedSetupDialog. 
  *
  * Will need ExtTextOut for winword6 (urgh!)
  *
@@ -9,51 +9,171 @@
  *
  */
 
-#include "windows.h"
-#include "psdrv.h"
-#include "debug.h"
+#include <windows.h>
+#include <psdrv.h>
+#include <debug.h>
+#include <resource.h>
+#include <string.h>
+#include <win.h>
+#include <print.h>
 
-
-static DEVMODE16 DefaultDevMode = 
-{
-/* dmDeviceName */	"Wine Postscript Driver",
-/* dmSpecVersion */	0x30a,
-/* dmDriverVersion */	0x001,
-/* dmSize */		sizeof(DEVMODE16),
-/* dmDriverExtra */	0,
-/* dmFields */		DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | 
-			  DM_PAPERWIDTH,
-/* dmOrientation */	DMORIENT_PORTRAIT,
-/* dmPaperSize */	DMPAPER_A4,
-/* dmPaperLength */	2930,
-/* dmPaperWidth */      2000,
-/* dmScale */		0,
-/* dmCopies */		0,
-/* dmDefaultSource */	0,
-/* dmPrintQuality */	0,
-/* dmColor */		0,
-/* dmDuplex */		0,
-/* dmYResolution */	0,
-/* dmTTOption */	0,
-/* dmCollate */		0,
-/* dmFormName */	"",
-/* dmUnusedPadding */   0,
-/* dmBitsPerPel */	0,
-/* dmPelsWidth */	0,
-/* dmPelsHeight */	0,
-/* dmDisplayFlags */	0,
-/* dmDisplayFrequency */ 0
-};
-
-
-static char PaperNames[][64] = {"My A4"};
-static WORD Papers[] = {DMPAPER_A4};
-static POINT16 PaperSizes[] = {{2110, 2975}};
-static char BinNames[][24] = {"My Bin"};
-static WORD Bins[] = {DMBIN_AUTO};
 static LONG Resolutions[][2] = { {600,600} };
 
 
+/************************************************************************
+ *
+ *		PSDRV_MergeDevmodes
+ *
+ * Updates dm1 with some fields from dm2
+ *
+ */
+void PSDRV_MergeDevmodes(PSDRV_DEVMODE16 *dm1, PSDRV_DEVMODE16 *dm2,
+			 PRINTERINFO *pi)
+{
+    /* some sanity checks here on dm2 */
+    if(dm2->dmPublic.dmFields & DM_ORIENTATION)
+        dm1->dmPublic.dmOrientation = dm2->dmPublic.dmOrientation;
+	    /* NB PaperWidth is always < PaperLength */
+        
+    if(dm2->dmPublic.dmFields & DM_PAPERSIZE) {
+        PAGESIZE *page;
+
+	for(page = pi->ppd->PageSizes; page; page = page->next) {
+	    if(page->WinPage == dm2->dmPublic.dmPaperSize)
+	        break;
+	}
+	if(page) {
+	    dm1->dmPublic.dmPaperSize = dm2->dmPublic.dmPaperSize;
+	    dm1->dmPublic.dmPaperWidth = page->PaperDimension->x * 25.4 / 72.0;
+	    dm1->dmPublic.dmPaperLength = page->PaperDimension->y * 25.4 / 72.0;
+	    TRACE(psdrv, "Changing page to %s %d x %d\n", page->FullName,
+		     dm1->dmPublic.dmPaperWidth, dm1->dmPublic.dmPaperLength );
+	} else {
+	    TRACE(psdrv, "Trying to change to unsupported pagesize %d\n",
+		      dm2->dmPublic.dmPaperSize);
+	}
+    }
+
+    if(dm2->dmPublic.dmFields & DM_DEFAULTSOURCE) {
+        INPUTSLOT *slot;
+	
+	for(slot = pi->ppd->InputSlots; slot; slot = slot->next) {
+	    if(slot->WinBin == dm2->dmPublic.dmDefaultSource)
+	        break;
+	}
+	if(slot) {
+	    dm1->dmPublic.dmDefaultSource = dm2->dmPublic.dmDefaultSource;
+	    TRACE(psdrv, "Changing bin to '%s'\n", slot->FullName);
+	} else {
+	  TRACE(psdrv, "Trying to change to unsupported bin %d\n",
+		dm2->dmPublic.dmDefaultSource);
+	}
+    }
+
+    /* etc */
+
+    return;
+}
+
+
+#if 0
+/*******************************************************************
+ *
+ *		PSDRV_NewPrinterDlgProc32
+ *
+ *
+ */
+LRESULT WINAPI PSDRV_NewPrinterDlgProc32(HWND32 hWnd, UINT32 wMsg,
+					    WPARAM32 wParam, LPARAM lParam)
+{
+  switch (wMsg) {
+  case WM_INITDIALOG:
+    TRACE(psdrv,"WM_INITDIALOG lParam=%08lX\n", lParam);
+    ShowWindow32(hWnd, SW_SHOWNORMAL);
+    return TRUE;
+ 
+  case WM_COMMAND:
+    switch (LOWORD(wParam)) {
+    case IDOK:
+      EndDialog32(hWnd, TRUE);
+      return TRUE;
+  
+    case IDCANCEL:
+      EndDialog32(hWnd, FALSE);
+      return TRUE;
+    
+    default:
+      return FALSE;
+    }
+  
+  default:
+    return FALSE;
+  }
+}
+
+LRESULT WINAPI PSDRV_AdvancedSetupDlgProc32(HWND32 hWnd, UINT32 wMsg,
+					    WPARAM32 wParam, LPARAM lParam)
+{
+  switch (wMsg) {
+  case WM_INITDIALOG:
+    TRACE(psdrv,"WM_INITDIALOG lParam=%08lX\n", lParam);
+    SendDlgItemMessage32A(hWnd, 99, CB_ADDSTRING32, 0, 
+			  (LPARAM)"Default Tray");
+    ShowWindow32(hWnd, SW_SHOWNORMAL);
+    return TRUE;
+
+  case WM_COMMAND:
+    switch (LOWORD(wParam)) {
+    case IDOK:
+      EndDialog32(hWnd, TRUE);
+      return TRUE;
+
+    case IDCANCEL:
+      EndDialog32(hWnd, FALSE);
+      return TRUE;
+
+    case 200:
+      DialogBoxIndirectParam32A( WIN_GetWindowInstance( hWnd ),
+			  SYSRES_GetResPtr( SYSRES_DIALOG_PSDRV_NEWPRINTER ),
+			  hWnd, PSDRV_NewPrinterDlgProc32, (LPARAM) NULL );
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+
+  default:    
+    return FALSE;
+  }
+}
+#endif /* 0 */
+
+/**************************************************************
+ *
+ *	PSDRV_AdvancedSetupDialog16	[WINEPS.93]
+ *
+ * Presumably dev1 and dev2 are in and out, don't know which is which yet.
+ * Not sure about return value either. (I haven't got any docs on this at all)
+ *
+ */
+INT16 WINAPI PSDRV_AdvancedSetupDialog16(HWND16 hwnd, HANDLE16 hDriver,
+					 LPDEVMODE16 dev1, LPDEVMODE16 dev2 )
+{
+
+  TRACE(psdrv, "hwnd = %04x, hDriver = %04x dev1=%p dev2=%p\n", hwnd,
+	hDriver, dev1, dev2);
+  return IDCANCEL;
+
+
+#if 0
+  return DialogBoxIndirectParam32A( WIN_GetWindowInstance( hwnd ),
+	SYSRES_GetResPtr( SYSRES_DIALOG_PSDRV_ADVANCEDSETUP ),
+	hwnd, PSDRV_AdvancedSetupDlgProc32, (LPARAM) NULL );
+#endif
+
+
+}
+
 /***************************************************************
  *
  *	PSDRV_ExtDeviceMode16	[WINEPS.90]
@@ -64,6 +184,7 @@
 LPDEVMODE16 lpdmOutput, LPSTR lpszDevice, LPSTR lpszPort,
 LPDEVMODE16 lpdmInput, LPSTR lpszProfile, WORD fwMode)
 {
+  PRINTERINFO *pi = PSDRV_FindPrinterInfo(lpszDevice);
 
   TRACE(psdrv,
 "(hwnd=%04x, hDriver=%04x, devOut=%p, Device='%s', Port='%s', devIn=%p, Profile='%s', Mode=%04x)\n",
@@ -71,14 +192,23 @@
 fwMode);
 
   if(!fwMode)
-    return sizeof(DefaultDevMode);
+    return sizeof(DEVMODE16); /* Just copy dmPublic bit of PSDRV_DEVMODE */
 
-  if(fwMode & DM_COPY)
-    memcpy(lpdmOutput, &DefaultDevMode, sizeof(DefaultDevMode));
-  
+  if((fwMode & DM_PROMPT) || (fwMode & DM_UPDATE))
+    FIXME(psdrv, "Mode %d not implemented\n", fwMode);
+
+  if(fwMode & DM_MODIFY) {
+    TRACE(psdrv, "DM_MODIFY set. devIn->dmFields = %08lx\n", lpdmInput->dmFields);
+    PSDRV_MergeDevmodes(pi->Devmode, (PSDRV_DEVMODE16 *)lpdmInput, pi);
+  }
+
+  if(fwMode & DM_COPY) {
+    memcpy(lpdmOutput, pi->Devmode, sizeof(DEVMODE16));
+  }
   return IDOK;
 }
 
+
 /***************************************************************
  *
  *	PSDRV_DeviceCapabilities16	[WINEPS.91]
@@ -87,37 +217,84 @@
 DWORD WINAPI PSDRV_DeviceCapabilities16(LPSTR lpszDevice, LPSTR lpszPort,
   WORD fwCapability, LPSTR lpszOutput, LPDEVMODE16 lpdm)
 {
-  TRACE(psdrv, "Cap=%d\n", fwCapability);
+  PRINTERINFO *pi;
+
+  pi = PSDRV_FindPrinterInfo(lpszDevice);
+  TRACE(psdrv, "Cap=%d. Got PrinterInfo = %p\n", fwCapability, pi);
 
   switch(fwCapability) {
 
   case DC_PAPERS:
-    if(lpszOutput != NULL)
-      memcpy(lpszOutput, Papers, sizeof(Papers));
-    return sizeof(Papers) / sizeof(WORD);
+    {
+      PAGESIZE *ps;
+      WORD *wp = (WORD *)lpszOutput;
+      int i = 0;
+
+      for(ps = pi->ppd->PageSizes; ps; ps = ps->next, i++)
+	if(lpszOutput != NULL)
+	  *wp++ = ps->WinPage;
+      return i;
+    }
 
   case DC_PAPERSIZE:
-    if(lpszOutput != NULL)
-      memcpy(lpszOutput, PaperSizes, sizeof(PaperSizes));
-    return sizeof(PaperSizes) / sizeof(POINT16);
+    {
+      PAGESIZE *ps;
+      POINT16 *pt = (POINT16 *)lpszOutput;
+      int i = 0;
 
-  case DC_BINS:
-    if(lpszOutput != NULL)
-      memcpy(lpszOutput, Bins, sizeof(Bins));
-    return sizeof(Bins) / sizeof(WORD);
-    
-  case DC_BINNAMES:
-    if(lpszOutput != NULL)
-      memcpy(lpszOutput, BinNames, sizeof(BinNames));
-    return sizeof(BinNames) / sizeof(BinNames[0]);
+      for(ps = pi->ppd->PageSizes; ps; ps = ps->next, i++)
+	if(lpszOutput != NULL) {
+	  pt->x = ps->PaperDimension->x * 254.0 / 72.0;
+	  pt->y = ps->PaperDimension->y * 254.0 / 72.0;
+	  pt++;
+	}
+      return i;
+    }
 
   case DC_PAPERNAMES:
-    if(lpszOutput != NULL)
-      memcpy(lpszOutput, PaperNames, sizeof(PaperNames));
-    return sizeof(PaperNames) / sizeof(PaperNames[0]);
+    {
+      PAGESIZE *ps;
+      char *cp = lpszOutput;
+      int i = 0;
+
+      for(ps = pi->ppd->PageSizes; ps; ps = ps->next, i++)
+	if(lpszOutput != NULL) {
+	  strncpy(cp, ps->FullName, 64);
+	  *(cp + 63) = '\0';
+	  cp += 64;
+	}
+      return i;
+    }
 
   case DC_ORIENTATION:
-    return 90;
+    return pi->ppd->LandscapeOrientation ? pi->ppd->LandscapeOrientation : 90;
+
+  case DC_BINS:
+    {
+      INPUTSLOT *slot;
+      WORD *wp = (WORD *)lpszOutput;
+      int i = 0;
+
+      for(slot = pi->ppd->InputSlots; slot; slot = slot->next, i++)
+	if(lpszOutput != NULL)
+	  *wp++ = slot->WinBin;
+      return i;
+    }
+
+  case DC_BINNAMES:
+    {
+      INPUTSLOT *slot;
+      char *cp = lpszOutput;
+      int i = 0;
+      
+      for(slot = pi->ppd->InputSlots; slot; slot = slot->next, i++)
+	if(lpszOutput != NULL) {
+	  strncpy(cp, slot->FullName, 24);
+	  *(cp + 23) = '\0';
+	  cp += 24;
+	}
+      return i;
+    }
 
   case DC_ENUMRESOLUTIONS:
     if(lpszOutput != NULL)
diff --git a/graphics/psdrv/escape.c b/graphics/psdrv/escape.c
index 036582b..d5f46e5 100644
--- a/graphics/psdrv/escape.c
+++ b/graphics/psdrv/escape.c
@@ -1,5 +1,5 @@
 /*
- *	Postscript driver Escape function
+ *	PostScript driver Escape function
  *
  *	Copyright 1998  Huw D M Davies
  */
diff --git a/graphics/psdrv/font.c b/graphics/psdrv/font.c
index fc7e5d5..6abab35 100644
--- a/graphics/psdrv/font.c
+++ b/graphics/psdrv/font.c
@@ -1,5 +1,5 @@
 /*
- *	Postscript driver font functions
+ *	PostScript driver font functions
  *
  *	Copyright 1998  Huw D M Davies
  *
@@ -22,8 +22,9 @@
     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
     LOGFONT16 *lf = &(font->logfont);
     BOOL32 bd = FALSE, it = FALSE;
+    AFMLISTENTRY *afmle;
     AFM *afm;
-    FontFamily *family;
+    FONTFAMILY *family;
     char FaceName[LF_FACESIZE];
 
 
@@ -69,39 +70,42 @@
 	}
     }
 
-    for(family = PSDRV_AFMFontList; family; family = family->next) {
+    for(family = physDev->pi->Fonts; family; family = family->next) {
         if(!lstrncmp32A(FaceName, family->FamilyName, 
 			                         strlen(family->FamilyName)))
 	    break;
     }
     if(!family)
-        family = PSDRV_AFMFontList;
+        family = physDev->pi->Fonts;
 
     
-    for(afm = family->afm; afm; afm = afm->next) {
-        if( (bd == (afm->Weight == FW_BOLD)) && 
-	    (it == (afm->ItalicAngle != 0.0)) )
+    for(afmle = family->afmlist; afmle; afmle = afmle->next) {
+        if( (bd == (afmle->afm->Weight == FW_BOLD)) && 
+	    (it == (afmle->afm->ItalicAngle != 0.0)) )
 	        break;
     }
-    if(!afm)
-        afm = family->afm; /* not ideal */
+    if(!afmle)
+        afmle = family->afmlist; /* not ideal */
     
-    physDev->font.afm = afm;
-    physDev->font.size = YLSTODS(dc, lf->lfHeight);
-    if(physDev->font.size < 0) {
-        TRACE(psdrv, "physDev->font.size < 0\n");
-        physDev->font.size = abs(physDev->font.size);
-        TRACE(psdrv, "physDev->font.size now %d\n", physDev->font.size);
-    }
-    physDev->font.scale = physDev->font.size / 
-                                    (afm->Ascender - afm->Descender);
+    afm = afmle->afm;
 
+    physDev->font.afm = afm;
+    physDev->font.tm.tmHeight = YLSTODS(dc, lf->lfHeight);
+    if(physDev->font.tm.tmHeight < 0) {
+        physDev->font.tm.tmHeight *= - (afm->FullAscender - afm->Descender) /
+				       (afm->Ascender - afm->Descender);
+	TRACE(psdrv, "Fixed -ve height to %d\n", physDev->font.tm.tmHeight);
+    }
+    physDev->font.size = physDev->font.tm.tmHeight * 1000.0 /
+				(afm->FullAscender - afm->Descender);
+    physDev->font.scale = physDev->font.size / 1000.0;
     physDev->font.escapement = lf->lfEscapement;
-    physDev->font.tm.tmHeight = physDev->font.size;
-    physDev->font.tm.tmAscent = afm->Ascender * physDev->font.scale;
+    physDev->font.tm.tmAscent = afm->FullAscender * physDev->font.scale;
     physDev->font.tm.tmDescent = -afm->Descender * physDev->font.scale;
-    physDev->font.tm.tmInternalLeading = physDev->font.tm.tmHeight * 0.2;
-    physDev->font.tm.tmExternalLeading = physDev->font.tm.tmHeight * 0.2;
+    physDev->font.tm.tmInternalLeading = (afm->FullAscender - afm->Ascender)
+						* physDev->font.scale;
+    physDev->font.tm.tmExternalLeading = (1000.0 - afm->FullAscender)
+						* physDev->font.scale; /* ?? */
     physDev->font.tm.tmAveCharWidth = afm->CharWidths[120] * /* x */
                                                    physDev->font.scale;
     physDev->font.tm.tmMaxCharWidth = afm->CharWidths[77] * /* M */
@@ -124,10 +128,14 @@
 
     physDev->font.set = FALSE;
 
-    TRACE(psdrv, "Selected PS font '%s' size %d weight %d\n", 
+    TRACE(psdrv, "Selected PS font '%s' size %d weight %d.\n", 
 	  physDev->font.afm->FontName, physDev->font.size,
 	  physDev->font.tm.tmWeight );
-    
+    TRACE(psdrv, "H = %d As = %d Des = %d IL = %d EL = %d\n",
+	  physDev->font.tm.tmHeight, physDev->font.tm.tmAscent,
+	  physDev->font.tm.tmDescent, physDev->font.tm.tmInternalLeading,
+	  physDev->font.tm.tmExternalLeading);
+
     return prevfont;
 }
 
@@ -156,10 +164,12 @@
     size->cy = YDSTOLS(dc, physDev->font.tm.tmHeight);
     width = 0.0;
 
-    for(i = 0; i < count && str[i]; i++)
+    for(i = 0; i < count && str[i]; i++) {
         width += physDev->font.afm->CharWidths[ (UINT32)str[i] ];
-    
+	TRACE(psdrv, "Width after %dth char '%c' = %f\n", i, str[i], width);
+    }
     width *= physDev->font.scale;
+    TRACE(psdrv, "Width after scale (%f) is %f\n", physDev->font.scale, width);
     size->cx = XDSTOLS(dc, width);
 
     return TRUE;
@@ -189,12 +199,13 @@
               ENUMLOGFONTEX16 *pLF, INT16 size)
 
 {
+    float scale = size / (pafm->FullAscender - pafm->Descender);
     memset( pLF, 0, sizeof(*pLF) );
     memset( pTM, 0, sizeof(*pTM) );
 
 #define plf ((LPLOGFONT16)pLF)
     plf->lfHeight    = pTM->tmHeight       = size;
-    plf->lfWidth     = pTM->tmAveCharWidth = size * 0.7;
+    plf->lfWidth     = pTM->tmAveCharWidth = pafm->CharWidths[120] * scale;
     plf->lfWeight    = pTM->tmWeight       = pafm->Weight;
     plf->lfItalic    = pTM->tmItalic       = pafm->ItalicAngle != 0.0;
     plf->lfUnderline = pTM->tmUnderlined   = 0;
@@ -210,10 +221,10 @@
     lstrcpyn32A( plf->lfFaceName, pafm->FamilyName, LF_FACESIZE );
 #undef plf
 
-    pTM->tmAscent = pTM->tmHeight * 0.2;
-    pTM->tmDescent = pTM->tmHeight - pTM->tmAscent;
-    pTM->tmInternalLeading = pTM->tmHeight * 0.2;
-    pTM->tmMaxCharWidth = pTM->tmHeight * 0.7;
+    pTM->tmAscent = pafm->FullAscender * scale;
+    pTM->tmDescent = -pafm->Descender * scale;
+    pTM->tmInternalLeading = (pafm->FullAscender - pafm->Ascender) * scale;
+    pTM->tmMaxCharWidth = pafm->CharWidths[77] * scale;
     pTM->tmDigitizedAspectX = dc->w.devCaps->logPixelsY;
     pTM->tmDigitizedAspectY = dc->w.devCaps->logPixelsX;
 
@@ -234,21 +245,23 @@
     ENUMLOGFONTEX16	lf;
     NEWTEXTMETRIC16	tm;
     BOOL32	  	b, bRet = 0;
-    AFM			*afm;
-    FontFamily		*family;
+    AFMLISTENTRY	*afmle;
+    FONTFAMILY		*family;
+    PSDRV_PDEVICE	*physDev = (PSDRV_PDEVICE *)dc->physDev;
 
     if( plf->lfFaceName[0] ) {
         TRACE(psdrv, "lfFaceName = '%s'\n", plf->lfFaceName);
-        for(family = PSDRV_AFMFontList; family; family = family->next) {
+        for(family = physDev->pi->Fonts; family; family = family->next) {
             if(!lstrncmp32A(plf->lfFaceName, family->FamilyName, 
 			strlen(family->FamilyName)))
 	        break;
 	}
 	if(family) {
-	    for(afm = family->afm; afm; afm = afm->next) {
-	        TRACE(psdrv, "Got '%s'\n", afm->FontName);
+	    for(afmle = family->afmlist; afmle; afmle = afmle->next) {
+	        TRACE(psdrv, "Got '%s'\n", afmle->afm->FontName);
 		if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
-			PSDRV_GetFontMetric( dc, afm, &tm, &lf, 200 ), lp )) )
+			PSDRV_GetFontMetric( dc, afmle->afm, &tm, &lf, 200 ),
+				  lp )) )
 		     bRet = b;
 		else break;
 	    }
@@ -256,11 +269,12 @@
     } else {
 
         TRACE(psdrv, "lfFaceName = NULL\n");
-        for(family = PSDRV_AFMFontList; family; family = family->next) {
-	    afm = family->afm;
-	    TRACE(psdrv, "Got '%s'\n", afm->FontName);
+        for(family = physDev->pi->Fonts; family; family = family->next) {
+	    afmle = family->afmlist;
+	    TRACE(psdrv, "Got '%s'\n", afmle->afm->FontName);
 	    if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
-		   PSDRV_GetFontMetric( dc, afm, &tm, &lf, 200 ), lp )) )
+		   PSDRV_GetFontMetric( dc, afmle->afm, &tm, &lf, 200 ), 
+			      lp )) )
 	        bRet = b;
 	    else break;
 	}
diff --git a/graphics/psdrv/graphics.c b/graphics/psdrv/graphics.c
index ebc4c2e..9b0e02d 100644
--- a/graphics/psdrv/graphics.c
+++ b/graphics/psdrv/graphics.c
@@ -1,5 +1,5 @@
 /*
- *	Postscript driver graphics functions
+ *	PostScript driver graphics functions
  *
  *	Copyright 1998  Huw D M Davies
  *
@@ -71,3 +71,41 @@
     
     return TRUE;
 }
+
+
+/***********************************************************************
+ *           PSDRV_Polyline
+ */
+BOOL32 PSDRV_Polyline( DC *dc, const LPPOINT32 pt, INT32 count )
+{
+    INT32 i;
+    TRACE(psdrv, "count = %d\n", count);
+    
+    PSDRV_WriteMoveTo(dc, XLPTODP(dc, pt[0].x), YLPTODP(dc, pt[0].y));
+    for(i = 1; i < count; i++)
+        PSDRV_WriteLineTo(dc, XLPTODP(dc, pt[i].x), YLPTODP(dc, pt[i].y));
+    PSDRV_WriteStroke(dc);
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           PSDRV_Polygon
+ */
+BOOL32 PSDRV_Polygon( DC *dc, LPPOINT32 pt, INT32 count )
+{
+    INT32 i;
+    TRACE(psdrv, "count = %d\n", count);
+    FIXME(psdrv, "Hack!\n");
+    PSDRV_WriteMoveTo(dc, XLPTODP(dc, pt[0].x), YLPTODP(dc, pt[0].y));
+    for(i = 1; i < count; i++)
+        PSDRV_WriteLineTo(dc, XLPTODP(dc, pt[i].x), YLPTODP(dc, pt[i].y));
+
+    if(pt[0].x != pt[count-1].x || pt[0].y != pt[count-1].y)
+        PSDRV_WriteLineTo(dc, XLPTODP(dc, pt[0].x), YLPTODP(dc, pt[0].y));
+
+    PSDRV_WriteStroke(dc);
+    return TRUE;
+}
+
+
diff --git a/graphics/psdrv/init.c b/graphics/psdrv/init.c
index e68f64c..3195200 100644
--- a/graphics/psdrv/init.c
+++ b/graphics/psdrv/init.c
@@ -1,15 +1,18 @@
 /*
- *	Postscript driver initialization functions
+ *	PostScript driver initialization functions
  *
  *	Copyright 1998 Huw D M Davies
  *
  */
 
-#include "windows.h"
-#include "gdi.h"
-#include "psdrv.h"
-#include "debug.h"
-#include "heap.h"
+#include <windows.h>
+#include <gdi.h>
+#include <psdrv.h>
+#include <debug.h>
+#include <heap.h>
+#include <winreg.h>
+#include <print.h>
+#include <winerror.h>
 
 static BOOL32 PSDRV_CreateDC( DC *dc, LPCSTR driver, LPCSTR device,
                                LPCSTR output, const DEVMODE16* initData );
@@ -46,9 +49,9 @@
     NULL,                            /* pPie */
     NULL,                            /* pPolyPolygon */
     NULL,                            /* pPolyPolyline */
-    NULL,                            /* pPolygon */
-    NULL,                            /* pPolyline */
-    NULL,                            /* pPolyBezier */
+    PSDRV_Polygon,                   /* pPolygon */
+    PSDRV_Polyline,                  /* pPolyline */
+    NULL,                            /* pPolyBezier */		     
     NULL,                            /* pRealizePalette */
     PSDRV_Rectangle,                 /* pRectangle */
     NULL,                            /* pRestoreDC */
@@ -88,10 +91,10 @@
 static DeviceCaps PSDRV_DevCaps = {
 /* version */		0, 
 /* technology */	DT_RASPRINTER,
-/* horzSize */		200,
-/* vertSize */		288,
-/* horzRes */		4733,
-/* vertRes */		6808, 
+/* horzSize */		210,
+/* vertSize */		297,
+/* horzRes */		4961,
+/* vertRes */		7016, 
 /* bitsPixel */		1,
 /* planes */		1,
 /* numBrushes */	-1,
@@ -108,7 +111,7 @@
 /* polygoalnCaps */	PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON |
 			PC_SCANLINE | PC_WIDE | PC_STYLED | PC_WIDESTYLED |
 			PC_INTERIORS,
-/* textCaps */		0, /* psdrv 0x59f7 */
+/* textCaps */		TC_CR_ANY, /* psdrv 0x59f7 */
 /* clipCaps */		CP_RECTANGLE,
 /* rasterCaps */	RC_BITBLT | RC_BANDING | RC_SCALING | RC_BITMAP64 |
 			RC_DI_BITMAP | RC_DIBTODEV | RC_BIGFONT |
@@ -124,6 +127,48 @@
 /* palette size */	0,
 /* ..etc */		0, 0 };
 
+static PSDRV_DEVMODE16 DefaultDevmode = 
+{
+  { /* dmPublic */
+/* dmDeviceName */	"Wine PostScript Driver",
+/* dmSpecVersion */	0x30a,
+/* dmDriverVersion */	0x001,
+/* dmSize */		sizeof(DEVMODE16),
+/* dmDriverExtra */	0,
+/* dmFields */		DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH |
+			DM_PAPERWIDTH | DM_SCALE | DM_COPIES | 
+			DM_DEFAULTSOURCE | DM_COLOR | DM_DUPLEX | 
+			DM_YRESOLUTION | DM_TTOPTION,
+/* dmOrientation */	DMORIENT_PORTRAIT,
+/* dmPaperSize */	DMPAPER_A4,
+/* dmPaperLength */	2969,
+/* dmPaperWidth */      2101,
+/* dmScale */		100, /* ?? */
+/* dmCopies */		1,
+/* dmDefaultSource */	DMBIN_AUTO,
+/* dmPrintQuality */	0,
+/* dmColor */		DMCOLOR_MONOCHROME,
+/* dmDuplex */		0,
+/* dmYResolution */	0,
+/* dmTTOption */	DMTT_SUBDEV,
+/* dmCollate */		0,
+/* dmFormName */	"",
+/* dmUnusedPadding */   0,
+/* dmBitsPerPel */	0,
+/* dmPelsWidth */	0,
+/* dmPelsHeight */	0,
+/* dmDisplayFlags */	0,
+/* dmDisplayFrequency */ 0
+  },
+  { /* dmDocPrivate */
+  },
+  { /* dmDrvPrivate */
+/* ppdfilename */	"default.ppd"
+  }
+};
+
+HANDLE32 PSDRV_Heap = 0;
+
 /*********************************************************************
  *	     PSDRV_Init
  *
@@ -132,12 +177,12 @@
  */
 BOOL32 PSDRV_Init(void)
 {
-  TRACE(psdrv, "\n");
-  PSDRV_GetFontMetrics();
-  return DRIVER_RegisterDriver( "WINEPS", &PSDRV_Funcs );
+    TRACE(psdrv, "\n");
+    PSDRV_Heap = HeapCreate(0, 0x10000, 0);
+    PSDRV_GetFontMetrics();
+    return DRIVER_RegisterDriver( "WINEPS", &PSDRV_Funcs );
 }
 
-
 /**********************************************************************
  *	     PSDRV_CreateDC
  */
@@ -145,24 +190,69 @@
                                LPCSTR output, const DEVMODE16* initData )
 {
     PSDRV_PDEVICE *physDev;
+    PRINTERINFO *pi = PSDRV_FindPrinterInfo(device);
+    DeviceCaps *devCaps;
 
     TRACE(psdrv, "(%s %s %s %p)\n", driver, device, output, initData);
 
-    if(!PSDRV_AFMFontList) {
+    if(!pi->Fonts) {
         MSG("To use WINEPS you need to install some AFM files.\n");
 	return FALSE;
     }
 
-    dc->w.devCaps = &PSDRV_DevCaps;
-    dc->w.hVisRgn = CreateRectRgn32(0, 0, dc->w.devCaps->horzRes,
-    			    dc->w.devCaps->vertRes);
-    
-    physDev = (PSDRV_PDEVICE *)HeapAlloc( GetProcessHeap(), 0,
+    physDev = (PSDRV_PDEVICE *)HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
 					             sizeof(*physDev) );
     if (!physDev) return FALSE;
     dc->physDev = physDev;
-    physDev->job.output = HEAP_strdupA( GetProcessHeap(), 0, output );
-    if (!physDev->job.output) return FALSE;
+
+    physDev->pi = pi;
+
+    physDev->Devmode = (PSDRV_DEVMODE16 *)HeapAlloc( PSDRV_Heap, 0,
+						     sizeof(PSDRV_DEVMODE16) );
+    if(!physDev->Devmode) {
+        HeapFree( PSDRV_Heap, 0, physDev );
+	return FALSE;
+    }
+    
+    memcpy( physDev->Devmode, pi->Devmode, sizeof(PSDRV_DEVMODE16) );
+
+    if(initData) {
+        PSDRV_MergeDevmodes(physDev->Devmode, (PSDRV_DEVMODE16 *)initData, pi);
+    }
+
+    
+    devCaps = HeapAlloc( PSDRV_Heap, 0, sizeof(PSDRV_DevCaps) );
+    memcpy(devCaps, &PSDRV_DevCaps, sizeof(PSDRV_DevCaps));
+
+    if(physDev->Devmode->dmPublic.dmOrientation == DMORIENT_PORTRAIT) {
+        devCaps->horzSize = physDev->Devmode->dmPublic.dmPaperWidth;
+	devCaps->vertSize = physDev->Devmode->dmPublic.dmPaperLength;
+    } else {
+        devCaps->horzSize = physDev->Devmode->dmPublic.dmPaperLength;
+	devCaps->vertSize = physDev->Devmode->dmPublic.dmPaperWidth;
+    }
+
+    devCaps->horzRes = physDev->pi->ppd->DefaultResolution * 
+      devCaps->horzSize / 25.4;
+    devCaps->vertRes = physDev->pi->ppd->DefaultResolution * 
+      devCaps->vertSize / 25.4;
+
+    /* Are aspect[XY] and logPixels[XY] correct? */
+    /* Need to handle different res in x and y => fix ppd */
+    devCaps->aspectX = devCaps->logPixelsX = 
+				physDev->pi->ppd->DefaultResolution;
+    devCaps->aspectY = devCaps->logPixelsY = 
+				physDev->pi->ppd->DefaultResolution;
+    devCaps->aspectXY = (int)hypot( (double)devCaps->aspectX, 
+				    (double)devCaps->aspectY );
+    /* etc */
+
+    dc->w.devCaps = devCaps;
+
+    dc->w.hVisRgn = CreateRectRgn32(0, 0, dc->w.devCaps->horzRes,
+    			    dc->w.devCaps->vertRes);
+    
+    physDev->job.output = HEAP_strdupA( PSDRV_Heap, 0, output );
     physDev->job.hJob = 0;
     return TRUE;
 }
@@ -174,11 +264,71 @@
 static BOOL32 PSDRV_DeleteDC( DC *dc )
 {
     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
-
+    
     TRACE(psdrv, "\n");
-    HeapFree( GetProcessHeap(), 0, physDev->job.output );
-    HeapFree( GetProcessHeap(), 0, physDev );
+
+    HeapFree( PSDRV_Heap, 0, physDev->Devmode );
+    HeapFree( PSDRV_Heap, 0, physDev->job.output );
+    HeapFree( PSDRV_Heap, 0, (void *)dc->w.devCaps );
+    HeapFree( PSDRV_Heap, 0, physDev );
     dc->physDev = NULL;
+
     return TRUE;
 }
 
+
+	
+
+/**********************************************************************
+ *		PSDRV_FindPrinterInfo
+ */
+PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) 
+{
+    static PRINTERINFO *PSDRV_PrinterList;
+    DWORD type = REG_BINARY, needed, res;
+    PRINTERINFO *pi = PSDRV_PrinterList, **last = &PSDRV_PrinterList;
+    FONTNAME *font;
+    AFM *afm;
+
+    TRACE(psdrv, "'%s'\n", name);
+    
+    for( ; pi; last = &pi->next, pi = pi->next) {
+        if(!strcmp(pi->FriendlyName, name))
+	    return pi;
+    }
+
+    pi = *last = HeapAlloc( PSDRV_Heap, 0, sizeof(*pi) );
+    pi->FriendlyName = HEAP_strdupA( PSDRV_Heap, 0, name );
+    res = DrvGetPrinterData((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
+			    NULL, 0, &needed );
+
+    if(res == ERROR_INVALID_PRINTER_NAME) {
+        pi->Devmode = HeapAlloc( PSDRV_Heap, 0, sizeof(DefaultDevmode) );
+	memcpy(pi->Devmode, &DefaultDevmode, sizeof(DefaultDevmode) );
+	DrvSetPrinterData((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE,
+		 REG_BINARY, (LPBYTE)&DefaultDevmode, sizeof(DefaultDevmode) );
+
+	/* need to do something here AddPrinter?? */
+    } else {
+        pi->Devmode = HeapAlloc( PSDRV_Heap, 0, needed );
+	DrvGetPrinterData((LPSTR)name, (LPSTR)INT_PD_DEFAULT_DEVMODE, &type,
+			  (LPBYTE)pi->Devmode, needed, &needed);
+    }
+
+    pi->ppd = PSDRV_ParsePPD(pi->Devmode->dmDrvPrivate.ppdFileName);
+    pi->next = NULL;
+    pi->Fonts = NULL;
+
+    for(font = pi->ppd->InstalledFonts; font; font = font->next) {
+        afm = PSDRV_FindAFMinList(PSDRV_AFMFontList, font->Name);
+	if(!afm) {
+	    MSG(
+	 "Couldn't find AFM file for installed printer font '%s' - ignoring\n",
+	 font->Name);
+	} else {
+	    PSDRV_AddAFMtoList(&pi->Fonts, afm);
+	}
+    }
+
+    return pi;
+}
diff --git a/graphics/psdrv/objects.c b/graphics/psdrv/objects.c
index 6d7de82..b8d8d47 100644
--- a/graphics/psdrv/objects.c
+++ b/graphics/psdrv/objects.c
@@ -1,5 +1,5 @@
 /*
- *	Postscript driver object handling
+ *	PostScript driver object handling
  *
  *	Copyright 1998  Huw D M Davies
  *
diff --git a/graphics/psdrv/ppd.c b/graphics/psdrv/ppd.c
new file mode 100644
index 0000000..8364d72
--- /dev/null
+++ b/graphics/psdrv/ppd.c
@@ -0,0 +1,656 @@
+/*	PostScript Printer Description (PPD) file parser
+ *
+ *	See  http://www.adobe.com/supportservice/devrelations/PDFS/TN/5003.PPD_Spec_v4.3.pdf
+ *
+ *	Copyright 1998  Huw D M Davies
+ */
+
+#include <windows.h>
+#include <winnt.h> /* HEAP_ZERO_MEMORY */
+#include <heap.h>
+#include <debug.h>
+#include <psdrv.h>
+#include <string.h>
+#include <ctype.h>
+#include <print.h>
+
+typedef struct {
+char	*key;
+char	*option;
+char	*opttrans;
+char	*value;
+char	*valtrans;
+} PPDTuple;
+
+
+/* map of page names in ppd file to Windows paper constants */
+
+static struct {
+  char *PSName;
+  WORD WinPage;
+} PageTrans[] = {
+  {"A4",	DMPAPER_A4},
+  {"Letter",	DMPAPER_LETTER},
+  {"Legal",	DMPAPER_LEGAL},
+  {"Executive",	DMPAPER_EXECUTIVE},
+  {"Comm10",	DMPAPER_ENV_10},
+  {"Monarch",	DMPAPER_ENV_MONARCH},
+  {"DL",	DMPAPER_ENV_DL},
+  {"C5",	DMPAPER_ENV_C5},
+  {"B5",	DMPAPER_ENV_B5},
+  {NULL,	0}
+};
+
+/* the same for bin names */
+
+static struct {
+  char *PSName;
+  WORD WinBin;
+} BinTrans[] = {
+  {"Lower",		DMBIN_LOWER},
+  {"Upper",		DMBIN_UPPER},
+  {"Envelope",		DMBIN_ENVELOPE},
+  {"LargeCapacity",	DMBIN_LARGECAPACITY},
+  {NULL,		0}
+};
+
+/***********************************************************************
+ *
+ *		PSDRV_PPDDecodeHex
+ *
+ * Copies str into a newly allocated string from the process heap subsituting
+ * hex strings enclosed in '<' and '>' for their byte codes.
+ *
+ */
+static char *PSDRV_PPDDecodeHex(char *str)
+{
+    char *buf, *in, *out;
+    BOOL32 inhex = FALSE;
+
+    buf = HeapAlloc(PSDRV_Heap, 0, strlen(str) + 1);
+    if(!buf)
+        return NULL;
+
+    for(in = str, out = buf; *in; in++) {
+        if(!inhex) {
+	    if(*in != '<')
+	        *out++ = *in;
+	    else
+	        inhex = TRUE;
+	} else {
+	    if(*in == '>') {
+	        inhex = FALSE;
+		continue;
+	    }
+	    else if(isspace(*in))
+	        continue;
+	    else {
+	        int i;
+	        if(!isxdigit(*in) || !isxdigit(*(in + 1))) {
+		    ERR(psdrv, "Invalid hex char in hex string\n");
+		    HeapFree(PSDRV_Heap, 0, buf);
+		    return NULL;
+		}
+		*out = 0;
+		for(i = 0; i < 2; i++) {
+		    if(isdigit(*(in + i)))
+		        *out |= (*(in + i) - '0') << ((1-i) * 4);
+		    else
+		        *out |= (toupper(*(in + i)) - 'A' + 10) << ((1-i) * 4);
+		}
+		out++;
+		in++;
+	    }
+	}
+    }
+    *out = '\0';
+    return buf;
+}
+
+
+/***********************************************************************
+ *
+ *		PSDRV_PPDGetTransValue
+ *
+ */
+static BOOL32 PSDRV_PPDGetTransValue(char *start, PPDTuple *tuple)
+{
+    char *buf, *end;
+
+    end = strpbrk(start, "\r\n");
+    if(end == start) return FALSE;
+    if(!end) end = start + strlen(start);
+    buf = HeapAlloc( PSDRV_Heap, 0, end - start + 1 );
+    memcpy(buf, start, end - start);
+    *(buf + (end - start)) = '\0';
+    tuple->valtrans = PSDRV_PPDDecodeHex(buf);
+    HeapFree( PSDRV_Heap, 0, buf );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *
+ *		PSDRV_PPDGetInvocationValue
+ *
+ * Passed string that should be surrounded by `"'s, return string alloced
+ * from process heap.
+ */
+static BOOL32 PSDRV_PPDGetInvocationValue(FILE *fp, char *pos, PPDTuple *tuple)
+{
+    char *start, *end, *buf;
+    char line[257];
+    int len;
+
+    start = pos + 1;
+    buf = HeapAlloc( PSDRV_Heap, 0, strlen(start) + 1 );
+    len = 0;
+    do {
+        end = strchr(start, '"');
+	if(end) {
+	    buf = HeapReAlloc( PSDRV_Heap, 0, buf, 
+			       len + (end - start) + 1 );
+	    memcpy(buf + len, start, end - start);
+	    *(buf + len + (end - start)) = '\0';
+	    tuple->value = buf;
+	    start = strchr(end, '/');
+	    if(start)
+	        return PSDRV_PPDGetTransValue(start + 1, tuple);
+	    return TRUE;
+	} else {
+	    int sl = strlen(start);
+	    buf = HeapReAlloc( PSDRV_Heap, 0, buf, len + sl + 1 );
+	    strcpy(buf + len, start);
+	    len += sl;
+	}
+    } while( fgets((start = line), sizeof(line), fp) );
+
+    tuple->value = NULL;
+    HeapFree( PSDRV_Heap, 0, buf );
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *
+ *		PSDRV_PPDGetQuotedValue
+ *
+ * Passed string that should be surrounded by `"'s. Expand <xx> as hex
+ * return string alloced from process heap.
+ */
+static BOOL32 PSDRV_PPDGetQuotedValue(FILE *fp, char *pos, PPDTuple *tuple)
+{
+    char *buf;
+
+    if(!PSDRV_PPDGetInvocationValue(fp, pos, tuple))
+        return FALSE;
+    buf = PSDRV_PPDDecodeHex(tuple->value);
+    HeapFree(PSDRV_Heap, 0, tuple->value);
+    tuple->value = buf;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *
+ *		PSDRV_PPDGetStringValue
+ *
+ * Just strip leading white space.
+ */
+static BOOL32 PSDRV_PPDGetStringValue(char *str, PPDTuple *tuple)
+{
+    char *start = str, *end;
+
+    while(*start != '\0' && isspace(*start))
+        start++;
+
+    end = strpbrk(start, "/\r\n");
+    if(!end) end = start + strlen(start);
+    tuple->value = HeapAlloc( PSDRV_Heap, 0, (end - start) + 1 );
+    memcpy(tuple->value, start, end - start);
+    *(tuple->value + (end - start)) = '\0';
+    if(*end == '/')
+        PSDRV_PPDGetTransValue(end + 1, tuple);
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *
+ *		PSDRV_PPDSymbolValue
+ *
+ * Not implemented yet.
+ */
+static BOOL32 PSDRV_PPDGetSymbolValue(char *pos, PPDTuple *tuple)
+{
+    FIXME(psdrv, "Stub\n");
+    return FALSE;
+}
+
+
+/*********************************************************************
+ *
+ *		PSDRV_PPDGetNextTuple
+ *
+ * Gets the next Keyword Option Value tuple from the file. Allocs space off
+ * the process heap which should be free()ed by the caller if not needed.
+ */
+static BOOL32 PSDRV_PPDGetNextTuple(FILE *fp, PPDTuple *tuple)
+{
+    char line[257], *opt = NULL, *cp, *trans;
+    BOOL32 gotoption = TRUE;
+
+    memset(tuple, 0, sizeof(*tuple));
+
+    do {
+        if(!fgets(line, sizeof(line), fp))
+            return FALSE;
+	if(line[0] == '*' && line[1] != '%' && strncmp(line, "*End", 4))
+	    break;
+    } while(1);
+
+    if(line[strlen(line)-1] != '\n') {
+        ERR(psdrv, "Line too long.\n");
+	return FALSE;
+    }
+
+    for(cp = line; !isspace(*cp); cp++)
+        ;
+
+    if(*(cp-1) == ':') {
+        cp--;
+        gotoption = FALSE;
+    } else {
+        opt = cp;
+    }
+
+    tuple->key = HeapAlloc( PSDRV_Heap, 0, cp - line + 1 );
+    if(!tuple->key) return FALSE;
+
+    memcpy(tuple->key, line, cp - line);
+    tuple->key[cp - line] = '\0';
+
+    if(gotoption) {
+        while(isspace(*opt))
+	    opt++;
+        cp = strpbrk(opt, ":/");
+	if(!cp) {
+	    ERR(psdrv, "Error in line '%s'?\n", line);
+	    return FALSE;
+	}
+	tuple->option = HeapAlloc( PSDRV_Heap, 0, cp - opt + 1 );
+	if(!tuple->option) return FALSE;
+	memcpy(tuple->option, opt, cp - opt);
+	tuple->option[cp - opt] = '\0';
+	if(*cp == '/') {
+	    char *buf;
+	    trans = cp + 1;
+	    cp = strchr(trans, ':');
+	    if(!cp) {
+	        ERR(psdrv, "Error in line '%s'?\n", line);
+		return FALSE;
+	    }
+	    buf = HeapAlloc( PSDRV_Heap, 0, cp - trans + 1 );
+	    if(!buf) return FALSE;
+	    memcpy(buf, trans, cp - trans);
+	    buf[cp - trans] = '\0';
+	    tuple->opttrans = PSDRV_PPDDecodeHex(buf);
+	    HeapFree( PSDRV_Heap, 0, buf );
+	}
+    }
+    while(!isspace(*cp))
+        cp++;
+
+    while(isspace(*cp))
+        cp++;
+
+    switch(*cp) {
+    case '"':
+        if( (!gotoption && strncmp(tuple->key, "*?", 2) ) ||
+	     !strncmp(tuple->key, "*JCL", 4))
+	    PSDRV_PPDGetQuotedValue(fp, cp, tuple);
+        else
+	    PSDRV_PPDGetInvocationValue(fp, cp, tuple);
+	break;
+
+    case '^':
+        PSDRV_PPDGetSymbolValue(cp, tuple);
+	break;
+
+    default:
+        PSDRV_PPDGetStringValue(cp, tuple);
+    }
+    return TRUE;
+}
+
+/*********************************************************************
+ *
+ *		PSDRV_PPDGetPageSizeInfo
+ *
+ * Searches ppd PageSize list to return entry matching name or creates new
+ * entry which is appended to the list if name is not found.
+ *
+ */
+PAGESIZE *PSDRV_PPDGetPageSizeInfo(PPD *ppd, char *name)
+{
+    PAGESIZE *page = ppd->PageSizes, *lastpage;
+    
+    if(!page) {
+       page = ppd->PageSizes = HeapAlloc( PSDRV_Heap,
+					    HEAP_ZERO_MEMORY, sizeof(*page) );
+       return page;
+    } else {
+        for( ; page; page = page->next) {
+	    if(!strcmp(page->Name, name))
+	         return page;
+	    lastpage = page;
+	}
+
+	lastpage->next = HeapAlloc( PSDRV_Heap,
+					   HEAP_ZERO_MEMORY, sizeof(*page) );
+	return lastpage->next;
+    }
+}
+
+/**********************************************************************
+ *
+ *		PSDRV_PPDGetWord
+ *
+ * Returns ptr alloced from heap to first word in str. Strips leading spaces.
+ * Puts ptr to next word in next
+ */
+static char *PSDRV_PPDGetWord(char *str, char **next)
+{
+    char *start, *end, *ret;
+
+    start = str;
+    while(start && *start && isspace(*start))
+        start++;
+    if(!start || !*start) return FALSE;
+
+    end = start;
+    while(*end && !isspace(*end))
+        end++;
+
+    ret = HeapAlloc( PSDRV_Heap, 0, end - start + 1 );
+    memcpy(ret, start, end - start );
+    *(ret + (end - start)) = '\0';
+
+    while(*end && isspace(*end))
+        end++;
+    if(*end)
+        *next = end;
+    else
+        *next = NULL;
+
+    return ret;
+}
+
+/***********************************************************************
+ *
+ *		PSDRV_ParsePPD
+ *
+ *
+ */
+PPD *PSDRV_ParsePPD(char *fname)
+{
+    FILE *fp;
+    PPD *ppd;
+    PPDTuple tuple;
+
+    TRACE(psdrv, "%s\n", fname);
+
+    if((fp = fopen(fname, "r")) == NULL)
+        return NULL;
+
+    ppd = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*ppd));
+    if(!ppd) {
+        ERR(psdrv, "Unable to allocate memory for ppd\n");
+	fclose(fp);
+	return NULL;
+    }
+
+    
+    while( PSDRV_PPDGetNextTuple(fp, &tuple)) {
+
+	if(!strcmp("*NickName", tuple.key)) {
+	    ppd->NickName = tuple.value;
+	    tuple.value = NULL;
+	    TRACE(psdrv, "NickName = '%s'\n", ppd->NickName);
+	}
+
+	else if(!strcmp("*LanguageLevel", tuple.key)) {
+	    sscanf(tuple.value, "%d", &(ppd->LanguageLevel));
+	    TRACE(psdrv, "LanguageLevel = %d\n", ppd->LanguageLevel);
+	}
+
+	else if(!strcmp("*ColorDevice", tuple.key)) {
+	    if(!strcasecmp(tuple.value, "true"))
+	        ppd->ColorDevice = TRUE;
+	    TRACE(psdrv, "ColorDevice = %d\n", (int)ppd->ColorDevice);
+	}
+
+	else if(!strcmp("*DefaultResolution", tuple.key)) {
+	    sscanf(tuple.value, "%d", &(ppd->DefaultResolution));
+	    TRACE(psdrv, "DefaultResolution = %d\n", ppd->DefaultResolution);
+	}
+
+	else if(!strcmp("*Font", tuple.key)) {
+	    FONTNAME *fn;
+
+	    for(fn = ppd->InstalledFonts; fn && fn->next; fn = fn->next)
+	        ;
+	    if(!fn) {
+	        ppd->InstalledFonts = HeapAlloc(PSDRV_Heap,
+					       HEAP_ZERO_MEMORY, sizeof(*fn));
+		fn = ppd->InstalledFonts;
+	    } else {
+	       fn->next = HeapAlloc(PSDRV_Heap,
+					       HEAP_ZERO_MEMORY, sizeof(*fn));
+	       fn = fn->next;
+	    }
+	    fn->Name = tuple.option;
+	    tuple.option = NULL;
+	}
+
+	else if(!strcmp("*DefaultFont", tuple.key)) {
+	    ppd->DefaultFont = tuple.value;
+	    tuple.value = NULL;
+	}
+
+	else if(!strcmp("*JCLBegin", tuple.key)) {
+	    ppd->JCLBegin = tuple.value;
+	    tuple.value = NULL;
+	}
+
+	else if(!strcmp("*JCLToPSInterpreter", tuple.key)) {
+	    ppd->JCLToPSInterpreter = tuple.value;
+	    tuple.value = NULL;
+	}
+
+	else if(!strcmp("*JCLEnd", tuple.key)) {
+	    ppd->JCLEnd = tuple.value;
+	    tuple.value = NULL;
+	}
+
+	else if(!strcmp("*PageSize", tuple.key)) {
+	    PAGESIZE *page;
+	    page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
+
+	    if(!page->Name) {
+	        int i;
+
+	        page->Name = tuple.option;
+		tuple.option = NULL;
+		
+		for(i = 0; PageTrans[i].PSName; i++) {
+		    if(!strcmp(PageTrans[i].PSName, page->Name)) { /* case ? */
+		        page->WinPage = PageTrans[i].WinPage;
+			break;
+		    }
+		}
+		if(!page->WinPage)
+		    FIXME(psdrv, "Can't find Windows page type for '%s'\n",
+			  page->Name);
+	    }
+	    if(!page->FullName) {
+		page->FullName = tuple.opttrans;
+		tuple.opttrans = NULL;
+	    }
+	    if(!page->InvocationString) {
+		page->InvocationString = tuple.value;
+	        tuple.value = NULL;
+	    }
+	}
+
+	else if(!strcmp("*ImageableArea", tuple.key)) {
+	    PAGESIZE *page;
+	    page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
+	    
+	    if(!page->Name) {
+	        page->Name = tuple.option;
+		tuple.option = NULL;
+	    }
+	    if(!page->FullName) {
+		page->FullName = tuple.opttrans;
+		tuple.opttrans = NULL;
+	    }
+
+#define PIA page->ImageableArea
+	    if(!PIA) {
+ 	        PIA = HeapAlloc( PSDRV_Heap, 0, sizeof(*PIA) );
+		sscanf(tuple.value, "%f%f%f%f", &PIA->llx, &PIA->lly,
+						&PIA->urx, &PIA->ury);
+	    }
+#undef PIA
+	}
+
+
+	else if(!strcmp("*PaperDimension", tuple.key)) {
+	    PAGESIZE *page;
+	    page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
+	    
+	    if(!page->Name) {
+	        page->Name = tuple.option;
+		tuple.option = NULL;
+	    }
+	    if(!page->FullName) {
+		page->FullName = tuple.opttrans;
+		tuple.opttrans = NULL;
+	    }
+
+#define PD page->PaperDimension
+	    if(!PD) {
+ 	        PD = HeapAlloc( PSDRV_Heap, 0, sizeof(*PD) );
+		sscanf(tuple.value, "%f%f", &PD->x, &PD->y);
+	    }
+#undef PD
+	}
+
+	else if(!strcmp("*LandscapeOrientation", tuple.key)) {
+	    if(!strcmp(tuple.value, "Plus90"))
+	        ppd->LandscapeOrientation = 90;
+	    else if(!strcmp(tuple.value, "Minus90"))
+	        ppd->LandscapeOrientation = 270;
+
+	    /* anything else, namely 'any', leaves value at 0 */
+
+	    TRACE(psdrv, "LandscapeOrientation = %d\n", 
+		  ppd->LandscapeOrientation);
+	}
+	
+	else if(!strcmp("*UIConstraints", tuple.key)) {
+	    char *start;
+	    CONSTRAINT *con, **insert = &ppd->Constraints;
+
+	    while(*insert)
+	        insert = &((*insert)->next);
+	    
+	    con = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
+				       sizeof(*con) );
+
+	    start = tuple.value;
+	    
+	    con->Feature1 = PSDRV_PPDGetWord(start, &start);
+	    con->Value1 = PSDRV_PPDGetWord(start, &start);
+	    con->Feature2 = PSDRV_PPDGetWord(start, &start);
+	    con->Value2 = PSDRV_PPDGetWord(start, &start);
+	}
+	    
+	else if(!strcmp("*InputSlot", tuple.key)) {
+	    INPUTSLOT *slot, **insert = &ppd->InputSlots;
+	    int i;
+
+	    while(*insert)
+	        insert = &((*insert)->next);
+
+	    slot = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
+				    sizeof(*slot) );
+
+	    slot->Name = tuple.option;
+	    tuple.option = NULL;
+	    if(tuple.opttrans) {
+	        slot->FullName = tuple.opttrans;
+		tuple.opttrans = NULL;
+	    }
+	    if(tuple.value) {
+	        slot->InvocationString = tuple.value;
+		tuple.value = NULL;
+	    }
+
+	    
+	    for(i = 0; BinTrans[i].PSName; i++) {
+	        if(!strcmp(BinTrans[i].PSName, slot->Name)) { /* case ? */
+		    slot->WinBin = BinTrans[i].WinBin;
+		    break;
+		}
+	    }
+	    if(!slot->WinBin)
+	        FIXME(psdrv, "Can't find Windows bin type for '%s'\n",
+			  slot->Name);
+
+	}   
+
+	if(tuple.key) HeapFree(PSDRV_Heap, 0, tuple.key);
+	if(tuple.option) HeapFree(PSDRV_Heap, 0, tuple.option);
+	if(tuple.value) HeapFree(PSDRV_Heap, 0, tuple.value);
+	if(tuple.opttrans) HeapFree(PSDRV_Heap, 0, tuple.opttrans);
+	if(tuple.valtrans) HeapFree(PSDRV_Heap, 0, tuple.valtrans);    
+	
+    }
+
+
+    {
+        FONTNAME *fn;
+	PAGESIZE *page;
+	CONSTRAINT *con;
+	INPUTSLOT *slot;
+
+	for(fn = ppd->InstalledFonts; fn; fn = fn->next)
+	    TRACE(psdrv, "'%s'\n", fn->Name);
+	
+	for(page = ppd->PageSizes; page; page = page->next) {
+	    TRACE(psdrv, "'%s' aka '%s' (%d) invoked by '%s'\n", page->Name,
+	      page->FullName, page->WinPage, page->InvocationString);
+	    if(page->ImageableArea)
+	        TRACE(psdrv, "Area = %.2f,%.2f - %.2f, %.2f\n", 
+		      page->ImageableArea->llx, page->ImageableArea->lly,
+		      page->ImageableArea->urx, page->ImageableArea->ury);
+	    if(page->PaperDimension)
+	        TRACE(psdrv, "Dimension = %.2f x %.2f\n", 
+		      page->PaperDimension->x, page->PaperDimension->y);
+	}
+
+	for(con = ppd->Constraints; con; con = con->next)
+	    TRACE(psdrv, "%s %s %s %s\n", con->Feature1, con->Value1,
+		  con->Feature2, con->Value2);
+
+	for(slot = ppd->InputSlots; slot; slot = slot->next)
+	    TRACE(psdrv, "Slot '%s' Name '%s' (%d) Invocation '%s'\n",
+		  slot->Name, slot->FullName, slot->WinBin, 
+		  slot->InvocationString);
+    }
+
+    return ppd;
+}
+
diff --git a/graphics/psdrv/ps.c b/graphics/psdrv/ps.c
index c544d17..0893ee6 100644
--- a/graphics/psdrv/ps.c
+++ b/graphics/psdrv/ps.c
@@ -1,20 +1,21 @@
 /*
- *	Postscript output functions
+ *	PostScript output functions
  *
  *	Copyright 1998  Huw D M Davies
  *
  */
 
-#include "windows.h"
-#include "psdrv.h"
-#include "print.h"
-#include "debug.h"
+#include <windows.h>
+#include <psdrv.h>
+#include <print.h>
+#include <debug.h>
+#include <ctype.h>
 
-char psheader[] = /* title */
+char psheader[] = /* title llx lly urx ury */
 "%%!PS-Adobe-3.0 (not quite)\n"
-"%%%%Creator: Wine Postscript Driver\n"
+"%%%%Creator: Wine PostScript Driver\n"
 "%%%%Title: %s\n"
-"%%%%BoundingBox: 0 0 595 842\n"
+"%%%%BoundingBox: %d %d %d %d\n"
 "%%%%Pages: (atend)\n"
 "%%%%EndComments\n"
 "%%%%BeginProlog\n"
@@ -27,9 +28,21 @@
 "end\n"
 "definefont pop\n"
 "} bind def\n"
-"%%%%EndProlog\n"
-"%%%%BeginSetup\n"
-"%%%%EndSetup\n";
+"%%%%EndProlog\n";
+
+char psbeginsetup[] =
+"%%BeginSetup\n";
+
+char psendsetup[] =
+"%%EndSetup\n";
+
+char psbeginfeature[] = /* feature, value */
+"mark {\n"
+"%%%%BeginFeature: %s %s\n";
+
+char psendfeature[] =
+"\n%%EndFeature\n"
+"} stopped cleartomark\n";
 
 char psnewpage[] = /* name, number */
 "%%%%Page: %s %d\n"
@@ -73,7 +86,7 @@
 
 char pssetfont[] = /* fontname, xscale, yscale, ascent, escapement */
 "/%s findfont\n"
-"[%d 0 0 %d 0 %d]\n"
+"[%d 0 0 %d 0 0]\n"
 "%d 10 div matrix rotate\n"
 "matrix concatmatrix\n"
 "makefont setfont\n";
@@ -96,13 +109,35 @@
 }
 
 
+INT32 PSDRV_WriteFeature(HANDLE16 hJob, char *feature, char *value,
+			 char *invocation)
+{
+
+    char *buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psheader) +
+			     strlen(feature) + strlen(value));
+
+
+    wsprintf32A(buf, psbeginfeature, feature, value);
+    WriteSpool( hJob, buf, strlen(buf) );
+
+    WriteSpool( hJob, invocation, strlen(invocation) );
+
+    WriteSpool( hJob, psendfeature, strlen(psendfeature) );
+    
+    HeapFree( PSDRV_Heap, 0, buf );
+    return 1;
+}
+
+
+
 INT32 PSDRV_WriteHeader( DC *dc, char *title, int len )
 {
     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
     char *buf, *titlebuf;
+    INPUTSLOT *slot;
+    PAGESIZE *page;
 
-
-    titlebuf = (char *)HeapAlloc( GetProcessHeap(), 0, len+1 );
+    titlebuf = (char *)HeapAlloc( PSDRV_Heap, 0, len+1 );
     if(!titlebuf) {
         WARN(psdrv, "HeapAlloc failed\n");
         return 0;
@@ -110,24 +145,54 @@
     memcpy(titlebuf, title, len);
     titlebuf[len] = '\0';
 
-    buf = (char *)HeapAlloc( GetProcessHeap(), 0, sizeof(psheader) + len);
+    buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psheader) + len + 20);
     if(!buf) {
         WARN(psdrv, "HeapAlloc failed\n");
-	HeapFree( GetProcessHeap(), 0, titlebuf );
+	HeapFree( PSDRV_Heap, 0, titlebuf );
         return 0;
     }
 
-    wsprintf32A(buf, psheader, title);
+    wsprintf32A(buf, psheader, title, 0, 0, 
+		(int) (dc->w.devCaps->horzSize * 72.0 / 25.4),
+		(int) (dc->w.devCaps->vertSize * 72.0 / 25.4) );
 
     if( WriteSpool( physDev->job.hJob, buf, strlen(buf) ) != 
 	                                             strlen(buf) ) {
         WARN(psdrv, "WriteSpool error\n");
-	HeapFree( GetProcessHeap(), 0, titlebuf );
-	HeapFree( GetProcessHeap(), 0, buf );
+	HeapFree( PSDRV_Heap, 0, titlebuf );
+	HeapFree( PSDRV_Heap, 0, buf );
 	return 0;
     }
-    HeapFree( GetProcessHeap(), 0, titlebuf );
-    HeapFree( GetProcessHeap(), 0, buf );
+    HeapFree( PSDRV_Heap, 0, titlebuf );
+    HeapFree( PSDRV_Heap, 0, buf );
+
+
+    WriteSpool( physDev->job.hJob, psbeginsetup, strlen(psbeginsetup) );
+
+    for(slot = physDev->pi->ppd->InputSlots; slot; slot = slot->next) {
+        if(slot->WinBin == physDev->Devmode->dmPublic.dmDefaultSource) {
+	    if(slot->InvocationString) {
+	        PSDRV_WriteFeature(physDev->job.hJob, "*InputSlot", slot->Name,
+			     slot->InvocationString);
+		break;
+	    }
+	}
+    }
+
+    for(page = physDev->pi->ppd->PageSizes; page; page = page->next) {
+        if(page->WinPage == physDev->Devmode->dmPublic.dmPaperSize) {
+	    if(page->InvocationString) {
+	        PSDRV_WriteFeature(physDev->job.hJob, "*PageSize", page->Name,
+			     page->InvocationString);
+		break;
+	    }
+	}
+    }
+
+
+    WriteSpool( physDev->job.hJob, psendsetup, strlen(psendsetup) );
+
+
     return 1;
 }
 
@@ -137,7 +202,7 @@
     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
     char *buf;
 
-    buf = (char *)HeapAlloc( GetProcessHeap(), 0, sizeof(psfooter) + 100 );
+    buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psfooter) + 100 );
     if(!buf) {
         WARN(psdrv, "HeapAlloc failed\n");
         return 0;
@@ -148,10 +213,10 @@
     if( WriteSpool( physDev->job.hJob, buf, strlen(buf) ) != 
 	                                             strlen(buf) ) {
         WARN(psdrv, "WriteSpool error\n");
-	HeapFree( GetProcessHeap(), 0, buf );
+	HeapFree( PSDRV_Heap, 0, buf );
 	return 0;
     }
-    HeapFree( GetProcessHeap(), 0, buf );
+    HeapFree( PSDRV_Heap, 0, buf );
     return 1;
 }
 
@@ -180,7 +245,7 @@
     
     wsprintf32A(name, "%d", physDev->job.PageNo);
 
-    buf = (char *)HeapAlloc( GetProcessHeap(), 0, sizeof(psnewpage) + 100 );
+    buf = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psnewpage) + 100 );
     if(!buf) {
         WARN(psdrv, "HeapAlloc failed\n");
         return 0;
@@ -190,10 +255,10 @@
     if( WriteSpool( physDev->job.hJob, buf, strlen(buf) ) != 
 	                                             strlen(buf) ) {
         WARN(psdrv, "WriteSpool error\n");
-	HeapFree( GetProcessHeap(), 0, buf );
+	HeapFree( PSDRV_Heap, 0, buf );
 	return 0;
     }
-    HeapFree( GetProcessHeap(), 0, buf );
+    HeapFree( PSDRV_Heap, 0, buf );
     return 1;
 }
 
@@ -238,7 +303,7 @@
     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
     char *buf, *newbuf;
 
-    buf = (char *)HeapAlloc( GetProcessHeap(), 0,
+    buf = (char *)HeapAlloc( PSDRV_Heap, 0,
 	     sizeof(pssetfont) + strlen(physDev->font.afm->FontName) + 40);
 
     if(!buf) {
@@ -246,23 +311,23 @@
         return FALSE;
     }
 
-    newbuf = (char *)HeapAlloc( GetProcessHeap(), 0,
+    newbuf = (char *)HeapAlloc( PSDRV_Heap, 0,
 	      strlen(physDev->font.afm->FontName) + sizeof(encodingext));
 
     if(!newbuf) {
         WARN(psdrv, "HeapAlloc failed\n");
-	HeapFree(GetProcessHeap(), 0, buf);
+	HeapFree(PSDRV_Heap, 0, buf);
         return FALSE;
     }
 
     wsprintf32A(newbuf, "%s%s", physDev->font.afm->FontName, encodingext);
 
     wsprintf32A(buf, pssetfont, newbuf, 
-		physDev->font.tm.tmHeight, -physDev->font.tm.tmHeight,
-		physDev->font.tm.tmAscent, -physDev->font.escapement);
+		physDev->font.size, -physDev->font.size,
+	        -physDev->font.escapement);
 
     PSDRV_WriteSpool(dc, buf, strlen(buf));
-    HeapFree(GetProcessHeap(), 0, buf);
+    HeapFree(PSDRV_Heap, 0, buf);
     return TRUE;
 }    
 
@@ -271,7 +336,7 @@
     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
     char *buf, *newbuf;
  
-    buf = (char *)HeapAlloc( GetProcessHeap(), 0,
+    buf = (char *)HeapAlloc( PSDRV_Heap, 0,
 	     sizeof(psreencodefont) + 2 * strlen(physDev->font.afm->FontName) 
 			     + sizeof(encodingext));
 
@@ -280,12 +345,12 @@
         return FALSE;
     }
 
-    newbuf = (char *)HeapAlloc( GetProcessHeap(), 0,
+    newbuf = (char *)HeapAlloc( PSDRV_Heap, 0,
 	      strlen(physDev->font.afm->FontName) + sizeof(encodingext));
 
     if(!newbuf) {
         WARN(psdrv, "HeapAlloc failed\n");
-	HeapFree(GetProcessHeap(), 0, buf);
+	HeapFree(PSDRV_Heap, 0, buf);
         return FALSE;
     }
 
@@ -294,26 +359,45 @@
 
     PSDRV_WriteSpool(dc, buf, strlen(buf));
 
-    HeapFree(GetProcessHeap(), 0, newbuf);
-    HeapFree(GetProcessHeap(), 0, buf);
+    HeapFree(PSDRV_Heap, 0, newbuf);
+    HeapFree(PSDRV_Heap, 0, buf);
     return TRUE;
 }    
 
 BOOL32 PSDRV_WriteShow(DC *dc, char *str, INT32 count)
 {
-    char *buf;
+    char *buf, *buf1;
+    INT32 buflen = count + 10, i, done;
 
-    buf = (char *)HeapAlloc( GetProcessHeap(), 0, sizeof(psshow) + count);
-
-    if(!buf) {
-        WARN(psdrv, "HeapAlloc failed\n");
-        return FALSE;
+    buf = (char *)HeapAlloc( PSDRV_Heap, 0, buflen );
+    
+    for(i = done = 0; i < count; i++) {
+        if(!isprint(str[i])) {
+	    if(done + 4 >= buflen)
+	        buf = HeapReAlloc( PSDRV_Heap, 0, buf, buflen += 10 );
+	    sprintf(buf + done, "\\%03o", (int)(unsigned char)str[i] );
+	    done += 4;
+	} else if(str[i] == '\\' || str[i] == '(' || str[i] == ')' ) {
+	    if(done + 2 >= buflen)
+	        buf = HeapReAlloc( PSDRV_Heap, 0, buf, buflen += 10 );
+	    buf[done++] = '\\';
+	    buf[done++] = str[i];
+	} else {
+	    if(done + 1 >= buflen)
+	        buf = HeapReAlloc( PSDRV_Heap, 0, buf, buflen += 10 );
+	    buf[done++] = str[i];
+	}
     }
+    buf[done] = '\0';
 
-    wsprintf32A(buf, psshow, str);
+    buf1 = (char *)HeapAlloc( PSDRV_Heap, 0, sizeof(psshow) + done);
 
-    PSDRV_WriteSpool(dc, buf, strlen(buf));
-    HeapFree(GetProcessHeap(), 0, buf);
+    wsprintf32A(buf1, psshow, buf);
+
+    PSDRV_WriteSpool(dc, buf1, strlen(buf1));
+    HeapFree(PSDRV_Heap, 0, buf);
+    HeapFree(PSDRV_Heap, 0, buf1);
+
     return TRUE;
 }    
 
diff --git a/graphics/psdrv/text.c b/graphics/psdrv/text.c
index f886b75..a8207b7 100644
--- a/graphics/psdrv/text.c
+++ b/graphics/psdrv/text.c
@@ -1,5 +1,5 @@
 /*
- *	Postscript driver text functions
+ *	PostScript driver text functions
  *
  *	Copyright 1998  Huw D M Davies
  *
@@ -24,7 +24,7 @@
     TRACE(psdrv, "(x=%d, y=%d, flags=0x%08x, str='%s', count=%d)\n", x, y,
 	  flags, str, count);
 
-    strbuf = (char *)HeapAlloc( GetProcessHeap(), 0, count + 1);
+    strbuf = (char *)HeapAlloc( PSDRV_Heap, 0, count + 1);
     if(!strbuf) {
         WARN(psdrv, "HeapAlloc failed\n");
         return FALSE;
@@ -61,14 +61,14 @@
 
     switch(dc->w.textAlign & (TA_TOP | TA_BASELINE | TA_BOTTOM) ) {
     case TA_TOP:
+        y += physDev->font.tm.tmAscent;
 	break;
 
     case TA_BASELINE:
-	y -= physDev->font.tm.tmAscent;
 	break;
 
     case TA_BOTTOM:
-        y -= sz.cy;
+        y -= physDev->font.tm.tmDescent;
 	break;
     }
 
@@ -80,6 +80,6 @@
     PSDRV_WriteMoveTo(dc, x, y);
     PSDRV_WriteShow(dc, strbuf, strlen(strbuf));
 
-    HeapFree(GetProcessHeap(), 0, strbuf);
+    HeapFree(PSDRV_Heap, 0, strbuf);
     return TRUE;
 }
diff --git a/graphics/win16drv/init.c b/graphics/win16drv/init.c
index e0f9699..053a2f3 100644
--- a/graphics/win16drv/init.c
+++ b/graphics/win16drv/init.c
@@ -613,7 +613,8 @@
 	    memset(pPrintJob, 0, sizeof(PRINTJOB));
 
 	    pPrintJob->pszOutput = strdup(lpOutput);
-	    pPrintJob->pszTitle = strdup(lpTitle);
+	    if(lpTitle)
+	        pPrintJob->pszTitle = strdup(lpTitle);
 	    pPrintJob->hDC = hDC;
 	    pPrintJob->fd = fd;
 	    pPrintJob->nIndex = 0;
diff --git a/graphics/x11drv/xfont.c b/graphics/x11drv/xfont.c
index 7120689..27c5009 100644
--- a/graphics/x11drv/xfont.c
+++ b/graphics/x11drv/xfont.c
@@ -165,7 +165,7 @@
 #undef ptr
    i = 0;
 #define ptr ((CHAR*)plf)
-   do { font[i++] = tolower(*ptr); } while (*ptr++);
+   do { font[i++] = tolower(*ptr++); } while (( i < LF_FACESIZE) && (*ptr) && (*ptr!=' '));
    for( ptr = font, i >>= 1; i > 0; i-- ) 
 #undef ptr
 #define ptr ((UINT16*)plf)
@@ -2240,6 +2240,7 @@
     }
     else
 	for( ; pfr ; pfr = pfr->next )
+          if(pfr->fi)
 	    if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
 		       XFONT_GetFontMetric( pfr->fi, &lf, &tm ), lp )) )
 		 bRet = b;
diff --git a/if1632/kernel.spec b/if1632/kernel.spec
index 918f129..52bcd9a 100644
--- a/if1632/kernel.spec
+++ b/if1632/kernel.spec
@@ -44,7 +44,7 @@
 42  return DisableDos 0 0
 45  pascal16 LoadModule(str ptr) LoadModule16
 46  pascal16 FreeModule(word) FreeModule16
-47  pascal16 GetModuleHandle(segstr) WIN16_GetModuleHandle
+47  pascal   GetModuleHandle(segstr) WIN16_GetModuleHandle
 48  pascal16 GetModuleUsage(word) GetModuleUsage
 49  pascal16 GetModuleFileName(word ptr s_word) GetModuleFileName16
 50  pascal GetProcAddress(word segstr) GetProcAddress16
@@ -309,7 +309,7 @@
 445 stub KERNEL_445
 446 stub KERNEL_446
 447 stub KERNEL_447
-449 pascal KERNEL_449() KERNEL_449
+449 pascal GetpWin16Lock() GetpWin16Lock16
 450 pascal16 KERNEL_450() stub_KERNEL_450
 452 stub KERNEL_452
 453 stub KERNEL_453
diff --git a/if1632/msvideo.spec b/if1632/msvideo.spec
index f3b6e1a..9c30f5f 100644
--- a/if1632/msvideo.spec
+++ b/if1632/msvideo.spec
@@ -1,7 +1,7 @@
 name msvideo
 type win16
 
-2 stub VIDEOFORWINDOWSVERSION
+2 pascal VideoForWindowsVersion() VideoForWindowsVersion
 20 stub VIDEOGETNUMDEVS
 21 stub VIDEOGETERRORTEXT
 22 stub VIDEOCAPDRIVERDESCANDVER
diff --git a/if1632/relay.c b/if1632/relay.c
index cc904e3..ca9f6bb 100644
--- a/if1632/relay.c
+++ b/if1632/relay.c
@@ -270,10 +270,10 @@
 	}
         DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(thdb->cur_stack),
                 OFFSETOF(thdb->cur_stack) );
-        DPRINTF("     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x\n",
+        DPRINTF("     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x FS=%04x\n",
                 AX_reg(context), BX_reg(context), CX_reg(context),
                 DX_reg(context), SI_reg(context), DI_reg(context),
-                BP_reg(context), (WORD)ES_reg(context) );
+                BP_reg(context), (WORD)ES_reg(context), (WORD)FS_reg(context) );
     }
     else
     {
@@ -291,6 +291,21 @@
 }
 
 
+/***********************************************************************
+ *           RELAY_DebugCallTo16Ret
+ */
+void RELAY_DebugCallTo16Ret( int ret_val )
+{
+    THDB *thdb;
+
+    if (!TRACE_ON(relay)) return;
+    thdb = THREAD_Current();
+
+    DPRINTF("CallTo16() ss:sp=%04x:%04x retval=0x%08x\n", 
+            SELECTOROF(thdb->cur_stack), OFFSETOF(thdb->cur_stack), ret_val);
+}
+
+
 /**********************************************************************
  *	     Catch    (KERNEL.55)
  *
diff --git a/if1632/thunk.c b/if1632/thunk.c
index 01794ab..83f5d87 100644
--- a/if1632/thunk.c
+++ b/if1632/thunk.c
@@ -250,7 +250,8 @@
     THDB *thdb = THREAD_Current();
 
     /* Window procedures want ax = hInstance, ds = es = ss */
-
+    
+    memset(&context, '\0', sizeof(context));
     DS_reg(&context)  = SELECTOROF(thdb->cur_stack);
     ES_reg(&context)  = DS_reg(&context);
     EAX_reg(&context) = wndPtr ? wndPtr->hInstance : DS_reg(&context);
@@ -892,8 +893,6 @@
             CS_reg(context) = stack[3];
             SP_reg(context) += td->apiDB[targetNr].nrArgBytes + 4;
 
-            /* Win95 allows delayed loading of the 32-bit DLL.
-               We don't do that at the moment. */
             ERR(thunk, "Process %08lx did not ThunkConnect32 %s to %s\n",
                        (DWORD)PROCESS_Current(), td->pszDll32, td->pszDll16);
         }
diff --git a/if1632/wineps.spec b/if1632/wineps.spec
index a02aca2..4ede174 100644
--- a/if1632/wineps.spec
+++ b/if1632/wineps.spec
@@ -4,4 +4,4 @@
 13 pascal16 DeviceMode(word word str str) PSDRV_DeviceMode16
 90 pascal16 ExtDeviceMode(word word ptr str str ptr str word) PSDRV_ExtDeviceMode16
 91 pascal DeviceCapabilities(str str word ptr ptr) PSDRV_DeviceCapabilities16
-
+93 pascal16 AdvancedSetupDialog(word word ptr ptr) PSDRV_AdvancedSetupDialog16
diff --git a/include/builtin32.h b/include/builtin32.h
index 05cf106..398846c 100644
--- a/include/builtin32.h
+++ b/include/builtin32.h
@@ -20,6 +20,7 @@
     const unsigned short *ordinals;     /* Pointer to ordinals table */
     const unsigned char  *args;         /* Pointer to argument lengths */
     const unsigned int   *argtypes;     /* Pointer to argument types bitmask */
+    const ENTRYPOINT32    dllentrypoint;/* Pointer to LibMain function */
 } BUILTIN32_DESCRIPTOR;
 
 extern ENTRYPOINT32 BUILTIN32_GetEntryPoint( char *buffer, void *relay,
diff --git a/include/commctrl.h b/include/commctrl.h
index d4e765c..04f29ff 100644
--- a/include/commctrl.h
+++ b/include/commctrl.h
@@ -6,6 +6,7 @@
 #define __WINE_COMMCTRL_H
 
 #include "windows.h"
+#include "imagelist.h"
 
 BOOL32 WINAPI ShowHideMenuCtl (HWND32, UINT32, LPINT32);
 VOID WINAPI GetEffectiveClientRect (HWND32, LPRECT32, LPINT32);
@@ -92,6 +93,13 @@
 #define ODT_TAB         101
 #define ODT_LISTVIEW    102
 
+/* common notification structures */
+typedef struct tagNMTOOLTIPSCREATED
+{
+    NMHDR  hdr;
+    HWND32 hwndToolTips;
+} NMTOOLTIPSCREATED, *LPNMTOOLTIPSCREATED;
+
 
 /* StatusWindow */
 
@@ -118,12 +126,19 @@
 #define SB_GETRECT            (WM_USER+10)
 #define SB_ISSIMPLE           (WM_USER+14)
 #define SB_SETICON            (WM_USER+15)
+#define SB_SETTIPTEXT32A      (WM_USER+16)
+#define SB_SETTIPTEXT32W      (WM_USER+17)
+#define SB_SETTIPTEXT WINELIB_NAME_AW(SB_SETTIPTEXT)
+#define SB_GETTIPTEXT32A      (WM_USER+18)
+#define SB_GETTIPTEXT32W      (WM_USER+19)
+#define SB_GETTIPTEXT WINELIB_NAME_AW(SB_GETTIPTEXT)
 #define SB_GETICON            (WM_USER+20)
 #define SB_SETBKCOLOR         CCM_SETBKCOLOR   /* lParam = bkColor */
 
 #define SBT_NOBORDERS         0x0100
 #define SBT_POPOUT            0x0200
 #define SBT_RTLREADING        0x0400  /* not supported */
+#define SBT_TOOLTIPS          0x0800
 #define SBT_OWNERDRAW         0x1000
 
 #define SBARS_SIZEGRIP        0x0100
@@ -132,7 +147,14 @@
 #define SBN_LAST              (0U-899U)
 #define SBN_SIMPLEMODECHANGE  (SBN_FIRST-0)
 
-void WINAPI MenuHelp (UINT32, WPARAM32, LPARAM, HMENU32,
+
+HWND32 WINAPI CreateStatusWindow32A (INT32, LPCSTR, HWND32, UINT32);
+HWND32 WINAPI CreateStatusWindow32W (INT32, LPCWSTR, HWND32, UINT32);
+#define    CreateStatusWindow WINELIB_NAME_AW(CreateStatusWindow)
+VOID WINAPI DrawStatusText32A (HDC32, LPRECT32, LPCSTR, UINT32);
+VOID WINAPI DrawStatusText32W (HDC32, LPRECT32, LPCWSTR, UINT32);
+#define    DrawStatusText WINELIB_NAME_AW(DrawStatusText)
+VOID WINAPI MenuHelp (UINT32, WPARAM32, LPARAM, HMENU32,
                       HINSTANCE32, HWND32, LPUINT32);
 
 
@@ -145,8 +167,8 @@
 
 typedef struct tagUDACCEL
 {
-  UINT32 nSec;
-  UINT32 nInc;
+    UINT32 nSec;
+    UINT32 nInc;
 } UDACCEL;
 
 #define UD_MAXVAL          0x7fff
@@ -177,13 +199,15 @@
 #define UDM_SETRANGE32     (WM_USER+111)
 #define UDM_GETRANGE32     (WM_USER+112)
 
+HWND32 WINAPI CreateUpDownControl (DWORD, INT32, INT32, INT32, INT32,
+                                   HWND32, INT32, HINSTANCE32, HWND32,
+                                   INT32, INT32, INT32);
 
 /* Progress Bar */
 
 #define PROGRESS_CLASS32A   "msctls_progress32"
 #define PROGRESS_CLASS32W  L"msctls_progress32"
 #define PROGRESS_CLASS16    "msctls_progress"
-
 #define PROGRESS_CLASS      WINELIB_NAME_AW(PROGRESS_CLASS)
 
 #define PBM_SETRANGE        (WM_USER+1)
@@ -206,27 +230,14 @@
   INT32 iHigh;
 } PBRANGE, *PPBRANGE;
 
- 
-/* Functions prototypes */
-
-HWND32     WINAPI CreateStatusWindow32A(INT32,LPCSTR,HWND32,UINT32);
-HWND32     WINAPI CreateStatusWindow32W(INT32,LPCWSTR,HWND32,UINT32);
-#define    CreateStatusWindow WINELIB_NAME_AW(CreateStatusWindow)
-HWND32     WINAPI CreateUpDownControl(DWORD,INT32,INT32,INT32,INT32,
-                                      HWND32,INT32,HINSTANCE32,HWND32,
-                                      INT32,INT32,INT32);
-VOID       WINAPI DrawStatusText32A(HDC32,LPRECT32,LPCSTR,UINT32);
-VOID       WINAPI DrawStatusText32W(HDC32,LPRECT32,LPCWSTR,UINT32);
-#define    DrawStatusText WINELIB_NAME_AW(DrawStatusText)
-
 
 /* ImageList */
-
+/*
 #if defined(__WINE__) && defined(__WINE_IMAGELIST_C)
 #else
 struct _IMAGELIST;
 typedef struct _IMAGELIST *HIMAGELIST;
-#endif  /* __WINE__ */
+#endif*/  /* __WINE__ */
 
 #define CLR_NONE         0xFFFFFFFF
 #define CLR_DEFAULT      0xFF000000
@@ -545,7 +556,24 @@
 #define TBSTYLE_FLAT            0x0800 
 #define TBSTYLE_LIST            0x1000 
 #define TBSTYLE_CUSTOMERASE     0x2000 
+
+#define TBIF_IMAGE              0x00000001
+#define TBIF_TEXT               0x00000002
+#define TBIF_STATE              0x00000004
+#define TBIF_STYLE              0x00000008
+#define TBIF_LPARAM             0x00000010
+#define TBIF_COMMAND            0x00000020
+#define TBIF_SIZE               0x00000040
  
+#define TBN_FIRST               (0U-700U)
+#define TBN_LAST                (0U-720U)
+#define TBN_GETBUTTONINFO32A    (TBN_FIRST-0)
+#define TBN_GETBUTTONINFO32W    (TBN_FIRST-20)
+
+#define TBN_GETINFOTIP32A       (TBN_FIRST-18)
+#define TBN_GETINFOTIP32W       (TBN_FIRST-19)
+
+
 #define TB_ENABLEBUTTON          (WM_USER+1)
 #define TB_CHECKBUTTON           (WM_USER+2)
 #define TB_PRESSBUTTON           (WM_USER+3)
@@ -612,6 +640,12 @@
 #define TB_SETMAXTEXTROWS        (WM_USER+60)
 #define TB_GETTEXTROWS           (WM_USER+61)
 #define TB_GETOBJECT             (WM_USER+62)
+#define TB_GETBUTTONINFO32W      (WM_USER+63)
+#define TB_GETBUTTONINFO32A      (WM_USER+65)
+#define TB_GETBUTTONINFO WINELIB_NAME_AW(TB_GETBUTTONINFO)
+#define TB_SETBUTTONINFO32W      (WM_USER+64)
+#define TB_SETBUTTONINFO32A      (WM_USER+66)
+#define TB_SETBUTTONINFO WINELIB_NAME_AW(TB_SETBUTTONINFO)
 #define TB_SETDRAWTEXTFLAGS      (WM_USER+70)
 #define TB_GETHOTITEM            (WM_USER+71)
 #define TB_SETHOTITEM            (WM_USER+72)
@@ -692,6 +726,58 @@
 #define TBSAVEPARAMS   WINELIB_NAMEAW(TBSAVEPARAMS)
 #define LPTBSAVEPARAMS WINELIB_NAMEAW(LPTBSAVEPARAMS)
 
+typedef struct
+{
+    UINT32 cbSize;
+    DWORD  dwMask;
+    INT32  idCommand;
+    INT32  iImage;
+    BYTE   fsState;
+    BYTE   fsStyle;
+    WORD   cx;
+    DWORD  lParam;
+    LPSTR  pszText;
+    INT32  cchText;
+} TBBUTTONINFO32A, *LPTBBUTTONINFO32A;
+
+typedef struct
+{
+    UINT32 cbSize;
+    DWORD  dwMask;
+    INT32  idCommand;
+    INT32  iImage;
+    BYTE   fsState;
+    BYTE   fsStyle;
+    WORD   cx;
+    DWORD  lParam;
+    LPWSTR pszText;
+    INT32  cchText;
+} TBBUTTONINFO32W, *LPTBBUTTONINFO32W;
+
+#define TBBUTTONINFO   WINELIB_NAMEAW(TBBUTTONINFO)
+#define LPTBBUTTONINFO WINELIB_NAMEAW(LPTBBUTTONINFO)
+
+typedef struct tagNMTBGETINFOTIPA
+{
+    NMHDR  hdr;
+    LPSTR  pszText;
+    INT32  cchTextMax;
+    INT32  iItem;
+    LPARAM lParam;
+} NMTBGETINFOTIP32A, *LPNMTBGETINFOTIP32A;
+
+typedef struct tagNMTBGETINFOTIPW
+{
+    NMHDR  hdr;
+    LPWSTR pszText;
+    INT32  cchTextMax;
+    INT32  iItem;
+    LPARAM lParam;
+} NMTBGETINFOTIP32W, *LPNMTBGETINFOTIP32W;
+
+#define NMTBGETINFOTIP   WINELIB_NAMEAW(NMTBGETINFOFTIP)
+#define LPNMTBGETINFOTIP WINELIB_NAMEAW(LPNMTBGETINFOTIP)
+
 
 HWND32 WINAPI
 CreateToolbar(HWND32, DWORD, UINT32, INT32, HINSTANCE32,
@@ -786,12 +872,12 @@
 
 #define TTN_FIRST               (0U-520U)
 #define TTN_LAST                (0U-549U)
-#define TTN_GETDISPINFOA        (TTN_FIRST-0)
-#define TTN_GETDISPINFOW        (TTN_FIRST-10)
+#define TTN_GETDISPINFO32A      (TTN_FIRST-0)
+#define TTN_GETDISPINFO32W      (TTN_FIRST-10)
+#define TTN_GETDISPINFO WINELIB_NAME_AW(TTN_GETDISPINFO)
 #define TTN_SHOW                (TTN_FIRST-1)
 #define TTN_POP                 (TTN_FIRST-2)
 
-
 typedef struct tagTOOLINFOA {
     UINT32 cbSize;
     UINT32 uFlags;
@@ -801,7 +887,7 @@
     HINSTANCE32 hinst;
     LPSTR lpszText;
     LPARAM lParam;
-} TTTOOLINFOA, *PTOOLINFOA, *LPTTTOOLINFOA;
+} TTTOOLINFO32A, *PTOOLINFO32A, *LPTTTOOLINFO32A;
 
 typedef struct tagTOOLINFOW {
     UINT32 cbSize;
@@ -812,21 +898,28 @@
     HINSTANCE32 hinst;
     LPWSTR lpszText;
     LPARAM lParam;
-} TTTOOLINFOW, *PTOOLINFOW, *LPTTTOOLINFOW;
+} TTTOOLINFO32W, *PTOOLINFO32W, *LPTTTOOLINFO32W;
+
+#define TTTOOLINFO WINELIB_NAME_AW(TTTOOLINFO)
+#define PTOOLINFO WINELIB_NAME_AW(PTOOLINFO)
+#define LPTTTOOLINFO WINELIB_NAME_AW(LPTTTOOLINFO)
 
 typedef struct _TT_HITTESTINFOA
 {
-    HWND32      hwnd;
-    POINT32     pt;
-    TTTOOLINFOA ti;
-} TTHITTESTINFOA, *LPTTHITTESTINFOA;
+    HWND32        hwnd;
+    POINT32       pt;
+    TTTOOLINFO32A ti;
+} TTHITTESTINFO32A, *LPTTHITTESTINFO32A;
 
 typedef struct _TT_HITTESTINFOW
 {
-    HWND32      hwnd;
-    POINT32     pt;
-    TTTOOLINFOW ti;
-} TTHITTESTINFOW, *LPTTHITTESTINFOW;
+    HWND32        hwnd;
+    POINT32       pt;
+    TTTOOLINFO32W ti;
+} TTHITTESTINFO32W, *LPTTHITTESTINFO32W;
+
+#define TTHITTESTINFO WINELIB_NAME_AW(TTHITTESTINFO)
+#define LPTTHITTESTINFO WINELIB_NAME_AW(LPTTHITTESTINFO)
 
 typedef struct tagNMTTDISPINFOA
 {
@@ -836,7 +929,7 @@
     HINSTANCE32 hinst;
     UINT32      uFlags;
     LPARAM      lParam;
-} NMTTDISPINFOA, *LPNMTTDISPINFOA;
+} NMTTDISPINFO32A, *LPNMTTDISPINFO32A;
 
 typedef struct tagNMTTDISPINFOW
 {
@@ -846,8 +939,10 @@
     HINSTANCE32 hinst;
     UINT32      uFlags;
     LPARAM      lParam;
-} NMTTDISPINFOW, *LPNMTTDISPINFOW;
+} NMTTDISPINFO32W, *LPNMTTDISPINFO32W;
 
+#define NMTTDISPINFO WINELIB_NAME_AW(NMTTDISPINFO)
+#define LPNMTTDISPINFO WINELIB_NAME_AW(LPNMTTDISPINFO)
 
 
 /* Rebar control */
@@ -879,13 +974,41 @@
 #define TBS_NOTHUMB             0x0080
 #define TBS_TOOLTIPS            0x0100
 
+#define TBTS_TOP                0
+#define TBTS_LEFT               1
+#define TBTS_BOTTOM             2
+#define TBTS_RIGHT              3
+
+#define TB_LINEUP               0
+#define TB_LINEDOWN             1
+#define TB_PAGEUP               2
+#define TB_PAGEDOWN             3
+#define TB_THUMBPOSITION        4
+#define TB_THUMBTRACK           5
+#define TB_TOP                  6
+#define TB_BOTTOM               7
+#define TB_ENDTRACK             8
+
+#define TBCD_TICS               0x0001
+#define TBCD_THUMB              0x0002
+#define TBCD_CHANNEL            0x0003
+
 #define TBM_GETPOS              (WM_USER)
 #define TBM_GETRANGEMIN         (WM_USER+1)
 #define TBM_GETRANGEMAX         (WM_USER+2)
 #define TBM_GETTIC              (WM_USER+3)
 #define TBM_SETTIC              (WM_USER+4)
 #define TBM_SETPOS              (WM_USER+5)
-
+#define TBM_SETRANGE            (WM_USER+6)
+#define TBM_SETRANGEMIN         (WM_USER+7)
+#define TBM_SETRANGEMAX         (WM_USER+8)
+#define TBM_CLEARTICS           (WM_USER+9)
+#define TBM_SETSEL              (WM_USER+10)
+#define TBM_SETSELSTART         (WM_USER+11)
+#define TBM_SETSELEND           (WM_USER+12)
+#define TBM_GETPTICS            (WM_USER+14)
+#define TBM_GETTICPOS           (WM_USER+15)
+#define TBM_GETNUMTICS          (WM_USER+16)
 #define TBM_GETSELSTART         (WM_USER+17)
 #define TBM_GETSELEND           (WM_USER+18)
 #define TBM_CLEARSEL            (WM_USER+19)
@@ -898,6 +1021,13 @@
 #define TBM_GETCHANNELRECT      (WM_USER+26)
 #define TBM_SETTHUMBLENGTH      (WM_USER+27)
 #define TBM_GETTHUMBLENGTH      (WM_USER+28)
+#define TBM_SETTOOLTIPS         (WM_USER+29)
+#define TBM_GETTOOLTIPS         (WM_USER+30)
+#define TBM_SETTIPSIDE          (WM_USER+31)
+#define TBM_SETBUDDY            (WM_USER+32)
+#define TBM_GETBUDDY            (WM_USER+33)
+#define TBM_SETUNICODEFORMAT    CCM_SETUNICODEFORMAT
+#define TBM_GETUNICODEFORMAT    CCM_GETUNICODEFORMAT
 
 
 /* Pager control */
@@ -949,11 +1079,36 @@
 
 #define TV_FIRST                0x1100
 
-
+#define TVM_INSERTITEMA         (TV_FIRST+0)
+#define TVM_INSERTITEMW         (TV_FIRST+50)
+#define TVM_DELETEITEM          (TV_FIRST+1)
+#define TVM_EXPAND              (TV_FIRST+2)
+#define TVM_GETITEMRECT         (TV_FIRST+4)
+#define TVM_GETCOUNT            (TV_FIRST+5)
+#define TVM_GETINDENT           (TV_FIRST+6)
+#define TVM_SETINDENT           (TV_FIRST+7)
 #define TVM_GETIMAGELIST        (TV_FIRST+8)
 #define TVM_SETIMAGELIST        (TV_FIRST+9)
-
-
+#define TVM_GETNEXTITEM         (TV_FIRST+10)
+#define TVM_SELECTITEM          (TV_FIRST+11)
+#define TVM_GETITEMA            (TV_FIRST+12)
+#define TVM_GETITEMW            (TV_FIRST+62)
+#define TVM_SETITEMA            (TV_FIRST+13)
+#define TVM_SETITEMW            (TV_FIRST+63)
+#define TVM_EDITLABELA          (TV_FIRST+14)
+#define TVM_EDITLABELW          (TV_FIRST+65)
+#define TVM_GETEDITCONTROL      (TV_FIRST+15)
+#define TVM_GETVISIBLECOUNT     (TV_FIRST+16)
+#define TVM_HITTEST             (TV_FIRST+17)
+#define TVM_CREATEDRAGIMAGE     (TV_FIRST+18)
+#define TVM_SORTCHILDREN        (TV_FIRST+19)
+#define TVM_ENSUREVISIBLE       (TV_FIRST+20)
+#define TVM_SORTCHILDRENCB      (TV_FIRST+21)
+#define TVM_ENDEDITLABELNOW     (TV_FIRST+22)
+#define TVM_GETISEARCHSTRINGA   (TV_FIRST+23)
+#define TVM_GETISEARCHSTRINGW   (TV_FIRST+64)
+#define TVM_SETTOOLTIPS         (TV_FIRST+24)
+#define TVM_GETTOOLTIPS         (TV_FIRST+25)
 
 /* Listview control */
 
diff --git a/include/config.h.in b/include/config.h.in
index 30fe2a3..73fc304 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -72,6 +72,9 @@
 /* Define if you have the memmove function.  */
 #undef HAVE_MEMMOVE
 
+/* Define if you have the sendmsg function.  */
+#undef HAVE_SENDMSG
+
 /* Define if you have the sigaltstack function.  */
 #undef HAVE_SIGALTSTACK
 
@@ -153,5 +156,8 @@
 /* Define if you have the i386 library (-li386).  */
 #undef HAVE_LIBI386
 
+/* Define if you have the socket library (-lsocket).  */
+#undef HAVE_LIBSOCKET
+
 /* Define if you have the w library (-lw).  */
 #undef HAVE_LIBW
diff --git a/include/debug.h b/include/debug.h
index b21d384..9056a5c 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -81,62 +81,64 @@
 #define dbch_module 73
 #define dbch_mpr 74
 #define dbch_msg 75
-#define dbch_nonclient 76
-#define dbch_ntdll 77
-#define dbch_ole 78
-#define dbch_pager 79
-#define dbch_palette 80
-#define dbch_print 81
-#define dbch_process 82
-#define dbch_profile 83
-#define dbch_progress 84
-#define dbch_prop 85
-#define dbch_psdrv 86
-#define dbch_rebar 87
-#define dbch_reg 88
-#define dbch_region 89
-#define dbch_relay 90
-#define dbch_resource 91
-#define dbch_s 92
-#define dbch_scroll 93
-#define dbch_security 94
-#define dbch_segment 95
-#define dbch_selector 96
-#define dbch_sem 97
-#define dbch_sendmsg 98
-#define dbch_shell 99
-#define dbch_shm 100
-#define dbch_snoop 101
-#define dbch_sound 102
-#define dbch_static 103
-#define dbch_stress 104
-#define dbch_string 105
-#define dbch_syscolor 106
-#define dbch_system 107
-#define dbch_task 108
-#define dbch_text 109
-#define dbch_thread 110
-#define dbch_thunk 111
-#define dbch_timer 112
-#define dbch_toolbar 113
-#define dbch_toolhelp 114
-#define dbch_tooltips 115
-#define dbch_trackbar 116
-#define dbch_treeview 117
-#define dbch_tweak 118
-#define dbch_uitools 119
-#define dbch_updown 120
-#define dbch_ver 121
-#define dbch_virtual 122
-#define dbch_vxd 123
-#define dbch_win 124
-#define dbch_win16drv 125
-#define dbch_win32 126
-#define dbch_wing 127
-#define dbch_winsock 128
-#define dbch_wnet 129
-#define dbch_x11 130
-#define dbch_x11drv 131
+#define dbch_msvideo 76
+#define dbch_nonclient 77
+#define dbch_ntdll 78
+#define dbch_ole 79
+#define dbch_pager 80
+#define dbch_palette 81
+#define dbch_print 82
+#define dbch_process 83
+#define dbch_profile 84
+#define dbch_progress 85
+#define dbch_prop 86
+#define dbch_psdrv 87
+#define dbch_rebar 88
+#define dbch_reg 89
+#define dbch_region 90
+#define dbch_relay 91
+#define dbch_resource 92
+#define dbch_s 93
+#define dbch_scroll 94
+#define dbch_security 95
+#define dbch_segment 96
+#define dbch_selector 97
+#define dbch_sem 98
+#define dbch_sendmsg 99
+#define dbch_shell 100
+#define dbch_shm 101
+#define dbch_snoop 102
+#define dbch_sound 103
+#define dbch_static 104
+#define dbch_statusbar 105
+#define dbch_stress 106
+#define dbch_string 107
+#define dbch_syscolor 108
+#define dbch_system 109
+#define dbch_task 110
+#define dbch_text 111
+#define dbch_thread 112
+#define dbch_thunk 113
+#define dbch_timer 114
+#define dbch_toolbar 115
+#define dbch_toolhelp 116
+#define dbch_tooltips 117
+#define dbch_trackbar 118
+#define dbch_treeview 119
+#define dbch_tweak 120
+#define dbch_uitools 121
+#define dbch_updown 122
+#define dbch_ver 123
+#define dbch_virtual 124
+#define dbch_vxd 125
+#define dbch_win 126
+#define dbch_win16drv 127
+#define dbch_win32 128
+#define dbch_wing 129
+#define dbch_winsock 130
+#define dbch_wnet 131
+#define dbch_x11 132
+#define dbch_x11drv 133
 /* Definitions for classes identifiers */
 #define dbcl_fixme 0
 #define dbcl_err 1
diff --git a/include/debugdefs.h b/include/debugdefs.h
index 3a8bb30..14450de 100644
--- a/include/debugdefs.h
+++ b/include/debugdefs.h
@@ -4,7 +4,7 @@
 #include "debugtools.h"
 #endif
 
-#define DEBUG_CHANNEL_COUNT 132
+#define DEBUG_CHANNEL_COUNT 134
 #ifdef DEBUG_RUNTIME
 short debug_msg_enabled[][DEBUG_CLASS_COUNT] = {
 {1, 1, 0, 0},
@@ -139,6 +139,8 @@
 {1, 1, 0, 0},
 {1, 1, 0, 0},
 {1, 1, 0, 0},
+{1, 1, 0, 0},
+{1, 1, 0, 0},
 };
 const char* debug_ch_name[] = {
 "1",
@@ -217,6 +219,7 @@
 "module",
 "mpr",
 "msg",
+"msvideo",
 "nonclient",
 "ntdll",
 "ole",
@@ -245,6 +248,7 @@
 "snoop",
 "sound",
 "static",
+"statusbar",
 "stress",
 "string",
 "syscolor",
diff --git a/include/dosexe.h b/include/dosexe.h
new file mode 100644
index 0000000..56cd478
--- /dev/null
+++ b/include/dosexe.h
@@ -0,0 +1,38 @@
+/*
+ * DOS EXE loader
+ *
+ * Copyright 1998 Ove Kåven
+ */
+
+#ifdef linux
+
+#include <unistd.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/vm86.h>
+#include "wintypes.h"
+
+typedef struct _DOSTASK {
+ LPVOID img;
+ unsigned img_ofs;
+ HMODULE16 hModule;
+ struct vm86plus_struct VM86;
+ int fn, state;
+#ifdef MZ_USESYSV
+ /* SYSV IPC is not quite supported yet... */
+ key_t shm_key;
+ int shm_id;
+#else
+ char mm_name[128];
+ int mm_fd;
+#endif
+ int read_pipe,write_pipe;
+ pid_t task;
+} DOSTASK, *LPDOSTASK;
+
+extern HINSTANCE16 MZ_LoadModule( LPCSTR name, LPCSTR cmdline, LPCSTR env, UINT16 show_cmd );
+extern int MZ_RunModule( LPDOSTASK lpDosTask );
+extern void MZ_KillModule( LPDOSTASK lpDosTask );
+extern int DOSVM_Process( LPDOSTASK lpDosTask );
+
+#endif /* linux */
diff --git a/include/interfaces.h b/include/interfaces.h
index da42f15..32c8435 100644
--- a/include/interfaces.h
+++ b/include/interfaces.h
@@ -46,6 +46,7 @@
 	STDMETHOD_(ULONG,AddRef) (THIS) PURE;
 	STDMETHOD_(ULONG,Release) (THIS) PURE;
 	STDMETHOD(CreateInstance) (THIS_ LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppvObject) PURE;
+    STDMETHOD(LockServer) (THIS) PURE;
 } *LPCLASSFACTORY_VTABLE,IClassFactory_VTable;
 
 struct IClassFactory {
diff --git a/include/miscemu.h b/include/miscemu.h
index 46f232d..5f4c766 100644
--- a/include/miscemu.h
+++ b/include/miscemu.h
@@ -14,11 +14,13 @@
 extern HANDLE16 DOSMEM_BiosSeg;
 extern DWORD DOSMEM_CollateTable;
 
-extern BOOL32 DOSMEM_Init(void);
+extern BOOL32 DOSMEM_Init(HMODULE16 hModule);
 extern void   DOSMEM_Tick(void);
 extern WORD   DOSMEM_AllocSelector(WORD);
-extern LPVOID DOSMEM_GetBlock(UINT32 size, UINT16* p);
-extern BOOL32 DOSMEM_FreeBlock(void* ptr);
+extern LPVOID DOSMEM_GetBlock(HMODULE16 hModule, UINT32 size, UINT16* p);
+extern BOOL32 DOSMEM_FreeBlock(HMODULE16 hModule, void* ptr);
+extern LPVOID DOSMEM_ResizeBlock(HMODULE16 hModule, void* ptr, UINT32 size, UINT16* p);
+extern UINT32 DOSMEM_Available(HMODULE16 hModule);
 extern LPVOID DOSMEM_MapRealToLinear(DWORD); /* real-mode to linear */
 extern LPVOID DOSMEM_MapDosToLinear(UINT32); /* linear DOS to Wine */
 extern UINT32 DOSMEM_MapLinearToDos(LPVOID); /* linear Wine to DOS */
@@ -46,6 +48,10 @@
 /* misc/aspi.c */
 extern void ASPI_DOS_HandleInt(CONTEXT *context);
 
+#define CTX_SEG_OFF_TO_LIN(context,seg,off) \
+    (ISV86(context) ? (void*)(V86BASE(context)+((seg)<<4)+off) \
+                    : PTR_SEG_OFF_TO_LIN(seg,off))
+
 #define INT_BARF(context,num) \
     fprintf( stderr, "int%x: unknown/not implemented parameters:\n" \
                      "int%x: AX %04x, BX %04x, CX %04x, DX %04x, " \
diff --git a/include/mmsystem.h b/include/mmsystem.h
index 502fb36..a0d46c8 100644
--- a/include/mmsystem.h
+++ b/include/mmsystem.h
@@ -144,8 +144,13 @@
 #define CALLBACK_WINDOW     0x00010000l    /* dwCallback is a HWND */
 #define CALLBACK_TASK       0x00020000l    /* dwCallback is a HTASK */
 #define CALLBACK_FUNCTION   0x00030000l    /* dwCallback is a FARPROC */
+#define CALLBACK_FUNC32     0x00070000l    /* (ugly hack) 32-bit FARPROC */
+#define CALLBACK32CONV(x)   ((((x)&CALLBACK_TYPEMASK)==CALLBACK_FUNCTION) ? \
+                             (((x)&~CALLBACK_TYPEMASK)|CALLBACK_FUNC32) : (x))
 
-typedef void (CALLBACK *LPDRVCALLBACK) (HDRVR16 h, UINT16 uMessage, DWORD dwUser, DWORD dw1, DWORD dw2);
+typedef void (CALLBACK *LPDRVCALLBACK16) (HDRVR16 h, UINT16 uMessage, DWORD dwUser, DWORD dw1, DWORD dw2);
+typedef void (CALLBACK *LPDRVCALLBACK32) (HDRVR32 h, UINT32 uMessage, DWORD dwUser, DWORD dw1, DWORD dw2);
+DECL_WINELIB_TYPE(LPDRVCALLBACK)
 
 #define MM_MICROSOFT            1       /* Microsoft Corp. */
 
@@ -196,7 +201,9 @@
 
 typedef HWAVEIN16 *LPHWAVEIN16;
 typedef HWAVEOUT16 *LPHWAVEOUT16;
-typedef LPDRVCALLBACK LPWAVECALLBACK;
+typedef LPDRVCALLBACK16 LPWAVECALLBACK16;
+typedef LPDRVCALLBACK32 LPWAVECALLBACK32;
+DECL_WINELIB_TYPE(LPWAVECALLBACK)
 typedef HMIXER16 *LPHMIXER16;
 typedef HMIXER32 *LPHMIXER32;
 
@@ -464,7 +471,9 @@
 
 typedef HMIDIIN16  *LPHMIDIIN16;
 typedef HMIDIOUT16  *LPHMIDIOUT16;
-typedef LPDRVCALLBACK LPMIDICALLBACK;
+typedef LPDRVCALLBACK16 LPMIDICALLBACK16;
+typedef LPDRVCALLBACK32 LPMIDICALLBACK32;
+DECL_WINELIB_TYPE(LPMIDICALLBACK)
 #define MIDIPATCHSIZE   128
 typedef WORD PATCHARRAY[MIDIPATCHSIZE];
 typedef WORD *LPPATCHARRAY;
@@ -2788,6 +2797,7 @@
 #define DCB_WINDOW		0x0001			/* dwCallback is a HWND */
 #define DCB_TASK		0x0002			/* dwCallback is a HTASK */
 #define DCB_FUNCTION	0x0003			/* dwCallback is a FARPROC */
+#define DCB_FUNC32	0x0007			/* (ugly hack) 32-bit FARPROC */
 #define DCB_TYPEMASK	0x0007
 #define DCB_NOSWITCH	0x0008			/* don't switch stacks for callback */
 
diff --git a/include/module.h b/include/module.h
index 7add294..485d784 100644
--- a/include/module.h
+++ b/include/module.h
@@ -10,6 +10,8 @@
 #include "wintypes.h"
 #include "pe_image.h"
 
+struct _DOSTASK;
+
   /* In-memory module structure. See 'Windows Internals' p. 219 */
 typedef struct _NE_MODULE
 {
@@ -49,6 +51,7 @@
     HMODULE32  module32;      /* 40 PE module handle for Win32 modules */
     HMODULE16  self;          /* 44 Handle for this module */
     WORD    self_loading_sel; /* 46 Selector used for self-loading apps. */
+    struct _DOSTASK *lpDosTask;
 } NE_MODULE;
 
 
diff --git a/include/ole2.h b/include/ole2.h
index e80454d..ee87629 100644
--- a/include/ole2.h
+++ b/include/ole2.h
@@ -17,4 +17,13 @@
 #define rmm             23
 #define rup            639
 
+/* FIXME should be in oleidl.h*/
+typedef struct  tagOleMenuGroupWidths
+{ LONG width[ 6 ];
+} OLEMENUGROUPWIDTHS32;
+
+typedef struct tagOleMenuGroupWidths *LPOLEMENUGROUPWIDTHS32;
+
+typedef HGLOBAL32 HOLEMENU32;
+
 #endif  /* __WINE_OLE2_H */
diff --git a/include/oleauto.h b/include/oleauto.h
index 61d42c6..4b675e6 100644
--- a/include/oleauto.h
+++ b/include/oleauto.h
@@ -1,14 +1,14 @@
 #ifndef __WINE_OLEAUTO_H
 #define __WINE_OLEAUTO_H
 
-BSTR16 SysAllocString16(LPOLESTR16);
-BSTR32 SysAllocString32(LPOLESTR32);
+BSTR16 WINAPI SysAllocString16(LPOLESTR16);
+BSTR32 WINAPI SysAllocString32(LPOLESTR32);
 #define SysAllocString WINELIB_NAME(SysAllocString)
-INT16 SysReAllocString16(LPBSTR16,LPOLESTR16);
-INT32 SysReAllocString32(LPBSTR32,LPOLESTR32);
+INT16 WINAPI SysReAllocString16(LPBSTR16,LPOLESTR16);
+INT32 WINAPI SysReAllocString32(LPBSTR32,LPOLESTR32);
 #define SysReAllocString WINELIB_NAME(SysReAllocString)
-VOID SysFreeString16(BSTR16);
-VOID SysFreeString32(BSTR32);
+VOID WINAPI SysFreeString16(BSTR16);
+VOID WINAPI SysFreeString32(BSTR32);
 #define SysFreeString WINELIB_NAME(SysFreeString)
 
 typedef char OLECHAR;
diff --git a/include/print.h b/include/print.h
index fa64a49..92d43e4 100644
--- a/include/print.h
+++ b/include/print.h
@@ -25,6 +25,11 @@
 #define PRINTER_ATTRIBUTE_WORK_OFFLINE   0x00000400
 #define PRINTER_ATTRIBUTE_ENABLE_BIDI    0x00000800
 
+
+DWORD WINAPI DrvGetPrinterData(LPSTR lpPrinter, LPSTR lpProfile,
+	  LPDWORD lpType, LPBYTE lpPrinterData, int cbData, LPDWORD lpNeeded);
+DWORD WINAPI DrvSetPrinterData(LPSTR lpPrinter, LPSTR lpProfile,
+          DWORD lpType, LPBYTE lpPrinterData, DWORD dwSize);
 HANDLE16 WINAPI OpenJob(LPSTR lpOutput, LPSTR lpTitle, HDC16 hDC);
 int WINAPI CloseJob(HANDLE16 hJob);
 int WINAPI WriteSpool(HANDLE16 hJob, LPSTR lpData, WORD cch);
@@ -35,3 +40,4 @@
 int WINAPI WriteDialog(HANDLE16 hJob, LPSTR lpMsg, WORD cchMsg);
 
 #endif  /* __WINE_PRINT_H */
+
diff --git a/include/process.h b/include/process.h
index a5abc05..8f82294 100644
--- a/include/process.h
+++ b/include/process.h
@@ -14,12 +14,14 @@
 #include "k32obj.h"
 
 struct _NE_MODULE;
+struct _THREAD_ENTRY;
 
 /* Process handle entry */
 typedef struct
 {
     DWORD    access;  /* Access flags */
     K32OBJ  *ptr;     /* Object ptr */
+    int      server;  /* Server handle (FIXME: tmp hack) */
 } HANDLE_ENTRY;
 
 /* Process handle table */
@@ -78,7 +80,7 @@
     HANDLE_TABLE    *handle_table;     /* 44 Handle table */
     struct _PDB32   *parent;           /* 48 Parent process */
     WINE_MODREF     *modref_list;      /* 4c MODREF list */
-    void            *thread_list;      /* 50 List of threads */
+    struct _THREAD_ENTRY *thread_list; /* 50 List of threads */
     void            *debuggee_CB;      /* 54 Debuggee context block */
     void            *local_heap_free;  /* 58 Head of local heap free list */
     DWORD            unknown4;         /* 5c Unknown */
@@ -125,9 +127,10 @@
 /* scheduler/handle.c */
 extern BOOL32 HANDLE_CreateTable( PDB32 *pdb, BOOL32 inherit );
 extern HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access,
-                              BOOL32 inherit );
+                              BOOL32 inherit, int server_handle );
 extern K32OBJ *HANDLE_GetObjPtr( PDB32 *pdb, HANDLE32 handle,
-                                 K32OBJ_TYPE type, DWORD access );
+                                 K32OBJ_TYPE type, DWORD access,
+                                 int *server_handle );
 extern BOOL32 HANDLE_SetObjPtr( PDB32 *pdb, HANDLE32 handle,
                                 K32OBJ *ptr, DWORD access );
 extern void HANDLE_CloseAll( PDB32 *pdb, K32OBJ *ptr );
@@ -135,10 +138,13 @@
 /* scheduler/process.c */
 extern BOOL32 PROCESS_Init( void );
 extern PDB32 *PROCESS_Current(void);
-extern PDB32 *PROCESS_GetPtr( HANDLE32 handle, DWORD access );
+extern PDB32 *PROCESS_GetPtr( HANDLE32 handle, DWORD access, int *server_handle );
 extern PDB32 *PROCESS_IdToPDB( DWORD id );
 extern PDB32 *PROCESS_Create( struct _NE_MODULE *pModule, LPCSTR cmd_line,
                               LPCSTR env, HINSTANCE16 hInstance,
-                              HINSTANCE16 hPrevInstance, UINT32 cmdShow );
+                              HINSTANCE16 hPrevInstance, UINT32 cmdShow,
+                              PROCESS_INFORMATION *info );
+extern void PROCESS_SuspendOtherThreads(void);
+extern void PROCESS_ResumeOtherThreads(void);
 
 #endif  /* __WINE_PROCESS_H */
diff --git a/include/psdrv.h b/include/psdrv.h
index 0c47895..171e085 100644
--- a/include/psdrv.h
+++ b/include/psdrv.h
@@ -1,5 +1,6 @@
+
 /*
- *	Postscript driver definitions
+ *	PostScript driver definitions
  *
  *	Copyright 1998  Huw D M Davies
  */
@@ -39,19 +40,126 @@
     float		XHeight;
     float		Ascender;
     float		Descender;
+    float		FullAscender;		/* Ascent of Aring character */
     float		CharWidths[256];
     int			NumofMetrics;
     AFMMETRICS		*Metrics;
-    struct _tagAFM	*next;
 } AFM; /* CharWidths is a shortcut to the WX values of numbered glyphs */
 
-typedef struct _tagFontFamily {
-    char			*FamilyName; /* family name */
-    AFM				*afm;	     /* list of afms for this family */
-    struct _tagFontFamily	*next;       /* next family */
-} FontFamily;
+/* Note no 'next' in AFM. Use AFMLISTENTRY as a container. This allow more than
+   one list to exist without having to reallocate the entire AFM structure. We
+   keep a global list of all afms (PSDRV_AFMFontList) plus a list of available
+   fonts for each DC (dc->physDev->Fonts) */
 
-extern FontFamily *PSDRV_AFMFontList;
+typedef struct _tagAFMLISTENTRY {
+    AFM				*afm;
+    struct _tagAFMLISTENTRY	*next;
+} AFMLISTENTRY;
+
+typedef struct _tagFONTFAMILY {
+    char			*FamilyName; /* family name */
+    AFMLISTENTRY		*afmlist;    /* list of afms for this family */
+    struct _tagFONTFAMILY	*next;       /* next family */
+} FONTFAMILY;
+
+extern FONTFAMILY *PSDRV_AFMFontList;
+
+typedef struct _tagFONTNAME {
+    char		*Name;
+    struct _tagFONTNAME *next;
+} FONTNAME;
+
+typedef struct {
+    float	llx, lly, urx, ury;
+} IMAGEABLEAREA;
+
+typedef struct {
+    float	x, y;
+} PAPERDIMENSION;
+
+typedef struct _tagPAGESIZE {
+    char		*Name;
+    char		*FullName;
+    char		*InvocationString;
+    IMAGEABLEAREA	*ImageableArea;
+    PAPERDIMENSION	*PaperDimension;
+    WORD		WinPage; /*eg DMPAPER_A4. Doesn't really belong here */
+    struct _tagPAGESIZE *next;
+} PAGESIZE;
+
+
+typedef struct _tagOPTIONENTRY {
+    char			*Name;		/* eg "True" */
+    char			*FullName;	/* eg "Installed" */
+    char			*InvocationString; /* Often NULL */
+    struct _tagOPTIONENTRY	*next;
+} OPTIONENTRY;
+
+typedef struct _tagOPTION { /* Treat bool as a special case of pickone */
+    char			*OptionName;	/* eg "*Option1" */
+    char			*FullName;	/* eg "Envelope Feeder" */
+    char			*DefaultOption; /* eg "False" */
+    OPTIONENTRY			*Options;
+    struct _tagOPTION		*next;
+} OPTION;
+
+typedef struct _tagCONSTRAINT {
+    char			*Feature1;
+    char			*Value1;
+    char			*Feature2;
+    char			*Value2;
+    struct _tagCONSTRAINT	*next;
+} CONSTRAINT;
+
+typedef struct _tagINPUTSLOT {
+    char			*Name;
+    char			*FullName;
+    char			*InvocationString;
+    WORD			WinBin; /* eg DMBIN_LOWER */
+    struct _tagINPUTSLOT	*next;
+} INPUTSLOT;
+
+typedef struct {
+    char		*NickName;
+    int			LanguageLevel;
+    BOOL32		ColorDevice;
+    int			DefaultResolution;
+    int			LandscapeOrientation;
+    char		*JCLBegin;
+    char		*JCLToPSInterpreter;
+    char		*JCLEnd;
+    char		*DefaultFont;
+    FONTNAME		*InstalledFonts; /* ptr to a list of FontNames */
+    PAGESIZE		*PageSizes;
+    OPTION		*InstalledOptions;
+    CONSTRAINT		*Constraints;
+    INPUTSLOT		*InputSlots;
+} PPD;
+
+typedef struct {
+    DEVMODE16			dmPublic;
+    struct _tagdocprivate {
+    }				dmDocPrivate;
+    struct _tagdrvprivate {
+      char	ppdFileName[100]; /* Hack */
+      UINT32	numInstalledOptions; /* Options at end of struct */
+    }				dmDrvPrivate;
+
+/* Now comes:
+
+numInstalledOptions of OPTIONs
+
+*/
+
+} PSDRV_DEVMODE16;
+
+typedef struct _tagPI {
+    char		*FriendlyName;
+    PPD			*ppd;
+    PSDRV_DEVMODE16	*Devmode;
+    FONTFAMILY		*Fonts;
+    struct _tagPI	*next;
+} PRINTERINFO;
 
 typedef struct {
     AFM			*afm;
@@ -74,10 +182,20 @@
 {
     PSFONT		font;		/* Current PS font */
     JOB			job;
+    PSDRV_DEVMODE16	*Devmode;
+    PRINTERINFO		*pi;
 } PSDRV_PDEVICE;
 
+extern HANDLE32 PSDRV_Heap;
 
+extern void PSDRV_MergeDevmodes(PSDRV_DEVMODE16 *dm1, PSDRV_DEVMODE16 *dm2,
+			 PRINTERINFO *pi);
 extern BOOL32 PSDRV_GetFontMetrics(void);
+extern PPD *PSDRV_ParsePPD(char *fname);
+extern PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name);
+extern AFM *PSDRV_FindAFMinList(FONTFAMILY *head, char *name);
+extern void PSDRV_AddAFMtoList(FONTFAMILY **head, AFM *afm);
+extern void PSDRV_FreeAFMList( FONTFAMILY *head );
 
 extern BOOL32 PSDRV_Init(void);
 extern HFONT16 PSDRV_FONT_SelectObject( DC *dc, HFONT16 hfont, FONTOBJ *font);
@@ -115,6 +233,8 @@
 extern BOOL32 PSDRV_GetTextMetrics( DC *dc, TEXTMETRIC32A *metrics );
 extern BOOL32 PSDRV_LineTo( DC *dc, INT32 x, INT32 y );
 extern BOOL32 PSDRV_MoveToEx( DC *dc, INT32 x, INT32 y, LPPOINT32 pt );
+extern BOOL32 PSDRV_Polyline( DC *dc, const LPPOINT32 pt, INT32 count );
+extern BOOL32 PSDRV_Polygon( DC *dc, LPPOINT32 pt, INT32 count );
 extern HGDIOBJ32 PSDRV_SelectObject( DC *dc, HGDIOBJ32 handle );
 
 extern BOOL32 PSDRV_Rectangle(DC *dc, INT32 left, INT32 top, INT32 right,
diff --git a/include/server.h b/include/server.h
index d6501f1..0b80e48 100644
--- a/include/server.h
+++ b/include/server.h
@@ -27,47 +27,115 @@
     int fd;    /* fd to pass */
 };
 
-/* request from client to server */
 
-enum request
-{
-    REQ_TIMEOUT,         /* internal timeout msg */
-    REQ_KILL_THREAD,     /* internal kill thread msg */
-    REQ_NEW_THREAD,      /* create a new thread (called from the creator) */
-    REQ_INIT_THREAD,     /* init a new thread (called by itself) */
-    REQ_NB_REQUESTS
-};
+/* Request structures */
 
-/* request structures */
+/* following are the definitions of all the client<->server  */
+/* communication format; requests are from client to server, */
+/* replies are from server to client. All requests must have */
+/* a corresponding structure; the replies can be empty in    */
+/* which case it isn't necessary to define a structure.      */
 
+
+/* Create a new thread from the context of the parent */
 struct new_thread_request
 {
-    void *pid;  /* process id for the new thread (or 0 if none yet) */
+    void*        pid;          /* process id for the new thread (or 0 if none yet) */
 };
-
 struct new_thread_reply
 {
-    void *tid;  /* thread id */
-    void *pid;  /* process id (created if necessary) */
+    void*        tid;          /* thread id */
+    int          thandle;      /* thread handle (in the current process) */
+    void*        pid;          /* process id (created if necessary) */
+    int          phandle;      /* process handle (in the current process) */
 };
 
+
+/* Initialize a thread; called from the child after fork()/clone() */
 struct init_thread_request
 {
-    int  pid;
-/*    char name[...];*/
+    int          unix_pid;     /* Unix pid of new thread */
 };
 
-/* server-side functions */
 
-extern void server_main_loop( int fd );
+/* Terminate a process */
+struct terminate_process_request
+{
+    int          handle;       /* process handle to terminate */
+    int          exit_code;    /* process exit code */
+};
+
+
+/* Terminate a thread */
+struct terminate_thread_request
+{
+    int          handle;       /* thread handle to terminate */
+    int          exit_code;    /* thread exit code */
+};
+
+
+/* Retrieve information about a process */
+struct get_process_info_request
+{
+    int          handle;       /* process handle */
+};
+struct get_process_info_reply
+{
+    void*        pid;          /* server process id */
+    int          exit_code;    /* process exit code */
+};
+
+
+/* Close a handle for the current process */
+struct close_handle_request
+{
+    int          handle;       /* handle to close */
+};
+
+
+/* Duplicate a handle */
+struct dup_handle_request
+{
+    int          src_process;  /* src process handle */
+    int          src_handle;   /* src handle to duplicate */
+    int          dst_process;  /* dst process handle */
+    int          dst_handle;   /* handle to duplicate to (or -1 for any) */
+    unsigned int access;       /* wanted access rights */
+    int          inherit;      /* inherit flag */
+    int          options;      /* duplicate options (see below) */
+};
+struct dup_handle_reply
+{
+    int          handle;       /* duplicated handle in dst process */
+};
+
+
+/* Open a handle to a process */
+struct open_process_request
+{
+    void*        pid;          /* process id to open */
+    unsigned int access;       /* wanted access rights */
+    int          inherit;      /* inherit flag */
+};
+struct open_process_reply
+{
+    int          handle;       /* handle to the process */
+};
 
 
 /* client-side functions */
 
 #ifndef __WINE_SERVER__
 struct _THDB;
-extern int CLIENT_NewThread( struct _THDB *thdb );
+extern int CLIENT_NewThread( struct _THDB *thdb, int *thandle, int *phandle );
 extern int CLIENT_InitThread(void);
+extern int CLIENT_TerminateProcess( int handle, int exit_code );
+extern int CLIENT_TerminateThread( int handle, int exit_code );
+extern int CLIENT_CloseHandle( int handle );
+extern int CLIENT_DuplicateHandle( int src_process, int src_handle, int dst_process,
+                                   int dst_handle, DWORD access, BOOL32 inherit, DWORD options );
+extern int CLIENT_GetProcessInfo( int handle, struct get_process_info_reply *reply );
+extern int CLIENT_OpenProcess( void *pid, DWORD access, BOOL32 inherit );
 #endif  /* __WINE_SERVER__ */
 
 #endif  /* __WINE_SERVER_H */
diff --git a/include/server/object.h b/include/server/object.h
new file mode 100644
index 0000000..bf6dcd3
--- /dev/null
+++ b/include/server/object.h
@@ -0,0 +1,98 @@
+/*
+ * Wine server objects
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ */
+
+#ifndef __WINE_SERVER_OBJECT_H
+#define __WINE_SERVER_OBJECT_H
+
+#ifndef __WINE_SERVER__
+#error This file can only be used in the Wine server
+#endif
+
+#include <sys/time.h>
+#include "server/request.h"
+
+/* kernel objects */
+
+struct object;
+struct object_name;
+
+struct object_ops
+{
+    void (*dump)(struct object *,int);   /* dump the object (for debugging) */
+    void (*destroy)(struct object *);    /* destroy on refcount == 0 */
+};
+
+struct object
+{
+    unsigned int              refcount;
+    const struct object_ops  *ops;
+    struct object_name       *name;
+};
+
+extern void init_object( struct object *obj, const struct object_ops *ops,
+                         const char *name );
+/* grab/release_object can take any pointer, but you better make sure */
+/* that the thing pointed to starts with a struct object... */
+extern struct object *grab_object( void *obj );
+extern void release_object( void *obj );
+
+/* request handlers */
+
+struct iovec;
+struct thread;
+
+extern void call_req_handler( struct thread *thread, enum request req,
+                              void *data, int len, int fd );
+extern void call_timeout_handler( struct thread *thread );
+extern void call_kill_handler( struct thread *thread, int exit_code );
+
+extern void trace_request( enum request req, void *data, int len, int fd );
+extern void trace_timeout(void);
+extern void trace_kill( int exit_code );
+extern void trace_reply( struct thread *thread, int type, int pass_fd,
+                         struct iovec *vec, int veclen );
+
+/* socket functions */
+
+extern int add_client( int client_fd, struct thread *self );
+extern void remove_client( int client_fd, int exit_code );
+extern int get_initial_client_fd(void);
+extern void set_timeout( int client_fd, struct timeval *when );
+extern int send_reply_v( int client_fd, int type, int pass_fd,
+                         struct iovec *vec, int veclen );
+
+/* process functions */
+
+struct process;
+
+extern struct process *create_process(void);
+extern struct process *get_process_from_id( void *id );
+extern struct process *get_process_from_handle( int handle, unsigned int access );
+extern void add_process_thread( struct process *process,
+                                struct thread *thread );
+extern void remove_process_thread( struct process *process,
+                                   struct thread *thread );
+extern void kill_process( struct process *process, int exit_code );
+extern void get_process_info( struct process *process,
+                              struct get_process_info_reply *reply );
+
+/* handle functions */
+
+/* alloc_handle takes a void *obj for convenience, but you better make sure */
+/* that the thing pointed to starts with a struct object... */
+extern int alloc_handle( struct process *process, void *obj,
+                         unsigned int access, int inherit );
+extern int close_handle( struct process *process, int handle );
+extern int set_handle_info( struct process *process, int handle,
+                            int mask, int flags );
+extern struct object *get_handle_obj( struct process *process, int handle,
+                                      unsigned int access, const struct object_ops *ops );
+extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
+                             int dst_handle, unsigned int access, int inherit, int options );
+
+extern int debug_level;
+
+#endif  /* __WINE_SERVER_OBJECT_H */
diff --git a/include/server/request.h b/include/server/request.h
new file mode 100644
index 0000000..574b732
--- /dev/null
+++ b/include/server/request.h
@@ -0,0 +1,48 @@
+/* File generated automatically by tools/make_requests; DO NOT EDIT!! */
+
+#ifndef __WINE_SERVER_REQUEST_H
+#define __WINE_SERVER_REQUEST_H
+
+enum request
+{
+    REQ_NEW_THREAD,
+    REQ_INIT_THREAD,
+    REQ_TERMINATE_PROCESS,
+    REQ_TERMINATE_THREAD,
+    REQ_GET_PROCESS_INFO,
+    REQ_CLOSE_HANDLE,
+    REQ_DUP_HANDLE,
+    REQ_OPEN_PROCESS,
+    REQ_NB_REQUESTS
+};
+
+#ifdef WANT_REQUEST_HANDLERS
+
+#define DECL_HANDLER(name) \
+    static void req_##name( struct name##_request *req, void *data, int len, int fd )
+
+DECL_HANDLER(new_thread);
+DECL_HANDLER(init_thread);
+DECL_HANDLER(terminate_process);
+DECL_HANDLER(terminate_thread);
+DECL_HANDLER(get_process_info);
+DECL_HANDLER(close_handle);
+DECL_HANDLER(dup_handle);
+DECL_HANDLER(open_process);
+
+static const struct handler {
+    void       (*handler)();
+    unsigned int min_size;
+} req_handlers[REQ_NB_REQUESTS] = {
+    { (void(*)())req_new_thread, sizeof(struct new_thread_request) },
+    { (void(*)())req_init_thread, sizeof(struct init_thread_request) },
+    { (void(*)())req_terminate_process, sizeof(struct terminate_process_request) },
+    { (void(*)())req_terminate_thread, sizeof(struct terminate_thread_request) },
+    { (void(*)())req_get_process_info, sizeof(struct get_process_info_request) },
+    { (void(*)())req_close_handle, sizeof(struct close_handle_request) },
+    { (void(*)())req_dup_handle, sizeof(struct dup_handle_request) },
+    { (void(*)())req_open_process, sizeof(struct open_process_request) },
+};
+#endif  /* WANT_REQUEST_HANDLERS */
+
+#endif  /* __WINE_SERVER_REQUEST_H */
diff --git a/include/server/thread.h b/include/server/thread.h
new file mode 100644
index 0000000..9edbfdf
--- /dev/null
+++ b/include/server/thread.h
@@ -0,0 +1,52 @@
+/*
+ * Wine server threads
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ */
+
+#ifndef __WINE_SERVER_THREAD_H
+#define __WINE_SERVER_THREAD_H
+
+#ifndef __WINE_SERVER__
+#error This file can only be used in the Wine server
+#endif
+
+#include "server/object.h"
+
+/* thread structure */
+
+struct process;
+
+struct thread
+{
+    struct object   obj;       /* object header */
+    struct thread  *next;      /* system-wide thread list */
+    struct thread  *prev;
+    struct thread  *proc_next; /* per-process thread list */
+    struct thread  *proc_prev;
+    struct process *process;
+    int             error;     /* current error code */
+    int             exit_code; /* thread exit code */
+    int             client_fd; /* client fd for socket communications */
+    int             unix_pid;  /* Unix pid of client */
+    enum request    last_req;  /* last request received (for debugging) */
+    char           *name;
+};
+
+extern struct thread *current;
+
+/* thread functions */
+
+extern struct thread *create_thread( int fd, void *pid, int *thread_handle,
+                                     int *process_handle );
+extern struct thread *get_thread_from_id( void *id );
+extern struct thread *get_thread_from_handle( int handle, unsigned int access );
+extern int send_reply( struct thread *thread, int pass_fd,
+                       int n, ... /* arg_1, len_1, ..., arg_n, len_n */ );
+extern void kill_thread( struct thread *thread, int exit_code );
+extern void thread_killed( struct thread *thread, int exit_code );
+
+#define SET_ERROR(err)  (current->error = (err))
+#define CLEAR_ERROR()   (current->error = 0)
+
+#endif  /* __WINE_SERVER_THREAD_H */
diff --git a/include/shell.h b/include/shell.h
index 27bb795..cda641c 100644
--- a/include/shell.h
+++ b/include/shell.h
@@ -25,6 +25,37 @@
 #define SHELL_ERROR_INVALID_PARAMETER 7L
 #define SHELL_ERROR_ACCESS_DENIED     8L
 
+/******************************
+* common shell file structures
+*/
+#define FO_MOVE           0x0001
+#define FO_COPY           0x0002
+#define FO_DELETE         0x0003
+#define FO_RENAME         0x0004
+
+#define FOF_MULTIDESTFILES         0x0001
+#define FOF_CONFIRMMOUSE           0x0002
+#define FOF_SILENT                 0x0004  
+#define FOF_RENAMEONCOLLISION      0x0008
+#define FOF_NOCONFIRMATION         0x0010  
+#define FOF_WANTMAPPINGHANDLE      0x0020  
+#define FOF_ALLOWUNDO              0x0040
+#define FOF_FILESONLY              0x0080  
+#define FOF_SIMPLEPROGRESS         0x0100  
+#define FOF_NOCONFIRMMKDIR         0x0200  
+#define FOF_NOERRORUI              0x0400  
+
+typedef WORD FILEOP_FLAGS;
+
+#define PO_DELETE       0x0013  
+#define PO_RENAME       0x0014  
+#define PO_PORTCHANGE   0x0020  
+
+typedef WORD PRINTEROP_FLAGS;
+
+/******************************
+* DROPFILESTRUCT
+*/
 typedef struct { 	   /* structure for dropped files */ 
 	WORD		wSize;
 	POINT16		ptMousePos;   
@@ -32,6 +63,9 @@
 	/* memory block with filenames follows */     
 } DROPFILESTRUCT, *LPDROPFILESTRUCT; 
 
+/******************************
+* NOTIFYICONDATA
+*/
 typedef struct _NOTIFYICONDATA {
 	DWORD cbSize;
 	HWND32 hWnd;
@@ -42,6 +76,29 @@
 	CHAR szTip[64];
 } NOTIFYICONDATA, *PNOTIFYICONDATA;
 
+/*******************************
+* SHITEMID, ITEMIDLIST, PIDL API
+*/
+typedef struct 
+{ WORD		cb;	/* nr of bytes in this item */
+  BYTE		abID[1];/* first byte in this item */
+} SHITEMID,*LPSHITEMID;
+
+typedef struct 
+{ SHITEMID mkid; /* first itemid in list */
+} ITEMIDLIST,*LPITEMIDLIST,*LPCITEMIDLIST;
+
+LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl);
+LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST iil1,LPCITEMIDLIST iil2);
+DWORD WINAPI ILGetSize(LPITEMIDLIST pidl);
+
+DWORD WINAPI SHGetPathFromIDList32A (LPCITEMIDLIST pidl,LPSTR pszPath);
+DWORD WINAPI SHGetPathFromIDList32W (LPCITEMIDLIST pidl,LPWSTR pszPath);
+#define  SHGetPathFromIDList WINELIB_NAME_AW(SHGetPathFromIDList)
+
+/****************************************************************************
+* SHFILEINFO API
+*/
 typedef struct tagSHFILEINFO32A {
 	HICON32	hIcon;			/* icon */
 	int	iIcon;			/* icon index */
@@ -60,6 +117,45 @@
 
 DECL_WINELIB_TYPE_AW(SHFILEINFO)
 
+DWORD    WINAPI SHGetFileInfo32A(LPCSTR,DWORD,SHFILEINFO32A*,UINT32,UINT32);
+DWORD    WINAPI SHGetFileInfo32W(LPCWSTR,DWORD,SHFILEINFO32W*,UINT32,UINT32);
+#define  SHGetFileInfo WINELIB_NAME_AW(SHGetFileInfo)
+
+/****************************************************************************
+* SHFILEOPSTRUCT API
+*/
+typedef struct _SHFILEOPSTRUCTA
+{ HWND32          hwnd;
+  UINT32          wFunc;
+  LPCSTR          pFrom;
+  LPCSTR          pTo;
+  FILEOP_FLAGS    fFlags;
+  BOOL32          fAnyOperationsAborted;
+  LPVOID          hNameMappings;
+  LPCSTR          lpszProgressTitle;
+} SHFILEOPSTRUCT32A, *LPSHFILEOPSTRUCT32A;
+
+typedef struct _SHFILEOPSTRUCTW
+{ HWND32          hwnd;
+  UINT32          wFunc;
+  LPCWSTR         pFrom;
+  LPCWSTR         pTo;
+  FILEOP_FLAGS    fFlags;
+  BOOL32          fAnyOperationsAborted;
+  LPVOID          hNameMappings;
+  LPCWSTR         lpszProgressTitle;
+} SHFILEOPSTRUCT32W, *LPSHFILEOPSTRUCT32W;
+
+typedef SHFILEOPSTRUCT32A SHFILEOPSTRUCT32;
+typedef LPSHFILEOPSTRUCT32A LPSHFILEOPSTRUCT32;
+
+DECL_WINELIB_TYPE_AW(SHFILEOPSTRUCT)
+
+DWORD WINAPI SHFileOperation32(LPSHFILEOPSTRUCT32 lpFileOp);
+
+/****************
+* APPBARDATA 
+*/
 typedef struct _AppBarData {
 	DWORD	cbSize;
 	HWND32	hWnd;
@@ -84,9 +180,33 @@
 #define SHGFI_SHELLICONSIZE     0x000000004     /* get shell size icon */
 #define SHGFI_PIDL              0x000000008     /* pszPath is a pidl */
 #define SHGFI_USEFILEATTRIBUTES 0x000000010     /* use passed dwFileAttribute */
-DWORD    WINAPI SHGetFileInfo32A(LPCSTR,DWORD,SHFILEINFO32A*,UINT32,UINT32);
-DWORD    WINAPI SHGetFileInfo32W(LPCWSTR,DWORD,SHFILEINFO32W*,UINT32,UINT32);
-#define  SHGetFileInfo WINELIB_NAME_AW(SHGetFileInfo)
+
+/****************************************************************************
+* SHChangeNotifyRegister API
+*/
+typedef struct
+{ LPITEMIDLIST pidl;
+  DWORD unknown;
+} IDSTRUCT;
+DWORD WINAPI SHChangeNotifyRegister(HWND32 hwnd,LONG events1,LONG events2,DWORD msg,int count,IDSTRUCT *idlist);
+DWORD WINAPI SHChangeNotifyDeregister(LONG x1,LONG x2);
+
+/****************************************************************************
+* SHAddToRecentDocs API
+*/
+#define SHARD_PIDL      0x00000001L
+#define SHARD_PATH      0x00000002L
+
+DWORD WINAPI SHAddToRecentDocs(UINT32 uFlags, LPCVOID pv);
+
+/****************************************************************************
+*  other functions
+*/
+LPVOID WINAPI SHAlloc(DWORD len);
+DWORD WINAPI SHFree(LPVOID x);
+LPSTR WINAPI PathAddBackslash(LPSTR path);	
+LPSTR WINAPI PathCombine(LPSTR target,LPSTR x1,LPSTR x2);
+LPSTR WINAPI PathRemoveBlanks(LPSTR str);
 
 #define SE_ERR_SHARE            26
 #define SE_ERR_ASSOCINCOMPLETE  27
@@ -113,4 +233,10 @@
 #define	CSIDL_FONTS		0x0014
 #define	CSIDL_TEMPLATES		0x0015
 
+/*******************************************
+*  global SHELL32.DLL variables
+*/
+extern HINSTANCE32 shell32_hInstance;
+extern UINT32      shell32_DllRefCount;
+
 #endif  /* __WINE_SHELL_H */
diff --git a/include/shlobj.h b/include/shlobj.h
index 4aed441..350fe57 100644
--- a/include/shlobj.h
+++ b/include/shlobj.h
@@ -5,6 +5,8 @@
 #include "ole.h"
 #include "ole2.h"
 #include "compobj.h"
+#include "storage.h"
+#include "commctrl.h"
 
 #define STDMETHOD(xfn) HRESULT (CALLBACK *fn##xfn)
 #define STDMETHOD_(type,xfn) type (CALLBACK *fn##xfn)
@@ -12,88 +14,41 @@
 #define FAR
 #define THIS_ THIS,
 
-/* common shell file structures*/
-#define FO_MOVE           0x0001
-#define FO_COPY           0x0002
-#define FO_DELETE         0x0003
-#define FO_RENAME         0x0004
 
-#define FOF_MULTIDESTFILES         0x0001
-#define FOF_CONFIRMMOUSE           0x0002
-#define FOF_SILENT                 0x0004  
-#define FOF_RENAMEONCOLLISION      0x0008
-#define FOF_NOCONFIRMATION         0x0010  
-#define FOF_WANTMAPPINGHANDLE      0x0020  
-#define FOF_ALLOWUNDO              0x0040
-#define FOF_FILESONLY              0x0080  
-#define FOF_SIMPLEPROGRESS         0x0100  
-#define FOF_NOCONFIRMMKDIR         0x0200  
-#define FOF_NOERRORUI              0x0400  
-typedef WORD FILEOP_FLAGS;
 
-#define PO_DELETE       0x0013  
-#define PO_RENAME       0x0014  
-#define PO_PORTCHANGE   0x0020  
+/****************************************************************************
+*  DllGetClassObject
+*/
+DWORD WINAPI SHELL32_DllGetClassObject(LPCLSID,REFIID,LPVOID*);
 
-typedef WORD PRINTEROP_FLAGS;
-
-typedef struct _SHFILEOPSTRUCTA
-{ HWND32          hwnd;
-  UINT32          wFunc;
-  LPCSTR          pFrom;
-  LPCSTR          pTo;
-  FILEOP_FLAGS    fFlags;
-  BOOL32          fAnyOperationsAborted;
-  LPVOID          hNameMappings;
-  LPCSTR          lpszProgressTitle;
-} SHFILEOPSTRUCT32A, FAR *LPSHFILEOPSTRUCT32A;
-
-typedef struct _SHFILEOPSTRUCTW
-{ HWND32          hwnd;
-  UINT32          wFunc;
-  LPCWSTR         pFrom;
-  LPCWSTR         pTo;
-  FILEOP_FLAGS    fFlags;
-  BOOL32          fAnyOperationsAborted;
-  LPVOID          hNameMappings;
-  LPCWSTR         lpszProgressTitle;
-} SHFILEOPSTRUCT32W, FAR *LPSHFILEOPSTRUCT32W;
-
-typedef SHFILEOPSTRUCT32A SHFILEOPSTRUCT32;
-typedef LPSHFILEOPSTRUCT32A LPSHFILEOPSTRUCT32;
-
-/*common IDList structures*/
-typedef struct {
-	WORD		cb;	/* nr of bytes in this item */
-	BYTE		abID[1];/* first byte in this item */
-} SHITEMID,*LPSHITEMID;
-
-typedef struct {
-	SHITEMID	mkid; /* first itemid in list */
-} ITEMIDLIST,*LPITEMIDLIST,*LPCITEMIDLIST;
-
-/* for SHChangeNotifyRegister*/
-typedef struct {
-   LPITEMIDLIST pidl;
-   DWORD unknown;
-} IDSTRUCT;
-
-/* for SHAddToRecentDocs*/
-#define SHARD_PIDL      0x00000001L
-#define SHARD_PATH      0x00000002L
 
 typedef LPVOID	LPBC; /* *IBindCtx really */
 
-/*
- * shell32 classids
- */
+/* foreward declaration of the objects*/
+typedef struct IEnumIDList IEnumIDList,*LPENUMIDLIST;
+typedef struct tagSHELLFOLDER *LPSHELLFOLDER,IShellFolder;
+typedef struct tagSHELLVIEW *LPSHELLVIEW,IShellView;
+typedef struct tagSHELLBROWSER *LPSHELLBROWSER,IShellBrowser;
+
+/****************************************************************************
+*  SHELL ID
+*/
+/* shell32 classids */
 DEFINE_SHLGUID(CLSID_ShellDesktop,      0x00021400L, 0, 0);
 DEFINE_SHLGUID(CLSID_ShellLink,         0x00021401L, 0, 0);
+/* shell32 formatids */
+DEFINE_SHLGUID(FMTID_Intshcut,          0x000214A0L, 0, 0);
+DEFINE_SHLGUID(FMTID_InternetSite,      0x000214A1L, 0, 0);
+/* command group ids */
+DEFINE_SHLGUID(CGID_Explorer,           0x000214D0L, 0, 0);
+DEFINE_SHLGUID(CGID_ShellDocView,       0x000214D1L, 0, 0);
 
-/*
- * shell32 Interface ids
- */
+ /* shell32 Interface ids */
+DEFINE_SHLGUID(IID_INewShortcutHookA,   0x000214E1L, 0, 0);
+DEFINE_SHLGUID(IID_IShellBrowser,       0x000214E2L, 0, 0);
+DEFINE_SHLGUID(IID_IShellView,          0x000214E3L, 0, 0);
 DEFINE_SHLGUID(IID_IContextMenu,        0x000214E4L, 0, 0);
+DEFINE_SHLGUID(IID_IShellIcon,          0x000214E5L, 0, 0);
 DEFINE_SHLGUID(IID_IShellFolder,        0x000214E6L, 0, 0);
 DEFINE_SHLGUID(IID_IShellExtInit,       0x000214E8L, 0, 0);
 DEFINE_SHLGUID(IID_IShellPropSheetExt,  0x000214E9L, 0, 0);
@@ -101,12 +56,25 @@
 DEFINE_SHLGUID(IID_IShellLink,          0x000214EEL, 0, 0);
 DEFINE_SHLGUID(IID_IShellCopyHook,      0x000214EFL, 0, 0);
 DEFINE_SHLGUID(IID_IFileViewer,         0x000214F0L, 0, 0);
+DEFINE_SHLGUID(IID_ICommDlgBrowser,     0x000214F1L, 0, 0);
 DEFINE_SHLGUID(IID_IEnumIDList,         0x000214F2L, 0, 0);
 DEFINE_SHLGUID(IID_IFileViewerSite,     0x000214F3L, 0, 0);
+DEFINE_SHLGUID(IID_IContextMenu2,       0x000214F4L, 0, 0);
+DEFINE_SHLGUID(IID_IShellExecuteHookA,  0x000214F5L, 0, 0);
+DEFINE_SHLGUID(IID_IPropSheetPage,      0x000214F6L, 0, 0);
+DEFINE_SHLGUID(IID_INewShortcutHookW,   0x000214F7L, 0, 0);
+DEFINE_SHLGUID(IID_IFileViewerW,        0x000214F8L, 0, 0);
+DEFINE_SHLGUID(IID_IShellLinkW,         0x000214F9L, 0, 0);
+DEFINE_SHLGUID(IID_IExtractIconW,       0x000214FAL, 0, 0);
+DEFINE_SHLGUID(IID_IShellExecuteHookW,  0x000214FBL, 0, 0);
+DEFINE_SHLGUID(IID_IShellCopyHookW,     0x000214FCL, 0, 0);
 
-#define	STRRET_WSTR	0x0000
+/****************************************************************************
+*  STRRET
+*/
+#define	STRRET_WSTR	    0x0000
 #define	STRRET_OFFSET	0x0001
-#define	STRRET_CSTR	0x0002
+#define	STRRET_CSTR	    0x0002
 
 typedef struct _STRRET
 { UINT32 uType;		/* STRRET_xxx */
@@ -126,18 +94,18 @@
 typedef enum tagPIDLTYPE
 { PT_DESKTOP = 0x00000000,
   PT_MYCOMP =  0x00000001,
-	PT_CONTROL = 0x00000002,
-	PT_RECYCLER =0x00000004,
+  PT_CONTROL = 0x00000002,
+  PT_RECYCLER =0x00000004,
   PT_DRIVE =   0x00000008,
   PT_FOLDER =  0x00000010,
-	PT_VALUE =   0x00000020,
+  PT_VALUE =   0x00000020,
   PT_TEXT = PT_FOLDER | PT_VALUE
 } PIDLTYPE;
 
 typedef struct tagPIDLDATA
 { PIDLTYPE type;
   CHAR    szText[1];
-}PIDLDATA, FAR *LPPIDLDATA;
+} PIDLDATA, FAR *LPPIDLDATA;
 
 typedef struct pidlmgr pidlmgr,*LPPIDLMGR;
 typedef struct PidlMgr_VTable
@@ -146,13 +114,11 @@
    STDMETHOD_(LPITEMIDLIST, CreateDrive) (THIS_ LPCSTR);
    STDMETHOD_(LPITEMIDLIST, CreateFolder) (THIS_ LPCSTR);
    STDMETHOD_(LPITEMIDLIST, CreateValue) (THIS_ LPCSTR);
-   STDMETHOD_(void, Delete) (THIS_ LPITEMIDLIST);
+/*   STDMETHOD_(void, Delete) (THIS_ LPITEMIDLIST);*/
    STDMETHOD_(LPITEMIDLIST, GetNextItem) (THIS_ LPCITEMIDLIST);
-   STDMETHOD_(LPITEMIDLIST, Copy) (THIS_ LPCITEMIDLIST);
-   STDMETHOD_(UINT16, GetSize) (THIS_ LPCITEMIDLIST);
    STDMETHOD_(BOOL32, GetDesktop) (THIS_ LPCITEMIDLIST, LPSTR);
    STDMETHOD_(BOOL32, GetDrive) (THIS_ LPCITEMIDLIST, LPSTR, UINT16);
-	 STDMETHOD_(LPITEMIDLIST, GetLastItem) (THIS_ LPCITEMIDLIST);
+   STDMETHOD_(LPITEMIDLIST, GetLastItem) (THIS_ LPCITEMIDLIST);
    STDMETHOD_(DWORD, GetItemText) (THIS_ LPCITEMIDLIST, LPSTR, UINT16);
    STDMETHOD_(BOOL32, IsDesktop) (THIS_ LPCITEMIDLIST);
    STDMETHOD_(BOOL32, IsMyComputer) (THIS_ LPCITEMIDLIST);
@@ -162,15 +128,9 @@
    STDMETHOD_(BOOL32, HasFolders) (THIS_ LPSTR, LPCITEMIDLIST);
    STDMETHOD_(DWORD, GetFolderText) (THIS_ LPCITEMIDLIST, LPSTR, DWORD);
    STDMETHOD_(DWORD, GetValueText) (THIS_ LPCITEMIDLIST, LPSTR, DWORD);
-   
-/*   STDMETHOD_(BOOL32, GetValueType) (THIS_ LPCITEMIDLIST, LPDWORD);*/
    STDMETHOD_(BOOL32, GetValueType) (THIS_ LPCITEMIDLIST, LPCITEMIDLIST, LPDWORD);
-   
-/*   STDMETHOD_(DWORD, GetDataText) (THIS_ LPCITEMIDLIST, LPSTR, DWORD);*/
    STDMETHOD_(DWORD, GetDataText) (THIS_ LPCITEMIDLIST, LPCITEMIDLIST, LPSTR, DWORD);
-   
    STDMETHOD_(DWORD, GetPidlPath) (THIS_ LPCITEMIDLIST, LPSTR, DWORD);
-   STDMETHOD_(LPITEMIDLIST, Concatenate) (THIS_ LPCITEMIDLIST, LPCITEMIDLIST);
    STDMETHOD_(LPITEMIDLIST, Create) (THIS_ PIDLTYPE, LPVOID, UINT16);
    STDMETHOD_(DWORD, GetData) (THIS_ PIDLTYPE, LPCITEMIDLIST, LPVOID, UINT16);
    STDMETHOD_(LPPIDLDATA, GetDataPointer) (THIS_ LPCITEMIDLIST);
@@ -179,8 +139,9 @@
 } *LPPIDLMGR_VTABLE,PidlMgr_VTable;
 
 struct pidlmgr 
-{	LPPIDLMGR_VTABLE	lpvtbl;
+{ LPPIDLMGR_VTABLE	lpvtbl;
 };
+
 #ifdef __WINE__
 extern LPPIDLMGR PidlMgr_Constructor();
 extern void PidlMgr_Destructor(THIS);
@@ -192,16 +153,16 @@
  * IEnumIDList interface
  */
 #define THIS LPENUMIDLIST this
+
 typedef struct tagENUMLIST
 { struct tagENUMLIST	*pNext;
   LPITEMIDLIST pidl;
 } ENUMLIST, *LPENUMLIST;
 
-typedef struct IEnumIDList IEnumIDList,*LPENUMIDLIST;
-typedef struct IEnumIDList_VTable {
-    /* *** IUnknown methods *** */
+typedef struct IEnumIDList_VTable 
+{    /* *** IUnknown methods *** */
     STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;
-		STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
+    STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
     STDMETHOD_(ULONG,Release) (THIS) PURE;
 
     /* *** IEnumIDList methods *** */
@@ -212,26 +173,79 @@
     STDMETHOD(Reset) (THIS) PURE;
     STDMETHOD(Clone) (THIS_ IEnumIDList **ppenum) PURE;
 		/* *** private methods *** */
-		STDMETHOD_(BOOL32,CreateEnumList)(THIS_ LPCSTR, DWORD) PURE;
+    STDMETHOD_(BOOL32,CreateEnumList)(THIS_ LPCSTR, DWORD) PURE;
     STDMETHOD_(BOOL32,AddToEnumList)(THIS_ LPITEMIDLIST) PURE;
     STDMETHOD_(BOOL32,DeleteList)(THIS) PURE;
 
 		
 } IEnumIDList_VTable,*LPENUMIDLIST_VTABLE;
 
-struct IEnumIDList {
-	LPENUMIDLIST_VTABLE	lpvtbl;
-	DWORD			 ref;
-	LPPIDLMGR  mpPidlMgr;
-	LPENUMLIST mpFirst;
-	LPENUMLIST mpLast;
-	LPENUMLIST mpCurrent;
-
+struct IEnumIDList
+{ LPENUMIDLIST_VTABLE	lpvtbl;
+  DWORD			 ref;
+  LPPIDLMGR  mpPidlMgr;
+  LPENUMLIST mpFirst;
+  LPENUMLIST mpLast;
+  LPENUMLIST mpCurrent;
 };
 
 #undef THIS
+//--------------------------------------------------------------------------
+//
+// FOLDERSETTINGS
+//
+//  FOLDERSETTINGS is a data structure that explorer passes from one folder
+// view to another, when the user is browsing. It calls ISV::GetCurrentInfo
+// member to get the current settings and pass it to ISV::CreateViewWindow
+// to allow the next folder view "inherit" it. These settings assumes a
+// particular UI (which the shell's folder view has), and shell extensions
+// may or may not use those settings.
+//
+//--------------------------------------------------------------------------
+
+typedef LPBYTE LPVIEWSETTINGS;
+
+// NB Bitfields.
+// FWF_DESKTOP implies FWF_TRANSPARENT/NOCLIENTEDGE/NOSCROLL
+typedef enum
+{ FWF_AUTOARRANGE =       0x0001,
+  FWF_ABBREVIATEDNAMES =  0x0002,
+  FWF_SNAPTOGRID =        0x0004,
+  FWF_OWNERDATA =         0x0008,
+  FWF_BESTFITWINDOW =     0x0010,
+  FWF_DESKTOP =           0x0020,
+  FWF_SINGLESEL =         0x0040,
+  FWF_NOSUBFOLDERS =      0x0080,
+  FWF_TRANSPARENT  =      0x0100,
+  FWF_NOCLIENTEDGE =      0x0200,
+  FWF_NOSCROLL     =      0x0400,
+  FWF_ALIGNLEFT    =      0x0800,
+  FWF_SINGLECLICKACTIVATE=0x8000  // TEMPORARY -- NO UI FOR THIS
+} FOLDERFLAGS;
+
+typedef enum
+{ FVM_ICON =              1,
+  FVM_SMALLICON =         2,
+  FVM_LIST =              3,
+  FVM_DETAILS =           4,
+} FOLDERVIEWMODE;
+
+typedef struct
+{ UINT32 ViewMode;       // View mode (FOLDERVIEWMODE values)
+  UINT32 fFlags;         // View options (FOLDERFLAGS bits)
+} FOLDERSETTINGS, *LPFOLDERSETTINGS;
+
+typedef const FOLDERSETTINGS * LPCFOLDERSETTINGS;
+
+/* FIXME; the next two lines are propersheet related, move to prsht.h when created */
+struct _PSP;
+typedef struct _PSP FAR* HPROPSHEETPAGE;
+
+typedef BOOL32 (CALLBACK FAR * LPFNADDPROPSHEETPAGE)(HPROPSHEETPAGE, LPARAM);
+typedef BOOL32 (CALLBACK FAR * LPFNADDPROPSHEETPAGES)(LPVOID, LPFNADDPROPSHEETPAGE,LPARAM);
+
 /************************************************************************
- * The IShellFolder interface ... the basic interface for a lot of stuff
+ * IShellFolder interface
  */
 
 #define THIS LPSHELLFOLDER this
@@ -279,50 +293,146 @@
 #define SFGAO_VALIDATE          0x01000000L     /* invalidate cached information */
 #define SFGAO_REMOVABLE        0x02000000L      /* is this removeable media? */
 
-
-typedef struct tagSHELLFOLDER *LPSHELLFOLDER,IShellFolder;
 typedef struct IShellFolder_VTable {
     /* *** IUnknown methods *** */
     STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;
     STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
     STDMETHOD_(ULONG,Release) (THIS) PURE;
-    /* *** IPersist Folder methods *** */
-/*		STDMETHOD(Initialize)(THIS_ LPCITEMIDLIST pidl) PURE; */
+
     /* *** IShellFolder methods *** */
-    STDMETHOD(ParseDisplayName) (THIS_ HWND32 hwndOwner,
-        LPBC pbcReserved, LPOLESTR32 lpszDisplayName,
-        ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes) PURE;
-    STDMETHOD(EnumObjects) ( THIS_ HWND32 hwndOwner, DWORD grfFlags, LPENUMIDLIST
-* ppenumIDList) PURE;
-    STDMETHOD(BindToObject)     (THIS_ LPCITEMIDLIST pidl, LPBC pbcReserved,
-                                 REFIID riid, LPVOID * ppvOut) PURE;
-    STDMETHOD(BindToStorage)    (THIS_ LPCITEMIDLIST pidl, LPBC pbcReserved,
-                                 REFIID riid, LPVOID * ppvObj) PURE;
-    STDMETHOD(CompareIDs)       (THIS_ LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) PURE;
-    STDMETHOD(CreateViewObject) (THIS_ HWND32 hwndOwner, REFIID riid, LPVOID * ppvOut) PURE;
-    STDMETHOD(GetAttributesOf)  (THIS_ UINT32 cidl, LPCITEMIDLIST * apidl,
-                                    ULONG * rgfInOut) PURE;
-    STDMETHOD(GetUIObjectOf)    (THIS_ HWND32 hwndOwner, UINT32 cidl, LPCITEMIDLIST
-* apidl,
-                                 REFIID riid, UINT32 * prgfInOut, LPVOID * ppvOut) PURE;
-    STDMETHOD(GetDisplayNameOf) (THIS_ LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName) PURE;
-    STDMETHOD(SetNameOf)        (THIS_ HWND32 hwndOwner, LPCITEMIDLIST pidl,
-                                 LPCOLESTR32 lpszName, DWORD uFlags,
-                                 LPITEMIDLIST * ppidlOut) PURE;
+    STDMETHOD(ParseDisplayName) (THIS_ HWND32 hwndOwner,LPBC pbcReserved, LPOLESTR32 lpszDisplayName,ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes) PURE;
+    STDMETHOD(EnumObjects)( THIS_ HWND32 hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumIDList) PURE;
+    STDMETHOD(BindToObject)(THIS_ LPCITEMIDLIST pidl, LPBC pbcReserved,REFIID riid, LPVOID * ppvOut) PURE;
+    STDMETHOD(BindToStorage)(THIS_ LPCITEMIDLIST pidl, LPBC pbcReserved,REFIID riid, LPVOID * ppvObj) PURE;
+    STDMETHOD(CompareIDs)(THIS_ LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) PURE;
+    STDMETHOD(CreateViewObject)(THIS_ HWND32 hwndOwner, REFIID riid, LPVOID * ppvOut) PURE;
+    STDMETHOD(GetAttributesOf)(THIS_ UINT32 cidl, LPCITEMIDLIST * apidl,ULONG * rgfInOut) PURE;
+    STDMETHOD(GetUIObjectOf)(THIS_ HWND32 hwndOwner, UINT32 cidl, LPCITEMIDLIST * apidl,REFIID riid, UINT32 * prgfInOut, LPVOID * ppvOut) PURE;
+    STDMETHOD(GetDisplayNameOf)(THIS_ LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName) PURE;
+    STDMETHOD(SetNameOf)(THIS_ HWND32 hwndOwner, LPCITEMIDLIST pidl,LPCOLESTR32 lpszName, DWORD uFlags,LPITEMIDLIST * ppidlOut) PURE;
 } *LPSHELLFOLDER_VTABLE,IShellFolder_VTable;
 
 struct tagSHELLFOLDER {
 	LPSHELLFOLDER_VTABLE	lpvtbl;
 	DWORD			   ref;
 	LPSTR        mlpszFolder;
-  LPPIDLMGR	   pPidlMgr;
+    LPPIDLMGR	   pPidlMgr;
 	LPITEMIDLIST mpidl;
 	LPITEMIDLIST mpidlNSRoot;
 	LPSHELLFOLDER mpSFParent;
 };
+
 extern LPSHELLFOLDER pdesktopfolder;
 #undef THIS
 
+/************************************************************************
+* IShellBrowser Inteface
+*/
+#define THIS LPSHELLBROWSER this
+
+typedef struct IShellBrowser_VTable 
+{    // *** IUnknown methods ***
+    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;
+    STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
+    STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+    // *** IOleWindow methods ***
+    STDMETHOD(GetWindow) (THIS_ HWND32 * lphwnd) PURE;
+    STDMETHOD(ContextSensitiveHelp) (THIS_ BOOL32 fEnterMode) PURE;
+
+    // *** IShellBrowser methods *** (same as IOleInPlaceFrame)
+    STDMETHOD(InsertMenusSB) (THIS_ HMENU32 hmenuShared, LPOLEMENUGROUPWIDTHS32 lpMenuWidths) PURE;
+    STDMETHOD(SetMenuSB) (THIS_ HMENU32 hmenuShared, HOLEMENU32 holemenuReserved, HWND32 hwndActiveObject) PURE;
+    STDMETHOD(RemoveMenusSB) (THIS_ HMENU32 hmenuShared) PURE;
+    STDMETHOD(SetStatusTextSB) (THIS_ LPCOLESTR32 lpszStatusText) PURE;
+    STDMETHOD(EnableModelessSB) (THIS_ BOOL32 fEnable) PURE;
+    STDMETHOD(TranslateAcceleratorSB) (THIS_ LPMSG32 lpmsg, WORD wID) PURE;
+
+    // *** IShellBrowser methods ***
+    STDMETHOD(BrowseObject)(THIS_ LPCITEMIDLIST pidl, UINT32 wFlags) PURE;
+    STDMETHOD(GetViewStateStream)(THIS_ DWORD grfMode, LPSTREAM32  *ppStrm) PURE;
+    STDMETHOD(GetControlWindow)(THIS_ UINT32 id, HWND32 * lphwnd) PURE;
+    STDMETHOD(SendControlMsg)(THIS_ UINT32 id, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam, LRESULT * pret) PURE;
+    STDMETHOD(QueryActiveShellView)(THIS_ IShellView ** ppshv) PURE;
+    STDMETHOD(OnViewWindowActive)(THIS_ IShellView * ppshv) PURE;
+    STDMETHOD(SetToolbarItems)(THIS_ LPTBBUTTON lpButtons, UINT32 nButtons, UINT32 uFlags) PURE;
+} *LPSHELLBROWSER_VTABLE,IShellBrowser_VTable;;
+
+struct tagSHELLBROWSER 
+{ LPSHELLBROWSER_VTABLE	lpvtbl;
+  DWORD	ref;
+};
+
+#undef THIS
+
+/************************************************************************
+* IShellView Inteface
+*/
+#define THIS LPSHELLVIEW this
+
+/* shellview select item flags*/
+#define SVSI_DESELECT   0x0000
+#define SVSI_SELECT     0x0001
+#define SVSI_EDIT       0x0003  // includes select
+#define SVSI_DESELECTOTHERS 0x0004
+#define SVSI_ENSUREVISIBLE  0x0008
+#define SVSI_FOCUSED        0x0010
+
+/* shellview get item object flags */
+#define SVGIO_BACKGROUND    0x00000000
+#define SVGIO_SELECTION     0x00000001
+#define SVGIO_ALLVIEW       0x00000002
+
+/* uState values for IShellView::UIActivate */
+typedef enum 
+{ SVUIA_DEACTIVATE       = 0,
+  SVUIA_ACTIVATE_NOFOCUS = 1,
+  SVUIA_ACTIVATE_FOCUS   = 2,
+  SVUIA_INPLACEACTIVATE  = 3          // new flag for IShellView2
+} SVUIA_STATUS;
+
+
+
+typedef struct IShellView_VTable
+{   // *** IUnknown methods ***
+    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;
+    STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
+    STDMETHOD_(ULONG,Release) (THIS) PURE;
+
+    // *** IOleWindow methods ***
+    STDMETHOD(GetWindow) (THIS_ HWND32 * lphwnd) PURE;
+    STDMETHOD(ContextSensitiveHelp) (THIS_ BOOL32 fEnterMode) PURE;
+
+    // *** IShellView methods ***
+    STDMETHOD(TranslateAccelerator) (THIS_ LPMSG32 lpmsg) PURE;
+    STDMETHOD(EnableModeless) (THIS_ BOOL32 fEnable) PURE;
+    STDMETHOD(UIActivate) (THIS_ UINT32 uState) PURE;
+    STDMETHOD(Refresh) (THIS) PURE;
+    STDMETHOD(CreateViewWindow)(THIS_ IShellView *lpPrevView,LPCFOLDERSETTINGS lpfs, IShellBrowser * psb,RECT32 * prcView, HWND32  *phWnd) PURE;
+    STDMETHOD(DestroyViewWindow)(THIS) PURE;
+    STDMETHOD(GetCurrentInfo)(THIS_ LPFOLDERSETTINGS lpfs) PURE;
+    STDMETHOD(AddPropertySheetPages)(THIS_ DWORD dwReserved,LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam) PURE;
+    STDMETHOD(SaveViewState)(THIS) PURE;
+    STDMETHOD(SelectItem)(THIS_ LPCITEMIDLIST pidlItem, UINT32 uFlags) PURE;
+    STDMETHOD(GetItemObject)(THIS_ UINT32 uItem, REFIID riid,LPVOID *ppv) PURE;
+} IShellView_VTable,*LPSHELLVIEW_VTABLE;;
+
+struct tagSHELLVIEW 
+{ LPSHELLVIEW_VTABLE lpvtbl;
+  DWORD			     ref;
+  LPITEMIDLIST       mpidl;
+  LPSHELLFOLDER      pSFParent;
+  LPSHELLBROWSER     pShellBrowser;
+  HWND32             hWnd;
+  FOLDERSETTINGS     FolderSettings;
+  HWND32             hWndParent;
+};
+
+typedef GUID SHELLVIEWID;
+#define SV_CLASS_NAME   ("ShellViewClass")
+
+#undef THIS
+
 /****************************************************************************
  * IShellLink interface
  */
@@ -389,8 +499,10 @@
 #undef THIS
 
 #ifdef __WINE__
+
 extern LPCLASSFACTORY IClassFactory_Constructor();
 extern LPSHELLFOLDER IShellFolder_Constructor(LPSHELLFOLDER,LPITEMIDLIST);
+extern LPSHELLVIEW IShellView_Constructor();
 extern LPSHELLLINK IShellLink_Constructor();
 extern LPENUMIDLIST IEnumIDList_Constructor(LPCSTR,DWORD,HRESULT*);
 #endif
@@ -452,8 +564,6 @@
 #define BFFM_SETSELECTIONW      (WM_USER+103)
 #define BFFM_SETSTATUSTEXTW     (WM_USER+104)
 
-
-
 /*
 #ifdef UNICODE
 #define SHBrowseForFolder   SHBrowseForFolderW
@@ -470,10 +580,30 @@
 #endif 
 */
 
+LPITEMIDLIST WINAPI SHBrowseForFolder32A(LPBROWSEINFO32A lpbi);
+/*LPITEMIDLIST WINAPI SHBrowseForFolder32W(LPBROWSEINFO32W lpbi);*/
+#define  SHBrowseForFolder WINELIB_NAME_AW(SHBrowseForFolder)
+
 /****************************************************************************
  * shlview structures
  */
-typedef HRESULT(CALLBACK *SHELLVIEWPROC)(DWORD dwUserParam,LPSHELLFOLDER psf,HWND32 hwnd,UINT32 uMsg,UINT32 wParam,LPARAM lParam);
+/*
+* IShellFolderViewCallback Callback
+*  This "callback" is called by the shells default IShellView implementation (that
+*  we got using SHCreateShellViewEx()), to notify us of the various things that
+*  are happening to the shellview (and ask for things too).
+*
+*  You don't have to support anything here - anything you don't want to 
+*  handle, the shell will do itself if you just return E_NOTIMPL. This parameters
+*  that the shell passes to this function are entirely undocumented.
+*
+*  HOWEVER, as the cabview sample as originally written used this callback, the
+*  writers implemented the callback mechanism on top of their own IShellView.
+*  Look there for some clues on what to do here.
+*/
+
+typedef HRESULT(CALLBACK *SHELLVIEWPROC)(DWORD dwUserParam,LPSHELLFOLDER psf,
+                         HWND32 hwnd,UINT32 uMsg,UINT32 wParam,LPARAM lParam);
 
 /* NF valid values for the "viewmode" item of the SHELLTEMPLATE*/
 #define NF_INHERITVIEW    0x0000
@@ -489,22 +619,6 @@
   DWORD           viewmode;  // NF_* enum
 } SHELLVIEWDATA, * LPSHELLVIEWDATA;
 
-/****************************************************************************
- * functions
- */
-
-DWORD  WINAPI ILGetSize(LPITEMIDLIST iil);
-DWORD  WINAPI SHAddToRecentDocs(UINT32 uFlags, LPCVOID pv);
-LPVOID WINAPI SHAlloc(DWORD len);
-LPITEMIDLIST WINAPI SHBrowseForFolder32A(LPBROWSEINFO32A lpbi);
-/*LPITEMIDLIST WINAPI SHBrowseForFolder32W(LPBROWSEINFO32W lpbi);*/
-DWORD  WINAPI SHChangeNotifyRegister(HWND32 hwnd,LONG events1,LONG events2,DWORD msg,int count,IDSTRUCT *idlist);
-DWORD  WINAPI SHELL32_DllGetClassObject(LPCLSID,REFIID,LPVOID*);
-DWORD  WINAPI SHFileOperation32(LPSHFILEOPSTRUCT32 lpFileOp);
-LPSTR  WINAPI PathAddBackslash(LPSTR path);	
-LPSTR  WINAPI PathRemoveBlanks(LPSTR str);
-
-
 #undef PURE
 #undef FAR
 #undef THIS
diff --git a/include/stackframe.h b/include/stackframe.h
index 7a0196a..24cad98 100644
--- a/include/stackframe.h
+++ b/include/stackframe.h
@@ -18,13 +18,13 @@
 typedef struct _STACK32FRAME
 {
     SEGPTR  frame16;        /* 00 16-bit frame from last CallFrom16() */
-    DWORD   edi;            /* 04 saved registers */
-    DWORD   esi;            /* 08 */
-    DWORD   edx;            /* 0c */
-    DWORD   ecx;            /* 10 */
-    DWORD   ebx;            /* 14 */
-    DWORD   restore_addr;   /* 18 return address for restoring code selector */
-    DWORD   codeselector;   /* 1c code selector to restore */
+    DWORD   restore_addr;   /* 04 return address for restoring code selector */
+    DWORD   codeselector;   /* 08 code selector to restore */
+    DWORD   edi;            /* 0c saved registers */
+    DWORD   esi;            /* 10 */
+    DWORD   edx;            /* 14 */
+    DWORD   ecx;            /* 18 */
+    DWORD   ebx;            /* 1c */
     DWORD   ebp;            /* 20 saved 32-bit frame pointer */
     DWORD   retaddr;        /* 24 actual return address */
     DWORD   args[1];        /* 28 arguments to 16-bit function */
@@ -35,14 +35,16 @@
 {
     STACK32FRAME *frame32;        /* 00 32-bit frame from last CallTo16() */
     DWORD         ebp;            /* 04 full 32-bit content of ebp */
-    WORD          entry_ip;       /* 08 ip of entry point */
-    WORD          ds;             /* 0a ds */
-    WORD          entry_cs;       /* 0c cs of entry point */
-    WORD          es;             /* 0e es */
-    DWORD         entry_point;    /* 10 32-bit entry point to call */
-    WORD          bp;             /* 14 16-bit bp */
-    WORD          ip;             /* 16 return address */
-    WORD          cs;             /* 18 */
+    WORD          mutex_count;    /* 08 Win16Mutex recursion count */
+    WORD          fs;             /* 0a fs */
+    WORD          entry_ip;       /* 0c ip of entry point */
+    WORD          ds;             /* 0e ds */
+    WORD          entry_cs;       /* 10 cs of entry point */
+    WORD          es;             /* 12 es */
+    DWORD         entry_point;    /* 14 32-bit entry point to call */
+    WORD          bp;             /* 18 16-bit bp */
+    WORD          ip;             /* 1a return address */
+    WORD          cs;             /* 1c */
 } STACK16FRAME;
 
 #pragma pack(4)
diff --git a/include/status.h b/include/status.h
index 7bf2b4c..45323f4 100644
--- a/include/status.h
+++ b/include/status.h
@@ -24,6 +24,7 @@
     UINT16              textHeight;
     UINT32              height;
     BOOL32              simple;
+    HWND32              hwndToolTip;
     HFONT32             hFont;
     HFONT32             hDefaultFont;
     COLORREF            clrBk;  /* background color */
diff --git a/include/syslevel.h b/include/syslevel.h
new file mode 100644
index 0000000..56ac846
--- /dev/null
+++ b/include/syslevel.h
@@ -0,0 +1,28 @@
+/*
+ * Win32 'syslevel' routines
+ *
+ * Copyright 1998 Ulrich Weigand
+ */
+
+#ifndef __WINE_SYSLEVEL_H
+#define __WINE_SYSLEVEL_H
+
+#include "wintypes.h"
+#include "winbase.h"
+
+void SYSLEVEL_Init(void);
+VOID SYSLEVEL_EnterWin16Lock(VOID);
+VOID SYSLEVEL_LeaveWin16Lock(VOID);
+VOID SYSLEVEL_ReleaseWin16Lock(VOID);
+VOID SYSLEVEL_RestoreWin16Lock(VOID);
+
+VOID WINAPI GetpWin16Lock32(CRITICAL_SECTION **lock);
+SEGPTR WINAPI GetpWin16Lock16(void);
+
+VOID WINAPI _EnterSysLevel(CRITICAL_SECTION *lock);
+VOID WINAPI _LeaveSysLevel(CRITICAL_SECTION *lock);
+
+VOID WINAPI ReleaseThunkLock(DWORD *mutex_count);
+VOID WINAPI RestoreThunkLock(DWORD mutex_count);
+
+#endif  /* __WINE_SYSLEVEL_H */
diff --git a/include/thread.h b/include/thread.h
index 8d81fd2..e033b29 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -9,6 +9,7 @@
 
 #include "k32obj.h"
 #include "windows.h"
+#include "winbase.h"
 #include "winnt.h"
 #include "selectors.h"  /* for SET_FS */
 
@@ -41,6 +42,7 @@
     DWORD         count;     /* Count of valid objects */
     DWORD         signaled;  /* Index of signaled object (or WAIT_FAILED)*/
     BOOL32        wait_all;  /* Wait for all objects flag */
+    BOOL32        wait_msg;  /* Wait for message flag */
     K32OBJ       *objs[MAXIMUM_WAIT_OBJECTS];  /* Object pointers */
 } WAIT_STRUCT;
 
@@ -70,7 +72,7 @@
     DWORD          cur_stack;      /*  80 Current stack (was: unknown) */
     DWORD          unknown3[2];    /*  84 Unknown */
     WORD           current_ss;     /*  8c Another 16-bit stack selector */
-    WORD           saved_fs;       /*  8e Saved 16-bit FS (was: pad2) */
+    WORD           pad2;           /*  8e */
     void          *ss_table;       /*  90 Pointer to info about 16-bit stack */
     WORD           thunk_ss;       /*  94 Yet another 16-bit stack selector */
     WORD           pad3;           /*  96 */
@@ -82,12 +84,10 @@
     void          *entry_point;    /* 1c0 Thread entry point (was: unknown) */
     void          *entry_arg;      /* 1c4 Entry point arg (was: unknown) */
     int            unix_pid;       /* 1c8 Unix thread pid (was: unknown) */
-    DWORD          unknown5[6];    /* 1cc Unknown */
-    K32OBJ        *crit_section;   /* 1e4 Some critical section */
-    K32OBJ        *win16_mutex;    /* 1e8 Pointer to Win16 mutex */
-    K32OBJ        *win32_mutex;    /* 1ec Pointer to KERNEL32 mutex */
-    K32OBJ        *crit_section2;  /* 1f0 Another critical section */
-    K32OBJ        *mutex_list;     /* 1f4 List of owned mutex (was: unknown)*/
+    K32OBJ        *mutex_list;     /* 1cc List of owned mutex (was: unknown)*/
+    DWORD          unknown5[2];    /* 1d0 Unknown */
+    DWORD          sys_count[4];   /* 1d8 Syslevel mutex entry counters */
+    CRITICAL_SECTION *sys_mutex[4];/* 1e8 Syslevel mutex pointers */
     DWORD          unknown6[2];    /* 1f8 Unknown */
     /* The following are Wine-specific fields */
     CONTEXT        context;        /* 200 Thread context */
@@ -125,9 +125,11 @@
 /* scheduler/thread.c */
 extern THDB *THREAD_Create( struct _PDB32 *pdb, DWORD stack_size,
                             BOOL32 alloc_stack16,
+                            int *server_thandle, int *server_phandle,
                             LPTHREAD_START_ROUTINE start_addr, LPVOID param );
 extern THDB *THREAD_Current(void);
-extern THDB *THREAD_GetPtr( HANDLE32 handle, DWORD access );
+extern void THREAD_Start( THDB *thdb );
+extern THDB *THREAD_GetPtr( HANDLE32 handle, DWORD access, int *server_handle );
 extern void THREAD_AddQueue( THREAD_QUEUE *queue, THDB *thread );
 extern void THREAD_RemoveQueue( THREAD_QUEUE *queue, THDB *thread );
 extern DWORD THREAD_TlsAlloc( THDB *thread );
@@ -142,7 +144,12 @@
 /* scheduler/synchro.c */
 extern void SYNC_WaitForCondition( WAIT_STRUCT *wait, DWORD timeout );
 extern void SYNC_WakeUp( THREAD_QUEUE *queue, DWORD max );
+extern void SYNC_MsgWakeUp( THDB *thdb );
 extern void SYNC_SetupSignals(void);
+extern DWORD SYNC_DoWait( DWORD count, const HANDLE32 *handles,
+                          BOOL32 wait_all, DWORD timeout,
+                          BOOL32 alertable, BOOL32 wait_msg );
+
 
 /* scheduler/sysdeps.c */
 extern int SYSDEPS_SpawnThread( THDB *thread );
diff --git a/include/tooltips.h b/include/tooltips.h
index 95e2a6c..b4875c0 100644
--- a/include/tooltips.h
+++ b/include/tooltips.h
@@ -18,7 +18,7 @@
     LPSTR  lpszText;
     LPARAM lParam;
 
-
+    WNDPROC32 lpfnOrigProc;
 } TTTOOL_INFO; 
 
 
@@ -26,21 +26,23 @@
 {
     CHAR       szTipText[INFOTIPSIZE];
     BOOL32     bActive;
+    BOOL32     bTrackActive;
     UINT32     uNumTools;
     COLORREF   clrBk;
     COLORREF   clrText;
     HFONT32    hFont;
+    INT32      xTrackPos;
+    INT32      yTrackPos;
     INT32      nMaxTipWidth;
     INT32      nTool;
     INT32      nOldTool;
     INT32      nCurrentTool;
-
+    INT32      nTrackTool;
     INT32      nAutomaticTime;
     INT32      nReshowTime;
     INT32      nAutoPopTime;
     INT32      nInitialTime;
     RECT32     rcMargin;
-
     TTTOOL_INFO *tools;
 } TOOLTIPS_INFO;
 
diff --git a/include/tweak.h b/include/tweak.h
index 02ac88a..346f6a0 100644
--- a/include/tweak.h
+++ b/include/tweak.h
@@ -13,17 +13,11 @@
 
 int  TWEAK_Init();
 int  TWEAK_CheckConfiguration();
-INT32  TWEAK_PartyMessageBox(LPCSTR, LPCSTR, DWORD);
 void  TWEAK_DrawReliefRect95(HDC32, RECT32 const *);
 void  TWEAK_DrawRevReliefRect95(HDC32, RECT32 const *);
 void  TWEAK_DrawMenuSeparatorHoriz95(HDC32, UINT32, UINT32, UINT32);
 void  TWEAK_DrawMenuSeparatorVert95(HDC32, UINT32, UINT32, UINT32);
 extern int  TWEAK_Win95Look;
 extern int  TWEAK_WineInitialized;
-extern HPEN32  TWEAK_PenFF95;
-extern HPEN32  TWEAK_PenE095;
-extern HPEN32  TWEAK_PenC095;
-extern HPEN32  TWEAK_Pen8095;
-extern HPEN32  TWEAK_Pen0095;
 
 #endif /* __WINE_TWEAK_H */
diff --git a/include/user.h b/include/user.h
index d1f891c..00cd9ae 100644
--- a/include/user.h
+++ b/include/user.h
@@ -29,7 +29,7 @@
 #define USUD_LOCALHEAP         0x0004
 #define USUD_FIRSTCLASS        0x0005
 
-void USER_SignalProc(HANDLE16, UINT16, UINT16, HINSTANCE16, HQUEUE16);
+void WINAPI USER_SignalProc(HANDLE16, UINT16, UINT16, HINSTANCE16, HQUEUE16);
 void USER_ExitWindows(void);
 HGLOBAL16 USER_CallDefaultRsrcHandler( HGLOBAL16 hMemObj, HMODULE16 hModule,
 				       HRSRC16 hRsrc );
diff --git a/include/ver.h b/include/ver.h
index 5f5dd97..93433b8 100644
--- a/include/ver.h
+++ b/include/ver.h
@@ -109,7 +109,7 @@
 #define	VIF_OUTOFMEMORY		0x00008000L
 #define	VIF_CANNOTREADSRC	0x00010000L
 #define	VIF_CANNOTREADDST	0x00020000L
-#define	VIF_BUFTOSMALL		0x00040000L
+#define	VIF_BUFFTOOSMALL	0x00040000L
 
 typedef struct tagVS_FIXEDFILEINFO {
 	DWORD   dwSignature;
diff --git a/include/version.h b/include/version.h
index 2eeda85..2311c01 100644
--- a/include/version.h
+++ b/include/version.h
@@ -1 +1 @@
-#define WINE_RELEASE_INFO "Wine release 980726"
+#define WINE_RELEASE_INFO "Wine release 980809"
diff --git a/include/windows.h b/include/windows.h
index a8bee8a..a94c819 100644
--- a/include/windows.h
+++ b/include/windows.h
@@ -5203,25 +5203,38 @@
 
 /* Process startup information.
  */
+
+/* STARTUPINFO.dwFlags */
+#define	STARTF_USESHOWWINDOW	0x00000001
+#define	STARTF_USESIZE		0x00000002
+#define	STARTF_USEPOSITION	0x00000004
+#define	STARTF_USECOUNTCHARS	0x00000008
+#define	STARTF_USEFILLATTRIBUTE	0x00000010
+#define	STARTF_RUNFULLSCREEN	0x00000020
+#define	STARTF_FORCEONFEEDBACK	0x00000040
+#define	STARTF_FORCEOFFFEEDBACK	0x00000080
+#define	STARTF_USESTDHANDLES	0x00000100
+#define	STARTF_USEHOTKEY	0x00000200
+
 typedef struct {
-        DWORD cb;
-        LPSTR lpReserved;
-        LPSTR lpDesktop;
-        LPSTR lpTitle;
-        DWORD dwX;
-        DWORD dwY;
-        DWORD dwXSize;
-        DWORD dwYSize;
-        DWORD dwXCountChars;
-        DWORD dwYCountChars;
-        DWORD dwFillAttribute;
-        DWORD dwFlags;
-        WORD wShowWindow;
-        WORD cbReserved2;
-        BYTE *lpReserved2;
-        HANDLE32 hStdInput;
-        HANDLE32 hStdOutput;
-        HANDLE32 hStdError;
+        DWORD cb;		/* 00: size of struct */
+        LPSTR lpReserved;	/* 04: */
+        LPSTR lpDesktop;	/* 08: */
+        LPSTR lpTitle;		/* 0c: */
+        DWORD dwX;		/* 10: */
+        DWORD dwY;		/* 14: */
+        DWORD dwXSize;		/* 18: */
+        DWORD dwYSize;		/* 1c: */
+        DWORD dwXCountChars;	/* 20: */
+        DWORD dwYCountChars;	/* 24: */
+        DWORD dwFillAttribute;	/* 28: */
+        DWORD dwFlags;		/* 2c: */
+        WORD wShowWindow;	/* 30: */
+        WORD cbReserved2;	/* 32: */
+        BYTE *lpReserved2;	/* 34: */
+        HANDLE32 hStdInput;	/* 38: */
+        HANDLE32 hStdOutput;	/* 3c: */
+        HANDLE32 hStdError;	/* 40: */
 } STARTUPINFO32A, *LPSTARTUPINFO32A;
 
 typedef struct {
@@ -5504,6 +5517,7 @@
 DECL_WINELIB_TYPE_AW(DEVMODE)
 DECL_WINELIB_TYPE_AW(LPDEVMODE)
 
+
 #define DM_UPDATE	1
 #define DM_COPY		2
 #define DM_PROMPT	4
@@ -5519,7 +5533,8 @@
 #define DM_PRINTQUALITY		0x00000400L
 #define DM_COLOR		0x00000800L
 #define DM_DUPLEX		0x00001000L
-
+#define DM_YRESOLUTION		0x00002000L
+#define DM_TTOPTION		0x00004000L
 #define DM_BITSPERPEL           0x00040000L
 #define DM_PELSWIDTH            0x00080000L
 #define DM_PELSHEIGHT           0x00100000L
@@ -5531,13 +5546,34 @@
 #define DMORIENT_PORTRAIT	1
 #define DMORIENT_LANDSCAPE	2
 
-#define DMPAPER_LETTER	1
-#define DMPAPER_A3	8
-#define DMPAPER_A4	9
-#define DMPAPER_A5	11
+#define DMPAPER_LETTER		1
+#define DMPAPER_LEGAL		5
+#define DMPAPER_EXECUTIVE	7
+#define DMPAPER_A3		8
+#define DMPAPER_A4		9
+#define DMPAPER_A5		11
+#define DMPAPER_ENV_10		20
+#define DMPAPER_ENV_DL		27
+#define DMPAPER_ENV_C5		28
+#define DMPAPER_ENV_B5		34
+#define DMPAPER_ENV_MONARCH	37
 
-#define DMBIN_UPPER	1
-#define DMBIN_AUTO	7
+#define DMBIN_UPPER		1
+#define DMBIN_LOWER		2
+#define DMBIN_MIDDLE		3
+#define DMBIN_MANUAL		4
+#define DMBIN_ENVELOPE		5
+#define DMBIN_ENVMANUAL		6
+#define DMBIN_AUTO		7
+#define DMBIN_LARGECAPACITY	11
+
+#define DMCOLOR_MONOCHROME	1
+#define DMCOLOR_COLOR		2
+
+#define DMTT_BITMAP		1
+#define DMTT_DOWNLOAD		2
+#define DMTT_SUBDEV		3
+
 
 #define DC_FIELDS		1
 #define DC_PAPERS		2
@@ -5558,6 +5594,7 @@
 #define DC_ORIENTATION		17
 #define DC_COPIES		18
 
+
 typedef struct _PRINTER_DEFAULTS32A {
     LPSTR        pDatatype;
     LPDEVMODE32A pDevMode;
@@ -6705,6 +6742,7 @@
 #define     RegUnLoadKey WINELIB_NAME_AW(RegUnLoadKey)
 BOOL32      WINAPI ReleaseSemaphore(HANDLE32,LONG,LPLONG);
 BOOL32      WINAPI ResetEvent(HANDLE32);
+DWORD       WINAPI ResumeThread(HANDLE32);
 VOID        WINAPI RtlFillMemory(LPVOID,UINT32,UINT32);
 VOID        WINAPI RtlMoveMemory(LPVOID,LPCVOID,UINT32);
 VOID        WINAPI RtlZeroMemory(LPVOID,UINT32);
@@ -6754,6 +6792,7 @@
 BOOL32      WINAPI StartService32A(HANDLE32,DWORD,LPCSTR*);
 BOOL32      WINAPI StartService32W(HANDLE32,DWORD,LPCWSTR*);
 #define     StartService WINELIB_NAME_AW(StartService)
+DWORD       WINAPI SuspendThread(HANDLE32);
 BOOL32      WINAPI SystemTimeToFileTime(const SYSTEMTIME*,LPFILETIME);
 WORD        WINAPI TileWindows (HWND32, UINT32, const LPRECT32,
                                 UINT32, const HWND32 *);
@@ -6990,7 +7029,7 @@
 HWND16      WINAPI ChildWindowFromPoint16(HWND16,POINT16);
 HWND32      WINAPI ChildWindowFromPoint32(HWND32,POINT32);
 #define     ChildWindowFromPoint WINELIB_NAME(ChildWindowFromPoint)
-INT32       ChoosePixelFormat(HDC32,PIXELFORMATDESCRIPTOR*);
+INT32       WINAPI ChoosePixelFormat(HDC32,PIXELFORMATDESCRIPTOR*);
 BOOL16      WINAPI Chord16(HDC16,INT16,INT16,INT16,INT16,INT16,INT16,INT16,INT16);
 BOOL32      WINAPI Chord32(HDC32,INT32,INT32,INT32,INT32,INT32,INT32,INT32,INT32);
 #define     Chord WINELIB_NAME(Chord)
@@ -8426,6 +8465,9 @@
 BOOL16      WINAPI PolyBezier16(HDC16,LPPOINT16,INT16);
 BOOL32      WINAPI PolyBezier32(HDC32,LPPOINT32,DWORD);
 #define     PolyBezier WINELIB_NAME(PolyBezier)
+BOOL16      WINAPI PolyBezierTo16(HDC16,LPPOINT16,INT16);
+BOOL32      WINAPI PolyBezierTo32(HDC32,LPPOINT32,DWORD);
+#define     PolyBezierTo WINELIB_NAME(PolyBezierTo)
 BOOL16      WINAPI PolyPolygon16(HDC16,LPPOINT16,LPINT16,UINT16);
 BOOL32      WINAPI PolyPolygon32(HDC32,LPPOINT32,LPINT32,UINT32);
 #define     PolyPolygon WINELIB_NAME(PolyPolygon)
diff --git a/include/winerror.h b/include/winerror.h
index 8c6c8d6..12f1727 100644
--- a/include/winerror.h
+++ b/include/winerror.h
@@ -66,6 +66,11 @@
 #define ERROR_NO_NETWORK            1222
 #define ERROR_ALREADY_INITIALIZED   1247
 #define ERROR_PRIVILEGE_NOT_HELD    1314
+#define ERROR_CANNOT_FIND_WND_CLASS 1407
+#define ERROR_WINDOW_OF_OTHER_THREAD 1408
+#define ERROR_CLASS_ALREADY_EXISTS  1410
+#define ERROR_CLASS_DOES_NOT_EXIST  1411
+#define ERROR_CLASS_HAS_WINDOWS     1412
 #define ERROR_COMMITMENT_LIMIT      1455
 #define ERROR_INVALID_PRINTER_NAME  1801
 
@@ -155,4 +160,7 @@
 #define	E_FAIL				0x80000008
 #define E_ACCESSDENIED			0x80000009 */
 
+/* Obtained from lcc-win32 include files */
+#define GDI_ERROR			0xffffffff
+
 #endif  /* __WINE_WINERROR_H */
diff --git a/include/winnt.h b/include/winnt.h
index 44fc732..bb44df9 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -148,6 +148,9 @@
 #define SET_CFLAG(context)   (EFL_reg(context) |= 0x0001)
 #define RESET_CFLAG(context) (EFL_reg(context) &= 0xfffffffe)
 
+#define ISV86(context)       (EFL_reg(context) & 0x00020000)
+#define V86BASE(context)     ((context)->Dr7) /* ugly */
+
 #endif  /* __WINE__ */
 
 /*
diff --git a/include/winsock.h b/include/winsock.h
index aa4bdca..363615b 100644
--- a/include/winsock.h
+++ b/include/winsock.h
@@ -557,6 +557,12 @@
   INT16			last_free;		/* entry in the socket table */
   UINT16		buflen;
   char*			buffer;			/* allocated from SEGPTR heap */
+  struct ws_hostent	*he;
+  int			helen;
+  struct ws_servent	*se;
+  int			selen;
+  struct ws_protoent	*pe;
+  int			pelen;
   char*			dbuffer;		/* buffer for dummies (32 bytes) */
 
   ws_socket		sock[WS_MAX_SOCKETS_PER_PROCESS];
diff --git a/loader/dos/Makefile.in b/loader/dos/Makefile.in
new file mode 100644
index 0000000..c605049
--- /dev/null
+++ b/loader/dos/Makefile.in
@@ -0,0 +1,19 @@
+DEFS      = @DLLFLAGS@ -D__WINE__
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = dos
+
+C_SRCS = \
+	module.c \
+	dosvm.c
+
+all: $(MODULE).o dosmod
+
+dosmod: dosmod.c
+	$(CC) $(ALLCFLAGS) -o dosmod $<
+
+@MAKE_RULES@
+
+### Dependencies:
diff --git a/loader/dos/dosmod.c b/loader/dos/dosmod.c
new file mode 100644
index 0000000..b5ad24f
--- /dev/null
+++ b/loader/dos/dosmod.c
@@ -0,0 +1,77 @@
+/*
+ * DOS Virtual Machine
+ *
+ * Copyright 1998 Ove Kåven
+ */
+
+#ifdef linux
+
+/* force dosmod at high addresses */
+asm(".org 0x110000");
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/vm86.h>
+#include <sys/syscall.h>
+
+/* FIXME: hack because libc vm86 may be the old syscall version */
+static __inline__ int vm86plus( int func, struct vm86plus_struct *ptr )
+{
+    int res;
+#ifdef __PIC__
+    __asm__ __volatile__( "pushl %%ebx\n\t"
+                          "movl %2,%%ebx\n\t"
+                          "int $0x80\n\t"
+                          "popl %%ebx"
+                          : "=a" (res)
+                          : "0" (SYS_vm86),
+                            "g" (func),
+                            "c" (ptr) );
+#else
+    __asm__ __volatile__("int $0x80"
+                         : "=a" (res)
+                         : "0" (SYS_vm86),
+                           "b" (func),
+                           "c" (ptr) );
+#endif  /* __PIC__ */
+    if (res >= 0) return res;
+    errno = -res;
+    return -1;
+}
+
+int main(int argc,char**argv)
+{
+ int mfd=open(argv[0],O_RDWR);
+ void*img;
+ struct vm86plus_struct VM86;
+ int func,ret;
+ 
+/* fprintf(stderr,"main is at %08lx, file is %s, fd=%d\n",(unsigned long)&main,argv[0],mfd); */
+ if (mfd<0) return 1;
+/* Map in our DOS image at the start of the process address space */
+ img=mmap(NULL,0x110000,PROT_EXEC|PROT_READ|PROT_WRITE,MAP_FIXED|MAP_SHARED,mfd,0);
+ if (img==(void*)-1) {
+  fprintf(stderr,"DOS memory map failed, error=%s\n",strerror(errno));
+  return 1;
+ }
+/* fprintf(stderr,"Successfully mapped DOS memory, entering vm86 loop\n"); */
+/* context exchange loop */
+ do {
+  if (read(0,&func,sizeof(func))!=sizeof(func)) return 1;
+  if (read(0,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
+  if (func<0) break;
+  ret=vm86plus(func,&VM86);
+  if (write(1,&ret,sizeof(ret))!=sizeof(ret)) return 1;
+  if (write(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1;
+ } while (1);
+ return 0;
+}
+
+#else /* !linux */
+int main(void) {return 1;}
+#endif
diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c
new file mode 100644
index 0000000..3818daa
--- /dev/null
+++ b/loader/dos/dosvm.c
@@ -0,0 +1,118 @@
+/*
+ * DOS Virtual Machine
+ *
+ * Copyright 1998 Ove Kåven
+ */
+
+#ifdef linux
+ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "windows.h"
+#include "winbase.h"
+#include "msdos.h"
+#include "miscemu.h"
+#include "debug.h"
+#include "module.h"
+#include "ldt.h"
+#include "dosexe.h"
+
+void DOSVM_Dump( LPDOSTASK lpDosTask)
+{
+ unsigned iofs;
+ BYTE*inst;
+ int x;
+
+ switch (VM86_TYPE(lpDosTask->fn)) {
+  case VM86_SIGNAL:
+   printf("Trapped signal\n"); break;
+  case VM86_UNKNOWN:
+   printf("Trapped unhandled GPF\n"); break;
+  case VM86_INTx:
+   printf("Trapped INT %02x\n",VM86_ARG(lpDosTask->fn)); break;
+  case VM86_STI:
+   printf("Trapped STI\n"); break;
+  case VM86_PICRETURN:
+   printf("Trapped due to pending PIC request\n"); break;
+  case VM86_TRAP:
+   printf("Trapped debug request\n"); break;
+ }
+#define REGS lpDosTask->VM86.regs
+ fprintf(stderr,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS.eax,REGS.ebx,REGS.ecx,REGS.edx);
+ fprintf(stderr,"SI=%04lX DI=%04lX SP=%04lX BP=%04lX\n",REGS.esi,REGS.edi,REGS.esp,REGS.ebp);
+ fprintf(stderr,"CS=%04X DS=%04X ES=%04X SS=%04X\n",REGS.cs,REGS.ds,REGS.es,REGS.ss);
+
+ iofs=((DWORD)REGS.cs<<4)+REGS.eip;
+#undef REGS
+ inst=(BYTE*)lpDosTask->img+iofs;
+ printf("Opcodes:");
+ for (x=0; x<8; x++) printf(" %02x",inst[x]);
+ printf("\n");
+
+ exit(0);
+}
+
+int DOSVM_Int(int vect, LPDOSTASK lpDosTask, PCONTEXT context )
+{
+ switch (vect) {
+  case 0x20:
+   return -1;
+  case 0x21:
+   if (AH_reg(context)==0x4c) return -1;
+   DOS3Call(context);
+   break;
+ }
+ return 0;
+}
+
+int DOSVM_Process( LPDOSTASK lpDosTask )
+{
+ CONTEXT context;
+ int ret=0;
+
+#define REGS lpDosTask->VM86.regs
+ context.Eax=REGS.eax; context.Ecx=REGS.ecx; context.Edx=REGS.edx; context.Ebx=REGS.ebx;
+ context.Esi=REGS.esi; context.Edi=REGS.edi; context.Esp=REGS.esp; context.Ebp=REGS.ebp;
+ context.SegCs=REGS.cs; context.SegDs=REGS.ds; context.SegEs=REGS.es;
+ context.SegSs=REGS.ss; context.SegFs=REGS.fs; context.SegGs=REGS.gs;
+ context.Eip=REGS.eip; context.EFlags=REGS.eflags;
+ (void*)V86BASE(&context)=lpDosTask->img;
+
+ switch (VM86_TYPE(lpDosTask->fn)) {
+  case VM86_SIGNAL:
+   printf("Trapped signal\n");
+   ret=-1; break;
+  case VM86_UNKNOWN:
+   DOSVM_Dump(lpDosTask);
+   break;
+  case VM86_INTx:
+   TRACE(int,"DOS EXE calls INT %02x\n",VM86_ARG(lpDosTask->fn));
+   ret=DOSVM_Int(VM86_ARG(lpDosTask->fn),lpDosTask,&context); break;
+  case VM86_STI:
+   break;
+  case VM86_PICRETURN:
+   printf("Trapped due to pending PIC request\n"); break;
+  case VM86_TRAP:
+   printf("Trapped debug request\n"); break;
+  default:
+   DOSVM_Dump(lpDosTask);
+ }
+
+ lpDosTask->fn=VM86_ENTER;
+ REGS.eax=context.Eax; REGS.ecx=context.Ecx; REGS.edx=context.Edx; REGS.ebx=context.Ebx;
+ REGS.esi=context.Esi; REGS.edi=context.Edi; REGS.esp=context.Esp; REGS.ebp=context.Ebp;
+ REGS.cs=context.SegCs; REGS.ds=context.SegDs; REGS.es=context.SegEs;
+ REGS.ss=context.SegSs; REGS.fs=context.SegFs; REGS.gs=context.SegGs;
+ REGS.eip=context.Eip; REGS.eflags=context.EFlags;
+#undef REGS
+ return ret;
+}
+
+#endif /* linux */
diff --git a/loader/dos/module.c b/loader/dos/module.c
new file mode 100644
index 0000000..053c2c3
--- /dev/null
+++ b/loader/dos/module.c
@@ -0,0 +1,313 @@
+/*
+ * DOS (MZ) loader
+ *
+ * Copyright 1998 Ove Kåven
+ */
+
+#ifdef linux
+ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef MZ_USESYSV
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#else
+#include <sys/mman.h>
+#endif
+#include <sys/vm86.h>
+#ifdef MZ_USESYSV
+#include <linux/mm.h> /* FIXME: where else should I fetch the PAGE_SIZE define? */
+#endif
+#include "windows.h"
+#include "winbase.h"
+#include "module.h"
+#include "task.h"
+#include "ldt.h"
+#include "process.h"
+#include "miscemu.h"
+#include "debug.h"
+#include "dosexe.h"
+
+#define BIOS_DATA_SEGMENT 0x40
+#define BIOS_SEGMENT BIOSSEG /* BIOSSEG is defined to 0xf000 in sys/vm86.h */
+#define STUB_SEGMENT BIOS_SEGMENT
+#ifdef MZ_USESYSV
+/* it might be that SYSV supports START_OFFSET 0 after all, haven't checked */
+#define START_OFFSET PAGE_SIZE
+#else
+#define START_OFFSET 0
+#endif
+#define PSP_SIZE 0x10
+
+#define SEG16(ptr,seg) ((LPVOID)((BYTE*)ptr+((DWORD)(seg)<<4)))
+#define SEGPTR16(ptr,segptr) ((LPVOID)((BYTE*)ptr+((DWORD)SELECTOROF(segptr)<<4)+OFFSETOF(segptr)))
+
+#define STUB(x) (0x90CF00CD|(x<<8)) /* INT x; IRET; NOP */
+
+static void MZ_InitSystem( LPVOID lpImage )
+{
+ SEGPTR*isr=lpImage;
+ DWORD*stub=SEG16(lpImage,STUB_SEGMENT);
+ int x;
+ 
+ /* initialize ISR table to make it point to INT stubs in BIOSSEG;
+    Linux only sends INTs performed from or destined to BIOSSEG at us,
+    if the int_revectored table is empty.
+    This allows DOS programs to hook interrupts, as well as use their
+    familiar retf tricks to call them... */
+ /* (note that the hooking might not actually work since DOS3Call stuff
+     isn't fully integrated with the DOS VM yet...) */
+ TRACE(module,"Initializing interrupt vector table\n");
+ for (x=0; x<256; x++) isr[x]=PTR_SEG_OFF_TO_SEGPTR(STUB_SEGMENT,x*4);
+ TRACE(module,"Initializing interrupt stub table\n");
+ for (x=0; x<256; x++) stub[x]=STUB(x);
+}
+
+static void MZ_InitPSP( LPVOID lpPSP, LPCSTR cmdline, LPCSTR env )
+{
+ PDB*psp=lpPSP;
+ const char*cmd=cmdline?strchr(cmdline,' '):NULL;
+
+ psp->int20=0x20CD; /* int 20 */
+ /* some programs use this to calculate how much memory they need */
+ psp->nextParagraph=0x9FFF;
+ /* copy parameters */
+ if (cmd) {
+  while (*cmd == ' ') cmd++;
+  psp->cmdLine[0]=strlen(cmd);
+  strcpy(psp->cmdLine+1,cmd);
+  psp->cmdLine[psp->cmdLine[0]+1]='\r';
+ } else psp->cmdLine[1]='\r';
+ /* FIXME: integrate the memory stuff from Wine (msdos/dosmem.c) */
+ /* FIXME: integrate the PDB stuff from Wine (loader/task.c) */
+}
+
+static int MZ_LoadImage( HFILE16 hFile, LPCSTR cmdline, LPCSTR env, LPDOSTASK lpDosTask )
+{
+ IMAGE_DOS_HEADER mz_header;
+ DWORD image_start,image_size,min_size,max_size,avail;
+ WORD psp_seg,load_seg;
+ BYTE*psp_start,*load_start;
+ int x;
+ SEGPTR reloc;
+
+ if ((_hread16(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
+     (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
+     return 11; /* invalid exe */
+ /* calculate load size */
+ image_start=mz_header.e_cparhdr<<4;
+ image_size=mz_header.e_cp<<9; /* pages are 512 bytes */
+ if ((mz_header.e_cblp!=0)&&(mz_header.e_cblp!=4)) image_size-=512-mz_header.e_cblp;
+ image_size-=image_start;
+ min_size=image_size+((DWORD)mz_header.e_minalloc<<4)+(PSP_SIZE<<4);
+ max_size=image_size+((DWORD)mz_header.e_maxalloc<<4)+(PSP_SIZE<<4);
+
+ /* allocate 1MB+64K shared memory */
+ lpDosTask->img_ofs=START_OFFSET;
+#ifdef MZ_USESYSV
+ lpDosTask->key=ftok(".",'d'); /* FIXME: this is from my IPC intro doc */
+ lpDosTask->shm_id=shmget(lpDosTask->key,0x110000-START_OFFSET,IPC_CREAT|SHM_R|SHM_W);
+ lpDosTask->img=shmat(lpDosTask->shm_id,NULL,0);
+#else
+ tmpnam(lpDosTask->mm_name);
+/* strcpy(lpDosTask->mm_name,"/tmp/mydosimage"); */
+ lpDosTask->mm_fd=open(lpDosTask->mm_name,O_RDWR|O_CREAT /* |O_TRUNC */,S_IRUSR|S_IWUSR);
+ if (lpDosTask->mm_fd<0) ERR(module,"file %s could not be opened\n",lpDosTask->mm_name);
+ /* expand file to 1MB+64K */
+ lseek(lpDosTask->mm_fd,0x110000-1,SEEK_SET);
+ x=0; write(lpDosTask->mm_fd,&x,1);
+ /* map it in */
+ lpDosTask->img=mmap(NULL,0x110000-START_OFFSET,PROT_READ|PROT_WRITE,MAP_SHARED,lpDosTask->mm_fd,0);
+#endif
+ if (lpDosTask->img==(LPVOID)-1) {
+  ERR(module,"could not map shared memory, error=%s\n",strerror(errno));
+  return 0;
+ }
+ TRACE(module,"DOS VM86 image mapped at %08lx\n",(DWORD)lpDosTask->img);
+
+ /* initialize the memory */
+ MZ_InitSystem(lpDosTask->img);
+ TRACE(module,"Initializing DOS memory structures\n");
+ DOSMEM_Init(lpDosTask->hModule);
+
+ /* FIXME: allocate memory for environment variables */
+
+ /* allocate memory for the executable */
+ TRACE(module,"Allocating DOS memory (min=%ld, max=%ld)\n",min_size,max_size);
+ avail=DOSMEM_Available(lpDosTask->hModule);
+ if (avail<min_size) {
+  ERR(module, "insufficient DOS memory\n");
+  return 0;
+ }
+ if (avail>max_size) avail=max_size;
+ psp_start=DOSMEM_GetBlock(lpDosTask->hModule,avail,&psp_seg);
+ if (!psp_start) {
+  ERR(module, "error allocating DOS memory\n");
+  return 0;
+ }
+ load_seg=psp_seg+PSP_SIZE;
+ load_start=psp_start+(PSP_SIZE<<4);
+ MZ_InitPSP(psp_start, cmdline, env);
+
+ /* load executable image */
+ TRACE(module,"loading DOS EXE image size, %08lx bytes\n",image_size);
+ _llseek16(hFile,image_start,FILE_BEGIN);
+ if ((_hread16(hFile,load_start,image_size)) != image_size)
+  return 11; /* invalid exe */
+
+ /* load relocation table */
+ TRACE(module,"loading DOS EXE relocation table, %d entries\n",mz_header.e_lfarlc);
+ /* FIXME: is this too slow without read buffering? */
+ _llseek16(hFile,mz_header.e_lfarlc,FILE_BEGIN);
+ for (x=0; x<mz_header.e_crlc; x++) {
+  if (_lread16(hFile,&reloc,sizeof(reloc)) != sizeof(reloc))
+   return 11; /* invalid exe */
+  *(WORD*)SEGPTR16(load_start,reloc)+=load_seg;
+ }
+
+ /* initialize vm86 struct */
+ memset(&lpDosTask->VM86,0,sizeof(lpDosTask->VM86));
+ lpDosTask->VM86.regs.cs=load_seg+mz_header.e_cs;
+ lpDosTask->VM86.regs.eip=mz_header.e_ip;
+ lpDosTask->VM86.regs.ss=load_seg+mz_header.e_ss;
+ lpDosTask->VM86.regs.esp=mz_header.e_sp;
+ lpDosTask->VM86.regs.ds=psp_seg;
+ lpDosTask->VM86.regs.es=psp_seg;
+ /* hmm, what else do we need? */
+
+ return 32;
+}
+
+static int MZ_InitTask( LPDOSTASK lpDosTask )
+{
+ int read_fd[2],write_fd[2];
+ pid_t child;
+
+ /* create read pipe */
+ if (pipe(read_fd)<0) return 0;
+ if (pipe(write_fd)<0) {
+  close(read_fd[0]); close(read_fd[1]); return 0;
+ }
+ lpDosTask->read_pipe=read_fd[0];
+ lpDosTask->write_pipe=write_fd[1];
+ lpDosTask->fn=VM86_ENTER;
+ lpDosTask->state=1;
+ TRACE(module,"Preparing to load DOS EXE support module: forking\n");
+ if ((child=fork())<0) {
+  close(write_fd[0]); close(write_fd[1]);
+  close(read_fd[0]); close(read_fd[1]); return 0;
+ }
+ if (child!=0) {
+  /* parent process */
+  close(read_fd[1]); close(write_fd[0]);
+  lpDosTask->task=child;
+ } else {
+  /* child process */
+  close(read_fd[0]); close(write_fd[1]);
+  /* put our pipes somewhere dosmod can find them */
+  dup2(write_fd[0],0);      /* stdin */
+  dup2(read_fd[1],1);       /* stdout */
+  /* now load dosmod */
+  execlp("dosmod",lpDosTask->mm_name,NULL);
+  execl("dosmod",lpDosTask->mm_name,NULL);
+  execl("loader/dos/dosmod",lpDosTask->mm_name,NULL);
+  /* if failure, exit */
+  ERR(module,"Failed to spawn dosmod, error=%s\n",strerror(errno));
+  exit(1);
+ }
+ return 32;
+}
+
+HINSTANCE16 MZ_LoadModule( LPCSTR name, LPCSTR cmdline, 
+                           LPCSTR env, UINT16 show_cmd )
+{
+ LPDOSTASK lpDosTask;
+ HMODULE16 hModule;
+ HINSTANCE16 hInstance;
+ NE_MODULE *pModule;
+ HFILE16 hFile;
+ OFSTRUCT ofs;
+ PROCESS_INFORMATION info;
+ int err;
+
+ if ((lpDosTask = calloc(1, sizeof(DOSTASK))) == NULL)
+  return 0;
+
+ if ((hFile = OpenFile16( name, &ofs, OF_READ )) == HFILE_ERROR16)
+  return 2; /* File not found */
+
+ if ((hModule = MODULE_CreateDummyModule(&ofs)) < 32)
+  return hModule;
+
+ lpDosTask->hModule = hModule;
+
+ pModule = (NE_MODULE *)GlobalLock16(hModule);
+ pModule->lpDosTask = lpDosTask;
+ 
+ lpDosTask->img=NULL; lpDosTask->mm_name[0]=0; lpDosTask->mm_fd=-1;
+ err = MZ_LoadImage( hFile, cmdline, env, lpDosTask );
+ _lclose16(hFile);
+ if (err<32) {
+  if (lpDosTask->img!=NULL) munmap(lpDosTask->img,0x110000-START_OFFSET);
+  if (lpDosTask->mm_fd>=0) close(lpDosTask->mm_fd);
+  if (lpDosTask->mm_name[0]!=0) unlink(lpDosTask->mm_name);
+  return err;
+ }
+ MZ_InitTask( lpDosTask );
+
+ hInstance = NE_CreateInstance(pModule, NULL, (cmdline == NULL));
+ PROCESS_Create( pModule, cmdline, env, hInstance, 0, show_cmd, &info );
+ /* we don't need the handles for now */
+ CloseHandle( info.hThread );
+ CloseHandle( info.hProcess );
+ return hInstance;
+}
+
+void MZ_KillModule( LPDOSTASK lpDosTask )
+{
+ munmap(lpDosTask->img,0x110000-START_OFFSET);
+ close(lpDosTask->mm_fd);
+ unlink(lpDosTask->mm_name);
+ close(lpDosTask->read_pipe);
+ close(lpDosTask->write_pipe);
+ kill(lpDosTask->task,SIGTERM);
+}
+
+int MZ_RunModule( LPDOSTASK lpDosTask )
+{
+/* transmit the current context structure to the DOS task */
+ if (lpDosTask->state==1) {
+  if (write(lpDosTask->write_pipe,&lpDosTask->fn,sizeof(lpDosTask->fn))!=sizeof(lpDosTask->fn))
+   return -1;
+  if (write(lpDosTask->write_pipe,&lpDosTask->VM86,sizeof(lpDosTask->VM86))!=sizeof(lpDosTask->VM86))
+   return -1;
+  lpDosTask->state=2;
+ }
+/* wait for another context structure to appear (this may block) */
+ if (lpDosTask->state==2) {
+  if (read(lpDosTask->read_pipe,&lpDosTask->fn,sizeof(lpDosTask->fn))!=sizeof(lpDosTask->fn)) {
+   if ((errno==EINTR)||(errno==EAGAIN)) return 0;
+   return -1;
+  }
+  lpDosTask->state=3;
+ }
+ if (lpDosTask->state==3) {
+  if (read(lpDosTask->read_pipe,&lpDosTask->VM86,sizeof(lpDosTask->VM86))!=sizeof(lpDosTask->VM86)) {
+   if ((errno==EINTR)||(errno==EAGAIN)) return 0;
+   return -1;
+  }
+/* got one */
+  lpDosTask->state=1;
+  return 1;
+ }
+ return 0;
+}
+
+#endif /* linux */
diff --git a/loader/main.c b/loader/main.c
index 5f592a6..d859bfd 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -35,6 +35,7 @@
 #include "dce.h"
 #include "shell.h"
 #include "winproc.h"
+#include "syslevel.h"
 #include "debug.h"
 
 
@@ -45,6 +46,9 @@
  */
 BOOL32 MAIN_KernelInit(void)
 {
+    /* Initialize syslevel handling */
+    SYSLEVEL_Init();
+
     /* Initialize signal handling */
     if (!SIGNAL_Init()) return FALSE;
 
@@ -52,7 +56,7 @@
     if (!PROFILE_LoadWineIni()) return FALSE;
 
       /* Initialize DOS memory */
-    if (!DOSMEM_Init()) return FALSE;
+    if (!DOSMEM_Init(0)) return FALSE;
 
     /* Initialise DOS drives */
     if (!DRIVE_Init()) return FALSE;
diff --git a/loader/module.c b/loader/module.c
index b6f859b..21d5665 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -18,6 +18,7 @@
 #include "module.h"
 #include "neexe.h"
 #include "pe_image.h"
+#include "dosexe.h"
 #include "process.h"
 #include "thread.h"
 #include "resource.h"
@@ -313,6 +314,10 @@
                                  (cmd_line == NULL) );
         if ((hInstance == 21) && cmd_line)
             return PE_LoadModule( name, cmd_line, env, show_cmd );
+#ifdef linux
+        if (hInstance == 11)
+            return MZ_LoadModule(name, cmd_line, env, show_cmd );
+#endif
     }
 
     /* Create a task for this instance */
@@ -322,11 +327,15 @@
     if (cmd_line && !(pModule->flags & NE_FFLAGS_LIBMODULE))
     {
         PDB32 *pdb;
+        PROCESS_INFORMATION info;
 
 	pModule->flags |= NE_FFLAGS_GUI;
 
         pdb = PROCESS_Create( pModule, cmd_line, env, hInstance,
-                              hPrevInstance, show_cmd );
+                              hPrevInstance, show_cmd, &info );
+        /* we don't need the handles for now */
+        CloseHandle( info.hThread );
+        CloseHandle( info.hProcess );
         if (pdb && (GetNumTasks() > 1)) Yield16();
     }
 
@@ -337,7 +346,7 @@
 /**********************************************************************
  *	    LoadModule16    (KERNEL.45)
  */
-HINSTANCE16 LoadModule16( LPCSTR name, LPVOID paramBlock )
+HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock )
 {
     LOADPARAMS *params;
     LPSTR cmd_line, new_cmd_line;
@@ -379,7 +388,7 @@
  *  This should get implemented via CreateProcess -- MODULE_Load
  *  is resolutely 16-bit.
  */
-DWORD LoadModule32( LPCSTR name, LPVOID paramBlock ) 
+DWORD WINAPI LoadModule32( LPCSTR name, LPVOID paramBlock ) 
 {
     LOADPARAMS32 *params = (LOADPARAMS32 *)paramBlock;
 #if 0
diff --git a/loader/ne/module.c b/loader/ne/module.c
index 0bf46e4..c085678 100644
--- a/loader/ne/module.c
+++ b/loader/ne/module.c
@@ -1020,13 +1020,17 @@
  * Find a module from a path name.
  *
  * RETURNS
+ *   LOWORD:
  *	the win16 module handle if found
  * 	0 if not
+ *   HIWORD (undocumented, see "Undocumented Windows", chapter 5):
+ *	Always hFirstModule
  */
-HMODULE16 WINAPI WIN16_GetModuleHandle( SEGPTR name )
+DWORD WINAPI WIN16_GetModuleHandle( SEGPTR name )
 {
-    if (HIWORD(name) == 0) return GetExePtr( (HINSTANCE16)name );
-    return GetModuleHandle16( PTR_SEG_TO_LIN(name) );
+    if (HIWORD(name) == 0)
+	return MAKELONG(GetExePtr( (HINSTANCE16)name), hFirstModule );
+    return MAKELONG(GetModuleHandle16( PTR_SEG_TO_LIN(name)), hFirstModule );
 }
 
 HMODULE16 WINAPI GetModuleHandle16( LPCSTR name )
diff --git a/loader/ne/segment.c b/loader/ne/segment.c
index 1c47dd1..ff92d5c 100644
--- a/loader/ne/segment.c
+++ b/loader/ne/segment.c
@@ -425,8 +425,13 @@
         /* some BootApp procs overwrite the selector of dgroup */
         pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
         thdb->cur_stack = oldstack;
-        for (i = 2; i <= pModule->seg_count; i++)
-            if (!NE_LoadSegment( pModule, i )) return FALSE;
+
+	/* FIXME
+	commented out by Andreas Mohr;
+	some self-loading exe ("BLINKER") relies on non-primary segs not loaded.
+	contact me if you experience problems */
+        /*for (i = 2; i <= pModule->seg_count; i++)
+            if (!NE_LoadSegment( pModule, i )) return FALSE;*/
     }
     else
     {
@@ -580,7 +585,7 @@
 static BOOL32 NE_InitDLL( TDB* pTask, NE_MODULE *pModule )
 {
     SEGTABLEENTRY *pSegTable;
-    WORD hInst, ds, heap, fs;
+    WORD hInst, ds, heap;
     CONTEXT context;
 
     pSegTable = NE_SEG_TABLE( pModule );
@@ -611,13 +616,11 @@
     memset( &context, 0, sizeof(context) );
 
     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
-    GET_FS( fs );
 
     ECX_reg(&context) = heap;
     EDI_reg(&context) = hInst;
     DS_reg(&context)  = ds;
     ES_reg(&context)  = ds;   /* who knows ... */
-    FS_reg(&context)  = fs;
 
     CS_reg(&context)  = pSegTable[pModule->cs-1].selector;
     EIP_reg(&context) = pModule->ip;
@@ -641,7 +644,7 @@
 
 static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason )
 {
-    WORD hInst, ds, heap, fs;
+    WORD hInst, ds, heap;
     FARPROC16 entryPoint;
     WORD ordinal;
     CONTEXT context;
@@ -655,11 +658,9 @@
     memset( &context, 0, sizeof(context) );
 
     NE_GetDLLInitParams( pModule, &hInst, &ds, &heap );
-    GET_FS( fs );
 
     DS_reg(&context) = ds;
     ES_reg(&context) = ds;   /* who knows ... */
-    FS_reg(&context) = fs;
 
     CS_reg(&context) = HIWORD(entryPoint);
     IP_reg(&context) = LOWORD(entryPoint);
@@ -745,6 +746,7 @@
                                  pModule->self, FALSE, FALSE, FALSE );
     if (!hNewInstance) return 0;
     pSegment->selector = hNewInstance;
+    pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
     return hNewInstance;
 }
 
@@ -821,6 +823,7 @@
                                       FALSE,
                             FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
         if (!pSegment->selector) return FALSE;
+	pSegment->flags |= NE_SEGFLAGS_ALLOCATED;
     }
 
     pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
diff --git a/loader/pe_image.c b/loader/pe_image.c
index 5d5a51c..76dc87e 100644
--- a/loader/pe_image.c
+++ b/loader/pe_image.c
@@ -854,10 +854,14 @@
     if (cmd_line &&
         !(PE_HEADER(hModule32)->FileHeader.Characteristics & IMAGE_FILE_DLL))
     {
+        PROCESS_INFORMATION info;
         PDB32 *pdb = PROCESS_Create( pModule, cmd_line, env,
-                                     hInstance, 0, show_cmd );
+                                     hInstance, 0, show_cmd, &info );
         TDB *pTask = (TDB *)GlobalLock16( pdb->task );
         thdb = pTask->thdb;
+        /* we don't need the handles for now */
+        CloseHandle( info.hThread );
+        CloseHandle( info.hProcess );
     }
 
     process = thdb->process;
diff --git a/loader/resource.c b/loader/resource.c
index 4f0d28d..bff00b9 100644
--- a/loader/resource.c
+++ b/loader/resource.c
@@ -550,7 +550,7 @@
 /**********************************************************************
  *	LoadMessage32A		(internal)
  */
-INT32 LoadMessage32A( HMODULE32 instance, UINT32 id, WORD lang,
+INT32 WINAPI LoadMessage32A( HMODULE32 instance, UINT32 id, WORD lang,
                       LPSTR buffer, INT32 buflen )
 {
     HGLOBAL32	hmem;
@@ -617,7 +617,7 @@
 /**********************************************************************
  *	LoadMessage32W	(internal)
  */
-INT32 LoadMessage32W( HMODULE32 instance, UINT32 id, WORD lang,
+INT32 WINAPI LoadMessage32W( HMODULE32 instance, UINT32 id, WORD lang,
                       LPWSTR buffer, INT32 buflen )
 {
     INT32 retval;
diff --git a/loader/task.c b/loader/task.c
index 84d5b1d..7d1814d 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -30,7 +30,9 @@
 #include "winnt.h"
 #include "winsock.h"
 #include "thread.h"
+#include "syslevel.h"
 #include "debug.h"
+#include "dosexe.h"
 #include "dde_proc.h"
 #include "server.h"
 
@@ -227,8 +229,10 @@
 
     SET_CUR_THREAD( pTask->thdb );
     CLIENT_InitThread();
-    /* Terminate the stack frame */
-    THREAD_STACK16(pTask->thdb)->frame32 = NULL;
+
+    /* Terminate the stack frame chain */
+    memset(THREAD_STACK16( pTask->thdb ), '\0', sizeof(STACK16FRAME));
+
     if (pModule->flags & NE_FFLAGS_WIN32)
     {
         /* FIXME: all this is an ugly hack */
@@ -245,6 +249,19 @@
         exit_code = entry();
         TASK_KillCurrentTask( exit_code );
     }
+#ifdef linux
+    else if (pModule->lpDosTask)
+    {
+        int stat;
+
+        while ((stat = MZ_RunModule(pModule->lpDosTask)) >= 0)
+            if (stat > 0 && DOSVM_Process(pModule->lpDosTask) < 0)
+                break;
+
+        MZ_KillModule(pModule->lpDosTask);
+        TASK_KillCurrentTask( 0 );
+    }
+#endif
     else
     {
         /* Registers at initialization must be:
@@ -315,6 +332,8 @@
 
     if (pModule->flags & NE_FFLAGS_WIN32)
     	pTask->flags 	|= TDBF_WIN32;
+    if (pModule->lpDosTask)
+    	pTask->flags 	|= TDBF_WINOLDAP;
 
     pTask->version       = pModule->expected_version;
     pTask->hInstance     = hInstance;
@@ -393,13 +412,15 @@
         sp = pSegTable[pModule->ss-1].minsize + pModule->stack_size;
     sp &= ~1;
     pTask->thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( pTask->hInstance, sp );
-    pTask->thdb->cur_stack -= sizeof(STACK16FRAME) + sizeof(STACK32FRAME *);
+    pTask->thdb->cur_stack -= 2*sizeof(STACK16FRAME);
     frame16 = (STACK16FRAME *)PTR_SEG_TO_LIN( pTask->thdb->cur_stack );
     frame16->ebp = sp + (int)&((STACK16FRAME *)0)->bp;
     frame16->bp = LOWORD(frame16->ebp);
     frame16->ds = frame16->es = pTask->hInstance;
+    frame16->fs = 0;
     frame16->entry_point = 0;
     frame16->entry_cs = 0;
+    frame16->mutex_count = 1; /* TASK_Reschedule is called from 16-bit code */
     /* The remaining fields will be initialized in TASK_Reschedule */
 
     /* Create the 32-bit stack frame */
@@ -546,6 +567,8 @@
     HTASK16 hTask = 0;
     STACK16FRAME *newframe16;
 
+    SYSLEVEL_ReleaseWin16Lock();
+
 #ifdef CONFIG_IPC
     dde_reschedule();
 #endif
@@ -599,6 +622,7 @@
     if (hTask == hCurrentTask) 
     {
        TRACE(task, "returning to the current task(%04x)\n", hTask );
+       SYSLEVEL_RestoreWin16Lock();
        return;  /* Nothing to do */
     }
     pNewTask = (TDB *)GlobalLock16( hTask );
@@ -634,6 +658,8 @@
     hCurrentTask = hTask;
     SET_CUR_THREAD( pNewTask->thdb );
     pNewTask->ss_sp = pNewTask->thdb->cur_stack;
+
+    SYSLEVEL_RestoreWin16Lock();
 }
 
 
@@ -696,7 +722,13 @@
          * si     instance handle of the previous instance
          * di     instance handle of the new task
          * es:bx  pointer to command-line inside PSP
+         *
+         * 0 (=%bp) is pushed on the stack
          */
+        SEGPTR ptr = STACK16_PUSH( pTask->thdb, sizeof(WORD) );
+        *(WORD *)PTR_SEG_TO_LIN(ptr) = 0;
+        SP_reg(context) -= 2;
+
         EAX_reg(context) = 1;
         
 	if (!pTask->pdb.cmdLine[0]) EBX_reg(context) = 0x80;
diff --git a/memory/atom.c b/memory/atom.c
index f2744cb..c3aeb9b 100644
--- a/memory/atom.c
+++ b/memory/atom.c
@@ -21,6 +21,7 @@
 #include "ldt.h"
 #include "stackframe.h"
 #include "user.h"
+#include "debug.h"
 
 #ifdef CONFIG_IPC
 #include "dde_atom.h"
@@ -136,6 +137,8 @@
 ) {
     WORD i, hash = 0;
 
+    TRACE(atom,"%x, %s, %x\n", entries, str, len);
+    
     for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
     return hash % entries;
 }
@@ -163,6 +166,8 @@
     ATOMTABLE * table;
     int len, ae_len;
 
+    TRACE(atom,"0x%x, %s\n", selector, str);
+    
     if (str[0] == '#') return atoi( &str[1] );  /* Check for integer atom */
     if ((len = strlen( str )) > MAX_ATOM_LEN) len = MAX_ATOM_LEN;
     if (!(table = ATOM_GetTable( selector, TRUE ))) return 0;
@@ -175,6 +180,7 @@
 	    (!lstrncmpi32A( entryPtr->str, str, len )))
 	{
 	    entryPtr->refCount++;
+        TRACE(atom,"-- existing 0x%x\n", entry);
 	    return HANDLETOATOM( entry );
 	}
 	entry = entryPtr->next;
@@ -191,6 +197,7 @@
     entryPtr->length = len;
     strncpy( entryPtr->str, str, ae_len - sizeof(ATOMENTRY) + 1); /* always use strncpy ('\0's padding) */
     table->entries[hash] = entry;
+    TRACE(atom,"-- new 0x%x\n", entry);
     return HANDLETOATOM( entry );
 }
 
@@ -209,6 +216,8 @@
     ATOMTABLE * table;
     HANDLE16 entry, *prevEntry;
     WORD hash;
+
+    TRACE(atom,"0x%x, 0x%x\n", selector, atom);
     
     if (atom < MIN_STR_ATOM) return 0;  /* Integer atom */
 
@@ -251,6 +260,8 @@
     HANDLE16 entry;
     int len;
 
+    TRACE(atom,"%x, %s\n", selector, str);
+
     if (str[0] == '#') return atoi( &str[1] );  /* Check for integer atom */
     if ((len = strlen( str )) > 255) len = 255;
     if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
@@ -261,9 +272,12 @@
 	ATOMENTRY * entryPtr = ATOM_MakePtr( selector, entry );
 	if ((entryPtr->length == len) && 
 	    (!lstrncmpi32A( entryPtr->str, str, len )))
+    {    TRACE(atom,"-- found %x\n", entry);
 	    return HANDLETOATOM( entry );
+    }
 	entry = entryPtr->next;
     }
+    TRACE(atom,"-- not found\n");
     return 0;
 }
 
@@ -287,6 +301,8 @@
     UINT32 len;
     char text[8];
     
+    TRACE(atom,"%x, %x\n", selector, atom);
+    
     if (!count) return 0;
     if (atom < MIN_STR_ATOM)
     {
@@ -296,7 +312,7 @@
     }
     else
     {
-        if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
+       if (!(table = ATOM_GetTable( selector, FALSE ))) return 0;
 	entry = ATOMTOHANDLE( atom );
 	entryPtr = ATOM_MakePtr( selector, entry );
 	len = entryPtr->length;
diff --git a/memory/global.c b/memory/global.c
index b4b4d05..f2ba8f0 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -715,7 +715,7 @@
              DWORD size /* [in] Number of bytes to be allocated */
 ) {
    UINT16    uParagraph;
-   LPVOID    lpBlock = DOSMEM_GetBlock( size, &uParagraph );
+   LPVOID    lpBlock = DOSMEM_GetBlock( 0, size, &uParagraph );
 
    if( lpBlock )
    {
@@ -744,7 +744,7 @@
    if( block && block < 0x100000 ) 
    {
        LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
-       if( DOSMEM_FreeBlock( lpBlock ) )
+       if( DOSMEM_FreeBlock( 0, lpBlock ) )
 	   GLOBAL_FreeBlock( sel );
        sel = 0;
    }
diff --git a/memory/heap.c b/memory/heap.c
index 6585ac5..3bcc396 100644
--- a/memory/heap.c
+++ b/memory/heap.c
@@ -1310,8 +1310,8 @@
  */
 LPSTR HEAP_strdupA( HANDLE32 heap, DWORD flags, LPCSTR str )
 {
-    LPSTR p = HEAP_xalloc( heap, flags, lstrlen32A(str) + 1 );
-    lstrcpy32A( p, str );
+    LPSTR p = HEAP_xalloc( heap, flags, strlen(str) + 1 );
+    strcpy( p, str );
     return p;
 }
 
@@ -1336,7 +1336,7 @@
     LPWSTR ret;
 
     if (!str) return NULL;
-    ret = HEAP_xalloc( heap, flags, (lstrlen32A(str)+1) * sizeof(WCHAR) );
+    ret = HEAP_xalloc( heap, flags, (strlen(str)+1) * sizeof(WCHAR) );
     lstrcpyAtoW( ret, str );
     return ret;
 }
diff --git a/memory/selector.c b/memory/selector.c
index dbe68fe..859cc6a 100644
--- a/memory/selector.c
+++ b/memory/selector.c
@@ -179,8 +179,6 @@
             WARN(selector, "Freeing %%fs selector (%04x), not good.\n", fs );
             SET_FS( 0 );
         }
-        fs = THREAD_Current()->saved_fs;
-        if ((fs >= sel) && (fs < nextsel)) THREAD_Current()->saved_fs = 0;
         GET_GS(gs);
         if ((gs >= sel) && (gs < nextsel)) SET_GS( 0 );
     }
@@ -199,6 +197,7 @@
     {
         if ((frame->ds >= sel) && (frame->ds < nextsel)) frame->ds = 0;
         if ((frame->es >= sel) && (frame->es < nextsel)) frame->es = 0;
+        if ((frame->fs >= sel) && (frame->fs < nextsel)) frame->fs = 0;
         frame = PTR_SEG_TO_LIN( frame->frame32->frame16 );
     }
 }
diff --git a/memory/virtual.c b/memory/virtual.c
index 414e9ca..801237c 100644
--- a/memory/virtual.c
+++ b/memory/virtual.c
@@ -817,7 +817,7 @@
 ) {
     BOOL32 ret = FALSE;
 
-    PDB32 *pdb = PROCESS_GetPtr( handle, PROCESS_VM_OPERATION );
+    PDB32 *pdb = PROCESS_GetPtr( handle, PROCESS_VM_OPERATION, NULL );
     if (pdb)
     {
         if (pdb == PROCESS_Current())
@@ -914,7 +914,7 @@
 ) {
     DWORD ret = len;
 
-    PDB32 *pdb = PROCESS_GetPtr( handle, PROCESS_QUERY_INFORMATION );
+    PDB32 *pdb = PROCESS_GetPtr( handle, PROCESS_QUERY_INFORMATION, NULL );
     if (pdb)
     {
         if (pdb == PROCESS_Current())
@@ -1089,13 +1089,15 @@
     /* First search for an object with the same name */
 
     K32OBJ *obj = K32OBJ_FindName( name );
+
+    SetLastError(0); /* Win95 does that for some functions, like CFM */
     if (obj)
     {
         if (obj->type == K32OBJ_MEM_MAPPED_FILE)
         {
             SetLastError( ERROR_ALREADY_EXISTS );
             handle = HANDLE_Alloc( PROCESS_Current(), obj,
-                                   FILE_MAP_ALL_ACCESS /*FIXME*/, inherit );
+                                   FILE_MAP_ALL_ACCESS /*FIXME*/, inherit, -1 );
         }
         else
         {
@@ -1145,7 +1147,7 @@
             ((protect & 0xff) == PAGE_EXECUTE_WRITECOPY))
                 access |= GENERIC_WRITE;
         if (!(obj = HANDLE_GetObjPtr( PROCESS_Current(), hFile,
-                                      K32OBJ_FILE, access )))
+                                      K32OBJ_FILE, access, NULL )))
             goto error;
 
         if (!GetFileInformationByHandle( hFile, &info )) goto error;
@@ -1177,7 +1179,7 @@
 
     if (!K32OBJ_AddName( &mapping->header, name )) handle = 0;
     else handle = HANDLE_Alloc( PROCESS_Current(), &mapping->header,
-                                FILE_MAP_ALL_ACCESS /*FIXME*/, inherit );
+                                FILE_MAP_ALL_ACCESS /*FIXME*/, inherit, -1 );
     K32OBJ_DecCount( &mapping->header );
     return handle;
 
@@ -1222,7 +1224,7 @@
     SYSTEM_LOCK();
     if ((obj = K32OBJ_FindNameType( name, K32OBJ_MEM_MAPPED_FILE )))
     {
-        handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit );
+        handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 );
         K32OBJ_DecCount( obj );
     }
     SYSTEM_UNLOCK();
@@ -1312,7 +1314,7 @@
     if (!(mapping = (FILE_MAPPING *)HANDLE_GetObjPtr( PROCESS_Current(),
                                                       handle,
                                                       K32OBJ_MEM_MAPPED_FILE,
-                                                      0  /* FIXME */ )))
+                                                      0  /* FIXME */, NULL )))
         return NULL;
 
     if (mapping->size_high || offset_high)
diff --git a/misc/crtdll.c b/misc/crtdll.c
index c2f3750..6b808a4 100644
--- a/misc/crtdll.c
+++ b/misc/crtdll.c
@@ -140,6 +140,45 @@
 
 typedef void (*_INITTERMFUN)();
 
+ /*********************************************************************
+ *                  _findfirst    (CRTDLL.099)
+ * 
+ * BUGS
+ *   Unimplemented
+ */
+DWORD __cdecl CRTDLL__findfirst(LPCSTR fname,struct find_t* x2)
+{
+  FIXME(crtdll, ":(%s,%p): stub\n",fname,x2);
+  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  return FALSE;
+}
+
+/*********************************************************************
+ *                  _findnext     (CRTDLL.100)
+ * 
+ * BUGS
+ *   Unimplemented
+ */
+INT32 __cdecl CRTDLL__findnext(DWORD hand,struct find_t* x2)
+{
+  FIXME(crtdll, ":(%d,%p): stub\n",hand,x2);
+  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  return FALSE;
+}
+
+/*********************************************************************
+ *                  _fstat        (CRTDLL.111)
+ * 
+ * BUGS
+ *   Unimplemented
+ */
+int __cdecl CRTDLL__fstat(int file, struct stat* buf)
+{
+  FIXME(crtdll, ":(%d,%p): stub\n",file,buf);
+  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  return FALSE;
+}
+
 /*********************************************************************
  *                  _initterm     (CRTDLL.135)
  */
@@ -209,6 +248,18 @@
 {
     TRACE(crtdll,"(%p,%ld)\n",endframe,nr);
 }
+/*********************************************************************
+ *                  _read     (CRTDLL.256)
+ * 
+ * BUGS
+ *   Unimplemented
+ */
+INT32 __cdecl CRTDLL__read(INT32 fd, LPVOID buf, UINT32 count)
+{
+  FIXME(crtdll,":(%d,%p,%d): stub\n",fd,buf,count);
+  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  return FALSE;
+}
 
 /*********************************************************************
  *                  fopen     (CRTDLL.372)
@@ -296,7 +347,19 @@
   return ret;
 #endif
 }
-  
+/*********************************************************************
+ *                  freopen    (CRTDLL.379)
+ * 
+ * BUGS
+ *   Unimplemented
+ */
+DWORD __cdecl CRTDLL_freopen(LPCSTR path, LPCSTR mode, LPVOID stream)
+{
+  FIXME(crtdll, ":(%s,%s,%p): stub\n", path, mode, stream);
+  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+  return FALSE;
+}
+
 /*********************************************************************
  *                  fscanf     (CRTDLL.381)
  */
diff --git a/misc/ddeml.c b/misc/ddeml.c
index 9a54694..7a5c47a 100644
--- a/misc/ddeml.c
+++ b/misc/ddeml.c
@@ -9,6 +9,7 @@
 
 #include "ddeml.h"
 #include "debug.h"
+#include "atom.h"
 
 /* FIXME: What are these values? */
 #define DMLERR_NO_ERROR		0
@@ -241,12 +242,18 @@
 
 /*****************************************************************
  * DdeCreateStringHandle32A [USER32.95]
+ *
+ * RETURNS
+ *    Success: String handle
+ *    Failure: 0
  */
 HSZ WINAPI DdeCreateStringHandle32A( DWORD idInst, LPCSTR psz, INT32 codepage )
-{
-    FIXME(ddeml, "(...): stub\n" );
-    DDE_current_handle++;
-    return DDE_current_handle;
+{ TRACE(ddeml, "(%ld,%s,%d): stub\n",idInst,debugstr_a(psz),codepage);
+  
+  if (codepage==1004)  /*fixme: should be CP_WINANSI*/
+    return GlobalAddAtom32A (psz);
+  else
+    return 0;  
 }
 
 
@@ -279,11 +286,12 @@
 
 /*****************************************************************
  *            DdeFreeStringHandle32   (USER32.101)
+ * RETURNS: success: nonzero
+ *          fail:    zero
  */
 BOOL32 WINAPI DdeFreeStringHandle32( DWORD idInst, HSZ hsz )
-{
-    FIXME( ddeml, "(%ld,%ld): stub\n",idInst, hsz );
-    return TRUE;
+{   TRACE( ddeml, "(%ld,%ld): stub\n",idInst, hsz );
+    return GlobalDeleteAtom (hsz) ? hsz : 0;
 }
 
 
diff --git a/misc/main.c b/misc/main.c
index d714aad..814c5a4 100644
--- a/misc/main.c
+++ b/misc/main.c
@@ -970,7 +970,7 @@
 		case SPI_GETSCREENSAVETIMEOUT:
 			/* FIXME GetProfileInt( "windows", "ScreenSaveTimeout", 300 ); */
 			TSXGetScreenSaver(display, &timeout, &temp,&temp,&temp);
-			*(INT16 *) lpvParam = timeout * 1000;
+			*(INT16 *) lpvParam = timeout;
 			break;
 
 		case SPI_ICONHORIZONTALSPACING:
diff --git a/misc/network.c b/misc/network.c
index d955016..89664d0 100644
--- a/misc/network.c
+++ b/misc/network.c
@@ -115,7 +115,7 @@
 /*******************************************************************
  * WNetConnectionDialog1_32A [MPR.59]
  */
-UINT32 WNetConnectionDialog1_32A (LPCONNECTDLGSTRUCT32A lpConnDlgStruct)
+UINT32 WINAPI WNetConnectionDialog1_32A (LPCONNECTDLGSTRUCT32A lpConnDlgStruct)
 { FIXME(wnet,"%p stub\n", lpConnDlgStruct);   
   SetLastError(WN_NO_NETWORK);
   return ERROR_NO_NETWORK;
@@ -123,16 +123,16 @@
 /*******************************************************************
  * WNetConnectionDialog1_32W [MPR.60]
  */ 
-UINT32 WNetConnectionDialog1_32W (LPCONNECTDLGSTRUCT32W lpConnDlgStruct)
+UINT32 WINAPI WNetConnectionDialog1_32W (LPCONNECTDLGSTRUCT32W lpConnDlgStruct)
 { FIXME(wnet,"%p stub\n", lpConnDlgStruct);
   SetLastError(WN_NO_NETWORK);
   return ERROR_NO_NETWORK;
 }
  
 /*******************************************************************
- * WNetConnectionDialog1_32 [MPR.61]
+ * WNetConnectionDialog_32 [MPR.61]
  */ 
-UINT32 WNetConnectionDialog1_32(HWND32 owner, DWORD flags  )
+UINT32 WINAPI WNetConnectionDialog_32(HWND32 owner, DWORD flags  )
 { FIXME(wnet,"owner = 0x%x, flags=0x%lx stub\n", owner,flags);
   SetLastError(WN_NO_NETWORK);
   return ERROR_NO_NETWORK;
@@ -275,15 +275,11 @@
     if (lpLocalName[1] == ':')
     {
         int drive = toupper(lpLocalName[0]) - 'A';
-        switch(GetDriveType16(drive))
+        switch(DRIVE_GetType(drive))
         {
-        case DRIVE_CANNOTDETERMINE:
-        case DRIVE_DOESNOTEXIST:
+        case TYPE_INVALID:
             return WN_BAD_LOCALNAME;
-        case DRIVE_REMOVABLE:
-        case DRIVE_FIXED:
-            return WN_NOT_CONNECTED;
-        case DRIVE_REMOTE:
+        case TYPE_NETWORK:
             path = DRIVE_GetLabel(drive);
             if (strlen(path) + 1 > *cbRemoteName)
             {
@@ -293,6 +289,8 @@
             strcpy( lpRemoteName, path );
             *cbRemoteName = strlen(lpRemoteName) + 1;
             return WN_SUCCESS;
+	default:
+	    return WN_BAD_LOCALNAME;
         }
     }
     return WN_BAD_LOCALNAME;
@@ -690,15 +688,6 @@
 }
 
 /*****************************************************************
- *  [MPR.25]
- */
-
-DWORD WINAPI _MPR_25(DWORD x, DWORD y)
-{
-	FIXME(mpr,"(%lx,%lx): stub\n",x,y);
-	return 1;
-}
-/*****************************************************************
  *  MultinetGetErrorTextA [MPR.28]
  */
 
diff --git a/misc/printdrv.c b/misc/printdrv.c
index 75a6a8f..a2146e5 100644
--- a/misc/printdrv.c
+++ b/misc/printdrv.c
@@ -41,31 +41,29 @@
   return  Escape16(hdc, ENDDOC, 0, 0, 0);
 }
 
-WORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer, LPBYTE lpPrinterData, int cbData)
+DWORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer, LPBYTE lpPrinterData, int cbData)
 {
-    WORD res = -1;
+    DWORD res = -1;
     HKEY hkey;
     DWORD dwType, cbQueryData;
 
     if (!(RegOpenKey32A(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) {
         if (cbData > 1) { /* "Default DevMode" */
             if (!(RegQueryValueEx32A(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) {
-                if (!lpPrinterData) res = cbQueryData;
-		else
-		if ((cbQueryData) && (cbQueryData <= cbData)) {
+                if (!lpPrinterData)
+		    res = cbQueryData;
+		else if ((cbQueryData) && (cbQueryData <= cbData)) {
 		    cbQueryData = cbData;
 		    if (RegQueryValueEx32A(hkey, DefaultDevMode, 0,
 				&dwType, lpPrinterData, &cbQueryData))
 		        res = cbQueryData;
 		}
-            }
-            else /* "Printer Driver" */
-	    {
-		cbQueryData = 32;
-	        RegQueryValueEx32A(hkey, "Printer Driver", 0,
-			&dwType, lpPrinterData, &cbQueryData);
-		res = cbQueryData;
 	    }
+	} else { /* "Printer Driver" */
+	    cbQueryData = 32;
+	    RegQueryValueEx32A(hkey, "Printer Driver", 0,
+			&dwType, lpPrinterData, &cbQueryData);
+	    res = cbQueryData;
 	}
     }
     if (hkey) RegCloseKey(hkey);
@@ -192,20 +190,24 @@
 
     if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) &&
     (!strcmp(lpProfile, DefaultDevMode)))) {
-	if (!(RegOpenKey32A(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ||
-	    (RegSetValueEx32A(hkey, DefaultDevMode, 0, REG_BINARY, lpPrinterData, dwSize)))
+	if ( RegOpenKey32A(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey) 
+	     != ERROR_SUCCESS ||
+	     RegSetValueEx32A(hkey, DefaultDevMode, 0, REG_BINARY, 
+			      lpPrinterData, dwSize) != ERROR_SUCCESS )
 	        res = ERROR_INVALID_PRINTER_NAME;
     }
     else
     {
 	strcat(RegStr_Printer, "\\");
 
-	if (!(res = RegOpenKey32A(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) {
+	if( (res = RegOpenKey32A(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) ==
+	    ERROR_SUCCESS ) {
 
 	    if (!lpPrinterData) 
 	        res = RegDeleteValue32A(hkey, lpProfile);
 	    else
-                res = RegSetValueEx32A(hkey, lpProfile, 0, lpType, lpPrinterData, dwSize);
+                res = RegSetValueEx32A(hkey, lpProfile, 0, lpType,
+				       lpPrinterData, dwSize);
 	}
     }
 
diff --git a/misc/shell.c b/misc/shell.c
index 671914c..1b8ebbf 100644
--- a/misc/shell.c
+++ b/misc/shell.c
@@ -28,6 +28,8 @@
 #include "shlobj.h"
 #include "debug.h"
 #include "winreg.h"
+#include "imagelist.h"
+#include "commctrl.h"
 
 /* FIXME should be moved to a header file. IsEqualGUID 
 is declared but not exported in compobj.c !!!*/
@@ -96,6 +98,7 @@
     "Alex Korobka",
     "Greg Kreider",
     "Anand Kumria",
+    "Ove Kåven",
     "Scott A. Laird",
     "David Lee Lambert",
     "Andrew Lewycky",
@@ -218,8 +221,7 @@
  *				DragAcceptFiles		[SHELL.9]
  */
 void WINAPI DragAcceptFiles(HWND16 hWnd, BOOL16 b)
-{
-    WND* wnd = WIN_FindWndPtr(hWnd);
+{ WND* wnd = WIN_FindWndPtr(hWnd);
 
     if( wnd )
 	wnd->dwExStyle = b? wnd->dwExStyle | WS_EX_ACCEPTFILES
@@ -232,8 +234,7 @@
  */
 UINT16 WINAPI DragQueryFile(HDROP16 hDrop, WORD wFile, LPSTR lpszFile,
                             WORD wLength)
-{
-    /* hDrop is a global memory block allocated with GMEM_SHARE 
+{ /* hDrop is a global memory block allocated with GMEM_SHARE 
      * with DROPFILESTRUCT as a header and filenames following
      * it, zero length filename is in the end */       
     
@@ -241,24 +242,25 @@
     LPSTR lpCurrent;
     WORD  i;
     
-    TRACE(reg,"(%04x, %i, %p, %u)\n",
+  TRACE(shell,"(%04x, %i, %p, %u)\n",
 		hDrop,wFile,lpszFile,wLength);
     
     lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop); 
-    if(!lpDropFileStruct) return 0;
+  if(!lpDropFileStruct)
+    return 0;
 
     lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
     
     i = 0;
     while (i++ < wFile)
-    {
-	while (*lpCurrent++);  /* skip filename */
+  { while (*lpCurrent++);  /* skip filename */
 	if (!*lpCurrent) 
 	    return (wFile == 0xFFFF) ? i : 0;  
     }
     
     i = strlen(lpCurrent); 
-    if (!lpszFile) return i+1;   /* needed buffer size */
+  if (!lpszFile)
+    return i+1;   /* needed buffer size */
     
     i = (wLength > i) ? i : wLength-1;
     strncpy(lpszFile, lpCurrent, i);
@@ -273,7 +275,7 @@
  *				DragFinish		[SHELL.12]
  */
 void WINAPI DragFinish(HDROP16 h)
-{
+{ TRACE(shell,"\n");
     GlobalFree16((HGLOBAL16)h);
 }
 
@@ -282,10 +284,9 @@
  *				DragQueryPoint		[SHELL.13]
  */
 BOOL16 WINAPI DragQueryPoint(HDROP16 hDrop, POINT16 *p)
-{
-    LPDROPFILESTRUCT lpDropFileStruct;  
+{ LPDROPFILESTRUCT lpDropFileStruct;  
     BOOL16           bRet;
-
+  TRACE(shell,"\n");
     lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
 
     memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT16));
@@ -303,8 +304,7 @@
 static HINSTANCE32 SHELL_FindExecutable( LPCSTR lpFile, 
                                          LPCSTR lpOperation,
                                          LPSTR lpResult)
-{
-    char *extension = NULL; /* pointer to file extension */
+{ char *extension = NULL; /* pointer to file extension */
     char tmpext[5];         /* local copy to mung as we please */
     char filetype[256];     /* registry name for this filetype */
     LONG filetypelen=256;   /* length of above */
@@ -316,21 +316,19 @@
     int i;                  /* random counter */
     char xlpFile[256];      /* result of SearchPath */
 
-    TRACE(exec, "%s\n", (lpFile != NULL?lpFile:"-") );
+  TRACE(shell, "%s\n", (lpFile != NULL?lpFile:"-") );
 
     lpResult[0]='\0'; /* Start off with an empty return string */
 
     /* trap NULL parameters on entry */
     if (( lpFile == NULL ) || ( lpResult == NULL ) || ( lpOperation == NULL ))
-    {
-	WARN(exec, "(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
+  { WARN(exec, "(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
            lpFile, lpOperation, lpResult);
         return 2; /* File not found. Close enough, I guess. */
     }
 
     if (SearchPath32A( NULL, lpFile,".exe",sizeof(xlpFile),xlpFile,NULL))
-    {
-	TRACE(exec, "SearchPath32A returned non-zero\n");
+  { TRACE(shell, "SearchPath32A returned non-zero\n");
         lpFile = xlpFile;
     }
 
@@ -338,18 +336,17 @@
     extension = strrchr( xlpFile, '.' ); /* Assume last "." is the one; */
 					/* File->Run in progman uses */
 					/* .\FILE.EXE :( */
-    TRACE(exec, "xlpFile=%s,extension=%s\n", xlpFile, extension);
+  TRACE(shell, "xlpFile=%s,extension=%s\n", xlpFile, extension);
 
     if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)]))
-    {
-        WARN(exec, "Returning 31 - No association\n");
+  { WARN(shell, "Returning 31 - No association\n");
         return 31; /* no association */
     }
 
     /* Make local copy & lowercase it for reg & 'programs=' lookup */
     lstrcpyn32A( tmpext, extension, 5 );
     CharLower32A( tmpext );
-    TRACE(exec, "%s file\n", tmpext);
+  TRACE(shell, "%s file\n", tmpext);
     
     /* Three places to check: */
     /* 1. win.ini, [windows], programs (NB no leading '.') */
@@ -364,8 +361,7 @@
      * got a lot more to worry about than running a program... */
     if ( GetProfileString32A("windows", "programs", "exe pif bat com",
 						  buffer, sizeof(buffer)) > 0 )
-	  {
-		for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
+  { for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
 
 		tok = strtok(buffer, " \t"); /* ? */
 		while( tok!= NULL)
@@ -375,8 +371,7 @@
 				strcpy(lpResult, xlpFile);
 				/* Need to perhaps check that the file has a path
 				 * attached */
-				TRACE(exec, "found %s\n",
-							 lpResult);
+        TRACE(shell, "found %s\n", lpResult);
                                 return 33;
 
 		/* Greater than 32 to indicate success FIXME According to the
@@ -393,8 +388,7 @@
                          &filetypelen ) == ERROR_SUCCESS )
     {
 	filetype[filetypelen]='\0';
-	TRACE(exec, "File type: %s\n",
-		     filetype);
+  TRACE(shell, "File type: %s\n", filetype);
 
 	/* Looking for ...buffer\shell\lpOperation\command */
 	strcat( filetype, "\\shell\\" );
@@ -447,7 +441,7 @@
 	  }
 	}
 
-    TRACE(exec, "returning %s\n", lpResult);
+    TRACE(shell, "returning %s\n", lpResult);
     return retval;
 }
 
@@ -457,12 +451,11 @@
 HINSTANCE16 WINAPI ShellExecute16( HWND16 hWnd, LPCSTR lpOperation,
                                    LPCSTR lpFile, LPCSTR lpParameters,
                                    LPCSTR lpDirectory, INT16 iShowCmd )
-{
-    HINSTANCE16 retval=31;
+{   HINSTANCE16 retval=31;
     char old_dir[1024];
     char cmd[256];
 
-    TRACE(exec, "(%04x,'%s','%s','%s','%s',%x)\n",
+    TRACE(shell, "(%04x,'%s','%s','%s','%s',%x)\n",
 		hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
 		lpParameters ? lpParameters : "<null>", 
 		lpDirectory ? lpDirectory : "<null>", iShowCmd);
@@ -472,25 +465,23 @@
       lpOperation="open";
 
     if (lpDirectory)
-    {
-        GetCurrentDirectory32A( sizeof(old_dir), old_dir );
+    { GetCurrentDirectory32A( sizeof(old_dir), old_dir );
         SetCurrentDirectory32A( lpDirectory );
     }
 
     retval = SHELL_FindExecutable( lpFile, lpOperation, cmd );
 
     if (retval > 32)  /* Found */
-    {
-        if (lpParameters)
-        {
-            strcat(cmd," ");
+    { if (lpParameters)
+      { strcat(cmd," ");
             strcat(cmd,lpParameters);
         }
 
-        TRACE(exec,"starting %s\n",cmd);
+      TRACE(shell,"starting %s\n",cmd);
         retval = WinExec32( cmd, iShowCmd );
     }
-    if (lpDirectory) SetCurrentDirectory32A( old_dir );
+    if (lpDirectory)
+      SetCurrentDirectory32A( old_dir );
     return retval;
 }
 
@@ -501,19 +492,17 @@
 HINSTANCE32 WINAPI ShellExecute32A( HWND32 hWnd, LPCSTR lpOperation,
                                     LPCSTR lpFile, LPCSTR lpParameters,
                                     LPCSTR lpDirectory, INT32 iShowCmd )
-{
+{   TRACE(shell,"\n");
     return ShellExecute16( hWnd, lpOperation, lpFile, lpParameters,
                            lpDirectory, iShowCmd );
 }
 
-
 /*************************************************************************
  *             FindExecutable16   (SHELL.21)
  */
 HINSTANCE16 WINAPI FindExecutable16( LPCSTR lpFile, LPCSTR lpDirectory,
                                      LPSTR lpResult )
-{
-    return (HINSTANCE16)FindExecutable32A( lpFile, lpDirectory, lpResult );
+{ return (HINSTANCE16)FindExecutable32A( lpFile, lpDirectory, lpResult );
 }
 
 /*************************************************************************
@@ -521,11 +510,10 @@
  */
 HINSTANCE32 WINAPI FindExecutable32A( LPCSTR lpFile, LPCSTR lpDirectory,
                                       LPSTR lpResult )
-{
-    HINSTANCE32 retval=31;    /* default - 'No association was found' */
+{ HINSTANCE32 retval=31;    /* default - 'No association was found' */
     char old_dir[1024];
 
-    TRACE(exec, "File %s, Dir %s\n", 
+  TRACE(shell, "File %s, Dir %s\n", 
 		 (lpFile != NULL?lpFile:"-"), 
 		 (lpDirectory != NULL?lpDirectory:"-"));
 
@@ -533,27 +521,25 @@
 
     /* trap NULL parameters on entry */
     if (( lpFile == NULL ) || ( lpResult == NULL ))
-    {
-	/* FIXME - should throw a warning, perhaps! */
+  { /* FIXME - should throw a warning, perhaps! */
 	return 2; /* File not found. Close enough, I guess. */
     }
 
     if (lpDirectory)
-    {
-        GetCurrentDirectory32A( sizeof(old_dir), old_dir );
+  { GetCurrentDirectory32A( sizeof(old_dir), old_dir );
         SetCurrentDirectory32A( lpDirectory );
     }
 
     retval = SHELL_FindExecutable( lpFile, "open", lpResult );
 
-    TRACE(exec, "returning %s\n", lpResult);
-    if (lpDirectory) SetCurrentDirectory32A( old_dir );
+  TRACE(shell, "returning %s\n", lpResult);
+  if (lpDirectory)
+    SetCurrentDirectory32A( old_dir );
     return retval;
 }
 
 typedef struct
-{
-    LPCSTR  szApp;
+{ LPCSTR  szApp;
     LPCSTR  szOtherStuff;
     HICON32 hIcon;
 } ABOUT_INFO;
@@ -568,11 +554,9 @@
 extern HICON32 hIconTitleFont;
 
 static BOOL32 __get_dropline( HWND32 hWnd, LPRECT32 lprect )
-{
-    HWND32 hWndCtl = GetDlgItem32(hWnd, IDC_WINE_TEXT);
+{ HWND32 hWndCtl = GetDlgItem32(hWnd, IDC_WINE_TEXT);
     if( hWndCtl )
-    {
-	GetWindowRect32( hWndCtl, lprect );
+  { GetWindowRect32( hWndCtl, lprect );
 	MapWindowPoints32( 0, hWnd, (LPPOINT32)lprect, 2 );
 	lprect->bottom = (lprect->top += DROP_FIELD_TOP);
 	return TRUE;
@@ -585,18 +569,16 @@
  */
 LRESULT WINAPI AboutDlgProc32( HWND32 hWnd, UINT32 msg, WPARAM32 wParam,
                                LPARAM lParam )
-{
-    HWND32 hWndCtl;
+{   HWND32 hWndCtl;
     char Template[512], AppTitle[512];
 
+    TRACE(shell,"\n");
+
     switch(msg)
-    {
-    case WM_INITDIALOG:
-        {
-            ABOUT_INFO *info = (ABOUT_INFO *)lParam;
+    { case WM_INITDIALOG:
+      { ABOUT_INFO *info = (ABOUT_INFO *)lParam;
             if (info)
-            {
-                const char* const *pstr = SHELL_People;
+        { const char* const *pstr = SHELL_People;
                 SendDlgItemMessage32A(hWnd, stc1, STM_SETICON32,info->hIcon, 0);
                 GetWindowText32A( hWnd, Template, sizeof(Template) );
                 sprintf( AppTitle, Template, info->szApp );
@@ -607,9 +589,7 @@
                 SendMessage32A( hWndCtl, WM_SETREDRAW, 0, 0 );
                 SendMessage32A( hWndCtl, WM_SETFONT, hIconTitleFont, 0 );
                 while (*pstr)
-                {
-                    SendMessage32A( hWndCtl, LB_ADDSTRING32,
-                                    (WPARAM32)-1, (LPARAM)*pstr );
+          { SendMessage32A( hWndCtl, LB_ADDSTRING32, (WPARAM32)-1, (LPARAM)*pstr );
                     pstr++;
                 }
                 SendMessage32A( hWndCtl, WM_SETREDRAW, 1, 0 );
@@ -618,8 +598,7 @@
         return 1;
 
     case WM_PAINT:
-	{
-	    RECT32 rect;
+      { RECT32 rect;
 	    PAINTSTRUCT32 ps;
 	    HDC32 hDC = BeginPaint32( hWnd, &ps );
 
@@ -630,29 +609,25 @@
 	break;
 
     case WM_LBTRACKPOINT:
-
 	hWndCtl = GetDlgItem32(hWnd, IDC_LISTBOX);
 	if( (INT16)GetKeyState16( VK_CONTROL ) < 0 )
-	{
-	    if( DragDetect32( hWndCtl, *((LPPOINT32)&lParam) ) )
-	    {
-		INT32 idx = SendMessage32A( hWndCtl, LB_GETCURSEL32, 0, 0 );
+      { if( DragDetect32( hWndCtl, *((LPPOINT32)&lParam) ) )
+        { INT32 idx = SendMessage32A( hWndCtl, LB_GETCURSEL32, 0, 0 );
 		if( idx != -1 )
-		{
-		    INT32 length = SendMessage32A( hWndCtl, LB_GETTEXTLEN32, (WPARAM32)idx, 0 );
+          { INT32 length = SendMessage32A( hWndCtl, LB_GETTEXTLEN32, (WPARAM32)idx, 0 );
 		    HGLOBAL16 hMemObj = GlobalAlloc16( GMEM_MOVEABLE, length + 1 );
 		    char* pstr = (char*)GlobalLock16( hMemObj );
 
 		    if( pstr )
-		    {
-			HCURSOR16 hCursor = LoadCursor16( 0, MAKEINTRESOURCE16(OCR_DRAGOBJECT) );
+            { HCURSOR16 hCursor = LoadCursor16( 0, MAKEINTRESOURCE16(OCR_DRAGOBJECT) );
 			SendMessage32A( hWndCtl, LB_GETTEXT32, (WPARAM32)idx, (LPARAM)pstr );
 			SendMessage32A( hWndCtl, LB_DELETESTRING32, (WPARAM32)idx, 0 );
 			UpdateWindow32( hWndCtl );
 			if( !DragObject16((HWND16)hWnd, (HWND16)hWnd, DRAGOBJ_DATA, 0, (WORD)hMemObj, hCursor) )
 			    SendMessage32A( hWndCtl, LB_ADDSTRING32, (WPARAM32)-1, (LPARAM)pstr );
 		    }
-		    if( hMemObj ) GlobalFree16( hMemObj );
+            if( hMemObj )
+              GlobalFree16( hMemObj );
 		}
 	    }
 	}
@@ -660,18 +635,14 @@
 
     case WM_QUERYDROPOBJECT:
 	if( wParam == 0 )
-	{
-	    LPDRAGINFO lpDragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN((SEGPTR)lParam);
+      { LPDRAGINFO lpDragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN((SEGPTR)lParam);
 	    if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA )
-	    {
-		RECT32 rect;
+        { RECT32 rect;
 		if( __get_dropline( hWnd, &rect ) )
-		{
-		    POINT32 pt = { lpDragInfo->pt.x, lpDragInfo->pt.y };
+          { POINT32 pt = { lpDragInfo->pt.x, lpDragInfo->pt.y };
 		    rect.bottom += DROP_FIELD_HEIGHT;
 		    if( PtInRect32( &rect, pt ) )
-		    {
-			SetWindowLong32A( hWnd, DWL_MSGRESULT, 1 );
+            { SetWindowLong32A( hWnd, DWL_MSGRESULT, 1 );
 			return TRUE;
 		    }
 		}
@@ -681,22 +652,18 @@
 
     case WM_DROPOBJECT:
 	if( wParam == hWnd )
-	{
-	    LPDRAGINFO lpDragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN((SEGPTR)lParam);
+      { LPDRAGINFO lpDragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN((SEGPTR)lParam);
 	    if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA && lpDragInfo->hList )
-	    {
-		char* pstr = (char*)GlobalLock16( (HGLOBAL16)(lpDragInfo->hList) );
+        { char* pstr = (char*)GlobalLock16( (HGLOBAL16)(lpDragInfo->hList) );
 		if( pstr )
-		{
-		    static char __appendix_str[] = " with";
+          { static char __appendix_str[] = " with";
 
 		    hWndCtl = GetDlgItem32( hWnd, IDC_WINE_TEXT );
 		    SendMessage32A( hWndCtl, WM_GETTEXT, 512, (LPARAM)Template );
 		    if( !lstrncmp32A( Template, "WINE", 4 ) )
 			SetWindowText32A( GetDlgItem32(hWnd, IDC_STATIC_TEXT), Template );
 		    else
-		    {
-			char* pch = Template + strlen(Template) - strlen(__appendix_str);
+          { char* pch = Template + strlen(Template) - strlen(__appendix_str);
 			*pch = '\0';
 			SendMessage32A( GetDlgItem32(hWnd, IDC_LISTBOX), LB_ADDSTRING32, 
 					(WPARAM32)-1, (LPARAM)Template );
@@ -705,7 +672,6 @@
 		    lstrcpy32A( Template, pstr );
 		    lstrcat32A( Template, __appendix_str );
 		    SetWindowText32A( hWndCtl, Template );
-
 		    SetWindowLong32A( hWnd, DWL_MSGRESULT, 1 );
 		    return TRUE;
 		}
@@ -715,8 +681,7 @@
 
     case WM_COMMAND:
         if (wParam == IDOK)
-        {
-            EndDialog32(hWnd, TRUE);
+    {  EndDialog32(hWnd, TRUE);
             return TRUE;
         }
         break;
@@ -730,8 +695,7 @@
  */
 LRESULT WINAPI AboutDlgProc16( HWND16 hWnd, UINT16 msg, WPARAM16 wParam,
                                LPARAM lParam )
-{
-    return AboutDlgProc32( hWnd, msg, wParam, lParam );
+{ return AboutDlgProc32( hWnd, msg, wParam, lParam );
 }
 
 
@@ -740,8 +704,7 @@
  */
 BOOL16 WINAPI ShellAbout16( HWND16 hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
                             HICON16 hIcon )
-{
-    return ShellAbout32A( hWnd, szApp, szOtherStuff, hIcon );
+{ return ShellAbout32A( hWnd, szApp, szOtherStuff, hIcon );
 }
 
 /*************************************************************************
@@ -749,8 +712,8 @@
  */
 BOOL32 WINAPI ShellAbout32A( HWND32 hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
                              HICON32 hIcon )
-{
-    ABOUT_INFO info;
+{   ABOUT_INFO info;
+    TRACE(shell,"\n");
     info.szApp        = szApp;
     info.szOtherStuff = szOtherStuff;
     info.hIcon        = hIcon;
@@ -766,10 +729,11 @@
  */
 BOOL32 WINAPI ShellAbout32W( HWND32 hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
                              HICON32 hIcon )
-{
-    BOOL32 ret;
+{   BOOL32 ret;
     ABOUT_INFO info;
 
+    TRACE(shell,"\n");
+    
     info.szApp        = HEAP_strdupWtoA( GetProcessHeap(), 0, szApp );
     info.szOtherStuff = HEAP_strdupWtoA( GetProcessHeap(), 0, szOtherStuff );
     info.hIcon        = hIcon;
@@ -790,7 +754,7 @@
  */
 BOOL32 WINAPI Shell_NotifyIcon(	DWORD dwMessage,
 				PNOTIFYICONDATA pnid )
-{
+{   TRACE(shell,"\n");
     return FALSE;
 }
 
@@ -802,7 +766,7 @@
  */
 BOOL32 WINAPI Shell_NotifyIconA(DWORD dwMessage,
 				PNOTIFYICONDATA pnid )
-{
+{   TRACE(shell,"\n");
     return FALSE;
 }
 
@@ -814,7 +778,7 @@
   IMAGE_DOS_HEADER	mz_header;
   char			magic[4];
   int			size;
-  
+  TRACE(shell,"\n");  
   *retptr = NULL;
   _llseek32( hFile, 0, SEEK_SET );
   if (	(_lread32(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
@@ -864,13 +828,11 @@
  *			SHELL_LoadResource
  */
 static HGLOBAL16 SHELL_LoadResource(HINSTANCE16 hInst, HFILE32 hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
-{
- BYTE*	ptr;
+{ BYTE*  ptr;
  HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
-
+  TRACE(shell,"\n");
  if( (ptr = (BYTE*)GlobalLock16( handle )) )
-   {
-    _llseek32( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
+  { _llseek32( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
      _lread32( hFile, (char*)ptr, pNInfo->length << sizeShift);
      return handle;
    }
@@ -881,13 +843,11 @@
  *                      ICO_LoadIcon
  */
 static HGLOBAL16 ICO_LoadIcon(HINSTANCE16 hInst, HFILE32 hFile, LPicoICONDIRENTRY lpiIDE)
-{
- BYTE*  ptr;
+{ BYTE*  ptr;
  HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, lpiIDE->dwBytesInRes);
-
+  TRACE(shell,"\n");
  if( (ptr = (BYTE*)GlobalLock16( handle )) )
-   {
-    _llseek32( hFile, lpiIDE->dwImageOffset, SEEK_SET);
+  { _llseek32( hFile, lpiIDE->dwImageOffset, SEEK_SET);
      _lread32( hFile, (char*)ptr, lpiIDE->dwBytesInRes);
      return handle;
    }
@@ -900,11 +860,11 @@
  *  Read .ico file and build phony ICONDIR struct for GetIconID
  */
 static HGLOBAL16 ICO_GetIconDirectory(HINSTANCE16 hInst, HFILE32 hFile, LPicoICONDIR* lplpiID ) 
-{
-  WORD		id[3];	/* idReserved, idType, idCount */
+{ WORD    id[3];  /* idReserved, idType, idCount */
   LPicoICONDIR	lpiID;
   int		i;
  
+  TRACE(shell,"\n"); 
   _llseek32( hFile, 0, SEEK_SET );
   if( _lread32(hFile,(char*)id,sizeof(id)) != sizeof(id) ) return 0;
 
@@ -920,18 +880,15 @@
   lpiID = (LPicoICONDIR)HeapAlloc( GetProcessHeap(), 0, i);
 
   if( _lread32(hFile,(char*)lpiID->idEntries,i) == i )
-  {  
-     HGLOBAL16 handle = DirectResAlloc( hInst, 0x10,
+  { HGLOBAL16 handle = DirectResAlloc( hInst, 0x10,
                                      id[2]*sizeof(ICONDIRENTRY) + sizeof(id) );
      if( handle ) 
-     {
-       CURSORICONDIR*     lpID = (CURSORICONDIR*)GlobalLock16( handle );
+    { CURSORICONDIR*     lpID = (CURSORICONDIR*)GlobalLock16( handle );
        lpID->idReserved = lpiID->idReserved = id[0];
        lpID->idType = lpiID->idType = id[1];
        lpID->idCount = lpiID->idCount = id[2];
        for( i=0; i < lpiID->idCount; i++ )
-         {
-	    memcpy((void*)(lpID->idEntries + i), 
+      { memcpy((void*)(lpID->idEntries + i), 
 		   (void*)(lpiID->idEntries + i), sizeof(ICONDIRENTRY) - 2);
 	    lpID->idEntries[i].icon.wResId = i;
          }
@@ -962,10 +919,11 @@
   HFILE32 	hFile = OpenFile32( lpszExeFileName, &ofs, OF_READ );
   UINT16	iconDirCount = 0,iconCount = 0;
   
-  TRACE(reg,"(%04x,file %s,start %d,extract %d\n", 
+  TRACE(shell,"(%04x,file %s,start %d,extract %d\n", 
 		       hInstance, lpszExeFileName, nIconIndex, n);
 
-  if( hFile == HFILE_ERROR32 || !n ) return 0;
+  if( hFile == HFILE_ERROR32 || !n )
+    return 0;
 
   hRet = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON16)*n);
   RetPtr = (HICON16*)GlobalLock16(hRet);
@@ -998,13 +956,13 @@
 	  {
 	     iconDirCount = pTInfo->count;
 	     pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
-	     TRACE(reg,"\tfound directory - %i icon families\n", iconDirCount);
+       TRACE(shell,"\tfound directory - %i icon families\n", iconDirCount);
 	  }
 	if( pTInfo->type_id == NE_RSCTYPE_ICON ) 
 	  { 
 	     iconCount = pTInfo->count;
 	     pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
-	     TRACE(reg,"\ttotal icons - %i\n", iconCount);
+       TRACE(shell,"\ttotal icons - %i\n", iconCount);
 	  }
   	pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
     }
@@ -1068,13 +1026,13 @@
 	
 	fmapping = CreateFileMapping32A(hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL);
 	if (fmapping == 0) { /* FIXME, INVALID_HANDLE_VALUE? */
-		WARN(reg,"failed to create filemap.\n");
+    WARN(shell,"failed to create filemap.\n");
 		_lclose32( hFile);
 		return 0;
 	}
 	peimage = MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0);
 	if (!peimage) {
-		WARN(reg,"failed to mmap filemap.\n");
+    WARN(shell,"failed to mmap filemap.\n");
 		CloseHandle(fmapping);
 		_lclose32( hFile);
 		return 0;
@@ -1098,7 +1056,7 @@
 	}
 
 	if (!rootresdir) {
-		WARN(reg,"haven't found section for resource directory.\n");
+    WARN(shell,"haven't found section for resource directory.\n");
 		UnmapViewOfFile(peimage);
 		CloseHandle(fmapping);
 		_lclose32( hFile);
@@ -1107,7 +1065,7 @@
 	icongroupresdir = GetResDirEntryW(rootresdir,RT_GROUP_ICON32W,
                                           (DWORD)rootresdir,FALSE);
 	if (!icongroupresdir) {
-		WARN(reg,"No Icongroupresourcedirectory!\n");
+    WARN(shell,"No Icongroupresourcedirectory!\n");
 		UnmapViewOfFile(peimage);
 		CloseHandle(fmapping);
 		_lclose32( hFile);
@@ -1124,7 +1082,7 @@
 	}
 
 	if (nIconIndex >= iconDirCount) {
-		WARN(reg,"nIconIndex %d is larger than iconDirCount %d\n",
+    WARN(shell,"nIconIndex %d is larger than iconDirCount %d\n",
 			    nIconIndex,iconDirCount);
 		UnmapViewOfFile(peimage);
 		CloseHandle(fmapping);
@@ -1163,7 +1121,7 @@
 			igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
 		}
 		if (!igdata) {
-			WARN(reg,"no matching real address for icongroup!\n");
+      WARN(shell,"no matching real address for icongroup!\n");
 			UnmapViewOfFile(peimage);
 			CloseHandle(fmapping);
 			_lclose32( hFile);
@@ -1177,7 +1135,7 @@
 	iconresdir=GetResDirEntryW(rootresdir,RT_ICON32W,
                                    (DWORD)rootresdir,FALSE);
 	if (!iconresdir) {
-	    WARN(reg,"No Iconresourcedirectory!\n");
+      WARN(shell,"No Iconresourcedirectory!\n");
 	    UnmapViewOfFile(peimage);
 	    CloseHandle(fmapping);
 	    _lclose32( hFile);
@@ -1201,7 +1159,7 @@
 		idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
 	    }
 	    if (!idata) {
-		WARN(reg,"no matching real address found for icondata!\n");
+    WARN(shell,"no matching real address found for icondata!\n");
 		RetPtr[i]=0;
 		continue;
 	    }
@@ -1223,7 +1181,7 @@
  */
 HICON16 WINAPI ExtractIcon16( HINSTANCE16 hInstance, LPCSTR lpszExeFileName,
 	UINT16 nIconIndex )
-{
+{   TRACE(shell,"\n");
     return ExtractIcon32A( hInstance, lpszExeFileName, nIconIndex );
 }
 
@@ -1233,9 +1191,8 @@
  */
 HICON32 WINAPI ExtractIcon32A( HINSTANCE32 hInstance, LPCSTR lpszExeFileName,
 	UINT32 nIconIndex )
-{
-    HGLOBAL16 handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
-
+{   HGLOBAL16 handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
+    TRACE(shell,"\n");
     if( handle )
     {
 	HICON16* ptr = (HICON16*)GlobalLock16(handle);
@@ -1252,9 +1209,12 @@
  */
 HICON32 WINAPI ExtractIcon32W( HINSTANCE32 hInstance, LPCWSTR lpszExeFileName,
 	UINT32 nIconIndex )
-{
-	LPSTR	exefn = HEAP_strdupWtoA(GetProcessHeap(),0,lpszExeFileName);
-	HICON32	ret = ExtractIcon32A(hInstance,exefn,nIconIndex);
+{ LPSTR  exefn;
+  HICON32  ret;
+  TRACE(shell,"\n");
+
+  exefn = HEAP_strdupWtoA(GetProcessHeap(),0,lpszExeFileName);
+  ret = ExtractIcon32A(hInstance,exefn,nIconIndex);
 
 	HeapFree(GetProcessHeap(),0,exefn);
 	return ret;
@@ -1269,29 +1229,28 @@
  */
 HICON32 WINAPI ExtractAssociatedIcon32A(HINSTANCE32 hInst,LPSTR lpIconPath,
 	LPWORD lpiIcon)
-{
+{ TRACE(shell,"\n");
 	return ExtractAssociatedIcon16(hInst,lpIconPath,lpiIcon);
 }
 
 HICON16 WINAPI ExtractAssociatedIcon16(HINSTANCE16 hInst,LPSTR lpIconPath,
 	LPWORD lpiIcon)
-{
-    HICON16 hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
+{ HICON16 hIcon;
 
-    if( hIcon < 2 )
-    {
+  TRACE(shell,"\n");
 
-	if( hIcon == 1 ) /* no icons found in given file */
-	{
-	    char  tempPath[0x80];
+  hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
+
+  if( hIcon < 2 )
+  { if( hIcon == 1 ) /* no icons found in given file */
+    { char  tempPath[0x80];
 	    UINT16  uRet = FindExecutable16(lpIconPath,NULL,tempPath);
 
 	    if( uRet > 32 && tempPath[0] )
-	    {
-		strcpy(lpIconPath,tempPath);
+      { strcpy(lpIconPath,tempPath);
 		hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
-
-		if( hIcon > 2 ) return hIcon;
+        if( hIcon > 2 ) 
+          return hIcon;
 	    }
 	    else hIcon = 0;
 	}
@@ -1304,7 +1263,6 @@
 	GetModuleFileName16(hInst, lpIconPath, 0x80);
 	hIcon = LoadIcon16( hInst, MAKEINTRESOURCE16(*lpiIcon));
     }
-
     return hIcon;
 }
 
@@ -1314,12 +1272,14 @@
  * Returns a pointer into the DOS environment... Ugh.
  */
 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
-{
-    UINT16 	l = strlen(entry); 
-    for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
-    {
-	if( lstrncmpi32A(lpEnv, entry, l) ) continue;
+{ UINT16 l;
 
+  TRACE(shell,"\n");
+
+  l = strlen(entry); 
+  for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
+  { if( lstrncmpi32A(lpEnv, entry, l) ) 
+      continue;
 	if( !*(lpEnv+l) )
 	    return (lpEnv + l); 		/* empty entry */
 	else if ( *(lpEnv+l)== '=' )
@@ -1329,15 +1289,17 @@
 }
 
 SEGPTR WINAPI FindEnvironmentString(LPSTR str)
-{
-    SEGPTR  spEnv = GetDOSEnvironment();
-    LPSTR  lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
+{ SEGPTR  spEnv;
+  LPSTR lpEnv,lpString;
+  TRACE(shell,"\n");
+    
+  spEnv = GetDOSEnvironment();
 
-    LPSTR  lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL; 
+  lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
+  lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL; 
 
     if( lpString )		/*  offset should be small enough */
 	return spEnv + (lpString - lpEnv);
-
     return (SEGPTR)NULL;
 }
 
@@ -1356,7 +1318,7 @@
 
   CharToOem32A(str,str);
 
-  TRACE(reg,"accept %s\n", str);
+  TRACE(shell,"accept %s\n", str);
 
   while( *lpstr && lpbstr - lpBuffer < length )
    {
@@ -1376,7 +1338,7 @@
 
 		   if( l > length - (lpbstr - lpBuffer) - 1 )
 		     {
-		       WARN(reg,"Env subst aborted - string too short\n");
+           WARN(shell,"-- Env subst aborted - string too short\n");
 		      *lpend = '%';
 		       break;
 		     }
@@ -1404,7 +1366,7 @@
   else
       length = 0;
 
-  TRACE(reg,"    return %s\n", str);
+  TRACE(shell,"-- return %s\n", str);
 
   OemToChar32A(str,str);
   HeapFree( GetProcessHeap(), 0, lpBuffer);
@@ -1421,7 +1383,7 @@
  */
 LRESULT WINAPI ShellHookProc(INT16 code, WPARAM16 wParam, LPARAM lParam)
 {
-    TRACE(reg,"%i, %04x, %08x\n", code, wParam, 
+    TRACE(shell,"%i, %04x, %08x\n", code, wParam, 
 						      (unsigned)lParam );
     if( SHELL_hHook && SHELL_hWnd )
     {
@@ -1441,64 +1403,144 @@
  *				RegisterShellHook	[SHELL.102]
  */
 BOOL32 WINAPI RegisterShellHook(HWND16 hWnd, UINT16 uAction)
-{
-    TRACE(reg,"%04x [%u]\n", hWnd, uAction );
+{ TRACE(shell,"%04x [%u]\n", hWnd, uAction );
 
     switch( uAction )
-    {
-	case 2:	/* register hWnd as a shell window */
-
+  { case 2:  /* register hWnd as a shell window */
 	     if( !SHELL_hHook )
-	     {
-		HMODULE16 hShell = GetModuleHandle16( "SHELL" );
-
-		SHELL_hHook = SetWindowsHookEx16( WH_SHELL, ShellHookProc,
-                                                  hShell, 0 );
+      { HMODULE16 hShell = GetModuleHandle16( "SHELL" );
+        SHELL_hHook = SetWindowsHookEx16( WH_SHELL, ShellHookProc, hShell, 0 );
 		if( SHELL_hHook )
-		{
-		    uMsgWndCreated = RegisterWindowMessage32A( lpstrMsgWndCreated );
+        { uMsgWndCreated = RegisterWindowMessage32A( lpstrMsgWndCreated );
 		    uMsgWndDestroyed = RegisterWindowMessage32A( lpstrMsgWndDestroyed );
 		    uMsgShellActivate = RegisterWindowMessage32A( lpstrMsgShellActivate );
 		} 
-		else WARN(reg, "unable to install ShellHookProc()!\n");
+        else 
+          WARN(shell,"-- unable to install ShellHookProc()!\n");
 	     }
 
-	     if( SHELL_hHook ) return ((SHELL_hWnd = hWnd) != 0);
+      if( SHELL_hHook )
+        return ((SHELL_hWnd = hWnd) != 0);
 	     break;
 
 	default:
-
-	     WARN(reg, "unknown code %i\n", uAction );
-
+    WARN(shell, "-- unknown code %i\n", uAction );
 	     /* just in case */
-
 	     SHELL_hWnd = 0;
     }
     return FALSE;
 }
 
-
 /*************************************************************************
  *				SHGetFileInfoA		[SHELL32.218]
+ *
+ * FIXME
+ *   
  */
+HIMAGELIST ShellSmallIconList = 0;
+HIMAGELIST ShellBigIconList = 0;
+
 DWORD WINAPI SHGetFileInfo32A(LPCSTR path,DWORD dwFileAttributes,
                               SHFILEINFO32A *psfi, UINT32 sizeofpsfi,
                               UINT32 flags )
-{
-	FIXME(shell,"(%s,0x%08lx,%p,%d,0x%08x): stub\n",
+{ CHAR szTemp[MAX_PATH];
+  DWORD ret=0;
+  
+  TRACE(shell,"(%s,0x%x,%p,0x%x,0x%x)\n",
 	      path,dwFileAttributes,psfi,sizeofpsfi,flags);
-	return TRUE;
+
+  /* translate the pidl to a path*/
+  if (flags & SHGFI_PIDL)
+  { SHGetPathFromIDList32A ((LPCITEMIDLIST)path,szTemp);
+    TRACE(shell,"pidl=%p is %s\n",path,szTemp);
+  }
+
+  if (flags & SHGFI_ATTRIBUTES)
+  { FIXME(shell,"file attributes, stub\n");
+    psfi->dwAttributes=0;
+    ret=TRUE;    
+  }
+
+  if (flags & SHGFI_DISPLAYNAME)
+  { if (flags & SHGFI_PIDL)
+    { strcpy(psfi->szDisplayName,szTemp);
+    }
+    else
+    { strcpy(psfi->szDisplayName,path);
+      TRACE(shell,"displayname=%s\n", szTemp);
+    }
+    ret=TRUE;
+  }
+  
+  if (flags & SHGFI_TYPENAME)
+  { FIXME(shell,"get the file type, stub\n");
+    strcpy(psfi->szTypeName,"");
+    ret=TRUE;
+  }
+  
+  if (flags & SHGFI_ICONLOCATION)
+  { FIXME(shell,"location of icon, stub\n");
+    strcpy(psfi->szDisplayName,"");
+    ret=TRUE;
+  }
+
+  if (flags & SHGFI_EXETYPE)
+    FIXME(shell,"type of executable, stub\n");
+
+  if (flags & SHGFI_LINKOVERLAY)
+    FIXME(shell,"set icon to link, stub\n");
+
+  if (flags & SHGFI_OPENICON)
+    FIXME(shell,"set to open icon, stub\n");
+
+  if (flags & SHGFI_SELECTED)
+    FIXME(shell,"set icon to selected, stub\n");
+
+  if (flags & SHGFI_SHELLICONSIZE)
+    FIXME(shell,"set icon to shell size, stub\n");
+
+  if (flags & SHGFI_USEFILEATTRIBUTES)
+    FIXME(shell,"use the dwFileAttributes, stub\n");
+ 
+  if (flags & SHGFI_ICON)
+  { FIXME(shell,"icon handle\n");
+    if (flags & SHGFI_SMALLICON)
+     { TRACE(shell,"set to small icon\n"); 
+       psfi->hIcon=ImageList_GetIcon(ShellSmallIconList,0,ILD_NORMAL);
+       ret = (DWORD) ShellSmallIconList;
+     }
+     else
+     { TRACE(shell,"set to big icon\n");
+       psfi->hIcon=ImageList_GetIcon(ShellBigIconList,0,ILD_NORMAL);
+       ret = (DWORD) ShellBigIconList;
+     }      
+  }
+
+  if (flags & SHGFI_SYSICONINDEX)
+  {  FIXME(shell,"get the SYSICONINDEX\n");
+     psfi->iIcon=1;
+     if (flags & SHGFI_SMALLICON)
+     { TRACE(shell,"set to small icon\n"); 
+       ret = (DWORD) ShellSmallIconList;
+     }
+     else        
+     { TRACE(shell,"set to big icon\n");
+       ret = (DWORD) ShellBigIconList;
+     }
+  }
+
+ 
+  return ret;
 }
 
 /*************************************************************************
  *				SHAppBarMessage32	[SHELL32.207]
  */
 UINT32 WINAPI SHAppBarMessage32(DWORD msg, PAPPBARDATA data)
-{
-    FIXME(shell,"(0x%08lx,%p): stub\n", msg, data);
+{ FIXME(shell,"(0x%08lx,%p): stub\n", msg, data);
 #if 0
-    switch (msg) {
-        case ABM_ACTIVATE:
+  switch (msg)
+  { case ABM_ACTIVATE:
         case ABM_GETAUTOHIDEBAR:
         case ABM_GETSTATE:
         case ABM_GETTASKBARPOS:
@@ -1518,17 +1560,17 @@
  *				CommandLineToArgvW	[SHELL32.7]
  */
 LPWSTR* WINAPI CommandLineToArgvW(LPWSTR cmdline,LPDWORD numargs)
-{
-	LPWSTR	*argv,s,t;
+{ LPWSTR  *argv,s,t;
 	int	i;
+  TRACE(shell,"\n");
 
         /* to get writeable copy */
 	cmdline = HEAP_strdupW( GetProcessHeap(), 0, cmdline);
 	s=cmdline;i=0;
-	while (*s) {
-		/* space */
-		if (*s==0x0020) {
-			i++;
+  while (*s)
+  { /* space */
+    if (*s==0x0020) 
+    { i++;
 			s++;
 			while (*s && *s==0x0020)
 				s++;
@@ -1539,9 +1581,9 @@
 	argv=(LPWSTR*)HeapAlloc( GetProcessHeap(), 0, sizeof(LPWSTR)*(i+1) );
 	s=t=cmdline;
 	i=0;
-	while (*s) {
-		if (*s==0x0020) {
-			*s=0;
+  while (*s)
+  { if (*s==0x0020)
+    { *s=0;
 			argv[i++]=HEAP_strdupW( GetProcessHeap(), 0, t );
 			*s=0x0020;
 			while (*s && *s==0x0020)
@@ -1571,8 +1613,7 @@
  */
 
 void WINAPI Control_RunDLL (HWND32 hwnd, LPCVOID code, LPCSTR cmd, DWORD arg4)
-{
-  TRACE(exec, "(%08x, %p, \"%s\", %08lx)\n",
+{ FIXME(shell, "(%08x, %p, \"%s\", %08lx)\n",
 	hwnd, code ? code : "(null)", cmd ? cmd : "(null)", arg4);
 }
 
@@ -1580,8 +1621,7 @@
  * FreeIconList
  */
 void WINAPI FreeIconList( DWORD dw )
-{
-    FIXME(reg, "(%lx): stub\n",dw);
+{ FIXME(shell, "(%lx): stub\n",dw);
 }
 
 /*************************************************************************
@@ -1615,8 +1655,6 @@
 	  if(IsEqualCLSID(rclsid, &CLSID_ShellLink))         /*debug*/
 	    TRACE(shell,"requested CLSID_ShellLink\n");
 
-    /* fixme: the IClassFactory_Constructor is at the moment only 
-		 for rclsid=CLSID_ShellDesktop, so we get the right Interface (jsch)*/
 	  lpclf = IClassFactory_Constructor();
     if(lpclf)
     { hres = lpclf->lpvtbl->fnQueryInterface(lpclf,iid, ppv);
@@ -1891,48 +1929,71 @@
 /*************************************************************************
  * SHGetPathFromIDList32A        [SHELL32.261][NT 4.0: SHELL32.220]
  *
+ * PARAMETERS
+ *  pidl,   [IN] pidl 
+ *  pszPath [OUT] path
+ *
+ * RETURNS 
+ *  path from a passed PIDL.
+ *
  * NOTES
  *     exported by name
+ *
  * FIXME
  *  fnGetDisplayNameOf can return different types of OLEString
  */
-DWORD WINAPI SHGetPathFromIDList32A (
-    LPCITEMIDLIST pidl, /* [IN] pidl */
-		LPSTR pszPath)      /* [OUT] path */
+DWORD WINAPI SHGetPathFromIDList32A (LPCITEMIDLIST pidl,LPSTR pszPath)
 {	STRRET lpName;
 	LPSHELLFOLDER shellfolder;
+  CHAR  buffer[MAX_PATH],tpath[MAX_PATH];
+  DWORD type,tpathlen=MAX_PATH,dwdisp;
+  HKEY  key;
+
 	TRACE(shell,"(pidl=%p,%p)\n",pidl,pszPath);
 
-	if (SHGetDesktopFolder(&shellfolder)==S_OK)
+  if (!pidl)
+  {  strcpy(buffer,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\");
+
+     if (RegCreateKeyEx32A(HKEY_CURRENT_USER,buffer,0,NULL,REG_OPTION_NON_VOLATILE,KEY_WRITE,NULL,&key,&dwdisp))
+     { return E_OUTOFMEMORY;
+     }
+     type=REG_SZ;    
+     strcpy (buffer,"Desktop");					/*registry name*/
+     if ( RegQueryValueEx32A(key,buffer,NULL,&type,tpath,&tpathlen))
+     { GetWindowsDirectory32A(tpath,MAX_PATH);
+       PathAddBackslash(tpath);
+       strcat (tpath,"Desktop");				/*folder name*/
+       RegSetValueEx32A(key,buffer,0,REG_SZ,tpath,tpathlen);
+       CreateDirectory32A(tpath,NULL);
+     }
+     RegCloseKey(key);
+     strcpy(pszPath,tpath);
+  }
+  else
+  { if (SHGetDesktopFolder(&shellfolder)==S_OK)
 	{ shellfolder->lpvtbl->fnGetDisplayNameOf(shellfolder,pidl,SHGDN_FORPARSING,&lpName);
 	  shellfolder->lpvtbl->fnRelease(shellfolder);
 	}
   /*WideCharToLocal32(pszPath, lpName.u.pOleStr, MAX_PATH);*/
 	strcpy(pszPath,lpName.u.cStr);
 	/* fixme free the olestring*/
+  }
 	TRACE(shell,"-- (%s)\n",pszPath);
 	return NOERROR;
 }
 /*************************************************************************
  * SHGetPathFromIDList32W [SHELL32.262]
- *
- * NOTES
- *     exported by name
  */
-DWORD WINAPI SHGetPathFromIDList32W (DWORD dwParam1,DWORD dwParam2)
-{ FIXME (shell,"(0x%08lx,0x%08lx):stub.\n", dwParam1, dwParam2);
+DWORD WINAPI SHGetPathFromIDList32W (LPCITEMIDLIST pidl,LPWSTR pszPath)
+{ FIXME (shell,"(pidl=%p %s):stub.\n", pidl, debugstr_w(pszPath));
   return 0;
 }
+
 /*************************************************************************
  *			 SHGetPathFromIDList		[SHELL32.221][NT 4.0: SHELL32.219]
- *
- * returns the path from a passed PIDL.
  */
-BOOL32 WINAPI SHGetPathFromIDList( 
-    LPCITEMIDLIST pidl, /* [IN] pidl */
-		LPSTR pszPath)      /* [OUT] path */
+BOOL32 WINAPI SHGetPathFromIDList32(LPCITEMIDLIST pidl,LPSTR pszPath)     
 { TRACE(shell,"(pidl=%p,%p)\n",pidl,pszPath);
-
   return SHGetPathFromIDList32A(pidl,pszPath);
 }
 
@@ -1940,9 +2001,7 @@
  * SHHelpShortcuts_RunDLL [SHELL32.224]
  *
  */
-
-DWORD WINAPI
-SHHelpShortcuts_RunDLL (DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
+DWORD WINAPI SHHelpShortcuts_RunDLL (DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
 { FIXME (exec, "(%lx, %lx, %lx, %lx) empty stub!\n",
 	dwArg1, dwArg2, dwArg3, dwArg4);
 
@@ -1954,11 +2013,8 @@
  *
  */
 
-DWORD WINAPI
-SHLoadInProc (DWORD dwArg1)
-{
-    FIXME (shell, "(%lx) empty stub!\n", dwArg1);
-
+DWORD WINAPI SHLoadInProc (DWORD dwArg1)
+{ FIXME (shell, "(%lx) empty stub!\n", dwArg1);
     return 0;
 }
 
@@ -1966,11 +2022,60 @@
  * SHBrowseForFolderA [SHELL32.209]
  *
  */
-
-LPITEMIDLIST WINAPI
-SHBrowseForFolder32A (LPBROWSEINFO32A lpbi)
-{ FIXME (shell, "(%lx) empty stub!\n", (DWORD)lpbi);
-  FIXME (shell, "(%s) empty stub!\n", lpbi->lpszTitle);
+LPITEMIDLIST WINAPI SHBrowseForFolder32A (LPBROWSEINFO32A lpbi)
+{ FIXME (shell, "(%lx,%s) empty stub!\n", (DWORD)lpbi, lpbi->lpszTitle);
   return NULL;
 }
 
+/*************************************************************************
+ * SHELL32 LibMain
+ *
+ * FIXME
+ *  at the moment the icons are extracted from shell32.dll
+ */
+HINSTANCE32 shell32_hInstance; 
+
+BOOL32 WINAPI Shell32LibMain(HINSTANCE32 hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{ HICON32 htmpIcon;
+  UINT32 iiconindex;
+  UINT32 index;
+  CHAR   szShellPath[MAX_PATH];
+  
+  TRACE(shell,"0x%x 0x%lx %p\n", hinstDLL, fdwReason, lpvReserved);
+
+  shell32_hInstance = hinstDLL;
+  
+  GetWindowsDirectory32A(szShellPath,MAX_PATH);
+  PathAddBackslash(szShellPath);
+  strcat(szShellPath,"system\\shell32.dll");
+       
+  if (fdwReason==DLL_PROCESS_ATTACH)
+  { if ( ! ShellSmallIconList )
+    { if ( (ShellSmallIconList = ImageList_Create(16,16,ILC_COLOR,64,16)) )
+      { for (index=0;index < 40; index++)
+        { if ( ( htmpIcon = ExtractIcon32A(hinstDLL, szShellPath, index)) )
+          { iiconindex = ImageList_AddIcon (ShellSmallIconList, htmpIcon);
+          }
+          else
+          { ERR(shell,"could not initialize iconlist (is shell32.dll in the system directory?)\n");
+            break;
+          }
+        }
+      }
+    }
+    if ( ! ShellBigIconList )
+    { if ( (ShellBigIconList = ImageList_Create(32,32,ILC_COLOR,64,16)) )
+      { for (index=0;index < 40; index++)
+        { if ( (htmpIcon = ExtractIcon32A( hinstDLL, szShellPath, index)) )
+          { iiconindex = ImageList_AddIcon (ShellBigIconList, htmpIcon);
+          }
+          else
+          { ERR(shell,"could not initialize iconlist (is shell32.dll in the system directory?)\n");
+            break;
+          }
+        }
+      }
+    }
+  }
+  return TRUE;
+}
diff --git a/misc/shellord.c b/misc/shellord.c
index 6661780..9076838 100644
--- a/misc/shellord.c
+++ b/misc/shellord.c
@@ -8,6 +8,7 @@
  * They are just here so that explorer.exe and iexplore.exe can be tested.
  *
  * Copyright 1997 Marcus Meissner
+ *           1998 Jürgen Schmied
  */
 #include <stdlib.h>
 #include <string.h>
@@ -30,6 +31,18 @@
 #include "debug.h"
 #include "winreg.h"
 
+void pdump (LPCITEMIDLIST pidl)
+{ DWORD type;
+  CHAR * szData;
+  LPITEMIDLIST pidltemp = pidl;
+  TRACE(shell,"---------- pidl=%p \n", pidl);
+  do
+  { szData = ((LPPIDLDATA )(pidltemp->mkid.abID))->szText;
+    type   = ((LPPIDLDATA )(pidltemp->mkid.abID))->type;
+    TRACE (shell,"---- pidl=%p size=%u type=%lx %s\n",pidltemp, pidltemp->mkid.cb,type,debugstr_a(szData));
+    pidltemp = (LPITEMIDLIST)(((BYTE*)pidltemp)+pidltemp->mkid.cb);
+  } while (pidltemp->mkid.cb);
+}
 /*************************************************************************
  * SHChangeNotifyRegister [SHELL32.2]
  * NOTES
@@ -85,9 +98,12 @@
 /*************************************************************************
  * ILFindLastID [SHELL32.17]
  * NOTES
- *  Creates a new list with the last tiem removed
+ *  Creates a new list with the last item removed
  */
- LPITEMIDLIST WINAPI ILRemoveLastID(LPCITEMIDLIST);
+LPITEMIDLIST WINAPI ILRemoveLastID(LPCITEMIDLIST pidl)
+{ TRACE(shell,"pidl=%p\n",pidl);
+  return NULL;
+}
 
 
 /*************************************************************************
@@ -96,15 +112,20 @@
  * NOTES
  *    dupicate an idlist
  */
-LPITEMIDLIST WINAPI ILClone (LPITEMIDLIST iil) {
-	DWORD		len;
-	LPITEMIDLIST	newiil;
-  TRACE(shell,"%p\n",iil);
-	len = ILGetSize(iil);
-	newiil = (LPITEMIDLIST)SHAlloc(len);
-	if (newiil)
-		memcpy(newiil,iil,len);
-	return newiil;
+LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl)
+{ DWORD    len;
+  LPITEMIDLIST  newpidl;
+
+  TRACE(shell,"%p\n",pidl);
+
+  if (!pidl)
+    return NULL;
+    
+  len = ILGetSize(pidl);
+  newpidl = (LPITEMIDLIST)SHAlloc(len);
+  if (newpidl)
+    memcpy(newpidl,pidl,len);
+  return newpidl;
 }
 
 /*************************************************************************
@@ -113,7 +134,10 @@
  * NOTES
  *  duplicates the first idlist of a complex pidl
  */
-LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl);
+LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl)
+{ FIXME(shell,"pidl=%p\n",pidl);
+  return NULL;
+}
 
 /*************************************************************************
  * ILCombine [SHELL32.25]
@@ -123,16 +147,37 @@
  *  The pidl is the first one, pidlsub the next one
  *  Does not destroy the passed in idlists!
  */
-LPITEMIDLIST WINAPI ILCombine(LPITEMIDLIST iil1,LPITEMIDLIST iil2) {
-	DWORD		len1,len2;
-	LPITEMIDLIST	newiil;
-	TRACE(shell,"%p %p\n",iil1,iil2);
-	len1 	= ILGetSize(iil1)-2;
-	len2	= ILGetSize(iil2);
-	newiil	= SHAlloc(len1+len2);
-	memcpy(newiil,iil1,len1);
-	memcpy(((char*)newiil)+len1,iil2,len2);
-	return newiil;
+LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
+{ DWORD    len1,len2;
+  LPITEMIDLIST  pidlNew;
+  
+  TRACE(shell,"pidl=%p pidl=%p\n",pidl1,pidl2);
+
+  if(!pidl1 && !pidl2)
+  {  return NULL;
+  }
+ 
+  if(!pidl1)
+  { pidlNew = ILClone(pidl2);
+    return pidlNew;
+  }
+
+  if(!pidl2)
+  { pidlNew = ILClone(pidl1);
+    return pidlNew;
+  }
+
+  len1  = ILGetSize(pidl1)-2;
+  len2  = ILGetSize(pidl2);
+  pidlNew  = SHAlloc(len1+len2);
+  
+  if (pidlNew)
+  { memcpy(pidlNew,pidl1,len1);
+    memcpy(((BYTE *)pidlNew)+len1,pidl2,len2);
+  }
+
+/*  TRACE(shell,"--new pidl=%p\n",pidlNew);*/
+  return pidlNew;
 }
 
 /*************************************************************************
@@ -291,6 +336,19 @@
 }
 
 /*************************************************************************
+ * PathAppend [SHELL32.36]
+ * 
+ * NOTES
+ *     concat_paths(char*target,const char*add);
+ *     concats "target\\add" and writes them to target
+ */
+LPSTR WINAPI PathAppend(LPSTR x1,LPSTR x2) {
+  TRACE(shell,"%s %s\n",x1,x2);
+  while (x2[0]=='\\') x2++;
+  return PathCombine(x1,x1,x2);
+}
+
+/*************************************************************************
  * PathCombine [SHELL32.37]
  * 
  * NOTES
@@ -312,19 +370,6 @@
 }
 
 /*************************************************************************
- * PathAppend [SHELL32.36]
- * 
- * NOTES
- *     concat_paths(char*target,const char*add);
- *     concats "target\\add" and writes them to target
- */
-LPSTR WINAPI PathAppend(LPSTR x1,LPSTR x2) {
-  TRACE(shell,"%s %s\n",x1,x2);
-	while (x2[0]=='\\') x2++;
-	return PathCombine(x1,x1,x2);
-}
-
-/*************************************************************************
  * PathIsUNC [SHELL32.39]
  * 
  * NOTES
@@ -457,69 +502,28 @@
  * Shell_GetCachedImageIndex [SHELL32.72]
  *
  */
-void WINAPI Shell_GetCachedImageIndex(LPSTR x,DWORD y,DWORD z) {
-	FIXME(shell,"(%s,%08lx,%08lx):stub.\n",x,y,z);
+void WINAPI Shell_GetCachedImageIndex(LPSTR x,DWORD y,DWORD z) 
+{ FIXME(shell,"(%s,%08lx,%08lx):stub.\n",x,y,z);
 }
+
 /*************************************************************************
  * SHShellFolderView_Message [SHELL32.73]
+ *
+ * PARAMETERS
+ *  hwndCabinet defines the explorer cabinet window that contains the 
+ *              shellview you need to communicate with
+ *  uMsg        identifying the SFVM enum to perform
+ *  lParam
+ *
  * NOTES
  *  Message SFVM_REARRANGE = 1
  *    This message gets sent when a column gets clicked to instruct the
  *    shell view to re-sort the item list. lParam identifies the column
  *    that was clicked.
  */
-int WINAPI SHShellFolderView_Message(
-    HWND32 hwndCabinet, /* This hwnd defines the explorer cabinet window that contains the 
-                         shellview you need to communicate with*/
-		UINT32 uMsg,        /* A parameter identifying the SFVM enum to perform */
-		LPARAM lParam);
-/*************************************************************************
- * SHCloneSpecialIDList [SHELL32.89]
- * 
- * NOTES
- *     exported by ordinal
- */
-DWORD WINAPI SHCloneSpecialIDList(DWORD x1,DWORD x2,DWORD x3) {
-	FIXME(shell,"(0x%08lx,0x%08lx,0x%08lx):stub.\n",
-		x1,x2,x3
-	);
-	return 0;
-}
-
-/*************************************************************************
- * IsLFNDrive [SHELL32.119]
- * 
- * NOTES
- *     exported by ordinal Name
- */
-void WINAPI IsLFNDrive(LPVOID x) {
-    FIXME(shell,"(%p(%s)):stub.\n",x,(char *)x);
-}
-
-/*************************************************************************
- * SHGetSpecialFolderPath [SHELL32.175]
- * 
- * NOTES
- *     exported by ordinal
- */
-void WINAPI SHGetSpecialFolderPath(DWORD x1,DWORD x2,DWORD x3,DWORD x4) {
-    FIXME(shell,"(0x%08lx,0x%08lx,0x%08lx,0x%08lx):stub.\n",
-    	x1,x2,x3,x4
-    );
-}
-
-/*************************************************************************
- * RegisterShellHook [SHELL32.181]
- *
- * PARAMS
- *      hwnd [I]  window handle
- *      y    [I]  flag ????
- *
- * NOTES
- *     exported by ordinal
- */
-void WINAPI RegisterShellHook32(HWND32 hwnd, DWORD y) {
-    FIXME(shell,"(0x%08x,0x%08lx):stub.\n",hwnd,y);
+int WINAPI SHShellFolderView_Message(HWND32 hwndCabinet,UINT32 uMsg,LPARAM lParam)
+{ FIXME(shell,"%04x %08ux %08lx stub\n",hwndCabinet,uMsg,lParam);
+  return 0;
 }
 
 /*************************************************************************
@@ -535,22 +539,22 @@
 
 /*************************************************************************
  * SHMapPIDLToSystemImageListIndex [SHELL32.77]
+ *
+ * PARAMETERS
+ * x  pointer to an instance of IShellFolder 
  * 
  * NOTES
  *     exported by ordinal
  *
  */
 DWORD WINAPI
-SHMapPIDLToSystemImageListIndex(
-    DWORD x,	/* pointer to an instance of IShellFolder */
-		DWORD y,
-		DWORD z)
-{	FIXME(shell,"(%08lx,%08lx,%08lx):stub.\n",x,y,z);
-	return 0;
+SHMapPIDLToSystemImageListIndex(DWORD x,DWORD y,DWORD z)
+{ FIXME(shell,"(%08lx,%08lx,%08lx):stub.\n",x,y,z);
+  return 0;
 }
 
 /*************************************************************************
- * OleStrToStrN	[SHELL32.78]
+ * OleStrToStrN  [SHELL32.78]
  * 
  * NOTES
  *     exported by ordinal
@@ -558,12 +562,12 @@
 BOOL32 WINAPI
 OleStrToStrN (LPSTR lpMulti, INT32 nMulti, LPCWSTR lpWide, INT32 nWide) {
     return WideCharToMultiByte (0, 0, lpWide, nWide,
-				lpMulti, nMulti, NULL, NULL);
+        lpMulti, nMulti, NULL, NULL);
 }
 
 /*************************************************************************
- * StrToOleStrN	[SHELL32.79]
- * 
+ * StrToOleStrN  [SHELL32.79]
+ *
  * NOTES
  *     exported by ordinal
  */
@@ -573,14 +577,68 @@
 }
 
 /*************************************************************************
+ * SHCloneSpecialIDList [SHELL32.89]
+ * 
+ * PARAMETERS
+ *  hwnd 
+ * NOTES
+ *     exported by ordinal
+ */
+DWORD WINAPI SHCloneSpecialIDList(HWND32 hwnd,DWORD x2,DWORD x3) {
+  FIXME(shell,"(hwnd=0x%x,0x%lx,0x%lx):stub.\n",
+    hwnd,x2,x3
+  );
+  return S_OK;
+}
+
+/*************************************************************************
+ * IsLFNDrive [SHELL32.119]
+ * 
+ * NOTES
+ *     exported by ordinal Name
+ */
+BOOL32 WINAPI IsLFNDrive(LPCSTR path) {
+    DWORD	fnlen;
+
+    if (!GetVolumeInformation32A(path,NULL,0,NULL,&fnlen,NULL,NULL,0))
+	return FALSE;
+    return fnlen>12;
+}
+
+/*************************************************************************
+ * SHGetSpecialFolderPath [SHELL32.175]
+ * 
+ * NOTES
+ *     exported by ordinal
+ */
+void WINAPI SHGetSpecialFolderPath(DWORD x1,DWORD x2,DWORD x3,DWORD x4) {
+    FIXME(shell,"(0x%08lx,0x%08lx,0x%08lx,0x%08lx):stub.\n",
+      x1,x2,x3,x4
+    );
+}
+
+/*************************************************************************
+ * RegisterShellHook [SHELL32.181]
+ *
+ * PARAMS
+ *      hwnd [I]  window handle
+ *      y    [I]  flag ????
+ * 
+ * NOTES
+ *     exported by ordinal
+ */
+void WINAPI RegisterShellHook32(HWND32 hwnd, DWORD y) {
+    FIXME(shell,"(0x%08x,0x%08lx):stub.\n",hwnd,y);
+}
+
+/*************************************************************************
  *
  */
 typedef DWORD (* WINAPI GetClassPtr)(REFCLSID,REFIID,LPVOID);
 
 static GetClassPtr SH_find_moduleproc(LPSTR dllname,HMODULE32 *xhmod,
                                       LPSTR name)
-{
-	HMODULE32	hmod;
+{ HMODULE32  hmod;
 	FARPROC32	dllunload,nameproc;
 
 	if (xhmod) *xhmod = 0;
@@ -760,23 +818,31 @@
 
 /*************************************************************************
  * ILGetSize [SHELL32.152]
+ *  gets the byte size of an idlist including zero terminator (pidl)
+ *
+ * PARAMETERS
+ *  pidl ITEMIDLIST
+ *
+ * RETURNS
+ *  size of pidl
  *
  * NOTES
  *  exported by ordinal
- *  Gets the byte size of an idlist including zero terminator
  */
-DWORD WINAPI ILGetSize(LPITEMIDLIST iil) {
-	LPSHITEMID	si;
-	DWORD		len;
-	TRACE(shell,"%p\n",iil);
-	if (!iil)
-		return 0;
-	si = &(iil->mkid);
-	len = 2;
-	while (si->cb) {
-		len	+= si->cb;
-		si	 = (LPSHITEMID)(((char*)si)+si->cb);
+DWORD WINAPI ILGetSize(LPITEMIDLIST pidl)
+{ LPSHITEMID si = &(pidl->mkid);
+  DWORD  len=0;
+
+  TRACE(shell,"pidl=%p\n",pidl);
+
+  if (pidl)
+  { while (si->cb) 
+    { len += si->cb;
+      si  = (LPSHITEMID)(((LPBYTE)si)+si->cb);
+    }
+    len += 2;
 	}
+/*  TRACE(shell,"-- size=%lu\n",len);*/
 	return len;
 }
 /*************************************************************************
@@ -788,7 +854,10 @@
  *  otherwise adds the item to the end.
  *  Destroys the passed in idlist!
  */
-LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL32 bEnd);
+LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl,LPCITEMIDLIST item,BOOL32 bEnd)
+{ TRACE(shell,"(pidl=%p,pidl=%p,%08u)\n",pidl,item,bEnd);
+  return NULL;
+}
 
 /*************************************************************************
  * PathGetExtension [SHELL32.158]
@@ -796,8 +865,8 @@
  * NOTES
  *     exported by ordinal
  */
-LPSTR WINAPI PathGetExtension(LPSTR path,DWORD y,DWORD z) {
-    TRACE(shell,"(%s,%08lx,%08lx)\n",path,y,z);
+LPSTR WINAPI PathGetExtension(LPSTR path,DWORD y,DWORD z)
+{ TRACE(shell,"(%s,%08lx,%08lx)\n",path,y,z);
     path = PathFindExtension(path);
     return *path?(path+1):path;
 }
@@ -831,7 +900,8 @@
  */
 DWORD WINAPI SHFree(LPVOID x) {
   TRACE(shell,"%p\n",x);
-	return LocalFree32((HANDLE32)x);
+  /*return LocalFree32((HANDLE32)x);*/ /* crashes */
+  return HeapFree(GetProcessHeap(),0,x);
 }
 
 /*************************************************************************
@@ -842,8 +912,10 @@
  *     exported by ordinal
  */
 LPVOID WINAPI SHAlloc(DWORD len) {
-  TRACE(shell,"%lu\n",len);
-	return (LPVOID)LocalAlloc32(len,LMEM_ZEROINIT); /* FIXME */
+ /* void * ret = (LPVOID)LocalAlloc32(len,LMEM_ZEROINIT);*/ /* chrashes */
+ void * ret = (LPVOID) HeapAlloc(GetProcessHeap(),0,len);
+  TRACE(shell,"%lu bytes at %p\n",len, ret);
+  return ret;
 }
 
 
@@ -855,11 +927,11 @@
  *     allocated by SHMalloc allocator
  *     exported by ordinal
  */
-DWORD WINAPI ILFree(LPVOID x) {
-	FIXME (shell,"(0x%08lx):stub.\n", (DWORD)x);
-	if (!x)
+DWORD WINAPI ILFree(LPVOID pidl) 
+{ TRACE (shell,"(pidl=0x%08lx)\n",(DWORD)pidl);
+  if (!pidl)
 		return 0;
-	return SHFree(x);
+  return SHFree(pidl);
 }
 
 /*************************************************************************
@@ -976,12 +1048,14 @@
 /*************************************************************************
  * SHAddToRecentDocs [SHELL32.234]
  *
+ * PARAMETERS
+ *   uFlags  [IN] SHARD_PATH or SHARD_PIDL
+ *   pv      [IN] string or pidl, NULL clears the list
+ *
  * NOTES
  *     exported by name
  */
-DWORD WINAPI SHAddToRecentDocs32 (
-    UINT32 uFlags,  /* [IN] SHARD_PATH or SHARD_PIDL */
-		LPCVOID pv)     /* [IN] string or pidl, NULL clears the list */
+DWORD WINAPI SHAddToRecentDocs32 (UINT32 uFlags,LPCVOID pv)   
 { if (SHARD_PIDL==uFlags)
   { FIXME (shell,"(0x%08x,pidl=%p):stub.\n", uFlags,pv);
 	}
@@ -1020,6 +1094,8 @@
 /*************************************************************************
  * SHCreateShellFolderViewEx [SHELL32.174]
  *
+ * NOTES
+ *  see IShellFolder::CreateViewObject
  */
 HRESULT WINAPI SHCreateShellFolderViewEx32(
   LPSHELLVIEWDATA psvcbi, /*[in ] shelltemplate struct*/
@@ -1027,3 +1103,55 @@
 { FIXME (shell,"(%p,%p):stub.\n", psvcbi,ppv);
   return 0;
 }
+/*************************************************************************
+ * SHFind_InitMenuPopup [SHELL32.149]
+ *
+ */
+HRESULT WINAPI SHFind_InitMenuPopup (DWORD u, DWORD v, DWORD w, DWORD x)
+{ FIXME(shell,"0x%08lx 0x%08lx 0x%08lx 0x%08lx stub\n",u,v,w,x);
+  return 0;
+}
+/*************************************************************************
+ * FileMenu_Create [SHELL32.114]
+ *
+ */
+HRESULT WINAPI FileMenu_Create (DWORD u, DWORD v, DWORD w, DWORD x, DWORD z)
+{ FIXME(shell,"0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx stub\n",u,v,w,x,z);
+  return 0;
+}
+/*************************************************************************
+ * ShellExecuteEx [SHELL32.291]
+ *
+ */
+HRESULT WINAPI ShellExecuteEx (DWORD u)
+{ FIXME(shell,"0x%08lx stub\n",u);
+  return 0;
+}
+/*************************************************************************
+ * SHSetInstanceExplorer [SHELL32.176]
+ *
+ */
+HRESULT WINAPI SHSetInstanceExplorer (DWORD u)
+{ FIXME(shell,"0x%08lx stub\n",u);
+  return 0;
+}
+/*************************************************************************
+ * SHGetInstanceExplorer [SHELL32.256]
+ *
+ * NOTES
+ *  exported by name
+ */
+HRESULT WINAPI SHGetInstanceExplorer (DWORD u)
+{ FIXME(shell,"0x%08lx stub\n",u);
+  return 0;
+}
+/*************************************************************************
+ * SHFreeUnusedLibraries [SHELL32.123]
+ *
+ * NOTES
+ *  exported by name
+ */
+HRESULT WINAPI SHFreeUnusedLibraries (DWORD u)
+{ FIXME(shell,"0x%08lx stub\n",u);
+  return 0;
+}
diff --git a/misc/tweak.c b/misc/tweak.c
index 11c19a4..952e141 100644
--- a/misc/tweak.c
+++ b/misc/tweak.c
@@ -22,6 +22,9 @@
  *        03-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
  *             Original implementation.
  *
+ *        05-Aug-1998 Eric Kohl (ekohl@abo.rhein-zeitung.de)
+ *             Removed some unused code.
+ *
  *****************************************************************************/
 
 #include <malloc.h>
@@ -35,10 +38,6 @@
 #include "tweak.h"
 #include "windows.h"
 
-/* Parameters for windows/nonclient.c */
-extern int  NC_MaxControlNudge;
-extern int  NC_MinControlNudge;
-extern UINT32  NC_CaptionTextFlags;
 
 /* Parameters for controls/menu.c */
 extern UINT32  MENU_BarItemTopNudge;
@@ -50,13 +49,8 @@
 extern UINT32  MENU_HighlightBottomNudge;
 extern UINT32  MENU_HighlightRightNudge;
 
-/* General options */
-HPEN32  TWEAK_PenFF95;
-HPEN32  TWEAK_PenE095;
-HPEN32  TWEAK_PenC095;
-HPEN32  TWEAK_Pen8095;
-HPEN32  TWEAK_Pen0095;
 
+/* General options */
 #if defined(WIN_95_LOOK)
 int  TWEAK_Win95Look = 1;
 #else
@@ -104,53 +98,6 @@
 
 /******************************************************************************
  *
- *   int  TWEAK_NonClientInit()
- *
- *   Initializes the Win95 tweaks to the non-client drawing functions.  See
- *   windows/nonclient.c.  Return value indicates success (non-zero) or
- *   failure.
- *
- *   Revision history
- *        05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
- *             Original implementation.
- *
- *****************************************************************************/
-
-static int  TWEAK_NonClientInit()
-{
-    char  key_value[2];
-
-    NC_MaxControlNudge =
-	PROFILE_GetWineIniInt("Tweak.Layout", "MaxControlNudge", 0);
-    NC_MinControlNudge =
-	PROFILE_GetWineIniInt("Tweak.Layout", "MinControlNudge", 0);
-
-    NC_CaptionTextFlags = DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX;
-
-    PROFILE_GetWineIniString("Tweak.Layout", "CaptionAlignment", 
-			     TWEAK_Win95Look ? "l" : "c", key_value, 2);
-
-    switch(key_value[0]) {
-    case 'l':
-    case 'L':
-	NC_CaptionTextFlags |= DT_LEFT;
-	break;
-
-    case 'r':
-    case 'R':
-	NC_CaptionTextFlags |= DT_RIGHT;
-	break;
-
-    default:
-	NC_CaptionTextFlags |= DT_CENTER;
-    }
-
-    return 1;
-}
-
-
-/******************************************************************************
- *
  *   int  TWEAK_VarInit()
  *
  *   Initializes the miscellaneous variables which are used in the tweak
@@ -166,35 +113,6 @@
 {
     TWEAK_Win95Look = PROFILE_GetWineIniBool("Tweak.Layout", "Win95Look", 0);
 
-    /* FIXME: Each color should really occupy a single entry in the wine.conf
-       file, but I couldn't settle on a good (intuitive!) format. */
-
-    TWEAK_PenFF95 = CreatePen32(
-	PS_SOLID, 1,
-	RGB(PROFILE_GetWineIniInt("Tweak.Colors", "PenFF95.Red", 0xff),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "PenFF95.Grn", 0xff),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "PenFF95.Blu", 0xff)));
-    TWEAK_PenE095 = CreatePen32(
-	PS_SOLID, 1,
-	RGB(PROFILE_GetWineIniInt("Tweak.Colors", "PenE095.Red", 0xe0),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "PenE095.Grn", 0xe0),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "PenE095.Blu", 0xe0)));
-    TWEAK_PenC095 = CreatePen32(
-	PS_SOLID, 1,
-	RGB(PROFILE_GetWineIniInt("Tweak.Colors", "PenC095.Red", 0xc0),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "PenC095.Grn", 0xc0),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "PenC095.Blu", 0xc0)));
-    TWEAK_Pen8095 = CreatePen32(
-	PS_SOLID, 1,
-	RGB(PROFILE_GetWineIniInt("Tweak.Colors", "Pen8095.Red", 0x80),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "Pen8095.Grn", 0x80),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "Pen8095.Blu", 0x80)));
-    TWEAK_Pen0095 = CreatePen32(
-	PS_SOLID, 1,
-	RGB(PROFILE_GetWineIniInt("Tweak.Colors", "Pen0095.Red", 0x00),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "Pen0095.Grn", 0x00),
-	    PROFILE_GetWineIniInt("Tweak.Colors", "Pen0095.Blu", 0x00)));
-
     TRACE(tweak, "Using %s look and feel.\n",
 		 TWEAK_Win95Look ? "Win95" : "Win3.1");
     return 1;
@@ -217,7 +135,6 @@
 int  TWEAK_Init()
 {
     TWEAK_VarInit();
-    TWEAK_NonClientInit();
     TWEAK_MenuInit();
     return 1;
 }
@@ -279,14 +196,14 @@
     if((dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC))) {
 
 	/* Draw the top/left lines first */
-	prevpen = SelectObject32(hdc, TWEAK_PenE095);
+	prevpen = SelectObject32(hdc, GetSysColorPen32(COLOR_3DLIGHT));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left, rect->top,
 		  rect->right - 1, rect->top);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left, rect->top,
 		  rect->left, rect->bottom - 1);
 
-	SelectObject32(hdc, TWEAK_PenFF95);
+	SelectObject32(hdc, GetSysColorPen32(COLOR_3DHIGHLIGHT));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left + 1,
 		  rect->top + 1, rect->right - 2, rect->top + 1);
@@ -295,14 +212,14 @@
 
 
 	/* Now the bottom/right lines */
-	SelectObject32(hdc, TWEAK_Pen0095);
+	SelectObject32(hdc, GetSysColorPen32(COLOR_3DDKSHADOW));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left,
 		  rect->bottom - 1, rect->right - 1, rect->bottom - 1);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->right - 1,
 		  rect->top, rect->right - 1, rect->bottom - 1);
 
-	SelectObject32(hdc, TWEAK_Pen8095);
+	SelectObject32(hdc, GetSysColorPen32(COLOR_3DSHADOW));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left + 1,
 		  rect->bottom - 2, rect->right - 2, rect->bottom - 2);
@@ -348,14 +265,14 @@
     if((dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC))) {
 
 	/* Draw the top/left lines first */
-	prevpen = SelectObject32(hdc, TWEAK_Pen8095);
+	prevpen = SelectObject32(hdc, GetSysColorPen32(COLOR_3DSHADOW));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left, rect->top,
 		  rect->right - 1, rect->top);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left, rect->top,
 		  rect->left, rect->bottom - 1);
 
-	SelectObject32(hdc, TWEAK_Pen0095);
+	SelectObject32(hdc, GetSysColorPen32(COLOR_3DDKSHADOW));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left + 1,
 		  rect->top + 1, rect->right - 2, rect->top + 1);
@@ -364,14 +281,14 @@
 
 
 	/* Now the bottom/right lines */
-	SelectObject32(hdc, TWEAK_PenFF95);
+	SelectObject32(hdc, GetSysColorPen32(COLOR_3DHIGHLIGHT));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left,
 		  rect->bottom - 1, rect->right - 1, rect->bottom - 1);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->right - 1,
 		  rect->top, rect->right - 1, rect->bottom - 1);
 
-	SelectObject32(hdc, TWEAK_PenE095);
+	SelectObject32(hdc, GetSysColorPen32(COLOR_3DLIGHT));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, rect->left + 1,
 		  rect->bottom - 2, rect->right - 2, rect->bottom - 2);
@@ -419,13 +336,13 @@
     if((dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC))) {
 
 	/* Draw the top line */
-	prevpen = SelectObject32(hdc, TWEAK_Pen8095);
+	prevpen = SelectObject32(hdc, GetSysColorPen32(COLOR_3DSHADOW));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, xc1, yc - 1, xc2,
 		  yc - 1);
 
 	/* And the bottom line */
-	SelectObject32(hdc, TWEAK_PenFF95);
+	SelectObject32(hdc, GetSysColorPen32(COLOR_3DHIGHLIGHT));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, xc1, yc, xc2, yc);
 
@@ -467,13 +384,13 @@
     if((dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC))) {
 
 	/* Draw the top line */
-	prevpen = SelectObject32(hdc, TWEAK_Pen8095);
+	prevpen = SelectObject32(hdc, GetSysColorPen32(COLOR_3DSHADOW));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, xc, yc1, xc,
 		  yc2);
 
 	/* And the bottom line */
-	SelectObject32(hdc, TWEAK_PenFF95);
+	SelectObject32(hdc, GetSysColorPen32(COLOR_3DHIGHLIGHT));
 	DC_SetupGCForPen(dc);
 	TSXDrawLine(display, dc->u.x.drawable, dc->u.x.gc, xc + 1, yc1, xc + 1,
 		  yc2);
diff --git a/misc/ver.c b/misc/ver.c
index 0c8149b..00d9815 100644
--- a/misc/ver.c
+++ b/misc/ver.c
@@ -1069,7 +1069,7 @@
     }
     if (xret) {
 	if (*tmpfilelen<strlen(tmpfn+tmplast)) {
-	    xret|=VIF_BUFTOSMALL;
+	    xret|=VIF_BUFFTOOSMALL;
 	    DeleteFile32A(tmpfn);
 	} else {
 	    strcpy(tmpfile,tmpfn+tmplast);
diff --git a/misc/winsock.c b/misc/winsock.c
index 5eb67d5..b328794 100644
--- a/misc/winsock.c
+++ b/misc/winsock.c
@@ -514,6 +514,33 @@
     return pwsi->buffer;
 }
 
+struct ws_hostent* _check_buffer_he(LPWSINFO pwsi, int size)
+{
+    if( pwsi->he && pwsi->helen >= size ) return pwsi->he;
+    else SEGPTR_FREE(pwsi->he);
+
+    pwsi->he = (struct ws_hostent*)SEGPTR_ALLOC((pwsi->helen = size)); 
+    return pwsi->he;
+}
+
+struct ws_servent* _check_buffer_se(LPWSINFO pwsi, int size)
+{
+    if( pwsi->se && pwsi->selen >= size ) return pwsi->se;
+    else SEGPTR_FREE(pwsi->se);
+
+    pwsi->se = (struct ws_servent*)SEGPTR_ALLOC((pwsi->selen = size)); 
+    return pwsi->se;
+}
+
+struct ws_protoent* _check_buffer_pe(LPWSINFO pwsi, int size)
+{
+    if( pwsi->pe && pwsi->pelen >= size ) return pwsi->pe;
+    else SEGPTR_FREE(pwsi->pe);
+
+    pwsi->pe = (struct ws_protoent*)SEGPTR_ALLOC((pwsi->pelen = size)); 
+    return pwsi->pe;
+}
+
 /* ----------------------------------- i/o APIs */
 
 /***********************************************************************
@@ -1430,7 +1457,7 @@
 	struct hostent*	host;
 	if( (host = gethostbyaddr(addr, len, type)) != NULL )
 	    if( WS_dup_he(pwsi, host, dup_flag) )
-		return (struct WIN_hostent*)(pwsi->buffer);
+		return (struct WIN_hostent*)(pwsi->he);
 	    else 
 		pwsi->err = WSAENOBUFS;
 	else 
@@ -1468,7 +1495,7 @@
 	struct hostent*     host;
 	if( (host = gethostbyname(name)) != NULL )
 	     if( WS_dup_he(pwsi, host, dup_flag) )
-		 return (struct WIN_hostent*)(pwsi->buffer);
+		 return (struct WIN_hostent*)(pwsi->he);
 	     else pwsi->err = WSAENOBUFS;
 	else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
     }
@@ -1502,7 +1529,7 @@
 	struct protoent*     proto;
 	if( (proto = getprotobyname(name)) != NULL )
 	    if( WS_dup_pe(pwsi, proto, dup_flag) )
-		return (struct WIN_protoent*)(pwsi->buffer);
+		return (struct WIN_protoent*)(pwsi->pe);
 	    else pwsi->err = WSAENOBUFS;
 	else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
     }
@@ -1536,7 +1563,7 @@
 	struct protoent*     proto;
 	if( (proto = getprotobynumber(number)) != NULL )
 	    if( WS_dup_pe(pwsi, proto, dup_flag) )
-		return (struct WIN_protoent*)(pwsi->buffer);
+		return (struct WIN_protoent*)(pwsi->pe);
 	    else pwsi->err = WSAENOBUFS;
 	else pwsi->err = WSANO_DATA;
     }
@@ -1573,7 +1600,7 @@
 	if( i )
 	    if( (serv = getservbyname(pwsi->buffer, pwsi->buffer + i)) != NULL )
 		if( WS_dup_se(pwsi, serv, dup_flag) )
-		    return (struct WIN_servent*)(pwsi->buffer);
+		    return (struct WIN_servent*)(pwsi->se);
 		else pwsi->err = WSAENOBUFS;
 	    else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
 	else pwsi->err = WSAENOBUFS;
@@ -1613,7 +1640,7 @@
 	if( i )
 	    if( (serv = getservbyport(port, pwsi->buffer)) != NULL )
 		if( WS_dup_se(pwsi, serv, dup_flag) )
-		    return (struct WIN_servent*)(pwsi->buffer);
+		    return (struct WIN_servent*)(pwsi->se);
 		else pwsi->err = WSAENOBUFS;
 	    else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
 	else pwsi->err = WSAENOBUFS;
@@ -2450,29 +2477,30 @@
     */
 
    int size = hostent_size(p_he);
+
    if( size )
    {
      struct ws_hostent* p_to;
      char* p_name,*p_aliases,*p_addr,*p_base,*p;
 
-     _check_buffer(pwsi, size);
-     p_to = (struct ws_hostent*)pwsi->buffer;
-     p = pwsi->buffer;
+     _check_buffer_he(pwsi, size);
+     p_to = (struct ws_hostent*)pwsi->he;
+     p = (char*)pwsi->he;
      p_base = (flag & WS_DUP_OFFSET) ? NULL
 				     : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p);
      p += sizeof(struct ws_hostent);
      p_name = p;
      strcpy(p, p_he->h_name); p += strlen(p) + 1;
      p_aliases = p;
-     p += list_dup(p_he->h_aliases, p, p_base + (p - pwsi->buffer), 0);
+     p += list_dup(p_he->h_aliases, p, p_base + (p - (char*)pwsi->he), 0);
      p_addr = p;
-     list_dup(p_he->h_addr_list, p, p_base + (p - pwsi->buffer), p_he->h_length);
+     list_dup(p_he->h_addr_list, p, p_base + (p - (char*)pwsi->he), p_he->h_length);
 
      p_to->h_addrtype = (INT16)p_he->h_addrtype; 
      p_to->h_length = (INT16)p_he->h_length;
-     p_to->h_name = (SEGPTR)(p_base + (p_name - pwsi->buffer));
-     p_to->h_aliases = (SEGPTR)(p_base + (p_aliases - pwsi->buffer));
-     p_to->h_addr_list = (SEGPTR)(p_base + (p_addr - pwsi->buffer));
+     p_to->h_name = (SEGPTR)(p_base + (p_name - (char*)pwsi->he));
+     p_to->h_aliases = (SEGPTR)(p_base + (p_aliases - (char*)pwsi->he));
+     p_to->h_addr_list = (SEGPTR)(p_base + (p_addr - (char*)pwsi->he));
 
      size += (sizeof(struct ws_hostent) - sizeof(struct hostent));
    }
@@ -2499,20 +2527,20 @@
      struct ws_protoent* p_to;
      char* p_name,*p_aliases,*p_base,*p;
 
-     _check_buffer(pwsi, size);
-     p_to = (struct ws_protoent*)pwsi->buffer;
-     p = pwsi->buffer; 
+     _check_buffer_pe(pwsi, size);
+     p_to = (struct ws_protoent*)pwsi->pe;
+     p = (char*)pwsi->pe; 
      p_base = (flag & WS_DUP_OFFSET) ? NULL
 				     : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p);
      p += sizeof(struct ws_protoent);
      p_name = p;
      strcpy(p, p_pe->p_name); p += strlen(p) + 1;
      p_aliases = p;
-     list_dup(p_pe->p_aliases, p, p_base + (p - pwsi->buffer), 0);
+     list_dup(p_pe->p_aliases, p, p_base + (p - (char*)pwsi->pe), 0);
 
      p_to->p_proto = (INT16)p_pe->p_proto;
-     p_to->p_name = (SEGPTR)(p_base) + (p_name - pwsi->buffer);
-     p_to->p_aliases = (SEGPTR)((p_base) + (p_aliases - pwsi->buffer)); 
+     p_to->p_name = (SEGPTR)(p_base) + (p_name - (char*)pwsi->pe);
+     p_to->p_aliases = (SEGPTR)((p_base) + (p_aliases - (char*)pwsi->pe)); 
 
      size += (sizeof(struct ws_protoent) - sizeof(struct protoent));
    }
@@ -2539,9 +2567,9 @@
      struct ws_servent* p_to;
      char* p_name,*p_aliases,*p_proto,*p_base,*p;
 
-     _check_buffer(pwsi, size);
-     p_to = (struct ws_servent*)pwsi->buffer;
-     p = pwsi->buffer;
+     _check_buffer_se(pwsi, size);
+     p_to = (struct ws_servent*)pwsi->se;
+     p = (char*)pwsi->se;
      p_base = (flag & WS_DUP_OFFSET) ? NULL 
 				     : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p);
      p += sizeof(struct ws_servent);
@@ -2550,12 +2578,12 @@
      p_proto = p;
      strcpy(p, p_se->s_proto); p += strlen(p) + 1;
      p_aliases = p;
-     list_dup(p_se->s_aliases, p, p_base + (p - pwsi->buffer), 0);
+     list_dup(p_se->s_aliases, p, p_base + (p - (char*)pwsi->se), 0);
 
      p_to->s_port = (INT16)p_se->s_port;
-     p_to->s_name = (SEGPTR)(p_base + (p_name - pwsi->buffer));
-     p_to->s_proto = (SEGPTR)(p_base + (p_proto - pwsi->buffer));
-     p_to->s_aliases = (SEGPTR)(p_base + (p_aliases - pwsi->buffer)); 
+     p_to->s_name = (SEGPTR)(p_base + (p_name - (char*)pwsi->se));
+     p_to->s_proto = (SEGPTR)(p_base + (p_proto - (char*)pwsi->se));
+     p_to->s_aliases = (SEGPTR)(p_base + (p_aliases - (char*)pwsi->se)); 
 
      size += (sizeof(struct ws_servent) - sizeof(struct servent));
    }
diff --git a/misc/winsock_dns.c b/misc/winsock_dns.c
index cf84172..113c50e 100644
--- a/misc/winsock_dns.c
+++ b/misc/winsock_dns.c
@@ -470,7 +470,7 @@
 		     ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
   if( size )
   {
-      async_ctl.buffer = pwsi->buffer;
+      async_ctl.buffer = (char*)pwsi->he;
       async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
      _async_notify( flag );
   }
@@ -494,7 +494,7 @@
 		     ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
   if( size )
   {
-      async_ctl.buffer = pwsi->buffer;
+      async_ctl.buffer = (char*)pwsi->pe;
       async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
      _async_notify( flag );
   } 
@@ -516,7 +516,7 @@
 		      ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
   if( size )
   {
-      async_ctl.buffer = pwsi->buffer;
+      async_ctl.buffer = (char*)pwsi->se;
       async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
      _async_notify( flag );
   }
@@ -569,4 +569,3 @@
    ((p_wsse->s_aliases)) += (unsigned)base;
    for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base;
 }
-
diff --git a/miscemu/main.c b/miscemu/main.c
index 4eac2c4..7230d05 100644
--- a/miscemu/main.c
+++ b/miscemu/main.c
@@ -84,7 +84,6 @@
 
     /* Initialize CALL32 routines */
     /* This needs to be done just before task-switching starts */
-    IF1632_CallLargeStack = (int (*)(int (*func)(), void *arg))CALL32_Init();
 
     loaded=0;
     for (i = 1; i < argc; i++)
@@ -117,6 +116,7 @@
 
     if (Options.debug) DEBUG_AddModuleBreakpoints();
 
+    IF1632_CallLargeStack = (int (*)(int (*func)(), void *arg))CALL32_Init();
     Yield16();  /* Start the first task */
     MSG("WinMain: Should never happen: returned from Yield16()\n" );
     return 0;
diff --git a/msdos/dosmem.c b/msdos/dosmem.c
index 0226450..d0bfddd 100644
--- a/msdos/dosmem.c
+++ b/msdos/dosmem.c
@@ -14,6 +14,8 @@
 #include "ldt.h"
 #include "miscemu.h"
 #include "module.h"
+#include "task.h"
+#include "dosexe.h"
 #include "debug.h"
 
 HANDLE16 DOSMEM_BiosSeg;  /* BIOS data segment at 0x40:0 */
@@ -75,7 +77,6 @@
 
 static BIOSDATA *pBiosData = NULL;
 static char	*DOSMEM_dosmem;
-static char	*DOSMEM_top;
 
        DWORD 	 DOSMEM_CollateTable;
 
@@ -107,6 +108,32 @@
 	 sizeof(dosmem_entry) + ((block)->size & DM_BLOCK_MASK))
 
 /***********************************************************************
+ *           DOSMEM_MemoryBase
+ *
+ * Gets the DOS memory base.
+ */
+static char *DOSMEM_MemoryBase(HMODULE16 hModule)
+{
+    TDB *pTask = hModule ? NULL : (TDB *)GlobalLock16( GetCurrentTask() );
+    NE_MODULE *pModule = (hModule || pTask) ? NE_GetPtr( hModule ? hModule : pTask->hModule ) : NULL;
+
+    if (pModule && pModule->lpDosTask)
+        return pModule->lpDosTask->img;
+    else
+        return DOSMEM_dosmem;
+}
+                                                            
+/***********************************************************************
+ *           DOSMEM_MemoryTop
+ *
+ * Gets the DOS memory top.
+ */
+static char *DOSMEM_MemoryTop(HMODULE16 hModule)
+{
+    return DOSMEM_MemoryBase(hModule)+0x9FFFC; /* 640K */
+}
+                                                            
+/***********************************************************************
  *           DOSMEM_FillBiosSegment
  *
  * Fill the BIOS data segment with dummy values.
@@ -163,21 +190,22 @@
  *
  * Initialises the DOS memory structures.
  */
-static void DOSMEM_InitMemory()
+static void DOSMEM_InitMemory(HMODULE16 hModule)
 {
    /* Low 64Kb are reserved for DOS/BIOS so the useable area starts at
     * 1000:0000 and ends at 9FFF:FFEF. */
 
+    char*               dosmem = DOSMEM_MemoryBase(hModule);
     dosmem_entry*       dm;
 
-    DOSMEM_top = DOSMEM_dosmem+0x9FFFC; /* 640K */
-    info_block = (dosmem_info*)( DOSMEM_dosmem + 0x10000 );
+    /* FIXME: these static variables can't cope with several DOS heaps */
+    info_block = (dosmem_info*)( dosmem + 0x10000 );
 
     /* first block has to be paragraph-aligned relative to the DOSMEM_dosmem */
 
-    root_block = (dosmem_entry*)( DOSMEM_dosmem + 0x10000 +
+    root_block = (dosmem_entry*)( dosmem + 0x10000 +
                  ((((sizeof(dosmem_info) + 0xf) & ~0xf) - sizeof(dosmem_entry))));
-    root_block->size = DOSMEM_top - (((char*)root_block) + sizeof(dosmem_entry));
+    root_block->size = DOSMEM_MemoryTop(hModule) - (((char*)root_block) + sizeof(dosmem_entry));
 
     info_block->blocks = 0;
     info_block->free = root_block->size;
@@ -197,24 +225,29 @@
  * Create the dos memory segments, and store them into the KERNEL
  * exported values.
  */
-BOOL32 DOSMEM_Init(void)
+BOOL32 DOSMEM_Init(HMODULE16 hModule)
 {
-    /* Allocate 1 MB dosmemory 
-     * - it is mostly wasted but we use can some of it to 
-     *   store internal translation tables, etc...
-     */
-    DOSMEM_dosmem = VirtualAlloc( NULL, 0x100000, MEM_COMMIT,
-                                  PAGE_EXECUTE_READWRITE );
-    if (!DOSMEM_dosmem)
+    if (!hModule)
     {
-        WARN(dosmem, "Could not allocate DOS memory.\n" );
-        return FALSE;
-    }
-    DOSMEM_BiosSeg = GLOBAL_CreateBlock(GMEM_FIXED,DOSMEM_dosmem+0x400,0x100,
+        /* Allocate 1 MB dosmemory 
+         * - it is mostly wasted but we use can some of it to 
+         *   store internal translation tables, etc...
+         */
+        DOSMEM_dosmem = VirtualAlloc( NULL, 0x100000, MEM_COMMIT,
+                                      PAGE_EXECUTE_READWRITE );
+        if (!DOSMEM_dosmem)
+        {
+            WARN(dosmem, "Could not allocate DOS memory.\n" );
+            return FALSE;
+        }
+        DOSMEM_BiosSeg = GLOBAL_CreateBlock(GMEM_FIXED,DOSMEM_dosmem+0x400,0x100,
                                         0, FALSE, FALSE, FALSE, NULL );
-    DOSMEM_FillBiosSegment();
-    DOSMEM_InitMemory();
-    DOSMEM_InitCollateTable();
+        DOSMEM_FillBiosSegment();
+        DOSMEM_InitMemory(0);
+        DOSMEM_InitCollateTable();
+    }
+    else
+        DOSMEM_InitMemory(hModule);
     return TRUE;
 }
 
@@ -234,7 +267,7 @@
  *
  * Carve a chunk of the DOS memory block (without selector).
  */
-LPVOID DOSMEM_GetBlock(UINT32 size, UINT16* pseg)
+LPVOID DOSMEM_GetBlock(HMODULE16 hModule, UINT32 size, UINT16* pseg)
 {
    UINT32  	 blocksize;
    char         *block = NULL;
@@ -290,7 +323,7 @@
 
 	       info_block->blocks++;
 	       info_block->free -= dm->size;
-	       if( pseg ) *pseg = (block - DOSMEM_dosmem) >> 4;
+	       if( pseg ) *pseg = (block - DOSMEM_MemoryBase(hModule)) >> 4;
 #ifdef __DOSMEM_DEBUG__
                dm->size |= DM_BLOCK_DEBUG;
 #endif
@@ -306,10 +339,11 @@
 /***********************************************************************
  *           DOSMEM_FreeBlock
  */
-BOOL32 DOSMEM_FreeBlock(void* ptr)
+BOOL32 DOSMEM_FreeBlock(HMODULE16 hModule, void* ptr)
 {
    if( ptr >= (void*)(((char*)root_block) + sizeof(dosmem_entry)) &&
-       ptr < (void*)DOSMEM_top && !((((char*)ptr) - DOSMEM_dosmem) & 0xf) )
+       ptr < (void*)DOSMEM_MemoryTop(hModule) && !((((char*)ptr)
+                  - DOSMEM_MemoryBase(hModule)) & 0xf) )
    {
        dosmem_entry  *dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
 
@@ -329,6 +363,109 @@
    return FALSE;
 }
 
+/***********************************************************************
+ *           DOSMEM_ResizeBlock
+ */
+LPVOID DOSMEM_ResizeBlock(HMODULE16 hModule, void* ptr, UINT32 size, UINT16* pseg)
+{
+   char         *block = NULL;
+
+   if( ptr >= (void*)(((char*)root_block) + sizeof(dosmem_entry)) &&
+       ptr < (void*)DOSMEM_MemoryTop(hModule) && !((((char*)ptr)
+                  - DOSMEM_MemoryBase(hModule)) & 0xf) )
+   {
+       dosmem_entry  *dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
+
+       if( pseg ) *pseg = ((char*)ptr - DOSMEM_MemoryBase(hModule)) >> 4;
+
+       if( !(dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL))
+	 )
+       {
+	     dosmem_entry  *next = NEXT_BLOCK(dm);
+	     UINT32 blocksize, orgsize = dm->size & DM_BLOCK_MASK;
+
+	     while( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
+	     {
+	         dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
+	         next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
+	         next = NEXT_BLOCK(dm);
+	     }
+
+	     blocksize = dm->size & DM_BLOCK_MASK;
+	     if (blocksize >= size)
+	     {
+	         block = ((char*)dm) + sizeof(dosmem_entry);
+	         if( blocksize - size > 0x20 )
+	         {
+		     /* split dm so that the next one stays
+		      * paragraph-aligned (and next gains free bit) */
+
+	             dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
+			         	        sizeof(dosmem_entry));
+	             next = (dosmem_entry*)(((char*)dm) + 
+	 		     sizeof(dosmem_entry) + dm->size);
+	             next->size = (blocksize - (dm->size + 
+			     sizeof(dosmem_entry))) | DM_BLOCK_FREE 
+						    ;
+	         } else dm->size &= DM_BLOCK_MASK;
+
+		 info_block->free += orgsize - dm->size;
+	     } else {
+		 block = DOSMEM_GetBlock(hModule, size, pseg);
+		 if (block) {
+		     info_block->blocks--;
+		     info_block->free += dm->size;
+
+		     dm->size |= DM_BLOCK_FREE;
+		 }
+	     }
+       }
+   }
+   return (LPVOID)block;
+}
+
+
+/***********************************************************************
+ *           DOSMEM_Available
+ */
+UINT32 DOSMEM_Available(HMODULE16 hModule)
+{
+   UINT32  	 blocksize, available = 0;
+   char         *block = NULL;
+   dosmem_entry *dm;
+   
+   dm = root_block;
+
+   while (dm && dm->size != DM_BLOCK_TERMINAL)
+   {
+#ifdef __DOSMEM_DEBUG__
+       if( (dm->size & DM_BLOCK_DEBUG) != DM_BLOCK_DEBUG )
+       {
+	    WARN(dosmem,"MCB overrun! [prev = 0x%08x]\n", 4 + (UINT32)prev);
+	    return NULL;
+       }
+       prev = dm;
+#endif
+       if( dm->size & DM_BLOCK_FREE )
+       {
+	   dosmem_entry  *next = NEXT_BLOCK(dm);
+
+	   while( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
+	   {
+	       dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
+	       next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
+	       next = NEXT_BLOCK(dm);
+	   }
+
+	   blocksize = dm->size & DM_BLOCK_MASK;
+	   if ( blocksize > available ) available = blocksize;
+ 	   dm = next;
+       }
+       else dm = NEXT_BLOCK(dm);
+   }
+   return available;
+}
+
 
 /***********************************************************************
  *           DOSMEM_MapLinearToDos
@@ -337,9 +474,9 @@
  */
 UINT32 DOSMEM_MapLinearToDos(LPVOID ptr)
 {
-    if (((char*)ptr >= DOSMEM_dosmem) &&
-        ((char*)ptr < DOSMEM_dosmem + 0x100000))
-	  return (UINT32)ptr - (UINT32)DOSMEM_dosmem;
+    if (((char*)ptr >= DOSMEM_MemoryBase(0)) &&
+        ((char*)ptr < DOSMEM_MemoryBase(0) + 0x100000))
+	  return (UINT32)ptr - (UINT32)DOSMEM_MemoryBase(0);
     return (UINT32)ptr;
 }
 
@@ -351,7 +488,7 @@
  */
 LPVOID DOSMEM_MapDosToLinear(UINT32 ptr)
 {
-    if (ptr < 0x100000) return (LPVOID)(ptr + (UINT32)DOSMEM_dosmem);
+    if (ptr < 0x100000) return (LPVOID)(ptr + (UINT32)DOSMEM_MemoryBase(0));
     return (LPVOID)ptr;
 }
 
@@ -365,7 +502,7 @@
 {
    LPVOID       lin;
 
-   lin=DOSMEM_dosmem+(x&0xffff)+(((x&0xffff0000)>>16)*16);
+   lin=DOSMEM_MemoryBase(0)+(x&0xffff)+(((x&0xffff0000)>>16)*16);
    TRACE(selector,"(0x%08lx) returns 0x%p.\n",
                     x,lin );
    return lin;
diff --git a/msdos/dpmi.c b/msdos/dpmi.c
index ee20a38..ebcfca1 100644
--- a/msdos/dpmi.c
+++ b/msdos/dpmi.c
@@ -126,7 +126,7 @@
 		 */
 		if (newsize<=mbi.RegionSize)
 			return ptr;
-		memcpy(newptr,ptr,newsize);
+		memcpy(newptr,ptr,mbi.RegionSize);
 		DPMI_xfree(ptr);
 	}
 	return newptr;
@@ -417,7 +417,7 @@
 
     if (NewRMCB)
     {
-	LPVOID RMCBmem = DOSMEM_GetBlock(20, &uParagraph);
+	LPVOID RMCBmem = DOSMEM_GetBlock(0, 20, &uParagraph);
 	LPBYTE p = RMCBmem;
 
 	*p++ = 0x68; /* pushl */
@@ -467,7 +467,7 @@
 	PrevRMCB->next = CurrRMCB->next;
 	    else
 	FirstRMCB = CurrRMCB->next;
-	DOSMEM_FreeBlock(DOSMEM_MapRealToLinear(CurrRMCB->address));
+	DOSMEM_FreeBlock(0, DOSMEM_MapRealToLinear(CurrRMCB->address));
 	HeapFree(GetProcessHeap(), 0, CurrRMCB);
     }
     else
diff --git a/msdos/int21.c b/msdos/int21.c
index b39592f..6bb650e 100644
--- a/msdos/int21.c
+++ b/msdos/int21.c
@@ -32,6 +32,14 @@
 #endif
 
 
+#define DOS_TO_HANDLE(handle) (((handle)==0) ? GetStdHandle(STD_INPUT_HANDLE) : \
+			      ((handle)==1) ? GetStdHandle(STD_OUTPUT_HANDLE) : \
+			      ((handle)==2) ? GetStdHandle(STD_ERROR_HANDLE) : \
+			       (handle)-5)
+#define HANDLE_TO_DOS(handle) ({ WORD hnd=handle; \
+			      ((hnd==HFILE_ERROR16) ? HFILE_ERROR16 : \
+			        hnd+5); })
+
 #define DOS_GET_DRIVE(reg) ((reg) ? (reg) - 1 : DRIVE_GetCurrentDrive())
 
 /* Define the drive parameter block, as used by int21/1F
@@ -92,10 +100,13 @@
     return TRUE;
 }
 
-static BYTE *GetCurrentDTA(void)
+static BYTE *GetCurrentDTA( CONTEXT *context )
 {
     TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
-    return (BYTE *)PTR_SEG_TO_LIN( pTask->dta );
+
+    /* FIXME: This assumes DTA was set correctly! */
+    return (BYTE *)CTX_SEG_OFF_TO_LIN( context, SELECTOROF(pTask->dta), 
+                                                OFFSETOF(pTask->dta) );
 }
 
 
@@ -209,7 +220,7 @@
 
 static void ioctlGetDeviceInfo( CONTEXT *context )
 {
-    int curr_drive, i;
+    int curr_drive;
     FILE_OBJECT *file;
 
     TRACE(int21, "(%d)\n", BX_reg(context));
@@ -217,7 +228,7 @@
     RESET_CFLAG(context);
 
     /* DOS device ? */
-    if ((file = FILE_GetFile( BX_reg(context) )))
+    if ((file = FILE_GetFile( DOS_TO_HANDLE(BX_reg(context)) )))
     {
         const DOS_DEVICE *dev = DOSFS_GetDevice( file->unix_name );
         FILE_ReleaseFile( file );
@@ -243,7 +254,7 @@
 
 static BOOL32 ioctlGenericBlkDevReq( CONTEXT *context )
 {
-	BYTE *dataptr = PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+	BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, DS_reg(context), DX_reg(context));
 	int drive = DOS_GET_DRIVE( BL_reg(context) );
 
 	if (!DRIVE_IsValid(drive))
@@ -353,16 +364,16 @@
 }
 static BOOL32 INT21_CreateFile( CONTEXT *context )
 {
-    AX_reg(context) = _lcreat16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
-                                          DX_reg(context) ), CX_reg(context) );
+    AX_reg(context) = HANDLE_TO_DOS(_lcreat16( CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
+                                          DX_reg(context) ), CX_reg(context) ));
     return (AX_reg(context) == (WORD)HFILE_ERROR16);
 }
 
 
 static void OpenExistingFile( CONTEXT *context )
 {
-    AX_reg(context) = _lopen16( PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)),
-                              AL_reg(context) );
+    AX_reg(context) = HANDLE_TO_DOS(_lopen16( CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context)),
+                              AL_reg(context) ));
     if (AX_reg(context) == (WORD)HFILE_ERROR16)
     {
         AX_reg(context) = DOS_ExtendedError;
@@ -383,7 +394,7 @@
 
 	  case 0x30:    /* DENYREAD */
 	    TRACE(int21, "(%s): DENYREAD changed to DENYALL\n",
-			 (char *)PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)));
+			 (char *)CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context)));
 	  case 0x10:    /* DENYALL */  
 	    lock = LOCK_EX;
 	    break;
@@ -431,7 +442,7 @@
         }
 
 	Error (0,0,0);
-	AX_reg(context) = handle;
+	AX_reg(context) = HANDLE_TO_DOS(handle);
 	RESET_CFLAG(context);
     }
 #endif
@@ -439,7 +450,7 @@
 
 static void CloseFile( CONTEXT *context )
 {
-    if ((AX_reg(context) = _lclose16( BX_reg(context) )) != 0)
+    if ((AX_reg(context) = _lclose16( DOS_TO_HANDLE(BX_reg(context)) )) != 0)
     {
         AX_reg(context) = DOS_ExtendedError;
         SET_CFLAG(context);
@@ -550,7 +561,7 @@
 static BOOL32 INT21_ChangeDir( CONTEXT *context )
 {
     int drive;
-    char *dirname = PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context));
+    char *dirname = CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context));
 
     TRACE(int21,"changedir %s\n", dirname);
     if (dirname[0] && (dirname[1] == ':'))
@@ -568,9 +579,9 @@
     char *p;
     const char *path;
     DOS_FULL_NAME full_name;
-    FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA();
+    FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
 
-    path = (const char *)PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+    path = (const char *)CTX_SEG_OFF_TO_LIN(context, DS_reg(context), DX_reg(context));
     dta->unixPath = NULL;
     if (!DOSFS_GetFullName( path, FALSE, &full_name ))
     {
@@ -604,7 +615,7 @@
 
 static int INT21_FindNext( CONTEXT *context )
 {
-    FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA();
+    FINDFILE_DTA *dta = (FINDFILE_DTA *)GetCurrentDTA(context);
     WIN32_FIND_DATA32A entry;
     int count;
 
@@ -629,6 +640,13 @@
     FileTimeToDosDateTime( &entry.ftLastWriteTime,
                            &dta->filedate, &dta->filetime );
     strcpy( dta->filename, entry.cAlternateFileName );
+    if (!memchr(dta->mask,'?',11)) {
+	/* wildcardless search, release resources in case no findnext will
+	 * be issued, and as a workaround in case file creation messes up
+	 * findnext, as sometimes happens with pkunzip */
+        HeapFree( GetProcessHeap(), 0, dta->unixPath );
+        dta->unixPath = NULL;
+    }
     return 1;
 }
 
@@ -636,7 +654,7 @@
 static BOOL32 INT21_CreateTempFile( CONTEXT *context )
 {
     static int counter = 0;
-    char *name = PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context) );
+    char *name = CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context) );
     char *p = name + strlen(name);
 
     /* despite what Ralf Brown says, some programs seem to call without 
@@ -648,7 +666,7 @@
         sprintf( p, "wine%04x.%03d", (int)getpid(), counter );
         counter = (counter + 1) % 1000;
 
-        if ((AX_reg(context) = _lcreat_uniq( name, 0 )) != (WORD)HFILE_ERROR16)
+        if ((AX_reg(context) = HANDLE_TO_DOS(_lcreat_uniq( name, 0 ))) != (WORD)HFILE_ERROR16)
         {
             TRACE(int21, "created %s\n", name );
             return TRUE;
@@ -661,7 +679,7 @@
 static BOOL32 INT21_GetCurrentDirectory( CONTEXT *context ) 
 {
     int drive = DOS_GET_DRIVE( DL_reg(context) );
-    char *ptr = (char *)PTR_SEG_OFF_TO_LIN( DS_reg(context), SI_reg(context) );
+    char *ptr = (char *)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), SI_reg(context) );
 
     if (!DRIVE_IsValid(drive))
     {
@@ -676,7 +694,7 @@
 
 static int INT21_GetDiskSerialNumber( CONTEXT *context )
 {
-    BYTE *dataptr = PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+    BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, DS_reg(context), DX_reg(context));
     int drive = DOS_GET_DRIVE( BL_reg(context) );
 	
     if (!DRIVE_IsValid(drive))
@@ -695,7 +713,7 @@
 
 static int INT21_SetDiskSerialNumber( CONTEXT *context )
 {
-    BYTE *dataptr = PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+    BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, DS_reg(context), DX_reg(context));
     int drive = DOS_GET_DRIVE( BL_reg(context) );
 
     if (!DRIVE_IsValid(drive))
@@ -714,7 +732,7 @@
 
 static int INT21_FindFirstFCB( CONTEXT *context )
 {
-    BYTE *fcb = (BYTE *)PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+    BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, DS_reg(context), DX_reg(context));
     FINDFILE_FCB *pFCB;
     LPCSTR root, cwd;
     int drive;
@@ -737,9 +755,9 @@
 
 static int INT21_FindNextFCB( CONTEXT *context )
 {
-    BYTE *fcb = (BYTE *)PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context));
+    BYTE *fcb = (BYTE *)CTX_SEG_OFF_TO_LIN(context, DS_reg(context), DX_reg(context));
     FINDFILE_FCB *pFCB;
-    DOS_DIRENTRY_LAYOUT *pResult = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA();
+    DOS_DIRENTRY_LAYOUT *pResult = (DOS_DIRENTRY_LAYOUT *)GetCurrentDTA(context);
     WIN32_FIND_DATA32A entry;
     BYTE attr;
     int count;
@@ -826,7 +844,7 @@
 		BX_reg(context),
 		MAKELONG(DX_reg(context),CX_reg(context)),
 		MAKELONG(DI_reg(context),SI_reg(context))) ;
-	  if (!LockFile(BX_reg(context),
+	  if (!LockFile(DOS_TO_HANDLE(BX_reg(context)),
                         MAKELONG(DX_reg(context),CX_reg(context)), 0,
                         MAKELONG(DI_reg(context),SI_reg(context)), 0)) {
 	    AX_reg(context) = DOS_ExtendedError;
@@ -839,7 +857,7 @@
 		BX_reg(context),
 		MAKELONG(DX_reg(context),CX_reg(context)),
 		MAKELONG(DI_reg(context),SI_reg(context))) ;
-	  if (!UnlockFile(BX_reg(context),
+	  if (!UnlockFile(DOS_TO_HANDLE(BX_reg(context)),
                           MAKELONG(DX_reg(context),CX_reg(context)), 0,
                           MAKELONG(DI_reg(context),SI_reg(context)), 0)) {
 	    AX_reg(context) = DOS_ExtendedError;
@@ -859,7 +877,7 @@
      switch (AL_reg(context)) {
      case 0x00: /* Get machine name. */
      {
-	  char *dst = PTR_SEG_OFF_TO_LIN (DS_reg(context),DX_reg(context));
+	  char *dst = CTX_SEG_OFF_TO_LIN (context,DS_reg(context),DX_reg(context));
 	  TRACE(int21, "getting machine name to %p\n", dst);
 	  if (gethostname (dst, 15))
 	  {
@@ -969,6 +987,13 @@
         return;
     }
 
+    if (AH_reg(context) == 0x0C)  /* Flush buffer and read standard input */
+    {
+	TRACE(int21, "FLUSH BUFFER AND READ STANDARD INPUT\n");
+	/* no flush here yet */
+	AH_reg(context) = AL_reg(context);
+    }
+
     DOS_ERROR( 0, 0, 0, 0 );
     RESET_CFLAG(context);  /* Not sure if this is a good idea */
 
@@ -985,12 +1010,8 @@
     case 0x04: /* WRITE CHARACTER TO STDAUX */
     case 0x05: /* WRITE CHARACTER TO PRINTER */
     case 0x06: /* DIRECT CONSOLE IN/OUTPUT */
-    case 0x07: /* DIRECT CHARACTER INPUT, WITHOUT ECHO */
-    case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
-    case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
     case 0x0a: /* BUFFERED INPUT */
     case 0x0b: /* GET STDIN STATUS */
-    case 0x0c: /* FLUSH BUFFER AND READ STANDARD INPUT */
     case 0x0f: /* OPEN FILE USING FCB */
     case 0x10: /* CLOSE FILE USING FCB */
     case 0x14: /* SEQUENTIAL READ FROM FCB FILE */		
@@ -1008,11 +1029,29 @@
                   "SWITCHAR" - SET SWITCH CHARACTER
                   "AVAILDEV" - SPECIFY \DEV\ PREFIX USE */
     case 0x54: /* GET VERIFY FLAG */
-    case 0x48: /* ALLOCATE MEMORY */
-    case 0x49: /* FREE MEMORY */
-    case 0x4a: /* RESIZE MEMORY BLOCK */
         INT_BARF( context, 0x21 );
         break;
+
+    case 0x07: /* DIRECT CHARACTER INPUT WITHOUT ECHO */
+        TRACE(int21,"DIRECT CHARACTER INPUT WITHOUT ECHO\n");
+	_lread16( DOS_TO_HANDLE(0), &AL_reg(context), 1);
+        break;
+
+    case 0x08: /* CHARACTER INPUT WITHOUT ECHO */
+        TRACE(int21,"CHARACTER INPUT WITHOUT ECHO\n");
+	_lread16( DOS_TO_HANDLE(0), &AL_reg(context), 1);
+        break;
+
+    case 0x09: /* WRITE STRING TO STANDARD OUTPUT */
+        TRACE(int21,"WRITE '$'-terminated string from %04lX:%04X to stdout\n",
+	      DS_reg(context),DX_reg(context) );
+        {
+            LPSTR data = CTX_SEG_OFF_TO_LIN(context,DS_reg(context),DX_reg(context));
+            LONG length = strchr(data,'$')-data;
+            _hwrite16( DOS_TO_HANDLE(1), data, length);
+        }
+        break;
+
     case 0x2e: /* SET VERIFY FLAG */
         TRACE(int21,"SET VERIFY FLAG ignored\n");
     	/* we cannot change the behaviour anyway, so just ignore it */
@@ -1043,7 +1082,7 @@
 
     case 0x11: /* FIND FIRST MATCHING FILE USING FCB */
 	TRACE(int21,"FIND FIRST MATCHING FILE USING FCB %p\n", 
-	      PTR_SEG_OFF_TO_LIN(DS_reg(context), DX_reg(context)));
+	      CTX_SEG_OFF_TO_LIN(context, DS_reg(context), DX_reg(context)));
         if (!INT21_FindFirstFCB(context))
         {
             AL_reg(context) = 0xff;
@@ -1211,63 +1250,67 @@
 
     case 0x39: /* "MKDIR" - CREATE SUBDIRECTORY */
         TRACE(int21,"MKDIR %s\n",
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
-        bSetDOSExtendedError = (!CreateDirectory16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
+        bSetDOSExtendedError = (!CreateDirectory16( CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
                                                            DX_reg(context) ), NULL));
         break;
 	
     case 0x3a: /* "RMDIR" - REMOVE SUBDIRECTORY */
         TRACE(int21,"RMDIR %s\n",
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
-        bSetDOSExtendedError = (!RemoveDirectory16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
+        bSetDOSExtendedError = (!RemoveDirectory16( CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
                                                                  DX_reg(context) )));
         break;
 
     case 0x3b: /* "CHDIR" - SET CURRENT DIRECTORY */
         TRACE(int21,"CHDIR %s\n",
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
         bSetDOSExtendedError = !INT21_ChangeDir(context);
         break;
 	
     case 0x3c: /* "CREAT" - CREATE OR TRUNCATE FILE */
         TRACE(int21,"CREAT flag 0x%02x %s\n",CX_reg(context),
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
-        AX_reg(context) = _lcreat16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
-                                    DX_reg(context) ), CX_reg(context) );
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
+        AX_reg(context) = HANDLE_TO_DOS(_lcreat16( CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
+                                    DX_reg(context) ), CX_reg(context) ));
         bSetDOSExtendedError = (AX_reg(context) == (WORD)HFILE_ERROR16);
         break;
 
     case 0x3d: /* "OPEN" - OPEN EXISTING FILE */
         TRACE(int21,"OPEN mode 0x%02x %s\n",AL_reg(context),
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
         OpenExistingFile(context);
         break;
 
     case 0x3e: /* "CLOSE" - CLOSE FILE */
         TRACE(int21,"CLOSE handle %d\n",BX_reg(context));
-        bSetDOSExtendedError = ((AX_reg(context) = _lclose16( BX_reg(context) )) != 0);
+	if (BX_reg(context)<5) {
+	    /* hack to make sure stdio isn't closed */
+	    DOS_ExtendedError = 0x06;
+	    bSetDOSExtendedError = TRUE;
+	} else
+        bSetDOSExtendedError = ((AX_reg(context) = _lclose16( DOS_TO_HANDLE(BX_reg(context)) )) != 0);
         break;
 
     case 0x3f: /* "READ" - READ FROM FILE OR DEVICE */
-        TRACE(int21,"READ from %d to %ld for %d byte\n",BX_reg(context),
-	      PTR_SEG_OFF_TO_SEGPTR( DS_reg(context),DX_reg(context)),CX_reg(context) );
+        TRACE(int21,"READ from %d to %04lX:%04X for %d byte\n",BX_reg(context),
+	      DS_reg(context),DX_reg(context),CX_reg(context) );
         {
-            LONG result = WIN16_hread( BX_reg(context),
-                                       PTR_SEG_OFF_TO_SEGPTR( DS_reg(context),
-                                                              DX_reg(context) ),
-                                       CX_reg(context) );
+            LONG result = _hread16( DOS_TO_HANDLE(BX_reg(context)),
+                                    CTX_SEG_OFF_TO_LIN(context, DS_reg(context),
+                                                                DX_reg(context) ),
+                                    CX_reg(context) );
             if (result == -1) bSetDOSExtendedError = TRUE;
             else AX_reg(context) = (WORD)result;
         }
         break;
 
     case 0x40: /* "WRITE" - WRITE TO FILE OR DEVICE */
-        TRACE(int21,"WRITE from %ld to handle %d for %d byte\n",
-	      PTR_SEG_OFF_TO_SEGPTR( DS_reg(context),DX_reg(context)),
-	      BX_reg(context),CX_reg(context) );
+        TRACE(int21,"WRITE from %04lX:%04X to handle %d for %d byte\n",
+	      DS_reg(context),DX_reg(context),BX_reg(context),CX_reg(context) );
         {
-            LONG result = _hwrite16( BX_reg(context),
-                                     PTR_SEG_OFF_TO_LIN( DS_reg(context),
+            LONG result = _hwrite16( DOS_TO_HANDLE(BX_reg(context)),
+                                     CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
                                                          DX_reg(context) ),
                                      CX_reg(context) );
             if (result == -1) bSetDOSExtendedError = TRUE;
@@ -1277,8 +1320,8 @@
 
     case 0x41: /* "UNLINK" - DELETE FILE */
         TRACE(int21,"UNLINK%s\n",
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
-        bSetDOSExtendedError = (!DeleteFile32A( PTR_SEG_OFF_TO_LIN( DS_reg(context),
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
+        bSetDOSExtendedError = (!DeleteFile32A( CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
                                                              DX_reg(context) )));
         break;
 
@@ -1288,7 +1331,7 @@
 	      (AL_reg(context)==0)?"start of file":(AL_reg(context)==1)?
 	      "current file position":"end of file");
         {
-            LONG status = _llseek16( BX_reg(context),
+            LONG status = _llseek16( DOS_TO_HANDLE(BX_reg(context)),
                                      MAKELONG(DX_reg(context),CX_reg(context)),
                                      AL_reg(context) );
             if (status == -1) bSetDOSExtendedError = TRUE;
@@ -1305,9 +1348,9 @@
         {
         case 0x00:
             TRACE(int21,"GET FILE ATTRIBUTES for %s\n", 
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
             AX_reg(context) = (WORD)GetFileAttributes32A(
-                                          PTR_SEG_OFF_TO_LIN(DS_reg(context),
+                                          CTX_SEG_OFF_TO_LIN(context, DS_reg(context),
                                                              DX_reg(context)));
             if (AX_reg(context) == 0xffff) bSetDOSExtendedError = TRUE;
             else CX_reg(context) = AX_reg(context);
@@ -1315,15 +1358,15 @@
 
         case 0x01:
             TRACE(int21,"SET FILE ATTRIBUTES 0x%02x for %s\n", CX_reg(context),
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
             bSetDOSExtendedError = 
-		(!SetFileAttributes32A( PTR_SEG_OFF_TO_LIN(DS_reg(context), 
+		(!SetFileAttributes32A( CTX_SEG_OFF_TO_LIN(context, DS_reg(context), 
 							   DX_reg(context)),
                                        			   CX_reg(context) ));
             break;
         case 0x02:
             TRACE(int21,"GET COMPRESSED FILE SIZE for %s stub\n",
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
         }
         break;
 	
@@ -1338,14 +1381,14 @@
             break;
         case 0x02:{
            FILE_OBJECT *file;
-           file = FILE_GetFile(BX_reg(context));
+           file = FILE_GetFile(DOS_TO_HANDLE(BX_reg(context)));
            if (!strcasecmp(file->unix_name, "SCSIMGR$"))
                         ASPI_DOS_HandleInt(context);
            FILE_ReleaseFile( file );
            break;
        }
 	case 0x05:{	/* IOCTL - WRITE TO BLOCK DEVICE CONTROL CHANNEL */
-	    /*BYTE *dataptr = PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context));*/
+	    /*BYTE *dataptr = CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context));*/
 	    int	drive = DOS_GET_DRIVE(BL_reg(context));
 
 	    FIXME(int21,"program tried to write to block device control channel of drive %d:\n",drive);
@@ -1450,13 +1493,13 @@
 
     case 0x45: /* "DUP" - DUPLICATE FILE HANDLE */
         TRACE(int21,"DUP - DUPLICATE FILE HANDLE %d\n",BX_reg(context));
-        bSetDOSExtendedError = ((AX_reg(context) = FILE_Dup(BX_reg(context))) == (WORD)HFILE_ERROR16);
+        bSetDOSExtendedError = ((AX_reg(context) = HANDLE_TO_DOS(FILE_Dup(DOS_TO_HANDLE(BX_reg(context))))) == (WORD)HFILE_ERROR16);
         break;
 
     case 0x46: /* "DUP2", "FORCEDUP" - FORCE DUPLICATE FILE HANDLE */
         TRACE(int21,"FORCEDUP - FORCE DUPLICATE FILE HANDLE %d to %d\n",
 	      BX_reg(context),CX_reg(context));
-        bSetDOSExtendedError = (FILE_Dup2( BX_reg(context), CX_reg(context) ) == HFILE_ERROR32);
+        bSetDOSExtendedError = (FILE_Dup2( DOS_TO_HANDLE(BX_reg(context)), DOS_TO_HANDLE(CX_reg(context)) ) == HFILE_ERROR32);
         break;
 
     case 0x47: /* "CWD" - GET CURRENT DIRECTORY */
@@ -1465,10 +1508,48 @@
         bSetDOSExtendedError = !INT21_GetCurrentDirectory(context);
         break;
 
+    case 0x48: /* ALLOCATE MEMORY */
+        TRACE(int21,"ALLOCATE MEMORY for %d paragraphs\n", BX_reg(context));
+        {
+            LPVOID *mem = DOSMEM_GetBlock(0,BX_reg(context)<<4,NULL);
+            if (mem)
+                AX_reg(context) = DOSMEM_MapLinearToDos(mem)>>4;
+            else {
+                SET_CFLAG(context);
+                AX_reg(context) = 0x0008; /* insufficient memory */
+                BX_reg(context) = DOSMEM_Available(0)>>4;
+            }
+        }
+        break;
+
+    case 0x49: /* FREE MEMORY */
+        TRACE(int21,"FREE MEMORY segment %04lX\n", ES_reg(context));
+        if (!DOSMEM_FreeBlock(0,DOSMEM_MapDosToLinear(ES_reg(context)<<4)))
+        {
+            SET_CFLAG(context);
+            AX_reg(context) = 0x0009; /* memory block address invalid */
+        }
+        break;
+
+    case 0x4a: /* RESIZE MEMORY BLOCK */
+        TRACE(int21,"RESIZE MEMORY segment %04lX to %d paragraphs\n", ES_reg(context), BX_reg(context));
+	{
+	    LPVOID *mem = DOSMEM_ResizeBlock(0,DOSMEM_MapDosToLinear(ES_reg(context)<<4),
+					       BX_reg(context)<<4,NULL);
+	    if (mem)
+		AX_reg(context) = DOSMEM_MapLinearToDos(mem)>>4;
+	    else {
+		SET_CFLAG(context);
+		AX_reg(context) = 0x0008; /* insufficient memory */
+		BX_reg(context) = DOSMEM_Available(0)>>4; /* not quite right */
+	    }
+	}
+        break;
+
     case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
         TRACE(int21,"EXEC %s\n",
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context),DX_reg(context) ));
-        AX_reg(context) = WinExec16( PTR_SEG_OFF_TO_LIN( DS_reg(context),
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),DX_reg(context) ));
+        AX_reg(context) = WinExec16( CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
                                                          DX_reg(context) ),
                                      SW_NORMAL );
         if (AX_reg(context) < 32) SET_CFLAG(context);
@@ -1486,7 +1567,7 @@
 
     case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
         TRACE(int21,"FINDFIRST mask 0x%04x spec %s\n",CX_reg(context),
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
         if (!INT21_FindFirst(context)) break;
         /* fall through */
 
@@ -1526,11 +1607,11 @@
 
     case 0x56: /* "RENAME" - RENAME FILE */
         TRACE(int21,"RENAME %s to %s\n",
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)),
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN(ES_reg(context),DI_reg(context)));
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context)),
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context, ES_reg(context),DI_reg(context)));
         bSetDOSExtendedError = 
-		(!MoveFile32A( PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)),
-			       PTR_SEG_OFF_TO_LIN(ES_reg(context),DI_reg(context))));
+		(!MoveFile32A( CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context)),
+			       CTX_SEG_OFF_TO_LIN(context, ES_reg(context),DI_reg(context))));
         break;
 
     case 0x57: /* FILE DATE AND TIME */
@@ -1587,9 +1668,9 @@
 
     case 0x5b: /* CREATE NEW FILE */
         TRACE(int21,"CREATE NEW FILE 0x%02x for %s\n", CX_reg(context),
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)));
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)));
         bSetDOSExtendedError = ((AX_reg(context) = 
-		_lcreat_uniq( PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)), 0 )) 
+		HANDLE_TO_DOS(_lcreat_uniq( CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context)), 0 ))) 
 								== (WORD)HFILE_ERROR16);
         break;
 
@@ -1636,11 +1717,11 @@
 
     case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */
         TRACE(int21,"TRUENAME %s\n",
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN(DS_reg(context),SI_reg(context)));
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context, DS_reg(context),SI_reg(context)));
         {
-            if (!GetFullPathName32A( PTR_SEG_OFF_TO_LIN(DS_reg(context),
+            if (!GetFullPathName32A( CTX_SEG_OFF_TO_LIN(context, DS_reg(context),
                                                         SI_reg(context)), 128,
-                                     PTR_SEG_OFF_TO_LIN(ES_reg(context),
+                                     CTX_SEG_OFF_TO_LIN(context, ES_reg(context),
                                                         DI_reg(context)),NULL))
 		bSetDOSExtendedError = TRUE;
             else AX_reg(context) = 0;
@@ -1656,7 +1737,7 @@
 
     case 0x65:{/* GET EXTENDED COUNTRY INFORMATION */
     	extern WORD WINE_LanguageId;
-	BYTE    *dataptr=PTR_SEG_OFF_TO_LIN(ES_reg(context),DI_reg(context));
+	BYTE    *dataptr=CTX_SEG_OFF_TO_LIN(context, ES_reg(context),DI_reg(context));
 	TRACE(int21,"GET EXTENDED COUNTRY INFORMATION code page %d country %d\n",
 	      BX_reg(context), DX_reg(context));
     	switch (AL_reg(context)) {
@@ -1708,7 +1789,7 @@
     case 0x68: /* "FFLUSH" - COMMIT FILE */
     case 0x6a: /* COMMIT FILE */
         TRACE(int21,"FFLUSH/COMMIT handle %d\n",BX_reg(context));
-        bSetDOSExtendedError = (!FlushFileBuffers( BX_reg(context) ));
+        bSetDOSExtendedError = (!FlushFileBuffers( DOS_TO_HANDLE(BX_reg(context)) ));
         break;		
 	
     case 0x69: /* DISK SERIAL NUMBER */
@@ -1732,43 +1813,49 @@
     
     case 0x6C: /* Extended Open/Create*/
         TRACE(int21,"EXTENDED OPEN/CREATE %s\n",
-	      (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DI_reg(context)));
+	      (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DI_reg(context)));
         bSetDOSExtendedError = INT21_ExtendedOpenCreateFile(context);
         break;
 	
     case 0x71: /* MS-DOS 7 (Windows95) - LONG FILENAME FUNCTIONS */
+	if ((GetVersion32()&0xC0000004)!=0xC0000004) {
+	    /* not supported on anything but Win95 */
+	    TRACE(int21,"LONG FILENAME functions supported only by win95\n");
+	    SET_CFLAG(context);
+	    AL_reg(context) = 0;
+	} else
         switch(AL_reg(context))
         {
         case 0x39:  /* Create directory */
 	    TRACE(int21,"LONG FILENAME - MAKE DIRECTORY %s\n",
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context),DX_reg(context)));
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),DX_reg(context)));
             bSetDOSExtendedError = (!CreateDirectory32A( 
-					PTR_SEG_OFF_TO_LIN( DS_reg(context),
+					CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
                                                   DX_reg(context) ), NULL));
             break;
         case 0x3a:  /* Remove directory */
 	    TRACE(int21,"LONG FILENAME - REMOVE DIRECTORY %s\n",
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context),DX_reg(context)));
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),DX_reg(context)));
             bSetDOSExtendedError = (!RemoveDirectory32A( 
-					PTR_SEG_OFF_TO_LIN( DS_reg(context),
+					CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),
                                                         DX_reg(context) )));
             break;
         case 0x43:  /* Get/Set file attributes */
 	  TRACE(int21,"LONG FILENAME -EXTENDED GET/SET FILE ATTRIBUTES %s\n",
-		(LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context),DX_reg(context)));
+		(LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),DX_reg(context)));
         switch (BL_reg(context))
         {
         case 0x00: /* Get file attributes */
             TRACE(int21,"\tretrieve attributes\n");
             CX_reg(context) = (WORD)GetFileAttributes32A(
-                                          PTR_SEG_OFF_TO_LIN(DS_reg(context),
+                                          CTX_SEG_OFF_TO_LIN(context, DS_reg(context),
                                                              DX_reg(context)));
             if (CX_reg(context) == 0xffff) bSetDOSExtendedError = TRUE;
             break;
         case 0x01:
             TRACE(int21,"\tset attributes 0x%04x\n",CX_reg(context));
             bSetDOSExtendedError = (!SetFileAttributes32A( 
-				  	PTR_SEG_OFF_TO_LIN(DS_reg(context),
+				  	CTX_SEG_OFF_TO_LIN(context, DS_reg(context),
                                                            DX_reg(context)),
                                         CX_reg(context)  ) );
             break;
@@ -1788,11 +1875,11 @@
 
         case 0x4e:  /* Find first file */
 	    TRACE(int21," LONG FILENAME - FIND FIRST MATCHING FILE for %s\n",
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)));
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context)));
             /* FIXME: use attributes in CX */
             if ((AX_reg(context) = FindFirstFile16(
-                   PTR_SEG_OFF_TO_LIN(DS_reg(context),DX_reg(context)),
-                   (WIN32_FIND_DATA32A *)PTR_SEG_OFF_TO_LIN(ES_reg(context),
+                   CTX_SEG_OFF_TO_LIN(context, DS_reg(context),DX_reg(context)),
+                   (WIN32_FIND_DATA32A *)CTX_SEG_OFF_TO_LIN(context, ES_reg(context),
                                                             DI_reg(context))))
 		== INVALID_HANDLE_VALUE16)
 		bSetDOSExtendedError = TRUE;
@@ -1801,7 +1888,7 @@
 	    TRACE(int21,"LONG FILENAME - FIND NEXT MATCHING FILE for handle %d\n",
 		  BX_reg(context));
             if (!FindNextFile16( BX_reg(context),
-                    (WIN32_FIND_DATA32A *)PTR_SEG_OFF_TO_LIN(ES_reg(context),
+                    (WIN32_FIND_DATA32A *)CTX_SEG_OFF_TO_LIN(context, ES_reg(context),
                                                              DI_reg(context))))
 		bSetDOSExtendedError = TRUE;
             break;
@@ -1812,16 +1899,25 @@
             break;
 	case 0xa0:
 	    TRACE(int21,"LONG FILENAME - GET VOLUME INFORMATION for drive %s stub\n",
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context),DX_reg(context)));
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context),DX_reg(context)));
 	    break;
         case 0x60:  
 	  switch(CL_reg(context))
 	  {
+	    case 0x01:  /*Get short filename or path */
+	      if (!GetShortPathName32A
+		  ( CTX_SEG_OFF_TO_LIN(context, DS_reg(context),
+				       SI_reg(context)),
+		    CTX_SEG_OFF_TO_LIN(context, ES_reg(context),
+				       DI_reg(context)), 67))
+		bSetDOSExtendedError = TRUE;
+	      else AX_reg(context) = 0;
+	      break;
 	    case 0x02:  /*Get canonical long filename or path */
 	      if (!GetFullPathName32A
-		  ( PTR_SEG_OFF_TO_LIN(DS_reg(context),
+		  ( CTX_SEG_OFF_TO_LIN(context, DS_reg(context),
 				       SI_reg(context)), 128,
-		    PTR_SEG_OFF_TO_LIN(ES_reg(context),
+		    CTX_SEG_OFF_TO_LIN(context, ES_reg(context),
 				       DI_reg(context)),NULL))
 		bSetDOSExtendedError = TRUE;
 	      else AX_reg(context) = 0;
@@ -1836,15 +1932,15 @@
 	    break;
         case 0x6c:  /* Create or open file */
             TRACE(int21,"LONG FILENAME - CREATE OR OPEN FILE %s\n",
-		 (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), SI_reg(context))); 
+		 (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), SI_reg(context))); 
 	  /* translate Dos 7 action to Dos 6 action */
 	    bSetDOSExtendedError = INT21_ExtendedOpenCreateFile(context);
 	    break;
 
         case 0x3b:  /* Change directory */
             TRACE(int21,"LONG FILENAME - CHANGE DIRECTORY %s\n",
-		 (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context))); 
-	    if (!SetCurrentDirectory32A(PTR_SEG_OFF_TO_LIN(
+		 (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context))); 
+	    if (!SetCurrentDirectory32A(CTX_SEG_OFF_TO_LIN(context, 
 	    					DS_reg(context),
 				        	DX_reg(context)
 					))
@@ -1855,8 +1951,8 @@
 	    break;
         case 0x41:  /* Delete file */
             TRACE(int21,"LONG FILENAME - DELETE FILE %s\n",
-		 (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context))); 
-	    if (!DeleteFile32A(PTR_SEG_OFF_TO_LIN(
+		 (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context))); 
+	    if (!DeleteFile32A(CTX_SEG_OFF_TO_LIN(context, 
 	    				DS_reg(context),
 					DX_reg(context))
 	    )) {
@@ -1866,8 +1962,8 @@
 	    break;
         case 0x56:  /* Move (rename) file */
             TRACE(int21,"LONG FILENAME - RENAME FILE %s to %s stub\n",
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN( DS_reg(context), DX_reg(context)),
-		  (LPCSTR)PTR_SEG_OFF_TO_LIN( ES_reg(context), DI_reg(context))); 
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  DS_reg(context), DX_reg(context)),
+		  (LPCSTR)CTX_SEG_OFF_TO_LIN(context,  ES_reg(context), DI_reg(context))); 
         default:
             FIXME(int21, "Unimplemented long file name function:\n");
             INT_BARF( context, 0x21 );
diff --git a/msdos/vxd.c b/msdos/vxd.c
index 186bdb3..3f08ac8 100644
--- a/msdos/vxd.c
+++ b/msdos/vxd.c
@@ -924,7 +924,7 @@
         TRACE(vxd, "NtDupSection(%lx)\n", (DWORD)handle);
  
         /* Handle is 'duplicated' by incrementing RefCount */
-        HANDLE_GetObjPtr(PROCESS_Current(), handle, K32OBJ_MEM_MAPPED_FILE, 0);
+        HANDLE_GetObjPtr(PROCESS_Current(), handle, K32OBJ_MEM_MAPPED_FILE, 0,NULL);
 
         EAX_reg(context) = STATUS_SUCCESS;
     }
diff --git a/multimedia/Makefile.in b/multimedia/Makefile.in
index 347b0d6..8762d25 100644
--- a/multimedia/Makefile.in
+++ b/multimedia/Makefile.in
@@ -19,6 +19,7 @@
 	mmaux.c \
 	mmio.c \
 	mmsystem.c \
+	msvideo.c \
 	time.c
 
 all: $(MODULE).o
diff --git a/multimedia/audio.c b/multimedia/audio.c
index 7ae0251..07cfc13 100644
--- a/multimedia/audio.c
+++ b/multimedia/audio.c
@@ -1195,7 +1195,7 @@
 /**************************************************************************
  * 				wodMessage			[sample driver]
  */
-DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
   int audio;
@@ -1660,7 +1660,7 @@
 /**************************************************************************
  * 				widMessage			[sample driver]
  */
-DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
   int audio;
@@ -1810,7 +1810,7 @@
 /**************************************************************************
  * 				wodMessage			[sample driver]
  */
-DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
 	FIXME(mciwave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
@@ -1821,7 +1821,7 @@
 /**************************************************************************
  * 				widMessage			[sample driver]
  */
-DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
 	FIXME(mciwave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
diff --git a/multimedia/init.c b/multimedia/init.c
index 63df1bf..7d138c8 100644
--- a/multimedia/init.c
+++ b/multimedia/init.c
@@ -81,6 +81,7 @@
   
   if (status == -1) {
     ERR (midi, "ioctl failed.\n");
+    close(fd);
     return TRUE;
   }
 
@@ -91,6 +92,7 @@
     status = ioctl(fd, SNDCTL_SYNTH_INFO, &sinfo);
     if (status == -1) {
       ERR(midi, "ioctl failed.\n");
+      close(fd);
       return TRUE;
     }
 
@@ -133,6 +135,7 @@
   status = ioctl(fd, SNDCTL_SEQ_NRMIDIS, &nummididevs);
   if (status == -1) {
     ERR(midi, "ioctl failed.\n");
+    close(fd);
     return TRUE;
   }
 
@@ -151,6 +154,7 @@
     status = ioctl(fd, SNDCTL_MIDI_INFO, &minfo);
     if (status == -1) {
       ERR(midi, "ioctl failed.\n");
+      close(fd);
       return TRUE;
     }
 
diff --git a/multimedia/midi.c b/multimedia/midi.c
index abcccb5..c7cae5a 100644
--- a/multimedia/midi.c
+++ b/multimedia/midi.c
@@ -894,7 +894,7 @@
 /**************************************************************************
  * 			midMessage				[sample driver]
  */
-DWORD midMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI midMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
 	TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n", 
@@ -1150,7 +1150,7 @@
 /**************************************************************************
  * 				modMessage			[sample driver]
  */
-DWORD modMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI modMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
 	TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n", 
diff --git a/multimedia/mixer.c b/multimedia/mixer.c
index 1c29e47..921d1f9 100644
--- a/multimedia/mixer.c
+++ b/multimedia/mixer.c
@@ -190,7 +190,7 @@
 /**************************************************************************
  * 				mixMessage			[sample driver]
  */
-DWORD mixMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI mixMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
 	TRACE(mmaux,"(%04X, %04X, %08lX, %08lX, %08lX);\n", 
diff --git a/multimedia/mmaux.c b/multimedia/mmaux.c
index 5bbbf81..4272db4 100644
--- a/multimedia/mmaux.c
+++ b/multimedia/mmaux.c
@@ -226,7 +226,7 @@
 /**************************************************************************
  * 				auxMessage			[sample driver]
  */
-DWORD auxMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+DWORD WINAPI auxMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
 					DWORD dwParam1, DWORD dwParam2)
 {
 	TRACE(mmaux,"(%04X, %04X, %08lX, %08lX, %08lX);\n", 
diff --git a/multimedia/mmio.c b/multimedia/mmio.c
index 5d88542..f6bdc77 100644
--- a/multimedia/mmio.c
+++ b/multimedia/mmio.c
@@ -2,9 +2,9 @@
  * MMIO functions
  *
  * Copyright 1998 Andrew Taylor
+ * Copyright 1998 Ove Kåven
  *
- * NOTES:  I/O is still unbuffered;  mmioSetBuffer must be implemented
- * and mmio{Read,Write,Seek,others?} need buffer support.
+ * Buffering is not guaranteed to work properly yet, but if it does...
  * Buffering should almost give us memory files for free.
  */
 
@@ -232,6 +232,7 @@
 		}
 	}
 
+	lpmminfo->dwFlags = dwOpenFlags;
 	lpmminfo->hmmio = hmmio;
 
 	/* call IO proc to actually open file */
@@ -301,7 +302,37 @@
 	if (lpmminfo == NULL)
 		return -1;
 
-	count = mmioSendMessage(hmmio, MMIOM_READ, (LPARAM) pch, (LPARAM) cch);
+	if (lpmminfo->pchNext != lpmminfo->pchEndRead) {
+		count = lpmminfo->pchEndRead - lpmminfo->pchNext;
+		if (count > cch) count = cch;
+		memcpy(pch, lpmminfo->pchNext, count);
+		lpmminfo->pchNext += count;
+		pch += count;
+		cch -= count;
+	} else
+		count = 0;
+
+	if (cch) {
+		if (lpmminfo->cchBuffer) {
+			mmioFlush32(hmmio, MMIO_EMPTYBUF);
+
+			while (cch) {
+				LONG size = mmioSendMessage(hmmio, MMIOM_READ,
+						(LPARAM) lpmminfo->pchBuffer,
+						(LPARAM) lpmminfo->cchBuffer);
+				lpmminfo->pchNext = lpmminfo->pchBuffer;
+				lpmminfo->pchEndRead = lpmminfo->pchBuffer + size;
+				if (size > cch) size = cch;
+				memcpy(pch, lpmminfo->pchNext, size);
+				lpmminfo->pchNext += size;
+				pch += size;
+				cch -= size;
+				count += size;
+			}
+		} else {
+			count += mmioSendMessage(hmmio, MMIOM_READ, (LPARAM) pch, (LPARAM) cch);
+		}
+	}
 
 	GlobalUnlock16(hmmio);
 	TRACE(mmio, "count=%ld\n", count);
@@ -330,7 +361,25 @@
 	if (lpmminfo == NULL)
 		return -1;
 
-	count = mmioSendMessage(hmmio, MMIOM_WRITE, (LPARAM) pch, (LPARAM) cch);
+	if (lpmminfo->cchBuffer) {
+		count = 0;
+		while (cch) {
+			if (lpmminfo->pchNext != lpmminfo->pchEndWrite) {
+				count = lpmminfo->pchEndWrite - lpmminfo->pchNext;
+				if (count > cch) count = cch;
+				memcpy(lpmminfo->pchNext, pch, count);
+				lpmminfo->pchNext += count;
+				pch += count;
+				cch -= count;
+				lpmminfo->dwFlags |= MMIO_DIRTY;
+			}
+
+			if (lpmminfo->pchNext == lpmminfo->pchEndWrite
+				&& mmioFlush32(hmmio, MMIO_EMPTYBUF)) break;
+		}
+	} else {
+		count = mmioSendMessage(hmmio, MMIOM_WRITE, (LPARAM) pch, (LPARAM) cch);
+	}
 
 	GlobalUnlock16(hmmio);
 	TRACE(mmio, "count=%ld\n", count);
@@ -355,11 +404,14 @@
 
 	TRACE(mmio, "(%04X, %08lX, %d);\n", hmmio, lOffset, iOrigin);
 
+	if (mmioFlush32(hmmio, MMIO_EMPTYBUF))
+		return -1;
+
 	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
 	if (lpmminfo == NULL)
 		return 0;
 
-    offset = mmioSendMessage(hmmio, MMIOM_SEEK, (LPARAM) lOffset, (LPARAM) iOrigin);
+	offset = mmioSendMessage(hmmio, MMIOM_SEEK, (LPARAM) lOffset, (LPARAM) iOrigin);
 
 	GlobalUnlock16(hmmio);
 	return offset;
@@ -428,6 +480,8 @@
 	TRACE(mmio, "mmioSetInfo\n");
 	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
 	if (lpmminfo == NULL) return 0;
+	lpmminfo->pchNext	= lpmmioinfo->pchNext;
+	lpmminfo->pchEndRead	= lpmmioinfo->pchEndRead;
 	GlobalUnlock16(hmmio);
 	return 0;
 }
@@ -438,12 +492,56 @@
 UINT16 WINAPI mmioSetBuffer(HMMIO16 hmmio, LPSTR pchBuffer, 
                             LONG cchBuffer, UINT16 uFlags)
 {
-	FIXME(mmio, "(hmmio=%d, pchBuf=%p, cchBuf=%ld, uFlags=%#08x): stub\n",
+	LPMMIOINFO16	lpmminfo;
+
+	if (mmioFlush32(hmmio, MMIO_EMPTYBUF) != 0)
+		return MMIOERR_CANNOTWRITE;
+
+	TRACE(mmio, "(hmmio=%04x, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
 	      hmmio, pchBuffer, cchBuffer, uFlags);
+
+	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
+	if (lpmminfo == NULL) return 0;
+	if ((!cchBuffer || pchBuffer) && lpmminfo->dwFlags&MMIO_ALLOCBUF) {
+		GlobalUnlock16(lpmminfo->dwReserved1);
+		GlobalFree16(lpmminfo->dwReserved1);
+		lpmminfo->dwFlags &= ~MMIO_ALLOCBUF;
+	}
+	if (pchBuffer) {
+		lpmminfo->pchBuffer = pchBuffer;
+	} else
+	if (lpmminfo->dwFlags&MMIO_ALLOCBUF) {
+		HGLOBAL16 hNewBuf;
+		GlobalUnlock16(lpmminfo->dwReserved1);
+		hNewBuf = GlobalReAlloc16(lpmminfo->dwReserved1, cchBuffer, 0);
+		if (!hNewBuf) {
+			/* FIXME: this assumes the memory block didn't move */
+			GlobalLock16(lpmminfo->dwReserved1);
+			GlobalUnlock16(hmmio);
+			return MMIOERR_OUTOFMEMORY;
+		}
+		lpmminfo->dwReserved1 = hNewBuf;
+		lpmminfo->pchBuffer = GlobalLock16(hNewBuf);
+	} else
+	if (cchBuffer) {
+		HGLOBAL16 hNewBuf = GlobalAlloc16(GMEM_MOVEABLE, cchBuffer);
+		if (!hNewBuf) {
+			GlobalUnlock16(hmmio);
+			return MMIOERR_OUTOFMEMORY;
+		}
+		lpmminfo->dwReserved1 = hNewBuf;
+		lpmminfo->pchBuffer = GlobalLock16(hNewBuf);
+		lpmminfo->dwFlags |= MMIO_ALLOCBUF;
+	} else
+		lpmminfo->pchBuffer = NULL;
+	lpmminfo->cchBuffer = cchBuffer;
+	lpmminfo->pchNext = lpmminfo->pchBuffer;
+	lpmminfo->pchEndRead = lpmminfo->pchBuffer;
+	lpmminfo->pchEndWrite = lpmminfo->pchBuffer + cchBuffer;
+	lpmminfo->lBufOffset = 0;
+
+	GlobalUnlock16(hmmio);
 	return (UINT16) 0;
-/*	stops Corel Draw 4 (16 bit) from working
-	return MMIOERR_OUTOFMEMORY;
-*/
 }
 
 /**************************************************************************
@@ -455,6 +553,27 @@
 	TRACE(mmio, "(%04X, %04X)\n", hmmio, uFlags);
 	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
 	if (lpmminfo == NULL) return 0;
+
+	/* not quite sure what to do here, but I'll guess */
+	if (lpmminfo->dwFlags&MMIO_DIRTY) {
+		if (lpmminfo->pchNext != (lpmminfo->pchBuffer + lpmminfo->lBufOffset)) {
+			if (lpmminfo->dwFlags&MMIO_READWRITE)
+				mmioSendMessage(hmmio, MMIOM_SEEK,
+					(LPARAM) (lpmminfo->pchBuffer - lpmminfo->pchEndRead) + lpmminfo->lBufOffset,
+					(LPARAM) SEEK_CUR );
+			mmioSendMessage(hmmio, MMIOM_WRITE,
+				(LPARAM) lpmminfo->pchBuffer + lpmminfo->lBufOffset,
+				(LPARAM) (lpmminfo->pchNext - lpmminfo->pchBuffer) - lpmminfo->lBufOffset );
+		}
+		lpmminfo->lBufOffset = lpmminfo->pchNext - lpmminfo->pchBuffer;
+		lpmminfo->dwFlags &= ~MMIO_DIRTY;
+	}
+	if (uFlags & MMIO_EMPTYBUF) {
+		lpmminfo->pchNext = lpmminfo->pchBuffer;
+		lpmminfo->pchEndRead = lpmminfo->pchBuffer;
+		lpmminfo->lBufOffset = 0;
+	}
+
 	GlobalUnlock16(hmmio);
 	return 0;
 }
@@ -472,20 +591,21 @@
  */
 UINT32 WINAPI mmioAdvance32(HMMIO32 hmmio,MMIOINFO32*lpmmioinfo,UINT32 uFlags)
 {
-	int		count = 0;
 	LPMMIOINFO16	lpmminfo;
 	TRACE(mmio, "mmioAdvance\n");
 	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
 	if (lpmminfo == NULL) return 0;
 	if (uFlags == MMIO_READ)
-		count = _lread32(LOWORD(lpmminfo->adwInfo[0]), 
-			lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer);
+	        lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer +
+	            mmioSendMessage(hmmio, MMIOM_READ,
+	                (LPARAM) lpmmioinfo->pchBuffer,
+	                (LPARAM) lpmmioinfo->cchBuffer);
 	if (uFlags == MMIO_WRITE)
-		count = _lwrite32(LOWORD(lpmminfo->adwInfo[0]),
-			lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer);
-	lpmmioinfo->pchNext	+= count;
+	            mmioSendMessage(hmmio, MMIOM_WRITE,
+	                (LPARAM) lpmmioinfo->pchBuffer,
+	                (LPARAM) lpmmioinfo->cchBuffer);
+	lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
 	GlobalUnlock16(hmmio);
-	lpmminfo->lDiskOffset = _llseek32((HFILE32)lpmminfo->adwInfo[0], 0, SEEK_CUR);
 	return 0;
 }
 
@@ -494,20 +614,21 @@
  */
 UINT16 WINAPI mmioAdvance16(HMMIO16 hmmio,MMIOINFO16*lpmmioinfo,UINT16 uFlags)
 {
-	int		count = 0;
 	LPMMIOINFO16	lpmminfo;
 	TRACE(mmio, "mmioAdvance\n");
 	lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
 	if (lpmminfo == NULL) return 0;
 	if (uFlags == MMIO_READ)
-		count = _lread32(LOWORD(lpmminfo->adwInfo[0]), 
-			lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer);
+	        lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer +
+	            mmioSendMessage(hmmio, MMIOM_READ,
+	                (LPARAM) lpmmioinfo->pchBuffer,
+	                (LPARAM) lpmmioinfo->cchBuffer);
 	if (uFlags == MMIO_WRITE)
-		count = _lwrite32(LOWORD(lpmminfo->adwInfo[0]),
-			lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer);
-	lpmmioinfo->pchNext	+= count;
+	            mmioSendMessage(hmmio, MMIOM_WRITE,
+	                (LPARAM) lpmmioinfo->pchBuffer,
+	                (LPARAM) lpmmioinfo->cchBuffer);
+	lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
 	GlobalUnlock16(hmmio);
-	lpmminfo->lDiskOffset = _llseek32((HFILE32)lpmminfo->adwInfo[0], 0, SEEK_CUR);
 	return 0;
 }
 
@@ -708,7 +829,29 @@
  */
 UINT32 WINAPI mmioAscend32(HMMIO32 hmmio, MMCKINFO * lpck, UINT32 uFlags)
 {
-	FIXME(mmio, "empty stub !\n");
+	TRACE(mmio, "(%04X, %p, %04X);\n", 
+				hmmio, lpck, uFlags);
+	if (lpck->dwFlags&MMIO_DIRTY) {
+		DWORD	dwOldPos, dwNewSize, dwSizePos;
+		
+		dwOldPos = mmioSeek32(hmmio, 0, SEEK_CUR);
+		TRACE(mmio, "dwOldPos=%ld\n", dwOldPos);
+		dwNewSize = dwOldPos - lpck->dwDataOffset;
+		if (dwNewSize != lpck->cksize) {
+			TRACE(mmio, "dwNewSize=%ld\n", dwNewSize);
+			lpck->cksize = dwNewSize;
+
+			dwSizePos = lpck->dwDataOffset - sizeof(DWORD);
+			if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) 
+				dwSizePos -= sizeof(DWORD);
+			TRACE(mmio, "dwSizePos=%ld\n", dwSizePos);
+
+			mmioSeek32(hmmio, dwSizePos, SEEK_SET);
+			mmioWrite32(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD));
+		}
+	}
+	mmioSeek32(hmmio,lpck->dwDataOffset+lpck->cksize,SEEK_SET);
+
 	return 0;
 }
 
@@ -725,7 +868,34 @@
  */
 UINT16 WINAPI mmioCreateChunk(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
 {
-	FIXME(mmio, "empty stub \n");
+	DWORD	dwOldPos;
+	LONG ix;
+
+	TRACE(mmio, "(%04X, %p, %04X);\n", 
+				hmmio, lpck, uFlags);
+
+	dwOldPos = mmioSeek32(hmmio, 0, SEEK_CUR);
+	TRACE(mmio, "dwOldPos=%ld\n", dwOldPos);
+
+	if (uFlags == MMIO_CREATELIST)
+		lpck->ckid = FOURCC_LIST;
+	else if (uFlags == MMIO_CREATERIFF)
+		lpck->ckid = FOURCC_RIFF;
+
+	lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
+	if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) 
+		lpck->dwDataOffset += sizeof(DWORD);
+	lpck->dwFlags = MMIO_DIRTY;
+
+	ix = mmioWrite32(hmmio, (LPSTR)lpck, lpck->dwDataOffset - dwOldPos);
+	TRACE(mmio, "after _lwrite32 ix = %ld req = %ld, errno = %d\n",ix,lpck->dwDataOffset - dwOldPos,errno);
+	if (ix < lpck->dwDataOffset - dwOldPos) {
+
+		mmioSeek32(hmmio, dwOldPos, SEEK_SET);
+		WARN(mmio, "return CannotWrite\n");
+		return MMIOERR_CANNOTWRITE;
+	}
+
 	return 0;
 }
 
diff --git a/multimedia/mmsystem.c b/multimedia/mmsystem.c
index 3dbc7c1..458a5be 100644
--- a/multimedia/mmsystem.c
+++ b/multimedia/mmsystem.c
@@ -33,7 +33,7 @@
 
 struct LINUX_MCIDRIVER mciDrv[MAXMCIDRIVERS];
 
-UINT16 midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
+UINT16 WINAPI midiGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
 static UINT16 waveGetErrorText(UINT16 uError, LPSTR lpText, UINT16 uSize);
 LONG WINAPI DrvDefDriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
                              DWORD dwParam1, DWORD dwParam2);
@@ -333,6 +333,11 @@
                                                        hDev, wMsg, dwUser,
                                                        dwParam1, dwParam2 );
 			break;
+		case DCB_FUNC32:
+			TRACE(mmsys, "CALLBACK_FUNCTION !\n");
+			((LPDRVCALLBACK32)dwCallBack)( hDev, wMsg, dwUser,
+                                                       dwParam1, dwParam2 );
+			break;
 		}
 	return TRUE;
 }
@@ -499,7 +504,7 @@
 /**************************************************************************
  * 				mixerGetControlDetailsA	[WINMM.99]
  */
-UINT32 mixerGetControlDetails32A(HMIXEROBJ32 hmix,LPMIXERCONTROLDETAILS32 lpmcd,DWORD fdwDetails) {
+UINT32 WINAPI mixerGetControlDetails32A(HMIXEROBJ32 hmix,LPMIXERCONTROLDETAILS32 lpmcd,DWORD fdwDetails) {
 	FIXME(mmsys,"(%04x,%p,%08lx): stub!\n",hmix,lpmcd,fdwDetails);
 	return MMSYSERR_NOTENABLED;
 }
@@ -507,7 +512,7 @@
 /**************************************************************************
  * 				mixerGetControlDetailsW	[WINMM.100]
  */
-UINT32 mixerGetControlDetails32W(HMIXEROBJ32 hmix,LPMIXERCONTROLDETAILS32 lpmcd,DWORD fdwDetails) {
+UINT32 WINAPI mixerGetControlDetails32W(HMIXEROBJ32 hmix,LPMIXERCONTROLDETAILS32 lpmcd,DWORD fdwDetails) {
 	FIXME(mmsys,"(%04x,%p,%08lx): stub!\n",	hmix,lpmcd,fdwDetails);
 	return MMSYSERR_NOTENABLED;
 }
@@ -515,7 +520,7 @@
 /**************************************************************************
  * 				mixerGetControlDetails	[MMSYSTEM.808]
  */
-UINT16 mixerGetControlDetails16(HMIXEROBJ16 hmix,LPMIXERCONTROLDETAILS16 lpmcd,DWORD fdwDetails) {
+UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix,LPMIXERCONTROLDETAILS16 lpmcd,DWORD fdwDetails) {
 	FIXME(mmsys,"(%04x,%p,%08lx): stub!\n",hmix,lpmcd,fdwDetails);
 	return MMSYSERR_NOTENABLED;
 }
@@ -1316,6 +1321,10 @@
 	DWORD	dwRet = MCIERR_INTERNAL;
 
 	TRACE(mmsys, "(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms);
+	if(wDevID==MCI_ALL_DEVICE_ID) {
+	  FIXME(mmsys, "unhandled MCI_ALL_DEVICE_ID\n");
+	  return MCIERR_CANNOT_USE_ALL;
+	}
 	switch(GetDrv(wDevID)->modp.wType) {
 	case MCI_DEVTYPE_CD_AUDIO:
 		dwRet = CDAUDIO_DriverProc(GetDrv(wDevID)->modp.wDeviceID,0,
@@ -1799,7 +1808,8 @@
 	HMIDIOUT16	hmo16;
 	UINT32		ret;
 
-	ret = midiOutOpen16(&hmo16,uDeviceID,dwCallback,dwInstance,dwFlags);
+	ret = midiOutOpen16(&hmo16,uDeviceID,dwCallback,dwInstance,
+			    CALLBACK32CONV(dwFlags));
 	if (lphMidiOut) *lphMidiOut = hmo16;
 	return ret;
 }
@@ -2688,7 +2698,8 @@
                             DWORD dwInstance, DWORD dwFlags)
 {
 	HWAVEOUT16	hwo16;
-	UINT32	ret=waveOutOpen16(&hwo16,uDeviceID,lpFormat,dwCallback,dwInstance,dwFlags);
+	UINT32	ret=waveOutOpen16(&hwo16,uDeviceID,lpFormat,dwCallback,dwInstance,
+				  CALLBACK32CONV(dwFlags));
 	if (lphWaveOut) *lphWaveOut=hwo16;
 	return ret;
 }
diff --git a/multimedia/msvideo.c b/multimedia/msvideo.c
new file mode 100644
index 0000000..387f85b
--- /dev/null
+++ b/multimedia/msvideo.c
@@ -0,0 +1,21 @@
+/*
+ * MSVIDEO procedures
+ *
+ * Copyright 1998 Luiz Otavio L. Zorzella
+ */
+
+#include "windows.h"
+#include "debug.h"
+
+/***********************************************************************
+ *           VideoForWindowsVersion     [MSVIDEO.2]
+ */
+DWORD WINAPI VideoForWindowsVersion ()
+{
+
+  FIXME (msvideo, "(void): stub\n");
+
+  /* What should be returned? */
+  return 1;
+  
+}
diff --git a/objects/cursoricon.c b/objects/cursoricon.c
index 45d1cc6..b7969c1 100644
--- a/objects/cursoricon.c
+++ b/objects/cursoricon.c
@@ -874,7 +874,9 @@
 {
     TRACE(icon, "%04x\n", hIcon );
     /* FIXME: should check for OEM/global heap icon here */
-    return (FreeResource32( hIcon ) == 0);
+    /* Unlike DestroyIcon16, only icons created with CreateIcon32
+       are valid for DestroyIcon32, so don't use FreeResource32 */
+    return (GlobalFree16( hIcon ) == 0);
 }
 
 
@@ -884,8 +886,21 @@
 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
 {
     TRACE(cursor, "%04x\n", hCursor );
-    /* FIXME: should check for OEM/global heap cursor here */
-    return (FreeResource16( hCursor ) == 0);
+    if (FreeResource16( hCursor ) == 0)
+      return TRUE;
+    else
+      /* I believe this very same line should be added for every function
+	 where appears the comment:
+
+	 "FIXME: should check for OEM/global heap cursor here"
+
+	 which are most (all?) the ones that call FreeResource, at least
+	 in this module. Maybe this should go to a wrapper to avoid
+	 repetition. Or: couldn't it go to FreeResoutce itself?
+	 
+	 I'll let this to someone savvy on the subject.
+	 */
+      return (GlobalFree16 (hCursor) == 0);
 }
 
 
@@ -896,7 +911,9 @@
 {
     TRACE(cursor, "%04x\n", hCursor );
     /* FIXME: should check for OEM/global heap cursor here */
-    return (FreeResource32( hCursor ) == 0);
+    /* Unlike DestroyCursor16, only cursors created with CreateCursor32
+       are valid for DestroyCursor32, so don't use FreeResource32 */
+    return (GlobalFree16( hCursor ) == 0);
 }
 
 
@@ -1540,7 +1557,8 @@
                                 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
                                 (char *)(ciconinfo + 1)
                                 + ciconinfo->nHeight *
-                                BITMAP_WIDTH_BYTES(ciconinfo->nWidth,1) );
+                                BITMAP_GetBitsWidth (ciconinfo->nWidth,1) );
+//                                BITMAP_WIDTH_BYTES(ciconinfo->nWidth,1) );
     iconinfo->hbmMask = CreateBitmap32 ( ciconinfo->nWidth, ciconinfo->nHeight,
                                 1, 1, (char *)(ciconinfo + 1));
 
diff --git a/objects/dib.c b/objects/dib.c
index 413e233..3b1a81a 100644
--- a/objects/dib.c
+++ b/objects/dib.c
@@ -1977,12 +1977,6 @@
 	  bi->biWidth, bi->biHeight, bi->biPlanes, bi->biBitCount,
 	  bi->biSizeImage, bi->biClrUsed, usage == DIB_PAL_COLORS? "PAL" : "RGB");
 
-    if (bi->biCompression)
-    {
-	FIXME(bitmap, "Compression not implemented!\n");
-	return 0;
-    }
-
     bm.bmType = 0;
     bm.bmWidth = bi->biWidth;
     bm.bmHeight = bi->biHeight;
@@ -2005,11 +1999,12 @@
     /* Create Color Map */
     if (bm.bmBits && bm.bmBitsPixel <= 8)
     {
-        DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
-        if (!dc) dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
+        DC *dc = hdc? (DC *)GDI_GetObjPtr(hdc, DC_MAGIC) : NULL;
+        if (hdc && !dc) dc = (DC *)GDI_GetObjPtr(hdc, METAFILE_DC_MAGIC);
 
-        if (dc) colorMap = DIB_BuildColorMap( dc, usage, bm.bmBitsPixel,
-                                              bmi, &nColorMap );
+        if (!hdc || dc)
+            colorMap = DIB_BuildColorMap( dc, usage, bm.bmBitsPixel,
+                                          bmi, &nColorMap );
         GDI_HEAP_UNLOCK(hdc);
     }
 
diff --git a/objects/font.c b/objects/font.c
index 8da7089..91434d3 100644
--- a/objects/font.c
+++ b/objects/font.c
@@ -12,6 +12,7 @@
 #include "metafile.h"
 #include "options.h"
 #include "debug.h"
+#include "winerror.h"
 
 #define ENUM_UNICODE	0x00000001
 
@@ -1260,6 +1261,30 @@
 	return 0;
 }
 
+/*************************************************************************
+ * GetFontData32 [GDI32.181] Retrieve data for TrueType font
+ *
+ * RETURNS
+ *
+ * success: Number of bytes returned 
+ * failure: GDI_ERROR
+ *
+ * NOTES
+ *
+ * Calls SetLastError()  
+ *
+ * BUGS
+ *
+ * Unimplemented
+ */
+DWORD WINAPI GetFontData32(HDC32 hdc, DWORD table, DWORD offset, 
+    LPVOID buffer, DWORD length)
+{
+    FIXME(font, "(%x,%ld,%ld,%p,%ld): stub\n", 
+        hdc, table, offset, buffer, length);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return GDI_ERROR;
+}
 
 /*************************************************************************
  * GetCharacterPlacement32A [GDI32.160]
diff --git a/ole/folders.c b/ole/folders.c
index 7be42ed..3ddde11 100644
--- a/ole/folders.c
+++ b/ole/folders.c
@@ -5,7 +5,7 @@
  *	Copyright 1998	Juergen Schmied
  *
  *  !!! currently work in progress on all classes !!!
- *  <contact juergen.schmied@metronet.de, 980624>
+ *  <contact juergen.schmied@metronet.de, 980801>
  */
 
 #include <ctype.h>
@@ -19,6 +19,7 @@
 #include "shlobj.h"
 #include "winerror.h"
 #include "winnls.h"
+#include "winproc.h"
 
 /* FIXME should be moved to a header file. IsEqualGUID 
 is declared but not exported in compobj.c !!!*/
@@ -28,16 +29,20 @@
 /***************************************************************************
  *  GetNextElement (internal function)
  *
+ * gets a part of a string till the first backslash
+ *
+ * PARAMETERS
+ *  pszNext [IN] string to get the element from
+ *  pszOut  [IN] pointer to buffer whitch receives string
+ *  dwOut   [IN] length of pszOut
+ *
  *  RETURNS
  *    LPSTR pointer to first, not yet parsed char
  */
-LPSTR GetNextElement(
-    LPSTR pszNext, /*[IN] string to get the element from*/
-		LPSTR pszOut,  /*[IN] pointer to buffer whitch receives string*/
-		DWORD dwOut)   /*[IN] length of pszOut*/
+LPSTR GetNextElement(LPSTR pszNext,LPSTR pszOut,DWORD dwOut)
 { LPSTR   pszTail = pszNext;
   DWORD dwCopy;
-  TRACE(shell,"(%s %p 0x%08lx)\n",pszNext,	pszOut, dwOut);
+  TRACE(shell,"(%s %p 0x%08lx)\n",debugstr_a(pszNext),pszOut,dwOut);
 
   if(!pszNext || !*pszNext)
     return NULL;
@@ -52,7 +57,7 @@
   {  pszTail++;
 	}
 
-  TRACE(shell,"--(%s %s 0x%08lx)\n",pszNext,	pszOut, dwOut);
+  TRACE(shell,"--(%s %s 0x%08lx)\n",debugstr_a(pszNext),debugstr_a(pszOut),dwOut);
   return pszTail;
 }
 
@@ -63,16 +68,16 @@
 static ULONG WINAPI IClassFactory_AddRef(LPCLASSFACTORY);
 static ULONG WINAPI IClassFactory_Release(LPCLASSFACTORY);
 static HRESULT WINAPI IClassFactory_CreateInstance();
-/*static HRESULT WINAPI IClassFactory_LockServer();*/
+static HRESULT WINAPI IClassFactory_LockServer();
 /**************************************************************************
  *  IClassFactory_VTable
  */
-static IClassFactory_VTable clfvt = {
-	IClassFactory_QueryInterface,
+static IClassFactory_VTable clfvt = 
+{ IClassFactory_QueryInterface,
 	IClassFactory_AddRef,
 	IClassFactory_Release,
 	IClassFactory_CreateInstance,
-/*	IClassFactory_LockServer*/
+  IClassFactory_LockServer
 };
 
 /**************************************************************************
@@ -143,7 +148,7 @@
 	char	xriid[50];
 
   WINE_StringFromCLSID((LPCLSID)riid,xriid);
-  TRACE(shell,"%p->(%p,\n\tIID:\t%s)\n",this,pUnknown,xriid);
+  TRACE(shell,"%p->(%p,\n\tIID:\t%s,%p)\n",this,pUnknown,xriid,ppObject);
 
 	*ppObject = NULL;
 		
@@ -154,6 +159,12 @@
 	if (IsEqualIID(riid, &IID_IShellFolder))
   { pObj = (IUnknown *)IShellFolder_Constructor(NULL,NULL);
   } 
+  else if (IsEqualIID(riid, &IID_IShellView))
+  { pObj = (IUnknown *)IShellView_Constructor();
+  } 
+  else if (IsEqualIID(riid, &IID_IShellLink))
+  { pObj = (IUnknown *)IShellLink_Constructor();
+  } 
 	else
 	{ ERR(shell,"unknown IID requested\n\tIID:\t%s\n",xriid);
 	  return(E_NOINTERFACE);
@@ -172,12 +183,11 @@
 /******************************************************************************
  * IClassFactory_LockServer
  */
-/*static HRESULT WINAPI IClassFactory_LockServer(LPCLASSFACTORY this, BOOL)
-{ TRACE(shell,"%p->(), not implemented\n",this)
+static HRESULT WINAPI IClassFactory_LockServer(LPCLASSFACTORY this, BOOL32 fLock)
+{ TRACE(shell,"%p->(0x%x), not implemented\n",this, fLock);
   return E_NOTIMPL;
 }
 
-*/
 /**************************************************************************
  *  IEnumIDList Implementation
  */
@@ -194,8 +204,8 @@
 /**************************************************************************
  *  IEnumIDList_VTable
  */
-static IEnumIDList_VTable eidlvt = {
-	IEnumIDList_QueryInterface,
+static IEnumIDList_VTable eidlvt = 
+{ IEnumIDList_QueryInterface,
 	IEnumIDList_AddRef,
 	IEnumIDList_Release,
 	IEnumIDList_Next,
@@ -221,7 +231,7 @@
 	lpeidl->mpLast=NULL;
 	lpeidl->mpCurrent=NULL;
 
-  TRACE(shell,"(%p)->(%s 0x%08lx %p)\n",lpeidl,lpszPath,dwFlags,pResult);
+  TRACE(shell,"(%p)->(%s 0x%08lx %p)\n",lpeidl,debugstr_a(lpszPath),dwFlags,pResult);
 
 	lpeidl->mpPidlMgr=PidlMgr_Constructor();
   if (!lpeidl->mpPidlMgr)
@@ -300,11 +310,16 @@
 	LPENUMIDLIST this,ULONG celt,LPITEMIDLIST * rgelt,ULONG *pceltFetched) 
 { ULONG    i;
   HRESULT  hr = S_OK;
-
   LPITEMIDLIST  temp;
 
 	TRACE(shell,"(%p)->(%ld,%p, %p)\n",this,celt,rgelt,pceltFetched);
 
+  /* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's
+     subsystems actually use it (and so may a third party browser)
+   */
+  if(pceltFetched)
+    *pceltFetched = 0;
+
 	*rgelt=0;
 	
   if(celt > 1 && !pceltFetched)
@@ -316,7 +331,7 @@
     { hr =  S_FALSE;
       break;
     }
-		temp = this->mpPidlMgr->lpvtbl->fnCopy(this->mpPidlMgr, this->mpCurrent->pidl);
+    temp = ILClone(this->mpCurrent->pidl);
     rgelt[i] = temp;
     this->mpCurrent = this->mpCurrent->pNext;
   }
@@ -371,53 +386,78 @@
 { LPITEMIDLIST   pidl=NULL;
   WIN32_FIND_DATA32A stffile;	
   HANDLE32 hFile;
-	
-  TRACE(shell,"(%p)->(%s 0x%08lx) \n",this,lpszPath,dwFlags);
+  DWORD dwDrivemap;
+  CHAR  szDriveName[4];
+  CHAR  szPath[MAX_PATH];
+    
+  TRACE(shell,"(%p)->(%s 0x%08lx) \n",this,debugstr_a(lpszPath),dwFlags);
+
+  if (lpszPath && lpszPath[0]!='\0')
+  { strcpy(szPath, lpszPath);
+    PathAddBackslash(szPath);
+    strcat(szPath,"*.*");
+  }
 
   /*enumerate the folders*/
   if(dwFlags & SHCONTF_FOLDERS)
   {	/* special case - we can't enumerate the Desktop level Objects (MyComputer,Nethood...
     so we need to fake an enumeration of those.*/
 	  if(!lpszPath)
-    { TRACE (shell,"(%p)-> enumerate the special-folder items\n",this);
+    { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (special) items\n",this);
   		//create the pidl for this item
-      pidl = this->mpPidlMgr->lpvtbl->fnCreateDesktop(this->mpPidlMgr);
+      pidl = this->mpPidlMgr->lpvtbl->fnCreateMyComputer(this->mpPidlMgr);
+      if(pidl)
+      { if(!IEnumIDList_AddToEnumList(this, pidl))
+        return FALSE;
+      }
+    }   
+    else if (lpszPath[0]=='\0') /* enumerate the drives*/
+    { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS (drives)\n",this);
+      dwDrivemap = GetLogicalDrives();
+      strcpy (szDriveName,"A:\\");
+      while (szDriveName[0]<='Z')
+      { if(dwDrivemap & 0x00000001L)
+        { pidl = this->mpPidlMgr->lpvtbl->fnCreateDrive(this->mpPidlMgr,szDriveName );
       if(pidl)
       { if(!IEnumIDList_AddToEnumList(this, pidl))
           return FALSE;
       }
-      else
-      { return FALSE;
       }
+        szDriveName[0]++;
+        dwDrivemap = dwDrivemap >> 1;
      }   
+    }
+    
      else
-     { TRACE (shell,"(%p)-> enumerate the folder items for %s\n",this,lpszPath);
-		   hFile = FindFirstFile32A(lpszPath,&stffile);
-       do
-       { if (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-         //create the pidl for this item
-         /* fixme: the shortname should be given too*/
-         pidl = this->mpPidlMgr->lpvtbl->fnCreateFolder(this->mpPidlMgr, stffile.cFileName);
+    { TRACE (shell,"-- (%p)-> enumerate SHCONTF_FOLDERS of %s\n",this,debugstr_a(szPath));
+      hFile = FindFirstFile32A(szPath,&stffile);
+      if ( hFile != INVALID_HANDLE_VALUE32 )
+      { do
+        { if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp (stffile.cFileName, ".") && strcmp (stffile.cFileName, ".."))
+          { pidl = this->mpPidlMgr->lpvtbl->fnCreateFolder(this->mpPidlMgr, stffile.cFileName);
          if(pidl)
          { if(!IEnumIDList_AddToEnumList(this, pidl))
-             return FALSE;
+               {  return FALSE;
+               }
          }
          else
          { return FALSE;
          }   
+           }
       } while( FindNextFile32A(hFile,&stffile));
 			FindClose32 (hFile);
     }
   }   
+  }   
   //enumerate the non-folder items (values)
   if(dwFlags & SHCONTF_NONFOLDERS)
-  { TRACE (shell,"(%p)-> enumerate the non-folder items (values) of %s\n",this,lpszPath);
-	  hFile = FindFirstFile32A(lpszPath,&stffile);
-    do
+  { if(lpszPath)
+    { TRACE (shell,"-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n",this,debugstr_a(szPath));
+      hFile = FindFirstFile32A(szPath,&stffile);
+      if ( hFile != INVALID_HANDLE_VALUE32 )
+      { do
     { if (! (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
-		  //create the pidl for this item
-			/* fixme: the shortname should be given too*/
-      pidl = this->mpPidlMgr->lpvtbl->fnCreateFolder(this->mpPidlMgr, stffile.cFileName);
+          { pidl = this->mpPidlMgr->lpvtbl->fnCreateValue(this->mpPidlMgr, stffile.cFileName);
       if(pidl)
       { if(!IEnumIDList_AddToEnumList(this, pidl))
         { return FALSE;
@@ -426,9 +466,12 @@
       else
       { return FALSE;
       }   
+          }
     } while( FindNextFile32A(hFile,&stffile));
 	  FindClose32 (hFile);
   } 
+    }
+  } 
   return TRUE;
 }
 
@@ -458,7 +501,7 @@
    
     //update the last item pointer
     this->mpLast = pNew;
-		TRACE(shell,"(%p)->(first=%p, last=%p)\n",this,this->mpFirst,this->mpLast);
+    TRACE(shell,"-- (%p)->(first=%p, last=%p)\n",this,this->mpFirst,this->mpLast);
     return TRUE;
   }
   return FALSE;
@@ -474,21 +517,291 @@
   while(this->mpFirst)
   { pDelete = this->mpFirst;
     this->mpFirst = pDelete->pNext;
-
-    //free the pidl
-    this->mpPidlMgr->lpvtbl->fnDelete(this->mpPidlMgr,pDelete->pidl);
-   
-    //free the list item
-		HeapFree(GetProcessHeap(),0,pDelete);
+    SHFree(pDelete->pidl);
+    SHFree(pDelete);
   }
   this->mpFirst = this->mpLast = this->mpCurrent = NULL;
   return TRUE;
 }
+/***********************************************************************
+*   IShellView implementation
+*/
+static HRESULT WINAPI IShellView_QueryInterface(LPSHELLVIEW,REFIID riid, LPVOID *ppvObj);
+static ULONG WINAPI IShellView_AddRef(LPSHELLVIEW) ;
+static ULONG WINAPI IShellView_Release(LPSHELLVIEW);
+
+    // *** IOleWindow methods ***
+static HRESULT WINAPI IShellView_GetWindow(LPSHELLVIEW,HWND32 * lphwnd);
+static HRESULT WINAPI IShellView_ContextSensitiveHelp(LPSHELLVIEW,BOOL32 fEnterMode);
+
+    // *** IShellView methods ***
+static HRESULT WINAPI IShellView_TranslateAccelerator(LPSHELLVIEW,LPMSG32 lpmsg);
+static HRESULT WINAPI IShellView_EnableModeless(LPSHELLVIEW,BOOL32 fEnable);
+static HRESULT WINAPI IShellView_UIActivate(LPSHELLVIEW,UINT32 uState);
+static HRESULT WINAPI IShellView_Refresh(LPSHELLVIEW);
+static HRESULT WINAPI IShellView_CreateViewWindow(LPSHELLVIEW, IShellView *lpPrevView,LPCFOLDERSETTINGS lpfs, IShellBrowser * psb,RECT32 * prcView, HWND32  *phWnd);
+static HRESULT WINAPI IShellView_DestroyViewWindow(LPSHELLVIEW);
+static HRESULT WINAPI IShellView_GetCurrentInfo(LPSHELLVIEW, LPFOLDERSETTINGS lpfs);
+static HRESULT WINAPI IShellView_AddPropertySheetPages(LPSHELLVIEW, DWORD dwReserved,LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam);
+static HRESULT WINAPI IShellView_SaveViewState(LPSHELLVIEW);
+static HRESULT WINAPI IShellView_SelectItem(LPSHELLVIEW, LPCITEMIDLIST pidlItem, UINT32 uFlags);
+static HRESULT WINAPI IShellView_GetItemObject(LPSHELLVIEW, UINT32 uItem, REFIID riid,LPVOID *ppv);
+
+static struct IShellView_VTable svvt = 
+{ IShellView_QueryInterface,
+  IShellView_AddRef,
+  IShellView_Release,
+  IShellView_GetWindow,
+  IShellView_ContextSensitiveHelp,
+  IShellView_TranslateAccelerator,
+  IShellView_EnableModeless,
+  IShellView_UIActivate,
+  IShellView_Refresh,
+  IShellView_CreateViewWindow,
+  IShellView_DestroyViewWindow,
+  IShellView_GetCurrentInfo,
+  IShellView_AddPropertySheetPages,
+  IShellView_SaveViewState,
+  IShellView_SelectItem,
+  IShellView_GetItemObject
+};
+/**************************************************************************
+*  IShellView_Constructor
+*/
+LPSHELLVIEW IShellView_Constructor(LPSHELLFOLDER pFolder, LPCITEMIDLIST pidl)
+{ LPSHELLVIEW sv;
+  sv=(LPSHELLVIEW)HeapAlloc(GetProcessHeap(),0,sizeof(IShellView));
+  sv->ref=1;
+  sv->lpvtbl=&svvt;
+  
+  sv->mpidl = ILClone(pidl);
+
+  sv->pSFParent = pFolder;
+  if(sv->pSFParent)
+    sv->pSFParent->lpvtbl->fnAddRef(sv->pSFParent);
+
+  TRACE(shell,"(%p)->(%p pidl=%p)\n",sv, pFolder, pidl);
+  return sv;
+}
+/**************************************************************************
+*  ShellView_WndProc
+*/
+LRESULT CALLBACK ShellView_WndProc(HWND32 hWnd, UINT32 uMessage, WPARAM32 wParam, LPARAM lParam)
+{ LPSHELLVIEW pThis = (LPSHELLVIEW)GetWindowLong32A(hWnd, GWL_USERDATA);
+  LPCREATESTRUCT32A lpcs;
+
+  FIXME(shell,"(hwnd=%x msg=%x wparm=%x lparm=%lx)\n",hWnd, uMessage, wParam, lParam);
+    
+  switch (uMessage)
+  { case WM_NCCREATE:
+      { TRACE(shell,"WM_NCCREATE\n");
+        lpcs = (LPCREATESTRUCT32A)lParam;
+        pThis = (LPSHELLVIEW)(lpcs->lpCreateParams);
+        SetWindowLong32A(hWnd, GWL_USERDATA, (LONG)pThis);
+
+        //set the window handle
+        pThis->hWnd = hWnd;
+      }
+      break;
+   
+   case WM_SIZE:
+      TRACE(shell,"WM_SIZE\n");
+      return FALSE;
+   
+   case WM_CREATE:
+      TRACE(shell,"WM_CREATE\n");
+      return FALSE;
+   
+   case WM_SETFOCUS:
+      TRACE(shell,"WM_SETFOCUS\n");   
+      return FALSE;
+   
+   case WM_KILLFOCUS:
+      TRACE(shell,"WM_KILLFOCUS\n");
+      return FALSE;
+
+   case WM_ACTIVATE:
+      TRACE(shell,"WM_ACTIVATE\n");
+      return FALSE;
+   
+   case WM_COMMAND:
+      TRACE(shell,"WM_COMMAND\n");
+      return FALSE;
+   
+   case WM_INITMENUPOPUP:
+      TRACE(shell,"WM_INITMENUPOPUP\n");
+      return FALSE;
+   
+   case WM_NOTIFY:
+      TRACE(shell,"WM_NOTIFY\n");
+      return FALSE;
+   
+/*   case WM_SETTINGCHANGE:
+      return FALSE;*/
+  }
+
+  return DefWindowProc32A (hWnd, uMessage, wParam, lParam);
+}
+
+
+/**************************************************************************
+*  IShellView::QueryInterface
+*/
+static HRESULT WINAPI IShellView_QueryInterface(LPSHELLVIEW this,REFIID riid, LPVOID *ppvObj)
+{ char    xriid[50];
+  WINE_StringFromCLSID((LPCLSID)riid,xriid);
+  TRACE(shell,"(%p)->(\n\tIID:\t%s,%p)\n",this,xriid,ppvObj);
+
+  *ppvObj = NULL;
+
+  if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
+  { *ppvObj = this; 
+  }
+  else if(IsEqualIID(riid, &IID_IShellView))  /*IShellView*/
+  { *ppvObj = (IShellView*)this;
+  }   
+
+  if(*ppvObj)
+  { (*(LPSHELLVIEW*)ppvObj)->lpvtbl->fnAddRef(this);      
+    TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
+    return S_OK;
+  }
+  TRACE(shell,"-- Interface: E_NOINTERFACE\n");
+  return E_NOINTERFACE;
+}   
+/**************************************************************************
+*  IShellView::AddRef
+*/
+static ULONG WINAPI IShellView_AddRef(LPSHELLVIEW this)
+{ TRACE(shell,"(%p)->(count=%lu)\n",this,(this->ref)+1);
+  return ++(this->ref);
+}
+/**************************************************************************
+*  IShellView::Release
+*/
+static ULONG WINAPI IShellView_Release(LPSHELLVIEW this)
+{ TRACE(shell,"(%p)->()\n",this);
+  if (!--(this->ref)) 
+  { TRACE(shell," destroying IEnumIDList(%p)\n",this);
+
+    if(this->pSFParent)
+       this->pSFParent->lpvtbl->fnRelease(this->pSFParent);
+
+    HeapFree(GetProcessHeap(),0,this);
+    return 0;
+  }
+  return this->ref;
+}
+/**************************************************************************
+*  IShellView::GetWindow
+*/
+static HRESULT WINAPI IShellView_GetWindow(LPSHELLVIEW this,HWND32 * phWnd)
+{ TRACE(shell,"(%p) stub\n",this);
+ *phWnd = this->hWnd;
+
+ return S_OK;
+}
+static HRESULT WINAPI IShellView_ContextSensitiveHelp(LPSHELLVIEW this,BOOL32 fEnterMode)
+{ FIXME(shell,"(%p) stub\n",this);
+  return E_NOTIMPL;
+}
+static HRESULT WINAPI IShellView_TranslateAccelerator(LPSHELLVIEW this,LPMSG32 lpmsg)
+{ FIXME(shell,"(%p)->(%p) stub\n",this,lpmsg);
+  return E_NOTIMPL;
+}
+static HRESULT WINAPI IShellView_EnableModeless(LPSHELLVIEW this,BOOL32 fEnable)
+{ FIXME(shell,"(%p) stub\n",this);
+  return E_NOTIMPL;
+}
+static HRESULT WINAPI IShellView_UIActivate(LPSHELLVIEW this,UINT32 uState)
+{ FIXME(shell,"(%p) stub\n",this);
+  return E_NOTIMPL;
+}
+static HRESULT WINAPI IShellView_Refresh(LPSHELLVIEW this)
+{ FIXME(shell,"(%p) stub\n",this);
+  return S_OK;
+}
+static HRESULT WINAPI IShellView_CreateViewWindow(LPSHELLVIEW this, IShellView *lpPrevView,
+                     LPCFOLDERSETTINGS lpfs, IShellBrowser * psb,RECT32 * prcView, HWND32  *phWnd)
+{  WNDCLASS32A wc;
+   *phWnd = 0;
+
+   TRACE(shell,"(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n",this, lpPrevView,lpfs, psb, prcView, phWnd);
+
+//if our window class has not been registered, then do so
+  if(!GetClassInfo32A(shell32_hInstance, SV_CLASS_NAME, &wc))
+  { ZeroMemory(&wc, sizeof(wc));
+    wc.style          = CS_HREDRAW | CS_VREDRAW;
+    wc.lpfnWndProc    = (WNDPROC32) ShellView_WndProc;
+    wc.cbClsExtra     = 0;
+    wc.cbWndExtra     = 0;
+    wc.hInstance      = shell32_hInstance;
+    wc.hIcon          = 0;
+    wc.hCursor        = LoadCursor32A (0, IDC_ARROW32A);
+    wc.hbrBackground  = (HBRUSH32)(COLOR_WINDOW + 1);
+    wc.lpszMenuName   = NULL;
+    wc.lpszClassName  = SV_CLASS_NAME;
+   
+    if(!RegisterClass32A(&wc))
+      return E_FAIL;
+   }
+   //set up the member variables
+   this->pShellBrowser = psb;
+   this->FolderSettings = *lpfs;
+
+   //get our parent window
+   this->pShellBrowser->lpvtbl->fnGetWindow(this->pShellBrowser, &(this->hWndParent));
+
+   *phWnd = CreateWindowEx32A(0, SV_CLASS_NAME, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
+                           prcView->left, prcView->top, prcView->right - prcView->left, prcView->bottom - prcView->top,
+                           this->hWndParent, 0, shell32_hInstance, (LPVOID)this);
+                           
+   if(!*phWnd)
+     return E_FAIL;
+
+   this->pShellBrowser->lpvtbl->fnAddRef(this->pShellBrowser);
+
+   return S_OK;
+}
+
+static HRESULT WINAPI IShellView_DestroyViewWindow(LPSHELLVIEW this)
+{ FIXME(shell,"(%p) stub\n",this);
+
+  this->pShellBrowser->lpvtbl->fnRelease(this->pShellBrowser);
+
+  return S_OK;
+}
+static HRESULT WINAPI IShellView_GetCurrentInfo(LPSHELLVIEW this, LPFOLDERSETTINGS lpfs)
+{ FIXME(shell,"(%p)->(%p)stub\n",this, lpfs);
+
+  *lpfs = this->FolderSettings;
+  return S_OK;
+}
+static HRESULT WINAPI IShellView_AddPropertySheetPages(LPSHELLVIEW this, DWORD dwReserved,LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
+{ FIXME(shell,"(%p) stub\n",this);
+  return E_NOTIMPL;
+}
+static HRESULT WINAPI IShellView_SaveViewState(LPSHELLVIEW this)
+{ FIXME(shell,"(%p) stub\n",this);
+  return S_OK;
+}
+static HRESULT WINAPI IShellView_SelectItem(LPSHELLVIEW this, LPCITEMIDLIST pidlItem, UINT32 uFlags)
+{ FIXME(shell,"(%p)->(pidl=%p, 0x%08x) stub\n",this, pidlItem, uFlags);
+  return E_NOTIMPL;
+}
+static HRESULT WINAPI IShellView_GetItemObject(LPSHELLVIEW this, UINT32 uItem, REFIID riid,LPVOID *ppvOut)
+{ char    xriid[50];
+  WINE_StringFromCLSID((LPCLSID)riid,xriid);
+
+  FIXME(shell,"(%p)->(0x%08x,\n\t%s, %p)stub\n",this, uItem, xriid, ppvOut);
+
+  *ppvOut = NULL;
+  return E_NOTIMPL;
+}
 
 /***********************************************************************
 *   IShellFolder implementation
 */
-/*LPSHELLFOLDER IShellFolder_Constructor();*/
 static HRESULT WINAPI IShellFolder_QueryInterface(LPSHELLFOLDER,REFIID,LPVOID*);
 static ULONG WINAPI IShellFolder_AddRef(LPSHELLFOLDER);
 static ULONG WINAPI IShellFolder_Release(LPSHELLFOLDER);
@@ -507,11 +820,10 @@
 *
 *	  IShellFolder_VTable
 */
-static struct IShellFolder_VTable sfvt = {
-  IShellFolder_QueryInterface,
+static struct IShellFolder_VTable sfvt = 
+{ IShellFolder_QueryInterface,
 	IShellFolder_AddRef,
 	IShellFolder_Release,
-/*	IShellFolder_Initialize,*/
 	IShellFolder_ParseDisplayName,
 	IShellFolder_EnumObjects,
 	IShellFolder_BindToObject,
@@ -522,18 +834,18 @@
   IShellFolder_GetUIObjectOf,
   IShellFolder_GetDisplayNameOf,
   IShellFolder_SetNameOf
+  /*    IShellFolder_Initialize*/
 };
 /**************************************************************************
 *	  IShellFolder_Constructor
 */
 
-LPSHELLFOLDER IShellFolder_Constructor(LPSHELLFOLDER pParent,LPITEMIDLIST pidl) {
-	LPSHELLFOLDER	sf;
+LPSHELLFOLDER IShellFolder_Constructor(LPSHELLFOLDER pParent,LPITEMIDLIST pidl) 
+{ LPSHELLFOLDER    sf;
 	DWORD dwSize=0;
-	WORD wLen;
-	sf = (LPSHELLFOLDER)HeapAlloc(GetProcessHeap(),0,sizeof(IShellFolder));
-	sf->ref		= 1;
-	sf->lpvtbl	= &sfvt;
+  sf=(LPSHELLFOLDER)HeapAlloc(GetProcessHeap(),0,sizeof(IShellFolder));
+  sf->ref=1;
+  sf->lpvtbl=&sfvt;
   sf->mlpszFolder=NULL;
 	sf->mpSFParent=pParent;
 
@@ -548,39 +860,35 @@
 	}
 
   /* keep a copy of the pidl in the instance*/
-	sf->mpidl = sf->pPidlMgr->lpvtbl->fnCopy(sf->pPidlMgr, pidl);
+  sf->mpidl = ILClone(pidl);
 	sf->mpidlNSRoot = NULL;
 	
   if(sf->mpidl)        /* do we have a pidl?*/
-  { /*if(sf->pPidlMgr->lpvtbl->fnIsDesktop(sf->pPidlMgr,sf->mpidl))
-    { sf->pPidlMgr->lpvtbl->fnGetDesktop(sf->pPidlMgr,sf->mpidl);
-    }*/
-    dwSize = 0;
+  { dwSize = 0;
     if(sf->mpSFParent->mlpszFolder)
     { dwSize += strlen(sf->mpSFParent->mlpszFolder) + 1;
     }   
     dwSize += sf->pPidlMgr->lpvtbl->fnGetFolderText(sf->pPidlMgr,sf->mpidl,NULL,0);
-    sf->mlpszFolder = (LPSTR)HeapAlloc(GetProcessHeap(),0,dwSize);
+    sf->mlpszFolder = SHAlloc(dwSize);
     if(sf->mlpszFolder)
-    { *(sf->mlpszFolder) = 0;
+    { *(sf->mlpszFolder)=0x00;
       if(sf->mpSFParent->mlpszFolder)
       {  strcpy(sf->mlpszFolder, sf->mpSFParent->mlpszFolder);
-         wLen = strlen(sf->mlpszFolder);
-         if (wLen && sf->mlpszFolder[wLen-1]!='\\')
-         { sf->mlpszFolder[wLen+0]='\\';
-           sf->mlpszFolder[wLen+1]='\0';
-         }
+         PathAddBackslash (sf->mlpszFolder);
       }
       sf->pPidlMgr->lpvtbl->fnGetFolderText(sf->pPidlMgr, sf->mpidl, sf->mlpszFolder+strlen(sf->mlpszFolder), dwSize-strlen(sf->mlpszFolder));
     }
   }
 	
-	TRACE(shell,"-- (%p)->(%p,%p,%s)\n",sf,pParent, pidl, debugstr_a(sf->mlpszFolder));
+  TRACE(shell,"-- (%p)->(%p,%p,parent=%s)\n",sf,pParent, pidl, debugstr_a(sf->mlpszFolder));
 	return sf;
 }
 /**************************************************************************
- *  IShellFolder::QueryInterface
- */
+*  IShellFolder::QueryInterface
+* PARAMETERS
+*  REFIID riid,        //[in ] Requested InterfaceID
+*  LPVOID* ppvObject)  //[out] Interface* to hold the result
+*/
 static HRESULT WINAPI IShellFolder_QueryInterface(
   LPSHELLFOLDER this, REFIID riid, LPVOID *ppvObj)
 {  char	xriid[50];
@@ -619,19 +927,41 @@
  */
 static ULONG WINAPI IShellFolder_Release(LPSHELLFOLDER this) 
 { TRACE(shell,"(%p)->(count=%lu)\n",this,this->ref);
-	if (!--(this->ref)) {
-		TRACE(shell,"-- destroying IShellFolder(%p)\n",this);
+  if (!--(this->ref)) 
+  { TRACE(shell,"-- destroying IShellFolder(%p)\n",this);
+
 		if (pdesktopfolder==this)
 		{ pdesktopfolder=NULL;
 		  TRACE(shell,"-- destroyed IShellFolder(%p) was Desktopfolder\n",this);
 		}
+    if (this->pPidlMgr)
+    { PidlMgr_Destructor(this->pPidlMgr);
+    }
+    if(this->mpidlNSRoot)
+    { SHFree(this->mpidlNSRoot);
+    }
+    if(this->mpidl)
+    { SHFree(this->mpidl);
+    }
+    if(this->mlpszFolder)
+    { SHFree(this->mlpszFolder);
+    }
+
 		HeapFree(GetProcessHeap(),0,this);
+
 		return 0;
 	}
 	return this->ref;
 }
 /**************************************************************************
 *		IShellFolder_ParseDisplayName
+* PARAMETERS
+*  HWND          hwndOwner,      //[in ] Parent window for any message's
+*  LPBC          pbc,            //[in ] reserved
+*  LPOLESTR      lpszDisplayName,//[in ] "Unicode" displayname.
+*  ULONG*        pchEaten,       //[out] (unicode) characters processed
+*  LPITEMIDLIST* ppidl,          //[out] complex pidl to item
+*  ULONG*        pdwAttributes   //[out] items attributes
 *
 * FIXME: 
 *    pdwAttributes: not used
@@ -640,9 +970,9 @@
 	LPSHELLFOLDER this,
 	HWND32 hwndOwner,
 	LPBC pbcReserved,
-	LPOLESTR32 lpszDisplayName,    /* [in]  name of file or folder*/
-	DWORD *pchEaten,               /* [out] number of chars parsed*/
-	LPITEMIDLIST *ppidl,           /* [out] the pidl*/
+    LPOLESTR32 lpszDisplayName,
+    DWORD *pchEaten,
+    LPITEMIDLIST *ppidl,
 	DWORD *pdwAttributes)
 {	HRESULT        hr=E_OUTOFMEMORY;
   LPITEMIDLIST   pidlFull=NULL, pidlTemp = NULL, pidlOld = NULL;
@@ -661,9 +991,8 @@
     WideCharToLocal32(pszTemp, lpszDisplayName, dwChars);
     if(*pszTemp)
     { if (strcmp(pszTemp,"Desktop")==0)
-		  { pidlFull = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,sizeof(ITEMIDLIST));
+      { pidlFull = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,2);
 			  pidlFull->mkid.cb = 0;
-        pidlFull->mkid.abID[0] = 0;
 			}
 		  else
 			{ pidlFull = this->pPidlMgr->lpvtbl->fnCreateMyComputer(this->pPidlMgr);
@@ -674,8 +1003,8 @@
   
         pidlTemp = this->pPidlMgr->lpvtbl->fnCreateDrive(this->pPidlMgr,szElement);			
         pidlOld = pidlFull;
-        pidlFull = this->pPidlMgr->lpvtbl->fnConcatenate(this->pPidlMgr,pidlFull,pidlTemp);
-  	    this->pPidlMgr->lpvtbl->fnDelete(this->pPidlMgr,pidlOld);
+        pidlFull = ILCombine(pidlFull,pidlTemp);
+        SHFree(pidlOld);
   
   			if(pidlFull)
         { while((pszNext=GetNextElement(pszNext, szElement, MAX_PATH)))
@@ -686,8 +1015,8 @@
             { pidlTemp = this->pPidlMgr->lpvtbl->fnCreateFolder(this->pPidlMgr,szElement);
   					}
             pidlOld = pidlFull;
-            pidlFull = this->pPidlMgr->lpvtbl->fnConcatenate(this->pPidlMgr,pidlFull,pidlTemp);
-            this->pPidlMgr->lpvtbl->fnDelete(this->pPidlMgr,pidlOld);
+            pidlFull = ILCombine(pidlFull,pidlTemp);
+            SHFree(pidlOld);
           }
           hr = S_OK;
         }
@@ -701,6 +1030,10 @@
 
 /**************************************************************************
 *		IShellFolder_EnumObjects
+* PARAMETERS
+*  HWND          hwndOwner,    //[in ] Parent Window
+*  DWORD         grfFlags,     //[in ] SHCONTF enumeration mask
+*  LPENUMIDLIST* ppenumIDList  //[out] IEnumIDList interface
 */
 static HRESULT WINAPI IShellFolder_EnumObjects(
 	LPSHELLFOLDER this,
@@ -727,15 +1060,20 @@
 	LPCITEMIDLIST pidl)
 { TRACE(shell,"(%p)->(pidl=%p)\n",this,pidl);
   if(this->mpidlNSRoot)
-  { this->pPidlMgr->lpvtbl->fnDelete(this->pPidlMgr, this->mpidlNSRoot);
+  { SHFree(this->mpidlNSRoot);
     this->mpidlNSRoot = NULL;
   }
-  this->mpidlNSRoot = this->pPidlMgr->lpvtbl->fnCopy(this->pPidlMgr, pidl);
+  this->mpidlNSRoot=ILClone(pidl);
   return S_OK;
 }
 
 /**************************************************************************
 *		IShellFolder_BindToObject
+* PARAMETERS
+*  LPCITEMIDLIST pidl,       //[in ] complex pidl to open
+*  LPBC          pbc,        //[in ] reserved
+*  REFIID        riid,       //[in ] Initial Interface
+*  LPVOID*       ppvObject   //[out] Interface*
 */
 static HRESULT WINAPI IShellFolder_BindToObject(
 	LPSHELLFOLDER this,
@@ -755,7 +1093,7 @@
   pShellFolder = IShellFolder_Constructor(this, pidl);
   if(!pShellFolder)
     return E_OUTOFMEMORY;
-/*  pShellFolder->lpvtbl->fnInitialize(pShellFolder, this->mpidlNSRoot);*/
+  /*  pShellFolder->lpvtbl->fnInitialize(pShellFolder, this->mpidlNSRoot);*/
   IShellFolder_Initialize(pShellFolder, this->mpidlNSRoot);
   hr = pShellFolder->lpvtbl->fnQueryInterface(pShellFolder, riid, ppvOut);
   pShellFolder->lpvtbl->fnRelease(pShellFolder);
@@ -765,10 +1103,15 @@
 
 /**************************************************************************
 *  IShellFolder_BindToStorage
+* PARAMETERS
+*  LPCITEMIDLIST pidl,       //[in ] complex pidl to store
+*  LPBC          pbc,        //[in ] reserved
+*  REFIID        riid,       //[in ] Initial storage interface 
+*  LPVOID*       ppvObject   //[out] Interface* returned
 */
 static HRESULT WINAPI IShellFolder_BindToStorage(
   	LPSHELLFOLDER this,
-    LPCITEMIDLIST pidl, 
+    LPCITEMIDLIST pidl, /*simple/complex pidl*/
     LPBC pbcReserved, 
     REFIID riid, 
     LPVOID *ppvOut)
@@ -783,29 +1126,36 @@
 
 /**************************************************************************
 *  IShellFolder_CompareIDs
+*
+* PARMETERS
+*  LPARAM        lParam, //[in ] Column?
+*  LPCITEMIDLIST pidl1,  //[in ] simple pidl
+*  LPCITEMIDLIST pidl2)  //[in ] simple pidl
+* FIXME
+*  we have to handle simple pidl's only
 */
 static HRESULT WINAPI  IShellFolder_CompareIDs(
   	LPSHELLFOLDER this,
 		LPARAM lParam, 
-    LPCITEMIDLIST pidl1, 
-    LPCITEMIDLIST pidl2)
+    LPCITEMIDLIST pidl1, /*simple pidl*/
+    LPCITEMIDLIST pidl2) /*simple pidl*/
 { CHAR szString1[MAX_PATH] = "";
   CHAR szString2[MAX_PATH] = "";
   int   nReturn;
   LPCITEMIDLIST  pidlTemp1 = pidl1, pidlTemp2 = pidl2;
 
-  TRACE(shell,"(%p)->(0x%08lx,pidl1=%p,pidl2=%p) stub\n",this,lParam,pidl1,pidl2);
+  TRACE(shell,"(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n",this,lParam,pidl1,pidl2);
 
   /*Special case - If one of the items is a Path and the other is a File, always 
   make the Path come before the File.*/
 
-  //get the last item in each list
+  /* get the last item in each list */
   while((this->pPidlMgr->lpvtbl->fnGetNextItem(this->pPidlMgr,pidlTemp1))->mkid.cb)
     pidlTemp1 = this->pPidlMgr->lpvtbl->fnGetNextItem(this->pPidlMgr,pidlTemp1);
   while((this->pPidlMgr->lpvtbl->fnGetNextItem(this->pPidlMgr,pidlTemp2))->mkid.cb)
     pidlTemp2 = this->pPidlMgr->lpvtbl->fnGetNextItem(this->pPidlMgr,pidlTemp2);
 
-  //at this point, both pidlTemp1 and pidlTemp2 point to the last item in the list
+  /* at this point, both pidlTemp1 and pidlTemp2 point to the last item in the list */
   if(this->pPidlMgr->lpvtbl->fnIsValue(this->pPidlMgr,pidlTemp1) != this->pPidlMgr->lpvtbl->fnIsValue(this->pPidlMgr,pidlTemp2))
   { if(this->pPidlMgr->lpvtbl->fnIsValue(this->pPidlMgr,pidlTemp1))
       return 1;
@@ -831,6 +1181,14 @@
 
 /**************************************************************************
 *	  IShellFolder_CreateViewObject
+* Creates an View Object representing the ShellFolder
+*  IShellView / IShellBrowser / IContextMenu
+*
+* PARAMETERS
+*  HWND    hwndOwner,  // Handle of owner window
+*  REFIID  riid,       // Requested initial interface
+*  LPVOID* ppvObject)  // Resultant interface*
+*
 * NOTES
 *  the same as SHCreateShellFolderViewEx ???
 */
@@ -839,34 +1197,104 @@
 	HWND32 hwndOwner,
 	REFIID riid,
 	LPVOID *ppvOut)
-{	char	xriid[50];
+{ LPSHELLVIEW pShellView;
+  char    xriid[50];
+  HRESULT       hr;
 
 	WINE_StringFromCLSID(riid,xriid);
-	FIXME(shell,"(%p)->(0x%04x,\n\tIID:\t%s,%p),stub!\n",this,hwndOwner,xriid,ppvOut);
+  TRACE(shell,"(%p)->(hwnd=0x%x,\n\tIID:\t%s,%p)\n",this,hwndOwner,xriid,ppvOut);
 	
 	*ppvOut = NULL;
-	return E_NOTIMPL;
+
+  pShellView = IShellView_Constructor(this, this->mpidl);
+  if(!pShellView)
+    return E_OUTOFMEMORY;
+  hr = pShellView->lpvtbl->fnQueryInterface(pShellView, riid, ppvOut);
+  pShellView->lpvtbl->fnRelease(pShellView);
+  TRACE(shell,"-- (%p)->(interface=%p)\n",this, ppvOut);
+  return hr; 
 }
 
 /**************************************************************************
 *  IShellFolder_GetAttributesOf
+*
+* PARAMETERS
+*  UINT            cidl,     //[in ] num elements in pidl array
++  LPCITEMIDLIST*  apidl,    //[in ] simple pidl array 
+*  ULONG*          rgfInOut) //[out] result array  
+*
+* FIXME: quick hack
+*  Note: rgfInOut is documented as being an array of ULONGS.
+*  This does not seem to be the case. Testing this function using the shell to 
+*  call it with cidl > 1 (by deleting multiple items) reveals that the shell
+*  passes ONE element in the array and writing to further elements will
+*  cause the shell to fail later.
 */
 static HRESULT WINAPI IShellFolder_GetAttributesOf(
 	LPSHELLFOLDER this,
 	UINT32 cidl,
-	LPCITEMIDLIST *apidl,
+    LPCITEMIDLIST *apidl, /*simple pidl's*/
 	DWORD *rgfInOut)
-{ FIXME(shell,"(%p)->(%d,%p,%p),stub!\n",this,cidl,apidl,rgfInOut);
-	return E_NOTIMPL;
+{ LPCITEMIDLIST * pidltemp;
+  DWORD i;
+  TRACE(shell,"(%p)->(%d,%p,%p)\n",this,cidl,apidl,rgfInOut);
+
+  pidltemp=apidl;
+  *rgfInOut = 0x00;
+  i=cidl;
+  if ((! cidl )| (!apidl) | (!rgfInOut))
+    return E_INVALIDARG;
+  
+  do
+  { if (*pidltemp)
+    { if (this->pPidlMgr->lpvtbl->fnIsDesktop(this->pPidlMgr, *pidltemp))
+      { *rgfInOut |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR);
+      }
+      else if (this->pPidlMgr->lpvtbl->fnIsMyComputer(this->pPidlMgr, *pidltemp))
+      { *rgfInOut |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
+      }
+      else if (this->pPidlMgr->lpvtbl->fnIsDrive(this->pPidlMgr, *pidltemp))
+      { *rgfInOut |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM);
+      }
+      else if (this->pPidlMgr->lpvtbl->fnIsFolder(this->pPidlMgr, *pidltemp))
+      { *rgfInOut |= (SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER);
+      }
+      else if (this->pPidlMgr->lpvtbl->fnIsValue(this->pPidlMgr, *pidltemp))
+      { *rgfInOut |= (SFGAO_FILESYSTEM);
+      }
+    }
+    pidltemp++;
+    cidl--;
+  } while (cidl > 0 && *pidltemp);
+
+  return S_OK;
 }
 /**************************************************************************
 *  IShellFolder_GetUIObjectOf
+*
+* PARAMETERS
+*  HWND           hwndOwner, //[in ] Parent window for any output
+*  UINT           cidl,      //[in ] array size
+*  LPCITEMIDLIST* apidl,     //[in ] simple pidl array
+*  REFIID         riid,      //[in ] Requested Interface
+*  UINT*          prgfInOut, //[   ] reserved 
+*  LPVOID*        ppvObject) //[out] Resulting Interface
+*
+* NOTES
+*  This function gets asked to return "view objects" for one or more (multiple select)
+*  items:
+*  The viewobject typically is an COM object with one of the following interfaces:
+*  IExtractIcon,IDataObject,IContextMenu
+*  In order to support icon positions in the default Listview your DataObject
+*  must implement the SetData method (in addition to GetData :) - the shell passes
+*  a barely documented "Icon positions" structure to SetData when the drag starts,
+*  and GetData's it if the drop is in another explorer window that needs the positions.
 */
 static HRESULT WINAPI IShellFolder_GetUIObjectOf(
 	LPSHELLFOLDER this,
 	HWND32 hwndOwner,
 	UINT32 cidl, 
-	LPCITEMIDLIST * apidl,
+  LPCITEMIDLIST * apidl, /* simple pidl's*/
   REFIID riid,
 	UINT32 * prgfInOut,
 	LPVOID * ppvOut)
@@ -882,6 +1310,12 @@
 }
 /**************************************************************************
 *  IShellFolder_GetDisplayNameOf
+*  Retrieves the display name for the specified file object or subfolder
+*
+* PARAMETERS
+*  LPCITEMIDLIST pidl,    //[in ] complex pidl to item
+*  DWORD         dwFlags, //[in ] SHGNO formatting flags
+*  LPSTRRET      lpName)  //[out] Returned display name
 *
 * FIXME
 *  if the name is in the pidl the ret value should be a STRRET_OFFSET
@@ -891,7 +1325,7 @@
 
 static HRESULT WINAPI IShellFolder_GetDisplayNameOf( 
   	LPSHELLFOLDER this,
-    LPCITEMIDLIST pidl, 
+    LPCITEMIDLIST pidl, /* simple/complex pidl*/
     DWORD dwFlags, 
     LPSTRRET lpName)
 { CHAR           szText[MAX_PATH];
@@ -904,6 +1338,13 @@
 		
   TRACE(shell,"(%p)->(pidl=%p,0x%08lx,%p)\n",this,pidl,dwFlags,lpName);
 
+  if (!pidl)
+  {  return E_OUTOFMEMORY;
+  } 
+
+  szSpecial[0]=0x00; 
+  szDrive[0]=0x00;
+
   /* test if simple(relative) or complex(absolute) pidl */
   pidlTemp = this->pPidlMgr->lpvtbl->fnGetNextItem(this->pPidlMgr,pidl);
 	if (pidlTemp->mkid.cb==0x00)
@@ -913,11 +1354,9 @@
 	{ strcpy (szText,"Desktop");
 	}
 	else
-	{	szSpecial[0]=0x00;
-	  if (this->pPidlMgr->lpvtbl->fnIsMyComputer(this->pPidlMgr, pidl))
+  { if (this->pPidlMgr->lpvtbl->fnIsMyComputer(this->pPidlMgr, pidl))
     { this->pPidlMgr->lpvtbl->fnGetItemText(this->pPidlMgr, pidl, szSpecial, MAX_PATH);
     }
-		szDrive[0]=0x00;
 	  if (this->pPidlMgr->lpvtbl->fnIsDrive(this->pPidlMgr, pidl))
 		{ pidlTemp = this->pPidlMgr->lpvtbl->fnGetLastItem(this->pPidlMgr,pidl);
   		if (pidlTemp)
@@ -926,7 +1365,7 @@
 		  if ( dwFlags==SHGDN_NORMAL || dwFlags==SHGDN_INFOLDER)
   		{ GetVolumeInformation32A(szTemp,szDrive,MAX_PATH,&dwVolumeSerialNumber,&dwMaximumComponetLength,&dwFileSystemFlags,NULL,0);
 				if (szTemp[2]=='\\')
-				{ szTemp[2]='\0';
+        { szTemp[2]=0x00;
 				}
         strcat (szDrive," (");
 				strcat (szDrive,szTemp);
@@ -952,12 +1391,12 @@
 			  if (bSimplePidl)
 				{ /* if the IShellFolder has parents, get the path from the
 				  parent and add the ItemName*/
+          szText[0]=0x00;
 				  if (this->mlpszFolder && strlen (this->mlpszFolder))
+          { if (strcmp(this->mlpszFolder,"My Computer"))
   			  { strcpy (szText,this->mlpszFolder);
   			    PathAddBackslash (szText);
   			  }
-    			else
-    			{ strcpy(szText,"");
   		  	}
           pidlTemp = this->pPidlMgr->lpvtbl->fnGetLastItem(this->pPidlMgr,pidl);
         	if (pidlTemp)
@@ -978,7 +1417,6 @@
 		if (szText[0]==0x00 && szSpecial[0]!=0x00)
 		{ strcpy(szText,szSpecial);
 		}
- 
   }
   
   TRACE(shell,"-- (%p)->(%s,%s,%s)\n",this,szSpecial,szDrive,szText);
@@ -993,11 +1431,20 @@
 
 /**************************************************************************
 *  IShellFolder_SetNameOf
+*  Changes the name of a file object or subfolder, possibly changing its item
+*  identifier in the process.
+*
+* PARAMETERS
+*  HWND          hwndOwner,  //[in ] Owner window for output
+*  LPCITEMIDLIST pidl,       //[in ] simple pidl of item to change
+*  LPCOLESTR     lpszName,   //[in ] the items new display name
+*  DWORD         dwFlags,    //[in ] SHGNO formatting flags
+*  LPITEMIDLIST* ppidlOut)   //[out] simple pidl returned
 */
 static HRESULT WINAPI IShellFolder_SetNameOf(
   	LPSHELLFOLDER this,
 		HWND32 hwndOwner, 
-    LPCITEMIDLIST pidl, 
+    LPCITEMIDLIST pidl, /*simple pidl*/
     LPCOLESTR32 lpName, 
     DWORD dw, 
     LPITEMIDLIST *pPidlOut)
@@ -1007,30 +1454,37 @@
 }
 
 /**************************************************************************
+* IShellLink Implementation
+*/
+static HRESULT WINAPI IShellLink_QueryInterface(LPSHELLLINK,REFIID,LPVOID*);
+static ULONG WINAPI IShellLink_AddRef(LPSHELLLINK);
+static ULONG WINAPI IShellLink_Release(LPSHELLLINK);
+
+/**************************************************************************
 *	  IShellLink_VTable
 */
 static struct IShellLink_VTable slvt = {
-    (void *)1,
-    (void *)2,
-    (void *)3,
-    (void *)4,
-    (void *)5,
-    (void *)6,
-    (void *)7,
-    (void *)8,
-    (void *)9,
-    (void *)10,
-    (void *)11,
-    (void *)12,
-    (void *)13,
-    (void *)14,
-    (void *)15,
-    (void *)16,
-    (void *)17,
-    (void *)18,
-    (void *)19,
-    (void *)20,
-    (void *)21
+  IShellLink_QueryInterface,
+  IShellLink_AddRef,
+  IShellLink_Release,
+    (void *)0xcafe0004,
+    (void *)0xcafe0005,
+    (void *)0xcafe0006,
+    (void *)0xcafe0007,
+    (void *)0xcafe0008,
+    (void *)0xcafe0009,
+    (void *)0xcafe0010,
+    (void *)0xcafe0011,
+    (void *)0xcafe0012,
+    (void *)0xcafe0013,
+    (void *)0xcafe0014,
+    (void *)0xcafe0015,
+    (void *)0xcafe0016,
+    (void *)0xcafe0017,
+    (void *)0xcafe0018,
+    (void *)0xcafe0019,
+    (void *)0xcafe0020,
+    (void *)0xcafe0021
 };
 
 /**************************************************************************
@@ -1047,6 +1501,53 @@
 }
 
 /**************************************************************************
+ *  IShellLink::QueryInterface
+ */
+static HRESULT WINAPI IShellLink_QueryInterface(
+  LPSHELLLINK this, REFIID riid, LPVOID *ppvObj)
+{  char    xriid[50];
+   WINE_StringFromCLSID((LPCLSID)riid,xriid);
+   TRACE(shell,"(%p)->(\n\tIID:\t%s)\n",this,xriid);
+
+  *ppvObj = NULL;
+
+  if(IsEqualIID(riid, &IID_IUnknown))          /*IUnknown*/
+  { *ppvObj = this; 
+  }
+  else if(IsEqualIID(riid, &IID_IShellLink))  /*IShellLink*/
+  {    *ppvObj = (LPSHELLLINK)this;
+  }   
+
+  if(*ppvObj)
+  { (*(LPSHELLLINK*)ppvObj)->lpvtbl->fnAddRef(this);      
+    TRACE(shell,"-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
+    return S_OK;
+  }
+    TRACE(shell,"-- Interface: E_NOINTERFACE\n");
+  return E_NOINTERFACE;
+}  
+/******************************************************************************
+ * IShellLink_AddRef
+ */
+static ULONG WINAPI IShellLink_AddRef(LPSHELLLINK this)
+{ TRACE(shell,"(%p)->(count=%lu)\n",this,this->ref);
+    return ++(this->ref);
+}
+/******************************************************************************
+ * IClassFactory_Release
+ */
+static ULONG WINAPI IShellLink_Release(LPSHELLLINK this)
+{ TRACE(shell,"(%p)->(count=%lu)\n",this,this->ref);
+  if (!--(this->ref)) 
+  { TRACE(shell,"-- destroying IShellLink(%p)\n",this);
+    HeapFree(GetProcessHeap(),0,this);
+    return 0;
+  }
+  return this->ref;
+}
+
+
+/**************************************************************************
 *	  INTERNAL CLASS pidlmgr
 */
 LPITEMIDLIST PidlMgr_CreateDesktop(LPPIDLMGR);
@@ -1054,10 +1555,8 @@
 LPITEMIDLIST PidlMgr_CreateDrive(LPPIDLMGR,LPCSTR);
 LPITEMIDLIST PidlMgr_CreateFolder(LPPIDLMGR,LPCSTR);
 LPITEMIDLIST PidlMgr_CreateValue(LPPIDLMGR,LPCSTR);
-void PidlMgr_Delete(LPPIDLMGR,LPITEMIDLIST);
+/*void PidlMgr_Delete(LPPIDLMGR,LPITEMIDLIST);*/
 LPITEMIDLIST PidlMgr_GetNextItem(LPPIDLMGR,LPITEMIDLIST);
-LPITEMIDLIST PidlMgr_Copy(LPPIDLMGR,LPITEMIDLIST);
-UINT16 PidlMgr_GetSize(LPPIDLMGR,LPITEMIDLIST);
 BOOL32 PidlMgr_GetDesktop(LPPIDLMGR,LPCITEMIDLIST,LPSTR);
 BOOL32 PidlMgr_GetDrive(LPPIDLMGR,LPCITEMIDLIST,LPSTR,UINT16);
 LPITEMIDLIST PidlMgr_GetLastItem(LPPIDLMGR,LPCITEMIDLIST);
@@ -1073,7 +1572,6 @@
 BOOL32 PidlMgr_GetValueType(LPPIDLMGR,LPCITEMIDLIST,LPCITEMIDLIST,LPDWORD);
 DWORD PidlMgr_GetDataText(LPPIDLMGR,LPCITEMIDLIST,LPCITEMIDLIST,LPSTR,DWORD);
 DWORD PidlMgr_GetPidlPath(LPPIDLMGR,LPCITEMIDLIST,LPSTR,DWORD);
-LPITEMIDLIST PidlMgr_Concatenate(LPPIDLMGR,LPITEMIDLIST,LPITEMIDLIST);
 LPITEMIDLIST PidlMgr_Create(LPPIDLMGR,PIDLTYPE,LPVOID,UINT16);
 DWORD PidlMgr_GetData(LPPIDLMGR,PIDLTYPE,LPCITEMIDLIST,LPVOID,UINT16);
 LPPIDLDATA PidlMgr_GetDataPointer(LPPIDLMGR,LPCITEMIDLIST);
@@ -1085,10 +1583,8 @@
 		PidlMgr_CreateDrive,
     PidlMgr_CreateFolder,
     PidlMgr_CreateValue,
-		PidlMgr_Delete,
+  /*  PidlMgr_Delete,*/
     PidlMgr_GetNextItem,
-    PidlMgr_Copy,
-    PidlMgr_GetSize,
     PidlMgr_GetDesktop,
 		PidlMgr_GetDrive,
     PidlMgr_GetLastItem,
@@ -1104,7 +1600,6 @@
     PidlMgr_GetValueType,
     PidlMgr_GetDataText,
     PidlMgr_GetPidlPath,
-		PidlMgr_Concatenate,
     PidlMgr_Create,
     PidlMgr_GetData,
     PidlMgr_GetDataPointer,
@@ -1132,6 +1627,7 @@
 
 /**************************************************************************
  *  PidlMgr_CreateDesktop()
+ *  PidlMgr_CreateMyComputer()
  *  PidlMgr_CreateDrive()
  *  PidlMgr_CreateFolder() 
  *  PidlMgr_CreateValue()
@@ -1142,7 +1638,7 @@
 }
 LPITEMIDLIST PidlMgr_CreateMyComputer(LPPIDLMGR this)
 { TRACE(shell,"(%p)->()\n",this);
-  return PidlMgr_Create(this,PT_MYCOMP, (void *)"My Computer", sizeof("My Computer"));
+  return PidlMgr_Create(this,PT_MYCOMP, (void *)"My Computer", strlen ("My Computer")+1);
 }
 LPITEMIDLIST PidlMgr_CreateDrive(LPPIDLMGR this, LPCSTR lpszNew)
 { char sTemp[4];
@@ -1164,11 +1660,11 @@
  *  PidlMgr_Delete()
  *  Deletes a PIDL
  */
-void PidlMgr_Delete(LPPIDLMGR this,LPITEMIDLIST pidl)
+/*void PidlMgr_Delete(LPPIDLMGR this,LPITEMIDLIST pidl)
 { TRACE(shell,"(%p)->(pidl=%p)\n",this,pidl);
   HeapFree(GetProcessHeap(),0,pidl);
 }
-
+*/
 /**************************************************************************
  *  PidlMgr_GetNextItem()
  */
@@ -1185,52 +1681,6 @@
   {  return (NULL);
 	}
 }
-
-/**************************************************************************
- *  PidlMgr_Copy()
- */
-LPITEMIDLIST PidlMgr_Copy(LPPIDLMGR this, LPITEMIDLIST pidlSource)
-{ LPITEMIDLIST pidlTarget = NULL;
-  UINT16 cbSource = 0;
-
-	TRACE(shell,"(%p)->(pidl=%p)\n",this,pidlSource);
-
-  if(NULL == pidlSource)
- 	{  TRACE(shell,"-- (%p)->(%p)\n",this,pidlSource);
-     return (NULL);
-	}
-
-  cbSource = PidlMgr_GetSize(this, pidlSource);
-  pidlTarget = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,cbSource);
-  if(!pidlTarget)
-  { return (NULL);
-	}
-
-  memcpy(pidlTarget, pidlSource, cbSource);
-
-	TRACE(shell,"-- (%p)->(pidl=%p to new pidl=%p)\n",this,pidlSource,pidlTarget);
-  return pidlTarget;
-}
-/**************************************************************************
- *  PidlMgr_GetSize()
- *  calculates the size of the complete pidl
- */
-UINT16 PidlMgr_GetSize(LPPIDLMGR this, LPITEMIDLIST pidl)
-{ UINT16 cbTotal = 0;
-  LPITEMIDLIST pidlTemp = pidl;
-
-  TRACE(shell,"(%p)->(pidl=%p)\n",this,pidl);
-  if(pidlTemp)
-  { while(pidlTemp->mkid.cb)
-    { cbTotal += pidlTemp->mkid.cb;
-      pidlTemp = PidlMgr_GetNextItem(this, pidlTemp);
-    }  
-    //add the size of the NULL terminating ITEMIDLIST
-    cbTotal += sizeof(ITEMIDLIST);
-  }
-	TRACE(shell,"-- size %u\n",cbTotal);
-  return (cbTotal);
-}
 /**************************************************************************
  *  PidlMgr_GetDesktop()
  * 
@@ -1252,7 +1702,7 @@
   if(PidlMgr_IsMyComputer(this,pidl))
   { pidlTemp = PidlMgr_GetNextItem(this,pidl);
 	}
-	else if (PidlMgr_IsDrive(this,pidlTemp))
+  else if (pidlTemp && PidlMgr_IsDrive(this,pidlTemp))
   { return (BOOL32)PidlMgr_GetData(this,PT_DRIVE, pidlTemp, (LPVOID)pOut, uSize);
 	}
 	return FALSE;
@@ -1296,12 +1746,20 @@
 */
 BOOL32 PidlMgr_IsDesktop(LPPIDLMGR this,LPCITEMIDLIST pidl)
 { TRACE(shell,"%p->(%p)\n",this,pidl);
+
+  if (! pidl)
+    return FALSE;
+
   return (  pidl->mkid.cb == 0x00 );
 }
 
 BOOL32 PidlMgr_IsMyComputer(LPPIDLMGR this,LPCITEMIDLIST pidl)
 { LPPIDLDATA  pData;
   TRACE(shell,"%p->(%p)\n",this,pidl);
+
+  if (! pidl)
+    return FALSE;
+
   pData = PidlMgr_GetDataPointer(this,pidl);
   return (PT_MYCOMP == pData->type);
 }
@@ -1309,6 +1767,10 @@
 BOOL32 PidlMgr_IsDrive(LPPIDLMGR this,LPCITEMIDLIST pidl)
 { LPPIDLDATA  pData;
   TRACE(shell,"%p->(%p)\n",this,pidl);
+
+  if (! pidl)
+    return FALSE;
+
   pData = PidlMgr_GetDataPointer(this,pidl);
   return (PT_DRIVE == pData->type);
 }
@@ -1316,6 +1778,10 @@
 BOOL32 PidlMgr_IsFolder(LPPIDLMGR this,LPCITEMIDLIST pidl)
 { LPPIDLDATA  pData;
   TRACE(shell,"%p->(%p)\n",this,pidl);
+
+  if (! pidl)
+    return FALSE;
+
   pData = PidlMgr_GetDataPointer(this,pidl);
   return (PT_FOLDER == pData->type);
 }
@@ -1323,6 +1789,10 @@
 BOOL32 PidlMgr_IsValue(LPPIDLMGR this,LPCITEMIDLIST pidl)
 { LPPIDLDATA  pData;
   TRACE(shell,"%p->(%p)\n",this,pidl);
+
+  if (! pidl)
+    return FALSE;
+
   pData = PidlMgr_GetDataPointer(this,pidl);
   return (PT_VALUE == pData->type);
 }
@@ -1366,6 +1836,7 @@
 
   if(PidlMgr_IsMyComputer(this,pidl))
   { pidlTemp = PidlMgr_GetNextItem(this,pidl);
+    TRACE(shell,"-- (%p)->skip My Computer\n",this);
 	}
   else
   { pidlTemp = (LPITEMIDLIST)pidl;
@@ -1516,15 +1987,7 @@
 
   FIXME(shell,"(%p)->(pidl=%p pidl=%p) stub\n",this,pidlPath,pidlValue);
 
-  if(!lpszOut)
-  { return FALSE;
-	}
-
-  if(!pidlPath)
-  { return FALSE;
-	}
-
-  if(!pidlValue)
+  if(!lpszOut || !pidlPath || !pidlValue)
   { return FALSE;
 	}
 
@@ -1601,45 +2064,7 @@
   return strlen(lpszOut);
 
 }
-/**************************************************************************
- * PidlMgr_Concatenate()
- * Create a new PIDL by combining two existing PIDLs.
- */  
-LPITEMIDLIST PidlMgr_Concatenate(
-    LPPIDLMGR this,
-		LPITEMIDLIST pidl1,
-		LPITEMIDLIST pidl2)
-{ LPITEMIDLIST   pidlNew;
-  UINT32         cb1 = 0, cb2 = 0;
 
-  TRACE(shell,"(%p)->(%p,%p)\n",this,pidl1,pidl2);
-
-  if(!pidl1 && !pidl2)
-  {  return NULL;
-	}
-
-  if(!pidl1)
-  { pidlNew = PidlMgr_Copy(this,pidl2);
-    return pidlNew;
-  }
-
-  if(!pidl2)
-  { pidlNew = PidlMgr_Copy(this,pidl1);
-    return pidlNew;
-  }
-
-  cb1 = PidlMgr_GetSize(this,pidl1) - sizeof(ITEMIDLIST);
-  cb2 = PidlMgr_GetSize(this,pidl2);
-
-  pidlNew = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,cb1+cb2);
-
-  if(pidlNew)
-  { memcpy(pidlNew, pidl1, cb1);
-    memcpy(((LPBYTE)pidlNew) + cb1, pidl2, cb2);
-  }
-  TRACE(shell,"-- (%p)-> (new pidl=%p)\n",this,pidlNew);
-	return pidlNew;
-}
 /**************************************************************************
  *  PidlMgr_Create()
  *  Creates a new PIDL
@@ -1657,44 +2082,45 @@
   TRACE(shell,"(%p)->(%x %p %x)\n",this,type,pIn,uInSize);
 
   if ( type == PT_DESKTOP)
-	{   pidlOut = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,sizeof(ITEMIDLIST));
-  		memset(pidlOut, 0x00, sizeof(ITEMIDLIST));
+  {   pidlOut = SHAlloc(2);
+      pidlOut->mkid.cb=0x0000;
+      return pidlOut;
 	}
 
   if (! pIn)
 	{ return NULL;
 	}	
-  uSize = sizeof(ITEMIDLIST) + (sizeof(PIDLTYPE)) + uInSize;
 
-  /* Allocate the memory, adding an additional ITEMIDLIST for the NULL terminating 
-  ID List. */
-  pidlOut = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,uSize + sizeof(ITEMIDLIST));
-	memset(pidlOut, 0xAA, uSize);
+  uSize = 2 + (sizeof(PIDLTYPE)) + uInSize + 2;  /* cb + PIDLTYPE + uInSize +2 */
+  pidlOut = SHAlloc(uSize);
   pidlTemp = pidlOut;
   if(pidlOut)
-  { pidlTemp->mkid.cb = uSize;
-    pData = PidlMgr_GetDataPointer(this,pidlTemp);
+  { pidlTemp->mkid.cb = uSize - 2;
+    pData =(LPPIDLDATA) &(pidlTemp->mkid.abID[0]);
     pData->type = type;
     switch(type)
-    { case PT_MYCOMP:  memcpy(pData->szText, pIn, uInSize);
+    { case PT_MYCOMP:
+        memcpy(pData->szText, pIn, uInSize);
                        TRACE(shell,"- (%p)->create My Computer: %s\n",this,debugstr_a(pData->szText));
                        break;
-			case PT_DRIVE:	 memcpy(pData->szText, pIn, uInSize);
+      case PT_DRIVE:
+        memcpy(pData->szText, pIn, uInSize);
                        TRACE(shell,"- (%p)->create Drive: %s\n",this,debugstr_a(pData->szText));
 											 break;
       case PT_FOLDER:
-      case PT_VALUE:   memcpy(pData->szText, pIn, uInSize);
+      case PT_VALUE:   
+        memcpy(pData->szText, pIn, uInSize);
                        TRACE(shell,"- (%p)->create Value: %s\n",this,debugstr_a(pData->szText));
 											 break;
-		  default:         FIXME(shell,"- (%p) wrong argument\n",this);
+      default: 
+        FIXME(shell,"- (%p) wrong argument\n",this);
 			                 break;
     }
    
     pidlTemp = PidlMgr_GetNextItem(this,pidlTemp);
-    pidlTemp->mkid.cb = 0;
-    pidlTemp->mkid.abID[0] = 0;
+  pidlTemp->mkid.cb = 0x00;
   }
-	TRACE(shell,"-- (%p)->(pidl=%p)\n",this,pidlOut);
+  TRACE(shell,"-- (%p)->(pidl=%p, size=%u)\n",this,pidlOut,uSize-2);
   return pidlOut;
 }
 /**************************************************************************
@@ -1779,12 +2205,11 @@
   { return FALSE;
 	}
 
-  *ppidlValue = PidlMgr_Copy(this,*ppidlValue);
-  *ppidlPath = PidlMgr_Copy(this,pidlFQ);
+  *ppidlValue = ILClone(*ppidlValue);
+  *ppidlPath = ILClone(pidlFQ);
 
   pidlTemp = PidlMgr_GetLastItem(this,*ppidlPath);
-  pidlTemp->mkid.cb = 0;
-  pidlTemp->mkid.abID[0] = 0;
+  pidlTemp->mkid.cb = 0x00;
 
   return TRUE;
 }
diff --git a/ole/nls/deu.nls b/ole/nls/deu.nls
index 21bf71e..7b99de7 100644
--- a/ole/nls/deu.nls
+++ b/ole/nls/deu.nls
@@ -99,8 +99,8 @@
 LOCVAL(LOCALE_SABBREVMONTHNAME12,"Dez")
 LOCVAL(LOCALE_SABBREVMONTHNAME13,"")
 
-/* LOCVAL(LOCALE_SPOSITIVESIGN) */
-/* LOCVAL(LOCALE_SNEGATIVESIGN) */
+LOCVAL(LOCALE_SPOSITIVESIGN, "")
+LOCVAL(LOCALE_SNEGATIVESIGN, "-")
 /* LOCVAL(LOCALE_IPOSSIGNPOSN) */
 /* LOCVAL(LOCALE_INEGSIGNPOSN) */
 /* LOCVAL(LOCALE_IPOSSYMPRECEDES) */
diff --git a/ole/ole2nls.c b/ole/ole2nls.c
index 7d18e99..e1684ea 100644
--- a/ole/ole2nls.c
+++ b/ole/ole2nls.c
@@ -1611,7 +1611,7 @@
  19,  /* ÿ - 255 */
 } ;
 
-static int is_punctuation(unsigned char c) 
+static int OLE2NLS_isPunctuation(unsigned char c) 
 {
   /* "punctuation character" in this context is a character which is 
      considered "less important" during word sort comparison.
@@ -1639,17 +1639,24 @@
  *    Error : 0.
  *    Success : length of the result string.
  *
- * REMARKS
+ * NOTES
  *    If called with scrlen = -1, the function will compute the length
  *      of the 0-terminated string strsrc by itself.      
  * 
  *    If called with dstlen = 0, returns the buffer length that 
  *      would be required.
+ *
+ *    NORM_IGNOREWIDTH means to compare ASCII and Unicode characters
+ *    as if they are equal.  Since Wine separates ASCII and Unicode into
+ *    separate functions, we shouldn't have to do anything for this flag.
+ *    I added it to the list of flags that don't need a fixme message
+ *    to make MS Word 95 not print several thousand fixme messages for 
+ *    this function.
  */
 INT32 WINAPI LCMapString32A(
 	LCID lcid /* locale identifier created with MAKELCID; 
-		     LOCALE_SYSTEM_DEFAULT and LOCALE_USER_DEFAULT are predefined
-		     values. */,
+		     LOCALE_SYSTEM_DEFAULT and LOCALE_USER_DEFAULT are 
+                     predefined values. */,
 	DWORD mapflags /* flags */,
 	LPCSTR srcstr  /* source buffer */,
 	INT32 srclen   /* source length */,
@@ -1663,20 +1670,22 @@
 
   if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) )
   {
+    ERR(ole, "(src=%s,dest=%s): Invalid NULL string\n", srcstr, dststr);
     SetLastError(ERROR_INVALID_PARAMETER);
     return 0;
   }
-  if (srclen==-1) 
+  if (srclen == -1) 
     srclen = lstrlen32A(srcstr) + 1 ;    /* (include final '\0') */
 
   if (mapflags & ~ ( LCMAP_UPPERCASE | LCMAP_LOWERCASE | LCMAP_SORTKEY |
-		     NORM_IGNORECASE | NORM_IGNORENONSPACE | SORT_STRINGSORT) )
+		     NORM_IGNORECASE | NORM_IGNORENONSPACE | SORT_STRINGSORT |
+		     NORM_IGNOREWIDTH) )
   {
     FIXME(string,"(0x%04lx,0x%08lx,%p,%d,%p,%d): "
 	  "unimplemented flags: 0x%08lx\n",
 	  lcid,mapflags,srcstr,srclen,dststr,dstlen,mapflags);
   }
-  
+
   if ( !(mapflags & LCMAP_SORTKEY) )
   {
     int (*f)(int)=identity; 
@@ -1714,7 +1723,7 @@
       unsigned char source_char = srcstr[i];
       if (source_char!='\0') 
       {
-	if (flag_stringsort || !is_punctuation(source_char))
+	if (flag_stringsort || !OLE2NLS_isPunctuation(source_char))
 	{
 	  unicode_len++;
 	  if ( LCM_Unicode_LUT[-2+2*source_char] & ~15 )
@@ -1780,7 +1789,7 @@
 	type = LCM_Unicode_LUT[-2+2*source_char];
 	longcode = type >> 4;
 	type &= 15;
-	if (!flag_stringsort && is_punctuation(source_char)) 
+	if (!flag_stringsort && OLE2NLS_isPunctuation(source_char)) 
 	{
 	  UINT16 encrypted_location = (1<<15) + 7 + 4*count;
 	  *delayed_punctuation_component++ = (unsigned char) (encrypted_location>>8);
@@ -1829,6 +1838,15 @@
   }
 }
 		     
+/*************************************************************************
+ *              LCMapString32W                [KERNEL32.493]
+ *
+ * Convert a string, or generate a sort key from it.
+ *
+ * NOTE
+ *
+ * See LCMapString32A for documentation
+ */
 INT32 WINAPI LCMapString32W(
 	LCID lcid,DWORD mapflags,LPCWSTR srcstr,INT32 srclen,LPWSTR dststr,
 	INT32 dstlen)
@@ -1840,6 +1858,7 @@
 
   if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) )
   {
+    ERR(ole, "(src=%p,dst=%p): Invalid NULL string\n", srcstr, dststr);
     SetLastError(ERROR_INVALID_PARAMETER);
     return 0;
   }
@@ -1880,13 +1899,34 @@
 }
 
 /***********************************************************************
- *           CompareString32A   (KERNEL32.29)
+ * CompareString32A [KERNEL32.29] Compares two strings using locale
+ *
+ * RETURNS
+ *
+ * success: CSTR_LESS_THAN, CSTR_EQUAL, CSTR_GREATER_THAN
+ * failure: 0
+ *
+ * NOTES
+ *
+ * Defaults to a word sort, but uses a string sort if
+ * SORT_STRINGSORT is set.
+ * Calls SetLastError for ERROR_INVALID_FLAGS, ERROR_INVALID_PARAMETER.
+ * 
+ * BUGS
+ *
  * This implementation ignores the locale
+ *
  * FIXME
- * Moreover it is quite inefficient. FIXME too!
+ * 
+ * Quite inefficient.
  */
-UINT32 WINAPI CompareString32A(DWORD lcid, DWORD fdwStyle, 
-                               LPCSTR s1, DWORD l1, LPCSTR s2,DWORD l2)
+UINT32 WINAPI CompareString32A(
+    DWORD lcid,     /* locale ID */
+    DWORD fdwStyle, /* comparison-style options */
+    LPCSTR s1,      /* first string */
+    DWORD l1,       /* length of first string */
+    LPCSTR s2,      /* second string */
+    DWORD l2)       /* length of second string */
 {
   int mapstring_flags;
   int len1,len2;
@@ -1897,6 +1937,7 @@
 
   if ( (s1==NULL) || (s2==NULL) )
   {    
+    ERR(ole, "(s1=%s,s2=%s): Invalid NULL string\n", s1, s2);
     SetLastError(ERROR_INVALID_PARAMETER);
     return 0;
   }
@@ -1915,15 +1956,25 @@
   sk2 = (LPSTR)HeapAlloc(GetProcessHeap(),0,len2);
   if ( (!LCMapString32A(lcid,mapstring_flags,s1,l1,sk1,len1))
 	 || (!LCMapString32A(lcid,mapstring_flags,s2,l2,sk2,len2)) )
-  { ERR(ole,"Bug in LCmapString32A.\n");
+  {
+    ERR(ole,"Bug in LCmapString32A.\n");
     result = 0;
   }
   else
-  { result = strcmp(sk1,sk2)+2;
+  {
+    /* strcmp doesn't necessarily return -1, 0, or 1 */
+    result = strcmp(sk1,sk2);
   }
   HeapFree(GetProcessHeap(),0,sk1);
   HeapFree(GetProcessHeap(),0,sk2);
-  return result;
+
+  if (result < 0)
+    return 1;
+  if (result == 0)
+    return 2;
+
+  /* must be greater, if we reach this point */
+  return 3;
 }
 
 /***********************************************************************
diff --git a/relay32/builtin32.c b/relay32/builtin32.c
index e5f9695..5ea46b4 100644
--- a/relay32/builtin32.c
+++ b/relay32/builtin32.c
@@ -170,7 +170,9 @@
     nt->OptionalHeader.SizeOfImage                 = size;
     nt->OptionalHeader.SizeOfHeaders               = (BYTE *)exp - addr;
     nt->OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
-
+    if (dll->descr->dllentrypoint) 
+        nt->OptionalHeader.AddressOfEntryPoint = (DWORD)dll->descr->dllentrypoint - (DWORD)addr;
+    
     /* Build the export directory */
 
     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
diff --git a/relay32/comctl32.spec b/relay32/comctl32.spec
index 87e4439..8c7aa82 100644
--- a/relay32/comctl32.spec
+++ b/relay32/comctl32.spec
@@ -1,5 +1,6 @@
 name	comctl32
 type	win32
+init	ComCtl32LibMain
 
 # Functions exported by the Win95 comctl32.dll 
 # (these need to have these exact ordinals, because some win95 dlls 
diff --git a/relay32/crtdll.spec b/relay32/crtdll.spec
index 95a5555..8d15fc7 100644
--- a/relay32/crtdll.spec
+++ b/relay32/crtdll.spec
@@ -100,8 +100,8 @@
  96 stub _filelength
  97 stub _fileno
  98 stub _findclose
- 99 stub _findfirst
-100 stub _findnext
+ 99 cdecl _findfirst(str ptr) CRTDLL__findfirst
+100 cdecl _findnext(long ptr) CRTDLL__findnext
 101 stub _finite
 102 stub _flsbuf
 103 stub _flushall
@@ -112,7 +112,7 @@
 108 stub _fputchar
 109 stub _fputwchar
 110 stub _fsopen
-111 stub _fstat
+111 cdecl _fstat(long ptr) CRTDLL__fstat
 112 stub _ftime
 113 cdecl _ftol(double) CRTDLL__ftol
 114 cdecl _fullpath(ptr str long) CRTDLL__fullpath
@@ -257,7 +257,7 @@
 253 stub _putenv
 254 stub _putw
 255 stub _pwctype_dll
-256 stub _read
+256 cdecl _read(long ptr long) CRTDLL__read
 257 stub _rmdir
 258 stub _rmtmp
 259 cdecl _rotl (long long) CRTDLL__rotl
@@ -380,7 +380,7 @@
 376 stub fputwc
 377 cdecl fread(ptr long long ptr) CRTDLL_fread
 378 cdecl free(ptr) CRTDLL_free
-379 stub freopen
+379 cdecl freopen(str str ptr) CRTDLL_freopen
 380 cdecl frexp(double ptr) frexp
 381 varargs fscanf() CRTDLL_fscanf
 382 cdecl fseek(ptr long long) CRTDLL_fseek
diff --git a/relay32/gdi32.spec b/relay32/gdi32.spec
index 8f11c9c..087e09b 100644
--- a/relay32/gdi32.spec
+++ b/relay32/gdi32.spec
@@ -182,7 +182,7 @@
 178 stdcall GetEnhMetaFileHeader(long long ptr) GetEnhMetaFileHeader
 179 stub GetEnhMetaFilePaletteEntries
 180 stub GetEnhMetaFileW
-181 stub GetFontData
+181 stdcall GetFontData(long long long ptr long) GetFontData32
 182 stdcall GetFontLanguageInfo(long) GetFontLanguageInfo32
 183 stub GetFontResourceInfo
 184 stub GetFontResourceInfoW
diff --git a/relay32/kernel32.spec b/relay32/kernel32.spec
index 65f2dd8..8576577 100644
--- a/relay32/kernel32.spec
+++ b/relay32/kernel32.spec
@@ -97,16 +97,16 @@
  83 stub K32RtlLargeIntegerSubtract
  84 stub K32RtlConvertLongToLargeInteger
  85 stub K32RtlConvertUlongToLargeInteger
- 86 stub _KERNEL32_86
+ 86 stdcall _KERNEL32_86(ptr) _KERNEL32_86
  87 stdcall SSOnBigStack() SSOnBigStack
  88 varargs SSCall() SSCall
  89 register FT_PrologPrime() FT_PrologPrime
  90 register QT_ThunkPrime() QT_ThunkPrime
  91 stub PK16FNF
  92 stdcall GetPK16SysVar() GetPK16SysVar
- 93 stdcall GetpWin16Lock(ptr) GetpWin16Lock
- 94 stub _CheckNotSysLevel
- 95 stub _ConfirmSysLevel
+ 93 stdcall GetpWin16Lock(ptr) GetpWin16Lock32
+ 94 stdcall _CheckNotSysLevel(ptr) _CheckNotSysLevel
+ 95 stdcall _ConfirmSysLevel(ptr) _ConfirmSysLevel
  96 stdcall _ConfirmWin16Lock() _ConfirmWin16Lock
  97 stdcall _EnterSysLevel(ptr) _EnterSysLevel
  98 stdcall _LeaveSysLevel(ptr) _LeaveSysLevel
diff --git a/relay32/mpr.spec b/relay32/mpr.spec
index 760f1de..d1768b5 100644
--- a/relay32/mpr.spec
+++ b/relay32/mpr.spec
@@ -9,9 +9,9 @@
 0006 stub MPR_6
 0007 stub MPR_7
 0008 stub MPR_8
-0009 stub MPR_9
-0010 stub DllCanUnloadNow
-0011 stub DllGetClassObject
+0009 stub DllCanUnloadNow
+0010 stub DllGetClassObject
+0011 stub MPR_11
 0012 stub MPR_12
 0013 stub MPR_13
 0014 stub MPR_14
@@ -25,89 +25,89 @@
 0022 stdcall MPR_22(long) _MPR_22
 0023 stub MPR_23
 0024 stub MPR_24
-0025 stdcall MPR_25(str long) _MPR_25
-	0026 stdcall MultinetGetConnectionPerformanceA(ptr ptr) MultinetGetConnectionPerformance32A
-0027 stub MultinetGetConnectionPerformanceW
-0028 stdcall MultinetGetErrorTextA(long ptr long)MultinetGetErrorText32A
-0029 stdcall MultinetGetErrorTextW(long ptr long)MultinetGetErrorText32W
-0030 stub NPSAuthenticationDialogA
-0031 stub NPSCopyStringA
-0032 stub NPSDeviceGetNumberA
-0033 stub NPSDeviceGetStringA
-0034 stub NPSGetProviderHandleA
-0035 stub NPSGetProviderNameA
-0036 stub NPSGetSectionNameA
-0037 stub NPSNotifyGetContextA
-0038 stub NPSNotifyRegisterA
-0039 stub NPSSetCustomTextA
-0040 stub NPSSetExtendedErrorA
-0041 stub PwdChangePasswordA
-0042 stub PwdChangePasswordW
-0043 stub PwdGetPasswordStatusA
-0044 stub PwdGetPasswordStatusW
-0045 stub PwdSetPasswordStatusA
-0046 stub PwdSetPasswordStatusW
-0047 stdcall WNetAddConnection2A(ptr str str long) WNetAddConnection2_32A
-0048 stdcall WNetAddConnection2W(ptr wstr wstr long) WNetAddConnection2_32W
-0049 stdcall WNetAddConnection3A(long ptr str str long) WNetAddConnection3_32A
-0050 stdcall WNetAddConnection3W(long ptr wstr wstr long) WNetAddConnection3_32W
-0051 stdcall WNetAddConnectionA(str str str) WNetAddConnection32A
-0052 stdcall WNetAddConnectionW(wstr wstr wstr) WNetAddConnection32W
-0053 stdcall WNetCachePassword(str long str long long) WNetCachePassword
-0054 stub WNetCancelConnection2A
-0055 stub WNetCancelConnection2W
-0056 stub WNetCancelConnectionA
-0057 stub WNetCancelConnectionW
-0058 stub WNetCloseEnum
-0059 stdcall WNetConnectionDialog1A(ptr) WNetConnectionDialog1_32A
-0060 stdcall WNetConnectionDialog1W(ptr) WNetConnectionDialog1_32W
-0061 stdcall WNetConnectionDialog1(long long) WNetConnectionDialog1_32
-0062 stub WNetDisconnectDialog1A
-0063 stub WNetDisconnectDialog1W
-0064 stub WNetDisconnectDialog
-0065 stub WNetEnumCachedPasswords
-0066 stub WNetEnumResourceA
-0067 stub WNetEnumResourceW
-0068 stub WNetFormatNetworkNameA
-0069 stub WNetFormatNetworkNameW
-0070 stdcall WNetGetCachedPassword(ptr long ptr ptr long) WNetGetCachedPassword
-0071 stdcall WNetGetConnectionA(str ptr ptr) WNetGetConnection32A
-0072 stdcall WNetGetConnectionW(wstr ptr ptr) WNetGetConnection32W
-0073 stub WNetGetHomeDirectoryA
-0074 stub WNetGetHomeDirectoryW
-0075 stub WNetGetLastErrorA
-0076 stub WNetGetLastErrorW
-0077 stub WNetGetNetworkInformationA
-0078 stub WNetGetNetworkInformationW
-0079 stub WNetGetProviderNameA
-0080 stub WNetGetProviderNameW
-0081 stdcall WNetGetResourceInformationA(ptr ptr ptr ptr) WNetGetResourceInformation32A
-0082 stub WNetGetResourceInformationW
-0083 stub WNetGetResourceParentA
-0084 stub WNetGetResourceParentW
-0085 stub WNetGetUniversalNameA
-0086 stub WNetGetUniversalNameW
-0087 stub WNetGetUserA
-0088 stub WNetGetUserW
-0089 stub WNetLogoffA
-0090 stub WNetLogoffW
-0091 stub WNetLogonA
-0092 stub WNetLogonW
-0093 stdcall WNetOpenEnumA(long long long ptr ptr) WNetOpenEnum32A
-0094 stub WNetOpenEnumW
-0095 stub WNetRemoveCachedPassword
-0096 stub WNetRestoreConnectionA
-0097 stub WNetRestoreConnectionW
-0098 stub WNetSetConnectionA
-0099 stub WNetSetConnectionW
-0100 stub WNetUseConnectionA
-0101 stub WNetUseConnectionW
-0102 stub WNetVerifyPasswordA
-0103 stub WNetVerifyPasswordW 
-#additions
-0104 stub WNetRestoreConnection
-0105 stub WNetLogonNotify
-0106 stub WNetPasswordChangeNotify
-0107 stub WNetGetPropertyTextA
-0108 stub WNetPropertyDialogA
-0109 stub WNetGetDirectoryTypeA
+0025 stdcall MultinetGetConnectionPerformanceA(ptr ptr) MultinetGetConnectionPerformance32A
+0026 stub MultinetGetConnectionPerformanceW
+0027 stdcall MultinetGetErrorTextA(long ptr long)MultinetGetErrorText32A
+0028 stdcall MultinetGetErrorTextW(long ptr long)MultinetGetErrorText32W
+0029 stub NPSAuthenticationDialogA
+0030 stub NPSCopyStringA
+0031 stub NPSDeviceGetNumberA
+0032 stub NPSDeviceGetStringA
+0033 stub NPSGetProviderHandleA
+0034 stub NPSGetProviderNameA
+0035 stub NPSGetSectionNameA
+0036 stub NPSNotifyGetContextA
+0037 stub NPSNotifyRegisterA
+0038 stub NPSSetCustomTextA
+0039 stub NPSSetExtendedErrorA
+0040 stub PwdChangePasswordA
+0041 stub PwdChangePasswordW
+0042 stub PwdGetPasswordStatusA
+0043 stub PwdGetPasswordStatusW
+0044 stub PwdSetPasswordStatusA
+0045 stub PwdSetPasswordStatusW
+0046 stdcall WNetAddConnection2A(ptr str str long) WNetAddConnection2_32A
+0047 stdcall WNetAddConnection2W(ptr wstr wstr long) WNetAddConnection2_32W
+0048 stdcall WNetAddConnection3A(long ptr str str long) WNetAddConnection3_32A
+0049 stdcall WNetAddConnection3W(long ptr wstr wstr long) WNetAddConnection3_32W
+0050 stdcall WNetAddConnectionA(str str str) WNetAddConnection32A
+0051 stdcall WNetAddConnectionW(wstr wstr wstr) WNetAddConnection32W
+0052 stdcall WNetCachePassword(str long str long long) WNetCachePassword
+0053 stub WNetCancelConnection2A
+0054 stub WNetCancelConnection2W
+0055 stub WNetCancelConnectionA
+0056 stub WNetCancelConnectionW
+0057 stub WNetCloseEnum
+0058 stdcall WNetConnectionDialog1A(ptr) WNetConnectionDialog1_32A
+0059 stdcall WNetConnectionDialog1W(ptr) WNetConnectionDialog1_32W
+0060 stdcall WNetConnectionDialog(long long) WNetConnectionDialog_32
+0061 stub WNetDisconnectDialog1A
+0062 stub WNetDisconnectDialog1W
+0063 stub WNetDisconnectDialog
+0064 stub WNetEnumCachedPasswords
+0065 stub WNetEnumResourceA
+0066 stub WNetEnumResourceW
+0067 stub WNetFormatNetworkNameA
+0068 stub WNetFormatNetworkNameW
+0069 stdcall WNetGetCachedPassword(ptr long ptr ptr long) WNetGetCachedPassword
+0070 stdcall WNetGetConnectionA(str ptr ptr) WNetGetConnection32A
+0071 stdcall WNetGetConnectionW(wstr ptr ptr) WNetGetConnection32W
+0072 stub WNetGetHomeDirectoryA
+0073 stub WNetGetHomeDirectoryW
+0074 stub WNetGetLastErrorA
+0075 stub WNetGetLastErrorW
+0076 stub WNetGetNetworkInformationA
+0077 stub WNetGetNetworkInformationW
+0078 stub WNetGetProviderNameA
+0079 stub WNetGetProviderNameW
+0080 stdcall WNetGetResourceInformationA(ptr ptr ptr ptr) WNetGetResourceInformation32A
+0081 stub WNetGetResourceInformationW
+0082 stub WNetGetResourceParentA
+0083 stub WNetGetResourceParentW
+0084 stub WNetGetUniversalNameA
+0085 stub WNetGetUniversalNameW
+0086 stub WNetGetUserA
+0087 stub WNetGetUserW
+0088 stub WNetLogoffA
+0089 stub WNetLogoffW
+0090 stub WNetLogonA
+0091 stub WNetLogonW
+0092 stdcall WNetOpenEnumA(long long long ptr ptr) WNetOpenEnum32A
+0093 stub WNetOpenEnumW
+0094 stub WNetRemoveCachedPassword
+0095 stub WNetRestoreConnectionA
+0096 stub WNetRestoreConnectionW
+0097 stub WNetSetConnectionA
+0098 stub WNetSetConnectionW
+0099 stub WNetUseConnectionA
+0100 stub WNetUseConnectionW
+0101 stub WNetVerifyPasswordA
+0102 stub WNetVerifyPasswordW 
+
+#additions, not in win95 mpr.dll
+0103 stub WNetRestoreConnection
+0104 stub WNetLogonNotify
+0105 stub WNetPasswordChangeNotify
+0106 stub WNetGetPropertyTextA
+0107 stub WNetPropertyDialogA
+0108 stub WNetGetDirectoryTypeA
diff --git a/relay32/ntdll.spec b/relay32/ntdll.spec
index cd5daaa..0fbaf76 100644
--- a/relay32/ntdll.spec
+++ b/relay32/ntdll.spec
@@ -972,3 +972,16 @@
 967 stub RtlLookupAtomInAtomTable
 968 stub RtlQueryAtomInAtomTable
 969 stdcall RtlTryEnterCriticalSection(ptr) TryEnterCriticalSection
+970 stub RtlEnumerateProperties
+971 stub RtlSetPropertyClassId
+972 stub RtlSetPropertyNames
+973 stub RtlQueryPropertyNames
+974 stub RtlFlushPropertySet
+975 stub RtlSetProperties
+976 stub RtlQueryProperties
+977 stub RtlQueryPropertySet
+978 stub RtlSetUnicodeCallouts
+979 stub RtlPropertySetNameToGuid
+980 stub RtlGuidToPropertySetName
+981 stub RtlClosePropertySet
+982 stub RtlCreatePropertySet
diff --git a/relay32/shell32.spec b/relay32/shell32.spec
index 524063a..ecfefab 100644
--- a/relay32/shell32.spec
+++ b/relay32/shell32.spec
@@ -1,5 +1,6 @@
 name	shell32
 type	win32
+init	Shell32LibMain
 
 # Functions exported by the Win95 shell32.dll 
 # (these need to have these exact ordinals, for some 
@@ -7,10 +8,10 @@
 # This list was updated to dll version 4.72
 
    2 stdcall SHChangeNotifyRegister(long long long long long long) SHChangeNotifyRegister
-   3 stub CheckEscapesA@8   # exported by name
+   3 stub CheckEscapesA   # exported by name
    4 stdcall SHChangeNotifyDeregister (long long) SHChangeNotifyDeregister
    5 stub SHChangeNotifyUpdateEntryList@16
-   6 stub CheckEscapesW@8   # exported by name
+   6 stub CheckEscapesW   # exported by name
    7 stdcall CommandLineToArgvW(wstr ptr) CommandLineToArgvW   # exported by name
    8 stub Control_FillCache_RunDLL@16   # exported by name
    9 stub PifMgr_OpenProperties@16
@@ -118,16 +119,16 @@
  111 stub FileMenu_Invalidate
  112 stub FileMenu_MeasureItem
  113 stub FileMenu_ReplaceUsingPidl
- 114 stub FileMenu_Create
+ 114 stdcall FileMenu_Create (long long long long long) FileMenu_Create
  115 stub FileMenu_AppendItem
  116 stub FileMenu_TrackPopupMenuEx
  117 stub FileMenu_DeleteItemByCmd
  118 stub FileMenu_Destroy
- 119 stdcall IsLFNDrive(ptr) IsLFNDrive
+ 119 stdcall IsLFNDrive(str) IsLFNDrive
  120 stub FileMenu_AbortInitMenu
  121 stub SHFlushClipboard
  122 stub RunDLL_CallEntry16
- 123 stub SHFreeUnusedLibraries
+ 123 stdcall SHFreeUnusedLibraries (long) SHFreeUnusedLibraries
  124 stub FileMenu_AppendFilesForPidl
  125 stub FileMenu_AddFilesForPidl
  126 stub SHOutOfMemoryMessageBox
@@ -153,7 +154,7 @@
  146 stub RLBuildListOfPaths
  147 stdcall SHCLSIDFromString(long long) SHCLSIDFromString
  148 stdcall ExtractAssociatedIconA(long ptr long) ExtractAssociatedIcon32A   # exported by name
- 149 stub SHFind_InitMenuPopup
+ 149 stdcall SHFind_InitMenuPopup(long long long long) SHFind_InitMenuPopup
  150 stub ExtractAssociatedIconExA   # exported by name
  151 stub SHLoadOLE
  152 stdcall ILGetSize(ptr) ILGetSize
@@ -180,14 +181,14 @@
  173 stub SHValidateUNC
  174 stdcall SHCreateShellFolderViewEx (ptr ptr) SHCreateShellFolderViewEx32
  175 stdcall SHGetSpecialFolderPath(long long long long) SHGetSpecialFolderPath
- 176 stub SHSetInstanceExplorer
+ 176 stdcall SHSetInstanceExplorer (long) SHSetInstanceExplorer
  177 stub DAD_SetDragImageFromListView
  178 stub SHObjectProperties
  179 stub SHGetNewLinkInfoA
  180 stub SHGetNewLinkInfoW
  181 stdcall RegisterShellHook(long long) RegisterShellHook32
  182 stub ShellMessageBoxW
- 183 cdecl ShellMessageBoxA(long long long long long long) ShellMessageBoxA
+ 183 cdecl ShellMessageBoxA(long long long str long long) ShellMessageBoxA
  184 stdcall ArrangeWindows(long long long long long) ArrangeWindows
  185 stub SHHandleDiskFull
  186 stub ExtractAssociatedIconExW   # exported by name
@@ -237,7 +238,7 @@
  230 stub RealShellExecuteExA   # exported by name
  231 stub RealShellExecuteExW   # exported by name
  232 stub RealShellExecuteW   # exported by name
- 233 stub RegenerateUserEnvironment@8   # exported by name
+ 233 stub RegenerateUserEnvironment   # exported by name
  234 stdcall SHAddToRecentDocs (long ptr) SHAddToRecentDocs32  # exported by name
  235 stdcall SHAppBarMessage(long ptr) SHAppBarMessage32   # exported by name
  236 stdcall SHBrowseForFolder(ptr) SHBrowseForFolder32A   # exported by name
@@ -260,10 +261,10 @@
  253 stdcall SHGetFileInfo(ptr long ptr long long) SHGetFileInfo32A   # exported by name
  254 stdcall SHGetFileInfoA(ptr long ptr long long) SHGetFileInfo32A   # exported by name
  255 stub SHGetFileInfoW@20 # exported by name
- 256 stub SHGetInstanceExplorer   # exported by name
+ 256 stdcall SHGetInstanceExplorer (long) SHGetInstanceExplorer
  257 stdcall SHGetMalloc(ptr) SHGetMalloc   # exported by name
  258 stub SHGetNewLinkInfo@20   # exported by name
- 259 stdcall SHGetPathFromIDList(ptr ptr) SHGetPathFromIDList   # exported by name
+ 259 stdcall SHGetPathFromIDList(ptr ptr) SHGetPathFromIDList32   # exported by name
  260 stub SHGetPathFromIDList@8 # exported by name
  261 stdcall SHGetPathFromIDListA (long long) SHGetPathFromIDList32A # exported by name
  262 stdcall SHGetPathFromIDListW (long long) SHGetPathFromIDList32W # exported by name
@@ -296,7 +297,7 @@
  288 stdcall ShellAboutA(long str str long) ShellAbout32A
  289 stdcall ShellAboutW(long wstr wstr long) ShellAbout32W
  290 stdcall ShellExecuteA(long str str str str long) ShellExecute32A
- 291 stub ShellExecuteEx
+ 291 stdcall ShellExecuteEx (long) ShellExecuteEx
  292 stub ShellExecuteExA
  293 stub ShellExecuteExW
  294 stub ShellExecuteW
diff --git a/scheduler/Makefile.in b/scheduler/Makefile.in
index c273db6..26b91e0 100644
--- a/scheduler/Makefile.in
+++ b/scheduler/Makefile.in
@@ -16,6 +16,7 @@
 	semaphore.c \
 	synchro.c \
 	sysdeps.c \
+	syslevel.c \
 	thread.c
 
 all: $(MODULE).o
diff --git a/scheduler/client.c b/scheduler/client.c
index 98f4f75..4a35bcf 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -16,6 +16,7 @@
 #include "process.h"
 #include "thread.h"
 #include "server.h"
+#include "server/request.h"
 #include "winerror.h"
 
 /* Some versions of glibc don't define this */
@@ -23,6 +24,26 @@
 #define SCM_RIGHTS 1
 #endif
 
+#define CHECK_LEN(len,wanted) \
+  if ((len) == (wanted)) ; \
+  else CLIENT_ProtocolError( __FUNCTION__ ": len %d != %d\n", (len), (wanted) );
+
+/***********************************************************************
+ *           CLIENT_ProtocolError
+ */
+static void CLIENT_ProtocolError( const char *err, ... )
+{
+    THDB *thdb = THREAD_Current();
+    va_list args;
+
+    va_start( args, err );
+    fprintf( stderr, "Client protocol error:%p: ", thdb->server_tid );
+    vfprintf( stderr, err, args );
+    va_end( args );
+    ExitThread(1);
+}
+
+
 /***********************************************************************
  *           CLIENT_SendRequest_v
  *
@@ -62,10 +83,8 @@
 
     if ((ret = sendmsg( thdb->socket, &msghdr, 0 )) < len)
     {
-        fprintf( stderr, "Fatal protocol error: " );
         if (ret == -1) perror( "sendmsg" );
-        else fprintf( stderr, "partial msg sent %d/%d\n", ret, len );
-        ExitThread(1);
+        CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret, len );
     }
     /* we passed the fd now we can close it */
     if (pass_fd != -1) close( pass_fd );
@@ -123,30 +142,21 @@
 
     if ((ret = recvmsg( thdb->socket, &msghdr, 0 )) == -1)
     {
-        fprintf( stderr, "Fatal protocol error: " );
         perror("recvmsg");
-        ExitThread(1);
+        CLIENT_ProtocolError( "recvmsg\n" );
     }
+    if (!ret) ExitThread(1); /* the server closed the connection; time to die... */
+
+    /* sanity checks */
+
     if (ret < sizeof(head))
-    {
-        fprintf( stderr,
-                 "Fatal protocol error: partial header received %d/%d\n",
-                 ret, sizeof(head));
-        ExitThread(1);
-    }
+        CLIENT_ProtocolError( "partial header received %d/%d\n", ret, sizeof(head) );
+
     if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
-    {
-        fprintf( stderr, "Fatal protocol error: header length %d\n",
-                 head.len );
-        ExitThread(1);
-    }
+        CLIENT_ProtocolError( "header length %d\n", head.len );
+
     if (head.seq != thdb->seq++)
-    {
-        fprintf( stderr,
-                 "Fatal protocol error: sequence %08x instead of %08x\n",
-                 head.seq, thdb->seq - 1 );
-        ExitThread(1);
-    }
+        CLIENT_ProtocolError( "sequence %08x instead of %08x\n", head.seq, thdb->seq - 1 );
 
 #ifndef HAVE_MSGHDR_ACCRIGHTS
     pass_fd = cmsg.fd;
@@ -171,10 +181,10 @@
         int len = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
         if ((len = recv( thdb->socket, buffer, len, 0 )) == -1)
         {
-            fprintf( stderr, "Fatal protocol error: " );
             perror( "recv" );
-            ExitThread(1);
+            CLIENT_ProtocolError( "recv\n" );
         }
+        if (!len) ExitThread(1); /* the server closed the connection; time to die... */
         remaining -= len;
     }
 
@@ -208,48 +218,17 @@
 
 
 /***********************************************************************
- *           send_new_thread
- *
- * Send a new thread request. Helper function for CLIENT_NewThread.
- */
-static int send_new_thread( THDB *thdb )
-{
-    struct new_thread_request request;
-    struct new_thread_reply reply;
-    int len, fd[2];
-
-    if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
-    {
-        SetLastError( ERROR_TOO_MANY_OPEN_FILES );  /* FIXME */
-        return -1;
-    }
-
-    request.pid = thdb->process->server_pid;
-    CLIENT_SendRequest( REQ_NEW_THREAD, fd[1], 1, &request, sizeof(request) );
-
-    if (CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) )) goto error;
-    if (len < sizeof(reply)) goto error;
-    thdb->server_tid = reply.tid;
-    thdb->process->server_pid = reply.pid;
-    if (thdb->socket != -1) close( thdb->socket );
-    thdb->socket = fd[0];
-    thdb->seq = 0;  /* reset the sequence number for the new fd */
-    return 0;
-
- error:
-    close( fd[0] );
-    return -1;
-}
-
-
-/***********************************************************************
  *           CLIENT_NewThread
  *
  * Send a new thread request.
  */
-int CLIENT_NewThread( THDB *thdb )
+int CLIENT_NewThread( THDB *thdb, int *thandle, int *phandle )
 {
+    struct new_thread_request request;
+    struct new_thread_reply reply;
+    int len, fd[2];
     extern BOOL32 THREAD_InitDone;
+    extern void server_main_loop( int fd );
 
     if (!THREAD_InitDone)  /* first thread -> start the server */
     {
@@ -285,7 +264,33 @@
         }
     }
 
-    return send_new_thread( thdb );
+    if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
+    {
+        SetLastError( ERROR_TOO_MANY_OPEN_FILES );  /* FIXME */
+        return -1;
+    }
+
+    request.pid = thdb->process->server_pid;
+    CLIENT_SendRequest( REQ_NEW_THREAD, fd[1], 1, &request, sizeof(request) );
+
+    if (CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) )) goto error;
+    if (len < sizeof(reply)) goto error;
+    thdb->server_tid = reply.tid;
+    thdb->process->server_pid = reply.pid;
+    if (thdb->socket != -1) close( thdb->socket );
+    thdb->socket = fd[0];
+    thdb->seq = 0;  /* reset the sequence number for the new fd */
+
+    /* we don't need the handles for now */
+    if (thandle) *thandle = reply.thandle;
+    else if (reply.thandle != -1) CLIENT_CloseHandle( reply.thandle );
+    if (phandle) *phandle = reply.phandle;
+    else if (reply.phandle != -1) CLIENT_CloseHandle( reply.phandle );
+    return 0;
+
+ error:
+    close( fd[0] );
+    return -1;
 }
 
 
@@ -300,11 +305,112 @@
     struct init_thread_request init;
     int len = strlen( thdb->process->env_db->cmd_line );
 
-    init.pid = getpid();
+    init.unix_pid = getpid();
     len = MIN( len, MAX_MSG_LENGTH - sizeof(init) );
 
     CLIENT_SendRequest( REQ_INIT_THREAD, -1, 2,
                         &init, sizeof(init),
                         thdb->process->env_db->cmd_line, len );
-    return CLIENT_WaitReply( NULL, NULL, NULL, 0 );
+    return CLIENT_WaitReply( NULL, NULL, 0 );
+}
+
+
+/***********************************************************************
+ *           CLIENT_TerminateProcess
+ *
+ * Send a terminate process request. Return 0 if OK.
+ */
+int CLIENT_TerminateProcess( int handle, int exit_code )
+{
+    CLIENT_SendRequest( REQ_TERMINATE_PROCESS, -1, 2,
+                        &handle, sizeof(handle),
+                        &exit_code, sizeof(exit_code) );
+    return CLIENT_WaitReply( NULL, NULL, 0 );
+}
+
+/***********************************************************************
+ *           CLIENT_TerminateThread
+ *
+ * Send a terminate thread request. Return 0 if OK.
+ */
+int CLIENT_TerminateThread( int handle, int exit_code )
+{
+    CLIENT_SendRequest( REQ_TERMINATE_THREAD, -1, 2,
+                        &handle, sizeof(handle),
+                        &exit_code, sizeof(exit_code) );
+    return CLIENT_WaitReply( NULL, NULL, 0 );
+}
+
+/***********************************************************************
+ *           CLIENT_CloseHandle
+ *
+ * Send a close handle request. Return 0 if OK.
+ */
+int CLIENT_CloseHandle( int handle )
+{
+    CLIENT_SendRequest( REQ_CLOSE_HANDLE, -1, 1, &handle, sizeof(handle) );
+    return CLIENT_WaitReply( NULL, NULL, 0 );
+}
+
+/***********************************************************************
+ *           CLIENT_DuplicateHandle
+ *
+ * Send a duplicate handle request. Return 0 if OK.
+ */
+int CLIENT_DuplicateHandle( int src_process, int src_handle, int dst_process, int dst_handle,
+                            DWORD access, BOOL32 inherit, DWORD options )
+{
+    struct dup_handle_request req;
+    struct dup_handle_reply reply;
+    int len;
+
+    req.src_process = src_process;
+    req.src_handle  = src_handle;
+    req.dst_process = dst_process;
+    req.dst_handle  = dst_handle;
+    req.access      = access;
+    req.inherit     = inherit;
+    req.options     = options;
+
+    CLIENT_SendRequest( REQ_DUP_HANDLE, -1, 1, &req, sizeof(req) );
+    CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) );
+    CHECK_LEN( len, sizeof(reply) );
+    return reply.handle;
+}
+
+/***********************************************************************
+ *           CLIENT_GetProcessInfo
+ *
+ * Send a get process info request. Return 0 if OK.
+ */
+int CLIENT_GetProcessInfo( int handle, struct get_process_info_reply *reply )
+{
+    int len, err;
+
+    CLIENT_SendRequest( REQ_GET_PROCESS_INFO, -1, 1, &handle, sizeof(handle) );
+    err = CLIENT_WaitReply( &len, NULL, 1, reply, sizeof(*reply) );
+    CHECK_LEN( len, sizeof(*reply) );
+    return err;
+}
+
+
+/***********************************************************************
+ *           CLIENT_OpenProcess
+ *
+ * Open a handle to a process.
+ */
+int CLIENT_OpenProcess( void *pid, DWORD access, BOOL32 inherit )
+{
+    struct open_process_request req;
+    struct open_process_reply reply;
+    int len;
+
+    req.pid     = pid;
+    req.access  = access;
+    req.inherit = inherit;
+
+    CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
+    CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) );
+    CHECK_LEN( len, sizeof(reply) );
+    return reply.handle;
 }
diff --git a/scheduler/event.c b/scheduler/event.c
index d5ad9c8..1ca9d16 100644
--- a/scheduler/event.c
+++ b/scheduler/event.c
@@ -125,7 +125,7 @@
     SYSTEM_LOCK();
     if ((obj = K32OBJ_FindNameType( name, K32OBJ_EVENT )) != NULL)
     {
-        handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit );
+        handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 );
         K32OBJ_DecCount( obj );
     }
     SYSTEM_UNLOCK();
@@ -153,7 +153,7 @@
     EVENT *event;
     SYSTEM_LOCK();
     if (!(event = (EVENT *)HANDLE_GetObjPtr(PROCESS_Current(), handle,
-                                            K32OBJ_EVENT, EVENT_MODIFY_STATE)))
+                                            K32OBJ_EVENT, EVENT_MODIFY_STATE, NULL)))
     {
         SYSTEM_UNLOCK();
         return FALSE;
@@ -175,7 +175,7 @@
     EVENT *event;
     SYSTEM_LOCK();
     if (!(event = (EVENT *)HANDLE_GetObjPtr(PROCESS_Current(), handle,
-                                            K32OBJ_EVENT, EVENT_MODIFY_STATE)))
+                                            K32OBJ_EVENT, EVENT_MODIFY_STATE, NULL)))
     {
         SYSTEM_UNLOCK();
         return FALSE;
@@ -196,7 +196,7 @@
     EVENT *event;
     SYSTEM_LOCK();
     if (!(event = (EVENT *)HANDLE_GetObjPtr(PROCESS_Current(), handle,
-                                            K32OBJ_EVENT, EVENT_MODIFY_STATE)))
+                                            K32OBJ_EVENT, EVENT_MODIFY_STATE, NULL)))
     {
         SYSTEM_UNLOCK();
         return FALSE;
diff --git a/scheduler/handle.c b/scheduler/handle.c
index 72b301d..4d5957d 100644
--- a/scheduler/handle.c
+++ b/scheduler/handle.c
@@ -11,6 +11,7 @@
 #include "winerror.h"
 #include "heap.h"
 #include "process.h"
+#include "server.h"
 
 #define HTABLE_SIZE  0x30  /* Handle table initial size */
 #define HTABLE_INC   0x10  /* Handle table increment */
@@ -81,6 +82,7 @@
                 {
                     dst->access = src->access;
                     dst->ptr    = src->ptr;
+                    dst->server = src->server;
                     K32OBJ_IncCount( dst->ptr );
                 }
             }
@@ -90,6 +92,7 @@
         {
             pdb->handle_table->entries[1].ptr    = &pdb->header;
             pdb->handle_table->entries[1].access = PROCESS_ALL_ACCESS;
+            pdb->handle_table->entries[1].server = -1;  /* FIXME */
             K32OBJ_IncCount( &pdb->header );
         }
     }
@@ -103,7 +106,8 @@
  *
  * Allocate a handle for a kernel object and increment its refcount.
  */
-HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access, BOOL32 inherit )
+HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access,
+                       BOOL32 inherit, int server_handle )
 {
     HANDLE32 h;
     HANDLE_ENTRY *entry;
@@ -125,11 +129,13 @@
         entry = &pdb->handle_table->entries[h];
         entry->access = access;
         entry->ptr    = ptr;
+        entry->server = server_handle;
         SYSTEM_UNLOCK();
         return h;
     }
     K32OBJ_DecCount( ptr );
     SYSTEM_UNLOCK();
+    if (server_handle != -1) CLIENT_CloseHandle( server_handle );
     SetLastError( ERROR_OUTOFMEMORY );
     return INVALID_HANDLE_VALUE32;
 }
@@ -142,7 +148,8 @@
  * The refcount must be decremented when the pointer is no longer used.
  */
 K32OBJ *HANDLE_GetObjPtr( PDB32 *pdb, HANDLE32 handle,
-                          K32OBJ_TYPE type, DWORD access )
+                          K32OBJ_TYPE type, DWORD access,
+                          int *server_handle )
 {
     K32OBJ *ptr = NULL;
 
@@ -154,6 +161,7 @@
             WARN(win32, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
                      handle, entry->access, access );
         ptr = entry->ptr;
+        if (server_handle) *server_handle = entry->server;
         if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
             K32OBJ_IncCount( ptr );
         else
@@ -234,6 +242,8 @@
             {
                 entry->access = 0;
                 entry->ptr    = NULL;
+                if (entry->server != -1)
+                    CLIENT_CloseHandle( entry->server );
                 K32OBJ_DecCount( ptr );
                 ret = TRUE;
             }
@@ -266,6 +276,7 @@
         if (obj && (ptr != obj)) continue;  /* not the right object */
         entry->access = 0;
         entry->ptr    = NULL;
+        if (entry->server != -1) CLIENT_CloseHandle( entry->server );
         K32OBJ_DecCount( ptr );
     }
     SYSTEM_UNLOCK();
@@ -343,27 +354,35 @@
     K32OBJ *obj = NULL;
     BOOL32 ret = FALSE;
     HANDLE32 handle;
+    int src_process, src_handle, dst_process, dst_handle;
 
     SYSTEM_LOCK();
 
-    if (!(src_pdb = PROCESS_GetPtr( source_process, PROCESS_DUP_HANDLE )))
+    if (!(src_pdb = PROCESS_GetPtr( source_process, PROCESS_DUP_HANDLE, &src_process )))
         goto done;
-    if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0 )))
+    if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0, &src_handle )))
         goto done;
 
     /* Now that we are sure the source is valid, handle the options */
 
-    if (options & DUPLICATE_CLOSE_SOURCE)
-        HANDLE_Close( src_pdb, source );
     if (options & DUPLICATE_SAME_ACCESS)
         HANDLE_GetAccess( src_pdb, source, &access );
+    if (options & DUPLICATE_CLOSE_SOURCE)
+        HANDLE_Close( src_pdb, source );
 
     /* And duplicate the handle in the dest process */
 
-    if (!(dst_pdb = PROCESS_GetPtr( dest_process, PROCESS_DUP_HANDLE )))
+    if (!(dst_pdb = PROCESS_GetPtr( dest_process, PROCESS_DUP_HANDLE, &dst_process )))
         goto done;
-    if ((handle = HANDLE_Alloc( dst_pdb, obj,
-                                access, inherit )) != INVALID_HANDLE_VALUE32)
+
+    if ((src_process != -1) && (src_handle != -1) && (dst_process != -1))
+        dst_handle = CLIENT_DuplicateHandle( src_process, src_handle, dst_process, -1,
+                                             access, inherit, options );
+    else
+        dst_handle = -1;
+
+    if ((handle = HANDLE_Alloc( dst_pdb, obj, access, inherit,
+                                dst_handle )) != INVALID_HANDLE_VALUE32)
     {
         if (dest) *dest = handle;
         ret = TRUE;
diff --git a/scheduler/k32obj.c b/scheduler/k32obj.c
index 989d319..960e962 100644
--- a/scheduler/k32obj.c
+++ b/scheduler/k32obj.c
@@ -19,6 +19,7 @@
 extern const K32OBJ_OPS PROCESS_Ops;
 extern const K32OBJ_OPS THREAD_Ops;
 extern const K32OBJ_OPS FILE_Ops;
+extern const K32OBJ_OPS CHANGE_Ops;
 extern const K32OBJ_OPS MEM_MAPPED_FILE_Ops;
 extern const K32OBJ_OPS CONSOLE_Ops;
 
@@ -43,7 +44,7 @@
     &PROCESS_Ops,           /* K32OBJ_PROCESS */
     &THREAD_Ops,            /* K32OBJ_THREAD */
     &FILE_Ops,              /* K32OBJ_FILE */
-    &K32OBJ_NullOps,        /* K32OBJ_CHANGE */
+    &CHANGE_Ops,            /* K32OBJ_CHANGE */
     &CONSOLE_Ops,           /* K32OBJ_CONSOLE */
     &K32OBJ_NullOps,        /* K32OBJ_SCREEN_BUFFER */
     &MEM_MAPPED_FILE_Ops,   /* K32OBJ_MEM_MAPPED_FILE */
@@ -175,7 +176,7 @@
         if (obj->type == type)
         {
             SetLastError( ERROR_ALREADY_EXISTS );
-            *handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit );
+            *handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 );
         }
         else
         {
@@ -212,7 +213,7 @@
 
     /* Allocate a handle */
 
-    *handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit );
+    *handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 );
     SYSTEM_UNLOCK();
     return obj;
 }
diff --git a/scheduler/mutex.c b/scheduler/mutex.c
index 407e50e..084fae0 100644
--- a/scheduler/mutex.c
+++ b/scheduler/mutex.c
@@ -140,7 +140,7 @@
     SYSTEM_LOCK();
     if ((obj = K32OBJ_FindNameType( name, K32OBJ_MUTEX )) != NULL)
     {
-        handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit );
+        handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 );
         K32OBJ_DecCount( obj );
     }
     SYSTEM_UNLOCK();
@@ -168,7 +168,7 @@
     MUTEX *mutex;
     SYSTEM_LOCK();
     if (!(mutex = (MUTEX *)HANDLE_GetObjPtr(PROCESS_Current(), handle,
-                                            K32OBJ_MUTEX, MUTEX_MODIFY_STATE)))
+                                            K32OBJ_MUTEX, MUTEX_MODIFY_STATE, NULL)))
     {
         SYSTEM_UNLOCK();
         return FALSE;
diff --git a/scheduler/process.c b/scheduler/process.c
index c213d2a..3ccd3d2 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -57,16 +57,18 @@
  *
  * Get a process from a handle, incrementing the PDB refcount.
  */
-PDB32 *PROCESS_GetPtr( HANDLE32 handle, DWORD access )
+PDB32 *PROCESS_GetPtr( HANDLE32 handle, DWORD access, int *server_handle )
 {
     PDB32 *pdb = PROCESS_Current();
 
     if (handle == PROCESS_SELF)
     {
+        if (server_handle) *server_handle = PROCESS_SELF;
         K32OBJ_IncCount( &pdb->header );
         return pdb;
     }
-    return (PDB32 *)HANDLE_GetObjPtr( pdb, handle, K32OBJ_PROCESS, access );
+    return (PDB32 *)HANDLE_GetObjPtr( pdb, handle, K32OBJ_PROCESS, access,
+                                      server_handle );
 }
 
 
@@ -227,7 +229,7 @@
 
     /* Create the initial process and thread structures */
     if (!(pdb = PROCESS_CreatePDB( NULL ))) return FALSE;
-    if (!(thdb = THREAD_Create( pdb, 0, FALSE, NULL, NULL ))) return FALSE;
+    if (!(thdb = THREAD_Create( pdb, 0, FALSE, NULL, NULL, NULL, NULL ))) return FALSE;
     thdb->unix_pid = getpid();
 
     /* Create the environment DB of the first process */
@@ -247,14 +249,16 @@
  */
 PDB32 *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
                        HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
-                       UINT32 cmdShow )
+                       UINT32 cmdShow, PROCESS_INFORMATION *info )
 {
     DWORD size, commit;
+    int server_thandle, server_phandle;
     THDB *thdb = NULL;
     PDB32 *parent = PROCESS_Current();
     PDB32 *pdb = PROCESS_CreatePDB( parent );
 
     if (!pdb) return NULL;
+    info->hThread = info->hProcess = INVALID_HANDLE_VALUE32;
 
     /* Create the heap */
 
@@ -282,7 +286,16 @@
         size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
     else
         size = 0;
-    if (!(thdb = THREAD_Create( pdb, size, FALSE, NULL, NULL ))) goto error;
+    if (!(thdb = THREAD_Create( pdb, size, FALSE, &server_thandle, &server_phandle,
+                                NULL, NULL ))) goto error;
+    if ((info->hThread = HANDLE_Alloc( parent, &thdb->header, THREAD_ALL_ACCESS,
+                                       FALSE, server_thandle )) == INVALID_HANDLE_VALUE32)
+        goto error;
+    if ((info->hProcess = HANDLE_Alloc( parent, &pdb->header, PROCESS_ALL_ACCESS,
+                                        FALSE, server_phandle )) == INVALID_HANDLE_VALUE32)
+        goto error;
+    info->dwProcessId = PDB_TO_PROCESS_ID(pdb);
+    info->dwProcessId = THDB_TO_THREAD_ID(thdb);
 
     thdb->unix_pid = getpid(); /* FIXME: wrong here ... */
 
@@ -294,6 +307,8 @@
     return pdb;
 
 error:
+    if (info->hThread != INVALID_HANDLE_VALUE32) CloseHandle( info->hThread );
+    if (info->hProcess != INVALID_HANDLE_VALUE32) CloseHandle( info->hProcess );
     if (thdb) K32OBJ_DecCount( &thdb->header );
     PROCESS_FreePDB( pdb );
     return NULL;
@@ -398,13 +413,20 @@
  */
 HANDLE32 WINAPI OpenProcess( DWORD access, BOOL32 inherit, DWORD id )
 {
+    int server_handle;
     PDB32 *pdb = PROCESS_ID_TO_PDB(id);
     if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
     {
         SetLastError( ERROR_INVALID_HANDLE );
         return 0;
     }
-    return HANDLE_Alloc( PROCESS_Current(), &pdb->header, access, inherit );
+    if ((server_handle = CLIENT_OpenProcess( pdb->server_pid, access, inherit )) == -1)
+    {
+        SetLastError( ERROR_INVALID_HANDLE );
+        return 0;
+    }
+    return HANDLE_Alloc( PROCESS_Current(), &pdb->header, access,
+                         inherit, server_handle );
 }			      
 
 
@@ -442,7 +464,7 @@
  */
 BOOL32 WINAPI SetPriorityClass( HANDLE32 hprocess, DWORD priorityclass )
 {
-    PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_SET_INFORMATION );
+    PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_SET_INFORMATION, NULL );
     if (!pdb) return FALSE;
     switch (priorityclass)
     {
@@ -472,7 +494,7 @@
  */
 DWORD WINAPI GetPriorityClass(HANDLE32 hprocess)
 {
-    PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_QUERY_INFORMATION );
+    PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_QUERY_INFORMATION, NULL );
     DWORD ret = 0;
     if (pdb)
     {
@@ -689,10 +711,18 @@
     LPDWORD lpExitCode) /* [O] address to receive termination status */
 {
     PDB32 *process;
+    int server_handle;
+    struct get_process_info_reply info;
 
-    if (!(process = PROCESS_GetPtr( hProcess, PROCESS_QUERY_INFORMATION )))
+    if (!(process = PROCESS_GetPtr( hProcess, PROCESS_QUERY_INFORMATION,
+                                    &server_handle )))
         return FALSE;
-    if (lpExitCode) *lpExitCode = process->exit_code;
+    if (server_handle != -1)
+    {
+        CLIENT_GetProcessInfo( server_handle, &info );
+        if (lpExitCode) *lpExitCode = info.exit_code;
+    }
+    else if (lpExitCode) *lpExitCode = process->exit_code;
     K32OBJ_DecCount( &process->header );
     return TRUE;
 }
@@ -711,3 +741,64 @@
 	/* number of available heaps */
 	return 1;
 }
+
+/***********************************************************************
+ * PROCESS_SuspendOtherThreads
+ */
+
+void PROCESS_SuspendOtherThreads(void)
+{
+    PDB32 *pdb;
+    THREAD_ENTRY *entry;
+
+    SYSTEM_LOCK();
+
+    pdb = PROCESS_Current();
+    entry = pdb->thread_list->next;
+    for (;;)
+    {
+         if (entry->thread != THREAD_Current())
+         {
+             HANDLE32 handle = HANDLE_Alloc( PROCESS_Current(), 
+                                             &entry->thread->header,
+                                             THREAD_ALL_ACCESS, FALSE, -1 );
+             SuspendThread(handle);
+             CloseHandle(handle);
+         }
+         if (entry == pdb->thread_list) break;
+         entry = entry->next;
+    }
+
+    SYSTEM_UNLOCK();
+}
+
+/***********************************************************************
+ * PROCESS_ResumeOtherThreads
+ */
+
+void PROCESS_ResumeOtherThreads(void)
+{
+    PDB32 *pdb;
+    THREAD_ENTRY *entry;
+
+    SYSTEM_LOCK();
+
+    pdb = PROCESS_Current();
+    entry = pdb->thread_list->next;
+    for (;;)
+    {
+         if (entry->thread != THREAD_Current())
+         {
+             HANDLE32 handle = HANDLE_Alloc( PROCESS_Current(), 
+                                             &entry->thread->header,
+                                             THREAD_ALL_ACCESS, FALSE, -1 );
+             ResumeThread(handle);
+             CloseHandle(handle);
+         }
+         if (entry == pdb->thread_list) break;
+         entry = entry->next;
+    }
+
+    SYSTEM_UNLOCK();
+}
+
diff --git a/scheduler/semaphore.c b/scheduler/semaphore.c
index a456ebf..626150e 100644
--- a/scheduler/semaphore.c
+++ b/scheduler/semaphore.c
@@ -94,7 +94,7 @@
     SYSTEM_LOCK();
     if ((obj = K32OBJ_FindNameType( name, K32OBJ_SEMAPHORE )) != NULL)
     {
-        handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit );
+        handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit, -1 );
         K32OBJ_DecCount( obj );
     }
     SYSTEM_UNLOCK();
@@ -124,7 +124,7 @@
     SYSTEM_LOCK();
     if (!(sem = (SEMAPHORE *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
                                                K32OBJ_SEMAPHORE,
-                                               SEMAPHORE_MODIFY_STATE )))
+                                               SEMAPHORE_MODIFY_STATE, NULL )))
     {
         SYSTEM_UNLOCK();
         return FALSE;
diff --git a/scheduler/synchro.c b/scheduler/synchro.c
index bb4a110..229134c 100644
--- a/scheduler/synchro.c
+++ b/scheduler/synchro.c
@@ -19,7 +19,8 @@
  *           SYNC_BuildWaitStruct
  */
 static BOOL32 SYNC_BuildWaitStruct( DWORD count, const HANDLE32 *handles,
-                                    BOOL32 wait_all, WAIT_STRUCT *wait )
+                                    BOOL32 wait_all, BOOL32 wait_msg, 
+                                    WAIT_STRUCT *wait )
 {
     DWORD i;
     K32OBJ **ptr;
@@ -27,15 +28,20 @@
     wait->count    = count;
     wait->signaled = WAIT_FAILED;
     wait->wait_all = wait_all;
+    wait->wait_msg = wait_msg;
     SYSTEM_LOCK();
     for (i = 0, ptr = wait->objs; i < count; i++, ptr++)
     {
         if (!(*ptr = HANDLE_GetObjPtr( PROCESS_Current(), handles[i],
-                                       K32OBJ_UNKNOWN, SYNCHRONIZE )))
-            break;
+                                       K32OBJ_UNKNOWN, SYNCHRONIZE, NULL )))
+        { 
+            ERR(win32, "Bad handle %08x\n", handles[i]); 
+            break; 
+        }
         if (!K32OBJ_OPS( *ptr )->signaled)
         {
             /* This object type cannot be waited upon */
+            ERR(win32, "Cannot wait on handle %08x\n", handles[i]); 
             K32OBJ_DecCount( *ptr );
             break;
         }
@@ -44,6 +50,7 @@
     if (i != count)
     {
         /* There was an error */
+        wait->wait_msg = FALSE;
         while (i--) K32OBJ_DecCount( wait->objs[i] );
     }
     SYSTEM_UNLOCK();
@@ -59,6 +66,7 @@
     DWORD i;
     K32OBJ **ptr;
     SYSTEM_LOCK();
+    wait->wait_msg = FALSE;
     for (i = 0, ptr = wait->objs; i < wait->count; i++, ptr++)
         K32OBJ_DecCount( *ptr );
     SYSTEM_UNLOCK();
@@ -256,42 +264,39 @@
     SYSTEM_UNLOCK();
 }
 
-
 /***********************************************************************
- *           WaitForSingleObject   (KERNEL32.723)
+ *           SYNC_MsgWakeUp
  */
-DWORD WINAPI WaitForSingleObject( HANDLE32 handle, DWORD timeout )
+void SYNC_MsgWakeUp( THDB *thdb )
 {
-    return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, FALSE );
+    SYSTEM_LOCK();
+
+    if (!thdb) 
+    {
+        SYSTEM_UNLOCK();
+        return;
+    }
+
+    if (thdb->wait_struct.wait_msg)
+    {
+        thdb->wait_struct.signaled = thdb->wait_struct.count;
+
+        TRACE(win32, "waking up %04x for message\n", thdb->teb_sel );
+        if (thdb->unix_pid)
+            kill( thdb->unix_pid, SIGUSR1 );
+        else
+            FIXME(win32,"have got unix_pid 0\n");
+    }
+
+    SYSTEM_UNLOCK();
 }
 
-
 /***********************************************************************
- *           WaitForSingleObjectEx   (KERNEL32.724)
+ *           SYNC_DoWait
  */
-DWORD WINAPI WaitForSingleObjectEx( HANDLE32 handle, DWORD timeout,
-                                    BOOL32 alertable )
-{
-    return WaitForMultipleObjectsEx( 1, &handle, FALSE, timeout, alertable );
-}
-
-
-/***********************************************************************
- *           WaitForMultipleObjects   (KERNEL32.721)
- */
-DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE32 *handles,
-                                     BOOL32 wait_all, DWORD timeout )
-{
-    return WaitForMultipleObjectsEx(count, handles, wait_all, timeout, FALSE);
-}
-
-
-/***********************************************************************
- *           WaitForMultipleObjectsEx   (KERNEL32.722)
- */
-DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE32 *handles,
-                                       BOOL32 wait_all, DWORD timeout,
-                                       BOOL32 alertable )
+DWORD SYNC_DoWait( DWORD count, const HANDLE32 *handles,
+                   BOOL32 wait_all, DWORD timeout, 
+                   BOOL32 alertable, BOOL32 wait_msg )
 {
     WAIT_STRUCT *wait = &THREAD_Current()->wait_struct;
 
@@ -305,7 +310,7 @@
         FIXME(win32, "alertable not implemented\n" );
 
     SYSTEM_LOCK();
-    if (!SYNC_BuildWaitStruct( count, handles, wait_all, wait ))
+    if (!SYNC_BuildWaitStruct( count, handles, wait_all, wait_msg, wait ))
         wait->signaled = WAIT_FAILED;
     else
     {
@@ -316,3 +321,42 @@
     SYSTEM_UNLOCK();
     return wait->signaled;
 }
+
+/***********************************************************************
+ *           WaitForSingleObject   (KERNEL32.723)
+ */
+DWORD WINAPI WaitForSingleObject( HANDLE32 handle, DWORD timeout )
+{
+    return SYNC_DoWait( 1, &handle, FALSE, timeout, FALSE, FALSE );
+}
+
+
+/***********************************************************************
+ *           WaitForSingleObjectEx   (KERNEL32.724)
+ */
+DWORD WINAPI WaitForSingleObjectEx( HANDLE32 handle, DWORD timeout,
+                                    BOOL32 alertable )
+{
+    return SYNC_DoWait( 1, &handle, FALSE, timeout, alertable, FALSE );
+}
+
+
+/***********************************************************************
+ *           WaitForMultipleObjects   (KERNEL32.721)
+ */
+DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE32 *handles,
+                                     BOOL32 wait_all, DWORD timeout )
+{
+    return SYNC_DoWait( count, handles, wait_all, timeout, FALSE, FALSE );
+}
+
+
+/***********************************************************************
+ *           WaitForMultipleObjectsEx   (KERNEL32.722)
+ */
+DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE32 *handles,
+                                       BOOL32 wait_all, DWORD timeout,
+                                       BOOL32 alertable )
+{
+    return SYNC_DoWait( count, handles, wait_all, timeout, alertable, FALSE );
+}
diff --git a/scheduler/sysdeps.c b/scheduler/sysdeps.c
index 390c68c..d63d30f 100644
--- a/scheduler/sysdeps.c
+++ b/scheduler/sysdeps.c
@@ -80,11 +80,9 @@
  */
 static void SYSDEPS_StartThread( THDB *thdb )
 {
-    LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
     thdb->unix_pid = getpid();
     SET_FS( thdb->teb_sel );
-    CLIENT_InitThread();
-    ExitThread( func( thdb->entry_arg ) );
+    THREAD_Start( thdb );
 }
 #endif  /* __linux__ */
 
diff --git a/scheduler/syslevel.c b/scheduler/syslevel.c
new file mode 100644
index 0000000..50a5dd3
--- /dev/null
+++ b/scheduler/syslevel.c
@@ -0,0 +1,177 @@
+/*
+ * Win32 'syslevel' routines
+ *
+ * Copyright 1998 Ulrich Weigand
+ */
+
+#include <unistd.h>
+#include "syslevel.h"
+#include "heap.h"
+#include "stackframe.h"
+#include "debug.h"
+
+static CRITICAL_SECTION Win16Mutex;
+static SEGPTR segpWin16Mutex;
+
+
+/************************************************************************
+ *           SYSLEVEL_Init
+ */
+void SYSLEVEL_Init(void)
+{
+    CRITICAL_SECTION **w16Mutex = SEGPTR_ALLOC(sizeof(CRITICAL_SECTION *));
+
+    *w16Mutex = &Win16Mutex;
+    segpWin16Mutex = SEGPTR_GET(w16Mutex);
+
+    InitializeCriticalSection(&Win16Mutex);
+}
+
+/************************************************************************
+ *           GetpWin16Lock32    (KERNEL32.93)
+ */
+VOID WINAPI GetpWin16Lock32(CRITICAL_SECTION **lock)
+{
+    *lock = &Win16Mutex;
+}
+
+/************************************************************************
+ *           GetpWin16Lock16    (KERNEL.449)
+ */
+SEGPTR WINAPI GetpWin16Lock16(void) 
+{ 
+    return segpWin16Mutex;
+}
+
+/************************************************************************
+ *           _EnterSysLevel    (KERNEL32.97)
+ */
+VOID WINAPI _EnterSysLevel(CRITICAL_SECTION *lock)
+{
+    EnterCriticalSection(lock);
+}
+
+/************************************************************************
+ *           _LeaveSysLevel    (KERNEL32.98)
+ */
+VOID WINAPI _LeaveSysLevel(CRITICAL_SECTION *lock)
+{
+    LeaveCriticalSection(lock);
+}
+
+/************************************************************************
+ *           (KERNEL32.86)
+ */
+VOID WINAPI _KERNEL32_86(CRITICAL_SECTION *lock)
+{
+    _LeaveSysLevel(lock);
+}
+
+/************************************************************************
+ *           SYSLEVEL_EnterWin16Lock
+ */
+VOID SYSLEVEL_EnterWin16Lock(VOID)
+{
+    TRACE(win32, "thread %04x (pid %d) about to enter\n", 
+          THREAD_Current()->teb_sel, getpid());
+
+    _EnterSysLevel(&Win16Mutex);
+
+    TRACE(win32, "thread %04x (pid %d) entered, count is %ld\n",
+          THREAD_Current()->teb_sel, getpid(), Win16Mutex.RecursionCount);
+}
+
+/************************************************************************
+ *           SYSLEVEL_LeaveWin16Lock
+ */
+VOID SYSLEVEL_LeaveWin16Lock(VOID)
+{
+    TRACE(win32, "thread %04x (pid %d) about to leave, count is %ld\n", 
+          THREAD_Current()->teb_sel, getpid(), Win16Mutex.RecursionCount);
+
+    _LeaveSysLevel(&Win16Mutex);
+}
+
+/************************************************************************
+ *           _CheckNotSysLevel    (KERNEL32.94)
+ */
+VOID WINAPI _CheckNotSysLevel(CRITICAL_SECTION *lock)
+{
+    FIXME(win32, "()\n");
+}
+
+/************************************************************************
+ *           _ConfirmSysLevel    (KERNEL32.95)
+ */
+VOID WINAPI _ConfirmSysLevel(CRITICAL_SECTION *lock)
+{
+    FIXME(win32, "()\n");
+}
+
+/************************************************************************
+ *           _ConfirmWin16Lock    (KERNEL32.96)
+ */
+DWORD WINAPI _ConfirmWin16Lock(void)
+{
+    FIXME(win32, "()\n");
+    return 1;
+}
+
+/************************************************************************
+ *           ReleaseThunkLock    (KERNEL32.48)
+ */
+VOID WINAPI ReleaseThunkLock(DWORD *mutex_count)
+{
+    DWORD count = Win16Mutex.RecursionCount;
+    *mutex_count = count;
+
+    while (count-- > 0)
+        _LeaveSysLevel(&Win16Mutex);
+}
+
+/************************************************************************
+ *           RestoreThunkLock    (KERNEL32.49)
+ */
+VOID WINAPI RestoreThunkLock(DWORD mutex_count)
+{
+    while (mutex_count-- > 0)
+        _EnterSysLevel(&Win16Mutex);
+}
+
+/************************************************************************
+ *           SYSLEVEL_ReleaseWin16Lock
+ */
+VOID SYSLEVEL_ReleaseWin16Lock(VOID)
+{
+    DWORD count;
+
+    TRACE(win32, "thread %04x (pid %d) about to release, count is %ld\n", 
+          THREAD_Current()->teb_sel, getpid(), Win16Mutex.RecursionCount);
+
+    ReleaseThunkLock(&count);
+
+    if (count > 0xffff)
+        ERR(win32, "Win16Mutex recursion count too large!\n");
+
+    CURRENT_STACK16->mutex_count = (WORD)count;
+}
+
+/************************************************************************
+ *           SYSLEVEL_RestoreWin16Lock
+ */
+VOID SYSLEVEL_RestoreWin16Lock(VOID)
+{
+    DWORD count = CURRENT_STACK16->mutex_count;
+
+    if (!count)
+        ERR(win32, "Win16Mutex recursion count is zero!\n");
+
+    TRACE(win32, "thread %04x (pid %d) about to restore (count %ld)\n", 
+          THREAD_Current()->teb_sel, getpid(), count);
+
+    RestoreThunkLock(count);
+
+    TRACE(win32, "thread %04x (pid %d) restored lock, count is %ld\n", 
+          THREAD_Current()->teb_sel, getpid(), Win16Mutex.RecursionCount);
+}
+
diff --git a/scheduler/thread.c b/scheduler/thread.c
index e881e05..2fabdbc 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -15,6 +15,7 @@
 #include "miscemu.h"
 #include "winnt.h"
 #include "server.h"
+#include "stackframe.h"
 #include "debug.h"
 
 #ifndef __i386__
@@ -50,17 +51,18 @@
  * Return a pointer to a thread object. The object count must be decremented
  * when no longer used.
  */
-THDB *THREAD_GetPtr( HANDLE32 handle, DWORD access )
+THDB *THREAD_GetPtr( HANDLE32 handle, DWORD access, int *server_handle )
 {
     THDB *thread;
 
     if (handle == CURRENT_THREAD_PSEUDOHANDLE)  /* Self-thread handle */
     {
         thread = THREAD_Current();
+        if (server_handle) *server_handle = CURRENT_THREAD_PSEUDOHANDLE;
         K32OBJ_IncCount( &thread->header );
     }
     else thread = (THDB *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
-                                            K32OBJ_THREAD, access );
+                                            K32OBJ_THREAD, access, server_handle );
     return thread;
 }
 
@@ -134,6 +136,7 @@
  *           THREAD_Create
  */
 THDB *THREAD_Create( PDB32 *pdb, DWORD stack_size, BOOL32 alloc_stack16,
+                     int *server_thandle, int *server_phandle,
                      LPTHREAD_START_ROUTINE start_addr, LPVOID param )
 {
     DWORD old_prot;
@@ -194,7 +197,8 @@
                                                    0x10000, SEGMENT_DATA,
                                                    FALSE, FALSE );
         if (!thdb->teb.stack_sel) goto error;
-        thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( thdb->teb.stack_sel, 0xfffc );
+        thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( thdb->teb.stack_sel, 
+                                                 0x10000 - sizeof(STACK16FRAME) );
     }
 
     /* Allocate the event */
@@ -203,7 +207,11 @@
 
     /* Create the thread socket */
 
-    if (CLIENT_NewThread( thdb )) goto error;
+    if (CLIENT_NewThread( thdb, server_thandle, server_phandle )) goto error;
+
+    /* Add thread to process's list of threads */
+
+    THREAD_AddQueue( &pdb->thread_list, thdb );
 
     /* Initialize the thread context */
 
@@ -316,20 +324,36 @@
 
 
 /***********************************************************************
+ *           THREAD_Start
+ *
+ * Start execution of a newly created thread. Does not return.
+ */
+void THREAD_Start( THDB *thdb )
+{
+    LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
+    assert( THREAD_Current() == thdb );
+    CLIENT_InitThread();
+    PE_InitializeDLLs( thdb->process, DLL_THREAD_ATTACH, NULL );
+    ExitThread( func( thdb->entry_arg ) );
+}
+
+
+/***********************************************************************
  *           CreateThread   (KERNEL32.63)
  */
 HANDLE32 WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
                               LPTHREAD_START_ROUTINE start, LPVOID param,
                               DWORD flags, LPDWORD id )
 {
+    int server_handle = -1;
     HANDLE32 handle = INVALID_HANDLE_VALUE32;
     BOOL32 inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
 
     THDB *thread = THREAD_Create( PROCESS_Current(), stack,
-                                  TRUE, start, param );
+                                  TRUE, &server_handle, NULL, start, param );
     if (!thread) return INVALID_HANDLE_VALUE32;
     handle = HANDLE_Alloc( PROCESS_Current(), &thread->header,
-                           THREAD_ALL_ACCESS, inherit );
+                           THREAD_ALL_ACCESS, inherit, server_handle );
     if (handle == INVALID_HANDLE_VALUE32) goto error;
     if (SYSDEPS_SpawnThread( thread ) == -1) goto error;
     *id = THDB_TO_THREAD_ID( thread );
@@ -354,6 +378,11 @@
     THDB *thdb = THREAD_Current();
     LONG count;
 
+    /* Remove thread from process's list */
+    THREAD_RemoveQueue( &thdb->process->thread_list, thdb );
+
+    PE_InitializeDLLs( thdb->process, DLL_THREAD_DETACH, NULL );
+
     SYSTEM_LOCK();
     thdb->exit_code = code;
     EVENT_Set( thdb->event );
@@ -407,7 +436,9 @@
 DWORD WINAPI GetLastError(void)
 {
     THDB *thread = THREAD_Current();
-    return thread->last_error;
+    DWORD ret = thread->last_error;
+    TRACE(thread,"0x%lx\n",ret);
+    return ret;
 }
 
 
@@ -422,7 +453,11 @@
 {
     THDB *thread = THREAD_Current();
     /* This one must work before we have a thread (FIXME) */
-    if (thread) thread->last_error = error;
+
+    TRACE(thread,"%p error=0x%lx\n",thread,error);
+
+    if (thread)
+      thread->last_error = error;
 }
 
 
@@ -436,7 +471,7 @@
     DWORD error, /* [in] Per-thread error code */
     DWORD type)  /* [in] Error type */
 {
-    TRACE(thread, "(%08lx, %08lx)\n", error,type);
+    TRACE(thread, "(0x%08lx, 0x%08lx)\n", error,type);
     switch(type) {
         case 0:
             break;
@@ -584,7 +619,7 @@
     HANDLE32 handle,  /* [in]  Handle to thread with context */
     CONTEXT *context) /* [out] Address of context structure */
 {
-    THDB *thread = THREAD_GetPtr( handle, THREAD_GET_CONTEXT );
+    THDB *thread = THREAD_GetPtr( handle, THREAD_GET_CONTEXT, NULL );
     if (!thread) return FALSE;
     *context = thread->context;
     K32OBJ_DecCount( &thread->header );
@@ -602,7 +637,7 @@
     HANDLE32 handle,  /* [in]  Handle to thread with context */
     CONTEXT *context) /* [out] Address of context structure */
 {
-    THDB *thread = THREAD_GetPtr( handle, THREAD_GET_CONTEXT );
+    THDB *thread = THREAD_GetPtr( handle, THREAD_GET_CONTEXT, NULL );
     if (!thread) return FALSE;
     *context = thread->context;
     K32OBJ_DecCount( &thread->header );
@@ -623,7 +658,7 @@
     THDB *thread;
     INT32 ret;
     
-    if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION )))
+    if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION, NULL )))
         return THREAD_PRIORITY_ERROR_RETURN;
     ret = thread->delta_priority;
     K32OBJ_DecCount( &thread->header );
@@ -644,7 +679,7 @@
 {
     THDB *thread;
     
-    if (!(thread = THREAD_GetPtr( hthread, THREAD_SET_INFORMATION )))
+    if (!(thread = THREAD_GetPtr( hthread, THREAD_SET_INFORMATION, NULL )))
         return FALSE;
     thread->delta_priority = priority;
     K32OBJ_DecCount( &thread->header );
@@ -682,7 +717,7 @@
 {
     THDB *thread;
     
-    if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION )))
+    if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION, NULL )))
         return FALSE;
     if (exitcode) *exitcode = thread->exit_code;
     K32OBJ_DecCount( &thread->header );
@@ -708,7 +743,7 @@
     DWORD oldcount;
 
     SYSTEM_LOCK();
-    if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION )))
+    if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION, NULL )))
     {
         SYSTEM_UNLOCK();
         WARN(thread, "Invalid thread handle\n");
@@ -746,7 +781,7 @@
     DWORD oldcount;
 
     SYSTEM_LOCK();
-    if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION )))
+    if (!(thread = THREAD_GetPtr( hthread, THREAD_QUERY_INFORMATION, NULL )))
     {
         SYSTEM_UNLOCK();
         WARN(thread, "Invalid thread handle\n");
diff --git a/server/Makefile.in b/server/Makefile.in
index 1881c52..01b67f1 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -8,8 +8,10 @@
 C_SRCS = \
 	object.c \
 	process.c \
+	request.c \
 	socket.c \
-	thread.c
+	thread.c \
+	trace.c
 
 EXTRA_SRCS = main.c
 MAIN_OBJS = main.o
@@ -21,6 +23,6 @@
 @MAKE_RULES@
 
 wineserver: $(OBJS) $(MAIN_OBJS)
-	gcc -o $(PROGRAMS) $(OBJS) $(MAIN_OBJS)
+	$(CC) -o $(PROGRAMS) $(OBJS) $(MAIN_OBJS) $(LIBS)
 
 ### Dependencies:
diff --git a/server/main.c b/server/main.c
index a596a76..d7f06c9 100644
--- a/server/main.c
+++ b/server/main.c
@@ -11,10 +11,12 @@
 #include <unistd.h>
 
 #include "server.h"
+#include "server/object.h"
 
 int main( int argc, char *argv[] )
 {
     int fd;
+    extern void server_main_loop( int fd );
 
     if (argc != 2) goto error;
     if (!isdigit( *argv[1] )) goto error;
@@ -22,9 +24,11 @@
     /* make sure the fd is valid */
     if (fcntl( fd, F_GETFL, 0 ) == -1) goto error;
 
-    fprintf( stderr, "Server: starting (pid=%d)\n", getpid() );
+    debug_level = 1;
+
+    if (debug_level) printf( "Server: starting (pid=%d)\n", getpid() );
     server_main_loop( fd );
-    fprintf( stderr, "Server: exiting (pid=%d)\n", getpid() );
+    if (debug_level) printf( "Server: exiting (pid=%d)\n", getpid() );
     exit(0);
 
  error:    
diff --git a/server/object.c b/server/object.c
index 3724761..17a6843 100644
--- a/server/object.c
+++ b/server/object.c
@@ -6,11 +6,15 @@
  */
 
 #include <assert.h>
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "server.h"
-#include "object.h"
+
+#include "server/object.h"
+
+int debug_level = 0;
 
 struct object_name
 {
@@ -69,7 +73,16 @@
     else obj->name = add_name( obj, name );
 }
 
-/* release an object (i.e. decrement its refcount */
+/* grab an object (i.e. increment its refcount) and return the object */
+struct object *grab_object( void *ptr )
+{
+    struct object *obj = (struct object *)ptr;
+    assert( obj->refcount < INT_MAX );
+    obj->refcount++;
+    return obj;
+}
+
+/* release an object (i.e. decrement its refcount) */
 void release_object( void *ptr )
 {
     struct object *obj = (struct object *)ptr;
@@ -88,7 +101,6 @@
     struct object_name *ptr = names[hash];
     while (ptr && strcmp( ptr->name, name )) ptr = ptr->next;
     if (!ptr) return NULL;
-    ptr->obj->refcount++;
+    grab_object( ptr->obj );
     return ptr->obj;
 }
-
diff --git a/server/object.h b/server/object.h
deleted file mode 100644
index c9f6abe..0000000
--- a/server/object.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Wine server objects
- *
- * Copyright (C) 1998 Alexandre Julliard
- */
-
-#ifndef __WINE_OBJECT_H
-#define __WINE_OBJECT_H
-
-#include <sys/time.h>
-
-struct object;
-struct object_name;
-
-struct object_ops
-{
-    void (*destroy)(struct object *);    /* destroy on refcount == 0 */
-};
-
-struct object
-{
-    unsigned int              refcount;
-    const struct object_ops  *ops;
-    struct object_name       *name;
-};
-
-extern void init_object( struct object *obj, const struct object_ops *ops,
-                         const char *name );
-/* release object can take any pointer, but you better make sure that */
-/* the thing pointed to starts with a struct object... */
-extern void release_object( void *obj );
-
-/* request handlers */
-
-struct thread;
-typedef void (*req_handler)( void *data, int len, int fd, struct thread *self);
-extern const req_handler req_handlers[REQ_NB_REQUESTS];
-
-/* socket functions */
-
-extern int add_client( int client_fd, struct thread *self );
-extern void remove_client( int client_fd );
-extern int get_initial_client_fd(void);
-extern void set_timeout( int client_fd, struct timeval *when );
-extern int send_reply( int client_fd, int err_code, int pass_fd,
-                       int n, ... /* arg_1, len_1, ..., arg_n, len_n */ );
-
-/* process functions */
-
-struct process;
-
-extern struct process *create_process(void);
-extern struct process *get_process_from_id( void *id );
-
-#endif  /* __WINE_OBJECT_H */
diff --git a/server/process.c b/server/process.c
index 95690db..b3adcb2 100644
--- a/server/process.c
+++ b/server/process.c
@@ -5,29 +5,61 @@
  */
 
 #include <assert.h>
+#include <limits.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "winerror.h"
+#include "winbase.h"
+#include "winnt.h"
 
 #include "server.h"
-#include "object.h"
+#include "server/thread.h"
 
+/* reserved handle access rights */
+#define RESERVED_SHIFT         25
+#define RESERVED_INHERIT       (HANDLE_FLAG_INHERIT << RESERVED_SHIFT)
+#define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT)
+#define RESERVED_ALL           (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
+
+struct handle_entry
+{
+    struct object *ptr;
+    unsigned int   access;
+};
 
 /* process structure; not much for now... */
 
 struct process
 {
-    struct object   obj;       /* object header */
-    struct process *next;      /* system-wide process list */
-    struct process *prev;
+    struct object        obj;             /* object header */
+    struct process      *next;            /* system-wide process list */
+    struct process      *prev;
+    struct thread       *thread_list;     /* head of the thread list */
+    struct handle_entry *entries;         /* handle entry table */
+    int                  handle_count;    /* nb of allocated handle entries */
+    int                  handle_last;     /* last used handle entry */
+    int                  exit_code;       /* process exit code */
+    int                  running_threads; /* number of threads running in this process */
+    struct timeval       start_time;      /* absolute time at process start */
+    struct timeval       end_time;        /* absolute time at process end */
 };
 
 static struct process *first_process;
 
+#define MIN_HANDLE_ENTRIES  32
+
 /* process operations */
 
+static void dump_process( struct object *obj, int verbose );
 static void destroy_process( struct object *obj );
+static void free_handles( struct process *process );
 
 static const struct object_ops process_ops =
 {
+    dump_process,
     destroy_process
 };
 
@@ -35,12 +67,29 @@
 struct process *create_process(void)
 {
     struct process *process;
+    struct handle_entry *entries;
 
     if (!(process = malloc( sizeof(*process) ))) return NULL;
+    if (!(entries = malloc( MIN_HANDLE_ENTRIES * sizeof(struct handle_entry))))
+    {
+        free( process );
+        return NULL;
+    }
     init_object( &process->obj, &process_ops, NULL );
-    process->next = first_process;
-    process->prev = NULL;
+    process->next            = first_process;
+    process->prev            = NULL;
+    process->thread_list     = NULL;
+    process->exit_code       = 0x103;  /* STILL_ACTIVE */
+    process->running_threads = 0;
+    process->handle_count    = MIN_HANDLE_ENTRIES;
+    process->handle_last     = -1;
+    process->entries         = entries;
+
+    if (first_process) first_process->prev = process;
     first_process = process;
+
+    gettimeofday( &process->start_time, NULL );
+    alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
     return process;
 }
 
@@ -50,17 +99,316 @@
     struct process *process = (struct process *)obj;
     assert( obj->ops == &process_ops );
 
+    /* we can't have a thread remaining */
+    assert( !process->thread_list );
     if (process->next) process->next->prev = process->prev;
     if (process->prev) process->prev->next = process->next;
     else first_process = process->next;
+    free_handles( process );
     free( process );
 }
 
+/* dump a process on stdout for debugging purposes */
+static void dump_process( struct object *obj, int verbose )
+{
+    struct process *process = (struct process *)obj;
+    assert( obj->ops == &process_ops );
+
+    printf( "Process next=%p prev=%p\n", process->next, process->prev );
+}
+
 /* get a process from an id (and increment the refcount) */
 struct process *get_process_from_id( void *id )
 {
     struct process *p = first_process;
     while (p && (p != id)) p = p->next;
-    if (p) p->obj.refcount++;
+    if (p) grab_object( p );
+    else SET_ERROR( ERROR_INVALID_PARAMETER );
     return p;
 }
+
+/* get a process from a handle (and increment the refcount) */
+struct process *get_process_from_handle( int handle, unsigned int access )
+{
+    return (struct process *)get_handle_obj( current->process, handle,
+                                             access, &process_ops );
+}
+
+/* a process has been killed (i.e. its last thread died) */
+static void process_killed( struct process *process, int exit_code )
+{
+    assert( !process->thread_list );
+    process->exit_code = exit_code;
+    gettimeofday( &process->end_time, NULL );
+    free_handles( process );
+}
+
+/* free the process handle entries */
+static void free_handles( struct process *process )
+{
+    struct handle_entry *entry;
+    int handle;
+
+    if (!(entry = process->entries)) return;
+    for (handle = 0; handle <= process->handle_last; handle++, entry++)
+    {
+        struct object *obj = entry->ptr;
+        entry->ptr = NULL;
+        if (obj) release_object( obj );
+    }
+    free( process->entries );
+    process->handle_count = 0;
+    process->handle_last  = -1;
+    process->entries = NULL;
+}
+
+/* add a thread to a process running threads list */
+void add_process_thread( struct process *process, struct thread *thread )
+{
+    thread->proc_next = process->thread_list;
+    thread->proc_prev = NULL;
+    if (thread->proc_next) thread->proc_next->proc_prev = thread;
+    process->thread_list = thread;
+    process->running_threads++;
+    grab_object( thread );
+}
+
+/* remove a thread from a process running threads list */
+void remove_process_thread( struct process *process, struct thread *thread )
+{
+    assert( process->running_threads > 0 );
+    assert( process->thread_list );
+
+    if (thread->proc_next) thread->proc_next->proc_prev = thread->proc_prev;
+    if (thread->proc_prev) thread->proc_prev->proc_next = thread->proc_next;
+    else process->thread_list = thread->proc_next;
+
+    if (!--process->running_threads)
+    {
+        /* we have removed the last running thread, exit the process */
+        process_killed( process, thread->exit_code );
+    }
+    release_object( thread );
+}
+
+/* grow a handle table */
+/* return 1 if OK, 0 on error */
+static int grow_handle_table( struct process *process )
+{
+    struct handle_entry *new_entries;
+    int count = process->handle_count;
+
+    if (count >= INT_MAX / 2) return 0;
+    count *= 2;
+    if (!(new_entries = realloc( process->entries, count * sizeof(struct handle_entry) )))
+    {
+        SET_ERROR( ERROR_NOT_ENOUGH_MEMORY );
+        return 0;
+    }
+    process->handle_count = count;
+    process->entries      = new_entries;
+    return 1;
+}
+
+/* allocate a handle for an object, incrementing its refcount */
+/* return the handle, or -1 on error */
+int alloc_handle( struct process *process, void *obj, unsigned int access,
+                  int inherit )
+{
+    struct handle_entry *entry;
+    int handle;
+
+    assert( !(access & RESERVED_ALL) );
+    if (inherit) access |= RESERVED_INHERIT;
+
+    /* find the first free entry */
+
+    if (!(entry = process->entries)) return -1;
+    for (handle = 0; handle <= process->handle_last; handle++, entry++)
+        if (!entry->ptr) goto found;
+
+    if (handle >= process->handle_count)
+    {
+        if (!grow_handle_table( process )) return -1;
+        entry = process->entries + handle;  /* the table may have moved */
+    }
+    process->handle_last = handle;
+
+ found:
+    entry->ptr    = grab_object( obj );
+    entry->access = access;
+    return handle + 1;  /* avoid handle 0 */
+}
+
+/* allocate a specific handle for an object, incrementing its refcount */
+static int alloc_specific_handle( struct process *process, void *obj, int handle,
+                                  unsigned int access, int inherit )
+{
+    struct handle_entry *entry;
+    struct object *old;
+
+    if (handle == -1) return alloc_handle( process, obj, access, inherit );
+
+    assert( !(access & RESERVED_ALL) );
+    if (inherit) access |= RESERVED_INHERIT;
+
+    handle--;  /* handles start at 1 */
+    if ((handle < 0) || (handle > process->handle_last))
+    {
+        SET_ERROR( ERROR_INVALID_HANDLE );
+        return -1;
+    }
+    entry = process->entries + handle;
+
+    old = entry->ptr;
+    entry->ptr = grab_object( obj );
+    entry->access = access;
+    if (old) release_object( old );
+    return handle + 1;
+}
+
+/* return an handle entry, or NULL if the handle is invalid */
+static struct handle_entry *get_handle( struct process *process, int handle )
+{
+    struct handle_entry *entry;
+
+    handle--;  /* handles start at 1 */
+    if ((handle < 0) || (handle > process->handle_last)) goto error;
+    entry = process->entries + handle;
+    if (!entry->ptr) goto error;
+    return entry;
+
+ error:
+    SET_ERROR( ERROR_INVALID_HANDLE );
+    return NULL;
+}
+
+/* attempt to shrink a table */
+/* return 1 if OK, 0 on error */
+static int shrink_handle_table( struct process *process )
+{
+    struct handle_entry *new_entries;
+    struct handle_entry *entry = process->entries + process->handle_last;
+    int count = process->handle_count;
+
+    while (process->handle_last >= 0)
+    {
+        if (entry->ptr) break;
+        process->handle_last--;
+        entry--;
+    }
+    if (process->handle_last >= count / 4) return 1;  /* no need to shrink */
+    if (count < MIN_HANDLE_ENTRIES * 2) return 1;  /* too small to shrink */
+    count /= 2;
+    if (!(new_entries = realloc( process->entries,
+                                 count * sizeof(struct handle_entry) )))
+        return 0;
+    process->handle_count = count;
+    process->entries      = new_entries;
+    return 1;
+}
+
+/* close a handle and decrement the refcount of the associated object */
+/* return 1 if OK, 0 on error */
+int close_handle( struct process *process, int handle )
+{
+    struct handle_entry *entry;
+    struct object *obj;
+
+    if (!(entry = get_handle( process, handle ))) return 0;
+    if (entry->access & RESERVED_CLOSE_PROTECT) return 0;  /* FIXME: error code */
+    obj = entry->ptr;
+    entry->ptr = NULL;
+    if (handle-1 == process->handle_last) shrink_handle_table( process );
+    release_object( obj );
+    return 1;
+}
+
+/* retrieve the object corresponding to a handle, incrementing its refcount */
+struct object *get_handle_obj( struct process *process, int handle,
+                               unsigned int access, const struct object_ops *ops )
+{
+    struct handle_entry *entry;
+    struct object *obj;
+
+    switch( handle )
+    {
+    case 0xfffffffe:  /* current thread pseudo-handle */
+        obj = &current->obj;
+        break;
+    case 0x7fffffff:  /* current process pseudo-handle */
+        obj = (struct object *)current->process;
+        break;
+    default:
+        if (!(entry = get_handle( process, handle ))) return NULL;
+        if ((entry->access & access) != access)
+        {
+            SET_ERROR( ERROR_ACCESS_DENIED );
+            return NULL;
+        }
+        obj = entry->ptr;
+        break;
+    }
+    if (ops && (obj->ops != ops))
+    {
+        SET_ERROR( ERROR_INVALID_HANDLE );  /* not the right type */
+        return NULL;
+    }
+    return grab_object( obj );
+}
+
+/* get/set the handle reserved flags */
+/* return the new flags (or -1 on error) */
+int set_handle_info( struct process *process, int handle, int mask, int flags )
+{
+    struct handle_entry *entry;
+
+    if (!(entry = get_handle( process, handle ))) return -1;
+    mask  = (mask << RESERVED_SHIFT) & RESERVED_ALL;
+    flags = (flags << RESERVED_SHIFT) & mask;
+    entry->access = (entry->access & ~mask) | flags;
+    return (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
+}
+
+/* duplicate a handle */
+int duplicate_handle( struct process *src, int src_handle, struct process *dst,
+                      int dst_handle, unsigned int access, int inherit, int options )
+{
+    struct handle_entry *entry = get_handle( src, src_handle );
+    if (!entry) return -1;
+
+    if (options & DUPLICATE_SAME_ACCESS) access = entry->access;
+    access &= ~RESERVED_ALL;
+    return alloc_specific_handle( dst, entry->ptr, dst_handle, access, inherit );
+}
+
+/* dump a handle table on stdout */
+void dump_handles( struct process *process )
+{
+    struct handle_entry *entry;
+    int i;
+
+    if (!process->entries) return;
+    entry = process->entries;
+    for (i = 0; i < process->handle_last; i++, entry++)
+    {
+        if (!entry->ptr) continue;
+        printf( "%5d: %p %08x ", i + 1, entry->ptr, entry->access );
+        entry->ptr->ops->dump( entry->ptr, 0 );
+    }
+}
+
+/* kill a process on the spot */
+void kill_process( struct process *process, int exit_code )
+{
+    while (process->thread_list)
+        kill_thread( process->thread_list, exit_code );
+}
+
+/* get all information about a process */
+void get_process_info( struct process *process,
+                       struct get_process_info_reply *reply )
+{
+    reply->pid       = process;
+    reply->exit_code = process->exit_code;
+}
diff --git a/server/request.c b/server/request.c
new file mode 100644
index 0000000..397fe4f
--- /dev/null
+++ b/server/request.c
@@ -0,0 +1,228 @@
+/*
+ * Server-side request handling
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include "winerror.h"
+#include "winnt.h"
+#include "winbase.h"
+#define WANT_REQUEST_HANDLERS
+#include "server.h"
+#include "server/request.h"
+#include "server/thread.h"
+
+
+struct thread *current = NULL;  /* thread handling the current request */
+
+/* complain about a protocol error and terminate the client connection */
+static void fatal_protocol_error( const char *err, ... )
+{
+    va_list args;
+
+    va_start( args, err );
+    fprintf( stderr, "Protocol error:%p: ", current );
+    vfprintf( stderr, err, args );
+    va_end( args );
+    remove_client( current->client_fd, -2 );
+}
+
+/* call a request handler */
+void call_req_handler( struct thread *thread, enum request req,
+                       void *data, int len, int fd )
+{
+    const struct handler *handler = &req_handlers[req];
+    char *ptr;
+
+    current = thread;
+    if ((req < 0) || (req >= REQ_NB_REQUESTS))
+    {
+        fatal_protocol_error( "unknown request %d\n", req );
+        return;
+    }
+
+    if (len < handler->min_size)
+    {
+        fatal_protocol_error( "req %d bad length %d < %d)\n", req, len, handler->min_size );
+        return;
+    }
+
+    /* now call the handler */
+    if (current)
+    {
+        CLEAR_ERROR();
+        if (debug_level) trace_request( req, data, len, fd );
+    }
+    len -= handler->min_size;
+    ptr = (char *)data + handler->min_size;
+    handler->handler( data, ptr, len, fd );
+    current = NULL;
+}
+
+/* handle a client timeout (unused for now) */
+void call_timeout_handler( struct thread *thread )
+{
+    current = thread;
+    if (debug_level) trace_timeout();
+    CLEAR_ERROR();
+    send_reply( current, -1, 0 );
+    current = NULL;
+}
+
+/* a thread has been killed */
+void call_kill_handler( struct thread *thread, int exit_code )
+{
+    /* must be reentrant WRT call_req_handler */
+    struct thread *old_current = current;
+    current = thread;
+    if (current)
+    {
+        if (debug_level) trace_kill( exit_code );
+        thread_killed( current, exit_code );
+    }
+    current = (old_current != thread) ? old_current : NULL;
+}
+
+
+/* create a new thread */
+DECL_HANDLER(new_thread)
+{
+    struct new_thread_reply reply;
+    struct thread *new_thread;
+    int new_fd, err;
+
+    if ((new_fd = dup(fd)) == -1)
+    {
+        new_thread = NULL;
+        err = ERROR_TOO_MANY_OPEN_FILES;
+        goto done;
+    }
+    if (!(new_thread = create_thread( new_fd, req->pid, &reply.thandle,
+                                      &reply.phandle )))
+    {
+        err = ERROR_NOT_ENOUGH_MEMORY;
+        close( new_fd );
+        goto done;
+    }
+    reply.tid = new_thread;
+    reply.pid = new_thread->process;
+    err = ERROR_SUCCESS;
+
+ done:
+    if (!current)
+    {
+        /* first client doesn't have a current */
+        struct iovec vec = { &reply, sizeof(reply) };
+        send_reply_v( get_initial_client_fd(), err, -1, &vec, 1 );
+    }
+    else
+    {
+        SET_ERROR( err );
+        send_reply( current, -1, 1, &reply, sizeof(reply) );
+    }
+}
+
+/* create a new thread */
+DECL_HANDLER(init_thread)
+{
+    current->unix_pid = req->unix_pid;
+    if (!(current->name = malloc( len + 1 )))
+    {
+        SET_ERROR( ERROR_NOT_ENOUGH_MEMORY );
+        goto done;
+    }
+    memcpy( current->name, data, len );
+    current->name[len] = '\0';
+    CLEAR_ERROR();
+ done:
+    send_reply( current, -1, 0 );
+}
+
+/* terminate a process */
+DECL_HANDLER(terminate_process)
+{
+    struct process *process;
+
+    if ((process = get_process_from_handle( req->handle, PROCESS_TERMINATE )))
+    {
+        kill_process( process, req->exit_code );
+        release_object( process );
+    }
+    if (current) send_reply( current, -1, 0 );
+}
+
+/* terminate a thread */
+DECL_HANDLER(terminate_thread)
+{
+    struct thread *thread;
+
+    if ((thread = get_thread_from_handle( req->handle, THREAD_TERMINATE )))
+    {
+        kill_thread( thread, req->exit_code );
+        release_object( thread );
+    }
+    if (current) send_reply( current, -1, 0 );
+}
+
+/* close a handle */
+DECL_HANDLER(close_handle)
+{
+    close_handle( current->process, req->handle );
+    send_reply( current, -1, 0 );
+}
+
+/* duplicate a handle */
+DECL_HANDLER(dup_handle)
+{
+    struct dup_handle_reply reply = { -1 };
+    struct process *src, *dst;
+
+    if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
+    {
+        if ((dst = get_process_from_handle( req->dst_process, PROCESS_DUP_HANDLE )))
+        {
+            reply.handle = duplicate_handle( src, req->src_handle, dst, req->dst_handle,
+                                             req->access, req->inherit, req->options );
+            release_object( dst );
+        }
+        /* close the handle no matter what happened */
+        if (req->options & DUPLICATE_CLOSE_SOURCE)
+            close_handle( src, req->src_handle );
+        release_object( src );
+    }
+    send_reply( current, -1, 1, &reply, sizeof(reply) );
+}
+
+/* fetch information about a process */
+DECL_HANDLER(get_process_info)
+{
+    struct process *process;
+    struct get_process_info_reply reply = { 0, 0 };
+
+    if ((process = get_process_from_handle( req->handle, PROCESS_QUERY_INFORMATION )))
+    {
+        get_process_info( process, &reply );
+        release_object( process );
+    }
+    send_reply( current, -1, 1, &reply, sizeof(reply) );
+}
+
+/* open a handle a process */
+DECL_HANDLER(open_process)
+{
+    struct open_process_reply reply = { -1 };
+    struct process *process = get_process_from_id( req->pid );
+    if (process)
+    {
+        reply.handle = alloc_handle( current->process, process,
+                                     req->access, req->inherit );
+        release_object( process );
+    }
+    send_reply( current, -1, 1, &reply, sizeof(reply) );
+}
diff --git a/server/socket.c b/server/socket.c
index 3dd73c9..5d96a93 100644
--- a/server/socket.c
+++ b/server/socket.c
@@ -20,7 +20,8 @@
 
 #include "config.h"
 #include "server.h"
-#include "object.h"
+
+#include "server/object.h"
 
 /* Some versions of glibc don't define this */
 #ifndef SCM_RIGHTS
@@ -67,6 +68,11 @@
 static struct timeout *timeout_head;        /* sorted timeouts list head */
 static struct timeout *timeout_tail;        /* sorted timeouts list tail */
 
+/* exit code passed to remove_client */
+#define OUT_OF_MEMORY  -1
+#define BROKEN_PIPE    -2
+#define PROTOCOL_ERROR -3
+
 
 /* signal a client protocol error */
 static void protocol_error( int client_fd, const char *err, ... )
@@ -81,7 +87,7 @@
 
 
 /* send a message to a client that is ready to receive something */
-static int do_write( int client_fd )
+static void do_write( int client_fd )
 {
     struct client *client = clients[client_fd];
     struct iovec vec[2];
@@ -124,14 +130,15 @@
     if (ret == -1)
     {
         if (errno != EPIPE) perror("sendmsg");
-        return -1;
+        remove_client( client_fd, BROKEN_PIPE );
+        return;
     }
     if (client->pass_fd != -1)  /* We sent the fd, now we can close it */
     {
         close( client->pass_fd );
         client->pass_fd = -1;
     }
-    if ((client->count += ret) < client->head.len) return 0;
+    if ((client->count += ret) < client->head.len) return;
 
     /* we have finished with this message */
     if (client->data) free( client->data );
@@ -141,12 +148,11 @@
     client->seq++;
     FD_CLR( client_fd, &write_set );
     FD_SET( client_fd, &read_set );
-    return 0;
 }
 
 
 /* read a message from a client that has something to say */
-static int do_read( int client_fd )
+static void do_read( int client_fd )
 {
     struct client *client = clients[client_fd];
     struct iovec vec;
@@ -171,7 +177,10 @@
     {
         if (!client->data &&
             !(client->data = malloc(client->head.len-sizeof(client->head))))
-            return -1;
+        {
+            remove_client( client_fd, OUT_OF_MEMORY );
+            return;
+        }
         vec.iov_base = client->data + client->count - sizeof(client->head);
         vec.iov_len  = client->head.len - client->count;
     }
@@ -180,7 +189,8 @@
     if (ret == -1)
     {
         perror("recvmsg");
-        return -1;
+        remove_client( client_fd, BROKEN_PIPE );
+        return;
     }
 #ifndef HAVE_MSGHDR_ACCRIGHTS
     pass_fd = cmsg.fd;
@@ -191,26 +201,32 @@
         if (client->pass_fd != -1) close( client->pass_fd );
         client->pass_fd = pass_fd;
     }
-    else if (!ret) return -1;  /* closed pipe */
+    else if (!ret)  /* closed pipe */
+    {
+        remove_client( client_fd, BROKEN_PIPE );
+        return;
+    }
 
     client->count += ret;
 
     /* received the complete header yet? */
-    if (client->count < sizeof(client->head)) return 0;
+    if (client->count < sizeof(client->head)) return;
 
     /* sanity checks */
     if (client->head.seq != client->seq)
     {
         protocol_error( client_fd, "bad sequence %08x instead of %08x\n",
                         client->head.seq, client->seq );
-        return -1;
+        remove_client( client_fd, PROTOCOL_ERROR );
+        return;
     }
     if ((client->head.len < sizeof(client->head)) ||
         (client->head.len > MAX_MSG_LENGTH + sizeof(client->head)))
     {
         protocol_error( client_fd, "bad header length %08x\n",
                         client->head.len );
-        return -1;
+        remove_client( client_fd, PROTOCOL_ERROR );
+        return;
     }
 
     /* received the whole message? */
@@ -218,17 +234,10 @@
     {
         /* done reading the data, call the callback function */
 
+        int len = client->head.len - sizeof(client->head);
         char *data = client->data;
         int passed_fd = client->pass_fd;
-        unsigned short type = client->head.type;
-        unsigned short len  = client->head.len - sizeof(client->head);
-
-        if ((type >= REQ_NB_REQUESTS) || !req_handlers[client->head.type])
-        {
-            protocol_error( client_fd, "unknown request %08x\n",
-                            client->head.type );
-            return -1;
-        }
+        enum request type = client->head.type;
 
         /* clear the info now, as the client may be deleted by the callback */
         client->head.len  = 0;
@@ -239,57 +248,19 @@
         client->state     = WAITING;
         client->seq++;
 
-        req_handlers[type]( data, len, passed_fd, client->self );
+        call_req_handler( client->self, type, data, len, passed_fd );
         if (passed_fd != -1) close( passed_fd );
         if (data) free( data );
     }
-    return 0;
 }
 
 
 /* handle a client timeout */
-static int do_timeout( int client_fd )
+static void do_timeout( int client_fd )
 {
     struct client *client = clients[client_fd];
     set_timeout( client_fd, 0 );  /* Remove the timeout */
-    req_handlers[REQ_TIMEOUT]( NULL, 0, -1, client->self );
-    return 0;
-}
-
-
-/* send a reply to a client */
-static int send_reply_v( int client_fd, int type, int pass_fd,
-                         struct iovec *vec, int veclen )
-{
-    int i;
-    unsigned int len;
-    char *p;
-    struct client *client = clients[client_fd];
-
-    assert( client );
-    assert( client->state == WAITING );
-    assert( !client->data );
-
-    for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
-    assert( len < MAX_MSG_LENGTH );
-
-    if (len && !(client->data = malloc( len ))) return -1;
-    client->count     = 0;
-    client->head.len  = len + sizeof(client->head);
-    client->head.type = type;
-    client->head.seq  = client->seq;
-    client->pass_fd   = pass_fd;
-
-    for (i = 0, p = client->data; i < veclen; i++)
-    {
-        memcpy( p, vec[i].iov_base, vec[i].iov_len );
-        p += vec[i].iov_len;
-    }
-
-    client->state = READING;
-    FD_CLR( client_fd, &read_set );
-    FD_SET( client_fd, &write_set );
-    return 0;
+    call_timeout_handler( client->self );
 }
 
 
@@ -317,8 +288,7 @@
                 ((timeout_head->when.tv_sec == now.tv_sec) &&
                  (timeout_head->when.tv_usec < now.tv_usec)))
             {
-                int id = timeout_head->client;
-                if (do_timeout( id ) == -1) remove_client( id );
+                do_timeout( timeout_head->client );
                 continue;
             }
             tv.tv_sec = timeout_head->when.tv_sec - now.tv_sec;
@@ -341,13 +311,11 @@
         {
             if (FD_ISSET( i, &write ))
             {
-                if (!clients[i]) continue;
-                if (do_write( i ) == -1) remove_client( i );
+                if (clients[i]) do_write( i );
             }
             else if (FD_ISSET( i, &read ))
             {
-                if (!clients[i]) continue;
-                if (do_read( i ) == -1) remove_client( i );
+                if (clients[i]) do_read( i );
             }
         }
     }
@@ -388,12 +356,12 @@
 }
 
 /* remove a client */
-void remove_client( int client_fd )
+void remove_client( int client_fd, int exit_code )
 {
     struct client *client = clients[client_fd];
     assert( client );
 
-    req_handlers[REQ_KILL_THREAD]( NULL, 0, -1, client->self );
+    call_kill_handler( client->self, exit_code );
 
     set_timeout( client_fd, 0 );
     clients[client_fd] = NULL;
@@ -463,21 +431,40 @@
     }
 }
 
-/* send a reply to a client */
-int send_reply( int client_fd, int err_code, int pass_fd,
-                int n, ... /* arg_1, len_1, ..., arg_n, len_n */ )
-{
-    struct iovec vec[16];
-    va_list args;
-    int i;
 
-    assert( n < 16 );
-    va_start( args, n );
-    for (i = 0; i < n; i++)
+/* send a reply to a client */
+int send_reply_v( int client_fd, int type, int pass_fd,
+                  struct iovec *vec, int veclen )
+{
+    int i;
+    unsigned int len;
+    char *p;
+    struct client *client = clients[client_fd];
+
+    assert( client );
+    assert( client->state == WAITING );
+    assert( !client->data );
+
+    if (debug_level) trace_reply( client->self, type, pass_fd, vec, veclen );
+
+    for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
+    assert( len < MAX_MSG_LENGTH );
+
+    if (len && !(client->data = malloc( len ))) return -1;
+    client->count     = 0;
+    client->head.len  = len + sizeof(client->head);
+    client->head.type = type;
+    client->head.seq  = client->seq;
+    client->pass_fd   = pass_fd;
+
+    for (i = 0, p = client->data; i < veclen; i++)
     {
-        vec[i].iov_base = va_arg( args, void * );
-        vec[i].iov_len  = va_arg( args, int );
+        memcpy( p, vec[i].iov_base, vec[i].iov_len );
+        p += vec[i].iov_len;
     }
-    va_end( args );
-    return send_reply_v( client_fd, err_code, pass_fd, vec, n );
+
+    client->state = READING;
+    FD_CLR( client_fd, &read_set );
+    FD_SET( client_fd, &write_set );
+    return 0;
 }
diff --git a/server/thread.c b/server/thread.c
index d1ce30b..206e1a9 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -6,96 +6,91 @@
 
 #include <assert.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/uio.h>
 #include <unistd.h>
 
+#include "winnt.h"
 #include "winerror.h"
 #include "server.h"
-#include "object.h"
+#include "server/thread.h"
 
 
-/* request handling */
-
-static void handle_timeout( void *data, int len, int fd,
-                            struct thread *self );
-static void handle_kill_thread( void *data, int len, int fd,
-                                struct thread *self );
-static void handle_new_thread( void *data, int len, int fd,
-                               struct thread *self );
-static void handle_init_thread( void *data, int len, int fd,
-                                struct thread *self );
-
-const req_handler req_handlers[REQ_NB_REQUESTS] =
-{
-    handle_timeout,        /* REQ_TIMEOUT */
-    handle_kill_thread,    /* REQ_KILL_THREAD */
-    handle_new_thread,     /* REQ_NEW_THREAD */
-    handle_init_thread     /* REQ_INIT_THREAD */
-};
-
-
-/* thread structure; not much for now... */
-
-struct thread
-{
-    struct object   obj;       /* object header */
-    struct thread  *next;      /* system-wide thread list */
-    struct thread  *prev;
-    struct process *process;
-    int             client_fd; /* client fd for socket communications */
-    int             unix_pid;
-    char           *name;
-};
-
-static struct thread *first_thread;
-
 /* thread operations */
 
+static void dump_thread( struct object *obj, int verbose );
 static void destroy_thread( struct object *obj );
 
 static const struct object_ops thread_ops =
 {
+    dump_thread,
     destroy_thread
 };
 
+static struct thread *first_thread;
+
 
 /* create a new thread */
-static struct thread *create_thread( int fd, void *pid )
+struct thread *create_thread( int fd, void *pid, int *thread_handle,
+                              int *process_handle )
 {
     struct thread *thread;
     struct process *process;
 
-    if (pid)
+    if (!(thread = malloc( sizeof(*thread) ))) return NULL;
+
+    if (pid) process = get_process_from_id( pid );
+    else process = create_process();
+    if (!process)
     {
-        if (!(process = get_process_from_id( pid ))) return NULL;
-    }
-    else
-    {
-        if (!(process = create_process())) return NULL;
-    }
-    if (!(thread = malloc( sizeof(*thread) )))
-    {
-        release_object( process );
+        free( thread );
         return NULL;
     }
+
     init_object( &thread->obj, &thread_ops, NULL );
     thread->client_fd = fd;
     thread->process   = process;
     thread->unix_pid  = 0;  /* not known yet */
     thread->name      = NULL;
+    thread->error     = 0;
+    thread->exit_code = 0x103;  /* STILL_ACTIVE */
+    thread->next      = first_thread;
+    thread->prev      = NULL;
 
-    thread->next = first_thread;
-    thread->prev = NULL;
+    if (first_thread) first_thread->prev = thread;
     first_thread = thread;
+    add_process_thread( process, thread );
 
-    if (add_client( fd, thread ) == -1)
+    *thread_handle = *process_handle = -1;
+    if (current)
     {
-        release_object( thread );
-        return NULL;
+        if ((*thread_handle = alloc_handle( current->process, thread,
+                                            THREAD_ALL_ACCESS, 0 )) == -1)
+            goto error;
     }
+    if (current && !pid)
+    {
+        if ((*process_handle = alloc_handle( current->process, process,
+                                             PROCESS_ALL_ACCESS, 0 )) == -1)
+            goto error;
+    }
+
+    if (add_client( fd, thread ) == -1) goto error;
+
     return thread;
+
+ error:
+    if (current)
+    {
+        close_handle( current->process, *thread_handle );
+        close_handle( current->process, *process_handle );
+    }
+    remove_process_thread( process, thread );
+    release_object( thread );
+    return NULL;
 }
 
 /* destroy a thread when its refcount is 0 */
@@ -112,93 +107,62 @@
     free( thread );
 }
 
+/* dump a thread on stdout for debugging purposes */
+static void dump_thread( struct object *obj, int verbose )
+{
+    struct thread *thread = (struct thread *)obj;
+    assert( obj->ops == &thread_ops );
+
+    printf( "Thread pid=%d fd=%d name='%s'\n",
+            thread->unix_pid, thread->client_fd, thread->name );
+}
+
+/* get a thread pointer from a thread id (and increment the refcount) */
 struct thread *get_thread_from_id( void *id )
 {
     struct thread *t = first_thread;
     while (t && (t != id)) t = t->next;
+    if (t) grab_object( t );
     return t;
 }
 
-/* handle a client timeout (unused for now) */
-static void handle_timeout( void *data, int len, int fd, struct thread *self )
+/* get a thread from a handle (and increment the refcount) */
+struct thread *get_thread_from_handle( int handle, unsigned int access )
 {
-/*    fprintf( stderr, "Server: got timeout for %s\n", self->name );*/
-    send_reply( self->client_fd, 0, -1, 0 );
+    return (struct thread *)get_handle_obj( current->process, handle,
+                                            access, &thread_ops );
+}
+
+/* send a reply to a thread */
+int send_reply( struct thread *thread, int pass_fd, int n,
+                ... /* arg_1, len_1, ..., arg_n, len_n */ )
+{
+    struct iovec vec[16];
+    va_list args;
+    int i;
+
+    assert( n < 16 );
+    va_start( args, n );
+    for (i = 0; i < n; i++)
+    {
+        vec[i].iov_base = va_arg( args, void * );
+        vec[i].iov_len  = va_arg( args, int );
+    }
+    va_end( args );
+    return send_reply_v( thread->client_fd, thread->error, pass_fd, vec, n );
+}
+
+/* kill a thread on the spot */
+void kill_thread( struct thread *thread, int exit_code )
+{
+    if (thread->unix_pid) kill( thread->unix_pid, SIGTERM );
+    remove_client( thread->client_fd, exit_code ); /* this will call thread_killed */
 }
 
 /* a thread has been killed */
-static void handle_kill_thread( void *data, int len, int fd,
-                                struct thread *self )
+void thread_killed( struct thread *thread, int exit_code )
 {
-    if (!self) return;  /* initial client being killed */
-/*    fprintf( stderr, "Server: thread '%s' killed\n",
-               self->name ? self->name : "???" );
-*/
-    release_object( &self->obj );
-}
-
-/* create a new thread */
-static void handle_new_thread( void *data, int len, int fd,
-                               struct thread *self )
-{
-    struct new_thread_request *req = (struct new_thread_request *)data;
-    struct new_thread_reply reply;
-    struct thread *new_thread;
-    int new_fd, err;
-
-    if ((new_fd = dup(fd)) == -1)
-    {
-        new_thread = NULL;
-        err = ERROR_TOO_MANY_OPEN_FILES;
-        goto done;
-    }
-    if (len != sizeof(*req))
-    {
-        err = ERROR_INVALID_PARAMETER;
-        goto done;
-    }
-    if (!(new_thread = create_thread( new_fd, req->pid )))
-    {
-        err = ERROR_NOT_ENOUGH_MEMORY;
-        close( new_fd );
-        goto done;
-    }
-    reply.tid = new_thread;
-    reply.pid = new_thread->process;
-    err = ERROR_SUCCESS;
- done:
-    send_reply( self ? self->client_fd : get_initial_client_fd(),
-                err, -1, 1, &reply, sizeof(reply) );
-}
-
-/* create a new thread */
-static void handle_init_thread( void *data, int len, int fd,
-                                struct thread *self )
-{
-    struct init_thread_request *req = (struct init_thread_request *)data;
-    int err;
-
-    if (len < sizeof(*req))
-    {
-        err = ERROR_INVALID_PARAMETER;
-        goto done;
-    }
-    len -= sizeof(*req);
-    self->unix_pid = req->pid;
-    if (!(self->name = malloc( len + 1 )))
-    {
-        err = ERROR_NOT_ENOUGH_MEMORY;
-        goto done;
-    }
-    memcpy( self->name, (char *)data + sizeof(*req), len );
-    self->name[len] = '\0';
-    
-/*    fprintf( stderr,
-             "Server: init thread '%s' pid=%08x tid=%08x unix_pid=%d\n",
-             self->name, (int)self->process, (int)self, self->unix_pid );
-*/
-
-    err = ERROR_SUCCESS;
- done:
-    send_reply( self->client_fd, err, -1, 0 );
+    thread->exit_code = exit_code;
+    remove_process_thread( thread->process, thread );
+    release_object( thread );
 }
diff --git a/server/trace.c b/server/trace.c
new file mode 100644
index 0000000..712edea
--- /dev/null
+++ b/server/trace.c
@@ -0,0 +1,180 @@
+/* File generated automatically by tools/make_requests; DO NOT EDIT!! */
+
+#include <stdio.h>
+#include <sys/uio.h>
+#include "server.h"
+#include "server/thread.h"
+
+static void dump_new_thread_request( struct new_thread_request *req )
+{
+    printf( " pid=%p", req->pid );
+}
+
+static void dump_new_thread_reply( struct new_thread_reply *req )
+{
+    printf( " tid=%p,", req->tid );
+    printf( " thandle=%d,", req->thandle );
+    printf( " pid=%p,", req->pid );
+    printf( " phandle=%d", req->phandle );
+}
+
+static void dump_init_thread_request( struct init_thread_request *req )
+{
+    printf( " unix_pid=%d", req->unix_pid );
+}
+
+static void dump_terminate_process_request( struct terminate_process_request *req )
+{
+    printf( " handle=%d,", req->handle );
+    printf( " exit_code=%d", req->exit_code );
+}
+
+static void dump_terminate_thread_request( struct terminate_thread_request *req )
+{
+    printf( " handle=%d,", req->handle );
+    printf( " exit_code=%d", req->exit_code );
+}
+
+static void dump_get_process_info_request( struct get_process_info_request *req )
+{
+    printf( " handle=%d", req->handle );
+}
+
+static void dump_get_process_info_reply( struct get_process_info_reply *req )
+{
+    printf( " pid=%p,", req->pid );
+    printf( " exit_code=%d", req->exit_code );
+}
+
+static void dump_close_handle_request( struct close_handle_request *req )
+{
+    printf( " handle=%d", req->handle );
+}
+
+static void dump_dup_handle_request( struct dup_handle_request *req )
+{
+    printf( " src_process=%d,", req->src_process );
+    printf( " src_handle=%d,", req->src_handle );
+    printf( " dst_process=%d,", req->dst_process );
+    printf( " dst_handle=%d,", req->dst_handle );
+    printf( " access=%08x,", req->access );
+    printf( " inherit=%d,", req->inherit );
+    printf( " options=%d", req->options );
+}
+
+static void dump_dup_handle_reply( struct dup_handle_reply *req )
+{
+    printf( " handle=%d", req->handle );
+}
+
+static void dump_open_process_request( struct open_process_request *req )
+{
+    printf( " pid=%p,", req->pid );
+    printf( " access=%08x,", req->access );
+    printf( " inherit=%d", req->inherit );
+}
+
+static void dump_open_process_reply( struct open_process_reply *req )
+{
+    printf( " handle=%d", req->handle );
+}
+
+struct dumper
+{
+    void (*dump_req)();
+    void (*dump_reply)();
+    unsigned int size;
+};
+
+static const struct dumper dumpers[REQ_NB_REQUESTS] =
+{
+    { (void(*)())dump_new_thread_request,
+      (void(*)())dump_new_thread_reply,
+      sizeof(struct new_thread_request) },
+    { (void(*)())dump_init_thread_request,
+      (void(*)())0,
+      sizeof(struct init_thread_request) },
+    { (void(*)())dump_terminate_process_request,
+      (void(*)())0,
+      sizeof(struct terminate_process_request) },
+    { (void(*)())dump_terminate_thread_request,
+      (void(*)())0,
+      sizeof(struct terminate_thread_request) },
+    { (void(*)())dump_get_process_info_request,
+      (void(*)())dump_get_process_info_reply,
+      sizeof(struct get_process_info_request) },
+    { (void(*)())dump_close_handle_request,
+      (void(*)())0,
+      sizeof(struct close_handle_request) },
+    { (void(*)())dump_dup_handle_request,
+      (void(*)())dump_dup_handle_reply,
+      sizeof(struct dup_handle_request) },
+    { (void(*)())dump_open_process_request,
+      (void(*)())dump_open_process_reply,
+      sizeof(struct open_process_request) },
+};
+
+static const char * const req_names[REQ_NB_REQUESTS] =
+{
+    "new_thread",
+    "init_thread",
+    "terminate_process",
+    "terminate_thread",
+    "get_process_info",
+    "close_handle",
+    "dup_handle",
+    "open_process",
+};
+
+void trace_request( enum request req, void *data, int len, int fd )
+{
+    current->last_req = req;
+    printf( "%08x: %s(", (unsigned int)current, req_names[req] );
+    dumpers[req].dump_req( data );
+    if (len > dumpers[req].size)
+    {
+        unsigned char *ptr = (unsigned char *)data + dumpers[req].size;
+	len -= dumpers[req].size;
+        while (len--) printf( ", %02x", *ptr++ );
+    }
+    if (fd != -1) printf( " ) fd=%d\n", fd );
+    else printf( " )\n" );
+}
+
+void trace_timeout(void)
+{
+    printf( "%08x: *timeout*\n", (unsigned int)current );
+}
+
+void trace_kill( int exit_code )
+{
+    printf( "%08x: *killed* exit_code=%d\n",
+            (unsigned int)current, exit_code );
+}
+
+void trace_reply( struct thread *thread, int type, int pass_fd,
+                  struct iovec *vec, int veclen )
+{
+    if (!thread) return;
+    printf( "%08x: %s() = %d",
+            (unsigned int)thread, req_names[thread->last_req], type );
+    if (veclen)
+    {
+	printf( " {" );
+	if (dumpers[thread->last_req].dump_reply)
+	{
+	    dumpers[thread->last_req].dump_reply( vec->iov_base );
+	    vec++;
+	    veclen--;
+	}
+	for (; veclen; veclen--, vec++)
+	{
+	    unsigned char *ptr = vec->iov_base;
+	    int len = vec->iov_len;
+	    while (len--) printf( ", %02x", *ptr++ );
+	}
+	printf( " }" );
+    }
+    if (pass_fd != -1) printf( " fd=%d\n", pass_fd );
+    else printf( "\n" );
+}
diff --git a/tools/build.c b/tools/build.c
index c119136..76d8b7e 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -150,6 +150,7 @@
 static char *SpecName;
 static FILE *SpecFp;
 static WORD Code_Selector, Data_Selector;
+static char DLLInitFunc[80];
 
 char *ParseBuffer = NULL;
 char *ParseNext;
@@ -167,9 +168,6 @@
   /* Offset of the stack pointer relative to %fs:(0) */
 #define STACKOFFSET (STRUCTOFFSET(THDB,cur_stack) - STRUCTOFFSET(THDB,teb))
 
-  /* Offset of the saved fs relative to %fs:(0) */
-#define FSOFFSET (STRUCTOFFSET(THDB,saved_fs) - STRUCTOFFSET(THDB,teb))
-
 
 static void *xmalloc (size_t size)
 {
@@ -705,6 +703,14 @@
             }
             DLLHeapSize = atoi(token);
 	}
+        else if (strcmp(token, "init") == 0)
+        {
+            strcpy(DLLInitFunc, GetToken());
+            if (!DLLInitFunc[0])
+                fprintf(stderr, "%s:%d: Expected function name after init\n", SpecName, Line);
+            else  
+                fprintf(stderr, "InitFunc is %s\n", DLLInitFunc);
+        }
 	else if (IsNumberString(token))
 	{
 	    int ordinal;
@@ -1037,6 +1043,10 @@
         }
     }
 
+    /* Output LibMain function */
+    if (DLLInitFunc[0]) fprintf( outfile, "extern void %s();\n", DLLInitFunc );
+
+
     /* Output the DLL functions table */
 
     fprintf( outfile, "\nstatic const ENTRYPOINT32 Functions[%d] =\n{\n",
@@ -1151,8 +1161,9 @@
              "    FuncNames,\n"
              "    FuncOrdinals,\n"
              "    FuncArgs,\n"
-             "    ArgTypes\n"
-             "};\n" );
+             "    ArgTypes,\n");
+    fprintf( outfile, "    %s\n", DLLInitFunc[0] ? DLLInitFunc : "0" );
+    fprintf( outfile, "};\n" );             
     return 0;
 }
 
@@ -1410,7 +1421,7 @@
     fprintf( outfile, "\tmovl %%edi,%d(%%ebx)\n",
              CONTEXTOFFSET(Edi) - sizeof(CONTEXT) );
 
-    fprintf( outfile, "\tmovl -20(%%ebp),%%eax\n" ); /* Get %ebx from stack*/
+    fprintf( outfile, "\tmovl -24(%%ebp),%%eax\n" ); /* Get %ebx from stack*/
     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
              CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
     fprintf( outfile, "\tmovzwl -10(%%ebp),%%eax\n" ); /* Get %ds from stack*/
@@ -1422,7 +1433,7 @@
     fprintf( outfile, "\tpushfl\n" );
     fprintf( outfile, "\tpopl %d(%%ebx)\n",
              CONTEXTOFFSET(EFlags) - sizeof(CONTEXT) );
-    fprintf( outfile, "\tmovl -16(%%ebp),%%eax\n" ); /* Get %ebp from stack */
+    fprintf( outfile, "\tmovl -20(%%ebp),%%eax\n" ); /* Get %ebp from stack */
     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
              CONTEXTOFFSET(Ebp) - sizeof(CONTEXT) );
     fprintf( outfile, "\tmovzwl 2(%%ebp),%%eax\n" ); /* Get %ip from stack */
@@ -1434,7 +1445,7 @@
     fprintf( outfile, "\tmovzwl 4(%%ebp),%%eax\n" ); /* Get %cs from stack */
     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
              CONTEXTOFFSET(SegCs) - sizeof(CONTEXT) );
-    fprintf( outfile, "\tmovw %%fs,%%ax\n" );
+    fprintf( outfile, "\tmovzwl -14(%%ebp),%%eax\n" ); /* Get %fs from stack */
     fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
              CONTEXTOFFSET(SegFs) - sizeof(CONTEXT) );
     fprintf( outfile, "\tmovw %%gs,%%ax\n" );
@@ -1492,6 +1503,8 @@
              CONTEXTOFFSET(SegDs) - sizeof(CONTEXT) );
     fprintf( outfile, "\tpushl %d(%%ebx)\n",  /* Push new es */
              CONTEXTOFFSET(SegEs) - sizeof(CONTEXT) );
+    fprintf( outfile, "\tpushl %d(%%ebx)\n",  /* Push new fs */
+             CONTEXTOFFSET(SegFs) - sizeof(CONTEXT) );
     fprintf( outfile, "\tpushl %d(%%ebx)\n",
              CONTEXTOFFSET(EFlags) - sizeof(CONTEXT) );
     fprintf( outfile, "\tpopfl\n" );
@@ -1499,6 +1512,7 @@
              CONTEXTOFFSET(Eax) - sizeof(CONTEXT) );
     fprintf( outfile, "\tmovl %d(%%ebx),%%ebx\n",
              CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
+    fprintf( outfile, "\tpopl %%fs\n" );  /* Set fs */
     fprintf( outfile, "\tpopl %%es\n" );  /* Set es */
     fprintf( outfile, "\tpopl %%ds\n" );  /* Set ds */
 }
@@ -1539,8 +1553,10 @@
  * (sp)    word   low word of ip of 16-bit entry point
  *
  * Added on the stack:
- * (sp-4)  long   ebp
- * (sp-8)  long   saved previous stack
+ * (sp-2)  word   saved fs
+ * (sp-4)  word   buffer for Win16Mutex recursion count
+ * (sp-8)  long   ebp
+ * (sp-12) long   saved previous stack
  */
 static void BuildCallFrom16Func( FILE *outfile, char *profile )
 {
@@ -1579,11 +1595,16 @@
     fprintf( outfile, "\t.globl " PREFIX "CallFrom16_%s\n", profile );
     fprintf( outfile, PREFIX "CallFrom16_%s:\n", profile );
 
+    /* Save 16-bit fs and leave room for Win16Mutex recursion count */
+
+    fprintf( outfile, "\tpushw %%fs\n" );
+    fprintf( outfile, "\tpushw $0\n" );
+
     /* Setup bp to point to its copy on the stack */
 
     fprintf( outfile, "\tpushl %%ebp\n" );  /* Save the full 32-bit ebp */
     fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
-    fprintf( outfile, "\taddw $16,%%bp\n" );
+    fprintf( outfile, "\taddw $20,%%bp\n" );
 
     /* Save 16-bit ds and es */
 
@@ -1609,9 +1630,7 @@
 #endif
     fprintf( outfile, "\tmovw %%bx,%%es\n" );
 
-    fprintf( outfile, "\tmovw %%fs, %%bx\n" );
     fprintf( outfile, "\tmovw " PREFIX "CALLTO16_Current_fs,%%fs\n" );
-    fprintf( outfile, "\t.byte 0x64\n\tmovw %%bx,(%d)\n", FSOFFSET );
 
     /* Get the 32-bit stack pointer from the TEB */
 
@@ -1635,10 +1654,10 @@
         fprintf( outfile, "\tmovw %%ss,%%ax\n" );
         fprintf( outfile, "\tandl $0xfff8,%%eax\n" );
         fprintf( outfile, "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
-        fprintf( outfile, "\tmovl %%eax,-20(%%ebp)\n" );
+        fprintf( outfile, "\tmovl %%eax,-24(%%ebp)\n" );
         /* Add the offset */
-        fprintf( outfile, "\tleal -16(%%ebp),%%eax\n" );
-        fprintf( outfile, "\taddl %%eax,-20(%%ebp)\n" );
+        fprintf( outfile, "\tleal -20(%%ebp),%%eax\n" );
+        fprintf( outfile, "\taddl %%eax,-24(%%ebp)\n" );
     }
 
     /* Get the address of the API function */
@@ -1730,9 +1749,6 @@
     fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
     fprintf( outfile, "\tmovw %%fs," PREFIX "CALLTO16_Current_fs\n" );
 
-    fprintf( outfile, "\t.byte 0x64\n\tmovw (%d),%%bx\n", FSOFFSET );
-    fprintf( outfile, "\tmovw %%bx, %%fs\n" );
-
     if (reg_func)
     {
         /* Calc the arguments size */
@@ -1765,8 +1781,10 @@
         fprintf( outfile, "\tpopl %%ebp\n" );
 
         /* Restore ds and es */
-        fprintf( outfile, "\tincl %%esp\n" );      /* Remove ip */
+        fprintf( outfile, "\tincl %%esp\n" );      /* Remove mutex count */
         fprintf( outfile, "\tincl %%esp\n" );
+        fprintf( outfile, "\tpopl %%edx\n" );      /* Remove ip and fs */
+        fprintf( outfile, "\tmovw %%dx,%%fs\n" );  /* and restore fs */
         fprintf( outfile, "\tpopl %%edx\n" );      /* Remove cs and ds */
         fprintf( outfile, "\tmovw %%dx,%%ds\n" );  /* and restore ds */
         fprintf( outfile, "\t.byte 0x66\n\tpopl %%es\n" );    /* Restore es */
@@ -1858,33 +1876,18 @@
     fprintf( outfile, "\tpushl %%ebp\n" );
     fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
 
-    /* Call the actual CallTo16 routine (simulate a lcall) */
-
-    fprintf( outfile, "\tpushl %%cs\n" );
-    fprintf( outfile, "\tcall do_callto16_%s\n", profile );
-
-    /* Exit code */
-
-    /* FIXME: this is a hack because of task.c */
-    if (!strcmp( profile, "word_" ))
-    {
-        fprintf( outfile, ".globl " PREFIX "CALLTO16_Restore\n" );
-        fprintf( outfile, PREFIX "CALLTO16_Restore:\n" );
-    }
-    fprintf( outfile, "\tpopl %%ebp\n" );
-    fprintf( outfile, "\tret $%d\n", 4 * strlen(args) + 4 );
-
-    /* Start of the actual CallTo16 routine */
-
     /* Save the 32-bit registers */
 
-    fprintf( outfile, "do_callto16_%s:\n", profile );
     fprintf( outfile, "\tpushl %%ebx\n" );
     fprintf( outfile, "\tpushl %%ecx\n" );
     fprintf( outfile, "\tpushl %%edx\n" );
     fprintf( outfile, "\tpushl %%esi\n" );
     fprintf( outfile, "\tpushl %%edi\n" );
 
+    /* Enter Win16 Mutex */
+
+    fprintf( outfile, "\tcall " PREFIX "SYSLEVEL_EnterWin16Lock\n" );
+
     /* Print debugging info */
 
     if (debugging)
@@ -1898,6 +1901,53 @@
         fprintf( outfile, "\tpopl %%eax\n" );
     }
 
+    /* Call the actual CallTo16 routine (simulate a lcall) */
+
+    fprintf( outfile, "\tpushl %%cs\n" );
+    fprintf( outfile, "\tcall do_callto16_%s\n", profile );
+
+    fprintf( outfile, "\tpushl %%eax\n" );
+
+    /* Print debugging info */
+
+    if (debugging)
+    {
+        fprintf( outfile, "\tpushl %%eax\n" );
+        fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16Ret\n" );
+        fprintf( outfile, "\tpopl %%eax\n" );
+    }
+
+    /* Leave Win16 Mutex */
+
+    fprintf( outfile, "\tcall " PREFIX "SYSLEVEL_LeaveWin16Lock\n" );
+
+    /* Restore the 32-bit registers */
+
+    fprintf( outfile, "\tpopl %%eax\n" );
+    fprintf( outfile, "\tpopl %%edi\n" );
+    fprintf( outfile, "\tpopl %%esi\n" );
+    fprintf( outfile, "\tpopl %%edx\n" );
+    fprintf( outfile, "\tpopl %%ecx\n" );
+    fprintf( outfile, "\tpopl %%ebx\n" );
+
+    /* Exit code */
+
+#if 0
+    /* FIXME: this is a hack because of task.c */
+    if (!strcmp( profile, "word_" ))
+    {
+        fprintf( outfile, ".globl " PREFIX "CALLTO16_Restore\n" );
+        fprintf( outfile, PREFIX "CALLTO16_Restore:\n" );
+    }
+#endif
+    fprintf( outfile, "\tpopl %%ebp\n" );
+    fprintf( outfile, "\tret $%d\n", 4 * strlen(args) + 4 );
+
+
+    /* Start of the actual CallTo16 routine */
+
+    fprintf( outfile, "do_callto16_%s:\n", profile );
+
     /* Save the 32-bit stack and %fs */
 
     fprintf( outfile, "\t.byte 0x64\n\tpushl (%d)\n", STACKOFFSET );
@@ -1918,14 +1968,13 @@
         fprintf( outfile, "\tmovl %%eax,%%esp\n" );
         fprintf( outfile, "\t.byte 0x64\n\tmovl %%edx,(%d)\n", STACKOFFSET );
 
-    fprintf( outfile, "\t.byte 0x64\n\tmovw (%d),%%cx\n", FSOFFSET );
-    fprintf( outfile, "\tmovw %%cx, %%fs\n" );
-
         /* Get the registers. ebx is handled later on. */
 
         fprintf( outfile, "\tmovl 8(%%ebx),%%ebx\n" );
         fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(SegEs) );
         fprintf( outfile, "\tmovw %%ax,%%es\n" );
+        fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(SegFs) );
+        fprintf( outfile, "\tmovw %%ax,%%fs\n" );
         fprintf( outfile, "\tmovl %d(%%ebx),%%ebp\n", CONTEXTOFFSET(Ebp) );
         fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(Eax) );
         fprintf( outfile, "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(Ecx) );
@@ -1971,9 +2020,6 @@
         fprintf( outfile, "\t.byte 0x64\n\tmovw (%d),%%sp\n", STACKOFFSET );
         fprintf( outfile, "\t.byte 0x64\n\tmovl %%edx,(%d)\n", STACKOFFSET );
 
-    fprintf( outfile, "\t.byte 0x64\n\tmovw (%d),%%cx\n", FSOFFSET );
-    fprintf( outfile, "\tmovw %%cx, %%fs\n" );
-
         /* Make %bp point to the previous stackframe (built by CallFrom16) */
         fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
         fprintf( outfile, "\tleal %d(%%ebp),%%ebp\n",
@@ -2007,6 +2053,11 @@
 
         fprintf( outfile, "\tpushl 8(%%ebx)\n" );
 
+        /* Set %fs to the value saved by the last CallFrom16 */
+
+        fprintf( outfile, "\tmovw -14(%%ebp),%%ax\n" );
+        fprintf( outfile, "\tmovw %%ax,%%fs\n" );
+
         /* Set %ds and %es (and %ax just in case) equal to %ss */
 
         fprintf( outfile, "\tmovw %%ss,%%ax\n" );
@@ -2055,9 +2106,7 @@
 #endif
     fprintf( outfile, "\tmovw %%bx,%%es\n" );
 
-    fprintf( outfile, "\tmovw %%fs, %%cx\n" );
     fprintf( outfile, "\tmovw " PREFIX "CALLTO16_Current_fs,%%fs\n" );
-    fprintf( outfile, "\t.byte 0x64\n\tmovw %%cx,(%d)\n", FSOFFSET );
 
     /* Restore the 32-bit stack */
 
@@ -2068,14 +2117,6 @@
     fprintf( outfile, "\t.byte 0x64\n\tmovl (%d),%%esp\n", STACKOFFSET );
     fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
 
-    /* Restore the 32-bit registers */
-
-    fprintf( outfile, "\tpopl %%edi\n" );
-    fprintf( outfile, "\tpopl %%esi\n" );
-    fprintf( outfile, "\tpopl %%edx\n" );
-    fprintf( outfile, "\tpopl %%ecx\n" );
-    fprintf( outfile, "\tpopl %%ebx\n" );
-
     /* Return to caller */
 
     fprintf( outfile, "\tlret\n" );
diff --git a/tools/make_requests b/tools/make_requests
new file mode 100755
index 0000000..1cba580
--- /dev/null
+++ b/tools/make_requests
@@ -0,0 +1,244 @@
+#! /usr/bin/perl
+#
+# Build the server/trace.c and include/server/request.h files
+# from the contents of include/server.h.
+#
+# Copyright (C) 1998 Alexandre Julliard
+#
+
+%formats =
+(
+    "int"          => "%d",
+    "unsigned int" => "%08x",
+    "void*"        => "%p"
+);
+
+my @requests = ();
+my %replies = ();
+
+open(SERVER,"include/server.h") or die "Can't open include/server.h";
+open(TRACE,">server/trace.c") or die "Can't create server/trace.c";
+open(REQUESTS,">include/server/request.h") or die "Can't create include/server/request.h";
+
+### Generate the header
+
+print TRACE <<EOF;
+/* File generated automatically by $0; DO NOT EDIT!! */
+
+#include <stdio.h>
+#include <sys/uio.h>
+#include "server.h"
+#include "server/thread.h"
+EOF
+
+### Parse server.h to find request/reply structure definitions
+
+while (<SERVER>)
+{
+    if (/^struct +(\w+)_request/) { &DO_REQUEST($1); }
+    if (/^struct +(\w+)_reply/)   { &DO_REPLY($1); }
+}
+
+### Output the dumping function tables
+
+print TRACE<<EOF;
+
+struct dumper
+{
+    void (*dump_req)();
+    void (*dump_reply)();
+    unsigned int size;
+};
+
+static const struct dumper dumpers[REQ_NB_REQUESTS] =
+{
+EOF
+
+foreach $req (@requests)
+{
+    $request = $req . "_request";
+    $reply = $replies{$req} ? "dump_${req}_reply" : "0";
+    print TRACE "    { (void(*)())dump_$request,\n";
+    print TRACE "      (void(*)())$reply,\n";
+    print TRACE "      sizeof(struct $request) },\n";
+}
+
+print TRACE <<EOF;
+};
+
+static const char * const req_names[REQ_NB_REQUESTS] =
+{
+EOF
+foreach $req (@requests)
+{
+    print TRACE "    \"$req\",\n";
+}
+
+### Output the tracing functions
+
+print TRACE <<EOF;
+};
+
+void trace_request( enum request req, void *data, int len, int fd )
+{
+    current->last_req = req;
+    printf( "%08x: %s(", (unsigned int)current, req_names[req] );
+    dumpers[req].dump_req( data );
+    if (len > dumpers[req].size)
+    {
+        unsigned char *ptr = (unsigned char *)data + dumpers[req].size;
+	len -= dumpers[req].size;
+        while (len--) printf( ", %02x", *ptr++ );
+    }
+    if (fd != -1) printf( " ) fd=%d\\n", fd );
+    else printf( " )\\n" );
+}
+
+void trace_timeout(void)
+{
+    printf( "%08x: *timeout*\\n", (unsigned int)current );
+}
+
+void trace_kill( int exit_code )
+{
+    printf( "%08x: *killed* exit_code=%d\\n",
+            (unsigned int)current, exit_code );
+}
+
+void trace_reply( struct thread *thread, int type, int pass_fd,
+                  struct iovec *vec, int veclen )
+{
+    if (!thread) return;
+    printf( "%08x: %s() = %d",
+            (unsigned int)thread, req_names[thread->last_req], type );
+    if (veclen)
+    {
+	printf( " {" );
+	if (dumpers[thread->last_req].dump_reply)
+	{
+	    dumpers[thread->last_req].dump_reply( vec->iov_base );
+	    vec++;
+	    veclen--;
+	}
+	for (; veclen; veclen--, vec++)
+	{
+	    unsigned char *ptr = vec->iov_base;
+	    int len = vec->iov_len;
+	    while (len--) printf( ", %02x", *ptr++ );
+	}
+	printf( " }" );
+    }
+    if (pass_fd != -1) printf( " fd=%d\\n", pass_fd );
+    else printf( "\\n" );
+}
+EOF
+
+### Output the requests list
+
+print REQUESTS <<EOF;
+/* File generated automatically by $0; DO NOT EDIT!! */
+
+#ifndef __WINE_SERVER_REQUEST_H
+#define __WINE_SERVER_REQUEST_H
+
+enum request
+{
+EOF
+
+foreach $req (@requests)
+{
+    print REQUESTS "    REQ_\U$req,\n";
+}
+
+print REQUESTS <<EOF;
+    REQ_NB_REQUESTS
+};
+
+#ifdef WANT_REQUEST_HANDLERS
+
+#define DECL_HANDLER(name) \\
+    static void req_##name( struct name##_request *req, void *data, int len, int fd )
+
+EOF
+
+foreach $req (@requests) { print REQUESTS "DECL_HANDLER($req);\n"; }
+
+print REQUESTS <<EOF;
+
+static const struct handler {
+    void       (*handler)();
+    unsigned int min_size;
+} req_handlers[REQ_NB_REQUESTS] = {
+EOF
+
+foreach $req (@requests)
+{
+    print REQUESTS "    { (void(*)())req_$req, sizeof(struct ${req}_request) },\n";
+}
+
+print REQUESTS <<EOF;
+};
+#endif  /* WANT_REQUEST_HANDLERS */
+
+#endif  /* __WINE_SERVER_REQUEST_H */
+EOF
+
+### Handle a request structure definition
+
+sub DO_REQUEST
+{
+    my $name = shift;
+    my @struct = ();
+    while (<SERVER>)
+    {
+	last if /^};$/;
+        next if /^{$/;
+	s!/\*.*\*/!!g;
+	/ *(\w+\**( +\w+\**)*) +(\w+);/ or die "Unrecognized syntax $_";
+	my $type = $1;
+	my $var = $3;
+        die "Unrecognized type $type" unless defined($formats{$type});
+	push @struct, $type, $var;
+    }
+    push @requests, $name;
+    &DO_DUMP_FUNC( $name . "_request",@struct);
+}
+
+### Handle a reply structure definition
+
+sub DO_REPLY
+{
+    my $name = shift;
+    my @struct = ();
+    while (<SERVER>)
+    {
+	last if /^};$/;
+        next if /^{$/;
+	s!/\*.*\*/!!g;
+	/ *(\w+\**( +\w+\**)*) +(\w+);/ or die "Unrecognized syntax $_";
+	my $type = $1;
+	my $var = $3;
+        die "Unrecognized type $type" unless defined($formats{$type});
+	push @struct, $type, $var;
+    }
+    $replies{$name} = 1;
+    &DO_DUMP_FUNC( $name . "_reply" ,@struct);
+}
+
+### Generate a dumping function
+
+sub DO_DUMP_FUNC
+{
+    my $name = shift;
+    print TRACE "\nstatic void dump_$name( struct $name *req )\n{\n";
+    while ($#_ >= 0)
+    {
+	my $type = shift;
+	my $var = shift;
+	print TRACE "    printf( \" $var=$formats{$type}";
+	print TRACE "," if ($#_ > 0);
+	print TRACE "\", req->$var );\n";
+	$size .= "+sizeof($type)";
+    }
+    print TRACE "}\n";
+}
diff --git a/win32/console.c b/win32/console.c
index 6bab46d..0c24ff6 100644
--- a/win32/console.c
+++ b/win32/console.c
@@ -383,7 +383,7 @@
 	SYSTEM_LOCK();
 	if (pdb->console != NULL) {
 		CONSOLE *console = (CONSOLE *)pdb->console;
-		handle = (HFILE32)HANDLE_Alloc(pdb, &console->header, 0, TRUE);
+		handle = (HFILE32)HANDLE_Alloc(pdb, &console->header, 0, TRUE, -1);
 	}
 	SYSTEM_UNLOCK();
 	return handle;
@@ -440,14 +440,14 @@
 	console->slave = slave;
 	console->pid = pid;
 
-	if ((hIn = HANDLE_Alloc(pdb,&console->header, 0, TRUE)) == INVALID_HANDLE_VALUE32)
+	if ((hIn = HANDLE_Alloc(pdb,&console->header, 0, TRUE,-1)) == INVALID_HANDLE_VALUE32)
         {
             K32OBJ_DecCount(&console->header);
             SYSTEM_UNLOCK();
             return FALSE;
 	}
 
-	if ((hOut = HANDLE_Alloc(pdb,&console->header, 0, TRUE)) == INVALID_HANDLE_VALUE32)
+	if ((hOut = HANDLE_Alloc(pdb,&console->header, 0, TRUE,-1)) == INVALID_HANDLE_VALUE32)
         {
             CloseHandle(hIn);
             K32OBJ_DecCount(&console->header);
@@ -456,7 +456,7 @@
 	}
 
 
-	if ((hErr = HANDLE_Alloc(pdb,&console->header, 0, TRUE)) == INVALID_HANDLE_VALUE32)
+	if ((hErr = HANDLE_Alloc(pdb,&console->header, 0, TRUE,-1)) == INVALID_HANDLE_VALUE32)
         {
             CloseHandle(hIn);
             CloseHandle(hOut);
diff --git a/win32/device.c b/win32/device.c
index 052e472..7574bb5 100644
--- a/win32/device.c
+++ b/win32/device.c
@@ -59,7 +59,7 @@
 
 	handle = HANDLE_Alloc( PROCESS_Current(), &(dev->header),
 			       FILE_ALL_ACCESS | GENERIC_READ |
-			       GENERIC_WRITE | GENERIC_EXECUTE /*FIXME*/, TRUE );
+			       GENERIC_WRITE | GENERIC_EXECUTE /*FIXME*/, TRUE, -1 );
 	/* If the allocation failed, the object is already destroyed */
 	if (handle == INVALID_HANDLE_VALUE32) dev = NULL;
 	return handle;
@@ -86,7 +86,7 @@
 			      LPOVERLAPPED lpOverlapped)
 {
 	DEVICE_OBJECT	*dev = (DEVICE_OBJECT *)HANDLE_GetObjPtr(
-		PROCESS_Current(), hDevice, K32OBJ_DEVICE_IOCTL, 0 /*FIXME*/ );
+		PROCESS_Current(), hDevice, K32OBJ_DEVICE_IOCTL, 0 /*FIXME*/, NULL );
 
         FIXME(win32, "(%ld,%ld,%p,%ld,%p,%ld,%p,%p), stub\n",
 		hDevice,dwIoControlCode,lpvlnBuffer,cblnBuffer,
diff --git a/win32/file.c b/win32/file.c
index 3d24640..fd1de18 100644
--- a/win32/file.c
+++ b/win32/file.c
@@ -41,7 +41,7 @@
 		     numberOfBytesToWrite);
 	
 	if (!(ioptr = HANDLE_GetObjPtr( PROCESS_Current(), hFile,
-                                        K32OBJ_UNKNOWN, 0 ))) 
+                                        K32OBJ_UNKNOWN, 0, NULL ))) 
 		return HFILE_ERROR32;
         if (K32OBJ_OPS(ioptr)->write)
             status = K32OBJ_OPS(ioptr)->write(ioptr, lpBuffer, numberOfBytesToWrite, 
@@ -63,7 +63,7 @@
 		     numberOfBytesToRead);
 	
 	if (!(ioptr = HANDLE_GetObjPtr( PROCESS_Current(), hFile,
-                                        K32OBJ_UNKNOWN, 0 ))) 
+                                        K32OBJ_UNKNOWN, 0, NULL ))) 
 		return HFILE_ERROR32;
         if (K32OBJ_OPS(ioptr)->read)
             status = K32OBJ_OPS(ioptr)->read(ioptr, lpBuffer, numberOfBytesToRead, 
@@ -78,7 +78,7 @@
  */
 typedef
 VOID
-(WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(
+(CALLBACK *LPOVERLAPPED_COMPLETION_ROUTINE)(
     DWORD dwErrorCode,
     DWORD dwNumberOfBytesTransfered,
     LPOVERLAPPED lpOverlapped
diff --git a/win32/init.c b/win32/init.c
index 6a646cb..0224954 100644
--- a/win32/init.c
+++ b/win32/init.c
@@ -26,6 +26,7 @@
 
     lpStartupInfo->cbReserved2 = 0;
     lpStartupInfo->lpReserved2 = NULL; /* must be NULL for VC runtime */
+    lpStartupInfo->dwFlags    = STARTF_USESTDHANDLES;
     lpStartupInfo->hStdInput  = (HANDLE32)0;
     lpStartupInfo->hStdOutput = (HANDLE32)1;
     lpStartupInfo->hStdError  = (HANDLE32)2;
diff --git a/win32/kernel32.c b/win32/kernel32.c
index 12e69b4..08eca15 100644
--- a/win32/kernel32.c
+++ b/win32/kernel32.c
@@ -20,6 +20,7 @@
 #include "win.h"
 #include "debug.h"
 #include "flatthunk.h"
+#include "syslevel.h"
 
 
 /***********************************************************************
@@ -1049,7 +1050,7 @@
  */
 VOID WINAPI _KERNEL_475(CONTEXT *context) 
 {
-    GET_FS( THREAD_Current()->saved_fs );
+    GET_FS( FS_reg(context) );
 }
 
 /**********************************************************************
@@ -1165,6 +1166,8 @@
       TRACE(thunk, "after  SYSTHUNK hack: EBP: %08lx ESP: %08lx cur_stack: %08lx\n",
                    EBP_reg(context), ESP_reg(context), thdb->cur_stack);
    }
+
+   SYSLEVEL_ReleaseWin16Lock();
 }
 
 /***********************************************************************
@@ -1174,6 +1177,8 @@
 {
    LPBYTE code = (LPBYTE)EIP_reg(context) - 13;
 
+   SYSLEVEL_RestoreWin16Lock();
+
    /* We undo the SYSTHUNK hack if necessary. See K32Thk1632Prolog. */
 
    if (   code[5] == 0xFF && code[6] == 0x55 && code[7] == 0xFC
diff --git a/win32/newfns.c b/win32/newfns.c
index 7f61887..693c5f7 100644
--- a/win32/newfns.c
+++ b/win32/newfns.c
@@ -55,28 +55,6 @@
     return TRUE;
 }
 
-HANDLE32 WINAPI FindFirstChangeNotification32A(LPCSTR lpPathName,BOOL32 bWatchSubtree,DWORD dwNotifyFilter) {
-	FIXME(file,"(%s,%d,%08lx): stub\n",
-	      lpPathName,bWatchSubtree,dwNotifyFilter);
-	return 0xcafebabe;
-}
-
-HANDLE32 WINAPI FindFirstChangeNotification32W(LPCWSTR lpPathName,BOOL32 bWatchSubtree,DWORD dwNotifyFilter) {
-	FIXME(file,"(%s,%d,%08lx): stub\n",
-	      debugstr_w(lpPathName),bWatchSubtree,dwNotifyFilter);
-	return 0xcafebabe;
-}
-
-BOOL32 WINAPI FindNextChangeNotification(HANDLE32 fcnhandle) {
-	FIXME(file,"(%08x): stub!\n",fcnhandle);
-	return FALSE;
-}
-
-BOOL32 WINAPI FindCloseChangeNotification(HANDLE32 fcnhandle) {
-	FIXME(file,"(%08x): stub!\n",fcnhandle);
-	return FALSE;
-}
-
 /****************************************************************************
  *		QueryPerformanceFrequency (KERNEL32.565)
  */
diff --git a/win32/ordinals.c b/win32/ordinals.c
index a1077a6..a9699cf 100644
--- a/win32/ordinals.c
+++ b/win32/ordinals.c
@@ -16,78 +16,6 @@
 #include "callback.h"
 #include "debug.h"
 
-static CRITICAL_SECTION Win16Mutex;
-static SEGPTR segWin16Mutex = (SEGPTR)NULL;
-
-
-/***********************************************
- *           GetpWin16Lock    (KERNEL32.93)
- * Return the infamous Win16Mutex.
- */
-VOID WINAPI GetpWin16Lock(CRITICAL_SECTION **lock)
-{
-    FIXME(win32, "(%p)\n",lock);
-    *lock = &Win16Mutex;
-}
-
-/***********************************************
- *           _ConfirmWin16Lock    (KERNEL32.96)
- */
-DWORD WINAPI _ConfirmWin16Lock(void)
-{
-    FIXME(win32, "()\n");
-    return 1;
-}
-
-/***********************************************
- *           _EnterSysLevel    (KERNEL32.97)
- */
-VOID WINAPI _EnterSysLevel(CRITICAL_SECTION *lock)
-{
-    FIXME(win32, "(%p)\n", lock);
-}
-
-/***********************************************
- *           _EnterSysLevel    (KERNEL32.98)
- */
-VOID WINAPI _LeaveSysLevel(CRITICAL_SECTION *lock)
-{
-    FIXME(win32, "(%p)\n", lock);
-}
-
-/***********************************************
- *           ReleaseThunkLock    (KERNEL32.48)
- */
-VOID WINAPI ReleaseThunkLock(DWORD *mutex_count)
-{
-    _LeaveSysLevel(&Win16Mutex);
-
-    *mutex_count = (DWORD) NtCurrentTeb()->mutex_count;
-    NtCurrentTeb()->mutex_count = 0xFFFF;
-}
-
-/***********************************************
- *           RestoreThunkLock    (KERNEL32.49)
- */
-VOID WINAPI RestoreThunkLock(DWORD mutex_count)
-{
-    NtCurrentTeb()->mutex_count = (WORD)mutex_count;
-
-    _EnterSysLevel(&Win16Mutex);
-}
-
-/***********************************************
- *           GetPK16SysVar    (KERNEL32.92)
- */
-LPVOID WINAPI GetPK16SysVar(void)
-{
-    static BYTE PK16SysVar[128];
-
-    FIXME(win32, "()\n");
-    return PK16SysVar;
-}
-
-
 /**********************************************************************
  *           WOWGetDescriptor        (KERNEL32.88) (WOW32.1)
  */
@@ -180,6 +108,18 @@
 	return 0;
 }
 
+/**********************************************************************
+ *           GetPK16SysVar    (KERNEL32.92)
+ */
+LPVOID WINAPI GetPK16SysVar(void)
+{
+    static BYTE PK16SysVar[128];
+
+    FIXME(win32, "()\n");
+    return PK16SysVar;
+}
+
+
 BOOL32 WINAPI _KERNEL32_100(HANDLE32 threadid,DWORD exitcode,DWORD x) {
 	FIXME(thread,"(%d,%ld,0x%08lx): stub\n",threadid,exitcode,x);
 	return TRUE;
@@ -190,18 +130,3 @@
 	return 1;
 }
 
-/************************************************************************
- *		KERNEL_449		(KERNEL.449)
- * This returns a segmented static pointer to a linear pointer to a critical
- * section in kernel32 address space. This is most likely the Win16 Lock,
- * but I am not sure.
- */
-SEGPTR WINAPI KERNEL_449(void) { 
-	if (!segWin16Mutex) {
-		LPDWORD	w16m = SEGPTR_ALLOC(4);
-		
-		*w16m = (DWORD)&Win16Mutex;
-		segWin16Mutex = SEGPTR_GET(w16m);
-	}
-	return segWin16Mutex;
-}
diff --git a/win32/process.c b/win32/process.c
index a9e8b2d..3a85430 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -14,29 +14,11 @@
 #include "process.h"
 #include "pe_image.h"
 #include "file.h"
+#include "task.h"
+#include "toolhelp.h"
 #include "debug.h"
 
 
-/***********************************************************************
- *           MsgWaitForMultipleObjects    (USER32.400)
- */
-DWORD WINAPI MsgWaitForMultipleObjects(
-	DWORD nCount,HANDLE32 *pHandles,BOOL32 fWaitAll,DWORD dwMilliseconds,
-	DWORD dwWakeMask
-) {
-#if 0
-	int	i;
-	fprintf(stderr,"MsgWaitForMultipleObjects(%ld,[",nCount);
-	for (i=0;i<nCount;i++)
-		fprintf(stderr,"%ld,",(DWORD)pHandles[i]);
-	fprintf(stderr,"],%d,%ld,0x%08lx)\n",fWaitAll,dwMilliseconds,dwWakeMask);
-	return 0;
-#else
-	return WaitForMultipleObjectsEx(nCount, pHandles, fWaitAll, dwMilliseconds,
-					FALSE);
-#endif
-}
-
 /**********************************************************************
  *          GetProcessAffinityMask
  */
@@ -62,7 +44,7 @@
  */
 BOOL32 WINAPI SetThreadAffinityMask(HANDLE32 hThread, DWORD dwThreadAffinityMask)
 {
-	THDB	*thdb = THREAD_GetPtr( hThread, THREAD_SET_INFORMATION );
+	THDB	*thdb = THREAD_GetPtr( hThread, THREAD_SET_INFORMATION, NULL );
 
 	if (!thdb) 
 		return FALSE;
@@ -85,13 +67,16 @@
 	DWORD creationflags,LPVOID env,LPCSTR curdir,
 	LPSTARTUPINFO32A startupinfo,LPPROCESS_INFORMATION processinfo
 ) {
-	WARN(win32,"CreateProcessA(%s,%s,%p,%p,%d,%08lx,%p,%s,%p,%p),\n
-		calling WinExec32 instead\n",
+	HINSTANCE16 hInst = 0;
+	if (processinfo) memset(processinfo, '\0', sizeof(*processinfo));
+
+	FIXME(win32,"(%s,%s,%p,%p,%d,%08lx,%p,%s,%p,%p): calling WinExec32\n",
 		appname,cmdline,processattributes,threadattributes,
-		inherithandles,creationflags,env,curdir,startupinfo,processinfo
-	);
-        WinExec32(cmdline,TRUE);
-        return TRUE;
+		inherithandles,creationflags,env,curdir,startupinfo,processinfo);
+
+	hInst = WinExec32(cmdline,TRUE);
+
+        return hInst >= 32;
 #if 0
 	/* make from lcc uses system as fallback if CreateProcess returns
 	   FALSE, so return false */
diff --git a/windows/class.c b/windows/class.c
index b33606d..aef5cd3 100644
--- a/windows/class.c
+++ b/windows/class.c
@@ -2,10 +2,14 @@
  * Window classes functions
  *
  * Copyright 1993, 1996 Alexandre Julliard
+ *           1998 Juergen Schmied (jsch)
  *
  * FIXME: In win32 all classes are local. They are registered at 
  *	  program start. Processes CANNOT share classes. (Source: some
  *	  win31->NT migration book)
+ *
+ * FIXME: There seems to be a general problem with hInstance in WINE
+ *   classes are getting registred with wrong hInstance.
  */
 
 #include <stdlib.h>
@@ -19,6 +23,7 @@
 #include "toolhelp.h"
 #include "winproc.h"
 #include "debug.h"
+#include "winerror.h"
 
 
 static CLASS *firstClass = NULL;
@@ -160,6 +165,7 @@
 static BOOL32 CLASS_FreeClass( CLASS *classPtr )
 {
     CLASS **ppClass;
+    TRACE(class,"%p \n", classPtr);  
 
     /* Check if we can remove this class */
 
@@ -195,6 +201,8 @@
 {
     CLASS *ptr, *next;
   
+    TRACE(class,"0x%08x \n", hModule);  
+
     for (ptr = firstClass; ptr; ptr = next)
     {
         next = ptr->next;
@@ -208,19 +216,30 @@
  *
  * Return a pointer to the class.
  * hinstance has been normalized by the caller.
+ *
+ * NOTES
+ *  980805 a local class will be found now if registred with hInst=0
+ *  and looed up with a hInst!=0. msmoney does it (jsch)
  */
 CLASS *CLASS_FindClassByAtom( ATOM atom, HINSTANCE32 hinstance )
-{
-    CLASS * class;
+{   CLASS * class, *tclass=0;
+
+    TRACE(class,"0x%08x 0x%08x\n", atom, hinstance);
 
     /* First search task-specific classes */
 
     for (class = firstClass; (class); class = class->next)
     {
         if (class->style & CS_GLOBALCLASS) continue;
-        if ((class->atomName == atom) && 
-            ((hinstance == 0xffff) ||
-             (hinstance == class->hInstance))) return class;
+        if (class->atomName == atom)
+        {
+            if (hinstance==class->hInstance || hinstance==0xffff )
+            {
+                TRACE(class,"-- found local %p\n", class);
+                return class;
+            }
+            if (class->hInstance==0) tclass = class;
+        }
     }
     
       /* Then search global classes */
@@ -228,9 +247,21 @@
     for (class = firstClass; (class); class = class->next)
     {
         if (!(class->style & CS_GLOBALCLASS)) continue;
-        if (class->atomName == atom) return class;
+        if (class->atomName == atom)
+        {
+            TRACE(class,"-- found global %p\n", class);
+            return class;
+        }
     }
 
+    /* Then check if there was a local class with hInst=0*/
+    if ( tclass )
+    {
+        WARN(class,"-- found local Class registred with hInst=0\n");
+        return tclass;
+    }
+    
+    TRACE(class,"-- not found\n");
     return 0;
 }
 
@@ -247,8 +278,10 @@
 {
     CLASS *classPtr;
 
-    /* Check if a class with this name already exists */
+    TRACE(class,"atom=0x%x hinst=0x%x style=0x%lx clExtr=0x%x winExtr=0x%x wndProc=0x%p ProcType=0x%x\n",
+     atom, hInstance, style, classExtra, winExtra, wndProc, wndProcType);
 
+   /* Check if a class with this name already exists */
     classPtr = CLASS_FindClassByAtom( atom, hInstance );
     if (classPtr)
     {
@@ -346,18 +379,21 @@
     ATOM atom;
     CLASS *classPtr;
 
-    if (!(atom = GlobalAddAtom32A( wc->lpszClassName ))) return 0;
+    if (!(atom = GlobalAddAtom32A( wc->lpszClassName ))) 
+    {
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
+        return FALSE;
+    }
     if (!(classPtr = CLASS_RegisterClass( atom, wc->hInstance, wc->style,
                                           wc->cbClsExtra, wc->cbWndExtra,
                                           (WNDPROC16)wc->lpfnWndProc,
                                           WIN_PROC_32A )))
-    {
-        GlobalDeleteAtom( atom );
-        return 0;
+    {   GlobalDeleteAtom( atom );
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
+        return FALSE;
     }
 
-    TRACE(class, "atom=%04x wndproc=%08lx
-hinst=%04x bg=%04x style=%08x clsExt=%d winExt=%d class=%p name='%s'\n",
+    TRACE(class, "atom=%04x wndproc=%08lx hinst=%04x bg=%04x style=%08x clsExt=%d winExt=%d class=%p name='%s'\n",
                    atom, (DWORD)wc->lpfnWndProc, wc->hInstance,
                    wc->hbrBackground, wc->style, wc->cbClsExtra,
                    wc->cbWndExtra, classPtr,
@@ -380,12 +416,17 @@
     ATOM atom;
     CLASS *classPtr;
 
-    if (!(atom = GlobalAddAtom32W( wc->lpszClassName ))) return 0;
+    if (!(atom = GlobalAddAtom32W( wc->lpszClassName )))
+    {
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
+        return FALSE;
+    }
     if (!(classPtr = CLASS_RegisterClass( atom, wc->hInstance, wc->style,
                                           wc->cbClsExtra, wc->cbWndExtra,
                                           (WNDPROC16)wc->lpfnWndProc,
                                           WIN_PROC_32W )))
     {
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
         GlobalDeleteAtom( atom );
         return 0;
     }
@@ -446,14 +487,19 @@
     ATOM atom;
     CLASS *classPtr;
 
-    if (!(atom = GlobalAddAtom32A( wc->lpszClassName ))) return 0;
+    if (!(atom = GlobalAddAtom32A( wc->lpszClassName )))
+    {
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
+        return FALSE;
+    }
     if (!(classPtr = CLASS_RegisterClass( atom, wc->hInstance, wc->style,
                                           wc->cbClsExtra, wc->cbWndExtra,
                                           (WNDPROC16)wc->lpfnWndProc,
                                           WIN_PROC_32A )))
     {
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
         GlobalDeleteAtom( atom );
-        return 0;
+        return FALSE;
     }
 
     TRACE(class, "atom=%04x wndproc=%08lx hinst=%04x bg=%04x style=%08x clsExt=%d winExt=%d class=%p\n",
@@ -478,12 +524,17 @@
     ATOM atom;
     CLASS *classPtr;
 
-    if (!(atom = GlobalAddAtom32W( wc->lpszClassName ))) return 0;
+    if (!(atom = GlobalAddAtom32W( wc->lpszClassName )))
+    {
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
+        return 0;
+    }
     if (!(classPtr = CLASS_RegisterClass( atom, wc->hInstance, wc->style,
                                           wc->cbClsExtra, wc->cbWndExtra,
                                           (WNDPROC16)wc->lpfnWndProc,
                                           WIN_PROC_32W )))
     {
+        SetLastError(ERROR_CLASS_ALREADY_EXISTS);
         GlobalDeleteAtom( atom );
         return 0;
     }
@@ -520,34 +571,57 @@
 
 /***********************************************************************
  *           UnregisterClass32A    (USER32.563)
+ *
  */
 BOOL32 WINAPI UnregisterClass32A( LPCSTR className, HINSTANCE32 hInstance )
-{
-    CLASS *classPtr;
+{   CLASS *classPtr;
     ATOM atom;
+    BOOL32 ret;
 
-    if (!(atom = GlobalFindAtom32A( className ))) return FALSE;
+    TRACE(class,"%s %x\n",className, hInstance);
+
+    if (!(atom = GlobalFindAtom32A( className )))
+    {
+        SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
+        return FALSE;
+    }
     if (!(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
-        (classPtr->hInstance != hInstance)) return FALSE;
-    return CLASS_FreeClass( classPtr );
+        (classPtr->hInstance != hInstance))
+    {
+        SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
+        return FALSE;
+    }
+    if (!(ret = CLASS_FreeClass( classPtr )))
+        SetLastError(ERROR_CLASS_HAS_WINDOWS);
+    return ret;
 }
 
-
 /***********************************************************************
  *           UnregisterClass32W    (USER32.564)
  */
 BOOL32 WINAPI UnregisterClass32W( LPCWSTR className, HINSTANCE32 hInstance )
-{
-    CLASS *classPtr;
+{   CLASS *classPtr;
     ATOM atom;
+    BOOL32 ret;
 
-    if (!(atom = GlobalFindAtom32W( className ))) return FALSE;
+    TRACE(class,"%s %x\n",debugstr_w(className), hInstance);
+
+    if (!(atom = GlobalFindAtom32W( className )))
+    {
+        SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
+        return FALSE;
+    }
     if (!(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
-        (classPtr->hInstance != hInstance)) return FALSE;
-    return CLASS_FreeClass( classPtr );
+        (classPtr->hInstance != hInstance))
+    {
+        SetLastError(ERROR_CLASS_DOES_NOT_EXIST);
+        return FALSE;
+    }
+    if (!(ret = CLASS_FreeClass( classPtr )))
+        SetLastError(ERROR_CLASS_HAS_WINDOWS);
+    return ret;
 }
 
-
 /***********************************************************************
  *           GetClassWord16    (USER.129)
  */
@@ -564,6 +638,8 @@
 {
     WND * wndPtr;
     
+    TRACE(class,"%x %x\n",hwnd, offset);
+    
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
     if (offset >= 0)
     {
@@ -583,6 +659,7 @@
         case GCW_HMODULE:
             return (WORD)GetClassLong32A( hwnd, offset );
     }
+
     WARN(class, "Invalid offset %d\n", offset);
     return 0;
 }
@@ -596,6 +673,8 @@
     WND *wndPtr;
     LONG ret;
 
+    TRACE(class,"%x %x\n",hwnd, offset);
+
     switch( offset )
     {
     case GCL_WNDPROC:
@@ -617,6 +696,8 @@
 {
     WND * wndPtr;
     
+    TRACE(class,"%x %x\n",hwnd, offset);
+    
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
     if (offset >= 0)
     {
@@ -651,6 +732,8 @@
 {
     WND * wndPtr;
 
+    TRACE(class,"%x %x\n",hwnd, offset);
+
     switch(offset)
     {
     case GCL_WNDPROC:
@@ -683,6 +766,8 @@
     WORD retval = 0;
     void *ptr;
     
+    TRACE(class,"%x %x %x\n",hwnd, offset, newval);
+    
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
     if (offset >= 0)
     {
@@ -724,6 +809,8 @@
     WND *wndPtr;
     LONG retval;
 
+    TRACE(class,"%x %x %lx\n",hwnd, offset, newval);
+
     switch(offset)
     {
     case GCL_WNDPROC:
@@ -749,6 +836,8 @@
     LONG retval = 0;
     void *ptr;
     
+    TRACE(class,"%x %x %lx\n",hwnd, offset, newval);
+        
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
     if (offset >= 0)
     {
@@ -798,6 +887,8 @@
     WND *wndPtr;
     LONG retval;
 
+    TRACE(class,"%x %x %lx\n",hwnd, offset, newval);
+    
     switch(offset)
     {
     case GCL_WNDPROC:
@@ -831,10 +922,14 @@
  *           GetClassName32A      (USER32.217)
  */
 INT32 WINAPI GetClassName32A( HWND32 hwnd, LPSTR buffer, INT32 count )
-{
+{   INT32 ret;
     WND *wndPtr;
+            
     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
-    return GlobalGetAtomName32A( wndPtr->class->atomName, buffer, count );
+    ret = GlobalGetAtomName32A( wndPtr->class->atomName, buffer, count );
+
+    TRACE(class,"%x %s %x\n",hwnd, buffer, count);
+    return ret;
 }
 
 
@@ -842,10 +937,15 @@
  *           GetClassName32W      (USER32.218)
  */
 INT32 WINAPI GetClassName32W( HWND32 hwnd, LPWSTR buffer, INT32 count )
-{
+{   INT32 ret;
     WND *wndPtr;
+
     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
-    return GlobalGetAtomName32W( wndPtr->class->atomName, buffer, count );
+    ret = GlobalGetAtomName32W( wndPtr->class->atomName, buffer, count );
+
+    TRACE(class,"%x %s %x\n",hwnd, debugstr_w(buffer), count);
+    
+    return ret;
 }
 
 
@@ -858,6 +958,8 @@
     ATOM atom;
     CLASS *classPtr;
 
+    TRACE(class,"%x %p %p\n",hInstance, PTR_SEG_TO_LIN (name), wc);
+    
     hInstance = GetExePtr( hInstance );
     if (!(atom = GlobalFindAtom16( name )) ||
         !(classPtr = CLASS_FindClassByAtom( atom, hInstance )))
@@ -890,11 +992,23 @@
     ATOM atom;
     CLASS *classPtr;
 
-    if (!(atom = GlobalFindAtom32A( name )) ||
-        !(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
-	(classPtr->hInstance && (hInstance != classPtr->hInstance)))
+    TRACE(class,"%x %p %p\n",hInstance, name, wc);
+
+    /* workaround: if hInstance=NULL you expect to get the system classes
+    but this classes (as example from comctl32.dll SysListView) won't be
+    registred with hInstance=NULL in WINE because of the late loading
+    of this dll. fixes file dialogs in WinWord95 (jsch)*/
+
+    if (!(atom=GlobalFindAtom32A(name)) || !(classPtr=CLASS_FindClassByAtom(atom,hInstance)))
         return FALSE;
 
+    if  (classPtr->hInstance && (hInstance != classPtr->hInstance))
+    {
+        if (hInstance) return FALSE;
+        else    
+            WARN(class,"systemclass %s (hInst=0) demanded but only class with hInst!=0 found\n",name);
+    }
+
     wc->style         = classPtr->style;
     wc->lpfnWndProc   = (WNDPROC32)WINPROC_GetProc( classPtr->winproc,
                                                     WIN_PROC_32A );
@@ -919,6 +1033,8 @@
     ATOM atom;
     CLASS *classPtr;
 
+    TRACE(class,"%x %p %p\n",hInstance, name, wc);
+
     if (!(atom = GlobalFindAtom32W( name )) ||
         !(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
 	(classPtr->hInstance && (hInstance != classPtr->hInstance)))
@@ -951,6 +1067,8 @@
     ATOM atom;
     CLASS *classPtr;
 
+    TRACE(class,"%x %p %p\n",hInstance,PTR_SEG_TO_LIN( name ), wc);
+    
     hInstance = GetExePtr( hInstance );
     if (!(atom = GlobalFindAtom16( name )) ||
         !(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
@@ -981,6 +1099,8 @@
     ATOM atom;
     CLASS *classPtr;
 
+    TRACE(class,"%x %p %p\n",hInstance, name, wc);
+    
     if (!(atom = GlobalFindAtom32A( name )) ||
         !(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
         (hInstance != classPtr->hInstance)) return FALSE;
@@ -1009,6 +1129,8 @@
     ATOM atom;
     CLASS *classPtr;
 
+    TRACE(class,"%x %p %p\n",hInstance, name, wc);
+    
     if (!(atom = GlobalFindAtom32W( name )) ||
         !(classPtr = CLASS_FindClassByAtom( atom, hInstance )) ||
         (hInstance != classPtr->hInstance)) return FALSE;
@@ -1033,6 +1155,7 @@
  */
 BOOL16 WINAPI ClassFirst( CLASSENTRY *pClassEntry )
 {
+    TRACE(class,"%p\n",pClassEntry);
     pClassEntry->wNext = 1;
     return ClassNext( pClassEntry );
 }
@@ -1046,6 +1169,8 @@
     int i;
     CLASS *class = firstClass;
 
+    TRACE(class,"%p\n",pClassEntry);
+   
     if (!pClassEntry->wNext) return FALSE;
     for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
     if (!class)
diff --git a/windows/message.c b/windows/message.c
index fa351b0..4e8c632 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -23,6 +23,7 @@
 #include "dde.h"
 #include "queue.h"
 #include "winproc.h"
+#include "task.h"
 #include "process.h"
 #include "thread.h"
 #include "options.h"
@@ -943,11 +944,39 @@
 }
 
 /***********************************************************************
- *         PeekMessageW
+ *         PeekMessageW             Check queue for messages
+ *
+ * Checks for a message in the thread's queue, filtered as for
+ * GetMessage(). Returns immediately whether a message is available
+ * or not.
+ *
+ * Whether a retrieved message is removed from the queue is set by the
+ * _wRemoveMsg_ flags, which should be one of the following values:
+ *
+ *    PM_NOREMOVE    Do not remove the message from the queue. 
+ *
+ *    PM_REMOVE      Remove the message from the queue.
+ *
+ * In addition, PM_NOYIELD may be combined into _wRemoveMsg_ to
+ * request that the system not yield control during PeekMessage();
+ * however applications may not rely on scheduling behavior.
+ * 
+ * RETURNS
+ *
+ *  Nonzero if a message is available and is retrieved, zero otherwise.
+ *
+ * CONFORMANCE
+ *
+ * ECMA-234, Win32
+ *
  */
-BOOL32 WINAPI PeekMessage32W( LPMSG32 lpmsg, HWND32 hwnd,
-                              UINT32 min,UINT32 max,UINT32 wRemoveMsg)
-{
+BOOL32 WINAPI PeekMessage32W( 
+  LPMSG32 lpmsg,    /* buffer to receive message */
+  HWND32 hwnd,      /* restrict to messages for hwnd */
+  UINT32 min,       /* minimum message to receive */
+  UINT32 max,       /* maximum message to receive */
+  UINT32 wRemoveMsg /* removal flags */ 
+) {
 	/* FIXME: Should perform Unicode translation on specific messages */
 	return PeekMessage32A(lpmsg,hwnd,min,max,wRemoveMsg);
 }
@@ -983,10 +1012,38 @@
 }
 
 /***********************************************************************
- *          GetMessage32W   (USER32.274)
+ *          GetMessage32W   (USER32.274) Retrieve next message
+ *
+ * GetMessage retrieves the next event from the calling thread's
+ * queue and deposits it in *lpmsg.
+ *
+ * If _hwnd_ is not NULL, only messages for window _hwnd_ and its
+ * children as specified by IsChild() are retrieved. If _hwnd_ is NULL
+ * all application messages are retrieved.
+ *
+ * _min_ and _max_ specify the range of messages of interest. If
+ * min==max==0, no filtering is performed. Useful examples are
+ * WM_KEYFIRST and WM_KEYLAST to retrieve keyboard input, and
+ * WM_MOUSEFIRST and WM_MOUSELAST to retrieve mouse input.
+ *
+ * WM_PAINT messages are not removed from the queue; they remain until
+ * processed. Other messages are removed from the queue.
+ *
+ * RETURNS
+ *
+ * -1 on error, 0 if message is WM_QUIT, nonzero otherwise.
+ *
+ * CONFORMANCE
+ *
+ * ECMA-234, Win32
+ * 
  */
-BOOL32 WINAPI GetMessage32W(MSG32* lpmsg,HWND32 hwnd,UINT32 min,UINT32 max)
-{
+BOOL32 WINAPI GetMessage32W(
+  MSG32* lpmsg, /* buffer to receive message */
+  HWND32 hwnd,  /* restrict to messages for hwnd */
+  UINT32 min,   /* minimum message to receive */
+  UINT32 max    /* maximum message to receive */
+) {
     BOOL32 ret;
     MSG16 *msg = SEGPTR_NEW(MSG16);
     if (!msg) return 0;
@@ -1335,13 +1392,48 @@
 
 
 /***********************************************************************
- *           WaitMessage    (USER.112) (USER32.578)
+ *  WaitMessage    (USER.112) (USER32.578)  Suspend thread pending messages
+ *
+ * WaitMessage() suspends a thread until events appear in the thread's
+ * queue.
+ *
+ * BUGS
+ *
+ * Is supposed to return BOOL under Win32.
+ *
+ * CONFORMANCE
+ *
+ * ECMA-234, Win32
+ * 
  */
 void WINAPI WaitMessage( void )
 {
     QUEUE_WaitBits( QS_ALLINPUT );
 }
 
+/***********************************************************************
+ *           MsgWaitForMultipleObjects    (USER32.400)
+ */
+DWORD WINAPI MsgWaitForMultipleObjects( DWORD nCount, HANDLE32 *pHandles,
+                                        BOOL32 fWaitAll, DWORD dwMilliseconds,
+                                        DWORD dwWakeMask )
+{
+    DWORD retv;
+
+    TDB *currTask = (TDB *)GlobalLock16( GetCurrentTask() );
+    HQUEUE16 hQueue = currTask? currTask->hQueue : 0;
+    MESSAGEQUEUE *msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
+    if (!msgQueue) return 0xFFFFFFFF;
+
+    msgQueue->changeBits = 0;
+    msgQueue->wakeMask = dwWakeMask;
+
+    retv = SYNC_DoWait( nCount, pHandles, fWaitAll, dwMilliseconds, FALSE, TRUE );
+
+    return retv;
+}
+
+
 
 struct accent_char
 {
@@ -1649,6 +1741,24 @@
 
 /***********************************************************************
  *           DispatchMessage32W   (USER32.142)
+ *
+ * Process the message specified in the structure *_msg_.
+ *
+ * If the lpMsg parameter points to a WM_TIMER message and the
+ * parameter of the WM_TIMER message is not NULL, the lParam parameter
+ * points to the function that is called instead of the window
+ * procedure.
+ *  
+ * The message must be valid.
+ *
+ * RETURNS
+ *
+ *   DispatchMessage() returns the result of the window procedure invoked.
+ *
+ * CONFORMANCE
+ *
+ *   ECMA-234, Win32 
+ *
  */
 LONG WINAPI DispatchMessage32W( const MSG32* msg )
 {
diff --git a/windows/msgbox.c b/windows/msgbox.c
index 6c084e4..441ea4a 100644
--- a/windows/msgbox.c
+++ b/windows/msgbox.c
@@ -183,6 +183,7 @@
  */
 INT16 WINAPI MessageBox16( HWND16 hwnd, LPCSTR text, LPCSTR title, UINT16 type)
 {
+    WARN(dialog,"Messagebox\n");
     return MessageBox32A( hwnd, text, title, type );
 }
 
@@ -193,7 +194,7 @@
 INT32 WINAPI MessageBox32A(HWND32 hWnd, LPCSTR text, LPCSTR title, UINT32 type)
 {
     MSGBOXPARAMS32A mbox;
-
+    WARN(dialog,"Messagebox\n");
     if (!text) text="<WINE-NULL>";
     if (!title)
       title="Error";
@@ -214,7 +215,11 @@
 {
     LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
     LPSTR textA  = HEAP_strdupWtoA( GetProcessHeap(), 0, text );
-    INT32 ret = MessageBox32A( hwnd, textA, titleA, type );
+    INT32 ret;
+    
+    WARN(dialog,"Messagebox\n");
+
+    ret = MessageBox32A( hwnd, textA, titleA, type );
     HeapFree( GetProcessHeap(), 0, titleA );
     HeapFree( GetProcessHeap(), 0, textA );
     return ret;
@@ -227,6 +232,7 @@
 INT32 WINAPI MessageBoxEx32A( HWND32 hWnd, LPCSTR text, LPCSTR title,
                               UINT32 type, WORD langid )
 {
+    WARN(dialog,"Messagebox\n");
     /* ignore language id for now */
     return MessageBox32A(hWnd,text,title,type);
 }
@@ -237,6 +243,7 @@
 INT32 WINAPI MessageBoxEx32W( HWND32 hWnd, LPCWSTR text, LPCWSTR title,
                               UINT32 type, WORD langid )
 {
+    WARN(dialog,"Messagebox\n");
     /* ignore language id for now */
     return MessageBox32W(hWnd,text,title,type);
 }
@@ -247,6 +254,7 @@
 INT16 WINAPI MessageBoxIndirect16( LPMSGBOXPARAMS16 msgbox )
 {
     MSGBOXPARAMS32A msgbox32;
+    WARN(dialog,"Messagebox\n");    
     
     msgbox32.cbSize		= msgbox->cbSize;
     msgbox32.hwndOwner		= msgbox->hwndOwner;
@@ -270,6 +278,7 @@
  */
 INT32 WINAPI MessageBoxIndirect32A( LPMSGBOXPARAMS32A msgbox )
 {
+    WARN(dialog,"Messagebox\n");
     return DialogBoxIndirectParam32A( msgbox->hInstance,
    				      SYSRES_GetResPtr( SYSRES_DIALOG_MSGBOX ),
                                       msgbox->hwndOwner, MSGBOX_DlgProc,
@@ -282,10 +291,13 @@
 INT32 WINAPI MessageBoxIndirect32W( LPMSGBOXPARAMS32W msgbox )
 {
     MSGBOXPARAMS32A	msgboxa;
+    WARN(dialog,"Messagebox\n");
 
     memcpy(&msgboxa,msgbox,sizeof(msgboxa));
-    if (msgbox->lpszCaption)	lstrcpyWtoA(msgboxa.lpszCaption,msgbox->lpszCaption);
-    if (msgbox->lpszText)	lstrcpyWtoA(msgboxa.lpszText,msgbox->lpszText);
+    if (msgbox->lpszCaption)	
+      lstrcpyWtoA(msgboxa.lpszCaption,msgbox->lpszCaption);
+    if (msgbox->lpszText)	
+      lstrcpyWtoA(msgboxa.lpszText,msgbox->lpszText);
 
     return MessageBoxIndirect32A(&msgboxa);
 }
@@ -296,6 +308,7 @@
  */
 void WINAPI FatalAppExit16( UINT16 action, LPCSTR str )
 {
+    WARN(dialog,"AppExit\n");
     FatalAppExit32A( action, str );
 }
 
@@ -305,6 +318,7 @@
  */
 void WINAPI FatalAppExit32A( UINT32 action, LPCSTR str )
 {
+    WARN(dialog,"AppExit\n");
     MessageBox32A( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
     TASK_KillCurrentTask(0);
 }
@@ -315,6 +329,7 @@
  */
 void WINAPI FatalAppExit32W( UINT32 action, LPCWSTR str )
 {
+    WARN(dialog,"AppExit\n");
     MessageBox32W( 0, str, NULL, MB_SYSTEMMODAL | MB_OK );
     TASK_KillCurrentTask(0);
 }
diff --git a/windows/nonclient.c b/windows/nonclient.c
index 8ab8abf..82d779a 100644
--- a/windows/nonclient.c
+++ b/windows/nonclient.c
@@ -26,10 +26,6 @@
 #include "options.h"
 
 
-int  NC_MaxControlNudge;
-int  NC_MinControlNudge;
-UINT32  NC_CaptionTextFlags;
-
 static HBITMAP16 hbitmapClose = 0;
 static HBITMAP16 hbitmapCloseD = 0;
 static HBITMAP16 hbitmapMinimize = 0;
@@ -921,7 +917,7 @@
 	if (wndPtr->dwStyle & WS_SYSMENU)
 	    rect.right -= sysMetrics[SM_CYCAPTION] + 1;
 	
-	GRAPH_DrawBitmap( hdc, bm, rect.right + NC_MinControlNudge -
+	GRAPH_DrawBitmap( hdc, bm, rect.right -
 			  (sysMetrics[SM_CXSIZE] + bmsz.cx) / 2,
 			  rect.top + (sysMetrics[SM_CYCAPTION] - 1 - bmsz.cy) / 2,
 			  0, 0, bmsz.cx, bmsz.cy, FALSE );
@@ -970,10 +966,10 @@
 	    rect.right -= sysMetrics[SM_CYCAPTION] + 1;
 
 	if (wndPtr->dwStyle & WS_MAXIMIZEBOX)
-	    rect.right += -1 + NC_MaxControlNudge -
+	    rect.right += -1 -
 		(sysMetrics[SM_CXSIZE] + bmsz.cx) / 2;
 
-	GRAPH_DrawBitmap( hdc, bm, rect.right + NC_MinControlNudge -
+	GRAPH_DrawBitmap( hdc, bm, rect.right -
 			  (sysMetrics[SM_CXSIZE] + bmsz.cx) / 2,
 			  rect.top + (sysMetrics[SM_CYCAPTION] - 1 - bmsz.cy) / 2,
 			  0, 0, bmsz.cx, bmsz.cy, FALSE );
@@ -1266,7 +1262,7 @@
 
     if (wndPtr->flags & WIN_MANAGED) return;
 
-    GRAPH_DrawLines( hdc, sep, 1, TWEAK_PenC095 );
+    GRAPH_DrawLines( hdc, sep, 1, GetSysColorPen32(COLOR_3DFACE) );
     r.bottom--;
 
     FillRect32( hdc, &r, GetSysColorBrush32(active ? COLOR_ACTIVECAPTION :
@@ -1309,7 +1305,8 @@
 	else SetTextColor32( hdc, GetSysColor32( COLOR_INACTIVECAPTIONTEXT ) );
 	SetBkMode32( hdc, TRANSPARENT );
 	r.left += 2;
-	DrawText32A( hdc, buffer, -1, &r, NC_CaptionTextFlags );
+	DrawText32A( hdc, buffer, -1, &r,
+		     DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
 	DeleteObject32 (SelectObject32 (hdc, hOldFont));
     }
 }
diff --git a/windows/queue.c b/windows/queue.c
index b45bbe2..712dea1 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -13,6 +13,7 @@
 #include "win.h"
 #include "clipboard.h"
 #include "hook.h"
+#include "heap.h"
 #include "thread.h"
 #include "process.h"
 #include "debug.h"
@@ -235,6 +236,27 @@
     {
         queue->wakeMask = 0;
         PostEvent( queue->hTask );
+
+        /* Wake up thread waiting for message */
+        /* NOTE: This should really wake up *the* thread that owns
+                 the queue. Since we dont't have thread-local message
+                 queues yet, we wake up all waiting threads ... */
+        SYSTEM_LOCK();
+        {
+            TDB *pTask = (TDB *)GlobalLock16( queue->hTask );
+            PDB32 *pdb = pTask? pTask->thdb->process : NULL;
+            THREAD_ENTRY *entry = pdb? pdb->thread_list->next : NULL;
+
+            if (entry)
+                for (;;)
+                {
+                    if (entry->thread->wait_struct.wait_msg)
+                        SYNC_MsgWakeUp( entry->thread );
+                    if (entry == pdb->thread_list) break;
+                    entry = entry->next;
+                }
+        }
+        SYSTEM_UNLOCK();
     }
 }
 
diff --git a/windows/win.c b/windows/win.c
index d9366e4..1b09c8a 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -30,6 +30,7 @@
 #include "winproc.h"
 #include "thread.h"
 #include "debug.h"
+#include "winerror.h"
 
 /* Desktop window */
 static WND *pWndDesktop = NULL;
@@ -458,13 +459,13 @@
     WND *wndPtr;
     HWND16 hwnd, hwndLinkAfter;
     POINT32 maxSize, maxPos, minTrack, maxTrack;
-    LRESULT (WINAPI *localSend32)(HWND32, UINT32, WPARAM32, LPARAM);
+    LRESULT (CALLBACK *localSend32)(HWND32, UINT32, WPARAM32, LPARAM);
 
-    TRACE(win, "%s %s %08lx %08lx %d,%d %dx%d "
-		 "%04x %04x %08x %p\n", debugres_a(cs->lpszName), 
-		 debugres_a(cs->lpszClass), cs->dwExStyle, 
-		 cs->style, cs->x, cs->y, cs->cx, cs->cy,
-		 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams);
+    TRACE(win, "%s %s %08lx %08lx %d,%d %dx%d %04x %04x %08x %p\n",
+          unicode ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName), 
+          unicode ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
+          cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
+          cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
 
     /* Find the parent window */
 
@@ -563,10 +564,13 @@
     if (HOOK_IsHooked( WH_CBT ))
     {
 	CBT_CREATEWND32A cbtc;
+        LRESULT ret;
 
 	cbtc.lpcs = cs;
 	cbtc.hwndInsertAfter = hwndLinkAfter;
-	if ( HOOK_CallHooks32A(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc) )
+        ret = unicode ? HOOK_CallHooks32W(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc)
+                      : HOOK_CallHooks32A(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc);
+        if (ret)
 	{
 	    TRACE(win, "CBT-hook returned 0\n");
 	    USER_HEAP_FREE( hwnd );
@@ -1209,7 +1213,9 @@
  */
 HWND32 WINAPI FindWindow32A( LPCSTR className, LPCSTR title )
 {
-    return FindWindowEx32A( 0, 0, className, title );
+    HWND32 ret = FindWindowEx32A( 0, 0, className, title );
+    if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
+    return ret;
 }
 
 
@@ -1225,7 +1231,11 @@
     {
         /* If the atom doesn't exist, then no class */
         /* with this name exists either. */
-        if (!(atom = GlobalFindAtom32A( className ))) return 0;
+        if (!(atom = GlobalFindAtom32A( className ))) 
+        {
+            SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
+            return 0;
+        }
     }
     return WIN_FindWindow( parent, child, atom, title );
 }
@@ -1245,7 +1255,11 @@
     {
         /* If the atom doesn't exist, then no class */
         /* with this name exists either. */
-        if (!(atom = GlobalFindAtom32W( className ))) return 0;
+        if (!(atom = GlobalFindAtom32W( className )))
+        {
+            SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
+            return 0;
+        }
     }
     buffer = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
     hwnd = WIN_FindWindow( parent, child, atom, buffer );
@@ -1625,10 +1639,79 @@
 
 
 /**********************************************************************
- *	     SetWindowLong32W    (USER32.518)
+ *	     SetWindowLong32W    (USER32.518) Set window attribute
+ *
+ * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
+ * value in a window's extra memory. 
+ *
+ * The _hwnd_ parameter specifies the window.  is the handle to a
+ * window that has extra memory. The _newval_ parameter contains the
+ * new attribute or extra memory value.  If positive, the _offset_
+ * parameter is the byte-addressed location in the window's extra
+ * memory to set.  If negative, _offset_ specifies the window
+ * attribute to set, and should be one of the following values:
+ *
+ * GWL_EXSTYLE      The window's extended window style
+ *
+ * GWL_STYLE        The window's window style. 
+ *
+ * GWL_WNDPROC      Pointer to the window's window procedure. 
+ *
+ * GWL_HINSTANCE    The window's pplication instance handle.
+ *
+ * GWL_ID           The window's identifier.
+ *
+ * GWL_USERDATA     The window's user-specified data. 
+ *
+ * If the window is a dialog box, the _offset_ parameter can be one of 
+ * the following values:
+ *
+ * DWL_DLGPROC      The address of the window's dialog box procedure.
+ *
+ * DWL_MSGRESULT    The return value of a message 
+ *                  that the dialog box procedure processed.
+ *
+ * DWL_USER         Application specific information.
+ *
+ * RETURNS
+ *
+ * If successful, returns the previous value located at _offset_. Otherwise,
+ * returns 0.
+ *
+ * NOTES
+ *
+ * Extra memory for a window class is specified by a nonzero cbWndExtra 
+ * parameter of the WNDCLASS structure passed to RegisterClass() at the
+ * time of class creation.
+ *  
+ * Using GWL_WNDPROC to set a new window procedure effectively creates
+ * a window subclass. Use CallWindowProc() in the new windows procedure
+ * to pass messages to the superclass's window procedure.
+ *
+ * The user data is reserved for use by the application which created
+ * the window.
+ *
+ * Do not use GWL_STYLE to change the window's WS_DISABLE style;
+ * instead, call the EnableWindow() function to change the window's
+ * disabled state.
+ *
+ * Do not use GWL_HWNDPARENT to reset the window's parent, use
+ * SetParent() instead.
+ *
+ * BUGS
+ *
+ * GWL_STYLE does not dispatch WM_STYLE_... messages.
+ *
+ * CONFORMANCE
+ *
+ * ECMA-234, Win32 
+ *
  */
-LONG WINAPI SetWindowLong32W( HWND32 hwnd, INT32 offset, LONG newval )
-{
+LONG WINAPI SetWindowLong32W( 
+    HWND32 hwnd, /* window to alter */
+    INT32 offset, /* offset, in bytes, of location to alter */
+    LONG newval  /* new value of location */
+) {
     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
 }
 
@@ -1656,8 +1739,8 @@
  */
 INT32 WINAPI InternalGetWindowText(HWND32 hwnd,LPWSTR lpString,INT32 nMaxCount )
 {
-	FIXME(win,"(0x%08lx,0x%08lx,%ld),stub!\n",hwnd,lpString,nMaxCount);
-	return GetWindowText32W(hwnd,lpString,nMaxCount);
+    FIXME(win,"(0x%08x,%s,0x%x),stub!\n",hwnd,debugstr_w(lpString),nMaxCount);
+    return GetWindowText32W(hwnd,lpString,nMaxCount);
 }
 
 
diff --git a/windows/winproc.c b/windows/winproc.c
index 03fdeff..f62f86f 100644
--- a/windows/winproc.c
+++ b/windows/winproc.c
@@ -249,8 +249,10 @@
     {
         if (((WINDOWPROC *)proc)->type == WIN_PROC_16)
             return (WNDPROC16)&((WINDOWPROC *)proc)->thunk;
+        else if (type != ((WINDOWPROC *)proc)->type)
+            /* Have to return the jmp address if types don't match */
+            return (WNDPROC16)&((WINDOWPROC *)proc)->jmp;
         else
-            /* return (WNDPROC16)&((WINDOWPROC *)proc)->jmp; */
             /* Some Win16 programs want to get back the proc they set */
             return (WNDPROC16)((WINDOWPROC *)proc)->thunk.t_from16.proc;
     }
@@ -803,12 +805,15 @@
             *plparam = (LPARAM)wp;
         }
         return 1;
+    case WM_NOTIFY:
+    	*plparam = (LPARAM)PTR_SEG_TO_LIN(*plparam);
+    	return 1;
     case WM_ASKCBFORMATNAME:
     case WM_DEVMODECHANGE:
     case WM_PAINTCLIPBOARD:
     case WM_SIZECLIPBOARD:
     case WM_WININICHANGE:
-        WARN( msg, "message %04x needs translation\n",msg16 );
+        FIXME( msg, "message %04x needs translation\n",msg16 );
         return -1;
 
     default:  /* No translation needed */
@@ -1858,11 +1863,36 @@
 
 
 /**********************************************************************
- *	     CallWindowProc32A    (USER32.18)
+ *	     CallWindowProc32A    (USER32.18) 
+ *
+ * The CallWindowProc() function invokes the windows procedure _func_,
+ * with _hwnd_ as the target window, the message specified by _msg_, and
+ * the message parameters _wParam_ and _lParam_.
+ *
+ * Some kinds of argument conversion may be done, I'm not sure what.
+ *
+ * CallWindowProc() may be used for windows subclassing. Use
+ * SetWindowLong() to set a new windows procedure for windows of the
+ * subclass, and handle subclassed messages in the new windows
+ * procedure. The new windows procedure may then use CallWindowProc()
+ * with _func_ set to the parent class's windows procedure to dispatch
+ * the message to the superclass.
+ *
+ * RETURNS
+ *
+ *    The return value is message dependent.
+ *
+ * CONFORMANCE
+ *
+ *   ECMA-234, Win32 
  */
-LRESULT WINAPI CallWindowProc32A( WNDPROC32 func, HWND32 hwnd, UINT32 msg,
-                                  WPARAM32 wParam, LPARAM lParam )
-{
+LRESULT WINAPI CallWindowProc32A( 
+    WNDPROC32 func, /* window procedure */
+    HWND32 hwnd, /* target window */
+    UINT32 msg,  /* message */
+    WPARAM32 wParam, /* message dependent parameter */
+    LPARAM lParam    /* message dependent parameter */
+) {
     WINDOWPROC *proc = WINPROC_GetPtr( (WNDPROC16)func );
 
     if (!proc) return WINPROC_CallWndProc32( func, hwnd, msg, wParam, lParam );