2000-07-10 13:19:28 +00:00
|
|
|
/* DirectPlay & DirectPlayLobby messaging implementation
|
|
|
|
*
|
|
|
|
* Copyright 2000 - Peter Hunnisett
|
|
|
|
*
|
|
|
|
* <presently under construction - contact hunnise@nortelnetworks.com>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "debugtools.h"
|
|
|
|
|
2000-08-25 21:58:05 +00:00
|
|
|
#include "wingdi.h"
|
|
|
|
#include "winuser.h"
|
2000-08-29 23:55:06 +00:00
|
|
|
#include "winerror.h"
|
2000-08-25 21:58:05 +00:00
|
|
|
|
2000-07-10 13:19:28 +00:00
|
|
|
#include "dplayx_messages.h"
|
2000-08-29 23:55:06 +00:00
|
|
|
#include "dplay_global.h"
|
|
|
|
#include "dplayx_global.h"
|
2000-07-10 13:19:28 +00:00
|
|
|
|
|
|
|
DEFAULT_DEBUG_CHANNEL(dplay)
|
|
|
|
|
2000-08-25 21:58:05 +00:00
|
|
|
typedef struct tagMSGTHREADINFO
|
|
|
|
{
|
|
|
|
HANDLE hStart;
|
|
|
|
HANDLE hDeath;
|
|
|
|
HANDLE hSettingRead;
|
|
|
|
HANDLE hNotifyEvent;
|
|
|
|
} MSGTHREADINFO, *LPMSGTHREADINFO;
|
|
|
|
|
2000-07-10 13:19:28 +00:00
|
|
|
|
2000-08-25 21:58:05 +00:00
|
|
|
static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
|
2000-07-10 13:19:28 +00:00
|
|
|
|
|
|
|
/* Create the message reception thread to allow the application to receive
|
|
|
|
* asynchronous message reception
|
|
|
|
*/
|
2000-08-25 21:58:05 +00:00
|
|
|
DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
|
|
|
|
HANDLE hDeath, HANDLE hConnRead )
|
2000-07-10 13:19:28 +00:00
|
|
|
{
|
2000-08-25 21:58:05 +00:00
|
|
|
DWORD dwMsgThreadId;
|
|
|
|
LPMSGTHREADINFO lpThreadInfo;
|
2000-07-10 13:19:28 +00:00
|
|
|
|
2000-08-25 21:58:05 +00:00
|
|
|
lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
|
|
|
|
if( lpThreadInfo == NULL )
|
2000-07-10 13:19:28 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-08-25 21:58:05 +00:00
|
|
|
/* The notify event may or may not exist. Depends if async comm or not */
|
|
|
|
if( hNotifyEvent &&
|
|
|
|
!DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
|
|
|
|
GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
|
|
|
|
0, FALSE, DUPLICATE_SAME_ACCESS ) )
|
|
|
|
{
|
|
|
|
ERR( "Unable to duplicate event handle\n" );
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* These 3 handles don't need to be duplicated because we don't keep a
|
|
|
|
* reference to them where they're created. They're created specifically
|
|
|
|
* for the message thread
|
|
|
|
*/
|
|
|
|
lpThreadInfo->hStart = hStart;
|
|
|
|
lpThreadInfo->hDeath = hDeath;
|
|
|
|
lpThreadInfo->hSettingRead = hConnRead;
|
|
|
|
|
|
|
|
if( !CreateThread( NULL, /* Security attribs */
|
|
|
|
0, /* Stack */
|
|
|
|
DPL_MSG_ThreadMain, /* Msg reception function */
|
|
|
|
lpThreadInfo, /* Msg reception func parameter */
|
|
|
|
0, /* Flags */
|
|
|
|
&dwMsgThreadId /* Updated with thread id */
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ERR( "Unable to create msg thread\n" );
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: Should I be closing the handle to the thread or does that
|
|
|
|
terminate the thread? */
|
2000-07-10 13:19:28 +00:00
|
|
|
|
|
|
|
return dwMsgThreadId;
|
2000-08-25 21:58:05 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
|
|
|
|
HeapFree( GetProcessHeap(), 0, lpThreadInfo );
|
|
|
|
|
|
|
|
return 0;
|
2000-07-10 13:19:28 +00:00
|
|
|
}
|
2000-08-25 21:58:05 +00:00
|
|
|
|
|
|
|
static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
|
2000-07-10 13:19:28 +00:00
|
|
|
{
|
2000-08-25 21:58:05 +00:00
|
|
|
LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext;
|
|
|
|
DWORD dwWaitResult;
|
|
|
|
|
|
|
|
TRACE( "Msg thread created. Waiting on app startup\n" );
|
|
|
|
|
|
|
|
/* Wait to ensure that the lobby application is started w/ 1 min timeout */
|
|
|
|
dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
|
|
|
|
if( dwWaitResult == WAIT_TIMEOUT )
|
|
|
|
{
|
|
|
|
FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult );
|
|
|
|
goto end_of_thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close this handle as it's not needed anymore */
|
|
|
|
CloseHandle( lpThreadInfo->hStart );
|
|
|
|
lpThreadInfo->hStart = 0;
|
|
|
|
|
|
|
|
/* Wait until the lobby knows what it is */
|
|
|
|
dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
|
|
|
|
if( dwWaitResult == WAIT_TIMEOUT )
|
|
|
|
{
|
|
|
|
ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close this handle as it's not needed anymore */
|
|
|
|
CloseHandle( lpThreadInfo->hSettingRead );
|
|
|
|
lpThreadInfo->hSettingRead = 0;
|
|
|
|
|
|
|
|
TRACE( "App created && intialized starting main message reception loop\n" );
|
2000-07-10 13:19:28 +00:00
|
|
|
|
|
|
|
for ( ;; )
|
|
|
|
{
|
2000-08-25 21:58:05 +00:00
|
|
|
MSG lobbyMsg;
|
|
|
|
#ifdef STRICT
|
|
|
|
HANDLE hNullHandle = NULL;
|
|
|
|
#else
|
|
|
|
HANDLE hNullHandle = 0;
|
|
|
|
#endif
|
2000-07-10 13:19:28 +00:00
|
|
|
|
2000-08-25 21:58:05 +00:00
|
|
|
GetMessageW( &lobbyMsg, hNullHandle, 0, 0 );
|
2000-07-10 13:19:28 +00:00
|
|
|
}
|
|
|
|
|
2000-08-25 21:58:05 +00:00
|
|
|
end_of_thread:
|
|
|
|
TRACE( "Msg thread exiting!\n" );
|
|
|
|
HeapFree( GetProcessHeap(), 0, lpThreadInfo );
|
|
|
|
|
|
|
|
return 0;
|
2000-07-10 13:19:28 +00:00
|
|
|
}
|
|
|
|
|
2000-08-29 23:55:06 +00:00
|
|
|
|
|
|
|
HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
|
|
|
|
LPDPID lpdpidAllocatedId )
|
|
|
|
{
|
|
|
|
LPVOID lpMsg;
|
|
|
|
LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
|
|
|
|
DWORD dwMsgSize;
|
|
|
|
DWORD dwWaitReturn;
|
|
|
|
HRESULT hr = DP_OK;
|
|
|
|
|
|
|
|
FIXME( "semi stub\n" );
|
|
|
|
|
|
|
|
DebugBreak();
|
|
|
|
|
|
|
|
dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
|
|
|
|
|
|
|
|
lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
|
|
|
|
|
|
|
|
lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg +
|
|
|
|
This->dp2->spData.dwSPHeaderSize );
|
|
|
|
|
|
|
|
lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
|
|
|
|
lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
|
|
|
|
lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
|
|
|
|
|
|
|
|
lpMsgBody->dwFlags = dwFlags;
|
|
|
|
|
|
|
|
/* FIXME: Need to have a more advanced queuing system as this needs to
|
|
|
|
* block on send until we get response. Otherwise we need to be
|
|
|
|
* able to ensure we can pick out the exact response. Of course,
|
|
|
|
* with something as non critical as this, would it matter? The
|
|
|
|
* id has been effectively reserved for this session...
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
DPSP_SENDDATA data;
|
|
|
|
|
|
|
|
data.dwFlags = DPSEND_GUARANTEED;
|
|
|
|
data.idPlayerTo = 0; /* Name server */
|
|
|
|
data.idPlayerFrom = 0; /* Sending from DP */
|
|
|
|
data.lpMessage = lpMsg;
|
|
|
|
data.dwMessageSize = dwMsgSize;
|
|
|
|
data.bSystemMessage = TRUE; /* Allow reply to be sent */
|
|
|
|
data.lpISP = This->dp2->spData.lpISP;
|
|
|
|
|
|
|
|
/* Setup for receipt */
|
|
|
|
This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
|
|
|
|
|
|
|
|
hr = (*This->dp2->spData.lpCB->Send)( &data );
|
|
|
|
|
|
|
|
if( FAILED(hr) )
|
|
|
|
{
|
|
|
|
ERR( "Request for new playerID send failed: %s\n",
|
|
|
|
DPLAYX_HresultToString( hr ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dwWaitReturn = WaitForSingleObject( This->dp2->hMsgReceipt, 30000 );
|
|
|
|
if( dwWaitReturn != WAIT_OBJECT_0 )
|
|
|
|
{
|
|
|
|
ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle( This->dp2->hMsgReceipt );
|
|
|
|
This->dp2->hMsgReceipt = 0;
|
|
|
|
|
|
|
|
/* Need to examine the data and extract the new player id */
|
|
|
|
/* I just hope that dplay doesn't return the whole new player! */
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This function seems to cause a trap in the SP. It would seem unnecessary */
|
|
|
|
/* FIXME: Remove this method if not required */
|
|
|
|
HRESULT DP_MSG_OpenStream( IDirectPlay2AImpl* This )
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
DPSP_SENDDATA data;
|
|
|
|
|
|
|
|
data.dwFlags = DPSEND_OPENSTREAM;
|
|
|
|
data.idPlayerTo = 0; /* Name server */
|
|
|
|
data.idPlayerFrom = 0; /* From DP itself */
|
|
|
|
data.lpMessage = NULL;
|
|
|
|
data.dwMessageSize = This->dp2->spData.dwSPHeaderSize;
|
|
|
|
data.bSystemMessage = FALSE; /* FIXME? */
|
|
|
|
data.lpISP = This->dp2->spData.lpISP;
|
|
|
|
|
|
|
|
hr = (*This->dp2->spData.lpCB->Send)( &data );
|
|
|
|
|
|
|
|
if( FAILED(hr) )
|
|
|
|
{
|
|
|
|
ERR( "Request for open stream send failed: %s\n",
|
|
|
|
DPLAYX_HresultToString( hr ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: hack to give some time for channel to open */
|
|
|
|
SleepEx( 1000 /* 1 sec */, FALSE );
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|