diff options
Diffstat (limited to 'c/misc_win32.h')
-rw-r--r-- | c/misc_win32.h | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/c/misc_win32.h b/c/misc_win32.h new file mode 100644 index 0000000..07b76c1 --- /dev/null +++ b/c/misc_win32.h @@ -0,0 +1,241 @@ +#include <malloc.h> /* for alloca() */ + + +/************************************************************/ +/* errno and GetLastError support */ + +#include "misc_thread_common.h" + +static DWORD cffi_tls_index = TLS_OUT_OF_INDEXES; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, + DWORD reason_for_call, + LPVOID reserved) +{ + LPVOID p; + + switch (reason_for_call) { + + case DLL_THREAD_DETACH: + if (cffi_tls_index != TLS_OUT_OF_INDEXES) { + p = TlsGetValue(cffi_tls_index); + if (p != NULL) { + TlsSetValue(cffi_tls_index, NULL); + cffi_thread_shutdown(p); + } + } + break; + + default: + break; + } + return TRUE; +} + +static void init_cffi_tls(void) +{ + if (cffi_tls_index == TLS_OUT_OF_INDEXES) { + cffi_tls_index = TlsAlloc(); + if (cffi_tls_index == TLS_OUT_OF_INDEXES) + PyErr_SetString(PyExc_WindowsError, "TlsAlloc() failed"); + } +} + +static struct cffi_tls_s *get_cffi_tls(void) +{ + LPVOID p = TlsGetValue(cffi_tls_index); + + if (p == NULL) { + p = malloc(sizeof(struct cffi_tls_s)); + if (p == NULL) + return NULL; + memset(p, 0, sizeof(struct cffi_tls_s)); + TlsSetValue(cffi_tls_index, p); + } + return (struct cffi_tls_s *)p; +} + +#ifdef USE__THREAD +# error "unexpected USE__THREAD on Windows" +#endif + +static void save_errno(void) +{ + int current_err = errno; + int current_lasterr = GetLastError(); + struct cffi_tls_s *p = get_cffi_tls(); + if (p != NULL) { + p->saved_errno = current_err; + p->saved_lasterror = current_lasterr; + } + /* else: cannot report the error */ +} + +static void restore_errno(void) +{ + struct cffi_tls_s *p = get_cffi_tls(); + if (p != NULL) { + SetLastError(p->saved_lasterror); + errno = p->saved_errno; + } + /* else: cannot report the error */ +} + +/************************************************************/ + + +#if PY_MAJOR_VERSION >= 3 +static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) +{ + int err = -1; + int len; + WCHAR *s_buf = NULL; /* Free via LocalFree */ + PyObject *v, *message; + static char *keywords[] = {"code", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) + return NULL; + + if (err == -1) { + struct cffi_tls_s *p = get_cffi_tls(); + if (p == NULL) + return PyErr_NoMemory(); + err = p->saved_lasterror; + } + + len = FormatMessageW( + /* Error API error */ + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, /* no message source */ + err, + MAKELANGID(LANG_NEUTRAL, + SUBLANG_DEFAULT), /* Default language */ + (LPWSTR) &s_buf, + 0, /* size not used */ + NULL); /* no args */ + if (len==0) { + /* Only seen this in out of mem situations */ + message = PyUnicode_FromFormat("Windows Error 0x%X", err); + } else { + /* remove trailing cr/lf and dots */ + while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.')) + s_buf[--len] = L'\0'; + message = PyUnicode_FromWideChar(s_buf, len); + } + if (message != NULL) + v = Py_BuildValue("(iO)", err, message); + else + v = NULL; + LocalFree(s_buf); + return v; +} +#else +static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) +{ + int err = -1; + int len; + char *s; + char *s_buf = NULL; /* Free via LocalFree */ + char s_small_buf[40]; /* Room for "Windows Error 0xFFFFFFFFFFFFFFFF" */ + PyObject *v; + static char *keywords[] = {"code", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) + return NULL; + + if (err == -1) { + struct cffi_tls_s *p = get_cffi_tls(); + if (p == NULL) + return PyErr_NoMemory(); + err = p->saved_lasterror; + } + + len = FormatMessage( + /* Error API error */ + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, /* no message source */ + err, + MAKELANGID(LANG_NEUTRAL, + SUBLANG_DEFAULT), /* Default language */ + (LPTSTR) &s_buf, + 0, /* size not used */ + NULL); /* no args */ + if (len==0) { + /* Only seen this in out of mem situations */ + sprintf(s_small_buf, "Windows Error 0x%X", err); + s = s_small_buf; + s_buf = NULL; + } else { + s = s_buf; + /* remove trailing cr/lf and dots */ + while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.')) + s[--len] = '\0'; + } + v = Py_BuildValue("(is)", err, s); + LocalFree(s_buf); + return v; +} +#endif + + +/************************************************************/ +/* Emulate dlopen()&co. from the Windows API */ + +#define RTLD_LAZY 0 +#define RTLD_NOW 0 +#define RTLD_GLOBAL 0 +#define RTLD_LOCAL 0 + +static void *dlopen(const char *filename, int flag) +{ + return (void *)LoadLibraryA(filename); +} + +static void *dlopenW(const wchar_t *filename) +{ + return (void *)LoadLibraryW(filename); +} + +static void *dlsym(void *handle, const char *symbol) +{ + void *address = GetProcAddress((HMODULE)handle, symbol); +#ifndef MS_WIN64 + if (!address) { + /* If 'symbol' is not found, then try '_symbol@N' for N in + (0, 4, 8, 12, ..., 124). Unlike ctypes, we try to do that + for any symbol, although in theory it should only be done + for __stdcall functions. + */ + int i; + char *mangled_name = alloca(1 + strlen(symbol) + 1 + 3 + 1); + if (!mangled_name) + return NULL; + for (i = 0; i < 32; i++) { + sprintf(mangled_name, "_%s@%d", symbol, i * 4); + address = GetProcAddress((HMODULE)handle, mangled_name); + if (address) + break; + } + } +#endif + return address; +} + +static int dlclose(void *handle) +{ + return FreeLibrary((HMODULE)handle) ? 0 : -1; +} + +static const char *dlerror(void) +{ + static char buf[32]; + DWORD dw = GetLastError(); + if (dw == 0) + return NULL; + sprintf(buf, "error 0x%x", (unsigned int)dw); + return buf; +} |