Domanda

Vorrei fornire qualche modo di creare caricabili dinamicamente plugin nel mio software.Tipico modo per farlo è utilizzando il LoadLibrary WinAPI funzione per caricare una dll e chiamata GetProcAddress per ottenere un puntatore a una funzione all'interno di che dll.

La mia domanda è come faccio a caricare dinamicamente un plugin in C#/.Net applicazione?

È stato utile?

Soluzione

Il seguente frammento di codice (C #) costruisce un'istanza di tutte le classi concrete derivate da Base trovate nelle librerie di classi (* .dll) nel percorso dell'applicazione e le memorizza in un elenco.

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

Modifica: le classi a cui fa riferimento Matt sono probabilmente un'opzione migliore in .NET 3.5.

Altri suggerimenti

A partire da .NET 3.5 esiste un modo formalizzato e integrato per creare e caricare plugin da un'applicazione .NET. È tutto nello spazio dei nomi System.AddIn . Per ulteriori informazioni è possibile consultare questo articolo su MSDN: Componenti aggiuntivi ed estensibilità

Caricamento dinamico dei plug-in

Per informazioni su come caricare in modo dinamico gli assembly .NET, vedere questa domanda (e la mia risposta ). Ecco un po 'di codice per caricare la creazione di un AppDomain e il caricamento di un assembly in esso.

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

Plug-in di scarico

Un requisito tipico di un framework di plugin è scaricare i plugin. Per scaricare assembly caricati dinamicamente (ad esempio plug-in e componenti aggiuntivi) è necessario scaricare il AppDomain contenente. Per ulteriori informazioni, consultare questo articolo su MSDN su Unloading AppDomains .

Uso di WCF

Esiste una domanda di overflow dello stack e risposta che descrive come utilizzare Windows Communication Framework (WCF) per creare un framework di plug-in.

Quadri plug-in esistenti

Conosco due framework di plug-in:

Alcune persone parlano del Managed Extensibility Framework (MEF) come plug-in o framework aggiuntivo, che non lo è. Per ulteriori informazioni, vedere questa domanda StackOverflow.com e questa domanda StackOverflow.com .

Un suggerimento è caricare tutti i plugin e simili in un proprio AppDomain, poiché il codice in esecuzione può essere potenzialmente dannoso. Un proprio AppDomain può anche essere usato per "filtrare" assiemi e tipi che non si desidera caricare.

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

E per caricare un assembly nel dominio dell'applicazione:

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

Per scaricare il dominio dell'applicazione:

AppDomain.Unload(domain);

Sì, ++ a Matt e System.AddIn (sono disponibili articoli di una rivista MSDN in due parti su System.AddIn qui e qui ). Un'altra tecnologia che potresti voler prendere in considerazione per farti un'idea di dove .NET Framework potrebbe andare in futuro è il gestito Extensibility Framework attualmente disponibile in formato CTP su Codeplex.

Fondamentalmente puoi farlo in due modi.

Il primo è importare kernel32.dll e utilizzare LoadLibrary e GetProcAddress come in precedenza:

[DllImport("kernel32.dll")]

internal static extern IntPtr LoadLibrary(String dllname);

[DllImport("kernel32.dll")]

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

Il secondo è farlo in modo .NET: usando reflection. Controllare lo spazio dei nomi System.Reflection e i seguenti metodi:

Prima carichi l'assembly dal suo percorso, quindi ottieni il tipo (classe) da esso con il suo nome, quindi ottieni nuovamente il metodo della classe dal suo nome e infine chiama il metodo con i parametri pertinenti.

L'articolo è un po 'più vecchio, ma è ancora applicabile per creare un livello di estensibilità all'interno dell'applicazione:

Consenti agli utenti di aggiungere funzionalità alle tue applicazioni .NET con macro e plug-in

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top