| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 | using System;using System.Diagnostics;using System.Linq;using System.Reflection;using HarmonyLib;namespace BepInEx.Preloader.RuntimeFixes{	/// <summary>	/// This exists because the Mono implementation of <see cref="Trace"/> is/was broken, and would call Write directly instead of calling TraceEvent.	/// </summary>	internal static class TraceFix	{		private static Type TraceImplType;		private static object ListenersSyncRoot;		private static TraceListenerCollection Listeners;		private static PropertyInfo prop_AutoFlush;		private static bool AutoFlush => (bool)prop_AutoFlush.GetValue(null, null);		public static void ApplyFix()		{			TraceImplType = AppDomain.CurrentDomain.GetAssemblies()									 .First(x => x.GetName().Name == "System")									 .GetTypes()									 .FirstOrDefault(x => x.Name == "TraceImpl");			// assembly that has already fixed this			if (TraceImplType == null) return;			ListenersSyncRoot = AccessTools.Property(TraceImplType, "ListenersSyncRoot").GetValue(null, null);			Listeners = (TraceListenerCollection)AccessTools.Property(TraceImplType, "Listeners").GetValue(null, null);			prop_AutoFlush = AccessTools.Property(TraceImplType, "AutoFlush");			HarmonyLib.Harmony instance = new HarmonyLib.Harmony("com.bepis.bepinex.tracefix");			instance.Patch(				typeof(Trace).GetMethod("DoTrace", BindingFlags.Static | BindingFlags.NonPublic),				prefix: new HarmonyMethod(typeof(TraceFix).GetMethod(nameof(DoTraceReplacement), BindingFlags.Static | BindingFlags.NonPublic)));		}		private static bool DoTraceReplacement(string kind, Assembly report, string message)		{			string arg = string.Empty;			try			{				arg = report.GetName().Name;			}			catch (MethodAccessException) { }			TraceEventType type = (TraceEventType)Enum.Parse(typeof(TraceEventType), kind);			lock (ListenersSyncRoot)			{				foreach (object obj in Listeners)				{					TraceListener traceListener = (TraceListener)obj;					traceListener.TraceEvent(new TraceEventCache(), arg, type, 0, message);					if (AutoFlush)					{						traceListener.Flush();					}				}			}			return false;		}	}}
 |