Avez-vous déjà utilisé Adobe Photoshop? Pour les laïcs, les plugins ne sont que des blocs de code fournis à l'application de l'extérieur (par exemple, dans une DLL). La différence entre un plugin et une DLL normale est que le plugin a la capacité d'étendre la fonctionnalité de l'application parent. Par exemple, Photoshop lui-même n'a pas une grande quantité de fonctions de traitement d'image. L'ajout de plug-ins lui donne un effet génial tel que le flou, le spot et tous les autres styles, et aucun d'entre eux n'a l'application parent elle-même.
C'est très bon pour les programmes de traitement d'image, mais pourquoi avez-vous besoin de dépenser beaucoup d'efforts pour compléter les applications commerciales qui prennent en charge les plugins? Supposons, donnons un exemple, votre application générera des rapports. Vos clients continueront certainement de demander des mises à jour ou d'ajouter de nouveaux rapports. Vous pouvez utiliser un générateur de rapports externe tel que Report Smith, qui est une solution pas si très semblable, nécessite de publier des fichiers supplémentaires, une formation supplémentaire pour les utilisateurs, etc. Vous pouvez également utiliser QuickReport, mais cela vous mettra dans un cauchemar de contrôle de version - si vous souhaitez reconstruire votre application à chaque fois que vous modifiez la police.
Cependant, tant que vous faites le rapport dans le plugin, vous pouvez l'utiliser. Besoin d'un nouveau rapport? Pas de problème, installez simplement une DLL et vous le verrez la prochaine fois que l'application démarre. Un autre exemple est une application qui traite les données des appareils externes (tels que les scanners de code-barres). En écrivant chaque routine de traitement d'interface de périphérique en tant que plug-in, vous pouvez obtenir une évolutivité maximale sans apporter de modifications à l'application parent.
commencer
La chose la plus importante avant de commencer à écrire du code est de déterminer les fonctionnalités de votre application pour étendre. En effet, le plugin interagit avec l'application parent via une interface spécifique, qui sera définie en fonction de vos besoins. Dans cet article, nous créerons 3 plugins pour présenter plusieurs façons dont le plugin interagit avec l'application parent.
Nous transformerons le plugin en DLL. Avant de le faire, cependant, nous devons faire un shell pour les charger et les tester. La figure 1 montre le programme de test après le chargement du premier plug-in. Le premier plugin n'accomplit rien de grand, et en fait, tout ce qu'il fait est de renvoyer une chaîne qui se décrit. Cependant, il confirme un point important - il fonctionnera correctement avec ou sans applications de plug-in. S'il n'y a pas de plug-in, il n'apparaîtra pas dans la liste des plug-ins installés, mais l'application peut toujours effectuer des fonctions normalement.
La seule différence entre notre shell de plug-in et les applications normales est l'unité ShareMem dans le fichier source du projet qui apparaît dans la clause Utilisation et le code qui charge le fichier plug-in. Toute application qui transmet des paramètres de chaîne entre lui-même et l'unité Child DLL? Pour tester ce shell, vous devez copier le fichier delphimm.dll à partir du répertoire Delphi / bin sur le chemin contenu dans la variable d'environnement de chemin ou le répertoire où se trouve l'application. Le fichier doit également être distribué en même temps lorsque la version finale est publiée.
Le plug-in est chargé dans ce shell de test via le processus LoadPlugins, qui est appelé dans l'événement FormCreate dans la fenêtre principale, voir la figure 2. Ce processus utilise des fonctions FindFirst et FindNext pour trouver des fichiers de plugin dans le répertoire où se trouve l'application. Après avoir trouvé un fichier, utilisez le processus LoadPlugins illustré à la figure 3 pour le charger.
{Trouver des fichiers de plugin dans le répertoire des applications}
Procédure tfrmmain.loadPlugins;
var
SR: TSearchrec;
Chemin: String;
Trouvé: entier;
Commencer
Chemin: = ExtractFilePath (application.exename);
essayer
Trouvé: = findFirst (path + cplugin_mask, 0, sr);
tandis que trouvé = 0 commence
LoadPlugin (SR);
Trouvé: = findNext (sr);
fin;
Enfin
FindClose (sr);
fin;
fin;
{Chargez la DLL du plugin spécifié.
Procédure tfrmmain.loadPlugin (SR: TSearchRec);
var
Description: String;
Libhandle: entier;
DRÉCRIPÉE: TPLUGINDESCRIME;
Commencer
LibHandle: = loadLibrary (pChar (sr.name));
Si libhandle $ # @ 60; $ # @ 62;
Commencer
DécritProc: = getProcAddress (libhandle, cplugin_describe);
Si elle est affectée (décréproc) alors
DescriptionProc (description);
mecplugins.lines.add (description);
fin
autre
Commencer
Messagedlg ('Fichier "' + sr.name + '" n'est pas un plug-in valide.',
mTinformation, [mbok], 0);
fin;
fin
autre
Messagedlg ('Une erreur s'est produite en chargeant le plug-in "' +
sr.name + '".', mterror, [mbok], 0);
fin;
La méthode LoadPlugin montre le noyau du mécanisme de plug-in. Tout d'abord, le plugin est écrit en DLL. Deuxièmement, il est chargé dynamiquement via l'API LoadLibrary. Une fois la DLL chargée, nous avons besoin d'un moyen d'accéder aux procédures et fonctions qu'il contient. Les appels API GetProcaddress fournissent ce mécanisme, qui renvoie un pointeur vers la routine requise. Dans notre démonstration simple, le plugin ne contient qu'une procédure appelée DescReplugin, spécifiée par le CPLUGIN_DESCribe constant (le cas du nom de la procédure est très important, et le nom passé à GetProcaddress doit être exactement le même que le nom de routine inclus dans la DLL) . Si aucune routine demandée n'est trouvée dans la DLL, GetProcadDree renvoie NIL, vous allez donc accepter d'utiliser la fonction attribuée pour déterminer la valeur de retour.
Afin de stocker des pointeurs vers une fonction de manière facile à utiliser, il est nécessaire de créer un type spécifique pour les variables utilisées. Notez que la valeur de retour de GetProcAddress est stockée dans une variable, décriteproc, appartient au type tpluginDescribe. Voici sa déclaration:
taper
TpluginDescribe = procédure (var desc: string);
Étant donné que la procédure existe à l'intérieur de la DLL, elle compile toutes les routines d'exportation via des conversions d'appels standard, donc l'indicateur STDCALL est requis. Ce processus utilise un paramètre VAR, qui contient la description du plugin lorsque le processus revient.
Pour appeler le processus que vous venez d'obtenir, utilisez simplement la variable qui enregistre l'adresse comme nom de processus, suivie de tous les paramètres. Dans notre cas, la déclaration:
DescriptionProc (Description)
Le processus de description obtenu dans le plug-in sera appelé et la variable description est remplie d'une chaîne décrivant la fonctionnalité du plug-in.
Plug-in de construction
Nous avons créé l'application parent et il est temps de créer le plugin que nous voulons charger. Le fichier de plugin est une DLL Delphi standard, nous créons donc un nouveau projet DLL à partir de Delphi IDE et l'enregistrons. Étant donné que la fonction de plug-in exportée utilisera les paramètres de chaîne, l'unité Sharemen doit être placée en premier dans la clause d'utilisation du projet. La figure 4 répertorie le fichier source du projet de notre plug-in simple.
usages
Partagem, sysutils, classes,
Main dans «main.pas»;
{$ E plg.}
exportations
DécritPlugin;
Commencer
fin.
Bien que le plugin soit un fichier DLL, il n'est pas nécessaire de lui donner une extension .dll. En fait, une raison est suffisante pour nous donner une raison de modifier l'extension: lorsque l'application parent recherche le fichier à charger, la nouvelle extension peut servir de masque de fichier spécifique. En utilisant une autre extension (notre exemple utilise * .plg), vous pouvez être quelque peu confiant que l'application ne chargera que les fichiers correspondants. Compiler l'indicateur $ x peut réaliser cette modification, ou vous pouvez définir l'extension via la page d'application de la boîte de dialogue Options du projet.
Le code du premier exemple de plugin est très simple. La figure 5 montre le code contenu dans une nouvelle unité. Notez que le prototype de descriptionPlugin est cohérent avec le type TPLUGINDESCribe dans l'application Shell et utilise le mot réservé à l'exportation supplémentaire pour spécifier que le processus sera exporté. Le nom du processus exporté apparaîtra également dans la section des exportations du code source principal du projet (répertorié dans la figure 4).
unité principale;
interface
procédure décritsplugin (var desc: string);
Exportation; STDCALL;
Mise en œuvre
procédure décritsplugin (var desc: string);
Commencer
Desc: = 'Test Plugin v1.00';
fin;
fin.
Avant de tester ce plugin, copiez-le sur le chemin de l'application principale. Le moyen le plus simple consiste à créer un plug-in dans le sous-répertoire du répertoire domestique, puis à définir le chemin de sortie vers le chemin principal (les répertoires / conditionnels de la boîte de dialogue Options du projet peuvent également être utilisés pour ce paramètre).
déboguer
Permettez-moi maintenant d'introduire une meilleure fonctionnalité dans Delphi 3: la possibilité de déboguer les DLL de l'IDE. Dans un projet DLL, vous pouvez spécifier un programme en tant qu'application hôte via la boîte de dialogue Exécuter Paramats. Ensuite, vous pouvez définir des points d'arrêt dans votre code DLL et appuyez sur F9 pour l'exécuter - tout comme vous le feriez dans une application normale. Delphi exécutera le programme hôte spécifié et, en compilant la DLL avec des informations de débogage, vous dirigez vers le point d'arrêt du code DLL.