diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index d72db1d0bf6..541c465a8cc 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -25,8 +25,15 @@ #include "wine/exception.h" #include "excpt.h" #include "wine/debug.h" +#include "wine/server.h" +#include "ntdll_misc.h" WINE_DEFAULT_DEBUG_CHANNEL(ntdll); +WINE_DECLARE_DEBUG_CHANNEL(module); +WINE_DECLARE_DEBUG_CHANNEL(module); +WINE_DECLARE_DEBUG_CHANNEL(loaddll); + +static int free_lib_count; /* recursion depth of FreeLibrary calls */ /* filter for page-fault exceptions */ static WINE_EXCEPTION_FILTER(page_fault) @@ -154,7 +161,6 @@ FARPROC MODULE_GetProcAddress( if ((wm = MODULE32_LookupHMODULE( hModule ))) { retproc = wm->find_export( wm, function, hint, snoop ); - if (!retproc) SetLastError(ERROR_PROC_NOT_FOUND); } RtlLeaveCriticalSection( &loader_section ); return retproc; @@ -172,7 +178,7 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE base, PANSI_STRING name, ULONG or *address = MODULE_GetProcAddress( base, name ? name->Buffer : (LPSTR)ord, -1, TRUE ); - return (*address) ? STATUS_SUCCESS : STATUS_DLL_NOT_FOUND; + return (*address) ? STATUS_SUCCESS : STATUS_PROCEDURE_NOT_FOUND; } @@ -216,6 +222,131 @@ NTSTATUS WINAPI LdrShutdownThread(void) return STATUS_SUCCESS; /* FIXME */ } +/*********************************************************************** + * MODULE_FlushModrefs + * + * 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_FlushModrefs(void) +{ + WINE_MODREF *wm, *next; + + for (wm = MODULE_modref_list; wm; wm = next) + { + next = wm->next; + + if (wm->refCount) + continue; + + /* Unlink this modref from the chain */ + if (wm->next) + wm->next->prev = wm->prev; + if (wm->prev) + wm->prev->next = wm->next; + if (wm == MODULE_modref_list) + MODULE_modref_list = wm->next; + + TRACE(" unloading %s\n", wm->filename); + if (!TRACE_ON(module)) + TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename, + wm->dlhandle ? "builtin" : "native" ); + + SERVER_START_REQ( unload_dll ) + { + req->base = (void *)wm->module; + wine_server_call( req ); + } + SERVER_END_REQ; + + if (wm->dlhandle) wine_dll_unload( wm->dlhandle ); + else UnmapViewOfFile( (LPVOID)wm->module ); + FreeLibrary16( wm->hDummyMod ); + RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps ); + RtlFreeHeap( ntdll_get_process_heap(), 0, wm ); + } +} + +/*********************************************************************** + * 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("(%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; + } +} + +/****************************************************************** + * LdrUnloadDll (NTDLL.@) + * + * + */ +NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule ) +{ + NTSTATUS retv = STATUS_SUCCESS; + + TRACE("(%p)\n", hModule); + + RtlEnterCriticalSection( &loader_section ); + + /* if we're stopping the whole process (and forcing the removal of all + * DLLs) the library will be freed anyway + */ + if (!process_detaching) + { + WINE_MODREF *wm; + + free_lib_count++; + if ((wm = MODULE32_LookupHMODULE( hModule )) != NULL) + { + TRACE("(%s) - START\n", wm->modname); + + /* Recursively decrement reference counts */ + MODULE_DecRefCount( wm ); + + /* Call process detach notifications */ + if ( free_lib_count <= 1 ) + { + MODULE_DllProcessDetach( FALSE, NULL ); + MODULE_FlushModrefs(); + } + + TRACE("END\n"); + } + else + retv = STATUS_DLL_NOT_FOUND; + + free_lib_count--; + } + + RtlLeaveCriticalSection( &loader_section ); + + return retv; +} + /*********************************************************************** * RtlImageNtHeader (NTDLL.@) */ diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 39e2c848bbd..64d848e63de 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -48,7 +48,7 @@ @ stub LdrQueryProcessModuleInformation @ stdcall LdrShutdownProcess() LdrShutdownProcess @ stdcall LdrShutdownThread() LdrShutdownThread -@ stub LdrUnloadDll +@ stdcall LdrUnloadDll(ptr) LdrUnloadDll @ stub LdrVerifyImageMatchesChecksum @ stub NPXEMULATORTABLE @ extern NlsAnsiCodePage NlsAnsiCodePage diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 618001ecad4..38ebcb40c85 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -21,6 +21,7 @@ #include "winnt.h" #include "winternl.h" +#include "thread.h" /* debug helper */ extern LPCSTR debugstr_us( const UNICODE_STRING *str ); @@ -29,4 +30,10 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes); /* module handling */ extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop ); +static inline HANDLE ntdll_get_process_heap(void) +{ + HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process; + return pdb[0x18 / sizeof(HANDLE)]; /* get dword at offset 0x18 in pdb */ +} + #endif diff --git a/include/module.h b/include/module.h index b8688fe8b20..195eaf57a6c 100644 --- a/include/module.h +++ b/include/module.h @@ -194,12 +194,10 @@ enum binary_type /* module.c */ extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ); -extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop ); extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ); extern void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved ); extern void MODULE_DllThreadAttach( LPVOID lpReserved ); extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HANDLE hfile, DWORD flags ); -extern BOOL MODULE_FreeLibrary( WINE_MODREF *wm ); extern WINE_MODREF *MODULE_FindModule( LPCSTR path ); extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 ); extern enum binary_type MODULE_GetBinaryType( HANDLE hfile ); diff --git a/loader/module.c b/loader/module.c index a27d5cc31f8..649de9ce28b 100644 --- a/loader/module.c +++ b/loader/module.c @@ -48,7 +48,6 @@ WINE_DECLARE_DEBUG_CHANNEL(loaddll); WINE_MODREF *MODULE_modref_list = NULL; WINE_MODREF *exe_modref; -static int free_lib_count; /* recursion depth of FreeLibrary calls */ int process_detaching = 0; /* set on process detach to avoid deadlocks with thread detach */ CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" ); @@ -1083,7 +1082,7 @@ HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags) if ( !MODULE_DllProcessAttach( wm, NULL ) ) { WARN_(module)("Attach failed for module '%s'.\n", libname); - MODULE_FreeLibrary(wm); + LdrUnloadDll(wm->module); SetLastError(ERROR_DLL_INIT_FAILED); wm = NULL; } @@ -1333,67 +1332,14 @@ HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW,HANDLE hfile,DWORD flags) return ret; } -/*********************************************************************** - * MODULE_FlushModrefs - * - * 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_FlushModrefs(void) -{ - WINE_MODREF *wm, *next; - - for(wm = MODULE_modref_list; wm; wm = next) - { - next = wm->next; - - if(wm->refCount) - continue; - - /* Unlink this modref from the chain */ - if(wm->next) - wm->next->prev = wm->prev; - if(wm->prev) - wm->prev->next = wm->next; - if(wm == MODULE_modref_list) - MODULE_modref_list = wm->next; - - TRACE(" unloading %s\n", wm->filename); - if (!TRACE_ON(module)) - TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename, - wm->dlhandle ? "builtin" : "native" ); - - SERVER_START_REQ( unload_dll ) - { - req->base = (void *)wm->module; - wine_server_call( req ); - } - SERVER_END_REQ; - - if (wm->dlhandle) wine_dll_unload( wm->dlhandle ); - else UnmapViewOfFile( (LPVOID)wm->module ); - FreeLibrary16(wm->hDummyMod); - HeapFree( GetProcessHeap(), 0, wm->deps ); - HeapFree( GetProcessHeap(), 0, wm ); - } -} - /*********************************************************************** * FreeLibrary (KERNEL32.@) * FreeLibrary32 (KERNEL.486) */ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) { - BOOL retv = FALSE; - WINE_MODREF *wm; - - if (!hLibModule) - { - SetLastError( ERROR_INVALID_HANDLE ); - return FALSE; - } + BOOL retv = FALSE; + NTSTATUS nts; if ((ULONG_PTR)hLibModule & 1) { @@ -1402,80 +1348,20 @@ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) UnmapViewOfFile( ptr ); return TRUE; } - - RtlEnterCriticalSection( &loader_section ); - - /* if we're stopping the whole process (and forcing the removal of all - * DLLs) the library will be freed anyway - */ - if (process_detaching) retv = TRUE; - else + + if (!hLibModule) { - free_lib_count++; - if ((wm = MODULE32_LookupHMODULE( hLibModule ))) retv = MODULE_FreeLibrary( wm ); - free_lib_count--; + SetLastError( ERROR_INVALID_HANDLE ); + RtlLeaveCriticalSection( &loader_section ); + return FALSE; } - RtlLeaveCriticalSection( &loader_section ); + if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE; + else SetLastError( RtlNtStatusToDosError( nts ) ); 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("(%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("(%s) - START\n", wm->modname ); - - /* Recursively decrement reference counts */ - MODULE_DecRefCount( wm ); - - /* Call process detach notifications */ - if ( free_lib_count <= 1 ) - { - MODULE_DllProcessDetach( FALSE, NULL ); - MODULE_FlushModrefs(); - } - - TRACE("END\n"); - - return TRUE; -} - - /*********************************************************************** * FreeLibraryAndExitThread (KERNEL32.@) */