Extending Word Documents and Excel Workbooks in Application-Level Add-ins at Run Time

You can use an application-level add-in to customize Word documents and Excel workbooks in the following ways:

  • Add managed controls to any open document or worksheet.

  • Create smart tags that are recognized in a specific document or workbook.

    Note

    Smart tags are deprecated in Excel 2010 and Word 2010. For more information, see Smart Tags Overview.

  • 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 topic applies to application-level projects for the following applications: Excel 2007 and Excel 2010; Word 2007 and Word 2010. For more information, see Features Available by Office Application and Project Type.

Generating Extended Objects in 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 Microsoft.Office.Interop.Word.Document object, the method returns a Microsoft.Office.Tools.Word.Document object.

The way that you access the GetVstoObject method depends on what version of the .NET Framework your project targets:

The GetVstoObject methods are intended to be used primarily in application-level projects. You can also use these methods in document-level projects, but they behave differently, and have fewer uses. For more information, see Getting Extended Objects from Native Office Objects in Document-Level Customizations.

To determine whether an extended object has already been generated for a particular native Office object, use the HasVstoObject method. For more information, see Determining Whether an Office Object Has Been Extended.

Note

To use the GetVstoObject and HasVstoObject methods in a code file other than ThisAddIn.cs or ThisAddIn.vb in a project that targets the .NET Framework 3.5, you must modify your project. For more information, see Configuring Your Project to Use the GetVstoObject and HasVstoObject Methods.

Generating Host Items

When you use the GetVstoObject to extend a document-level object (that is, a Microsoft.Office.Interop.Excel.Workbook, Microsoft.Office.Interop.Excel.Worksheet, or Microsoft.Office.Interop.Word.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 smart tags or managed controls to the document, workbook, or worksheet. For more information, see Adding Smart Tags to Documents and Workbooks and Adding 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 in a project that targets the .NET Framework 4.

    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);
    }
    
  • The following code example demonstrates the same task in a project that targets the .NET Framework 3.5.

    If Globals.ThisAddIn.Application.Documents.Count > 0 Then
        Dim NativeDocument As Microsoft.Office.Interop.Word.Document =
            Globals.ThisAddIn.Application.ActiveDocument
        If NativeDocument IsNot Nothing Then
            Dim vstoDocument As Microsoft.Office.Tools.Word.Document =
                NativeDocument.GetVstoObject()
        End If
    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 =
            nativeDocument.GetVstoObject();
    }
    

To generate a host item for an Excel workbook

  • The following code example demonstrates how to generate a host item for the active workbook in a project that targets the .NET Framework 4.

    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);
    }
    
  • The following code example demonstrates the same task in a project that targets the .NET Framework 3.5.

    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 = _
            NativeWorkbook.GetVstoObject()
    End If
    
    Microsoft.Office.Interop.Excel.Workbook nativeWorkbook =
        Globals.ThisAddIn.Application.ActiveWorkbook;
    
    if (nativeWorkbook != null)
    {
        Microsoft.Office.Tools.Excel.Workbook vstoWorkbook =
            nativeWorkbook.GetVstoObject();
    }
    

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 that targets the .NET Framework 4.

    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);
    }
    
  • The following code example demonstrates the same task in a project that targets the .NET Framework 3.5.

    Dim NativeSheet As Microsoft.Office.Interop.Excel.Worksheet = _
        TryCast(Globals.ThisAddIn.Application.ActiveSheet,  _
        Microsoft.Office.Interop.Excel.Worksheet)
    
    If NativeSheet IsNot Nothing Then
        Dim VstoSheet As Microsoft.Office.Tools.Excel.Worksheet = _
            NativeSheet.GetVstoObject()
    End If
    
    Microsoft.Office.Interop.Excel.Worksheet nativeSheet =
        Globals.ThisAddIn.Application.ActiveSheet as
        Microsoft.Office.Interop.Excel.Worksheet;
    
    if (nativeSheet != null)
    {
        Microsoft.Office.Tools.Excel.Worksheet vstoSheet =
            nativeSheet.GetVstoObject();
    }
    

Generating ListObject Host Controls

When you use the GetVstoObject method to extend a Microsoft.Office.Interop.Excel.ListObject, the method returns a Microsoft.Office.Tools.Excel.ListObject. The Microsoft.Office.Tools.Excel.ListObject has all of the features of the original Microsoft.Office.Interop.Excel.ListObject, but it also has additional functionality, such as the ability to 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 Microsoft.Office.Tools.Excel.ListObject for the first Microsoft.Office.Interop.Excel.ListObject in the active worksheet in a project that targets the .NET Framework 4.

    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);
    }
    
  • The following code example demonstrates the same task in a project that targets the .NET Framework 3.5.

    Dim sheet As 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 = _
            listObject.GetVstoObject()
    End If
    
    Microsoft.Office.Interop.Excel.Worksheet sheet =
        Globals.ThisAddIn.Application.ActiveSheet as
        Microsoft.Office.Interop.Excel.Worksheet;
    
    if (sheet.ListObjects.Count > 0)
    {
        Excel.ListObject listObject = sheet.ListObjects[1];
        Microsoft.Office.Tools.Excel.ListObject vstoListObject =
            listObject.GetVstoObject();
    }
    

Adding Smart Tags to Documents and Workbooks

After you generate a Microsoft.Office.Tools.Word.Document or Microsoft.Office.Tools.Excel.Workbook, you can create a smart tag that is recognized in the context of the document or workbook that these objects represent. To do this, use the VstoSmartTags property of the Microsoft.Office.Tools.Word.Document or Microsoft.Office.Tools.Excel.Workbook. For more information, see the following topics:

Adding Managed Controls to Documents and Worksheets

After you generate a Microsoft.Office.Tools.Word.Document or Microsoft.Office.Tools.Excel.Worksheet, you can add controls to the document or worksheet that these extended objects represent. To do this, use the Controls property of the Microsoft.Office.Tools.Word.Document or Microsoft.Office.Tools.Excel.Worksheet. For more information, see Adding 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, but 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 an XmlMappedRange control to a worksheet, or an XMLNode or XMLNodes control to a document, by using an add-in. These host controls cannot be added programmatically. For more information, see Programmatic Limitations of Host Items and Host Controls.

Persisting and Removing 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 Microsoft.Office.Tools.Excel.ListObject becomes a Microsoft.Office.Interop.Excel.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 add-in to clean up the controls, or to recreate the controls the next time the document is opened. For more information, see Persisting Dynamic Controls in Office Documents.

Accessing 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 Microsoft.Office.Interop.Word.Application class, rather than the Microsoft.Office.Interop.Word.Document class.

When you use only native Office objects in your 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. Because this is an application-level event that is raised for the Microsoft.Office.Interop.Word.Application object, 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 Microsoft.Office.Tools.Word.Document host item. The CreateDocument2 method in these examples generate a Microsoft.Office.Tools.Word.Document that extends the document2 object, and then it defines a BeforeSave event handler that prevents the document from being saved. Because this event handler is called only when document2 is saved, the event handler can cancel the save action without doing any extra work to verify which document was saved.

The following code example demonstrates this task in a project that targets the .NET Framework 4.

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

The following code example demonstrates this task in a project that targets the .NET Framework 3.5.

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

Private Sub CreateDocument2()
    document2 = Me.Application.Documents.Add()
    vstoDocument = document2.GetVstoObject()
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 = document2.GetVstoObject();
    vstoDocument.BeforeSave += new SaveEventHandler(vstoDocument_BeforeSave);
}

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

Determining 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; otherwise, it returns false.

In projects that target the .NET Framework 3.5, the HasVstoObject method is available on instances of the following types in the Excel and Word primary interop assemblies:

In projects that target the .NET Framework 4, use the Globals.Factory.HasVstoMethod method. Pass in the native Word or Excel object (such as a Microsoft.Office.Interop.Word.Document or Microsoft.Office.Interop.Excel.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 add-in that handles the DocumentBeforeSave event to remove managed controls from a document before it is saved, you can use the HasVstoObject method to determine whether the document has been extended. If the document has not been extended, it cannot contain managed controls, and therefore the event handler can simply return without trying to clean up controls on the document.

Configuring .NET Framework 3.5 Projects to Use the GetVstoObject and HasVstoObject Methods

When you create an application-level project that targets the .NET Framework 3.5, the project is automatically configured for you to use the GetVstoObject and HasVstoObject methods in the ThisAddIn.cs or ThisAddIn.vb code files. To use these methods in a code file other than ThisAddIn.cs or ThisAddIn.vb, you must make the following changes to the code file.

To modify a code file in an Excel project to create extended objects

  • Add the following using (for C#) or Imports (for Visual Basic) statements to the top of the code file in which you want to use the GetVstoObject and HasVstoObject methods.

    Imports Microsoft.Office.Tools.Excel.Extensions
    
    using Microsoft.Office.Tools.Excel.Extensions;
    

To modify a code file in a Word project to create extended objects

  • Add the following using (for C#) or Imports (for Visual Basic) statements to the top of the code file in which you want to use the GetVstoObject and HasVstoObject methods.

    Imports Microsoft.Office.Tools.Word.Extensions
    
    using Microsoft.Office.Tools.Word.Extensions;
    

These changes are required because the GetVstoObject and HasVstoObject methods are implemented as extension methods. Although you use the GetVstoObject and HasVstoObject methods as though they were defined in types in the Excel or Word primary interop assemblies, they are actually defined in types in the Microsoft.Office.Tools.Excel.Extensions and Microsoft.Office.Tools.Word.Extensions namespaces of the Visual Studio Tools for Office runtime. For more information about extension methods, see Extension Methods (C# Programming Guide) and Extension Methods (Visual Basic).

See Also

Concepts

Adding Controls to Office Documents at Run Time

Host Items and Host Controls Overview

Getting Extended Objects from Native Office Objects in Document-Level Customizations

Other Resources

Programming Application-Level Add-Ins

Smart Tags Overview

Office Development Samples and Walkthroughs