aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys/win32/erl_win32_sys_ddll.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/sys/win32/erl_win32_sys_ddll.c')
-rw-r--r--erts/emulator/sys/win32/erl_win32_sys_ddll.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
new file mode 100644
index 0000000000..a19f49af10
--- /dev/null
+++ b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
@@ -0,0 +1,206 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Interface functions to the dynamic linker using dl* functions.
+ * (As far as I know it works on SunOS 4, 5, Linux and FreeBSD. /Seb)
+ */
+
+#include <windows.h>
+
+#define GET_ERTS_ALC_TEST
+#include "sys.h"
+#include "global.h"
+#include "erl_alloc.h"
+
+#include "erl_driver.h"
+#include "erl_win_dyn_driver.h"
+
+#include "erl_nif.h"
+
+#define EXT_LEN 4
+#define FILE_EXT ".dll"
+
+static DWORD tls_index = 0;
+static TWinDynDriverCallbacks wddc;
+static TWinDynNifCallbacks nif_callbacks;
+
+void erl_sys_ddll_init(void) {
+ tls_index = TlsAlloc();
+ ERL_INIT_CALLBACK_STRUCTURE(wddc);
+
+#define ERL_NIF_API_FUNC_DECL(RET,NAME,ARGS) nif_callbacks.NAME = NAME
+#include "erl_nif_api_funcs.h"
+#undef ERL_NIF_API_FUNC_DECL
+
+ return;
+}
+
+/*
+ * Open a shared object
+ */
+int erts_sys_ddll_open2(char *full_name, void **handle, ErtsSysDdllError* err)
+{
+ int len;
+ char dlname[MAXPATHLEN + 1];
+
+ if ((len = sys_strlen(full_name)) >= MAXPATHLEN - EXT_LEN) {
+ if (err != NULL) {
+ err->str = "Library name too long";
+ }
+ return ERL_DE_LOAD_ERROR_NAME_TO_LONG;
+ }
+ sys_strcpy(dlname, full_name);
+ sys_strcpy(dlname+len, FILE_EXT);
+ return erts_sys_ddll_open_noext(dlname, handle, err);
+}
+int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err)
+{
+ HINSTANCE hinstance;
+
+ if ((hinstance = LoadLibrary(dlname)) == NULL) {
+ int code = ERL_DE_DYNAMIC_ERROR_OFFSET - GetLastError();
+ if (err != NULL) {
+ err->str = erts_sys_ddll_error(code);
+ }
+ return code;
+ } else {
+ *handle = (void *) hinstance;
+ return ERL_DE_NO_ERROR;
+ }
+}
+
+/*
+ * Find a symbol in the shared object
+ */
+int erts_sys_ddll_sym2(void *handle, char *func_name, void **function,
+ ErtsSysDdllError* err)
+{
+ FARPROC proc;
+ if ((proc = GetProcAddress( (HINSTANCE) handle, func_name)) == NULL) {
+ int code = ERL_DE_DYNAMIC_ERROR_OFFSET - GetLastError();
+ if (err != NULL) {
+ err->str = erts_sys_ddll_error(code);
+ }
+ return code;
+ }
+ *function = (void *) proc;
+ return ERL_DE_NO_ERROR;
+}
+
+/* XXX:PaN These two will be changed with new driver interface! */
+
+/*
+ * Load the driver init function, might appear under different names depending on object arch...
+ */
+
+int erts_sys_ddll_load_driver_init(void *handle, void **function)
+{
+ void *fn;
+ int res;
+ if ((res = erts_sys_ddll_sym(handle, "driver_init", &fn)) != ERL_DE_NO_ERROR) {
+ return res;
+ }
+ *function = fn;
+ return res;
+}
+
+int erts_sys_ddll_load_nif_init(void *handle, void **function, ErtsSysDdllError* err)
+{
+ void *fn;
+ int res;
+ if ((res = erts_sys_ddll_sym2(handle, "nif_init", &fn, err)) != ERL_DE_NO_ERROR) {
+ return res;
+ }
+ *function = fn;
+ return res;
+}
+
+
+/*
+ * Call the driver_init function, whatever it's really called, simple on unix...
+*/
+void *erts_sys_ddll_call_init(void *function) {
+ void *(*initfn)(TWinDynDriverCallbacks *) = function;
+ return (*initfn)(&wddc);
+}
+
+void *erts_sys_ddll_call_nif_init(void *function) {
+ void *(*initfn)(TWinDynNifCallbacks *) = function;
+ return (*initfn)(&nif_callbacks);
+}
+
+
+/*
+ * Close a chared object
+ */
+int erts_sys_ddll_close2(void *handle, ErtsSysDdllError* err)
+{
+ if (!FreeLibrary((HINSTANCE) handle)) {
+ int code = ERL_DE_DYNAMIC_ERROR_OFFSET - GetLastError();
+ if (err != NULL) {
+ err->str = erts_sys_ddll_error(code);
+ }
+ return code;
+ }
+ return ERL_DE_NO_ERROR;
+}
+
+/*
+ * Return string that describes the (current) error
+ */
+#define MAX_ERROR 255
+char *erts_sys_ddll_error(int code)
+{
+ int actual_code;
+ char *local_ptr;
+ if (code > ERL_DE_DYNAMIC_ERROR_OFFSET) {
+ return "Unspecified error";
+ }
+ actual_code = -1*(code - ERL_DE_DYNAMIC_ERROR_OFFSET);
+
+ local_ptr = TlsGetValue(tls_index);
+ if (local_ptr == NULL) {
+ local_ptr = erts_alloc(ERTS_ALC_T_DDLL_ERRCODES, MAX_ERROR);
+ TlsSetValue(tls_index,local_ptr);
+ }
+ if (!FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ (DWORD) actual_code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ local_ptr,
+ MAX_ERROR, NULL )) {
+ return "Unspecified error";
+ } else {
+ char *ptr = local_ptr + strlen(local_ptr) - 1;
+ while (ptr >= local_ptr && (*ptr == '\r' || *ptr == '\n')) {
+ *ptr-- = '\0';
+ }
+ }
+ return local_ptr;
+}
+
+void erts_sys_ddll_free_error(ErtsSysDdllError* err)
+{
+ /* err->str may be either a static string or reused as thread local data,
+ * so wo don't bother free it.
+ */
+}
+