Skip to content

Commit

Permalink
General Cleanup, Fix Resolving Issue with .NET Executables used as de…
Browse files Browse the repository at this point in the history
…pendencies
  • Loading branch information
HerpDerpinstine committed Sep 4, 2024
1 parent 4cd252e commit 62567fd
Show file tree
Hide file tree
Showing 19 changed files with 88 additions and 56 deletions.
4 changes: 2 additions & 2 deletions Dependencies/MelonStartScreen/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private static unsafe bool ApplyUser32SetTimerPatch()
}

// We get a native function pointer to User32SetTimerDetour from our current class
#if NET6_0
#if NET6_0_OR_GREATER
delegate* unmanaged[Cdecl]<IntPtr, IntPtr, uint, IntPtr, IntPtr> detourPtr = &User32SetTimerDetour;
#else
IntPtr detourPtr = Marshal.GetFunctionPointerForDelegate((User32SetTimerDelegate)User32SetTimerDetour);
Expand All @@ -142,7 +142,7 @@ private static unsafe bool ApplyUser32SetTimerPatch()
return true;
}

#if NET6_0
#if NET6_0_OR_GREATER
[UnmanagedCallersOnly(CallConvs = new[] {typeof(CallConvCdecl)})]
#endif
private unsafe static IntPtr User32SetTimerDetour(IntPtr hWnd, IntPtr nIDEvent, uint uElapse, IntPtr timerProc)
Expand Down
2 changes: 1 addition & 1 deletion Dependencies/MelonStartScreen/UI/StartScreenResources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ private static byte[] GetResource(string name)
using var s = Assembly.GetExecutingAssembly().GetManifestResourceStream($"MelonLoader.MelonStartScreen.Resources.{name}");
if (s == null)
return null;
#if NET6_0
#if NET6_0_OR_GREATER
using var ms = new MemoryStream();
s.CopyTo(ms);
return ms.ToArray();
Expand Down
4 changes: 2 additions & 2 deletions MelonLoader/BootstrapInterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

#if NET6_0
#if NET6_0_OR_GREATER
using MelonLoader.CoreClrUtils;
#endif

namespace MelonLoader
{
internal static unsafe class BootstrapInterop
{
#if NET6_0
#if NET6_0_OR_GREATER
internal static delegate* unmanaged<void**, void*, void> HookAttach;
internal static delegate* unmanaged<void**, void*, void> HookDetach;
#endif
Expand Down
11 changes: 7 additions & 4 deletions MelonLoader/Core.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ internal static int Initialize()
if (MelonUtils.IsUnderWineOrSteamProton())
Pastel.ConsoleExtensions.Disable();

#if NET6_0_OR_GREATER
Fixes.DotnetLoadFromManagedFolderFix.Install();
#endif

Fixes.UnhandledException.Install(AppDomain.CurrentDomain);
Fixes.ServerCertificateValidation.Install();
Assertions.LemonAssertMapping.Setup();
Expand All @@ -63,7 +66,7 @@ internal static int Initialize()
MelonDebug.Msg("[MonoLibrary] Caught SecurityException, assuming not running under mono and continuing with init");
}

#if NET6_0
#if NET6_0_OR_GREATER
if (MelonLaunchOptions.Core.UserWantsDebugger && MelonEnvironment.IsDotnetRuntime)
{
MelonLogger.Msg("[Init] User requested debugger, attempting to launch now...");
Expand All @@ -76,7 +79,7 @@ internal static int Initialize()
HarmonyInstance = new HarmonyLib.Harmony(BuildInfo.Name);
Fixes.DetourContextDisposeFix.Install();

#if NET6_0
#if NET6_0_OR_GREATER
// if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
// NativeStackWalk.LogNativeStackTrace();

Expand All @@ -88,7 +91,7 @@ internal static int Initialize()
Fixes.InstancePatchFix.Install();
Fixes.ProcessFix.Install();

#if NET6_0
#if NET6_0_OR_GREATER
Fixes.Il2CppInteropFixes.Install();
#endif

Expand Down Expand Up @@ -116,7 +119,7 @@ internal static int PreStart()

private static int PreSetup()
{
#if NET6_0
#if NET6_0_OR_GREATER
if (_success)
_success = Il2CppAssemblyGenerator.Run();
#endif
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/CoreClrUtils/CoreClrDelegateFixer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0_OR_GREATER

using Microsoft.Diagnostics.Runtime;
using System;
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/CoreClrUtils/MethodBaseHelper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0_OR_GREATER
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/CoreClrUtils/NativeStackWalk.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0_OR_GREATER

#nullable enable
#pragma warning disable CS0169
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/Fixes/DotnetAssemblyLoadContextFix.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0_OR_GREATER
using HarmonyLib;
using MelonLoader.Utils;
using System;
Expand Down
36 changes: 20 additions & 16 deletions MelonLoader/Fixes/DotnetLoadFromManagedFolderFix.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
#if NET6_0
#if NET6_0_OR_GREATER
using MelonLoader.Utils;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
#endif

namespace MelonLoader.Fixes
{
internal static class DotnetLoadFromManagedFolderFix
{

#if !NET6_0
internal static void Install()
{
}
#else
//TODO Update for non-windows platforms in future, or when updating runtime
private static readonly string OurRuntimeDir = Path.Combine(MelonEnvironment.OurRuntimeDirectory, "runtimes", "win", "lib", "net6.0");

Expand All @@ -30,18 +23,32 @@ private static Assembly TryLoad(AssemblyLoadContext alc, string path)
MelonDebug.Msg($"[DotnetManagedFolder] Loading from {path}...");
return alc.LoadFromAssemblyPath(path);
}

return null;
}

private static Assembly OnResolve(AssemblyLoadContext alc, AssemblyName name)
{
var ret = TryFind(alc, name);
if (ret == null)
MelonDebug.Msg($"[DotnetManagedFolder] Failed to find {name.Name} in any of the known search directories");
return ret;
}

internal static Assembly TryFind(AssemblyLoadContext alc, AssemblyName name)
{
// Redirect ModHandler to main MelonLoader dll (us)
if (name.Name == "MelonLoader.ModHandler")
//Redirect ModHandler to main MelonLoader dll (us)
return Assembly.GetExecutingAssembly();

var filename = name.Name + ".dll";
var ret = TryLoadFromFolders(alc, name.Name + ".dll");
if (ret == null)
TryLoadFromFolders(alc, name.Name + ".exe");

return ret;
}

private static Assembly TryLoadFromFolders(AssemblyLoadContext alc, string filename)
{
var osSpecificPath = Path.Combine(OurRuntimeDir, filename);
var il2cppPath = Path.Combine(MelonEnvironment.Il2CppAssembliesDirectory, filename);
var managedPath = Path.Combine(MelonEnvironment.MelonManagedDirectory, filename);
Expand All @@ -58,11 +65,8 @@ private static Assembly OnResolve(AssemblyLoadContext alc, AssemblyName name)
?? TryLoad(alc, runtimeSpecificPath)
?? TryLoad(alc, gameRootPath);

if (ret == null)
MelonDebug.Msg($"[DotnetManagedFolder] Failed to find {filename} in any of the known search directories");

return ret;
}
#endif
}
}
}
#endif
2 changes: 1 addition & 1 deletion MelonLoader/Fixes/DotnetModHandlerRedirectionFix.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0_OR_GREATER
using HarmonyLib;
using System;
using System.Reflection;
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/Fixes/Il2CppInteropFixes.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0_OR_GREATER
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down
19 changes: 18 additions & 1 deletion MelonLoader/InternalUtils/DependencyGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
using System.Reflection;
using System.IO;

#if NET35

using MelonLoader.MonoInternals.ResolveInternals;

#elif NET6_0_OR_GREATER

using MelonLoader.Fixes;
using System.Runtime.Loader;

#endif

namespace MelonLoader.InternalUtils
{
internal class DependencyGraph<T> where T : MelonBase
Expand Down Expand Up @@ -132,7 +143,13 @@ private static bool TryLoad(AssemblyName assembly)
{
try
{
Assembly.Load(assembly);
#if NET35
Assembly asm = SearchDirectoryManager.Scan(assembly.Name);
#elif NET6_0_OR_GREATER
Assembly asm = DotnetLoadFromManagedFolderFix.TryFind(AssemblyLoadContext.Default, assembly);
#endif
if (asm == null)
return false;
return true;
}
catch (FileNotFoundException) { return false; }
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/InternalUtils/Il2CppAssemblyGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0_OR_GREATER
using MelonLoader.Modules;
using System;
using System.Diagnostics;
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/MelonUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ internal static string GetOSVersion()
public static void NativeHookAttach(IntPtr target, IntPtr detour) => BootstrapInterop.NativeHookAttach(target, detour);

[Obsolete("Use NativeUtils.NativeHook instead")]
#if NET6_0
#if NET6_0_OR_GREATER
internal static void NativeHookAttachDirect(IntPtr target, IntPtr detour) => BootstrapInterop.NativeHookAttachDirect(target, detour);
#else
//On mono, NativeHookAttach *is* direct.
Expand Down
6 changes: 3 additions & 3 deletions MelonLoader/Melons/MelonAssembly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.IO;
using System.Reflection;
using MelonLoader.Utils;
#if NET6_0
#if NET6_0_OR_GREATER
using System.Runtime.Loader;
#endif

Expand Down Expand Up @@ -80,7 +80,7 @@ public static MelonAssembly LoadMelonAssembly(string path, bool loadMelons = tru

try
{
#if NET6_0
#if NET6_0_OR_GREATER
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
#else
var assembly = Assembly.LoadFrom(path);
Expand All @@ -107,7 +107,7 @@ public static MelonAssembly LoadRawMelonAssembly(string path, byte[] assemblyDat

try
{
#if NET6_0
#if NET6_0_OR_GREATER
var fileStream = new MemoryStream(assemblyData);
var symStream = symbolsData == null ? null : new MemoryStream(symbolsData);

Expand Down
20 changes: 8 additions & 12 deletions MelonLoader/MonoInternals/MonoResolveManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ internal static bool Setup()
};
foreach (string path in searchdirlist)
AddSearchDirectory(path);

ForceResolveRuntime("Mono.Cecil");
ForceResolveRuntime("MonoMod");
ForceResolveRuntime("MonoMod.Utils");
ForceResolveRuntime("MonoMod.RuntimeDetour");
ForceResolveRuntime("Mono.Cecil.dll");
ForceResolveRuntime("MonoMod.exe");
ForceResolveRuntime("MonoMod.Utils.dll");
ForceResolveRuntime("MonoMod.RuntimeDetour.dll");

// Setup Redirections
string[] assembly_list =
Expand All @@ -47,11 +47,9 @@ internal static bool Setup()
return true;
}

private static void ForceResolveRuntime(string assemblyName)
=> ForceResolveRuntime(assemblyName, assemblyName);
private static void ForceResolveRuntime(string assemblyName, string fileName)
private static void ForceResolveRuntime(string fileName)
{
string filePath = Path.Combine(MelonEnvironment.OurRuntimeDirectory, $"{fileName}.dll");
string filePath = Path.Combine(MelonEnvironment.OurRuntimeDirectory, fileName);
if (!File.Exists(filePath))
return;

Expand All @@ -62,17 +60,15 @@ private static void ForceResolveRuntime(string assemblyName, string fileName)
if (assembly == null)
return;

GetAssemblyResolveInfo(assemblyName).Override = assembly;
GetAssemblyResolveInfo(Path.GetFileNameWithoutExtension(fileName)).Override = assembly;
}

// Search Directories
public static void AddSearchDirectory(string path, int priority = 0)
=> SearchDirectoryManager.Add(path, priority);

public static void RemoveSearchDirectory(string path)
=> SearchDirectoryManager.Remove(path);


// Assembly
public delegate void OnAssemblyLoadHandler(Assembly assembly);
public static event OnAssemblyLoadHandler OnAssemblyLoad;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,30 @@ internal static Assembly Scan(string requested_name)

string filepath = Directory.GetFiles(folderpath).Where(x =>
!string.IsNullOrEmpty(x)
&& Path.GetExtension(x).ToLowerInvariant().Equals(".dll")
&& Path.GetFileName(x).Equals($"{requested_name}.dll")
&& ((Path.GetExtension(x).ToLowerInvariant().Equals(".dll")
&& Path.GetFileName(x).Equals($"{requested_name}.dll"))
|| (Path.GetExtension(x).ToLowerInvariant().Equals(".exe")
&& Path.GetFileName(x).Equals($"{requested_name}.exe")))
).FirstOrDefault();

if (string.IsNullOrEmpty(filepath))
continue;

IntPtr assemblyptr = MonoLibrary.Instance.mono_assembly_open_full(Marshal.StringToHGlobalAnsi(filepath), IntPtr.Zero, false);
if (assemblyptr == IntPtr.Zero)
IntPtr filePathPtr = Marshal.StringToHGlobalAnsi(filepath);
if (filePathPtr == IntPtr.Zero)
continue;

IntPtr assemblyReflectionPtr = MonoLibrary.Instance.mono_assembly_get_object(MonoLibrary.GetRootDomainPtr(), assemblyptr);
IntPtr rootPtr = MonoLibrary.GetRootDomainPtr();
if (rootPtr == IntPtr.Zero)
continue;

IntPtr assemblyPtr = MonoLibrary.Instance.mono_assembly_open_full(filePathPtr, IntPtr.Zero, false);
if (assemblyPtr == IntPtr.Zero)
continue;

IntPtr assemblyReflectionPtr = MonoLibrary.Instance.mono_assembly_get_object(rootPtr, assemblyPtr);
if (assemblyReflectionPtr == IntPtr.Zero)
continue;

return MonoLibrary.CastManagedAssemblyPtr(assemblyReflectionPtr);
}
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/Utils/AssemblyVerifier.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if NET6_0
#if NET6_0_OR_GREATER
using AsmResolver.DotNet;
using AsmResolver.PE.DotNet.Metadata;
using AsmResolver.PE.DotNet.Metadata.Tables;
Expand Down
2 changes: 1 addition & 1 deletion MelonLoader/Utils/MelonEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class MelonEnvironment
public static string MelonLoaderDirectory { get; internal set; }
public static string GameRootDirectory { get; internal set; }

#if NET6_0
#if NET6_0_OR_GREATER
public static string GameExecutablePath => System.Environment.ProcessPath;
#else
public static string GameExecutablePath => Process.GetCurrentProcess().MainModule!.FileName;
Expand Down

0 comments on commit 62567fd

Please sign in to comment.