cdff67b0962477ec4d915c78c250333918e3a769
[mono.git] / mcs / class / referencesource / mscorlib / system / resources / resourcemanager.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  ResourceManager
9 ** 
10 ** <OWNER>jathaine</OWNER>
11 **
12 **
13 ** Purpose: Default way to access String and Object resources
14 ** from an assembly.
15 **
16 ** 
17 ===========================================================*/
18
19 namespace System.Resources {    
20     using System;
21     using System.IO;
22     using System.Globalization;
23     using System.Collections;
24     using System.Text;
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;
36 #if !FEATURE_CORECLR
37     using System.Diagnostics.Tracing;
38 #endif
39
40 #if FEATURE_APPX
41     //
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.
48     //
49     [FriendAccessAllowed]
50     [SecurityCritical]
51     internal class WindowsRuntimeResourceManagerBase
52     {
53         [SecurityCritical]
54         public virtual bool Initialize(string libpath, string reswFilename, out PRIExceptionInfo exceptionInfo){exceptionInfo = null; return false;}
55
56         [SecurityCritical]
57         public virtual String GetString(String stringName, String startingCulture, String neutralResourcesCulture){return null;}
58
59         public virtual CultureInfo GlobalResourceContextBestFitCultureInfo { 
60             [SecurityCritical]
61             get { return null; } 
62         }
63         
64         [SecurityCritical]
65         public virtual bool SetGlobalResourceContextDefaultCulture(CultureInfo ci) { return false; }
66     }
67
68     [FriendAccessAllowed]
69     // [Microsoft 3/9/2012] This class should be named PRIErrorInfo.
70     //
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
82     {
83         public string _PackageSimpleName;
84         public string _ResWFile;
85     }
86 #endif // FEATURE_APPX
87
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.
96     // 
97     // Users should ideally create a resource file for every culture, or
98     // at least a meaningful subset.  The filenames will follow the naming 
99     // scheme:
100     // 
101     // basename.culture name.resources
102     // 
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.
108     // 
109     // -----------------
110     // Refactoring Notes
111     // -----------------
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.
121     // 
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.
128     //
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.
136     // 
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.
144     //
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 
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172     [Serializable]
173     [System.Runtime.InteropServices.ComVisible(true)]
174     public class ResourceManager
175     {
176
177         internal class CultureNameResourceSetPair {
178             public String lastCultureName;
179             public ResourceSet lastResourceSet;
180         }
181
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;
187         
188
189         // don't serialize the cache of ResourceSets
190         [NonSerialized]
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.
197
198         [NonSerialized]
199         private CultureNameResourceSetPair _lastUsedResourceCache;
200
201         private bool _ignoreCase;   // Whether case matters in GetString & GetObject
202
203         private bool UseManifest;  // Use Assembly manifest, or grovel disk.
204
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?
214 #endif
215
216         // Whether to fall back to the main assembly or a particular 
217         // satellite for the neutral resources.
218         [OptionalField]
219         private UltimateResourceFallbackLocation _fallbackLoc;
220         // Version number of satellite assemblies to look for.  May be null.
221         [OptionalField]
222         private Version _satelliteContractVersion;
223         [OptionalField]
224         private bool _lookedForSatelliteContractVersion;
225
226         // unused! But need to keep for serialization
227         [OptionalField(VersionAdded = 1)]
228         private Assembly _callingAssembly;  // Assembly who created the ResMgr.
229
230         // replaces _callingAssembly
231         [OptionalField(VersionAdded = 4)]
232         private RuntimeAssembly m_callingAssembly;  // Assembly who created the ResMgr.
233
234         // no need to serialize this; just create a new one on deserialization
235         [NonSerialized]
236         private IResourceGroveler resourceGroveler;
237
238         public static readonly int MagicNumber = unchecked((int)0xBEEFCACE);  // If only hex had a K...
239
240         // Version number so ResMgr can get the ideal set of classes for you.
241         // ResMgr header is:
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;
248
249         //
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.
255         //
256         //      private static CultureInfo _neutralCulture = null;
257
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
262         // InternalResGen.
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;
268
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.
272         
273         private static volatile bool s_IsAppXModel;
274         
275         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
276         private void Init()
277         {
278             m_callingAssembly = (RuntimeAssembly)Assembly.GetCallingAssembly();
279         }
280
281         protected ResourceManager() 
282         {
283 #if !FEATURE_CORECLR
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());
288 #endif
289
290             Init();
291
292             _lastUsedResourceCache = new CultureNameResourceSetPair();
293             ResourceManagerMediator mediator = new ResourceManagerMediator(this);
294             resourceGroveler = new ManifestBasedResourceGroveler(mediator);
295         }
296         
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.
301         //
302         // A good example of a baseName might be "Strings".  BaseName 
303         // should not end in ".resources".
304         //
305         // Note: System.Windows.Forms uses this method at design time.
306         // 
307         [ResourceExposure(ResourceScope.Machine)]
308         [ResourceConsumption(ResourceScope.Machine)]
309         private ResourceManager(String baseName, String resourceDir, Type usingResourceSet) {
310             if (null==baseName)
311                 throw new ArgumentNullException("baseName");
312             if (null==resourceDir)
313                 throw new ArgumentNullException("resourceDir");
314             Contract.EndContractBlock();
315
316 #if !FEATURE_CORECLR
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());
321 #endif
322
323             BaseNameField = baseName;
324
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();
332             UseManifest = false;
333
334             ResourceManagerMediator mediator = new ResourceManagerMediator(this);
335             resourceGroveler = new FileBasedResourceGroveler(mediator);
336
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);
341
342                 if (resourceGroveler.HasNeutralResources(culture, defaultResName)) {
343                     FrameworkEventSource.Log.ResourceManagerNeutralResourcesFound(BaseNameField, MainAssembly, defaultResName);
344                 }
345                 else {
346                     FrameworkEventSource.Log.ResourceManagerNeutralResourcesNotFound(BaseNameField, MainAssembly, defaultResName);
347                 }
348             }           
349 #endif
350         }
351     
352         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
353         public ResourceManager(String baseName, Assembly assembly)
354         {
355             if (null==baseName)
356                 throw new ArgumentNullException("baseName");
357
358             if (null==assembly)
359                 throw new ArgumentNullException("assembly");
360             Contract.EndContractBlock();
361
362             if (!(assembly is RuntimeAssembly))
363                 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"));
364
365             MainAssembly = assembly;
366             BaseNameField = baseName;
367
368             SetAppXConfiguration();
369
370             CommonAssemblyInit();
371
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)
378             {
379                 m_callingAssembly = null;
380             }
381         }
382
383         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
384         public ResourceManager(String baseName, Assembly assembly, Type usingResourceSet)
385         {
386             if (null==baseName)
387                 throw new ArgumentNullException("baseName");
388             if (null==assembly)
389                 throw new ArgumentNullException("assembly");
390             Contract.EndContractBlock();
391
392 #if !FEATURE_CORECLR
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());
397 #endif
398
399             if (!(assembly is RuntimeAssembly))
400                 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"));
401
402             MainAssembly = assembly;
403             BaseNameField = baseName;
404     
405             if (usingResourceSet != null && (usingResourceSet != _minResourceSet) && !(usingResourceSet.IsSubclassOf(_minResourceSet)))
406                 throw new ArgumentException(Environment.GetResourceString("Arg_ResMgrNotResSet"), "usingResourceSet");
407             _userResourceSet = usingResourceSet;
408
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;
417         }
418         
419         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
420         public ResourceManager(Type resourceSource)
421         {
422             if (null==resourceSource)
423                 throw new ArgumentNullException("resourceSource");
424             Contract.EndContractBlock();
425
426             if (!(resourceSource is RuntimeType))
427                 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"));
428
429             _locationInfo = resourceSource;
430             MainAssembly = _locationInfo.Assembly;
431             BaseNameField = resourceSource.Name;
432             
433             SetAppXConfiguration();
434
435             CommonAssemblyInit();
436
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)
440             {
441                 m_callingAssembly = null;
442             }
443         }
444
445         [OnDeserializing]
446         private void OnDeserializing(StreamingContext ctx)
447         {
448             this._resourceSets = null;
449             this.resourceGroveler = null;
450             this._lastUsedResourceCache = null;
451         }
452
453         [System.Security.SecuritySafeCritical]
454         [OnDeserialized]
455         private void OnDeserialized(StreamingContext ctx)
456         {
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);
462             if (UseManifest)
463             {
464                 resourceGroveler = new ManifestBasedResourceGroveler(mediator);
465             }
466             else
467             {
468                 resourceGroveler = new FileBasedResourceGroveler(mediator);
469             }
470
471             // correct callingAssembly for v2
472             if (this.m_callingAssembly == null)
473             {
474                 this.m_callingAssembly = (RuntimeAssembly)_callingAssembly;
475             }
476
477             // v2 does this lazily
478             if (UseManifest && this._neutralResourcesCulture == null)
479             {
480                 _neutralResourcesCulture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(MainAssembly, ref _fallbackLoc);
481             }
482         }
483
484         [OnSerializing]
485         private void OnSerializing(StreamingContext ctx)
486         {
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
493         }
494       
495
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()
500         {
501             if (_bUsingModernResourceManagement == false)
502             {
503                 UseManifest = true;
504         
505                 _resourceSets = new Dictionary<String,ResourceSet>();
506                 _lastUsedResourceCache = new CultureNameResourceSetPair();
507
508                 _fallbackLoc = UltimateResourceFallbackLocation.MainAssembly;
509
510                 ResourceManagerMediator mediator = new ResourceManagerMediator(this);
511                 resourceGroveler = new ManifestBasedResourceGroveler(mediator);
512             }
513
514             _neutralResourcesCulture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(MainAssembly, ref _fallbackLoc);
515
516 #if !FEATURE_CORECLR   // PAL doesn't support eventing, and we don't compile event providers for coreclr
517             if (_bUsingModernResourceManagement == false)
518             {
519 #if !MONO
520                 if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled()) {
521                     CultureInfo culture = CultureInfo.InvariantCulture;
522                     String defaultResName = GetResourceFileName(culture);
523
524                     if (resourceGroveler.HasNeutralResources(culture, defaultResName)) {
525                         FrameworkEventSource.Log.ResourceManagerNeutralResourcesFound(BaseNameField, MainAssembly, defaultResName);
526                     }
527                     else {
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);
532                     }
533                 }
534 #endif
535 #pragma warning disable 618
536                 ResourceSets = new Hashtable(); // for backward compatibility
537 #pragma warning restore 618
538             }
539 #endif
540         }
541
542         // Gets the base name for the ResourceManager.
543         public virtual String BaseName {
544             get { return BaseNameField; }
545         }
546     
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; }
552         }
553
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; }
558         }
559
560         protected UltimateResourceFallbackLocation FallbackLocation
561         {
562             get { return _fallbackLoc; }
563             set { _fallbackLoc = value; }
564         }
565
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.
572         // 
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()
576         {
577 #if !FEATURE_CORECLR && !MONO
578             if (FrameworkEventSource.IsInitialized)
579             {
580                 FrameworkEventSource.Log.ResourceManagerReleasingResources(BaseNameField, MainAssembly);
581             }
582 #endif
583             Dictionary<String, ResourceSet> localResourceSets = _resourceSets;
584
585             // If any calls to Close throw, at least leave ourselves in a
586             // consistent state.
587             _resourceSets = new Dictionary<String,ResourceSet>();
588             _lastUsedResourceCache = new CultureNameResourceSetPair();
589             
590             lock(localResourceSets) {
591                 IDictionaryEnumerator setEnum = localResourceSets.GetEnumerator();
592
593 #if !FEATURE_CORECLR
594                 IDictionaryEnumerator setEnum2 = null;
595 #pragma warning disable 618
596                 if (ResourceSets != null) {
597                     setEnum2 = ResourceSets.GetEnumerator();
598                 }
599                 ResourceSets = new Hashtable(); // for backwards compat
600 #pragma warning restore 618
601 #endif
602
603                 while (setEnum.MoveNext()) {
604                     ((ResourceSet)setEnum.Value).Close();
605                 }
606
607 #if !FEATURE_CORECLR
608                 if (setEnum2 != null) {
609                     while (setEnum2.MoveNext()) {
610                         ((ResourceSet)setEnum2.Value).Close();
611                     }
612                 }
613 #endif
614             }
615         }
616
617         [ResourceExposure(ResourceScope.Machine)]
618         [ResourceConsumption(ResourceScope.Machine)]
619         public static ResourceManager CreateFileBasedResourceManager(String baseName, String resourceDir, Type usingResourceSet)
620         {
621             return new ResourceManager(baseName, resourceDir, usingResourceSet);
622         }
623       
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.
631         // 
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)
639             {
640                 CultureInfo.VerifyCultureName(culture.Name, true);
641                 sb.Append('.');
642                 sb.Append(culture.Name);
643             }
644             sb.Append(ResFileExtension);
645             return sb.ToString();
646         }
647
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)
651         {
652             // Logic from ResourceFallbackManager.GetEnumerator()
653             if (_neutralResourcesCulture != null && culture.Name == _neutralResourcesCulture.Name) 
654             {
655                 culture = CultureInfo.InvariantCulture;
656             }
657
658             if(_lastUsedResourceCache != null) {
659                 lock (_lastUsedResourceCache) {
660                     if (culture.Name == _lastUsedResourceCache.lastCultureName)
661                         return _lastUsedResourceCache.lastResourceSet;
662                 }
663             }
664
665             // Look in the ResourceSet table
666             Dictionary<String,ResourceSet> localResourceSets = _resourceSets;
667             ResourceSet rs = null;
668             if (localResourceSets != null) 
669             {
670                 lock (localResourceSets) 
671                 {
672                     localResourceSets.TryGetValue(culture.Name, out rs);
673                 }
674             }
675
676             if (rs != null)
677             {
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;
683                     }
684                 }
685                 return rs;
686             }
687
688             return null;
689         }
690         
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.  
694         //
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.
698         //         
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) {
702             if (null==culture)
703                 throw new ArgumentNullException("culture");
704             Contract.EndContractBlock();
705
706             Dictionary<String,ResourceSet> localResourceSets = _resourceSets;
707             ResourceSet rs;
708             if (localResourceSets != null) {
709                 lock (localResourceSets) {
710                     if (localResourceSets.TryGetValue(culture.Name, out rs))
711                         return rs;
712                 }
713             }
714
715             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
716
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);                    
724                     return rs;
725                 }
726             }
727
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.
736             // <
737             return InternalGetResourceSet(culture, createIfNotExists, tryParents);
738         }
739
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) 
749         {
750             Contract.Assert(culture != null, "culture != null");
751
752             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
753             return InternalGetResourceSet(culture,createIfNotExists,tryParents, ref stackMark);
754         }
755
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)
764         {
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);
773                     }
774 #endif
775                     return rs;
776                 }
777             }
778
779             ResourceFallbackManager mgr = new ResourceFallbackManager(requestedCulture, _neutralResourcesCulture, tryParents);
780
781             foreach (CultureInfo currentCultureInfo in mgr)
782             {
783 #if !FEATURE_CORECLR && !MONO
784                 if (FrameworkEventSource.IsInitialized)
785                 {
786                     FrameworkEventSource.Log.ResourceManagerLookingForResourceSet(BaseNameField, MainAssembly, currentCultureInfo.Name);
787                 }
788 #endif
789                 lock(localResourceSets) {
790                     if (localResourceSets.TryGetValue(currentCultureInfo.Name, out rs)) {
791 #if !FEATURE_CORECLR && !MONO
792                         if (FrameworkEventSource.IsInitialized)
793                         {
794                             FrameworkEventSource.Log.ResourceManagerFoundResourceSetInCache(BaseNameField, MainAssembly, currentCultureInfo.Name);
795                         }
796 #endif
797                         // we need to update the cache if we fellback
798                         if(requestedCulture != currentCultureInfo) foundCulture = currentCultureInfo;
799                         break;
800                     }
801                 }
802
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.
808
809                 rs = resourceGroveler.GrovelForResourceSet(currentCultureInfo, localResourceSets, 
810                                                            tryParents, createIfNotExists, ref stackMark);
811
812                 // found a ResourceSet; we're done
813                 if (rs != null)
814                 {
815                     foundCulture = currentCultureInfo;
816                     break;
817                 }
818
819             }
820
821             if (rs != null && foundCulture != null)
822             {
823                 // add entries to the cache for the cultures we have gone through
824
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)
829                 {
830                     AddResourceSet(localResourceSets, updateCultureInfo.Name, ref rs);
831
832                     // stop when we've added current or reached invariant (top of chain)
833                     if (updateCultureInfo == foundCulture)
834                     {
835                         break;
836                     }
837                 } 
838             }
839
840             return rs;
841         }
842
843         // Simple helper to ease maintenance and improve readability.
844         private static void AddResourceSet(Dictionary<String,ResourceSet> localResourceSets, String cultureName, ref ResourceSet rs)
845         {
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))
859                             rs.Dispose();
860                         rs = lostRace;
861                     }
862                 }
863                 else {
864                     localResourceSets.Add(cultureName, rs);
865                 }
866             }
867         }
868
869         protected static Version GetSatelliteContractVersion(Assembly a)
870         {
871             // Ensure that the assembly reference is not null
872             if (a == null) {
873                 throw new ArgumentNullException("a", Environment.GetResourceString("ArgumentNull_Assembly"));
874             }
875             Contract.EndContractBlock();
876
877 #if !FEATURE_WINDOWSPHONE
878             String v = null;
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;
883                         break;
884                     }
885                 }
886
887                 if (v == null)
888                     return null;
889             }
890             else {
891                 Object[] attrs = a.GetCustomAttributes(typeof(SatelliteContractVersionAttribute), false);
892                 if (attrs.Length == 0)
893                     return null;
894                 Contract.Assert(attrs.Length == 1, "Cannot have multiple instances of SatelliteContractVersionAttribute on an assembly!");
895                 v = ((SatelliteContractVersionAttribute)attrs[0]).Version;
896             }
897             Version ver;
898             try {
899                 ver = new Version(v);
900             }
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
905                 // BCL directory.
906                 if (a == typeof(Object).Assembly) {
907                     Contract.Assert(false, "mscorlib's SatelliteContractVersionAttribute is a malformed version string!");
908                     return null;
909                 }
910
911                 throw new ArgumentException(Environment.GetResourceString("Arg_InvalidSatelliteContract_Asm_Ver", a.ToString(), v), e);
912             }
913             return ver;
914 #else
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.
917             return null;
918 #endif
919         }
920
921         [System.Security.SecuritySafeCritical]  // auto-generated
922         protected static CultureInfo GetNeutralResourcesLanguage(Assembly a)
923         {
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);
928             return culture;
929         }
930
931         // IGNORES VERSION
932         internal static bool CompareNames(String asmTypeName1,
933                                           String typeName2, 
934                                           AssemblyName asmName2)
935         {
936             Contract.Assert(asmTypeName1 != null, "asmTypeName1 was unexpectedly null");
937
938             // First, compare type names
939             int comma = asmTypeName1.IndexOf(',');
940             if (((comma == -1) ? asmTypeName1.Length : comma) != typeName2.Length)
941                 return false;
942
943             // case sensitive
944             if (String.Compare(asmTypeName1, 0, typeName2, 0, typeName2.Length, StringComparison.Ordinal) != 0)
945                 return false;
946             if (comma == -1)
947                 return true;
948
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]));
952
953             // case insensitive
954             AssemblyName an1 = new AssemblyName(asmTypeName1.Substring(comma));
955             if (String.Compare(an1.Name, asmName2.Name, StringComparison.OrdinalIgnoreCase) != 0)
956                 return false;
957
958             // to match IsMscorlib() in VM
959             if (String.Compare(an1.Name, "mscorlib", StringComparison.OrdinalIgnoreCase) == 0)
960                 return true;
961
962
963             if ((an1.CultureInfo != null) && (asmName2.CultureInfo != null) &&
964 #if FEATURE_USE_LCID                
965                 (an1.CultureInfo.LCID != asmName2.CultureInfo.LCID)
966 #else
967                 (an1.CultureInfo.Name != asmName2.CultureInfo.Name)
968 #endif                
969                 )
970                 return false;
971
972             byte[] pkt1 = an1.GetPublicKeyToken();
973             byte[] pkt2 = asmName2.GetPublicKeyToken();
974             if ((pkt1 != null) && (pkt2 != null)) {
975                 if (pkt1.Length != pkt2.Length)
976                     return false;
977
978                 for(int i=0; i < pkt1.Length; i++) {
979                     if(pkt1[i] != pkt2[i])
980                         return false;
981                 }
982             }
983
984             return true;
985         }
986
987 #if FEATURE_APPX
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());
995         
996             if (stringName.Length == 0)
997                 return null;
998             
999             string resourceString = null;
1000
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(
1004                                        stringName,
1005                                        String.IsNullOrEmpty(startingCulture) ? null : startingCulture,
1006                                        String.IsNullOrEmpty(neutralResourcesCulture) ? null : neutralResourcesCulture);
1007             
1008             return resourceString;
1009         }
1010
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.
1014         [SecurityCritical]
1015         internal static WindowsRuntimeResourceManagerBase GetWinRTResourceManager()
1016         {
1017             Type WinRTResourceManagerType = Type.GetType("System.Resources.WindowsRuntimeResourceManager, " + AssemblyRef.SystemRuntimeWindowsRuntime, true);
1018             return (WindowsRuntimeResourceManagerBase)Activator.CreateInstance(WinRTResourceManagerType, true);
1019         }
1020 #endif
1021
1022         [NonSerialized]
1023         private bool _bUsingModernResourceManagement; // Written only by SetAppXConfiguration
1024
1025 #if FEATURE_APPX
1026         [NonSerialized]
1027         [SecurityCritical]
1028         private WindowsRuntimeResourceManagerBase _WinRTResourceManager; // Written only by SetAppXConfiguration
1029
1030         [NonSerialized]
1031         private bool _PRIonAppXInitialized; // Written only by SetAppXConfiguration
1032
1033         [NonSerialized]
1034         private PRIExceptionInfo _PRIExceptionInfo; // Written only by SetAppXConfiguration
1035
1036         // When running under AppX, the following rules apply for resource lookup:
1037         //
1038         // Desktop
1039         // -------
1040         //
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.
1044         //
1045         // CoreCLR
1046         // -------
1047         //
1048         // 1) For Framework assemblies, we always use satellite assembly based lookup.
1049         // 2) For non-FX assemblies:
1050         //    
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.
1053         //   
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)
1058         {
1059             bool fUseSatelliteAssemblyResourceLookupUnderAppX = resourcesAssembly.IsFrameworkAssembly();
1060             
1061 #if FEATURE_CORECLR     
1062             if (!fUseSatelliteAssemblyResourceLookupUnderAppX)
1063             {
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))
1067                 {
1068                     string resourceAssemblyPath = resourcesAssembly.Location;
1069                     
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))
1072                     {
1073                         if (resourceAssemblyPath.StartsWith(pathPlatformResourceRoot, StringComparison.CurrentCultureIgnoreCase))
1074                         {
1075                             // Found the resource assembly to be present in one of the PLATFORM_RESOURCE_ROOT, so stop the enumeration loop.
1076                             fUseSatelliteAssemblyResourceLookupUnderAppX = true;
1077                             break;
1078                         }
1079                     }
1080                 }
1081             }
1082 #endif // FEATURE_CORECLR
1083             return fUseSatelliteAssemblyResourceLookupUnderAppX;
1084             
1085         }
1086         
1087         [SecuritySafeCritical]
1088 #endif // FEATURE_APPX
1089         // Only call SetAppXConfiguration from ResourceManager constructors, and nowhere else.
1090         // Throws MissingManifestResourceException and WinRT HResults
1091
1092         private void SetAppXConfiguration()
1093         {
1094             Contract.Assert(_bUsingModernResourceManagement == false); // Only this function writes to this member
1095 #if FEATURE_APPX
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
1099
1100             bool bUsingSatelliteAssembliesUnderAppX = false;
1101
1102             RuntimeAssembly resourcesAssembly = (RuntimeAssembly)MainAssembly;
1103
1104             if (resourcesAssembly == null)
1105                 resourcesAssembly = m_callingAssembly;
1106
1107             if (resourcesAssembly != null)
1108             {
1109                 if (resourcesAssembly != typeof(Object).Assembly) // We are not loading resources for mscorlib
1110                 {
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)
1114                     {
1115                         s_IsAppXModel = true;
1116
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;
1119
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;
1131
1132                         WindowsRuntimeResourceManagerBase WRRM = null;
1133                         bool bWRRM_Initialized = false;
1134                         
1135                         if (AppDomain.IsAppXDesignMode())
1136                         {
1137                             WRRM = GetWinRTResourceManager();
1138                             try {
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;
1142                             }
1143                             catch(Exception e)
1144                             {
1145                                 bUsingSatelliteAssembliesUnderAppX = true;
1146                                 if (e.IsTransient)
1147                                     throw;
1148                             }
1149                         }
1150
1151                         if (!bUsingSatelliteAssembliesUnderAppX)
1152                         {
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); 
1156
1157                             if (_bUsingModernResourceManagement)
1158                             {
1159                                 // Only now are we certain that we need the PRI file.
1160
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.
1163
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.
1171
1172                                 if (WRRM != null && bWRRM_Initialized)
1173                                 {
1174                                     // Reuse the one successfully created earlier
1175                                     _WinRTResourceManager = WRRM;
1176                                     _PRIonAppXInitialized = true;
1177                                 }
1178                                 else 
1179                                 {
1180                                     _WinRTResourceManager = GetWinRTResourceManager();
1181                                     
1182                                     try {
1183                                         _PRIonAppXInitialized = _WinRTResourceManager.Initialize(resourcesAssembly.Location, reswFilename, out _PRIExceptionInfo);
1184
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.
1189                                     }
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)
1197                                     {
1198                                         // We will throw MissingManifestResource_NoPRIresources from GetString
1199                                         // when we see that _PRIonAppXInitialized is false.
1200                                     }
1201                                     catch(Exception e)
1202                                     {
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.
1210                                     }
1211                                     // Allow all other exception types to bubble up to the caller.
1212
1213                                     // Yes, this causes us to potentially throw exception types that are not documented.
1214
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.
1221
1222
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.
1226                                 }
1227                             }
1228                         }
1229                     }
1230                 }
1231             }
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            
1236         }
1237
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.
1241         // 
1242         public virtual String GetString(String name) {
1243             return GetString(name, (CultureInfo)null);
1244         }
1245         
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.
1249         // 
1250         public virtual String GetString(String name, CultureInfo culture) {
1251             if (null==name)
1252                 throw new ArgumentNullException("name");
1253             Contract.EndContractBlock();
1254
1255 #if FEATURE_APPX
1256             if(s_IsAppXModel)
1257             {
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))
1264                  {
1265                      culture = null;
1266                  }              
1267             }
1268
1269             if (_bUsingModernResourceManagement)
1270             {
1271                 if (_PRIonAppXInitialized == false)
1272                 {
1273                     // Always throw if we did not fully succeed in initializing the WinRT Resource Manager.
1274
1275                     if (_PRIExceptionInfo != null && _PRIExceptionInfo._PackageSimpleName != null && _PRIExceptionInfo._ResWFile != null)
1276                         throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_ResWFileNotLoaded", _PRIExceptionInfo._ResWFile, _PRIExceptionInfo._PackageSimpleName));
1277
1278                     throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoPRIresources"));
1279                 }
1280             
1281                 // Throws WinRT hresults.
1282                 return GetStringFromPRI(name,
1283                                         culture == null ? null : culture.Name,
1284                                         _neutralResourcesCulture.Name);
1285             }
1286             else
1287 #endif // FEATURE_APPX
1288             {
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();
1293                 }
1294     
1295 #if !FEATURE_CORECLR && !MONO
1296                 if (FrameworkEventSource.IsInitialized)
1297                 {
1298                     FrameworkEventSource.Log.ResourceManagerLookupStarted(BaseNameField, MainAssembly, culture.Name);
1299                 }
1300 #endif
1301                 ResourceSet last = GetFirstResourceSet(culture);
1302
1303                 if (last != null)
1304                 {
1305                     String value = last.GetString(name, _ignoreCase);
1306                     if (value != null)
1307                         return value;
1308                 }
1309                 
1310                 
1311                 // This is the CultureInfo hierarchy traversal code for resource 
1312                 // lookups, similar but necessarily orthogonal to the ResourceSet 
1313                 // lookup logic.
1314                 ResourceFallbackManager mgr = new ResourceFallbackManager(culture, _neutralResourcesCulture, true);
1315                 foreach (CultureInfo currentCultureInfo in mgr) {
1316
1317                     ResourceSet rs = InternalGetResourceSet(currentCultureInfo, true, true);
1318                     if (rs == null)
1319                         break;
1320
1321                     if (rs != last) {
1322                         String value = rs.GetString(name, _ignoreCase);
1323                         if (value != null)
1324                         {
1325                             // update last used ResourceSet
1326                             if (_lastUsedResourceCache != null) {
1327                                 lock (_lastUsedResourceCache) {
1328                                     _lastUsedResourceCache.lastCultureName = currentCultureInfo.Name;
1329                                     _lastUsedResourceCache.lastResourceSet = rs;
1330                                 }
1331                             }
1332                             return value;
1333                         }
1334
1335                         last = rs;
1336                     }
1337                 }
1338
1339 #if !FEATURE_CORECLR && !MONO
1340                 if (FrameworkEventSource.IsInitialized)
1341                 {
1342                     FrameworkEventSource.Log.ResourceManagerLookupFailed(BaseNameField, MainAssembly, culture.Name);
1343                 }
1344 #endif
1345             }
1346
1347             return null;
1348         }
1349         
1350         
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.
1354         // 
1355         public virtual Object GetObject(String name) {
1356             return GetObject(name, (CultureInfo)null, true);
1357         }
1358         
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);
1364         }
1365
1366         private Object GetObject(String name, CultureInfo culture, bool wrapUnmanagedMemStream)
1367         {
1368             if (null==name)
1369                 throw new ArgumentNullException("name");
1370             Contract.EndContractBlock();
1371
1372 #if FEATURE_APPX
1373             if(s_IsAppXModel)
1374             {
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))
1379                  {
1380                      culture = null;
1381                  }              
1382             }
1383 #endif
1384
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();
1389             }
1390
1391 #if !FEATURE_CORECLR && !MONO
1392             if (FrameworkEventSource.IsInitialized)
1393             {
1394                 FrameworkEventSource.Log.ResourceManagerLookupStarted(BaseNameField, MainAssembly, culture.Name);
1395             }
1396 #endif
1397             ResourceSet last = GetFirstResourceSet(culture);
1398             if (last != null)
1399             {
1400                 Object value = last.GetObject(name, _ignoreCase);
1401
1402                 if (value != null) 
1403                 {
1404                     UnmanagedMemoryStream stream = value as UnmanagedMemoryStream;
1405                     if (stream != null && wrapUnmanagedMemStream)
1406                         return new UnmanagedMemoryStreamWrapper(stream);
1407                     else
1408                         return value;
1409                 }
1410             }
1411             
1412             // This is the CultureInfo hierarchy traversal code for resource 
1413             // lookups, similar but necessarily orthogonal to the ResourceSet 
1414             // lookup logic.
1415             ResourceFallbackManager mgr = new ResourceFallbackManager(culture, _neutralResourcesCulture, true);
1416             
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);
1424                 if (rs == null)
1425                     break;
1426
1427                 if (rs != last) {
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;
1435                             }
1436                         }
1437
1438                         UnmanagedMemoryStream stream = value as UnmanagedMemoryStream;
1439                         if (stream != null && wrapUnmanagedMemStream)
1440                             return new UnmanagedMemoryStreamWrapper(stream);
1441                         else
1442                             return value;
1443                     }
1444
1445                     last = rs;
1446                 }
1447             }
1448
1449 #if !FEATURE_CORECLR && !MONO
1450             if (FrameworkEventSource.IsInitialized)
1451             {
1452                 FrameworkEventSource.Log.ResourceManagerLookupFailed(BaseNameField, MainAssembly, culture.Name);
1453             }
1454 #endif
1455             return null;
1456         }
1457
1458         [ComVisible(false)]
1459         public UnmanagedMemoryStream GetStream(String name) {
1460             return GetStream(name, (CultureInfo)null);
1461         }
1462         
1463         [ComVisible(false)]
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));
1469             return ums;
1470         }
1471
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)
1477         {
1478             if (!_checkedConfigFile) {
1479                 lock (this) {
1480                     if (!_checkedConfigFile) {
1481                         _checkedConfigFile = true;
1482                         _installedSatelliteInfo = GetSatelliteAssembliesFromConfig();
1483                     }
1484                 }
1485             }
1486
1487             if (_installedSatelliteInfo == null)
1488                 return true;
1489
1490             String[] installedSatellites = (String[]) _installedSatelliteInfo[MainAssembly.FullName];
1491
1492             if (installedSatellites == null)
1493                 return true;
1494
1495             // The config file told us what satellites might be installed.
1496             int pos = Array.IndexOf(installedSatellites, lookForCulture.Name);
1497
1498 #if !FEATURE_CORECLR && !MONO
1499             if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled()) {
1500                 if (pos < 0) {
1501                     FrameworkEventSource.Log.ResourceManagerCultureNotFoundInConfigFile(BaseNameField, MainAssembly, lookForCulture.Name);
1502                 }
1503                 else {
1504                     FrameworkEventSource.Log.ResourceManagerCultureFoundInConfigFile(BaseNameField, MainAssembly, lookForCulture.Name);
1505                 }
1506             }
1507 #endif
1508             return pos >= 0;
1509         }
1510
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()
1517         {
1518 #if FEATURE_FUSION
1519
1520             String fileName = AppDomain.CurrentDomain.FusionStore.ConfigurationFileInternal;
1521             if (fileName == null) {
1522                 return null;
1523             }
1524
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.
1529
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))
1536                 return null;
1537
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.
1542             try {
1543                 node = parser.Parse(fileName, queryPath, true);
1544             }
1545             catch(Exception) {}
1546
1547             if (node == null) {
1548                 return null;
1549             }
1550
1551             // The application config file will contain sections like this:
1552             // <?xml version="1.0"?>
1553             // <configuration>
1554             //     <satelliteassemblies>
1555             //         <assembly name="mscorlib, Version=..., PublicKeyToken=...">
1556             //             <culture>fr</culture>
1557             //         </assembly>
1558             //         <assembly name="UserAssembly, ...">
1559             //             <culture>fr-FR</culture>
1560             //             <culture>de-CH</culture>
1561             //         </assembly>
1562             //         <assembly name="UserAssembly2, ...">
1563             //         </assembly>
1564             //    </satelliteassemblies>
1565             // </configuration>
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));
1570
1571                 if (assemblyNode.Attributes.Count == 0)
1572                     throw new ApplicationException(Environment.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTagNoAttr", Path.GetFileName(fileName)));
1573
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));
1578
1579                 ArrayList list = new ArrayList(5);
1580                 foreach(ConfigNode child in assemblyNode.Children)
1581                     if (child.Value != null)
1582                         list.Add(child.Value);
1583
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)
1590                     {
1591                         FrameworkEventSource.Log.ResourceManagerAddingCultureFromConfigFile(BaseNameField, MainAssembly, cultureName);
1592                     }
1593 #endif
1594                 }
1595
1596                 satelliteInfo.Add(assemblyName, satellites);
1597             }
1598
1599             return satelliteInfo;
1600 #else
1601             return null;
1602 #endif //FEATURE_FUSION
1603
1604         }
1605 #endif  // RESOURCE_SATELLITE_CONFIG
1606
1607         internal class ResourceManagerMediator
1608         {
1609             private ResourceManager _rm;
1610
1611             internal ResourceManagerMediator(ResourceManager rm)
1612             {
1613                 if (rm == null)
1614                 {
1615                     throw new ArgumentNullException("rm");
1616                 }
1617                 _rm = rm;
1618             }
1619
1620             // NEEDED ONLY BY FILE-BASED
1621             internal String ModuleDir
1622             {
1623                 get { return _rm.moduleDir; }
1624             }
1625
1626             // NEEDED BOTH BY FILE-BASED  AND ----Y-BASED
1627             internal Type LocationInfo
1628             {
1629                 get { return _rm._locationInfo; }
1630             }
1631
1632             internal Type UserResourceSet 
1633             {
1634                 get { return _rm._userResourceSet; }
1635             }
1636
1637             internal String BaseNameField
1638             {
1639                 get { return _rm.BaseNameField; }
1640             }
1641
1642             internal CultureInfo NeutralResourcesCulture
1643             {
1644                 get { return _rm._neutralResourcesCulture; }
1645                 set { _rm._neutralResourcesCulture = value; }
1646             }
1647
1648             internal String GetResourceFileName(CultureInfo culture)
1649             {
1650                 return _rm.GetResourceFileName(culture);
1651             }
1652
1653             // NEEDED ONLY BY ----Y-BASED
1654             internal bool LookedForSatelliteContractVersion
1655             {
1656                 get { return _rm._lookedForSatelliteContractVersion; }
1657                 set { _rm._lookedForSatelliteContractVersion = value; }
1658             }
1659
1660             internal Version SatelliteContractVersion
1661             {
1662                 get { return _rm._satelliteContractVersion; }
1663                 set { _rm._satelliteContractVersion = value; }
1664             }
1665
1666             internal Version ObtainSatelliteContractVersion(Assembly a)
1667             {
1668                 return ResourceManager.GetSatelliteContractVersion(a);
1669             }
1670
1671             internal UltimateResourceFallbackLocation FallbackLoc
1672             {
1673                 get { return _rm.FallbackLocation; } 
1674                 set { _rm._fallbackLoc = value; }
1675             }
1676
1677             internal RuntimeAssembly CallingAssembly
1678             {
1679                 get { return _rm.m_callingAssembly; }
1680             }
1681
1682             internal RuntimeAssembly MainAssembly
1683             {
1684                 get { return (RuntimeAssembly)_rm.MainAssembly; }
1685             }
1686
1687             // this is weird because we have BaseNameField accessor above, but we're sticking
1688             // with it for compat.
1689             internal String BaseName
1690             {
1691                 get { return _rm.BaseName; }
1692             }
1693
1694
1695 #if RESOURCE_SATELLITE_CONFIG
1696             [System.Security.SecurityCritical]  // auto-generated
1697             internal bool TryLookingForSatellite(CultureInfo lookForCulture)
1698             {
1699                 return _rm.TryLookingForSatellite(lookForCulture);
1700             }
1701 #endif
1702
1703         }
1704     }
1705 }