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_ParseSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
54 LPBYTE lpPackedPlayer
,
55 LPPACKEDPLAYERDATA lpData
,
58 static DWORD
DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
59 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
,
63 static DWORD
DP_MSG_FillPackedPlayer( IDirectPlay2Impl
* lpDP
,
64 LPDPLAYI_PACKEDPLAYER lpPackedPlayer
,
68 static HRESULT
DP_MSG_ParsePlayerEnumeration( IDirectPlay2Impl
* lpDP
,
71 static DWORD
DP_MSG_ParseSessionDesc( IDirectPlay2Impl
* lpDP
,
72 LPDPSESSIONDESC2 lpSessionDesc
,
73 LPWSTR lpszSessionName
,
74 LPWSTR lpszPassword
);
75 DWORD
DP_CopyString( LPVOID destination
, LPVOID source
, BOOL bAnsi
);
78 /* Create the message reception thread to allow the application to receive
79 * asynchronous message reception
81 DWORD
CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent
, HANDLE hStart
,
82 HANDLE hDeath
, HANDLE hConnRead
)
85 LPMSGTHREADINFO lpThreadInfo
;
87 lpThreadInfo
= HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo
) );
88 if( lpThreadInfo
== NULL
)
93 /* The notify event may or may not exist. Depends if async comm or not */
95 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent
,
96 GetCurrentProcess(), &lpThreadInfo
->hNotifyEvent
,
97 0, FALSE
, DUPLICATE_SAME_ACCESS
) )
99 ERR( "Unable to duplicate event handle\n" );
103 /* These 3 handles don't need to be duplicated because we don't keep a
104 * reference to them where they're created. They're created specifically
105 * for the message thread
107 lpThreadInfo
->hStart
= hStart
;
108 lpThreadInfo
->hDeath
= hDeath
;
109 lpThreadInfo
->hSettingRead
= hConnRead
;
111 if( !CreateThread( NULL
, /* Security attribs */
113 DPL_MSG_ThreadMain
, /* Msg reception function */
114 lpThreadInfo
, /* Msg reception func parameter */
116 &dwMsgThreadId
/* Updated with thread id */
120 ERR( "Unable to create msg thread\n" );
124 /* FIXME: Should I be closing the handle to the thread or does that
125 terminate the thread? */
127 return dwMsgThreadId
;
131 HeapFree( GetProcessHeap(), 0, lpThreadInfo
);
136 static DWORD CALLBACK
DPL_MSG_ThreadMain( LPVOID lpContext
)
138 LPMSGTHREADINFO lpThreadInfo
= lpContext
;
141 TRACE( "Msg thread created. Waiting on app startup\n" );
143 /* Wait to ensure that the lobby application is started w/ 1 min timeout */
144 dwWaitResult
= WaitForSingleObject( lpThreadInfo
->hStart
, 10000 /* 10 sec */ );
145 if( dwWaitResult
== WAIT_TIMEOUT
)
147 FIXME( "Should signal app/wait creation failure (0x%08x)\n", dwWaitResult
);
151 /* Close this handle as it's not needed anymore */
152 CloseHandle( lpThreadInfo
->hStart
);
153 lpThreadInfo
->hStart
= 0;
155 /* Wait until the lobby knows what it is */
156 dwWaitResult
= WaitForSingleObject( lpThreadInfo
->hSettingRead
, INFINITE
);
157 if( dwWaitResult
== WAIT_TIMEOUT
)
159 ERR( "App Read connection setting timeout fail (0x%08x)\n", dwWaitResult
);
162 /* Close this handle as it's not needed anymore */
163 CloseHandle( lpThreadInfo
->hSettingRead
);
164 lpThreadInfo
->hSettingRead
= 0;
166 TRACE( "App created && initialized starting main message reception loop\n" );
171 GetMessageW( &lobbyMsg
, 0, 0, 0 );
175 TRACE( "Msg thread exiting!\n" );
176 HeapFree( GetProcessHeap(), 0, lpThreadInfo
);
181 /* DP messaging stuff */
182 static HANDLE
DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl
* This
,
183 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
184 WORD wReplyCommandId
);
185 static LPVOID
DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
186 LPVOID
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
187 LPDWORD lpdwMsgBodySize
);
191 HANDLE
DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl
* This
,
192 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
, WORD wReplyCommandId
)
194 lpReplyStructList
->replyExpected
.hReceipt
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
195 lpReplyStructList
->replyExpected
.wExpectedReply
= wReplyCommandId
;
196 lpReplyStructList
->replyExpected
.lpReplyHdr
= NULL
;
197 lpReplyStructList
->replyExpected
.lpReplyMsg
= NULL
;
198 lpReplyStructList
->replyExpected
.dwMsgBodySize
= 0;
200 /* Insert into the message queue while locked */
201 EnterCriticalSection( &This
->unk
->DP_lock
);
202 DPQ_INSERT( This
->dp2
->replysExpected
, lpReplyStructList
, replysExpected
);
203 LeaveCriticalSection( &This
->unk
->DP_lock
);
205 return lpReplyStructList
->replyExpected
.hReceipt
;
209 LPVOID
DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList
,
210 LPVOID
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
211 LPDWORD lpdwMsgBodySize
)
213 CloseHandle( lpReplyStructList
->replyExpected
.hReceipt
);
217 *lplpReplyHdr
= lpReplyStructList
->replyExpected
.lpReplyHdr
;
220 *lplpReplyMsg
= lpReplyStructList
->replyExpected
.lpReplyMsg
;
221 *lpdwMsgBodySize
= lpReplyStructList
->replyExpected
.dwMsgBodySize
;
223 return lpReplyStructList
->replyExpected
.lpReplyMsg
;
226 HRESULT
DP_MSG_PackMessage( IDirectPlay2AImpl
* This
, LPVOID
* lpMsg
,
227 LPDWORD lpMessageSize
)
230 LPDPSP_MSG_PACKET lpPacketBody
;
232 TRACE( "Packing message with command 0x%x\n",
233 ( (LPDPSP_MSG_ENVELOPE
)
234 (((LPBYTE
) *lpMsg
) + This
->dp2
->spData
.dwSPHeaderSize
))->wCommandId
);
235 FIXME( "TODO: Segment the package if needed\n" );
237 lpPacket
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
238 *lpMessageSize
+ sizeof(DPSP_MSG_PACKET
) );
239 lpPacketBody
= (LPDPSP_MSG_PACKET
)( (LPBYTE
) lpPacket
+
240 This
->dp2
->spData
.dwSPHeaderSize
);
242 /* TODO: When do we have to send a DPMSGCMD_PACKET2_DATA? */
243 lpPacketBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
244 lpPacketBody
->envelope
.wCommandId
= DPMSGCMD_PACKET
;
245 lpPacketBody
->envelope
.wVersion
= DX61AVERSION
;
247 CoCreateGuid( &lpPacketBody
->GuidMessage
);
248 lpPacketBody
->PacketIndex
= 0;
249 lpPacketBody
->DataSize
= *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
;
250 lpPacketBody
->Offset
= 0;
251 lpPacketBody
->TotalPackets
= 1;
252 lpPacketBody
->MessageSize
= *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
;
253 lpPacketBody
->PackedOffset
= 0;
255 /* Copy the header of the original message */
256 CopyMemory( lpPacket
, *lpMsg
, This
->dp2
->spData
.dwSPHeaderSize
);
257 /* Copy the body of the original message */
258 CopyMemory( lpPacketBody
+ 1,
259 ((LPBYTE
) *lpMsg
) + This
->dp2
->spData
.dwSPHeaderSize
,
260 *lpMessageSize
- This
->dp2
->spData
.dwSPHeaderSize
);
261 *lpMessageSize
+= sizeof(DPSP_MSG_PACKET
);
263 HeapFree( GetProcessHeap(), 0, *lpMsg
);
269 HRESULT
DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl
* This
, DWORD dwFlags
,
270 LPDPID lpdpidAllocatedId
)
273 LPDPSP_MSG_REQUESTPLAYERID lpMsgBody
;
277 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+ sizeof( *lpMsgBody
);
279 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
281 lpMsgBody
= (LPDPSP_MSG_REQUESTPLAYERID
)( (LPBYTE
)lpMsg
+
282 This
->dp2
->spData
.dwSPHeaderSize
);
284 /* Compose dplay message envelope */
285 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
286 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_REQUESTPLAYERID
;
287 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
289 /* Compose the body of the message */
290 lpMsgBody
->Flags
= dwFlags
;
292 /* Send the message */
296 data
.dwFlags
= DPSEND_GUARANTEED
;
297 data
.idPlayerTo
= 0; /* Name server */
298 data
.idPlayerFrom
= 0; /* Sending from DP */
299 data
.lpMessage
= lpMsg
;
300 data
.dwMessageSize
= dwMsgSize
;
301 data
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
302 data
.lpISP
= This
->dp2
->spData
.lpISP
;
304 TRACE( "Asking for player id w/ Flags 0x%08x\n", lpMsgBody
->Flags
);
306 lpMsg
= DP_MSG_ExpectReply( This
, &data
,
307 DPMSG_RELIABLE_API_TIMER
,
308 DPMSGCMD_REQUESTPLAYERREPLY
,
309 NULL
, &lpMsg
, &dwMsgSize
);
315 *lpdpidAllocatedId
= ((LPCDPSP_MSG_REQUESTPLAYERREPLY
) lpMsg
)->ID
;
316 TRACE( "Received new id 0x%08x\n", *lpdpidAllocatedId
);
320 ERR( "Didn't receive reply\n" );
324 HeapFree( GetProcessHeap(), 0, lpMsg
);
328 HRESULT
DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl
* This
, DPID dpidServer
)
330 LPBYTE lpMsg
, lpReply
, lpReplyHdr
;
331 LPDPSP_MSG_ADDFORWARDREQUEST lpMsgBody
;
332 DWORD dwMsgSize
, dwReplySize
, offset
, tick_count
;
333 lpPlayerList lpPList
;
334 DPSP_SENDDATA sendData
;
337 /* Check if player id is valid and get player data */
338 lpPList
= DP_FindPlayer( This
, dpidServer
);
339 if ( lpPList
== NULL
)
341 ERR( "Invalid ID 0x%08x\n", dpidServer
);
342 return DPERR_GENERIC
;
345 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+
346 sizeof(DPSP_MSG_ADDFORWARDREQUEST
) +
347 256 + /* Estimated max size for player data */
348 max( sizeof(WCHAR
), /* If password==NULL, we set a null unicode string */
350 This
->dp2
->lpSessionDesc
->lpszPassword
,
351 TRUE
) ) + /* Password */
352 sizeof(DWORD
); /* TickCount */
354 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
356 lpMsgBody
= (LPDPSP_MSG_ADDFORWARDREQUEST
)( lpMsg
+
357 This
->dp2
->spData
.dwSPHeaderSize
);
359 /* Compose dplay message envelope */
360 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
361 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_ADDFORWARDREQUEST
;
362 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
364 /* Compose body of message */
365 lpMsgBody
->IDTo
= 0; /* Name server */
366 lpMsgBody
->PlayerID
= dpidServer
;
367 lpMsgBody
->GroupID
= 0; /* Ignored */
368 lpMsgBody
->CreateOffset
= sizeof(DPSP_MSG_ADDFORWARDREQUEST
);
370 offset
= This
->dp2
->spData
.dwSPHeaderSize
+ lpMsgBody
->CreateOffset
;
373 offset
+= DP_MSG_FillPackedPlayer(
374 This
, (LPDPLAYI_PACKEDPLAYER
)( lpMsg
+ offset
),
375 lpPList
->lpPData
, FALSE
, TRUE
);
378 lpMsgBody
->PasswordOffset
= offset
;
379 if ( This
->dp2
->lpSessionDesc
->lpszPassword
)
381 offset
+= DP_CopyString( lpMsg
+ offset
,
382 This
->dp2
->lpSessionDesc
->lpszPassword
,
387 offset
+= sizeof(WCHAR
); /* Null unicode string */
391 tick_count
= GetTickCount();
392 CopyMemory( lpMsg
+ offset
, &tick_count
, sizeof(DWORD
) );
394 /* Recalculation of the exact message size */
395 dwMsgSize
= offset
+ sizeof(DWORD
);
397 /* Send the message and wait for reply */
398 sendData
.dwFlags
= DPSEND_GUARANTEED
;
399 sendData
.idPlayerTo
= 0; /* Name server */
400 sendData
.idPlayerFrom
= dpidServer
; /* Sending from session server */
401 sendData
.lpMessage
= lpMsg
;
402 sendData
.dwMessageSize
= dwMsgSize
;
403 sendData
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
404 sendData
.lpISP
= This
->dp2
->spData
.lpISP
;
406 TRACE( "Sending forward player request for id 0x%08x\n", dpidServer
);
409 lpReply
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwReplySize
);
411 DP_MSG_ExpectReply( This
, &sendData
,
412 DPMSG_RELIABLE_API_TIMER
,
413 DPMSGCMD_ADDFORWARDREPLY
,
414 (LPVOID
*) &lpReplyHdr
,
415 (LPVOID
*) &lpReply
, &dwReplySize
);
420 switch( ((LPDPSP_MSG_ENVELOPE
) lpReply
)->wCommandId
)
422 case DPMSGCMD_ADDFORWARDREPLY
:
424 hr
= ((LPDPSP_MSG_ADDFORWARDREPLY
) lpReply
)->Error
;
425 TRACE( "Received error code %s\n", DPLAYX_HresultToString(hr
) );
428 case DPMSGCMD_SUPERENUMPLAYERSREPLY
:
430 TRACE( "Received player enumeration\n" );
431 hr
= DP_MSG_ParsePlayerEnumeration( This
, lpReply
, lpReplyHdr
);
436 ERR( "Unknown reply with cmd 0x%x\n",
437 ((LPDPSP_MSG_ENVELOPE
) lpReply
)->wCommandId
);
444 ERR( "Didn't receive reply\n" );
448 HeapFree( GetProcessHeap(), 0, lpMsg
);
449 HeapFree( GetProcessHeap(), 0, lpReply
);
453 HRESULT
DP_MSG_SendCreatePlayer( IDirectPlay2AImpl
* This
, lpPlayerData lpData
)
456 LPDPSP_MSG_CREATEPLAYER lpMsgBody
;
457 DWORD dwMsgSize
, dwWrapperSize
;
460 TRACE( "(%p)->(0x%08x)\n", This
, lpData
->dpid
);
463 /* If the session supports multicast, wrap the message up into
464 * a DPSP_MSG_ASK4MULTICAST */
465 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
467 dwWrapperSize
= sizeof(DPSP_MSG_ASK4MULTICAST
);
475 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+
477 sizeof(DPSP_MSG_CREATEPLAYER
) +
478 256; /* Estimated max size for player data */
480 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
481 lpMsgBody
= (LPDPSP_MSG_CREATEPLAYER
)( lpMsg
+
482 This
->dp2
->spData
.dwSPHeaderSize
+
486 /* Fill wrapper if needed */
487 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
489 LPDPSP_MSG_ASK4MULTICAST lpWrapper
= (LPDPSP_MSG_ASK4MULTICAST
) lpMsg
;
491 lpWrapper
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
492 lpWrapper
->envelope
.wCommandId
= DPMSGCMD_CREATEPLAYER
;
493 lpWrapper
->envelope
.wVersion
= DX61AVERSION
;
495 lpWrapper
->GroupTo
= 0; /*TODO*/
496 lpWrapper
->PlayerFrom
= lpData
->dpid
;
497 lpWrapper
->MessageOffset
= sizeof(DPSP_MSG_ASK4MULTICAST
);
501 /* Compose dplay message envelope */
502 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
503 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_CREATEPLAYER
;
504 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
506 /* Compose body of message */
507 lpMsgBody
->IDTo
= 0; /* Name server */
508 lpMsgBody
->PlayerID
= lpData
->dpid
;
509 lpMsgBody
->GroupID
= 0; /* Ignored */
510 lpMsgBody
->CreateOffset
= sizeof(DPSP_MSG_CREATEPLAYER
);
511 lpMsgBody
->PasswordOffset
= 0; /* Ignored */
513 /* Add PlayerInfo and recalculation of exact message size */
514 dwMsgSize
-= 256; /* We estimated 256 */
515 dwMsgSize
+= DP_MSG_FillPackedPlayer(
517 (LPDPLAYI_PACKEDPLAYER
)(((LPBYTE
) lpMsgBody
) + lpMsgBody
->CreateOffset
),
518 lpData
, FALSE
, TRUE
);
521 /* If the session supports multicast, send message to the game host */
522 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
524 DPSP_SENDDATA sendData
;
525 sendData
.dwFlags
= DPSEND_GUARANTEED
;
526 sendData
.idPlayerTo
= 0; /* Name server */
527 sendData
.idPlayerFrom
= lpData
->dpid
;
528 sendData
.lpMessage
= lpMsg
;
529 sendData
.dwMessageSize
= dwMsgSize
;
530 sendData
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
531 sendData
.lpISP
= This
->dp2
->spData
.lpISP
;
533 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( &sendData
);
535 /* Otherwise, send the message to each player in the session */
538 lpPlayerList lpPList
;
539 DPSP_SENDDATA sendData
;
540 sendData
.dwFlags
= DPSEND_GUARANTEED
;
541 sendData
.idPlayerFrom
= lpData
->dpid
;
542 sendData
.lpMessage
= lpMsg
;
543 sendData
.dwMessageSize
= dwMsgSize
;
544 sendData
.bSystemMessage
= TRUE
;
545 sendData
.lpISP
= This
->dp2
->spData
.lpISP
;
547 if ( (lpPList
= DPQ_FIRST( This
->dp2
->lpSysGroup
->players
)) )
551 if ( ( lpPList
->lpPData
->dwFlags
& DPLAYI_PLAYER_SYSPLAYER
) &&
552 ( ~lpPList
->lpPData
->dwFlags
& DPLAYI_PLAYER_PLAYERLOCAL
) )
554 sendData
.idPlayerTo
= lpPList
->lpPData
->dpid
;
555 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( &sendData
);
558 ERR( "Failed to send message to 0x%08x\n", sendData
.idPlayerTo
);
562 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
567 HeapFree( GetProcessHeap(), 0, lpMsg
);
571 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
572 * not seem to offer any way of uniquely differentiating between replies of the same type
573 * relative to the request sent. There is an implicit assumption that there will be no
574 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
575 * a networking company.
578 LPVOID
DP_MSG_ExpectReply( IDirectPlay2AImpl
* This
, LPDPSP_SENDDATA lpData
,
579 DWORD dwWaitTime
, WORD wReplyCommandId
,
580 LPVOID
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
581 LPDWORD lpdwMsgBodySize
)
585 DP_MSG_REPLY_STRUCT_LIST replyStructList
;
589 /* Setup for receipt */
590 hMsgReceipt
= DP_MSG_BuildAndLinkReplyStruct( This
, &replyStructList
,
593 wCommandId
= ((LPCDPSP_MSG_ENVELOPE
)
594 ( ((LPBYTE
) lpData
->lpMessage
) +
595 This
->dp2
->spData
.dwSPHeaderSize
))->wCommandId
;
596 TRACE( "Sending cmd 0x%x and expecting cmd 0x%x in reply within %u ticks\n",
597 wCommandId
, wReplyCommandId
, dwWaitTime
);
598 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( lpData
);
602 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr
) );
606 /* The reply message will trigger the hMsgReceipt event effectively switching
607 * control back to this thread. See DP_MSG_ReplyReceived.
609 dwWaitReturn
= WaitForSingleObject( hMsgReceipt
, dwWaitTime
);
610 if( dwWaitReturn
!= WAIT_OBJECT_0
)
612 ERR( "Wait failed 0x%08x\n", dwWaitReturn
);
617 return DP_MSG_CleanReplyStruct( &replyStructList
, lplpReplyHdr
,
618 lplpReplyMsg
, lpdwMsgBodySize
);
621 /* Determine if there is a matching request for this incoming message and then copy
622 * all important data. It is quite silly to have to copy the message, but the documents
623 * indicate that a copy is taken. Silly really.
625 BOOL
DP_MSG_ReplyReceived( IDirectPlay2AImpl
* This
, WORD wCommandId
,
626 LPCVOID lpcMsgHdr
, LPCVOID lpcMsgBody
,
627 DWORD dwMsgBodySize
)
629 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList
;
631 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
634 EnterCriticalSection( &This
->unk
->DP_lock
);
635 DPQ_REMOVE_ENTRY( This
->dp2
->replysExpected
, replysExpected
, replyExpected
.wExpectedReply
,
636 ==, wCommandId
, lpReplyList
);
637 LeaveCriticalSection( &This
->unk
->DP_lock
);
639 if( lpReplyList
== NULL
)
641 TRACE( "No receipt event set for cmd 0x%x\n", wCommandId
);
645 lpReplyList
->replyExpected
.dwMsgBodySize
= dwMsgBodySize
;
646 /* TODO: Can we avoid theese allocations? */
647 lpReplyList
->replyExpected
.lpReplyHdr
= HeapAlloc( GetProcessHeap(),
649 This
->dp2
->spData
.dwSPHeaderSize
);
650 lpReplyList
->replyExpected
.lpReplyMsg
= HeapAlloc( GetProcessHeap(),
653 CopyMemory( lpReplyList
->replyExpected
.lpReplyHdr
,
654 lpcMsgHdr
, This
->dp2
->spData
.dwSPHeaderSize
);
655 CopyMemory( lpReplyList
->replyExpected
.lpReplyMsg
,
656 lpcMsgBody
, dwMsgBodySize
);
658 /* Signal the thread which sent the message that it has a reply */
659 SetEvent( lpReplyList
->replyExpected
.hReceipt
);
664 DWORD
DP_CopyString( LPVOID destination
, LPVOID source
, BOOL bAnsi
)
666 /* Copies an ASCII string (bAnsi=TRUE) or a wide string (bAnsi=FALSE)
667 * from source to the previously allocated destination buffer.
668 * The destination string will be always wide.
669 * If destination is NULL, doesn't perform the copy but the
670 * returned size is still correct.
672 * Returns: The size in bytes of the written string. */
676 if ( source
== NULL
)
681 dwLength
= MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1, NULL
, 0 );
683 MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1,
684 (LPWSTR
) destination
, dwLength
);
688 dwLength
= lstrlenW( (LPWSTR
) source
) + 1;
690 CopyMemory( destination
, source
, dwLength
);
693 return dwLength
* sizeof(WCHAR
);
696 static DWORD
DP_MSG_ParseSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
697 LPBYTE lpPackedPlayer
,
698 LPPACKEDPLAYERDATA lpData
,
704 ZeroMemory( lpData
, sizeof(LPPACKEDPLAYERDATA
) );
705 offset
= sizeof(DPLAYI_SUPERPACKEDPLAYER
);
708 lpData
->name
.dwSize
= sizeof(DPNAME
);
711 if ( ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
& SPP_SN
)
713 size
= (lstrlenW((LPWSTR
) (lpPackedPlayer
+ offset
)) + 1) * sizeof(WCHAR
);
714 lpData
->name
.lpszShortName
= (LPWSTR
) (lpPackedPlayer
+ offset
);
718 /* lpData->name.lpszShortName and lpData->name.lpszShortNameA point to
719 * the same memory location, but if we're using an ANSI interface we'll
720 * no longer need the wide string version of the name, and the space in
721 * the buffer is always more than enough to allocate the ASCII version. */
722 WideCharToMultiByte( CP_ACP
, 0, lpData
->name
.lpszShortName
, -1,
723 lpData
->name
.lpszShortNameA
,
724 size
/sizeof(WCHAR
), NULL
, NULL
);
728 if ( ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
& SPP_LN
)
730 size
= (lstrlenW((LPWSTR
) (lpPackedPlayer
+ offset
)) + 1) * sizeof(WCHAR
);
731 lpData
->name
.lpszLongName
= (LPWSTR
) (lpPackedPlayer
+ offset
);
735 WideCharToMultiByte( CP_ACP
, 0, lpData
->name
.lpszLongName
, -1,
736 lpData
->name
.lpszLongNameA
,
737 size
/sizeof(WCHAR
), NULL
, NULL
);
742 size
= spp_flags2size(
743 ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
, SPP_SL_OFFSET
);
746 CopyMemory( &lpData
->dwPlayerSPDataSize
,
747 lpPackedPlayer
+ offset
, size
);
749 lpData
->lpPlayerSPData
= lpPackedPlayer
+ offset
;
750 offset
+= lpData
->dwPlayerSPDataSize
;
754 size
= spp_flags2size(
755 ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
, SPP_PD_OFFSET
);
758 CopyMemory( &lpData
->dwPlayerDataSize
,
759 lpPackedPlayer
+ offset
, size
);
761 lpData
->lpPlayerData
= lpPackedPlayer
+ offset
;
762 offset
+= lpData
->dwPlayerDataSize
;
768 size
= spp_flags2size(
769 ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
, SPP_PC_OFFSET
);
772 CopyMemory( &lpData
->dwPlayerCount
,
773 lpPackedPlayer
+ offset
, size
);
775 lpData
->lpPlayerIDs
= (LPDPID
) (lpPackedPlayer
+ offset
);
776 offset
+= lpData
->dwPlayerCount
* sizeof(DPID
);
780 if ( ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
& SPP_PI
)
782 lpData
->parentID
= (DPID
) *(lpPackedPlayer
+ offset
);
783 offset
+= sizeof(DPID
);
787 size
= spp_flags2size(
788 ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
, SPP_SC_OFFSET
);
791 CopyMemory( &lpData
->dwShortcutCount
,
792 lpPackedPlayer
+ offset
, size
);
794 lpData
->lpShortcutIDs
= (LPDPID
) (lpPackedPlayer
+ offset
);
795 offset
+= lpData
->dwShortcutCount
* sizeof(DPID
);
802 DWORD
DP_MSG_ParsePackedPlayer( IDirectPlay2Impl
* lpDP
,
803 LPBYTE lpPackedPlayer
,
804 LPPACKEDPLAYERDATA lpData
,
809 LPDPLAYI_PACKEDPLAYER lpPackedPlayerData
=
810 (LPDPLAYI_PACKEDPLAYER
) lpPackedPlayer
;
812 ZeroMemory( lpData
, sizeof(LPPACKEDPLAYERDATA
) );
813 offset
= lpPackedPlayerData
->FixedSize
;
816 lpData
->name
.dwSize
= sizeof(DPNAME
);
819 if ( lpPackedPlayerData
->ShortNameLength
)
821 lpData
->name
.lpszShortName
= (LPWSTR
) (lpPackedPlayer
+ offset
);
822 offset
+= lpPackedPlayerData
->ShortNameLength
;
825 WideCharToMultiByte( CP_ACP
, 0, lpData
->name
.lpszShortName
, -1,
826 lpData
->name
.lpszShortNameA
,
827 lpPackedPlayerData
->ShortNameLength
/sizeof(WCHAR
),
833 if ( lpPackedPlayerData
->LongNameLength
)
835 lpData
->name
.lpszLongName
= (LPWSTR
) (lpPackedPlayer
+ offset
);
836 offset
+= lpPackedPlayerData
->LongNameLength
;
839 WideCharToMultiByte( CP_ACP
, 0, lpData
->name
.lpszLongName
, -1,
840 lpData
->name
.lpszLongNameA
,
841 lpPackedPlayerData
->LongNameLength
/sizeof(WCHAR
),
847 lpData
->dwPlayerSPDataSize
= lpPackedPlayerData
->ServiceProviderDataSize
;
848 if ( lpPackedPlayerData
->ServiceProviderDataSize
)
850 lpData
->lpPlayerSPData
= lpPackedPlayer
+ offset
;
851 offset
+= lpPackedPlayerData
->ServiceProviderDataSize
;
855 lpData
->dwPlayerDataSize
= lpPackedPlayerData
->PlayerDataSize
;
856 if ( lpPackedPlayerData
->PlayerDataSize
)
858 lpData
->lpPlayerData
= lpPackedPlayer
+ offset
;
859 offset
+= lpPackedPlayerData
->PlayerDataSize
;
865 lpData
->parentID
= lpPackedPlayerData
->ParentID
;
868 lpData
->dwPlayerCount
= lpPackedPlayerData
->NumberOfPlayers
;
869 if ( lpPackedPlayerData
->NumberOfPlayers
)
871 lpData
->lpPlayerIDs
= (LPDPID
)(lpPackedPlayer
+ offset
);
872 offset
+= lpPackedPlayerData
->NumberOfPlayers
;
879 static DWORD
DP_MSG_ParseSessionDesc( IDirectPlay2Impl
* lpDP
,
880 LPDPSESSIONDESC2 lpSessionDesc
,
881 LPWSTR lpszSessionName
,
882 LPWSTR lpszPassword
)
884 /* The "DPSessionDesc" field of a dplay network message represents a
885 * valid session description but its fields "lpszSessionName" and
886 * "lpszPassword" are set to null, while the actual strings sit after
887 * the session description.
888 * Theese strings are pointed by lpszSessionName and lpszPassword, which
889 * had to be calculated by the calling functiong adding the fields NameOffset
890 * and PasswordOffset to the base address of the message.
891 * Since this message buffer won't be used anymore, it's safe to copy this
892 * addresses to the dpSessionDesc struct and call SetSessionDesc in the
893 * calling function, which will copy all the data to a new SessionDesc
894 * struct owned by us.
895 * If this instance of dplay uses ANSI strings, we will have to transform
896 * the given wide strings, and we can do it in the same buffer, as place will
897 * be more than enough.
899 * Returns: The addition of the lengths of session name and password strings. */
902 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
906 if ( lpszSessionName
)
908 size
= lstrlenW( lpszSessionName
) + 1;
909 lpSessionDesc
->lpszSessionName
= lpszSessionName
;
912 WideCharToMultiByte( CP_ACP
, 0, lpSessionDesc
->lpszSessionName
, -1,
913 lpSessionDesc
->lpszSessionNameA
, size
,
916 offset
+= size
* sizeof(WCHAR
);
921 size
= lstrlenW( lpszPassword
) + 1;
922 lpSessionDesc
->lpszPassword
= lpszPassword
;
925 WideCharToMultiByte( CP_ACP
, 0, lpSessionDesc
->lpszPassword
, -1,
926 lpSessionDesc
->lpszPasswordA
, size
,
929 offset
+= size
* sizeof(WCHAR
);
936 static HRESULT
DP_MSG_ParsePlayerEnumeration( IDirectPlay2Impl
* lpDP
,
940 LPDPSP_MSG_ENUMPLAYERSREPLY lpMsgBody
=
941 (LPDPSP_MSG_ENUMPLAYERSREPLY
) lpMsg
;
942 PACKEDPLAYERDATA packedPlayerData
;
946 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
948 TRACE( "Received %d players, %d groups, %d shortcuts\n",
949 lpMsgBody
->PlayerCount
, lpMsgBody
->GroupCount
,
950 lpMsgBody
->ShortcutCount
);
952 offset
= sizeof(DPSP_MSG_ENUMPLAYERSREPLY
);
956 offset
+= DP_MSG_ParseSessionDesc( lpDP
, &lpMsgBody
->DPSessionDesc
,
957 ( lpMsgBody
->NameOffset
958 ? (LPWSTR
) (lpMsg
+ lpMsgBody
->NameOffset
)
960 ( lpMsgBody
->PasswordOffset
961 ? (LPWSTR
) (lpMsg
+ lpMsgBody
->PasswordOffset
)
964 /* Reset player counter, as it will be updated as we create players.
965 * Otherwise we can get players counted twice. */
966 lpMsgBody
->DPSessionDesc
.dwCurrentPlayers
= 0;
968 hr
= DP_SetSessionDesc( lpDP
, &lpMsgBody
->DPSessionDesc
, 0, FALSE
, bAnsi
);
970 TRACE( "Adding session %s, %d/%d\n",
971 debugstr_guid(&lpMsgBody
->DPSessionDesc
.guidInstance
),
972 lpMsgBody
->DPSessionDesc
.dwCurrentPlayers
,
973 lpMsgBody
->DPSessionDesc
.dwMaxPlayers
);
977 ERR( "Invalid session: %s\n", DPLAYX_HresultToString(hr
) );
982 for ( i
=0; i
<lpMsgBody
->PlayerCount
; i
++ )
984 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
=
985 (LPDPLAYI_SUPERPACKEDPLAYER
) (lpMsg
+ offset
);
987 ZeroMemory( &packedPlayerData
, sizeof(PACKEDPLAYERDATA
) );
989 if ( lpMsgBody
->envelope
.wCommandId
== DPMSGCMD_ENUMPLAYERSREPLY
)
991 offset
+= DP_MSG_ParsePackedPlayer( lpDP
, (LPBYTE
) lpPackedPlayer
,
997 offset
+= DP_MSG_ParseSuperPackedPlayer( lpDP
, (LPBYTE
) lpPackedPlayer
,
1002 if ( lpPackedPlayer
->Flags
& DPLAYI_PLAYER_PLAYERLOCAL
)
1004 /* Local players are no local anymore */
1005 lpPackedPlayer
->Flags
^= DPLAYI_PLAYER_PLAYERLOCAL
;
1008 TRACE( "Importing player 0x%08x, flags=0x%08x\n",
1010 lpPackedPlayer
->Flags
);
1012 hr
= DP_CreatePlayer( lpDP
, lpPackedPlayer
->ID
,
1013 &packedPlayerData
.name
,
1014 lpPackedPlayer
->Flags
,
1015 packedPlayerData
.lpPlayerData
,
1016 packedPlayerData
.dwPlayerDataSize
,
1017 NULL
, bAnsi
, NULL
);
1020 ERR( "Couldn't import player: %s\n", DPLAYX_HresultToString(hr
) );
1024 hr
= IDirectPlaySP_SetSPPlayerData( lpDP
->dp2
->spData
.lpISP
,
1026 packedPlayerData
.lpPlayerSPData
,
1027 packedPlayerData
.dwPlayerSPDataSize
,
1031 ERR( "Couldn't set SP data: %s\n", DPLAYX_HresultToString(hr
) );
1035 /* Let the SP know that we've added this player */
1036 if( lpDP
->dp2
->spData
.lpCB
->CreatePlayer
)
1038 DPSP_CREATEPLAYERDATA data
;
1040 data
.idPlayer
= lpPackedPlayer
->ID
;
1041 data
.dwFlags
= lpPackedPlayer
->Flags
;
1042 data
.lpSPMessageHeader
= lpMsgHdr
;
1043 data
.lpISP
= lpDP
->dp2
->spData
.lpISP
;
1045 hr
= (*lpDP
->dp2
->spData
.lpCB
->CreatePlayer
)( &data
);
1049 ERR( "Couldn't create player with SP: %s\n", DPLAYX_HresultToString(hr
) );
1057 for ( i
=0; i
<lpMsgBody
->GroupCount
; i
++ )
1059 FIXME( "TODO: parse groups\n" );
1062 for ( i
=0; i
<lpMsgBody
->ShortcutCount
; i
++ )
1064 FIXME( "TODO: parse shortcuts\n" );
1070 static DWORD
DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
1071 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
,
1076 /* Fills lpPackedPlayer with the information in lpData.
1077 * lpData can be a player or a group.
1078 * If lpPackedPlayer is NULL just returns the size
1079 * needed to pack the player.
1081 * Returns: the size of the written data in bytes */
1083 #define PLAYER_OR_GROUP( bIsGroup, lpData, field ) \
1085 ? ((lpGroupData) lpData)->field \
1086 : ((lpPlayerData) lpData)->field )
1088 DWORD offset
, length
, size
;
1089 LPVOID playerSPData
;
1091 if ( lpPackedPlayer
== NULL
)
1093 size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
); /* Fixed data */
1094 size
+= DP_CopyString( NULL
, /* Short name */
1095 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1097 size
+= DP_CopyString( NULL
, /* Long name */
1098 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1100 /* Player data length */
1102 /* SP data length */
1110 /* Shortcut ID Count */
1116 lpPackedPlayer
->Size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
);
1118 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
1119 lpPackedPlayer
->ID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
1121 if ( lpPackedPlayer
->Flags
& DPLAYI_PLAYER_SYSPLAYER
)
1123 lpPackedPlayer
->VersionOrSystemPlayerID
= DX61AVERSION
;
1127 lpPackedPlayer
->VersionOrSystemPlayerID
=
1128 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
1131 offset
= lpPackedPlayer
->Size
;
1134 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
1135 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1138 lpPackedPlayer
->PlayerInfoMask
|= SPP_SN
;
1142 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
1143 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
1146 lpPackedPlayer
->PlayerInfoMask
|= SPP_LN
;
1150 length
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
1153 size
= spp_get_optimum_size( length
);
1154 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PD_OFFSET
);
1155 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
1158 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1159 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
1164 /* Service provider data */
1165 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
, lpPackedPlayer
->ID
,
1166 &playerSPData
, &length
, DPGET_REMOTE
);
1169 size
= spp_get_optimum_size( length
);
1170 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_SL_OFFSET
);
1171 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
1173 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
, length
);
1180 if( !DPQ_IS_EMPTY( ((lpGroupData
)lpData
)->players
) )
1182 DWORD player_count
, offset_PC
;
1183 lpPlayerList lpPList
;
1185 offset_PC
= offset
; /* Space for PlayerCount */
1190 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
1194 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1195 &lpPList
->lpPData
->dpid
,
1197 offset
+= sizeof(DPID
);
1200 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
1204 size
= spp_get_optimum_size( player_count
);
1205 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PC_OFFSET
);
1207 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset_PC
, &player_count
, size
);
1211 if ( ((lpGroupData
)lpData
)->parent
)
1213 lpPackedPlayer
->PlayerInfoMask
|= SPP_PI
;
1214 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1215 &((lpGroupData
)lpData
)->parent
,
1217 offset
+= sizeof(DWORD
);
1221 /*size = spp_get_optimum_size( ___ );
1222 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
1223 FIXME( "TODO: Add shortcut IDs\n" );
1229 static DWORD
DP_MSG_FillPackedPlayer( IDirectPlay2Impl
* lpDP
,
1230 LPDPLAYI_PACKEDPLAYER lpPackedPlayer
,
1235 /* Fills lpPackedPlayer with the information in lpData.
1236 * lpData can be a player or a group.
1237 * If lpPackedPlayer is NULL just returns the size
1238 * needed to pack the player.
1240 * Returns: the size of the written data in bytes */
1242 LPVOID playerSPData
;
1245 if ( lpPackedPlayer
== NULL
)
1248 size
= sizeof(DPLAYI_PACKEDPLAYER
); /* Fixed data */
1249 size
+= DP_CopyString( NULL
, /* Short name */
1250 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1252 size
+= DP_CopyString( NULL
, /* Long name */
1253 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
1265 lpPackedPlayer
->SystemPlayerID
=
1266 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
1267 lpPackedPlayer
->FixedSize
= sizeof(DPLAYI_PACKEDPLAYER
);
1268 lpPackedPlayer
->PlayerVersion
= DX61AVERSION
;
1270 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
1271 lpPackedPlayer
->PlayerID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
1272 lpPackedPlayer
->ParentID
= ( bIsGroup
1273 ? ((lpGroupData
)lpData
)->parent
1276 offset
= lpPackedPlayer
->FixedSize
;
1279 lpPackedPlayer
->ShortNameLength
=
1280 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
1281 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1283 offset
+= lpPackedPlayer
->ShortNameLength
;
1286 lpPackedPlayer
->LongNameLength
=
1287 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
1288 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
1290 offset
+= lpPackedPlayer
->LongNameLength
;
1292 /* Service provider data */
1293 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
,
1294 lpPackedPlayer
->PlayerID
,
1296 &lpPackedPlayer
->ServiceProviderDataSize
,
1298 if ( lpPackedPlayer
->ServiceProviderDataSize
)
1300 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
,
1301 lpPackedPlayer
->ServiceProviderDataSize
);
1302 offset
+= lpPackedPlayer
->ServiceProviderDataSize
;
1306 lpPackedPlayer
->PlayerDataSize
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
1307 if ( lpPackedPlayer
->PlayerDataSize
)
1309 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1310 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
1311 lpPackedPlayer
->PlayerDataSize
);
1312 offset
+= lpPackedPlayer
->PlayerDataSize
;
1317 lpPlayerList lpPList
;
1320 lpPackedPlayer
->NumberOfPlayers
= 0;
1322 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
1326 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1327 &lpPList
->lpPData
->dpid
,
1329 offset
+= sizeof(DPID
);
1330 lpPackedPlayer
->NumberOfPlayers
++;
1332 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
1338 lpPackedPlayer
->Size
= offset
;
1340 return lpPackedPlayer
->Size
;
1343 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl
* lpDP
,
1345 LPDWORD lpdwMsgSize
)
1347 /* Depending on the type of session, builds either a EnumPlayers
1348 reply or a SuperEnumPlayers reply, and places it in lplpReply */
1350 /* TODO: Find size to allocate *lplpReply
1351 * Check if we're releasing that memory */
1353 LPDPSP_MSG_ENUMPLAYERSREPLY lpReply
; /* Also valid in the SUPER case */
1354 lpPlayerList lpPList
;
1355 lpGroupList lpGList
;
1357 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
1360 *lplpReply
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 1024 );
1361 lpReply
= (LPDPSP_MSG_ENUMPLAYERSREPLY
)( (LPBYTE
)(*lplpReply
) +
1362 lpDP
->dp2
->spData
.dwSPHeaderSize
);
1364 lpReply
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
1365 lpReply
->envelope
.wVersion
= DX61AVERSION
;
1367 if ( lpDP
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_CLIENTSERVER
)
1369 lpReply
->envelope
.wCommandId
= DPMSGCMD_ENUMPLAYERSREPLY
;
1373 lpReply
->envelope
.wCommandId
= DPMSGCMD_SUPERENUMPLAYERSREPLY
;
1377 /* Session description */
1378 lpReply
->DescriptionOffset
= ( sizeof(DPSP_MSG_ENUMPLAYERSREPLY
) -
1379 sizeof(DPSESSIONDESC2
) );
1380 CopyMemory( &lpReply
->DPSessionDesc
, lpDP
->dp2
->lpSessionDesc
,
1381 sizeof(DPSESSIONDESC2
) );
1383 offset
= sizeof(DPSP_MSG_ENUMPLAYERSREPLY
);
1386 if ( lpDP
->dp2
->lpSessionDesc
->lpszSessionName
)
1388 lpReply
->NameOffset
= offset
;
1389 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
1390 lpDP
->dp2
->lpSessionDesc
->lpszSessionName
,
1394 /* Session password */
1395 if ( lpDP
->dp2
->lpSessionDesc
->lpszPassword
)
1397 lpReply
->PasswordOffset
= offset
;
1398 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
1399 lpDP
->dp2
->lpSessionDesc
->lpszPassword
,
1403 /* Populate PlayerInfo list */
1406 if ( (lpPList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)) )
1410 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
1412 offset
+= DP_MSG_FillSuperPackedPlayer(
1413 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
1414 lpPList
->lpPData
, FALSE
, bAnsi
);
1418 offset
+= DP_MSG_FillPackedPlayer(
1419 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
1420 lpPList
->lpPData
, FALSE
, bAnsi
);
1423 lpReply
->PlayerCount
++;
1425 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
1429 if ( (lpGList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->groups
)) )
1433 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
1435 offset
+= DP_MSG_FillSuperPackedPlayer(
1436 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
1437 lpGList
->lpGData
, TRUE
, bAnsi
);
1441 offset
+= DP_MSG_FillPackedPlayer(
1442 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
1443 lpGList
->lpGData
, TRUE
, bAnsi
);
1446 lpReply
->GroupCount
++;
1448 while( (lpGList
= DPQ_NEXT( lpGList
->groups
)) );
1451 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
1453 /* - Groups with shortcuts */
1454 FIXME( "TODO: Add shortcut IDs\n" );
1457 *lpdwMsgSize
= lpDP
->dp2
->spData
.dwSPHeaderSize
+ offset
;