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/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;
-}