Développement - Delphi : Projet "TypeLibReader"

 "Delphi TypeLibReader" : un visualisateur de bibliothèque de type écrit avec Delphi.


Ce visualisateur de bibliothèque de type / Débugeur Automation est développé avec Delphi afin de mettre en oeuvre l'API de lecture des informations de type contenu dans le binaire d'une bibliothèque de type. Ce projet déjà ancien est un projet expérimental de mise en oeuvre des API dédiées à la lecture/écriture des informations de type dans une bibliothèque de type au format binaire. Ce projet est donné lieu à un article publié sur le site "Developpez.com" à l'adresse suivante : http://pchapuis.developpez.com/typelibreader.

Développement - Delphi : Projet "TLBDepends"

 "TLBDepends" un outils complet pour les TLB dans l'idée de "DLLDepends".


"DLLDepends" est un utilitaire orienté "DLL" (library ou bibliothèque) permettant de voir les entrées de la DLL sélectionnée ainsi que les dépendances nécessaires à cette DLL c'est à dire les bibliothèques mises en oeuvre par la DLL sélectionnée. Cet utilitaire est très complet et il permet de résoudre le fameux problème de "DLL Hell" lié aux bibliothèques. Son ergonomie associée à sa simplicité en font un outils indispensable pour résoudre les problèmes liés aux dépendances.

L'application "TLBDepends" est développée dans l'objectif de fournir un outils comme "DLLDepends" mais spécifiquement dédié aux bibliothèques de type (TLB). Cette extension au projet "TypeLibReader" a été réalisée spécifiquement pour gérer les dépendances de bibliothèque de type. L'idée de cet outils est née avec un environnement dans lequel de nombreuses TLB composent une application. Ces TLB généralement écrites avec Delphi (mais aussi avec C++ / ATL) doivent impérativement être appréhendées globalement ou "synoptiquement" par un développeur désirant maitriser l'architecture complète de l'application. Delphi affiche les dépendances d'une TLB ouverte avec cet EDI dans un onglet dédié aux bibliothèques de type "utilisées". Avec Delphi il est donc possible d'ouvrir une TLB utilisée par une autre TLB simplement avec un double-click sur la dépendance alors une fenêtre de visualisation de la TLB affiche les informations de celle-ci (et à son tour... ses dépendances).

Cependant le parcours automatique en profondeur des dépendances et la visualisation de l'ensemble de ces TLB avec Delphi n'est pas proposé; avec l'interface "MDI" (Multi Document Interface) chaque TLB est dans sa propre fenêtre ce qui peut rapidement devenir difficile à gérer avec une architecture composée de nombreuses TLB. La consultation des informations d'une TLB complexe (avec un arbre de dépendances "profond"), en particulier dans le cadre de la cohabitation avec un autre RAD Delphi (ouvert en mode "debug" ou simplement pour développer en mode "design-time") est "lourde" et pas très pratique (IMHO). Hors "exercise de style" avec l'écriture d'une application "Delphi (Win32)" mettant en oeuvre des composants Microsoft .NET, l'objectif principal de "TLBDepends" est de proposer un outils simple et léger permettant de visualiser, naviguer et rechercher dans une TLB et ses dépendances. Avec son code source disponible cet outils est extensible; les quelques fonctions actuellement non implémentées (ou partiellement) seront finalisées à terme (avec un peu de temps)... La structure même de l'application avec ses différents composants (implémentant un "bridge" entre les composants .NET et Win32) sera éventuellement modifiée dans l'objectif de supprimer et/ou simplifier ces dépendances .NET "custom" afin de standardiser au maximum la technique de couplage entre l'application Win32 et le composant .NET "TreeMapControl".

Pour rendre l'application plus ergonomique et conviviale, celle-ci implémente les fonction suivantes :
  • Sauvegarde de différents paramètres : MRU, Liste d'exclusion des TLB "systèmes", ...
  • Recherche "full-text" mono ou multi TLB...
  • Vue graphique : zoom, personnalisation diverses...
  • ...

 Fonctions principales de l'outils.


Le projet "TLBDepends" implémenté avec Delphi 7 (Win32) et Visual Studio 2005 ou 2012 (.NET 2.0) est essentiellement un exemple d'utilisation de .NET dans une application "Win32". Le projet dans sa version actuelle (Oct. 2014) implémente les fonctions suivantes :
  • Lecture des informations d'une TLB binaire et affichage avec la synthaxe Pascal ou IDL.
  • Lecture des informations des TLB "dépendances" (définissants des types dans la tlb selectionnée).
  • Affichage optionnellement récursif des informations de la TLB selectionnée, des TLB en dépendances.
  • Filtre d'exclusion optionnelle pour les TLB "systèmes" (masquage possible des éléments de la liste des TLB "systèmes").
  • Masquage possible des éléments du type "IDispatch".
  • Navigation de type "hyper-lien" entre :
    • une dépendance de TLB et la TLB dépendance.
    • une entitée (type, alias, ...) définie dans une TLB de dépendance.
    • historique de navigation : back, next.
  • Un onglet présente l'ensemble des dépendances avec le composant "TreeMapControl"
    • zoom possible du niveau de dépendance (TLB sélectionnée ou autre)
    • éléments graphiques personnalisables : légende, couleurs, ...
    • masquage optionnel des TLB systèmes (liste d'exclusion).
    • taille optionnellement proportionnelle à la taille de la TLB binaire.
    • source XML de la vue du graphique "TreeMap" (possibilité d'utiliser ce XML avec un autre composant TMC).
  • Un onglet affiche les résultats de la/des recherche(s) effectuée(s).
  • Les options de recherche suivantes sont proposées :
    • Recherche dans une TLB binaire via l'API de recherche intégrée à l'API dédiée aux TLB ou recherche full-text.
    • Idéalement (*) la fenêtre des options de recherche est identique à celle de Delphi et propose les mêmes options.
         (*) Certaines options comme la recherche via l'API TypeLib ne supportent pas les options disponibles dans la recherche Delphi.
    • Recherche mono ou multi TLB : dans la TLB courante ou dans l'ensemble des TLB dépendances.

NB : les fonctions suivantes sont partiellement ou non implémentées :
  • Miniatures ie. "thumbnails" des dépendances pour la publication (papier, web, ...) d'un synoptique.
  • Navigation HTML dans les dépendances exportées : browse XML mapping.
  • Générateur de classe PROXY (**) :
    • Génération automatique des classes "proxy" pour les interfaces sélectionnées dans une TLB.
    • Deux types de modèles de proxy : "Passthrough" ou "MOCK".
  • Utilitaires : recencement COM d'une TLB et de toutes ses dépendances.
(**) le générateur automatique de PROXY fait partie des recherches effectuées autour de COM et d'AOP : Aspect Oriented Programming. En effet suite à l'article passionnant de Bertrand Goetzmann "Framework Programmation Orientée Aspect sous Delphi" la réalisation d'un générateur de "proxy" m'a semblée viable et intéressante afin d'obtenir une solution équivalente à la solution de hooking COM générique proposée avec la technique de l'article de référence.

La présentation des projets en cours avec l'onglet "TLBDepends" présente plus en détails spécifiquement l'IHM de l'application avec les différentes fonctions disponibles.

 Synthèse de l'historique du développement de l'application "TLBDepends".


Initialement le projet "TLBDepends" était un simple test ou "POC" (Proof Of Concept) dans le but d'énumérer les différentes TLB utilisées par une TLB. Dans ce but l'unité "uTypeLibObj.pas" du projet "TypeLibReader" était modifiée de manière triviale (et absolument pas optimisée) afin de couvrir les exigences de cet objectif.

Après avoir techniquement validé la méthode reflective d'énumération des dépendances (avec les API dédiées au TLB), le problème de l'affichage de ces dépendances s'est présenté naturellement. Ce sujet étant directement issu d'un besoin de mise à jour de documentation absolète et/ou incomplète concernant l'architecture d'une application principalement composée de serveur COM, une représentation synthètique et optimum semblait nécessaire. Le type de graphisme "TreeMap" ou "squarified treemap" semblait le plus adapté en raison de sa nature permettant de représenter à la fois :
  • la hiérarchie : arborescence des dépendances de TLB
  • le poids : taille du binaire de chaque TLB ou nombre d'entités définies dans une TLB
  • le type : couleur en fonction du type système ou personnalisé de la TLB
pour chacune des TLB mises en oeuvre par la TLB sélectionnée ou par une dépendance de celle-ci.

Pour rendre l'objectif initial plus convivial en terme d'affichage synoptique, l'affichage des dépendances dans un graphisme de type "TreeMapControl" est donc implémenté dans "TLBDepends". Cependant avec ce choix le problème de l'intéropérabilité Win32 avec .NET se pose donc remettant en cause l'architecture "Win32" de l'application principale.

Malgré un chemin critique évidement plus court en optant pour une ré-écriture avec .NET et malgré le "gap" entre Delphi 7 et .NET 2.0 "l'exercice de style" avec l'intérop Win32/.NET m'a paru intéressant. Un import de l'assembly du composant "TreeMapControl" permet d'asservir rapidement ce composant .NET à l'application écrite en Delphi 7. Hélas la trivialité de cette étape laisse rapidement apparaître un problème dans la gestion de l'affichage du composant. L'application "TLBDepends" renseigne les différents données/attributs nécessaires à la description de l'arbre des dépendances et au paramètrage des attributs graphiques mais le "drawing" du composant .NET (en dépit de divers tests laborieux) s'avére difficile à déporter directement sur l'IHM de l'application Win32 réalisée avec Delphi. Ce problème d'affichage du composant "TreeMapControl" directement sur l'IHM Win32 a donc motivé la création de deux nouveaux composants .NET additionnels au projet : "TLBDependsHelper.exe" et "PictureDispToBitmapHelper.dll".

 Description des composants de l'application "TLBDepends".


Le tableau ci-dessous synthétise les différents composants nécessaires à l'application "TLBDepends" avec une brève description de chacun d'eux.

Nom Editeur Type / Description ...
TreemapControl.dll Microsoft Research Composant Microsoft .NET "TreeMapControl" Le Composant .NET "TMC" ou TreeMapControl implémente un algorithme de Treemapping et fournit un moteur de rendu graphique avec différentes options (coloration, légende, ...).

TreemapGenerator.dll Microsoft Research Composant Microsoft .NET associé au composant "TreeMapControl" Le composant .NET "TreemapGenerator.dll" est un "helper" associé au composant TreeMapControl. Son rôle de "helper" est par exemple de prendre en charge le document XML de description des données du TreeMap.

TLBDependsHelper.exe Custom Helper .NET (C#) container graphique de type "WinForm" du composant "TreeMapControl". Helper de type container "fenêtré" .NET dédié au composant TMC (utilisé par l'application Win32 via COM). Le rôle de ce composant est l'hébergement du composant TMC en offrant un container graphique respectant les exigences .NET (pour permettre au composant TMC de s'afficher correctement).

PictureDispToBitmapHelper.dll Custom Helper/Assembly bibliothèque. Simple bibliothèque de méthodes statiques proposant des fonctions utilitaires avec une interface entre les images .NET et les images COM (Win32)

TLBDepends.exe Custom Application principale de type "stand-alone" IHM de l'application (réalisée avec Delphi 7 et donc "Win32"). L'interface principale de l'application est un container Win32 interfacé avec les composants .NET 2.0 via COM (et interop). Un thread assure la création/mise à disposition de ces composants afin de résoudre les problèmes d'affichage du TMC dans un contexte COM et donc "Win32".

TLBDepends.exe.xml Custom Paramètres de l'application Fichier des paramètres de l'application (réalisée avec Delphi 7 et donc "Win32") sont stockés dans ce fichier au format XML. Les différentes catégories des paramètres ci-dessous aident à rendre l'application plus riche, ergonomique et conviviale :
  • <MainOptions> : paramètres principaux de l'application.
  • <TreeMapOption> : paramètres/options du graphisme TreeMap.
  • <Files> : répertoire courant et MRU (10 derniers fichiers ouverts).
  • <SystemTypeLib> : définition de la liste des TLB systèmes (exclues de l'introspection récurrente des TLB).
  • <SearchOption> : paramètres de recherche.

 Ultime fonction de "TLBDepends" : générateur de proxy.


La partie script présente dans l'application initiale "TypeLibReader" (avec un moteur de script intégré pour le debug) est totalement absente de "TLBDepends". En effet l'objectif initial de "TLBDepends" n'est pas orienté "runtime" mais "design-time" (avec la présentation des méta-données ou entités d'une TLB et de ses dépendances).

Cependant l'aspect "run-time" est abordé avec l'utilisation de la réflectivité fournit par l'outils pour automatiquement générer pour une interface ou pour l'ensemble d'une bibliothèque de type une ou plusieurs classes implémentant une "pattern proxy".

 Installation et éxécution de l'application "TLBDepends".


Les composants .NET associés à l'application (avec les helpers image .NET / image COM - Win32) doivent-être enregistrés/recencés via la commande .NET "REGASM" (REGister ASseMbly) pour pouvoir être rendu disponibles via interop dans l'application principale réalisée avec Delphi 7 (Win32).


Ci-dessus une copie d'écran de l'ensemble des fichiers pour que l'application fonctionne (avec .NET 2.0 et après "REGASM"). Ensuite à titre d'exemple un script BATCH permettant d'enregistrer tous les composants .NET (afin qu'ils puissent exposer leurs types via interop vers TLBDepends écrit, compilé et construit avec Delphi 7;). Ci-dessous une copie d'écran du résultat de l'exécution (avec succés cf. "Inscription des types réussie") du script de enregistrement/recencement des composants .NET.


 Fonctions actuellement non implémentées, bugs connus et extensions possibles


Le projet "TLBDepend" (essentiellement par manque de temps;) n'est pas maintenu "régulièrement"; quelques bugs, imperfections et fonctions non implémentées sont encore actuellement présents dans l'application...

Par exemple des bugs d'affichage dans le tableau des résultats de recherche (avec les éléments trouvés "collapsables"), l'implémentation partielle de la recherche (avec uniquement la recherche via l'API COM), quelques défauts lors de la navigation comme la perte de la sélection sur l'arbre des entités de la TLB qui rend inactif les boutons de navigation inactifs ainsi que différents autres problèmes et quelques fonctions non implémentées sont encore présents dans l'application...

L'application "TLBDepends" permet cependant de visualiser correctement les entités définies dans une TLB et récursivement les dépendances de cette TLB; la navigation bien qu'encore un peu "primitive" permet de "browser" simplement et intuitivement une ou plusieurs bibliothèques de type et la recherche permet de trouver une élément dans une ou plusieurs TLB...

 Téléchargement de "TLBDepends".


Ci-dessous les liens pour le téléchargement de la version d'Octobre 2014 associée à cet article :
  • TLBDepends 1_0_0_10.zip
    Application "TLBDepends" complète : le fichier ZIP embarque les trois fichiers nécessaires à l'application.

    Les composants Microsoft .NET ne sont pas packager dans ce ZIP mais sont disponibles avec le package Microsoft dédié. La page suivante traite les problèmes éventuels d'installation de ces composants .NET (runtime .NET / version de Windows nécessaire à ces composants) avec un lien permettant de télécharger ces composants Microsoft dans la version 1.4 (version "difficile" à trouver sur le site de Microsoft Research).

  • TLBDepends_Sources.zip
    Code source complet de l'application "TLBDepends".

    Ce fichier ZIP embarque tous les fichiers nécessaires pour reconstruire l'application (Delphi et .NET) avec tous les composants "custom" nécessaires.
Le projet "TLBDepends" et l'article associé sont encore "en cours de construction"...

"TLBDepends" (à suivre...) les points suivants seront détaillés dans la prochaine révision :
  • Fonctions actuellement non implémentées et extensions à réaliser ou simplement envisageables : planning / points pondérés et ordonnés de la fin des développements.
  • Utilisation des composants .NET Microsoft TreeMapControl/TreeMapGenerator.
  • Intéropérabilité entre Delphi (Win32) et .NET : solution actuelle de "drawing" (GUI = EXE .NET + dll/lib pour export bitmap de .NET vers COM).
  • Publication & export DHTML : XML + XSLT = HTML + composant .NET + JavaScript

© Pascal Chapuis - ChapsAndChips 2014