From b1f5b2e3ffeec006125d53355d93a862603e8f97 Mon Sep 17 00:00:00 2001 From: jf-0 <116807061+jf-0@users.noreply.github.com> Date: Fri, 17 Feb 2023 13:38:35 +0100 Subject: [PATCH] Support 'Windows 10 LTSB 2016, 1607 and Server 2016' Windows Server 2016, Windows 10 LTSB 2016 and Windows 10 version 1607: GetThreadDescription and SetThreadDescription are only available by Run Time Dynamic Linking in KernelBase.dll. see: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription --- quill/src/detail/misc/Os.cpp | 73 +++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/quill/src/detail/misc/Os.cpp b/quill/src/detail/misc/Os.cpp index bb9f6a21..96f87ad4 100644 --- a/quill/src/detail/misc/Os.cpp +++ b/quill/src/detail/misc/Os.cpp @@ -25,7 +25,6 @@ #include #include #include - #include #include #elif defined(__APPLE__) #include @@ -120,6 +119,55 @@ tm* localtime_rs(time_t const* timer, tm* buf) #endif } +#if defined(_WIN32) +/***/ +template +ReturnT callRunTimeDynamicLinkedFunction(const std::string& dll_name, + const std::string& function_name, Args... args) +{ + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreaddescription + // Windows Server 2016, Windows 10 LTSB 2016 and Windows 10 version 1607: e.g. GetThreadDescription is only available by Run Time Dynamic Linking in KernelBase.dll. + + #ifdef UNICODE + HINSTANCE const hinstLibrary = LoadLibraryW(s2ws(dll_name).c_str()); + #else + HINSTANCE const hinstLibrary = LoadLibraryA(dll_name.c_str()); + #endif + + if (QUILL_UNLIKELY(hinstLibrary == NULL)) + { + std::ostringstream error_msg; + error_msg << "Failed to load library " + << "\"" << dll_name << "\""; + QUILL_THROW(QuillError{error_msg.str()}); + } + + auto const callable = reinterpret_cast(GetProcAddress(hinstLibrary, function_name.c_str())); + + if (QUILL_UNLIKELY(callable == NULL)) + { + std::ostringstream error_msg; + error_msg << "Failed to call " + << "\"" << function_name << "\" in " + << "\"" << dll_name << "\""; + QUILL_THROW(QuillError{error_msg.str()}); + } + + ReturnT const hr = callable(std::forward(args)...); + BOOL const fFreeResult = FreeLibrary(hinstLibrary); + + if (QUILL_UNLIKELY(!fFreeResult)) + { + std::ostringstream error_msg; + error_msg << "Failed to free library " + << "\"" << dll_name << "\""; + QUILL_THROW(QuillError{error_msg.str()}); + } + + return hr; +} +#endif + /***/ void set_cpu_affinity(uint16_t cpu_id) { @@ -174,7 +222,11 @@ void set_thread_name(char const* name) #elif defined(_WIN32) std::wstring name_ws = s2ws(name); // Set the thread name - HRESULT hr = SetThreadDescription(GetCurrentThread(), name_ws.data()); + + typedef HRESULT(WINAPI * SetThreadDescriptionSignature)(HANDLE, PCWSTR); + HRESULT hr = callRunTimeDynamicLinkedFunction( + "KernelBase.dll", "SetThreadDescription", GetCurrentThread(), name_ws.data()); + if (FAILED(hr)) { QUILL_THROW(QuillError{"Failed to set thread name"}); @@ -205,14 +257,23 @@ std::string get_thread_name() // Disabled on MINGW / Cygwin. return std::string{}; #elif defined(_WIN32) - PWSTR data; - HRESULT hr = GetThreadDescription(GetCurrentThread(), &data); + PWSTR data = nullptr; + + typedef HRESULT(WINAPI * GetThreadDescriptionSignature)(HANDLE, PWSTR*); + HRESULT hr = callRunTimeDynamicLinkedFunction( + "KernelBase.dll", "GetThreadDescription", GetCurrentThread(), &data); + if (FAILED(hr)) { QUILL_THROW(QuillError{"Failed to get thread name"}); } - std::wstring tname{&data[0], wcslen(&data[0])}; + if (QUILL_UNLIKELY(data == nullptr)) + { + QUILL_THROW(QuillError{"Failed to get thread name. Invalid data."}); + } + + const std::wstring tname{&data[0], wcslen(&data[0])}; LocalFree(data); return ws2s(tname); #else @@ -372,4 +433,4 @@ bool fsync(FILE* fd) return ::fsync(fileno(fd)) == 0; #endif } -} // namespace quill::detail \ No newline at end of file +} // namespace quill::detail