Using Microsoft Agent

This article demonstrates how to implement the Microsoft Agent into your own applications.


This article originally appeared in Delphi Developer



Copyright Pinnacle Publishing, Inc. All rights reserved.



USING MICROSOFT AGENT IN DELPHI

by Clay Shannon





When I tell people how fun and effective it is to use Microsoft Agents in my programs, they either already know what I'm talking about and heartily agree, or they look at me as if I just fell off the back of a rutabaga truck and say something like: "You mean that paperclip guy who makes Twiggy look like a sumo wrestler?! I hate that guy!" Well, I'm not overly fond of those Agents, either. If when you hear "Microsoft Agent" you think of the "Office Agents", such as "that paperclip guy" in the ugly dialog box who's always pestering you with questions like "it looks like you're doing this, do you want me to help?", and "it looks like you're doing that, do you want help, huh? huh?", you're thinking of a different breed of Microsoft Agent than those which will be discussed in this article. Aren't you glad?



These Agents are not trapped inside a dialog box, and they appear when and where you tell them to, and say exactly what you program them to say. So let's introduce them. They are: Peedy (the Bird), Robby (the Robot), Merlin (the Magician), and Genie (the... well, the Genie):





Are these "cute" little characters of any practical value? In some programs, indubitably not. In others, though, they can not only add appeal (depending on the user's preferences, of course) but also be of use in helping the user learn to use the program and make it through "the rough spots". I tend to think of the Agents as a sort of "Master of Ceremonies". They can be used to introduce the user to the program - what does it do? How can you use it? They can be utilized as an adjunct to, or even a replacement of, a help file. Additionally, the Agents have a great potential, or future, as "guides" in CBT (Computer-Based Training) and in demo programs.



Not all machines will have the Microsoft Agents installed. If you're not sure whether your users will have the Agents installed or not, you have two options: distribute the agents to your users in case they don't have them, or write your code in such a way that it is transparent to the Agent-less users that your program is even able to use Agents ("they don't know what they're missing"). To deploy the agents, you must go to Microsoft's Agent web site, download a form, fill it out, send it to them, etc. in order to get permission to distribute the agents. I don't know about you, but for me that is, in the words of Chuck Berry "too much monkey business". I opt to code for either situation: if they have the Agents installed, they will see them, otherwise they won't.



The first thing you as a developer need to know is to download and install the Agent technology yourself, if you have not done so already. The Agent components are available at http://msdn.microsoft.com/workshop/imedia/agent/default.asp



The most pertinent downloads there are:


  1. The Agent Server
  2. The characters/Agents
  3. A Text-to-Speech piece
  4. Voice command (input) piece



This article will not deal with the Voice Command download and functionality (repeat after me: "that is an exercise left to the reader"). The site also contains info about a new book entitled "Microsoft Agent Software Development Kit" and you can also download the Microsoft Agent Character Editor (software) for creating your own agents. This is "beyond the scope of this article" and is thus also "left as an exercise..." - well, you know the rest. Let's get down to "business", or fun, or whatever it is we're having here (funsiness?).



The only downloads you will absolutely need are the Agent Server and one character. I recommend downloading all the characters and the Text-to-Speech functionality, though.



The download from Microsoft installs and registers the Agent server on your machine. What's left for you to do is install the Agent control into Delphi. To do so, follow these steps:


  1. Select Component | Import ActiveX Control
  2. Locate the Microsoft Agent Control from the list box and select the Add button



The Agent should now be installed on your ActiveX page:



If you drop this control on a form, you will see that a component of type TAgent is added to your form's definition. However, if we are not sure whether the user will have the Agent server installed on their machine, we will want to create the Agent dynamically. Not doing so can cause the same problem as having a statically loaded .DLL that is not found by the application on the user's machine. We will first check for the existence of the Agent technology, and only then create the Agent, if such exists.



Add a Boolean field to your form which reflects the state of Agent technology presence. For example, this could be a field called AgentInstalled. This is shown below along with other Agent-specific Boolean fields and their corresponding public properties that you may want to declare:





TYourObject

  private

    AgentInstalled: Boolean;

    function AgentIsInstalled: Boolean;

    procedure CreateAndLoadAgentIfInstalled;

    function GetColorDepth: Word;

    function GetWinDir: String;

    procedure SetFormColor;

    function AgentWasClicked



         

You can populate this field with its appropriate value with a procedure that checks for the existence of the Agent files on the user's machine. For example, if you're using Robby (the Robot) as your Agent, your code might look like this:





{----------------------------------------------------------------}

function TYourObject.AgentIsInstalled: Boolean;

begin

  Result := (FileSearch('Robby.acs', Format('%s\MSAGENT\CHARS',

    [GetWinDir]))<>'');

end;



{----------------------------------------------------------------}

function TYourObject.GetWinDir : string;

var

  WinDirZ : array[0..256] of Char;

begin

  GetWindowsDirectory(WinDirZ, SizeOf(WinDirZ));

  Result := StrPas(WinDirZ);

end;





NOTE: Don't assume that the agents have been downloaded to their "normal place" on the user's machine C:\WINDOWS\MSAGENT\CHARS).

We all know what can happen (and usually eventually does) when we assume too much. So, you can use the GetWinDir function above along with the call to FileSearch to find the Windows directory on the user's machine.




As we are going to create the Agent component dynamically, don't place an Agent ActiveX control on the form. Instead, add the OLECtrls and AgentObjects_TLB units to the implementation uses clause of the form[s] on which you want to use the agent:



implementation



uses

  AgentDemoConsts,

  Registry,

  OLECtrls, AgentObjects_TLB;



You can then dynamically create the Agent component in this way:



{-----------------------------------------------------------------}

procedure TYourObject.CreateAndLoadAgentIfInstalled;

const

  RightBias = 80;

  TopBias = 70;

var

  tp: TPoint;

begin

  if (AgentInstalled) and not (Assigned(RobotAgent)) then begin

    RobotAgent := TAgent.Create(Application);

    RobotAgent.Characters.Load('Robby','Robby.acs');

    { Move the Agent to the center of the screen }

    tp.x := (Screen.Width div 2)-(Width div 2);

    tp.y := (Screen.Height div 2)-(Height div 2);

    with RobotAgent.Characters.Item['Robby'] do begin

      MoveTo(tp.x+RightBias, tp.y+TopBias, 0);

      Show(0);

      Play('Greet');

      Play('Explain');

      Speak(SDemoIntro, '');

      Play('Pleased');

      Play('RestPose');

      Speak(SWhisper, '');

      Speak(SMonotone, '');

      Speak(SMap, '');

      { You can have him filibuster and gesture like a madman if

        you want... }

    end;

  end;

end;





Adding expression

There are several special speech/text options that you can use to more exactly control how the Agent speaks. For example, you can make him whisper, speak in a monotone, pause, emphasize a certain part of his oratory, or even have him say one thing while the balloon above his head reads differently. You could use the latter functionality to have him speak in English, and show the translation into another language in the balloon. Or, you could go the "Mad magazine" route and have him say one thing while thinking another. These capabilties are available through the following additions:









\Chr='Whisper"\ The Agent will whisper the following text
\Pau=N\ The Agent will pause for the designated number of milliseconds
\Emp\ The Agent will give special emphasis to the following phrase
\Chr="Montone"\ The Agent will emphasize nothing at all
\Map== The Agent will say one thing, and "think" another.





Here are some examples of using these speech "qualities":



SFuzzyWuzzy = 'Fuzzy wuzzy was a bear;\Pau=500\ fuzzy wuzzy had no ' +

  'hair;\Pau=500\fuzzy wuzzy wasn''t very \Emp\fuzzy, ' +

  '\Emp\was he?';



SWhisper = '\Chr="Whisper"\Now I will whisper: Whisper whisper ' +

  'whisper.';



SMonotone = '\Chr="Monotone"\Now I will speak in a monotone. Pat ' +

  'Paulsen for President.';



SMap = '\Map="I will now continue to speak in English, but you will '+

  'see my words translated into German in the ballon above my ' +

  'head. ' +

  'How are you today? I am just \Emp\dandy!"="Jetzt werde ich ' +

  'zwar immer noch in Englisch reden, sie werden aber meine ' +

  'Woerte im Ballon obenauf ins Deutsch uebersetzt sehen. ' +

  'Wie geht es Ihnen heute? Mir geht es ganz gut!"\';



Note: Not all actions (arguments passed to the Play method) are available for all Agents. See the corresponding documentation contained in the Microsoft files downloaded with the Agent to see which characters (Agents) support which actions.



Interaction

If you want to respond to the Agent's events, you can hook these up by following these steps:


  1. Drop an Agent component on a form.
  2. Go to the Object Inspector's event page
  3. Click the event you want to handle
  4. Copy its method signature (to the clipboard, to Notepad, or whatever)
  5. Add a method with that signature to your form's declaration
  6. After creation of the Agent, assign your method to the event you want to handle.



For example, if you want to handle the Agent's OnClick event, write a method with this signature:



procedure AgentWasClicked(Sender: TObject;

  const CharacterID: WideString; Button, Shift, x, y: Smallint);





Make the assignment of the event handler to your method directly after creating the Agent:



RobotAgent := TAgent.Create(Application);

RobotAgent.OnClick := AgentWasClicked;





and then write the definition for the event handler in the unit's implementation section:



procedure TYourObject.AgentWasClicked(

  Sender: TObject;

  const CharacterID: WideString;

  Button, Shift, x, y: Smallint);

begin

   ShowMessage('Don''t touch me there!');

end;



{----------------------------------------------------------------}

function TfrmAgent.UsersName: String;

var

  Buff: DWord;

  CharArray: array[0..255] of Char;

begin

  Buff := SizeOf(CharArray);

  GetUserName(CharArray, Buff);

  Result := CharArray;

end;





Clay Shannon is an independent Delphi consultant based in northern Idaho. He is available for:



1) Delphi consulting work in the greater Spokane/Coeur d'Alene areas

2) Remote development (no job too small!)

3) Short-term or part-time assignments in other locales.



Clay is a certified Delphi 5 developer, and is the author of Developer's Guideto Delphi Troubleshooting [Wordware, 1999]. You can reach him at BClayShannon@aol.com

 

Share this article!

Follow us!

Find more helpful articles: