You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

_cffi_errors.h 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #ifndef CFFI_MESSAGEBOX
  2. # ifdef _MSC_VER
  3. # define CFFI_MESSAGEBOX 1
  4. # else
  5. # define CFFI_MESSAGEBOX 0
  6. # endif
  7. #endif
  8. #if CFFI_MESSAGEBOX
  9. /* Windows only: logic to take the Python-CFFI embedding logic
  10. initialization errors and display them in a background thread
  11. with MessageBox. The idea is that if the whole program closes
  12. as a result of this problem, then likely it is already a console
  13. program and you can read the stderr output in the console too.
  14. If it is not a console program, then it will likely show its own
  15. dialog to complain, or generally not abruptly close, and for this
  16. case the background thread should stay alive.
  17. */
  18. static void *volatile _cffi_bootstrap_text;
  19. static PyObject *_cffi_start_error_capture(void)
  20. {
  21. PyObject *result = NULL;
  22. PyObject *x, *m, *bi;
  23. if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text,
  24. (void *)1, NULL) != NULL)
  25. return (PyObject *)1;
  26. m = PyImport_AddModule("_cffi_error_capture");
  27. if (m == NULL)
  28. goto error;
  29. result = PyModule_GetDict(m);
  30. if (result == NULL)
  31. goto error;
  32. #if PY_MAJOR_VERSION >= 3
  33. bi = PyImport_ImportModule("builtins");
  34. #else
  35. bi = PyImport_ImportModule("__builtin__");
  36. #endif
  37. if (bi == NULL)
  38. goto error;
  39. PyDict_SetItemString(result, "__builtins__", bi);
  40. Py_DECREF(bi);
  41. x = PyRun_String(
  42. "import sys\n"
  43. "class FileLike:\n"
  44. " def write(self, x):\n"
  45. " try:\n"
  46. " of.write(x)\n"
  47. " except: pass\n"
  48. " self.buf += x\n"
  49. "fl = FileLike()\n"
  50. "fl.buf = ''\n"
  51. "of = sys.stderr\n"
  52. "sys.stderr = fl\n"
  53. "def done():\n"
  54. " sys.stderr = of\n"
  55. " return fl.buf\n", /* make sure the returned value stays alive */
  56. Py_file_input,
  57. result, result);
  58. Py_XDECREF(x);
  59. error:
  60. if (PyErr_Occurred())
  61. {
  62. PyErr_WriteUnraisable(Py_None);
  63. PyErr_Clear();
  64. }
  65. return result;
  66. }
  67. #pragma comment(lib, "user32.lib")
  68. static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored)
  69. {
  70. Sleep(666); /* may be interrupted if the whole process is closing */
  71. #if PY_MAJOR_VERSION >= 3
  72. MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text,
  73. L"Python-CFFI error",
  74. MB_OK | MB_ICONERROR);
  75. #else
  76. MessageBoxA(NULL, (char *)_cffi_bootstrap_text,
  77. "Python-CFFI error",
  78. MB_OK | MB_ICONERROR);
  79. #endif
  80. _cffi_bootstrap_text = NULL;
  81. return 0;
  82. }
  83. static void _cffi_stop_error_capture(PyObject *ecap)
  84. {
  85. PyObject *s;
  86. void *text;
  87. if (ecap == (PyObject *)1)
  88. return;
  89. if (ecap == NULL)
  90. goto error;
  91. s = PyRun_String("done()", Py_eval_input, ecap, ecap);
  92. if (s == NULL)
  93. goto error;
  94. /* Show a dialog box, but in a background thread, and
  95. never show multiple dialog boxes at once. */
  96. #if PY_MAJOR_VERSION >= 3
  97. text = PyUnicode_AsWideCharString(s, NULL);
  98. #else
  99. text = PyString_AsString(s);
  100. #endif
  101. _cffi_bootstrap_text = text;
  102. if (text != NULL)
  103. {
  104. HANDLE h;
  105. h = CreateThread(NULL, 0, _cffi_bootstrap_dialog,
  106. NULL, 0, NULL);
  107. if (h != NULL)
  108. CloseHandle(h);
  109. }
  110. /* decref the string, but it should stay alive as 'fl.buf'
  111. in the small module above. It will really be freed only if
  112. we later get another similar error. So it's a leak of at
  113. most one copy of the small module. That's fine for this
  114. situation which is usually a "fatal error" anyway. */
  115. Py_DECREF(s);
  116. PyErr_Clear();
  117. return;
  118. error:
  119. _cffi_bootstrap_text = NULL;
  120. PyErr_Clear();
  121. }
  122. #else
  123. static PyObject *_cffi_start_error_capture(void) { return NULL; }
  124. static void _cffi_stop_error_capture(PyObject *ecap) { }
  125. #endif