📄 netconnect.cpp
字号:
case WM_DESTROY:
{
KillTimer( hDlg, 1 );
// Cancel the enum hosts search
// if the enumeration is going on
if( m_bSearchingForSessions && m_hEnumAsyncOp )
{
m_pDP->CancelAsyncOperation( m_hEnumAsyncOp, 0 );
m_bSearchingForSessions = FALSE;
}
break;
}
default:
return FALSE; // Message not handled
}
// Message was handled
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgInitListbox()
// Desc: Initializes the listbox
//-----------------------------------------------------------------------------
VOID CNetConnectWizard::SessionsDlgInitListbox( HWND hDlg )
{
HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
// Clear the contents from the list box, and
// display "Looking for games" text in listbox
SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
if( m_bSearchingForSessions )
{
SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM) TEXT("Looking for games...") );
}
else
{
SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM) TEXT("Click Start Search to see a list of games. ")
TEXT("Click Create to start a new game.") );
}
SendMessage( hWndListBox, LB_SETITEMDATA, 0, NULL );
SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
// Disable the join button until sessions are found
EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), FALSE );
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgEnumHosts()
// Desc: Enumerates the DirectPlay sessions, and displays them in the listbox
//-----------------------------------------------------------------------------
HRESULT CNetConnectWizard::SessionsDlgEnumHosts( HWND hDlg )
{
HRESULT hr;
m_bEnumListChanged = TRUE;
// Enumerate hosts
DPN_APPLICATION_DESC dnAppDesc;
ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
dnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC);
dnAppDesc.guidApplication = m_guidApp;
// Enumerate all the active DirectPlay games on the selected connection
hr = m_pDP->EnumHosts( &dnAppDesc, // application description
m_pHostAddress, // host address
m_pDeviceAddress, // device address
NULL, // pointer to user data
0, // user data size
INFINITE, // retry count (forever)
0, // retry interval (0=default)
INFINITE, // time out (forever)
NULL, // user context
&m_hEnumAsyncOp, // async handle
DPNENUMHOSTS_OKTOQUERYFORADDRESSING // flags
);
if( FAILED(hr) )
return DXTRACE_ERR( TEXT("EnumHosts"), hr );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgNoteEnumResponse()
// Desc: Stores them in the linked list, m_DPHostEnumHead. This is
// called from the DirectPlay message handler so it could be
// called simultaneously from multiple threads.
//-----------------------------------------------------------------------------
HRESULT CNetConnectWizard::SessionsDlgNoteEnumResponse( PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg )
{
HRESULT hr = S_OK;
BOOL bFound;
// This function is called from the DirectPlay message handler so it could be
// called simultaneously from multiple threads, so enter a critical section
// to assure that it we don't get race conditions. Locking the entire
// function is crude, and could be more optimal but is effective for this
// simple sample
EnterCriticalSection( &m_csHostEnum );
DPHostEnumInfo* pDPHostEnum = m_DPHostEnumHead.pNext;
DPHostEnumInfo* pDPHostEnumNext = NULL;
const DPN_APPLICATION_DESC* pResponseMsgAppDesc =
pEnumHostsResponseMsg->pApplicationDescription;
// Look for a matching session instance GUID.
bFound = FALSE;
while ( pDPHostEnum != &m_DPHostEnumHead )
{
if( pResponseMsgAppDesc->guidInstance == pDPHostEnum->pAppDesc->guidInstance )
{
bFound = TRUE;
break;
}
pDPHostEnumNext = pDPHostEnum;
pDPHostEnum = pDPHostEnum->pNext;
}
if( !bFound )
{
m_bEnumListChanged = TRUE;
// If there's no match, then look for invalid session and use it
pDPHostEnum = m_DPHostEnumHead.pNext;
while ( pDPHostEnum != &m_DPHostEnumHead )
{
if( !pDPHostEnum->bValid )
break;
pDPHostEnum = pDPHostEnum->pNext;
}
// If no invalid sessions are found then make a new one
if( pDPHostEnum == &m_DPHostEnumHead )
{
// Found a new session, so create a new node
pDPHostEnum = new DPHostEnumInfo;
if( NULL == pDPHostEnum )
{
hr = E_OUTOFMEMORY;
goto LCleanup;
}
ZeroMemory( pDPHostEnum, sizeof(DPHostEnumInfo) );
// Add pDPHostEnum to the circular linked list, m_DPHostEnumHead
pDPHostEnum->pNext = m_DPHostEnumHead.pNext;
m_DPHostEnumHead.pNext = pDPHostEnum;
}
}
// Update the pDPHostEnum with new information
TCHAR strName[MAX_PATH];
if( pResponseMsgAppDesc->pwszSessionName )
{
DXUtil_ConvertWideStringToGeneric( strName, pResponseMsgAppDesc->pwszSessionName );
}
// Cleanup any old enum
if( pDPHostEnum->pAppDesc )
{
SAFE_DELETE_ARRAY( pDPHostEnum->pAppDesc->pwszSessionName );
SAFE_DELETE_ARRAY( pDPHostEnum->pAppDesc );
}
SAFE_RELEASE( pDPHostEnum->pHostAddr );
SAFE_RELEASE( pDPHostEnum->pDeviceAddr );
//
// Duplicate pEnumHostsResponseMsg->pAddressSender in pDPHostEnum->pHostAddr.
// Duplicate pEnumHostsResponseMsg->pAddressDevice in pDPHostEnum->pDeviceAddr.
//
if( FAILED( hr = pEnumHostsResponseMsg->pAddressSender->Duplicate( &pDPHostEnum->pHostAddr ) ) )
{
DXTRACE_ERR( TEXT("Duplicate"), hr );
goto LCleanup;
}
if( FAILED( hr = pEnumHostsResponseMsg->pAddressDevice->Duplicate( &pDPHostEnum->pDeviceAddr ) ) )
{
DXTRACE_ERR( TEXT("Duplicate"), hr );
goto LCleanup;
}
// Deep copy the DPN_APPLICATION_DESC from
pDPHostEnum->pAppDesc = new DPN_APPLICATION_DESC;
ZeroMemory( pDPHostEnum->pAppDesc, sizeof(DPN_APPLICATION_DESC) );
memcpy( pDPHostEnum->pAppDesc, pResponseMsgAppDesc, sizeof(DPN_APPLICATION_DESC) );
if( pResponseMsgAppDesc->pwszSessionName )
{
pDPHostEnum->pAppDesc->pwszSessionName = new WCHAR[ wcslen(pResponseMsgAppDesc->pwszSessionName)+1 ];
wcscpy( pDPHostEnum->pAppDesc->pwszSessionName,
pResponseMsgAppDesc->pwszSessionName );
}
// 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 = timeGetTime();
// Check to see if the current number of players changed
TCHAR szSessionTemp[MAX_PATH];
if( pResponseMsgAppDesc->dwMaxPlayers > 0 )
{
wsprintf( szSessionTemp, TEXT("%s (%d/%d) (%dms)"), strName,
pResponseMsgAppDesc->dwCurrentPlayers,
pResponseMsgAppDesc->dwMaxPlayers,
pEnumHostsResponseMsg->dwRoundTripLatencyMS );
}
else
{
wsprintf( szSessionTemp, TEXT("%s (%d) (%dms)"), strName,
pResponseMsgAppDesc->dwCurrentPlayers,
pEnumHostsResponseMsg->dwRoundTripLatencyMS );
}
// 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 CNetConnectWizard::SessionsDlgExpireOldHostEnums()
{
DWORD dwCurrentTime = timeGetTime();
// 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 CNetConnectWizard::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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -