SUMMARY
Smart Tags are a technology that was introduced with Office
XP that provides Office users more interactivity with the content of their
Office documents. A Smart Tag is an element of text in an Office document that
is recognized as having custom actions associated with it. An example of one of
these special elements of text might be an e-mail name that is typed into a
Word document or an Excel workbook. If the e-mail name is recognized as a Smart
Tag, the user is presented with one or more actions to perform on the selected
text. Possible actions associated with an e-mail name are to look up additional
contact information, or to send a new e-mail message to that contact.
You can extend the capabilities of Office XP by developing your own Smart Tag
Recognizer/Action DLL for use in Office documents. This article describes how
to build a Smart Tag DLL by using Visual C# .NET and discusses what registry
settings are required for Office XP to identify and use your Smart Tag
DLL.
NOTE: Excel 2002 and Word 2002 are the only Office XP programs that
support Smart Tags. However, the information presented in this article can be
applied to Smart Tag development for any program that adopts the Smart Tag
technology.
back to the top
Smart Tag Interfaces
A Smart Tag DLL is an object that implements two special
interfaces:
ISmartTagRecognizer and
ISmartTagAction. The
ISmartTagRecognizer interface is responsible for recognizing text that is typed into
a document as a Smart Tag. The
ISmartTagAction interface is responsible for performing actions on a particular
Smart Tag string at the user's request. It is not required that these
interfaces be implemented in the same DLL. You can have a recognizer DLL, and
then one or more action DLLs that extend a single Smart Tag type for different
actions.
Documentation for these interfaces, and the type library
that defines them, is provided in the Smart Tag Software Development Kit (SDK).
If you have not already done so, install the Smart Tag SDK before you continue
with the steps to create the sample Smart Tag. You can obtain the Smart Tag SDK
from the Microsoft Office XP Developer (MOD) CD-ROM, or you can download it. To
download the Smart Tag SDK, visit the following Microsoft Web site:
back to the top
Step-by-Step Instructions to Build a Smart Tag DLL
The following steps create a simple Smart Tag DLL that recognizes
the Microsoft Network (MSN) Instant Messenger contacts and gives the user the
ability to send e-mail or instant messages to a recognized contact. You must
have Instant Messenger 4.5 to use this sample. If you do not have Instant
Messenger 4.5, you can download a copy. To do this, visit the following
Microsoft Web site:
back to the top
Create the Resource Libraries and Install Them in the Global Assembly Cache
- On the Start menu, point to Programs, click Microsoft Visual Studio .NET, click Visual Studio .NET Tools, and then click Visual Studio .NET Command Prompt. Change to the root directory of drive C.
- Generate strong named key pairs by issuing the following
commands:
sn -k SmartTagLib.snk
sn -k Messenger.snk
sn -k SmartTagSample.snk
- From the command prompt, change the directory to the
location that contains the Smart Tag SDK type library. The default location for
this directory is C:\Program Files\Common Files\Microsoft Shared\Smart
Tag.
- Issue the following command to generate the strong named
wrapper DLL from the type library:NOTE: The following command is case-sensitive. If you do not follow
the case that is presented below, you may have to change the sample code so
that it will work.
tlbimp mstag.tlb /keyfile:c:\SmartTagLib.snk /out:c:\SmartTagLib.dll
- Issue the following command to install this DLL into the
global assembly cache:
gacutil /i c:\SmartTagLib.dll
- From the command prompt, change the directory to the
installation location for MSN Instant Messenger. The default location for this
directory is C:\Program Files\Messenger.
- Issue the following command to generate the strong named
wrapper DLL from the type library:NOTE: The following command is case-sensitive. If you do not follow
the case that is presented below, you may have to change the sample code so
that it will work.
tlbimp msmsgs.exe\3 /keyfile:c:\Messenger.snk /out:c:\Messenger.dll
- Issue the following command to install this DLL into the
global assembly cache:
gacutil /i c:\Messenger.dll
back to the top
Create the Smart Tag DLL
- Start Microsoft Visual Studio .NET. On the File menu, click New, and then click Project. Under Project types click Visual C# Projects, and then select Class Library. Name the project SmartTagSample. Class1 is created by
default.
- Add references to the MSN Instant Messenger Library and the
Smart Tag SDK library that you just created. To do this, follow these steps:
- On the Project menu, click Add Reference.
- Click Browse. In the Select Component dialog box, select C:\SmartTagLib.dll, and then click Open.
- Click Browse. In the Select Component dialog box, select C:\Messenger.dll, and then click Open.
- Click OK in the Add References dialog box to accept your selections.
- In the Project Properties window, rename Class1.cs to Recognizer.cs.
- Replace the code in the code window for Recognizer.cs with
the following:
using System;
using System.Diagnostics;
namespace SmartTagSample
{
public class Recognizer : SmartTagLib.ISmartTagRecognizer
{
String[] Contacts;
public Recognizer()
{
int i;
Messenger.MessengerClass oMessenger = new Messenger.MessengerClass();
Messenger.IMessengerContacts oUsers;
oUsers = (Messenger.IMessengerContacts) oMessenger.MyContacts;
Contacts = new String[oUsers.Count];
i = 0;
foreach (Messenger.IMessengerContact oUser in oUsers)
{
Contacts.SetValue(oUser.FriendlyName.ToLower(),i);
i++;
}
}
public string ProgId
{
get
{
Debug.WriteLine("Recognizer::ProgID");
// Return the ProgID of the Recognizer interface.
return "SmartTagSample.Recognizer";
}
}
public int SmartTagCount
{
get
{
Debug.WriteLine("Recognizer::SmartTagCount");
// Return the number of Smart Tags you support.
return 1;
}
}
public System.String get_Desc ( System.Int32 LocaleID )
{
Debug.WriteLine("Recognizer::Desc");
// Return a long description of your recognizer.
return
"Microsoft Messenger recognizes your Instant Messenger Contacts";
}
public System.String get_Name ( System.Int32 LocaleID )
{
Debug.WriteLine("Recognizer::Name");
// Return a short title about your recognizer.
return "Microsoft Messenger Contacts Visual C# .NET Recognizer";
}
public System.String get_SmartTagDownloadURL ( System.Int32 SmartTagID )
{
Debug.WriteLine("Recognizer::SmartTagDownloadURL");
// Return the URL that is embedded in documents.
return null;
}
public System.String get_SmartTagName ( System.Int32 SmartTagID )
{
Debug.WriteLine("Recognizer::SmartTagName");
// This method is called the same number of times as you
// return in SmartTagCount. This method sets a unique name
// for the Smart Tag.
return "microsoft/messenger#contacts";
}
public void Recognize ( System.String Text , SmartTagLib.IF_TYPE DataType ,
System.Int32 LocaleID , SmartTagLib.ISmartTagRecognizerSite RecognizerSite )
{
Debug.WriteLine("Recognizer::Recognize");
// The Recognize method is called and passed a text value.
// You should recognize strings in the text and set up the actions.
int i;
int startpos;
int strlen;
SmartTagLib.ISmartTagProperties propbag;
// Convert the text to lowercase.
Text = Text.ToLower();
// Loop through all contacts.
for (i = 0; i < Contacts.GetUpperBound(0); i++)
{
// Look for a contact name in the text.
startpos = Text.IndexOf(Contacts[i]) + 1;
// Find the length of the contact name.
strlen = Contacts[i].Length;
// Look for all occurrences of contacts in the string.
while (startpos > 0)
{
// Create a new property bag.
propbag = RecognizerSite.GetNewPropertyBag();
// Commit the Smart Tag to the property bag.
RecognizerSite.CommitSmartTag("microsoft/
messenger#contacts", startpos, strlen, propbag);
// Continue looking for contacts in the string.
startpos = Text.IndexOf(Contacts[i],startpos +
strlen) + 1;
}
}
}
}
}
- On the Project menu, select Add Class. Under Templates, select Class, and then name the class Action.cs. Click Open to create the new class.
- Replace the code in the code window for Action.cs with the
following:
using System;
using System.Diagnostics;
namespace SmartTagSample
{
public class Action: SmartTagLib.ISmartTagAction
{
// Property implementation.
public string ProgId
{
get
{
Debug.WriteLine("Action::ProgID");
// Return the ProgID of the Action interface.
return "SmartTagSample.Action";
}
}
public int SmartTagCount
{
get
{
Debug.WriteLine("Action::SmartTagCount");
// Return the number of smart tags that
// this action supports.
return 1;
}
}
public System.String get_Desc ( System.Int32 LocaleID )
{
Debug.WriteLine("Action::Desc");
// Return a long description describing the action.
return
"Provides actions for the Messenger Smart Tag";
}
public System.String get_Name ( System.Int32 LocaleID )
{
Debug.WriteLine("Action::Name");
// Return a short name describing the action.
return "Messenger Smart Tag";
}
public System.String get_SmartTagCaption
( System.Int32 SmartTagID , System.Int32 LocaleID )
{
Debug.WriteLine("Action::SmartTagCaption");
// This caption appears on the menu
// for the smart tag.
return "Messenger Smart Tag";
}
public System.String get_SmartTagName ( System.Int32 SmartTagID )
{
Debug.WriteLine("Action::SmartTagName");
// This method is called the same number of
// times as you return in SmartTagCount.
// This method sets a unique name
// for the smart tag.
return "microsoft/messenger#contacts";
}
public System.String get_VerbCaptionFromID ( System.Int32 VerbID ,
System.String ApplicationName , System.Int32 LocaleID )
{
Debug.WriteLine("Action::VerbCaptionFromID");
// Get a caption for each verb.
// This caption appears
// on the Smart Tag menu.
switch(VerbID)
{
case 1:
return
"Send this contact an Instant Message";
case 2:
return
"Send e-mail to this contact";
default:
return null;
}
}
public System.Int32 get_VerbCount
( System.String SmartTagName )
{
Debug.WriteLine("Action::VerbCount");
// Return the number of verbs you support.
if
(SmartTagName.Equals("microsoft/messenger#contacts"))
{
return 2;
}
return 0;
}
public System.Int32 get_VerbID ( System.String SmartTagName ,
System.Int32 VerbIndex )
{
Debug.WriteLine("Action::VerbID");
// Return a unique ID for each verb you support.
return VerbIndex;
}
public System.String get_VerbNameFromID ( System.Int32 VerbID )
{
// Return a string name for each verb.
switch(VerbID)
{
case 1:
return "SendInstantMessage";
case 2:
return "SendEmail";
default:
return null;
}
}
public void InvokeVerb ( System.Int32 VerbID , System.String
ApplicationName , System.Object Target ,
SmartTagLib.ISmartTagProperties Properties , System.String Text ,
System.String Xml )
{
Debug.WriteLine("Action::InvokeVerb");
// This method is called when a user invokes a verb
// from the Smart Tag menu.
Messenger.MessengerClass oMessenger =
new Messenger.MessengerClass();
Messenger.IMessengerContacts oUsers;
oUsers = (Messenger.IMessengerContacts)
oMessenger.MyContacts;
foreach (Messenger.IMessengerContact oUser in oUsers)
{
if (String.Compare(oUser.FriendlyName,Text,true) == 0)
{
switch(VerbID)
{
case 1:
// The user wants to display the
// Instant Message box to send
// the contact a message.
oMessenger.InstantMessage(oUser);
break;
case 2:
// Shell the "mailto" protocol to
// start the user's mail program
// and create a new message.
System.Diagnostics.Process.Start
("mailto:" + oUser.SigninName);
break;
}
}
}
}
}
}
- Open the Assemblyinfo.cs file.
- Replace the line that reads
[assembly: AssemblyKeyFile("")]
with:
[assembly: AssemblyKeyFile("C:\\SmartTagSample.snk")]
- From Project Properties, select Build. Change the value of Register for COM Interop to True, and then click OK.
- On the Build menu, click Build Solution to create the DLL.
- From a Visual Studio .NET command prompt, change the
directory to the bin\Debug directory for your project.
- For this DLL to work correctly, you must install it into
the global assembly cache. Issue the following command to install the DLL:
gacutil /i SmartTagSample.dll
back to the top
Register the Smart Tag DLL for Use with Office
WARNING: If you use Registry Editor incorrectly, you may cause serious
problems that may require you to reinstall your operating system. Microsoft
cannot guarantee that you can solve problems that result from using Registry
Editor incorrectly. Use Registry Editor at your own risk.
Before you can use any Smart Tag DLL, it must be registered on the system.
Typical COM registration is completed for you when you compile the project,
distribute the DLL with the Package and Deployment Wizard, or call Regsvr32.exe
with the DLL name. You must create additional registry entries that are not
part of typical COM registration so that Office applications can identify the
DLL as a Smart Tag DLL. To do this, follow these steps:
- From a command line, start Regedit.exe.
- Locate the following key in the registry:
HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Actions
- Add a new subkey named SmartTagSample.Action.
- Locate the following key in the registry:
HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Recognizers
- Add a new subkey named SmartTagSample.Recognize.
- Close Registry Editor.
back to the top
Steps to Test the Smart Tag DLL
Smart Tags obey the same security model as macros. If the
security settings of the application are set to High, the Smart Tag DLL does
not load unless
Trust all installed add-ins and templates is
selected. If the security settings are set to Medium and
Trust all
installed add-ins and templates is not selected, the user is prompted
to enable or disable each add-in. Because the
InprocServer32 key for the .NET assembly references the Mscoree.dll file instead
of the DLL that you build, a dialog box prompts you to enable or disable macros
for Mscoree.dll.
To test the custom Smart Tag Recognizer/Action DLL
in Word, follow these steps:
- Start Instant Messenger, and log on.
NOTE: The sample Smart Tag requires that you log on to Instant
Messenger; if you are not logged on to Instant Messenger, the custom DLL loads
but does not recognize any contacts. - Start Word 2002. On the Tools menu, point to Macro, and then click Security. Set the macro security to Medium, and then click OK. If the macro security setting was previously set to High, restart Word.
- Type the friendly name of a contact in a new document (for
example, John Smith), and then press ENTER. A faint line appears under the
friendly name to indicate that it is recognized as a Smart Tag. Move the
pointer over the friendly name, and the Smart Tag Action button
appears.
- Click the Smart Tag button, and then select one of the custom action items from the
drop-down menu. You can send an e-mail or instant message to the contact from
your new document.
You can use similar steps to test the Smart Tag DLL in Excel
2002.
back to the top
Troubleshooting
If you have problems getting your custom Smart Tags to work,
first verify that the custom Smart Tag DLL is being loaded. In Word or Excel,
on the
Tools menu, click
Auto Correct Options, click the
Smart Tag tab, and verify that
Label Text with Smart Tags
is selected and that your Smart Tag DLL is listed and selected. If your Smart
Tag is not listed, it may not be properly registered.
If the
execution of the custom recognizer or action class is the source of the
problem, you can debug a Smart Tag DLL as you would any Visual C# .NET DLL.
From
Project Properties, click
Configuration Properties and then click
Debugging. Select
Start Application and specify the path to Winword.exe or Excel.exe. Set
Debug Mode to
Program, and then click
OK. Set a breakpoint in the constructor for the class item that you
want to debug. When Excel or Word starts and loads the Smart Tag, your code
breaks at the breakpoint and you can step through the code for
debugging.
Your Smart Tag DLL should trap and handle any run-time
errors. If an error is raised in your code and the error is not handled, Office
immediately unloads the DLL and clears the item so that it is not loaded again.
This behavior is the same as the way Office treats COM Add-Ins, and can give
you the impression that Office is not loading the DLL when it is in fact doing
so, but was forced to unload it because of an unhandled run-time error.
back to the top