📄 dptools.cpp
字号:
/*
Semion S. Bezrukov 5-31-99
e-mail: deltree@rocketmail.com
This file is a compilation of Direct Play routines for the management
and setup of DirectPlay object and player. The majority of this code comes
from 'Inside Direct X' by Bradley Bargen and Peter Donnelly. There, that's
all the legal stuff.
To get this to work with your program, simply include 'dptools.h' in
your main .h file and initialize DirectPlay like so:
InitializeDirectPlay(hinstance);
where hinstance is the instance of your application.
To deinitialize DirectPlay, simply use:
UninitializeDirectPlay();
just before you quit the application. You must have dplay.lib and
dplayx.lib specified in your library compile path or you'll get a ton
of link errors.
To see how to send and receive data simply look to the SendFireMessage()
and EvaluateGameMessage().
SendFireMessage() simply fills the FIREMSG struct and then sends it using
another general function.
EvaluateGameMessage(), casts the received struct to a general struct
to figure out the exact type and then recasts it to the specific struct
so that the data can be extracted.
Good luck,
SIM.
*/
#define WIN32_LEAN_AND_MEAN
#define IDIRECTPLAY2_OR_GREATER
#define INITGUID
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <objbase.h> // GUID functions
#include "dplay.h"
#include "dplobby.h"
#include "dptools.h"
#include "resource.h"
#include "dpex.h"
int receive_count; //a global variable that holds the recieved
//data. When the main program asks for it, a
//function simply returns it. I chose this
//approach for it's ease.
typedef struct
{
GUID guidSP;
LPVOID lpConnection;
DWORD dwConnectionSize;
}CONNECTIONINFO;
typedef CONNECTIONINFO* LPCONNECTIONINFO;
GUID ZCAR_GUID = {
0x949a21e2,
0x6179,
0x11cf,
{0x95, 0x4f, 0x00, 0xaa, 0x00, 0x6c, 0x26, 0x58}
};
#define TIMER_ID 1
#define TIMER_RATE 2000 // milliseconds
LPDIRECTPLAY3 lpDP = NULL;
LPDIRECTPLAYLOBBY2 lpDPLobby2 = NULL;
DPSESSIONDESC2 dpDesc;
LPDPSESSIONDESC2 lpdpDesc = NULL;
DPCAPS dpCaps;
HANDLE hPlayerEvent = NULL;
HANDLE hKillEvent = NULL;
HANDLE hReceiveThread = NULL;
DWORD idReceiveThread = 0;
LPVOID lpReceiveBuffer = NULL;
DWORD dwReceiveBufferSize = 0;
bool bEnumerating = FALSE;
bool bUserCancel = TRUE;
HOSTMSG MsgHost;
SYNCMSG MsgSync;
FIREMSG MsgFire;
CONTROLMSG MsgControl;
BOOL g_bHost = FALSE;
char g_szPlayerName[31]; // our name
DPID g_dpPlayerID; // our id
HANDLE g_hInstance;
HWND g_hwnd;
void InitMessageBuffers( void )
{
MsgHost.byType = MSG_HOST;
MsgSync.byType = MSG_SYNC;
MsgFire.byType = MSG_FIRE;
MsgControl.byType = MSG_CONTROL;
}
BOOL FAR PASCAL EnumPlayer( DPID pidID,
DWORD dwPlayerType, LPCDPNAME lpName,
DWORD dwFlags, LPVOID lpContext)
{
HWND hWnd = ( HWND ) lpContext;
SendMessage( hWnd, LB_ADDSTRING, 0,
( LPARAM ) lpName->lpszShortNameA );
return( TRUE );
}
BOOL WINAPI EnumConnection( LPCGUID lpguidSP,
LPVOID lpConnection, DWORD dwSize,
LPDPNAME lpName, DWORD dwFlags,
LPVOID lpContext )
{
LONG iIndex;
HWND hWnd = ( HWND ) lpContext;
LPVOID lpOurConnection = NULL;
LPCONNECTIONINFO lpConnectionInfo = NULL;
LPDIRECTPLAY3 lpDPTemp;
// Check to see if a connection can be initialized
if FAILED( CoCreateInstance( CLSID_DirectPlay,
NULL, CLSCTX_ALL, IID_IDirectPlay3A,
( LPVOID* ) &lpDPTemp ) )
{
return( FALSE );
}
if FAILED( lpDPTemp->InitializeConnection( lpConnection, 0 ) )
{
lpDPTemp->Release();
return( TRUE );
}
lpDPTemp->Release();
// If it was initialized, add it to the list box
iIndex = SendMessage( hWnd, CB_ADDSTRING, 0,
(LPARAM) lpName->lpszShortNameA );
// If it got added to the list box, create a copy of the connection
// info and store a pointer to it in the list box.
if ( iIndex != LB_ERR )
{
lpConnectionInfo =
(LPCONNECTIONINFO)malloc( sizeof( CONNECTIONINFO ) );
memcpy( &lpConnectionInfo->guidSP, lpguidSP, sizeof( GUID ) );
lpConnectionInfo->lpConnection = malloc( dwSize );
memcpy( lpConnectionInfo->lpConnection, lpConnection, dwSize );
lpConnectionInfo->dwConnectionSize = dwSize;
SendMessage( hWnd, CB_SETITEMDATA, iIndex,
( LPARAM ) lpConnectionInfo );
}
else
{
return FALSE;
}
return( TRUE );
}
BOOL WINAPI EnumSession( LPDPSESSIONDESC2 lpDPGameDesc, LPDWORD lpdwTimeOut,
DWORD dwFlags, LPVOID lpContext )
{
LONG iIndex;
HWND hWnd = ( HWND ) lpContext;
LPGUID lpGuid;
// First check and see if the enumeration timed out. If so, we
// could reset it, but we'll just canel it instead.
if( dwFlags & DPESC_TIMEDOUT )
{
return FALSE;
}
iIndex = SendMessage( hWnd, LB_ADDSTRING, 0,
(LPARAM) lpDPGameDesc->lpszSessionName );
// If it got added to the list box, create a copy of the GUID
// and store a pointer to it in the list box.
if ( iIndex != LB_ERR )
{
lpGuid = ( LPGUID ) malloc( sizeof( GUID ) );
if ( !lpGuid ) return FALSE;
*lpGuid = lpDPGameDesc->guidInstance;
SendMessage( hWnd, LB_SETITEMDATA, iIndex,
( LPARAM ) lpGuid );
}
return(TRUE);
}
LRESULT CALLBACK DlgProcEnumPlayers( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
int iIndex;
LPGUID lpGuid;
switch( message )
{
case WM_INITDIALOG:
iIndex = SendDlgItemMessage( GetParent( hWnd ), IDC_SESSIONS,
LB_GETCURSEL, 0, 0L );
lpGuid = ( LPGUID )SendDlgItemMessage( GetParent( hWnd ),
IDC_SESSIONS, LB_GETITEMDATA, iIndex, 0 );
if FAILED( lpDP->EnumPlayers( lpGuid,
( LPDPENUMPLAYERSCALLBACK2 )EnumPlayer,
( LPVOID )GetDlgItem( hWnd, IDC_PLAYERS ),
DPENUMPLAYERS_SESSION ) )
{
MessageBox( hWnd, "Error enumerating players.",
"Error", MB_OK );
EndDialog( hWnd, FALSE );
}
return TRUE;
case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case IDOK:
case IDCANCEL:
EndDialog( hWnd, FALSE );
return TRUE;
}
}
return FALSE;
}
BOOL CreateGamePlayer( void )
{
DPNAME dpPlayerName;
ZeroMemory( &dpPlayerName,
sizeof( dpPlayerName ) );
dpPlayerName.dwSize = sizeof( DPNAME );
dpPlayerName.lpszShortNameA = g_szPlayerName;
if FAILED( lpDP->CreatePlayer( &g_dpPlayerID, &dpPlayerName,
hPlayerEvent, NULL, 0, 0 ) )
{
OutputDebugString(
"CreateGamePlayer: Player create failed!\n" );
return FALSE;
}
OutputDebugString(
"CreateGamePlayer: Player created.\n" );
return TRUE;
}
BOOL CALLBACK DlgProcDPStart( HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam )
{
long i;
HRESULT hr;
LPDIRECTPLAYLOBBY lpDPLobby = NULL;
LPDIRECTPLAY2 lpDP2 = NULL;
LPVOID lpHeap, lpConnection;
LPDPLCONNECTION lpLConnection;
LPCONNECTIONINFO lpConnectionInfo;
DWORD dwSessions;
LPDELETEITEMSTRUCT lpdis;
char szSessionName[30];
LPGUID lpGuid;
DPCOMPOUNDADDRESSELEMENT addressChunks[2];
DWORD dwChunkCount;
DWORD dwSize = 0;
switch( message )
{
case WM_INITDIALOG:
if FAILED( CoCreateInstance( CLSID_DirectPlay,
NULL, CLSCTX_ALL, IID_IDirectPlay3A,
( LPVOID* ) &lpDP ) )
{
MessageBox( hWnd, "Error creating DirectPlay object.",
"Error", MB_OK );
EndDialog( hWnd, -1 );
}
if FAILED( DirectPlayLobbyCreate( NULL, &lpDPLobby,
NULL, NULL, 0 ) )
{
MessageBox( hWnd, "Error creating DirectPlayLobby object.",
"Error", MB_OK );
EndDialog( hWnd, -1 );
}
// DirectPlayLobbyCreate gives us an IID_IDirectPlayLobby
// interface. Query for the newer *ANSI* interface.
else if FAILED( lpDPLobby->QueryInterface(
IID_IDirectPlayLobby2A, (LPVOID*) &lpDPLobby2 ) )
{
MessageBox( hWnd, "Error getting Lobby interface.",
"Error", MB_OK );
EndDialog( hWnd, -1 );
}
// This version of the interface is no longer needed
lpDPLobby->Release();
// Check for lobby launch
hr = lpDPLobby2->GetConnectionSettings( 0, NULL, &dwSize );
if ( hr != DPERR_NOTLOBBIED )
{
OutputDebugString("Attempting Lobby Launch...\n");
// We were lobbied. Get the connection settings.
lpLConnection = (LPDPLCONNECTION) malloc( dwSize );
lpDPLobby2->GetConnectionSettings( 0,
lpLConnection, &dwSize );
// Set the session up the way we want it.
lpLConnection->lpSessionDesc->dwFlags = DPSESSION_MIGRATEHOST |
DPSESSION_KEEPALIVE;
lpLConnection->lpSessionDesc->dwMaxPlayers = 4;
lpDPLobby2->SetConnectionSettings( 0, 0, lpLConnection );
// Connect to the session.
lpDPLobby2->Connect( 0, &lpDP2, NULL );
lpDP2->QueryInterface( IID_IDirectPlay3A, (LPVOID*)&lpDP );
lpDP2->Release();
EndDialog( hWnd, 0 );
}
// Fill the connections drop down list box
SendDlgItemMessage( hWnd, IDC_CONNECTIONS,
CB_ADDSTRING, 0,
(LPARAM) "<<Select a Connection>>" );
if FAILED( lpDP->EnumConnections( NULL,
( LPDPENUMCONNECTIONSCALLBACK )EnumConnection,
( LPVOID )GetDlgItem( hWnd, IDC_CONNECTIONS ),
0 ) )
{
MessageBox( hWnd, "Couldn't enumerate connections.",
"Error", MB_OK );
EndDialog( hWnd, -1 );
}
else
{
SendDlgItemMessage( hWnd, IDC_CONNECTIONS,
CB_SETCURSEL, 0, 0L );
}
// Start a timer for async session list
SetTimer( hWnd, TIMER_ID, TIMER_RATE, NULL );
return TRUE;
case WM_DELETEITEM:
// Delete the memory allocated when the list and combo
// boxes are filled.
lpdis = ( LPDELETEITEMSTRUCT ) lParam;
if ( wParam == IDC_CONNECTIONS )
{
lpConnectionInfo = ( LPCONNECTIONINFO )lpdis->itemData;
if ( lpConnectionInfo )
{
if ( lpConnectionInfo->lpConnection )
free( lpConnectionInfo->lpConnection );
free( lpConnectionInfo );
}
}
else
{
lpHeap = ( LPVOID )lpdis->itemData;
if ( lpHeap )
free( lpHeap );
}
return TRUE;
case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case IDC_CONNECTIONS:
switch (HIWORD(wParam))
{
case CBN_SELCHANGE:
// Release the existing DP object so we can
// reinitialize it with the selected connection.
if ( lpDP ) lpDP->Release();
if FAILED( CoCreateInstance( CLSID_DirectPlay,
NULL, CLSCTX_ALL, IID_IDirectPlay3A,
( LPVOID* ) &lpDP) )
{
MessageBox( hWnd,
"Error creating DirectPlay object.",
"Error", MB_OK );
return TRUE;
}
// Get the currently selected connection from
// the list box.
i = SendDlgItemMessage( hWnd, IDC_CONNECTIONS,
CB_GETCURSEL,
0, 0L );
lpConnectionInfo = (LPCONNECTIONINFO)
SendDlgItemMessage(
hWnd, IDC_CONNECTIONS,
CB_GETITEMDATA,
i, 0 );
lpConnection = lpConnectionInfo->lpConnection;
// If the connection uses the TCP/IP service
// provider, fill in chunks for the provider
// and TCP/IP address.
if ( IsEqualGUID( lpConnectionInfo->guidSP,
DPSPGUID_TCPIP ) )
{
dwChunkCount = 0;
addressChunks[ dwChunkCount ].guidDataType =
DPAID_ServiceProvider;
addressChunks[ dwChunkCount ].dwDataSize =
sizeof(GUID);
addressChunks[ dwChunkCount ].lpData =
(LPVOID) &DPSPGUID_TCPIP;
dwChunkCount++;
// An empty address will trigger a
// local enumeration.
addressChunks[dwChunkCount].guidDataType =
DPAID_INet;
addressChunks[dwChunkCount].dwDataSize = 1;
addressChunks[dwChunkCount].lpData = "";
dwChunkCount++;
// Find out how much space we'll need for
// the connection data and allocate.
lpDPLobby2->CreateCompoundAddress(
addressChunks,
dwChunkCount,
NULL, &dwSize );
lpConnection = malloc( dwSize );
// Create the connection buffer.
if FAILED( lpDPLobby2->CreateCompoundAddress(
addressChunks,
dwChunkCount,
lpConnection,
&dwSize ) )
{
OutputDebugString(
"Couldn't create compound address.\n");
}
}
if FAILED( lpDP->InitializeConnection(
lpConnection, 0 ) )
{
MessageBox( hWnd,
"Error initializing DirectPlay object.",
"Error", MB_OK );
EnableWindow( GetDlgItem( hWnd, IDCREATE ),
FALSE );
EnableWindow( GetDlgItem( hWnd, IDPLAYERS ),
FALSE );
EnableWindow( GetDlgItem( hWnd, IDJOIN ),
FALSE );
}
else
{
EnableWindow( GetDlgItem( hWnd, IDCREATE ),
TRUE );
bUserCancel = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -