📄 netconnect.cpp
字号:
}
break;
case IDC_CREATE:
if( FAILED( hr = SessionsDlgCreateGame( hDlg ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgCreateGame"), hr );
MessageBox( hDlg, TEXT("Unable to create game."),
TEXT("DirectPlay Sample"),
MB_OK | MB_ICONERROR );
}
break;
case IDCANCEL: // The close button was press
m_hrDialog = NCW_S_QUIT;
EndDialog(hDlg, 0);
break;
case IDC_BACK: // Cancel button was pressed
m_hrDialog = NCW_S_BACKUP;
EndDialog(hDlg, 0);
break;
default:
return FALSE; // Message not handled
}
break;
case WM_DESTROY:
SessionsDlgStopEnumHosts(hDlg);
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."));
SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM) 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 )
{
UNREFERENCED_PARAMETER( hDlg );
HRESULT hr = S_OK;
m_bEnumListChanged = TRUE;
IDirectPlay8Address* pDP8AddressHost = NULL;
IDirectPlay8Address* pDP8AddressLocal = NULL;
// Create the local device address object
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,
CLSCTX_ALL, IID_IDirectPlay8Address,
(LPVOID*) &pDP8AddressLocal ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("CoCreateInstance"), hr );
goto LCleanup;
}
// Set local service provider
if( FAILED( hr = pDP8AddressLocal->SetSP( &m_guidSP ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("SetSP"), hr );
goto LCleanup;
}
// Create the remote host address object
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL,
CLSCTX_ALL, IID_IDirectPlay8Address,
(LPVOID*) &pDP8AddressHost ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("CoCreateInstance"), hr );
goto LCleanup;
}
// Set remote service provider
if( FAILED( hr = pDP8AddressHost->SetSP( &m_guidSP ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("SetSP"), hr );
goto LCleanup;
}
// If we're using a TCP/IP (including network simulator) or IPX
// service provider, the user was given an option for hostname and
// port before the search started.
if( SPRequiresPort( &m_guidSP ) )
{
// Add the hostname. If this is blank, DirectPlay will attempt
// to search the local network.
if( _tcscmp(m_strHostname, TEXT("")) != 0 )
{
WCHAR wszHostName[MAX_PATH];
DXUtil_ConvertGenericStringToWideCch( wszHostName, m_strHostname, MAX_PATH );
hr = pDP8AddressHost->AddComponent( DPNA_KEY_HOSTNAME, wszHostName,
(DWORD) (wcslen(wszHostName)+1)*sizeof(WCHAR),
DPNA_DATATYPE_STRING );
if( FAILED(hr) )
{
DXTRACE_ERR_MSGBOX( TEXT("AddComponent"), hr );
goto LCleanup;
}
}
// Add the requested port value. The port value is required in order to
// receive any search hits if DPNSVR isn't running on the remote machine.
// Games will typically hard code the port so the user need not know it
if( m_dwPort != 0 )
{
hr = pDP8AddressHost->AddComponent( DPNA_KEY_PORT,
&m_dwPort, sizeof(m_dwPort),
DPNA_DATATYPE_DWORD );
if( FAILED(hr) )
{
DXTRACE_ERR_MSGBOX( TEXT("AddComponent"), hr );
goto LCleanup;
}
}
}
// Enumerate hosts
DPN_APPLICATION_DESC dnAppDesc;
ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) );
dnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC);
dnAppDesc.guidApplication = m_guidApp;
DWORD dwFlags;
dwFlags = 0;
// For certain service providers the user has not been
// asked to fill in the components of the remote address,
// so DirectPlay should ask for required fields.
if( !SPRequiresPort( &m_guidSP ) )
{
dwFlags = DPNENUMHOSTS_OKTOQUERYFORADDRESSING;
}
// Enumerate all the active DirectPlay games on the selected connection
hr = m_pDP->EnumHosts( &dnAppDesc, // application description
pDP8AddressHost, // host address
pDP8AddressLocal, // 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
dwFlags // flags
);
if( FAILED(hr) )
{
DXTRACE_ERR_MSGBOX( TEXT("EnumHosts"), hr );
goto LCleanup;
}
LCleanup:
SAFE_RELEASE( pDP8AddressHost);
SAFE_RELEASE( pDP8AddressLocal );
return hr;
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgStopEnumHosts()
// Desc: Stops the running session enumeration
//-----------------------------------------------------------------------------
VOID CNetConnectWizard::SessionsDlgStopEnumHosts( HWND hDlg )
{
HRESULT hr;
// Update the UI
EnableWindow( GetDlgItem( hDlg, IDC_SEARCH_CHECK ), FALSE );
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Stopping...") );
// Stop the timer, and stop the async enumeration
KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
// Until the CancelAsyncOperation returns, it is possible
// to still receive host enumerations. Instruct DirectPlay to
// stop the current enumeration and handle the rest of the cleanup
// when receiving the ASYNC_OP_COMPLETE message. If this method
// fails we should assume there's no active enumeration and call
// the finalization method directly.
if( m_hEnumAsyncOp )
{
hr = m_pDP->CancelAsyncOperation( m_hEnumAsyncOp, 0 );
if( FAILED(hr) )
SessionsDlgFinalizeEnumHosts( hDlg );
}
else
{
SessionsDlgFinalizeEnumHosts( hDlg );
}
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgFinalizeEnumHosts()
// Desc: This method should be called when we receive confirmation from
// DirectPlay that the enumeration has completed. It reset the search
// UI and state variables, and enables the search button.
//-----------------------------------------------------------------------------
VOID CNetConnectWizard::SessionsDlgFinalizeEnumHosts( HWND hDlg )
{
// Clear the data list
SessionsDlgEnumListCleanup();
// Reset the search state variables
m_hEnumAsyncOp = NULL;
m_bSearchingForSessions = FALSE;
// Reset the search portion of the dialog
SessionsDlgInitListbox( hDlg );
CheckDlgButton( hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start &Search") );
EnableWindow( GetDlgItem( hDlg, IDC_SEARCH_CHECK ), TRUE );
}
//-----------------------------------------------------------------------------
// 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_ConvertWideStringToGenericCch( strName, pResponseMsgAppDesc->pwszSessionName, MAX_PATH );
}
// Cleanup any old enum
if( pDPHostEnum->pAppDesc )
{
SAFE_DELETE_ARRAY( pDPHostEnum->pAppDesc->pwszSessionName );
SAFE_DELETE( pDPHostEnum->pAppDesc );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -