#include "vk_layer_setup.hpp" #include #include "coop/tool_paths.hpp" namespace coop { namespace { // The Vulkan loader's per-user implicit-layer registry list. Each value is a manifest path; its // DWORD data 0 = enabled. constexpr const wchar_t* kImplicitLayersKey = L"SOFTWARE\\Khronos\\Vulkan\\ImplicitLayers"; std::wstring manifest_path() { return exe_directory() + L"coop_vk_layer.json"; // staged next to coop_host.exe } std::wstring scoping_file() { wchar_t dir[MAX_PATH] = {}; const DWORD n = GetTempPathW(MAX_PATH, dir); return (n != 0 && n < MAX_PATH) ? std::wstring(dir) + L"coop_vk_target.txt" : std::wstring(); } } // namespace bool register_vk_layer(const std::wstring& target_image) { // Write the scoping file (target image basename, UTF-8) the layer checks against its own image. const std::wstring sf = scoping_file(); if (!sf.empty()) { const std::size_t slash = target_image.find_last_of(L"\\/"); const std::wstring base = slash == std::wstring::npos ? target_image : target_image.substr(slash + 1); const int n = WideCharToMultiByte(CP_UTF8, 0, base.c_str(), static_cast(base.size()), nullptr, 0, nullptr, nullptr); std::string utf8(static_cast(n), '\0'); WideCharToMultiByte(CP_UTF8, 0, base.c_str(), static_cast(base.size()), utf8.data(), n, nullptr, nullptr); HANDLE f = CreateFileW(sf.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (f != INVALID_HANDLE_VALUE) { DWORD written = 0; WriteFile(f, utf8.data(), static_cast(utf8.size()), &written, nullptr); CloseHandle(f); } } HKEY key = nullptr; if (RegCreateKeyExW(HKEY_CURRENT_USER, kImplicitLayersKey, 0, nullptr, 0, KEY_SET_VALUE, nullptr, &key, nullptr) != ERROR_SUCCESS) { return false; } const std::wstring mp = manifest_path(); DWORD enabled = 0; // 0 = enabled, per the loader's convention const LONG r = RegSetValueExW(key, mp.c_str(), 0, REG_DWORD, reinterpret_cast(&enabled), sizeof(enabled)); RegCloseKey(key); return r == ERROR_SUCCESS; } void unregister_vk_layer() { HKEY key = nullptr; if (RegOpenKeyExW(HKEY_CURRENT_USER, kImplicitLayersKey, 0, KEY_SET_VALUE, &key) == ERROR_SUCCESS) { RegDeleteValueW(key, manifest_path().c_str()); RegCloseKey(key); } const std::wstring sf = scoping_file(); if (!sf.empty()) { DeleteFileW(sf.c_str()); } } } // namespace coop