Locale.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #include "il2cpp-config.h"
  2. #if IL2CPP_TARGET_WINRT || IL2CPP_TARGET_XBOXONE || IL2CPP_TARGET_WINDOWS_GAMES
  3. #include "os/Locale.h"
  4. #include "os/Win32/WindowsHeaders.h"
  5. #if IL2CPP_TARGET_WINRT
  6. #include "utils/StringUtils.h"
  7. #include "WinRTVector.h"
  8. #include <Windows.ApplicationModel.Resources.Core.h>
  9. #include <wrl.h>
  10. #endif
  11. namespace il2cpp
  12. {
  13. namespace os
  14. {
  15. std::string Locale::GetLocale()
  16. {
  17. WCHAR wideLocaleName[LOCALE_NAME_MAX_LENGTH];
  18. if (GetUserDefaultLocaleName(wideLocaleName, LOCALE_NAME_MAX_LENGTH) == 0)
  19. return std::string();
  20. int length = static_cast<int>(wcslen(wideLocaleName));
  21. std::string multiLocaleName;
  22. multiLocaleName.resize(2 * length);
  23. int narrowLength = WideCharToMultiByte(CP_ACP, 0, &wideLocaleName[0], length, &multiLocaleName[0], 2 * length, NULL, NULL);
  24. multiLocaleName.resize(narrowLength);
  25. return multiLocaleName;
  26. }
  27. #if IL2CPP_TARGET_WINRT
  28. static CultureInfoChangedCallback s_OnCultureInfoChangedInAppX;
  29. static EventRegistrationToken s_OnGlobalResourceContextChangedToken;
  30. static Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::Resources::Core::IResourceContext> s_AppResourceContext;
  31. static Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IObservableMap<HSTRING, HSTRING> > s_AppResourceContextValues;
  32. static il2cpp_hresult_t DispatchLanguageUpdateToManagedCode()
  33. {
  34. using namespace ABI::Windows::Foundation::Collections;
  35. using namespace Microsoft::WRL;
  36. using namespace Microsoft::WRL::Wrappers;
  37. ComPtr<IVectorView<HSTRING> > languages;
  38. auto hr = s_AppResourceContext->get_Languages(&languages);
  39. if (FAILED(hr))
  40. return hr;
  41. uint32_t languageCount;
  42. hr = languages->get_Size(&languageCount);
  43. if (FAILED(hr))
  44. return hr;
  45. for (uint32_t i = 0; i < languageCount; i++)
  46. {
  47. HString language;
  48. hr = languages->GetAt(i, language.GetAddressOf());
  49. if (SUCCEEDED(hr))
  50. {
  51. uint32_t languageLength;
  52. auto languagePtr = language.GetRawBuffer(&languageLength);
  53. // HSTRINGs aren't null terminated so we need to copy
  54. // it into a null terminated buffer before passing it to
  55. // win32 APIs or to managed code
  56. if (languageLength >= LOCALE_NAME_MAX_LENGTH)
  57. languageLength = LOCALE_NAME_MAX_LENGTH - 1;
  58. wchar_t languageBuffer[LOCALE_NAME_MAX_LENGTH];
  59. memcpy(languageBuffer, languagePtr, languageLength * sizeof(wchar_t));
  60. languageBuffer[languageLength] = 0;
  61. if (IsValidLocaleName(languageBuffer))
  62. {
  63. s_OnCultureInfoChangedInAppX(languageBuffer);
  64. return S_OK;
  65. }
  66. wchar_t resolvedLanguage[LOCALE_NAME_MAX_LENGTH];
  67. if (ResolveLocaleName(languageBuffer, resolvedLanguage, IL2CPP_ARRAY_SIZE(resolvedLanguage)) != 0)
  68. {
  69. s_OnCultureInfoChangedInAppX(resolvedLanguage);
  70. return S_OK;
  71. }
  72. }
  73. }
  74. s_OnCultureInfoChangedInAppX(nullptr);
  75. return S_OK;
  76. }
  77. il2cpp_hresult_t Locale::InitializeUserPreferredCultureInfoInAppX(CultureInfoChangedCallback onCultureInfoChangedInAppX)
  78. {
  79. using namespace ABI::Windows::ApplicationModel::Resources::Core;
  80. using namespace ABI::Windows::Foundation::Collections;
  81. using namespace Microsoft::WRL;
  82. using namespace Microsoft::WRL::Wrappers;
  83. s_OnCultureInfoChangedInAppX = onCultureInfoChangedInAppX;
  84. if (s_OnGlobalResourceContextChangedToken.value == 0)
  85. {
  86. ComPtr<IResourceContextStatics2> resourceContextStatics;
  87. auto hr = RoGetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_Resources_Core_ResourceContext).Get(), __uuidof(resourceContextStatics), &resourceContextStatics);
  88. if (FAILED(hr))
  89. return hr;
  90. hr = resourceContextStatics->GetForViewIndependentUse(&s_AppResourceContext);
  91. if (FAILED(hr))
  92. return hr;
  93. hr = s_AppResourceContext->get_QualifierValues(&s_AppResourceContextValues);
  94. if (FAILED(hr))
  95. return hr;
  96. hr = s_AppResourceContextValues->add_MapChanged(Callback<MapChangedEventHandler<HSTRING, HSTRING> >([](IObservableMap<HSTRING, HSTRING>* sender, IMapChangedEventArgs<HSTRING>* e)
  97. {
  98. DispatchLanguageUpdateToManagedCode();
  99. return S_OK;
  100. }).Get(), &s_OnGlobalResourceContextChangedToken);
  101. if (FAILED(hr))
  102. return hr;
  103. hr = DispatchLanguageUpdateToManagedCode();
  104. if (FAILED(hr))
  105. return hr;
  106. }
  107. return IL2CPP_S_OK;
  108. }
  109. static bool AreLanguagesEqual(HSTRING language, const Il2CppChar* name, uint32_t length)
  110. {
  111. uint32_t languageLength;
  112. auto languagePtr = WindowsGetStringRawBuffer(language, &languageLength);
  113. return CompareStringOrdinal(name, length, languagePtr, languageLength, TRUE) == CSTR_EQUAL;
  114. }
  115. il2cpp_hresult_t Locale::SetUserPreferredCultureInfoInAppX(const Il2CppChar* name)
  116. {
  117. using namespace ABI::Windows::Foundation::Collections;
  118. using namespace Microsoft::WRL;
  119. using namespace Microsoft::WRL::Wrappers;
  120. ComPtr<IVectorView<HSTRING> > languages;
  121. auto hr = s_AppResourceContext->get_Languages(&languages);
  122. if (FAILED(hr))
  123. return hr;
  124. uint32_t languageCount;
  125. hr = languages->get_Size(&languageCount);
  126. if (FAILED(hr))
  127. return hr;
  128. auto nameLength = static_cast<uint32_t>(utils::StringUtils::StrLen(name));
  129. if (languageCount > 0)
  130. {
  131. HString firstLanguage;
  132. if (SUCCEEDED(languages->GetAt(0, firstLanguage.GetAddressOf())) && AreLanguagesEqual(firstLanguage.Get(), name, nameLength))
  133. return S_OK; // Nothing to do, the language is already set
  134. }
  135. auto newLanguages = Make<winrt::Vector<HSTRING> >();
  136. newLanguages->Reserve(languageCount + 1);
  137. newLanguages->Append(HStringReference(name).Get());
  138. if (languageCount > 0)
  139. {
  140. HString language;
  141. if (SUCCEEDED(languages->GetAt(0, language.GetAddressOf())))
  142. {
  143. // No need to check for duplicates: we already checked that the new language doesn't match the first language above
  144. newLanguages->Append(language.Get());
  145. }
  146. for (uint32_t i = 1; i < languageCount; i++)
  147. {
  148. if (SUCCEEDED(languages->GetAt(i, language.GetAddressOf())) && !AreLanguagesEqual(language.Get(), name, nameLength))
  149. newLanguages->Append(language.Get());
  150. }
  151. }
  152. return s_AppResourceContext->put_Languages(newLanguages.Get());
  153. }
  154. void Locale::UnInitializeWinRT()
  155. {
  156. if (s_OnGlobalResourceContextChangedToken.value != 0)
  157. {
  158. s_AppResourceContextValues->remove_MapChanged(s_OnGlobalResourceContextChangedToken);
  159. s_OnGlobalResourceContextChangedToken.value = 0;
  160. }
  161. s_OnCultureInfoChangedInAppX = nullptr;
  162. s_AppResourceContext = nullptr;
  163. s_AppResourceContextValues = nullptr;
  164. }
  165. #endif
  166. } /* namespace os */
  167. } /* namespace il2cpp */
  168. #endif