Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to make a Smart Tag using C#

0.00/5 (No votes)
8 Sep 2003 1  
This article is a tutorial on the creation of a simple smart tag

Introduction

This document contains information on the creation of Smart Tags for Microsoft Office. This focuses on the ISmartTagRecognizer and ISmartTagAction interfaces that work with Office XP and 2003. Their newer counterparts, ISmartTagRecognizer2 and ISmartTagAction2, will not be discussed here because although Microsoft has published information about these interfaces and their new features (cascading menus, dynamic captions, backwards compatibility, etc), they have not yet published much information on their actual implementation***. As an example to go along with my explanation, I will use the creation of a simple smart tag (named SimpleTerm) that recognizes different coffee flavors for a make believe company.

***EDIT: Refer to John Liu's message at the bottom for more info on Smart Tags 2

Notes on Smart Tags

If you try to create two smart tags that recognize the same text, the application will arbitrarily pick one of the two smart tags to run. You could also disable the smart tag that you do not wish to run in the application settings. One smart tag I have made was to recognize phone numbers and then give the user options of formatting the number. This smart tag was chosen over Microsoft Office�s smart tag, which probably looks for the phone number in Outlook or adds it into your address book (I couldn�t get Microsoft�s version to recognize any phone numbers).

If you wish to put smart tags into a document and send it to someone else, you can embed them in the file. This puts information into the document that the smart tag exists along with a URL where the user may download the smart tag (if the URL was provided by the smart tag�s programmer) The user you send the file to will then be notified that the smart tags exist and will be prompted to download the whole smart tag from that URL. If you receive a document and wish to scan it to see if the smart tags on your computer recognize any text, you can do so in the smart tag options of your application.

Smart Tags do not work in IE6.

Making the Smart Tag

Create the Resource Libraries and Install Them in the Global Assembly Cache

For security reasons, every library you use must have a strong name and must be registered in the global assembly cache (even your final .dll smart tag file). Since the Smart Tag Library lacks a strong name, we must create a strong-named wrapper library for it. First we�ll create a strong name for this library and then install it into the GAC.

  1. Open a Visual Studio Command Prompt (Start -> Programs -> Visual Studio .NET -> Visual Studio .NET Tools -> Visual Studio .NET 2003 Command Prompt)
  2. Create a strong name by issuing the command:
    sn �k SmartTagLib.snk
  3. Here you could also create a strong name for your final .dll file:
    sn �k SimpleTerm.snk
  4. Next move to the directory C:\Program Files\Common Files\Microsoft Shared\Smart Tag and type the following to create a strong named wrapper for the Strong Tag Library:
    tlbimp mstag.tlb /keyfile:c:\SmartTagLib.snk /out:c:\SmartTagLib.dll

    Notice that the library was originally mstag.tlb and now a new library named SmartTagLib.dll is located at the root directory of drive C. The path to SmartTagLib.snk may differ if you created it in another folder.

  5. Issue the following command to install this DLL into the GAC
    gacutil /i c:\SmartTagLib.dll
  6. Create strong names and install other libraries that you will be using as resources

Create and Install the Smart Tag DLL

Open Visual Studio .NET and create a new Visual C# Class Library. I named my project SimpleTerm and created two classes, SmartTagRecognizer (to recognize the Smart Tag) and SmartTagAction (to perform an action on the Smart Tag). In the Solution Explorer, Right Click on References and choose to Add Reference. Click on Browse and locate all the strong named libraries that you created and will be using and add them.

Add using SmartTagLib to the top of your classes along with the names of other libraries you are using Create your Recognizer Class, implementing SmartTagLib.ISmartTagRecognizer. ISmartTagRecognizer has 6 properties (ProgID, Name, Desc, SmartTagCount, SmartTagDownloadURL, SmartTagName) and one method (Recognize()). Here is a description of the ISmartTagRecognizer interface along with examples from my SimpleTerm project. The Smart Tag SDK v1.1 also has a description of the Smart Tag interfaces and is downloadable from Microsoft�s website

  • ProgID is the programmatic identifier of the recognizer interface. It can be implemented like this:

    public string ProgId
    {
       get
       {
          return "SimpleTerm.SmartTagRecognizer";
       }
    }
  • Name is a short title that reflects what the recognizer does. This is what appears in the Smart Tag Menu
    public string get_Name(int localeID)
    {
       return "My Simple Term Recognizer";
    }
    localeID is the per-paragraph language identifier for the string being passed in. It is always equal to the locale identifier or language of the host application. So if a host application calls ISmartTagRecognizer::get_Name with a localeID that represents English, it is asking the ISmartTagRecognizer to provide the recognizer name in English. Applications that do not have a notion of a per-item localeID will pass in 0 (zero).
  • Desc is a substantive description of what the recognizer does
    public string get_Desc(int localeID)
    {
       return "Simple Term Recognizer recognizes Fourth Coffee flavors"
          + " in documents";
    }
    localeID is the per-paragraph language identifier for the string being passed in
  • SmartTagCount specifies the number of smart tag types that the recognizer supports
    public int SmartTagCount
    {
       get
       {
          return 1;
       }
    }
    Note that based on this count, implementing applications will call SmartTagDownloadURL and SmartTagName a corresponding number of times to find out more information about the recognizer's supported smart tags

  • SmartTagDownloadURL is a URL that gets embedded in documents to allow users to download actions if they do not already have them installed for that particular smart tag. There is an option in the Smart Tag Actions button called "Check for New Actions�" to navigate to the download URL site so that recipients of documents with smart tags can easily download the actions for those smart tags.
    public string get_SmartTagDownloadURL(int smartTagID)
    {
       return "http://www.mydownloadurl.com";
    }
    smartTagID is an enumerated integer that corresponds to SmartTagCount. The count will range from 1 to SmartTagCount. Upon initialization, if a recognizer returns 3 from SmartTagCount, it will subsequently receive 3 calls to SmartTagDownloadURL, with SmartTagID ranging from 1 to 3. If this recognizer does not want to supply a SmartTagDownloadURL, it should return "" or Null.

    This property is useful in the following example:

    Person A creates an e-mail message with several CameraName smart tags in it and sends it to person B. Ordinarily, because person B does not have the CameraName DLL installed on their machine, the annotated data cannot be seen. Smart-tagging the e-mail message would have been a pretty useless exercise on the part of person A. But because the CameraName recognizer embeds a download URL, at the very least, person B can take advantage of the fact that there are CameraName smart tags in the documents by going to the Web page to download the actions and install the CameraName recognizer/action smart tag DLL.

  • SmartTagName�s are the unique identifiers of smart tag types that the recognizer supports. The strings that are returned by this method must conform to the "namespaceURI#tagname" key style that defines a smart tag

    public string get_SmartTagName(int smartTagID)
    {
       if(smartTagID == 1)
          return ("schemas-fourth-com/fourthcoffee#flavor");
       else
          return null;
    }
  • Recognize() This is the main method where all the action happens. Text is recognized as a smart tag type and committed for the Action class to handle.

public void Recognize(string text, SmartTagLib.IF_TYPE dataType, int localeID, SmartTagLib.ISmartTagRecognizerSite recognizerSite)

  • text is the string that is searched for smart tags. dataType an enumerator that describes the type of text being passed to the recognizer
  • typedef enum { IF_TYPE_CHAR = 0x000000001, IF_TYPE_SINGLE_WD = 0x00000002, IF_TYPE_REGEXP = 0x00000004, IF_TYPE_PARA = 0x00000008, IF_TYPE_CELL = 0x00000010} IF_TYPE
  • IF_TYPE_CHAR applies to text being passed to the recognizer a single character at a time.
  • IF_TYPE_SINGLE_WD applies to text being passed to the recognizer a single word at a time.
  • IF_TYPE_REGEXP applies to text being passed to the recognizer after filtering using pattern matching.
  • IF_TYPE_PARA applies to text being passed to the recognizer a paragraph at a time.
  • IF_TYPE_CELL applies to text being passed to the recognizer a cell at a time (as in Excel, for example).

Note that presently onlyIF_TYPE_PARA and IF_TYPE_CELL are used (according to Smart Tag SDK 1.1, which will be outdated when the new Smart Tag SDK 2.0 is released). localeID is the per-paragraph language identifier for the string being passed in

RecognizerSite is the interface that host applications expose so that recognizers can get property bags and commit smart tags. RecognizerSite's GetNewPropertyBag() method returns a property bag that can hold key/value pairs to be passed on to the action class once the smart tag has been committed. Its other method, CommitSmartTag(), tells the ISmartRecognizerSite interface to add a new smart tag based on the passed in text. Its syntax is as follows:

void CommitSmartTag(string smartTagName, int start, int length, ISmartTagProperties Properties)

    • smartTagName is a smart tag type string, in the form of namespaceURI#localname
    • start is an integer (1- based) which specifies the start position of the recognized smart tag in a recognized text
    • length is a count of the number of characters that the smart tag will span
    • properties is the ISmartTagProperties object previously obtained from GetNewPropertyBag()

The ISmartTagProperties interface is what is used as the property bag. Its properties are : -

Count: an integer of how many properties are stored, KeyFromIndex: returns a key string corresponding to a passed index integer, Read: returns a value string corresponding to the passed key string, and ValueFromIndex: returns a value string corresponding to a passed index integer. It has one method, Write(string key, string value) to write a key/value pair to it

Now create your Action Class, implementing SmartTagLib.ISmartTagAction. ISmartTagAction has 10 properties (ProgID, Name, Desc, SmartTagCount, SmartTagName, SmartTagCaption, VerbCount, VerbID, VerbCaptionFromID, VerbNameFromID) and one method (Invokeverb()).

  • ProgID is the programmatic identifier of the action interface. Its implementation is just like ISmartTagRecognizer�sProgID

    public string ProgId
    {
       get
       {
          return "SimpleTerm.SmartTagAction";
       }
    }
  • Name is a short title of what the action does (similar to ISmartTagRecognizer�s)

  • Desc is a substantive description of what the action does (similar to ISmartTagRecognizer�s)

  • SmartTagCount specifies the number of smart tag types that the recognizer supports (similar to ISmartTagRecognizer�s)

  • SmartTagName�s are the unique identifiers of smart tag types that the dll supports. The strings that are returned by this method must conform to the "namespaceURI#tagname" key style that defines a smart tag (similar to ISmartTagRecognizer�s)

  • SmartTagCaption is a caption for a smart tag type for use in the menu for the Smart Tag
    public string get_SmartTagCaption(int smartTagID, 
    int localeID)
    {
       return "Fourth Coffee";
    }
    smartTagID is an enumerated integer that corresponds to smartTagCount. Its value ranges from 1 to the value of smartTagCount. This method is called SmartTagCount times to retrieve names for each smart tag type. localeID is the per-paragraph language identifier for the string being passed in

  • VerbCount is the total number of verbs, or actions, that are supported by this DLL for a given smart tag type
    public int get_VerbCount(string smartTagName)
    {
       if (smartTagName == "schemas-fourth-" + 
          "com/fourthcoffee#flavor")
          return 1;
       else
          return 0;
    }
    smartTagName is a smart tag type string in the form of namespaceURI#tagname

  • VerbID is a unique integer identifier for a verb
    public int get_VerbID(string smartTagName, int verbIndex)
    {
       return verbIndex;
    }
    smartTagName is in the form of namespaceURI#tagname. verbIndex is a unique verb identifier. This mechanism is supplied so that DLLs can mix and match verbs for the various smart tag types they support. For example, a smart tag action DLL might support one verb for four smart tag types, or it might support four variants of one smart tag verb for a smart tag type.
  • VerbCaptionFromID is a caption for a verb that appears on the Smart Tag Menu
    public string get_VerbCaptionFromID(int verbID, 
    string applicationName, int localeID)
    {
       if(verbID == 1)
          return ("View Fourth Coffee product" +
             " information");
       else
          return null;
    }
    verbID is an unique integer identifier for the verb obtained earlier. applicationName is the ProgID of the calling application. A verb can customize its caption for the application. localeID is the language identifier that corresponds to the UI language of the calling application. A verb can customize its caption for this localeID, or return null or �� to specify that the verb does not work under the respective localeID

  • VerbNameFromID is a language-agnostic identifier string for a verb that is used internally in the application to represent the VerbID
    public string get_VerbNameFromID(int verbID)
    {
       switch(verbID)
       {
          case 1:
             return "viewProductInfo";
          default:
             return null;
       }
    }
    verbID is an integer previously specified with the VerbID method

  • InvokeVerb() invokes the appropriate verb when a user clicks on an action displayed in the smart tag UI that corresponds to the VerbCaptionFromID value.

 public void InvokeVerb(int verbID, string applicationName, Object target, SmartTagLib.ISmartTagProperties properties, string text, string xml)

VerbID is the unique ID of the verb to invoke. applicationName is a string that represents the name (ProgID) of the calling application. This is an object-model-agnostic way of getting the name of an application. It is also used to identify applications that do not support the passing in of a Target. target is a reference to the application-specific object that is responsible for calling the smart tag. In Excel, it is an Excel range object that points to the cell that the smart tag was attached to. In Word, it is a Word range object that wraps around the block of text that the smart tag refers to. However, note that this object may be any other kind of pointer to an object appropriate for the calling application. It could also be null. properties is the smart tag property bag. An action DLL can read, write, and modify these properties so that future action invocations can take advantage of this information. text is a read-only string that represents the text of the smart tag. For example, if a smart tag on a cell reads �MSFT�, text would equal �MSFT�. xml is a read only string that is an XML representation of the smart tag

After making these classes, a strong name key needs to be assigned to the project so the library will have strong name after its compiled. Open AssemblyInfo.cs and replace the line that reads

[assembly: AssemblyKeyFile(��)]
with
[assembly: AssemblyKeyFile(�C:\\SimpleTerm.snk�)]
This uses the key you created in earlier. The name and location of the key may be whatever you specified.

Now you need to tell Visual Studio .NET to register you DLL when you compile it. To do this go to your Project Properties, click on Configuration Properties -> Build and set Register for COM Interop to True.

Build the solution. Open a Visual Studio Command Prompt and go to the bin\Debug directory of your project. Install your DLL with the following command:

gacutil /i SimpleTerm.dll
(replace �SimpleTerm� with your library�s name)

If you compile your project multiple times, the classes� CLSIDs will keep changing, which could lead to errors. To prevent this, open regedit and go to HKEY_CLASSES_ROOT. In this registry you should be able to find two subkeys by the names of your classes given in the format library.class. For my example it is SimpleTerm.SmartTagAction and SimpleTerm.SmartTagRecognizer. As subkeys for both of these, you will find each class�s CLSID. For each class, copy the CLSID and insert the following right above your class declaration:

[System.Runtime.InteropServices.GuidAttribute(<CLSID>), 
System.Runtime.InteropServices.ProgIdAttribute()]
This will tell the compiler what to make your CLSID and your ProgID. For the SmartTagRecognizer class in our example the entry would look like:
[System.Runtime.InteropServices.GuidAttribute("69D56959-B1C2"
+ "-3987-80F2-845E73197626"), 
System.Runtime.InteropServices.ProgIdAttribute( "SimpleTerm"
+ ".SmartTagRecognizer")]
Once the CLSIDs are set, you need to insert them into a place in the registry where applications look for smart tag DLLs. Locate the following key in the registry:
HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Actions
Here you will find many subkeys with CLSID values. Add the CLSID of your Smart Tag Action class here. Add the CLSID of your Smart Tag Recognizer class to the subkeys of
HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Recognizers
Note that with the newer Smart Tags for Office 2003, CLSIDs can be entered in HKEY_LOCAL_MACHINE to install the smart tag for all users of a computer

.NET also has a problem with referencing your DLL from certain applications. This is because the applications find your DLL through another DLL called mscoree.dll. This is done for security reasons in .Net. If an application is unable to load mscoree.dll when it starts, your DLL will not be referenced either. To ensure that mscoree.dll can be located by the application you must edit registry keys via regedit. Go to HKEY_CLASSES_ROOT\CLSID and locate the CLSIDs of both of your classes. Both of these keys will have a subkey called InprocServer32 and this will have a default value of mscoree.dll. Change this value to C:/Windows/System32/mscoree.dll for both of your classes. With this full pathname, your application should be able to correctly locate mscoree.dll. If you cannot find your CLSID in the registry, see if restarting regedit helps.

Note: You will have to change this value every time you compile

Your Smart Tag should now be working. If it doesn�t seem to be loading, check your security settings. For Word, you can adjust your security settings by going to Tools -> Macro -> Security. On the Trusted Publishers tab, make sure you have the Trust all installed add-ins and templates box checked. If your smart tag is loading but not functioning properly, you can debug it through Visual Studio .NET by going to Project Properties -> Configuration Properties -> Debugging. Change the Debug Mode to Program and select your Start Application to be the .exe file of the application you wish to test your smart tag with. For example, if you are trying to make a smart tag for Word, you would put C:\Program Files\Microsoft Office\OFFICE11\WINWORD.EXE as your Start Application. If you are still having problems with your smart tag, refer to the FAQ of the Smart Tag SDK.

Additional References

All these contain information about the new Smart Tags API. The last link contains the most detailed information I�ve found about the actual methods, but I still found it lacking.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here