- implementation of LdrUnloadDll out of loader/module.c

- in impacted functions, ensure that we only use ntdll functions
- making use of new LdrUnloadDll
This commit is contained in:
Eric Pouech 2003-03-14 04:00:52 +00:00 committed by Alexandre Julliard
parent 580da246f5
commit 1efa50e47e
5 changed files with 151 additions and 129 deletions

View File

@ -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.@)
*/

View File

@ -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

View File

@ -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

View File

@ -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 );

View File

@ -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.@)
*/