Walkthrough: Adding Host Items and Host Objects to an Add-in Project

This walkthrough demonstrates how to add, remove, and rename host items and host objects in a project in response to an add-in developer's actions in the host application during debugging. It uses drawings and shapes in the ShapeApp sample application for the example.

For more information about dynamically updating host items and host objects in an add-in project, see Dynamically Creating and Modifying Host Items and Host Objects in an Add-in Project.

This walkthrough illustrates the following tasks:

  • Starting and stopping the IDE.

  • Starting the IDE by using a menu item.

  • Adding, removing, and renaming shapes and drawings in an add-in project.

    Note

    This walkthrough does not include code to load and unload document-level add-ins. To view a complete sample that includes this code, see How to: Build and Run the ShapeAppDynamicProgrammingModelCSharp Sample.

Prerequisites

You need the following components to complete this walkthrough:

  • Visual Studio 2008.

  • Microsoft Visual Studio Tools for Applications 2.0.

  • The built ShapeAppBasicCSharp sample. This walkthrough assumes that you have extracted the ShapeAppBasicCSharp sample to %SYSTEMDRIVE%\ShapeAppSamples\ShapeAppBasicCSharp. For more information, see How to: Build and Run the ShapeAppBasicCSharp Sample.

    Note

    When you build the ShapeAppBasicCSharp sample, an executable file named ShapeAppBasicCSharp.exe is created in the %SYSTEMDRIVE%\ShapeAppSamples\ShapeAppBasicCSharp\core\base\bin\Debug directory. Use that executable file to follow this walkthrough.

Opening the Solution

First, open the ShapeAppBasicCSharp sample project in Visual Studio.

To open ShapeAppBasicCSharp

  1. Start Visual Studio 2008. If you are using Windows Vista as your operating system, start Visual Studio 2008 by using the Run as Administrator option.

  2. On the File menu, point to Open, and then click Project/Solution.

  3. In the Open Project dialog, navigate to the %SYSTEMDRIVE%\ShapeAppSamples\ShapeAppBasicCSharp folder.

  4. Select the ShapeAppCSharp.sln file, and then click Open.

Adding References to the Project

Before you can add and remove host items and host objects, you must add references to the extensibility libraries. These assemblies contain the methods that are required for Visual Studio Tools for Applications to access the IDE object model. 

To add the required references

  1. In Solution Explorer, right-click References under the ShapeAppBasicCSharp project, and then click Add Reference.

    The Add Reference dialog box appears.

  2. Click the .NET tab and add references to the following assemblies:

    • EnvDTE80

    • Microsoft.VisualStudio.Tools.Applications.DesignTime.v9.0

    • Microsoft.VisualStudio.Tools.Applications.ProgrammingModel

  3. Click the COM tab and add a reference to the following type library:

    • DTEProvider 1.0 Type Library. Select the version that is located in the directory C:\Program Files\Common Files\Microsoft Shared\VSTA\9.0\x86.
  4. Click OK.

Starting and Stopping the IDE

The add-in developer needs a way to start the Visual Studio Tools for Applications IDE from the host application. Add code to the ShapeAppBasicCSharp sample that starts the Visual Studio Tools for Applications IDE when the developer selects a menu option in the ShapeApp UI. 

To start and stop the IDE

  1. In Solution Explorer, right-click the ShapeAppBasicCSharp project, point to Add on the shortcut menu, and then click Class.

  2. Change the name of the class to VstaDesignTimeIntegration.cs, and then click Add.

  3. Add the following using statements to the top of the VstaDesignTimeIntegration.cs code file.

    using System.IO;
    using Microsoft.VisualStudio.Tools.Applications.DesignTime.Interop;
    using VSTADTEProvider.Interop;
    
  4. Replace the definition of the VstaDesignTimeIntegration class with the following code.

    internal sealed class VstaDesignTimeIntegration
    {
    }
    
  5. Add the following fields to the VstaDesignTimeIntegration class.

    private Document document;
    private bool connected;
    private EnvDTE.Project project;
    private string hostItemTemplatesPath;
    private EnvDTE.DTE dte;
    private IVstaHostAdapter hostAdapter;
    
  6. Add the following method to the VstaDesignTimeIntegration class. This code calls the EnsureIDE method to initialize the IDE. Later in this walkthrough, you will use the Document parameter to define event handlers for the active document.

    internal void Connect(Document doc)
    {
        if (connected)
            return;
        EnsureIDE();
        connected = true;
    }
    
  7. Add the following method to the VstaDesignTimeIntegration class. The ShowIDE method uses the DTE object that is created in the EnsureIDE method later in this walkthrough to start the IDE.

    internal void ShowIDE()
    {
        EnsureIDE();
        dte.MainWindow.Visible = true;
    }
    
  8. Add the following method to the VstaDesignTimeIntegration class. The Disconnect method stops the IDE debugger. This ensures that any external processes that are running for the debugger close along with the IDE.

    internal void Disconnect()
    {
        if (dte != null)
        {
            if (dte.Mode == EnvDTE.vsIDEMode.vsIDEModeDebug)
            {
                dte.Debugger.Stop(false);                    
                dte.Quit();
                dte = null;
            }
         }
    }
    
  9. Add the following method to the VstaDesignTimeIntegration class. The EnsureIDE method uses the VSTADTEProviderClass to obtain the DTE instance that is used to start the IDE. The VSTADTEProviderClass class contains many other methods and properties that you can use to automate the IDE.

    private void EnsureIDE()
    {
        if (this.hostAdapter != null)
            return;
        if (this.dte == null)
        {
    
            IDTEProvider dteProvider = (IDTEProvider)new VSTADTEProviderClass();
            this.dte = (EnvDTE.DTE)dteProvider.GetDTE("ShapeAppCSharp", 0);
            if (this.dte == null)
                throw new InvalidOperationException("Cannot launch VSTA");
         }
         if (this.project == null)
             this.project = CreateProject();
         if (this.hostAdapter == null)
             hostAdapter = (IVstaHostAdapter)project.get_Extender("VSTAHostAdapter2007");
         if (string.IsNullOrEmpty(this.hostItemTemplatesPath))
         {
             Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey
    (@"Software\Microsoft\ShapeAppCSharp");
             this.hostItemTemplatesPath = (string)regKey.GetValue("HostItemTemplatesLocation");
             if (String.IsNullOrEmpty(this.hostItemTemplatesPath))
             {
                 throw new InvalidOperationException("Cannot find HostItemTemplatesLocation.");
             }
         }
         if (hostAdapter == null)
         {
             this.Disconnect();
             throw new InvalidOperationException("cannot get the host adapter");
         }
     }
    
  10. Add the following method to the VstaDesignTimeIntegration class. The CreateProject method creates a document-level add-in project. This project appears in Solution Explorer when you open the Visual Studio Tools for Applications IDE. 

    private EnvDTE.Project CreateProject()
    {
        EnvDTE80.Solution2 sol = (EnvDTE80.Solution2)dte.Solution;
        string projectTemplatePath = sol.GetProjectTemplate("ShapeAppCSharp-DocLevel.zip", "CSharp");
        string myDocumentFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        string projectDir = Path.Combine(myDocumentFolder, @"ShapeAppCSharp\" + "Document1");
        string projectFilePath = projectDir + @"\" + "Document1" + ".csproj";
        if (Directory.Exists(projectDir))
            Directory.Delete(projectDir, true);
        Directory.CreateDirectory(projectDir);
        dte.Solution.AddFromTemplate(projectTemplatePath, projectDir,
                                     "Document1", true);
        foreach (EnvDTE.Project curProject in dte.Solution.Projects)
        {
            string projPath = curProject.FullName;
            if (String.Compare(projPath, projectFilePath,
                 StringComparison.OrdinalIgnoreCase) == 0)
            {
                EnvDTE.Project macroProject = curProject;
                return macroProject;
            }
        }
    throw new InvalidOperationException("Fail to create project");
    }  
    

Starting the IDE by Using a Menu Item

Add a menu to the ShapeApp UI that enables the add-in developer to start the Visual Studio Tools for Applications IDE. 

To start the IDE by using a menu item

  1. In Solution Explorer, double-click ApplicationForm.cs.

    The ApplicationForm.cs file opens in design mode.

  2. In the forms designer, on the ShapeApp form, click the menu strip next to the Help label.

    An editable combo box appears and displays the text Type Here.

  3. Type Customize, and then press ENTER.

    An editable combo box appears below the Customize menu item and displays the text Type Here.

  4. Type Create Document Add-In, and then press ENTER.

  5. Double-click the Create Document Add-In menu item.

    The ApplicationForm.cs file opens in the Code Editor.

  6. Replace the createDocumentAddInToolStripMenu_Click event handler with the following code. This code initializes and displays the Visual Studio Tools for Applications IDE.

    private void createDocumentAddInToolStripMenuItem_Click(object sender, EventArgs e)
    {
        if (this.application.Document != null)
        {             
            VstaDesignTimeIntegration vstaDesignTimeIntegration = 
                new VstaDesignTimeIntegration();
                        vstaDesignTimeIntegration.Connect
                            (this.application.Document);
            vstaDesignTimeIntegration.ShowIDE();     
         }
     }
    

Checkpoint

Run your project to verify that the Visual Studio Tools for Applications IDE has been properly integrated.

To test the Visual Studio Tools for Applications IDE

  1. In Visual Studio, press F5 to run ShapeApp.

  2. On the Customize menu of ShapeApp, click Create Document Add-In.

    The Visual Studio Tools for Applications IDE appears and opens a document-level add-in project in Project Explorer.

  3. Close the Visual Studio Tools for Applications IDE and ShapeApp.

Adding, Removing, and Renaming Shapes and Drawings

The IDE is configured, but when you add, remove, or rename drawings and shapes in ShapeApp during debugging, you will not yet see those changes reflected in the IDE. To enable this, add code to ShapeApp event handlers to call the methods in the extensibility libraries. You can determine which drawings and shapes are added, removed, or renamed by using the event parameters, and then use the extensibility classes to make those changes in the project.

To add, remove, and rename shapes and drawings in the add-in project

  1. Add the following using statements to the top of the VstaDesignTimeIntegration.cs code file.

    using System.Xml.Linq;
    using System.Text.RegularExpressions;
    using System.IO.Packaging;
    using Microsoft.VisualStudio.Tools.Applications.DesignTime;
    using Microsoft.VisualStudio.Tools.Applications.ProgrammingModel.Interop;
    
  2. Add the following code to the Connect method. This code adds the following host item classes to the add-in project:

    • A document class that represents the document that is open in ShapeApp.

    • One or more drawing classes that represent drawings that are open in ShapeApp.

    This code also loads event handlers for the DrawingInserted and DrawingRemoved events of the document. Shapeapp raises these events when you add or remove a drawing.

    this.document = doc;
    AddDocumentProjectHostItem();
    foreach (Drawing drawing in this.document.Drawings)
    AddDrawingProjectHostItem(drawing);
    
    this.document.Drawings.DrawingRemoved += new DrawingRemovedEventHandler(Drawings_DrawingRemoved);
    this.document.Drawings.DrawingInserted += new EventHandler(Drawings_DrawingInserted);
    
  3. Add the following event handler to the VstaDesignTimeIntegration class. This code handles the DrawingInserted event of the document. The Drawings_DrawingsInserted method performs the following tasks:

    • Gets the drawing that was added to the document in ShapeApp.

    • Adds a host item class that represents the drawing to the add-in project.

    void Drawings_DrawingInserted(object sender, EventArgs e)
    {
        Drawing drawing = (Drawing)sender;
        AddDrawingProjectHostItem(drawing);
    }
    
  4. Add the following method to the VstaDesignTimeIntegration class. This code handles the DrawingRemoved event of the document. The drawing_DrawingRemoved method performs the following tasks:

    • Gets a string that identifies the drawing.

    • Gets the host item that represents the drawing.

    • Removes the host item from a collection of host items that is associated with the add-in project.

    void Drawings_DrawingRemoved(object sender, DrawingRemovedEventArgs e)
    {
        string cookie = e.RemovedDrawingCookie;
        IVstaProjectHostItem item = this.hostAdapter.ProjectHostItems[cookie];
        if (item != null)                 
            this.hostAdapter.ProjectHostItems.RemoveProjectHostItem(item);
    }
    
  5. Add the following method to the VstaDesignTimeIntegration class. This method provides the code for the AddDocumentProjectHostItem method that you called in the Connect method.

    The AddDocumentProjectHostItem method adds a document host item class to the add-in project. This class inherits from the Microsoft.VisualStudio.Tools.Applications.Samples ShapeApp.DocumentEntryPoint class defined in the ShapeAppBasicCSharp proxy class.

    private void AddDocumentProjectHostItem()
    {
        hostAdapter.ProjectHostItems.AddProjectHostItem("ThisDocument", 
        "Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.DocumentEntryPoint",
    "Microsoft.VisualStudio.Tools.Applications.Runtime.IEntryPoint",
        "ThisDocument", this.hostItemTemplatesPath + @"\CSharp\ThisDocument");
    }
    
  6. Add the following method to the VstaDesignTimeIntegration class. This method provides the code for the AddDrawingProjectHostItem method that you called in the Connect method. The AddDocumentProjectHostItem method performs the following tasks:

    • Adds a drawing host item class to the add-in project. This class inherits from the Microsoft.VisualStudio.Tools.Applications.Samples .ShapeApp.DrawingEntry point class defined in the ShapeAppBasicCSharp proxy class.

    • Loads event handlers for the ShapeAdded and NameChanged events of the drawing. ShapeApp raises these events when you add or rename a drawing.

    private void AddDrawingProjectHostItem(ShapeApp.Drawing drawing)
    {
        hostAdapter.ProjectHostItems.AddProjectHostItem(drawing.Name,
    "Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.DrawingEntryPoint",
    "Microsoft.VisualStudio.Tools.Applications.Runtime.IEntryPoint", drawing.Name,
    this.hostItemTemplatesPath + @"\CSharp\drawing");
         drawing.ShapeAdded += new AddedEventHandler(drawing_ShapeAdded);
            drawing.ShapeRemoved += new ShapeRemovedEventHandler(drawing_ShapeRemoved);
         drawing.NameChanged += new NameChangedEventHandler(drawing_NameChanged);
    }
    
  7. Add the following method to the VstaDesignTimeIntegration class. This code handles the ShapeAdded event of a drawing. The drawing_ShapeAdded method performs the following tasks:

    • Gets the shape that was added to the drawing.

    • Gets the drawing to which the shape was added.

    • Gets the host item that represents the drawing.

    • Adds a host object that represents the shape to a collection of host objects that are associated with the host item.

    void drawing_ShapeAdded(object sender, EventArgs e)
    {
        AddedEventArgs addedEventArgs = (AddedEventArgs)e;
        IShape s = (IShape)addedEventArgs.AddedItem;
        Drawing drawing = (Drawing)sender;
        IVstaHostItem item = this.hostAdapter.ProjectHostItems[drawing.Cookie].ProgrammingModelHostItem;
        if (item == null)
        {
            throw new ArgumentOutOfRangeException("Cannot find the" +
                "drawing with the given cookie: ", drawing.Cookie);
        }
        item.HostObjects.Add(s.Name, "Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.IShape",
     drawing.Cookie + "$" + s.Name);
    }
    
  8. Add the following method to the VstaDesignTimeIntegration class. This code handles the ShapeRemoved event of a drawing. The drawing_ShapeRemoved method performs the following tasks:

    • Gets the shape that was removed from the drawing.

    • Gets the drawing from which the drawing was removed.

    • Gets the host item that represents the drawing.

    • Removes a host object that represents the shape from a collection of host objects that are associated with the host item.

    void drawing_ShapeRemoved(object sender, ShapeRemovedEventArgs e)
    {
         string shapeName = e.RemovedShapeName;
         Drawing drawing = (Drawing)sender;
         IVstaHostItem item = 
        this.hostAdapter.ProjectHostItems[drawing.Cookie].ProgrammingModelHostItem;
         if (item == null)
         {
             throw new ArgumentOutOfRangeException("sender", "Cannot find the drawing with the" +
    " given cookie: " + drawing.Cookie);
         }
         IVstaHostObject hostObject = item.HostObjects[drawing.Cookie + "$" + shapeName];
         if (hostObject == null)
         {
             return;
         }
         item.HostObjects.Remove(hostObject);
     }
    
  9. Add the following method to the VstaDesignTimeIntegration class. This code handles the NameChanged event of a drawing. The drawing_NameChanged method performs the following tasks:

    • Gets the drawing.

    • Gets the host item that represents the drawing.

    • Sets the display name of the host item to the updated name of the drawing.

    void drawing_NameChanged(object sender, NameChangedEventArgs e)
    {
        Drawing drawing = (Drawing)sender;
        string cookie = drawing.Cookie;
        if (string.IsNullOrEmpty(cookie))
        {
            throw new InvalidOperationException("Cannot find matching drawing cookie");
        }
        IVstaProjectHostItem projectHostItem = this.hostAdapter.ProjectHostItems[cookie];
        if (projectHostItem == null)
        {
        throw new InvalidOperationException("Cannot find matching drawing");
        }
        projectHostItem.ProgrammingModelHostItem.DisplayName = drawing.Name;
    }
    

Testing Code That Adds, Removes, and Renames Shapes and Drawings

When you add a drawing to ShapeApp while you debug, you also automatically add a host item class to the project. When you delete the drawing in ShapeApp, the host item class is removed from the project and the host item no longer appears in Project Explorer.

To test code that adds, removes, and renames drawing and shape classes

  1. In Visual Studio, press F5 to run ShapeApp.

  2. On the Customize menu of ShapeApp, click Create Document Add-In.

    The Visual Studio Tools for Applications IDE appears and opens an add-in project in Project Explorer.

  3. On the Drawings menu, click Insert.

  4. In the Visual Studio Tools for Applications IDE, verify that a new item named Drawing4.cs appears in Project Explorer.

  5. In ShapeApp, drag a triangle onto Drawing4.

  6. In the Visual Studio Tools for Applications IDE, double-click Drawing4.cs.

    Drawing4.cs opens in the Code Editor.

  7. In the Drawing4_Startup method, type Triangle1.Color = Color.Blue; to verify that you can access the new triangle in code.

  8. On the Drawings menu of ShapeApp, click Rename. Rename Drawing4 to myDrawing.

  9. In the Visual Studio Tools for Applications IDE, verify that Drawing4.cs now appears as Drawing4.cs (myDrawing) in Project Explorer.

  10. On the Drawings menu of ShapeApp, click Delete.

  11. In the Visual Studio Tools for Applications IDE, verify that the item named Drawing4 no longer appears in Project Explorer.

Next Steps

You can perform a comprehensive series of walkthroughs that demonstrate how to integrate Visual Studio Tools for Applications into the ShapeApp sample. For more information, see Walkthrough: Integrating Visual Studio Tools for Applications with ShapeApp.

To learn how to incorporate the Visual Studio Tools for Applications debugger and enable macro recording in a host application, see Walkthrough: Incorporating the IDE for a Managed Object Model.

See Also

Tasks

How to: Add and Remove Host Items in an Add-in Project

How to: Add and Remove Host Objects in an Add-in Project

How to: Change the Display Name of a Host Item

Concepts

Dynamically Creating and Modifying Host Items and Host Objects in an Add-in Project

Creating In-Process Hosts