DllHostInitializer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.ComIntegration
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics.CodeAnalysis;
  9. using System.EnterpriseServices;
  10. using System.Runtime.InteropServices;
  11. using System.ServiceModel.Configuration;
  12. using System.Diagnostics;
  13. using System.Runtime;
  14. using System.Runtime.Diagnostics;
  15. using System.Threading;
  16. using System.ServiceModel.Diagnostics;
  17. class DllHostInitializeWorker
  18. {
  19. List<ComPlusServiceHost> hosts = new List<ComPlusServiceHost>();
  20. Guid applicationId;
  21. // This thread pings rpcss and the host process so that
  22. // it does not assume that we are stuck and kills itself.
  23. [SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods)] // no identified security vulnerability that would justify making a breaking change
  24. public static void PingProc(object o)
  25. {
  26. IProcessInitControl control = o as IProcessInitControl;
  27. try
  28. {
  29. // This will loop for a max of 2000 seconds, which is a sanity check
  30. // that should never be hit. The assumption behind that is that
  31. // the main thread will not get stuck. It will either make progress
  32. // or fail with an exception, which will abort this thread and kill the process.
  33. // No COM app should take longer than 30 minutes to initialize since an app that
  34. // takes that long would have to be so big that it hits other limits before it hits this.
  35. for (int i = 0; i < 200; i++)
  36. {
  37. Thread.Sleep(10000);
  38. // Add 30 more seconds to the timeout
  39. control.ResetInitializerTimeout(30);
  40. }
  41. }
  42. catch (ThreadAbortException)
  43. {
  44. }
  45. }
  46. // We call ContextUtil.ApplicationId, from a non-APTCA assembly. There is no identified security vulnerability with that property, so we can't justify
  47. // adding a demand for full trust here, causing a breaking change to the public DllHostInitializer.Startup(..) method that calls this one.
  48. // ContextUtil.ApplicationId calls a native function (GetObjectContext from mtxex.dll), but it doesn't pass user input to it, and it doesn't
  49. // cache its result (so there is no leak as a side-effect).
  50. [SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods)]
  51. public void Startup(IProcessInitControl control)
  52. {
  53. // Find our application object, and associated components
  54. // (classes) collection from the COM+ catalog.
  55. //
  56. applicationId = ContextUtil.ApplicationId;
  57. ComPlusDllHostInitializerTrace.Trace(TraceEventType.Information, TraceCode.ComIntegrationDllHostInitializerStarting,
  58. SR.TraceCodeComIntegrationDllHostInitializerStarting, applicationId);
  59. Thread pingThread = null;
  60. try
  61. {
  62. pingThread = new Thread(PingProc);
  63. pingThread.Start(control);
  64. ComCatalogObject application;
  65. application = CatalogUtil.FindApplication(applicationId);
  66. if (application == null)
  67. {
  68. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
  69. SR.GetString(SR.ApplicationNotFound,
  70. applicationId.ToString("B").ToUpperInvariant())));
  71. }
  72. bool processPooled = ((int)application.GetValue("ConcurrentApps")) > 1;
  73. if (processPooled)
  74. {
  75. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
  76. SR.GetString(SR.PooledApplicationNotSupportedForComplusHostedScenarios,
  77. applicationId.ToString("B").ToUpperInvariant())));
  78. }
  79. bool processRecycled = ((int)application.GetValue("RecycleLifetimeLimit")) > 0 ||
  80. ((int)application.GetValue("RecycleCallLimit")) > 0 ||
  81. ((int)application.GetValue("RecycleActivationLimit")) > 0 ||
  82. ((int)application.GetValue("RecycleMemoryLimit")) > 0;
  83. if (processRecycled)
  84. {
  85. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
  86. SR.GetString(SR.RecycledApplicationNotSupportedForComplusHostedScenarios,
  87. applicationId.ToString("B").ToUpperInvariant())));
  88. }
  89. ComCatalogCollection classes;
  90. classes = application.GetCollection("Components");
  91. // Load up Indigo configuration.
  92. //
  93. ServicesSection services = ServicesSection.GetSection();
  94. bool foundService = false;
  95. foreach (ServiceElement service in services.Services)
  96. {
  97. Guid clsidToCompare = Guid.Empty;
  98. Guid appIdToCompare = Guid.Empty;
  99. string[] serviceParams = service.Name.Split(',');
  100. if (serviceParams.Length != 2)
  101. {
  102. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OnlyClsidsAllowedForServiceType, service.Name)));
  103. }
  104. if (!DiagnosticUtility.Utility.TryCreateGuid(serviceParams[0], out appIdToCompare))
  105. {
  106. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OnlyClsidsAllowedForServiceType, service.Name)));
  107. }
  108. if (!DiagnosticUtility.Utility.TryCreateGuid(serviceParams[1], out clsidToCompare))
  109. {
  110. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OnlyClsidsAllowedForServiceType, service.Name)));
  111. }
  112. foundService = false;
  113. // CODEWORK: Consider farming this out across multiple threadpool threads.
  114. // When it was discovered that startup time could be a problem it was too late
  115. // to to do that since it can cause failure conditions that need to be considered
  116. // (such as the threadpool running out) so we decided not to touch that part.
  117. // But since this can potentially take a very long time on big COM apps
  118. // it should be parallelized at some point.
  119. foreach (ComCatalogObject classObject in classes)
  120. {
  121. Guid clsid = Fx.CreateGuid((string)classObject.GetValue("CLSID"));
  122. if (clsid == clsidToCompare && applicationId == appIdToCompare)
  123. {
  124. foundService = true;
  125. ComPlusDllHostInitializerTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationDllHostInitializerAddingHost,
  126. SR.TraceCodeComIntegrationDllHostInitializerAddingHost, applicationId, clsid, service);
  127. this.hosts.Add(
  128. new DllHostedComPlusServiceHost(clsid,
  129. service,
  130. application,
  131. classObject));
  132. }
  133. }
  134. if (!foundService)
  135. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString
  136. (SR.CannotFindClsidInApplication, clsidToCompare.ToString("B").ToUpperInvariant(), applicationId.ToString("B").ToUpperInvariant())));
  137. }
  138. if (foundService == false)
  139. {
  140. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.DllHostInitializerFoundNoServices());
  141. }
  142. foreach (ComPlusServiceHost host in this.hosts)
  143. {
  144. host.Open();
  145. }
  146. }
  147. catch (Exception e)
  148. {
  149. DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
  150. (ushort)System.Runtime.Diagnostics.EventLogCategory.ComPlus,
  151. (uint)System.Runtime.Diagnostics.EventLogEventId.ComPlusDllHostInitializerStartingError,
  152. applicationId.ToString(),
  153. e.ToString());
  154. throw;
  155. }
  156. finally
  157. {
  158. if (null != pingThread)
  159. pingThread.Abort(); // We are done; stop pinging.
  160. }
  161. ComPlusDllHostInitializerTrace.Trace(TraceEventType.Information, TraceCode.ComIntegrationDllHostInitializerStarted,
  162. SR.TraceCodeComIntegrationDllHostInitializerStarted, applicationId);
  163. }
  164. public void Shutdown()
  165. {
  166. ComPlusDllHostInitializerTrace.Trace(TraceEventType.Information, TraceCode.ComIntegrationDllHostInitializerStopping,
  167. SR.TraceCodeComIntegrationDllHostInitializerStopping, applicationId);
  168. foreach (ComPlusServiceHost host in this.hosts)
  169. {
  170. host.Close();
  171. }
  172. ComPlusDllHostInitializerTrace.Trace(TraceEventType.Information, TraceCode.ComIntegrationDllHostInitializerStopped,
  173. SR.TraceCodeComIntegrationDllHostInitializerStopped, applicationId);
  174. }
  175. }
  176. [ComVisible(true)]
  177. [Guid("59856830-3ECB-4D29-9CFE-DDD0F74B96A2")]
  178. public class DllHostInitializer : IProcessInitializer
  179. {
  180. DllHostInitializeWorker worker = new DllHostInitializeWorker();
  181. public void Startup(object punkProcessControl)
  182. {
  183. IProcessInitControl control = punkProcessControl as IProcessInitControl;
  184. worker.Startup(control);
  185. }
  186. public void Shutdown()
  187. {
  188. worker.Shutdown();
  189. }
  190. }
  191. }