- Add proper message reply mechanism and sp player data storage
- More implementation and fixes
diff --git a/dlls/dplayx/dpclassfactory.c b/dlls/dplayx/dpclassfactory.c
index 660aa3a..9a7546a 100644
--- a/dlls/dplayx/dpclassfactory.c
+++ b/dlls/dplayx/dpclassfactory.c
@@ -77,7 +77,7 @@
/*******************************************************************************
- * DPLAYX_DllGetClassObject [DPLAYX.?]
+ * DPLAYX_DllGetClassObject [DPLAYX.11]
* Retrieves DP or DPL class object from a DLL object
*
* NOTES
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c
index 63c3a58..3ead55c 100644
--- a/dlls/dplayx/dplay.c
+++ b/dlls/dplayx/dplay.c
@@ -160,6 +160,8 @@
( 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 @@
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 @@
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 @@
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 @@
}
/* *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 @@
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 @@
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 @@
/* FIXME: Should we validate the dwFlags? */
lpGData->dwFlags = dwFlags;
+ TRACE( "Created group id 0x%08lx\n", *lpid );
+
return lpGData;
}
@@ -968,6 +949,7 @@
if( DPID_SYSTEM_GROUP == *lpidGroup )
{
This->dp2->lpSysGroup = lpGData;
+ TRACE( "Inserting system group\n" );
}
else
{
@@ -1149,6 +1131,11 @@
}
}
+ /* Initialize the SP data section */
+ lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
+
+ TRACE( "Created player id 0x%08lx\n", *lpid );
+
return lpPData;
}
@@ -1325,6 +1312,7 @@
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 @@
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 @@
}
else
{
- hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer );
+ hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
if( FAILED(hr) )
{
@@ -1376,6 +1393,7 @@
*/
}
+ /* FIXME: Should we be storing these dwFlags or the creation ones? */
lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
hEvent, bAnsi );
@@ -1406,28 +1424,15 @@
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 @@
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 @@
hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
}
+#endif
return hr;
}
@@ -2055,7 +2072,8 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
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 @@
continue;
}
+ TRACE( "Loading %s\n", returnBuffer );
return LoadLibraryA( returnBuffer );
}
}
@@ -3917,18 +3943,17 @@
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 */
+ const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
+ BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
- ICOM_THIS(IDirectPlay3Impl,iface);
-
- 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 @@
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 @@
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 @@
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 @@
};
#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 @@
}
/***************************************************************************
- * DirectPlayEnumerateW (DPLAYX.3)
+ * DirectPlayEnumerateW [DPLAYX.3]
*
*/
HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
@@ -5027,7 +5104,7 @@
/***************************************************************************
- * DirectPlayCreate (DPLAYX.1) (DPLAY.1)
+ * DirectPlayCreate [DPLAYX.1][DPLAY.1]
*
*/
HRESULT WINAPI DirectPlayCreate
@@ -5044,7 +5121,6 @@
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 )
diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h
index 0cfc5f5..b7daa74 100644
--- a/dlls/dplayx/dplay_global.h
+++ b/dlls/dplayx/dplay_global.h
@@ -35,6 +35,21 @@
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 @@
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 @@
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 @@
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 */
diff --git a/dlls/dplayx/dplaysp.c b/dlls/dplayx/dplaysp.c
index 2a21a01..b1a8a18 100644
--- a/dlls/dplayx/dplaysp.c
+++ b/dlls/dplayx/dplaysp.c
@@ -26,7 +26,6 @@
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 @@
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 @@
/* 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 @@
*/
/* 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 @@
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 @@
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 @@
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 @@
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 @@
}
/* 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 @@
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 @@
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 @@
break;
}
-
- default:
- FIXME( "Unknown Command of %u and size 0x%08lx\n",
- lpMsg->wCommandId, dwMessageBodySize );
}
#if 0
@@ -736,22 +779,40 @@
DWORD dwFlags
)
{
+ HRESULT hr;
+ LPDP_SPPLAYERDATA lpPlayerEntry;
+ LPVOID lpPlayerData;
+
ICOM_THIS(IDirectPlaySPImpl,iface);
- /* FIXME: I'm not sure if this stuff should be associated with the DPlay
- * player lists. How else would this stuff get deleted?
- */
-
- 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 @@
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 @@
/* 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 @@
{
*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 @@
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 @@
/* 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 @@
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 ) );
+}
+
diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c
index 4f63d01..0d24d3c 100644
--- a/dlls/dplayx/dplayx_messages.c
+++ b/dlls/dplayx/dplayx_messages.c
@@ -27,8 +27,11 @@
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 @@
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 @@
LPVOID lpMsg;
LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
DWORD dwMsgSize;
- DWORD dwWaitReturn;
HRESULT hr = DP_OK;
dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
@@ -156,19 +194,16 @@
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 @@
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;
- }
+ DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY,
+ &lpMsg, &dwMsgSize );
}
- dwWaitReturn = WaitForSingleObject( This->dp2->hMsgReceipt, 30000 );
- if( dwWaitReturn != WAIT_OBJECT_0 )
- {
- ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
- hr = DPERR_TIMEOUT;
- }
-
- 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 @@
/* 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 );
-#endif
-
- HeapFree( GetProcessHeap(), 0, This->dp2->lpMsgReceived );
- This->dp2->lpMsgReceived = NULL;
+ HeapFree( GetProcessHeap(), 0, lpMsg );
}
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 DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer )
{
- HRESULT hr;
- DPSP_SENDDATA data;
+ LPVOID lpMsg;
+ LPDPMSG_FORWARDADDPLAYER lpMsgBody;
+ DWORD dwMsgSize;
+ HRESULT hr = DP_OK;
- 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;
+ dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
- hr = (*This->dp2->spData.lpCB->Send)( &data );
+ 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
+
+ /* 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 open stream send failed: %s\n",
- DPLAYX_HresultToString( hr ) );
+ ERR( "Request for new playerID send failed: %s\n",
+ DPLAYX_HresultToString( hr ) );
+ return NULL;
}
- /* FIXME: hack to give some time for channel to open */
- SleepEx( 1000 /* 1 sec */, FALSE );
+ dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime );
+ if( dwWaitReturn != WAIT_OBJECT_0 )
+ {
+ ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
+ return NULL;
+ }
- return hr;
+ /* Clean Up */
+ return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyMsg, lpdwMsgBodySize );
}
+
+/* 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 )
+{
+ LPDP_MSG_REPLY_STRUCT_LIST lpReplyList;
+
+#if 0
+ if( wCommandId == DPMSGCMD_FORWARDADDPLAYER )
+ {
+ DebugBreak();
+ }
+#endif
+
+ /* 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( lpReplyList != NULL )
+ {
+ 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();
+ }
+
+}
+
+void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
+ LPCVOID lpMsgBody, DWORD dwMsgBodySize )
+{
+ LPCDPMSG_FORWARDADDPLAYERNACK lpcErrorMsg;
+
+ lpcErrorMsg = (LPCDPMSG_FORWARDADDPLAYERNACK)lpMsgBody;
+
+ ERR( "Received error message %u. Error is %s\n",
+ wCommandId, DPLAYX_HresultToString( lpcErrorMsg->errorCode) );
+ DebugBreak();
+}
+
diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h
index c1812d6..6c0dd61 100644
--- a/dlls/dplayx/dplayx_messages.h
+++ b/dlls/dplayx/dplayx_messages.h
@@ -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 @@
/* 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 @@
#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 @@
/* 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 @@
} 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 @@
} 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 @@
} 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 @@
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;
+typedef struct tagDPMSG_FORWARDADDPLAYER
+{
+ DPMSG_SENDENVELOPE envelope;
+
+ DWORD unknown; /* 0 */
+
+ 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 }
+
+ 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"
-
-HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
- LPDPID lpdipidAllocatedId );
-
-/* FIXME: I don't think that this is a needed method */
-HRESULT DP_MSG_OpenStream( IDirectPlay2AImpl* This );
-
-
#endif
diff --git a/dlls/dplayx/dplobby.c b/dlls/dplayx/dplobby.c
index 3a451fe..c1340c4 100644
--- a/dlls/dplayx/dplobby.c
+++ b/dlls/dplayx/dplobby.c
@@ -343,15 +343,15 @@
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 ) )
{