C
C#2mo ago
aliser

Loading DLLs with same names

Hi! I'm making a mod loader (.net 9), and I've encountered an issue when trying to load multiple mod files (dll files) with the same name but from different locations. They have different namespaces so I expected no collisions when loading them. I was using Assembly.LoadFrom, and it worked fine for a single mod. But when I tried to load 2, I've got this error: Could not load file or assembly 'Main, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Assembly with same name is already loaded I've gathered this due to the assembly name being the same for different mods. This is done intentionally to make the mod development easier. There's still a difference in namespace naming between different mods. I tried to switch to Assembly.LoadFile (heard it can use the paths to differentiate between same-named dlls). But I started to get these errors: Could not load file or assembly '0Harmony, Version=2.3.5.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified. 0Harmony is a dependency of a mod (both mods actually, but they each have it on their own). It doesn't load for some reason. I tried messing with AssemblyLoadContext and looking up solutions online, but it's a bit too advanced for me. Please help 😭
5 Replies
Arjix
Arjix2mo ago
are you making a modloader to be compatible with other mod loaders? usually, mods don't have their own 0Harmony.dll, they expect the mod loader to already have it so they simply depend on it
Arjix
Arjix2mo ago
for example BepInEx, has the core directory
No description
Arjix
Arjix2mo ago
mods don't ship with those dlls but they expect them to exist and be loaded by the modloader, in this example BepInEx
aliser
aliserOP2mo ago
makes sense this wouldn't solve the problem with dependencies though? if a mod decides to use some library, it would be a dependency shipped with the mod and still wouldn't load, resulting in an error. managed to solve this by using AssemblyLoadContext and manually loading dependencies. something like this:
c#
ModAssemblyLoadContext assemblyLoadCtx = new ModAssemblyLoadContext();
assemblyLoadCtx.LoadFromAssemblyPath(dllAbsPath);
assemblyLoadCtx.Resolving += ModAssemblyLoadContext.ResolveDependencies;
assembly = ModAssemblyLoadContext.GetMainAssembly(assemblyLoadCtx);
c#
ModAssemblyLoadContext assemblyLoadCtx = new ModAssemblyLoadContext();
assemblyLoadCtx.LoadFromAssemblyPath(dllAbsPath);
assemblyLoadCtx.Resolving += ModAssemblyLoadContext.ResolveDependencies;
assembly = ModAssemblyLoadContext.GetMainAssembly(assemblyLoadCtx);
c#
class ModAssemblyLoadContext : AssemblyLoadContext {
public ModAssemblyLoadContext()
: base("ModAssemblyLoadContext") { }

/// <summary>
/// Returns the main assembly.
/// </summary>
public static Assembly GetMainAssembly(AssemblyLoadContext ctx) {
Assembly? mainAssembly = ctx.Assemblies.FirstOrDefault();
if(mainAssembly == null) {
throw new NullReferenceException("Failed to extract the main assembly");
}

return mainAssembly;
}

/// <summary>
/// Resolves dependencies for a given assembly.
/// </summary>
public static Assembly? ResolveDependencies(AssemblyLoadContext ctx, AssemblyName depAssemblyName) {
string depAssemblyFilename = depAssemblyName.Name + ".dll";

Assembly mainAssembly = GetMainAssembly(ctx);
string mainAssemblyLoadedFrom = Path.GetDirectoryName(mainAssembly.Location);

string depAssemblyPathAlongMainAssembly = Path.Combine(mainAssemblyLoadedFrom, depAssemblyFilename);
if(File.Exists(depAssemblyPathAlongMainAssembly)) {
return Assembly.LoadFrom(depAssemblyPathAlongMainAssembly);
}

return null;
}
}
c#
class ModAssemblyLoadContext : AssemblyLoadContext {
public ModAssemblyLoadContext()
: base("ModAssemblyLoadContext") { }

/// <summary>
/// Returns the main assembly.
/// </summary>
public static Assembly GetMainAssembly(AssemblyLoadContext ctx) {
Assembly? mainAssembly = ctx.Assemblies.FirstOrDefault();
if(mainAssembly == null) {
throw new NullReferenceException("Failed to extract the main assembly");
}

return mainAssembly;
}

/// <summary>
/// Resolves dependencies for a given assembly.
/// </summary>
public static Assembly? ResolveDependencies(AssemblyLoadContext ctx, AssemblyName depAssemblyName) {
string depAssemblyFilename = depAssemblyName.Name + ".dll";

Assembly mainAssembly = GetMainAssembly(ctx);
string mainAssemblyLoadedFrom = Path.GetDirectoryName(mainAssembly.Location);

string depAssemblyPathAlongMainAssembly = Path.Combine(mainAssemblyLoadedFrom, depAssemblyFilename);
if(File.Exists(depAssemblyPathAlongMainAssembly)) {
return Assembly.LoadFrom(depAssemblyPathAlongMainAssembly);
}

return null;
}
}
Ꜳåąɐȁặⱥᴀᴬ
if you look at nick cosentino's videos he deals with these topics

Did you find this page helpful?