在LccWin32中使用Microsoft Agent控件——主文件AgentSvr.c

来源:互联网 发布:知乎 垃圾 编辑:程序博客网 时间:2024/04/30 02:03

这是使用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 );
}