Here's the setup:
A pure DotNET class library is loaded by an unmanaged desktop application. The Class Library acts as a plugin. This plugin loads little baby plugins of its own (all DotNET Class Libraries), and it does so by reading the dll into memory as a byte-stream, then
Assembly asm = Assembly.Load(COFF_Image);
The problem arises when those little baby plugins have references to other dlls. Since they are loaded via the memory rather than directly from the disk, the framework often cannot find these referenced assemblies and is thus incapable of loading them.
I can add an AssemblyResolver handler to my project and I can see these referenced assemblies drop past. I have a reasonably good idea about where to find these referenced assemblies on the disk, but how can I make sure that the Assmebly I load is the correct one?
In short, how do I reliably go from the System.ResolveEventArgs.Name field to a dll file path, presuming I have a list of all the folders where this dll could be hiding)?
When I have used this in the past we have just compared the file name with the part of the ResolveEventArgs.Name that has the name. If you want to be sure that you are loading the exact same version I suppose you could check if the names match, if they do then load the assembly and then check the assemblies full name against the ResolveEventArgs.Name.
something along these lines:
string name = GetAssemblyName (args); //gets just the name part of the assembly name
foreach (string searchDirectory in m_searchDirectories)
{
string assemblyPath = Path.Combine (executingAssemblyPath, searchDirectory);
assemblyPath = Path.Combine (assemblyPath, name + ".dll");
if (File.Exists (assemblyPath))
{
Assembly assembly = Assembly.LoadFrom (assemblyPath);
if (assembly.FullName == args.Name)
return assembly;
}
}
for completeness:
private string GetAssemblyName (ResolveEventArgs args)
{
String name;
if (args.Name.IndexOf (",") > -1)
{
name = args.Name.Substring (0, args.Name.IndexOf (","));
}
else
{
name = args.Name;
}
return name;
}
The Managed Extensibility Framework (MEF) sounds like something that'll solve all your problems. It can scan folders to locate DLLs, resolve dependencies for any depth and manages plug-in composition in general. Each part (or 'plug-in') just has to declare what it needs and what it provides, and MEF takes care of the wiring. If MEF succeeded in taming VS2010's extensibility beast, then it can handle anything.
I've never had luck with AssemblyResolver. I usually do one of these three:
Require plugins not have external references that are not in the GAC. If they bitch, tell them to ILMerge.
Require plugins to dump all their dlls into a known plugin directory. Load all assemblies in that directory into memory.
Require that plugin dependencies exist in a path that is probed by fusion. You can figure out where the binder is looking for assemblies turn on the fusion log (fuslogvw.exe--don't forget to reboot after turning on logging!).
Related
I've a directory with a large number of dlls. I need to find all those that reference a specific dll.
I'm thinking about the following solution :
Loop the assemblies and invoke each one with ildasm
Dump the manifest into a text file
Search the text files for the required assembly name.
Yet this solution feels immensely wrong to me. Is there a better way to achieve it?
You could write a small tool for that purpose, using Reflection to find the referenced assemblies:
string[] fileNames = ...; // get all the filenames
foreach (string fileName in fileNames) {
var assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(fileName);
var referencedAssemblies = assembly.GetReferencedAssemblies();
foreach (var assemblyName in referencedAssemblies) {
// do your comparison
}
}
According to Microsoft documentationnn AppDomain.CurrentDomain.GetAssemblies() Gets the assemblies that have been loaded into the execution context of this application domain. About AppDomain.CurrentDomain.GetAssemblies()
It seems that you need to change strategy of loading the asseblies you need from using the appdomain to looking for dlls in your applications folder.
I found a discuss on similar problem here
Download AsmSpy.exe, it has the option to list all assemblies and all the references within the assemblies.
https://github.com/mikehadlow/AsmSpy
Download IlSpy.exe, and open the assembly whose references you want to see, it will list all referenced assemblies.
https://github.com/icsharpcode/ILSpy/releases
today I'd like to know how do you configure your projects in C# WPF which references additional assemblies in a chain. By the "in a chain" I mean something like this:
we have application which refers to assembly Plugin
Plugin assembly refers Resources where resources used by Plugin are located, eg. images
main application does not refers to Resource in any way.
The following image illustrates what I've just said:
The problem is that Resources is not copied to the bin folder of the application, causing Plugin (Ctrl on the image) resources it requires finding failure.
Workaround
There are workarounds for it which are simply to include Resources to references of the main application or use a post-build step and manually copy required files in that step.
Conclusion
Concluding, I'd like to ask how do you deal with that problem. Are the any other solutions besides those I mentioned in workaround section? Am I missing something in the projects' configuration?
Make sure that the output directory in the Plugin project properties is same as the output directory of your application. Otherwise you have to copy files yourself as you do.
Second option would be using embedded resources.
If you load the plugin dynamically from a different folder than the EXE, you can also copy its dependencies to the same folder as the plugin and load those assemblies dynamically, as well. You then need to handle AssemblyResolve so that the already-loaded assemblies will be resolved instead of trying to find new assemblies:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var domain = (AppDomain)sender;
var assemblies = domain.GetAssemblies();
return assemblies.FirstOrDefault(assembly => assembly.GetName().Name == args.Name.Split(',')[0]);
}
The code above does a version and strong-naming insensitive match; you can implement your own policy here if you want something stricter.
I am writing an application which uses plugins. Plugins are class libraries which lie in Plug-ins directory. My app loads these libraries via LoadFrom. Some of them have dependencies in the form of libraries which lie in the same Plug-ins directory. When I try to create instance of class from one of plugins via Activator.CreateInstance i recieve an exception 'Unable to find assembly' (this is dependency assembly of plugin), but this assembly is already loaded (!) along with plugins and It is visible in ProcessExplorer.
I can't uderstand in what my trouble is.
Your problem might be, that de loaded assembly isn't the same version as the request one. .Net Runtime maps the Assembly after their name and after their Version if the name equals and the Version differes you get an exception if the other one is loaded, which says "Assembly cann't be found" or something like that. The Problem is, that the assembly could not be matched properly. But there is a solution:
Take a look at the MSDN for further information about that Problem.
Solution for that problem:
If you have to load 2 Versions of that assembly try helping the runtime by implementing the AssemblyResolve Event Samples are also here.
Try using the AssemblyBindLogViewer to determine the dependencies of your plugins and to crosscheck your problem.
I recommend implementing the event anyways if you deal with plugins,
so you can log all assembly requests of that AppDomain.
You will find furhter information about runtime behavior and assembly loading here
Hope i could help, please give us feedback about your solution!
Configuring the Plugin Folder
Load the Plugins into a seperat AppDomain which has the pluginfolder as ApplicationBaseTo configure AppDomains see. This is the recomendet solution to load Plugins, becaus you can define the security level of the AppDomain (Sandboxing)
Extend your current AppDomains PrivatePath, so it also searches the Assemblies in this Path. This method is Obsolete!(but does it's job)
You should provide Full Path of assembly files.
class Program
{
static void Main(string[] args)
{
var asmFileName = "test.dll"; // Your plug-in file name
var asmPath = AppDomain.CurrentDomain.BaseDirectory; // Your assemblies's root folder
var asmFullPath = System.IO.Path.Combine(asmPath, asmFileName);
var asm = System.Reflection.Assembly.LoadFrom(asmFullPath);
}
}
I had similar problems and they were usually solved by changing target framework in the project properties...
If you create a class library that uses things from other assemblies, is it possible to embed those other assemblies inside the class library as some kind of resource?
I.e. instead of having MyAssembly.dll, SomeAssembly1.dll and SomeAssembly2.dll sitting on the file system, those other two files get bundled in to MyAssembly.dll and are usable in its code.
I'm also a little confused about why .NET assemblies are .dll files. Didn't this format exist before .NET? Are all .NET assemblies DLLs, but not all DLLs are .NET assemblies? Why do they use the same file format and/or file extension?
ILMerge does merge assemblies, which is nice, but sometimes not quite what you want. For example, when the assembly in question is a strongly-named assembly, and you don't have the key for it, then you cannot do ILMerge without breaking that signature. Which means you have to deploy multiple assemblies.
As an alternative to ilmerge, you can embed one or more assemblies as resources into your exe or DLL. Then, at runtime, when the assemblies are being loaded, you can extract the embedded assembly programmatically, and load and run it. It sounds tricky but there's just a little bit of boilerplate code.
To do it, embed an assembly, just as you would embed any other resource (image, translation file, data, etc). Then, set up an AssemblyResolver that gets called at runtime. It should be set up in the static constructor of the startup class. The code is very simple.
static NameOfStartupClassHere()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
}
static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
{
Assembly a1 = Assembly.GetExecutingAssembly();
Stream s = a1.GetManifestResourceStream(args.Name);
byte[] block = new byte[s.Length];
s.Read(block, 0, block.Length);
Assembly a2 = Assembly.Load(block);
return a2;
}
The Name property on the ResolveEventArgs parameter is the name of the assembly to be resolved. This name refers to the resource, not to the filename. If you embed the file named "MyAssembly.dll", and call the embedded resource "Foo", then the name you want here is "Foo". But that would be confusing, so I suggest using the filename of the assembly for the name of the resource. If you have embedded and named your assembly properly, you can just call GetManifestResourceStream() with the assembly name and load the assembly that way. Very simple.
This works with multiple assemblies, just as nicely as with a single embedded assembly.
In a real app you're gonna want better error handling in that routine - like what if there is no stream by the given name? What happens if the Read fails? etc. But that's left for you to do.
In the rest of the application code, you use types from the assembly as normal.
When you build the app, you need to add a reference to the assembly in question, as you would normally. If you use the command-line tools, use the /r option in csc.exe; if you use Visual Studio, you'll need to "Add Reference..." in the popup menu on the project.
At runtime, assembly version-checking and verification works as usual.
The only difference is in distribution. When you deploy or distribute your app, you need not distribute the DLL for the embedded (and referenced) assembly. Just deploy the main assembly; there's no need to distribute the other assemblies because they're embedded into the main DLL or EXE.
Take a look at ILMerge for merging assemblies.
I'm also a little confused about why .NET assemblies are .dll files. Didn't this format exist before .NET?
Yes.
Are all .NET assemblies DLLs,
Either DLLs or EXE normally - but can also be netmodule.
but not all DLLs are .NET assemblies?
Correct.
Why do they use the same file format and/or file extension?
Why should it be any different - it serves the same purpose!
You can embed an assembly (or any file, actually) as a resource (and then use the ResourceManager class to access them), but if you just want to combine assemblies, you're better off using a tool like ILMerge.
EXE and DLL files are Windows portable executables, which are generic enough to accomodate future types of code, including any .NET code (they can also run in DOS but only display a message saying that they're not supposed to run in DOS). They include instructions to fire up the .NET runtime if it isn't already running. It's also possible for a single assembly to span across multiple files, though this is hardly ever the case.
Note ILMerge doesn't work with embedded resources like XAML, so WPF apps etc will need to use Cheeso's method.
There's also the mkbundle utility offered by the Mono project
Why do they use the same file format and/or file extension?
Why should it be any different - it serves the same purpose!
My 2¢ bit of clarification here: DLL is Dynamic Link Library. Both the old style .dll (C-code) and .net style .dll are by definition "dynamic link" libraries. So .dll is a proper description for both.
With respect to Cheeso's answer of embedding the assemblies as resources and loading them dynamically using the Load(byte[]) overload using an AssemblyResolve event handler, you need to modify the resolver to check the AppDomain for an existing instance of the Assembly to load and return the existing assembly instance if it's already loaded.
Assemblies loaded using that overload do not have a context, which can cause the framework to try and reload the assembly multiple times. Without returning an already loaded instance, you can end up with multiple instances of the same assembly code and types that should be equal but won't be, because the framework considers them to be from two different assemblies.
At least one way that multiple AssemblyResolve events will be made for the same assembly loaded into the "No context" is when you have references to types it exposes from multiple assemblies loaded into your AppDomain, as code executes that needs those types resolved.
https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx
A couple of salient points from the link:
"Other assemblies cannot bind to assemblies that are loaded without context, unless you handle the AppDomain.AssemblyResolve event"
"Loading multiple assemblies with the same identity without context can cause type identity problems similar to those caused by loading assemblies with the same identity into multiple contexts. See Avoid Loading an Assembly into Multiple Contexts."
I would suggest you to try Costura.Fody. Just don't forget to Install-Package Fody before Costura.Fody (in order to get the newest Fody!)
I have a Windows C# program that uses a C++ dll for data i/o. My goal is to deploy the application as a single EXE.
What are the steps to create such an executable?
Single Assembly Deployment of Managed and Unmanaged Code
Sunday, February 4, 2007
.NET developers love XCOPY deployment. And they love single assembly components. At least I always feel kinda uneasy, if I have to use some component and need remember a list of files to also include with the main assembly of that component. So when I recently had to develop a managed code component and had to augment it with some unmanaged code from a C DLL (thx to Marcus Heege for helping me with this!), I thought about how to make it easier to deploy the two DLLs. If this were just two assemblies I could have used ILmerge to pack them up in just one file. But this doesn´t work for mixed code components with managed as well as unmanaged DLLs.
So here´s what I came up with for a solution:
I include whatever DLLs I want to deploy with my component´s main assembly as embedded resources.
Then I set up a class constructor to extract those DLLs like below. The class ctor is called just once within each AppDomain so it´s a neglible overhead, I think.
namespace MyLib
{
public class MyClass
{
static MyClass()
{
ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll");
ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll");
}
...
In this example I included two DLLs as resources, one being an unmanaged code DLL, and one being a managed code DLL (just for demonstration purposes), to show, how this technique works for both kinds of code.
The code to extract the DLLs into files of their own is simple:
public static class ResourceExtractor
{
public static void ExtractResourceToFile(string resourceName, string filename)
{
if (!System.IO.File.Exists(filename))
using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
{
byte[] b = new byte[s.Length];
s.Read(b, 0, b.Length);
fs.Write(b, 0, b.Length);
}
}
}
Working with a managed code assembly like this is the same as usual - almost. You reference it (here: ManagedService.dll) in your component´s main project (here: MyLib), but set the Copy Local property to false. Additionally you link in the assembly as an Existing Item and set the Build Action to Embedded Resource.
For the unmanaged code (here: UnmanagedService.dll) you just link in the DLL as an Existing Item and set the Build Action to Embedded Resource. To access its functions use the DllImport attribute as usual, e.g.
[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);
That´s it! As soon as you create the first instance of the class with the static ctor the embedded DLLs get extracted into files of their own and are ready to use as if you deployed them as separate files. As long as you have write permissions for the execution directory this should work fine for you. At least for prototypical code I think this way of single assembly deployment is quite convenient.
Enjoy!
http://weblogs.asp.net/ralfw/archive/2007/02/04/single-assembly-deployment-of-managed-and-unmanaged-code.aspx
Try boxedapp; it allows to load all DLLs from memory. Also, it seems that you can even embed .net runtime. Good to create a really standalone applications...
Use Fody.Costura nuget
Open your solution -> Project -> Manage Nuget Packages
Search for Fody.Costura
Compile your project.
That's it !
Source:
http://www.manuelmeyer.net/2016/01/net-power-tip-10-merging-assemblies/
Have you tried ILMerge? http://research.microsoft.com/~mbarnett/ILMerge.aspx
ILMerge is a utility that can be used to merge multiple .NET assemblies into a single assembly. It is freely available for use from the Tools & Utilities page at the Microsoft .NET Framework Developer Center.
If you're building the C++ DLL with the /clr flag (all or partially C++/CLI), then it should work:
ilmerge /out:Composite.exe MyMainApp.exe Utility.dll
It will not work with an ordinary (native) Windows DLL however.
Just right-click your project in Visual Studio, choose Project Properties -> Resources -> Add Resource -> Add Existing File…
And include the code below to your App.xaml.cs or equivalent.
public App()
{
AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");
dllName = dllName.Replace(".", "_");
if (dllName.EndsWith("_resources")) return null;
System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
byte[] bytes = (byte[])rm.GetObject(dllName);
return System.Reflection.Assembly.Load(bytes);
}
Here's my original blog post:
http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/
Thinstall is one solution. For a native windows application I would suggest embedding the DLL as a binary resource object, then extracting it at runtime before you need it.
Smart Assembly can do this and more. If your dll has unmanaged code, it wont let you merge the dlls to a single assembly, instead it can embed the required dependencies as resources to your main exe. Its flip-side, its not free.
You can do this manually by embedding dll to your resources and then relying on AppDomain's Assembly ResolveHandler. When it comes to mixed mode dlls, I found many of the variants and flavours of ResolveHandler approach to not work for me (all which read dll bytes to memory and read from it). They all worked for managed dlls. Here is what worked for me:
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName.EndsWith(".resources"))
return null;
string dllName = assemblyName + ".dll";
string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
{
byte[] data = new byte[stream.Length];
s.Read(data, 0, data.Length);
//or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);
File.WriteAllBytes(dllFullPath, data);
}
return Assembly.LoadFrom(dllFullPath);
};
}
The key here is to write the bytes to a file and load from its location. To avoid chicken and egg problem, you have to ensure you declare the handler before accessing assembly and that you do not access the assembly members (or instantiate anything that has to deal with the assembly) inside the loading (assembly resolving) part. Also take care to ensure GetMyApplicationSpecificPath() is not any temp directory since temp files could be attempted to get erased by other programs or by yourself (not that it will get deleted while your program is accessing the dll, but at least its a nuisance. AppData is good location). Also note that you have to write the bytes each time, you cant load from location just 'cos the dll already resides there.
If the assembly is fully unmanaged, you can see this link or this as to how to load such dlls.
If you want to pack an application that already exists (including its dlls and other resources, no matter what language it's coded in) into a single .exe you can use SerGreen's Appacker for that purpose. But it'll be "detected" to "run malicious code from a hacker" because it unpacks itself:
Appacker and packages created by it can be detected as malware by some antivirus software. That's because of a hacky way i used to package files: packed app reads its own executable and extracts other files from it, which antiviruses find hella suspicious. It's false positive, but it still gets in the way of using this app.
-SerGreen on GitHub
To use it you can simply open it up, click away any virus warnings (and tell Windows Defender to not delete it!), then choose a directory that should be packed and the executable to be run after unpacking.
You can optionally change the unpacking behaviour of the app (windowed/windowless unpacker, unpacking target directory, should it be repacked or changes to the unpacked files be ignored, ...)
PostBuild from Xenocode can package up both managed and unmanged into a single exe.