📄 netclient.cpp
字号:
//-----------------------------------------------------------------------------
// Name: MessageHandler
// Desc: Handler for DirectPlay messages. This function is called by
// the DirectPlay message handler pool of threads, so be careful of thread
// synchronization problems with shared memory
//-----------------------------------------------------------------------------
HRESULT WINAPI CNetClientWizard::MessageHandler( PVOID pvUserContext,
DWORD dwMessageId,
PVOID pMsgBuffer )
{
// Try not to stay in this message handler for too long, otherwise
// there will be a backlog of data. The best solution is to
// queue data as it comes in, and then handle it on other threads.
// This function is called by the DirectPlay message handler pool of
// threads, so be careful of thread synchronization problems with shared memory
switch(dwMessageId)
{
case DPN_MSGID_ENUM_HOSTS_RESPONSE:
{
PDPNMSG_ENUM_HOSTS_RESPONSE pEnumHostsResponseMsg;
pEnumHostsResponseMsg = (PDPNMSG_ENUM_HOSTS_RESPONSE)pMsgBuffer;
// Take note of the host response
SessionsDlgNoteEnumResponse( pEnumHostsResponseMsg );
break;
}
case DPN_MSGID_ASYNC_OP_COMPLETE:
{
PDPNMSG_ASYNC_OP_COMPLETE pAsyncOpCompleteMsg;
pAsyncOpCompleteMsg = (PDPNMSG_ASYNC_OP_COMPLETE)pMsgBuffer;
if( pAsyncOpCompleteMsg->hAsyncOp == m_hEnumAsyncOp )
{
SessionsDlgEnumListCleanup();
// The user canceled the DirectPlay connection dialog,
// so stop the search
if( m_bSearchingForSessions )
{
CheckDlgButton( m_hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
SendMessage( m_hDlg, WM_COMMAND, IDC_SEARCH_CHECK, 0 );
}
m_hEnumAsyncOp = NULL;
m_bSearchingForSessions = FALSE;
}
break;
}
case DPN_MSGID_CONNECT_COMPLETE:
{
PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg;
pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer;
// Set m_hrConnectComplete, then set an event letting
// everyone know that the DPN_MSGID_CONNECT_COMPLETE msg
// has been handled
m_hrConnectComplete = pConnectCompleteMsg->hResultCode;
SetEvent( m_hConnectCompleteEvent );
break;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: ConnectUsingLobbySettings
// Desc: Call this after the DPL_MSGID_CONNECT has been processed to carry out
// the connection settings received by the lobby client. DPL_MSGID_CONNECT
// will have already been processed if we were lobby launched, or after
// WaitForConnection returns without timing out.
//-----------------------------------------------------------------------------
HRESULT CNetClientWizard::ConnectUsingLobbySettings()
{
HRESULT hr;
DPNHANDLE hAsync;
if( m_hLobbyClient == NULL )
return E_INVALIDARG;
DPL_CONNECTION_SETTINGS* pSettings = NULL;
DWORD dwSettingsSize = 0;
// Get the connection settings from the lobby.
hr = m_pLobbiedApp->GetConnectionSettings( m_hLobbyClient, pSettings, &dwSettingsSize, 0 );
if( hr != DPNERR_BUFFERTOOSMALL )
{
DXTRACE_ERR_MSGBOX( TEXT("GetConnectionSettings"), hr );
goto LCleanReturn;
}
pSettings = (DPL_CONNECTION_SETTINGS*) new BYTE[dwSettingsSize];
if( NULL == pSettings )
{
hr = E_OUTOFMEMORY;
DXTRACE_ERR_MSGBOX( TEXT("ConnectUsingLobbySettings"), hr );
goto LCleanReturn;
}
if( FAILED( hr = m_pLobbiedApp->GetConnectionSettings( m_hLobbyClient, pSettings, &dwSettingsSize, 0 ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("GetConnectionSettings"), hr );
goto LCleanReturn;
}
// Set the peer info
WCHAR wszPeerName[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;
}
// Connect to an existing session. There should only be on device address in
// the connection settings structure when connecting to a session, so just
// pass in the first one.
// The enumeration is automatically cancelled after Connect is called
hr = m_pDPClient->Connect( &pSettings->dpnAppDesc, // the application desc
pSettings->pdp8HostAddress, // address of the host of the session
pSettings->ppdp8DeviceAddresses[0], // address of the local device used to connect to the host
NULL, NULL, // DPN_SECURITY_DESC, DPN_SECURITY_CREDENTIALS
NULL, 0, // user data, user data size
NULL, &hAsync, // async context, async handle,
0 ); // flags
if( hr != E_PENDING && FAILED(hr) )
{
DXTRACE_ERR_MSGBOX( TEXT("Connect"), hr );
goto LCleanReturn;
}
hr = S_OK; // Accept E_PENDING.
// Wait until the MessageHandler sets an event to tell us the
// DPN_MSGID_CONNECT_COMPLETE has been processed. Then m_hrConnectComplete
// will be valid.
WaitForSingleObject( m_hConnectCompleteEvent, INFINITE );
if( FAILED( m_hrConnectComplete ) )
{
DXTRACE_ERR_MSGBOX( TEXT("DPN_MSGID_CONNECT_COMPLETE"), m_hrConnectComplete );
MessageBox( m_hDlg, TEXT("Unable to join game."),
TEXT("DirectPlay Sample"),
MB_OK | MB_ICONERROR );
hr = m_hrConnectComplete;
}
// Cleanup the addresses and memory obtained from GetConnectionSettings
LCleanReturn:
if( pSettings )
{
SAFE_RELEASE( pSettings->pdp8HostAddress );
for( DWORD dwIndex=0; dwIndex < pSettings->cNumDeviceAddresses; dwIndex++ )
SAFE_RELEASE( pSettings->ppdp8DeviceAddresses[dwIndex] );
SAFE_DELETE_ARRAY( pSettings );
}
return hr;
}
//-----------------------------------------------------------------------------
// Name: LobbyMessageHandler
// Desc: Handler for DirectPlay messages. This function is called by
// the DirectPlay lobby message handler pool of threads, so be careful of thread
// synchronization problems with shared memory
//-----------------------------------------------------------------------------
HRESULT WINAPI CNetClientWizard::LobbyMessageHandler( PVOID pvUserContext,
DWORD dwMessageId,
PVOID pMsgBuffer )
{
HRESULT hr = S_OK;
switch(dwMessageId)
{
case DPL_MSGID_CONNECT:
{
// This message will be processed when a lobby connection has been
// established. If you were lobby launched then
// IDirectPlay8LobbiedApplication::Initialize()
// waits until this message has been processed before returning, so
// take care not to deadlock by making calls that need to be handled by
// the thread who called Initialize(). The same is true for WaitForConnection()
PDPL_MESSAGE_CONNECT pConnectMsg;
pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
PDPL_CONNECTION_SETTINGS pSettings = pConnectMsg->pdplConnectionSettings;
m_hLobbyClient = pConnectMsg->hConnectId;
if( FAILED( hr = m_pDPClient->RegisterLobby( m_hLobbyClient, m_pLobbiedApp,
DPNLOBBY_REGISTER ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("RegisterLobby"), hr );
if( pSettings == NULL )
{
// There aren't connection settings from the lobby
m_bHaveConnectionSettingsFromLobby = FALSE;
}
else
{
// Record the player name if found
if( pSettings->pwszPlayerName != NULL )
{
TCHAR strPlayerName[MAX_PLAYER_NAME];
DXUtil_ConvertWideStringToGenericCch( strPlayerName, pSettings->pwszPlayerName, MAX_PLAYER_NAME );
_tcsncpy( m_strLocalPlayerName, strPlayerName, MAX_PLAYER_NAME );
m_strLocalPlayerName[MAX_PLAYER_NAME-1] = 0;
}
else
{
_tcsncpy( m_strLocalPlayerName, TEXT("Unknown"), MAX_PLAYER_NAME );
m_strLocalPlayerName[MAX_PLAYER_NAME-1] = 0;
}
m_bHaveConnectionSettingsFromLobby = TRUE;
}
// Tell everyone we have a lobby connection now
SetEvent( m_hLobbyConnectionEvent );
break;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: StaticLobbyWaitDlgProc()
// Desc: Static msg handler which passes messages
//-----------------------------------------------------------------------------
INT_PTR CALLBACK CNetClientWizard::StaticLobbyWaitDlgProc( HWND hDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
if( g_pNCW )
return g_pNCW->LobbyWaitDlgProc( hDlg, uMsg, wParam, lParam );
return FALSE; // Message not handled
}
//-----------------------------------------------------------------------------
// Name: LobbyWaitDlgProc()
// Desc: Handles messages for the lobby wait status dialog
//-----------------------------------------------------------------------------
INT_PTR CALLBACK CNetClientWizard::LobbyWaitDlgProc( HWND hDlg, UINT msg,
WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_INITDIALOG:
#if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
SHINITDLGINFO shidi;
memset(&shidi, 0, sizeof(SHINITDLGINFO));
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
shidi.hDlg = hDlg;
SetForegroundWindow(hDlg);
SHInitDialog(&shidi);
#endif // WIN32_PLATFORM_PSPC
// 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 );
SetDlgItemText( hDlg, IDC_WAIT_TEXT, TEXT("Waiting for lobby connection...") );
return TRUE;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDCANCEL:
EndDialog( hDlg, IDCANCEL );
return TRUE;
}
break;
case WM_TIMER:
{
if( wParam == TIMERID_CONNECT_COMPLETE )
{
// Wait for a lobby connection. If this call
// returns WAIT_OBJECT_0 then the DPL_MSGID_CONNECT will
// have already been processed.
DWORD dwResult = WaitForSingleObject( m_hLobbyConnectionEvent, 100 );
if( dwResult != WAIT_TIMEOUT )
EndDialog( hDlg, IDOK );
}
break;
}
}
return FALSE; // Didn't handle message
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -