ntdll: Implement LdrGetDllHandleEx() function.

Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2021-09-27 13:50:01 +03:00 committed by Alexandre Julliard
parent b8d0118517
commit cf0a828b02
4 changed files with 152 additions and 5 deletions

View file

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

View file

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

View file

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

View file

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