If you're reading this from the future, here's what I found out:
TL;DR: Unicode char 8203 wasn't representable in the console codepage, which caused std::wcout
to fail. The solution is to check for std::wcout.fail()
and if true
call std::wcout.clear()
.
Here's how I got to the bottom of it.
I started suspecting it had something to do with std::wcout
because the following code would keep printing even when I switched to Microsoft Edge (and switched tabs within it):
#include <iostream>
#include <Windows.h>
#include <WinUser.h>
int main()
{
// Use environment's default locale for char type
setlocale(LC_CTYPE, "");
while (1)
{
// Get foreground window
HWND hwnd = GetForegroundWindow();
if (!hwnd) continue;
// Get window process ID
DWORD pid = 0;
GetWindowThreadProcessId(hwnd, &pid);
std::cout << "pid " << pid << " ";
// Get window text length
int len = GetWindowTextLength(hwnd);
// Get window text
WCHAR* text = new WCHAR[len + 1];
GetWindowText(hwnd, text, len + 1);
std::cout << "text " << text << std::endl;
text = NULL;
Sleep(1000);
}
return 0;
}

Where:
- PID
3892
- ConsoleApplication1.exe
- PID
3144
- Visual Studio Code
- PID
9812
- Slack
- PID
8772
- Microsoft Edge - with tabs switched during execution (same PID)
The following code, however, would stop printing the text ...
line but keep printing the pid ...
line when I switched to Edge (and switched tabs within it):
// ...
std::wcout << "text " << text << std::endl; // switched 'cout' with 'wcout'
// ...

Where:
- PID
424
- ConsoleApplication1.exe
- PIDs
3144
, 9812
and 8772
same as before
Also, if I switched both pid ...
and text ...
lines to wcout
, then the console output would completely hang as soon as I switched to Edge, clearly showing that the wcout
stream had failed:
// ...
std::wcout << "pid " << pid << " "; // switched 'cout' with 'wcout'
// ...
std::wcout << "text " << text << std::endl; // same
// ...

Where:
- PID
13584
- ConsoleApplication1.exe
- PIDs
3144
, 9812
and 8772
same as before
Now I needed to know what was causing wcout
to fail. Per the console outputs above, wcout
seemed to fail right after the t
in "Microsoft". Invisible faulty char, maybe? So I tweaked the code once more to print both the char and its code:
// ...
// std::wcout << "text " << text << std::endl;
for (int i = 0; i < wcslen(text); i++) std::cout << (char)text[i] << " (" << (int)text[i] << ")\n";

As expected, there was an invisible char right after the t
in Microsoft: Unicode character 8203. Now, finally knowing what to throw on Google (a.k.a. "wcout fail unicode 8203"), I found this and this pivotal answers.
Specifically, the code from @dev7060's comment was the litmus test I needed (here modified):
std::wcout << "abc " << L'\u200b' << " defg" << std::endl; // L'\u200b' is unicode char 8203
if (std::wcout.fail()) {
std::cout << "\nConversion didn't succeed\n";
std::wcout << "This statement has no effect on the console";
std::wcout.clear();
std::wcout << "hello world from wcout! \n";
}
std::cout << "hello world from cout! \n";
std::wcout << "hello world from wcout again! \n";

The solution (so far) is the one below.
// std::wcout << "text " << text << std::endl;
std::wcout << "text " << text;
if (std::wcout.fail()) std::wcout.clear();
std::cout << std::endl;
EDIT: found a new (better?) solution that doesn't involve checking std::wcout.fail()
and calling std::wcout.clear()
:
TL;DR: use setlocale(LC_CTYPE, "en_US.UTF8")
or (in my case) setlocale(LC_CTYPE, "pt_BR.UTF8")
.
I wanted to figure out why the default environment locale (setlocale(LC_CTYPE, "")
) wasn't working, so I devised the following little experiment:
std::cout << "default locale " << setlocale(LC_CTYPE, NULL) << std::endl;
std::cout << "default console output code page " << GetConsoleOutputCP() << std::endl;
setlocale(LC_CTYPE, "pt_BR.UTF8"); // 'method' column from table below
// SetConsoleOutputCP(850)
std::cout << "new locale " << setlocale(LC_CTYPE, NULL) << std::endl;
std::cout << "new console output code page " << GetConsoleOutputCP() << std::endl;
Method |
Default locale |
Default CP |
New locale |
New CP |
wcout fail? |
setlocale(LC_CTYPE, "") |
C |
850 |
Portuguese_Brazil.1252 |
850 |
Yes |
setlocale(LC_CTYPE, "en_US.UTF8") |
C |
850 |
en_US.UTF8 |
850 |
No |
setlocale(LC_CTYPE, "pt_BR.UTF8") |
C |
850 |
pt_BR.UTF8 |
850 |
No |
SetConsoleOutputCP(850) OEM Multilingual Latin 1; Western European (DOS) |
C |
850 |
C |
850 |
Yes |
SetConsoleOutputCP(1252) ANSI Latin 1; Western European (Windows) |
C |
850 |
C |
1252 |
Yes |
SetConsoleOutputCP(65001) Unicode (UTF-8) |
C |
850 |
C |
65001 |
Yes |
In my computer (Windows 10 x86-64), the constants CP_WINANSI
and CP_WINUNICODE
map to 850
and CP_UTF8
to 65001
.
Recommended reading: