dplayx: Handling for CreatePlayer messages
[wine/gsoc_dplay.git] / dlls / dplayx / dplayx_messages.c
blob59cf79a8d83d5a4654742bb9f896ce97376b5cb6
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
19 * NOTES
20 * o Messaging interface required for both DirectPlay and DirectPlayLobby.
23 #include <stdarg.h>
24 #include <string.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "winnls.h"
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
42 HANDLE hStart;
43 HANDLE hDeath;
44 HANDLE hSettingRead;
45 HANDLE hNotifyEvent;
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,
56 BOOL bIsGroup,
57 BOOL bAnsi );
58 static DWORD DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl* lpDP,
59 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer,
60 LPVOID lpData,
61 BOOL bIsGroup,
62 BOOL bAnsi );
63 static DWORD DP_MSG_FillPackedPlayer( IDirectPlay2Impl* lpDP,
64 LPDPLAYI_PACKEDPLAYER lpPackedPlayer,
65 LPVOID lpData,
66 BOOL bIsGroup,
67 BOOL bAnsi );
68 static HRESULT DP_MSG_ParsePlayerEnumeration( IDirectPlay2Impl* lpDP,
69 LPBYTE lpMsg,
70 LPVOID lpMsgHdr );
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 )
84 DWORD dwMsgThreadId;
85 LPMSGTHREADINFO lpThreadInfo;
87 lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
88 if( lpThreadInfo == NULL )
90 return 0;
93 /* The notify event may or may not exist. Depends if async comm or not */
94 if( hNotifyEvent &&
95 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
96 GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
97 0, FALSE, DUPLICATE_SAME_ACCESS ) )
99 ERR( "Unable to duplicate event handle\n" );
100 goto error;
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 */
112 0, /* Stack */
113 DPL_MSG_ThreadMain, /* Msg reception function */
114 lpThreadInfo, /* Msg reception func parameter */
115 0, /* Flags */
116 &dwMsgThreadId /* Updated with thread id */
120 ERR( "Unable to create msg thread\n" );
121 goto error;
124 /* FIXME: Should I be closing the handle to the thread or does that
125 terminate the thread? */
127 return dwMsgThreadId;
129 error:
131 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
133 return 0;
136 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
138 LPMSGTHREADINFO lpThreadInfo = lpContext;
139 DWORD dwWaitResult;
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 );
148 goto end_of_thread;
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" );
168 for ( ;; )
170 MSG lobbyMsg;
171 GetMessageW( &lobbyMsg, 0, 0, 0 );
174 end_of_thread:
175 TRACE( "Msg thread exiting!\n" );
176 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
178 return 0;
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 );
190 static
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;
208 static
209 LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
210 LPVOID* lplpReplyHdr, LPVOID* lplpReplyMsg,
211 LPDWORD lpdwMsgBodySize )
213 CloseHandle( lpReplyStructList->replyExpected.hReceipt );
215 if ( lplpReplyHdr )
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 )
229 LPVOID lpPacket;
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 );
264 *lpMsg = lpPacket;
266 return DP_OK;
269 HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
270 LPDPID lpdpidAllocatedId )
272 LPVOID lpMsg;
273 LPDPSP_MSG_REQUESTPLAYERID lpMsgBody;
274 DWORD dwMsgSize;
275 HRESULT hr = DP_OK;
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 */
294 DPSP_SENDDATA data;
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 );
312 /* Examine reply */
313 if( lpMsg )
315 *lpdpidAllocatedId = ((LPCDPSP_MSG_REQUESTPLAYERREPLY) lpMsg)->ID;
316 TRACE( "Received new id 0x%08x\n", *lpdpidAllocatedId );
318 else
320 ERR( "Didn't receive reply\n" );
321 hr = DPERR_GENERIC;
324 HeapFree( GetProcessHeap(), 0, lpMsg );
325 return hr;
328 HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer )
330 LPVOID lpMsg;
331 LPDPSP_MSG_ADDFORWARDREQUEST lpMsgBody;
332 DWORD dwMsgSize;
333 HRESULT hr = DP_OK;
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 */
348 FIXME( "TODO\n" );
350 /* Send the message */
352 DPSP_SENDDATA data;
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,
366 DPMSGCMD_ADDFORWARD,
367 NULL, &lpMsg, &dwMsgSize );
370 /* Need to examine the data and extract the new player id */
371 if( lpMsg != NULL )
373 FIXME( "Name Table reply received: stub\n" );
376 return hr;
379 HRESULT DP_MSG_SendCreatePlayer( IDirectPlay2AImpl* This, lpPlayerData lpData )
381 LPBYTE lpMsg;
382 LPDPSP_MSG_CREATEPLAYER lpMsgBody;
383 DWORD dwMsgSize, dwWrapperSize;
384 HRESULT hr;
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);
395 else
397 dwWrapperSize = 0;
401 dwMsgSize = This->dp2->spData.dwSPHeaderSize +
402 dwWrapperSize +
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 +
409 dwWrapperSize );
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(
442 This,
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 */
462 else
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 );
482 if ( FAILED(hr) )
484 ERR( "Failed to send message to 0x%08x\n", sendData.idPlayerTo );
488 while( (lpPList = DPQ_NEXT( lpPList->players )) );
493 HeapFree( GetProcessHeap(), 0, lpMsg );
494 return hr;
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.
503 static
504 LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData,
505 DWORD dwWaitTime, WORD wReplyCommandId,
506 LPVOID* lplpReplyHdr, LPVOID* lplpReplyMsg,
507 LPDWORD lpdwMsgBodySize )
509 HRESULT hr;
510 HANDLE hMsgReceipt;
511 DP_MSG_REPLY_STRUCT_LIST replyStructList;
512 DWORD dwWaitReturn;
513 WORD wCommandId;
515 /* Setup for receipt */
516 hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList,
517 wReplyCommandId );
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 );
526 if( FAILED(hr) )
528 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr ) );
529 return NULL;
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 );
539 return NULL;
542 /* Clean Up */
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
558 * avoid problems.
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 );
568 return FALSE;
571 lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize;
572 /* TODO: Can we avoid theese allocations? */
573 lpReplyList->replyExpected.lpReplyHdr = HeapAlloc( GetProcessHeap(),
574 HEAP_ZERO_MEMORY,
575 This->dp2->spData.dwSPHeaderSize );
576 lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(),
577 HEAP_ZERO_MEMORY,
578 dwMsgBodySize );
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 );
587 return TRUE;
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. */
600 DWORD dwLength;
602 if ( source == NULL )
603 return 0;
605 if ( bAnsi )
607 dwLength = MultiByteToWideChar( CP_ACP, 0, (LPSTR) source, -1, NULL, 0 );
608 if ( destination )
609 MultiByteToWideChar( CP_ACP, 0, (LPSTR) source, -1,
610 (LPWSTR) destination, dwLength );
612 else
614 dwLength = lstrlenW( (LPWSTR) source ) + 1;
615 if ( destination )
616 CopyMemory( destination, source, dwLength );
619 return dwLength * sizeof(WCHAR);
622 static DWORD DP_MSG_ParseSuperPackedPlayer( IDirectPlay2Impl* lpDP,
623 LPBYTE lpPackedPlayer,
624 LPPACKEDPLAYERDATA lpData,
625 BOOL bIsGroup,
626 BOOL bAnsi )
628 DWORD offset, size;
630 ZeroMemory( lpData, sizeof(LPPACKEDPLAYERDATA) );
631 offset = sizeof(DPLAYI_SUPERPACKEDPLAYER);
633 /* Player name */
634 lpData->name.dwSize = sizeof(DPNAME);
636 /* - Short name */
637 if ( ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask & SPP_SN )
639 size = (lstrlenW((LPWSTR) (lpPackedPlayer + offset)) + 1) * sizeof(WCHAR);
640 lpData->name.lpszShortName = (LPWSTR) (lpPackedPlayer + offset);
641 offset += size;
642 if ( bAnsi )
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 );
653 /* - Long name */
654 if ( ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask & SPP_LN )
656 size = (lstrlenW((LPWSTR) (lpPackedPlayer + offset)) + 1) * sizeof(WCHAR);
657 lpData->name.lpszLongName = (LPWSTR) (lpPackedPlayer + offset);
658 offset += size;
659 if ( bAnsi )
661 WideCharToMultiByte( CP_ACP, 0, lpData->name.lpszLongName, -1,
662 lpData->name.lpszLongNameA,
663 size/sizeof(WCHAR), NULL, NULL );
667 /* Player SP data */
668 size = spp_flags2size(
669 ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask, SPP_SL_OFFSET );
670 if ( size )
672 CopyMemory( &lpData->dwPlayerSPDataSize,
673 lpPackedPlayer + offset, size );
674 offset += size;
675 lpData->lpPlayerSPData = lpPackedPlayer + offset;
676 offset += lpData->dwPlayerSPDataSize;
679 /* Player data */
680 size = spp_flags2size(
681 ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask, SPP_PD_OFFSET );
682 if ( size )
684 CopyMemory( &lpData->dwPlayerDataSize,
685 lpPackedPlayer + offset, size );
686 offset += size;
687 lpData->lpPlayerData = lpPackedPlayer + offset;
688 offset += lpData->dwPlayerDataSize;
691 if ( bIsGroup )
693 /* Player IDs */
694 size = spp_flags2size(
695 ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask, SPP_PC_OFFSET );
696 if ( size )
698 CopyMemory( &lpData->dwPlayerCount,
699 lpPackedPlayer + offset, size );
700 offset += size;
701 lpData->lpPlayerIDs = (LPDPID) (lpPackedPlayer + offset);
702 offset += lpData->dwPlayerCount * sizeof(DPID);
705 /* Parent ID */
706 if ( ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask & SPP_PI )
708 lpData->parentID = (DPID) *(lpPackedPlayer + offset);
709 offset += sizeof(DPID);
712 /* Shortcut IDs */
713 size = spp_flags2size(
714 ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask, SPP_SC_OFFSET );
715 if ( size )
717 CopyMemory( &lpData->dwShortcutCount,
718 lpPackedPlayer + offset, size );
719 offset += size;
720 lpData->lpShortcutIDs = (LPDPID) (lpPackedPlayer + offset);
721 offset += lpData->dwShortcutCount * sizeof(DPID);
725 return offset;
728 DWORD DP_MSG_ParsePackedPlayer( IDirectPlay2Impl* lpDP,
729 LPBYTE lpPackedPlayer,
730 LPPACKEDPLAYERDATA lpData,
731 BOOL bIsGroup,
732 BOOL bAnsi )
734 DWORD offset;
735 LPDPLAYI_PACKEDPLAYER lpPackedPlayerData =
736 (LPDPLAYI_PACKEDPLAYER) lpPackedPlayer;
738 ZeroMemory( lpData, sizeof(LPPACKEDPLAYERDATA) );
739 offset = lpPackedPlayerData->FixedSize;
741 /* Player name */
742 lpData->name.dwSize = sizeof(DPNAME);
744 /* - Short name */
745 if ( lpPackedPlayerData->ShortNameLength )
747 lpData->name.lpszShortName = (LPWSTR) (lpPackedPlayer + offset);
748 offset += lpPackedPlayerData->ShortNameLength;
749 if ( bAnsi )
751 WideCharToMultiByte( CP_ACP, 0, lpData->name.lpszShortName, -1,
752 lpData->name.lpszShortNameA,
753 lpPackedPlayerData->ShortNameLength/sizeof(WCHAR),
754 NULL, NULL );
758 /* - Long name */
759 if ( lpPackedPlayerData->LongNameLength )
761 lpData->name.lpszLongName = (LPWSTR) (lpPackedPlayer + offset);
762 offset += lpPackedPlayerData->LongNameLength;
763 if ( bAnsi )
765 WideCharToMultiByte( CP_ACP, 0, lpData->name.lpszLongName, -1,
766 lpData->name.lpszLongNameA,
767 lpPackedPlayerData->LongNameLength/sizeof(WCHAR),
768 NULL, NULL );
772 /* Player SP data */
773 lpData->dwPlayerSPDataSize = lpPackedPlayerData->ServiceProviderDataSize;
774 if ( lpPackedPlayerData->ServiceProviderDataSize )
776 lpData->lpPlayerSPData = lpPackedPlayer + offset;
777 offset += lpPackedPlayerData->ServiceProviderDataSize;
780 /* Player data */
781 lpData->dwPlayerDataSize = lpPackedPlayerData->PlayerDataSize;
782 if ( lpPackedPlayerData->PlayerDataSize )
784 lpData->lpPlayerData = lpPackedPlayer + offset;
785 offset += lpPackedPlayerData->PlayerDataSize;
788 if ( bIsGroup )
790 /* Parent ID */
791 lpData->parentID = lpPackedPlayerData->ParentID;
793 /* Player IDs */
794 lpData->dwPlayerCount = lpPackedPlayerData->NumberOfPlayers;
795 if ( lpPackedPlayerData->NumberOfPlayers )
797 lpData->lpPlayerIDs = (LPDPID)(lpPackedPlayer + offset);
798 offset += lpPackedPlayerData->NumberOfPlayers;
802 return offset;
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. */
827 DWORD offset, size;
828 BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */
830 offset = 0;
832 if ( lpszSessionName )
834 size = lstrlenW( lpszSessionName ) + 1;
835 lpSessionDesc->lpszSessionName = lpszSessionName;
836 if ( bAnsi )
838 WideCharToMultiByte( CP_ACP, 0, lpSessionDesc->lpszSessionName, -1,
839 lpSessionDesc->lpszSessionNameA, size,
840 NULL, NULL );
842 offset += size * sizeof(WCHAR);
845 if ( lpszPassword )
847 size = lstrlenW( lpszPassword ) + 1;
848 lpSessionDesc->lpszPassword = lpszPassword;
849 if ( bAnsi )
851 WideCharToMultiByte( CP_ACP, 0, lpSessionDesc->lpszPassword, -1,
852 lpSessionDesc->lpszPasswordA, size,
853 NULL, NULL );
855 offset += size * sizeof(WCHAR);
858 return offset;
862 static HRESULT DP_MSG_ParsePlayerEnumeration( IDirectPlay2Impl* lpDP,
863 LPBYTE lpMsg,
864 LPVOID lpMsgHdr )
866 LPDPSP_MSG_ENUMPLAYERSREPLY lpMsgBody =
867 (LPDPSP_MSG_ENUMPLAYERSREPLY) lpMsg;
868 PACKEDPLAYERDATA packedPlayerData;
869 DWORD offset;
870 HRESULT hr;
871 UINT i;
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);
880 /* Session */
882 offset += DP_MSG_ParseSessionDesc( lpDP, &lpMsgBody->DPSessionDesc,
883 ( lpMsgBody->NameOffset
884 ? (LPWSTR) (lpMsg + lpMsgBody->NameOffset)
885 : NULL ),
886 ( lpMsgBody->PasswordOffset
887 ? (LPWSTR) (lpMsg + lpMsgBody->PasswordOffset)
888 : NULL ) );
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 );
901 if ( FAILED(hr) )
903 ERR( "Invalid session: %s\n", DPLAYX_HresultToString(hr) );
904 return hr;
907 /* Players */
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,
918 &packedPlayerData,
919 FALSE, bAnsi );
921 else
923 offset += DP_MSG_ParseSuperPackedPlayer( lpDP, (LPBYTE) lpPackedPlayer,
924 &packedPlayerData,
925 FALSE, bAnsi );
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",
935 lpPackedPlayer->ID,
936 lpPackedPlayer->Flags );
938 hr = DP_CreatePlayer( lpDP, lpPackedPlayer->ID,
939 &packedPlayerData.name,
940 lpPackedPlayer->Flags,
941 packedPlayerData.lpPlayerData,
942 packedPlayerData.dwPlayerDataSize,
943 NULL, bAnsi, NULL );
944 if ( FAILED(hr) )
946 ERR( "Couldn't import player: %s\n", DPLAYX_HresultToString(hr) );
947 continue;
950 hr = IDirectPlaySP_SetSPPlayerData( lpDP->dp2->spData.lpISP,
951 lpPackedPlayer->ID,
952 packedPlayerData.lpPlayerSPData,
953 packedPlayerData.dwPlayerSPDataSize,
954 DPSET_REMOTE );
955 if ( FAILED(hr) )
957 ERR( "Couldn't set SP data: %s\n", DPLAYX_HresultToString(hr) );
958 continue;
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 );
973 if( FAILED(hr) )
975 ERR( "Couldn't create player with SP: %s\n", DPLAYX_HresultToString(hr) );
976 continue;
982 /* Groups */
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" );
993 return DP_OK;
996 static DWORD DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl* lpDP,
997 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer,
998 LPVOID lpData,
999 BOOL bIsGroup,
1000 BOOL bAnsi )
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 ) \
1010 ( bIsGroup \
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 ),
1022 bAnsi );
1023 size += DP_CopyString( NULL, /* Long name */
1024 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
1025 bAnsi );
1026 /* Player data length */
1027 /* Player data */
1028 /* SP data length */
1029 /* SP data */
1031 if ( bIsGroup )
1033 /* Player count */
1034 /* Player IDs */
1035 /* ParentID */
1036 /* Shortcut ID Count */
1037 /* Shortcut IDs */
1039 return size;
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;
1051 else
1053 lpPackedPlayer->VersionOrSystemPlayerID =
1054 DPQ_FIRST( lpDP->dp2->lpSysGroup->players )->lpPData->dpid;
1057 offset = lpPackedPlayer->Size;
1059 /* Short name */
1060 length = DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
1061 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
1062 bAnsi );
1063 if ( length )
1064 lpPackedPlayer->PlayerInfoMask |= SPP_SN;
1065 offset += length;
1067 /* Long name */
1068 length = DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
1069 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
1070 bAnsi );
1071 if ( length )
1072 lpPackedPlayer->PlayerInfoMask |= SPP_LN;
1073 offset += length;
1075 /* Player data */
1076 length = PLAYER_OR_GROUP( bIsGroup, lpData, dwRemoteDataSize);
1077 if ( length )
1079 size = spp_get_optimum_size( length );
1080 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_PD_OFFSET );
1081 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, &length, size );
1082 offset += size;
1084 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
1085 PLAYER_OR_GROUP( bIsGroup, lpData, lpRemoteData ),
1086 length );
1087 offset += length;
1090 /* Service provider data */
1091 IDirectPlaySP_GetSPPlayerData( lpDP->dp2->spData.lpISP, lpPackedPlayer->ID,
1092 &playerSPData, &length, DPGET_REMOTE );
1093 if ( length )
1095 size = spp_get_optimum_size( length );
1096 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SL_OFFSET );
1097 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, &length, size );
1098 offset += size;
1099 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, playerSPData, length );
1100 offset += length;
1103 if ( bIsGroup )
1105 /* Player IDs */
1106 if( !DPQ_IS_EMPTY( ((lpGroupData)lpData)->players ) )
1108 DWORD player_count, offset_PC;
1109 lpPlayerList lpPList;
1111 offset_PC = offset; /* Space for PlayerCount */
1112 offset += 4;
1113 player_count = 0;
1115 /* PlayerIDs */
1116 if ( (lpPList = DPQ_FIRST( ((lpGroupData)lpData)->players )) )
1120 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
1121 &lpPList->lpPData->dpid,
1122 sizeof(DPID) );
1123 offset += sizeof(DPID);
1124 player_count++;
1126 while( (lpPList = DPQ_NEXT( lpPList->players )) );
1129 /* PlayerCount */
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 );
1136 /* ParentID */
1137 if ( ((lpGroupData)lpData)->parent )
1139 lpPackedPlayer->PlayerInfoMask |= SPP_PI;
1140 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
1141 &((lpGroupData)lpData)->parent,
1142 sizeof(DWORD) );
1143 offset += sizeof(DWORD);
1146 /* Shortcut IDs */
1147 /*size = spp_get_optimum_size( ___ );
1148 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
1149 FIXME( "TODO: Add shortcut IDs\n" );
1152 return offset;
1155 static DWORD DP_MSG_FillPackedPlayer( IDirectPlay2Impl* lpDP,
1156 LPDPLAYI_PACKEDPLAYER lpPackedPlayer,
1157 LPVOID lpData,
1158 BOOL bIsGroup,
1159 BOOL bAnsi )
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;
1169 DWORD offset;
1171 if ( lpPackedPlayer == NULL )
1173 DWORD size;
1174 size = sizeof(DPLAYI_PACKEDPLAYER); /* Fixed data */
1175 size += DP_CopyString( NULL, /* Short name */
1176 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
1177 bAnsi );
1178 size += DP_CopyString( NULL, /* Long name */
1179 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
1180 bAnsi );
1181 /* SP data */
1182 /* Player data */
1184 if ( bIsGroup )
1186 /* Player IDs */
1188 return size;
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
1200 : 0 );
1202 offset = lpPackedPlayer->FixedSize;
1204 /* Short name */
1205 lpPackedPlayer->ShortNameLength =
1206 DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
1207 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
1208 bAnsi );
1209 offset += lpPackedPlayer->ShortNameLength;
1211 /* Long name */
1212 lpPackedPlayer->LongNameLength =
1213 DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
1214 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
1215 bAnsi );
1216 offset += lpPackedPlayer->LongNameLength;
1218 /* Service provider data */
1219 IDirectPlaySP_GetSPPlayerData( lpDP->dp2->spData.lpISP,
1220 lpPackedPlayer->PlayerID,
1221 &playerSPData,
1222 &lpPackedPlayer->ServiceProviderDataSize,
1223 DPGET_REMOTE );
1224 if ( lpPackedPlayer->ServiceProviderDataSize )
1226 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, playerSPData,
1227 lpPackedPlayer->ServiceProviderDataSize );
1228 offset += lpPackedPlayer->ServiceProviderDataSize;
1231 /* Player data */
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;
1241 if ( bIsGroup )
1243 lpPlayerList lpPList;
1245 /* Player IDs */
1246 lpPackedPlayer->NumberOfPlayers = 0;
1248 if ( (lpPList = DPQ_FIRST( ((lpGroupData)lpData)->players )) )
1252 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
1253 &lpPList->lpPData->dpid,
1254 sizeof(DPID) );
1255 offset += sizeof(DPID);
1256 lpPackedPlayer->NumberOfPlayers++;
1258 while( (lpPList = DPQ_NEXT( lpPList->players )) );
1263 /* Total size */
1264 lpPackedPlayer->Size = offset;
1266 return lpPackedPlayer->Size;
1269 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl* lpDP,
1270 LPVOID* lplpReply,
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;
1282 DWORD offset;
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;
1297 else
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);
1311 /* Session name */
1312 if ( lpDP->dp2->lpSessionDesc->lpszSessionName )
1314 lpReply->NameOffset = offset;
1315 offset += DP_CopyString( ((LPBYTE) lpReply) + offset,
1316 lpDP->dp2->lpSessionDesc->lpszSessionName,
1317 bAnsi );
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,
1326 bAnsi );
1329 /* Populate PlayerInfo list */
1331 /* - Players */
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 );
1342 else
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 )) );
1354 /* - Groups */
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 );
1365 else
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;