Files
Client/Library/dxx8/samples/Multimedia/Demos/DuelVoice/dpconnect.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

1283 lines
44 KiB
C++

//-----------------------------------------------------------------------------
// File: DPConnect.cpp
//
// Desc: Support file to prompt the user for the DirectPlay connection
// and the DirectPlay session they want to join or create.
//
// Call DPConnect_StartDirectPlayConnect() to start the series of
// dialogs boxes. At the end the player will be connected to an active
// DirectPlay session that the user either created or joined. Or the
// function may also return an EXITCODE as defined below in the event
// of error or user cancel.
//
// Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
//-----------------------------------------------------------------------------
#define IDIRECTPLAY2_OR_GREATER
#include <windows.h>
#include <basetsd.h>
#include <dplobby.h>
#include <dplay.h>
#include <stdio.h>
#include "resource.h"
//-----------------------------------------------------------------------------
// Defines, and constants
//-----------------------------------------------------------------------------
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#define MAX_PLAYER_NAME 14
#define MAX_SESSION_NAME 256
struct DPSessionInfo
{
GUID guidSession;
TCHAR szSession[MAX_SESSION_NAME];
DPSessionInfo* pDPSINext;
};
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
#define EXITCODE_FORWARD 1 // Dialog success, so go forward
#define EXITCODE_BACKUP 2 // Dialog canceled, show previous dialog
#define EXITCODE_QUIT 3 // Dialog quit, close app
#define EXITCODE_ERROR 4 // Dialog error, terminate app
#define EXITCODE_LOBBYCONNECT 5 // Dialog connected from lobby, connect success
extern LPDIRECTPLAY4A g_pDP;
extern LPDPLCONNECTION g_pDPLConnection;
extern LPDIRECTPLAYLOBBY3 g_pDPLobby;
extern GUID g_AppGUID;
extern HANDLE g_hDPMessageEvent;
extern TCHAR g_strPreferredProvider[MAX_SESSION_NAME];
extern TCHAR g_strSessionName[MAX_SESSION_NAME];
extern TCHAR g_strLocalPlayerName[MAX_PLAYER_NAME];
extern DPID g_LocalPlayerDPID;
extern BOOL g_bHostPlayer;
extern TCHAR g_strAppName[256];
extern BOOL g_bUseProtocol;
extern BOOL g_bAsyncSupported; // Asynchronous sends supported
DPSessionInfo g_DPSIHead;
BOOL g_bSearchingForSessions;
BOOL g_bWaitForConnectionSettings;
//-----------------------------------------------------------------------------
// Function-prototypes
//-----------------------------------------------------------------------------
int DPConnect_StartDirectPlayConnect( HINSTANCE hInst, BOOL bBackTrack );
INT_PTR CALLBACK DPConnect_ConnectionsDlgProc( HWND, UINT, WPARAM, LPARAM );
BOOL FAR PASCAL DPConnect_EnumConnectionsCallback( LPCGUID, VOID*, DWORD, LPCDPNAME, DWORD, VOID* );
HRESULT DPConnect_ConnectionsDlgFillListBox( HWND hDlg );
HRESULT DPConnect_ConnectionsDlgOnOK( HWND hDlg );
VOID DPConnect_ConnectionsDlgCleanup( HWND hDlg );
INT_PTR CALLBACK DPConnect_SessionsDlgProc( HWND, UINT, WPARAM, LPARAM );
INT_PTR CALLBACK DPConnect_CreateSessionDlgProc( HWND, UINT, WPARAM, LPARAM );
BOOL FAR PASCAL DPConnect_EnumSessionsCallback( LPCDPSESSIONDESC2, DWORD*, DWORD, VOID* );
VOID DPConnect_SessionsDlgInitListbox( HWND hDlg );
HRESULT DPConnect_SessionsDlgShowGames( HWND hDlg );
HRESULT DPConnect_SessionsDlgJoinGame( HWND hDlg );
HRESULT DPConnect_SessionsDlgCreateGame( HWND hDlg );
VOID DPConnect_SessionsDlgCleanup();
INT_PTR CALLBACK DPConnect_LobbyWaitDlgProc( HWND, UINT, WPARAM, LPARAM );
HRESULT DPConnect_CheckForLobbyLaunch( BOOL* pbLaunchedByLobby );
HRESULT DPConnect_DoLobbyLaunch();
HRESULT DPConnect_WaitForLobbyLaunch( HWND hParentDlg );
HRESULT DPConnect_GetLobbyConnectionSettingsMessage();
//-----------------------------------------------------------------------------
// Name: DPConnect_StartDirectPlayConnect()
// Desc: Prompts the user for the DirectPlay connection and the DirectPlay
// session they want to join or create. This function returns one
// of the EXITCODEs as #defined above
//-----------------------------------------------------------------------------
int DPConnect_StartDirectPlayConnect( HINSTANCE hInst, BOOL bBackTrack = FALSE )
{
int nExitCode;
int nStep;
// Setup the g_DPSIHead circular linked list
ZeroMemory( &g_DPSIHead, sizeof( DPSessionInfo ) );
g_DPSIHead.pDPSINext = &g_DPSIHead;
// If the back track flag is true, then the user has already been through
// the connect process once, and has back tracked out of the main 'game'
// so we need start at the last dialog box
if( bBackTrack )
nStep = 1;
else
nStep = 0;
// Show the dialog boxes to connect
while( TRUE )
{
switch( nStep )
{
case 0:
// Display the multiplayer connect dialog box.
nExitCode = (int)DialogBox( hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_CONNECT),
NULL, (DLGPROC)DPConnect_ConnectionsDlgProc );
break;
case 1:
// Display the multiplayer games dialog box.
nExitCode = (int)DialogBox( hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_GAMES),
NULL, (DLGPROC)DPConnect_SessionsDlgProc );
break;
}
if( nExitCode == EXITCODE_ERROR ||
nExitCode == EXITCODE_QUIT )
return nExitCode;
if( nExitCode == EXITCODE_BACKUP )
nStep--;
else
nStep++;
if( nExitCode == EXITCODE_LOBBYCONNECT )
return EXITCODE_LOBBYCONNECT;
if( nStep == 2 )
break;
}
return EXITCODE_FORWARD;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_ConnectionsDlgProc()
// Desc: Handles messages for the multiplayer connect dialog
//-----------------------------------------------------------------------------
INT_PTR CALLBACK DPConnect_ConnectionsDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
HRESULT hr;
switch( msg )
{
case WM_INITDIALOG:
{
SetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, g_strLocalPlayerName );
// Load and set the icon
#ifdef _WIN64
HINSTANCE hInst = (HINSTANCE) GetWindowLongPtr( hDlg, GWLP_HINSTANCE );
#else
HINSTANCE hInst = (HINSTANCE) GetWindowLong( hDlg, GWL_HINSTANCE );
#endif
HICON hIcon = LoadIcon( 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
// Set the window title
TCHAR strWindowTitle[256];
sprintf( strWindowTitle, "%s - Multiplayer Connect", g_strAppName );
SetWindowText( hDlg, strWindowTitle );
if( FAILED( hr = DPConnect_ConnectionsDlgFillListBox( hDlg ) ) )
EndDialog( hDlg, EXITCODE_ERROR );
}
break;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDC_CONNECTION_LIST:
if( HIWORD(wParam) != LBN_DBLCLK )
break;
// Fall through
case IDOK:
if( FAILED( hr = DPConnect_ConnectionsDlgOnOK( hDlg ) ) )
EndDialog( hDlg, EXITCODE_ERROR );
break;
case IDCANCEL:
EndDialog( hDlg, EXITCODE_QUIT );
break;
default:
return FALSE; // Message not handled
}
break;
case WM_DESTROY:
DPConnect_ConnectionsDlgCleanup( hDlg );
break;
default:
return FALSE; // Message not handled
}
// Message was handled
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_ConnectionsDlgFillListBox()
// Desc: Fills the DirectPlay connection listbox, and also adds
// a "Wait for Lobby" connection option.
//-----------------------------------------------------------------------------
HRESULT DPConnect_ConnectionsDlgFillListBox( HWND hDlg )
{
HRESULT hr;
HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
LPDIRECTPLAY4 pDP = NULL;
int nIndex;
// Create a IDirectPlay object
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay, NULL, CLSCTX_ALL,
IID_IDirectPlay4A, (VOID**)&pDP ) ) )
{
if( hr == E_NOINTERFACE )
{
MessageBox( NULL, TEXT("This application requires DirectPlay 6 or later. "
"The sample will now quit."),
TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
}
return hr;
}
// Enumerate all DirectPlay connections, and store them in the listbox
if( FAILED( hr = pDP->EnumConnections( &g_AppGUID, DPConnect_EnumConnectionsCallback,
hWndListBox, 0 ) ) )
{
SAFE_RELEASE( pDP );
return hr;
}
SAFE_RELEASE( pDP );
// Add "Wait for Lobby Connection" selection in list box
SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM)"Wait for Lobby Connection" );
SetFocus( hWndListBox );
nIndex = (int)SendMessage( hWndListBox, LB_FINDSTRINGEXACT, -1,
(LPARAM)g_strPreferredProvider );
if( nIndex != LB_ERR )
SendMessage( hWndListBox, LB_SETCURSEL, nIndex, 0 );
else
SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_EnumConnectionsCallback()
// Desc: Enumerates through all DirectPlay connections types,
// and stores them in the listbox
//-----------------------------------------------------------------------------
BOOL FAR PASCAL DPConnect_EnumConnectionsCallback( LPCGUID pguidSP,
VOID* pConnection,
DWORD dwConnectionSize,
LPCDPNAME pName,
DWORD dwFlags,
VOID* pvContext )
{
HRESULT hr;
LPDIRECTPLAY4 pDP = NULL;
VOID* pConnectionBuffer = NULL;
HWND hWndListBox = (HWND)pvContext;
LRESULT iIndex;
// Create a IDirectPlay object
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay, NULL, CLSCTX_ALL,
IID_IDirectPlay4A, (VOID**)&pDP ) ) )
return FALSE; // Error, stop enumerating
// Test the if the connection is available by attempting to initialize
// the connection
if( FAILED( hr = pDP->InitializeConnection( pConnection, 0 ) ) )
{
SAFE_RELEASE( pDP );
return TRUE; // Unavailable connection, keep enumerating
}
// Don't need the IDirectPlay interface anymore, so release it
SAFE_RELEASE( pDP );
// Found a good connection, so put it in the listbox
iIndex = SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM)pName->lpszShortNameA );
if( iIndex == CB_ERR )
return FALSE; // Error, stop enumerating
pConnectionBuffer = new BYTE[ dwConnectionSize ];
if( pConnectionBuffer == NULL )
return FALSE; // Error, stop enumerating
// Store pointer to GUID in listbox
memcpy( pConnectionBuffer, pConnection, dwConnectionSize );
SendMessage( hWndListBox, LB_SETITEMDATA, iIndex,
(LPARAM)pConnectionBuffer );
return TRUE; // Keep enumerating
}
//-----------------------------------------------------------------------------
// Name: DPConnect_ConnectionsDlgOnOK()
// Desc: Stores the player name g_strPlayerName, and in creates a IDirectPlay
// object based on the connection type the user selected.
//-----------------------------------------------------------------------------
HRESULT DPConnect_ConnectionsDlgOnOK( HWND hDlg )
{
VOID* pConnection = NULL;
LRESULT iIndex;
HRESULT hr;
GetDlgItemText( hDlg, IDC_PLAYER_NAME_EDIT, g_strLocalPlayerName,
MAX_PLAYER_NAME );
if( strlen( g_strLocalPlayerName ) == 0 )
{
MessageBox( hDlg, TEXT("You must enter a valid player name."),
TEXT("DirectPlay Sample"), MB_OK );
return S_OK;
}
HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
iIndex = SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
SendMessage( hWndListBox, LB_GETTEXT, iIndex, (LPARAM)g_strPreferredProvider );
pConnection = (VOID*) SendMessage( hWndListBox, LB_GETITEMDATA, iIndex, 0 );
if( NULL == pConnection )
{
if( FAILED( hr = DPConnect_WaitForLobbyLaunch( hDlg ) ) )
{
if( hr == DPERR_USERCANCEL )
return S_OK;
return hr;
}
EndDialog( hDlg, EXITCODE_LOBBYCONNECT );
return S_OK;
}
// Release previously selected DirectPlay object, if any.
SAFE_RELEASE( g_pDP );
// Create the DirectPlay object
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay, NULL, CLSCTX_ALL,
IID_IDirectPlay4A, (VOID**)&g_pDP ) ) )
return hr;
// Initialize the connection based on the selected connection type
if( FAILED( hr = g_pDP->InitializeConnection( pConnection, 0 ) ) )
return hr;
EndDialog( hDlg, EXITCODE_FORWARD );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_ConnectionsDlgCleanup()
// Desc: Deletes the connection buffers from the listbox
//-----------------------------------------------------------------------------
VOID DPConnect_ConnectionsDlgCleanup( HWND hDlg )
{
VOID* pConnectionBuffer = NULL;
DWORD iIndex;
DWORD dwCount;
HWND hWndListBox = GetDlgItem( hDlg, IDC_CONNECTION_LIST );
dwCount = (DWORD)SendMessage( hWndListBox, LB_GETCOUNT, 0, 0 );
for( iIndex = 0; iIndex < dwCount; iIndex++ )
{
pConnectionBuffer = (VOID*) SendMessage( hWndListBox, LB_GETITEMDATA,
iIndex, 0 );
SAFE_DELETE_ARRAY( pConnectionBuffer );
}
}
//-----------------------------------------------------------------------------
// Name: DPConnect_SessionsDlgProc()
// Desc: Handles messages fro the multiplayer games dialog
//-----------------------------------------------------------------------------
INT_PTR CALLBACK DPConnect_SessionsDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
HRESULT hr;
switch( msg )
{
case WM_INITDIALOG:
{
// Load and set the icon
#ifdef _WIN64
HINSTANCE hInst = (HINSTANCE) GetWindowLongPtr( hDlg, GWLP_HINSTANCE );
#else
HINSTANCE hInst = (HINSTANCE) GetWindowLong( hDlg, GWL_HINSTANCE );
#endif
HICON hIcon = LoadIcon( 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
// Set the window title
TCHAR strWindowTitle[256];
sprintf( strWindowTitle, "%s - Multiplayer Games", g_strAppName );
SetWindowText( hDlg, strWindowTitle );
g_bSearchingForSessions = FALSE;
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, "Start Search" );
DPConnect_SessionsDlgInitListbox( hDlg );
}
break;
case WM_TIMER:
if( FAILED( hr = DPConnect_SessionsDlgShowGames( hDlg ) ) )
{
KillTimer( hDlg, 1 );
MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
TEXT("DirectPlay Sample"),
MB_OK | MB_ICONERROR );
}
break;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDC_SEARCH_CHECK:
g_bSearchingForSessions = !g_bSearchingForSessions;
if( g_bSearchingForSessions )
{
// Start the timer, and start the async enumeratation
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, "Searching..." );
SetTimer( hDlg, 1, 250, NULL );
if( FAILED( hr = DPConnect_SessionsDlgShowGames( hDlg ) ) )
{
KillTimer( hDlg, 1 );
MessageBox( hDlg, TEXT("Error enumerating DirectPlay games."),
TEXT("DirectPlay Sample"),
MB_OK | MB_ICONERROR );
}
}
else
{
// Stop the timer, and stop the async enumeration
KillTimer( hDlg, 1 );
DPSESSIONDESC2 dpsd;
ZeroMemory( &dpsd, sizeof(dpsd) );
dpsd.dwSize = sizeof(dpsd);
dpsd.guidApplication = g_AppGUID;
hr = g_pDP->EnumSessions( &dpsd, 0, DPConnect_EnumSessionsCallback,
NULL, DPENUMSESSIONS_STOPASYNC );
if( hr != DPERR_GENERIC && FAILED(hr) )
EndDialog( hDlg, EXITCODE_ERROR );
SetDlgItemText( hDlg, IDC_SEARCH_CHECK, "Start Search" );
DPConnect_SessionsDlgInitListbox( hDlg );
}
break;
case IDC_GAMES_LIST:
if( HIWORD(wParam) != LBN_DBLCLK )
break;
// Fall through
case IDC_JOIN:
if( FAILED( hr = DPConnect_SessionsDlgJoinGame( hDlg ) ) )
{
MessageBox( hDlg, TEXT("Unable to join game."),
TEXT("DirectPlay Sample"),
MB_OK | MB_ICONERROR );
}
break;
case IDC_CREATE:
if( FAILED( hr = DPConnect_SessionsDlgCreateGame( hDlg ) ) )
{
MessageBox( hDlg, TEXT("Unable to create game."),
TEXT("DirectPlay Sample"),
MB_OK | MB_ICONERROR );
}
break;
case IDCANCEL: // The close button was press
EndDialog( hDlg, EXITCODE_QUIT );
break;
case IDC_BACK: // "Cancel" button was pressed
EndDialog( hDlg, EXITCODE_BACKUP );
break;
default:
return FALSE; // Message not handled
}
break;
case WM_DESTROY:
KillTimer( hDlg, 1 );
DPConnect_SessionsDlgCleanup();
break;
default:
return FALSE; // Message not handled
}
// Message was handled
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_SessionsDlgInitListbox()
// Desc: Initializes the listbox
//-----------------------------------------------------------------------------
VOID DPConnect_SessionsDlgInitListbox( HWND hDlg )
{
HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
LPDIRECTPLAY4 pDP = NULL;
// Clear the contents from the list box, and
// display "Looking for games" text in listbox
SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
if( g_bSearchingForSessions )
{
SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM)"Looking for games..." );
}
else
{
SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM)"Click Start Search to see a list of games. "
"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: DPConnect_SessionsDlgShowGames()
// Desc: Enumerates the DirectPlay sessions, and displays them in the listbox
//-----------------------------------------------------------------------------
HRESULT DPConnect_SessionsDlgShowGames( HWND hDlg )
{
HRESULT hr;
HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
DPSESSIONDESC2 dpsd;
DPSessionInfo* pDPSISelected = NULL;
int nItemSelected;
GUID guidSelectedSession;
BOOL bFindSelectedGUID;
BOOL bFoundSelectedGUID;
// Try to keep the same session selected unless it goes away or
// there is no real session currently selected
bFindSelectedGUID = FALSE;
bFoundSelectedGUID = TRUE;
nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
if( nItemSelected != LB_ERR )
{
pDPSISelected = (DPSessionInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
nItemSelected, 0 );
if( pDPSISelected != NULL )
{
guidSelectedSession = pDPSISelected->guidSession;
bFindSelectedGUID = TRUE;
}
}
// Remove the previous games from the linked list
DPConnect_SessionsDlgCleanup();
// Enum sessions and let DirectPlay decide the timeout
ZeroMemory( &dpsd, sizeof(dpsd) );
dpsd.dwSize = sizeof(dpsd);
dpsd.guidApplication = g_AppGUID;
// Enumerate all the active DirectPlay games on the selected connection
hr = g_pDP->EnumSessions( &dpsd, 0, DPConnect_EnumSessionsCallback, NULL,
DPENUMSESSIONS_ALL | DPENUMSESSIONS_ASYNC );
if( FAILED(hr) )
{
if( hr == DPERR_USERCANCEL )
{
// The user canceled the DirectPlay connection dialog,
// so stop the search
if( g_bSearchingForSessions )
{
CheckDlgButton( hDlg, IDC_SEARCH_CHECK, BST_UNCHECKED );
SendMessage( hDlg, WM_COMMAND, IDC_SEARCH_CHECK, 0 );
}
return S_OK;
}
else
{
DPConnect_SessionsDlgInitListbox( hDlg );
if ( hr == DPERR_CONNECTING )
return S_OK;
return hr;
}
}
// Tell listbox not to redraw itself since the contents are going to change
SendMessage( hWndListBox, WM_SETREDRAW, FALSE, 0 );
// Add the enumerated sessions to the listbox
if( g_DPSIHead.pDPSINext != &g_DPSIHead )
{
// Clear the contents from the list box and enable the join button
SendMessage( hWndListBox, LB_RESETCONTENT, 0, 0 );
EnableWindow( GetDlgItem( hDlg, IDC_JOIN ), TRUE );
DPSessionInfo* pDPSI = g_DPSIHead.pDPSINext;
while ( pDPSI != &g_DPSIHead )
{
// Add session to the list box
int nIndex = (int)SendMessage( hWndListBox, LB_ADDSTRING, 0,
(LPARAM)pDPSI->szSession );
SendMessage( hWndListBox, LB_SETITEMDATA, nIndex, (LPARAM)pDPSI );
if( bFindSelectedGUID )
{
// Look for the session the was selected before
if( pDPSI->guidSession == guidSelectedSession )
{
SendMessage( hWndListBox, LB_SETCURSEL, nIndex, 0 );
bFoundSelectedGUID = TRUE;
}
}
pDPSI = pDPSI->pDPSINext;
}
if( !bFindSelectedGUID || !bFoundSelectedGUID )
SendMessage( hWndListBox, LB_SETCURSEL, 0, 0 );
}
else
{
// There are no active session, so just reset the listbox
DPConnect_SessionsDlgInitListbox( hDlg );
}
// Tell listbox to redraw itself now since the contents have changed
SendMessage( hWndListBox, WM_SETREDRAW, TRUE, 0 );
InvalidateRect( hWndListBox, NULL, FALSE );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_EnumSessionsCallback()
// Desc: Enumerates the sessions, and stores them in the linked list, g_DPSIHead
//-----------------------------------------------------------------------------
BOOL FAR PASCAL DPConnect_EnumSessionsCallback( LPCDPSESSIONDESC2 pdpsd,
DWORD* pdwTimeout,
DWORD dwFlags,
VOID* pvContext )
{
DPSessionInfo* pDPSINew = NULL;
if( dwFlags & DPESC_TIMEDOUT )
return FALSE; // The enumeration has timed out, so stop the enumeration.
// Found a good session, save it
pDPSINew = new DPSessionInfo;
if( NULL == pDPSINew )
return FALSE;
ZeroMemory( pDPSINew, sizeof(DPSessionInfo) );
// Copy the information into pDPSINew
pDPSINew->guidSession = pdpsd->guidInstance;
sprintf( pDPSINew->szSession, "%s (%d/%d)", pdpsd->lpszSessionNameA,
pdpsd->dwCurrentPlayers, pdpsd->dwMaxPlayers );
// Add pDPSINew to the circular linked list, g_pDPSIFirst
pDPSINew->pDPSINext = g_DPSIHead.pDPSINext;
g_DPSIHead.pDPSINext = pDPSINew;
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_SessionsDlgJoinGame()
// Desc: Joins the selected DirectPlay session
//-----------------------------------------------------------------------------
HRESULT DPConnect_SessionsDlgJoinGame( HWND hDlg )
{
DPSESSIONDESC2 dpsd;
DPNAME dpname;
HRESULT hr;
HWND hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );
DPSessionInfo* pDPSISelected = NULL;
int nItemSelected;
nItemSelected = (int)SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );
// Add status text in list box
pDPSISelected = (DPSessionInfo*) SendMessage( hWndListBox, LB_GETITEMDATA,
nItemSelected, 0 );
if( NULL == pDPSISelected )
{
MessageBox( hDlg, TEXT("There are no games to join."),
TEXT("DirectPlay Sample"), MB_OK );
return S_OK;
}
// Setup the DPSESSIONDESC2, and get the session guid from
// the selected listbox item
ZeroMemory( &dpsd, sizeof(dpsd) );
dpsd.dwSize = sizeof(dpsd);
dpsd.guidInstance = pDPSISelected->guidSession;
dpsd.guidApplication = g_AppGUID;
// Join the session
g_bHostPlayer = FALSE;
if( FAILED( hr = g_pDP->Open( &dpsd, DPOPEN_JOIN ) ) )
return hr;
// Check for Async message support
// The caps we are checking do not differ for guaranteed msg
DPCAPS dpcaps;
ZeroMemory( &dpcaps, sizeof(DPCAPS) );
dpcaps.dwSize = sizeof(DPCAPS);
g_pDP->GetCaps( &dpcaps, 0 );
// Determine if Aync messages are supported.
g_bAsyncSupported = (dpcaps.dwFlags & DPCAPS_ASYNCSUPPORTED) != 0;
// Create player based on g_strLocalPlayerName.
// Store the player's DPID in g_LocalPlayerDPID.
// Also all DirectPlay messages for this player will signal g_hDPMessageEvent
ZeroMemory( &dpname, sizeof(DPNAME) );
dpname.dwSize = sizeof(DPNAME);
dpname.lpszShortNameA = g_strLocalPlayerName;
if( FAILED( hr = g_pDP->CreatePlayer( &g_LocalPlayerDPID, &dpname,
g_hDPMessageEvent, NULL, 0, 0 ) ) )
return hr;
// DirectPlay connect successful, so end dialog
EndDialog( hDlg, EXITCODE_FORWARD );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_SessionsDlgCreateGame()
// Desc: Asks the user the session name, and creates a new DirectPlay session
//-----------------------------------------------------------------------------
HRESULT DPConnect_SessionsDlgCreateGame( HWND hDlg )
{
DPSESSIONDESC2 dpsd;
DPNAME dpname;
HRESULT hr;
int nResult;
HINSTANCE hInst;
#ifdef _WIN64
hInst = (HINSTANCE) GetWindowLongPtr( hDlg, GWLP_HINSTANCE );
#else
hInst = (HINSTANCE) GetWindowLong( hDlg, GWL_HINSTANCE );
#endif
// Display a modal multiplayer connect dialog box.
EnableWindow( hDlg, FALSE );
nResult = (int)DialogBox( hInst, MAKEINTRESOURCE(IDD_MULTIPLAYER_CREATE),
hDlg, (DLGPROC)DPConnect_CreateSessionDlgProc );
EnableWindow( hDlg, TRUE );
if( nResult == IDCANCEL )
return S_OK;
// Setup the DPSESSIONDESC2 based on g_AppGUID, and g_strSessionName.
// The DPSESSION_KEEPALIVE flag keeps the session alive if players abnormally exit
ZeroMemory( &dpsd, sizeof(dpsd) );
dpsd.dwSize = sizeof(dpsd);
dpsd.guidApplication = g_AppGUID;
dpsd.lpszSessionNameA = g_strSessionName;
dpsd.dwMaxPlayers = 10;
dpsd.dwFlags = DPSESSION_KEEPALIVE | DPSESSION_MIGRATEHOST;
if( g_bUseProtocol )
dpsd.dwFlags |= DPSESSION_DIRECTPLAYPROTOCOL;
// Create a new session
g_bHostPlayer = TRUE;
if( FAILED( hr = g_pDP->Open( &dpsd, DPOPEN_CREATE ) ) )
return hr;
// Check for Async message support
// The caps we are checking do not differ for guaranteed msg
DPCAPS dpcaps;
ZeroMemory( &dpcaps, sizeof(DPCAPS) );
dpcaps.dwSize = sizeof(DPCAPS);
g_pDP->GetCaps( &dpcaps, 0 );
// Determine if Aync messages are supported.
g_bAsyncSupported = (dpcaps.dwFlags & DPCAPS_ASYNCSUPPORTED) != 0;
// Create player based on g_strLocalPlayerName.
// Store the player's DPID in g_LocalPlayerDPID.
// Also all DirectPlay messages for this player will signal g_hDPMessageEvent
ZeroMemory( &dpname, sizeof(DPNAME) );
dpname.dwSize = sizeof(DPNAME);
dpname.lpszShortNameA = g_strLocalPlayerName;
if( FAILED( hr = g_pDP->CreatePlayer( &g_LocalPlayerDPID, &dpname,
g_hDPMessageEvent, NULL, 0,
DPPLAYER_SERVERPLAYER ) ) )
return hr;
// DirectPlay connect successful, so end dialog
EndDialog( hDlg, EXITCODE_FORWARD );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_CreateSessionDlgProc()
// Desc: Handles messages fro the multiplayer create game dialog
//-----------------------------------------------------------------------------
INT_PTR CALLBACK DPConnect_CreateSessionDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
DWORD dwNameLength;
switch( msg )
{
case WM_INITDIALOG:
SetDlgItemText( hDlg, IDC_EDIT_SESSION_NAME, g_strSessionName );
return TRUE;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDOK:
dwNameLength = GetDlgItemText( hDlg, IDC_EDIT_SESSION_NAME,
g_strSessionName,
MAX_SESSION_NAME );
if( dwNameLength == 0 )
return TRUE; // Don't accept blank session names
g_bUseProtocol = TRUE;
EndDialog( hDlg, IDOK );
return TRUE;
case IDCANCEL:
EndDialog( hDlg, IDCANCEL );
return TRUE;
}
break;
}
return FALSE; // Didn't handle message
}
//-----------------------------------------------------------------------------
// Name: DPConnect_SessionsDlgCleanup()
// Desc: Deletes the linked list, g_DPSIHead
//-----------------------------------------------------------------------------
VOID DPConnect_SessionsDlgCleanup()
{
DPSessionInfo* pDPSI = g_DPSIHead.pDPSINext;
DPSessionInfo* pDPSIDelete;
while ( pDPSI != &g_DPSIHead )
{
pDPSIDelete = pDPSI;
pDPSI = pDPSI->pDPSINext;
SAFE_DELETE( pDPSIDelete );
}
// Re-link the g_DPSIHead circular linked list
g_DPSIHead.pDPSINext = &g_DPSIHead;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_WaitForLobbyLaunch()
// Desc: Wait for the a lobby connection and connect when found
//-----------------------------------------------------------------------------
HRESULT DPConnect_WaitForLobbyLaunch( HWND hParentDlg )
{
HRESULT hr;
BOOL bLaunchedByLobby;
// Create a new lobby object
SAFE_RELEASE( g_pDPLobby );
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlayLobby, NULL,
CLSCTX_INPROC_SERVER, IID_IDirectPlayLobby3A,
(VOID**)&g_pDPLobby ) ) )
return hr;
// Put the application into wait mode
if( FAILED( hr = g_pDPLobby->WaitForConnectionSettings( 0 ) ) )
return hr;
// Use the IDD_LOBBY_WAIT_STATUS dialog to check for a connection message
g_bWaitForConnectionSettings = TRUE;
EnableWindow( hParentDlg, FALSE );
// Display a dialog box and wait for the connection settings
DialogBoxParam( NULL, MAKEINTRESOURCE( IDD_LOBBY_WAIT_STATUS ), hParentDlg,
(DLGPROC)DPConnect_LobbyWaitDlgProc, (LPARAM)&hr );
EnableWindow( hParentDlg, TRUE );
if( FAILED(hr) )
{
g_pDPLobby->WaitForConnectionSettings( DPLWAIT_CANCEL );
SAFE_RELEASE( g_pDPLobby );
return hr;
}
// The lobby server has launched the game, so check for a lobby
// launch to continue on to connect to the session and create the player
if( FAILED( hr = DPConnect_CheckForLobbyLaunch( &bLaunchedByLobby ) ) )
return hr; // This may be DPERR_USERCANCEL if the user canceled the dialog
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_CheckForLobbyLaunch()
// Desc: Determines if we were launched by a lobby. If so, gets the connection
// settings and creates our player using the information from the lobby
//-----------------------------------------------------------------------------
HRESULT DPConnect_CheckForLobbyLaunch( BOOL* pbLaunchedByLobby )
{
HRESULT hr;
DWORD dwSize;
if( NULL == pbLaunchedByLobby )
return E_FAIL;
// Create a new lobby object
SAFE_RELEASE( g_pDPLobby );
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlayLobby, NULL,
CLSCTX_INPROC_SERVER, IID_IDirectPlayLobby3A,
(VOID**)&g_pDPLobby ) ) )
{
if( hr == E_NOINTERFACE )
{
MessageBox( NULL, TEXT("This application requires DirectPlay 6 or later. "
"The sample will now quit."),
TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
}
return hr;
}
// Get connection settings from the lobby (into g_pdplConnection)
hr = g_pDPLobby->GetConnectionSettings( 0, NULL, &dwSize );
if( FAILED(hr) && (DPERR_BUFFERTOOSMALL != hr) )
{
if( DPERR_NOTLOBBIED == hr )
{
*pbLaunchedByLobby = FALSE;
// Cleanup since we were not launched from the lobby
SAFE_DELETE_ARRAY( g_pDPLConnection );
SAFE_RELEASE( g_pDPLobby );
return S_OK;
}
return hr;
}
// Allocate memory for the connection
SAFE_DELETE_ARRAY( g_pDPLConnection );
g_pDPLConnection = (DPLCONNECTION*)new BYTE[ dwSize ];
// Get the connection settings
if( FAILED( hr = g_pDPLobby->GetConnectionSettings( 0, g_pDPLConnection,
&dwSize ) ) )
return hr;
*pbLaunchedByLobby = TRUE;
if( FAILED( hr = DPConnect_DoLobbyLaunch() ) )
{
// Cleanup
SAFE_DELETE_ARRAY( g_pDPLConnection );
SAFE_RELEASE( g_pDPLobby );
return hr; // This may be DPERR_USERCANCEL if the user canceled the dialog
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_DoLobbyLaunch()
// Desc: The app was launched by the lobby server, so connect to the session
// and create the player
//-----------------------------------------------------------------------------
HRESULT DPConnect_DoLobbyLaunch()
{
HRESULT hr;
// Detrimine if this is the host player
g_bHostPlayer = ( (g_pDPLConnection->dwFlags & DPLCONNECTION_CREATESESSION) != 0 );
// Set our session flags
g_pDPLConnection->lpSessionDesc->dwFlags = DPSESSION_KEEPALIVE |
DPSESSION_MIGRATEHOST;
// Let lobby know our connection flags
if( FAILED( hr = g_pDPLobby->SetConnectionSettings( 0, 0, g_pDPLConnection ) ) )
return hr;
// If we're hosting, just call ConnectEx syncronously. Otherwise, display
// the connecting dialog and do the connect asynchronously.
if( g_bHostPlayer )
{
// Connect to the lobby syncronously
if( FAILED( hr = g_pDPLobby->ConnectEx( 0, IID_IDirectPlay4A,
(VOID**)&g_pDP, NULL ) ) )
return hr;
}
else
{
// Use the IDD_LOBBY_WAIT_STATUS dialog to attempt to connect to
// the new session
g_bWaitForConnectionSettings = FALSE;
// Connect to the lobby asyncronously
DialogBoxParam( NULL, MAKEINTRESOURCE( IDD_LOBBY_WAIT_STATUS ), NULL,
(DLGPROC)DPConnect_LobbyWaitDlgProc, (LPARAM)&hr );
if( FAILED(hr) )
return hr; // This may be DPERR_USERCANCEL if the user canceled the dialog
}
strcpy( g_strLocalPlayerName, g_pDPLConnection->lpPlayerName->lpszShortNameA );
// Create our player
DPNAME dpname;
ZeroMemory( &dpname, sizeof(DPNAME) );
dpname.dwSize = sizeof(DPNAME);
dpname.lpszShortNameA = g_strLocalPlayerName;
if( FAILED( hr = g_pDP->CreatePlayer( &g_LocalPlayerDPID, &dpname,
NULL, NULL, 0, 0 ) ) )
return hr;
// Successfully lobby launch, note that we don't release the lobby object
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DPConnect_LobbyWaitDlgProc()
// Desc: Handles dialog messages. This dialog starts a timer that attempts to
// either receive a lobby connection settings message or
// connect to new session via the lobby connection depending on the
// g_bWaitForConnectionSettings flag.
//-----------------------------------------------------------------------------
INT_PTR CALLBACK DPConnect_LobbyWaitDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
static HRESULT* phr = NULL;
switch( msg )
{
case WM_INITDIALOG:
// Save the HRESULT pointer
phr = (HRESULT*)lParam;
if( g_bWaitForConnectionSettings )
SetDlgItemText( hDlg, IDC_WAIT_TEXT, TEXT("Waiting for connection...") );
else
SetDlgItemText( hDlg, IDC_WAIT_TEXT, TEXT("Finding Game...") );
// Create a timer. The dialog will attempt to connect at every WM_TIMER
SetTimer( hDlg, 0, 250, NULL );
break;
case WM_DESTROY:
KillTimer( hDlg, 0 );
break;
case WM_TIMER:
// Attempt to connect to the game
if( g_bWaitForConnectionSettings )
{
*phr = DPConnect_GetLobbyConnectionSettingsMessage();
if( *phr == S_OK )
EndDialog( hDlg, 0 );
}
else
{
*phr = g_pDPLobby->ConnectEx( DPCONNECT_RETURNSTATUS, IID_IDirectPlay4A,
(VOID**)&g_pDP, NULL );
if( *phr == DPERR_CONNECTING )
break; // Try again on the next WM_TIMER message
EndDialog( hDlg, 0 );
}
break;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDC_LOBBYCONNECTCANCEL:
case IDCANCEL:
// the async Connect will be stopped when the
// IDirectPlayLobby3 interface is released.
// Set the HRESULT to user cancel and close the dialog
*phr = DPERR_USERCANCEL;
EndDialog( hDlg, 0 );
break;
default:
return FALSE; // Message not handled
}
break;
default:
return FALSE; // Message not handled
}
return TRUE; // Message handled
}
//-----------------------------------------------------------------------------
// Name: DPConnect_GetLobbyConnectionSettingsMessage()
// Desc: Attepts to get a lobby connection settings message. If it does
// it returns S_OK otherwise it returns S_FALSE
//-----------------------------------------------------------------------------
HRESULT DPConnect_GetLobbyConnectionSettingsMessage()
{
HRESULT hr = NOERROR;
LPVOID pvMsgBuffer = NULL;
DWORD dwMsgBufferSize = 0;
DWORD dwMsgFlags;
while( TRUE )
{
hr = g_pDPLobby->ReceiveLobbyMessage( 0, 0, &dwMsgFlags,
pvMsgBuffer, &dwMsgBufferSize );
if( hr == DPERR_BUFFERTOOSMALL )
{
// The current buffer was too small,
// so reallocate it and try again
SAFE_DELETE_ARRAY( pvMsgBuffer );
pvMsgBuffer = new BYTE[ dwMsgBufferSize ];
if( pvMsgBuffer == NULL )
return E_OUTOFMEMORY;
continue; // Now that the buffer is bigger, try again
}
if( DPERR_NOMESSAGES == hr )
break;
if( FAILED(hr) )
break;
// Found a messages, check to see if its a CONNECTIONSETTINGS message
if( dwMsgFlags & DPLMSG_SYSTEM )
{
// If it is found then stop looking for it
if( ( (DPLMSG_GENERIC*)pvMsgBuffer)->dwType == DPLSYS_NEWCONNECTIONSETTINGS )
break;
}
}
// Cleanup buffer
SAFE_DELETE_ARRAY( pvMsgBuffer );
// Return S_FALSE if there we no connection settings messages
if( DPERR_NOMESSAGES == hr )
return S_FALSE;
// If the message was recieved the hr should be S_OK
return hr;
}