From 24be1c8460895ccec8a84e53966b324e35cac6c9 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 20 Nov 2015 13:34:15 +0200 Subject: [PATCH] Improve MS-Windows implementation in dynlib.c * src/dynlib.c [WINDOWSNT]: Include errno.h, lisp.h, and w32.h. No need to include windows.h, as w32.h already does that. : New static variable. (dynlib_reset_last_error): New function. (dynlib_open): Convert forward slashes to backslashes. Convert file names from UTF-8 to either UTF-16 or the current ANSI codepage, and call either LoadLibraryW or LoadLibraryA. If the argument is NULL, return a handle to the main module, like 'dlopen' does. Record the error, if any, for use by dynlib_error. (dynlib_sym): Check the handle for validity. Record the error, if any, for use by dynlib_error. (dynlib_error): Call w32_strerror to produce the error string, and zero out the last error code, like dlerror does. (dynlib_close): Check the handle for validity. Record the error, if any, for use by dynlib_error. Don't call FreeLibrary with a handle for the main module. * src/w32.c (globals_of_w32): Call dynlib_reset_last_error. --- src/dynlib.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++----- src/w32.c | 5 +++ 2 files changed, 100 insertions(+), 9 deletions(-) diff --git a/src/dynlib.c b/src/dynlib.c index 1b66c4ad8e8..47ffb418140 100644 --- a/src/dynlib.c +++ b/src/dynlib.c @@ -28,42 +28,128 @@ along with GNU Emacs. If not, see . */ #include "dynlib.h" -#if defined _WIN32 +#ifdef WINDOWSNT /* MS-Windows systems. */ -#include +#include +#include "lisp.h" +#include "w32.h" + +static DWORD dynlib_last_err; + +/* This needs to be called at startup to countermand any non-zero + values recorded by temacs. */ +void +dynlib_reset_last_error (void) +{ + dynlib_last_err = 0; +} dynlib_handle_ptr -dynlib_open (const char *path) +dynlib_open (const char *dll_fname) { + HMODULE hdll; + char dll_fname_local[MAX_UTF8_PATH]; - return (dynlib_handle_ptr) LoadLibrary (path); + if (!dll_fname) + { + errno = ENOTSUP; + return NULL; + } + + if (!dll_fname) + hdll = GetModuleHandle (NULL); + else + { + /* LoadLibrary wants backslashes. */ + strcpy (dll_fname_local, dll_fname); + unixtodos_filename (dll_fname_local); + + if (w32_unicode_filenames) + { + wchar_t dll_fname_w[MAX_PATH]; + + filename_to_utf16 (dll_fname_local, dll_fname_w); + hdll = LoadLibraryW (dll_fname_w); + } + else + { + char dll_fname_a[MAX_PATH]; + + filename_to_ansi (dll_fname_local, dll_fname_a); + hdll = LoadLibraryA (dll_fname_a); + } + } + + if (!hdll) + dynlib_last_err = GetLastError (); + + return (dynlib_handle_ptr) hdll; } void * dynlib_sym (dynlib_handle_ptr h, const char *sym) { - return GetProcAddress ((HMODULE) h, sym); + FARPROC sym_addr = NULL; + + if (!h || h == INVALID_HANDLE_VALUE || !sym) + { + dynlib_last_err = ERROR_INVALID_PARAMETER; + return NULL; + } + + sym_addr = GetProcAddress ((HMODULE) h, sym); + if (!sym_addr) + dynlib_last_err = GetLastError (); + + return (void *)sym_addr; } bool dynlib_addr (void *ptr, const char **path, const char **sym) { - return false; /* not implemented */ + return false; /* Not implemented yet. */ } const char * dynlib_error (void) { - /* TODO: use GetLastError(), FormatMessage(), ... */ - return "Can't load DLL"; + char *error_string = NULL; + + if (dynlib_last_err) + { + error_string = w32_strerror (dynlib_last_err); + dynlib_last_err = 0; + } + + return error_string; } int dynlib_close (dynlib_handle_ptr h) { - return FreeLibrary ((HMODULE) h) != 0; + if (!h || h == INVALID_HANDLE_VALUE) + { + dynlib_last_err = ERROR_INVALID_PARAMETER; + return -1; + } + /* If the handle is for the main module (the .exe file), it + shouldn't be passed to FreeLibrary, because GetModuleHandle + doesn't increment the refcount, but FreeLibrary does decrement + it. I don't think this should matter for the main module, but + just in case, we avoid the call here, relying on another call to + GetModuleHandle to return the same value. */ + if (h == GetModuleHandle (NULL)) + return 0; + + if (!FreeLibrary ((HMODULE) h)) + { + dynlib_last_err = GetLastError (); + return -1; + } + + return 0; } #elif defined HAVE_UNISTD_H diff --git a/src/w32.c b/src/w32.c index 15cfd92a29a..9601012acd6 100644 --- a/src/w32.c +++ b/src/w32.c @@ -9379,6 +9379,11 @@ globals_of_w32 (void) w32_unicode_filenames = 0; else w32_unicode_filenames = 1; + +#ifdef HAVE_MODULES + extern void dynlib_reset_last_error (void); + dynlib_reset_last_error (); +#endif } /* For make-serial-process */ -- 2.39.5