Programming MicrosoftВ® OutlookВ® and Microsoft Exchange 2003, Third Edition (Pro-Developer)
The book's companion files include a sample application that implements several of the new features for smart tags. This smart tag recognizes a number of terms and performs different smart tag actions based on those terms. For example, when you type temporary , a temporary smart tag is recognized. When you type expire , a smart tag is created that expires in 1 minute. When you type the application name in Word, Excel, or PowerPoint, a smart tag is created in that application. The example smart tag also shows how to use property pages and dynamic action naming. Here's the Visual Basic code for the recognizer DLL for the smart tag:
Implements SmartTagLib.ISmartTagRecognizer Implements SmartTagLib.ISmartTagRecognizer2 Const smartTagType = "urn-schemas-microsoft-com#applicationName" Private Property Get ISmartTagRecognizer_Desc( _ ByVal LocaleID As Long) As String 'Create a long description of this recognizer ISmartTagRecognizer_Desc = "Description of your recognizer goes here" End Property Private Property Get ISmartTagRecognizer_Name( _ ByVal LocaleID As Long) As String 'What is shown in the Tools Autocorrect Option Smart Tags 'dialog box in Word, Excel and PowerPoint ISmartTagRecognizer_Name = "Application name recognizer" End Property Private Property Get ISmartTagRecognizer_ProgId() As String 'Unique identifier for this recognizer that corresponds 'to the ProgID of this DLL ISmartTagRecognizer_ProgId = "Smarttag.AllNewFeaturesRecog" End Property Private Sub ISmartTagRecognizer_Recognize( _ ByVal Text As String, _ ByVal DataType As SmartTagLib.IF_TYPE, _ ByVal LocaleID As Long, _ ByVal RecognizerSite As SmartTagLib.ISmartTagRecognizerSite) 'This method should not be called since there is a 'Recognize2 method in this recognizer DLL End Sub Private Property Get ISmartTagRecognizer_SmartTagCount() As Long 'The number of Smart Tag types this recognizer supports ISmartTagRecognizer_SmartTagCount = 1 End Property Private Property Get ISmartTagRecognizer_SmartTagDownloadURL( _ ByVal SmartTagID As Long) As String ISmartTagRecognizer_SmartTagDownloadURL = "http://smarttagweb" End Property Private Property Get ISmartTagRecognizer_SmartTagName( _ ByVal SmartTagID As Long) As String 'The name of the Smart Tag type supported If (SmartTagID = 1) Then ISmartTagRecognizer_SmartTagName = smartTagType End If End Property Private Sub ISmartTagRecognizer2_DisplayPropertyPage( _ ByVal SmartTagID As Long, _ ByVal LocaleID As Long) frmPropPage.Show vbModal End Sub Private Property Get ISmartTagRecognizer2_PropertyPage( _ ByVal SmartTagID As Long, _ ByVal LocaleID As Long) As Boolean ISmartTagRecognizer2_PropertyPage = True End Property Private Sub ISmartTagRecognizer2_Recognize2( _ ByVal Text As String, _ ByVal DataType As SmartTagLib.IF_TYPE, _ ByVal LocaleID As Long, _ ByVal RecognizerSite2 As SmartTagLib.ISmartTagRecognizerSite2, _ ByVal ApplicationName As String, _ ByVal TokenList As SmartTagLib.ISmartTagTokenList) Dim i As Long Dim sValue As String Dim lOffset As Long, lLength As Long Dim propbag As SmartTagLib.ISmartTagProperties Dim ShortAppName As String Dim endPos As Integer endPos = InStr(1, ApplicationName, ".") ShortAppName = LCase(Mid(ApplicationName, 1, endPos - 1)) On Error GoTo Error_Handler If TokenList Is Nothing Then If LocaleID = 2052 Or LocaleID = 4100 Or LocaleID = 1028 Or _ LocaleID = 3076 Or LocaleID = 5124 Or LocaleID = 1041 Or _ LocaleID = 1042 Or LocaleID = 1054 Then MsgBox "TokenList is Nothing. This is a falure if " & _ "the word breaker for LocaleID = " & _ LocaleID & " is installed." Else MsgBox "TokenList is Nothing. It should have been " & _ "tokenized by the Western Language tokenizer " & _ "for LocaleID = " & LocaleID End If Else For i = 1 To TokenList.Count sValue = TokenList.Item(i).Text sValue = LCase(sValue) lOffset = TokenList.Item(i).Start lLength = TokenList.Item(i).Length Set propbag = RecognizerSite2.GetNewPropertyBag If LCase(sValue) = "recognize" Then 'Run action on recognize propbag.Write "o:runAction", "launchCalc" RecognizerSite2.CommitSmartTag2 smartTagType, _ lOffset, lLength, propbag ElseIf sValue = ShortAppName Then 'If the user types the app name such as Word propbag.Write "sValue", sValue propbag.Write "lOffset", Str(lOffset) propbag.Write "lLength", Str(lLength) RecognizerSite2.CommitSmartTag2 smartTagType, _ lOffset, lLength, propbag ElseIf LCase(sValue) = "expire" Then 'Get 1 minute from now to expire the smart tag dDate = DateAdd("n", 1, Now) dDate = Year(dDate) & ":" & Month(dDate) & _ ":" & Day(dDate) & ":" & Hour(dDate) & _ ":" & Minute(dDate) propbag.Write "o:exp", dDate RecognizerSite2.CommitSmartTag2 smartTagType, _ lOffset, lLength, propbag ElseIf LCase(sValue) = "temporary" Then 'Create a temporary smart tag propbag.Write "o:ls", "temp" RecognizerSite2.CommitSmartTag2 smartTagType, _ lOffset, lLength, propbag End If Next i End If Exit Sub Error_Handler: MsgBox Err.Description Err.Clear Resume Next End Sub Private Sub ISmartTagRecognizer2_SmartTagInitialize( _ ByVal ApplicationName As String) MsgBox "In ISmartTagRecognizer2_SmartTagInitialize. " & _ "App name is " & ApplicationName End Sub
The main points of interest in this code are in the property page implementation and the Recognize2 method. The smart tag implements a property page and displays a Visual Basic form when a user clicks the Properties button in the smart tag user interface in the host application. Figure 9-12 shows the property page in Excel.
The host application figures out that a property page is supported by inspecting the ISmartTagRecognizer2_PropertyPage Boolean property. The code returns True , which indicates that it supports a property page.
To show tokenizing the input, the ISmartTagRecognizer2_Recognize2 method uses the new capabilities of that interface. You can see that the method goes through the token list returned by the smart tag host and recognizes which terms should be smart tagged. Then the method uses some of the new capabilities in smart tags ”such as expiring, being temporary, or firing actions on recognition ”as part of the sample.
The code for the action part of the DLL is shown here:
Implements ISmartTagAction Implements ISmartTagAction2 Const smartTagType = "urn-schemas-microsoft-com#applicationName" Private Property Get ISmartTagAction_Desc( _ ByVal LocaleID As Long) As String 'Description of Action DLL ISmartTagAction_Desc = _ "This smart tag shows the new features of smart tags." End Property Private Sub ISmartTagAction_InvokeVerb( _ ByVal VerbID As Long, _ ByVal ApplicationName As String, _ ByVal Target As Object, _ ByVal Properties As SmartTagLib.ISmartTagProperties, _ ByVal Text As String, _ ByVal Xml As String) 'This method shouldn't be called since we have an InvokeVerb2 End Sub Private Property Get ISmartTagAction_Name( _ ByVal LocaleID As Long) As String 'Name of the Action DLL ISmartTagAction_Name = "All New Features Actions" End Property Private Property Get ISmartTagAction_ProgId() As String 'ProgID of the Action DLL ISmartTagAction_ProgId = "Smarttag.AllNewFeaturesActions" End Property Private Property Get ISmartTagAction_SmartTagCaption( _ ByVal SmartTagID As Long, _ ByVal LocaleID As Long) As String 'This will appear in the smart tag UI ISmartTagAction_SmartTagCaption = "All New Features Actions" End Property Private Property Get ISmartTagAction_SmartTagCount() As Long 'Number of smart tag types this DLL supports ISmartTagAction_SmartTagCount = 1 End Property Private Property Get ISmartTagAction_SmartTagName( _ ByVal SmartTagID As Long) As String If (SmartTagID = 1) Then ISmartTagAction_SmartTagName = smartTagType End If End Property Private Property Get ISmartTagAction_VerbCaptionFromID( _ ByVal VerbID As Long, _ ByVal ApplicationName As String, _ ByVal LocaleID As Long) As String If (VerbID = 1) Then ISmartTagAction_VerbCaptionFromID = _ "&Dynamic actions unavailable" Else ISmartTagAction_VerbCaptionFromID = Null End If End Property Private Property Get ISmartTagAction_VerbCount( _ ByVal SmartTagName As String) As Long 'Specify the number of verbs supported for a given smart tag type If (SmartTagName = smartTagType) Then ISmartTagAction_VerbCount = 3 End If End Property Private Property Get ISmartTagAction_VerbID( _ ByVal SmartTagName As String, _ ByVal VerbIndex As Long) As Long ISmartTagAction_VerbID = VerbIndex End Property Private Property Get ISmartTagAction_VerbNameFromID( _ ByVal VerbID As Long) As String If (VerbID = 1) Then ISmartTagAction_VerbNameFromID = "action1" ElseIf (VerbID = 2) Then ISmartTagAction_VerbNameFromID = "action2" ElseIf (VerbID = 3) Then ISmartTagAction_VerbNameFromID = "launchCalc" End If End Property Private Sub ISmartTagAction2_InvokeVerb2( _ ByVal VerbID As Long, _ ByVal ApplicationName As String, _ ByVal Target As Object, _ ByVal Properties As SmartTagLib.ISmartTagProperties, _ ByVal Text As String, _ ByVal Xml As String, _ ByVal LocaleID As Long) Dim sValue As String Dim sOffset As String Dim sLength As String If (VerbID = 1) Then sValue = Properties.Read("sValue") sOffset = Properties.Read("lOffset") sLength = Properties.Read("lLength") MsgBox "The token is " & sValue & Chr(13) & "Offset: " & _ sOffset & Chr(13) & "Length: " & sLength ElseIf (VerbID = 2) Then MsgBox "Action #2" ElseIf (VerbID = 3) Then iRet = Shell("calc.exe", vbMaximizedFocus) End If End Sub Private Property Get ISmartTagAction2_IsCaptionDynamic( _ ByVal VerbID As Long, _ ByVal ApplicationName As String, _ ByVal LocaleID As Long) As Boolean ISmartTagAction2_IsCaptionDynamic = True End Property Private Property Get ISmartTagAction2_ShowSmartTagIndicator( _ ByVal VerbID As Long, _ ByVal ApplicationName As String, _ ByVal LocaleID As Long) As Boolean ISmartTagAction2_ShowSmartTagIndicator = True End Property Private Sub ISmartTagAction2_SmartTagInitialize( _ ByVal ApplicationName As String) MsgBox "In ISmartTagAction2_SmartTagInitialize. App is " & _ ApplicationName End Sub Private Property Get ISmartTagAction2_VerbCaptionFromID2( _ ByVal VerbID As Long, _ ByVal ApplicationName As String, _ ByVal LocaleID As Long, _ ByVal Properties As SmartTagLib.ISmartTagProperties, _ ByVal Text As String, _ ByVal Xml As String, _ ByVal Target As Object) As String If (VerbID = 1) Then If (LCase(Text) = "word") Then ISmartTagAction2_VerbCaptionFromID2 = "&Text is///word" Else ISmartTagAction2_VerbCaptionFromID2 = "&Text is not///word" End If ElseIf (VerbID = 2) Then If (LCase(ApplicationName) = "word.application.11") Then If (InStr(Target.paragraphs(1).range.Text, "the")) Then ISmartTagAction2_VerbCaptionFromID2 = "Contains the" Else 'hide the action completely ISmartTagAction2_VerbCaptionFromID2 = "" End If Else ISmartTagAction2_VerbCaptionFromID2 = "Not in Word" End If ElseIf (VerbID = 3) Then 'No verb caption for firing on recognition Else ISmartTagAction2_VerbCaptionFromID2 = "" End If End Property
An interesting part of this code is the dynamic caption naming for the actions. If you look at ISmartTagAction2_VerbCaptionFromID2 , you'll notice that this method supports getting the text that is recognized. Based on the text being passed, the application either changes the caption for the smart tag actions or hides the caption entirely by setting the property to ""