📄 sessionwnd.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*************************************************************************
Disclaimer:
This code and information is provided "as is" without warranty of
any kind, either expressed or implied, including but not limited to
the implied warranties of merchantability and/or fitness for a
particular purpose.
Module Name:
SessionWnd.cpp
Abstract:
Methods for the SessionWindow or UI of current voice / IM sessions.
Notes:
This module contains all methods related to the session window, which
is used to display status messages for voice sessions and for user input
of instant messages and display of the receipt of these.
The SessionWindowCallBack function is notified of RTC events through the
rtcevent.cpp event handlers.
**************************************************************************/
#include "stdafx.h"
#include <commctrl.h>
#include "rtcs.h"
#include "voipdemo.h"
#include "sessionwnd.h"
#include "dbase.h"
#define MSGSENDBUTTON 0
/*************************************************************************************************
Internal global variables
*************************************************************************************************/
// Handle to the local user's information
extern LOCAL_USER_INFO* g_pLocalUserInfo;
// information for display of different buttons
SBUTTONDATA m_sSessionButtons[]=
{ { 0, 0, 0, 0, { IDB_SMSGBTN, IDB_SMSGBTN, IDB_SMSGDISABLEDBTN } }, // Send message
{ 10, 10, 50, 50, { IDB_CALLBTN, IDB_HANGUPBTN, IDB_CALLDISABLEDBTN } }, // Should be talking
{ 62, 10, 50, 50, { IDB_SENDBTN, IDB_STOPSENDBTN, IDB_SENDDISABLEDBTN } },// Should be messaging
{ 114, 10, 50, 50, { IDB_STATBTN, IDB_STATBTN, IDB_STATBTN } } }; // Should be changing my status
// Static data members must be initialized at file scope, even if private.
HINSTANCE CSessionWndContainer::hInstance;
CSessionWnd* CSessionWndContainer::pSessionWindow;
WNDPROC CSessionWnd::m_pEditProc;
/*************************************************************************************************
CSessionWndContainer constructor
Store the program instance in the container
*************************************************************************************************/
CSessionWndContainer::CSessionWndContainer( HINSTANCE hInst )
{
pSessionWindow = NULL;
hInstance = hInst;
}
/*************************************************************************************************
~CSessionWndContainer destructor
Destroy any existing sessionwindows (at present date, only 1 supported)s
*************************************************************************************************/
CSessionWndContainer::~CSessionWndContainer()
{
if ( pSessionWindow )
delete pSessionWindow;
}
/*************************************************************************************************
MyRegisterSessionWnd
Register the session window class with Win32
*************************************************************************************************/
ATOM CSessionWndContainer::MyRegisterSessionWnd( HINSTANCE hInstance, LPTSTR szWindowClass )
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) CSessionWnd::SessionWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE( IDI_VOIPDEMO ) );
wc.hCursor = 0;
wc.hbrBackground = ( HBRUSH ) CreateSolidBrush( RGB( 128, 128, 255 ) ); // blue background
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
}
/*************************************************************************************************
SessionWndCallback
Handle callback messages from other UI methods, events, and recursive calls.
This callback
*************************************************************************************************/
int CSessionWndContainer::SessionWndCallback( SESSIONWNDCALLBACKMSGS eMsgType, void* pMsgBody, HANDLE hSess )
{
// If the callback has been called with no window present - only valid if initiating from other party or party has left
if ( !pSessionWindow && eMsgType != SWCBM_IM_INITIATING_INCOMING && eMsgType != SWCBM_CALL_INITIATING_INCOMING &&
eMsgType != SWCBM_IM_INITIATING_OUTGOING && eMsgType != SWCBM_CALL_INITIATING_OUTGOING &&
eMsgType != SWCBM_IM_PARTICIPANT_LEFT && eMsgType != SWCBM_CALL_PARTICIPANT_LEFT &&
eMsgType != SWCBM_P2P_CALL_INITIATING_OUTGOING)
{
return 0;
}
switch ( eMsgType )
{
case SWCBM_IM_MESSAGE_LOCAL:
case SWCBM_IM_MESSAGE_STATUS:
case SWCBM_IM_MESSAGE_ARRIVED:
{
// If we have no msg window yet, then set up one now
if ( eMsgType == SWCBM_IM_MESSAGE_ARRIVED && pSessionWindow->ssMessage == SS_INITIATING_INCOMING )
{
if ( !SessionWndCallback( SWCBM_IM_INITIATING_INCOMING, pMsgBody, hSess ) )
{
// If it has been declined
if ( pSessionWindow->m_hWndSession )
{
// Clean window if we have one
pSessionWindow->ssMessage = SS_QUITTING;
pSessionWindow->InvalidateSessionButton( -100 );
pSessionWindow->SessionWndUpdateTitle();
}
// Stop messaging session
SessionStop(pSessionWindow->m_hIMSession);
pSessionWindow->m_hIMSession = NULL;
// If we have no window, destroy the object now (otherwise the window destroy will destroy it later)
if ( !pSessionWindow->m_hWndSession )
{
delete pSessionWindow;
pSessionWindow = NULL;
}
return 0;
}
else
{
// Accepted the session
pSessionWindow->ssMessage = SS_GOING;
pSessionWindow->InvalidateSessionButton( -100 );
pSessionWindow->SessionWndUpdateTitle();
pSessionWindow->SessionWndRedrawClient();
}
}
if( !pSessionWindow->m_hMsgWindow )
return 0;
SWCB_MESSAGE_ARRIVED* pMA = ( SWCB_MESSAGE_ARRIVED* ) pMsgBody;
TCHAR* szTxt;
ASSERT( pMA );
// Print the other party's line (e.g. "xyz says:")
// Only if there's a party in the parameter
if ( pMA->sFrom )
{
szTxt = ( TCHAR* )malloc( wcslen( pMA->sFrom->get_Name() ) * sizeof( TCHAR ) + 32 );
if ( !szTxt )
{
DEBUGMSG( ZONE_ERROR, ( L"VoIPDemo: could not allocate memory for other party's name\r\n" ) );
return 0;
}
wsprintf( szTxt, L"%s says:", pMA->sFrom->get_Name() );
pSessionWindow->AddMessage( szTxt, LMT_SAYS );
free( szTxt );
}
// Now print the message itself line by line
TCHAR* pTxt = pMA->szMsg;
TCHAR* pLine = pMA->szMsg;
DWORD nIndex = 0;
TCHAR szLinePref[] = L" ";
// Need these for figuring out whether a line can fit on the screen or should be wrapped
RECT rt;
GetClientRect( pSessionWindow->m_hWndSession, &rt );
HDC dc = GetDC( pSessionWindow->m_hMsgWindow );
SelectObject( dc, pSessionWindow->m_hFont );
SIZE s = { 0, 0 };
GetTextExtentPoint32( dc, szLinePref, wcslen( szLinePref ), &s );
int nLinePrefWidth = ( eMsgType != SWCBM_IM_MESSAGE_STATUS )?s.cx : 0;
// Run through the text
while ( pTxt && *pTxt )
{
// Find EOL characters
if ( *pTxt == '\n' )
{
// Case of \n
*pTxt = '\0';
szTxt = ( TCHAR* )malloc( wcslen( pLine ) * sizeof( TCHAR ) + 32 );
if ( !szTxt )
break;
wsprintf( szTxt, L"%s%s", ( eMsgType != SWCBM_IM_MESSAGE_STATUS )?szLinePref:L"", pLine );
pSessionWindow->AddMessage( szTxt, ( eMsgType == SWCBM_IM_MESSAGE_STATUS )? LMT_PARTY_ACCEPTED:LMT_TEXT );
free( szTxt );
pLine = pTxt + 1;
}
else
if ( *pTxt == '\r' && *( pTxt+1 ) == '\n' )
{
// Case of \r\n
*pTxt = '\0';
*( pTxt+1 ) = '\0';
szTxt = ( TCHAR* )malloc( wcslen( pLine ) * sizeof( TCHAR ) + 32 );
if ( !szTxt )
break;
wsprintf( szTxt, L"%s%s", ( eMsgType != SWCBM_IM_MESSAGE_STATUS )?szLinePref:L"", pLine );
pSessionWindow->AddMessage( szTxt, ( eMsgType == SWCBM_IM_MESSAGE_STATUS )? LMT_PARTY_ACCEPTED:LMT_TEXT );
free( szTxt );
pTxt++; // 2 to skip!
pLine = pTxt + 1;
}
else
if ( !*( pTxt + 1 ) )
{
// Case of end of text
szTxt = ( TCHAR* )malloc( wcslen( pLine ) * sizeof( TCHAR ) + 32 );
if ( !szTxt )
break;
wsprintf( szTxt, L"%s%s", ( eMsgType != SWCBM_IM_MESSAGE_STATUS )?szLinePref:L"", pLine );
pSessionWindow->AddMessage( szTxt, ( eMsgType == SWCBM_IM_MESSAGE_STATUS )? LMT_PARTY_ACCEPTED:LMT_TEXT );
free( szTxt );
}
else
{
TCHAR ch = *( pTxt + 1 );
*( pTxt + 1 ) = '\0';
SIZE s = { 0, 0 };
GetTextExtentPoint32( dc, pLine, wcslen( pLine ), &s );
*( pTxt + 1 ) = ch;
if ( nLinePrefWidth + s.cx > rt.right - 12 -rt.left - 12 - GetSystemMetrics( SM_CXVSCROLL ) - 16 )
{
ch = *pTxt;
*pTxt = '\0';
// Too long line
szTxt = ( TCHAR* )malloc( wcslen( pLine ) * sizeof( TCHAR ) + 32 );
if ( !szTxt )
break;
wsprintf( szTxt, L"%s%s", ( eMsgType != SWCBM_IM_MESSAGE_STATUS )?szLinePref:L"", pLine );
pSessionWindow->AddMessage( szTxt, ( eMsgType == SWCBM_IM_MESSAGE_STATUS )? LMT_PARTY_ACCEPTED:LMT_TEXT );
free( szTxt );
pLine = pTxt;
*pTxt = ch;
}
}
pTxt++;
}
ReleaseDC( pSessionWindow->m_hMsgWindow, dc );
return 1;
}
case SWCBM_PRESENCECHANGED:
{
if (!pSessionWindow || (IRTCBuddy*) pMsgBody != pSessionWindow->cOtherParty.pBuddy) {
// buddy not in this session, ignore this callback
return 1;
}
// Get the current presence info for the buddy for this session
ESTATUS esOldStatus = pSessionWindow->cOtherParty.eStat;
ESTATUS esThisBuddyStatus = GetBuddyStatus(pSessionWindow->cOtherParty.pBuddy, pSessionWindow->cOtherParty.btBuddyType);
// Check if the status of our other party has changed
if ( esThisBuddyStatus != ES_NOSTATUS && esThisBuddyStatus != esOldStatus )
{
pSessionWindow->cOtherParty.eStat = esThisBuddyStatus;
pSessionWindow->InvalidateSessionButton( -100 );
TCHAR szTxt[ MAX_LOADSTRING ];
LoadString( m_hInstance, esThisBuddyStatus, szTxt, MAX_LOADSTRING );
pSessionWindow->LocalMessage( LMT_PARTY_STATUS_CHANGE, pSessionWindow->cOtherParty.get_Name(), szTxt );
}
return 1;
}
case SWCBM_IM_INITIATING_INCOMING:
case SWCBM_IM_INITIATING_OUTGOING:
{
// Check if it's incoming with or without message
if ( eMsgType == SWCBM_IM_INITIATING_INCOMING && ( !pSessionWindow || pSessionWindow->ssMessage == SS_OFF ) )
{
// Incoming with no message
// Make a new session window if we have none
if ( !pSessionWindow ) {
pSessionWindow = new CSessionWnd();
}
// Incoming with no msg -> just change status
pSessionWindow->ssMessage = SS_INITIATING_INCOMING;
pSessionWindow->InvalidateSessionButton( -100 );
pSessionWindow->SessionWndUpdateTitle();
// need to get the session handle here
pSessionWindow->m_hIMSession = hSess;
return 1;
}
SWCB_PARTICIPANT_INFO* pPI;
// Init other party's structure
if ( eMsgType == SWCBM_IM_INITIATING_INCOMING ) {
pPI = (( SWCB_MESSAGE_ARRIVED* ) pMsgBody)->sFrom;
} else {
pPI = ( SWCB_PARTICIPANT_INFO* ) pMsgBody;
}
// Throw message box for accepting or declining session
if ( eMsgType == SWCBM_IM_INITIATING_INCOMING )
{
TCHAR* szTxt = ( TCHAR* ) malloc( ( wcslen( ( ( SWCB_MESSAGE_ARRIVED* ) pMsgBody )->szMsg ) +
wcslen( pPI->get_Name() ) +
64 ) * sizeof( TCHAR ) );
wsprintf( szTxt, L"%s said:\r\n%s\r\nDo you accept this messaging session?", pPI->get_Name(), ( ( SWCB_MESSAGE_ARRIVED* ) pMsgBody )->szMsg );
TCHAR szTitle[ MAX_LOADSTRING ];
LoadString( m_hInstance, IDS_MSGSESSION, szTitle, MAX_LOADSTRING );
int iRet = MessageBox( NULL, szTxt, szTitle, MB_YESNO );
free( szTxt );
if ( iRet == IDNO )
{
pSessionWindow->m_hIMSession = NULL;
// Return with rejected
return 0;
}
else
if ( iRet == IDABORT || iRet == IDIGNORE )
{
pSessionWindow->m_hIMSession = NULL;
// Return with timed out
return 2;
}
}
// If there's no window (just receiving an invitation), pull up window now
if ( !pSessionWindow ) {
pSessionWindow = new CSessionWnd();
}
if ( !pSessionWindow->m_hWndSession )
{
pSessionWindow->OpenSessionWnd( pPI, eMsgType );
}
pSessionWindow->ssMessage = SS_INITIATING;
pSessionWindow->InvalidateSessionButton( -100 );
pSessionWindow->SessionWndUpdateTitle();
pSessionWindow->SessionWndRedrawClient();
pSessionWindow->SessionWndScrollMessages();
if ( eMsgType == SWCBM_IM_INITIATING_OUTGOING ) {
// create the call
if (!(pSessionWindow->m_hIMSession = OpenSessionTo( (PARTICIPANT_INFO*) pMsgBody, RTCST_IM, (FARPROC) SessionWndCallback))) {
// NOTE: need some sort of error message/error handling
}
} else if ( eMsgType == SWCBM_IM_INITIATING_INCOMING ) {
pSessionWindow->m_hIMSession = hSess;
DEBUGMSG( ZONE_STATUS, (L"Voipdemo:SessionWnd storing %l as the IM Session handle\r\n", hSess) );
}
return 1;
}
case SWCBM_IM_PARTICIPANT_JOINED:
if ( pSessionWindow && pSessionWindow->ssMessage != SS_INITIATING_INCOMING )
{
// These are going to happen on the callee side only if accepted
pSessionWindow->ssMessage = SS_GOING;
pSessionWindow->InvalidateSessionButton( -100 );
pSessionWindow->SessionWndUpdateTitle();
pSessionWindow->SessionWndRedrawClient();
pSessionWindow->SessionWndScrollMessages();
// The caller should see an acceptance message
pSessionWindow->LocalMessage( LMT_PARTY_ACCEPTED, (BSTR) pMsgBody, L"messaging" );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -