1 /* DirectPlay & DirectPlayLobby messaging implementation
3 * Copyright 2000,2001 - Peter Hunnisett
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * o Messaging interface required for both DirectPlay and DirectPlayLobby.
32 #include "dplayx_messages.h"
33 #include "dplay_global.h"
34 #include "dplayx_global.h"
35 #include "name_server.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(dplay
);
40 typedef struct tagMSGTHREADINFO
46 } MSGTHREADINFO
, *LPMSGTHREADINFO
;
48 static DWORD CALLBACK
DPL_MSG_ThreadMain( LPVOID lpContext
);
49 static LPVOID
DP_MSG_ExpectReply( IDirectPlay2AImpl
* This
, LPDPSP_SENDDATA data
,
50 DWORD dwWaitTime
, WORD wReplyCommandId
,
51 LPVOID
* lplpReplyMsg
, LPDWORD lpdwMsgBodySize
);
52 static DWORD
DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
53 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
,
57 static DWORD
DP_MSG_FillPackedPlayer( IDirectPlay2Impl
* lpDP
,
58 LPDPLAYI_PACKEDPLAYER lpPackedPlayer
,
62 DWORD
DP_CopyString( LPVOID destination
, LPVOID source
, BOOL bAnsi
);
65 /* Create the message reception thread to allow the application to receive
66 * asynchronous message reception
68 DWORD
CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent
, HANDLE hStart
,
69 HANDLE hDeath
, HANDLE hConnRead
)
72 LPMSGTHREADINFO lpThreadInfo
;
74 lpThreadInfo
= HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo
) );
75 if( lpThreadInfo
== NULL
)
80 /* The notify event may or may not exist. Depends if async comm or not */
82 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent
,
83 GetCurrentProcess(), &lpThreadInfo
->hNotifyEvent
,
84 0, FALSE
, DUPLICATE_SAME_ACCESS
) )
86 ERR( "Unable to duplicate event handle\n" );
90 /* These 3 handles don't need to be duplicated because we don't keep a
91 * reference to them where they're created. They're created specifically
92 * for the message thread
94 lpThreadInfo
->hStart
= hStart
;
95 lpThreadInfo
->hDeath
= hDeath
;
96 lpThreadInfo
->hSettingRead
= hConnRead
;
98 if( !CreateThread( NULL
, /* Security attribs */
100 DPL_MSG_ThreadMain
, /* Msg reception function */
101 lpThreadInfo
, /* Msg reception func parameter */
103 &dwMsgThreadId
/* Updated with thread id */
107 ERR( "Unable to create msg thread\n" );
111 /* FIXME: Should I be closing the handle to the thread or does that
112 terminate the thread? */
114 return dwMsgThreadId
;
118 HeapFree( GetProcessHeap(), 0, lpThreadInfo
);
123 static DWORD CALLBACK
DPL_MSG_ThreadMain( LPVOID lpContext
)
125 LPMSGTHREADINFO lpThreadInfo
= lpContext
;
128 TRACE( "Msg thread created. Waiting on app startup\n" );
130 /* Wait to ensure that the lobby application is started w/ 1 min timeout */
131 dwWaitResult
= WaitForSingleObject( lpThreadInfo
->hStart
, 10000 /* 10 sec */ );
132 if( dwWaitResult
== WAIT_TIMEOUT
)
134 FIXME( "Should signal app/wait creation failure (0x%08x)\n", dwWaitResult
);
138 /* Close this handle as it's not needed anymore */
139 CloseHandle( lpThreadInfo
->hStart
);
140 lpThreadInfo
->hStart
= 0;
142 /* Wait until the lobby knows what it is */
143 dwWaitResult
= WaitForSingleObject( lpThreadInfo
->hSettingRead
, INFINITE
);
144 if( dwWaitResult
== WAIT_TIMEOUT
)
146 ERR( "App Read connection setting timeout fail (0x%08x)\n", dwWaitResult
);
149 /* Close this handle as it's not needed anymore */
150 CloseHandle( lpThreadInfo
->hSettingRead
);
151 lpThreadInfo
->hSettingRead
= 0;
153 TRACE( "App created && initialized starting main message reception loop\n" );
158 GetMessageW( &lobbyMsg
, 0, 0, 0 );
162 TRACE( "Msg thread exiting!\n" );
163 HeapFree( GetProcessHeap(), 0, lpThreadInfo
);
168 /* DP messaging stuff */
169 static HANDLE
DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl
* This
,
170 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
171 WORD wReplyCommandId
);
172 static LPVOID
DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
173 LPVOID
* lplpReplyMsg
, LPDWORD lpdwMsgBodySize
);
177 HANDLE
DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl
* This
,
178 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
, WORD wReplyCommandId
)
180 lpReplyStructList
->replyExpected
.hReceipt
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
181 lpReplyStructList
->replyExpected
.wExpectedReply
= wReplyCommandId
;
182 lpReplyStructList
->replyExpected
.lpReplyMsg
= NULL
;
183 lpReplyStructList
->replyExpected
.dwMsgBodySize
= 0;
185 /* Insert into the message queue while locked */
186 EnterCriticalSection( &This
->unk
->DP_lock
);
187 DPQ_INSERT( This
->dp2
->replysExpected
, lpReplyStructList
, replysExpected
);
188 LeaveCriticalSection( &This
->unk
->DP_lock
);
190 return lpReplyStructList
->replyExpected
.hReceipt
;
194 LPVOID
DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
195 LPVOID
* lplpReplyMsg
, LPDWORD lpdwMsgBodySize
)
197 CloseHandle( lpReplyStructList
->replyExpected
.hReceipt
);
199 *lplpReplyMsg
= lpReplyStructList
->replyExpected
.lpReplyMsg
;
200 *lpdwMsgBodySize
= lpReplyStructList
->replyExpected
.dwMsgBodySize
;
202 return lpReplyStructList
->replyExpected
.lpReplyMsg
;
205 HRESULT
DP_MSG_PackMessage( IDirectPlay2AImpl
* This
, LPVOID
* lpMsg
,
206 LPDWORD lpMessageSize
)
209 LPDPSP_MSG_PACKET lpPacketBody
;
211 TRACE( "Packing message with command 0x%x\n",
212 ( (LPDPSP_MSG_ENVELOPE
)
213 (((LPBYTE
) *lpMsg
) + This
->dp2
->spData
.dwSPHeaderSize
))->wCommandId
);
214 FIXME( "TODO: Segment the package if needed\n" );
216 lpPacket
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
217 *lpMessageSize
+ sizeof(DPSP_MSG_PACKET
) );
218 lpPacketBody
= (LPDPSP_MSG_PACKET
)( (LPBYTE
) lpPacket
+
219 This
->dp2
->spData
.dwSPHeaderSize
);
221 /* TODO: When do we have to send a DPMSGCMD_PACKET2_DATA? */
222 lpPacketBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
223 lpPacketBody
->envelope
.wCommandId
= DPMSGCMD_PACKET
;
224 lpPacketBody
->envelope
.wVersion
= DX61AVERSION
;
226 CoCreateGuid( &lpPacketBody
->GuidMessage
);
227 lpPacketBody
->PacketIndex
= 0;
228 lpPacketBody
->DataSize
= *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
;
229 lpPacketBody
->Offset
= 0;
230 lpPacketBody
->TotalPackets
= 1;
231 lpPacketBody
->MessageSize
= *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
;
232 lpPacketBody
->PackedOffset
= 0;
234 /* Copy the header of the original message */
235 CopyMemory( lpPacket
, *lpMsg
, This
->dp2
->spData
.dwSPHeaderSize
);
236 /* Copy the body of the original message */
237 CopyMemory( lpPacketBody
+ 1,
238 ((LPBYTE
) *lpMsg
) + This
->dp2
->spData
.dwSPHeaderSize
,
239 *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
);
240 *lpMessageSize
+= sizeof(DPSP_MSG_PACKET
);
242 HeapFree( GetProcessHeap(), 0, *lpMsg
);
248 HRESULT
DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl
* This
, DWORD dwFlags
,
249 LPDPID lpdpidAllocatedId
)
252 LPDPSP_MSG_REQUESTPLAYERID lpMsgBody
;
256 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+ sizeof( *lpMsgBody
);
258 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
260 lpMsgBody
= (LPDPSP_MSG_REQUESTPLAYERID
)( (LPBYTE
)lpMsg
+
261 This
->dp2
->spData
.dwSPHeaderSize
);
263 /* Compose dplay message envelope */
264 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
265 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_REQUESTPLAYERID
;
266 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
268 /* Compose the body of the message */
269 lpMsgBody
->Flags
= dwFlags
;
271 /* Send the message */
275 data
.dwFlags
= DPSEND_GUARANTEED
;
276 data
.idPlayerTo
= 0; /* Name server */
277 data
.idPlayerFrom
= 0; /* Sending from DP */
278 data
.lpMessage
= lpMsg
;
279 data
.dwMessageSize
= dwMsgSize
;
280 data
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
281 data
.lpISP
= This
->dp2
->spData
.lpISP
;
283 TRACE( "Asking for player id w/ Flags 0x%08x\n", lpMsgBody
->Flags
);
285 lpMsg
= DP_MSG_ExpectReply( This
, &data
,
286 DPMSG_RELIABLE_API_TIMER
,
287 DPMSGCMD_REQUESTPLAYERREPLY
,
288 &lpMsg
, &dwMsgSize
);
294 *lpdpidAllocatedId
= ((LPCDPSP_MSG_REQUESTPLAYERREPLY
) lpMsg
)->ID
;
295 TRACE( "Received new id 0x%08x\n", *lpdpidAllocatedId
);
299 ERR( "Didn't receive reply\n" );
303 HeapFree( GetProcessHeap(), 0, lpMsg
);
307 HRESULT
DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl
* This
, DPID dpidServer
)
310 LPDPSP_MSG_ADDFORWARDREQUEST lpMsgBody
;
314 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+ sizeof( *lpMsgBody
);
316 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
318 lpMsgBody
= (LPDPSP_MSG_ADDFORWARDREQUEST
)( (LPBYTE
)lpMsg
+
319 This
->dp2
->spData
.dwSPHeaderSize
);
321 /* Compose dplay message envelope */
322 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
323 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_ADDFORWARDREQUEST
;
324 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
326 /* Compose body of message */
329 /* Send the message */
333 data
.dwFlags
= DPSEND_GUARANTEED
;
334 data
.idPlayerTo
= 0; /* Name server */
335 data
.idPlayerFrom
= dpidServer
; /* Sending from session server */
336 data
.lpMessage
= lpMsg
;
337 data
.dwMessageSize
= dwMsgSize
;
338 data
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
339 data
.lpISP
= This
->dp2
->spData
.lpISP
;
341 TRACE( "Sending forward player request with 0x%08x\n", dpidServer
);
343 lpMsg
= DP_MSG_ExpectReply( This
, &data
,
344 DPMSG_RELIABLE_API_TIMER
,
346 &lpMsg
, &dwMsgSize
);
349 /* Need to examine the data and extract the new player id */
352 FIXME( "Name Table reply received: stub\n" );
358 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
359 * not seem to offer any way of uniquely differentiating between replies of the same type
360 * relative to the request sent. There is an implicit assumption that there will be no
361 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
362 * a networking company.
365 LPVOID
DP_MSG_ExpectReply( IDirectPlay2AImpl
* This
, LPDPSP_SENDDATA lpData
,
366 DWORD dwWaitTime
, WORD wReplyCommandId
,
367 LPVOID
* lplpReplyMsg
, LPDWORD lpdwMsgBodySize
)
371 DP_MSG_REPLY_STRUCT_LIST replyStructList
;
375 /* Setup for receipt */
376 hMsgReceipt
= DP_MSG_BuildAndLinkReplyStruct( This
, &replyStructList
,
379 wCommandId
= ((LPCDPSP_MSG_ENVELOPE
)
380 ( ((LPBYTE
) lpData
->lpMessage
) +
381 This
->dp2
->spData
.dwSPHeaderSize
))->wCommandId
;
382 TRACE( "Sending cmd 0x%x and expecting cmd 0x%x in reply within %u ticks\n",
383 wCommandId
, wReplyCommandId
, dwWaitTime
);
384 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( lpData
);
388 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr
) );
392 /* The reply message will trigger the hMsgReceipt event effectively switching
393 * control back to this thread. See DP_MSG_ReplyReceived.
395 dwWaitReturn
= WaitForSingleObject( hMsgReceipt
, dwWaitTime
);
396 if( dwWaitReturn
!= WAIT_OBJECT_0
)
398 ERR( "Wait failed 0x%08x\n", dwWaitReturn
);
403 return DP_MSG_CleanReplyStruct( &replyStructList
, lplpReplyMsg
, lpdwMsgBodySize
);
406 /* Determine if there is a matching request for this incoming message and then copy
407 * all important data. It is quite silly to have to copy the message, but the documents
408 * indicate that a copy is taken. Silly really.
410 void DP_MSG_ReplyReceived( IDirectPlay2AImpl
* This
, WORD wCommandId
,
411 LPCVOID lpcMsgBody
, DWORD dwMsgBodySize
)
413 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList
;
415 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
418 EnterCriticalSection( &This
->unk
->DP_lock
);
419 DPQ_REMOVE_ENTRY( This
->dp2
->replysExpected
, replysExpected
, replyExpected
.wExpectedReply
,
420 ==, wCommandId
, lpReplyList
);
421 LeaveCriticalSection( &This
->unk
->DP_lock
);
423 if( lpReplyList
!= NULL
)
425 lpReplyList
->replyExpected
.dwMsgBodySize
= dwMsgBodySize
;
426 lpReplyList
->replyExpected
.lpReplyMsg
= HeapAlloc( GetProcessHeap(),
429 CopyMemory( lpReplyList
->replyExpected
.lpReplyMsg
,
430 lpcMsgBody
, dwMsgBodySize
);
432 /* Signal the thread which sent the message that it has a reply */
433 SetEvent( lpReplyList
->replyExpected
.hReceipt
);
437 ERR( "No receipt event set for cmd 0x%x, only expecting in reply mode\n",
442 DWORD
DP_CopyString( LPVOID destination
, LPVOID source
, BOOL bAnsi
)
444 /* Copies an ASCII string (bAnsi=TRUE) or a wide string (bAnsi=FALSE)
445 * from source to the previously allocated destination buffer.
446 * The destination string will be always wide.
447 * If destination is NULL, doesn't perform the copy but the
448 * returned size is still correct.
450 * Returns: The size in bytes of the written string. */
454 if ( source
== NULL
)
459 dwLength
= MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1, NULL
, 0 );
461 MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1,
462 (LPWSTR
) destination
, dwLength
);
466 dwLength
= lstrlenW( (LPWSTR
) source
) + 1;
468 CopyMemory( destination
, source
, dwLength
);
471 return dwLength
* sizeof(WCHAR
);
474 static DWORD
DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
475 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
,
480 /* Fills lpPackedPlayer with the information in lpData.
481 * lpData can be a player or a group.
482 * If lpPackedPlayer is NULL just returns the size
483 * needed to pack the player.
485 * Returns: the size of the written data in bytes */
487 #define PLAYER_OR_GROUP( bIsGroup, lpData, field ) \
489 ? ((lpGroupData) lpData)->field \
490 : ((lpPlayerData) lpData)->field )
492 DWORD offset
, length
, size
;
495 if ( lpPackedPlayer
== NULL
)
497 size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
); /* Fixed data */
498 size
+= DP_CopyString( NULL
, /* Short name */
499 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
501 size
+= DP_CopyString( NULL
, /* Long name */
502 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
504 /* Player data length */
514 /* Shortcut ID Count */
520 lpPackedPlayer
->Size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
);
522 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
523 lpPackedPlayer
->ID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
525 if ( lpPackedPlayer
->Flags
& DPLAYI_PLAYER_SYSPLAYER
)
527 lpPackedPlayer
->VersionOrSystemPlayerID
= DX61AVERSION
;
531 lpPackedPlayer
->VersionOrSystemPlayerID
=
532 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
535 offset
= lpPackedPlayer
->Size
;
538 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
539 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
542 lpPackedPlayer
->PlayerInfoMask
|= SPP_SN
;
546 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
547 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
550 lpPackedPlayer
->PlayerInfoMask
|= SPP_LN
;
554 length
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
557 size
= spp_get_optimum_size( length
);
558 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PD_OFFSET
);
559 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
562 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
563 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
568 /* Service provider data */
569 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
, lpPackedPlayer
->ID
,
570 &playerSPData
, &length
, DPGET_REMOTE
);
573 size
= spp_get_optimum_size( length
);
574 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_SL_OFFSET
);
575 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
577 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
, length
);
584 if( !DPQ_IS_EMPTY( ((lpGroupData
)lpData
)->players
) )
586 DWORD player_count
, offset_PC
;
587 lpPlayerList lpPList
;
589 offset_PC
= offset
; /* Space for PlayerCount */
594 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
598 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
599 &lpPList
->lpPData
->dpid
,
601 offset
+= sizeof(DPID
);
604 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
608 size
= spp_get_optimum_size( player_count
);
609 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PC_OFFSET
);
611 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset_PC
, &player_count
, size
);
615 if ( ((lpGroupData
)lpData
)->parent
)
617 lpPackedPlayer
->PlayerInfoMask
|= SPP_PI
;
618 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
619 &((lpGroupData
)lpData
)->parent
,
621 offset
+= sizeof(DWORD
);
625 /*size = spp_get_optimum_size( ___ );
626 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
627 FIXME( "TODO: Add shortcut IDs\n" );
633 static DWORD
DP_MSG_FillPackedPlayer( IDirectPlay2Impl
* lpDP
,
634 LPDPLAYI_PACKEDPLAYER lpPackedPlayer
,
639 /* Fills lpPackedPlayer with the information in lpData.
640 * lpData can be a player or a group.
641 * If lpPackedPlayer is NULL just returns the size
642 * needed to pack the player.
644 * Returns: the size of the written data in bytes */
649 if ( lpPackedPlayer
== NULL
)
652 size
= sizeof(DPLAYI_PACKEDPLAYER
); /* Fixed data */
653 size
+= DP_CopyString( NULL
, /* Short name */
654 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
656 size
+= DP_CopyString( NULL
, /* Long name */
657 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
669 lpPackedPlayer
->SystemPlayerID
=
670 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
671 lpPackedPlayer
->FixedSize
= sizeof(DPLAYI_PACKEDPLAYER
);
672 lpPackedPlayer
->PlayerVersion
= DX61AVERSION
;
674 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
675 lpPackedPlayer
->PlayerID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
676 lpPackedPlayer
->ParentID
= ( bIsGroup
677 ? ((lpGroupData
)lpData
)->parent
680 offset
= lpPackedPlayer
->FixedSize
;
683 lpPackedPlayer
->ShortNameLength
=
684 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
685 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
687 offset
+= lpPackedPlayer
->ShortNameLength
;
690 lpPackedPlayer
->LongNameLength
=
691 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
692 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
694 offset
+= lpPackedPlayer
->LongNameLength
;
696 /* Service provider data */
697 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
,
698 lpPackedPlayer
->PlayerID
,
700 &lpPackedPlayer
->ServiceProviderDataSize
,
702 if ( lpPackedPlayer
->ServiceProviderDataSize
)
704 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
,
705 lpPackedPlayer
->ServiceProviderDataSize
);
706 offset
+= lpPackedPlayer
->ServiceProviderDataSize
;
710 lpPackedPlayer
->PlayerDataSize
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
711 if ( lpPackedPlayer
->PlayerDataSize
)
713 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
714 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
715 lpPackedPlayer
->PlayerDataSize
);
716 offset
+= lpPackedPlayer
->PlayerDataSize
;
721 lpPlayerList lpPList
;
724 lpPackedPlayer
->NumberOfPlayers
= 0;
726 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
730 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
731 &lpPList
->lpPData
->dpid
,
733 offset
+= sizeof(DPID
);
734 lpPackedPlayer
->NumberOfPlayers
++;
736 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
742 lpPackedPlayer
->Size
= offset
;
744 return lpPackedPlayer
->Size
;
747 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl
* lpDP
,
749 LPDWORD lpdwMsgSize
)
751 /* Depending on the type of session, builds either a EnumPlayers
752 reply or a SuperEnumPlayers reply, and places it in lplpReply */
754 /* TODO: Find size to allocate *lplpReply
755 * Check if we're releasing that memory */
757 LPDPSP_MSG_ENUMPLAYERSREPLY lpReply
; /* Also valid in the SUPER case */
758 lpPlayerList lpPList
;
761 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
764 *lplpReply
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 1024 );
765 lpReply
= (LPDPSP_MSG_ENUMPLAYERSREPLY
)( (LPBYTE
)(*lplpReply
) +
766 lpDP
->dp2
->spData
.dwSPHeaderSize
);
768 lpReply
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
769 lpReply
->envelope
.wVersion
= DX61AVERSION
;
771 if ( lpDP
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_CLIENTSERVER
)
773 lpReply
->envelope
.wCommandId
= DPMSGCMD_ENUMPLAYERSREPLY
;
777 lpReply
->envelope
.wCommandId
= DPMSGCMD_SUPERENUMPLAYERSREPLY
;
781 /* Session description */
782 lpReply
->DescriptionOffset
= ( sizeof(DPSP_MSG_ENUMPLAYERSREPLY
) -
783 sizeof(DPSESSIONDESC2
) );
784 CopyMemory( &lpReply
->DPSessionDesc
, lpDP
->dp2
->lpSessionDesc
,
785 sizeof(DPSESSIONDESC2
) );
787 offset
= sizeof(DPSP_MSG_ENUMPLAYERSREPLY
);
790 if ( lpDP
->dp2
->lpSessionDesc
->lpszSessionName
)
792 lpReply
->NameOffset
= offset
;
793 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
794 lpDP
->dp2
->lpSessionDesc
->lpszSessionName
,
798 /* Session password */
799 if ( lpDP
->dp2
->lpSessionDesc
->lpszPassword
)
801 lpReply
->PasswordOffset
= offset
;
802 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
803 lpDP
->dp2
->lpSessionDesc
->lpszPassword
,
807 /* Populate PlayerInfo list */
810 if ( (lpPList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)) )
814 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
816 offset
+= DP_MSG_FillSuperPackedPlayer(
817 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
818 lpPList
->lpPData
, FALSE
, bAnsi
);
822 offset
+= DP_MSG_FillPackedPlayer(
823 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
824 lpPList
->lpPData
, FALSE
, bAnsi
);
827 lpReply
->PlayerCount
++;
829 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
833 if ( (lpGList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->groups
)) )
837 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
839 offset
+= DP_MSG_FillSuperPackedPlayer(
840 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
841 lpGList
->lpGData
, TRUE
, bAnsi
);
845 offset
+= DP_MSG_FillPackedPlayer(
846 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
847 lpGList
->lpGData
, TRUE
, bAnsi
);
850 lpReply
->GroupCount
++;
852 while( (lpGList
= DPQ_NEXT( lpGList
->groups
)) );
855 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
857 /* - Groups with shortcuts */
858 FIXME( "TODO: Add shortcut IDs\n" );
861 *lpdwMsgSize
= lpDP
->dp2
->spData
.dwSPHeaderSize
+ offset
;