Merge branch 'master' into jgrpp
# Conflicts: # cmake/CompileFlags.cmake # src/crashlog.cpp # src/crashlog.h # src/date_type.h # src/depot_type.h # src/landscape.cpp # src/openttd.cpp # src/order_cmd.cpp # src/order_gui.cpp # src/os/macosx/crashlog_osx.cpp # src/os/unix/crashlog_unix.cpp # src/os/windows/crashlog_win.cpp # src/pathfinder/npf/npf.cpp # src/road_cmd.cpp # src/script/api/script_infrastructure.cpp # src/stdafx.h # src/table/settings/gui_settings.ini # src/table/settings/pathfinding_settings.ini # src/tests/CMakeLists.txt
This commit is contained in:
		| @@ -26,6 +26,7 @@ | ||||
| #include <dlfcn.h> | ||||
| #include <cxxabi.h> | ||||
| #include <sys/mman.h> | ||||
| #include <execinfo.h> | ||||
| #ifdef WITH_UCONTEXT | ||||
| #include <sys/ucontext.h> | ||||
| #endif | ||||
| @@ -186,77 +187,16 @@ class CrashLogOSX : public CrashLog { | ||||
|  | ||||
| 	char *LogStacktrace(char *buffer, const char *last) const override | ||||
| 	{ | ||||
| 		/* As backtrace() is only implemented in 10.5 or later, | ||||
| 		 * we're rolling our own here. Mostly based on | ||||
| 		 * http://stackoverflow.com/questions/289820/getting-the-current-stack-trace-on-mac-os-x | ||||
| 		 * and some details looked up in the Darwin sources. */ | ||||
| 		buffer += seprintf(buffer, last, "\nStacktrace:\n"); | ||||
|  | ||||
| 		void **frame; | ||||
| 		int i = 0; | ||||
| 		void *trace[64]; | ||||
| 		int trace_size = backtrace(trace, lengthof(trace)); | ||||
|  | ||||
| 		auto print_frame = [&](void *ip) { | ||||
| 			/* Print running index. */ | ||||
| 			buffer += seprintf(buffer, last, " [%02d]", i); | ||||
|  | ||||
| 			Dl_info dli; | ||||
| 			bool dl_valid = dladdr(ip, &dli) != 0; | ||||
|  | ||||
| 			const char *fname = "???"; | ||||
| 			if (dl_valid && dli.dli_fname) { | ||||
| 				/* Valid image name? Extract filename from the complete path. */ | ||||
| 				const char *s = strrchr(dli.dli_fname, '/'); | ||||
| 				if (s != nullptr) { | ||||
| 					fname = s + 1; | ||||
| 				} else { | ||||
| 					fname = dli.dli_fname; | ||||
| 				} | ||||
| 			} | ||||
| 			/* Print image name and IP. */ | ||||
| 			buffer += seprintf(buffer, last, " %-20s " PRINTF_PTR, fname, (uintptr_t)ip); | ||||
|  | ||||
| 			/* Print function offset if information is available. */ | ||||
| 			if (dl_valid && dli.dli_sname != nullptr && dli.dli_saddr != nullptr) { | ||||
| 				/* Try to demangle a possible C++ symbol. */ | ||||
| 				int status = -1; | ||||
| 				char *func_name = abi::__cxa_demangle(dli.dli_sname, nullptr, 0, &status); | ||||
|  | ||||
| 				long int offset = (intptr_t)ip - (intptr_t)dli.dli_saddr; | ||||
| 				buffer += seprintf(buffer, last, " (%s + %ld)", func_name != nullptr ? func_name : dli.dli_sname, offset); | ||||
|  | ||||
| 				free(func_name); | ||||
| 			} | ||||
| 			buffer += seprintf(buffer, last, "\n"); | ||||
| 		}; | ||||
|  | ||||
| #if defined(__ppc__) || defined(__ppc64__) | ||||
| 		/* Apple says __builtin_frame_address can be broken on PPC. */ | ||||
| 		__asm__ volatile("mr %0, r1" : "=r" (frame)); | ||||
| #else | ||||
| 		frame = (void **)__builtin_frame_address(0); | ||||
| #endif | ||||
|  | ||||
| 		for (; frame != nullptr && i < MAX_STACK_FRAMES; i++) { | ||||
| 			auto guard = scope_guard([&]() { | ||||
| 				this->CrashLogFaultSectionCheckpoint(buffer); | ||||
| 			}); | ||||
|  | ||||
| 			/* Get IP for current stack frame. */ | ||||
| #if defined(__ppc__) || defined(__ppc64__) | ||||
| 			void *ip = frame[2]; | ||||
| #else | ||||
| 			void *ip = frame[1]; | ||||
| #endif | ||||
| 			if (ip == nullptr) break; | ||||
|  | ||||
| 			print_frame(ip); | ||||
|  | ||||
| 			/* Get address of next stack frame. */ | ||||
| 			void **next = (void **)frame[0]; | ||||
| 			/* Frame address not increasing or not aligned? Broken stack, exit! */ | ||||
| 			if (next <= frame || !IS_ALIGNED(next)) break; | ||||
| 			frame = next; | ||||
| 		char **messages = backtrace_symbols(trace, trace_size); | ||||
| 		for (int i = 0; i < trace_size; i++) { | ||||
| 			buffer += seprintf(buffer, last, "%s\n", messages[i]); | ||||
| 		} | ||||
| 		free(messages); | ||||
|  | ||||
| 		return buffer + seprintf(buffer, last, "\n"); | ||||
| 	} | ||||
|   | ||||
| @@ -48,10 +48,7 @@ | ||||
| #if defined(WITH_BFD) | ||||
| #   include <bfd.h> | ||||
| #endif | ||||
| #elif defined(SUNOS) | ||||
| #	include <ucontext.h> | ||||
| #	include <dlfcn.h> | ||||
| #endif | ||||
| #endif /* __GLIBC__ */ | ||||
|  | ||||
| #if defined(__NetBSD__) | ||||
| #include <unistd.h> | ||||
| @@ -363,39 +360,6 @@ class CrashLogUnix : public CrashLog { | ||||
| 		return buffer; | ||||
| 	} | ||||
|  | ||||
| #if defined(SUNOS) | ||||
| 	/** Data needed while walking up the stack */ | ||||
| 	struct StackWalkerParams { | ||||
| 		char **bufptr;    ///< Buffer | ||||
| 		const char *last; ///< End of buffer | ||||
| 		int counter;      ///< We are at counter-th stack level | ||||
| 	}; | ||||
|  | ||||
| 	/** | ||||
| 	 * Callback used while walking up the stack. | ||||
| 	 * @param pc program counter | ||||
| 	 * @param sig 'active' signal (unused) | ||||
| 	 * @param params parameters | ||||
| 	 * @return always 0, continue walking up the stack | ||||
| 	 */ | ||||
| 	static int SunOSStackWalker(uintptr_t pc, int sig, void *params) | ||||
| 	{ | ||||
| 		StackWalkerParams *wp = (StackWalkerParams *)params; | ||||
|  | ||||
| 		/* Resolve program counter to file and nearest symbol (if possible) */ | ||||
| 		Dl_info dli; | ||||
| 		if (dladdr((void *)pc, &dli) != 0) { | ||||
| 			*wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] %s(%s+0x%x) [0x%x]\n", | ||||
| 					wp->counter, dli.dli_fname, dli.dli_sname, (int)((byte *)pc - (byte *)dli.dli_saddr), (uint)pc); | ||||
| 		} else { | ||||
| 			*wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] [0x%x]\n", wp->counter, (uint)pc); | ||||
| 		} | ||||
| 		wp->counter++; | ||||
|  | ||||
| 		return 0; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	/** | ||||
| 	 * Log GDB information if available | ||||
| 	 */ | ||||
| @@ -663,17 +627,6 @@ class CrashLogUnix : public CrashLog { | ||||
| 		free(messages); | ||||
|  | ||||
| /* end of __GLIBC__ */ | ||||
| #elif defined(SUNOS) | ||||
| 		ucontext_t uc; | ||||
| 		if (getcontext(&uc) != 0) { | ||||
| 			buffer += seprintf(buffer, last, " getcontext() failed\n\n"); | ||||
| 			return buffer; | ||||
| 		} | ||||
|  | ||||
| 		StackWalkerParams wp = { &buffer, last, 0 }; | ||||
| 		walkcontext(&uc, &CrashLogUnix::SunOSStackWalker, &wp); | ||||
|  | ||||
| /* end of SUNOS */ | ||||
| #else | ||||
| 		buffer += seprintf(buffer, last, " Not supported.\n"); | ||||
| #endif | ||||
|   | ||||
| @@ -71,9 +71,10 @@ class CrashLogWindows : public CrashLog { | ||||
|  | ||||
| 	char *LogOSVersion(char *buffer, const char *last) const override; | ||||
| 	char *LogError(char *buffer, const char *last, const char *message) const override; | ||||
| #if defined(_MSC_VER) || defined(WITH_DBGHELP) | ||||
| 	char *LogStacktrace(char *buffer, const char *last) const override; | ||||
| #endif /* _MSC_VER || WITH_DBGHELP */ | ||||
| 	char *LogRegisters(char *buffer, const char *last) const override; | ||||
| 	char *LogModules(char *buffer, const char *last) const override; | ||||
|  | ||||
| protected: | ||||
| 	char *TryCrashLogFaultSection(char *buffer, const char *last, const char *section_name, CrashLogSectionWriter writer) override; | ||||
| @@ -83,19 +84,9 @@ public: | ||||
| #if defined(_MSC_VER) | ||||
| 	int WriteCrashDump(char *filename, const char *filename_last) const override; | ||||
| #endif /* _MSC_VER */ | ||||
| #if defined(_MSC_VER) || defined(WITH_DBGHELP) | ||||
| 	char *AppendDecodedStacktrace(char *buffer, const char *last) const; | ||||
| #endif /* _MSC_VER || WITH_DBGHELP */ | ||||
|  | ||||
|  | ||||
| 	/** Buffer for the generated crash log */ | ||||
| 	char crashlog[65536 * 4]; | ||||
| 	/** Buffer for the filename of the crash log */ | ||||
| 	char crashlog_filename[MAX_PATH]; | ||||
| 	/** Buffer for the filename of the crash dump */ | ||||
| 	char crashdump_filename[MAX_PATH]; | ||||
| 	/** Buffer for the filename of the crash screenshot */ | ||||
| 	char screenshot_filename[MAX_PATH]; | ||||
|  | ||||
| 	/** | ||||
| 	 * A crash log is always generated when it's generated. | ||||
| @@ -220,114 +211,6 @@ static const char *GetAccessViolationTypeString(uint type) | ||||
| 	return buffer; | ||||
| } | ||||
|  | ||||
| struct DebugFileInfo { | ||||
| 	uint32 size; | ||||
| 	uint32 crc32; | ||||
| 	SYSTEMTIME file_time; | ||||
| }; | ||||
|  | ||||
| static uint32 *_crc_table; | ||||
|  | ||||
| static void MakeCRCTable(uint32 *table) | ||||
| { | ||||
| 	uint32 crc, poly = 0xEDB88320L; | ||||
| 	int i; | ||||
| 	int j; | ||||
|  | ||||
| 	_crc_table = table; | ||||
|  | ||||
| 	for (i = 0; i != 256; i++) { | ||||
| 		crc = i; | ||||
| 		for (j = 8; j != 0; j--) { | ||||
| 			crc = (crc & 1 ? (crc >> 1) ^ poly : crc >> 1); | ||||
| 		} | ||||
| 		table[i] = crc; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static uint32 CalcCRC(byte *data, uint size, uint32 crc) | ||||
| { | ||||
| 	for (; size > 0; size--) { | ||||
| 		crc = ((crc >> 8) & 0x00FFFFFF) ^ _crc_table[(crc ^ *data++) & 0xFF]; | ||||
| 	} | ||||
| 	return crc; | ||||
| } | ||||
|  | ||||
| static void GetFileInfo(DebugFileInfo *dfi, const wchar_t *filename) | ||||
| { | ||||
| 	HANDLE file; | ||||
| 	memset(dfi, 0, sizeof(*dfi)); | ||||
|  | ||||
| 	file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0); | ||||
| 	if (file != INVALID_HANDLE_VALUE) { | ||||
| 		byte buffer[1024]; | ||||
| 		DWORD numread; | ||||
| 		uint32 filesize = 0; | ||||
| 		FILETIME write_time; | ||||
| 		uint32 crc = (uint32)-1; | ||||
|  | ||||
| 		for (;;) { | ||||
| 			if (ReadFile(file, buffer, sizeof(buffer), &numread, nullptr) == 0 || numread == 0) { | ||||
| 				break; | ||||
| 			} | ||||
| 			filesize += numread; | ||||
| 			crc = CalcCRC(buffer, numread, crc); | ||||
| 		} | ||||
| 		dfi->size = filesize; | ||||
| 		dfi->crc32 = crc ^ (uint32)-1; | ||||
|  | ||||
| 		if (GetFileTime(file, nullptr, nullptr, &write_time)) { | ||||
| 			FileTimeToSystemTime(&write_time, &dfi->file_time); | ||||
| 		} | ||||
| 		CloseHandle(file); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) | ||||
| { | ||||
| 	wchar_t buffer[MAX_PATH]; | ||||
| 	DebugFileInfo dfi; | ||||
|  | ||||
| 	GetModuleFileName(mod, buffer, MAX_PATH); | ||||
| 	GetFileInfo(&dfi, buffer); | ||||
| 	output += seprintf(output, last, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\n", | ||||
| 		FS2OTTD(buffer).c_str(), | ||||
| 		mod, | ||||
| 		dfi.size, | ||||
| 		dfi.crc32, | ||||
| 		dfi.file_time.wYear, | ||||
| 		dfi.file_time.wMonth, | ||||
| 		dfi.file_time.wDay, | ||||
| 		dfi.file_time.wHour, | ||||
| 		dfi.file_time.wMinute, | ||||
| 		dfi.file_time.wSecond | ||||
| 	); | ||||
| 	return output; | ||||
| } | ||||
|  | ||||
| /* virtual */ char *CrashLogWindows::LogModules(char *output, const char *last) const | ||||
| { | ||||
| 	MakeCRCTable(AllocaM(uint32, 256)); | ||||
| 	output += seprintf(output, last, "Module information:\n"); | ||||
|  | ||||
| 	HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); | ||||
| 	if (proc != nullptr) { | ||||
| 		HMODULE modules[100]; | ||||
| 		DWORD needed; | ||||
| 		BOOL res = EnumProcessModules(proc, modules, sizeof(modules), &needed); | ||||
| 		CloseHandle(proc); | ||||
| 		if (res) { | ||||
| 			size_t count = std::min<DWORD>(needed / sizeof(HMODULE), lengthof(modules)); | ||||
|  | ||||
| 			for (size_t i = 0; i != count; i++) output = PrintModuleInfo(output, last, modules[i]); | ||||
| 			return output + seprintf(output, last, "\n"); | ||||
| 		} | ||||
| 	} | ||||
| 	output = PrintModuleInfo(output, last, nullptr); | ||||
| 	return output + seprintf(output, last, "\n"); | ||||
| } | ||||
|  | ||||
| /* virtual */ char *CrashLogWindows::LogRegisters(char *buffer, const char *last) const | ||||
| { | ||||
| 	buffer += seprintf(buffer, last, "Registers:\n"); | ||||
| @@ -438,40 +321,6 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) | ||||
| 	return buffer + seprintf(buffer, last, "\n\n"); | ||||
| } | ||||
|  | ||||
| /* virtual */ char *CrashLogWindows::LogStacktrace(char *buffer, const char *last) const | ||||
| { | ||||
| #if defined(_MSC_VER) || defined(WITH_DBGHELP) | ||||
| 	char *stacktrace_end = this->AppendDecodedStacktrace(buffer, last); | ||||
| 	if (stacktrace_end - buffer >= 32) { | ||||
| 		/* If AppendDecodedStacktrace managed to write out anything more than just the section title, | ||||
| 		 * consider that a success and don't bother writing out the raw stack trace values as well. | ||||
| 		 * The raw values are useless in almost all cases. */ | ||||
| 		return stacktrace_end; | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	buffer += seprintf(buffer, last, "Stack trace:\n"); | ||||
| #ifdef _M_AMD64 | ||||
| 	uint32 *b = (uint32*)ep->ContextRecord->Rsp; | ||||
| #elif defined(_M_IX86) | ||||
| 	uint32 *b = (uint32*)ep->ContextRecord->Esp; | ||||
| #elif defined(_M_ARM64) | ||||
| 	uint32 *b = (uint32*)ep->ContextRecord->Sp; | ||||
| #endif | ||||
| 	for (int j = 0; j != 24; j++) { | ||||
| 		for (int i = 0; i != 8; i++) { | ||||
| 			if (IsBadReadPtr(b, sizeof(uint32))) { | ||||
| 				buffer += seprintf(buffer, last, " ????????"); // OCR: WAS - , 0); | ||||
| 			} else { | ||||
| 				buffer += seprintf(buffer, last, " %.8X", *b); | ||||
| 			} | ||||
| 			b++; | ||||
| 		} | ||||
| 		buffer += seprintf(buffer, last, "\n"); | ||||
| 	} | ||||
| 	return buffer + seprintf(buffer, last, "\n"); | ||||
| } | ||||
|  | ||||
| #if defined(_MSC_VER) || defined(WITH_DBGHELP) | ||||
| static const uint MAX_SYMBOL_LEN = 512; | ||||
| static const uint MAX_FRAMES     = 64; | ||||
| @@ -483,7 +332,7 @@ static const uint MAX_FRAMES     = 64; | ||||
| #pragma warning(default:4091) | ||||
| #endif | ||||
|  | ||||
| char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) const | ||||
| /* virtual */ char *CrashLogWindows::LogStacktrace(char *buffer, const char *last) const | ||||
| { | ||||
| #define M(x) x "\0" | ||||
| 	static const char dbg_import[] = | ||||
| @@ -796,8 +645,6 @@ thread_local void *_safe_esp = nullptr; | ||||
|  | ||||
| static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) | ||||
| { | ||||
| 	CrashLog::RegisterCrashed(); | ||||
|  | ||||
| 	/* Restore system timer resolution. */ | ||||
| 	timeEndPeriod(1); | ||||
|  | ||||
| @@ -818,22 +665,9 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) | ||||
| 		ImmediateExitProcess(3); | ||||
| 	} | ||||
|  | ||||
| 	VideoDriver::EmergencyAcquireGameLock(1000, 5); | ||||
|  | ||||
| 	CrashLogWindows *log = new CrashLogWindows(ep); | ||||
| 	CrashLogWindows::current = log; | ||||
| 	char *name_buffer_date = log->name_buffer + seprintf(log->name_buffer, lastof(log->name_buffer), "crash-"); | ||||
| 	UTCTime::Format(name_buffer_date, lastof(log->name_buffer), "%Y%m%dT%H%M%SZ"); | ||||
|  | ||||
| 	log->WriteCrashLog("", log->crashlog_filename, lastof(log->crashlog_filename), log->name_buffer, &(log->crash_file)); | ||||
| 	log->crash_buffer_write = log->crashlog; | ||||
| 	log->FillCrashLog(log->crashlog, lastof(log->crashlog)); | ||||
| 	log->CloseCrashLogFile(); | ||||
|  | ||||
| 	log->WriteCrashDump(log->crashdump_filename, lastof(log->crashdump_filename)); | ||||
| 	SetScreenshotAuxiliaryText("Crash Log", log->crashlog); | ||||
| 	log->WriteScreenshot(log->screenshot_filename, lastof(log->screenshot_filename), log->name_buffer); | ||||
| 	log->SendSurvey(); | ||||
| 	log->MakeCrashLog(log->crashlog, lastof(log->crashlog)); | ||||
|  | ||||
| 	/* Close any possible log files */ | ||||
| 	CloseConsoleLogIfActive(); | ||||
| @@ -973,13 +807,7 @@ static const TCHAR _crash_desc[] = | ||||
| 	L"Please send the crash information (log files and crash saves, if any) to the patchpack developer.\n" | ||||
| 	L"This will greatly help debugging. The correct place to do this is https://www.tt-forums.net/viewtopic.php?f=33&t=73469" | ||||
| 	L" or https://github.com/JGRennison/OpenTTD-patches\n" | ||||
| 	L"The information contained in the report is displayed below.\n" | ||||
| 	L"Press \"Emergency save\" to attempt saving the game. Generated file(s):\n"; | ||||
|  | ||||
| static const wchar_t _save_succeeded[] = | ||||
| 	L"Emergency save succeeded.\nIts location is '%s'.\n" | ||||
| 	L"Be aware that critical parts of the internal game state may have become " | ||||
| 	L"corrupted. The saved game is not guaranteed to work."; | ||||
| 	L"The information contained in the report is displayed below.\n"; | ||||
|  | ||||
| static const wchar_t * const _expand_texts[] = {L"S&how report >>", L"&Hide report <<" }; | ||||
|  | ||||
| @@ -1041,7 +869,7 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA | ||||
| 			} | ||||
| 			*p = '\0'; | ||||
|  | ||||
| 			/* Add path to crash.log and crash.dmp (if any) to the crash window text */ | ||||
| 			/* Add path to all files to the crash window text */ | ||||
| 			const wchar_t * const crash_desc_buf_last = crash_desc_buf + crash_desc_buf_length - 1; | ||||
| 			wcsncpy_s(crash_desc_buf, crash_desc_buf_length, _crash_desc, _TRUNCATE); | ||||
| 			wchar_t *desc = crash_desc_buf + wcslen(crash_desc_buf); | ||||
| @@ -1063,6 +891,10 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA | ||||
| 				append_newline(); | ||||
| 				append_str(CrashLogWindows::current->crashdump_filename); | ||||
| 			} | ||||
| 			if (CrashLogWindows::current->savegame_filename[0] != 0) { | ||||
| 				append_newline(); | ||||
| 				append_str(CrashLogWindows::current->savegame_filename); | ||||
| 			} | ||||
| 			if (CrashLogWindows::current->screenshot_filename[0] != 0) { | ||||
| 				append_newline(); | ||||
| 				append_str(CrashLogWindows::current->screenshot_filename); | ||||
| @@ -1078,23 +910,6 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA | ||||
| 				case 12: // Close | ||||
| 					CrashLog::AfterCrashLogCleanup(); | ||||
| 					ImmediateExitProcess(2); | ||||
| 				case 13: // Emergency save | ||||
| 					_savegame_DBGL_data = CrashLogWindows::current->crashlog; | ||||
| 					_save_DBGC_data = true; | ||||
| 					wchar_t filenamebuf[MAX_PATH * 2]; | ||||
| 					char filename[MAX_PATH]; | ||||
| 					if (CrashLogWindows::current->WriteSavegame(filename, lastof(filename), CrashLogWindows::current->name_buffer)) { | ||||
| 						convert_to_fs(filename, filenamebuf, lengthof(filenamebuf)); | ||||
| 						size_t len = lengthof(_save_succeeded) + wcslen(filenamebuf) + 1; | ||||
| 						wchar_t *text = AllocaM(wchar_t, len); | ||||
| 						_snwprintf(text, len, _save_succeeded, filenamebuf); | ||||
| 						MessageBox(wnd, text, L"Save successful", MB_ICONINFORMATION); | ||||
| 					} else { | ||||
| 						MessageBox(wnd, L"Save failed", L"Save failed", MB_ICONINFORMATION); | ||||
| 					} | ||||
| 					_savegame_DBGL_data = nullptr; | ||||
| 					_save_DBGC_data = false; | ||||
| 					break; | ||||
| 				case 15: // Expand window to show crash-message | ||||
| 					_expanded = !_expanded; | ||||
| 					SetWndSize(wnd, _expanded); | ||||
|   | ||||
| @@ -50,7 +50,6 @@ CAPTION "Fatal Application Failure" | ||||
| FONT 8, "MS Sans Serif" | ||||
| BEGIN | ||||
|     PUSHBUTTON      "&Close",12,7,82,60,14 | ||||
|     PUSHBUTTON      "&Emergency save",13,158,82,60,14 | ||||
|     PUSHBUTTON      "",15,238,82,60,14 | ||||
|     EDITTEXT        11,7,103,291,118,ES_MULTILINE | ES_READONLY | WS_VSCROLL | | ||||
|                     WS_HSCROLL | NOT WS_TABSTOP | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan G Rennison
					Jonathan G Rennison