TraceFix.cs 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. using System;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using System.Reflection;
  5. using HarmonyLib;
  6. namespace BepInEx.Preloader.RuntimeFixes
  7. {
  8. /// <summary>
  9. /// This exists because the Mono implementation of <see cref="Trace"/> is/was broken, and would call Write directly instead of calling TraceEvent. This class fixes that with a <see cref="BepInEx.Harmony"/> hook.
  10. /// </summary>
  11. internal static class TraceFix
  12. {
  13. private static Type TraceImplType;
  14. private static object ListenersSyncRoot;
  15. private static TraceListenerCollection Listeners;
  16. private static PropertyInfo prop_AutoFlush;
  17. private static bool AutoFlush => (bool)prop_AutoFlush.GetValue(null, null);
  18. public static void ApplyFix()
  19. {
  20. TraceImplType = AppDomain.CurrentDomain.GetAssemblies()
  21. .First(x => x.GetName().Name == "System")
  22. .GetTypes()
  23. .FirstOrDefault(x => x.Name == "TraceImpl");
  24. // assembly that has already fixed this
  25. if (TraceImplType == null) return;
  26. ListenersSyncRoot = AccessTools.Property(TraceImplType, "ListenersSyncRoot").GetValue(null, null);
  27. Listeners = (TraceListenerCollection)AccessTools.Property(TraceImplType, "Listeners").GetValue(null, null);
  28. prop_AutoFlush = AccessTools.Property(TraceImplType, "AutoFlush");
  29. HarmonyLib.Harmony instance = new HarmonyLib.Harmony("com.bepis.bepinex.tracefix");
  30. instance.Patch(
  31. typeof(Trace).GetMethod("DoTrace", BindingFlags.Static | BindingFlags.NonPublic),
  32. prefix: new HarmonyMethod(typeof(TraceFix).GetMethod(nameof(DoTraceReplacement), BindingFlags.Static | BindingFlags.NonPublic)));
  33. }
  34. private static bool DoTraceReplacement(string kind, Assembly report, string message)
  35. {
  36. string arg = string.Empty;
  37. try
  38. {
  39. arg = report.GetName().Name;
  40. }
  41. catch (MethodAccessException) { }
  42. TraceEventType type = (TraceEventType)Enum.Parse(typeof(TraceEventType), kind);
  43. lock (ListenersSyncRoot)
  44. {
  45. foreach (object obj in Listeners)
  46. {
  47. TraceListener traceListener = (TraceListener)obj;
  48. traceListener.TraceEvent(new TraceEventCache(), arg, type, 0, message);
  49. if (AutoFlush)
  50. {
  51. traceListener.Flush();
  52. }
  53. }
  54. }
  55. return false;
  56. }
  57. }
  58. }