I have an app that uses P/Invoke to call functions inside of Fusion.dll to enumerate .NET Framework assemblies in the Global Assembly Cache.
It works just fine when I target net472 but - the exact same code - does not work when I target netcoreapp2.2:
class Program
{
static void Main(string[] args)
{
GacUtility.CreateAssemblyCache(out var x, 0);
}
}
public class GacUtility
{
[DllImport("Fusion.dll")]
public static extern int CreateAssemblyCache(out object asmCache, int reserved);
}
The error message I get (in .NET Core) is:
Unhandled Exception: System.DllNotFoundException:
Unable to load DLL 'Fusion.dll' or one of its dependencies:
The specified module could not be found.
(Exception from HRESULT: 0x8007007E)
NB: I know that the correct signature of CreateAssemblyCache expects an IAssemblyName and I have that correct in my code, and gives me the same error. The code above is a simplified example that reproduces the error the same way...
.NET Core can do P/Invokes just as .NET Framework, but the Probing path that we use to find assemblies is different. In order for that to work, Fusion.dll would need to be part of the probing path for core, Have you tried having Fusion.dll copy-pasted right next to your app?
Thank you for following-up @joperezr. It works if I use the full path of Fusion.dll, so I'm sure if I would to put Fusion.dll inside my apps folder, it would work too (provided I copy any dependencies it has, if any)
[DllImport(@"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\fusion.dll")]
public static extern int CreateAssemblyCache(out IntPtr asmCache, int reserved);
My issue now is how to make this work properly:
Fusion.dll as location may differ at least for x86/x64?Fusion.dll I want, how do I add that path to .NET Core's probing path?The ideal case is that you should ship all your native dependencies along with your app. I'm not familiar with Fusion.dll, but if it is possible to get it as a NuGet dependency, that would be great so you can package that with your app and not requiring fusion.dll to be installed somewhere in the machine.
@joperezr Fusion.dll is part of the .NET Framework... I don't think it would be possible to ship it with my app. I have to check if the .NET Framework is installed on the machine, if it is is, I know it has Global Assembly Cache there...
Fusion.dll does not seem to be part of .NET Core, only Framework, so I'm not entirely sure it's expected to work, or if we support it.
What functionality are you trying to get from that DLL, @Lindsey1986 ? We might have something in Core that replaced it.
Are you still having this problem?
Since there was no response in 3 weeks, I'll go ahead and close this issue. @Lindsey1986 feel free to reopen if you have any more questions.
I am running into the same issue here for .NET 5.0, I have a .net5.0-windows application that needs to load a specific assembly from the GAC, to do that we need to query the cache via the above mentioned method:
[DllImport("Fusion.dll")]
public static extern int CreateAssemblyCache(out object asmCache, int reserved);
If the probing path is the issue how I can I modify that to work?
Or what other API can I use?
So Fusion.dll is a .NET Framework sub-system responsible for locating and loading assemblies. We probably have APIs in .NET 5.0 that can achieve the same results.
@GrabYourPitchforks @steveharter is this something that falls in the System.Reflection area that you could help with?
Use NativeLibary.Load(string), passing in the full path ("c:\blahblah\mymodule.dll") to the DLL you wish to load. Do this _before_ attempting to p/invoke into the DLL. Once the unmanaged DLL is loaded in-process, any future p/invokes decorated with [DllImport("mymodule.dll")] will bind to the already-loaded DLL.
To get the full path to fusion.dll, query the registry key listed at https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed#detect-net-framework-45-and-later-versions.
@carlossanlop We probably have APIs in .NET 5.0 that can achieve the same results.
Not for this scenario. This scenario specifically involves the Global Assembly Cache (GAC), which as a concept doesn't exist in .NET Core / .NET 5. You'd have to interface with the existing .NET Framework DLLs in order to pull this off.
_Note:_ Because the GAC doesn't exist as a concept in .NET Core, you might not be able to do much with the returned values. You shouldn't expect to be able to load .NET Framework GACed assemblies into a .NET Core process, for instance. But the steps above should still serve as the general answer for "How do I p/invoke something if I know it's installed on the machine somewhere but can't hard-code the path?"
I'm closing this issue because I believe the question has been answered. Please reopen the issue if further discussion is needed. Thanks!