Вы находитесь на странице: 1из 11

How to make smart tag using c#????

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.
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 Offices smart tag, which probably looks for the phone number in Outlook or adds it
into your address book (I couldnt get Microsofts 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 tags
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 well 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:


Copy Code

sn k SmartTagLib.snk
3. Here you could also create a strong name for your final .dll file:

Copy Code

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:

Copy Code

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

Copy Code

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
Microsofts website

ProgID is the programmatic identifier of the recognizer interface. It can be implemented

like this:

Copy Code

public string ProgId

return "SimpleTerm.SmartTagRecognizer";

Name is a short title that reflects what the recognizer does. This is what appears in the
Smart Tag Menu

Copy Code

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


Copy Code

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

Copy Code

public int SmartTagCount

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.

Copy Code

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.

SmartTagNames 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

Copy Code

public string get_SmartTagName(int smartTagID)

if(smartTagID == 1)
return ("schemas-fourth-com/fourthcoffee#flavor");
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


IF_TYPE_SINGLE_WD applies to text being passed to the recognizer a single word at a


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
o smartTagName is a smart tag type string, in the form of
o start is an integer (1- based) which specifies the start position of the recognized
smart tag in a recognized text
o length is a count of the number of characters that the smart tag will span
o properties is the ISmartTagProperties object previously obtained from
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 ISmartTagRecognizersProgID

Copy Code

public string ProgId

return "SimpleTerm.SmartTagAction";

Name is a short title of what the action does (similar to ISmartTagRecognizers)

Desc is a substantive description of what the action does (similar to


SmartTagCount specifies the number of smart tag types that the recognizer supports
(similar to ISmartTagRecognizers)

SmartTagNames 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 ISmartTagRecognizers)

SmartTagCaption is a caption for a smart tag type for use in the menu for the Smart Tag

Copy Code

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

Copy Code

public int get_VerbCount(string smartTagName)


if (smartTagName == "schemas-fourth-" +
return 1;
return 0;
smartTagName is a smart tag type string in the form of namespaceURI#tagname

VerbID is a unique integer identifier for a verb


Copy Code

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

Copy Code

public string get_VerbCaptionFromID(int verbID,

string applicationName, int localeID)
if(verbID == 1)
return ("View Fourth Coffee product" +
" information");
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

Copy Code

public string get_VerbNameFromID(int verbID)

case 1:
return "viewProductInfo";
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

Copy Code

[assembly: AssemblyKeyFile()]


Copy Code

[assembly: AssemblyKeyFile(C:\\SimpleTerm.snk)]
This uses the key you created in earlier. The name and location of the key may be whatever you
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:

Copy Code

gacutil /i SimpleTerm.dll
(replace SimpleTerm with your librarys 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 classs
CLSID. For each class, copy the CLSID and insert the following right above your class

Copy Code

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:
Copy Code
+ "-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:
Copy Code
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
Copy Code
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 doesnt 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.