Question

J'aimerais proposer un moyen de créer des plugins chargeables dynamiquement dans mon logiciel.Une manière typique de procéder consiste à utiliser le Charger la bibliothèque Fonction WinAPI pour charger une DLL et appeler ObtenirProcAddress pour obtenir un pointeur vers une fonction à l’intérieur de cette dll.

Ma question est de savoir comment charger dynamiquement un plugin dans une application C#/.Net ?

Était-ce utile?

La solution

L'extrait de code suivant (C#) construit une instance de toutes les classes concrètes dérivées de Base trouvé dans les bibliothèques de classes (*.dll) dans le chemin de l'application et les stocke dans une liste.

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

Modifier: Les classes mentionnées par Mat sont probablement une meilleure option dans .NET 3.5.

Autres conseils

Depuis .NET 3.5, il existe un moyen formalisé et intégré de créer et de charger des plugins à partir d'une application .NET.Tout est dans le Système.AddIn espace de noms.Pour plus d'informations, vous pouvez consulter cet article sur MSDN : Compléments et extensibilité

Chargement dynamique des plug-ins

Pour plus d’informations sur la façon de charger dynamiquement des assemblys .NET, consultez cette question (et ma réponse).Voici un code à charger pour créer un AppDomain et y charger un assembly.

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

Déchargement des plug-ins

Une exigence typique d’un framework de plugins est de décharger les plugins.Pour décharger des assemblys chargés dynamiquement (par ex.plug-ins et compléments), vous devez décharger le contenant AppDomain.Pour plus d'informations, voir cet article sur MSDN sur le déchargement des domaines d'application.

Utiliser WCF

Il y a un question et réponse sur le débordement de pile qui décrivent comment utiliser Windows Communication Framework (WCF) pour créer une infrastructure de plug-in.

Frameworks de plug-ins existants

Je connais deux frameworks de plug-ins :

Certains parlent de Cadre d'extensibilité géré (MEF) en tant que framework de plug-in ou de complément, ce qui n'est pas le cas.Pour plus d'informations, voir cette question StackOverflow.com et cette question StackOverflow.com.

Une astuce consiste à charger tous les plugins et autres dans votre propre AppDomain, car le code en cours d'exécution peut être potentiellement malveillant.Un propre AppDomain peut également être utilisé pour « filtrer » les assemblys et les types que vous ne souhaitez pas charger.

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

Et pour charger un assembly dans le domaine d'application :

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

Pour décharger le domaine d'application :

AppDomain.Unload(domain);

Oui, ++ pour Matt et System.AddIn (un article du magazine MSDN en deux parties sur System.AddIn est disponible ici et ici).Une autre technologie que vous voudrez peut-être examiner pour avoir une idée de l'orientation future du .NET Framework est la Cadre d'extensibilité géré actuellement disponible sous forme CTP sur Codeplex.

Fondamentalement, vous pouvez le faire de deux manières.

La première consiste à importer kernel32.dll et à utiliser LoadLibrary et GetProcAddress comme vous l'avez utilisé auparavant :

[DllImport("kernel32.dll")]

internal static extern IntPtr LoadLibrary(String dllname);

[DllImport("kernel32.dll")]

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

La seconde consiste à le faire à la manière .NET :en utilisant la réflexion.Vérifiez l’espace de noms System.Reflection et les méthodes suivantes :

Vous chargez d’abord l’assembly par son chemin, puis en récupérez le type (classe) par son nom, puis récupérez à nouveau la méthode de la classe par son nom et enfin appelez la méthode avec les paramètres appropriés.

L'article est un peu plus ancien, mais toujours applicable pour créer une couche d'extensibilité au sein de votre application :

Permettez aux utilisateurs d'ajouter des fonctionnalités à vos applications .NET avec des macros et des plug-ins

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top