Share via


Extend Word documents and Excel workbooks in VSTO add-ins at run time

Applies to: yesVisual Studio noVisual Studio for Mac

Note

This article applies to Visual Studio 2017. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here

You can use a VSTO Add-in to customize Word documents and Excel workbooks in the following ways:

  • Add managed controls to any open document or worksheet.

  • Convert an existing list object on an Excel worksheet to an extended ListObject that exposes events and can be bound to data by using the Windows Forms data binding model.

  • Access application-level events that are exposed by Word and Excel for specific documents, workbooks, and worksheets.

    To use this functionality, you generate an object at run time that extends the document or workbook.

    Applies to: The information in this article applies to VSTO Add-in projects for the following applications: Excel and Word. For more information, see Features available by Office application and project type.

Generate extended objects in VSTO Add-ins

Extended objects are instances of types provided by the Visual Studio Tools for Office runtime that add functionality to objects that exist natively in the Word or Excel object models (called native Office objects). To generate an extended object for a Word or Excel object, use the GetVstoObject method. The first time you call the GetVstoObject method for a specified Word or Excel object, it returns a new object that extends the specified object. Each time you call the method and specify the same Word or Excel object, it returns the same extended object.

The type of the extended object has the same name as the type of the native Office object, but the type is defined in the Microsoft.Office.Tools.Excel or Microsoft.Office.Tools.Word namespace. For example, if you call the GetVstoObject method to extend a Document object, the method returns a Document object.

The GetVstoObject methods are intended to be used primarily in VSTO Add-in projects. You can also use these methods in document-level projects, but they behave differently, and have fewer uses.

To determine whether an extended object has already been generated for a particular native Office object, use the HasVstoObject method. For more information, see Determine whether an Office object has been extended.

Generate host items

When you use the GetVstoObject to extend a document-level object (that is, a Workbook, Worksheet, or Document), the returned object is called a host item. A host item is a type that can contain other objects, including other extended objects and controls. It resembles the corresponding type in the Word or Excel primary interop assembly, but it has additional features. For more information about host items, see Host items and host controls overview.

After you generate a host item, you can use it to add managed controls to the document, workbook, or worksheet. For more information, see Add managed controls to documents and worksheets.

To generate a host item for a Word document

  • The following code example demonstrates how to generate a host item for the active document.

    If Globals.ThisAddIn.Application.Documents.Count > 0 Then
        Dim NativeDocument As Microsoft.Office.Interop.Word.Document = _
            Globals.ThisAddIn.Application.ActiveDocument
        Dim VstoDocument As Microsoft.Office.Tools.Word.Document = _
            Globals.Factory.GetVstoObject(NativeDocument)
    End If
    
    if (Globals.ThisAddIn.Application.Documents.Count > 0)
    {
        Microsoft.Office.Interop.Word.Document nativeDocument =
            Globals.ThisAddIn.Application.ActiveDocument;
        Microsoft.Office.Tools.Word.Document vstoDocument =
            Globals.Factory.GetVstoObject(nativeDocument);
    }
    

To generate a host item for an Excel workbook

  • The following code example demonstrates how to generate a host item for the active workbook.

    Dim NativeWorkbook As Microsoft.Office.Interop.Excel.Workbook =
        Globals.ThisAddIn.Application.ActiveWorkbook
    If NativeWorkbook IsNot Nothing Then
        Dim vstoWorkbook As Microsoft.Office.Tools.Excel.Workbook =
            Globals.Factory.GetVstoObject(NativeWorkbook)
    End If
    
    Microsoft.Office.Interop.Excel.Workbook nativeWorkbook = 
        Globals.ThisAddIn.Application.ActiveWorkbook;
    if (nativeWorkbook != null)
    {
        Microsoft.Office.Tools.Excel.Workbook vstoWorkbook = 
            Globals.Factory.GetVstoObject(nativeWorkbook);
    }
    

To generate a host item for an Excel worksheet

  • The following code example demonstrates how to generate a host item for the active worksheet in a project.

    Dim NativeWorksheet As Microsoft.Office.Interop.Excel.Worksheet =
        Globals.ThisAddIn.Application.ActiveSheet
    If NativeWorksheet IsNot Nothing Then
        Dim vstoSheet As Microsoft.Office.Tools.Excel.Worksheet =
            Globals.Factory.GetVstoObject(NativeWorksheet)
    End If
    
    Microsoft.Office.Interop.Excel.Worksheet nativeWorksheet =
        Globals.ThisAddIn.Application.ActiveSheet;
    if (nativeWorksheet != null)
    {
        Microsoft.Office.Tools.Excel.Worksheet vstoSheet = 
            Globals.Factory.GetVstoObject(nativeWorksheet);
    }
    

Generate ListObject host controls

When you use the GetVstoObject method to extend a ListObject, the method returns a ListObject. The ListObject has all of the features of the original ListObject. It also has additional functionality and can be bound to data by using the Windows Forms data binding model. For more information, see ListObject control.

To generate a host control for a ListObject

  • The following code example demonstrates how to generate a ListObject for the first ListObject in the active worksheet in a project.

    Dim sheet As Microsoft.Office.Interop.Excel.Worksheet =
        Globals.ThisAddIn.Application.ActiveSheet
    If sheet.ListObjects.Count > 0 Then
        Dim listObject As Excel.ListObject = sheet.ListObjects(1)
        Dim vstoListObject As Microsoft.Office.Tools.Excel.ListObject =
            Globals.Factory.GetVstoObject(listObject)
    End If
    
    Microsoft.Office.Interop.Excel.Worksheet sheet =
        Globals.ThisAddIn.Application.ActiveSheet;
    if (sheet.ListObjects.Count > 0)
    {
        Excel.ListObject listObject = 
            sheet.ListObjects[1];
        Microsoft.Office.Tools.Excel.ListObject vstoListObject =
            Globals.Factory.GetVstoObject(listObject);
    }
    

Add managed controls to documents and worksheets

After you generate a Document or Worksheet, you can add controls to the document or worksheet that these extended objects represent. To add controls, use the Controls property of the Document or Worksheet. For more information, see Add controls to Office documents at run time.

You can add Windows Forms controls or host controls. A host control is a control provided by the Visual Studio Tools for Office runtime that wraps a corresponding control in the Word or Excel primary interop assembly. A host control exposes all of the behavior of the underlying native Office object. It also raises events and can be bound to data by using the Windows Forms data binding model. For more information, see Host items and host controls overview.

Note

You cannot add a XmlMappedRange control to a worksheet, or a XMLNode or XMLNodes control to a document, by using a VSTO Add-in. These host controls cannot be added programmatically. For more information, see Programmatic limitations of host items and host controls.

Persist and remove controls

When you add managed controls to a document or worksheet, the controls are not persisted when the document is saved and then closed. All host controls are removed so that only the underlying native Office objects are left behind. For example, a ListObject becomes a ListObject. All Windows Forms controls are also removed, but ActiveX wrappers for the controls are left behind in the document. You must include code in your VSTO Add-in to clean up the controls, or to recreate the controls the next time the document is opened. For more information, see Persist dynamic controls in Office documents.

Access application-level events on documents and workbooks

Some document, workbook, and worksheet events in the native Word and Excel object models are raised only at the application level. For example, the DocumentBeforeSave event is raised when a document is opened in Word, but this event is defined in the Application class, rather than the Document class.

When you use only native Office objects in your VSTO Add-in, you must handle these application-level events and then write additional code to determine whether the document that raised the event is one that you have customized. Host items provide these events at the document level, so that it is easier to handle the events for a specific document. You can generate a host item and then handle the event for that host item.

Example that uses native Word objects

The following code example demonstrates how to handle an application-level event for Word documents. The CreateDocument method creates a new document, and then defines a DocumentBeforeSave event handler that prevents this document from being saved. The event is an application-level event that is raised for the Application object, and the event handler must compare the Doc parameter with the document1 object to determine if document1 represents the saved document.

Private document1 As Word.Document = Nothing

Private Sub CreateDocument1()
    document1 = Me.Application.Documents.Add()
End Sub

Private Sub Application_DocumentBeforeSave(ByVal Doc As Word.Document, _
    ByRef SaveAsUI As Boolean, ByRef Cancel As Boolean) _
    Handles Application.DocumentBeforeSave
    If Type.ReferenceEquals(Doc, document1) Then
        Cancel = True
    End If
End Sub
private Word.Document document1 = null;

private void CreateDocument1()
{
    document1 = this.Application.Documents.Add(ref missing,
        ref missing, ref missing, ref missing);
    this.Application.DocumentBeforeSave += 
        new Word.ApplicationEvents4_DocumentBeforeSaveEventHandler(
        Application_DocumentBeforeSave);
}

private void Application_DocumentBeforeSave(Word.Document Doc, 
    ref bool SaveAsUI, ref bool Cancel)
{
    if (Type.ReferenceEquals(Doc, document1)) 
    {
        Cancel = true;
    }
}

Examples that use a host item

The following code examples simplify this process by handling the BeforeSave event of a Document host item. The CreateDocument2 method in these examples generates a Document that extends the document2 object, and then it defines a BeforeSave event handler that prevents the document from being saved. The event handler is called only when document2 is saved, and can cancel the save action without doing any extra work to verify which document was saved.

The following code example demonstrates this task.

Private document2 As Word.Document = Nothing
Private WithEvents vstoDocument As Microsoft.Office.Tools.Word.Document = Nothing

Private Sub CreateDocument2()
    document2 = Me.Application.Documents.Add()
    vstoDocument = Globals.Factory.GetVstoObject(document2)
End Sub

Private Sub vstoDocument_BeforeSave(ByVal sender As Object, _
    ByVal e As SaveEventArgs) Handles vstoDocument.BeforeSave
    e.Cancel = True
End Sub
private Word.Document document2 = null;
private Microsoft.Office.Tools.Word.Document vstoDocument = null;

private void CreateDocument2()
{
    document2 = this.Application.Documents.Add(ref missing,
        ref missing, ref missing, ref missing);
    vstoDocument = Globals.Factory.GetVstoObject(document2);
    vstoDocument.BeforeSave += new SaveEventHandler(vstoDocument_BeforeSave);
}

private void vstoDocument_BeforeSave(object sender, SaveEventArgs e)
{
    e.Cancel = true;
}

Determine whether an Office object has been extended

To determine whether an extended object has already been generated for a particular native Office object, use the HasVstoObject method. This method returns true if an extended object has already been generated.

Use the Globals.Factory.HasVstoMethod method. Pass in the native Word or Excel object, such as a Document or Worksheet, that you want to test for an extended object.

The HasVstoObject method is useful when you want to run code only when a specified Office object has an extended object. For example, if you have a Word VSTO Add-in that handles the DocumentBeforeSave event to remove managed controls from a document before it's saved, use the HasVstoObject method to determine whether the document has been extended. If the document has not been extended, it cannot have managed controls, and the event handler can return without trying to clean up controls on the document.

See also