| #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; |
| } |