6

I'm following http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx

I've added WPFToolkit.Extended.dll to my solution, and set its Build Action to Embedded Resource.

In App.OnStartup(StartupEventArgs e) I have the following code:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    String resourceName = "AssemblyLoadingAndReflection." + new AssemblyName(args.Name).Name + ".dll";
    String assemblyName = Assembly.GetExecutingAssembly().FullName;
    Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
    using (stream)
    {
        Byte[] assemblyData = new Byte[stream.Length];
        stream.Read(assemblyData, 0, assemblyData.Length);
        return Assembly.Load(assemblyData);
    }
};

The debugger hits this block of code twice.

First time:

resourceName is "AssemblyLoadingAndReflection.StatusUtil.resources.dll"
assemblyName is "StatusUtil, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
stream is null

Second time:

resourceName is "AssemblyLoadingAndReflection.WPFToolkit.Extended.resources.dll"
assemblyName is "StatusUtil, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
stream is null

The code throws an exception when it hits stream.Length, since it's null.

I can't use ILMerge because it's a WPF project.

epalm
  • 4,283
  • 4
  • 43
  • 65

5 Answers5

8

You have to change the string "AssemblyLoadingAndReflection" to the name of your application assembly.

One thing you can do to make this code more generic by using some more reflection:

Assembly.GetExecutingAssembly().FullName.Split(',').First()

Don't forget to append a dot. This will of course not work if the dll is not in the resources of the application assembly.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • 1
    Did you place the dll in a folder? – H.B. Jun 23 '11 at 19:02
  • No, it's in the root of the project. – epalm Jun 23 '11 at 19:03
  • I don't understand your answer. I'm doing `String resourceName = Assembly.GetExecutingAssembly().FullName.Split(',').First() + "." + new AssemblyName(args.Name).Name + ".dll";` which gets me "StatusUtil.WPFToolkit.Extended.resources.dll", same symptoms. What should resourceName actually be, in its entirety? – epalm Jun 23 '11 at 19:09
  • That path looks about correct, but the file in your resources needs to fit this, i.e. it's name should be `WPFToolkit.Extended.resources.dll`. – H.B. Jun 23 '11 at 19:10
  • Renaming the dll seems to work in this block of code, but causes problems elsewhere. `xmlns:extToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended"` used to work in MainWindow.xaml, but doesn't now, and neither does `xmlns:extToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended.resources"` – epalm Jun 23 '11 at 19:15
  • While trying this myself, in the inner exception the FusionLog property is bickering about needing the fully qualified name of the assembly. As its late and I am tired I am not sure weather I am on the right track at all, but maybe you guys can do anything with that info. – Sascha Hennig Jun 23 '11 at 19:16
  • @epalm: Then you need to clean up those places, the file should have the name of the assembly it contains. – H.B. Jun 23 '11 at 19:18
  • That's what I'm saying, `assembly=WPFToolkit.Extended` used to work, doesn't now, and neither does `assembly=WPFToolkit.Extended.resources`. I'm not sure what else to put in this xmlns attribute. – epalm Jun 23 '11 at 19:19
  • I just mangled the string in AppDomain.CurrentDomain.AssemblyResolve's lambda to match the name of the dll. I don't know why args.Name contains/appends ".resources" to the assembly it wants to load. This seems to work: `Assembly assembly = Assembly.GetExecutingAssembly(); String assemblyName = assembly.FullName.Split(',').First(); String resourceName = new AssemblyName(args.Name).Name.Replace(".resources", ""); String path = String.Format("{0}.{1}.dll", assemblyName, resourceName);` – epalm Jun 23 '11 at 19:59
  • I did not have problems with it so for but if it can still locate the file that is fine i guess, even though i would do it the other way around. – H.B. Jun 23 '11 at 20:03
  • the problems appear as soon as there is a ".resources" file in the ManifestResourceFiles. I cannot set those to CompileType=EmbeddedResource, i cannot find those in the list of GetManifestResourceNames, changing the name to .dll.resources also didnt help to read into those. Also the App.Main.Namespace is something i cannot handle. – efkah Jan 16 '13 at 12:32
2

The answer by H.B. is actually not quite right. The prefix we need is not the name of the assembly, but the default namespace of the project. This is probably impossible to get entirely reliably, but the following code would be much more reliable than assuming it's the same as the assembly name.

Assembly thisAssembly = Assembly.GetEntryAssembly();
String resourceName = string.Format("{0}.{1}.dll",
    thisAssembly.EntryPoint.DeclaringType.Namespace,
    new AssemblyName(args.Name).Name);
Nathan Phillips
  • 11,899
  • 1
  • 31
  • 24
2

Nathan Philip's Answer worked like a charm for me..

This is the entire method that worked for me (and it works for multiple dlls also)

public MainWindow()
    {
        InitializeComponent();

        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            Assembly thisAssembly = Assembly.GetEntryAssembly();
            String resourceName = string.Format("{0}.{1}.dll",
                thisAssembly.EntryPoint.DeclaringType.Namespace,
                new AssemblyName(args.Name).Name);

            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
            {

                Byte[] assemblyData = new Byte[stream.Length];

                stream.Read(assemblyData, 0, assemblyData.Length);

                return Assembly.Load(assemblyData);

            }

        };
    }
dna
  • 537
  • 3
  • 8
0

I tried all of the above answers and they did not work for me. I found this post and it worked like a charm.

Post: http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application

I found that the .csproj file also needs to be edited. The post explains how to do everything.

Agrejus
  • 722
  • 7
  • 18
0

I have a full explanation of how to dynamically load embedded assemblies in StackOverflow question VB.NET embedded DLL in another DLL as embedded resource?

Community
  • 1
  • 1
Fütemire
  • 1,705
  • 1
  • 26
  • 21