Skip to content

Commit

Permalink
Merge pull request xbmc#6402 from Karlson2k/w32_setloc_01
Browse files Browse the repository at this point in the history
Locale fixes
  • Loading branch information
Paxxi committed Feb 19, 2015
2 parents 0c6eadc + 7d40084 commit a4d9823
Show file tree
Hide file tree
Showing 13 changed files with 229 additions and 4 deletions.
2 changes: 2 additions & 0 deletions project/VS2010Express/XBMC.vcxproj
Expand Up @@ -1460,6 +1460,7 @@
<ClCompile Include="..\..\xbmc\view\GUIViewState.cpp" />
<ClCompile Include="..\..\xbmc\view\ViewDatabase.cpp" />
<ClCompile Include="..\..\xbmc\view\ViewStateSettings.cpp" />
<ClCompile Include="..\..\xbmc\win32\crts_caller.cpp" />
<ClCompile Include="..\..\xbmc\win32\pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug Testsuite|Win32'">Create</PrecompiledHeader>
Expand Down Expand Up @@ -2147,6 +2148,7 @@
<ClInclude Include="..\..\xbmc\view\ViewDatabase.h" />
<ClInclude Include="..\..\xbmc\view\ViewState.h" />
<ClInclude Include="..\..\xbmc\view\ViewStateSettings.h" />
<ClInclude Include="..\..\xbmc\win32\crts_caller.h" />
<ClInclude Include="..\..\xbmc\win32\IMMNotificationClient.h" />
<ClInclude Include="..\..\xbmc\win32\pch.h" />
<ClInclude Include="..\..\xbmc\win32\PlatformDefs.h" />
Expand Down
6 changes: 6 additions & 0 deletions project/VS2010Express/XBMC.vcxproj.filters
Expand Up @@ -3092,6 +3092,9 @@
<ClCompile Include="..\..\xbmc\utils\HttpRangeUtils.cpp">
<Filter>utils</Filter>
</ClCompile>
<ClCompile Include="..\..\xbmc\win32\crts_caller.cpp">
<Filter>win32</Filter>
</ClCompile>
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPFileHandler.cpp">
<Filter>network\httprequesthandler</Filter>
</ClCompile>
Expand Down Expand Up @@ -6021,6 +6024,9 @@
<ClInclude Include="..\..\xbmc\cores\DataCacheCore.h">
<Filter>cores</Filter>
</ClInclude>
<ClInclude Include="..\..\xbmc\win32\crts_caller.h">
<Filter>win32</Filter>
</ClInclude>
<ClInclude Include="..\..\xbmc\filesystem\OverrideDirectory.h">
<Filter>filesystem</Filter>
</ClInclude>
Expand Down
4 changes: 4 additions & 0 deletions xbmc/Application.cpp
Expand Up @@ -734,6 +734,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())
{
Expand Down
3 changes: 3 additions & 0 deletions xbmc/LangInfo.cpp
Expand Up @@ -198,6 +198,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();
Expand Down Expand Up @@ -421,6 +422,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";
}
Expand Down
5 changes: 5 additions & 0 deletions xbmc/LangInfo.h
Expand Up @@ -25,6 +25,7 @@
#include <map>
#include <string>
#include <vector>
#include <locale>

#ifdef TARGET_WINDOWS
#ifdef GetDateFormat
Expand Down Expand Up @@ -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<std::string>& vecTokens);
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 7 additions & 1 deletion xbmc/threads/platform/win/ThreadImpl.cpp
Expand Up @@ -19,18 +19,22 @@
*/

#include <windows.h>
#include <process.h>
#include "threads/platform/win/Win32Exception.h"
#include "../../win32/WIN32Util.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());
Expand Down Expand Up @@ -70,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();
}

Expand Down
2 changes: 1 addition & 1 deletion xbmc/threads/platform/win/ThreadImpl.h
Expand Up @@ -30,7 +30,7 @@ struct threadOpaque

typedef DWORD ThreadIdentifier;
typedef threadOpaque ThreadOpaque;
typedef DWORD THREADFUNC;
#define THREADFUNC unsigned __stdcall

namespace XbmcThreads
{
Expand Down
17 changes: 16 additions & 1 deletion xbmc/utils/JSONVariantWriter.cpp
Expand Up @@ -33,13 +33,23 @@ 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)
if (currentLocale != NULL && (currentLocale[0] != 'C' || currentLocale[1] != 0))
{
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))
{
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion xbmc/utils/StringUtils.cpp
Expand Up @@ -32,6 +32,7 @@
#include "StringUtils.h"
#include "utils/fstrcmp.h"
#include "Util.h"
#include "LangInfo.h"
#include <locale>
#include <functional>

Expand Down Expand Up @@ -740,7 +741,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<wchar_t>& coll = use_facet< collate<wchar_t> >( locale() );
const collate<wchar_t>& coll = use_facet< collate<wchar_t> >( g_langInfo.GetLocale() );
int cmp_res = 0;
while (*l != 0 && *r != 0)
{
Expand Down
10 changes: 10 additions & 0 deletions xbmc/win32/WIN32Util.cpp
Expand Up @@ -42,6 +42,7 @@
#include "utils/Environment.h"
#include "utils/URIUtils.h"
#include "utils/StringUtils.h"
#include "win32/crts_caller.h"

#include <cassert>

Expand All @@ -53,6 +54,8 @@
"special://xbmc/system/webserver/;" \
"special://xbmc/"

#include <locale.h>

extern HWND g_hWnd;

using namespace std;
Expand Down Expand Up @@ -1606,3 +1609,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;
}

2 changes: 2 additions & 0 deletions xbmc/win32/WIN32Util.h
Expand Up @@ -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);
};
Expand Down
97 changes: 97 additions & 0 deletions 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
* <http://www.gnu.org/licenses/>.
*
*/

/**
* \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 <Windows.h>
#include <cassert>

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<std::wstring> crts_caller::getCrtNames()
{
return std::vector<std::wstring>(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);
}

}
74 changes: 74 additions & 0 deletions 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
* <http://www.gnu.org/licenses/>.
*
*/

/**
* \file win32\crts_caller.h
* \brief Declares crts_caller class for calling same function for all loaded CRTs.
* \author Karlson2k
*/

#include <string>
#include <vector>

#include <boost/preprocessor/stringize.hpp>

namespace win32_utils
{

class crts_caller
{
public:
crts_caller(const char* func_name);
const std::vector<void*>& get_pointers(void)
{ return m_funcPointers; }
~crts_caller();

template <typename ret_type, typename... param_types>
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<std::wstring> getCrtNames();
private:
std::vector<void*> m_funcPointers;
std::vector<void*> 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__)


}

0 comments on commit a4d9823

Please sign in to comment.