diff --git a/cmake/build_helpers.cmake b/cmake/build_helpers.cmake index 9e7d2f8f4..0d4839e7c 100644 --- a/cmake/build_helpers.cmake +++ b/cmake/build_helpers.cmake @@ -253,6 +253,9 @@ macro(createPackage) set(CPACK_GENERATOR "DragNDrop") 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}) + endif() endif() if (CREATE_PACKAGE) @@ -608,11 +611,13 @@ function(generatePDBs) ) FetchContent_Populate(cv2pdb) - set(PDBS_TO_GENERATE main libimhex ${PLUGINS}) + set(PDBS_TO_GENERATE main imhex-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") + set(GENERATED_PDB imhex-gui) elseif (PDB STREQUAL "libimhex") set(GENERATED_PDB libimhex) else () diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 65ed226e0..32afd1eb3 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -28,11 +28,28 @@ 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) -set_target_properties(main PROPERTIES +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) +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}") diff --git a/main/source/forwarder/main.cpp b/main/source/forwarder/main.cpp new file mode 100644 index 000000000..cad9b15e5 --- /dev/null +++ b/main/source/forwarder/main.cpp @@ -0,0 +1,54 @@ +#include +#include + +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; +} \ No newline at end of file diff --git a/main/source/window/win_window.cpp b/main/source/window/win_window.cpp index 8370469a6..880c1d3ae 100644 --- a/main/source/window/win_window.cpp +++ b/main/source/window/win_window.cpp @@ -237,7 +237,6 @@ namespace hex { ::GetWindowThreadProcessId(consoleWindow, &processId); if (GetCurrentProcessId() == processId) { ShowWindow(consoleWindow, SW_HIDE); - FreeConsole(); log::impl::redirectToFile(); } else { auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);