3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
8 ** Class: ResourceManager
10 ** <OWNER>jathaine</OWNER>
13 ** Purpose: Default way to access String and Object resources
17 ===========================================================*/
19 namespace System.Resources {
22 using System.Globalization;
23 using System.Collections;
25 using System.Reflection;
26 using System.Runtime.Serialization;
27 using System.Security;
28 using System.Security.Permissions;
29 using System.Threading;
30 using System.Runtime.InteropServices;
31 using System.Runtime.CompilerServices;
32 using Microsoft.Win32;
33 using System.Collections.Generic;
34 using System.Runtime.Versioning;
35 using System.Diagnostics.Contracts;
37 using System.Diagnostics.Tracing;
42 // This is implemented in System.Runtime.WindowsRuntime as function System.Resources.WindowsRuntimeResourceManager,
43 // allowing us to ask for a WinRT-specific ResourceManager.
44 // It is important to have WindowsRuntimeResourceManagerBase as regular class with virtual methods and default implementations.
45 // Defining WindowsRuntimeResourceManagerBase as abstract class or interface will cause issues when adding more methods to it
46 // because it�ll create dependency between mscorlib and System.Runtime.WindowsRuntime which will require always shipping both DLLs together.
47 // Also using interface or abstract class will not play nice with FriendAccessAllowed.
51 internal class WindowsRuntimeResourceManagerBase
54 public virtual bool Initialize(string libpath, string reswFilename, out PRIExceptionInfo exceptionInfo){exceptionInfo = null; return false;}
57 public virtual String GetString(String stringName, String startingCulture, String neutralResourcesCulture){return null;}
59 public virtual CultureInfo GlobalResourceContextBestFitCultureInfo {
65 public virtual bool SetGlobalResourceContextDefaultCulture(CultureInfo ci) { return false; }
69 // [Microsoft 3/9/2012] This class should be named PRIErrorInfo.
71 // During Dev11 CLR RC Ask mode, the Windows Modern Resource Manager
72 // made a breaking change such that ResourceMap.GetSubtree returns null when a subtree is
73 // not found instead of throwing an exception. As a result the name of this class is no longer accurate.
74 // It should be called PRIErrorInfo. However changing the name of this internal class would cause
75 // mscorlib.asmmeta and System.Runtime.WindowsRuntime.asmmeta to change,
76 // which would in turn require updating of the mscorlib and System.Runtime.WindowsRuntime
77 // reference assemblies under InternalApis. This would not meet the Ask Mode bar at this time.
78 // To get an idea of which files may need to be updated when updating this name,
79 // see changeset 399234 in the DevDiv2 database, though the update procedure may have changed
80 // by the time you read this.
81 internal class PRIExceptionInfo
83 public string _PackageSimpleName;
84 public string _ResWFile;
86 #endif // FEATURE_APPX
88 // Resource Manager exposes an assembly's resources to an application for
89 // the correct CultureInfo. An example would be localizing text for a
90 // user-visible message. Create a set of resource files listing a name
91 // for a message and its value, compile them using ResGen, put them in
92 // an appropriate place (your assembly manifest(?)), then create a Resource
93 // Manager and query for the name of the message you want. The Resource
94 // Manager will use CultureInfo.GetCurrentUICulture() to look
95 // up a resource for your user's locale settings.
97 // Users should ideally create a resource file for every culture, or
98 // at least a meaningful subset. The filenames will follow the naming
101 // basename.culture name.resources
103 // The base name can be the name of your application, or depending on
104 // the granularity desired, possibly the name of each class. The culture
105 // name is determined from CultureInfo's Name property.
106 // An example file name may be MyApp.en-US.resources for
107 // MyApp's US English resources.
112 // In Feb 08, began first step of refactoring ResourceManager to improve
113 // maintainability (sd changelist 3012100). This resulted in breaking
114 // apart the InternalGetResourceSet "big loop" so that the file-based
115 // and manifest-based lookup was located in separate methods.
116 // In Apr 08, continued refactoring so that file-based and manifest-based
117 // concerns are encapsulated by separate classes. At construction, the
118 // ResourceManager creates one of these classes based on whether the
119 // RM will need to use file-based or manifest-based resources, and
120 // afterwards refers to this through the interface IResourceGroveler.
122 // Serialization Compat: Ideally, we could have refactored further but
123 // this would have broken serialization compat. For example, the
124 // ResourceManager member UseManifest and UseSatelliteAssem are no
125 // longer relevant on ResourceManager. Similarly, other members could
126 // ideally be moved to the file-based or manifest-based classes
127 // because they are only relevant for those types of lookup.
129 // Solution now / in the future:
130 // For now, we simply use a mediator class so that we can keep these
131 // members on ResourceManager but allow the file-based and manifest-
132 // based classes to access/set these members in a uniform way. See
133 // ResourceManagerMediator.
134 // We encapsulate fallback logic in a fallback iterator class, so that
135 // this logic isn't duplicated in several methods.
137 // In the future, we can look into either breaking serialization if we
138 // decide this doesn't make sense for ResourceManager (i.e. how common
139 // is the scenario), manually make serialization work by providing
140 // appropriate OnSerialization, Deserialization methods. We can also
141 // look into further factoring and better design of IResourceGroveler
142 // interface to accommodate unused parameters that don't make sense
143 // for either file-based or manifest-based lookup paths.
145 // Benefits of this refactoring:
146 // - Makes it possible to understand what the ResourceManager does,
147 // which is key for maintainability.
148 // - Makes the ResourceManager more extensible by identifying and
149 // encapsulating what varies
173 [System.Runtime.InteropServices.ComVisible(true)]
174 public class ResourceManager
177 internal class CultureNameResourceSetPair {
178 public String lastCultureName;
179 public ResourceSet lastResourceSet;
182 protected String BaseNameField;
183 // Sets is a many-to-one table of CultureInfos mapped to ResourceSets.
184 // Don't synchronize ResourceSets - too fine-grained a lock to be effective
185 [Obsolete("call InternalGetResourceSet instead")]
186 protected Hashtable ResourceSets;
189 // don't serialize the cache of ResourceSets
191 private Dictionary <String,ResourceSet> _resourceSets;
192 private String moduleDir; // For assembly-ignorant directory location
193 protected Assembly MainAssembly; // Need the assembly manifest sometimes.
194 private Type _locationInfo; // For Assembly or type-based directory layout
195 private Type _userResourceSet; // Which ResourceSet instance to create
196 private CultureInfo _neutralResourcesCulture; // For perf optimizations.
199 private CultureNameResourceSetPair _lastUsedResourceCache;
201 private bool _ignoreCase; // Whether case matters in GetString & GetObject
203 private bool UseManifest; // Use Assembly manifest, or grovel disk.
205 // unused! But need to keep for serialization
206 [OptionalField(VersionAdded = 1)]
207 private bool UseSatelliteAssem; // Are all the .resources files in the
208 // main assembly, or in satellite assemblies for each culture?
209 #if RESOURCE_SATELLITE_CONFIG
210 private static volatile Hashtable _installedSatelliteInfo; // Give the user the option
211 // to prevent certain satellite assembly probes via a config file.
212 // Note that config files are per-appdomain, not per-assembly nor process
213 private static volatile bool _checkedConfigFile; // Did we read the app's config file?
216 // Whether to fall back to the main assembly or a particular
217 // satellite for the neutral resources.
219 private UltimateResourceFallbackLocation _fallbackLoc;
220 // Version number of satellite assemblies to look for. May be null.
222 private Version _satelliteContractVersion;
224 private bool _lookedForSatelliteContractVersion;
226 // unused! But need to keep for serialization
227 [OptionalField(VersionAdded = 1)]
228 private Assembly _callingAssembly; // Assembly who created the ResMgr.
230 // replaces _callingAssembly
231 [OptionalField(VersionAdded = 4)]
232 private RuntimeAssembly m_callingAssembly; // Assembly who created the ResMgr.
234 // no need to serialize this; just create a new one on deserialization
236 private IResourceGroveler resourceGroveler;
238 public static readonly int MagicNumber = unchecked((int)0xBEEFCACE); // If only hex had a K...
240 // Version number so ResMgr can get the ideal set of classes for you.
242 // 1) MagicNumber (little endian Int32)
243 // 2) HeaderVersionNumber (little endian Int32)
244 // 3) Num Bytes to skip past ResMgr header (little endian Int32)
245 // 4) IResourceReader type name for this file (bytelength-prefixed UTF-8 String)
246 // 5) ResourceSet type name for this file (bytelength-prefixed UTF8 String)
247 public static readonly int HeaderVersionNumber = 1;
250 //It would be better if we could use _neutralCulture instead of calling
251 //CultureInfo.InvariantCulture everywhere, but we run into problems with the .cctor. CultureInfo
252 //initializes assembly, which initializes ResourceManager, which tries to get a CultureInfo which isn't
253 //there yet because CultureInfo's class initializer hasn't finished. If we move SystemResMgr off of
254 //Assembly (or at least make it an internal property) we should be able to circumvent this problem.
256 // private static CultureInfo _neutralCulture = null;
258 // This is our min required ResourceSet type.
259 private static readonly Type _minResourceSet = typeof(ResourceSet);
260 // These Strings are used to avoid using Reflection in CreateResourceSet.
261 // The first set are used by ResourceWriter. The second are used by
263 internal static readonly String ResReaderTypeName = typeof(ResourceReader).FullName;
264 internal static readonly String ResSetTypeName = typeof(RuntimeResourceSet).FullName;
265 internal static readonly String MscorlibName = typeof(ResourceReader).Assembly.FullName;
266 internal const String ResFileExtension = ".resources";
267 internal const int ResFileExtensionLength = 10;
269 // My private debugging aid. Set to 5 or 6 for verbose output. Set to 3
270 // for summary level information.
271 internal static readonly int DEBUG = 0; //Making this const causes C# to consider all of the code that it guards unreachable.
273 private static volatile bool s_IsAppXModel;
275 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
278 m_callingAssembly = (RuntimeAssembly)Assembly.GetCallingAssembly();
281 protected ResourceManager()
284 // This constructor is not designed to be used under AppX and is not in the Win8 profile.
285 // However designers may use them even if they are running under AppX since they are
286 // not subject to the restrictions of the Win8 profile.
287 Contract.Assert(!AppDomain.IsAppXModel() || AppDomain.IsAppXDesignMode());
292 _lastUsedResourceCache = new CultureNameResourceSetPair();
293 ResourceManagerMediator mediator = new ResourceManagerMediator(this);
294 resourceGroveler = new ManifestBasedResourceGroveler(mediator);
297 // Constructs a Resource Manager for files beginning with
298 // baseName in the directory specified by resourceDir
299 // or in the current directory. This Assembly-ignorant constructor is
300 // mostly useful for testing your own ResourceSet implementation.
302 // A good example of a baseName might be "Strings". BaseName
303 // should not end in ".resources".
305 // Note: System.Windows.Forms uses this method at design time.
307 [ResourceExposure(ResourceScope.Machine)]
308 [ResourceConsumption(ResourceScope.Machine)]
309 private ResourceManager(String baseName, String resourceDir, Type usingResourceSet) {
311 throw new ArgumentNullException("baseName");
312 if (null==resourceDir)
313 throw new ArgumentNullException("resourceDir");
314 Contract.EndContractBlock();
317 // This constructor is not designed to be used under AppX and is not in the Win8 profile.
318 // However designers may use them even if they are running under AppX since they are
319 // not subject to the restrictions of the Win8 profile.
320 Contract.Assert(!AppDomain.IsAppXModel() || AppDomain.IsAppXDesignMode());
323 BaseNameField = baseName;
325 moduleDir = resourceDir;
326 _userResourceSet = usingResourceSet;
327 #pragma warning disable 618
328 ResourceSets = new Hashtable(); // for backward compatibility
329 #pragma warning restore 618
330 _resourceSets = new Dictionary<String, ResourceSet>();
331 _lastUsedResourceCache = new CultureNameResourceSetPair();
334 ResourceManagerMediator mediator = new ResourceManagerMediator(this);
335 resourceGroveler = new FileBasedResourceGroveler(mediator);
337 #if !FEATURE_CORECLR && !MONO // PAL doesn't support eventing, and we don't compile event providers for coreclr
338 if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled()) {
339 CultureInfo culture = CultureInfo.InvariantCulture;
340 String defaultResName = GetResourceFileName(culture);
342 if (resourceGroveler.HasNeutralResources(culture, defaultResName)) {
343 FrameworkEventSource.Log.ResourceManagerNeutralResourcesFound(BaseNameField, MainAssembly, defaultResName);
346 FrameworkEventSource.Log.ResourceManagerNeutralResourcesNotFound(BaseNameField, MainAssembly, defaultResName);
352 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
353 public ResourceManager(String baseName, Assembly assembly)
356 throw new ArgumentNullException("baseName");
359 throw new ArgumentNullException("assembly");
360 Contract.EndContractBlock();
362 if (!(assembly is RuntimeAssembly))
363 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"));
365 MainAssembly = assembly;
366 BaseNameField = baseName;
368 SetAppXConfiguration();
370 CommonAssemblyInit();
372 m_callingAssembly = (RuntimeAssembly)Assembly.GetCallingAssembly();
373 // Special case for mscorlib - protect mscorlib's private resources.
374 // This isn't for security reasons, but to ensure we can make
375 // breaking changes to mscorlib's internal resources without
376 // assuming users may have taken a dependency on them.
377 if (assembly == typeof(Object).Assembly && m_callingAssembly != assembly)
379 m_callingAssembly = null;
383 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
384 public ResourceManager(String baseName, Assembly assembly, Type usingResourceSet)
387 throw new ArgumentNullException("baseName");
389 throw new ArgumentNullException("assembly");
390 Contract.EndContractBlock();
393 // This constructor is not designed to be used under AppX and is not in the Win8 profile.
394 // However designers may use them even if they are running under AppX since they are
395 // not subject to the restrictions of the Win8 profile.
396 Contract.Assert(!AppDomain.IsAppXModel() || AppDomain.IsAppXDesignMode());
399 if (!(assembly is RuntimeAssembly))
400 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"));
402 MainAssembly = assembly;
403 BaseNameField = baseName;
405 if (usingResourceSet != null && (usingResourceSet != _minResourceSet) && !(usingResourceSet.IsSubclassOf(_minResourceSet)))
406 throw new ArgumentException(Environment.GetResourceString("Arg_ResMgrNotResSet"), "usingResourceSet");
407 _userResourceSet = usingResourceSet;
409 CommonAssemblyInit();
410 m_callingAssembly = (RuntimeAssembly)Assembly.GetCallingAssembly();
411 // Special case for mscorlib - protect mscorlib's private resources.
412 // This isn't for security reasons, but to ensure we can make
413 // breaking changes to mscorlib's internal resources without
414 // assuming users may have taken a dependency on them.
415 if (assembly == typeof(Object).Assembly && m_callingAssembly != assembly)
416 m_callingAssembly = null;
419 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
420 public ResourceManager(Type resourceSource)
422 if (null==resourceSource)
423 throw new ArgumentNullException("resourceSource");
424 Contract.EndContractBlock();
426 if (!(resourceSource is RuntimeType))
427 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"));
429 _locationInfo = resourceSource;
430 MainAssembly = _locationInfo.Assembly;
431 BaseNameField = resourceSource.Name;
433 SetAppXConfiguration();
435 CommonAssemblyInit();
437 m_callingAssembly = (RuntimeAssembly)Assembly.GetCallingAssembly();
438 // Special case for mscorlib - protect mscorlib's private resources.
439 if (MainAssembly == typeof(Object).Assembly && m_callingAssembly != MainAssembly)
441 m_callingAssembly = null;
446 private void OnDeserializing(StreamingContext ctx)
448 this._resourceSets = null;
449 this.resourceGroveler = null;
450 this._lastUsedResourceCache = null;
453 [System.Security.SecuritySafeCritical]
455 private void OnDeserialized(StreamingContext ctx)
457 _resourceSets = new Dictionary<String, ResourceSet>();
458 _lastUsedResourceCache = new CultureNameResourceSetPair();
459 // set up resource groveler, depending on whether this ResourceManager
460 // is looking for files or assemblies
461 ResourceManagerMediator mediator = new ResourceManagerMediator(this);
464 resourceGroveler = new ManifestBasedResourceGroveler(mediator);
468 resourceGroveler = new FileBasedResourceGroveler(mediator);
471 // correct callingAssembly for v2
472 if (this.m_callingAssembly == null)
474 this.m_callingAssembly = (RuntimeAssembly)_callingAssembly;
477 // v2 does this lazily
478 if (UseManifest && this._neutralResourcesCulture == null)
480 _neutralResourcesCulture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(MainAssembly, ref _fallbackLoc);
485 private void OnSerializing(StreamingContext ctx)
487 // Initialize the fields Whidbey expects
488 _callingAssembly = m_callingAssembly;
489 UseSatelliteAssem = UseManifest;
490 #pragma warning disable 618
491 ResourceSets = new Hashtable(); // for backward compatibility
492 #pragma warning restore 618
496 // Trying to unify code as much as possible, even though having to do a
497 // security check in each constructor prevents it.
498 [System.Security.SecuritySafeCritical]
499 private void CommonAssemblyInit()
501 if (_bUsingModernResourceManagement == false)
505 _resourceSets = new Dictionary<String,ResourceSet>();
506 _lastUsedResourceCache = new CultureNameResourceSetPair();
508 _fallbackLoc = UltimateResourceFallbackLocation.MainAssembly;
510 ResourceManagerMediator mediator = new ResourceManagerMediator(this);
511 resourceGroveler = new ManifestBasedResourceGroveler(mediator);
514 _neutralResourcesCulture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(MainAssembly, ref _fallbackLoc);
516 #if !FEATURE_CORECLR // PAL doesn't support eventing, and we don't compile event providers for coreclr
517 if (_bUsingModernResourceManagement == false)
520 if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled()) {
521 CultureInfo culture = CultureInfo.InvariantCulture;
522 String defaultResName = GetResourceFileName(culture);
524 if (resourceGroveler.HasNeutralResources(culture, defaultResName)) {
525 FrameworkEventSource.Log.ResourceManagerNeutralResourcesFound(BaseNameField, MainAssembly, defaultResName);
528 String outputResName = defaultResName;
529 if (_locationInfo != null && _locationInfo.Namespace != null)
530 outputResName = _locationInfo.Namespace + Type.Delimiter + defaultResName;
531 FrameworkEventSource.Log.ResourceManagerNeutralResourcesNotFound(BaseNameField, MainAssembly, outputResName);
535 #pragma warning disable 618
536 ResourceSets = new Hashtable(); // for backward compatibility
537 #pragma warning restore 618
542 // Gets the base name for the ResourceManager.
543 public virtual String BaseName {
544 get { return BaseNameField; }
547 // Whether we should ignore the capitalization of resources when calling
548 // GetString or GetObject.
549 public virtual bool IgnoreCase {
550 get { return _ignoreCase; }
551 set { _ignoreCase = value; }
554 // Returns the Type of the ResourceSet the ResourceManager uses
555 // to construct ResourceSets.
556 public virtual Type ResourceSetType {
557 get { return (_userResourceSet == null) ? typeof(RuntimeResourceSet) : _userResourceSet; }
560 protected UltimateResourceFallbackLocation FallbackLocation
562 get { return _fallbackLoc; }
563 set { _fallbackLoc = value; }
566 // Tells the ResourceManager to call Close on all ResourceSets and
567 // release all resources. This will shrink your working set by
568 // potentially a substantial amount in a running application. Any
569 // future resource lookups on this ResourceManager will be as
570 // expensive as the very first lookup, since it will need to search
571 // for files and load resources again.
573 // This may be useful in some complex threading scenarios, where
574 // creating a new ResourceManager isn't quite the correct behavior.
575 public virtual void ReleaseAllResources()
577 #if !FEATURE_CORECLR && !MONO
578 if (FrameworkEventSource.IsInitialized)
580 FrameworkEventSource.Log.ResourceManagerReleasingResources(BaseNameField, MainAssembly);
583 Dictionary<String, ResourceSet> localResourceSets = _resourceSets;
585 // If any calls to Close throw, at least leave ourselves in a
587 _resourceSets = new Dictionary<String,ResourceSet>();
588 _lastUsedResourceCache = new CultureNameResourceSetPair();
590 lock(localResourceSets) {
591 IDictionaryEnumerator setEnum = localResourceSets.GetEnumerator();
594 IDictionaryEnumerator setEnum2 = null;
595 #pragma warning disable 618
596 if (ResourceSets != null) {
597 setEnum2 = ResourceSets.GetEnumerator();
599 ResourceSets = new Hashtable(); // for backwards compat
600 #pragma warning restore 618
603 while (setEnum.MoveNext()) {
604 ((ResourceSet)setEnum.Value).Close();
608 if (setEnum2 != null) {
609 while (setEnum2.MoveNext()) {
610 ((ResourceSet)setEnum2.Value).Close();
617 [ResourceExposure(ResourceScope.Machine)]
618 [ResourceConsumption(ResourceScope.Machine)]
619 public static ResourceManager CreateFileBasedResourceManager(String baseName, String resourceDir, Type usingResourceSet)
621 return new ResourceManager(baseName, resourceDir, usingResourceSet);
624 // Given a CultureInfo, GetResourceFileName generates the name for
625 // the binary file for the given CultureInfo. This method uses
626 // CultureInfo's Name property as part of the file name for all cultures
627 // other than the invariant culture. This method does not touch the disk,
628 // and is used only to construct what a resource file name (suitable for
629 // passing to the ResourceReader constructor) or a manifest resource file
630 // name should look like.
632 // This method can be overriden to look for a different extension,
633 // such as ".ResX", or a completely different format for naming files.
634 protected virtual String GetResourceFileName(CultureInfo culture) {
635 StringBuilder sb = new StringBuilder(255);
636 sb.Append(BaseNameField);
637 // If this is the neutral culture, don't append culture name.
638 if (!culture.HasInvariantCultureName)
640 CultureInfo.VerifyCultureName(culture.Name, true);
642 sb.Append(culture.Name);
644 sb.Append(ResFileExtension);
645 return sb.ToString();
648 // WARNING: This function must be kept in sync with ResourceFallbackManager.GetEnumerator()
649 // Return the first ResourceSet, based on the first culture ResourceFallbackManager would return
650 internal ResourceSet GetFirstResourceSet(CultureInfo culture)
652 // Logic from ResourceFallbackManager.GetEnumerator()
653 if (_neutralResourcesCulture != null && culture.Name == _neutralResourcesCulture.Name)
655 culture = CultureInfo.InvariantCulture;
658 if(_lastUsedResourceCache != null) {
659 lock (_lastUsedResourceCache) {
660 if (culture.Name == _lastUsedResourceCache.lastCultureName)
661 return _lastUsedResourceCache.lastResourceSet;
665 // Look in the ResourceSet table
666 Dictionary<String,ResourceSet> localResourceSets = _resourceSets;
667 ResourceSet rs = null;
668 if (localResourceSets != null)
670 lock (localResourceSets)
672 localResourceSets.TryGetValue(culture.Name, out rs);
678 // update the cache with the most recent ResourceSet
679 if (_lastUsedResourceCache != null) {
680 lock (_lastUsedResourceCache) {
681 _lastUsedResourceCache.lastCultureName = culture.Name;
682 _lastUsedResourceCache.lastResourceSet = rs;
691 // Looks up a set of resources for a particular CultureInfo. This is
692 // not useful for most users of the ResourceManager - call
693 // GetString() or GetObject() instead.
695 // The parameters let you control whether the ResourceSet is created
696 // if it hasn't yet been loaded and if parent CultureInfos should be
697 // loaded as well for resource inheritance.
699 [System.Security.SecuritySafeCritical] // auto-generated
700 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
701 public virtual ResourceSet GetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents) {
703 throw new ArgumentNullException("culture");
704 Contract.EndContractBlock();
706 Dictionary<String,ResourceSet> localResourceSets = _resourceSets;
708 if (localResourceSets != null) {
709 lock (localResourceSets) {
710 if (localResourceSets.TryGetValue(culture.Name, out rs))
715 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
717 if (UseManifest && culture.HasInvariantCultureName) {
718 string fileName = GetResourceFileName(culture);
719 RuntimeAssembly mainAssembly = (RuntimeAssembly)MainAssembly;
720 Stream stream = mainAssembly.GetManifestResourceStream(_locationInfo, fileName, m_callingAssembly == MainAssembly, ref stackMark);
721 if (createIfNotExists && stream!=null) {
722 rs = ((ManifestBasedResourceGroveler)resourceGroveler).CreateResourceSet(stream, MainAssembly);
723 AddResourceSet(localResourceSets, culture.Name, ref rs);
728 // Note: ideally we could plumb through the stack crawl mark here, but we must
729 // call the virtual 3-argument InternalGetResourceSet method for compatibility.
730 // Security-wise, we're not overly interested in protecting access to resources,
731 // since full-trust callers can get them already and most resources are public.
732 // Also, the JIT inliner could always inline a caller into another assembly's
733 // method, so the entire idea of a security check written this way is ----.
734 // So if we happen to return some resources in cases where we should really be
735 // doing a demand for member access permissions, we're not overly concerned.
737 return InternalGetResourceSet(culture, createIfNotExists, tryParents);
740 // InternalGetResourceSet is a non-threadsafe method where all the logic
741 // for getting a resource set lives. Access to it is controlled by
742 // threadsafe methods such as GetResourceSet, GetString, & GetObject.
743 // This will take a minimal number of locks.
744 [System.Security.SecuritySafeCritical] // auto-generated
745 [ResourceExposure(ResourceScope.None)]
746 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
747 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
748 protected virtual ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
750 Contract.Assert(culture != null, "culture != null");
752 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
753 return InternalGetResourceSet(culture,createIfNotExists,tryParents, ref stackMark);
756 // InternalGetResourceSet is a non-threadsafe method where all the logic
757 // for getting a resource set lives. Access to it is controlled by
758 // threadsafe methods such as GetResourceSet, GetString, & GetObject.
759 // This will take a minimal number of locks.
760 [System.Security.SecurityCritical]
761 [ResourceExposure(ResourceScope.None)]
762 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
763 private ResourceSet InternalGetResourceSet(CultureInfo requestedCulture, bool createIfNotExists, bool tryParents, ref StackCrawlMark stackMark)
765 Dictionary<String, ResourceSet> localResourceSets = _resourceSets;
766 ResourceSet rs = null;
767 CultureInfo foundCulture = null;
768 lock (localResourceSets) {
769 if (localResourceSets.TryGetValue(requestedCulture.Name, out rs)) {
770 #if !FEATURE_CORECLR && !MONO
771 if (FrameworkEventSource.IsInitialized) {
772 FrameworkEventSource.Log.ResourceManagerFoundResourceSetInCache(BaseNameField, MainAssembly, requestedCulture.Name);
779 ResourceFallbackManager mgr = new ResourceFallbackManager(requestedCulture, _neutralResourcesCulture, tryParents);
781 foreach (CultureInfo currentCultureInfo in mgr)
783 #if !FEATURE_CORECLR && !MONO
784 if (FrameworkEventSource.IsInitialized)
786 FrameworkEventSource.Log.ResourceManagerLookingForResourceSet(BaseNameField, MainAssembly, currentCultureInfo.Name);
789 lock(localResourceSets) {
790 if (localResourceSets.TryGetValue(currentCultureInfo.Name, out rs)) {
791 #if !FEATURE_CORECLR && !MONO
792 if (FrameworkEventSource.IsInitialized)
794 FrameworkEventSource.Log.ResourceManagerFoundResourceSetInCache(BaseNameField, MainAssembly, currentCultureInfo.Name);
797 // we need to update the cache if we fellback
798 if(requestedCulture != currentCultureInfo) foundCulture = currentCultureInfo;
803 // InternalGetResourceSet will never be threadsafe. However, it must
804 // be protected against reentrancy from the SAME THREAD. (ie, calling
805 // GetSatelliteAssembly may send some window messages or trigger the
806 // Assembly load event, which could fail then call back into the
807 // ResourceManager). It's happened.
809 rs = resourceGroveler.GrovelForResourceSet(currentCultureInfo, localResourceSets,
810 tryParents, createIfNotExists, ref stackMark);
812 // found a ResourceSet; we're done
815 foundCulture = currentCultureInfo;
821 if (rs != null && foundCulture != null)
823 // add entries to the cache for the cultures we have gone through
825 // currentCultureInfo now refers to the culture that had resources.
826 // update cultures starting from requested culture up to the culture
827 // that had resources.
828 foreach (CultureInfo updateCultureInfo in mgr)
830 AddResourceSet(localResourceSets, updateCultureInfo.Name, ref rs);
832 // stop when we've added current or reached invariant (top of chain)
833 if (updateCultureInfo == foundCulture)
843 // Simple helper to ease maintenance and improve readability.
844 private static void AddResourceSet(Dictionary<String,ResourceSet> localResourceSets, String cultureName, ref ResourceSet rs)
846 // InternalGetResourceSet is both recursive and reentrant -
847 // assembly load callbacks in particular are a way we can call
848 // back into the ResourceManager in unexpectedly on the same thread.
849 lock(localResourceSets) {
850 // If another thread added this culture, return that.
851 ResourceSet lostRace;
852 if (localResourceSets.TryGetValue(cultureName, out lostRace)) {
853 if (!Object.ReferenceEquals(lostRace, rs)) {
854 // Note: In certain cases, we can be trying to add a ResourceSet for multiple
855 // cultures on one thread, while a second thread added another ResourceSet for one
856 // of those cultures. So when we lose the ----, we must make sure our ResourceSet
857 // isn't in our dictionary before closing it.
858 if (!localResourceSets.ContainsValue(rs))
864 localResourceSets.Add(cultureName, rs);
869 protected static Version GetSatelliteContractVersion(Assembly a)
871 // Ensure that the assembly reference is not null
873 throw new ArgumentNullException("a", Environment.GetResourceString("ArgumentNull_Assembly"));
875 Contract.EndContractBlock();
877 #if !FEATURE_WINDOWSPHONE
879 if (a.ReflectionOnly) {
880 foreach (CustomAttributeData data in CustomAttributeData.GetCustomAttributes(a)) {
881 if (data.Constructor.DeclaringType == typeof(SatelliteContractVersionAttribute)) {
882 v = (String)data.ConstructorArguments[0].Value;
891 Object[] attrs = a.GetCustomAttributes(typeof(SatelliteContractVersionAttribute), false);
892 if (attrs.Length == 0)
894 Contract.Assert(attrs.Length == 1, "Cannot have multiple instances of SatelliteContractVersionAttribute on an assembly!");
895 v = ((SatelliteContractVersionAttribute)attrs[0]).Version;
899 ver = new Version(v);
901 catch(ArgumentOutOfRangeException e) {
902 // Note we are prone to hitting infinite loops if mscorlib's
903 // SatelliteContractVersionAttribute contains bogus values.
904 // If this assert fires, please fix the build process for the
906 if (a == typeof(Object).Assembly) {
907 Contract.Assert(false, "mscorlib's SatelliteContractVersionAttribute is a malformed version string!");
911 throw new ArgumentException(Environment.GetResourceString("Arg_InvalidSatelliteContract_Asm_Ver", a.ToString(), v), e);
915 // On the phone return null. The calling code will use the assembly version instead to avoid potential type
916 // and library loads caused by CA lookup. NetCF uses the assembly version always.
921 [System.Security.SecuritySafeCritical] // auto-generated
922 protected static CultureInfo GetNeutralResourcesLanguage(Assembly a)
924 // This method should be obsolete - replace it with the one below.
925 // Unfortunately, we made it protected.
926 UltimateResourceFallbackLocation ignoringUsefulData = UltimateResourceFallbackLocation.MainAssembly;
927 CultureInfo culture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(a, ref ignoringUsefulData);
932 internal static bool CompareNames(String asmTypeName1,
934 AssemblyName asmName2)
936 Contract.Assert(asmTypeName1 != null, "asmTypeName1 was unexpectedly null");
938 // First, compare type names
939 int comma = asmTypeName1.IndexOf(',');
940 if (((comma == -1) ? asmTypeName1.Length : comma) != typeName2.Length)
944 if (String.Compare(asmTypeName1, 0, typeName2, 0, typeName2.Length, StringComparison.Ordinal) != 0)
949 // Now, compare assembly display names (IGNORES VERSION AND PROCESSORARCHITECTURE)
950 // also, for mscorlib ignores everything, since that's what the binder is going to do
951 while(Char.IsWhiteSpace(asmTypeName1[++comma]));
954 AssemblyName an1 = new AssemblyName(asmTypeName1.Substring(comma));
955 if (String.Compare(an1.Name, asmName2.Name, StringComparison.OrdinalIgnoreCase) != 0)
958 // to match IsMscorlib() in VM
959 if (String.Compare(an1.Name, "mscorlib", StringComparison.OrdinalIgnoreCase) == 0)
963 if ((an1.CultureInfo != null) && (asmName2.CultureInfo != null) &&
965 (an1.CultureInfo.LCID != asmName2.CultureInfo.LCID)
967 (an1.CultureInfo.Name != asmName2.CultureInfo.Name)
972 byte[] pkt1 = an1.GetPublicKeyToken();
973 byte[] pkt2 = asmName2.GetPublicKeyToken();
974 if ((pkt1 != null) && (pkt2 != null)) {
975 if (pkt1.Length != pkt2.Length)
978 for(int i=0; i < pkt1.Length; i++) {
979 if(pkt1[i] != pkt2[i])
988 [SecuritySafeCritical]
989 // Throws WinRT hresults
990 private string GetStringFromPRI(String stringName, String startingCulture, String neutralResourcesCulture) {
991 Contract.Assert(_bUsingModernResourceManagement);
992 Contract.Assert(_WinRTResourceManager != null);
993 Contract.Assert(_PRIonAppXInitialized);
994 Contract.Assert(AppDomain.IsAppXModel());
996 if (stringName.Length == 0)
999 string resourceString = null;
1001 // Do not handle exceptions. See the comment in SetAppXConfiguration about throwing
1002 // exception types that the ResourceManager class is not documented to throw.
1003 resourceString = _WinRTResourceManager.GetString(
1005 String.IsNullOrEmpty(startingCulture) ? null : startingCulture,
1006 String.IsNullOrEmpty(neutralResourcesCulture) ? null : neutralResourcesCulture);
1008 return resourceString;
1011 // Since we can't directly reference System.Runtime.WindowsRuntime from mscorlib, we have to get the type via reflection.
1012 // It would be better if we could just implement WindowsRuntimeResourceManager in mscorlib, but we can't, because
1013 // we can do very little with WinRT in mscorlib.
1015 internal static WindowsRuntimeResourceManagerBase GetWinRTResourceManager()
1017 Type WinRTResourceManagerType = Type.GetType("System.Resources.WindowsRuntimeResourceManager, " + AssemblyRef.SystemRuntimeWindowsRuntime, true);
1018 return (WindowsRuntimeResourceManagerBase)Activator.CreateInstance(WinRTResourceManagerType, true);
1023 private bool _bUsingModernResourceManagement; // Written only by SetAppXConfiguration
1028 private WindowsRuntimeResourceManagerBase _WinRTResourceManager; // Written only by SetAppXConfiguration
1031 private bool _PRIonAppXInitialized; // Written only by SetAppXConfiguration
1034 private PRIExceptionInfo _PRIExceptionInfo; // Written only by SetAppXConfiguration
1036 // When running under AppX, the following rules apply for resource lookup:
1041 // 1) For Framework assemblies, we always use satellite assembly based lookup.
1042 // 2) For non-FX assemblies, we use modern resource manager, with the premise being that app package
1043 // contains the PRI resources since such assemblies are expected to be application assemblies.
1048 // 1) For Framework assemblies, we always use satellite assembly based lookup.
1049 // 2) For non-FX assemblies:
1051 // a) If the assembly lives under PLATFORM_RESOURCE_ROOTS (as specified by the host during AppDomain creation),
1052 // then we will use satellite assembly based lookup in assemblies like *.resources.dll.
1054 // b) For any other non-FX assembly, we will use the modern resource manager with the premise that app package
1055 // contains the PRI resources.
1056 [SecuritySafeCritical]
1057 private bool ShouldUseSatelliteAssemblyResourceLookupUnderAppX(RuntimeAssembly resourcesAssembly)
1059 bool fUseSatelliteAssemblyResourceLookupUnderAppX = resourcesAssembly.IsFrameworkAssembly();
1062 if (!fUseSatelliteAssemblyResourceLookupUnderAppX)
1064 // Check to see if the assembly is under PLATFORM_RESOURCE_ROOTS. If it is, then we should use satellite assembly lookup for it.
1065 String platformResourceRoots = (String)(AppDomain.CurrentDomain.GetData("PLATFORM_RESOURCE_ROOTS"));
1066 if ((platformResourceRoots != null) && (platformResourceRoots != String.Empty))
1068 string resourceAssemblyPath = resourcesAssembly.Location;
1070 // Loop through the PLATFORM_RESOURCE_ROOTS and see if the assembly is contained in it.
1071 foreach(string pathPlatformResourceRoot in platformResourceRoots.Split(Path.PathSeparator))
1073 if (resourceAssemblyPath.StartsWith(pathPlatformResourceRoot, StringComparison.CurrentCultureIgnoreCase))
1075 // Found the resource assembly to be present in one of the PLATFORM_RESOURCE_ROOT, so stop the enumeration loop.
1076 fUseSatelliteAssemblyResourceLookupUnderAppX = true;
1082 #endif // FEATURE_CORECLR
1083 return fUseSatelliteAssemblyResourceLookupUnderAppX;
1087 [SecuritySafeCritical]
1088 #endif // FEATURE_APPX
1089 // Only call SetAppXConfiguration from ResourceManager constructors, and nowhere else.
1090 // Throws MissingManifestResourceException and WinRT HResults
1092 private void SetAppXConfiguration()
1094 Contract.Assert(_bUsingModernResourceManagement == false); // Only this function writes to this member
1096 Contract.Assert(_WinRTResourceManager == null); // Only this function writes to this member
1097 Contract.Assert(_PRIonAppXInitialized == false); // Only this function writes to this member
1098 Contract.Assert(_PRIExceptionInfo == null); // Only this function writes to this member
1100 bool bUsingSatelliteAssembliesUnderAppX = false;
1102 RuntimeAssembly resourcesAssembly = (RuntimeAssembly)MainAssembly;
1104 if (resourcesAssembly == null)
1105 resourcesAssembly = m_callingAssembly;
1107 if (resourcesAssembly != null)
1109 if (resourcesAssembly != typeof(Object).Assembly) // We are not loading resources for mscorlib
1111 // Cannot load the WindowsRuntimeResourceManager when in a compilation process, since it
1112 // lives in System.Runtime.WindowsRuntime and only mscorlib may be loaded for execution.
1113 if (AppDomain.IsAppXModel() && !AppDomain.IsAppXNGen)
1115 s_IsAppXModel = true;
1117 // If we have the type information from the ResourceManager(Type) constructor, we use it. Otherwise, we use BaseNameField.
1118 String reswFilename = _locationInfo == null ? BaseNameField : _locationInfo.FullName;
1120 // The only way this can happen is if a class inherited from ResourceManager and
1121 // did not set the BaseNameField before calling the protected ResourceManager() constructor.
1122 // For other constructors, we would already have thrown an ArgumentNullException by now.
1123 // Throwing an ArgumentNullException now is not the right thing to do because technically
1124 // ResourceManager() takes no arguments, and because it is not documented as throwing
1125 // any exceptions. Instead, let's go through the rest of the initialization with this set to
1126 // an empty string. We may in fact fail earlier for another reason, but otherwise we will
1127 // throw a MissingManifestResourceException when GetString is called indicating that a
1128 // resW filename called "" could not be found.
1129 if (reswFilename == null)
1130 reswFilename = String.Empty;
1132 WindowsRuntimeResourceManagerBase WRRM = null;
1133 bool bWRRM_Initialized = false;
1135 if (AppDomain.IsAppXDesignMode())
1137 WRRM = GetWinRTResourceManager();
1139 PRIExceptionInfo exceptionInfo; // If the exception info is filled in, we will ignore it.
1140 bWRRM_Initialized = WRRM.Initialize(resourcesAssembly.Location, reswFilename, out exceptionInfo);
1141 bUsingSatelliteAssembliesUnderAppX = !bWRRM_Initialized;
1145 bUsingSatelliteAssembliesUnderAppX = true;
1151 if (!bUsingSatelliteAssembliesUnderAppX)
1153 // See AssemblyNative::IsFrameworkAssembly for details on which kinds of assemblies are considered Framework assemblies.
1154 // The Modern Resource Manager is not used for such assemblies - they continue to use satellite assemblies (i.e. .resources.dll files).
1155 _bUsingModernResourceManagement = !ShouldUseSatelliteAssemblyResourceLookupUnderAppX(resourcesAssembly);
1157 if (_bUsingModernResourceManagement)
1159 // Only now are we certain that we need the PRI file.
1161 // Note that if IsAppXDesignMode is false, we haven't checked if the PRI file exists.
1162 // This is by design. We will find out in the call to WindowsRuntimeResourceManager.Initialize below.
1164 // At this point it is important NOT to set _bUsingModernResourceManagement to false
1165 // if the PRI file does not exist because we are now certain we need to load PRI
1166 // resources. We want to fail by throwing a MissingManifestResourceException
1167 // if WindowsRuntimeResourceManager.Initialize fails to locate the PRI file. We do not
1168 // want to fall back to using satellite assemblies anymore. Note that we would not throw
1169 // the MissingManifestResourceException from this function, but from GetString. See the
1170 // comment below on the reason for this.
1172 if (WRRM != null && bWRRM_Initialized)
1174 // Reuse the one successfully created earlier
1175 _WinRTResourceManager = WRRM;
1176 _PRIonAppXInitialized = true;
1180 _WinRTResourceManager = GetWinRTResourceManager();
1183 _PRIonAppXInitialized = _WinRTResourceManager.Initialize(resourcesAssembly.Location, reswFilename, out _PRIExceptionInfo);
1185 // Note that _PRIExceptionInfo might be null - this is OK.
1186 // In that case we will just throw the generic
1187 // MissingManifestResource_NoPRIresources exception.
1188 // See the implementation of GetString for more details.
1190 // We would like to be able to throw a MissingManifestResourceException here if PRI resources
1191 // could not be loaded for a recognized reason. However, the ResourceManager constructors
1192 // that call SetAppXConfiguration are not documented as throwing MissingManifestResourceException,
1193 // and since they are part of the portable profile, we cannot start throwing a new exception type
1194 // as that would break existing portable libraries. Hence we must save the exception information
1195 // now and throw the exception on the first call to GetString.
1196 catch(FileNotFoundException)
1198 // We will throw MissingManifestResource_NoPRIresources from GetString
1199 // when we see that _PRIonAppXInitialized is false.
1203 // ERROR_MRM_MAP_NOT_FOUND can be thrown by the call to ResourceManager.get_AllResourceMaps
1204 // in WindowsRuntimeResourceManager.Initialize.
1205 // In this case _PRIExceptionInfo is now null and we will just throw the generic
1206 // MissingManifestResource_NoPRIresources exception.
1207 // See the implementation of GetString for more details.
1208 if (e.HResult != __HResults.ERROR_MRM_MAP_NOT_FOUND)
1209 throw; // Unexpected exception code. Bubble it up to the caller.
1211 // Allow all other exception types to bubble up to the caller.
1213 // Yes, this causes us to potentially throw exception types that are not documented.
1215 // Ultimately the tradeoff is the following:
1216 // -We could ignore unknown exceptions or rethrow them as inner exceptions
1217 // of exceptions that the ResourceManager class is already documented as throwing.
1218 // This would allow existing portable libraries to gracefully recover if they don't care
1219 // too much about the ResourceManager object they are using. However it could
1220 // mask potentially fatal errors that we are not aware of, such as a disk drive failing.
1223 // The alternative, which we chose, is to throw unknown exceptions. This may tear
1224 // down the process if the portable library and app don't expect this exception type.
1225 // On the other hand, this won't mask potentially fatal errors we don't know about.
1232 // resourcesAssembly == null should not happen but it can. See the comment on Assembly.GetCallingAssembly.
1233 // However for the sake of 100% backwards compatibility on Win7 and below, we must leave
1234 // _bUsingModernResourceManagement as false.
1235 #endif // FEATURE_APPX
1238 // Looks up a resource value for a particular name. Looks in the
1239 // current thread's CultureInfo, and if not found, all parent CultureInfos.
1240 // Returns null if the resource wasn't found.
1242 public virtual String GetString(String name) {
1243 return GetString(name, (CultureInfo)null);
1246 // Looks up a resource value for a particular name. Looks in the
1247 // specified CultureInfo, and if not found, all parent CultureInfos.
1248 // Returns null if the resource wasn't found.
1250 public virtual String GetString(String name, CultureInfo culture) {
1252 throw new ArgumentNullException("name");
1253 Contract.EndContractBlock();
1258 // If the caller explictily passed in a culture that was obtained by calling CultureInfo.CurrentUICulture,
1259 // null it out, so that we re-compute it. If we use modern resource lookup, we may end up getting a "better"
1260 // match, since CultureInfo objects can't represent all the different languages the AppX resource model supports.
1261 // For classic resources, this causes us to ignore the languages list and instead use the older Win32 behavior,
1262 // which is the design choice we've made. (See the call a little later to GetCurrentUICultureNoAppX()).
1263 if(Object.ReferenceEquals(culture, CultureInfo.CurrentUICulture))
1269 if (_bUsingModernResourceManagement)
1271 if (_PRIonAppXInitialized == false)
1273 // Always throw if we did not fully succeed in initializing the WinRT Resource Manager.
1275 if (_PRIExceptionInfo != null && _PRIExceptionInfo._PackageSimpleName != null && _PRIExceptionInfo._ResWFile != null)
1276 throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_ResWFileNotLoaded", _PRIExceptionInfo._ResWFile, _PRIExceptionInfo._PackageSimpleName));
1278 throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoPRIresources"));
1281 // Throws WinRT hresults.
1282 return GetStringFromPRI(name,
1283 culture == null ? null : culture.Name,
1284 _neutralResourcesCulture.Name);
1287 #endif // FEATURE_APPX
1289 if (null==culture) {
1290 // When running inside AppX we want to ignore the languages list when trying to come up with our CurrentUICulture.
1291 // This line behaves the same way as CultureInfo.CurrentUICulture would have in .NET 4
1292 culture = Thread.CurrentThread.GetCurrentUICultureNoAppX();
1295 #if !FEATURE_CORECLR && !MONO
1296 if (FrameworkEventSource.IsInitialized)
1298 FrameworkEventSource.Log.ResourceManagerLookupStarted(BaseNameField, MainAssembly, culture.Name);
1301 ResourceSet last = GetFirstResourceSet(culture);
1305 String value = last.GetString(name, _ignoreCase);
1311 // This is the CultureInfo hierarchy traversal code for resource
1312 // lookups, similar but necessarily orthogonal to the ResourceSet
1314 ResourceFallbackManager mgr = new ResourceFallbackManager(culture, _neutralResourcesCulture, true);
1315 foreach (CultureInfo currentCultureInfo in mgr) {
1317 ResourceSet rs = InternalGetResourceSet(currentCultureInfo, true, true);
1322 String value = rs.GetString(name, _ignoreCase);
1325 // update last used ResourceSet
1326 if (_lastUsedResourceCache != null) {
1327 lock (_lastUsedResourceCache) {
1328 _lastUsedResourceCache.lastCultureName = currentCultureInfo.Name;
1329 _lastUsedResourceCache.lastResourceSet = rs;
1339 #if !FEATURE_CORECLR && !MONO
1340 if (FrameworkEventSource.IsInitialized)
1342 FrameworkEventSource.Log.ResourceManagerLookupFailed(BaseNameField, MainAssembly, culture.Name);
1351 // Looks up a resource value for a particular name. Looks in the
1352 // current thread's CultureInfo, and if not found, all parent CultureInfos.
1353 // Returns null if the resource wasn't found.
1355 public virtual Object GetObject(String name) {
1356 return GetObject(name, (CultureInfo)null, true);
1359 // Looks up a resource value for a particular name. Looks in the
1360 // specified CultureInfo, and if not found, all parent CultureInfos.
1361 // Returns null if the resource wasn't found.
1362 public virtual Object GetObject(String name, CultureInfo culture) {
1363 return GetObject(name, culture, true);
1366 private Object GetObject(String name, CultureInfo culture, bool wrapUnmanagedMemStream)
1369 throw new ArgumentNullException("name");
1370 Contract.EndContractBlock();
1375 // If the caller explictily passed in a culture that was obtained by calling CultureInfo.CurrentUICulture,
1376 // null it out, so that we re-compute it based on the Win32 value and not the AppX language list value.
1377 // (See the call a little later to GetCurrentUICultureNoAppX()).
1378 if(Object.ReferenceEquals(culture, CultureInfo.CurrentUICulture))
1385 if (null==culture) {
1386 // When running inside AppX we want to ignore the languages list when trying to come up with our CurrentUICulture.
1387 // This line behaves the same way as CultureInfo.CurrentUICulture would have in .NET 4
1388 culture = Thread.CurrentThread.GetCurrentUICultureNoAppX();
1391 #if !FEATURE_CORECLR && !MONO
1392 if (FrameworkEventSource.IsInitialized)
1394 FrameworkEventSource.Log.ResourceManagerLookupStarted(BaseNameField, MainAssembly, culture.Name);
1397 ResourceSet last = GetFirstResourceSet(culture);
1400 Object value = last.GetObject(name, _ignoreCase);
1404 UnmanagedMemoryStream stream = value as UnmanagedMemoryStream;
1405 if (stream != null && wrapUnmanagedMemStream)
1406 return new UnmanagedMemoryStreamWrapper(stream);
1412 // This is the CultureInfo hierarchy traversal code for resource
1413 // lookups, similar but necessarily orthogonal to the ResourceSet
1415 ResourceFallbackManager mgr = new ResourceFallbackManager(culture, _neutralResourcesCulture, true);
1417 foreach (CultureInfo currentCultureInfo in mgr) {
1418 // Note: Technically this method should be passed in a stack crawl mark that we then pass
1419 // to InternalGetResourceSet for ensuring we demand permissions to read your private resources
1420 // if you're reading resources from an assembly other than yourself. But, we must call our
1421 // three argument overload (without the stack crawl mark) for compatibility. After
1422 // consideration, we aren't worried about the security impact.
1423 ResourceSet rs = InternalGetResourceSet(currentCultureInfo, true, true);
1428 Object value = rs.GetObject(name, _ignoreCase);
1429 if (value != null) {
1430 // update the last used ResourceSet
1431 if (_lastUsedResourceCache != null) {
1432 lock (_lastUsedResourceCache) {
1433 _lastUsedResourceCache.lastCultureName = currentCultureInfo.Name;
1434 _lastUsedResourceCache.lastResourceSet = rs;
1438 UnmanagedMemoryStream stream = value as UnmanagedMemoryStream;
1439 if (stream != null && wrapUnmanagedMemStream)
1440 return new UnmanagedMemoryStreamWrapper(stream);
1449 #if !FEATURE_CORECLR && !MONO
1450 if (FrameworkEventSource.IsInitialized)
1452 FrameworkEventSource.Log.ResourceManagerLookupFailed(BaseNameField, MainAssembly, culture.Name);
1459 public UnmanagedMemoryStream GetStream(String name) {
1460 return GetStream(name, (CultureInfo)null);
1464 public UnmanagedMemoryStream GetStream(String name, CultureInfo culture) {
1465 Object obj = GetObject(name, culture, false);
1466 UnmanagedMemoryStream ums = obj as UnmanagedMemoryStream;
1467 if (ums == null && obj != null)
1468 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotStream_Name", name));
1472 #if RESOURCE_SATELLITE_CONFIG
1473 // Internal helper method - gives an end user the ability to prevent
1474 // satellite assembly probes for certain cultures via a config file.
1475 [System.Security.SecurityCritical] // auto-generated
1476 private bool TryLookingForSatellite(CultureInfo lookForCulture)
1478 if (!_checkedConfigFile) {
1480 if (!_checkedConfigFile) {
1481 _checkedConfigFile = true;
1482 _installedSatelliteInfo = GetSatelliteAssembliesFromConfig();
1487 if (_installedSatelliteInfo == null)
1490 String[] installedSatellites = (String[]) _installedSatelliteInfo[MainAssembly.FullName];
1492 if (installedSatellites == null)
1495 // The config file told us what satellites might be installed.
1496 int pos = Array.IndexOf(installedSatellites, lookForCulture.Name);
1498 #if !FEATURE_CORECLR && !MONO
1499 if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled()) {
1501 FrameworkEventSource.Log.ResourceManagerCultureNotFoundInConfigFile(BaseNameField, MainAssembly, lookForCulture.Name);
1504 FrameworkEventSource.Log.ResourceManagerCultureFoundInConfigFile(BaseNameField, MainAssembly, lookForCulture.Name);
1511 // Note: There is one config file per appdomain. This is not
1512 // per-process nor per-assembly.
1513 [System.Security.SecurityCritical] // auto-generated
1514 [ResourceExposure(ResourceScope.None)]
1515 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
1516 private Hashtable GetSatelliteAssembliesFromConfig()
1520 String fileName = AppDomain.CurrentDomain.FusionStore.ConfigurationFileInternal;
1521 if (fileName == null) {
1525 // Don't do a security assert. We need to support semi-trusted
1526 // scenarios, but asserting here causes infinite resource lookups
1527 // while initializing security & looking up mscorlib's config file.
1528 // Use internal methods to bypass security checks.
1530 // If we're dealing with a local file name or a UNC path instead
1531 // of a URL, check to see if the file exists here for perf (avoids
1532 // throwing a FileNotFoundException).
1533 if (fileName.Length >= 2 &&
1534 ((fileName[1] == Path.VolumeSeparatorChar) || (fileName[0] == Path.DirectorySeparatorChar && fileName[1] == Path.DirectorySeparatorChar)) &&
1535 !File.InternalExists(fileName))
1538 ConfigTreeParser parser = new ConfigTreeParser();
1539 String queryPath = "/configuration/satelliteassemblies";
1540 ConfigNode node = null;
1541 // Catch exceptions in case a web app doesn't have a config file.
1543 node = parser.Parse(fileName, queryPath, true);
1551 // The application config file will contain sections like this:
1552 // <?xml version="1.0"?>
1554 // <satelliteassemblies>
1555 // <assembly name="mscorlib, Version=..., PublicKeyToken=...">
1556 // <culture>fr</culture>
1558 // <assembly name="UserAssembly, ...">
1559 // <culture>fr-FR</culture>
1560 // <culture>de-CH</culture>
1562 // <assembly name="UserAssembly2, ...">
1564 // </satelliteassemblies>
1566 Hashtable satelliteInfo = new Hashtable(StringComparer.OrdinalIgnoreCase);
1567 foreach(ConfigNode assemblyNode in node.Children) {
1568 if (!String.Equals(assemblyNode.Name, "assembly"))
1569 throw new ApplicationException(Environment.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTag", Path.GetFileName(fileName), assemblyNode.Name));
1571 if (assemblyNode.Attributes.Count == 0)
1572 throw new ApplicationException(Environment.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTagNoAttr", Path.GetFileName(fileName)));
1574 DictionaryEntry de = (DictionaryEntry) assemblyNode.Attributes[0];
1575 String assemblyName = (String) de.Value;
1576 if (!String.Equals(de.Key, "name") || String.IsNullOrEmpty(assemblyName) || assemblyNode.Attributes.Count > 1)
1577 throw new ApplicationException(Environment.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTagBadAttr", Path.GetFileName(fileName), de.Key, de.Value));
1579 ArrayList list = new ArrayList(5);
1580 foreach(ConfigNode child in assemblyNode.Children)
1581 if (child.Value != null)
1582 list.Add(child.Value);
1584 String[] satellites = new String[list.Count];
1585 for(int i=0; i<satellites.Length; i++) {
1586 String cultureName = (String)list[i];
1587 satellites[i] = cultureName;
1588 #if !FEATURE_CORECLR && !MONO
1589 if (FrameworkEventSource.IsInitialized)
1591 FrameworkEventSource.Log.ResourceManagerAddingCultureFromConfigFile(BaseNameField, MainAssembly, cultureName);
1596 satelliteInfo.Add(assemblyName, satellites);
1599 return satelliteInfo;
1602 #endif //FEATURE_FUSION
1605 #endif // RESOURCE_SATELLITE_CONFIG
1607 internal class ResourceManagerMediator
1609 private ResourceManager _rm;
1611 internal ResourceManagerMediator(ResourceManager rm)
1615 throw new ArgumentNullException("rm");
1620 // NEEDED ONLY BY FILE-BASED
1621 internal String ModuleDir
1623 get { return _rm.moduleDir; }
1626 // NEEDED BOTH BY FILE-BASED AND ----Y-BASED
1627 internal Type LocationInfo
1629 get { return _rm._locationInfo; }
1632 internal Type UserResourceSet
1634 get { return _rm._userResourceSet; }
1637 internal String BaseNameField
1639 get { return _rm.BaseNameField; }
1642 internal CultureInfo NeutralResourcesCulture
1644 get { return _rm._neutralResourcesCulture; }
1645 set { _rm._neutralResourcesCulture = value; }
1648 internal String GetResourceFileName(CultureInfo culture)
1650 return _rm.GetResourceFileName(culture);
1653 // NEEDED ONLY BY ----Y-BASED
1654 internal bool LookedForSatelliteContractVersion
1656 get { return _rm._lookedForSatelliteContractVersion; }
1657 set { _rm._lookedForSatelliteContractVersion = value; }
1660 internal Version SatelliteContractVersion
1662 get { return _rm._satelliteContractVersion; }
1663 set { _rm._satelliteContractVersion = value; }
1666 internal Version ObtainSatelliteContractVersion(Assembly a)
1668 return ResourceManager.GetSatelliteContractVersion(a);
1671 internal UltimateResourceFallbackLocation FallbackLoc
1673 get { return _rm.FallbackLocation; }
1674 set { _rm._fallbackLoc = value; }
1677 internal RuntimeAssembly CallingAssembly
1679 get { return _rm.m_callingAssembly; }
1682 internal RuntimeAssembly MainAssembly
1684 get { return (RuntimeAssembly)_rm.MainAssembly; }
1687 // this is weird because we have BaseNameField accessor above, but we're sticking
1688 // with it for compat.
1689 internal String BaseName
1691 get { return _rm.BaseName; }
1695 #if RESOURCE_SATELLITE_CONFIG
1696 [System.Security.SecurityCritical] // auto-generated
1697 internal bool TryLookingForSatellite(CultureInfo lookForCulture)
1699 return _rm.TryLookingForSatellite(lookForCulture);