- 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 ); }