Pour afficher l’article en anglais, activez la case d’option Anglais. Vous pouvez aussi afficher la version anglaise dans une fenêtre contextuelle en faisant glisser le pointeur de la souris sur le texte.
Traduction
Anglais
Nous recommandons d’utiliser Visual Studio 2017

Découverte de code à l'aide du modèle de code (Visual Basic)

Les macros complémentaires Visual Studio sont déconseillées dans Visual Studio 2013. Vous devriez mettre vos macros complémentaires à niveau vers des extensions VSPackage. Pour plus d'informations sur les mises à jour, consultez FAQ : conversion de compléments en extensions VSPackage.

Le modèle de code de Visual Studio donne aux clients Automation la possibilité de découvrir des définitions de code dans un projet et de modifier ces éléments de code. Le modèle de code met automatiquement à jour tous les objets référencés lorsque des modifications sont apportées dans l'éditeur de code. Par exemple, si vous faites référence à un objet de classe et qu'un utilisateur ajoute par la suite une nouvelle fonction, celle-ci est répertoriée au sein des membres. Grâce au modèle de code, les clients Automation n'ont pas à implémenter d'analyseur pour les langages Visual Studio afin de découvrir les définitions de niveau supérieur d'un projet, telles que les classes, les interfaces, les structures, les méthodes, les propriétés, etc.

Le modèle de code principal de Visual Studio évite les zones de code propres au langage. Il ne fournit donc pas, par exemple, de modèle objet pour les instructions des fonctions ou de détails complets sur les paramètres. Pour les paramètres, le modèle de code expose uniquement le type et le nom du paramètre, et aucune information n'est fournie pour indiquer si le paramètre est d'entrée, de sortie, facultatif, etc. Visual C++ offre une version étendue du modèle de code principal ciblé vers des projets Visual C++. Pour plus d'informations à ce sujet, consultez Modèle de code Visual C++.

Le modèle de code est principalement basé sur le texte dans la mesure où le programme ou le code du projet est stocké dans des fichiers texte. Vous pouvez localiser le code d'un projet en utilisant le modèle de projet pour visiter chaque élément de projet, puis vérifier si l'élément de projet contient un code à l'aide de FileCodeModel. Si un élément de projet contient des éléments de code, ces éléments peuvent retourner des objets depuis l'éditeur, et le modèle de code peut utiliser le modèle Automation de l'éditeur de texte pour modifier le code ou effectuer une analyse localisée. À l'aide du modèle objet de l'éditeur, vous pouvez interroger l'élément de code contenant le point d'insertion de l'éditeur ou un objet TextPoint présent au niveau de la fonction ou de la classe.

Le point d'entrée principal du modèle de code de Visual Studio est l'objet CodeModel. Une collection CodeElements générale est utilisée à plusieurs endroits dans le modèle de code. Il y en a une au niveau de CodeElementset au niveau de la classe ou de l'interface retournant les membres de ces objets. Chaque élément d'une collection CodeElements est un objet CodeElement2, et chaque objet CodeElement2 dispose d'une propriété Kind qui identifie son type, à savoir s'il s'agit d'une classe, d'une interface, d'une structure, d'une fonction, d'une propriété, d'une variable, etc.

Visual C++ fournit une extension au modèle de code principal pour cibler le code spécifique à Visual C++. Par exemple, si Language  indique qu'un élément de code particulier est un objet du modèle de code Visual C++ et Kind = vsCMElementClass, vous pouvez choisir d'appeler QueryInterface (QI) pour CodeClass à partir du modèle de code Visual Studio ou QI pour VCCodeClass à partir du modèle de code spécifique au langage Visual C++. Pour plus d'informations sur le modèle de code spécifique à Visual C++, consultez Comment : manipuler le code à l'aide du modèle de code Visual C++ (Visual Basic) et Modèle de code Visual C++.

  • Seule l'implémentation du modèle de code de Visual C++ effectue une modélisation propre au langage des implémentations de langage Microsoft.

  • La mise en œuvre de certains langages n'implémente pas l'intégralité du modèle de code de Visual Studio. Des rubriques d'aide signalent les éventuelles exceptions. La plupart des différences entre les diverses implémentations du modèle de code sont dues à des différences fonctionnelles entre les langages. Par exemple, vous ne pouvez pas ajouter de fonctions aux objets CodeNamespace de Visual Basic ou Visual C# car seul Visual C++ dispose de définitions de fonctions de niveau supérieur.

Ce complément traverse les différents éléments de code d'un fichier Visual Studio. Pour exécuter l'exemple, vous devez disposer d'un fichier de code source ouvert dans l'éditeur de code de Visual Studio. Pour plus d'informations sur l'exécution des exemples, consultez Comment : compiler et exécuter les exemples de code du modèle objet Automation.

' Add-in code.
Public Sub OnConnection(ByVal application As Object, ByVal _
 connectMode As ext_ConnectMode, ByVal addInInst As Object,  _
 ByRef custom As Array) Implements IDTExtensibility2.OnConnection
    _applicationObject = CType(application, DTE2)
    _addInInstance = CType(addInInst, AddIn)
    ' Pass the applicationObject member variable to the code example.
    OutlineCode(_applicationObject)
End Sub

Sub OutlineCode(ByVal dte As DTE2)
    Dim fileCM As FileCodeModel2 _
      = CType(dte.ActiveDocument.ProjectItem.FileCodeModel, _
      FileCodeModel2)
    Dim elts As CodeElements
    elts = fileCM.CodeElements
    Dim elt As CodeElement2
    Dim i As Integer
    MsgBox("About to walk top-level elements ...")
    For i = 1 To fileCM.CodeElements.Count
        elt = CType(elts.Item(i), CodeElement2)
        CollapseElt(elt, elts, i)
    Next
End Sub

Sub CollapseElt(ByVal elt As CodeElement2, ByVal elts As _
    CodeElements, ByVal loc As Long)
    Dim epStart As EditPoint2
    Dim epEnd As EditPoint2
    epStart = CType(elt.StartPoint.CreateEditPoint, EditPoint2)
    ' Do this since we move it later.
    epEnd = CType(elt.EndPoint.CreateEditPoint, EditPoint2)
    epStart.EndOfLine()
    If ((elt.IsCodeType) And (elt.Kind <> _
      vsCMElement.vsCMElementDelegate)) Then
        MsgBox("Got type but not a delegate, named : " & elt.Name)
        Dim ct As CodeType
        ct = CType(elt, CodeType)
        Dim mems As CodeElements
        mems = ct.Members
        MsgBox("Set mems = ct.members")
        Dim i As Integer
        For i = 1 To ct.Members.Count
            CollapseElt(CType(mems.Item(i), CodeElement2), mems, i)
        Next
    ElseIf (elt.Kind = vsCMElement.vsCMElementNamespace) Then
        MsgBox("Got a namespace, named: " & elt.Name)
        Dim cns As CodeNamespace
        cns = CType(elt, CodeNamespace)
        MsgBox("set cns = elt, named: " & cns.Name)

        Dim mems_vb As CodeElements
        mems_vb = cns.Members
        MsgBox("Got cns.members")
        Dim i As Integer

        For i = 1 To cns.Members.Count
            CollapseElt(CType(mems_vb.Item(i), CodeElement2),  _
              mems_vb, i)
        Next
    End If
End Sub

Les valeurs assignées d'éléments de modèle de code, tels que des classes, des structures, des fonctions, des attributs, des délégués, etc., peuvent changer après certains types de modifications. Par conséquent, vous ne pouvez pas supposer que ces valeurs resteront statiques.

Si vous assignez un élément de modèle de code à une variable locale, par exemple, et que vous définissez ensuite une valeur de propriété pour cette variable locale, la variable locale peut ne pas contenir un élément de modèle de code valide lorsque vous la référencez ultérieurement. En fait, elle peut même contenir un élément de modèle de code différent.

Prenons l'exemple d'une classe contenant une fonction appelée "MyFunction", qui est assignée à une variable CodeFunction. La valeur "YourFunction" est ensuite affectée à la propriété Name de CodeFunction. Après l'assignation de cette variable, vous n'avez plus la garantie que votre variable locale représente le même CodeFunction. Par la suite, l'accès à la propriété peut, en conséquence, retourner E_FAIL.

Pour gérer cette situation, il est recommandé de réassigner explicitement votre variable locale afin de corriger l'élément de modèle de code avant d'accéder à ses valeurs de propriété. Le code ci-après indique comment effectuer cette opération. (Il se présente sous la forme d'un complément.)

Ce complément illustre la façon correcte d'accéder aux valeurs de CodeElements afin que la valeur appropriée soit récupérée. Pour plus d'informations sur l'exécution des exemples, consultez Comment : compiler et exécuter les exemples de code du modèle objet Automation.

[Visual Basic]

Public Sub OnConnection(ByVal application As Object, ByVal _
  connectMode As ext_ConnectMode, ByVal addInInst As Object, _
  ByRef custom As Array) Implements IDTExtensibility2.OnConnection
    _applicationObject = CType(application, DTE2)
    _addInInstance = CType(addInInst, AddIn)
    ReassignValue(_applicationObject)
End Sub

Sub ReassignValue(ByVal dte As DTE2)
    ' Before running, create a new Windows application project,
    ' and then add a function to it named MyFunction.
    Try
        Dim myFCM As FileCodeModel = _
          dte.ActiveDocument.ProjectItem.FileCodeModel
        ' Change the MyFunction name in Form1 class to
        ' the name, OtherFunction.
        Dim myClass1 As CodeClass = _
          CType(myFCM.CodeElements.Item("Form1"), CodeClass2)
        Dim myFunction As CodeFunction = _
          CType(myClass1.Members.Item("MyFunction"), CodeFunction2)
        myFunction.Name = "OtherFunction"
        myFunction = CType(myClass1.Members.Item("OtherFunction"), _
          CodeFunction2)
    Catch ex As Exception
        MsgBox(ex.ToString)
    End Try
End Sub

[C#]

public void OnConnection(object application, ext_ConnectMode 
  connectMode, object addInInst, ref Array custom)
{
    _applicationObject = (DTE2)application;
    _addInInstance = (AddIn)addInInst;
    ReassignValue(_applicationObject);
}

// Before running, create a new Windows application project,
// and then add a function to it named MyFunction.
public void ReassignValue(DTE2 dte)
{
    try
    {
        FileCodeModel myFCM = 
          dte.ActiveDocument.ProjectItem.FileCodeModel;
        // Change the MyFunction name in Form1 class to
        // the name, OtherFunction.
        CodeClass myClass1 = 
          (CodeClass2)myFCM.CodeElements.Item("Form1");
        CodeFunction myFunction = 
          (CodeFunction2)myClass1.Members.Item("MyFunction");
        myFunction.Name = "OtherFunction";
        myFunction = 
          (CodeFunction2)myClass1.Members.Item("OtherFunction");
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message);
    }
}
RemarqueRemarque

La définition des propriétés des éléments enfants de votre élément de modèle de code ne présente pas ce comportement. Seules les propriétés qui affectent directement CodeElement— telles que le nom de l'élément, le type d'une fonction, la signature d'une méthode, etc. — montrent ce comportement non déterministe.

De plus, cet exemple ne fonctionne que si le nouveau nom de CodeElement est unique parmi ses frères. En effet, la propriété Item retourne la première correspondance, ce qui ne fonctionne pas pour les méthodes/propriétés surchargées, les classes partielles ou les espaces de noms portant le même nom.

Afficher: