Skip to content

Commit 216a0dc

Browse files
3vcloudclaude
andcommitted
fix(window-title): stop mojibake when setting GW window title to char name
GetPlayerName() fell back to CharContext::player_name, a fixed-size buffer that isn't always null-terminated yet (e.g. still on the login screen), and read it unbounded via wcslen — running off into unrelated memory and rendering as garbled/CJK-looking text. Bound the read and return empty instead of garbage. Also send WM_SETTEXT via DefWindowProcW instead of SetWindowTextW when setting the title on GW's own HWND, since that window may be an ANSI window class, which would otherwise thunk the string through the system codepage. Same trick already used for our own windows in imgui_impl_win32.cpp. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 76758db commit 216a0dc

2 files changed

Lines changed: 16 additions & 3 deletions

File tree

GWToolboxdll/Modules/GameSettings.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ namespace {
8686
}
8787
const std::wstring title = GetPlayerName();
8888
if (!title.empty()) {
89-
SetWindowTextW(hwnd, title.c_str());
89+
// Guild Wars' window may be registered as an ANSI (non-Unicode) window class; in that
90+
// case SetWindowTextW() gets thunked down to the system codepage before being applied,
91+
// corrupting any character outside it. Sending WM_SETTEXT via DefWindowProcW directly
92+
// bypasses that thunking, same trick already used for our own windows in imgui_impl_win32.cpp.
93+
DefWindowProcW(hwnd, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(title.c_str()));
9094
}
9195
}
9296

GWToolboxdll/Utils/ToolboxUtils.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,9 +1004,18 @@ namespace ToolboxUtils {
10041004
if (!player_number) {
10051005
player = GW::PlayerMgr::GetPlayerByID(GW::PlayerMgr::GetPlayerNumber());
10061006
if (!player || !player->name) {
1007-
// Map not loaded; try to get from character context
1007+
// Map not loaded; try to get from character context.
1008+
// player_name is a fixed-size buffer that may not be populated/null-terminated
1009+
// yet (e.g. still on the login/char select screen); reading it unbounded via
1010+
// wcslen can run off into unrelated memory and produce garbled (often CJK-looking)
1011+
// output. Bail out to an empty string instead so callers retry later.
10081012
const auto c = GW::GetCharContext();
1009-
return c ? c->player_name : L"";
1013+
if (!c) {
1014+
return L"";
1015+
}
1016+
constexpr size_t max_len = sizeof(c->player_name) / sizeof(c->player_name[0]);
1017+
const size_t len = wcsnlen(c->player_name, max_len);
1018+
return len < max_len ? std::wstring(c->player_name, len) : L"";
10101019
}
10111020
}
10121021
else {

0 commit comments

Comments
 (0)