From 61ed5055a8dd33428df63ec1c8c7d4b5c6071915 Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Wed, 11 Feb 2015 12:24:30 +0300 Subject: [PATCH 1/9] LangInfo: add m_locale and GetLocale() for current locale --- xbmc/LangInfo.cpp | 3 +++ xbmc/LangInfo.h | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/xbmc/LangInfo.cpp b/xbmc/LangInfo.cpp index 5831d8d729ff8..4e7991760aa15 100644 --- a/xbmc/LangInfo.cpp +++ b/xbmc/LangInfo.cpp @@ -196,6 +196,7 @@ void CLangInfo::CRegion::SetGlobalLocale() strLocale = "C"; } + g_langInfo.m_locale = current_locale; // TODO: move to CLangInfo class locale::global(current_locale); #endif g_charsetConverter.resetSystemCharset(); @@ -419,6 +420,8 @@ void CLangInfo::SetDefaults() // Set the default region, we may be unable to load langinfo.xml m_currentRegion=&m_defaultRegion; + + m_locale = std::locale::classic(); m_languageCodeGeneral = "eng"; } diff --git a/xbmc/LangInfo.h b/xbmc/LangInfo.h index aa499fde8af12..6c9898c41fde2 100644 --- a/xbmc/LangInfo.h +++ b/xbmc/LangInfo.h @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef TARGET_WINDOWS #ifdef GetDateFormat @@ -130,6 +131,9 @@ class CLangInfo : public ISettingCallback void SetCurrentRegion(const std::string& strName); const std::string& GetCurrentRegion() const; + const std::locale& GetLocale() const + { return m_locale; } + static bool CheckLanguage(const std::string& language); static void LoadTokens(const TiXmlNode* pTokens, std::vector& vecTokens); @@ -179,6 +183,7 @@ class CLangInfo : public ISettingCallback MAPREGIONS m_regions; CRegion* m_currentRegion; // points to the current region CRegion m_defaultRegion; // default, will be used if no region available via langinfo.xml + std::locale m_locale; // current locale, matching GUI settings std::string m_audioLanguage; std::string m_subtitleLanguage; From c884094f122c3f0d828edcf7217dd42d19478b35 Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Wed, 11 Feb 2015 12:29:21 +0300 Subject: [PATCH 2/9] StringUtils::AlphaNumericCompare(): do not use temporal locale object as use_facet() return only reference to facet stored in locale --- xbmc/utils/StringUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xbmc/utils/StringUtils.cpp b/xbmc/utils/StringUtils.cpp index 6d0f19ca75a87..e1f2ee166e065 100644 --- a/xbmc/utils/StringUtils.cpp +++ b/xbmc/utils/StringUtils.cpp @@ -32,6 +32,7 @@ #include "StringUtils.h" #include "utils/fstrcmp.h" #include "Util.h" +#include "LangInfo.h" #include #include @@ -739,7 +740,7 @@ int64_t StringUtils::AlphaNumericCompare(const wchar_t *left, const wchar_t *rig wchar_t *ld, *rd; wchar_t lc, rc; int64_t lnum, rnum; - const collate& coll = use_facet< collate >( locale() ); + const collate& coll = use_facet< collate >( g_langInfo.GetLocale() ); int cmp_res = 0; while (*l != 0 && *r != 0) { From 209aa6eb13e1c8ddba2bda3be18ad2e905fbcc98 Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Wed, 21 Jan 2015 21:21:16 +0300 Subject: [PATCH 3/9] [win32] Use _beginthreadex() instead of CreateThread() for better compatibility with CRT functions --- xbmc/threads/platform/win/ThreadImpl.cpp | 5 ++++- xbmc/threads/platform/win/ThreadImpl.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/xbmc/threads/platform/win/ThreadImpl.cpp b/xbmc/threads/platform/win/ThreadImpl.cpp index 76b60fa83e4c0..2f1c66ac3c85b 100644 --- a/xbmc/threads/platform/win/ThreadImpl.cpp +++ b/xbmc/threads/platform/win/ThreadImpl.cpp @@ -19,18 +19,21 @@ */ #include +#include #include "threads/platform/win/Win32Exception.h" void CThread::SpawnThread(unsigned stacksize) { // Create in the suspended state, so that no matter the thread priorities and scheduled order, the handle will be assigned // before the new thread exits. - m_ThreadOpaque.handle = CreateThread(NULL, stacksize, (LPTHREAD_START_ROUTINE)&staticThread, this, CREATE_SUSPENDED, &m_ThreadId); + unsigned threadId; + m_ThreadOpaque.handle = (HANDLE)_beginthreadex(NULL, stacksize, &staticThread, this, CREATE_SUSPENDED, &threadId); if (m_ThreadOpaque.handle == NULL) { if (logger) logger->Log(LOGERROR, "%s - fatal error %d creating thread", __FUNCTION__, GetLastError()); return; } + m_ThreadId = threadId; if (ResumeThread(m_ThreadOpaque.handle) == -1) if (logger) logger->Log(LOGERROR, "%s - fatal error %d resuming thread", __FUNCTION__, GetLastError()); diff --git a/xbmc/threads/platform/win/ThreadImpl.h b/xbmc/threads/platform/win/ThreadImpl.h index ca423e737cd8d..b670df3cb239b 100644 --- a/xbmc/threads/platform/win/ThreadImpl.h +++ b/xbmc/threads/platform/win/ThreadImpl.h @@ -30,7 +30,7 @@ struct threadOpaque typedef DWORD ThreadIdentifier; typedef threadOpaque ThreadOpaque; -typedef DWORD THREADFUNC; +#define THREADFUNC unsigned __stdcall namespace XbmcThreads { From 0486a124fb6a6bbf494df390a588296d3623868b Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Fri, 23 Jan 2015 21:58:09 +0300 Subject: [PATCH 4/9] [win32] Add win32/crts_caller for calling same function in all loaded CRTs --- project/VS2010Express/XBMC.vcxproj | 2 + project/VS2010Express/XBMC.vcxproj.filters | 6 ++ xbmc/win32/crts_caller.cpp | 97 ++++++++++++++++++++++ xbmc/win32/crts_caller.h | 74 +++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 xbmc/win32/crts_caller.cpp create mode 100644 xbmc/win32/crts_caller.h diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj index 7e873102bb5c6..dd310fdd45307 100644 --- a/project/VS2010Express/XBMC.vcxproj +++ b/project/VS2010Express/XBMC.vcxproj @@ -1460,6 +1460,7 @@ + Create Create @@ -2147,6 +2148,7 @@ + diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters index 9f19d9fc19791..840fb87be2588 100644 --- a/project/VS2010Express/XBMC.vcxproj.filters +++ b/project/VS2010Express/XBMC.vcxproj.filters @@ -3092,6 +3092,9 @@ utils + + win32 + network\httprequesthandler @@ -6021,6 +6024,9 @@ cores + + win32 + filesystem diff --git a/xbmc/win32/crts_caller.cpp b/xbmc/win32/crts_caller.cpp new file mode 100644 index 0000000000000..a30e0e593d444 --- /dev/null +++ b/xbmc/win32/crts_caller.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2015 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +/** + * \file win32\crts_caller.h + * \brief Implements crts_caller class for calling same function for all loaded CRTs. + * \author Karlson2k + */ + +#include "crts_caller.h" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif // WIN32_LEAN_AND_MEAN +#include +#include + +namespace win32_utils +{ + +static const wchar_t* const s_listOfCrts[] = +{ + { L"msvcrt.dll" }, // Visual Studio 6.0 / MinGW[-w64] + { L"msvcr70.dll" }, // Visual Studio 2002 + { L"msvcr71.dll" }, // Visual Studio 2003 + { L"msvcr80.dll" }, // Visual Studio 2005 + { L"msvcr90.dll" }, // Visual Studio 2008 +#ifdef _DEBUG + { L"msvcr90d.dll" }, // Visual Studio 2008 (debug) +#endif + { L"msvcr100.dll" }, // Visual Studio 2010 +#ifdef _DEBUG + { L"msvcr100d.dll" },// Visual Studio 2010 (debug) +#endif + { L"msvcr110.dll" }, // Visual Studio 2012 +#ifdef _DEBUG + { L"msvcr110d.dll" },// Visual Studio 2012 (debug) +#endif + { L"msvcr120.dll" }, // Visual Studio 2013 +#ifdef _DEBUG + { L"msvcr120d.dll" },// Visual Studio 2013 (debug) +#endif +}; + +std::vector crts_caller::getCrtNames() +{ + return std::vector(s_listOfCrts, s_listOfCrts + (sizeof(s_listOfCrts) / sizeof(s_listOfCrts[0]))); +} + + +crts_caller::crts_caller(const char* func_name) +{ + assert(func_name); + assert(func_name[0]); + if (func_name == NULL) + return; + + for (const wchar_t* const crtName : s_listOfCrts) + { + HMODULE hCrt = NULL; + if (!GetModuleHandleExW(0, crtName, &hCrt) || hCrt == NULL) // Flag 0 ensures that CRL will not be unloaded while we are using it here + continue; // Module not loaded + + void* func_ptr = GetProcAddress(hCrt, func_name); + if (func_ptr != NULL) + { + m_crts.push_back(hCrt); + m_funcPointers.push_back(func_ptr); + } + else + FreeLibrary(hCrt); // this CRT will not be used + } +} + +crts_caller::~crts_caller() +{ + for (void* hCrt : m_crts) + FreeLibrary((HMODULE)hCrt); +} + +} diff --git a/xbmc/win32/crts_caller.h b/xbmc/win32/crts_caller.h new file mode 100644 index 0000000000000..6fe06722a3a3c --- /dev/null +++ b/xbmc/win32/crts_caller.h @@ -0,0 +1,74 @@ +#pragma once +/* + * Copyright (C) 2015 Team Kodi + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +/** + * \file win32\crts_caller.h + * \brief Declares crts_caller class for calling same function for all loaded CRTs. + * \author Karlson2k + */ + +#include +#include + +#include + +namespace win32_utils +{ + +class crts_caller +{ +public: + crts_caller(const char* func_name); + const std::vector& get_pointers(void) + { return m_funcPointers; } + ~crts_caller(); + + template + static typename ret_type call_in_all_crts(const char* func_name, ret_type(*cur_fnc_ptr) (param_types...), param_types... params) + { + typedef ret_type(*ptr_type)(param_types...); + + if (cur_fnc_ptr == NULL) + return (ret_type)0; // cur_fnc_ptr must point to process default CRT function + + crts_caller crts(func_name); + for (void* func_ptr : crts.m_funcPointers) + { + ptr_type func = (ptr_type)func_ptr; + if (func != cur_fnc_ptr) + (void)func(params...); // ignoring result of function call + } + + return cur_fnc_ptr(params...); // return result of calling process's CRT function + } + + static std::vector getCrtNames(); +private: + std::vector m_funcPointers; + std::vector m_crts; // actually contains HMODULE +}; + +// Call function in all loaded CRTs +// Function must have same return type and same parameters in all CRTs +#define CALL_IN_CRTS(function,...) ::win32_utils::crts_caller::call_in_all_crts(BOOST_PP_STRINGIZE(function),&(function),##__VA_ARGS__) + + +} From df182ba77b1185a30165308df37afeb634e8a6f0 Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Fri, 23 Jan 2015 22:03:35 +0300 Subject: [PATCH 5/9] [win32] WIN32Util: add SetThreadLocalLocale() for controlling thread local locale --- xbmc/win32/WIN32Util.cpp | 10 ++++++++++ xbmc/win32/WIN32Util.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/xbmc/win32/WIN32Util.cpp b/xbmc/win32/WIN32Util.cpp index e3630e3647057..245d18b2349f5 100644 --- a/xbmc/win32/WIN32Util.cpp +++ b/xbmc/win32/WIN32Util.cpp @@ -42,6 +42,7 @@ #include "utils/Environment.h" #include "utils/URIUtils.h" #include "utils/StringUtils.h" +#include "win32/crts_caller.h" #define DLL_ENV_PATH "special://xbmc/system/;" \ "special://xbmc/system/players/dvdplayer/;" \ @@ -51,6 +52,8 @@ "special://xbmc/system/webserver/;" \ "special://xbmc/" +#include + extern HWND g_hWnd; using namespace std; @@ -1604,3 +1607,10 @@ std::string CWIN32Util::WUSysMsg(DWORD dwError) else return StringUtils::Format("Unknown error (0x%X)", dwError); } + +bool CWIN32Util::SetThreadLocalLocale(bool enable /* = true */) +{ + const int param = enable ? _ENABLE_PER_THREAD_LOCALE : _DISABLE_PER_THREAD_LOCALE; + return CALL_IN_CRTS(_configthreadlocale, param) != -1; +} + diff --git a/xbmc/win32/WIN32Util.h b/xbmc/win32/WIN32Util.h index 572823ba266c2..55b1ee8efb039 100644 --- a/xbmc/win32/WIN32Util.h +++ b/xbmc/win32/WIN32Util.h @@ -94,6 +94,8 @@ class CWIN32Util static bool IsUsbDevice(const std::wstring &strWdrive); static std::string WUSysMsg(DWORD dwError); + + static bool SetThreadLocalLocale(bool enable = true); private: static DEVINST GetDrivesDevInstByDiskNumber(long DiskNumber); }; From d26c9bcb054301d9cf5a46cb97b9e367f608ef18 Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Fri, 23 Jan 2015 22:04:07 +0300 Subject: [PATCH 6/9] [win32] Set thread local locale for main thread --- xbmc/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index b66f739434f3f..0889e037e09c3 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -735,6 +735,10 @@ bool CApplication::Create() return false; } +#ifdef TARGET_WINDOWS + CWIN32Util::SetThreadLocalLocale(true); // enable independent locale for each thread, see https://connect.microsoft.com/VisualStudio/feedback/details/794122 +#endif // TARGET_WINDOWS + // start the AudioEngine if (!CAEFactory::StartEngine()) { From 804e16d3b1e3377bc2f6554e867faa72f4b19040 Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Fri, 23 Jan 2015 22:05:04 +0300 Subject: [PATCH 7/9] [win32] Set thread local locale for started threads --- xbmc/threads/platform/win/ThreadImpl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xbmc/threads/platform/win/ThreadImpl.cpp b/xbmc/threads/platform/win/ThreadImpl.cpp index 2f1c66ac3c85b..843839fd7537d 100644 --- a/xbmc/threads/platform/win/ThreadImpl.cpp +++ b/xbmc/threads/platform/win/ThreadImpl.cpp @@ -21,6 +21,7 @@ #include #include #include "threads/platform/win/Win32Exception.h" +#include "../../win32/WIN32Util.h" void CThread::SpawnThread(unsigned stacksize) { @@ -73,6 +74,8 @@ void CThread::SetThreadInfo() { } + CWIN32Util::SetThreadLocalLocale(true); // avoid crashing with setlocale(), see https://connect.microsoft.com/VisualStudio/feedback/details/794122 + win32_exception::install_handler(); } From cfddde98f6390ac49841c764107278e7a3a8b0c4 Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Thu, 5 Feb 2015 22:30:30 +0300 Subject: [PATCH 8/9] JSONVariantWriter::Write(): do no re-set locale if locale is already "C" --- xbmc/utils/JSONVariantWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xbmc/utils/JSONVariantWriter.cpp b/xbmc/utils/JSONVariantWriter.cpp index 61fdd4cb173ca..43ddcea46d78b 100644 --- a/xbmc/utils/JSONVariantWriter.cpp +++ b/xbmc/utils/JSONVariantWriter.cpp @@ -35,7 +35,7 @@ string CJSONVariantWriter::Write(const CVariant &value, bool compact) // Set locale to classic ("C") to ensure valid JSON numbers const char *currentLocale = setlocale(LC_NUMERIC, NULL); std::string backupLocale; - if (currentLocale != NULL) + if (currentLocale != NULL && (currentLocale[0] != 'C' || currentLocale[1] != 0)) { backupLocale = currentLocale; setlocale(LC_NUMERIC, "C"); From 7d40084d44640753b389864bc95db583775e953e Mon Sep 17 00:00:00 2001 From: Karlson2k Date: Thu, 5 Feb 2015 22:33:43 +0300 Subject: [PATCH 9/9] [win32] JSONVariantWriter::Write(): use wide string version of setlocale() to prevent crash on win32 --- xbmc/utils/JSONVariantWriter.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/xbmc/utils/JSONVariantWriter.cpp b/xbmc/utils/JSONVariantWriter.cpp index 43ddcea46d78b..0d0a7aa32f8a0 100644 --- a/xbmc/utils/JSONVariantWriter.cpp +++ b/xbmc/utils/JSONVariantWriter.cpp @@ -33,6 +33,7 @@ string CJSONVariantWriter::Write(const CVariant &value, bool compact) yajl_gen_config(g, yajl_gen_indent_string, "\t"); // Set locale to classic ("C") to ensure valid JSON numbers +#ifndef TARGET_WINDOWS const char *currentLocale = setlocale(LC_NUMERIC, NULL); std::string backupLocale; if (currentLocale != NULL && (currentLocale[0] != 'C' || currentLocale[1] != 0)) @@ -40,6 +41,15 @@ string CJSONVariantWriter::Write(const CVariant &value, bool compact) backupLocale = currentLocale; setlocale(LC_NUMERIC, "C"); } +#else // TARGET_WINDOWS + const wchar_t* const currentLocale = _wsetlocale(LC_NUMERIC, NULL); + std::wstring backupLocale; + if (currentLocale != NULL && (currentLocale[0] != L'C' || currentLocale[1] != 0)) + { + backupLocale = currentLocale; + _wsetlocale(LC_NUMERIC, L"C"); + } +#endif // TARGET_WINDOWS if (InternalWrite(g, value)) { @@ -51,8 +61,13 @@ string CJSONVariantWriter::Write(const CVariant &value, bool compact) } // Re-set locale to what it was before using yajl +#ifndef TARGET_WINDOWS if (!backupLocale.empty()) setlocale(LC_NUMERIC, backupLocale.c_str()); +#else // TARGET_WINDOWS + if (!backupLocale.empty()) + _wsetlocale(LC_NUMERIC, backupLocale.c_str()); +#endif // TARGET_WINDOWS yajl_gen_clear(g); yajl_gen_free(g);