]> code.delx.au - gnu-emacs/commitdiff
Improve MS-Windows implementation in dynlib.c
authorEli Zaretskii <eliz@gnu.org>
Fri, 20 Nov 2015 11:34:15 +0000 (13:34 +0200)
committerEli Zaretskii <eliz@gnu.org>
Fri, 20 Nov 2015 11:34:15 +0000 (13:34 +0200)
* 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.

src/dynlib.c
src/w32.c

index 1b66c4ad8e84062c0429581b7b3a0373b350dcb1..47ffb4181403c08d3159dcfe4553a8cc3b391911 100644 (file)
@@ -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
index 15cfd92a29a555f4c82dc2e392c6aac39b580b84..9601012acd6a1564885454521ba8c8fa48fdfd3b 100644 (file)
--- 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  */