// Returns the CultureInfo representing the first language in the list that we can construct a CultureInfo for or null if // no such culture exists. private static unsafe CultureInfo GetBestFitCultureFromLanguageList(List <string> languages) { char *localeNameBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH]; // LOCALE_NAME_MAX_LENGTH includes null terminator for (int i = 0; i < languages.Count; i++) { if (WindowsRuntimeResourceManagerBase.IsValidCulture(languages[i])) { return(new CultureInfo(languages[i])); } int result = Interop.Kernel32.ResolveLocaleName(languages[i], localeNameBuffer, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH); if (result != 0) { string localeName = new string(localeNameBuffer, 0, result - 1); // result length includes null terminator if (WindowsRuntimeResourceManagerBase.IsValidCulture(localeName)) { return(new CultureInfo(localeName)); } } } return(null); }
// Returns the CultureInfo representing the first language in the list that we can construct a CultureInfo for or null if // no such culture exists. private static CultureInfo GetBestFitCultureFromLanguageList(List <string> languages) { StringBuilder localeNameBuffer = new StringBuilder(Interop.Kernel32.LOCALE_NAME_MAX_LENGTH); for (int i = 0; i < languages.Count; i++) { if (WindowsRuntimeResourceManagerBase.IsValidCulture(languages[i])) { return(new CultureInfo(languages[i])); } if (Interop.Kernel32.ResolveLocaleName(languages[i], localeNameBuffer, localeNameBuffer.MaxCapacity) != 0) { string localeName = localeNameBuffer.ToString(); if (WindowsRuntimeResourceManagerBase.IsValidCulture(localeName)) { return(new CultureInfo(localeName)); } } } return(null); }
// Only call SetAppXConfiguration from ResourceManager constructors, and nowhere else. // Throws MissingManifestResourceException and WinRT HResults private void SetAppXConfiguration() { Contract.Assert(_bUsingModernResourceManagement == false); // Only this function writes to this member #if FEATURE_APPX Contract.Assert(_WinRTResourceManager == null); // Only this function writes to this member Contract.Assert(_PRIonAppXInitialized == false); // Only this function writes to this member Contract.Assert(_PRIExceptionInfo == null); // Only this function writes to this member bool bUsingSatelliteAssembliesUnderAppX = false; RuntimeAssembly resourcesAssembly = (RuntimeAssembly)MainAssembly; if (resourcesAssembly == null) resourcesAssembly = m_callingAssembly; if (resourcesAssembly != null) { if (resourcesAssembly != typeof(Object).Assembly) // We are not loading resources for mscorlib { // Cannot load the WindowsRuntimeResourceManager when in a compilation process, since it // lives in System.Runtime.WindowsRuntime and only mscorlib may be loaded for execution. if (AppDomain.IsAppXModel() && !AppDomain.IsAppXNGen) { s_IsAppXModel = true; // If we have the type information from the ResourceManager(Type) constructor, we use it. Otherwise, we use BaseNameField. String reswFilename = _locationInfo == null ? BaseNameField : _locationInfo.FullName; // The only way this can happen is if a class inherited from ResourceManager and // did not set the BaseNameField before calling the protected ResourceManager() constructor. // For other constructors, we would already have thrown an ArgumentNullException by now. // Throwing an ArgumentNullException now is not the right thing to do because technically // ResourceManager() takes no arguments, and because it is not documented as throwing // any exceptions. Instead, let's go through the rest of the initialization with this set to // an empty string. We may in fact fail earlier for another reason, but otherwise we will // throw a MissingManifestResourceException when GetString is called indicating that a // resW filename called "" could not be found. if (reswFilename == null) reswFilename = String.Empty; WindowsRuntimeResourceManagerBase WRRM = null; bool bWRRM_Initialized = false; if (AppDomain.IsAppXDesignMode()) { WRRM = GetWinRTResourceManager(); try { PRIExceptionInfo exceptionInfo; // If the exception info is filled in, we will ignore it. bWRRM_Initialized = WRRM.Initialize(resourcesAssembly.Location, reswFilename, out exceptionInfo); bUsingSatelliteAssembliesUnderAppX = !bWRRM_Initialized; } catch(Exception e) { bUsingSatelliteAssembliesUnderAppX = true; if (e.IsTransient) throw; } } if (!bUsingSatelliteAssembliesUnderAppX) { // See AssemblyNative::IsFrameworkAssembly for details on which kinds of assemblies are considered Framework assemblies. // The Modern Resource Manager is not used for such assemblies - they continue to use satellite assemblies (i.e. .resources.dll files). _bUsingModernResourceManagement = !ShouldUseSatelliteAssemblyResourceLookupUnderAppX(resourcesAssembly); if (_bUsingModernResourceManagement) { // Only now are we certain that we need the PRI file. // Note that if IsAppXDesignMode is false, we haven't checked if the PRI file exists. // This is by design. We will find out in the call to WindowsRuntimeResourceManager.Initialize below. // At this point it is important NOT to set _bUsingModernResourceManagement to false // if the PRI file does not exist because we are now certain we need to load PRI // resources. We want to fail by throwing a MissingManifestResourceException // if WindowsRuntimeResourceManager.Initialize fails to locate the PRI file. We do not // want to fall back to using satellite assemblies anymore. Note that we would not throw // the MissingManifestResourceException from this function, but from GetString. See the // comment below on the reason for this. if (WRRM != null && bWRRM_Initialized) { // Reuse the one successfully created earlier _WinRTResourceManager = WRRM; _PRIonAppXInitialized = true; } else { _WinRTResourceManager = GetWinRTResourceManager(); try { _PRIonAppXInitialized = _WinRTResourceManager.Initialize(resourcesAssembly.Location, reswFilename, out _PRIExceptionInfo); // Note that _PRIExceptionInfo might be null - this is OK. // In that case we will just throw the generic // MissingManifestResource_NoPRIresources exception. // See the implementation of GetString for more details. } // We would like to be able to throw a MissingManifestResourceException here if PRI resources // could not be loaded for a recognized reason. However, the ResourceManager constructors // that call SetAppXConfiguration are not documented as throwing MissingManifestResourceException, // and since they are part of the portable profile, we cannot start throwing a new exception type // as that would break existing portable libraries. Hence we must save the exception information // now and throw the exception on the first call to GetString. catch(FileNotFoundException) { // We will throw MissingManifestResource_NoPRIresources from GetString // when we see that _PRIonAppXInitialized is false. } catch(Exception e) { // ERROR_MRM_MAP_NOT_FOUND can be thrown by the call to ResourceManager.get_AllResourceMaps // in WindowsRuntimeResourceManager.Initialize. // In this case _PRIExceptionInfo is now null and we will just throw the generic // MissingManifestResource_NoPRIresources exception. // See the implementation of GetString for more details. if (e.HResult != __HResults.ERROR_MRM_MAP_NOT_FOUND) throw; // Unexpected exception code. Bubble it up to the caller. } // Allow all other exception types to bubble up to the caller. // Yes, this causes us to potentially throw exception types that are not documented. // Ultimately the tradeoff is the following: // -We could ignore unknown exceptions or rethrow them as inner exceptions // of exceptions that the ResourceManager class is already documented as throwing. // This would allow existing portable libraries to gracefully recover if they don't care // too much about the ResourceManager object they are using. However it could // mask potentially fatal errors that we are not aware of, such as a disk drive failing. // The alternative, which we chose, is to throw unknown exceptions. This may tear // down the process if the portable library and app don't expect this exception type. // On the other hand, this won't mask potentially fatal errors we don't know about. } } } } } } // resourcesAssembly == null should not happen but it can. See the comment on Assembly.GetCallingAssembly. // However for the sake of 100% backwards compatibility on Win7 and below, we must leave // _bUsingModernResourceManagement as false. #endif // FEATURE_APPX }
internal static bool SetCultureInfoForUserPreferredLanguageInAppX(CultureInfo ci) { // If running within a compilation process (mscorsvw.exe, for example), it is illegal to // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value, // which should be fine because we should only ever need to access FX resources during NGEN. // FX resources are always loaded from satellite assemblies - even in AppX processes (see the // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details). if (AppDomain.IsAppXNGen) { return false; } if (s_WindowsRuntimeResourceManager == null) { s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager(); } return s_WindowsRuntimeResourceManager.SetGlobalResourceContextDefaultCulture(ci); }
internal static CultureInfo GetCultureInfoForUserPreferredLanguageInAppX() { // If a call to GetCultureInfoForUserPreferredLanguageInAppX() generated a recursive // call to itself, return null, since we don't want to stack overflow. For example, // this can happen if some code in this method ends up calling CultureInfo.CurrentCulture // (which is common on check'd build because of BCLDebug logging which calls Int32.ToString()). // In this case, returning null will mean CultureInfo.CurrentCulture gets the default Win32 // value, which should be fine. if(ts_IsDoingAppXCultureInfoLookup) { return null; } // If running within a compilation process (mscorsvw.exe, for example), it is illegal to // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value, // which should be fine because we should only ever need to access FX resources during NGEN. // FX resources are always loaded from satellite assemblies - even in AppX processes (see the // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details). if (AppDomain.IsAppXNGen) { return null; } CultureInfo toReturn = null; try { ts_IsDoingAppXCultureInfoLookup = true; if(s_WindowsRuntimeResourceManager == null) { s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager(); } toReturn = s_WindowsRuntimeResourceManager.GlobalResourceContextBestFitCultureInfo; } finally { ts_IsDoingAppXCultureInfoLookup = false; } return toReturn; }
// Only call SetAppXConfiguration from ResourceManager constructors, and nowhere else. // Throws MissingManifestResourceException and WinRT HResults private void SetAppXConfiguration() { Debug.Assert(UseUapResourceManagement == false); // Only this function writes to this member Debug.Assert(_WinRTResourceManager == null); // Only this function writes to this member Debug.Assert(_PRIonAppXInitialized == false); // Only this function writes to this member Debug.Assert(_PRIExceptionInfo == null); // Only this function writes to this member bool bUsingSatelliteAssembliesUnderAppX = false; if (MainAssembly != null) { if (MainAssembly != typeof(object).Assembly) // We are not loading resources for System.Private.CoreLib { #if ENABLE_WINRT WinRTInteropCallbacks callbacks = WinRTInterop.UnsafeCallbacks; if (callbacks != null && callbacks.IsAppxModel()) #else if (ApplicationModel.IsUap) #endif { // If we have the type information from the ResourceManager(Type) constructor, we use it. Otherwise, we use BaseNameField. string reswFilename = _locationInfo == null ? BaseNameField : _locationInfo.FullName; // The only way this can happen is if a class inherited from ResourceManager and // did not set the BaseNameField before calling the protected ResourceManager() constructor. // For other constructors, we would already have thrown an ArgumentNullException by now. // Throwing an ArgumentNullException now is not the right thing to do because technically // ResourceManager() takes no arguments, and because it is not documented as throwing // any exceptions. Instead, let's go through the rest of the initialization with this set to // an empty string. We may in fact fail earlier for another reason, but otherwise we will // throw a MissingManifestResourceException when GetString is called indicating that a // resW filename called "" could not be found. if (reswFilename == null) { reswFilename = string.Empty; } if (!bUsingSatelliteAssembliesUnderAppX) { UseUapResourceManagement = !ShouldUseSatelliteAssemblyResourceLookupUnderAppX(MainAssembly); if (UseUapResourceManagement) { // Only now are we certain that we need the PRI file. // At this point it is important NOT to set UseUapResourceManagement to false // if the PRI file does not exist because we are now certain we need to load PRI // resources. We want to fail by throwing a MissingManifestResourceException // if WindowsRuntimeResourceManager.Initialize fails to locate the PRI file. We do not // want to fall back to using satellite assemblies anymore. Note that we would not throw // the MissingManifestResourceException from this function, but from GetString. See the // comment below on the reason for this. _WinRTResourceManager = GetWinRTResourceManager(); try { _PRIonAppXInitialized = _WinRTResourceManager.Initialize(MainAssembly.Location, reswFilename, out _PRIExceptionInfo); // Note that _PRIExceptionInfo might be null - this is OK. // In that case we will just throw the generic // MissingManifestResource_NoPRIresources exception. // See the implementation of GetString for more details. } // We would like to be able to throw a MissingManifestResourceException here if PRI resources // could not be loaded for a recognized reason. However, the ResourceManager constructors // that call SetAppXConfiguration are not documented as throwing MissingManifestResourceException, // and since they are part of the portable profile, we cannot start throwing a new exception type // as that would break existing portable libraries. Hence we must save the exception information // now and throw the exception on the first call to GetString. catch (FileNotFoundException) { // We will throw MissingManifestResource_NoPRIresources from GetString // when we see that _PRIonAppXInitialized is false. } catch (Exception e) { // ERROR_MRM_MAP_NOT_FOUND can be thrown by the call to ResourceManager.get_AllResourceMaps // in WindowsRuntimeResourceManager.Initialize. // In this case _PRIExceptionInfo is now null and we will just throw the generic // MissingManifestResource_NoPRIresources exception. // See the implementation of GetString for more details. if (e.HResult != HResults.ERROR_MRM_MAP_NOT_FOUND) { throw; // Unexpected exception code. Bubble it up to the caller. } } if (!_PRIonAppXInitialized) { UseUapResourceManagement = false; } // Allow all other exception types to bubble up to the caller. // Yes, this causes us to potentially throw exception types that are not documented. // Ultimately the tradeoff is the following: // -We could ignore unknown exceptions or rethrow them as inner exceptions // of exceptions that the ResourceManager class is already documented as throwing. // This would allow existing portable libraries to gracefully recover if they don't care // too much about the ResourceManager object they are using. However it could // mask potentially fatal errors that we are not aware of, such as a disk drive failing. // The alternative, which we chose, is to throw unknown exceptions. This may tear // down the process if the portable library and app don't expect this exception type. // On the other hand, this won't mask potentially fatal errors we don't know about. } } } } } // MainAssembly == null should not happen but it can. See the comment on Assembly.GetCallingAssembly. // However for the sake of 100% backwards compatibility on Win7 and below, we must leave // _bUsingModernResourceManagement as false. }