| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- #include <Windows.h>
- #include <atomic>
- #include "../../client/graphics/wine_compat.h"
- #include "../../client/hooks/egress/runtime.h"
- #include "../../client/hooks/package_trust/package_trust_bypass.h"
- #include "../../client/runtime/runtime.h"
- #include "../../core/logging/log.h"
- #include "../../core/runtime/core_runtime.h"
- #include "../../core/runtime/host_environment.h"
- #include "callbacks/callback_registry.h"
- #include "core/threading/data_mutex.h"
- #include "internal.h"
- #include "runtime.h"
- #include "steam_context_state.h"
- namespace sunrise::steam {
- namespace {
- /** The only delay-loaded module allowed to start the platform Client group. */
- constexpr wchar_t kNetworkingModuleName[] = L"steamnetworkingsockets.dll";
- struct Lifecycle {
- bool mainActivationDone{};
- bool mainActivationResult{};
- bool graphicsActivationAttempted{};
- bool platformActivationAttempted{};
- };
- core::threading::SharedDataMutex<Lifecycle> g_lifecycle;
- std::atomic_bool g_initialized{false};
- /**
- * Finds the loaded image that owns a caught return address. It takes no module reference.
- * @return The owning module, or null when it is not the Steam networking image.
- */
- [[nodiscard]] HMODULE networking_caller_module(const void* callerAddress) noexcept {
- if (callerAddress == nullptr) {
- return nullptr;
- }
- HMODULE callerModule{};
- const DWORD flags =
- GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
- if (GetModuleHandleExW(flags, reinterpret_cast<LPCWSTR>(callerAddress), &callerModule) == FALSE
- || callerModule != GetModuleHandleW(kNetworkingModuleName)) {
- return nullptr;
- }
- return callerModule;
- }
- } // namespace
- /** Starts the Steam shim and its exported state. */
- bool initialize(void* module) noexcept {
- if (core::runtime::is_wine()) {
- client::graphics::initialize_wine_display();
- }
- if (!client::hooks::egress::install()) {
- return false;
- }
- return g_lifecycle.lock_write([module](Lifecycle&) {
- if (g_initialized.load(std::memory_order_acquire)) {
- return true;
- }
- if (!core::initialize(module)) {
- return false;
- }
- // Base generation (_0) packages register during bootload, before the first callback pump,
- // so package trust must attach at Steam init rather than in the main-image hook sweep.
- if (!client::hooks::package_trust::install()) {
- core::log::write(core::log::Channel::client,
- core::log::Level::error,
- "ev=steam_init stage=package_trust result=fail");
- (void)core::shutdown();
- return false;
- }
- advance_context_generation();
- g_initialized.store(true, std::memory_order_release);
- core::log::write(
- core::log::Channel::client, core::log::Level::info, "ev=steam_init result=ok");
- // The guard attaches above, before Core logging exists, so its outcome is reported here.
- client::hooks::egress::report_installation();
- return true;
- });
- }
- /** Stops callback delivery and clears Steam state. */
- bool shutdown() noexcept {
- return g_lifecycle.lock_write([](Lifecycle& lifecycle) {
- const bool hadRuntime =
- g_initialized.load(std::memory_order_acquire) || core::is_initialized();
- if (!hadRuntime) {
- return true;
- }
- if (!core::shutdown()) {
- core::log::write(core::log::Channel::client,
- core::log::Level::error,
- "ev=steam_shutdown stage=core result=fail");
- return false;
- }
- // Callback pointers are released only after Client hooks stop producing events.
- runtime::callbacks::clear();
- g_initialized.store(false, std::memory_order_release);
- lifecycle.mainActivationDone = false;
- lifecycle.mainActivationResult = false;
- lifecycle.graphicsActivationAttempted = false;
- lifecycle.platformActivationAttempted = false;
- advance_context_generation();
- return true;
- });
- }
- /** @return True. The in-process Steam provider stays up for the whole DLL lifetime. */
- bool is_running() noexcept {
- return true;
- }
- } // namespace sunrise::steam
- namespace sunrise::steam::runtime {
- /** Runs main-image activation once, from a caller that proves the game is loaded. */
- bool activate_main_once() noexcept {
- return g_lifecycle.lock_write([](Lifecycle& lifecycle) {
- if (!lifecycle.mainActivationDone && core::is_initialized()) {
- lifecycle.mainActivationDone = true;
- lifecycle.mainActivationResult = client::activate_main_once();
- }
- const bool result = lifecycle.mainActivationResult;
- return result;
- });
- }
- /** @return True while the main-image sweep has not run yet. */
- bool main_activation_pending() noexcept {
- const bool pending = g_lifecycle.lock_read(
- [](const Lifecycle& lifecycle) { return !lifecycle.mainActivationDone; });
- // Matches the activation's Core test. A failed Core must not raise an endless overlay.
- return pending && core::is_initialized();
- }
- /** Installs the presentation hooks once, from the callback pump, before the game sweep. */
- void activate_graphics_once() noexcept {
- g_lifecycle.lock_write([](Lifecycle& lifecycle) {
- if (!lifecycle.graphicsActivationAttempted && core::is_initialized()) {
- lifecycle.graphicsActivationAttempted = true;
- (void)client::activate_graphics_once();
- }
- });
- }
- /** Activates the platform Client group at its exact interface request boundary. */
- void activate_platform_once(const void* callerAddress) noexcept {
- const HMODULE callerModule = networking_caller_module(callerAddress);
- if (callerModule == nullptr) {
- return;
- }
- g_lifecycle.lock_write([callerModule](Lifecycle& lifecycle) {
- if (!lifecycle.platformActivationAttempted
- && g_initialized.load(std::memory_order_acquire)) {
- lifecycle.platformActivationAttempted = true;
- (void)client::activate_platform_once(callerModule);
- }
- });
- }
- } // namespace sunrise::steam::runtime
|