Merge pull request #3522 from henricm/fix-csharp-compiler-path-windows
[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     // [[....] 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 bug that's been lurking a while in file-based 
151     // lookup paths for InternalGetResourceSet if createIfNotExists is
152     // false.
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.
162     // 
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.
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 #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?
216 #endif
217
218         // Whether to fall back to the main assembly or a particular 
219         // satellite for the neutral resources.
220         [OptionalField]
221         private UltimateResourceFallbackLocation _fallbackLoc;
222         // Version number of satellite assemblies to look for.  May be null.
223         [OptionalField]
224         private Version _satelliteContractVersion;
225         [OptionalField]
226         private bool _lookedForSatelliteContractVersion;
227
228         // unused! But need to keep for serialization
229         [OptionalField(VersionAdded = 1)]
230         private Assembly _callingAssembly;  // Assembly who created the ResMgr.
231
232         // replaces _callingAssembly
233         [OptionalField(VersionAdded = 4)]
234         private RuntimeAssembly m_callingAssembly;  // Assembly who created the ResMgr.
235
236         // no need to serialize this; just create a new one on deserialization
237         [NonSerialized]
238         private IResourceGroveler resourceGroveler;
239
240         public static readonly int MagicNumber = unchecked((int)0xBEEFCACE);  // If only hex had a K...
241
242         // Version number so ResMgr can get the ideal set of classes for you.
243         // ResMgr header is:
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;
250
251         //
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.
257         //
258         //      private static CultureInfo _neutralCulture = null;
259
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
264         // InternalResGen.
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;
270
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.
274 #if FEATURE_APPX        
275         private static volatile bool s_IsAppXModel;
276 #endif
277         
278         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
279         private void Init()
280         {
281             m_callingAssembly = (RuntimeAssembly)Assembly.GetCallingAssembly();
282         }
283
284         protected ResourceManager() 
285         {
286 #if !FEATURE_CORECLR
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());
291 #endif
292
293             Init();
294
295             _lastUsedResourceCache = new CultureNameResourceSetPair();
296             ResourceManagerMediator mediator = new ResourceManagerMediator(this);
297             resourceGroveler = new ManifestBasedResourceGroveler(mediator);
298         }
299         
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.
304         //
305         // A good example of a baseName might be "Strings".  BaseName 
306         // should not end in ".resources".
307         //
308         // Note: System.Windows.Forms uses this method at design time.
309         // 
310         [ResourceExposure(ResourceScope.Machine)]
311         [ResourceConsumption(ResourceScope.Machine)]
312         private ResourceManager(String baseName, String resourceDir, Type usingResourceSet) {
313             if (null==baseName)
314                 throw new ArgumentNullException("baseName");
315             if (null==resourceDir)
316                 throw new ArgumentNullException("resourceDir");
317             Contract.EndContractBlock();
318
319 #if !FEATURE_CORECLR
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());
324 #endif
325
326             BaseNameField = baseName;
327
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();
335             UseManifest = false;
336
337             ResourceManagerMediator mediator = new ResourceManagerMediator(this);
338             resourceGroveler = new FileBasedResourceGroveler(mediator);
339
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);
344
345                 if (resourceGroveler.HasNeutralResources(culture, defaultResName)) {
346                     FrameworkEventSource.Log.ResourceManagerNeutralResourcesFound(BaseNameField, MainAssembly, defaultResName);
347                 }
348                 else {
349                     FrameworkEventSource.Log.ResourceManagerNeutralResourcesNotFound(BaseNameField, MainAssembly, defaultResName);
350                 }
351             }           
352 #endif
353         }
354     
355         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
356         public ResourceManager(String baseName, Assembly assembly)
357         {
358             if (null==baseName)
359                 throw new ArgumentNullException("baseName");
360
361             if (null==assembly)
362                 throw new ArgumentNullException("assembly");
363             Contract.EndContractBlock();
364
365             if (!(assembly is RuntimeAssembly))
366                 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"));
367
368             MainAssembly = assembly;
369             BaseNameField = baseName;
370
371             SetAppXConfiguration();
372
373             CommonAssemblyInit();
374
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)
381             {
382                 m_callingAssembly = null;
383             }
384         }
385
386         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
387         public ResourceManager(String baseName, Assembly assembly, Type usingResourceSet)
388         {
389             if (null==baseName)
390                 throw new ArgumentNullException("baseName");
391             if (null==assembly)
392                 throw new ArgumentNullException("assembly");
393             Contract.EndContractBlock();
394
395 #if !FEATURE_CORECLR
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());
400 #endif
401
402             if (!(assembly is RuntimeAssembly))
403                 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeAssembly"));
404
405             MainAssembly = assembly;
406             BaseNameField = baseName;
407     
408             if (usingResourceSet != null && (usingResourceSet != _minResourceSet) && !(usingResourceSet.IsSubclassOf(_minResourceSet)))
409                 throw new ArgumentException(Environment.GetResourceString("Arg_ResMgrNotResSet"), "usingResourceSet");
410             _userResourceSet = usingResourceSet;
411
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;
420         }
421         
422         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
423         public ResourceManager(Type resourceSource)
424         {
425             if (null==resourceSource)
426                 throw new ArgumentNullException("resourceSource");
427             Contract.EndContractBlock();
428
429             if (!(resourceSource is RuntimeType))
430                 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"));
431
432             _locationInfo = resourceSource;
433             MainAssembly = _locationInfo.Assembly;
434             BaseNameField = resourceSource.Name;
435             
436             SetAppXConfiguration();
437
438             CommonAssemblyInit();
439
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)
443             {
444                 m_callingAssembly = null;
445             }
446         }
447
448         [OnDeserializing]
449         private void OnDeserializing(StreamingContext ctx)
450         {
451             this._resourceSets = null;
452             this.resourceGroveler = null;
453             this._lastUsedResourceCache = null;
454         }
455
456         [System.Security.SecuritySafeCritical]
457         [OnDeserialized]
458         private void OnDeserialized(StreamingContext ctx)
459         {
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);
465             if (UseManifest)
466             {
467                 resourceGroveler = new ManifestBasedResourceGroveler(mediator);
468             }
469             else
470             {
471                 resourceGroveler = new FileBasedResourceGroveler(mediator);
472             }
473
474             // correct callingAssembly for v2
475             if (this.m_callingAssembly == null)
476             {
477                 this.m_callingAssembly = (RuntimeAssembly)_callingAssembly;
478             }
479
480             // v2 does this lazily
481             if (UseManifest && this._neutralResourcesCulture == null)
482             {
483                 _neutralResourcesCulture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(MainAssembly, ref _fallbackLoc);
484             }
485         }
486
487         [OnSerializing]
488         private void OnSerializing(StreamingContext ctx)
489         {
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
496         }
497       
498
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()
503         {
504             if (_bUsingModernResourceManagement == false)
505             {
506                 UseManifest = true;
507         
508                 _resourceSets = new Dictionary<String,ResourceSet>();
509                 _lastUsedResourceCache = new CultureNameResourceSetPair();
510
511                 _fallbackLoc = UltimateResourceFallbackLocation.MainAssembly;
512
513                 ResourceManagerMediator mediator = new ResourceManagerMediator(this);
514                 resourceGroveler = new ManifestBasedResourceGroveler(mediator);
515             }
516
517             _neutralResourcesCulture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(MainAssembly, ref _fallbackLoc);
518
519 #if !FEATURE_CORECLR   // PAL doesn't support eventing, and we don't compile event providers for coreclr
520             if (_bUsingModernResourceManagement == false)
521             {
522 #if !MONO
523                 if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled()) {
524                     CultureInfo culture = CultureInfo.InvariantCulture;
525                     String defaultResName = GetResourceFileName(culture);
526
527                     if (resourceGroveler.HasNeutralResources(culture, defaultResName)) {
528                         FrameworkEventSource.Log.ResourceManagerNeutralResourcesFound(BaseNameField, MainAssembly, defaultResName);
529                     }
530                     else {
531                         String outputResName = defaultResName;
532                         if (_locationInfo != null && _locationInfo.Namespace != null)
533                             outputResName = _locationInfo.Namespace + Type.Delimiter + defaultResName;
534                         FrameworkEventSource.Log.ResourceManagerNeutralResourcesNotFound(BaseNameField, MainAssembly, outputResName);
535                     }
536                 }
537 #endif
538 #pragma warning disable 618
539                 ResourceSets = new Hashtable(); // for backward compatibility
540 #pragma warning restore 618
541             }
542 #endif
543         }
544
545         // Gets the base name for the ResourceManager.
546         public virtual String BaseName {
547             get { return BaseNameField; }
548         }
549     
550         // Whether we should ignore the capitalization of resources when calling
551         // GetString or GetObject.
552         public virtual bool IgnoreCase {
553             get { return _ignoreCase; }
554             set { _ignoreCase = value; }
555         }
556
557         // Returns the Type of the ResourceSet the ResourceManager uses
558         // to construct ResourceSets.
559         public virtual Type ResourceSetType {
560             get { return (_userResourceSet == null) ? typeof(RuntimeResourceSet) : _userResourceSet; }
561         }
562
563         protected UltimateResourceFallbackLocation FallbackLocation
564         {
565             get { return _fallbackLoc; }
566             set { _fallbackLoc = value; }
567         }
568
569         // Tells the ResourceManager to call Close on all ResourceSets and 
570         // release all resources.  This will shrink your working set by
571         // potentially a substantial amount in a running application.  Any
572         // future resource lookups on this ResourceManager will be as 
573         // expensive as the very first lookup, since it will need to search
574         // for files and load resources again.
575         // 
576         // This may be useful in some complex threading scenarios, where 
577         // creating a new ResourceManager isn't quite the correct behavior.
578         public virtual void ReleaseAllResources()
579         {
580 #if !FEATURE_CORECLR && !MONO
581             if (FrameworkEventSource.IsInitialized)
582             {
583                 FrameworkEventSource.Log.ResourceManagerReleasingResources(BaseNameField, MainAssembly);
584             }
585 #endif
586             Dictionary<String, ResourceSet> localResourceSets = _resourceSets;
587
588             // If any calls to Close throw, at least leave ourselves in a
589             // consistent state.
590             _resourceSets = new Dictionary<String,ResourceSet>();
591             _lastUsedResourceCache = new CultureNameResourceSetPair();
592             
593             lock(localResourceSets) {
594                 IDictionaryEnumerator setEnum = localResourceSets.GetEnumerator();
595
596 #if !FEATURE_CORECLR
597                 IDictionaryEnumerator setEnum2 = null;
598 #pragma warning disable 618
599                 if (ResourceSets != null) {
600                     setEnum2 = ResourceSets.GetEnumerator();
601                 }
602                 ResourceSets = new Hashtable(); // for backwards compat
603 #pragma warning restore 618
604 #endif
605
606                 while (setEnum.MoveNext()) {
607                     ((ResourceSet)setEnum.Value).Close();
608                 }
609
610 #if !FEATURE_CORECLR
611                 if (setEnum2 != null) {
612                     while (setEnum2.MoveNext()) {
613                         ((ResourceSet)setEnum2.Value).Close();
614                     }
615                 }
616 #endif
617             }
618         }
619
620         [ResourceExposure(ResourceScope.Machine)]
621         [ResourceConsumption(ResourceScope.Machine)]
622         public static ResourceManager CreateFileBasedResourceManager(String baseName, String resourceDir, Type usingResourceSet)
623         {
624             return new ResourceManager(baseName, resourceDir, usingResourceSet);
625         }
626       
627         // Given a CultureInfo, GetResourceFileName generates the name for 
628         // the binary file for the given CultureInfo.  This method uses 
629         // CultureInfo's Name property as part of the file name for all cultures
630         // other than the invariant culture.  This method does not touch the disk, 
631         // and is used only to construct what a resource file name (suitable for
632         // passing to the ResourceReader constructor) or a manifest resource file
633         // name should look like.
634         // 
635         // This method can be overriden to look for a different extension,
636         // such as ".ResX", or a completely different format for naming files.
637         protected virtual String GetResourceFileName(CultureInfo culture) {
638             StringBuilder sb = new StringBuilder(255);
639             sb.Append(BaseNameField);
640             // If this is the neutral culture, don't append culture name.
641             if (!culture.HasInvariantCultureName)
642             {
643                 CultureInfo.VerifyCultureName(culture.Name, true);
644                 sb.Append('.');
645                 sb.Append(culture.Name);
646             }
647             sb.Append(ResFileExtension);
648             return sb.ToString();
649         }
650
651         // WARNING: This function must be kept in [....] with ResourceFallbackManager.GetEnumerator()
652         // Return the first ResourceSet, based on the first culture ResourceFallbackManager would return
653         internal ResourceSet GetFirstResourceSet(CultureInfo culture)
654         {
655             // Logic from ResourceFallbackManager.GetEnumerator()
656             if (_neutralResourcesCulture != null && culture.Name == _neutralResourcesCulture.Name) 
657             {
658                 culture = CultureInfo.InvariantCulture;
659             }
660
661             if(_lastUsedResourceCache != null) {
662                 lock (_lastUsedResourceCache) {
663                     if (culture.Name == _lastUsedResourceCache.lastCultureName)
664                         return _lastUsedResourceCache.lastResourceSet;
665                 }
666             }
667
668             // Look in the ResourceSet table
669             Dictionary<String,ResourceSet> localResourceSets = _resourceSets;
670             ResourceSet rs = null;
671             if (localResourceSets != null) 
672             {
673                 lock (localResourceSets) 
674                 {
675                     localResourceSets.TryGetValue(culture.Name, out rs);
676                 }
677             }
678
679             if (rs != null)
680             {
681                 // update the cache with the most recent ResourceSet
682                 if (_lastUsedResourceCache != null) {
683                     lock (_lastUsedResourceCache) {
684                         _lastUsedResourceCache.lastCultureName = culture.Name;
685                         _lastUsedResourceCache.lastResourceSet = rs;
686                     }
687                 }
688                 return rs;
689             }
690
691             return null;
692         }
693         
694         // Looks up a set of resources for a particular CultureInfo.  This is
695         // not useful for most users of the ResourceManager - call 
696         // GetString() or GetObject() instead.  
697         //
698         // The parameters let you control whether the ResourceSet is created 
699         // if it hasn't yet been loaded and if parent CultureInfos should be 
700         // loaded as well for resource inheritance.
701         //         
702         [System.Security.SecuritySafeCritical]  // auto-generated
703         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
704         public virtual ResourceSet GetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents) {
705             if (null==culture)
706                 throw new ArgumentNullException("culture");
707             Contract.EndContractBlock();
708
709             Dictionary<String,ResourceSet> localResourceSets = _resourceSets;
710             ResourceSet rs;
711             if (localResourceSets != null) {
712                 lock (localResourceSets) {
713                     if (localResourceSets.TryGetValue(culture.Name, out rs))
714                         return rs;
715                 }
716             }
717
718             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
719
720             if (UseManifest && culture.HasInvariantCultureName) {
721                 string fileName = GetResourceFileName(culture);
722                 RuntimeAssembly mainAssembly = (RuntimeAssembly)MainAssembly;
723                 Stream stream = mainAssembly.GetManifestResourceStream(_locationInfo, fileName, m_callingAssembly == MainAssembly, ref stackMark);
724                 if (createIfNotExists && stream!=null) {
725                     rs = ((ManifestBasedResourceGroveler)resourceGroveler).CreateResourceSet(stream, MainAssembly);
726                     AddResourceSet(localResourceSets, culture.Name, ref rs);                    
727                     return rs;
728                 }
729             }
730
731             // Note: ideally we could plumb through the stack crawl mark here, but we must
732             // call the virtual 3-argument InternalGetResourceSet method for compatibility.
733             // Security-wise, we're not overly interested in protecting access to resources,
734             // since full-trust callers can get them already and most resources are public.
735             // Also, the JIT inliner could always inline a caller into another assembly's
736             // method, so the entire idea of a security check written this way is ----.
737             // So if we happen to return some resources in cases where we should really be
738             // doing a demand for member access permissions, we're not overly concerned.
739             // <
740             return InternalGetResourceSet(culture, createIfNotExists, tryParents);
741         }
742
743         // InternalGetResourceSet is a non-threadsafe method where all the logic
744         // for getting a resource set lives.  Access to it is controlled by
745         // threadsafe methods such as GetResourceSet, GetString, & GetObject.  
746         // This will take a minimal number of locks.
747         [System.Security.SecuritySafeCritical]  // auto-generated
748         [ResourceExposure(ResourceScope.None)]
749         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
750         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
751         protected virtual ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents) 
752         {
753             Contract.Assert(culture != null, "culture != null");
754
755             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
756             return InternalGetResourceSet(culture,createIfNotExists,tryParents, ref stackMark);
757         }
758
759         // InternalGetResourceSet is a non-threadsafe method where all the logic
760         // for getting a resource set lives.  Access to it is controlled by
761         // threadsafe methods such as GetResourceSet, GetString, & GetObject.  
762         // This will take a minimal number of locks.
763         [System.Security.SecurityCritical]
764         [ResourceExposure(ResourceScope.None)]
765         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
766         private ResourceSet InternalGetResourceSet(CultureInfo requestedCulture, bool createIfNotExists, bool tryParents, ref StackCrawlMark stackMark)
767         {
768             Dictionary<String, ResourceSet> localResourceSets = _resourceSets;
769             ResourceSet rs = null;
770             CultureInfo foundCulture = null;
771             lock (localResourceSets) {
772                 if (localResourceSets.TryGetValue(requestedCulture.Name, out rs)) {
773 #if !FEATURE_CORECLR && !MONO
774                     if (FrameworkEventSource.IsInitialized) {
775                         FrameworkEventSource.Log.ResourceManagerFoundResourceSetInCache(BaseNameField, MainAssembly, requestedCulture.Name);
776                     }
777 #endif
778                     return rs;
779                 }
780             }
781
782             ResourceFallbackManager mgr = new ResourceFallbackManager(requestedCulture, _neutralResourcesCulture, tryParents);
783
784             foreach (CultureInfo currentCultureInfo in mgr)
785             {
786 #if !FEATURE_CORECLR && !MONO
787                 if (FrameworkEventSource.IsInitialized)
788                 {
789                     FrameworkEventSource.Log.ResourceManagerLookingForResourceSet(BaseNameField, MainAssembly, currentCultureInfo.Name);
790                 }
791 #endif
792                 lock(localResourceSets) {
793                     if (localResourceSets.TryGetValue(currentCultureInfo.Name, out rs)) {
794 #if !FEATURE_CORECLR && !MONO
795                         if (FrameworkEventSource.IsInitialized)
796                         {
797                             FrameworkEventSource.Log.ResourceManagerFoundResourceSetInCache(BaseNameField, MainAssembly, currentCultureInfo.Name);
798                         }
799 #endif
800                         // we need to update the cache if we fellback
801                         if(requestedCulture != currentCultureInfo) foundCulture = currentCultureInfo;
802                         break;
803                     }
804                 }
805
806                 // InternalGetResourceSet will never be threadsafe.  However, it must
807                 // be protected against reentrancy from the SAME THREAD.  (ie, calling
808                 // GetSatelliteAssembly may send some window messages or trigger the
809                 // Assembly load event, which could fail then call back into the 
810                 // ResourceManager).  It's happened.
811
812                 rs = resourceGroveler.GrovelForResourceSet(currentCultureInfo, localResourceSets, 
813                                                            tryParents, createIfNotExists, ref stackMark);
814
815                 // found a ResourceSet; we're done
816                 if (rs != null)
817                 {
818                     foundCulture = currentCultureInfo;
819                     break;
820                 }
821
822             }
823
824             if (rs != null && foundCulture != null)
825             {
826                 // add entries to the cache for the cultures we have gone through
827
828                 // currentCultureInfo now refers to the culture that had resources.
829                 // update cultures starting from requested culture up to the culture
830                 // that had resources.
831                 foreach (CultureInfo updateCultureInfo in mgr)
832                 {
833                     AddResourceSet(localResourceSets, updateCultureInfo.Name, ref rs);
834
835                     // stop when we've added current or reached invariant (top of chain)
836                     if (updateCultureInfo == foundCulture)
837                     {
838                         break;
839                     }
840                 } 
841             }
842
843             return rs;
844         }
845
846         // Simple helper to ease maintenance and improve readability.
847         private static void AddResourceSet(Dictionary<String,ResourceSet> localResourceSets, String cultureName, ref ResourceSet rs)
848         {
849             // InternalGetResourceSet is both recursive and reentrant - 
850             // assembly load callbacks in particular are a way we can call
851             // back into the ResourceManager in unexpectedly on the same thread.
852             lock(localResourceSets) {
853                 // If another thread added this culture, return that.
854                 ResourceSet lostRace;
855                 if (localResourceSets.TryGetValue(cultureName, out lostRace)) {
856                     if (!Object.ReferenceEquals(lostRace, rs)) {
857                         // Note: In certain cases, we can be trying to add a ResourceSet for multiple
858                         // cultures on one thread, while a second thread added another ResourceSet for one
859                         // of those cultures.  So when we lose the ----, we must make sure our ResourceSet 
860                         // isn't in our dictionary before closing it.
861                         if (!localResourceSets.ContainsValue(rs))
862                             rs.Dispose();
863                         rs = lostRace;
864                     }
865                 }
866                 else {
867                     localResourceSets.Add(cultureName, rs);
868                 }
869             }
870         }
871
872         protected static Version GetSatelliteContractVersion(Assembly a)
873         {
874             // Ensure that the assembly reference is not null
875             if (a == null) {
876                 throw new ArgumentNullException("a", Environment.GetResourceString("ArgumentNull_Assembly"));
877             }
878             Contract.EndContractBlock();
879
880 #if !FEATURE_WINDOWSPHONE
881             String v = null;
882             if (a.ReflectionOnly) {
883                 foreach (CustomAttributeData data in CustomAttributeData.GetCustomAttributes(a)) {
884                     if (data.Constructor.DeclaringType == typeof(SatelliteContractVersionAttribute)) {
885                         v = (String)data.ConstructorArguments[0].Value;
886                         break;
887                     }
888                 }
889
890                 if (v == null)
891                     return null;
892             }
893             else {
894                 Object[] attrs = a.GetCustomAttributes(typeof(SatelliteContractVersionAttribute), false);
895                 if (attrs.Length == 0)
896                     return null;
897                 Contract.Assert(attrs.Length == 1, "Cannot have multiple instances of SatelliteContractVersionAttribute on an assembly!");
898                 v = ((SatelliteContractVersionAttribute)attrs[0]).Version;
899             }
900             Version ver;
901             try {
902                 ver = new Version(v);
903             }
904             catch(ArgumentOutOfRangeException e) {
905                 // Note we are prone to hitting infinite loops if mscorlib's
906                 // SatelliteContractVersionAttribute contains bogus values.
907                 // If this assert fires, please fix the build process for the
908                 // BCL directory.
909                 if (a == typeof(Object).Assembly) {
910                     Contract.Assert(false, "mscorlib's SatelliteContractVersionAttribute is a malformed version string!");
911                     return null;
912                 }
913
914                 throw new ArgumentException(Environment.GetResourceString("Arg_InvalidSatelliteContract_Asm_Ver", a.ToString(), v), e);
915             }
916             return ver;
917 #else
918             // On the phone return null. The calling code will use the assembly version instead to avoid potential type
919             // and library loads caused by CA lookup. NetCF uses the assembly version always.
920             return null;
921 #endif
922         }
923
924         [System.Security.SecuritySafeCritical]  // auto-generated
925         protected static CultureInfo GetNeutralResourcesLanguage(Assembly a)
926         {
927             // This method should be obsolete - replace it with the one below.
928             // Unfortunately, we made it protected.
929             UltimateResourceFallbackLocation ignoringUsefulData = UltimateResourceFallbackLocation.MainAssembly;
930             CultureInfo culture = ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(a, ref ignoringUsefulData);
931             return culture;
932         }
933
934         // IGNORES VERSION
935         internal static bool CompareNames(String asmTypeName1,
936                                           String typeName2, 
937                                           AssemblyName asmName2)
938         {
939             Contract.Assert(asmTypeName1 != null, "asmTypeName1 was unexpectedly null");
940
941             // First, compare type names
942             int comma = asmTypeName1.IndexOf(',');
943             if (((comma == -1) ? asmTypeName1.Length : comma) != typeName2.Length)
944                 return false;
945
946             // case sensitive
947             if (String.Compare(asmTypeName1, 0, typeName2, 0, typeName2.Length, StringComparison.Ordinal) != 0)
948                 return false;
949             if (comma == -1)
950                 return true;
951
952             // Now, compare assembly display names (IGNORES VERSION AND PROCESSORARCHITECTURE)
953             // also, for  mscorlib ignores everything, since that's what the binder is going to do
954             while(Char.IsWhiteSpace(asmTypeName1[++comma]));
955
956             // case insensitive
957             AssemblyName an1 = new AssemblyName(asmTypeName1.Substring(comma));
958             if (String.Compare(an1.Name, asmName2.Name, StringComparison.OrdinalIgnoreCase) != 0)
959                 return false;
960
961             // to match IsMscorlib() in VM
962             if (String.Compare(an1.Name, "mscorlib", StringComparison.OrdinalIgnoreCase) == 0)
963                 return true;
964
965
966             if ((an1.CultureInfo != null) && (asmName2.CultureInfo != null) &&
967 #if FEATURE_USE_LCID                
968                 (an1.CultureInfo.LCID != asmName2.CultureInfo.LCID)
969 #else
970                 (an1.CultureInfo.Name != asmName2.CultureInfo.Name)
971 #endif                
972                 )
973                 return false;
974
975             byte[] pkt1 = an1.GetPublicKeyToken();
976             byte[] pkt2 = asmName2.GetPublicKeyToken();
977             if ((pkt1 != null) && (pkt2 != null)) {
978                 if (pkt1.Length != pkt2.Length)
979                     return false;
980
981                 for(int i=0; i < pkt1.Length; i++) {
982                     if(pkt1[i] != pkt2[i])
983                         return false;
984                 }
985             }
986
987             return true;
988         }
989
990 #if FEATURE_APPX
991         [SecuritySafeCritical]
992         // Throws WinRT hresults
993         private string GetStringFromPRI(String stringName, String startingCulture, String neutralResourcesCulture) {
994             Contract.Assert(_bUsingModernResourceManagement);
995             Contract.Assert(_WinRTResourceManager != null);
996             Contract.Assert(_PRIonAppXInitialized);
997             Contract.Assert(AppDomain.IsAppXModel());
998         
999             if (stringName.Length == 0)
1000                 return null;
1001             
1002             string resourceString = null;
1003
1004             // Do not handle exceptions. See the comment in SetAppXConfiguration about throwing
1005             // exception types that the ResourceManager class is not documented to throw.
1006             resourceString = _WinRTResourceManager.GetString(
1007                                        stringName,
1008                                        String.IsNullOrEmpty(startingCulture) ? null : startingCulture,
1009                                        String.IsNullOrEmpty(neutralResourcesCulture) ? null : neutralResourcesCulture);
1010             
1011             return resourceString;
1012         }
1013
1014         // Since we can't directly reference System.Runtime.WindowsRuntime from mscorlib, we have to get the type via reflection.
1015         // It would be better if we could just implement WindowsRuntimeResourceManager in mscorlib, but we can't, because
1016         // we can do very little with WinRT in mscorlib.
1017         [SecurityCritical]
1018         internal static WindowsRuntimeResourceManagerBase GetWinRTResourceManager()
1019         {
1020             Type WinRTResourceManagerType = Type.GetType("System.Resources.WindowsRuntimeResourceManager, " + AssemblyRef.SystemRuntimeWindowsRuntime, true);
1021             return (WindowsRuntimeResourceManagerBase)Activator.CreateInstance(WinRTResourceManagerType, true);
1022         }
1023 #endif
1024
1025         [NonSerialized]
1026         private bool _bUsingModernResourceManagement; // Written only by SetAppXConfiguration
1027
1028 #if FEATURE_APPX
1029         [NonSerialized]
1030         [SecurityCritical]
1031         private WindowsRuntimeResourceManagerBase _WinRTResourceManager; // Written only by SetAppXConfiguration
1032
1033         [NonSerialized]
1034         private bool _PRIonAppXInitialized; // Written only by SetAppXConfiguration
1035
1036         [NonSerialized]
1037         private PRIExceptionInfo _PRIExceptionInfo; // Written only by SetAppXConfiguration
1038
1039         // When running under AppX, the following rules apply for resource lookup:
1040         //
1041         // Desktop
1042         // -------
1043         //
1044         // 1) For Framework assemblies, we always use satellite assembly based lookup.
1045         // 2) For non-FX assemblies, we use modern resource manager, with the premise being that app package
1046         //    contains the PRI resources since such assemblies are expected to be application assemblies.
1047         //
1048         // CoreCLR
1049         // -------
1050         //
1051         // 1) For Framework assemblies, we always use satellite assembly based lookup.
1052         // 2) For non-FX assemblies:
1053         //    
1054         //    a) If the assembly lives under PLATFORM_RESOURCE_ROOTS (as specified by the host during AppDomain creation),
1055         //       then we will use satellite assembly based lookup in assemblies like *.resources.dll.
1056         //   
1057         //    b) For any other non-FX assembly, we will use the modern resource manager with the premise that app package
1058         //       contains the PRI resources.
1059         [SecuritySafeCritical]
1060         private bool ShouldUseSatelliteAssemblyResourceLookupUnderAppX(RuntimeAssembly resourcesAssembly)
1061         {
1062             bool fUseSatelliteAssemblyResourceLookupUnderAppX = resourcesAssembly.IsFrameworkAssembly();
1063             
1064 #if FEATURE_CORECLR     
1065             if (!fUseSatelliteAssemblyResourceLookupUnderAppX)
1066             {
1067                 // Check to see if the assembly is under PLATFORM_RESOURCE_ROOTS. If it is, then we should use satellite assembly lookup for it.
1068                 String platformResourceRoots = (String)(AppDomain.CurrentDomain.GetData("PLATFORM_RESOURCE_ROOTS"));
1069                 if ((platformResourceRoots != null) && (platformResourceRoots != String.Empty))
1070                 {
1071                     string resourceAssemblyPath = resourcesAssembly.Location;
1072                     
1073                     // Loop through the PLATFORM_RESOURCE_ROOTS and see if the assembly is contained in it.
1074                     foreach(string pathPlatformResourceRoot in platformResourceRoots.Split(Path.PathSeparator))
1075                     {
1076                         if (resourceAssemblyPath.StartsWith(pathPlatformResourceRoot, StringComparison.CurrentCultureIgnoreCase))
1077                         {
1078                             // Found the resource assembly to be present in one of the PLATFORM_RESOURCE_ROOT, so stop the enumeration loop.
1079                             fUseSatelliteAssemblyResourceLookupUnderAppX = true;
1080                             break;
1081                         }
1082                     }
1083                 }
1084             }
1085 #endif // FEATURE_CORECLR
1086             return fUseSatelliteAssemblyResourceLookupUnderAppX;
1087             
1088         }
1089         
1090         [SecuritySafeCritical]
1091 #endif // FEATURE_APPX
1092         // Only call SetAppXConfiguration from ResourceManager constructors, and nowhere else.
1093         // Throws MissingManifestResourceException and WinRT HResults
1094
1095         private void SetAppXConfiguration()
1096         {
1097             Contract.Assert(_bUsingModernResourceManagement == false); // Only this function writes to this member
1098 #if FEATURE_APPX
1099             Contract.Assert(_WinRTResourceManager == null); // Only this function writes to this member
1100             Contract.Assert(_PRIonAppXInitialized == false); // Only this function writes to this member
1101             Contract.Assert(_PRIExceptionInfo == null); // Only this function writes to this member
1102
1103             bool bUsingSatelliteAssembliesUnderAppX = false;
1104
1105             RuntimeAssembly resourcesAssembly = (RuntimeAssembly)MainAssembly;
1106
1107             if (resourcesAssembly == null)
1108                 resourcesAssembly = m_callingAssembly;
1109
1110             if (resourcesAssembly != null)
1111             {
1112                 if (resourcesAssembly != typeof(Object).Assembly) // We are not loading resources for mscorlib
1113                 {
1114                     // Cannot load the WindowsRuntimeResourceManager when in a compilation process, since it
1115                     // lives in System.Runtime.WindowsRuntime and only mscorlib may be loaded for execution.
1116                     if (AppDomain.IsAppXModel() && !AppDomain.IsAppXNGen)
1117                     {
1118                         s_IsAppXModel = true;
1119
1120                         // If we have the type information from the ResourceManager(Type) constructor, we use it. Otherwise, we use BaseNameField.
1121                         String reswFilename = _locationInfo == null ? BaseNameField : _locationInfo.FullName;
1122
1123                         // The only way this can happen is if a class inherited from ResourceManager and
1124                         // did not set the BaseNameField before calling the protected ResourceManager() constructor.
1125                         // For other constructors, we would already have thrown an ArgumentNullException by now.
1126                         // Throwing an ArgumentNullException now is not the right thing to do because technically
1127                         // ResourceManager() takes no arguments, and because it is not documented as throwing
1128                         // any exceptions. Instead, let's go through the rest of the initialization with this set to
1129                         // an empty string. We may in fact fail earlier for another reason, but otherwise we will
1130                         // throw a MissingManifestResourceException when GetString is called indicating that a
1131                         // resW filename called "" could not be found.
1132                         if (reswFilename == null)
1133                             reswFilename = String.Empty;
1134
1135                         WindowsRuntimeResourceManagerBase WRRM = null;
1136                         bool bWRRM_Initialized = false;
1137                         
1138                         if (AppDomain.IsAppXDesignMode())
1139                         {
1140                             WRRM = GetWinRTResourceManager();
1141                             try {
1142                                 PRIExceptionInfo exceptionInfo; // If the exception info is filled in, we will ignore it.
1143                                 bWRRM_Initialized = WRRM.Initialize(resourcesAssembly.Location, reswFilename, out exceptionInfo);
1144                                 bUsingSatelliteAssembliesUnderAppX = !bWRRM_Initialized;
1145                             }
1146                             catch(Exception e)
1147                             {
1148                                 bUsingSatelliteAssembliesUnderAppX = true;
1149                                 if (e.IsTransient)
1150                                     throw;
1151                             }
1152                         }
1153
1154                         if (!bUsingSatelliteAssembliesUnderAppX)
1155                         {
1156                             // See AssemblyNative::IsFrameworkAssembly for details on which kinds of assemblies are considered Framework assemblies.
1157                             // The Modern Resource Manager is not used for such assemblies - they continue to use satellite assemblies (i.e. .resources.dll files).
1158                             _bUsingModernResourceManagement = !ShouldUseSatelliteAssemblyResourceLookupUnderAppX(resourcesAssembly); 
1159
1160                             if (_bUsingModernResourceManagement)
1161                             {
1162                                 // Only now are we certain that we need the PRI file.
1163
1164                                 // Note that if IsAppXDesignMode is false, we haven't checked if the PRI file exists.
1165                                 // This is by design. We will find out in the call to WindowsRuntimeResourceManager.Initialize below.
1166
1167                                 // At this point it is important NOT to set _bUsingModernResourceManagement to false
1168                                 // if the PRI file does not exist because we are now certain we need to load PRI
1169                                 // resources. We want to fail by throwing a MissingManifestResourceException
1170                                 // if WindowsRuntimeResourceManager.Initialize fails to locate the PRI file. We do not
1171                                 // want to fall back to using satellite assemblies anymore. Note that we would not throw
1172                                 // the MissingManifestResourceException from this function, but from GetString. See the
1173                                 // comment below on the reason for this.
1174
1175                                 if (WRRM != null && bWRRM_Initialized)
1176                                 {
1177                                     // Reuse the one successfully created earlier
1178                                     _WinRTResourceManager = WRRM;
1179                                     _PRIonAppXInitialized = true;
1180                                 }
1181                                 else 
1182                                 {
1183                                     _WinRTResourceManager = GetWinRTResourceManager();
1184                                     
1185                                     try {
1186                                         _PRIonAppXInitialized = _WinRTResourceManager.Initialize(resourcesAssembly.Location, reswFilename, out _PRIExceptionInfo);
1187
1188                                         // Note that _PRIExceptionInfo might be null - this is OK.
1189                                         // In that case we will just throw the generic
1190                                         // MissingManifestResource_NoPRIresources exception.
1191                                         // See the implementation of GetString for more details.
1192                                     }
1193                                     // We would like to be able to throw a MissingManifestResourceException here if PRI resources
1194                                     // could not be loaded for a recognized reason. However, the ResourceManager constructors
1195                                     // that call SetAppXConfiguration are not documented as throwing MissingManifestResourceException,
1196                                     // and since they are part of the portable profile, we cannot start throwing a new exception type
1197                                     // as that would break existing portable libraries. Hence we must save the exception information
1198                                     // now and throw the exception on the first call to GetString.
1199                                     catch(FileNotFoundException)
1200                                     {
1201                                         // We will throw MissingManifestResource_NoPRIresources from GetString
1202                                         // when we see that _PRIonAppXInitialized is false.
1203                                     }
1204                                     catch(Exception e)
1205                                     {
1206                                         // ERROR_MRM_MAP_NOT_FOUND can be thrown by the call to ResourceManager.get_AllResourceMaps
1207                                         // in WindowsRuntimeResourceManager.Initialize.
1208                                         // In this case _PRIExceptionInfo is now null and we will just throw the generic
1209                                         // MissingManifestResource_NoPRIresources exception.
1210                                         // See the implementation of GetString for more details.
1211                                         if (e.HResult != __HResults.ERROR_MRM_MAP_NOT_FOUND)
1212                                             throw; // Unexpected exception code. Bubble it up to the caller.
1213                                     }
1214                                     // Allow all other exception types to bubble up to the caller.
1215
1216                                     // Yes, this causes us to potentially throw exception types that are not documented.
1217
1218                                     // Ultimately the tradeoff is the following:
1219                                     // -We could ignore unknown exceptions or rethrow them as inner exceptions
1220                                     // of exceptions that the ResourceManager class is already documented as throwing.
1221                                     // This would allow existing portable libraries to gracefully recover if they don't care
1222                                     // too much about the ResourceManager object they are using. However it could
1223                                     // mask potentially fatal errors that we are not aware of, such as a disk drive failing.
1224
1225
1226                                     // The alternative, which we chose, is to throw unknown exceptions. This may tear
1227                                     // down the process if the portable library and app don't expect this exception type.
1228                                     // On the other hand, this won't mask potentially fatal errors we don't know about.
1229                                 }
1230                             }
1231                         }
1232                     }
1233                 }
1234             }
1235             // resourcesAssembly == null should not happen but it can. See the comment on Assembly.GetCallingAssembly.
1236             // However for the sake of 100% backwards compatibility on Win7 and below, we must leave
1237             // _bUsingModernResourceManagement as false.
1238 #endif // FEATURE_APPX            
1239         }
1240
1241         // Looks up a resource value for a particular name.  Looks in the 
1242         // current thread's CultureInfo, and if not found, all parent CultureInfos.
1243         // Returns null if the resource wasn't found.
1244         // 
1245         public virtual String GetString(String name) {
1246             return GetString(name, (CultureInfo)null);
1247         }
1248         
1249         // Looks up a resource value for a particular name.  Looks in the 
1250         // specified CultureInfo, and if not found, all parent CultureInfos.
1251         // Returns null if the resource wasn't found.
1252         // 
1253         public virtual String GetString(String name, CultureInfo culture) {
1254             if (null==name)
1255                 throw new ArgumentNullException("name");
1256             Contract.EndContractBlock();
1257
1258 #if FEATURE_APPX
1259             if(s_IsAppXModel)
1260             {
1261                  // If the caller explictily passed in a culture that was obtained by calling CultureInfo.CurrentUICulture,
1262                  // null it out, so that we re-compute it.  If we use modern resource lookup, we may end up getting a "better"
1263                  // match, since CultureInfo objects can't represent all the different languages the AppX resource model supports.
1264                  // For classic resources, this causes us to ignore the languages list and instead use the older Win32 behavior,
1265                  // which is the design choice we've made. (See the call a little later to GetCurrentUICultureNoAppX()).
1266                  if(Object.ReferenceEquals(culture, CultureInfo.CurrentUICulture))
1267                  {
1268                      culture = null;
1269                  }              
1270             }
1271
1272             if (_bUsingModernResourceManagement)
1273             {
1274                 if (_PRIonAppXInitialized == false)
1275                 {
1276                     // Always throw if we did not fully succeed in initializing the WinRT Resource Manager.
1277
1278                     if (_PRIExceptionInfo != null && _PRIExceptionInfo._PackageSimpleName != null && _PRIExceptionInfo._ResWFile != null)
1279                         throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_ResWFileNotLoaded", _PRIExceptionInfo._ResWFile, _PRIExceptionInfo._PackageSimpleName));
1280
1281                     throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoPRIresources"));
1282                 }
1283             
1284                 // Throws WinRT hresults.
1285                 return GetStringFromPRI(name,
1286                                         culture == null ? null : culture.Name,
1287                                         _neutralResourcesCulture.Name);
1288             }
1289             else
1290 #endif // FEATURE_APPX
1291             {
1292                 if (null==culture) {
1293                     // When running inside AppX we want to ignore the languages list when trying to come up with our CurrentUICulture.
1294                     // This line behaves the same way as CultureInfo.CurrentUICulture would have in .NET 4
1295                     culture = Thread.CurrentThread.GetCurrentUICultureNoAppX();
1296                 }
1297     
1298 #if !FEATURE_CORECLR && !MONO
1299                 if (FrameworkEventSource.IsInitialized)
1300                 {
1301                     FrameworkEventSource.Log.ResourceManagerLookupStarted(BaseNameField, MainAssembly, culture.Name);
1302                 }
1303 #endif
1304                 ResourceSet last = GetFirstResourceSet(culture);
1305
1306                 if (last != null)
1307                 {
1308                     String value = last.GetString(name, _ignoreCase);
1309                     if (value != null)
1310                         return value;
1311                 }
1312                 
1313                 
1314                 // This is the CultureInfo hierarchy traversal code for resource 
1315                 // lookups, similar but necessarily orthogonal to the ResourceSet 
1316                 // lookup logic.
1317                 ResourceFallbackManager mgr = new ResourceFallbackManager(culture, _neutralResourcesCulture, true);
1318                 foreach (CultureInfo currentCultureInfo in mgr) {
1319
1320                     ResourceSet rs = InternalGetResourceSet(currentCultureInfo, true, true);
1321                     if (rs == null)
1322                         break;
1323
1324                     if (rs != last) {
1325                         String value = rs.GetString(name, _ignoreCase);
1326                         if (value != null)
1327                         {
1328                             // update last used ResourceSet
1329                             if (_lastUsedResourceCache != null) {
1330                                 lock (_lastUsedResourceCache) {
1331                                     _lastUsedResourceCache.lastCultureName = currentCultureInfo.Name;
1332                                     _lastUsedResourceCache.lastResourceSet = rs;
1333                                 }
1334                             }
1335                             return value;
1336                         }
1337
1338                         last = rs;
1339                     }
1340                 }
1341
1342 #if !FEATURE_CORECLR && !MONO
1343                 if (FrameworkEventSource.IsInitialized)
1344                 {
1345                     FrameworkEventSource.Log.ResourceManagerLookupFailed(BaseNameField, MainAssembly, culture.Name);
1346                 }
1347 #endif
1348             }
1349
1350             return null;
1351         }
1352         
1353         
1354         // Looks up a resource value for a particular name.  Looks in the 
1355         // current thread's CultureInfo, and if not found, all parent CultureInfos.
1356         // Returns null if the resource wasn't found.
1357         // 
1358         public virtual Object GetObject(String name) {
1359             return GetObject(name, (CultureInfo)null, true);
1360         }
1361         
1362         // Looks up a resource value for a particular name.  Looks in the 
1363         // specified CultureInfo, and if not found, all parent CultureInfos.
1364         // Returns null if the resource wasn't found.
1365         public virtual Object GetObject(String name, CultureInfo culture) {
1366             return GetObject(name, culture, true);
1367         }
1368
1369         private Object GetObject(String name, CultureInfo culture, bool wrapUnmanagedMemStream)
1370         {
1371             if (null==name)
1372                 throw new ArgumentNullException("name");
1373             Contract.EndContractBlock();
1374
1375 #if FEATURE_APPX
1376             if(s_IsAppXModel)
1377             {
1378                  // If the caller explictily passed in a culture that was obtained by calling CultureInfo.CurrentUICulture,
1379                  // null it out, so that we re-compute it based on the Win32 value and not the AppX language list value.
1380                  // (See the call a little later to GetCurrentUICultureNoAppX()).
1381                  if(Object.ReferenceEquals(culture, CultureInfo.CurrentUICulture))
1382                  {
1383                      culture = null;
1384                  }              
1385             }
1386 #endif
1387
1388             if (null==culture) {
1389                 // When running inside AppX we want to ignore the languages list when trying to come up with our CurrentUICulture.
1390                 // This line behaves the same way as CultureInfo.CurrentUICulture would have in .NET 4
1391                 culture = Thread.CurrentThread.GetCurrentUICultureNoAppX();
1392             }
1393
1394 #if !FEATURE_CORECLR && !MONO
1395             if (FrameworkEventSource.IsInitialized)
1396             {
1397                 FrameworkEventSource.Log.ResourceManagerLookupStarted(BaseNameField, MainAssembly, culture.Name);
1398             }
1399 #endif
1400             ResourceSet last = GetFirstResourceSet(culture);
1401             if (last != null)
1402             {
1403                 Object value = last.GetObject(name, _ignoreCase);
1404
1405                 if (value != null) 
1406                 {
1407                     UnmanagedMemoryStream stream = value as UnmanagedMemoryStream;
1408                     if (stream != null && wrapUnmanagedMemStream)
1409                         return new UnmanagedMemoryStreamWrapper(stream);
1410                     else
1411                         return value;
1412                 }
1413             }
1414             
1415             // This is the CultureInfo hierarchy traversal code for resource 
1416             // lookups, similar but necessarily orthogonal to the ResourceSet 
1417             // lookup logic.
1418             ResourceFallbackManager mgr = new ResourceFallbackManager(culture, _neutralResourcesCulture, true);
1419             
1420             foreach (CultureInfo currentCultureInfo in mgr) {
1421                 // Note: Technically this method should be passed in a stack crawl mark that we then pass
1422                 // to InternalGetResourceSet for ensuring we demand permissions to read your private resources
1423                 // if you're reading resources from an assembly other than yourself.  But, we must call our
1424                 // three argument overload (without the stack crawl mark) for compatibility.  After 
1425                 // consideration, we aren't worried about the security impact.
1426                 ResourceSet rs = InternalGetResourceSet(currentCultureInfo, true, true);
1427                 if (rs == null)
1428                     break;
1429
1430                 if (rs != last) {
1431                     Object value = rs.GetObject(name, _ignoreCase);
1432                     if (value != null) {
1433                         // update the last used ResourceSet
1434                         if (_lastUsedResourceCache != null) {
1435                             lock (_lastUsedResourceCache) {
1436                                 _lastUsedResourceCache.lastCultureName = currentCultureInfo.Name;
1437                                 _lastUsedResourceCache.lastResourceSet = rs;
1438                             }
1439                         }
1440
1441                         UnmanagedMemoryStream stream = value as UnmanagedMemoryStream;
1442                         if (stream != null && wrapUnmanagedMemStream)
1443                             return new UnmanagedMemoryStreamWrapper(stream);
1444                         else
1445                             return value;
1446                     }
1447
1448                     last = rs;
1449                 }
1450             }
1451
1452 #if !FEATURE_CORECLR && !MONO
1453             if (FrameworkEventSource.IsInitialized)
1454             {
1455                 FrameworkEventSource.Log.ResourceManagerLookupFailed(BaseNameField, MainAssembly, culture.Name);
1456             }
1457 #endif
1458             return null;
1459         }
1460
1461         [ComVisible(false)]
1462         public UnmanagedMemoryStream GetStream(String name) {
1463             return GetStream(name, (CultureInfo)null);
1464         }
1465         
1466         [ComVisible(false)]
1467         public UnmanagedMemoryStream GetStream(String name, CultureInfo culture) {
1468             Object obj = GetObject(name, culture, false);
1469             UnmanagedMemoryStream ums = obj as UnmanagedMemoryStream;
1470             if (ums == null && obj != null)
1471                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotStream_Name", name));
1472             return ums;
1473         }
1474
1475 #if RESOURCE_SATELLITE_CONFIG
1476         // Internal helper method - gives an end user the ability to prevent
1477         // satellite assembly probes for certain cultures via a config file.
1478         [System.Security.SecurityCritical]  // auto-generated
1479         private bool TryLookingForSatellite(CultureInfo lookForCulture)
1480         {
1481             if (!_checkedConfigFile) {
1482                 lock (this) {
1483                     if (!_checkedConfigFile) {
1484                         _checkedConfigFile = true;
1485                         _installedSatelliteInfo = GetSatelliteAssembliesFromConfig();
1486                     }
1487                 }
1488             }
1489
1490             if (_installedSatelliteInfo == null)
1491                 return true;
1492
1493             String[] installedSatellites = (String[]) _installedSatelliteInfo[MainAssembly.FullName];
1494
1495             if (installedSatellites == null)
1496                 return true;
1497
1498             // The config file told us what satellites might be installed.
1499             int pos = Array.IndexOf(installedSatellites, lookForCulture.Name);
1500
1501 #if !FEATURE_CORECLR && !MONO
1502             if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled()) {
1503                 if (pos < 0) {
1504                     FrameworkEventSource.Log.ResourceManagerCultureNotFoundInConfigFile(BaseNameField, MainAssembly, lookForCulture.Name);
1505                 }
1506                 else {
1507                     FrameworkEventSource.Log.ResourceManagerCultureFoundInConfigFile(BaseNameField, MainAssembly, lookForCulture.Name);
1508                 }
1509             }
1510 #endif
1511             return pos >= 0;
1512         }
1513
1514         // Note: There is one config file per appdomain.  This is not 
1515         // per-process nor per-assembly.
1516         [System.Security.SecurityCritical]  // auto-generated
1517         [ResourceExposure(ResourceScope.None)]
1518         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
1519         private Hashtable GetSatelliteAssembliesFromConfig()
1520         {
1521 #if FEATURE_FUSION
1522
1523             String fileName = AppDomain.CurrentDomain.FusionStore.ConfigurationFileInternal;
1524             if (fileName == null) {
1525                 return null;
1526             }
1527
1528             // Don't do a security assert.  We need to support semi-trusted 
1529             // scenarios, but asserting here causes infinite resource lookups
1530             // while initializing security & looking up mscorlib's config file.
1531             // Use internal methods to bypass security checks.
1532
1533             // If we're dealing with a local file name or a UNC path instead 
1534             // of a URL, check to see if the file exists here for perf (avoids
1535             // throwing a FileNotFoundException).
1536             if (fileName.Length >= 2 && 
1537                 ((fileName[1] == Path.VolumeSeparatorChar) || (fileName[0] == Path.DirectorySeparatorChar && fileName[1] == Path.DirectorySeparatorChar)) &&
1538                 !File.InternalExists(fileName))
1539                 return null;
1540
1541             ConfigTreeParser parser = new ConfigTreeParser();
1542             String queryPath = "/configuration/satelliteassemblies";
1543             ConfigNode node = null;
1544             // Catch exceptions in case a web app doesn't have a config file.
1545             try {
1546                 node = parser.Parse(fileName, queryPath, true);
1547             }
1548             catch(Exception) {}
1549
1550             if (node == null) {
1551                 return null;
1552             }
1553
1554             // The application config file will contain sections like this:
1555             // <?xml version="1.0"?>
1556             // <configuration>
1557             //     <satelliteassemblies>
1558             //         <assembly name="mscorlib, Version=..., PublicKeyToken=...">
1559             //             <culture>fr</culture>
1560             //         </assembly>
1561             //         <assembly name="UserAssembly, ...">
1562             //             <culture>fr-FR</culture>
1563             //             <culture>de-CH</culture>
1564             //         </assembly>
1565             //         <assembly name="UserAssembly2, ...">
1566             //         </assembly>
1567             //    </satelliteassemblies>
1568             // </configuration>
1569             Hashtable satelliteInfo = new Hashtable(StringComparer.OrdinalIgnoreCase);
1570             foreach(ConfigNode assemblyNode in node.Children) {
1571                 if (!String.Equals(assemblyNode.Name, "assembly"))
1572                     throw new ApplicationException(Environment.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTag", Path.GetFileName(fileName), assemblyNode.Name));
1573
1574                 if (assemblyNode.Attributes.Count == 0)
1575                     throw new ApplicationException(Environment.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTagNoAttr", Path.GetFileName(fileName)));
1576
1577                 DictionaryEntry de = (DictionaryEntry) assemblyNode.Attributes[0];
1578                 String assemblyName = (String) de.Value;
1579                 if (!String.Equals(de.Key, "name") || String.IsNullOrEmpty(assemblyName) || assemblyNode.Attributes.Count > 1) 
1580                     throw new ApplicationException(Environment.GetResourceString("XMLSyntax_InvalidSyntaxSatAssemTagBadAttr", Path.GetFileName(fileName), de.Key, de.Value));
1581
1582                 ArrayList list = new ArrayList(5);
1583                 foreach(ConfigNode child in assemblyNode.Children)
1584                     if (child.Value != null)
1585                         list.Add(child.Value);
1586
1587                 String[] satellites = new String[list.Count];
1588                 for(int i=0; i<satellites.Length; i++) {
1589                     String cultureName = (String)list[i];
1590                     satellites[i] = cultureName;
1591 #if !FEATURE_CORECLR && !MONO
1592                     if (FrameworkEventSource.IsInitialized)
1593                     {
1594                         FrameworkEventSource.Log.ResourceManagerAddingCultureFromConfigFile(BaseNameField, MainAssembly, cultureName);
1595                     }
1596 #endif
1597                 }
1598
1599                 satelliteInfo.Add(assemblyName, satellites);
1600             }
1601
1602             return satelliteInfo;
1603 #else
1604             return null;
1605 #endif //FEATURE_FUSION
1606
1607         }
1608 #endif  // RESOURCE_SATELLITE_CONFIG
1609
1610         internal class ResourceManagerMediator
1611         {
1612             private ResourceManager _rm;
1613
1614             internal ResourceManagerMediator(ResourceManager rm)
1615             {
1616                 if (rm == null)
1617                 {
1618                     throw new ArgumentNullException("rm");
1619                 }
1620                 _rm = rm;
1621             }
1622
1623             // NEEDED ONLY BY FILE-BASED
1624             internal String ModuleDir
1625             {
1626                 get { return _rm.moduleDir; }
1627             }
1628
1629             // NEEDED BOTH BY FILE-BASED  AND ----Y-BASED
1630             internal Type LocationInfo
1631             {
1632                 get { return _rm._locationInfo; }
1633             }
1634
1635             internal Type UserResourceSet 
1636             {
1637                 get { return _rm._userResourceSet; }
1638             }
1639
1640             internal String BaseNameField
1641             {
1642                 get { return _rm.BaseNameField; }
1643             }
1644
1645             internal CultureInfo NeutralResourcesCulture
1646             {
1647                 get { return _rm._neutralResourcesCulture; }
1648                 set { _rm._neutralResourcesCulture = value; }
1649             }
1650
1651             internal String GetResourceFileName(CultureInfo culture)
1652             {
1653                 return _rm.GetResourceFileName(culture);
1654             }
1655
1656             // NEEDED ONLY BY ----Y-BASED
1657             internal bool LookedForSatelliteContractVersion
1658             {
1659                 get { return _rm._lookedForSatelliteContractVersion; }
1660                 set { _rm._lookedForSatelliteContractVersion = value; }
1661             }
1662
1663             internal Version SatelliteContractVersion
1664             {
1665                 get { return _rm._satelliteContractVersion; }
1666                 set { _rm._satelliteContractVersion = value; }
1667             }
1668
1669             internal Version ObtainSatelliteContractVersion(Assembly a)
1670             {
1671                 return ResourceManager.GetSatelliteContractVersion(a);
1672             }
1673
1674             internal UltimateResourceFallbackLocation FallbackLoc
1675             {
1676                 get { return _rm.FallbackLocation; } 
1677                 set { _rm._fallbackLoc = value; }
1678             }
1679
1680             internal RuntimeAssembly CallingAssembly
1681             {
1682                 get { return _rm.m_callingAssembly; }
1683             }
1684
1685             internal RuntimeAssembly MainAssembly
1686             {
1687                 get { return (RuntimeAssembly)_rm.MainAssembly; }
1688             }
1689
1690             // this is weird because we have BaseNameField accessor above, but we're sticking
1691             // with it for compat.
1692             internal String BaseName
1693             {
1694                 get { return _rm.BaseName; }
1695             }
1696
1697
1698 #if RESOURCE_SATELLITE_CONFIG
1699             [System.Security.SecurityCritical]  // auto-generated
1700             internal bool TryLookingForSatellite(CultureInfo lookForCulture)
1701             {
1702                 return _rm.TryLookingForSatellite(lookForCulture);
1703             }
1704 #endif
1705
1706         }
1707     }
1708 }