[PATCH 1/2] ntdll: Implement LdrGetDllHandleEx() function.

Paul Gofman pgofman at codeweavers.com
Fri Sep 24 15:18:59 CDT 2021


Signed-off-by: Paul Gofman <pgofman at 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*);
-- 
2.31.1




More information about the wine-devel mailing list