diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h index 87c8c5a0..c9d0642f 100644 --- a/include/spdlog/details/os-inl.h +++ b/include/spdlog/details/os-inl.h @@ -459,6 +459,41 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); } + +SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, memory_buf_t &target) +{ + if (str.size() > static_cast((std::numeric_limits::max)())) + { + throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16"); + } + + int str_size = static_cast(str.size()); + if (str_size == 0) + { + target.resize(0); + return; + } + + int result_size = static_cast(target.capacity()); + if ((str_size + 1) * 2 < result_size) + { + result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0); + } + + if (result_size > 0) + { + target.resize(result_size); + result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, (LPWSTR)target.data(), result_size); + + if (result_size > 0) + { + target.resize(result_size); + return; + } + } + + throw_spdlog_ex(fmt::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); +} #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) // return true on success diff --git a/include/spdlog/details/os.h b/include/spdlog/details/os.h index 243a4fb8..88f13dbe 100644 --- a/include/spdlog/details/os.h +++ b/include/spdlog/details/os.h @@ -85,6 +85,8 @@ SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); + +SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, memory_buf_t &target); #endif // Return directory name from given path or empty string diff --git a/include/spdlog/sinks/win_eventlog_sink.h b/include/spdlog/sinks/win_eventlog_sink.h index 384fa9eb..f154c55a 100644 --- a/include/spdlog/sinks/win_eventlog_sink.h +++ b/include/spdlog/sinks/win_eventlog_sink.h @@ -57,7 +57,7 @@ struct win32_error : public spdlog_ex LPSTR format_message_result{}; auto format_message_succeeded = - ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result, 0, nullptr); if (format_message_succeeded && format_message_result) @@ -203,7 +203,7 @@ private: { if (!hEventLog_) { - hEventLog_ = ::RegisterEventSource(nullptr, source_.c_str()); + hEventLog_ = ::RegisterEventSourceA(nullptr, source_.c_str()); if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED) { SPDLOG_THROW(internal::win32_error("RegisterEventSource")); @@ -218,18 +218,41 @@ protected: { using namespace internal; + bool succeeded; memory_buf_t formatted; base_sink::formatter_->format(msg, formatted); formatted.push_back('\0'); - LPCSTR lp_str = static_cast(formatted.data()); - auto succeeded = ::ReportEvent(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, - current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr); +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + try + { + memory_buf_t buf; + details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf); + + LPCWSTR lp_wstr = reinterpret_cast(buf.data()); + succeeded = ::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, + current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr); + + if (!succeeded) + { + SPDLOG_THROW(win32_error("ReportEvent")); + } + } + catch (...) + { + // WCHAR string conversion can fail and if it does, we shouldn't call to report event function. + } +#else + LPCSTR lp_str = reinterpret_cast(formatted.data()); + + succeeded = ::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, + current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr); if (!succeeded) { SPDLOG_THROW(win32_error("ReportEvent")); } +#endif } void flush_() override {}