impr: Refactored forwarder executable and add lots more information to it
@ -54,7 +54,7 @@ addBundledLibraries()
|
||||
# Add ImHex sources
|
||||
add_subdirectory(lib/libimhex)
|
||||
add_subdirectory(main)
|
||||
add_custom_target(imhex_all ALL DEPENDS main libimhex)
|
||||
add_custom_target(imhex_all ALL DEPENDS main main-forwarder libimhex)
|
||||
|
||||
# Add unit tests
|
||||
enable_testing()
|
||||
|
@ -254,7 +254,7 @@ macro(createPackage)
|
||||
else()
|
||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
if(WIN32) # Forwarder is only needed on Windows
|
||||
install(TARGETS imhex-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS main-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -611,12 +611,12 @@ function(generatePDBs)
|
||||
)
|
||||
FetchContent_Populate(cv2pdb)
|
||||
|
||||
set(PDBS_TO_GENERATE main imhex-forwarder libimhex ${PLUGINS})
|
||||
set(PDBS_TO_GENERATE main main-forwarder libimhex ${PLUGINS})
|
||||
add_custom_target(pdbs)
|
||||
foreach (PDB ${PDBS_TO_GENERATE})
|
||||
if (PDB STREQUAL "main")
|
||||
set(GENERATED_PDB imhex)
|
||||
elseif (PDB STREQUAL "imhex-forwarder")
|
||||
elseif (PDB STREQUAL "main-forwarder")
|
||||
set(GENERATED_PDB imhex-gui)
|
||||
elseif (PDB STREQUAL "libimhex")
|
||||
set(GENERATED_PDB libimhex)
|
||||
|
@ -1,65 +1,10 @@
|
||||
project(main)
|
||||
|
||||
add_executable(main ${APPLICATION_TYPE}
|
||||
source/main.cpp
|
||||
source/crash_handlers.cpp
|
||||
|
||||
source/window/window.cpp
|
||||
source/window/win_window.cpp
|
||||
source/window/macos_window.cpp
|
||||
source/window/linux_window.cpp
|
||||
|
||||
source/messaging/common.cpp
|
||||
source/messaging/linux.cpp
|
||||
source/messaging/macos.cpp
|
||||
source/messaging/win.cpp
|
||||
|
||||
source/init/splash_window.cpp
|
||||
source/init/tasks.cpp
|
||||
|
||||
${IMHEX_ICON}
|
||||
)
|
||||
|
||||
target_include_directories(main PUBLIC include)
|
||||
setupCompilerFlags(main)
|
||||
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME imhex)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/main/libromfs EXCLUDE_FROM_ALL)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if (WIN32)
|
||||
# HACK: `imhex` -> `imhex-gui` and we add a forwarder as `imhex`, so that the user can just run `imhex` and it will start the GUI
|
||||
# Workaround for .NET plugin crashing caused by the console window being freed.
|
||||
set(IMHEX_APPLICATION_NAME "imhex-gui")
|
||||
add_executable(imhex-forwarder
|
||||
source/forwarder/main.cpp
|
||||
${IMHEX_ICON})
|
||||
target_link_libraries(imhex-forwarder PRIVATE libwolv-io ${FMT_LIBRARIES})
|
||||
set_target_properties(imhex-forwarder PROPERTIES
|
||||
OUTPUT_NAME "imhex"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
set(IMHEX_APPLICATION_NAME "imhex-gui")
|
||||
else ()
|
||||
set(IMHEX_APPLICATION_NAME "imhex")
|
||||
endif ()
|
||||
|
||||
set_target_properties(main PROPERTIES
|
||||
OUTPUT_NAME ${IMHEX_APPLICATION_NAME}
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
target_link_libraries(main PRIVATE libromfs-imhex libimhex ${FMT_LIBRARIES})
|
||||
add_subdirectory(gui)
|
||||
if (WIN32)
|
||||
target_link_libraries(main PRIVATE usp10 wsock32 ws2_32 Dwmapi.lib)
|
||||
else ()
|
||||
target_link_libraries(main PRIVATE pthread)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
add_compile_definitions(GL_SILENCE_DEPRECATION)
|
||||
endif ()
|
||||
add_subdirectory(forwarder)
|
||||
endif ()
|
12
main/forwarder/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
project(main-forwarder)
|
||||
|
||||
add_executable(main-forwarder
|
||||
source/main.cpp
|
||||
${IMHEX_ICON}
|
||||
)
|
||||
target_link_libraries(main-forwarder PRIVATE libwolv-io ${FMT_LIBRARIES})
|
||||
set_target_properties(main-forwarder PROPERTIES
|
||||
OUTPUT_NAME "imhex"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
POSITION_INDEPENDENT_CODE ON)
|
88
main/forwarder/source/main.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* This is a simple forwarder that launches the main ImHex executable with the
|
||||
* same command line as the current process. The reason for this is that even
|
||||
* though ImHex is a GUI application in general, it also has a command line
|
||||
* interface that can be used to perform various tasks. The issue with this is
|
||||
* that kernel32 will automatically allocate a console for us which will float
|
||||
* around in the background if we launch ImHex from the explorer. This forwarder
|
||||
* will get rid of the console window if ImHex was launched from the explorer and
|
||||
* enables ANSI escape sequences if ImHex was launched from the command line.
|
||||
*
|
||||
* The main reason this is done in a separate executable is because we use FreeConsole()
|
||||
* to get rid of the console window. Due to bugs in older versions of Windows (Windows 10 and older)
|
||||
* this will also close the process's standard handles (stdin, stdout, stderr) in
|
||||
* a way that cannot be recovered from. This means that if we were to do this in the
|
||||
* main application, if any code would try to interact with these handles (duplicate them
|
||||
* or modify them in any way), the application would crash.
|
||||
*
|
||||
* None of this would be necessary if Windows had a third type of application (besides
|
||||
* console and GUI) that would act like a console application but would not allocate
|
||||
* a console window. This would allow us to have a single executable that would work
|
||||
* the same as on all other platforms. There are plans to add this to Windows in the
|
||||
* future, but it is not yet available. Also even if it was available, it would not
|
||||
* be available on older versions of Windows, so we would still need this forwarder
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
void handleConsoleWindow() {
|
||||
HWND consoleWindow = ::GetConsoleWindow();
|
||||
DWORD processId = 0;
|
||||
::GetWindowThreadProcessId(consoleWindow, &processId);
|
||||
|
||||
// Check if ImHex was launched from the explorer or from the command line
|
||||
if (::GetCurrentProcessId() == processId) {
|
||||
// If it was launched from the explorer, kernel32 has allocated a console for us
|
||||
// Get rid of it to avoid having a useless console window floating around
|
||||
::FreeConsole();
|
||||
} else {
|
||||
// If it was launched from the command line, enable ANSI escape sequences to have colored output
|
||||
auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hConsole != INVALID_HANDLE_VALUE) {
|
||||
DWORD mode = 0;
|
||||
if (::GetConsoleMode(hConsole, &mode) == TRUE) {
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT;
|
||||
::SetConsoleMode(hConsole, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int launchExecutable() {
|
||||
// Get the path of the main ImHex executable
|
||||
auto executablePath = wolv::io::fs::getExecutablePath();
|
||||
auto executableFullPath = executablePath->parent_path() / "imhex-gui.exe";
|
||||
|
||||
::PROCESS_INFORMATION process = { };
|
||||
::STARTUPINFOW startupInfo = { };
|
||||
startupInfo.cb = sizeof(STARTUPINFOW);
|
||||
|
||||
// Create a new process for imhex-gui.exe with the same command line as the current process
|
||||
if (::CreateProcessW(executableFullPath.wstring().c_str(), ::GetCommandLineW(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupInfo, &process) == FALSE) {
|
||||
// Handle error if the process could not be created
|
||||
|
||||
auto errorCode = ::GetLastError();
|
||||
auto errorMessageString = std::system_category().message(errorCode);
|
||||
|
||||
auto errorMessage = fmt::format("Failed to start ImHex:\n\nError code: 0x{:08X}\n\n{}", errorCode, errorMessageString);
|
||||
|
||||
::MessageBoxA(nullptr, errorMessage.c_str(), "ImHex Forwarder", MB_OK | MB_ICONERROR);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
::WaitForSingleObject(process.hProcess, INFINITE);
|
||||
::CloseHandle(process.hProcess);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main() {
|
||||
handleConsoleWindow();
|
||||
auto result = launchExecutable();
|
||||
|
||||
return result;
|
||||
}
|
48
main/gui/CMakeLists.txt
Normal file
@ -0,0 +1,48 @@
|
||||
project(main)
|
||||
|
||||
add_executable(main ${APPLICATION_TYPE}
|
||||
source/main.cpp
|
||||
source/crash_handlers.cpp
|
||||
|
||||
source/window/window.cpp
|
||||
source/window/win_window.cpp
|
||||
source/window/macos_window.cpp
|
||||
source/window/linux_window.cpp
|
||||
|
||||
source/messaging/common.cpp
|
||||
source/messaging/linux.cpp
|
||||
source/messaging/macos.cpp
|
||||
source/messaging/win.cpp
|
||||
|
||||
source/init/splash_window.cpp
|
||||
source/init/tasks.cpp
|
||||
|
||||
${IMHEX_ICON}
|
||||
)
|
||||
|
||||
target_include_directories(main PUBLIC include)
|
||||
setupCompilerFlags(main)
|
||||
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME imhex)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/main/gui/libromfs EXCLUDE_FROM_ALL)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set_target_properties(main PROPERTIES
|
||||
OUTPUT_NAME ${IMHEX_APPLICATION_NAME}
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
target_link_libraries(main PRIVATE libromfs-imhex libimhex ${FMT_LIBRARIES})
|
||||
if (WIN32)
|
||||
target_link_libraries(main PRIVATE usp10 wsock32 ws2_32 Dwmapi.lib)
|
||||
else ()
|
||||
target_link_libraries(main PRIVATE pthread)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
add_compile_definitions(GL_SILENCE_DEPRECATION)
|
||||
endif ()
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 157 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
@ -57,11 +57,15 @@ namespace hex::init {
|
||||
std::future<bool> WindowSplash::processTasksAsync() {
|
||||
return std::async(std::launch::async, [this] {
|
||||
bool status = true;
|
||||
|
||||
std::atomic<u32> tasksCompleted = 0;
|
||||
|
||||
// Loop over all registered init tasks
|
||||
for (const auto &[name, task, async] : this->m_tasks) {
|
||||
|
||||
// Construct a new task callback
|
||||
auto runTask = [&, task = task, name = name] {
|
||||
try {
|
||||
// Save an iterator to the current task name
|
||||
decltype(this->m_currTaskNames)::iterator taskNameIter;
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
@ -69,32 +73,43 @@ namespace hex::init {
|
||||
taskNameIter = std::prev(this->m_currTaskNames.end());
|
||||
}
|
||||
|
||||
// When the task finished, increment the progress bar
|
||||
ON_SCOPE_EXIT {
|
||||
tasksCompleted++;
|
||||
this->m_progress = float(tasksCompleted) / this->m_tasks.size();
|
||||
};
|
||||
|
||||
// Execute the actual task and track the amount of time it took to run
|
||||
auto startTime = std::chrono::high_resolution_clock::now();
|
||||
bool taskStatus = task();
|
||||
auto endTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
log::info("Task '{}' finished in {} ms (success={})", name, std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count(), taskStatus);
|
||||
|
||||
log::info("Task '{}' finished {} in {} ms",
|
||||
name,
|
||||
taskStatus ? "successfully" : "unsuccessfully",
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count()
|
||||
);
|
||||
|
||||
// Track the overall status of the tasks
|
||||
status = status && taskStatus;
|
||||
|
||||
// Erase the task name from the list of running tasks
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
this->m_currTaskNames.erase(taskNameIter);
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Init task '{}' threw an exception: {}", name, e.what());
|
||||
status = false;
|
||||
} catch (...) {
|
||||
log::error("Init task '{}' threw an unidentifiable exception", name);
|
||||
status = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// If the task can be run asynchronously, run it in a separate thread
|
||||
// otherwise run it in this thread and wait for it to finish
|
||||
if (async) {
|
||||
std::thread([runTask]{ runTask(); }).detach();
|
||||
} else {
|
||||
@ -102,6 +117,7 @@ namespace hex::init {
|
||||
}
|
||||
}
|
||||
|
||||
// Check every 100ms if all tasks have run
|
||||
while (tasksCompleted < this->m_tasks.size()) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
@ -127,10 +143,14 @@ namespace hex::init {
|
||||
auto drawList = ImGui::GetBackgroundDrawList();
|
||||
{
|
||||
|
||||
// Draw the splash screen background
|
||||
drawList->AddImage(this->splashBackgroundTexture, ImVec2(0, 0), this->splashBackgroundTexture.getSize() * scale);
|
||||
|
||||
{
|
||||
|
||||
// Function to highlight a given number of bytes at a position in the splash screen
|
||||
const auto highlightBytes = [&](ImVec2 start, size_t count, ImColor color, float opacity) {
|
||||
// Dimensions and number of bytes that are drawn. Taken from the splash screen image
|
||||
const auto hexSize = ImVec2(29, 18) * scale;
|
||||
const auto hexSpacing = ImVec2(17.4, 15) * scale;
|
||||
const auto hexStart = ImVec2(27, 127) * scale;
|
||||
@ -141,22 +161,29 @@ namespace hex::init {
|
||||
|
||||
color.Value.w *= opacity;
|
||||
|
||||
// Loop over all the bytes on the splash screen
|
||||
for (u32 y = u32(start.y); y < u32(hexCount.y); y += 1) {
|
||||
for (u32 x = u32(start.x); x < u32(hexCount.x); x += 1) {
|
||||
if (count-- == 0)
|
||||
return;
|
||||
|
||||
// Find the start position of the byte to draw
|
||||
auto pos = hexStart + ImVec2(float(x), float(y)) * (hexSize + hexSpacing);
|
||||
|
||||
// Fill the rectangle in the byte with the given color
|
||||
drawList->AddRectFilled(pos + ImVec2(0, -hexSpacing.y / 2), pos + hexSize + ImVec2(0, hexSpacing.y / 2), color);
|
||||
|
||||
// Add some extra color on the right if the current byte isn't the last byte, and we didn't reach the right side of the image
|
||||
if (count > 0 && x != u32(hexCount.x) - 1)
|
||||
drawList->AddRectFilled(pos + ImVec2(hexSize.x, -hexSpacing.y / 2), pos + hexSize + ImVec2(hexSpacing.x, hexSpacing.y / 2), color);
|
||||
|
||||
// Add some extra color on the left if this is the first byte we're highlighting
|
||||
if (isStart) {
|
||||
isStart = false;
|
||||
drawList->AddRectFilled(pos - hexSpacing / 2, pos + ImVec2(0, hexSize.y + hexSpacing.y / 2), color);
|
||||
}
|
||||
|
||||
// Add some extra color on the right if this is the last byte
|
||||
if (count == 0) {
|
||||
drawList->AddRectFilled(pos + ImVec2(hexSize.x, -hexSpacing.y / 2), pos + hexSize + hexSpacing / 2, color);
|
||||
}
|
||||
@ -166,16 +193,21 @@ namespace hex::init {
|
||||
}
|
||||
};
|
||||
|
||||
// Draw all highlights, slowly fading them in as the init tasks progress
|
||||
for (const auto &highlight : this->highlights)
|
||||
highlightBytes(highlight.start, highlight.count, highlight.color, this->progressLerp);
|
||||
}
|
||||
|
||||
this->progressLerp += (this->m_progress - this->progressLerp) * 0.1F;
|
||||
|
||||
// Draw the splash screen foreground
|
||||
drawList->AddImage(this->splashTextTexture, ImVec2(0, 0), this->splashTextTexture.getSize() * scale);
|
||||
|
||||
// Draw the "copyright" notice
|
||||
drawList->AddText(ImVec2(35, 85) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv\n2020 - {0}", &__DATE__[7]).c_str());
|
||||
|
||||
// Draw version information
|
||||
// In debug builds, also display the current commit hash and branch
|
||||
#if defined(DEBUG)
|
||||
const static auto VersionInfo = hex::format("{0} : {1} {2}@{3}", ImHexApi::System::getImHexVersion(), ICON_FA_CODE_BRANCH, ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
|
||||
#else
|
||||
@ -194,8 +226,11 @@ namespace hex::init {
|
||||
|
||||
const auto progressStart = progressBackgroundStart + ImVec2(0, 20) * scale;
|
||||
const auto progressSize = ImVec2(progressBackgroundSize.x * this->m_progress, 10 * scale);
|
||||
|
||||
// Draw progress bar
|
||||
drawList->AddRectFilled(progressStart, progressStart + progressSize, 0xD0FFFFFF);
|
||||
|
||||
// Draw task names separated by | characters
|
||||
if (!this->m_currTaskNames.empty()) {
|
||||
drawList->PushClipRect(progressBackgroundStart, progressBackgroundStart + progressBackgroundSize, true);
|
||||
drawList->AddText(progressStart + ImVec2(5, -20) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{}", fmt::join(this->m_currTaskNames, " | ")).c_str());
|
||||
@ -424,7 +459,7 @@ namespace hex::init {
|
||||
}
|
||||
|
||||
void WindowSplash::startStartupTasks() {
|
||||
// Launch init tasks in background
|
||||
// Launch init tasks in the background
|
||||
this->tasksSucceeded = processTasksAsync();
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace hex::messaging {
|
||||
void sendToOtherInstance(const std::string &eventName, const std::vector<u8> &args) {
|
||||
hex::unused(eventName);
|
||||
hex::unused(args);
|
||||
log::error("Not implemented function sendToOtherInstance() called");
|
||||
log::error("Unimplemented function 'sendToOtherInstance()' called");
|
||||
}
|
||||
|
||||
// Not implemented, so lets say we are the main instance every time so events are forwarded to ourselves
|
@ -12,7 +12,7 @@ namespace hex::messaging {
|
||||
void sendToOtherInstance(const std::string &eventName, const std::vector<u8> &args) {
|
||||
hex::unused(eventName);
|
||||
hex::unused(args);
|
||||
log::error("Not implemented function sendToOtherInstance() called");
|
||||
log::error("Unimplemented function 'sendToOtherInstance()' called");
|
||||
}
|
||||
|
||||
// Not implemented, so lets say we are the main instance every time so events are forwarded to ourselves
|
@ -1,54 +0,0 @@
|
||||
#include <windows.h>
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
int main() {
|
||||
HWND consoleWindow = ::GetConsoleWindow();
|
||||
DWORD processId = 0;
|
||||
::GetWindowThreadProcessId(consoleWindow, &processId);
|
||||
if (GetCurrentProcessId() == processId) {
|
||||
FreeConsole();
|
||||
} else {
|
||||
auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hConsole != INVALID_HANDLE_VALUE) {
|
||||
DWORD mode = 0;
|
||||
if (::GetConsoleMode(hConsole, &mode) == TRUE) {
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT;
|
||||
::SetConsoleMode(hConsole, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto executablePath = wolv::io::fs::getExecutablePath();
|
||||
auto executableFullPath = executablePath->parent_path() / "imhex-gui.exe";
|
||||
|
||||
PROCESS_INFORMATION process;
|
||||
STARTUPINFOW startupInfo;
|
||||
ZeroMemory(&process, sizeof(PROCESS_INFORMATION));
|
||||
ZeroMemory(&startupInfo, sizeof(STARTUPINFOW));
|
||||
startupInfo.cb = sizeof(STARTUPINFOW);
|
||||
|
||||
if (CreateProcessW(executableFullPath.wstring().c_str(), GetCommandLineW(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupInfo, &process) == FALSE) {
|
||||
auto error = GetLastError();
|
||||
|
||||
wchar_t errorMessageString[1024];
|
||||
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, error, 0, errorMessageString, 1024, nullptr);
|
||||
|
||||
std::wstring errorMessage = L"Failed to start ImHex:\n\nError code: ";
|
||||
|
||||
// Format error code to have 8 digits hex
|
||||
wchar_t errorCodeString[11];
|
||||
swprintf_s(errorCodeString, 11, L"0x%08X", error);
|
||||
|
||||
errorMessage += errorCodeString;
|
||||
errorMessage += L"\n\n";
|
||||
errorMessage += errorMessageString;
|
||||
|
||||
MessageBoxW(nullptr, errorMessage.c_str(), L"ImHex Forwarder", MB_OK | MB_ICONERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
WaitForSingleObject(process.hProcess, INFINITE);
|
||||
CloseHandle(process.hProcess);
|
||||
|
||||
return 0;
|
||||
}
|
@ -50,18 +50,18 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
IMHEX_PLUGIN_SUBCOMMANDS() {
|
||||
{ "help", "Print help about this command", hex::plugin::builtin::handleHelpCommand },
|
||||
{ "version", "Print ImHex version", hex::plugin::builtin::handleVersionCommand },
|
||||
{ "plugins", "Lists all plugins that have been installed", hex::plugin::builtin::handlePluginsCommand },
|
||||
{ "help", "Print help about this command", hex::plugin::builtin::handleHelpCommand },
|
||||
{ "version", "Print ImHex version", hex::plugin::builtin::handleVersionCommand },
|
||||
{ "plugins", "Lists all plugins that have been installed", hex::plugin::builtin::handlePluginsCommand },
|
||||
|
||||
{ "open", "Open files passed as argument. [default]", hex::plugin::builtin::handleOpenCommand },
|
||||
{ "open", "Open files passed as argument. [default]", hex::plugin::builtin::handleOpenCommand },
|
||||
|
||||
{ "calc", "Evaluate a mathematical expression", hex::plugin::builtin::handleCalcCommand },
|
||||
{ "hash", "Calculate the hash of a file", hex::plugin::builtin::handleHashCommand },
|
||||
{ "encode", "Encode a string", hex::plugin::builtin::handleEncodeCommand },
|
||||
{ "decode", "Decode a string", hex::plugin::builtin::handleDecodeCommand },
|
||||
{ "magic", "Identify file types", hex::plugin::builtin::handleMagicCommand },
|
||||
{ "pl", "Interact with the pattern language", hex::plugin::builtin::handlePatternLanguageCommand },
|
||||
{ "calc", "Evaluate a mathematical expression", hex::plugin::builtin::handleCalcCommand },
|
||||
{ "hash", "Calculate the hash of a file", hex::plugin::builtin::handleHashCommand },
|
||||
{ "encode", "Encode a string", hex::plugin::builtin::handleEncodeCommand },
|
||||
{ "decode", "Decode a string", hex::plugin::builtin::handleDecodeCommand },
|
||||
{ "magic", "Identify file types", hex::plugin::builtin::handleMagicCommand },
|
||||
{ "pl", "Interact with the pattern language", hex::plugin::builtin::handlePatternLanguageCommand },
|
||||
};
|
||||
|
||||
IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
|