impr: Refactored forwarder executable and add lots more information to it
@ -54,7 +54,7 @@ addBundledLibraries()
|
|||||||
# Add ImHex sources
|
# Add ImHex sources
|
||||||
add_subdirectory(lib/libimhex)
|
add_subdirectory(lib/libimhex)
|
||||||
add_subdirectory(main)
|
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
|
# Add unit tests
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
@ -254,7 +254,7 @@ macro(createPackage)
|
|||||||
else()
|
else()
|
||||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
if(WIN32) # Forwarder is only needed on Windows
|
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()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -611,12 +611,12 @@ function(generatePDBs)
|
|||||||
)
|
)
|
||||||
FetchContent_Populate(cv2pdb)
|
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)
|
add_custom_target(pdbs)
|
||||||
foreach (PDB ${PDBS_TO_GENERATE})
|
foreach (PDB ${PDBS_TO_GENERATE})
|
||||||
if (PDB STREQUAL "main")
|
if (PDB STREQUAL "main")
|
||||||
set(GENERATED_PDB imhex)
|
set(GENERATED_PDB imhex)
|
||||||
elseif (PDB STREQUAL "imhex-forwarder")
|
elseif (PDB STREQUAL "main-forwarder")
|
||||||
set(GENERATED_PDB imhex-gui)
|
set(GENERATED_PDB imhex-gui)
|
||||||
elseif (PDB STREQUAL "libimhex")
|
elseif (PDB STREQUAL "libimhex")
|
||||||
set(GENERATED_PDB 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)
|
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
|
set(IMHEX_APPLICATION_NAME "imhex-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)
|
|
||||||
else ()
|
else ()
|
||||||
set(IMHEX_APPLICATION_NAME "imhex")
|
set(IMHEX_APPLICATION_NAME "imhex")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set_target_properties(main PROPERTIES
|
add_subdirectory(gui)
|
||||||
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)
|
if (WIN32)
|
||||||
target_link_libraries(main PRIVATE usp10 wsock32 ws2_32 Dwmapi.lib)
|
add_subdirectory(forwarder)
|
||||||
else ()
|
endif ()
|
||||||
target_link_libraries(main PRIVATE pthread)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
add_compile_definitions(GL_SILENCE_DEPRECATION)
|
|
||||||
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() {
|
std::future<bool> WindowSplash::processTasksAsync() {
|
||||||
return std::async(std::launch::async, [this] {
|
return std::async(std::launch::async, [this] {
|
||||||
bool status = true;
|
bool status = true;
|
||||||
|
|
||||||
std::atomic<u32> tasksCompleted = 0;
|
std::atomic<u32> tasksCompleted = 0;
|
||||||
|
|
||||||
|
// Loop over all registered init tasks
|
||||||
for (const auto &[name, task, async] : this->m_tasks) {
|
for (const auto &[name, task, async] : this->m_tasks) {
|
||||||
|
|
||||||
|
// Construct a new task callback
|
||||||
auto runTask = [&, task = task, name = name] {
|
auto runTask = [&, task = task, name = name] {
|
||||||
try {
|
try {
|
||||||
|
// Save an iterator to the current task name
|
||||||
decltype(this->m_currTaskNames)::iterator taskNameIter;
|
decltype(this->m_currTaskNames)::iterator taskNameIter;
|
||||||
{
|
{
|
||||||
std::lock_guard guard(this->m_progressMutex);
|
std::lock_guard guard(this->m_progressMutex);
|
||||||
@ -69,32 +73,43 @@ namespace hex::init {
|
|||||||
taskNameIter = std::prev(this->m_currTaskNames.end());
|
taskNameIter = std::prev(this->m_currTaskNames.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When the task finished, increment the progress bar
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
tasksCompleted++;
|
tasksCompleted++;
|
||||||
this->m_progress = float(tasksCompleted) / this->m_tasks.size();
|
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();
|
auto startTime = std::chrono::high_resolution_clock::now();
|
||||||
bool taskStatus = task();
|
bool taskStatus = task();
|
||||||
auto endTime = std::chrono::high_resolution_clock::now();
|
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;
|
status = status && taskStatus;
|
||||||
|
|
||||||
|
// Erase the task name from the list of running tasks
|
||||||
{
|
{
|
||||||
std::lock_guard guard(this->m_progressMutex);
|
std::lock_guard guard(this->m_progressMutex);
|
||||||
this->m_currTaskNames.erase(taskNameIter);
|
this->m_currTaskNames.erase(taskNameIter);
|
||||||
}
|
}
|
||||||
} catch (std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
log::error("Init task '{}' threw an exception: {}", name, e.what());
|
log::error("Init task '{}' threw an exception: {}", name, e.what());
|
||||||
status = false;
|
status = false;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
log::error("Init task '{}' threw an unidentifiable exception", name);
|
||||||
status = false;
|
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) {
|
if (async) {
|
||||||
std::thread([runTask]{ runTask(); }).detach();
|
std::thread([runTask]{ runTask(); }).detach();
|
||||||
} else {
|
} else {
|
||||||
@ -102,6 +117,7 @@ namespace hex::init {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check every 100ms if all tasks have run
|
||||||
while (tasksCompleted < this->m_tasks.size()) {
|
while (tasksCompleted < this->m_tasks.size()) {
|
||||||
std::this_thread::sleep_for(100ms);
|
std::this_thread::sleep_for(100ms);
|
||||||
}
|
}
|
||||||
@ -127,10 +143,14 @@ namespace hex::init {
|
|||||||
auto drawList = ImGui::GetBackgroundDrawList();
|
auto drawList = ImGui::GetBackgroundDrawList();
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Draw the splash screen background
|
||||||
drawList->AddImage(this->splashBackgroundTexture, ImVec2(0, 0), this->splashBackgroundTexture.getSize() * scale);
|
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) {
|
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 hexSize = ImVec2(29, 18) * scale;
|
||||||
const auto hexSpacing = ImVec2(17.4, 15) * scale;
|
const auto hexSpacing = ImVec2(17.4, 15) * scale;
|
||||||
const auto hexStart = ImVec2(27, 127) * scale;
|
const auto hexStart = ImVec2(27, 127) * scale;
|
||||||
@ -141,22 +161,29 @@ namespace hex::init {
|
|||||||
|
|
||||||
color.Value.w *= opacity;
|
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 y = u32(start.y); y < u32(hexCount.y); y += 1) {
|
||||||
for (u32 x = u32(start.x); x < u32(hexCount.x); x += 1) {
|
for (u32 x = u32(start.x); x < u32(hexCount.x); x += 1) {
|
||||||
if (count-- == 0)
|
if (count-- == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Find the start position of the byte to draw
|
||||||
auto pos = hexStart + ImVec2(float(x), float(y)) * (hexSize + hexSpacing);
|
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);
|
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)
|
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);
|
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) {
|
if (isStart) {
|
||||||
isStart = false;
|
isStart = false;
|
||||||
drawList->AddRectFilled(pos - hexSpacing / 2, pos + ImVec2(0, hexSize.y + hexSpacing.y / 2), color);
|
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) {
|
if (count == 0) {
|
||||||
drawList->AddRectFilled(pos + ImVec2(hexSize.x, -hexSpacing.y / 2), pos + hexSize + hexSpacing / 2, color);
|
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)
|
for (const auto &highlight : this->highlights)
|
||||||
highlightBytes(highlight.start, highlight.count, highlight.color, this->progressLerp);
|
highlightBytes(highlight.start, highlight.count, highlight.color, this->progressLerp);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->progressLerp += (this->m_progress - this->progressLerp) * 0.1F;
|
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);
|
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());
|
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)
|
#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());
|
const static auto VersionInfo = hex::format("{0} : {1} {2}@{3}", ImHexApi::System::getImHexVersion(), ICON_FA_CODE_BRANCH, ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash());
|
||||||
#else
|
#else
|
||||||
@ -194,8 +226,11 @@ namespace hex::init {
|
|||||||
|
|
||||||
const auto progressStart = progressBackgroundStart + ImVec2(0, 20) * scale;
|
const auto progressStart = progressBackgroundStart + ImVec2(0, 20) * scale;
|
||||||
const auto progressSize = ImVec2(progressBackgroundSize.x * this->m_progress, 10 * scale);
|
const auto progressSize = ImVec2(progressBackgroundSize.x * this->m_progress, 10 * scale);
|
||||||
|
|
||||||
|
// Draw progress bar
|
||||||
drawList->AddRectFilled(progressStart, progressStart + progressSize, 0xD0FFFFFF);
|
drawList->AddRectFilled(progressStart, progressStart + progressSize, 0xD0FFFFFF);
|
||||||
|
|
||||||
|
// Draw task names separated by | characters
|
||||||
if (!this->m_currTaskNames.empty()) {
|
if (!this->m_currTaskNames.empty()) {
|
||||||
drawList->PushClipRect(progressBackgroundStart, progressBackgroundStart + progressBackgroundSize, true);
|
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());
|
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() {
|
void WindowSplash::startStartupTasks() {
|
||||||
// Launch init tasks in background
|
// Launch init tasks in the background
|
||||||
this->tasksSucceeded = processTasksAsync();
|
this->tasksSucceeded = processTasksAsync();
|
||||||
}
|
}
|
||||||
|
|
@ -12,7 +12,7 @@ namespace hex::messaging {
|
|||||||
void sendToOtherInstance(const std::string &eventName, const std::vector<u8> &args) {
|
void sendToOtherInstance(const std::string &eventName, const std::vector<u8> &args) {
|
||||||
hex::unused(eventName);
|
hex::unused(eventName);
|
||||||
hex::unused(args);
|
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
|
// 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) {
|
void sendToOtherInstance(const std::string &eventName, const std::vector<u8> &args) {
|
||||||
hex::unused(eventName);
|
hex::unused(eventName);
|
||||||
hex::unused(args);
|
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
|
// 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() {
|
IMHEX_PLUGIN_SUBCOMMANDS() {
|
||||||
{ "help", "Print help about this command", hex::plugin::builtin::handleHelpCommand },
|
{ "help", "Print help about this command", hex::plugin::builtin::handleHelpCommand },
|
||||||
{ "version", "Print ImHex version", hex::plugin::builtin::handleVersionCommand },
|
{ "version", "Print ImHex version", hex::plugin::builtin::handleVersionCommand },
|
||||||
{ "plugins", "Lists all plugins that have been installed", hex::plugin::builtin::handlePluginsCommand },
|
{ "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 },
|
{ "calc", "Evaluate a mathematical expression", hex::plugin::builtin::handleCalcCommand },
|
||||||
{ "hash", "Calculate the hash of a file", hex::plugin::builtin::handleHashCommand },
|
{ "hash", "Calculate the hash of a file", hex::plugin::builtin::handleHashCommand },
|
||||||
{ "encode", "Encode a string", hex::plugin::builtin::handleEncodeCommand },
|
{ "encode", "Encode a string", hex::plugin::builtin::handleEncodeCommand },
|
||||||
{ "decode", "Decode a string", hex::plugin::builtin::handleDecodeCommand },
|
{ "decode", "Decode a string", hex::plugin::builtin::handleDecodeCommand },
|
||||||
{ "magic", "Identify file types", hex::plugin::builtin::handleMagicCommand },
|
{ "magic", "Identify file types", hex::plugin::builtin::handleMagicCommand },
|
||||||
{ "pl", "Interact with the pattern language", hex::plugin::builtin::handlePatternLanguageCommand },
|
{ "pl", "Interact with the pattern language", hex::plugin::builtin::handlePatternLanguageCommand },
|
||||||
};
|
};
|
||||||
|
|
||||||
IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||||
|