mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Merge remote-tracking branch 'origin/master' into net8-rollup
This commit is contained in:
commit
a2cc9ffe34
11 changed files with 148 additions and 77 deletions
|
|
@ -68,10 +68,25 @@ void from_json(const nlohmann::json& json, DalamudStartInfo::ClientLanguage& val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void from_json(const nlohmann::json& json, DalamudStartInfo::LoadMethod& value) {
|
||||||
|
if (json.is_number_integer()) {
|
||||||
|
value = static_cast<DalamudStartInfo::LoadMethod>(json.get<int>());
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (json.is_string()) {
|
||||||
|
const auto langstr = unicode::convert<std::string>(json.get<std::string>(), &unicode::lower);
|
||||||
|
if (langstr == "entrypoint")
|
||||||
|
value = DalamudStartInfo::LoadMethod::Entrypoint;
|
||||||
|
else if (langstr == "inject")
|
||||||
|
value = DalamudStartInfo::LoadMethod::DllInject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void from_json(const nlohmann::json& json, DalamudStartInfo& config) {
|
void from_json(const nlohmann::json& json, DalamudStartInfo& config) {
|
||||||
if (!json.is_object())
|
if (!json.is_object())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
config.DalamudLoadMethod = json.value("LoadMethod", config.DalamudLoadMethod);
|
||||||
config.WorkingDirectory = json.value("WorkingDirectory", config.WorkingDirectory);
|
config.WorkingDirectory = json.value("WorkingDirectory", config.WorkingDirectory);
|
||||||
config.ConfigurationPath = json.value("ConfigurationPath", config.ConfigurationPath);
|
config.ConfigurationPath = json.value("ConfigurationPath", config.ConfigurationPath);
|
||||||
config.PluginDirectory = json.value("PluginDirectory", config.PluginDirectory);
|
config.PluginDirectory = json.value("PluginDirectory", config.PluginDirectory);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,13 @@ struct DalamudStartInfo {
|
||||||
};
|
};
|
||||||
friend void from_json(const nlohmann::json&, ClientLanguage&);
|
friend void from_json(const nlohmann::json&, ClientLanguage&);
|
||||||
|
|
||||||
|
enum class LoadMethod : int {
|
||||||
|
Entrypoint,
|
||||||
|
DllInject,
|
||||||
|
};
|
||||||
|
friend void from_json(const nlohmann::json&, LoadMethod&);
|
||||||
|
|
||||||
|
LoadMethod DalamudLoadMethod = LoadMethod::Entrypoint;
|
||||||
std::string WorkingDirectory;
|
std::string WorkingDirectory;
|
||||||
std::string ConfigurationPath;
|
std::string ConfigurationPath;
|
||||||
std::string PluginDirectory;
|
std::string PluginDirectory;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ struct exception_info
|
||||||
CONTEXT ContextRecord;
|
CONTEXT ContextRecord;
|
||||||
uint64_t nLifetime;
|
uint64_t nLifetime;
|
||||||
HANDLE hThreadHandle;
|
HANDLE hThreadHandle;
|
||||||
|
HANDLE hEventHandle;
|
||||||
DWORD dwStackTraceLength;
|
DWORD dwStackTraceLength;
|
||||||
DWORD dwTroubleshootingPackDataLength;
|
DWORD dwTroubleshootingPackDataLength;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,6 @@ DWORD WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
|
||||||
logging::I("Initializing VEH...");
|
logging::I("Initializing VEH...");
|
||||||
if (g_startInfo.NoExceptionHandlers) {
|
if (g_startInfo.NoExceptionHandlers) {
|
||||||
logging::W("=> Exception handlers are disabled from DalamudStartInfo.");
|
logging::W("=> Exception handlers are disabled from DalamudStartInfo.");
|
||||||
} else if (utils::is_running_on_wine()) {
|
|
||||||
logging::I("=> VEH was disabled, running on wine");
|
|
||||||
} else if (g_startInfo.BootVehEnabled) {
|
} else if (g_startInfo.BootVehEnabled) {
|
||||||
if (veh::add_handler(g_startInfo.BootVehFull, g_startInfo.WorkingDirectory))
|
if (veh::add_handler(g_startInfo.BootVehFull, g_startInfo.WorkingDirectory))
|
||||||
logging::I("=> Done!");
|
logging::I("=> Done!");
|
||||||
|
|
|
||||||
|
|
@ -578,21 +578,14 @@ std::vector<std::string> utils::get_env_list(const wchar_t* pcszName) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool utils::is_running_on_wine() {
|
std::wstring utils::to_wstring(const std::string& str) {
|
||||||
if (get_env<bool>(L"XL_WINEONLINUX"))
|
if (str.empty()) return std::wstring();
|
||||||
return true;
|
size_t convertedChars = 0;
|
||||||
HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
|
size_t newStrSize = str.size() + 1;
|
||||||
if (!hntdll)
|
std::wstring wstr(newStrSize, L'\0');
|
||||||
return true;
|
mbstowcs_s(&convertedChars, &wstr[0], newStrSize, str.c_str(), _TRUNCATE);
|
||||||
if (GetProcAddress(hntdll, "wine_get_version"))
|
wstr.resize(convertedChars - 1);
|
||||||
return true;
|
return wstr;
|
||||||
if (GetProcAddress(hntdll, "wine_get_host_version"))
|
|
||||||
return true;
|
|
||||||
if (GetProcAddress(hntdll, "wine_server_call"))
|
|
||||||
return true;
|
|
||||||
if (GetProcAddress(hntdll, "wine_unix_to_nt_file_name"))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path utils::get_module_path(HMODULE hModule) {
|
std::filesystem::path utils::get_module_path(HMODULE hModule) {
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ namespace utils {
|
||||||
return get_env_list<T>(unicode::convert<std::wstring>(pcszName).c_str());
|
return get_env_list<T>(unicode::convert<std::wstring>(pcszName).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_running_on_wine();
|
std::wstring to_wstring(const std::string& str);
|
||||||
|
|
||||||
std::filesystem::path get_module_path(HMODULE hModule);
|
std::filesystem::path get_module_path(HMODULE hModule);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ PVOID g_veh_handle = nullptr;
|
||||||
bool g_veh_do_full_dump = false;
|
bool g_veh_do_full_dump = false;
|
||||||
|
|
||||||
HANDLE g_crashhandler_process = nullptr;
|
HANDLE g_crashhandler_process = nullptr;
|
||||||
|
HANDLE g_crashhandler_event = nullptr;
|
||||||
HANDLE g_crashhandler_pipe_write = nullptr;
|
HANDLE g_crashhandler_pipe_write = nullptr;
|
||||||
|
|
||||||
std::recursive_mutex g_exception_handler_mutex;
|
std::recursive_mutex g_exception_handler_mutex;
|
||||||
|
|
@ -101,8 +102,21 @@ bool is_ffxiv_address(const wchar_t* module_name, const DWORD64 address)
|
||||||
|
|
||||||
static void append_injector_launch_args(std::vector<std::wstring>& args)
|
static void append_injector_launch_args(std::vector<std::wstring>& args)
|
||||||
{
|
{
|
||||||
args.emplace_back(L"-g");
|
args.emplace_back(L"--game=\"" + utils::loaded_module::current_process().path().wstring() + L"\"");
|
||||||
args.emplace_back(utils::loaded_module::current_process().path().wstring());
|
switch (g_startInfo.DalamudLoadMethod) {
|
||||||
|
case DalamudStartInfo::LoadMethod::Entrypoint:
|
||||||
|
args.emplace_back(L"--mode=entrypoint");
|
||||||
|
break;
|
||||||
|
case DalamudStartInfo::LoadMethod::DllInject:
|
||||||
|
args.emplace_back(L"--mode=inject");
|
||||||
|
}
|
||||||
|
args.emplace_back(L"--logpath=\"" + utils::to_wstring(g_startInfo.BootLogPath) + L"\"");
|
||||||
|
args.emplace_back(L"--dalamud-working-directory=\"" + utils::to_wstring(g_startInfo.WorkingDirectory) + L"\"");
|
||||||
|
args.emplace_back(L"--dalamud-configuration-path=\"" + utils::to_wstring(g_startInfo.ConfigurationPath) + L"\"");
|
||||||
|
args.emplace_back(L"--dalamud-plugin-directory=\"" + utils::to_wstring(g_startInfo.PluginDirectory) + L"\"");
|
||||||
|
args.emplace_back(L"--dalamud-asset-directory=\"" + utils::to_wstring(g_startInfo.AssetDirectory) + L"\"");
|
||||||
|
args.emplace_back(L"--dalamud-client-language=" + std::to_wstring(static_cast<int>(g_startInfo.Language)));
|
||||||
|
args.emplace_back(L"--dalamud-delay-initialize=" + std::to_wstring(g_startInfo.DelayInitializeMs));
|
||||||
if (g_startInfo.BootShowConsole)
|
if (g_startInfo.BootShowConsole)
|
||||||
args.emplace_back(L"--console");
|
args.emplace_back(L"--console");
|
||||||
if (g_startInfo.BootEnableEtw)
|
if (g_startInfo.BootEnableEtw)
|
||||||
|
|
@ -158,6 +172,7 @@ LONG exception_handler(EXCEPTION_POINTERS* ex)
|
||||||
g_time_start.time_since_epoch()).count();
|
g_time_start.time_since_epoch()).count();
|
||||||
exinfo.nLifetime = lifetime;
|
exinfo.nLifetime = lifetime;
|
||||||
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), g_crashhandler_process, &exinfo.hThreadHandle, 0, TRUE, DUPLICATE_SAME_ACCESS);
|
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), g_crashhandler_process, &exinfo.hThreadHandle, 0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||||
|
DuplicateHandle(GetCurrentProcess(), g_crashhandler_event, g_crashhandler_process, &exinfo.hEventHandle, 0, TRUE, DUPLICATE_SAME_ACCESS);
|
||||||
|
|
||||||
std::wstring stackTrace;
|
std::wstring stackTrace;
|
||||||
if (void* fn; const auto err = static_cast<DWORD>(g_clr->get_function_pointer(
|
if (void* fn; const auto err = static_cast<DWORD>(g_clr->get_function_pointer(
|
||||||
|
|
@ -185,7 +200,20 @@ LONG exception_handler(EXCEPTION_POINTERS* ex)
|
||||||
if (DWORD written; !WriteFile(g_crashhandler_pipe_write, &g_startInfo.TroubleshootingPackData[0], static_cast<DWORD>(std::span(g_startInfo.TroubleshootingPackData).size_bytes()), &written, nullptr) || std::span(g_startInfo.TroubleshootingPackData).size_bytes() != written)
|
if (DWORD written; !WriteFile(g_crashhandler_pipe_write, &g_startInfo.TroubleshootingPackData[0], static_cast<DWORD>(std::span(g_startInfo.TroubleshootingPackData).size_bytes()), &written, nullptr) || std::span(g_startInfo.TroubleshootingPackData).size_bytes() != written)
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
SuspendThread(GetCurrentThread());
|
HANDLE waitHandles[] = { g_crashhandler_process, g_crashhandler_event };
|
||||||
|
DWORD waitResult = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
|
||||||
|
|
||||||
|
switch (waitResult) {
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
logging::E("DalamudCrashHandler.exe exited unexpectedly");
|
||||||
|
break;
|
||||||
|
case WAIT_OBJECT_0 + 1:
|
||||||
|
logging::I("Crashing thread was resumed");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logging::E("Unexpected WaitForMultipleObjects return code 0x{:x}", waitResult);
|
||||||
|
}
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -308,6 +336,12 @@ bool veh::add_handler(bool doFullDump, const std::string& workingDirectory)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(g_crashhandler_event = CreateEventW(NULL, FALSE, FALSE, NULL)))
|
||||||
|
{
|
||||||
|
logging::W("Failed to create crash synchronization event: CreateEventW error 0x{:x}", GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
|
|
||||||
g_crashhandler_process = pi.hProcess;
|
g_crashhandler_process = pi.hProcess;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@ public record DalamudStartInfo
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Dalamud load method.
|
||||||
|
/// </summary>
|
||||||
|
public LoadMethod LoadMethod { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the working directory of the XIVLauncher installations.
|
/// Gets or sets the working directory of the XIVLauncher installations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
17
Dalamud.Common/LoadMethod.cs
Normal file
17
Dalamud.Common/LoadMethod.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
namespace Dalamud.Common;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enum describing the method Dalamud has been loaded.
|
||||||
|
/// </summary>
|
||||||
|
public enum LoadMethod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Load Dalamud by rewriting the games entrypoint.
|
||||||
|
/// </summary>
|
||||||
|
Entrypoint,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load Dalamud via DLL-injection.
|
||||||
|
/// </summary>
|
||||||
|
DllInject,
|
||||||
|
}
|
||||||
|
|
@ -680,11 +680,11 @@ namespace Dalamud.Injector
|
||||||
mode = mode == null ? "entrypoint" : mode.ToLowerInvariant();
|
mode = mode == null ? "entrypoint" : mode.ToLowerInvariant();
|
||||||
if (mode.Length > 0 && mode.Length <= 10 && "entrypoint"[0..mode.Length] == mode)
|
if (mode.Length > 0 && mode.Length <= 10 && "entrypoint"[0..mode.Length] == mode)
|
||||||
{
|
{
|
||||||
mode = "entrypoint";
|
dalamudStartInfo.LoadMethod = LoadMethod.Entrypoint;
|
||||||
}
|
}
|
||||||
else if (mode.Length > 0 && mode.Length <= 6 && "inject"[0..mode.Length] == mode)
|
else if (mode.Length > 0 && mode.Length <= 6 && "inject"[0..mode.Length] == mode)
|
||||||
{
|
{
|
||||||
mode = "inject";
|
dalamudStartInfo.LoadMethod = LoadMethod.DllInject;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -796,7 +796,7 @@ namespace Dalamud.Injector
|
||||||
noFixAcl,
|
noFixAcl,
|
||||||
p =>
|
p =>
|
||||||
{
|
{
|
||||||
if (!withoutDalamud && mode == "entrypoint")
|
if (!withoutDalamud && dalamudStartInfo.LoadMethod == LoadMethod.Entrypoint)
|
||||||
{
|
{
|
||||||
var startInfo = AdjustStartInfo(dalamudStartInfo, gamePath);
|
var startInfo = AdjustStartInfo(dalamudStartInfo, gamePath);
|
||||||
Log.Information("Using start info: {0}", JsonConvert.SerializeObject(startInfo));
|
Log.Information("Using start info: {0}", JsonConvert.SerializeObject(startInfo));
|
||||||
|
|
@ -813,7 +813,7 @@ namespace Dalamud.Injector
|
||||||
|
|
||||||
Log.Verbose("Game process started with PID {0}", process.Id);
|
Log.Verbose("Game process started with PID {0}", process.Id);
|
||||||
|
|
||||||
if (!withoutDalamud && mode == "inject")
|
if (!withoutDalamud && dalamudStartInfo.LoadMethod == LoadMethod.DllInject)
|
||||||
{
|
{
|
||||||
var startInfo = AdjustStartInfo(dalamudStartInfo, gamePath);
|
var startInfo = AdjustStartInfo(dalamudStartInfo, gamePath);
|
||||||
Log.Information("Using start info: {0}", JsonConvert.SerializeObject(startInfo));
|
Log.Information("Using start info: {0}", JsonConvert.SerializeObject(startInfo));
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ std::wstring u8_to_ws(const std::string& s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring get_window_string(HWND hWnd) {
|
std::wstring get_window_string(HWND hWnd) {
|
||||||
std::wstring buf(GetWindowTextLengthW(hWnd), L'\0');
|
std::wstring buf(GetWindowTextLengthW(hWnd) + 1, L'\0');
|
||||||
GetWindowTextW(hWnd, &buf[0], static_cast<int>(buf.size()));
|
GetWindowTextW(hWnd, &buf[0], static_cast<int>(buf.size()));
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
@ -456,8 +456,10 @@ void export_tspack(HWND hWndParent, const std::filesystem::path& logDir, const s
|
||||||
{ L"All files (*.*)", L"*" },
|
{ L"All files (*.*)", L"*" },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
IShellItemPtr pItem;
|
std::optional<std::wstring> filePath;
|
||||||
|
std::fstream fileStream;
|
||||||
try {
|
try {
|
||||||
|
IShellItemPtr pItem;
|
||||||
SYSTEMTIME st;
|
SYSTEMTIME st;
|
||||||
GetLocalTime(&st);
|
GetLocalTime(&st);
|
||||||
IFileSaveDialogPtr pDialog;
|
IFileSaveDialogPtr pDialog;
|
||||||
|
|
@ -475,32 +477,38 @@ void export_tspack(HWND hWndParent, const std::filesystem::path& logDir, const s
|
||||||
|
|
||||||
throw_if_failed(pDialog->GetResult(&pItem), {}, "pDialog->GetResult");
|
throw_if_failed(pDialog->GetResult(&pItem), {}, "pDialog->GetResult");
|
||||||
|
|
||||||
IBindCtxPtr pBindCtx;
|
PWSTR pFilePath = nullptr;
|
||||||
throw_if_failed(CreateBindCtx(0, &pBindCtx), {}, "CreateBindCtx");
|
throw_if_failed(pItem->GetDisplayName(SIGDN_FILESYSPATH, &pFilePath), {}, "pItem->GetDisplayName");
|
||||||
|
pItem.Release();
|
||||||
|
filePath.emplace(pFilePath);
|
||||||
|
|
||||||
auto options = BIND_OPTS{.cbStruct = sizeof(BIND_OPTS), .grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE};
|
fileStream.open(*filePath, std::ios::binary | std::ios::in | std::ios::out | std::ios::trunc);
|
||||||
throw_if_failed(pBindCtx->SetBindOptions(&options), {}, "pBindCtx->SetBindOptions");
|
|
||||||
|
|
||||||
IStreamPtr pStream;
|
|
||||||
throw_if_failed(pItem->BindToHandler(pBindCtx, BHID_Stream, IID_PPV_ARGS(&pStream)), {}, "pItem->BindToHandler");
|
|
||||||
|
|
||||||
throw_if_failed(pStream->SetSize({}), {}, "pStream->SetSize");
|
|
||||||
|
|
||||||
mz_zip_archive zipa{};
|
mz_zip_archive zipa{};
|
||||||
zipa.m_pIO_opaque = &*pStream;
|
zipa.m_pIO_opaque = &fileStream;
|
||||||
zipa.m_pRead = [](void* pOpaque, mz_uint64 file_ofs, void* pBuf, size_t n) -> size_t {
|
zipa.m_pRead = [](void* pOpaque, mz_uint64 file_ofs, void* pBuf, size_t n) -> size_t {
|
||||||
const auto pStream = static_cast<IStream*>(pOpaque);
|
const auto pStream = static_cast<std::fstream*>(pOpaque);
|
||||||
throw_if_failed(pStream->Seek({ .QuadPart = static_cast<int64_t>(file_ofs) }, STREAM_SEEK_SET, nullptr), {}, "pStream->Seek");
|
if (!pStream || !pStream->is_open())
|
||||||
ULONG read;
|
throw std::runtime_error("Read operation failed: Stream is not open");
|
||||||
throw_if_failed(pStream->Read(pBuf, static_cast<ULONG>(n), &read), {}, "pStream->Read");
|
pStream->seekg(file_ofs, std::ios::beg);
|
||||||
return read;
|
if (pStream->fail())
|
||||||
|
throw std::runtime_error("Read operation failed: Error seeking in stream");
|
||||||
|
pStream->read(static_cast<char*>(pBuf), n);
|
||||||
|
if (pStream->fail())
|
||||||
|
throw std::runtime_error("Read operation failed: Error reading from stream");
|
||||||
|
return pStream->gcount();
|
||||||
};
|
};
|
||||||
zipa.m_pWrite = [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n) -> size_t {
|
zipa.m_pWrite = [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n) -> size_t {
|
||||||
const auto pStream = static_cast<IStream*>(pOpaque);
|
const auto pStream = static_cast<std::fstream*>(pOpaque);
|
||||||
throw_if_failed(pStream->Seek({ .QuadPart = static_cast<int64_t>(file_ofs) }, STREAM_SEEK_SET, nullptr), {}, "pStream->Seek");
|
if (!pStream || !pStream->is_open())
|
||||||
ULONG written;
|
throw std::runtime_error("Write operation failed: Stream is not open");
|
||||||
throw_if_failed(pStream->Write(pBuf, static_cast<ULONG>(n), &written), {}, "pStream->Write");
|
pStream->seekp(file_ofs, std::ios::beg);
|
||||||
return written;
|
if (pStream->fail())
|
||||||
|
throw std::runtime_error("Write operation failed: Error seeking in stream");
|
||||||
|
pStream->write(static_cast<const char*>(pBuf), n);
|
||||||
|
if (pStream->fail())
|
||||||
|
throw std::runtime_error("Write operation failed: Error writing to stream");
|
||||||
|
return n;
|
||||||
};
|
};
|
||||||
const auto mz_throw_if_failed = [&zipa](mz_bool res, const std::string& clue) {
|
const auto mz_throw_if_failed = [&zipa](mz_bool res, const std::string& clue) {
|
||||||
if (!res)
|
if (!res)
|
||||||
|
|
@ -545,7 +553,14 @@ void export_tspack(HWND hWndParent, const std::filesystem::path& logDir, const s
|
||||||
}
|
}
|
||||||
|
|
||||||
auto handleInfo = HandleAndBaseOffset{.h = hLogFile, .off = baseOffset.QuadPart};
|
auto handleInfo = HandleAndBaseOffset{.h = hLogFile, .off = baseOffset.QuadPart};
|
||||||
const auto modt = std::chrono::system_clock::to_time_t(std::chrono::clock_cast<std::chrono::system_clock>(last_write_time(logFilePath)));
|
WIN32_FILE_ATTRIBUTE_DATA fileInfo = { 0 };
|
||||||
|
time_t modt = time(nullptr);
|
||||||
|
if (GetFileAttributesExW(logFilePath.c_str(), GetFileExInfoStandard, &fileInfo)) {
|
||||||
|
ULARGE_INTEGER ull = { 0 };
|
||||||
|
ull.LowPart = fileInfo.ftLastWriteTime.dwLowDateTime;
|
||||||
|
ull.HighPart = fileInfo.ftLastWriteTime.dwHighDateTime;
|
||||||
|
modt = ull.QuadPart / 10000000ULL - 11644473600ULL;
|
||||||
|
}
|
||||||
mz_throw_if_failed(mz_zip_writer_add_read_buf_callback(
|
mz_throw_if_failed(mz_zip_writer_add_read_buf_callback(
|
||||||
&zipa,
|
&zipa,
|
||||||
pcszLogFileName,
|
pcszLogFileName,
|
||||||
|
|
@ -564,34 +579,20 @@ void export_tspack(HWND hWndParent, const std::filesystem::path& logDir, const s
|
||||||
|
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
MessageBoxW(hWndParent, std::format(L"Failed to save file: {}", u8_to_ws(e.what())).c_str(), get_window_string(hWndParent).c_str(), MB_OK | MB_ICONERROR);
|
MessageBoxW(hWndParent, std::format(L"Failed to save file: {}", u8_to_ws(e.what())).c_str(), get_window_string(hWndParent).c_str(), MB_OK | MB_ICONERROR);
|
||||||
|
fileStream.close();
|
||||||
if (pItem) {
|
if (filePath) {
|
||||||
try {
|
try {
|
||||||
IFileOperationPtr pFileOps;
|
std::filesystem::remove(*filePath);
|
||||||
throw_if_failed(pFileOps.CreateInstance(__uuidof(FileOperation), nullptr, CLSCTX_ALL));
|
} catch (const std::filesystem::filesystem_error& e2) {
|
||||||
throw_if_failed(pFileOps->SetOperationFlags(FOF_NO_UI));
|
|
||||||
throw_if_failed(pFileOps->DeleteItem(pItem, nullptr));
|
|
||||||
throw_if_failed(pFileOps->PerformOperations());
|
|
||||||
} catch (const std::exception& e2) {
|
|
||||||
std::wcerr << std::format(L"Failed to remove temporary file: {}", u8_to_ws(e2.what())) << std::endl;
|
std::wcerr << std::format(L"Failed to remove temporary file: {}", u8_to_ws(e2.what())) << std::endl;
|
||||||
}
|
}
|
||||||
pItem.Release();
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pItem) {
|
fileStream.close();
|
||||||
PWSTR pwszFileName;
|
if (filePath) {
|
||||||
if (FAILED(pItem->GetDisplayName(SIGDN_FILESYSPATH, &pwszFileName))) {
|
ShellExecuteW(hWndParent, nullptr, L"explorer.exe", escape_shell_arg(std::format(L"/select,{}", *filePath)).c_str(), nullptr, SW_SHOW);
|
||||||
if (FAILED(pItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEEDITING, &pwszFileName))) {
|
|
||||||
MessageBoxW(hWndParent, L"The file has been saved to the specified path.", get_window_string(hWndParent).c_str(), MB_OK | MB_ICONINFORMATION);
|
|
||||||
} else {
|
|
||||||
std::unique_ptr<std::remove_pointer<PWSTR>::type, decltype(CoTaskMemFree)*> pszFileNamePtr(pwszFileName, CoTaskMemFree);
|
|
||||||
MessageBoxW(hWndParent, std::format(L"The file has been saved to: {}", pwszFileName).c_str(), get_window_string(hWndParent).c_str(), MB_OK | MB_ICONINFORMATION);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::unique_ptr<std::remove_pointer<PWSTR>::type, decltype(CoTaskMemFree)*> pszFileNamePtr(pwszFileName, CoTaskMemFree);
|
|
||||||
ShellExecuteW(hWndParent, nullptr, L"explorer.exe", escape_shell_arg(std::format(L"/select,{}", pwszFileName)).c_str(), nullptr, SW_SHOW);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -612,7 +613,8 @@ void restart_game_using_injector(int nRadioButton, const std::vector<std::wstrin
|
||||||
pathStr.resize(GetModuleFileNameExW(GetCurrentProcess(), GetModuleHandleW(nullptr), &pathStr[0], PATHCCH_MAX_CCH));
|
pathStr.resize(GetModuleFileNameExW(GetCurrentProcess(), GetModuleHandleW(nullptr), &pathStr[0], PATHCCH_MAX_CCH));
|
||||||
|
|
||||||
std::vector<std::wstring> args;
|
std::vector<std::wstring> args;
|
||||||
args.emplace_back((std::filesystem::path(pathStr).parent_path() / L"Dalamud.Injector.exe").wstring());
|
std::wstring injectorPath = (std::filesystem::path(pathStr).parent_path() / L"Dalamud.Injector.exe").wstring();
|
||||||
|
args.emplace_back(L'\"' + injectorPath + L'\"');
|
||||||
args.emplace_back(L"launch");
|
args.emplace_back(L"launch");
|
||||||
switch (nRadioButton) {
|
switch (nRadioButton) {
|
||||||
case IdRadioRestartWithout3pPlugins:
|
case IdRadioRestartWithout3pPlugins:
|
||||||
|
|
@ -625,12 +627,11 @@ void restart_game_using_injector(int nRadioButton, const std::vector<std::wstrin
|
||||||
args.emplace_back(L"--without-dalamud");
|
args.emplace_back(L"--without-dalamud");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
args.emplace_back(L"--");
|
|
||||||
args.insert(args.end(), launcherArgs.begin(), launcherArgs.end());
|
args.insert(args.end(), launcherArgs.begin(), launcherArgs.end());
|
||||||
|
|
||||||
std::wstring argstr;
|
std::wstring argstr;
|
||||||
for (const auto& arg : args) {
|
for (const auto& arg : args) {
|
||||||
argstr.append(escape_shell_arg(arg));
|
argstr.append(arg);
|
||||||
argstr.push_back(L' ');
|
argstr.push_back(L' ');
|
||||||
}
|
}
|
||||||
argstr.pop_back();
|
argstr.pop_back();
|
||||||
|
|
@ -644,7 +645,7 @@ void restart_game_using_injector(int nRadioButton, const std::vector<std::wstrin
|
||||||
si.wShowWindow = SW_SHOW;
|
si.wShowWindow = SW_SHOW;
|
||||||
#endif
|
#endif
|
||||||
PROCESS_INFORMATION pi{};
|
PROCESS_INFORMATION pi{};
|
||||||
if (CreateProcessW(args[0].c_str(), &argstr[0], nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
|
if (CreateProcessW(injectorPath.c_str(), &argstr[0], nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -840,7 +841,7 @@ int main() {
|
||||||
log << std::format(L"Dump at: {}", dumpPath.wstring()) << std::endl;
|
log << std::format(L"Dump at: {}", dumpPath.wstring()) << std::endl;
|
||||||
else
|
else
|
||||||
log << std::format(L"Dump error: {}", dumpError) << std::endl;
|
log << std::format(L"Dump error: {}", dumpError) << std::endl;
|
||||||
log << L"Time: " << std::chrono::zoned_time{ std::chrono::current_zone(), std::chrono::system_clock::now() } << std::endl;
|
log << L"System Time: " << std::chrono::system_clock::now() << std::endl;
|
||||||
log << L"\n" << stackTrace << std::endl;
|
log << L"\n" << stackTrace << std::endl;
|
||||||
|
|
||||||
SymRefreshModuleList(GetCurrentProcess());
|
SymRefreshModuleList(GetCurrentProcess());
|
||||||
|
|
@ -991,7 +992,7 @@ int main() {
|
||||||
|
|
||||||
int nButtonPressed = 0, nRadioButton = 0;
|
int nButtonPressed = 0, nRadioButton = 0;
|
||||||
if (FAILED(TaskDialogIndirect(&config, &nButtonPressed, &nRadioButton, nullptr))) {
|
if (FAILED(TaskDialogIndirect(&config, &nButtonPressed, &nRadioButton, nullptr))) {
|
||||||
ResumeThread(exinfo.hThreadHandle);
|
SetEvent(exinfo.hEventHandle);
|
||||||
} else {
|
} else {
|
||||||
switch (nButtonPressed) {
|
switch (nButtonPressed) {
|
||||||
case IdButtonRestart:
|
case IdButtonRestart:
|
||||||
|
|
@ -1002,7 +1003,7 @@ int main() {
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if (attemptResume)
|
if (attemptResume)
|
||||||
ResumeThread(exinfo.hThreadHandle);
|
SetEvent(exinfo.hEventHandle);
|
||||||
else
|
else
|
||||||
TerminateProcess(g_hProcess, exinfo.ExceptionRecord.ExceptionCode);
|
TerminateProcess(g_hProcess, exinfo.ExceptionRecord.ExceptionCode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue