Including a DLL as an Embedded Resource in a WPF p

2019-03-31 04:03发布

问题:

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.

回答1:

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.



回答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);


回答3:

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);

            }

        };
    }


回答4:

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.



回答5:

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?