Дата публикации статьи: 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.
|