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
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
52 LPDWORD lpdwMsgBodySize
);
53 static DWORD
DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
54 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
,
58 static DWORD
DP_MSG_FillPackedPlayer( IDirectPlay2Impl
* lpDP
,
59 LPDPLAYI_PACKEDPLAYER lpPackedPlayer
,
63 DWORD
DP_CopyString( LPVOID destination
, LPVOID source
, BOOL bAnsi
);
66 /* Create the message reception thread to allow the application to receive
67 * asynchronous message reception
69 DWORD
CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent
, HANDLE hStart
,
70 HANDLE hDeath
, HANDLE hConnRead
)
73 LPMSGTHREADINFO lpThreadInfo
;
75 lpThreadInfo
= HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo
) );
76 if( lpThreadInfo
== NULL
)
81 /* The notify event may or may not exist. Depends if async comm or not */
83 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent
,
84 GetCurrentProcess(), &lpThreadInfo
->hNotifyEvent
,
85 0, FALSE
, DUPLICATE_SAME_ACCESS
) )
87 ERR( "Unable to duplicate event handle\n" );
91 /* These 3 handles don't need to be duplicated because we don't keep a
92 * reference to them where they're created. They're created specifically
93 * for the message thread
95 lpThreadInfo
->hStart
= hStart
;
96 lpThreadInfo
->hDeath
= hDeath
;
97 lpThreadInfo
->hSettingRead
= hConnRead
;
99 if( !CreateThread( NULL
, /* Security attribs */
101 DPL_MSG_ThreadMain
, /* Msg reception function */
102 lpThreadInfo
, /* Msg reception func parameter */
104 &dwMsgThreadId
/* Updated with thread id */
108 ERR( "Unable to create msg thread\n" );
112 /* FIXME: Should I be closing the handle to the thread or does that
113 terminate the thread? */
115 return dwMsgThreadId
;
119 HeapFree( GetProcessHeap(), 0, lpThreadInfo
);
124 static DWORD CALLBACK
DPL_MSG_ThreadMain( LPVOID lpContext
)
126 LPMSGTHREADINFO lpThreadInfo
= lpContext
;
129 TRACE( "Msg thread created. Waiting on app startup\n" );
131 /* Wait to ensure that the lobby application is started w/ 1 min timeout */
132 dwWaitResult
= WaitForSingleObject( lpThreadInfo
->hStart
, 10000 /* 10 sec */ );
133 if( dwWaitResult
== WAIT_TIMEOUT
)
135 FIXME( "Should signal app/wait creation failure (0x%08x)\n", dwWaitResult
);
139 /* Close this handle as it's not needed anymore */
140 CloseHandle( lpThreadInfo
->hStart
);
141 lpThreadInfo
->hStart
= 0;
143 /* Wait until the lobby knows what it is */
144 dwWaitResult
= WaitForSingleObject( lpThreadInfo
->hSettingRead
, INFINITE
);
145 if( dwWaitResult
== WAIT_TIMEOUT
)
147 ERR( "App Read connection setting timeout fail (0x%08x)\n", dwWaitResult
);
150 /* Close this handle as it's not needed anymore */
151 CloseHandle( lpThreadInfo
->hSettingRead
);
152 lpThreadInfo
->hSettingRead
= 0;
154 TRACE( "App created && initialized starting main message reception loop\n" );
159 GetMessageW( &lobbyMsg
, 0, 0, 0 );
163 TRACE( "Msg thread exiting!\n" );
164 HeapFree( GetProcessHeap(), 0, lpThreadInfo
);
169 /* DP messaging stuff */
170 static HANDLE
DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl
* This
,
171 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
172 WORD wReplyCommandId
);
173 static LPVOID
DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
174 LPVOID
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
175 LPDWORD lpdwMsgBodySize
);
179 HANDLE
DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl
* This
,
180 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
, WORD wReplyCommandId
)
182 lpReplyStructList
->replyExpected
.hReceipt
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
183 lpReplyStructList
->replyExpected
.wExpectedReply
= wReplyCommandId
;
184 lpReplyStructList
->replyExpected
.lpReplyHdr
= NULL
;
185 lpReplyStructList
->replyExpected
.lpReplyMsg
= NULL
;
186 lpReplyStructList
->replyExpected
.dwMsgBodySize
= 0;
188 /* Insert into the message queue while locked */
189 EnterCriticalSection( &This
->unk
->DP_lock
);
190 DPQ_INSERT( This
->dp2
->replysExpected
, lpReplyStructList
, replysExpected
);
191 LeaveCriticalSection( &This
->unk
->DP_lock
);
193 return lpReplyStructList
->replyExpected
.hReceipt
;
197 LPVOID
DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
198 LPVOID
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
199 LPDWORD lpdwMsgBodySize
)
201 CloseHandle( lpReplyStructList
->replyExpected
.hReceipt
);
205 *lplpReplyHdr
= lpReplyStructList
->replyExpected
.lpReplyHdr
;
208 *lplpReplyMsg
= lpReplyStructList
->replyExpected
.lpReplyMsg
;
209 *lpdwMsgBodySize
= lpReplyStructList
->replyExpected
.dwMsgBodySize
;
211 return lpReplyStructList
->replyExpected
.lpReplyMsg
;
214 HRESULT
DP_MSG_PackMessage( IDirectPlay2AImpl
* This
, LPVOID
* lpMsg
,
215 LPDWORD lpMessageSize
)
218 LPDPSP_MSG_PACKET lpPacketBody
;
220 TRACE( "Packing message with command 0x%x\n",
221 ( (LPDPSP_MSG_ENVELOPE
)
222 (((LPBYTE
) *lpMsg
) + This
->dp2
->spData
.dwSPHeaderSize
))->wCommandId
);
223 FIXME( "TODO: Segment the package if needed\n" );
225 lpPacket
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
226 *lpMessageSize
+ sizeof(DPSP_MSG_PACKET
) );
227 lpPacketBody
= (LPDPSP_MSG_PACKET
)( (LPBYTE
) lpPacket
+
228 This
->dp2
->spData
.dwSPHeaderSize
);
230 /* TODO: When do we have to send a DPMSGCMD_PACKET2_DATA? */
231 lpPacketBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
232 lpPacketBody
->envelope
.wCommandId
= DPMSGCMD_PACKET
;
233 lpPacketBody
->envelope
.wVersion
= DX61AVERSION
;
235 CoCreateGuid( &lpPacketBody
->GuidMessage
);
236 lpPacketBody
->PacketIndex
= 0;
237 lpPacketBody
->DataSize
= *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
;
238 lpPacketBody
->Offset
= 0;
239 lpPacketBody
->TotalPackets
= 1;
240 lpPacketBody
->MessageSize
= *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
;
241 lpPacketBody
->PackedOffset
= 0;
243 /* Copy the header of the original message */
244 CopyMemory( lpPacket
, *lpMsg
, This
->dp2
->spData
.dwSPHeaderSize
);
245 /* Copy the body of the original message */
246 CopyMemory( lpPacketBody
+ 1,
247 ((LPBYTE
) *lpMsg
) + This
->dp2
->spData
.dwSPHeaderSize
,
248 *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
);
249 *lpMessageSize
+= sizeof(DPSP_MSG_PACKET
);
251 HeapFree( GetProcessHeap(), 0, *lpMsg
);
257 HRESULT
DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl
* This
, DWORD dwFlags
,
258 LPDPID lpdpidAllocatedId
)
261 LPDPSP_MSG_REQUESTPLAYERID lpMsgBody
;
265 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+ sizeof( *lpMsgBody
);
267 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
269 lpMsgBody
= (LPDPSP_MSG_REQUESTPLAYERID
)( (LPBYTE
)lpMsg
+
270 This
->dp2
->spData
.dwSPHeaderSize
);
272 /* Compose dplay message envelope */
273 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
274 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_REQUESTPLAYERID
;
275 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
277 /* Compose the body of the message */
278 lpMsgBody
->Flags
= dwFlags
;
280 /* Send the message */
284 data
.dwFlags
= DPSEND_GUARANTEED
;
285 data
.idPlayerTo
= 0; /* Name server */
286 data
.idPlayerFrom
= 0; /* Sending from DP */
287 data
.lpMessage
= lpMsg
;
288 data
.dwMessageSize
= dwMsgSize
;
289 data
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
290 data
.lpISP
= This
->dp2
->spData
.lpISP
;
292 TRACE( "Asking for player id w/ Flags 0x%08x\n", lpMsgBody
->Flags
);
294 lpMsg
= DP_MSG_ExpectReply( This
, &data
,
295 DPMSG_RELIABLE_API_TIMER
,
296 DPMSGCMD_REQUESTPLAYERREPLY
,
297 NULL
, &lpMsg
, &dwMsgSize
);
303 *lpdpidAllocatedId
= ((LPCDPSP_MSG_REQUESTPLAYERREPLY
) lpMsg
)->ID
;
304 TRACE( "Received new id 0x%08x\n", *lpdpidAllocatedId
);
308 ERR( "Didn't receive reply\n" );
312 HeapFree( GetProcessHeap(), 0, lpMsg
);
316 HRESULT
DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl
* This
, DPID dpidServer
)
319 LPDPSP_MSG_ADDFORWARDREQUEST lpMsgBody
;
323 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+ sizeof( *lpMsgBody
);
325 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
327 lpMsgBody
= (LPDPSP_MSG_ADDFORWARDREQUEST
)( (LPBYTE
)lpMsg
+
328 This
->dp2
->spData
.dwSPHeaderSize
);
330 /* Compose dplay message envelope */
331 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
332 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_ADDFORWARDREQUEST
;
333 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
335 /* Compose body of message */
338 /* Send the message */
342 data
.dwFlags
= DPSEND_GUARANTEED
;
343 data
.idPlayerTo
= 0; /* Name server */
344 data
.idPlayerFrom
= dpidServer
; /* Sending from session server */
345 data
.lpMessage
= lpMsg
;
346 data
.dwMessageSize
= dwMsgSize
;
347 data
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
348 data
.lpISP
= This
->dp2
->spData
.lpISP
;
350 TRACE( "Sending forward player request with 0x%08x\n", dpidServer
);
352 lpMsg
= DP_MSG_ExpectReply( This
, &data
,
353 DPMSG_RELIABLE_API_TIMER
,
355 NULL
, &lpMsg
, &dwMsgSize
);
358 /* Need to examine the data and extract the new player id */
361 FIXME( "Name Table reply received: stub\n" );
367 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
368 * not seem to offer any way of uniquely differentiating between replies of the same type
369 * relative to the request sent. There is an implicit assumption that there will be no
370 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
371 * a networking company.
374 LPVOID
DP_MSG_ExpectReply( IDirectPlay2AImpl
* This
, LPDPSP_SENDDATA lpData
,
375 DWORD dwWaitTime
, WORD wReplyCommandId
,
376 LPVOID
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
377 LPDWORD lpdwMsgBodySize
)
381 DP_MSG_REPLY_STRUCT_LIST replyStructList
;
385 /* Setup for receipt */
386 hMsgReceipt
= DP_MSG_BuildAndLinkReplyStruct( This
, &replyStructList
,
389 wCommandId
= ((LPCDPSP_MSG_ENVELOPE
)
390 ( ((LPBYTE
) lpData
->lpMessage
) +
391 This
->dp2
->spData
.dwSPHeaderSize
))->wCommandId
;
392 TRACE( "Sending cmd 0x%x and expecting cmd 0x%x in reply within %u ticks\n",
393 wCommandId
, wReplyCommandId
, dwWaitTime
);
394 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( lpData
);
398 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr
) );
402 /* The reply message will trigger the hMsgReceipt event effectively switching
403 * control back to this thread. See DP_MSG_ReplyReceived.
405 dwWaitReturn
= WaitForSingleObject( hMsgReceipt
, dwWaitTime
);
406 if( dwWaitReturn
!= WAIT_OBJECT_0
)
408 ERR( "Wait failed 0x%08x\n", dwWaitReturn
);
413 return DP_MSG_CleanReplyStruct( &replyStructList
, lplpReplyHdr
,
414 lplpReplyMsg
, lpdwMsgBodySize
);
417 /* Determine if there is a matching request for this incoming message and then copy
418 * all important data. It is quite silly to have to copy the message, but the documents
419 * indicate that a copy is taken. Silly really.
421 BOOL
DP_MSG_ReplyReceived( IDirectPlay2AImpl
* This
, WORD wCommandId
,
422 LPCVOID lpcMsgHdr
, LPCVOID lpcMsgBody
,
423 DWORD dwMsgBodySize
)
425 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList
;
427 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
430 EnterCriticalSection( &This
->unk
->DP_lock
);
431 DPQ_REMOVE_ENTRY( This
->dp2
->replysExpected
, replysExpected
, replyExpected
.wExpectedReply
,
432 ==, wCommandId
, lpReplyList
);
433 LeaveCriticalSection( &This
->unk
->DP_lock
);
435 if( lpReplyList
== NULL
)
437 TRACE( "No receipt event set for cmd 0x%x\n", wCommandId
);
441 lpReplyList
->replyExpected
.dwMsgBodySize
= dwMsgBodySize
;
442 /* TODO: Can we avoid theese allocations? */
443 lpReplyList
->replyExpected
.lpReplyHdr
= HeapAlloc( GetProcessHeap(),
445 This
->dp2
->spData
.dwSPHeaderSize
);
446 lpReplyList
->replyExpected
.lpReplyMsg
= HeapAlloc( GetProcessHeap(),
449 CopyMemory( lpReplyList
->replyExpected
.lpReplyHdr
,
450 lpcMsgHdr
, This
->dp2
->spData
.dwSPHeaderSize
);
451 CopyMemory( lpReplyList
->replyExpected
.lpReplyMsg
,
452 lpcMsgBody
, dwMsgBodySize
);
454 /* Signal the thread which sent the message that it has a reply */
455 SetEvent( lpReplyList
->replyExpected
.hReceipt
);
460 DWORD
DP_CopyString( LPVOID destination
, LPVOID source
, BOOL bAnsi
)
462 /* Copies an ASCII string (bAnsi=TRUE) or a wide string (bAnsi=FALSE)
463 * from source to the previously allocated destination buffer.
464 * The destination string will be always wide.
465 * If destination is NULL, doesn't perform the copy but the
466 * returned size is still correct.
468 * Returns: The size in bytes of the written string. */
472 if ( source
== NULL
)
477 dwLength
= MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1, NULL
, 0 );
479 MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1,
480 (LPWSTR
) destination
, dwLength
);
484 dwLength
= lstrlenW( (LPWSTR
) source
) + 1;
486 CopyMemory( destination
, source
, dwLength
);
489 return dwLength
* sizeof(WCHAR
);
492 static DWORD
DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
493 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
,
498 /* Fills lpPackedPlayer with the information in lpData.
499 * lpData can be a player or a group.
500 * If lpPackedPlayer is NULL just returns the size
501 * needed to pack the player.
503 * Returns: the size of the written data in bytes */
505 #define PLAYER_OR_GROUP( bIsGroup, lpData, field ) \
507 ? ((lpGroupData) lpData)->field \
508 : ((lpPlayerData) lpData)->field )
510 DWORD offset
, length
, size
;
513 if ( lpPackedPlayer
== NULL
)
515 size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
); /* Fixed data */
516 size
+= DP_CopyString( NULL
, /* Short name */
517 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
519 size
+= DP_CopyString( NULL
, /* Long name */
520 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
522 /* Player data length */
532 /* Shortcut ID Count */
538 lpPackedPlayer
->Size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
);
540 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
541 lpPackedPlayer
->ID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
543 if ( lpPackedPlayer
->Flags
& DPLAYI_PLAYER_SYSPLAYER
)
545 lpPackedPlayer
->VersionOrSystemPlayerID
= DX61AVERSION
;
549 lpPackedPlayer
->VersionOrSystemPlayerID
=
550 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
553 offset
= lpPackedPlayer
->Size
;
556 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
557 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
560 lpPackedPlayer
->PlayerInfoMask
|= SPP_SN
;
564 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
565 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
568 lpPackedPlayer
->PlayerInfoMask
|= SPP_LN
;
572 length
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
575 size
= spp_get_optimum_size( length
);
576 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PD_OFFSET
);
577 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
580 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
581 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
586 /* Service provider data */
587 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
, lpPackedPlayer
->ID
,
588 &playerSPData
, &length
, DPGET_REMOTE
);
591 size
= spp_get_optimum_size( length
);
592 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_SL_OFFSET
);
593 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
595 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
, length
);
602 if( !DPQ_IS_EMPTY( ((lpGroupData
)lpData
)->players
) )
604 DWORD player_count
, offset_PC
;
605 lpPlayerList lpPList
;
607 offset_PC
= offset
; /* Space for PlayerCount */
612 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
616 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
617 &lpPList
->lpPData
->dpid
,
619 offset
+= sizeof(DPID
);
622 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
626 size
= spp_get_optimum_size( player_count
);
627 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PC_OFFSET
);
629 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset_PC
, &player_count
, size
);
633 if ( ((lpGroupData
)lpData
)->parent
)
635 lpPackedPlayer
->PlayerInfoMask
|= SPP_PI
;
636 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
637 &((lpGroupData
)lpData
)->parent
,
639 offset
+= sizeof(DWORD
);
643 /*size = spp_get_optimum_size( ___ );
644 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
645 FIXME( "TODO: Add shortcut IDs\n" );
651 static DWORD
DP_MSG_FillPackedPlayer( IDirectPlay2Impl
* lpDP
,
652 LPDPLAYI_PACKEDPLAYER lpPackedPlayer
,
657 /* Fills lpPackedPlayer with the information in lpData.
658 * lpData can be a player or a group.
659 * If lpPackedPlayer is NULL just returns the size
660 * needed to pack the player.
662 * Returns: the size of the written data in bytes */
667 if ( lpPackedPlayer
== NULL
)
670 size
= sizeof(DPLAYI_PACKEDPLAYER
); /* Fixed data */
671 size
+= DP_CopyString( NULL
, /* Short name */
672 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
674 size
+= DP_CopyString( NULL
, /* Long name */
675 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
687 lpPackedPlayer
->SystemPlayerID
=
688 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
689 lpPackedPlayer
->FixedSize
= sizeof(DPLAYI_PACKEDPLAYER
);
690 lpPackedPlayer
->PlayerVersion
= DX61AVERSION
;
692 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
693 lpPackedPlayer
->PlayerID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
694 lpPackedPlayer
->ParentID
= ( bIsGroup
695 ? ((lpGroupData
)lpData
)->parent
698 offset
= lpPackedPlayer
->FixedSize
;
701 lpPackedPlayer
->ShortNameLength
=
702 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
703 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
705 offset
+= lpPackedPlayer
->ShortNameLength
;
708 lpPackedPlayer
->LongNameLength
=
709 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
710 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
712 offset
+= lpPackedPlayer
->LongNameLength
;
714 /* Service provider data */
715 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
,
716 lpPackedPlayer
->PlayerID
,
718 &lpPackedPlayer
->ServiceProviderDataSize
,
720 if ( lpPackedPlayer
->ServiceProviderDataSize
)
722 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
,
723 lpPackedPlayer
->ServiceProviderDataSize
);
724 offset
+= lpPackedPlayer
->ServiceProviderDataSize
;
728 lpPackedPlayer
->PlayerDataSize
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
729 if ( lpPackedPlayer
->PlayerDataSize
)
731 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
732 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
733 lpPackedPlayer
->PlayerDataSize
);
734 offset
+= lpPackedPlayer
->PlayerDataSize
;
739 lpPlayerList lpPList
;
742 lpPackedPlayer
->NumberOfPlayers
= 0;
744 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
748 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
749 &lpPList
->lpPData
->dpid
,
751 offset
+= sizeof(DPID
);
752 lpPackedPlayer
->NumberOfPlayers
++;
754 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
760 lpPackedPlayer
->Size
= offset
;
762 return lpPackedPlayer
->Size
;
765 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl
* lpDP
,
767 LPDWORD lpdwMsgSize
)
769 /* Depending on the type of session, builds either a EnumPlayers
770 reply or a SuperEnumPlayers reply, and places it in lplpReply */
772 /* TODO: Find size to allocate *lplpReply
773 * Check if we're releasing that memory */
775 LPDPSP_MSG_ENUMPLAYERSREPLY lpReply
; /* Also valid in the SUPER case */
776 lpPlayerList lpPList
;
779 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
782 *lplpReply
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 1024 );
783 lpReply
= (LPDPSP_MSG_ENUMPLAYERSREPLY
)( (LPBYTE
)(*lplpReply
) +
784 lpDP
->dp2
->spData
.dwSPHeaderSize
);
786 lpReply
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
787 lpReply
->envelope
.wVersion
= DX61AVERSION
;
789 if ( lpDP
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_CLIENTSERVER
)
791 lpReply
->envelope
.wCommandId
= DPMSGCMD_ENUMPLAYERSREPLY
;
795 lpReply
->envelope
.wCommandId
= DPMSGCMD_SUPERENUMPLAYERSREPLY
;
799 /* Session description */
800 lpReply
->DescriptionOffset
= ( sizeof(DPSP_MSG_ENUMPLAYERSREPLY
) -
801 sizeof(DPSESSIONDESC2
) );
802 CopyMemory( &lpReply
->DPSessionDesc
, lpDP
->dp2
->lpSessionDesc
,
803 sizeof(DPSESSIONDESC2
) );
805 offset
= sizeof(DPSP_MSG_ENUMPLAYERSREPLY
);
808 if ( lpDP
->dp2
->lpSessionDesc
->lpszSessionName
)
810 lpReply
->NameOffset
= offset
;
811 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
812 lpDP
->dp2
->lpSessionDesc
->lpszSessionName
,
816 /* Session password */
817 if ( lpDP
->dp2
->lpSessionDesc
->lpszPassword
)
819 lpReply
->PasswordOffset
= offset
;
820 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
821 lpDP
->dp2
->lpSessionDesc
->lpszPassword
,
825 /* Populate PlayerInfo list */
828 if ( (lpPList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)) )
832 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
834 offset
+= DP_MSG_FillSuperPackedPlayer(
835 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
836 lpPList
->lpPData
, FALSE
, bAnsi
);
840 offset
+= DP_MSG_FillPackedPlayer(
841 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
842 lpPList
->lpPData
, FALSE
, bAnsi
);
845 lpReply
->PlayerCount
++;
847 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
851 if ( (lpGList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->groups
)) )
855 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
857 offset
+= DP_MSG_FillSuperPackedPlayer(
858 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
859 lpGList
->lpGData
, TRUE
, bAnsi
);
863 offset
+= DP_MSG_FillPackedPlayer(
864 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
865 lpGList
->lpGData
, TRUE
, bAnsi
);
868 lpReply
->GroupCount
++;
870 while( (lpGList
= DPQ_NEXT( lpGList
->groups
)) );
873 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
875 /* - Groups with shortcuts */
876 FIXME( "TODO: Add shortcut IDs\n" );
879 *lpdwMsgSize
= lpDP
->dp2
->spData
.dwSPHeaderSize
+ offset
;