这是使用Microsoft Agent控件的主程序文件。编译后,总是在函数AgChr_Load()中的“注册 IAgentNotifySink 接口”处失败,初步的推测是,函数AgChr_Load()中“初始化 IAgentNotifySink 接口”部分,语句“InitIAgentNotifySink( &g_AgNSink );”并没有成功的创建IAgentNotifySink接口的实例,但我目前还不知道如何解决这个问题。
/**************************************************************************
* AgentSvr.c
*
* 本模块创建 Microsoft Agent Server 控件实例,加载 Agent 角色 Peedy,
* 添加自定义菜单命令,并处理命令事件。
* 由于 Agent 服务器在自己的内存空间中运行,所以传送的字符串变量需要用
* SysAllocString( ) 来分配内存,并用 SysFreeString( ) 释放。使用这两个函数
* 需要链接库文件 oleaut32.lib。
**************************************************************************/
#include "Resource.h"
#include "AgentSvr.h"
#define LoadWStr( id, pBuf ) LoadStringW( g_hInst, (id), (pBuf), sizeof(pBuf) )
#define LoadStr( id, pBuf ) LoadString( g_hInst, (id), (pBuf), sizeof(pBuf) )
#define ErrMsg( s ) MessageBox( g_hwndMain, (s), "哦喔……", MB_OK|MB_ICONINFORMATION )
#define ErrStr( id, pBuf ) LoadStr( (id), (pBuf) ); ErrMsg( pBuf )
#define ZeroMem( p ) memset( (p), 0, sizeof( p ) )
#define AGENT_VERSION_MAJOR 2
#define AGENT_VERSION_MINOR 0
#define MENU_SUM 5
#define BUF_SIZE 256
// Extern varibles
extern HINSTANCE g_hInst;
extern HWND g_hwndMain;
// Global varibles for Agent
typedef struct _MENU {
LONG dwID;
WCHAR wsCap[16];
} MENU;
MENU g_AgMenu[MENU_SUM];
MENU g_AgFile;
LONG g_lRequestID = 0;
LONG g_lNotifySinkID = 0;
IAgentEx * g_Agent = NULL;
IAgentCharacterEx * g_Peedy = NULL;
IAgentNotifySink g_AgNSink;
// Functions' prototypes
BOOL AgChr_AddMenus( IAgentCharacterEx * );
BOOL AgChr_Load( void );
void AgChr_Play_Speak( IAgentCharacterEx *, BSTR, BSTR );
void AgChr_SelfIntroduce( IAgentCharacterEx * );
void AgChr_Unload( void );
BOOL IsValidAgentVersion( IAgentEx * );
void ShowLastError( void );
/*<-------------------------------------------------------------------->*/
/*<-- 重载 IAgentNotifySink 接口的全部函数,函数的处理过程、返回结果 -->*/
/*<-- 参见:Microsoft Platform SDK : Microsoft Agent Start Page -->*/
HRESULT STDMETHODCALLTYPE IAgentNotifySink_QueryInterface( IAgentNotifySink *This, GUID* riid, void** ppvObj )
{
*ppvObj = NULL;
if( IsEqualIID( riid, &IID_IAgentNotifySink ) )
{
*ppvObj = (LPVOID)This;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE IAgentNotifySink_AddRef( IAgentNotifySink *This )
{
return 1;
}
ULONG STDMETHODCALLTYPE IAgentNotifySink_Release( IAgentNotifySink *This )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_GetTypeInfoCount( IAgentNotifySink *This, UINT* pctinfo )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_GetTypeInfo( IAgentNotifySink *This, UINT itinfo, ULONG lcid, void** pptinfo )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_GetIDsOfNames( IAgentNotifySink *This, GUID* riid, char** rgszNames, UINT cNames, ULONG lcid, LONG* rgdispid )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_Invoke( IAgentNotifySink *This, LONG dispidMember, GUID* riid, ULONG lcid, USHORT wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_Command( IAgentNotifySink *This, LONG dwCommandID, IUnknown* punkUserInput )
{
if( This == NULL ) return -1;
if( dwCommandID == 0 ) return 0;
if( dwCommandID == g_AgMenu[0].dwID ) { // 赚取邮票
return 1;
}
if( dwCommandID == g_AgMenu[1].dwID ) { // 选项设置
return 2;
}
if( dwCommandID == g_AgMenu[2].dwID ) { // 功能说明
return 3;
}
if( dwCommandID == g_AgMenu[3].dwID ) { // 关于 ...
return 4;
}
if( dwCommandID == g_AgMenu[4].dwID ) { // 退出程序
return 5;
}
return -1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_ActivateInputState( IAgentNotifySink *This, LONG dwCharID, LONG bActivated )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_Restart( IAgentNotifySink *This )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_Shutdown( IAgentNotifySink *This )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_VisibleState( IAgentNotifySink *This, LONG dwCharID, LONG bVisible, LONG dwCause )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_Click( IAgentNotifySink *This, LONG dwCharID, SHORT fwKeys, LONG x, LONG y )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_DblClick( IAgentNotifySink *This, LONG dwCharID, SHORT fwKeys, LONG x, LONG y )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_DragStart( IAgentNotifySink *This, LONG dwCharID, SHORT fwKeys, LONG x, LONG y )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_DragComplete( IAgentNotifySink *This, LONG dwCharID, SHORT fwKeys, LONG x, LONG y )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_RequestStart( IAgentNotifySink *This, LONG dwRequestID )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_RequestComplete( IAgentNotifySink *This, LONG dwRequestID, LONG hrStatus )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_BookMark( IAgentNotifySink *This, LONG dwBookMarkID )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_Idle( IAgentNotifySink *This, LONG dwCharID, LONG bStart )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_Move( IAgentNotifySink *This, LONG dwCharID, LONG x, LONG y, LONG dwCause )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_Size( IAgentNotifySink *This, LONG dwCharID, LONG lWidth, LONG lHeight )
{
return 1;
}
HRESULT STDMETHODCALLTYPE IAgentNotifySink_BalloonVisibleState( IAgentNotifySink *This, LONG dwCharID, LONG bVisible )
{
return 1;
}
static IAgentNotifySinkVtbl NotifySinkVtbl =
{
IAgentNotifySink_QueryInterface,
IAgentNotifySink_AddRef,
IAgentNotifySink_Release,
IAgentNotifySink_GetTypeInfoCount,
IAgentNotifySink_GetTypeInfo,
IAgentNotifySink_GetIDsOfNames,
IAgentNotifySink_Invoke,
IAgentNotifySink_Command,
IAgentNotifySink_ActivateInputState,
IAgentNotifySink_Restart,
IAgentNotifySink_Shutdown,
IAgentNotifySink_VisibleState,
IAgentNotifySink_Click,
IAgentNotifySink_DblClick,
IAgentNotifySink_DragStart,
IAgentNotifySink_DragComplete,
IAgentNotifySink_RequestStart,
IAgentNotifySink_RequestComplete,
IAgentNotifySink_BookMark,
IAgentNotifySink_Idle,
IAgentNotifySink_Move,
IAgentNotifySink_Size,
IAgentNotifySink_BalloonVisibleState
};
void InitIAgentNotifySink( IAgentNotifySink * NotifySink )
{
NotifySink->lpVtbl = &NotifySinkVtbl;
// 增加引用计数
IAgentNotifySink_AddRef( NotifySink );
}
void UninitIAgentNotifySink( IAgentNotifySink * NotifySink )
{
// 释放 IAgentNotifySink 接口
IAgentNotifySink_Release( NotifySink );
NotifySink->lpVtbl = NULL;
}
/*<-------------------------------------------------------------------->*/
/*------------------------------------------------------------------------
Procedure: void ShowLastError( void )
Purpose: 显示最近错误信息
Input: none
Output: none
------------------------------------------------------------------------*/
void ShowLastError( void )
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError( ),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the string.
MessageBox( g_hwndMain, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
}
/*------------------------------------------------------------------------
Procedure: BOOL IsValidAgentVersion( IAgentEx * )
Purpose: 检验系统所安装的 Agent Server 控件的版本是否合乎要求
Input: IAgentEx * - 指定 Agent Server 控件
Output: TRUE - 合乎要求
FALSE - 不合乎要求
------------------------------------------------------------------------*/
BOOL IsValidAgentVersion( IAgentEx * pAgent )
{
SHORT sMajor, sMinor;
// 获取系统中 Agent Server 控件的版本信息
IAgentEx_GetVersion( pAgent, &sMajor, &sMinor);
if( (sMajor > AGENT_VERSION_MAJOR) ||
( (sMajor == AGENT_VERSION_MAJOR) &&
(sMinor >= AGENT_VERSION_MINOR) ) )
return TRUE;
return FALSE;
}
/*------------------------------------------------------------------------
Procedure: BOOL AgChr_AddMenus( IAgentCharacterEx * )
Purpose: 添加自定义菜单
Input: IAgentCharacterEx * - 指定 Agent 角色
Output: TRUE - 添加成功
FALSE - 添加失败
------------------------------------------------------------------------*/
BOOL AgChr_AddMenus( IAgentCharacterEx * peedy )
{
IAgentCommandsEx *agCmds = NULL;
HRESULT hr;
BOOL blAdded = TRUE;
static BSTR bsCmd = NULL;
char buf[2][BUF_SIZE];
int i;
ZeroMem( buf );
// 获取 IAgentCommandsEx 接口
hr = IAgentCharacterEx_QueryInterface( peedy, &IID_IAgentCommandsEx, &agCmds );
if( FAILED( hr ) ) {
ErrStr( IDS_ERROR, buf[0] );
return FALSE;
}
LoadStr( IDS_ERROR+1, buf[0] );
for( i=0; i<MENU_SUM; i++ ) {
// 加载自定义菜单
LoadWStr( IDS_POPUP+i, g_AgMenu[i].wsCap );
bsCmd = SysAllocString( g_AgMenu[i].wsCap );
// 添加自定义菜单
hr = IAgentCommandsEx_Add( agCmds, bsCmd, NULL, TRUE, TRUE, &(g_AgMenu[i].dwID) );
SysFreeString( bsCmd );
if( FAILED( hr ) ) {
blAdded = FALSE;
wsprintf( buf[1], " ·%ls/n", g_AgMenu[i].wsCap);
strcat( buf[0], buf[1] );
}
}
// 释放 IAgentCommandsEx 接口
IAgentCommandsEx_Release( agCmds );
if( !blAdded ) ErrMsg( buf[0] );
return blAdded;
}
/*------------------------------------------------------------------------
Procedure: BOOL AgChr_Load( void )
Purpose: 创建 Agent Server 实例,并加载 Agent 角色 Peedy。
Input: none
Output: TRUE - 加载成功
FALSE - 加载失败
------------------------------------------------------------------------*/
BOOL AgChr_Load( void )
{
VARIANT vPath;
HRESULT hr;
IDispatch * pdCharacter = NULL;
IDispatch * pdNSink = NULL;
char buf[2][BUF_SIZE];
ZeroMem( g_AgMenu );
g_AgFile.dwID = 0;
ZeroMem( g_AgFile.wsCap );
ZeroMem( buf );
CoInitialize( NULL );
// 创建 Agent Server 实例
hr = CoCreateInstance( &CLSID_AgentServer, NULL, CLSCTX_LOCAL_SERVER, &IID_IAgentEx, &g_Agent );
if( FAILED( hr ) ) {
ErrStr( IDS_ERROR+3, buf[0] );
return FALSE;
}
// 检查 Agent Server 的版本
if( !IsValidAgentVersion(g_Agent) ) {
LoadStr( IDS_ERROR+4, buf[1] );
wsprintf( buf[0], buf[1], AGENT_VERSION_MAJOR, AGENT_VERSION_MINOR );
ErrMsg( buf[0] );
return FALSE;
}
// 初始化 IAgentNotifySink 接口
InitIAgentNotifySink( &g_AgNSink );
// 注册 IAgentNotifySink 接口
hr = IAgentEx_Register( g_Agent, (IUnknown *)&g_AgNSink, &g_lNotifySinkID );
ShowLastError( );
wsprintf( buf[0], "HRESULT : %d", hr);
ErrMsg( buf[0] );
if( FAILED( hr ) ) {
ErrStr( IDS_ERROR+10, buf[0] );
return FALSE;
}
// 加载 Agent 角色 Peedy
LoadWStr( IDS_SMALL, g_AgFile.wsCap );
VariantInit( &vPath ); // 初始化 OLE 变量
vPath.vt = VT_BSTR; // 指明变量类型为 Unicode 的字符串
vPath.bstrVal = SysAllocString( g_AgFile.wsCap );
hr = IAgentEx_Load( g_Agent, vPath, &(g_AgFile.dwID), &g_lRequestID );
VariantClear( &vPath ); // 清除 OLE 变量
if( FAILED( hr ) ) {
ErrStr( IDS_ERROR+5, buf[0] );
return FALSE;
}
// 获取 Agent 角色的 IDispatch 接口
hr = IAgentEx_GetCharacter( g_Agent, g_AgFile.dwID, &pdCharacter );
if( FAILED( hr ) ) {
ErrStr( IDS_ERROR+6, buf[0] );
return FALSE;
}
// 获取 IAgentCharacterEx 接口
hr = IDispatch_QueryInterface( pdCharacter, &IID_IAgentCharacter, &g_Peedy );
IDispatch_Release( pdCharacter ); // 释放IDispath
if( FAILED( hr ) ) {
ErrStr( IDS_ERROR+7, buf[0] );
return FALSE;
}
// 设置 Agent 角色的语言类型:简体中文
hr = IAgentCharacterEx_SetLanguageID( g_Peedy, 0x0804 );
if( FAILED( hr ) ) {
ErrStr( IDS_ERROR+8, buf[0] );
return FALSE;
}
// 添加自定义菜单
if( !AgChr_AddMenus( g_Peedy ) ) {
return FALSE;
}
// Peedy 自我介绍
AgChr_SelfIntroduce( g_Peedy );
return TRUE;
}
/*------------------------------------------------------------------------
Procedure: void AgChr_Unload( void )
Purpose: 卸载 Agent 角色 Peedy,释放 Agent Server 实例。
Input: none
Output: none
------------------------------------------------------------------------*/
void AgChr_Unload( void )
{
HRESULT hr;
char buf[BUF_SIZE];
ZeroMem( buf );
if( g_Peedy != NULL ) {
//IAgentCharacterEx_StopAll( g_Peedy, 0xFFFFFFFF );
IAgentCharacterEx_Hide( g_Peedy, TRUE, &g_lRequestID );
IAgentCharacterEx_Release( g_Peedy );
}
if( g_Agent != NULL ) {
if( g_AgFile.dwID != 0 ) {
hr = IAgentEx_Unload( g_Agent, g_AgFile.dwID ); // 卸载动画人物数据
if( FAILED( hr ) ) {
ErrStr( IDS_ERROR+9, buf );
}
}
// 注销 IAgentNotifySink 接口
if( g_lNotifySinkID != 0 )
IAgentEx_Unregister( g_Agent, g_lNotifySinkID );
UninitIAgentNotifySink( &g_AgNSink );
IAgentEx_Release( g_Agent ); // 释放Agent对象
}
CoUninitialize( );
}
/*------------------------------------------------------------------------
Procedure: void AgChr_Play_Speak( IAgentCharacterEx *, BSTR, BSTR )
Purpose: Agent 角色播放动作,并说一句台词。
Input: IAgentCharacterEx * - 指定 Agent 角色
BSTR - 指定动作
BSTR - 指定台词
Output: none
------------------------------------------------------------------------*/
void AgChr_Play_Speak( IAgentCharacterEx * peedy, BSTR bsAction, BSTR bsWords )
{
static BSTR bsBuf = NULL;
if( bsAction != NULL) {
bsBuf = SysAllocString( bsAction );
IAgentCharacterEx_Play( peedy, bsBuf, &g_lRequestID );
SysFreeString( bsBuf );
}
if( bsWords != NULL) {
bsBuf = SysAllocString( bsWords );
IAgentCharacterEx_Speak( peedy, bsBuf, NULL, &g_lRequestID );
SysFreeString( bsBuf );
}
}
/*------------------------------------------------------------------------
Procedure: void AgChr_SelfIntroduce( IAgentCharacterEx * )
Purpose: Agent 角色自我介绍。
Input: IAgentCharacterEx * - 指定 Agent 角色
Output: none
------------------------------------------------------------------------*/
void AgChr_SelfIntroduce( IAgentCharacterEx * peedy )
{
WCHAR wsWords[BUF_SIZE];
// Move the character and make it visible
IAgentCharacterEx_MoveTo( peedy, 200, 200, 1000, &g_lRequestID );
IAgentCharacterEx_Show( peedy, FALSE, &g_lRequestID );
// And play an intro animations
LoadWStr( IDS_WORDS, wsWords );
AgChr_Play_Speak( peedy, L"GetAttention", wsWords );
LoadWStr( IDS_WORDS+1, wsWords );
AgChr_Play_Speak( peedy, L"Greet", wsWords );
LoadWStr( IDS_WORDS+2, wsWords );
AgChr_Play_Speak( peedy, L"Explain", wsWords );
AgChr_Play_Speak( peedy, L"RestPose", NULL );
}