Assembly.LoadFrom is not loading DLL from folder

0

I built an app that needs access to three DLL's for an optional feature. Since it's optional, I don't ship those 3 DLL's and let the user select if he wants or not to have it. But since I'm actually using the DLL in code, I need to reference them (via nuget).

The problem is that if those 3 DLL's are stored in a folder different than where the main executable is located, the app fails to access them.

SharpDX.Direct3D11.dll
SharpDX.dll
SharpDX.DXGI.dll

I already tried to manually call Assembly.LoadFrom(path) without success.
The strange part is that the app fails to load one of them:

Load

*** Assembly Binder Log Entry  (27/02/2020 @ 10:51:36) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
Running under executable  C:\Program Files (x86)\MyApp\MyApp.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = SharpDX.DXGI, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/MyApp/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyApp.exe
Calling assembly : MyApp, Version=2.21.1.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Post-policy reference: SharpDX.DXGI, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/MyApp/SharpDX.DXGI.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/MyApp/SharpDX.DXGI/SharpDX.DXGI.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/MyApp/SharpDX.DXGI.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/MyApp/SharpDX.DXGI/SharpDX.DXGI.EXE.
LOG: All probing URLs attempted and failed.



*** Assembly Binder Log Entry  (27/02/2020 @ 10:51:36) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
Running under executable  C:\Program Files (x86)\MyApp\MyApp.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = SharpDX.DXGI, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/MyApp/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyApp.exe
Calling assembly : MyApp, Version=2.21.1.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Post-policy reference: SharpDX.DXGI, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/MyApp/SharpDX.DXGI.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/MyApp/SharpDX.DXGI/SharpDX.DXGI.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/MyApp/SharpDX.DXGI.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/MyApp/SharpDX.DXGI/SharpDX.DXGI.EXE.
LOG: All probing URLs attempted and failed.

The code that tried to load the three DLL's is this and it runs right before any call or reference to the SharpDX library appears, I debugged and it executes those lines normally:

public static void LoadSharpDx()
{
    var realPath = UserSettings.All.SharpDxLocationFolder ?? "";

    //In order to get the correct location, I need to combine the current base directory with the relative path.
    if (!string.IsNullOrWhiteSpace(UserSettings.All.SharpDxLocationFolder) && !Path.IsPathRooted(UserSettings.All.SharpDxLocationFolder))
        realPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, UserSettings.All.SharpDxLocationFolder.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));

    if (string.IsNullOrEmpty(realPath) || realPath == ".")
        return;

    //The realPath is C:\Users\nicke\Desktop\Dll  
    //So, it's correct.

    Assembly.LoadFrom(Path.Combine(realPath, "SharpDX.dll"));
    Assembly.LoadFrom(Path.Combine(realPath, "SharpDX.Direct3D11.dll"));
    Assembly.LoadFrom(Path.Combine(realPath, "SharpDX.DXGI.dll"));

    //Throws a different error.
    //Assembly.Load(Path.Combine(realPath, "SharpDX.dll"));
    //Assembly.Load(Path.Combine(realPath, "SharpDX.Direct3D11.dll"));
    //Assembly.Load(Path.Combine(realPath, "SharpDX.DXGI.dll"));
}

When analyzing ProcMon, I can see that the app is able to find and load the DLL inside the folder.

ProcMon

So, what's going on?

Why can't it load the SharpDX.DXGI library?

c#
.net
.net-4.8
asked on Stack Overflow Feb 27, 2020 by Nicke Manarin

1 Answer

0

So, I interpreted wrong what Assembly.LoadFrom() was doing.

In the end, I just had to use the CurrentDomain.AssemblyResolve event:

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    try
    {
        var assemblyName = args.Name.Split(',').First();

        if (!assemblyName.StartsWith("SharpDX"))
            return null;

        //Simply converts relative paths to full paths in order to
        //prevent getting the wrong path when the app is loaded from a
        //link or "Open with..." commands.
        var path = Other.AdjustPath(UserSettings.All.SharpDxLocationFolder ?? "");

        return Assembly.LoadFrom(System.IO.Path.Combine(path, $"{assemblyName}.dll"));
    }
    catch (Exception e)
    {
        LogWriter.Log(e, "Error loading assemblies");
        return null;
    }
}
answered on Stack Overflow Feb 27, 2020 by Nicke Manarin

User contributions licensed under CC BY-SA 3.0