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 HRESULT
DP_MSG_SendCreatePlayer( IDirectPlay2AImpl
* This
, lpPlayerData lpData
)
370 LPDPSP_MSG_CREATEPLAYER lpMsgBody
;
371 DWORD dwMsgSize
, dwWrapperSize
;
374 TRACE( "(%p)->(0x%08x)\n", This
, lpData
->dpid
);
377 /* If the session supports multicast, wrap the message up into
378 * a DPSP_MSG_ASK4MULTICAST */
379 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
381 dwWrapperSize
= sizeof(DPSP_MSG_ASK4MULTICAST
);
389 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+
391 sizeof(DPSP_MSG_CREATEPLAYER
) +
392 256; /* Estimated max size for player data */
394 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
395 lpMsgBody
= (LPDPSP_MSG_CREATEPLAYER
)( lpMsg
+
396 This
->dp2
->spData
.dwSPHeaderSize
+
400 /* Fill wrapper if needed */
401 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
403 LPDPSP_MSG_ASK4MULTICAST lpWrapper
= (LPDPSP_MSG_ASK4MULTICAST
) lpMsg
;
405 lpWrapper
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
406 lpWrapper
->envelope
.wCommandId
= DPMSGCMD_CREATEPLAYER
;
407 lpWrapper
->envelope
.wVersion
= DX61AVERSION
;
409 lpWrapper
->GroupTo
= 0; /*TODO*/
410 lpWrapper
->PlayerFrom
= lpData
->dpid
;
411 lpWrapper
->MessageOffset
= sizeof(DPSP_MSG_ASK4MULTICAST
);
415 /* Compose dplay message envelope */
416 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
417 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_CREATEPLAYER
;
418 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
420 /* Compose body of message */
421 lpMsgBody
->IDTo
= 0; /* Name server */
422 lpMsgBody
->PlayerID
= lpData
->dpid
;
423 lpMsgBody
->GroupID
= 0; /* Ignored */
424 lpMsgBody
->CreateOffset
= sizeof(DPSP_MSG_CREATEPLAYER
);
425 lpMsgBody
->PasswordOffset
= 0; /* Ignored */
427 /* Add PlayerInfo and recalculation of exact message size */
428 dwMsgSize
-= 256; /* We estimated 256 */
429 dwMsgSize
+= DP_MSG_FillPackedPlayer(
431 (LPDPLAYI_PACKEDPLAYER
)(((LPBYTE
) lpMsgBody
) + lpMsgBody
->CreateOffset
),
432 lpData
, FALSE
, TRUE
);
435 /* If the session supports multicast, send message to the game host */
436 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
438 DPSP_SENDDATA sendData
;
439 sendData
.dwFlags
= DPSEND_GUARANTEED
;
440 sendData
.idPlayerTo
= 0; /* Name server */
441 sendData
.idPlayerFrom
= lpData
->dpid
;
442 sendData
.lpMessage
= lpMsg
;
443 sendData
.dwMessageSize
= dwMsgSize
;
444 sendData
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
445 sendData
.lpISP
= This
->dp2
->spData
.lpISP
;
447 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( &sendData
);
449 /* Otherwise, send the message to each player in the session */
452 lpPlayerList lpPList
;
453 DPSP_SENDDATA sendData
;
454 sendData
.dwFlags
= DPSEND_GUARANTEED
;
455 sendData
.idPlayerFrom
= lpData
->dpid
;
456 sendData
.lpMessage
= lpMsg
;
457 sendData
.dwMessageSize
= dwMsgSize
;
458 sendData
.bSystemMessage
= TRUE
;
459 sendData
.lpISP
= This
->dp2
->spData
.lpISP
;
461 if ( (lpPList
= DPQ_FIRST( This
->dp2
->lpSysGroup
->players
)) )
465 if ( ( lpPList
->lpPData
->dwFlags
& DPLAYI_PLAYER_SYSPLAYER
) &&
466 ( ~lpPList
->lpPData
->dwFlags
& DPLAYI_PLAYER_PLAYERLOCAL
) )
468 sendData
.idPlayerTo
= lpPList
->lpPData
->dpid
;
469 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( &sendData
);
472 ERR( "Failed to send message to 0x%08x\n", sendData
.idPlayerTo
);
476 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
481 HeapFree( GetProcessHeap(), 0, lpMsg
);
485 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
486 * not seem to offer any way of uniquely differentiating between replies of the same type
487 * relative to the request sent. There is an implicit assumption that there will be no
488 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
489 * a networking company.
492 LPVOID
DP_MSG_ExpectReply( IDirectPlay2AImpl
* This
, LPDPSP_SENDDATA lpData
,
493 DWORD dwWaitTime
, WORD wReplyCommandId
,
494 LPVOID
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
495 LPDWORD lpdwMsgBodySize
)
499 DP_MSG_REPLY_STRUCT_LIST replyStructList
;
503 /* Setup for receipt */
504 hMsgReceipt
= DP_MSG_BuildAndLinkReplyStruct( This
, &replyStructList
,
507 wCommandId
= ((LPCDPSP_MSG_ENVELOPE
)
508 ( ((LPBYTE
) lpData
->lpMessage
) +
509 This
->dp2
->spData
.dwSPHeaderSize
))->wCommandId
;
510 TRACE( "Sending cmd 0x%x and expecting cmd 0x%x in reply within %u ticks\n",
511 wCommandId
, wReplyCommandId
, dwWaitTime
);
512 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( lpData
);
516 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr
) );
520 /* The reply message will trigger the hMsgReceipt event effectively switching
521 * control back to this thread. See DP_MSG_ReplyReceived.
523 dwWaitReturn
= WaitForSingleObject( hMsgReceipt
, dwWaitTime
);
524 if( dwWaitReturn
!= WAIT_OBJECT_0
)
526 ERR( "Wait failed 0x%08x\n", dwWaitReturn
);
531 return DP_MSG_CleanReplyStruct( &replyStructList
, lplpReplyHdr
,
532 lplpReplyMsg
, lpdwMsgBodySize
);
535 /* Determine if there is a matching request for this incoming message and then copy
536 * all important data. It is quite silly to have to copy the message, but the documents
537 * indicate that a copy is taken. Silly really.
539 BOOL
DP_MSG_ReplyReceived( IDirectPlay2AImpl
* This
, WORD wCommandId
,
540 LPCVOID lpcMsgHdr
, LPCVOID lpcMsgBody
,
541 DWORD dwMsgBodySize
)
543 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList
;
545 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
548 EnterCriticalSection( &This
->unk
->DP_lock
);
549 DPQ_REMOVE_ENTRY( This
->dp2
->replysExpected
, replysExpected
, replyExpected
.wExpectedReply
,
550 ==, wCommandId
, lpReplyList
);
551 LeaveCriticalSection( &This
->unk
->DP_lock
);
553 if( lpReplyList
== NULL
)
555 TRACE( "No receipt event set for cmd 0x%x\n", wCommandId
);
559 lpReplyList
->replyExpected
.dwMsgBodySize
= dwMsgBodySize
;
560 /* TODO: Can we avoid theese allocations? */
561 lpReplyList
->replyExpected
.lpReplyHdr
= HeapAlloc( GetProcessHeap(),
563 This
->dp2
->spData
.dwSPHeaderSize
);
564 lpReplyList
->replyExpected
.lpReplyMsg
= HeapAlloc( GetProcessHeap(),
567 CopyMemory( lpReplyList
->replyExpected
.lpReplyHdr
,
568 lpcMsgHdr
, This
->dp2
->spData
.dwSPHeaderSize
);
569 CopyMemory( lpReplyList
->replyExpected
.lpReplyMsg
,
570 lpcMsgBody
, dwMsgBodySize
);
572 /* Signal the thread which sent the message that it has a reply */
573 SetEvent( lpReplyList
->replyExpected
.hReceipt
);
578 DWORD
DP_CopyString( LPVOID destination
, LPVOID source
, BOOL bAnsi
)
580 /* Copies an ASCII string (bAnsi=TRUE) or a wide string (bAnsi=FALSE)
581 * from source to the previously allocated destination buffer.
582 * The destination string will be always wide.
583 * If destination is NULL, doesn't perform the copy but the
584 * returned size is still correct.
586 * Returns: The size in bytes of the written string. */
590 if ( source
== NULL
)
595 dwLength
= MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1, NULL
, 0 );
597 MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1,
598 (LPWSTR
) destination
, dwLength
);
602 dwLength
= lstrlenW( (LPWSTR
) source
) + 1;
604 CopyMemory( destination
, source
, dwLength
);
607 return dwLength
* sizeof(WCHAR
);
610 static DWORD
DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
611 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
,
616 /* Fills lpPackedPlayer with the information in lpData.
617 * lpData can be a player or a group.
618 * If lpPackedPlayer is NULL just returns the size
619 * needed to pack the player.
621 * Returns: the size of the written data in bytes */
623 #define PLAYER_OR_GROUP( bIsGroup, lpData, field ) \
625 ? ((lpGroupData) lpData)->field \
626 : ((lpPlayerData) lpData)->field )
628 DWORD offset
, length
, size
;
631 if ( lpPackedPlayer
== NULL
)
633 size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
); /* Fixed data */
634 size
+= DP_CopyString( NULL
, /* Short name */
635 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
637 size
+= DP_CopyString( NULL
, /* Long name */
638 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
640 /* Player data length */
650 /* Shortcut ID Count */
656 lpPackedPlayer
->Size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
);
658 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
659 lpPackedPlayer
->ID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
661 if ( lpPackedPlayer
->Flags
& DPLAYI_PLAYER_SYSPLAYER
)
663 lpPackedPlayer
->VersionOrSystemPlayerID
= DX61AVERSION
;
667 lpPackedPlayer
->VersionOrSystemPlayerID
=
668 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
671 offset
= lpPackedPlayer
->Size
;
674 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
675 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
678 lpPackedPlayer
->PlayerInfoMask
|= SPP_SN
;
682 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
683 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
686 lpPackedPlayer
->PlayerInfoMask
|= SPP_LN
;
690 length
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
693 size
= spp_get_optimum_size( length
);
694 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PD_OFFSET
);
695 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
698 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
699 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
704 /* Service provider data */
705 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
, lpPackedPlayer
->ID
,
706 &playerSPData
, &length
, DPGET_REMOTE
);
709 size
= spp_get_optimum_size( length
);
710 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_SL_OFFSET
);
711 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
713 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
, length
);
720 if( !DPQ_IS_EMPTY( ((lpGroupData
)lpData
)->players
) )
722 DWORD player_count
, offset_PC
;
723 lpPlayerList lpPList
;
725 offset_PC
= offset
; /* Space for PlayerCount */
730 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
734 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
735 &lpPList
->lpPData
->dpid
,
737 offset
+= sizeof(DPID
);
740 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
744 size
= spp_get_optimum_size( player_count
);
745 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PC_OFFSET
);
747 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset_PC
, &player_count
, size
);
751 if ( ((lpGroupData
)lpData
)->parent
)
753 lpPackedPlayer
->PlayerInfoMask
|= SPP_PI
;
754 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
755 &((lpGroupData
)lpData
)->parent
,
757 offset
+= sizeof(DWORD
);
761 /*size = spp_get_optimum_size( ___ );
762 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
763 FIXME( "TODO: Add shortcut IDs\n" );
769 static DWORD
DP_MSG_FillPackedPlayer( IDirectPlay2Impl
* lpDP
,
770 LPDPLAYI_PACKEDPLAYER lpPackedPlayer
,
775 /* Fills lpPackedPlayer with the information in lpData.
776 * lpData can be a player or a group.
777 * If lpPackedPlayer is NULL just returns the size
778 * needed to pack the player.
780 * Returns: the size of the written data in bytes */
785 if ( lpPackedPlayer
== NULL
)
788 size
= sizeof(DPLAYI_PACKEDPLAYER
); /* Fixed data */
789 size
+= DP_CopyString( NULL
, /* Short name */
790 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
792 size
+= DP_CopyString( NULL
, /* Long name */
793 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
805 lpPackedPlayer
->SystemPlayerID
=
806 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
807 lpPackedPlayer
->FixedSize
= sizeof(DPLAYI_PACKEDPLAYER
);
808 lpPackedPlayer
->PlayerVersion
= DX61AVERSION
;
810 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
811 lpPackedPlayer
->PlayerID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
812 lpPackedPlayer
->ParentID
= ( bIsGroup
813 ? ((lpGroupData
)lpData
)->parent
816 offset
= lpPackedPlayer
->FixedSize
;
819 lpPackedPlayer
->ShortNameLength
=
820 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
821 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
823 offset
+= lpPackedPlayer
->ShortNameLength
;
826 lpPackedPlayer
->LongNameLength
=
827 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
828 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
830 offset
+= lpPackedPlayer
->LongNameLength
;
832 /* Service provider data */
833 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
,
834 lpPackedPlayer
->PlayerID
,
836 &lpPackedPlayer
->ServiceProviderDataSize
,
838 if ( lpPackedPlayer
->ServiceProviderDataSize
)
840 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
,
841 lpPackedPlayer
->ServiceProviderDataSize
);
842 offset
+= lpPackedPlayer
->ServiceProviderDataSize
;
846 lpPackedPlayer
->PlayerDataSize
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
847 if ( lpPackedPlayer
->PlayerDataSize
)
849 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
850 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
851 lpPackedPlayer
->PlayerDataSize
);
852 offset
+= lpPackedPlayer
->PlayerDataSize
;
857 lpPlayerList lpPList
;
860 lpPackedPlayer
->NumberOfPlayers
= 0;
862 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
866 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
867 &lpPList
->lpPData
->dpid
,
869 offset
+= sizeof(DPID
);
870 lpPackedPlayer
->NumberOfPlayers
++;
872 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
878 lpPackedPlayer
->Size
= offset
;
880 return lpPackedPlayer
->Size
;
883 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl
* lpDP
,
885 LPDWORD lpdwMsgSize
)
887 /* Depending on the type of session, builds either a EnumPlayers
888 reply or a SuperEnumPlayers reply, and places it in lplpReply */
890 /* TODO: Find size to allocate *lplpReply
891 * Check if we're releasing that memory */
893 LPDPSP_MSG_ENUMPLAYERSREPLY lpReply
; /* Also valid in the SUPER case */
894 lpPlayerList lpPList
;
897 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
900 *lplpReply
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 1024 );
901 lpReply
= (LPDPSP_MSG_ENUMPLAYERSREPLY
)( (LPBYTE
)(*lplpReply
) +
902 lpDP
->dp2
->spData
.dwSPHeaderSize
);
904 lpReply
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
905 lpReply
->envelope
.wVersion
= DX61AVERSION
;
907 if ( lpDP
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_CLIENTSERVER
)
909 lpReply
->envelope
.wCommandId
= DPMSGCMD_ENUMPLAYERSREPLY
;
913 lpReply
->envelope
.wCommandId
= DPMSGCMD_SUPERENUMPLAYERSREPLY
;
917 /* Session description */
918 lpReply
->DescriptionOffset
= ( sizeof(DPSP_MSG_ENUMPLAYERSREPLY
) -
919 sizeof(DPSESSIONDESC2
) );
920 CopyMemory( &lpReply
->DPSessionDesc
, lpDP
->dp2
->lpSessionDesc
,
921 sizeof(DPSESSIONDESC2
) );
923 offset
= sizeof(DPSP_MSG_ENUMPLAYERSREPLY
);
926 if ( lpDP
->dp2
->lpSessionDesc
->lpszSessionName
)
928 lpReply
->NameOffset
= offset
;
929 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
930 lpDP
->dp2
->lpSessionDesc
->lpszSessionName
,
934 /* Session password */
935 if ( lpDP
->dp2
->lpSessionDesc
->lpszPassword
)
937 lpReply
->PasswordOffset
= offset
;
938 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
939 lpDP
->dp2
->lpSessionDesc
->lpszPassword
,
943 /* Populate PlayerInfo list */
946 if ( (lpPList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)) )
950 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
952 offset
+= DP_MSG_FillSuperPackedPlayer(
953 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
954 lpPList
->lpPData
, FALSE
, bAnsi
);
958 offset
+= DP_MSG_FillPackedPlayer(
959 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
960 lpPList
->lpPData
, FALSE
, bAnsi
);
963 lpReply
->PlayerCount
++;
965 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
969 if ( (lpGList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->groups
)) )
973 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
975 offset
+= DP_MSG_FillSuperPackedPlayer(
976 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
977 lpGList
->lpGData
, TRUE
, bAnsi
);
981 offset
+= DP_MSG_FillPackedPlayer(
982 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
983 lpGList
->lpGData
, TRUE
, bAnsi
);
986 lpReply
->GroupCount
++;
988 while( (lpGList
= DPQ_NEXT( lpGList
->groups
)) );
991 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
993 /* - Groups with shortcuts */
994 FIXME( "TODO: Add shortcut IDs\n" );
997 *lpdwMsgSize
= lpDP
->dp2
->spData
.dwSPHeaderSize
+ offset
;