Skip to content

Commit cf38659

Browse files
fix(audio-info): crash when device name contains special characters
1 parent 31f87bb commit cf38659

File tree

11 files changed

+587
-41
lines changed

11 files changed

+587
-41
lines changed

cmake/compile_definitions/windows.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ set(PLATFORM_TARGET_FILES
5959
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_ram.cpp"
6060
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_wgc.cpp"
6161
"${CMAKE_SOURCE_DIR}/src/platform/windows/audio.cpp"
62+
"${CMAKE_SOURCE_DIR}/src/platform/windows/tools/helper.h"
6263
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/src/ViGEmClient.cpp"
6364
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include/ViGEm/Client.h"
6465
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include/ViGEm/Common.h"

src/platform/windows/input.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#define WINVER 0x0A00
66

77
// platform includes
8-
#include <windows.h>
8+
#include <Windows.h>
99

1010
// standard includes
1111
#include <cmath>

src/platform/windows/misc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include <timeapi.h>
2525
#include <userenv.h>
2626
#include <winsock2.h>
27-
#include <windows.h>
27+
#include <Windows.h>
2828
#include <winuser.h>
2929
#include <wlanapi.h>
3030
#include <ws2tcpip.h>

src/platform/windows/misc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <string_view>
1010

1111
// platform includes
12-
#include <windows.h>
12+
#include <Windows.h>
1313
#include <winnt.h>
1414

1515
namespace platf {

src/platform/windows/nvprefs/nvprefs_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// platform includes
88
// disable clang-format header reordering
99
// clang-format off
10-
#include <windows.h>
10+
#include <Windows.h>
1111
#include <aclapi.h>
1212
// clang-format on
1313

src/platform/windows/publish.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// winsock2.h must be included before windows.h
77
// clang-format off
88
#include <winsock2.h>
9-
#include <windows.h>
9+
#include <Windows.h>
1010
// clang-format on
1111
#include <windns.h>
1212
#include <winerror.h>
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/**
2+
* @file src/platform/windows/tools/helper.h
3+
* @brief Helpers for tools.
4+
*/
5+
#pragma once
6+
7+
// standard includes
8+
#include <iostream>
9+
#include <string>
10+
11+
// lib includes
12+
#include <boost/locale.hpp>
13+
#include <boost/locale/conversion.hpp>
14+
15+
// platform includes
16+
#include <Windows.h>
17+
18+
/**
19+
* @brief Safe console output utilities for Windows
20+
* These functions prevent crashes when outputting strings with special characters.
21+
* This is only used in tools/audio-info and tools/dxgi-info.
22+
*/
23+
namespace output {
24+
/**
25+
* @brief Return a non-null wide string, defaulting to "Unknown" if null
26+
* @param str The wide string to check
27+
* @return A non-null wide string
28+
*/
29+
inline const wchar_t *no_null(const wchar_t *str) {
30+
return str ? str : L"Unknown";
31+
}
32+
33+
/**
34+
* @brief Safely convert a wide string to console output using Windows API
35+
* @param wstr The wide string to output
36+
*/
37+
inline void safe_wcout(const std::wstring &wstr) {
38+
if (wstr.empty()) {
39+
return;
40+
}
41+
42+
// Try to use the Windows console API for proper Unicode output
43+
if (HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); hConsole != INVALID_HANDLE_VALUE) {
44+
DWORD written;
45+
if (WriteConsoleW(hConsole, wstr.c_str(), static_cast<DWORD>(wstr.length()), &written, nullptr)) {
46+
return; // Success with WriteConsoleW
47+
}
48+
}
49+
50+
// Fallback: convert to narrow string and output to std::cout
51+
try {
52+
std::string narrow_str = boost::locale::conv::utf_to_utf<char>(wstr);
53+
std::cout << narrow_str;
54+
} catch (const boost::locale::conv::conversion_error &) {
55+
// Final fallback: output character by character, replacing non-ASCII
56+
for (wchar_t wc : wstr) {
57+
if (wc >= 32 && wc < 127) { // Printable ASCII
58+
std::cout << static_cast<char>(wc);
59+
} else {
60+
std::cout << '?';
61+
}
62+
}
63+
}
64+
}
65+
66+
/**
67+
* @brief Safely convert a wide string literal to console encoding and output it
68+
* @param wstr The wide string literal to output
69+
*/
70+
inline void safe_wcout(const wchar_t *wstr) {
71+
if (wstr) {
72+
safe_wcout(std::wstring(wstr));
73+
} else {
74+
std::cout << "Unknown";
75+
}
76+
}
77+
78+
/**
79+
* @brief Safely convert a string to wide string and then to console output
80+
* @param str The string to output
81+
*/
82+
inline void safe_cout(const std::string &str) {
83+
if (str.empty()) {
84+
return;
85+
}
86+
87+
try {
88+
// Convert string to wide string first, then to console output
89+
std::wstring wstr = boost::locale::conv::utf_to_utf<wchar_t>(str);
90+
safe_wcout(wstr);
91+
} catch (const boost::locale::conv::conversion_error &) {
92+
// Fallback: output string directly, replacing problematic characters
93+
for (char c : str) {
94+
if (c >= 32 && c < 127) { // Printable ASCII
95+
std::cout << c;
96+
} else {
97+
std::cout << '?';
98+
}
99+
}
100+
}
101+
}
102+
103+
/**
104+
* @brief Output a label and value pair safely
105+
* @param label The label to output
106+
* @param value The wide string value to output
107+
*/
108+
inline void output_field(const std::string &label, const wchar_t *value) {
109+
std::cout << label << " : ";
110+
safe_wcout(value ? value : L"Unknown");
111+
std::cout << std::endl;
112+
}
113+
114+
/**
115+
* @brief Output a label and string value pair
116+
* @param label The label to output
117+
* @param value The string value to output
118+
*/
119+
inline void output_field(const std::string &label, const std::string &value) {
120+
std::cout << label << " : ";
121+
safe_cout(value);
122+
std::cout << std::endl;
123+
}
124+
} // namespace output

0 commit comments

Comments
 (0)