c#类库项目 - 从同一文件夹加载DLL?

时间:2013-12-16 23:06:17

标签: c# .net dll using naudio

我正在为现有的C#.NET程序开发一个插件。它的结构是这样的,你将自定义.dll文件放在程序根目录/插件/你的插件名称/你的插件name.dll

这一切都运作良好,但现在我正在尝试在我的项目中使用NAudio。

我已经通过Nuget下载了NAudio,这部分工作正常,但问题是它在程序根目录中查找NAudio.dll,而不是在我的插件的文件夹中。

这使我很难分发我的插件,因为除了将插件放入“插件”文件夹之外,它还会依赖用户在其程序根目录中删除NAudio.dll。

来源: 的 SettingsView.xaml:

<Button HorizontalAlignment="Center"
    Margin="0 5"
    Width="120"
    Command="{Binding SoundTestCommand,
    Source={StaticResource SettingsViewModel}}"
    Content="Sound Test" />

SettingsViewModel.cs:

using NAudio.Wave;
.
.
.
    public void SoundTest()
    {
        IWavePlayer waveOutDevice;
        WaveStream mainOutputStream;
        WaveChannel32 inputStream;

        waveOutDevice = new WaveOut();

        mainOutputStream = new Mp3FileReader(@"E:\1.mp3");
        inputStream = new WaveChannel32(mainOutputStream);

        inputStream.Volume = 0.2F;

        waveOutDevice.Init(mainOutputStream);
        waveOutDevice.Play();
    }

如何让C#在Program Root / Plugins /我的插件名称/ NAudio.dll中查找NAudio,而不是在Program Root / NAudio.dll中查找?

我正在使用VS Express 2013,目标框架是4.5,输出类型是类库。

修改

我找到了两种方法来完成这项工作(我不确定这两种方法的优点和缺点是什么 - 如果有人知道我会欣赏其他信息)。

  1. 使用NuGet包 Costura.Fody

    安装NuGet包之后,我只需将所有其他引用“Copy Local”设置为“ False ”,然后将NAudio的“Copy Local”设置为“ True

    现在,当我构建时,NAudio.dll被压缩并添加到我自己的DLL中。

  2. 使用下面列出的 AssemblyResolver

    虽然它没有立即起作用,所以这里有一些额外的信息可以帮助任何人面对同样的问题:

    我将Corey的代码发布到Helpers文件夹中。

    我的入口点是Plugin.cs,类是public class Plugin : IPlugin, INotifyPropertyChanged

    在那里,输入方法是public void Initialize(IPluginHost pluginHost),但只是放PluginResolver.Init(path)不起作用。

    主机程序使用WPF并且是线程化的,我必须使用宿主程序的调度程序帮助函数才能使其工作:DispatcherHelper.Invoke(() => Resolver.Init(path));

  3. 如前所述,我目前不确定使用哪种方法,但我很高兴能让它发挥作用。谢谢科里!

1 个答案:

答案 0 :(得分:1)

您可以使用PATH环境变量将其他文件夹添加到搜索路径中。这适用于本机DLL,但我没有尝试将它用于.NET程序集。

另一种选择是在当前应用程序域上的AssemblyResolve事件中添加一个钩子,并使用自定义解析器从您找到它的任何地方加载相应的程序集。这可以在程序集级别完成 - 我在NAudio.Lame中使用它来从资源加载程序集。

这些方面的东西:

public static class PluginResolver
{
    private static bool hooked = false;
    public static string PluginBasePath { get; private set; }

    public static void Init(string BasePath)
    {
        PluginBasePath = BasePath;
        if (!hooked)
        {
            AppDomain.CurrentDomain.AssemblyResolve += ResolvePluginAssembly;
            hooked = true;
        }
    }

    static Assembly ResolvePluginAssembly(object sender, ResolveEventArgs args)
    {
        var asmName = new AssemblyName(args.Name).Name + ".dll";
        var assemblyFiles = Directory.EnumerateFiles(PluginBasePath, "*.dll", SearchOption.AllDirectories);

        var asmFile = assemblyFiles.FirstOrDefault(fn => string.Compare(Path.GetFileName(fn), asmName, true) == 0);

        if (string.IsNullOrEmpty(asmFile))
            return null;

        return Assembly.LoadFile(asmFile);
    }
}

(上述内容的使用:System.IOSystem.ReflectionSystem.Linq

使用插件文件夹的基本路径调用Init。当您尝试引用尚未加载的程序集时,它将搜索与附加dll的程序集的基本名称匹配的第一个文件。例如,NAudio程序集将匹配名为NAudio.dll的第一个文件。然后它将加载并返回组件。

上述代码中没有对版本等进行检查,也没有优先选择当前插件的文件夹。