Release 960428

Sun Apr 28 14:32:43 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [Makefile.in]
	Subdir memory is now also compiled for Winelib, in order to get
	the Win32 heap functions.

	* [if1632/Makefile.in]
	Renamed winprocs and winprocs32 to wprocs and wprocs32 to avoid
	DLL names > 8 characters.

	* [loader/builtin.c] (New file)
	Grouped all built-in DLLs code in a single file.

	* [memory/global.c]
	Use the Win32 heap code instead of malloc() to allocate linear
	memory. This will help test the heap code.

	* [memory/local.c]
	Fixed FreeSelector() to clear DS and ES correctly for huge blocks.

	* [tools/build.c] [if1632/relay.c]
	Removed 'id' directive in spec files. For relay debugging, the DLL
	entry point is now computed from the CS:IP entry point address.
	Added 'heap' directive to specifiy a local heap for the DLL. USER
	and GDI heap are now created this way.

	* [windows/class.c] [include/class.h]
	Changed the class structure to use pointers instead of handles.
	Changed Get/SetClassWord/Long to use a switch statement; this
	allows changing the layout of the CLASS structure.

	* [windows/win.c] [include/win.h]
	Use a CLASS * instead of a handle for the window class.

Sat Apr 27 18:10:11 Martin von Loewis <loewis@informatik.hu-berlin.de>

	* [if1632/kernel32.spec] [memory/global.c]
	  [win32/memory.c] [win32/process.c]
	GetProcessAffinityMask,GlobalLock,IsBadReadPtr,IsBadWritePtr,
	LocalLock,SetThreadAffinityMask: new relays.

	* [win32/cursoricon32.c]
	Return same handle if a cursor is loaded multiple times.

Sat Apr 27 15:13:37 1996  Bang Jun Young <bangjy@nownuri.nowcom.co.kr>

	* [resources/sysres_Ko.rc]
        Added support for Korean [Ko] language.

Fri Apr 26 00:49:05 1996  Huw D. M. Davies <h.davies1@physics.oxford.ac.uk>

	* [objects/dc.c] [objects/font.c]
	Fixed problem with SaveDC()/RestoreDC() and font cache 'used' count.

	* [objects/metafile.c] [objects/dcvalues.c]
	Fixed broken SetTextAlign() on metafiles.

	* [objects/metafile.c]
	Delete objects in handle table at end of PlayMetaFile().

Wed Apr 24 19:21:01  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [if1632/ver.spec] [misc/ver.c] [include/ver.h] (New files)
	VER.DLL (partially) implemented (VerFindFile,VerInstallFile)
	[If it doesn't work for you, use -dll -ver and report it to me]

	* [if1632/user32.spec] [if1632/kernel32.spec] [if1632/shell.spec]
	  [if1632/shell32.spec] [misc/ole2nls.c] [windows/message.c]
	  [windows/graphics.c]
	Simple win32 functions, where we can just use the win16 counterpart.
	Misc. stubs. 

	* [misc/lstr.c]
	Someone reported a _lstrlen(NULL). NULL is a valid argument. Fixed.

	* [misc/registry.c]
	Some alloclens were off by 1, one double fclose() fixed.
	Requesting value 0 of a key with no values returns an error 
	(should we always return a made up value NULL? what does win3.1?)

Tue Apr 23 17:00:00 1996 Alex Korobka <alex@phm30.pharm.sunysb.edu>

	* [misc/shell.c]
	Implemented FindEnvironmentString(), DoEnvironmentSubst(),
	ExtractIcon(), InternalExtractIcon() and ExtractAssociatedIcon().

	* [misc/user.c]
	Do extensive cleanup on application exit.

	* [windows/hook.c] [windows/win.c] [windows/class.c]
	Added miscellaneous cleanup routines.

	* [controls/menu.c]
	More efficient popup menu window handling.

Mon Apr 22 21:35:22 1996  Albrecht Kleine  <kleine@ak.sax.de>

	* [include/windows.h][objects/oembitmap.c][include/bitmaps/obm_trtype]
	Added "TT-bitmap" for later usage in a ChooseFont() ownerdraw combobox.
diff --git a/ANNOUNCE b/ANNOUNCE
index 23bded41..90ff09d 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,15 +1,14 @@
-This is release 960421 of Wine the MS Windows emulator.  This is still a
+This is release 960428 of Wine the MS Windows emulator.  This is still a
 developer's only release.  There are many bugs and many unimplemented API
 features.  Most applications still do not work.
 
 Patches should be submitted to "julliard@lrc.epfl.ch".  Please don't
 forget to include a ChangeLog entry.
 
-WHAT'S NEW with Wine-960421: (see ChangeLog for details)
-	- Preliminary support for W32SYS.DLL.
-	- Built-in COMMDLG improvements.
-	- New format and location for registry files.
-	- Window refresh optimized.
+WHAT'S NEW with Wine-960428: (see ChangeLog for details)
+	- Preliminary support for VER.DLL.
+	- Suuport for Korean [Ko] language.
+	- More Win32 functions.
 	- Lots of bug fixes.
 
 See the README file in the distribution for installation instructions.
@@ -18,10 +17,10 @@
 the release is available at the ftp sites.  The sources will be available
 from the following locations:
 
-    sunsite.unc.edu:/pub/Linux/ALPHA/wine/development/Wine-960421.tar.gz
-    tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-960421.tar.gz
-    ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-960421.tar.gz
-    aris.com:/pub/linux/ALPHA/Wine/development/Wine-960421.tar.gz
+    sunsite.unc.edu:/pub/Linux/ALPHA/wine/development/Wine-960428.tar.gz
+    tsx-11.mit.edu:/pub/linux/ALPHA/Wine/development/Wine-960428.tar.gz
+    ftp.infomagic.com:/pub/mirrors/linux/wine/development/Wine-960428.tar.gz
+    aris.com:/pub/linux/ALPHA/Wine/development/Wine-960428.tar.gz
 
 It should also be available from any site that mirrors tsx-11 or sunsite.
 
diff --git a/ChangeLog b/ChangeLog
index f8d4c3d..de17466 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,105 @@
 ----------------------------------------------------------------------
+Sun Apr 28 14:32:43 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>
+
+	* [Makefile.in]
+	Subdir memory is now also compiled for Winelib, in order to get
+	the Win32 heap functions.
+
+	* [if1632/Makefile.in]
+	Renamed winprocs and winprocs32 to wprocs and wprocs32 to avoid
+	DLL names > 8 characters.
+
+	* [loader/builtin.c] (New file)
+	Grouped all built-in DLLs code in a single file.
+
+	* [memory/global.c]
+	Use the Win32 heap code instead of malloc() to allocate linear
+	memory. This will help test the heap code.
+
+	* [memory/local.c]
+	Fixed FreeSelector() to clear DS and ES correctly for huge blocks.
+
+	* [tools/build.c] [if1632/relay.c]
+	Removed 'id' directive in spec files. For relay debugging, the DLL
+	entry point is now computed from the CS:IP entry point address.
+	Added 'heap' directive to specifiy a local heap for the DLL. USER
+	and GDI heap are now created this way.
+
+	* [windows/class.c] [include/class.h]
+	Changed the class structure to use pointers instead of handles.
+	Changed Get/SetClassWord/Long to use a switch statement; this
+	allows changing the layout of the CLASS structure.
+
+	* [windows/win.c] [include/win.h]
+	Use a CLASS * instead of a handle for the window class.
+
+Sat Apr 27 18:10:11 Martin von Loewis <loewis@informatik.hu-berlin.de>
+
+	* [if1632/kernel32.spec] [memory/global.c]
+	  [win32/memory.c] [win32/process.c]
+	GetProcessAffinityMask,GlobalLock,IsBadReadPtr,IsBadWritePtr,
+	LocalLock,SetThreadAffinityMask: new relays.
+
+	* [win32/cursoricon32.c]
+	Return same handle if a cursor is loaded multiple times.
+
+Sat Apr 27 15:13:37 1996  Bang Jun Young <bangjy@nownuri.nowcom.co.kr>
+
+	* [resources/sysres_Ko.rc]
+        Added support for Korean [Ko] language.
+
+Fri Apr 26 00:49:05 1996  Huw D. M. Davies <h.davies1@physics.oxford.ac.uk>
+
+	* [objects/dc.c] [objects/font.c]
+	Fixed problem with SaveDC()/RestoreDC() and font cache 'used' count.
+
+	* [objects/metafile.c] [objects/dcvalues.c]
+	Fixed broken SetTextAlign() on metafiles.
+
+	* [objects/metafile.c]
+	Delete objects in handle table at end of PlayMetaFile().
+
+Wed Apr 24 19:21:01  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
+
+	* [if1632/ver.spec] [misc/ver.c] [include/ver.h] (New files)
+	VER.DLL (partially) implemented (VerFindFile,VerInstallFile)
+	[If it doesn't work for you, use -dll -ver and report it to me]
+
+	* [if1632/user32.spec] [if1632/kernel32.spec] [if1632/shell.spec]
+	  [if1632/shell32.spec] [misc/ole2nls.c] [windows/message.c]
+	  [windows/graphics.c]
+	Simple win32 functions, where we can just use the win16 counterpart.
+	Misc. stubs. 
+
+	* [misc/lstr.c]
+	Someone reported a _lstrlen(NULL). NULL is a valid argument. Fixed.
+
+	* [misc/registry.c]
+	Some alloclens were off by 1, one double fclose() fixed.
+	Requesting value 0 of a key with no values returns an error 
+	(should we always return a made up value NULL? what does win3.1?)
+
+Tue Apr 23 17:00:00 1996 Alex Korobka <alex@phm30.pharm.sunysb.edu>
+
+	* [misc/shell.c]
+	Implemented FindEnvironmentString(), DoEnvironmentSubst(),
+	ExtractIcon(), InternalExtractIcon() and ExtractAssociatedIcon().
+
+	* [misc/user.c]
+	Do extensive cleanup on application exit.
+
+	* [windows/hook.c] [windows/win.c] [windows/class.c]
+	Added miscellaneous cleanup routines.
+
+	* [controls/menu.c]
+	More efficient popup menu window handling.
+
+Mon Apr 22 21:35:22 1996  Albrecht Kleine  <kleine@ak.sax.de>
+
+	* [include/windows.h][objects/oembitmap.c][include/bitmaps/obm_trtype]
+	Added "TT-bitmap" for later usage in a ChooseFont() ownerdraw combobox.
+
+----------------------------------------------------------------------
 Sat Apr 20 23:23:16 1996  Robert Pouliot <krynos@qbc.clic.net>
 
 	* [resources/sysres_Fr.rc] [resources/TODO]
diff --git a/Makefile.in b/Makefile.in
index 12bd1b7..c333861 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -53,6 +53,7 @@
 	files \
 	ipc \
 	loader \
+	memory \
 	misc \
 	multimedia \
 	objects \
@@ -65,7 +66,6 @@
 	debugger \
 	debugger/readline \
 	if1632 \
-	memory \
 	miscemu
 
 LIBSUBDIRS = library
@@ -79,6 +79,7 @@
 	files/files.o \
 	ipc/ipc.o \
 	loader/loader.o \
+	memory/memory.o \
 	misc/misc.o \
 	multimedia/multimedia.o \
 	objects/objects.o \
@@ -90,7 +91,6 @@
 	debugger/debugger.o \
 	debugger/readline/readline.o \
 	if1632/if1632.o \
-	memory/memory.o \
 	miscemu/miscemu.o
 
 LIBOBJS = library/library.o
diff --git a/controls/menu.c b/controls/menu.c
index 78e991d..eecb575 100644
--- a/controls/menu.c
+++ b/controls/menu.c
@@ -18,6 +18,7 @@
 #include "windows.h"
 #include "syscolor.h"
 #include "sysmetrics.h"
+#include "task.h"
 #include "win.h"
 #include "menu.h"
 #include "module.h"
@@ -65,6 +66,12 @@
 static HBITMAP hStdCheck = 0;
 static HBITMAP hStdMnArrow = 0;
 
+/* we _can_ use global popup window because there's no way 2 menues can
+ * be tracked at the same time.
+ */ 
+
+static WND* pTopPWnd   = 0;
+static UINT uSubPWndLevel = 0;
 
 /***********************************************************************
  *           MENU_Init
@@ -678,6 +685,23 @@
     return lppop->Height;
 } 
 
+/***********************************************************************
+ *	     MENU_SwitchTPWndTo
+ */
+BOOL MENU_SwitchTPWndTo( HTASK hTask)
+{
+  /* This is supposed to be called when popup is hidden */
+
+  TDB* task = (TDB*)GlobalLock(hTask);
+
+  if( !task ) return 0;
+
+  /* if this task got as far as menu tracking it must have a queue */
+
+  pTopPWnd->hInstance = task->hInstance;
+  pTopPWnd->hmemTaskQ = task->hQueue;
+  return 1;
+}
 
 /***********************************************************************
  *           MENU_ShowPopup
@@ -686,7 +710,9 @@
  */
 static BOOL MENU_ShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, int x, int y)
 {
-    POPUPMENU *menu;
+    POPUPMENU 	*menu;
+    WND 	*wndPtr = NULL;
+    BOOL	 skip_init = 0;
 
     if (!(menu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hmenu ))) return FALSE;
     if (menu->FocusedItem != NO_SELECTED_ITEM)
@@ -698,21 +724,47 @@
     SendMessage( hwndOwner, WM_INITMENUPOPUP, (WPARAM)hmenu,
 		 MAKELONG( id, (menu->wFlags & MF_SYSMENU) ? 1 : 0 ));
     MENU_PopupMenuCalcSize( menu, hwndOwner );
-    if (!menu->hWnd)
+
+    wndPtr = WIN_FindWndPtr( hwndOwner );
+    if (!wndPtr) return FALSE;
+
+    if (!pTopPWnd)
     {
-	WND *wndPtr = WIN_FindWndPtr( hwndOwner );
-	if (!wndPtr) return FALSE;
-	menu->hWnd = CreateWindow( POPUPMENU_CLASS_ATOM, (SEGPTR)0,
-				   WS_POPUP | WS_BORDER, x, y, 
-				   menu->Width + 2*SYSMETRICS_CXBORDER,
-				   menu->Height + 2*SYSMETRICS_CYBORDER,
-				   0, 0, wndPtr->hInstance, (SEGPTR)hmenu );
-	if (!menu->hWnd) return FALSE;
+	pTopPWnd = WIN_FindWndPtr(CreateWindow( POPUPMENU_CLASS_ATOM, (SEGPTR)0,
+				   		WS_POPUP | WS_BORDER, x, y, 
+				   		menu->Width + 2*SYSMETRICS_CXBORDER,
+				   		menu->Height + 2*SYSMETRICS_CYBORDER,
+				   		0, 0, wndPtr->hInstance, (SEGPTR)hmenu ));
+	if (!pTopPWnd) return FALSE;
+	skip_init = TRUE;
     }
-    else SetWindowPos( menu->hWnd, 0, x, y,
-		       menu->Width + 2*SYSMETRICS_CXBORDER,
-		       menu->Height + 2*SYSMETRICS_CYBORDER,
-		       SWP_NOACTIVATE | SWP_NOZORDER );
+
+    if( uSubPWndLevel )
+    {
+	/* create new window for the submenu */
+	HWND  hWnd = CreateWindow( POPUPMENU_CLASS_ATOM, (SEGPTR)0,
+                                   WS_POPUP | WS_BORDER, x, y,
+                                   menu->Width + 2*SYSMETRICS_CXBORDER,
+                                   menu->Height + 2*SYSMETRICS_CYBORDER,
+                                   menu->hWnd, 0, wndPtr->hInstance, (SEGPTR)hmenu );
+	if( !hWnd ) return FALSE;
+	menu->hWnd = hWnd;
+    }
+    else 
+    {
+	if( !skip_init )
+	  {
+            MENU_SwitchTPWndTo(GetCurrentTask());
+	    SendMessage( pTopPWnd->hwndSelf, WM_USER, (WPARAM)hmenu, 0L);
+	  }
+	menu->hWnd = pTopPWnd->hwndSelf;
+    }
+
+    uSubPWndLevel++;
+
+    SetWindowPos(menu->hWnd, 0, x, y, menu->Width + 2*SYSMETRICS_CXBORDER, 
+				      menu->Height + 2*SYSMETRICS_CYBORDER,
+		  		      SWP_NOACTIVATE | SWP_NOZORDER );
 
       /* Display the window */
 
@@ -1095,7 +1147,16 @@
     }
     submenu = (POPUPMENU *) USER_HEAP_LIN_ADDR( hsubmenu );
     MENU_HideSubPopups( hwndOwner, hsubmenu );
-    if (submenu->hWnd) ShowWindow( submenu->hWnd, SW_HIDE );
+    if (submenu->hWnd == pTopPWnd->hwndSelf ) 
+      {
+	ShowWindow( submenu->hWnd, SW_HIDE );
+	uSubPWndLevel = 0;
+      }
+    else
+      {
+	DestroyWindow( submenu->hWnd );
+	submenu->hWnd = 0;
+      }
     MENU_SelectItem( hwndOwner, hsubmenu, NO_SELECTED_ITEM );
 }
 
@@ -1596,7 +1657,11 @@
     USER_HEAP_FREE( hMsg );
     ReleaseCapture();
     MENU_HideSubPopups( hwnd, hmenu );
-    if (menu->wFlags & MF_POPUP) ShowWindow( menu->hWnd, SW_HIDE );
+    if (menu->wFlags & MF_POPUP) 
+       {
+         ShowWindow( menu->hWnd, SW_HIDE );
+	 uSubPWndLevel = 0;
+       }
     MENU_SelectItem( hwnd, hmenu, NO_SELECTED_ITEM );
     SendMessage( hwnd, WM_MENUSELECT, 0, MAKELONG( 0xffff, 0 ) );
     fEndMenuCalled = FALSE;
@@ -1743,6 +1808,25 @@
 	    return 0;
 	}
 
+    case WM_DESTROY:
+	    /* zero out global pointer in case system popup
+	     * was destroyed by AppExit 
+	     */
+
+	    if( hwnd == pTopPWnd->hwndSelf )
+		pTopPWnd = 0;
+	    else
+		uSubPWndLevel--;
+	    break;
+
+    case WM_USER:
+	if( wParam )
+#ifdef WINELIB32
+            SetWindowLong( hwnd, 0, (HMENU)wParam );
+#else
+            SetWindowWord( hwnd, 0, (HMENU)wParam );
+#endif
+        break;
     default:
 	return DefWindowProc(hwnd, message, wParam, lParam);
     }
@@ -2139,7 +2223,7 @@
     lppop = (LPPOPUPMENU) USER_HEAP_LIN_ADDR(hMenu);
     if (!lppop || (lppop->wMagic != MENU_MAGIC)) return FALSE;
     lppop->wMagic = 0;  /* Mark it as destroyed */
-    if ((lppop->wFlags & MF_POPUP) && lppop->hWnd)
+    if ((lppop->wFlags & MF_POPUP) && lppop->hWnd && lppop->hWnd != pTopPWnd->hwndSelf )
         DestroyWindow( lppop->hWnd );
 
     if (lppop->hItems)
diff --git a/debugger/dbg.y b/debugger/dbg.y
index e809a37..e6064ca 100644
--- a/debugger/dbg.y
+++ b/debugger/dbg.y
@@ -129,7 +129,7 @@
 
 info_command:
       tINFO tBREAK tEOL         { DEBUG_InfoBreakpoints(); }
-    | tINFO tCLASS expr tEOL    { CLASS_DumpClass( $3 ); }
+    | tINFO tCLASS expr tEOL    { CLASS_DumpClass( (CLASS *)$3 ); }
     | tINFO tMODULE expr tEOL   { MODULE_DumpModule( $3 ); }
     | tINFO tQUEUE expr tEOL    { QUEUE_DumpQueue( $3 ); }
     | tINFO tREGS tEOL          { DEBUG_InfoRegisters(); }
diff --git a/debugger/stack.c b/debugger/stack.c
index de54160..bbf9033 100644
--- a/debugger/stack.c
+++ b/debugger/stack.c
@@ -71,7 +71,7 @@
         DEBUG_PrintAddress( &addr, 32 );
         fprintf( stderr, "\n" );
         addr.off = EBP_reg(DEBUG_context);
-        for (;;)
+        while (addr.off)
         {
             FRAME32 *frame = (FRAME32 *)addr.off;
             if (!DBG_CHECK_READ_PTR( &addr, sizeof(FRAME32) )) return;
diff --git a/if1632/Makefile.in b/if1632/Makefile.in
index 288e84a..684948a 100644
--- a/if1632/Makefile.in
+++ b/if1632/Makefile.in
@@ -34,12 +34,13 @@
 	toolhelp.spec \
 	user.spec \
 	user32.spec \
+	ver.spec \
 	w32sys.spec \
 	win87em.spec \
-	winprocs.spec \
-	winprocs32.spec \
 	winsock.spec \
-	winspool.spec
+	winspool.spec \
+	wprocs.spec \
+	wprocs32.spec
 
 SPEC_FILES = $(DLLS:.spec=.S)
 
diff --git a/if1632/commdlg.spec b/if1632/commdlg.spec
index 0f5dc75..7f85c1d 100644
--- a/if1632/commdlg.spec
+++ b/if1632/commdlg.spec
@@ -1,6 +1,5 @@
 name	commdlg
 type	win16
-id	14
 
 1   pascal16 GetOpenFileName(ptr) GetOpenFileName
 2   pascal16 GetSaveFileName(ptr) GetSaveFileName
diff --git a/if1632/compobj.spec b/if1632/compobj.spec
index 398c68c..e325c24 100644
--- a/if1632/compobj.spec
+++ b/if1632/compobj.spec
@@ -1,6 +1,5 @@
 name	compobj
 type	win16
-id	22
 
 1 pascal CoBuildVersion() CoBuildVersion
 2 pascal CoInitialize(long) CoInitialize
diff --git a/if1632/ddeml.spec b/if1632/ddeml.spec
index 0a03761..12c1420 100644
--- a/if1632/ddeml.spec
+++ b/if1632/ddeml.spec
@@ -1,6 +1,5 @@
 name	ddeml
 type	win16
-id	25
 
 2 stub DdeInitialize #(ptr segptr long long) DdeInitialize
 3 stub DdeUnInitialize #(long) DdeUnInitialize
diff --git a/if1632/gdi.spec b/if1632/gdi.spec
index cbd75d0..0e23946 100644
--- a/if1632/gdi.spec
+++ b/if1632/gdi.spec
@@ -1,6 +1,6 @@
 name	gdi
 type	win16
-id	3
+heap	65488  # 65536 - 16 (instance data) - 32 (stock objects)
 
 1   pascal SetBkColor(word long) SetBkColor
 2   pascal16 SetBkMode(word word) SetBkMode
diff --git a/if1632/kernel.spec b/if1632/kernel.spec
index c2cabe6..64e9c54 100644
--- a/if1632/kernel.spec
+++ b/if1632/kernel.spec
@@ -1,6 +1,5 @@
 name	kernel
 type	win16
-id	1
 
 1   stub FatalExit
 2   stub ExitKernel
diff --git a/if1632/kernel32.spec b/if1632/kernel32.spec
index e58e0cf..77c095f 100644
--- a/if1632/kernel32.spec
+++ b/if1632/kernel32.spec
@@ -31,7 +31,7 @@
 0026 stub CommConfigDialogA
 0027 stub CommConfigDialogW
 0028 stub CompareFileTime
-0029 stub CompareStringA
+0029 stdcall CompareStringA(long long ptr long ptr long) CompareStringA
 0030 stub CompareStringW
 0031 stub ConnectNamedPipe
 0032 stub ConsoleMenuControl
@@ -231,7 +231,7 @@
 0226 stub GetLargestConsoleWindowSize
 0227    stdcall GetLastError() GetLastError
 0228    stdcall GetLocalTime(ptr) GetLocalTime
-0229 stub GetLocaleInfoA
+0229 stdcall GetLocaleInfoA(long long ptr long) GetLocaleInfoA
 0230 stub GetLocaleInfoW
 0231 stub GetLogicalDriveStringsA
 0232 stub GetLogicalDriveStringsW
@@ -257,10 +257,10 @@
 0252 stub GetPrivateProfileIntW
 0253 stub GetPrivateProfileSectionA
 0254 stub GetPrivateProfileSectionW
-0255 stub GetPrivateProfileStringA
+0255 stdcall GetPrivateProfileStringA(ptr ptr ptr ptr long ptr) GetPrivateProfileString
 0256 stub GetPrivateProfileStringW
 0257	stdcall GetProcAddress(long long)	WIN32_GetProcAddress
-0258 stub GetProcessAffinityMask
+0258 stdcall GetProcessAffinityMask(long ptr ptr)	GetProcessAffinityMask
 0259 stdcall GetProcessHeap() GetProcessHeap
 0260 stub GetProcessHeaps
 0261 stub GetProcessShutdownParameters
@@ -270,7 +270,7 @@
 0265 stub GetProfileIntW
 0266 stub GetProfileSectionA
 0267 stub GetProfileSectionW
-0268 stub GetProfileStringA
+0268 stdcall GetProfileStringA(ptr ptr ptr ptr long) GetProfileString
 0269 stub GetProfileStringW
 0270 stub GetQueuedCompletionStatus
 0271 stub GetShortPathNameA
@@ -282,7 +282,7 @@
 0277 stub GetStringTypeExA
 0278 stub GetStringTypeExW
 0279 stub GetStringTypeW
-0280 stub GetSystemDefaultLCID
+0280 stdcall GetSystemDefaultLCID() GetSystemDefaultLCID
 0281 stub GetSystemDefaultLangID
 0282 stub GetSystemDirectoryA
 0283 stub GetSystemDirectoryW
@@ -329,7 +329,7 @@
 0323 stub GlobalGetAtomNameA
 0324 stub GlobalGetAtomNameW
 0325 stub GlobalHandle
-0326 stub GlobalLock
+0326 stdcall GlobalLock(long)	GlobalLock32
 0327 stub GlobalMemoryStatus
 0328 stub GlobalReAlloc
 0329 stub GlobalSize
@@ -357,10 +357,10 @@
 0351 stub IsBadCodePtr
 0352 stub IsBadHugeReadPtr
 0353 stub IsBadHugeWritePtr
-0354 stub IsBadReadPtr
+0354 stdcall IsBadReadPtr(ptr long)	WIN32_IsBadReadPtr
 0355 stub IsBadStringPtrA
 0356 stub IsBadStringPtrW
-0357 stub IsBadWritePtr
+0357 stdcall IsBadWritePtr(ptr long)	WIN32_IsBadWritePtr
 0358 stub IsDBCSLeadByte
 0359 stub IsDBCSLeadByteEx
 0360 stub IsValidCodePage
@@ -380,7 +380,7 @@
 0374 stub LocalFlags
 0375 stub LocalFree
 0376 stub LocalHandle
-0377 stub LocalLock
+0377 stdcall LocalLock(long)	GlobalLock32
 0378 stub LocalReAlloc
 0379 stub LocalShrink
 0380 stub LocalSize
@@ -502,7 +502,7 @@
 0496 stub SetLastConsoleEventActive
 0497    stdcall SetLastError(long) SetLastError
 0498 stub SetLocalTime
-0499 stub SetLocaleInfoA
+0499 stdcall SetLocaleInfoA(long long ptr) SetLocaleInfoA
 0500 stub SetLocaleInfoW
 0501 stub SetMailslotInfo
 0502 stub SetNamedPipeHandleState
@@ -514,7 +514,7 @@
 0508 stub SetSystemTimeAdjustment
 0509 stub SetTapeParameters
 0510 stub SetTapePosition
-0511 stub SetThreadAffinityMask
+0511 stdcall SetThreadAffinityMask(long long)	SetThreadAffinityMask
 0512 stub SetThreadContext
 0513 stub SetThreadLocale
 0514 stub SetThreadPriority
diff --git a/if1632/keyboard.spec b/if1632/keyboard.spec
index 5820363..bf3ba43 100644
--- a/if1632/keyboard.spec
+++ b/if1632/keyboard.spec
@@ -1,6 +1,5 @@
 name	keyboard
 type	win16
-id	7
 
 #1	pascal	Inquire
 #2	pascal	Enable
diff --git a/if1632/lzexpand.spec b/if1632/lzexpand.spec
index 3e6b2c9..ca0e9d3 100644
--- a/if1632/lzexpand.spec
+++ b/if1632/lzexpand.spec
@@ -1,6 +1,5 @@
 name	lzexpand
 type	win16
-id	26
 
 1  pascal   LZCopy(word word) LZCopy
 2  pascal16 LZOpenFile(ptr ptr word) LZOpenFile
diff --git a/if1632/mmsystem.spec b/if1632/mmsystem.spec
index cb28204..d2ebd00 100644
--- a/if1632/mmsystem.spec
+++ b/if1632/mmsystem.spec
@@ -1,6 +1,5 @@
 name	mmsystem
 type	win16
-id	10
 
 #1      pascal  MMSYSTEM_WEP(word word word ptr) MMSYSTEM_WEP
 2      pascal  SNDPLAYSOUND(ptr word) sndPlaySound
diff --git a/if1632/mouse.spec b/if1632/mouse.spec
index fe8599f..fa5dac8 100644
--- a/if1632/mouse.spec
+++ b/if1632/mouse.spec
@@ -1,6 +1,5 @@
 name	mouse
 type	win16
-id	13
 
 1 stub INQUIRE
 2 stub ENABLE
diff --git a/if1632/ole2.spec b/if1632/ole2.spec
index f7c8ad2..b86a0f8 100644
--- a/if1632/ole2.spec
+++ b/if1632/ole2.spec
@@ -1,6 +1,5 @@
 name	OLE2
 type	win16
-id	15
 
 1 pascal OleBuildVersion() OleBuildVersion
 2 pascal OleInitialize(ptr) OleInitialize
diff --git a/if1632/ole2conv.spec b/if1632/ole2conv.spec
index 39808a8..1a33d71 100644
--- a/if1632/ole2conv.spec
+++ b/if1632/ole2conv.spec
@@ -1,6 +1,5 @@
 name	ole2conv
 type	win16
-id	16
 
 1 stub GETFILTERINFO
 2 stub IMPORTGR
diff --git a/if1632/ole2disp.spec b/if1632/ole2disp.spec
index 1364f5a..8b50520 100644
--- a/if1632/ole2disp.spec
+++ b/if1632/ole2disp.spec
@@ -1,6 +1,5 @@
 name	ole2disp
 type	win16
-id	17
 
 1 stub DLLGETCLASSOBJECT
 2 pascal SysAllocString(ptr)	SysAllocString
diff --git a/if1632/ole2nls.spec b/if1632/ole2nls.spec
index 57b136a..ae5892b 100644
--- a/if1632/ole2nls.spec
+++ b/if1632/ole2nls.spec
@@ -1,6 +1,5 @@
 name	ole2nls
 type	win16
-id	18
 
 1 pascal GetUserDefaultLCID()      GetUserDefaultLCID
 2 pascal GetSystemDefaultLCID()    GetSystemDefaultLCID
diff --git a/if1632/ole2prox.spec b/if1632/ole2prox.spec
index e2822cb..34201e0 100644
--- a/if1632/ole2prox.spec
+++ b/if1632/ole2prox.spec
@@ -1,6 +1,5 @@
 name	ole2prox
 type	win16
-id	19
 
 1 stub DLLGETCLASSOBJECT
 #2 WEP
diff --git a/if1632/olecli.spec b/if1632/olecli.spec
index 9376d69..291db7f 100644
--- a/if1632/olecli.spec
+++ b/if1632/olecli.spec
@@ -1,6 +1,5 @@
 name	olecli
 type	win16
-id	20
 
 #1 WEP
 2 stub OLEDELETE
diff --git a/if1632/olesvr.spec b/if1632/olesvr.spec
index a79115d..922da54 100644
--- a/if1632/olesvr.spec
+++ b/if1632/olesvr.spec
@@ -1,6 +1,5 @@
 name	olesvr
 type	win16
-id	21
 
 #1 WEP
 2  pascal OleRegisterServer(ptr ptr ptr word word) OleRegisterServer
diff --git a/if1632/relay.c b/if1632/relay.c
index 1197af7..41ddc24 100644
--- a/if1632/relay.c
+++ b/if1632/relay.c
@@ -5,7 +5,6 @@
 
 #include <stdio.h>
 
-#include "dlls.h"
 #include "global.h"
 #include "module.h"
 #include "registers.h"
@@ -19,55 +18,6 @@
 dprintf_relay
 #endif
 
-#define DLL_ENTRY(name,flags) \
-  { #name, name##_Code_Start, name##_Data_Start, \
-    name##_Module_Start, name##_Module_End, (flags) }
-
-BUILTIN_DLL dll_builtin_table[] =
-{
-    /* Win16 DLLs */
-    DLL_ENTRY( KERNEL,     DLL_FLAG_ALWAYS_USED),
-    DLL_ENTRY( USER,       DLL_FLAG_ALWAYS_USED),
-    DLL_ENTRY( GDI,        DLL_FLAG_ALWAYS_USED),
-    DLL_ENTRY( WIN87EM,    DLL_FLAG_NOT_USED),
-    DLL_ENTRY( SHELL,      0),
-    DLL_ENTRY( SOUND,      0),
-    DLL_ENTRY( KEYBOARD,   0),
-    DLL_ENTRY( WINSOCK,    0),
-    DLL_ENTRY( STRESS,     0),
-    DLL_ENTRY( MMSYSTEM,   0),
-    DLL_ENTRY( SYSTEM,     0),
-    DLL_ENTRY( TOOLHELP,   0),
-    DLL_ENTRY( MOUSE,      0),
-    DLL_ENTRY( COMMDLG,    DLL_FLAG_NOT_USED),
-    DLL_ENTRY( OLE2,       DLL_FLAG_NOT_USED),
-    DLL_ENTRY( OLE2CONV,   DLL_FLAG_NOT_USED),
-    DLL_ENTRY( OLE2DISP,   DLL_FLAG_NOT_USED),
-    DLL_ENTRY( OLE2NLS,    DLL_FLAG_NOT_USED),
-    DLL_ENTRY( OLE2PROX,   DLL_FLAG_NOT_USED),
-    DLL_ENTRY( OLECLI,     DLL_FLAG_NOT_USED),
-    DLL_ENTRY( OLESVR,     DLL_FLAG_NOT_USED),
-    DLL_ENTRY( COMPOBJ,    DLL_FLAG_NOT_USED),
-    DLL_ENTRY( STORAGE,    DLL_FLAG_NOT_USED),
-    DLL_ENTRY( WINPROCS,   DLL_FLAG_ALWAYS_USED),
-    DLL_ENTRY( DDEML,      DLL_FLAG_NOT_USED),
-    DLL_ENTRY( LZEXPAND,   0),
-    DLL_ENTRY( W32SYS,     0),
-    /* Win32 DLLs */
-    DLL_ENTRY( ADVAPI32,   0),
-    DLL_ENTRY( COMCTL32,   0),
-    DLL_ENTRY( COMDLG32,   0),
-    DLL_ENTRY( OLE32,      0),
-    DLL_ENTRY( GDI32,      0),
-    DLL_ENTRY( KERNEL32,   DLL_FLAG_ALWAYS_USED),
-    DLL_ENTRY( SHELL32,    0),
-    DLL_ENTRY( USER32,     0),
-    DLL_ENTRY( WINPROCS32, DLL_FLAG_ALWAYS_USED),
-    DLL_ENTRY( WINSPOOL,   0),
-    /* Last entry */
-    { NULL, }
-};
-
   /* Saved 16-bit stack for current process (Win16 only) */
 WORD IF1632_Saved16_ss = 0;
 WORD IF1632_Saved16_sp = 0;
@@ -116,17 +66,20 @@
                             void *entry_point, int args32 )
 {
     STACK16FRAME *frame;
-    struct dll_table_s *table;
+    NE_MODULE *pModule;
+    WORD ordinal;
     char *args16, *name;
     int i;
 
     if (!debugging_relay) return;
 
     frame = CURRENT_STACK16;
-    table = &dll_builtin_table[frame->dll_id-1];
-    name  = MODULE_GetEntryPointName( table->hModule, frame->ordinal_number );
-    printf( "Call %s.%d: %.*s(",
-            table->name, frame->ordinal_number, *name, name + 1 );
+    pModule = BUILTIN_GetEntryPoint( frame->entry_cs, frame->entry_ip,
+                                     &ordinal, &name );
+    printf( "Call %.*s.%d: %.*s(",
+            *((BYTE *)pModule + pModule->name_table),
+            (char *)pModule + pModule->name_table + 1,
+            ordinal, *name, name + 1 );
 
     args16 = (char *)frame->args;
     for (i = 0; i < strlen(args); i++)
@@ -184,7 +137,8 @@
 void RELAY_DebugCallFrom16Ret( int func_type, int ret_val, int args32 )
 {
     STACK16FRAME *frame;
-    struct dll_table_s *table;
+    NE_MODULE *pModule;
+    WORD ordinal;
     char *name;
 
     if (*(DWORD *)PTR_SEG_TO_LIN(IF1632_Stack32_base) != 0xDEADBEEF)
@@ -194,11 +148,14 @@
     }
     if (!debugging_relay) return;
 
-    frame = CURRENT_STACK16;
-    table = &dll_builtin_table[frame->dll_id-1];
-    name  = MODULE_GetEntryPointName( table->hModule, frame->ordinal_number );
-    printf( "Ret  %s.%d: %.*s() ",
-            table->name, frame->ordinal_number, *name, name + 1 );
+    frame   = CURRENT_STACK16;
+    pModule = BUILTIN_GetEntryPoint( frame->entry_cs, frame->entry_ip,
+                                     &ordinal, &name );
+    printf( "Ret  %.*s.%d: %.*s() ",
+            *((BYTE *)pModule + pModule->name_table),
+            (char *)pModule + pModule->name_table + 1,
+            ordinal, *name, name + 1 );
+
     switch(func_type)
     {
     case 0: /* long */
@@ -232,12 +189,16 @@
  */
 void RELAY_Unimplemented16(void)
 {
+    WORD ordinal;
+    char *name;
     STACK16FRAME *frame = CURRENT_STACK16;
-    struct dll_table_s *table = &dll_builtin_table[frame->dll_id-1];
-    char *name = MODULE_GetEntryPointName( table->hModule, frame->ordinal_number );
-
-    fprintf( stderr, "No handler for routine %s.%d (%.*s)\n",
-             table->name, frame->ordinal_number, *name, name + 1 );
+    NE_MODULE *pModule  = BUILTIN_GetEntryPoint( frame->entry_cs,
+                                                 frame->entry_ip,
+                                                 &ordinal, &name );
+    fprintf( stderr, "No handler for routine %.*s.%d (%.*s)\n",
+             *((BYTE *)pModule + pModule->name_table),
+             (char *)pModule + pModule->name_table + 1,
+             ordinal, *name, name + 1 );
     exit(1);
 }
 
diff --git a/if1632/relay32.c b/if1632/relay32.c
index 14d98a4..c67ac68 100644
--- a/if1632/relay32.c
+++ b/if1632/relay32.c
@@ -12,70 +12,16 @@
 #include <errno.h>
 #include "windows.h"
 #include "callback.h"
-#include "dlls.h"
 #include "module.h"
 #include "neexe.h"
 #include "peexe.h"
 #include "relay32.h"
 #include "struct32.h"
 #include "stackframe.h"
-#include "xmalloc.h"
 #include "ldt.h"
 #include "stddebug.h"
 #include "debug.h"
 
-typedef struct
-{
-    char *name;
-    void *definition;
-} WIN32_function;
-
-typedef struct
-{
-    int base;
-    int size;
-    WIN32_function functions[1];
-} WIN32_DLL_INFO;
-
-
-void *RELAY32_GetEntryPoint(BUILTIN_DLL *dll, char *item, int hint)
-{
-    const WIN32_DLL_INFO *info = (const WIN32_DLL_INFO *)dll->data_start;
-    int i;
-
-    dprintf_module(stddeb, "Looking for %s in %s, hint %x\n",
-                   item ? item: "(no name)", dll->name, hint);
-    if(!dll) return 0;
-
-    /* import by ordinal */
-    if(!item)
-    {
-        if(hint && hint < info->size)
-            return info->functions[hint - info->base].definition;
-        return 0;
-    }
-
-    /* hint is correct */
-    if (hint && hint < info->size && 
-        info->functions[hint].name &&
-        strcmp(item,info->functions[hint].name)==0)
-        return info->functions[hint].definition;
-
-    /* hint is incorrect, search for name */
-    for(i=0;i < info->size;i++)
-        if (info->functions[i].name && !strcmp(item,info->functions[i].name))
-            return info->functions[i].definition;
-
-    /* function at hint has no name (unimplemented) */
-    if(hint && hint < info->size && !info->functions[hint].name)
-    {
-/*        info->functions[hint].name=xstrdup(item); */
-        dprintf_module(stddeb,"Returning unimplemented function %s.%d (%s?)\n",
-                       dll->name,hint,item);
-        return info->functions[hint].definition;
-    }
-    return 0;
-}
 
 LONG RELAY32_CallWindowProcConvStruct( WNDPROC func, int hwnd, int message,
 	int wParam, LPARAM lParam16)
diff --git a/if1632/shell.spec b/if1632/shell.spec
index f7b2bea..7623fac 100644
--- a/if1632/shell.spec
+++ b/if1632/shell.spec
@@ -1,6 +1,5 @@
 name	shell
 type	win16
-id	5
 
   1 pascal   RegOpenKey(long ptr ptr) RegOpenKey
   2 pascal   RegCreateKey(long ptr ptr) RegCreateKey
@@ -20,12 +19,30 @@
  34 pascal16 ExtractIcon(word ptr s_word) ExtractIcon
  36 pascal16 ExtractAssociatedIcon(word ptr ptr) ExtractAssociatedIcon
  37 pascal   DoEnvironmentSubst(ptr word) DoEnvironmentSubst
- 38 stub FindEnvironmentString
- 39 stub InternalExtractIcon
+ 38 pascal   FindEnvironmentString(ptr) FindEnvironmentString
+ 39 pascal16 InternalExtractIcon(word ptr s_word word) InternalExtractIcon
+ 40 stub ExtractIconEx
+ 98 stub SHL3216_THUNKDATA16
+ 99 stub SHL1632_THUNKDATA16
+
+#100   4  0550  HERETHARBETYGARS exported, shared data
+#101   8  010e  FINDEXEDLGPROC exported, shared data
+#101 DLLENTRYPOINT #win95 SHELL.DLL
+
 102 pascal16 RegisterShellHook(ptr) RegisterShellHook
 103 pascal16 ShellHookProc() ShellHookProc
 
-#  8   7  0000  WEP exported, shared data
-#100   4  0550  HERETHARBETYGARS exported, shared data
-#101   8  010e  FINDEXEDLGPROC exported, shared data
-# 32   9  0829  WCI exported, shared data
+#  157 RESTARTDIALOG
+#  166 PICKICONDLG
+
+262 pascal16 DriveType(long) GetDriveType
+
+#  263 SH16TO32DRIVEIOCTL
+#  264 SH16TO32INT2526
+#  300 SHGETFILEINFO
+#  400 SHFORMATDRIVE
+#  401 SHCHECKDRIVE
+#  402 _RUNDLLCHECKDRIVE
+
+# 8 WEP 
+#32 WCI
diff --git a/if1632/shell32.spec b/if1632/shell32.spec
index 1e0a54b..e0d598f 100644
--- a/if1632/shell32.spec
+++ b/if1632/shell32.spec
@@ -86,7 +86,7 @@
 0081 stub SheShortenPathW
 0082 stub ShellAboutA
 0083 stub ShellAboutW
-0084 stub ShellExecuteA
+0084 stdcall ShellExecuteA(word ptr ptr ptr ptr s_word) ShellExecute
 0085 stub ShellExecuteEx
 0086 stub ShellExecuteExA
 0087 stub ShellExecuteExW
diff --git a/if1632/sound.spec b/if1632/sound.spec
index 23b656f..a0ab624 100644
--- a/if1632/sound.spec
+++ b/if1632/sound.spec
@@ -1,6 +1,5 @@
 name	sound
 type	win16
-id	6
 
 1  pascal16 OpenSound() OpenSound
 2  pascal16 CloseSound() CloseSound
diff --git a/if1632/storage.spec b/if1632/storage.spec
index 2c03b1e..f09c13b 100644
--- a/if1632/storage.spec
+++ b/if1632/storage.spec
@@ -1,6 +1,5 @@
 name	storage
 type	win16
-id	23
  
 1 stub StgCreateDocFile
 2 stub StgCreateDocFileOnILockBytes
diff --git a/if1632/stress.spec b/if1632/stress.spec
index 69c8309..dec65fc 100644
--- a/if1632/stress.spec
+++ b/if1632/stress.spec
@@ -2,7 +2,6 @@
 #
 name	stress
 type	win16
-id	9
 
 2   pascal allocmem(long)		AllocMem
 3   pascal freeallmem()			FreeAllMem
diff --git a/if1632/system.spec b/if1632/system.spec
index 975364c..0b727a1 100644
--- a/if1632/system.spec
+++ b/if1632/system.spec
@@ -1,6 +1,5 @@
 name	system
 type	win16
-id	11
 
 1 stub InquireSystem
 2 stub CreateSystemTimer
diff --git a/if1632/toolhelp.spec b/if1632/toolhelp.spec
index 9085053..c3837e9 100644
--- a/if1632/toolhelp.spec
+++ b/if1632/toolhelp.spec
@@ -1,6 +1,5 @@
 name	toolhelp
 type	win16
-id	12
 
 50 pascal16 GlobalHandleToSel(word) GlobalHandleToSel
 51 pascal16 GlobalFirst(ptr word) GlobalFirst
diff --git a/if1632/user.spec b/if1632/user.spec
index 721fde0..f5e7d91 100644
--- a/if1632/user.spec
+++ b/if1632/user.spec
@@ -1,6 +1,6 @@
 name	user
 type	win16
-id	2
+heap	65520
 
 1   pascal16 MessageBox(word ptr ptr word) MessageBox
 2   stub OldExitWindows
@@ -300,7 +300,7 @@
 294 stub LockWindowUpdate
 299 register Mouse_Event() Mouse_Event
 300 stub UnloadInstalledDrivers
-#301 BOZOSLIVEHERE :-))
+#301 BOZOSLIVEHERE :-))	<- this is actually EditWndProc
 #306 BEAR306
 308 pascal   DefDlgProc(word word word long) DefDlgProc
 309 pascal16 GetClipCursor(ptr) GetClipCursor
@@ -481,10 +481,10 @@
 652 stub GetKeyboardLayoutList
 654 stub UnloadKeyboardLayout
 655 stub PostPostedMessages
-656 stub DrawFrameControl
+656 pascal16 DrawFrameControl(word ptr word word) DrawFrameControl
 657 stub DrawCaptionTemp
 658 stub DispatchInput
-659 stub DrawEdge
+659 pascal16 DrawEdge(word ptr word word) DrawEdge
 660 stub DrawCaption
 661 stub SetSysColorsTemp
 662 stub DrawMenubarTemp
diff --git a/if1632/user32.spec b/if1632/user32.spec
index 13e7ab7..6f68215 100644
--- a/if1632/user32.spec
+++ b/if1632/user32.spec
@@ -240,7 +240,7 @@
 0228 stub GetCursorPos
 0229 stdcall GetDC(long) GetDC
 0230 stub GetDCEx
-0231 stub GetDesktopWindow
+0231 stdcall GetDesktopWindow() GetDesktopWindow
 0232 stub GetDialogBaseUnits
 0233 stub GetDlgCtrlID
 0234 stdcall GetDlgItem(long long) GetDlgItem
@@ -298,8 +298,8 @@
 0286 stub GetShellWindow
 0287 stub GetSubMenu
 0288 	stdcall GetSysColor(long) GetSysColor
-0289 stub GetSysColorBrush
-0290 stub GetSystemMenu
+0289 stdcall GetSysColorBrush(long) GetSysColorBrush
+0290 stdcall GetSystemMenu(long long) GetSystemMenu
 0291 stdcall GetSystemMetrics(long) GetSystemMetrics
 0292 stub GetTabbedTextExtentA
 0293 stub GetTabbedTextExtentW
@@ -310,14 +310,14 @@
 0298 stub GetUserObjectInformationA
 0299 stub GetUserObjectInformationW
 0300 stub GetUserObjectSecurity
-0301 stub GetWindow
+0301 stdcall GetWindow(long long) GetWindow
 0302 stub GetWindowContextHelpId
 0303 stdcall GetWindowDC(long) GetWindowDC
 0304 stub GetWindowLongA
 0305 stub GetWindowLongW
 0306 stub GetWindowPlacement
 0307 stub GetWindowRect
-0308 stub GetWindowTextA
+0308 stdcall GetWindowTextA(long segptr long) WIN16_GetWindowText
 0309 stub GetWindowTextLengthA
 0310 stub GetWindowTextLengthW
 0311 stub GetWindowTextW
@@ -398,7 +398,7 @@
 0386 stub MenuItemFromPoint
 0387 stub MenuWindowProcA
 0388 stub MenuWindowProcW
-0389 stub MessageBeep
+0389 stdcall MessageBeep(long) MessageBeep
 0390	stdcall MessageBoxA(long ptr ptr long)	MessageBox
 0391 stub MessageBoxExA
 0392 stub MessageBoxExW
diff --git a/if1632/ver.spec b/if1632/ver.spec
new file mode 100644
index 0000000..60cadc8
--- /dev/null
+++ b/if1632/ver.spec
@@ -0,0 +1,16 @@
+name	ver
+type	win16
+
+#1 DLLENTRYPOINT
+
+2 pascal GetFileResourceSize(ptr segptr segptr ptr) GetFileResourceSize
+3 pascal GetFileResource(ptr segptr segptr long long ptr) GetFileResource
+6 pascal GetFileVersionInfoSize(ptr ptr) GetFileVersionInfoSize
+7 pascal GetFileVersionInfo(ptr long long ptr) GetFileVersionInfo
+8 pascal VerFindFile(word ptr ptr ptr ptr ptr ptr ptr) VerFindFile
+9 pascal VerInstallFile(word ptr ptr ptr ptr ptr ptr ptr) VerInstallFile
+10 pascal VerLanguageName(word ptr word) VerLanguageName
+11 pascal VerQueryValue(segptr ptr ptr ptr) VerQueryValue
+20 stub GETFILEVERSIONINFORAW
+#21 VERFTHK_THUNKDATA16
+#22 VERTHKSL_THUNKDATA16
diff --git a/if1632/w32sys.spec b/if1632/w32sys.spec
index 04dd968..ff5a3dd 100644
--- a/if1632/w32sys.spec
+++ b/if1632/w32sys.spec
@@ -1,6 +1,5 @@
 name	w32sys
 type	win16
-id	27
 
 #1 WEP
 2 stub ISPEFORMAT
diff --git a/if1632/win87em.spec b/if1632/win87em.spec
index 7cee198..da00ef7 100644
--- a/if1632/win87em.spec
+++ b/if1632/win87em.spec
@@ -1,6 +1,5 @@
 name	win87em
 type	win16
-id	4
 
 1 register _fpMath() WIN87_fpmath
 3 pascal16 __WinEm87Info(ptr word) WIN87_WinEm87Info
diff --git a/if1632/winsock.spec b/if1632/winsock.spec
index 52975071..ee58e55 100644
--- a/if1632/winsock.spec
+++ b/if1632/winsock.spec
@@ -5,7 +5,6 @@
 #  
 name	winsock
 type	win16
-id	8
 
 1   pascal16 accept(word ptr ptr) WINSOCK_accept
 2   pascal16 bind(word ptr word) WINSOCK_bind
diff --git a/if1632/winprocs.spec b/if1632/wprocs.spec
similarity index 99%
rename from if1632/winprocs.spec
rename to if1632/wprocs.spec
index 056c9f6..fb7c614 100644
--- a/if1632/winprocs.spec
+++ b/if1632/wprocs.spec
@@ -1,6 +1,5 @@
-name	winprocs
+name	wprocs
 type	win16
-id	24
 
 1  pascal ButtonWndProc(word word word long) ButtonWndProc
 2  pascal StaticWndProc(word word word long) StaticWndProc
diff --git a/if1632/winprocs32.spec b/if1632/wprocs32.spec
similarity index 98%
rename from if1632/winprocs32.spec
rename to if1632/wprocs32.spec
index d40dafa..287a0a3 100644
--- a/if1632/winprocs32.spec
+++ b/if1632/wprocs32.spec
@@ -1,4 +1,4 @@
-name	winprocs32
+name	wprocs32
 type	win32
 
 1  stdcall ButtonWndProc(long long long long) ButtonWndProc32
diff --git a/include/bitmaps/obm_trtype b/include/bitmaps/obm_trtype
new file mode 100644
index 0000000..c74a002
--- /dev/null
+++ b/include/bitmaps/obm_trtype
@@ -0,0 +1,20 @@
+/* XPM */
+static char * obm_trtype[] = {
+"14 14 3 1",
+" 	s white c white",
+".	s black c black",
+"o	s dkgray c #808080",
+"              ",
+" oooooooo     ",
+" oo oo oo     ",
+" o  oo  o     ",
+" o  o........ ",
+"    o.. .. .. ",
+"    o.  ..  . ",
+"    o.  ..  . ",
+"    oo  ..    ",
+" ooooooo..    ",
+"        ..    ",
+"        ..    ",
+"      ......  ",
+"              "};
diff --git a/include/class.h b/include/class.h
index 073745f..042c746 100644
--- a/include/class.h
+++ b/include/class.h
@@ -11,30 +11,21 @@
 
 #define CLASS_MAGIC   0x4b4e      /* 'NK' */
 
-#ifndef WINELIB
-#pragma pack(1)
-#endif
-
-  /* !! Don't change this structure (see GetClassLong()) */
 typedef struct tagCLASS
 {
-    HCLASS       hNext;         /* Next class */
-    WORD         wMagic;        /* Magic number (must be CLASS_MAGIC) */
-    ATOM         atomName;      /* Name of the class */
-    HANDLE       hdce;          /* Class DCE (if CS_CLASSDC) */
-    WORD         cWindows;      /* Count of existing windows of this class */
-    WNDCLASS     wc WINE_PACKED;  /* Class information */
-    WORD         wExtra[1];     /* Class extra bytes */
+    struct tagCLASS *next;      /* Next class */
+    HCLASS           self;      /* Handle to this class */
+    WORD             wMagic;    /* Magic number (must be CLASS_MAGIC) */
+    ATOM             atomName;  /* Name of the class */
+    HANDLE           hdce;      /* Class DCE (if CS_CLASSDC) */
+    WORD             cWindows;  /* Count of existing windows of this class */
+    WNDCLASS         wc;        /* Class information */
+    WORD             wExtra[1]; /* Class extra bytes */
 } CLASS;
 
-#ifndef WINELIB
-#pragma pack(4)
-#endif
-
-extern void CLASS_DumpClass( HCLASS hClass );
+extern void CLASS_DumpClass( CLASS *class );
 extern void CLASS_WalkClasses(void);
-extern HCLASS CLASS_FindClassByName( SEGPTR name, HINSTANCE hinstance,
-                                     CLASS **ptr );
-extern CLASS * CLASS_FindClassPtr( HCLASS hclass );
+extern void CLASS_FreeModuleClasses( HMODULE hModule );
+extern CLASS * CLASS_FindClassByName( SEGPTR name, HINSTANCE hinstance );
 
 #endif  /* CLASS_H */
diff --git a/include/dlls.h b/include/dlls.h
deleted file mode 100644
index 70d34cc..0000000
--- a/include/dlls.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright  Robert J. Amstadt, 1993
- */
-
-#ifndef __WINE_DLLS_H
-#define __WINE_DLLS_H
-
-#include "wintypes.h"
-
-
-typedef struct dll_table_s
-{
-    char       *name;          /* DLL name */
-    const BYTE *code_start;    /* 32-bit address of DLL code */
-    const BYTE *data_start;    /* 32-bit address of DLL data */
-    BYTE       *module_start;  /* 32-bit address of the module data */
-    BYTE       *module_end;
-    int         flags;         /* flags (see below) */
-    HMODULE     hModule;       /* module created for this DLL */
-} BUILTIN_DLL;
-
-/* DLL flags */
-#define DLL_FLAG_NOT_USED    0x01  /* Use original Windows DLL if possible */
-#define DLL_FLAG_ALWAYS_USED 0x02  /* Always use built-in DLL */
-#define DLL_FLAG_WIN32       0x04  /* DLL is a Win32 DLL */
-
-#define DECLARE_DLL(name) \
-extern const BYTE name##_Code_Start[]; \
-extern const BYTE name##_Data_Start[]; \
-extern BYTE name##_Module_Start[]; \
-extern BYTE name##_Module_End[];
-
-/* 16-bit DLLs */
-DECLARE_DLL(KERNEL)
-DECLARE_DLL(USER)
-DECLARE_DLL(GDI)
-DECLARE_DLL(WIN87EM)
-DECLARE_DLL(MMSYSTEM)
-DECLARE_DLL(SHELL)
-DECLARE_DLL(SOUND)
-DECLARE_DLL(KEYBOARD)
-DECLARE_DLL(WINSOCK)
-DECLARE_DLL(STRESS)
-DECLARE_DLL(SYSTEM)
-DECLARE_DLL(TOOLHELP)
-DECLARE_DLL(MOUSE)
-DECLARE_DLL(COMMDLG)
-DECLARE_DLL(OLE2)
-DECLARE_DLL(OLE2CONV)
-DECLARE_DLL(OLE2DISP)
-DECLARE_DLL(OLE2NLS)
-DECLARE_DLL(OLE2PROX)
-DECLARE_DLL(OLECLI)
-DECLARE_DLL(OLESVR)
-DECLARE_DLL(COMPOBJ)
-DECLARE_DLL(STORAGE)
-DECLARE_DLL(WINPROCS)
-DECLARE_DLL(DDEML)
-DECLARE_DLL(LZEXPAND)
-DECLARE_DLL(W32SYS)
-
-/* 32-bit DLLs */
-
-DECLARE_DLL(ADVAPI32)
-DECLARE_DLL(COMCTL32)
-DECLARE_DLL(COMDLG32)
-DECLARE_DLL(OLE32)
-DECLARE_DLL(GDI32)
-DECLARE_DLL(KERNEL32)
-DECLARE_DLL(SHELL32)
-DECLARE_DLL(USER32)
-DECLARE_DLL(WINPROCS32)
-DECLARE_DLL(WINSPOOL)
-
-extern BUILTIN_DLL dll_builtin_table[];
-
-#endif /* __WINE_DLLS_H */
diff --git a/include/gdi.h b/include/gdi.h
index 16a631c..39a65f4 100644
--- a/include/gdi.h
+++ b/include/gdi.h
@@ -258,7 +258,6 @@
 
 #else
 
-extern LPSTR GDI_Heap;
 extern WORD GDI_HeapSel;
 
 #define GDI_HEAP_ALLOC(size) \
diff --git a/include/heap.h b/include/heap.h
new file mode 100644
index 0000000..e541815
--- /dev/null
+++ b/include/heap.h
@@ -0,0 +1,15 @@
+/*
+ * Win32 heap definitions
+ *
+ * Copyright 1996 Alexandre Julliard
+ */
+
+#ifndef __WINE_HEAP_H
+#define __WINE_HEAP_H
+
+#include "winbase.h"
+#include "winnt.h"
+
+extern HANDLE32 SystemHeap;
+
+#endif  /* __WINE_HEAP_H */
diff --git a/include/hook.h b/include/hook.h
index 610b816..4d82514 100644
--- a/include/hook.h
+++ b/include/hook.h
@@ -4,8 +4,8 @@
  * Copyright 1994 Alexandre Julliard
  */
 
-#ifndef HOOK_H
-#define HOOK_H
+#ifndef __WINE_HOOK_H
+#define __WINE_HOOK_H
 
 #include "windows.h"
 #include "ldt.h"
@@ -34,5 +34,7 @@
 
 extern DWORD HOOK_CallHooks( short id, short code,
                              WPARAM wParam, LPARAM lParam );
+extern void HOOK_FreeModuleHooks( HMODULE hModule );
+extern void HOOK_FreeQueueHooks( HQUEUE hQueue );
 
-#endif  /* HOOK_H */
+#endif  /* __WINE_HOOK_H */
diff --git a/include/kernel32.h b/include/kernel32.h
index 2a078d3..9b5b014 100644
--- a/include/kernel32.h
+++ b/include/kernel32.h
@@ -119,14 +119,4 @@
 #define FILE_ATTRIBUTE_ATOMIC_WRITE     0x0200
 #define FILE_ATTRIBUTE_XACTION_WRITE    0x0400
 
-/* Could this type be considered opaque? */
-typedef struct {
-	LPVOID	DebugInfo;
-	LONG LockCount;
-	LONG RecursionCount;
-	HANDLE OwningThread;
-	HANDLE LockSemaphore;
-	DWORD Reserved;
-}CRITICAL_SECTION;
-
 #endif  /* __WINE_KERNEL32_H */
diff --git a/include/mdi.h b/include/mdi.h
index 99d7974..adde0b0 100644
--- a/include/mdi.h
+++ b/include/mdi.h
@@ -35,14 +35,14 @@
     HWND   flagChildMaximized;
     HWND   hwndActiveChild;
     HMENU  hWindowMenu;
-    WORD   idFirstChild;       /* order is 3.1-like up to this point */
+    WORD   idFirstChild;
     HANDLE hFrameTitle;
     WORD   sbNeedUpdate;
     WORD   sbRecalc;
     HBITMAP obmClose;
     HBITMAP obmRestore;
-    HWND   hwndHitTest;
     HWND   self;
 } MDICLIENTINFO;
 
 #endif /* MDI_H */
+
diff --git a/include/module.h b/include/module.h
index 01c7840..e6ca763 100644
--- a/include/module.h
+++ b/include/module.h
@@ -94,6 +94,10 @@
     SEGPTR reserved;
 } LOADPARAMS;
 
+/* Resource types */
+typedef struct resource_typeinfo_s NE_TYPEINFO;
+typedef struct resource_nameinfo_s NE_NAMEINFO;
+
 #define NE_SEG_TABLE(pModule) \
     ((SEGTABLEENTRY *)((char *)(pModule) + (pModule)->seg_table))
 
@@ -111,20 +115,30 @@
 #pragma pack(4)
 #endif
 
-extern BOOL MODULE_Init(void);
+/* module.c */
 extern NE_MODULE *MODULE_GetPtr( HMODULE hModule );
 extern void MODULE_DumpModule( HMODULE hmodule );
 extern void MODULE_WalkModules(void);
 extern int MODULE_OpenFile( HMODULE hModule );
 extern LPSTR MODULE_GetModuleName( HMODULE hModule );
-extern void MODULE_RegisterModule( HMODULE hModule );
+extern void MODULE_RegisterModule( NE_MODULE *pModule );
+extern HINSTANCE MODULE_GetInstance( HMODULE hModule );
 extern WORD MODULE_GetOrdinal( HMODULE hModule, const char *name );
 extern SEGPTR MODULE_GetEntryPoint( HMODULE hModule, WORD ordinal );
 extern BOOL MODULE_SetEntryPoint( HMODULE hModule, WORD ordinal, WORD offset );
-extern LPSTR MODULE_GetEntryPointName( HMODULE hModule, WORD ordinal );
 extern FARPROC MODULE_GetWndProcEntry16( const char *name );
 extern FARPROC MODULE_GetWndProcEntry32( const char *name );
 
+/* builtin.c */
+extern BOOL BUILTIN_Init(void);
+extern HMODULE BUILTIN_LoadModule( LPCSTR name, BOOL force );
+extern NE_MODULE *BUILTIN_GetEntryPoint( WORD cs, WORD ip,
+                                         WORD *pOrd, char **ppName );
+extern DWORD BUILTIN_GetProcAddress32( NE_MODULE *pModule, char *function );
+extern BOOL BUILTIN_ParseDLLOptions( const char *str );
+extern void BUILTIN_PrintDLLs(void);
+
+/* ne_image.c */
 extern BOOL NE_LoadSegment( HMODULE hModule, WORD segnum );
 extern void NE_FixupPrologs( NE_MODULE *pModule );
 extern void NE_InitializeDLLs( HMODULE hModule );
diff --git a/include/options.h b/include/options.h
index 9f6a1db..1bbbdd4 100644
--- a/include/options.h
+++ b/include/options.h
@@ -19,7 +19,8 @@
     LANG_Da,  /* Danish */
     LANG_Cz,  /* Czech */
     LANG_Eo,  /* Esperanto */
-    LANG_It   /* Italian */
+    LANG_It,  /* Italian */
+    LANG_Ko   /* Korean */
 } WINE_LANGUAGE;
 
 extern const char *langNames[];
diff --git a/include/pe_image.h b/include/pe_image.h
index f527481..b9c74d8 100644
--- a/include/pe_image.h
+++ b/include/pe_image.h
@@ -3,7 +3,6 @@
 
 #include <sys/types.h>
 #include "windows.h"
-#include "dlls.h"
 
 struct pe_data {
 	struct pe_header_s *pe_header;
diff --git a/include/relay32.h b/include/relay32.h
index 06b8741..1eb2692 100644
--- a/include/relay32.h
+++ b/include/relay32.h
@@ -7,11 +7,8 @@
 #ifndef __WINE_RELAY32_H
 #define __WINE_RELAY32_H
 
-#include "dlls.h"
 #include "struct32.h"
 
-void *RELAY32_GetEntryPoint(BUILTIN_DLL *dll, char *item, int hint);
-
 typedef struct tagWNDCLASSA{
 	UINT	style;
 	WNDPROC	lpfnWndProc;
diff --git a/include/stackframe.h b/include/stackframe.h
index 0b4451d..d0c8400 100644
--- a/include/stackframe.h
+++ b/include/stackframe.h
@@ -19,11 +19,11 @@
 {
     WORD    saved_ss;                /* saved previous 16-bit stack */
     WORD    saved_sp;
-    WORD    es;
-    WORD    ds;                      /* 16-bit ds */
-    DWORD   entry_point WINE_PACKED; /* entry point to call */
-    WORD    ordinal_number;          /* ordinal number of entry point */
-    WORD    dll_id;                  /* DLL id of entry point */
+    WORD    entry_ip;                /* ip of entry point */
+    WORD    ds;                      /* ds */
+    WORD    entry_cs;                /* cs of entry point */
+    WORD    es;                      /* es */
+    DWORD   entry_point WINE_PACKED; /* 32-bit entry point to call */
     WORD    bp;                      /* 16-bit bp */
     WORD    ip;                      /* return address */
     WORD    cs;
diff --git a/include/user.h b/include/user.h
index 5e18d8f..c17364e 100644
--- a/include/user.h
+++ b/include/user.h
@@ -10,9 +10,6 @@
 #include "ldt.h"
 #include "local.h"
 
-extern BOOL USER_HeapInit(void);
-/* USER local heap */
-
 #ifdef WINELIB
 
 #define USER_HEAP_ALLOC(size) LocalAlloc (LMEM_FIXED, size)
@@ -23,7 +20,6 @@
 
 #else  /* WINELIB */
 
-extern LPSTR USER_Heap;
 extern WORD USER_HeapSel;
 
 #define USER_HEAP_ALLOC(size) \
diff --git a/include/ver.h b/include/ver.h
new file mode 100644
index 0000000..e6bcd8e
--- /dev/null
+++ b/include/ver.h
@@ -0,0 +1,168 @@
+/* Definitions for the VERsion infolibrary (VER.DLL)
+ * 
+ * Copyright 1996 Marcus Meissner
+ */
+#ifndef __WINE_VER_H
+#define __WINE_VER_H
+
+#include "windows.h"
+
+/* resource ids for different version infos */
+#define	VS_FILE_INFO	MAKEINTRESOURCE(16)
+#define	VS_VERSION_INFO	MAKEINTRESOURCE(1)
+#define	VS_USER_INFO	MAKEINTRESOURCE(100)
+
+#define	VS_FFI_SIGNATURE	0xfeef04bdL	/* FileInfo Magic */
+#define	VS_FFI_STRUCVERSION	0x00010000L	/* struc version 1.0 */
+#define	VS_FFI_FILEFLAGSMASK	0x0000003fL	/* valid flags */
+
+/* VS_VERSION.dwFileFlags */
+#define	VS_FF_DEBUG		0x01L
+#define	VS_FF_PRERELEASE	0x02L
+#define	VS_FF_PATCHED		0x04L
+#define	VS_FF_PRIVATEBUILD	0x08L
+#define	VS_FF_INFOINFERRED	0x10L
+#define	VS_FF_SPECIALBUILD	0x20L
+
+/* VS_VERSION.dwFileOS */
+
+/* major os version */
+#define	VOS_UNKNOWN		0x00000000L
+#define	VOS_DOS			0x00010000L
+#define	VOS_OS216		0x00020000L
+#define	VOS_OS232		0x00030000L
+#define	VOS_NT			0x00040000L
+
+/* minor os version */
+#define	VOS__BASE		0x00000000L
+#define	VOS__WINDOWS16		0x00000001L
+#define	VOS__PM16		0x00000002L
+#define	VOS__PM32		0x00000003L
+#define	VOS__WINDOWS32		0x00000004L
+
+/* possible versions */
+#define	VOS_DOS_WINDOWS16	(VOS_DOS|VOS__WINDOWS16)
+#define	VOS_DOS_WINDOWS32	(VOS_DOS|VOS__WINDOWS32)
+#define	VOS_OS216_PM16		(VOS_OS216|VOS__PM16)
+#define	VOS_OS232_PM32		(VOS_OS232|VOS__PM32)
+#define	VOS_NT_WINDOWS32	(VOS_NT|VOS__WINDOWS32)
+
+/* VS_VERSION.dwFileType */
+#define	VFT_UNKNOWN		0x00000000L
+#define	VFT_APP			0x00000001L
+#define	VFT_DLL			0x00000002L
+#define	VFT_DRV			0x00000003L
+#define	VFT_FONT		0x00000004L
+#define	VFT_VXD			0x00000005L
+/* ??one type missing??		0x00000006L -Marcus */
+#define	VFT_STATIC_LIB		0x00000007L
+
+/* VS_VERSION.dwFileSubtype for VFT_DRV */
+#define	VFT2_UNKNOWN		0x00000000L
+#define	VFT2_DRV_PRINTER	0x00000001L
+#define	VFT2_DRV_KEYBOARD	0x00000002L
+#define	VFT2_DRV_LANGUAGE	0x00000003L
+#define	VFT2_DRV_DISPLAY	0x00000004L
+#define	VFT2_DRV_MOUSE		0x00000005L
+#define	VFT2_DRV_NETWORK	0x00000006L
+#define	VFT2_DRV_SYSTEM		0x00000007L
+#define	VFT2_DRV_INSTALLABLE	0x00000008L
+#define	VFT2_DRV_SOUND		0x00000009L
+#define	VFT2_DRV_COMM		0x0000000aL
+#define	VFT2_DRV_INPUTMETHOD	0x0000000bL
+
+/* VS_VERSION.dwFileSubtype for VFT_FONT */
+#define	VFT2_FONT_RASTER	0x00000001L
+#define	VFT2_FONT_VECTOR	0x00000002L
+#define	VFT2_FONT_TRUETYPE	0x00000003L
+
+/* VerFindFile Flags */
+	/* input */
+#define	VFFF_ISSHAREDFILE	0x0001
+
+	/* output (returned) */
+#define	VFF_CURNEDEST		0x0001
+#define	VFF_FILEINUSE		0x0002
+#define	VFF_BUFFTOSMALL		0x0003
+
+/* VerInstallFile Flags */
+	/* input */
+#define	VIFF_FORCEINSTALL	0x0001
+#define	VIFF_DONTDELETEOLD	0x0002
+
+	/* output (return) */
+#define	VIF_TEMPFILE		0x00000001L
+#define	VIF_MISMATCH		0x00000002L
+#define	VIF_SRCOLD		0x00000004L
+#define	VIF_DIFFLANG		0x00000008L
+#define	VIF_DIFFCODEPG		0x00000010L
+#define	VIF_DIFFTYPE		0x00000020L
+#define	VIF_WRITEPROT		0x00000040L
+#define	VIF_FILEINUSE		0x00000080L
+#define	VIF_OUTOFSPACE		0x00000100L
+#define	VIF_ACCESSVIOLATION	0x00000200L
+#define	VIF_SHARINGVIOLATION	0x00000400L
+#define	VIF_CANNOTCREATE	0x00000800L
+#define	VIF_CANNOTDELETE	0x00001000L
+#define	VIF_CANNOTRENAME	0x00002000L
+#define	VIF_CANNOTDELETECUR	0x00004000L
+#define	VIF_OUTOFMEMORY		0x00008000L
+#define	VIF_CANNOTREADSRC	0x00010000L
+#define	VIF_CANNOTREADDST	0x00020000L
+#define	VIF_BUFTOSMALL		0x00040000L
+
+typedef struct tagVS_FIXEDFILEINFO {
+	DWORD   dwSignature;
+	DWORD   dwStrucVersion;
+	DWORD   dwFileVersionMS;
+	DWORD   dwFileVersionLS;
+	DWORD   dwProductVersionMS;
+	DWORD   dwProductVersionLS;
+	DWORD   dwFileFlagsMask;
+	DWORD   dwFileFlags;
+	DWORD   dwFileOS;
+	DWORD   dwFileType;
+	DWORD   dwFileSubtype;
+	DWORD   dwFileDateMS;
+	DWORD   dwFileDateLS;
+} VS_FIXEDFILEINFO;
+
+DWORD WINAPI
+GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid,LPDWORD off);
+
+DWORD WINAPI
+GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid,
+		DWORD off,DWORD reslen,LPVOID data
+);
+
+DWORD WINAPI
+GetFileVersionInfoSize(LPCSTR filename,LPDWORD handle);
+
+DWORD WINAPI
+GetFileVersionInfo(LPCSTR filename,DWORD handle,DWORD datasize,LPVOID data);
+
+DWORD WINAPI
+VerFindFile(
+	UINT flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
+	LPSTR curdir,UINT *curdirlen,LPSTR destdir,UINT*destdirlen
+);
+
+DWORD WINAPI
+VerInstallFile(
+	UINT flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
+	LPCSTR destdir,LPSTR tmpfile,UINT*tmpfilelen
+);
+
+DWORD WINAPI
+VerLanguageName(UINT lang,LPSTR langname,UINT langnamelen);
+
+DWORD WINAPI
+VerQueryValue(SEGPTR block,LPCSTR subblock,SEGPTR *buffer,UINT *buflen);
+
+/*
+   20 GETFILEVERSIONINFORAW
+   21 VERFTHK_THUNKDATA16
+   22 VERTHKSL_THUNKDATA16
+*/
+
+#endif	/* __WINE_VER_H */
diff --git a/include/win.h b/include/win.h
index a4ecf1b..9738880 100644
--- a/include/win.h
+++ b/include/win.h
@@ -29,35 +29,35 @@
 
 typedef struct tagWND
 {
-    struct tagWND *next;         /* Next sibling */
-    struct tagWND *child;        /* First child */
-    struct tagWND *parent;       /* Window parent (from CreateWindow) */
-    struct tagWND *owner;        /* Window owner */
-    DWORD        dwMagic;        /* Magic number (must be WND_MAGIC) */
-    HWND         hwndSelf;       /* Handle of this window */
-    HCLASS       hClass;         /* Window class */
-    HANDLE       hInstance;      /* Window hInstance (from CreateWindow) */
-    RECT         rectClient;     /* Client area rel. to parent client area */
-    RECT         rectWindow;     /* Whole window rel. to parent client area */
-    RECT         rectNormal;     /* Window rect. when in normal state */
-    POINT        ptIconPos;      /* Icon position */
-    POINT        ptMaxPos;       /* Maximized window position */
-    HGLOBAL      hmemTaskQ;      /* Task queue global memory handle */
-    HRGN         hrgnUpdate;     /* Update region */
-    HWND         hwndLastActive; /* Last active popup hwnd */
-    WNDPROC      lpfnWndProc;    /* Window procedure */
-    DWORD        dwStyle;        /* Window style (from CreateWindow) */
-    DWORD        dwExStyle;      /* Extended style (from CreateWindowEx) */
-    HANDLE       hdce;           /* Window DCE (if CS_OWNDC or CS_CLASSDC) */
-    HANDLE       hVScroll;       /* Vertical scroll-bar info */
-    HANDLE       hHScroll;       /* Horizontal scroll-bar info */
-    UINT         wIDmenu;        /* ID or hmenu (from CreateWindow) */
-    HANDLE       hText;          /* Handle of window text */
-    WORD         flags;          /* Misc. flags (see below) */
-    Window       window;         /* X window (only for top-level windows) */
-    HMENU        hSysMenu;	 /* window's copy of System Menu */
-    HANDLE       hProp;          /* Handle of Properties List */
-    WORD         wExtra[1];      /* Window extra bytes */
+    struct tagWND *next;          /* Next sibling */
+    struct tagWND *child;         /* First child */
+    struct tagWND *parent;        /* Window parent (from CreateWindow) */
+    struct tagWND *owner;         /* Window owner */
+    CLASS         *class;         /* Window class */
+    DWORD          dwMagic;       /* Magic number (must be WND_MAGIC) */
+    HWND           hwndSelf;      /* Handle of this window */
+    HANDLE         hInstance;     /* Window hInstance (from CreateWindow) */
+    RECT           rectClient;    /* Client area rel. to parent client area */
+    RECT           rectWindow;    /* Whole window rel. to parent client area */
+    RECT           rectNormal;    /* Window rect. when in normal state */
+    POINT          ptIconPos;     /* Icon position */
+    POINT          ptMaxPos;      /* Maximized window position */
+    HGLOBAL        hmemTaskQ;     /* Task queue global memory handle */
+    HRGN           hrgnUpdate;    /* Update region */
+    HWND           hwndLastActive;/* Last active popup hwnd */
+    WNDPROC        lpfnWndProc;   /* Window procedure */
+    DWORD          dwStyle;       /* Window style (from CreateWindow) */
+    DWORD          dwExStyle;     /* Extended style (from CreateWindowEx) */
+    HANDLE         hdce;          /* Window DCE (if CS_OWNDC or CS_CLASSDC) */
+    HANDLE         hVScroll;      /* Vertical scroll-bar info */
+    HANDLE         hHScroll;      /* Horizontal scroll-bar info */
+    UINT           wIDmenu;       /* ID or hmenu (from CreateWindow) */
+    HANDLE         hText;         /* Handle of window text */
+    WORD           flags;         /* Misc. flags (see below) */
+    Window         window;        /* X window (only for top-level windows) */
+    HMENU          hSysMenu;      /* window's copy of System Menu */
+    HANDLE         hProp;         /* Handle of Properties List */
+    WORD           wExtra[1];     /* Window extra bytes */
 } WND;
 
   /* WND flags values */
@@ -71,9 +71,6 @@
 #define WIN_NCACTIVATED        0x0080 /* last WM_NCACTIVATE was positive */
 #define WIN_MANAGED            0x0100 /* Window managed by the X wm */
 
-#define WIN_CLASS_INFO(wndPtr)   (CLASS_FindClassPtr((wndPtr)->hClass)->wc)
-#define WIN_CLASS_STYLE(wndPtr)  (WIN_CLASS_INFO(wndPtr).style)
-
   /* Window functions */
 extern WND *WIN_FindWndPtr( HWND hwnd );
 extern WND *WIN_GetDesktop(void);
diff --git a/include/winbase.h b/include/winbase.h
index 66d8e1a..e913407 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -102,6 +102,15 @@
   int ss;
 } exception_info;
 
+/* Could this type be considered opaque? */
+typedef struct {
+	LPVOID	DebugInfo;
+	LONG LockCount;
+	LONG RecursionCount;
+	HANDLE OwningThread;
+	HANDLE LockSemaphore;
+	DWORD Reserved;
+}CRITICAL_SECTION;
 
 /*DWORD WINAPI GetVersion( void );*/
 
diff --git a/include/windows.h b/include/windows.h
index 5ad16fb..3a0ff78 100644
--- a/include/windows.h
+++ b/include/windows.h
@@ -1371,6 +1371,7 @@
 #define OBM_FLOPPY          32731
 #define OBM_HDISK           32730
 #define OBM_CDROM           32729
+#define OBM_TRTYPE          32728
 
 #define OBM_OLD_CLOSE       32767
 #define OBM_SIZE            32766
@@ -2811,7 +2812,7 @@
 BOOL       ExitWindows(DWORD,WORD);
 BOOL       ExtFloodFill(HDC,INT,INT,COLORREF,WORD);
 BOOL       ExtTextOut(HDC,short,short,WORD,LPRECT,LPSTR,WORD,LPINT);
-HICON      ExtractIcon(HINSTANCE,LPCSTR,UINT);
+HICON      ExtractIcon(HINSTANCE,LPCSTR,WORD);
 WORD       FarGetOwner(HANDLE);
 void       FarSetOwner(HANDLE,HANDLE);
 void       FatalAppExit(UINT,LPCSTR);
diff --git a/include/wintypes.h b/include/wintypes.h
index 9430f56..afce262 100644
--- a/include/wintypes.h
+++ b/include/wintypes.h
@@ -19,6 +19,11 @@
 # endif
 #endif
 
+typedef short INT16;
+typedef unsigned short UINT16;
+typedef int INT32;
+typedef unsigned int UINT32;
+
 typedef unsigned short WORD;
 typedef unsigned long DWORD;
 typedef unsigned short BOOL;
@@ -42,8 +47,9 @@
 typedef DWORD SEGPTR;
 #endif  /* WINELIB32 */
 
+typedef UINT16 HANDLE16;
+typedef UINT32 HANDLE32;
 typedef UINT HANDLE;
-typedef DWORD HANDLE32;
 typedef UINT WPARAM;
 typedef LONG LPARAM;
 typedef LONG LRESULT;
@@ -69,7 +75,10 @@
 typedef DWORD ACCESS_MASK;
 typedef ACCESS_MASK REGSAM;
 
-#define DECLARE_HANDLE(a) typedef HANDLE a;
+#define DECLARE_HANDLE(a) \
+    typedef HANDLE a; \
+    typedef HANDLE16 a##16; \
+    typedef HANDLE32 a##32;
 
 DECLARE_HANDLE(HBITMAP);
 DECLARE_HANDLE(HBRUSH);
diff --git a/include/winuser.h b/include/winuser.h
new file mode 100644
index 0000000..9ee274f
--- /dev/null
+++ b/include/winuser.h
@@ -0,0 +1,97 @@
+/*
+ * USER definitions
+ *
+ * Copyright 1996 Alexandre Julliard
+ */
+
+#ifndef __WINE_WINUSER_H
+#define __WINE_WINUSER_H
+
+#include "wintypes.h"
+
+
+/* Window classes */
+
+typedef struct
+{
+    UINT32      style;
+    WNDPROC32   lpfnWndProc;
+    INT32       cbClsExtra;
+    INT32       cbWndExtra;
+    HINSTANCE32 hInstance;
+    HICON32     hIcon;
+    HCURSOR32   hCursor;
+    HBRUSH32    hbrBackground;
+    LPCSTR      lpszMenuName;
+    LPCSTR      lpszClassName;
+} WNDCLASS32A, *LPWNDCLASS32A;
+
+typedef struct
+{
+    UINT32      style;
+    WNDPROC32   lpfnWndProc;
+    INT32       cbClsExtra;
+    INT32       cbWndExtra;
+    HINSTANCE32 hInstance;
+    HICON32     hIcon;
+    HCURSOR32   hCursor;
+    HBRUSH32    hbrBackground;
+    LPCWSTR     lpszMenuName;
+    LPCWSTR     lpszClassName;
+} WNDCLASS32W, *LPWNDCLASS32W;
+
+typedef struct
+{
+    UINT16      style;
+    WNDPROC     lpfnWndProc WINE_PACKED;
+    INT16       cbClsExtra;
+    INT16       cbWndExtra;
+    HANDLE16    hInstance;
+    HICON16     hIcon;
+    HCURSOR16   hCursor;
+    HBRUSH16    hbrBackground;
+    SEGPTR      lpszMenuName WINE_PACKED;
+    SEGPTR      lpszClassName WINE_PACKED;
+} WNDCLASS16, *LPWNDCLASS16;
+
+typedef struct
+{
+    UINT32      cbSize;
+    UINT32      style;
+    WNDPROC32   lpfnWndProc;
+    INT32       cbClsExtra;
+    INT32       cbWndExtra;
+    HINSTANCE32 hInstance;
+    HICON32     hIcon;
+    HCURSOR32   hCursor;
+    HBRUSH32    hbrBackground;
+    LPCSTR      lpszMenuName;
+    LPCSTR      lpszClassName;
+    HICON32     hIconSm;
+} WNDCLASSEX32A, *LPWNDCLASSEX32A;
+
+typedef struct
+{
+    UINT32      cbSize;
+    UINT32      style;
+    WNDPROC32   lpfnWndProc;
+    INT32       cbClsExtra;
+    INT32       cbWndExtra;
+    HINSTANCE32 hInstance;
+    HICON32     hIcon;
+    HCURSOR32   hCursor;
+    HBRUSH32    hbrBackground;
+    LPCWSTR     lpszMenuName;
+    LPCWSTR     lpszClassName;
+    HICON32     hIconSm;
+} WNDCLASSEX32W, *LPWNDCLASSEX32W;
+
+typedef void WNDCLASSEX16;  /* There's no WNDCLASSEX in Win16 */
+
+DECL_WINELIB_TYPE_AW(WNDCLASS);
+DECL_WINELIB_TYPE_AW(LPWNDCLASS);
+DECL_WINELIB_TYPE_AW(WNDCLASSEX);
+DECL_WINELIB_TYPE_AW(LPWNDCLASSEX);
+
+
+#endif  /* __WINE_WINUSER_H */
diff --git a/library/miscstubs.c b/library/miscstubs.c
index 846f702..407de96 100644
--- a/library/miscstubs.c
+++ b/library/miscstubs.c
@@ -129,11 +129,6 @@
   return 0;
 }
 
-void *RELAY32_GetEntryPoint(BUILTIN_DLL *dll, char *item, int hint)
-{
-  return NULL;
-}
-
 extern LRESULT ACTIVATEAPP_callback(HWND,UINT,WPARAM,LPARAM);
 extern LRESULT AboutDlgProc(HWND,UINT,WPARAM,LPARAM);
 extern LRESULT ButtonWndProc(HWND,UINT,WPARAM,LPARAM);
@@ -166,7 +161,7 @@
 /***********************************************************************
  *           MODULE_GetWndProcEntry16 (not a Windows API function)
  *
- * Return an entry point from the WINPROCS dll.
+ * Return an entry point from the WPROCS dll.
  */
 WNDPROC MODULE_GetWndProcEntry16( char *name )
 {
@@ -201,7 +196,7 @@
 /***********************************************************************
  *           MODULE_GetWndProcEntry32 (not a Windows API function)
  *
- * Return an entry point from the WINPROCS32 dll.
+ * Return an entry point from the WPROCS32 dll.
  */
 WNDPROC MODULE_GetWndProcEntry32( char *name )
 {
diff --git a/loader/Makefile.in b/loader/Makefile.in
index 74d6a71..7ae4cf8 100644
--- a/loader/Makefile.in
+++ b/loader/Makefile.in
@@ -2,6 +2,7 @@
 MODULE = loader
 
 C_SRCS = \
+	builtin.c \
 	main.c \
 	module.c \
 	ne_image.c \
diff --git a/loader/builtin.c b/loader/builtin.c
new file mode 100644
index 0000000..a2f074d
--- /dev/null
+++ b/loader/builtin.c
@@ -0,0 +1,426 @@
+/*
+ * Built-in modules
+ *
+ * Copyright 1996 Alexandre Julliard
+ */
+
+#ifndef WINELIB
+
+#include <ctype.h>
+#include <string.h>
+#include "windows.h"
+#include "gdi.h"
+#include "global.h"
+#include "module.h"
+#include "neexe.h"
+#include "user.h"
+#include "stddebug.h"
+#include "debug.h"
+
+
+/* Built-in modules descriptors */
+/* Don't change these structures! (see tools/build.c) */
+
+typedef struct
+{
+    const BYTE *code_start;        /* 32-bit address of DLL code */
+    const BYTE *data_start;        /* 32-bit address of DLL data */
+} WIN16_DESCRIPTOR;
+
+typedef struct
+{
+    int                 base;      /* Ordinal base */
+    int                 size;      /* Number of functions */
+    const void        **functions; /* Pointer to functions table */
+    const char * const *names;     /* Pointer to names table */
+} WIN32_DESCRIPTOR;
+
+typedef struct
+{
+    const char *name;              /* DLL name */
+    void       *module_start;      /* 32-bit address of the module data */
+    int         module_size;       /* Size of the module data */
+    union
+    {
+        WIN16_DESCRIPTOR win16;    /* Descriptor for Win16 DLL */
+        WIN32_DESCRIPTOR win32;    /* Descriptor for Win32 DLL */
+    } u;
+} DLL_DESCRIPTOR;
+
+typedef struct
+{
+    const DLL_DESCRIPTOR *descr;   /* DLL descriptor */
+    int                   flags;   /* flags (see below) */
+} BUILTIN_DLL;
+
+
+/* DLL flags */
+#define DLL_FLAG_NOT_USED    0x01  /* Use original Windows DLL if possible */
+#define DLL_FLAG_ALWAYS_USED 0x02  /* Always use built-in DLL */
+#define DLL_FLAG_WIN32       0x04  /* DLL is a Win32 DLL */
+
+
+/* 16-bit DLLs */
+
+extern const DLL_DESCRIPTOR KERNEL_Descriptor;
+extern const DLL_DESCRIPTOR USER_Descriptor;
+extern const DLL_DESCRIPTOR GDI_Descriptor;
+extern const DLL_DESCRIPTOR WIN87EM_Descriptor;
+extern const DLL_DESCRIPTOR MMSYSTEM_Descriptor;
+extern const DLL_DESCRIPTOR SHELL_Descriptor;
+extern const DLL_DESCRIPTOR SOUND_Descriptor;
+extern const DLL_DESCRIPTOR KEYBOARD_Descriptor;
+extern const DLL_DESCRIPTOR WINSOCK_Descriptor;
+extern const DLL_DESCRIPTOR STRESS_Descriptor;
+extern const DLL_DESCRIPTOR SYSTEM_Descriptor;
+extern const DLL_DESCRIPTOR TOOLHELP_Descriptor;
+extern const DLL_DESCRIPTOR MOUSE_Descriptor;
+extern const DLL_DESCRIPTOR COMMDLG_Descriptor;
+extern const DLL_DESCRIPTOR OLE2_Descriptor;
+extern const DLL_DESCRIPTOR OLE2CONV_Descriptor;
+extern const DLL_DESCRIPTOR OLE2DISP_Descriptor;
+extern const DLL_DESCRIPTOR OLE2NLS_Descriptor;
+extern const DLL_DESCRIPTOR OLE2PROX_Descriptor;
+extern const DLL_DESCRIPTOR OLECLI_Descriptor;
+extern const DLL_DESCRIPTOR OLESVR_Descriptor;
+extern const DLL_DESCRIPTOR COMPOBJ_Descriptor;
+extern const DLL_DESCRIPTOR STORAGE_Descriptor;
+extern const DLL_DESCRIPTOR WPROCS_Descriptor;
+extern const DLL_DESCRIPTOR DDEML_Descriptor;
+extern const DLL_DESCRIPTOR LZEXPAND_Descriptor;
+extern const DLL_DESCRIPTOR VER_Descriptor;
+extern const DLL_DESCRIPTOR W32SYS_Descriptor;
+
+/* 32-bit DLLs */
+
+extern const DLL_DESCRIPTOR ADVAPI32_Descriptor;
+extern const DLL_DESCRIPTOR COMCTL32_Descriptor;
+extern const DLL_DESCRIPTOR COMDLG32_Descriptor;
+extern const DLL_DESCRIPTOR OLE32_Descriptor;
+extern const DLL_DESCRIPTOR GDI32_Descriptor;
+extern const DLL_DESCRIPTOR KERNEL32_Descriptor;
+extern const DLL_DESCRIPTOR SHELL32_Descriptor;
+extern const DLL_DESCRIPTOR USER32_Descriptor;
+extern const DLL_DESCRIPTOR WPROCS32_Descriptor;
+extern const DLL_DESCRIPTOR WINSPOOL_Descriptor;
+
+/* Table of all built-in DLLs */
+
+static BUILTIN_DLL BuiltinDLLs[] =
+{
+    /* Win16 DLLs */
+    { &KERNEL_Descriptor,   DLL_FLAG_ALWAYS_USED },
+    { &USER_Descriptor,     DLL_FLAG_ALWAYS_USED },
+    { &GDI_Descriptor,      DLL_FLAG_ALWAYS_USED },
+    { &WIN87EM_Descriptor,  DLL_FLAG_NOT_USED },
+    { &SHELL_Descriptor,    0 },
+    { &SOUND_Descriptor,    0 },
+    { &KEYBOARD_Descriptor, 0 },
+    { &WINSOCK_Descriptor,  0 },
+    { &STRESS_Descriptor,   0 },
+    { &MMSYSTEM_Descriptor, 0 },
+    { &SYSTEM_Descriptor,   0 },
+    { &TOOLHELP_Descriptor, 0 },
+    { &MOUSE_Descriptor,    0 },
+    { &COMMDLG_Descriptor,  DLL_FLAG_NOT_USED },
+    { &OLE2_Descriptor,     DLL_FLAG_NOT_USED },
+    { &OLE2CONV_Descriptor, DLL_FLAG_NOT_USED },
+    { &OLE2DISP_Descriptor, DLL_FLAG_NOT_USED },
+    { &OLE2NLS_Descriptor,  DLL_FLAG_NOT_USED },
+    { &OLE2PROX_Descriptor, DLL_FLAG_NOT_USED },
+    { &OLECLI_Descriptor,   DLL_FLAG_NOT_USED },
+    { &OLESVR_Descriptor,   DLL_FLAG_NOT_USED },
+    { &COMPOBJ_Descriptor,  DLL_FLAG_NOT_USED },
+    { &STORAGE_Descriptor,  DLL_FLAG_NOT_USED },
+    { &WPROCS_Descriptor,   DLL_FLAG_ALWAYS_USED },
+    { &DDEML_Descriptor,    DLL_FLAG_NOT_USED },
+    { &LZEXPAND_Descriptor, 0 },
+    { &VER_Descriptor,      0 },
+    { &W32SYS_Descriptor,   0 },
+    /* Win32 DLLs */
+    { &ADVAPI32_Descriptor, 0 },
+    { &COMCTL32_Descriptor, 0 },
+    { &COMDLG32_Descriptor, 0 },
+    { &OLE32_Descriptor,    0 },
+    { &GDI32_Descriptor,    0 },
+    { &KERNEL32_Descriptor, DLL_FLAG_ALWAYS_USED },
+    { &SHELL32_Descriptor,  0 },
+    { &USER32_Descriptor,   0 },
+    { &WPROCS32_Descriptor, DLL_FLAG_ALWAYS_USED },
+    { &WINSPOOL_Descriptor, 0 },
+    /* Last entry */
+    { NULL, 0 }
+};
+
+
+/***********************************************************************
+ *           BUILTIN_Init
+ *
+ * Load all built-in modules marked as 'always used'.
+ */
+BOOL BUILTIN_Init(void)
+{
+    BUILTIN_DLL *dll;
+    NE_MODULE *pModule;
+
+    for (dll = BuiltinDLLs; dll->descr; dll++)
+        if (dll->flags & DLL_FLAG_ALWAYS_USED)
+            if (!BUILTIN_LoadModule(dll->descr->name, TRUE)) return FALSE;
+
+    /* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */
+
+    MODULE_SetEntryPoint( GetModuleHandle( "KERNEL" ), 178, GetWinFlags() );
+
+    /* Set the USER and GDI heap selectors */
+
+    pModule      = MODULE_GetPtr( GetModuleHandle( "USER" ));
+    USER_HeapSel = (NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->selector;
+    pModule      = MODULE_GetPtr( GetModuleHandle( "GDI" ));
+    GDI_HeapSel  = (NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->selector;
+
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           BUILTIN_LoadModule
+ *
+ * Load a built-in module. If the 'force' parameter is FALSE, we only
+ * load the module if it has not been disabled via the -dll option.
+ */
+HMODULE BUILTIN_LoadModule( LPCSTR name, BOOL force )
+{
+    HMODULE hModule;
+    NE_MODULE *pModule;
+    BUILTIN_DLL *table;
+    char dllname[16], *p;
+
+    /* Fix the name in case we have a full path and extension */
+
+    if ((p = strrchr( name, '\\' ))) name = p + 1;
+    lstrcpyn( dllname, name, sizeof(dllname) );
+    if ((p = strrchr( dllname, '.' ))) *p = '\0';
+
+    for (table = BuiltinDLLs; table->descr; table++)
+        if (!lstrcmpi( table->descr->name, dllname )) break;
+    if (!table->descr) return 0;
+    if ((table->flags & DLL_FLAG_NOT_USED) && !force) return 0;
+
+    hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, table->descr->module_start,
+                                  table->descr->module_size, 0,
+                                  FALSE, FALSE, FALSE, NULL );
+    if (!hModule) return 0;
+    FarSetOwner( hModule, hModule );
+
+    dprintf_module( stddeb, "Built-in %s: hmodule=%04x\n",
+                    table->descr->name, hModule );
+    pModule = (NE_MODULE *)GlobalLock( hModule );
+    pModule->self = hModule;
+
+    if (pModule->flags & NE_FFLAGS_WIN32)
+    {
+        pModule->pe_module = (PE_MODULE *)table;
+    }
+    else  /* Win16 module */
+    {
+        const WIN16_DESCRIPTOR *descr = &table->descr->u.win16;
+        int minsize;
+
+        /* Allocate the code segment */
+
+        SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
+        pSegTable->selector = GLOBAL_CreateBlock(GMEM_FIXED, descr->code_start,
+                                                 pSegTable->minsize, hModule,
+                                                 TRUE, TRUE, FALSE, NULL );
+        if (!pSegTable->selector) return 0;
+        pSegTable++;
+
+        /* Allocate the data segment */
+
+        minsize = pSegTable->minsize ? pSegTable->minsize : 0x10000;
+        minsize += pModule->heap_size;
+        if (minsize > 0x10000) minsize = 0x10000;
+        pSegTable->selector = GLOBAL_Alloc( GMEM_FIXED, minsize,
+                                            hModule, FALSE, FALSE, FALSE );
+        if (!pSegTable->selector) return 0;
+        if (pSegTable->minsize) memcpy( GlobalLock( pSegTable->selector ),
+                                        descr->data_start, pSegTable->minsize);
+        if (pModule->heap_size)
+            LocalInit( pSegTable->selector, pSegTable->minsize, minsize );
+    }
+
+    MODULE_RegisterModule( pModule );
+    return hModule;
+}
+
+
+/***********************************************************************
+ *           BUILTIN_GetEntryPoint
+ *
+ * Return the built-in module, ordinal and name corresponding
+ * to a CS:IP address. This is used only by relay debugging.
+ */
+NE_MODULE *BUILTIN_GetEntryPoint( WORD cs, WORD ip, WORD *pOrd, char **ppName )
+{
+    WORD ordinal, i, max_offset;
+    register BYTE *p;
+    NE_MODULE *pModule;
+
+    if (!(pModule = MODULE_GetPtr( FarGetOwner( GlobalHandle(cs) ))))
+        return NULL;
+
+    /* Search for the ordinal */
+
+    p = (BYTE *)pModule + pModule->entry_table;
+    max_offset = 0;
+    ordinal = 1;
+    *pOrd = 0;
+    while (*p)
+    {
+        switch(p[1])
+        {
+        case 0:    /* unused */
+            ordinal += *p;
+            p += 2;
+            break;
+        case 1:    /* code segment */
+            i = *p;
+            p += 2;
+            while (i-- > 0)
+            {
+                p++;
+                if ((*(WORD *)p <= ip) && (*(WORD *)p >= max_offset))
+                {
+                    max_offset = *(WORD *)p;
+                    *pOrd = ordinal;
+                }
+                p += 2;
+                ordinal++;
+            }
+            break;
+        case 0xff: /* moveable (should not happen in built-in modules) */
+            fprintf( stderr, "Built-in module has moveable entry\n" );
+            ordinal += *p;
+            p += 2 + *p * 6;
+            break;
+        default:   /* other segment */
+            ordinal += *p;
+            p += 2 + *p * 3;
+            break;
+        }
+    }
+
+    /* Search for the name in the resident names table */
+    /* (built-in modules have no non-resident table)   */
+    
+    p = (BYTE *)pModule + pModule->name_table;
+    *ppName = "???";
+    while (*p)
+    {
+        p += *p + 1 + sizeof(WORD);
+        if (*(WORD *)(p + *p + 1) == *pOrd)
+        {
+            *ppName = (char *)p;
+            break;
+        }
+    }
+
+    return pModule;
+}
+
+
+/***********************************************************************
+ *           BUILTIN_GetProcAddress32
+ *
+ * Implementation of GetProcAddress() for built-in Win32 modules.
+ * FIXME: this should be unified with the real GetProcAddress32().
+ */
+DWORD BUILTIN_GetProcAddress32( NE_MODULE *pModule, char *function )
+{
+    BUILTIN_DLL *dll = (BUILTIN_DLL *)pModule->pe_module;
+    const WIN32_DESCRIPTOR *info = &dll->descr->u.win32;
+
+    if (!dll) return 0;
+
+    if (HIWORD(function))  /* Find function by name */
+    {
+        int i;
+
+        dprintf_module( stddeb, "Looking for function %s in %s\n",
+                        function, dll->descr->name );
+        for (i = 0; i < info->size; i++)
+            if (info->names[i] && !strcmp( function, info->names[i] ))
+                return (DWORD)info->functions[i];
+    }
+    else  /* Find function by ordinal */
+    {
+        WORD ordinal = LOWORD(function);
+        dprintf_module( stddeb, "Looking for ordinal %d in %s\n",
+                        ordinal, dll->descr->name );
+        if (ordinal && ordinal < info->size)
+            return (DWORD)info->functions[ordinal - info->base];
+    }
+    return 0;
+}
+
+
+/***********************************************************************
+ *           BUILTIN_ParseDLLOptions
+ *
+ * Set runtime DLL usage flags
+ */
+BOOL BUILTIN_ParseDLLOptions( const char *str )
+{
+    BUILTIN_DLL *dll;
+    const char *p;
+
+    while (*str)
+    {
+        while (*str && isspace(*str)) str++;
+        if (!*str) return TRUE;
+        if ((*str != '+') && (*str != '-')) return FALSE;
+        str++;
+        if (!(p = strchr( str, ',' ))) p = str + strlen(str);
+        while ((p > str) && isspace(p[-1])) p--;
+        if (p == str) return FALSE;
+        for (dll = BuiltinDLLs; dll->descr; dll++)
+        {
+            if (!lstrncmpi( str, dll->descr->name, (int)(p - str) ))
+            {
+                if (str[-1] == '-')
+                {
+                    if (dll->flags & DLL_FLAG_ALWAYS_USED) return FALSE;
+                    dll->flags |= DLL_FLAG_NOT_USED;
+                }
+                else dll->flags &= ~DLL_FLAG_NOT_USED;
+                break;
+            }
+        }
+        if (!dll->descr) return FALSE;
+        str = p;
+    }
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           BUILTIN_PrintDLLs
+ *
+ * Print the list of built-in DLLs that can be disabled.
+ */
+void BUILTIN_PrintDLLs(void)
+{
+    int i;
+    BUILTIN_DLL *dll;
+
+    for (i = 0, dll = BuiltinDLLs; dll->descr; dll++)
+    {
+        if (!(dll->flags & DLL_FLAG_ALWAYS_USED))
+            fprintf( stderr, "%-9s%c", dll->descr->name,
+                     ((++i) % 8) ? ' ' : '\n' );
+    }
+    fprintf(stderr,"\n");
+    exit(1);
+}
+
+#endif  /* WINELIB */
diff --git a/loader/main.c b/loader/main.c
index b06e261..334ec82 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -16,7 +16,6 @@
 #include "task.h"
 #include "selectors.h"
 #include "comm.h"
-#include "user.h"
 #include "win.h"
 #include "menu.h"
 #include "kernel32.h"
@@ -28,8 +27,8 @@
 #include "syscolor.h"
 #include "sysmetrics.h"
 #include "gdi.h"
+#include "heap.h"
 #include "debugger.h"
-#include "dlls.h"
 #include "miscemu.h"
 #include "neexe.h"
 #include "options.h"
@@ -42,6 +41,7 @@
 
 void init_wine_signals(void);
 
+HANDLE32 SystemHeap = 0;
 
 /***********************************************************************
  *           Main initialisation routine
@@ -52,6 +52,9 @@
 
     int queueSize;
 
+    /* Create the system heap */
+    if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return 0;
+
     /* Load the configuration file */
     if (!PROFILE_LoadWineIni()) return 0;
 
@@ -61,10 +64,10 @@
 #ifndef WINELIB
       /* Initialize relay code */
     if (!RELAY_Init()) return 0;
-#endif
 
       /* Create built-in modules */
-    if (!MODULE_Init()) return 0;
+    if (!BUILTIN_Init()) return 0;
+#endif
 
     /* Initialise DOS drives */
     if (!DRIVE_Init()) return 0;
@@ -90,9 +93,6 @@
 
       /* Initialize the DOS memory */
     if (!INT21_Init()) return 0;
-
-      /* Create USER heap */
-    if (!USER_HeapInit()) return 0;
 #endif
     
       /* Global atom table initialisation */
diff --git a/loader/module.c b/loader/module.c
index 128c05a..a3f4615 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -11,10 +11,11 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include "windows.h"
-#include "dlls.h"
+#include "class.h"
 #include "dos_fs.h"
 #include "file.h"
 #include "global.h"
+#include "hook.h"
 #include "ldt.h"
 #include "module.h"
 #include "neexe.h"
@@ -35,96 +36,6 @@
 #ifndef WINELIB
 static HANDLE hInitialStack32 = 0;
 #endif
-/***********************************************************************
- *           MODULE_LoadBuiltin
- *
- * Load a built-in module. If the 'force' parameter is FALSE, we only
- * load the module if it has not been disabled via the -dll option.
- */
-#ifndef WINELIB
-static HMODULE MODULE_LoadBuiltin( LPCSTR name, BOOL force )
-{
-    HMODULE hModule;
-    NE_MODULE *pModule;
-    SEGTABLEENTRY *pSegTable;
-    BUILTIN_DLL *table;
-    char dllname[16], *p;
-
-    /* Fix the name in case we have a full path and extension */
-
-    if ((p = strrchr( name, '\\' ))) name = p + 1;
-    lstrcpyn( dllname, name, sizeof(dllname) );
-    if ((p = strrchr( dllname, '.' ))) *p = '\0';
-
-    for (table = dll_builtin_table; table->name; table++)
-        if (!lstrcmpi( table->name, dllname )) break;
-    if (!table->name) return 0;
-    if ((table->flags & DLL_FLAG_NOT_USED) && !force) return 0;
-
-    hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, table->module_start,
-                                  table->module_end - table->module_start,
-                                  0, FALSE, FALSE, FALSE, NULL );
-    if (!hModule) return 0;
-    FarSetOwner( hModule, hModule );
-
-    table->hModule = hModule;
-
-    dprintf_module( stddeb, "Built-in %s: hmodule=%04x\n",
-                    table->name, hModule );
-    pModule = (NE_MODULE *)GlobalLock( hModule );
-    pModule->self = hModule;
-
-    if (pModule->flags & NE_FFLAGS_WIN32)
-    {
-        pModule->pe_module = (PE_MODULE *)table;
-    }
-    else  /* Win16 module */
-    {
-        /* Allocate the code segment */
-
-        pSegTable = NE_SEG_TABLE( pModule );
-        pSegTable->selector = GLOBAL_CreateBlock(GMEM_FIXED, table->code_start,
-                                                 pSegTable->minsize, hModule,
-                                                 TRUE, TRUE, FALSE, NULL );
-        if (!pSegTable->selector) return 0;
-        pSegTable++;
-
-        /* Allocate the data segment */
-
-        pSegTable->selector = GLOBAL_Alloc( GMEM_FIXED, pSegTable->minsize,
-                                            hModule, FALSE, FALSE, FALSE );
-        if (!pSegTable->selector) return 0;
-        memcpy( GlobalLock( pSegTable->selector ),
-                table->data_start, pSegTable->minsize );
-    }
-
-    pModule->next = hFirstModule;
-    hFirstModule = hModule;
-    return hModule;
-}
-#endif
-
-/***********************************************************************
- *           MODULE_Init
- *
- * Create the built-in modules.
- */
-BOOL MODULE_Init(void)
-{
-#ifndef WINELIB32
-    BUILTIN_DLL *dll;
-
-    /* Load all modules marked as always used */
-
-    for (dll = dll_builtin_table; dll->name; dll++)
-        if (dll->flags & DLL_FLAG_ALWAYS_USED)
-            if (!MODULE_LoadBuiltin(dll->name, TRUE)) return FALSE;
-#endif
-    /* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */
-
-    MODULE_SetEntryPoint( GetModuleHandle( "KERNEL" ), 178, GetWinFlags() );
-    return TRUE;
-}
 
 
 /***********************************************************************
@@ -358,7 +269,7 @@
 }
 
 /***********************************************************************
- *           MODULE_AllocateSegment (WINPROCS.26)
+ *           MODULE_AllocateSegment (WPROCS.26)
  */
 
 DWORD MODULE_AllocateSegment(WORD wFlags, WORD wSize, WORD wElem)
@@ -410,7 +321,7 @@
  *           MODULE_GetInstance
  */
 #ifndef WINELIB32
-static HINSTANCE MODULE_GetInstance( HMODULE hModule )
+HINSTANCE MODULE_GetInstance( HMODULE hModule )
 {
     SEGTABLEENTRY *pSegment;
     NE_MODULE *pModule;
@@ -462,7 +373,7 @@
 /***********************************************************************
  *           MODULE_LoadExeHeader
  */
-HMODULE MODULE_LoadExeHeader( HFILE hFile, OFSTRUCT *ofs )
+static HMODULE MODULE_LoadExeHeader( HFILE hFile, OFSTRUCT *ofs )
 {
     struct mz_header_s mz_header;
     struct ne_header_s ne_header;
@@ -677,8 +588,7 @@
     }
     else pModule->dlls_to_init = 0;
 
-    pModule->next = hFirstModule;
-    hFirstModule = hModule;
+    MODULE_RegisterModule( pModule );
     return hModule;
 #undef READ
 }
@@ -844,45 +754,9 @@
 
 
 /***********************************************************************
- *           MODULE_GetEntryPointName
- *
- * Return the entry point name for a given ordinal.
- * Used only by relay debugging.
- * Warning: returned pointer is to a Pascal-type string.
- */
-LPSTR MODULE_GetEntryPointName( HMODULE hModule, WORD ordinal )
-{
-    register char *cpnt;
-    NE_MODULE *pModule;
-
-    if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
-
-      /* First search the resident names */
-
-    cpnt = (char *)pModule + pModule->name_table;
-    while (*cpnt)
-    {
-        cpnt += *cpnt + 1 + sizeof(WORD);
-        if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
-    }
-
-      /* Now search the non-resident names table */
-
-    if (!pModule->nrname_handle) return 0;  /* No non-resident table */
-    cpnt = (char *)GlobalLock( pModule->nrname_handle );
-    while (*cpnt)
-    {
-        cpnt += *cpnt + 1 + sizeof(WORD);
-        if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
-    }
-    return NULL;
-}
-
-
-/***********************************************************************
  *           MODULE_GetWndProcEntry16  (not a Windows API function)
  *
- * Return an entry point from the WINPROCS dll.
+ * Return an entry point from the WPROCS dll.
  */
 #ifndef WINELIB
 WNDPROC MODULE_GetWndProcEntry16( const char *name )
@@ -890,7 +764,7 @@
     WORD ordinal;
     static HMODULE hModule = 0;
 
-    if (!hModule) hModule = GetModuleHandle( "WINPROCS" );
+    if (!hModule) hModule = GetModuleHandle( "WPROCS" );
     ordinal = MODULE_GetOrdinal( hModule, name );
     return MODULE_GetEntryPoint( hModule, ordinal );
 }
@@ -900,14 +774,14 @@
 /***********************************************************************
  *           MODULE_GetWndProcEntry32  (not a Windows API function)
  *
- * Return an entry point from the WINPROCS32 dll.
+ * Return an entry point from the WPROCS32 dll.
  */
 #ifndef WINELIB
 WNDPROC MODULE_GetWndProcEntry32( const char *name )
 {
     static HMODULE hModule = 0;
 
-    if (!hModule) hModule = GetModuleHandle( "WINPROCS32" );
+    if (!hModule) hModule = GetModuleHandle( "WPROCS32" );
     return PE_GetProcAddress( hModule, name );
 }
 #endif
@@ -934,13 +808,13 @@
 /**********************************************************************
  *           MODULE_RegisterModule
  */
-void MODULE_RegisterModule( HMODULE hModule )
+void MODULE_RegisterModule( NE_MODULE *pModule )
 {
-    NE_MODULE *pModule = MODULE_GetPtr( hModule );
     pModule->next = hFirstModule;
-    hFirstModule = hModule;
+    hFirstModule = pModule->self;
 }
 
+
 /**********************************************************************
  *	    MODULE_FindModule
  *
@@ -996,6 +870,11 @@
 
     /* FIXME: should call the exit code for the library here */
 
+    /* Free the objects owned by the module */
+
+    HOOK_FreeModuleHooks( hModule );
+    CLASS_FreeModuleClasses( hModule );
+
     /* Clear magic number just in case */
 
     pModule->magic = pModule->self = 0;
@@ -1058,12 +937,12 @@
         OFSTRUCT ofs;
 
         /* Try to load the built-in first if not disabled */
-        if ((hModule = MODULE_LoadBuiltin( name, FALSE ))) return hModule;
+        if ((hModule = BUILTIN_LoadModule( name, FALSE ))) return hModule;
 
         if ((hFile = OpenFile( name, &ofs, OF_READ )) == HFILE_ERROR)
         {
             /* Now try the built-in even if disabled */
-            if ((hModule = MODULE_LoadBuiltin( name, TRUE )))
+            if ((hModule = BUILTIN_LoadModule( name, TRUE )))
             {
                 fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
                 return hModule;
@@ -1148,7 +1027,7 @@
 		/* Handle self loading modules */
 		SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
 		SELFLOADHEADER *selfloadheader;
-		HMODULE hselfload = GetModuleHandle("WINPROCS");
+		HMODULE hselfload = GetModuleHandle("WPROCS");
 		WORD oldss, oldsp, saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
 		fprintf (stderr, "Warning:  %*.*s is a self-loading module\n"
                                 "Support for self-loading modules is very experimental\n",
diff --git a/loader/ne_image.c b/loader/ne_image.c
index 2fcd8f9..447b500 100644
--- a/loader/ne_image.c
+++ b/loader/ne_image.c
@@ -16,7 +16,6 @@
 #include <string.h>
 #include <errno.h>
 #include "neexe.h"
-#include "dlls.h"
 #include "windows.h"
 #include "arch.h"
 #include "selectors.h"
diff --git a/loader/ne_resource.c b/loader/ne_resource.c
index 7e45089..caee5f8 100644
--- a/loader/ne_resource.c
+++ b/loader/ne_resource.c
@@ -23,9 +23,6 @@
 #include "stddebug.h"
 #include "debug.h"
 
-typedef struct resource_typeinfo_s NE_TYPEINFO;
-typedef struct resource_nameinfo_s NE_NAMEINFO;
-
 
 /***********************************************************************
  *           NE_FindNameTableId
diff --git a/loader/pe_image.c b/loader/pe_image.c
index 79789b7..d16417a 100644
--- a/loader/pe_image.c
+++ b/loader/pe_image.c
@@ -18,8 +18,8 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include "windows.h"
+#include "winbase.h"
 #include "callback.h"
-#include "dlls.h"
 #include "neexe.h"
 #include "peexe.h"
 #include "pe_image.h"
@@ -140,16 +140,9 @@
     NE_MODULE *pModule;
 
     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
-    if (!(pModule->flags & NE_FFLAGS_WIN32)) return 0;
+    if (!(pModule->flags & NE_FFLAGS_WIN32) || !pModule->pe_module) return 0;
     if (pModule->flags & NE_FFLAGS_BUILTIN)
-    {
-        BUILTIN_DLL *dll = (BUILTIN_DLL *)pModule->pe_module;
-        if(HIWORD(function))
-            return RELAY32_GetEntryPoint(dll,function,0);
-        else
-            return RELAY32_GetEntryPoint(dll,0,(int)function);
-    }
-    if (!pModule->pe_module) return 0;
+        return BUILTIN_GetProcAddress32( pModule, function );
     return PE_FindExportedFunction( pModule->pe_module, function );
 }
 
@@ -247,12 +240,8 @@
         dprintf_win32(stddeb, "--- %s %s.%d\n", pe_name->Name, Module, pe_name->Hint);
 #ifndef WINELIB /* FIXME: JBP: Should this happen in libwine.a? */
 	/* FIXME: Both calls should be unified into GetProcAddress */
-#if 0
-        *thunk_list=(unsigned int)RELAY32_GetEntryPoint(Module,pe_name->Name,pe_name->Hint);
-	if(*thunk_list == 0)
-#endif
-	  	*thunk_list = WIN32_GetProcAddress(MODULE_FindModule(Module),
-				pe_name->Name);
+        *thunk_list = WIN32_GetProcAddress(MODULE_FindModule(Module),
+                                           pe_name->Name);
 #else
         fprintf(stderr,"JBP: Call to RELAY32_GetEntryPoint being ignored.\n");
 #endif
@@ -619,7 +608,7 @@
 	pModule->res_table=pModule->import_table=pModule->entry_table=
 		(int)pStr-(int)pModule;
 
-        MODULE_RegisterModule(hModule);
+        MODULE_RegisterModule( pModule );
 
 	pe = PE_LoadImage( fd, hModule, mz_header.ne_offset );
 
@@ -656,7 +645,6 @@
     int fs;
     HMODULE hModule;
     NE_MODULE *pModule;
-    struct pe_data *pe;
 
     dprintf_win32(stddeb,"Going to start Win32 program\n");	
     InitTask(context);
diff --git a/loader/pe_resource.c b/loader/pe_resource.c
index b0d6203..da19a65 100644
--- a/loader/pe_resource.c
+++ b/loader/pe_resource.c
@@ -18,7 +18,6 @@
 #include "ldt.h"
 #include "neexe.h"
 #include "peexe.h"
-#include "dlls.h"
 #include "pe_image.h"
 #include "resource.h"
 #include "stddebug.h"
diff --git a/loader/resource.c b/loader/resource.c
index b6a4549..5c5ec93 100644
--- a/loader/resource.c
+++ b/loader/resource.c
@@ -18,7 +18,6 @@
 #include "global.h"
 #include "neexe.h"
 #include "accel.h"
-#include "dlls.h"
 #include "module.h"
 #include "resource.h"
 #include "stddebug.h"
diff --git a/loader/task.c b/loader/task.c
index 7ddac31..bab6794 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -34,8 +34,7 @@
 #define STACK32_SIZE 0x10000
 
 extern void TIMER_SwitchQueue(HQUEUE, HQUEUE );
-extern void TIMER_NukeTimers(HWND, HQUEUE );
-
+extern void USER_AppExit(HTASK, HINSTANCE, HQUEUE );
 /* ------ Internal variables ------ */
 
 static HTASK hFirstTask = 0;
@@ -71,6 +70,18 @@
 
 
 /***********************************************************************
+ *	     TASK_GetNextTask
+ */
+HTASK TASK_GetNextTask( HTASK hTask )
+{
+    TDB* pTask = (TDB*)GlobalLock(hTask);
+
+    if (pTask->hNext) return pTask->hNext;
+    return (hFirstTask != hTask) ? hFirstTask : 0; 
+}
+
+
+/***********************************************************************
  *           TASK_CreateDOSEnvironment
  *
  * Create the original DOS environment.
@@ -526,8 +537,8 @@
     frame16->saved_sp = 0; /*pTask->sp;*/
     frame16->ds = frame16->es = pTask->hInstance;
     frame16->entry_point = 0;
-    frame16->ordinal_number = 24;  /* WINPROCS.24 is TASK_Reschedule */
-    frame16->dll_id = 24; /* WINPROCS */
+    frame16->entry_ip = OFFSETOF(TASK_RescheduleProc) + 14;
+    frame16->entry_cs = SELECTOROF(TASK_RescheduleProc);
     frame16->bp = 0;
     frame16->ip = LOWORD( CALLTO16_RetAddr_word );
     frame16->cs = HIWORD( CALLTO16_RetAddr_word );
@@ -583,14 +594,6 @@
 
     FILE_CloseAllFiles( pTask->hPDB );
 
-    /* Nuke timers */
-
-    TIMER_NukeTimers( 0, pTask->hQueue );
-
-    /* Free the message queue */
-
-    QUEUE_DeleteMsgQueue( pTask->hQueue );
-
     /* Free the selector aliases */
 
     GLOBAL_FreeBlock( pTask->hCSAlias );
@@ -619,6 +622,12 @@
 {
     extern void EXEC_ExitWindows( int retCode );
 
+    TDB* pTask = (TDB*) GlobalLock( hCurrentTask );
+
+    /* Perform USER cleanup */
+
+    USER_AppExit( hCurrentTask, pTask->hInstance, pTask->hQueue );
+
     if (hTaskToKill && (hTaskToKill != hCurrentTask))
     {
         /* If another task is already marked for destruction, */
diff --git a/memory/atom.c b/memory/atom.c
index fe807cd..9676a54 100644
--- a/memory/atom.c
+++ b/memory/atom.c
@@ -11,6 +11,8 @@
  * have to be changed.
  */
 
+#ifndef WINELIB
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -39,9 +41,6 @@
 #define GET_ATOM_TABLE(sel)  ((ATOMTABLE*)PTR_SEG_OFF_TO_LIN(sel, \
           ((INSTANCEDATA*)PTR_SEG_OFF_TO_LIN(sel,0))->atomtable))
 		
-#ifdef WINELIB
-#define USER_HeapSel	0
-#endif
 
 /***********************************************************************
  *           ATOM_InitTable
@@ -375,3 +374,5 @@
 #endif
     return ATOM_GetAtomName( USER_HeapSel, atom, buffer, count );
 }
+
+#endif  /* WINELIB */
diff --git a/memory/global.c b/memory/global.c
index 98d7bd0..54dcd07 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -4,6 +4,8 @@
  * Copyright 1995 Alexandre Julliard
  */
 
+#ifndef WINELIB
+
 #include <sys/types.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -11,6 +13,7 @@
 
 #include "windows.h"
 #include "global.h"
+#include "heap.h"
 #include "toolhelp.h"
 #include "selectors.h"
 #include "dde_mem.h"
@@ -199,7 +202,7 @@
     else 
 #endif  /* CONFIG_IPC */
     {
-	ptr = malloc( size );
+	ptr = HeapAlloc( SystemHeap, 0, size );
     }
     if (!ptr) return 0;
 
@@ -209,7 +212,7 @@
 				isCode, is32Bit, isReadOnly, &shmdata);
     if (!handle)
     {
-        free( ptr );
+        HeapFree( SystemHeap, 0, ptr );
         return 0;
     }
 
@@ -306,7 +309,7 @@
         if (!(pArena->flags & GA_MOVEABLE) ||
             !(pArena->flags & GA_DISCARDABLE) ||
             (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
-        free( (void *)pArena->base );
+        HeapFree( SystemHeap, 0, (void *)pArena->base );
         pArena->base = 0;
         /* Note: we rely on the fact that SELECTOR_ReallocBlock won't */
         /* change the selector if we are shrinking the block */
@@ -337,7 +340,7 @@
     dprintf_global(stddeb,"oldsize %08lx\n",oldsize);
     if (ptr && (size == oldsize)) return handle;  /* Nothing to do */
 
-    ptr = realloc( ptr, size );
+    ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
     if (!ptr)
     {
         FreeSelector( sel );
@@ -350,7 +353,7 @@
     sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
     if (!sel)
     {
-        free( ptr );
+        HeapFree( SystemHeap, 0, ptr );
         memset( pArena, 0, sizeof(GLOBALARENA) );
         return 0;
     }
@@ -358,7 +361,7 @@
 
     if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
     {
-        free( ptr );
+        HeapFree( SystemHeap, 0, ptr );
         FreeSelector( sel );
         return 0;
     }
@@ -392,7 +395,7 @@
 #ifdef CONFIG_IPC
     if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
 #endif  /* CONFIG_IPC */
-    if (ptr) free( ptr );
+    if (ptr) HeapFree( SystemHeap, 0, ptr );
     return 0;
 }
 
@@ -825,3 +828,13 @@
     dprintf_global(stddeb,"GlobalAlloc32(%x,%x)\n",flags,size);
     return malloc(size);
 }
+
+/***********************************************************************
+ *               GlobalLock32
+ */
+void* GlobalLock32(DWORD ptr)
+{
+	return (void*)ptr;
+}
+
+#endif  /* WINELIB */
diff --git a/memory/heap.c b/memory/heap.c
index 945c844..77fded0 100644
--- a/memory/heap.c
+++ b/memory/heap.c
@@ -179,7 +179,7 @@
     HEAP *heapPtr = (HEAP *)heap;
     if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
     {
-        fprintf( stderr, "Invalid heap %08lx!\n", heap );
+        fprintf( stderr, "Invalid heap %08x!\n", heap );
         SetLastError( ERROR_INVALID_HANDLE );
         return NULL;
     }
@@ -740,7 +740,7 @@
     HEAP *heapPtr = HEAP_GetPtr( heap );
     SUBHEAP *subheap;
 
-    dprintf_heap( stddeb, "HeapDestroy: %08lx\n", heap );
+    dprintf_heap( stddeb, "HeapDestroy: %08x\n", heap );
     if (!heapPtr) return FALSE;
 
     DeleteCriticalSection( &heapPtr->critSection );
@@ -779,7 +779,7 @@
 
     if (!(pArena = HEAP_FindFreeBlock( heapPtr, size, &subheap )))
     {
-        dprintf_heap( stddeb, "HeapAlloc(%08lx,%08lx,%08lx): returning NULL\n",
+        dprintf_heap( stddeb, "HeapAlloc(%08x,%08lx,%08lx): returning NULL\n",
                   heap, flags, size  );
         if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
         SetLastError( ERROR_OUTOFMEMORY );
@@ -810,7 +810,7 @@
     if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
     SetLastError( 0 );
 
-    dprintf_heap( stddeb, "HeapAlloc(%08lx,%08lx,%08lx): returning %08lx\n",
+    dprintf_heap( stddeb, "HeapAlloc(%08x,%08lx,%08lx): returning %08lx\n",
                   heap, flags, size, (DWORD)(pInUse + 1) );
     return (LPVOID)(pInUse + 1);
 }
@@ -835,7 +835,7 @@
     {
         if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
         SetLastError( ERROR_INVALID_PARAMETER );
-        dprintf_heap( stddeb, "HeapFree(%08lx,%08lx,%08lx): returning FALSE\n",
+        dprintf_heap( stddeb, "HeapFree(%08x,%08lx,%08lx): returning FALSE\n",
                       heap, flags, (DWORD)ptr );
         return FALSE;
     }
@@ -849,7 +849,7 @@
     if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
     SetLastError( 0 );
 
-    dprintf_heap( stddeb, "HeapFree(%08lx,%08lx,%08lx): returning TRUE\n",
+    dprintf_heap( stddeb, "HeapFree(%08x,%08lx,%08lx): returning TRUE\n",
                   heap, flags, (DWORD)ptr );
     return TRUE;
 }
@@ -881,7 +881,7 @@
     {
         if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
         SetLastError( ERROR_INVALID_PARAMETER );
-        dprintf_heap( stddeb, "HeapReAlloc(%08lx,%08lx,%08lx,%08lx): returning NULL\n",
+        dprintf_heap( stddeb, "HeapReAlloc(%08x,%08lx,%08lx,%08lx): returning NULL\n",
                       heap, flags, (DWORD)ptr, size );
         return NULL;
     }
@@ -904,6 +904,13 @@
             pFree->next->prev = pFree->prev;
             pFree->prev->next = pFree->next;
             pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree);
+            if (!HEAP_Commit( subheap, (char *)pArena + sizeof(ARENA_INUSE)
+                                               + size + HEAP_MIN_BLOCK_SIZE))
+            {
+                if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
+                SetLastError( ERROR_OUTOFMEMORY );
+                return NULL;
+            }
         }
         else  /* Do it the hard way */
         {
@@ -915,6 +922,7 @@
                 !(pNew = HEAP_FindFreeBlock( heapPtr, size, &newsubheap )))
             {
                 if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
+                SetLastError( ERROR_OUTOFMEMORY );
                 return NULL;
             }
 
@@ -959,7 +967,7 @@
     pArena->callerEIP = *((DWORD *)&heap - 1);  /* hack hack */
     if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
 
-    dprintf_heap( stddeb, "HeapReAlloc(%08lx,%08lx,%08lx,%08lx): returning %08lx\n",
+    dprintf_heap( stddeb, "HeapReAlloc(%08x,%08lx,%08lx,%08lx): returning %08lx\n",
                   heap, flags, (DWORD)ptr, size, (DWORD)(pArena + 1) );
     return (LPVOID)(pArena + 1);
 }
@@ -1024,7 +1032,7 @@
     }
     if (!(flags & HEAP_NO_SERIALIZE)) HeapUnlock( heap );
 
-    dprintf_heap( stddeb, "HeapSize(%08lx,%08lx,%08lx): returning %08lx\n",
+    dprintf_heap( stddeb, "HeapSize(%08x,%08lx,%08lx): returning %08lx\n",
                   heap, flags, (DWORD)ptr, ret );
     return ret;
 }
@@ -1040,7 +1048,7 @@
 
     if (!heapPtr || (heapPtr->magic != HEAP_MAGIC))
     {
-        fprintf( stderr, "Invalid heap %08lx!\n", heap );
+        fprintf( stderr, "Invalid heap %08x!\n", heap );
         return FALSE;
     }
 
diff --git a/memory/ldt.c b/memory/ldt.c
index e5267d7..87323db 100644
--- a/memory/ldt.c
+++ b/memory/ldt.c
@@ -202,6 +202,7 @@
  *
  * Print the content of the LDT on stdout.
  */
+#ifndef WINELIB
 void LDT_Print( int start, int length )
 {
     int i;
@@ -231,3 +232,4 @@
                 flags[0], flags[1], flags[2] );
     }
 }
+#endif  /* WINELIB */
diff --git a/memory/local.c b/memory/local.c
index b4aba40..ff9ae25 100644
--- a/memory/local.c
+++ b/memory/local.c
@@ -11,6 +11,8 @@
  * parameter than usual.
  */
 
+#ifndef WINELIB
+
 #include <stdlib.h>
 #include <string.h>
 #include "windows.h"
@@ -1029,8 +1031,15 @@
 {
     WORD arena, total;
     LOCALARENA *pArena;
+    LOCALHEAPINFO *pInfo;
     char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
-    LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
+
+    if (!(pInfo = LOCAL_GetHeap( ds )))
+    {
+        fprintf( stderr, "LOCAL_Handle(%04x): Local heap not found\n", ds );
+	LOCAL_PrintHeap( ds );
+	return 0;
+    }
 
     total = 0;
     arena = pInfo->first;
@@ -1309,3 +1318,5 @@
     pLocalEntry->wSize     = pLocalEntry->wNext - pLocalEntry->hHandle;
     return TRUE;
 }
+
+#endif  /* WINELIB */
diff --git a/memory/selector.c b/memory/selector.c
index b3b117f..6eef187 100644
--- a/memory/selector.c
+++ b/memory/selector.c
@@ -4,6 +4,8 @@
  * Copyright 1995 Alexandre Julliard
  */
 
+#ifndef WINELIB
+
 #include <string.h>
 #include "windows.h"
 #include "ldt.h"
@@ -64,13 +66,14 @@
  */
 WORD FreeSelector( WORD sel )
 {
-    WORD i, count;
+    WORD i, count, nextsel;
     ldt_entry entry;
     STACK16FRAME *frame;
 
     dprintf_selector( stddeb, "FreeSelector(%04x)\n", sel );
     if (IS_SELECTOR_FREE(sel)) return sel;  /* error */
     count = (GET_SEL_LIMIT(sel) >> 16) + 1;
+    nextsel = sel + (count << __AHSHIFT);
     memset( &entry, 0, sizeof(entry) );  /* clear the LDT entries */
     /* FIXME: is it correct to free the whole array? */
     for (i = SELECTOR_TO_ENTRY(sel); count; i++, count--)
@@ -84,8 +87,8 @@
     frame = CURRENT_STACK16;
     while (frame)
     {
-        if (frame->ds == sel) frame->ds = 0;
-        if (frame->es == sel) frame->es = 0;
+        if ((frame->ds >= sel) && (frame->ds < nextsel)) frame->ds = 0;
+        if ((frame->es >= sel) && (frame->es < nextsel)) frame->es = 0;
 	frame = PTR_SEG_OFF_TO_LIN(frame->saved_ss, frame->saved_sp);
     }
 #endif
@@ -481,3 +484,5 @@
     return ((entry << 16) | ((unsigned) ptr & 0xffff));
 }
 #endif
+
+#endif  /* WINELIB */
diff --git a/misc/Makefile.in b/misc/Makefile.in
index 5e7701f..b2030ee 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -28,6 +28,7 @@
 	stress.c \
 	toolhelp.c \
 	user.c \
+	ver.c \
 	w32sys.c \
 	winsocket.c \
 	xmalloc.c
diff --git a/misc/driver.c b/misc/driver.c
index 30567fa..7f9f951 100644
--- a/misc/driver.c
+++ b/misc/driver.c
@@ -9,7 +9,6 @@
 #include "windows.h"
 #include "win.h"
 #include "user.h"
-#include "dlls.h"
 #include "driver.h"
 #include "stddebug.h"
 #include "debug.h"
diff --git a/misc/exec.c b/misc/exec.c
index e66f09f..085bb86 100644
--- a/misc/exec.c
+++ b/misc/exec.c
@@ -8,7 +8,6 @@
 #include <string.h>
 #include <unistd.h>
 #include "neexe.h"
-#include "dlls.h"
 #include "shell.h"
 #include "windows.h"
 #include "callback.h"
diff --git a/misc/lstr.c b/misc/lstr.c
index 5bc9032..b806061 100644
--- a/misc/lstr.c
+++ b/misc/lstr.c
@@ -125,6 +125,14 @@
 /* KERNEL.90 */
 INT lstrlen(LPCSTR str)
 {
+  /* looks weird, but win3.1 KERNEL got a GeneralProtection handler
+   * in lstrlen() ... we check only for NULL pointer reference.
+   * - Marcus Meissner
+   */
+  if (str==NULL) {
+  	fprintf(stddeb,"lstrlen(NULL) caught, returning 0.\n");
+  	return 0;
+  }
   return strlen(str);
 }
 
diff --git a/misc/main.c b/misc/main.c
index 3dcd171..2cb0af4 100644
--- a/misc/main.c
+++ b/misc/main.c
@@ -19,13 +19,13 @@
 #include <X11/cursorfont.h>
 #include "wine.h"
 #include "message.h"
+#include "module.h"
 #include "msdos.h"
 #include "windows.h"
 #include "winsock.h"
 #include "options.h"
 #include "desktop.h"
 #include "shell.h"
-#include "dlls.h"
 #define DEBUG_DEFINE_VARIABLES
 #include "stddebug.h"
 #include "debug.h"
@@ -65,6 +65,7 @@
     "Cz",  /* LANG_Cz */
     "Eo",  /* LANG_Eo */
     "It",  /* LANG_It */
+    "Ko",  /* LANG_Ko */
     NULL
 };
 
@@ -147,7 +148,7 @@
   "    -fixedmap       Use a \"standard\" color map\n" \
   "    -iconic         Start as an icon\n" \
   "    -ipc            Enable IPC facilities\n" \
-  "    -language xx    Set the language (one of En,Es,De,No,Fr,Fi,Da,Cz,Eo,It)\n" \
+  "    -language xx    Set the language (one of En,Es,De,No,Fr,Fi,Da,Cz,Eo,It,Ko)\n" \
   "    -managed        Allow the window manager to manage created windows\n" \
   "    -mode mode      Start Wine in a particular mode (standard or enhanced)\n" \
   "    -name name      Set the application name\n" \
@@ -265,48 +266,6 @@
 
 #endif
 
-#ifndef WINELIB
-/***********************************************************************
- *           MAIN_ParseDLLOptions
- *
- * Set runtime DLL usage flags
- */
-static BOOL MAIN_ParseDLLOptions(char *options)
-{
-    int l;
-    BUILTIN_DLL *dll;
-
-    if (strlen(options)<3) return FALSE;
-    do
-    {
-        if ((*options!='+') && (*options!='-')) return FALSE;
-        if (strchr(options,',')) l=strchr(options,',')-options;
-        else l=strlen(options);
-        for (dll = dll_builtin_table; dll->name; dll++)
-        {
-            if (!lstrncmpi(options+1,dll->name,l-1))
-            {
-                if (*options == '+') dll->flags &= ~DLL_FLAG_NOT_USED;
-                else
-                {
-                    if (dll->flags & DLL_FLAG_ALWAYS_USED) return FALSE;
-                    dll->flags |= DLL_FLAG_NOT_USED;
-                }
-                break;
-            }
-        }
-        if (!dll->name) return FALSE;
-        options+=l;
-    }
-    while((*options==',')&&(*(++options)));
-    if (*options)
-        return FALSE;
-    else
-        return TRUE;
-}
-#endif
-
-
 
 /***********************************************************************
  *           MAIN_ParseLanguageOption
@@ -441,23 +400,20 @@
       }
 
       if(MAIN_GetResource( db, ".dll", &value))
+      {
 #ifndef WINELIB
-       if(MAIN_ParseDLLOptions((char*)value.addr)==FALSE)
-       {
-         int i;
-         BUILTIN_DLL *dll;
-         fprintf(stderr,"%s: Syntax: -dll +xxx,... or -dll -xxx,...\n",argv[0]);
-         fprintf(stderr,"Example: -dll -ole2    Do not use emulated OLE2.DLL\n");
-         fprintf(stderr,"Available DLLs\n");
-         for (i = 0, dll = dll_builtin_table; dll->name; dll++)
-             if (!(dll->flags & DLL_FLAG_ALWAYS_USED))
-                 fprintf(stderr,"%-9s%c",dll->name, (((++i)%8==0)?'\n':' '));
-         fprintf(stderr,"\n\n");
-         exit(1);
-       }
+          if (!BUILTIN_ParseDLLOptions( (char*)value.addr ))
+          {
+              fprintf(stderr,"%s: Syntax: -dll +xxx,... or -dll -xxx,...\n",argv[0]);
+              fprintf(stderr,"Example: -dll -ole2    Do not use emulated OLE2.DLL\n");
+              fprintf(stderr,"Available DLLs:\n");
+              BUILTIN_PrintDLLs();
+              exit(1);
+          }
 #else
-		fprintf(stderr,"-dll not supported in libwine\n");
+          fprintf(stderr,"-dll not supported in libwine\n");
 #endif
+      }
 }
 
 
diff --git a/misc/ole2nls.c b/misc/ole2nls.c
index fc93301..72e5bee 100644
--- a/misc/ole2nls.c
+++ b/misc/ole2nls.c
@@ -33,6 +33,7 @@
     case LANG_Cz:
     case LANG_Eo:
     case LANG_It:
+    case LANG_Ko:
     default:
 	return 0;  /* Neutral language */
     }
@@ -699,3 +700,10 @@
 	return (l1<l2)? 1 : 3;
 }
 
+/***********************************************************************
+ *           SetLocalInfoA       (KERNEL32.499)
+ */
+BOOL SetLocaleInfoA(DWORD lcid, DWORD lctype, LPCSTR data) {
+	fprintf(stdnimp,"SetLocaleInfoA(%ld,%ld,%s)\n",lcid,lctype,data);
+	return TRUE;
+}
diff --git a/misc/registry.c b/misc/registry.c
index 7e72b71..182f471 100644
--- a/misc/registry.c
+++ b/misc/registry.c
@@ -368,11 +368,10 @@
 		strcat(fn,WINE_PREFIX);
 		/* create the directory. don't care about errorcodes. */
 		mkdir(fn,0755); /* drwxr-xr-x */
-		strcat(fn,"/");
-		strcat(fn,SAVE_CURRENT_USER);
+		strcat(fn,"/"SAVE_CURRENT_USER);
 		_SaveSubReg(key_current_user,fn);
 		free(fn);
-		fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+1);
+		fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
 		strcpy(fn,pwd->pw_dir);
 		strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
 		_SaveSubReg(key_local_machine,fn);
@@ -676,6 +675,7 @@
 	if (!_do_loadsubreg(F,lpkey)) {
 		fclose(F);
 		unlink(fn);
+		return;
 	}
 	fclose(F);
 }
@@ -694,12 +694,12 @@
 	/* load the user saved registry. overwriting only newer entries */
 	pwd=getpwuid(getuid());
 	if (pwd!=NULL && pwd->pw_dir!=NULL) {
-		fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+1);
+		fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_CURRENT_USER)+2);
 		strcpy(fn,pwd->pw_dir);
 		strcat(fn,WINE_PREFIX"/"SAVE_CURRENT_USER);
 		_LoadSubReg(key_current_user,fn);
 		free(fn);
-		fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+1);
+		fn=(char*)xmalloc(strlen(pwd->pw_dir)+strlen(WINE_PREFIX)+strlen(SAVE_LOCAL_MACHINE)+2);
 		strcpy(fn,pwd->pw_dir);
 		strcat(fn,WINE_PREFIX"/"SAVE_LOCAL_MACHINE);
 		_LoadSubReg(key_local_machine,fn);
@@ -1710,7 +1710,7 @@
 	lpkey = lookup_hkey(hkey);
 	if (!lpkey)
 		return SHELL_ERROR_BADKEY;
-	if (lpkey->nrofvalues<iValue)
+	if (lpkey->nrofvalues<=iValue)
 		return ERROR_NO_MORE_ITEMS;
 	val	= lpkey->values+iValue;
 
diff --git a/misc/shell.c b/misc/shell.c
index c209531..66fd258 100644
--- a/misc/shell.c
+++ b/misc/shell.c
@@ -7,6 +7,7 @@
 #include <unistd.h>
 #include <ctype.h>
 #include "windows.h"
+#include "file.h"
 #include "shell.h"
 #include "module.h"
 #include "neexe.h"
@@ -17,17 +18,19 @@
 #include "debug.h"
 #include "xmalloc.h"
 
+extern HANDLE 	CURSORICON_LoadHandler( HANDLE, HINSTANCE, BOOL);
+extern WORD 	GetIconID( HANDLE hResource, DWORD resType );
+
 /*************************************************************************
  *				DragAcceptFiles		[SHELL.9]
  */
 void DragAcceptFiles(HWND hWnd, BOOL b)
 {
-    /* flips WS_EX_ACCEPTFILES bit according to the value of b */
-    dprintf_reg(stddeb,"DragAcceptFiles(%04x, %u) old exStyle %08lx\n",
-		hWnd,b,GetWindowLong(hWnd,GWL_EXSTYLE));
+    WND* wnd = WIN_FindWndPtr(hWnd);
 
-    SetWindowLong(hWnd,GWL_EXSTYLE,
-		  GetWindowLong(hWnd,GWL_EXSTYLE) | b*(LONG)WS_EX_ACCEPTFILES);
+    if( wnd )
+	wnd->dwExStyle = b? wnd->dwExStyle | WS_EX_ACCEPTFILES
+			  : wnd->dwExStyle & ~WS_EX_ACCEPTFILES;
 }
 
 
@@ -111,15 +114,20 @@
     char *p,*x;
     long len;
     char subclass[200];
+
     /* OK. We are supposed to lookup the program associated with lpFile,
      * then to execute it using that program. If lpFile is a program,
      * we have to pass the parameters. If an instance is already running,
      * we might have to send DDE commands.
+     *
+     * FIXME: Should also look up WIN.INI [Extensions] section?
      */
+
     dprintf_exec(stddeb, "ShellExecute(%04x,'%s','%s','%s','%s',%x)\n",
 		hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
 		lpParameters ? lpParameters : "<null>", 
 		lpDirectory ? lpDirectory : "<null>", iShowCmd);
+
     if (lpFile==NULL) return 0; /* should not happen */
     if (lpOperation==NULL) /* default is open */
       lpOperation="open";
@@ -188,8 +196,10 @@
  */
 HINSTANCE FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
 {
-	fprintf(stdnimp, "FindExecutable : Empty Stub !!!\n");
-        return 0;
+	fprintf(stdnimp, "FindExecutable: someone has to fix me and this is YOUR turn! :-)\n");
+
+	lpResult[0]='\0';
+        return 31;		/* no association */
 }
 
 static char AppName[128], AppMisc[906];
@@ -253,48 +263,305 @@
 }
 
 /*************************************************************************
- *				ExtractIcon		[SHELL.34]
+ *				SHELL_GetResourceTable
+ *
+ * FIXME: Implement GetPEResourceTable in w32sys.c and call it here.
  */
-HICON ExtractIcon(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT nIconIndex)
+BYTE* SHELL_GetResourceTable(HFILE hFile)
 {
-	HICON	hIcon = 0;
-	HINSTANCE hInst2 = hInst;
-	dprintf_reg(stddeb, "ExtractIcon(%04x, '%s', %d\n", 
-			hInst, lpszExeFileName, nIconIndex);
-        return 0;
-	if (lpszExeFileName != NULL) {
-		hInst2 = LoadModule(lpszExeFileName,(LPVOID)-1);
-	}
-	if (hInst2 != 0 && nIconIndex == (UINT)-1) {
-#if 0
-		count = GetRsrcCount(hInst2, NE_RSCTYPE_GROUP_ICON);
-		dprintf_reg(stddeb, "ExtractIcon // '%s' has %d icons !\n", lpszExeFileName, count);
-		return (HICON)count;
-#endif
-	}
-	if (hInst2 != hInst && hInst2 != 0) {
-		FreeLibrary(hInst2);
-	}
-	return hIcon;
+  struct mz_header_s mz_header;
+  struct ne_header_s ne_header;
+  int		size;
+  
+  _llseek( hFile, 0, SEEK_SET );
+  if ((FILE_Read(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
+      (mz_header.mz_magic != MZ_SIGNATURE)) return (BYTE*)-1;
+
+  _llseek( hFile, mz_header.ne_offset, SEEK_SET );
+  if (FILE_Read( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
+      return NULL;
+
+  if (ne_header.ne_magic == PE_SIGNATURE) 
+     { fprintf(stdnimp,"Win32 FIXME: file %s line %i\n", __FILE__, __LINE__ );
+       return NULL; }
+
+  if (ne_header.ne_magic != NE_SIGNATURE) return NULL;
+
+  size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
+
+  if( size > sizeof(NE_TYPEINFO) )
+    {
+      BYTE* pTypeInfo = (BYTE*)xmalloc(size);
+
+      if( !pTypeInfo ) return NULL;
+
+      _llseek(hFile, mz_header.ne_offset+ne_header.resource_tab_offset, SEEK_SET);
+      if( FILE_Read( hFile, (char*)pTypeInfo, size) != size )
+	{ free(pTypeInfo); return NULL; }
+      return pTypeInfo;
+    }
+  /* no resources */
+
+  return NULL;
 }
 
+/*************************************************************************
+ *			SHELL_LoadResource
+ */
+HANDLE	SHELL_LoadResource(HINSTANCE hInst, HFILE hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
+{
+ BYTE*	ptr;
+ HANDLE handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
+
+ if( (ptr = (BYTE*)GlobalLock( handle )) )
+   {
+    _llseek( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
+     FILE_Read( hFile, (char*)ptr, pNInfo->length << sizeShift);
+     return handle;
+   }
+ return (HANDLE)0;
+}
+
+/*************************************************************************
+ *			InternalExtractIcon		[SHELL.39]
+ *
+ * This abortion is called directly by Progman
+ */
+HICON InternalExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, UINT nIconIndex, WORD n )
+{
+  HANDLE 	hRet = 0;
+  HICON*	RetPtr = NULL;
+  BYTE*  	pData;
+  OFSTRUCT 	ofs;
+  HFILE 	hFile = OpenFile( lpszExeFileName, &ofs, OF_READ );
+  
+  dprintf_reg(stddeb, "InternalExtractIcon(%04x, file '%s', start from %d, extract %d\n", 
+		       hInstance, lpszExeFileName, nIconIndex, n);
+
+  if( hFile == HFILE_ERROR || !n ) return 0;
+
+  hRet = GlobalAlloc( GMEM_MOVEABLE, sizeof(HICON)*n);
+  RetPtr = (HICON*)GlobalLock(hRet);
+
+ *RetPtr = (n == 0xFFFF)? 0: 1;				/* error return values */
+
+  pData = SHELL_GetResourceTable(hFile);
+  if( pData ) 
+    if( pData == (BYTE*)-1 )
+      {
+	/* FIXME: possible .ICO file */
+
+	fprintf(stddeb,"InternalExtractIcon: cannot handle file %s\n", lpszExeFileName);
+      }
+    else						/* got resource table */
+      {
+	UINT	     iconDirCount = 0;
+	UINT	     iconCount = 0;
+	NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
+	NE_NAMEINFO* pIconStorage = NULL;
+	NE_NAMEINFO* pIconDir = NULL;
+
+	/* find icon directory and icon repository */
+
+        while( pTInfo->type_id && !(pIconStorage && pIconDir) )
+	  {
+	   if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON ) 
+	       {
+		 iconDirCount = pTInfo->count;
+	         pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
+		 dprintf_reg(stddeb,"\tfound directory - %i icon families\n", iconDirCount);
+	       }
+	   if( pTInfo->type_id == NE_RSCTYPE_ICON ) 
+	       { 
+		 iconCount = pTInfo->count;
+		 pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
+		 dprintf_reg(stddeb,"\ttotal icons - %i\n", iconCount);
+	       }
+  	   pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
+          }
+
+	/* load resources and create icons */
+
+        if( pIconStorage && pIconDir )
+
+            if( nIconIndex == (UINT)-1 ) RetPtr[0] = iconDirCount;
+	    else if( nIconIndex < iconDirCount )
+	      {
+		  HANDLE hIcon;
+		  UINT   i, icon;
+
+		  if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
+
+		  for( i = nIconIndex; i < nIconIndex + n; i++ ) 
+		     {
+		       hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + (i - nIconIndex), 
+										 *(WORD*)pData );
+		       RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
+		       GlobalFree(hIcon); 
+		     }
+
+		  for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
+		     {
+		       hIcon = 0;
+		       for( i = 0; i < iconCount; i++ )
+			  if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
+			      hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,
+									     *(WORD*)pData );
+	               RetPtr[icon-nIconIndex] = (hIcon)?CURSORICON_LoadHandler( hIcon, hInstance, FALSE ):0;
+		     }
+	      }
+	free(pData);
+      }
+
+ _lclose( hFile );
+ 
+  /* return array with icon handles */
+
+  return hRet;
+}
+
+/*************************************************************************
+ *				ExtractIcon 		[SHELL.34]
+ */
+HICON ExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, WORD nIconIndex)
+{
+  HANDLE handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
+
+  if( handle )
+    {
+      HICON* ptr = (HICON*)GlobalLock(handle);
+      HICON  hIcon = *ptr;
+
+      GlobalFree(handle);
+      return hIcon;
+    }
+  return 0;
+}
 
 /*************************************************************************
  *				ExtractAssociatedIcon	[SHELL.36]
  */
 HICON ExtractAssociatedIcon(HINSTANCE hInst,LPSTR lpIconPath, LPWORD lpiIcon)
 {
-    dprintf_reg(stdnimp, "ExtractAssociatedIcon : Empty Stub !!!\n");
-    return 0;
+    HICON hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
+
+    /* MAKEINTRESOURCE(2) seems to be "default" icon according to Progman 
+     *
+     * For data files it probably should call FindExecutable and load
+     * icon from there. As of now FindExecutable is empty stub.
+     */
+
+    if( hIcon < 2 ) hIcon = LoadIcon( hInst, MAKEINTRESOURCE(2));
+
+    return hIcon;
 }
 
 /*************************************************************************
- *              DoEnvironmentSubst      [SHELL.37]
+ *				FindEnvironmentString	[SHELL.38]
+ *
+ * Returns a pointer into the DOS environment... Ugh.
  */
-DWORD DoEnvironmentSubst(LPSTR str,WORD len)
+LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
 {
-    dprintf_reg(stdnimp, "DoEnvironmentSubst(%s,%x): Empty Stub !!!\n",str,len);
-    return 0;
+  UINT 	l = strlen(entry); 
+  for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
+     {
+       if( strncasecmp(lpEnv, entry, l) ) continue;
+       
+       if( !*(lpEnv+l) )
+         return (lpEnv + l); 		/* empty entry */
+       else if ( *(lpEnv+l)== '=' )
+	 return (lpEnv + l + 1);
+     }
+  return NULL;
+}
+
+SEGPTR FindEnvironmentString(LPSTR str)
+{
+ SEGPTR  spEnv = GetDOSEnvironment();
+ LPSTR  lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
+ 
+ LPSTR  lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL; 
+
+ if( lpString )		/*  offset should be small enough */
+     return spEnv + (lpString - lpEnv);
+
+ return (SEGPTR)NULL;
+}
+
+/*************************************************************************
+ *              		DoEnvironmentSubst      [SHELL.37]
+ *
+ * Replace %KEYWORD% in the str with the value of variable KEYWORD
+ * from "DOS" environment.
+ */
+DWORD DoEnvironmentSubst(LPSTR str,WORD length)
+{
+  LPSTR   lpEnv = (LPSTR)PTR_SEG_TO_LIN(GetDOSEnvironment());
+  LPSTR   lpBuffer = (LPSTR)xmalloc(length);
+  LPSTR   lpstr = str;
+  LPSTR   lpbstr = lpBuffer;
+
+  AnsiToOem(str,str);
+
+  dprintf_reg(stddeb,"DoEnvSubst: accept %s", str);
+
+  while( *lpstr && lpbstr - lpBuffer < length )
+   {
+     LPSTR lpend = lpstr;
+
+     if( *lpstr == '%' )
+       {
+	  do { lpend++; } while( *lpend && *lpend != '%' );
+	  if( *lpend == '%' && lpend - lpstr > 1 )	/* found key */
+	    {
+	       LPSTR lpKey;
+	      *lpend = '\0';  
+	       lpKey = SHELL_FindString(lpEnv, lpstr+1);
+	       if( lpKey )				/* found key value */
+		 {
+		   int l = strlen(lpKey);
+
+		   if( l > length - (lpbstr - lpBuffer) - 1 )
+		     {
+		       fprintf(stdnimp,"File %s, line %i: Env subst aborted - string too short\n", 
+					__FILE__, __LINE__);
+		      *lpend = '%';
+		       break;
+		     }
+		   strcpy(lpbstr, lpKey);
+		   lpbstr += l;
+		 }
+	       else break;
+	      *lpend = '%';
+	       lpstr = lpend + 1;
+	    }
+	  else break;					/* back off and whine */
+
+	  continue;
+       } 
+
+     *lpbstr++ = *lpstr++;
+   }
+
+ *lpbstr = '\0';
+  if( lpstr - str == strlen(str) )
+    {
+      strncpy(str, lpBuffer, length);
+      length = 1;
+    }
+  else
+      length = 0;
+
+  dprintf_reg(stddeb," return %s\n", str);
+
+  OemToAnsi(str,str);
+  free(lpBuffer);
+
+  /*  Return str length in the LOWORD
+   *  and 1 in HIWORD if subst was successful.
+   */
+ return (DWORD)MAKELONG(strlen(str), length);
 }
 
 /*************************************************************************
diff --git a/misc/user.c b/misc/user.c
index 194da4c..dc8dc8d 100644
--- a/misc/user.c
+++ b/misc/user.c
@@ -2,6 +2,7 @@
  * Misc. USER functions
  *
  * Copyright 1993 Robert J. Amstadt
+ *	     1996 Alex Korobka 
  */
 
 #include <stdio.h>
@@ -9,15 +10,19 @@
 #include "windows.h"
 #include "gdi.h"
 #include "user.h"
+#include "task.h"
+#include "queue.h"
+#include "class.h"
 #include "win.h"
+#include "hook.h"
+#include "debug.h"
 #include "toolhelp.h"
 
-#define USER_HEAP_SIZE          0x10000
-
 #ifndef WINELIB
-LPSTR USER_Heap = NULL;
 WORD USER_HeapSel = 0;
 
+extern void 	TIMER_NukeTimers(HWND, HQUEUE );
+extern HTASK	TASK_GetNextTask(HTASK);
 
 /***********************************************************************
  *           GetFreeSystemResources   (USER.284)
@@ -66,19 +71,7 @@
     return TRUE;
 }
 
-
-/***********************************************************************
- *           USER_HeapInit
- */
-BOOL USER_HeapInit(void)
-{
-    if (!(USER_HeapSel = GlobalAlloc(GMEM_FIXED,USER_HEAP_SIZE))) return FALSE;
-    USER_Heap = GlobalLock( USER_HeapSel );
-    LocalInit( USER_HeapSel, 0, USER_HEAP_SIZE-1 );
-    return TRUE;
-}
-#endif
-
+#endif  /* WINELIB */
 
 /***********************************************************************
  *           TimerCount   (TOOLHELP.80)
@@ -114,3 +107,35 @@
 
     return 1;
 }
+
+/**********************************************************************
+ *					USER_AppExit
+ */
+void USER_AppExit(HTASK hTask, HINSTANCE hInstance, HQUEUE hQueue)
+{
+    /* FIXME: flush send messages (which are not implemented yet),
+     *        empty clipboard if needed, maybe destroy menus (Windows
+     *	      only complains about them but does nothing);
+     */
+
+    WND* desktop = WIN_GetDesktop();
+
+    /* Patch desktop window queue */
+    if( desktop->hmemTaskQ == hQueue )
+	desktop->hmemTaskQ = GetTaskQueue(TASK_GetNextTask(hTask));
+
+    /* Nuke timers */
+
+    TIMER_NukeTimers( 0, hQueue );
+
+    HOOK_FreeQueueHooks( hQueue );
+
+    /* Nuke orphaned windows */
+
+    WIN_DestroyQueueWindows( desktop->child, hQueue );
+
+    /* Free the message queue */
+
+    QUEUE_DeleteMsgQueue( hQueue );
+}
+
diff --git a/misc/ver.c b/misc/ver.c
new file mode 100644
index 0000000..b390fd9
--- /dev/null
+++ b/misc/ver.c
@@ -0,0 +1,523 @@
+/* 
+ * Implementation of VER.DLL
+ * 
+ * Copyright 1996 Marcus Meissner
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "windows.h"
+#include "win.h"
+#include "winerror.h"
+#include "ver.h"
+#include "lzexpand.h"
+#include "module.h"
+#include "neexe.h"
+#include "stackframe.h"	/* MAKE_SEGPTR */
+#include "stddebug.h"
+#include "debug.h"
+#include "xmalloc.h"
+#include "winreg.h"
+
+#define LZREAD(what)	if (sizeof(*what)!=LZRead(lzfd,MAKE_SEGPTR(what),sizeof(*what))) return 0;
+
+int
+read_ne_header(HFILE lzfd,struct ne_header_s *nehd) {
+	struct	mz_header_s	mzh;
+
+	LZSeek(lzfd,0,SEEK_SET);
+	if (sizeof(mzh)!=LZRead(lzfd,MAKE_SEGPTR(&mzh),sizeof(mzh)))
+		return 0;
+	if (mzh.mz_magic!=MZ_SIGNATURE)
+		return 0;
+	LZSeek(lzfd,mzh.ne_offset,SEEK_SET);
+	LZREAD(nehd);
+	if (nehd->ne_magic == NE_SIGNATURE) {
+		LZSeek(lzfd,mzh.ne_offset,SEEK_SET);
+		return 1;
+	}
+	/* must handle PE files too. Later. */
+	return 0;
+}
+
+
+int
+find_ne_resource(
+	HFILE lzfd,struct ne_header_s *nehd,SEGPTR typeid,SEGPTR resid,
+	BYTE **resdata,int *reslen,DWORD *off
+) {
+	NE_TYPEINFO	ti;
+	NE_NAMEINFO	ni;
+	int		i;
+	WORD		shiftcount;
+	DWORD		nehdoffset;
+
+	nehdoffset=LZSeek(lzfd,nehd->resource_tab_offset,SEEK_CUR);
+	LZREAD(&shiftcount);
+	dprintf_resource(stderr,"shiftcount is %d\n",shiftcount);
+	dprintf_resource(stderr,"reading resource typeinfo dir.\n");
+
+	if (!HIWORD(typeid)) typeid = (SEGPTR)((WORD)typeid | 0x8000);
+	if (!HIWORD(resid))  resid  = (SEGPTR)((WORD)resid | 0x8000);
+	while (1) {
+		int	skipflag;
+
+		LZREAD(&ti);
+		if (!ti.type_id)
+			return 0;
+		dprintf_resource(stderr,"    ti.typeid =%04x,count=%d\n",ti.type_id,ti.count);
+		skipflag=0;
+		if (!HIWORD(typeid)) {
+			if ((ti.type_id&0x8000)&&(typeid!=ti.type_id))
+				skipflag=1;
+		} else {
+			if (ti.type_id & 0x8000) {
+				skipflag=1; 
+			} else {
+				BYTE	len;
+				char	*str;
+				DWORD	whereleft;
+
+				whereleft=LZSeek(
+					lzfd,
+					nehdoffset+nehd->resource_tab_offset+ti.type_id,
+					SEEK_SET
+				);
+				LZREAD(&len);
+				str=xmalloc(len);
+				if (len!=LZRead(lzfd,MAKE_SEGPTR(str),len))
+					return 0;
+				dprintf_resource(stderr,"read %s to compare it with %s\n",
+					str,(char*)PTR_SEG_TO_LIN(typeid)
+				);
+				if (lstrcmpi(str,(char*)PTR_SEG_TO_LIN(typeid)))
+					skipflag=1;
+				free(str);
+				LZSeek(lzfd,whereleft,SEEK_SET);
+			}
+		}
+		if (skipflag) {
+			LZSeek(lzfd,ti.count*sizeof(ni),SEEK_CUR);
+			continue;
+		}
+		for (i=0;i<ti.count;i++) {
+			WORD	*rdata;
+			int	len;
+
+			LZREAD(&ni);
+			dprintf_resource(stderr,"	ni.id=%4x,offset=%d,length=%d\n",
+				ni.id,ni.offset,ni.length
+			);
+			skipflag=1;
+			if (!HIWORD(resid)) {
+				if (ni.id == resid)
+					skipflag=0;
+			} else {
+				if (!(ni.id & 0x8000)) {
+					BYTE	len;
+					char	*str;
+					DWORD	whereleft;
+
+					whereleft=LZSeek(
+						lzfd,
+						nehdoffset+nehd->resource_tab_offset+ni.id,
+						SEEK_SET
+					);
+					LZREAD(&len);
+					str=xmalloc(len);
+					if (len!=LZRead(lzfd,MAKE_SEGPTR(str),len))
+						return 0;
+					dprintf_resource(stderr,"read %s to compare it with %s\n",
+						str,(char*)PTR_SEG_TO_LIN(typeid)
+					);
+					if (!lstrcmpi(str,(char*)PTR_SEG_TO_LIN(typeid)))
+						skipflag=0;
+					free(str);
+					LZSeek(lzfd,whereleft,SEEK_SET);
+				}
+			}
+			if (skipflag)
+				continue;
+			LZSeek(lzfd,((int)ni.offset<<shiftcount),SEEK_SET);
+			*off	= (int)ni.offset<<shiftcount;
+			len	= ni.length<<shiftcount;
+			rdata=(WORD*)xmalloc(len);
+			if (len!=LZRead(lzfd,MAKE_SEGPTR(rdata),len)) {
+				free(rdata);
+				return 0;
+			}
+			dprintf_resource(stderr,"resource found.\n");
+			*resdata= (BYTE*)rdata;
+			*reslen	= len;
+			return 1;
+		}
+	}
+}
+
+DWORD
+GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid,LPDWORD off) {
+	HFILE	lzfd;
+	OFSTRUCT	ofs;
+	BYTE	*resdata;
+	int	reslen;
+	struct	ne_header_s	nehd;
+
+	fprintf(stderr,"GetFileResourceSize(%s,%lx,%lx,%p)\n",
+		filename,(LONG)restype,(LONG)resid,off
+	);
+	lzfd=LZOpenFile(filename,&ofs,OF_READ);
+	if (lzfd==0)
+		return 0;
+	if (!read_ne_header(lzfd,&nehd)) {
+		LZClose(lzfd);
+		return 0;
+	}
+	if (!find_ne_resource(lzfd,&nehd,restype,resid,&resdata,&reslen,off)) {
+		LZClose(lzfd);
+		return 0;
+	}
+	free(resdata);
+	LZClose(lzfd);
+	return reslen;
+}
+
+DWORD
+GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid,
+		DWORD off,DWORD datalen,LPVOID data
+) {
+	HFILE	lzfd;
+	OFSTRUCT	ofs;
+	BYTE	*resdata;
+	int	reslen;
+	struct	ne_header_s	nehd;
+	fprintf(stderr,"GetFileResource(%s,%lx,%lx,%ld,%ld,%p)\n",
+		filename,(LONG)restype,(LONG)resid,off,datalen,data
+	);
+
+	lzfd=LZOpenFile(filename,&ofs,OF_READ);
+	if (lzfd==0)
+		return 0;
+	if (!off) {
+		if (!read_ne_header(lzfd,&nehd)) {
+			LZClose(lzfd);
+			return 0;
+		}
+		if (!find_ne_resource(lzfd,&nehd,restype,resid,&resdata,&reslen,&off)) {
+			LZClose(lzfd);
+			return 0;
+		}
+		free(resdata);
+	}
+	LZSeek(lzfd,off,SEEK_SET);
+	if (reslen>datalen)
+		reslen=datalen;
+	LZRead(lzfd,MAKE_SEGPTR(data),reslen);
+	LZClose(lzfd);
+	return reslen;
+}
+
+DWORD
+GetFileVersionInfoSize(LPCSTR filename,LPDWORD handle) {
+	DWORD	len,ret;
+	BYTE	buf[72];
+	VS_FIXEDFILEINFO *vffi;
+
+	fprintf(stderr,"GetFileVersionInfoSize(%s,%p)\n",filename,handle);
+
+	len=GetFileResourceSize(filename,VS_FILE_INFO,VS_VERSION_INFO,handle);
+	if (!len)
+		return 0;
+	ret=GetFileResource(
+		filename,VS_FILE_INFO,VS_VERSION_INFO,*handle,sizeof(buf),buf
+	);
+	if (!ret)
+		return 0;
+
+	vffi=(VS_FIXEDFILEINFO*)(buf+0x14);
+	if (vffi->dwSignature != VS_FFI_SIGNATURE)
+		return 0;
+	if (*(WORD*)buf < len)
+		len = *(WORD*)buf;
+	fprintf(stderr,"->strucver=%ld.%ld,filever=%ld.%ld,productver=%ld.%ld,flagmask=%lx,flags=%lx,OS=",
+		(vffi->dwStrucVersion>>16),vffi->dwStrucVersion&0xFFFF,
+		vffi->dwFileVersionMS,vffi->dwFileVersionLS,
+		vffi->dwProductVersionMS,vffi->dwProductVersionLS,
+		vffi->dwFileFlagsMask,vffi->dwFileFlags
+	);
+	switch (vffi->dwFileOS&0xFFFF0000) {
+	case VOS_DOS:fprintf(stderr,"DOS,");break;
+	case VOS_OS216:fprintf(stderr,"OS/2-16,");break;
+	case VOS_OS232:fprintf(stderr,"OS/2-32,");break;
+	case VOS_NT:fprintf(stderr,"NT,");break;
+	case VOS_UNKNOWN:
+	default:
+		fprintf(stderr,"UNKNOWN(%ld),",vffi->dwFileOS&0xFFFF0000);break;
+	}
+	switch (vffi->dwFileOS & 0xFFFF) {
+	case VOS__BASE:fprintf(stderr,"BASE");break;
+	case VOS__WINDOWS16:fprintf(stderr,"WIN16");break;
+	case VOS__WINDOWS32:fprintf(stderr,"WIN32");break;
+	case VOS__PM16:fprintf(stderr,"PM16");break;
+	case VOS__PM32:fprintf(stderr,"PM32");break;
+	default:fprintf(stderr,"UNKNOWN(%ld)",vffi->dwFileOS&0xFFFF);break;
+	}
+	switch (vffi->dwFileType) {
+	default:
+	case VFT_UNKNOWN:
+		fprintf(stderr,"filetype=Unknown(%ld)",vffi->dwFileType);
+		break;
+	case VFT_APP:fprintf(stderr,"filetype=APP");break;
+	case VFT_DLL:fprintf(stderr,"filetype=DLL");break;
+	case VFT_DRV:
+		fprintf(stderr,"filetype=DRV,");
+		switch(vffi->dwFileSubtype) {
+		default:
+		case VFT2_UNKNOWN:
+			fprintf(stderr,"UNKNOWN(%ld)",vffi->dwFileSubtype);
+			break;
+		case VFT2_DRV_PRINTER:
+			fprintf(stderr,"PRINTER");
+			break;
+		case VFT2_DRV_KEYBOARD:
+			fprintf(stderr,"KEYBOARD");
+			break;
+		case VFT2_DRV_LANGUAGE:
+			fprintf(stderr,"LANGUAGE");
+			break;
+		case VFT2_DRV_DISPLAY:
+			fprintf(stderr,"DISPLAY");
+			break;
+		case VFT2_DRV_MOUSE:
+			fprintf(stderr,"MOUSE");
+			break;
+		case VFT2_DRV_NETWORK:
+			fprintf(stderr,"NETWORK");
+			break;
+		case VFT2_DRV_SYSTEM:
+			fprintf(stderr,"SYSTEM");
+			break;
+		case VFT2_DRV_INSTALLABLE:
+			fprintf(stderr,"INSTALLABLE");
+			break;
+		case VFT2_DRV_SOUND:
+			fprintf(stderr,"SOUND");
+			break;
+		case VFT2_DRV_COMM:
+			fprintf(stderr,"COMM");
+			break;
+		case VFT2_DRV_INPUTMETHOD:
+			fprintf(stderr,"INPUTMETHOD");
+			break;
+		}
+		break;
+	case VFT_FONT:
+		fprintf(stderr,"filetype=FONT.");
+		switch (vffi->dwFileSubtype) {
+		default:
+			fprintf(stderr,"UNKNOWN(%ld)",vffi->dwFileSubtype);
+			break;
+		case VFT2_FONT_RASTER:fprintf(stderr,"RASTER");break;
+		case VFT2_FONT_VECTOR:fprintf(stderr,"VECTOR");break;
+		case VFT2_FONT_TRUETYPE:fprintf(stderr,"TRUETYPE");break;
+		}
+		break;
+	case VFT_VXD:fprintf(stderr,"filetype=VXD");break;
+	case VFT_STATIC_LIB:fprintf(stderr,"filetype=STATIC_LIB");break;
+	}
+	fprintf(stderr,"filedata=%lx.%lx\n",vffi->dwFileDateMS,vffi->dwFileDateLS);
+	return len;
+}
+
+DWORD 
+GetFileVersionInfo(LPCSTR filename,DWORD handle,DWORD datasize,LPVOID data) {
+	fprintf(stderr,"GetFileVersionInfo(%s,%ld,%ld,%p)\n->",
+		filename,handle,datasize,data
+	);
+	return GetFileResource(
+		filename,VS_FILE_INFO,VS_VERSION_INFO,handle,datasize,data
+	);
+}
+
+DWORD 
+VerFindFile(
+	UINT flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
+	LPSTR curdir,UINT *curdirlen,LPSTR destdir,UINT*destdirlen
+) {
+	fprintf(stderr,"VerFindFile(%x,%s,%s,%s,%p,%d,%p,%d)\n",
+		flags,filename,windir,appdir,curdir,*curdirlen,destdir,*destdirlen
+	);
+	strcpy(curdir,"Z:\\ROOT\\.WINE\\");/*FIXME*/
+	*curdirlen=strlen(curdir);
+	strcpy(destdir,"Z:\\ROOT\\.WINE\\");/*FIXME*/
+	*destdirlen=strlen(destdir);
+	return 0;
+}
+
+DWORD
+VerInstallFile(
+	UINT flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
+	LPCSTR destdir,LPSTR tmpfile,UINT*tmpfilelen
+) {
+	fprintf(stderr,"VerInstallFile(%x,%s,%s,%s,%s,%p,%d)\n",
+		flags,srcfilename,destfilename,srcdir,destdir,tmpfile,*tmpfilelen
+	);
+	return VIF_SRCOLD;
+}
+
+/* FIXME: This table should, of course, be language dependend */
+static struct map_id2str {
+	UINT	langid;
+	char	*langname;
+} languages[]={
+	{0x0401,"Arabisch"},
+	{0x0402,"Bulgarisch"},
+	{0x0403,"Katalanisch"},
+	{0x0404,"Traditionales Chinesisch"},
+	{0x0405,"Tschecisch"},
+	{0x0406,"Dänisch"},
+	{0x0407,"Deutsch"},
+	{0x0408,"Griechisch"},
+	{0x0409,"Amerikanisches Englisch"},
+	{0x040A,"Kastilisches Spanisch"},
+	{0x040B,"Finnisch"},
+	{0x040C,"Französisch"},
+	{0x040D,"Hebräisch"},
+	{0x040E,"Ungarisch"},
+	{0x040F,"Isländisch"},
+	{0x0410,"Italienisch"},
+	{0x0411,"Japanisch"},
+	{0x0412,"Koreanisch"},
+	{0x0413,"Niederländisch"},
+	{0x0414,"Norwegisch-Bokmal"},
+	{0x0415,"Polnisch"},
+	{0x0416,"Brasilianisches Portugiesisch"},
+	{0x0417,"Rätoromanisch"},
+	{0x0418,"Rumänisch"},
+	{0x0419,"Russisch"},
+	{0x041A,"Kroatoserbisch (lateinisch)"},
+	{0x041B,"Slowenisch"},
+	{0x041C,"Albanisch"},
+	{0x041D,"Schwedisch"},
+	{0x041E,"Thai"},
+	{0x041F,"Türkisch"},
+	{0x0420,"Urdu"},
+	{0x0421,"Bahasa"},
+	{0x0804,"Vereinfachtes Chinesisch"},
+	{0x0807,"Schweizerdeutsch"},
+	{0x0809,"Britisches Englisch"},
+	{0x080A,"Mexikanisches Spanisch"},
+	{0x080C,"Belgisches Französisch"},
+	{0x0810,"Schweizerisches Italienisch"},
+	{0x0813,"Belgisches Niederländisch"},
+	{0x0814,"Norgwegisch-Nynorsk"},
+	{0x0816,"Portugiesisch"},
+	{0x081A,"Serbokratisch (kyrillisch)"},
+	{0x0C1C,"Kanadisches Französisch"},
+	{0x100C,"Schweizerisches Französisch"},
+	{0x0000,"Unbekannt"},
+};
+
+
+DWORD
+VerLanguageName(UINT langid,LPSTR langname,UINT langnamelen) {
+	int	i;
+
+	fprintf(stderr,"VerLanguageName(%d,%p,%d)\n",langid,langname,langnamelen);
+	for (i=0;languages[i].langid!=0;i++)
+		if (langid==languages[i].langid)
+			break;
+	strncpy(langname,languages[i].langname,langnamelen);
+	langname[langnamelen-1]='\0';
+	return strlen(languages[i].langname);
+}
+
+struct db {
+	WORD	nextoff;
+	WORD	datalen;
+/* in memory structure... */
+	char	name[1]; 	/* padded to dword alignment */
+/* .... 
+	char	data[datalen];     padded to dword alignemnt
+	BYTE	subdirdata[];      until nextoff
+ */
+};
+
+static BYTE*
+_find_data(BYTE *block,LPCSTR str) {
+	char	*nextslash;
+	int	substrlen;
+	struct	db	*db;
+
+	while (*str && *str=='\\')
+		str++;
+	if (NULL!=(nextslash=strchr(str,'\\')))
+		substrlen=nextslash-str;
+	else
+		substrlen=strlen(str);
+	if (nextslash!=NULL) {
+		while (*nextslash && *nextslash=='\\')
+			nextslash++;
+		if (!*nextslash)
+			nextslash=NULL;
+	}
+
+
+	while (1) {
+		db=(struct db*)block;
+		fprintf(stderr,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s,db->data=%s\n",
+			db,db->nextoff,db->datalen,db->name,(char*)((char*)db+4+((strlen(db->name)+4)&~3))
+		);
+		if (!db->nextoff)
+			return NULL;
+
+		fprintf(stderr,"comparing with %s\n",db->name);
+		if (!strncmp(db->name,str,substrlen)) {
+			if (nextslash)
+				return _find_data(
+					block+4+((strlen(db->name)+4)&~3)+((db->datalen+3)&~3)
+					,nextslash
+				);
+			else
+				return block;
+		}
+		block=block+((db->nextoff+3)&~3);
+	}
+
+}
+
+/* take care, 'buffer' is NOT a SEGPTR, it just points to one */
+DWORD
+VerQueryValue(SEGPTR segblock,LPCSTR subblock,SEGPTR *buffer,UINT *buflen) {
+	BYTE	*block=PTR_SEG_TO_LIN(segblock),*b;
+	struct	db	*db;
+	char	*s;
+
+	fprintf(stderr,"VerQueryValue(%p,%s,%p,%d)\n",
+		block,subblock,buffer,*buflen
+	);
+	s=(char*)xmalloc(strlen("VS_VERSION_INFO")+strlen(subblock)+1);
+	strcpy(s,"VS_VERSION_INFO");strcat(s,subblock);
+	b=_find_data(block,s);
+	if (b==NULL) {
+		*buflen=0;
+		return 0;
+	}
+	db=(struct db*)b;
+	*buflen	= db->datalen;
+	/* let b point to data area */
+	b	= b+4+((strlen(db->name)+4)&3);
+	/* now look up what the resp. SEGPTR would be ... 
+	 * we could use MAKE_SEGPTR , but we don't need to
+	 */
+	*buffer	= (b-block)+segblock;
+	fprintf(stderr,"	-> %s=%s\n",subblock,b);
+	return 1;
+}
+
+/*
+   20 GETFILEVERSIONINFORAW
+   21 VERFTHK_THUNKDATA16
+   22 VERTHKSL_THUNKDATA16
+*/
diff --git a/miscemu/dosmem.c b/miscemu/dosmem.c
index a4c156a..6fd52e2 100644
--- a/miscemu/dosmem.c
+++ b/miscemu/dosmem.c
@@ -9,11 +9,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include "windows.h"
+#include "winbase.h"
 #include "global.h"
 #include "ldt.h"
 #include "miscemu.h"
 #include "module.h"
-#include "xmalloc.h"
 
 
 HANDLE DOSMEM_BiosSeg;  /* BIOS data segment at 0x40:0 */
@@ -82,7 +82,7 @@
  *           DOSMEM_Init
  *
  * Create the dos memory segments, and store them into the KERNEL
- * exported values. MODULE_Init() must already have been called.
+ * exported values. BUILTIN_Init() must already have been called.
  */
 BOOL DOSMEM_Init(void)
 {
@@ -91,7 +91,12 @@
 
     /* Allocate 7 64k segments for 0000, A000, B000, C000, D000, E000, F000. */
 
-    dosmem = xmalloc( 0x70000 );
+    dosmem = VirtualAlloc( NULL, 0x70000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
+    if (!dosmem)
+    {
+        fprintf( stderr, "Could not allocate DOS segments\n" );
+        return FALSE;
+    }
 
     MODULE_SetEntryPoint( hModule, 183,  /* KERNEL.183: __0000H */
                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem,
diff --git a/miscemu/int2f.c b/miscemu/int2f.c
index cc40aac..fdfd3a5 100644
--- a/miscemu/int2f.c
+++ b/miscemu/int2f.c
@@ -14,7 +14,7 @@
 /* #define DEBUG_INT */
 #include "debug.h"
 
-  /* base WINPROC module number for VxDs */
+  /* base WPROCS.DLL ordinal number for VxDs */
 #define VXD_BASE 400
 
 static void do_int2f_16(struct sigcontext_struct *context);
@@ -100,7 +100,7 @@
 	break;
 
     case 0x84:  /* Get device API entry point */
-        addr = MODULE_GetEntryPoint( GetModuleHandle("WINPROCS"),
+        addr = MODULE_GetEntryPoint( GetModuleHandle("WPROCS"),
                                      VXD_BASE + BX_reg(context) );
         if (!addr)  /* not supported */
         {
diff --git a/miscemu/interrupts.c b/miscemu/interrupts.c
index 8e492c7..308d69f 100644
--- a/miscemu/interrupts.c
+++ b/miscemu/interrupts.c
@@ -18,7 +18,7 @@
 
 static SEGPTR INT_Vectors[256];
 
-  /* Ordinal number for interrupt 0 handler in WINPROCS.DLL */
+  /* Ordinal number for interrupt 0 handler in WPROCS.DLL */
 #define FIRST_INTERRUPT_ORDINAL 100
 
 
@@ -28,7 +28,7 @@
 BOOL INT_Init(void)
 {
     WORD vector;
-    HMODULE hModule = GetModuleHandle( "WINPROCS" );
+    HMODULE hModule = GetModuleHandle( "WPROCS" );
 
     for (vector = 0; vector < 256; vector++)
     {
@@ -72,8 +72,11 @@
  */
 void INT_DummyHandler( struct sigcontext_struct context )
 {
-    INT_BARF( &context,
-              CURRENT_STACK16->ordinal_number - FIRST_INTERRUPT_ORDINAL );
+    WORD ordinal;
+    char *name;
+    STACK16FRAME *frame = CURRENT_STACK16;
+    BUILTIN_GetEntryPoint( frame->entry_cs, frame->entry_ip, &ordinal, &name );
+    INT_BARF( &context, ordinal - FIRST_INTERRUPT_ORDINAL );
 }
 
 
diff --git a/multimedia/mmsystem.c b/multimedia/mmsystem.c
index f678ee4..a7fc32d 100644
--- a/multimedia/mmsystem.c
+++ b/multimedia/mmsystem.c
@@ -20,6 +20,7 @@
 #include "callback.h"
 #include "user.h"
 #include "driver.h"
+#include "file.h"
 #include "mmsystem.h"
 #include "stddebug.h"
 #include "debug.h"
diff --git a/objects/cursoricon.c b/objects/cursoricon.c
index 870f0ef..b645f0e 100644
--- a/objects/cursoricon.c
+++ b/objects/cursoricon.c
@@ -231,7 +231,7 @@
  *
  * Create a cursor or icon from a resource.
  */
-static HANDLE CURSORICON_LoadHandler( HANDLE handle, HINSTANCE hInstance,
+HANDLE CURSORICON_LoadHandler( HANDLE handle, HINSTANCE hInstance,
                                       BOOL fCursor )
 {
     HANDLE hAndBits, hXorBits;
diff --git a/objects/dc.c b/objects/dc.c
index 6c7a5dc..d2ee88c 100644
--- a/objects/dc.c
+++ b/objects/dc.c
@@ -362,16 +362,20 @@
 {
     DC * dc, * dcs;
     HRGN hVisRgn, hClipRgn, hGCClipRgn;
-
+    HFONT hfont;
+    HBRUSH hbrush;
+    
     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return;
     if (!(dcs = (DC *) GDI_GetObjPtr( hdcs, DC_MAGIC ))) return;
     if (!dcs->w.flags & DC_SAVED) return;
     dprintf_dc(stddeb, "SetDCState: %04x %04x\n", hdc, hdcs );
 
-      /* Save the regions before overwriting everything */
+      /* Save the regions, font & brush before overwriting everything */
     hVisRgn    = dc->w.hVisRgn;
     hClipRgn   = dc->w.hClipRgn;
     hGCClipRgn = dc->w.hGCClipRgn;
+    hfont      = dc->w.hFont;
+    hbrush     = dc->w.hBrush;
     memcpy( &dc->w, &dcs->w, sizeof(dc->w) );
     memcpy( &dc->u.x.pen, &dcs->u.x.pen, sizeof(dc->u.x.pen) );
     dc->w.flags &= ~DC_SAVED;
@@ -380,6 +384,8 @@
     dc->w.hVisRgn    = hVisRgn;
     dc->w.hClipRgn   = hClipRgn;
     dc->w.hGCClipRgn = hGCClipRgn;
+    dc->w.hFont      = hfont;
+    dc->w.hBrush     = hbrush;
     CombineRgn( dc->w.hVisRgn, dcs->w.hVisRgn, 0, RGN_COPY );
     SelectClipRgn( hdc, dcs->w.hClipRgn );
 
@@ -659,6 +665,25 @@
 
 
 /***********************************************************************
+ *           SetTextAlign    (GDI.346)
+ */
+WORD SetTextAlign( HDC hdc, WORD textAlign )
+{
+    WORD prevAlign;
+    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc)
+    {
+	if (!(dc = (DC *)GDI_GetObjPtr( hdc, METAFILE_DC_MAGIC ))) return 0;
+	MF_MetaParam1( dc, META_SETTEXTALIGN, textAlign );
+	return 1;
+    }
+    prevAlign = dc->w.textAlign;
+    dc->w.textAlign = textAlign;
+    return prevAlign;
+}
+
+
+/***********************************************************************
  *           GetDCOrg    (GDI.79)
  */
 DWORD GetDCOrg( HDC hdc )
diff --git a/objects/dcvalues.c b/objects/dcvalues.c
index 5bd7729..cf67de7 100644
--- a/objects/dcvalues.c
+++ b/objects/dcvalues.c
@@ -35,17 +35,6 @@
     return TRUE; \
 }
 
-#define DC_SET_VAL( func_type, func_name, dc_field ) \
-func_type func_name( HDC hdc, func_type val ) \
-{ \
-    func_type prevVal; \
-    DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); \
-    if (!dc) return 0; \
-    prevVal = dc->w.dc_field; \
-    dc->w.dc_field = val; \
-    return prevVal; \
-}
-
 #define DC_SET_MODE( func_name, dc_field, min_val, max_val, meta_func ) \
 WORD func_name( HDC hdc, WORD mode ) \
 { \
@@ -90,7 +79,6 @@
 DC_GET_X_Y( DWORD, GetBrushOrg, brushOrgX, brushOrgY )            /* GDI.149 */
 DC_GET_VAL( HRGN, GetClipRgn, hClipRgn )                          /* GDI.173 */
 DC_GET_VAL( WORD, GetTextAlign, textAlign )                       /* GDI.345 */
-DC_SET_VAL( WORD, SetTextAlign, textAlign )                       /* GDI.346 */
 DC_GET_VAL( HFONT, GetCurLogFont, hFont )                         /* GDI.411 */
 DC_GET_VAL_EX( GetBrushOrgEx, brushOrgX, brushOrgY )              /* GDI.469 */
 DC_GET_VAL_EX( GetCurrentPositionEx, CursPosX, CursPosY )         /* GDI.470 */
diff --git a/objects/font.c b/objects/font.c
index f9cfc8b..e1e1bb0 100644
--- a/objects/font.c
+++ b/objects/font.c
@@ -491,9 +491,12 @@
       /* Unuse previous font */
 	for (i=0; i < FONTCACHE; i++) {
 		if (cacheFonts[i].id == prevHandle) {
-			cacheFonts[i].used--;
-			}
+			if(cacheFonts[i].used == 0)
+				fprintf(stderr, "Trying to decrement a use count of 0.\n");
+			else 
+				cacheFonts[i].used--;
 		}
+	}
 
       /* Store font */
     dc->w.hFont = hfont;
@@ -517,9 +520,10 @@
 			if ((!cacheFontsMin) || ((cacheFontsMin) && (cacheFontsMin->access > cacheFonts[i].access)))
 				cacheFontsMin=&cacheFonts[i];
 		}
-	if (!cacheFontsMin)
+	if (!cacheFontsMin) {
 		fprintf(stderr,"No unused font cache entry !!!!\n" );
-
+		return prevHandle;
+	}
 	if (cacheFontsMin->id!=0) {
 		dprintf_font(stddeb,
 			"FONT_SelectObject: Freeing %04x \n",cacheFontsMin->id );
diff --git a/objects/gdiobj.c b/objects/gdiobj.c
index ad3ef50..d677e5d 100644
--- a/objects/gdiobj.c
+++ b/objects/gdiobj.c
@@ -20,7 +20,6 @@
 #include "debug.h"
 #include "xmalloc.h"
 
-LPSTR GDI_Heap = NULL;
 WORD GDI_HeapSel = 0;
 
 /* Object types for EnumObjects() */
@@ -163,14 +162,6 @@
 {
     HPALETTE hpalette;
 
-#ifndef WINELIB
-      /* Create GDI heap */
-
-    if (!(GDI_HeapSel = GlobalAlloc(GMEM_FIXED, GDI_HEAP_SIZE))) return FALSE;
-    GDI_Heap = GlobalLock( GDI_HeapSel );
-    LocalInit( GDI_HeapSel, 0, GDI_HEAP_SIZE-1 );
-#endif
-    
       /* Create default palette */
 
     if (!(hpalette = COLOR_Init())) return FALSE;
diff --git a/objects/metafile.c b/objects/metafile.c
index e831017..8cb460e 100644
--- a/objects/metafile.c
+++ b/objects/metafile.c
@@ -138,6 +138,7 @@
 		      sizeof(HANDLETABLE) * HTLen);
     
     GlobalUnlock(dc->w.hMetaFile);
+    dprintf_metafile(stddeb,"CreateMetaFile: returning %04x\n", handle);
     return handle;
 }
 
@@ -265,7 +266,8 @@
     METARECORD *mr;
     HANDLETABLE *ht;
     int offset = 0;
-    
+    WORD i;
+
     dprintf_metafile(stddeb,"PlayMetaFile(%04x %04x)\n",hdc,hmf);
     
     /* create the handle table */
@@ -284,6 +286,11 @@
 	PlayMetaFileRecord(hdc, ht, mr, mh->mtNoObjects);
     }
 
+    /* free objects in handle table */
+    for(i = 0; i < mh->mtNoObjects; i++)
+      if(*(ht->objectHandle + i) != 0)
+        DeleteObject(*(ht->objectHandle + i));
+    
     /* free handle table */
     GlobalFree(hHT);
 
@@ -356,6 +363,7 @@
 
     case META_DELETEOBJECT:
       DeleteObject(*(ht->objectHandle + *(mr->rdParam)));
+      *(ht->objectHandle + *(mr->rdParam)) = 0;
       break;
 
     case META_SETBKCOLOR:
@@ -576,8 +584,7 @@
 	break;
 
     case META_SETTEXTALIGN:
-        fprintf(stderr,"PlayMetaFileRecord: SETTEXTALIGN: %hd\n",mr->rdParam[0]);
-	SetTextAlign(hdc, *(mr->rdParam));
+       	SetTextAlign(hdc, *(mr->rdParam));
 	break;
 
     case META_SELECTPALETTE:
diff --git a/objects/oembitmap.c b/objects/oembitmap.c
index 36bbe20..04867fa 100644
--- a/objects/oembitmap.c
+++ b/objects/oembitmap.c
@@ -54,6 +54,7 @@
 #include "bitmaps/obm_old_uparrow"
 #include "bitmaps/obm_size"
 #include "bitmaps/obm_old_close"
+#include "bitmaps/obm_trtype"
 
 #ifndef WIN_95_LOOK
 #include "bitmaps/obm_zoomd"
@@ -70,7 +71,7 @@
 #include "bitmaps/obm_closed_95"
 #endif  /* WIN_95_LOOK */
 
-#define OBM_FIRST  OBM_CDROM      /* First OEM bitmap */
+#define OBM_FIRST  OBM_TRTYPE	   /* First OEM bitmap */
 #define OBM_LAST   OBM_OLD_CLOSE   /* Last OEM bitmap */
 
 static const struct
@@ -78,6 +79,7 @@
     char** data;   /* Pointer to bitmap data */
     BOOL   color;  /* Is it a color bitmap?  */
 } OBM_Pixmaps_Data[OBM_LAST-OBM_FIRST+1] = {
+    { obm_trtype, TRUE },	/* OBM_TRTYPE */    
     { obm_cdrom, TRUE },        /* OBM_CDROM    */
     { obm_harddisk, TRUE },     /* OBM_HARDDISK */
     { obm_drive, TRUE },        /* OBM_DRIVE    */
diff --git a/resources/Makefile.in b/resources/Makefile.in
index dc53de0..d6e2d9b 100644
--- a/resources/Makefile.in
+++ b/resources/Makefile.in
@@ -2,7 +2,7 @@
 
 MODULE = resources
 
-LANGUAGES = En Es De No Fr Fi Da Cz Eo It
+LANGUAGES = En Es De No Fr Fi Da Cz Eo It Ko
 
 SYSRES_SRCS = $(LANGUAGES:%=sysres_%.c)
 
diff --git a/resources/sysres.c b/resources/sysres.c
index 832d026..0b9f95b 100644
--- a/resources/sysres.c
+++ b/resources/sysres.c
@@ -19,7 +19,7 @@
 #include "sysres_Cz.h"
 #include "sysres_Eo.h"
 #include "sysres_It.h"
-
+#include "sysres_Ko.h"
 
 static const struct resource * const * SYSRES_Resources[] =
 {
@@ -32,7 +32,8 @@
     sysres_Da_Table,  /* LANG_Da */
     sysres_Cz_Table,  /* LANG_Cz */
     sysres_Eo_Table,  /* LANG_Eo */
-    sysres_It_Table   /* LANG_It */
+    sysres_It_Table,  /* LANG_It */
+    sysres_Ko_Table   /* LANG_Ko */
 };
 
 
diff --git a/resources/sysres_Ko.rc b/resources/sysres_Ko.rc
new file mode 100644
index 0000000..b6588a5
--- /dev/null
+++ b/resources/sysres_Ko.rc
@@ -0,0 +1,215 @@
+SYSMENU MENU LOADONCALL MOVEABLE DISCARDABLE
+{
+ MENUITEM "º¹±Í(&R)", 61728
+ MENUITEM "À̵¿(&M)", 61456
+ MENUITEM "Å©±â º¯°æ(&S)", 61440
+ MENUITEM "Ãà¼Ò(&N)", 61472
+ MENUITEM "È®´ë(&M)", 61488
+ MENUITEM SEPARATOR
+ MENUITEM "´Ý±â(&C)\tAlt-F4", 61536
+ MENUITEM SEPARATOR
+ MENUITEM "ÀÛ¾÷ Àüȯ(&W) ...\tCtrl-Esc", 61744
+ MENUITEM SEPARATOR
+ MENUITEM "¿ÍÀο¡ °üÇÏ¿© ...", 61761
+}
+
+MSGBOX DIALOG 100, 80, 216, 168
+STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+BEGIN
+	ICON "", 1088, 8, 20, 16, 16, WS_CHILD | WS_VISIBLE
+	LTEXT "", 100, 32, 4, 176, 48, WS_CHILD | WS_VISIBLE | WS_GROUP
+	PUSHBUTTON "½ÂÀÎ(&O)", 1, 16, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+	PUSHBUTTON "Ãë¼Ò(&C)", 2, 64, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+	PUSHBUTTON "Áß´Ü(&A)", 3, 112, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+	PUSHBUTTON "Àç½Ãµµ(&R)", 4, 160, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+	PUSHBUTTON "¹«½Ã(&I)", 5, 208, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+	PUSHBUTTON "¿¹(&Y)", 6, 256, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+	PUSHBUTTON "¾Æ´Ï¿À(&N)", 7, 304, 56, 40, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
+END
+
+SHELL_ABOUT_MSGBOX DIALOG LOADONCALL MOVEABLE DISCARDABLE 50, 44, 223, 200
+STYLE DS_LOCALEDIT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "%s¿¡ °üÇÏ¿©"
+FONT 10, "System"
+{
+ DEFPUSHBUTTON "½ÂÀÎ", 1, 91, 180, 40, 14
+ CONTROL "", -1, "STATIC", SS_BLACKFRAME | WS_CHILD | WS_VISIBLE | WS_DISABLED, 4, 35, 215, 140
+ LTEXT "Text", 100, 11, 40, 200, 130, SS_NOPREFIX | WS_GROUP
+ ICON "", 1088, 195, 10, 18, 20
+}
+
+
+OPEN_FILE DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 275, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "¿­±â"
+FONT 8, "Helv"
+{
+ LTEXT "ÆÄÀÏ À̸§(&N):", 1090, 6, 6, 76, 9
+ EDITTEXT 1152, 6, 16, 90, 12, ES_AUTOHSCROLL | ES_OEMCONVERT | WS_BORDER | WS_TABSTOP
+ LISTBOX 1120, 6, 32, 90, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
+ LTEXT "µð·ºÅ丮(&D):", -1, 110, 6, 92, 9
+ LTEXT "", 1088, 110, 18, 92, 9, SS_NOPREFIX | WS_GROUP
+ LISTBOX 1121, 110, 32, 92, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
+ LTEXT "ÆÄÀÏ Çü½Ä(&T):", 1089, 6, 104, 90, 9
+ COMBOBOX 1136, 6, 114, 90, 36, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ LTEXT "µå¶óÀ̺ê(&V):", 1091, 110, 104, 92, 9
+ COMBOBOX 1137, 110, 114, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "¿­±â", 1, 208, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Ãë¼Ò", 2, 208, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "µµ¿ò¸»(&H)", 1038, 208, 46, 56, 14, WS_GROUP | WS_TABSTOP
+ CHECKBOX "Àбâ Àü¿ë(&R)", 1040, 208, 68, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+}
+
+
+SAVE_FILE DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 275, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "´Ù¸¥ À̸§À¸·Î ÀúÀå ..."
+FONT 8, "Helv"
+{
+ LTEXT "ÆÄÀÏ À̸§(&N):", 1090, 6, 6, 76, 9
+ EDITTEXT 1152, 6, 16, 90, 12, ES_AUTOHSCROLL | ES_OEMCONVERT | WS_BORDER | WS_TABSTOP
+ LISTBOX 1120, 6, 32, 90, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
+ LTEXT "µð·ºÅ丮(&D):", -1, 110, 6, 92, 9
+ LTEXT "", 1088, 110, 18, 92, 9, SS_NOPREFIX | WS_GROUP
+ LISTBOX 1121, 110, 32, 92, 68, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_TABSTOP
+ LTEXT "ÆÄÀÏ Çü½Ä(&T):", 1089, 6, 104, 90, 9
+ COMBOBOX 1136, 6, 114, 90, 36, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ LTEXT "µå¶óÀ̺ê(&V):", 1091, 110, 104, 92, 9
+ COMBOBOX 1137, 110, 114, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "ÀúÀå", 1, 208, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Ãë¼Ò", 2, 208, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "µµ¿ò¸»(&H)", 1038, 208, 46, 56, 14, WS_GROUP | WS_TABSTOP
+ CHECKBOX "Àбâ Àü¿ë(&R)", 1040, 208, 68, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+}
+
+
+PRINT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Àμâ"
+FONT 8, "Helv"
+{
+ LTEXT "Àμâ±â:", 1088, 6, 6, 40, 9
+ LTEXT "", 1089, 60, 6, 150, 9
+ GROUPBOX "Àμ⠹üÀ§", 1072, 6, 30, 160, 65, BS_GROUPBOX
+ RADIOBUTTON "¸ðµÎ(&A)", 1056, 16, 45, 60, 12
+ RADIOBUTTON "¼±ÅÃ(&E)", 1057, 16, 60, 60, 12
+ RADIOBUTTON "ÂÊ(&P)", 1058, 16, 75, 60, 12
+ DEFPUSHBUTTON "Àμâ", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Ãë¼Ò", 2, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "¼³Á¤(&S)", 1024, 206, 46, 56, 14, WS_GROUP | WS_TABSTOP
+ LTEXT "½ÃÀÛ(&F):", 1090, 60, 80, 30, 9
+ LTEXT "³¡(&T):", 1091, 120, 80, 30, 9
+ LTEXT "Àμâ Ç°Áú(&Q):", 1092, 6, 100, 76, 9
+ COMBOBOX 1136, 80, 100, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ CHECKBOX "ÆÄÀÏ·Î Àμâ(&L)", 1040, 20, 100, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+ CHECKBOX "Condensed", 1041, 160, 100, 50, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+}
+
+
+PRINT_SETUP DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Àμ⠼³Á¤"
+FONT 8, "Helv"
+{
+ GROUPBOX "Àμâ±â", 1072, 6, 10, 180, 65, BS_GROUPBOX
+ RADIOBUTTON "±âº» Àμâ±â(&D)", 1056, 16, 20, 80, 12
+ LTEXT "[¾øÀ½]", 1088, 35, 35, 120, 9
+ RADIOBUTTON "ÁöÁ¤µÈ Àμâ±â(&P)", 1057, 16, 50, 80, 12
+ COMBOBOX 1136, 35, 65, 149, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "½ÂÀÎ", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Ãë¼Ò", 2, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "¼³Á¤(&S)", 1024, 206, 46, 56, 14, WS_GROUP | WS_TABSTOP
+ GROUPBOX "¹æÇâ", 1073, 6, 85, 100, 50, BS_GROUPBOX
+ RADIOBUTTON "¼¼·Î(&R)", 1058, 50, 100, 40, 12
+ RADIOBUTTON "°¡·Î(&L)", 1059, 50, 115, 40, 12
+ ICON "LANDSCAP", 1097, 10, 95, 32, 32
+ ICON "PORTRAIT", 1098, 10, 95, 32, 32
+ GROUPBOX "Á¾ÀÌ", 1074, 120, 85, 180, 50, BS_GROUPBOX
+ LTEXT "Å©±â(&Z)", 1089, 130, 95, 30, 9
+ LTEXT "¹æ½Ä(&S)", 1090, 130, 110, 30, 9
+ COMBOBOX 1137, 155, 95, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX 1138, 155, 110, 92, 68, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+}
+
+
+CHOOSE_FONT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 264, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "±ÛÀÚü"
+FONT 8, "Helv"
+{
+ LTEXT "±ÛÀÚü:", 1088, 6, 6, 40, 9
+ LTEXT "", 1089, 60, 6, 150, 9
+ DEFPUSHBUTTON "½ÂÀÎ", 1, 206, 6, 56, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Ãë¼Ò", 2, 206, 24, 56, 14, WS_GROUP | WS_TABSTOP
+}
+
+
+CHOOSE_COLOR DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 300, 200
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "»ö"
+FONT 8, "Helv"
+{
+ LTEXT "±âº»»ö(&B):",   1088, 4,    4,  140, 10
+ LTEXT "»ç¿ëÀÚ»ö(&C):",  1089, 4,   106, 140, 10
+ LTEXT "È¥»ö |  ´Ü»ö(&i)",  1090, 150, 151,  48, 10
+ LTEXT	 "»¡°­(&R):", 726 /*1094*/,249,126,24,10
+ EDITTEXT 706, 275,124,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT	 "ÃÊ·Ï(&G):",727/*1095*/,249,140,24,10
+ EDITTEXT 707, 275,138,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT	 "ÆĶû(&B):",728 /*1096*/,249,154,24,10
+ EDITTEXT 708, 275,152,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT	"»ö»ó(&H):" ,723 /*1091*/,202,126,22,10
+ EDITTEXT 703, 226,124,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT	"äµµ(&S):" ,724 /*1092*/,202,140,22,10
+ EDITTEXT 704, 226,138,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT	"¸íµµ(&L):" ,725 /*1093*/,202,154,22,10
+ EDITTEXT 705, 226,152,18,12, WS_BORDER | WS_GROUP | WS_TABSTOP
+ CONTROL "" ,720,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP,4,14,140,86
+ CONTROL "" ,721,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP,4,116,140,28
+ CONTROL "" ,710,"STATIC",WS_BORDER|SS_SIMPLE|WS_TABSTOP|WS_GROUP, 152,4,118,116
+ CONTROL "" ,702,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP, 278,4,8,116
+ CONTROL "" ,709,"STATIC",SS_SIMPLE|WS_TABSTOP|WS_GROUP, 152,124,40,26
+ DEFPUSHBUTTON "½ÂÀÎ",  1,  4, 166, 44, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Ãë¼Ò", 2, 52, 166, 44, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "µµ¿ò¸»", 1038,100,166, 44, 14
+ PUSHBUTTON "»ç¿ëÀÚ»ö¿¡ Ãß°¡(&A)",    712/*1024*/, 152, 166, 142, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "»ç¿ëÀÚ»ö Á¤ÀÇ(&D) >>", 719/*1025*/,   4, 150, 142, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON  "&i",713,300,200,4,14   /* just a dummy:  'i' is  like  &i  in "sol&id"  */
+}
+
+
+FIND_TEXT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 236, 62
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "ã±â"
+FONT 8, "Helv"
+{
+ LTEXT "ãÀ» ¹®ÀÚ¿­(&N):", -1, 4, 8, 42, 8
+ EDITTEXT 1152, 47, 7, 128, 12, ES_AUTOHSCROLL | WS_BORDER | WS_GROUP | WS_TABSTOP
+ CHECKBOX "´Ü¾î¸¸(&W)", 1040, 4, 26, 100, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+ CHECKBOX "´ë¼Ò¹®ÀÚ ±¸º°(&C)", 1041, 4, 42, 64, 12, BS_AUTOCHECKBOX | WS_TABSTOP
+ GROUPBOX "¹æÇâ", 1072, 107, 26, 68, 28
+ CONTROL "ˤ(&U)", 1056, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 111, 38, 20, 12
+ CONTROL "¾Æ·¡(&D)", 1057, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 138, 38, 30, 12
+ DEFPUSHBUTTON "´ÙÀ½ ã±â(&F)", 1, 182, 5, 50, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Ãë¼Ò", 2, 182, 23, 50, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "µµ¿ò¸»(&H)", 1038, 182, 45, 50, 14, WS_GROUP | WS_TABSTOP
+}
+
+
+REPLACE_TEXT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 230, 94
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "¹Ù²Ù±â"
+FONT 8, "Helv"
+{
+ LTEXT "ãÀ» ¹®ÀÚ¿­(&N):", -1, 4, 9, 48, 8
+ EDITTEXT 1152, 54, 7, 114, 12, ES_AUTOHSCROLL | WS_BORDER | WS_GROUP | WS_TABSTOP
+ LTEXT "¹Ù²Ü ¹®ÀÚ¿­(&P):", -1, 4, 26, 48, 8
+ EDITTEXT 1153, 54, 24, 114, 12, ES_AUTOHSCROLL | WS_BORDER | WS_GROUP | WS_TABSTOP
+ CHECKBOX "´Ü¾î¸¸(&W)", 1040, 5, 46, 104, 12, BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP
+ CHECKBOX "´ë¼Ò¹®ÀÚ ±¸º°(&C)", 1041, 5, 62, 59, 12, BS_AUTOCHECKBOX | WS_TABSTOP
+ DEFPUSHBUTTON "´ÙÀ½ ã±â(&F)", 1, 174, 4, 50, 14, BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "¹Ù²Ù±â(&R)", 1024, 174, 21, 50, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "¸ðµÎ ¹Ù²Ù±â(&A)", 1025, 174, 38, 50, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Ãë¼Ò", 2, 174, 55, 50, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "µµ¿ò¸»(&H)", 1038, 174, 75, 50, 14, WS_GROUP | WS_TABSTOP
+}
diff --git a/tools/build.c b/tools/build.c
index dfa2d40..ac2af32 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -80,8 +80,8 @@
 static enum SPEC_TYPE SpecType = SPEC_INVALID;
 char DLLName[80];
 int Limit = 0;
-int DLLId;
 int Base = 0;
+int HeapSize = 0;
 FILE *SpecFp;
 
 char *ParseBuffer = NULL;
@@ -475,27 +475,25 @@
                 exit(1);
             }
         }
-	else if (strcmp(token, "id") == 0)
-	{
-	    token = GetToken();
-	    if (!IsNumberString(token))
-	    {
-		fprintf(stderr, "%d: Expected number after id\n", Line);
-		exit(1);
-	    }
-	    
-	    DLLId = atoi(token);
-	}
 	else if (strcmp(token, "base") == 0)
 	{
-		token = GetToken();
-		if (!IsNumberString(token))
-		{
+            token = GetToken();
+            if (!IsNumberString(token))
+            {
 		fprintf(stderr, "%d: Expected number after base\n", Line);
 		exit(1);
-		}
-
-		Base = atoi(token);
+            }
+            Base = atoi(token);
+	}
+	else if (strcmp(token, "heap") == 0)
+	{
+            token = GetToken();
+            if (!IsNumberString(token))
+            {
+		fprintf(stderr, "%d: Expected number after heap\n", Line);
+		exit(1);
+            }
+            HeapSize = atoi(token);
 	}
 	else if (IsNumberString(token))
 	{
@@ -554,16 +552,11 @@
  * Dump a byte stream into the assembly code.
  */
 static void DumpBytes( const unsigned char *data, int len,
-                       const char *section, const char *label_start,
-                       const char *label_end )
+                       const char *section, const char *label_start )
 {
     int i;
     if (section) printf( "\t%s\n", section );
-    if (label_start)
-    {
-        printf( "\t.globl " PREFIX "%s_%s\n", DLLName, label_start );
-        printf( PREFIX "%s_%s:\n", DLLName, label_start );
-    }
+    if (label_start) printf( "%s:\n", label_start );
     for (i = 0; i < len; i++)
     {
         if (!(i & 0x0f)) printf( "\t.byte " );
@@ -571,11 +564,6 @@
         if (i < len - 1) printf( "%c", ((i & 0x0f) != 0x0f) ? ',' : '\n' );
     }
     printf( "\n" );
-    if (label_end)
-    {
-        printf( "\t.globl " PREFIX "%s_%s\n", DLLName, label_end );
-        printf( PREFIX "%s_%s:\n", DLLName, label_end );
-    }
 }
 
 
@@ -585,7 +573,7 @@
  * Build the in-memory representation of a 16-bit NE module, and dump it
  * as a byte stream into the assembly code.
  */
-static void BuildModule16( int max_code_offset, int max_data_offset )
+static int BuildModule16( int max_code_offset, int max_data_offset )
 {
     ORDDEF *odp;
     int i;
@@ -615,7 +603,7 @@
     pModule->next = 0;
     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
     pModule->dgroup = 2;
-    pModule->heap_size = 0xffff;
+    pModule->heap_size = HeapSize;
     pModule->stack_size = 0;
     pModule->ip = 0;
     pModule->cs = 0;
@@ -761,7 +749,8 @@
       /* Dump the module content */
 
     DumpBytes( (char *)pModule, (int)pstr - (int)pModule,
-               ".data", "Module_Start", "Module_End" );
+               ".data", "Module_Start" );
+    return (int)pstr - (int)pModule;
 }
 
 
@@ -771,7 +760,7 @@
  * Build the in-memory representation of a 32-bit pseudo-NE module, and dump it
  * as a byte stream into the assembly code.
  */
-static void BuildModule32(void)
+static int BuildModule32(void)
 {
     char *buffer;
     NE_MODULE *pModule;
@@ -798,7 +787,7 @@
     pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN |
                      NE_FFLAGS_LIBMODULE | NE_FFLAGS_WIN32;
     pModule->dgroup = 0;
-    pModule->heap_size = 0;
+    pModule->heap_size = HeapSize;
     pModule->stack_size = 0;
     pModule->ip = 0;
     pModule->cs = 0;
@@ -869,7 +858,8 @@
       /* Dump the module content */
 
     DumpBytes( (char *)pModule, (int)pstr - (int)pModule,
-               ".data", "Module_Start", "Module_End" );
+               ".data", "Module_Start" );
+    return (int)pstr - (int)pModule;
 }
 
 
@@ -883,13 +873,12 @@
     ORDDEF *odp;
     ORDFUNCDEF *fdp;
     ORDRETDEF *rdp;
-    int i;
+    int i, module_size;
 
     printf( "/* File generated automatically; do not edit! */\n" );
     printf( "\t.text\n" );
     printf( "\t.align 4\n" );
-    printf( "\t.globl " PREFIX "%s_Code_Start\n", DLLName );
-    printf( PREFIX "%s_Code_Start:\n\n", DLLName );
+    printf( "Code_Start:\n\n" );
 
     odp = OrdinalDefinitions;
     for (i = 0; i <= Limit; i++, odp++)
@@ -940,25 +929,28 @@
         }
     }
 
-    BuildModule32();
+    module_size = BuildModule32();
+
+    /* Output the DLL functions table */
 
     printf( "\t.text\n" );
-    printf( "\t.globl " PREFIX "%s_Data_Start\n", DLLName );
-    printf( PREFIX "%s_Data_Start:\n", DLLName );
-    printf( "\t.long %d,%d\n", Base, Limit );
-    printf( "\n/* Function table */\n" );
+    printf( "\t.align 4\n" );
+    printf( "Functions:\n" );
+    odp = OrdinalDefinitions;
+    for (i = 0; i <= Limit; i++, odp++) printf("\t.long %s_%d\n", DLLName, i);
 
+    /* Output the DLL names table */
+
+    printf( "FuncNames:\n" );
     odp = OrdinalDefinitions;
     for (i = 0; i <= Limit; i++, odp++)
     {
-        if (odp->type == TYPE_INVALID)
-            printf( "\t.long 0,%s_%d\n", DLLName, i );
-        else
-            printf( "\t.long Name_%d,%s_%d\n", i, DLLName, i );
+        if (odp->type == TYPE_INVALID) printf( "\t.long 0\n" );
+        else printf( "\t.long Name_%d\n", i );
     }
-    printf( "\t.long 0,0\n" );
 
-    printf( "\n/* Name table */\n" );
+    /* Output the DLL names */
+
     for (i = 0, odp = OrdinalDefinitions; i <= Limit; i++, odp++)
     {
         printf( "Name_%d:\t", i );
@@ -967,6 +959,20 @@
         else
             printf( ".ascii \"%s\\0\"\n", odp->export_name );
     }
+
+    /* Output the DLL descriptor */
+
+    printf( "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
+    printf( "\t.align 4\n" );
+    printf( "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
+    printf( PREFIX "%s_Descriptor:\n", DLLName );
+    printf( "\t.long DLLName\n" );          /* Name */
+    printf( "\t.long Module_Start\n" );     /* Module start */
+    printf( "\t.long %d\n", module_size );  /* Module size */
+    printf( "\t.long %d\n", Base );         /* Base */
+    printf( "\t.long %d\n", Limit );        /* Limit */
+    printf( "\t.long Functions\n" );        /* Functions */
+    printf( "\t.long FuncNames\n" );        /* Function names */
 }
 
 
@@ -981,7 +987,7 @@
     ORDFUNCDEF *fdp;
     ORDRETDEF *rdp;
     int i;
-    int code_offset, data_offset;
+    int code_offset, data_offset, module_size;
     unsigned char *data;
 
     data = (unsigned char *)xmalloc( 0x10000 );
@@ -990,8 +996,7 @@
 
     printf( "/* File generated automatically; do not edit! */\n" );
     printf( "\t.text\n" );
-    printf( "\t.globl " PREFIX "%s_Code_Start\n", DLLName );
-    printf( PREFIX "%s_Code_Start:\n", DLLName );
+    printf( "Code_Start:\n" );
     code_offset = 0;
 
     odp = OrdinalDefinitions;
@@ -1051,20 +1056,16 @@
           case TYPE_STUB:
             printf( "/* %s.%d */\n", DLLName, i);
             printf( "\tpushw %%bp\n" );
-            printf( "\tpushl $0x%08x\n", (DLLId << 16) | i);
             printf( "\tpushl $" PREFIX "%s\n", fdp->internal_name );
-            printf( "\tljmp $0x%04x, $" PREFIX "CallFrom16_%s_%s\n",
+            printf( "\tlcall $0x%04x, $" PREFIX "CallFrom16_%s_%s\n",
                     WINE_CODE_SELECTOR,
                     (odp->type == TYPE_REGISTER) ? "regs" :
                     (odp->type == TYPE_PASCAL) ? "long" : "word",
                     fdp->arg_types );
             printf( "\tnop\n" );
-            printf( "\tnop\n" );
-            printf( "\tnop\n" );
-            printf( "\tnop\n" );
             printf( "\tnop\n\n" );
             odp->offset = code_offset;
-            code_offset += 24;  /* Assembly code is 24 bytes long */
+            code_offset += 16;  /* Assembly code is 16 bytes long */
             break;
 		
           default:
@@ -1082,11 +1083,24 @@
 
     /* Output data segment */
 
-    DumpBytes( data, data_offset, NULL, "Data_Start", NULL );
+    DumpBytes( data, data_offset, NULL, "Data_Start" );
 
     /* Build the module */
 
-    BuildModule16( code_offset, data_offset );
+    module_size = BuildModule16( code_offset, data_offset );
+
+    /* Output the DLL descriptor */
+
+    printf( "\t.text\n" );
+    printf( "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
+    printf( "\t.align 4\n" );
+    printf( "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
+    printf( PREFIX "%s_Descriptor:\n", DLLName );
+    printf( "\t.long DLLName\n" );          /* Name */
+    printf( "\t.long Module_Start\n" );     /* Module start */
+    printf( "\t.long %d\n", module_size );  /* Module size */
+    printf( "\t.long Code_Start\n" );       /* Code start */
+    printf( "\t.long Data_Start\n" );       /* Data start */
 }
 
 
@@ -1306,7 +1320,7 @@
     printf( "\tmovl %%edi,%d(%%ebx)\n", CONTEXTOFFSET(EDI) );
     printf( "\tmovw -10(%%ebp),%%ax\n" );  /* Get saved ds from stack */
     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(DS) );
-    printf( "\tmovw -12(%%ebp),%%ax\n" );  /* Get saved es from stack */
+    printf( "\tmovw -6(%%ebp),%%ax\n" );  /* Get saved es from stack */
     printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(ES) );
     printf( "\tpushfl\n" );
     printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(EFL) );
@@ -1330,7 +1344,8 @@
     printf( "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(EDX) );
     printf( "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(ESI) );
     printf( "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(EDI) );
-    printf( "\tpopl %%eax\n" );  /* Remove old ds and es from stack */
+    printf( "\tpopl %%eax\n" );  /* Remove old ds and ip from stack */
+    printf( "\tpopl %%eax\n" );  /* Remove old cs and es from stack */
     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(DS) ); /* Push new ds */
     printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(ES) ); /* Push new es */
     printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(EFL) );
@@ -1351,13 +1366,16 @@
  * removed from the stack upon return.
  *
  * Stack layout upon entry to the callback function:
- *  ...      ...
- * (sp+14)  first 16-bit arg
- * (sp+12)  cs (word)
- * (sp+10)  ip (word)
- * (sp+8)   bp (word)
- * (sp+4)   dll_id+ordinal (long)
- * (sp)     entrypoint (long)
+ *  ...           ...
+ * (sp+18) word   first 16-bit arg
+ * (sp+16) word   cs
+ * (sp+14) word   ip
+ * (sp+12) word   bp
+ * (sp+8)  long   32-bit entry point
+ * (sp+6)  word   high word of cs (always 0, used to store es)
+ * (sp+4)  word   low word of cs of 16-bit entry point
+ * (sp+2)  word   high word of ip (always 0, used to store ds)
+ * (sp)    word   low word of ip of 16-bit entry point
  *
  */
 static void BuildCallFrom16Func( char *profile )
@@ -1389,12 +1407,12 @@
     /* Setup bp to point to its copy on the stack */
 
     printf( "\tmovzwl %%sp,%%ebp\n" );
-    printf( "\taddw $8,%%bp\n" );
+    printf( "\taddw $12,%%bp\n" );
 
     /* Save 16-bit ds and es */
 
-    printf( "\tpushw %%ds\n" );
-    printf( "\tpushw %%es\n" );
+    printf( "\tmovw %%ds,-10(%%ebp)\n" );
+    printf( "\tmovw %%es,-6(%%ebp)\n" );
 
     /* Restore 32-bit ds and es */
 
@@ -1420,12 +1438,12 @@
 
     /* Get the address of the API function */
 
-    printf( "\tmovl -8(%%ebp),%%eax\n" );
+    printf( "\tmovl -4(%%ebp),%%eax\n" );
 
     /* If necessary, save %edx over the API function address */
 
     if (!reg_func && short_ret)
-        printf( "\tmovl %%edx,-8(%%ebp)\n" );
+        printf( "\tmovl %%edx,-4(%%ebp)\n" );
 
     /* Switch to the 32-bit stack */
 
@@ -1506,38 +1524,33 @@
             }
             args++;
         }
-    }
 
-    /* Restore ds and es */
+        /* Restore ds and es */
+        printf( "\tpopw %%es\n" );
+        printf( "\tpopw %%ds\n" );
 
-    printf( "\tpopw %%es\n" );
-    printf( "\tpopw %%ds\n" );
-
-    /* Get the return value into dx:ax and clean up the stack */
-
-    if (!reg_func)
-    {
-        if (short_ret)
-        {
-            printf( "\tpopl %%edx\n" );     /* Restore %edx */
-            printf( "\taddl $4,%%esp\n" );  /* Remove DLL id and ordinal */
-        }
-        else
-        {
-            printf( "\tpushl %%eax\n" );
-            printf( "\tpopw %%ax\n" );
-            printf( "\tpopw %%dx\n" );
-            /* Remove API entry point, DLL id and ordinal from the stack */
-            printf( "\taddl $8,%%esp\n" );
-        }
+        /* Remove the entry point from the stack */
+        /* (we don't use add to avoid modifying the carry flag) */
+        printf( "\tpopl %%ebp\n" );
     }
     else
     {
-        /* Remove API entry point, DLL id and ordinal from the stack, */
-        /* but take care not to change the value of the carry flag.   */
+        /* Restore ds and es */
+        printf( "\tpopw %%bp\n" );       /* Remove ip */
+        printf( "\tpopl %%ebp\n" );      /* Remove ds and cs */
+        printf( "\tmovw %%bp,%%ds\n" );  /* Restore ds */
+        printf( "\tpopw %%es\n" );       /* Restore es */
 
-        printf( "\tpopl %%ebp\n" );
-        printf( "\tpopl %%ebp\n" );
+        if (short_ret) printf( "\tpopl %%edx\n" );     /* Restore edx */
+        else
+        {
+            /* Get the return value into dx:ax */
+            printf( "\tpushl %%eax\n" );
+            printf( "\tpopw %%ax\n" );
+            printf( "\tpopw %%dx\n" );
+            /* Remove API entry point */
+            printf( "\taddl $4,%%esp\n" );
+        }
     }
 
     /* Restore bp */
diff --git a/win32/cursoricon32.c b/win32/cursoricon32.c
index 633eee2..e5a102d 100644
--- a/win32/cursoricon32.c
+++ b/win32/cursoricon32.c
@@ -39,6 +39,43 @@
 #include "xmalloc.h"
 #include "task.h"
 
+/* This dictionary could might eventually become a macro for better reuse */
+struct MAP_DWORD_DWORD{
+	DWORD key;
+	DWORD value;
+};
+
+struct MAP_DWORD_DWORD *CURSORICON_map;
+int CURSORICON_count;
+
+BOOL CURSORICON_lookup(DWORD key,DWORD *value)
+{
+	int i;
+	for(i=0;i<CURSORICON_count;i++)
+	{
+		if(key==CURSORICON_map[i].key)
+		{
+			*value=CURSORICON_map[i].value;
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+void CURSORICON_insert(DWORD key,DWORD value)
+{
+	if(!CURSORICON_count)
+	{
+		CURSORICON_count=1;
+		CURSORICON_map=malloc(sizeof(struct MAP_DWORD_DWORD));
+	}else{
+		CURSORICON_count++;
+		CURSORICON_map=realloc(CURSORICON_map,
+			sizeof(struct MAP_DWORD_DWORD)*CURSORICON_count);
+	}
+	CURSORICON_map[CURSORICON_count-1].key=key;
+	CURSORICON_map[CURSORICON_count-1].value=value;
+}
 
 /**********************************************************************
  *	    CURSORICON32_FindBestIcon
@@ -407,8 +444,13 @@
                       (LPWSTR) (fCursor ? RT_CURSOR : RT_ICON )))) return 0;
     if (!(handle = LoadResource32( hInstance, hRsrc ))) return 0;
 
+	/* Use the resource handle as key to detect multiple loading */
+	if(CURSORICON_lookup(handle,&hRet))
+		return hRet;
+
     hRet = CURSORICON32_LoadHandler( handle, hInstance, fCursor );
-    FreeResource32(handle);
+    /* Obsolete - FreeResource32(handle);*/
+	CURSORICON_insert(handle,hRet);
     return hRet;
 }
 
diff --git a/win32/memory.c b/win32/memory.c
index ba58f6f..67455e4 100644
--- a/win32/memory.c
+++ b/win32/memory.c
@@ -296,3 +296,23 @@
    return prot;
 }
 
+
+/******************************************************************
+ *                   IsBadReadPtr
+ */
+BOOL WIN32_IsBadReadPtr(void* ptr, unsigned int bytes)
+{
+	dprintf_global(stddeb,"IsBadReadPtr(%x,%x)\n",ptr,bytes);
+	/* FIXME: Should make check based on actual mappings, here */
+	return FALSE;
+}
+
+/******************************************************************
+ *                   IsBadWritePtr
+ */
+BOOL WIN32_IsBadWritePtr(void* ptr, unsigned int bytes)
+{
+	dprintf_global(stddeb,"IsBadWritePtr(%x,%x)\n",ptr,bytes);
+	/* FIXME: Should make check based on actual mappings, here */
+	return FALSE;
+}
diff --git a/win32/newfns.c b/win32/newfns.c
index c4a99f1..31bb179 100644
--- a/win32/newfns.c
+++ b/win32/newfns.c
@@ -8,7 +8,6 @@
 at a later date. */
 
 #include <stdio.h>
-#include "module.h"
 #include "windows.h"
 #include "winerror.h"
 #include "kernel32.h"
@@ -16,25 +15,6 @@
 #include "debug.h"
 
 /***********************************************************************
- *           GetProcAddress		(KERNEL32.257)
- *
- */
- /* FIXME: This is currently not used, see WIN32_GetProcAddress */
-WINAPI FARPROC W32_GetProcAddress(HMODULE hModule,
-			      LPCSTR lpszProc)
-{
-    char *modulename;
-
-    modulename = MODULE_GetModuleName(hModule);
-    if (modulename == NULL)
-	return (FARPROC) NULL;
-    if (((int) lpszProc) & 0xffff) 
-	return RELAY32_GetEntryPoint(modulename, lpszProc, 0);
-    else
-	return RELAY32_GetEntryPoint(modulename, (char *) NULL, (int) lpszProc);
-}
-
-/***********************************************************************
  *          WinHelpA           (USER32.578)
  */
 BOOL WIN32_WinHelpA(HWND hWnd,LPCSTR lpszHelp,UINT uCommand, DWORD dwData)
diff --git a/win32/process.c b/win32/process.c
index a7a86c8..2901524 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -120,3 +120,32 @@
 	return PE_GetProcAddress(GetExePtr(hModule),function);
 }
 #endif  /* WINELIB */
+
+/**********************************************************************
+ *          GetProcessAffinityMask
+ */
+BOOL GetProcessAffinityMask(HANDLE32 hProcess, LPDWORD lpProcessAffinityMask,
+  LPDWORD lpSystemAffinityMask)
+{
+	dprintf_task(stddeb,"GetProcessAffinityMask(%x,%x,%x)\n",
+		hProcess,(lpProcessAffinityMask?*lpProcessAffinityMask:0),
+		(lpSystemAffinityMask?*lpSystemAffinityMask:0));
+	/* It is definitely important for a process to know on what processor
+	   it is running :-) */
+	if(lpProcessAffinityMask)
+		*lpProcessAffinityMask=1;
+	if(lpSystemAffinityMask)
+		*lpSystemAffinityMask=1;
+	return TRUE;
+}
+
+/**********************************************************************
+ *           SetThreadAffinityMask
+ */
+BOOL SetThreadAffinityMask(HANDLE32 hThread, DWORD dwThreadAffinityMask)
+{
+	dprintf_task(stddeb,"SetThreadAffinityMask(%x,%x)\n",hThread,
+		dwThreadAffinityMask);
+	/* FIXME: We let it fail */
+	return 1;
+}
diff --git a/win32/thread.c b/win32/thread.c
index 3d958d0..5aa0ad5 100644
--- a/win32/thread.c
+++ b/win32/thread.c
@@ -8,6 +8,7 @@
 #include <unistd.h>
 #include <string.h>
 #include "windows.h"
+#include "winbase.h"
 #include "winerror.h"
 #include "kernel32.h"
 #include "stddebug.h"
diff --git a/windows/class.c b/windows/class.c
index 04a05df..1a97140 100644
--- a/windows/class.c
+++ b/windows/class.c
@@ -15,11 +15,10 @@
 #include "ldt.h"
 #include "toolhelp.h"
 #include "stddebug.h"
-/* #define DEBUG_CLASS */
 #include "debug.h"
 
 
-static HCLASS firstClass = 0;
+static CLASS *firstClass = NULL;
 
 
 /***********************************************************************
@@ -27,25 +26,26 @@
  *
  * Dump the content of a class structure to stderr.
  */
-void CLASS_DumpClass( HCLASS hClass )
+void CLASS_DumpClass( CLASS *ptr )
 {
-    CLASS *ptr;
     char className[80];
     int i;
 
-    if (!(ptr = CLASS_FindClassPtr( hClass )))
+    if (((CLASS *)USER_HEAP_LIN_ADDR(ptr->self) != ptr) ||
+        (ptr->wMagic != CLASS_MAGIC))
     {
-        fprintf( stderr, "%04x is not a class handle\n", hClass );
+        fprintf( stderr, "%p is not a class\n", ptr );
         return;
     }
+
     GlobalGetAtomName( ptr->atomName, className, sizeof(className) );
 
-    fprintf( stderr, "Class %04x:\n", hClass );
+    fprintf( stderr, "Class %p:\n", ptr );
     fprintf( stderr,
-             "next=%04x  name=%04x '%s'  style=%04x  wndProc=%08lx\n"
+             "next=%p  name=%04x '%s'  style=%04x  wndProc=%08lx\n"
              "inst=%04x  hdce=%04x  icon=%04x  cursor=%04x  bkgnd=%04x\n"
              "clsExtra=%d  winExtra=%d  #windows=%d\n",
-             ptr->hNext, ptr->atomName, className, ptr->wc.style,
+             ptr->next, ptr->atomName, className, ptr->wc.style,
              (DWORD)ptr->wc.lpfnWndProc, ptr->wc.hInstance, ptr->hdce,
              ptr->wc.hIcon, ptr->wc.hCursor, ptr->wc.hbrBackground,
              ptr->wc.cbClsExtra, ptr->wc.cbWndExtra, ptr->cWindows );
@@ -67,67 +67,94 @@
  */
 void CLASS_WalkClasses(void)
 {
-    HCLASS hClass = firstClass;
     CLASS *ptr;
     char className[80];
 
-    fprintf( stderr, "Class  Name                Style WndProc\n" );
-    while (hClass)
+    fprintf( stderr, " Class   Name                Style WndProc\n" );
+    for (ptr = firstClass; ptr; ptr = ptr->next)
     {
-        if (!(ptr = CLASS_FindClassPtr( hClass )))
-        {
-            fprintf( stderr, "*** Bad class %04x in list\n", hClass );
-            return;
-        }
         GlobalGetAtomName( ptr->atomName, className, sizeof(className) );
-        fprintf( stderr, "%04x  %-20.20s %04x %08lx\n",
-                 hClass, className, ptr->wc.style, (DWORD)ptr->wc.lpfnWndProc);
-        hClass = ptr->hNext;
+        fprintf( stderr, "%08lx %-20.20s %04x %08lx\n", (DWORD)ptr, className,
+                 ptr->wc.style, (DWORD)ptr->wc.lpfnWndProc );
     }
     fprintf( stderr, "\n" );
 }
 
 
 /***********************************************************************
+ *           CLASS_FreeClass
+ *
+ * Free a class structure.
+ */
+static void CLASS_FreeClass( CLASS *classPtr )
+{
+    CLASS **ppClass;
+
+    /* Remove the class from the linked list */
+
+    for (ppClass = &firstClass; *ppClass; ppClass = &(*ppClass)->next)
+        if (*ppClass == classPtr) break;
+    if (!*ppClass)
+    {
+        fprintf(stderr, "ERROR: Class list corrupted\n" );
+        return;
+    }
+    *ppClass = classPtr->next;
+
+    /* Delete the class */
+
+    if (classPtr->hdce) DCE_FreeDCE( classPtr->hdce );
+    if (classPtr->wc.hbrBackground) DeleteObject( classPtr->wc.hbrBackground );
+    GlobalDeleteAtom( classPtr->atomName );
+    if (HIWORD(classPtr->wc.lpszMenuName))
+	USER_HEAP_FREE( (HANDLE)classPtr->wc.lpszMenuName );
+    USER_HEAP_FREE( classPtr->self );
+}
+
+
+/***********************************************************************
+ *           CLASS_FreeModuleClasses
+ */
+void CLASS_FreeModuleClasses( HMODULE hModule )
+{
+    CLASS *ptr, *next;
+  
+    for (ptr = firstClass; ptr; ptr = next)
+    {
+        next = ptr->next;
+	if (ptr->wc.hInstance == hModule) CLASS_FreeClass( ptr );
+    }
+}
+
+
+/***********************************************************************
  *           CLASS_FindClassByName
  *
- * Return a handle and a pointer to the class.
- * 'ptr' can be NULL if the pointer is not needed.
+ * Return a pointer to the class.
  */
-HCLASS CLASS_FindClassByName( SEGPTR name, HINSTANCE hinstance, CLASS **ptr )
+CLASS *CLASS_FindClassByName( SEGPTR name, HINSTANCE hinstance )
 {
     ATOM atom;
-    HCLASS class;
-    CLASS * classPtr;
+    CLASS * class;
 
     if (!(atom = GlobalFindAtom( name ))) return 0;
 
       /* First search task-specific classes */
 
-    for (class = firstClass; (class); class = classPtr->hNext)
+    for (class = firstClass; (class); class = class->next)
     {
-        classPtr = (CLASS *) USER_HEAP_LIN_ADDR(class);
-        if (classPtr->wc.style & CS_GLOBALCLASS) continue;
-        if ((classPtr->atomName == atom) && 
-            ( (hinstance==(HINSTANCE)0xffff) ||
-	      (hinstance == classPtr->wc.hInstance) ) )
-        {
-            if (ptr) *ptr = classPtr;
-            return class;
-        }
+        if (class->wc.style & CS_GLOBALCLASS) continue;
+        if ((class->atomName == atom) && 
+            ((hinstance==(HINSTANCE)0xffff) ||
+             (hinstance == class->wc.hInstance))) return class;
     }
     
       /* Then search global classes */
 
-    for (class = firstClass; (class); class = classPtr->hNext)
+    for (class = firstClass; (class); class = class->next)
     {
-        classPtr = (CLASS *) USER_HEAP_LIN_ADDR(class);
-        if (!(classPtr->wc.style & CS_GLOBALCLASS)) continue;
-        if (classPtr->atomName == atom)
-        {
-            if (ptr) *ptr = classPtr;
-            return class;
-        }
+        if (!(class->wc.style & CS_GLOBALCLASS)) continue;
+        if (class->atomName == atom) return class;
     }
 
     return 0;
@@ -135,28 +162,12 @@
 
 
 /***********************************************************************
- *           CLASS_FindClassPtr
- *
- * Return a pointer to the CLASS structure corresponding to a HCLASS.
- */
-CLASS * CLASS_FindClassPtr( HCLASS hclass )
-{
-    CLASS * ptr;
-    
-    if (!hclass) return NULL;
-    ptr = (CLASS *) USER_HEAP_LIN_ADDR( hclass );
-    if (ptr->wMagic != CLASS_MAGIC) return NULL;
-    return ptr;
-}
-
-
-/***********************************************************************
  *           RegisterClass    (USER.57)
  */
 ATOM RegisterClass( LPWNDCLASS class )
 {
-    CLASS * newClass, * prevClassPtr;
-    HCLASS handle, prevClass;
+    CLASS * newClass, * prevClass;
+    HCLASS handle;
     int classExtra;
 
     dprintf_class( stddeb, "RegisterClass: wndproc=%08lx hinst=%04x name='%s' background %04x\n",
@@ -171,15 +182,14 @@
     class->hInstance = GetExePtr( class->hInstance );
     
       /* Check if a class with this name already exists */
-    prevClass = CLASS_FindClassByName( class->lpszClassName,
-                                       class->hInstance, &prevClassPtr );
+    prevClass = CLASS_FindClassByName( class->lpszClassName, class->hInstance);
     if (prevClass)
     {
 	  /* Class can be created only if it is local and */
 	  /* if the class with the same name is global.   */
 
 	if (class->style & CS_GLOBALCLASS) return 0;
-	if (!(prevClassPtr->wc.style & CS_GLOBALCLASS)) return 0;
+	if (!(prevClass->wc.style & CS_GLOBALCLASS)) return 0;
     }
 
       /* Create class */
@@ -188,7 +198,8 @@
     handle = USER_HEAP_ALLOC( sizeof(CLASS) + classExtra );
     if (!handle) return 0;
     newClass = (CLASS *) USER_HEAP_LIN_ADDR( handle );
-    newClass->hNext         = firstClass;
+    newClass->self          = handle;
+    newClass->next          = firstClass;
     newClass->wMagic        = CLASS_MAGIC;
     newClass->cWindows      = 0;  
     newClass->wc            = *class;
@@ -216,7 +227,7 @@
     }
 
     if (classExtra) memset( newClass->wExtra, 0, classExtra );
-    firstClass = handle;
+    firstClass = newClass;
     return newClass->atomName;
 }
 
@@ -226,40 +237,16 @@
  */
 BOOL UnregisterClass( SEGPTR className, HANDLE hinstance )
 {
-    HANDLE class, prevClass;
-    CLASS * classPtr, * prevClassPtr;
-    
+    CLASS *classPtr;
+
     hinstance = GetExePtr( hinstance );
+
       /* Check if we can remove this class */
-    class = CLASS_FindClassByName( className, hinstance, &classPtr );
-    if (!class) return FALSE;
+    if (!(classPtr = CLASS_FindClassByName( className, hinstance )))
+        return FALSE;
     if ((classPtr->wc.hInstance != hinstance) || (classPtr->cWindows > 0))
 	return FALSE;
-    
-      /* Remove the class from the linked list */
-    if (firstClass == class) firstClass = classPtr->hNext;
-    else
-    {
-	for (prevClass = firstClass; prevClass; prevClass=prevClassPtr->hNext)
-	{
-	    prevClassPtr = (CLASS *) USER_HEAP_LIN_ADDR(prevClass);
-	    if (prevClassPtr->hNext == class) break;
-	}
-	if (!prevClass)
-	{
-	    fprintf(stderr, "ERROR: Class list corrupted\n" );
-	    return FALSE;
-	}
-	prevClassPtr->hNext = classPtr->hNext;
-    }
-
-      /* Delete the class */
-    if (classPtr->hdce) DCE_FreeDCE( classPtr->hdce );
-    if (classPtr->wc.hbrBackground) DeleteObject( classPtr->wc.hbrBackground );
-    GlobalDeleteAtom( classPtr->atomName );
-    if (HIWORD(classPtr->wc.lpszMenuName))
-	USER_HEAP_FREE( (HANDLE)classPtr->wc.lpszMenuName );
-    USER_HEAP_FREE( class );
+    CLASS_FreeClass( classPtr );
     return TRUE;
 }
 
@@ -269,7 +256,24 @@
  */
 WORD GetClassWord( HWND hwnd, short offset )
 {
-    return (WORD)GetClassLong( hwnd, offset );
+    WND * wndPtr;
+    
+    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
+    if (offset >= 0)
+        return *(WORD *)(((char *)wndPtr->class->wExtra) + offset);
+    switch(offset)
+    {
+        case GCW_HBRBACKGROUND: return wndPtr->class->wc.hbrBackground;
+        case GCW_HCURSOR:       return wndPtr->class->wc.hCursor;
+        case GCW_HICON:         return wndPtr->class->wc.hIcon;
+        case GCW_HMODULE:       return wndPtr->class->wc.hInstance;
+        case GCW_CBWNDEXTRA:    return wndPtr->class->wc.cbWndExtra;
+        case GCW_CBCLSEXTRA:    return wndPtr->class->wc.cbClsExtra;
+        case GCW_STYLE:         return wndPtr->class->wc.style;
+        case GCW_ATOM:          return wndPtr->class->atomName;
+    }
+    fprintf(stderr, "Warning: invalid offset %d for GetClassWord()\n", offset);
+    return 0;
 }
 
 
@@ -278,13 +282,26 @@
  */
 WORD SetClassWord( HWND hwnd, short offset, WORD newval )
 {
-    CLASS * classPtr;
     WND * wndPtr;
     WORD *ptr, retval = 0;
     
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
-    if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
-    ptr = (WORD *)(((char *)classPtr->wExtra) + offset);
+    if (offset >= 0) ptr = (WORD *)(((char *)wndPtr->class->wExtra) + offset);
+    else switch(offset)
+    {
+        case GCW_HBRBACKGROUND: ptr = &wndPtr->class->wc.hbrBackground; break;
+        case GCW_HCURSOR:       ptr = &wndPtr->class->wc.hCursor; break;
+        case GCW_HICON:         ptr = &wndPtr->class->wc.hIcon; break;
+        case GCW_HMODULE:       ptr = &wndPtr->class->wc.hInstance; break;
+        case GCW_CBWNDEXTRA:    ptr = &wndPtr->class->wc.cbWndExtra; break;
+        case GCW_CBCLSEXTRA:    ptr = &wndPtr->class->wc.cbClsExtra; break;
+        case GCW_STYLE:         ptr = &wndPtr->class->wc.style; break;
+        case GCW_ATOM:          ptr = &wndPtr->class->atomName; break;
+        default:
+            fprintf( stderr, "Warning: invalid offset %d for SetClassWord()\n",
+                     offset);
+            return 0;
+    }
     retval = *ptr;
     *ptr = newval;
     return retval;
@@ -296,12 +313,18 @@
  */
 LONG GetClassLong( HWND hwnd, short offset )
 {
-    CLASS * classPtr;
     WND * wndPtr;
     
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
-    if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
-    return *(LONG *)(((char *)classPtr->wExtra) + offset);
+    if (offset >= 0)
+        return *(WORD *)(((char *)wndPtr->class->wExtra) + offset);
+    switch(offset)
+    {
+        case GCL_MENUNAME: return (LONG)wndPtr->class->wc.lpszMenuName;
+        case GCL_WNDPROC:  return (LONG)wndPtr->class->wc.lpfnWndProc;
+    }
+    fprintf(stderr, "Warning: invalid offset %d for GetClassLong()\n", offset);
+    return 0;
 }
 
 
@@ -310,13 +333,20 @@
  */
 LONG SetClassLong( HWND hwnd, short offset, LONG newval )
 {
-    CLASS * classPtr;
     WND * wndPtr;
     LONG *ptr, retval = 0;
     
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
-    if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
-    ptr = (LONG *)(((char *)classPtr->wExtra) + offset);
+    if (offset >= 0) ptr = (LONG *)(((char *)wndPtr->class->wExtra) + offset);
+    else switch(offset)
+    {
+        case GCL_MENUNAME: ptr = (LONG*)&wndPtr->class->wc.lpszMenuName; break;
+        case GCL_WNDPROC:  ptr = (LONG*)&wndPtr->class->wc.lpfnWndProc; break;
+        default:
+            fprintf( stderr, "Warning: invalid offset %d for SetClassLong()\n",
+                     offset);
+            return 0;
+    }
     retval = *ptr;
     *ptr = newval;
     return retval;
@@ -329,14 +359,12 @@
 int GetClassName(HWND hwnd, LPSTR lpClassName, short maxCount)
 {
     WND *wndPtr;
-    CLASS *classPtr;
 
     /* FIXME: We have the find the correct hInstance */
     dprintf_class(stddeb,"GetClassName(%04x,%p,%d)\n",hwnd,lpClassName,maxCount);
     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
-    if (!(classPtr = CLASS_FindClassPtr(wndPtr->hClass))) return 0;
     
-    return GlobalGetAtomName(classPtr->atomName, lpClassName, maxCount);
+    return GlobalGetAtomName( wndPtr->class->atomName, lpClassName, maxCount );
 }
 
 
@@ -353,7 +381,7 @@
 
     hInstance = GetExePtr( hInstance );
     
-    if (!(CLASS_FindClassByName( name, hInstance, &classPtr))) return FALSE;
+    if (!(classPtr = CLASS_FindClassByName( name, hInstance ))) return FALSE;
     if (hInstance && (hInstance != classPtr->wc.hInstance)) return FALSE;
 
     memcpy(lpWndClass, &(classPtr->wc), sizeof(WNDCLASS));
@@ -366,7 +394,7 @@
  */
 BOOL ClassFirst( CLASSENTRY *pClassEntry )
 {
-    pClassEntry->wNext = firstClass;
+    pClassEntry->wNext = 1;
     return ClassNext( pClassEntry );
 }
 
@@ -376,12 +404,19 @@
  */
 BOOL ClassNext( CLASSENTRY *pClassEntry )
 {
-    CLASS *classPtr = (CLASS *) USER_HEAP_LIN_ADDR( pClassEntry->wNext );
-    if (!classPtr) return FALSE;
+    int i;
+    CLASS *class = firstClass;
 
-    pClassEntry->hInst = classPtr->wc.hInstance;
-    pClassEntry->wNext = classPtr->hNext;
-    GlobalGetAtomName( classPtr->atomName, pClassEntry->szClassName,
+    if (!pClassEntry->wNext) return FALSE;
+    for (i = 1; (i < pClassEntry->wNext) && class; i++) class = class->next;
+    if (!class)
+    {
+        pClassEntry->wNext = 0;
+        return FALSE;
+    }
+    pClassEntry->hInst = class->wc.hInstance;
+    pClassEntry->wNext++;
+    GlobalGetAtomName( class->atomName, pClassEntry->szClassName,
                        sizeof(pClassEntry->szClassName) );
     return TRUE;
 }
diff --git a/windows/dce.c b/windows/dce.c
index 3ff9f54..afdf32e 100644
--- a/windows/dce.c
+++ b/windows/dce.c
@@ -310,9 +310,9 @@
                    DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
 	if (wndPtr)
 	{
-            if (!(WIN_CLASS_STYLE(wndPtr) & (CS_OWNDC | CS_CLASSDC)))
+            if (!(wndPtr->class->wc.style & (CS_OWNDC | CS_CLASSDC)))
 		flags |= DCX_CACHE;
-            if (WIN_CLASS_STYLE(wndPtr) & CS_PARENTDC) flags |= DCX_PARENTCLIP;
+            if (wndPtr->class->wc.style & CS_PARENTDC) flags |= DCX_PARENTCLIP;
 	    if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN;
 	    if (wndPtr->dwStyle & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
 	}
diff --git a/windows/defwnd.c b/windows/defwnd.c
index f84bdda..cce7311 100644
--- a/windows/defwnd.c
+++ b/windows/defwnd.c
@@ -8,7 +8,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include "win.h"
-#include "class.h"
 #include "user.h"
 #include "nonclient.h"
 #include "winpos.h"
@@ -52,7 +51,6 @@
  */
 LRESULT DefWindowProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
 {
-    CLASS * classPtr;
     LPSTR textPtr;
     int len;
     WND * wndPtr = WIN_FindWndPtr( hwnd );
@@ -164,19 +162,18 @@
     case WM_ERASEBKGND:
     case WM_ICONERASEBKGND:
 	{
-	    if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0;
-	    if (!classPtr->wc.hbrBackground) return 0;
-            if (classPtr->wc.hbrBackground <= (HBRUSH)(COLOR_MAX+1))
+	    if (!wndPtr->class->wc.hbrBackground) return 0;
+            if (wndPtr->class->wc.hbrBackground <= (HBRUSH)(COLOR_MAX+1))
             {
                  HBRUSH hbrush;
                  hbrush = CreateSolidBrush(
-                     GetSysColor(((DWORD)classPtr->wc.hbrBackground)-1));
+                     GetSysColor(((DWORD)wndPtr->class->wc.hbrBackground)-1));
                  FillWindow( GetParent(hwnd), hwnd, (HDC)wParam, hbrush);
                  DeleteObject (hbrush);
             }
             else
 	         FillWindow( GetParent(hwnd), hwnd, (HDC)wParam,
-		        classPtr->wc.hbrBackground );
+                             wndPtr->class->wc.hbrBackground );
 	    return 1;
 	}
 
diff --git a/windows/graphics.c b/windows/graphics.c
index ba65dbe..0a68479 100644
--- a/windows/graphics.c
+++ b/windows/graphics.c
@@ -994,3 +994,26 @@
 {
     return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
 }
+
+
+/**********************************************************************
+ *          DrawEdge  (USER.659)
+ */
+BOOL WINAPI 
+DrawEdge(HDC hdc, LPRECT qrc, UINT edge, UINT flags) {
+	fprintf(stdnimp,"DrawEdge(%x,%p,%d,%x), empty stub!\n",
+		hdc,qrc,edge,flags
+	);
+	return TRUE;
+}
+
+/**********************************************************************
+ *          DrawFrameControl  (USER.656)
+ */
+BOOL WINAPI 
+DrawFrameControl(HDC hdc, LPRECT qrc, UINT edge, UINT flags) {
+	fprintf(stdnimp,"DrawFrameControl(%x,%p,%d,%x), empty stub!\n",
+		hdc,qrc,edge,flags
+	);
+	return TRUE;
+}
diff --git a/windows/hook.c b/windows/hook.c
index dc25685..d68e038 100644
--- a/windows/hook.c
+++ b/windows/hook.c
@@ -32,7 +32,7 @@
 static HANDLE HOOK_GetNextHook( HANDLE hook )
 {
     HOOKDATA *data = (HOOKDATA *)USER_HEAP_LIN_ADDR( hook );
-    if (!data) return 0;
+    if (!data || !hook) return 0;
     if (data->next) return data->next;
     if (!data->ownerQueue) return 0;  /* Already system hook */
     /* Now start enumerating the system hooks */
@@ -45,12 +45,12 @@
  *
  * Get the first hook for a given type.
  */
-static HANDLE HOOK_GetHook( short id )
+static HANDLE HOOK_GetHook( short id , HQUEUE hQueue )
 {
     MESSAGEQUEUE *queue;
     HANDLE hook = 0;
 
-    if ((queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) )) != NULL)
+    if ((queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(hQueue) )) != NULL)
         hook = queue->hooks[id - WH_FIRST_HOOK];
     if (!hook) hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
     return hook;
@@ -206,13 +206,71 @@
  */
 DWORD HOOK_CallHooks( short id, short code, WPARAM wParam, LPARAM lParam )
 {
-    HANDLE hook = HOOK_GetHook( id );
+    HANDLE hook = HOOK_GetHook( id , 0 );
     if (!hook) return 0;
     return HOOK_CallHook( hook, code, wParam, lParam );
 }
 
 
 /***********************************************************************
+ *	     HOOK_FreeModuleHooks
+ */
+void HOOK_FreeModuleHooks( HMODULE hModule )
+{
+ /* remove all system hooks registered by this module */
+
+  HOOKDATA*     hptr;
+  HHOOK         hook, next;
+  int           id;
+
+  for( id = WH_FIRST_HOOK; id <= WH_LAST_HOOK; id++ )
+    {
+       hook = HOOK_systemHooks[id - WH_FIRST_HOOK];
+       while( hook )
+          if( (hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook)) )
+	    {
+	      next = hptr->next;
+	      if( hptr->ownerModule == hModule )
+                {
+                  hptr->inHookProc = 0;
+                  HOOK_RemoveHook(hook);
+                }
+	      hook = next;
+	    }
+	  else hook = 0;
+    }
+}
+
+/***********************************************************************
+ *	     HOOK_FreeQueueHooks
+ */
+void HOOK_FreeQueueHooks( HQUEUE hQueue )
+{
+  /* remove all hooks registered by this queue */
+
+  HOOKDATA*	hptr = NULL;
+  HHOOK 	hook, next;
+  int 		id;
+
+  for( id = WH_FIRST_HOOK; id <= WH_LAST_HOOK; id++ )
+    {
+       hook = HOOK_GetHook( id, hQueue );
+       while( hook )
+	{
+	  next = HOOK_GetNextHook(hook);
+
+	  hptr = (HOOKDATA *)USER_HEAP_LIN_ADDR(hook);
+	  if( hptr && hptr->ownerQueue == hQueue )
+	    {
+	      hptr->inHookProc = 0;
+	      HOOK_RemoveHook(hook);
+	    }
+	  hook = next;
+	}
+    }
+}
+
+/***********************************************************************
  *           SetWindowsHook   (USER.121)
  */
 FARPROC SetWindowsHook( short id, HOOKPROC proc )
@@ -243,7 +301,7 @@
  */
 BOOL UnhookWindowsHook( short id, HOOKPROC proc )
 {
-    HANDLE hook = HOOK_GetHook( id );
+    HANDLE hook = HOOK_GetHook( id , 0 );
 
     dprintf_hook( stddeb, "UnhookWindowsHook: %d %08lx\n", id, (DWORD)proc );
 
diff --git a/windows/mdi.c b/windows/mdi.c
index 1a533f8..ea7a450 100644
--- a/windows/mdi.c
+++ b/windows/mdi.c
@@ -12,6 +12,8 @@
  *        SetWindowPos(childHwnd,...) implicitly calls it if SWP_NOACTIVATE
  *        is not used.
  *
+ *        Also, Excel and WinWord do _not_ use MDI so if you're trying
+ *	  to fix them look elsewhere. 
  */
 
 #include <stdlib.h>
diff --git a/windows/message.c b/windows/message.c
index 78942bc..1237a8e 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -127,7 +127,7 @@
 	if (dbl_click && (hittest == HTCLIENT))
 	{
 	    /* Check whether window wants the double click message. */
-            dbl_click = (WIN_CLASS_STYLE(pWnd) & CS_DBLCLKS) != 0;
+            dbl_click = (pWnd->class->wc.style & CS_DBLCLKS) != 0;
 	}
 
 	if (dbl_click) switch(msg->message)
@@ -812,6 +812,12 @@
     return GlobalAddAtom( str );
 }
 
+WORD RegisterWindowMessageA( LPSTR str )
+{
+    char buffer[256];
+    lstrcpyn( buffer, str, sizeof(buffer) );
+    return RegisterWindowMessage(MAKE_SEGPTR(buffer));
+}
 
 /***********************************************************************
  *           GetTickCount    (USER.13) (KERNEL32.299)
diff --git a/windows/nonclient.c b/windows/nonclient.c
index c94ca9c..57ba892 100644
--- a/windows/nonclient.c
+++ b/windows/nonclient.c
@@ -6,7 +6,6 @@
  */
 
 #include "win.h"
-#include "class.h"
 #include "message.h"
 #include "sysmetrics.h"
 #include "user.h"
@@ -644,11 +643,10 @@
      */
     if (IsIconic(hwnd))
     {
-        HICON hIcon = WIN_CLASS_INFO(wndPtr).hIcon;
-        if (hIcon)  
+        if (wndPtr->class->wc.hIcon)
         {
             SendMessage(hwnd, WM_ICONERASEBKGND, (WPARAM)hdc, 0);
-            DrawIcon(hdc, 0, 0, hIcon);
+            DrawIcon( hdc, 0, 0, wndPtr->class->wc.hIcon );
         }
         ReleaseDC(hwnd, hdc);
         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
@@ -783,12 +781,10 @@
     case HTCLIENT:
 	{
 	    WND *wndPtr;
-	    CLASS *classPtr;
 	    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) break;
-	    if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) break;
-	    if (classPtr->wc.hCursor)
+	    if (wndPtr->class->wc.hCursor)
 	    {
-		SetCursor( classPtr->wc.hCursor );
+		SetCursor( wndPtr->class->wc.hCursor );
 		return TRUE;
 	    }
 	    else return FALSE;
diff --git a/windows/painting.c b/windows/painting.c
index 31573ff..d3f7694 100644
--- a/windows/painting.c
+++ b/windows/painting.c
@@ -317,8 +317,8 @@
             {
               /* Don't send WM_ERASEBKGND to icons */
               /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
-                if (!(wndPtr->dwStyle & WS_MINIMIZE)
-                    || !WIN_CLASS_INFO(wndPtr).hIcon)
+                if (!(wndPtr->dwStyle & WS_MINIMIZE) ||
+                    !wndPtr->class->wc.hIcon)
                 {
                     if (SendMessage( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ))
                         wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
diff --git a/windows/queue.c b/windows/queue.c
index 0606645..04d8081 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -91,6 +91,8 @@
     MESSAGEQUEUE * msgQueue;
     int queueSize;
 
+    dprintf_msg(stddeb,"Creating message queue...\n");
+
     queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
     if (!(hQueue = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, queueSize )))
         return 0;
@@ -113,6 +115,8 @@
     MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)GlobalLock(hQueue);
     HQUEUE *pPrev;
 
+    dprintf_msg(stddeb,"Deleting message queue %04x\n", hQueue);
+
     if (!hQueue || !msgQueue)
     {
 	dprintf_msg(stddeb,"DeleteMsgQueue: invalid argument.\n");
@@ -399,6 +403,8 @@
     HQUEUE hQueue, hNewQueue;
     MESSAGEQUEUE *queuePtr;
 
+    dprintf_msg(stddeb,"SetMessageQueue: task %04x size %i\n", GetCurrentTask(), size); 
+
     if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
 
     if( !(hNewQueue = QUEUE_CreateMsgQueue( size ))) 
diff --git a/windows/win.c b/windows/win.c
index 9a41b5d..ce2b70a 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -66,7 +66,6 @@
  */
 void WIN_DumpWindow( HWND hwnd )
 {
-    CLASS *classPtr;
     WND *ptr;
     char className[80];
     int i;
@@ -82,13 +81,13 @@
 
     fprintf( stderr, "Window %04x (%p):\n", hwnd, ptr );
     fprintf( stderr,
-             "next=%p  child=%p  parent=%p  owner=%p  class=%04x '%s'\n"
+             "next=%p  child=%p  parent=%p  owner=%p  class=%p '%s'\n"
              "inst=%04x  taskQ=%04x  updRgn=%04x  active=%04x hdce=%04x  idmenu=%04x\n"
              "style=%08lx  exstyle=%08lx  wndproc=%08lx  text=%04x '%s'\n"
              "client=%d,%d-%d,%d  window=%d,%d-%d,%d  iconpos=%d,%d  maxpos=%d,%d\n"
              "sysmenu=%04x  flags=%04x  props=%04x  vscroll=%04x  hscroll=%04x\n",
              ptr->next, ptr->child, ptr->parent, ptr->owner,
-             ptr->hClass, className, ptr->hInstance, ptr->hmemTaskQ,
+             ptr->class, className, ptr->hInstance, ptr->hmemTaskQ,
              ptr->hrgnUpdate, ptr->hwndLastActive, ptr->hdce, ptr->wIDmenu,
              ptr->dwStyle, ptr->dwExStyle, (DWORD)ptr->lpfnWndProc, ptr->hText,
              ptr->hText ? (char*)USER_HEAP_LIN_ADDR(ptr->hText) : "",
@@ -98,11 +97,10 @@
              ptr->ptIconPos.y, ptr->ptMaxPos.x, ptr->ptMaxPos.y, ptr->hSysMenu,
              ptr->flags, ptr->hProp, ptr->hVScroll, ptr->hHScroll );
 
-    if ((classPtr = CLASS_FindClassPtr( ptr->hClass )) &&
-        classPtr->wc.cbWndExtra)
+    if (ptr->class->wc.cbWndExtra)
     {
         fprintf( stderr, "extra bytes:" );
-        for (i = 0; i < classPtr->wc.cbWndExtra; i++)
+        for (i = 0; i < ptr->class->wc.cbWndExtra; i++)
             fprintf( stderr, " %02x", *((BYTE*)ptr->wExtra+i) );
         fprintf( stderr, "\n" );
     }
@@ -118,7 +116,6 @@
 void WIN_WalkWindows( HWND hwnd, int indent )
 {
     WND *ptr;
-    CLASS *classPtr;
     char className[80];
 
     ptr = hwnd ? WIN_FindWndPtr( hwnd ) : pWndDesktop;
@@ -135,9 +132,8 @@
     while (ptr)
     {
         fprintf(stderr, "%*s%04x%*s", indent, "", ptr->hwndSelf, 13-indent,"");
-        
-        if (!(classPtr = CLASS_FindClassPtr( ptr->hClass ))) strcpy( className, "#NULL#" );
-        else GlobalGetAtomName( classPtr->atomName, className, sizeof(className) );
+
+        GlobalGetAtomName( ptr->class->atomName, className, sizeof(className));
         
         fprintf( stderr, "%08lx %-6.4x %-17.17s %08x %04x:%04x\n",
                  (DWORD)ptr, ptr->hmemTaskQ, className,
@@ -307,14 +303,13 @@
 static void WIN_DestroyWindow( HWND hwnd )
 {
     WND *wndPtr = WIN_FindWndPtr( hwnd );
-    CLASS *classPtr = CLASS_FindClassPtr( wndPtr->hClass );
 
 #ifdef CONFIG_IPC
     if (main_block)
 	DDE_DestroyWindow(hwnd);
 #endif  /* CONFIG_IPC */
 	
-    if (!wndPtr || !classPtr) return;
+    if (!wndPtr) return;
     WIN_UnlinkWindow( hwnd ); /* Remove the window from the linked list */
     wndPtr->dwMagic = 0;  /* Mark it as invalid */
     wndPtr->hwndSelf = 0;
@@ -329,28 +324,44 @@
     }
     if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
     if (wndPtr->window) XDestroyWindow( display, wndPtr->window );
-    if (classPtr->wc.style & CS_OWNDC) DCE_FreeDCE( wndPtr->hdce );
-    classPtr->cWindows--;
+    if (wndPtr->class->wc.style & CS_OWNDC) DCE_FreeDCE( wndPtr->hdce );
+    wndPtr->class->cWindows--;
     USER_HEAP_FREE( hwnd );
 }
 
 
 /***********************************************************************
+ *	     WIN_DestroyQueueWindows
+ */
+void WIN_DestroyQueueWindows( WND* wnd, HQUEUE hQueue )
+{
+    WND* next;
+
+    while (wnd)
+    {
+        next = wnd->next;
+        if (wnd->hmemTaskQ == hQueue) DestroyWindow( wnd->hwndSelf );
+        else WIN_DestroyQueueWindows( wnd->child, hQueue );
+        wnd = next;
+    }
+}
+
+
+/***********************************************************************
  *           WIN_CreateDesktopWindow
  *
  * Create the desktop window.
  */
 BOOL WIN_CreateDesktopWindow(void)
 {
-    HCLASS hclass;
-    CLASS *classPtr;
+    CLASS *class;
     HDC hdc;
     HWND hwndDesktop;
 
-    if (!(hclass = CLASS_FindClassByName( DESKTOP_CLASS_ATOM, 0, &classPtr )))
+    if (!(class = CLASS_FindClassByName( DESKTOP_CLASS_ATOM, 0 )))
 	return FALSE;
 
-    hwndDesktop = USER_HEAP_ALLOC( sizeof(WND)+classPtr->wc.cbWndExtra );
+    hwndDesktop = USER_HEAP_ALLOC( sizeof(WND)+class->wc.cbWndExtra );
     if (!hwndDesktop) return FALSE;
     pWndDesktop = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
 
@@ -358,9 +369,9 @@
     pWndDesktop->child             = NULL;
     pWndDesktop->parent            = NULL;
     pWndDesktop->owner             = NULL;
+    pWndDesktop->class             = class;
     pWndDesktop->dwMagic           = WND_MAGIC;
     pWndDesktop->hwndSelf          = hwndDesktop;
-    pWndDesktop->hClass            = hclass;
     pWndDesktop->hInstance         = 0;
     pWndDesktop->rectWindow.left   = 0;
     pWndDesktop->rectWindow.top    = 0;
@@ -375,7 +386,7 @@
     pWndDesktop->hmemTaskQ         = 0; /* Desktop does not belong to a task */
     pWndDesktop->hrgnUpdate        = 0;
     pWndDesktop->hwndLastActive    = hwndDesktop;
-    pWndDesktop->lpfnWndProc       = classPtr->wc.lpfnWndProc;
+    pWndDesktop->lpfnWndProc       = class->wc.lpfnWndProc;
     pWndDesktop->dwStyle           = WS_VISIBLE | WS_CLIPCHILDREN |
                                      WS_CLIPSIBLINGS;
     pWndDesktop->dwExStyle         = 0;
@@ -418,7 +429,7 @@
 		     DWORD style, INT x, INT y, INT width, INT height,
 		     HWND parent, HMENU menu, HANDLE instance, SEGPTR data ) 
 {
-    HANDLE class, hwnd;
+    HANDLE hwnd;
     CLASS *classPtr;
     WND *wndPtr;
     POINT maxSize, maxPos, minTrack, maxTrack;
@@ -427,8 +438,6 @@
     XSetWindowAttributes win_attr;
     Atom XA_WM_DELETE_WINDOW;
 
-    /* FIXME: windowName and className should be SEGPTRs */
-
     dprintf_win( stddeb, "CreateWindowEx: " );
     if (HIWORD(windowName))
 	dprintf_win( stddeb, "'%s' ", (char *)PTR_SEG_TO_LIN(windowName) );
@@ -468,8 +477,7 @@
 	}
     }
 
-    if (!(class = CLASS_FindClassByName( className, GetExePtr(instance),
-                                         &classPtr )))
+    if (!(classPtr = CLASS_FindClassByName( className, GetExePtr(instance) )))
     {
         fprintf(stderr,"CreateWindow BAD CLASSNAME " );
         if (HIWORD(className)) fprintf( stderr, "'%s'\n", 
@@ -500,9 +508,9 @@
     wndPtr->parent         = (style & WS_CHILD) ? WIN_FindWndPtr( parent ) : pWndDesktop;
     wndPtr->owner          = (style & WS_CHILD) ? NULL : WIN_FindWndPtr(WIN_GetTopParent(parent));
     wndPtr->window         = 0;
+    wndPtr->class          = classPtr;
     wndPtr->dwMagic        = WND_MAGIC;
     wndPtr->hwndSelf       = hwnd;
-    wndPtr->hClass         = class;
     wndPtr->hInstance      = instance;
     wndPtr->ptIconPos.x    = -1;
     wndPtr->ptIconPos.y    = -1;
@@ -679,7 +687,6 @@
 BOOL DestroyWindow( HWND hwnd )
 {
     WND * wndPtr;
-    CLASS * classPtr;
 
     dprintf_win(stddeb, "DestroyWindow(%04x)\n", hwnd);
     
@@ -687,7 +694,6 @@
 
     if (hwnd == pWndDesktop->hwndSelf) return FALSE; /* Can't destroy desktop*/
     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
-    if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return FALSE;
 
       /* Hide the window */
 
@@ -754,22 +760,19 @@
  */
 HWND FindWindow( SEGPTR ClassMatch, LPSTR TitleMatch )
 {
-    HCLASS hclass;
-    CLASS *classPtr;
     WND *wndPtr;
+    CLASS *class = NULL;
 
     if (ClassMatch)
     {
-	hclass = CLASS_FindClassByName( ClassMatch, (HINSTANCE)0xffff,
-                                        &classPtr );
-	if (!hclass) return 0;
+	if (!(class = CLASS_FindClassByName( ClassMatch, (HINSTANCE)0xffff )))
+            return 0;
     }
-    else hclass = 0;
 
     wndPtr = pWndDesktop->child;
     while (wndPtr)
     {
-	if (!hclass || (wndPtr->hClass == hclass))
+	if (!class || (wndPtr->class == class))
 	{
 	      /* Found matching class */
 	    if (!TitleMatch) return wndPtr->hwndSelf;
diff --git a/windows/winpos.c b/windows/winpos.c
index 09ad76a..9e7f073 100644
--- a/windows/winpos.c
+++ b/windows/winpos.c
@@ -1056,8 +1056,6 @@
  */
 static void WINPOS_SizeMoveClean(WND* Wnd, HRGN oldVisRgn, LPRECT lpOldWndRect, LPRECT lpOldClientRect, BOOL bNoCopy )
 {
- /* visible regions are in window coordinates */
-
  HRGN newVisRgn    = DCE_GetVisRgn(Wnd->hwndSelf, DCX_WINDOW | DCX_CLIPSIBLINGS );
  HRGN dirtyRgn     = CreateRectRgn(0,0,0,0);
  int  other, my;
diff --git a/wine.man b/wine.man
index c08f564..8d5f17c 100644
--- a/wine.man
+++ b/wine.man
@@ -104,7 +104,7 @@
 .I -language xx
 Set the language to
 .I xx
-(one of En, Es, De, No, Fr, Fi, Da, Cz, Eo, It)
+(one of En, Es, De, No, Fr, Fi, Da, Cz, Eo, It, Ko)
 .TP
 .I -managed
 Create each top-level window as a properly managed X window