Restore reporting of unhandled exceptions during GUI application startup on windows

Not as nice as it was previously since errors importing the site module
will not be reported, but the python API provides no hooks for this in
Py_RunMain
This commit is contained in:
Kovid Goyal 2019-12-04 23:03:34 +05:30
parent 007b6d06ed
commit 1c13f9634c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 53 additions and 1 deletions

View File

@ -170,6 +170,7 @@ typedef struct {
#endif #endif
const wchar_t *basename, *module, *function; const wchar_t *basename, *module, *function;
int argc; int argc;
PyObject* (*calibre_os_module)(void);
#ifdef _WIN32 #ifdef _WIN32
wchar_t* const *argv; wchar_t* const *argv;
#else #else
@ -237,6 +238,11 @@ run_interpreter() {
status = PyConfig_SetBytesArgv(&config, interpreter_data.argc, interpreter_data.argv); status = PyConfig_SetBytesArgv(&config, interpreter_data.argc, interpreter_data.argv);
#endif #endif
CHECK_STATUS; CHECK_STATUS;
if (interpreter_data.calibre_os_module) {
if (PyImport_AppendInittab("calibre_os_module", interpreter_data.calibre_os_module) == -1) {
fatal("Failed to add calibre_os_module to the init table");
}
}
status = Py_InitializeFromConfig(&config); status = Py_InitializeFromConfig(&config);
CHECK_STATUS; CHECK_STATUS;

View File

@ -85,4 +85,13 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() try:
main()
except Exception:
if sys.gui_app:
import traceback
import calibre_os_module
calibre_os_module.gui_error_message(
f"Unhandled exception running {sys.calibre_basename}",
traceback.format_exc())
raise

View File

@ -115,6 +115,42 @@ redirect_out_stream(FILE *stream) {
} }
} }
static PyObject*
gui_error_message(PyObject *self, PyObject *args) {
PyObject *pt, *pm;
if (!PyArg_ParseTuple(args, "UU", &pt, &pm)) return NULL;
wchar_t title[256] = {0}, text[4096] = {0};
PyUnicode_AsWideChar(pt, title, arraysz(title)-1);
PyUnicode_AsWideChar(pm, text, arraysz(text)-1);
MessageBoxW(NULL, text, title, MB_ICONERROR|MB_OK);
return PyBool_FromLong(1);
}
static PyMethodDef methods[] = {
{"gui_error_message", (PyCFunction)gui_error_message, METH_VARARGS,
"gui_error_message(title, msg) -> Show a GUI based error message."
},
{NULL} /* Sentinel */
};
static struct PyModuleDef module = {
/* m_base */ PyModuleDef_HEAD_INIT,
/* m_name */ "calibre_os_module",
/* m_doc */ "Integration with OS facilities during startup",
/* m_size */ -1,
/* m_methods */ methods,
/* m_slots */ 0,
/* m_traverse */ 0,
/* m_clear */ 0,
/* m_free */ 0,
};
PyObject*
calibre_os_module(void) {
return PyModule_Create(&module);
}
static void static void
null_invalid_parameter_handler( null_invalid_parameter_handler(
const wchar_t * expression, const wchar_t * expression,
@ -151,6 +187,7 @@ execute_python_entrypoint(const wchar_t *basename, const wchar_t *module, const
interpreter_data.argv = CommandLineToArgvW(GetCommandLineW(), &interpreter_data.argc); interpreter_data.argv = CommandLineToArgvW(GetCommandLineW(), &interpreter_data.argc);
if (interpreter_data.argv == NULL) ExitProcess(show_last_error(L"Failed to get command line")); if (interpreter_data.argv == NULL) ExitProcess(show_last_error(L"Failed to get command line"));
interpreter_data.basename = basename; interpreter_data.module = module; interpreter_data.function = function; interpreter_data.basename = basename; interpreter_data.module = module; interpreter_data.function = function;
interpreter_data.calibre_os_module = calibre_os_module;
load_python_dll(); load_python_dll();
pre_initialize_interpreter(is_gui_app); pre_initialize_interpreter(is_gui_app);
run_interpreter(); run_interpreter();