From 455721236e88a072e171c41e146c2dbce21f7ce4 Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Mon, 9 May 2016 10:55:42 -0700 Subject: [PATCH 3/3] kernel32: Implement Add/RemoveDllDirectory msdn says you can't mix LOAD_WITH_ALTERED_SEARCH_PATH with LOAD_LIBRARY_SEARCH_* flags win7 returns an error but win8+ silently ignores and follows behavior in the tests Signed-off-by: Daniel Lehman --- dlls/kernel32/module.c | 79 +++++++++++++++++++++++++++++++++++++++----- dlls/kernel32/tests/module.c | 71 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 8 deletions(-) diff --git a/dlls/kernel32/module.c b/dlls/kernel32/module.c index fbf2c69..6d635c1 100644 --- a/dlls/kernel32/module.c +++ b/dlls/kernel32/module.c @@ -43,12 +43,20 @@ #include "wine/exception.h" #include "wine/debug.h" #include "wine/unicode.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(module); #define NE_FFLAGS_LIBMODULE 0x8000 static WCHAR *dll_directory; /* extra path for SetDllDirectoryW */ +static struct list dll_directories = LIST_INIT(dll_directories); /* extra paths for AddDllDirectory */ + +struct dir_entry { + struct list entry; + DWORD len; + WCHAR name[1]; +}; static CRITICAL_SECTION dlldir_section; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -772,18 +780,19 @@ static inline const WCHAR *get_module_path_end(const WCHAR *module) } /****************************************************************** - * MODULE_get_dll_load_path + * get_dll_load_path * * Compute the load path to use for a given dll. * Returned pointer must be freed by caller. */ -WCHAR *MODULE_get_dll_load_path( LPCWSTR module ) +static WCHAR *get_dll_load_path( DWORD flags, LPCWSTR module ) { static const WCHAR pathW[] = {'P','A','T','H',0}; const WCHAR *system_path = get_dll_system_path(); const WCHAR *mod_end = NULL; UNICODE_STRING name, value; + struct dir_entry *entry; WCHAR *p, *ret; int len = 0, path_len = 0; @@ -813,6 +822,13 @@ WCHAR *MODULE_get_dll_load_path( LPCWSTR module ) RtlEnterCriticalSection( &dlldir_section ); if (dll_directory) len += strlenW(dll_directory) + 1; + if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS) + { + LIST_FOR_EACH_ENTRY(entry, &dll_directories, struct dir_entry, entry) + { + len += entry->len + 1; + } + } if ((p = ret = HeapAlloc( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) ))) { if (module) @@ -821,6 +837,15 @@ WCHAR *MODULE_get_dll_load_path( LPCWSTR module ) p += (mod_end - module); *p++ = ';'; } + if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS) + { + LIST_FOR_EACH_ENTRY(entry, &dll_directories, struct dir_entry, entry) + { + memcpy( p, entry->name, entry->len * sizeof(WCHAR) ); + p += entry->len; + *p++ = ';'; + } + } if (dll_directory) { strcpyW( p, dll_directory ); @@ -856,6 +881,14 @@ WCHAR *MODULE_get_dll_load_path( LPCWSTR module ) return ret; } +/****************************************************************** + * MODULE_get_dll_load_path + */ +WCHAR *MODULE_get_dll_load_path( LPCWSTR module ) +{ + return get_dll_load_path( 0, module ); +} + /****************************************************************** * load_library_as_datafile @@ -915,14 +948,13 @@ static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags ) LOAD_LIBRARY_REQUIRE_SIGNED_TARGET | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_APPLICATION_DIR | - LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; if( flags & unsupported_flags) FIXME("unsupported flag(s) used (flags: 0x%08x)\n", flags); - load_path = MODULE_get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL ); + load_path = get_dll_load_path( flags, flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL ); if (flags & LOAD_LIBRARY_AS_DATAFILE) { @@ -1452,8 +1484,29 @@ BOOL WINAPI SetDefaultDllDirectories(DWORD flags) */ DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(PCWSTR dir) { - FIXME("(%s) stub\n", debugstr_w(dir)); - return NULL; + struct dir_entry *entry; + DWORD len, attr; + + TRACE("(%s)\n", debugstr_w(dir)); + + attr = GetFileAttributesW(dir); + if (attr == INVALID_FILE_ATTRIBUTES) return NULL; + + len = strlenW(dir); + if (!(entry = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(struct dir_entry, name[len])))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return NULL; + } + + entry->len = len; + memcpy(entry->name, dir, len * sizeof(WCHAR)); + + RtlEnterCriticalSection( &dlldir_section ); + list_add_tail(&dll_directories, &entry->entry); + RtlLeaveCriticalSection( &dlldir_section ); + + return (DLL_DIRECTORY_COOKIE)entry; } /*********************************************************************** @@ -1461,6 +1514,16 @@ DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory(PCWSTR dir) */ BOOL WINAPI RemoveDllDirectory(DLL_DIRECTORY_COOKIE cookie) { - FIXME("(%p) stub\n", cookie); - return FALSE; + struct dir_entry *entry; + + TRACE("(%p)\n", cookie); + + entry = (struct dir_entry *)cookie; + RtlEnterCriticalSection( &dlldir_section ); + list_remove(&entry->entry); + RtlLeaveCriticalSection( &dlldir_section ); + + HeapFree( GetProcessHeap(), 0, entry ); + + return TRUE; } diff --git a/dlls/kernel32/tests/module.c b/dlls/kernel32/tests/module.c index 277c276..10a38f1 100644 --- a/dlls/kernel32/tests/module.c +++ b/dlls/kernel32/tests/module.c @@ -25,6 +25,7 @@ #include #include +typedef void *DLL_DIRECTORY_COOKIE; static DWORD (WINAPI *pGetDllDirectoryA)(DWORD,LPSTR); static DWORD (WINAPI *pGetDllDirectoryW)(DWORD,LPWSTR); static BOOL (WINAPI *pSetDllDirectoryA)(LPCSTR); @@ -32,6 +33,9 @@ static BOOL (WINAPI *pGetModuleHandleExA)(DWORD,LPCSTR,HMODULE*); static BOOL (WINAPI *pGetModuleHandleExW)(DWORD,LPCWSTR,HMODULE*); static BOOL (WINAPI *pK32GetModuleInformation)(HANDLE process, HMODULE module, MODULEINFO *modinfo, DWORD cb); +static BOOL (WINAPI *pSetDefaultDllDirectories)(DWORD); +static DLL_DIRECTORY_COOKIE (WINAPI *pAddDllDirectory)(PCWSTR); +static BOOL (WINAPI *pRemoveDllDirectory)(DLL_DIRECTORY_COOKIE); static BOOL is_unicode_enabled = TRUE; @@ -408,6 +412,15 @@ static void testLoadLibraryEx(void) hmodule = LoadLibraryExA(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); ok(hmodule != NULL, "got %p\n", hmodule); FreeLibrary(hmodule); + + /* test mixing LOAD_WITH_ALTERED_SEARCH_PATH with other search flags */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH|LOAD_LIBRARY_SEARCH_USER_DIRS); + ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Vista & 7 */ + "wrong error %u\n", GetLastError()); + ok((hmodule != NULL) || broken(hmodule == NULL), /* Vista & 7 */ + "got %p\n", hmodule); + FreeLibrary(hmodule); } static void testGetDllDirectory(void) @@ -521,6 +534,9 @@ static void init_pointers(void) MAKEFUNC(GetModuleHandleExA); MAKEFUNC(GetModuleHandleExW); MAKEFUNC(K32GetModuleInformation); + MAKEFUNC(SetDefaultDllDirectories); + MAKEFUNC(AddDllDirectory); + MAKEFUNC(RemoveDllDirectory); #undef MAKEFUNC /* not all Windows versions export this in kernel32 */ @@ -1088,6 +1104,16 @@ static void test_load_expect(const char *dll, DWORD flags, const char *expect_ma FreeLibrary(hmod); } +/* convert a dll name A->W without depending on the current codepage */ +static WCHAR *AtoW( WCHAR *nameW, const char *nameA, unsigned int len ) +{ + unsigned int i; + + for (i = 0; i < len; i++) nameW[i] = nameA[i]; + nameW[i] = 0; + return nameW; +} + static void testLoadOrder(void) { int i; @@ -1096,12 +1122,17 @@ static void testLoadOrder(void) char *oldenv; char *newenv; char path[MAX_PATH]; + WCHAR pathW[MAX_PATH]; char olddir[MAX_PATH]; char dirs[5][MAX_PATH]; char deps[5][MAX_PATH]; char mains[5][MAX_PATH]; + DLL_DIRECTORY_COOKIE cookie; + DLL_DIRECTORY_COOKIE cookie2; const char *depdll = "dep.dll"; const char *maindll = "main.dll"; + static const WCHAR bogusW[] = {'b','o','g','u','s',0}; + static const WCHAR emptyW[] = {'e','m','p','t','y',0}; /* prevent displaying of the "Unable to load this DLL" message box */ SetErrorMode(SEM_FAILCRITICALERRORS); @@ -1156,6 +1187,46 @@ static void testLoadOrder(void) test_load_expect(mains[0], 0, mains[0], deps[2]); test_load_expect(mains[0], LOAD_WITH_ALTERED_SEARCH_PATH, mains[0], deps[0]); + if (!pAddDllDirectory) + { + win_skip("AddDllDirectory not available\n"); + goto cleanup; + } + + if (0) /* crash on Windows */ + { + cookie = pAddDllDirectory(NULL); + pRemoveDllDirectory(NULL); + pRemoveDllDirectory((DLL_DIRECTORY_COOKIE)0xdeadbeef); + } + + test_load_expect(maindll, LOAD_LIBRARY_SEARCH_USER_DIRS, mains[2], deps[2]); + test_load_expect(mains[0], LOAD_LIBRARY_SEARCH_USER_DIRS, mains[0], deps[2]); + + cookie = pAddDllDirectory(emptyW); + ok(!cookie, "expected NULL, got %p\n", cookie); + + cookie = pAddDllDirectory(bogusW); + ok(!cookie, "expected NULL, got %p\n", cookie); + + AtoW(pathW, dirs[3], strlen(dirs[3])); + cookie = pAddDllDirectory(pathW); + ok(!!cookie, "failed to get cookie for %s\n", wine_dbgstr_w(pathW)); + test_load_expect(maindll, 0, mains[2], deps[2]); + test_load_expect(mains[0], 0, mains[0], deps[2]); + test_load_expect(mains[0], LOAD_WITH_ALTERED_SEARCH_PATH, mains[0], deps[0]); + + test_load_expect(maindll, LOAD_LIBRARY_SEARCH_USER_DIRS, mains[3], deps[3]); + test_load_expect(mains[0], LOAD_LIBRARY_SEARCH_USER_DIRS, mains[0], deps[3]); + pRemoveDllDirectory(cookie); + + cookie = pAddDllDirectory(pathW); + cookie2 = pAddDllDirectory(pathW); + ok(cookie != cookie2, "expected different cookies for duplicate paths, got %p\n", cookie); + pRemoveDllDirectory(cookie); + if (cookie != cookie2) + pRemoveDllDirectory(cookie2); + cleanup: SetCurrentDirectoryA(olddir); SetDllDirectoryA(NULL); -- 1.9.5