Microsoft Agent Technology Application
Realization principle of at theAgentshell
[Summary]
This article describes how to apply Agent and the implementation principle of AgentShell and several important technical processes.
[Key words]
Agent, COM, Role, Speech Recognition, Speech Synthesis.
The method for programming the Agent mainly uses the language of VB, VC and other languages, in addition to this, COM directly through VC
Programming call. Adding Agent in VB is the simplest, but because the VB program itself has many defects, it is difficult to apply in practice.
In VC, since the internal Unicode encoding is completely used, it also handles a variety of complicated COM interfaces, thereby also exists.
Problem. AgentShell is a shell bundle between Agent and applications, which can connect Agent complex COM.
The mouth is encapsulated, transforming into a simple function call, which is a good implementation of the Agent control. At the same time, AgentShell also acts as an independent process.
In order to handle English automatic reading, this article will detail its implementation principle.
(1) Principle introduction
The connection of AgentShell and Agent Server is implemented through COM calls, and communication with the application is through WM_COPYDATA
The message is implemented, the following figure shows the relationship between AgentShell and other programs:
[Agent Server]
|
[COM call]
|
[Agentshell]
|
[Message]
|
[ application ]
Load an Agent Control We call "role", usually use COM call to create an Agent role,
To pass through the following procedures:
[Initialization COM]
|
[Connect Agent COM Sever, create an Agent Control]
|
[Register Agent Control Message Reactor (Notify Sink)]
|
[Load role data file, create a role (character)]
|
[Set the language, initial position, and other properties]
|
[Display role]
The following global variables are defined in the AgentShell to control the properties and action of the role:
Role Message ID: long g_lnotifysinkid.
Role ID: long g_lmyagentid.
Agent Control Pointer: IAGENTEX * G_PAGENTEX.
Role pointer: IAGENTCHARACTEREX * G_PMYAGENT.
Role Message Reactor Pointer: AgentNotifyInsink * g_psink.
Use the above variables to easily call the Agent function, such as displaying the role:
Bool agentshow ()
{
HRESULT HRES;
Long Lrequestid;
IF (! g_pmyagent)
Return False;
HRES = g_pmyagent-> show (false, & lrequestid);
IF (Failed (HRES))
Return False;
Return True;
}
(2) Language processing of roles
At present, Agent supports many languages, not only shows, but also speech synthesis and speech recognition (for Chinese, currently only supports).
Language is also divided into primary language and subordinates (or subordinates), such as Chinese's primary language is Chinese (lang_chinese), and subordinates can be
Simplified (SUBLANG_CHINESE_SIMPLIFIED) and traditional. Two global variables are defined in the AgentShell:
Main language: DWORD G_NMAINLANG.
Sub-language: DWORD G_NSUBLANG.
In this way, different information must be displayed in accordance with the different language, such as the program exiting the greeting letter:
First define different language information, you can define or resource data for macro: #define mes_goodbyel "goodbye!"
#define mes_goodbye_ch L "Goodbye!"
#define mes_goodnightl "good night!"
#define mes_goodnight_ch L "I wish you good night!"
The following is an exit prompt code:
void goodbye ()
{
IF (g_bagentok)
{
SystemTime Time;
AgentStop ();
Agentshow ();
AgentPlay (L "Wave");
GetLocalTime (& Time);
/ / Different information according to time
IF (g_nmainlang == lang_english)
{
/ / Tip English information
IF (Time.Whour <19)
AgentSpeak (Mes_Goodbye);
Else
Agentspeak (MES_GOODNIGHT);
}
Else
{
/ / Tips Chinese information
IF (Time.Whour <19)
AgentSpeak (MES_GOODBYE_CH);
Else
AgentSpeak (MES_GOODNIGHT_CH);
}
Agenethide ();
// Wait for several times
Sleep (max_quit_time);
}
}
Of course, it is only a simple method described above, and is only to describe this principle.
(3) Realizing automatic reading English
Automatic reading is actually responding to the process of clipboard messages, when copying the selected text information, the system automatically sends WM_DRAWCLIPBOARD
The message gives all the windows in all clipboard monitor queues. The corresponding window will read it aloud as soon as you read the information in the current clipboard. The specific implementation is as follows:
Install clipboard monitoring:
void installclipspy ()
{
g_hnextwnd = setClipboardViewer (g_hmainwnd);
}
The corresponding clipboard message in the callback function of the main window:
Lresult Callback WndProc (HWND HWND, UINT MESSAGE, WPARAM WPARAM, LPARAM LPARAM)
{
// Clipboard window queue changes
Case WM_CHANGECBCHAIN:
HWndremove = (hwnd) wparam; // handle of window being removed
HWndNext = (hwnd) LPARAM;
IF (hwndremove == g_hnextwnd)
{
g_hnextwnd = hwndNext;
}
IF (g_hnextwnd)
{
SendMessage (HwndNext, WM_Changecbchain, WPARAM, LPARAM);
}
// Scrapped data changes
Case WM_DRAWCLIPBOARD:
/ / Do you automatically read
IF (g_benableread)
{
// Read clipboard information
Readcliptext ();
}
IF (g_hnextwnd)
{
SendMessage (G_HNEXTWND, WM_DRAWCLIPBOARD, WPARAM, LPARAM);
}
Get the clipboard information and read it carefully:
Void ReadCliptext ()
{
IF (g_bagentok)
{
// Read only text files
IF (IsclipboardFormatavailable (cf_text))
{
IF (OpenClipboard (g_hmainwnd))
{
LPWSTR PWSZ;
Uint CCH;
Hglobal hglb;
LPSTR LPSTR; HGLB = getClipboardData (CF_Text);
LPSTR = (LPSTR) GlobalLock (HGLB);
CCH = LSTRLEN (LPSTR);
IF (cch> 0)
{
PWSZ = New Wchar [CCH 1];
MultibyToWideChar (CP_ACP, 0, LPSTR, -1, PWSZ, CCH);
PWSZ [CCH] = '/ 0';
Agentsavestate ();
AgentPlay (L "read");
AgentSpeak (PWSZ);
AgentPlay (l "readreturn");
AgentRestorestate ();
DELETE PWSZ;
}
GlobalUnlock (HGLB);
CloseClipboard ();
}
}
}
}
Finally, you must move the current window handle from the clipboard monitor queue when you quit:
Void RemoveClipspy ()
{
ChangeClipboardchain (g_hmainwnd, g_hnextwnd);
}
(4) Interface with external programs
The transfer data between the application and the AgentShell is mainly implemented by the WM_COPYDATA message, due to the passed data type
There is different, so you need to define a data structure to describe:
Struct AgentActionstruct
{
Word naction;
DWORD ND1;
DWORD ND2;
Wchar SDATA [MAX_DATA_LEN];
}
NACTION is used to indicate an operation that Agent should perform, such as display, performance, etc. ND1, ND2, and SDATA are used to record passed data.
Passing messages must get the handle of the AgentShell main window, as follows:
HWnd getAgentMainWnd ()
{
Return FindWindow (Agent_Class_name, NULL);
}
Since Agent uses Unicode, the ANSI character must be converted to a Unicode character:
Bool SendmestoAgent (Word ND2, DWORD ND1, DWORD ND2, LPCSTR SDATA)
{
Uint nsize;
HWND HWND = GetagentMainWnd ();
IF (hwnd)
{
Action.nAction = nAction;
Action.nd1 = (dword) ND1;
Action.nd2 = (DWORD) ND2;
// Convert ANSI to Unicode characters
nsize = multibytetowideChar (CP_ACP, 0, SDATA, LSTRLEN (SDATA) 1,
Action.sdata, Max_Data_Len;
Action.sdata [nsize] = '/ 0';
//
CopyDataStruct CDS;
Cds.dwdata = (dword) 0;
Cds.cbdata = (dword) sizeof (action);
Cds.lpdata = (void *) & Action;
// Exchange data with AgentShell via WM_COPYDATA message
SendMessage (HWND, WM_COPYDATA, (WPARAM) NULL, (LPARAM) & CDS);
Return True;
}
Return False;
}
The function provided by AgentShell is mainly:
// Start the role shell (agentshell) BRUN is executed
Bool Agentapirun (Bool Brun = True); // Exit Role Housing (AgentShell)
Bool agentapiExit ();
// Create a new role (Spath Role Data File Path, NSUBLANG Language)
Bool AgentApicreate (LPCSTR Spath, Uint NLANG, UINT NSUBLANG);
/ / Set the role name (Sname role name)
Bool AgentapiSetName (LPCSTR sname);
// Uninstall the role
Bool agentapiunload ();
// Display role
Bool ageapishow ();
// Hide role
Bool agentapihide ();
// Show or hide the role
Bool agentapishoworhide ();
// Stop role performance
Bool ageapistop ();
// Role show (SACTION action name)
Bool AgentapiPlay (LPCSTR SACTION);
// Role Speech (Stext sentence)
Bool Agentapispeak (LPCSTR Stext);
// Role 鞠 (x, y "direction)
Bool Agentapigesat (Word X, Word Y);
/ / Mobile role to the specified location (coordinate of x, y)
Bool Agentapimoveto (Word X, Word Y);
/ / Save the current role display status
Bool ageapisavestate ();
// Restore the status of the role
Bool agentapirestorestate ();
// Allow automatic reading
Bool agentapienableautoread ();
// Do not automatically read
Bool ageapidisableautoread ();
Note that the data passed to the AgentShell should not exceed 1K (actually generally not more than 1k).
2) Use the interface
With the interface functions described above, the control of the Agent is very simple, the following is an example of a simple greeting:
// Start AgentShell
IF (Agentapirun (TRUE))
{
/ / Save the status of the current Agent
Agentapisavestate ();
// Start performance
AgentapiPlay (_T ("Greet"));
// Speech
Agentapispeak (_T ("Hello, My Friend."));
// End of performance
AgentapiPlay (_T ("GreetReturn"));
// Restore the original state
AgentapiRestorestate ();
// drop out
AgentapiExit ();
}
AgentShell has been very good in the author's free software "My Assistant", of course, is currently only a small part of the Agent, as well as speech recognition, nothing to do, and to be improved. The above programs are compiled by Visual C 6.0, and the source code can be downloaded to the House of Assistant (http://www.helperhome.com).