blob: 07b76c131e651d89cd921469a7da5ab40551a2ff [file] [log] [blame]
#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;
}