| 515 | } |
| 516 | |
| 517 | void reshade::hooks::register_module(const std::filesystem::path &target_path) |
| 518 | { |
| 519 | #ifndef RESHADE_TEST_APPLICATION |
| 520 | if (s_dll_notification_cookie == nullptr) |
| 521 | { |
| 522 | const auto ntdll_module = GetModuleHandleW(L"ntdll.dll"); |
| 523 | assert(ntdll_module != nullptr); |
| 524 | |
| 525 | const auto LdrRegisterDllNotification = reinterpret_cast<LONG (NTAPI *)(ULONG Flags, FARPROC NotificationFunction, PVOID Context, PVOID *Cookie)>(GetProcAddress(ntdll_module, "LdrRegisterDllNotification")); |
| 526 | if (LdrRegisterDllNotification == nullptr || |
| 527 | // The Steam overlay is using 'LoadLibrary' hooks, so always use them too if it is used, to ensure that ReShade installs hooks after the Steam overlay already did so |
| 528 | // Detect whether the Steam overlay is used by checking for a 'SteamOverlayGameId' environment variable that Steam sets, instead of looking for 'GameOverlayRenderer[64].dll', since ReShade may be injected before the Steam overlay DLL |
| 529 | GetEnvironmentVariableW(L"SteamOverlayGameId", nullptr, 0) || |
| 530 | LdrRegisterDllNotification(0, reinterpret_cast<FARPROC>(&DllNotificationCallback), nullptr, &s_dll_notification_cookie) != 0 /* STATUS_SUCCESS */) |
| 531 | { |
| 532 | #if RESHADE_VERBOSE_LOG |
| 533 | log::message(log::level::debug, "Using LoadLibrary hooks."); |
| 534 | #endif |
| 535 | |
| 536 | // Fall back 'LoadLibrary' hooks if DLL notification registration failed or the Steam overlay is used |
| 537 | // Skip this in the test application to make RenderDoc work (which hooks these too) |
| 538 | install("LoadLibraryA", reinterpret_cast<hook::address>(&LoadLibraryA), reinterpret_cast<hook::address>(&HookLoadLibraryA), true); |
| 539 | install("LoadLibraryExA", reinterpret_cast<hook::address>(&LoadLibraryExA), reinterpret_cast<hook::address>(&HookLoadLibraryExA), true); |
| 540 | install("LoadLibraryW", reinterpret_cast<hook::address>(&LoadLibraryW), reinterpret_cast<hook::address>(&HookLoadLibraryW), true); |
| 541 | install("LoadLibraryExW", reinterpret_cast<hook::address>(&LoadLibraryExW), reinterpret_cast<hook::address>(&HookLoadLibraryExW), true); |
| 542 | |
| 543 | // Install all 'LoadLibrary' hooks in one go immediately |
| 544 | if (hook::apply_queued_actions()) |
| 545 | s_dll_notification_cookie = reinterpret_cast<PVOID>(-1); // Set cookie to something so that these hooks are only installed once |
| 546 | else |
| 547 | log::message(log::level::error, "Failed to install LoadLibrary hooks!"); |
| 548 | } |
| 549 | } |
| 550 | #endif |
| 551 | |
| 552 | log::message(log::level::info, "Registering hooks for '%s' ...", target_path.u8string().c_str()); |
| 553 | |
| 554 | // Compare module names and delay export hooks for later installation since we cannot call 'LoadLibrary' from this function (it is called from 'DLLMain', which does not allow this) |
| 555 | // Do a case insensitive comparison here to catch cases like "OPENGL32" refering to the same module as "opengl32.dll" |
| 556 | assert(target_path.extension() == L".dll"); |
| 557 | const std::filesystem::path target_name = target_path.filename(); |
| 558 | const std::filesystem::path replacement_name = g_reshade_dll_path.filename(); |
| 559 | if (_wcsicmp(target_name.c_str(), replacement_name.c_str()) == 0) |
| 560 | { |
| 561 | assert(target_path != g_reshade_dll_path && target_path.is_absolute()); |
| 562 | |
| 563 | if (!s_export_module_path.empty()) |
| 564 | { |
| 565 | log::message(log::level::info, "> Skipped."); |
| 566 | } |
| 567 | else |
| 568 | { |
| 569 | log::message(log::level::info, "> Delayed until first call to an exported function."); |
| 570 | |
| 571 | register_export_module(target_path); |
| 572 | |
| 573 | // Register for function hooking as well, in case a third party (like NVIDIA Streamline) explicitly loads the system library between now and the first call to an exported function |
| 574 | s_delayed_hook_paths.push_back(target_path); |
nothing calls this directly
no test coverage detected