利用Microsoft Agent的COM接口编程
副标题#e#
Microsoft Agent具有相当遍及的用途,我们既可以把它插手到普通应用措施中供当地系统利用,也可以把它嵌入到HTML文档中供Internet/Intranet利用。Microsoft Agent支持C/C++、Visual Basic、Java、JScript和VBScript等多种编程语言,并为措施员提供了OLE自动化处事器和ActiveX控件两种编程要领,从本质上讲,这两种编程要领都属于OLE技能的领域,都成立在COM (Component Object Model,组件工具模子)的基本之上。操作VC++的MFC类库或VB等支持ActiveX的编程东西可以很容易地挪用ActiveX控件,可是ActiveX控件把很多OLE技能的细节都埋没起来了,假如我们想加深对一个COM工具的相识的话,则应直接利用它的COM接口来编程,从这一点出发,本文将先容Microsoft Agent的COM接口的根基编程要领,但愿可以或许起到抛砖引玉的浸染。
OLE编程的基本常识
早期的OLE(现称为OLE 1)首次呈此刻Windows 3.1中,其主要用途是生成复合型文档,使得一个应用措施的文档可以通过链连或嵌入的方法包括其它应用措施的数据(工具)。跟着软件组件技能变得日益重要起来,Microsoft在OLE 1
的基本上设计了OLE 2,操作它可以实现二进制级上可重用的软件组件,而且节制这些组件的版本和扩充其成果变得相当容易。由于OLE 2的体系布局被设计成为开放式的、可扩充的,所以今后不会再呈现OLE 3或4。颠末多年的成长,如今的OLE已经包罗了OLE自动化、COM、COM+、DCOM和ActiveX等多项技能,它们是ActiveDirectory(将用于NT 5.0的一项要害技能)、OLE Messaging、DirectX 、Active Controls、ActiveX Scripting和Task Scheduler等等多种新技能的基本,OLE已不再是Object Linking and Embedding的缩写,它酿成了一个独立的单词,专门用来暗示Microsoft的软件组件集成技能。
COM是OLE技能的基本,它划定了工具之间如何彼此通讯,切合COM类型的工具也叫做COM工具。凭据COM的划定,工具内部可以利用任何语言来编写,它们通过接口(Interface)来与外界通信。所谓接口是指工具提供的一组特定的成果挪用(要领),每个工具可以有多个接口,差异的工具可以实现同一种接口,客户措施通过工具的接口指针来挪用工具的成果。由于OLE划定了组件在二进制级上可重用,客户措施不可以或许直接会见工具内部的数据,读取或配置工具的属性也都要通过接口来举办。每一种接口都是从一个叫IUnknown接口担任而来,都必需从头实现IUnknown的三个要领:QueryInterface、AddRef和Release,客户措施挪用QueryInterface可以得到工具的其它接口指针,AddRef和Release别离将工具的引用计数加一和减一,当引用计数为零时,工具就会被释放。客户措施挪用COM工具的一般步调是首先建设一个工具,然后获取需要的接口指针,挪用相应的成果,最后释放接口指针和工具。
C++措施挪用Microsoft Agent的根基要领
按照前面先容的基本常识,下面我们来看看C++措施中如何挪用Microsoft Agent。
1.配置与选项
本文利用的编程东西为Visual C++ 5.0,措施为一般的Win32应用措施,为了使措施可以或许正确地编译毗连和运行,您首先需要拥有AgtSvr.h和AgtSvr—i.c两个界说Microsoft Agent的COM接口的文件,它们可以在Microsoft的MS Agent站点(http://www.microsoft.com/workshop/
prog/agent/)上找到,可能请下载Microsoft最新的Internet Client SDK或Platform SDK,其次,请在Project/Settings/Link菜单中插手以下的库:ole32.lib、oleaut32.lib、uuid.lib、odbc32.lib odbccp32.lib,最后要确保系统中安装有Microsoft Agent及动画人物数据。
2.建设Microsoft Agent工具
建设OLE工具之前需要初始化OLE,这由OleInitialize()函数来完成,假如OLE初始化不乐成,那么就无法继承执行后头的代码,建设工具由CoCreateInstance()函数来完成:
if (FAILED(OleInitialize(NULL))) return -1;//初始化OLE
hRes = CoCreateInstance(CLSID—AgentServer,NULL,CLSCTX—SERVER,IID—IAgent,(LPVOID *)&pAgent);//建设Microsoft Agent Server的实例
if (FAILED(hRes)) return -1;
CoCreateInstance()的第一个参数是工具的CLSID(类代码),Microsoft Agent Server的CLSID为界说在AgtSvr—i.c文件中的CLSID—AgentServer,这个128位的编码独一地标识了Agent处事器,处事器地址路径和运行参数等信息都放在系统注册表中;第二个参数一般环境下设为NULL;第三个参数用来指明工具的运行情况,如长途或当地,此处设为CLSCTX—SERVER;第四个参数指明用来与工具通信的接口的ID,这也是一个128位的编码,Agent的接口ID为IID—IAgent;第五个参数是用来吸收IAgent的接口指针。
#p#分页标题#e#
假如Microsoft Agent Server还没有在内存中运行,那么CoCreateInstance()会启动它并建设一个Agent工具,假如处事器已经运行了,则CoCreateInstance()会与之毗连并建设一个Agent工具。当所有的Agent工具都被释放了后,处事器自动退出。
#p#副标题#e#
3.装入动画人物数据
下面的代码挪用IAgent::Load()要领来装入一个动画人物的数据,由于Agent处事器在本身的内存空间中运行,所以传送的字符串变量需要用SysAllocString()来分派内存:
VariantInit(&vPath); //初始化OLE变量
vPath.vt = VT—BSTR; //指明变量范例为Unicode的字符串
vPath.bstrVal=SysAllocString(kpwszCharacter);
//kpwszCharacter为动画人物数据的存放路径
hRes = pAgent->Load(vPath,&lCharID,&lRequestID);
//装入数据,人物ID在lCharID中返回
hRes = pAgent->GetCharacter(lCharID,&pdCharacter);
//获取lCharID的IDispatch接口指针挪用IDispatch::QueryInterface()要领可以获得 //IAgentCharacter的接口指针:
hRes = pdCharacter->QueryInterface(IID—IAgentCharacter, (LPVOID *)&pCharacter);
pdCharacter->Release(); //释放IDispath
通过IAgentCharacter接口就可以挪用动画人物支持的各类要领了:
hRes = pCharacter->Show(FALSE, &lRequestID);//显示动画人物
hRes = pCharacter->MoveTo(320,240,100,&lRequestID); //移动动画人物到屏幕中央
bszSpeak = SysAllocString(L"Hello World!"); //分派字符串
hRes = pCharacter->Speak(bszSpeak, NULL, &lRequestID); //让动画人物措辞
SysFreeString(bszSpeak); //释放字符串所占内存
4.释放工具
措施在退出之前需要把建设的Agent工具释放:
if (pCharacter) {
pCharacter->Release(); //释放IAgentCharacter接口
pAgent->Unload(lCharID); //卸载动画人物数据
}
pAgent->Release(); //释放Agent工具
VariantClear(&vPath); //排除OLE变量
进一步的编程要点
前面先容的是挪用Microsoft Agent处事器最根基的一些步调,为了完成较量实际的任务,客户措施还应按照本身的环境思量下面的一些编程要点。
1.查抄Agent Server的版本
OLE要求组件或工具具有向后兼容性,高版本工具支持低版本工具的所有接口和属性,这样可以很利便地举办组件进级。客户措施凡是应查抄工具的版本,只有系统中安装的工具的版本号高于或便是所期望的版本号时才气挪用工具。下面的IsValidAgentVersion()函数查抄Microsoft Agent的版本号,并将它与界说在AgtSvr.h文件中的版本号对较量:
BOOL IsValidAgentVersion(IAgent *pAgent) {
IDispatch *pdAgent = NULL;
ITypeInfo *pTypeInfo = NULL;
ITypeLib *pTypeLib = NULL;
TLIBATTR *pTypeLibAttr = NULL;
BOOL bValid = FALSE;
UINT uiIndex;
pAgent->QueryInterface(IID—IDispatch, (LPVOID *)&pdAgent);
pdAgent->GetTypeInfo(0, 0, &pTypeInfo); //取得范例信息
pTypeInfo->GetContainingTypeLib(&pTypeLib, &uiIndex);//取得范例库
pTypeLib->GetLibAttr(&pTypeLibAttr); //取得范例库中的属性
if ((pTypeLibAttr->wMajorVerNum > AGENT—VERSION—MAJOR) ||((pTypeLibAttr->wMajorVerNum == AGENT—VERSION—MAJOR) &&(pTypeLibAttr->wMinorVerNum >= AGENT—VERSION—MINOR)))
bValid = TRUE; //期望的版本号界说在AgtSvr.h文件中
if (pTypeLib) {
if (pTypeLibAttr) pTypeLib->ReleaseTLibAttr(pTypeLibAttr);
pTypeLib->Release(); }
if (pTypeInfo) pTypeInfo->Release();
if (pdAgent) pdAgent->Release();
return bValid;}
2.实现IAgentNotifySink接口
为了可以或许处理惩罚用户的输入,相识Agent工具的状态,客户措施应实现IAgentNotifySink接口来吸收Agent工具的事件。IAgentNotifySink的声明和缺省实现可以在Platform SDK或Internet Clinet SDK中的Notify.h和Notify.cpp中找到,客户措施应按照需要修改某些事件的处理惩罚函数
。下面的代码向Agent工具注册IAgentNotifySink接口,个中AgentNotifySink是从IAgentNotifySink担任而来:
pSink = new AgentNotifySink;
pSink->AddRef(); //增加引用计数
hRes = pAgent->Register((IUnknown *)pSink, &lNotifySinkID);//举办注册
...
if (pSink) {
pAgent->Unregister(lNotifySinkID); //注销IAgentNotifySink接口
pSink->Release(); }
#p#分页标题#e#
客户措施最感乐趣的两个事件是RequestComplete和Command。Agent处事器回收异步方法来处理惩罚客户措施的各类请求,这样客户措施可以在请求处事的同时举办本身的事情,当处事器完成一项请求时就会引发RequestComplete事件,客户措施可以判定是哪一项请求已经竣事,并做相应的处理惩罚。Command事件是当用户利用鼠标或麦克风向动画人物发出呼吁时引发的,客户措施可以通过IAgentUserInput接口来相识呼吁的详细信息。
3.自界说呼吁
Agent处事器为每个动画人物都提供了一些缺省的呼吁,这些呼吁呈此刻关联菜单或呼吁窗口中,客户措施可以通过IAgentCommands接口添加自界说呼吁。
为了获得IAgentCommands的接口指针,应利用参数IID—IAgentCommands来挪用IAgentCharacter::QueryInterface(),IAgentCommands的Add()或Insert()要领可以插手自界说呼吁,同时配置Caption、Visible和Voice属性,指明该呼吁是否显示出来,显示在关联菜单中照旧在呼吁窗口中。
Agent处事器为每个呼吁赋予一个ID值,客户措施可以利用这个ID值挪用IAgentCommands::GetCommand()要领,获得每个呼吁的IAgentCommand接口指针,从而对单个呼吁的各类属性举办调解。
4.WAV文件取代语音合成
Microsoft Agent今朝只支持英语的语音合乐成能,要输出中文时只能用WAV文件来取代。假如给IAgentCharacter::Speak()要领的第二个参数通报一个WAV文件的路径,那么Agent处事器自动播放这个WAV文件,并在文字气球中显示出第一个参数中包括的文字,假如给第二个参数通报一个带音节信息的LWV文件的路径,则不需要在第一个参数中提供文字,因为LWV文件中包括有文字信息。当利用LWV文件时,动画人物的嘴部行动能与输出的语音保持一致,所以在大概的环境应该只管利用LWV文件,这种名目标文件可用Microsoft Agent Linguistic Information Sound Editing Tool编辑WAV文件来生成。
5.其它一些COM接口
除了前面提到的接口外,Agent处事器尚有其它一些COM接口。IAgentCommandWindow答允客户措施会见或配置呼吁窗口的属性,包罗位置、巨细和是否可见。IAgentSpeechInputProperties答允客户措施会见语音输入成果的属性,个中大部门属性都是只读的。IAgentAudioOutputProperties答允客户措施读取语音输出成果的部门属性。IAg
entPropertySheet答允客户措施会见或配置Agent处事器的属性表。IAgentBalloon答允客户措施会见文字气球的属性,可以配置少数属性,如是否可见和字体名称。关于这些接口的详细界说和用途请参考Microsoft Agent的辅佐文档。
总 结
Microsoft Agent是一项较新的技能,它属于OLE的领域,涉及较深的编程理论,本文所先容的只是从OLE自动化处事角度出发的最根基的利用要领。