dplayx: Code to forward player creation
[wine/gsoc_dplay.git] / dlls / dplayx / dplayx_messages.c
blobe8b506e1d74cff6db3641e7f7d2b4360aac0bef0
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 LPBYTE lpMsg, lpReply, lpReplyHdr;
331 LPDPSP_MSG_ADDFORWARDREQUEST lpMsgBody;
332 DWORD dwMsgSize, dwReplySize, offset, tick_count;
333 lpPlayerList lpPList;
334 DPSP_SENDDATA sendData;
335 HRESULT hr = DP_OK;
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 */
349 DP_CopyString( NULL,
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;
372 /* Player data */
373 offset += DP_MSG_FillPackedPlayer(
374 This, (LPDPLAYI_PACKEDPLAYER)( lpMsg + offset ),
375 lpPList->lpPData, FALSE, TRUE );
377 /* Password */
378 lpMsgBody->PasswordOffset = offset;
379 if ( This->dp2->lpSessionDesc->lpszPassword )
381 offset += DP_CopyString( lpMsg + offset,
382 This->dp2->lpSessionDesc->lpszPassword,
383 TRUE );
385 else
387 offset += sizeof(WCHAR); /* Null unicode string */
390 /* TickCount */
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 );
408 dwReplySize = 2048;
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 );
417 /* Examine reply */
418 if( lpReply )
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) );
426 break;
428 case DPMSGCMD_SUPERENUMPLAYERSREPLY:
430 TRACE( "Received player enumeration\n" );
431 hr = DP_MSG_ParsePlayerEnumeration( This, lpReply, lpReplyHdr );
432 break;
434 default:
436 ERR( "Unknown reply with cmd 0x%x\n",
437 ((LPDPSP_MSG_ENVELOPE) lpReply)->wCommandId );
438 hr = DPERR_GENERIC;
442 else
444 ERR( "Didn't receive reply\n" );
445 hr = DPERR_GENERIC;
448 HeapFree( GetProcessHeap(), 0, lpMsg );
449 HeapFree( GetProcessHeap(), 0, lpReply );
450 return hr;
453 HRESULT DP_MSG_SendCreatePlayer( IDirectPlay2AImpl* This, lpPlayerData lpData )
455 LPBYTE lpMsg;
456 LPDPSP_MSG_CREATEPLAYER lpMsgBody;
457 DWORD dwMsgSize, dwWrapperSize;
458 HRESULT hr;
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);
469 else
471 dwWrapperSize = 0;
475 dwMsgSize = This->dp2->spData.dwSPHeaderSize +
476 dwWrapperSize +
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 +
483 dwWrapperSize );
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(
516 This,
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 */
536 else
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 );
556 if ( FAILED(hr) )
558 ERR( "Failed to send message to 0x%08x\n", sendData.idPlayerTo );
562 while( (lpPList = DPQ_NEXT( lpPList->players )) );
567 HeapFree( GetProcessHeap(), 0, lpMsg );
568 return hr;
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.
577 static
578 LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData,
579 DWORD dwWaitTime, WORD wReplyCommandId,
580 LPVOID* lplpReplyHdr, LPVOID* lplpReplyMsg,
581 LPDWORD lpdwMsgBodySize )
583 HRESULT hr;
584 HANDLE hMsgReceipt;
585 DP_MSG_REPLY_STRUCT_LIST replyStructList;
586 DWORD dwWaitReturn;
587 WORD wCommandId;
589 /* Setup for receipt */
590 hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList,
591 wReplyCommandId );
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 );
600 if( FAILED(hr) )
602 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr ) );
603 return NULL;
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 );
613 return NULL;
616 /* Clean Up */
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
632 * avoid problems.
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 );
642 return FALSE;
645 lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize;
646 /* TODO: Can we avoid theese allocations? */
647 lpReplyList->replyExpected.lpReplyHdr = HeapAlloc( GetProcessHeap(),
648 HEAP_ZERO_MEMORY,
649 This->dp2->spData.dwSPHeaderSize );
650 lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(),
651 HEAP_ZERO_MEMORY,
652 dwMsgBodySize );
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 );
661 return TRUE;
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. */
674 DWORD dwLength;
676 if ( source == NULL )
677 return 0;
679 if ( bAnsi )
681 dwLength = MultiByteToWideChar( CP_ACP, 0, (LPSTR) source, -1, NULL, 0 );
682 if ( destination )
683 MultiByteToWideChar( CP_ACP, 0, (LPSTR) source, -1,
684 (LPWSTR) destination, dwLength );
686 else
688 dwLength = lstrlenW( (LPWSTR) source ) + 1;
689 if ( destination )
690 CopyMemory( destination, source, dwLength );
693 return dwLength * sizeof(WCHAR);
696 static DWORD DP_MSG_ParseSuperPackedPlayer( IDirectPlay2Impl* lpDP,
697 LPBYTE lpPackedPlayer,
698 LPPACKEDPLAYERDATA lpData,
699 BOOL bIsGroup,
700 BOOL bAnsi )
702 DWORD offset, size;
704 ZeroMemory( lpData, sizeof(LPPACKEDPLAYERDATA) );
705 offset = sizeof(DPLAYI_SUPERPACKEDPLAYER);
707 /* Player name */
708 lpData->name.dwSize = sizeof(DPNAME);
710 /* - Short name */
711 if ( ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask & SPP_SN )
713 size = (lstrlenW((LPWSTR) (lpPackedPlayer + offset)) + 1) * sizeof(WCHAR);
714 lpData->name.lpszShortName = (LPWSTR) (lpPackedPlayer + offset);
715 offset += size;
716 if ( bAnsi )
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 );
727 /* - Long name */
728 if ( ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask & SPP_LN )
730 size = (lstrlenW((LPWSTR) (lpPackedPlayer + offset)) + 1) * sizeof(WCHAR);
731 lpData->name.lpszLongName = (LPWSTR) (lpPackedPlayer + offset);
732 offset += size;
733 if ( bAnsi )
735 WideCharToMultiByte( CP_ACP, 0, lpData->name.lpszLongName, -1,
736 lpData->name.lpszLongNameA,
737 size/sizeof(WCHAR), NULL, NULL );
741 /* Player SP data */
742 size = spp_flags2size(
743 ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask, SPP_SL_OFFSET );
744 if ( size )
746 CopyMemory( &lpData->dwPlayerSPDataSize,
747 lpPackedPlayer + offset, size );
748 offset += size;
749 lpData->lpPlayerSPData = lpPackedPlayer + offset;
750 offset += lpData->dwPlayerSPDataSize;
753 /* Player data */
754 size = spp_flags2size(
755 ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask, SPP_PD_OFFSET );
756 if ( size )
758 CopyMemory( &lpData->dwPlayerDataSize,
759 lpPackedPlayer + offset, size );
760 offset += size;
761 lpData->lpPlayerData = lpPackedPlayer + offset;
762 offset += lpData->dwPlayerDataSize;
765 if ( bIsGroup )
767 /* Player IDs */
768 size = spp_flags2size(
769 ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask, SPP_PC_OFFSET );
770 if ( size )
772 CopyMemory( &lpData->dwPlayerCount,
773 lpPackedPlayer + offset, size );
774 offset += size;
775 lpData->lpPlayerIDs = (LPDPID) (lpPackedPlayer + offset);
776 offset += lpData->dwPlayerCount * sizeof(DPID);
779 /* Parent ID */
780 if ( ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask & SPP_PI )
782 lpData->parentID = (DPID) *(lpPackedPlayer + offset);
783 offset += sizeof(DPID);
786 /* Shortcut IDs */
787 size = spp_flags2size(
788 ((LPDPLAYI_SUPERPACKEDPLAYER) lpPackedPlayer)->PlayerInfoMask, SPP_SC_OFFSET );
789 if ( size )
791 CopyMemory( &lpData->dwShortcutCount,
792 lpPackedPlayer + offset, size );
793 offset += size;
794 lpData->lpShortcutIDs = (LPDPID) (lpPackedPlayer + offset);
795 offset += lpData->dwShortcutCount * sizeof(DPID);
799 return offset;
802 DWORD DP_MSG_ParsePackedPlayer( IDirectPlay2Impl* lpDP,
803 LPBYTE lpPackedPlayer,
804 LPPACKEDPLAYERDATA lpData,
805 BOOL bIsGroup,
806 BOOL bAnsi )
808 DWORD offset;
809 LPDPLAYI_PACKEDPLAYER lpPackedPlayerData =
810 (LPDPLAYI_PACKEDPLAYER) lpPackedPlayer;
812 ZeroMemory( lpData, sizeof(LPPACKEDPLAYERDATA) );
813 offset = lpPackedPlayerData->FixedSize;
815 /* Player name */
816 lpData->name.dwSize = sizeof(DPNAME);
818 /* - Short name */
819 if ( lpPackedPlayerData->ShortNameLength )
821 lpData->name.lpszShortName = (LPWSTR) (lpPackedPlayer + offset);
822 offset += lpPackedPlayerData->ShortNameLength;
823 if ( bAnsi )
825 WideCharToMultiByte( CP_ACP, 0, lpData->name.lpszShortName, -1,
826 lpData->name.lpszShortNameA,
827 lpPackedPlayerData->ShortNameLength/sizeof(WCHAR),
828 NULL, NULL );
832 /* - Long name */
833 if ( lpPackedPlayerData->LongNameLength )
835 lpData->name.lpszLongName = (LPWSTR) (lpPackedPlayer + offset);
836 offset += lpPackedPlayerData->LongNameLength;
837 if ( bAnsi )
839 WideCharToMultiByte( CP_ACP, 0, lpData->name.lpszLongName, -1,
840 lpData->name.lpszLongNameA,
841 lpPackedPlayerData->LongNameLength/sizeof(WCHAR),
842 NULL, NULL );
846 /* Player SP data */
847 lpData->dwPlayerSPDataSize = lpPackedPlayerData->ServiceProviderDataSize;
848 if ( lpPackedPlayerData->ServiceProviderDataSize )
850 lpData->lpPlayerSPData = lpPackedPlayer + offset;
851 offset += lpPackedPlayerData->ServiceProviderDataSize;
854 /* Player data */
855 lpData->dwPlayerDataSize = lpPackedPlayerData->PlayerDataSize;
856 if ( lpPackedPlayerData->PlayerDataSize )
858 lpData->lpPlayerData = lpPackedPlayer + offset;
859 offset += lpPackedPlayerData->PlayerDataSize;
862 if ( bIsGroup )
864 /* Parent ID */
865 lpData->parentID = lpPackedPlayerData->ParentID;
867 /* Player IDs */
868 lpData->dwPlayerCount = lpPackedPlayerData->NumberOfPlayers;
869 if ( lpPackedPlayerData->NumberOfPlayers )
871 lpData->lpPlayerIDs = (LPDPID)(lpPackedPlayer + offset);
872 offset += lpPackedPlayerData->NumberOfPlayers;
876 return offset;
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. */
901 DWORD offset, size;
902 BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */
904 offset = 0;
906 if ( lpszSessionName )
908 size = lstrlenW( lpszSessionName ) + 1;
909 lpSessionDesc->lpszSessionName = lpszSessionName;
910 if ( bAnsi )
912 WideCharToMultiByte( CP_ACP, 0, lpSessionDesc->lpszSessionName, -1,
913 lpSessionDesc->lpszSessionNameA, size,
914 NULL, NULL );
916 offset += size * sizeof(WCHAR);
919 if ( lpszPassword )
921 size = lstrlenW( lpszPassword ) + 1;
922 lpSessionDesc->lpszPassword = lpszPassword;
923 if ( bAnsi )
925 WideCharToMultiByte( CP_ACP, 0, lpSessionDesc->lpszPassword, -1,
926 lpSessionDesc->lpszPasswordA, size,
927 NULL, NULL );
929 offset += size * sizeof(WCHAR);
932 return offset;
936 static HRESULT DP_MSG_ParsePlayerEnumeration( IDirectPlay2Impl* lpDP,
937 LPBYTE lpMsg,
938 LPVOID lpMsgHdr )
940 LPDPSP_MSG_ENUMPLAYERSREPLY lpMsgBody =
941 (LPDPSP_MSG_ENUMPLAYERSREPLY) lpMsg;
942 PACKEDPLAYERDATA packedPlayerData;
943 DWORD offset;
944 HRESULT hr;
945 UINT i;
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);
954 /* Session */
956 offset += DP_MSG_ParseSessionDesc( lpDP, &lpMsgBody->DPSessionDesc,
957 ( lpMsgBody->NameOffset
958 ? (LPWSTR) (lpMsg + lpMsgBody->NameOffset)
959 : NULL ),
960 ( lpMsgBody->PasswordOffset
961 ? (LPWSTR) (lpMsg + lpMsgBody->PasswordOffset)
962 : NULL ) );
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 );
975 if ( FAILED(hr) )
977 ERR( "Invalid session: %s\n", DPLAYX_HresultToString(hr) );
978 return hr;
981 /* Players */
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,
992 &packedPlayerData,
993 FALSE, bAnsi );
995 else
997 offset += DP_MSG_ParseSuperPackedPlayer( lpDP, (LPBYTE) lpPackedPlayer,
998 &packedPlayerData,
999 FALSE, bAnsi );
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",
1009 lpPackedPlayer->ID,
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 );
1018 if ( FAILED(hr) )
1020 ERR( "Couldn't import player: %s\n", DPLAYX_HresultToString(hr) );
1021 continue;
1024 hr = IDirectPlaySP_SetSPPlayerData( lpDP->dp2->spData.lpISP,
1025 lpPackedPlayer->ID,
1026 packedPlayerData.lpPlayerSPData,
1027 packedPlayerData.dwPlayerSPDataSize,
1028 DPSET_REMOTE );
1029 if ( FAILED(hr) )
1031 ERR( "Couldn't set SP data: %s\n", DPLAYX_HresultToString(hr) );
1032 continue;
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 );
1047 if( FAILED(hr) )
1049 ERR( "Couldn't create player with SP: %s\n", DPLAYX_HresultToString(hr) );
1050 continue;
1056 /* Groups */
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" );
1067 return DP_OK;
1070 static DWORD DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl* lpDP,
1071 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer,
1072 LPVOID lpData,
1073 BOOL bIsGroup,
1074 BOOL bAnsi )
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 ) \
1084 ( bIsGroup \
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 ),
1096 bAnsi );
1097 size += DP_CopyString( NULL, /* Long name */
1098 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
1099 bAnsi );
1100 /* Player data length */
1101 /* Player data */
1102 /* SP data length */
1103 /* SP data */
1105 if ( bIsGroup )
1107 /* Player count */
1108 /* Player IDs */
1109 /* ParentID */
1110 /* Shortcut ID Count */
1111 /* Shortcut IDs */
1113 return size;
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;
1125 else
1127 lpPackedPlayer->VersionOrSystemPlayerID =
1128 DPQ_FIRST( lpDP->dp2->lpSysGroup->players )->lpPData->dpid;
1131 offset = lpPackedPlayer->Size;
1133 /* Short name */
1134 length = DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
1135 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
1136 bAnsi );
1137 if ( length )
1138 lpPackedPlayer->PlayerInfoMask |= SPP_SN;
1139 offset += length;
1141 /* Long name */
1142 length = DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
1143 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
1144 bAnsi );
1145 if ( length )
1146 lpPackedPlayer->PlayerInfoMask |= SPP_LN;
1147 offset += length;
1149 /* Player data */
1150 length = PLAYER_OR_GROUP( bIsGroup, lpData, dwRemoteDataSize);
1151 if ( length )
1153 size = spp_get_optimum_size( length );
1154 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_PD_OFFSET );
1155 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, &length, size );
1156 offset += size;
1158 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
1159 PLAYER_OR_GROUP( bIsGroup, lpData, lpRemoteData ),
1160 length );
1161 offset += length;
1164 /* Service provider data */
1165 IDirectPlaySP_GetSPPlayerData( lpDP->dp2->spData.lpISP, lpPackedPlayer->ID,
1166 &playerSPData, &length, DPGET_REMOTE );
1167 if ( length )
1169 size = spp_get_optimum_size( length );
1170 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SL_OFFSET );
1171 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, &length, size );
1172 offset += size;
1173 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, playerSPData, length );
1174 offset += length;
1177 if ( bIsGroup )
1179 /* Player IDs */
1180 if( !DPQ_IS_EMPTY( ((lpGroupData)lpData)->players ) )
1182 DWORD player_count, offset_PC;
1183 lpPlayerList lpPList;
1185 offset_PC = offset; /* Space for PlayerCount */
1186 offset += 4;
1187 player_count = 0;
1189 /* PlayerIDs */
1190 if ( (lpPList = DPQ_FIRST( ((lpGroupData)lpData)->players )) )
1194 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
1195 &lpPList->lpPData->dpid,
1196 sizeof(DPID) );
1197 offset += sizeof(DPID);
1198 player_count++;
1200 while( (lpPList = DPQ_NEXT( lpPList->players )) );
1203 /* PlayerCount */
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 );
1210 /* ParentID */
1211 if ( ((lpGroupData)lpData)->parent )
1213 lpPackedPlayer->PlayerInfoMask |= SPP_PI;
1214 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
1215 &((lpGroupData)lpData)->parent,
1216 sizeof(DWORD) );
1217 offset += sizeof(DWORD);
1220 /* Shortcut IDs */
1221 /*size = spp_get_optimum_size( ___ );
1222 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
1223 FIXME( "TODO: Add shortcut IDs\n" );
1226 return offset;
1229 static DWORD DP_MSG_FillPackedPlayer( IDirectPlay2Impl* lpDP,
1230 LPDPLAYI_PACKEDPLAYER lpPackedPlayer,
1231 LPVOID lpData,
1232 BOOL bIsGroup,
1233 BOOL bAnsi )
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;
1243 DWORD offset;
1245 if ( lpPackedPlayer == NULL )
1247 DWORD size;
1248 size = sizeof(DPLAYI_PACKEDPLAYER); /* Fixed data */
1249 size += DP_CopyString( NULL, /* Short name */
1250 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
1251 bAnsi );
1252 size += DP_CopyString( NULL, /* Long name */
1253 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
1254 bAnsi );
1255 /* SP data */
1256 /* Player data */
1258 if ( bIsGroup )
1260 /* Player IDs */
1262 return size;
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
1274 : 0 );
1276 offset = lpPackedPlayer->FixedSize;
1278 /* Short name */
1279 lpPackedPlayer->ShortNameLength =
1280 DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
1281 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
1282 bAnsi );
1283 offset += lpPackedPlayer->ShortNameLength;
1285 /* Long name */
1286 lpPackedPlayer->LongNameLength =
1287 DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
1288 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
1289 bAnsi );
1290 offset += lpPackedPlayer->LongNameLength;
1292 /* Service provider data */
1293 IDirectPlaySP_GetSPPlayerData( lpDP->dp2->spData.lpISP,
1294 lpPackedPlayer->PlayerID,
1295 &playerSPData,
1296 &lpPackedPlayer->ServiceProviderDataSize,
1297 DPGET_REMOTE );
1298 if ( lpPackedPlayer->ServiceProviderDataSize )
1300 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, playerSPData,
1301 lpPackedPlayer->ServiceProviderDataSize );
1302 offset += lpPackedPlayer->ServiceProviderDataSize;
1305 /* Player data */
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;
1315 if ( bIsGroup )
1317 lpPlayerList lpPList;
1319 /* Player IDs */
1320 lpPackedPlayer->NumberOfPlayers = 0;
1322 if ( (lpPList = DPQ_FIRST( ((lpGroupData)lpData)->players )) )
1326 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
1327 &lpPList->lpPData->dpid,
1328 sizeof(DPID) );
1329 offset += sizeof(DPID);
1330 lpPackedPlayer->NumberOfPlayers++;
1332 while( (lpPList = DPQ_NEXT( lpPList->players )) );
1337 /* Total size */
1338 lpPackedPlayer->Size = offset;
1340 return lpPackedPlayer->Size;
1343 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl* lpDP,
1344 LPVOID* lplpReply,
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;
1356 DWORD offset;
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;
1371 else
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);
1385 /* Session name */
1386 if ( lpDP->dp2->lpSessionDesc->lpszSessionName )
1388 lpReply->NameOffset = offset;
1389 offset += DP_CopyString( ((LPBYTE) lpReply) + offset,
1390 lpDP->dp2->lpSessionDesc->lpszSessionName,
1391 bAnsi );
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,
1400 bAnsi );
1403 /* Populate PlayerInfo list */
1405 /* - Players */
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 );
1416 else
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 )) );
1428 /* - Groups */
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 );
1439 else
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;