Fixed sequence of DLL_PROCESS_DETACH notification calls.
Moved PE_MODREF flags to WINE_MODREF level.
Better handling of LoadLibraryEx flags.
PE_InitTls() changed to work only on the current thread.

diff --git a/include/module.h b/include/module.h
index 9a81bd7..4ae9d7b 100644
--- a/include/module.h
+++ b/include/module.h
@@ -111,6 +111,7 @@
 typedef struct _wine_modref
 {
 	struct _wine_modref	*next;
+	struct _wine_modref	*prev;
 	MODULE32_TYPE		type;
 	union {
 		PE_MODREF	pe;
@@ -121,13 +122,24 @@
 
 	int			nDeps;
 	struct _wine_modref	**deps;
-	int			initDone;
+
+	int			flags;
+	int			refCount;
 
 	char			*modname;
 	char			*shortname;
 	char 			*longname;
 } WINE_MODREF;
 
+#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
+
+
 
 /* Resource types */
 typedef struct resource_typeinfo_s NE_TYPEINFO;
diff --git a/include/pe_image.h b/include/pe_image.h
index 7ba71f5..9ce289f 100644
--- a/include/pe_image.h
+++ b/include/pe_image.h
@@ -11,12 +11,6 @@
 	PIMAGE_IMPORT_DESCRIPTOR	pe_import;
 	PIMAGE_EXPORT_DIRECTORY	pe_export;
 	PIMAGE_RESOURCE_DIRECTORY	pe_resource;
-	int				flags;
-#define PE_MODREF_PROCESS_ATTACHED	0x00000001
-#define PE_MODREF_NO_DLL_CALLS		0x00000002
-#define PE_MODREF_RELOCS_DONE		0x00000004
-#define PE_MODREF_TLS_ALLOCED		0x00000008
-#define PE_MODREF_INTERNAL		0x00000010
 	int				tlsindex;
 } PE_MODREF;
 
@@ -41,8 +35,7 @@
                               BOOL inherit, LPSTARTUPINFOA startup,
                               LPPROCESS_INFORMATION info );
 
-struct _THDB; /* forward definition */
-extern void PE_InitTls(struct _THDB*);
+extern void PE_InitTls(void);
 extern void PE_InitDLL(struct _wine_modref *wm, DWORD type, LPVOID lpReserved);
 
 extern PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA(PIMAGE_RESOURCE_DIRECTORY,LPCSTR,DWORD,BOOL);
diff --git a/include/thread.h b/include/thread.h
index 7bb63a0..4c275cf 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -123,7 +123,6 @@
 extern THDB *THREAD_Current(void);
 extern BOOL THREAD_IsWin16( THDB *thdb );
 extern THDB *THREAD_IdToTHDB( DWORD id );
-extern DWORD THREAD_TlsAlloc( THDB *thread );
 
 /* scheduler/sysdeps.c */
 extern int SYSDEPS_SpawnThread( THDB *thread );
diff --git a/loader/module.c b/loader/module.c
index 86cc727..9d1008e 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -73,37 +73,84 @@
 static void MODULE_DoInitializeDLLs( WINE_MODREF *wm,
                                      DWORD type, LPVOID lpReserved )
 {
-    int i;
+    WINE_MODREF *xwm;
+    int i, skip = FALSE;
 
-    assert( wm && !wm->initDone );
-    TRACE( module, "(%08x,%ld,%p) - START\n", 
-           wm->module, type, lpReserved );
+    assert( wm && !(wm->flags & WINE_MODREF_MARKER) );
+    TRACE( module, "(%s,%08x,%ld,%p) - START\n", 
+           wm->modname, wm->module, type, lpReserved );
 
     /* Tag current MODREF to prevent recursive loop */
-    wm->initDone = TRUE;
+    wm->flags |= WINE_MODREF_MARKER;
 
-    /* Recursively initialize all child DLLs */
-    for ( i = 0; i < wm->nDeps; i++ )
-        if ( wm->deps[i] && !wm->deps[i]->initDone )
-            MODULE_DoInitializeDLLs( wm->deps[i], type, lpReserved );
-
-    /* Now we can call the initialization routine */
-    switch ( wm->type )
+    switch ( type )
     {
-    case MODULE32_PE:
-        PE_InitDLL( wm, type, lpReserved );
+    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 MODULE32_ELF:
-    	/* no need to do that, dlopen() already does */
-    	break;
-    default:
-    	ERR(module, "wine_modref type %d not handled.\n", wm->type);
+    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;
     }
 
-    TRACE( module, "(%08x,%ld,%p) - END\n", 
-           wm->module, type, lpReserved );
+    /* 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
+            wm->flags |= WINE_MODREF_PROCESS_ATTACHED;
+
+    if ( type == DLL_PROCESS_DETACH )
+        if ( wm->flags & WINE_MODREF_PROCESS_DETACHED )
+            skip = TRUE;
+        else
+            wm->flags |= WINE_MODREF_PROCESS_DETACHED;
+
+    if ( !skip )
+    {
+        /* Now we can call the initialization routine */
+        TRACE( module, "(%s,%08x,%ld,%p) - CALL\n", 
+               wm->modname, wm->module, type, lpReserved );
+
+        switch ( wm->type )
+        {
+        case MODULE32_PE:
+            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);
+           break;
+        }
+    }
+
+    TRACE( module, "(%s,%08x,%ld,%p) - END\n", 
+           wm->modname, wm->module, type, lpReserved );
 }
 
 void MODULE_InitializeDLLs( HMODULE root, DWORD type, LPVOID lpReserved )
@@ -119,7 +166,7 @@
 
     /* First, check whether initialization is currently in progress */
     for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
-        if ( wm->initDone )
+        if ( wm->flags & WINE_MODREF_MARKER )
         {
             inProgress = TRUE;
             break;
@@ -135,7 +182,7 @@
         if ( root )
         {
             wm = MODULE32_LookupHMODULE( root );
-            if ( wm && !wm->initDone )
+            if ( wm && !(wm->flags & WINE_MODREF_MARKER) )
                 MODULE_DoInitializeDLLs( wm, type, lpReserved );
         }
         else
@@ -147,9 +194,26 @@
         if ( !root )
         {
             /* If called for main EXE, initialize all DLLs */
-            for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
-                if ( !wm->initDone )
-                    MODULE_DoInitializeDLLs( wm, type, lpReserved );
+            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;
+
+            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
         {
@@ -160,7 +224,7 @@
 
         /* We're finished, so we reset all recursion flags */
         for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
-            wm->initDone = FALSE;
+            wm->flags &= ~WINE_MODREF_MARKER;
     }
 
     TRACE( module, "(%08x,%ld,%p) - END\n", root, type, lpReserved );
@@ -169,6 +233,49 @@
     LeaveCriticalSection( &PROCESS_Current()->crit_section );
 }
 
+/****************************************************************************
+ *              DisableThreadLibraryCalls (KERNEL32.74)
+ *
+ * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
+ */
+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 = MODULE32_LookupHMODULE( hModule );
+    if ( !wm ) return;
+
+    EnterCriticalSection( &PROCESS_Current()->crit_section );
+    wm->refCount++;
+    LeaveCriticalSection( &PROCESS_Current()->crit_section );
+}
+
+/****************************************************************************
+ *              MODULE_DecRefCount
+ */
+static int MODULE_DecRefCount( HMODULE hModule )
+{
+    int retv;
+    WINE_MODREF *wm = MODULE32_LookupHMODULE( hModule );
+    if ( !wm ) return 0;
+
+    EnterCriticalSection( &PROCESS_Current()->crit_section );
+    if ( ( retv = wm->refCount ) > 0 ) wm->refCount--;
+    LeaveCriticalSection( &PROCESS_Current()->crit_section );
+
+    return retv;
+}
+
 
 /***********************************************************************
  *           MODULE_CreateDummyModule
@@ -1103,15 +1210,14 @@
     HMODULE hmod;
     hmod = MODULE_LoadLibraryExA( libname, hfile, flags );
 
-    /* at least call not the dllmain...*/
-    if ( DONT_RESOLVE_DLL_REFERENCES==flags || LOAD_LIBRARY_AS_DATAFILE==flags )
-    { FIXME(module,"flag not properly supported %lx\n", flags);
-      return hmod;
-    }
+    if ( hmod >= 32 )
+    {
+        /* Increment RefCount */
+        MODULE_IncRefCount( hmod );
 
-    /* initialize DLL just loaded */
-    if ( hmod >= 32 )       
-        MODULE_InitializeDLLs( hmod, DLL_PROCESS_ATTACH, (LPVOID)-1 );
+        /* Initialize DLL just loaded */
+        MODULE_InitializeDLLs( hmod, DLL_PROCESS_ATTACH, NULL );
+    }
 
     return hmod;
 }
@@ -1159,8 +1265,10 @@
  */
 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
 {
-    FIXME(module,"(0x%08x): stub\n", hLibModule);
-    return TRUE;  /* FIXME */
+    if ( MODULE_DecRefCount( hLibModule ) != 1 ) return TRUE;
+
+    FIXME(module,"(0x%08x): should unload now\n", hLibModule);
+    return TRUE; /* FIXME */
 }
 
 /***********************************************************************
diff --git a/loader/pe_image.c b/loader/pe_image.c
index b6e0466..4982dc4 100644
--- a/loader/pe_image.c
+++ b/loader/pe_image.c
@@ -740,11 +740,18 @@
                                    HEAP_ZERO_MEMORY, sizeof(*wm) );
     wm->module = hModule;
 
+    if ( builtin ) 
+        wm->flags |= WINE_MODREF_INTERNAL;
+    if ( flags & DONT_RESOLVE_DLL_REFERENCES )
+        wm->flags |= WINE_MODREF_DONT_RESOLVE_REFS;
+    if ( flags & LOAD_LIBRARY_AS_DATAFILE )
+        wm->flags |= WINE_MODREF_LOAD_AS_DATAFILE;
+
     wm->type = MODULE32_PE;
-    wm->binfmt.pe.flags = builtin? PE_MODREF_INTERNAL : 0;
     wm->binfmt.pe.pe_export = pe_export;
     wm->binfmt.pe.pe_import = pe_import;
     wm->binfmt.pe.pe_resource = pe_resource;
+    wm->binfmt.pe.tlsindex = -1;
 
     if ( pe_export ) 
         modname = (char *)RVA( pe_export->Name );
@@ -753,8 +760,7 @@
         /* try to find out the name from the OFSTRUCT */
         char *s;
         modname = ofs->szPathName;
-        while ((s=strchr(modname,'\\')))
-            modname = s+1;
+        if ((s=strrchr(modname,'\\'))) modname = s+1;
     }
     wm->modname = HEAP_strdupA( GetProcessHeap(), 0, modname );
 
@@ -766,8 +772,11 @@
 
     /* Link MODREF into process list */
 
+    EnterCriticalSection( &PROCESS_Current()->crit_section );
+
     wm->next = PROCESS_Current()->modref_list;
     PROCESS_Current()->modref_list = wm;
+    if ( wm->next ) wm->next->prev = wm;
 
     if ( !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) )
     {
@@ -776,6 +785,9 @@
         PROCESS_Current()->exe_modref = wm;
     }
 
+    LeaveCriticalSection( &PROCESS_Current()->crit_section );
+
+
     /* Dump Exports */
 
     if ( pe_export )
@@ -783,16 +795,23 @@
 
     /* Fixup Imports */
 
-    if ( pe_import && fixup_imports( wm ) ) 
+    if (    pe_import && fixup_imports( wm ) 
+         && !( wm->flags & WINE_MODREF_LOAD_AS_DATAFILE )
+         && !( wm->flags & WINE_MODREF_DONT_RESOLVE_REFS ) ) 
     {
         /* remove entry from modref chain */
-        WINE_MODREF **xwm;
-        for ( xwm = &PROCESS_Current()->modref_list; *xwm; xwm = &(*xwm)->next )
-            if ( *xwm == wm )
-            {
-                *xwm = wm->next;
-                break;
-            }
+        EnterCriticalSection( &PROCESS_Current()->crit_section );
+
+        if ( !wm->prev )
+            PROCESS_Current()->modref_list = wm->next;
+        else
+            wm->prev->next = wm->next;
+
+        if ( wm->next ) wm->next->prev = wm->prev;
+        wm->next = wm->prev = NULL;
+
+        LeaveCriticalSection( &PROCESS_Current()->crit_section );
+
         /* FIXME: there are several more dangling references
          * left. Including dlls loaded by this dll before the
          * failed one. Unrolling is rather difficult with the
@@ -943,15 +962,6 @@
 {
     if (wm->type!=MODULE32_PE)
     	return;
-    if (wm->binfmt.pe.flags & PE_MODREF_NO_DLL_CALLS)
-    	return;
-    if (type==DLL_PROCESS_ATTACH)
-    {
-        if (wm->binfmt.pe.flags & PE_MODREF_PROCESS_ATTACHED)
-            return;
-
-        wm->binfmt.pe.flags |= PE_MODREF_PROCESS_ATTACHED;
-    }
 
     /*  DLL_ATTACH_PROCESS:
      *		lpreserved is NULL for dynamic loads, not-NULL for static loads
@@ -979,7 +989,7 @@
  * Pointers in those structs are not RVAs but real pointers which have been
  * relocated by do_relocations() already.
  */
-void PE_InitTls(THDB *thdb)
+void PE_InitTls( void )
 {
 	WINE_MODREF		*wm;
 	PE_MODREF		*pem;
@@ -987,10 +997,9 @@
 	DWORD			size,datasize;
 	LPVOID			mem;
 	PIMAGE_TLS_DIRECTORY	pdir;
-	PDB			*pdb = thdb->process;
         int delta;
 	
-	for (wm = pdb->modref_list;wm;wm=wm->next) {
+	for (wm = PROCESS_Current()->modref_list;wm;wm=wm->next) {
 		if (wm->type!=MODULE32_PE)
 			continue;
 		pem = &(wm->binfmt.pe);
@@ -1002,11 +1011,10 @@
 			DataDirectory[IMAGE_FILE_THREAD_LOCAL_STORAGE].VirtualAddress);
 		
 		
-		if (!(pem->flags & PE_MODREF_TLS_ALLOCED)) {
-			pem->tlsindex = THREAD_TlsAlloc(thdb);
+		if ( pem->tlsindex == -1 ) {
+			pem->tlsindex = TlsAlloc();
 			*pdir->AddressOfIndex=pem->tlsindex;   
 		}
-		pem->flags |= PE_MODREF_TLS_ALLOCED;
 		datasize= pdir->EndAddressOfRawData-pdir->StartAddressOfRawData;
 		size	= datasize + pdir->SizeOfZeroFill;
 		mem=VirtualAlloc(0,size,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
@@ -1018,21 +1026,8 @@
 		     if (*cbs)
 		       FIXME(win32, "TLS Callbacks aren't going to be called\n");
 		}
-		/* Don't use TlsSetValue, we are in the wrong thread */
-		thdb->tls_array[pem->tlsindex] = mem;
+
+		TlsSetValue( pem->tlsindex, mem );
 	}
 }
 
-/****************************************************************************
- *		DisableThreadLibraryCalls (KERNEL32.74)
- * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
- */
-BOOL WINAPI DisableThreadLibraryCalls(HMODULE hModule)
-{
-	WINE_MODREF	*wm;
-
-	for (wm=PROCESS_Current()->modref_list;wm;wm=wm->next)
-		if ((wm->module == hModule) && (wm->type==MODULE32_PE))
-			wm->binfmt.pe.flags|=PE_MODREF_NO_DLL_CALLS;
-	return TRUE;
-}
diff --git a/scheduler/process.c b/scheduler/process.c
index fa96c6f..b1450f3 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -363,14 +363,14 @@
 
     /* Initialize thread-local storage */
 
-    PE_InitTls( thdb );
+    PE_InitTls();
 
     if (PE_HEADER(pModule->module32)->OptionalHeader.Subsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI)
         AllocConsole();
 
     /* Now call the entry point */
 
-    MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)-1 );
+    MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)1 );
     entry = (LPTHREAD_START_ROUTINE)RVA_PTR(pModule->module32,
                                             OptionalHeader.AddressOfEntryPoint);
     TRACE(relay, "(entryproc=%p)\n", entry );
@@ -509,7 +509,7 @@
  */
 void WINAPI ExitProcess( DWORD status )
 {
-    MODULE_InitializeDLLs( 0, DLL_PROCESS_DETACH, NULL );
+    MODULE_InitializeDLLs( 0, DLL_PROCESS_DETACH, (LPVOID)1 );
 
     if ( THREAD_IsWin16( THREAD_Current() ) )
         TASK_KillCurrentTask( status );
diff --git a/scheduler/thread.c b/scheduler/thread.c
index b9c6ee2..28c8a1f 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -261,7 +261,6 @@
     if (!THREAD_InitTHDB( thdb, stack_size, alloc_stack16, sa )) goto error;
     thdb->next = THREAD_First;
     THREAD_First = thdb;
-    PE_InitTls( thdb );
     return thdb;
 
 error:
@@ -282,6 +281,7 @@
 {
     THDB *thdb = THREAD_Current();
     LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)thdb->entry_point;
+    PE_InitTls();
     MODULE_InitializeDLLs( 0, DLL_THREAD_ATTACH, NULL );
     ExitThread( func( thdb->entry_arg ) );
 }
@@ -412,10 +412,17 @@
 
 
 /**********************************************************************
- *           THREAD_TlsAlloc
+ * TlsAlloc [KERNEL32.530]  Allocates a TLS index.
+ *
+ * Allocates a thread local storage index
+ *
+ * RETURNS
+ *    Success: TLS Index
+ *    Failure: 0xFFFFFFFF
  */
-DWORD THREAD_TlsAlloc(THDB *thread)
+DWORD WINAPI TlsAlloc( void )
 {
+    THDB *thread = THREAD_Current();
     DWORD i, mask, ret = 0;
     DWORD *bits = thread->process->tls_bits;
     EnterCriticalSection( &thread->process->crit_section );
@@ -438,21 +445,6 @@
 
 
 /**********************************************************************
- * TlsAlloc [KERNEL32.530]  Allocates a TLS index.
- *
- * Allocates a thread local storage index
- *
- * RETURNS
- *    Success: TLS Index
- *    Failure: 0xFFFFFFFF
- */
-DWORD WINAPI TlsAlloc(void)
-{
-    return THREAD_TlsAlloc(THREAD_Current());
-}
-
-
-/**********************************************************************
  * TlsFree [KERNEL32.531]  Releases a TLS index.
  *
  * Releases a thread local storage index, making it available for reuse