internal String GetResourceString(String key)
            {
                if (key == null || key.Length == 0)
                {
                    BCLDebug.Assert(false, "Environment::GetResourceString with null or empty key.  Bug in caller, or weird recursive loading problem?");
                    return("[Resource lookup failed - null or empty resource name]");
                }

                // We have a somewhat common potential for infinite
                // loops with mscorlib's ResourceManager.  If "potentially dangerous"
                // code throws an exception, we will get into an infinite loop
                // inside the ResourceManager and this "potentially dangerous" code.
                // Potentially dangerous code includes the IO package, CultureInfo,
                // parts of the loader, some parts of Reflection, Security (including
                // custom user-written permissions that may parse an XML file at
                // class load time), assembly load event handlers, etc.  Essentially,
                // this is not a bounded set of code, and we need to fix the problem.
                // Fortunately, this is limited to mscorlib's error lookups and is NOT
                // a general problem for all user code using the ResourceManager.

                // The solution is to make sure only one thread at a time can call
                // GetResourceString.  Also, since resource lookups can be
                // reentrant, if the same thread comes into GetResourceString
                // twice looking for the exact same resource name before
                // returning, we're going into an infinite loop and we should
                // return a bogus string.

                GetResourceStringUserData userData = new GetResourceStringUserData(this, key);

                RuntimeHelpers.TryCode     tryCode     = new RuntimeHelpers.TryCode(GetResourceStringCode);
                RuntimeHelpers.CleanupCode cleanupCode = new RuntimeHelpers.CleanupCode(GetResourceStringBackoutCode);

                RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(tryCode, cleanupCode, userData);
                return(userData.m_retVal);
            }
            private void GetResourceStringCode(object userDataIn)
            {
                GetResourceStringUserData data = (GetResourceStringUserData)userDataIn;

                Environment.ResourceHelper resourceHelper = data.m_resourceHelper;
                string      key     = data.m_key;
                CultureInfo culture = data.m_culture;

                Monitor.Enter(resourceHelper, ref data.m_lockWasTaken);
                if (((resourceHelper.currentlyLoading != null) && (resourceHelper.currentlyLoading.Count > 0)) && resourceHelper.currentlyLoading.Contains(key))
                {
                    try
                    {
                        new StackTrace(true).ToString(StackTrace.TraceFormat.NoResourceLookup);
                    }
                    catch (StackOverflowException)
                    {
                    }
                    catch (NullReferenceException)
                    {
                    }
                    catch (OutOfMemoryException)
                    {
                    }
                    data.m_retVal = "[Resource lookup failed - infinite recursion or critical failure detected.]";
                }
                else
                {
                    if (resourceHelper.currentlyLoading == null)
                    {
                        resourceHelper.currentlyLoading = new Stack(4);
                    }
                    if (!resourceHelper.resourceManagerInited)
                    {
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try
                        {
                        }
                        finally
                        {
                            RuntimeHelpers.RunClassConstructor(typeof(ResourceManager).TypeHandle);
                            RuntimeHelpers.RunClassConstructor(typeof(ResourceReader).TypeHandle);
                            RuntimeHelpers.RunClassConstructor(typeof(RuntimeResourceSet).TypeHandle);
                            RuntimeHelpers.RunClassConstructor(typeof(BinaryReader).TypeHandle);
                            resourceHelper.resourceManagerInited = true;
                        }
                    }
                    resourceHelper.currentlyLoading.Push(key);
                    if (resourceHelper.SystemResMgr == null)
                    {
                        resourceHelper.SystemResMgr = new ResourceManager(this.m_name, typeof(object).Assembly);
                    }
                    string str2 = resourceHelper.SystemResMgr.GetString(key, null);
                    resourceHelper.currentlyLoading.Pop();
                    data.m_retVal = str2;
                }
            }
            internal string GetResourceString(string key, CultureInfo culture)
            {
                if ((key == null) || (key.Length == 0))
                {
                    return("[Resource lookup failed - null or empty resource name]");
                }
                GetResourceStringUserData userData = new GetResourceStringUserData(this, key, culture);

                RuntimeHelpers.TryCode     code        = new RuntimeHelpers.TryCode(this.GetResourceStringCode);
                RuntimeHelpers.CleanupCode backoutCode = new RuntimeHelpers.CleanupCode(this.GetResourceStringBackoutCode);
                RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(code, backoutCode, userData);
                return(userData.m_retVal);
            }
            private void GetResourceStringBackoutCode(object userDataIn, bool exceptionThrown)
            {
                GetResourceStringUserData data = (GetResourceStringUserData)userDataIn;

                Environment.ResourceHelper resourceHelper = data.m_resourceHelper;
                if (exceptionThrown && data.m_lockWasTaken)
                {
                    resourceHelper.SystemResMgr     = null;
                    resourceHelper.currentlyLoading = null;
                }
                if (data.m_lockWasTaken)
                {
                    Monitor.Exit(resourceHelper);
                }
            }
            private void GetResourceStringBackoutCode(Object userDataIn, bool exceptionThrown)
            {
                GetResourceStringUserData userData = (GetResourceStringUserData)userDataIn;
                ResourceHelper            rh       = userData.m_resourceHelper;

                if (exceptionThrown)
                {
                    if (userData.m_lockWasTaken)
                    {
                        // Backout code - throw away potentially corrupt state
                        rh.SystemResMgr     = null;
                        rh.currentlyLoading = null;
                    }
                }
                // Release the lock, if we took it.
                if (userData.m_lockWasTaken)
                {
                    Monitor.Exit(rh);
                }
            }
            internal String GetResourceString(String key, CultureInfo culture)  {
                if (key == null || key.Length == 0) {
                    Contract.Assert(false, "Environment::GetResourceString with null or empty key.  Bug in caller, or weird recursive loading problem?");
                    return "[Resource lookup failed - null or empty resource name]";
                }

#if FEATURE_SPLIT_RESOURCES
                if (UseFallback()) {
                    return null;
                }
#endif // FEATURE_SPLIT_RESOURCES

                // We have a somewhat common potential for infinite 
                // loops with mscorlib's ResourceManager.  If "potentially dangerous"
                // code throws an exception, we will get into an infinite loop
                // inside the ResourceManager and this "potentially dangerous" code.
                // Potentially dangerous code includes the IO package, CultureInfo,
                // parts of the loader, some parts of Reflection, Security (including 
                // custom user-written permissions that may parse an XML file at
                // class load time), assembly load event handlers, etc.  Essentially,
                // this is not a bounded set of code, and we need to fix the problem.
                // Fortunately, this is limited to mscorlib's error lookups and is NOT
                // a general problem for all user code using the ResourceManager.
                
                // The solution is to make sure only one thread at a time can call 
                // GetResourceString.  Also, since resource lookups can be 
                // reentrant, if the same thread comes into GetResourceString
                // twice looking for the exact same resource name before 
                // returning, we're going into an infinite loop and we should 
                // return a bogus string.  

                GetResourceStringUserData userData = new GetResourceStringUserData(this, key, culture);

                RuntimeHelpers.TryCode tryCode = new RuntimeHelpers.TryCode(GetResourceStringCode);
                RuntimeHelpers.CleanupCode cleanupCode = new RuntimeHelpers.CleanupCode(GetResourceStringBackoutCode);

                RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(tryCode, cleanupCode, userData);
                return userData.m_retVal;
            }
            private void GetResourceStringCode(Object userDataIn)
            {
                GetResourceStringUserData userData = (GetResourceStringUserData)userDataIn;
                ResourceHelper            rh       = userData.m_resourceHelper;
                String key = userData.m_key;

                Monitor.ReliableEnter(rh, ref userData.m_lockWasTaken);

                // Are we recursively looking up the same resource?
                if (rh.currentlyLoading != null && rh.currentlyLoading.Count > 0 && rh.currentlyLoading.Contains(key))
                {
                    // This is often a bug in the BCL, security, NLS+ code,
                    // or the loader somewhere.  However, this could also
                    // be a setup problem - check whether mscorlib &
                    // mscorwks are both of the same build flavor.
                    String stackTrace = "[Couldn't get a stack trace]";
                    try
                    {
                        StackTrace st = new StackTrace(true);
                        // Don't attempt to localize strings in this stack trace, otherwise it could cause
                        // infinite recursion. This stack trace is used for an Assert message only, and
                        // so the lack of localization should not be an issue.
                        stackTrace = st.ToString(System.Diagnostics.StackTrace.TraceFormat.NoResourceLookup);
                    }
                    catch (StackOverflowException) {}
                    catch (NullReferenceException) {}
                    catch (OutOfMemoryException) {}

                    BCLDebug.Assert(false, "Infinite recursion during resource lookup.  Resource name: " + key + "\r\n" + stackTrace);

                    // Note: can't append the key name, since that may require
                    // an extra allocation...
                    userData.m_retVal = "[Resource lookup failed - infinite recursion or critical failure detected.]";
                    return;
                }
                if (rh.currentlyLoading == null)
                {
                    rh.currentlyLoading = new Stack(4);
                }

                // Call class constructors preemptively, so that we cannot get into an infinite
                // loop constructing a TypeInitializationException.  If this were omitted,
                // we could get the Infinite recursion assert above by failing type initialization
                // between the Push and Pop calls below.

                if (!rh.resourceManagerInited)
                {
                    // process-critical code here.  No ThreadAbortExceptions
                    // can be thrown here.  Other exceptions percolate as normal.
                    RuntimeHelpers.PrepareConstrainedRegions();
                    try {
                    }
                    finally {
                        RuntimeHelpers.RunClassConstructor(typeof(ResourceManager).TypeHandle);
                        RuntimeHelpers.RunClassConstructor(typeof(ResourceReader).TypeHandle);
                        RuntimeHelpers.RunClassConstructor(typeof(RuntimeResourceSet).TypeHandle);
                        RuntimeHelpers.RunClassConstructor(typeof(BinaryReader).TypeHandle);
                        rh.resourceManagerInited = true;
                    }
                }

                rh.currentlyLoading.Push(key);
                if (rh.SystemResMgr == null)
                {
                    rh.SystemResMgr = new ResourceManager("mscorlib", typeof(Object).Assembly);
                }
                String s = rh.SystemResMgr.GetString(key, null);

                rh.currentlyLoading.Pop();

                BCLDebug.Assert(s != null, "Managed resource string lookup failed.  Was your resource name misspelled?  Did you rebuild mscorlib after adding a resource to resources.txt?  Debug this w/ cordbg and bug whoever owns the code that called rhironment.GetResourceString.  Resource name was: \"" + key + "\"");

                userData.m_retVal = s;
            }
 internal string GetResourceString(string key, CultureInfo culture)
 {
     if ((key == null) || (key.Length == 0))
     {
         return "[Resource lookup failed - null or empty resource name]";
     }
     GetResourceStringUserData userData = new GetResourceStringUserData(this, key, culture);
     RuntimeHelpers.TryCode code = new RuntimeHelpers.TryCode(this.GetResourceStringCode);
     RuntimeHelpers.CleanupCode backoutCode = new RuntimeHelpers.CleanupCode(this.GetResourceStringBackoutCode);
     RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(code, backoutCode, userData);
     return userData.m_retVal;
 }