1 #include <malloc.h> /* for alloca() */
2
3
4 /************************************************************/
5 /* errno and GetLastError support */
6
7 #include "misc_thread_common.h"
8
9 static DWORD cffi_tls_index = TLS_OUT_OF_INDEXES;
10
DllMain(HINSTANCE hinstDLL,DWORD reason_for_call,LPVOID reserved)11 BOOL WINAPI DllMain(HINSTANCE hinstDLL,
12 DWORD reason_for_call,
13 LPVOID reserved)
14 {
15 LPVOID p;
16
17 switch (reason_for_call) {
18
19 case DLL_THREAD_DETACH:
20 if (cffi_tls_index != TLS_OUT_OF_INDEXES) {
21 p = TlsGetValue(cffi_tls_index);
22 if (p != NULL) {
23 TlsSetValue(cffi_tls_index, NULL);
24 cffi_thread_shutdown(p);
25 }
26 }
27 break;
28
29 default:
30 break;
31 }
32 return TRUE;
33 }
34
init_cffi_tls(void)35 static void init_cffi_tls(void)
36 {
37 if (cffi_tls_index == TLS_OUT_OF_INDEXES) {
38 cffi_tls_index = TlsAlloc();
39 if (cffi_tls_index == TLS_OUT_OF_INDEXES)
40 PyErr_SetString(PyExc_WindowsError, "TlsAlloc() failed");
41 }
42 }
43
get_cffi_tls(void)44 static struct cffi_tls_s *get_cffi_tls(void)
45 {
46 LPVOID p = TlsGetValue(cffi_tls_index);
47
48 if (p == NULL) {
49 p = malloc(sizeof(struct cffi_tls_s));
50 if (p == NULL)
51 return NULL;
52 memset(p, 0, sizeof(struct cffi_tls_s));
53 TlsSetValue(cffi_tls_index, p);
54 }
55 return (struct cffi_tls_s *)p;
56 }
57
58 #ifdef USE__THREAD
59 # error "unexpected USE__THREAD on Windows"
60 #endif
61
save_errno(void)62 static void save_errno(void)
63 {
64 int current_err = errno;
65 int current_lasterr = GetLastError();
66 struct cffi_tls_s *p = get_cffi_tls();
67 if (p != NULL) {
68 p->saved_errno = current_err;
69 p->saved_lasterror = current_lasterr;
70 }
71 /* else: cannot report the error */
72 }
73
restore_errno(void)74 static void restore_errno(void)
75 {
76 struct cffi_tls_s *p = get_cffi_tls();
77 if (p != NULL) {
78 SetLastError(p->saved_lasterror);
79 errno = p->saved_errno;
80 }
81 /* else: cannot report the error */
82 }
83
84 /************************************************************/
85
86
87 #if PY_MAJOR_VERSION >= 3
b_getwinerror(PyObject * self,PyObject * args,PyObject * kwds)88 static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
89 {
90 int err = -1;
91 int len;
92 WCHAR *s_buf = NULL; /* Free via LocalFree */
93 PyObject *v, *message;
94 static char *keywords[] = {"code", NULL};
95
96 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err))
97 return NULL;
98
99 if (err == -1) {
100 struct cffi_tls_s *p = get_cffi_tls();
101 if (p == NULL)
102 return PyErr_NoMemory();
103 err = p->saved_lasterror;
104 }
105
106 len = FormatMessageW(
107 /* Error API error */
108 FORMAT_MESSAGE_ALLOCATE_BUFFER |
109 FORMAT_MESSAGE_FROM_SYSTEM |
110 FORMAT_MESSAGE_IGNORE_INSERTS,
111 NULL, /* no message source */
112 err,
113 MAKELANGID(LANG_NEUTRAL,
114 SUBLANG_DEFAULT), /* Default language */
115 (LPWSTR) &s_buf,
116 0, /* size not used */
117 NULL); /* no args */
118 if (len==0) {
119 /* Only seen this in out of mem situations */
120 message = PyUnicode_FromFormat("Windows Error 0x%X", err);
121 } else {
122 /* remove trailing cr/lf and dots */
123 while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.'))
124 s_buf[--len] = L'\0';
125 message = PyUnicode_FromWideChar(s_buf, len);
126 }
127 if (message != NULL) {
128 v = Py_BuildValue("(iO)", err, message);
129 Py_DECREF(message);
130 }
131 else
132 v = NULL;
133 LocalFree(s_buf);
134 return v;
135 }
136 #else
b_getwinerror(PyObject * self,PyObject * args,PyObject * kwds)137 static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
138 {
139 int err = -1;
140 int len;
141 char *s;
142 char *s_buf = NULL; /* Free via LocalFree */
143 char s_small_buf[40]; /* Room for "Windows Error 0xFFFFFFFFFFFFFFFF" */
144 PyObject *v;
145 static char *keywords[] = {"code", NULL};
146
147 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err))
148 return NULL;
149
150 if (err == -1) {
151 struct cffi_tls_s *p = get_cffi_tls();
152 if (p == NULL)
153 return PyErr_NoMemory();
154 err = p->saved_lasterror;
155 }
156
157 len = FormatMessage(
158 /* Error API error */
159 FORMAT_MESSAGE_ALLOCATE_BUFFER |
160 FORMAT_MESSAGE_FROM_SYSTEM |
161 FORMAT_MESSAGE_IGNORE_INSERTS,
162 NULL, /* no message source */
163 err,
164 MAKELANGID(LANG_NEUTRAL,
165 SUBLANG_DEFAULT), /* Default language */
166 (LPTSTR) &s_buf,
167 0, /* size not used */
168 NULL); /* no args */
169 if (len==0) {
170 /* Only seen this in out of mem situations */
171 sprintf(s_small_buf, "Windows Error 0x%X", err);
172 s = s_small_buf;
173 } else {
174 s = s_buf;
175 /* remove trailing cr/lf and dots */
176 while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.'))
177 s[--len] = '\0';
178 }
179 v = Py_BuildValue("(is)", err, s);
180 LocalFree(s_buf);
181 return v;
182 }
183 #endif
184
185
186 /************************************************************/
187 /* Emulate dlopen()&co. from the Windows API */
188
189 #define RTLD_LAZY 0
190 #define RTLD_NOW 0
191 #define RTLD_GLOBAL 0
192 #define RTLD_LOCAL 0
193
dlopen(const char * filename,int flag)194 static void *dlopen(const char *filename, int flag)
195 {
196 return (void *)LoadLibraryA(filename);
197 }
198
dlopenW(const wchar_t * filename)199 static void *dlopenW(const wchar_t *filename)
200 {
201 return (void *)LoadLibraryW(filename);
202 }
203
dlsym(void * handle,const char * symbol)204 static void *dlsym(void *handle, const char *symbol)
205 {
206 void *address = GetProcAddress((HMODULE)handle, symbol);
207 #ifndef MS_WIN64
208 if (!address) {
209 /* If 'symbol' is not found, then try '_symbol@N' for N in
210 (0, 4, 8, 12, ..., 124). Unlike ctypes, we try to do that
211 for any symbol, although in theory it should only be done
212 for __stdcall functions.
213 */
214 int i;
215 char *mangled_name = alloca(1 + strlen(symbol) + 1 + 3 + 1);
216 if (!mangled_name)
217 return NULL;
218 for (i = 0; i < 32; i++) {
219 sprintf(mangled_name, "_%s@%d", symbol, i * 4);
220 address = GetProcAddress((HMODULE)handle, mangled_name);
221 if (address)
222 break;
223 }
224 }
225 #endif
226 return address;
227 }
228
dlclose(void * handle)229 static int dlclose(void *handle)
230 {
231 return FreeLibrary((HMODULE)handle) ? 0 : -1;
232 }
233
dlerror(void)234 static const char *dlerror(void)
235 {
236 static char buf[32];
237 DWORD dw = GetLastError();
238 if (dw == 0)
239 return NULL;
240 sprintf(buf, "error 0x%x", (unsigned int)dw);
241 return buf;
242 }
243