📄 netclient.cpp
字号:
//-----------------------------------------------------------------------------
// File: NetClient.cpp
//
// Desc: This is a class that given a IDirectPlay8Client upon DoConnectWizard()
// will enumerate hosts, and allows the user to join a session. The class uses
// dialog boxes and GDI for the interactive UI. Most games will
// want to change the graphics to use Direct3D or another graphics
// layer, but this simplistic sample uses dialog boxes. Feel
// free to use this class as a starting point for adding extra
// functionality.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#ifndef STRICT
#define STRICT
#endif // !STRICT
#include <windows.h>
#include <basetsd.h>
#include <stdio.h>
#include <mmsystem.h>
#include <dxerr9.h>
#include <dplay8.h>
#include <dpaddr.h>
#include <dplobby8.h>
#include "NetClient.h"
#include "NetClientRes.h"
#include "DXUtil.h"
#if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
#include <aygshell.h>
#endif // PocketPC
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
CNetClientWizard* g_pNCW = NULL; // Pointer to the net connect wizard
//-----------------------------------------------------------------------------
// Name: CNetClientWizard
// Desc: Init the class
//-----------------------------------------------------------------------------
CNetClientWizard::CNetClientWizard( HINSTANCE hInst, LPCTSTR strAppName,
GUID* pGuidApp )
{
g_pNCW = this;
m_hInst = hInst;
m_guidApp = *pGuidApp;
m_dwPort = 0;
if( NULL == strAppName )
strAppName = TEXT("DirectPlay App");
_tcsncpy( m_strAppName, strAppName, MAX_PATH-1 );
m_strAppName[ MAX_PATH-1 ] = 0;
m_dwEnumHostExpireInterval = 0;
m_hConnectCompleteEvent = NULL;
m_hrConnectComplete = 0;
m_bConnecting = FALSE;
m_bEnumListChanged = FALSE;
m_bSearchingForSessions = FALSE;
m_hEnumAsyncOp = NULL;
m_hConnectAsyncOp = NULL;
m_pDPClient = NULL;
m_pLobbiedApp = NULL;
m_bHaveConnectionSettingsFromLobby = FALSE;
m_hLobbyClient = NULL;
m_hDlg = NULL;
InitializeCriticalSection( &m_csHostEnum );
m_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
m_hLobbyConnectionEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
// Setup the m_DPHostEnumHead circular linked list
ZeroMemory( &m_DPHostEnumHead, sizeof( DPHostEnumInfo ) );
m_DPHostEnumHead.pNext = &m_DPHostEnumHead;
}
//-----------------------------------------------------------------------------
// Name: ~CNetClientWizard
// Desc: Cleanup the class
//-----------------------------------------------------------------------------
CNetClientWizard::~CNetClientWizard()
{
DeleteCriticalSection( &m_csHostEnum );
CloseHandle( m_hConnectCompleteEvent );
CloseHandle( m_hLobbyConnectionEvent );
}
//-----------------------------------------------------------------------------
// Name: Init
// Desc: Initialize member variables
//-----------------------------------------------------------------------------
HRESULT CNetClientWizard::Init( IDirectPlay8Client* pDPClient,
IDirectPlay8LobbiedApplication* pLobbiedApp )
{
if( NULL == pDPClient || NULL == pLobbiedApp )
return E_INVALIDARG;
m_pDPClient = pDPClient;
m_pLobbiedApp = pLobbiedApp;
m_bHaveConnectionSettingsFromLobby = FALSE;
m_hLobbyClient = NULL;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DoConnectWizard
// Desc: Show the connection wizard UI
//-----------------------------------------------------------------------------
HRESULT CNetClientWizard::DoConnectWizard()
{
m_hrDialog = S_OK;
// Display the multiplayer games dialog box.
DialogBox( m_hInst, MAKEINTRESOURCE(IDD_CLIENT_CONNECT), NULL,
(DLGPROC) StaticSessionsDlgProc );
return m_hrDialog;
}
//-----------------------------------------------------------------------------
// Name: StaticSessionsDlgProc()
// Desc: Static msg handler which passes messages
//-----------------------------------------------------------------------------
INT_PTR CALLBACK CNetClientWizard::StaticSessionsDlgProc( HWND hDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
if( g_pNCW )
return g_pNCW->SessionsDlgProc( hDlg, uMsg, wParam, lParam );
return FALSE; // Message not handled
}
//-----------------------------------------------------------------------------
// Name: SessionsDlgProc()
// Desc: Handles messages for the multiplayer games dialog
//-----------------------------------------------------------------------------
INT_PTR CALLBACK CNetClientWizard::SessionsDlgProc( HWND hDlg, UINT msg,
WPARAM wParam, LPARAM lParam )
{
HRESULT hr;
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
// Load and set the icon
HICON hIcon = LoadIcon( m_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
SendMessage( hDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon ); // Set big icon
SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon ); // Set small icon
SetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, m_strLocalPlayerName );
// Limit the player name size
SendDlgItemMessage( hDlg, IDC_PLAYER_NAME_EDIT, EM_LIMITTEXT, MAX_PLAYER_NAME-1, 0 );
// Set the window title
TCHAR strWindowTitle[256];
_sntprintf( strWindowTitle, 255, TEXT("%s - Multiplayer Games"), m_strAppName );
strWindowTitle[255] = 0;
SetWindowText( hDlg, strWindowTitle );
// Set the default port
if( m_dwPort != 0 )
{
TCHAR strPort[40];
_itot( m_dwPort, strPort, 10 );
SetDlgItemText( hDlg, IDC_REMOTE_PORT, strPort );
}
// Init the search portion of the dialog
m_bSearchingForSessions = FALSE;
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start Search") );
SessionsDlgInitListbox( hDlg );
}
break;
case WM_TIMER:
// Upon this timer message, then refresh the list of hosts
// by expiring old hosts, and displaying the list in the
// dialog box
if( wParam == TIMERID_DISPLAY_HOSTS )
{
// Don't refresh if we are not enumerating hosts
if( !m_bSearchingForSessions )
break;
// Expire all of the hosts that haven't
// refreshed in a certain period of time
SessionsDlgExpireOldHostEnums();
// Display the list of hosts in the dialog
if( FAILED( hr = SessionsDlgDisplayEnumList( hDlg ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgEnumHosts"), hr );
MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
m_strAppName, MB_OK | MB_ICONERROR );
m_bSearchingForSessions = FALSE;
KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
CheckDlgButton( hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start Search") );
SessionsDlgInitListbox( hDlg );
}
}
else if( wParam == TIMERID_CONNECT_COMPLETE )
{
// Check to see if the MessageHandler has set an event to tell us the
// DPN_MSGID_CONNECT_COMPLETE has been processed. Now m_hrConnectComplete
// is valid.
if( WAIT_OBJECT_0 == WaitForSingleObject( m_hConnectCompleteEvent, 0 ) )
{
m_bConnecting = FALSE;
if( FAILED( m_hrConnectComplete ) )
{
DXTRACE_ERR_MSGBOX( TEXT("DPN_MSGID_CONNECT_COMPLETE"), m_hrConnectComplete );
MessageBox( hDlg, TEXT("Unable to join game."),
m_strAppName, MB_OK | MB_ICONERROR );
}
else
{
// DirectPlay connect successful, so end dialog
m_hrDialog = NCW_S_FORWARD;
EndDialog( hDlg, 0 );
}
}
}
break;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDC_SEARCH_CHECK:
m_bSearchingForSessions = !m_bSearchingForSessions;
if( m_bSearchingForSessions )
{
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Searching...") );
// Start the timer to display the host list every so often
SetTimer( hDlg, TIMERID_DISPLAY_HOSTS, DISPLAY_REFRESH_RATE, NULL );
// Start the async enumeration
if( FAILED( hr = SessionsDlgEnumHosts( hDlg ) ) )
{
if( hr == DPNERR_ADDRESSING )
{
// This will be returned if the ip address is invalid
// for example something like "asdf"
MessageBox( hDlg, TEXT("IP address not valid. Stopping search"),
m_strAppName, MB_OK );
}
else
{
DXTRACE_ERR_MSGBOX( TEXT("SessionsDlgEnumHosts"), hr );
MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
m_strAppName, MB_OK | MB_ICONERROR );
}
m_bSearchingForSessions = FALSE;
KillTimer( hDlg, TIMERID_DISPLAY_HOSTS );
CheckDlgButton( hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start Search") );
SessionsDlgInitListbox( hDlg );
}
}
else
{
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, TEXT("Start Search") );
// 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
if( m_hEnumAsyncOp )
m_pDPClient->CancelAsyncOperation( m_hEnumAsyncOp, 0 );
// Reset the search portion of the dialog
SessionsDlgInitListbox( hDlg );
}
break;
case IDC_GAMES_LIST:
if( HIWORD(wParam) != LBN_DBLCLK )
break;
// Fall through
case IDC_JOIN:
if( FAILED( hr = SessionsDlgJoinGame( hDlg ) ) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -