次の方法で共有


コード モデルを使用したコードの調査 (Visual Basic)

Visual Studio コード モデルには、オートメーション クライアントでプロジェクト内のコード定義を調査し、コード要素を変更する機能が用意されています。コード エディターで内容が変更された場合、コード モデルによって、参照されているすべてのオブジェクトが自動的に更新されます。たとえば、クラス オブジェクトを参照している場合に、別のユーザーが新しい関数を追加すると、その追加された関数はメンバーの中に表示されます。コード モデルを使用すると、オートメーション クライアントでは、プロジェクト内でクラス、インターフェイス、構造体、メソッド、プロパティなどの高度な定義を調査するために、Visual Studio 言語のパーサーを実装する必要がなくなります。

Visual Studio コア コード モデルでは、コードの言語固有の部分はありません。たとえば、関数内のステートメント用のオブジェクト モデルは用意されておらず、パラメーターの詳細も指定されていません。パラメーターに関しては、コード モデルでは、パラメーターの型と名前だけが公開されます。パラメーターが入力パラメーター、出力パラメーター、省略可能なパラメーターなどのうちどれであるかを示す情報は提供されません。Visual C++ には、Visual C++ プロジェクトを対象とするコア コード モデルの拡張バージョンが用意されています。マクロのデバッグについては、「Visual C++ コード モデル」を参照してください。

コード モデルによるコードの調査と編集

コード モデルは、主にテキスト ベースであり、プロジェクトのプログラムやコードはテキスト ファイルに格納されています。プロジェクト モデルを使用してプロジェクトのコード内を検索し、各プロジェクト項目を参照します。その後、FileCodeModel を使用して、プロジェクト項目にコードが含まれているかどうかをチェックします。プロジェクト項目にコード要素が含まれる場合、コード要素はエディターからオブジェクトを返すことができます。また、コード モデルでは、テキスト エディターのオートメーション モデルを使用して、コードを変更したりローカライズされた解析を実行したりできます。Editor オブジェクト モデルを使用すると、エディターのカーソル位置を含むコード要素、または関数レベルやクラス レベルの TextPoint オブジェクトを要求できます。

Visual Studio コア コード モデルへの主なエントリ ポイントは、CodeModel オブジェクトです。標準の CodeElements コレクションは、コード モデルの複数の場所で使用されています。このコレクションは、CodeElements レベルおよびクラス レベルまたはインターフェイス レベルで、これらのオブジェクトのメンバーを返します。CodeElements コレクションの各要素は CodeElement2 オブジェクトであり、各 CodeElement2 オブジェクトには Kind プロパティがあります。このプロパティでは、このオブジェクトの型がクラス、インターフェイス、構造体、関数、プロパティ、変数などのどの型であるかを識別します。

言語に固有のコード モデル

Visual C++ には、コア コード モデルの拡張機能が用意されており、Visual C++ 固有のコードを対象とします。たとえば、Language で指定されたコード要素が Visual C++ コード モデル オブジェクトであり、Kind = vsCMElementClass である場合は、Visual Studio コード モデルから CodeClass の QueryInterface (QI) を使用するか、Visual C++ 言語固有のコード モデルから VCCodeClass の QI を使用するかを選択できます。Visual C++ 固有のコード モデルの詳細については、「方法 : Visual C++ コード モデルを使用したコード操作 (Visual Basic)」および「Visual C++ コード モデル」を参照してください。

tz746te4.collapse_all(ja-jp,VS.110).gifVisual Studio コア コード モデルに関するメモ

  • 言語に固有な Microsoft 言語実装のモデリングを実行するのは、Visual C++ コード モデルの実装のみです。

  • 一部の言語では、Visual Studio コード モデル全体が実装されません。ヘルプ トピックは、例外が存在する場合にその例外を示します。コード モデルの実装間の相違点の多くは、各言語で機能が異なることが原因です。たとえば、トップレベルの関数定義は Visual C++ でしか機能しないため、Visual Basic または Visual C# では、CodeNamespace オブジェクトに関数を追加できません。

tz746te4.collapse_all(ja-jp,VS.110).gifDescription

このアドインでは、Visual Studio ファイルのさまざまなコード要素を処理します。この例を実行するには、Visual Studio コード エディターでソース コード ファイルを開いておく必要があります。この例の実行方法の詳細については、「方法 : オートメーション オブジェクト モデルのコード例をコンパイルおよび実行する」を参照してください。

tz746te4.collapse_all(ja-jp,VS.110).gifコード

' 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

変更されるコード モデル要素値

なんらかの編集よって、クラス、構造体、関数、属性、デリゲートなどのコード モデル要素に割り当てられた値が変更されることがあります。したがって、これらの値が静的なものであると想定することはできません。

たとえば、コード モデル要素をローカル変数に割り当て、このローカル変数のプロパティ値を設定した場合、あとでローカル変数を参照すると有効なコード モデル要素が含まれていないことがあります。実際、別のコード モデル要素が含まれていることもあります。

CodeFunction 変数に割り当て、CodeFunction の Name プロパティに "YourFunction" の値を設定した "MyFunction" という名前の関数を含むクラスの例を考えてみます。このように変数を割り当てると、ローカル変数が同じ CodeFunction を示すとは限りません。したがって、このプロパティの値を参照すると E_FAIL という結果が返されることがあります。

この問題に対処するときに推奨される方法は、プロパティの値を参照する前に、明示的にローカル変数を正しいコード モデル要素に再割り当てすることです。これを行うための方法を次に示します。コードはアドインの形式です。

tz746te4.collapse_all(ja-jp,VS.110).gifDescription

このアドインの例は、適切な値が返されるように CodeElements の値を参照する正しい方法を示しています。この例の実行方法の詳細については、「方法 : オートメーション オブジェクト モデルのコード例をコンパイルおよび実行する」を参照してください。

tz746te4.collapse_all(ja-jp,VS.110).gifコード

[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);
    }
}

[!メモ]

コード モデル要素の子要素のプロパティを設定した場合は、このような動作は起きません。要素名、関数の型、メソッドのシグネチャなど、CodeElement に直接影響を及ぼすプロパティだけが、このような不確定な動作を示します。

また、この例が適用されるのは、CodeElement の新しい名前が兄弟間で一意の名前になる場合だけです。これは、Item プロパティが最初の一致を返してくるためですが、オーバーロードされたメソッドやプロパティ、部分クラス、または同じ名前を持つ名前空間には適用されません。

参照

処理手順

方法 : Visual C++ コード モデル機能拡張のプログラム例をコンパイルする

方法 : アドインを作成する

チュートリアル : ウィザードの作成

方法 : Visual C++ コード モデルを使用したコード操作 (Visual C#)

概念

コード モデルを使用したコードの調査 (Visual C#)

Visual C++ コード モデル

オートメーション オブジェクト モデルの階層図

Visual C++ コード モデル

その他の技術情報

環境ウィンドウの作成と制御

アドインおよびウィザードの作成

オートメーションと機能拡張のリファレンス