📄 netclient.cpp
字号:
if( NULL == wstr )
{
hr = E_OUTOFMEMORY;
DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgNoteEnumResponse"), hr );
goto LCleanup;
}
wcscpy( wstr, pResponseMsgAppDesc->pwszSessionName );
pDPHostEnum->pAppDesc->pwszSessionName = wstr;
}
// Update the time this was done, so that we can expire this host
// if it doesn't refresh w/in a certain amount of time
pDPHostEnum->dwLastPollTime = GETTIMESTAMP();
// Check to see if the current number of players changed
TCHAR szSessionTemp[MAX_PATH];
if( pResponseMsgAppDesc->dwMaxPlayers > 0 )
{
_sntprintf( szSessionTemp, MAX_PATH-1, TEXT("%s (%d/%d) (%dms)"), strName,
pResponseMsgAppDesc->dwCurrentPlayers - 1, // ignore the host player
pResponseMsgAppDesc->dwMaxPlayers - 1, // ignore the host player
pEnumHostsResponseMsg->dwRoundTripLatencyMS );
// Null terminate
szSessionTemp[ MAX_PATH-1 ] = 0;
}
else
{
_sntprintf( szSessionTemp, MAX_PATH-1, TEXT("%s (%d) (%dms)"), strName,
pResponseMsgAppDesc->dwCurrentPlayers - 1, // ignore the host player
pEnumHostsResponseMsg->dwRoundTripLatencyMS );
// Null terminate
szSessionTemp[ MAX_PATH-1 ] = 0;
}
// if this node was previously invalidated, or the session name is now
// different the session list in the dialog needs to be updated
if( ( pDPHostEnum->bValid == FALSE ) ||
( _tcscmp( pDPHostEnum->szSession, szSessionTemp ) != 0 ) )
{
m_bEnumListChanged = TRUE;
}
_tcscpy( pDPHostEnum->szSession, szSessionTemp );
// This host is now valid
pDPHostEnum->bValid = TRUE;
LCleanup:
LeaveCriticalSection( &m_csHostEnum );
return hr;
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgExpireOldHostEnums
// Desc: Check all nodes to see if any have expired yet.
//-----------------------------------------------------------------------------
VOID CNetClientWizard::SessionsDlgExpireOldHostEnums()
{
DWORD dwCurrentTime = GETTIMESTAMP();
// This is called from the dialog UI thread, SessionsDlgNoteEnumResponse
// is called from the DirectPlay message handler threads so
// they may also be inside it at this time, so we need to go into the
// critical section first
EnterCriticalSection( &m_csHostEnum );
DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
while ( pDPHostEnum != &m_DPHostEnumHead )
{
// Check the poll time to expire stale entries. Also check to see if
// the entry is already invalid. If so, don't note that the enum list
// changed because that causes the list in the dialog to constantly redraw.
if( ( pDPHostEnum->bValid != FALSE ) &&
( pDPHostEnum->dwLastPollTime < dwCurrentTime - m_dwEnumHostExpireInterval ) )
{
// This node has expired, so invalidate it.
pDPHostEnum->bValid = FALSE;
m_bEnumListChanged = TRUE;
}
pDPHostEnum = pDPHostEnum->pNext;
}
LeaveCriticalSection( &m_csHostEnum );
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgDisplayEnumList
// Desc: Display the list of hosts in the dialog box
//-----------------------------------------------------------------------------
HRESULT CNetClientWizard::SessionsDlgDisplayEnumList( HWND hDlg )
{
HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
DPHostEnumInfo* pDPHostEnumSelected = NULL;
GUID guidSelectedInstance;
BOOL bFindSelectedGUID;
BOOL bFoundSelectedGUID;
int nItemSelected;
// This is called from the dialog UI thread, SessionsDlgNoteEnumResponse
// is called from the DirectPlay message handler threads so
// they may also be inside it at this time, so we need to go into the
// critical section first
EnterCriticalSection( &m_csHostEnum );
// Only update the display list if it has changed since last time
if( !m_bEnumListChanged )
{
LeaveCriticalSection( &m_csHostEnum );
return S_OK;
}
m_bEnumListChanged = FALSE;
bFindSelectedGUID = FALSE;
bFoundSelectedGUID = FALSE;
// Try to keep the same session selected unless it goes away or
// there is no real session currently selected
nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
if( nItemSelected != LB_ERR )
{
pDPHostEnumSelected = (DPHostEnumInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
nItemSelected, 0 );
if( pDPHostEnumSelected != NULL && pDPHostEnumSelected->bValid )
{
guidSelectedInstance = pDPHostEnumSelected->pAppDesc->guidInstance;
bFindSelectedGUID = TRUE;
}
}
// Tell listbox not to redraw itself since the contents are going to change
SendMessage( hWndListBox, WM_SETREDRAW, FALSE, 0 );
// Test to see if any sessions exist in the linked list
DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
while ( pDPHostEnum != &m_DPHostEnumHead )
{
if( pDPHostEnum->bValid )
break;
pDPHostEnum = pDPHostEnum->pNext;
}
// If there are any sessions in list,
// then add them to the listbox
if( pDPHostEnum != &m_DPHostEnumHead )
{
// Clear the contents from the list box and enable the join button
SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
// Enable the join button only if not already connecting to a game
if( !m_bConnecting )
EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), TRUE );
pDPHostEnum = m_DPHostEnumHead.pNext;
while ( pDPHostEnum != &m_DPHostEnumHead )
{
// Add host to list box if it is valid
if( pDPHostEnum->bValid )
{
int nIndex = (int)SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM)pDPHostEnum->szSession );
SendMessage( hWndListBox, LB_SETITEMDATA, nIndex, (LPARAM)pDPHostEnum );
if( bFindSelectedGUID )
{
// Look for the session the was selected before
if( pDPHostEnum->pAppDesc->guidInstance == guidSelectedInstance )
{
SendMessage( hWndListBox, LB_SETCURSEL, nIndex, 0 );
bFoundSelectedGUID = TRUE;
}
}
}
pDPHostEnum = pDPHostEnum->pNext;
}
if( !bFindSelectedGUID || !bFoundSelectedGUID )
SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
}
else
{
// There are no active session, so just reset the listbox
SessionsDlgInitListbox( hDlg );
}
// Tell listbox to redraw itself now since the contents have changed
SendMessage( hWndListBox, WM_SETREDRAW, TRUE, 0 );
InvalidateRect( hWndListBox, NULL, FALSE );
LeaveCriticalSection( &m_csHostEnum );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgJoinGame()
// Desc: Joins the selected DirectPlay session
//-----------------------------------------------------------------------------
HRESULT CNetClientWizard::SessionsDlgJoinGame( HWND hDlg )
{
HRESULT hr;
HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
DPHostEnumInfo* pDPHostEnumSelected = NULL;
int nItemSelected;
// Add status text in list box
nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
EnterCriticalSection( &m_csHostEnum );
pDPHostEnumSelected = (DPHostEnumInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
nItemSelected, 0 );
if( NULL == pDPHostEnumSelected )
{
MessageBox( hDlg, TEXT("There are no games to join."),
TEXT("DirectPlay Sample"), MB_OK );
hr = S_OK;
goto LCleanReturn;
}
m_bConnecting = TRUE;
// Set the peer info
WCHAR wszPeerName[MAX_PLAYER_NAME];
GetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, m_strLocalPlayerName, MAX_PLAYER_NAME );
DXUtil_ConvertGenericStringToWideCch( wszPeerName, m_strLocalPlayerName, MAX_PLAYER_NAME );
DPN_PLAYER_INFO dpPlayerInfo;
ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) );
dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO);
dpPlayerInfo.dwInfoFlags = DPNINFO_NAME;
dpPlayerInfo.pwszName = wszPeerName;
// Set the peer info, and use the DPNOP_SYNC since by default this
// is an async call. If it is not DPNOP_SYNC, then the peer info may not
// be set by the time we call Connect() below.
if( FAILED( hr = m_pDPClient->SetClientInfo( &dpPlayerInfo, NULL, NULL, DPNOP_SYNC ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("SetClientInfo"), hr );
goto LCleanReturn;
}
ResetEvent( m_hConnectCompleteEvent );
// Connect to an existing session. DPNCONNECT_OKTOQUERYFORADDRESSING allows
// DirectPlay to prompt the user using a dialog box for any device address
// or host address information that is missing
// We also pass in copies of the app desc and host addr, since pDPHostEnumSelected
// might be deleted from another thread that calls SessionsDlgExpireOldHostEnums().
// This process could also be done using reference counting instead.
hr = m_pDPClient->Connect( pDPHostEnumSelected->pAppDesc, // the application desc
pDPHostEnumSelected->pHostAddr, // address of the host of the session
pDPHostEnumSelected->pDeviceAddr, // address of the local device the enum responses were received on
NULL, NULL, // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
NULL, 0, // user data, user data size
NULL, &m_hConnectAsyncOp, // async context, async handle,
DPNCONNECT_OKTOQUERYFORADDRESSING ); // flags
if( FAILED(hr) && hr != E_PENDING )
{
DXTRACE_ERR_MSGBOX( TEXT("Connect"), hr );
goto LCleanReturn;
}
// Set a timer to wait for m_hConnectCompleteEvent to be signaled.
// This will tell us when DPN_MSGID_CONNECT_COMPLETE has been processed
// which lets us know if the connect was successful or not.
SetTimer( hDlg, TIMERID_CONNECT_COMPLETE, 100, NULL );
// Disable the join button until connect succeeds or fails
EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), FALSE );
hr = S_OK;
LCleanReturn:
LeaveCriticalSection( &m_csHostEnum );
return hr;
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgEnumListCleanup()
// Desc: Deletes the linked list, g_DPHostEnumInfoHead
//-----------------------------------------------------------------------------
VOID CNetClientWizard::SessionsDlgEnumListCleanup()
{
DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
DPHostEnumInfo* pDPHostEnumDelete;
while ( pDPHostEnum != &m_DPHostEnumHead )
{
pDPHostEnumDelete = pDPHostEnum;
pDPHostEnum = pDPHostEnum->pNext;
if( pDPHostEnumDelete->pAppDesc )
{
SAFE_DELETE_ARRAY( pDPHostEnumDelete->pAppDesc->pwszSessionName );
SAFE_DELETE( pDPHostEnumDelete->pAppDesc );
}
// Changed from array delete to Release
SAFE_RELEASE( pDPHostEnumDelete->pHostAddr );
SAFE_RELEASE( pDPHostEnumDelete->pDeviceAddr );
SAFE_DELETE( pDPHostEnumDelete );
}
// Re-link the g_DPHostEnumInfoHead circular linked list
m_DPHostEnumHead.pNext = &m_DPHostEnumHead;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -