Home > Back-end >  Assembly/DLL loading
Assembly/DLL loading

Time:10-09

I am using a shared DLL. In my Main() I add a handler to AppDomain.CurrentDomain.AssemblyResolve which loads the DLL. This works for some of my programs, others crash before even getting into Main() with a System.IO.FileNotFoundException (it could not locate the DLL file).

Does anybody know why some of my programs try to load the DLL before getting into Main() and others do not? What must I change to prevent the loading of the DLL before reaching Main()?

CodePudding user response:

I have made a repro. As stressed, it is important that you provide a minimal, reproducible example.

It involves a public enum property (Address.All in your case). When I deploy this program and remove the shared DLL, this throws without invoking my event handler:

public class Program
{
    public static void Main(string[] args)
    {
        AppDomain.CurrentDomain.AssemblyResolve  = AssemblyResolveHandler;

        Console.WriteLine("In Main()");

        _ = new Foo();
    }

    private static Assembly AssemblyResolveHandler(object sender, ResolveEventArgs args)
    {
        throw new NotImplementedException("I'm afraid I can't do that, Dave.");
    }
}

public class Foo
{
    public Foo()
    {
        Console.WriteLine("In Foo constructor");
    }

    public SharedClassLibrary.SharedEnum Unused { get; set; }
}

The shared class library consists of just this:

namespace SharedClassLibrary
{
    public enum SharedEnum
    {
        Zero = 0,
        One = 1
    }
}

Running this program without the shared DLL present throws a FileNotFoundException complaining about a missing DLL even before entering the Main() method.

So the solution is to have the assembly next to your executable, I don't know why you want to involve your own assembly loading code.

The cause is the JIT, wanting to know everything about the types used within the Main() method. This type Foo is used, and in order to instantiate it, the runtime has to know everything about Foo, among others to be able to allocate memory for the instance.

Part of Foo is an enum, and since enums can inherit from various numeric types with varying sizes (one byte or more), the runtime wants to look up the enum's definition, hence has to load the assembly.

The workaround is to instantiate your form in a new method:

public static void Main(string[] args)
{
    AppDomain.CurrentDomain.AssemblyResolve  = AssemblyResolveHandler;

    Console.WriteLine("In Main()");

    RunApplication();
}

private static void RunApplication()
{
    _ = new Foo();
    // or in your case, Application.Run(new MainForm());
}

This shows that my custom assembly resolver is hit:

In Main()

Unhandled exception. System.IO.FileLoadException: Could not load file or assembly 'SharedClassLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Not implemented (0x80004001 (E_NOTIMPL)) File name: 'SharedClassLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'

---> System.NotImplementedException: I'm afraid I can't do that, Dave.

  • Related