e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
222 lines
11 KiB
C#
222 lines
11 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
namespace System.ServiceModel.ComIntegration
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.EnterpriseServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.ServiceModel.Configuration;
|
|
using System.Diagnostics;
|
|
using System.Runtime;
|
|
using System.Runtime.Diagnostics;
|
|
using System.Threading;
|
|
using System.ServiceModel.Diagnostics;
|
|
|
|
class DllHostInitializeWorker
|
|
{
|
|
|
|
List<ComPlusServiceHost> hosts = new List<ComPlusServiceHost>();
|
|
Guid applicationId;
|
|
|
|
// This thread pings rpcss and the host process so that
|
|
// it does not assume that we are stuck and kills itself.
|
|
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods)] // no identified security vulnerability that would justify making a breaking change
|
|
public static void PingProc(object o)
|
|
{
|
|
IProcessInitControl control = o as IProcessInitControl;
|
|
|
|
try
|
|
{
|
|
// This will loop for a max of 2000 seconds, which is a sanity check
|
|
// that should never be hit. The assumption behind that is that
|
|
// the main thread will not get stuck. It will either make progress
|
|
// or fail with an exception, which will abort this thread and kill the process.
|
|
// No COM app should take longer than 30 minutes to initialize since an app that
|
|
// takes that long would have to be so big that it hits other limits before it hits this.
|
|
for (int i = 0; i < 200; i++)
|
|
{
|
|
Thread.Sleep(10000);
|
|
|
|
// Add 30 more seconds to the timeout
|
|
control.ResetInitializerTimeout(30);
|
|
}
|
|
}
|
|
catch (ThreadAbortException)
|
|
{
|
|
}
|
|
}
|
|
|
|
// We call ContextUtil.ApplicationId, from a non-APTCA assembly. There is no identified security vulnerability with that property, so we can't justify
|
|
// adding a demand for full trust here, causing a breaking change to the public DllHostInitializer.Startup(..) method that calls this one.
|
|
// ContextUtil.ApplicationId calls a native function (GetObjectContext from mtxex.dll), but it doesn't pass user input to it, and it doesn't
|
|
// cache its result (so there is no leak as a side-effect).
|
|
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods)]
|
|
public void Startup(IProcessInitControl control)
|
|
{
|
|
// Find our application object, and associated components
|
|
// (classes) collection from the COM+ catalog.
|
|
//
|
|
applicationId = ContextUtil.ApplicationId;
|
|
|
|
ComPlusDllHostInitializerTrace.Trace(TraceEventType.Information, TraceCode.ComIntegrationDllHostInitializerStarting,
|
|
SR.TraceCodeComIntegrationDllHostInitializerStarting, applicationId);
|
|
|
|
Thread pingThread = null;
|
|
|
|
try
|
|
{
|
|
pingThread = new Thread(PingProc);
|
|
pingThread.Start(control);
|
|
|
|
ComCatalogObject application;
|
|
application = CatalogUtil.FindApplication(applicationId);
|
|
if (application == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
|
|
SR.GetString(SR.ApplicationNotFound,
|
|
applicationId.ToString("B").ToUpperInvariant())));
|
|
}
|
|
|
|
bool processPooled = ((int)application.GetValue("ConcurrentApps")) > 1;
|
|
if (processPooled)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
|
|
SR.GetString(SR.PooledApplicationNotSupportedForComplusHostedScenarios,
|
|
applicationId.ToString("B").ToUpperInvariant())));
|
|
}
|
|
|
|
bool processRecycled = ((int)application.GetValue("RecycleLifetimeLimit")) > 0 ||
|
|
((int)application.GetValue("RecycleCallLimit")) > 0 ||
|
|
((int)application.GetValue("RecycleActivationLimit")) > 0 ||
|
|
((int)application.GetValue("RecycleMemoryLimit")) > 0;
|
|
|
|
if (processRecycled)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ListenerInitFailed(
|
|
SR.GetString(SR.RecycledApplicationNotSupportedForComplusHostedScenarios,
|
|
applicationId.ToString("B").ToUpperInvariant())));
|
|
}
|
|
|
|
|
|
ComCatalogCollection classes;
|
|
classes = application.GetCollection("Components");
|
|
|
|
// Load up Indigo configuration.
|
|
//
|
|
ServicesSection services = ServicesSection.GetSection();
|
|
bool foundService = false;
|
|
|
|
|
|
foreach (ServiceElement service in services.Services)
|
|
{
|
|
Guid clsidToCompare = Guid.Empty;
|
|
Guid appIdToCompare = Guid.Empty;
|
|
|
|
string[] serviceParams = service.Name.Split(',');
|
|
if (serviceParams.Length != 2)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OnlyClsidsAllowedForServiceType, service.Name)));
|
|
}
|
|
|
|
if (!DiagnosticUtility.Utility.TryCreateGuid(serviceParams[0], out appIdToCompare))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OnlyClsidsAllowedForServiceType, service.Name)));
|
|
}
|
|
|
|
if (!DiagnosticUtility.Utility.TryCreateGuid(serviceParams[1], out clsidToCompare))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OnlyClsidsAllowedForServiceType, service.Name)));
|
|
}
|
|
|
|
foundService = false;
|
|
|
|
// CODEWORK: Consider farming this out across multiple threadpool threads.
|
|
// When it was discovered that startup time could be a problem it was too late
|
|
// to to do that since it can cause failure conditions that need to be considered
|
|
// (such as the threadpool running out) so we decided not to touch that part.
|
|
// But since this can potentially take a very long time on big COM apps
|
|
// it should be parallelized at some point.
|
|
foreach (ComCatalogObject classObject in classes)
|
|
{
|
|
Guid clsid = Fx.CreateGuid((string)classObject.GetValue("CLSID"));
|
|
|
|
if (clsid == clsidToCompare && applicationId == appIdToCompare)
|
|
{
|
|
foundService = true;
|
|
ComPlusDllHostInitializerTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationDllHostInitializerAddingHost,
|
|
SR.TraceCodeComIntegrationDllHostInitializerAddingHost, applicationId, clsid, service);
|
|
this.hosts.Add(
|
|
new DllHostedComPlusServiceHost(clsid,
|
|
service,
|
|
application,
|
|
classObject));
|
|
}
|
|
}
|
|
if (!foundService)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString
|
|
(SR.CannotFindClsidInApplication, clsidToCompare.ToString("B").ToUpperInvariant(), applicationId.ToString("B").ToUpperInvariant())));
|
|
}
|
|
if (foundService == false)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.DllHostInitializerFoundNoServices());
|
|
}
|
|
|
|
foreach (ComPlusServiceHost host in this.hosts)
|
|
{
|
|
host.Open();
|
|
}
|
|
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error,
|
|
(ushort)System.Runtime.Diagnostics.EventLogCategory.ComPlus,
|
|
(uint)System.Runtime.Diagnostics.EventLogEventId.ComPlusDllHostInitializerStartingError,
|
|
applicationId.ToString(),
|
|
e.ToString());
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
if (null != pingThread)
|
|
pingThread.Abort(); // We are done; stop pinging.
|
|
|
|
}
|
|
ComPlusDllHostInitializerTrace.Trace(TraceEventType.Information, TraceCode.ComIntegrationDllHostInitializerStarted,
|
|
SR.TraceCodeComIntegrationDllHostInitializerStarted, applicationId);
|
|
}
|
|
|
|
public void Shutdown()
|
|
{
|
|
ComPlusDllHostInitializerTrace.Trace(TraceEventType.Information, TraceCode.ComIntegrationDllHostInitializerStopping,
|
|
SR.TraceCodeComIntegrationDllHostInitializerStopping, applicationId);
|
|
foreach (ComPlusServiceHost host in this.hosts)
|
|
{
|
|
host.Close();
|
|
}
|
|
ComPlusDllHostInitializerTrace.Trace(TraceEventType.Information, TraceCode.ComIntegrationDllHostInitializerStopped,
|
|
SR.TraceCodeComIntegrationDllHostInitializerStopped, applicationId);
|
|
}
|
|
}
|
|
|
|
[ComVisible(true)]
|
|
[Guid("59856830-3ECB-4D29-9CFE-DDD0F74B96A2")]
|
|
public class DllHostInitializer : IProcessInitializer
|
|
{
|
|
DllHostInitializeWorker worker = new DllHostInitializeWorker();
|
|
public void Startup(object punkProcessControl)
|
|
{
|
|
IProcessInitControl control = punkProcessControl as IProcessInitControl;
|
|
worker.Startup(control);
|
|
}
|
|
public void Shutdown()
|
|
{
|
|
worker.Shutdown();
|
|
}
|
|
|
|
}
|
|
}
|