mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-30 05:05:19 -05:00
feat: Added support for adding custom providers through C#
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Runtime.Loader;
|
||||
|
||||
namespace ImHex
|
||||
@@ -12,7 +13,7 @@ namespace ImHex
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteScript(Marshal.PtrToStringUTF8(arg, argLength)) ? 0 : 1;
|
||||
return ExecuteScript(Marshal.PtrToStringUTF8(arg, argLength));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -21,61 +22,108 @@ namespace ImHex
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool ExecuteScript(string path)
|
||||
private static List<string> loadedPlugins = new();
|
||||
private static int ExecuteScript(string args)
|
||||
{
|
||||
// Parse input in the form of "execType||path"
|
||||
var splitArgs = args.Split("||");
|
||||
var type = splitArgs[0];
|
||||
var methodName = splitArgs[1];
|
||||
var path = splitArgs[2];
|
||||
|
||||
// Get the parent folder of the passed path
|
||||
string? basePath = Path.GetDirectoryName(path);
|
||||
if (basePath == null)
|
||||
{
|
||||
Console.WriteLine("[.NET Script] Failed to get base path");
|
||||
return false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create a new assembly context
|
||||
AssemblyLoadContext? context = new("ScriptDomain_" + basePath, true);
|
||||
|
||||
int result = 0;
|
||||
try
|
||||
{
|
||||
if (type is "LOAD")
|
||||
{
|
||||
if (loadedPlugins.Contains(path))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if the plugin is already loaded
|
||||
loadedPlugins.Add(path);
|
||||
}
|
||||
|
||||
// Load all assemblies in the parent folder
|
||||
foreach (var file in Directory.GetFiles(basePath, "*.dll"))
|
||||
{
|
||||
// Skip main Assembly
|
||||
if (file.EndsWith("Main.dll"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
context.LoadFromStream(new MemoryStream(File.ReadAllBytes(file)));
|
||||
}
|
||||
|
||||
// Load the script assembly
|
||||
var assembly = context.LoadFromStream(new MemoryStream(File.ReadAllBytes(path)));
|
||||
|
||||
// Find a class named "Script"
|
||||
var entryPointType = assembly.GetType("Script");
|
||||
if (entryPointType == null)
|
||||
{
|
||||
Console.WriteLine("[.NET Script] Failed to find Script type");
|
||||
return false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
var entryPointMethod = entryPointType.GetMethod("Main", BindingFlags.Static | BindingFlags.Public);
|
||||
if (entryPointMethod == null)
|
||||
if (type is "EXEC" or "LOAD")
|
||||
{
|
||||
Console.WriteLine("[.NET Script] Failed to find ScriptMain method");
|
||||
return false;
|
||||
}
|
||||
// Load the function
|
||||
var method = entryPointType.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public);
|
||||
if (method == null)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
entryPointMethod.Invoke(null, null);
|
||||
// Execute it
|
||||
method.Invoke(null, null);
|
||||
}
|
||||
else if (type == "CHECK")
|
||||
{
|
||||
return entryPointType.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public) != null ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("[.NET Script] Exception in AssemblyLoader: " + e.ToString());
|
||||
return false;
|
||||
return 3;
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Unload();
|
||||
context = null;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
if (type != "LOAD")
|
||||
{
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
// Unload all assemblies associated with this script
|
||||
context.Unload();
|
||||
context = null;
|
||||
|
||||
// Run the garbage collector multiple times to make sure that the
|
||||
// assemblies are unloaded for sure
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user