Pergunta

Gostaria de fornecer uma maneira de criar plug-ins carregáveis ​​dinamicamente em meu software.A maneira típica de fazer isso é usar o Biblioteca de carga Função WinAPI para carregar uma dll e chamar GetProcAddress para obter um ponteiro para uma função dentro dessa dll.

Minha pergunta é como carrego dinamicamente um plugin no aplicativo C#/.Net?

Foi útil?

Solução

O trecho de código a seguir (C#) constrói uma instância de quaisquer classes concretas derivadas de Base encontrado em bibliotecas de classes (*.dll) no caminho do aplicativo e os armazena em uma lista.

using System.IO;
using System.Reflection;

List<Base> objects = new List<Base>();
DirectoryInfo dir = new DirectoryInfo(Application.StartupPath);

foreach (FileInfo file in dir.GetFiles("*.dll"))
{
    Assembly assembly = Assembly.LoadFrom(file.FullName);
    foreach (Type type in assembly.GetTypes())
    {
        if (type.IsSubclassOf(typeof(Base)) && type.IsAbstract == false)
        {
            Base b = type.InvokeMember(null,
                                       BindingFlags.CreateInstance,
                                       null, null, null) as Base;
            objects.Add(b);
        }
    }
}

Editar: As aulas referidas por Matt são provavelmente uma opção melhor no .NET 3.5.

Outras dicas

A partir do .NET 3.5, existe uma maneira formalizada e integrada de criar e carregar plug-ins de um aplicativo .NET.Está tudo no System.AddIn espaço para nome.Para mais informações você pode conferir este artigo no MSDN: Suplementos e extensibilidade

Carregando plug-ins dinamicamente

Para obter informações sobre como carregar dinamicamente assemblies .NET, consulte essa questão (e minha resposta).Aqui está um código para carregar a criação de um AppDomain e carregando um assembly nele.

var domain = AppDomain.CreateDomain("NewDomainName");
var pathToDll = @"C:\myDll.dll"; 
var t = typeof(TypeIWantToLoad);
var runnable = domain.CreateInstanceFromAndUnwrap(pathToDll, t.FullName) 
    as IRunnable;
if (runnable == null) throw new Exception("broke");
runnable.Run();

Descarregando plug-ins

Um requisito típico de uma estrutura de plugins é descarregar os plugins.Para descarregar montagens carregadas dinamicamente (por exemplo,plug-ins e suplementos), você precisa descarregar o conteúdo AppDomain.Para mais informações, veja este artigo no MSDN sobre descarregamento de AppDomains.

Usando WCF

Existe um pergunta e resposta de estouro de pilha que descrevem como usar o Windows Communication Framework (WCF) para criar uma estrutura de plug-in.

Estruturas de plug-ins existentes

Conheço duas estruturas de plug-ins:

Algumas pessoas falam sobre Estrutura de extensibilidade gerenciada (MEF) como uma estrutura de plug-in ou suplemento, o que não é.Para mais informações, veja esta pergunta do StackOverflow.com e esta pergunta do StackOverflow.com.

Uma dica é carregar todos os plugins e afins em um AppDomain próprio, já que o código em execução pode ser potencialmente malicioso.Um AppDomain próprio também pode ser usado para "filtrar" assemblies e tipos que você não deseja carregar.

AppDomain domain = AppDomain.CreateDomain("tempDomain");

E para carregar um assembly no domínio do aplicativo:

AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
Assembly assembly = domain.Load(assemblyName);

Para descarregar o domínio do aplicativo:

AppDomain.Unload(domain);

Sim, ++ para Matt e System.AddIn (um artigo de duas partes da revista MSDN sobre System.AddIn está disponível aqui e aqui).Outra tecnologia que você pode querer observar para ter uma ideia de onde o .NET Framework pode estar indo no futuro é a Estrutura de extensibilidade gerenciada atualmente disponível em formato CTP no Codeplex.

Basicamente você pode fazer isso de duas maneiras.

A primeira é importar kernel32.dll e usar LoadLibrary e GetProcAddress como você usou antes:

[DllImport("kernel32.dll")]

internal static extern IntPtr LoadLibrary(String dllname);

[DllImport("kernel32.dll")]

internal static extern IntPtr GetProcAddress(IntPtr hModule, String procname);

A segunda é fazer isso no estilo .NET:usando reflexão.Verifique o namespace System.Reflection e os seguintes métodos:

Primeiro você carrega o assembly pelo seu caminho, depois obtém o tipo (classe) dele pelo seu nome, depois obtém o método da classe pelo seu nome novamente e finalmente chama o método com os parâmetros relevantes.

O artigo é um pouco mais antigo, mas ainda é aplicável para a criação de uma camada de extensibilidade em seu aplicativo:

Permita que os usuários adicionem funcionalidade aos seus aplicativos .NET com macros e plug-ins

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top