mart tags were first introduced in Microsoft® Office XP as an integrated way to enable users to dynamically present additional information in their documents. For general users of Office, smart tags are a way to boost productivity by having actions linked to keywords. For corporate users, smart tags are used to link users to internal resources based on the type of data they view or input into Office applications. A good example is linking a purchase order number in an Excel spreadsheet to detailed information about the sale from a source on the company intranet. For developers, smart tags represent a new way to link information-driven services into the applications that clients spend most of their time using.
I polled developers in my community and found that most of them recognized the benefits of smart tags but had not yet taken steps to develop them or to use the Microsoft .NET Framework to do so. While many developers are excited about the prospect of building managed smart tags, developing smart tags using .NET has not received the attention it deserves.
In this article I'll demonstrate how to develop smart tags. I'll cover topics such as using the Microsoft Office Smart Tag List (MOSTL) XML schema to develop smart tags quickly as well as using the .NET Framework to create more advanced, managed smart tags for Office 2003 and Office XP. Then I'll talk about how you can deploy these features in your organization.
Smart tags came onto the scene in Office XP with full support in Word, Excel, and Microsoft Outlook® (when Word is used as the e-mail editor, which is the default). Microsoft Internet Explorer 5.0 and above support smart tags in a manner that's different from Office applications. Text is not recognized by smart tags automatically in these versions of Internet Explorer; however, custom HTML tags can be added to the HTML source file to enable recognition of text for which you want to have a smart tag action. In this first iteration, smart tags for Office XP were developed using the Microsoft Smart Tag 1.0 Type Library.
The simplicity of smart tags is what makes them so powerful. The smart tag must first recognize data as matching some important criteria and should then present the user with a menu list of actions that pertain to that data. When the user makes a selection, the appropriate action is taken. Two COM classes comprise a smart tag. A recognizer class is responsible for matching data passed by a smart tag-enabled application; an action class tells the application the menu items to display and executes an action when the application signals the action to be taken. The general interaction between the application and these classes is shown in Figure 1.
Based on customer feedback Microsoft made enhancements to smart tags with the release of Office 2003. The number of applications that support smart tags has been expanded to include Microsoft PowerPoint® and Microsoft Access. Besides broader application support, the next iterations of smart tags include some better usability options. In Office XP, smart tags supported only one level of menus when displayed, but now cascading menus are included to group actions within the smart tag menu. The ability to control the period of time that smart tags are active, and allowing users to disable them from a single configuration window are also included in Office 2003. Another feature that developers have asked for is the ability to know what application is calling the smart tag. This enables you to handle recognition and actions one way if the request comes from Word and another if it comes from Excel. For a complete list of new smart tag features in Office 2003, go to What's New with Smart Tags in Office 2003.
Microsoft Smart Tags 2.0 Type Library, which is used to develop smart tags for Office 2003, is completely backward compatible with Office XP. All features that existed in Office XP will work with smart tags developed using the new type library, which is very nice for organizations that run both Office XP and Office 2003.
Simple smart tags that come to mind involve recognizing a word and then linking that word to a Web site. Building this type of smart tag is as easy as constructing an XML file. In Office XP and Office 2003 there is a library named MOFL.dll (C:\Program Files\Common Files\Microsoft Shared\Smart Tag\MOFL.dll) that allows developers to build XML files that conform to the MOSTL schema to build tags with no coding necessary.
The MOSTL schema is used when you want to build smart tags where well-defined words or patterns are recognized and where relatively simple actions are executed once recognition occurs. A new feature in Office 2003 allows developers to use regular expressions to recognize a pattern instead of just a list of terms. For example, you can write a smart tag that can recognize an IP address and develop an action that will go to a Web site listing who owns that IP address. While this may not be practical for a business user, it does illustrate the power of MOSTL combined with regular expressions. This type of pattern recognition can be used in most businesses as unique formatted codes are commonly used for order numbers, tracking numbers, and other identifiers. The MOSTL XML that performs IP address recognition and action is shown in Figure 2.
XML that is produced for a smart tag must strictly conform to the MOSTL schema and must be a valid XML document. This means that all characters within XML must be properly escaped. The beginning of the MOSTL schema deals with setting up the smart tag so that it is recognized as a valid smart tag, setting the locale, and creating the ability to update the smart tag from a Web site at some frequency. The most important XML tags create the regular expression to be recognized and also the action that is to be taken when a user clicks on an action in the smart tag. In this case, when an IP address is recognized and the user clicks on the "Find WhoIs for IP" action in the smart tag, they are taken to the WhoIs registry for that particular IP address, as shown in Figure 3.
Using the MOSTL XML schema is a fast way to create smart tags. Deploying a new smart tag involves copying the XML file to the location where Office is installed. By default, copying the file to C:\Program Files\Common Files\Microsoft Shared\Smart Tag\LISTS or a subdirectory for a specific locale will make it available to a user. This can be done using an installation application, group policy, or through a software update service such as Microsoft System Management Service.
Oftentimes, it is not quite so easy to link recognized data to the appropriate action so a developer might need to add more programming logic than the MOSTL schema affords. As mentioned earlier, most businesses use unique identifiers for purchase orders, tracking shipments, or products for sale. More often than not, linking these identifiers to meaningful information involves deriving information from multiple sources, and to be more valuable, aggregating the data for the user. A user with a sales order identifier can quickly see the customer, price paid, shipping information, and purchase history without ever having to leave Office. In cases like this, it is necessary to build a library that implements the interfaces required to create a smart tag. Creating a simple smart tag involves implementing defined interfaces and, as with any software project, gets more complicated as more logic is needed to perform advanced functions. Building a managed smart tag allows developers to take advantage of all the features of the .NET Framework that they have been accustomed to.
Before creating a smart tag library, I would like to describe the functionality in my smart tag library example. Being a fan of major league baseball, it would be helpful to recognize terms that relate to teams. Once these terms are recognized, I can link them to various Web sites to show team standing, averages, and other information that a baseball fan might want to see. This smart tag will have to have some internal logic to determine the correct team to link to. For instance, if I match the word "Sox" in the smart tag, then I may have to present the user with choices to the Web site for the Chicago White Sox or the Boston Red Sox.
This major league baseball smart tag will be written using Visual Studio® .NET 2003. The first step to building a managed smart tag is to create a new Class Library project and add a reference to the COM Microsoft Smart Tags 2.0 Type Library, shown in Figure 4.
Adding this reference allows smart tags to be created for both Office 2003 and Office XP. Referencing this library automatically wraps the COM library for use by the .NET Framework without requiring the developer to do any more work. The library that will be produced needs to be registered for COM Interoperability, so doing this within Visual Studio .NET will assist with debugging and deployment once the library is produced.
The two aforementioned classes that are required for the smart tag are the recognizer class, responsible for recognizing text or patterns that exist within applications that support smart tags, and the action class, which determines the menus that are shown to the user and the appropriate operation that corresponds with a menu item. I will first explore how to develop a recognizer class and then build the action class.
A recognizer class interfaces with the smart tag infrastructure using COM, so it is necessary to add the System.Runtime.InteropServices namespace to include the necessary attributes for COM integration with .NET-based applications. The Microsoft.Office.Interop.SmartTag namespace is also imported so that my Msdn.MlbSmartTag.Recognizer class can easily implement the appropriate interfaces, as shown here:
using System; using System.Runtime.InteropServices; using Microsoft.Office.Interop.SmartTag; namespace Msdn.MlbSmartTag { [ProgId("MlbSmartTag.Recognizer")] [GuidAttribute("90D62E8D-79E3-4197-907F-BF3EC133698D")] [ComVisible(true)] public class Recognizer : ISmartTagRecognizer2, ISmartTagRecognizer ...
There are three important attributes that decorate my Recognizer class. The ProgId attribute allows you to specify the programmatic identifier that can be used when the class is registered with COM. More important, though, is GuidAttribute, which forms a unique class ID (CLSID) for the class. When deploying the library, it is possible to use either ProgId or the CLSID to register the interface, but it's recommended that you use the CLSID to avoid a problem in Office XP where the status flag does not update when registering the interface using the ProgId. The ComVisible attribute is added to the class to ensure that it can be seen as a type in COM.
A recognizer class must implement the ISmartTagRecognizer2 and ISmartTagRecognizer interfaces. Visual Studio .NET will include the stubs for implementing the necessary interfaces, which makes it very easy to fill in the necessary logic to complete the recognizer class.
Figure 5 shows a complete list of the properties and methods to implement the interfaces for a valid recognizer. The SmartTagName property is used to uniquely identify the recognizer, as well as serving as the action key when text is recognized and sent to the corresponding action class. The SmartTagName is formed by using a namespace URI, and then adding the smart tag name separated by a pound sign. In this example the SmartTagName is urn:schemas-microsoft-com:msdnmag#mlb. It is important that this name does not conflict with any other SmartTag name that is deployed within the same environment. This name is also very important when building an action class since the smart tag name serves at the glue that binds the recognizer to the action. These names must be the same; otherwise the two classes will not be properly linked together.
It is important to remember that all COM-accessible .NET classes must provide a default constructor; that is, a constructor that requires no parameters. COM object creation functions do not pass parameters to the objects that they create so you need to ensure that the default constructor is present.
The SmartTagInitialize method is used to perform any initialization necessary when the smart tag recognizer is loaded. In the example, a list of team names are initialized into an array and that will serve as the terms that should be recognized. It should be mentioned that there are many other ways to recognize terms other than a simple list of tokens. Regular expressions are typically used to match patterns such as unique identifiers, while programming logic can be used to retrieve data or determine other match criteria. A good example of this is the Person Name Smart Tag that is included with Office. This smart tag retrieves a list of names from Outlook Contacts for recognition and allows the user to quickly send an e-mail, schedule an appointment, or see if that user is currently online. By performing this sort of setup and information retrieval in SmartTagInitialize, performance of the smart tag recognizer can be improved, since it can access the cached data rather than having to query for it on every recognition request.
The Recognize2 method (see Figure 6) is where the bulk of the responsibility exists for this class. The calling app passes to this method the text to be recognized, the locale, and type of data where the text was found in the app. The data type is set based on the text's surrounding context. The type would be IF_TYPE_CELL if it is found within a cell in Excel, and IF_TYPE_PARA if it is within a paragraph in Word. Some new parameters have also been added that did not exist in the original Recognize method. The calling app name allows a recognizer to perform alternate recognition based on the application, and a tokenized list of text items has been added to assist in developing match algorithms.
The Recognize2 method loops through all of the tokenized text passed to it by the calling application to try to find a match. If a match is found, a smart tag property bag is created to let you add more properties for the text that is matched. The RecognizerSite2 is responsible for interfacing with the calling app. The CommitSmartTag2 method passes the property bag and the location where the recognition occurred within the app. A call to this method causes the app to call the corresponding Action class along with the property bag to display the menu that lists possible actions.
Building my Msdn.MlbSmartTag.Action class is similar to building my Recognizer class. Figure 7 shows the most important properties and methods needed to build the Action class. The same namespaces are necessary to make the class accessible to COM and to use the smart tag interfaces. It is important to note that the ProgId and GuidAttribute should not be the same as the values in my Recognizer class (they are, after all, different COM classes), so it is necessary to create a new unique identifier that will be the CLSID for the Action class.
The Action class implements two interfaces from the Smart Tag 2.0 Type library: ISmartTagAction2 and ISmartTagAction. As with a recognizer class, all the properties and methods are necessary and Visual Studio .NET will generate stubs when adding the interfaces to the class declaration, as shown here:
using System; using System.Runtime.InteropServices; using Microsoft.Office.Interop.SmartTag; namespace Msdn.MlbSmartTag { [ProgId("MlbSmartTag.Action")] [GuidAttribute("63CB4201-3387-47c3-B0B2-0CCF56BB892D")] [ComVisible(true)] public class Action : ISmartTagAction2, ISmartTagAction ...
Figure 8 lists the properties and methods used by an Action class. Some properties are the same as those in the recognizer class but there are a few that deserve more attention. As I mentioned in the recognizer discussion, the SmartTagName property value must be the same in an Action class as it is in the corresponding recognizer so that the calling application can forward the request to the appropriate action handler.
The ShowSmartTagIndicator property is used to determine whether the underline indicator should be shown in order to signal to the user that the smart tag has been recognized and has action(s) associated with it. Typically, this property is always set to true, but based on the calling application or locale, it might be set to not show the indicator.
The VerbCount property is set to the maximum number of actions that the smart tag will display. In the example, a simple check is made to make sure that the correct smart tag is calling this property and then the value 4 is returned because the Smart Tag Action menu has four possible actions.
The VerbCaptionFormID2 property does a substantial amount of work for an action class. Based on the value set in the VerbCount property, this property is called repeatedly, each time with a different VerbID. It is responsible for creating the text that will de displayed in the Smart Tag Action menu. Cascading menus are a new feature in Office 2003. Using the "///" delimiter in the text that is returned by the property will apportion the text into submenus.
The first time the VerbCaptionFromID2 property is called, the value of VerbID will be 1 and the appropriate case statement is called. It is important to note that if you are using the VerbIndex as the VerbID (as in the example), the beginning index for VerbIndex is 1 rather than 0. This is something that can sometimes cause issues for those accustomed to doing development primarily with the .NET Framework. Custom logic is embedded in this property to handle the case where the word "Sox" is recognized. This is because we do not know if the user wanted to match the Boston Red Sox or the Chicago White Sox.
The IsCaptionDynamic property comes into play when the menu that is displayed to the user changes because of some value. If the menus for the action do not change, then this property should be set to false. For this example, we display a different menu based on what has been recognized so this property is set to true. These dynamic menus are one of the reasons why this smart tag is being built as a library rather than using the MOSTL schema.
The capstone to a smart tag is when a user clicks on a menu item to invoke an action. This is handled by the InvokeVerb2 method and is where developers can provide the horsepower for doing interesting things. The VerbID, application name, property bag, and recognized text are passed to this method. New to the InvokeVerb2 method is the locale so that developers can more easily build multilingual applications.
The example InvokeVerb2 is relatively straightforward and serves as a good example. Based on the menu item that the user selected, a browser opens the appropriate Web page. A user who types in "Cubs" or "Chicago Cubs" can navigate quickly to their stats. (If they are a Cubs fan like me then they will no doubt be disappointed—a common theme for us Cubs fans.)
There are countless other actions that can be taken when a user clicks a smart tag action. Using the .NET Framework to create the smart tag increases the possibilities by allowing you to do virtually anything that you can already do in .NET. This includes calling Web services, querying a database, and finding other interesting ways to add value to the data in Office documents.
One other feature of Office 2003 that is complementary to smart tags is the Office Research pane. The Research pane gives developers a place to display information to users without having to leave Office. Smart tags offer a nice link to notify users that they can view more information in the Research pane. For further information, see John Durant's article on storing and searching instant messages using the Research pane in Research Services in this issue of MSDN Magazine.
There have been some tools released recently that help developers debug and test smart tags without having to test directly within Office applications. The first utility, called the Smart Tag Explorer, enables developers to view all of the smart tag recognizers and actions that are configured on the local system. This is especially useful for ensuring that registration has completed successfully and that the smart tags are enabled on the system. It also shows which applications are configured to run the smart tags along with other settings, such as where to check for updates and the color of the smart tag indicator.
Another priceless utility is the Smart Tag Recognize Tester. This utility can be run from the Smart Tag Explorer and is used to test the recognition functionality. This utility is a time saver when the recognition logic is complicated and you want to quickly test a variety of data to be recognized. Both of these utilities are managed applications, so it is very easy to attach to them with a debugger in order to quickly step through the code to debug or test the smart tag. It's easy to see how the interface for the Smart Tag Recognize Tester, shown in Figure 9, can be helpful for debugging and testing by indicating the text and offsets of the recognition. These tools are available for download at Introduction to the Smart Tag Explorer and Smart Tag Recognize Tester.
Now that you have developed the functionality of the smart tag, it is just as important to get it in the hands of the users who need it. Deploying a smart tag that has been developed using the MOSTL schema involves copying the XML file to all the machines that need the smart tag. MOSTL also lets you set the frequency and location where updates can be downloaded from a Web site.
Deploying smart tags libraries is not as simple because the library must be registered and Windows registry keys must be created to allow the application to know that the smart tag exists. Creating a managed smart tag library provides the ability to modify the registry using the ComRegisterFunctionAttribute when the library is registered using the Register Assembly (regasm.exe) app.
The are only two registry keys that are needed to allow the smart tag to run: one for the recognizer (HKEY_CURRENT_USER\Software\Microsoft\Office\ Common\ Smart Tag\Recognizers\{CLSID}) and one for the action (HKEY_CURRENT_USER\Software\Microsoft\Office\ Common\Smart Tag\Actions\{CLSID}). The unique identifier created for each class is placed into the appropriate sub key. The code in Figure 10 demonstrates how to ensure that these correct keys are placed in the registry for the recognizer class when the library is registered. It also shows the UnregisterFunction for when the library is unregistered.
Having the registry keys applied when the library is registered simplifies deployment. Copying the library to the clients and registering it can be accomplished in a variety of ways. The first is to build an installation for the smart tag library and allow users to install it themselves. Other ways include deploying the library via group policy or other software update applications that exist in the environment to which you are deploying.
When creating a smart tag developed with the .NET Framework in Office XP, the library was subject to Office security checks based on a digital signature. Unfortunately, the .NET runtime engine (Mscoree.dll) is not digitally signed for Office. This meant that it was possible for users to see a macro security dialog box when using smart tags. The workaround for Office XP was to develop an unmanaged shim to call the .NET component.
In Office 2003, it is no longer necessary to develop an unmanaged shim because Office 2003 allows smart tags and other managed add-ins to be subject to the .NET security policy instead of to the Office security checks. The Visual Studio Tools for Office loader, which is included with Office 2003, loads the managed smart tag and is subject to Office security checks instead of the managed code—another good reason to start building managed smart tags.
There are many great uses for smart tags, and the tags are easily built using the MOSTL schema. Using the .NET Framework to build smart tags makes it easier to link Office users to external data quickly and intuitively. Likewise, building managed smart tags makes it simpler to deploy smart tags to users who need them.