MyApp is a C# .NET v4.5.2 WPF app. MyAssembly is a Matlab .NET assembly I created containing MyClass. MyAssembly requires MCR v9.1. MyApp performs various tasks; when one requires Matlab and it tries to instantiate MyClass then a popup window displays:
The procedure entry point H5Rdereference could not be located in dynamic link library C:\Program Files\MATLAB\MATLAB Runtime\v91\bin\win64\libmat.dll.
MyApp contains a version of hdf5.dll (obtained from Nuget package HDF.PInvoke v1.10.1), and I discovered that MCR 9.1 also contains a (different) version of hdf5.dll in C:\Program Files\MATLAB\MATLAB Runtime\v91\bin\win64. When I replaced MyApp's version of that dll with MCR 9.1's version, MyApp is able to instantiate MyClass, but then MyApp is no longer able to perform its HDF5 tasks; calls to H5.open() throw:
Unable to load DLL 'hdf5.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)'
MyClass doesn't require HDF5, so why is the MCR loading its copy of that DLL?
How do I get around this conflict?
Update 1: I moved all of MyApp's non-Matlab-related use of HDF5 into a separate app domain, but the problem persists. It is as if HDF5.dll is getting loaded into the primary app domain even though the code that loads it is executing in a separate app domain.
HDF5.dll is a native DLL and thus not bound by AppDomain boundaries.
Related
This is a .NET Core 2.0 console app that loads a C++ dll (DllImport). It "works on my machine" (windows 10, .NET Core 2.1.103) in all situations.
But when deployed in the staging env. it does not work if the exe is not executed from its current directory: if I run the executable from the parent directory, I get a System.DllNotFoundException: Unable to load DLL '***' : The specified module could not be found. (Exception from HRESULT: 0x8007007E)
The problem is that this process is started this way and I have no other choices! (i.e. started from a parent process located in a parent folder)
I have tried to add a SetCurrentDirectory + SetDllDirectory in the Main method w/o any effects.
To summarize:
If the app is started from the CLI using dotnet ***.dll, it works from any directory
If the app is started the same way from another process using Process.Start(), it fails
If the app is published as an executable, it works using the CLI from its current directory
But it fails from the parent directory and of course, also using Process.Start() (which is the final use case)
Last detail: the DllImport is done in the context of an Activator.CreateInstance (using Windsor)
A bit upset...
As Thomas suggested, it was related to the c++ runtime: it works in all situations if dependencies are all present in the current executable directory. A bit confusing as it worked in some cases without copying these dependencies (maybe a problem with the runtime installation)
I'm porting a console app to .NET core which load types from external libraries. In full .NET Framework using Type.GetType("typename, assemblyname") works when the assembly is located in the same folder that executable.
In .NET Core, it returns null, wherever I place the library.
As a workaround I've installed the System.Runtime.Loader package and attached to Resolving event to force the loading from a full path:
AssemblyLoadContext.Default.Resolving += Default_Resolving;
type = Type.GetType(value);
where delegate is:
private static Assembly Default_Resolving(AssemblyLoadContext context, AssemblyName assembly)
{
return context.LoadFromAssemblyPath(Path.Combine(Directory.GetCurrentDirectory(), #"bin\Debug\netcoreapp1.1", $"{assembly.Name}.dll"));
}
The question is: where does .NET core looks for when loading an external assembly?
This took me ages to work out. Dynamic loads only happen from the execution directory by default. Static loads are quite capable of walking into your nuget package cache (this is what .runtimeconfig.json and .deps.json are for), but if you didn't link the target dll it won't be there.
You really really don't want to load from the current directory; it's quite possibly a place unsafe to load dlls from.
To get your load path: System.IO.Path.GetDirectoryName(typeof(myclassname).GetTypeInfo().Assembly.Location)
I created a class library that references some .net core packages (like Microsoft.Extensions.DependencyInjection.Abstractions).
This class library is meant to be used as a COM library. I'm able to build the dll and register the dll of my class library. I can then load the COM object. In a separate program. However, as soon as a call a function that uses a .net core class, I get the error:
Could not load file or assembly 'Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' or one of its dependencies. The system cannot find the file specified.
I can see the Microsoft.Extensions.DependencyInjection.dll next to MyApp.dll in the bin. Do I need to register all these dll's? I tried installing the .net core runtime (both x86 and x64 versions), but that didn't work.
I have an application that relies on a set of third-party DLLs, version v1.1. In order to use them, I reference the main one, which is found somewhere under the Program Files folder. This library uses the other ones, installed in the GAC.
A new version of the third-party DLLs is released, v1.2. The DLL in the Program Files folder is replaced by the new version; in the GAC, both versions co-exist.
The problem is to get the application (compiled with DLLs v1.1) to work when v1.2 is installed, without re-compiling it, and without changing the app.exe.config file.
I am the maintainer of the DLLs; additional constraints are that only the latest version of the DLL is installed in Program Files, and other DLLs are all installed in the GAC (all versions are kept).
My problem is that the application starts, but eventually I get an error because of incompatibilities between types:
Unhandled Exception: System.InvalidCastException:
[A]ThirdParty.User cannot be cast to [B]ThirdParty.User.
Type A originates from 'ThirdParty, Version=1.2.0.0, Culture=neutral, PublicKeyToken=XXXX'
in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_32\ThirdParty\v4.0_1.2.0.0__XXXX\ThirdParty.dll'.
Type B originates from 'ThirdParty, Version=1.1.0.0, Culture=neutral, PublicKeyToken=XXXX'
in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_32\ThirdPart\v4.0_1.1.0.0__XXXX\ThirdParty.dll'.
I am not sure to understand how the v1.2 DLL is chosen, I am guessing that the path to the DLL is stored in the application, which in turn decides to use the DLLs in the GAC for this version? I am testing on a system different from the one used for compiling, but the DLLs are located in the same location. My understanding from the documentation is that the v1.1 version in the GAC should be chosen, not v1.2.
Where is my mistake? How can I fix it?
Thanks,
I found a solution in my specific case, and re-reading my question I realize I did not mention that my initial DLL does rely on a PowerShell instance. Which is where I worked around my problem. In my DLL, I load a specific version if the DLL that is present in the GAC, and load it in my PowerShell instance:
var assembly = Assembly.Load("ThirdParty, Version=1.1.0.0, Culture=neutral, PublicKeyToken=XXXX");
var ps = PowerShell.Create();
ps.Commands.AddCommand("Import-Module").AddParameter("-Assembly", assembly);
ps.Invoke();
I have a PowerShell module (.NET assembly) that references the Autofac v3.5.2 and Autofac Configuration v3.3.0 libraries. When I load this module in PowerShell:
PowerShell.exe -NoExit -Command "& {Import-Module -Name .\MyModule.dll }
PowerShell opens, but displays the error:
"Could not load file or assembly 'Autofac, Version=3.3.0.0,
Culture=neutral, PublicKeyToken=17863af14b0044da' or one of its
dependencies. The system cannot find the file specified."
However, making the same Autofac references from within a Forms or WPF app does not result in an error - everything loads correctly. Note that both the module and UI apps invoke AutoFac Configuration code - they aren't just making reference to those two libraries.
I double checked all the assembly references and they're all set to "Specific Version=False". What then about PowerShell is telling it to require a specific version of the assembly?
Based on your most recent comment, you might also have some luck handling AppDomain.CurrentDomain.AssemblyResolve as per the article linked below. I've only ever used this when creating proxies that load an appropriate x86 or x64 assembly at runtime, but it does appear you can use it for version forwarding too.
http://blog.slaks.net/2013-12-25/redirecting-assembly-loads-at-runtime/