/* * Copyright (C) 2021 Patrick Mours * SPDX-License-Identifier: BSD-3-Clause OR MIT */ #pragma once #include "reshade_events.hpp" #include "reshade_overlay.hpp" #include #include // Current version of the ReShade API #define RESHADE_API_VERSION 8 // Optionally import ReShade API functions when 'RESHADE_API_LIBRARY' is defined instead of using header-only mode #if defined(RESHADE_API_LIBRARY) || defined(RESHADE_API_LIBRARY_EXPORT) #ifdef RESHADE_API_LIBRARY_EXPORT #define RESHADE_API_LIBRARY_DECLSPEC extern "C" __declspec(dllexport) #else #define RESHADE_API_LIBRARY_DECLSPEC extern "C" __declspec(dllimport) #endif RESHADE_API_LIBRARY_DECLSPEC void ReShadeLogMessage(HMODULE module, int level, const char *message); RESHADE_API_LIBRARY_DECLSPEC void ReShadeGetBasePath(char *path, size_t *path_size); RESHADE_API_LIBRARY_DECLSPEC bool ReShadeGetConfigValue(HMODULE module, reshade::api::effect_runtime *runtime, const char *section, const char *key, char *value, size_t *value_size); RESHADE_API_LIBRARY_DECLSPEC void ReShadeSetConfigValue(HMODULE module, reshade::api::effect_runtime *runtime, const char *section, const char *key, const char *value); RESHADE_API_LIBRARY_DECLSPEC bool ReShadeRegisterAddon(HMODULE module, uint32_t api_version); RESHADE_API_LIBRARY_DECLSPEC void ReShadeUnregisterAddon(HMODULE module); RESHADE_API_LIBRARY_DECLSPEC void ReShadeRegisterEvent(reshade::addon_event ev, void *callback); RESHADE_API_LIBRARY_DECLSPEC void ReShadeUnregisterEvent(reshade::addon_event ev, void *callback); RESHADE_API_LIBRARY_DECLSPEC void ReShadeRegisterOverlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime)); RESHADE_API_LIBRARY_DECLSPEC void ReShadeUnregisterOverlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime)); #else // Use the kernel32 variant of module enumeration functions so it can be safely called from 'DllMain' extern "C" BOOL WINAPI K32EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded); namespace reshade { namespace internal { /// /// Gets the handle to the ReShade module. /// inline HMODULE get_reshade_module_handle(HMODULE reshade_module = nullptr) { static HMODULE handle = reshade_module; if (handle == nullptr) { HMODULE modules[1024]; DWORD num = 0; if (K32EnumProcessModules(GetCurrentProcess(), modules, sizeof(modules), &num)) { if (num > sizeof(modules)) num = sizeof(modules); for (DWORD i = 0; i < num / sizeof(HMODULE); ++i) { if (GetProcAddress(modules[i], "ReShadeRegisterAddon") && GetProcAddress(modules[i], "ReShadeUnregisterAddon")) { handle = modules[i]; break; } } } } return handle; } /// /// Gets the handle to the current add-on module. /// inline HMODULE get_current_module_handle(HMODULE addon_module = nullptr) { static HMODULE handle = addon_module; return handle; } } } #endif namespace reshade { /// /// Available log severity levels. /// enum class log_level { error = 1, warning = 2, info = 3, debug = 4 }; /// /// Writes a message to ReShade's log. /// /// Severity level. /// A null-terminated message string. inline void log_message(log_level level, const char *message) { #if defined(RESHADE_API_LIBRARY) || defined(RESHADE_API_LIBRARY_EXPORT) ReShadeLogMessage(nullptr, static_cast(level), message); #else static const auto func = reinterpret_cast( GetProcAddress(internal::get_reshade_module_handle(), "ReShadeLogMessage")); func(internal::get_current_module_handle(), static_cast(level), message); #endif } /// /// Gets the file path ReShade uses to resolve relative paths. /// /// Pointer to a string buffer that is filled with the file path to the preset, or to query the necessary size. /// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator. inline void get_reshade_base_path(char *path, size_t *path_size) { #if defined(RESHADE_API_LIBRARY) || defined(RESHADE_API_LIBRARY_EXPORT) ReShadeGetBasePath(path, path_size); #else static const auto func = reinterpret_cast( GetProcAddress(internal::get_reshade_module_handle(), "ReShadeGetBasePath")); func(path, path_size); #endif } /// /// Gets a value from one of ReShade's config files. /// /// Optional effect runtime to use the config file from, or to use the global config file. /// Name of the config section. /// Name of the config value. /// Pointer to a string buffer that is filled with the config value, or to query the necessary size. /// Pointer to an integer that contains the size of the string buffer and is set to the actual length of the string, including the null-terminator. /// if the specified config value exists, otherwise. inline bool get_config_value(api::effect_runtime *runtime, const char *section, const char *key, char *value, size_t *value_size) { #if defined(RESHADE_API_LIBRARY) || defined(RESHADE_API_LIBRARY_EXPORT) return ReShadeGetConfigValue(nullptr, runtime, section, key, value, value_size); #else static const auto func = reinterpret_cast( GetProcAddress(internal::get_reshade_module_handle(), "ReShadeGetConfigValue")); return func(internal::get_current_module_handle(), runtime, section, key, value, value_size); #endif } #if _HAS_CXX17 template inline bool get_config_value(api::effect_runtime *runtime, const char *section, const char *key, T &value) { char value_string[32]; size_t value_length = sizeof(value_string) - 1; if (!get_config_value(runtime, section, key, value_string, &value_length)) return false; return std::from_chars(value_string, value_string + value_length, value).ec == std::errc {}; } template <> inline bool get_config_value(api::effect_runtime *runtime, const char *section, const char *key, bool &value) { int value_int = 0; if (!get_config_value(runtime, section, key, value_int)) return false; value = (value_int != 0); return true; } #endif /// /// Sets and saves a value in one of ReShade's config files. /// /// Optional effect runtime to use the config file from, or to use the global config file. /// Name of the config section. /// Name of the config value. /// Config value to set. inline void set_config_value(api::effect_runtime *runtime, const char *section, const char *key, const char *value) { #if defined(RESHADE_API_LIBRARY) || defined(RESHADE_API_LIBRARY_EXPORT) ReShadeSetConfigValue(nullptr, runtime, section, key, value); #else static const auto func = reinterpret_cast( GetProcAddress(internal::get_reshade_module_handle(), "ReShadeSetConfigValue")); func(internal::get_current_module_handle(), runtime, section, key, value); #endif } #if _HAS_CXX17 template inline void set_config_value(api::effect_runtime *runtime, const char *section, const char *key, const T &value) { char value_string[32] = ""; std::to_chars(value_string, value_string + sizeof(value_string) - 1, value); set_config_value(runtime, section, key, static_cast(value_string)); } template <> inline void set_config_value(api::effect_runtime *runtime, const char *section, const char *key, const bool &value) { set_config_value(runtime, section, key, value ? 1 : 0); } #endif /// /// Registers this module as an add-on with ReShade. /// Call this in 'AddonInit' or 'DllMain' during process attach, before any of the other API functions! /// /// Handle of the current module. /// Handle of the ReShade module in the process, or to find it automatically. inline bool register_addon(HMODULE addon_module, [[maybe_unused]] HMODULE reshade_module = nullptr) { #if defined(RESHADE_API_LIBRARY) || (defined(RESHADE_API_LIBRARY_EXPORT) && RESHADE_ADDON) return ReShadeRegisterAddon(addon_module, RESHADE_API_VERSION); #elif !defined(RESHADE_API_LIBRARY_EXPORT) addon_module = internal::get_current_module_handle(addon_module); reshade_module = internal::get_reshade_module_handle(reshade_module); if (reshade_module == nullptr) return false; const auto func = reinterpret_cast( GetProcAddress(reshade_module, "ReShadeRegisterAddon")); // Check that the ReShade module supports the used API if (func == nullptr || !func(addon_module, RESHADE_API_VERSION)) return false; #if defined(IMGUI_VERSION_NUM) const auto imgui_func = reinterpret_cast( GetProcAddress(reshade_module, "ReShadeGetImGuiFunctionTable")); // Check that the ReShade module was built with Dear ImGui support and supports the used version if (imgui_func == nullptr || !(imgui_function_table_instance() = imgui_func(IMGUI_VERSION_NUM))) return false; #endif return true; #else UNREFERENCED_PARAMETER(addon_module); UNREFERENCED_PARAMETER(reshade_module); return false; #endif } /// /// Unregisters this module. /// Call this in 'AddonUninit' or 'DllMain' during process detach, after any of the other API functions. /// /// Handle of the current module. /// Handle of the ReShade module in the process, or to find it automatically. inline void unregister_addon(HMODULE addon_module, [[maybe_unused]] HMODULE reshade_module = nullptr) { #if defined(RESHADE_API_LIBRARY) || (defined(RESHADE_API_LIBRARY_EXPORT) && RESHADE_ADDON) ReShadeUnregisterAddon(addon_module); #elif !defined(RESHADE_API_LIBRARY_EXPORT) addon_module = internal::get_current_module_handle(addon_module); reshade_module = internal::get_reshade_module_handle(reshade_module); if (reshade_module == nullptr) return; const auto func = reinterpret_cast( GetProcAddress(reshade_module, "ReShadeUnregisterAddon")); if (func != nullptr) func(addon_module); #else UNREFERENCED_PARAMETER(addon_module); UNREFERENCED_PARAMETER(reshade_module); #endif } /// /// Registers a callback for the specified event (via template) with ReShade. /// The callback function is then called whenever the application performs a task associated with this event (see also the enumeration). /// /// Pointer to the callback function. template inline void register_event(typename reshade::addon_event_traits::decl callback) { #if defined(RESHADE_API_LIBRARY) || (defined(RESHADE_API_LIBRARY_EXPORT) && RESHADE_ADDON) ReShadeRegisterEvent(ev, static_cast(callback)); #elif !defined(RESHADE_API_LIBRARY_EXPORT) static const auto func = reinterpret_cast( GetProcAddress(internal::get_reshade_module_handle(), "ReShadeRegisterEvent")); if (func != nullptr) func(ev, static_cast(callback)); #else UNREFERENCED_PARAMETER(callback); #endif } /// /// Unregisters a callback for the specified event (via template) that was previously registered via . /// /// Pointer to the callback function. template inline void unregister_event(typename reshade::addon_event_traits::decl callback) { #if defined(RESHADE_API_LIBRARY) || (defined(RESHADE_API_LIBRARY_EXPORT) && RESHADE_ADDON) ReShadeUnregisterEvent(ev, static_cast(callback)); #elif !defined(RESHADE_API_LIBRARY_EXPORT) static const auto func = reinterpret_cast( GetProcAddress(internal::get_reshade_module_handle(), "ReShadeUnregisterEvent")); if (func != nullptr) func(ev, static_cast(callback)); #else UNREFERENCED_PARAMETER(callback); #endif } /// /// Registers an overlay with ReShade. /// The callback function is then called when the overlay is visible and allows adding Dear ImGui widgets for user interaction. /// /// Null-terminated title string, or to register a settings overlay for this add-on. /// Pointer to the callback function. inline void register_overlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime)) { #if defined(RESHADE_API_LIBRARY) || (defined(RESHADE_API_LIBRARY_EXPORT) && RESHADE_ADDON && RESHADE_GUI) ReShadeRegisterOverlay(title, callback); #elif !defined(RESHADE_API_LIBRARY_EXPORT) static const auto func = reinterpret_cast( GetProcAddress(internal::get_reshade_module_handle(), "ReShadeRegisterOverlay")); if (func != nullptr) func(title, callback); #else UNREFERENCED_PARAMETER(title); UNREFERENCED_PARAMETER(callback); #endif } /// /// Unregisters an overlay that was previously registered via . /// /// Null-terminated title string. /// Pointer to the callback function. inline void unregister_overlay(const char *title, void(*callback)(reshade::api::effect_runtime *runtime)) { #if defined(RESHADE_API_LIBRARY) || (defined(RESHADE_API_LIBRARY_EXPORT) && RESHADE_ADDON && RESHADE_GUI) ReShadeUnregisterOverlay(title, callback); #elif !defined(RESHADE_API_LIBRARY_EXPORT) static const auto func = reinterpret_cast( GetProcAddress(internal::get_reshade_module_handle(), "ReShadeUnregisterOverlay")); if (func != nullptr) func(title, callback); #else UNREFERENCED_PARAMETER(title); UNREFERENCED_PARAMETER(callback); #endif } }