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
150 // - Unearthed a bug that's been lurking a while in file-based
151 // lookup paths for InternalGetResourceSet if createIfNotExists is
153 // - Reuses logic, e.g. by breaking apart the culture fallback into
154 // the fallback iterator class, we don't have to repeat the
155 // sometimes confusing fallback logic across multiple methods
156 // - Fxcop violations reduced to 1/5th of original count. Most
157 // importantly, code complexity violations disappeared.
158 // - Finally, it got rid of dead code paths. Because the big loop was
159 // so confusing, it masked unused chunks of code. Also, dividing
160 // between file-based and manifest-based allowed functionaliy
161 // unused in silverlight to fall out.
163 // Note: this type is integral to the construction of exception objects,
164 // and sometimes this has to be done in low memory situtations (OOM) or
165 // to create TypeInitializationExceptions due to failure of a static class
166 // constructor. This type needs to be extremely careful and assume that
167 // any type it references may have previously failed to construct, so statics
168 // belonging to that type may not be initialized. FrameworkEventSource.Log
169 // is one such example.
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 #pragma warning disable 414
206 // unused! But need to keep for serialization
207 [OptionalField(VersionAdded
= 1)]
208 private bool UseSatelliteAssem
; // Are all the .resources files in the
209 // main assembly, or in satellite assemblies for each culture?
210 #pragma warning restore
211 #if RESOURCE_SATELLITE_CONFIG
212 private static volatile Hashtable _installedSatelliteInfo
; // Give the user the option
213 // to prevent certain satellite assembly probes via a config file.
214 // Note that config files are per-appdomain, not per-assembly nor process
215 private static volatile bool _checkedConfigFile
; // Did we read the app's config file?
218 // Whether to fall back to the main assembly or a particular
219 // satellite for the neutral resources.
221 private UltimateResourceFallbackLocation _fallbackLoc
;
222 // Version number of satellite assemblies to look for. May be null.
224 private Version _satelliteContractVersion
;
226 private bool _lookedForSatelliteContractVersion
;
228 // unused! But need to keep for serialization
229 [OptionalField(VersionAdded
= 1)]
230 private Assembly _callingAssembly
; // Assembly who created the ResMgr.
232 // replaces _callingAssembly
233 [OptionalField(VersionAdded
= 4)]
234 private RuntimeAssembly m_callingAssembly
; // Assembly who created the ResMgr.
236 // no need to serialize this; just create a new one on deserialization
238 private IResourceGroveler resourceGroveler
;
240 public static readonly int MagicNumber
= unchecked((int)0xBEEFCACE); // If only hex had a K...
242 // Version number so ResMgr can get the ideal set of classes for you.
244 // 1) MagicNumber (little endian Int32)
245 // 2) HeaderVersionNumber (little endian Int32)
246 // 3) Num Bytes to skip past ResMgr header (little endian Int32)
247 // 4) IResourceReader type name for this file (bytelength-prefixed UTF-8 String)
248 // 5) ResourceSet type name for this file (bytelength-prefixed UTF8 String)
249 public static readonly int HeaderVersionNumber
= 1;
252 //It would be better if we could use _neutralCulture instead of calling
253 //CultureInfo.InvariantCulture everywhere, but we run into problems with the .cctor. CultureInfo
254 //initializes assembly, which initializes ResourceManager, which tries to get a CultureInfo which isn't
255 //there yet because CultureInfo's class initializer hasn't finished. If we move SystemResMgr off of
256 //Assembly (or at least make it an internal property) we should be able to circumvent this problem.
258 // private static CultureInfo _neutralCulture = null;
260 // This is our min required ResourceSet type.
261 private static readonly Type _minResourceSet
= typeof(ResourceSet
);
262 // These Strings are used to avoid using Reflection in CreateResourceSet.
263 // The first set are used by ResourceWriter. The second are used by
265 internal static readonly String ResReaderTypeName
= typeof(ResourceReader
).FullName
;
266 internal static readonly String ResSetTypeName
= typeof(RuntimeResourceSet
).FullName
;
267 internal static readonly String MscorlibName
= typeof(ResourceReader
).Assembly
.FullName
;
268 internal const String ResFileExtension
= ".resources";
269 internal const int ResFileExtensionLength
= 10;
271 // My private debugging aid. Set to 5 or 6 for verbose output. Set to 3
272 // for summary level information.
273 internal static readonly int DEBUG
= 0; //Making this const causes C# to consider all of the code that it guards unreachable.
275 private static volatile bool s_IsAppXModel
;
278 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
281 m_callingAssembly
= (RuntimeAssembly
)Assembly
.GetCallingAssembly();
284 protected ResourceManager()
287 // This constructor is not designed to be used under AppX and is not in the Win8 profile.
288 // However designers may use them even if they are running under AppX since they are
289 // not subject to the restrictions of the Win8 profile.
290 Contract
.Assert(!AppDomain
.IsAppXModel() || AppDomain
.IsAppXDesignMode());
295 _lastUsedResourceCache
= new CultureNameResourceSetPair();
296 ResourceManagerMediator mediator
= new ResourceManagerMediator(this);
297 resourceGroveler
= new ManifestBasedResourceGroveler(mediator
);
300 // Constructs a Resource Manager for files beginning with
301 // baseName in the directory specified by resourceDir
302 // or in the current directory. This Assembly-ignorant constructor is
303 // mostly useful for testing your own ResourceSet implementation.
305 // A good example of a baseName might be "Strings". BaseName
306 // should not end in ".resources".
308 // Note: System.Windows.Forms uses this method at design time.
310 [ResourceExposure(ResourceScope
.Machine
)]
311 [ResourceConsumption(ResourceScope
.Machine
)]
312 private ResourceManager(String baseName
, String resourceDir
, Type usingResourceSet
) {
314 throw new ArgumentNullException("baseName");
315 if (null==resourceDir
)
316 throw new ArgumentNullException("resourceDir");
317 Contract
.EndContractBlock();
320 // This constructor is not designed to be used under AppX and is not in the Win8 profile.
321 // However designers may use them even if they are running under AppX since they are
322 // not subject to the restrictions of the Win8 profile.
323 Contract
.Assert(!AppDomain
.IsAppXModel() || AppDomain
.IsAppXDesignMode());
326 BaseNameField
= baseName
;
328 moduleDir
= resourceDir
;
329 _userResourceSet
= usingResourceSet
;
330 #pragma warning disable 618
331 ResourceSets
= new Hashtable(); // for backward compatibility
332 #pragma warning restore 618
333 _resourceSets
= new Dictionary
<String
, ResourceSet
>();
334 _lastUsedResourceCache
= new CultureNameResourceSetPair();
337 ResourceManagerMediator mediator
= new ResourceManagerMediator(this);
338 resourceGroveler
= new FileBasedResourceGroveler(mediator
);
340 #if !FEATURE_CORECLR && !MONO // PAL doesn't support eventing, and we don't compile event providers for coreclr
341 if (FrameworkEventSource
.IsInitialized
&& FrameworkEventSource
.Log
.IsEnabled()) {
342 CultureInfo culture
= CultureInfo
.InvariantCulture
;
343 String defaultResName
= GetResourceFileName(culture
);
345 if (resourceGroveler
.HasNeutralResources(culture
, defaultResName
)) {
346 FrameworkEventSource
.Log
.ResourceManagerNeutralResourcesFound(BaseNameField
, MainAssembly
, defaultResName
);
349 FrameworkEventSource
.Log
.ResourceManagerNeutralResourcesNotFound(BaseNameField
, MainAssembly
, defaultResName
);
355 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
356 public ResourceManager(String baseName
, Assembly assembly
)
359 throw new ArgumentNullException("baseName");
362 throw new ArgumentNullException("assembly");
363 Contract
.EndContractBlock();
365 if (!(assembly
is RuntimeAssembly
))
366 throw new ArgumentException(Environment
.GetResourceString("Argument_MustBeRuntimeAssembly"));
368 MainAssembly
= assembly
;
369 BaseNameField
= baseName
;
371 SetAppXConfiguration();
373 CommonAssemblyInit();
375 m_callingAssembly
= (RuntimeAssembly
)Assembly
.GetCallingAssembly();
376 // Special case for mscorlib - protect mscorlib's private resources.
377 // This isn't for security reasons, but to ensure we can make
378 // breaking changes to mscorlib's internal resources without
379 // assuming users may have taken a dependency on them.
380 if (assembly
== typeof(Object
).Assembly
&& m_callingAssembly
!= assembly
)
382 m_callingAssembly
= null;
386 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
387 public ResourceManager(String baseName
, Assembly assembly
, Type usingResourceSet
)
390 throw new ArgumentNullException("baseName");
392 throw new ArgumentNullException("assembly");
393 Contract
.EndContractBlock();
396 // This constructor is not designed to be used under AppX and is not in the Win8 profile.
397 // However designers may use them even if they are running under AppX since they are
398 // not subject to the restrictions of the Win8 profile.
399 Contract
.Assert(!AppDomain
.IsAppXModel() || AppDomain
.IsAppXDesignMode());
402 if (!(assembly
is RuntimeAssembly
))
403 throw new ArgumentException(Environment
.GetResourceString("Argument_MustBeRuntimeAssembly"));
405 MainAssembly
= assembly
;
406 BaseNameField
= baseName
;
408 if (usingResourceSet
!= null && (usingResourceSet
!= _minResourceSet
) && !(usingResourceSet
.IsSubclassOf(_minResourceSet
)))
409 throw new ArgumentException(Environment
.GetResourceString("Arg_ResMgrNotResSet"), "usingResourceSet");
410 _userResourceSet
= usingResourceSet
;
412 CommonAssemblyInit();
413 m_callingAssembly
= (RuntimeAssembly
)Assembly
.GetCallingAssembly();
414 // Special case for mscorlib - protect mscorlib's private resources.
415 // This isn't for security reasons, but to ensure we can make
416 // breaking changes to mscorlib's internal resources without
417 // assuming users may have taken a dependency on them.
418 if (assembly
== typeof(Object
).Assembly
&& m_callingAssembly
!= assembly
)
419 m_callingAssembly
= null;
422 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
423 public ResourceManager(Type resourceSource
)
425 if (null==resourceSource
)
426 throw new ArgumentNullException("resourceSource");
427 Contract
.EndContractBlock();
429 if (!(resourceSource
is RuntimeType
))
430 throw new ArgumentException(Environment
.GetResourceString("Argument_MustBeRuntimeType"));
432 _locationInfo
= resourceSource
;
433 MainAssembly
= _locationInfo
.Assembly
;
434 BaseNameField
= resourceSource
.Name
;
436 SetAppXConfiguration();
438 CommonAssemblyInit();
440 m_callingAssembly
= (RuntimeAssembly
)Assembly
.GetCallingAssembly();
441 // Special case for mscorlib - protect mscorlib's private resources.
442 if (MainAssembly
== typeof(Object
).Assembly
&& m_callingAssembly
!= MainAssembly
)
444 m_callingAssembly
= null;
449 private void OnDeserializing(StreamingContext ctx
)
451 this._resourceSets
= null;
452 this.resourceGroveler
= null;
453 this._lastUsedResourceCache
= null;
456 [System
.Security
.SecuritySafeCritical
]
458 private void OnDeserialized(StreamingContext ctx
)
460 _resourceSets
= new Dictionary
<String
, ResourceSet
>();
461 _lastUsedResourceCache
= new CultureNameResourceSetPair();
462 // set up resource groveler, depending on whether this ResourceManager
463 // is looking for files or assemblies
464 ResourceManagerMediator mediator
= new ResourceManagerMediator(this);
467 resourceGroveler
= new ManifestBasedResourceGroveler(mediator
);
471 resourceGroveler
= new FileBasedResourceGroveler(mediator
);
474 // correct callingAssembly for v2
475 if (this.m_callingAssembly
== null)
477 this.m_callingAssembly
= (RuntimeAssembly
)_callingAssembly
;
480 // v2 does this lazily
481 if (UseManifest
&& this._neutralResourcesCulture
== null)
483 _neutralResourcesCulture
= ManifestBasedResourceGroveler
.GetNeutralResourcesLanguage(MainAssembly
, ref _fallbackLoc
);
488 private void OnSerializing(StreamingContext ctx
)
490 // Initialize the fields Whidbey expects
491 _callingAssembly
= m_callingAssembly
;
492 UseSatelliteAssem
= UseManifest
;
493 #pragma warning disable 618
494 ResourceSets
= new Hashtable(); // for backward compatibility
495 #pragma warning restore 618
499 // Trying to unify code as much as possible, even though having to do a
500 // security check in each constructor prevents it.
501 [System
.Security
.SecuritySafeCritical
]
502 private void CommonAssemblyInit()
505 if (_bUsingModernResourceManagement
== false)
510 _resourceSets
= new Dictionary
<String
,ResourceSet
>();
511 _lastUsedResourceCache
= new CultureNameResourceSetPair();
513 _fallbackLoc
= UltimateResourceFallbackLocation
.MainAssembly
;
515 ResourceManagerMediator mediator
= new ResourceManagerMediator(this);
516 resourceGroveler
= new ManifestBasedResourceGroveler(mediator
);
519 _neutralResourcesCulture
= ManifestBasedResourceGroveler
.GetNeutralResourcesLanguage(MainAssembly
, ref _fallbackLoc
);
521 #if !FEATURE_CORECLR && FEATURE_APPX // PAL doesn't support eventing, and we don't compile event providers for coreclr
522 if (_bUsingModernResourceManagement
== false)
524 if (FrameworkEventSource
.IsInitialized
&& FrameworkEventSource
.Log
.IsEnabled()) {
525 CultureInfo culture
= CultureInfo
.InvariantCulture
;
526 String defaultResName
= GetResourceFileName(culture
);
528 if (resourceGroveler
.HasNeutralResources(culture
, defaultResName
)) {
529 FrameworkEventSource
.Log
.ResourceManagerNeutralResourcesFound(BaseNameField
, MainAssembly
, defaultResName
);
532 String outputResName
= defaultResName
;
533 if (_locationInfo
!= null && _locationInfo
.Namespace
!= null)
534 outputResName
= _locationInfo
.Namespace
+ Type
.Delimiter
+ defaultResName
;
535 FrameworkEventSource
.Log
.ResourceManagerNeutralResourcesNotFound(BaseNameField
, MainAssembly
, outputResName
);
538 #pragma warning disable 618
539 ResourceSets
= new Hashtable(); // for backward compatibility
540 #pragma warning restore 618
544 ResourceSets
= new Hashtable(); // for backward compatibility
548 // Gets the base name for the ResourceManager.
549 public virtual String BaseName
{
550 get { return BaseNameField; }
553 // Whether we should ignore the capitalization of resources when calling
554 // GetString or GetObject.
555 public virtual bool IgnoreCase
{
556 get { return _ignoreCase; }
557 set { _ignoreCase = value; }
560 // Returns the Type of the ResourceSet the ResourceManager uses
561 // to construct ResourceSets.
562 public virtual Type ResourceSetType
{
563 get { return (_userResourceSet == null) ? typeof(RuntimeResourceSet) : _userResourceSet; }
566 protected UltimateResourceFallbackLocation FallbackLocation
568 get { return _fallbackLoc; }
569 set { _fallbackLoc = value; }
572 // Tells the ResourceManager to call Close on all ResourceSets and
573 // release all resources. This will shrink your working set by
574 // potentially a substantial amount in a running application. Any
575 // future resource lookups on this ResourceManager will be as
576 // expensive as the very first lookup, since it will need to search
577 // for files and load resources again.
579 // This may be useful in some complex threading scenarios, where
580 // creating a new ResourceManager isn't quite the correct behavior.
581 public virtual void ReleaseAllResources()
583 #if !FEATURE_CORECLR && !MONO
584 if (FrameworkEventSource
.IsInitialized
)
586 FrameworkEventSource
.Log
.ResourceManagerReleasingResources(BaseNameField
, MainAssembly
);
589 Dictionary
<String
, ResourceSet
> localResourceSets
= _resourceSets
;
591 // If any calls to Close throw, at least leave ourselves in a
593 _resourceSets
= new Dictionary
<String
,ResourceSet
>();
594 _lastUsedResourceCache
= new CultureNameResourceSetPair();
596 lock(localResourceSets
) {
597 IDictionaryEnumerator setEnum
= localResourceSets
.GetEnumerator();
600 IDictionaryEnumerator setEnum2
= null;
601 #pragma warning disable 618
602 if (ResourceSets
!= null) {
603 setEnum2
= ResourceSets
.GetEnumerator();
605 ResourceSets
= new Hashtable(); // for backwards compat
606 #pragma warning restore 618
609 while (setEnum
.MoveNext()) {
610 ((ResourceSet
)setEnum
.Value
).Close();
614 if (setEnum2
!= null) {
615 while (setEnum2
.MoveNext()) {
616 ((ResourceSet
)setEnum2
.Value
).Close();
623 [ResourceExposure(ResourceScope
.Machine
)]
624 [ResourceConsumption(ResourceScope
.Machine
)]
625 public static ResourceManager
CreateFileBasedResourceManager(String baseName
, String resourceDir
, Type usingResourceSet
)
627 return new ResourceManager(baseName
, resourceDir
, usingResourceSet
);
630 // Given a CultureInfo, GetResourceFileName generates the name for
631 // the binary file for the given CultureInfo. This method uses
632 // CultureInfo's Name property as part of the file name for all cultures
633 // other than the invariant culture. This method does not touch the disk,
634 // and is used only to construct what a resource file name (suitable for
635 // passing to the ResourceReader constructor) or a manifest resource file
636 // name should look like.
638 // This method can be overriden to look for a different extension,
639 // such as ".ResX", or a completely different format for naming files.
640 protected virtual String
GetResourceFileName(CultureInfo culture
) {
641 StringBuilder sb
= new StringBuilder(255);
642 sb
.Append(BaseNameField
);
643 // If this is the neutral culture, don't append culture name.
644 if (!culture
.HasInvariantCultureName
)
646 CultureInfo
.VerifyCultureName(culture
.Name
, true);
648 sb
.Append(culture
.Name
);
650 sb
.Append(ResFileExtension
);
651 return sb
.ToString();
654 // WARNING: This function must be kept in sync with ResourceFallbackManager.GetEnumerator()
655 // Return the first ResourceSet, based on the first culture ResourceFallbackManager would return
656 internal ResourceSet
GetFirstResourceSet(CultureInfo culture
)
658 // Logic from ResourceFallbackManager.GetEnumerator()
659 if (_neutralResourcesCulture
!= null && culture
.Name
== _neutralResourcesCulture
.Name
)
661 culture
= CultureInfo
.InvariantCulture
;
664 if(_lastUsedResourceCache
!= null) {
665 lock (_lastUsedResourceCache
) {
666 if (culture
.Name
== _lastUsedResourceCache
.lastCultureName
)
667 return _lastUsedResourceCache
.lastResourceSet
;
671 // Look in the ResourceSet table
672 Dictionary
<String
,ResourceSet
> localResourceSets
= _resourceSets
;
673 ResourceSet rs
= null;
674 if (localResourceSets
!= null)
676 lock (localResourceSets
)
678 localResourceSets
.TryGetValue(culture
.Name
, out rs
);
684 // update the cache with the most recent ResourceSet
685 if (_lastUsedResourceCache
!= null) {
686 lock (_lastUsedResourceCache
) {
687 _lastUsedResourceCache
.lastCultureName
= culture
.Name
;
688 _lastUsedResourceCache
.lastResourceSet
= rs
;
697 // Looks up a set of resources for a particular CultureInfo. This is
698 // not useful for most users of the ResourceManager - call
699 // GetString() or GetObject() instead.
701 // The parameters let you control whether the ResourceSet is created
702 // if it hasn't yet been loaded and if parent CultureInfos should be
703 // loaded as well for resource inheritance.
705 [System
.Security
.SecuritySafeCritical
] // auto-generated
706 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
707 public virtual ResourceSet
GetResourceSet(CultureInfo culture
, bool createIfNotExists
, bool tryParents
) {
709 throw new ArgumentNullException("culture");
710 Contract
.EndContractBlock();
712 Dictionary
<String
,ResourceSet
> localResourceSets
= _resourceSets
;
714 if (localResourceSets
!= null) {
715 lock (localResourceSets
) {
716 if (localResourceSets
.TryGetValue(culture
.Name
, out rs
))
721 StackCrawlMark stackMark
= StackCrawlMark
.LookForMyCaller
;
723 if (UseManifest
&& culture
.HasInvariantCultureName
) {
724 string fileName
= GetResourceFileName(culture
);
725 RuntimeAssembly mainAssembly
= (RuntimeAssembly
)MainAssembly
;
726 Stream stream
= mainAssembly
.GetManifestResourceStream(_locationInfo
, fileName
, m_callingAssembly
== MainAssembly
, ref stackMark
);
727 if (createIfNotExists
&& stream
!=null) {
728 rs
= ((ManifestBasedResourceGroveler
)resourceGroveler
).CreateResourceSet(stream
, MainAssembly
);
729 AddResourceSet(localResourceSets
, culture
.Name
, ref rs
);
734 // Note: ideally we could plumb through the stack crawl mark here, but we must
735 // call the virtual 3-argument InternalGetResourceSet method for compatibility.
736 // Security-wise, we're not overly interested in protecting access to resources,
737 // since full-trust callers can get them already and most resources are public.
738 // Also, the JIT inliner could always inline a caller into another assembly's
739 // method, so the entire idea of a security check written this way is ----.
740 // So if we happen to return some resources in cases where we should really be
741 // doing a demand for member access permissions, we're not overly concerned.
743 return InternalGetResourceSet(culture
, createIfNotExists
, tryParents
);
746 // InternalGetResourceSet is a non-threadsafe method where all the logic
747 // for getting a resource set lives. Access to it is controlled by
748 // threadsafe methods such as GetResourceSet, GetString, & GetObject.
749 // This will take a minimal number of locks.
750 [System
.Security
.SecuritySafeCritical
] // auto-generated
751 [ResourceExposure(ResourceScope
.None
)]
752 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
753 [MethodImplAttribute(MethodImplOptions
.NoInlining
)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
754 protected virtual ResourceSet
InternalGetResourceSet(CultureInfo culture
, bool createIfNotExists
, bool tryParents
)
756 Contract
.Assert(culture
!= null, "culture != null");
758 StackCrawlMark stackMark
= StackCrawlMark
.LookForMyCaller
;
759 return InternalGetResourceSet(culture
,createIfNotExists
,tryParents
, ref stackMark
);
762 // InternalGetResourceSet is a non-threadsafe method where all the logic
763 // for getting a resource set lives. Access to it is controlled by
764 // threadsafe methods such as GetResourceSet, GetString, & GetObject.
765 // This will take a minimal number of locks.
766 [System
.Security
.SecurityCritical
]
767 [ResourceExposure(ResourceScope
.None
)]
768 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
769 private ResourceSet
InternalGetResourceSet(CultureInfo requestedCulture
, bool createIfNotExists
, bool tryParents
, ref StackCrawlMark stackMark
)
771 Dictionary
<String
, ResourceSet
> localResourceSets
= _resourceSets
;
772 ResourceSet rs
= null;
773 CultureInfo foundCulture
= null;
774 lock (localResourceSets
) {
775 if (localResourceSets
.TryGetValue(requestedCulture
.Name
, out rs
)) {
776 #if !FEATURE_CORECLR && !MONO
777 if (FrameworkEventSource
.IsInitialized
) {
778 FrameworkEventSource
.Log
.ResourceManagerFoundResourceSetInCache(BaseNameField
, MainAssembly
, requestedCulture
.Name
);
785 ResourceFallbackManager mgr
= new ResourceFallbackManager(requestedCulture
, _neutralResourcesCulture
, tryParents
);
787 foreach (CultureInfo currentCultureInfo
in mgr
)
789 #if !FEATURE_CORECLR && !MONO
790 if (FrameworkEventSource
.IsInitialized
)
792 FrameworkEventSource
.Log
.ResourceManagerLookingForResourceSet(BaseNameField
, MainAssembly
, currentCultureInfo
.Name
);
795 lock(localResourceSets
) {
796 if (localResourceSets
.TryGetValue(currentCultureInfo
.Name
, out rs
)) {
797 #if !FEATURE_CORECLR && !MONO
798 if (FrameworkEventSource
.IsInitialized
)
800 FrameworkEventSource
.Log
.ResourceManagerFoundResourceSetInCache(BaseNameField
, MainAssembly
, currentCultureInfo
.Name
);
803 // we need to update the cache if we fellback
804 if(requestedCulture
!= currentCultureInfo
) foundCulture
= currentCultureInfo
;
809 // InternalGetResourceSet will never be threadsafe. However, it must
810 // be protected against reentrancy from the SAME THREAD. (ie, calling
811 // GetSatelliteAssembly may send some window messages or trigger the
812 // Assembly load event, which could fail then call back into the
813 // ResourceManager). It's happened.
815 rs
= resourceGroveler
.GrovelForResourceSet(currentCultureInfo
, localResourceSets
,
816 tryParents
, createIfNotExists
, ref stackMark
);
818 // found a ResourceSet; we're done
821 foundCulture
= currentCultureInfo
;
827 if (rs
!= null && foundCulture
!= null)
829 // add entries to the cache for the cultures we have gone through
831 // currentCultureInfo now refers to the culture that had resources.
832 // update cultures starting from requested culture up to the culture
833 // that had resources.
834 foreach (CultureInfo updateCultureInfo
in mgr
)
836 AddResourceSet(localResourceSets
, updateCultureInfo
.Name
, ref rs
);
838 // stop when we've added current or reached invariant (top of chain)
839 if (updateCultureInfo
== foundCulture
)
849 // Simple helper to ease maintenance and improve readability.
850 private static void AddResourceSet(Dictionary
<String
,ResourceSet
> localResourceSets
, String cultureName
, ref ResourceSet rs
)
852 // InternalGetResourceSet is both recursive and reentrant -
853 // assembly load callbacks in particular are a way we can call
854 // back into the ResourceManager in unexpectedly on the same thread.
855 lock(localResourceSets
) {
856 // If another thread added this culture, return that.
857 ResourceSet lostRace
;
858 if (localResourceSets
.TryGetValue(cultureName
, out lostRace
)) {
859 if (!Object
.ReferenceEquals(lostRace
, rs
)) {
860 // Note: In certain cases, we can be trying to add a ResourceSet for multiple
861 // cultures on one thread, while a second thread added another ResourceSet for one
862 // of those cultures. So when we lose the ----, we must make sure our ResourceSet
863 // isn't in our dictionary before closing it.
864 if (!localResourceSets
.ContainsValue(rs
))
870 localResourceSets
.Add(cultureName
, rs
);
875 protected static Version
GetSatelliteContractVersion(Assembly a
)
877 // Ensure that the assembly reference is not null
879 throw new ArgumentNullException("a", Environment
.GetResourceString("ArgumentNull_Assembly"));
881 Contract
.EndContractBlock();
883 #if !FEATURE_WINDOWSPHONE
885 if (a
.ReflectionOnly
) {
886 foreach (CustomAttributeData data
in CustomAttributeData
.GetCustomAttributes(a
)) {
887 if (data
.Constructor
.DeclaringType
== typeof(SatelliteContractVersionAttribute
)) {
888 v
= (String
)data
.ConstructorArguments
[0].Value
;
897 Object
[] attrs
= a
.GetCustomAttributes(typeof(SatelliteContractVersionAttribute
), false);
898 if (attrs
.Length
== 0)
900 Contract
.Assert(attrs
.Length
== 1, "Cannot have multiple instances of SatelliteContractVersionAttribute on an assembly!");
901 v
= ((SatelliteContractVersionAttribute
)attrs
[0]).Version
;
905 ver
= new Version(v
);
907 catch(ArgumentOutOfRangeException e
) {
908 // Note we are prone to hitting infinite loops if mscorlib's
909 // SatelliteContractVersionAttribute contains bogus values.
910 // If this assert fires, please fix the build process for the
912 if (a
== typeof(Object
).Assembly
) {
913 Contract
.Assert(false, "mscorlib's SatelliteContractVersionAttribute is a malformed version string!");
917 throw new ArgumentException(Environment
.GetResourceString("Arg_InvalidSatelliteContract_Asm_Ver", a
.ToString(), v
), e
);
921 // On the phone return null. The calling code will use the assembly version instead to avoid potential type
922 // and library loads caused by CA lookup. NetCF uses the assembly version always.
927 [System
.Security
.SecuritySafeCritical
] // auto-generated
928 protected static CultureInfo
GetNeutralResourcesLanguage(Assembly a
)
930 // This method should be obsolete - replace it with the one below.
931 // Unfortunately, we made it protected.
932 UltimateResourceFallbackLocation ignoringUsefulData
= UltimateResourceFallbackLocation
.MainAssembly
;
933 CultureInfo culture
= ManifestBasedResourceGroveler
.GetNeutralResourcesLanguage(a
, ref ignoringUsefulData
);
938 internal static bool CompareNames(String asmTypeName1
,
940 AssemblyName asmName2
)
942 Contract
.Assert(asmTypeName1
!= null, "asmTypeName1 was unexpectedly null");
944 // First, compare type names
945 int comma
= asmTypeName1
.IndexOf(',');
946 if (((comma
== -1) ? asmTypeName1
.Length
: comma
) != typeName2
.Length
)
950 if (String
.Compare(asmTypeName1
, 0, typeName2
, 0, typeName2
.Length
, StringComparison
.Ordinal
) != 0)
955 // Now, compare assembly display names (IGNORES VERSION AND PROCESSORARCHITECTURE)
956 // also, for mscorlib ignores everything, since that's what the binder is going to do
957 while(Char
.IsWhiteSpace(asmTypeName1
[++comma
]));
960 AssemblyName an1
= new AssemblyName(asmTypeName1
.Substring(comma
));
961 if (String
.Compare(an1
.Name
, asmName2
.Name
, StringComparison
.OrdinalIgnoreCase
) != 0)
964 // to match IsMscorlib() in VM
965 if (String
.Compare(an1
.Name
, "mscorlib", StringComparison
.OrdinalIgnoreCase
) == 0)
969 if ((an1
.CultureInfo
!= null) && (asmName2
.CultureInfo
!= null) &&
971 (an1
.CultureInfo
.LCID
!= asmName2
.CultureInfo
.LCID
)
973 (an1
.CultureInfo
.Name
!= asmName2
.CultureInfo
.Name
)
978 byte[] pkt1
= an1
.GetPublicKeyToken();
979 byte[] pkt2
= asmName2
.GetPublicKeyToken();
980 if ((pkt1
!= null) && (pkt2
!= null)) {
981 if (pkt1
.Length
!= pkt2
.Length
)
984 for(int i
=0; i
< pkt1
.Length
; i
++) {
985 if(pkt1
[i
] != pkt2
[i
])
994 [SecuritySafeCritical
]
995 // Throws WinRT hresults
996 private string GetStringFromPRI(String stringName
, String startingCulture
, String neutralResourcesCulture
) {
997 Contract
.Assert(_bUsingModernResourceManagement
);
998 Contract
.Assert(_WinRTResourceManager
!= null);
999 Contract
.Assert(_PRIonAppXInitialized
);
1000 Contract
.Assert(AppDomain
.IsAppXModel());
1002 if (stringName
.Length
== 0)
1005 string resourceString
= null;
1007 // Do not handle exceptions. See the comment in SetAppXConfiguration about throwing
1008 // exception types that the ResourceManager class is not documented to throw.
1009 resourceString
= _WinRTResourceManager
.GetString(
1011 String
.IsNullOrEmpty(startingCulture
) ? null : startingCulture
,
1012 String
.IsNullOrEmpty(neutralResourcesCulture
) ? null : neutralResourcesCulture
);
1014 return resourceString
;
1017 // Since we can't directly reference System.Runtime.WindowsRuntime from mscorlib, we have to get the type via reflection.
1018 // It would be better if we could just implement WindowsRuntimeResourceManager in mscorlib, but we can't, because
1019 // we can do very little with WinRT in mscorlib.
1021 internal static WindowsRuntimeResourceManagerBase
GetWinRTResourceManager()
1023 Type WinRTResourceManagerType
= Type
.GetType("System.Resources.WindowsRuntimeResourceManager, " + AssemblyRef
.SystemRuntimeWindowsRuntime
, true);
1024 return (WindowsRuntimeResourceManagerBase
)Activator
.CreateInstance(WinRTResourceManagerType
, true);
1028 private bool _bUsingModernResourceManagement
; // Written only by SetAppXConfiguration
1032 private WindowsRuntimeResourceManagerBase _WinRTResourceManager
; // Written only by SetAppXConfiguration
1035 private bool _PRIonAppXInitialized
; // Written only by SetAppXConfiguration
1038 private PRIExceptionInfo _PRIExceptionInfo
; // Written only by SetAppXConfiguration
1040 // When running under AppX, the following rules apply for resource lookup:
1045 // 1) For Framework assemblies, we always use satellite assembly based lookup.
1046 // 2) For non-FX assemblies, we use modern resource manager, with the premise being that app package
1047 // contains the PRI resources since such assemblies are expected to be application assemblies.
1052 // 1) For Framework assemblies, we always use satellite assembly based lookup.
1053 // 2) For non-FX assemblies:
1055 // a) If the assembly lives under PLATFORM_RESOURCE_ROOTS (as specified by the host during AppDomain creation),
1056 // then we will use satellite assembly based lookup in assemblies like *.resources.dll.
1058 // b) For any other non-FX assembly, we will use the modern resource manager with the premise that app package
1059 // contains the PRI resources.
1060 [SecuritySafeCritical
]
1061 private bool ShouldUseSatelliteAssemblyResourceLookupUnderAppX(RuntimeAssembly resourcesAssembly
)
1063 bool fUseSatelliteAssemblyResourceLookupUnderAppX
= resourcesAssembly
.IsFrameworkAssembly();
1066 if (!fUseSatelliteAssemblyResourceLookupUnderAppX
)
1068 // Check to see if the assembly is under PLATFORM_RESOURCE_ROOTS. If it is, then we should use satellite assembly lookup for it.
1069 String platformResourceRoots
= (String
)(AppDomain
.CurrentDomain
.GetData("PLATFORM_RESOURCE_ROOTS"));
1070 if ((platformResourceRoots
!= null) && (platformResourceRoots
!= String
.Empty
))
1072 string resourceAssemblyPath
= resourcesAssembly
.Location
;
1074 // Loop through the PLATFORM_RESOURCE_ROOTS and see if the assembly is contained in it.
1075 foreach(string pathPlatformResourceRoot
in platformResourceRoots
.Split(Path
.PathSeparator
))
1077 if (resourceAssemblyPath
.StartsWith(pathPlatformResourceRoot
, StringComparison
.CurrentCultureIgnoreCase
))
1079 // Found the resource assembly to be present in one of the PLATFORM_RESOURCE_ROOT, so stop the enumeration loop.
1080 fUseSatelliteAssemblyResourceLookupUnderAppX
= true;
1086 #endif // FEATURE_CORECLR
1087 return fUseSatelliteAssemblyResourceLookupUnderAppX
;
1091 [SecuritySafeCritical
]
1092 #endif // FEATURE_APPX
1093 // Only call SetAppXConfiguration from ResourceManager constructors, and nowhere else.
1094 // Throws MissingManifestResourceException and WinRT HResults
1096 private void SetAppXConfiguration()
1099 Contract
.Assert(_bUsingModernResourceManagement
== false); // Only this function writes to this member
1100 Contract
.Assert(_WinRTResourceManager
== null); // Only this function writes to this member
1101 Contract
.Assert(_PRIonAppXInitialized
== false); // Only this function writes to this member
1102 Contract
.Assert(_PRIExceptionInfo
== null); // Only this function writes to this member
1104 bool bUsingSatelliteAssembliesUnderAppX
= false;
1106 RuntimeAssembly resourcesAssembly
= (RuntimeAssembly
)MainAssembly
;
1108 if (resourcesAssembly
== null)
1109 resourcesAssembly
= m_callingAssembly
;
1111 if (resourcesAssembly
!= null)
1113 if (resourcesAssembly
!= typeof(Object
).Assembly
) // We are not loading resources for mscorlib
1115 // Cannot load the WindowsRuntimeResourceManager when in a compilation process, since it
1116 // lives in System.Runtime.WindowsRuntime and only mscorlib may be loaded for execution.
1117 if (AppDomain
.IsAppXModel() && !AppDomain
.IsAppXNGen
)
1119 s_IsAppXModel
= true;
1121 // If we have the type information from the ResourceManager(Type) constructor, we use it. Otherwise, we use BaseNameField.
1122 String reswFilename
= _locationInfo
== null ? BaseNameField
: _locationInfo
.FullName
;
1124 // The only way this can happen is if a class inherited from ResourceManager and
1125 // did not set the BaseNameField before calling the protected ResourceManager() constructor.
1126 // For other constructors, we would already have thrown an ArgumentNullException by now.
1127 // Throwing an ArgumentNullException now is not the right thing to do because technically
1128 // ResourceManager() takes no arguments, and because it is not documented as throwing
1129 // any exceptions. Instead, let's go through the rest of the initialization with this set to
1130 // an empty string. We may in fact fail earlier for another reason, but otherwise we will
1131 // throw a MissingManifestResourceException when GetString is called indicating that a
1132 // resW filename called "" could not be found.
1133 if (reswFilename
== null)
1134 reswFilename
= String
.Empty
;
1136 WindowsRuntimeResourceManagerBase WRRM
= null;
1137 bool bWRRM_Initialized
= false;
1139 if (AppDomain
.IsAppXDesignMode())
1141 WRRM
= GetWinRTResourceManager();
1143 PRIExceptionInfo exceptionInfo
; // If the exception info is filled in, we will ignore it.
1144 bWRRM_Initialized
= WRRM
.Initialize(resourcesAssembly
.Location
, reswFilename
, out exceptionInfo
);
1145 bUsingSatelliteAssembliesUnderAppX
= !bWRRM_Initialized
;
1149 bUsingSatelliteAssembliesUnderAppX
= true;
1155 if (!bUsingSatelliteAssembliesUnderAppX
)
1157 // See AssemblyNative::IsFrameworkAssembly for details on which kinds of assemblies are considered Framework assemblies.
1158 // The Modern Resource Manager is not used for such assemblies - they continue to use satellite assemblies (i.e. .resources.dll files).
1159 _bUsingModernResourceManagement
= !ShouldUseSatelliteAssemblyResourceLookupUnderAppX(resourcesAssembly
);
1161 if (_bUsingModernResourceManagement
)
1163 // Only now are we certain that we need the PRI file.
1165 // Note that if IsAppXDesignMode is false, we haven't checked if the PRI file exists.
1166 // This is by design. We will find out in the call to WindowsRuntimeResourceManager.Initialize below.
1168 // At this point it is important NOT to set _bUsingModernResourceManagement to false
1169 // if the PRI file does not exist because we are now certain we need to load PRI
1170 // resources. We want to fail by throwing a MissingManifestResourceException
1171 // if WindowsRuntimeResourceManager.Initialize fails to locate the PRI file. We do not
1172 // want to fall back to using satellite assemblies anymore. Note that we would not throw
1173 // the MissingManifestResourceException from this function, but from GetString. See the
1174 // comment below on the reason for this.
1176 if (WRRM
!= null && bWRRM_Initialized
)
1178 // Reuse the one successfully created earlier
1179 _WinRTResourceManager
= WRRM
;
1180 _PRIonAppXInitialized
= true;
1184 _WinRTResourceManager
= GetWinRTResourceManager();
1187 _PRIonAppXInitialized
= _WinRTResourceManager
.Initialize(resourcesAssembly
.Location
, reswFilename
, out _PRIExceptionInfo
);
1189 // Note that _PRIExceptionInfo might be null - this is OK.
1190 // In that case we will just throw the generic
1191 // MissingManifestResource_NoPRIresources exception.
1192 // See the implementation of GetString for more details.
1194 // We would like to be able to throw a MissingManifestResourceException here if PRI resources
1195 // could not be loaded for a recognized reason. However, the ResourceManager constructors
1196 // that call SetAppXConfiguration are not documented as throwing MissingManifestResourceException,
1197 // and since they are part of the portable profile, we cannot start throwing a new exception type
1198 // as that would break existing portable libraries. Hence we must save the exception information
1199 // now and throw the exception on the first call to GetString.
1200 catch(FileNotFoundException
)
1202 // We will throw MissingManifestResource_NoPRIresources from GetString
1203 // when we see that _PRIonAppXInitialized is false.
1207 // ERROR_MRM_MAP_NOT_FOUND can be thrown by the call to ResourceManager.get_AllResourceMaps
1208 // in WindowsRuntimeResourceManager.Initialize.
1209 // In this case _PRIExceptionInfo is now null and we will just throw the generic
1210 // MissingManifestResource_NoPRIresources exception.
1211 // See the implementation of GetString for more details.
1212 if (e
.HResult
!= __HResults
.ERROR_MRM_MAP_NOT_FOUND
)
1213 throw; // Unexpected exception code. Bubble it up to the caller.
1215 // Allow all other exception types to bubble up to the caller.
1217 // Yes, this causes us to potentially throw exception types that are not documented.
1219 // Ultimately the tradeoff is the following:
1220 // -We could ignore unknown exceptions or rethrow them as inner exceptions
1221 // of exceptions that the ResourceManager class is already documented as throwing.
1222 // This would allow existing portable libraries to gracefully recover if they don't care
1223 // too much about the ResourceManager object they are using. However it could
1224 // mask potentially fatal errors that we are not aware of, such as a disk drive failing.
1227 // The alternative, which we chose, is to throw unknown exceptions. This may tear
1228 // down the process if the portable library and app don't expect this exception type.
1229 // On the other hand, this won't mask potentially fatal errors we don't know about.
1236 // resourcesAssembly == null should not happen but it can. See the comment on Assembly.GetCallingAssembly.
1237 // However for the sake of 100% backwards compatibility on Win7 and below, we must leave
1238 // _bUsingModernResourceManagement as false.
1239 #endif // FEATURE_APPX
1242 // Looks up a resource value for a particular name. Looks in the
1243 // current thread's CultureInfo, and if not found, all parent CultureInfos.
1244 // Returns null if the resource wasn't found.
1246 public virtual String
GetString(String name
) {
1247 return GetString(name
, (CultureInfo
)null);
1250 // Looks up a resource value for a particular name. Looks in the
1251 // specified CultureInfo, and if not found, all parent CultureInfos.
1252 // Returns null if the resource wasn't found.
1254 public virtual String
GetString(String name
, CultureInfo culture
) {
1256 throw new ArgumentNullException("name");
1257 Contract
.EndContractBlock();
1262 // If the caller explictily passed in a culture that was obtained by calling CultureInfo.CurrentUICulture,
1263 // null it out, so that we re-compute it. If we use modern resource lookup, we may end up getting a "better"
1264 // match, since CultureInfo objects can't represent all the different languages the AppX resource model supports.
1265 // For classic resources, this causes us to ignore the languages list and instead use the older Win32 behavior,
1266 // which is the design choice we've made. (See the call a little later to GetCurrentUICultureNoAppX()).
1267 if(Object
.ReferenceEquals(culture
, CultureInfo
.CurrentUICulture
))
1273 if (_bUsingModernResourceManagement
)
1275 if (_PRIonAppXInitialized
== false)
1277 // Always throw if we did not fully succeed in initializing the WinRT Resource Manager.
1279 if (_PRIExceptionInfo
!= null && _PRIExceptionInfo
._PackageSimpleName
!= null && _PRIExceptionInfo
._ResWFile
!= null)
1280 throw new MissingManifestResourceException(Environment
.GetResourceString("MissingManifestResource_ResWFileNotLoaded", _PRIExceptionInfo
._ResWFile
, _PRIExceptionInfo
._PackageSimpleName
));
1282 throw new MissingManifestResourceException(Environment
.GetResourceString("MissingManifestResource_NoPRIresources"));
1285 // Throws WinRT hresults.
1286 return GetStringFromPRI(name
,
1287 culture
== null ? null : culture
.Name
,
1288 _neutralResourcesCulture
.Name
);
1291 #endif // FEATURE_APPX
1293 if (null==culture
) {
1294 // When running inside AppX we want to ignore the languages list when trying to come up with our CurrentUICulture.
1295 // This line behaves the same way as CultureInfo.CurrentUICulture would have in .NET 4
1296 culture
= Thread
.CurrentThread
.GetCurrentUICultureNoAppX();
1299 #if !FEATURE_CORECLR && !MONO
1300 if (FrameworkEventSource
.IsInitialized
)
1302 FrameworkEventSource
.Log
.ResourceManagerLookupStarted(BaseNameField
, MainAssembly
, culture
.Name
);
1305 ResourceSet last
= GetFirstResourceSet(culture
);
1309 String
value = last
.GetString(name
, _ignoreCase
);
1315 // This is the CultureInfo hierarchy traversal code for resource
1316 // lookups, similar but necessarily orthogonal to the ResourceSet
1318 ResourceFallbackManager mgr
= new ResourceFallbackManager(culture
, _neutralResourcesCulture
, true);
1319 foreach (CultureInfo currentCultureInfo
in mgr
) {
1321 ResourceSet rs
= InternalGetResourceSet(currentCultureInfo
, true, true);
1326 String
value = rs
.GetString(name
, _ignoreCase
);
1329 // update last used ResourceSet
1330 if (_lastUsedResourceCache
!= null) {
1331 lock (_lastUsedResourceCache
) {
1332 _lastUsedResourceCache
.lastCultureName
= currentCultureInfo
.Name
;
1333 _lastUsedResourceCache
.lastResourceSet
= rs
;
1343 #if !FEATURE_CORECLR && !MONO
1344 if (FrameworkEventSource
.IsInitialized
)
1346 FrameworkEventSource
.Log
.ResourceManagerLookupFailed(BaseNameField
, MainAssembly
, culture
.Name
);
1355 // Looks up a resource value for a particular name. Looks in the
1356 // current thread's CultureInfo, and if not found, all parent CultureInfos.
1357 // Returns null if the resource wasn't found.
1359 public virtual Object
GetObject(String name
) {
1360 return GetObject(name
, (CultureInfo
)null, true);
1363 // Looks up a resource value for a particular name. Looks in the
1364 // specified CultureInfo, and if not found, all parent CultureInfos.
1365 // Returns null if the resource wasn't found.
1366 public virtual Object
GetObject(String name
, CultureInfo culture
) {
1367 return GetObject(name
, culture
, true);
1370 private Object
GetObject(String name
, CultureInfo culture
, bool wrapUnmanagedMemStream
)
1373 throw new ArgumentNullException("name");
1374 Contract
.EndContractBlock();
1379 // If the caller explictily passed in a culture that was obtained by calling CultureInfo.CurrentUICulture,
1380 // null it out, so that we re-compute it based on the Win32 value and not the AppX language list value.
1381 // (See the call a little later to GetCurrentUICultureNoAppX()).
1382 if(Object
.ReferenceEquals(culture
, CultureInfo
.CurrentUICulture
))
1389 if (null==culture
) {
1390 // When running inside AppX we want to ignore the languages list when trying to come up with our CurrentUICulture.
1391 // This line behaves the same way as CultureInfo.CurrentUICulture would have in .NET 4
1392 culture
= Thread
.CurrentThread
.GetCurrentUICultureNoAppX();
1395 #if !FEATURE_CORECLR && !MONO
1396 if (FrameworkEventSource
.IsInitialized
)
1398 FrameworkEventSource
.Log
.ResourceManagerLookupStarted(BaseNameField
, MainAssembly
, culture
.Name
);
1401 ResourceSet last
= GetFirstResourceSet(culture
);
1404 Object
value = last
.GetObject(name
, _ignoreCase
);
1408 UnmanagedMemoryStream stream
= value as UnmanagedMemoryStream
;
1409 if (stream
!= null && wrapUnmanagedMemStream
)
1410 return new UnmanagedMemoryStreamWrapper(stream
);
1416 // This is the CultureInfo hierarchy traversal code for resource
1417 // lookups, similar but necessarily orthogonal to the ResourceSet
1419 ResourceFallbackManager mgr
= new ResourceFallbackManager(culture
, _neutralResourcesCulture
, true);
1421 foreach (CultureInfo currentCultureInfo
in mgr
) {
1422 // Note: Technically this method should be passed in a stack crawl mark that we then pass
1423 // to InternalGetResourceSet for ensuring we demand permissions to read your private resources
1424 // if you're reading resources from an assembly other than yourself. But, we must call our
1425 // three argument overload (without the stack crawl mark) for compatibility. After
1426 // consideration, we aren't worried about the security impact.
1427 ResourceSet rs
= InternalGetResourceSet(currentCultureInfo
, true, true);
1432 Object
value = rs
.GetObject(name
, _ignoreCase
);
1433 if (value != null) {
1434 // update the last used ResourceSet
1435 if (_lastUsedResourceCache
!= null) {
1436 lock (_lastUsedResourceCache
) {
1437 _lastUsedResourceCache
.lastCultureName
= currentCultureInfo
.Name
;
1438 _lastUsedResourceCache
.lastResourceSet
= rs
;
1442 UnmanagedMemoryStream stream
= value as UnmanagedMemoryStream
;
1443 if (stream
!= null && wrapUnmanagedMemStream
)
1444 return new UnmanagedMemoryStreamWrapper(stream
);
1453 #if !FEATURE_CORECLR && !MONO
1454 if (FrameworkEventSource
.IsInitialized
)
1456 FrameworkEventSource
.Log
.ResourceManagerLookupFailed(BaseNameField
, MainAssembly
, culture
.Name
);
1463 public UnmanagedMemoryStream
GetStream(String name
) {
1464 return GetStream(name
, (CultureInfo
)null);
1468 public UnmanagedMemoryStream
GetStream(String name
, CultureInfo culture
) {
1469 Object obj
= GetObject(name
, culture
, false);
1470 UnmanagedMemoryStream ums
= obj
as UnmanagedMemoryStream
;
1471 if (ums
== null && obj
!= null)
1472 throw new InvalidOperationException(Environment
.GetResourceString("InvalidOperation_ResourceNotStream_Name", name
));
1476 #if RESOURCE_SATELLITE_CONFIG
1477 // Internal helper method - gives an end user the ability to prevent
1478 // satellite assembly probes for certain cultures via a config file.
1479 [System
.Security
.SecurityCritical
] // auto-generated
1480 private bool TryLookingForSatellite(CultureInfo lookForCulture
)
1482 if (!_checkedConfigFile
) {
1484 if (!_checkedConfigFile
) {
1485 _checkedConfigFile
= true;
1486 _installedSatelliteInfo
= GetSatelliteAssembliesFromConfig();
1491 if (_installedSatelliteInfo
== null)
1494 String
[] installedSatellites
= (String
[]) _installedSatelliteInfo
[MainAssembly
.FullName
];
1496 if (installedSatellites
== null)
1499 // The config file told us what satellites might be installed.
1500 int pos
= Array
.IndexOf(installedSatellites
, lookForCulture
.Name
);
1502 #if !FEATURE_CORECLR && !MONO
1503 if (FrameworkEventSource
.IsInitialized
&& FrameworkEventSource
.Log
.IsEnabled()) {
1505 FrameworkEventSource
.Log
.ResourceManagerCultureNotFoundInConfigFile(BaseNameField
, MainAssembly
, lookForCulture
.Name
);
1508 FrameworkEventSource
.Log
.ResourceManagerCultureFoundInConfigFile(BaseNameField
, MainAssembly
, lookForCulture
.Name
);
1515 // Note: There is one config file per appdomain. This is not
1516 // per-process nor per-assembly.
1517 [System
.Security
.SecurityCritical
] // auto-generated
1518 [ResourceExposure(ResourceScope
.None
)]
1519 [ResourceConsumption(ResourceScope
.Machine
, ResourceScope
.Machine
)]
1520 private Hashtable
GetSatelliteAssembliesFromConfig()
1524 String fileName
= AppDomain
.CurrentDomain
.FusionStore
.ConfigurationFileInternal
;
1525 if (fileName
== null) {
1529 // Don't do a security assert. We need to support semi-trusted
1530 // scenarios, but asserting here causes infinite resource lookups
1531 // while initializing security & looking up mscorlib's config file.
1532 // Use internal methods to bypass security checks.
1534 // If we're dealing with a local file name or a UNC path instead
1535 // of a URL, check to see if the file exists here for perf (avoids
1536 // throwing a FileNotFoundException).
1537 if (fileName
.Length
>= 2 &&
1538 ((fileName
[1] == Path
.VolumeSeparatorChar
) || (fileName
[0] == Path
.DirectorySeparatorChar
&& fileName
[1] == Path
.DirectorySeparatorChar
)) &&
1539 !File
.InternalExists(fileName
))
1542 ConfigTreeParser parser
= new ConfigTreeParser();
1543 String queryPath
= "/configuration/satelliteassemblies";
1544 ConfigNode node
= null;
1545 // Catch exceptions in case a web app doesn't have a config file.
1547 node
= parser
.Parse(fileName
, queryPath
, true);
1555 // The application config file will contain sections like this:
1556 // <?xml version="1.0"?>
1558 // <satelliteassemblies>
1559 // <assembly name="mscorlib, Version=..., PublicKeyToken=...">
1560 // <culture>fr</culture>
1562 // <assembly name="UserAssembly, ...">
1563 // <culture>fr-FR</culture>
1564 // <culture>de-CH</culture>
1566 // <assembly name="UserAssembly2, ...">
1568 // </satelliteassemblies>
1570 Hashtable satelliteInfo
= new Hashtable(StringComparer
.OrdinalIgnoreCase
);
1571 foreach(ConfigNode assemblyNode
in node
.Children
) {
1572 if (!String
.Equals(assemblyNode
.Name
, "assembly"))
1573 throw new ApplicationException(Environment
.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTag", Path
.GetFileName(fileName
), assemblyNode
.Name
));
1575 if (assemblyNode
.Attributes
.Count
== 0)
1576 throw new ApplicationException(Environment
.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTagNoAttr", Path
.GetFileName(fileName
)));
1578 DictionaryEntry de
= (DictionaryEntry
) assemblyNode
.Attributes
[0];
1579 String assemblyName
= (String
) de
.Value
;
1580 if (!String
.Equals(de
.Key
, "name") || String
.IsNullOrEmpty(assemblyName
) || assemblyNode
.Attributes
.Count
> 1)
1581 throw new ApplicationException(Environment
.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTagBadAttr", Path
.GetFileName(fileName
), de
.Key
, de
.Value
));
1583 ArrayList list
= new ArrayList(5);
1584 foreach(ConfigNode child
in assemblyNode
.Children
)
1585 if (child
.Value
!= null)
1586 list
.Add(child
.Value
);
1588 String
[] satellites
= new String
[list
.Count
];
1589 for(int i
=0; i
<satellites
.Length
; i
++) {
1590 String cultureName
= (String
)list
[i
];
1591 satellites
[i
] = cultureName
;
1592 #if !FEATURE_CORECLR && !MONO
1593 if (FrameworkEventSource
.IsInitialized
)
1595 FrameworkEventSource
.Log
.ResourceManagerAddingCultureFromConfigFile(BaseNameField
, MainAssembly
, cultureName
);
1600 satelliteInfo
.Add(assemblyName
, satellites
);
1603 return satelliteInfo
;
1606 #endif //FEATURE_FUSION
1609 #endif // RESOURCE_SATELLITE_CONFIG
1611 internal class ResourceManagerMediator
1613 private ResourceManager _rm
;
1615 internal ResourceManagerMediator(ResourceManager rm
)
1619 throw new ArgumentNullException("rm");
1624 // NEEDED ONLY BY FILE-BASED
1625 internal String ModuleDir
1627 get { return _rm.moduleDir; }
1630 // NEEDED BOTH BY FILE-BASED AND ----Y-BASED
1631 internal Type LocationInfo
1633 get { return _rm._locationInfo; }
1636 internal Type UserResourceSet
1638 get { return _rm._userResourceSet; }
1641 internal String BaseNameField
1643 get { return _rm.BaseNameField; }
1646 internal CultureInfo NeutralResourcesCulture
1648 get { return _rm._neutralResourcesCulture; }
1649 set { _rm._neutralResourcesCulture = value; }
1652 internal String
GetResourceFileName(CultureInfo culture
)
1654 return _rm
.GetResourceFileName(culture
);
1657 // NEEDED ONLY BY ----Y-BASED
1658 internal bool LookedForSatelliteContractVersion
1660 get { return _rm._lookedForSatelliteContractVersion; }
1661 set { _rm._lookedForSatelliteContractVersion = value; }
1664 internal Version SatelliteContractVersion
1666 get { return _rm._satelliteContractVersion; }
1667 set { _rm._satelliteContractVersion = value; }
1670 internal Version
ObtainSatelliteContractVersion(Assembly a
)
1672 return ResourceManager
.GetSatelliteContractVersion(a
);
1675 internal UltimateResourceFallbackLocation FallbackLoc
1677 get { return _rm.FallbackLocation; }
1678 set { _rm._fallbackLoc = value; }
1681 internal RuntimeAssembly CallingAssembly
1683 get { return _rm.m_callingAssembly; }
1686 internal RuntimeAssembly MainAssembly
1688 get { return (RuntimeAssembly)_rm.MainAssembly; }
1691 // this is weird because we have BaseNameField accessor above, but we're sticking
1692 // with it for compat.
1693 internal String BaseName
1695 get { return _rm.BaseName; }
1699 #if RESOURCE_SATELLITE_CONFIG
1700 [System
.Security
.SecurityCritical
] // auto-generated
1701 internal bool TryLookingForSatellite(CultureInfo lookForCulture
)
1703 return _rm
.TryLookingForSatellite(lookForCulture
);