Quantcast
Channel: reflection – Tag
Viewing all articles
Browse latest Browse all 2

Embedded Class Libraries (DLL)

$
0
0

Sometimes we need to prepare a single file application, but what if we want to split a code into DLLs or use 3rd party libraries?

Fortunately .NET provides an event AssemblyResolve, which allows us to resolve them manually. In this article I will show how to prepare a Windows Forms Application with loading DLLs from resources.

1. Include DLLs

Add references

First we need to add references to our libraries, so that we would be able to use them in our project.

Add references
Add references
Disable “Copy Local”

As we want to embed those libraries, we don’t want them to be copied into our output directory. We need to right click on each reference to our DLL, go to Properties and set Copy Local to false.

Add to resources

Now we need to put our libraries into the project’s resources. Go to Solution Explorer, select Properties and double click on Resources.resx. In the designer add compiled DLL files.

Add libraries to resources
Add libraries to resources

When it’s done, there will be created a directory Resources with copied DLLs.

Copied libraries
Copied libraries
Change Build Action

There is one more thing we need to do – change build action. Go to Solution Explorer, right click on each resource (Library1.dll, Library2.dll), open Properties and set Build Action to Embedded Resource. Now our libraries are ready and will be included in the executable file.

2. Load libraries from resources

Ok, we’ve got included DLLs, but still we need to load them, otherwise there will be thrown an exception during the first call to them. Now it’s time to use AssemblyResolve event.

We are going to list all DLLs in resources and load them using Assembly.Load(). Fortunately we don’t have to resolve all assemblies, for unknown (not ours) we can just return null. The following code contains a complete Program.cs file.

using System;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
 
namespace EmbeddedLibraries
{
    static class Program
    {
        private static Assembly ExecutingAssembly = Assembly.GetExecutingAssembly();
        private static string[] EmbeddedLibraries = 
            ExecutingAssembly.GetManifestResourceNames().Where(x => x.EndsWith(".dll")).ToArray();
 
        [STAThread]
        static void Main()
        {
            // Attach custom event handler
            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
 
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
 
        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            // Get assembly name
            var assemblyName = new AssemblyName(args.Name).Name + ".dll";
 
            // Get resource name
            var resourceName = EmbeddedLibraries.FirstOrDefault(x => x.EndsWith(assemblyName));
            if (resourceName == null)
            {
                return null;
            }
 
            // Load assembly from resource
            using (var stream = ExecutingAssembly.GetManifestResourceStream(resourceName))
            {
                var bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                return Assembly.Load(bytes);
            }
        }
    }
}

AssemblyResolve event

If you write your own AssemblyResolve handler, be aware that some methods like for example Assembly.Load(name) can cause a stack overflow, because of recursion. For more information read this.

Sample project

Viewing all articles
Browse latest Browse all 2

Trending Articles