在WPF项目中将DLL作为嵌入式资源包含进来

6
我将遵循http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx
我已经将WPFToolkit.Extended.dll添加到我的解决方案中,并将其构建操作设置为嵌入式资源。
在App.OnStartup(StartupEventArgs e)中,我有以下代码:
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);
    }
};

调试器会两次进入这个代码块。
第一次:
resourceName is "AssemblyLoadingAndReflection.StatusUtil.resources.dll"
assemblyName is "StatusUtil, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
stream is null

第二次:

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

当代码遇到stream.Length为null时,会抛出异常。

由于这是一个WPF项目,因此无法使用ILMerge。

5个回答

8

您需要将字符串"AssemblyLoadingAndReflection"更改为您的应用程序程序集的名称。

您可以通过使用更多反射来使此代码更加通用:

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

不要忘记添加一个点号。当然,如果dll不在应用程序程序集的资源中,则无法正常工作。


1
你把 dll 放在文件夹里了吗? - H.B.
不,它在项目的根目录。 - epalm
我不理解你的回答。我正在执行 String resourceName = Assembly.GetExecutingAssembly().FullName.Split(',').First() + "." + new AssemblyName(args.Name).Name + ".dll"; 这段代码,它给我返回了 "StatusUtil.WPFToolkit.Extended.resources.dll",出现了相同的症状。请问完整的 resourceName 应该是什么? - epalm
重命名dll似乎在这个代码块中起作用,但会在其他地方引起问题。xmlns:extToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended"曾经在MainWindow.xaml中起作用,但现在不行了,xmlns:extToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended.resources"也是如此。 - epalm
只要在ManifestResourceFiles中有“.resources”文件,问题就会出现。我无法将它们设置为CompileType=EmbeddedResource,也找不到它们在GetManifestResourceNames列表中,将名称更改为.dll.resources也无法帮助读取它们。此外,App.Main.Namespace是我无法处理的内容。 - efkah
显示剩余6条评论

2

对我来说,Nathan Philip的答案非常有效。

这是整个方法,对我很有用(对多个dll也适用)。

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

            }

        };
    }

2
H.B.的回答实际上并不完全正确。我们需要的前缀不是程序集的名称,而是项目的默认命名空间。要完全可靠地获取它可能是不可能的,但是以下代码比假设它与程序集名称相同要可靠得多。
Assembly thisAssembly = Assembly.GetEntryAssembly();
String resourceName = string.Format("{0}.{1}.dll",
    thisAssembly.EntryPoint.DeclaringType.Namespace,
    new AssemblyName(args.Name).Name);

0

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接