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
)
331 LPDPSP_MSG_ADDFORWARDREQUEST lpMsgBody
;
335 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+ sizeof( *lpMsgBody
);
337 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
339 lpMsgBody
= (LPDPSP_MSG_ADDFORWARDREQUEST
)( (LPBYTE
)lpMsg
+
340 This
->dp2
->spData
.dwSPHeaderSize
);
342 /* Compose dplay message envelope */
343 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
344 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_ADDFORWARDREQUEST
;
345 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
347 /* Compose body of message */
350 /* Send the message */
354 data
.dwFlags
= DPSEND_GUARANTEED
;
355 data
.idPlayerTo
= 0; /* Name server */
356 data
.idPlayerFrom
= dpidServer
; /* Sending from session server */
357 data
.lpMessage
= lpMsg
;
358 data
.dwMessageSize
= dwMsgSize
;
359 data
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
360 data
.lpISP
= This
->dp2
->spData
.lpISP
;
362 TRACE( "Sending forward player request with 0x%08x\n", dpidServer
);
364 lpMsg
= DP_MSG_ExpectReply( This
, &data
,
365 DPMSG_RELIABLE_API_TIMER
,
367 NULL
, &lpMsg
, &dwMsgSize
);
370 /* Need to examine the data and extract the new player id */
373 FIXME( "Name Table reply received: stub\n" );
379 HRESULT
DP_MSG_SendCreatePlayer( IDirectPlay2AImpl
* This
, lpPlayerData lpData
)
382 LPDPSP_MSG_CREATEPLAYER lpMsgBody
;
383 DWORD dwMsgSize
, dwWrapperSize
;
386 TRACE( "(%p)->(0x%08x)\n", This
, lpData
->dpid
);
389 /* If the session supports multicast, wrap the message up into
390 * a DPSP_MSG_ASK4MULTICAST */
391 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
393 dwWrapperSize
= sizeof(DPSP_MSG_ASK4MULTICAST
);
401 dwMsgSize
= This
->dp2
->spData
.dwSPHeaderSize
+
403 sizeof(DPSP_MSG_CREATEPLAYER
) +
404 256; /* Estimated max size for player data */
406 lpMsg
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMsgSize
);
407 lpMsgBody
= (LPDPSP_MSG_CREATEPLAYER
)( lpMsg
+
408 This
->dp2
->spData
.dwSPHeaderSize
+
412 /* Fill wrapper if needed */
413 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
415 LPDPSP_MSG_ASK4MULTICAST lpWrapper
= (LPDPSP_MSG_ASK4MULTICAST
) lpMsg
;
417 lpWrapper
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
418 lpWrapper
->envelope
.wCommandId
= DPMSGCMD_CREATEPLAYER
;
419 lpWrapper
->envelope
.wVersion
= DX61AVERSION
;
421 lpWrapper
->GroupTo
= 0; /*TODO*/
422 lpWrapper
->PlayerFrom
= lpData
->dpid
;
423 lpWrapper
->MessageOffset
= sizeof(DPSP_MSG_ASK4MULTICAST
);
427 /* Compose dplay message envelope */
428 lpMsgBody
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
429 lpMsgBody
->envelope
.wCommandId
= DPMSGCMD_CREATEPLAYER
;
430 lpMsgBody
->envelope
.wVersion
= DX61AVERSION
;
432 /* Compose body of message */
433 lpMsgBody
->IDTo
= 0; /* Name server */
434 lpMsgBody
->PlayerID
= lpData
->dpid
;
435 lpMsgBody
->GroupID
= 0; /* Ignored */
436 lpMsgBody
->CreateOffset
= sizeof(DPSP_MSG_CREATEPLAYER
);
437 lpMsgBody
->PasswordOffset
= 0; /* Ignored */
439 /* Add PlayerInfo and recalculation of exact message size */
440 dwMsgSize
-= 256; /* We estimated 256 */
441 dwMsgSize
+= DP_MSG_FillPackedPlayer(
443 (LPDPLAYI_PACKEDPLAYER
)(((LPBYTE
) lpMsgBody
) + lpMsgBody
->CreateOffset
),
444 lpData
, FALSE
, TRUE
);
447 /* If the session supports multicast, send message to the game host */
448 if ( This
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_MULTICASTSERVER
)
450 DPSP_SENDDATA sendData
;
451 sendData
.dwFlags
= DPSEND_GUARANTEED
;
452 sendData
.idPlayerTo
= 0; /* Name server */
453 sendData
.idPlayerFrom
= lpData
->dpid
;
454 sendData
.lpMessage
= lpMsg
;
455 sendData
.dwMessageSize
= dwMsgSize
;
456 sendData
.bSystemMessage
= TRUE
; /* Allow reply to be sent */
457 sendData
.lpISP
= This
->dp2
->spData
.lpISP
;
459 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( &sendData
);
461 /* Otherwise, send the message to each player in the session */
464 lpPlayerList lpPList
;
465 DPSP_SENDDATA sendData
;
466 sendData
.dwFlags
= DPSEND_GUARANTEED
;
467 sendData
.idPlayerFrom
= lpData
->dpid
;
468 sendData
.lpMessage
= lpMsg
;
469 sendData
.dwMessageSize
= dwMsgSize
;
470 sendData
.bSystemMessage
= TRUE
;
471 sendData
.lpISP
= This
->dp2
->spData
.lpISP
;
473 if ( (lpPList
= DPQ_FIRST( This
->dp2
->lpSysGroup
->players
)) )
477 if ( ( lpPList
->lpPData
->dwFlags
& DPLAYI_PLAYER_SYSPLAYER
) &&
478 ( ~lpPList
->lpPData
->dwFlags
& DPLAYI_PLAYER_PLAYERLOCAL
) )
480 sendData
.idPlayerTo
= lpPList
->lpPData
->dpid
;
481 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( &sendData
);
484 ERR( "Failed to send message to 0x%08x\n", sendData
.idPlayerTo
);
488 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
493 HeapFree( GetProcessHeap(), 0, lpMsg
);
497 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
498 * not seem to offer any way of uniquely differentiating between replies of the same type
499 * relative to the request sent. There is an implicit assumption that there will be no
500 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
501 * a networking company.
504 LPVOID
DP_MSG_ExpectReply( IDirectPlay2AImpl
* This
, LPDPSP_SENDDATA lpData
,
505 DWORD dwWaitTime
, WORD wReplyCommandId
,
506 LPVOID
* lplpReplyHdr
, LPVOID
* lplpReplyMsg
,
507 LPDWORD lpdwMsgBodySize
)
511 DP_MSG_REPLY_STRUCT_LIST replyStructList
;
515 /* Setup for receipt */
516 hMsgReceipt
= DP_MSG_BuildAndLinkReplyStruct( This
, &replyStructList
,
519 wCommandId
= ((LPCDPSP_MSG_ENVELOPE
)
520 ( ((LPBYTE
) lpData
->lpMessage
) +
521 This
->dp2
->spData
.dwSPHeaderSize
))->wCommandId
;
522 TRACE( "Sending cmd 0x%x and expecting cmd 0x%x in reply within %u ticks\n",
523 wCommandId
, wReplyCommandId
, dwWaitTime
);
524 hr
= (*This
->dp2
->spData
.lpCB
->Send
)( lpData
);
528 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr
) );
532 /* The reply message will trigger the hMsgReceipt event effectively switching
533 * control back to this thread. See DP_MSG_ReplyReceived.
535 dwWaitReturn
= WaitForSingleObject( hMsgReceipt
, dwWaitTime
);
536 if( dwWaitReturn
!= WAIT_OBJECT_0
)
538 ERR( "Wait failed 0x%08x\n", dwWaitReturn
);
543 return DP_MSG_CleanReplyStruct( &replyStructList
, lplpReplyHdr
,
544 lplpReplyMsg
, lpdwMsgBodySize
);
547 /* Determine if there is a matching request for this incoming message and then copy
548 * all important data. It is quite silly to have to copy the message, but the documents
549 * indicate that a copy is taken. Silly really.
551 BOOL
DP_MSG_ReplyReceived( IDirectPlay2AImpl
* This
, WORD wCommandId
,
552 LPCVOID lpcMsgHdr
, LPCVOID lpcMsgBody
,
553 DWORD dwMsgBodySize
)
555 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList
;
557 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
560 EnterCriticalSection( &This
->unk
->DP_lock
);
561 DPQ_REMOVE_ENTRY( This
->dp2
->replysExpected
, replysExpected
, replyExpected
.wExpectedReply
,
562 ==, wCommandId
, lpReplyList
);
563 LeaveCriticalSection( &This
->unk
->DP_lock
);
565 if( lpReplyList
== NULL
)
567 TRACE( "No receipt event set for cmd 0x%x\n", wCommandId
);
571 lpReplyList
->replyExpected
.dwMsgBodySize
= dwMsgBodySize
;
572 /* TODO: Can we avoid theese allocations? */
573 lpReplyList
->replyExpected
.lpReplyHdr
= HeapAlloc( GetProcessHeap(),
575 This
->dp2
->spData
.dwSPHeaderSize
);
576 lpReplyList
->replyExpected
.lpReplyMsg
= HeapAlloc( GetProcessHeap(),
579 CopyMemory( lpReplyList
->replyExpected
.lpReplyHdr
,
580 lpcMsgHdr
, This
->dp2
->spData
.dwSPHeaderSize
);
581 CopyMemory( lpReplyList
->replyExpected
.lpReplyMsg
,
582 lpcMsgBody
, dwMsgBodySize
);
584 /* Signal the thread which sent the message that it has a reply */
585 SetEvent( lpReplyList
->replyExpected
.hReceipt
);
590 DWORD
DP_CopyString( LPVOID destination
, LPVOID source
, BOOL bAnsi
)
592 /* Copies an ASCII string (bAnsi=TRUE) or a wide string (bAnsi=FALSE)
593 * from source to the previously allocated destination buffer.
594 * The destination string will be always wide.
595 * If destination is NULL, doesn't perform the copy but the
596 * returned size is still correct.
598 * Returns: The size in bytes of the written string. */
602 if ( source
== NULL
)
607 dwLength
= MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1, NULL
, 0 );
609 MultiByteToWideChar( CP_ACP
, 0, (LPSTR
) source
, -1,
610 (LPWSTR
) destination
, dwLength
);
614 dwLength
= lstrlenW( (LPWSTR
) source
) + 1;
616 CopyMemory( destination
, source
, dwLength
);
619 return dwLength
* sizeof(WCHAR
);
622 static DWORD
DP_MSG_ParseSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
623 LPBYTE lpPackedPlayer
,
624 LPPACKEDPLAYERDATA lpData
,
630 ZeroMemory( lpData
, sizeof(LPPACKEDPLAYERDATA
) );
631 offset
= sizeof(DPLAYI_SUPERPACKEDPLAYER
);
634 lpData
->name
.dwSize
= sizeof(DPNAME
);
637 if ( ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
& SPP_SN
)
639 size
= (lstrlenW((LPWSTR
) (lpPackedPlayer
+ offset
)) + 1) * sizeof(WCHAR
);
640 lpData
->name
.lpszShortName
= (LPWSTR
) (lpPackedPlayer
+ offset
);
644 /* lpData->name.lpszShortName and lpData->name.lpszShortNameA point to
645 * the same memory location, but if we're using an ANSI interface we'll
646 * no longer need the wide string version of the name, and the space in
647 * the buffer is always more than enough to allocate the ASCII version. */
648 WideCharToMultiByte( CP_ACP
, 0, lpData
->name
.lpszShortName
, -1,
649 lpData
->name
.lpszShortNameA
,
650 size
/sizeof(WCHAR
), NULL
, NULL
);
654 if ( ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
& SPP_LN
)
656 size
= (lstrlenW((LPWSTR
) (lpPackedPlayer
+ offset
)) + 1) * sizeof(WCHAR
);
657 lpData
->name
.lpszLongName
= (LPWSTR
) (lpPackedPlayer
+ offset
);
661 WideCharToMultiByte( CP_ACP
, 0, lpData
->name
.lpszLongName
, -1,
662 lpData
->name
.lpszLongNameA
,
663 size
/sizeof(WCHAR
), NULL
, NULL
);
668 size
= spp_flags2size(
669 ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
, SPP_SL_OFFSET
);
672 CopyMemory( &lpData
->dwPlayerSPDataSize
,
673 lpPackedPlayer
+ offset
, size
);
675 lpData
->lpPlayerSPData
= lpPackedPlayer
+ offset
;
676 offset
+= lpData
->dwPlayerSPDataSize
;
680 size
= spp_flags2size(
681 ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
, SPP_PD_OFFSET
);
684 CopyMemory( &lpData
->dwPlayerDataSize
,
685 lpPackedPlayer
+ offset
, size
);
687 lpData
->lpPlayerData
= lpPackedPlayer
+ offset
;
688 offset
+= lpData
->dwPlayerDataSize
;
694 size
= spp_flags2size(
695 ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
, SPP_PC_OFFSET
);
698 CopyMemory( &lpData
->dwPlayerCount
,
699 lpPackedPlayer
+ offset
, size
);
701 lpData
->lpPlayerIDs
= (LPDPID
) (lpPackedPlayer
+ offset
);
702 offset
+= lpData
->dwPlayerCount
* sizeof(DPID
);
706 if ( ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
& SPP_PI
)
708 lpData
->parentID
= (DPID
) *(lpPackedPlayer
+ offset
);
709 offset
+= sizeof(DPID
);
713 size
= spp_flags2size(
714 ((LPDPLAYI_SUPERPACKEDPLAYER
) lpPackedPlayer
)->PlayerInfoMask
, SPP_SC_OFFSET
);
717 CopyMemory( &lpData
->dwShortcutCount
,
718 lpPackedPlayer
+ offset
, size
);
720 lpData
->lpShortcutIDs
= (LPDPID
) (lpPackedPlayer
+ offset
);
721 offset
+= lpData
->dwShortcutCount
* sizeof(DPID
);
728 DWORD
DP_MSG_ParsePackedPlayer( IDirectPlay2Impl
* lpDP
,
729 LPBYTE lpPackedPlayer
,
730 LPPACKEDPLAYERDATA lpData
,
735 LPDPLAYI_PACKEDPLAYER lpPackedPlayerData
=
736 (LPDPLAYI_PACKEDPLAYER
) lpPackedPlayer
;
738 ZeroMemory( lpData
, sizeof(LPPACKEDPLAYERDATA
) );
739 offset
= lpPackedPlayerData
->FixedSize
;
742 lpData
->name
.dwSize
= sizeof(DPNAME
);
745 if ( lpPackedPlayerData
->ShortNameLength
)
747 lpData
->name
.lpszShortName
= (LPWSTR
) (lpPackedPlayer
+ offset
);
748 offset
+= lpPackedPlayerData
->ShortNameLength
;
751 WideCharToMultiByte( CP_ACP
, 0, lpData
->name
.lpszShortName
, -1,
752 lpData
->name
.lpszShortNameA
,
753 lpPackedPlayerData
->ShortNameLength
/sizeof(WCHAR
),
759 if ( lpPackedPlayerData
->LongNameLength
)
761 lpData
->name
.lpszLongName
= (LPWSTR
) (lpPackedPlayer
+ offset
);
762 offset
+= lpPackedPlayerData
->LongNameLength
;
765 WideCharToMultiByte( CP_ACP
, 0, lpData
->name
.lpszLongName
, -1,
766 lpData
->name
.lpszLongNameA
,
767 lpPackedPlayerData
->LongNameLength
/sizeof(WCHAR
),
773 lpData
->dwPlayerSPDataSize
= lpPackedPlayerData
->ServiceProviderDataSize
;
774 if ( lpPackedPlayerData
->ServiceProviderDataSize
)
776 lpData
->lpPlayerSPData
= lpPackedPlayer
+ offset
;
777 offset
+= lpPackedPlayerData
->ServiceProviderDataSize
;
781 lpData
->dwPlayerDataSize
= lpPackedPlayerData
->PlayerDataSize
;
782 if ( lpPackedPlayerData
->PlayerDataSize
)
784 lpData
->lpPlayerData
= lpPackedPlayer
+ offset
;
785 offset
+= lpPackedPlayerData
->PlayerDataSize
;
791 lpData
->parentID
= lpPackedPlayerData
->ParentID
;
794 lpData
->dwPlayerCount
= lpPackedPlayerData
->NumberOfPlayers
;
795 if ( lpPackedPlayerData
->NumberOfPlayers
)
797 lpData
->lpPlayerIDs
= (LPDPID
)(lpPackedPlayer
+ offset
);
798 offset
+= lpPackedPlayerData
->NumberOfPlayers
;
805 static DWORD
DP_MSG_ParseSessionDesc( IDirectPlay2Impl
* lpDP
,
806 LPDPSESSIONDESC2 lpSessionDesc
,
807 LPWSTR lpszSessionName
,
808 LPWSTR lpszPassword
)
810 /* The "DPSessionDesc" field of a dplay network message represents a
811 * valid session description but its fields "lpszSessionName" and
812 * "lpszPassword" are set to null, while the actual strings sit after
813 * the session description.
814 * Theese strings are pointed by lpszSessionName and lpszPassword, which
815 * had to be calculated by the calling functiong adding the fields NameOffset
816 * and PasswordOffset to the base address of the message.
817 * Since this message buffer won't be used anymore, it's safe to copy this
818 * addresses to the dpSessionDesc struct and call SetSessionDesc in the
819 * calling function, which will copy all the data to a new SessionDesc
820 * struct owned by us.
821 * If this instance of dplay uses ANSI strings, we will have to transform
822 * the given wide strings, and we can do it in the same buffer, as place will
823 * be more than enough.
825 * Returns: The addition of the lengths of session name and password strings. */
828 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
832 if ( lpszSessionName
)
834 size
= lstrlenW( lpszSessionName
) + 1;
835 lpSessionDesc
->lpszSessionName
= lpszSessionName
;
838 WideCharToMultiByte( CP_ACP
, 0, lpSessionDesc
->lpszSessionName
, -1,
839 lpSessionDesc
->lpszSessionNameA
, size
,
842 offset
+= size
* sizeof(WCHAR
);
847 size
= lstrlenW( lpszPassword
) + 1;
848 lpSessionDesc
->lpszPassword
= lpszPassword
;
851 WideCharToMultiByte( CP_ACP
, 0, lpSessionDesc
->lpszPassword
, -1,
852 lpSessionDesc
->lpszPasswordA
, size
,
855 offset
+= size
* sizeof(WCHAR
);
862 static HRESULT
DP_MSG_ParsePlayerEnumeration( IDirectPlay2Impl
* lpDP
,
866 LPDPSP_MSG_ENUMPLAYERSREPLY lpMsgBody
=
867 (LPDPSP_MSG_ENUMPLAYERSREPLY
) lpMsg
;
868 PACKEDPLAYERDATA packedPlayerData
;
872 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
874 TRACE( "Received %d players, %d groups, %d shortcuts\n",
875 lpMsgBody
->PlayerCount
, lpMsgBody
->GroupCount
,
876 lpMsgBody
->ShortcutCount
);
878 offset
= sizeof(DPSP_MSG_ENUMPLAYERSREPLY
);
882 offset
+= DP_MSG_ParseSessionDesc( lpDP
, &lpMsgBody
->DPSessionDesc
,
883 ( lpMsgBody
->NameOffset
884 ? (LPWSTR
) (lpMsg
+ lpMsgBody
->NameOffset
)
886 ( lpMsgBody
->PasswordOffset
887 ? (LPWSTR
) (lpMsg
+ lpMsgBody
->PasswordOffset
)
890 /* Reset player counter, as it will be updated as we create players.
891 * Otherwise we can get players counted twice. */
892 lpMsgBody
->DPSessionDesc
.dwCurrentPlayers
= 0;
894 hr
= DP_SetSessionDesc( lpDP
, &lpMsgBody
->DPSessionDesc
, 0, FALSE
, bAnsi
);
896 TRACE( "Adding session %s, %d/%d\n",
897 debugstr_guid(&lpMsgBody
->DPSessionDesc
.guidInstance
),
898 lpMsgBody
->DPSessionDesc
.dwCurrentPlayers
,
899 lpMsgBody
->DPSessionDesc
.dwMaxPlayers
);
903 ERR( "Invalid session: %s\n", DPLAYX_HresultToString(hr
) );
908 for ( i
=0; i
<lpMsgBody
->PlayerCount
; i
++ )
910 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
=
911 (LPDPLAYI_SUPERPACKEDPLAYER
) (lpMsg
+ offset
);
913 ZeroMemory( &packedPlayerData
, sizeof(PACKEDPLAYERDATA
) );
915 if ( lpMsgBody
->envelope
.wCommandId
== DPMSGCMD_ENUMPLAYERSREPLY
)
917 offset
+= DP_MSG_ParsePackedPlayer( lpDP
, (LPBYTE
) lpPackedPlayer
,
923 offset
+= DP_MSG_ParseSuperPackedPlayer( lpDP
, (LPBYTE
) lpPackedPlayer
,
928 if ( lpPackedPlayer
->Flags
& DPLAYI_PLAYER_PLAYERLOCAL
)
930 /* Local players are no local anymore */
931 lpPackedPlayer
->Flags
^= DPLAYI_PLAYER_PLAYERLOCAL
;
934 TRACE( "Importing player 0x%08x, flags=0x%08x\n",
936 lpPackedPlayer
->Flags
);
938 hr
= DP_CreatePlayer( lpDP
, lpPackedPlayer
->ID
,
939 &packedPlayerData
.name
,
940 lpPackedPlayer
->Flags
,
941 packedPlayerData
.lpPlayerData
,
942 packedPlayerData
.dwPlayerDataSize
,
946 ERR( "Couldn't import player: %s\n", DPLAYX_HresultToString(hr
) );
950 hr
= IDirectPlaySP_SetSPPlayerData( lpDP
->dp2
->spData
.lpISP
,
952 packedPlayerData
.lpPlayerSPData
,
953 packedPlayerData
.dwPlayerSPDataSize
,
957 ERR( "Couldn't set SP data: %s\n", DPLAYX_HresultToString(hr
) );
961 /* Let the SP know that we've added this player */
962 if( lpDP
->dp2
->spData
.lpCB
->CreatePlayer
)
964 DPSP_CREATEPLAYERDATA data
;
966 data
.idPlayer
= lpPackedPlayer
->ID
;
967 data
.dwFlags
= lpPackedPlayer
->Flags
;
968 data
.lpSPMessageHeader
= lpMsgHdr
;
969 data
.lpISP
= lpDP
->dp2
->spData
.lpISP
;
971 hr
= (*lpDP
->dp2
->spData
.lpCB
->CreatePlayer
)( &data
);
975 ERR( "Couldn't create player with SP: %s\n", DPLAYX_HresultToString(hr
) );
983 for ( i
=0; i
<lpMsgBody
->GroupCount
; i
++ )
985 FIXME( "TODO: parse groups\n" );
988 for ( i
=0; i
<lpMsgBody
->ShortcutCount
; i
++ )
990 FIXME( "TODO: parse shortcuts\n" );
996 static DWORD
DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl
* lpDP
,
997 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer
,
1002 /* Fills lpPackedPlayer with the information in lpData.
1003 * lpData can be a player or a group.
1004 * If lpPackedPlayer is NULL just returns the size
1005 * needed to pack the player.
1007 * Returns: the size of the written data in bytes */
1009 #define PLAYER_OR_GROUP( bIsGroup, lpData, field ) \
1011 ? ((lpGroupData) lpData)->field \
1012 : ((lpPlayerData) lpData)->field )
1014 DWORD offset
, length
, size
;
1015 LPVOID playerSPData
;
1017 if ( lpPackedPlayer
== NULL
)
1019 size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
); /* Fixed data */
1020 size
+= DP_CopyString( NULL
, /* Short name */
1021 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1023 size
+= DP_CopyString( NULL
, /* Long name */
1024 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1026 /* Player data length */
1028 /* SP data length */
1036 /* Shortcut ID Count */
1042 lpPackedPlayer
->Size
= sizeof(DPLAYI_SUPERPACKEDPLAYER
);
1044 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
1045 lpPackedPlayer
->ID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
1047 if ( lpPackedPlayer
->Flags
& DPLAYI_PLAYER_SYSPLAYER
)
1049 lpPackedPlayer
->VersionOrSystemPlayerID
= DX61AVERSION
;
1053 lpPackedPlayer
->VersionOrSystemPlayerID
=
1054 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
1057 offset
= lpPackedPlayer
->Size
;
1060 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
1061 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1064 lpPackedPlayer
->PlayerInfoMask
|= SPP_SN
;
1068 length
= DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
1069 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
1072 lpPackedPlayer
->PlayerInfoMask
|= SPP_LN
;
1076 length
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
1079 size
= spp_get_optimum_size( length
);
1080 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PD_OFFSET
);
1081 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
1084 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1085 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
1090 /* Service provider data */
1091 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
, lpPackedPlayer
->ID
,
1092 &playerSPData
, &length
, DPGET_REMOTE
);
1095 size
= spp_get_optimum_size( length
);
1096 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_SL_OFFSET
);
1097 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, &length
, size
);
1099 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
, length
);
1106 if( !DPQ_IS_EMPTY( ((lpGroupData
)lpData
)->players
) )
1108 DWORD player_count
, offset_PC
;
1109 lpPlayerList lpPList
;
1111 offset_PC
= offset
; /* Space for PlayerCount */
1116 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
1120 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1121 &lpPList
->lpPData
->dpid
,
1123 offset
+= sizeof(DPID
);
1126 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
1130 size
= spp_get_optimum_size( player_count
);
1131 lpPackedPlayer
->PlayerInfoMask
|= spp_size2flags( size
, SPP_PC_OFFSET
);
1133 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset_PC
, &player_count
, size
);
1137 if ( ((lpGroupData
)lpData
)->parent
)
1139 lpPackedPlayer
->PlayerInfoMask
|= SPP_PI
;
1140 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1141 &((lpGroupData
)lpData
)->parent
,
1143 offset
+= sizeof(DWORD
);
1147 /*size = spp_get_optimum_size( ___ );
1148 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
1149 FIXME( "TODO: Add shortcut IDs\n" );
1155 static DWORD
DP_MSG_FillPackedPlayer( IDirectPlay2Impl
* lpDP
,
1156 LPDPLAYI_PACKEDPLAYER lpPackedPlayer
,
1161 /* Fills lpPackedPlayer with the information in lpData.
1162 * lpData can be a player or a group.
1163 * If lpPackedPlayer is NULL just returns the size
1164 * needed to pack the player.
1166 * Returns: the size of the written data in bytes */
1168 LPVOID playerSPData
;
1171 if ( lpPackedPlayer
== NULL
)
1174 size
= sizeof(DPLAYI_PACKEDPLAYER
); /* Fixed data */
1175 size
+= DP_CopyString( NULL
, /* Short name */
1176 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1178 size
+= DP_CopyString( NULL
, /* Long name */
1179 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
1191 lpPackedPlayer
->SystemPlayerID
=
1192 DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)->lpPData
->dpid
;
1193 lpPackedPlayer
->FixedSize
= sizeof(DPLAYI_PACKEDPLAYER
);
1194 lpPackedPlayer
->PlayerVersion
= DX61AVERSION
;
1196 lpPackedPlayer
->Flags
= 0x000000FF & PLAYER_OR_GROUP( bIsGroup
, lpData
, dwFlags
);
1197 lpPackedPlayer
->PlayerID
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dpid
);
1198 lpPackedPlayer
->ParentID
= ( bIsGroup
1199 ? ((lpGroupData
)lpData
)->parent
1202 offset
= lpPackedPlayer
->FixedSize
;
1205 lpPackedPlayer
->ShortNameLength
=
1206 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
1207 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszShortName
),
1209 offset
+= lpPackedPlayer
->ShortNameLength
;
1212 lpPackedPlayer
->LongNameLength
=
1213 DP_CopyString( ((LPBYTE
) lpPackedPlayer
) + offset
,
1214 PLAYER_OR_GROUP( bIsGroup
, lpData
, name
.lpszLongName
),
1216 offset
+= lpPackedPlayer
->LongNameLength
;
1218 /* Service provider data */
1219 IDirectPlaySP_GetSPPlayerData( lpDP
->dp2
->spData
.lpISP
,
1220 lpPackedPlayer
->PlayerID
,
1222 &lpPackedPlayer
->ServiceProviderDataSize
,
1224 if ( lpPackedPlayer
->ServiceProviderDataSize
)
1226 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
, playerSPData
,
1227 lpPackedPlayer
->ServiceProviderDataSize
);
1228 offset
+= lpPackedPlayer
->ServiceProviderDataSize
;
1232 lpPackedPlayer
->PlayerDataSize
= PLAYER_OR_GROUP( bIsGroup
, lpData
, dwRemoteDataSize
);
1233 if ( lpPackedPlayer
->PlayerDataSize
)
1235 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1236 PLAYER_OR_GROUP( bIsGroup
, lpData
, lpRemoteData
),
1237 lpPackedPlayer
->PlayerDataSize
);
1238 offset
+= lpPackedPlayer
->PlayerDataSize
;
1243 lpPlayerList lpPList
;
1246 lpPackedPlayer
->NumberOfPlayers
= 0;
1248 if ( (lpPList
= DPQ_FIRST( ((lpGroupData
)lpData
)->players
)) )
1252 CopyMemory( ((LPBYTE
) lpPackedPlayer
) + offset
,
1253 &lpPList
->lpPData
->dpid
,
1255 offset
+= sizeof(DPID
);
1256 lpPackedPlayer
->NumberOfPlayers
++;
1258 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
1264 lpPackedPlayer
->Size
= offset
;
1266 return lpPackedPlayer
->Size
;
1269 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl
* lpDP
,
1271 LPDWORD lpdwMsgSize
)
1273 /* Depending on the type of session, builds either a EnumPlayers
1274 reply or a SuperEnumPlayers reply, and places it in lplpReply */
1276 /* TODO: Find size to allocate *lplpReply
1277 * Check if we're releasing that memory */
1279 LPDPSP_MSG_ENUMPLAYERSREPLY lpReply
; /* Also valid in the SUPER case */
1280 lpPlayerList lpPList
;
1281 lpGroupList lpGList
;
1283 BOOL bAnsi
= TRUE
; /* FIXME: This needs to be in the DPLAY interface */
1286 *lplpReply
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 1024 );
1287 lpReply
= (LPDPSP_MSG_ENUMPLAYERSREPLY
)( (LPBYTE
)(*lplpReply
) +
1288 lpDP
->dp2
->spData
.dwSPHeaderSize
);
1290 lpReply
->envelope
.dwMagic
= DPMSG_SIGNATURE
;
1291 lpReply
->envelope
.wVersion
= DX61AVERSION
;
1293 if ( lpDP
->dp2
->lpSessionDesc
->dwFlags
& DPSESSION_CLIENTSERVER
)
1295 lpReply
->envelope
.wCommandId
= DPMSGCMD_ENUMPLAYERSREPLY
;
1299 lpReply
->envelope
.wCommandId
= DPMSGCMD_SUPERENUMPLAYERSREPLY
;
1303 /* Session description */
1304 lpReply
->DescriptionOffset
= ( sizeof(DPSP_MSG_ENUMPLAYERSREPLY
) -
1305 sizeof(DPSESSIONDESC2
) );
1306 CopyMemory( &lpReply
->DPSessionDesc
, lpDP
->dp2
->lpSessionDesc
,
1307 sizeof(DPSESSIONDESC2
) );
1309 offset
= sizeof(DPSP_MSG_ENUMPLAYERSREPLY
);
1312 if ( lpDP
->dp2
->lpSessionDesc
->lpszSessionName
)
1314 lpReply
->NameOffset
= offset
;
1315 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
1316 lpDP
->dp2
->lpSessionDesc
->lpszSessionName
,
1320 /* Session password */
1321 if ( lpDP
->dp2
->lpSessionDesc
->lpszPassword
)
1323 lpReply
->PasswordOffset
= offset
;
1324 offset
+= DP_CopyString( ((LPBYTE
) lpReply
) + offset
,
1325 lpDP
->dp2
->lpSessionDesc
->lpszPassword
,
1329 /* Populate PlayerInfo list */
1332 if ( (lpPList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->players
)) )
1336 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
1338 offset
+= DP_MSG_FillSuperPackedPlayer(
1339 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
1340 lpPList
->lpPData
, FALSE
, bAnsi
);
1344 offset
+= DP_MSG_FillPackedPlayer(
1345 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
1346 lpPList
->lpPData
, FALSE
, bAnsi
);
1349 lpReply
->PlayerCount
++;
1351 while( (lpPList
= DPQ_NEXT( lpPList
->players
)) );
1355 if ( (lpGList
= DPQ_FIRST( lpDP
->dp2
->lpSysGroup
->groups
)) )
1359 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
1361 offset
+= DP_MSG_FillSuperPackedPlayer(
1362 lpDP
, (LPDPLAYI_SUPERPACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
1363 lpGList
->lpGData
, TRUE
, bAnsi
);
1367 offset
+= DP_MSG_FillPackedPlayer(
1368 lpDP
, (LPDPLAYI_PACKEDPLAYER
)( ((LPBYTE
)lpReply
) + offset
),
1369 lpGList
->lpGData
, TRUE
, bAnsi
);
1372 lpReply
->GroupCount
++;
1374 while( (lpGList
= DPQ_NEXT( lpGList
->groups
)) );
1377 if ( lpReply
->envelope
.wCommandId
== DPMSGCMD_SUPERENUMPLAYERSREPLY
)
1379 /* - Groups with shortcuts */
1380 FIXME( "TODO: Add shortcut IDs\n" );
1383 *lpdwMsgSize
= lpDP
->dp2
->spData
.dwSPHeaderSize
+ offset
;