Programming MicrosoftВ® OutlookВ® and Microsoft Exchange 2003, Third Edition (Pro-Developer)

Note  

You should read the white paper "Building Smart Tags in Microsoft Visual Basic .NET" at http://msdn.microsoft.com/office before reading this section. This section includes information adapted from that white paper and also provides additional details.

Building smart tags in .NET is similar to building COM add-ins. The chief difference is that .NET doesn't include a wizard for smart tags, as it does for COM add-ins. You have to create the necessary references, event handlers, and code manually to build your smart tag.

Because the process is so similar, I'll show you one completed smart tag, written in Visual Basic .NET, to help get you started. The code in this section is from the DotNet Smart Tag sample application. In Visual Basic .NET, you create a class library. The smart tag contains a recognizer that recognizes the word Outlook and a single action that displays in a message box the information recognized, such as the data type, locale ID, and the text. Here's the code for the recognizer:

Imports SmartTagLib Imports System.Runtime.InteropServices <ProgId("DotNetSmartTag.Recognizer"), _ GuidAttribute("8981FE26-D112-402e-9A01-06C8A2F01207"), _ ComVisible(True)> Public Class Recognizer Implements ISmartTagRecognizer <ComRegisterFunction()> Shared Sub Register( _ ByVal RegKey As String) RegSmartTag(RegKey, True) End Sub <ComUnregisterFunction()> Shared Sub Unregister( _ ByVal RegKey As String) RegSmartTag(RegKey, False) End Sub 'Default Constructor with no arguments 'Required for COM Interop Public Sub New() End Sub 'A substantive description of what the recognizer does. Public ReadOnly Property Desc( _ ByVal LocaleID As Integer) As String _ Implements SmartTagLib.ISmartTagRecognizer.Desc Get Return "Sample DotNet Smart Tag" End Get End Property 'A short title reflecting what the recognizer does. Public ReadOnly Property Name( _ ByVal LocaleID As Integer) As String _ Implements SmartTagLib.ISmartTagRecognizer.Name Get Return "DotNet Sample Smart Tag" End Get End Property 'The COM ProgID of the Smart Tag Public ReadOnly Property ProgId() As String _ Implements SmartTagLib.ISmartTagRecognizer.ProgId Get Return "DotNetSmartTag.Recognizer" End Get End Property 'Recognizes terms. Public Sub Recognize(ByVal strRecText As String, _ ByVal DataType As SmartTagLib.IF_TYPE, _ ByVal LocaleID As Integer, _ ByVal RecognizerSite As SmartTagLib.ISmartTagRecognizerSite) _ Implements SmartTagLib.ISmartTagRecognizer.Recognize Dim position As Integer Dim lLength As Integer 'Remove any ???? lLength = Len(strRecText) If (lLength > 0) Then position = InStr(1, strRecText, ChrW(-4)) Else position = 0 End If While (lLength > 0 And position > 0) Mid$(strRecText, position, 1) = "" lLength = lLength - 1 If (lLength > 0) Then position = InStr(1, strRecText, ChrW(-4)) Else position = 0 End If position = InStr(1, strRecText, ChrW(-4)) End While strRecText = RTrim(strRecText) position = InStr(1, strRecText, ChrW(-4)) If (position > 0) Then lLength = Len(strRecText) Mid$(strRecText, (lLength - position + 1)) = _ Space$(lLength - position + 1) strRecText = RTrim(strRecText) End If If Right(strRecText, 1) = ChrW(13) Then strRecText = Left(strRecText, Len(strRecText) - 1) End If Dim intLocation As Integer = InStr(UCase(strRecText), _ UCase("Outlook"), _ CompareMethod.Binary) If intLocation > 0 Then Dim stPropBag As ISmartTagProperties = _ RecognizerSite.GetNewPropertyBag() Dim strPropType As String 'Determine the data type (as a string) Select Case DataType Case IF_TYPE.IF_TYPE_CELL strPropType = "IF_TYPE_CELL" Case IF_TYPE.IF_TYPE_CHAR strPropType = "IF_TYPE_CHAR" Case IF_TYPE.IF_TYPE_PARA strPropType = "IF_TYPE_PARA" Case IF_TYPE.IF_TYPE_REGEXP strPropType = "IF_TYPE_REGEXP" Case IF_TYPE.IF_TYPE_SINGLE_WD strPropType = "IF_TYPE_SINGLE_WD" End Select 'Add the data to the propbag stPropBag.Write("DataType", strPropType) 'Add the text so the function can receive it stPropBag.Write("Text", strRecText) 'Add the LocaleID stPropBag.Write("LocaleID", LocaleID) 'Commit the SmartTag On Error Resume Next RecognizerSite.CommitSmartTag( _ "urn:thomriz:com#DotNetSmartTag", _ intLocation, 7, stPropBag) End If End Sub 'The number of smart tag types that this recognizer supports Public ReadOnly Property SmartTagCount() As Integer _ Implements SmartTagLib.ISmartTagRecognizer.SmartTagCount Get Return 1 End Get End Property 'We have no download URL, so return empty Public ReadOnly Property SmartTagDownloadURL( _ ByVal SmartTagID As Integer) As String _ Implements SmartTagLib.ISmartTagRecognizer.SmartTagDownloadURL Get Return "" End Get End Property 'The unique IDs of smart tag types the recognizer supports. Public ReadOnly Property SmartTagName( _ ByVal SmartTagID As Integer) As String _ Implements SmartTagLib.ISmartTagRecognizer.SmartTagName Get Return "urn:thomriz:com#DotNetSmartTag" End Get End Property End Class

Notice that the recognizer leverages the built-in COM interoperability features of the .NET platform. Otherwise , the recognizer looks like the standard recognizers we built using Visual Basic 6.0. The only difference is the register and unregister functions included for COM, which we will discuss in the next section. For the action, the code is as follows . (It is in a different class file.)

Imports SmartTagLib Imports System.Runtime.InteropServices <ProgId("DotNetSmartTag.Action"), _ GuidAttribute("A7253D8D-B8B0-4769-A8BB-65584AC3C9EF"), _ ComVisible(True)> _ Public Class Action Implements ISmartTagAction Public ReadOnly Property Desc( _ ByVal LocaleID As Integer) As String _ Implements SmartTagLib.ISmartTagAction.Desc Get Return "DotNet Smart Tag Action" End Get End Property Public Sub InvokeVerb(ByVal VerbID As Integer, _ ByVal ApplicationName As String, _ ByVal Target As Object, _ ByVal Properties As SmartTagLib.ISmartTagProperties, _ ByVal strText As String, ByVal Xml As String) _ Implements SmartTagLib.ISmartTagAction.InvokeVerb Dim strMsg As String = strText Dim i As Short For i = 0 To Properties.Count - 1 strMsg &= vbCrLf & Properties.KeyFromIndex(i) strMsg &= "=" & Properties.ValueFromIndex(i) Next MsgBox(strMsg, , "DotNet Smart Tag") End Sub Public ReadOnly Property Name( _ ByVal LocaleID As Integer) As String _ Implements SmartTagLib.ISmartTagAction.Name Get Return "DotNet Action" End Get End Property Public ReadOnly Property ProgId() As String _ Implements SmartTagLib.ISmartTagAction.ProgId Get Return "DotNetSmartTag.Action" End Get End Property Public ReadOnly Property SmartTagCaption( _ ByVal SmartTagID As Integer, _ ByVal LocaleID As Integer) As String _ Implements SmartTagLib.ISmartTagAction.SmartTagCaption Get Return "DotNet Smart Tag" End Get End Property Public ReadOnly Property SmartTagCount() As Integer _ Implements SmartTagLib.ISmartTagAction.SmartTagCount Get Return 1 End Get End Property Public ReadOnly Property SmartTagName( _ ByVal SmartTagID As Integer) As String _ Implements SmartTagLib.ISmartTagAction.SmartTagName Get Return "urn:thomriz:com#DotNetSmartTag" End Get End Property Public ReadOnly Property VerbCaptionFromID( _ ByVal VerbID As Integer, _ ByVal ApplicationName As String, _ ByVal LocaleID As Integer) As String _ Implements SmartTagLib.ISmartTagAction.VerbCaptionFromID Get Return "Show DotNet Smart Tag" End Get End Property Public ReadOnly Property VerbCount( _ ByVal SmartTagName As String) As Integer _ Implements SmartTagLib.ISmartTagAction.VerbCount Get Return 1 End Get End Property Public ReadOnly Property VerbID( _ ByVal SmartTagName As String, _ ByVal VerbIndex As Integer) As Integer _ Implements SmartTagLib.ISmartTagAction.VerbID Get Return 1 End Get End Property Public ReadOnly Property VerbNameFromID( _ ByVal VerbID As Integer) As String _ Implements SmartTagLib.ISmartTagAction.VerbNameFromID Get Return "ShowTag" End Get End Property End Class

Again, the code looks like a standard smart tag action except for the COM interoperability. Building smart tags with .NET is easy because .NET performs all the interoperability work for you.

Automatic Registration with Reflection

One useful function that the sample application called DotNet Smart Tag provides is a function for the smart tag to register itself as a smart tag in the registry when .NET registers the DLL for COM interoperability. You do this through Reflection, which is the ability of your application to obtain information about itself or other components at run time. When .NET registers the DLL, the code contained in the recognizer's Register function fires and runs code that queries the component and places the information that's required to register the component as a smart tag recognizer in the registry. When the .NET component is unregistered, the opposite occurs, and the registry information is removed. The code for this functionality is shown in the following example and is explained more fully in the white paper cited at the beginning of this section.

Imports Microsoft.Win32 Imports System.Runtime.InteropServices Imports System.Reflection Imports System Module FileRegistration 'Registration flag so we know if this registration code 'has already been executed. (We only want it to run once.) Private fReg As Boolean = False Public Sub RegSmartTag( _ ByVal RegKey As String, _ ByVal Register As Boolean) If Not fReg Then OutputMsg("***** Beginning SmartTag Registration *****") OutputMsg(vbTab & "Register=" & Register.ToString()) OutputMsg("") 'Main SmartTags Registry Key Dim rkeySmartTags As RegistryKey _ = Registry.CurrentUser.OpenSubKey _ ("Software\Microsoft\Office\Common\Smart Tag", True) 'Actions Sub Key Dim rkeyActions As RegistryKey _ = rkeySmartTags.OpenSubKey("Actions", True) 'Recognizers Sub Key Dim rkeyRecognizers As RegistryKey _ = rkeySmartTags.OpenSubKey("Recognizers", True) 'Get the current assembly Dim reflAssembly As [Assembly] = _ [Assembly].GetExecutingAssembly() 'Get all public types for the assembly Dim reflTypes As Type() = reflAssembly.GetExportedTypes() Dim reflType As Type 'Loop through the exported types. For Each reflType In reflTypes 'Get the interfaces to look for the SmartTag interfaces. If reflType.IsClass Then 'Make sure that it's a class. Dim reflInterfaces As Type() = _ reflType.GetInterfaces() Dim reflInterface As Type For Each reflInterface In reflInterfaces Select Case reflInterface.Name 'SmartTag Action Interface Case "ISmartTagAction" HandleReg(reflType, rkeyActions, Register) 'SmartTag Recognizer Interface Case "ISmartTagRecognizer" HandleReg(reflType, _ rkeyRecognizers, Register) End Select Next reflInterface End If Next reflType 'Done. Now clean up. reflTypes = Nothing reflAssembly = Nothing rkeyActions.Close() rkeyActions = Nothing rkeyRecognizers.Close() rkeyRecognizers = Nothing rkeySmartTags.Close() rkeySmartTags = Nothing fReg = True '<-- Set our shared variable to True OutputMsg("") OutputMsg("***** Completed SmartTag Registration *****") OutputMsg("") End If End Sub Private Sub HandleReg( _ ByVal sysType As Type, _ ByVal RegKey As RegistryKey, _ ByVal Register As Boolean) 'Code to actually do the registration of the SmartTag. 'INPUTS: ' sysType: Type for the class that's getting registered. ' RegKey: RegKey to register the class in. ' Should be the Actions or Recognizers Key. ' Register: True to register, False to Unregister. 'Get the type of the GuidAttribute class. We'll need this. Dim typGUIDAttr As Type = GetType(GuidAttribute) 'Check to see if the GuidAttribute is defined on the class. If Attribute.IsDefined(sysType, typGUIDAttr) Then Dim attrValue As GuidAttribute 'Get the GuidAttribute. attrValue = CType(Attribute.GetCustomAttribute( _ sysType, typGUIDAttr), GuidAttribute) 'Get the string representation of the GUID. Dim strGuidVal As String = "{" & attrValue.Value & "}" If Register Then Try Dim newKey As RegistryKey _ = RegKey.CreateSubKey(strGuidVal) newKey.SetValue("Assembly", _ sysType.Assembly.FullName) newKey.SetValue("Type", sysType.FullName) OutputMsg(sysType.Name & _ " registered with SmartTags successfully") Catch OutputMsg("Failed to register " & _ sysType.Name & " with SmartTags") OutputMsg(Err.GetType.Name & ":" & Err.Description) End Try Else Try RegKey.DeleteSubKey(strGuidVal, False) OutputMsg(sysType.Name & _ " unregistered with SmartTags successfully") Catch OutputMsg("Failed to unregister " & _ sysType.Name & " with SmartTags") OutputMsg(Err.GetType.Name & ":" & Err.Description) End Try End If Else 'If we don't find the guid attribute, 'write to the system console. OutputMsg("Could not register " & _ sysType.Name & " as SmartTag") OutputMsg("GUID Attribute not found on class") End If End Sub Private Sub OutputMsg(ByVal Msg As String) 'Use DEBUG conditional compile constant to only output 'when compiling the DEBUG version. #If DEBUG Then System.Console.WriteLine(Msg) #End If End Sub End Module

Testing Your Smart Tag in .NET

When you test your smart tag, be sure to set macro security in your Office application to Medium ”otherwise, the smart tag will not work. After you launch an Office application such as Word, you will then be prompted to enable or disable a DLL called mscoree.dll. If you are running Office 2003, you will not be prompted for .NET smart tags. This DLL is the DLL that contains the common language runtime (CLR). Be sure to enable this macro. You can then type the word Outlook wherever you want, and the smart tag should work as shown in Figure 9-8.

Figure 9-8: The .NET smart tag working in Word

Категории