dplayx: Stub function to pack dplay messages
[wine/gsoc_dplay.git] / dlls / dplayx / dplayx_messages.c
blobc7725dc5073385c9dc06e9f043a9c5911f7a7a1e
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* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
52 static DWORD DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl* lpDP,
53 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer,
54 LPVOID lpData,
55 BOOL bIsGroup,
56 BOOL bAnsi );
57 static DWORD DP_MSG_FillPackedPlayer( IDirectPlay2Impl* lpDP,
58 LPDPLAYI_PACKEDPLAYER lpPackedPlayer,
59 LPVOID lpData,
60 BOOL bIsGroup,
61 BOOL bAnsi );
62 DWORD DP_CopyString( LPVOID destination, LPVOID source, BOOL bAnsi );
65 /* Create the message reception thread to allow the application to receive
66 * asynchronous message reception
68 DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
69 HANDLE hDeath, HANDLE hConnRead )
71 DWORD dwMsgThreadId;
72 LPMSGTHREADINFO lpThreadInfo;
74 lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
75 if( lpThreadInfo == NULL )
77 return 0;
80 /* The notify event may or may not exist. Depends if async comm or not */
81 if( hNotifyEvent &&
82 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
83 GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
84 0, FALSE, DUPLICATE_SAME_ACCESS ) )
86 ERR( "Unable to duplicate event handle\n" );
87 goto error;
90 /* These 3 handles don't need to be duplicated because we don't keep a
91 * reference to them where they're created. They're created specifically
92 * for the message thread
94 lpThreadInfo->hStart = hStart;
95 lpThreadInfo->hDeath = hDeath;
96 lpThreadInfo->hSettingRead = hConnRead;
98 if( !CreateThread( NULL, /* Security attribs */
99 0, /* Stack */
100 DPL_MSG_ThreadMain, /* Msg reception function */
101 lpThreadInfo, /* Msg reception func parameter */
102 0, /* Flags */
103 &dwMsgThreadId /* Updated with thread id */
107 ERR( "Unable to create msg thread\n" );
108 goto error;
111 /* FIXME: Should I be closing the handle to the thread or does that
112 terminate the thread? */
114 return dwMsgThreadId;
116 error:
118 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
120 return 0;
123 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
125 LPMSGTHREADINFO lpThreadInfo = lpContext;
126 DWORD dwWaitResult;
128 TRACE( "Msg thread created. Waiting on app startup\n" );
130 /* Wait to ensure that the lobby application is started w/ 1 min timeout */
131 dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
132 if( dwWaitResult == WAIT_TIMEOUT )
134 FIXME( "Should signal app/wait creation failure (0x%08x)\n", dwWaitResult );
135 goto end_of_thread;
138 /* Close this handle as it's not needed anymore */
139 CloseHandle( lpThreadInfo->hStart );
140 lpThreadInfo->hStart = 0;
142 /* Wait until the lobby knows what it is */
143 dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
144 if( dwWaitResult == WAIT_TIMEOUT )
146 ERR( "App Read connection setting timeout fail (0x%08x)\n", dwWaitResult );
149 /* Close this handle as it's not needed anymore */
150 CloseHandle( lpThreadInfo->hSettingRead );
151 lpThreadInfo->hSettingRead = 0;
153 TRACE( "App created && initialized starting main message reception loop\n" );
155 for ( ;; )
157 MSG lobbyMsg;
158 GetMessageW( &lobbyMsg, 0, 0, 0 );
161 end_of_thread:
162 TRACE( "Msg thread exiting!\n" );
163 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
165 return 0;
168 /* DP messaging stuff */
169 static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
170 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
171 WORD wReplyCommandId );
172 static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
173 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
176 static
177 HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
178 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId )
180 lpReplyStructList->replyExpected.hReceipt = CreateEventW( NULL, FALSE, FALSE, NULL );
181 lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId;
182 lpReplyStructList->replyExpected.lpReplyMsg = NULL;
183 lpReplyStructList->replyExpected.dwMsgBodySize = 0;
185 /* Insert into the message queue while locked */
186 EnterCriticalSection( &This->unk->DP_lock );
187 DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected );
188 LeaveCriticalSection( &This->unk->DP_lock );
190 return lpReplyStructList->replyExpected.hReceipt;
193 static
194 LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
195 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
197 CloseHandle( lpReplyStructList->replyExpected.hReceipt );
199 *lplpReplyMsg = lpReplyStructList->replyExpected.lpReplyMsg;
200 *lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize;
202 return lpReplyStructList->replyExpected.lpReplyMsg;
205 HRESULT DP_MSG_PackMessage( IDirectPlay2AImpl* This, LPVOID* lpMsg,
206 LPDWORD lpMessageSize )
208 LPVOID lpPacket;
209 LPDPSP_MSG_PACKET lpPacketBody;
211 TRACE( "Packing message with command 0x%x\n",
212 ( (LPDPSP_MSG_ENVELOPE)
213 (((LPBYTE) *lpMsg) + This->dp2->spData.dwSPHeaderSize))->wCommandId );
214 FIXME( "TODO: Segment the package if needed\n" );
216 lpPacket = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
217 *lpMessageSize + sizeof(DPSP_MSG_PACKET) );
218 lpPacketBody = (LPDPSP_MSG_PACKET)( (LPBYTE) lpPacket +
219 This->dp2->spData.dwSPHeaderSize );
221 /* TODO: When do we have to send a DPMSGCMD_PACKET2_DATA? */
222 lpPacketBody->envelope.dwMagic = DPMSG_SIGNATURE;
223 lpPacketBody->envelope.wCommandId = DPMSGCMD_PACKET;
224 lpPacketBody->envelope.wVersion = DX61AVERSION;
226 CoCreateGuid( &lpPacketBody->GuidMessage );
227 lpPacketBody->PacketIndex = 0;
228 lpPacketBody->DataSize = *lpMessageSize - This->dp2->spData.dwSPHeaderSize;
229 lpPacketBody->Offset = 0;
230 lpPacketBody->TotalPackets = 1;
231 lpPacketBody->MessageSize = *lpMessageSize - This->dp2->spData.dwSPHeaderSize;
232 lpPacketBody->PackedOffset = 0;
234 /* Copy the header of the original message */
235 CopyMemory( lpPacket, *lpMsg, This->dp2->spData.dwSPHeaderSize );
236 /* Copy the body of the original message */
237 CopyMemory( lpPacketBody + 1,
238 ((LPBYTE) *lpMsg) + This->dp2->spData.dwSPHeaderSize,
239 *lpMessageSize - This->dp2->spData.dwSPHeaderSize );
240 *lpMessageSize += sizeof(DPSP_MSG_PACKET);
242 HeapFree( GetProcessHeap(), 0, *lpMsg );
243 *lpMsg = lpPacket;
245 return DP_OK;
248 HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
249 LPDPID lpdpidAllocatedId )
251 LPVOID lpMsg;
252 LPDPSP_MSG_REQUESTPLAYERID lpMsgBody;
253 DWORD dwMsgSize;
254 HRESULT hr = DP_OK;
256 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
258 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
260 lpMsgBody = (LPDPSP_MSG_REQUESTPLAYERID)( (LPBYTE)lpMsg +
261 This->dp2->spData.dwSPHeaderSize );
263 /* Compose dplay message envelope */
264 lpMsgBody->envelope.dwMagic = DPMSG_SIGNATURE;
265 lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTPLAYERID;
266 lpMsgBody->envelope.wVersion = DX61AVERSION;
268 /* Compose the body of the message */
269 lpMsgBody->Flags = dwFlags;
271 /* Send the message */
273 DPSP_SENDDATA data;
275 data.dwFlags = DPSEND_GUARANTEED;
276 data.idPlayerTo = 0; /* Name server */
277 data.idPlayerFrom = 0; /* Sending from DP */
278 data.lpMessage = lpMsg;
279 data.dwMessageSize = dwMsgSize;
280 data.bSystemMessage = TRUE; /* Allow reply to be sent */
281 data.lpISP = This->dp2->spData.lpISP;
283 TRACE( "Asking for player id w/ Flags 0x%08x\n", lpMsgBody->Flags );
285 lpMsg = DP_MSG_ExpectReply( This, &data,
286 DPMSG_RELIABLE_API_TIMER,
287 DPMSGCMD_REQUESTPLAYERREPLY,
288 &lpMsg, &dwMsgSize );
291 /* Examine reply */
292 if( lpMsg )
294 *lpdpidAllocatedId = ((LPCDPSP_MSG_REQUESTPLAYERREPLY) lpMsg)->ID;
295 TRACE( "Received new id 0x%08x\n", *lpdpidAllocatedId );
297 else
299 ERR( "Didn't receive reply\n" );
300 hr = DPERR_GENERIC;
303 HeapFree( GetProcessHeap(), 0, lpMsg );
304 return hr;
307 HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer )
309 LPVOID lpMsg;
310 LPDPSP_MSG_ADDFORWARDREQUEST lpMsgBody;
311 DWORD dwMsgSize;
312 HRESULT hr = DP_OK;
314 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
316 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
318 lpMsgBody = (LPDPSP_MSG_ADDFORWARDREQUEST)( (LPBYTE)lpMsg +
319 This->dp2->spData.dwSPHeaderSize );
321 /* Compose dplay message envelope */
322 lpMsgBody->envelope.dwMagic = DPMSG_SIGNATURE;
323 lpMsgBody->envelope.wCommandId = DPMSGCMD_ADDFORWARDREQUEST;
324 lpMsgBody->envelope.wVersion = DX61AVERSION;
326 /* Compose body of message */
327 FIXME( "TODO\n" );
329 /* Send the message */
331 DPSP_SENDDATA data;
333 data.dwFlags = DPSEND_GUARANTEED;
334 data.idPlayerTo = 0; /* Name server */
335 data.idPlayerFrom = dpidServer; /* Sending from session server */
336 data.lpMessage = lpMsg;
337 data.dwMessageSize = dwMsgSize;
338 data.bSystemMessage = TRUE; /* Allow reply to be sent */
339 data.lpISP = This->dp2->spData.lpISP;
341 TRACE( "Sending forward player request with 0x%08x\n", dpidServer );
343 lpMsg = DP_MSG_ExpectReply( This, &data,
344 DPMSG_RELIABLE_API_TIMER,
345 DPMSGCMD_ADDFORWARD,
346 &lpMsg, &dwMsgSize );
349 /* Need to examine the data and extract the new player id */
350 if( lpMsg != NULL )
352 FIXME( "Name Table reply received: stub\n" );
355 return hr;
358 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
359 * not seem to offer any way of uniquely differentiating between replies of the same type
360 * relative to the request sent. There is an implicit assumption that there will be no
361 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
362 * a networking company.
364 static
365 LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData,
366 DWORD dwWaitTime, WORD wReplyCommandId,
367 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
369 HRESULT hr;
370 HANDLE hMsgReceipt;
371 DP_MSG_REPLY_STRUCT_LIST replyStructList;
372 DWORD dwWaitReturn;
373 WORD wCommandId;
375 /* Setup for receipt */
376 hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList,
377 wReplyCommandId );
379 wCommandId = ((LPCDPSP_MSG_ENVELOPE)
380 ( ((LPBYTE) lpData->lpMessage) +
381 This->dp2->spData.dwSPHeaderSize ))->wCommandId;
382 TRACE( "Sending cmd 0x%x and expecting cmd 0x%x in reply within %u ticks\n",
383 wCommandId, wReplyCommandId, dwWaitTime );
384 hr = (*This->dp2->spData.lpCB->Send)( lpData );
386 if( FAILED(hr) )
388 ERR( "Send failed: %s\n", DPLAYX_HresultToString( hr ) );
389 return NULL;
392 /* The reply message will trigger the hMsgReceipt event effectively switching
393 * control back to this thread. See DP_MSG_ReplyReceived.
395 dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime );
396 if( dwWaitReturn != WAIT_OBJECT_0 )
398 ERR( "Wait failed 0x%08x\n", dwWaitReturn );
399 return NULL;
402 /* Clean Up */
403 return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyMsg, lpdwMsgBodySize );
406 /* Determine if there is a matching request for this incoming message and then copy
407 * all important data. It is quite silly to have to copy the message, but the documents
408 * indicate that a copy is taken. Silly really.
410 void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId,
411 LPCVOID lpcMsgBody, DWORD dwMsgBodySize )
413 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList;
415 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
416 * avoid problems.
418 EnterCriticalSection( &This->unk->DP_lock );
419 DPQ_REMOVE_ENTRY( This->dp2->replysExpected, replysExpected, replyExpected.wExpectedReply,
420 ==, wCommandId, lpReplyList );
421 LeaveCriticalSection( &This->unk->DP_lock );
423 if( lpReplyList != NULL )
425 lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize;
426 lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(),
427 HEAP_ZERO_MEMORY,
428 dwMsgBodySize );
429 CopyMemory( lpReplyList->replyExpected.lpReplyMsg,
430 lpcMsgBody, dwMsgBodySize );
432 /* Signal the thread which sent the message that it has a reply */
433 SetEvent( lpReplyList->replyExpected.hReceipt );
435 else
437 ERR( "No receipt event set for cmd 0x%x, only expecting in reply mode\n",
438 wCommandId );
442 DWORD DP_CopyString( LPVOID destination, LPVOID source, BOOL bAnsi )
444 /* Copies an ASCII string (bAnsi=TRUE) or a wide string (bAnsi=FALSE)
445 * from source to the previously allocated destination buffer.
446 * The destination string will be always wide.
447 * If destination is NULL, doesn't perform the copy but the
448 * returned size is still correct.
450 * Returns: The size in bytes of the written string. */
452 DWORD dwLength;
454 if ( source == NULL )
455 return 0;
457 if ( bAnsi )
459 dwLength = MultiByteToWideChar( CP_ACP, 0, (LPSTR) source, -1, NULL, 0 );
460 if ( destination )
461 MultiByteToWideChar( CP_ACP, 0, (LPSTR) source, -1,
462 (LPWSTR) destination, dwLength );
464 else
466 dwLength = lstrlenW( (LPWSTR) source ) + 1;
467 if ( destination )
468 CopyMemory( destination, source, dwLength );
471 return dwLength * sizeof(WCHAR);
474 static DWORD DP_MSG_FillSuperPackedPlayer( IDirectPlay2Impl* lpDP,
475 LPDPLAYI_SUPERPACKEDPLAYER lpPackedPlayer,
476 LPVOID lpData,
477 BOOL bIsGroup,
478 BOOL bAnsi )
480 /* Fills lpPackedPlayer with the information in lpData.
481 * lpData can be a player or a group.
482 * If lpPackedPlayer is NULL just returns the size
483 * needed to pack the player.
485 * Returns: the size of the written data in bytes */
487 #define PLAYER_OR_GROUP( bIsGroup, lpData, field ) \
488 ( bIsGroup \
489 ? ((lpGroupData) lpData)->field \
490 : ((lpPlayerData) lpData)->field )
492 DWORD offset, length, size;
493 LPVOID playerSPData;
495 if ( lpPackedPlayer == NULL )
497 size = sizeof(DPLAYI_SUPERPACKEDPLAYER); /* Fixed data */
498 size += DP_CopyString( NULL, /* Short name */
499 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
500 bAnsi );
501 size += DP_CopyString( NULL, /* Long name */
502 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
503 bAnsi );
504 /* Player data length */
505 /* Player data */
506 /* SP data length */
507 /* SP data */
509 if ( bIsGroup )
511 /* Player count */
512 /* Player IDs */
513 /* ParentID */
514 /* Shortcut ID Count */
515 /* Shortcut IDs */
517 return size;
520 lpPackedPlayer->Size = sizeof(DPLAYI_SUPERPACKEDPLAYER);
522 lpPackedPlayer->Flags = 0x000000FF & PLAYER_OR_GROUP( bIsGroup, lpData, dwFlags );
523 lpPackedPlayer->ID = PLAYER_OR_GROUP( bIsGroup, lpData, dpid );
525 if ( lpPackedPlayer->Flags & DPLAYI_PLAYER_SYSPLAYER )
527 lpPackedPlayer->VersionOrSystemPlayerID = DX61AVERSION;
529 else
531 lpPackedPlayer->VersionOrSystemPlayerID =
532 DPQ_FIRST( lpDP->dp2->lpSysGroup->players )->lpPData->dpid;
535 offset = lpPackedPlayer->Size;
537 /* Short name */
538 length = DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
539 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
540 bAnsi );
541 if ( length )
542 lpPackedPlayer->PlayerInfoMask |= SPP_SN;
543 offset += length;
545 /* Long name */
546 length = DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
547 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
548 bAnsi );
549 if ( length )
550 lpPackedPlayer->PlayerInfoMask |= SPP_LN;
551 offset += length;
553 /* Player data */
554 length = PLAYER_OR_GROUP( bIsGroup, lpData, dwRemoteDataSize);
555 if ( length )
557 size = spp_get_optimum_size( length );
558 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_PD_OFFSET );
559 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, &length, size );
560 offset += size;
562 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
563 PLAYER_OR_GROUP( bIsGroup, lpData, lpRemoteData ),
564 length );
565 offset += length;
568 /* Service provider data */
569 IDirectPlaySP_GetSPPlayerData( lpDP->dp2->spData.lpISP, lpPackedPlayer->ID,
570 &playerSPData, &length, DPGET_REMOTE );
571 if ( length )
573 size = spp_get_optimum_size( length );
574 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SL_OFFSET );
575 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, &length, size );
576 offset += size;
577 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, playerSPData, length );
578 offset += length;
581 if ( bIsGroup )
583 /* Player IDs */
584 if( !DPQ_IS_EMPTY( ((lpGroupData)lpData)->players ) )
586 DWORD player_count, offset_PC;
587 lpPlayerList lpPList;
589 offset_PC = offset; /* Space for PlayerCount */
590 offset += 4;
591 player_count = 0;
593 /* PlayerIDs */
594 if ( (lpPList = DPQ_FIRST( ((lpGroupData)lpData)->players )) )
598 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
599 &lpPList->lpPData->dpid,
600 sizeof(DPID) );
601 offset += sizeof(DPID);
602 player_count++;
604 while( (lpPList = DPQ_NEXT( lpPList->players )) );
607 /* PlayerCount */
608 size = spp_get_optimum_size( player_count );
609 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_PC_OFFSET );
611 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset_PC, &player_count, size );
614 /* ParentID */
615 if ( ((lpGroupData)lpData)->parent )
617 lpPackedPlayer->PlayerInfoMask |= SPP_PI;
618 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
619 &((lpGroupData)lpData)->parent,
620 sizeof(DWORD) );
621 offset += sizeof(DWORD);
624 /* Shortcut IDs */
625 /*size = spp_get_optimum_size( ___ );
626 lpPackedPlayer->PlayerInfoMask |= spp_size2flags( size, SPP_SC_OFFSET );*/
627 FIXME( "TODO: Add shortcut IDs\n" );
630 return offset;
633 static DWORD DP_MSG_FillPackedPlayer( IDirectPlay2Impl* lpDP,
634 LPDPLAYI_PACKEDPLAYER lpPackedPlayer,
635 LPVOID lpData,
636 BOOL bIsGroup,
637 BOOL bAnsi )
639 /* Fills lpPackedPlayer with the information in lpData.
640 * lpData can be a player or a group.
641 * If lpPackedPlayer is NULL just returns the size
642 * needed to pack the player.
644 * Returns: the size of the written data in bytes */
646 LPVOID playerSPData;
647 DWORD offset;
649 if ( lpPackedPlayer == NULL )
651 DWORD size;
652 size = sizeof(DPLAYI_PACKEDPLAYER); /* Fixed data */
653 size += DP_CopyString( NULL, /* Short name */
654 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
655 bAnsi );
656 size += DP_CopyString( NULL, /* Long name */
657 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
658 bAnsi );
659 /* SP data */
660 /* Player data */
662 if ( bIsGroup )
664 /* Player IDs */
666 return size;
669 lpPackedPlayer->SystemPlayerID =
670 DPQ_FIRST( lpDP->dp2->lpSysGroup->players )->lpPData->dpid;
671 lpPackedPlayer->FixedSize = sizeof(DPLAYI_PACKEDPLAYER);
672 lpPackedPlayer->PlayerVersion = DX61AVERSION;
674 lpPackedPlayer->Flags = 0x000000FF & PLAYER_OR_GROUP( bIsGroup, lpData, dwFlags );
675 lpPackedPlayer->PlayerID = PLAYER_OR_GROUP( bIsGroup, lpData, dpid );
676 lpPackedPlayer->ParentID = ( bIsGroup
677 ? ((lpGroupData)lpData)->parent
678 : 0 );
680 offset = lpPackedPlayer->FixedSize;
682 /* Short name */
683 lpPackedPlayer->ShortNameLength =
684 DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
685 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszShortName ),
686 bAnsi );
687 offset += lpPackedPlayer->ShortNameLength;
689 /* Long name */
690 lpPackedPlayer->LongNameLength =
691 DP_CopyString( ((LPBYTE) lpPackedPlayer) + offset,
692 PLAYER_OR_GROUP( bIsGroup, lpData, name.lpszLongName ),
693 bAnsi );
694 offset += lpPackedPlayer->LongNameLength;
696 /* Service provider data */
697 IDirectPlaySP_GetSPPlayerData( lpDP->dp2->spData.lpISP,
698 lpPackedPlayer->PlayerID,
699 &playerSPData,
700 &lpPackedPlayer->ServiceProviderDataSize,
701 DPGET_REMOTE );
702 if ( lpPackedPlayer->ServiceProviderDataSize )
704 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset, playerSPData,
705 lpPackedPlayer->ServiceProviderDataSize );
706 offset += lpPackedPlayer->ServiceProviderDataSize;
709 /* Player data */
710 lpPackedPlayer->PlayerDataSize = PLAYER_OR_GROUP( bIsGroup, lpData, dwRemoteDataSize );
711 if ( lpPackedPlayer->PlayerDataSize )
713 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
714 PLAYER_OR_GROUP( bIsGroup, lpData, lpRemoteData ),
715 lpPackedPlayer->PlayerDataSize );
716 offset += lpPackedPlayer->PlayerDataSize;
719 if ( bIsGroup )
721 lpPlayerList lpPList;
723 /* Player IDs */
724 lpPackedPlayer->NumberOfPlayers = 0;
726 if ( (lpPList = DPQ_FIRST( ((lpGroupData)lpData)->players )) )
730 CopyMemory( ((LPBYTE) lpPackedPlayer) + offset,
731 &lpPList->lpPData->dpid,
732 sizeof(DPID) );
733 offset += sizeof(DPID);
734 lpPackedPlayer->NumberOfPlayers++;
736 while( (lpPList = DPQ_NEXT( lpPList->players )) );
741 /* Total size */
742 lpPackedPlayer->Size = offset;
744 return lpPackedPlayer->Size;
747 void DP_MSG_ReplyToEnumPlayersRequest( IDirectPlay2Impl* lpDP,
748 LPVOID* lplpReply,
749 LPDWORD lpdwMsgSize )
751 /* Depending on the type of session, builds either a EnumPlayers
752 reply or a SuperEnumPlayers reply, and places it in lplpReply */
754 /* TODO: Find size to allocate *lplpReply
755 * Check if we're releasing that memory */
757 LPDPSP_MSG_ENUMPLAYERSREPLY lpReply; /* Also valid in the SUPER case */
758 lpPlayerList lpPList;
759 lpGroupList lpGList;
760 DWORD offset;
761 BOOL bAnsi = TRUE; /* FIXME: This needs to be in the DPLAY interface */
764 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 1024 );
765 lpReply = (LPDPSP_MSG_ENUMPLAYERSREPLY)( (LPBYTE)(*lplpReply) +
766 lpDP->dp2->spData.dwSPHeaderSize );
768 lpReply->envelope.dwMagic = DPMSG_SIGNATURE;
769 lpReply->envelope.wVersion = DX61AVERSION;
771 if ( lpDP->dp2->lpSessionDesc->dwFlags & DPSESSION_CLIENTSERVER )
773 lpReply->envelope.wCommandId = DPMSGCMD_ENUMPLAYERSREPLY;
775 else
777 lpReply->envelope.wCommandId = DPMSGCMD_SUPERENUMPLAYERSREPLY;
781 /* Session description */
782 lpReply->DescriptionOffset = ( sizeof(DPSP_MSG_ENUMPLAYERSREPLY) -
783 sizeof(DPSESSIONDESC2) );
784 CopyMemory( &lpReply->DPSessionDesc, lpDP->dp2->lpSessionDesc,
785 sizeof(DPSESSIONDESC2) );
787 offset = sizeof(DPSP_MSG_ENUMPLAYERSREPLY);
789 /* Session name */
790 if ( lpDP->dp2->lpSessionDesc->lpszSessionName )
792 lpReply->NameOffset = offset;
793 offset += DP_CopyString( ((LPBYTE) lpReply) + offset,
794 lpDP->dp2->lpSessionDesc->lpszSessionName,
795 bAnsi );
798 /* Session password */
799 if ( lpDP->dp2->lpSessionDesc->lpszPassword )
801 lpReply->PasswordOffset = offset;
802 offset += DP_CopyString( ((LPBYTE) lpReply) + offset,
803 lpDP->dp2->lpSessionDesc->lpszPassword,
804 bAnsi );
807 /* Populate PlayerInfo list */
809 /* - Players */
810 if ( (lpPList = DPQ_FIRST( lpDP->dp2->lpSysGroup->players )) )
814 if ( lpReply->envelope.wCommandId == DPMSGCMD_SUPERENUMPLAYERSREPLY )
816 offset += DP_MSG_FillSuperPackedPlayer(
817 lpDP, (LPDPLAYI_SUPERPACKEDPLAYER)( ((LPBYTE)lpReply) + offset ),
818 lpPList->lpPData, FALSE, bAnsi );
820 else
822 offset += DP_MSG_FillPackedPlayer(
823 lpDP, (LPDPLAYI_PACKEDPLAYER)( ((LPBYTE)lpReply) + offset ),
824 lpPList->lpPData, FALSE, bAnsi );
827 lpReply->PlayerCount++;
829 while( (lpPList = DPQ_NEXT( lpPList->players )) );
832 /* - Groups */
833 if ( (lpGList = DPQ_FIRST( lpDP->dp2->lpSysGroup->groups )) )
837 if ( lpReply->envelope.wCommandId == DPMSGCMD_SUPERENUMPLAYERSREPLY )
839 offset += DP_MSG_FillSuperPackedPlayer(
840 lpDP, (LPDPLAYI_SUPERPACKEDPLAYER)( ((LPBYTE)lpReply) + offset ),
841 lpGList->lpGData, TRUE, bAnsi );
843 else
845 offset += DP_MSG_FillPackedPlayer(
846 lpDP, (LPDPLAYI_PACKEDPLAYER)( ((LPBYTE)lpReply) + offset ),
847 lpGList->lpGData, TRUE, bAnsi );
850 lpReply->GroupCount++;
852 while( (lpGList = DPQ_NEXT( lpGList->groups )) );
855 if ( lpReply->envelope.wCommandId == DPMSGCMD_SUPERENUMPLAYERSREPLY )
857 /* - Groups with shortcuts */
858 FIXME( "TODO: Add shortcut IDs\n" );
861 *lpdwMsgSize = lpDP->dp2->spData.dwSPHeaderSize + offset;