Windows: show popup after crash

Implements a crash dialog for Windows.

The crash popup provides the following actions:
- Restart: reopen Blender from the last saved or auto-saved time
- Report a Bug: forward to Blender bug tracker
- View Crash Log: open the .txt file with the crash log
- Close: Closes without any further action

Pull Request: https://projects.blender.org/blender/blender/pulls/129974
This commit is contained in:
Germano Cavalcante 2025-04-04 18:38:53 +02:00 committed by Germano Cavalcante
parent 3179cb0069
commit 3ab65cff04
16 changed files with 465 additions and 46 deletions

View File

@ -174,8 +174,8 @@ remove_cc_flag(
)
if(MSVC_CLANG) # Clangs version of cl doesn't support all flags
string(APPEND CMAKE_CXX_FLAGS " ${CXX_WARN_FLAGS} /MP /nologo /J /Gd /showFilenames /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference /clang:-funsigned-char /clang:-fno-strict-aliasing /clang:-ffp-contract=off")
string(APPEND CMAKE_C_FLAGS " /MP /nologo /J /Gd /showFilenames -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference /clang:-funsigned-char /clang:-fno-strict-aliasing /clang:-ffp-contract=off")
string(APPEND CMAKE_CXX_FLAGS " ${CXX_WARN_FLAGS} /Gy /MP /nologo /J /Gd /showFilenames /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference /clang:-funsigned-char /clang:-fno-strict-aliasing /clang:-ffp-contract=off")
string(APPEND CMAKE_C_FLAGS " /MP /nologo /J /Gy /Gd /showFilenames -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference /clang:-funsigned-char /clang:-fno-strict-aliasing /clang:-ffp-contract=off")
else()
string(APPEND CMAKE_CXX_FLAGS " /nologo /J /Gd /MP /EHsc /bigobj")
string(APPEND CMAKE_C_FLAGS " /nologo /J /Gd /MP /bigobj")

View File

@ -39,9 +39,13 @@ if(WITH_BULLET)
add_subdirectory(rigidbody)
endif()
# only windows needs utf16 converter
if(WIN32)
# Only windows needs utf16 converter.
add_subdirectory(utfconv)
# Only used for Windows for now.
add_subdirectory(uriconvert)
endif()
if(WITH_MOD_FLUID)

View File

@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: 2024 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
.
)
set(INC_SYS
)
set(SRC
uri_convert.cc
uri_convert.hh
)
set(LIB
)
blender_add_lib(bf_intern_uriconvert "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -0,0 +1,42 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include <cctype>
#include <cstdio>
#include "uri_convert.hh" /* Own include. */
bool url_encode(const char *str, char *dst, size_t dst_size)
{
size_t i = 0;
while (*str && i < dst_size - 1) {
char c = char(*str);
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
dst[i++] = *str;
}
else if (c == ' ') {
dst[i++] = '+';
}
else {
if (i + 3 >= dst_size) {
/* There is not enough space for %XX. */
dst[i] = '\0';
return false;
}
sprintf(&dst[i], "%%%02X", c);
i += 3;
}
++str;
}
dst[i] = '\0';
if (*str != '\0') {
/* Output buffer was too small. */
return false;
}
return true;
}

View File

@ -0,0 +1,25 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup intern_uri
*/
/**
* \brief Encodes a string into URL format by converting special characters into percent-encoded
* sequences.
*
* This function iterates over the provided C-string and replaces non-alphanumeric characters
* (except for '-', '_', '.', '~') with their hexadecimal representations prefixed with '%'.
* Spaces are converted into '+', following the conventions of URL encoding for forms
* (application/x-www-form-urlencoded).
*
* \param str: The input C-string to be URL-encoded.
* \param dst: The output buffer where the URL-encoded string will be stored.
* \param dst_size: The size of the output buffer `dst`.
* \return: `true` if encoding was successful, or `false` if the output buffer was insufficient.
*/
bool url_encode(const char *str, char *dst, size_t dst_size);

View File

@ -37,7 +37,12 @@ if(WIN32)
add_library(BlendThumb SHARED ${SRC} ${SRC_WIN32})
target_link_libraries(BlendThumb bf_blenlib dbghelp.lib Version.lib)
target_link_libraries(BlendThumb bf_blenlib dbghelp.lib Version.lib Comctl32.lib)
# Blenlib drags in a whole bunch of dependencies on shared libs, none of which are used by
# blenthumb, but will cause load issues since the debug linker will not eleminate them.
# Link with /OPT:ref to force elmination of those unused dependencies this is already
# enabled by default on the release mode flags.
set_target_properties(BlendThumb PROPERTIES LINK_FLAGS "/OPT:ref")
set_target_properties(BlendThumb PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt")
set_target_properties(BlendThumb PROPERTIES VS_GLOBAL_VcpkgEnabled "false")

View File

@ -29,6 +29,8 @@ void BKE_blender_globals_main_replace(Main *bmain);
*/
Main *BKE_blender_globals_main_swap(Main *new_gmain);
void BKE_blender_globals_crash_path_get(char *filepath);
void BKE_blender_userdef_data_swap(UserDef *userdef_a, UserDef *userdef_b);
void BKE_blender_userdef_data_set(UserDef *userdef);
void BKE_blender_userdef_data_set_and_free(UserDef *userdef);

View File

@ -42,6 +42,12 @@ struct Global {
char filepath_last_image[/*FILE_MAX*/ 1024];
/** Last used location for library link/append. */
char filepath_last_library[/*FILE_MAX*/ 1024];
/**
* Last saved location for .blend files.
* This is used for recovery in case of a crash.
* It is set when a .blend file is loaded or when saving (manually or through autosave).
*/
char filepath_last_blend[/*FILE_MAX*/ 1024];
/**
* Strings of recently opened files to show in the file menu.

View File

@ -28,6 +28,7 @@
#include "MOV_util.hh"
#include "BKE_addon.h"
#include "BKE_appdir.hh"
#include "BKE_asset.hh"
#include "BKE_blender.hh" /* own include */
#include "BKE_blender_user_menu.hh" /* own include */
@ -199,6 +200,7 @@ void BKE_blender_globals_init()
BKE_blender_globals_main_replace(BKE_main_new());
STRNCPY(G.filepath_last_image, "//");
G.filepath_last_blend[0] = '\0';
#ifndef WITH_PYTHON_SECURITY /* default */
G.f |= G_FLAG_SCRIPT_AUTOEXEC;
@ -241,6 +243,20 @@ Main *BKE_blender_globals_main_swap(Main *new_gmain)
return old_gmain;
}
void BKE_blender_globals_crash_path_get(char filepath[FILE_MAX])
{
/* Might be called after WM/Main exit, so needs to be careful about nullptr-checking before
* de-referencing. */
if (!(G_MAIN && G_MAIN->filepath[0])) {
BLI_path_join(filepath, FILE_MAX, BKE_tempdir_base(), "blender.crash.txt");
}
else {
BLI_path_join(filepath, FILE_MAX, BKE_tempdir_base(), BLI_path_basename(G_MAIN->filepath));
BLI_path_extension_replace(filepath, FILE_MAX, ".crash.txt");
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -1202,6 +1202,9 @@ static void setup_app_data(bContext *C,
STRNCPY(bmain->filepath, bfd->filepath);
}
/* Set the loaded .blend file path for crash recovery. */
STRNCPY(G.filepath_last_blend, bmain->filepath);
/* Base-flags, groups, make depsgraph, etc. */
/* first handle case if other windows have different scenes visible. */
if (mode == LOAD_UI) {

View File

@ -43,7 +43,12 @@ int BLI_system_memory_max_in_megabytes_int(void);
* \note Use `void *` for `exception` since we really do not want to drag Windows.h
* in to get the proper `typedef`.
*/
void BLI_windows_handle_exception(void *exception);
void BLI_windows_exception_capture(void *exception);
void BLI_windows_exception_show_dialog(const void *exception,
const char *filepath_crashlog,
const char *filepath_relaunch,
const char *gpu_name,
const char *build_version);
#else
# define BLI_SYSTEM_PID_H <unistd.h>

View File

@ -466,9 +466,11 @@ if(WIN32)
add_definitions(-DWITH_BLENDER_THUMBNAILER)
endif()
list(APPEND INC
../../../intern/uriconvert
../../../intern/utfconv
)
list(APPEND LIB
bf_intern_uriconvert
bf_intern_utfconv
dxgi
)

View File

@ -5,8 +5,10 @@
/** \file
* \ingroup bli
*/
#include <Windows.h>
#include <stdio.h>
#include <commctrl.h>
#include <sstream>
#include <dbghelp.h>
#include <shlwapi.h>
@ -14,6 +16,9 @@
#include "MEM_guardedalloc.h"
#include "uri_convert.hh"
#include "utfconv.hh"
#include "BLI_string.h"
#include "BLI_system.h" /* Own include. */
@ -397,22 +402,276 @@ void BLI_system_backtrace_with_os_info(FILE *fp, const void *os_info)
bli_windows_system_backtrace_modules(fp);
}
void BLI_windows_handle_exception(void *exception)
static void bli_windows_exception_message_get(const EXCEPTION_POINTERS *exception,
char r_message[512])
{
const EXCEPTION_POINTERS *exception_info = static_cast<EXCEPTION_POINTERS *>(exception);
if (exception_info) {
fprintf(stderr,
"Error : %s\n",
bli_windows_get_exception_description(exception_info->ExceptionRecord->ExceptionCode));
fflush(stderr);
LPVOID address = exception_info->ExceptionRecord->ExceptionAddress;
fprintf(stderr, "Address : 0x%p\n", address);
CHAR modulename[MAX_PATH];
bli_windows_get_module_name(address, modulename, sizeof(modulename));
fprintf(stderr, "Module : %s\n", modulename);
fprintf(stderr, "Thread : %.8x\n", GetCurrentThreadId());
if (!exception) {
r_message[0] = '\0';
return;
}
fflush(stderr);
const char *exception_name = bli_windows_get_exception_description(
exception->ExceptionRecord->ExceptionCode);
LPVOID address = exception->ExceptionRecord->ExceptionAddress;
CHAR modulename[MAX_PATH];
bli_windows_get_module_name(address, modulename, sizeof(modulename));
DWORD threadId = GetCurrentThreadId();
snprintf(r_message,
512,
"Error : %s\n"
"Address : 0x%p\n"
"Module : %s\n"
"Thread : %.8x\n",
exception_name,
address,
modulename,
threadId);
}
/* -------------------------------------------------------------------- */
/** \name bli_show_message_box
* \{ */
static std::string get_os_info()
{
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
return "Unknown System";
}
std::string version = std::to_string(osvi.dwMajorVersion) + "-" +
std::to_string(osvi.dwMajorVersion) + "." +
std::to_string(osvi.dwMinorVersion) + "." +
std::to_string(osvi.dwBuildNumber) + "-SP" +
std::to_string(osvi.wServicePackMajor);
SYSTEM_INFO si;
GetSystemInfo(&si);
std::string architecture;
switch (si.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64:
architecture = "64 Bits";
break;
case PROCESSOR_ARCHITECTURE_INTEL:
architecture = "32 Bits";
break;
case PROCESSOR_ARCHITECTURE_ARM:
architecture = "ARM Architecture";
break;
case PROCESSOR_ARCHITECTURE_ARM64:
architecture = "ARM64 Architecture";
break;
case PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64:
architecture = "ARM32 on Windows 64-bit";
break;
case PROCESSOR_ARCHITECTURE_IA32_ON_ARM64:
architecture = "IA32 on ARM64";
break;
default:
architecture = "Unknown Architecture";
}
return "Windows-" + version + " " + architecture;
}
/**
* Retrieve the path to "blender-launcher.exe" if it exists; otherwise, return the current
* executable path.
*/
static bool bli_executable_path_get(LPWSTR path, DWORD size)
{
wchar_t executable_path[MAX_PATH];
DWORD nSize = GetModuleFileNameW(nullptr, executable_path, MAX_PATH);
if (nSize == 0 || nSize == MAX_PATH) {
return false;
}
if (size <= nSize) {
return false;
}
/* Copy the path to the output buffer. */
if (wcscpy_s(path, size, executable_path) != 0) {
return false;
}
/* Replace the filename "blender.exe" with "blender-launcher.exe". */
if (!PathRemoveFileSpecW(executable_path)) {
/* Failed to remove the file spec. Use the original path. */
return true;
}
if (!PathAppendW(executable_path, L"blender-launcher.exe")) {
/* Failed to append the new filename. Use the original path. */
return true;
}
/* Check if "blender-launcher.exe" exists at this path. */
DWORD attributes = GetFileAttributesW(executable_path);
if (attributes == INVALID_FILE_ATTRIBUTES || (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
/* "blender-launcher.exe" does not exist. Use the original executable path. */
return true;
}
if (wcslen(executable_path) + 1 > size) {
/* The output buffer is not large enough for the new path. Use the original path. */
return true;
}
/* The file exists. Copy the path to the output buffer. */
if (wcscpy_s(path, size, executable_path) != 0) {
/* Error: It's not supposed to happen. Return false since the buffer has been modified. */
return false;
}
return true;
}
/* Wrapper function for url_encode. */
static std::wstring url_encode_wstring(const std::string &str)
{
size_t len = str.length();
/* Maximum encoded length is 3 times the original length +1 for null terminator. */
size_t encoded_len_max = len * 3 + 1;
char *encoded_str = new char[encoded_len_max];
url_encode(str.c_str(), encoded_str, encoded_len_max);
/* Convert the encoded char *to a std::wstring (assuming the encoded string is ASCII). */
std::wstring result(encoded_str, encoded_str + strlen(encoded_str));
delete[] encoded_str;
return result;
}
/**
* Displays a crash report dialog with options to open the crash log, restart the application, and
* report a bug. This is based on the `showMessageBox` function in `GHOST_SystemWin32.cc`.
*/
static void bli_show_crash_report_dialog(const char *filepath_crashlog,
const char *filepath_relaunch,
const char *gpu_name,
const char *build_version)
{
/* Redundant: InitCommonControls is already called during GHOST System initialization. */
// InitCommonControls();
/* Convert file paths to UTF-16 to handle non-ASCII characters. */
wchar_t *filepath_crashlog_utf16 = alloc_utf16_from_8(filepath_crashlog, 0);
wchar_t *filepath_relaunch_utf16 = filepath_relaunch[0] ?
alloc_utf16_from_8(filepath_relaunch, 0) :
nullptr;
std::wstring full_message_16 =
L"A problem has caused the program to stop functioning correctly. If you know the steps to "
L"reproduce this issue, please submit a bug report.\n"
"\n"
L"The crash log can be found at:\n" +
std::wstring(filepath_crashlog_utf16);
TASKDIALOGCONFIG config = {0};
const TASKDIALOG_BUTTON buttons[] = {{IDRETRY, L"Restart"},
{IDOK, L"Report a Bug"},
{IDHELP, L"View Crash Log"},
{IDCLOSE, L"Close"}};
config.cbSize = sizeof(config);
config.hwndParent = GetActiveWindow();
config.hInstance = 0;
config.dwCommonButtons = 0;
config.pszMainIcon = TD_ERROR_ICON;
config.pszWindowTitle = L"Blender";
config.pszMainInstruction = L"Blender has stopped working";
config.pszContent = full_message_16.c_str();
config.pButtons = buttons;
config.cButtons = ARRAY_SIZE(buttons);
/* Data passed to the callback function for handling button events. */
const struct Data {
const wchar_t *filepath_crashlog_utf16;
const wchar_t *filepath_relaunch_utf16;
const char *gpu_name;
const char *build_version;
} data = {filepath_crashlog_utf16, filepath_relaunch_utf16, gpu_name, build_version};
config.lpCallbackData = reinterpret_cast<LONG_PTR>(&data);
/* Callback for handling button events. */
config.pfCallback = [](HWND /*hwnd*/,
UINT uNotification,
WPARAM wParam,
LPARAM /*lParam*/,
LONG_PTR dwRefData) -> HRESULT {
const Data *data_ptr = reinterpret_cast<const Data *>(dwRefData);
if (uNotification != TDN_BUTTON_CLICKED) {
return S_OK;
}
int pnButton = static_cast<int>(wParam);
switch (pnButton) {
case IDCLOSE:
return S_OK;
case IDRETRY: {
/* Relaunch the application. */
wchar_t executable_path[MAX_PATH];
if (bli_executable_path_get(executable_path, ARRAYSIZE(executable_path))) {
std::wstring parameters;
if (data_ptr->filepath_relaunch_utf16) {
/* Properly quote the argument to handle spaces and special characters. */
parameters = L"\"" + std::wstring(data_ptr->filepath_relaunch_utf16) + L"\"";
}
else {
/* Proceeding without parameters. */
parameters = L"";
}
ShellExecuteW(
nullptr, L"open", executable_path, parameters.c_str(), nullptr, SW_SHOWNORMAL);
}
return S_OK;
}
case IDHELP:
/* Open the crash log. */
ShellExecuteW(
nullptr, L"open", data_ptr->filepath_crashlog_utf16, nullptr, nullptr, SW_SHOWNORMAL);
return S_FALSE;
case IDOK: {
/* Open the bug report form with pre-filled data. */
/* clang-format off */
std::wstring link =
L"https://redirect.blender.org/"
L"?type=bug_report"
L"&project=blender"
L"&os=" + url_encode_wstring(get_os_info()) +
L"&gpu=" + url_encode_wstring(data_ptr->gpu_name) +
L"&broken_version=" + url_encode_wstring(data_ptr->build_version);
/* clang-format on */
ShellExecuteW(nullptr, L"open", link.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
return S_FALSE;
}
default:
return S_FALSE;
}
};
TaskDialogIndirect(&config, nullptr, nullptr, nullptr);
free((void *)filepath_crashlog_utf16);
free((void *)filepath_relaunch_utf16);
}
void BLI_windows_exception_show_dialog(const void *exception,
const char *filepath_crashlog,
const char *filepath_relaunch,
const char *gpu_name,
const char *build_version)
{
char message[512];
bli_windows_exception_message_get(static_cast<const EXCEPTION_POINTERS *>(exception), message);
fprintf(stderr, message);
fflush(stderr);
bli_show_crash_report_dialog(filepath_crashlog, filepath_relaunch, gpu_name, build_version);
}
/** \} */

View File

@ -1771,7 +1771,10 @@ static bool BLO_write_file_impl(Main *mainvar,
}
write_file_main_validate_post(mainvar, reports);
if (mainvar->is_global_main && !params->use_save_as_copy) {
/* It is used to reload Blender after a crash on Windows OS. */
STRNCPY(G.filepath_last_blend, filepath);
}
return true;
}

View File

@ -12,6 +12,11 @@ set(SRC
msgfmt.cc
)
# Manifest required for selecting comctl32 v6 required by the crash popup.
if(WIN32 AND NOT WITH_WINDOWS_EXTERNAL_MANIFEST)
LIST(APPEND SRC "${CMAKE_BINARY_DIR}/tests.exe.manifest")
endif()
set(LIB
PRIVATE PRIVATE bf::blenlib
PRIVATE bf::intern::guardedalloc
@ -29,3 +34,10 @@ add_executable(msgfmt ${SRC})
setup_platform_linker_flags(msgfmt)
blender_target_include_dirs(msgfmt ${INC})
target_link_libraries(msgfmt ${LIB})
# If using an external manifest, copy it to the output directory after building.
if(WITH_WINDOWS_EXTERNAL_MANIFEST)
add_custom_command(TARGET msgfmt POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/tests.exe.manifest $<TARGET_FILE_DIR:msgfmt>/$<TARGET_FILE_NAME:msgfmt>.manifest
)
endif()

View File

@ -8,6 +8,9 @@
#ifndef WITH_PYTHON_MODULE
# include <cerrno>
# include <cstdlib>
# if defined(__linux__) && defined(__GNUC__)
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
@ -23,23 +26,20 @@
# ifdef WIN32
# include <float.h>
# include <windows.h>
# endif
# include <cerrno>
# include <cstdlib>
# include <cstring>
# ifdef WIN32
# include "BLI_winstuff.h"
# include "GPU_platform.hh"
# endif
# include "BLI_fileops.h"
# include "BLI_path_utils.hh"
# include "BLI_string.h"
# include "BLI_system.h"
# include "BLI_utildefines.h"
# include BLI_SYSTEM_PID_H
# include "BKE_appdir.hh" /* #BKE_tempdir_base. */
# include "BKE_appdir.hh" /* #BKE_tempdir_session_purge. */
# include "BKE_blender.hh"
# include "BKE_blender_version.h"
# include "BKE_global.hh"
# include "BKE_main.hh"
@ -81,7 +81,7 @@ static void sig_handle_blender_esc(int sig)
}
}
static void sig_handle_crash_backtrace(int signum, const void *os_info)
static void crashlog_file_generate(const char *filepath, const void *os_info)
{
/* Might be called after WM/Main exit, so needs to be careful about nullptr-checking before
* de-referencing. */
@ -91,17 +91,6 @@ static void sig_handle_crash_backtrace(int signum, const void *os_info)
FILE *fp;
char header[512];
char filepath[FILE_MAX];
if (!(G_MAIN && G_MAIN->filepath[0])) {
BLI_path_join(filepath, sizeof(filepath), BKE_tempdir_base(), "blender.crash.txt");
}
else {
BLI_path_join(
filepath, sizeof(filepath), BKE_tempdir_base(), BLI_path_basename(G_MAIN->filepath));
BLI_path_extension_replace(filepath, sizeof(filepath), ".crash.txt");
}
printf("Writing: %s\n", filepath);
fflush(stdout);
@ -140,7 +129,10 @@ static void sig_handle_crash_backtrace(int signum, const void *os_info)
fclose(fp);
}
}
static void sig_cleanup_and_terminate(int signum)
{
/* Delete content of temp directory. */
BKE_tempdir_session_purge();
@ -155,7 +147,10 @@ static void sig_handle_crash_backtrace(int signum, const void *os_info)
static void sig_handle_crash_fn(int signum)
{
sig_handle_crash_backtrace(signum, nullptr);
char filepath_crashlog[FILE_MAX];
BKE_blender_globals_crash_path_get(filepath_crashlog);
crashlog_file_generate(filepath_crashlog, nullptr);
sig_cleanup_and_terminate(signum);
}
# ifdef WIN32
@ -176,8 +171,26 @@ extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
}
}
else {
BLI_windows_handle_exception(ExceptionInfo);
sig_handle_crash_backtrace(SIGSEGV, ExceptionInfo);
std::string version;
# ifndef BUILD_DATE
const char *build_hash = G_MAIN ? G_MAIN->build_hash : "unknown";
version = std::string("version: ") + BKE_blender_version_string() + ", hash: `" + build_hash +
"`";
# else
version = std::string("version: ") + BKE_blender_version_string() +
", Commit date: " + build_commit_date + " " + build_commit_time + ", hash: `" +
build_hash + "`";
# endif
char filepath_crashlog[FILE_MAX];
BKE_blender_globals_crash_path_get(filepath_crashlog);
crashlog_file_generate(filepath_crashlog, ExceptionInfo);
BLI_windows_exception_show_dialog(ExceptionInfo,
filepath_crashlog,
G.filepath_last_blend,
GPU_platform_gpu_name(),
version.c_str());
sig_cleanup_and_terminate(SIGSEGV);
}
return EXCEPTION_EXECUTE_HANDLER;