diff --git a/src/shared/inc/stringshared.h b/src/shared/inc/stringshared.h index 97c1e19283..7f7d98268c 100644 --- a/src/shared/inc/stringshared.h +++ b/src/shared/inc/stringshared.h @@ -927,81 +927,15 @@ struct std::formatter template auto format(const std::source_location& location, TCtx& ctx) const { - return std::format_to(ctx.out(), L"{}[{}:{}]", location.function_name(), location.file_name(), location.line()); + return std::format_to( + ctx.out(), + L"{}[{}:{}]", + wsl::shared::string::MultiByteToWide(location.function_name()), + wsl::shared::string::MultiByteToWide(location.file_name()), + location.line()); } }; -// char -> wchar_t formatting is only used by the Windows components. libc++ (used to -// build the Linux components) now provides these as deleted specializations per C++23 -// [format.formatter.spec], which would collide, so restrict them to Windows. -#ifdef WIN32 - -template <> -struct std::formatter -{ - template - static constexpr auto parse(TCtx& ctx) - { - return ctx.begin(); - } - - template - auto format(const char* str, TCtx& ctx) const - { - return std::format_to(ctx.out(), "{}", wsl::shared::string::MultiByteToWide(str)); - } -}; - -template <> -struct std::formatter -{ - template - static constexpr auto parse(TCtx& ctx) - { - return ctx.begin(); - } - - template - auto format(const char* str, TCtx& ctx) const - { - return std::format_to(ctx.out(), "{}", wsl::shared::string::MultiByteToWide(str)); - } -}; - -template -struct std::formatter -{ - template - static constexpr auto parse(TCtx& ctx) - { - return ctx.begin(); - } - - template - auto format(const char str[N], TCtx& ctx) const - { - return std::format_to(ctx.out(), "{}", wsl::shared::string::MultiByteToWide(str)); - } -}; - -template -struct std::formatter, wchar_t> -{ - template - static constexpr auto parse(TCtx& ctx) - { - return ctx.begin(); - } - - template - auto format(const std::basic_string& str, TCtx& ctx) const - { - return std::format_to(ctx.out(), "{}", wsl::shared::string::MultiByteToWide(str)); - } -}; - -#endif // WIN32 - template <> struct std::formatter { diff --git a/src/windows/common/WSLCUserSettings.cpp b/src/windows/common/WSLCUserSettings.cpp index b0c3e1e861..9fcf3c5c6c 100644 --- a/src/windows/common/WSLCUserSettings.cpp +++ b/src/windows/common/WSLCUserSettings.cpp @@ -377,8 +377,7 @@ namespace { } catch (const std::exception& e) { - warnings.push_back( - {wsl::shared::Localization::WSLCUserSettings_Warning_ParseError(path.wstring(), MultiByteToWide(e.what())), {}}); + warnings.push_back({wsl::shared::Localization::WSLCUserSettings_Warning_ParseError(path.wstring(), e.what()), {}}); return std::nullopt; } } diff --git a/src/windows/wslc/commands/VersionCommand.cpp b/src/windows/wslc/commands/VersionCommand.cpp index 29ded785ac..24b857a26e 100644 --- a/src/windows/wslc/commands/VersionCommand.cpp +++ b/src/windows/wslc/commands/VersionCommand.cpp @@ -42,7 +42,7 @@ std::wstring VersionCommand::LongDescription() const void VersionCommand::PrintVersion(Reporter& reporter) { - reporter.Output(L"{} {}\n", s_ExecutableName, WSL_PACKAGE_VERSION); + reporter.Output(L"{} {}\n", s_ExecutableName, STRING_TO_WIDE_STRING(WSL_PACKAGE_VERSION)); } void VersionCommand::ExecuteInternal(CLIExecutionContext& context) const diff --git a/src/windows/wslc/services/BuildImageCallback.cpp b/src/windows/wslc/services/BuildImageCallback.cpp index 1f636cedf4..392037da29 100644 --- a/src/windows/wslc/services/BuildImageCallback.cpp +++ b/src/windows/wslc/services/BuildImageCallback.cpp @@ -41,7 +41,7 @@ try { for (const auto& line : m_allLines) { - m_reporter.Info(L"{}", line); + m_reporter.Info(L"{}", wsl::shared::string::MultiByteToWide(line)); } } } @@ -100,7 +100,7 @@ try // Skip pull progress updates when output is redirected, show only major steps if (!isPullProgress) { - m_reporter.Info(L"{}", status); + m_reporter.Info(L"{}", wsl::shared::string::MultiByteToWide(status)); } return S_OK; } diff --git a/src/windows/wslc/services/ContainerModel.cpp b/src/windows/wslc/services/ContainerModel.cpp index baaaa562fb..2916655e55 100644 --- a/src/windows/wslc/services/ContainerModel.cpp +++ b/src/windows/wslc/services/ContainerModel.cpp @@ -27,20 +27,20 @@ PublishPort::PortRange PublishPort::PortRange::ParsePortPart(const std::string& // Ensure the value is not empty and contains only digits before parsing if (value.empty() || !std::all_of(value.begin(), value.end(), ::isdigit)) { - THROW_HR_WITH_USER_ERROR(E_INVALIDARG, errorMessage); + THROW_HR_WITH_USER_ERROR(E_INVALIDARG, MultiByteToWide(errorMessage)); } // Parse the port number and validate the range auto port = std::stoul(value, nullptr, 10); if (!PublishPort::IsValidPort(port)) { - THROW_HR_WITH_USER_ERROR(E_INVALIDARG, errorMessage); + THROW_HR_WITH_USER_ERROR(E_INVALIDARG, MultiByteToWide(errorMessage)); } return static_cast(port); } catch (const std::exception&) { - THROW_HR_WITH_USER_ERROR(E_INVALIDARG, errorMessage); + THROW_HR_WITH_USER_ERROR(E_INVALIDARG, MultiByteToWide(errorMessage)); } }; @@ -84,7 +84,7 @@ PublishPort PublishPort::Parse(const std::string& value) else { THROW_HR_WITH_USER_ERROR( - E_INVALIDARG, "Invalid protocol specified in port mapping. Only 'tcp' and 'udp' are supported."); + E_INVALIDARG, L"Invalid protocol specified in port mapping. Only 'tcp' and 'udp' are supported."); } } @@ -128,24 +128,24 @@ void PublishPort::Validate() const { if (m_containerPort.Count() == 0) { - THROW_HR_WITH_USER_ERROR(E_INVALIDARG, "Container port must specify at least one port."); + THROW_HR_WITH_USER_ERROR(E_INVALIDARG, L"Container port must specify at least one port."); } if (!m_containerPort.IsValid()) { - THROW_HR_WITH_USER_ERROR(E_INVALIDARG, "Container port must be a valid port number (1-65535)."); + THROW_HR_WITH_USER_ERROR(E_INVALIDARG, L"Container port must be a valid port number (1-65535)."); } if (!m_hostPort.IsEphemeral()) { if (!m_hostPort.IsValid()) { - THROW_HR_WITH_USER_ERROR(E_INVALIDARG, "Host port must be a valid port number (1-65535)."); + THROW_HR_WITH_USER_ERROR(E_INVALIDARG, L"Host port must be a valid port number (1-65535)."); } if (m_hostPort.Count() != m_containerPort.Count()) { - THROW_HR_WITH_USER_ERROR(E_INVALIDARG, "Host port range must match the container port range."); + THROW_HR_WITH_USER_ERROR(E_INVALIDARG, L"Host port range must match the container port range."); } } } diff --git a/src/windows/wslc/services/ContainerService.cpp b/src/windows/wslc/services/ContainerService.cpp index b1854faa57..9c20927b3a 100644 --- a/src/windows/wslc/services/ContainerService.cpp +++ b/src/windows/wslc/services/ContainerService.cpp @@ -251,7 +251,7 @@ static wsl::windows::common::RunningWSLCContainer CreateInternal(Reporter& repor // Implicit pull for run/create: progress goes to Info (stderr), keeping stdout for the // container id/output. ImageProgressCallback callback(reporter, Reporter::Level::Info); - reporter.Info(L"{}\n", Localization::WSLCCLI_ImageNotFoundPulling(wsl::shared::string::MultiByteToWide(image))); + reporter.Info(L"{}\n", Localization::WSLCCLI_ImageNotFoundPulling(image)); ImageService imageService; imageService.Pull(reporter, session, image, &callback); } diff --git a/src/windows/wslc/services/FileCredStorage.cpp b/src/windows/wslc/services/FileCredStorage.cpp index 3cf562c691..8e0692100e 100644 --- a/src/windows/wslc/services/FileCredStorage.cpp +++ b/src/windows/wslc/services/FileCredStorage.cpp @@ -229,7 +229,7 @@ void FileCredStorage::Erase(const std::string& serverAddress) }); } - THROW_HR_WITH_USER_ERROR_IF(E_NOT_SET, Localization::WSLCCLI_LogoutNotFound(wsl::shared::string::MultiByteToWide(serverAddress)), !erased); + THROW_HR_WITH_USER_ERROR_IF(E_NOT_SET, Localization::WSLCCLI_LogoutNotFound(serverAddress), !erased); } std::vector FileCredStorage::List() diff --git a/src/windows/wslc/services/ImageProgressCallback.cpp b/src/windows/wslc/services/ImageProgressCallback.cpp index 34c76f5953..b0c10dd7b4 100644 --- a/src/windows/wslc/services/ImageProgressCallback.cpp +++ b/src/windows/wslc/services/ImageProgressCallback.cpp @@ -57,7 +57,7 @@ HRESULT ImageProgressCallback::OnProgress(LPCSTR status, LPCSTR id, ULONGLONG cu { if (id == nullptr || *id == '\0') { - m_reporter.Write(m_level, L"{}\n", status); + m_reporter.Write(m_level, L"{}\n", wsl::shared::string::MultiByteToWide(status)); } else { @@ -65,7 +65,7 @@ HRESULT ImageProgressCallback::OnProgress(LPCSTR status, LPCSTR id, ULONGLONG cu if (inserted || it->second != status) { it->second = status; - m_reporter.Write(m_level, L"{}: {}\n", id, status); + m_reporter.Write(m_level, L"{}: {}\n", wsl::shared::string::MultiByteToWide(id), wsl::shared::string::MultiByteToWide(status)); } } @@ -79,7 +79,7 @@ HRESULT ImageProgressCallback::OnProgress(LPCSTR status, LPCSTR id, ULONGLONG cu if (id == nullptr || *id == '\0') // Print all 'global' statuses on their own line { - m_reporter.Write(m_level, L"{}\n", status); + m_reporter.Write(m_level, L"{}\n", wsl::shared::string::MultiByteToWide(status)); m_currentLine++; return S_OK; } @@ -144,15 +144,20 @@ std::wstring ImageProgressCallback::GenerateStatusLine(LPCSTR status, LPCSTR id, progress += std::format(L"/{}", wsl::shared::string::FormatBytes(total)); } - line = std::format(L"{}: {} [{}] {}", safeId, safeStatus, bar, progress); + line = std::format( + L"{}: {} [{}] {}", wsl::shared::string::MultiByteToWide(safeId), wsl::shared::string::MultiByteToWide(safeStatus), bar, progress); } else if (current != 0) { - line = std::format(L"{}: {} {}", safeId, safeStatus, wsl::shared::string::FormatBytes(current)); + line = std::format( + L"{}: {} {}", + wsl::shared::string::MultiByteToWide(safeId), + wsl::shared::string::MultiByteToWide(safeStatus), + wsl::shared::string::FormatBytes(current)); } else { - line = std::format(L"{}: {}", safeId, safeStatus); + line = std::format(L"{}: {}", wsl::shared::string::MultiByteToWide(safeId), wsl::shared::string::MultiByteToWide(safeStatus)); } // Truncate to the console width to prevent wrapping that breaks cursor repositioning, then pad diff --git a/src/windows/wslc/services/SessionService.cpp b/src/windows/wslc/services/SessionService.cpp index b0ffbaf277..f6ab20abcd 100644 --- a/src/windows/wslc/services/SessionService.cpp +++ b/src/windows/wslc/services/SessionService.cpp @@ -113,7 +113,7 @@ int SessionService::Attach(Reporter& reporter, const Session& session) auto exitCode = process.GetExitCode(); - reporter.Output(L"{}\n", wsl::shared::Localization::MessageWslcShellExited(string::MultiByteToWide(shell), static_cast(exitCode))); + reporter.Output(L"{}\n", wsl::shared::Localization::MessageWslcShellExited(shell, static_cast(exitCode))); return static_cast(exitCode); } diff --git a/src/windows/wslc/services/WinCredStorage.cpp b/src/windows/wslc/services/WinCredStorage.cpp index dfafcea0a1..2c3c573232 100644 --- a/src/windows/wslc/services/WinCredStorage.cpp +++ b/src/windows/wslc/services/WinCredStorage.cpp @@ -82,8 +82,7 @@ void WinCredStorage::Erase(const std::string& serverAddress) if (!CredDeleteW(targetName.c_str(), CRED_TYPE_GENERIC, 0)) { auto error = GetLastError(); - THROW_HR_WITH_USER_ERROR_IF( - E_NOT_SET, Localization::WSLCCLI_LogoutNotFound(wsl::shared::string::MultiByteToWide(serverAddress)), error == ERROR_NOT_FOUND); + THROW_HR_WITH_USER_ERROR_IF(E_NOT_SET, Localization::WSLCCLI_LogoutNotFound(serverAddress), error == ERROR_NOT_FOUND); THROW_WIN32(error); } diff --git a/src/windows/wslc/tasks/ImageTasks.cpp b/src/windows/wslc/tasks/ImageTasks.cpp index 49fb280488..754fb1380e 100644 --- a/src/windows/wslc/tasks/ImageTasks.cpp +++ b/src/windows/wslc/tasks/ImageTasks.cpp @@ -160,7 +160,7 @@ void ListImages(CLIExecutionContext& context) bool trunc = !context.Args.Contains(ArgType::NoTrunc); for (const auto& image : images) { - context.Reporter.Output(L"{}\n", trunc ? TruncateId(image.Id, true) : image.Id); + context.Reporter.Output(L"{}\n", wsl::shared::string::MultiByteToWide(trunc ? TruncateId(image.Id, true) : image.Id)); } return; diff --git a/src/windows/wslc/tasks/NetworkTasks.cpp b/src/windows/wslc/tasks/NetworkTasks.cpp index ee402e077d..b69f7f62d4 100644 --- a/src/windows/wslc/tasks/NetworkTasks.cpp +++ b/src/windows/wslc/tasks/NetworkTasks.cpp @@ -224,7 +224,7 @@ void PruneNetworks(CLIExecutionContext& context) for (const auto& networkName : result.PrunedNetworks) { - context.Reporter.Output(L"{}\n", Localization::WSLCCLI_NetworkPruneDeleted(MultiByteToWide(networkName))); + context.Reporter.Output(L"{}\n", Localization::WSLCCLI_NetworkPruneDeleted(networkName)); } } diff --git a/src/windows/wslc/tasks/RegistryTasks.cpp b/src/windows/wslc/tasks/RegistryTasks.cpp index 7084988cb9..7f9efc3ab0 100644 --- a/src/windows/wslc/tasks/RegistryTasks.cpp +++ b/src/windows/wslc/tasks/RegistryTasks.cpp @@ -60,7 +60,7 @@ void Logout(CLIExecutionContext& context) RegistryService::Erase(serverAddress); - context.Reporter.Output(L"{}\n", Localization::WSLCCLI_LogoutSucceeded(MultiByteToWide(serverAddress))); + context.Reporter.Output(L"{}\n", Localization::WSLCCLI_LogoutSucceeded(serverAddress)); } } // namespace wsl::windows::wslc::task diff --git a/src/windows/wslc/tasks/VolumeTasks.cpp b/src/windows/wslc/tasks/VolumeTasks.cpp index 6bc521b50b..e6113646a5 100644 --- a/src/windows/wslc/tasks/VolumeTasks.cpp +++ b/src/windows/wslc/tasks/VolumeTasks.cpp @@ -217,7 +217,7 @@ void PruneVolumes(CLIExecutionContext& context) for (const auto& volumeName : result.PrunedVolumes) { - context.Reporter.Output(L"{}\n", Localization::WSLCCLI_VolumePruneDeleted(MultiByteToWide(volumeName))); + context.Reporter.Output(L"{}\n", Localization::WSLCCLI_VolumePruneDeleted(volumeName)); } context.Reporter.Output(L"\n"); diff --git a/src/windows/wslcsession/DockerHTTPClient.h b/src/windows/wslcsession/DockerHTTPClient.h index c957940014..8c535a19ec 100644 --- a/src/windows/wslcsession/DockerHTTPClient.h +++ b/src/windows/wslcsession/DockerHTTPClient.h @@ -26,7 +26,10 @@ Module Name: if ((_Ex).HasErrorMessage()) \ { \ THROW_HR_WITH_USER_ERROR_MSG( \ - (_Ex).HResultFromStatusCode(), (_Ex).DockerMessage().message, _Msg, ##__VA_ARGS__); \ + (_Ex).HResultFromStatusCode(), \ + wsl::shared::string::MultiByteToWide((_Ex).DockerMessage().message), \ + _Msg, \ + ##__VA_ARGS__); \ } \ else \ { \ diff --git a/src/windows/wslcsession/WSLCContainer.cpp b/src/windows/wslcsession/WSLCContainer.cpp index 55d9f85198..e925d1d0d8 100644 --- a/src/windows/wslcsession/WSLCContainer.cpp +++ b/src/windows/wslcsession/WSLCContainer.cpp @@ -1193,8 +1193,9 @@ void WSLCContainerImpl::Export(WSLCHandle OutHandle) const // Export failed, parse the error message. auto error = wsl::shared::FromJson(errorJson.c_str()); - THROW_HR_WITH_USER_ERROR_IF(WSLC_E_CONTAINER_NOT_FOUND, error.message, SocketCodePair.first == 404); - THROW_HR_WITH_USER_ERROR(E_FAIL, error.message); + const auto wideErrorMessage = wsl::shared::string::MultiByteToWide(error.message); + THROW_HR_WITH_USER_ERROR_IF(WSLC_E_CONTAINER_NOT_FOUND, wideErrorMessage, SocketCodePair.first == 404); + THROW_HR_WITH_USER_ERROR(E_FAIL, wideErrorMessage); } } @@ -1254,8 +1255,9 @@ void WSLCContainerImpl::UploadArchive(WSLCHandle TarHandle, LPCSTR DestPath, ULO { auto error = wsl::shared::FromJson(pendingErrorJson->c_str()); - THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), error.message, httpStatusCode == 404); - THROW_HR_WITH_USER_ERROR(E_FAIL, error.message); + const auto wideErrorMessage = wsl::shared::string::MultiByteToWide(error.message); + THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), wideErrorMessage, httpStatusCode == 404); + THROW_HR_WITH_USER_ERROR(E_FAIL, wideErrorMessage); } } @@ -1301,8 +1303,9 @@ void WSLCContainerImpl::DownloadArchive(LPCSTR SrcPath, WSLCHandle OutHandle) co { auto error = wsl::shared::FromJson(errorJson.c_str()); - THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), error.message, statusCode == 404); - THROW_HR_WITH_USER_ERROR(E_FAIL, error.message); + const auto wideErrorMessage = wsl::shared::string::MultiByteToWide(error.message); + THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), wideErrorMessage, statusCode == 404); + THROW_HR_WITH_USER_ERROR(E_FAIL, wideErrorMessage); } } diff --git a/src/windows/wslcsession/WSLCSession.cpp b/src/windows/wslcsession/WSLCSession.cpp index 6c82d61a48..deac3b8249 100644 --- a/src/windows/wslcsession/WSLCSession.cpp +++ b/src/windows/wslcsession/WSLCSession.cpp @@ -803,21 +803,21 @@ void WSLCSession::StreamImageOperation(DockerHTTPClient::HTTPRequestContext& req if (httpResponse->result == boost::beast::http::status::not_found) { - THROW_HR_WITH_USER_ERROR(WSLC_E_IMAGE_NOT_FOUND, errorMessage); + THROW_HR_WITH_USER_ERROR(WSLC_E_IMAGE_NOT_FOUND, wsl::shared::string::MultiByteToWide(errorMessage)); } else if (httpResponse->result == boost::beast::http::status::bad_request) { - THROW_HR_WITH_USER_ERROR(E_INVALIDARG, errorMessage); + THROW_HR_WITH_USER_ERROR(E_INVALIDARG, wsl::shared::string::MultiByteToWide(errorMessage)); } else { - THROW_HR_WITH_USER_ERROR(E_FAIL, errorMessage); + THROW_HR_WITH_USER_ERROR(E_FAIL, wsl::shared::string::MultiByteToWide(errorMessage)); } } else if (reportedError.has_value()) { // Can happen if an error is returned during progress after receiving an OK status. - THROW_HR_WITH_USER_ERROR(E_FAIL, reportedError.value().c_str()); + THROW_HR_WITH_USER_ERROR(E_FAIL, wsl::shared::string::MultiByteToWide(reportedError.value())); } } @@ -1221,7 +1221,7 @@ try // Stripping \r normalizes to plain \n which becomes \r\n once via text-mode // translation. std::erase(allOutput, '\r'); - THROW_HR_WITH_USER_ERROR_IF(E_FAIL, allOutput, exitCode != 0); + THROW_HR_WITH_USER_ERROR_IF(E_FAIL, wsl::shared::string::MultiByteToWide(allOutput), exitCode != 0); return S_OK; } @@ -1418,11 +1418,11 @@ std::optional WSLCSession::ImportImageImpl(DockerHTTPClient::HTTPRe { auto error = wsl::shared::FromJson(pendingErrorJson->c_str()); - THROW_HR_WITH_USER_ERROR(E_FAIL, error.message); + THROW_HR_WITH_USER_ERROR(E_FAIL, wsl::shared::string::MultiByteToWide(error.message)); } // Otherwise look for an error message returned via the progress stream (HTTP 200 followed by a stream error). - THROW_HR_WITH_USER_ERROR_IF(E_FAIL, errorMessage.value(), errorMessage.has_value()); + THROW_HR_WITH_USER_ERROR_IF(E_FAIL, wsl::shared::string::MultiByteToWide(errorMessage.value()), errorMessage.has_value()); return imageId; } @@ -1510,8 +1510,9 @@ void WSLCSession::SaveImageImpl(std::pair& SocketC { // Save failed, parse the error message. auto error = wsl::shared::FromJson(errorJson.c_str()); - THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, error.message, SocketCodePair.first == 404); - THROW_HR_WITH_USER_ERROR(E_FAIL, error.message.c_str()); + const auto wideErrorMessage = wsl::shared::string::MultiByteToWide(error.message); + THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, wideErrorMessage, SocketCodePair.first == 404); + THROW_HR_WITH_USER_ERROR(E_FAIL, wideErrorMessage); } } @@ -1671,9 +1672,10 @@ try errorMessage = e.DockerMessage().message; } - THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, errorMessage, e.StatusCode() == 404); - THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), errorMessage, e.StatusCode() == 409); - THROW_HR_WITH_USER_ERROR(E_FAIL, errorMessage); + const auto wideErrorMessage = wsl::shared::string::MultiByteToWide(errorMessage); + THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, wideErrorMessage, e.StatusCode() == 404); + THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), wideErrorMessage, e.StatusCode() == 409); + THROW_HR_WITH_USER_ERROR(E_FAIL, wideErrorMessage); } THROW_HR_IF_MSG(E_FAIL, deletedImages.empty(), "Failed to delete image: %hs", Options->Image); @@ -1743,10 +1745,11 @@ try errorMessage = e.DockerMessage().message; } - THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS), errorMessage, e.StatusCode() == 400); - THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, errorMessage, e.StatusCode() == 404); - THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), errorMessage, e.StatusCode() == 409); - THROW_HR_WITH_USER_ERROR(E_FAIL, errorMessage); + const auto wideErrorMessage = wsl::shared::string::MultiByteToWide(errorMessage); + THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS), wideErrorMessage, e.StatusCode() == 400); + THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, wideErrorMessage, e.StatusCode() == 404); + THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION), wideErrorMessage, e.StatusCode() == 409); + THROW_HR_WITH_USER_ERROR(E_FAIL, wideErrorMessage); } return S_OK; @@ -1809,9 +1812,10 @@ std::string WSLCSession::InspectImageLockHeld(const std::string& NameOrId) errorMessage = e.DockerMessage().message; } - THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, errorMessage, e.StatusCode() == 404); - THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS), errorMessage, e.StatusCode() == 400); - THROW_HR_WITH_USER_ERROR(E_FAIL, errorMessage); + const auto wideErrorMessage = wsl::shared::string::MultiByteToWide(errorMessage); + THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, wideErrorMessage, e.StatusCode() == 404); + THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS), wideErrorMessage, e.StatusCode() == 400); + THROW_HR_WITH_USER_ERROR(E_FAIL, wideErrorMessage); } // Convert to WSLC schema @@ -2020,9 +2024,10 @@ void WSLCSession::CreateContainerImpl(const WSLCContainerOptions* containerOptio errorMessage = e.DockerMessage().message; } - THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, errorMessage, e.StatusCode() == 404); - THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS), errorMessage, e.StatusCode() == 409); - THROW_HR_WITH_USER_ERROR(E_FAIL, errorMessage); + const auto wideErrorMessage = wsl::shared::string::MultiByteToWide(errorMessage); + THROW_HR_WITH_USER_ERROR_IF(WSLC_E_IMAGE_NOT_FOUND, wideErrorMessage, e.StatusCode() == 404); + THROW_HR_WITH_USER_ERROR_IF(HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS), wideErrorMessage, e.StatusCode() == 409); + THROW_HR_WITH_USER_ERROR(E_FAIL, wideErrorMessage); } } @@ -3486,8 +3491,7 @@ void WSLCSession::RecoverExistingContainers() catch (...) { LOG_CAUGHT_EXCEPTION_MSG("Failed to recover container: %hs", dockerContainer.Id.c_str()); - EMIT_USER_WARNING( - Localization::MessageWslcFailedToRecoverContainer(wsl::shared::string::MultiByteToWide(dockerContainer.Id))); + EMIT_USER_WARNING(Localization::MessageWslcFailedToRecoverContainer(dockerContainer.Id)); } } @@ -3543,7 +3547,7 @@ void WSLCSession::RecoverExistingNetworks() catch (...) { LOG_CAUGHT_EXCEPTION_MSG("Failed to recover network: %hs", network.Name.c_str()); - EMIT_USER_WARNING(Localization::MessageWslcFailedToRecoverNetwork(wsl::shared::string::MultiByteToWide(network.Name))); + EMIT_USER_WARNING(Localization::MessageWslcFailedToRecoverNetwork(network.Name)); } } diff --git a/test/windows/Common.cpp b/test/windows/Common.cpp index 3345771777..c110f373c7 100644 --- a/test/windows/Common.cpp +++ b/test/windows/Common.cpp @@ -2760,7 +2760,8 @@ void VerifyPatternMatch(const std::string& Content, const std::string& Pattern) { if (!PathMatchSpecA(Content.c_str(), Pattern.c_str())) { - std::wstring message = std::format(L"Output: '{}' didn't match pattern: '{}'", Content, Pattern); + std::wstring message = std::format( + L"Output: '{}' didn't match pattern: '{}'", wsl::shared::string::MultiByteToWide(Content), wsl::shared::string::MultiByteToWide(Pattern)); VERIFY_FAIL(message.c_str()); } } diff --git a/test/windows/Common.h b/test/windows/Common.h index 46790519d8..63a60bb0b2 100644 --- a/test/windows/Common.h +++ b/test/windows/Common.h @@ -662,6 +662,17 @@ std::optional GetHostAdapterIpv4(); template void VerifyAreEqualUnordered(const std::vector& expected, const std::vector& actual, const std::source_location& source = std::source_location::current()) { + auto formatValue = [](const T& value) -> decltype(auto) { + if constexpr (std::is_same_v) + { + return wsl::shared::string::MultiByteToWide(value); + } + else + { + return (value); + } + }; + std::map expectedCounts; std::map actualCounts; @@ -681,7 +692,7 @@ void VerifyAreEqualUnordered(const std::vector& expected, const std::vector& expected, const std::vector& expected, const std::vectorc_str())) { - std::wstring message = std::format(L"Output: '{}' didn't match pattern: '{}'", output, options.value()); + std::wstring message = std::format( + L"Output: '{}' didn't match pattern: '{}'", + wsl::shared::string::MultiByteToWide(output), + wsl::shared::string::MultiByteToWide(options.value())); VERIFY_FAIL(message.c_str()); } } @@ -6526,7 +6529,7 @@ class WSLCTests auto id = container.Id(); VERIFY_ARE_EQUAL(container.Get().Stop(WSLCSignalSIGKILL, 0), WSLC_E_CONTAINER_NOT_RUNNING); - ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", id)); + ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", wsl::shared::string::MultiByteToWide(id))); // Verify that the container is in running state. VERIFY_SUCCEEDED(container.Get().Start(WSLCContainerStartFlagsNone, nullptr, nullptr)); @@ -6648,7 +6651,7 @@ class WSLCTests // Validate that a created container cannot be killed. auto id = container.Id(); VERIFY_ARE_EQUAL(container.Get().Kill(WSLCSignalNone), WSLC_E_CONTAINER_NOT_RUNNING); - ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", id)); + ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", wsl::shared::string::MultiByteToWide(id))); VERIFY_SUCCEEDED(container.Get().Start(WSLCContainerStartFlagsNone, nullptr, nullptr)); VERIFY_ARE_EQUAL(container.State(), WslcContainerStateRunning); @@ -6659,7 +6662,7 @@ class WSLCTests // Validate that killing a non-running container fails (unlike Stop()) VERIFY_ARE_EQUAL(container.Get().Kill(WSLCSignalNone), WSLC_E_CONTAINER_NOT_RUNNING); - ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", id)); + ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", wsl::shared::string::MultiByteToWide(id))); // Verify that deleting a container stopped via Kill() works. VERIFY_SUCCEEDED(container.Get().Delete(WSLCDeleteFlagsNone)); @@ -6705,7 +6708,7 @@ class WSLCTests auto id = container.Id(); VERIFY_ARE_EQUAL(container.Get().Delete(WSLCDeleteFlagsNone), WSLC_E_CONTAINER_IS_RUNNING); ValidateCOMErrorMessage( - std::format(L"Container '{}' is running and cannot be removed. Either stop the container before removing or use forced remove (-f).", id)); + std::format(L"Container '{}' is running and cannot be removed. Either stop the container before removing or use forced remove (-f).", wsl::shared::string::MultiByteToWide(id))); // Kill the container. auto initProcess = container.GetInitProcess(); @@ -6758,7 +6761,7 @@ class WSLCTests // Verify that Start() can't be called again on a running container. auto id = container->Id(); VERIFY_ARE_EQUAL(container->Get().Start(WSLCContainerStartFlagsNone, nullptr, nullptr), WSLC_E_CONTAINER_IS_RUNNING); - ValidateCOMErrorMessage(std::format(L"Container '{}' is running.", id)); + ValidateCOMErrorMessage(std::format(L"Container '{}' is running.", wsl::shared::string::MultiByteToWide(id))); VERIFY_ARE_EQUAL(container->State(), WslcContainerStateRunning); @@ -6815,7 +6818,7 @@ class WSLCTests auto id = container.Id(); VERIFY_ARE_EQUAL(container.Get().Delete(WSLCDeleteFlagsNone), WSLC_E_CONTAINER_IS_RUNNING); ValidateCOMErrorMessage( - std::format(L"Container '{}' is running and cannot be removed. Either stop the container before removing or use forced remove (-f).", id)); + std::format(L"Container '{}' is running and cannot be removed. Either stop the container before removing or use forced remove (-f).", wsl::shared::string::MultiByteToWide(id))); // Validate that invalid flags are rejected. VERIFY_ARE_EQUAL(container.Get().Delete(static_cast(0x4)), E_INVALIDARG); @@ -8097,7 +8100,7 @@ class WSLCTests auto retVal = launcher.LaunchNoThrow(*m_defaultSession); VERIFY_ARE_EQUAL(WSLC_E_CONTAINER_NOT_FOUND, retVal.first); - ValidateCOMErrorMessage(std::format(L"Target container '{}' not found.", targetName)); + ValidateCOMErrorMessage(std::format(L"Target container '{}' not found.", wsl::shared::string::MultiByteToWide(targetName))); } WSLC_TEST_METHOD(ContainerNetworkModePortsRejectedTest) @@ -8481,7 +8484,7 @@ class WSLCTests auto [result, _] = WSLCProcessLauncher({}, {"/bin/cat"}).LaunchNoThrow(container.Get()); VERIFY_ARE_EQUAL(result, WSLC_E_CONTAINER_NOT_RUNNING); - ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", id)); + ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", wsl::shared::string::MultiByteToWide(id))); } // Validate that invalid tty sizes are rejected. @@ -8942,7 +8945,7 @@ class WSLCTests auto container = createTcpContainer({{WSLC_EPHEMERAL_PORT, 8000, AF_INET, IPPROTO_TCP, "127.0.0.1"}}); auto hostPort = validateInspectPortBinding(container, 8000, IPPROTO_TCP, "127.0.0.1", std::nullopt); - ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", hostPort).c_str(), 200); + ExpectHttpResponse(std::format(L"http://127.0.0.1:{}", wsl::shared::string::MultiByteToWide(hostPort)).c_str(), 200); } // Anonymous bind on host ip (ephemeral host port). @@ -8952,7 +8955,8 @@ class WSLCTests auto container = createTcpContainer({{WSLC_EPHEMERAL_PORT, 8000, AF_INET, IPPROTO_TCP, hostIpNarrow.value()}}); auto hostPort = validateInspectPortBinding(container, 8000, IPPROTO_TCP, hostIpNarrow.value(), std::nullopt); - ExpectHttpResponse(std::format(L"http://{}:{}", hostIp.value(), hostPort).c_str(), 200); + ExpectHttpResponse( + std::format(L"http://{}:{}", hostIp.value(), wsl::shared::string::MultiByteToWide(hostPort)).c_str(), 200); } else { @@ -10706,7 +10710,7 @@ class WSLCTests COMOutputHandle stderrHandle{}; auto id = container->Id(); VERIFY_ARE_EQUAL(container->Get().Attach(nullptr, &stdinHandle, &stdoutHandle, &stderrHandle), WSLC_E_CONTAINER_NOT_RUNNING); - ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", id)); + ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", wsl::shared::string::MultiByteToWide(id))); // Start the container. VERIFY_SUCCEEDED(container->Get().Start(WSLCContainerStartFlagsAttach, nullptr, nullptr)); @@ -10761,7 +10765,7 @@ class WSLCTests stdoutHandle.Reset(); stderrHandle.Reset(); VERIFY_ARE_EQUAL(container->Get().Attach(nullptr, &stdinHandle, &stdoutHandle, &stderrHandle), WSLC_E_CONTAINER_NOT_RUNNING); - ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", id)); + ValidateCOMErrorMessage(std::format(L"Container '{}' is not running.", wsl::shared::string::MultiByteToWide(id))); // Validate that attaching to a deleted container fails. VERIFY_SUCCEEDED(container->Get().Delete(WSLCDeleteFlagsNone)); @@ -11022,7 +11026,7 @@ class WSLCTests VERIFY_ARE_EQUAL(m_defaultSession->OpenContainer(name.c_str(), &container), E_INVALIDARG); VERIFY_IS_NULL(container.get()); - ValidateCOMErrorMessage(std::format(L"Invalid name: '{}'", name)); + ValidateCOMErrorMessage(std::format(L"Invalid name: '{}'", wsl::shared::string::MultiByteToWide(name))); }; expectInvalidArg("container with spaces"); @@ -11041,7 +11045,7 @@ class WSLCTests auto comError = wsl::windows::common::wslutil::GetCOMErrorInfo(); VERIFY_IS_TRUE(comError.has_value()); - VERIFY_ARE_EQUAL(comError->Message.get(), std::format(L"Invalid image: '{}'", name)); + VERIFY_ARE_EQUAL(comError->Message.get(), std::format(L"Invalid image: '{}'", wsl::shared::string::MultiByteToWide(name))); }; expectInvalidPull("?foo&bar/url\n:name"); @@ -12092,9 +12096,7 @@ class WSLCTests // Verify the warning matches the expected localized message for the corrupt container. auto warnings = warningCallback->GetWarnings(); - auto expectedWarning = std::format( - L"wsl: {}\n", - wsl::shared::Localization::MessageWslcFailedToRecoverContainer(wsl::shared::string::MultiByteToWide(containerId))); + auto expectedWarning = std::format(L"wsl: {}\n", wsl::shared::Localization::MessageWslcFailedToRecoverContainer(containerId)); VERIFY_IS_TRUE(std::ranges::any_of(warnings, [&](const auto& w) { return w == expectedWarning; })); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp index 350113a162..5c2f702e5f 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerAttachTests.cpp @@ -53,8 +53,8 @@ class WSLCE2EContainerAttachTests VerifyContainerIsNotListed(WslcContainerName); const auto& prompt = ">"; - auto result = RunWslc(std::format( - L"container run -itd -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); + auto result = RunWslc( + std::format(L"container run -itd -e PS1={} --name {} {} bash --norc", L">", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp index bccaaa9b3c..9e213df66d 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerCreateTests.cpp @@ -91,7 +91,7 @@ class WSLCE2EContainerCreateTests auto session = OpenDefaultElevatedSession(); auto [registryContainer, registryAddress] = StartLocalRegistry(*session, "", "", 5000); - auto reference = std::format(L"{}/invalid-image:latest", registryAddress); + auto reference = std::format(L"{}/invalid-image:latest", wsl::shared::string::MultiByteToWide(registryAddress)); auto result = RunWslc(std::format(L"container create --name {} {}", WslcContainerName, reference)); @@ -522,7 +522,7 @@ class WSLCE2EContainerCreateTests const auto& prompt = ">"; auto result = RunWslc(std::format( - L"container create -it -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); + L"container create -it -e PS1={} --name {} {} bash --norc", L">", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); diff --git a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp index 0a16883100..2eafbf5194 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerExecTests.cpp @@ -107,7 +107,7 @@ class WSLCE2EContainerExecTests const auto& prompt = ">"; auto result = - RunWslc(std::format(L"container run -itd -e PS1={} --name {} {}", prompt, WslcContainerName, DebianImage.NameAndTag())); + RunWslc(std::format(L"container run -itd -e PS1={} --name {} {}", L">", WslcContainerName, DebianImage.NameAndTag())); result.Verify({.Stderr = L"", .ExitCode = 0}); auto containerId = result.GetStdoutOneLine(); @@ -425,7 +425,9 @@ class WSLCE2EContainerExecTests auto inspect = InspectContainer(WslcContainerName); result = RunWslc(std::format(L"container exec {} echo should-fail", WslcContainerName)); - auto errorMessage = std::format(L"Container '{}' is not running.\r\nError code: WSLC_E_CONTAINER_NOT_RUNNING\r\n", inspect.Id); + auto errorMessage = std::format( + L"Container '{}' is not running.\r\nError code: WSLC_E_CONTAINER_NOT_RUNNING\r\n", + wsl::shared::string::MultiByteToWide(inspect.Id)); result.Verify({.Stderr = errorMessage, .ExitCode = 1}); } diff --git a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp index 74ac853a64..4dc9ae4798 100644 --- a/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EContainerRunTests.cpp @@ -675,7 +675,7 @@ class WSLCE2EContainerRunTests const auto& prompt = ">"; auto session = RunWslcInteractive( - std::format(L"container run -it -e PS1={} --name {} {} bash --norc", prompt, WslcContainerName, DebianImage.NameAndTag())); + std::format(L"container run -it -e PS1={} --name {} {} bash --norc", L">", WslcContainerName, DebianImage.NameAndTag())); VERIFY_IS_TRUE(session.IsRunning(), L"Container session should be running"); // Ignore resize-repaint messages. Those are emitted when the the tty initial size is set, which can happen before or after we start running commands. diff --git a/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp b/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp index 8eb1dbd748..7d58f8df10 100644 --- a/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp @@ -590,7 +590,7 @@ class WSLCE2EGlobalTests private: std::wstring GetVersionMessage() const { - return std::format(L"wslc {}\r\n", WSL_PACKAGE_VERSION); + return std::format(L"wslc {}\r\n", STRING_TO_WIDE_STRING(WSL_PACKAGE_VERSION)); } }; } // namespace WSLCE2ETests diff --git a/test/windows/wslc/e2e/WSLCE2EHelpers.cpp b/test/windows/wslc/e2e/WSLCE2EHelpers.cpp index e7266beab9..7d4daeae88 100644 --- a/test/windows/wslc/e2e/WSLCE2EHelpers.cpp +++ b/test/windows/wslc/e2e/WSLCE2EHelpers.cpp @@ -27,6 +27,7 @@ namespace WSLCE2ETests { using namespace WEX::Logging; using namespace wsl::windows::common; +using wsl::shared::string::MultiByteToWide; namespace { // Lazily compute the session storage base path. @@ -97,7 +98,8 @@ namespace { std::filesystem::remove_all(storagePath, error); if (error) { - Log::Error(std::format(L"Failed to cleanup storage path {}: {}", storagePath.wstring(), error.message()).c_str()); + Log::Error( + std::format(L"Failed to cleanup storage path {}: {}", storagePath.wstring(), MultiByteToWide(error.message())).c_str()); } } } @@ -309,8 +311,8 @@ wslc_schema::Health WaitForContainerHealth(const std::wstring& containerName, co VERIFY_FAIL(std::format( L"Container '{}' did not reach health status '{}' (last status: '{}')", containerName, - wsl::shared::string::MultiByteToWide(std::string(expectedStatus)), - wsl::shared::string::MultiByteToWide(actual)) + MultiByteToWide(std::string(expectedStatus)), + MultiByteToWide(actual)) .c_str()); throw; } @@ -367,8 +369,8 @@ void EnsureImageContainersAreDeleted(const TestImage& image) auto nameAndTag = wsl::shared::string::WideToMultiByte(image.NameAndTag()); if (container.Image.find(nameAndTag) != std::string::npos) { - auto result = RunWslc(std::format(L"container remove --force {}", container.Id)); - result.Verify({.Stdout = std::format(L"{}\r\n", container.Id), .Stderr = L"", .ExitCode = 0}); + auto result = RunWslc(std::format(L"container remove --force {}", MultiByteToWide(container.Id))); + result.Verify({.Stdout = std::format(L"{}\r\n", MultiByteToWide(container.Id)), .Stderr = L"", .ExitCode = 0}); } } } @@ -406,7 +408,7 @@ void DeleteImagesWithRepositoryPrefix(const std::wstring& repositoryPrefix) // No container cleanup here: the images this prunes are only ever built and inspected, never used to // create containers, so image delete --force is sufficient. If a future test containerizes a built // image, remove its container in that test's cleanup rather than broadening this prefix-based safety net. - const auto nameAndTag = wsl::shared::string::MultiByteToWide(std::format("{}:{}", *image.Repository, *image.Tag)); + const auto nameAndTag = MultiByteToWide(std::format("{}:{}", *image.Repository, *image.Tag)); RunWslc(std::format(L"image delete --force {}", nameAndTag)).Verify({.Stderr = L"", .ExitCode = 0}); } } @@ -421,7 +423,7 @@ void EnsureNoUntaggedImages() for (const auto& image : images) { - const auto id = wsl::shared::string::MultiByteToWide(GetHashId(image.Id, true)); + const auto id = MultiByteToWide(GetHashId(image.Id, true)); auto deleteResult = RunWslc(std::format(L"image delete --force {}", id)); // Tolerate WSLC_E_IMAGE_NOT_FOUND - an untagged image may already be gone if it was a @@ -616,7 +618,7 @@ std::pair StartLocalRegistry( else { auto address = std::format("127.0.0.1:{}", port); - auto url = std::format(L"http://{}/v2/", wsl::shared::string::MultiByteToWide(address)); + auto url = std::format(L"http://{}/v2/", MultiByteToWide(address)); int expectedCode = username.empty() ? 200 : 401; ExpectHttpResponse(url.c_str(), expectedCode, true); @@ -716,9 +718,7 @@ namespace { catch (...) { const std::string data = session.GetStdoutData(); - VERIFY_FAIL(std::format( - L"Timed out waiting for tty resize. Captured pseudoconsole output: \"{}\"", - wsl::shared::string::MultiByteToWide(EscapeString(data))) + VERIFY_FAIL(std::format(L"Timed out waiting for tty resize. Captured pseudoconsole output: \"{}\"", MultiByteToWide(EscapeString(data))) .c_str()); } } diff --git a/test/windows/wslc/e2e/WSLCE2EImageDeleteTests.cpp b/test/windows/wslc/e2e/WSLCE2EImageDeleteTests.cpp index be49f238ba..166399ef03 100644 --- a/test/windows/wslc/e2e/WSLCE2EImageDeleteTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EImageDeleteTests.cpp @@ -102,8 +102,8 @@ class WSLCE2EImageDeleteTests L"conflict: unable to remove repository reference \"{}\" (must force) - container {} is using its referenced image " L"{}\r\nError code: ERROR_SHARING_VIOLATION\r\n", DebianImage.Name, - containerId, - imageId); + wsl::shared::string::MultiByteToWide(containerId), + wsl::shared::string::MultiByteToWide(imageId)); result.Verify({.Stdout = L"", .Stderr = errorMessage, .ExitCode = 1}); } diff --git a/test/windows/wslc/e2e/WSLCE2EWarningTests.cpp b/test/windows/wslc/e2e/WSLCE2EWarningTests.cpp index 81afbef07a..6db6a4c03a 100644 --- a/test/windows/wslc/e2e/WSLCE2EWarningTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EWarningTests.cpp @@ -104,8 +104,8 @@ class WSLCE2EWarningTests VERIFY_ARE_EQUAL(0u, result.ExitCode.value()); VERIFY_IS_TRUE(result.Stderr.has_value()); - const auto expectedStderr = std::format( - L"wsl: {}\r\n", wsl::shared::Localization::MessageWslcFailedToRecoverContainer(string::MultiByteToWide(corruptContainerId))); + const auto expectedStderr = + std::format(L"wsl: {}\r\n", wsl::shared::Localization::MessageWslcFailedToRecoverContainer(corruptContainerId)); VERIFY_ARE_EQUAL(expectedStderr, result.Stderr.value()); } }; diff --git a/tools/generateLocalizationHeader.ps1 b/tools/generateLocalizationHeader.ps1 index afb21b532f..825f64670b 100644 --- a/tools/generateLocalizationHeader.ps1 +++ b/tools/generateLocalizationHeader.ps1 @@ -21,6 +21,47 @@ $content = @" namespace wsl::shared { +namespace localization_detail { + +#ifdef WIN32 + +inline std::wstring FormatArgument(const char* value) +{ + return string::MultiByteToWide(value); +} + +inline std::wstring FormatArgument(char* value) +{ + return string::MultiByteToWide(value); +} + +inline std::wstring FormatArgument(const std::string& value) +{ + return string::MultiByteToWide(value); +} + +template +std::wstring FormatArgument(const std::basic_string& value) +{ + return string::MultiByteToWide(value.c_str()); +} + +template +std::wstring FormatArgument(std::basic_string_view value) +{ + return string::MultiByteToWide(std::string{value.data(), value.size()}); +} + +#endif + +template +constexpr const T& FormatArgument(const T& value) noexcept +{ + return value; +} + +} // namespace localization_detail + class Localization { public: @@ -108,7 +149,10 @@ function generateEntry { $ArgumentTypes = [string]::Join(', ', ((1..$ArgumentsCount) |% {"typename T$_"})) $ArgumentHeaders = [string]::Join(', ', ((1..$ArgumentsCount) |% {"const T$_& arg$_"})) - $Arguments = [string]::Join(', ', ((1..$ArgumentsCount) |% {"arg$_"})) + $ArgumentConversions = [string]::Join( + "`r`n ", + ((1..$ArgumentsCount) |% {"decltype(auto) formattedArg$_ = localization_detail::FormatArgument(arg$_);"})) + $Arguments = [string]::Join(', ', ((1..$ArgumentsCount) |% {"formattedArg$_"})) return ' /* Message: {4}*/ @@ -118,9 +162,10 @@ function generateEntry {5}; auto message = LookupString(strings, options); + {6} return std::vformat(message, ARGS({3})); }} - ' -f $Name, $ArgumentTypes, $ArgumentHeaders, $Arguments, $Content.split("`n")[0], $map + ' -f $Name, $ArgumentTypes, $ArgumentHeaders, $Arguments, $Content.split("`n")[0], $map, $ArgumentConversions } }