Дата публикации статьи: 09.10.2004 15:59

Гайдар Магдануров
SmartTags в Office

  • Введение

  • Реализация

  • Пример

  • Регистрация компонента

  • Отладка

  • Заключение

  • Скачать архив исходного кода к статье

  •     Некоторые постоянные посетители VBStreets уже обвиняют меня в том, что я преждевременно "похоронил" Visual Basic 6, всецело и бесповоротно "уверовав в .NET". Что ж, должен опротестовать эти слухи. Я всегда за ту технологию, которая удобнее и надежнее для решения той или иной задачи. К сожалению (некоторых неразумных товарищей) и радости (моей) Visual Basic .NET весьма удобен для решения практически всех задач, которые приходится решать большинству программистов по всему миру.. Но, к сожалению, не всегда применим. Причем, наиболее распространенной причиной является инертность VB-программистов.
        Поэтому я решил написать несколько статей посвященной новым технологиям и реализации оных в Visual Basic 6 версии. На время оставим .NET в покое и "помучаем" наш старый добрый "VB не .NET".

    Введение

        С появлением Office XP корпорация Microsoft представила новую технологию для Office - SmartTags. Те, кто пользовался Office XP / 2003, наверное уже заметили, что если ввести дату или имя человека из адресной книги Outlook, то появляется значок, позволяющий выбрать некоторые действия.
        Лично мне эта технология очень понравилась, поэтому-то и появилась эта короткая статья. Как всегда (да-да, на самом деле так) в статье могут быть ошибки и неточности, поэтому - пробуйте, экспериментируйте и сообщайте мне.

    Реализация

        Что представляет собой компонент поддерживающий SmartTags? Как и следовало ожидать - это COM компонент (по VBшному ActiveX), зарегистрированный для использования Office и следующий некоторым правилам реализации. Точнее - имеющий два стандартных класса, реализующих (иногда говорят имплементирующий, и заменяют слово реализация словом имплементация, но это совершенно не по-русски) два стандартных интерфейса. Эти интерфейсы ISmartTagRecognizer и ISmartTagAction.
        Таким образом, чтобы создать компонент SmartTags необходимо - подключить к проекту Microsoft SmartTags Type Library, создать два класса реализующих указанные выше интерфейсы и наполнить эту реализацию осмысленным содержимым. Чтобы не толочь воду в ступе, сразу же перейдем к примеру.

    Пример

        Допустим, мы хотим создать компонент, который будет распознавать ники пользователей на форуме bbs.vbstreets.ru (для простоты возьмем только модераторов и "зашьем" всю информацию непосредственно в двоичный файл компонента, хотя по-хорошему надо бы получать ее из Интернет).
        Компонент должен выполнять три действия - открывать окно Internet Explorer или почтового клиента с целью показать профиль пользователя, создать пустое письмо этому пользователю адресованное и перейти на страничку пользователя.
        Код двух основных классов приведен ниже. Подробнее в архиве с примером. Код полностью комментирован и его можно использовать как справочник.
    Могу вас уверить - в комментариях есть вся необходимая информация.

    RecognizerClass
    Option Explicit ' Будем все делать правильно
    
    ' Ключевая строка кода
    ' Чтобы наш класс воспринимался Office, надо
    ' использовать интерфейс ISmartTagRecognizer
    
    Implements ISmartTagRecognizer
    
    
    
    Private Sub Class_Initialize()
    ' Здесь приведена заглушка, в реальном приложении
    ' нужно получить список терминов из файла или сети
    ' в противном случае понадобится перекомпиляция всякий раз
    ' как бедет добавлен новый термин
    Dim tData As Data
    
    ReDim knownTerms(3)
    Set termData = New DataCollection
    
    knownTerms(0) = "gaidar"
    Set tData = termData.Add("gaidar", "gaidar")
    tData.ID = "109"
    tData.Mail = "gaidar@vbstreets.ru"
    tData.Url = "gaidar.com.ru"
    
    knownTerms(1) = "asd"
    Set tData = termData.Add("asd", "asd")
    tData.ID = "3"
    tData.Mail = "admin@vbstreets.ru"
    tData.Url = "www.vbstreets.ru"
    
    knownTerms(2) = "moderator"
    Set tData = termData.Add("moderator", "moderator")
    tData.ID = "33"
    tData.Mail = "anton@vbstreets.ru"
    tData.Url = "www.bitshape.ru"
    
    knownTerms(3) = "rayshade"
    Set tData = termData.Add("rayshade", "rayshade")
    tData.ID = "1974"
    tData.Mail = "rayshade@vbstreets.ru"
    tData.Url = "www.vbstreets.ru"
    
    End Sub
    
    Private Sub Class_Terminate()
    ' Здесь ничего не делаем
    
    End Sub
    
    Private Property Get ISmartTagRecognizer_Desc(ByVal LocaleID As Long) As String
    ' Описание класса
    ISmartTagRecognizer_Desc = "Компонент распознования ников модераторов форума"
    End Property
    
    Private Property Get ISmartTagRecognizer_Name(ByVal LocaleID As Long) As String
    ' Имя будет отображаться в Microsoft Word в меню
    ' Tools -> Autocorrect Option -> Smart Tags
    ISmartTagRecognizer_Name = "VBStreets Nick Recognizer"
    End Property
    
    Private Property Get ISmartTagRecognizer_ProgId() As String
    ' Уникальное имя
    ISmartTagRecognizer_ProgId = "VBS_SmartTags.RecognizerClass"
    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)
    
    ' Процесс распознавания необычайно прост, достаточно найти
    ' в переданном в качестве параметра тексе имеющиеся в списке
    ' термины
    Dim i As Integer, stStart As Integer, stLength As Integer
    Dim SmartTagPB As SmartTagLib.ISmartTagProperties
    ' Прежде всего необходимо следить за тем, чтобы регистр text и
    ' регистр терминов был одинаковый, иначе поиск с помощью InStr
    ' закончится неудачей
    
    Text = LCase(Text)
    
    ' Проходим в цикле через массив терминов
    For i = 0 To UBound(knownTerms)
    ' вычисляем длину термина в символах
    stLength = Len(knownTerms(i))
    ' ищем термин в тексте
    stStart = InStr(1, Text, LCase(knownTerms(i)))
    ' если термин присутствует в тексте, ищем его еще раз
    Do While (stStart <> 0)
    ' Создаем новый объект SmartTag Property Bag
    Set SmartTagPB = RecognizerSite.GetNewPropertyBag
    ' У нас только один тип SmartTags в компоненте
    ' поэтому схема везде одна, потому-то она и
    ' константа
    Call RecognizerSite.CommitSmartTag(SchemaName, stStart, stLength, SmartTagPB)
    ' нет ли еще тут чего-нибудь
    stStart = InStr(stStart + stLength, Text, knownTerms(i))
    Loop
    Next i
    
    End Sub
    
    Private Property Get ISmartTagRecognizer_SmartTagCount() As Long
    ' Количество распозноваемых типов SmartTags
    ' В нашем примере тип только один - ники модераторов
    ' форума VBStreets
    ISmartTagRecognizer_SmartTagCount = 1
    End Property
    
    Private Property Get ISmartTagRecognizer_SmartTagDownloadURL(ByVal SmartTagID As Long) _
    As String
    ' Наш компонент не поддерживает эту фичу, для простоты примера
    ISmartTagRecognizer_SmartTagDownloadURL = ""
    End Property
    
    Private Property Get ISmartTagRecognizer_SmartTagName(ByVal SmartTagID As Long) As String
    ' Название типов поддерживаемых SmartTags
    ' формат: namespaceURI#tagname
    Select Case SmartTagID
    Case 1:
    ISmartTagRecognizer_SmartTagName = SchemaName
    End Select
    End Property
    ActionClass
    
    Option Explicit
    
    ' Ключевая строка кода
    ' Чтобы наш класс воспринимался Office, надо
    ' использовать интерфейс ISmartTagAction
    
    Implements ISmartTagAction
    
    Private Sub Class_Initialize()
    ' ничего тут не делаем
    End Sub
    
    Private Sub Class_Terminate()
    ' да и тут тоже ничего
    End Sub
    
    
    Private Property Get ISmartTagAction_Desc(ByVal LocaleID As Long) As String
    ' Описание
    ISmartTagAction_Desc = "Обработка распознаных ников"
    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)
    ' Выполняем затребованное пользователем действие
    ' Для простоты переложим всю работу на ShellExecute
    
    Dim tData As New Data
    Set tData = termData.Item(LCase(Text))
    Select Case VerbID
    Case 1:
    ShellExecute 0, vbNullString, "http://bbs.vbstreets.ru/profile.php?mode=viewprofile&u=" _
     & tData.ID, vbNullString, vbNullString, SW_SHOWNORMAL
    Case 2:
    ShellExecute 0, vbNullString, "mailto:" & tData.Mail, vbNullString, vbNullString,_
     SW_SHOWNORMAL
    Case 3:
    ShellExecute 0, vbNullString, "http://" & tData.Url, vbNullString, vbNullString,_
     SW_SHOWNORMAL
    End Select
    End Sub
    
    Private Property Get ISmartTagAction_Name(ByVal LocaleID As Long) As String
    ' Описание
    ISmartTagAction_Name = "VBS Forum Nicks Actions Class"
    End Property
    
    Private Property Get ISmartTagAction_ProgId() As String
    ' Уникальное имя
    ISmartTagAction_ProgId = "VBS_SmartTags.ActionClass"
    End Property
    
    Private Property Get ISmartTagAction_SmartTagCaption(ByVal SmartTagID As Long,_
     ByVal LocaleID As Long) As String
    ' Этот текст будет видеть пользователь в качестве заголовка
    ISmartTagAction_SmartTagCaption = "VBS Forum Nicks"
    End Property
    
    Private Property Get ISmartTagAction_SmartTagCount() As Long
    ' Количество распозноваемых типов SmartTags
    ' В нашем примере тип только один - ники модераторов
    ' форума VBStreets
    ISmartTagAction_SmartTagCount = 1
    End Property
    
    Private Property Get ISmartTagAction_SmartTagName(ByVal SmartTagID As Long) As String
    ' Название типов поддерживаемых SmartTags
    ' формат: namespaceURI#tagname
    Select Case SmartTagID
    Case 1:
    ISmartTagAction_SmartTagName = SchemaName
    End Select
    End Property
    
    Private Property Get ISmartTagAction_VerbCaptionFromID(ByVal VerbID As Long,_
     ByVal ApplicationName As String, ByVal LocaleID As Long) As String
    ' Название действия (VerbCaption), которое
    ' будет видеть пользователь
    Select Case VerbID
    Case 1:
    ISmartTagAction_VerbCaptionFromID = "Помотреть профиль на форуме"
    Case 2:
    ISmartTagAction_VerbCaptionFromID = "Послать письмо"
    Case 3:
    ISmartTagAction_VerbCaptionFromID = "Посмотреть домашнюю страницу"
    End Select
    End Property
    
    Private Property Get ISmartTagAction_VerbCount(ByVal SmartTagName As String) As Long
    ' Возвращаем количество выполняемых действий
    Select Case SmartTagName
    Case SchemaName
    ISmartTagAction_VerbCount = 3 ' всего три действия
    End Select
    End Property
    
    Private Property Get ISmartTagAction_VerbID(ByVal SmartTagName As String, ByVal_
     VerbIndex As Long) As Long
    ' ID действия
    ' у нас всего три действия для одного типа
    ' SmartTags поэтому Index = ID
    Select Case SmartTagName
    Case SchemaName
    ISmartTagAction_VerbID = VerbIndex
    End Select
    End Property
    
    Private Property Get ISmartTagAction_VerbNameFromID(ByVal VerbID As Long) As String
    ' Имя действия (VerbID)
    ' на каждое по своему имени
    ' в дальнейшем они используются в Office, например
    ' для взаимодействия VBA программам с этим компонентом SmartTags
    Select Case VerbID
    Case 1:
    ISmartTagAction_VerbNameFromID = "viewProfile"
    Case 2:
    ISmartTagAction_VerbNameFromID = "sendMail"
    Case 3:
    ISmartTagAction_VerbNameFromID = "viewHomePage"
    End Select
    
    End Property
    

    Вот как это выглядит "на натуре".

    Регистрация компонента

        Когда основа компонента создана, необходимо зарегистрировать скомпилированный файл в Office, что можно сделать добавив необходимые значения в реестр. Эти значения CLSID каждого из двух классов. Приведенный ниже файл редактора реестра позволит выполнить этот процесс очень просто и быстро.

    REGEDIT4
    
    [HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag]
    
    [HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Actions]
    
    [HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Actions\{ACTION_CLSID}]
    
    [HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Recognizers]
    
    [HKEY_CURRENT_USER\Software\Microsoft\Office\Common\Smart Tag\Recognizers\{RECOGNIZER_CLSID}]
    

        Чтобы зарегистрировать компонент необходимо в приведенном файле заменить {ACTION_CLSID} и {RECOGNIZER_CLSID} на соответствующие значения. Для этого можно использовать мою утилиту COMV, входящую в архив к статье, позволяющую получить значения CLSID.


        После этого сохраните reg файл с именем вашего компонента (или любым другим, лишь бы путанницы не было) и добавьте значения в реестр (двойной щелчок или RegEdit -> Import).

    Отладка

        Для отладки компонента необходимо его зарегистрировать в Office (см. выше) после чего указать в свойствах проекта (Project -> ProjectName Properties), что для отладки необходимо запускать Microsoft Word.

    Заключение

        Я специально не стал описывать все свойства и методы классов (интерфейсов), а лишь привел подробные комментарии и "рыбу" компонента, на основе которой можно создать такие же несложные компоненты, которых, обычно, вполне достаточно. Я не сделал этого только потому, что весьма подробное описание, хотя и на английском языке, существует в Smart Tag SDK, который можно найти на сайте Microsoft.com.