- More implementation
- Should be able to enumerate sessions anywhere with at least tcp/ip
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c
index 7f9ccf0..cec6ac4 100644
--- a/dlls/dplayx/dplay.c
+++ b/dlls/dplayx/dplay.c
@@ -45,13 +45,15 @@
LPVOID lpData, DWORD dwDataSize );
static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
-static BOOL cbDeletePlayerFromAllGroups( DPID dpId, DWORD dwPlayerType,
- LPCDPNAME lpName, DWORD dwFlags,
- LPVOID lpContext );
+static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
+ DWORD dwPlayerType,
+ LPCDPNAME lpName,
+ DWORD dwFlags,
+ LPVOID lpContext );
static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
-static BOOL cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
- LPCDPNAME lpName, DWORD dwFlags,
- LPVOID lpContext );
+static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
+ LPCDPNAME lpName, DWORD dwFlags,
+ LPVOID lpContext );
static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
/* Helper methods for player/group interfaces */
@@ -152,9 +154,21 @@
static HRESULT WINAPI DP_IF_GetGroupParent
( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
BOOL bAnsi );
+static HRESULT WINAPI DP_IF_GetCaps
+ ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
+static HRESULT WINAPI DP_IF_EnumSessions
+ ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
+ LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
+ LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
+static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
+ LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
+ DWORD dwFlags, LPVOID lpContext );
+
static inline DPID DP_NextObjectId(void);
+static DPID DP_GetRemoteNextObjectId(void);
+
static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
@@ -309,6 +323,30 @@
CloseHandle( This->dp2->hEnumSessionThread );
}
+ /* Finish with the SP - have it shutdown */
+ if( This->dp2->spData.lpCB->ShutdownEx )
+ {
+ DPSP_SHUTDOWNDATA data;
+
+ TRACE( "Calling SP ShutdownEx\n" );
+
+ data.lpISP = This->dp2->spData.lpISP;
+
+ (*This->dp2->spData.lpCB->ShutdownEx)( &data );
+ }
+ else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
+ {
+ TRACE( "Calling obsolete SP Shutdown\n" );
+ (*This->dp2->spData.lpCB->Shutdown)();
+ }
+
+ /* Unload the SP */
+ if( This->dp2->hServiceProvider != 0 )
+ {
+ FreeLibrary( This->dp2->hServiceProvider );
+ }
+
+
#if 0
DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
@@ -574,6 +612,82 @@
return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
}
+/* *lplpReply will be non NULL iff there is something to reply */
+HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
+ DWORD dwMessageBodySize, LPCVOID lpMessageHeader,
+ WORD wCommandId, WORD wVersion,
+ LPVOID* lplpReply, LPDWORD lpdwMsgSize )
+{
+ TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
+ This, lpMessageBody, dwMessageBodySize, lpMessageHeader, wCommandId,
+ wVersion );
+
+ switch( wCommandId )
+ {
+ case DPMSGCMD_REQUESTNEWPLAYERID:
+ {
+#if 0
+ LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
+ (LPCDPMSG_REQUESTNEWPLAYERID)lpMessageBody;
+#endif
+ LPDPMSG_NEWPLAYERIDREPLY lpReply;
+
+ *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
+
+ *lplpReply = (LPDPMSG_NEWPLAYERIDREPLY)HeapAlloc( GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ *lpdwMsgSize );
+
+ FIXME( "Ignoring dwFlags in msg\n" );
+
+ /* Setup the reply */
+ lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
+ This->dp2->spData.dwSPHeaderSize );
+
+ lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
+ lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
+ lpReply->envelope.wVersion = DPMSGVER_DP6;
+
+#if 0
+ /* FIXME: Need to know the proper contents of the message! */
+ lpReply->dpidNewPlayerId = DP_NextObjectId();
+#endif
+
+ break;
+ }
+
+ case DPMSGCMD_NEWPLAYERIDREPLY:
+ {
+
+ DebugBreak();
+
+ 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\n" );
+ }
+
+ break;
+ }
+
+ default:
+ {
+ FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
+ break;
+ }
+ }
+
+ return DP_OK;
+}
+
static HRESULT WINAPI DP_IF_AddPlayerToGroup
( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
@@ -607,6 +721,7 @@
}
/* Add the shortcut */
+ lpPList->lpPData->uRef++;
lpNewPList->lpPData = lpPList->lpPData;
/* Add the player to the list of players for this group */
@@ -623,7 +738,7 @@
data.idGroup = idGroup;
data.lpISP = This->dp2->spData.lpISP;
- (This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
+ (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
}
/* Inform all other peers of the addition of player to the group. If there are
@@ -668,7 +783,7 @@
{
HRESULT hr = DP_OK;
- FIXME("(%p)->(%u): stub\n", This, bAnsi );
+ TRACE("(%p)->(%u)\n", This, bAnsi );
/* FIXME: Need to find a new host I assume (how?) */
/* FIXME: Need to destroy all local groups */
@@ -683,38 +798,16 @@
data.lpISP = This->dp2->spData.lpISP;
- hr = (This->dp2->spData.lpCB->CloseEx)( &data );
+ hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
}
else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
{
TRACE( "Calling SP Close (obsolete interface)\n" );
- hr = (This->dp2->spData.lpCB->Close)();
+ hr = (*This->dp2->spData.lpCB->Close)();
}
- /* Even if the SP close failed, we should press on... */
-
- /* Invoke the SP callback to inform the SP we don't need it any more */
- if( This->dp2->spData.lpCB->ShutdownEx )
- {
- DPSP_SHUTDOWNDATA data;
-
- TRACE( "Calling SP ShutdownEx\n" );
-
- data.lpISP = This->dp2->spData.lpISP;
-
- hr = (This->dp2->spData.lpCB->ShutdownEx)( &data );
- }
- else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
- {
- TRACE( "Calling obsolete SP Shutdown\n" );
- hr = (This->dp2->spData.lpCB->Shutdown)();
- }
-
- /* Unload the service provider now that we've stoped it */
- FreeLibrary( This->dp2->hServiceProvider );
-
return hr;
}
@@ -781,6 +874,12 @@
return;
}
+ if( --(lpGList->lpGData->uRef) )
+ {
+ FIXME( "Why is this not the last reference to group?\n" );
+ DebugBreak();
+ }
+
/* Delete player */
DP_DeleteDPNameStruct( &lpGList->lpGData->name );
HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
@@ -804,6 +903,11 @@
{
DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
}
+
+ if( lpGroups == NULL )
+ {
+ return NULL;
+ }
return lpGroups->lpGData;
}
@@ -831,11 +935,7 @@
}
else
{
- /* Request the id from the name server */
- FIXME( "Request id from NS for group\n" );
-
- /* Hack for now */
- *lpidGroup = DP_NextObjectId();
+ *lpidGroup = DP_GetRemoteNextObjectId();
}
}
@@ -862,6 +962,9 @@
DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
}
+ /* Something is now referencing this data */
+ lpGData->uRef++;
+
/* Set all the important stuff for the group */
DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
@@ -891,7 +994,7 @@
data.lpSPMessageHeader = lpMsgHdr;
data.lpISP = This->dp2->spData.lpISP;
- (This->dp2->spData.lpCB->CreateGroup)( &data );
+ (*This->dp2->spData.lpCB->CreateGroup)( &data );
}
/* Inform all other peers of the creation of a new group. If there are
@@ -989,12 +1092,7 @@
}
-/* This function will just create the storage for the new player.
- * In the future it may want to intialize, but for the time being
- * that will be done seperately.
- *
- * If *lpid == DPID_UNKNOWN then assign the next available player
- */
+/* This function will just create the storage for the new player. */
static
lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
LPDPNAME lpName, DWORD dwFlags,
@@ -1048,26 +1146,33 @@
static void
DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
{
- lpPlayerList lpPlayers;
+ lpPlayerList lpPList;
TRACE( "(%p)->(0x%08lx)\n", This, dpid );
- DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
+ DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
- if( lpPlayers == NULL )
+ if( lpPList == NULL )
{
ERR( "DPID 0x%08lx not found\n", dpid );
return;
}
+
+ /* Verify that this is the last reference to the data */
+ if( --(lpPList->lpPData->uRef) )
+ {
+ FIXME( "Why is this not the last reference to player?\n" );
+ DebugBreak();
+ }
/* Delete player */
- DP_DeleteDPNameStruct( &lpPlayers->lpPData->name );
+ DP_DeleteDPNameStruct( &lpPList->lpPData->name );
- CloseHandle( lpPlayers->lpPData->hEvent );
- HeapFree( GetProcessHeap(), 0, lpPlayers->lpPData );
+ CloseHandle( lpPList->lpPData->hEvent );
+ HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
/* Delete Player List object */
- HeapFree( GetProcessHeap(), 0, lpPlayers );
+ HeapFree( GetProcessHeap(), 0, lpPList );
}
static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
@@ -1236,11 +1341,13 @@
}
else
{
- /* Request the id from the name server */
- FIXME( "Request id from NS for new player\n" );
+ HRESULT hr = DP_MSG_SendRequestPlayerId( This, dwFlags, lpidPlayer );
- /* Hack for now */
- *lpidPlayer = DP_NextObjectId();
+ if( FAILED(hr) )
+ {
+ ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
+ return hr;
+ }
}
}
else
@@ -1258,9 +1365,6 @@
return DPERR_CANTADDPLAYER;
}
- /* Update the information and send it to all players in the session */
- DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
-
/* Create the list object and link it in */
lpPList = (lpPlayerList)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( *lpPList ) );
@@ -1270,10 +1374,14 @@
return DPERR_CANTADDPLAYER;
}
+ lpPData->uRef = 1;
lpPList->lpPData = lpPData;
+ /* Add the player to the system group */
DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
+ /* Update the information and send it to all players in the session */
+ DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
/* Let the SP know that we've created this player */
if( This->dp2->spData.lpCB->CreatePlayer )
@@ -1301,19 +1409,9 @@
data.lpSPMessageHeader = lpMsgHdr;
data.lpISP = This->dp2->spData.lpISP;
- (This->dp2->spData.lpCB->CreatePlayer)( &data );
+ (*This->dp2->spData.lpCB->CreatePlayer)( &data );
}
- /* FIXME: The native version adds everything to group 0 (similar to
- * the player queue that we have. I think that the native
- * service providers rely on this fact.
- * NOTE: The lpMsgHdr is always non NULL because there is no requirement to
- * broadcast this information since every node will automatically
- * do it.
- */
- DP_IF_AddPlayerToGroup( This, NULL, DPID_NOPARENT_GROUP,
- *lpidPlayer, bAnsi );
-
/* 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.
@@ -1345,7 +1443,8 @@
}
static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
- ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+ ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
+ HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
{
ICOM_THIS(IDirectPlay2Impl,iface);
@@ -1363,7 +1462,8 @@
}
static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
- ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
+ ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
+ HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
{
ICOM_THIS(IDirectPlay2Impl,iface);
@@ -1380,6 +1480,14 @@
lpData, dwDataSize, dwFlags, FALSE );
}
+static DPID DP_GetRemoteNextObjectId(void)
+{
+ FIXME( ":stub\n" );
+
+ /* Hack solution */
+ return DP_NextObjectId();
+}
+
static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
DPID idPlayer, BOOL bAnsi )
@@ -1412,6 +1520,9 @@
return DPERR_INVALIDPLAYER;
}
+ /* One less reference */
+ lpPList->lpPData->uRef--;
+
/* Delete the Player List element */
HeapFree( GetProcessHeap(), 0, lpPList );
@@ -1426,7 +1537,7 @@
data.idGroup = idGroup;
data.lpISP = This->dp2->spData.lpISP;
- hr = (This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
+ hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
}
/* Need to send a DELETEPLAYERFROMGROUP message */
@@ -1451,12 +1562,12 @@
typedef struct _DPRGOPContext
{
- LPDIRECTPLAY3 iface;
- BOOL bAnsi;
- DPID idGroup;
+ IDirectPlay3Impl* This;
+ BOOL bAnsi;
+ DPID idGroup;
} DPRGOPContext, *lpDPRGOPContext;
-static BOOL
+static BOOL CALLBACK
cbRemoveGroupOrPlayer(
DPID dpId,
DWORD dwPlayerType,
@@ -1471,8 +1582,8 @@
if( dwPlayerType == DPPLAYERTYPE_GROUP )
{
- if( FAILED( IDirectPlayX_DeleteGroupFromGroup( lpCtxt->iface,
- lpCtxt->idGroup, dpId )
+ if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
+ dpId )
)
)
{
@@ -1482,8 +1593,9 @@
}
else
{
- if( FAILED( IDirectPlayX_DeletePlayerFromGroup( lpCtxt->iface,
- lpCtxt->idGroup, dpId )
+ if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
+ NULL, lpCtxt->idGroup,
+ dpId, lpCtxt->bAnsi )
)
)
{
@@ -1510,27 +1622,28 @@
return DPERR_INVALIDPLAYER; /* yes player */
}
- context.iface = (LPDIRECTPLAY3)This;
+ context.This = (IDirectPlay3Impl*)This;
context.bAnsi = bAnsi;
context.idGroup = idGroup;
- /* Remove all links to groups that this group has since this is dp3 */
- IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)This, idGroup, NULL,
- cbRemoveGroupOrPlayer, (LPVOID)&context, 0 );
-
- /* FIXME: Is it allowed to delete a sub group with a parent? Must be */
- if( lpGData->parent != DPID_SYSTEM_GROUP )
- {
- IDirectPlayX_DeleteGroupFromGroup( (LPDIRECTPLAY3A)This,
- lpGData->parent,
- idGroup );
- }
-
/* Remove all players that this group has */
- IDirectPlayX_EnumGroupPlayers( (LPDIRECTPLAY3A)This, idGroup, NULL,
- cbRemoveGroupOrPlayer, (LPVOID)&context, 0 );
+ DP_IF_EnumGroupPlayers( This, idGroup, NULL,
+ cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
- /* Now delete this group data and list */
+ /* Remove all links to groups that this group has since this is dp3 */
+ DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
+ cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
+
+ /* Remove this group from the parent group - if it has one */
+ if( ( idGroup != DPID_SYSTEM_GROUP ) &&
+ ( lpGData->parent != DPID_SYSTEM_GROUP )
+ )
+ {
+ DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
+ idGroup );
+ }
+
+ /* Now delete this group data and list from the system group */
DP_DeleteGroup( This, idGroup );
/* Let the SP know that we've destroyed this group */
@@ -1544,7 +1657,7 @@
data.dwFlags = 0;
data.lpISP = This->dp2->spData.lpISP;
- (This->dp2->spData.lpCB->DeleteGroup)( &data );
+ (*This->dp2->spData.lpCB->DeleteGroup)( &data );
}
FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
@@ -1568,8 +1681,9 @@
typedef struct _DPFAGContext
{
- LPDIRECTPLAY2 iface;
- DPID idPlayer;
+ IDirectPlay2Impl* This;
+ DPID idPlayer;
+ BOOL bAnsi;
} DPFAGContext, *lpDPFAGContext;
static HRESULT WINAPI DP_IF_DestroyPlayer
@@ -1587,15 +1701,16 @@
/* FIXME: If the player is remote, we must be the host to delete this */
- cbContext.iface = (LPDIRECTPLAY2)This;
+ cbContext.This = This;
cbContext.idPlayer = idPlayer;
+ cbContext.bAnsi = bAnsi;
/* Find each group and call DeletePlayerFromGroup if the player is a
member of the group */
- IDirectPlayX_EnumGroups( (LPDIRECTPLAY2)This, NULL, cbDeletePlayerFromAllGroups,
- (LPVOID)&cbContext, DPENUMGROUPS_ALL);
+ DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
+ (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
- /* Now delete player and player list */
+ /* Now delete player and player list from the sys group */
DP_DeletePlayer( This, idPlayer );
/* Let the SP know that we've destroyed this group */
@@ -1609,7 +1724,7 @@
data.dwFlags = 0;
data.lpISP = This->dp2->spData.lpISP;
- (This->dp2->spData.lpCB->DeletePlayer)( &data );
+ (*This->dp2->spData.lpCB->DeletePlayer)( &data );
}
FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
@@ -1617,7 +1732,7 @@
return DP_OK;
}
-static BOOL
+static BOOL CALLBACK
cbDeletePlayerFromAllGroups(
DPID dpId,
DWORD dwPlayerType,
@@ -1629,13 +1744,18 @@
if( dwPlayerType == DPPLAYERTYPE_GROUP )
{
- IDirectPlayX_DeletePlayerFromGroup( lpCtxt->iface, lpCtxt->idPlayer, dpId );
+ DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
+ lpCtxt->bAnsi );
- /* Enumerate all groups in this group - yes this is pseudo recursive */
- IDirectPlayX_EnumGroupsInGroup( (LPDIRECTPLAY3A)lpCtxt->iface, /*FIXME*/
- dpId, NULL,
- cbDeletePlayerFromAllGroups,
- lpContext, DPENUMGROUPS_ALL );
+ /* Enumerate all groups in this group since this will normally only
+ * be called for top level groups
+ */
+ DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
+ dpId, NULL,
+ cbDeletePlayerFromAllGroups,
+ (LPVOID)lpContext, DPENUMGROUPS_ALL,
+ lpCtxt->bAnsi );
+
}
else
{
@@ -1806,10 +1926,11 @@
/* This function should call the registered callback function that the user
passed into EnumSessions for each entry available.
*/
-static void DP_InvokeEnumSessionCallbacksA( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
- LPVOID lpNSInfo,
- DWORD dwTimeout,
- LPVOID lpContext )
+static void DP_InvokeEnumSessionCallbacks
+ ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
+ LPVOID lpNSInfo,
+ DWORD dwTimeout,
+ LPVOID lpContext )
{
LPDPSESSIONDESC2 lpSessionDesc;
@@ -1832,33 +1953,6 @@
lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
}
-static void DP_InvokeEnumSessionCallbacksW( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
- LPVOID lpNSInfo,
- DWORD dwTimeout,
- LPVOID lpContext )
-{
- LPDPSESSIONDESC2 lpSessionDesc;
-
- FIXME( ": not checking for conditions\n" );
-
- NS_ResetSessionEnumeration( lpNSInfo );
-
- /* Enumerate all sessions */
- /* FIXME: Need to indicate UNICODE */
- while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
- {
- TRACE( "EnumSessionsCallback2 invoked\n" );
- if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
- {
- return;
- }
- }
-
- /* Invoke one last time to indicate that there is no more to come */
- lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
-
-}
-
static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
{
EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
@@ -1869,9 +1963,7 @@
for( ;; )
{
- NS_SendSessionRequestBroadcast( &data->requestGuid,
- data->dwEnumSessionFlags,
- data->lpSpData );
+ HRESULT hr;
/* Sleep up to dwTimeout waiting for request to terminate thread */
if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
@@ -1879,6 +1971,18 @@
TRACE( "Thread terminating on terminate request\n" );
break;
}
+
+ /* Now resend the enum request */
+ hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
+ data->dwEnumSessionFlags,
+ data->lpSpData );
+
+ if( FAILED(hr) )
+ {
+ ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
+ /* FIXME: Should we kill this thread? How to inform the main thread? */
+ }
+
}
TRACE( "Thread terminating\n" );
@@ -1887,6 +1991,13 @@
CloseHandle( hSuicideRequest );
HeapFree( GetProcessHeap(), 0, lpContext );
+ /* FIXME: Need to have some notification to main app thread that this is
+ * dead. It would serve two purposes. 1) allow sync on termination
+ * so that we don't actually send something to ourselves when we
+ * become name server (race condition) and 2) so that if we die
+ * abnormally something else will be able to tell.
+ */
+
return 1;
}
@@ -1908,18 +2019,16 @@
}
}
-static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
- ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
+static HRESULT WINAPI DP_IF_EnumSessions
+ ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
- LPVOID lpContext, DWORD dwFlags )
+ LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
{
HRESULT hr = DP_OK;
- ICOM_THIS(IDirectPlay2Impl,iface);
- /* FIXME: Combine ANSI and UNICODE versions */
-
- TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx)\n",
- This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags );
+ TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx,%u)\n",
+ This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
+ bAnsi );
/* Can't enumerate if the interface is already open */
if( This->dp2->bConnectionOpen )
@@ -1933,7 +2042,7 @@
DPCAPS spCaps;
spCaps.dwSize = sizeof( spCaps );
- IDirectPlayX_GetCaps( iface, &spCaps, 0 );
+ DP_IF_GetCaps( This, &spCaps, 0 );
dwTimeout = spCaps.dwTimeout;
/* FIXME: If it's still 0, we need to provide the IP default */
@@ -1949,48 +2058,57 @@
if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
{
/* Enumerate everything presently in the local session cache */
- DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2,
- This->dp2->lpNameServerData, dwTimeout,
- lpContext );
+ DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
+ This->dp2->lpNameServerData, dwTimeout,
+ lpContext );
/* See if we've already created a thread to service this interface */
if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
{
DWORD dwThreadId;
- EnumSessionAsyncCallbackData* lpData
- = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- sizeof( *lpData ) );
- /* FIXME: need to kill the thread on object deletion */
- lpData->lpSpData = &This->dp2->spData;
- CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
- lpData->dwEnumSessionFlags = dwFlags;
- lpData->dwTimeout = dwTimeout;
- This->dp2->hKillEnumSessionThreadEvent =
- CreateEventA( NULL, TRUE, FALSE, NULL );
+ /* Send the first enum request inline since the user may cancel a dialog
+ * if one is presented. Also, may also have a connecting return code.
+ */
+ hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
+ dwFlags, &This->dp2->spData );
- if( !DuplicateHandle( GetCurrentProcess(),
- This->dp2->hKillEnumSessionThreadEvent,
- GetCurrentProcess(),
- &lpData->hSuicideRequest,
- 0, FALSE, DUPLICATE_SAME_ACCESS )
- )
+ if( !FAILED(hr) )
{
- ERR( "Can't duplicate thread killing handle\n" );
+ EnumSessionAsyncCallbackData* lpData
+ = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof( *lpData ) );
+ /* FIXME: need to kill the thread on object deletion */
+ lpData->lpSpData = &This->dp2->spData;
+ CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
+ lpData->dwEnumSessionFlags = dwFlags;
+ lpData->dwTimeout = dwTimeout;
+
+ This->dp2->hKillEnumSessionThreadEvent =
+ CreateEventA( NULL, TRUE, FALSE, NULL );
+
+ if( !DuplicateHandle( GetCurrentProcess(),
+ This->dp2->hKillEnumSessionThreadEvent,
+ GetCurrentProcess(),
+ &lpData->hSuicideRequest,
+ 0, FALSE, DUPLICATE_SAME_ACCESS )
+ )
+ {
+ ERR( "Can't duplicate thread killing handle\n" );
+ }
+
+ TRACE( ": creating EnumSessionsRequest thread\n" );
+
+ This->dp2->hEnumSessionThread = CreateThread( NULL,
+ 0,
+ DP_EnumSessionsSendAsyncRequestThread,
+ lpData,
+ 0,
+ &dwThreadId );
}
-
- TRACE( ": creating EnumSessionsRequest thread\n" );
-
- This->dp2->hEnumSessionThread = CreateThread( NULL,
- 0,
- DP_EnumSessionsSendAsyncRequestThread,
- lpData,
- 0,
- &dwThreadId );
- }
-
+ }
}
else
{
@@ -2005,116 +2123,32 @@
SleepEx( dwTimeout, FALSE );
- DP_InvokeEnumSessionCallbacksA( lpEnumSessionsCallback2,
- This->dp2->lpNameServerData, dwTimeout, lpContext );
+ DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
+ This->dp2->lpNameServerData, dwTimeout,
+ lpContext );
}
return hr;
}
+static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
+ ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
+ LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
+ LPVOID lpContext, DWORD dwFlags )
+{
+ ICOM_THIS(IDirectPlay2Impl,iface);
+ return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
+ lpContext, dwFlags, TRUE );
+}
+
static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
LPVOID lpContext, DWORD dwFlags )
{
- HRESULT hr = DP_OK;
ICOM_THIS(IDirectPlay2Impl,iface);
-
- TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx)\n",
- This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags );
-
- /* Can't enumerate if the interface is already open */
- if( This->dp2->bConnectionOpen )
- {
- return DPERR_GENERIC;
- }
-
- /* Use the service provider default? */
- if( dwTimeout == 0 )
- {
- DPCAPS spCaps;
- spCaps.dwSize = sizeof( spCaps );
-
- IDirectPlayX_GetCaps( iface, &spCaps, 0 );
- dwTimeout = spCaps.dwTimeout;
- }
-
- /* FIXME: Interface locking ... */
-
- if( dwFlags & DPENUMSESSIONS_STOPASYNC )
- {
- DP_KillEnumSessionThread( This );
-
- return hr;
- }
-
- /* FIXME: Interface locking sucks in this method */
-
- if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
- {
- /* Enumerate everything presently in the local session cache */
- DP_InvokeEnumSessionCallbacksW( lpEnumSessionsCallback2,
- This->dp2->lpNameServerData,
- dwTimeout, lpContext );
-
- /* See if we've already created a thread to service this interface */
- if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
- {
- DWORD dwThreadId;
-
- EnumSessionAsyncCallbackData* lpData
- = (EnumSessionAsyncCallbackData*)HeapAlloc( GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- sizeof( *lpData ) );
- /* FIXME: need to kill the thread on object deletion */
- lpData->lpSpData = &This->dp2->spData;
- CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
- lpData->dwEnumSessionFlags = dwFlags;
- lpData->dwTimeout = dwTimeout;
-
- This->dp2->hKillEnumSessionThreadEvent =
- CreateEventA( NULL, TRUE, FALSE, NULL );
-
- if( !DuplicateHandle( GetCurrentProcess(),
- This->dp2->hKillEnumSessionThreadEvent,
- GetCurrentProcess(),
- &lpData->hSuicideRequest,
- 0, FALSE, DUPLICATE_SAME_ACCESS )
- )
- {
- ERR( "Can't duplicate thread killing handle\n" );
- }
-
-
- TRACE( ": creating EnumSessionsRequest thread\n" );
-
- This->dp2->hEnumSessionThread = CreateThread( NULL,
- 0,
- DP_EnumSessionsSendAsyncRequestThread,
- lpData,
- 0,
- &dwThreadId );
- }
-
- }
- else
- {
- /* Invalidate the session cache for the interface */
- NS_InvalidateSessionCache( This->dp2->lpNameServerData );
-
- /* Send the broadcast for session enumeration */
- hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
- dwFlags,
- &This->dp2->spData );
-
- SleepEx( dwTimeout, FALSE );
-
- DP_InvokeEnumSessionCallbacksW( lpEnumSessionsCallback2,
- This->dp2->lpNameServerData,
- dwTimeout, lpContext );
- }
-
- return hr;
+ return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
+ lpContext, dwFlags, FALSE );
}
static HRESULT WINAPI DP_IF_GetPlayerCaps
@@ -2131,22 +2165,27 @@
data.lpCaps = lpDPCaps;
data.lpISP = This->dp2->spData.lpISP;
- return (This->dp2->spData.lpCB->GetCaps)( &data );
+ return (*This->dp2->spData.lpCB->GetCaps)( &data );
}
+static HRESULT WINAPI DP_IF_GetCaps
+ ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
+{
+ return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
+}
static HRESULT WINAPI DirectPlay2AImpl_GetCaps
( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
{
ICOM_THIS(IDirectPlay2Impl,iface);
- return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
+ return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
}
static HRESULT WINAPI DirectPlay2WImpl_GetCaps
( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
{
ICOM_THIS(IDirectPlay2Impl,iface);
- return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
+ return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
}
static HRESULT WINAPI DP_IF_GetGroupData
@@ -2605,11 +2644,16 @@
data.dwOpenFlags = dwFlags;
data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
- hr = (This->dp2->spData.lpCB->Open)(&data);
+ hr = (*This->dp2->spData.lpCB->Open)(&data);
+ if( FAILED( hr ) )
+ {
+ ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
+ return hr;
+ }
}
-
+
{
- /* FIXME: DPLAY creates this after the name server... */
+ /* Create the system group of which everything is a part of */
DPID systemGroup = DPID_SYSTEM_GROUP;
hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
@@ -2630,7 +2674,8 @@
* message is directed to.
*/
hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
- 0, DPPLAYER_SERVERPLAYER, bAnsi );
+ 0,
+ DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
}
else if( dwFlags & DPOPEN_CREATE )
{
@@ -3138,6 +3183,7 @@
}
/* Add the shortcut */
+ lpGData->uRef++;
lpNewGList->lpGData = lpGData;
/* Add the player to the list of players for this group */
@@ -3191,6 +3237,9 @@
{
return DPERR_CANTADDPLAYER; /* yes player not group */
}
+
+ /* Something else is referencing this data */
+ lpGData->uRef++;
DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
@@ -3220,7 +3269,7 @@
data.lpSPMessageHeader = lpMsgHdr;
data.lpISP = This->dp2->spData.lpISP;
- (This->dp2->spData.lpCB->CreateGroup)( &data );
+ (*This->dp2->spData.lpCB->CreateGroup)( &data );
}
/* Inform all other peers of the creation of a new group. If there are
@@ -3300,6 +3349,9 @@
return DPERR_INVALIDGROUP;
}
+ /* Decrement the ref count */
+ lpGList->lpGData->uRef--;
+
/* Free up the list item */
HeapFree( GetProcessHeap(), 0, lpGList );
@@ -3869,9 +3921,6 @@
return DPERR_UNAVAILABLE;
}
- /* NOTE: This will crash until I know what parameters/interface this has */
- /* The first parameter is a pointer to memory which is written to... */
-
TRACE( "Calling SPInit\n" );
hr = (*SPInit)( &This->dp2->spData );
@@ -4136,7 +4185,7 @@
{
bValidDestination = TRUE;
- /* Have the servie provider send this message */
+ /* Have the service provider send this message */
/* FIXME: Could optimize for local interface sends */
return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
dwTimeout, lpContext, lpdwMsgID );
@@ -4161,6 +4210,21 @@
{
FIXME( "Send to all players using EnumPlayersInGroup\n" );
}
+
+#if 0
+ if( bExpectReply )
+ {
+ DWORD dwWaitReturn;
+
+ This->dp2->hReplyEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
+
+ dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
+ if( dwWaitReturn != WAIT_OBJECT_0 )
+ {
+ ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
+ }
+ }
+#endif
}
if( !bValidDestination )
@@ -4202,38 +4266,18 @@
{
LPDPMSG lpMElem;
- FIXME( ": stub - wont work for multi process\n" );
+ FIXME( ": stub\n" );
- /* FIXME: Need to send the passed message inside another message type
- * I think. System message - but what is the format?
- */
+ /* FIXME: This queuing should only be for async messages */
- /* OK. Let's run a nasty hack to bypass the fact that we don't yet know
- how to initialize the service provider. The hack will place the message
- to be sent automatically into the send queue. There will
- be nothing put into the send queue. In reality we should be calling
- the service provider and only putting things into the send queue if
- the service provider can't immediately accept/send it.
- NOTE: Two hacks are provided. The first is only for a single process,
- the second is a start towards a allowing sharing across the whole
- computer (it requires some way of signalling that there's a message
- available).
- */
-
-#ifdef SP_MULTIPROCESS_SEND_HACK
- lpMElem = (LPDPMSG)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
- sizeof( *lpMElem ) );
- lpMElem->msg = (DPMSG_GENERIC*)DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
- dwDataSize );
-#else
lpMElem = (LPDPMSG)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( *lpMElem ) );
lpMElem->msg = (DPMSG_GENERIC*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
dwDataSize );
-#endif
CopyMemory( lpMElem->msg, lpData, dwDataSize );
+ /* FIXME: Need to queue based on priority */
DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
return DP_OK;
@@ -4266,7 +4310,7 @@
data.lpdwNumMsgs = lpdwNumMsgs;
data.lpdwNumBytes = lpdwNumBytes;
- hr = (This->dp2->spData.lpCB->GetMessageQueue)( &data );
+ hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
}
else
{
@@ -4318,7 +4362,7 @@
data.dwMinPriority = dwMinPriority;
data.dwMaxPriority = dwMaxPriority;
- hr = (This->dp2->spData.lpCB->Cancel)( &data );
+ hr = (*This->dp2->spData.lpCB->Cancel)( &data );
}
else
{
@@ -4900,7 +4944,7 @@
} CreateEnumData, *lpCreateEnumData;
/* Find and copy the matching connection for the SP guid */
-BOOL CALLBACK cbDPCreateEnumConnections(
+static BOOL CALLBACK cbDPCreateEnumConnections(
LPCGUID lpguidSP,
LPVOID lpConnection,
DWORD dwConnectionSize,
diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h
index 8547568..0cfc5f5 100644
--- a/dlls/dplayx/dplay_global.h
+++ b/dlls/dplayx/dplay_global.h
@@ -43,6 +43,8 @@
DPNAME name;
HANDLE hEvent;
+ ULONG uRef; /* What is the reference count on this data? */
+
/* View of local data */
LPVOID lpLocalData;
DWORD dwLocalDataSize;
@@ -68,6 +70,8 @@
/* Internal information */
DPID parent; /* If parent == 0 it's a top level group */
+ ULONG uRef; /* Reference count */
+
DPQ_HEAD(GroupList) groups; /* A group has [0..n] groups */
DPQ_HEAD(PlayerList) players; /* A group has [0..n] players */
@@ -117,12 +121,7 @@
BOOL bHostInterface; /* Did this interface create the session */
-#if 0
- DPQ_HEAD(PlayerList) players; /* All players w/ interface */
- DPQ_HEAD(GroupList) groups; /* All main groups w/ interface */
-#else
lpGroupData lpSysGroup; /* System group with _everything_ in it */
-#endif
LPDPSESSIONDESC2 lpSessionDesc;
@@ -137,6 +136,11 @@
HMODULE hServiceProvider;
BOOL bConnectionInitialized;
+
+
+ /* proof of concept for message reception */
+ HANDLE hMsgReceipt;
+ LPVOID lpMsgReceived;
} DirectPlay2Data;
typedef struct tagDirectPlay3Data
@@ -182,4 +186,11 @@
extern ICOM_VTABLE(IDirectPlay3) directPlay3WVT;
extern ICOM_VTABLE(IDirectPlay4) directPlay4WVT;
+
+HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpMessageBody,
+ DWORD dwMessageBodySize, LPCVOID lpMessageHeader,
+ WORD wCommandId, WORD wVersion,
+ LPVOID* lplpReply, LPDWORD lpdwMsgSize );
+
+
#endif /* __WINE_DPLAY_GLOBAL_INCLUDED */
diff --git a/dlls/dplayx/dplaysp.c b/dlls/dplayx/dplaysp.c
index 98962de..1148dc8 100644
--- a/dlls/dplayx/dplaysp.c
+++ b/dlls/dplayx/dplaysp.c
@@ -384,6 +384,8 @@
{
LPDPMSG_SENDENVELOPE lpMsg = (LPDPMSG_SENDENVELOPE)lpMessageBody;
HRESULT hr = DPERR_GENERIC;
+ WORD wCommandId;
+ WORD wVersion;
ICOM_THIS(IDirectPlaySPImpl,iface);
@@ -391,16 +393,20 @@
FIXME( "(%p)->(%p,0x%08lx,%p): mostly stub\n",
This, lpMessageBody, dwMessageBodySize, lpMessageHeader );
+ wCommandId = lpMsg->wCommandId;
+ wVersion = lpMsg->wVersion;
+
TRACE( "Incomming message has envelope of 0x%08lx, %u, %u\n",
- lpMsg->dwMagic, lpMsg->wCommandId, lpMsg->wVersion );
+ lpMsg->dwMagic, wCommandId, wVersion );
if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
{
- FIXME( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
+ ERR( "Unknown magic 0x%08lx!\n", lpMsg->dwMagic );
}
switch( lpMsg->wCommandId )
{
+ /* Name server needs to handle this request */
case DPMSGCMD_ENUMSESSIONSREQUEST:
{
DPSP_REPLYDATA data;
@@ -421,6 +427,7 @@
break;
}
+ /* Name server needs to handle this request */
case DPMSGCMD_ENUMSESSIONSREPLY:
{
NS_SetRemoteComputerAsNameServer( lpMessageHeader,
@@ -432,8 +439,43 @@
break;
}
+
+ case DPMSGCMD_NEWPLAYERIDREPLY:
+ case DPMSGCMD_REQUESTNEWPLAYERID:
+ {
+ DPSP_REPLYDATA data;
+
+ data.lpMessage = NULL;
+ 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 );
+
+ /* Do we want a reply? */
+ if( data.lpMessage != NULL )
+ {
+ HRESULT hr;
+
+ data.lpSPMessageHeader = lpMessageHeader;
+ data.idNameServer = 0;
+ data.lpISP = iface;
+
+ hr = (This->sp->dplay->dp2->spData.lpCB->Reply)( &data );
+
+ if( FAILED(hr) )
+ {
+ ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) );
+ }
+ }
+
+ break;
+ }
+
default:
- FIXME( "Unknown Command of %u\n", lpMsg->wCommandId );
+ FIXME( "Unknown Command of %u and size 0x%08lx\n",
+ lpMsg->wCommandId, dwMessageBodySize );
}
#if 0
@@ -443,10 +485,7 @@
/* FIXME: Need some sort of context for this callback. Need to determine
* how this is actually done with the SP
*/
- /* FIXME: Add in size checks for all messages to determine corrupt messages */ /* FIXME: Who needs to delete the message when done? */
- /* FIXME: Does this get invoked as soon as the message arrives, or as soon
- * as it's removed from the queue (or peeked in queue?)
- */
+ /* FIXME: Who needs to delete the message when done? */
switch( lpMsg->dwType )
{
case DPSYS_CREATEPLAYERORGROUP:
diff --git a/dlls/dplayx/dplaysp.h b/dlls/dplayx/dplaysp.h
index c2028f0..9072e30 100644
--- a/dlls/dplayx/dplaysp.h
+++ b/dlls/dplayx/dplaysp.h
@@ -331,7 +331,7 @@
/* This variable is exported from the DLL at ordinal 6 to be accessed by the
* SP directly
*/
-extern DWORD gdwDPlaySPRefCount;
+extern __declspec(dllimport) DWORD gdwDPlaySPRefCount;
#endif
diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c
index bc23ef2..c4a4ac0 100644
--- a/dlls/dplayx/dplayx_messages.c
+++ b/dlls/dplayx/dplayx_messages.c
@@ -11,8 +11,11 @@
#include "wingdi.h"
#include "winuser.h"
+#include "winerror.h"
#include "dplayx_messages.h"
+#include "dplay_global.h"
+#include "dplayx_global.h"
DEFAULT_DEBUG_CHANNEL(dplay)
@@ -136,3 +139,103 @@
return 0;
}
+
+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;
+}
diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h
index 7c8cd07..7703435 100644
--- a/dlls/dplayx/dplayx_messages.h
+++ b/dlls/dplayx/dplayx_messages.h
@@ -6,6 +6,8 @@
#include "dplay.h"
#include "rpc.h" /* For GUID */
+#include "dplay_global.h"
+
DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
HANDLE hDeath, HANDLE hConnRead );
@@ -27,11 +29,13 @@
#define DPMSGCMD_CREATESESSION 8
#define DPMSGCMD_CREATENEWPLAYER 9
#define DPMSGCMD_SYSTEMMESSAGE 10
-
+#define DPMSGCMD_DELETEPLAYER 11
#define DPMSGCMD_DELETEGROUP 12
#define DPMSGCMD_ENUMGROUPS 17
+#define DPMSGCMD_FORWARDCREATEPLAYER 19 /* This may be a get name table req */
+
/* This is what DP 6 defines it as. Don't know what it means. All messages
* defined below are DPMSGVER_DP6.
*/
@@ -112,12 +116,12 @@
} DPMSG_CREATESESSION, *LPDPMSG_CREATESESSION;
typedef const DPMSG_CREATESESSION* LPCDPMSG_CREATESESSION;
-/* 28 bytes - ~18 header ~= 10 bytes msg */
+/* 12 bytes msg */
typedef struct tagDPMSG_REQUESTNEWPLAYERID
{
DPMSG_SENDENVELOPE envelope;
-
+ DWORD dwFlags; /* dwFlags used for CreatePlayer */
} DPMSG_REQUESTNEWPLAYERID, *LPDPMSG_REQUESTNEWPLAYERID;
typedef const DPMSG_REQUESTNEWPLAYERID* LPCDPMSG_REQUESTNEWPLAYERID;
@@ -127,10 +131,23 @@
{
DPMSG_SENDENVELOPE envelope;
+#if 0
+ DPID dpidNewPlayerId;
+#else
+ BYTE unknown[38];
+#endif
+
} DPMSG_NEWPLAYERIDREPLY, *LPDPMSG_NEWPLAYERIDREPLY;
typedef const DPMSG_NEWPLAYERIDREPLY* LPCDPMSG_NEWPLAYERIDREPLY;
-
#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/name_server.c b/dlls/dplayx/name_server.c
index 07a66dc..3a1ef07 100644
--- a/dlls/dplayx/name_server.c
+++ b/dlls/dplayx/name_server.c
@@ -303,7 +303,8 @@
lpReplyData->lpMessage = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
lpReplyData->dwMessageSize );
- rmsg = (LPDPMSG_ENUMSESSIONSREPLY)lpReplyData->lpMessage;
+ rmsg = (LPDPMSG_ENUMSESSIONSREPLY)( (BYTE*)lpReplyData->lpMessage +
+ lpDP->dp2->spData.dwSPHeaderSize);
rmsg->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
rmsg->envelope.wCommandId = DPMSGCMD_ENUMSESSIONSREPLY;
@@ -323,7 +324,7 @@
string = lpDP->dp2->lpSessionDesc->sess.lpszSessionName;
}
- lstrcpyW( (LPWSTR)rmsg+1, string );
+ lstrcpyW( (LPWSTR)(rmsg+1), string );
}