Files
CoopAllTheThings/host/CMakeLists.txt
BlackMark 0eb275daca Reconnect to an already-injected DLL (reuse it, survive a tool restart)
Disconnect -> reconnect now reuses the DLL already in the game instead of
injecting again, including across a tool restart or crash: a connected DLL keeps
its per-pid shared section (and worker) alive after the host goes away, so a
fresh host can find it and re-attach to the same section.

- hook_dll_alive(pid) (host/src/inject/dll_probe.cpp): detect a live DLL by
  opening the per-pid section and polling its heartbeat (returns as soon as a
  beat lands; a missing section or stalled worker reads as not-alive). It does
  not check magic -- a graceful disconnect zeroes magic but the DLL keeps
  beating and the worker never re-checks magic post-connect.
- InjectionPanel: the Inject and Connect button branches to reconnect_selected()
  when a live DLL is detected -- IpcServer::start() re-attaches to the SAME
  section the DLL still holds and re-publishes the subsystem state; no
  re-injection. Factored the shared post-connect setup (publish_subsystem_state
  / begin_liveness_tracking). The DLL needed no change -- it just resumes reading
  the re-attached section.
- A false not-alive is benign: the inject path still re-attaches an
  already-injected DLL (LoadLibrary no-ops), so the timeout only needs to clear
  the worker's ~250ms beat period with margin.

Test (mock_game_test test_reconnect): inject -> hooked -> graceful disconnect ->
drop the host handle (simulating a restart while the DLL keeps the section alive)
-> detect via heartbeat -> re-attach to the same section -> hooks re-install
without re-injecting -> and hook_dll_alive goes false once the game is gone.

Roadmap: both current tasks (graceful disconnect, reconnect) done -> removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 14:05:54 +02:00

108 lines
4.4 KiB
CMake

add_executable(coop_host WIN32
src/main.cpp
src/d3d11_window.cpp
src/imgui_layer.cpp
src/controllers_panel.cpp
src/injection_panel.cpp
src/capture_panel.cpp
src/audio_panel.cpp
src/log_panel.cpp
src/ui/app_chrome.cpp
src/input/xinput_source.cpp
src/input/input_worker.cpp
src/inject/process_list.cpp
src/inject/window_list.cpp
src/inject/injector.cpp
src/inject/dll_probe.cpp
src/inject/mkb_forward.cpp
src/ipc/ipc_server.cpp
src/capture/frame_renderer.cpp
src/capture/window_capture.cpp
src/capture/shared_texture.cpp
src/audio/audio_loopback.cpp
src/audio/audio_format_verifier.cpp
src/audio/audio_overrides.cpp
src/audio/process_loopback_capture.cpp
src/vk_layer_setup.cpp
src/test_harness.cpp)
target_include_directories(coop_host PRIVATE src)
# Debug-only IPC test harness: lets a script drive the real UI code paths (inject /
# audio / override / ...) and read state back, instead of simulating mouse input. OFF
# by default, so the shipped host never contains it (the source compiles to nothing
# without the macro). Enable with -DCOOP_TEST_HARNESS=ON for a debuggable build.
option(COOP_TEST_HARNESS "Build the host with the debug IPC test harness (dev only)" OFF)
if(COOP_TEST_HARNESS)
target_compile_definitions(coop_host PRIVATE COOP_TEST_HARNESS)
message(STATUS "Host test harness ENABLED (debug IPC driver)")
endif()
# Process-loopback capture (AUDIOCLIENT_ACTIVATION_TYPE_PROCESS_LOOPBACK) needs the
# Windows 10 20H1 (NTDDI_WIN10_CO) headers; raise the target SDK version for it.
target_compile_definitions(coop_host PRIVATE NTDDI_VERSION=0x0A00000B)
target_link_libraries(coop_host PRIVATE
coop_common
imgui
d3d11
dxgi
dwmapi
d3dcompiler
windowsapp
xinput
mmdevapi
winmm
ole32)
set_target_properties(coop_host PROPERTIES OUTPUT_NAME "coop_host")
# Optional Steam Input: enabled automatically when the Steamworks SDK is vendored
# under third_party/steamworks_sdk (it isn't redistributable, so it's gitignored
# and never committed). Without it, the host builds XInput-only.
set(COOP_STEAM_SDK_DIR "${CMAKE_SOURCE_DIR}/third_party/steamworks_sdk/sdk")
if(EXISTS "${COOP_STEAM_SDK_DIR}/public/steam/steam_api.h")
message(STATUS "Steamworks SDK found -> Steam Input enabled")
target_sources(coop_host PRIVATE src/input/steam_input_source.cpp)
target_compile_definitions(coop_host PRIVATE COOP_WITH_STEAM)
target_include_directories(coop_host SYSTEM PRIVATE "${COOP_STEAM_SDK_DIR}/public")
# The SDK headers trip /W4 (strncpy, non-UTF-8 bytes); silence for this TU only.
set_source_files_properties(src/input/steam_input_source.cpp PROPERTIES
COMPILE_OPTIONS "/wd4996;/wd4828")
target_link_libraries(coop_host PRIVATE
"${COOP_STEAM_SDK_DIR}/redistributable_bin/win64/steam_api64.lib")
# Stage steam_api64.dll + the action manifest next to coop_host.exe.
add_custom_command(TARGET coop_host POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${COOP_STEAM_SDK_DIR}/redistributable_bin/win64/steam_api64.dll"
"$<TARGET_FILE_DIR:coop_host>/steam_api64.dll"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/assets/steam_input_actions.vdf"
"$<TARGET_FILE_DIR:coop_host>/steam_input_actions.vdf"
VERBATIM)
# Console smoke test for Steam Input (reuses the shipping source). Not a ctest
# (needs Steam running + an appid); run manually from bin/<config>/.
add_executable(coop_steam_input_probe
${CMAKE_SOURCE_DIR}/tools/steam_input_probe/main.cpp
src/input/steam_input_source.cpp
src/input/xinput_source.cpp)
target_include_directories(coop_steam_input_probe PRIVATE src)
target_include_directories(coop_steam_input_probe SYSTEM PRIVATE "${COOP_STEAM_SDK_DIR}/public")
target_compile_definitions(coop_steam_input_probe PRIVATE COOP_WITH_STEAM)
set_source_files_properties(src/input/steam_input_source.cpp PROPERTIES COMPILE_OPTIONS "/wd4996;/wd4828")
target_link_libraries(coop_steam_input_probe PRIVATE
coop_common
xinput
"${COOP_STEAM_SDK_DIR}/redistributable_bin/win64/steam_api64.lib")
# Dev tool -> bin/<config>/tools/ (its steam_api64.dll copy follows via TARGET_FILE_DIR).
coop_output_subdir(tools coop_steam_input_probe)
add_custom_command(TARGET coop_steam_input_probe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${COOP_STEAM_SDK_DIR}/redistributable_bin/win64/steam_api64.dll"
"$<TARGET_FILE_DIR:coop_steam_input_probe>/steam_api64.dll"
VERBATIM)
else()
message(STATUS "Steamworks SDK not found -> Steam Input disabled (XInput only)")
endif()