Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In Windows host, use WriteConsoleW for stdout and stderr, and locale enabled print for file output #102295

Merged
merged 10 commits into from
Jun 6, 2024
2 changes: 1 addition & 1 deletion src/native/corehost/apphost/apphost.windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace
// Add to buffer for later use.
g_buffered_errors.append(message).append(_X("\n"));
// Also write to stderr immediately
pal::err_fputs(message);
pal::err_print_line(message);
}

// Determines if the current module (apphost executable) is marked as a Windows GUI application
Expand Down
14 changes: 7 additions & 7 deletions src/native/corehost/hostmisc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ namespace pal

inline FILE* file_open(const string_t& path, const char_t* mode) { return ::_wfsopen(path.c_str(), mode, _SH_DENYNO); }

inline void file_vprintf(FILE* f, const char_t* format, va_list vl) { ::vfwprintf(f, format, vl); ::fputwc(_X('\n'), f); }
inline void err_fputs(const char_t* message) { ::fputws(message, stderr); ::fputwc(_X('\n'), stderr); }
inline void out_vprintf(const char_t* format, va_list vl) { ::vfwprintf(stdout, format, vl); ::fputwc(_X('\n'), stdout); }
void file_vprintf(FILE* f, const char_t* format, va_list vl);
void err_print_line(const char_t* message);
void out_vprint_line(const char_t* format, va_list vl);

inline int str_vprintf(char_t* buffer, size_t count, const char_t* format, va_list vl) { return ::_vsnwprintf_s(buffer, count, _TRUNCATE, format, vl); }
inline int strlen_vprintf(const char_t* format, va_list vl) { return ::_vscwprintf(format, vl); }
Expand All @@ -188,7 +188,7 @@ namespace pal
inline bool munmap(void* addr, size_t length) { return UnmapViewOfFile(addr) != 0; }
inline int get_pid() { return GetCurrentProcessId(); }
inline void sleep(uint32_t milliseconds) { Sleep(milliseconds); }
#else
#else // _WIN32
#ifdef EXPORT_SHARED_API
#define SHARED_API extern "C" __attribute__((__visibility__("default")))
#else
Expand Down Expand Up @@ -226,8 +226,8 @@ namespace pal
inline size_t strlen(const char_t* str) { return ::strlen(str); }
inline FILE* file_open(const string_t& path, const char_t* mode) { return fopen(path.c_str(), mode); }
inline void file_vprintf(FILE* f, const char_t* format, va_list vl) { ::vfprintf(f, format, vl); ::fputc('\n', f); }
inline void err_fputs(const char_t* message) { ::fputs(message, stderr); ::fputc(_X('\n'), stderr); }
inline void out_vprintf(const char_t* format, va_list vl) { ::vfprintf(stdout, format, vl); ::fputc('\n', stdout); }
inline void err_print_line(const char_t* message) { ::fputs(message, stderr); ::fputc(_X('\n'), stderr); }
inline void out_vprint_line(const char_t* format, va_list vl) { ::vfprintf(stdout, format, vl); ::fputc('\n', stdout); }
inline int str_vprintf(char_t* str, size_t size, const char_t* format, va_list vl) { return ::vsnprintf(str, size, format, vl); }
inline int strlen_vprintf(const char_t* format, va_list vl) { return ::vsnprintf(nullptr, 0, format, vl); }

Expand All @@ -254,7 +254,7 @@ namespace pal
inline bool munmap(void* addr, size_t length) { return ::munmap(addr, length) == 0; }
inline int get_pid() { return getpid(); }
inline void sleep(uint32_t milliseconds) { usleep(milliseconds * 1000); }
#endif
#endif // _WIN32

inline int snwprintf(char_t* buffer, size_t count, const char_t* format, ...)
{
Expand Down
54 changes: 54 additions & 0 deletions src/native/corehost/hostmisc/pal.windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,64 @@
#include "utils.h"
#include "longfile.h"

// #include <string>
// #include <cstring>
// #include <cstdarg>
// #include <cstdint>
jtschuster marked this conversation as resolved.
Show resolved Hide resolved
#include <windows.h>
#include <cassert>
#include <ShlObj.h>
#include <ctime>


void pal::file_vprintf(FILE* f, const pal::char_t* format, va_list vl) {
jtschuster marked this conversation as resolved.
Show resolved Hide resolved
// In order to properly print characters in the GB18030 standard, we need to use the locale version of vfwprintf
jtschuster marked this conversation as resolved.
Show resolved Hide resolved
_locale_t loc = _create_locale(LC_ALL, ".utf8");
::_vfwprintf_l(f, format, loc, vl);
::fputwc(_X('\n'), f);
_free_locale(loc);
}

// Helper to write output to std handles and handle redirection to a file
void print_line_to_handle(const pal::char_t* message, HANDLE handle, FILE* fallbackFileHandle) {
jtschuster marked this conversation as resolved.
Show resolved Hide resolved
DWORD output;
// GetConsoleMode fails when the output is redirected to a file
// In this case, we'll use the handle to print to the file
BOOL success = ::GetConsoleMode(handle, &output);
if (success == 0)
{
pal::file_vprintf(fallbackFileHandle, message, va_list());
return;
jtschuster marked this conversation as resolved.
Show resolved Hide resolved
}
else {
// In order to properly print characters in the GB18030 standard, we need to use WriteConsoleW
::WriteConsoleW(handle, message, (int)pal::strlen(message), NULL, NULL);
}
}

void pal::err_print_line(const pal::char_t* message) {
// In order to properly print characters in the GB18030 standard, we need to use WriteConsoleW
print_line_to_handle(message, ::GetStdHandle(STD_ERROR_HANDLE), stderr);
}

void pal::out_vprint_line(const pal::char_t* format, va_list vl) {
va_list vl_copy;
va_copy(vl_copy, vl);
// Get the length of the formatted string + 1 for null terminator
int len = 1 + pal::strlen_vprintf(format, vl_copy);
if (len < 0)
{
return;
}
std::vector<pal::char_t> buffer(len);
int written = pal::str_vprintf(&buffer[0], len, format, vl);
if (written != len - 1)
{
return;
}
print_line_to_handle(&buffer[0], ::GetStdHandle(STD_OUTPUT_HANDLE), stdout);
}

bool GetModuleFileNameWrapper(HMODULE hModule, pal::string_t* recv)
{
pal::string_t path;
Expand Down
4 changes: 2 additions & 2 deletions src/native/corehost/hostmisc/trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ void trace::error(const pal::char_t* format, ...)

if (g_error_writer == nullptr)
{
pal::err_fputs(buffer.data());
pal::err_print_line(buffer.data());
}
else
{
Expand All @@ -200,7 +200,7 @@ void trace::println(const pal::char_t* format, ...)
va_start(args, format);
{
std::lock_guard<spin_lock> lock(g_trace_lock);
pal::out_vprintf(format, args);
pal::out_vprint_line(format, args);
}
va_end(args);
}
Expand Down
Loading