http://www.developer.com/

Back to article

Using Visual Studio to Write Word Add-ins


August 4, 2009

Introduction

For a long time, businesses have relied on Microsoft's Office applications to help running their daily routines. Word is used to write e-mails and letters, Excel does the calculations, and Outlook communicates. Everyone has seen a slideshow made with PowerPoint. During the years, Office has grown, and today the number of applications part of the suite has grown to over ten.

Although many businesses can run their business with stock versions of these products, it is common to repeat the same steps again and again. For instance, sales people might copy and paste information from their sales system to a Word document, write their offer, send it out, and then return to the sales system to mark their offer as done. And then they start all over again.

As with many other Microsoft products, Office applications are also highly customizable. In the past few releases, extending these applications has become easier, and you as a developer are not anymore limited to writing COM DLLs with complex interfaces. Today, .NET developers can also easily get started.

In this article, you are going to learn how you can use Visual Studio 2008 and .NET to write custom add-ins for Word. Along the way, you will explore the possibilities for writing such applications. For instance, you can integrate databases, web services and even blogs to your add-ins.

Say hello to VSTO

Developing applications for the Office products, and especially for Office 2003 and 2007, is best done using Visual Studio Tools for Office, or VSTO. With VSTO in Visual Studio 2008, you can create different types of applications that utilize the Office products as a platform. For instance, you can create application-level add-ins, document-level customizations, templates, workflows, and so on. And as you might guess, you can develop your applications from the convenience of the Visual Studio IDE.

Love or hate it, the Office 2007 release bought developers the Ribbon (Figure 1). With VSTO, you can also create your own customizations to the ribbon, for example by adding buttons or creating new groups of commands. Although ribbon customizations are not the focus of this article, it is important to realize that this kind of user interface is getting more and more common. Windows 7 also contains a ribbon interface in many of the built-in applications such as Paint and Wordpad.



Click here for larger image

Figure 1. Office 2007 bought us a new user interface along with the Ribbon.

Office applications have had a user interface element called a task panel for a long time already (Figure 2). With VSTO, you can create your custom task panels, and for the purpose of this article, they are a great way to expose the add-in's user interface, but more on that shortly.



Click here for larger image

Figure 2. The Mail Merge feature uses a custom task panel to display its interface.

If you have studied Office application development before, you might have the impression that such development work is hard. With previous versions of Visual Studio, this arguably was the case, as you had to fiddle with different COM interfaces, primary interoperability assemblies (PIAs), and so on. But if you are using Visual Studio 2008 and are targeting Office 2007 applications, things have gotten much easier.

Installing VSTO usually happens along with Visual Studio. When selecting the features to be installed, you will also have the chance to select VSTO components (Figure 3). Note however, that VSTO is only available from Visual Studio Professional upwards. It is not available in the Visual Studio Standard or Expression editions, nor can it be purchased separately.



Click here for larger image

Figure 3 - Visual Studio Setup Screen.png

Figure 3. VSTO components are part of Visual Studio 2008 Professional and Team editions.

Creating a custom solution for Word

A technology like VSTO is best demonstrated with the help of a sample application. To demonstrate the possibilities of expanding Office applications with a custom solution, this article walks you through in creating an add-in for Word with VSTO in Visual Studio 2008.

The add-in itself contains a custom task panel. The purpose of this panel is to let a sales person send quotes to customers more efficiently. The sales person can simply enter a customer ID, and automatically fetch customer's basic information into the active Word document. The panel also contains a little utility to convert U.S. dollar amount to euros using a web service. Finally, once the document is saved, the add-in posts an update to a public blog. This way, other sales persons are aware of the updated quote.

To begin developing your custom task panel, you first need to fire up Visual Studio 2008. Choose to create a new project (with the File/New/Project menu command), and in the subsequent New Project dialog box, navigate to the Office/2007 project type node on the left (Figure 4). From there, select a Word Add-in, enter a name for your project (such as WordSalesToolsAddIn), and click OK.



Click here for larger image

Figure 4. Starting a Word add-in project is easy with the Office project templates.

Once Visual Studio has finished creating your project from the template, you should see a project with several files and references (Figure 5). For instance, under the Word folder, you should see a file named ThisAddIn.cs. This file acts like the Global.asax.cs file in ASP.NET web applications: the code in the file is executed when the add- in first loads, and also when add-in is unloaded, i.e. when Word closes down.



Click here for larger image

Figure 5. An empty add-in project as created by Visual Studio.

If you run the project immediately after creating it, Visual Studio will automatically register your add-in so that Word can load it, and will then start Word. This makes development and testing very easy. However, unless you have written additional code to the project, you cannot actually see anything in Word when you run your project. Even on the Ribbon, the Add-ins tab (if visible) doesn't contain any hints about your creation.

Of course, creating a custom task panel will create something that's visible in Word. At this point, you might be tempted to return to Visual Studio, open the Add New Item dialog box (Project/Add New Item) and look for a custom task panel object. Unfortunately, such an object does not exist. Instead, to create custom task panels for Word and other compatible Office applications, you need user controls.

Task panels as user controls

To create a new custom task panel for Word, you need to add a Windows Forms user control to your project. To do this, open the Add New Item dialog box and select the User Control template from the Windows Forms group (Figure 6). Alternatively, you can use the Project menu's "Add User Control" command.



Click here for larger image

Figure 6. Custom task panels are implemented as WinForms user controls.

Once added, the user control will show as a blank, gray area in the Visual Studio designer. The next step would be to add controls to the designer surface. You will also need a small piece of code in the ThisAddIn.cs file to register your task panel with Word, and make it visible. The code is similar to the following:

  SalesToolsUserControl userControl =
    new SalesToolsUserControl();
  CustomTaskPane myCustomTaskPane =
    this.CustomTaskPanes.Add(
    userControl, "Sales Tools");
  myCustomTaskPane.Visible = true;

This code is added to the ThisAddIn_Startup method in the ThisAddIn.cs file. In the code, an instance of the user control (here called SalesToolsUserControl) is created, and then it is added to the list of custom task panes that Word controls. Finally, the pane is shown on the screen.

Implementing the functionality for the add-in

Once you have the basic user control skeleton created for your custom task pane, it is time to add some functionality. You can easily design the user interface of your pane in Visual Studio, as a full-blown form designer is already there. By default, Word sets the pane's width to equal 200 pixels, with a height dependent on the size of Word's main window. You might wish to set the width of your user control to equal 200 pixels so that designing would be easier.

Figure 7 shows the designed user interface for the sample user control. Overall, the user interface itself is very basic, but it's the underlying code that makes the add-in useful. The first feature in the add-in allows the user to type in a customer ID, and then the add-in will fetch that customer's details from the Northwind SQL Server sample database, and add them to the active Word document.


Figure 7. The sample application's task panel in Visual Studio designer.
The code to fetch the details is straightforward: an SQL connection is opened, a command is executed, and finally a SqlDataReader object is used to fetch the results of the query: string connStr = Properties.Settings.

      Default.DatabaseConnection;
  SqlConnection conn = new SqlConnection(
      connStr);
  try
  {
    conn.Open();
    string sql = "SELECT [companyname], "+
        "[contactname], [address], [city], " +
        "[region], [postalcode] "+
        "FROM [customers] " +
        "WHERE [customerid] = @custid";
    SqlCommand cmd = new SqlCommand(
        sql, conn);
    cmd.Parameters.AddWithValue(
        "@custid", customerId);
    try
    {
      SqlDataReader reader =
          cmd.ExecuteReader();
      try
      {
        if (reader.Read())
        {
          CustomerDetails cust =
              new CustomerDetails();
          cust.CompanyName = reader.GetString(0);
          cust.ContactName = reader.GetString(1);
          cust.Address = reader.GetString(2);
          cust.City = reader.GetString(3);
          if (!reader.IsDBNull(4))
          {
              cust.Region = reader.GetString(4);
          }
          cust.ZipCode = reader.GetString(5);
  
          // finished
          return cust;
        }
      }
  ...

Here, the connection string is read from the add-in's XML configuration file, and the given customer ID is passed as a parameter to the SqlCommand object. The results are returned in a custom class instance, which contains simple public properties for each value.

Once the query has been executed, it is time to insert the results into the active Word document.

This is done with the following code:

  CustomerDetails cust =
    DataAccess.GetCustomerDetails(
    customerIdTextBox.Text);
  // format text
  StringBuilder buffer = new StringBuilder();
  buffer.AppendLine(cust.CompanyName);
  buffer.AppendLine(cust.ContactName);
  buffer.AppendLine(cust.Address);
  buffer.AppendLine(cust.City);
  buffer.AppendLine(cust.Region);
  buffer.AppendLine(cust.ZipCode);
  // insert text at the current cursor location
  Microsoft.Office.Interop.Word.Application
    word = Globals.ThisAddIn.Application;
  Word.Range selection = word.Selection.Range;
  selection.Text = buffer.ToString();

The main interaction with Word happens in the last three lines of code. The Globals class is a designer-created class that is part of every Word add-in project, and is created automatically by Visual Studio when you start the project. It lives in the hidden ThisAddIn.Designer.cs file. Through the Globals object, you can access your add-in's ThisAddIn class. In turn, this class then contains the Application reference, which points to Word's automation interface master object. The Word object is defined in the Microsoft.Office.Interop.Word.Application namespace, which has a rather lengthy name to type. Thus, you might wish to use the following C# using statements to help you manage the long names:

  using Word = Microsoft.Office.Interop.Word;
  using Office = Microsoft.Office.Core;
  using Microsoft.Office.Tools.Word;
  using Microsoft.Office.Tools.Word.Extensions;
  using Microsoft.Office.Tools;

These same using statements are available in ThisAddIn.cs, from which you might wish to copy them to your user control file.

Converting currency values

The next part of functionality in the sample add-in is the ability to convert currencies. In this case, the sample application can take a USD dollar amount, and convert it to Euros (€). This is done with the help of a free currency conversion service available at Nimacon.net.

To use this service, you will first need to add a service reference to the project. This is done easily using the Add Service Reference dialog box in Visual Studio, launched for example using the similarly named command in the Project menu. Once the reference has been added, the following code can be used to convert a USD amount into Euros:

  float usdAmount = float.Parse(usdAmountTextBox.Text);
  CurrencyRateService.CurrencyRateServiceClient
    client = new CurrencyRateService.CurrencyRateServiceClient();
  float euroAmount = client.GetEuroAmount(
    "USD", usdAmount);
  MessageBox.Show("$" + usdAmount + " is " +
    euroAmount + " €.");

First, the code takes the USD amount the user has entered, and converts the string to a float value. Then, an instance of the web service client class is constructed (Visual Studio automatically creates the CurrencyRateServiceClient class when the service reference is added). The next step is to make the actual web service (SOAP) call using the GetEuroAmount method of the service. This method takes in a currency amount in any supported currency, and a string specifying which currency the value is in. The return value is the amount in Euros with the current exchange rate.

Publishing to a blog

In a corporate setting, sharing information is a necessity. For instance, if a member of a sales team creates or updates an important offer, the other members of the team should know about it. However, letting other people know that you've updated a document is an additional, often manual step. Why couldn't the system automatically send a status update to colleagues whenever an important document changes?

In the sample application, this need to inform others is addressed via a blog. Whenever the user saves the offer (i.e. commits the updates made), the add-in automatically publishes a new entry on a Google Blogger blog, which is available at www.blogspot.com (Figure 8). The Blogger service uses a free HTTP based API, which is divided into two major parts: authentication with the generic Google authentication APIs, and the specific Blogger interfaces to submit blog posts.



Click here for larger image

Figure 8. The sample application can publish to a Google Blogger blog.

Since the focus of this article is in Word add-ins and not the Google interfaces, only a short description follows. As mentioned previously, the first part of using the Blogger service is to authenticate properly. This is done by sending a HTTP POST request to the authentication URL, and passing in the username and password for the service. In exchange, the service returns an authentication token, which must be passed when submitting a post to the user's blog with the Blogger API.

The following is a snippet of the code to authenticate with the service. The Google developer documentation for the service is publicly available on the Internet; see the Links section for details.

  
  WebClient web = new WebClient();
  try
  {
    NameValueCollection postParams =
      new NameValueCollection();
    postParams.Add("accountType", accountType);
    postParams.Add("Email", email);
    postParams.Add("Passwd", password);
    postParams.Add("service", service);
    postParams.Add("source", sourceApp);
    byte[] result = web.UploadValues(
      loginUrl, "POST", postParams);
    string resultStr =
      Encoding.ASCII.GetString(result);
    string[] tokens = resultStr.Split();
    bloggerAuthToken = tokens[2].Substring(5);
  }
  finally
  {
    web.Dispose();
  }
  

With the authentication token available (the bloggerAuthToken member at the end of the code snippet), the next step is to call the actual posting function. This can be done with code similar to the following:

  public static void SubmitBlogPost(
    string title, string body)
  {
    string xml;
    MemoryStream xmlStream =
      new MemoryStream();
    try
    {
      XmlWriterSettings settings =
        new XmlWriterSettings();
      settings.Indent = true;
      XmlWriter writer = XmlWriter.Create(
        xmlStream, settings);
      try
      {
        writer.WriteStartElement(
          "entry", "http://www.w3.org/2005/Atom");
        ...
        writer.WriteEndElement();
      }
      finally
      {
        writer.Close();
      }
      xml = Encoding.ASCII.GetString(xmlStream.ToArray());
    }
    finally
    {
      xmlStream.Dispose();
    }
    WebClient web = new WebClient();
    try
    {
      web.Headers.Add("Content-Type", "application/atom+xml");
      web.Headers.Add("Authorization", "GoogleLogin auth=" +
        bloggerAuthToken);
      web.Headers.Add("GData-Version", "2");
      web.Encoding = Encoding.UTF8;
      string response = web.UploadString(submitUrl, "POST", xml);
    }
    finally
    {
      web.Dispose();
    }
  }

Here, the code first constructs an XML based Atom entry that the Blogger service accepts (the actual lines are omitted for brevity), and then uses a WebClient to connect to the HTTP service. Note how several custom headers have to be added to the HTTP request for the Google API to accept it.

Now that the code to submit a blog entry is in place, next you need to notice when the Word document is being saved. The Word object model supports a set of events, and one of them is called DocumentBeforeSave. You can hook into this event, and then execute the necessary code to update the blog whenever the document has been saved.

The logical place to hook into this event is in ThisAddIn.cs' ThisAddIn_Startup method. Here is the code to hook and handle the event:

  private void ThisAddIn_Startup(
    object sender, System.EventArgs e)
  {
    userControl = new SalesToolsUserControl();
    ...
    ApplicationEvents4_DocumentBeforeSaveEventHandler
      handler = new ApplicationEvents4_
        DocumentBeforeSaveEventHandler(
        Application_DocumentBeforeSave);
    this.Application.DocumentBeforeSave += handler;
  }
  
  private void Application_DocumentBeforeSave(
      Microsoft.Office.Interop.Word.Document Doc,
      ref bool SaveAsUI, ref bool Cancel)
  {
    // the document is about to be saved
    if (!SaveAsUI)
    {
      // not saving with a new name
      // or for the first time
      userControl.PublishSaveToBlog(Doc.FullName);
    }
  }

Once the event handler has been assigned to the event, the Application_DocumentBeforeSave method is called each time the user saves the document. Notice how a presentation of the active document is passed to the event handler as the Doc parameter. This object contains a property called FullName, which is used when creating the blog entry text. The code in the user control's PublishSaveToBlog method looks like the following:

  public void PublishSaveToBlog(string filename)
  {
    if (publishToBlogCheckBox.Checked)
    {
      BloggerClient.SubmitBlogPost("Offer updated",
        "The offer \"" + filename +
        "\" has been updated.");
      MessageBox.Show("Blog entry published!");
    }
  }

The end result is a blog entry similar to the one in Figure 9.


Figure 9. A submitted blog entry by the sample application.

Conclusion

In this article, you saw how you can use Visual Studio 2008 to create add-in applications for the Office 2007 suite of products, and more specifically Word 2007. Visual Studio 2008 provides ready-made templates for developing such add- ins, and this gives you a head start. Creating for example a custom task panel is easy as adding a new user control to the project, and then registering it with Word.

The sample application (Figure 10) showed you how you can easily extend Word to transform it to a powerful application platform: you can access SQL databases, call web services, and even associate your code with events in Word. From this perspective, the rule of thumb is that if you can do it from .NET code, you can also do it from an Office add-in.



Click here for larger image

Figure 10. The sample application running inside Word 2007.

If you are looking to build your custom solutions to help businesses run more efficiently, think about whether you could integrate the needed functionality into Office applications like Word, Excel, PowerPoint or Outlook. The possibilities in both business and personal settings are many. And once Visual Studio 2010 and Office 2010 become available, the story will get even better. In the mean time, let's empower the office!

Resource Links

Office Development with Visual Studio
Office Developer Center
Word 2007 Developer Reference
Word Object Model Reference
Google Data APIs Overview

About the Author

Jani Järvinen is a software development trainer and consultant in Finland. He is a Microsoft C# MVP and a frequent author and has published three books about software development. He is the group leader of a Finnish software development expert group at ITpro.fi and a board member of the Finnish Visual Studio Team System User Group. His blog can be found at http://www .saunalahti.fi/janij/. You can send him mail by clicking on his name at the top of the article.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date