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/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, */