File: ProcessHost.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (1376 lines) | stat: -rw-r--r-- 57,297 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
//------------------------------------------------------------------------------
// <copyright file="ProcessHost.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

namespace System.Web.Hosting {
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Diagnostics.CodeAnalysis;
    using System.IO;
    using System.Runtime.ExceptionServices;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Security;
    using System.Security.Permissions;
    using System.Threading;
    using System.Web;
    using System.Web.Configuration;
    using System.Web.Util;


    [ComImport, Guid("0ccd465e-3114-4ca3-ad50-cea561307e93"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IProcessHost {

        void StartApplication(
                [In, MarshalAs(UnmanagedType.LPWStr)]
                String appId,
                [In, MarshalAs(UnmanagedType.LPWStr)]
                String appPath,
                [MarshalAs(UnmanagedType.Interface)] out Object runtimeInterface);

        void ShutdownApplication([In, MarshalAs(UnmanagedType.LPWStr)] String appId);

        void Shutdown();

        void EnumerateAppDomains( [MarshalAs(UnmanagedType.Interface)] out IAppDomainInfoEnum appDomainInfoEnum);

    }

    // Used by webengine4.dll for launching Helios applications via ProcessHost.

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("E2A1F244-70EB-483A-ACC8-DE6ACE5BF8B1")]
    internal interface IProcessHostLite {
        [return: MarshalAs(UnmanagedType.Interface)]
        IObjectHandle GetCustomLoader(
            [In, MarshalAs(UnmanagedType.LPWStr)] string appId,
            [In, MarshalAs(UnmanagedType.LPWStr)] string appConfigPath,
            [Out, MarshalAs(UnmanagedType.Interface)] out IProcessHostSupportFunctions supportFunctions,
            [Out, MarshalAs(UnmanagedType.Interface)] out AppDomain newlyCreatedAppDomain);

        void ReportCustomLoaderError(
            [In, MarshalAs(UnmanagedType.LPWStr)] string appId,
            [In] int hr,
            [In, MarshalAs(UnmanagedType.Interface)] AppDomain newlyCreatedAppDomain);

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetFullExceptionMessage(
            [In] int hr,
            [In] IntPtr pErrorInfo);
    }

    //
    // App domain protocol manager
    // Note that this doesn't provide COM interop
    //

    public interface IAdphManager {

        void StartAppDomainProtocolListenerChannel(
            [In, MarshalAs(UnmanagedType.LPWStr)] String appId,
            [In, MarshalAs(UnmanagedType.LPWStr)] String protocolId,
            IListenerChannelCallback listenerChannelCallback);

        void StopAppDomainProtocolListenerChannel(
            [In, MarshalAs(UnmanagedType.LPWStr)] String appId,
            [In, MarshalAs(UnmanagedType.LPWStr)] String protocolId,
            int listenerChannelId,
            bool immediate);

        void StopAppDomainProtocol(
            [In, MarshalAs(UnmanagedType.LPWStr)] String appId,
            [In, MarshalAs(UnmanagedType.LPWStr)] String protocolId,
            bool immediate);
    }

    [ComImport, Guid("1cc9099d-0a8d-41cb-87d6-845e4f8c4e91"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPphManager {

        void StartProcessProtocolListenerChannel(
            [In, MarshalAs(UnmanagedType.LPWStr)] String protocolId,
            IListenerChannelCallback listenerChannelCallback);

        void StopProcessProtocolListenerChannel(
            [In, MarshalAs(UnmanagedType.LPWStr)] String protocolId,
            int listenerChannelId,
            bool immediate);

        void StopProcessProtocol(
            [In, MarshalAs(UnmanagedType.LPWStr)] String protocolId,
            bool immediate);
    }


    [ComImport, Guid("9d98b251-453e-44f6-9cec-8b5aed970129"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IProcessHostIdleAndHealthCheck {

        [return: MarshalAs(UnmanagedType.Bool)]
        bool IsIdle();

        void Ping(IProcessPingCallback callback);
    }


    [ComImport, Guid("5BC9C234-6CD7-49bf-A07A-6FDB7F22DFFF"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IAppDomainInfo {
        [return: MarshalAs(UnmanagedType.BStr)]
        string GetId();

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetVirtualPath();

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetPhysicalPath();

        [return: MarshalAs(UnmanagedType.I4)]
        int GetSiteId();

        [return: MarshalAs(UnmanagedType.Bool)]
        bool IsIdle();
    }

    [ComImport, Guid("F79648FB-558B-4a09-88F1-1E3BCB30E34F"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IAppDomainInfoEnum {
        [return: MarshalAs(UnmanagedType.Interface)]
        IAppDomainInfo GetData();

        [return: MarshalAs(UnmanagedType.I4)]
        int Count();

        [return: MarshalAs(UnmanagedType.Bool)]
        bool MoveNext();

        void Reset();
    }

    public class AppDomainInfoEnum : IAppDomainInfoEnum
    {
        private AppDomainInfo[] _appDomainInfos;
        private int _curPos;

        internal AppDomainInfoEnum(AppDomainInfo[] appDomainInfos)
        {
            _appDomainInfos = appDomainInfos;
            _curPos = -1;
        }

        public int Count()
        {
            return _appDomainInfos.Length;
        }

        public IAppDomainInfo GetData()
        {
            return _appDomainInfos[_curPos];
        }

        public bool MoveNext()
        {
            _curPos++;

            if (_curPos >= _appDomainInfos.Length)
            {
                return false;
            }

            return true;
        }

        public void Reset()
        {
            _curPos = -1;
        }
    }

    public class AppDomainInfo : IAppDomainInfo
    {
        private string _id;
        private string _virtualPath;
        private string _physicalPath;
        private int _siteId;
        private bool _isIdle;

        internal AppDomainInfo(string id, string vpath, string physPath, int siteId, bool isIdle)
        {
            _id = id;
            _virtualPath = vpath;
            _physicalPath = physPath;
            _siteId = siteId;
            _isIdle = isIdle;
        }

        public string GetId()
        {
            return _id;
        }

        public string GetVirtualPath()
        {
            return _virtualPath;
        }

        public string GetPhysicalPath()
        {
            return _physicalPath;
        }

        public int GetSiteId()
        {
            return _siteId;
        }

        public bool IsIdle()
        {
            return _isIdle;
        }
    }

    /////////////////////////////////////////////////////////////////////////////
    // New for Dev10
    [ComImport, Guid("AE54F424-71BC-4da5-AA2F-8C0CD53496FC"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IApplicationPreloadManager {
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId="Util",
                         Justification="Name must match IIS COM interface.")]
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId="0#Util",
                         Justification="Name must match IIS COM interface.")]
        void SetApplicationPreloadUtil(
            [In, MarshalAs(UnmanagedType.Interface)] IApplicationPreloadUtil preloadUtil);

        void SetApplicationPreloadState(
            [In, MarshalAs(UnmanagedType.LPWStr)] string context,
            [In, MarshalAs(UnmanagedType.LPWStr)] string appId,
            [In, MarshalAs(UnmanagedType.Bool)]  bool enabled);
    }

    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId="Util",
                     Justification="Name must match IIS COM interface.")]
    [ComImport, Guid("940D8ADD-9E40-4475-9A67-2CDCDF57995C"), InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IApplicationPreloadUtil {

        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId="1#",
                         Justification="Parameter kind must match IIS COM interface.")]
        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId="2#",
                         Justification="Parameter kind must match IIS COM interface.")]
        [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId="3#",
                         Justification="Parameter kind must match IIS COM interface.")]
        void GetApplicationPreloadInfo(
            [In, MarshalAs(UnmanagedType.LPWStr)] string context,
            [Out, MarshalAs(UnmanagedType.Bool)] out bool enabled,
            [Out, MarshalAs(UnmanagedType.BStr)] out string startupObjType,
            [Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] out string[] parametersForStartupObj);

        void ReportApplicationPreloadFailure(
            [In, MarshalAs(UnmanagedType.LPWStr)] string context,
            [In, MarshalAs(UnmanagedType.U4)] int errorCode,
            [In, MarshalAs(UnmanagedType.LPWStr)] string errorMessage);
    }


    /// <include file='doc\ProcessHost.uex' path='docs/doc[@for="ProcessHost"]/*' />
    public sealed class ProcessHost : MarshalByRefObject,
                                      IProcessHost,
                                      IProcessHostLite,
                                      ICustomRuntimeManager,
                                      IAdphManager, // process protocol handlers manager
                                      IPphManager,  // appdomain protocol handlers manager
                                      IProcessHostIdleAndHealthCheck,
                                      IProcessSuspendListener,
                                      IApplicationPreloadManager {
        private static Object _processHostStaticLock = new Object();
        private static ProcessHost _theProcessHost;

        [ThreadStatic]
        private static KeyValuePair<string, ExceptionDispatchInfo> _customLoaderStartupError;

        private readonly CustomRuntimeManager _customRuntimeManager = new CustomRuntimeManager();

        private IProcessHostSupportFunctions _functions;
        private ApplicationManager _appManager;
        private ProtocolsSection _protocolsConfig;

        // process protocol handlers by prot id
        private Hashtable _protocolHandlers = new Hashtable();
        private IApplicationPreloadUtil _preloadUtil = null;

        private System.Threading.Semaphore _preloadingThrottle = null;

        private ProtocolsSection ProtocolsConfig {
            get {
                if (_protocolsConfig == null) {
                    lock (this) {
                        if (_protocolsConfig == null) {

                            if (HttpConfigurationSystem.IsSet) {
                                _protocolsConfig = RuntimeConfig.GetRootWebConfig().Protocols;
                            } else {
                                Configuration c = WebConfigurationManager.OpenWebConfiguration(null);
                                _protocolsConfig = (ProtocolsSection) c.GetSection("system.web/protocols");
                            }

                        }
                    }
                }
                return _protocolsConfig;
            }
        }

        // ctor only called via GetProcessHost
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reading this particular registry value is safe.")]
        private ProcessHost(IProcessHostSupportFunctions functions) {
            try {
                // remember support functions
                _functions = functions;

                // pass them along to the HostingEnvironment in the default domain
                HostingEnvironment.SupportFunctions = functions;

                // create singleton app manager
                _appManager = ApplicationManager.GetApplicationManager();

                // For M3 we get the throttling limit from the registry.
                // Dev10\Beta1 work item 543420 is to investigate whether we need to get rid of the throttling
                int maxPreloadConcurrency = (int)Misc.GetAspNetRegValue(null, "MaxPreloadConcurrency", 0);
                if (maxPreloadConcurrency > 0) {
                    _preloadingThrottle = new System.Threading.Semaphore(maxPreloadConcurrency, maxPreloadConcurrency);
                }


            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[]
                                                  { SR.GetString(SR.Cant_Create_Process_Host)});
                    Debug.Trace("internal", "ProcessHost::ctor failed with " + e.GetType().FullName + ": " + e.Message + "\r\n" + e.StackTrace);
                }
                throw;
            }
        }

        // ValidateType
        //
        // Validate and Get the Type that is sent in
        //
        // Note: Because ProtocolElement is outside of our assembly we need to do
        //       that here, and because of that we need to hardcode the property
        //       names!!
        //
        private Type ValidateAndGetType( ProtocolElement element,
                                         string          typeName,
                                         Type            assignableType,
                                         string          elementPropertyName ) {
            Type handlerType;

            try {
                 handlerType = Type.GetType(typeName, true /*throwOnError*/);
            }
            catch (Exception e) {

                PropertyInformation propInfo = null;
                string source = String.Empty;
                int lineNum = 0;

                if (element != null  && null != element.ElementInformation) {
                    propInfo = element.ElementInformation.Properties[elementPropertyName];

                    if (null != propInfo) {
                        source = propInfo.Source;
                        lineNum = propInfo.LineNumber;
                    }

                }

                throw new ConfigurationErrorsException(
                            e.Message,
                            e,
                            source,
                            lineNum);
            }

            ConfigUtil.CheckAssignableType( assignableType, handlerType, element, elementPropertyName);

            return handlerType;
        }

        private Type GetAppDomainProtocolHandlerType(String protocolId) {
            Type t = null;

            try {
                // get app domaoin protocol handler type from config
                ProtocolElement configEntry = ProtocolsConfig.Protocols[protocolId];
                if (configEntry == null)
                    throw new ArgumentException(SR.GetString(SR.Unknown_protocol_id, protocolId));

                    t = ValidateAndGetType( configEntry,
                                       configEntry.AppDomainHandlerType,
                                       typeof(AppDomainProtocolHandler),
                                       "AppDomainHandlerType" );
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Invalid_AppDomain_Prot_Type)} );
                }
            }

            return t;
        }

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public override Object InitializeLifetimeService() {
            return null; // never expire lease
        }

        // called from ProcessHostFactoryHelper to get ProcessHost
        internal static ProcessHost GetProcessHost(IProcessHostSupportFunctions functions) {
            if (_theProcessHost == null) {
                lock (_processHostStaticLock) {
                    if (_theProcessHost == null) {
                        _theProcessHost = new ProcessHost(functions);
                    }
                }
            }

            return _theProcessHost;
        }

        internal static ProcessHost DefaultHost {
            get {
                return _theProcessHost; // may be null
            }
        }

        internal IProcessHostSupportFunctions SupportFunctions {
            get {
                return _functions;
            }
        }

        //
        // IProcessHostProcessProtocolManager interface implementation
        //

        // starts process protocol handler on demand
        public void StartProcessProtocolListenerChannel(String protocolId, IListenerChannelCallback listenerChannelCallback) {
            try {
                if (protocolId == null)
                    throw new ArgumentNullException("protocolId");

                // validate protocol id
                ProtocolElement configEntry = ProtocolsConfig.Protocols[protocolId];
                if (configEntry == null)
                    throw new ArgumentException(SR.GetString(SR.Unknown_protocol_id, protocolId));

                ProcessProtocolHandler protocolHandler = null;
                Type                   protocolHandlerType = null;

                protocolHandlerType = ValidateAndGetType( configEntry,
                                                          configEntry.ProcessHandlerType,
                                                          typeof(ProcessProtocolHandler),
                                                          "ProcessHandlerType" );

                lock (this) {
                    // lookup or create protocol handler
                    protocolHandler = _protocolHandlers[protocolId] as ProcessProtocolHandler;

                    if (protocolHandler == null) {
                        protocolHandler = (ProcessProtocolHandler)Activator.CreateInstance(protocolHandlerType);
                        _protocolHandlers[protocolId] = protocolHandler;
                    }

                }

                // call the handler to start listenerChannel
                if (protocolHandler != null) {
                    protocolHandler.StartListenerChannel(listenerChannelCallback, this);
                }
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Invalid_Process_Prot_Type)} );
                }
                throw;
            }
        }

        public void StopProcessProtocolListenerChannel(String protocolId, int listenerChannelId, bool immediate) {
            try {
                if (protocolId == null)
                    throw new ArgumentNullException("protocolId");

                ProcessProtocolHandler protocolHandler = null;

                lock (this) {
                    // lookup protocol handler
                    protocolHandler = _protocolHandlers[protocolId] as ProcessProtocolHandler;
                }

                // call the handler to stop listenerChannel
                if (protocolHandler != null) {
                    protocolHandler.StopListenerChannel(listenerChannelId, immediate);
                }
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_Stop_Listener_Channel)} );
                }
                throw;
            }
        }


        public void StopProcessProtocol(String protocolId, bool immediate) {
            try {
                if (protocolId == null)
                    throw new ArgumentNullException("protocolId");

                ProcessProtocolHandler protocolHandler = null;

                lock (this) {
                    // lookup and remove protocol handler
                    protocolHandler = _protocolHandlers[protocolId] as ProcessProtocolHandler;

                    if (protocolHandler != null) {
                        _protocolHandlers.Remove(protocolId);
                    }
                }

                if (protocolHandler != null) {
                    protocolHandler.StopProtocol(immediate);
                }
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_Stop_Process_Prot)} );
                }
                throw;
            }
        }

        //
        // IAppDomainProtocolManager
        //

        // starts app domain protocol handler on demand (called by process protocol handler

        public void StartAppDomainProtocolListenerChannel(String appId, String protocolId, IListenerChannelCallback listenerChannelCallback) {
            try {
                if (appId == null)
                    throw new ArgumentNullException("appId");
                if (protocolId == null)
                    throw new ArgumentNullException("protocolId");

                ISAPIApplicationHost appHost = CreateAppHost(appId, null);

                // get app domain protocol handler type from config
                Type handlerType = GetAppDomainProtocolHandlerType(protocolId);

                AppDomainProtocolHandler handler = null;

                LockableAppDomainContext ac = _appManager.GetLockableAppDomainContext(appId);

                lock (ac) {
                    HostingEnvironmentParameters hostingParameters = new HostingEnvironmentParameters();
                    hostingParameters.HostingFlags = HostingEnvironmentFlags.ThrowHostingInitErrors;
                    
                    PreloadApplicationIfRequired(appId, appHost, hostingParameters, ac);

                    // call app manager to create the handler
                    handler = (AppDomainProtocolHandler)_appManager.CreateObjectInternal(
                        appId, handlerType, appHost, false /*failIfExists*/,
                        hostingParameters);

                    // create a shim object that we can use for proxy unwrapping
                    ListenerAdapterDispatchShim shim = (ListenerAdapterDispatchShim)
                        _appManager.CreateObjectInternal(
                            appId, typeof(ListenerAdapterDispatchShim), appHost, false /*failIfExists*/,
                            hostingParameters);

                    if (null != shim) {
                        shim.StartListenerChannel(handler, listenerChannelCallback);

                        // remove the shim
                        ((IRegisteredObject)shim).Stop(true);
                    }
                    else {
                        throw new HttpException(SR.GetString(SR.Failure_Create_Listener_Shim));
                    }
                }
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_Start_AppDomain_Listener)} );
                }
                throw;
            }
        }


        public void StopAppDomainProtocolListenerChannel(String appId, String protocolId, int listenerChannelId, bool immediate) {
            try {
                if (appId == null)
                    throw new ArgumentNullException("appId");
                if (protocolId == null)
                    throw new ArgumentNullException("protocolId");

                // get app domaoin protocol handler type from config
                Type handlerType = GetAppDomainProtocolHandlerType(protocolId);

                AppDomainProtocolHandler handler = null;

                LockableAppDomainContext ac = _appManager.GetLockableAppDomainContext(appId);
                lock (ac) {
                    // call app manager to create the handler
                    handler = (AppDomainProtocolHandler)_appManager.GetObject(appId, handlerType);
                }

                // stop the listenerChannel
                if (handler != null) {
                    handler.StopListenerChannel(listenerChannelId, immediate);
                }
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_Stop_AppDomain_Listener)} );
                }
                throw;
            }
        }


        public void StopAppDomainProtocol(String appId, String protocolId, bool immediate) {
            try {
                if (appId == null)
                    throw new ArgumentNullException("appId");
                if (protocolId == null)
                    throw new ArgumentNullException("protocolId");

                // get app domaoin protocol handler type from config
                Type handlerType = GetAppDomainProtocolHandlerType(protocolId);

                AppDomainProtocolHandler handler = null;

                LockableAppDomainContext ac = _appManager.GetLockableAppDomainContext(appId);
                lock (ac) {
                    // call app manager to create the handler
                    handler = (AppDomainProtocolHandler)_appManager.GetObject(appId, handlerType);
                }

                // stop protocol
                if (handler != null) {
                    handler.StopProtocol(immediate);
                }
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_Stop_AppDomain_Protocol)} );
                }
                throw;
            }
        }

        public void StartApplication(String appId, String appPath, out Object runtimeInterface)
        {
            try {
                if (appId == null)
                    throw new ArgumentNullException("appId");
                if (appPath == null)
                    throw new ArgumentNullException("appPath");

                Debug.Assert(_functions != null, "_functions != null");

                runtimeInterface = null;

                PipelineRuntime runtime = null;

                //
                //  Fill app a Dictionary with 'binding rules' -- name value string pairs
                //  for app domain creation
                //

                // 


                if (appPath[0] == '.') {
                    System.IO.FileInfo file = new System.IO.FileInfo(appPath);
                    appPath = file.FullName;
                }

                if (!StringUtil.StringEndsWith(appPath, '\\')) {
                    appPath = appPath + "\\";
                }

                // Create new app host of a consistent type
                IApplicationHost appHost = CreateAppHost(appId, appPath);


                //
                // Create the AppDomain and a registered object in it
                //
                LockableAppDomainContext ac = _appManager.GetLockableAppDomainContext(appId);

                lock (ac) {
                    // #1 WOS 1690249: ASP.Net v2.0: ASP.NET stress: 2nd chance exception: Attempted to access an unloaded AppDomain.
                    // if an old AppDomain exists with a PipelineRuntime, remove it from
                    // AppManager._appDomains so that a new AppDomain will be created
                    // #2 WOS 1977425: ASP.NET apps continue recycling after touching machine.config once - this used to initiate shutdown,
                    // but that can cause us to recycle the app repeatedly if we initiate shutdown before IIS initiates shutdown of the
                    // previous app.

                    _appManager.RemoveFromTableIfRuntimeExists(appId, typeof(PipelineRuntime));


                    // Preload (if required) the App Domain before letting the first request to be processed
                    PreloadApplicationIfRequired(appId, appHost, null, ac);

                    try {
                        runtime = (PipelineRuntime)_appManager.CreateObjectInternal(
                            appId,
                            typeof(PipelineRuntime),
                            appHost,
                            true /* failIfExists */,
                            null /* default */ );
                    }
                    catch (AppDomainUnloadedException) {
                        // munch it so we can retry again
                    }

                    if (null != runtime) {
                        runtime.SetThisAppDomainsIsapiAppId(appId);
                        runtime.StartProcessing();
                        runtimeInterface = new ObjectHandle(runtime);
                    }
                }
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_Start_Integrated_App)} );
                }
                throw;
            }
        }


        public void ShutdownApplication(String appId) {
            try {
                // call into app manager
                _appManager.ShutdownApplication(appId);
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_Stop_Integrated_App)} );
                }
                throw;
            }
        }

        public void Shutdown() {
            try {
                // collect all protocols under lock
                ArrayList protocolList = new ArrayList();
                int       refCount = 0;

                lock (this) {
                    // lookup protocol handler
                    foreach (DictionaryEntry e in _protocolHandlers) {
                        protocolList.Add(e.Value);
                    }

                    _protocolHandlers = new Hashtable();
                }

                // stop all process protocols outside of lock
                foreach (ProcessProtocolHandler p in protocolList) {
                    p.StopProtocol(true);
                }

                // call into app manager to shutdown
                _appManager.ShutdownAll();


                // SupportFunctions interface provided by native layer
                // must be released now.
                // Otherwise the release of the COM object will have
                // to wait for GC. Native layer assumes that after
                // returning from Shutdown there is no reference
                // to the native objects from ProcessHost.
                //
                do {
                    refCount = Marshal.ReleaseComObject( _functions );
                } while( refCount != 0 );

            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_Shutdown_ProcessHost), e.ToString()} );
                }
                throw;
            }
        }

        [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", Justification = "See comment for why we're calling GC.Collect.")]
        IProcessResumeCallback IProcessSuspendListener.Suspend() {
            object resumeState = _appManager.SuspendAllApplications();
            Action customRuntimeResumeCallback = _customRuntimeManager.SuspendAllCustomRuntimes();

            IProcessResumeCallback callback = new SimpleProcessResumeCallbackDispatcher(() => {
                _appManager.ResumeAllApplications(resumeState);
                if (customRuntimeResumeCallback != null) {
                    customRuntimeResumeCallback();
                }
            });

            // Per CLR team's suggestion, we perform one final GC to try to free
            // any pages that can be reclaimed. Ideally we would do this in the
            // unmanaged layer, but the ICLRGCManager is unavailable to us at the
            // time we would need to perform a collection. So we'll do it here
            // instead.
            GC.Collect();

            return callback;
        }

        ICustomRuntimeRegistrationToken ICustomRuntimeManager.Register(ICustomRuntime customRuntime) {
            Debug.Assert(customRuntime != null);
            return _customRuntimeManager.Register(customRuntime);
        }

        public void EnumerateAppDomains( out IAppDomainInfoEnum appDomainInfoEnum )
        {
            try {
                ApplicationManager appManager = ApplicationManager.GetApplicationManager();
                AppDomainInfo [] infos;

                infos = appManager.GetAppDomainInfos();

                appDomainInfoEnum = new AppDomainInfoEnum(infos);
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_AppDomain_Enum)} );
                }
                throw;
            }
        }

        // IProcessHostIdleAndHealthCheck interface implementation
        public bool IsIdle() {
            bool result = false;

            try {
                result = _appManager.IsIdle();
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_PMH_Idle)} );
                }
                throw;
            }

            return result;
        }


        public void Ping(IProcessPingCallback callback) {
            try {
                if (callback != null)
                    _appManager.Ping(callback);
            }
            catch (Exception e) {
                using (new ProcessImpersonationContext()) {
                    Misc.ReportUnhandledException(e, new string[] {
                                              SR.GetString(SR.Failure_PMH_Ping)} );
                }
                throw;
            }
        }

        // Users cannot provide any call stack that eventually leads to this method, as it will fail at some
        // point with a NullReferenceException. The ASP.NET runtime is the only entity that can call this
        // without something failing, and those call sites are safe.
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "See comment above.")]
        private ISAPIApplicationHost CreateAppHost(string appId, string appPath) {

            //
            // if we have a null physical path, we need
            // to use the PMH to resolve it
            //
            if (String.IsNullOrEmpty(appPath)) {
                string virtualPath;
                string physicalPath;
                string siteName;
                string siteID;

                _functions.GetApplicationProperties(
                        appId,
                        out virtualPath,
                        out physicalPath,
                        out siteName,
                        out siteID);

                //
                // make sure physical app path ends with '\\' and virtual does not
                //
                if (!StringUtil.StringEndsWith(physicalPath, '\\')) {
                    physicalPath = physicalPath + "\\";
                }

                Debug.Assert( !String.IsNullOrEmpty(physicalPath), "!String.IsNullOrEmpty(physicalPath)");
                appPath = physicalPath;
            }

            //
            // Create a new application host
            // This needs to be a coherent type across all
            // protocol types so that we get a consistent
            // environment regardless of which protocol initializes first
            //
            ISAPIApplicationHost appHost = new
                ISAPIApplicationHost(
                        appId,
                        appPath,
                        false, /* validatePhysicalPath */
                        _functions
                        );


            return appHost;
        }

        public void SetApplicationPreloadUtil(IApplicationPreloadUtil applicationPreloadUtil) {

            // Do not allow setting PreloadUtil again if it has already has been set
            if (_preloadUtil != null) {
                throw new InvalidOperationException(SR.GetString(SR.Failure_ApplicationPreloadUtil_Already_Set));
            }

            _preloadUtil = applicationPreloadUtil;
        }

        public void SetApplicationPreloadState(string context, string appId, bool enabled) {
            // Check params
            if (String.IsNullOrEmpty(context)) {
                throw ExceptionUtil.ParameterNullOrEmpty("context");
            }
            if (String.IsNullOrEmpty(appId)) {
                throw ExceptionUtil.ParameterNullOrEmpty("appId");
            }

            // _preloadUtil must be not null if we have an application preload enabled
            if (enabled && _preloadUtil == null) {
                throw new ArgumentException(SR.GetString(SR.Invalid_Enabled_Preload_Parameter), "enabled");
            }

            LockableAppDomainContext ac = _appManager.GetLockableAppDomainContext(appId);

            lock (ac) {
                ac.PreloadContext = context;
                if (enabled) {
                    PreloadApplicationIfRequired(appId, null, null, ac);
                }
            }
        }

        internal static void PreloadApplicationIfNotShuttingdown (string appId, LockableAppDomainContext ac) {
            // If GL_STOP_LISTENING wasn't triggered, the reset is likely due to a configuration change.
            if (ProcessHost.DefaultHost != null && !UnsafeIISMethods.MgdIsAppPoolShuttingDown()) {
                // Start the new app on another thread instead of hijacking the current app unloading thread
                ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o) {
                    lock (ac) {
                        try {
                            // NOTE: we don't know what HostingEnvironmentParameters were passed to our previous application instance
                            // so we pass null (default for HTTP activation). We could have cached it in ApplicationContext if needed
                            ProcessHost.DefaultHost.PreloadApplicationIfRequired(appId, null, null, ac);
                        }
                        catch (Exception e) {
                            ProcessHost.DefaultHost.ReportApplicationPreloadFailureWithAssert(
                                ac.PreloadContext,
                                HResults.E_FAIL,
                                Misc.FormatExceptionMessage(
                                    e, new string[] { 
                                        SR.GetString(SR.Failure_Preload_Application_Initialization)}));
                        }
                    }
                }));
            }
        }

        // New for Dev10. 
        // creates a new AppDomain, preloads and calls user code in it
        internal void PreloadApplicationIfRequired(
                string appId, 
                IApplicationHost appHostParameter,
                HostingEnvironmentParameters hostingParameters, 
                LockableAppDomainContext ac) {

            // NOTE1:  Must never be called under lock (_appManager)
            // NOTE2:  Must always be called under lock (ac)
    
            // We only need to preload if auto start is enabled and we have not already preloaded (i.e. HostingEnvironment doesn't exist)
            if (_preloadUtil == null || ac.PreloadContext == null || ac.HostEnv != null) {
                return;
            }

            // Get and verify the preload parameters 
            string preloadObjTypeName;
            string[] paramsForStartupObj;
            bool stillEnabled;

            GetApplicationPreloadInfoWithAssert(ac.PreloadContext, out stillEnabled, out preloadObjTypeName, out paramsForStartupObj);
            
            // Dev10: 782385	ASP.NET autostart implementation should be tolerant of empty string for the provider type
            if (!stillEnabled || String.IsNullOrEmpty(preloadObjTypeName)) {
                return;
            }

            // Ready to load the App Domain
            if (_preloadingThrottle != null) {
                // Throttle the number of simultaneously created appdomains
                _preloadingThrottle.WaitOne();
            }

            try {
                
                // Create the app-host and start a new App Domain
                IApplicationHost appHost = (appHostParameter == null) ? CreateAppHost(appId, null) : appHostParameter;
                
                // call app manager to create the PreloadHost
                PreloadHost preloadHostObj = (PreloadHost)_appManager.CreateObjectInternal(
                    appId, 
                    typeof(PreloadHost), 
                    appHost, 
                    true /*failIfExists*/, 
                    hostingParameters);
                
                // Dev10 858421:  File sharing violations on config files cause unnecessary process shutdown in autostart mode
                // 
                // There are race conditions between whoever modifies the config files 
                // and the application config system that reads from the config files
                // These file sharing violation lead to random application initialization failures
                // Service auto-start mode is more vulnerable to these sharing violations because 
                // it starts a new app domain as soon as the file change notification is received
                // and when an error occurs IIS recycles the whole app pool rather than a particular app
                // 
                // In most cases that we see in stress the inner most exception is System.IO.IOException 
                // so if we see this exception we will give it another try before
                // reporting the errors to IIS and recycling the process
                // 

                // Check for I/O exceptions during initialization and retry one time
                Exception appInitEx = preloadHostObj.InitializationException;
                if (GetInnerMostException(appInitEx) is IOException) {
                    try {
                        // prevent ApplicationManager.HostingEnvironmentShutdownInitiated from attempting to preload again
                        ac.RetryingPreload = true;
                        // shutdown old hosting environment
                        ac.HostEnv.InitiateShutdownInternal();
                    }
                    finally {
                        ac.RetryingPreload = false;
                    }

                    // Create the app-host and start a new App Domain
                    appHost = (appHostParameter == null) ? CreateAppHost(appId, null) : appHostParameter;
                
                    // call app manager to create the PreloadHost
                    preloadHostObj = (PreloadHost)_appManager.CreateObjectInternal(
                        appId, 
                        typeof(PreloadHost), 
                        appHost, 
                        true /*failIfExists*/, 
                        hostingParameters);

                    appInitEx = preloadHostObj.InitializationException;
                }

                // Check again for initialization exception and tell IIS to recycle the process
                if (appInitEx != null) {
                    ReportApplicationPreloadFailureWithAssert(
                        ac.PreloadContext,
                        HResults.E_FAIL,
                        Misc.FormatExceptionMessage(
                            appInitEx, new string[] { 
                                SR.GetString(SR.Failure_Preload_Application_Initialization)} ));

                    // we must throw if preload fails because we cannot allow the normal
                    // startup path to continue and attempt to create a HostingEnvironment
                    throw appInitEx;
                }

                // Call preload code in the App Domain
                try {
                    preloadHostObj.CreateIProcessHostPreloadClientInstanceAndCallPreload(preloadObjTypeName, paramsForStartupObj);
                }
                catch (Exception e) {
                    // report errors
                    ReportApplicationPreloadFailureWithAssert(
                        ac.PreloadContext,
                        HResults.E_FAIL,
                        Misc.FormatExceptionMessage(
                            e, new string[] {
                                SR.GetString(SR.Failure_Calling_Preload_Provider)} ).ToString());

                    throw;
                }
            }
            finally {
                if (_preloadingThrottle != null) {
                    _preloadingThrottle.Release();
                }
            }

        }

        private static Exception GetInnerMostException(Exception e) {
            if (e == null) {
                return null;
            }
            while (e.InnerException != null) {
                e = e.InnerException;
            }
            return e;
        }

        [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
        private void GetApplicationPreloadInfoWithAssert(
                string context, out bool enabled, out string startupObjType, out string[] parametersForStartupObj) {
            _preloadUtil.GetApplicationPreloadInfo(context, out enabled, out startupObjType, out parametersForStartupObj);
        }

        [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
        private void ReportApplicationPreloadFailureWithAssert(string context, int errorCode, string errorMessage) {
            _preloadUtil.ReportApplicationPreloadFailure(context, errorCode, errorMessage);
        }

        private sealed class SimpleProcessResumeCallbackDispatcher : IProcessResumeCallback {
            private readonly Action _callback;
            public SimpleProcessResumeCallbackDispatcher(Action callback) {
                Debug.Assert(callback != null);
                _callback = callback;
            }

            public void Resume() {
                _callback();
            }
        }

        // The methods below are for propagating error information to ApplicationManager
        // so that we can display a YSOD when the application starts. We rely on the
        // fact that webengine4.dll will immediately call IProcessHost.StartApplication
        // if GetCustomLoader returns null, so TLS is appropriate.

        internal static ExceptionDispatchInfo GetExistingCustomLoaderFailureAndClear(string appId) {
            var copiedError = _customLoaderStartupError;
            if (String.Equals(copiedError.Key, appId, StringComparison.OrdinalIgnoreCase)) {
                _customLoaderStartupError = default(KeyValuePair<string, ExceptionDispatchInfo>);
                return copiedError.Value;
            }
            else {
                return null;
            }
        }

        private static void SetCustomLoaderFailure(string appId, ExceptionDispatchInfo error) {
            _customLoaderStartupError = new KeyValuePair<string, ExceptionDispatchInfo>(appId, error);
        }

        IObjectHandle IProcessHostLite.GetCustomLoader(string appId, string appConfigPath, out IProcessHostSupportFunctions supportFunctions, out AppDomain newlyCreatedAppDomain) {
            supportFunctions = null;
            newlyCreatedAppDomain = null;
            CustomLoaderHelperFunctions helperFunctions = new CustomLoaderHelperFunctions(_functions, appId);
            string appVirtualPath = helperFunctions.AppVirtualPath;

            try {
                string customLoaderAssemblyPhysicalPath = helperFunctions.MapPath("bin/AspNet.Loader.dll");

                if (!File.Exists(customLoaderAssemblyPhysicalPath)) {
                    return null; // no custom loader is in use; fall back to legacy hosting logic
                }

                // Technically there is a race condition between the file existence check above
                // and the assembly load that will take place shortly. We won't worry too much
                // about this since the window is very short and the application shouldn't be
                // modified during this process anyway.

                string appRootPhysicalPath = helperFunctions.AppPhysicalPath;
                string webConfigPhysicalPath = helperFunctions.MapPath("Web.config");
                bool webConfigFileExists = File.Exists(webConfigPhysicalPath);

                // The CustomLoaderHelper class is defined in System.Web.ApplicationServices.dll
                // so that OOB frameworks don't need to take a hardcoded System.Web.dll dependency.
                // There might be weird issues if we try to load a GACed System.Web.dll into the
                // same AppDomain as a bin-deployed System.Web.dll.
                supportFunctions = _functions;
                return CustomLoaderHelper.GetCustomLoader(
                    helperFunctions: helperFunctions,
                    appConfigMetabasePath: appConfigPath,
                    configFilePath: (webConfigFileExists) ? webConfigPhysicalPath : null,
                    customLoaderPhysicalPath: customLoaderAssemblyPhysicalPath,
                    newlyCreatedAppDomain: out newlyCreatedAppDomain);
            }
            catch (Exception ex) {
                SetCustomLoaderFailure(appId, ExceptionDispatchInfo.Capture(ex));
                return null;
            }
        }

        void IProcessHostLite.ReportCustomLoaderError(string appId, int hr, AppDomain newlyCreatedAppDomain) {
            try {
                try {
                    // If the failure originated in managed code (GetCustomLoader), this will actually
                    // result in the original managed exception being rethrown, which is convenient
                    // for us.
                    Marshal.ThrowExceptionForHR(hr);
                }
                finally {
                    // AD wasn't unloaded by CustomLoaderHelper, so kill it here.
                    AppDomain.Unload(newlyCreatedAppDomain);
                }
            }
            catch (Exception ex) {
                SetCustomLoaderFailure(appId, ExceptionDispatchInfo.Capture(ex));
            }
        }

        // Used to extract the full message of an exception, including class name and stack trace.
        string IProcessHostLite.GetFullExceptionMessage(int hr, IntPtr pErrorInfo) {
            // If no IErrorInfo is explicitly specified, provide -1 to suppress the automated
            // GetErrorInfo lookup, as it may have been overwritten and might be irrelevant.
            Exception ex = Marshal.GetExceptionForHR(hr, (pErrorInfo != IntPtr.Zero) ? pErrorInfo : (IntPtr)(-1));

            if (ex != null) {
                return ex.ToString();
            } else {
                // Should never hit this case, but just in case, return a dummy value.
                Debug.Fail("The provided HRESULT should've represented a failure.");
                return String.Empty;
            }
        }

        private sealed class CustomLoaderHelperFunctions : ICustomLoaderHelperFunctions {
            private static readonly bool? _isEnabled = GetIsEnabledValueFromRegistry();

            private readonly IProcessHostSupportFunctions _supportFunctions;

            internal CustomLoaderHelperFunctions(IProcessHostSupportFunctions supportFunctions, string appId) {
                _supportFunctions = supportFunctions;

                string appVirtualPath, appPhysicalPath, siteName, siteId;
                _supportFunctions.GetApplicationProperties(appId, out appVirtualPath, out appPhysicalPath, out siteName, out siteId);

                AppId = appId;
                AppVirtualPath = appVirtualPath;
                AppPhysicalPath = appPhysicalPath;
            }

            public string AppId { get; private set; }
            public string AppPhysicalPath { get; private set; }
            public string AppVirtualPath { get; private set; }
            public bool? CustomLoaderIsEnabled { get { return _isEnabled; } } // true = always enabled, false = always disabled, null = check trust level

            private static bool? GetIsEnabledValueFromRegistry() {
                bool? isEnabled = null;
                try {
                    int valueInRegistry = (int)Misc.GetAspNetRegValue(null, "CustomLoaderEnabled", -1);
                    if (valueInRegistry == 1) {
                        // explicitly enabled
                        isEnabled = true;
                    }
                    else if (valueInRegistry == 0) {
                        // explicitly disabled
                        isEnabled = false;
                    }
                }
                catch {
                    // We don't care about errors, as we'll just query fallback logic.
                }

                return isEnabled;
            }

            public string GetTrustLevel(string appConfigMetabasePath) {
                object retVal;
                int hr = UnsafeIISMethods.MgdGetConfigProperty(appConfigMetabasePath, "system.web/trust", "level", out retVal);
                Marshal.ThrowExceptionForHR(hr);
                return (string)retVal;
            }

            public string MapPath(string relativePath) {
                return _supportFunctions.MapPathInternal(AppId, AppVirtualPath, relativePath);
            }
        }
    }

    internal sealed class ListenerAdapterDispatchShim : MarshalByRefObject, IRegisteredObject {

        void IRegisteredObject.Stop(bool immediate) {
            HostingEnvironment.UnregisterObject(this);
        }

        // this should run in an Hosted app domain (not in the default domain)
        internal void StartListenerChannel( AppDomainProtocolHandler handler, IListenerChannelCallback listenerCallback ) {
            Debug.Assert( HostingEnvironment.IsHosted, "HostingEnvironment.IsHosted" );
            Debug.Assert( null != handler, "null != handler" );

            IListenerChannelCallback unwrappedProxy = MarshalComProxy(listenerCallback);

            Debug.Assert(null != unwrappedProxy, "null != unwrappedProxy");
            if (null != unwrappedProxy && null != handler) {
                handler.StartListenerChannel(unwrappedProxy);
            }
        }

        internal IListenerChannelCallback MarshalComProxy(IListenerChannelCallback defaultDomainCallback) {
            IListenerChannelCallback localProxy = null;

            // get the underlying COM object
            IntPtr pUnk = Marshal.GetIUnknownForObject(defaultDomainCallback);

            // this object isn't a COM object
            if (IntPtr.Zero == pUnk) {
                return null;
            }

            IntPtr ppv = IntPtr.Zero;
            try {
                // QI it for the interface
                Guid g = typeof(IListenerChannelCallback).GUID;

                int hresult = Marshal.QueryInterface(pUnk, ref g, out ppv);
                if (hresult < 0)  {
                    Marshal.ThrowExceptionForHR(hresult);
                }

                // create a RCW we can hold onto in this domain
                // this bumps the ref count so we can drop our refs on the raw interfaces
                localProxy = (IListenerChannelCallback)Marshal.GetObjectForIUnknown(ppv);
            }
            finally {
                // drop our explicit refs and keep the managed instance
                if (IntPtr.Zero != ppv) {
                    Marshal.Release(ppv);
                }
                if (IntPtr.Zero != pUnk) {
                    Marshal.Release(pUnk);
                }
            }

            return localProxy;
        }

    }
}