Consolidate the host's UTF-8/wide conversions into util/utf8.hpp

Five files each carried their own copy of the WideCharToMultiByte /
MultiByteToWideChar UTF-8 conversion (injection_panel, audio_overrides,
imgui_layer's to_utf8, main's harness widen, and vk_layer_setup's inline
form). Replace them all with coop::narrow / coop::widen from one header.

audio_panel's image_basename dropped its lossy `c & 0x7F` ASCII mask for
the proper narrow(), so a non-ASCII game exe name is no longer mangled
in log lines.
This commit is contained in:
2026-07-12 09:23:40 +02:00
parent 246289e386
commit 1eee482165
7 changed files with 54 additions and 81 deletions

View File

@@ -9,27 +9,11 @@
#include "coop/dpi.hpp"
#include "coop/tool_paths.hpp"
#include "ui/app_chrome.hpp"
#include "util/utf8.hpp"
namespace coop
{
namespace
{
// ImGui's file IO treats IniFilename as UTF-8 (it converts to wide for _wfopen), so
// the path must be UTF-8 rather than the system ANSI code page.
std::string to_utf8(const std::wstring& w)
{
if (w.empty())
{
return {};
}
const int n = WideCharToMultiByte(CP_UTF8, 0, w.c_str(), static_cast<int>(w.size()), nullptr, 0, nullptr, nullptr);
std::string s(static_cast<std::size_t>(n), '\0');
WideCharToMultiByte(CP_UTF8, 0, w.c_str(), static_cast<int>(w.size()), s.data(), n, nullptr, nullptr);
return s;
}
} // namespace
ImGuiLayer::~ImGuiLayer()
{
if (initialized_)
@@ -52,7 +36,9 @@ bool ImGuiLayer::init(HWND hwnd, ID3D11Device* device, ID3D11DeviceContext* cont
// computed default on startup (which would clobber the restored positions).
const std::wstring ini_w = exe_directory() + L"coop_layout.ini";
const bool had_layout = GetFileAttributesW(ini_w.c_str()) != INVALID_FILE_ATTRIBUTES;
ini_path_ = to_utf8(ini_w);
// ImGui treats IniFilename as UTF-8 (it converts to wide for _wfopen), so narrow to UTF-8, not
// the system ANSI code page.
ini_path_ = narrow(ini_w);
io.IniFilename = ini_path_.c_str();
set_layout_persisted(had_layout);