Spaces:
Runtime error
Runtime error
/* Windows only: logic to take the Python-CFFI embedding logic | |
initialization errors and display them in a background thread | |
with MessageBox. The idea is that if the whole program closes | |
as a result of this problem, then likely it is already a console | |
program and you can read the stderr output in the console too. | |
If it is not a console program, then it will likely show its own | |
dialog to complain, or generally not abruptly close, and for this | |
case the background thread should stay alive. | |
*/ | |
static void *volatile _cffi_bootstrap_text; | |
static PyObject *_cffi_start_error_capture(void) | |
{ | |
PyObject *result = NULL; | |
PyObject *x, *m, *bi; | |
if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, | |
(void *)1, NULL) != NULL) | |
return (PyObject *)1; | |
m = PyImport_AddModule("_cffi_error_capture"); | |
if (m == NULL) | |
goto error; | |
result = PyModule_GetDict(m); | |
if (result == NULL) | |
goto error; | |
bi = PyImport_ImportModule("builtins"); | |
bi = PyImport_ImportModule("__builtin__"); | |
if (bi == NULL) | |
goto error; | |
PyDict_SetItemString(result, "__builtins__", bi); | |
Py_DECREF(bi); | |
x = PyRun_String( | |
"import sys\n" | |
"class FileLike:\n" | |
" def write(self, x):\n" | |
" try:\n" | |
" of.write(x)\n" | |
" except: pass\n" | |
" self.buf += x\n" | |
" def flush(self):\n" | |
" pass\n" | |
"fl = FileLike()\n" | |
"fl.buf = ''\n" | |
"of = sys.stderr\n" | |
"sys.stderr = fl\n" | |
"def done():\n" | |
" sys.stderr = of\n" | |
" return fl.buf\n", /* make sure the returned value stays alive */ | |
Py_file_input, | |
result, result); | |
Py_XDECREF(x); | |
error: | |
if (PyErr_Occurred()) | |
{ | |
PyErr_WriteUnraisable(Py_None); | |
PyErr_Clear(); | |
} | |
return result; | |
} | |
static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) | |
{ | |
Sleep(666); /* may be interrupted if the whole process is closing */ | |
MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, | |
L"Python-CFFI error", | |
MB_OK | MB_ICONERROR); | |
MessageBoxA(NULL, (char *)_cffi_bootstrap_text, | |
"Python-CFFI error", | |
MB_OK | MB_ICONERROR); | |
_cffi_bootstrap_text = NULL; | |
return 0; | |
} | |
static void _cffi_stop_error_capture(PyObject *ecap) | |
{ | |
PyObject *s; | |
void *text; | |
if (ecap == (PyObject *)1) | |
return; | |
if (ecap == NULL) | |
goto error; | |
s = PyRun_String("done()", Py_eval_input, ecap, ecap); | |
if (s == NULL) | |
goto error; | |
/* Show a dialog box, but in a background thread, and | |
never show multiple dialog boxes at once. */ | |
text = PyUnicode_AsWideCharString(s, NULL); | |
text = PyString_AsString(s); | |
_cffi_bootstrap_text = text; | |
if (text != NULL) | |
{ | |
HANDLE h; | |
h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, | |
NULL, 0, NULL); | |
if (h != NULL) | |
CloseHandle(h); | |
} | |
/* decref the string, but it should stay alive as 'fl.buf' | |
in the small module above. It will really be freed only if | |
we later get another similar error. So it's a leak of at | |
most one copy of the small module. That's fine for this | |
situation which is usually a "fatal error" anyway. */ | |
Py_DECREF(s); | |
PyErr_Clear(); | |
return; | |
error: | |
_cffi_bootstrap_text = NULL; | |
PyErr_Clear(); | |
} | |
static PyObject *_cffi_start_error_capture(void) { return NULL; } | |
static void _cffi_stop_error_capture(PyObject *ecap) { } | |