Blender V4.5
system_win32.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <Windows.h>
10#include <commctrl.h>
11#include <sstream>
12
13#include <dbghelp.h>
14#include <shlwapi.h>
15#include <tlhelp32.h>
16
17#include "MEM_guardedalloc.h"
18
19#include "uri_convert.hh"
20#include "utfconv.hh"
21
22#include "BLI_string.h"
23
24#include "BLI_system.h" /* Own include. */
25
26static const char *bli_windows_get_exception_description(const DWORD exceptioncode)
27{
28 switch (exceptioncode) {
29 case EXCEPTION_ACCESS_VIOLATION:
30 return "EXCEPTION_ACCESS_VIOLATION";
31 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
32 return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
33 case EXCEPTION_BREAKPOINT:
34 return "EXCEPTION_BREAKPOINT";
35 case EXCEPTION_DATATYPE_MISALIGNMENT:
36 return "EXCEPTION_DATATYPE_MISALIGNMENT";
37 case EXCEPTION_FLT_DENORMAL_OPERAND:
38 return "EXCEPTION_FLT_DENORMAL_OPERAND";
39 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
40 return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
41 case EXCEPTION_FLT_INEXACT_RESULT:
42 return "EXCEPTION_FLT_INEXACT_RESULT";
43 case EXCEPTION_FLT_INVALID_OPERATION:
44 return "EXCEPTION_FLT_INVALID_OPERATION";
45 case EXCEPTION_FLT_OVERFLOW:
46 return "EXCEPTION_FLT_OVERFLOW";
47 case EXCEPTION_FLT_STACK_CHECK:
48 return "EXCEPTION_FLT_STACK_CHECK";
49 case EXCEPTION_FLT_UNDERFLOW:
50 return "EXCEPTION_FLT_UNDERFLOW";
51 case EXCEPTION_ILLEGAL_INSTRUCTION:
52 return "EXCEPTION_ILLEGAL_INSTRUCTION";
53 case EXCEPTION_IN_PAGE_ERROR:
54 return "EXCEPTION_IN_PAGE_ERROR";
55 case EXCEPTION_INT_DIVIDE_BY_ZERO:
56 return "EXCEPTION_INT_DIVIDE_BY_ZERO";
57 case EXCEPTION_INT_OVERFLOW:
58 return "EXCEPTION_INT_OVERFLOW";
59 case EXCEPTION_INVALID_DISPOSITION:
60 return "EXCEPTION_INVALID_DISPOSITION";
61 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
62 return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
63 case EXCEPTION_PRIV_INSTRUCTION:
64 return "EXCEPTION_PRIV_INSTRUCTION";
65 case EXCEPTION_SINGLE_STEP:
66 return "EXCEPTION_SINGLE_STEP";
67 case EXCEPTION_STACK_OVERFLOW:
68 return "EXCEPTION_STACK_OVERFLOW";
69 default:
70 return "UNKNOWN EXCEPTION";
71 }
72}
73
74static void bli_windows_get_module_name(LPVOID address, PCHAR buffer, size_t size)
75{
76 HMODULE mod;
77 buffer[0] = 0;
78 if (GetModuleHandleEx(
79 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCSTR>(address), &mod))
80 {
81 if (GetModuleFileName(mod, buffer, size)) {
82 PathStripPath(buffer);
83 }
84 }
85}
86
87static void bli_windows_get_module_version(const char *file, char *buffer, size_t buffersize)
88{
89 buffer[0] = 0;
90 DWORD verHandle = 0;
91 UINT size = 0;
92 LPBYTE lpBuffer = nullptr;
93 DWORD verSize = GetFileVersionInfoSize(file, &verHandle);
94 if (verSize != 0) {
95 LPSTR verData = (LPSTR)MEM_callocN(verSize, "crash module version");
96
97 if (GetFileVersionInfo(file, verHandle, verSize, verData)) {
98 if (VerQueryValue(verData, "\\", (VOID FAR * FAR *)&lpBuffer, &size)) {
99 if (size) {
100 VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer;
101 /* Magic value from
102 * https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
103 */
104 if (verInfo->dwSignature == 0xfeef04bd) {
105 BLI_snprintf(buffer,
106 buffersize,
107 "%d.%d.%d.%d",
108 (verInfo->dwFileVersionMS >> 16) & 0xffff,
109 (verInfo->dwFileVersionMS >> 0) & 0xffff,
110 (verInfo->dwFileVersionLS >> 16) & 0xffff,
111 (verInfo->dwFileVersionLS >> 0) & 0xffff);
112 }
113 }
114 }
115 }
116 MEM_freeN(verData);
117 }
118}
119
120static void bli_windows_system_backtrace_exception_record(FILE *fp, PEXCEPTION_RECORD record)
121{
122 char module[MAX_PATH];
123 fprintf(fp, "Exception Record:\n\n");
124 fprintf(fp,
125 "ExceptionCode : %s\n",
126 bli_windows_get_exception_description(record->ExceptionCode));
127 fprintf(fp, "Exception Address : 0x%p\n", record->ExceptionAddress);
128 bli_windows_get_module_name(record->ExceptionAddress, module, sizeof(module));
129 fprintf(fp, "Exception Module : %s\n", module);
130 fprintf(fp, "Exception Flags : 0x%.8x\n", record->ExceptionFlags);
131 fprintf(fp, "Exception Parameters : 0x%x\n", record->NumberParameters);
132 for (DWORD idx = 0; idx < record->NumberParameters; idx++) {
133 fprintf(fp, "\tParameters[%d] : 0x%p\n", idx, (LPVOID *)record->ExceptionInformation[idx]);
134 }
135 if (record->ExceptionRecord) {
136 fprintf(fp, "Nested ");
137 bli_windows_system_backtrace_exception_record(fp, record->ExceptionRecord);
138 }
139 fprintf(fp, "\n\n");
140}
141
142static bool BLI_windows_system_backtrace_run_trace(FILE *fp, HANDLE hThread, PCONTEXT context)
143{
144 const int max_symbol_length = 100;
145
146 bool result = true;
147
148 PSYMBOL_INFO symbolinfo = static_cast<PSYMBOL_INFO>(
149 MEM_callocN(sizeof(SYMBOL_INFO) + max_symbol_length * sizeof(char), "crash Symbol table"));
150 symbolinfo->MaxNameLen = max_symbol_length - 1;
151 symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO);
152
153 STACKFRAME frame = {0};
154 DWORD machineType = 0;
155#if defined(_M_AMD64)
156 frame.AddrPC.Offset = context->Rip;
157 frame.AddrPC.Mode = AddrModeFlat;
158 frame.AddrFrame.Offset = context->Rsp;
159 frame.AddrFrame.Mode = AddrModeFlat;
160 frame.AddrStack.Offset = context->Rsp;
161 frame.AddrStack.Mode = AddrModeFlat;
162 machineType = IMAGE_FILE_MACHINE_AMD64;
163#elif defined(_M_ARM64)
164 frame.AddrPC.Offset = context->Pc;
165 frame.AddrPC.Mode = AddrModeFlat;
166 frame.AddrFrame.Offset = context->Fp;
167 frame.AddrFrame.Mode = AddrModeFlat;
168 frame.AddrStack.Offset = context->Sp;
169 frame.AddrStack.Mode = AddrModeFlat;
170 machineType = IMAGE_FILE_MACHINE_ARM64;
171#endif
172
173 while (true) {
174 if (StackWalk64(machineType,
175 GetCurrentProcess(),
176 hThread,
177 &frame,
178 context,
179 nullptr,
180 SymFunctionTableAccess64,
181 SymGetModuleBase64,
182 0))
183 {
184 if (frame.AddrPC.Offset) {
185 char module[MAX_PATH];
186
187 bli_windows_get_module_name((LPVOID)frame.AddrPC.Offset, module, sizeof(module));
188
189 if (SymFromAddr(GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), 0, symbolinfo)) {
190 fprintf(fp, "%-20s:0x%p %s", module, (LPVOID)symbolinfo->Address, symbolinfo->Name);
191 IMAGEHLP_LINE lineinfo;
192 lineinfo.SizeOfStruct = sizeof(lineinfo);
193 DWORD displacement = 0;
194 if (SymGetLineFromAddr(
195 GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), &displacement, &lineinfo))
196 {
197 fprintf(fp, " %s:%d", lineinfo.FileName, lineinfo.LineNumber);
198 }
199 fprintf(fp, "\n");
200 }
201 else {
202 fprintf(fp,
203 "%-20s:0x%p %s\n",
204 module,
205 (LPVOID)frame.AddrPC.Offset,
206 "Symbols not available");
207 result = false;
208 break;
209 }
210 }
211 else {
212 break;
213 }
214 }
215 else {
216 break;
217 }
218 }
219 MEM_freeN(symbolinfo);
220 fprintf(fp, "\n\n");
221 return result;
222}
223
224static bool bli_windows_system_backtrace_stack_thread(FILE *fp, HANDLE hThread)
225{
226 CONTEXT context = {0};
227 context.ContextFlags = CONTEXT_ALL;
228 /* GetThreadContext requires the thread to be in a suspended state, which is problematic for the
229 * currently running thread, RtlCaptureContext is used as an alternative to sidestep this */
230 if (hThread != GetCurrentThread()) {
231 SuspendThread(hThread);
232 bool success = GetThreadContext(hThread, &context);
233 ResumeThread(hThread);
234 if (!success) {
235 fprintf(fp, "Cannot get thread context : 0x0%.8x\n", GetLastError());
236 return false;
237 }
238 }
239 else {
240 RtlCaptureContext(&context);
241 }
242 return BLI_windows_system_backtrace_run_trace(fp, hThread, &context);
243}
244
246{
247 fprintf(fp, "Loaded Modules :\n");
248 HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
249 if (hModuleSnap == INVALID_HANDLE_VALUE) {
250 return;
251 }
252
253 MODULEENTRY32 me32;
254 me32.dwSize = sizeof(MODULEENTRY32);
255
256 if (!Module32First(hModuleSnap, &me32)) {
257 CloseHandle(hModuleSnap); /* Must clean up the snapshot object! */
258 fprintf(fp, " Error getting module list.\n");
259 return;
260 }
261
262 do {
263 if (me32.th32ProcessID == GetCurrentProcessId()) {
264 char version[MAX_PATH];
265 bli_windows_get_module_version(me32.szExePath, version, sizeof(version));
266
267 IMAGEHLP_MODULE64 m64;
268 m64.SizeOfStruct = sizeof(m64);
269 if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)me32.modBaseAddr, &m64)) {
270 fprintf(fp,
271 "0x%p %-20s %s %s %s\n",
272 me32.modBaseAddr,
273 version,
274 me32.szModule,
275 m64.LoadedPdbName,
276 m64.PdbUnmatched ? "[unmatched]" : "");
277 }
278 else {
279 fprintf(fp, "0x%p %-20s %s\n", me32.modBaseAddr, version, me32.szModule);
280 }
281 }
282 } while (Module32Next(hModuleSnap, &me32));
283}
284
286{
287 fprintf(fp, "Threads:\n");
288 HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
289 THREADENTRY32 te32;
290
291 hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
292 if (hThreadSnap == INVALID_HANDLE_VALUE) {
293 fprintf(fp, "Unable to retrieve threads list.\n");
294 return;
295 }
296
297 te32.dwSize = sizeof(THREADENTRY32);
298
299 if (!Thread32First(hThreadSnap, &te32)) {
300 CloseHandle(hThreadSnap);
301 return;
302 }
303 do {
304 if (te32.th32OwnerProcessID == GetCurrentProcessId()) {
305 if (GetCurrentThreadId() != te32.th32ThreadID) {
306 fprintf(fp, "Thread : %.8x\n", te32.th32ThreadID);
307 HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
309 CloseHandle(ht);
310 }
311 }
312 } while (Thread32Next(hThreadSnap, &te32));
313 CloseHandle(hThreadSnap);
314}
315
316static bool bli_windows_system_backtrace_stack(FILE *fp, const EXCEPTION_POINTERS *exception_info)
317{
318 fprintf(fp, "Stack trace:\n");
319 /* If we are handling an exception use the context record from that. */
320 if (exception_info && exception_info->ExceptionRecord->ExceptionAddress) {
321 /* The back trace code will write to the context record, to protect the original record from
322 * modifications give the backtrace a copy to work on. */
323 CONTEXT TempContext = *exception_info->ContextRecord;
324 return BLI_windows_system_backtrace_run_trace(fp, GetCurrentThread(), &TempContext);
325 }
326 else {
327 /* If there is no current exception or the address is not set, walk the current stack. */
328 return bli_windows_system_backtrace_stack_thread(fp, GetCurrentThread());
329 }
330}
331
333{
334 IMAGEHLP_MODULE64 m64;
335 m64.SizeOfStruct = sizeof(m64);
336 if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)GetModuleHandle(nullptr), &m64)) {
337 return m64.GlobalSymbols;
338 }
339 return false;
340}
341
342static void bli_load_symbols()
343{
344 /* If this is a developer station and the private pdb is already loaded leave it be. */
346 return;
347 }
348
349 char pdb_file[MAX_PATH] = {0};
350
351 /* get the currently executing image */
352 if (GetModuleFileNameA(nullptr, pdb_file, sizeof(pdb_file))) {
353 /* remove the filename */
354 PathRemoveFileSpecA(pdb_file);
355 /* append blender.pdb */
356 PathAppendA(pdb_file, "blender.pdb");
357 if (PathFileExistsA(pdb_file)) {
358 HMODULE mod = GetModuleHandle(nullptr);
359 if (mod) {
360 WIN32_FILE_ATTRIBUTE_DATA file_data;
361 if (GetFileAttributesExA(pdb_file, GetFileExInfoStandard, &file_data)) {
362 /* SymInitialize will try to load symbols on its own, so we first must unload whatever it
363 * did trying to help */
364 SymUnloadModule64(GetCurrentProcess(), (DWORD64)mod);
365
366 DWORD64 module_base = SymLoadModule(GetCurrentProcess(),
367 nullptr,
368 pdb_file,
369 nullptr,
370 (DWORD64)mod,
371 (DWORD)file_data.nFileSizeLow);
372 if (module_base == 0) {
373 fprintf(stderr,
374 "Error loading symbols %s\n\terror:0x%.8x\n\tsize = %d\n\tbase=0x%p\n",
375 pdb_file,
376 GetLastError(),
377 file_data.nFileSizeLow,
378 (LPVOID)mod);
379 }
380 }
381 }
382 }
383 }
384}
385
386void BLI_system_backtrace_with_os_info(FILE *fp, const void *os_info)
387{
388 const EXCEPTION_POINTERS *exception_info = static_cast<const EXCEPTION_POINTERS *>(os_info);
389 SymInitialize(GetCurrentProcess(), nullptr, TRUE);
391 if (exception_info) {
392 bli_windows_system_backtrace_exception_record(fp, exception_info->ExceptionRecord);
393 }
394 if (bli_windows_system_backtrace_stack(fp, exception_info)) {
395 /* When the blender symbols are missing the stack traces will be unreliable
396 * so only run if the previous step completed successfully. */
398 }
400}
401
402void BLI_windows_exception_print_message(const void *os_info)
403{
404 if (!os_info) {
405 return;
406 }
407
408 const EXCEPTION_POINTERS *exception = static_cast<const EXCEPTION_POINTERS *>(os_info);
409 const char *exception_name = bli_windows_get_exception_description(
410 exception->ExceptionRecord->ExceptionCode);
411 LPVOID address = exception->ExceptionRecord->ExceptionAddress;
412 CHAR modulename[MAX_PATH];
413 bli_windows_get_module_name(address, modulename, sizeof(modulename));
414 DWORD threadId = GetCurrentThreadId();
415
416 char message[512];
417 BLI_snprintf(message,
418 512,
419 "Error : %s\n"
420 "Address : 0x%p\n"
421 "Module : %s\n"
422 "Thread : %.8x\n",
423 exception_name,
424 address,
425 modulename,
426 threadId);
427
428 fprintf(stderr, message);
429 fflush(stderr);
430}
431
432/* -------------------------------------------------------------------- */
435
436static std::string get_os_info()
437{
438 OSVERSIONINFOEX osvi;
439 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
440 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
441 if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
442 return "Unknown System";
443 }
444
445 std::string version = std::to_string(osvi.dwMajorVersion) + "-" +
446 std::to_string(osvi.dwMajorVersion) + "." +
447 std::to_string(osvi.dwMinorVersion) + "." +
448 std::to_string(osvi.dwBuildNumber) + "-SP" +
449 std::to_string(osvi.wServicePackMajor);
450
451 SYSTEM_INFO si;
452 GetSystemInfo(&si);
453 std::string architecture;
454 switch (si.wProcessorArchitecture) {
455 case PROCESSOR_ARCHITECTURE_AMD64:
456 architecture = "64 Bits";
457 break;
458 case PROCESSOR_ARCHITECTURE_INTEL:
459 architecture = "32 Bits";
460 break;
461 case PROCESSOR_ARCHITECTURE_ARM:
462 architecture = "ARM Architecture";
463 break;
464 case PROCESSOR_ARCHITECTURE_ARM64:
465 architecture = "ARM64 Architecture";
466 break;
467 case PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64:
468 architecture = "ARM32 on Windows 64-bit";
469 break;
470 case PROCESSOR_ARCHITECTURE_IA32_ON_ARM64:
471 architecture = "IA32 on ARM64";
472 break;
473 default:
474 architecture = "Unknown Architecture";
475 }
476
477 return "Windows-" + version + " " + architecture;
478}
479
484static bool bli_executable_path_get(LPWSTR path, DWORD size)
485{
486 wchar_t executable_path[MAX_PATH];
487 DWORD nSize = GetModuleFileNameW(nullptr, executable_path, MAX_PATH);
488 if (nSize == 0 || nSize == MAX_PATH) {
489 return false;
490 }
491
492 if (size <= nSize) {
493 return false;
494 }
495
496 /* Copy the path to the output buffer. */
497 if (wcscpy_s(path, size, executable_path) != 0) {
498 return false;
499 }
500
501 /* Replace the filename "blender.exe" with "blender-launcher.exe". */
502 if (!PathRemoveFileSpecW(executable_path)) {
503 /* Failed to remove the file spec. Use the original path. */
504 return true;
505 }
506 if (!PathAppendW(executable_path, L"blender-launcher.exe")) {
507 /* Failed to append the new filename. Use the original path. */
508 return true;
509 }
510
511 /* Check if "blender-launcher.exe" exists at this path. */
512 DWORD attributes = GetFileAttributesW(executable_path);
513 if (attributes == INVALID_FILE_ATTRIBUTES || (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
514 /* "blender-launcher.exe" does not exist. Use the original executable path. */
515 return true;
516 }
517
518 if (wcslen(executable_path) + 1 > size) {
519 /* The output buffer is not large enough for the new path. Use the original path. */
520 return true;
521 }
522
523 /* The file exists. Copy the path to the output buffer. */
524 if (wcscpy_s(path, size, executable_path) != 0) {
525 /* Error: It's not supposed to happen. Return false since the buffer has been modified. */
526 return false;
527 }
528
529 return true;
530}
531
532/* Wrapper function for url_encode. */
533static std::wstring url_encode_wstring(const std::string &str)
534{
535 size_t len = str.length();
536
537 /* Maximum encoded length is 3 times the original length +1 for null terminator. */
538 size_t encoded_len_max = len * 3 + 1;
539
540 char *encoded_str = new char[encoded_len_max];
541 url_encode(str.c_str(), encoded_str, encoded_len_max);
542
543 /* Convert the encoded char *to a std::wstring (assuming the encoded string is ASCII). */
544 std::wstring result(encoded_str, encoded_str + strlen(encoded_str));
545
546 delete[] encoded_str;
547
548 return result;
549}
550
551void BLI_windows_exception_show_dialog(const char *filepath_crashlog,
552 const char *filepath_relaunch,
553 const char *gpu_name,
554 const char *build_version)
555{
556 /* Redundant: #InitCommonControls is already called during GHOST System initialization. */
557 // InitCommonControls();
558
559 /* Convert file paths to UTF16 to handle non-ASCII characters. */
560 wchar_t *filepath_crashlog_utf16 = alloc_utf16_from_8(filepath_crashlog, 0);
561 wchar_t *filepath_relaunch_utf16 = filepath_relaunch[0] ?
562 alloc_utf16_from_8(filepath_relaunch, 0) :
563 nullptr;
564
565 std::wstring full_message_16 =
566 L"A problem has caused the program to stop functioning correctly. If you know the steps to "
567 L"reproduce this issue, please submit a bug report.\n"
568 "\n"
569 L"The crash log can be found at:\n" +
570 std::wstring(filepath_crashlog_utf16);
571
572 TASKDIALOGCONFIG config = {0};
573 const TASKDIALOG_BUTTON buttons[] = {
574 {IDRETRY, L"Restart"},
575#if 0
576 /* This lead to a large influx of low quality reports on the tracker,
577 and has been disabled for that reason, we can re-enable this when
578 a better workflow has been established. */
579 {IDOK, L"Report a Bug"},
580#endif
581 {IDHELP, L"View Crash Log"},
582 {IDCLOSE, L"Close"}
583 };
584
585 config.cbSize = sizeof(config);
586 config.hwndParent = GetActiveWindow();
587 config.hInstance = 0;
588 config.dwCommonButtons = 0;
589 config.pszMainIcon = TD_ERROR_ICON;
590 config.pszWindowTitle = L"Blender";
591 config.pszMainInstruction = L"Blender has stopped working";
592 config.pszContent = full_message_16.c_str();
593 config.pButtons = buttons;
594 config.cButtons = ARRAY_SIZE(buttons);
595
596 /* Data passed to the callback function for handling button events. */
597 const struct Data {
598 const wchar_t *filepath_crashlog_utf16;
599 const wchar_t *filepath_relaunch_utf16;
600 const char *gpu_name;
601 const char *build_version;
602 } data = {filepath_crashlog_utf16, filepath_relaunch_utf16, gpu_name, build_version};
603 config.lpCallbackData = reinterpret_cast<LONG_PTR>(&data);
604
605 /* Callback for handling button events. */
606 config.pfCallback = [](HWND /*hwnd*/,
607 UINT uNotification,
608 WPARAM wParam,
609 LPARAM /*lParam*/,
610 LONG_PTR dwRefData) -> HRESULT {
611 const Data *data_ptr = reinterpret_cast<const Data *>(dwRefData);
612 if (uNotification != TDN_BUTTON_CLICKED) {
613 return S_OK;
614 }
615 int pnButton = static_cast<int>(wParam);
616 switch (pnButton) {
617 case IDCLOSE:
618 return S_OK;
619 case IDRETRY: {
620 /* Relaunch the application. */
621 wchar_t executable_path[MAX_PATH];
622 if (bli_executable_path_get(executable_path, ARRAYSIZE(executable_path))) {
623 std::wstring parameters;
624 if (data_ptr->filepath_relaunch_utf16) {
625 /* Properly quote the argument to handle spaces and special characters. */
626 parameters = L"\"" + std::wstring(data_ptr->filepath_relaunch_utf16) + L"\"";
627 }
628 else {
629 /* Proceeding without parameters. */
630 parameters = L"";
631 }
632 ShellExecuteW(
633 nullptr, L"open", executable_path, parameters.c_str(), nullptr, SW_SHOWNORMAL);
634 }
635 return S_OK;
636 }
637 case IDHELP:
638 /* Open the crash log. */
639 ShellExecuteW(
640 nullptr, L"open", data_ptr->filepath_crashlog_utf16, nullptr, nullptr, SW_SHOWNORMAL);
641 return S_FALSE;
642 case IDOK: {
643 /* Open the bug report form with pre-filled data. */
644 /* clang-format off */
645 std::wstring link =
646 L"https://redirect.blender.org/"
647 L"?type=bug_report"
648 L"&project=blender"
649 L"&os=" + url_encode_wstring(get_os_info()) +
650 L"&gpu=" + url_encode_wstring(data_ptr->gpu_name) +
651 L"&broken_version=" + url_encode_wstring(data_ptr->build_version);
652 /* clang-format on */
653 ShellExecuteW(nullptr, L"open", link.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
654 return S_FALSE;
655 }
656 default:
657 return S_FALSE;
658 }
659 };
660
661 TaskDialogIndirect(&config, nullptr, nullptr, nullptr);
662 free((void *)filepath_crashlog_utf16);
663 free((void *)filepath_relaunch_utf16);
664}
665
void BLI_kdtree_nd_ free(KDTree *tree)
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define ARRAY_SIZE(arr)
#define FALSE
Read Guarded memory(de)allocation.
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define str(s)
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define L
static struct PyModuleDef module
Definition python.cpp:796
static void bli_windows_get_module_version(const char *file, char *buffer, size_t buffersize)
static bool bli_windows_system_backtrace_stack_thread(FILE *fp, HANDLE hThread)
static std::wstring url_encode_wstring(const std::string &str)
static void bli_windows_get_module_name(LPVOID address, PCHAR buffer, size_t size)
void BLI_windows_exception_print_message(const void *os_info)
static void bli_windows_system_backtrace_modules(FILE *fp)
static void bli_windows_system_backtrace_exception_record(FILE *fp, PEXCEPTION_RECORD record)
static bool bli_private_symbols_loaded()
static std::string get_os_info()
static bool bli_windows_system_backtrace_stack(FILE *fp, const EXCEPTION_POINTERS *exception_info)
void BLI_windows_exception_show_dialog(const char *filepath_crashlog, const char *filepath_relaunch, const char *gpu_name, const char *build_version)
static void bli_windows_system_backtrace_threads(FILE *fp)
static void bli_load_symbols()
void BLI_system_backtrace_with_os_info(FILE *fp, const void *os_info)
static bool BLI_windows_system_backtrace_run_trace(FILE *fp, HANDLE hThread, PCONTEXT context)
static const char * bli_windows_get_exception_description(const DWORD exceptioncode)
static bool bli_executable_path_get(LPWSTR path, DWORD size)
bool url_encode(const char *str, char *dst, size_t dst_size)
Encodes a string into URL format by converting special characters into percent-encoded sequences.
wchar_t * alloc_utf16_from_8(const char *in8, size_t add)
Definition utfconv.cc:292
uint len