From 9ac715f53c44609e82d177482c2cf2c6fdede21d Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Thu, 1 Dec 2022 23:03:04 -0500 Subject: [PATCH 1/4] Add LOAD_LIBRARY_SEARCH_USER_DIRS for DLL loading --- src/dlload.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/dlload.c b/src/dlload.c index dd5d75da31a34..08444f51b3370 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -161,6 +161,21 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI WCHAR *wfilename = (WCHAR*)alloca(len * sizeof(WCHAR)); if (!MultiByteToWideChar(CP_UTF8, 0, filename, -1, wfilename, len)) return NULL; HANDLE lib = LoadLibraryExW(wfilename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!lib) + { + /* If loading with LOAD_WITH_ALTERED_SEARCH_PATH fails, + search user directories added with `AddDllDirectory`. + + In Julia on Windows, user directories can be added to the DLL search path as follows. + `library::String = pwd()` + `@ccall "kernel32".AddDllDirectory(library::Cwstring)::Ptr{Nothing}` + + https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory + + Consider `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS` or + `LOAD_LIBRARY_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR` for use below. */ + lib = LoadLibraryExW(wfilename, NULL, LOAD_LIBRARY_SEARCH_USER_DIRS); + } if (lib) needsSymRefreshModuleList = 1; return lib; From ce74cc4bc7868e10a2047122ab262843d3717f2e Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Thu, 1 Dec 2022 23:28:51 -0500 Subject: [PATCH 2/4] Eliminate whitespace in comment --- src/dlload.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/dlload.c b/src/dlload.c index 08444f51b3370..23cf891b8c4cc 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -165,13 +165,10 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI { /* If loading with LOAD_WITH_ALTERED_SEARCH_PATH fails, search user directories added with `AddDllDirectory`. - In Julia on Windows, user directories can be added to the DLL search path as follows. `library::String = pwd()` `@ccall "kernel32".AddDllDirectory(library::Cwstring)::Ptr{Nothing}` - https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory - Consider `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS` or `LOAD_LIBRARY_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR` for use below. */ lib = LoadLibraryExW(wfilename, NULL, LOAD_LIBRARY_SEARCH_USER_DIRS); From eace14834f528ed24306301baf76ea5edfb934b1 Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Mon, 12 Dec 2022 19:40:52 -0500 Subject: [PATCH 3/4] Update src/dlload.c via vtjnash review Co-authored-by: Jameson Nash --- src/dlload.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/dlload.c b/src/dlload.c index 23cf891b8c4cc..d61998376c93e 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -160,18 +160,19 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI if (!len) return NULL; WCHAR *wfilename = (WCHAR*)alloca(len * sizeof(WCHAR)); if (!MultiByteToWideChar(CP_UTF8, 0, filename, -1, wfilename, len)) return NULL; - HANDLE lib = LoadLibraryExW(wfilename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (!lib) - { - /* If loading with LOAD_WITH_ALTERED_SEARCH_PATH fails, - search user directories added with `AddDllDirectory`. - In Julia on Windows, user directories can be added to the DLL search path as follows. - `library::String = pwd()` - `@ccall "kernel32".AddDllDirectory(library::Cwstring)::Ptr{Nothing}` - https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory - Consider `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS` or - `LOAD_LIBRARY_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR` for use below. */ - lib = LoadLibraryExW(wfilename, NULL, LOAD_LIBRARY_SEARCH_USER_DIRS); + /* Treat `AddDllDirectory` like `(DY)LD_LIBRARY_PATH` on other platforms. + In Julia on Windows, user directories can be added to the DLL search path as follows. + `library::String = pwd()` + `@ccall "kernel32".AddDllDirectory(library::Cwstring)::Ptr{Nothing}` + https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory + Consider `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS` or + `LOAD_LIBRARY_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR` for use below. */ + lib = LoadLibraryExW(wfilename, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS); // this is LOAD_LIBRARY_SEARCH_DEFAULT_DIRS with ALTERED_SEARCH_PATH + if (!lib) { + lib = LoadLibraryExW(".\\" wfilename, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS); + if (!lib) { + lib = LoadLibraryExW(wfilename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + } } if (lib) needsSymRefreshModuleList = 1; From ec5bc96674ac2899c60eaf998a29ced6225f701a Mon Sep 17 00:00:00 2001 From: Mark Kittisopikul Date: Wed, 4 Jan 2023 20:20:49 -0500 Subject: [PATCH 4/4] Make code compile --- src/dlload.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/dlload.c b/src/dlload.c index d61998376c93e..9761477f22eb2 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -13,6 +13,8 @@ #include "julia_internal.h" #ifdef _OS_WINDOWS_ #include +#define STRSAFE_NO_DEPRECATE +#include #else #include #include @@ -160,17 +162,26 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI if (!len) return NULL; WCHAR *wfilename = (WCHAR*)alloca(len * sizeof(WCHAR)); if (!MultiByteToWideChar(CP_UTF8, 0, filename, -1, wfilename, len)) return NULL; - /* Treat `AddDllDirectory` like `(DY)LD_LIBRARY_PATH` on other platforms. - In Julia on Windows, user directories can be added to the DLL search path as follows. - `library::String = pwd()` - `@ccall "kernel32".AddDllDirectory(library::Cwstring)::Ptr{Nothing}` - https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory - Consider `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS` or - `LOAD_LIBRARY_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR` for use below. */ - lib = LoadLibraryExW(wfilename, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS); // this is LOAD_LIBRARY_SEARCH_DEFAULT_DIRS with ALTERED_SEARCH_PATH + /* Treat `AddDllDirectory` like `(DY)LD_LIBRARY_PATH` on other platforms as Julia 1.10. + In Julia on Windows, user directories can be added to the DLL search path as follows. + `library::String = pwd()` + `@ccall "kernel32".AddDllDirectory(library::Cwstring)::Ptr{Nothing}` + https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-adddlldirectory + dwFlags below is LOAD_LIBRARY_SEARCH_DEFAULT_DIRS with ALTERED_SEARCH_PATH + and without LOAD_LIBRARY_SEARCH_APPLICATION_DIR. + */ + const DWORD dwFlags = LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS; + /* First, try searching for the file name without local prefix directory prefix.*/ + HANDLE lib = LoadLibraryExW(wfilename, NULL, dwFlags); if (!lib) { - lib = LoadLibraryExW(".\\" wfilename, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS); + /* Second, try searching for the file name with local prefix directory prefix.*/ + size_t prepended_len = len+3; + WCHAR *prepended_wfilename = (WCHAR*) alloca(prepended_len * sizeof(WCHAR)); + HRESULT status = StringCchPrintfW(prepended_wfilename, prepended_len, L"%s%s", L".\\", wfilename); + if (status != S_OK) return NULL; + lib = LoadLibraryExW(prepended_wfilename, NULL, dwFlags); if (!lib) { + /* Third, try the old loading mechanism used before Julia 1.10. */ lib = LoadLibraryExW(wfilename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); } }