Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/loader.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 766a3108425..927de8e25f5 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -496,6 +496,16 @@ static void unlock_module_info(void) RtlReleaseSRWLockExclusive( &loader_module_info_lock ); }
+/************************************************************************* + * is_thread_exclusive + * + * The loader must be locked while calling this function. + */ +static BOOL is_thread_exclusive(void) +{ + return RtlDllShutdownInProgress() || exclusive_lock_thread_id == GetCurrentThreadId(); +} + /************************************************************************* * get_cached_modref * @@ -3431,14 +3441,24 @@ NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %x not implemented\n", module, flags );
- lock_loader_exclusive(); + lock_loader_shared();
if ((wm = get_modref( module ))) { - if (flags & LDR_ADDREF_DLL_PIN) - wm->ldr.LoadCount = -1; - else - if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++; + lock_module_info(); + /* If LdrAddRefDll is called during unloading from the application callback + * (DLL entry point or LDR notification) it fails with LDR_ADDREF_DLL_PIN flag + * but succeeds without, while module is still unloaded regardless. */ + if (!wm->ldr.LoadCount) + { + if (is_thread_exclusive()) + ret = flags & LDR_ADDREF_DLL_PIN ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS; + else + ret = STATUS_DLL_NOT_FOUND; + } + else if (flags & LDR_ADDREF_DLL_PIN) wm->ldr.LoadCount = -1; + else if (wm->ldr.LoadCount != -1) ++wm->ldr.LoadCount; + unlock_module_info(); TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount ); } else ret = STATUS_INVALID_PARAMETER;