From the January 2002 issue of MSDN Magazine

MSDN Magazine

Office XP: Build a Custom DLL to Expose Your Objects and Services Through Smart Tag Technology

Paul Sanna
This article assumes you're familiar with Visual Basic, COM, and XML
Level of Difficulty     1   2   3 
Download the code for this article: SmartTag.exe (49KB)
Browse the code for this article at Code Center: Smart Tag DLL
SUMMARY Smart Tags is a new technology delivered with Office XP that makes it easy for users to complete common tasks on familiar and relevant data regardless of the application they are using. Microsoft provides tools to make it easy to roll out simple Smart Tag applications using XML as a backbone. The Smart Tag SDK provides the detail needed to build a COM automation server for Smart Tags in Visual Basic or Visual C++. This article brings the reader through the SDK to outline the process of building a Smart Tag DLL using the tag recognizer and the action provider to create customized user experiences.

S mart Tags is a new user-centric technology delivered to Windows® via Microsoft® Office XP. They provide common relevance, context, and automation to data, regardless of where the data is being used. Smart Tags recognize data and terms in Office applications and assign a type identifier to the recognized data. When a Smart Tag recognizes some data the user is working with, a menu appears containing options that are dictated by the type identifier. Smart Tags makes the application that the user is working with irrelevant while providing the tools for taking the most relevant action on the data in question.
      The use cases Microsoft employed to design Smart Tags are not complicated. Users typically perform the same kind of action on data no matter where that data is presented. Users send e-mail to individuals in their address book whether the person's name appears in a spreadsheet or an invoice written in Microsoft Word. Users check prices on parts listed in the parts list in Microsoft Excel or on a purchase order sent in Outlook®, and they launch a Web browser to retrieve information from the Web about topics relevant to projects they're working on. The goal of Smart Tags is to recognize frequently accessed data such as customer names, part numbers, and ZIP codes, and make it easy for users to perform actions on those pieces of data.
      There are several methods available for building custom Smart Tag solutions. Later in the article I'll mention a method that is based on XML and the Microsoft Smart Tag XML schema. The approach that offers the greatest flexibility is to build a Smart Tag automation server. In this article I will explain how to build a custom Smart Tag DLL with specialized term recognition and action provider handling.

Smart Tags Overview

      If you aren't familiar with how Smart Tags work from the user's perspective, you may want to spend a few minutes with Word or Excel 2002 to understand the Smart Tags functionality. In the meantime, let's look at a few scenarios in which Smart Tags streamline the process of working with data.
      For example, a distributor could provide a Smart Tag to check availability when encountering a part number on an Excel order form. The same user who takes advantage of that part number Smart Tag might have another Smart Tag installed which retrieves flight information when an airline and flight number is recognized in an Outlook-based document. The Smart Tag architecture provides the user with flexibility concerning which Smart Tags are used and to what level of granularity. Users can disable Smart Tags for entire categories such as the part number mentioned earlier, or they can disable the Smart Tag functionality associated with a particular piece of text or data in the host applications.
      Microsoft provides basic Smart Tag functionality out of the box with Office XP, including Smart Tags for working dates, times, and persons recently e-mailed from Outlook. Other Smart Tag functionality in Office XP includes recognizing and looking up certain technical terms on the MSDN® Online site. (Smart Tags are supported only in the Office XP versions of Word and Excel, and in Outlook when it is configured to use Word as its e-mail editor.)
      To create custom Smart Task solutions, Microsoft provides the Microsoft Office Smart Tag List (MOSTL) tool. This tool makes it easy for Office developers to build and update XML lists of terms to recognize. Using this tool to build and deploy Smart Tags, however, limits the actions available to users when data they have entered is recognized. The only action supported in applications built using the MOSTL tool is to connect to a URL and pass the recognized term. Nevertheless, a developer only needs experience with XML and XML schemas to successfully build a Smart Tag solution using MOSTL.

How Smart Tags Work

      Let's review the sequence of events that occur when Smart Tag functionality is used. To start, when a Smart Tag host application like Word or Excel launches, the application checks the Registry for registered Smart Tags at HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Recognizers. Specifically, the application looks for registered recognizers. A recognizer is a class that implements ISmartTagRecognizer. In Visual Basic®, a recognizer is registered when the Smart Tag DLL is compiled for the first time. The host application keeps a record of recognizers that were previously detected, and the application also tracks whether the user previously wanted to process the terms reflected in each recognizer (see Figure 1). If the user has deselected the recognizer, then most processing starts, although the Recognizer class is still initialized (I'll explain this later).

Figure 1 Recognizer List
Figure 1 Recognizer List

      As data is entered into the host application, the application passes the data to each of the registered recognizers, provided the user has not deselected them. Note that the collection of recognizers on a user's desktop may be a mix of the generic recognition provider that shipped with Office XP or it may be a custom Smart Tag DLL, such as the one I've developed in this article.
      Recognizer processing determines whether the text passed in matches any of the terms the recognizer knows about. This knowledge of the terms is gained either by compiling a static list of terms into the DLL or by creating the list dynamically, perhaps by accessing a dynamic data source, when the DLL is initialized. If the recognizer returns True, data about the recognized text is stored so it may be accessed by the action provider should the user want to take action on the data.
      With the Smart Tag indicator visible in the host application, a user will click on the icon to display the Smart Tag menu. The host application now checks for action providers in HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Actions. The action provider displays a menu. The user makes a choice from the menu, and then the code that supports the menu choice is fired.

Implementing the Recognizer

      To start implementing the recognizer, you must build a COM DLL. If you are using Visual Basic (as I did in the example project for this article), you build an ActiveX®-based DLL. The Smart Tag DLL that you build is an automation server. To expose the required interfaces to host applications, your project needs a reference to the Microsoft Smart Tags 1.0 type library (mstag.tlb). If you plan to use the techniques shown in the example project for accessing term data from XML, then your project should also include a reference to the Microsoft XML SDK, version 4.0 (see Figure 2).

Figure 2 Type Library References
Figure 2 Type Library References

      You can implement both the recognizer and action provider in one DLL or you can divide the work of the two into two different DLLs. In order to provide recognition services, the application must implement the ISmartTagRecognizer interface:

  Implements ISmartTagRecognizer

This interface is streamlined and easy to use. There are only six properties and one method to deal with. Once they are added to your project, you can start building the interfaces into your class.
      The Initialize function plays an important role in the services provided by a custom Smart Tag DLL. When a host application is launched, the Initialize function for your recognizer class is called first. There is no specific processing that you must build into this function, though it is likely you will want to do so.
      The Initialize function gives you the opportunity to collect and/or process any data your recognizer will need for recognizing terms. This function is probably the most natural location to place the code to access any data source from which you can build arrays of terms that should be recognized. In the example project, the Document Object Model (DOM) is used to access a page of XML that includes a list of terms to be recognized. The <PartNumber> element contains each of the part numbers this application needs recognized. DOM functions are used to retrieve those terms from specific elements, and an array containing those terms is built. Some error handling is added to stop recognizer processing if the application was unable to build the array containing the list of terms (see Figure 3).
      There may be one reason, though, to find another place for this type of processing. Users can choose on a recognizer-by-recognizer basis whether their host applications will recognize terms. However, recognizer DLLs are initialized even if a user chooses not to work with a specific Smart Tag. This means that the Initialize function is always called. So, if the code in your Initialize function will take a long time to process or will require significant resources, you may want to move the processing to another function in case the user chooses not to use your recognizer. If you decide to do this, you most likely will want to establish some sort of flag scheme so that processing occurs just once.
      Immediately after the Initialize method for the recognizer is fired, the Name property is interrogated. The Name property refers to the external identification for your recognizer. The text you supply for the Name property is the text that is displayed in the list of recognizers in the Smart Tag host application, so be sure the value you supply for this property is sufficiently descriptive. Like many of the other recognizer properties, the LocaleID is available to help you manage this property based on the locale/language of the host application. The ISmartTagRecognizer class also calls for you to supply a description of the recognizer with the Desc property, though it is not clear where this data is used.
      Continue your work by implementing the ProgID property. The ProgID naturally will take the format of projectname.classname. In the example application, the recognizer class is called Smart TagRecognizer; the action class is called Smart TagAction. You can implement the ProgID for both classes now, or you can do all of the work on the recognizer first and save the work on the action provider for later on in the process.
      Part of building your Smart Tag recognizer is implementing the SmartTagName property. This property shouldn't be confused with the Smart Tag's Name property, described earlier. The SmartTagName property is used to label each unique Smart Tag type. A Smart Tag type is a category of data you want Smart Tags to help recognize. For example, if you build a custom recognizer to make it easier for users to check prices on specific products, then the Smart Tag type would be "part number", or, to be syntactically correct, PartNumber. The SmartTagName property is interrogated as many times as the value of the SmartTagCount property, so your code must accommodate multiple calls to the property. This is relevant if your recognizer supports two Smart Tag types, like part number and customer number. The SmartTagID is passed to the property, so you can properly set the value of the SmartTagName. The SmartTagID is a unique index assigned to each Smart Tag type. Be sure to set the value of the SmartTagCount property to the number of Smart Tag types your recognizer will process.
      The value you supply for the SmartTagName property should be preceded by an XML namespace. This ensures that your Smart Tag type is unique, regardless of whether another recognizer by the same SmartTagName is registered on a user's desktop:

  schemas/msdn-mag#productnumber

      The ISmartTagRecognizer also allows the user to download Smart Tag Actions if they are not provided. You supply a URL to be associated with each Smart Tag type. Like the SmartTagName property, a call is made to set the SmartTagDownloadURL property from one time up to the value of SmartTagCount.
      The Recognize method is where the most important processing in the recognizer class occurs. This method gives you the flexibility to fully control the comparison of terms passed in from the host application to terms the DLL should recognize. Because you write the specific code that compares application data to DLL terms, the Recognize method can be lenient or strict, according to spec. By using further automation, the recognition processing can take context in the host application into account, such as the value of the cell above the cell being compared, or in the case of Word, other properties about the host document. The example application uses the InStr function, which is shown in Figure 4.
      The list of terms you provide to the recognizer can be built however you like in order to take advantage of the availability and format of the source terms. You can build a static list of terms that is compiled directly into the DLL, or you can build the list dynamically when the DLL is initialized, seeding the list by reaching into enterprise apps and databases whether directly or over the Web.
      The Recognize method has four parameters passed in. The first, text, is the data passed into the function by the host application. The DataType variable is used to determine the format of the value passed in. The Smart Tag SDK describes a number of possible formats, but the current release supports just two. When the host application is Excel, which passes in full-cell data only, the value of the DataType parameter is IF_TYPE_CELL. In the case of Word, the IF_TYPE_PARA is the only currently supported data type, which means Word only passes in text in paragraph format.
      The third parameter is the LocaleID, which again gives you the chance to manage processing if the Recognize function is based on language/locale.
      The fourth parameter passed into the Recognize function is a RecognizerSite object. This object helps manage the interface between the Smart Tag DLL and the specific instance in the host application of the text to be assigned the Smart Tag. When the code in the recognizer wants to apply a Smart Tag to recognized text in the host application, a call is made to the RecognizerSite object to create the new Smart Tag based on the found text, and a property bag is created to store information about the found text for use by the action provider. The Smart Tag graphic now appears with the recognized text.

Implementing the Action Provider

      The next step in building the Smart Tag DLL is to implement the action provider. To provide users with the option to take action on terms returned by the recognizer, you need to implement an action provider in your Smart Tag DLL. To do so, implement ISmartTagAction:

  Implements ISmartTagAction

      The plumbing work you completed for the Recognizer class is the same for the action provider. Like the Name, Desc, ProgID, SmartTagCount, and SmartTagName properties for the recognizer, you set the same properties for the action provider. Also, like recognizer policy, be sure to account for as many Smart Tag types when you set the value of the SmartTagName property as indicated in the value of the SmartTagCount property set for the action provider (see Figure 5).
      Next, use the SmartTagCaption to set the text that appears on the top of the Smart Tag menu. The menu appears when the user clicks on the Smart Tag indicator when the recognizer fires the Recognize method.
      The most important roles of the action provider are to build the Smart Tag menu and to house the code that runs when a user makes a selection from the menu. The VerbCount property determines, very simply, the number of options to appear on the Smart Tag menu. When this value is set, you can rely on the value of the VerbID variable, which is passed to all of the relevant properties, to help determine which menu option to work on. The VerbCount property is queried as many times as the value held in the SmartTagCount property. This makes sense considering your Smart Tag probably will present different menu options based on the type of Smart Tag recognized (customer number, part number, stock symbol, and so on) if you use more than one Smart Tag type in your project. One of the relevant properties where the VerbCount property is applied is VerbCaptionFromID, where the caption of specific menu choices is set, as you can see in Figure 6.
      The last major piece of code I'll review is the InvokeVerb method. This method is called when a user makes a selection from a Smart Tag menu. InvokeVerb gives you the opportunity to manage all of the processing that occurs when a user makes a selection. A number of useful parameters are passed into the method. As mentioned earlier, the VerbID is passed to help you determine which menu choice and action is being processed. The host's application name is also available via the ApplicationName string. As an example, if Excel were the host application, then the Application Name would be Excel.Application. This value can help the developer provide the appropriate application-specific automation.
      For example, if the purpose of the action is to retrieve a piece of data from another data source, then knowing the host application can help you when determining how to return the data. If the host app is Excel, the processing might return the value to an adjacent cell; if the host application is Word, the data might be returned to a specific browser favorite or to another open document.
      Another parameter available to the InvokeVerb method is the recognized text passed by the recognizer. This value is delivered through the Text parameter. It is likely that you will need this value to deliver the functionality designed into your application. As shown in Figure 7, the Text is passed to an ASP page to help return the product name, price, or availability.

Deploying the Smart Tag

      When the Smart Tag DLL has been compiled, tested, fixed, and recompiled, the DLL needs to be deployed. The procedures to deploy and register the Smart Tag DLL are simple. Keys for both the action provider and the recognizer should be added to the appropriate hives in the Registry. The Smart Tag SDK provides the details on manually registering these components and for creating installer packages, as well as downloadable Internet components.

Conclusion

      Building a Smart Tag DLL is not a sophisticated process. It may be more difficult to build the processing around retrieving a list of terms to recognize than to provide automation around the actions a user will want to take on the recognized term. The Smart Tag architecture provides you with all of the entry points and flexibility to completely customize the recognition and action processes. This flexibility is not available if the MOSTL tool is used, although using that approach may be simpler than building and deploying a custom component like a Smart Tag DLL. Evaluate both approaches to look at your current requirements, but also think about your future needs. Considering how easy it is to extend Smart Tag functionality using the SDK, your choice will probably be to take advantage of some of the techniques I've outlined in this article.

For related articles see:
Smart Tags Frequently Asked Questions
For background information see:
Smart Tag SDK
https://www.microsoft.com/Office/developer/platform/smartag.htm
https://msdn.microsoft.com/vbasic
Paul Sanna is the author of more than one dozen technology books, covering topics such as Visual Basic, Windows 2000, and Windows NT®. Paul is Vice President at a high-tech firm that provides wireless application platform and development tools.