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:
parent
3179cb0069
commit
3ab65cff04
@ -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")
|
||||
|
@ -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)
|
||||
|
22
intern/uriconvert/CMakeLists.txt
Normal file
22
intern/uriconvert/CMakeLists.txt
Normal 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}")
|
42
intern/uriconvert/uri_convert.cc
Normal file
42
intern/uriconvert/uri_convert.cc
Normal 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;
|
||||
}
|
25
intern/uriconvert/uri_convert.hh
Normal file
25
intern/uriconvert/uri_convert.hh
Normal 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);
|
@ -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")
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user