tapiPhoneDlg.cpp
上传用户:fast168168
上传日期:2010-01-05
资源大小:337k
文件大小:21k
源码类别:

TAPI编程

开发平台:

Visual C++

  1. // tapiPhoneDlg.cpp : 实现文件
  2. //
  3. #include "stdafx.h"
  4. #include "tapiPhone.h"
  5. #include "tapiPhoneDlg.h"
  6. #include "tapiPhoneSetupDlg.h"
  7. #include "control.h"
  8. #ifdef _DEBUG
  9. #define new DEBUG_NEW
  10. #endif
  11. // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
  12. class CAboutDlg : public CDialog
  13. {
  14. public:
  15. CAboutDlg();
  16. // 对话框数据
  17. enum { IDD = IDD_ABOUTBOX };
  18. protected:
  19. virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
  20. // 实现
  21. protected:
  22. DECLARE_MESSAGE_MAP()
  23. };
  24. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  25. {
  26. }
  27. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  28. {
  29. CDialog::DoDataExchange(pDX);
  30. }
  31. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  32. END_MESSAGE_MAP()
  33. // CtapiPhoneDlg 对话框
  34. CtapiPhoneDlg::CtapiPhoneDlg(CWnd* pParent /*=NULL*/)
  35. : CDialog(CtapiPhoneDlg::IDD, pParent)
  36. , m_AutoAnswer(FALSE)
  37. , m_valStcMsg(_T(""))
  38. {
  39. m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  40. m_valEdtNum = "";
  41. m_valCallerNum = "呼入方号码: 当前无呼叫";
  42. }
  43. void CtapiPhoneDlg::DoDataExchange(CDataExchange* pDX)
  44. {
  45. CDialog::DoDataExchange(pDX);
  46. DDX_Control(pDX, IDC_BTN_DISCONNECT, m_btDisconnect);
  47. DDX_Control(pDX, IDC_BTN_CALL, m_btCall);
  48. DDX_Control(pDX, IDC_BTN_CONFIG, m_btConfig);
  49. DDX_Control(pDX, IDC_BTN_PICKUP, m_btPickup);
  50. DDX_Check(pDX, IDC_CHK_AUTO, m_AutoAnswer);
  51. DDX_Text(pDX, IDC_STC_STATUS, m_valStcMsg);
  52. DDX_Text(pDX, IDC_EDIT_NUMBER, m_valEdtNum);
  53. DDX_Text(pDX, IDC_STATIC_, m_valCallerNum);
  54. DDX_Control(pDX, IDC_STC_IMAGE, m_stcImage);
  55. }
  56. BEGIN_MESSAGE_MAP(CtapiPhoneDlg, CDialog)
  57. ON_WM_SYSCOMMAND()
  58. ON_WM_PAINT()
  59. ON_WM_QUERYDRAGICON()
  60. //}}AFX_MSG_MAP
  61. ON_BN_CLICKED(IDC_BTN_PICKUP, OnBnClickedBtnPickup)
  62. //用户自定义消息响应函数
  63. ON_MESSAGE(WM_PRIVATETAPIEVENT, OnTapiEvent)
  64. ON_BN_CLICKED(IDC_CHK_AUTO, OnBnClickedChkAuto)
  65. ON_BN_CLICKED(IDC_BTN_DISCONNECT, OnBnClickedBtnDisconnect)
  66. ON_BN_CLICKED(IDC_BTN_CALL, OnBnClickedBtnCall)
  67. ON_BN_CLICKED(IDC_BTN_EXIT, OnBnClickedBtnExit)
  68. ON_BN_CLICKED(IDC_BTN_CONFIG, OnBnClickedBtnConfig)
  69. //}}AFX_MSG_MAP
  70. END_MESSAGE_MAP()
  71. // CtapiPhoneDlg 消息处理程序
  72. BOOL CtapiPhoneDlg::OnInitDialog()
  73. {
  74. CDialog::OnInitDialog();
  75. // 将“关于...”菜单项添加到系统菜单中。
  76. // IDM_ABOUTBOX 必须在系统命令范围内。
  77. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  78. ASSERT(IDM_ABOUTBOX < 0xF000);
  79. CMenu* pSysMenu = GetSystemMenu(FALSE);
  80. if (pSysMenu != NULL)
  81. {
  82. CString strAboutMenu;
  83. strAboutMenu.LoadString(IDS_ABOUTBOX);
  84. if (!strAboutMenu.IsEmpty())
  85. {
  86. pSysMenu->AppendMenu(MF_SEPARATOR);
  87. pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  88. }
  89. }
  90. // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
  91. //  执行此操作
  92. SetIcon(m_hIcon, TRUE); // 设置大图标
  93. SetIcon(m_hIcon, FALSE); // 设置小图标
  94. // TODO:在此添加额外的初始化代码
  95. //初始化TAPI,在此之前必需调用 AfxOleInit()初始化 COM
  96. //将窗口的句柄 m_hWnd 传给 CTapi,使二者之间建立联系
  97. m_Tapi.m_hWnd = this->m_hWnd;
  98. if( FAILED(m_Tapi.InitializeTapi()) )
  99. {
  100. MessageBox("致命错误:TAPI 初始化失败!");
  101. return FALSE;
  102. }
  103. //
  104. // 初始化按钮状态
  105. //
  106. m_btCall.EnableWindow();
  107. m_btDisconnect.EnableWindow();
  108. m_btPickup.EnableWindow(FALSE);
  109. SetStatusMessage("准备就绪,等待电话呼入...");
  110. // HBITMAP hBitmap;
  111. // m_stcImage.SetBitmap(hBitmap);
  112. return TRUE;  // 除非设置了控件的焦点,否则返回 TRUE
  113. }
  114. void CtapiPhoneDlg::OnSysCommand(UINT nID, LPARAM lParam)
  115. {
  116. if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  117. {
  118. CAboutDlg dlgAbout;
  119. dlgAbout.DoModal();
  120. }
  121. else
  122. {
  123. CDialog::OnSysCommand(nID, lParam);
  124. }
  125. }
  126. // 如果向对话框添加最小化按钮,则需要下面的代码
  127. // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
  128. // 这将由框架自动完成。
  129. void CtapiPhoneDlg::OnPaint() 
  130. {
  131. if (IsIconic())
  132. {
  133. CPaintDC dc(this); // 用于绘制的设备上下文
  134. SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
  135. // 使图标在工作矩形中居中
  136. int cxIcon = GetSystemMetrics(SM_CXICON);
  137. int cyIcon = GetSystemMetrics(SM_CYICON);
  138. CRect rect;
  139. GetClientRect(&rect);
  140. int x = (rect.Width() - cxIcon + 1) / 2;
  141. int y = (rect.Height() - cyIcon + 1) / 2;
  142. // 绘制图标
  143. dc.DrawIcon(x, y, m_hIcon);
  144. }
  145. else
  146. {
  147. CDialog::OnPaint();
  148. }
  149. }
  150. //当用户拖动最小化窗口时系统调用此函数取得光标显示。
  151. HCURSOR CtapiPhoneDlg::OnQueryDragIcon()
  152. {
  153. return static_cast<HCURSOR>(m_hIcon);
  154. }
  155. /////////////////////////////////////////////////////////////////////////////////////
  156. // SetStatusMessage
  157. //
  158. // 显示当前系统消息
  159. /////////////////////////////////////////////////////////////////////////////////////
  160. void CtapiPhoneDlg::SetStatusMessage(CString strMsg)
  161. {
  162. m_valStcMsg = strMsg;
  163. UpdateData(FALSE);
  164. }
  165. /////////////////////////////////////////////////////////////////////////////////////
  166. //
  167. // 以下是用户界面事件响应函数
  168. //
  169. /////////////////////////////////////////////////////////////////////////////////////
  170. void CtapiPhoneDlg::OnBnClickedBtnPickup()
  171. {
  172. // 
  173. // 接听电话
  174. //
  175.     SetStatusMessage("正在准备接听...");
  176.     if ( S_OK == m_Tapi.AnswerTheCall() )
  177.     {
  178. SetStatusMessage("通话中");
  179. m_btDisconnect.EnableWindow();
  180. m_btPickup.EnableWindow(FALSE);
  181.     }
  182.     else
  183.     {
  184. m_btPickup.EnableWindow(FALSE);
  185.         MessageBox("没有接听成功!");
  186.         SetStatusMessage("准备就绪,等待来电...");
  187.     }
  188. }
  189. void CtapiPhoneDlg::OnBnClickedChkAuto()
  190. {
  191. //
  192. // 自动接听与手工接听之间切换
  193. //
  194. UpdateData();
  195. }
  196. void CtapiPhoneDlg::OnBnClickedBtnDisconnect()
  197. {
  198. //
  199. // 如果是电话另一方先挂断电话,则 m_pCall 已经挂断并且释放
  200. // 此处不用再次挂断
  201. //
  202.     if ( m_Tapi.m_pCall != NULL )
  203.     {
  204.         SetStatusMessage("正在挂断电话...");
  205.         // 挂断电话
  206.         if (S_OK != m_Tapi.DisconnectTheCall())
  207.         {
  208. MessageBox("挂断电话失败!");
  209. }
  210. else
  211. {
  212. m_btCall.EnableWindow();
  213. m_btPickup.EnableWindow(FALSE);
  214. m_valCallerNum = "呼入方号码: 当前无呼叫";
  215. SetStatusMessage("准备就绪,正在等待电话呼入...");
  216. }
  217. }
  218. }
  219. void CtapiPhoneDlg::OnBnClickedBtnCall()
  220. {
  221.     //
  222.     // 呼叫号码
  223.     //
  224.     DWORD dwAddressType;
  225. BSTR  szAddressToCall;
  226. UpdateData();
  227. if( m_valEdtNum.GetLength() <= 2 )
  228. return;
  229. szAddressToCall = m_valEdtNum.AllocSysString();
  230. SetStatusMessage( "正在呼叫..." );
  231. dwAddressType = LINEADDRESSTYPE_PHONENUMBER ;
  232.     // 开始呼叫
  233.     if ( S_OK == m_Tapi.MakeTheCall(dwAddressType, szAddressToCall) )
  234.     {
  235. m_btDisconnect.EnableWindow();
  236. m_btPickup.EnableWindow(FALSE);
  237. m_btCall.EnableWindow(FALSE);
  238.     }
  239.     else
  240.     {
  241.         MessageBox("呼叫失败!");
  242.     }
  243. SysFreeString(szAddressToCall);
  244. // m_Tapi.PreparePlay("Greeting.wav");
  245. }
  246. void CtapiPhoneDlg::OnBnClickedBtnExit()
  247. {
  248. // 退出程序
  249. OnOK();
  250. }
  251. void CtapiPhoneDlg::OnBnClickedBtnConfig()
  252. {
  253. // 把配置对话框中的数据传入 
  254. CtapiPhoneSetupDlg SetupDlg;
  255. if(SetupDlg.DoModal() == IDOK)
  256. {
  257. m_Tapi.m_WelcomeFileName = SetupDlg.m_strFileName0;
  258. strFileName0 = SetupDlg.m_strFileName0;
  259. strFileName1 = SetupDlg.m_strFileName1;
  260. strFileName2 = SetupDlg.m_strFileName2;
  261. strPath = SetupDlg.m_strPath;
  262. }
  263. }
  264. ///////////////////////////////////////////////////////////////////
  265. // OnTapiEvent
  266. //
  267. // 这是真正的事件处理函数,当 UI 线程接收到 WM_PRIVATETAPIEVENT消息
  268. // 时调用此函数,在 UI 线程中进行事件响应处理
  269. //
  270. ///////////////////////////////////////////////////////////////////
  271. LRESULT
  272. CtapiPhoneDlg::OnTapiEvent(
  273.    WPARAM wp,
  274.    LPARAM lp
  275.                            )
  276. {
  277. TAPI_EVENT TapiEvent = (TAPI_EVENT)wp;
  278. IDispatch *pEvent = (IDispatch*) lp;
  279. if( TapiEvent == TE_DIGITEVENT )
  280. MessageBox("TE_DIGITEVENT");
  281. else if(TapiEvent == TE_GENERATEEVENT )
  282. MessageBox("TE_GENERATEEVENT");
  283. else if(TapiEvent == TE_GATHERDIGITS)
  284. MessageBox("TE_GATHERDIGITS");
  285. switch ( TapiEvent )
  286.     {
  287.         case TE_CALLNOTIFICATION:
  288.         {
  289. //
  290.             // TE_CALLNOTIFICATION: 程序发现一个呼入的电话
  291.             //
  292. TRACE("Event:-----------TE_CALLNOTIFICATION----------Eventn");
  293. DoCallNotification(pEvent);
  294.             break;
  295.         }//TE_CALLNOTIFICATION
  296.         
  297.         case TE_CALLSTATE:
  298.         {
  299.             //
  300. // TE_CALLSTATE: 程序发现整个 Call 过程状态有变化
  301. //
  302. TRACE("Event:-----------TE_CALLSTATE----------Eventn");
  303. DoCallState(pEvent);
  304.             break;
  305.         }//TE_CALLSTATE
  306.         case TE_CALLMEDIA:
  307.         {
  308. //
  309. // TE_CALLMEDIA:关于媒体的事件,如有某种媒体到达
  310. //
  311. TRACE("Event:-----------TE_CALLMEDIA----------Eventn");
  312. DoCallMedia(pEvent);
  313.             break;    
  314.         }//TE_CALLMEDIA  
  315. case TE_FILETERMINAL:
  316. {
  317.             //
  318. // TE_FILETERMINAL:文件终端事件,只在 TAPI3.1 中支持
  319. //
  320. TRACE("Event:-----------TE_FILETERMINAL----------Eventn");
  321. DoFileEvent(pEvent);
  322. break;
  323. }//TE_FILETERMINAL
  324. case TE_DIGITEVENT:
  325. {
  326. //
  327. // TE_DIGIT:接受到按键事件
  328. //
  329. TRACE("Event:-----------TE_DIGITEVENT----------Eventn");
  330. DoDigitEvent(pEvent);
  331. break;
  332. }
  333. default:
  334. break;
  335.     }    
  336.     pEvent->Release(); // 因为在 CTAPIEventNotification::Event() 中调用过 AddRef
  337.     return S_OK;
  338. }
  339. /////////////////////////////////////////////////////////////////////////////////////
  340. // 处理 TE_NOTIFICATION 事件,有新电话打入时触发此事件
  341. // 功能:
  342. // 1、获取拨入方信息,主要是对方电话号码或IP
  343. // 2、获取 ITBasicCallControl,存入 m_pCall,
  344. // 3、更新用户界面
  345. // 注意:不能在此时就应答电话,应用程序应当等待 TE_CALLSTATE 事件触发并判断当前事件为
  346. // CS_OFFERING 时才可以。
  347. /////////////////////////////////////////////////////////////////////////////////////
  348. HRESULT CtapiPhoneDlg::DoCallNotification( IN IDispatch * pEvent)
  349. {
  350. //
  351. //通过接口 ITCallNotificationEvent 可以获得所有关于拨入事件的信息,这里主要用来得到 ITCallInfo
  352. //
  353.     ITCallNotificationEvent         * pNotify;
  354. HRESULT hr;
  355.             
  356.     hr = pEvent->QueryInterface( IID_ITCallNotificationEvent, (void **)&pNotify );
  357.     if (S_OK != hr)
  358.     {
  359.         MessageBox( "有电话乎入,但获得接口 ITCallNotificationEvent 失败!");
  360.     }
  361.     else
  362.     {
  363. //
  364. //通过 ITCallInfo 获得拨入方信息,如拨入方电话号码等
  365. //
  366. CALL_PRIVILEGE          cp;
  367. ITCallInfo *            pCall;
  368. //
  369. // 得到 ITCallInfo 的指针
  370. //
  371. hr = pNotify->get_Call( &pCall );
  372. pNotify->Release();
  373. if ( SUCCEEDED(hr) )
  374. {
  375. //
  376. // 检测我们对 call 是否拥有 owner 权限
  377. //
  378. hr = pCall->get_Privilege( &cp );
  379. if ( FAILED(hr) || (CP_OWNER != cp) )
  380. {
  381. //
  382. // 如果没有 owner 权限,乎略这次拨入
  383. //
  384. pCall->Release();
  385. //
  386. // 注意:我们在 CTAPIEventNotification::Event() 中调用了 AddRef()
  387. //
  388. pEvent->Release(); 
  389. return S_OK;
  390. }
  391. //
  392. //用来获得乎叫方信息, 用于来电显示
  393. //
  394. BSTR bstrCallerName, bstrCallerNum;
  395. BSTR bstrCallidName, bstrCallidNum;
  396. BSTR bstrConnectName, bstrConnectNum;
  397. CString strCallerName, strCallerNum;
  398. CString strCallidName, strCallidNum;
  399. CString strConnectName, strConnectNum;
  400.  
  401. //The name of the caller. 
  402. pCall->get_CallInfoString(CIS_CALLERIDNAME, &bstrCallerName);
  403. strCallerName = bstrCallerName;
  404.  
  405. //The number of the caller. 
  406. pCall->get_CallInfoString(CIS_CALLERIDNUMBER, &bstrCallerNum);
  407. strCallerNum = bstrCallerNum;
  408.  
  409. //The name of the called location. 
  410. pCall->get_CallInfoString(CIS_CALLEDIDNAME, &bstrCallidName);
  411. strCallidName = bstrCallidName;
  412.  
  413. //The number of the called location. 
  414. pCall->get_CallInfoString(CIS_CALLEDIDNUMBER, &bstrCallidNum);
  415. strCallidNum = strCallidNum;
  416.  
  417. //The name of the connected location. 
  418. pCall->get_CallInfoString(CIS_CONNECTEDIDNAME, &bstrConnectName);
  419. strConnectName = bstrConnectName;
  420.  
  421. //The number of the connected location. 
  422. pCall->get_CallInfoString(CIS_CONNECTEDIDNUMBER, &bstrConnectNum);
  423. strConnectNum = bstrConnectNum;
  424. if( strCallidNum.IsEmpty() )
  425. m_valCallerNum = "呼叫方号码: 无法获得";
  426. else
  427. m_valCallerNum = "呼叫方号码: " + strCallidNum;
  428. UpdateData(FALSE);
  429. //
  430. // 获得 ITBasicCallControl 接口并把它保存在成员变量 ppCall 中
  431. //
  432. ITBasicCallControl * ppCall;
  433. hr = pCall->QueryInterface( IID_ITBasicCallControl,
  434. (void**)&ppCall );
  435. m_Tapi.m_pCall = ppCall;
  436. pCall->Release();
  437.                 
  438. if ( SUCCEEDED(hr) )
  439. {
  440. //
  441. // 更新 UI
  442. //
  443. m_btPickup.EnableWindow();
  444. m_btDisconnect.EnableWindow();
  445.             SetStatusMessage("有电话呼入...");
  446. }//end if
  447. }
  448.     }//end if
  449. return S_OK;
  450. }//end function
  451. /////////////////////////////////////////////////////////////////////////////////////
  452. // DoCallState 
  453. //
  454. // 功能:处理 TE_STATE 事件,有某种状态改变时触发此事件,比如只有状态为 CS_OFFERING 
  455. // 时才可以应答
  456. /////////////////////////////////////////////////////////////////////////////////////
  457. HRESULT CtapiPhoneDlg::DoCallState(IDispatch* pEvent)
  458. {
  459. HRESULT hr;
  460.     CALL_STATE cs;
  461.     ITCallStateEvent * pCallStateEvent;
  462.     //
  463. // 获得接口 
  464. //
  465.     hr = pEvent->QueryInterface( IID_ITCallStateEvent, (void **)&pCallStateEvent );
  466.     if ( FAILED(hr) )
  467.     {
  468.         return E_FAIL;
  469.     }
  470. //
  471. // 检测是否是同一个 Call - 如果不是,不处理这个事件
  472. //
  473. if(false == m_Tapi.SameCall(pCallStateEvent))
  474. {
  475. pCallStateEvent->Release();
  476. return hr;
  477. }
  478. //
  479.     // 通过 ITCallStateEvent 获得当前状态
  480. //
  481.     hr = pCallStateEvent->get_State( &cs );
  482.     //
  483. // 释放接口
  484. //
  485.     pCallStateEvent->Release();
  486.     if ( FAILED(hr) )
  487.     {
  488.         return E_FAIL;
  489.     }
  490.     //
  491. // 如果当前状态是 offering,则应答电话,同时更新 UI
  492. //
  493.     if (CS_OFFERING == cs)
  494.     {
  495.         if (m_AutoAnswer) //如果选种自动应答
  496.         {
  497. OnBnClickedBtnPickup();
  498.         }
  499.         else //选择手动应答
  500.         {
  501.             SetStatusMessage("请点击接听按钮接听电话");
  502.         }
  503. }
  504.     else if (CS_DISCONNECTED == cs)
  505.     {
  506. OnBnClickedBtnDisconnect();
  507. m_Tapi.ReleaseTheCall();
  508.     }
  509.     else if (CS_CONNECTED == cs)
  510.     {
  511. //
  512.         // 不作处理
  513. //
  514.     }
  515.     return S_OK;
  516. }
  517. /////////////////////////////////////////////////////////////////////////////////////
  518. // DoCallMedia
  519. //
  520. // 功能:处理 TE_MEDIA 事件,TE_CALLMEDIA 触发 Media 事件,对应接口:ITCallMediaEvent
  521. /////////////////////////////////////////////////////////////////////////////////////
  522. HRESULT CtapiPhoneDlg::DoCallMedia(
  523. IN IDispatch * pEvent)
  524. {
  525.     CALL_MEDIA_EVENT    cme = CME_STREAM_INACTIVE;
  526.     ITCallMediaEvent  * pCallMediaEvent = NULL;
  527. //
  528. // 检测当前 Call 是否有效
  529. //
  530. if(NULL == m_Tapi.m_pCall)
  531. {
  532. return E_UNEXPECTED;
  533. }
  534.     //
  535. // 获得接口
  536. //
  537.     HRESULT hr = pEvent->QueryInterface( IID_ITCallMediaEvent, (void **)&pCallMediaEvent );
  538. if(FAILED(hr))
  539. {
  540.         MessageBox("ITCallMediaEvent, 获取接口失败!");
  541. return hr;
  542. }
  543.     //
  544. // 获得我们检测到的 MediaEvent 具体类型
  545. //
  546.     hr = pCallMediaEvent->get_Event( &cme );
  547. if(FAILED(hr))
  548. {
  549. pCallMediaEvent->Release();
  550. MessageBox("ITCallMediaEvent, but failed to get_Event");
  551. return hr;
  552. }
  553.     switch ( cme ) 
  554.     {
  555. // 
  556. // 这是我们需要处理的唯一的事件
  557. //
  558.         case CME_STREAM_ACTIVE:    
  559.         {
  560.             //
  561.             // 获得当前活动的终端
  562.             //    
  563.             ITTerminal * pTerminal = NULL;
  564.             hr = m_Tapi.GetTerminalFromStreamEvent(pCallMediaEvent, &pTerminal);
  565.             if ( FAILED(hr) )  
  566. {
  567. MessageBox("ITCallMediaEvent: GetTerminalFromStreamEvent failed");
  568. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  569. break; 
  570. }
  571.             //
  572.             // 根据终端的方向进行处理
  573.             //
  574.             TERMINAL_DIRECTION td;
  575.             hr = pTerminal->get_Direction( &td);
  576. //
  577. // 释放接口
  578. //
  579.             pTerminal->Release(); 
  580.             if ( FAILED(hr) ) 
  581.             { 
  582.             MessageBox("ITCallMediaEvent: get_Direction failed");
  583. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  584.                 break; 
  585.             }
  586. //
  587. // 方向是 TD_CAPTURE:播放声音文件
  588. //
  589.             if ( TD_CAPTURE == td && NULL != m_Tapi.m_pPlayFileTerm) 
  590.             {
  591. ITMediaControl* pITMC = NULL;
  592. hr = m_Tapi.m_pPlayFileTerm->QueryInterface(IID_ITMediaControl, (void**)&pITMC);
  593. //
  594. // 获得 ITMediaControl,开始发送媒体流
  595. //
  596. if(FAILED(hr))
  597. {
  598. MessageBox("ITCallMediaEvent: m_pPlayFileTerm QI for ITMediaControl failed");
  599. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  600. break;
  601. }
  602. //
  603. // 开始发送
  604. //
  605. hr = pITMC->Start();
  606. pITMC->Release();
  607. if(SUCCEEDED(hr))
  608. {
  609. SetStatusMessage("正在播放音频文件... ");
  610. }
  611. else
  612. {
  613.             MessageBox("ITCallMediaEvent: ITMediaControl::Start() failed");
  614. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  615. }
  616. }
  617.         
  618.             break;
  619.         }
  620.     
  621.         default:
  622.             break;
  623.     }
  624.     //
  625. // 释放接口
  626. //
  627.     pCallMediaEvent->Release();
  628. return hr;
  629. }
  630. ///////////////////////////////////////////////////////////////////
  631. // DoFileEvent
  632. //
  633. //
  634. // TE_FILETERMINAL 文件终端事件.  pEvent: ITFileTerminalEvent
  635. // 说明:只有 WinXP 下才支持
  636. ///////////////////////////////////////////////////////////////////
  637. HRESULT CtapiPhoneDlg::DoFileEvent(
  638. IN IDispatch * pEvent)
  639. {
  640. //
  641. // 检测当前 Call 是否有效
  642. //
  643. if(NULL == m_Tapi.m_pCall)
  644. {
  645. return E_UNEXPECTED;
  646. }
  647. ITFileTerminalEvent* pITFTEvent = NULL;
  648. HRESULT hr = pEvent->QueryInterface( IID_ITFileTerminalEvent,
  649.  reinterpret_cast<void **>(&pITFTEvent) );
  650. if (FAILED(hr))
  651. {
  652. //
  653. // 致命错误 - 无法继续下去 - 切断此次通话
  654. //
  655.         MessageBox("ITFileTerminalEvent, 获得接口失败!");
  656. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  657. return hr;
  658. }
  659. //
  660. // 获得状态 - ???????因为我们要确保声音文件未被其它程序使用
  661. //
  662. TERMINAL_MEDIA_STATE ftState = TMS_ACTIVE;
  663. hr = pITFTEvent->get_State(&ftState);
  664. if(FAILED(hr))
  665. {
  666. //
  667. // 致命错误 - 无法继续下去 - 切断此次通话
  668. //
  669. pITFTEvent->Release();
  670.         MessageBox("ITFileTerminalEvent, but failed to get_State");
  671. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  672. return hr;
  673. }
  674. //
  675. // 我们对 TMS_IDLE 感兴趣,因为我们要停止播放
  676. //
  677. if(ftState != TMS_IDLE)
  678. {
  679. pITFTEvent->Release();
  680. return hr;
  681. }
  682. //
  683. // 获得终端
  684. //
  685. ITTerminal *pTerminal = NULL;
  686. hr = pITFTEvent->get_Terminal(&pTerminal);
  687. //
  688. // 不再需要这个接口
  689. //
  690. pITFTEvent->Release();
  691. if(FAILED(hr))
  692. {
  693. //
  694. // 致命错误 - 无法继续下去 - 切断此次通话
  695. //
  696.         MessageBox("ITFileTerminalEvent, but failed to get_Terminal");
  697. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  698. return hr;
  699. }
  700.     TERMINAL_DIRECTION td;
  701.     hr = pTerminal->get_Direction( &td);
  702.     pTerminal->Release(); 
  703. if(FAILED(hr))
  704. {
  705. //
  706. // 致命错误 - 无法继续下去 - 切断此次通话
  707. //
  708.         MessageBox("ITFileTerminalEvent, but failed to get_Direction");
  709. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  710. return hr;
  711. }
  712. if((td == TD_CAPTURE) && (NULL != m_Tapi.m_pPlayFileTerm))
  713. {
  714. SetStatusMessage("通话中...");
  715. //
  716. // unselect playback - 因为播放已经完成
  717. //
  718. ITBasicCallControl2 *pITBCC2 = NULL;
  719. hr = m_Tapi.m_pCall->QueryInterface(IID_ITBasicCallControl2, (void**)&pITBCC2);
  720. if(FAILED(hr))
  721. {
  722. //
  723. // 致命错误 - 无法继续下去 - 切断此次通话
  724. //
  725.         MessageBox("ITFileTerminalEvent, but failed to QI for ITBasicCallControl2");
  726. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  727. return hr;
  728. }
  729. //
  730. // 使用 ITBasicCallControl2 方法 - 要比列举媒体流、终端容易的多
  731. //
  732. hr = pITBCC2->UnselectTerminalOnCall( m_Tapi.m_pPlayFileTerm);
  733. m_Tapi.m_pPlayFileTerm->Release();
  734. m_Tapi.m_pPlayFileTerm = NULL;
  735. pITBCC2->Release();
  736. if(FAILED(hr))
  737. {
  738. //
  739. // 致命错误 - 无法继续下去 - 切断此次通话
  740. //
  741.         MessageBox("ITFileTerminalEvent, but failed to ITBasicCallControl2::UnselectTerminalOnCall");
  742. m_Tapi.m_pCall->Disconnect(DC_NORMAL);
  743. return hr;
  744. }
  745. }
  746. return hr;
  747. }
  748. /////////////////////////////////////////////////////////////////////////////////////
  749. // DigitEvent
  750. //
  751. // 处理 TE_DIGITEVENT 事件,TE_DIGITEVENT 时触发,对应接口 ITDigitDetectionEvent
  752. /////////////////////////////////////////////////////////////////////////////////////
  753. HRESULT CtapiPhoneDlg::DoDigitEvent(IN IDispatch* pEvent)
  754. {
  755. ITDigitDetectionEvent* pDigitEvent;
  756. //
  757. // 获得接口
  758. //
  759. pEvent->QueryInterface(IID_ITDigitDetectionEvent, (void**)&pDigitEvent);
  760. unsigned char dig;
  761. pDigitEvent->get_Digit(&dig);
  762. //
  763. // 跟据用户不同按键选择做出不同的回应
  764. //
  765. switch (dig)
  766. {
  767. case '1':
  768. // 播放声音1
  769. m_Tapi.PreparePlay(strFileName1);
  770. break;
  771. case '2':
  772. // 播放声间2
  773. m_Tapi.PreparePlay(strFileName2);
  774. break;
  775. case '3':
  776. // 留言
  777. m_Tapi.StartRecord();
  778. default:
  779. break;
  780. }
  781. return S_OK;
  782. }