Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmake/compile_definitions/windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ set(PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_ram.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_wgc.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/audio.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/utf_utils.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/utf_utils.h"
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/src/ViGEmClient.cpp"
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include/ViGEm/Client.h"
"${CMAKE_SOURCE_DIR}/third-party/ViGEmClient/include/ViGEm/Common.h"
Expand Down
14 changes: 7 additions & 7 deletions src/platform/windows/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
#include <synchapi.h>

// local includes
#include "misc.h"
#include "src/config.h"
#include "src/logging.h"
#include "src/platform/common.h"
#include "utf_utils.h"

// Must be the last included file
// clang-format off
Expand Down Expand Up @@ -697,7 +697,7 @@ namespace platf::audio {
audio::wstring_t id;
device->GetId(&id);

sink.host = to_utf8(id.get());
sink.host = utf_utils::to_utf8(id.get());
}

// Prepare to search for the device_id of the virtual audio sink device,
Expand All @@ -707,14 +707,14 @@ namespace platf::audio {
if (config::audio.virtual_sink.empty()) {
match_list = match_steam_speakers();
} else {
match_list = match_all_fields(from_utf8(config::audio.virtual_sink));
match_list = match_all_fields(utf_utils::from_utf8(config::audio.virtual_sink));
}

// Search for the virtual audio sink device currently present in the system.
auto matched = find_device_id(match_list);
if (matched) {
// Prepare to fill virtual audio sink names with device_id.
auto device_id = to_utf8(matched->second);
auto device_id = utf_utils::to_utf8(matched->second);
// Also prepend format name (basically channel layout at the moment)
// because we don't want to extend the platform interface.
sink.null = std::make_optional(sink_t::null_t {
Expand All @@ -730,7 +730,7 @@ namespace platf::audio {
}

bool is_sink_available(const std::string &sink) override {
const auto match_list = match_all_fields(from_utf8(sink));
const auto match_list = match_all_fields(utf_utils::from_utf8(sink));
const auto matched = find_device_id(match_list);
return static_cast<bool>(matched);
}
Expand All @@ -752,7 +752,7 @@ namespace platf::audio {
for (const auto &format : formats) {
auto &name = format.name;
if (current.find(name) == 0) {
auto device_id = from_utf8(current.substr(name.size(), current.size() - name.size()));
auto device_id = utf_utils::from_utf8(current.substr(name.size(), current.size() - name.size()));
return std::make_pair(device_id, std::reference_wrapper(format));
}
}
Expand Down Expand Up @@ -799,7 +799,7 @@ namespace platf::audio {
// Sink name does not begin with virtual-(format name), hence it's not a virtual sink
// and we don't want to change playback format of the corresponding device.
// Also need to perform matching, sink name is not necessarily device_id in this case.
auto matched = find_device_id(match_all_fields(from_utf8(sink)));
auto matched = find_device_id(match_all_fields(utf_utils::from_utf8(sink)));
if (matched) {
return matched->second;
} else {
Expand Down
13 changes: 8 additions & 5 deletions src/platform/windows/display_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#include <boost/process/v1.hpp>
#include <MinHook.h>

// local includes
#include "utf_utils.h"

// We have to include boost/process/v1.hpp before display.h due to WinSock.h,
// but that prevents the definition of NTSTATUS so we must define it ourself.
typedef long NTSTATUS;
Expand Down Expand Up @@ -464,8 +467,8 @@ namespace platf::dxgi {
return -1;
}

auto adapter_name = from_utf8(config::video.adapter_name);
auto output_name = from_utf8(display_name);
auto adapter_name = utf_utils::from_utf8(config::video.adapter_name);
auto output_name = utf_utils::from_utf8(display_name);

adapter_t::pointer adapter_p;
for (int tries = 0; tries < 2; ++tries) {
Expand Down Expand Up @@ -579,7 +582,7 @@ namespace platf::dxgi {
DXGI_ADAPTER_DESC adapter_desc;
adapter->GetDesc(&adapter_desc);

auto description = to_utf8(adapter_desc.Description);
auto description = utf_utils::to_utf8(adapter_desc.Description);
BOOST_LOG(info)
<< std::endl
<< "Device Description : " << description << std::endl
Expand Down Expand Up @@ -1051,7 +1054,7 @@ namespace platf {
BOOST_LOG(debug)
<< std::endl
<< "====== ADAPTER ====="sv << std::endl
<< "Device Name : "sv << to_utf8(adapter_desc.Description) << std::endl
<< "Device Name : "sv << utf_utils::to_utf8(adapter_desc.Description) << std::endl
<< "Device Vendor ID : 0x"sv << util::hex(adapter_desc.VendorId).to_string_view() << std::endl
<< "Device Device ID : 0x"sv << util::hex(adapter_desc.DeviceId).to_string_view() << std::endl
<< "Device Video Mem : "sv << adapter_desc.DedicatedVideoMemory / 1048576 << " MiB"sv << std::endl
Expand All @@ -1067,7 +1070,7 @@ namespace platf {
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);

auto device_name = to_utf8(desc.DeviceName);
auto device_name = utf_utils::to_utf8(desc.DeviceName);

auto width = desc.DesktopCoordinates.right - desc.DesktopCoordinates.left;
auto height = desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top;
Expand Down
3 changes: 2 additions & 1 deletion src/platform/windows/display_vram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extern "C" {
#include "src/nvenc/nvenc_d3d11_on_cuda.h"
#include "src/nvenc/nvenc_utils.h"
#include "src/video.h"
#include "utf_utils.h"

#if !defined(SUNSHINE_SHADERS_DIR) // for testing this needs to be defined in cmake as we don't do an install
#define SUNSHINE_SHADERS_DIR SUNSHINE_ASSETS_DIR "/shaders/directx"
Expand Down Expand Up @@ -359,7 +360,7 @@ namespace platf::dxgi {
flags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#endif

auto wFile = from_utf8(file);
auto wFile = utf_utils::from_utf8(file);
auto status = D3DCompileFromFile(wFile.c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, entrypoint, shader_model, flags, 0, &compiled_p, &msg_p);

if (msg_p) {
Expand Down
79 changes: 14 additions & 65 deletions src/platform/windows/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "src/logging.h"
#include "src/platform/common.h"
#include "src/utility.h"
#include "utf_utils.h"

// UDP_SEND_MSG_SIZE was added in the Windows 10 20H1 SDK
#ifndef UDP_SEND_MSG_SIZE
Expand Down Expand Up @@ -314,7 +315,7 @@ namespace platf {
// Parse the environment block and populate env
for (auto c = (PWCHAR) env_block; *c != UNICODE_NULL; c += wcslen(c) + 1) {
// Environment variable entries end with a null-terminator, so std::wstring() will get an entire entry.
std::string env_tuple = to_utf8(std::wstring {c});
std::string env_tuple = utf_utils::to_utf8(std::wstring {c});
std::string env_name = env_tuple.substr(0, env_tuple.find('='));
std::string env_val = env_tuple.substr(env_tuple.find('=') + 1);

Expand Down Expand Up @@ -384,7 +385,7 @@ namespace platf {
for (const auto &entry : env) {
auto name = entry.get_name();
auto value = entry.to_string();
size += from_utf8(name).length() + 1 /* L'=' */ + from_utf8(value).length() + 1 /* L'\0' */;
size += utf_utils::from_utf8(name).length() + 1 /* L'=' */ + utf_utils::from_utf8(value).length() + 1 /* L'\0' */;
}

size += 1 /* L'\0' */;
Expand All @@ -396,9 +397,9 @@ namespace platf {
auto value = entry.to_string();

// Construct the NAME=VAL\0 string
append_string_to_environment_block(env_block, offset, from_utf8(name));
append_string_to_environment_block(env_block, offset, utf_utils::from_utf8(name));
env_block[offset++] = L'=';
append_string_to_environment_block(env_block, offset, from_utf8(value));
append_string_to_environment_block(env_block, offset, utf_utils::from_utf8(value));
env_block[offset++] = L'\0';
}

Expand Down Expand Up @@ -676,14 +677,14 @@ namespace platf {
* @return A command string suitable for use by CreateProcess().
*/
std::wstring resolve_command_string(const std::string &raw_cmd, const std::wstring &working_dir, HANDLE token, DWORD &creation_flags) {
std::wstring raw_cmd_w = from_utf8(raw_cmd);
std::wstring raw_cmd_w = utf_utils::from_utf8(raw_cmd);

// First, convert the given command into parts so we can get the executable/file/URL without parameters
auto raw_cmd_parts = boost::program_options::split_winmain(raw_cmd_w);
if (raw_cmd_parts.empty()) {
// This is highly unexpected, but we'll just return the raw string and hope for the best.
BOOST_LOG(warning) << "Failed to split command string: "sv << raw_cmd;
return from_utf8(raw_cmd);
return utf_utils::from_utf8(raw_cmd);
}

auto raw_target = raw_cmd_parts.at(0);
Expand All @@ -697,7 +698,7 @@ namespace platf {
res = UrlGetPartW(raw_target.c_str(), scheme.data(), &out_len, URL_PART_SCHEME, 0);
if (res != S_OK) {
BOOST_LOG(warning) << "Failed to extract URL scheme from URL: "sv << raw_target << " ["sv << util::hex(res).to_string_view() << ']';
return from_utf8(raw_cmd);
return utf_utils::from_utf8(raw_cmd);
}

// If the target is a URL, the class is found using the URL scheme (prior to and not including the ':')
Expand All @@ -708,13 +709,13 @@ namespace platf {
if (extension == nullptr || *extension == 0) {
// If the file has no extension, assume it's a command and allow CreateProcess()
// to try to find it via PATH
return from_utf8(raw_cmd);
return utf_utils::from_utf8(raw_cmd);
} else if (boost::iequals(extension, L".exe")) {
// If the file has an .exe extension, we will bypass the resolution here and
// directly pass the unmodified command string to CreateProcess(). The argument
// escaping rules are subtly different between CreateProcess() and ShellExecute(),
// and we want to preserve backwards compatibility with older configs.
return from_utf8(raw_cmd);
return utf_utils::from_utf8(raw_cmd);
}

// For regular files, the class is found using the file extension (including the dot)
Expand All @@ -731,7 +732,7 @@ namespace platf {

// Override HKEY_CLASSES_ROOT and HKEY_CURRENT_USER to ensure we query the correct class info
if (!override_per_user_predefined_keys(token)) {
return from_utf8(raw_cmd);
return utf_utils::from_utf8(raw_cmd);
}

// Find the command string for the specified class
Expand Down Expand Up @@ -762,7 +763,7 @@ namespace platf {

if (res != S_OK) {
BOOST_LOG(warning) << "Failed to query command string for raw command: "sv << raw_cmd << " ["sv << util::hex(res).to_string_view() << ']';
return from_utf8(raw_cmd);
return utf_utils::from_utf8(raw_cmd);
}

// Finally, construct the real command string that will be passed into CreateProcess().
Expand Down Expand Up @@ -896,7 +897,7 @@ namespace platf {
* @return A `bp::child` object representing the new process, or an empty `bp::child` object if the launch fails.
*/
bp::child run_command(bool elevated, bool interactive, const std::string &cmd, boost::filesystem::path &working_dir, const bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
std::wstring start_dir = from_utf8(working_dir.string());
std::wstring start_dir = utf_utils::from_utf8(working_dir.string());
HANDLE job = group ? group->native_handle() : nullptr;
STARTUPINFOEXW startup_info = create_startup_info(file, job ? &job : nullptr, ec);
PROCESS_INFORMATION process_info;
Expand Down Expand Up @@ -1687,65 +1688,13 @@ namespace platf {
return {};
}

std::wstring from_utf8(const std::string &string) {
// No conversion needed if the string is empty
if (string.empty()) {
return {};
}

// Get the output size required to store the string
auto output_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, string.data(), string.size(), nullptr, 0);
if (output_size == 0) {
auto winerr = GetLastError();
BOOST_LOG(error) << "Failed to get UTF-16 buffer size: "sv << winerr;
return {};
}

// Perform the conversion
std::wstring output(output_size, L'\0');
output_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, string.data(), string.size(), output.data(), output.size());
if (output_size == 0) {
auto winerr = GetLastError();
BOOST_LOG(error) << "Failed to convert string to UTF-16: "sv << winerr;
return {};
}

return output;
}

std::string to_utf8(const std::wstring &string) {
// No conversion needed if the string is empty
if (string.empty()) {
return {};
}

// Get the output size required to store the string
auto output_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string.data(), string.size(), nullptr, 0, nullptr, nullptr);
if (output_size == 0) {
auto winerr = GetLastError();
BOOST_LOG(error) << "Failed to get UTF-8 buffer size: "sv << winerr;
return {};
}

// Perform the conversion
std::string output(output_size, '\0');
output_size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, string.data(), string.size(), output.data(), output.size(), nullptr, nullptr);
if (output_size == 0) {
auto winerr = GetLastError();
BOOST_LOG(error) << "Failed to convert string to UTF-8: "sv << winerr;
return {};
}

return output;
}

std::string get_host_name() {
WCHAR hostname[256];
if (GetHostNameW(hostname, ARRAYSIZE(hostname)) == SOCKET_ERROR) {
BOOST_LOG(error) << "GetHostNameW() failed: "sv << WSAGetLastError();
return "Sunshine"s;
}
return to_utf8(hostname);
return utf_utils::to_utf8(hostname);
}

class win32_high_precision_timer: public high_precision_timer {
Expand Down
14 changes: 0 additions & 14 deletions src/platform/windows/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,4 @@ namespace platf {
int64_t qpc_counter();

std::chrono::nanoseconds qpc_time_difference(int64_t performance_counter1, int64_t performance_counter2);

/**
* @brief Convert a UTF-8 string into a UTF-16 wide string.
* @param string The UTF-8 string.
* @return The converted UTF-16 wide string.
*/
std::wstring from_utf8(const std::string &string);

/**
* @brief Convert a UTF-16 wide string into a UTF-8 string.
* @param string The UTF-16 wide string.
* @return The converted UTF-8 string.
*/
std::string to_utf8(const std::wstring &string);
} // namespace platf
5 changes: 3 additions & 2 deletions src/platform/windows/publish.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "src/nvhttp.h"
#include "src/platform/common.h"
#include "src/thread_safe.h"
#include "utf_utils.h"

#define _FN(x, ret, args) \
typedef ret(*x##_fn) args; \
Expand Down Expand Up @@ -109,8 +110,8 @@ namespace platf::publish {
std::wstring domain {SERVICE_TYPE_DOMAIN.data(), SERVICE_TYPE_DOMAIN.size()};

auto hostname = platf::get_host_name();
auto name = from_utf8(net::mdns_instance_name(hostname) + '.') + domain;
auto host = from_utf8(hostname + ".local");
auto name = utf_utils::from_utf8(net::mdns_instance_name(hostname) + '.') + domain;
auto host = utf_utils::from_utf8(hostname + ".local");

DNS_SERVICE_INSTANCE instance {};
instance.pszInstanceName = name.data();
Expand Down
Loading
Loading