Added demo for cpp module and updated the CppModule
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -460,3 +460,4 @@ $RECYCLE.BIN/
|
||||
/WebUI/bin
|
||||
/WebUI_Old/bin
|
||||
Data/
|
||||
/WebUI/Libraries
|
||||
@@ -4,12 +4,6 @@ namespace CppCompatibilityModule.Extern;
|
||||
|
||||
public static class Delegates
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void ProcessObject(ref object obj);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void ExecuteDelegateFunction();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void SetExternFunctionPointerDelegate(IntPtr funcPtr);
|
||||
|
||||
|
||||
@@ -117,22 +117,5 @@ namespace CppCompatibilityModule.Extern
|
||||
return result;
|
||||
}
|
||||
|
||||
public void CallFunction(string methodName, ref object parameter)
|
||||
{
|
||||
var functionDelegate = GetDelegateForFunctionPointer<Delegates.ProcessObject>(methodName);
|
||||
|
||||
functionDelegate(ref parameter);
|
||||
|
||||
_Logger.Log($"Function {methodName} called successfully with parameter");
|
||||
}
|
||||
|
||||
public void CallFunction(string methodName)
|
||||
{
|
||||
var functionDelegate = GetDelegateForFunctionPointer<Delegates.ExecuteDelegateFunction>(methodName);
|
||||
|
||||
functionDelegate();
|
||||
|
||||
_Logger.Log($"Function {methodName} called successfully");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,24 +17,14 @@ public class ExternalApplication
|
||||
this._Logger = logger;
|
||||
}
|
||||
|
||||
internal void CallFunction(string methodName, ref object parameter)
|
||||
{
|
||||
_ExternLibrary.CallFunction(methodName, ref parameter);
|
||||
}
|
||||
|
||||
internal void CallFunction(string methodName)
|
||||
{
|
||||
_ExternLibrary.CallFunction(methodName);
|
||||
}
|
||||
|
||||
internal T GetDelegateForFunctionPointer<T>(string methodName) where T : Delegate
|
||||
{
|
||||
return _ExternLibrary.GetDelegateForFunctionPointer<T>(methodName);
|
||||
}
|
||||
|
||||
internal void SetExternFunctionToPointToFunction(string externalFunctionName, Delegates.CsharpFunctionDelegate localFunction)
|
||||
internal object? SetExternFunctionToPointToFunction<TLocalFunctionDelegate>(string externalFunctionName, TLocalFunctionDelegate localFunction) where TLocalFunctionDelegate : Delegate
|
||||
{
|
||||
_ExternLibrary.SetExternFunctionSetterPointerToCustomDelegate<Delegates.SetExternFunctionPointerDelegate, Delegates.CsharpFunctionDelegate>(externalFunctionName, localFunction);
|
||||
return _ExternLibrary.SetExternFunctionSetterPointerToCustomDelegate<Delegates.SetExternFunctionPointerDelegate, TLocalFunctionDelegate>(externalFunctionName, localFunction);
|
||||
}
|
||||
|
||||
internal void FreeLibrary()
|
||||
|
||||
@@ -43,25 +43,26 @@ public class ExternalApplicationHandler
|
||||
_ExternalApplicationManager.FreeApplication(applicationId);
|
||||
}
|
||||
|
||||
public void CallFunctionWithParameter(Guid appId, string functionName, ref object parameter)
|
||||
public T GetFunctionDelegate<T>(Guid applicationId, string functionName) where T : Delegate
|
||||
{
|
||||
if (_ExternalApplicationManager is null)
|
||||
{
|
||||
_Logger.Log("Failed to call function because the manager is not initialized. This should have never happened in the first place!!!", this, LogType.Critical);
|
||||
return;
|
||||
_Logger.Log("Failed to get function delegate because the manager is not initialized. This should have never happened in the first place!!!", this, LogType.Critical);
|
||||
return default!;
|
||||
}
|
||||
|
||||
_ExternalApplicationManager.ExecuteApplicationFunctionWithParameter(appId, functionName, ref parameter);
|
||||
return _ExternalApplicationManager.GetFunctionDelegate<T>(applicationId, functionName);
|
||||
}
|
||||
|
||||
public void CallFunctionWithoutParameter(Guid appId, string functionName)
|
||||
public object? SetExternFunctionToPointToFunction<TLocalFunctionDelegate>(Guid applicationId, string functionName,
|
||||
TLocalFunctionDelegate localFunction) where TLocalFunctionDelegate : Delegate
|
||||
{
|
||||
if(_ExternalApplicationManager is null)
|
||||
{
|
||||
_Logger.Log("Failed to call function because the manager is not initialized. This should have never happened in the first place!!!", this, LogType.Critical);
|
||||
return;
|
||||
_Logger.Log("Failed to set external function pointer because the manager is not initialized. This should have never happened in the first place!!!", this, LogType.Critical);
|
||||
return null;
|
||||
}
|
||||
|
||||
_ExternalApplicationManager.ExecuteApplicationFunctionWithoutParameter(appId, functionName);
|
||||
return _ExternalApplicationManager.SetExternFunctionToPointToFunction(applicationId, functionName, localFunction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,30 +46,28 @@ internal class ExternalApplicationManager
|
||||
_Logger.Log($"Application with id {applicationId} freed successfully");
|
||||
}
|
||||
|
||||
public void ExecuteApplicationFunctionWithParameter(Guid appId, string functionName, ref object parameter)
|
||||
public T GetFunctionDelegate<T>(Guid applicationId, string functionName) where T : Delegate
|
||||
{
|
||||
var application = _ExternalApplications.FirstOrDefault(app => app.ApplicationId == appId);
|
||||
var application = _ExternalApplications.FirstOrDefault(app => app.ApplicationId == applicationId, null);
|
||||
if(application is null)
|
||||
{
|
||||
_Logger.Log($"Couldn't find application with id {appId}");
|
||||
return;
|
||||
_Logger.Log($"Couldn't find application with id {applicationId}");
|
||||
return default!;
|
||||
}
|
||||
|
||||
application.CallFunction(functionName, ref parameter);
|
||||
return application.GetDelegateForFunctionPointer<T>(functionName);
|
||||
}
|
||||
|
||||
public void ExecuteApplicationFunctionWithoutParameter(Guid appId, string functionName)
|
||||
public object? SetExternFunctionToPointToFunction<TLocalFunctionDelegate>(Guid applicationId, string externalFunctionName, TLocalFunctionDelegate localFunction) where TLocalFunctionDelegate : Delegate
|
||||
{
|
||||
var application = _ExternalApplications.FirstOrDefault(app => app.ApplicationId == appId);
|
||||
var application = _ExternalApplications.FirstOrDefault(app => app.ApplicationId == applicationId, null);
|
||||
if(application is null)
|
||||
{
|
||||
_Logger.Log($"Couldn't find application with id {appId}");
|
||||
return;
|
||||
_Logger.Log($"Couldn't find application with id {applicationId}");
|
||||
return null;
|
||||
}
|
||||
|
||||
application.CallFunction(functionName);
|
||||
|
||||
return application.SetExternFunctionToPointToFunction<TLocalFunctionDelegate>(externalFunctionName, localFunction);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
14
Plugins/CppModuleDemo/CppModuleDemo.csproj
Normal file
14
Plugins/CppModuleDemo/CppModuleDemo.csproj
Normal file
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\DiscordBotCore.PluginCore\DiscordBotCore.PluginCore.csproj" />
|
||||
<ProjectReference Include="..\..\Modules\CppCompatibilityModule\CppCompatibilityModule.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
9
Plugins/CppModuleDemo/Delegates.cs
Normal file
9
Plugins/CppModuleDemo/Delegates.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CppModuleDemo;
|
||||
|
||||
public static class Delegates
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void ModifyComplexObject(ref ExampleComplexObject obj);
|
||||
}
|
||||
19
Plugins/CppModuleDemo/ExampleComplexObject.cs
Normal file
19
Plugins/CppModuleDemo/ExampleComplexObject.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CppModuleDemo;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
public struct ExampleComplexObject
|
||||
{
|
||||
public int IntegerValue;
|
||||
public double DoubleValue;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||
public string StringValue;
|
||||
|
||||
public ExampleComplexObject(int integerValue, double doubleValue, string stringValue)
|
||||
{
|
||||
IntegerValue = integerValue;
|
||||
DoubleValue = doubleValue;
|
||||
StringValue = stringValue;
|
||||
}
|
||||
}
|
||||
10
Plugins/CppModuleDemo/InternalSettings.cs
Normal file
10
Plugins/CppModuleDemo/InternalSettings.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using CppCompatibilityModule;
|
||||
using CppCompatibilityModule.Extern;
|
||||
|
||||
namespace CppModuleDemo;
|
||||
|
||||
internal static class InternalSettings
|
||||
{
|
||||
internal static ExternalApplicationHandler? ExternalApplicationHandler { get; set; } = null;
|
||||
internal static Guid DemoModuleInternalId { get; set; } = Guid.Empty;
|
||||
}
|
||||
78
Plugins/CppModuleDemo/ModuleSlashCommand.cs
Normal file
78
Plugins/CppModuleDemo/ModuleSlashCommand.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using DiscordBotCore.Logging;
|
||||
using DiscordBotCore.PluginCore.Interfaces;
|
||||
|
||||
namespace CppModuleDemo;
|
||||
|
||||
public class ModuleSlashCommand : IDbSlashCommand
|
||||
{
|
||||
public string Name => "cpp-module-demo";
|
||||
public string Description => "A demo command to showcase the C++ module integration with Discord Bot Core.";
|
||||
public bool CanUseDm => false;
|
||||
public bool HasInteraction => false;
|
||||
|
||||
public List<SlashCommandOptionBuilder> Options => new List<SlashCommandOptionBuilder>()
|
||||
{
|
||||
new SlashCommandOptionBuilder()
|
||||
{
|
||||
Name = "example-integer-value", Description = "An example integer value",
|
||||
Type = ApplicationCommandOptionType.Integer, IsRequired = true
|
||||
},
|
||||
new SlashCommandOptionBuilder()
|
||||
{
|
||||
Name = "example-number-value", Description = "An example number value",
|
||||
Type = ApplicationCommandOptionType.Number, IsRequired = true
|
||||
},
|
||||
new SlashCommandOptionBuilder()
|
||||
{
|
||||
Name = "example-string-value", Description = "An example boolean value",
|
||||
Type = ApplicationCommandOptionType.String, IsRequired = true
|
||||
}
|
||||
};
|
||||
|
||||
public async void ExecuteServer(ILogger logger, SocketSlashCommand context)
|
||||
{
|
||||
long integerValue = (long)context.Data.Options.First(option => option.Name == "example-integer-value").Value;
|
||||
double numberValue = (double)context.Data.Options.First(option => option.Name == "example-number-value").Value;
|
||||
string stringValue = (string)context.Data.Options.First(option => option.Name == "example-string-value").Value;
|
||||
|
||||
if(integerValue > int.MaxValue || integerValue < int.MinValue)
|
||||
{
|
||||
await context.Channel.SendMessageAsync("The provided integer value is out of range. Please provide a valid integer.");
|
||||
return;
|
||||
}
|
||||
|
||||
await context.RespondAsync("Processing your request...", ephemeral: true);
|
||||
|
||||
await context.Channel.SendMessageAsync("CppModuleDemo invoked with: \n" +
|
||||
$"Integer Value: {integerValue}\n" +
|
||||
$"Number Value: {numberValue}\n" +
|
||||
$"String Value: {stringValue}");
|
||||
|
||||
ExampleComplexObject complexObject = new ExampleComplexObject
|
||||
{
|
||||
IntegerValue = (int)integerValue,
|
||||
DoubleValue = numberValue,
|
||||
StringValue = stringValue
|
||||
};
|
||||
|
||||
Delegates.ModifyComplexObject? modifyComplexObject =
|
||||
InternalSettings.ExternalApplicationHandler?.GetFunctionDelegate<Delegates.ModifyComplexObject>(
|
||||
InternalSettings.DemoModuleInternalId, "modifyComplexObject");
|
||||
|
||||
if (modifyComplexObject is null)
|
||||
{
|
||||
await context.Channel.SendMessageAsync("Failed to retrieve the C++ function delegate. Please check the C++ module integration.");
|
||||
return;
|
||||
}
|
||||
|
||||
modifyComplexObject(ref complexObject);
|
||||
|
||||
await context.Channel.SendMessageAsync("CppModuleDemo command executed successfully! New values are:\n" +
|
||||
$"Integer Value: {((ExampleComplexObject)complexObject).IntegerValue}\n" +
|
||||
$"Number Value: {((ExampleComplexObject)complexObject).DoubleValue}\n" +
|
||||
$"String Value: {((ExampleComplexObject)complexObject).StringValue}");
|
||||
|
||||
}
|
||||
}
|
||||
31
Plugins/CppModuleDemo/StartupEvent.cs
Normal file
31
Plugins/CppModuleDemo/StartupEvent.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using CppCompatibilityModule;
|
||||
using CppCompatibilityModule.Extern;
|
||||
using DiscordBotCore.PluginCore.Helpers.Execution.DbEvent;
|
||||
using DiscordBotCore.PluginCore.Interfaces;
|
||||
|
||||
namespace CppModuleDemo;
|
||||
|
||||
public class StartupEvent : IDbEvent
|
||||
{
|
||||
public string Name => "CppModuleDemoStartupEvent";
|
||||
public string Description => "A demo event to showcase the C++ module integration with Discord Bot Core on startup.";
|
||||
|
||||
private static string _DllModule = "libCppModuleDemo.dylib";
|
||||
|
||||
public void Start(IDbEventExecutingArgument args)
|
||||
{
|
||||
args.PluginBaseDirectory.Create();
|
||||
InternalSettings.ExternalApplicationHandler = new ExternalApplicationHandler(args.Logger);
|
||||
string fullPath = Path.Combine(args.PluginBaseDirectory.FullName, _DllModule);
|
||||
Guid id = InternalSettings.ExternalApplicationHandler.CreateApplication(fullPath);
|
||||
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
args.Logger.Log("Failed to create the C++ module application. Please check the DLL path and ensure it is correct.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
args.Logger.Log($"CppModuleDemo started successfully with application ID: {id}", this);
|
||||
InternalSettings.DemoModuleInternalId = id;
|
||||
}
|
||||
}
|
||||
37
Plugins/CppModuleDemo/StopSlashCommand.cs
Normal file
37
Plugins/CppModuleDemo/StopSlashCommand.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using DiscordBotCore.Logging;
|
||||
using DiscordBotCore.PluginCore.Interfaces;
|
||||
|
||||
namespace CppModuleDemo;
|
||||
|
||||
public class StopSlashCommand : IDbSlashCommand
|
||||
{
|
||||
public string Name => "stop-cpp-module-demo";
|
||||
public string Description => "Stops the C++ module demo and cleans up resources.";
|
||||
public bool CanUseDm => false;
|
||||
public bool HasInteraction => false;
|
||||
public List<SlashCommandOptionBuilder> Options => [];
|
||||
|
||||
public async void ExecuteServer(ILogger logger, SocketSlashCommand context)
|
||||
{
|
||||
if (InternalSettings.ExternalApplicationHandler == null)
|
||||
{
|
||||
logger.Log("No C++ module is currently running.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
Guid id = InternalSettings.DemoModuleInternalId;
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
logger.Log("No valid C++ module ID found. Cannot stop the module.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
InternalSettings.ExternalApplicationHandler.StopApplication(id);
|
||||
InternalSettings.DemoModuleInternalId = Guid.Empty;
|
||||
logger.Log("CppModuleDemo stopped successfully.", this);
|
||||
|
||||
await context.Channel.SendMessageAsync("CppModuleDemo has been stopped and resources cleaned up.");
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,6 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordBotCore", "DiscordBotCore\DiscordBotCore.csproj", "{5A99BFC3-EB39-4AEF-8D61-3CE22D013B02}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{5CF9AD7B-6BF0-4035-835F-722F989C01E1}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Plugins\README.md = Plugins\README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{EA4FA308-7B2C-458E-8485-8747D745DD59}"
|
||||
EndProject
|
||||
@@ -41,6 +38,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.DiscordBotCore.Loggin
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.DiscordBotCore.Configuration", "Tests\Tests.DiscordBotCore.Configuration\Tests.DiscordBotCore.Configuration.csproj", "{52C59C73-C23C-4608-8827-383577DEB8D8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CppModuleDemo", "Plugins\CppModuleDemo\CppModuleDemo.csproj", "{55425935-456E-4ED4-9283-2CB6A6C7AC7D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -231,6 +230,18 @@ Global
|
||||
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -241,6 +252,7 @@ Global
|
||||
{9A4B98C1-00AC-481C-BE55-A70C0B9D3BE7} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1}
|
||||
{94238D37-60C6-4E40-80EC-4B4D242F5914} = {8F27B3EA-F292-40DF-B9B3-4B0E6BEA4E70}
|
||||
{52C59C73-C23C-4608-8827-383577DEB8D8} = {8F27B3EA-F292-40DF-B9B3-4B0E6BEA4E70}
|
||||
{55425935-456E-4ED4-9283-2CB6A6C7AC7D} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF}
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
var buffer = new byte[file.Size];
|
||||
await file.OpenReadStream().ReadAsync(buffer);
|
||||
_message = $"Uploaded file: {file.Name} ({file.Size} bytes)";
|
||||
selectedFile = file;
|
||||
}
|
||||
|
||||
private async Task HandleValidSubmit()
|
||||
|
||||
@@ -1,7 +1,71 @@
|
||||
using System.Reflection;
|
||||
using WebUI;
|
||||
using WebUI.Services;
|
||||
using WebUI.Components;
|
||||
|
||||
#region Load External (Unmanaged) Assemblies
|
||||
|
||||
// This code is used to load external (unmanaged) assemblies from the same folder as the executing assembly.
|
||||
// It handles the AssemblyResolve event to search for the requested assembly in a specific folder structure.
|
||||
// The folder structure is expected to be: <ExecutingAssemblyDirectory>/Libraries/<RequestingAssemblyName>/<AssemblyName>.<Extension>
|
||||
// The extensions to search for are specified in the 'extensions' parameter.
|
||||
|
||||
var currentDomain = AppDomain.CurrentDomain;
|
||||
currentDomain.AssemblyResolve += (sender, args) => LoadFromSameFolder(sender,args, [".dll", ".so", ".dylib"]);
|
||||
|
||||
static Assembly? LoadFromSameFolder(object? sender, ResolveEventArgs args, string[] extensions)
|
||||
{
|
||||
string? requestingAssemblyName = args.RequestingAssembly?.GetName().Name;
|
||||
string executingAssemblyLocation = Assembly.GetExecutingAssembly().Location;
|
||||
string? executingAssemblyDirectory = Path.GetDirectoryName(executingAssemblyLocation);
|
||||
|
||||
if (string.IsNullOrEmpty(executingAssemblyDirectory))
|
||||
{
|
||||
Console.WriteLine($"Error: Could not determine the directory of the executing assembly.");
|
||||
return null;
|
||||
}
|
||||
|
||||
string librariesFolder = Path.Combine(executingAssemblyDirectory, "Libraries", requestingAssemblyName ?? "");
|
||||
string requestedAssemblyNameWithoutExtension = new AssemblyName(args.Name).Name;
|
||||
|
||||
Console.WriteLine($"Requesting Assembly: {requestingAssemblyName}");
|
||||
Console.WriteLine($"Requested Assembly Name (without extension): {requestedAssemblyNameWithoutExtension}");
|
||||
Console.WriteLine($"Searching in folder: {librariesFolder}");
|
||||
Console.WriteLine($"Searching for extensions: {string.Join(", ", extensions)}");
|
||||
|
||||
foreach (string extension in extensions)
|
||||
{
|
||||
string assemblyFileName = requestedAssemblyNameWithoutExtension + extension;
|
||||
string assemblyPath = Path.Combine(librariesFolder, assemblyFileName);
|
||||
|
||||
Console.WriteLine($"Attempting to load from: {assemblyPath}");
|
||||
|
||||
if (File.Exists(assemblyPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileAssembly = Assembly.LoadFrom(assemblyPath);
|
||||
Console.WriteLine($"Successfully loaded Assembly: {fileAssembly.FullName}");
|
||||
return fileAssembly;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error loading assembly from '{assemblyPath}': {ex.Message}");
|
||||
// Optionally log the full exception for debugging
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"File not found: {assemblyPath}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"Failed to load assembly '{args.Name}' from the specified locations.");
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
Reference in New Issue
Block a user