From e59ec8f8b319874f6d063bee10ae87ae43016224 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Wed, 21 Feb 2024 20:41:15 +0100 Subject: [PATCH] Win32: pass the flags from dlopen() to LoadLibraryEx() (#65) * Win32: pass the flags from dlopen() to LoadLibraryEx() Includes a default handling if flags==0, similar to the one in ctypes. * Fix a compiler warning * Document the new behavior of ffi.dlopen() --- doc/source/cdef.rst | 8 ++++++++ src/c/_cffi_backend.c | 2 +- src/c/misc_win32.h | 24 ++++++++++++++++++++---- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst index 13573ce2..d5d5b34d 100644 --- a/doc/source/cdef.rst +++ b/doc/source/cdef.rst @@ -381,6 +381,14 @@ Useful if you have special needs (e.g. you need the GNU extension automatically if the FFI object is garbage-collected (but you can still call ``ffi.dlclose()`` explicitly if needed). +*New in version 1.17:* on Windows, ``ffi.dlopen(filename, flags=0)`` now +passes the flags to ``LoadLibraryEx()``. Moreover, if you use the +default value of 0 but ``filename`` contains a slash or backslash +character, it will instead use +``LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR``. +This ensures that dependent DLLs from the same path are also found. +It is what ctypes does too. + .. _set_source: diff --git a/src/c/_cffi_backend.c b/src/c/_cffi_backend.c index a21bba4a..602117e3 100644 --- a/src/c/_cffi_backend.c +++ b/src/c/_cffi_backend.c @@ -4570,7 +4570,7 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename, if (sz1 < 0) return NULL; w1[sz1] = 0; - handle = dlopenW(w1); + handle = dlopenWinW(w1, flags); goto got_handle; } PyErr_Clear(); diff --git a/src/c/misc_win32.h b/src/c/misc_win32.h index 156cf5d9..f332940c 100644 --- a/src/c/misc_win32.h +++ b/src/c/misc_win32.h @@ -191,14 +191,30 @@ static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) #define RTLD_GLOBAL 0 #define RTLD_LOCAL 0 -static void *dlopen(const char *filename, int flag) +static void *dlopen(const char *filename, int flags) { - return (void *)LoadLibraryA(filename); + if (flags == 0) { + for (const char *p = filename; *p != 0; p++) + if (*p == '\\' || *p == '/') { + flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR; + break; + } + } + return (void *)LoadLibraryExA(filename, NULL, flags); } -static void *dlopenW(const wchar_t *filename) +static void *dlopenWinW(const wchar_t *filename, int flags) { - return (void *)LoadLibraryW(filename); + if (flags == 0) { + for (const wchar_t *p = filename; *p != 0; p++) + if (*p == '\\' || *p == '/') { + flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR; + break; + } + } + return (void *)LoadLibraryExW(filename, NULL, flags); } static void *dlsym(void *handle, const char *symbol)