Reorganization of the loader to correctly load and free libraries and
implementation of load order to load different types of libraries.

diff --git a/if1632/builtin.c b/if1632/builtin.c
index 8cc9fc8..f66f150 100644
--- a/if1632/builtin.c
+++ b/if1632/builtin.c
@@ -325,85 +325,3 @@
     INT_BARF( context, ordinal - FIRST_INTERRUPT_ORDINAL );
 }
 
-
-/***********************************************************************
- *           BUILTIN_ParseDLLOptions
- *
- * Set runtime DLL usage flags
- */
-BOOL BUILTIN_ParseDLLOptions( char *str )
-{
-    BUILTIN16_DLL *dll;
-    char *p,*last;
-
-
-    last = str;
-    while (*str)
-    {
-        while (*str && (*str==',' || isspace(*str))) str++;
-        if (!*str) {
-	    *last = '\0'; /* cut off garbage at end at */
-	    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 (!lstrncmpiA( str, dll->descr->name, (int)(p - str) ))
-            {
-	        if (dll->descr->name[(int)(p-str)])  /* only partial match */
-			continue;
-                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) {
-	    /* not found, but could get handled by BUILTIN32_, so move last */
-	    last = p;
-	    str = p;
-	} else {
-	    /* handled. cut out the "[+-]DLL," string, so it isn't handled
-	     * by BUILTIN32
-	     */
-	    if (*p) {
-		memcpy(last,p,strlen(p)+1);
-		str = last;
-	    } else {
-	    	*last = '\0';
-	    	break;
-	    }
-	}
-    }
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           BUILTIN_PrintDLLs
- *
- * Print the list of built-in DLLs that can be disabled.
- */
-void BUILTIN_PrintDLLs(void)
-{
-    int i;
-    BUILTIN16_DLL *dll;
-
-    MSG("Example: -dll -ole2    Do not use emulated OLE2.DLL\n");
-    MSG("Available Win16 DLLs:\n");
-    for (i = 0, dll = BuiltinDLLs; dll->descr; dll++)
-    {
-        if (!(dll->flags & DLL_FLAG_ALWAYS_USED))
-            MSG("%-9s%c", dll->descr->name,
-                     ((++i) % 8) ? ' ' : '\n' );
-    }
-    MSG("\n");
-    BUILTIN32_PrintDLLs();
-}
diff --git a/include/builtin32.h b/include/builtin32.h
index 7423cdb..3b263d6 100644
--- a/include/builtin32.h
+++ b/include/builtin32.h
@@ -27,8 +27,6 @@
                                              unsigned int *typemask );
 extern void BUILTIN32_Unimplemented( const BUILTIN32_DESCRIPTOR *descr,
                                      int ordinal );
-extern void BUILTIN32_PrintDLLs(void);
 extern void BUILTIN32_SwitchRelayDebug(int onoff);
-extern int BUILTIN32_EnableDLL( const char *name, int len, int enable );
 
 #endif /* __WINE_BUILTIN32_H */
diff --git a/include/module.h b/include/module.h
index ff320b8..fa35eca 100644
--- a/include/module.h
+++ b/include/module.h
@@ -121,7 +121,13 @@
 #pragma pack(4)
 
 /* internal representation of 32bit modules. per process. */
-typedef enum { MODULE32_PE=1, MODULE32_ELF /* ,... */ } MODULE32_TYPE;
+typedef enum {
+	MODULE32_PE = 1,
+	MODULE32_ELF,
+	MODULE32_ELFDLL,
+	MODULE32_BI
+} MODULE32_TYPE;
+
 typedef struct _wine_modref
 {
 	struct _wine_modref	*next;
@@ -132,7 +138,7 @@
 		ELF_MODREF	elf;
 	} binfmt;
 
-	HMODULE		module;
+	HMODULE			module;
 
 	int			nDeps;
 	struct _wine_modref	**deps;
@@ -148,7 +154,6 @@
 #define WINE_MODREF_INTERNAL              0x00000001
 #define WINE_MODREF_NO_DLL_CALLS          0x00000002
 #define WINE_MODREF_PROCESS_ATTACHED      0x00000004
-#define WINE_MODREF_PROCESS_DETACHED      0x00000008
 #define WINE_MODREF_LOAD_AS_DATAFILE      0x00000010
 #define WINE_MODREF_DONT_RESOLVE_REFS     0x00000020
 #define WINE_MODREF_MARKER                0x80000000
@@ -171,13 +176,17 @@
 /* module.c */
 extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, BOOL snoop );
 extern WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hModule );
-extern void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved );
-extern HMODULE MODULE_FindModule( LPCSTR path );
+extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
+extern void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved );
+extern void MODULE_DllThreadAttach( LPVOID lpReserved );
+extern void MODULE_DllThreadDetach( LPVOID lpReserved );
+extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags );
+extern BOOL MODULE_FreeLibrary( WINE_MODREF *wm );
+extern WINE_MODREF *MODULE_FindModule( LPCSTR path );
 extern HMODULE MODULE_CreateDummyModule( const OFSTRUCT *ofs, LPCSTR modName );
 extern FARPROC16 MODULE_GetWndProcEntry16( const char *name );
 extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name );
 extern SEGPTR WINAPI HasGPHandler16( SEGPTR address );
-HMODULE MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags );
 
 /* resource.c */
 extern INT       WINAPI AccessResource(HMODULE,HRSRC); 
@@ -192,7 +201,7 @@
 extern FARPROC16 NE_GetEntryPointEx( HMODULE16 hModule, WORD ordinal, BOOL16 snoop );
 extern BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset );
 extern HANDLE NE_OpenFile( NE_MODULE *pModule );
-extern HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL implicit );
+extern HINSTANCE16 MODULE_LoadModule16( LPCSTR name, BOOL implicit );
 extern BOOL NE_CreateProcess( HFILE hFile, OFSTRUCT *ofs, LPCSTR cmd_line, LPCSTR env, 
                               LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
                               BOOL inherit, LPSTARTUPINFOA startup,
@@ -225,12 +234,11 @@
 extern BOOL BUILTIN_Init(void);
 extern HMODULE16 BUILTIN_LoadModule( LPCSTR name, BOOL force );
 extern LPCSTR BUILTIN_GetEntryPoint16( WORD cs, WORD ip, WORD *pOrd );
-extern BOOL BUILTIN_ParseDLLOptions( char *str );
-extern void BUILTIN_PrintDLLs(void);
 
 /* relay32/builtin.c */
 extern HMODULE BUILTIN32_LoadImage( LPCSTR name, OFSTRUCT *ofs, BOOL force );
-extern BOOL BUILTIN32_ParseDLLOptions( char *str );
+extern WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags, DWORD *err);
+extern void BUILTIN32_UnloadLibrary(WINE_MODREF *wm);
 
 /* if1632/builtin.c */
 extern HMODULE16 (*fnBUILTIN_LoadModule)(LPCSTR name, BOOL force);
diff --git a/include/pe_image.h b/include/pe_image.h
index 9ce289f..9439658 100644
--- a/include/pe_image.h
+++ b/include/pe_image.h
@@ -25,7 +25,8 @@
 extern BOOL PE_EnumResourceLanguagesW(HMODULE,LPCWSTR,LPCWSTR,ENUMRESLANGPROCW,LONG);
 extern HRSRC PE_FindResourceExW(struct _wine_modref*,LPCWSTR,LPCWSTR,WORD);
 extern DWORD PE_SizeofResource(HMODULE,HRSRC);
-extern HMODULE PE_LoadLibraryExA(LPCSTR,HFILE,DWORD);
+extern struct _wine_modref *PE_LoadLibraryExA(LPCSTR, DWORD, DWORD *);
+extern void PE_UnloadLibrary(struct _wine_modref *);
 extern HGLOBAL PE_LoadResource(struct _wine_modref *wm,HRSRC);
 extern HMODULE PE_LoadImage( HFILE hFile, OFSTRUCT *ofs, LPCSTR *modName );
 extern struct _wine_modref *PE_CreateModule( HMODULE hModule, OFSTRUCT *ofs, 
@@ -36,7 +37,7 @@
                               LPPROCESS_INFORMATION info );
 
 extern void PE_InitTls(void);
-extern void PE_InitDLL(struct _wine_modref *wm, DWORD type, LPVOID lpReserved);
+extern BOOL PE_InitDLL(struct _wine_modref *wm, DWORD type, LPVOID lpReserved);
 
 extern PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA(PIMAGE_RESOURCE_DIRECTORY,LPCSTR,DWORD,BOOL);
 extern PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY,LPCWSTR,DWORD,BOOL);
@@ -64,7 +65,8 @@
 } ELF_MODREF;
 
 extern struct _wine_modref *ELF_CreateDummyModule(LPCSTR,LPCSTR);
-extern HMODULE ELF_LoadLibraryExA(LPCSTR,HFILE,DWORD);
+extern struct _wine_modref *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, DWORD *err);
+extern void ELF_UnloadLibrary(struct _wine_modref *);
 extern FARPROC ELF_FindExportedFunction(struct _wine_modref *wm, LPCSTR funcName);
 
 #endif /* __WINE_PE_IMAGE_H */
diff --git a/include/winerror.h b/include/winerror.h
index 0c73c7d..0b047a4 100644
--- a/include/winerror.h
+++ b/include/winerror.h
@@ -245,6 +245,7 @@
 #define ERROR_BADKEY                1010 /* Config reg key invalid */
 #define ERROR_CANTREAD              1012 /* Config reg key couldn't be read */
 #define ERROR_CANTWRITE             1013 /* Config reg key couldn't be written */
+#define ERROR_DLL_INIT_FAILED       1114
 #define ERROR_IO_DEVICE             1117
 #define ERROR_POSSIBLE_DEADLOCK     1131
 #define ERROR_BAD_DEVICE            1200
diff --git a/loader/Makefile.in b/loader/Makefile.in
index e405eeb..580d1e6 100644
--- a/loader/Makefile.in
+++ b/loader/Makefile.in
@@ -7,7 +7,9 @@
 
 C_SRCS = \
 	elf.c \
+	elfdll.c \
 	libres.c \
+	loadorder.c \
 	main.c \
 	module.c \
 	pe_image.c \
diff --git a/loader/elf.c b/loader/elf.c
index c2b1fb4..be7369e 100644
--- a/loader/elf.c
+++ b/loader/elf.c
@@ -21,9 +21,10 @@
 #include "neexe.h"
 #include "peexe.h"
 #include "heap.h"
-#include "pe_image.h"
 #include "module.h"
+#include "pe_image.h"
 #include "debug.h"
+#include "winerror.h"
 
 WINE_MODREF *ELF_CreateDummyModule( LPCSTR libname, LPCSTR modname )
 {
@@ -96,7 +97,7 @@
 
 #include <dlfcn.h>
 
-HMODULE ELF_LoadLibraryExA( LPCSTR libname, HANDLE hf, DWORD flags )
+WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, DWORD flags, DWORD *err)
 {
 	WINE_MODREF	*wm;
 	char		*modname,*s,*t,*x;
@@ -138,14 +139,16 @@
 	dlhandle = dlopen(t,RTLD_NOW);
 	if (!dlhandle) {
 		HeapFree( GetProcessHeap(), 0, t );
-		return 0;
+		*err = ERROR_FILE_NOT_FOUND;
+		return NULL;
 	}
 
 	wm = ELF_CreateDummyModule( t, modname );
 	wm->binfmt.elf.dlhandle = dlhandle;
 
 	SNOOP_RegisterDLL(wm->module,libname,STUBSIZE/sizeof(ELF_STDCALL_STUB));
-	return wm->module;
+	*err = 0;
+	return wm;
 }
 
 FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName) 
@@ -247,12 +250,29 @@
 	fun = SNOOP_GetProcAddress(wm->module,funcName,stub-wm->binfmt.elf.stubs,fun);
 	return (FARPROC)fun;
 }
+
+
+/***************************************************************************
+ *	ELF_UnloadLibrary
+ *
+ * Unload the elf library and free the modref
+ */
+void ELF_UnloadLibrary(WINE_MODREF *wm)
+{
+	/* FIXME: do something here */
+}
+
 #else
 
-HMODULE ELF_LoadLibraryExA( LPCSTR libname, HANDLE hf, DWORD flags)
+WINE_MODREF *ELF_LoadLibraryExA( LPCSTR libname, HANDLE hf, DWORD flags)
 {
-	return 0;
+	return NULL;
 }
+
+void ELF_UnloadLibrary(WINE_MODREF *wm)
+{
+}
+
 FARPROC ELF_FindExportedFunction( WINE_MODREF *wm, LPCSTR funcName) 
 {
 	return (FARPROC)0;
diff --git a/loader/main.c b/loader/main.c
index 707f16d..e7b34ba 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -45,6 +45,8 @@
 #include "debug.h"
 #include "psdrv.h"
 #include "server.h"
+#include "cursoricon.h"
+#include "loadorder.h"
 
 int __winelib = 1;  /* Winelib run-time flag */
 
@@ -69,6 +71,9 @@
     /* Load the configuration file */
     if (!PROFILE_LoadWineIni()) return FALSE;
 
+    /* Initialize module loadorder */
+    if (!MODULE_InitLoadOrder()) return FALSE;
+
       /* Initialize DOS memory */
     if (!DOSMEM_Init(0)) return FALSE;
 
diff --git a/loader/module.c b/loader/module.c
index 8ba903c..30e5bdc 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -29,6 +29,8 @@
 #include "task.h"
 #include "debug.h"
 #include "callback.h"
+#include "loadorder.h"
+#include "elfdll.h"
 
 
 /*************************************************************************
@@ -53,10 +55,55 @@
 }
 
 /*************************************************************************
- *		MODULE_InitializeDLLs
+ *		MODULE_InitDll
+ */
+static BOOL MODULE_InitDll( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
+{
+    BOOL retv = TRUE;
+
+    static LPCSTR typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH", 
+                                 "THREAD_ATTACH", "THREAD_DETACH" };
+    assert( wm );
+
+
+    /* Skip calls for modules loaded with special load flags */
+
+    if (    ( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS )
+         || ( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE ) )
+        return TRUE;
+
+
+    TRACE( module, "(%s,%s,%p) - CALL\n", 
+           wm->modname, typeName[type], lpReserved );
+
+    /* Call the initialization routine */
+    switch ( wm->type )
+    {
+    case MODULE32_PE:
+        retv = PE_InitDLL( wm, type, lpReserved );
+        break;
+
+    case MODULE32_ELF:
+        /* no need to do that, dlopen() already does */
+        break;
+
+    default:
+        ERR( module, "wine_modref type %d not handled.\n", wm->type );
+        retv = FALSE;
+        break;
+    }
+
+    TRACE( module, "(%s,%s,%p) - RETURN %d\n", 
+           wm->modname, typeName[type], lpReserved, retv );
+
+    return retv;
+}
+
+/*************************************************************************
+ *		MODULE_DllProcessAttach
  * 
- * Call the initialization routines of all DLLs belonging to the
- * current process. This is somewhat complicated due to the fact that
+ * Send the process attach notification to all DLLs the given module
+ * depends on (recursively). This is somewhat complicated due to the fact that
  *
  * - we have to respect the module dependencies, i.e. modules implicitly
  *   referenced by another module have to be initialized before the module
@@ -69,171 +116,159 @@
  * (Note that this routine can be recursively entered not only directly
  *  from itself, but also via LoadLibrary from one of the called initialization
  *  routines.)
+ *
+ * Furthermore, we need to rearrange the main WINE_MODREF list to allow
+ * the process *detach* notifications to be sent in the correct order.
+ * This must not only take into account module dependencies, but also 
+ * 'hidden' dependencies created by modules calling LoadLibrary in their
+ * attach notification routine.
+ *
+ * The strategy is rather simple: we move a WINE_MODREF to the head of the
+ * list after the attach notification has returned.  This implies that the
+ * detach notifications are called in the reverse of the sequence the attach
+ * notifications *returned*.
+ *
+ * NOTE: Assumes that the process critical section is held!
+ *
  */
-static void MODULE_DoInitializeDLLs( WINE_MODREF *wm,
-                                     DWORD type, LPVOID lpReserved )
+BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
 {
-    WINE_MODREF *xwm;
-    int i, skip = FALSE;
+    BOOL retv = TRUE;
+    int i;
+    assert( wm );
 
-    assert( wm && !(wm->flags & WINE_MODREF_MARKER) );
-    TRACE( module, "(%s,%08x,%ld,%p) - START\n", 
-           wm->modname, wm->module, type, lpReserved );
+    /* prevent infinite recursion in case of cyclical dependencies */
+    if (    ( wm->flags & WINE_MODREF_MARKER )
+         || ( wm->flags & WINE_MODREF_PROCESS_ATTACHED ) )
+        return retv;
+
+    TRACE( module, "(%s,%p) - START\n", 
+           wm->modname, lpReserved );
 
     /* Tag current MODREF to prevent recursive loop */
     wm->flags |= WINE_MODREF_MARKER;
 
-    switch ( type )
+    /* Recursively attach all DLLs this one depends on */
+    for ( i = 0; retv && i < wm->nDeps; i++ )
+        if ( wm->deps[i] )
+            retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved );
+
+    /* Call DLL entry point */
+    if ( retv )
     {
-    default:
-    case DLL_PROCESS_ATTACH:
-    case DLL_THREAD_ATTACH:
-        /* Recursively attach all DLLs this one depends on */
-        for ( i = 0; i < wm->nDeps; i++ )
-            if ( wm->deps[i] && !(wm->deps[i]->flags & WINE_MODREF_MARKER) )
-                MODULE_DoInitializeDLLs( wm->deps[i], type, lpReserved );
-        break;
-
-    case DLL_PROCESS_DETACH:
-    case DLL_THREAD_DETACH:
-        /* Recursively detach all DLLs that depend on this one */
-        for ( xwm = PROCESS_Current()->modref_list; xwm; xwm = xwm->next )
-            if ( !(xwm->flags & WINE_MODREF_MARKER) )
-                for ( i = 0; i < xwm->nDeps; i++ )
-                    if ( xwm->deps[i] == wm )
-                    {
-                        MODULE_DoInitializeDLLs( xwm, type, lpReserved );
-                        break;
-                    }
-        break;
-    }
-
-    /* Evaluate module flags */
-
-    if (    ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
-         || ( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS )
-         || ( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE ) )
-        skip = TRUE;
-
-    if ( type == DLL_PROCESS_ATTACH )
-    {
-        if ( wm->flags & WINE_MODREF_PROCESS_ATTACHED )
-            skip = TRUE;
-        else
+        retv = MODULE_InitDll( wm, DLL_PROCESS_ATTACH, lpReserved );
+        if ( retv )
             wm->flags |= WINE_MODREF_PROCESS_ATTACHED;
     }
 
-    if ( type == DLL_PROCESS_DETACH )
+    /* Re-insert MODREF at head of list */
+    if ( retv && wm->prev )
     {
-        if ( wm->flags & WINE_MODREF_PROCESS_DETACHED )
-            skip = TRUE;
-        else
-            wm->flags |= WINE_MODREF_PROCESS_DETACHED;
+        wm->prev->next = wm->next;
+        if ( wm->next ) wm->next->prev = wm->prev;
+
+        wm->prev = NULL;
+        wm->next = PROCESS_Current()->modref_list;
+        PROCESS_Current()->modref_list = wm->next->prev = wm;
     }
 
-    if ( !skip )
-    {
-        /* Now we can call the initialization routine */
-        TRACE( module, "(%s,%08x,%ld,%p) - CALL\n", 
-               wm->modname, wm->module, type, lpReserved );
+    /* Remove recursion flag */
+    wm->flags &= ~WINE_MODREF_MARKER;
 
-        switch ( wm->type )
-        {
-        case MODULE32_PE:
-            PE_InitDLL( wm, type, lpReserved );
-            break;
+    TRACE( module, "(%s,%p) - END\n", 
+           wm->modname, lpReserved );
 
-        case MODULE32_ELF:
-            /* no need to do that, dlopen() already does */
-            break;
-
-        default:
-           ERR(module, "wine_modref type %d not handled.\n", wm->type);
-           break;
-        }
-    }
-
-    TRACE( module, "(%s,%08x,%ld,%p) - END\n", 
-           wm->modname, wm->module, type, lpReserved );
+    return retv;
 }
 
-void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved )
+/*************************************************************************
+ *		MODULE_DllProcessDetach
+ * 
+ * Send DLL process detach notifications.  See the comment about calling 
+ * sequence at MODULE_DllProcessAttach.  Unless the bForceDetach flag
+ * is set, only DLLs with zero refcount are notified.
+ *
+ * NOTE: Assumes that the process critical section is held!
+ *
+ */
+void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
 {
-    BOOL inProgress = FALSE;
     WINE_MODREF *wm;
 
-    /* Grab the process critical section to protect the recursion flags */
-    /* FIXME: This is probably overkill! */
-    EnterCriticalSection( &PROCESS_Current()->crit_section );
-
-    TRACE( module, "(%08x,%ld,%p) - START\n", root, type, lpReserved );
-
-    /* First, check whether initialization is currently in progress */
-    for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
-        if ( wm->flags & WINE_MODREF_MARKER )
+    do
+    {
+        for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
         {
-            inProgress = TRUE;
+            /* Check whether to detach this DLL */
+            if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
+                continue;
+            if ( wm->refCount > 0 && !bForceDetach )
+                continue;
+
+            /* Call detach notification */
+            wm->flags &= ~WINE_MODREF_PROCESS_ATTACHED;
+            MODULE_InitDll( wm, DLL_PROCESS_DETACH, lpReserved );
+
+            /* Restart at head of WINE_MODREF list, as entries might have
+               been added and/or removed while performing the call ... */
             break;
         }
+    } while ( wm );
+}
 
-    if ( inProgress )
+/*************************************************************************
+ *		MODULE_DllThreadAttach
+ * 
+ * Send DLL thread attach notifications. These are sent in the
+ * reverse sequence of process detach notification.
+ *
+ */
+void MODULE_DllThreadAttach( LPVOID lpReserved )
+{
+    WINE_MODREF *wm;
+
+    EnterCriticalSection( &PROCESS_Current()->crit_section );
+
+    for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
+        if ( !wm->next )
+            break;
+
+    for ( ; wm; wm = wm->prev )
     {
-        /* 
-         * If this a LoadLibrary call from within an initialization routine,
-         * treat it analogously to an implicitly referenced DLL.
-         * Anything else may not happen at this point!
-         */
-        if ( root )
-        {
-            wm = MODULE32_LookupHMODULE( root );
-            if ( wm && !(wm->flags & WINE_MODREF_MARKER) )
-                MODULE_DoInitializeDLLs( wm, type, lpReserved );
-        }
-        else
-            FIXME(module, "Invalid recursion!\n");
-    }
-    else
-    {
-        /* If we arrive here, this is the start of an initialization run */
-        if ( !root )
-        {
-            /* If called for main EXE, initialize all DLLs */
-            switch ( type )
-            {
-            default:  /* Hmmm. */
-            case DLL_PROCESS_ATTACH:
-            case DLL_THREAD_ATTACH:
-                for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
-                    if ( !wm->next )
-                        break;
-                for ( ; wm; wm = wm->prev )
-                    if ( !(wm->flags & WINE_MODREF_MARKER) )
-                        MODULE_DoInitializeDLLs( wm, type, lpReserved );
-                break;
+        if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
+            continue;
+        if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
+            continue;
 
-            case DLL_PROCESS_DETACH:
-            case DLL_THREAD_DETACH:
-                for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
-                    if ( !(wm->flags & WINE_MODREF_MARKER) )
-                        MODULE_DoInitializeDLLs( wm, type, lpReserved );
-                break;
-            }
-        }
-        else
-        {
-            /* If called for a specific DLL, initialize only it and its children */
-            wm = MODULE32_LookupHMODULE( root );
-            if (wm) MODULE_DoInitializeDLLs( wm, type, lpReserved );
-        }
-
-        /* We're finished, so we reset all recursion flags */
-        for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
-            wm->flags &= ~WINE_MODREF_MARKER;
+        MODULE_InitDll( wm, DLL_THREAD_ATTACH, lpReserved );
     }
 
-    TRACE( module, "(%08x,%ld,%p) - END\n", root, type, lpReserved );
+    LeaveCriticalSection( &PROCESS_Current()->crit_section );
+}
 
-    /* Release critical section */
+/*************************************************************************
+ *		MODULE_DllThreadDetach
+ * 
+ * Send DLL thread detach notifications. These are sent in the
+ * same sequence as process detach notification.
+ *
+ */
+void MODULE_DllThreadDetach( LPVOID lpReserved )
+{
+    WINE_MODREF *wm;
+
+    EnterCriticalSection( &PROCESS_Current()->crit_section );
+
+    for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
+    {
+        if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
+            continue;
+        if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
+            continue;
+
+        MODULE_InitDll( wm, DLL_THREAD_DETACH, lpReserved );
+    }
+
     LeaveCriticalSection( &PROCESS_Current()->crit_section );
 }
 
@@ -244,48 +279,20 @@
  */
 BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
 {
-    WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule );
-    if ( !wm ) return FALSE;
-
-    wm->flags |= WINE_MODREF_NO_DLL_CALLS;
-    return TRUE;
-}
-
-/****************************************************************************
- *              MODULE_IncRefCount
- */
-static void MODULE_IncRefCount( HMODULE hModule )
-{
     WINE_MODREF *wm;
+    BOOL retval = TRUE;
 
     EnterCriticalSection( &PROCESS_Current()->crit_section );
-    wm = MODULE32_LookupHMODULE( hModule );
-    if( wm )
-    {
-        wm->refCount++;
-        TRACE(module, "(%08x) count now %d\n", hModule, wm->refCount);
-    }
-    LeaveCriticalSection( &PROCESS_Current()->crit_section );
-}
 
-/****************************************************************************
- *              MODULE_DecRefCount
- */
-static int MODULE_DecRefCount( HMODULE hModule )
-{
-    int retv = 0;
-    WINE_MODREF *wm;
-
-    EnterCriticalSection( &PROCESS_Current()->crit_section );
     wm = MODULE32_LookupHMODULE( hModule );
-    if( wm && ( retv = wm->refCount ) > 0 )
-    {
-        wm->refCount--;
-        TRACE(module, "(%08x) count now %d\n", hModule, wm->refCount);
-    }
+    if ( !wm )
+        retval = FALSE;
+    else
+        wm->flags |= WINE_MODREF_NO_DLL_CALLS;
+
     LeaveCriticalSection( &PROCESS_Current()->crit_section );
 
-    return retv;
+    return retval;
 }
 
 
@@ -449,7 +456,7 @@
  *	the module handle if found
  * 	0 if not
  */
-HMODULE MODULE_FindModule(
+WINE_MODREF *MODULE_FindModule(
 	LPCSTR path	/* [in] pathname of module/library to be found */
 ) {
     LPSTR	filename;
@@ -477,7 +484,7 @@
 	if (!strcasecmp( filename, xmodname)) {
 	    HeapFree( GetProcessHeap(), 0, filename );
 	    HeapFree( GetProcessHeap(), 0, xmodname );
-	    return wm->module;
+	    return wm;
 	}
 	if (dotptr) *dotptr='.';
 	/* FIXME: add paths, shortname */
@@ -504,14 +511,14 @@
 	if (!strcasecmp( filename, xlname)) {
 	    HeapFree( GetProcessHeap(), 0, filename );
 	    HeapFree( GetProcessHeap(), 0, xlname );
-	    return wm->module;
+	    return wm;
 	}
 	if (dotptr) *dotptr='.';
 	/* FIXME: add paths, shortname */
 	HeapFree( GetProcessHeap(), 0, xlname );
     }
     HeapFree( GetProcessHeap(), 0, filename );
-    return 0;
+    return NULL;
 }
 
 /***********************************************************************
@@ -1121,10 +1128,14 @@
  */
 HMODULE WINAPI GetModuleHandleA(LPCSTR module)
 {
-    if (module == NULL)
-    	return PROCESS_Current()->exe_modref->module;
+    WINE_MODREF *wm;
+
+    if ( module == NULL )
+        wm = PROCESS_Current()->exe_modref;
     else
-	return MODULE_FindModule( module );
+        wm = MODULE_FindModule( module );
+
+    return wm? wm->module : 0;
 }
 
 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
@@ -1186,43 +1197,116 @@
 }
 
 /***********************************************************************
- *           LoadLibraryEx32A   (KERNEL32)
+ *           LoadLibraryExA   (KERNEL32)
  */
-HMODULE WINAPI LoadLibraryExA(LPCSTR libname,HFILE hfile,DWORD flags)
+HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HFILE hfile, DWORD flags)
 {
-    HMODULE hmod;
+	WINE_MODREF *wm;
 
-    if (!libname) {
-    	SetLastError(ERROR_INVALID_PARAMETER);
-	return 0;
-    }
-    hmod = MODULE_LoadLibraryExA( libname, hfile, flags );
+	if(!libname)
+	{
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return 0;
+	}
 
-    if ( hmod >= 32 )
-    {
-        /* Initialize DLL just loaded */
-        MODULE_InitializeDLLs( hmod, DLL_PROCESS_ATTACH, NULL );
-	/* FIXME: check for failure, SLE(ERROR_DLL_INIT_FAILED) */
-    }
+	wm = MODULE_LoadLibraryExA( libname, hfile, flags );
 
-    return hmod;
+	return wm ? wm->module : 0;
 }
 
-HMODULE MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags )
+/***********************************************************************
+ *	MODULE_LoadLibraryExA	(internal)
+ *
+ * Load a PE style module according to the load order.
+ *
+ * The HFILE parameter is not used and marked reserved in the SDK. I can
+ * only guess that it should force a file to be mapped, but I rather
+ * ignore the parameter because it would be extremely difficult to
+ * integrate this with different types of module represenations.
+ *
+ */
+WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags )
 {
-    HMODULE hmod;
-    
-    hmod = ELF_LoadLibraryExA( libname, hfile, flags );
-    if(hmod < (HMODULE)32)
-        hmod = PE_LoadLibraryExA( libname, hfile, flags );
+	DWORD err;
+	WINE_MODREF *pwm;
+	int i;
+	module_loadorder_t *plo;
 
-    if(hmod >= (HMODULE)32)
-    {
-        /* Increment RefCount */
-        MODULE_IncRefCount( hmod );
-    }
+	EnterCriticalSection(&PROCESS_Current()->crit_section);
 
-    return hmod;
+	/* Check for already loaded module */
+	if((pwm = MODULE_FindModule(libname))) 
+	{
+		pwm->refCount++;
+		TRACE(module, "Already loaded module '%s' at 0x%08x, count=%d, \n", libname, pwm->module, pwm->refCount);
+		LeaveCriticalSection(&PROCESS_Current()->crit_section);
+		return pwm;
+	}
+
+	plo = MODULE_GetLoadOrder(libname);
+
+	for(i = 0; i < MODULE_LOADORDER_NTYPES; i++)
+	{
+		switch(plo->loadorder[i])
+		{
+		case MODULE_LOADORDER_DLL:
+			TRACE(module, "Trying native dll '%s'\n", libname);
+			pwm = PE_LoadLibraryExA(libname, flags, &err);
+			break;
+
+		case MODULE_LOADORDER_ELFDLL:
+			TRACE(module, "Trying elfdll '%s'\n", libname);
+			pwm = ELFDLL_LoadLibraryExA(libname, flags, &err);
+			break;
+
+		case MODULE_LOADORDER_SO:
+			TRACE(module, "Trying so-library '%s'\n", libname);
+			pwm = ELF_LoadLibraryExA(libname, flags, &err);
+			break;
+
+		case MODULE_LOADORDER_BI:
+			TRACE(module, "Trying built-in '%s'\n", libname);
+			pwm = BUILTIN32_LoadLibraryExA(libname, flags, &err);
+			break;
+
+		default:
+			ERR(module, "Got invalid loadorder type %d (%s index %d)\n", plo->loadorder[i], plo->modulename, i);
+		/* Fall through */
+
+		case MODULE_LOADORDER_INVALID:	/* We ignore this as it is an empty entry */
+			pwm = NULL;
+			break;
+		}
+
+		if(pwm)
+		{
+			/* Initialize DLL just loaded */
+			TRACE(module, "Loaded module '%s' at 0x%08x, \n", libname, pwm->module);
+
+			/* Set the refCount here so that an attach failure will */
+			/* decrement the dependencies through the MODULE_FreeLibrary call. */
+			pwm->refCount++;
+
+			if(!MODULE_DllProcessAttach(pwm, NULL))
+			{
+				WARN(module, "Attach failed for module '%s', \n", libname);
+				MODULE_FreeLibrary(pwm);
+				SetLastError(ERROR_DLL_INIT_FAILED);
+				pwm = NULL;
+			}
+
+			LeaveCriticalSection(&PROCESS_Current()->crit_section);
+			return pwm;
+		}
+
+		if(err != ERROR_FILE_NOT_FOUND)
+			break;
+	}
+
+	ERR(module, "Failed to load module '%s'; error=0x%08lx, \n", libname, err);
+	SetLastError(err);
+	LeaveCriticalSection(&PROCESS_Current()->crit_section);
+	return NULL;
 }
 
 /***********************************************************************
@@ -1252,97 +1336,121 @@
     return ret;
 }
 
-
 /***********************************************************************
- *	MODULE_FreeLibrary		(internal)
+ *           MODULE_FlushModrefs
  *
- * Decrease the loadcount of the dll.
- * If the count reaches 0, then notify the dll and free all dlls
- * that depend on this one.
+ * NOTE: Assumes that the process critical section is held!
  *
+ * Remove all unused modrefs and call the internal unloading routines
+ * for the library type.
  */
-static void MODULE_FreeLibrary(WINE_MODREF *wm, BOOL first)
+static void MODULE_FlushModrefs(void)
 {
-    int i;
+	WINE_MODREF *wm, *next;
 
-    assert(wm != NULL);
+	for(wm = PROCESS_Current()->modref_list; wm; wm = next)
+	{
+		next = wm->next;
 
-    /* Don't do anything if there still are references */
-    if( MODULE_DecRefCount(wm->module) > 1 )
-        return;
+		if(wm->refCount)
+			continue;
 
-    TRACE( module, "(%s, %08x, %d) - START\n", wm->modname, wm->module, first);
+		/* Unlink this modref from the chain */
+		if(wm->next)
+                        wm->next->prev = wm->prev;
+		if(wm->prev)
+                        wm->prev->next = wm->next;
+		if(wm == PROCESS_Current()->modref_list)
+			PROCESS_Current()->modref_list = wm->next;
 
-    /* Evaluate module flags */
-    if(!(    ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
-          || ( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS )
-          || ( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE ) ))
-    {
-        /* Now we can call the initialization routine */
-        TRACE( module, "(%s, %08x, %d) - CALL\n", wm->modname, wm->module, first);
+		/* 
+		 * The unloaders are also responsible for freeing the modref itself
+		 * because the loaders were responsible for allocating it.
+		 */
+		switch(wm->type)
+		{
+		case MODULE32_PE:	PE_UnloadLibrary(wm);		break;
+		case MODULE32_ELF:	ELF_UnloadLibrary(wm);		break;
+		case MODULE32_ELFDLL:	ELFDLL_UnloadLibrary(wm);	break;
+		case MODULE32_BI:	BUILTIN32_UnloadLibrary(wm);	break;
 
-        switch ( wm->type )
-        {
-        case MODULE32_PE:
-            PE_InitDLL(wm, DLL_PROCESS_DETACH, (LPVOID)(first ? 0 : 1));
-            break;
-
-        case MODULE32_ELF:
-            FIXME(module, "FreeLibrary requested on ELF module '%s'\n", wm->modname);
-            break;
-
-        default:
-           ERR(module, "wine_modref type %d not handled.\n", wm->type);
-           break;
-        }
-    }
-
-    /* Recursively free all DLLs that depend on this one */
-    for( i = 0; i < wm->nDeps; i++ )
-    {
-        if(wm->deps[i])
-        {
-            MODULE_FreeLibrary(wm->deps[i], FALSE);
-            break;
-        }
-    }
-
-    /* Be sure that the freed library and the list head are unlinked properly */
-    if(PROCESS_Current()->modref_list == wm)
-        PROCESS_Current()->modref_list = wm->next;
-    if(wm->next)
-        wm->next->prev = wm->prev;
-    if(wm->prev)
-        wm->prev->next = wm->next;
-
-    FIXME(module,"should free memory of module %08x '%s'\n", wm->module, wm->modname);
-
-    TRACE( module, "(%s, %08x, %d) - END\n", wm->modname, wm->module, first);
+		default:
+			ERR(module, "Invalid or unhandled MODREF type %d encountered (wm=%p)\n", wm->type, wm);
+		}
+	}
 }
 
-
 /***********************************************************************
  *           FreeLibrary
  */
 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
 {
+    BOOL retv = TRUE;
     WINE_MODREF *wm;
-    BOOL retval = TRUE;
 
-    EnterCriticalSection(&PROCESS_Current()->crit_section);
+    EnterCriticalSection( &PROCESS_Current()->crit_section );
 
-    wm = MODULE32_LookupHMODULE(hLibModule);
-    if(!wm)
-    {
-        ERR(module, "(%08x) module not found in process' modref_list. Freed too many times?\n", hLibModule);
-        retval = FALSE;
-    }
+    wm = MODULE32_LookupHMODULE( hLibModule );
+    if ( !wm )
+        SetLastError( ERROR_INVALID_HANDLE );
     else
-        MODULE_FreeLibrary(wm, TRUE);	/* This always succeeds */
+        retv = MODULE_FreeLibrary( wm );
 
-    LeaveCriticalSection(&PROCESS_Current()->crit_section);
+    LeaveCriticalSection( &PROCESS_Current()->crit_section );
 
-    return retval;
+    return retv;
+}
+
+/***********************************************************************
+ *           MODULE_DecRefCount
+ *
+ * NOTE: Assumes that the process critical section is held!
+ */
+static void MODULE_DecRefCount( WINE_MODREF *wm )
+{
+    int i;
+
+    if ( wm->flags & WINE_MODREF_MARKER )
+        return;
+
+    if ( wm->refCount <= 0 )
+        return;
+
+    --wm->refCount;
+    TRACE( module, "(%s) refCount: %d\n", wm->modname, wm->refCount );
+
+    if ( wm->refCount == 0 )
+    {
+        wm->flags |= WINE_MODREF_MARKER;
+
+        for ( i = 0; i < wm->nDeps; i++ )
+            if ( wm->deps[i] )
+                MODULE_DecRefCount( wm->deps[i] );
+
+        wm->flags &= ~WINE_MODREF_MARKER;
+    }
+}
+
+/***********************************************************************
+ *           MODULE_FreeLibrary
+ *
+ * NOTE: Assumes that the process critical section is held!
+ */
+BOOL MODULE_FreeLibrary( WINE_MODREF *wm )
+{
+    TRACE( module, "(%s) - START\n", wm->modname );
+
+    /* Recursively decrement reference counts */
+    MODULE_DecRefCount( wm );
+
+    /* Call process detach notifications */
+    MODULE_DllProcessDetach( FALSE, NULL );
+
+    MODULE_FlushModrefs();
+
+    TRACE( module, "(%s) - END\n", wm->modname );
+
+    return FALSE;
 }
 
 
diff --git a/loader/ne/module.c b/loader/ne/module.c
index 7856510..73a81a1 100644
--- a/loader/ne/module.c
+++ b/loader/ne/module.c
@@ -27,6 +27,8 @@
 #include "stackframe.h"
 #include "debug.h"
 #include "file.h"
+#include "loadorder.h"
+#include "elfdll.h"
 
 FARPROC16 (*fnSNOOP16_GetProcAddress16)(HMODULE16,DWORD,FARPROC16) = NULL;
 void (*fnSNOOP16_RegisterDLL)(NE_MODULE*,LPCSTR) = NULL;
@@ -755,7 +757,7 @@
             /* its handle in the list of DLLs to initialize.   */
             HMODULE16 hDLL;
 
-            if ((hDLL = NE_LoadModule( buffer, TRUE )) == 2)
+            if ((hDLL = MODULE_LoadModule16( buffer, TRUE )) == 2)
             {
                 /* file not found */
                 char *p;
@@ -765,7 +767,7 @@
                 if (!(p = strrchr( buffer, '\\' ))) p = buffer;
                 memcpy( p + 1, pstr + 1, *pstr );
                 strcpy( p + 1 + *pstr, ".dll" );
-                hDLL = NE_LoadModule( buffer, TRUE );
+                hDLL = MODULE_LoadModule16( buffer, TRUE );
             }
             if (hDLL < 32)
             {
@@ -857,23 +859,11 @@
 HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL implicit )
 {
     HINSTANCE16 hInstance;
-    HMODULE16 hModule;
     HFILE16 hFile;
     OFSTRUCT ofs;
 
-    /* Try to load the built-in first if not disabled */
-
-    if ((hModule = fnBUILTIN_LoadModule( name, FALSE ))) return hModule;
-
     if ((hFile = OpenFile16( name, &ofs, OF_READ )) == HFILE_ERROR16)
     {
-        /* Now try the built-in even if disabled */
-        if ((hModule = fnBUILTIN_LoadModule( name, TRUE )))
-        {
-            MSG( "Could not load Windows DLL '%s', using built-in module.\n",
-                 name );
-            return hModule;
-        }
         return 2;  /* File not found */
     }
 
@@ -883,6 +873,67 @@
     return hInstance;
 }
 
+
+/**********************************************************************
+ *	    MODULE_LoadModule16
+ *
+ * Load a NE module in the order of the loadorder specification.
+ * The caller is responsible that the module is not loaded already.
+ *
+ */
+HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit )
+{
+	HINSTANCE16 hinst;
+	int i;
+	module_loadorder_t *plo;
+
+	plo = MODULE_GetLoadOrder(libname);
+
+	for(i = 0; i < MODULE_LOADORDER_NTYPES; i++)
+	{
+		switch(plo->loadorder[i])
+		{
+		case MODULE_LOADORDER_DLL:
+			TRACE(module, "Trying native dll '%s'\n", libname);
+			hinst = NE_LoadModule(libname, implicit);
+			break;
+
+		case MODULE_LOADORDER_ELFDLL:
+			TRACE(module, "Trying elfdll '%s'\n", libname);
+			hinst = ELFDLL_LoadModule16(libname, implicit);
+			break;
+
+		case MODULE_LOADORDER_BI:
+			TRACE(module, "Trying built-in '%s'\n", libname);
+			hinst = fnBUILTIN_LoadModule(libname, TRUE);
+			break;
+
+		default:
+			ERR(module, "Got invalid loadorder type %d (%s index %d)\n", plo->loadorder[i], plo->modulename, i);
+		/* Fall through */
+
+		case MODULE_LOADORDER_SO:	/* This is not supported for NE modules */
+		case MODULE_LOADORDER_INVALID:	/* We ignore this as it is an empty entry */
+			hinst = 2;
+			break;
+		}
+
+		if(hinst >= 32)
+		{
+			TRACE(module, "Loaded module '%s' at 0x%04x, \n", libname, hinst);
+			return hinst;
+		}
+
+		if(hinst != 2)
+		{
+			/* We quit searching when we get another error than 'File not found' */
+			break;
+		}
+	}
+	return hinst;	/* The last error that occured */
+}
+
+
 /**********************************************************************
  *          LoadModule16    (KERNEL.45)
  */
@@ -918,7 +969,7 @@
     {
         /* Main case: load first instance of NE module */
 
-        if ( (hInstance = NE_LoadModule( name, FALSE )) < 32 )
+        if ( (hInstance = MODULE_LoadModule16( name, FALSE )) < 32 )
             return hInstance;
 
         if ( !(pModule = NE_GetPtr( hInstance )) )
diff --git a/loader/pe_image.c b/loader/pe_image.c
index 4982dc4..4b71368 100644
--- a/loader/pe_image.c
+++ b/loader/pe_image.c
@@ -196,7 +196,7 @@
 	}
 	if (forward)
         {
-                HMODULE hMod;
+                WINE_MODREF *wm;
 		char module[256];
 		char *end = strchr(forward, '.');
 
@@ -204,9 +204,9 @@
 		assert(end-forward<256);
 		strncpy(module, forward, (end - forward));
 		module[end-forward] = 0;
-                hMod = MODULE_FindModule( module );
-		assert(hMod);
-		return MODULE_GetProcAddress( hMod, end + 1, snoop );
+                wm = MODULE_FindModule( module );
+		assert(wm);
+		return MODULE_GetProcAddress( wm->module, end + 1, snoop );
 	}
 	return NULL;
 }
@@ -214,7 +214,6 @@
 DWORD fixup_imports( WINE_MODREF *wm )
 {
     IMAGE_IMPORT_DESCRIPTOR	*pe_imp;
-    WINE_MODREF			*xwm;
     PE_MODREF			*pem;
     unsigned int load_addr	= wm->module;
     int				i,characteristics_detection=1;
@@ -256,7 +255,7 @@
      */
  
     for (i = 0, pe_imp = pem->pe_import; pe_imp->Name ; pe_imp++) {
-    	HMODULE		hImpModule;
+    	WINE_MODREF		*wmImp;
 	IMAGE_IMPORT_BY_NAME	*pe_name;
 	PIMAGE_THUNK_DATA	import_list,thunk_list;
  	char			*name = (char *) RVA(pe_imp->Name);
@@ -265,8 +264,8 @@
 		break;
 
 	/* don't use MODULE_Load, Win32 creates new task differently */
-	hImpModule = MODULE_LoadLibraryExA( name, 0, 0 );
-	if (!hImpModule) {
+	wmImp = MODULE_LoadLibraryExA( name, 0, 0 );
+	if (!wmImp) {
 	    char *p,buffer[2000];
 	    
 	    /* GetModuleFileName would use the wrong process, so don't use it */
@@ -274,15 +273,13 @@
 	    if (!(p = strrchr (buffer, '\\')))
 		p = buffer;
 	    strcpy (p + 1, name);
-	    hImpModule = MODULE_LoadLibraryExA( buffer, 0, 0 );
+	    wmImp = MODULE_LoadLibraryExA( buffer, 0, 0 );
 	}
-	if (!hImpModule) {
+	if (!wmImp) {
 	    ERR (module, "Module %s not found\n", name);
 	    return 1;
 	}
-        xwm = MODULE32_LookupHMODULE( hImpModule );
-        assert( xwm );
-        wm->deps[i++] = xwm;
+        wm->deps[i++] = wmImp;
 
 	/* FIXME: forwarder entries ... */
 
@@ -297,7 +294,7 @@
 
 		    TRACE(win32, "--- Ordinal %s,%d\n", name, ordinal);
 		    thunk_list->u1.Function=MODULE_GetProcAddress(
-                        hImpModule, (LPCSTR)ordinal, TRUE
+                        wmImp->module, (LPCSTR)ordinal, TRUE
 		    );
 		    if (!thunk_list->u1.Function) {
 			ERR(win32,"No implementation for %s.%d, setting to 0xdeadbeef\n",
@@ -308,7 +305,7 @@
 		    pe_name = (PIMAGE_IMPORT_BY_NAME)RVA(import_list->u1.AddressOfData);
 		    TRACE(win32, "--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
 		    thunk_list->u1.Function=MODULE_GetProcAddress(
-                        hImpModule, pe_name->Name, TRUE
+                        wmImp->module, pe_name->Name, TRUE
 		    );
 		    if (!thunk_list->u1.Function) {
 			ERR(win32,"No implementation for %s.%d(%s), setting to 0xdeadbeef\n",
@@ -329,7 +326,7 @@
 
 		    TRACE(win32,"--- Ordinal %s.%d\n",name,ordinal);
 		    thunk_list->u1.Function=MODULE_GetProcAddress(
-                        hImpModule, (LPCSTR) ordinal, TRUE
+                        wmImp->module, (LPCSTR) ordinal, TRUE
 		    );
 		    if (!thunk_list->u1.Function) {
 			ERR(win32, "No implementation for %s.%d, setting to 0xdeadbeef\n",
@@ -341,7 +338,7 @@
 		    TRACE(win32,"--- %s %s.%d\n",
 		   		  pe_name->Name,name,pe_name->Hint);
 		    thunk_list->u1.Function=MODULE_GetProcAddress(
-                        hImpModule, pe_name->Name, TRUE
+                        wmImp->module, pe_name->Name, TRUE
 		    );
 		    if (!thunk_list->u1.Function) {
 		    	ERR(win32, "No implementation for %s.%d, setting to 0xdeadbeef\n",
@@ -829,68 +826,76 @@
  * The PE Library Loader frontend. 
  * FIXME: handle the flags.
  */
-HMODULE PE_LoadLibraryExA (LPCSTR name, 
-                               HFILE hFile, DWORD flags)
+WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags, DWORD *err)
 {
-    LPCSTR	modName = NULL;
-    OFSTRUCT	ofs;
-    HMODULE	hModule32;
-    HMODULE16	hModule16;
-    NE_MODULE	*pModule;
-    WINE_MODREF	*wm;
-    BOOL	builtin = TRUE;
-    char        dllname[256], *p;
+	LPCSTR		modName = NULL;
+	OFSTRUCT	ofs;
+	HMODULE		hModule32;
+	HMODULE16	hModule16;
+	NE_MODULE	*pModule;
+	WINE_MODREF	*wm;
+	BOOL		builtin = TRUE;
+	char        	dllname[256], *p;
+	HFILE		hFile;
 
-    /* Check for already loaded module */
-    if ((hModule32 = MODULE_FindModule( name ))) 
-        return hModule32;
+	/* Append .DLL to name if no extension present */
+	strcpy( dllname, name );
+	if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
+		strcat( dllname, ".DLL" );
 
-    /* Append .DLL to name if no extension present */
-    strcpy( dllname, name );
-    if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
-        strcat( dllname, ".DLL" );
+	/* Load PE module */
+	hFile = OpenFile( dllname, &ofs, OF_READ | OF_SHARE_DENY_WRITE );
+	if ( hFile != HFILE_ERROR )
+	{
+		hModule32 = PE_LoadImage( hFile, &ofs, &modName );
+		CloseHandle( hFile );
+		if(!hModule32)
+		{
+			*err = ERROR_OUTOFMEMORY;	/* Not entirely right, but good enough */
+			return NULL;
+		}
+	}
+	else
+	{
+		*err = ERROR_FILE_NOT_FOUND;
+		return NULL;
+	}
 
-    /* Try to load builtin enabled modules first */
-    if ( !(hModule32 = BUILTIN32_LoadImage( name, &ofs, FALSE )) )
-    {
-        /* Load PE module */
+	/* Create 16-bit dummy module */
+	if ((hModule16 = MODULE_CreateDummyModule( &ofs, modName )) < 32)
+	{
+		*err = (DWORD)hModule16;	/* This should give the correct error */
+		return NULL;
+	}
+	pModule = (NE_MODULE *)GlobalLock16( hModule16 );
+	pModule->flags    = NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA | NE_FFLAGS_WIN32;
+	pModule->module32 = hModule32;
 
-        hFile = OpenFile( dllname, &ofs, OF_READ | OF_SHARE_DENY_WRITE );
-        if ( hFile != HFILE_ERROR )
-            if ( (hModule32 = PE_LoadImage( hFile, &ofs, &modName )) >= 32 )
-                builtin = FALSE;
+	/* Create 32-bit MODREF */
+	if ( !(wm = PE_CreateModule( hModule32, &ofs, flags, builtin )) )
+	{
+		ERR(win32,"can't load %s\n",ofs.szPathName);
+		FreeLibrary16( hModule16 );
+		*err = ERROR_OUTOFMEMORY;
+		return NULL;
+	}
 
-        CloseHandle( hFile );
-    }
+	if (wm->binfmt.pe.pe_export)
+		SNOOP_RegisterDLL(wm->module,wm->modname,wm->binfmt.pe.pe_export->NumberOfFunctions);
 
-    /* Now try the built-in even if disabled */
-    if ( builtin ) {
-        if ( (hModule32 = BUILTIN32_LoadImage( name, &ofs, TRUE )) )
-            WARN( module, "Could not load external DLL '%s', using built-in module.\n", name );
-        else
-            return 0;
-    }
+	*err = 0;
+	return wm;
+}
 
 
-    /* Create 16-bit dummy module */
-    if ((hModule16 = MODULE_CreateDummyModule( &ofs, modName )) < 32) return hModule16;
-    pModule = (NE_MODULE *)GlobalLock16( hModule16 );
-    pModule->flags    = NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA |
-                        NE_FFLAGS_WIN32 | (builtin? NE_FFLAGS_BUILTIN : 0);
-    pModule->module32 = hModule32;
-
-    /* Create 32-bit MODREF */
-    if ( !(wm = PE_CreateModule( hModule32, &ofs, flags, builtin )) )
-    {
-        ERR(win32,"can't load %s\n",ofs.szPathName);
-        FreeLibrary16( hModule16 );
-        return 0;
-    }
-
-    if (wm->binfmt.pe.pe_export)
-        SNOOP_RegisterDLL(wm->module,wm->modname,wm->binfmt.pe.pe_export->NumberOfFunctions);
-
-    return wm->module;
+/*****************************************************************************
+ *	PE_UnloadLibrary
+ *
+ * Unload the library unmapping the image and freeing the modref structure.
+ */
+void PE_UnloadLibrary(WINE_MODREF *wm)
+{
+	/* FIXME, do something here */
 }
 
 /*****************************************************************************
@@ -958,18 +963,11 @@
  * DLL_PROCESS_ATTACH. Only new created threads do DLL_THREAD_ATTACH
  * (SDK)
  */
-void PE_InitDLL(WINE_MODREF *wm, DWORD type, LPVOID lpReserved)
+BOOL PE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
 {
-    if (wm->type!=MODULE32_PE)
-    	return;
+    BOOL retv = TRUE;
+    assert( wm->type == MODULE32_PE );
 
-    /*  DLL_ATTACH_PROCESS:
-     *		lpreserved is NULL for dynamic loads, not-NULL for static loads
-     *  DLL_DETACH_PROCESS:
-     *		lpreserved is NULL if called by FreeLibrary, not-NULL otherwise
-     *  the SDK doesn't mention anything for DLL_THREAD_*
-     */
-        
     /* Is this a library? And has it got an entrypoint? */
     if ((PE_HEADER(wm->module)->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
         (PE_HEADER(wm->module)->OptionalHeader.AddressOfEntryPoint)
@@ -978,8 +976,10 @@
         TRACE(relay, "CallTo32(entryproc=%p,module=%08x,type=%ld,res=%p)\n",
                        entry, wm->module, type, lpReserved );
 
-        entry( wm->module, type, lpReserved );
+        retv = entry( wm->module, type, lpReserved );
     }
+
+    return retv;
 }
 
 /************************************************************************
diff --git a/memory/global.c b/memory/global.c
index e5b9a1b..21da1fc 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -388,7 +388,11 @@
     TRACE(global,"oldsize %08lx\n",oldsize);
     if (ptr && (size == oldsize)) return handle;  /* Nothing to do */
 
-    ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
+    if (((char *)ptr >= DOSMEM_MemoryBase(0)) &&
+        ((char *)ptr <= DOSMEM_MemoryBase(0) + 0x100000))
+        ptr = DOSMEM_ResizeBlock(0, ptr, size, NULL);
+    else
+        ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
     if (!ptr)
     {
         SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
diff --git a/misc/main.c b/misc/main.c
index 54efa8c..71c4721 100644
--- a/misc/main.c
+++ b/misc/main.c
@@ -812,10 +812,6 @@
 
     MONITOR_Initialize(&MONITOR_PrimaryMonitor);
 
-    if (Options.dllFlags)
-	BUILTIN32_ParseDLLOptions( Options.dllFlags );
-	/* if (__winelib && errors ) print_error_message_like_misc_main(); */
-
     atexit(called_at_exit);
     return TRUE;
 }
diff --git a/miscemu/main.c b/miscemu/main.c
index c3c5072..5ee83ee 100644
--- a/miscemu/main.c
+++ b/miscemu/main.c
@@ -140,18 +140,6 @@
     if (!MAIN_WineInit( &argc, argv )) return 1;
     MAIN_argc = argc; MAIN_argv = argv;
 
-    /* Handle -dll option (hack) */
-    if (Options.dllFlags)
-    {
-	/* If there are options left, or if the parser had errors, report it */
-        if (!BUILTIN_ParseDLLOptions( Options.dllFlags )||Options.dllFlags[0]) {
-            MSG("%s: Syntax: -dll +xxx,... or -dll -xxx,...\n",
-                     argv[0] );
-            BUILTIN_PrintDLLs();
-            exit(1);
-        }
-    }
-
     /* Set up debugger/instruction emulation callback routines */
     ctx_debug_call		= ctx_debug;
     fnWINE_Debugger		= wine_debug;
diff --git a/relay32/builtin32.c b/relay32/builtin32.c
index 23af85c..a8421a3 100644
--- a/relay32/builtin32.c
+++ b/relay32/builtin32.c
@@ -14,6 +14,8 @@
 #include "heap.h"
 #include "debug.h"
 #include "main.h"
+#include "snoop.h"
+#include "winerror.h"
 
 typedef struct
 {
@@ -321,6 +323,77 @@
 
 
 /***********************************************************************
+ *           BUILTIN32_LoadLibraryExA
+ *
+ * Partly copied from the original PE_ version.
+ *
+ * Note: This implementation is not very nice and should be one with
+ * the BUILTIN32_LoadImage function. But, we don't care too much
+ * because this code will obsolete itself shortly when we get the
+ * modularization of wine implemented (BS 05-Mar-1999).
+ */
+WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err)
+{
+	LPCSTR		modName = NULL;
+	OFSTRUCT	ofs;
+	HMODULE		hModule32;
+	HMODULE16	hModule16;
+	NE_MODULE	*pModule;
+	WINE_MODREF	*wm;
+	char		dllname[256], *p;
+
+	/* Append .DLL to name if no extension present */
+	strcpy( dllname, path );
+	if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
+		strcat( dllname, ".DLL" );
+
+	hModule32 = BUILTIN32_LoadImage( path, &ofs, TRUE );
+	if(!hModule32)
+	{
+		*err = ERROR_FILE_NOT_FOUND;
+		return NULL;
+	}
+
+	/* Create 16-bit dummy module */
+	if ((hModule16 = MODULE_CreateDummyModule( &ofs, modName )) < 32)
+	{
+		*err = (DWORD)hModule16;
+		return NULL;	/* FIXME: Should unload the builtin module */
+	}
+
+	pModule = (NE_MODULE *)GlobalLock16( hModule16 );
+	pModule->flags = NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA | NE_FFLAGS_WIN32 | NE_FFLAGS_BUILTIN;
+	pModule->module32 = hModule32;
+
+	/* Create 32-bit MODREF */
+	if ( !(wm = PE_CreateModule( hModule32, &ofs, flags, TRUE )) )
+	{
+		ERR(win32,"can't load %s\n",ofs.szPathName);
+		FreeLibrary16( hModule16 );	/* FIXME: Should unload the builtin module */
+		*err = ERROR_OUTOFMEMORY;
+		return NULL;
+	}
+
+	if (wm->binfmt.pe.pe_export)
+		SNOOP_RegisterDLL(wm->module,wm->modname,wm->binfmt.pe.pe_export->NumberOfFunctions);
+
+	*err = 0;
+	return wm;
+}
+
+
+/***********************************************************************
+ *	BUILTIN32_UnloadLibrary
+ *
+ * Unload the built-in library and free the modref.
+ */
+void BUILTIN32_UnloadLibrary(WINE_MODREF *wm)
+{
+	/* FIXME: do something here */
+}
+
+
+/***********************************************************************
  *           BUILTIN32_GetEntryPoint
  *
  * Return the name of the DLL entry point corresponding
@@ -435,74 +508,3 @@
     ExitProcess(1);
 }
 
-/***********************************************************************
- *           BUILTIN32_ParseDLLOptions
- *
- * Set runtime DLL usage flags
- */
-BOOL BUILTIN32_ParseDLLOptions( char *str )
-{
-    BUILTIN32_DLL *dll;
-    char *p,*last;
-
-    last = str;
-    while (*str)
-    {
-        while (*str && (*str==',' || isspace(*str))) str++;
-        if (!*str) {
-	    *last = '\0'; /* cut off garbage at end at */
-	    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 (!lstrncmpiA( dll->descr->name, str, (int)(p-str) ))
-	    {
-	        if (dll->descr->name[p-str]) /* partial match - skip */
-			continue;
-		dll->used = (str[-1]!='-');
-		break;
-	    }
-	}
-        if (!dll->descr) {
-	    /* not found, but could get handled by BUILTIN_, so move last */
-	    last = p;
-	    str = p;
-	} else {
-	    /* handled. cut out the "[+-]DLL," string, so it isn't handled
-	     * by BUILTIN
-	     */
-	    if (*p) {
-		memcpy(last,p,strlen(p)+1);
-		str = last;
-	    } else {
-	    	*last = '\0';
-		break;
-	    }
-	}
-    }
-    return TRUE;
-}
-
-
-
-/***********************************************************************
- *           BUILTIN32_PrintDLLs
- *
- * Print the list of built-in DLLs that can be disabled.
- */
-void BUILTIN32_PrintDLLs(void)
-{
-    int i;
-    BUILTIN32_DLL *dll;
-
-    MSG("Available Win32 DLLs:\n");
-    for (i = 0, dll = BuiltinDLLs; dll->descr; dll++)
-        MSG("%-9s%c", dll->descr->name,
-                 ((++i) % 8) ? ' ' : '\n' );
-    MSG("\n");
-}
diff --git a/scheduler/process.c b/scheduler/process.c
index 94a44b7..5811498 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -486,6 +486,10 @@
     /* Create 32-bit MODREF */
     if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error;
 
+    /* Increment EXE refcount */
+    assert( PROCESS_Current()->exe_modref );
+    PROCESS_Current()->exe_modref->refCount++;
+
     PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0, 0 );   /* FIXME: correct location? */
 
     /* Initialize thread-local storage */
@@ -497,7 +501,9 @@
 
     /* Now call the entry point */
 
-    MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)1 );
+    EnterCriticalSection( &PROCESS_Current()->crit_section );
+    MODULE_DllProcessAttach( PROCESS_Current()->exe_modref, (LPVOID)1 );
+    LeaveCriticalSection( &PROCESS_Current()->crit_section );
 
     PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0, 0 );
 
@@ -651,7 +657,9 @@
  */
 void WINAPI ExitProcess( DWORD status )
 {
-    MODULE_InitializeDLLs( 0, DLL_PROCESS_DETACH, (LPVOID)1 );
+    EnterCriticalSection( &PROCESS_Current()->crit_section );
+    MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
+    LeaveCriticalSection( &PROCESS_Current()->crit_section );
 
     if ( THREAD_IsWin16( THREAD_Current() ) )
         TASK_KillCurrentTask( status );
diff --git a/scheduler/thread.c b/scheduler/thread.c
index b6909ce..c3a39b2 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -281,7 +281,7 @@
     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
     PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0, 0 );
     PE_InitTls();
-    MODULE_InitializeDLLs( 0, DLL_THREAD_ATTACH, NULL );
+    MODULE_DllThreadAttach( NULL );
     ExitThread( func( thdb->entry_arg ) );
 }
 
@@ -318,7 +318,7 @@
  */
 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
 {
-    MODULE_InitializeDLLs( 0, DLL_THREAD_DETACH, NULL );
+    MODULE_DllThreadDetach( NULL );
     TerminateThread( GetCurrentThread(), code );
 }