30 décembre 2008

Charger une dll dynamiquement

Grâce à la réflexion, il est tout à fait possible de charger une dll dynamiquement. La classe System.Reflection.Assembly contient une méthode statique LoadFrom prenant comme argument dans une méthode surchargée, une chaine de caractère. En passant à la fonction le nom de la dll, on récupère une référence de l'assembly contenu dans la dll.

string dllName = ConfigurationSettings.AppSettings["dll"];
Assembly assembly = Assembly.LoadFrom(dllName);

A partir de cette référence, il est possible d'instancier un type contenu dans l'assembly. Seulement pour manipuler facilement ce type (sans réflexion), il faut connaitre sa classe, ou du moins une interface ou une classe abstraite dont il hérite. Imaginons que ce type hérite d'une interface appelée IInterface contenant une méthode executer() qu'il implémente, voici un bout de code permettant d'invoquer cette fonction :

string typeName = ConfigurationSettings.AppSettings["type"];
Type dllType = assembly.GetType(typeName);
IInterface obj = Activator.CreateInstance(dllType) as IInterface;
obj.executer();

Dans les 2 exemples ci-dessus, je récupère le nom de la dll et du type dans le fichier de configuration de l'application (de type Console pour l'exemple). Ceci est une bonne façon de faire, si vous souhaitez spécifier une autre dll et un autre type sans recompilation. Voici le fichier de configuration de l'exemple :

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="dll" value="library.dll"/>
<add key="type" value="library.Class1"/>
</appSettings>
</configuration>

Pour plus d'infos, veuillez vous référer à l'archive ci-présente :

4 commentaires:

Unknown a dit…

Bonjour,

Votre exemple m'a beaucoup aidé pour comprendre comment charger des dlls dynamiquement et je vous en remercie. Je suis en stage et je dois créer un service Windows qui charge dynamiquement plusieurs dlls avec ayant pour chacune un thread. Or je ne vois pas comment implémenter cette situation. Je partais sur l'idée du "for each(..." et crée une liste de thread, mais je n'arrive pas à avancer.

Merci de votre réponse.
Cordialement,
Bluteau Simon

Popul a dit…

Bonjour,

Une dll se charge dans un domaine d'application. Si cela ne vous gène pas, vous pouvez tout à fait charger toutes vos dlls dans un seul domaine d'application, celui de votre service windows.

Et ensuite il suffit d'instancier autant de threads que de dlls chargées et y envoquer les méthodes souhaitées pour chacun d'eux.

Vous pouvez par exemple stocker et utiliser une ou plusieurs listes de string représentant les dlls à charger et les méthodes appeler dans un fichier "settings" ou sérialiser/désérialiser une liste d'objets représentant vos dlls et méthodes à appeler.
Il vous suffit ensuite d'itérer une 1ere fois pour charger toutes vos dlls et une deuxieme fois pour lancer les threads.

Anonyme a dit…

Bonjour,

je connais déjà la façon de charger une dll dynamiquement. Je suis déjà allé un peu plus loin que ça qui m'a amené à une question particulière:
Est-il possible de spécifier à l'application en cours d'exécution un chemin d'accès à un dossier conenant des dll qu'elle pourrais (éventuellement) charger automatiquement?
Pour illustrer, voici un problème que j'ai eu:
Une application qui va charger une dll dynamiquement, par exemple "DllBase.dll".
Au cours de l'exécution d'une méthode d'un classe chargée de "DllBase.dll", il s'est avéré que ça utilise une autre dll "DllRef.dll" qui se trouve dans le même dossier que la dll chargée.
Bien sûr ça a levé une erreur, mais il a suffit de changer le code en gérant l'évènement
"AppDomain.CurrentDomain.AssemblyResolve" qui permet de détecter une référence demandée afin de la charger à son tour.

Ma question est: est-il possible de faire autrement pour définir le dossier de la dll comme étant faisant partie du domaine de l'application? c'est à dire de faire en sorte que c'est comme si tout était dans le même dossier que l'application de base?

Merci d'avance.
Ahmed

Paul Musso a dit…

Bonjour Ahmed,

Si votre assembly est faiblement nommée, la CLR fait 2 choses :
1- Elle cherche un élément XML codebase le fichier de configuration de votre application
2 - Elle va faire du probing (elle cherche dans le dossier et ses sous dossiers) dans le dossier ApplicationBase du domaine d'application.

Peut-être que vous pouvez créer un nouveau domaine d'application pour charger votre DLL en définissant comme il se doit l'applicationBase du domaine (bon après faut tout marshaller, c'est ptet un peu chiant).

Autrement, si vous souhaitez vraiment modifier le comportement de la CLR pour le chargement des dll, je vous invite à regarder du côté de l'interface IHostAssemblyManager (gaffe c'est du c++) pour créer un gestionnaire de chargement d'assembly (assembly Loading Manager), comme on peut trouver dans SQL Serveur qui host une CLR pouvant charger des dll en base. Cependant ca risque d'être un peu compliqué il me semble :)