2010-03-22 5 views
4

Я создаю программу, которая использует очень простую систему плагинов. Это код, я использую, чтобы загрузить возможный плагины:Конкретные пути приложения для DLL Загрузка при динамической загрузке DLL

public interface IPlugin 
    { 
    string Name { get; } 
    string Description { get; } 
    bool Execute(System.Windows.Forms.IWin32Window parent); 
    } 


    private void loadPlugins() 
    { 
    int idx = 0; 
    string[] pluginFolders = getPluginFolders(); 
    Array.ForEach(pluginFolders, folder => 
    { 
     string[] pluginFiles = getPluginFiles(folder); 
     Array.ForEach(pluginFiles, file => 
     { 
     try 
     { 
      System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(file); 
      Array.ForEach(assembly.GetTypes(), type => 
      { 
      if(type.GetInterface("PluginExecutor.IPlugin") != null) 
      { 
       IPlugin plugin = assembly.CreateInstance(type.ToString()) as IPlugin; 
       if(plugin != null) 
       lista.Add(new PluginItem(plugin.Name, plugin.Description, file, plugin)); 
      } 
      }); 
     } 
     catch(Exception) { } 
     }); 
    }); 
    } 

Когда пользователь выбирает конкретный плагин из списка, я запускаю Execute метод плагина. Все идет нормально! Как вы можете видеть, плагины загружаются из папки, а внутри папки находятся несколько dll, которые необходимы, но плагин. Моя проблема в том, что я не могу заставить плагин «видеть» DLL, он просто ищет папку запуска запуска приложений, но не папку, в которую был загружен плагин.

Я пробовал несколько способов: 1. Изменение текущего каталога в папку плагинов. 2. С помощью вызова между оп к SetDllDirectory 3. Добавление записи в реестре, чтобы указать папку, где я хочу, чтобы она выглядела (см код ниже)

Ни один из этих методов работы. Что мне не хватает? Когда я загружаю плагин dll динамически, он, похоже, не подчиняется ни одному из вышеупомянутых методов. Что еще я могу попробовать?

С уважением, MartinH.

//HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths 
Microsoft.Win32.RegistryKey appPaths = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(
    string.Format(
    @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\{0}", 
    System.IO.Path.GetFileName(Application.ExecutablePath)), 
    Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree); 
appPaths.SetValue(string.Empty, Application.ExecutablePath); 
object path = appPaths.GetValue("Path"); 
if(path == null) 
    appPaths.SetValue("Path", System.IO.Path.GetDirectoryName(pluginItem.FileName)); 
else 
{ 
    string strPath = string.Format("{0};{1}", path, System.IO.Path.GetDirectoryName(pluginItem.FileName)); 
    appPaths.SetValue("Path", strPath); 
} 
appPaths.Flush(); 
+0

Добавить тег 'plugin' – Pat

ответ

2

Использование Assembly.LoadFrom не Assembly.LoadFile

+0

Если я использую этот метод, мой интерфейс, который присутствует в исполняющей программе, также присутствует в загруженной сборке, и программа не может различать их. Как бы я это сделал? С уважением, Martin. – MartinHT

+0

Erm он не должен иметь интерфейс в обоих местах, вы должны определить его один раз в основной сборке, а затем каждая сборка плагина должна ссылаться на базовую версию этого типа. Затем вы можете использовать что-то вроде 'Type.IsAssignableFrom', чтобы определить, реализует ли тип в вашем списке необходимый вам интерфейс. – tyranid

+0

Да, у меня есть интерфейс, определенный в его собственной сборке, и как исполняющая программа, так и плагин ссылаются на нее. Например, у меня есть prog.exe и plugin.dll (где IPlugin определен) в корневой папке. Тогда у меня есть вложенная папка, где у меня есть myplugin.dll (фактический рабочий плагин) и plugin.dll (ссылка на myplugin.dll). Когда я использую LoadFrom для загрузки myplugin, он также загружает ссылочный файл plugin.dll, который уже присутствует в моей исполняющей сборке. Надеюсь, я определил свою проблему немного яснее. С уважением, Martin. – MartinHT

2

Всякий раз, когда я динамически загружать плагины, как это, я обычно создаю домен приложения и загрузить сборку в новом домене приложения. При создании домена приложения вы можете указать базовый каталог. Зависимые сборки будут загружены из этого базового каталога.

+0

Хм, я думал об этом, но как я могу использовать открытость в новом AppDomain? Мне нужно динамически загружать мою сборку в новый AppDomain и перечислить ее тип, чтобы увидеть, реализует ли он мой интерфейс (IPlugin). – MartinHT

+0

Вы можете отобразить сборку в текущем домене приложения, получить список классов, реализующих интерфейс IPlugin, а затем передать местоположение сборки и имя класса в новый домен приложения. В новом домене приложения вы можете загрузить сборку и создать экземпляр класса интерфейса IPlugin. – Tallek

+0

Да, мне нравится эта идея. Простой, но эффективный, я попробую. Большое спасибо. – MartinHT

Смежные вопросы