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