summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2015-11-20 13:34:15 +0200
committerEli Zaretskii <eliz@gnu.org>2015-11-20 13:34:15 +0200
commit24be1c8460895ccec8a84e53966b324e35cac6c9 (patch)
treea9c2112a0013bc30c8385c2a96caf0519a7a81c3
parentbd715e3d3d214f61172beb78f858ac43d8ce0a78 (diff)
downloademacs-24be1c8460895ccec8a84e53966b324e35cac6c9.tar.gz
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. <dynlib_last_err>: 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.
-rw-r--r--src/dynlib.c104
-rw-r--r--src/w32.c5
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 <http://www.gnu.org/licenses/>. */
#include "dynlib.h"
-#if defined _WIN32
+#ifdef WINDOWSNT
/* MS-Windows systems. */
-#include <windows.h>
+#include <errno.h>
+#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 */