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.
This commit is contained in:
Eli Zaretskii 2015-11-20 13:34:15 +02:00
parent bd715e3d3d
commit 24be1c8460
2 changed files with 100 additions and 9 deletions

View 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

View file

@ -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 */