Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/kernel32/tests/module.c | 107 +++++++++++++++++++++++++++++++++++ dlls/ntdll/loader.c | 44 ++++++++++++-- dlls/ntdll/ntdll.spec | 1 + include/winternl.h | 5 ++ 4 files changed, 152 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/tests/module.c b/dlls/kernel32/tests/module.c index 0066f7de5a8..5ca137ad6ba 100644 --- a/dlls/kernel32/tests/module.c +++ b/dlls/kernel32/tests/module.c @@ -39,6 +39,9 @@ static BOOL (WINAPI *pK32GetModuleInformation)(HANDLE process, HMODULE module,
static NTSTATUS (WINAPI *pLdrGetDllDirectory)(UNICODE_STRING*); static NTSTATUS (WINAPI *pLdrSetDllDirectory)(UNICODE_STRING*); +static NTSTATUS (WINAPI *pLdrGetDllHandle)( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base ); +static NTSTATUS (WINAPI *pLdrGetDllHandleEx)( ULONG flags, LPCWSTR load_path, ULONG *dll_characteristics, + const UNICODE_STRING *name, HMODULE *base );
static BOOL is_unicode_enabled = TRUE;
@@ -826,6 +829,8 @@ static void init_pointers(void) mod = GetModuleHandleA( "ntdll.dll" ); MAKEFUNC(LdrGetDllDirectory); MAKEFUNC(LdrSetDllDirectory); + MAKEFUNC(LdrGetDllHandle); + MAKEFUNC(LdrGetDllHandleEx); #undef MAKEFUNC
/* before Windows 7 this was not exported in kernel32 */ @@ -1143,6 +1148,107 @@ static void test_SetDefaultDllDirectories(void) pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_DEFAULT_DIRS ); }
+static void check_refcount( HMODULE mod, unsigned int refcount ) +{ + unsigned int i; + BOOL ret; + + for (i = 0; i < min( refcount, 10 ); ++i) + { + ret = FreeLibrary( mod ); + ok( ret || broken( refcount == ~0u && GetLastError() == ERROR_MOD_NOT_FOUND && i == 2 ) /* Win8 */, + "Refcount test failed, i %u, error %u.\n", i, GetLastError() ); + if (!ret) return; + } + if (refcount != ~0u) + { + ret = FreeLibrary( mod ); + ok( !ret && GetLastError() == ERROR_MOD_NOT_FOUND, "Refcount test failed, ret %d, error %u.\n", + ret, GetLastError() ); + } +} + +static void test_LdrGetDllHandleEx(void) +{ + HMODULE mod, loaded_mod; + UNICODE_STRING name; + NTSTATUS status; + unsigned int i; + + if (!pLdrGetDllHandleEx) + { + win_skip( "LdrGetDllHandleEx is not available.\n" ); + return; + } + + RtlInitUnicodeString( &name, L"unknown.dll" ); + status = pLdrGetDllHandleEx( 0, NULL, NULL, &name, &mod ); + ok( status == STATUS_DLL_NOT_FOUND, "Got unexpected status %#x.\n", status ); + + RtlInitUnicodeString( &name, L"authz.dll" ); + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( 0, NULL, NULL, &name, &mod ); + ok( !status, "Got unexpected status %#x.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "Flags 0" ); + check_refcount( loaded_mod, 2 ); + winetest_pop_context(); + + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, + NULL, &name, &mod ); + ok( !status, "Got unexpected status %#x.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT" ); + check_refcount( loaded_mod, 1 ); + winetest_pop_context(); + + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandle( NULL, ~0u, &name, &mod ); + ok( !status, "Got unexpected status %#x.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "LdrGetDllHandle" ); + check_refcount( loaded_mod, 1 ); + winetest_pop_context(); + + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( 4, NULL, NULL, (void *)&name, &mod ); + ok( !status, "Got unexpected status %#x.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "Flag 4" ); + check_refcount( loaded_mod, 2 ); + winetest_pop_context(); + + for (i = 3; i < 32; ++i) + { + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( 1 << i, NULL, NULL, &name, &mod ); + ok( status == STATUS_INVALID_PARAMETER, "Got unexpected status %#x.\n", status ); + winetest_push_context( "Invalid flags, i %u", i ); + check_refcount( loaded_mod, 1 ); + winetest_pop_context(); + } + + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_PIN | LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + NULL, NULL, &name, &mod ); + ok( status == STATUS_INVALID_PARAMETER, "Got unexpected status %#x.\n", status ); + + loaded_mod = LoadLibraryW( name.Buffer ); + ok( !!loaded_mod, "Failed to load module.\n" ); + status = pLdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_PIN, NULL, + NULL, &name, &mod ); + ok( !status, "Got unexpected status %#x.\n", status ); + ok( mod == loaded_mod, "got %p\n", mod ); + winetest_push_context( "LDR_GET_DLL_HANDLE_EX_FLAG_PIN" ); + check_refcount( loaded_mod, ~0u ); + winetest_pop_context(); +} + START_TEST(module) { WCHAR filenameW[MAX_PATH]; @@ -1175,4 +1281,5 @@ START_TEST(module) testK32GetModuleInformation(); test_AddDllDirectory(); test_SetDefaultDllDirectories(); + test_LdrGetDllHandleEx(); } diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 819cf51b9fc..339873129f3 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -2996,16 +2996,33 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
/****************************************************************** - * LdrGetDllHandle (NTDLL.@) + * LdrGetDllHandleEx (NTDLL.@) */ -NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base ) +NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_characteristics, + const UNICODE_STRING *name, HMODULE *base ) { - NTSTATUS status; + static const ULONG supported_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT + | LDR_GET_DLL_HANDLE_EX_FLAG_PIN; + static const ULONG valid_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT + | LDR_GET_DLL_HANDLE_EX_FLAG_PIN | 4; + SECTION_IMAGE_INFORMATION image_info; UNICODE_STRING nt_name; + struct file_id id; + NTSTATUS status; WINE_MODREF *wm; HANDLE mapping; - SECTION_IMAGE_INFORMATION image_info; - struct file_id id; + + TRACE( "flag %#x, load_path %p, dll_characteristics %p, name %p, base %p.\n", + flags, load_path, dll_characteristics, name, base ); + + if (flags & ~valid_flags) return STATUS_INVALID_PARAMETER; + + if ((flags & (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN)) + == (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN)) + return STATUS_INVALID_PARAMETER; + + if (flags & ~supported_flags) FIXME( "Unsupported flags %#x.\n", flags ); + if (dll_characteristics) FIXME( "dll_characteristics unsupported.\n" );
RtlEnterCriticalSection( &loader_section );
@@ -3019,12 +3036,29 @@ NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_S } RtlFreeUnicodeString( &nt_name );
+ if (!status) + { + if (flags & LDR_GET_DLL_HANDLE_EX_FLAG_PIN) + LdrAddRefDll( LDR_ADDREF_DLL_PIN, *base ); + else if (!(flags & LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) + LdrAddRefDll( 0, *base ); + } + RtlLeaveCriticalSection( &loader_section ); TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) ); return status; }
+/****************************************************************** + * LdrGetDllHandle (NTDLL.@) + */ +NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base ) +{ + return LdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, load_path, NULL, name, base ); +} + + /****************************************************************** * LdrAddRefDll (NTDLL.@) */ diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 9837b09fd51..0f8ddbea669 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -88,6 +88,7 @@ @ stub LdrFlushAlternateResourceModules @ stdcall LdrGetDllDirectory(ptr) @ stdcall LdrGetDllHandle(wstr long ptr ptr) +@ stdcall LdrGetDllHandleEx(long ptr ptr ptr ptr) # @ stub LdrGetDllHandleEx @ stdcall LdrGetDllPath(wstr long ptr ptr) @ stdcall LdrGetProcedureAddress(ptr ptr long ptr) diff --git a/include/winternl.h b/include/winternl.h index 9e96591ad8e..7a3a5e94702 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3380,6 +3380,10 @@ typedef void (CALLBACK *PLDR_DLL_NOTIFICATION_FUNCTION)(ULONG, LDR_DLL_NOTIFICAT /* flag for LdrAddRefDll */ #define LDR_ADDREF_DLL_PIN 0x00000001
+/* flags for LdrGetDllHandleEx */ +#define LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x00000001 +#define LDR_GET_DLL_HANDLE_EX_FLAG_PIN 0x00000002 + #define LDR_DLL_NOTIFICATION_REASON_LOADED 1 #define LDR_DLL_NOTIFICATION_REASON_UNLOADED 2
@@ -3778,6 +3782,7 @@ NTSYSAPI NTSTATUS WINAPI LdrFindResourceDirectory_U(HMODULE,const LDR_RESOURCE_ NTSYSAPI NTSTATUS WINAPI LdrFindResource_U(HMODULE,const LDR_RESOURCE_INFO*,ULONG,const IMAGE_RESOURCE_DATA_ENTRY**); NTSYSAPI NTSTATUS WINAPI LdrGetDllDirectory(UNICODE_STRING*); NTSYSAPI NTSTATUS WINAPI LdrGetDllHandle(LPCWSTR, ULONG, const UNICODE_STRING*, HMODULE*); +NTSYSAPI NTSTATUS WINAPI LdrGetDllHandleEx(ULONG, LPCWSTR, ULONG *, const UNICODE_STRING*, HMODULE*); NTSYSAPI NTSTATUS WINAPI LdrGetDllPath(PCWSTR,ULONG,PWSTR*,PWSTR*); NTSYSAPI NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE, const ANSI_STRING*, ULONG, void**); NTSYSAPI NTSTATUS WINAPI LdrLoadDll(LPCWSTR, DWORD, const UNICODE_STRING*, HMODULE*);
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/kernelbase/loader.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/dlls/kernelbase/loader.c b/dlls/kernelbase/loader.c index ac463528e3c..a662305a250 100644 --- a/dlls/kernelbase/loader.c +++ b/dlls/kernelbase/loader.c @@ -375,8 +375,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetModuleHandleExW( DWORD flags, LPCWSTR name, HMO { NTSTATUS status = STATUS_SUCCESS; HMODULE ret = NULL; - ULONG_PTR magic; - BOOL lock;
if (!module) { @@ -384,10 +382,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetModuleHandleExW( DWORD flags, LPCWSTR name, HMO return FALSE; }
- /* if we are messing with the refcount, grab the loader lock */ - lock = (flags & GET_MODULE_HANDLE_EX_FLAG_PIN) || !(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT); - if (lock) LdrLockLoaderLock( 0, NULL, &magic ); - if (!name) { ret = NtCurrentTeb()->Peb->ImageBaseAddress; @@ -400,20 +394,26 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetModuleHandleExW( DWORD flags, LPCWSTR name, HMO else { UNICODE_STRING wstr; + ULONG ldr_flags = 0; + + if (flags & GET_MODULE_HANDLE_EX_FLAG_PIN) + ldr_flags |= LDR_GET_DLL_HANDLE_EX_FLAG_PIN; + if (flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) + ldr_flags |= LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; + RtlInitUnicodeString( &wstr, name ); - status = LdrGetDllHandle( NULL, 0, &wstr, &ret ); + status = LdrGetDllHandleEx( ldr_flags, NULL, NULL, &wstr, &ret ); + flags = GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; }
if (status == STATUS_SUCCESS) { if (flags & GET_MODULE_HANDLE_EX_FLAG_PIN) - LdrAddRefDll( LDR_ADDREF_DLL_PIN, ret ); + status = LdrAddRefDll( LDR_ADDREF_DLL_PIN, ret ); else if (!(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) - LdrAddRefDll( 0, ret ); + status = LdrAddRefDll( 0, ret ); }
- if (lock) LdrUnlockLoaderLock( 0, magic ); - *module = ret; return set_ntstatus( status ); }