MS Agent
в Delphi
MS Agent - это обычный
активный элемент ActiveX. Этот компонент активно используется Microsoft
в пакете MS Office. Да, MS Agent это та самая скрепка, кошка, собачка
или кто там у вас... появляющаяся при загрузке приложений MS Office.
Если вы уже скачали
и установили MS Agent v2.0, то приступим к установке его в среду
Delphi, else goto Насосная
станция.
Запустите Delphi,
откройте меню Component и выберите Install ActiveX control...
Попытайтесь найти в списке Microsoft Agent Control 2.0 (Version 2.0),
если его там нет, то нажмите кнопку Add и найдите вручную файл Agentctl.dll.
Теперь можно нажимать кнопку Install...

По умолчанию компонент
помещается на вкладку ActiveX (а на какую еще нормальный ActiveX может
поместиться?). Все! Теперь можно приступать непосредственно к программированию.
MS
Agent имеет большое количество интерфейсов, но для начала нам понадобится
немногое:
Теперь пропишем
обработчик события OnCreate главной формы.
procedure TForm1.FormCreate(Sender: TObject);
begin
Agent1.Characters.Load('MyAgent', 'Genie.acs');
{Здесь мы загружаем персонаж из файла 'merlin.acs' под именем 'Merlin'.
Вы можете здесь вписать свое имя и имя файла, имеющегося у вас персонажа}
Chars:= Agent1.Characters.Character('MyAgent') as IAgentCtlCharacterEx;
{Запоминаем персонаж в переменной Chars}
Req:=Chars.Show(0);
{Наконец-то показываем персонаж, и запоминаем, что он делает в данное вермя.
Будем всегда так поступать, т.к. это понадобится, если мы вдруг пожелаем
остановить анимацию в ходе ее выполнения}
end;
Не забудьте прописать
выгрузку персонажа при закрытии формы:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Agent1.Characters.Unload('MyAgent');
end;
Скомпилируйте и
запустите проект. Ну как?
А теперь давайте
попробуем сделать загрузку персонажа во время работы программы. То есть
дадим возможность пользователю загружать персонаж самостоятельно из
имеющихся у него на компьютере. Кстати, сейчас мы указывали только имя
файла при загрузке пресонажа, без его пути. Поэтому сначала система
будет искать персонаж в подпапке каталога с Windows "C:\Windows\MSAgent\Chars\",
а если не найдет, то будет error.
Поместим на форму
компонет OpenDialog, укажем маску файлов *.acs. Затем поместим на форму
батон (ну, то есть Button) и определим обработчик события на щелчок
мыши:
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then //Если выбрали файл
begin
if Chars<>nil then {Если какой-то персонаж загружен, выгружаем его}
Agent1.Characters.Unload('MyAgent');
Agent1.Characters.Load('MyAgent', OpenDialog1.FileName);
Chars:= Agent1.Characters.Character('MyAgent') as IAgentCtlCharacterEx;
Req:=Chars.Show(0);
end;
end;
Теперь давайте поперемещаем
наш персонаж по экрану. К примеру, вписываем в два поля редактирования
координаты позиции агента, и по клику соответстующей кнопки персонаж
перелетает на новое место. Два Edit'а обзовем PosX и PosY, а в OnClick
"соответствующей кнопки" запишем:
procedure TForm1.Button2Click(Sender: TObject);
begin
Chars.Stop(Req);
{Останавливаем выполняемое действие.
Правда остановим его,в том случае если мы его запоминали}
Req:=Chars.MoveTo(StrToInt(PosX.Text), StrToInt(PosY.Text), 1);
end;
Надеюсь, вы не догадаетесь
ввести в поля редактирования буковки, ведь это место не защищено от
подобных ситуаций. Вы, наверное,поняли, что метод MoveTo персонажа перемещает
его в позицию X, Y. Третий целочисленный параметр указывает с какой
скоростью нужно перемещать персонаж. Чем больше число, тем медленнее
перемещается агент. При нуле персонаж будет перелетать мнгновенно.
Еще одно интересное
замечание. Анализируя значение Req.Status можно выяснить следующую информацию
о запросе к MS Agent'у:
Теперь попробуем
сделать так, чтобы при загрузке персонажа в ListBox помещались названия
всех анимаций, а по выделению одной из анимаций в списке, она выполнялась
персонажем. Сначала создадим процедуру вывода всех анимаций. Например
вот так:
procedure ShowAgentAnim;
var
AEnum: IEnumVariant;
flag: Cardinal;
V: OleVariant;
begin
with Form1 do
begin
AEnum:=(Chars.AnimationNames.Enum) as IEnumVariant;
{Получаем интерфейс анимаций агента}
AEnum.Reset; //Сбрасываем список на первую анимацию
ListBox1.Items.Clear;
repeat
AEnum.Next(1, V, flag);
if VarToStr(V) <> '' Then
ListBox1.Items.Add(V);
until flag=0;
{Флажок будет равен 0, когда мы узнали имя последней анимации}
end;
end;
Еще одно отступление.
Попробуйте сейчас скомпилировать проект. Если Delphi показывает ошибку в строчке
AEnum: IEnumVariant
- необъявленный идентификатор, то наверняка в списке включаемых модулей в
секции uses отсутствует модуль ActiveX. Включите его вручную, и ошибка
изчезнет, так как IEnumVariant
объявлен именно в этом модульке.
Однако,
замечено странное явление в Delphi7. Об этом многие писали мне,
а так же в гостевой. В этой процедуре программа падает при выполнении
в строке:
AEnum:=(Chars.AnimationNames.Enum)
as IEnumVariant;
Падает с
самым общим исключением EAccessViolation. Такое явление наблюдается
только в Delphi7. При компиляции на Delphi6 в Win2000 - все
нормально, а в Delphi5 на Win98 - тем более. До сих пор не разобрался
точно в чем причина. Но есть некоторое решение проблемы. Я попробовал
в Delphi7 на WinXP файлы созданные при импортировании агента
(AgentObjects_TLB.pas, AgentServerObjects_TLB.pas - в папке
$Delphi\Imports) заменить файлами, созданными в Delphi5. На моей системе заработало,
пишите, кому помогло, а кому нет. На всякий случай выкладываю эти файлы, если
у кого нет. Качать здесь!
Теперь придется вставить
нашу процедуру создания списка анимаций в обработчик события создания формы
и в процедуру загрузки персонажа. Таким образом наши процедурки примут вид:
procedure TForm1.FormCreate(Sender: TObject);
begin
Agent1.Characters.Load('MyAgent', 'Genie.acs');
Chars:= Agent1.Characters.Character('MyAgent') as IAgentCtlCharacterEx;
ShowAgentAnim; //Создаем список анимаций
Req:=Chars.Show(0);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
if Chars<>nil then
Agent1.Characters.Unload('MyAgent');
Agent1.Characters.Load('MyAgent', OpenDialog1.FileName);
Chars:= Agent1.Characters.Character('MyAgent') as IAgentCtlCharacterEx;
ShowAgentAnim; //Создаем список анимаций
Req:=Chars.Show(0);
end;
end;
Ну и наконец создадим
процедуру проигрывания анимаций по клику в ListBox'е:
procedure TForm1.ListBox1Click(Sender: TObject);
begin
Chars.Stop(Req);
Req:=Chars.Play(ListBox1.Items.Strings[ListBox1.ItemIndex])
end;
Самым интересным
методом у MS Agent является , наверное, метод Speak:
function
Speak(Text: OleVariant; Url: OleVariant): IAgentCtlRequest;
Персонаж прочитает
вам голосом введенный текст. Правда для этого вам придется установить
пакет речевых функций Speech API и какой-нибудь голосовой синтезатор
- движок Text-To-Speech (TTS). Подробнее программирование речи в Delphi
мы резберем в следующем резделе Speech API в Delphi, там мы продолжим
совершенствовать проект, а сейчас посмотрим как синхронизировать два
персонажа между собой, то есть попробуем устроить между ними небольшой
диалог.
Естественно, что
нам понадобится еще одна переменная Chars2:
IAgentCtlCharacterEx,
а для того чтобы достичь "понимания" между двумя персонажами
такой вот метод:
function
Wait(const WaitForRequest: IDispatch): IAgentCtlRequest;
Сохраните как-нибудь
текущий проект, я, к примеру, его обозвал AgentTest, и попробуйте создать
новый проект с таким кодом в создании формы:
procedure TForm1.FormCreate(Sender: TObject);
begin
Agent1.Characters.Load('MyAgent', 'Genie.acs');
Chars:=Agent1.Characters.Character('MyAgent') as IAgentCtlCharacterEx;
Chars.MoveTo(200, 200, 1);
Chars.Show(0);
Chars.Set_LanguageID($419);//Меняем язык на русский
Agent1.Characters.Load('MyAgent2', 'Merlin.acs');
Chars2:=Agent1.Characters.Character('MyAgent2') as IAgentCtlCharacterEx;
Chars2.Set_LanguageID($419);
Chars.Speak('Привет! '+Chars.Get_Description, '');
Chars.Play('GestureLeft');
Chars2.Wait(Chars.Speak('А вот и мой друг Мерлин!', ''));
{Мерлин ждет пока его представит Джинн}
Chars2.MoveTo(400, 200, 0);
Chars2.Show(0); //А теперь появляется сам Мерлин
Chars.Play('RestPose');
Chars2.Speak('Привет!', '');
Chars.Play('LookLeft');
Chars.Wait(Chars2.Speak('Спасибо за представление!', ''));
Chars2.Wait(Chars.Play('Acknowledge'));
Chars.Play('LookLeft');
Chars.Wait(Chars2.Speak('Привет! '+Chars2.Get_Description, ''));
Chars2.Wait(Chars.Play('Congratulate'));
Chars.Play('RestPose');
Chars2.Speak('Пока!', '');
Chars2.Play('Wave');
Chars2.Hide(0);
end;
На этом ,пожалуй,
можно закончить. Думаю, теперь вам стали понятны основные принципы программирования
агентов.
Готовые проекты
можно скачать здесь:
Проект AgentTest
(~200Кб) и AgentDialog (~187Кб)