
L'une des innovations de Visual Studio 2012 s'est accompagnĂ©e de l'apparition d'un nouveau dĂ©bogueur personnalisĂ© appelĂ© Concord. Son systĂšme de composants permet aux plug-ins VSIX de personnaliser le comportement du dĂ©bogueur et d'Ă©crire de nouveaux outils contextuels qui peuvent utiliser le dĂ©bogueur pour leurs besoins. Son API fournit de nombreuses fonctionnalitĂ©s QOL, telles que le marshaling entre le code managĂ© / non managĂ©, l'intĂ©gration transparente avec un processus distant / dĂ©boguĂ© localement, et plus encore. En fait, presque tout ce qui peut ĂȘtre fait dans l'EDI peut ĂȘtre fait par programme en utilisant l'API Concord! Modifiez les valeurs de variables spĂ©cifiques Ă la volĂ©e, appelez des fonctions sur demande (ou faites spĂ©cifiquement le programme leur sauter des appels!), Les plugins peuvent rechercher par PDB (!), Bypass Ă©tape par Ă©tape et mĂȘme modification de code! Ouvrez le chat et vous dĂ©couvrirez ces innovations peu connues dans le domaine de la construction de vĂ©los.
Vous devriez probablement recommencer depuis le début. Le débogueur détecte les composants en lisant les informations du fichier
vsdconfig référencé par le manifeste du plugin VSIX. à son tour,
vsdconfig indique quelles interfaces sont implĂ©mentĂ©es par les composants du plugin et comment trouver ces composants (lien vers un fichier .dll, indiquant la classe ou, dans le cas de l'implĂ©mentation native, indiquant CLSID. Je donnerai des exemples en C #). De plus, un identifiant unique (GUID) pour chaque composant est indiquĂ©, ainsi que son "niveau". Un niveau est ce qui dĂ©termine dans quel ordre les plugins seront traitĂ©s, ainsi que dans le contexte de quel processus cette implĂ©mentation sera chargĂ©e - dans le processus IDE ou dans le processus de l'application dĂ©boguĂ©e. Cela est dĂ» au fait que certaines fonctionnalitĂ©s ne peut fonctionner que dans le cadre de l'IDE, et vice versa - que dans le contexte du processus en cours de dĂ©bogage. Certaines fonctions API fonctionnent de la mĂȘme maniĂšre ici et lĂ . En outre, un certain nombre de composants ont leurs propres rĂšgles de disposition, car ils peuvent dĂ©pendre des Ă©lĂ©ments de dĂ©bogueur existants situĂ©s Ă leurs niveaux fixes. Pour Ă©viter les incidents, je recommande RTFM (https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.debugger.componentinterfaces?view=visualstudiosdk-2017) et des expĂ©riences indĂ©pendantes dans un bac Ă sable sĂ©parĂ©, ce qui ne sera pas dommage. supprimer si quelque chose se produit (cela est connectĂ©, encore une fois, avec une telle nuance - dans certains cas, il n'est mĂȘme pas clair pourquoi l'assemblage ou le type ne se charge pas, car je ne pouvais toujours pas trouver oĂč les journaux apparaĂźtraient qui signaleraient le problĂšme de maniĂšre stable. Erreur, par exemple, en rĂ©fĂ©rence Ă une dĂ©pendance qui ne peut pas ĂȘtre chargĂ©e dans le processus cible, elle peut apparaĂźtre dans la sortie st di-, ou non. Soyez akuratno, prenez commits frĂ©quentes,
et ne restez pas assis derriÚre le volant ivre).La liste des niveaux est la suivante (je donnerai le texte en anglais pour que le lecteur n'ait pas d'incidents lors de la réalisation d'actes RFTM):
Niveaux des composants IDE (valeurs> 100 000):
Niveaux de composants du processus cible (valeurs <99,999):
Ensuite, dans l'ordre, le processus de création d'un projet. S'il n'y avait pas de nuances importantes, je pourrais décrire ce processus de maniÚre minimale ou l'ignorer du tout, mais les réalités sont complÚtement différentes - nous avons besoin d'un certain nombre de dépendances de bibliothÚque, ainsi que d'un outil pour créer des fichiers de configuration, qui pour une raison quelconque n'est pas distribué avec VisualStudio, mais est disponible uniquement avec pépite. En fait, nous devons maintenant passer à l'essentiel. Le processus de création et de configuration d'un projet est structuré comme suit:
- Ouvrez Visual Studio. Dans mon cas, 2017 Community Edition
- Projet VSIX ( Visual C # -> onglet Extensibilité , ou via la recherche). Appelons ça "HelloVSIX"
- Ajoutez un nouveau projet de bibliothÚque de classes dans la solution et appelez-le «DebuggeePlugin»
- Nous mettons la référence sur le projet "DebuggeePlugin" dans le projet "HelloVSIX"
- Nous mettons la référence à l'assembly "Microsoft.VisualStudio.Debugger.Engine" dans le projet DebuggeePlugin
- Ajouter au projet «DebuggeePlugin» une référence à l'ensemble NuGet Microsoft.VSSDK.Debugger.VSDConfigTool. Ceci est notre outil pour générer des configurations VSD.
Maintenant, nous sommes prĂȘts Ă faire de notre plugin quelque chose d'utile. Faisons la chose la plus simple que vous puissiez faire - laissez-le afficher un MessageBox qui dit "Bonjour VSIX" lorsque le processus cible rencontre un point d'entrĂ©e. Pour ce faire, nous devons crĂ©er une classe qui implĂ©mente l'interface
IDkmEntryPointNotification , ainsi que remplir plusieurs fichiers de configuration. Ajoutez une nouvelle classe publique appelée DkmEntryPointNotificationService et
héritez de l' interface
IDkmEntryPointNotification et laissez l'implémentation par défaut pour l'instant:
using Microsoft.VisualStudio.Debugger; using Microsoft.VisualStudio.Debugger.ComponentInterfaces; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DebuggeePlugin { class DkmEntryPointNotificationService : IDkmEntryPointNotification { public void OnEntryPoint(DkmProcess process, DkmThread thread, DkmEventDescriptor eventDescriptor) { throw new NotImplementedException(); } } }
Ajoutez le fichier «DkmEntryPointNotificationService.vsdconfigxml» au projet «DebuggeePlugin». Pour chaque classe dĂ©clarĂ©e qui doit recevoir des notifications via les implĂ©mentations des interfaces d'espace de noms Microsoft.VisualStudio.Debugger.ComponentInterfaces, vous devez disposer d'un tel fichier. Soit dit en passant, il est possible d'implĂ©menter plusieurs de ces interfaces Ă la fois dans une mĂȘme classe. Nous devons maintenant modifier l'action de gĂ©nĂ©ration de notre fichier ".vsdconfigxml". Pour ce faire, vous devez Ă©diter manuellement le fichier de projet (j'ai sĂ©rieusement). Nous dĂ©chargeons le projet DebuggeePlugin et l'ouvrons avec l'Ă©diteur de studio. Nous devons trouver la balise XLM suivante:
<None Include="DkmEntryPointNotificationService.vsdconfigxml" />
et déplacez cette balise vers votre propre ItemGroup, en changeant le type de None en VsdConfigXmlFiles:
<ItemGroup> <VsdConfigXmlFiles Include="DkmEntryPointNotificationService.vsdconfigxml" /> </ItemGroup>
Vous pouvez enregistrer et recharger le projet.
Maintenant, allez dans les configs. La premiĂšre chose Ă faire: si «DebuggeePlugin» a ajoutĂ© le fichier de projet vsdconfig.xsd, alors il doit ĂȘtre retirĂ©. Nous allons le remplacer maintenant, car il est plus facile de travailler avec du texte brut. Ouvrez DkmEntryPointNotificationService.vsdconfigxml et remplacez le texte par ce qui suit:
<?xml version="1.0" encoding="utf-8"?> <Configuration xmlns="http://schemas.microsoft.com/vstudio/vsdconfig/2008"> <ManagedComponent ComponentId="422413E1-450E-40A6-AE24-7E80A81CC668" ComponentLevel=^_^quotđźquot^_^ AssemblyName="DebuggeePlugin"> <Class Name="DebuggeePlugin.DkmEntryPointNotificationService"> <Implements> <InterfaceGroup> <NoFilter/> <Interface Name="IDkmEntryPointNotification"/> </InterfaceGroup> </Implements> </Class> </ManagedComponent> </Configuration>
Dans tout fichier de ce type, nous devrons indiquer les éléments suivants:
- ComponentId - cette valeur peut ĂȘtre gĂ©nĂ©rĂ©e Ă l'aide de l'outil de gĂ©nĂ©ration de GUID (Tools -> CreateGUID)
- ComponentLevel est le niveau de notre composant dans la hiérarchie. Consultez le tableau ci-dessus et les informations d'aide sur MSDN pour sélectionner la plage de valeurs souhaitée.
- Assemblyname est le nom de notre assemblage (pas une solution!). Dans ce cas, il y aura un DebuggeePlugin
- Nom de classe - doit ĂȘtre indiquĂ©, y compris l'espace de noms dans lequel se trouve la classe. Dans ce cas, DebuggeePlugin.DkmEntryPointNotificationService
- Tableau InterfaceGroup - chaque entrĂ©e qu'il contient indique une interface implĂ©mentĂ©e par ce composant. Ă l'intĂ©rieur de chaque nĆud InterfaceGroup, il devrait y avoir un sous-nĆud indiquant les interfaces communes Ă tous, dans ce groupe, filtre, mais sur les filtres plus tard. Nous avons maintenant un seul nĆud d'interface et porte le nom de l'interface IdkmEntryPointNotification. Si nous avions plusieurs interfaces, il y aurait plusieurs nĆuds d'interface.
Permettez-moi de vous rappeler que pour chaque classe qui devrait recevoir des notifications du dĂ©bogueur, il doit y avoir un tel fichier. Mais le plaisir ne s'arrĂȘte pas lĂ . Chacun de ces fichiers est ensuite collectĂ© dans un fichier .vsdconfig dans le rĂ©pertoire de sortie du projet. Et ils doivent ĂȘtre rĂ©fĂ©rencĂ©s dans le manifeste du plugin. Cela se fait comme suit:
- AprÚs avoir formé le fichier ".vsdconfigxml", nous devons ... collecter la solution une fois, sinon nous n'aurons aucun fichier .vsdconfig dans le répertoire de sortie du projet)
- AprÚs cela, ouvrez l'éditeur de texte pour le fichier source.extension.vsixmanifest et ajoutez le code suivant avant la balise PackageManifest de fermeture:
<Assets> <Asset Type="DebuggerEngineExtension" d:Source="File" Path="DebuggeePlugin.vsdconfig" /> </Assets>
Si, aprĂšs les actions terminĂ©es, le fichier «DebuggeePlugin.vsdconfig» apparaĂźt dans le projet HelloVSIX, il doit ĂȘtre
SUPPRIMĂ DU PROJET et la solution doit ĂȘtre collectĂ©e Ă nouveau, sinon elle ne sera pas mise Ă jour.
Les travaux prĂ©paratoires sont terminĂ©s! Vous pouvez commencer Ă dĂ©boguer notre plugin. Cela se fait en dĂ©marrant une instance expĂ©rimentale de VisualStudio (pour les projets VSIX, il s'agit de la cible de dĂ©bogage par dĂ©faut, donc aucune Ă©tape supplĂ©mentaire n'est nĂ©cessaire). En fait, nous cliquons sur Debug-> StartDebugging et nous voyons une instance expĂ©rimentale de VisualStudio. Dans celui-ci, par dĂ©faut, notre plugin devrait dĂ©jĂ ĂȘtre installĂ©. Vous pouvez le vĂ©rifier via le menu Outils-> Extensions et mises Ă jour.
Du fait que nous avons implémenté l'interface IDkmEntryPointNotification, nous devrons créer un projet de test dans une instance expérimentale de VisualStudio. En fait, nous créons un nouveau projet, sélectionnez
C ++ -> Application console (choisissez C ++, car les exemples suivants contiendront des spécificités C ++), appelez-le
VSIXTestApp , exécutez sans aucune modification, collectez et voyez que notre instance expérimentale a cessé de lever une exception à l'intérieur de la méthode DebuggeePlugin. DkmEntryPointNotificationService.OnEntryPoint. Super! Vous devez maintenant afficher la MessageBox. Pour ce faire, il est nécessaire d'ajouter les références suivantes au projet DebuggeePlugin:
- Microsoft.VisualStudio.Shell.15.0
- Microsoft.VisualStudio.Shell.Interop
- Microsoft.VisualStudio.Shell.Interop.8.0
- Microsoft.VisualStudio.OLE.Interop
Ajoutez deux utilisations au début du fichier DkmEntryPointNotificationService.cs:
using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop;
Et ajoutez un appel à la méthode
VsShellUtilities.ShowMessageBox dans la méthode DkmEntryPointNotificationService.OnEntryPoint:
using Microsoft.VisualStudio.Debugger; using Microsoft.VisualStudio.Debugger.ComponentInterfaces; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DebuggeePlugin { class DkmEntryPointNotificationService : IDkmEntryPointNotification { public void OnEntryPoint(DkmProcess process, DkmThread thread, DkmEventDescriptor eventDescriptor) { VsShellUtilities.ShowMessageBox(Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider, "Hello VSIX", "Hello VSIX", OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }
l' using Microsoft.VisualStudio.Debugger; using Microsoft.VisualStudio.Debugger.ComponentInterfaces; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DebuggeePlugin { class DkmEntryPointNotificationService : IDkmEntryPointNotification { public void OnEntryPoint(DkmProcess process, DkmThread thread, DkmEventDescriptor eventDescriptor) { VsShellUtilities.ShowMessageBox(Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider, "Hello VSIX", "Hello VSIX", OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }
du using Microsoft.VisualStudio.Debugger; using Microsoft.VisualStudio.Debugger.ComponentInterfaces; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DebuggeePlugin { class DkmEntryPointNotificationService : IDkmEntryPointNotification { public void OnEntryPoint(DkmProcess process, DkmThread thread, DkmEventDescriptor eventDescriptor) { VsShellUtilities.ShowMessageBox(Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider, "Hello VSIX", "Hello VSIX", OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } }
Nous reconstruisons, lançons une instance expérimentale du studio, lançons un projet de test et le tour est joué!
Nous voyons que l'instance de test du studio a créé MessageBox!

Et qu'en est-il en fait?
Ici, nous avons appris à configurer un projet VSIX contenant un plug-in pour le débogueur Visual Studio, en tenant compte de la plupart des nuances qui entravent le résultat. C'est le point de départ d'un travail plus détaillé. Dans le prochain article, je vais vous montrer un autre point important: comment la communication a lieu entre l'IDE et les composants cibles de débogage.
Pour obtenir de l'aide sur l'utilisation de l'API Concord, vous pouvez vous référer non seulement à MSDN, mais également aux référentiels Microsoft suivants sur le github:
github.com/microsoft/PTVSgithub.com/Microsoft/ConcordExtensibilitySamples