Commit 10a04e74 authored by Peter Hunnisett's avatar Peter Hunnisett Committed by Alexandre Julliard

- Add proper message reply mechanism and sp player data storage

- More implementation and fixes
parent 23a5b79f
......@@ -77,7 +77,7 @@ static IClassFactoryImpl DP_and_DPL_CF = {&DP_and_DPL_Vtbl, 1 };
/*******************************************************************************
* DPLAYX_DllGetClassObject [DPLAYX.?]
* DPLAYX_DllGetClassObject [DPLAYX.11]
* Retrieves DP or DPL class object from a DLL object
*
* NOTES
......
......@@ -160,6 +160,8 @@ static HRESULT WINAPI DP_IF_EnumSessions
( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_InitializeConnection
( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
DWORD dwFlags, LPVOID lpContext );
......@@ -174,7 +176,7 @@ static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData );
static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
......@@ -241,6 +243,7 @@ static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
DPQ_INIT(This->dp2->receiveMsgs);
DPQ_INIT(This->dp2->sendMsgs);
DPQ_INIT(This->dp2->replysExpected);
if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
{
......@@ -504,14 +507,14 @@ static HRESULT WINAPI DP_QueryInterface
TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
*ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( IDirectPlay2Impl ) );
sizeof( *This ) );
if( *ppvObj == NULL )
{
return DPERR_OUTOFMEMORY;
}
CopyMemory( *ppvObj, iface, sizeof( IDirectPlay2Impl ) );
CopyMemory( *ppvObj, This, sizeof( *This ) );
(*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
......@@ -613,25 +616,22 @@ static inline DPID DP_NextObjectId(void)
}
/* *lplpReply will be non NULL iff there is something to reply */
HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
DWORD dwMessageBodySize, LPCVOID lpMessageHeader,
HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
WORD wCommandId, WORD wVersion,
LPVOID* lplpReply, LPDWORD lpdwMsgSize )
{
TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
This, lpMessageBody, dwMessageBodySize, lpMessageHeader, wCommandId,
This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
wVersion );
DebugBreak();
switch( wCommandId )
{
case DPMSGCMD_REQUESTNEWPLAYERID:
{
#if 0
LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
(LPCDPMSG_REQUESTNEWPLAYERID)lpMessageBody;
#endif
(LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
LPDPMSG_NEWPLAYERIDREPLY lpReply;
*lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
......@@ -640,25 +640,8 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
HEAP_ZERO_MEMORY,
*lpdwMsgSize );
FIXME( "Ignoring dwFlags in request msg\n" );
#if 0
/* This is just a test. See how large the SPData is and send it */
{
LPVOID lpData;
DWORD dwDataSize;
HRESULT hr;
hr = IDirectPlaySP_GetSPData( This->dp2->spData.lpISP, &lpData,
&dwDataSize, DPSET_REMOTE );
if( FAILED(hr) )
{
ERR( "Unable to get remote SPData %s\n", DPLAYX_HresultToString(hr) );
}
}
#endif
FIXME( "Ignoring dwFlags 0x%08lx in request msg\n",
lpcMsg->dwFlags );
/* Setup the reply */
lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
......@@ -676,29 +659,25 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
break;
}
case DPMSGCMD_GETNAMETABLEREPLY:
case DPMSGCMD_NEWPLAYERIDREPLY:
{
if( This->dp2->hMsgReceipt )
{
/* This is a hack only */
This->dp2->lpMsgReceived = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwMessageBodySize );
CopyMemory( This->dp2->lpMsgReceived, lpMessageBody, dwMessageBodySize );
SetEvent( This->dp2->hMsgReceipt );
}
else
{
ERR( "No receipt event set - only expecting in reply mode\n" );
}
DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
break;
}
case DPMSGCMD_FORWARDADDPLAYERNACK:
{
DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
break;
}
default:
{
FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
DebugBreak();
break;
}
}
......@@ -873,6 +852,8 @@ lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
/* FIXME: Should we validate the dwFlags? */
lpGData->dwFlags = dwFlags;
TRACE( "Created group id 0x%08lx\n", *lpid );
return lpGData;
}
......@@ -968,6 +949,7 @@ static HRESULT WINAPI DP_IF_CreateGroup
if( DPID_SYSTEM_GROUP == *lpidGroup )
{
This->dp2->lpSysGroup = lpGData;
TRACE( "Inserting system group\n" );
}
else
{
......@@ -1149,6 +1131,11 @@ lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
}
}
/* Initialize the SP data section */
lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
TRACE( "Created player id 0x%08lx\n", *lpid );
return lpPData;
}
......@@ -1325,6 +1312,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer
HANDLE hr = DP_OK;
lpPlayerData lpPData;
lpPlayerList lpPList;
DWORD dwCreateFlags = 0;
TRACE( "(%p)->(%p,%p,%d,%p,0x%08lx,0x%08lx,%u)\n",
This, lpidPlayer, lpPlayerName, hEvent, lpData,
......@@ -1340,6 +1328,35 @@ static HRESULT WINAPI DP_IF_CreatePlayer
return DPERR_INVALIDPARAMS;
}
/* Determine the creation flags for the player. These will be passed
* to the name server if requesting a player id and to the SP when
* informing it of the player creation
*/
{
if( dwFlags & DPPLAYER_SERVERPLAYER )
{
if( *lpidPlayer == DPID_SERVERPLAYER )
{
/* Server player for the host interface */
dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
}
else if( *lpidPlayer == DPID_NAME_SERVER )
{
/* Name server - master of everything */
dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
}
else
{
/* Server player for a non host interface */
dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
}
}
if( lpMsgHdr == NULL )
dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
}
/* Verify we know how to handle all the flags */
if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
( dwFlags & DPPLAYER_SPECTATOR )
......@@ -1360,7 +1377,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer
}
else
{
hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer );
hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
if( FAILED(hr) )
{
......@@ -1376,6 +1393,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer
*/
}
/* FIXME: Should we be storing these dwFlags or the creation ones? */
lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
hEvent, bAnsi );
......@@ -1406,28 +1424,15 @@ static HRESULT WINAPI DP_IF_CreatePlayer
if( This->dp2->spData.lpCB->CreatePlayer )
{
DPSP_CREATEPLAYERDATA data;
DWORD dwCreateFlags = 0;
TRACE( "Calling SP CreatePlayer\n" );
if( ( dwFlags & DPPLAYER_SERVERPLAYER ) &&
( *lpidPlayer == DPID_SERVERPLAYER )
)
dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
if( ( dwFlags & DPPLAYER_SERVERPLAYER ) &&
( *lpidPlayer == DPID_NAME_SERVER )
)
dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
if( lpMsgHdr == NULL )
dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
data.idPlayer = *lpidPlayer;
data.dwFlags = dwCreateFlags;
data.lpSPMessageHeader = lpMsgHdr;
data.lpISP = This->dp2->spData.lpISP;
TRACE( "Calling SP CreatePlayer 0x%08lx: dwFlags: 0x%08lx lpMsgHdr: %p\n",
*lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
}
......@@ -1453,11 +1458,22 @@ static HRESULT WINAPI DP_IF_CreatePlayer
if( FAILED(hr) )
{
ERR( "Failed to add player to sys groupwith sp: %s\n",
ERR( "Failed to add player to sys group with sp: %s\n",
DPLAYX_HresultToString(hr) );
return hr;
}
#if 1
if( This->dp2->bHostInterface == FALSE )
{
/* Let the name server know about the creation of this player */
/* FIXME: Is this only to be done for the creation of a server player or
* is this used for regular players? If only for server players, move
* this call to DP_SecureOpen(...);
*/
hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
}
#else
/* Inform all other peers of the creation of a new player. If there are
* no peers keep this quiet.
* Also, if this was a remote event, no need to rebroadcast it.
......@@ -1484,6 +1500,7 @@ static HRESULT WINAPI DP_IF_CreatePlayer
hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
}
#endif
return hr;
}
......@@ -2055,7 +2072,8 @@ static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
/* Does a thread exist? If so we were doing an async enum session */
if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
{
TRACE( "Killing EnumSession thread\n" );
TRACE( "Killing EnumSession thread %u\n",
This->dp2->hEnumSessionThread );
/* Request that the thread kill itself nicely */
SetEvent( This->dp2->hKillEnumSessionThreadEvent );
......@@ -2094,7 +2112,12 @@ static HRESULT WINAPI DP_IF_EnumSessions
DP_IF_GetCaps( This, &spCaps, 0 );
dwTimeout = spCaps.dwTimeout;
/* FIXME: If it's still 0, we need to provide the IP default */
/* The service provider doesn't provide one either! */
if( dwTimeout == 0 )
{
/* Provide the TCP/IP default */
dwTimeout = DPMSG_WAIT_5_SECS;
}
}
if( dwFlags & DPENUMSESSIONS_STOPASYNC )
......@@ -2725,6 +2748,7 @@ static HRESULT WINAPI DP_SecureOpen
hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
0,
DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
}
else if( dwFlags & DPOPEN_CREATE )
{
......@@ -3792,7 +3816,7 @@ BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
/* Find and perform a LoadLibrary on the requested SP or LP GUID */
static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData )
static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
{
UINT i;
LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
......@@ -3814,6 +3838,7 @@ static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData )
FILETIME filetime;
(i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
*lpbIsDpSp = (i == 0) ? TRUE : FALSE;
/* Need to loop over the service providers in the registry */
......@@ -3910,6 +3935,7 @@ static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData )
continue;
}
TRACE( "Loading %s\n", returnBuffer );
return LoadLibraryA( returnBuffer );
}
}
......@@ -3917,18 +3943,17 @@ static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData )
return 0;
}
static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
static HRESULT WINAPI DP_IF_InitializeConnection
( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
{
HMODULE hServiceProvider;
HRESULT hr;
LPDPSP_SPINIT SPInit;
GUID guidSP;
DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
ICOM_THIS(IDirectPlay3Impl,iface);
const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
TRACE("(%p)->(%p,0x%08lx)\n", This, lpConnection, dwFlags );
TRACE("(%p)->(%p,0x%08lx,%u)\n", This, lpConnection, dwFlags, bAnsi );
if( dwFlags != 0 )
{
......@@ -3958,7 +3983,7 @@ static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
This->dp2->spData.lpGuid = &guidSP;
/* Load the service provider */
hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData );
hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
if( hServiceProvider == 0 )
{
......@@ -3966,22 +3991,35 @@ static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
return DPERR_UNAVAILABLE;
}
/* Initialize the service provider by calling SPInit */
SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
if( bIsDpSp )
{
/* Initialize the service provider by calling SPInit */
SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
}
else
{
/* Initialize the service provider by calling SPInit */
SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "DPLSPInit" );
}
if( SPInit == NULL )
{
ERR( "Service provider doesn't provide SPInit interface?\n" );
ERR( "Service provider doesn't provide %s interface?\n",
bIsDpSp ? "SPInit" : "DPLSPInit" );
FreeLibrary( hServiceProvider );
return DPERR_UNAVAILABLE;
}
TRACE( "Calling SPInit\n" );
TRACE( "Calling %s (SP entry point)\n", bIsDpSp ? "SPInit" : "DPLSPInit" );
/* FIXME: Need to break this out into a seperate routine for DP SP and
* DPL SP as they actually use different stuff...
*/
hr = (*SPInit)( &This->dp2->spData );
if( FAILED(hr) )
{
ERR( "SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
ERR( "DP/DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
FreeLibrary( hServiceProvider );
return hr;
}
......@@ -3995,12 +4033,18 @@ static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
return DP_OK;
}
static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
{
ICOM_THIS(IDirectPlay3Impl,iface);
return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
}
static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
{
ICOM_THIS(IDirectPlay3Impl,iface);
FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpConnection, dwFlags );
return DP_OK;
return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
}
static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
......@@ -4846,9 +4890,42 @@ static ICOM_VTABLE(IDirectPlay4) directPlay4AVT =
};
#undef XCAST
extern
HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
DPID idPlayer,
LPVOID* lplpData )
{
lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
if( lpPlayer == NULL )
{
return DPERR_INVALIDPLAYER;
}
*lplpData = lpPlayer->lpPData->lpSPPlayerData;
return DP_OK;
}
extern
HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
DPID idPlayer,
LPVOID lpData )
{
lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
if( lpPlayer == NULL )
{
return DPERR_INVALIDPLAYER;
}
lpPlayer->lpPData->lpSPPlayerData = lpData;
return DP_OK;
}
/***************************************************************************
* DirectPlayEnumerateA (DPLAYX.2)
* DirectPlayEnumerateA [DPLAYX.2][DPLAYX.9][DPLAY.2]
*
* The pointer to the structure lpContext will be filled with the
* appropriate data for each service offered by the OS. These services are
......@@ -4980,7 +5057,7 @@ HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback,
}
/***************************************************************************
* DirectPlayEnumerateW (DPLAYX.3)
* DirectPlayEnumerateW [DPLAYX.3]
*
*/
HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
......@@ -5027,7 +5104,7 @@ static BOOL CALLBACK cbDPCreateEnumConnections(
/***************************************************************************
* DirectPlayCreate (DPLAYX.1) (DPLAY.1)
* DirectPlayCreate [DPLAYX.1][DPLAY.1]
*
*/
HRESULT WINAPI DirectPlayCreate
......@@ -5044,7 +5121,6 @@ HRESULT WINAPI DirectPlayCreate
return CLASS_E_NOAGGREGATION;
}
/* Create an IDirectPlay object. We don't support that so we'll cheat and
give them an IDirectPlay2A object and hope that doesn't cause problems */
if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
......
......@@ -35,6 +35,21 @@ typedef struct tagEnumSessionAsyncCallbackData
HANDLE hSuicideRequest;
} EnumSessionAsyncCallbackData;
typedef struct tagDP_MSG_REPLY_STRUCT
{
HANDLE hReceipt;
WORD wExpectedReply;
LPVOID lpReplyMsg;
DWORD dwMsgBodySize;
/* FIXME: Is the message header required as well? */
} DP_MSG_REPLY_STRUCT, *LPDP_MSG_REPLY_STRUCT;
typedef struct tagDP_MSG_REPLY_STRUCT_LIST
{
DPQ_ENTRY(tagDP_MSG_REPLY_STRUCT_LIST) replysExpected;
DP_MSG_REPLY_STRUCT replyExpected;
} DP_MSG_REPLY_STRUCT_LIST, *LPDP_MSG_REPLY_STRUCT_LIST;
struct PlayerData
{
/* Individual player information */
......@@ -53,6 +68,9 @@ struct PlayerData
LPVOID lpRemoteData;
DWORD dwRemoteDataSize;
/* SP data on a per player basis */
LPVOID lpSPPlayerData;
DWORD dwFlags; /* Special remarks about the type of player */
};
typedef struct PlayerData* lpPlayerData;
......@@ -137,10 +155,8 @@ typedef struct tagDirectPlay2Data
BOOL bConnectionInitialized;
/* proof of concept for message reception */
HANDLE hMsgReceipt;
LPVOID lpMsgReceived;
/* Expected messages queue */
DPQ_HEAD( tagDP_MSG_REPLY_STRUCT_LIST ) replysExpected;
} DirectPlay2Data;
typedef struct tagDirectPlay3Data
......@@ -192,5 +208,11 @@ HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
WORD wCommandId, WORD wVersion,
LPVOID* lplpReply, LPDWORD lpdwMsgSize );
/* DP SP external interfaces into DirectPlay */
extern HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP, DPID idPlayer, LPVOID* lplpData );
extern HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP, DPID idPlayer, LPVOID lpData );
/* DP external interfaces to call into DPSP interface */
extern LPVOID DPSP_CreateSPPlayerData(void);
#endif /* __WINE_DPLAY_GLOBAL_INCLUDED */
......@@ -26,7 +26,6 @@ static BOOL DPSP_DestroyIUnknown( LPVOID lpSP );
static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp );
static BOOL DPSP_DestroyDirectPlaySP( LPVOID lpSP );
/* Predefine the interface */
typedef struct IDirectPlaySPImpl IDirectPlaySPImpl;
......@@ -46,8 +45,6 @@ typedef struct tagDirectPlaySPData
IDirectPlay2Impl* dplay; /* FIXME: This should perhaps be iface not impl */
LPVOID lpPlayerData; /* FIXME: Need to figure out how this actually behaves */
DWORD dwPlayerDataSize;
} DirectPlaySPData;
#define DPSP_IMPL_FIELDS \
......@@ -64,7 +61,15 @@ struct IDirectPlaySPImpl
/* Forward declaration of virtual tables */
static ICOM_VTABLE(IDirectPlaySP) directPlaySPVT;
/* This structure is passed to the DP object for safe keeping */
typedef struct tagDP_SPPLAYERDATA
{
LPVOID lpPlayerLocalData;
DWORD dwPlayerLocalDataSize;
LPVOID lpPlayerRemoteData;
DWORD dwPlayerRemoteDataSize;
} DP_SPPLAYERDATA, *LPDP_SPPLAYERDATA;
/* Create the SP interface */
extern
......@@ -165,6 +170,15 @@ static BOOL DPSP_CreateDirectPlaySP( LPVOID lpSP, IDirectPlay2Impl* dp )
*/
/* IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp ); */
/* FIXME: This is a kludge to get around a problem where a queryinterface
* is used to get a new interface and then is closed. We will then
* reference garbage. However, with this we will never deallocate
* the interface we store. The correct fix is to require all
* DP internal interfaces to use the This->dp2 interface which
* should be changed to This->dp
*/
IDirectPlayX_AddRef( (LPDIRECTPLAY2)dp );
return TRUE;
}
......@@ -200,14 +214,14 @@ static HRESULT WINAPI DPSP_QueryInterface
TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
*ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( IDirectPlaySPImpl ) );
sizeof( *This ) );
if( *ppvObj == NULL )
{
return DPERR_OUTOFMEMORY;
}
CopyMemory( *ppvObj, iface, sizeof( IDirectPlaySPImpl ) );
CopyMemory( *ppvObj, This, sizeof( *This ) );
(*(IDirectPlaySPImpl**)ppvObj)->ulInterfaceRef = 0;
if( IsEqualGUID( &IID_IDirectPlaySP, riid ) )
......@@ -363,18 +377,50 @@ static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData
DWORD dwFlags
)
{
HRESULT hr;
LPDP_SPPLAYERDATA lpPlayerData;
ICOM_THIS(IDirectPlaySPImpl,iface);
TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
FIXME( "(%p)->(0x%08lx,%p,%p,0x%08lx): stub\n",
/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx)\n",
This, idPlayer, lplpData, lpdwDataSize, dwFlags );
hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerData );
if( FAILED(hr) )
{
TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr) );
return DPERR_INVALIDPLAYER;
}
/* What to do in the case where there is nothing set yet? */
if( dwFlags == DPSET_LOCAL )
{
if( lpPlayerData->lpPlayerLocalData )
{
HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerLocalData );
}
*lplpData = This->sp->lpPlayerData;
*lpdwDataSize = This->sp->dwPlayerDataSize;
*lplpData = lpPlayerData->lpPlayerLocalData;
*lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize;
}
else if( dwFlags == DPSET_REMOTE )
{
if( lpPlayerData->lpPlayerRemoteData )
{
HeapFree( GetProcessHeap(), 0, lpPlayerData->lpPlayerRemoteData );
}
return DP_OK;
*lplpData = lpPlayerData->lpPlayerRemoteData;
*lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize;
}
if( *lplpData == NULL )
{
hr = DPERR_GENERIC;
}
return hr;
}
static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
......@@ -391,7 +437,7 @@ static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
ICOM_THIS(IDirectPlaySPImpl,iface);
TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n",
This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
......@@ -409,6 +455,7 @@ static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
switch( lpMsg->wCommandId )
{
/* Name server needs to handle this request */
/* FIXME: This should be done in direct play handler */
case DPMSGCMD_ENUMSESSIONSREQUEST:
{
DPSP_REPLYDATA data;
......@@ -430,6 +477,7 @@ static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
}
/* Name server needs to handle this request */
/* FIXME: This should be done in direct play handler */
case DPMSGCMD_ENUMSESSIONSREPLY:
{
NS_SetRemoteComputerAsNameServer( lpMessageHeader,
......@@ -438,14 +486,13 @@ static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
This->sp->dplay->dp2->lpNameServerData );
/* No reply expected */
hr = DP_OK;
break;
}
case DPMSGCMD_GETNAMETABLE:
case DPMSGCMD_GETNAMETABLEREPLY:
case DPMSGCMD_NEWPLAYERIDREPLY:
case DPMSGCMD_REQUESTNEWPLAYERID:
/* Pass everything else to Direct Play */
default:
{
DPSP_REPLYDATA data;
......@@ -453,9 +500,9 @@ static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
data.dwMessageSize = 0;
/* Pass this message to the dplay interface to handle */
DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
lpMessageHeader, wCommandId, wVersion,
&data.lpMessage, &data.dwMessageSize );
hr = DP_HandleMessage( This->sp->dplay, lpMessageBody, dwMessageBodySize,
lpMessageHeader, wCommandId, wVersion,
&data.lpMessage, &data.dwMessageSize );
/* Do we want a reply? */
if( data.lpMessage != NULL )
......@@ -476,10 +523,6 @@ static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage
break;
}
default:
FIXME( "Unknown Command of %u and size 0x%08lx\n",
lpMsg->wCommandId, dwMessageBodySize );
}
#if 0
......@@ -736,22 +779,40 @@ static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData
DWORD dwFlags
)
{
ICOM_THIS(IDirectPlaySPImpl,iface);
HRESULT hr;
LPDP_SPPLAYERDATA lpPlayerEntry;
LPVOID lpPlayerData;
/* FIXME: I'm not sure if this stuff should be associated with the DPlay
* player lists. How else would this stuff get deleted?
*/
ICOM_THIS(IDirectPlaySPImpl,iface);
TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
FIXME( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx): stub\n",
/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx)\n",
This, idPlayer, lpData, dwDataSize, dwFlags );
This->sp->lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
hr = DP_GetSPPlayerData( This->sp->dplay, idPlayer, (LPVOID*)&lpPlayerEntry );
if( FAILED(hr) )
{
/* Player must not exist */
return DPERR_INVALIDPLAYER;
}
This->sp->dwPlayerDataSize = dwDataSize;
CopyMemory( This->sp->lpPlayerData, lpData, dwDataSize );
lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
CopyMemory( lpPlayerData, lpData, dwDataSize );
return DP_OK;
if( dwFlags == DPSET_LOCAL )
{
lpPlayerEntry->lpPlayerLocalData = lpPlayerData;
lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize;
}
else if( dwFlags == DPSET_REMOTE )
{
lpPlayerEntry->lpPlayerRemoteData = lpPlayerData;
lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize;
}
hr = DP_SetSPPlayerData( This->sp->dplay, idPlayer, lpPlayerEntry );
return hr;
}
static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress
......@@ -777,15 +838,16 @@ static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
DWORD dwFlags
)
{
HRESULT hr = DP_OK;
ICOM_THIS(IDirectPlaySPImpl,iface);
TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
TRACE( "(%p)->(%p,%p,0x%08lx)\n",
This, lplpData, lpdwDataSize, dwFlags );
#if 0
/* This is what the documentation says... */
if( dwFlags != 0 )
if( dwFlags != DPSET_REMOTE )
{
return DPERR_INVALIDPARAMS;
}
......@@ -794,7 +856,7 @@ static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
/* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
* thing?
*/
if( dwFlags != 0 )
if( dwFlags != DPSET_REMOTE )
{
FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
}
......@@ -807,14 +869,24 @@ static HRESULT WINAPI IDirectPlaySPImpl_GetSPData
{
*lpdwDataSize = This->sp->dwSpRemoteDataSize;
*lplpData = This->sp->lpSpRemoteData;
if( This->sp->lpSpRemoteData == NULL )
{
hr = DPERR_GENERIC;
}
}
else if( dwFlags == DPSET_LOCAL )
{
*lpdwDataSize = This->sp->dwSpLocalDataSize;
*lplpData = This->sp->lpSpLocalData;
if( This->sp->lpSpLocalData == NULL )
{
hr = DPERR_GENERIC;
}
}
return DP_OK;
return hr;
}
static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
......@@ -828,13 +900,13 @@ static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
ICOM_THIS(IDirectPlaySPImpl,iface);
TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() );
/* TRACE( "Called on process 0x%08lx\n", GetCurrentProcessId() ); */
TRACE( "(%p)->(%p,0x%08lx,0x%08lx)\n",
This, lpData, dwDataSize, dwFlags );
#if 0
/* This is what the documentation says... */
if( dwFlags != 0 )
if( dwFlags != DPSET_REMOTE )
{
return DPERR_INVALIDPARAMS;
}
......@@ -843,35 +915,23 @@ static HRESULT WINAPI IDirectPlaySPImpl_SetSPData
/* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
* thing?
*/
if( dwFlags != 0 )
if( dwFlags != DPSET_REMOTE )
{
FIXME( "Undocumented dwFlags 0x%08lx used\n", dwFlags );
}
#endif
if( dwFlags == DPSET_REMOTE )
{
lpSpData = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY, dwDataSize );
}
else
{
lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
}
lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
CopyMemory( lpSpData, lpData, dwDataSize );
/* If we have data already allocated, free it and replace it */
if( dwFlags == DPSET_REMOTE )
{
/* FIXME: This doesn't strictly make sense as there is no means to share
* this shared data. Must be misinterpreting something...
*/
if( This->sp->lpSpRemoteData )
{
DPLAYX_PrivHeapFree( This->sp->lpSpRemoteData );
HeapFree( GetProcessHeap(), 0, This->sp->lpSpRemoteData );
}
/* NOTE: dwDataSize is also stored in the heap structure */
This->sp->dwSpRemoteDataSize = dwDataSize;
This->sp->lpSpRemoteData = lpSpData;
}
......@@ -923,3 +983,15 @@ static struct ICOM_VTABLE(IDirectPlaySP) directPlaySPVT =
IDirectPlaySPImpl_SetSPData,
IDirectPlaySPImpl_SendComplete
};
/* DP external interfaces to call into DPSP interface */
/* Allocate the structure */
extern LPVOID DPSP_CreateSPPlayerData(void)
{
TRACE( "Creating SPPlayer data struct\n" );
return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( DP_SPPLAYERDATA ) );
}
......@@ -27,8 +27,11 @@ typedef struct tagMSGTHREADINFO
HANDLE hNotifyEvent;
} MSGTHREADINFO, *LPMSGTHREADINFO;
static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
static LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA data,
DWORD dwWaitTime, WORD wReplyCommandId,
LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
/* Create the message reception thread to allow the application to receive
* asynchronous message reception
......@@ -139,6 +142,42 @@ end_of_thread:
return 0;
}
/* DP messageing stuff */
static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
WORD wReplyCommandId );
static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
static
HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId )
{
lpReplyStructList->replyExpected.hReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId;
lpReplyStructList->replyExpected.lpReplyMsg = NULL;
lpReplyStructList->replyExpected.dwMsgBodySize = 0;
/* Insert into the message queue while locked */
EnterCriticalSection( &This->unk->DP_lock );
DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected );
LeaveCriticalSection( &This->unk->DP_lock );
return lpReplyStructList->replyExpected.hReceipt;
}
static
LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
{
CloseHandle( lpReplyStructList->replyExpected.hReceipt );
*lplpReplyMsg = lpReplyStructList->replyExpected.lpReplyMsg;
*lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize;
return lpReplyStructList->replyExpected.lpReplyMsg;
}
HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
LPDPID lpdpidAllocatedId )
......@@ -146,7 +185,6 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
LPVOID lpMsg;
LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
DWORD dwMsgSize;
DWORD dwWaitReturn;
HRESULT hr = DP_OK;
dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
......@@ -156,19 +194,16 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg +
This->dp2->spData.dwSPHeaderSize );
/* Compose dplay message envelope */
lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
/* Compose the body of the message */
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...
*/
{
/* Send the message */
{
DPSP_SENDDATA data;
data.dwFlags = DPSEND_GUARANTEED;
......@@ -179,37 +214,20 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
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 );
TRACE( "Asking for player id w/ dwFlags 0x%08lx\n",
lpMsgBody->dwFlags );
TRACE( "Sending request for player id\n" );
hr = (*This->dp2->spData.lpCB->Send)( &data );
if( FAILED(hr) )
{
ERR( "Request for new playerID send failed: %s\n",
DPLAYX_HresultToString( hr ) );
return DPERR_NOCONNECTION;
}
}
dwWaitReturn = WaitForSingleObject( This->dp2->hMsgReceipt, 30000 );
if( dwWaitReturn != WAIT_OBJECT_0 )
{
ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
hr = DPERR_TIMEOUT;
DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY,
&lpMsg, &dwMsgSize );
}
CloseHandle( This->dp2->hMsgReceipt );
This->dp2->hMsgReceipt = 0;
/* Need to examine the data and extract the new player id */
if( !FAILED(hr) )
{
LPCDPMSG_NEWPLAYERIDREPLY lpcReply;
lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)This->dp2->lpMsgReceived;
lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)lpMsg;
*lpdpidAllocatedId = lpcReply->dpidNewPlayerId;
......@@ -217,47 +235,217 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
/* FIXME: I think that the rest of the message has something to do
* with remote data for the player that perhaps I need to setup.
* However, with the information that is passed, all that it could
* be used for is a standardized intialization value, which I'm
* guessing we can do without. Unless the message content is the same
* for several different messages?
*/
#if 0
/* Set the passed service provider data */
IDirectPlaySP_SetSPData( This->dp2->spData.lpISP, data,
msgsize, DPSET_REMOTE );
HeapFree( GetProcessHeap(), 0, lpMsg );
}
return hr;
}
HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer )
{
LPVOID lpMsg;
LPDPMSG_FORWARDADDPLAYER lpMsgBody;
DWORD dwMsgSize;
HRESULT hr = DP_OK;
dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
lpMsgBody = (LPDPMSG_FORWARDADDPLAYER)( (BYTE*)lpMsg +
This->dp2->spData.dwSPHeaderSize );
/* Compose dplay message envelope */
lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
lpMsgBody->envelope.wCommandId = DPMSGCMD_FORWARDADDPLAYER;
lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
#if 0
{
LPBYTE lpPData;
DWORD dwDataSize;
/* SP Player remote data needs to be propagated at some point - is this the point? */
IDirectPlaySP_GetSPPlayerData( This->dp2->spData.lpISP, dpidServer, (LPVOID*)&lpPData, &dwDataSize, DPSET_REMOTE );
ERR( "Player Data size is 0x%08lx\n"
"[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n"
"[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n",
dwDataSize,
lpPData[0], lpPData[1], lpPData[2], lpPData[3], lpPData[4],
lpPData[5], lpPData[6], lpPData[7], lpPData[8], lpPData[9],
lpPData[10], lpPData[11], lpPData[12], lpPData[13], lpPData[14],
lpPData[15], lpPData[16], lpPData[17], lpPData[18], lpPData[19],
lpPData[20], lpPData[21], lpPData[22], lpPData[23], lpPData[24],
lpPData[25], lpPData[26], lpPData[27], lpPData[28], lpPData[29],
lpPData[30], lpPData[31]
);
DebugBreak();
}
#endif
HeapFree( GetProcessHeap(), 0, This->dp2->lpMsgReceived );
This->dp2->lpMsgReceived = NULL;
/* Compose body of message */
lpMsgBody->dpidAppServer = dpidServer;
lpMsgBody->unknown2[0] = 0x0;
lpMsgBody->unknown2[1] = 0x1c;
lpMsgBody->unknown2[2] = 0x6c;
lpMsgBody->unknown2[3] = 0x50;
lpMsgBody->unknown2[4] = 0x9;
lpMsgBody->dpidAppServer2 = dpidServer;
lpMsgBody->unknown3[0] = 0x0;
lpMsgBody->unknown3[0] = 0x0;
lpMsgBody->unknown3[0] = 0x20;
lpMsgBody->unknown3[0] = 0x0;
lpMsgBody->unknown3[0] = 0x0;
lpMsgBody->dpidAppServer3 = dpidServer;
lpMsgBody->unknown4[0] = 0x30;
lpMsgBody->unknown4[1] = 0xb;
lpMsgBody->unknown4[2] = 0x0;
lpMsgBody->unknown4[3] = 0x1e090002;
lpMsgBody->unknown4[4] = 0x0;
lpMsgBody->unknown4[5] = 0x0;
lpMsgBody->unknown4[6] = 0x0;
lpMsgBody->unknown4[7] = 0x32090002;
lpMsgBody->unknown4[8] = 0x0;
lpMsgBody->unknown4[9] = 0x0;
lpMsgBody->unknown4[10] = 0x0;
lpMsgBody->unknown4[11] = 0x0;
lpMsgBody->unknown4[12] = 0x0;
lpMsgBody->unknown5[0] = 0x0;
lpMsgBody->unknown5[1] = 0x0;
/* Send the message */
{
DPSP_SENDDATA data;
data.dwFlags = DPSEND_GUARANTEED;
data.idPlayerTo = 0; /* Name server */
data.idPlayerFrom = dpidServer; /* Sending from session server */
data.lpMessage = lpMsg;
data.dwMessageSize = dwMsgSize;
data.bSystemMessage = TRUE; /* Allow reply to be sent */
data.lpISP = This->dp2->spData.lpISP;
lpMsg = DP_MSG_ExpectReply( This, &data,
DPMSG_WAIT_60_SECS,
DPMSGCMD_GETNAMETABLEREPLY,
&lpMsg, &dwMsgSize );
}
/* Need to examine the data and extract the new player id */
if( lpMsg != NULL )
{
FIXME( "Name Table reply received: stub\n" );
}
return hr;
}
/* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
* not seem to offer any way of uniquely differentiating between replies of the same type
* relative to the request sent. There is an implicit assumption that there will be no
* ordering issues on sends and receives from the opposite machine. No wonder MS is not
* a networking company.
*/
static
LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData,
DWORD dwWaitTime, WORD wReplyCommandId,
LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
{
HRESULT hr;
HANDLE hMsgReceipt;
DP_MSG_REPLY_STRUCT_LIST replyStructList;
DWORD dwWaitReturn;
/* Setup for receipt */
hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList,
wReplyCommandId );
TRACE( "Sending msg and expecting cmd %u in reply within %lu ticks\n",
wReplyCommandId, dwWaitTime );
hr = (*This->dp2->spData.lpCB->Send)( lpData );
if( FAILED(hr) )
{
ERR( "Request for new playerID send failed: %s\n",
DPLAYX_HresultToString( hr ) );
return NULL;
}
dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime );
if( dwWaitReturn != WAIT_OBJECT_0 )
{
ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
return NULL;
}
/* Clean Up */
return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyMsg, lpdwMsgBodySize );
}
/* 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 )
/* Determine if there is a matching request for this incomming message and then copy
* all important data. It is quite silly to have to copy the message, but the documents
* indicate that a copy is taken. Silly really.
*/
void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId,
LPCVOID lpcMsgBody, DWORD dwMsgBodySize )
{
HRESULT hr;
DPSP_SENDDATA data;
LPDP_MSG_REPLY_STRUCT_LIST lpReplyList;
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;
#if 0
if( wCommandId == DPMSGCMD_FORWARDADDPLAYER )
{
DebugBreak();
}
#endif
hr = (*This->dp2->spData.lpCB->Send)( &data );
/* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
* avoid problems.
*/
EnterCriticalSection( &This->unk->DP_lock );
DPQ_REMOVE_ENTRY( This->dp2->replysExpected, replysExpected, replyExpected.wExpectedReply,\
==, wCommandId, lpReplyList );
LeaveCriticalSection( &This->unk->DP_lock );
if( FAILED(hr) )
if( lpReplyList != NULL )
{
ERR( "Request for open stream send failed: %s\n",
DPLAYX_HresultToString( hr ) );
lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize;
lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwMsgBodySize );
CopyMemory( lpReplyList->replyExpected.lpReplyMsg,
lpcMsgBody, dwMsgBodySize );
/* Signal the thread which sent the message that it has a reply */
SetEvent( lpReplyList->replyExpected.hReceipt );
}
else
{
ERR( "No receipt event set - only expecting in reply mode\n" );
DebugBreak();
}
}
/* FIXME: hack to give some time for channel to open */
SleepEx( 1000 /* 1 sec */, FALSE );
void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
LPCVOID lpMsgBody, DWORD dwMsgBodySize )
{
LPCDPMSG_FORWARDADDPLAYERNACK lpcErrorMsg;
return hr;
lpcErrorMsg = (LPCDPMSG_FORWARDADDPLAYERNACK)lpMsgBody;
ERR( "Received error message %u. Error is %s\n",
wCommandId, DPLAYX_HresultToString( lpcErrorMsg->errorCode) );
DebugBreak();
}
......@@ -11,6 +11,20 @@
DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
HANDLE hDeath, HANDLE hConnRead );
HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
LPDPID lpdipidAllocatedId );
HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer );
void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId,
LPCVOID lpMsgBody, DWORD dwMsgBodySize );
void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
LPCVOID lpMsgBody, DWORD dwMsgBodySize );
/* Timings -> 1000 ticks/sec */
#define DPMSG_WAIT_5_SECS 5000
#define DPMSG_WAIT_30_SECS 30000
#define DPMSG_WAIT_60_SECS 60000
#define DPMSG_DEFAULT_WAIT_TIME DPMSG_WAIT_30_SECS
/* Message types etc. */
#include "pshpack1.h"
......@@ -18,12 +32,12 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
/* Non provided messages for DPLAY - guess work which may be wrong :( */
#define DPMSGCMD_ENUMSESSIONSREPLY 1
#define DPMSGCMD_ENUMSESSIONSREQUEST 2
#define DPMSGCMD_GETNAMETABLEREPLY 3 /* Contains all existing players in session */
#define DPMSGCMD_REQUESTNEWPLAYERID 5
#define DPMSGCMD_NEWPLAYERIDREPLY 7
#define DPMSGCMD_CREATESESSION 8
#define DPMSGCMD_CREATESESSION 8 /* Might be a create nameserver or new player msg */
#define DPMSGCMD_CREATENEWPLAYER 9
#define DPMSGCMD_SYSTEMMESSAGE 10
#define DPMSGCMD_DELETEPLAYER 11
......@@ -31,9 +45,9 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
#define DPMSGCMD_ENUMGROUPS 17
#define DPMSGCMD_GETNAMETABLE 19
#define DPMSGCMD_FORWARDADDPLAYER 19
#define DPMSGCMD_GETNAMETABLEREPLY 29
#define DPMSGCMD_FORWARDADDPLAYERNACK 36
/* This is what DP 6 defines it as. Don't know what it means. All messages
* defined below are DPMSGVER_DP6.
......@@ -45,9 +59,8 @@ DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
/* All messages sent from the system are sent with this at the beginning of
* the message.
* Size is 8 bytes
*/
/* Size is 8 bytes */
typedef struct tagDPMSG_SENDENVELOPE
{
DWORD dwMagic;
......@@ -56,6 +69,9 @@ typedef struct tagDPMSG_SENDENVELOPE
} DPMSG_SENDENVELOPE, *LPDPMSG_SENDENVELOPE;
typedef const DPMSG_SENDENVELOPE* LPCDPMSG_SENDENVELOPE;
/* System messages exchanged between players seems to have this
* payload envelope on top of the basic envelope
*/
typedef struct tagDPMSG_SYSMSGENVELOPE
{
DWORD dwPlayerFrom;
......@@ -63,7 +79,7 @@ typedef struct tagDPMSG_SYSMSGENVELOPE
} DPMSG_SYSMSGENVELOPE, *LPDPMSG_SYSMSGENVELOPE;
typedef const DPMSG_SYSMSGENVELOPE* LPCDPMSG_SYSMSGENVELOPE;
/* Reply sent in response to an enumsession request */
typedef struct tagDPMSG_ENUMSESSIONSREPLY
{
DPMSG_SENDENVELOPE envelope;
......@@ -93,13 +109,14 @@ typedef struct tagDPMSG_ENUMSESSIONSREPLY
} DPMSG_ENUMSESSIONSREPLY, *LPDPMSG_ENUMSESSIONSREPLY;
typedef const DPMSG_ENUMSESSIONSREPLY* LPCDPMSG_ENUMSESSIONSREPLY;
/* Msg sent to find out what sessions are available */
typedef struct tagDPMSG_ENUMSESSIONSREQUEST
{
DPMSG_SENDENVELOPE envelope;
GUID guidApplication;
DWORD dwPasswordSize; /* A Guess. This is normally 0x00000000. */
DWORD dwPasswordSize; /* A Guess. This is 0x00000000. */
/* This might be the name server DPID which
is needed for the reply */
......@@ -131,24 +148,50 @@ typedef struct tagDPMSG_NEWPLAYERIDREPLY
DPMSG_SENDENVELOPE envelope;
DPID dpidNewPlayerId;
#if 1
/* Assume that this is data that is tacked on to the end of the message
* that comes from the SP remote data stored that needs to be propagated.
*/
BYTE unknown[36]; /* This appears to always be 0 - not sure though */
#endif
} DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY;
typedef const DPMSG_NEWPLAYERIDREPLY* LPCDPMSG_NEWPLAYERIDREPLY;
#include "poppack.h"
typedef struct tagDPMSG_FORWARDADDPLAYER
{
DPMSG_SENDENVELOPE envelope;
DWORD unknown; /* 0 */
HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
LPDPID lpdipidAllocatedId );
DPID dpidAppServer; /* Remote application server id */
DWORD unknown2[5]; /* ??? */
#define FORWARDADDPLAYER_UNKNOWN2_INIT { 0x0, 0x1c, 0x6c, 0x50, 0x9 }
DPID dpidAppServer2; /* Remote application server id again !? */
DWORD unknown3[5]; /* ??? */
#define FORWARDADDPLAYER_UNKNOWN3_INIT { 0x0, 0x0, 0x20, 0x0, 0x0 }
DPID dpidAppServer3; /* Remote application server id again !? */
DWORD unknown4[12]; /* ??? - Is this a clump of 5 and then 8? */
/* NOTE: 1 byte infront of the two 0x??090002 entries changes! */
#define FORWARDADDPLAYER_UNKNOWN4_INIT { 0x30, 0xb, 0x0, 0x1e090002, 0x0, 0x0, 0x0, 0x32090002, 0x0, 0x0, 0x0, 0x0 }
/* FIXME: I don't think that this is a needed method */
HRESULT DP_MSG_OpenStream( IDirectPlay2AImpl* This );
BYTE unknown5[2]; /* 2 bytes at the end. This may be a part of something! */
#define FORWARDADDPLAYER_UNKNOWN5_INIT { 0x0 }
} DPMSG_FORWARDADDPLAYER, *LPDPMSG_FORWARDADDPLAYER;
typedef const DPMSG_FORWARDADDPLAYER* LPCDPMSG_FORWARDADDPLAYER;
/* This is an error message that can be received. Not sure if this is
* specifically for a forward add player or for all errors
*/
typedef struct tagDPMSG_FORWARDADDPLAYERNACK
{
DPMSG_SENDENVELOPE envelope;
HRESULT errorCode;
} DPMSG_FORWARDADDPLAYERNACK, *LPDPMSG_FORWARDADDPLAYERNACK;
typedef const DPMSG_FORWARDADDPLAYERNACK* LPCDPMSG_FORWARDADDPLAYERNACK;
#include "poppack.h"
#endif
......@@ -343,15 +343,15 @@ static HRESULT WINAPI DPL_QueryInterface
TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
*ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( IDirectPlayLobbyWImpl ) );
sizeof( *This ) );
if( *ppvObj == NULL )
{
return DPERR_OUTOFMEMORY;
}
CopyMemory( *ppvObj, iface, sizeof( IDirectPlayLobbyWImpl ) );
(*(IDirectPlayLobbyWImpl**)ppvObj)->ulInterfaceRef = 0;
CopyMemory( *ppvObj, This, sizeof( *This ) );
(*(IDirectPlayLobbyAImpl**)ppvObj)->ulInterfaceRef = 0;
if( IsEqualGUID( &IID_IDirectPlayLobby, riid ) )
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment