diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj b/Dalamud.Boot/Dalamud.Boot.vcxproj
index 77783e269..2e0f19aca 100644
--- a/Dalamud.Boot/Dalamud.Boot.vcxproj
+++ b/Dalamud.Boot/Dalamud.Boot.vcxproj
@@ -33,10 +33,12 @@
- $(LibraryPath)
+ true
+ $(SolutionDir)bin\lib\$(Configuration)\libMinHook\;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)
- $(SolutionDir)bin\lib\$(Configuration)\libMinHook\;$(LibraryPath)
+ false
+ $(SolutionDir)bin\lib\$(Configuration)\libMinHook\;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)
@@ -53,7 +55,7 @@
Windows
true
false
- dbghelp.lib;Version.lib;%(AdditionalDependencies)
+ Version.lib;%(AdditionalDependencies)
..\lib\CoreCLR;%(AdditionalLibraryDirectories)
diff --git a/Dalamud.Boot/DalamudStartInfo.h b/Dalamud.Boot/DalamudStartInfo.h
index 4bd377811..ed9d5c4a3 100644
--- a/Dalamud.Boot/DalamudStartInfo.h
+++ b/Dalamud.Boot/DalamudStartInfo.h
@@ -8,6 +8,9 @@ struct DalamudStartInfo {
BeforeDalamudConstruct = 1 << 2,
};
friend void from_json(const nlohmann::json&, WaitMessageboxFlags&);
+ friend WaitMessageboxFlags operator &(WaitMessageboxFlags a, WaitMessageboxFlags b) {
+ return static_cast(static_cast(a) & static_cast(b));
+ }
enum class DotNetOpenProcessHookMode : int {
ImportHooks = 0,
diff --git a/Dalamud.Boot/crashhandler_shared.h b/Dalamud.Boot/crashhandler_shared.h
index 6b17bb11f..c4bd606c7 100644
--- a/Dalamud.Boot/crashhandler_shared.h
+++ b/Dalamud.Boot/crashhandler_shared.h
@@ -1,19 +1,18 @@
#pragma once
-#include "windows.h"
+#include
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+#include
struct exception_info
{
- void* ExceptionPointers; // Cannot dereference!
- DWORD ThreadId;
- DWORD ProcessId;
- BOOL DoFullDump;
- wchar_t DumpPath[1000];
-
- // For metrics
- DWORD ExceptionCode;
- long long Lifetime;
+ LPEXCEPTION_POINTERS pExceptionPointers;
+ EXCEPTION_POINTERS ExceptionPointers;
+ EXCEPTION_RECORD ExceptionRecord;
+ CONTEXT ContextRecord;
+ uint64_t nLifetime;
+ HANDLE hThreadHandle;
+ DWORD dwStackTraceLength;
};
-
-constexpr wchar_t SHARED_INFO_FILE_NAME[] = L"DalamudCrashInfoShare";
-constexpr wchar_t CRASHDUMP_EVENT_NAME[] = L"Global\\DalamudRequestWriteDump";
diff --git a/Dalamud.Boot/dllmain.cpp b/Dalamud.Boot/dllmain.cpp
index d5660e976..9a741a47f 100644
--- a/Dalamud.Boot/dllmain.cpp
+++ b/Dalamud.Boot/dllmain.cpp
@@ -87,7 +87,7 @@ DWORD WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
logging::I("Dalamud.Boot Injectable, (c) 2021 XIVLauncher Contributors");
logging::I("Built at: " __DATE__ "@" __TIME__);
- if (static_cast(g_startInfo.BootWaitMessageBox) & static_cast(DalamudStartInfo::WaitMessageboxFlags::BeforeInitialize))
+ if ((g_startInfo.BootWaitMessageBox & DalamudStartInfo::WaitMessageboxFlags::BeforeInitialize) != DalamudStartInfo::WaitMessageboxFlags::None)
MessageBoxW(nullptr, L"Press OK to continue (BeforeInitialize)", L"Dalamud Boot", MB_OK);
if (minHookLoaded) {
diff --git a/Dalamud.Boot/pch.h b/Dalamud.Boot/pch.h
index bbd4b3d73..4cb2d7945 100644
--- a/Dalamud.Boot/pch.h
+++ b/Dalamud.Boot/pch.h
@@ -11,15 +11,16 @@
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
-// Windows Header Files
-#include
-#include
+// Windows Header Files (1)
+#include
+
+// Windows Header Files (2)
+#include
#include
#include
-#include
-#include
-#include
+#include
#include
+#include
// MSVC Compiler Intrinsic
#include
@@ -33,11 +34,11 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#include
#include
// https://www.akenotsuki.com/misc/srell/en/
@@ -50,8 +51,8 @@
#include "../lib/Nomade040-nmd/nmd_assembly.h"
// https://github.com/dotnet/coreclr
-#include "../lib/CoreCLR/CoreCLR.h"
#include "../lib/CoreCLR/boot.h"
+#include "../lib/CoreCLR/CoreCLR.h"
// https://github.com/nlohmann/json
#include "../lib/nlohmann-json/json.hpp"
diff --git a/Dalamud.Boot/utils.cpp b/Dalamud.Boot/utils.cpp
index f51ef7e49..e06e812ef 100644
--- a/Dalamud.Boot/utils.cpp
+++ b/Dalamud.Boot/utils.cpp
@@ -520,3 +520,36 @@ void utils::wait_for_game_window() {
};
SendMessageW(game_window, WM_NULL, 0, 0);
}
+
+std::wstring utils::escape_shell_arg(const std::wstring& arg) {
+ // https://docs.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way
+
+ std::wstring res;
+ if (!arg.empty() && arg.find_first_of(L" \t\n\v\"") == std::wstring::npos) {
+ res.append(arg);
+ } else {
+ res.push_back(L'"');
+ for (auto it = arg.begin(); ; ++it) {
+ size_t bsCount = 0;
+
+ while (it != arg.end() && *it == L'\\') {
+ ++it;
+ ++bsCount;
+ }
+
+ if (it == arg.end()) {
+ res.append(bsCount * 2, L'\\');
+ break;
+ } else if (*it == L'"') {
+ res.append(bsCount * 2 + 1, L'\\');
+ res.push_back(*it);
+ } else {
+ res.append(bsCount, L'\\');
+ res.push_back(*it);
+ }
+ }
+
+ res.push_back(L'"');
+ }
+ return res;
+}
diff --git a/Dalamud.Boot/utils.h b/Dalamud.Boot/utils.h
index bbcba1f84..ca350674a 100644
--- a/Dalamud.Boot/utils.h
+++ b/Dalamud.Boot/utils.h
@@ -260,4 +260,6 @@ namespace utils {
HWND try_find_game_window();
void wait_for_game_window();
+
+ std::wstring escape_shell_arg(const std::wstring& arg);
}
diff --git a/Dalamud.Boot/veh.cpp b/Dalamud.Boot/veh.cpp
index 890c7ab0d..bb3f37869 100644
--- a/Dalamud.Boot/veh.cpp
+++ b/Dalamud.Boot/veh.cpp
@@ -1,7 +1,5 @@
#include "pch.h"
-#include "resource.h"
-
#include "veh.h"
#include
@@ -10,6 +8,7 @@
#include "utils.h"
#include "crashhandler_shared.h"
+#include "DalamudStartInfo.h"
#pragma comment(lib, "comctl32.lib")
@@ -25,9 +24,8 @@
PVOID g_veh_handle = nullptr;
bool g_veh_do_full_dump = false;
-
-exception_info* g_crashhandler_shared_info;
-HANDLE g_crashhandler_event;
+HANDLE g_crashhandler_process = nullptr;
+HANDLE g_crashhandler_pipe_write = nullptr;
std::chrono::time_point g_time_start;
@@ -73,7 +71,6 @@ bool is_whitelist_exception(const DWORD code)
}
}
-
bool get_module_file_and_base(const DWORD64 address, DWORD64& module_base, std::filesystem::path& module_file)
{
HMODULE handle;
@@ -91,7 +88,6 @@ bool get_module_file_and_base(const DWORD64 address, DWORD64& module_base, std::
return false;
}
-
bool is_ffxiv_address(const wchar_t* module_name, const DWORD64 address)
{
DWORD64 module_base;
@@ -100,369 +96,223 @@ bool is_ffxiv_address(const wchar_t* module_name, const DWORD64 address)
return false;
}
-
-bool get_sym_from_addr(const DWORD64 address, DWORD64& displacement, std::wstring& symbol_name)
+static void append_injector_launch_args(std::vector& args)
{
- union {
- char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(wchar_t)]{};
- SYMBOL_INFOW symbol;
- };
- symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
- symbol.MaxNameLen = MAX_SYM_NAME;
+ args.emplace_back(L"-g");
+ args.emplace_back(utils::loaded_module::current_process().path().wstring());
+ if (g_startInfo.BootShowConsole)
+ args.emplace_back(L"--console");
+ if (g_startInfo.BootEnableEtw)
+ args.emplace_back(L"--etw");
+ if (g_startInfo.BootVehEnabled)
+ args.emplace_back(L"--veh");
+ if (g_startInfo.BootVehFull)
+ args.emplace_back(L"--veh-full");
+ if ((g_startInfo.BootWaitMessageBox & DalamudStartInfo::WaitMessageboxFlags::BeforeInitialize) != DalamudStartInfo::WaitMessageboxFlags::None)
+ args.emplace_back(L"--msgbox1");
+ if ((g_startInfo.BootWaitMessageBox & DalamudStartInfo::WaitMessageboxFlags::BeforeDalamudEntrypoint) != DalamudStartInfo::WaitMessageboxFlags::None)
+ args.emplace_back(L"--msgbox2");
+ if ((g_startInfo.BootWaitMessageBox & DalamudStartInfo::WaitMessageboxFlags::BeforeDalamudConstruct) != DalamudStartInfo::WaitMessageboxFlags::None)
+ args.emplace_back(L"--msgbox3");
- if (SymFromAddrW(GetCurrentProcess(), address, &displacement, &symbol) && symbol.Name[0])
- {
- symbol_name = symbol.Name;
- return true;
+ args.emplace_back(L"--");
+
+ if (int nArgs; LPWSTR * szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs)) {
+ for (auto i = 1; i < nArgs; i++)
+ args.emplace_back(szArgList[i]);
+ LocalFree(szArgList);
}
- return false;
-}
-
-
-std::wstring to_address_string(const DWORD64 address, const bool try_ptrderef = true)
-{
- DWORD64 module_base;
- std::filesystem::path module_path;
- bool is_mod_addr = get_module_file_and_base(address, module_base, module_path);
-
- DWORD64 value = 0;
- if(try_ptrderef && address > 0x10000 && address < 0x7FFFFFFE0000)
- {
- ReadProcessMemory(GetCurrentProcess(), reinterpret_cast(address), &value, sizeof value, nullptr);
- }
-
- std::wstring addr_str = is_mod_addr ?
- std::format(L"{}+{:X}", module_path.filename().c_str(), address - module_base) :
- std::format(L"{:X}", address);
-
- DWORD64 displacement;
- if (std::wstring symbol; get_sym_from_addr(address, displacement, symbol))
- return std::format(L"{}\t({})", addr_str, displacement != 0 ? std::format(L"{}+0x{:X}", symbol, displacement) : std::format(L"{}", symbol));
- return value != 0 ? std::format(L"{} [{}]", addr_str, to_address_string(value, false)) : addr_str;
-}
-
-void print_exception_info_extended(const EXCEPTION_POINTERS* ex, std::wostringstream& log)
-{
- CONTEXT ctx = *ex->ContextRecord;
-
- log << L"\nRegisters\n{";
-
- log << std::format(L"\n RAX:\t{}", to_address_string(ctx.Rax));
- log << std::format(L"\n RBX:\t{}", to_address_string(ctx.Rbx));
- log << std::format(L"\n RCX:\t{}", to_address_string(ctx.Rcx));
- log << std::format(L"\n RDX:\t{}", to_address_string(ctx.Rdx));
- log << std::format(L"\n R8:\t{}", to_address_string(ctx.R8));
- log << std::format(L"\n R9:\t{}", to_address_string(ctx.R9));
- log << std::format(L"\n R10:\t{}", to_address_string(ctx.R10));
- log << std::format(L"\n R11:\t{}", to_address_string(ctx.R11));
- log << std::format(L"\n R12:\t{}", to_address_string(ctx.R12));
- log << std::format(L"\n R13:\t{}", to_address_string(ctx.R13));
- log << std::format(L"\n R14:\t{}", to_address_string(ctx.R14));
- log << std::format(L"\n R15:\t{}", to_address_string(ctx.R15));
-
- log << std::format(L"\n RSI:\t{}", to_address_string(ctx.Rsi));
- log << std::format(L"\n RDI:\t{}", to_address_string(ctx.Rdi));
- log << std::format(L"\n RBP:\t{}", to_address_string(ctx.Rbp));
- log << std::format(L"\n RSP:\t{}", to_address_string(ctx.Rsp));
- log << std::format(L"\n RIP:\t{}", to_address_string(ctx.Rip));
-
- log << L"\n}" << std::endl;
-
- if(0x10000 < ctx.Rsp && ctx.Rsp < 0x7FFFFFFE0000)
- {
- log << L"\nStack\n{";
-
- for(DWORD64 i = 0; i < 16; i++)
- log << std::format(L"\n [RSP+{:X}]\t{}", i * 8, to_address_string(*reinterpret_cast(ctx.Rsp + i * 8ull)));
-
- log << L"\n}\n";
- }
-
- log << L"\nModules\n{";
-
- if(HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, GetCurrentProcessId()); snap != INVALID_HANDLE_VALUE)
- {
- MODULEENTRY32 mod;
- mod.dwSize = sizeof MODULEENTRY32;
- if(Module32First(snap, &mod))
- {
- do
- {
- log << std::format(L"\n {:08X}\t{}", reinterpret_cast(mod.modBaseAddr), mod.szExePath);
- }
- while (Module32Next(snap, &mod));
- }
- CloseHandle(snap);
- }
-
- log << L"\n}\n";
-}
-
-void print_exception_info(const EXCEPTION_POINTERS* ex, std::wostringstream& log)
-{
- size_t rec_index = 0;
- for (auto rec = ex->ExceptionRecord; rec; rec = rec->ExceptionRecord)
- {
- log << std::format(L"\nException Info #{}\n", ++rec_index);
- log << std::format(L"Address: {:X}\n", rec->ExceptionCode);
- log << std::format(L"Flags: {:X}\n", rec->ExceptionFlags);
- log << std::format(L"Address: {:X}\n", reinterpret_cast(rec->ExceptionAddress));
- if (!rec->NumberParameters)
- continue;
- log << L"Parameters: ";
- for (DWORD i = 0; i < rec->NumberParameters; ++i)
- {
- if (i != 0)
- log << L", ";
- log << std::format(L"{:X}", rec->ExceptionInformation[i]);
- }
- }
-
- log << L"\nCall Stack\n{";
-
- STACKFRAME64 sf;
- sf.AddrPC.Offset = ex->ContextRecord->Rip;
- sf.AddrPC.Mode = AddrModeFlat;
- sf.AddrStack.Offset = ex->ContextRecord->Rsp;
- sf.AddrStack.Mode = AddrModeFlat;
- sf.AddrFrame.Offset = ex->ContextRecord->Rbp;
- sf.AddrFrame.Mode = AddrModeFlat;
- CONTEXT ctx = *ex->ContextRecord;
- int frame_index = 0;
-
- log << std::format(L"\n [{}]\t{}", frame_index++, to_address_string(sf.AddrPC.Offset, false));
-
- do
- {
- if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, GetCurrentProcess(), GetCurrentThread(), &sf, &ctx, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
- break;
-
- log << std::format(L"\n [{}]\t{}", frame_index++, to_address_string(sf.AddrPC.Offset, false));
-
- } while (sf.AddrReturn.Offset != 0 && sf.AddrPC.Offset != sf.AddrReturn.Offset);
-
- log << L"\n}\n";
-}
-
-HRESULT CALLBACK TaskDialogCallbackProc(HWND hwnd,
- UINT uNotification,
- WPARAM wParam,
- LPARAM lParam,
- LONG_PTR dwRefData)
-{
- HRESULT hr = S_OK;
-
- switch (uNotification)
- {
- case TDN_CREATED:
- SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
- break;
- }
-
- return hr;
}
LONG exception_handler(EXCEPTION_POINTERS* ex)
{
static std::recursive_mutex s_exception_handler_mutex;
- if (!is_whitelist_exception(ex->ExceptionRecord->ExceptionCode))
- return EXCEPTION_CONTINUE_SEARCH;
+ if (ex->ExceptionRecord->ExceptionCode == 0x12345678)
+ {
+ // pass
+ }
+ else
+ {
+ if (!is_whitelist_exception(ex->ExceptionRecord->ExceptionCode))
+ return EXCEPTION_CONTINUE_SEARCH;
- if (!is_ffxiv_address(L"ffxiv_dx11.exe", ex->ContextRecord->Rip) &&
- !is_ffxiv_address(L"cimgui.dll", ex->ContextRecord->Rip))
- return EXCEPTION_CONTINUE_SEARCH;
+ if (!is_ffxiv_address(L"ffxiv_dx11.exe", ex->ContextRecord->Rip) &&
+ !is_ffxiv_address(L"cimgui.dll", ex->ContextRecord->Rip))
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
// block any other exceptions hitting the veh while the messagebox is open
const auto lock = std::lock_guard(s_exception_handler_mutex);
- const auto module_path = utils::loaded_module(g_hModule).path().parent_path();
-#ifndef NDEBUG
- const auto dmp_path = (module_path / L"dalamud_appcrashd.dmp").wstring();
-#else
- const auto dmp_path = (module_path / L"dalamud_appcrash.dmp").wstring();
-#endif
- const auto log_path = (module_path / L"dalamud_appcrash.log").wstring();
+ exception_info exinfo{};
+ exinfo.pExceptionPointers = ex;
+ exinfo.ExceptionPointers = *ex;
+ exinfo.ContextRecord = *ex->ContextRecord;
+ exinfo.ExceptionRecord = ex->ExceptionRecord ? *ex->ExceptionRecord : EXCEPTION_RECORD{};
+ const auto time_now = std::chrono::system_clock::now();
+ auto lifetime = std::chrono::duration_cast(
+ time_now.time_since_epoch()).count()
+ - std::chrono::duration_cast(
+ g_time_start.time_since_epoch()).count();
+ exinfo.nLifetime = lifetime;
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), g_crashhandler_process, &exinfo.hThreadHandle, 0, TRUE, DUPLICATE_SAME_ACCESS);
- std::wostringstream log;
- log << std::format(L"Unhandled native exception occurred at {}", to_address_string(ex->ContextRecord->Rip, false)) << std::endl;
- log << std::format(L"Code: {:X}", ex->ExceptionRecord->ExceptionCode) << std::endl;
- log << std::format(L"Dump at: {}", dmp_path) << std::endl;
- log << L"Time: " << std::chrono::zoned_time{ std::chrono::current_zone(), std::chrono::system_clock::now() } << std::endl;
-
- SymRefreshModuleList(GetCurrentProcess());
- print_exception_info(ex, log);
- auto window_log_str = log.str();
- print_exception_info_extended(ex, log);
-
- if (g_crashhandler_shared_info && g_crashhandler_event)
- {
- memset(g_crashhandler_shared_info, 0, sizeof(exception_info));
-
- wcsncpy_s(g_crashhandler_shared_info->DumpPath, dmp_path.c_str(), 1000);
- g_crashhandler_shared_info->ThreadId = GetThreadId(GetCurrentThread());
- g_crashhandler_shared_info->ProcessId = GetCurrentProcessId();
- g_crashhandler_shared_info->ExceptionPointers = ex;
- g_crashhandler_shared_info->DoFullDump = g_veh_do_full_dump;
- g_crashhandler_shared_info->ExceptionCode = ex->ExceptionRecord->ExceptionCode;
-
- const auto time_now = std::chrono::system_clock::now();
- auto lifetime = std::chrono::duration_cast(
- time_now.time_since_epoch()).count()
- - std::chrono::duration_cast(
- g_time_start.time_since_epoch()).count();
-
- g_crashhandler_shared_info->Lifetime = lifetime;
-
- SetEvent(g_crashhandler_event);
- }
-
- std::wstring message;
- void* fn;
- if (const auto err = static_cast(g_clr->get_function_pointer(
+ std::wstring stackTrace;
+ if (void* fn; const auto err = static_cast(g_clr->get_function_pointer(
L"Dalamud.EntryPoint, Dalamud",
L"VehCallback",
L"Dalamud.EntryPoint+VehDelegate, Dalamud",
nullptr, nullptr, &fn)))
{
- message = std::format(
- L"An error within the game has occurred.\n\n"
- L"This may be caused by a faulty plugin, a broken TexTools modification, any other third-party tool or simply a bug in the game.\n"
- L"Please try \"Start Over\" or \"Download Index Backup\" in TexTools, an integrity check in the XIVLauncher settings, and disabling plugins you don't need.\n\n"
- L"The log file is located at:\n"
- L"{1}\n\n"
- L"Press OK to exit the application.\n\nFailed to read stack trace: 0x{2:08x}",
- dmp_path, log_path, err);
+ stackTrace = std::format(L"Failed to read stack trace: 0x{:08x}", err);
}
else
{
- const auto pMessage = ((wchar_t*(__stdcall*)(const void*, const void*, const void*))fn)(dmp_path.c_str(), log_path.c_str(), log.str().c_str());
- message = pMessage;
+ stackTrace = static_cast(fn)();
// Don't free it, as the program's going to be quit anyway
}
+
+ exinfo.dwStackTraceLength = static_cast(stackTrace.size());
+ if (DWORD written; !WriteFile(g_crashhandler_pipe_write, &exinfo, static_cast(sizeof exinfo), &written, nullptr) || sizeof exinfo != written)
+ return EXCEPTION_CONTINUE_SEARCH;
- logging::E(std::format(L"Trapped in VEH handler: {}", message));
-
- // show in another thread to prevent messagebox from pumping messages of current thread
- std::thread([&]()
- {
- int nButtonPressed = 0;
- TASKDIALOGCONFIG config = {0};
- const TASKDIALOG_BUTTON buttons[] = {
- {IDOK, L"Disable all plugins"},
- {IDABORT, L"Open help page"},
- };
- config.cbSize = sizeof(config);
- config.hInstance = g_hModule;
- config.dwCommonButtons = TDCBF_CLOSE_BUTTON;
- config.pszMainIcon = MAKEINTRESOURCE(IDI_ICON1);
- //config.hMainIcon = dalamud_icon;
- config.pszMainInstruction = L"An error occurred";
- config.pszContent = message.c_str();
- config.pButtons = buttons;
- config.cButtons = ARRAYSIZE(buttons);
- config.pszExpandedInformation = window_log_str.c_str();
- config.pszWindowTitle = L"Dalamud Error";
- config.nDefaultButton = IDCLOSE;
- config.cxWidth = 300;
-
- // Can't do this, xiv stops pumping messages here
- //config.hwndParent = FindWindowA("FFXIVGAME", NULL);
-
- config.pfCallback = TaskDialogCallbackProc;
-
- TaskDialogIndirect(&config, &nButtonPressed, NULL, NULL);
- switch (nButtonPressed)
- {
- case IDOK:
- TCHAR szPath[MAX_PATH];
- if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, szPath)))
- {
- auto appdata = std::filesystem::path(szPath);
- auto safemode_file_path = ( appdata / "XIVLauncher" / ".dalamud_safemode" );
-
- std::ofstream ofs(safemode_file_path);
- ofs << "STAY SAFE!!!";
- ofs.close();
- }
-
- break;
- case IDABORT:
- ShellExecute(0, 0, L"https://goatcorp.github.io/faq?utm_source=vectored", 0, 0 , SW_SHOW );
- break;
- case IDCANCEL:
- break;
- default:
- break;
- }
- }).join();
+ if (DWORD written; !WriteFile(g_crashhandler_pipe_write, &stackTrace[0], static_cast(std::span(stackTrace).size_bytes()), &written, nullptr) || std::span(stackTrace).size_bytes() != written)
+ return EXCEPTION_CONTINUE_SEARCH;
+ SuspendThread(GetCurrentThread());
return EXCEPTION_CONTINUE_SEARCH;
}
-bool veh::add_handler(bool doFullDump, std::string workingDirectory)
+bool veh::add_handler(bool doFullDump, const std::string& workingDirectory)
{
if (g_veh_handle)
return false;
+
g_veh_handle = AddVectoredExceptionHandler(1, exception_handler);
SetUnhandledExceptionFilter(nullptr);
g_veh_do_full_dump = doFullDump;
g_time_start = std::chrono::system_clock::now();
- auto file_mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(exception_info), SHARED_INFO_FILE_NAME);
- if (!file_mapping) {
- std::cout << "Could not map info share file.\n";
- g_crashhandler_shared_info = nullptr;
+ std::optional, decltype(&CloseHandle)>> hWritePipe;
+ std::optional, decltype(&CloseHandle)>> hReadPipeInheritable;
+ if (HANDLE hReadPipeRaw, hWritePipeRaw; CreatePipe(&hReadPipeRaw, &hWritePipeRaw, nullptr, 65536))
+ {
+ hWritePipe.emplace(hWritePipeRaw, &CloseHandle);
+
+ if (HANDLE hReadPipeInheritableRaw; DuplicateHandle(GetCurrentProcess(), hReadPipeRaw, GetCurrentProcess(), &hReadPipeInheritableRaw, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+ {
+ hReadPipeInheritable.emplace(hReadPipeInheritableRaw, &CloseHandle);
+ }
+ else
+ {
+ logging::W("Failed to launch DalamudCrashHandler.exe: DuplicateHandle(1) error 0x{:x}", GetLastError());
+ return false;
+ }
}
else
{
- g_crashhandler_shared_info = (exception_info*)MapViewOfFile(file_mapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(exception_info));
- if (!g_crashhandler_shared_info) {
- std::cout << "Could not map view of info share file.\n";
+ logging::W("Failed to launch DalamudCrashHandler.exe: CreatePipe error 0x{:x}", GetLastError());
+ return false;
+ }
+
+ // additional information
+ STARTUPINFOEXW siex{};
+ PROCESS_INFORMATION pi{};
+
+ siex.StartupInfo.cb = sizeof siex;
+ siex.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
+#ifdef NDEBUG
+ siex.StartupInfo.wShowWindow = SW_HIDE;
+#else
+ siex.StartupInfo.wShowWindow = SW_SHOW;
+#endif
+
+ // set up list of handles to inherit to child process
+ std::vector attributeListBuf;
+ if (SIZE_T size = 0; !InitializeProcThreadAttributeList(nullptr, 1, 0, &size))
+ {
+ if (const auto err = GetLastError(); err != ERROR_INSUFFICIENT_BUFFER)
+ {
+ logging::W("Failed to launch DalamudCrashHandler.exe: InitializeProcThreadAttributeList(1) error 0x{:x}", err);
+ return false;
+ }
+
+ attributeListBuf.resize(size);
+ siex.lpAttributeList = reinterpret_cast(&attributeListBuf[0]);
+ if (!InitializeProcThreadAttributeList(siex.lpAttributeList, 1, 0, &size))
+ {
+ logging::W("Failed to launch DalamudCrashHandler.exe: InitializeProcThreadAttributeList(2) error 0x{:x}", GetLastError());
+ return false;
}
}
-
- g_crashhandler_event = CreateEvent(
- NULL, // default security attributes
- TRUE, // manual-reset event
- FALSE, // initial state is nonsignaled
- CRASHDUMP_EVENT_NAME // object name
- );
-
- if (!g_crashhandler_event)
+ else
{
- std::cout << "Couldn't acquire event handle\n";
+ logging::W("Failed to launch DalamudCrashHandler.exe: InitializeProcThreadAttributeList(0) was supposed to fail");
+ return false;
+ }
+ std::unique_ptr, decltype(&DeleteProcThreadAttributeList)> cleanAttributeList(siex.lpAttributeList, &DeleteProcThreadAttributeList);
+
+ std::vector handles;
+
+ HANDLE hInheritableCurrentProcess;
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hInheritableCurrentProcess, 0, TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ logging::W("Failed to launch DalamudCrashHandler.exe: DuplicateHandle(2) error 0x{:x}", GetLastError());
+ return false;
+ }
+ handles.push_back(hInheritableCurrentProcess);
+ handles.push_back(hReadPipeInheritable->get());
+
+ std::vector args;
+ std::wstring argstr;
+ args.emplace_back((std::filesystem::path(workingDirectory) / "DalamudCrashHandler.exe").wstring());
+ args.emplace_back(std::format(L"--process-handle={}", reinterpret_cast(hInheritableCurrentProcess)));
+ args.emplace_back(std::format(L"--exception-info-pipe-read-handle={}", reinterpret_cast(hReadPipeInheritable->get())));
+ args.emplace_back(std::format(L"--asset-directory={}", unicode::convert(g_startInfo.AssetDirectory)));
+ args.emplace_back(std::format(L"--log-directory={}", g_startInfo.BootLogPath.empty()
+ ? utils::loaded_module(g_hModule).path().parent_path().wstring()
+ : std::filesystem::path(unicode::convert(g_startInfo.BootLogPath)).parent_path().wstring()));
+ args.emplace_back(L"--");
+ append_injector_launch_args(args);
+
+ for (const auto& arg : args)
+ {
+ argstr.append(utils::escape_shell_arg(arg));
+ argstr.push_back(L' ');
+ }
+ argstr.pop_back();
+
+ if (!handles.empty() && !UpdateProcThreadAttribute(siex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &handles[0], std::span(handles).size_bytes(), nullptr, nullptr))
+ {
+ logging::W("Failed to launch DalamudCrashHandler.exe: UpdateProcThreadAttribute error 0x{:x}", GetLastError());
+ return false;
}
- auto handler_path = std::filesystem::path(workingDirectory) / "DalamudCrashHandler.exe";
-
- // additional information
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
+ if (!CreateProcessW(
+ args[0].c_str(), // The path
+ &argstr[0], // Command line
+ nullptr, // Process handle not inheritable
+ nullptr, // Thread handle not inheritable
+ TRUE, // Set handle inheritance to FALSE
+ EXTENDED_STARTUPINFO_PRESENT, // lpStartupInfo actually points to a STARTUPINFOEX(W)
+ nullptr, // Use parent's environment block
+ nullptr, // Use parent's starting directory
+ &siex.StartupInfo, // Pointer to STARTUPINFO structure
+ &pi // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
+ ))
+ {
+ logging::W("Failed to launch DalamudCrashHandler.exe: CreateProcessW error 0x{:x}", GetLastError());
+ return false;
+ }
- // set the size of the structures
- ZeroMemory( &si, sizeof(si) );
- si.cb = sizeof(si);
- ZeroMemory( &pi, sizeof(pi) );
+ CloseHandle(pi.hThread);
- CreateProcess( handler_path.c_str(), // the path
- NULL, // Command line
- NULL, // Process handle not inheritable
- NULL, // Thread handle not inheritable
- FALSE, // Set handle inheritance to FALSE
- 0, // No creation flags
- NULL, // Use parent's environment block
- NULL, // Use parent's starting directory
- &si, // Pointer to STARTUPINFO structure
- &pi // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
- );
-
- // Close process and thread handles.
- CloseHandle( pi.hProcess );
- CloseHandle( pi.hThread );
-
- return g_veh_handle != nullptr;
+ g_crashhandler_process = pi.hProcess;
+ g_crashhandler_pipe_write = hWritePipe->release();
+ logging::I("Launched DalamudCrashHandler.exe: PID {}", pi.dwProcessId);
+ return true;
}
bool veh::remove_handler()
diff --git a/Dalamud.Boot/veh.h b/Dalamud.Boot/veh.h
index 7820d6982..1905272ea 100644
--- a/Dalamud.Boot/veh.h
+++ b/Dalamud.Boot/veh.h
@@ -2,6 +2,6 @@
namespace veh
{
- bool add_handler(bool doFullDump, std::string workingDirectory);
+ bool add_handler(bool doFullDump, const std::string& workingDirectory);
bool remove_handler();
}
diff --git a/Dalamud.Injector/EntryPoint.cs b/Dalamud.Injector/EntryPoint.cs
index 88a240c65..9b5cfc07e 100644
--- a/Dalamud.Injector/EntryPoint.cs
+++ b/Dalamud.Injector/EntryPoint.cs
@@ -7,7 +7,7 @@ using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
-
+using System.Text.RegularExpressions;
using Dalamud.Game;
using Newtonsoft.Json;
using Reloaded.Memory.Buffers;
@@ -484,6 +484,7 @@ namespace Dalamud.Injector
var withoutDalamud = false;
var noFixAcl = false;
var waitForGameWindow = true;
+ var encryptArguments = false;
var parsingGameArgument = false;
for (var i = 2; i < args.Count; i++)
@@ -520,6 +521,43 @@ namespace Dalamud.Injector
throw new CommandLineException($"\"{args[i]}\" is not a command line argument.");
}
+ var checksumTable = "fX1pGtdS5CAP4_VL";
+ var argDelimiterRegex = new Regex(" (?
+ {
+ if (!x.StartsWith("//**sqex0003") || !x.EndsWith("**//"))
+ return new List() { x };
+
+ var checksum = checksumTable.IndexOf(x[x.Length - 5]);
+ if (checksum == -1)
+ return new List() { x };
+
+ var encData = Convert.FromBase64String(x.Substring(12, x.Length - 12 - 5).Replace('-', '+').Replace('_', '/').Replace('*', '='));
+ var rawData = new byte[encData.Length];
+
+ for (var i = (uint)checksum; i < 0x10000u; i += 0x10)
+ {
+ var bf = new LegacyBlowfish(Encoding.UTF8.GetBytes($"{i << 16:x08}"));
+ Buffer.BlockCopy(encData, 0, rawData, 0, rawData.Length);
+ bf.Decrypt(ref rawData);
+ var rawString = Encoding.UTF8.GetString(rawData).Split('\0', 2).First();
+ encryptArguments = true;
+ var args = argDelimiterRegex.Split(rawString).Skip(1).Select(y => string.Join('=', kvDelimiterRegex.Split(y, 2)).Replace(" ", " ")).ToList();
+ if (!args.Any())
+ continue;
+ if (!args.First().StartsWith("T="))
+ continue;
+ if (!uint.TryParse(args.First().Substring(2), out var tickCount))
+ continue;
+ if (tickCount >> 16 != i)
+ continue;
+ return args.Skip(1);
+ }
+
+ return new List() { x };
+ }).ToList();
+
if (showHelp)
{
ProcessHelpCommand(args, "launch");
@@ -603,7 +641,39 @@ namespace Dalamud.Injector
});
}
- var gameArgumentString = string.Join(" ", gameArguments.Select(x => EncodeParameterArgument(x)));
+ string gameArgumentString;
+ if (encryptArguments)
+ {
+ var rawTickCount = (uint)Environment.TickCount;
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ [System.Runtime.InteropServices.DllImport("c")]
+ static extern ulong clock_gettime_nsec_np(int clock_id);
+
+ const int CLOCK_MONOTONIC_RAW = 4;
+ var rawTickCountFixed = (clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW) / 1000000);
+ Log.Information("ArgumentBuilder::DeriveKey() fixing up rawTickCount from {0} to {1} on macOS", rawTickCount, rawTickCountFixed);
+ rawTickCount = (uint)rawTickCountFixed;
+ }
+
+ var ticks = rawTickCount & 0xFFFF_FFFFu;
+ var key = ticks & 0xFFFF_0000u;
+ gameArguments.Insert(0, $"T={ticks}");
+
+ var escapeValue = (string x) => x.Replace(" ", " ");
+ gameArgumentString = gameArguments.Select(x => x.Split('=', 2)).Aggregate(new StringBuilder(), (whole, part) => whole.Append($" /{escapeValue(part[0])} ={escapeValue(part.Length > 1 ? part[1] : string.Empty)}")).ToString();
+ var bf = new LegacyBlowfish(Encoding.UTF8.GetBytes($"{key:x08}"));
+ var ciphertext = bf.Encrypt(Encoding.UTF8.GetBytes(gameArgumentString));
+ var base64Str = Convert.ToBase64String(ciphertext).Replace('+', '-').Replace('/', '_').Replace('=', '*');
+ var checksum = checksumTable[(int)(key >> 16) & 0xF];
+ gameArgumentString = $"//**sqex0003{base64Str}{checksum}**//";
+ }
+ else
+ {
+ gameArgumentString = string.Join(" ", gameArguments.Select(x => EncodeParameterArgument(x)));
+ }
+
var process = GameStart.LaunchGame(Path.GetDirectoryName(gamePath), gamePath, gameArgumentString, noFixAcl, (Process p) =>
{
if (!withoutDalamud && mode == "entrypoint")
diff --git a/Dalamud.Injector/LegacyBlowfish.cs b/Dalamud.Injector/LegacyBlowfish.cs
new file mode 100644
index 000000000..576940521
--- /dev/null
+++ b/Dalamud.Injector/LegacyBlowfish.cs
@@ -0,0 +1,319 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dalamud.Injector
+{
+ internal class LegacyBlowfish
+ {
+ #region P-Array and S-Boxes
+
+ private readonly uint[] p =
+ {
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+ 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
+ };
+
+ private readonly uint[,] s =
+ {
+ {
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+ 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+ 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+ 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+ 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+ 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+ 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+ 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+ 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+ 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+ 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+ 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+ 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+ 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+ 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+ 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+ 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+ 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+ 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+ 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+ 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+ 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
+ },
+ {
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+ 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+ 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+ 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+ 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+ 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+ 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+ 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+ 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+ 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+ 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+ 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+ 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+ 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+ 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+ 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+ 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+ 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+ 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+ 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+ 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+ 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
+ },
+ {
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+ 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+ 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+ 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+ 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+ 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+ 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+ 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+ 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+ 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+ 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+ 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+ 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+ 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+ 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+ 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+ 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+ 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+ 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+ 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+ 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+ 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
+ },
+ {
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+ 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+ 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+ 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+ 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+ 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+ 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+ 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+ 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+ 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+ 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+ 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+ 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+ 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+ 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+ 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+ 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+ 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+ 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+ 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+ 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+ 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
+ }
+ };
+
+ #endregion
+
+ private static readonly int Rounds = 16;
+
+ ///
+ /// Initialize a new blowfish.
+ ///
+ /// The key to use.
+ /// Whether or not a sign confusion should be introduced during key init. This is needed for SE's implementation of blowfish.
+ public LegacyBlowfish(byte[] key)
+ {
+ foreach (var (i, keyFragment) in WrappingUInt32(key, this.p.Length))
+ this.p[i] ^= keyFragment;
+
+ uint l = 0, r = 0;
+ for (int i = 0; i < this.p.Length; i += 2)
+ (l, r) = (this.p[i], this.p[i + 1]) = Encrypt(l, r);
+
+ for (int i = 0; i < this.s.GetLength(0); i++)
+ for (int j = 0; j < this.s.GetLength(1); j += 2)
+ (l, r) = (this.s[i, j], this.s[i, j + 1]) = Encrypt(l, r);
+ }
+
+ public byte[] Encrypt(byte[] data)
+ {
+ var paddedLength = data.Length % 8 == 0 ? data.Length : data.Length + (8 - (data.Length % 8));
+ var buffer = new byte[paddedLength];
+ Buffer.BlockCopy(data, 0, buffer, 0, data.Length);
+
+ for (int i = 0; i < paddedLength; i += 8)
+ {
+ var (l, r) = Encrypt(BitConverter.ToUInt32(buffer, i), BitConverter.ToUInt32(buffer, i + 4));
+ CopyUInt32IntoArray(buffer, l, i);
+ CopyUInt32IntoArray(buffer, r, i + 4);
+ }
+
+ return buffer;
+ }
+
+ public void Decrypt(ref byte[] data)
+ {
+ for (int i = 0; i < data.Length; i += 8)
+ {
+ var (l, r) = Decrypt(BitConverter.ToUInt32(data, i), BitConverter.ToUInt32(data, i + 4));
+ CopyUInt32IntoArray(data, l, i);
+ CopyUInt32IntoArray(data, r, i + 4);
+ }
+ }
+
+ private static void CopyUInt32IntoArray(byte[] dest, uint val, int offset)
+ {
+ dest[offset] = (byte)(val & 0xFF);
+ dest[offset + 1] = (byte)((val >> 8) & 0xFF);
+ dest[offset + 2] = (byte)((val >> 16) & 0xFF);
+ dest[offset + 3] = (byte)((val >> 24) & 0xFF);
+ }
+
+ private uint F(uint i)
+ {
+ return ((this.s[0, i >> 24]
+ + this.s[1, (i >> 16) & 0xFF])
+ ^ this.s[2, (i >> 8) & 0xFF])
+ + this.s[3, i & 0xFF];
+ }
+
+ private (uint, uint) Encrypt(uint l, uint r)
+ {
+ for (int i = 0; i < Rounds; i += 2)
+ {
+ l ^= this.p[i];
+ r ^= F(l);
+ r ^= this.p[i + 1];
+ l ^= F(r);
+ }
+
+ return (r ^ this.p[17], l ^ this.p[16]);
+ }
+
+ private (uint, uint) Decrypt(uint l, uint r)
+ {
+ for (int i = Rounds; i > 0; i -= 2)
+ {
+ l ^= this.p[i + 1];
+ r ^= F(l);
+ r ^= this.p[i];
+ l ^= F(r);
+ }
+
+ return (r ^ this.p[0], l ^ this.p[1]);
+ }
+
+ private static IEnumerable Cycle(IEnumerable source)
+ {
+ while (true)
+ foreach (TSource t in source)
+ yield return t;
+ }
+
+ private IEnumerable<(int, uint)> WrappingUInt32(IEnumerable source, int count)
+ {
+ var enumerator = Cycle(source).GetEnumerator();
+
+ for (int i = 0; i < count; i++)
+ {
+ var n = 0u;
+
+ for (var j = 0; j < 4 && enumerator.MoveNext(); j++)
+ {
+ n = (uint)((n << 8) | (sbyte)enumerator.Current); // NOTE(goat): THIS IS A BUG! SE's implementation wrongly uses signed numbers for this, so we need to as well.
+ }
+
+ yield return (i, n);
+ }
+ }
+ }
+}
diff --git a/Dalamud.sln b/Dalamud.sln
index b7638754b..a618f1156 100644
--- a/Dalamud.sln
+++ b/Dalamud.sln
@@ -188,14 +188,14 @@ Global
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x64.Build.0 = Release|Any CPU
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x86.ActiveCfg = Release|Any CPU
{05AB2F46-268B-4915-806F-DDF813E2D59D}.Release|x86.Build.0 = Release|Any CPU
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|Any CPU.ActiveCfg = Debug|Win32
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|Any CPU.Build.0 = Debug|Win32
+ {317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|Any CPU.Build.0 = Debug|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|x64.ActiveCfg = Debug|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|x64.Build.0 = Debug|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|x86.ActiveCfg = Debug|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Debug|x86.Build.0 = Debug|x64
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Release|Any CPU.ActiveCfg = Release|Win32
- {317A264C-920B-44A1-8A34-F3A6827B0705}.Release|Any CPU.Build.0 = Release|Win32
+ {317A264C-920B-44A1-8A34-F3A6827B0705}.Release|Any CPU.ActiveCfg = Release|x64
+ {317A264C-920B-44A1-8A34-F3A6827B0705}.Release|Any CPU.Build.0 = Release|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|x64.ActiveCfg = Release|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|x64.Build.0 = Release|x64
{317A264C-920B-44A1-8A34-F3A6827B0705}.Release|x86.ActiveCfg = Release|x64
diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs
index cfc934f36..c28c3bbaf 100644
--- a/Dalamud/EntryPoint.cs
+++ b/Dalamud/EntryPoint.cs
@@ -3,7 +3,6 @@ using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -41,11 +40,8 @@ namespace Dalamud
///
/// A delegate used from VEH handler on exception which CoreCLR will fast fail by default.
///
- /// Path to minidump file created in UTF-16.
- /// Path to log file to create in UTF-16.
- /// Log text in UTF-16.
/// HGLOBAL for message.
- public delegate IntPtr VehDelegate(IntPtr dumpPath, IntPtr logPath, IntPtr log);
+ public delegate IntPtr VehDelegate();
///
/// Initialize Dalamud.
@@ -64,43 +60,19 @@ namespace Dalamud
}
///
- /// Show error message along with stack trace and exit.
+ /// Returns stack trace.
///
- /// Path to minidump file created in UTF-16.
- /// Path to log file to create in UTF-16.
- /// Log text in UTF-16.
- public static IntPtr VehCallback(IntPtr dumpPath, IntPtr logPath, IntPtr log)
+ /// HGlobal to wchar_t* stack trace c-string.
+ public static IntPtr VehCallback()
{
- string stackTrace;
try
{
- stackTrace = Environment.StackTrace;
+ return Marshal.StringToHGlobalUni(Environment.StackTrace);
}
catch (Exception e)
{
- stackTrace = "Fail: " + e.ToString();
+ return Marshal.StringToHGlobalUni("Fail: " + e);
}
-
- var msg = "This may be caused by a faulty plugin, a broken TexTools modification, any other third-party tool or simply a bug in the game.\n\n"
- + "Please attempt an integrity check in the XIVLauncher settings, and disabling plugins you don't need.";
-
- try
- {
- File.WriteAllText(
- Marshal.PtrToStringUni(logPath),
- "Stack trace:\n" + stackTrace + "\n\n" + Marshal.PtrToStringUni(log));
- }
- catch (Exception e)
- {
- msg += "\n\nAdditionally, failed to write file: " + e.ToString();
- }
-
- msg = msg.Format(
- Marshal.PtrToStringUni(dumpPath),
- Marshal.PtrToStringUni(logPath),
- stackTrace);
-
- return Marshal.StringToHGlobalUni(msg);
}
///
diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs
index 6e6e21301..fe81caf81 100644
--- a/Dalamud/Interface/Internal/DalamudInterface.cs
+++ b/Dalamud/Interface/Internal/DalamudInterface.cs
@@ -615,6 +615,16 @@ namespace Dalamud.Interface.Internal
Service.Get().Unload();
}
+ if (ImGui.MenuItem("Restart game"))
+ {
+ [DllImport("kernel32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ static extern void RaiseException(uint dwExceptionCode, uint dwExceptionFlags, uint nNumberOfArguments, IntPtr lpArguments);
+
+ RaiseException(0x12345678, 0, 0, IntPtr.Zero);
+ Process.GetCurrentProcess().Kill();
+ }
+
if (ImGui.MenuItem("Kill game"))
{
Process.GetCurrentProcess().Kill();
diff --git a/DalamudCrashHandler/DalamudCrashHandler.cpp b/DalamudCrashHandler/DalamudCrashHandler.cpp
index 2fc85e495..390b5085e 100644
--- a/DalamudCrashHandler/DalamudCrashHandler.cpp
+++ b/DalamudCrashHandler/DalamudCrashHandler.cpp
@@ -1,171 +1,633 @@
+#include
+#include
#include
+#include