Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/mscorlib/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,12 @@
<data name="Argument_InvalidSerializedString" xml:space="preserve">
<value>The specified serialized string '{0}' is not supported.</value>
</data>
<data name="Argument_InvalidStartupHookSyntax" xml:space="preserve">
<value>The syntax of the startup hook variable was invalid.</value>
</data>
<data name="Argument_InvalidStartupHookSignature" xml:space="preserve">
<value>The signature of the startup hook '{0}' in assembly '{1}' was invalid. It must be 'public static void Initialize()'.</value>
</data>
<data name="Argument_InvalidTimeSpanStyles" xml:space="preserve">
<value>An undefined TimeSpanStyles value is being used.</value>
</data>
Expand Down
1 change: 1 addition & 0 deletions src/mscorlib/System.Private.CoreLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@
<Compile Include="$(BclSourcesRoot)\System\RuntimeArgumentHandle.cs" />
<Compile Include="$(BclSourcesRoot)\System\RuntimeHandles.cs" />
<Compile Include="$(BclSourcesRoot)\System\SharedStatics.cs" />
<Compile Include="$(BclSourcesRoot)\System\StartupHookProvider.cs" />
<Compile Include="$(BclSourcesRoot)\System\StubHelpers.cs" />
<Compile Include="$(BclSourcesRoot)\System\Type.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\TypeNameParser.cs" />
Expand Down
120 changes: 120 additions & 0 deletions src/mscorlib/src/System/StartupHookProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;

namespace System
{
internal static class StartupHookProvider
{
private const string StartupHookTypeName = "StartupHook";
private const string InitializeMethodName = "Initialize";

// Parse a string specifying a list of assemblies and types
// containing a startup hook, and call each hook in turn.
private static void ProcessStartupHooks()
{
string startupHooksVariable = (string)AppContext.GetData("STARTUP_HOOKS");
if (startupHooksVariable == null)
{
return;
}

// Parse startup hooks variable
string[] startupHooks = startupHooksVariable.Split(Path.PathSeparator);
foreach (string startupHook in startupHooks)
{
if (String.IsNullOrEmpty(startupHook))
{
throw new ArgumentException(SR.Argument_InvalidStartupHookSyntax);
}
if (PathInternal.IsPartiallyQualified(startupHook))
{
throw new ArgumentException(SR.Argument_AbsolutePathRequired);
}
}

// Call each hook in turn
foreach (string startupHook in startupHooks)
{
CallStartupHook(startupHook);
}
}

// Load the specified assembly, and call the specified type's
// "static void Initialize()" method.
private static void CallStartupHook(string assemblyPath)
{
Debug.Assert(!String.IsNullOrEmpty(assemblyPath));
Debug.Assert(!PathInternal.IsPartiallyQualified(assemblyPath));

Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
Debug.Assert(assembly != null);
Type type = assembly.GetType(StartupHookTypeName, throwOnError: true);

// Look for a static method without any parameters
MethodInfo initializeMethod = type.GetMethod(InitializeMethodName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static,
null, // use default binder
Type.EmptyTypes, // parameters
null); // no parameter modifiers

bool wrongSignature = false;
if (initializeMethod == null)
{
// There weren't any static methods without
// parameters. Look for any methods with the correct
// name, to provide precise error handling.
try
{
// This could find zero, one, or multiple methods
// with the correct name.
initializeMethod = type.GetMethod(InitializeMethodName,
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance);
}
catch (AmbiguousMatchException)
{
// Found multiple
Debug.Assert(initializeMethod == null);
wrongSignature = true;
}
if (initializeMethod != null)
{
// Found one
wrongSignature = true;
}
else
{
// Didn't find any
throw new MissingMethodException(StartupHookTypeName, InitializeMethodName);
}
}
else if (initializeMethod.ReturnType != typeof(void))
{
wrongSignature = true;
}

if (wrongSignature)
{
throw new ArgumentException(SR.Format(SR.Argument_InvalidStartupHookSignature,
StartupHookTypeName + Type.Delimiter + InitializeMethodName,
assemblyPath));
}

Debug.Assert(initializeMethod != null &&
initializeMethod.IsStatic &&
initializeMethod.ReturnType == typeof(void) &&
initializeMethod.GetParameters().Length == 0);

initializeMethod.Invoke(null, null);
}
}
}
17 changes: 16 additions & 1 deletion src/vm/assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1764,6 +1764,21 @@ static void RunMainPost()
}
}

static void RunStartupHooks()
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
INJECT_FAULT(COMPlusThrowOM(););
}
CONTRACTL_END;

MethodDescCallSite processStartupHooks(METHOD__STARTUP_HOOK_PROVIDER__PROCESS_STARTUP_HOOKS);
processStartupHooks.Call(NULL);
}

INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThreads)
{
CONTRACTL
Expand Down Expand Up @@ -1808,7 +1823,6 @@ INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThre

RunMainPre();


// Set the root assembly as the assembly that is containing the main method
// The root assembly is used in the GetEntryAssembly method that on CoreCLR is used
// to get the TargetFrameworkMoniker for the app
Expand All @@ -1819,6 +1833,7 @@ INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThre
// Initialize the managed components of EventPipe and allow tracing to be started before Main.
EventPipe::InitializeManaged();
#endif
RunStartupHooks();

hr = RunMain(pMeth, 1, &iRetVal, stringArgs);
}
Expand Down
3 changes: 3 additions & 0 deletions src/vm/mscorlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,9 @@ DEFINE_CLASS(EVENTPIPE_CONTROLLER, Tracing, EventPipeController)
DEFINE_METHOD(EVENTPIPE_CONTROLLER, INITIALIZE, Initialize, SM_RetVoid)
#endif

DEFINE_CLASS(STARTUP_HOOK_PROVIDER, System, StartupHookProvider)
DEFINE_METHOD(STARTUP_HOOK_PROVIDER, PROCESS_STARTUP_HOOKS, ProcessStartupHooks, SM_RetVoid)

DEFINE_CLASS(STREAM, IO, Stream)
DEFINE_METHOD(STREAM, BEGIN_READ, BeginRead, IM_ArrByte_Int_Int_AsyncCallback_Object_RetIAsyncResult)
DEFINE_METHOD(STREAM, END_READ, EndRead, IM_IAsyncResult_RetInt)
Expand Down