Delete FriendAccessAllowedAttribute and associated dead code (#15101)
[platform/upstream/coreclr.git] / src / mscorlib / src / System / AppDomain.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*=============================================================================
6 **
7 **
8 **
9 ** Purpose: Domains represent an application within the runtime. Objects can 
10 **          not be shared between domains and each domain can be configured
11 **          independently. 
12 **
13 **
14 =============================================================================*/
15
16 namespace System
17 {
18     using System;
19     using System.Reflection;
20     using System.Runtime;
21     using System.Runtime.CompilerServices;
22     using System.Security;
23     using System.Collections;
24     using System.Collections.Generic;
25     using System.Threading;
26     using System.Runtime.InteropServices;
27     using System.Reflection.Emit;
28     using CultureInfo = System.Globalization.CultureInfo;
29     using System.IO;
30     using AssemblyHashAlgorithm = System.Configuration.Assemblies.AssemblyHashAlgorithm;
31     using System.Text;
32     using System.Runtime.ConstrainedExecution;
33     using System.Runtime.Versioning;
34     using System.Diagnostics;
35     using System.Diagnostics.Contracts;
36     using System.Runtime.ExceptionServices;
37
38     internal sealed class AppDomain
39     {
40         // Domain security information
41         // These fields initialized from the other side only. (NOTE: order 
42         // of these fields cannot be changed without changing the layout in 
43         // the EE- AppDomainBaseObject in this case)
44
45         private AppDomainManager _domainManager;
46         private Dictionary<String, Object> _LocalStore;
47         private AppDomainSetup _FusionStore;
48         public event AssemblyLoadEventHandler AssemblyLoad;
49
50         private ResolveEventHandler _TypeResolve;
51
52         public event ResolveEventHandler TypeResolve
53         {
54             add
55             {
56                 lock (this)
57                 {
58                     _TypeResolve += value;
59                 }
60             }
61
62             remove
63             {
64                 lock (this)
65                 {
66                     _TypeResolve -= value;
67                 }
68             }
69         }
70
71         private ResolveEventHandler _ResourceResolve;
72
73         public event ResolveEventHandler ResourceResolve
74         {
75             add
76             {
77                 lock (this)
78                 {
79                     _ResourceResolve += value;
80                 }
81             }
82
83             remove
84             {
85                 lock (this)
86                 {
87                     _ResourceResolve -= value;
88                 }
89             }
90         }
91
92         private ResolveEventHandler _AssemblyResolve;
93
94         public event ResolveEventHandler AssemblyResolve
95         {
96             add
97             {
98                 lock (this)
99                 {
100                     _AssemblyResolve += value;
101                 }
102             }
103
104             remove
105             {
106                 lock (this)
107                 {
108                     _AssemblyResolve -= value;
109                 }
110             }
111         }
112
113
114         private EventHandler _processExit;
115
116         private EventHandler _domainUnload;
117
118         private UnhandledExceptionEventHandler _unhandledException;
119
120         // The compat flags are set at domain creation time to indicate that the given breaking
121         // changes (named in the strings) should not be used in this domain. We only use the 
122         // keys, the vhe values are ignored.
123         private Dictionary<String, object> _compatFlags;
124
125         // Delegate that will hold references to FirstChance exception notifications
126         private EventHandler<FirstChanceExceptionEventArgs> _firstChanceException;
127
128         private IntPtr _pDomain;                      // this is an unmanaged pointer (AppDomain * m_pDomain)` used from the VM.
129
130         private bool _compatFlagsInitialized;
131
132         internal const String TargetFrameworkNameAppCompatSetting = "TargetFrameworkName";
133
134 #if FEATURE_APPX
135         private static APPX_FLAGS s_flags;
136
137         //
138         // Keep in async with vm\appdomainnative.cpp
139         //
140         [Flags]
141         private enum APPX_FLAGS
142         {
143             APPX_FLAGS_INITIALIZED = 0x01,
144
145             APPX_FLAGS_APPX_MODEL = 0x02,
146             APPX_FLAGS_APPX_DESIGN_MODE = 0x04,
147             APPX_FLAGS_APPX_MASK = APPX_FLAGS_APPX_MODEL |
148                                             APPX_FLAGS_APPX_DESIGN_MODE,
149         }
150
151         private static APPX_FLAGS Flags
152         {
153             get
154             {
155                 if (s_flags == 0)
156                     s_flags = nGetAppXFlags();
157
158                 Debug.Assert(s_flags != 0);
159                 return s_flags;
160             }
161         }
162 #endif // FEATURE_APPX
163
164 #if FEATURE_APPX
165         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
166         [return: MarshalAs(UnmanagedType.I4)]
167         private static extern APPX_FLAGS nGetAppXFlags();
168 #endif
169
170         /// <summary>
171         ///     Get a handle used to make a call into the VM pointing to this domain
172         /// </summary>
173         internal AppDomainHandle GetNativeHandle()
174         {
175             // This should never happen under normal circumstances. However, there ar ways to create an
176             // uninitialized object through remoting, etc.
177             if (_pDomain.IsNull())
178             {
179                 throw new InvalidOperationException(SR.Argument_InvalidHandle);
180             }
181
182             return new AppDomainHandle(_pDomain);
183         }
184
185         /// <summary>
186         ///     If this AppDomain is configured to have an AppDomain manager then create the instance of it.
187         ///     This method is also called from the VM to create the domain manager in the default domain.
188         /// </summary>
189         private void CreateAppDomainManager()
190         {
191             Debug.Assert(_domainManager == null, "_domainManager == null");
192
193             AppDomainSetup adSetup = FusionStore;
194             String trustedPlatformAssemblies = (String)(GetData("TRUSTED_PLATFORM_ASSEMBLIES"));
195             if (trustedPlatformAssemblies != null)
196             {
197                 String platformResourceRoots = (String)(GetData("PLATFORM_RESOURCE_ROOTS"));
198                 if (platformResourceRoots == null)
199                 {
200                     platformResourceRoots = String.Empty;
201                 }
202
203                 String appPaths = (String)(GetData("APP_PATHS"));
204                 if (appPaths == null)
205                 {
206                     appPaths = String.Empty;
207                 }
208
209                 String appNiPaths = (String)(GetData("APP_NI_PATHS"));
210                 if (appNiPaths == null)
211                 {
212                     appNiPaths = String.Empty;
213                 }
214
215                 String appLocalWinMD = (String)(GetData("APP_LOCAL_WINMETADATA"));
216                 if (appLocalWinMD == null)
217                 {
218                     appLocalWinMD = String.Empty;
219                 }
220                 SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths, appLocalWinMD);
221             }
222
223             InitializeCompatibilityFlags();
224         }
225
226         /// <summary>
227         ///     Initialize the compatibility flags to non-NULL values.
228         ///     This method is also called from the VM when the default domain doesn't have a domain manager.
229         /// </summary>
230         private void InitializeCompatibilityFlags()
231         {
232             AppDomainSetup adSetup = FusionStore;
233
234             // set up shim flags regardless of whether we create a DomainManager in this method.
235             if (adSetup.GetCompatibilityFlags() != null)
236             {
237                 _compatFlags = new Dictionary<String, object>(adSetup.GetCompatibilityFlags(), StringComparer.OrdinalIgnoreCase);
238             }
239
240             // for perf, we don't intialize the _compatFlags dictionary when we don't need to.  However, we do need to make a 
241             // note that we've run this method, because IsCompatibilityFlagsSet needs to return different values for the
242             // case where the compat flags have been setup.
243             Debug.Assert(!_compatFlagsInitialized);
244             _compatFlagsInitialized = true;
245         }
246
247         /// <summary>
248         ///     Returns whether the current AppDomain follows the AppX rules.
249         /// </summary>
250         [Pure]
251         internal static bool IsAppXModel()
252         {
253 #if FEATURE_APPX
254             return (Flags & APPX_FLAGS.APPX_FLAGS_APPX_MODEL) != 0;
255 #else
256             return false;
257 #endif
258         }
259
260         /// <summary>
261         ///     Returns the setting of the AppXDevMode config switch.
262         /// </summary>
263         [Pure]
264         internal static bool IsAppXDesignMode()
265         {
266 #if FEATURE_APPX
267             return (Flags & APPX_FLAGS.APPX_FLAGS_APPX_MASK) == (APPX_FLAGS.APPX_FLAGS_APPX_MODEL | APPX_FLAGS.APPX_FLAGS_APPX_DESIGN_MODE);
268 #else
269             return false;
270 #endif
271         }
272
273         /// <summary>
274         ///     Checks (and throws on failure) if the domain supports Assembly.LoadFrom.
275         /// </summary>
276         [Pure]
277         internal static void CheckLoadFromSupported()
278         {
279 #if FEATURE_APPX
280             if (IsAppXModel())
281                 throw new NotSupportedException(SR.Format(SR.NotSupported_AppX, "Assembly.LoadFrom"));
282 #endif
283         }
284
285         /// <summary>
286         ///     Checks (and throws on failure) if the domain supports Assembly.LoadFile.
287         /// </summary>
288         [Pure]
289         internal static void CheckLoadFileSupported()
290         {
291 #if FEATURE_APPX
292             if (IsAppXModel())
293                 throw new NotSupportedException(SR.Format(SR.NotSupported_AppX, "Assembly.LoadFile"));
294 #endif
295         }
296
297         /// <summary>
298         ///     Checks (and throws on failure) if the domain supports Assembly.Load(byte[] ...).
299         /// </summary>
300         [Pure]
301         internal static void CheckLoadByteArraySupported()
302         {
303 #if FEATURE_APPX
304             if (IsAppXModel())
305                 throw new NotSupportedException(SR.Format(SR.NotSupported_AppX, "Assembly.Load(byte[], ...)"));
306 #endif
307         }
308
309         public AppDomainManager DomainManager
310         {
311             get
312             {
313                 return _domainManager;
314             }
315         }
316
317         public static AppDomain CurrentDomain
318         {
319             get
320             {
321                 return Thread.GetDomain();
322             }
323         }
324
325         public String BaseDirectory
326         {
327             get
328             {
329                 return FusionStore.ApplicationBase;
330             }
331         }
332
333         public override String ToString()
334         {
335             StringBuilder sb = StringBuilderCache.Acquire();
336
337             String fn = nGetFriendlyName();
338             if (fn != null)
339             {
340                 sb.Append(SR.Loader_Name + fn);
341                 sb.Append(Environment.NewLine);
342             }
343
344             return StringBuilderCache.GetStringAndRelease(sb);
345         }
346
347         [MethodImpl(MethodImplOptions.InternalCall)]
348         private extern Assembly[] nGetAssemblies(bool forIntrospection);
349
350         internal Assembly[] GetAssemblies(bool forIntrospection)
351         {
352             return nGetAssemblies(forIntrospection);
353         }
354
355         // this is true when we've removed the handles etc so really can't do anything
356         [MethodImplAttribute(MethodImplOptions.InternalCall)]
357         internal extern bool IsUnloadingForcedFinalize();
358
359         // this is true when we've just started going through the finalizers and are forcing objects to finalize
360         // so must be aware that certain infrastructure may have gone away
361         [MethodImplAttribute(MethodImplOptions.InternalCall)]
362         public extern bool IsFinalizingForUnload();
363
364         [MethodImplAttribute(MethodImplOptions.InternalCall)]
365         internal static extern void PublishAnonymouslyHostedDynamicMethodsAssembly(RuntimeAssembly assemblyHandle);
366
367         public void SetData(string name, object data)
368         {
369             if (name == null)
370                 throw new ArgumentNullException(nameof(name));
371
372             lock (((ICollection)LocalStore).SyncRoot)
373             {
374                 LocalStore[name] = data;
375             }
376         }
377
378         [Pure]
379         public Object GetData(string name)
380         {
381             if (name == null)
382                 throw new ArgumentNullException(nameof(name));
383
384             object data;
385             lock (((ICollection)LocalStore).SyncRoot)
386             {
387                 LocalStore.TryGetValue(name, out data);
388             }
389             if (data == null)
390                 return null;
391             return data;
392         }
393
394         [Obsolete("AppDomain.GetCurrentThreadId has been deprecated because it does not provide a stable Id when managed threads are running on fibers (aka lightweight threads). To get a stable identifier for a managed thread, use the ManagedThreadId property on Thread.  http://go.microsoft.com/fwlink/?linkid=14202", false)]
395         [DllImport(Interop.Libraries.Kernel32)]
396         public static extern int GetCurrentThreadId();
397
398         private AppDomain()
399         {
400             throw new NotSupportedException(SR.NotSupported_Constructor);
401         }
402
403         [MethodImplAttribute(MethodImplOptions.InternalCall)]
404         internal extern void nCreateContext();
405
406         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
407         private static extern void nSetupBindingPaths(String trustedPlatformAssemblies, String platformResourceRoots, String appPath, String appNiPaths, String appLocalWinMD);
408
409         internal void SetupBindingPaths(String trustedPlatformAssemblies, String platformResourceRoots, String appPath, String appNiPaths, String appLocalWinMD)
410         {
411             nSetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPath, appNiPaths, appLocalWinMD);
412         }
413
414         [MethodImplAttribute(MethodImplOptions.InternalCall)]
415         private extern String nGetFriendlyName();
416
417         // support reliability for certain event handlers, if the target
418         // methods also participate in this discipline.  If caller passes
419         // an existing MulticastDelegate, then we could use a MDA to indicate
420         // that reliability is not guaranteed.  But if it is a single cast
421         // scenario, we can make it work.
422
423         public event EventHandler ProcessExit
424         {
425             add
426             {
427                 if (value != null)
428                 {
429                     RuntimeHelpers.PrepareContractedDelegate(value);
430                     lock (this)
431                         _processExit += value;
432                 }
433             }
434             remove
435             {
436                 lock (this)
437                     _processExit -= value;
438             }
439         }
440
441
442         public event EventHandler DomainUnload
443         {
444             add
445             {
446                 if (value != null)
447                 {
448                     RuntimeHelpers.PrepareContractedDelegate(value);
449                     lock (this)
450                         _domainUnload += value;
451                 }
452             }
453             remove
454             {
455                 lock (this)
456                     _domainUnload -= value;
457             }
458         }
459
460
461         public event UnhandledExceptionEventHandler UnhandledException
462         {
463             add
464             {
465                 if (value != null)
466                 {
467                     RuntimeHelpers.PrepareContractedDelegate(value);
468                     lock (this)
469                         _unhandledException += value;
470                 }
471             }
472             remove
473             {
474                 lock (this)
475                     _unhandledException -= value;
476             }
477         }
478
479         // This is the event managed code can wireup against to be notified
480         // about first chance exceptions. 
481         //
482         // To register/unregister the callback, the code must be SecurityCritical.
483         public event EventHandler<FirstChanceExceptionEventArgs> FirstChanceException
484         {
485             add
486             {
487                 if (value != null)
488                 {
489                     RuntimeHelpers.PrepareContractedDelegate(value);
490                     lock (this)
491                         _firstChanceException += value;
492                 }
493             }
494             remove
495             {
496                 lock (this)
497                     _firstChanceException -= value;
498             }
499         }
500
501         private void OnAssemblyLoadEvent(RuntimeAssembly LoadedAssembly)
502         {
503             AssemblyLoadEventHandler eventHandler = AssemblyLoad;
504             if (eventHandler != null)
505             {
506                 AssemblyLoadEventArgs ea = new AssemblyLoadEventArgs(LoadedAssembly);
507                 eventHandler(this, ea);
508             }
509         }
510
511         // This method is called by the VM.
512         private RuntimeAssembly OnResourceResolveEvent(RuntimeAssembly assembly, String resourceName)
513         {
514             ResolveEventHandler eventHandler = _ResourceResolve;
515             if (eventHandler == null)
516                 return null;
517
518             Delegate[] ds = eventHandler.GetInvocationList();
519             int len = ds.Length;
520             for (int i = 0; i < len; i++)
521             {
522                 Assembly asm = ((ResolveEventHandler)ds[i])(this, new ResolveEventArgs(resourceName, assembly));
523                 RuntimeAssembly ret = GetRuntimeAssembly(asm);
524                 if (ret != null)
525                     return ret;
526             }
527
528             return null;
529         }
530
531         // This method is called by the VM
532         private RuntimeAssembly OnTypeResolveEvent(RuntimeAssembly assembly, String typeName)
533         {
534             ResolveEventHandler eventHandler = _TypeResolve;
535             if (eventHandler == null)
536                 return null;
537
538             Delegate[] ds = eventHandler.GetInvocationList();
539             int len = ds.Length;
540             for (int i = 0; i < len; i++)
541             {
542                 Assembly asm = ((ResolveEventHandler)ds[i])(this, new ResolveEventArgs(typeName, assembly));
543                 RuntimeAssembly ret = GetRuntimeAssembly(asm);
544                 if (ret != null)
545                     return ret;
546             }
547
548             return null;
549         }
550
551         // This method is called by the VM.
552         private RuntimeAssembly OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)
553         {
554             ResolveEventHandler eventHandler = _AssemblyResolve;
555
556             if (eventHandler == null)
557             {
558                 return null;
559             }
560
561             Delegate[] ds = eventHandler.GetInvocationList();
562             int len = ds.Length;
563             for (int i = 0; i < len; i++)
564             {
565                 Assembly asm = ((ResolveEventHandler)ds[i])(this, new ResolveEventArgs(assemblyFullName, assembly));
566                 RuntimeAssembly ret = GetRuntimeAssembly(asm);
567                 if (ret != null)
568                     return ret;
569             }
570
571             return null;
572         }
573
574 #if FEATURE_COMINTEROP
575         // Called by VM - code:CLRPrivTypeCacheWinRT::RaiseDesignerNamespaceResolveEvent
576         private string[] OnDesignerNamespaceResolveEvent(string namespaceName)
577         {
578             return System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMetadata.OnDesignerNamespaceResolveEvent(this, namespaceName);
579         }
580 #endif // FEATURE_COMINTEROP
581
582         internal AppDomainSetup FusionStore
583         {
584             get
585             {
586                 Debug.Assert(_FusionStore != null,
587                                 "Fusion store has not been correctly setup in this domain");
588                 return _FusionStore;
589             }
590         }
591
592         internal static RuntimeAssembly GetRuntimeAssembly(Assembly asm)
593         {
594             if (asm == null)
595                 return null;
596
597             RuntimeAssembly rtAssembly = asm as RuntimeAssembly;
598             if (rtAssembly != null)
599                 return rtAssembly;
600
601             AssemblyBuilder ab = asm as AssemblyBuilder;
602             if (ab != null)
603                 return ab.InternalAssembly;
604
605             return null;
606         }
607
608         private Dictionary<String, Object> LocalStore
609         {
610             get
611             {
612                 if (_LocalStore != null)
613                     return _LocalStore;
614                 else
615                 {
616                     _LocalStore = new Dictionary<String, Object>();
617                     return _LocalStore;
618                 }
619             }
620         }
621
622         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
623         private static extern void nSetNativeDllSearchDirectories(string paths);
624
625         private void SetupFusionStore(AppDomainSetup info, AppDomainSetup oldInfo)
626         {
627             Debug.Assert(info != null);
628
629             if (info.ApplicationBase == null)
630             {
631                 info.SetupDefaults(RuntimeEnvironment.GetModuleFileName(), imageLocationAlreadyNormalized: true);
632             }
633
634             nCreateContext();
635
636             // This must be the last action taken
637             _FusionStore = info;
638         }
639
640         // Used to switch into other AppDomain and call SetupRemoteDomain.
641         //   We cannot simply call through the proxy, because if there
642         //   are any remoting sinks registered, they can add non-mscorlib
643         //   objects to the message (causing an assembly load exception when
644         //   we try to deserialize it on the other side)
645         private static object PrepareDataForSetup(String friendlyName,
646                                                         AppDomainSetup setup,
647                                                         string[] propertyNames,
648                                                         string[] propertyValues)
649         {
650             AppDomainSetup newSetup = new AppDomainSetup(setup, false);
651
652             // Remove the special AppDomainCompatSwitch entries from the set of name value pairs
653             // And add them to the AppDomainSetup
654             //
655             // This is only supported on CoreCLR through ICLRRuntimeHost2.CreateAppDomainWithManager
656             // Desktop code should use System.AppDomain.CreateDomain() or 
657             // System.AppDomainManager.CreateDomain() and add the flags to the AppDomainSetup
658             List<String> compatList = new List<String>();
659
660             if (propertyNames != null && propertyValues != null)
661             {
662                 for (int i = 0; i < propertyNames.Length; i++)
663                 {
664                     if (String.Compare(propertyNames[i], "AppDomainCompatSwitch", StringComparison.OrdinalIgnoreCase) == 0)
665                     {
666                         compatList.Add(propertyValues[i]);
667                         propertyNames[i] = null;
668                         propertyValues[i] = null;
669                     }
670                 }
671
672                 if (compatList.Count > 0)
673                 {
674                     newSetup.SetCompatibilitySwitches(compatList);
675                 }
676             }
677
678             return new Object[]
679             {
680                 friendlyName,
681                 newSetup,
682                 propertyNames,
683                 propertyValues
684             };
685         } // PrepareDataForSetup
686
687         private static Object Setup(Object arg)
688         {
689             Object[] args = (Object[])arg;
690             String friendlyName = (String)args[0];
691             AppDomainSetup setup = (AppDomainSetup)args[1];
692             string[] propertyNames = (string[])args[2]; // can contain null elements
693             string[] propertyValues = (string[])args[3]; // can contain null elements
694
695             AppDomain ad = AppDomain.CurrentDomain;
696             AppDomainSetup newSetup = new AppDomainSetup(setup, false);
697
698             if (propertyNames != null && propertyValues != null)
699             {
700                 for (int i = 0; i < propertyNames.Length; i++)
701                 {
702                     // We want to set native dll probing directories before any P/Invokes have a
703                     // chance to fire. The Path class, for one, has P/Invokes.
704                     if (propertyNames[i] == "NATIVE_DLL_SEARCH_DIRECTORIES")
705                     {
706                         if (propertyValues[i] == null)
707                             throw new ArgumentNullException("NATIVE_DLL_SEARCH_DIRECTORIES");
708
709                         string paths = propertyValues[i];
710                         if (paths.Length == 0)
711                             break;
712
713                         nSetNativeDllSearchDirectories(paths);
714                     }
715                 }
716
717                 for (int i = 0; i < propertyNames.Length; i++)
718                 {
719                     if (propertyNames[i] == "APPBASE") // make sure in sync with Fusion
720                     {
721                         if (propertyValues[i] == null)
722                             throw new ArgumentNullException("APPBASE");
723
724                         if (PathInternal.IsPartiallyQualified(propertyValues[i]))
725                             throw new ArgumentException(SR.Argument_AbsolutePathRequired);
726
727                         newSetup.ApplicationBase = NormalizePath(propertyValues[i], fullCheck: true);
728                     }
729                     else if (propertyNames[i] == "TRUSTED_PLATFORM_ASSEMBLIES" ||
730                        propertyNames[i] == "PLATFORM_RESOURCE_ROOTS" ||
731                        propertyNames[i] == "APP_PATHS" ||
732                        propertyNames[i] == "APP_NI_PATHS")
733                     {
734                         string values = propertyValues[i];
735                         if (values == null)
736                             throw new ArgumentNullException(propertyNames[i]);
737
738                         ad.SetData(propertyNames[i], NormalizeAppPaths(values));
739                     }
740                     else if (propertyNames[i] != null)
741                     {
742                         ad.SetData(propertyNames[i], propertyValues[i]);     // just propagate
743                     }
744                 }
745             }
746
747             ad.SetupFusionStore(newSetup, null); // makes FusionStore a ref to newSetup
748
749             // technically, we don't need this, newSetup refers to the same object as FusionStore 
750             // but it's confusing since it isn't immediately obvious whether we have a ref or a copy
751             AppDomainSetup adSetup = ad.FusionStore;
752
753             // set up the friendly name
754             ad.nSetupFriendlyName(friendlyName);
755
756             ad.CreateAppDomainManager(); // could modify FusionStore's object
757
758             return null;
759         }
760
761         private static string NormalizeAppPaths(string values)
762         {
763             int estimatedLength = values.Length + 1; // +1 for extra separator temporarily added at end
764             StringBuilder sb = StringBuilderCache.Acquire(estimatedLength);
765
766             for (int pos = 0; pos < values.Length; pos++)
767             {
768                 string path;
769
770                 int nextPos = values.IndexOf(Path.PathSeparator, pos);
771                 if (nextPos == -1)
772                 {
773                     path = values.Substring(pos);
774                     pos = values.Length - 1;
775                 }
776                 else
777                 {
778                     path = values.Substring(pos, nextPos - pos);
779                     pos = nextPos;
780                 }
781
782                 // Skip empty directories
783                 if (path.Length == 0)
784                     continue;
785
786                 if (PathInternal.IsPartiallyQualified(path))
787                     throw new ArgumentException(SR.Argument_AbsolutePathRequired);
788
789                 string appPath = NormalizePath(path, fullCheck: true);
790                 sb.Append(appPath);
791                 sb.Append(Path.PathSeparator);
792             }
793
794             // Strip the last separator
795             if (sb.Length > 0)
796             {
797                 sb.Remove(sb.Length - 1, 1);
798             }
799
800             return StringBuilderCache.GetStringAndRelease(sb);
801         }
802
803         internal static string NormalizePath(string path, bool fullCheck)
804         {
805             return Path.GetFullPath(path);
806         }
807
808         // This routine is called from unmanaged code to
809         // set the default fusion context.
810         private void SetupDomain(bool allowRedirects, String path, String configFile, String[] propertyNames, String[] propertyValues)
811         {
812             // It is possible that we could have multiple threads initializing
813             // the default domain. We will just take the winner of these two.
814             // (eg. one thread doing a com call and another doing attach for IJW)
815             lock (this)
816             {
817                 if (_FusionStore == null)
818                 {
819                     AppDomainSetup setup = new AppDomainSetup();
820
821                     // always use internet permission set
822                     SetupFusionStore(setup, null);
823                 }
824             }
825         }
826
827         [MethodImplAttribute(MethodImplOptions.InternalCall)]
828         private extern void nSetupFriendlyName(string friendlyName);
829
830         public AppDomainSetup SetupInformation
831         {
832             get
833             {
834                 return new AppDomainSetup(FusionStore, true);
835             }
836         }
837
838         [MethodImplAttribute(MethodImplOptions.InternalCall)]
839         internal extern String IsStringInterned(String str);
840
841         [MethodImplAttribute(MethodImplOptions.InternalCall)]
842         internal extern String GetOrInternString(String str);
843
844         public bool IsFullyTrusted
845         {
846             get
847             {
848                 return true;
849             }
850         }
851
852         public Int32 Id
853         {
854             get
855             {
856                 return GetId();
857             }
858         }
859
860         [MethodImplAttribute(MethodImplOptions.InternalCall)]
861         internal extern Int32 GetId();
862     }
863
864     /// <summary>
865     ///     Handle used to marshal an AppDomain to the VM (eg QCall). When marshaled via a QCall, the target
866     ///     method in the VM will receive a QCall::AppDomainHandle parameter.
867     /// </summary>
868     internal struct AppDomainHandle
869     {
870         private IntPtr m_appDomainHandle;
871
872         // Note: generall an AppDomainHandle should not be directly constructed, instead the
873         // code:System.AppDomain.GetNativeHandle method should be called to get the handle for a specific
874         // AppDomain.
875         internal AppDomainHandle(IntPtr domainHandle)
876         {
877             m_appDomainHandle = domainHandle;
878         }
879     }
880 }