La gestion des packages et la compatibilité des composants avec Delphi 6Date de publication : 5/09/2001 , Date de mise a jour : 24/10/2004
Par
Olivier Dahan (Contributions)
I. Présentation II. Vous avez dit Package ? III. Pourquoi utiliser des Packages ? Réduire la taille du code Englober un ensemble de composants IV. Les différents types de Packages V. Les fichiers des Packages VI. Installation des packages dans l'IDE Les packages "Projet" et les packages "par défaut" VI. Créer vos propres packages L'éditeur de Package La section Contains (contient) La section Requires (nécessite) Un peu de stratégie VIII. La stratégie de conception des packages Les Packages de composants Design time et Runtime L'enregistrement des composants IX. Les directives de compilation spécifiques aux packages X. Convention de nommage XI. ...et encore ? I. Présentation
Nombreux sont les fils de discussion sur les forums à parler de problèmes de compatibilité des composants avec Delphi 6. On cherche partout sur les disques les DsgnIntf.dcu ou .pas et on ne les trouve pas ! Horreur, erreur de packaging, on crie, on vocifère ! ... Alors qu'il ne s'agit d'une méconnaissance de la stratégie de développement des composants conseillée depuis Delphi 5 (donc plus de deux ans - voir référence en fin d'article) et aujourd'hui, après cette longue phase de transition, imposée dans Delphi 6.
Tout cela repose sur la séparation propre et nette des éditeurs de propriété et autres éditeurs de composants d'avec le code runtime utile des composants. La mise en oeuvre passe par l'utilisation des packages qui sont les grands incompris de Delphi alors que, introduits dès Delphi 3, ils ont apporté une souplesse dans la gestion des palettes de composants qui faisait cruellement défaut à Delphi 1 et son alter ego 32 bit, Delphi 2.
Nous présenterons ici les packages et la stratégie de développement convenable pour ne pas avoir de problème de compatibilité avec Delphi 6.
Cet article s'inspire de plusieurs publications en langue anglaise sur le net, notamment un excellent article de Xavier Pacheco datant de 1999 (pour preuve que le sujet est loin d'être récent !).
II. Vous avez dit Package ?
Sous Delphi 1 et 2, la librairie de composants était une DLL qui contenait la totalité des composants installés dans l'IDE. L'idée était intéressante puisqu'elle permettait, grande nouveauté, de créer des composants avec le même outil de développement et de les intégrer dynamiquement à son espace de travail en une manipulation simple. Il faut rappeler que de nombreux outils de développement n'autorisaient pas, et n'autorisent toujours pas une telle souplesse et qu'il est fréquent qu'il faille utiliser un autre langage pour étendre leur IDE (lorsque cela est possible..).
Toutefois, cette stratégie qui fut valable à la sortie de Delphi où les composants n'étaient pas trop nombreux et où les machines sous Windows 16 bit ne pouvaient pas offrir beaucoup de place mémoire ne pouvait plus être maintenue longtemps : la "Lib" devenait énorme, il fallait la recompiler à chaque ajout ou suppression de composants, et surtout tous les composants étaient présents en même temps, ce qui n'incitait pas en créer de trop.
Avec Delphi 3 Borland a introduit la notion de Package pour offrir cette souplesse indispensable à l'explosion des composants. Les packages ne sont qu'une suite logique de la "Lib" de D1 et D2 puisque cela revient à avoir plusieurs "Lib" en même temps qu'on peut charger ou décharger à volonté.
Ainsi, les Packages sont des DLL répondant à un modèle particulier autorisant l'IDE de Delphi à reconnaître les composants ou experts qu'elle contient. Cette caractéristique leur permet d'être exploités de façon particulière : au lieu de laisser Delphi associer (via son linker) le code des composants dans votre EXE, vous pouvez choisir d'utiliser les packages au runtime en accompagnement de vos EXE qui deviennent alors bien plus petits.
Les packages différent des DLL standard en ce sens qu'ils répondent à une norme spécifique à Delphi. A la différence des DLL que vous pouvez créer par ailleurs avec Delphi, les Packages compilés ne sont exploitables que par des applications Delphi.
Il existe deux utilisations des packages : l'une en mode Runtime (à l'exécution) l'autre en mode Designtime (à la conception sous Delphi), plus un troisième mode mixant les deux premiers. Nous étudierons plus loin les principales différences où se cachent d'ailleurs la solution du problème de compatibilité avec Delphi 6.
III. Pourquoi utiliser des Packages ?Réduire la taille du code
Lorsqu'on utilise des packages "runtime", Delphi n'associe plus le code des composants à celui de votre EXE. Ce dernier devient donc beaucoup plus petit. Par contre vous devez fournir les packages compilés en accompagnement de votre logiciel. Comme le Linker de Delphi est intelligent (c'est un smart linker) il supprime le code non appelé, de fait, un EXE avec les packages de runtime semblera plus petit mais l'ensemble des fichiers à fournir sera bien plus gros que l'EXE original sans package runtime. Où se trouve la réduction de code alors ? ... Elle est toute relative et ne s'apprécie que si vous devez fournir de nombreux EXE sur un même site client. A partir d'un moment, plein de petits EXE partageant les mêmes packages finissent par être bien moins gros que plusieurs EXE intégrant à chaque fois tout le code nécessaire. A titre personnel l'auteur n'a jamais vu de situations réelles où cela soit un vrai avantage (les problèmes de stockage sur disque dur n'existent plus et la fourniture et le maintien d'un ensemble cohérent de packages possède un coût important à ne pas négliger). On peut toutefois voir un avantage dans la séparation du code en unités indépendantes (les packages) notamment pour la distribution d'applications via Internet. Dans ce cadre vous pouvez fournir une fois pour toute les packages de votre application et permettre une mise à jour plus rapide de votre EXE qui sera de taille plus réduite. La mise à jour d'un package, le cas échéant, sera elle aussi moins consommatrice de bande passante. Englober un ensemble de composants
Si vous désirez distribuer un ensemble de composants sans fournir le code source, la création d'un package est une excellente solution. D'ailleurs même si vous souhaitez distribuer le code source, la création de composants passe aujourd'hui par celle de packages ! Les composants autonomes "à la" Delphi 1 et 2 n'existent plus et leur installation dans Delphi 3, 4, 5 et 6 passe par leur intégration dans un Package "utilisateur", ce que propose l'expert dédié à cet effet dans l'IDE de Delphi. Si vous créez des composants, alors vous devez tout savoir des Packages ! IV. Les différents types de Packages
Il existe quatre types de Packages :
V. Les fichiers des Packages
La table ci-dessous liste l'ensemble des fichiers liés directement à la notion de Package :
VI. Installation des packages dans l'IDE
L'installation des packages dans l'IDE de Delphi est une chose simple et nécessaire si vous devez intégrer des composants tiers dans votre environnement. La première chose à faire consiste à placer les différents fichiers au bon endroit. La table suivante liste les emplacements typiques des fichiers principaux d'un package.
Pour l'installation proprement dite des packages compilés, Delphi rend les choses très simples puisqu'il suffit d'ouvrir le dialogue ad hoc depuis le menu principal "Composant | Installer des paquets"
![]()
En cliquant sur le bouton "Ajouter" vous pouvez choisir un fichier "bpl". Si le package contient des composants ils seront affichés dans la palette.
Les packages "Projet" et les packages "par défaut"
Voici une "ruse" très peu connue et donc peu utilisée qui, pourtant, est très pratique : la configuration variable des packages.
Il n'y a pas de menu ni d'option spéciale pour çà, tout dépend si un projet est chargé ou non dans l'IDE. De là provient certainement la méconnaissance de cette facette de l'installation des packages.
A quoi cela peut il servir ?
C'est fort simple : si vous avez beaucoup de packages installés, cela prend de la place en mémoire, dans la palette de l'IDE, etc. Pire, les projets créés référencent par défaut ces packages et si vous portez les sources ailleurs, les développeurs auront des erreurs indiquant que le package "truc" est manquant alors qu'il ne sert à rien dans votre projet.
L'idée consiste donc à n'activer par défaut dans l'IDE que les packages utiles à tous les projets. Ensuite, dans chaque projet, vous ajoutez (ou enlevez) les packages nécessaires (ou superflus).
Comment procéder ?
Pour créer un sélection "par défaut" il suffit de fermer tous les fichiers ouverts dans l'IDE (menu "Fichier | Tout Fermer"), ensuite vous appelez la fenêtre d'installation des packages (figure précédente) et vous désélectionnez (la case à cocher) les packages inutiles. Par exemple les serveurs OLE ou le Decision Cube ne sont pas indispensables à tous les projets en général. Vous refermez la fenêtre d'installation des packages et vous quittez Delphi (il semble que cela fonctionne sans refermer Delphi mais tout dépend de la version, alors pour plus de sûreté ..).
Ensuite, lorsque vous créez un nouveau projet, il suffit d'appeler les Options du projet et d'aller faire votre choix dans l'onglet "Paquets". Delphi stocke les packages exclus dans le fichier "<monprojet>.DOF" sous la section "[Excluded Packages]".
VI. Créer vos propres packages
Avant de créer vos propres packages vous devez prendre certaines décisions. La première consiste à décider du type du package : runtime, design, les deux, aucun. Le choix se fondera sur certains éléments que nous détaillerons plus bas. En second lieu vous devrez décider comment appeler votre package et où le placer. Enfin, vous devrez décider des unités qui seront intégrées au package ainsi que de l'inclusion d'éventuels autres packages.
L'éditeur de Package![]()
La majorité du temps vous créerez un nouveau package en invoquant le menu "Fichier | Nouveau" puis en sélectionnant "nouveau paquet". L'éditeur de paquet, ci-dessus, sera affiché, vide bien entendu (à l'exception du paquet VCL50 présent dans la rubriques Requires).
On remarque que l'éditeur contient deux noeuds principaux : Contains et Requires.
La section Contains (contient)
Vous spécifiez ici l'ensemble des unités de code qui doivent être intégrées dans le package. Un certain nombre de règles doivent être respectées :
La section Requires (nécessite)
Vous spécifiez ici tous les packages nécessaires au fonctionnement de votre package et qui n'apparaissent pas dans la clause "Contains". On peut voir cette section comme l'équivalent de la clause "Uses" dans une unité de code.
En général et au minimum, les packages que vous créerez intégreront librairie VCL50 (ou 60 pour Delphi 6) car c'est ce package qui contient la base de la VCL. D'ailleurs, comme nous le disions plus haut, Delphi ajoute automatiquement cette référence à la création d'un nouveau package. Vous pouvez bien entendu supprimer cette référence si votre package ne fait pas référence à la VCL, mais c'est une situation rarissime.
Un peu de stratégie
Le fameux monstre du loch ness pointe le bout de son museau par ici ! En effet, le problème de DsgnIntf manquant sous Delphi 6 commence dès la conception d'un package de composants. Notamment pour éviter les problèmes de mélange entre code runtime et code de design, il était fortement conseillé de séparer les deux catégories en créant deux packages différents. Sous Delphi 6 c'est une obligation.
L'arrangement le plus typique est de placer le code de vos composants dans un package runtime et de créer ensuite un package de design qui intègre le premier dans sa section "Requires". Un tel placement de package en "Requires" doit répondre à quelques règles :
VIII. La stratégie de conception des packages
Nous touchons ici à la cause, et à la solution, du problème de "DsgnIntf" manquant sous Delphi 5 ou Delphi 6. Mais ce qui pouvait se régler sous Delphi 5 par une copie du source de cette unité n'est plus possible sous Delphi 6 car l'unité n'est plus fournie du tout... D'où l'intérêt d'ouvrir grand vos yeux pour comprendre ce qui va suivre !
Comme indiqué plus haut dans cet article, la première chose à savoir quand on créé un package est le type de celui-ci. Nous allons ici voir comment choisir entre les types runtime, design time, etc.
Les Packages de composants Design time et Runtime
C'est le scénario classique pour celui qui conçoit des composants car :
Ici vous n'avez guère le choix de la structure à choisir.. Il vous faudra créer deux packages distincts, l'un pour le Design et l'autre pour le Runtime.
Le dessin suivant schématise le jeu d'inclusion entre les deux packages :
![]()
Ainsi que vous le voyez, le package de Design ("MonPackLib50.Dpk") intègre à la fois les fonctions de Design proprement dites (éditeurs divers) et l'enregistrement des composants (appel(s) à RegisterComponent dans l'unité "MonCompReg.Pas") ainsi qu'une référence au package Runtime ("MonPackStd50.Dpk"). Ce dernier contenant le code du (des) composant(s) eux-mêmes ("Compomain.pas", "Compo2main.Pas", "MesFnctions.Pas"). le package de Runtime est donc intégré dans le package de Design par une référence dans la section "Requires" de ce dernier.
Pour que ce montage fonctionne vous devez modifier correctement les options de chacun des deux packages. Pour ce faire, vous devez appeler le dialogue Options (accessible par le bouton "Options" en haut à droite de la fenêtre de l'éditeur de package). Dans cette fenêtre il faut sélectionner le bon type de package en cliquant sur l'un des bouton-radio du groupe "Options d'utilisation", comme le montre l'illustration suivante : ![]()
Comme vous le voyez ci-dessus, il s'agit du package de Design des composants Indy. Le titre du package est parlant puisqu'on lit "...Property and Component Editors" et que le type (options d'utilisation) est bien à "Seulement en conception" (donc Design time). Pour le package des composants eux-mêmes, l'option "Seulement en exécution" doit être cochée. L'enregistrement des composants
Lorsque vous créez un nouveau composant (et si vous passez par "nouveau | composant") Delphi ajoute automatiquement une fonction "Register()" qui fait un appel à "RegisterComponents()". C'est cette procédure qui permet à l'IDE de repérer un code à installer. Dans le montage qui vient d'être présenté cette stratégie ne s'applique plus. Il convient de déplacer le code de Register() dans une unité séparée qui recensera l'ensemble des composants s'il y en a plusieurs ainsi que l'enregistrement des éditeurs et experts éventuels. Cette unité, comme nous l'avons vu plus haut, appairait dans la section "Contains" du package de Design. En faisant de la sorte, le code d'enregistrement se trouve bien là où il doit être : dans le package de Design, il ne sera pas intégré dans les applications qui utilisent vos composants, et mieux encore, cela interdira d'installer vos composants dans Delphi à partir du "bpl" si celui-ci est distribué avec les applications (au lieu d'être lié à l'EXE), ce qui constitue une protection supplémentaire pour gérer vos licences.
(Certains malins pourraient penser qu'il suffit de récréer une unité d'enregistrement puis un package de Design intégrant votre "bpl" pour contourner la chose.. Certes.. En effet, avec une telle astuce il sera possible de monter les composants dans la palette de Delphi et même de jouer un peu avec, mais il sera impossible de compiler une application car il manquera les "dcu" ...)
IX. Les directives de compilation spécifiques aux packages
Certaines directives sont spécifiques aux packages, elles sont incluses soit dans le code même du package, soit dans les unités qui peuvent être utilisées par un package.
X. Convention de nommage
Les packages vont souvent par paire, ne serait-ce que pour les composants, comme nous l'avons vu plus haut. De plus, les packages sont dépendants de la version de Delphi, c'est à dire qu'un package compilé avec Delphi 5 ne fonctionnera qu'avec des applications compilées sous Delphi 5. Il est dès lors essentiel de pouvoir faire la différence entre les packages compilés pour des versions différentes de Delphi. Il n'y aucune règle fixe, mais il existe quelques conventions relativement bien suivies. La première consiste à placer la version de Delphi sur deux chiffres dans le nom des packages. Par exemple le noyau de la VCL est contenu dans VCL50.bpl pour Delphi 5 et VCL60 pour Delphi 6. La seconde convention consiste à bien identifier les packages Design time et Runtime. L'une des normes suivie est celle qui consiste à ajouter, avant le numéro de version de Delphi, un sigle de trois lettres: Lib pour les packages de Design et Std pour les packages Runtime. On trouve aussi une autre norme qui consiste à utiliser dcl pour les package de Design et soit rien (Indy par exemple) soit les lettres Ctl (comme dans la RxLib). Enfin, il est habituel de placer un préfixe de trois lettres indiquant le nom du créateur. Reste à ajouter au milieu de tout çà le nom du package lui-même.
De fait, les deux packages d'un produit fictif "TOTO" créé par le célèbre John Smith pour Delphi 5 s'appelleraient :
Dans Indy, les packages sont nommés :
Vous pouvez adopter d'autres conventions, tant qu'elles sont claires et permettent de bien gérer la version de Delphi et la finalité (Design ou Runtime).
XI. ...et encore ?
Il reste beaucoup encore à dire sur les packages ! C'est un sujet bien plus riche qu'on peut le penser de prime abord...
Par exemple, il est possible d'utiliser les packages pour créer un système de Plug'in pour une application. On peut aussi tout simplement se servir des packages pour séparer le code d'une grosse application et ainsi rendre les mises à jour moins grosses (pour un envoi sur le Net par exemple).
Il resterait aussi à parler du système de distribution et d'installation automatique des packages contenu dans Delphi via le Package Collection Editor qui permet de créer des fichiers compressés contenant tout le nécessaire pour l'installation d'un package sur Delphi.
Mais nous en sommes déjà arrivés à la 3ème page et, pour un petit topo sur les packages, vous avouerez que cela est bien suffisant ! :-)

|
Copyright © 2004 Olivier Dahan. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.